pax_global_header00006660000000000000000000000064147405013720014515gustar00rootroot0000000000000052 comment=6687337e66c86b37a080e94e2abc7ee3bbe59d47 simutrans-124.3/000077500000000000000000000000001474050137200135535ustar00rootroot00000000000000simutrans-124.3/.editorconfig000066400000000000000000000007471474050137200162400ustar00rootroot00000000000000# EditorConfig (see https://EditorConfig.org) root = true [*] charset = utf-8 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true [*.{txt,tab}] trim_trailing_whitespace = false [**/CMakeLists.txt] trim_trailing_whitespace = true [*.rc] indent_style = space indent_size = 1 [*.{nsi,nsh}] indent_style = space indent_size = 2 [Makefile,*.mk] indent_style = space indent_size = 2 [{*.vcxitems,*.vcxproj}] insert_final_newline = false indent_style = space simutrans-124.3/.github/000077500000000000000000000000001474050137200151135ustar00rootroot00000000000000simutrans-124.3/.github/build32.sh000066400000000000000000000011101474050137200167040ustar00rootroot00000000000000#!/bin/sh # builds 32bit GDI for windows # libbrotli static is broken in MinGW for freetype2 for f in libbrotlidec libbrotlienc libbrotlicommon; do mv "/mingw32/lib/$f.dll.a" "/mingw32/lib/$f.dll._" cp "/mingw32/lib/$f-static.a" "/mingw32/lib/$f.a" done # normal build autoconf make clean sh ./configure echo "FLAGS = -DREVISION=$(svn info --show-item revision svn://servers.simutrans.org/simutrans) " >>config.default echo "STATIC = 1" >>config.default %echo "VERBOSE = 1" >>config.default cat config.default >2 make sh tools/distribute.sh mv simu*.zip simuwin-gdi32-nightly.zip simutrans-124.3/.github/build64-SDL2.sh000077500000000000000000000016111474050137200174240ustar00rootroot00000000000000#!/bin/sh # build SDL2 simutrans nightly # libbrotli static is broken in MinGW for freetype2 for f in libbrotlidec libbrotlienc libbrotlicommon; do mv "/mingw64/lib/$f.dll.a" "/mingw64/lib/$f.dll._" cp "/mingw64/lib/$f-static.a" "/mingw64/lib/$f.a" done # normal build echo "BACKEND = sdl2" >config.default echo "OSTYPE = mingw" >>config.default echo "DEBUG = 0" >>config.default echo "MSG_LEVEL = 3" >>config.default echo "OPTIMISE = 1" >>config.default echo "MULTI_THREAD = 1" >>config.default echo "USE_ZSTD = 1" >>config.default echo "WITH_REVISION = 0" >>config.default echo "FLAGS = -DREVISION=$(svn info --show-item revision svn://servers.simutrans.org/simutrans) " >>config.default echo "STATIC = 1" >>config.default echo "VERBOSE = 1" >>config.default echo "LDFLAGS += $(pkg-config --libs --static SDL2) " >>config.default make sh tools/distribute.sh mv simu*.zip simuwin64-SDL2-nightly.zipsimutrans-124.3/.github/prepare-nsis.ps1000066400000000000000000000030301474050137200201440ustar00rootroot00000000000000# downloads and unpacks the unicode plugin needed for NSIS installer of paksetdownloader Write-Output "Downloading and installing NSIS" Invoke-WebRequest -UserAgent "Wget" -Uri "https://sourceforge.net/projects/nsis/files/NSIS%203/3.09/nsis-3.09.zip/download" -OutFile "nsis.zip" expand-archive -path "nsis.zip" -DestinationPath "." -Force Invoke-WebRequest -Uri "https://nsis.sourceforge.io/mediawiki/images/5/5a/NSISunzU.zip" -OutFile "NSISunzU.zip" Invoke-WebRequest -Uri "https://nsis.sourceforge.io/mediawiki/images/c/c9/Inetc.zip" -OutFile "Inetc.zip" Invoke-WebRequest -Uri "https://nsis.sourceforge.io/mediawiki/images/c/c7/CabX.zip" -OutFile "CabX.zip" Invoke-WebRequest -Uri "https://nsis.sourceforge.io/mediawiki/images/9/9d/Untgz.zip" -OutFile "Untgz.zip" Invoke-WebRequest -Uri "https://nsis.sourceforge.io/mediawiki/images/6/6c/Shelllink.zip" -OutFile "Shelllink.zip" expand-archive -path "CabX.zip" -DestinationPath "nsis-3.09" -Force expand-archive -path "Inetc.zip" -DestinationPath "nsis-3.09" -Force expand-archive -path "NSISunzU.zip" -DestinationPath "dummy" -Force move ".\dummy\NSISunzU\Plugin unicode\nsisunz.dll" .\nsis-3.09\plugins\x86-unicode\ expand-archive -path "Untgz.zip" -DestinationPath "dummy" -Force move .\dummy\Untgz\unicode\untgz.dll .\nsis-3.09\plugins\x86-unicode\ expand-archive -path "Shelllink.zip" -DestinationPath "dummy" -Force move .\dummy\Unicode\Plugins\ShellLink.dll .\nsis-3.09\plugins\x86-unicode\ Remove-Item 'dummy' -Recurse del *.zip ./nsis-3.09/makensis.exe ./src/Windows/nsis/onlineupgrade.nsi simutrans-124.3/.github/workflows/000077500000000000000000000000001474050137200171505ustar00rootroot00000000000000simutrans-124.3/.github/workflows/makeobj.yml000066400000000000000000000061061474050137200213060ustar00rootroot00000000000000name: Nightly build makeobj on: [push] jobs: makeobj_windows-nightly: name: makeobj Windows runs-on: windows-2022 steps: - name: Setup Mingw uses: msys2/setup-msys2@v2 with: msystem: MINGW32 update: false install: base-devel mingw-w64-i686-toolchain mingw-w64-i686-gcc mingw-w64-i686-libpng - name: Checkout code uses: actions/checkout@v4 - name: build shell: msys2 {0} working-directory: ${{env.GITHUB_WORKSPACE}} run: | printf 'BACKEND := posix\nOSTYPE := mingw\nOPTIMISE := 1\nSTATIC := 1\n' | cat >config.default cd src/makeobj make cd ../../build/default/makeobj strip makeobj.exe - name: zip result shell: pwsh run: Compress-Archive build\default\makeobj\makeobj.exe build\default\makeobj\makeobj-windows-nightly.zip - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build\default\makeobj\makeobj-windows-nightly.zip asset_name: makeobj-win-nightly.zip tag: Nightly overwrite: true makeobj_linux-x64-nightly: name: makeobj Linux x64 runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v4 - name: install_dependencies run: | sudo apt-get -y update sudo apt-get -ym install autoconf sudo apt-get -ym install libpng-dev sudo apt-get -ym install libbz2-dev - name: setup run: | autoconf ./configure echo "STATIC = 1" >>config.default cat config.default >>/dev/stderr - name: make makeobj run: | cd src/makeobj make - name: zip result run: | cd src/makeobj zip -r -9 makeobj_linux-x64-nightly.zip makeobj - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: src/makeobj/makeobj_linux-x64-nightly.zip asset_name: makeobj_linux-x64-nightly.zip tag: Nightly overwrite: true makeobj-mac: name: makeobj macOS arm runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: install_dependencies run: | brew reinstall cmake pkg-config libpng - name: build run: | printf "#define REVISION %i\n" $(tools/get_revision.sh) > src/simutrans/revision.h cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build/src/makeobj - name: distribute run: | cd build/src/makeobj zip -r makeobj-arm-nightly.zip makeobj - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build/src/makeobj/makeobj-arm-nightly.zip asset_name: makeobj-arm-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-android.yml000066400000000000000000000142311474050137200227700ustar00rootroot00000000000000name: Nightly build Android on: push: jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 path: 'gh-clone/simutrans' - name: Install dependencies run: | sudo dpkg --add-architecture i386 sudo apt-get -yqq update sudo apt-get -ym install curl expect git libc6:i386 libgcc1:i386 libncurses6:i386 libstdc++6:i386 zlib1g:i386 openjdk-17-jdk wget unzip vim make subversion zip - name: Setup Android SDK environment variables run: | echo "ANDROID_HOME=/opt/android-sdk-linux" >> $GITHUB_ENV echo "ANDROID_SDK_HOME=/opt/android-sdk-linux" >> $GITHUB_ENV echo "ANDROID_SDK_ROOT=/opt/android-sdk-linux" >> $GITHUB_ENV echo "ANDROID_SDK=/opt/android-sdk-linux" >> $GITHUB_ENV echo "JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> $GITHUB_ENV - name: Create working directory for next steps run: | sudo mkdir /opt/android-sdk-linux sudo mkdir /android-sdl sudo chown -R runner /opt/android-sdk-linux sudo chgrp -R docker /opt/android-sdk-linux sudo chown -R runner /android-sdl sudo chgrp -R docker /android-sdl - name: Install Android SDK tools working-directory: /opt/android-sdk-linux run: | wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip unzip commandlinetools-linux-7583922_latest.zip rm commandlinetools-linux-7583922_latest.zip mv cmdline-tools latest mkdir cmdline-tools mv latest cmdline-tools/latest echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH - name: Install Android SDK dependencies working-directory: /opt/android-sdk-linux run: | yes | sdkmanager --licenses yes | sdkmanager --install "platform-tools" echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH yes | sdkmanager --install "build-tools;34.0.0" echo "$ANDROID_HOME/build-tools/34.0.0" >> $GITHUB_PATH yes | sdkmanager --install "cmake;3.22.1" echo "$ANDROID_HOME/cmake/3.22.1/bin" >> $GITHUB_PATH yes | sdkmanager --install "ndk;25.1.8937393" echo "$ANDROID_HOME/ndk/25.1.8937393" >> $GITHUB_PATH echo "$ANDROID_HOME/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/" >> $GITHUB_PATH ln -s llvm-objdump ${ANDROID_HOME}/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/objdump - name: Install keystore for Android APK signing run: | mkdir /home/runner/.android/ keytool -genkey -v -keystore /home/runner/.android/debug.keystore -alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -keypass android -storepass android -dname "cn=example.com,ou=exampleou,dc=example,dc=com" - name: Set up android project working-directory: /android-sdl run: | git clone --depth 1 https://github.com/simutrans/simutrans-android-project cd simutrans-android-project git submodule init git submodule update --depth 1 cp -r $GITHUB_WORKSPACE/gh-clone/simutrans simutrans/jni/simutrans cp -r simutrans/jni/SDL/android-project/app/src/main/java simutrans/src/main cd simutrans/jni ./simutrans/src/android/AndroidPreBuild.sh cp -rf simutrans/simutrans/. ../src/main/assets - name: Build libraries working-directory: /android-sdl/simutrans-android-project/simutrans/jni run: | ./build_libraries.sh # Fluidsynth is a PITA to build; using the prebuilt release instead wget https://github.com/FluidSynth/fluidsynth/releases/download/v2.3.5/fluidsynth-2.3.5-android24.zip unzip fluidsynth-*.zip -d fluidsynth - name: Build Simutrans env: SIGNING_KEYSTORE: /android-sdl/simutrans-android-project/simutrans/jni/simutrans/src/android/Simutrans-upload.keystore SIGNING_KEY_ALIAS: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_ALIAS }} SIGNING_KEY_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASS }} SIGNING_STORE_PASSWORD: ${{ secrets.ANDROID_UPLOAD_KEYSTORE_PASS }} working-directory: gh-clone/simutrans run: | echo "action_state=yellow" >> $GITHUB_ENV sed -i "s/versionCode [0-9]\+/versionCode $(./tools/get_revision.sh)/" /android-sdl/simutrans-android-project/simutrans/build.gradle cd /android-sdl/simutrans-android-project cat simutrans/build.gradle ./gradlew assembleRelease ./gradlew bundleRelease cd /android-sdl/simutrans-android-project/simutrans/build/outputs/bundle/release jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore $SIGNING_KEYSTORE -storepass $SIGNING_STORE_PASSWORD simutrans-release.aab $SIGNING_KEY_ALIAS mkdir whatsNewDirectory echo `cd $GITHUB_WORKSPACE/gh-clone/simutrans && git log --pretty=format:'%s' -1` > whatsNewDirectory/whatsnew-en-US - name: Update binaries of Nightly Release aab uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: /android-sdl/simutrans-android-project/simutrans/build/outputs/bundle/release/simutrans-release.aab asset_name: simuandroid-nightly.aab tag: Nightly overwrite: true - name: Update binaries of Nightly Release apk uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: /android-sdl/simutrans-android-project/simutrans/build/outputs/apk/release/simutrans-release-unsigned.apk asset_name: simuandroid-nightly.apk tag: Nightly overwrite: true - name: Release Beta on Google Play Store uses: r0adkll/upload-google-play@v1 if: github.repository == 'simutrans/simutrans' with: serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }} packageName: com.simutrans releaseFiles: /android-sdl/simutrans-android-project/simutrans/build/outputs/bundle/release/simutrans-release.aab track: beta status: completed whatsNewDirectory: /android-sdl/simutrans-android-project/simutrans/build/outputs/bundle/release/whatsNewDirectory simutrans-124.3/.github/workflows/nightly-macos-arm.yml000066400000000000000000000014411474050137200232260ustar00rootroot00000000000000name: Nightly build MacOS ARM on: [push] jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: install_dependencies run: | brew install cmake pkg-config libpng freetype zstd sdl2 fluidsynth - name: build run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSIMUTRANS_UPDATE_LANGFILES=ON .. cmake --build build --target install - name: distribute run: | cd build zip -r simumac-nightly.zip simutrans - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build/simumac-nightly.zip asset_name: simumac-arm-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-macos-intel.yml000066400000000000000000000014361474050137200235660ustar00rootroot00000000000000name: Nightly build MacOS Intel on: [push] jobs: build: runs-on: macos-13 steps: - uses: actions/checkout@v4 - name: install_dependencies run: | brew install cmake pkg-config libpng freetype zstd sdl2 fluidsynth - name: build run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSIMUTRANS_UPDATE_LANGFILES=ON cmake --build build --target install - name: distribute run: | cd build zip -r simumac-nightly.zip simutrans - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build/simumac-nightly.zip asset_name: simumac-intel-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-ubuntu.yml000066400000000000000000000035651474050137200227020ustar00rootroot00000000000000name: Nightly build Ubuntu on: [push] jobs: build: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 - name: install_dependencies run: | sudo apt-get -y update sudo apt-get -ym install libsdl2-dev sudo apt-get -ym install libfreetype6-dev sudo apt-get -ym install libfontconfig-dev sudo apt-get -ym install libminiupnpc-dev sudo apt-get -ym install libzstd-dev # We build fluidsynth with the minimum set of options we need to keep dependencies low sudo apt-get -ym install libsndfile1-dev wget https://github.com/FluidSynth/fluidsynth/archive/v2.3.0.tar.gz tar xf v*.tar.gz cd fluidsynth* cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib -Denable-aufile=0 -Denable-dbus=0 -Denable-ipv6=0 -Denable-jack=0 -Denable-ladspa=0 -Denable-midishare=0 -Denable-opensles=0 -Denable-oboe=0 -Denable-oss=0 -Denable-readline=0 -Denable-winmidi=0 -Denable-waveout=0 -Denable-network=0 -Denable-pulseaudio=0 -Denable-dsound=0 -Denable-alsa=0 -Denable-libinstpatch=0 -Denable-portaudio=0 -Denable-wasapi=0 -Denable-openmp=1 -Denable-libsndfile=1 -Denable-sdl2=1 cmake --build build -j $(nproc) sudo cmake --install build - name: build run: | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DOPTION_BUNDLE_LIBRARIES=ON -DSIMUTRANS_UPDATE_LANGFILES=ON cmake --build build -j$(nproc) --target install - name: distribute run: | cd build zip -r simulinux-x64-nightly.zip simutrans - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: build/simulinux-x64-nightly.zip asset_name: simulinux-x64-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-windows-ms.yml000066400000000000000000000026471474050137200234670ustar00rootroot00000000000000# This workflow sets up and runs MSBuild and VSTest # to build and test a Visual Studio solution. name: Nightly Build Windows32 GDI on: [push] jobs: winGDI-32: runs-on: windows-latest steps: - name: Setup MSBuild and add to PATH uses: microsoft/setup-msbuild@v2 - name: Checkout code uses: actions/checkout@v4 id: checkout_code - name: Make NSIS shell: pwsh run: ./.github/prepare-nsis.ps1 - name: Run MSBuild shell: pwsh working-directory: ${{env.GITHUB_WORKSPACE}} run: | git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.bat ./vcpkg integrate install cd .. msbuild /m .\Simutrans-GDI.vcxproj -p:Configuration=Release /p:platform=Win32 - name: Build zipfile shell: pwsh run: | move-item "build/GDI/Simutrans GDI Nightly.exe" "simutrans/simutrans.exe" move-item "src\Windows\nsis\download-paksets.exe" "simutrans/download-pakset.exe" tools/get_lang_files.ps1 Compress-Archive -Path simutrans -DestinationPath "simuwin-gdi32-nightly.zip" dir - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: ./simuwin-gdi32-nightly.zip asset_name: simuwin-gdi32-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-windows.broken000066400000000000000000000023151474050137200235210ustar00rootroot00000000000000name: Nightly Build Windows on: [push] jobs: wingdi32: runs-on: windows-latest steps: - name: Setup Mingw uses: msys2/setup-msys2@v2 with: msystem: MINGW32 update: true install: git zip unzip svn base-devel mingw-w64-i686-toolchain autoconf mingw-w64-i686-gcc mingw-w64-i686-freetype mingw-w64-i686-zstd mingw-w64-i686-libpng mingw-w64-i686-brotli mingw-w64-i686-pkg-config - name: Checkout code uses: actions/checkout@v3 - name: Prepares NSIS plugins run: ./.github/prepare-nsis.ps1 shell: powershell - name: Create nsis installer uses: joncloud/makensis-action@v4 with: arguments: "/V3" additional-plugin-paths: NSIS_Plugins/Plugins script-file: src/Windows/nsis/onlineupgrade.nsi - name: CI-Build run: sh ./.github/build32.sh shell: msys2 {0} - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: ./simuwin-gdi32-nightly.zip asset_name: simuwin-gdi32-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-windows64-SDL2-ms.yml000066400000000000000000000024651474050137200243410ustar00rootroot00000000000000# This workflow sets up and runs MSBuild and VSTest # to build and test a Visual Studio solution. name: Nightly Built Windows64 SDL2 on: [push] jobs: winSDL2-64: runs-on: windows-latest steps: - name: Setup MSBuild and add to PATH uses: microsoft/setup-msbuild@v2 - name: Checkout code uses: actions/checkout@v4 id: checkout_code - name: Make NSIS shell: pwsh run: ./.github/prepare-nsis.ps1 - name: Run MSBuild shell: pwsh working-directory: ${{env.GITHUB_WORKSPACE}} run: | vcpkg integrate install msbuild /m .\Simutrans-SDL2.vcxproj -p:Configuration=Release /p:platform=x64 - name: Build zipfile shell: pwsh run: | move-item "build/SDL2/Simutrans SDL2 Nightly.exe" "simutrans/simutrans.exe" move-item "src\Windows\nsis\download-paksets.exe" "simutrans/download-pakset.exe" tools/get_lang_files.ps1 Compress-Archive -Path simutrans -DestinationPath "simuwin64-SDL2-nightly.zip" dir - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: ./simuwin64-SDL2-nightly.zip asset_name: simuwin64-SDL2-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/nightly-windows64-SDL2.broken000066400000000000000000000023721474050137200244000ustar00rootroot00000000000000name: Nightly Built Windows on: [push] jobs: winSDL2-64: runs-on: windows-latest steps: - name: Setup Mingw uses: msys2/setup-msys2@v2 with: msystem: MINGW64 update: true install: git zip unzip svn base-devel mingw-w64-x86_64-toolchain autoconf mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-zstd mingw-w64-x86_64-libpng mingw-w64-x86_64-brotli mingw-w64-x86_64-SDL2 mingw-w64-x86_64-pkg-config - name: Checkout code uses: actions/checkout@v3 - name: Prepares NSIS plugins run: ./.github/prepare-nsis.ps1 shell: powershell - name: Create nsis installer uses: joncloud/makensis-action@v4 with: arguments: "/V3" additional-plugin-paths: NSIS_Plugins/Plugins script-file: src/Windows/nsis/onlineupgrade.nsi - name: CI-Build run: sh ./.github/build64-sdl2.sh shell: msys2 {0} - name: Update binaries of Nightly Release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: ./simuwin64-SDL2-nightly.zip asset_name: simuwin64-SDL2-nightly.zip tag: Nightly overwrite: true simutrans-124.3/.github/workflows/run-tests.yml000066400000000000000000000041251474050137200216410ustar00rootroot00000000000000# # CI for running tests # on: [push] name: Automated Tests jobs: run-tests-linux: runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get -y update sudo apt-get -ym install libbz2-dev zlib1g-dev libpng-dev autoconf clang-18 ccache moreutils - name: Cache uses: actions/cache@v4 with: path: ~/.ccache key: ccache:${{ github.job }}:${{ github.ref }}:${{ github.sha }} restore-keys: | ccache:${{ github.job }}:${{ github.ref }} ccache:${{ github.job }} - name: Configure Simutrans Build run: | autoconf CC="ccache clang" CXX="ccache clang++" ./configure echo "FLAGS += -Wno-cast-align" >> config.default echo "FLAGS += -fsanitize=address,undefined -fno-sanitize-recover=all -fno-sanitize=shift,function" >> config.default echo "LDFLAGS += -fsanitize=address,undefined" >> config.default echo "STATIC := 0" >> config.default - name: Build Simutrans run: | CC="ccache clang" CXX="ccache clang++" make -j$(nproc) - name: Install pak64 run: | pushd simutrans printf '1\ni\ny\n' | ../tools/get_pak.sh popd - name: Install language files run: tools/get_lang_files.sh - name: Link tests as scenario run: | mkdir -p ~/simutrans/addons/pak/scenario ln -sT $GITHUB_WORKSPACE/tests ~/simutrans/addons/pak/scenario/automated-tests - name: Create simuconf run: | mkdir -p ~/simutrans/ echo "frames_per_second = 100" >> ~/simutrans/simuconf.tab echo "fast_forward_frames_per_second = 100" >> ~/simutrans/simuconf.tab - name: Run tests run: | export ASAN_OPTIONS="print_stacktrace=1 abort_on_error=1 detect_leaks=0" export UBSAN_OPTIONS="print_stacktrace=1 abort_on_error=1" cp tools/run-automated-tests.sh . chmod +x run-automated-tests.sh ulimit -St 600 # 10 minutes ought to be enough for anybody. ./run-automated-tests.sh simutrans-124.3/.github/workflows/update-nightly-release.yml000066400000000000000000000013231474050137200242460ustar00rootroot00000000000000name: Update tag on: [push] jobs: update-nightly: runs-on: ubuntu-latest permissions: write-all steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: detect revision run: | echo "revision=`tools/get_revision.sh`" >> $GITHUB_ENV - name: set current head to nightly uses: richardsimko/update-tag@v1 with: tag_name: Nightly env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: rename the release to include revision uses: meeDamian/github-release@2.0 with: token: ${{ secrets.GITHUB_TOKEN }} tag: Nightly name: Nightly build r${{ env.revision }} allow_override: true simutrans-124.3/.gitignore000066400000000000000000000007131474050137200155440ustar00rootroot00000000000000*.ncb *.suo *.vcproj.* /out /Debug /Release build /vcpkg* /config.* /makeobj/makeobj /makeobj/makeobj.exe *sim /sim.exe *.*~ *~ /.build *.orig *.rej /simutrans/*pak* /simutrans/pak* /simutrans/PAK* /simutrans/text *.bdf *.zip *.vcxproj.* /ipch/* *.*sdf *.diff *.patch *.log /doxygen .vs/ revision.h .idea *.d *.res /autom4te.cache *.exe *.kdev4 vcpkg_installed/ UpgradeLog.htm src/linux/com.simutrans.Simutrans.metainfo.xml src/android/AndroidAppSettings.cfg simutrans-124.3/CMakeLists.txt000066400000000000000000000326311474050137200163200ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # cmake_minimum_required(VERSION 3.16) # Disable in-source builds if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "Building Simutrans in-source is not supported. " "Please delete ${CMAKE_SOURCE_DIR}/CMakeCache.txt and configure in a different " "(preferrably empty) directory.") endif (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) set(CMAKE_WARN_DEPRECATED ON) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransVcpkgTriplet.cmake) project(simutrans LANGUAGES C CXX) # Force C++14 everywhere if(SIMUTRANS_STEAM_BUILT) set(CMAKE_CXX_STANDARD 17) else() set(CMAKE_CXX_STANDARD 14) endif() set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS OFF) include(TestBigEndian) TEST_BIG_ENDIAN(SIMUTRANS_BIG_ENDIAN) if (MINGW) set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ON) set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++") endif () if (APPLE) list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/readline") link_directories(/usr/local/lib /opt/homebrew/lib) set(CMAKE_EXE_LINKER_FLAGS "-framework Cocoa") endif () # # Dependencies # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransFindDependencies.cmake) # # Configuration options # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransBackend.cmake) # Select backend (SDL2 / GDI) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransCompileOptions.cmake) # CMake does not fill in CMAKE_BUILD_TYPE automatically. if (NOT MSVC) if (NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "") set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build type. Valid values are Debug Release MinSizeRel RelWithDebInfo" FORCE) endif () set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release MinSizeRel RelWithDebInfo) endif (NOT MSVC) # # sources # if(ANDROID) add_library(simutrans SHARED) target_link_libraries(simutrans PRIVATE android log) target_sources(simutrans PRIVATE src/android/android.cc) else () add_executable(simutrans MACOSX_BUNDLE) endif () if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") set_target_properties(simutrans PROPERTIES WIN32_EXECUTABLE 1) endif () include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransSourceList.cmake) # # output directory # file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/simutrans) set_target_properties( simutrans PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/simutrans/$<0:> ) # # Generate revision on compile time (so only if needed) if no revision is given # if (${SIMUTRANS_USE_REVISION}) file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/src/simutrans/revision.h "#define REVISION ${SIMUTRANS_USE_REVISION}\n") message(STATUS "Compiling Simutrans with manually specified revision ${SIMUTRANS_USE_REVISION}") else () string(FIND ${CMAKE_GENERATOR} "Visual Studio" VS ) if (${VS} EQUAL 0) # using a script for MSVC project files file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/src/simutrans/revision.h "#define REVISION \n") add_custom_command(TARGET simutrans PRE_BUILD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND cscript.exe ARGS "/Nologo tools/revision.jse" COMMENT "Find SVN revision" ) else () # using custom target svnhear that is always built to update the revision.h file using cmake script add_custom_target(svnheader ALL DEPENDS svn_header) add_custom_command(OUTPUT svn_header COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransRevision.cmake) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/simutrans/revision.h PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) add_dependencies(simutrans svnheader) endif () endif () # # Documentation # find_package(Doxygen) if (DOXYGEN_FOUND) if (DOXYGEN_HAVE_DOT) # DOXYGEN_DOT_PATH is deprecated, see # https://cmake.org/cmake/help/latest/module/FindDoxygen.html#variable:DOXYGEN_DOT_PATH get_target_property(graphviz_dot_executable doxygen::dot IMPORTED_LOCATION) get_filename_component(graphviz_dot_temp_dir ${GRAPHVIZ_DOT_EXE} DIRECTORY) file(TO_NATIVE_PATH "${graphviz_dot_temp_dir}" graphviz_dot_dir) endif () configure_file( documentation/Doxyfile.in documentation/Doxyfile @ONLY ) doxygen_add_docs(docs_simutrans CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/documentation/Doxyfile ) add_custom_target(docs DEPENDS docs_simutrans) # The sqapi doxygen file depends on .sh shell scripts to filter files if (LINUX OR MINGW) configure_file( documentation/DoxyfileSQAPI.in documentation/DoxyfileSQAPI @ONLY ) doxygen_add_docs(docs_sqapi CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/documentation/DoxyfileSQAPI WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/simutrans/script/api/ ) add_dependencies(docs docs_sqapi) endif () endif () # # Libraries # target_link_libraries(simutrans PRIVATE PNG::PNG) if (WIN32) target_sources(simutrans PRIVATE src/Windows/simres.rc) target_sources(simutrans PRIVATE src/simutrans/sys/clipboard_w32.cc) target_link_libraries(simutrans PRIVATE ws2_32 winmm) # Backup sound and music routines if the selected backend does not provide any routines set(BACKUP_SOUND src/simutrans/sound/win32_sound_xa.cc) set(BACKUP_MUSIC src/simutrans/music/w32_midi.cc) else () if (SIMUTRANS_BACKEND STREQUAL "sdl2") target_sources(simutrans PRIVATE src/simutrans/sys/clipboard_s2.cc) else () target_sources(simutrans PRIVATE src/simutrans/sys/clipboard_internal.cc) endif () if (APPLE) #Darwin kernel version is used to identify macOS version (16->10.12/Sierra) if (CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 16) #AVF set(BACKUP_SOUND src/simutrans/sound/AVF_core-audio_sound.mm) #AVF MIDI currently crash Simutrans #set(BACKUP_MUSIC src/simutrans/music/AVF_core-audio_midi.mm) set(BACKUP_MUSIC src/simutrans/music/no_midi.cc) else () #QTKit set(BACKUP_SOUND src/simutrans/sound/core-audio_sound.mm) set(BACKUP_MUSIC src/simutrans/music/core-audio_midi.mm) endif () else () set(BACKUP_SOUND src/simutrans/sound/no_sound.cc) set(BACKUP_MUSIC src/simutrans/music/no_midi.cc) endif () endif () if (SIMUTRANS_MULTI_THREAD) target_compile_definitions(simutrans PRIVATE MULTI_THREAD=1) target_link_libraries(simutrans PRIVATE Threads::Threads) endif (SIMUTRANS_MULTI_THREAD) if (SIMUTRANS_BACKEND STREQUAL "sdl2") target_sources(simutrans PRIVATE src/simutrans/display/simgraph16.cc src/simutrans/sys/simsys_s2.cc src/simutrans/sound/sdl2_sound.cc) target_include_directories(simutrans PRIVATE ${SDL2_INCLUDE_DIRS}) if (MINGW) target_link_libraries(simutrans PRIVATE ${SDL2_STATIC_LIBRARIES}) elseif (APPLE) target_link_libraries(simutrans PRIVATE ${SDL2_LIBRARIES}) elseif (MSVC) target_link_libraries(simutrans PRIVATE $ $,SDL2::SDL2,SDL2::SDL2-static>) elseif (ANDROID) target_link_libraries(simutrans PRIVATE SDL2 SDL2main) else () target_link_libraries(simutrans PRIVATE PkgConfig::SDL2) endif () target_compile_definitions(simutrans PRIVATE COLOUR_DEPTH=16) elseif (SIMUTRANS_BACKEND STREQUAL "gdi") target_sources(simutrans PRIVATE src/simutrans/display/simgraph16.cc src/simutrans/sys/simsys_w.cc ${BACKUP_SOUND} ) target_link_libraries(simutrans PRIVATE imm32 xaudio2_8) target_compile_definitions(simutrans PRIVATE COLOUR_DEPTH=16) else () if (NOT SIMUTRANS_BACKEND STREQUAL "none") message(WARNING "Unknown backend '${SIMUTRANS_BACKEND}', falling back to headless compilation") endif () target_sources(simutrans PRIVATE src/simutrans/display/simgraph0.cc src/simutrans/sys/simsys_posix.cc src/simutrans/sound/no_sound.cc src/simutrans/music/no_midi.cc) target_compile_definitions(simutrans PRIVATE COLOUR_DEPTH=0) endif () # # Link dependencies # target_link_libraries(simutrans PRIVATE ZLIB::ZLIB) target_link_libraries(simutrans PRIVATE BZip2::BZip2) # Freetype is mandatory for graphical builds if (SIMUTRANS_BACKEND STREQUAL "sdl2" OR SIMUTRANS_BACKEND STREQUAL "gdi") target_include_directories(simutrans PRIVATE ${Freetype_INCLUDE_DIRS}) if (MINGW) target_link_libraries(simutrans PRIVATE ${Freetype_STATIC_LIBRARIES}) elseif (APPLE) target_link_libraries(simutrans PRIVATE ${Freetype_LIBRARIES}) elseif (MSVC OR ANDROID) target_link_libraries(simutrans PRIVATE Freetype::Freetype) else () target_link_libraries(simutrans PRIVATE PkgConfig::Freetype) endif () if (SIMUTRANS_USE_FONTCONFIG) target_compile_definitions(simutrans PRIVATE USE_FONTCONFIG=1) target_link_libraries(simutrans PRIVATE Fontconfig::Fontconfig) endif () endif () if (SIMUTRANS_USE_UPNP) target_compile_definitions(simutrans PRIVATE USE_UPNP=1) target_link_libraries(simutrans PRIVATE MiniUPNP::MiniUPNP) endif (SIMUTRANS_USE_UPNP) if (SIMUTRANS_USE_ZSTD) target_sources(simutrans PRIVATE src/simutrans/io/rdwr/zstd_file_rdwr_stream.cc) target_include_directories(simutrans PRIVATE ${ZSTD_INCLUDE_DIRS}) target_compile_definitions(simutrans PRIVATE USE_ZSTD=1) if (MSVC) target_link_libraries(simutrans PRIVATE $,zstd::libzstd_shared,zstd::libzstd_static>) elseif (MINGW) # only 64 bit cmake, 32 bit is broken target_link_libraries(simutrans PRIVATE -lzstd) elseif (ANDROID) target_link_libraries(simutrans PRIVATE ZSTD::ZSTD) else() target_link_libraries(simutrans PRIVATE PkgConfig::ZSTD) endif () endif (SIMUTRANS_USE_ZSTD) # only consider FluidSynth for SDL2 and GDI backends if ((SIMUTRANS_BACKEND STREQUAL "sdl2") OR (SIMUTRANS_BACKEND STREQUAL "gdi")) if (SIMUTRANS_USE_FLUIDSYNTH_MIDI) target_sources(simutrans PRIVATE src/simutrans/music/fluidsynth.cc src/simutrans/gui/loadsoundfont_frame.cc) target_compile_definitions(simutrans PRIVATE USE_FLUIDSYNTH_MIDI=1) if (MINGW) # since fluidsynth 2.2.2 fluidsynth.pc include static libraries, but some are still missing target_link_libraries(simutrans PRIVATE ${FluidSynth_STATIC_LIBRARIES} -liconv -lgomp) elseif (MSVC) target_link_libraries(simutrans PRIVATE FluidSynth::libfluidsynth) elseif (ANDROID) target_link_libraries(simutrans PRIVATE fluidsynth) else () target_link_libraries(simutrans PRIVATE PkgConfig::FluidSynth) endif (MINGW) else () target_sources( simutrans PRIVATE ${BACKUP_MUSIC} ) endif (SIMUTRANS_USE_FLUIDSYNTH_MIDI) endif ((SIMUTRANS_BACKEND STREQUAL "sdl2") OR (SIMUTRANS_BACKEND STREQUAL "gdi")) if (SIMUTRANS_STEAM_BUILT AND NOT ANDROID) target_compile_definitions(simutrans PRIVATE STEAM_BUILT=1) target_sources(simutrans PRIVATE src/steam/steam.cc src/steam/workshop_item.cc src/steam/achievements.cc ) add_library(steam SHARED IMPORTED) if(APPLE) set_target_properties(steam PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/osx/libsteam_api.dylib) elseif(UNIX) set_target_properties(steam PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/linux64/libsteam_api.so) elseif(MSVC AND CMAKE_GENERATOR_PLATFORM MATCHES "x64") set_target_properties(steam PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/win64/steam_api64.dll) set_target_properties(steam PROPERTIES IMPORTED_IMPLIB ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/win64/steam_api64.lib) else(MSVC AND CMAKE_GENERATOR_PLATFORM MATCHES "Win32") set_target_properties(steam PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/steam_api.dll) set_target_properties(steam PROPERTIES IMPORTED_IMPLIB ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/steam_api.lib) endif() target_include_directories(simutrans PRIVATE ${CMAKE_SOURCE_DIR}/sdk/public/steam) target_link_libraries(simutrans PRIVATE steam) endif () # # compile options # if (MSVC) target_link_options(simutrans PRIVATE /INCREMENTAL:NO /NODEFAULTLIB:LIBCMTD /MANIFEST:NO /LARGEADDRESSAWARE) endif () if (SIMUTRANS_BIG_ENDIAN) target_compile_definitions(simutrans PRIVATE SIM_BIG_ENDIAN=1) endif () if (SIMUTRANS_VALGRIND_SUPPORT) add_definitions(-DUSE_VALGRIND_MEMCHECK=1) endif () if (SIMUTRANS_ENABLE_PROFILING) add_definitions(-DPROFILE=1) endif () target_compile_options(simutrans PRIVATE ${SIMUTRANS_COMMON_COMPILE_OPTIONS}) target_compile_definitions(simutrans PRIVATE $,DEBUG=1,>) target_compile_definitions(simutrans PRIVATE $,NDEBUG=1,>) target_compile_definitions(simutrans PRIVATE MSG_LEVEL=${SIMUTRANS_MSG_LEVEL}) if (SIMUTRANS_AUTOJOIN_PUBLIC) target_compile_definitions(simutrans PRIVATE AUTOJOIN_PUBLIC=1) endif () if (SIMUTRANS_ENABLE_WATERWAY_SIGNS) target_compile_definitions(simutrans PRIVATE ENABLE_WATERWAY_SIGNS=1) endif () if (SIMUTRANS_USE_SYSLOG) target_compile_definitions(simutrans PRIVATE SYSLOG=1) endif () if (SIMUTRANS_DEBUG_FLUSH_BUFFER) target_compile_definitions(simutrans PRIVATE DEBUG_FLUSH_BUFFER=1) endif () if (SIMUTRANS_USE_IP4_ONLY) target_compile_definitions(simutrans PRIVATE USE_IP4_ONLY=1) endif () if (SIMUTRANS_USE_OWN_PAKINSTALL) target_compile_definitions(simutrans PRIVATE USE_OWN_PAKINSTALL=1) endif () if (APPLE) target_compile_definitions(simutrans PRIVATE ALT_SDL_DIR=1) endif (APPLE) # # Package # if (APPLE) include(MacBundle) endif () # # Tests # add_custom_target(test $ -set_workdir ${CMAKE_CURRENT_SOURCE_DIR}/simutrans -objects pak -scenario automated-tests -debug 2 -lang en -fps 100 DEPENDS simutrans ) # # Installation # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/SimutransInstall.cmake) # # Nettool/Makeobj # if (NOT ANDROID) add_subdirectory(src/makeobj EXCLUDE_FROM_ALL) add_subdirectory(src/nettool EXCLUDE_FROM_ALL) endif () simutrans-124.3/LICENSE.txt000066400000000000000000000134001474050137200153740ustar00rootroot00000000000000This is the simutrans source code. (c) 1997-2004 Hj. Malthaner (c) since 2005 The Simutrans Team Simutrans source code is provided by the current simutrans team (team64@simutrans.com) as copyright holder under the artistic license. This includes the translations from: https://translator.simutrans.com/ the documentation, images and .dat files included in the source distribution, the midi files and the fonts with the exception of the m+10r.bdf, which is taken from the M+ font project: https://mplus-fonts.osdn.jp/ ----------------------------------------------------------------------------- The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: * "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. * "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. * "Copyright Holder" is whoever is named in the copyright or copyrights for the package. * "You" is you, if you're thinking about copying or distributing this Package. * "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) * "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End --------------------------------------------------------------------------- This means, translated to ebay terms: You may not charge for the program, if you charge shipping fees. simutrans-124.3/Makefile000066400000000000000000000703101474050137200152140ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Define variables here to force them as simple flavor. -> Faster parallel builds. FLAGS := CFLAGS ?= LDFLAGS ?= LIBS := SOURCES := STATIC := 0 DYNAMICSTART = DYNAMICEND = CFG ?= default -include config.$(CFG) HOSTCC ?=$(CC) HOSTCXX ?=$(CXX) SDL2_CONFIG ?= pkg-config sdl2 #SDL2_CONFIG ?= sdl2-config FREETYPE_CONFIG ?= pkg-config freetype2 # FREETYPE_CONFIG ?= freetype-config FONTCONFIG_CONFIG ?= pkg-config fontconfig BACKENDS := gdi sdl2 mixer_sdl2 posix OSTYPES := amiga freebsd haiku linux mac mingw openbsd ifeq ($(findstring $(BACKEND), $(BACKENDS)),) $(error Unkown BACKEND "$(BACKEND)", must be one of "$(BACKENDS)") endif ifeq ($(findstring $(OSTYPE), $(OSTYPES)),) $(error Unkown OSTYPE "$(OSTYPE)", must be one of "$(OSTYPES)") endif ifeq ($(BACKEND),posix) COLOUR_DEPTH := 0 else COLOUR_DEPTH := 16 endif # since threads are needed to be linked dynamically on most systems ifdef MULTI_THREAD ifeq ($(shell expr $(MULTI_THREAD) \>= 1), 1) CFLAGS += -DMULTI_THREAD ifneq ($(OSTYPE),mingw) ifneq ($(OSTYPE),haiku) # mingw has already added pthread statically ifneq ($(OSTYPE),mingw) LDFLAGS += -lpthread endif endif endif else ifneq ($(OSTYPE),mingw) ifeq ($(BACKEND),sdl2) LDFLAGS += -lpthread endif ifeq ($(BACKEND),mixer_sdl2) LDFLAGS += -lpthread endif endif endif endif ifeq ($(OSTYPE),amiga) STD_LIBS ?= -lunix -lSDL_mixer -lsmpeg -lvorbisfile -lvorbis -logg CFLAGS += -mcrt=newlib -DSIM_BIG_ENDIAN -gstabs+ LDFLAGS += -Bstatic -non_shared else ifeq ($(OSTYPE),beos) # BeOS (obsolete) LIBS += -lnet else ifeq ($(OSTYPE),freebsd) CFLAGS += -I/usr/local/include else ifeq ($(OSTYPE),haiku) # Haiku (needs to activate the GCC 4x) LIBS += -lnetwork -lbe else ifeq ($(OSTYPE),mingw) CFLAGS += -DPNG_STATIC -DZLIB_STATIC ifeq ($(shell expr $(STATIC) \>= 1), 1) CFLAGS += -static LDFLAGS += -static-libgcc -static-libstdc++ -static endif ifeq ($(MINGW_PACKAGE_PREFIX),mingw-w64-i686) LDFLAGS += -Wl,--large-address-aware endif LDFLAGS += -pthread CFLAGS += -Wno-deprecated-copy -DNOMINMAX -DWIN32_LEAN_AND_MEAN -DWINVER=0x0501 -D_WIN32_IE=0x0500 LIBS += -lmingw32 -lgdi32 -lwinmm -lws2_32 -limm32 # Disable the console on Windows unless WIN32_CONSOLE is set or graphics are disabled ifdef WIN32_CONSOLE ifeq ($(shell expr $(WIN32_CONSOLE) \>= 1), 1) LDFLAGS += -mconsole endif else ifeq ($(BACKEND),posix) LDFLAGS += -mconsole else LDFLAGS += -mwindows endif else ifeq ($(OSTYPE),linux) ifeq ($(shell expr $(STATIC) \>= 1), 1) LDFLAGS += -Wl,-Bstatic -lm DYNAMICSTART = -Wl,-Bdynamic DYNAMICEND = -Wl,-Bstatic endif else ifeq ($(OSTYPE),mac) LDFLAGS += -framework Cocoa endif ifeq ($(BACKEND),sdl2) SOURCES += src/simutrans/sys/clipboard_s2.cc else ifeq ($(OSTYPE),mingw) SOURCES += src/simutrans/sys/clipboard_w32.cc else SOURCES += src/simutrans/sys/clipboard_internal.cc endif LIBS += -lbz2 -lz -lpng ifdef OPTIMISE ifeq ($(shell expr $(OPTIMISE) \>= 1), 1) CFLAGS += -O3 ifeq ($(findstring amiga, $(OSTYPE)),) ifneq ($(findstring clang, $(CXX)),) CFLAGS += -minline-all-stringops endif endif endif else CFLAGS += -O1 endif ifneq ($(LTO),) CFLAGS += -flto LDFLAGS += -flto endif ifdef DEBUG MSG_LEVEL ?= 3 PROFILE ?= 0 ifeq ($(shell expr $(DEBUG) \>= 1), 1) CFLAGS += -g -DDEBUG endif ifeq ($(shell expr $(DEBUG) \>= 2), 1) ifeq ($(shell expr $(PROFILE) \>= 2), 1) CFLAGS += -fno-inline endif endif ifeq ($(shell expr $(DEBUG) \>= 3), 1) ifeq ($(shell expr $(PROFILE) \>= 2), 1) CFLAGS += -O0 endif endif else CFLAGS += -DNDEBUG endif ifdef MSG_LEVEL CFLAGS += -DMSG_LEVEL=$(MSG_LEVEL) endif ifneq ($(BACKEND),posix) ifneq ($(FREETYPE_CONFIG),) CFLAGS += $(shell $(FREETYPE_CONFIG) --cflags) ifeq ($(shell expr $(STATIC) \>= 1), 1) # since static is not supported by slightly old freetype versions FTF := $(shell $(FREETYPE_CONFIG) --libs --static) ifneq ($(FTF),) LDFLAGS += $(subst -lm ,,$(FTF)) else LDFLAGS += $(shell $(FREETYPE_CONFIG) --libs) endif else LDFLAGS += $(shell $(FREETYPE_CONFIG) --libs) endif else LDFLAGS += -lfreetype ifeq ($(OSTYPE),mingw) LDFLAGS += -lpng -lharfbuzz endif endif ifeq ($(OSTYPE),mingw) LDFLAGS += -lfreetype endif ifdef USE_FONTCONFIG ifeq ($(shell expr $(USE_FONTCONFIG) \>= 1), 1) sdfsfsd := $(shell echo error) CFLAGS += -DUSE_FONTCONFIG CFLAGS += $(shell $(FONTCONFIG_CONFIG) --cflags) LDFLAGS += $(shell $(FONTCONFIG_CONFIG) --libs) endif endif endif ifdef USE_UPNP ifeq ($(shell expr $(USE_UPNP) \>= 1), 1) CFLAGS += -DUSE_UPNP LDFLAGS += -lminiupnpc ifeq ($(OSTYPE),mingw) ifeq ($(shell expr $(STATIC) \>= 1), 1) LDFLAGS += -Wl,-Bdynamic endif LDFLAGS += -liphlpapi ifeq ($(shell expr $(STATIC) \>= 1), 1) LDFLAGS += -Wl,-Bstatic endif endif endif endif ifdef USE_ZSTD ifeq ($(shell expr $(USE_ZSTD) \>= 1), 1) CFLAGS += -DUSE_ZSTD LDFLAGS += -lzstd SOURCES += src/simutrans/io/rdwr/zstd_file_rdwr_stream.cc endif endif ifdef USE_FLUIDSYNTH_MIDI ifeq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) CFLAGS += -DUSE_FLUIDSYNTH_MIDI SOURCES += src/simutrans/music/fluidsynth.cc SOURCES += src/simutrans/gui/loadsoundfont_frame.cc LDFLAGS += $(DYNAMICSTART)-lfluidsynth $(DYNAMICEND) ifeq ($(OSTYPE),mingw) # fluidsynth.pc doesn't properly list dependant libraries, unable to use pkg-config. Manually listed below. Only valid for fluidsynth built with options: "-DBUILD_SHARED_LIBS=0 -Denable-aufile=0 -Denable-dbus=0 -Denable-ipv6=0 -Denable-jack=0 -Denable-ladspa=0 -Denable-midishare=0 -Denable-opensles=0 -Denable-oboe=0 -Denable-oss=0 -Denable-readline=0 -Denable-winmidi=0 -Denable-waveout=0 -Denable-libsndfile=0 -Denable-network=0 -Denable-pulseaudio=0 Denable-dsound=1 -Denable-sdl2=0" LDFLAGS += -lglib-2.0 -lintl -liconv -ldsound -lole32 else endif endif else USE_FLUIDSYNTH_MIDI := 0 endif ifdef PROFILE ifeq ($(shell expr $(PROFILE) \>= 1), 1) CFLAGS += -pg -DPROFILE ifeq ($(shell expr $(PROFILE) \>= 2), 1) CFLAGS += -fno-inline ifeq ($(findstring clang, $(CXX)),) CFLAGS += -fno-schedule-insns endif endif LDFLAGS += -pg endif endif ifdef WITH_REVISION ifeq ($(shell expr $(WITH_REVISION) \>= 1), 1) ifeq ($(shell expr $(WITH_REVISION) \>= 2), 1) REV := $(WITH_REVISION) else REV := $(shell tools/get_revision.sh) $(info Revision is $(REV)) endif endif endif ifneq ($(REV),) CFLAGS += -DREVISION=$(REV) DUMMY := $(shell rm -f src/simutrans/revision.h) else ifeq ("$(wildcard src/simutrans/revision.h)","") DUMMY := $(shell printf '#define REVISION' > src/simutrans/revision.h) endif endif ifneq ($(GIT_HASH),) GIT_HASH := $(shell git rev-parse --short=7 HEAD) ifeq ($(.SHELLSTATUS),0) $(info Git hash is 0x$(GIT_HASH)) CFLAGS += -DGIT_HASH=0x$(GIT_HASH) endif endif CFLAGS += -Wall -Wextra -Wcast-qual -Wpointer-arith -Wcast-align $(FLAGS) CCFLAGS += -ansi -Wstrict-prototypes -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 # sources (in alphabetic order) SOURCES += src/simutrans/builder/brueckenbauer.cc SOURCES += src/simutrans/builder/fabrikbauer.cc SOURCES += src/simutrans/builder/goods_manager.cc SOURCES += src/simutrans/builder/hausbauer.cc SOURCES += src/simutrans/builder/tree_builder.cc SOURCES += src/simutrans/builder/tunnelbauer.cc SOURCES += src/simutrans/builder/vehikelbauer.cc SOURCES += src/simutrans/builder/wegbauer.cc SOURCES += src/simutrans/dataobj/crossing_logic.cc SOURCES += src/simutrans/dataobj/environment.cc SOURCES += src/simutrans/dataobj/freelist.cc SOURCES += src/simutrans/dataobj/gameinfo.cc SOURCES += src/simutrans/dataobj/height_map_loader.cc SOURCES += src/simutrans/dataobj/koord.cc SOURCES += src/simutrans/dataobj/koord3d.cc SOURCES += src/simutrans/dataobj/loadsave.cc SOURCES += src/simutrans/dataobj/marker.cc SOURCES += src/simutrans/dataobj/objlist.cc SOURCES += src/simutrans/dataobj/pakset_manager.cc SOURCES += src/simutrans/dataobj/pakset_downloader.cc SOURCES += src/simutrans/dataobj/powernet.cc SOURCES += src/simutrans/dataobj/records.cc SOURCES += src/simutrans/dataobj/rect.cc SOURCES += src/simutrans/dataobj/ribi.cc SOURCES += src/simutrans/dataobj/route.cc SOURCES += src/simutrans/dataobj/scenario.cc SOURCES += src/simutrans/dataobj/schedule.cc SOURCES += src/simutrans/dataobj/settings.cc SOURCES += src/simutrans/dataobj/sve_cache.cc SOURCES += src/simutrans/dataobj/tabfile.cc SOURCES += src/simutrans/dataobj/translator.cc SOURCES += src/simutrans/descriptor/bridge_desc.cc SOURCES += src/simutrans/descriptor/building_desc.cc SOURCES += src/simutrans/descriptor/factory_desc.cc SOURCES += src/simutrans/descriptor/goods_desc.cc SOURCES += src/simutrans/descriptor/ground_desc.cc SOURCES += src/simutrans/descriptor/image.cc SOURCES += src/simutrans/descriptor/obj_base_desc.cc SOURCES += src/simutrans/descriptor/reader/bridge_reader.cc SOURCES += src/simutrans/descriptor/reader/building_reader.cc SOURCES += src/simutrans/descriptor/reader/citycar_reader.cc SOURCES += src/simutrans/descriptor/reader/crossing_reader.cc SOURCES += src/simutrans/descriptor/reader/factory_reader.cc SOURCES += src/simutrans/descriptor/reader/good_reader.cc SOURCES += src/simutrans/descriptor/reader/ground_reader.cc SOURCES += src/simutrans/descriptor/reader/groundobj_reader.cc SOURCES += src/simutrans/descriptor/reader/image_reader.cc SOURCES += src/simutrans/descriptor/reader/imagelist2d_reader.cc SOURCES += src/simutrans/descriptor/reader/imagelist_reader.cc SOURCES += src/simutrans/descriptor/reader/obj_reader.cc SOURCES += src/simutrans/descriptor/reader/pedestrian_reader.cc SOURCES += src/simutrans/descriptor/reader/roadsign_reader.cc SOURCES += src/simutrans/descriptor/reader/root_reader.cc SOURCES += src/simutrans/descriptor/reader/sim_reader.cc SOURCES += src/simutrans/descriptor/reader/skin_reader.cc SOURCES += src/simutrans/descriptor/reader/sound_reader.cc SOURCES += src/simutrans/descriptor/reader/text_reader.cc SOURCES += src/simutrans/descriptor/reader/tree_reader.cc SOURCES += src/simutrans/descriptor/reader/tunnel_reader.cc SOURCES += src/simutrans/descriptor/reader/vehicle_reader.cc SOURCES += src/simutrans/descriptor/reader/way_obj_reader.cc SOURCES += src/simutrans/descriptor/reader/way_reader.cc SOURCES += src/simutrans/descriptor/reader/xref_reader.cc SOURCES += src/simutrans/descriptor/sound_desc.cc SOURCES += src/simutrans/descriptor/tunnel_desc.cc SOURCES += src/simutrans/descriptor/vehicle_desc.cc SOURCES += src/simutrans/descriptor/way_desc.cc SOURCES += src/simutrans/display/font.cc SOURCES += src/simutrans/display/simgraph$(COLOUR_DEPTH).cc SOURCES += src/simutrans/display/simview.cc SOURCES += src/simutrans/display/viewport.cc SOURCES += src/simutrans/freight_list_sorter.cc SOURCES += src/simutrans/ground/boden.cc SOURCES += src/simutrans/ground/brueckenboden.cc SOURCES += src/simutrans/ground/fundament.cc SOURCES += src/simutrans/ground/grund.cc SOURCES += src/simutrans/ground/monorailboden.cc SOURCES += src/simutrans/ground/tunnelboden.cc SOURCES += src/simutrans/ground/wasser.cc SOURCES += src/simutrans/gui/components/gui_aligned_container.cc SOURCES += src/simutrans/gui/components/gui_building.cc SOURCES += src/simutrans/gui/components/gui_button.cc SOURCES += src/simutrans/gui/components/gui_button_to_chart.cc SOURCES += src/simutrans/gui/components/gui_chart.cc SOURCES += src/simutrans/gui/components/gui_colorbox.cc SOURCES += src/simutrans/gui/components/gui_combobox.cc SOURCES += src/simutrans/gui/components/gui_component.cc SOURCES += src/simutrans/gui/components/gui_container.cc SOURCES += src/simutrans/gui/components/gui_convoiinfo.cc SOURCES += src/simutrans/gui/components/gui_divider.cc SOURCES += src/simutrans/gui/components/gui_fixedwidth_textarea.cc SOURCES += src/simutrans/gui/components/gui_flowtext.cc SOURCES += src/simutrans/gui/components/gui_image.cc SOURCES += src/simutrans/gui/components/gui_image_list.cc SOURCES += src/simutrans/gui/components/gui_label.cc SOURCES += src/simutrans/gui/components/gui_map_preview.cc SOURCES += src/simutrans/gui/components/gui_numberinput.cc SOURCES += src/simutrans/gui/components/gui_obj_view.cc SOURCES += src/simutrans/gui/components/gui_schedule.cc SOURCES += src/simutrans/gui/components/gui_scrollbar.cc SOURCES += src/simutrans/gui/components/gui_scrolled_list.cc SOURCES += src/simutrans/gui/components/gui_scrollpane.cc SOURCES += src/simutrans/gui/components/gui_speedbar.cc SOURCES += src/simutrans/gui/components/gui_tab_panel.cc SOURCES += src/simutrans/gui/components/gui_textarea.cc SOURCES += src/simutrans/gui/components/gui_textinput.cc SOURCES += src/simutrans/gui/components/gui_timeinput.cc SOURCES += src/simutrans/gui/components/gui_waytype_tab_panel.cc SOURCES += src/simutrans/gui/components/gui_world_view.cc SOURCES += src/simutrans/gui/ai_option.cc SOURCES += src/simutrans/gui/ai_selector.cc SOURCES += src/simutrans/gui/banner.cc SOURCES += src/simutrans/gui/base_info.cc SOURCES += src/simutrans/gui/baum_edit.cc SOURCES += src/simutrans/gui/chat_frame.cc SOURCES += src/simutrans/gui/city_info.cc SOURCES += src/simutrans/gui/citybuilding_edit.cc SOURCES += src/simutrans/gui/citylist_frame.cc SOURCES += src/simutrans/gui/citylist_stats.cc SOURCES += src/simutrans/gui/climates.cc SOURCES += src/simutrans/gui/convoi_detail.cc SOURCES += src/simutrans/gui/convoi_filter_frame.cc SOURCES += src/simutrans/gui/convoi_frame.cc SOURCES += src/simutrans/gui/convoi_info.cc SOURCES += src/simutrans/gui/convoy_item.cc SOURCES += src/simutrans/gui/curiosity_edit.cc SOURCES += src/simutrans/gui/curiositylist_frame.cc SOURCES += src/simutrans/gui/curiositylist_stats.cc SOURCES += src/simutrans/gui/depot_frame.cc SOURCES += src/simutrans/gui/depotlist_frame.cc SOURCES += src/simutrans/gui/display_settings.cc SOURCES += src/simutrans/gui/enlarge_map_frame.cc SOURCES += src/simutrans/gui/extend_edit.cc SOURCES += src/simutrans/gui/fabrik_info.cc SOURCES += src/simutrans/gui/factory_chart.cc SOURCES += src/simutrans/gui/factory_edit.cc SOURCES += src/simutrans/gui/factorylist_frame.cc SOURCES += src/simutrans/gui/factorylist_stats.cc SOURCES += src/simutrans/gui/goods_frame.cc SOURCES += src/simutrans/gui/goods_stats.cc SOURCES += src/simutrans/gui/ground_info.cc SOURCES += src/simutrans/gui/groundobj_edit.cc SOURCES += src/simutrans/gui/gui_frame.cc SOURCES += src/simutrans/gui/gui_theme.cc SOURCES += src/simutrans/gui/halt_info.cc SOURCES += src/simutrans/gui/halt_list_filter_frame.cc SOURCES += src/simutrans/gui/halt_list_frame.cc SOURCES += src/simutrans/gui/halt_list_stats.cc SOURCES += src/simutrans/gui/headquarter_info.cc SOURCES += src/simutrans/gui/help_frame.cc SOURCES += src/simutrans/gui/jump_frame.cc SOURCES += src/simutrans/gui/kennfarbe.cc SOURCES += src/simutrans/gui/label_info.cc SOURCES += src/simutrans/gui/labellist_frame.cc SOURCES += src/simutrans/gui/labellist_stats.cc SOURCES += src/simutrans/gui/line_item.cc SOURCES += src/simutrans/gui/line_management_gui.cc SOURCES += src/simutrans/gui/load_relief_frame.cc SOURCES += src/simutrans/gui/loadfont_frame.cc SOURCES += src/simutrans/gui/loadsave_frame.cc SOURCES += src/simutrans/gui/map_frame.cc SOURCES += src/simutrans/gui/message_frame.cc SOURCES += src/simutrans/gui/message_option.cc SOURCES += src/simutrans/gui/message_stats.cc SOURCES += src/simutrans/gui/messagebox.cc SOURCES += src/simutrans/gui/minimap.cc SOURCES += src/simutrans/gui/money_frame.cc SOURCES += src/simutrans/gui/obj_info.cc SOURCES += src/simutrans/gui/optionen.cc SOURCES += src/simutrans/gui/pakinstaller.cc SOURCES += src/simutrans/gui/pakselector.cc SOURCES += src/simutrans/gui/password_frame.cc SOURCES += src/simutrans/gui/player_frame.cc SOURCES += src/simutrans/gui/player_ranking_frame.cc SOURCES += src/simutrans/gui/privatesign_info.cc SOURCES += src/simutrans/gui/savegame_frame.cc SOURCES += src/simutrans/gui/scenario_frame.cc SOURCES += src/simutrans/gui/scenario_info.cc SOURCES += src/simutrans/gui/schedule_list.cc SOURCES += src/simutrans/gui/script_generator_frame.cc SOURCES += src/simutrans/gui/script_tool_frame.cc SOURCES += src/simutrans/gui/server_frame.cc SOURCES += src/simutrans/gui/settings_frame.cc SOURCES += src/simutrans/gui/settings_stats.cc SOURCES += src/simutrans/gui/signal_info.cc SOURCES += src/simutrans/gui/signal_spacing.cc SOURCES += src/simutrans/gui/simwin.cc SOURCES += src/simutrans/gui/sound_frame.cc SOURCES += src/simutrans/gui/sprachen.cc SOURCES += src/simutrans/gui/station_building_select.cc SOURCES += src/simutrans/gui/themeselector.cc SOURCES += src/simutrans/gui/tool_selector.cc SOURCES += src/simutrans/gui/trafficlight_info.cc SOURCES += src/simutrans/gui/vehiclelist_frame.cc SOURCES += src/simutrans/gui/welt.cc SOURCES += src/simutrans/io/classify_file.cc SOURCES += src/simutrans/io/raw_image.cc SOURCES += src/simutrans/io/raw_image_bmp.cc SOURCES += src/simutrans/io/raw_image_png.cc SOURCES += src/simutrans/io/raw_image_ppm.cc SOURCES += src/simutrans/io/rdwr/adler32_stream.cc SOURCES += src/simutrans/io/rdwr/bzip2_file_rdwr_stream.cc SOURCES += src/simutrans/io/rdwr/compare_file_rd_stream.cc SOURCES += src/simutrans/io/rdwr/raw_file_rdwr_stream.cc SOURCES += src/simutrans/io/rdwr/rdwr_stream.cc SOURCES += src/simutrans/io/rdwr/zlib_file_rdwr_stream.cc SOURCES += src/simutrans/network/checksum.cc SOURCES += src/simutrans/network/memory_rw.cc SOURCES += src/simutrans/network/network.cc SOURCES += src/simutrans/network/network_address.cc SOURCES += src/simutrans/network/network_cmd.cc SOURCES += src/simutrans/network/network_cmd_ingame.cc SOURCES += src/simutrans/network/network_cmd_scenario.cc SOURCES += src/simutrans/network/network_cmp_pakset.cc SOURCES += src/simutrans/network/network_file_transfer.cc SOURCES += src/simutrans/network/network_packet.cc SOURCES += src/simutrans/network/network_socket_list.cc SOURCES += src/simutrans/network/pakset_info.cc SOURCES += src/simutrans/obj/baum.cc SOURCES += src/simutrans/obj/bruecke.cc SOURCES += src/simutrans/obj/crossing.cc SOURCES += src/simutrans/obj/depot.cc SOURCES += src/simutrans/obj/field.cc SOURCES += src/simutrans/obj/gebaeude.cc SOURCES += src/simutrans/obj/groundobj.cc SOURCES += src/simutrans/obj/label.cc SOURCES += src/simutrans/obj/leitung2.cc SOURCES += src/simutrans/obj/pillar.cc SOURCES += src/simutrans/obj/roadsign.cc SOURCES += src/simutrans/obj/signal.cc SOURCES += src/simutrans/obj/simobj.cc SOURCES += src/simutrans/obj/tunnel.cc SOURCES += src/simutrans/obj/way/kanal.cc SOURCES += src/simutrans/obj/way/maglev.cc SOURCES += src/simutrans/obj/way/monorail.cc SOURCES += src/simutrans/obj/way/narrowgauge.cc SOURCES += src/simutrans/obj/way/runway.cc SOURCES += src/simutrans/obj/way/schiene.cc SOURCES += src/simutrans/obj/way/strasse.cc SOURCES += src/simutrans/obj/way/weg.cc SOURCES += src/simutrans/obj/wayobj.cc SOURCES += src/simutrans/obj/wolke.cc SOURCES += src/simutrans/obj/zeiger.cc SOURCES += src/simutrans/old_blockmanager.cc SOURCES += src/simutrans/player/ai.cc SOURCES += src/simutrans/player/ai_goods.cc SOURCES += src/simutrans/player/ai_passenger.cc SOURCES += src/simutrans/player/ai_scripted.cc SOURCES += src/simutrans/player/finance.cc SOURCES += src/simutrans/player/simplay.cc SOURCES += src/simutrans/script/api/api_city.cc SOURCES += src/simutrans/script/api/api_command.cc SOURCES += src/simutrans/script/api/api_const.cc SOURCES += src/simutrans/script/api/api_control.cc SOURCES += src/simutrans/script/api/api_convoy.cc SOURCES += src/simutrans/script/api/api_factory.cc SOURCES += src/simutrans/script/api/api_gui.cc SOURCES += src/simutrans/script/api/api_halt.cc SOURCES += src/simutrans/script/api/api_include.cc SOURCES += src/simutrans/script/api/api_line.cc SOURCES += src/simutrans/script/api/api_map_objects.cc SOURCES += src/simutrans/script/api/api_obj_desc.cc SOURCES += src/simutrans/script/api/api_obj_desc_base.cc SOURCES += src/simutrans/script/api/api_pathfinding.cc SOURCES += src/simutrans/script/api/api_player.cc SOURCES += src/simutrans/script/api/api_scenario.cc SOURCES += src/simutrans/script/api/api_schedule.cc SOURCES += src/simutrans/script/api/api_settings.cc SOURCES += src/simutrans/script/api/api_simple.cc SOURCES += src/simutrans/script/api/api_tiles.cc SOURCES += src/simutrans/script/api/api_world.cc SOURCES += src/simutrans/script/api/export_desc.cc SOURCES += src/simutrans/script/api/get_next.cc SOURCES += src/simutrans/script/api_class.cc SOURCES += src/simutrans/script/api_function.cc SOURCES += src/simutrans/script/api_param.cc SOURCES += src/simutrans/script/dynamic_string.cc SOURCES += src/simutrans/script/export_objs.cc SOURCES += src/simutrans/script/script.cc SOURCES += src/simutrans/script/script_loader.cc SOURCES += src/simutrans/script/script_tool_manager.cc SOURCES += src/simutrans/simachievements.cc SOURCES += src/simutrans/simconvoi.cc SOURCES += src/simutrans/simdebug.cc SOURCES += src/simutrans/simevent.cc SOURCES += src/simutrans/simfab.cc SOURCES += src/simutrans/simhalt.cc SOURCES += src/simutrans/siminteraction.cc SOURCES += src/simutrans/simintr.cc SOURCES += src/simutrans/simio.cc SOURCES += src/simutrans/simline.cc SOURCES += src/simutrans/simlinemgmt.cc SOURCES += src/simutrans/simloadingscreen.cc SOURCES += src/simutrans/simmain.cc SOURCES += src/simutrans/simmem.cc SOURCES += src/simutrans/simmesg.cc SOURCES += src/simutrans/simskin.cc SOURCES += src/simutrans/simsound.cc SOURCES += src/simutrans/simticker.cc SOURCES += src/simutrans/simware.cc SOURCES += src/simutrans/sys/simsys.cc SOURCES += src/simutrans/tool/simmenu.cc SOURCES += src/simutrans/tool/simtool-script-generator.cc SOURCES += src/simutrans/tool/simtool-scripted.cc SOURCES += src/simutrans/tool/simtool.cc SOURCES += src/simutrans/utils/cbuffer.cc SOURCES += src/simutrans/utils/checklist.cc SOURCES += src/simutrans/utils/csv.cc SOURCES += src/simutrans/utils/log.cc SOURCES += src/simutrans/utils/searchfolder.cc SOURCES += src/simutrans/utils/sha1.cc SOURCES += src/simutrans/utils/sha1_hash.cc SOURCES += src/simutrans/utils/simrandom.cc SOURCES += src/simutrans/utils/simstring.cc SOURCES += src/simutrans/utils/simthread.cc SOURCES += src/simutrans/utils/unicode.cc SOURCES += src/simutrans/vehicle/air_vehicle.cc SOURCES += src/simutrans/vehicle/movingobj.cc SOURCES += src/simutrans/vehicle/pedestrian.cc SOURCES += src/simutrans/vehicle/rail_vehicle.cc SOURCES += src/simutrans/vehicle/road_vehicle.cc SOURCES += src/simutrans/vehicle/simroadtraffic.cc SOURCES += src/simutrans/vehicle/vehicle.cc SOURCES += src/simutrans/vehicle/vehicle_base.cc SOURCES += src/simutrans/vehicle/water_vehicle.cc SOURCES += src/simutrans/world/placefinder.cc SOURCES += src/simutrans/world/simcity.cc SOURCES += src/simutrans/world/simplan.cc SOURCES += src/simutrans/world/simworld.cc SOURCES += src/simutrans/world/surface.cc SOURCES += src/simutrans/world/terraformer.cc SOURCES += src/squirrel/sq_extensions.cc SOURCES += src/squirrel/sqstdlib/sqstdaux.cc SOURCES += src/squirrel/sqstdlib/sqstdblob.cc SOURCES += src/squirrel/sqstdlib/sqstdio.cc SOURCES += src/squirrel/sqstdlib/sqstdmath.cc SOURCES += src/squirrel/sqstdlib/sqstdrex.cc SOURCES += src/squirrel/sqstdlib/sqstdstream.cc SOURCES += src/squirrel/sqstdlib/sqstdstring.cc SOURCES += src/squirrel/sqstdlib/sqstdsystem.cc SOURCES += src/squirrel/squirrel/sqapi.cc SOURCES += src/squirrel/squirrel/sqbaselib.cc SOURCES += src/squirrel/squirrel/sqclass.cc SOURCES += src/squirrel/squirrel/sqcompiler.cc SOURCES += src/squirrel/squirrel/sqdebug.cc SOURCES += src/squirrel/squirrel/sqfuncstate.cc SOURCES += src/squirrel/squirrel/sqlexer.cc SOURCES += src/squirrel/squirrel/sqmem.cc SOURCES += src/squirrel/squirrel/sqobject.cc SOURCES += src/squirrel/squirrel/sqstate.cc SOURCES += src/squirrel/squirrel/sqtable.cc SOURCES += src/squirrel/squirrel/sqvm.cc ifeq ($(BACKEND),gdi) SOURCES += src/simutrans/sys/simsys_w.cc SOURCES += src/simutrans/sound/win32_sound_xa.cc LDFLAGS += -lxaudio2_8 ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) SOURCES += src/simutrans/music/w32_midi.cc endif endif ifeq ($(BACKEND),sdl2) SOURCES += src/simutrans/sys/simsys_s2.cc ifeq ($(OSTYPE),mac) AV_FOUNDATION ?= 0 ifeq ($(shell expr $(AV_FOUNDATION) \>= 1), 1) # Core Audio (AVFoundation) base sound system routines SOURCES += src/simutrans/sound/AVF_core-audio_sound.mm LIBS += -framework Foundation -framework AVFoundation ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) SOURCES += src/simutrans/music/AVF_core-audio_midi.mm endif else # Core Audio (Quicktime) base sound system routines SOURCES += src/simutrans/sound/core-audio_sound.mm LIBS += -framework Foundation -framework QTKit ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) SOURCES += src/simutrans/music/core-audio_midi.mm endif endif else SOURCES += src/simutrans/sound/sdl2_sound.cc ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) ifneq ($(OSTYPE),mingw) SOURCES += src/simutrans/music/no_midi.cc else SOURCES += src/simutrans/music/w32_midi.cc endif endif endif ifeq ($(SDL2_CONFIG),) ifeq ($(OSTYPE),mac) SDL_CFLAGS := -F /Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers SDL_LDFLAGS := -framework SDL2 -F /Library/Frameworks -I /Library/Frameworks/SDL2.framework/Headers else SDL_CFLAGS := -I$(MINGDIR)/include/SDL2 -Dmain=SDL_main SDL_LDFLAGS := -lSDL2main -lSDL2 endif else SDL_CFLAGS := $(shell $(SDL2_CONFIG) --cflags) SDL_LDFLAGS := $(DYNAMICSTART) $(shell $(SDL2_CONFIG) --libs) $(DYNAMICEND) ifeq ($(shell expr $(STATIC) \>= 1), 1) ifeq ($(OSTYPE),mingw) SDL_LDFLAGS = $(shell $(SDL2_CONFIG) --static --libs) endif endif endif CFLAGS += $(SDL_CFLAGS) LIBS += $(SDL_LDFLAGS) endif ifeq ($(BACKEND),mixer_sdl2) SOURCES += src/simutrans/sys/simsys_s2.cc ifeq ($(SDL2_CONFIG),) ifeq ($(OSTYPE),mac) SDL_CFLAGS := -F /Library/Frameworks -I/Library/Frameworks/SDL2.framework/Headers SDL_LDFLAGS := -framework SDL2 -F /Library/Frameworks -I /Library/Frameworks/SDL2.framework/Headers else SDL_CFLAGS := -I$(MINGDIR)/include/SDL2 -Dmain=SDL_main SDL_LDFLAGS := -lSDL2main -lSDL2 endif else SOURCES += src/simutrans/sound/sdl_mixer_sound.cc SOURCES += src/simutrans/music/sdl_midi.cc SDL_CFLAGS := $(shell $(SDL2_CONFIG) --cflags) SDL_LDFLAGS := $(DYMANICSTART) $(shell $(SDL2_CONFIG) --libs) -lSDL2_mixer $(DYNAMICEND) ifeq ($(shell expr $(STATIC) \>= 1), 1) ifeq ($(OSTYPE),mingw) SDL_LDFLAGS = $(shell $(SDL2_CONFIG) --static --libs) -lSDL2_mixer endif endif endif CFLAGS += $(SDL_CFLAGS) LIBS += $(SDL_LDFLAGS) endif ifeq ($(BACKEND),posix) SOURCES += src/simutrans/sys/simsys_posix.cc SOURCES += src/simutrans/music/no_midi.cc SOURCES += src/simutrans/sound/no_sound.cc endif CFLAGS += -DCOLOUR_DEPTH=$(COLOUR_DEPTH) ifeq ($(OSTYPE),mingw) SOURCES += src/Windows/simres.rc ifneq ($(REV),) WINDRES ?= windres -DREVISION=$(REV) else WINDRES ?= windres -DREVISION endif endif CCFLAGS += $(CFLAGS) CXXFLAGS += $(CFLAGS) # static linking everything but SDL2 works is the best one can do on Linux ... ifeq ($(OSTYPE),linux) ifeq ($(shell expr $(STATIC) \>= 1), 1) LIBS += -static-libgcc -static-libstdc++ ifeq ($(BACKEND),posix) LIBS += -static endif endif endif BUILDDIR ?= build/$(CFG) PROGDIR ?= $(BUILDDIR) PROG ?= sim .DEFAULT_GOAL := simutrans .PHONY: simutrans makeobj nettool include common.mk ifeq ($(OSTYPE),mac) include OSX/osx.mk endif all: simutrans makeobj nettool makeobj: @echo "Building makeobj" $(Q)$(MAKE) -e -C src/makeobj FLAGS="$(FLAGS)" nettool: @echo "Building nettool" $(Q)$(MAKE) -e -C src/nettool FLAGS="$(FLAGS)" test: simutrans $(PROGDIR)/$(PROG) -set_basedir $(shell pwd)/simutrans -objects pak -scenario automated-tests -debug 2 -lang en -fps 100 clean: @echo "===> Cleaning up" $(Q)rm -f $(OBJS) $(Q)rm -f $(DEPS) $(Q)rm -f $(PROGDIR)/$(PROG) $(Q)rm -fr $(PROGDIR)/$(PROG).app $(Q)$(MAKE) -e -C src/makeobj clean $(Q)$(MAKE) -e -C src/nettool clean simutrans-124.3/README.html000066400000000000000000000277071474050137200154130ustar00rootroot00000000000000 About the Simutrans Code

Simutrans

1) About

Simutrans is a freeware and open-source transportation simulator. Your goal is to establish a successful transport company. Transport passengers, mail and goods by rail, road, ship, and even air. Interconnect districts, cities, public buildings, industries and tourist attractions by building a transport network you always dreamed of.

1.1) Download Simutrans

You can download Simutrans from:

There is a "nightly" version available, but most most people should use the last "stable" release.

Main sites

Help

Additional downloads

2) Compiling Simutrans

This is a short guide on compiling simutrans. If you want more detailed information, read the Compiling Simutrans wiki page.

If you are on Windows, download either Microsoft Visual Studio or MSYS2. MSVC is easy for debugging, MSYS2 is easy to set up (but it has to be done on the command line).

2.1) Getting the Source Code

You can download the latest version with a SVN client:

svn checkout svn://servers.simutrans.org/simutrans/trunk

If you prefer to use git, there is a mirror of the svn repository available at github:

git clone http://github.com/simutrans/simutrans.git

Note that the svn repository is the main repository, and the git repository is just a mirror. If you use git instead of svn, you will need to set the game version manually to join a network game.

2.2) Getting the libraries

This is a list of libraries used by Simutrans. Not all of them are necessary, some are optional, so pick them according to your needs. Read below about how to install them.

Library Website Necessary? Notes
zlib https://zlib.net/ Necessary Basic compression support
bzip2 https://www.bzip.org/downloads.html Necessary Alternative compression. You can pick this or zstd
libpng http://www.libpng.org/pub/png/ Necessary Image manipulation
libSDL2 http://www.libsdl.org/ Necessary* *On Linux & Mac. Optional but recommended for Windows. Graphics back-end
libzstd https://github.com/facebook/zstd Optional Alternative compression (larger save files than bzip2, but faster)
libfreetype http://www.freetype.org/ Necessary TrueType font support
libminiupnpc http://miniupnp.free.fr/ Optional Easy Server option
libfluidsynth https://www.fluidsynth.org/ Optional MIDI playback recommended on Linux & temporarily on Mac
libSDL2_mixer http://www.libsdl.org/ Optional Alternative MIDI playback and sound system
libfontconfig https://www.fontconfig.org/ Optional Font autodetection (Linux/Mac)

You will also need pkgconfig (Unix) or vcpkg (Microsoft Visual C++)

  • MSVC: Should compile the needed libraries automatically, if VCPKG is installed. Alternative, copy install-building-libs-.bat to the vcpkg folder and run it.
  • MSYS2: Run [setup-mingw.sh] (tools/setup-mingw.sh) to get the libraries and set up the environment.
  • Ubuntu/Debian: Run [setup-debian.sh] (tools/setup-debian.sh) to get the libraries and set up the environment.
  • Linux: Use pkgs.org to search for development libraries available in your package manager.
  • Mac: Install libraries via [Homebrew] (https://brew.sh/). Some guidance can be found in the github directory.

2.3) Compiling

Go to the source code directory of simutrans (simutrans/trunk if you downloaded from svn). You have three build systems to choose from: make, MSVC, and CMake. We recommend make or MSVC for debug builds, cmake for MacOS and Android.

Compiling will give you only the executable, you still need a Simutrans installation to run the program. You can start simutrans with -use_workdir to point it to an existing installation.

2.3.1) Compiling with make

The executable will be built in build/default.

(Linux) autoconf
(MacOS) autoreconf -ivf
./configure
make -j 4
(MacOS) make OSX/getversion

2.3.2) Compiling with Microsoft Visual Studio

Simutrans solution is a single solution file simutrans.sln with 4 projects:

  • Simutrans-Main: The project that holds the shared, non back-end specific, files. All the followings use Main to build the specific back-end executables.
  • Simutrans SDL2: Preferred back-end for Simutrans.
  • Simutrans GDI: Windows-only back-end.
  • Simutrans Server: Server back-end with no graphical interface.

Select on of them as startup project and in the configuration manager compile it.

2.3.3) Compiling with CMake

The executable will be built in build/simutrans.

Commandline on Linux/MinGW/MacOS ...
cmake -G "Insert Correct Makefiles Generator" -B build .
cmake --build build -j 4

See here for a list of generators.

MSVC
mkdir build && cd build
cmake.exe .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake
cmake --build . --config Release

2.4) Cross-Compiling

If you want to cross-compile Simutrans from Linux for Windows, see the Cross-Compiling Simutrans wiki page.

3) Contribute

You cand find general information about contributing to Simutrans in the Development Index of the wiki.

3.1) Coding

  • If you want to contribute, read the coding guidelines in simutrans/documentation/coding_styles.txt
  • You definitely should check out the Technical Documentation Sub-Forum as well.
  • Do not open Pull Requests in GitHub. Use the Patches & Projects Sub-Forum instead.

3.2) Translating

Simutrans is constantly updating and adding texts so we are always in need for translators:

3.3) Painting

Simutrans is always looking for artists! If you want to paint graphics for Simutrans, check:

3.4) Reporting bugs

For bug reports use the Bug Reports Sub-Forum.

4) License

Simutrans is licensed under the Artistic License version 1.0. The Artistic License 1.0 is an OSI-approved license which allows for use, distribution, modification, and distribution of modified versions, under the terms of the Artistic License 1.0. For the complete license text see LICENSE.txt.

Simutrans paksets (which are necessary to run the game) have their own license, but no one is included alongside this code.

5) Credits

Simutrans was originally written by Hansjörg Malthaner "Hajo" from 1997 until he retired from development around 2004. Since then a team of contributors (The Simutrans Team) lead by Markus Pristovsek "Prissi" is developing Simutrans.

A list of early contributors can be found in simutrans/thanks.txt

simutrans-124.3/README.md000066400000000000000000000232451474050137200150400ustar00rootroot00000000000000# Simutrans - 1.0) [About](#1-about) - 1.1) [Download Simutrans](#11-download-simutrans) - 1.2) [Helpful links](#12-helpful-links) - 2.0) [Compiling Simutrans](#2-compiling-simutrans) - 2.1) [Getting the Source Code](#21-getting-the-source-code) - 2.2) [Getting the libraries](#22-getting-the-libraries) - 2.3) [Compiling](#23-compiling) - 2.3.1) [Compiling with make](#232-compiling-with-make) - 2.3.2) [Compiling with MSVC](#233-compiling-with-microsoft-visual-studio) - 2.3.3) [Compiling with CMake](#231-compiling-with-cmake) - 2.4) [Cross-Compiling](#24-Cross-Compiling) - 3.0) [Contribute](#3-contribute) - 3.1) [Coding](#31-coding) - 3.2) [Getting the libraries](#32-translating) - 3.3) [Painting](#33-painting) - 3.4) [Reporting-bugs](#34-reporting-bugs) - 4.0) [License](#4-license) - 5.0) [Credits](#5-credits) ## 1) About Simutrans is a freeware and open-source transportation simulator. Your goal is to establish a successful transport company. Transport passengers, mail and goods by rail, road, ship, and even air. Interconnect districts, cities, public buildings, industries and tourist attractions by building a transport network you always dreamed of. ## 1.1) Download Simutrans You can download Simutrans from: - [Simutrans Official Website](https://www.simutrans.com/en/) - [Steam](https://store.steampowered.com/app/434520/Simutrans/) - [Linux package managers](https://pkgs.org/search/?q=simutrans) There is a "nightly" version available, but most most people should use the last "stable" release. ## 1.2) Helpful links ### Main sites - [Main website](https://www.simutrans.com/) - [International Forum](https://forum.simutrans.com/) - [German Forumurl](https://www.simutrans-forum.de/) - [Japanese Forum](https://forum.japanese.simutrans.com/) ### Help - [Simutrans Wiki](https://wiki.simutrans.com) - [Starter Guide (PDF)](http://simutrans.igoreliezer.com/docs/Simutrans%20Starter%20Guide.pdf) - [Help Center (International Forum)](https://forum.simutrans.com/index.php/board,7.0.html) ### Additional downloads - [Paksets](https://www.simutrans.com/en/paksets/) - [Addons](https://simutrans-germany.com/wiki/wiki/en_Addons) ## 2) Compiling Simutrans This is a short guide on compiling simutrans. If you want more detailed information, read the [Compiling Simutrans](https://simutrans-germany.com/wiki/wiki/en_CompilingSimutrans) wiki page. If you are on Windows, download either [Microsoft Visual Studio](https://visualstudio.microsoft.com/) or [MSYS2](https://www.msys2.org/). MSVC is easy for debugging, MSYS2 is easy to set up (but it has to be done on the command line). ### 2.1) Getting the Source Code You can download the latest version with a SVN client: ``` svn checkout svn://servers.simutrans.org/simutrans/trunk ``` If you prefer to use git, there is a mirror of the svn repository available at github: ``` git clone http://github.com/simutrans/simutrans.git ``` Note that the svn repository is the main repository, and the git repository is just a mirror. If you use git instead of svn, you will need to set the game version manually to join a network game. ### 2.2) Getting the libraries This is a list of libraries used by Simutrans. Not all of them are necessary, some are optional, so pick them according to your needs. Read below about how to install them. | Library | Website | Necessary? | Notes | |---------------|-------------------------------------|------------|---------------------------------------------------------------------------| | zlib | https://zlib.net/ | Necessary | Basic compression support | | bzip2 | https://www.bzip.org/downloads.html | Necessary | Alternative compression. You can pick this or zstd | | libpng | http://www.libpng.org/pub/png/ | Necessary | Image manipulation | | libSDL2 | http://www.libsdl.org/ | Necessary* | *On Linux & Mac. Optional but recommended for Windows. Graphics back-end | | libzstd | https://github.com/facebook/zstd | Optional | Alternative compression (larger save files than bzip2, but faster) | | libfreetype | http://www.freetype.org/ | Necessary | TrueType font support | | libminiupnpc | http://miniupnp.free.fr/ | Optional | Easy Server option | | libfluidsynth | https://www.fluidsynth.org/ | Optional | MIDI playback recommended on Linux & temporarily on Mac | | libSDL2_mixer | http://www.libsdl.org/ | Optional | Alternative MIDI playback and sound system | | libfontconfig | https://www.fontconfig.org/ | Optional | Font autodetection (Linux/Mac) | You will also need pkgconfig (Unix) or [vcpkg](https://github.com/Microsoft/vcpkg) (Microsoft Visual C++) - MSVC: Should compile the needed libraries automatically, if VCPKG is installed. Alternative, copy install-building-libs-{architecture}.bat to the vcpkg folder and run it. - MSYS2: Run [setup-mingw.sh] (tools/setup-mingw.sh) to get the libraries and set up the environment. - Ubuntu/Debian: Run [setup-debian.sh] (tools/setup-debian.sh) to get the libraries and set up the environment. - Linux: Use [pkgs.org](https://pkgs.org/) to search for development libraries available in your package manager. - Mac: Install libraries via [Homebrew] (https://brew.sh/). Some guidance can be found in the github directory. ### 2.3) Compiling Go to the source code directory of simutrans (simutrans/trunk if you downloaded from svn). You have three build systems to choose from: make, MSVC, and CMake. We recommend make or MSVC for debug builds, cmake for MacOS and Android. Compiling will give you only the executable, you still need a Simutrans installation to run the program. You can start simutrans with `-use_workdir` to point it to an existing installation. #### 2.3.1) Compiling with make The executable will be built in build/default. ``` (Linux) autoconf (MacOS) autoreconf -ivf ./configure make -j 4 (MacOS) make OSX/getversion ``` #### 2.3.2) Compiling with Microsoft Visual Studio Simutrans solution is a single solution file [simutrans.sln](./simutrans.sln) with 4 projects: - Simutrans-Main: The project that holds the shared, non back-end specific, files. All the followings use Main to build the specific back-end executables. - Simutrans SDL2: Preferred back-end for Simutrans. - Simutrans GDI: Windows-only back-end. - Simutrans Server: Server back-end with no graphical interface. Select on of them as startup project and in the configuration manager compile it. #### 2.3.3) Compiling with CMake The executable will be built in build/simutrans. ##### Commandline on Linux/MinGW/MacOS ... ``` cmake -G "Insert Correct Makefiles Generator" -B build . cmake --build build -j 4 ``` See [here](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) for a list of generators. ##### MSVC ``` mkdir build && cd build cmake.exe .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake cmake --build . --config Release ``` ### 2.4) Cross-Compiling If you want to cross-compile Simutrans from Linux for Windows, see the [Cross-Compiling Simutrans](https://simutrans-germany.com/wiki/wiki/en_Cross-Compiling_Simutrans) wiki page. ## 3) Contribute You cand find general information about contributing to Simutrans in the [Development Index](https://simutrans-germany.com/wiki/wiki/en_Devel_Index?structure=en_Devel_Index) of the wiki. ### 3.1) Coding - If you want to contribute, read the coding guidelines in simutrans/documentation/coding_styles.txt - You definitely should check out the [Technical Documentation Sub-Forum](https://forum.simutrans.com/index.php/board,112.0.html) as well. - **Do not open Pull Requests** in GitHub. Use the [Patches & Projects](https://forum.simutrans.com/index.php/board,33.0.html) Sub-Forum instead. ### 3.2) Translating Simutrans is constantly updating and adding texts so we are always in need for translators: - To help with translation use the [SimuTranslator](https://translator.simutrans.com/) web tool. - To request a translator account use the [Translation Sub-Forum](https://forum.simutrans.com/index.php/board,47.0.html). ### 3.3) Painting Simutrans is always looking for artists! If you want to paint graphics for Simutrans, check: - The "Creating images" section of the [Development Index](https://simutrans-germany.com/wiki/wiki/en_Devel_Index). - The [General Resources and Tools](https://forum.simutrans.com/index.php/board,108.0.html) Sub-Forum. ### 3.4) Reporting bugs For bug reports use the [Bug Reports](https://forum.simutrans.com/index.php/board,8.0.html) Sub-Forum. ## 4) License Simutrans is licensed under the Artistic License version 1.0. The Artistic License 1.0 is an OSI-approved license which allows for use, distribution, modification, and distribution of modified versions, under the terms of the Artistic License 1.0. For the complete license text see [LICENSE.txt](./LICENSE.txt). Simutrans paksets (which are necessary to run the game) have their own license, but no one is included alongside this code. ## 5) Credits Simutrans was originally written by Hansjörg Malthaner "Hajo" from 1997 until he retired from development around 2004. Since then a team of contributors (The Simutrans Team) lead by Markus Pristovsek "Prissi" is developing Simutrans. A list of early contributors can be found in [simutrans/thanks.txt](./simutrans/thanks.txt) simutrans-124.3/Simutrans-GDI.vcxproj000066400000000000000000000235051474050137200175630ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 Stable Win32 Stable x64 {0621B295-BEB7-4767-82F1-F27995610323} Simutrans Simutrans GDI x86-windows-static x64-windows-static Application $(DefaultPlatformToolset) true true true <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)build\GDI\ $(SolutionDir)build\GDI\$(Configuration)\ $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(ProjectName) Debug false $(ProjectName) Nightly false false true true true true x64-windows-static true x64-windows-static true x64-windows-static true Level3 true true 4250;4373;4800;4996;26812;26451 true false Windows true ProgramDatabase Disabled USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;DEBUG=3;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP MultiThreaded EnableFastChecks kernel32.lib;user32.lib;gdi32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib;Xaudio2.lib;iphlpapi.lib true false false true USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP tools/get_revision.bat Obtain SVN revision number true true true ProgramDatabase MaxSpeed true Speed MultiThreaded true true true true kernel32.lib;user32.lib;gdi32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib;Xaudio2.lib;iphlpapi.lib false true true true simutrans-124.3/Simutrans-GDI.vcxproj.filters000066400000000000000000003174361474050137200212430ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source 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 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 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 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 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 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 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 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 Header Files Header Files Header Files Header Files Header Files Header Files Resource Files simutrans-124.3/Simutrans-Main.vcxitems000066400000000000000000002056751474050137200202250ustar00rootroot00000000000000 $(MSBuildAllProjects);$(MSBuildThisFileFullPath) true {5a9777dd-ce40-45ae-8cb4-0ff2db4abd27} %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)src\simutrans\ simutrans-124.3/Simutrans-Main.vcxitems.filters000066400000000000000000003201361474050137200216620ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source 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 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 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 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 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 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 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 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 Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Resource Files simutrans-124.3/Simutrans-SDL2.vcxproj000066400000000000000000000236521474050137200176670ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 Stable Win32 Stable x64 {E74757E8-C2FD-44AD-87BD-3D55F4709484} Simutrans Simutrans SDL2 x86-windows-static x64-windows-static Application $(DefaultPlatformToolset) true true true <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)build\SDL2\ $(SolutionDir)build\SDL2\$(Configuration)\ $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(ProjectName) Debug false $(ProjectName) Nightly false false true true true true Level3 true true 4250;4373;4800;4996;26812;26451 true false Windows true ProgramDatabase Disabled USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;DEBUG=3;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP MultiThreaded EnableFastChecks kernel32.lib;user32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib;iphlpapi.lib;OleAut32.lib;GDI32.lib;version.lib;Ole32.lib;SetupAPI.lib;urlmon.lib true false false true USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP USE_ZSTD;USE_UPNP;COLOUR_DEPTH=16;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP tools/get_revision.bat Obtain SVN revision number true true false true true MaxSpeed true Speed MultiThreaded true true true true false false true true kernel32.lib;user32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib;iphlpapi.lib;OleAut32.lib;GDI32.lib;version.lib;Ole32.lib;SetupAPI.lib;urlmon.lib false true true true true true simutrans-124.3/Simutrans-SDL2.vcxproj.filters000066400000000000000000000015041474050137200213260ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 simutrans-124.3/Simutrans-Server.vcxproj000066400000000000000000000226121474050137200204240ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 Stable Win32 Stable x64 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C} Simutrans Simutrans Server x86-windows-static x64-windows-static Application $(DefaultPlatformToolset) true <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)build\Server\ $(SolutionDir)build\Server\$(Configuration)\ $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(ProjectName) Debug false $(ProjectName) Nightly false false true true true true true true true Level3 true true 4250;4373;4800;4996;26812;26451 true false Console MachineX86 true ProgramDatabase Disabled USE_ZSTD;COLOUR_DEPTH=0;MULTI_THREAD=1;MSG_LEVEL=3;DEBUG=3;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP MultiThreadedDebugDLL EnableFastChecks kernel32.lib;user32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib true false false true USE_ZSTD;COLOUR_DEPTH=0;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;REVISION_FROM_FILE;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP USE_ZSTD;COLOUR_DEPTH=0;MULTI_THREAD=1;MSG_LEVEL=3;NDEBUG;NOMINMAX;WIN32_LEAN_AND_MEAN;WINVER=_WIN32_WINNT_WINXP tools/get_revision.bat Obtain SVN revision number true true true MaxSpeed true Speed MultiThreadedDLL true true true true kernel32.lib;user32.lib;shell32.lib;winmm.lib;advapi32.lib;ws2_32.lib;imm32.lib false true true true simutrans-124.3/Simutrans-Server.vcxproj.filters000066400000000000000000000015041474050137200220700ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 simutrans-124.3/Simutrans.sln000066400000000000000000000071661474050137200162700ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33424.131 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans-Main", "Simutrans-Main.vcxitems", "{5A9777DD-CE40-45AE-8CB4-0FF2DB4ABD27}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans GDI", "Simutrans-GDI.vcxproj", "{0621B295-BEB7-4767-82F1-F27995610323}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans SDL2", "Simutrans-SDL2.vcxproj", "{E74757E8-C2FD-44AD-87BD-3D55F4709484}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans Server", "Simutrans-Server.vcxproj", "{0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 Stable|x64 = Stable|x64 Stable|x86 = Stable|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0621B295-BEB7-4767-82F1-F27995610323}.Debug|x64.ActiveCfg = Debug|x64 {0621B295-BEB7-4767-82F1-F27995610323}.Debug|x64.Build.0 = Debug|x64 {0621B295-BEB7-4767-82F1-F27995610323}.Debug|x86.ActiveCfg = Debug|Win32 {0621B295-BEB7-4767-82F1-F27995610323}.Debug|x86.Build.0 = Debug|Win32 {0621B295-BEB7-4767-82F1-F27995610323}.Release|x64.ActiveCfg = Release|x64 {0621B295-BEB7-4767-82F1-F27995610323}.Release|x86.ActiveCfg = Release|Win32 {0621B295-BEB7-4767-82F1-F27995610323}.Release|x86.Build.0 = Release|Win32 {0621B295-BEB7-4767-82F1-F27995610323}.Stable|x64.ActiveCfg = Stable|x64 {0621B295-BEB7-4767-82F1-F27995610323}.Stable|x64.Build.0 = Stable|x64 {0621B295-BEB7-4767-82F1-F27995610323}.Stable|x86.ActiveCfg = Stable|Win32 {0621B295-BEB7-4767-82F1-F27995610323}.Stable|x86.Build.0 = Stable|Win32 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Debug|x64.ActiveCfg = Debug|x64 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Debug|x86.ActiveCfg = Debug|Win32 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Release|x64.ActiveCfg = Release|x64 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Release|x64.Build.0 = Release|x64 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Release|x86.ActiveCfg = Release|Win32 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Stable|x64.ActiveCfg = Stable|x64 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Stable|x86.ActiveCfg = Stable|Win32 {E74757E8-C2FD-44AD-87BD-3D55F4709484}.Stable|x86.Build.0 = Stable|Win32 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Debug|x64.ActiveCfg = Debug|Win32 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Debug|x86.ActiveCfg = Debug|Win32 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Release|x64.ActiveCfg = Release|x64 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Release|x86.ActiveCfg = Release|Win32 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Stable|x64.ActiveCfg = Stable|x64 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Stable|x86.ActiveCfg = Stable|Win32 {0EE7EB1C-43C6-4548-9C60-B79F4D781B4C}.Stable|x86.Build.0 = Stable|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {49739D12-4369-4D44-B614-A4C97AF7D06A} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution Simutrans-Main.vcxitems*{0621b295-beb7-4767-82f1-f27995610323}*SharedItemsImports = 4 Simutrans-Main.vcxitems*{0ee7eb1c-43c6-4548-9c60-b79f4d781b4c}*SharedItemsImports = 4 Simutrans-Main.vcxitems*{5a9777dd-ce40-45ae-8cb4-0ff2db4abd27}*SharedItemsImports = 9 Simutrans-Main.vcxitems*{e74757e8-c2fd-44ad-87bd-3d55f4709484}*SharedItemsImports = 4 EndGlobalSection EndGlobal simutrans-124.3/cmake/000077500000000000000000000000001474050137200146335ustar00rootroot00000000000000simutrans-124.3/cmake/FindCCache.cmake000066400000000000000000000016621474050137200175510ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # - Find CCache compiler cache executable. # # This module defines the following variables: # CCache_FOUND - true if CCache was found. # CCache_EXECUTABLE - Path to CCache executable. # CCache_VERSION - Version string of CCache executable. # include(FindPackageHandleStandardArgs) find_program(CCache_EXECUTABLE ccache) if (CCache_EXECUTABLE) execute_process(COMMAND "${CCache_EXECUTABLE}" --version OUTPUT_VARIABLE CCache_VERSION_OUTPUT ) if (CCache_VERSION_OUTPUT MATCHES "version ([0-9]+\\.[0-9]+\\.[0-9]+)") set(CCache_VERSION "${CMAKE_MATCH_1}") endif () endif (CCache_EXECUTABLE) find_package_handle_standard_args(CCache FOUND_VAR CCache_FOUND REQUIRED_VARS CCache_EXECUTABLE VERSION_VAR CCache_VERSION ) if (CCache_FOUND OR NOT CCache_FIND_REQUIRED) mark_as_advanced(CCache_EXECUTABLE) endif () simutrans-124.3/cmake/FindMiniUPNP.cmake000066400000000000000000000043411474050137200200370ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # Locate MiniUPNP library. # This module defines # MiniUPNP_FOUND, if miniupnp library and headers have been found # MiniUPNP_LIBRARY, the miniupnp variant # MiniUPNP_INCLUDE_DIR, where to find miniupnpc.h and family) # MiniUPNP_VERSION, the API version of MiniUPNP # if (MiniUPNP_INCLUDE_DIR AND MiniUPNP_LIBRARY) # Already in cache, be silent set(MiniUPNP_FIND_QUIETLY TRUE) endif () find_path(MiniUPNP_INCLUDE_DIR miniupnpc.h HINTS $ENV{MINIUPNP_INCLUDE_DIR} PATH_SUFFIXES miniupnpc ) find_library(MiniUPNP_LIBRARY miniupnpc HINTS $ENV{MINIUPNP_LIBRARY} ) find_library(MiniUPNP_STATIC_LIBRARY libminiupnpc.a HINTS $ENV{MINIUPNP_STATIC_LIBRARY} ) set(MiniUPNP_INCLUDE_DIRS ${MiniUPNP_INCLUDE_DIR}) set(MiniUPNP_LIBRARIES ${MiniUPNP_LIBRARY}) set(MiniUPNP_STATIC_LIBRARIES ${MiniUPNP_STATIC_LIBRARY}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( MiniUPNP DEFAULT_MSG MiniUPNP_LIBRARY MiniUPNP_INCLUDE_DIR ) if (MiniUPNP_FOUND) file(STRINGS "${MiniUPNP_INCLUDE_DIR}/miniupnpc.h" MiniUPNP_API_VERSION_STR REGEX "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+[0-9]+") if (MiniUPNP_API_VERSION_STR MATCHES "^#define[\t ]+MINIUPNPC_API_VERSION[\t ]+([0-9]+)") set(MiniUPNP_API_VERSION "${CMAKE_MATCH_1}") endif() if (MiniUPNP_API_VERSION GREATER_EQUAL 10 AND NOT MiniUPNP_FIND_QUIETLY) message(STATUS "Found MiniUPNP API version ${MiniUPNP_API_VERSION}") endif() endif() mark_as_advanced(MiniUPNP_INCLUDE_DIR MiniUPNP_LIBRARY MiniUPNP_STATIC_LIBRARY) if (MiniUPNP_FOUND) if (NOT TARGET MiniUPNP::MiniUPNP) add_library(MiniUPNP::MiniUPNP UNKNOWN IMPORTED) endif (NOT TARGET MiniUPNP::MiniUPNP) set_target_properties(MiniUPNP::MiniUPNP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MiniUPNP_INCLUDE_DIRS}") set_target_properties(MiniUPNP::MiniUPNP PROPERTIES IMPORTED_LOCATION "${MiniUPNP_LIBRARIES}") if (MINGW) # MinGW needs an additional link flags set_property(TARGET MiniUPNP::MiniUPNP PROPERTY INTERFACE_LINK_LIBRARIES "-liphlpapi -lws2_32") endif (MINGW) if (MSVC) set_property(TARGET MiniUPNP::MiniUPNP PROPERTY INTERFACE_LINK_LIBRARIES "iphlpapi.lib") endif (MSVC) endif (MiniUPNP_FOUND) simutrans-124.3/cmake/MacBundle.cmake000066400000000000000000000025311474050137200174700ustar00rootroot00000000000000# Set copyright text string(TIMESTAMP YEAR "%Y") set(COPYRIGHT "Copyright 1997-${YEAR} by the Simutrans Team") # Get version number file(READ ${SOURCE_DIR}src/simutrans/simversion.h VERSION_FILE) string(REGEX MATCH "VERSION_MAJOR ([0-9]*)" _ ${VERSION_FILE}) set(VERSION ${CMAKE_MATCH_1}) # Copy the icon file set(ICON ${SOURCE_DIR}src/OSX/simutrans.icns) target_sources(simutrans PRIVATE ${ICON}) set_source_files_properties(${ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") # Bundle information set_target_properties(simutrans PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME simutrans MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION} MACOSX_BUNDLE_COPYRIGHT ${COPYRIGHT} MACOSX_BUNDLE_GUI_IDENTIFIER org.simutrans.simutrans MACOSX_BUNDLE_ICON_FILE simutrans MACOSX_BUNDLE_INFO_STRING "Simutrans ${VERSION}, ${COPYRIGHT}" MACOSX_BUNDLE_LONG_VERSION_STRING ${VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION} ) # Change the install directory from /usr/local to the build directory, so it's easier to package. set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}) if (SIMUTRANS_STEAM_BUILT) install(FILES ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/osx/libsteam_api.dylib DESTINATION ${CMAKE_BINARY_DIR}/simutrans/simutrans.app/Contents/MacOS) endif () install(CODE " include(BundleUtilities) fixup_bundle(\"${CMAKE_BINARY_DIR}/simutrans/simutrans.app\" \"\" \"\") ") simutrans-124.3/cmake/SimutransBackend.cmake000066400000000000000000000010511474050137200210670ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # if (SDL2_FOUND AND Freetype_FOUND) list(APPEND AVAILABLE_BACKENDS "sdl2") mark_as_advanced(SDL2_DIR) endif () if (WIN32 AND Freetype_FOUND) list(APPEND AVAILABLE_BACKENDS "gdi") endif () list(APPEND AVAILABLE_BACKENDS "none") string(REGEX MATCH "^[^;][^;]*" FIRST_BACKEND "${AVAILABLE_BACKENDS}") set(SIMUTRANS_BACKEND "${FIRST_BACKEND}" CACHE STRING "Graphics backend") set_property(CACHE SIMUTRANS_BACKEND PROPERTY STRINGS ${AVAILABLE_BACKENDS}) simutrans-124.3/cmake/SimutransCompileOptions.cmake000066400000000000000000000141221474050137200225070ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # if (CCache_FOUND) option(SIMUTRANS_USE_CCACHE "Use CCache compiler cache to improve recompilation speed" ON) if (SIMUTRANS_USE_CCACHE) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCache_EXECUTABLE}") set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCache_EXECUTABLE}") endif (SIMUTRANS_USE_CCACHE) endif (CCache_FOUND) if (CMAKE_USE_PTHREADS_INIT) option(SIMUTRANS_MULTI_THREAD "Use multiple threads for drawing" ON) else (CMAKE_USE_PTHREADS_INIT) set(SIMUTRANS_MULTI_THREAD OFF) endif (CMAKE_USE_PTHREADS_INIT) if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4) option(SIMUTRANS_BUILD_32BIT "Build 32 or 64 bit executable" OFF) endif () option(SIMUTRANS_VALGRIND_SUPPORT "Add support for valgrind \"memcheck\" tool" OFF) if (MiniUPNP_FOUND) option(SIMUTRANS_USE_UPNP "Use MiniUPNP for easier server setup" ON) endif (MiniUPNP_FOUND) if (ZSTD_FOUND) option(SIMUTRANS_USE_ZSTD "Enable support for zstd save file compression (larger save files than bzip2, but faster)" ON) endif (ZSTD_FOUND) if (FluidSynth_FOUND AND NOT WIN32) option(SIMUTRANS_USE_FLUIDSYNTH_MIDI "Enable FluidSynth for MIDI playback" ON) endif (FluidSynth_FOUND AND NOT WIN32) if(Fontconfig_FOUND) option(SIMUTRANS_USE_FONTCONFIG "Use Fontconfig for font autodetection" ON) endif() option(SIMUTRANS_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF) option(SIMUTRANS_INSTALL_PAK64 "Download pak64 on install" OFF) option(SIMUTRANS_UPDATE_LANGFILES "Update language files from the translator on install" OFF) option(SIMUTRANS_ENABLE_PROFILING "Enable profiling code" OFF) option(SIMUTRANS_USE_SYSLOG "Enable logging to syslog" OFF) option(SIMUTRANS_USE_IP4_ONLY "Use only IPv4" OFF) option(SIMUTRANS_STEAM_BUILT "Compile a Steam build" OFF) option(DEBUG_FLUSH_BUFFER "Highlite areas changes since last redraw" OFF) option(ENABLE_WATERWAY_SIGNS "Allow private signs on watersways" OFF) option(AUTOJOIN_PUBLIC "Join when making things public" OFF) option(SIMUTRANS_USE_REVISION "Use the given revision number" OFF) option(SIMUTRANS_USE_OWN_PAKINSTALL "Use built-in pakset installer instead of scripted" OFF) if(NOT SIMUTRANS_DEBUG_LEVEL) set(SIMUTRANS_DEBUG_LEVEL $) endif () if(NOT SIMUTRANS_MSG_LEVEL) set(SIMUTRANS_MSG_LEVEL 3 CACHE STRING "Message verbosity level") endif () set_property(CACHE SIMUTRANS_MSG_LEVEL PROPERTY STRINGS 0 1 2 3 4) if(OPTION_BUNDLE_LIBRARIES AND UNIX AND NOT APPLE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_INSTALL_RPATH "\$ORIGIN/lib") # otherwise RUNPATH will be set instead of RPATH, which can lead to issues add_link_options("-Wl,--disable-new-dtags") endif() include(CheckCXXCompilerFlag) # # This function adds all supported compiler flags to result_list # Example: SIMUTRANS_CHECK_CXX_COMPILER_FLAGS(COMMON_COMPILE_OPTIONS -Wall -Wextra -Werror) # will add -Wall -Wextra -Werror to COMMON_COMPILE_OPTIONS. # function(SIMUTRANS_CHECK_CXX_COMPILER_FLAGS result_list) set(temp_list "") foreach (flag ${ARGN}) # We cannot check for -Wno-* or -fno-* as this won't throw a warning so we must check for -W* or -f* directly string(REGEX REPLACE "^(-[Wf])no-" "\\1" sanitizedFlag ${flag}) set(cachedVarName ${sanitizedFlag}) string(REPLACE "+" "X" cachedVarName ${cachedVarName}) string(REGEX REPLACE "[-=]" "_" cachedVarName ${cachedVarName}) if (NOT ${CMAKE_CXX_COMPILER_ID}_${cachedVarName}_CHECKED) check_cxx_compiler_flag(${sanitizedFlag} CXX_FLAG_${cachedVarName}_SUPPORTED) set(${CMAKE_CXX_COMPILER_ID}_${cachedVarName}_CHECKED YES CACHE INTERNAL "") endif() if (CXX_FLAG_${cachedVarName}_SUPPORTED) list(APPEND temp_list ${flag}) endif (CXX_FLAG_${cachedVarName}_SUPPORTED) unset(cachedVarName) unset(sanitizedFlag) endforeach () if (NOT ${result_list}) set(${result_list} ${temp_list} PARENT_SCOPE) elseif (temp_list) set(${result_list} "${${result_list}};${temp_list}" PARENT_SCOPE) endif () endfunction() if (MSVC) SIMUTRANS_CHECK_CXX_COMPILER_FLAGS(SIMUTRANS_COMMON_COMPILE_OPTIONS /W3 4250;4373;4800;4996;26812;26451 /wd4244 # C4244: 'conversion_type': conversion from 'type1' to 'type2', possible loss of data /wd4267 # C4267: '=': conversion from 'type1' to 'type2', possible loss of data /wd4068 # C4068: unknown pragma /wd4250 # C4250: same name in derived class belong to derived class (silly) /wd26812 # Prefer 'enum class' over 'enum' (silly) /wd26451 # Arithmetic overflow: Using operator 'operator' on a size-a byte value and then casting the result to a size-b byte value. (widely used in finances) /wdD9025 # /MT # static multithreded libaries /MP # parallel builds ) set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") foreach(CompilerFlag ${CompilerFlags}) string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") endforeach() add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_SCL_SECURE_NO_WARNINGS) add_definitions(-DNOMINMAX) add_definitions(-DWIN32_LEAN_AND_MEAN) if (SIMUTRANS_WARNINGS_AS_ERRORS) add_compile_options(/WX) endif () if (CMAKE_SIZEOF_VOID_P EQUAL 4) add_link_options(/LARGEADDRESSAWARE) endif () else (MSVC) # Assume GCC/Clang SIMUTRANS_CHECK_CXX_COMPILER_FLAGS(SIMUTRANS_COMMON_COMPILE_OPTIONS -Wall -Wextra -Wformat=2 -Wundef -Wmissing-include-dirs -Wcast-qual -Wpointer-arith -Wcast-align -Wduplicated-cond ) SIMUTRANS_CHECK_CXX_COMPILER_FLAGS(SIMUTRANS_COMMON_COMPILE_OPTIONS -Wno-format-nonliteral # Mostly for translator -Wno-overloaded-virtual # For makeobj -Wno-deprecated-declarations # auto_ptr for squirrel -Wno-deprecated-copy # for squirrel -Wno-cast-align # for squirrel -Wno-return-std-move # for squirrel ) if (SIMUTRANS_WARNINGS_AS_ERRORS) add_compile_options(-Werror) endif () # only add large address linking to 32 bin windows programs if (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) add_link_options(-Wl,--large-address-aware) endif () if (SIMUTRANS_PROFILE) SIMUTRANS_CHECK_CXX_COMPILER_FLAGS(SIMUTRANS_COMMON_COMPILE_OPTIONS -pg -fno-inline -fno-schedule-insns ) endif (SIMUTRANS_PROFILE) endif (MSVC) simutrans-124.3/cmake/SimutransFindDependencies.cmake000066400000000000000000000156751474050137200227500ustar00rootroot00000000000000if (NOT ANDROID) find_package(CCache) find_package(ZLIB REQUIRED) find_package(BZip2 REQUIRED) find_package(PNG REQUIRED) find_package(MiniUPNP) find_package(Fontconfig) if (MSVC) find_package(ZSTD) find_package(SDL2) find_package(Freetype) find_package(FluidSynth) else () find_package(PkgConfig MODULE REQUIRED) pkg_check_modules(ZSTD REQUIRED IMPORTED_TARGET libzstd) pkg_check_modules(SDL2 IMPORTED_TARGET sdl2) pkg_check_modules(Freetype IMPORTED_TARGET freetype2) pkg_check_modules(FluidSynth IMPORTED_TARGET fluidsynth>=2.1.0) endif () set(CMAKE_THREAD_PREFER_PTHREAD ON) find_package(Threads) else () if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(PREBUILT_DIR "debug") else () set(PREBUILT_DIR "release") endif () include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../zlib/) add_library(ZLIB::ZLIB SHARED IMPORTED) set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../zlib/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libz.so) set_target_properties(ZLIB::ZLIB PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../bzip2/) add_library(BZip2::BZip2 SHARED IMPORTED) set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../bzip2/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libbz2.so) set_target_properties(BZip2::BZip2 PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libpng/) add_library(PNG::PNG SHARED IMPORTED) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../libpng/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libpng16d.so) else () set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../libpng/prebuilt/release/${CMAKE_ANDROID_ARCH_ABI}/libpng16.so) endif () set_target_properties(PNG::PNG PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../zstd/lib/) add_library(ZSTD::ZSTD SHARED IMPORTED) set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../zstd/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libzstd.so) set_target_properties(ZSTD::ZSTD PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../freetype/include/) add_library(Freetype::Freetype SHARED IMPORTED) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../freetype/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libfreetyped.so) else () set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../freetype/prebuilt/${PREBUILT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libfreetype.so) endif () set_target_properties(Freetype::Freetype PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) find_library(SDL2 SDL2) # Fluidsynth dependencies are a big family # We may be able to reduce the family numbers by compiling Fluidsynth ourselves # But such process is long and tedious (see: https://github.com/FluidSynth/fluidsynth/blob/master/.azure/azure-pipelines-android.yml ) # For now we use the release libraries include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/include/) find_package(OpenMP REQUIRED) add_library(libfluidsynth SHARED IMPORTED) set(SHARED_LIBRARY_SO ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libfluidsynth.so) set_target_properties(libfluidsynth PROPERTIES IMPORTED_LOCATION ${SHARED_LIBRARY_SO}) add_library(libFLAC SHARED IMPORTED) set_target_properties(libFLAC PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libFLAC.so) add_library(libfluidsynth-assetloader SHARED IMPORTED) set_target_properties(libfluidsynth-assetloader PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libfluidsynth-assetloader.so) add_library(libgio-2.0 SHARED IMPORTED) set_target_properties(libgio-2.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libgio-2.0.so) add_library(libglib-2.0 SHARED IMPORTED) set_target_properties(libglib-2.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libglib-2.0.so) add_library(libgmodule-2.0 SHARED IMPORTED) set_target_properties(libgmodule-2.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libgmodule-2.0.so) add_library(libgobject-2.0 SHARED IMPORTED) set_target_properties(libgobject-2.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libgobject-2.0.so) add_library(libgthread-2.0 SHARED IMPORTED) set_target_properties(libgthread-2.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libgthread-2.0.so) add_library(libinstpatch-1.0 SHARED IMPORTED) set_target_properties(libinstpatch-1.0 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libinstpatch-1.0.so) add_library(liboboe SHARED IMPORTED) set_target_properties(liboboe PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/liboboe.so) add_library(libogg SHARED IMPORTED) set_target_properties(libogg PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libogg.so) add_library(libopus SHARED IMPORTED) set_target_properties(libopus PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libopus.so) add_library(libpcre SHARED IMPORTED) set_target_properties(libpcre PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libpcre.so) add_library(libpcreposix SHARED IMPORTED) set_target_properties(libpcreposix PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libpcreposix.so) add_library(libsndfile SHARED IMPORTED) set_target_properties(libsndfile PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libsndfile.so) add_library(libvorbis SHARED IMPORTED) set_target_properties(libvorbis PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libvorbis.so) add_library(libvorbisenc SHARED IMPORTED) set_target_properties(libvorbisenc PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libvorbisenc.so) add_library(libvorbisfile SHARED IMPORTED) set_target_properties(libvorbisfile PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../fluidsynth/lib/${CMAKE_ANDROID_ARCH_ABI}/libvorbisfile.so) add_library(fluidsynth INTERFACE) target_link_libraries(fluidsynth INTERFACE libFLAC libfluidsynth-assetloader libgio-2.0 libglib-2.0 libgmodule-2.0 libgobject-2.0 libgthread-2.0 libinstpatch-1.0 liboboe libogg libopus libpcre libpcreposix libsndfile libvorbis libvorbisenc libvorbisfile libfluidsynth OpenMP::OpenMP_CXX ) endif () simutrans-124.3/cmake/SimutransInstall.cmake000066400000000000000000000132461474050137200211570ustar00rootroot00000000000000if (APPLE) # Self-contained bundle set(SIMUTRANS_BASE_DIR "${CMAKE_BINARY_DIR}/simutrans/simutrans.app/Contents/Resources/simutrans") set(SIMUTRANS_BIN_DIR "${CMAKE_BINARY_DIR}/simutrans") set(SIMUTRANS_OUTPUT_DIR "") elseif (UNIX AND NOT OPTION_BUNDLE_LIBRARIES AND NOT SINGLE_INSTALL) # System Installation (Linux only) include(GNUInstallDirs) if (USE_GAMES_DATADIR) set(SIMUTRANS_BASE_DIR "${CMAKE_INSTALL_DATADIR}/games/simutrans") else () set(SIMUTRANS_BASE_DIR "${CMAKE_INSTALL_DATADIR}/simutrans") endif () set(SIMUTRANS_BIN_DIR "${CMAKE_INSTALL_BINDIR}") set(SIMUTRANS_OUTPUT_DIR "${CMAKE_INSTALL_PREFIX}") install(FILES ${CMAKE_SOURCE_DIR}/src/simutrans/simutrans.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) install(FILES ${CMAKE_SOURCE_DIR}/src/linux/simutrans.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) install(FILES ${CMAKE_SOURCE_DIR}/src/linux/com.simutrans.Simutrans.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) else () # Portable installation set(SIMUTRANS_BASE_DIR "${CMAKE_BINARY_DIR}/simutrans") set(SIMUTRANS_BIN_DIR "${CMAKE_BINARY_DIR}/simutrans") set(SIMUTRANS_OUTPUT_DIR "") endif () install(TARGETS simutrans RUNTIME DESTINATION "${SIMUTRANS_BIN_DIR}" BUNDLE DESTINATION "${SIMUTRANS_BIN_DIR}") install(DIRECTORY "${CMAKE_SOURCE_DIR}/simutrans/" DESTINATION ${SIMUTRANS_BASE_DIR} REGEX "get_pak.sh" EXCLUDE) # # Download language files # if (SIMUTRANS_UPDATE_LANGFILES) if (MSVC) # MSVC has no variable on the install target path at execution time, which is why we expand the directories at creation time! install(CODE "execute_process(COMMAND powershell -ExecutionPolicy Bypass -File ${CMAKE_SOURCE_DIR}/tools/get_lang_files.ps1 WORKING_DIRECTORY ${SIMUTRANS_OUTPUT_DIR}/${SIMUTRANS_BASE_DIR}/..)") else () install(CODE "execute_process(COMMAND sh ${CMAKE_SOURCE_DIR}/tools/get_lang_files.sh WORKING_DIRECTORY ${SIMUTRANS_OUTPUT_DIR}/${SIMUTRANS_BASE_DIR}/.. )") endif () endif () # # Pak installer # if (NOT WIN32) install(FILES "${CMAKE_SOURCE_DIR}/tools/get_pak.sh" DESTINATION "${SIMUTRANS_BASE_DIR}" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) else () # NSIS must be installed manually in the path with the right addons if(MINGW) install(CODE "execute_process(COMMAND makensis onlineupgrade.nsi WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/Windows/nsis)") else () install(CODE "execute_process(COMMAND cmd /k \"$ENV{ProgramFiles\(x86\)}/NSIS/makensis.exe\" onlineupgrade.nsi WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/Windows/nsis)") endif () install(FILES "${CMAKE_SOURCE_DIR}/src/Windows/nsis/download-paksets.exe" DESTINATION "${SIMUTRANS_BASE_DIR}") endif () # # Install pak64 if requested or needed # if (SIMUTRANS_INSTALL_PAK64) if (MSVC) install(CODE "if(NOT EXISTS ${SIMUTRANS_BASE_DIR}/pak) execute_process(COMMAND powershell -Command \"Remove-Item \'${SIMUTRANS_BASE_DIR}/pak\' -Recurse\" WORKING_DIRECTORY ${SIMUTRANS_OUTPUT_DIR}/${SIMUTRANS_BASE_DIR}) file(STRINGS ${CMAKE_SOURCE_DIR}/src/simutrans/paksetinfo.h URLpak64 REGEX \"/pak64/\") string( REGEX REPLACE \"^.[\\t ]*\\\"\" \"\" URLpak64 \${URLpak64}) string( REGEX REPLACE \"\\\", .*\$\" \"\" URLpak64 \${URLpak64}) message(\"install pak to \" ${SIMUTRANS_BASE_DIR}) execute_process(COMMAND powershell -ExecutionPolicy Bypass -File ${CMAKE_SOURCE_DIR}/tools/get_pak.ps1 \${URLpak64} WORKING_DIRECTORY ${SIMUTRANS_OUTPUT_DIR}/${SIMUTRANS_BASE_DIR}) endif () ") else () # install pak64 with the bundle install(CODE "file(STRINGS ${CMAKE_SOURCE_DIR}/src/simutrans/paksetinfo.h URLpak64 REGEX \"/pak64/\") string( REGEX REPLACE \"^.[\\t ]*\\\"\" \"\" URLpak64 \${URLpak64}) string( REGEX REPLACE \"\\\", .*\$\" \"\" URLpak64 \${URLpak64}) execute_process(COMMAND sh ${CMAKE_SOURCE_DIR}/tools/get_pak.sh \${URLpak64} WORKING_DIRECTORY ${SIMUTRANS_OUTPUT_DIR}/${SIMUTRANS_BASE_DIR}) ") endif () endif () # # Bundle libraries on linux if requested # if (OPTION_BUNDLE_LIBRARIES AND UNIX AND NOT APPLE) # Steam Runtime already includes some of our libraries if (SIMUTRANS_STEAM_BUILT) install(CODE [[ file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR DEPENDENCIES EXECUTABLES "${CMAKE_BINARY_DIR}/simutrans/simutrans" PRE_EXCLUDE_REGEXES "libSDL2*|libz.so*|libfreetype*|libpng*|libglib*|libogg*|libpcre*|libvorbis*|libfontconfig*|libsteam_api.so*" POST_EXCLUDE_REGEXES "ld-linux|libc.so|libdl.so|libm.so|libgcc_s.so|libpthread.so|libstdc...so|libgomp.so") ]]) else () install(CODE [[ file(GET_RUNTIME_DEPENDENCIES RESOLVED_DEPENDENCIES_VAR DEPENDENCIES EXECUTABLES "${CMAKE_BINARY_DIR}/simutrans/simutrans" PRE_EXCLUDE_REGEXES "libSDL2*|libz.so*|libfontconfig*" POST_EXCLUDE_REGEXES "ld-linux|libc.so|libdl.so|libm.so|libgcc_s.so|libpthread.so|libstdc...so|libgomp.so") ]]) endif () install(CODE [[ file(INSTALL DESTINATION "${CMAKE_BINARY_DIR}/simutrans/lib" FILES ${DEPENDENCIES} FOLLOW_SYMLINK_CHAIN) ]]) endif () # # Include steam library (for some reason it is not done automagically as others) # if (SIMUTRANS_STEAM_BUILT) if(MSVC AND CMAKE_GENERATOR_PLATFORM MATCHES "Win32") install(FILES ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/steam_api.dll DESTINATION ${CMAKE_BINARY_DIR}/simutrans) elseif(MSVC AND CMAKE_GENERATOR_PLATFORM MATCHES "x64") install(FILES ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/win64/steam_api64.dll DESTINATION ${CMAKE_BINARY_DIR}/simutrans) elseif(UNIX AND NOT APPLE) # For Apple it was already done in MacBundle.cmake install(FILES ${CMAKE_SOURCE_DIR}/sdk/redistributable_bin/linux64/libsteam_api.so DESTINATION ${CMAKE_BINARY_DIR}/simutrans/lib) endif() endif()simutrans-124.3/cmake/SimutransRevision.cmake000066400000000000000000000104161474050137200213430ustar00rootroot00000000000000# # This file is part of the Simutrans project under the artistic licence. # (see licence.txt) # find_package(Subversion QUIET) find_package(Git QUIET) # assume this is from simutrans/simutrans! if (Git_FOUND) execute_process(WORKING_DIRECTORY "${SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" log -1 RESULT_VARIABLE res_var OUTPUT_VARIABLE SIMUTRANS_RAW_WC_REVISION ) if (res_var EQUAL 0) message( "git log -1 ok:" ${SIMUTRANS_RAW_WC_REVISION}) string( REGEX REPLACE "[\t\r\n]" " " TEMP1 ${SIMUTRANS_RAW_WC_REVISION}) string( REGEX REPLACE "^.*trunk\@" "" TEMP2 ${TEMP1}) string( REGEX REPLACE " .*$" "" SIMUTRANS_WC_REVISION ${TEMP2}) if(SIMUTRANS_WC_REVISION MATCHES "commit") unset(SIMUTRANS_WC_REVISION) else () execute_process(WORKING_DIRECTORY "${SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" rev-parse --short=7 HEAD RESULT_VARIABLE res_var OUTPUT_VARIABLE SIMUTRANS_WC_HASH ) endif() endif() endif () if (NOT SIMUTRANS_WC_REVISION AND Subversion_FOUND) execute_process(WORKING_DIRECTORY "${SOURCE_DIR}" COMMAND svn info --show-item revision RESULT_VARIABLE res_var OUTPUT_VARIABLE SIMUTRANS_WC_REVISION ERROR_VARIABLE dummy ) if (res_var) # SVN not found => no result unset(SIMUTRANS_WC_REVISION) endif () endif () # Fallback for git commits not submitted to svn (e.g. when using git-svn) if (NOT SIMUTRANS_WC_REVISION AND Git_FOUND) execute_process(WORKING_DIRECTORY "${SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" rev-list --count --first-parent HEAD RESULT_VARIABLE res_var OUTPUT_VARIABLE SIMUTRANS_WC_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE ) if (res_var) # not a git repository unset(SIMUTRANS_WC_REVISION) else () # the number of commit +328 equals the revision ... MATH(EXPR res_var "${res_var}+328") execute_process(WORKING_DIRECTORY "${SOURCE_DIR}" COMMAND "${GIT_EXECUTABLE}" rev-parse --short=7 HEAD RESULT_VARIABLE res_var OUTPUT_VARIABLE SIMUTRANS_WC_HASH ) endif () endif () if (SIMUTRANS_WC_REVISION) # write a file with the SVNVERSION define if (NOT SIMUTRANS_WC_HASH) file(WRITE revision.h.txt "#define REVISION ${SIMUTRANS_WC_REVISION}\n") message(STATUS "Compiling Simutrans revision ${SIMUTRANS_WC_REVISION} without hash ...") else () file(WRITE revision.h.txt "#define REVISION ${SIMUTRANS_WC_REVISION}\n#define GIT_HASH 0x${SIMUTRANS_WC_HASH}\n") message(STATUS "Compiling Simutrans revision ${SIMUTRANS_WC_REVISION} with hash ${SIMUTRANS_WC_HASH} ...") endif () # copy the file to the final header only if the version changes # reduces needless rebuilds execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different revision.h.txt "${SOURCE_DIR}/src/simutrans/revision.h") # gather informations to update flatpak and Android creation files STRING(STRIP ${SIMUTRANS_WC_REVISION} SIMUTRANS_WC_REVISION) file(READ "${SOURCE_DIR}/src/simutrans/simversion.h" FILE_CONTENT) string(REGEX MATCH "#define SIM_VERSION_MAJOR[ ]+([0-9]*)" _ ${FILE_CONTENT}) set(ver_major ${CMAKE_MATCH_1}) string(REGEX MATCH "#define SIM_VERSION_MINOR[ ]+([0-9]*)" _ ${FILE_CONTENT}) set(ver_minor ${CMAKE_MATCH_1}) string(REGEX MATCH "#define SIM_VERSION_PATCH[ ]+([0-9]*)" _ ${FILE_CONTENT}) set(ver_patch ${CMAKE_MATCH_1}) string(REGEX MATCH "#define[ ]+SIM_VERSION_BUILD[ ]+SIM_BUILD_RELEASE[\r\n]+" RELEASE_FLAG ${FILE_CONTENT}) string(TIMESTAMP TODAY "%Y-%m-%d") # finally, update flatpak xml if (RELEASE_FLAG) set(nightly_suffix "") else () set(nightly_suffix " nightly") endif () configure_file( "${SOURCE_DIR}/src/linux/com.simutrans.Simutrans.metainfo.xml.in" "${SOURCE_DIR}/src/linux/com.simutrans.Simutrans.metainfo.xml" @ONLY ) # and Android files if (RELEASE_FLAG) set(nightly_suffix "-Release") else () set(nightly_suffix "-Nightly") endif () configure_file( "${SOURCE_DIR}/src/android/AndroidAppSettings.cfg.in" "${SOURCE_DIR}/src/android/AndroidAppSettings.cfg" @ONLY ) else () message(WARNING "Could not find revision information because this repository " "is neither a Subversion nor a Git repository. Revision information " "will be unavailable. You can set the SIMUTRANS_USE_REVISION option " "to manually specify a revision number") if (NOT EXISTS "${CMAKE_SOURCE_DIR}/revision.h") file(WRITE "${CMAKE_SOURCE_DIR}/revision.h" "#define REVISION \n") endif () endif () simutrans-124.3/cmake/SimutransSourceList.cmake000066400000000000000000000325211474050137200216420ustar00rootroot00000000000000target_sources(simutrans PRIVATE src/simutrans/builder/brueckenbauer.cc src/simutrans/builder/fabrikbauer.cc src/simutrans/builder/goods_manager.cc src/simutrans/builder/hausbauer.cc src/simutrans/builder/tree_builder.cc src/simutrans/builder/tunnelbauer.cc src/simutrans/builder/vehikelbauer.cc src/simutrans/builder/wegbauer.cc src/simutrans/dataobj/crossing_logic.cc src/simutrans/dataobj/environment.cc src/simutrans/dataobj/freelist.cc src/simutrans/dataobj/gameinfo.cc src/simutrans/dataobj/height_map_loader.cc src/simutrans/dataobj/koord.cc src/simutrans/dataobj/koord3d.cc src/simutrans/dataobj/loadsave.cc src/simutrans/dataobj/marker.cc src/simutrans/dataobj/objlist.cc src/simutrans/dataobj/pakset_manager.cc src/simutrans/dataobj/pakset_downloader.cc src/simutrans/dataobj/powernet.cc src/simutrans/dataobj/records.cc src/simutrans/dataobj/rect.cc src/simutrans/dataobj/ribi.cc src/simutrans/dataobj/route.cc src/simutrans/dataobj/scenario.cc src/simutrans/dataobj/schedule.cc src/simutrans/dataobj/settings.cc src/simutrans/dataobj/sve_cache.cc src/simutrans/dataobj/tabfile.cc src/simutrans/dataobj/translator.cc src/simutrans/descriptor/bridge_desc.cc src/simutrans/descriptor/building_desc.cc src/simutrans/descriptor/factory_desc.cc src/simutrans/descriptor/goods_desc.cc src/simutrans/descriptor/ground_desc.cc src/simutrans/descriptor/image.cc src/simutrans/descriptor/obj_base_desc.cc src/simutrans/descriptor/reader/bridge_reader.cc src/simutrans/descriptor/reader/building_reader.cc src/simutrans/descriptor/reader/citycar_reader.cc src/simutrans/descriptor/reader/crossing_reader.cc src/simutrans/descriptor/reader/factory_reader.cc src/simutrans/descriptor/reader/good_reader.cc src/simutrans/descriptor/reader/ground_reader.cc src/simutrans/descriptor/reader/groundobj_reader.cc src/simutrans/descriptor/reader/image_reader.cc src/simutrans/descriptor/reader/imagelist2d_reader.cc src/simutrans/descriptor/reader/imagelist_reader.cc src/simutrans/descriptor/reader/obj_reader.cc src/simutrans/descriptor/reader/pedestrian_reader.cc src/simutrans/descriptor/reader/roadsign_reader.cc src/simutrans/descriptor/reader/root_reader.cc src/simutrans/descriptor/reader/sim_reader.cc src/simutrans/descriptor/reader/skin_reader.cc src/simutrans/descriptor/reader/sound_reader.cc src/simutrans/descriptor/reader/text_reader.cc src/simutrans/descriptor/reader/tree_reader.cc src/simutrans/descriptor/reader/tunnel_reader.cc src/simutrans/descriptor/reader/vehicle_reader.cc src/simutrans/descriptor/reader/way_obj_reader.cc src/simutrans/descriptor/reader/way_reader.cc src/simutrans/descriptor/reader/xref_reader.cc src/simutrans/descriptor/sound_desc.cc src/simutrans/descriptor/tunnel_desc.cc src/simutrans/descriptor/vehicle_desc.cc src/simutrans/descriptor/way_desc.cc src/simutrans/display/font.cc src/simutrans/display/simview.cc src/simutrans/display/viewport.cc src/simutrans/freight_list_sorter.cc src/simutrans/ground/boden.cc src/simutrans/ground/brueckenboden.cc src/simutrans/ground/fundament.cc src/simutrans/ground/grund.cc src/simutrans/ground/monorailboden.cc src/simutrans/ground/tunnelboden.cc src/simutrans/ground/wasser.cc src/simutrans/gui/components/gui_aligned_container.cc src/simutrans/gui/components/gui_building.cc src/simutrans/gui/components/gui_button.cc src/simutrans/gui/components/gui_button_to_chart.cc src/simutrans/gui/components/gui_chart.cc src/simutrans/gui/components/gui_colorbox.cc src/simutrans/gui/components/gui_combobox.cc src/simutrans/gui/components/gui_component.cc src/simutrans/gui/components/gui_container.cc src/simutrans/gui/components/gui_convoiinfo.cc src/simutrans/gui/components/gui_divider.cc src/simutrans/gui/components/gui_fixedwidth_textarea.cc src/simutrans/gui/components/gui_flowtext.cc src/simutrans/gui/components/gui_image.cc src/simutrans/gui/components/gui_image_list.cc src/simutrans/gui/components/gui_label.cc src/simutrans/gui/components/gui_map_preview.cc src/simutrans/gui/components/gui_numberinput.cc src/simutrans/gui/components/gui_obj_view.cc src/simutrans/gui/components/gui_schedule.cc src/simutrans/gui/components/gui_scrollbar.cc src/simutrans/gui/components/gui_scrolled_list.cc src/simutrans/gui/components/gui_scrollpane.cc src/simutrans/gui/components/gui_speedbar.cc src/simutrans/gui/components/gui_tab_panel.cc src/simutrans/gui/components/gui_textarea.cc src/simutrans/gui/components/gui_textinput.cc src/simutrans/gui/components/gui_timeinput.cc src/simutrans/gui/components/gui_waytype_tab_panel.cc src/simutrans/gui/components/gui_world_view.cc src/simutrans/gui/ai_option.cc src/simutrans/gui/ai_selector.cc src/simutrans/gui/banner.cc src/simutrans/gui/base_info.cc src/simutrans/gui/baum_edit.cc src/simutrans/gui/city_info.cc src/simutrans/gui/citybuilding_edit.cc src/simutrans/gui/citylist_frame.cc src/simutrans/gui/citylist_stats.cc src/simutrans/gui/climates.cc src/simutrans/gui/chat_frame.cc src/simutrans/gui/convoi_detail.cc src/simutrans/gui/convoi_filter_frame.cc src/simutrans/gui/convoi_frame.cc src/simutrans/gui/convoi_info.cc src/simutrans/gui/convoy_item.cc src/simutrans/gui/curiosity_edit.cc src/simutrans/gui/curiositylist_frame.cc src/simutrans/gui/curiositylist_stats.cc src/simutrans/gui/depot_frame.cc src/simutrans/gui/depotlist_frame.cc src/simutrans/gui/display_settings.cc src/simutrans/gui/enlarge_map_frame.cc src/simutrans/gui/extend_edit.cc src/simutrans/gui/fabrik_info.cc src/simutrans/gui/factory_chart.cc src/simutrans/gui/factory_edit.cc src/simutrans/gui/factorylist_frame.cc src/simutrans/gui/factorylist_stats.cc src/simutrans/gui/goods_frame.cc src/simutrans/gui/goods_stats.cc src/simutrans/gui/ground_info.cc src/simutrans/gui/groundobj_edit.cc src/simutrans/gui/gui_frame.cc src/simutrans/gui/gui_theme.cc src/simutrans/gui/halt_info.cc src/simutrans/gui/halt_list_filter_frame.cc src/simutrans/gui/halt_list_frame.cc src/simutrans/gui/halt_list_stats.cc src/simutrans/gui/headquarter_info.cc src/simutrans/gui/help_frame.cc src/simutrans/gui/jump_frame.cc src/simutrans/gui/kennfarbe.cc src/simutrans/gui/label_info.cc src/simutrans/gui/labellist_frame.cc src/simutrans/gui/labellist_stats.cc src/simutrans/gui/line_item.cc src/simutrans/gui/line_management_gui.cc src/simutrans/gui/load_relief_frame.cc src/simutrans/gui/loadfont_frame.cc src/simutrans/gui/loadsave_frame.cc src/simutrans/gui/map_frame.cc src/simutrans/gui/message_frame.cc src/simutrans/gui/message_option.cc src/simutrans/gui/message_stats.cc src/simutrans/gui/messagebox.cc src/simutrans/gui/minimap.cc src/simutrans/gui/money_frame.cc src/simutrans/gui/obj_info.cc src/simutrans/gui/optionen.cc src/simutrans/gui/pakinstaller.cc src/simutrans/gui/pakselector.cc src/simutrans/gui/password_frame.cc src/simutrans/gui/player_frame.cc src/simutrans/gui/player_ranking_frame.cc src/simutrans/gui/privatesign_info.cc src/simutrans/gui/savegame_frame.cc src/simutrans/gui/scenario_frame.cc src/simutrans/gui/scenario_info.cc src/simutrans/gui/schedule_list.cc src/simutrans/gui/script_generator_frame.cc src/simutrans/gui/script_tool_frame.cc src/simutrans/gui/server_frame.cc src/simutrans/gui/settings_frame.cc src/simutrans/gui/settings_stats.cc src/simutrans/gui/signal_info.cc src/simutrans/gui/signal_spacing.cc src/simutrans/gui/simwin.cc src/simutrans/gui/sound_frame.cc src/simutrans/gui/sprachen.cc src/simutrans/gui/station_building_select.cc src/simutrans/gui/themeselector.cc src/simutrans/gui/tool_selector.cc src/simutrans/gui/trafficlight_info.cc src/simutrans/gui/vehiclelist_frame.cc src/simutrans/gui/welt.cc src/simutrans/io/classify_file.cc src/simutrans/io/raw_image.cc src/simutrans/io/raw_image_bmp.cc src/simutrans/io/raw_image_png.cc src/simutrans/io/raw_image_ppm.cc src/simutrans/io/rdwr/adler32_stream.cc src/simutrans/io/rdwr/bzip2_file_rdwr_stream.cc src/simutrans/io/rdwr/compare_file_rd_stream.cc src/simutrans/io/rdwr/raw_file_rdwr_stream.cc src/simutrans/io/rdwr/rdwr_stream.cc src/simutrans/io/rdwr/zlib_file_rdwr_stream.cc src/simutrans/network/checksum.cc src/simutrans/network/memory_rw.cc src/simutrans/network/network.cc src/simutrans/network/network_address.cc src/simutrans/network/network_cmd.cc src/simutrans/network/network_cmd_ingame.cc src/simutrans/network/network_cmd_scenario.cc src/simutrans/network/network_cmp_pakset.cc src/simutrans/network/network_file_transfer.cc src/simutrans/network/network_packet.cc src/simutrans/network/network_socket_list.cc src/simutrans/network/pakset_info.cc src/simutrans/obj/baum.cc src/simutrans/obj/bruecke.cc src/simutrans/obj/crossing.cc src/simutrans/obj/depot.cc src/simutrans/obj/field.cc src/simutrans/obj/gebaeude.cc src/simutrans/obj/groundobj.cc src/simutrans/obj/label.cc src/simutrans/obj/leitung2.cc src/simutrans/obj/pillar.cc src/simutrans/obj/roadsign.cc src/simutrans/obj/signal.cc src/simutrans/obj/simobj.cc src/simutrans/obj/tunnel.cc src/simutrans/obj/way/kanal.cc src/simutrans/obj/way/maglev.cc src/simutrans/obj/way/monorail.cc src/simutrans/obj/way/narrowgauge.cc src/simutrans/obj/way/runway.cc src/simutrans/obj/way/schiene.cc src/simutrans/obj/way/strasse.cc src/simutrans/obj/way/weg.cc src/simutrans/obj/wayobj.cc src/simutrans/obj/wolke.cc src/simutrans/obj/zeiger.cc src/simutrans/old_blockmanager.cc src/simutrans/player/ai.cc src/simutrans/player/ai_goods.cc src/simutrans/player/ai_passenger.cc src/simutrans/player/ai_scripted.cc src/simutrans/player/finance.cc src/simutrans/player/simplay.cc src/simutrans/revision.h src/simutrans/script/api/api_city.cc src/simutrans/script/api/api_command.cc src/simutrans/script/api/api_const.cc src/simutrans/script/api/api_control.cc src/simutrans/script/api/api_convoy.cc src/simutrans/script/api/api_factory.cc src/simutrans/script/api/api_gui.cc src/simutrans/script/api/api_halt.cc src/simutrans/script/api/api_include.cc src/simutrans/script/api/api_line.cc src/simutrans/script/api/api_map_objects.cc src/simutrans/script/api/api_obj_desc.cc src/simutrans/script/api/api_obj_desc_base.cc src/simutrans/script/api/api_pathfinding.cc src/simutrans/script/api/api_player.cc src/simutrans/script/api/api_scenario.cc src/simutrans/script/api/api_schedule.cc src/simutrans/script/api/api_settings.cc src/simutrans/script/api/api_simple.cc src/simutrans/script/api/api_tiles.cc src/simutrans/script/api/api_world.cc src/simutrans/script/api/export_desc.cc src/simutrans/script/api/get_next.cc src/simutrans/script/api_class.cc src/simutrans/script/api_function.cc src/simutrans/script/api_param.cc src/simutrans/script/dynamic_string.cc src/simutrans/script/export_objs.cc src/simutrans/script/script.cc src/simutrans/script/script_loader.cc src/simutrans/script/script_tool_manager.cc src/simutrans/simachievements.cc src/simutrans/simconvoi.cc src/simutrans/simdebug.cc src/simutrans/simevent.cc src/simutrans/simfab.cc src/simutrans/simhalt.cc src/simutrans/siminteraction.cc src/simutrans/simintr.cc src/simutrans/simio.cc src/simutrans/simline.cc src/simutrans/simlinemgmt.cc src/simutrans/simloadingscreen.cc src/simutrans/simmain.cc src/simutrans/simmem.cc src/simutrans/simmesg.cc src/simutrans/simskin.cc src/simutrans/simsound.cc src/simutrans/simticker.cc src/simutrans/simware.cc src/simutrans/sys/simsys.cc src/simutrans/tool/simmenu.cc src/simutrans/tool/simtool-script-generator.cc src/simutrans/tool/simtool-scripted.cc src/simutrans/tool/simtool.cc src/simutrans/utils/cbuffer.cc src/simutrans/utils/checklist.cc src/simutrans/utils/csv.cc src/simutrans/utils/log.cc src/simutrans/utils/searchfolder.cc src/simutrans/utils/sha1.cc src/simutrans/utils/sha1_hash.cc src/simutrans/utils/simrandom.cc src/simutrans/utils/simstring.cc src/simutrans/utils/simthread.cc src/simutrans/utils/unicode.cc src/simutrans/vehicle/air_vehicle.cc src/simutrans/vehicle/movingobj.cc src/simutrans/vehicle/pedestrian.cc src/simutrans/vehicle/rail_vehicle.cc src/simutrans/vehicle/road_vehicle.cc src/simutrans/vehicle/simroadtraffic.cc src/simutrans/vehicle/vehicle.cc src/simutrans/vehicle/vehicle_base.cc src/simutrans/vehicle/water_vehicle.cc src/simutrans/world/placefinder.cc src/simutrans/world/simcity.cc src/simutrans/world/simplan.cc src/simutrans/world/simworld.cc src/simutrans/world/surface.cc src/simutrans/world/terraformer.cc src/squirrel/sq_extensions.cc src/squirrel/sqstdlib/sqstdaux.cc src/squirrel/sqstdlib/sqstdblob.cc src/squirrel/sqstdlib/sqstdio.cc src/squirrel/sqstdlib/sqstdmath.cc src/squirrel/sqstdlib/sqstdrex.cc src/squirrel/sqstdlib/sqstdstream.cc src/squirrel/sqstdlib/sqstdstring.cc src/squirrel/sqstdlib/sqstdsystem.cc src/squirrel/squirrel/sqapi.cc src/squirrel/squirrel/sqbaselib.cc src/squirrel/squirrel/sqclass.cc src/squirrel/squirrel/sqcompiler.cc src/squirrel/squirrel/sqdebug.cc src/squirrel/squirrel/sqfuncstate.cc src/squirrel/squirrel/sqlexer.cc src/squirrel/squirrel/sqmem.cc src/squirrel/squirrel/sqobject.cc src/squirrel/squirrel/sqstate.cc src/squirrel/squirrel/sqtable.cc src/squirrel/squirrel/sqvm.cc ) simutrans-124.3/cmake/SimutransVcpkgTriplet.cmake000066400000000000000000000055051474050137200221660ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # set the correct triplet when compiling on MSVC using VCPKG # # MSVC variable is not defined until the first call to project if (CMAKE_GENERATOR MATCHES "Visual Studio.*" OR CMAKE_GENERATOR MATCHES "Ninja" AND WIN32) if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "CMAKE_TOOLCHAIN_FILE") elseif (NOT DEFINED CMAKE_TOOLCHAIN_FILE) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/build/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "CMAKE_TOOLCHAIN_FILE") endif () endif () # to built static libaries on vcpkg (exists on Linux too), we need to modify the VCPKG triplet (only if vcpkg) STRING(TOLOWER "${CMAKE_TOOLCHAIN_FILE}" CMAKE_TOOLCHAIN_FILE_LC) if (CMAKE_TOOLCHAIN_FILE_LC MATCHES ".*vcpkg.cmake") if (CMAKE_GENERATOR MATCHES "Visual Studio.*" AND "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # default is 32bit for now message( WARNING "No architecture givem => assume x86 build") set(CMAKE_GENERATOR_PLATFORM "Win32" CACHE STRING "" FORCE) set(VCPKG_TARGET_TRIPLET "x86-windows-static" CACHE STRING "Default target is 32bit static builds" FORCE) endif () if (DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET) set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "") endif () # if not defined, then guess if (NOT DEFINED VCPKG_TARGET_TRIPLET) if (DEFINED CMAKE_INSTALL_PREFIX) if (CMAKE_INSTALL_PREFIX MATCHES ".*x86-.*") set(VCPKG_TARGET_TRIPLET "x86-windows-static" CACHE STRING "Default target is 32bit static builds") elseif (CMAKE_INSTALL_PREFIX MATCHES ".*arm64-.*") set(VCPKG_TARGET_TRIPLET "arm64-windows-static" CACHE STRING "Default target is 64bit arm static builds") else () set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "Default target is 64bit static builds") endif () elseif (CMAKE_GENERATOR MATCHES "Visual Studio.*") if (CMAKE_GENERATOR_PLATFORM MATCHES "Win32") set(VCPKG_TARGET_TRIPLET "x86-windows-static" CACHE STRING "Default target is 32bit static builds") elseif (CMAKE_GENERATOR_PLATFORM MATCHES "ARM64") set(VCPKG_TARGET_TRIPLET "arm64-windows-static" CACHE STRING "Default target is 64bit arm static builds") else () set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "Default target is 64bit static builds") endif () else () message(FATAL_ERROR "Please specify VCPKG triplet!") endif () endif () message( "-- VCPKG: triplet=" ${VCPKG_TARGET_TRIPLET} " platform=" ${CMAKE_GENERATOR_PLATFORM}) else () if (CMAKE_GENERATOR MATCHES "Visual Studio.*" OR CMAKE_GENERATOR MATCHES "Ninja" AND WIN32) message(WARNING "CMake will fail without setting CMAKE_TOOLCHAIN_FILE!") endif () endif () simutrans-124.3/common.mk000066400000000000000000000025411474050137200153760ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # OBJS := $(patsubst %, $(BUILDDIR)/%.o, $(basename $(SOURCES))) DEPS := $(OBJS:%.o=%.d) DIRS := $(sort $(dir $(OBJS))) # Make build directories DUMMY := $(shell mkdir -p $(DIRS)) BUILDCONFIG_FILES := common.mk Makefile config.$(CFG) .PHONY: all clean .SUFFIXES: .rc ifeq ($(VERBOSE),) Q := @ else Q := endif simutrans: $(PROGDIR)/$(PROG) $(PROGDIR)/$(PROG): $(OBJS) @echo "===> LD $@" $(Q)$(HOSTCXX) $(OBJS) $(LDFLAGS) $(LIBS) -o $(PROGDIR)/$(PROG) -include $(DEPS) # Silence stale header dependency errors %.h: @true $(BUILDDIR)/%.o: %.mm $(BUILDCONFIG_FILES) @echo "===> Obj-c OSX $<" $(Q)$(HOSTCXX) $(CXXFLAGS) $(OBJCFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/%.o: %.m $(BUILDCONFIG_FILES) @echo "===> Obj-c OSX $<" $(Q)$(HOSTCXX) $(CXXFLAGS) $(OBJCFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/%.o: %.c $(BUILDCONFIG_FILES) @echo "===> HOSTCC $<" $(Q)$(HOSTCC) $(CCFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/%.o: %.cc $(BUILDCONFIG_FILES) @echo "===> HOSTCXX $<" $(Q)$(HOSTCXX) $(CXXFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/%.o: %.rc $(BUILDCONFIG_FILES) @echo "===> RES $<" # $(Q)$(WINDRES) --preprocessor "$(HOSTCXX) -E -xc -DRC_INVOKED -MMD -MF $(@:%.o=%.d) -MT $@" -O COFF $< $@ $(Q)$(WINDRES) --preprocessor "$(HOSTCXX) -E -xc -DRC_INVOKED -MMD -MT $@" -O COFF $< $@ simutrans-124.3/config.default.in000066400000000000000000000071531474050137200170010ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # this is config.default.in #BACKEND := gdi #BACKEND := sdl2 #BACKEND := posix BACKEND = @backend@ #OSTYPE := amiga #OSTYPE := beos #OSTYPE := freebsd #OSTYPE := haiku #OSTYPE := linux #OSTYPE := mac #OSTYPE := mingw #OSTYPE := openbsd OSTYPE = @os_type@ #DEBUG := 1 # Level 1-3, higher number means more debug-friendly but slower, see Makefile MSG_LEVEL := 3 # Level 1-4, more runtime debug messages (without only warnings and errors) OPTIMISE := 1 # Add umpteen optimisation flags #PROFILE := 1 # Enable profiling #PROFILE := 2 # Enable profiling with optimisation flags, can be used with `OPTIMISE = 1' STATIC := 1 # Enable static linkage (to be at least somewhat portable), Freetype and SDL only for non-MinGW OSTYPE. AV_FOUNDATION := @av_foundation@ # Use AVFoundation instead of QTKit. If you are building on macOS 10.12 or later, this must be enabled. WITH_REVISION := @svn@ # adds the revision from svn; required for networkgames # if you do not use SVN, add -DREVISION="1234" to the FLAGS below #WIN32_CONSOLE := 1 # adds a console for windows debugging MULTI_THREAD := @multithread@ # Enable multithreading, highly recommended BUNDLE_PTHREADGC2 := @bundlepthread@ # using UPnP for easy server hosting behind routers USE_UPNP := @upnp@ # using fontconfig for linux/mac TTF selection USE_FONTCONFIG := @fontconfig@ # using zstd compression USE_ZSTD := @zstd@ # using FluidSynth for MIDI playback (SDL2 backend needed for Linux/MacOS, SDL2 or GDI for MinGW) USE_FLUIDSYNTH_MIDI := @fluidsynth@ # enable link time optimizations #LTO := 1 # Define these as empty strings, if you don't have the respective config program #ALLEGRO_CONFIG := #PNG_CONFIG := #SDL_CONFIG := #SDL2_CONFIG := #FREETYPE_CONFIG := # Or define as the config program if you do #ALLEGRO_CONFIG := allegro-config #PNG_CONFIG := pkg-config libpng #SDL_CONFIG := sdl-config #SDL2_CONFIG := sdl2-config #FREETYPE_CONFIG := freetype-config #VERBOSE := 1 # The following useful conditional compilation flags exist # # Needed to compile: # SIM_BIG_ENDIAN: MUST be set for PPC/Motorola byte order! (old mac, amiga) # NO_INTPTR_T: must be set if intptr_t is not available # # Changing appearance: # USE_SOFTPOINTER: emulate mouse pointer (set automatically in Makefile) # # Useful for debugging: # DEBUG_ROUTES: show routing calculation information in minimap # SHOW_FORE_GRUND: show which objects are drawn as foreground # DEBUG_FLUSH_BUFFER: show the dirty areas on the screen # USE_VALGRIND_MEMCHECK: make valgrind-memcheck aware of the memory allocation stuff in dataobj/freelist # SYSLOG: send debug output to syslog # # Following flags alter game engine (and are off for standard builds) # OTTD_LIKE: Enables half height tiles and crossconnects all industries # AUTOMATIC_BRIDGES and AUTOMATIC_TUNNELS: will be built also for player # AUTOJOIN_PUBLIC: stations next to a public stop will be joined to it # MAX_CHOOSE_BLOCK_TILES=xxx: maximum distance between choose signal and a target (undefined means no limit) # DESTINATION_CITYCARS: Citycars can have a destination (not recommended) # # In order to use the flags, add a line like this: (-Dxxx) # FLAGS := -DREVISION="1234" FLAGS := @endian@ # Output directories: # # use this put objects file in same directory, where the sources are (not recommended): # ... otherwise defaults to 'build/default') # # BUILDDIR := $(shell pwd) # # use this to specify the target directory for the executable: # .. otherwise defaults to BUILDDIR # MAKEOBJ_PROGDIR := $(shell pwd) NETTOOL_PROGDIR := $(shell pwd) PROGDIR := $(shell pwd) simutrans-124.3/config.template000066400000000000000000000071241474050137200165610ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # to compile: # copy this file to config.default and adjust the settings # #BACKEND := gdi #BACKEND := sdl2 #BACKEND := posix #OSTYPE := amiga #OSTYPE := freebsd #OSTYPE := haiku #OSTYPE := linux #OSTYPE := mac #OSTYPE := mingw #OSTYPE := openbsd #DEBUG := 1 # Level 1-3, higher number means more debug-friendly but slower, see Makefile #MSG_LEVEL := 3 # Level 1-4, more runtime debug messages (without only warnings and errors) #OPTIMISE := 1 # Add umpteen optimisation flags #PROFILE := 1 # Enable profiling #PROFILE := 2 # Enable profiling with optimisation flags, can be used with `OPTIMISE = 1' #STATIC := 1 # Enable static linkage, but not SDL2 for non-MinGW OSTYPE. #AV_FOUNDATION := 1 # Use AVFoundation instead of QTKit. If you are building on macOS 10.12 or later, this must be enabled. #WITH_REVISION := 1 # adds the revision from svn; required for networkgames # if you do not use SVN, add -DREVISION="1234" to the FLAGS below #WIN32_CONSOLE := 1 # adds a console for windows debugging #MULTI_THREAD := 1 # Enable multithreading # using freetype for Truetype font support #USE_FREETYPE := 1 # using UPnP for easy server hosting behind routers #USE_UPNP := 1 # Enable support for zstd save file compression (larger save files than bzip2, but faster) #USE_ZSTD := 1 # use fontconfig to find default font (does not work for windows) #USE_FONTCONFIG := 0 # enable link time optimizations #LTO := 1 # using FluidSynth for MIDI playback (SDL2 backend needed for Linux/MacOS, SDL2 or GDI for MinGW) #USE_FLUIDSYNTH_MIDI := 1 # Define these as empty strings, if you don't have the respective config program #ALLEGRO_CONFIG := #PNG_CONFIG := #SDL_CONFIG := #SDL2_CONFIG := #FREETYPE_CONFIG := # Or define as the config program if you do #ALLEGRO_CONFIG := allegro-config #PNG_CONFIG := pkg-config libpng #SDL_CONFIG := sdl-config #SDL2_CONFIG := sdl2-config #FREETYPE_CONFIG := freetype-config #VERBOSE := 1 # The following useful conditional compilation flags exist # # Needed to compile: # SIM_BIG_ENDIAN: MUST be set for PPC/Motorola byte order! (old mac, amiga) # NO_INTPTR_T: must be set if intptr_t is not available # # Changing appearance: # USE_SOFTPOINTER: emulate mouse pointer (set automatically in Makefile) # # Useful for debugging: # DEBUG_ROUTES: show routing calculation information in minimap # SHOW_FORE_GRUND: show which objects are drawn as foreground # DEBUG_FLUSH_BUFFER: show the dirty areas on the screen # USE_VALGRIND_MEMCHECK: make valgrind-memcheck aware of the memory allocation stuff in dataobj/freelist # SYSLOG: send debug output to syslog # # Following flags alter game engine (and are off for standard builds) # OTTD_LIKE: Enables half height tiles and crossconnects all industries # AUTOMATIC_BRIDGES and AUTOMATIC_TUNNELS: will be built also for player # AUTOJOIN_PUBLIC: stations next to a public stop will be joined to it # MAX_CHOOSE_BLOCK_TILES=xxx: maximum distance between choose signal and a target (undefined means no limit) # DESTINATION_CITYCARS: Citycars can have a destination (not recommended) # # In order to use the flags, add a line like this: (-Dxxx) # FLAGS := -DREVISION="1234" # Output directories: # # use this put objects file in same directory, where the sources are (not recommended): # ... otherwise defaults to 'build/default') # # BUILDDIR := $(shell pwd) # # use this to specify the target directory for the executable: # .. otherwise defaults to BUILDDIR # # MAKEOBJ_PROGDIR := $(shell pwd) # NETTOOL_PROGDIR := $(shell pwd) # PROGDIR := $(shell pwd) simutrans-124.3/configure.ac000066400000000000000000000073771474050137200160570ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # simutrans.ac AC_INIT([simutrans],[version-0.2]) AC_PROG_CC AC_LANG(C++) # architecture AC_C_BIGENDIAN([AC_SUBST(endian, '-DSIM_BIG_ENDIAN')], [AC_SUBST(endian, '')], [AC_SUBST(endian, '')], [AC_SUBST(endian, '')]) # missing libs AC_CHECK_LIB(png, png_read_image, [], [AC_MSG_WARN([libpng is missing! Makeobj will not compile!])] ) AC_CHECK_LIB(bz2, BZ2_bzReadOpen, [], [AC_MSG_WARN([libbz2 is missing! Only zlib compressed saves will be available.])] ) # optional (but highly recommended) multithreading AC_SEARCH_LIBS(pthread_mutex_destroy, pthread, [AC_SUBST(multithread, 1)], [AC_SUBST(multithread, 0)] ) AC_CHECK_LIB(pthreadGC2, pthread_mutex_destroy, [AC_SUBST(bundlepthread, 1)], [AC_SUBST(bundlepthread, 0)] ) # find OS and backend by libs ... AC_CHECK_LIB(SDL2, SDL_GetRenderDriverInfo) AC_CHECK_HEADERS(windows.h) AC_CHECK_HEADERS(LocaleRoster.h) # optional zstd AC_SEARCH_LIBS(ZSTD_CStreamInSize, zstd, [AC_SUBST(zstd, 1)], [AC_SUBST(zstd, 0)] ) # hackish detection of OS ... if test "$ac_cv_header_windows_h" == yes then AC_SUBST(os_type, mingw) AC_SUBST(av_foundation, 0) # optional upnp AC_SEARCH_LIBS(upnpDiscover, miniupnpc, [AC_SUBST(upnp, 1)], [AC_SUBST(upnp, 0)], -liphlpapi -lws2_32 ) # optional fluidsynth AC_SEARCH_LIBS(new_fluid_settings, fluidsynth, [AC_SUBST(fluidsynth, 1)], [AC_SUBST(fluidsynth, 0)], -lglib-2.0 -lintl -liconv -ldsound -lole32) else # optional upnp AC_SEARCH_LIBS(upnpDiscover, miniupnpc, [AC_SUBST(upnp, 1)], [AC_SUBST(upnp, 0)] ) # optional fontconfig AC_SEARCH_LIBS(FcInitLoadConfigAndFonts, fontconfig, [AC_SUBST(fontconfig, 1)], [AC_SUBST(fontconfig, 0)], -lfontconfig ) # optional fluidsynth AC_SEARCH_LIBS(new_fluid_settings, fluidsynth, [AC_SUBST(fluidsynth, 1)], [AC_SUBST(fluidsynth, 0)] ) # optional fluidsynth AC_SEARCH_LIBS(FcInit, fontconfig, [AC_SUBST(fontconfig, 1)], [AC_SUBST(fontconfig, 0)] ) if uname | grep "Darwin" then AC_LANG_PUSH(Objective C++) AC_CHECK_HEADERS(AVFoundation/AVFoundation.h) AC_CHECK_HEADERS(QTKit/QTMovie.h) AC_LANG_POP(Objective C++) if test "$ac_cv_header_AVFoundation_AVFoundation_h" == yes then AC_SUBST(av_foundation, 1) else AC_SUBST(av_foundation, 0) if test "$ac_cv_header_QTKit_QTMovie_h" != yes then AC_MSG_ERROR([Neither AVFoundation nor QTKit are available as a sound driver. Simutrans will not compile!]) fi fi AC_SUBST(os_type, mac) else # Mac stuff AC_SUBST(av_foundation, 0) if test "$ac_cv_header_LocaleRoster_h" == yes then AC_SUBST(os_type, haiku) elif uname | grep "Linux" then AC_SUBST(os_type, linux) elif uname | grep "BSD" then AC_SUBST(os_type, freebsd) elif uname | grep "miga" then AC_SUBST(os_type, amiga) else AC_MSG_ERROR([Unknow OS!]) fi fi fi # and backend ... AC_ARG_ENABLE([server], [AS_HELP_STRING( [--enable-server], [Builds a server without graphics])], [], [enable_server=no]) # first test if forced as server if test "x$enable_server" != "xno" then AC_SUBST(backend, posix) elif test "$ac_cv_header_windows_h" == yes then AC_SUBST(backend, gdi) AC_MSG_WARN([Using GDI backend!]) AC_SEARCH_LIBS(FT_Init_FreeType, freetype, [], [AC_MSG_ERROR([FreeType Library is needed for graphical interface!])]) elif test "$ac_cv_lib_SDL2_SDL_GetRenderDriverInfo" == yes then AC_SUBST(backend, sdl2) AC_MSG_WARN([Using SDL2 backend!]) AC_SEARCH_LIBS(FT_Init_FreeType, freetype, [], [AC_MSG_ERROR([FreeType Library is needed for graphical interface!])]) else AC_SUBST(backend, posix) AC_MSG_WARN([No backend found, using server (posix)!]) fi # are we in a svn? if svn info then AC_SUBST(svn, 1) else AC_SUBST(svn, 0) fi AC_CONFIG_FILES([config.default]) AC_OUTPUT simutrans-124.3/documentation/000077500000000000000000000000001474050137200164245ustar00rootroot00000000000000simutrans-124.3/documentation/Doxyfile.in000066400000000000000000000137031474050137200205430ustar00rootroot00000000000000# Doxyfile 1.12.0 # This file describes the settings to be used by the documentation system # Doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). # # Note: # # Use Doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] # Use Doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables or CMake type # replacement variables: # doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = "Simutrans" PROJECT_ICON = "@CMAKE_CURRENT_SOURCE_DIR@/src/simutrans/simutrans.svg" OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@/documentation/simutrans/" OUTPUT_LANGUAGE = English ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the OPTIMIZE_OUTPUT_FOR_C = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_LOCAL_METHODS = YES SORT_GROUP_NAMES = YES SORT_BY_SCOPE_NAME = YES #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/src/" \ "@CMAKE_CURRENT_SOURCE_DIR@/documentation/simutrans_doc.h" FILE_PATTERNS = *.c \ *.cc \ *.h \ *.mm RECURSIVE = YES # Simutrans Squirrel API has its own documentation definition EXCLUDE = "@CMAKE_CURRENT_SOURCE_DIR@/src/simutrans/script/" \ "@CMAKE_CURRENT_SOURCE_DIR@/src/external/" #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = YES #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to Sqlite3 output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # Configuration options related to diagram generator tools #--------------------------------------------------------------------------- HAVE_DOT = @DOXYGEN_HAVE_DOT@ DOT_PATH = "@graphviz_dot_dir@" simutrans-124.3/documentation/DoxyfileSQAPI.in000066400000000000000000000024541474050137200213420ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # Doxygen file to generate documentation for Squirrel API # Assumes Doxygen is started in src/simutrans/script/api/ # PROJECT_NAME = Simutrans-Squirrel-API PROJECT_ICON = @CMAKE_CURRENT_SOURCE_DIR@/src/simutrans/simutrans.svg OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/documentation/sqapi/ EXTRACT_PRIVATE = YES INPUT = api_factory.cc \ api_base.h \ api_doc.h \ changelog.h \ api_skeleton.h \ api_skeleton.cc \ api_city.cc \ api_command.cc \ api_const.cc \ api_control.cc \ api_convoy.cc \ api_gui.cc \ api_halt.cc \ api_include.cc \ api_line.cc \ api_map_objects.cc \ api_obj_desc.cc \ api_pathfinding.cc \ api_player.cc \ api_schedule.cc \ api_settings.cc \ api_scenario.cc \ api_simple.cc \ api_world.cc \ api_tiles.cc INPUT_FILTER = ./filter_cpp.sh FILTER_PATTERNS = *.cc #FILTER_SOURCE_FILES = YES #FILTER_SOURCE_PATTERNS = ./filter_sq.sh SOURCE_BROWSER = YES ENABLE_PREPROCESSING = YES PREDEFINED = SQAPI_DOC EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/simutrans/pak/scenario/ EXAMPLE_PATTERNS = *.nut = simutrans-124.3/documentation/NeuePalette.png000066400000000000000000000041431474050137200213470ustar00rootroot00000000000000‰PNG  IHDR! ÌŸ5ŒPLTE$Kg9^|Lq‘`„§t—½ˆ«Óœ¾é°ÒÿXXXkkk}}}¢¢¢µµµÈÈÈÛÛÛ7…G–%V§0f¹:uÊE…ÜO•íZ¥ÿ{XŽo¡†´Æ´ÙË ìâ ÿù V n(†0ž9¶AÎJæRÿ["; ,P5e?zM\¤%j¹,yÏ4VNlb‚v˜Š®žÄ²ÚÆñÛJz_‹t%œŠ5­ E¿µUÐËeááuó;)S7kEƒT›b³qË€ãW+o E‡\Ÿ-s·>ŠæJ®õyÂÿœÑ0 ,JDc-]|>v•O®`¨ÇqÁá‚6R,,nE:‹_H¨yVÅ“eâ­sÿÇ‚ dt!‹,¢)J¹9hÐL„ç` ÿ+.D2U]Fnv[‚oª¨„¾Á™ÒÛ®æ? Z&u:*‘N7¬bCÈvPãŠ\ÿŸi D!^86xQL“jb®ƒxÉœŽäµ¤ÿÏ@`€Àÿÿ@@ÿ``ÿ€€€Äáðÿ@ÿ@^ÿ^€ÿ€€Ààÿ@ÿ^ÿjÿ€ÿ€@Áa×kÿ€ÿ€ÿ•+ÿªUÿÁ„4@ P0`@p T„h”€¨,¤¤ÁÁ××ÿÿÿÿ ÿÿ@ÿÿ€ÿÿ¬ @Tl,€8(”H8¨\L¸lX@`px Š@œH ®`0À€@ @@``€€¬¬ÀÀàà@`Pl `x0p8€¬@–ÒD¬îPÀÿ` 000@@@PPP```¬¬¬ìììÿÿÿ))6<-FK>l_Mˆqi–‡x°¥‘ÚÆ¿èÝÿ!ÿÿS›ñÁ±ÑWeoããÿMMMÿÿkkk›››³³³ÉÉÉßß߀€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÁ¬È€IDATxÚíÝYws‡ñ7•%YÒ‚²¯©”½dÉ’„Ee_²•} e …(ŒFQ´hA5JÚ˜le_²Ó˜n-75æ¹|æ5çwë?ó|fÎÍ÷ò¹8çœù9/¼Is¸„õUÂ2°¼ZX^#,¯–y…e>a™_X–× Ë‚ÂòzaYHX–E¤BªP…*T¡ U¨BªP…*T¡Y(”)©ÐH…F(´¨°¾AX–7 Ë›„åÍÂòaY\X––%…å­Âò6aYJX––e„eY©P…*T¡ U¨BªP…*T¡ Uh eJ…F*4R¡ -'¬Ë Ë Â²¢°¬$,+ Ë*²ª°¼]XV–wË;…å]²º°¼[XÞ#ªP…*T¡ U¨BªP…*T¡ ÍB¡L©ÐH…F*4B¡5„uMaYKXÖ–u„e]aYOXÞ+,ï–õ…åý²°l(, ËÆÂò©P…*T¡ U¨BªP…*T¡ Uh eJ…F*4R¡ m"¬› Ëf²¹°l!,–-…e+aÙZX>$,Ûˇ…e[aùˆ°l',• U¨BªP…*T¡ U¨BªP…f¡P¦Th¤B#¡Ðöºƒ°ì(,– Ë'„哲“°|JX>-,; Ë.Âòaù¬°|NXv• U¨BªP…*T¡ U¨BªP…f¡P¦Th¤B#¡Ðnº»°ì!,{ Ë^²·°ì#,û Ë~ÂòyaÙ_X–…å a9XX¾ ªP…*T¡ U¨BªP…*T¡ ÍB¡L©ÐH…F*4B¡/ ë!Âò%a9TX–Ã…åËÂr„°),G ËÑÂrŒ°+,Ç ËñÂr‚T¨BªP…*T¡ U¨BªP…*4 …2¥B#©Ð…NÖ¯ËIÂr²°œ",_–¯ Ë©Ârš°œ.,gË×…åLa9KXΖoH…*T¡ U¨BªP…*T¡ U¨B³P(S*4R¡‘ Pè›Âzްœ+,ç Ë·„å|a¹@X¾-,ß– …å"a¹X^~¹DX¾+,/wªE…*T¡ U¨BªP…*T¡ U¨B¯ìB™R¡‘ Th„B— ë÷„åûÂr™°\.,?– ËÂr¥°üHX~,,?–Ÿ ËUÂò3aù¹T¨BªP…*T¡ U¨BªP…*4 …2¥B#©Ð…~!¬¿–«…åa¹VX~%,¿–ßËÜ_À_',¿–ß ËõÂò{a¹AXþ ªP…*T¡ U¨BªP…*T¡ ÍB¡L©ÐH…F*4B¡? 럄åÏÂòa¹QXn–¹ßëüUXn–[„åVa¹MXn–¿ Ëß…å©P…*T¡ U¨BªP…*T¡ Uh eJ…F*4R¡ Ý)¬w ËÝÂr°Ü+,÷ ËýÂò€°<(,ÿ–‡„åaayDX–Ç„åq©P…*T¡ U¨BªP…*T¡ Uh eJ…Fæl—i¡ÐÂú¤°<%,ÿ– Ë¿…å?Âò´°<#,>¥—åYaY@Xþ+, ˲ˆT¨BªP…*T¡ U¨BªP…*4 …2¥B#©Ð…æ¾ë$,§ ‹¿8gñ_¾Xž–ç…ÅÏÍY^–S„åLañɹ,sßßÿ',ÿ¿ªP…*T¡ U¨BªP…*T¡ Uh eJ…F*4òðùþô®»5ðIEND®B`‚simutrans-124.3/documentation/ReservedColors.png000066400000000000000000000036671474050137200221070ustar00rootroot00000000000000‰PNG  IHDRö¬ÇeÆ~IDATxÚíÝ1¬EÇñ=£¡4@„&Vb#ÁŠB ^(”B*ƒ„‚¢Qã3j¨4ÄP$&TX y4ZPI°+€bI4 œ\œÛ·;³ûßÝÙÝ»ß~?¡˜wogwîî÷†Ù½›ÙÑñ8t­ê»@»ˆ8Ä­î»ód÷Âaã–—–N¹ò>2Öúþì§®üÎ{_k}ýå»®|ìóoµŽð–+qêGc­÷¿æÊgÏÿf¬u`ß‹®|ñ§¿Œµö¼ú¬+ÿ|ÕX)yeGözqˆ{Ò‹oò¿¸óÿièä·wú8+Í4ÌÒ†X­íñY#®é@%ýv.¿ÁËÿú}ƒ3!ë¬IÞ?xÌ/ÿ@e’¤ßì|'ÚY“–Dç­¤òé¦wðOdú‘Ðx#ý¸%Uùý—VuhÌ//‰ºÇ]WWÚ­ZªT ™±msgÚ‹[úÅå'câÐã¡N½@!#ßCà?Ý ÉŸÃ9úí£ŸLŸùƒ‰Ò_r!5týÑwœ“—:“oÔS­÷ŽÅÝ|òÛ$w±/SÅ>FU4î³ö¡¡äIċ߸æCŽP•Ò]l`Üg‡Æ|‰9Pa,ç#ñÐY&лž¿ˆ´/ÓB‡8"qDâˆ8Äqˆc~'÷[_®#ç¹ò¹£kŒµöŸxèÊ?_k¬õú±®üË7댵^~û¾+_¿ø”±Ö¶=ÿºò½+Ok­ßù+¯¹õŒ±ÖÃÍ»ò†ëµî®½—y„^â˜_r\>›wÓ^ÜMë}nòDItÑ; ¯b>Ä1¿• J˜ÌÀ—%ú‹Ž.1ß|Ë`~ùÓÄ\c~?GAg˜qÌÀ÷ãÓÌÀ¯Ü*ÌfàC3ð!ŽøÇ—i!ŽˆC‡8"qDâˆ8Äqˆ#âGÄ!ŽˆC‡8"qDâˆ8Äqˆ#âGÄ!ŽˆC‡¸'÷.ß“~и¾q³&:8ÄL{ñ‚踕]ë!—èÑŠ A„Ó‚o¥ Òz·Ï¬KèÖ…Ëï9¿Ÿè+ä³€Û`­¸×ORqIüÐ6ÞUÆí òG_!ŸÛ÷ ÙŠJÕ„ˬה†#~{óèÅ%{ÑP²ŸsOŠßÊuñ™ºß"ºä‰x½E¸›k¯‹¥ó²¢ûnüªRhJÏÝÞÜRüÞÇÕKÛÌX|Pš®LKh0ã†2Ç`Õ¹c›ñs`°„>Ä1P8"qDâˆ8ÄÕ¹¢bÔÙ%óM׬¨··?vå Û·kݽvsZ+Ùg­•œwåSgîk>¸Þ•¿ð«±Ö {_r壇Žk8}•ýi¬”¬~nZ>´w¯±Öé \yêEc­»§[n2÷Æ·¯ø‘^âˆ8ÄE¨|qÅûQ~0Ã7WÌ^¼`Bq"][•LÊC“òó;ºpDÕâ•´Ò Î@Kú?ÝäËÜhU[§ŸÆŒˆñ‚ AÞ±xfÅ•„.-ˆ</t¬ÿ±xÂ…´©£+*!ù± WÏ'ÙhÛ n&Æâ@{ˆ8Äqˆ#âGÄ!ŽˆC‡8"ôCanÎèë³??ýBÎxÛfëþ¯ßšÖ¿i­5úΕ/]5ÖZܽÕ¯^Z4ÖÚ±{±a­ñø–±Öh4}Ýjkô±õXãORǵ~™j<^‘‡È§›Æ»ZróKt¦»¥‚,XbÑqÑâjöâ™aFfòNÁ\žü:AInbÛrޱ4íÅ÷Å´TÏÏÌškq{½[et€±8Äqˆë(â\G_ZŒxÁrã¥Uú~Y £æEÃô™b¨œ.Ú«Í1‡¸vWà }BÇÊ´ÇECˆ#âGÄ!ŽˆC‡8"qDâˆ8Äqˆ#âGÄ!ŽˆC‡8"qDâˆ8Äqˆ#âGÄ!ŽˆC‡8"qDâˆ8Äqˆ#âGÄ!ŽˆC‡¸vo„‚¾|väˆqËOžtå¥3gŒµtå+KKÆZ;\ùæåËÆZ[víråû7nk­ÛºuRè¡ß8Õ¸éO½Zmï ³oˆ½8Kª cqˆ›öâ™ÿ»Cw‚Mÿª JFÁÀÀ²sïÍ K›QüøäGû³=ÁÐfùö{•¿at¨yüçS§ϼ¸éû|{ߪ$ð:w ·ï<_%VóJŸuA-Ëf™(´³xçœ?Ô“x®"Áô¿âÝ›:,ÎwæÕØÆx8ïf¥uCZùÍèÅ뉺Yé(rTÝÏì«ÔÎå—%ý—OÄ뙳+*î]÷þo0ûB=}(Êé?þü³†E×WTšw·¥ãþè=ºq‡•Žki'×ï£(x~¸\µ/Iï¡tç‰!+ùkMšWµÍ56+m§+çŒû¼h:Pñ¾âÞ-U ¶4þª¸ –C‡¶±”3?$8´™÷”1©ˆX7ÇG?3~º=svºÙ%ã[öÏ¿Š«“ï–p’q T ŽˆC‡8"qDâþžùG1iìIEND®B`‚simutrans-124.3/documentation/about-the-code.txt000066400000000000000000000063331474050137200217720ustar00rootroot00000000000000 Short Description of the Simutrans code ======================================= Simutrans is actually quite hierarchical, as it was a learning project for OOP once. It starts all with karte_t, which holds an array of planquadrat_t (a 2D coordinate), which holds arrays of grund_t (the actual ground, or foundations, tunnel, bridges, highways, water). Each ground holds an objlist, which contains moving objects such as cars, trains and airplanes as well as other objects including buildings and trees. The objects are derived from obj_t and are located in the obj/ folder. Each stuff can have three periodic calls: for very regularly and fast actions which require exclusive access on the map (moving cars, collision avoidance) there is sync_step, called before every frame. Slower actions like route_finding, way building etc. is done in step(), where the map can change in between slightly. Some objects (most notable trees) require seasonal changes, which are covered by the relatively new action method of check_season(); The program was developed by a single person most of the time, so sometimes the documentation might not be as good as it could be. So if you find something out about a section of code please document it. But other than that, most of Simutrans is quite compartmentalised and separate from other modules. Therefore it is, in my humble opinion, best to just work locally on one issue, and submit a patch. You will get some critical reception in the forum at https://forum.simutrans.com. How the UI works ---------------- The UI is almost fully separated from the main code. All dialogues are nowadays derived from gui_frame_t and fully object oriented. If you want to add a new dialogue, derive it from the gui_frame class. Then add components out of the gui/components folder. You will find almost all components there you could need. Scroll bars are best used as scroll panes: the containing component will be clipped and can be drawn as normal. After initializing a component you have to add it to your dialogue using add_component(). Failing to do so will just not show it. Certain active things like buttons and many more can give a feedback. Use action_listener(this) for them, or query them on closing; you do not need to handle events for them yourself. Comboboxes are more tricky, but you can ignore this for now. When there is an action (like a mouse click, test input finished by return etc.) and you have called action_listener(this) before, then action_triggered() will be called by the element. It has two parameters, one is a pointer to the element (to find also out which called) and the second the returned value. For buttons there are two variants of types. The one with _state are the recommended one, as they will keep their latest state. If you use only components from gui/components, it may be enough to init your dialogue and query them when the dialogue is closed. You do not need to define drawing or action routines. It can be as easy as that. The extended settings are an example for this. Certain elements have certain spacings. Please use the spacings provided by gui_themes.h which will scale nicely even with different button or font sizes. Avoid fixed numbers without good reasons. Written Nov. 2011/Feb 2014 by prissi simutrans-124.3/documentation/coding_styles.txt000066400000000000000000000330421474050137200220350ustar00rootroot00000000000000All this rules are written as the code should be. Simutrans does not yet conform 100% to this rules, but it should. 1. General coding rules: ----------------------- - Use always the simplest working solution. -> The solution must work, and should be safe and robust. Try to use the simplest (not shortest!) piece of code which gives the needed result. -> So called hacks and tricks most often break this rule. - Use always the same name for the same thing (i.e. give variables with same semantics the same name) -> This rule tries to avoid confusion and reduces the amount of things one has to remember while coding - Use meaningful names. Method names should describe actions (i.e. use "scrollbar_moved" instead of "scrollbar_callback"). Class names should be nouns, method names should be verbs or include action descriptions. -> A method named "holy_hand_grenade()" may be useful, but what does it do? Try to give the reader as much information as possible about what's going on there. -> Class names should be nouns because classes are static elements -> Method names should be verbs because methods are dynamic elements There are some standard prefixes used throughout the program: get_ returns a value set_ will set a value is_ (ist_) will test a conditions For new functions, the first (English) form should be used. Function names should never start with uppercase letters. - Use const wherever possible -> This helps the reader of the program (he sees which values are intended not to be changed) and the compiler (to optimize the code) - Keep as much class members as possible private -> This reduces dependencies between classes. Therefore the program can be changed easier and the probability of errors reduces. - Always initialize all member variables in all constructors -> Even if it seems easy, often it is forgotten - particularly if a class has several constructors - It is preferred to have class and member variables private and public get_/set_ methods instead of public variables. -> This allows adding actions to value changes and retrievals. -> Read the section about extern variables for more benefits of using getter/setter methods. There are strong advantages! - Avoid public member variables. Never use "protected" variables, rather make the variable private and use public or protected gib_xxx() and setze_xxx() methods. -> protected variables can be changed in subclasses. The super class doesn't see this changes and can't react to them. This is likely to produce errors and makes the code harder to maintain. -> sometimes it's necessary to bind actions to value assignments to variables later on in development. Public variables don't support this change of protocol and impose much work on the programmer if such a change is needed later. -> (prissi:) However, do not hide too much. Especially with virtual functions the use of protected members is also advisable. - Avoid extern variables. Global variables make programs harder to change and make some bugs harder to find. Sometimes it gets necessary to bind actions to variable access. Use getter/setter procedures and static variables instead. -> this rule reduces direct coupling and thus enhances the chance for reusing a component. -> using getter/setter methods allows to bind actions to read/write access later on -> using getter/setter methods allows checking for valid values in assignments -> using only one of getter/setter allows to make a variable read only or write only for other parts of the program. Read only is not the same as constant, and can't be replaced with a const variable. Write only is also not expressible with language features themselves. - References are preferred instead of pointers. -> References can be NULL and add safety and robustness to a program. Many problems with pointers don't occur when references are used. Unfortunately references can't be used always instead of pointers. -> Don't complicate code. Use pointers if the use of references would complicate things. -> Also reference can hide the fact, that a variable is changed. Thus again, use const when possible. - Avoid casts if possible. -> casts can lead to errors which are very hard to find, especially if pointers to connect are casted. -> try to use dynamic_cast(expression) if you need to cast (even though this eats performance) - Don't cast const'ness away. Use mutable copies of the objects or think about another design if you run into problems with const. -> Program maintainers and compiler rely on things declared const to be immutable. Both run into trouble if you cast const away. - If you need to cast use dynamic_cast() to get type checking support from the compiler. On static pointers, also a static_cast() can do the trick. - Avoid void * if possible. This is especially dangerous when used for pointers to objects, because the compiler can't call the destructor of the object through a void pointer. Also all type checks are impossible on void *. Use of void* is tolerated in C code, but not in C++ code. -> try using templates instead of void pointers. - Keep code readable. Spaces and formatting help the reader. I.e. space between methods shows clearly the end of one method and the beginning of another. On the other hand spaces can destroy readability if used wrong. -> Use spaces where the visual separation of things reflects separate entities in the code. -> Unreadable code is hard to maintain. Time is a valuable resource. Spaces and newlines are cheap. Use the cheap resource to save the valuable. - Avoid includes in header files. Use forward declarations "class xyz_t" where possible. -> This rule tries to reduce coupling of code and compile time. - use inline methods just for very small methods (1 to 3 lines max.) -> This rule tries to reduce coupling of code and compile time. - use the size defined type like sint8, sint16, sint32, sint64 and uint8, uint16, uint32 and image_id (for image numbers) Different compilers/platforms use different rules for values. If your code depends on signedness, write this explicitly down. Note, that this errors don't show up on your platform/with your compiler but perhaps only on your teammates systems. Be very careful about this because you can't test for this problems in your own development environment. i.e. Linux/PPC treats chars as unsigned, whereas Linux/Intel treats chars as signed values! -> This rule tries to increase robustness of the code There is one exception to this rule: If you really ever need to cast a pointer to an int, cast it to "long". All C compiler will guarantee, that a pointer fits into a long. - take care of boundary violations. Simutrans offers bounds checked templates (arrays, vectors, lists). Use them where possible. If you have to use plain arrays, always double check the values. Never trust a parameter! The caller might be erroneous, or a dangling pointer trashed some memory. I feel urged to write: ever and always check index values before accessing a plain array. -> This rule tries to increase robustness of the code - keep class interfaces minimal Classes should have only the minimal set of methods that are needed to cover all requirements. Convenience methods should go into other modules or subclasses. -> Small interfaces enhance the readability and understandability of a class. -> Small interfaces also enhance the re-usability. -> Separating convenience from core methods helps to understand the structure of the design. Try to comment all classes and methods in header files. Don't hesitate to write comments for variables, too. -> Class and method comments are found in the header files rather than the code files. Code files carry comments on algorithms and operations. Class comments should include: 1.) Purpose of the class. 2.) Relations of this class to others. 3.) What are the duties of this class (what are not?) 4.) Creator and creation date (if modified by someone else add a note too!) Method comments should answer the following questions: 1.) What does this method do? 2.) How does it do it? 3.) Why is it done that way? 4.) What is valid input (what not?) 5.) What are the results for valid input 6.) How does it react on invalid input? 7.) In which context should/may/can't this method be used? (If appropriate) 8.) Creator and creation data (if modified by someone else add a note too!) Class/Instance variable comments should state: 1.) Purpose of this variable 2.) Range of valid values, maybe a list of 'special' values if there are any 3.) Creator and creation data (if modified by someone else add a note too!) I know, many existing things in Simutrans are not commented in full detail, but new things should be! Rather add comments on old parts than leave out comments on new parts, if you want to have consistency. - Header comments: Include files which define classes do not need header comments, because the class comment can serve as a header comment. Other files should carry header comments like the example shown below: /* boden.cc <- name of the file * * Natur-Untergrund für Simutrans. <- Short description of file contents * Erstellt am ???? <- Creation date (if known) * Überarbeitet Januar 2001 <- Additional history information * von Hj. Malthaner <- author/creator of the file */ If you found an outdated version (very likely) it would be great if you update it. 2. Coding styles ---------------- Always use braces. Even is there is only one line in that block! An example: if(condition) { // do something here } else { // do something else here } Or K&R if you really like this more if(condition) { ... } else { ... } No other styles of using braces are allowed. This rule applies to loops and other compound statements, too. Do not forget brackets along comparisons and use double spaces around logical operators. Avoid spaces before the comparison operator: if((i&3)==1 && ptr==NULL) { You may also use double spaces after/before the brackets: if( (i&3)==1 && ptr==NULL ) { No space between if/while/for and bracket is allowed. Use spaces in for loops like in ifs: for( int i=0; i<10; i++ ) { Use spaces in parameters list. For example: call(x, y, count); instead of call(x,y,count); If a function accepts no parameters, on its delaration, and using C++ notation we'll use: int function() This C-style declaration is *not* conformant to our standards: int function(void) Also a space between type and pointer mark is preferred: use char *bla_t::get_text() instead char* bla_t::get_text() For function definitions, put the return type in the previous line: const slist_tpl * stadt_t::get_all_buildings() const { ... Do not use macros; if possible use inlines. If you use macros, then list all parameters like #define bla(s,t) ((s)+(t)) and don't forget the brackets around each parameter! (Again, better use inline) 3. Tables and detailed information ---------------------------------- According to the rule "Use always the same name for the same thing" we need a list of common names to avoid confusion. Unfortunately the program was started with many german terms in use, so many of the names are german names: Preferred variable names: Loop counters (int): i, j, n Indices (int): i, index, n Coordinates: pos (position), k (arbitrary coordinate) Screen positions: x, y (short form), xpos, ypos (long form, preferred) Convoi: cnv Vehicles: v Rail signals: sig Rail blocks: bs (obsolete) Grounds: gr (often also bd (from boden)) Roads: str Railroads: sch Generic way: weg Buildings: gb Factories: fab UI components: comp, c (temporary component variables) seldom directly used UI windows: ??? (win is preferred) UI events: ev Button: button Button lists/vectors: buttons Scrollable list: scl Temporary int value: t Temporary char value: c Temp. general value: tmp Temporary result: r, res, result ('result' is preferred) Variable pre-/suffixes: Offsets to a base value: xxx_off Method pre-/suffixes: Retrieving a member variable value: [obsolete: gib_xxx()] use get_xxx() Setting a member variable value: [obsolete: setze_xxx()] use set_xxx() Adding a listener to a component: add_listener(xxx_listener_t *) Remove a listener from a component: remove_listener(xxx_listener_t *) Class per-/suffixes: Standard class names get the suffix "_t" (for "Type") Template classes get the suffix "_tpl" (for "template") GUI (windows) classes carry a "_gui_t" suffix Classes of the new, component-oriented UI carry a gui_ prefix instead of the _gui_t suffix. Written by Hj. Malthaner Initial version: November 2000 MFC-coding styles: For being able to compile Simutrans with MSVC v6.00, some additional rules are necessary: (these are more suggestions, since it does not compile with VC6.0) 1. Change the following construct from: class myclass { ... static const int MY_CONST = 77; ... }; to: class myclass { ... enum { MY_CONST = 77 }; ... }; Reason: VC cannot compile the first. Both constructs achieve the same result. 2. Do not use: any_type *x = new any_type[0]; Reason: VC code crashes when deleting a zero sized array. Written by prissi Initial version: June 2006 simutrans-124.3/documentation/header.txt000066400000000000000000000003251474050137200204150ustar00rootroot00000000000000/* * filename * * Copyright (c) 1997 - 2011 Hansjörg Malthaner and * the simutrans development team * * This file is part of the Simutrans project under the artistic license. * (see license.txt) */ simutrans-124.3/documentation/simutrans-palette.pal000066400000000000000000000050461474050137200226100ustar00rootroot00000000000000JASC-PAL 0100 256 36 75 103 57 94 124 76 113 145 96 132 167 116 151 189 136 171 211 156 190 233 176 210 255 88 88 88 107 107 107 125 125 125 144 144 144 162 162 162 181 181 181 200 200 200 219 219 219 17 55 133 27 71 150 37 86 167 48 102 185 58 117 202 69 133 220 79 149 237 90 165 255 123 88 3 142 111 4 161 134 5 180 157 7 198 180 8 217 203 10 236 226 11 255 249 13 86 32 14 110 40 16 134 48 18 158 57 20 182 65 22 206 74 24 230 82 26 255 91 28 34 59 10 44 80 14 53 101 18 63 122 22 77 143 29 92 164 37 106 185 44 121 207 52 0 86 78 0 108 98 0 130 118 0 152 138 0 174 158 0 196 178 0 218 198 0 241 219 74 7 122 95 21 139 116 37 156 138 53 173 160 69 191 181 85 208 203 101 225 225 117 243 59 41 0 83 55 0 107 69 0 131 84 0 155 98 0 179 113 0 203 128 0 227 143 0 87 0 43 111 11 69 135 28 92 159 45 115 183 62 138 230 74 174 245 121 194 255 156 209 20 48 10 44 74 28 68 99 45 93 124 62 118 149 79 143 174 96 168 199 113 193 225 130 54 19 29 82 44 44 110 69 58 139 95 72 168 121 86 197 147 101 226 173 115 255 199 130 8 11 100 14 22 116 20 33 139 26 44 162 41 74 185 57 104 208 76 132 231 96 160 255 43 30 46 68 50 85 93 70 110 118 91 130 143 111 170 168 132 190 193 153 210 219 174 230 63 18 12 90 38 30 117 58 42 145 78 55 172 98 67 200 118 80 227 138 92 255 159 105 11 68 30 33 94 56 54 120 81 76 147 106 98 174 131 120 201 156 142 228 181 164 255 207 64 0 0 96 0 0 128 0 0 192 0 0 255 0 0 255 64 64 255 96 96 255 128 128 0 128 0 0 196 0 0 225 0 0 240 0 0 255 0 64 255 64 94 255 94 128 255 128 0 0 128 0 0 192 0 0 224 0 0 255 0 64 255 0 94 255 0 106 255 0 128 255 128 64 0 193 97 0 215 107 0 255 128 0 255 128 0 255 149 43 255 170 85 255 193 132 8 52 0 16 64 0 32 80 4 48 96 4 64 112 12 84 132 20 104 148 28 128 168 44 164 164 0 193 193 0 215 215 0 255 255 0 255 255 32 255 255 64 255 255 128 255 255 172 32 4 0 64 20 8 84 28 16 108 44 28 128 56 40 148 72 56 168 92 76 184 108 88 64 0 0 96 8 0 112 16 0 120 32 8 138 64 16 156 72 32 174 96 48 192 128 64 32 32 0 64 64 0 96 96 0 128 128 0 144 144 0 172 172 0 192 192 0 224 224 0 64 96 8 80 108 32 96 120 48 112 144 56 128 172 64 150 210 68 172 238 80 192 255 96 32 32 32 48 48 48 64 64 64 80 80 80 96 96 96 172 172 172 236 236 236 255 255 255 41 41 54 60 45 70 75 62 108 95 77 136 113 105 150 135 120 176 165 145 218 198 191 232 1 221 1 255 33 29 255 255 83 127 155 241 193 177 209 87 101 111 227 227 255 77 77 77 255 1 127 1 1 255 0 0 0 107 107 107 155 155 155 179 179 179 201 201 201 223 223 223 0 0 0 128 0 0 0 128 0 128 128 0 0 0 128 128 0 128 0 128 128 192 192 192 128 128 128 255 0 0 0 255 0 255 255 0 0 0 255 255 0 255 0 255 255 255 255 255 simutrans-124.3/documentation/simutrans_doc.h000066400000000000000000000074701474050137200214570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file simutrans_doc.h Just contains pages of exciting documentation */ /** * @mainpage * * Simutrans * * @tableofcontents * * Simutrans Code Documentation * * License * ======= * * Simutrans is licensed under the Artistic License version 1.0. The Artistic License 1.0 is an OSI-approved license which allows for use, distribution, modification, and distribution of modified versions, under the terms of the Artistic License 1.0. For the complete license text see LICENSE.txt. * * Simutrans paksets (which are necessary to run the game) have their own license, but no one is included alongside this code. * * * * * @section s_squirrel squirrel Scripting language * ------------------ * * The scripts have to be written in squirrel. The manual can be found at Squirrel main page. * As squirrels like to crack nuts, understandably the script files get the extension '.nut'. * * @subsection sec_scenarios Scripted scenarios * * .... * * ### How to create a scenario. * * You first need an @e idea - a vision what a scenario may look like. Then you have * to cast this idea into a @e savegame. That is, create the world in which your scenario will live. * You are the ruler of this toy universe, you are in charge of the rules, which go into the @e script. * * ### Recommended directory structure * * The scenario plays in a savegame. This savegame is tied to the pak-set you are using (e.g. pak64, pak128.Britain). * Hence, the scenario files have to go into a sub-folder of the pak-set. * The pak-set is found in a directory named pak-something, which is in the same directory, where the program * itself is located or under user-directory/addons/. * * Your scenario file goes into the folder * * * pak-something/scenario/myscenario/ * * * Scenarios can also be put into the addons folder: * * * addons/pak-something/scenario/myscenario/ * * * * @subsection sec_ai_player Scripted AI players * * .... * * ### Recommended directory structure * * Your script file goes into the folder * * * ai/myai/ * * * The main script file must be * * * ai/myai/ai.nut * * * The ai scripts can also be put into * * * addons/ai/myai/ * * * @subsection sec_scripted_tools Scripted tools * * .... * * ### Recommended directory structure * * The script file (tool.nut) as well as the configuration file (description.tab) go into * * * pak-something/tool/mytool/ * * * Related pak-files have to be placed in * * * pak-something/ * * * * Check out the sections on the Modules page. */ /** * @defgroup squirrel-scen-api Squirrel scenario interface * * The following methods are vital for the functioning of a scripted scenarios. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup squirrel-ai-api Squirrel ai interface * * The following methods are vital for the functioning of a scripted AI. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup squirrel-tool-api Squirrel tool interface * * The following methods are vital for the functioning of scripted tools. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup squirrel-toolkit-api Squirrel toolkit interface * * The following methods create macro scripted tools. * * * */ simutrans-124.3/documentation/utf8-support.txt000066400000000000000000000015211474050137200215640ustar00rootroot00000000000000UTF8 support works very simple: If the language file is UTF8, then all input/output is handled as UTF8. However, this is only recommended for real multibyte codepages, as SDL just returns keys from Windows/Latin codepages (0...256) and not real UTF8, as far as I could find out. Also, if a font has less than 256 characters, then the font encoding will be ignored at the moment. Otherwise the font encoding must be ISO10626-1 (or what ever Unicode is). UTF8 files are beginning with "§" in UTF8 as very first letter. The line endings must be "\xA" (see the japanese files) The only exception so far is the citylist, which must be in the same encoding as the language file. But this will also change someday. If an UTF8 file is encountered in a non UTF8 language, it will be translated to 8Bit Latin (by just ignoring all bits but the lowest 8). simutrans-124.3/readme.txt000066400000000000000000000100311474050137200155440ustar00rootroot00000000000000About ===== Simutrans is a freeware and open-source transportation simulator. Your goal is to establish a successful transport company. Transport passengers, mail and goods by rail, road, ship, and even air. Interconnect districts, cities, public buildings, industries and tourist attractions by building a transport network you always dreamed of. You can download Simutrans from: - Simutrans Website: https://www.simutrans.com/en/ - Steam: https://store.steampowered.com/app/434520/Simutrans/ Check the forum or wiki if you need help: - International Forum: https://forum.simutrans.com/ - Simutrans Wiki: https://wiki.simutrans.com/ Compiling Simutrans =================== This is a short guide on compiling simutrans. If you want more detailed information, read the Compiling Simutrans forum thread https://simutrans-germany.com/wiki/wiki/en_CompilingSimutrans If you are on Windows, download either MSVC or MinGW. MSVC is easy for debugging, MSYS2 is easy to set up (but it has to be done on the command line). - MSVC: https://visualstudio.microsoft.com/ - MSYS2: https://www.msys2.org/ Getting the libraries ------------------------ You will need pkgconfig (Unix) or vcpkg (Microsoft Visual C++) https://github.com/Microsoft/vcpkg - Needed (All): libpng2 libbzip2 zlib libfreetype - Needed (Linux/Mac): libSDL2 libfluidsynth (for midi music) - Optional but recommended: libzstd (faster compression) miniupnpc (for easy server setup) - MSVC: Copy install-building-libs-{architecture}.bat to the vcpkg folder and run it. - MSYS2/Ubuntu/Debian: Run setup-development.sh to get the libraries and set up the environment. - Linux: Use https://pkgs.org/ to search for development libraries available in your package manager. - Mac: Install libraries via Homebrew: https://brew.sh/ Compiling --------- Go to the source code directory of simutrans (simutrans/trunk if you downloaded from svn). You have three build systems to choose from: make, MSVC, and CMake. We recommend make or MSVC for debug builds. Compiling will give you only the executable, you still need a Simutrans installation to run the program. You can start simutrans with "-use_workdir" to point it to an existing installation. 1) make (MacOS) autoreconf -ivf (Linux) autoconf ./configure make -j 4 (MacOS) make OSX/getversion 2) Microsoft Visual C++ Open the simutrans.sln, select the target (default is GDI) and build. 3) CMake (Unix) cmake -G "Insert Correct Makefiles Generator" -B build . (Unix) cmake --build build -j 4 (MSVC) cmake.exe -B build -G "Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake (MSVC) cmake.exe --build build --config Release See here for a list of generators: https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html Cross-Compiling =============== If you want to cross-compile Simutrans from Linux for Windows, see the Cross-Compiling Simutrans wiki page https://simutrans-germany.com/wiki/wiki/en_Cross-Compiling_Simutrans Contribute ========== You cand find general information about contributing to Simutrans in the Development Index of the wiki: https://simutrans-germany.com/wiki/wiki/en_Devel_Index?structure=en_Devel_Index Reporting bugs ============== For bug reports use the Bug Reports Sub-Forum: https://forum.simutrans.com/index.php/board,8.0.html License ======= Simutrans is licensed under the Artistic License version 1.0. The Artistic License 1.0 is an OSI-approved license which allows for use, distribution, modification, and distribution of modified versions, under the terms of the Artistic License 1.0. For the complete license text see LICENSE.txt. Simutrans paksets (which are necessary to run the game) have their own license, but no one is included alongside this code. Credits ======= Simutrans was originally written by Hansjörg Malthaner "Hajo" from 1997 until he retired from development around 2004. Since then a team of contributors (The Simutrans Team) lead by Markus Pristovsek "Prissi" develop Simutrans. A list of early contributors can be found in simutrans/thanks.txt simutrans-124.3/reorganise-code-r10444.sh000077500000000000000000000212151474050137200200150ustar00rootroot00000000000000#!/bin/bash if [[ -n "$(ls | grep -e '.editorconfig')" ]]; then echo "Wrong directory!" >&2 exit 1 fi rm -rf revision.h mkdir -p src/simutrans mkdir -p src/simutrans/tool mkdir -p src/Windows svn add src declare -a PATHREPLACE=("s|\.\./squirrel/|\.\./\.\./squirrel/|") sed -i 's|#include "\.\./|#include "\.\./simutrans/|' squirrel/*.{h,cc} svn mv squirrel src/ sed -i 's|#include "\.\.|#include "\.\./simutrans|' makeobj/*.{h,cc} svn mv makeobj src/ svn mv gui src/simutrans svn mv obj src/simutrans svn mv dataobj descriptor display io music network player script sound sys tpl utils vehicle world src/simutrans/ PATHREPLACE+=("s|boden/wege/|obj/way/|") sed -i -E 's|#include \"\.\./([^/]+\")|#include \"\.\./\.\./ground/\1|' boden/wege/*.{h,cc} svn mv boden/wege/ src/simutrans/obj/way PATHREPLACE+=("s|bauer/|builder/|") svn mv bauer src/simutrans/builder PATHREPLACE+=("s|boden/|ground/|") sed -i 's|wege/|../obj/way/|' boden/*.{h,cc} svn mv boden src/simutrans/ground PATHREPLACE+=("s|nettools/|nettool/|") sed -i 's|#include "..|#include "../simutrans|' nettools/*.{h,cc} svn mv nettools src/nettool # Additional reorganizations PATHREPLACE+=("s|unicode\.cc|utils/unicode\.cc|" "s|unicode\.h|utils/unicode\.h|") sed -i 's|#include "|#include "../|' unicode.{h,cc} sed -i 's|#include "../utils/|#include "|' unicode.{h,cc} svn mv unicode.{h,cc} src/simutrans/utils PATHREPLACE+=("s|simdepot\.cc|obj/depot\.cc|" "s|simdepot\.h|obj/depot\.h|") sed -i 's|#include "|#include "../|' simdepot.{h,cc} sed -i 's|#include "../obj/|#include "|' simdepot.{h,cc} svn mv simdepot.cc src/simutrans/obj/depot.cc svn mv simdepot.h src/simutrans/obj/depot.h PATHREPLACE+=("s|simmenu\.cc|tool/simmenu\.cc|" "s|simmenu\.h|tool/simmenu\.h|") sed -i 's|#include "|#include "../|' simmenu.{h,cc} svn mv simmenu.{h,cc} src/simutrans/tool/ PATHREPLACE+=("s|simtool|tool/simtool|") sed -i 's|#include "|#include "../|' simtool* svn mv simtool* src/simutrans/tool/ PATHREPLACE+=("s|simworld\.cc|world/simworld\.cc|" "s|simworld\.h|world/simworld\.h|") sed -i 's|#include "|#include "../|' simworld.{h,cc} svn mv simworld.{h,cc} src/simutrans/world/ PATHREPLACE+=("s|simplan\.cc|world/simplan\.cc|" "s|simplan\.h|world/simplan\.h|") sed -i 's|#include "|#include "../|' simplan.{h,cc} svn mv simplan.{h,cc} src/simutrans/world/ PATHREPLACE+=("s|simcity\.cc|world/simcity\.cc|" "s|simcity\.h|world/simcity\.h|") sed -i 's|#include "|#include "../|' simcity.{h,cc} svn mv simcity.{h,cc} src/simutrans/world/ find . -maxdepth 1 -type f -name "*.cc" -exec svn mv {} src/simutrans \; find . -maxdepth 1 -type f -name "*.h" -exec svn mv {} src/simutrans \; PATHREPLACE+=("s|finder/|world/|") svn mv finder/*.{h,cc} src/simutrans/world svn rm --force finder PATHREPLACE+=("s|ifc/simtestdriver\.h|vehicle/simtestdriver\.h|" "s|ifc/sync_steppable\.h|obj/sync_steppable\.h|") svn mv ifc/simtestdriver.h src/simutrans/vehicle/ svn mv ifc/sync_steppable.h src/simutrans/obj/ svn rm --force ifc svn mv simres.rc src/Windows svn mv Simutrans.manifest src/Windows svn mv nsis src/Windows svn mv OSX src svn mv android src svn mv scripts tools svn mv distribute.sh tools svn mv findversion.sh tools svn mv get_lang_files.* tools svn mv get_pak.* tools svn mv get_revision.* tools svn mv install-building-libs* tools svn mv revision.jse tools svn mv ../base.tab src svn mv ../zipsrc.sh tools svn mv ../patches src/ svn mv *.ico src/Windows/ svn mv simutrans.svg src/simutrans/ svn mv .desktop src/simutrans/ find . -name '*_t.cc' -exec bash -c 'svn mv $0 ${0/_t\.cc/\.cc}' {} \; find . -name '*_t.h' -exec bash -c 'svn mv $0 ${0/_t\.h/\.h}' {} \; echo "Remove _t suffix from files" # remove _t also in the include files sed -i 's|_t\.|\.|' cmake/SimutransSourceList.cmake sed -i 's|_t\.|\.|' Simutrans-Main.vcxitems find . -type f -name "Makefile" -exec sed -E -i 's|_t\.|\.|' {} \; includereplace="-e s|_t\.h\\\"|\.h\\\"|" # process accumulated path and name changes in include files for pattern in "${PATHREPLACE[@]}" do echo "Replacing $pattern" if ! [[ $pattern == *".cc|"* ]]; then includereplace="${includereplace} -e ${pattern} " fi sed -i "$pattern" cmake/SimutransSourceList.cmake frontpattern=`echo $pattern | sed -E 's-(s\|.+\|).+\|-\1-'` backpattern=`echo $pattern | sed -E 's-s\|.+\|(.+\|)-\1-' | sed 's|/|\\\\\\\\|g'` mspattern=`echo $pattern | sed 's|/|\\\\\\\\|g'` sed -i "$mspattern" Simutrans-Main.vcxitems find . -type f -name "Makefile" -exec sed -E -i "$pattern" {} \; done #set -x echo "Now replace in include files" find . -type f "(" -name "*.cc" -o -name "*.h" -o -name "*mm" ")" -exec sed -i ${includereplace} {} \; sed -i 's|../world/||' src/simutrans/world/*.{h,cc} echo "Final cleaning up build system" sed -i -E 's|^\t\t([^\\\$]+)|\t\tsrc/simutrans/\1|' cmake/SimutransSourceList.cmake sed -i 's|makeboj/|add_subdirectory(src/makeobj EXCLUDE_FROM_ALL)|' cmake/SimutransSourceList.cmake sed -i 's|add_subdirectory(makeobj EXCLUDE_FROM_ALL)|add_subdirectory(src/makeobj EXCLUDE_FROM_ALL)|' CMakeLists.txt sed -i 's|add_subdirectory(nettools EXCLUDE_FROM_ALL)|add_subdirectory(src/nettool EXCLUDE_FROM_ALL)|' CMakeLists.txt sed -i 's|Directory)|Directory)src\\simutrans\\|' Simutrans-Main.vcxitems sed -i 's|ClCompile Include=\"|ClCompile Include=\"src\\simutrans\\|' Simutrans*.vcxproj sed -i 's|cscript.exe //Nologo revision.jse|cscript.exe //Nologo tools\\revision.jse|' Simutrans*.vcxproj sed -i 's|revision\.h\"|src\\\\simutrans\\\\revision\.h\"|' tools/revision.jse sed -i 's|SOURCES *+= |SOURCES += src/simutrans/|' Makefile sed -i 's|./get_revision.sh|tools/get_revision.sh|' Makefile sed -i 's| sys/| src/simutrans/sys/|' CMakeLists.txt sed -i 's| display/| src/simutrans/display/|' CMakeLists.txt sed -i 's| music/| src/simutrans/music/|' CMakeLists.txt sed -i 's| sound/| src/simutrans/sound/|' CMakeLists.txt sed -i 's| io/| src/simutrans/io/|' CMakeLists.txt sed -i 's| gui/| src/simutrans/gui/|' CMakeLists.txt sed -i 's|${SOURCE_DIR}/revision.h|${SOURCE_DIR}/src/simutrans/revision.h|' CMakeLists.txt sed -i 's|${SOURCE_DIR}/revision.h|${SOURCE_DIR}/src/simutrans/revision.h|' cmake/SimutransRevision.cmake sed -i 's|/nsis|/src/Windows/nsis|' CMakeLists.txt sed -i 's|get_pak.sh|${CMAKE_SOURCE_DIR}/tools/get_pak.sh|' CMakeLists.txt sed -i 's|get_pak.ps1|tools/get_pak.ps1|' CMakeLists.txt sed -i 's|get_lang_files.ps1|tools/get_lang_files.ps1|' CMakeLists.txt sed -i 's|../get_lang_files.sh|${CMAKE_SOURCE_DIR}/tools/get_lang_files.sh|' CMakeLists.txt sed -i 's|paksetinfo.h|src/simutrans/paksetinfo.h|' CMakeLists.txt sed -i 's|#include \"simversion.h\"|#include \"../simutrans/simversion.h\"|' src/Windows/simres.rc sed -i 's| simres.rc| src/Windows/simres.rc|' CMakeLists.txt sed -i 's|simutrans\\simres.rc|Windows\\simres.rc|' Simutrans-Main.vcxitems sed -i 's|src/simutrans/simres.rc|src/Windows/simres.rc|' Makefile # since squirrel moved up sed -i 's|simutrans/squirrel|squirrel|' cmake/SimutransSourceList.cmake sed -i 's|src\\simutrans\\squirrel|src\\squirrel|' Simutrans-Main.vcxitems find . -type f -name "Makefile" -exec sed -E -i 's|simutrans/squirrel/|squirrel/|' {} \; # Fix makeobj/nettool CMakeLists.txt sed -i 's|../|../simutrans/|' src/makeobj/CMakeLists.txt sed -i 's|../|../simutrans/|' src/nettool/CMakeLists.txt # Fix makeobj/nettool Makefile build sed -i 's|\$(MAKE) -e -C makeobj|$(MAKE) -e -C src/makeobj|' Makefile sed -i 's|\$(MAKE) -e -C nettools|$(MAKE) -e -C src/nettool|' Makefile sed -i 's|-include |-include ../|' src/{makeobj,nettool}/Makefile sed -i 's|\.\./uncommon\.mk|../../uncommon.mk|' src/{makeobj,nettool}/Makefile uncommon.mk sed -i 's|+= \.\./|+= ../simutrans/|' src/{makeobj,nettool}/Makefile sed -i 's|_PROGDIR := \.\./|_PROGDIR := ../../|' src/{makeobj,nettool}/Makefile sed -i 's|BUILDDIR := \.\./|BUILDDIR := ../../|' src/{makeobj,nettool}/Makefile sed -i 's|\.\./config\.|../../config.|' uncommon.mk sed -i 's|OBJS := $(patsubst %, $(BUILDDIR)/%-$(TOOL).o, $(basename $(patsubst ../%, %,$(filter ../%,$(SOURCES)))))|OBJS := $(patsubst %, $(BUILDDIR)/%-$(TOOL).o, $(basename $(patsubst ../simutrans/%, %,$(filter ../simutrans/%,$(SOURCES)))))|' uncommon.mk sed -i 's|OBJS += $(patsubst %, $(BUILDDIR)/$(TOOL)/%-$(TOOL).o, $(basename $(filter-out ../%,$(SOURCES))))|OBJS += $(patsubst %, $(BUILDDIR)/$(TOOL)/%-$(TOOL).o, $(basename $(filter-out ../simutrans/%,$(SOURCES))))|' uncommon.mk sed -i 's|\.\./%\.c \$(BUILDCONFIG_FILES)|../simutrans/%.cc $(BUILDCONFIG_FILES)|' uncommon.mk sed -i 's|\.\./%\.cc \$(BUILDCONFIG_FILES)|../simutrans/%.cc $(BUILDCONFIG_FILES)|' uncommon.mk # TODO Update location of paksetinfo.h in get_pak.sh # TODO fix distribution and github actions # prissi prefernces # TODO add file prefixes to some files (like obj_ for objects) # TODO rename xxx_vehicle.cc to vehicle_xxx.cc and so on simutrans-124.3/setup-development.sh000077500000000000000000000010551474050137200175730ustar00rootroot00000000000000 if grep "Ubuntu" /etc/*-release then echo "Setup for Ubuntu, please be patient!" sudo sh tools/setup-debian.sh elif grep -q MSYS2 /etc/*-release then echo "Setup for Mingw, please be patient!" tools/setup-mingw.sh elif grep "Debian" /etc/*-release then echo "Setup for Debian, please be patient!" su -c "sh tools/setup-debian.sh" fi read -p "Confirm compile simutrans? (Yy) " reply if [ $reply = "y" -o $reply = "Y" ]; then echo "Compiling using make" autoconf ./configure make -j $(nproc) echo "Update translations" tools/distribute.sh fi simutrans-124.3/simutrans/000077500000000000000000000000001474050137200156005ustar00rootroot00000000000000simutrans-124.3/simutrans/ai/000077500000000000000000000000001474050137200161715ustar00rootroot00000000000000simutrans-124.3/simutrans/ai/readme.txt000066400000000000000000000001431474050137200201650ustar00rootroot00000000000000Put AI scripts here: - Create directory for the ai script - Put the *.nut files in this directory simutrans-124.3/simutrans/ai/sqai/000077500000000000000000000000001474050137200171265ustar00rootroot00000000000000simutrans-124.3/simutrans/ai/sqai/ai.nut000066400000000000000000000121721474050137200202520ustar00rootroot00000000000000/** * Main file of the AI player. */ // TODO obey construction speed setting // TODO check allowed transport types // some meta data - unused ai <- {} ai.short_description <- "Test AI player implementation" ai.author <-"dwachs" ai.version <- "0.1" // includes include("basic") // .. definition of basic node classes include("astar") // .. route search for way building etc include("save") // .. routines to save class instances include("factorysearcher") // .. checks factories for available connections include("industry_connection_planner") // .. plans connection between 2 factories include("combined_connections") // .. plans connections using water + land transport include("industry_manager") // .. manages existing connection (buys, sells, upgrades convoys) include("placefinder") // .. utility functions to find places for stations near factories etc include("prototyper") // .. plans convoy-type for a connection include("road_connector") // .. builds road connection include("ship_connector") // .. creates ship connection include("station_manager") // .. keeps information about freight station include("vehicle_constructor") // .. constructs convoy, assign to line, start // basic functions sum <- @(a,b) a+b function abs(x) { return x>0 ? x : -x } // global variables our_player_nr <- -1 our_player <- null // player_x instance // the AI is organized as a tree, // all the work is done in the nodes of the tree tree <- {} // nodes with particular jobs factorysearcher <- null industry_manager <- null station_manager <- null // stepping info s <- {} s._step <- 0 s._next_construction_step <- 0 // the table 'persistent' will be saved in the savegame persistent.s <- s // 2.. 14 = 13 names possible_names <- ["Petersil Cars", "Teumer Alp Dream Trucks", "Runk & Strunk Transports", "A. Nach B. Transports", "Interflug Fourwheelers", "Pfarnest International", "Suboptimal Transports", "Conveyor Belts & Braces", "Bucket Brigade Inc.", "Maggikraut AG", "Bugs & Eggs Unlimited", "S. Claus & R. Deer Worldwide", "Leiterwagn & Sons" ] /** * Start-routine. Will be called when AI is initialized. * Parameter: the number of the AI player. */ function start(pl_nr) { init() our_player_nr = pl_nr if (our_player_nr > 1 && our_player_nr-2 < possible_names.len()) { player_x(our_player_nr).set_name( possible_names[our_player_nr-2]); } our_player = player_x(our_player_nr) print("Act as player no " + our_player_nr + " under the name " + our_player.get_name()) init_tree() } /** * Initialize the tree with basic nodes. */ function init_tree() { if (factorysearcher == null) { factorysearcher = factorysearcher_t() } if (industry_manager == null) { industry_manager = industry_manager_t() } if (!("tree" in persistent)) { tree = manager_t() tree.append_child(factorysearcher) tree.append_child(industry_manager) persistent.tree <- tree } else { if (persistent.tree.getclass() != manager_t) { // upgrade tree = manager_t() foreach(i in ["nodes", "next_to_step"]) { tree[i] = persistent.tree[i] } } else { tree = persistent.tree } } if (!("station_manager" in persistent)) { persistent.station_manager <- freight_station_manager_t(1) } } /** * Called after savegame is loaded. */ function resume_game(pl_nr) { init() our_player_nr = pl_nr our_player = player_x(our_player_nr) init_tree() s = persistent.s } function init() { annotate_classes() // sets class name as attribute for all known classes (save.nut) } /** * The heart beat of the player. * If the routine will take too much time, execution is suspended and later resumed. * This should be completely transparent to the script. * Then the main program is still responsive. */ function step() { tree.step() s._step++ // connector node may fail, but may offer alternative connector node local report = tree.get_report() if (report) { factorysearcher.append_report(report) } if (s._step > s._next_construction_step) { local r = factorysearcher.get_report() if (r && r.action) { print("New report: expected construction cost: " + (r.cost_fix / 100.0)) tree.append_child(r.action) } s._next_construction_step += 1 + (s._step % 3) } } /** * Helper routine: translate 3d-coordinate to string. * This can be used as key in tables. */ function coord3d_to_key(c) { return ("coord3d_" + c.x + "_" + c.y + "_" + c.z).toalnum(); } function coord_to_key(c) { return ("coord_" + c.x + "_" + c.y).toalnum(); } function is_cash_available(cost /* in 1/100 cr */) { return 2*cost + 2*our_player.get_current_maintenance() < our_player.get_current_net_wealth() } /** * Called to save into savegame. * Returns string that will be saved. * Here: we turn the persistent table into a string using recursive_save (from script/script_base.nut). */ function save() { local str = "" local tic = get_ops_total() local rem = get_ops_remaining() str = "persistent = " + recursive_save(persistent, "\t", [ persistent ] ) local toc = get_ops_total() print("save used " + (toc-tic) + " ops, remaining = " + rem) return str } simutrans-124.3/simutrans/ai/sqai/astar.nut000066400000000000000000000215371474050137200210000ustar00rootroot00000000000000/** * Classes to help with route-searching. * Based on the A* algorithm. */ /** * Nodes for A* */ class astar_node extends coord3d { previous = null // previous node cost = -1 // cost to reach this node dist = -1 // distance to target constructor(c, p, co, d) { x = c.x y = c.y z = c.z previous = p cost = co dist = d } function is_straight_move(d) { return d == dir || (previous && previous.dir == d) } } /** * Class to perform A* searches. * * Derived classes have to implement: * process_node(node): add nodes to open list reachable by node * * To use this: * 1) call prepare_search * 2) add tiles to target array * 3) call compute_bounding_box * 4) add start tiles to open list * 5) call search() * 6) use route */ class astar { closed_list = null // table nodes = null // array of astar_node heap = null // binary heap targets = null // array of coord3d's boundingbox = null // box containing all the targets route = null // route, reversed: target to start // statistics calls_open = 0 calls_closed = 0 calls_pop = 0 // costs - can be fine-tuned cost_straight = 10 cost_curve = 14 constructor() { closed_list = {} heap = simple_heap_x() targets = [] } function prepare_search() { closed_list = {} nodes = [] route = [] heap.clear() targets = [] calls_open = 0 calls_closed = 0 calls_pop = 0 } // adds node c to closed list function add_to_close(c) { closed_list[ coord3d_to_key(c) ] <- 1 calls_closed++ } function test_and_close(c) { local key = coord3d_to_key(c) if (key in closed_list) { return false } else { closed_list[ key ] <- 1 calls_closed++ return true } } function is_closed(c) { local key = coord3d_to_key(c) return (key in closed_list) } // add node c to open list with give weight function add_to_open(c, weight) { local i = nodes.len() nodes.append(c) heap.insert(weight, i) calls_open++ } function search() { // compute bounding box of targets compute_bounding_box() local current_node = null while (!heap.is_empty()) { calls_pop++ local wi = heap.pop() current_node = nodes[wi.value] local dist = current_node.dist // target reached if (dist == 0) break; // already visited previously if (!test_and_close(current_node)) { current_node = null continue; } // investigate neighbours and put them into open list process_node(current_node) current_node = null } route = [] if (current_node) { // found route route.append(current_node) while (current_node.previous) { current_node = current_node.previous route.append(current_node) } } print("Calls: pop = " + calls_pop + ", open = " + calls_open + ", close = " + calls_closed) } /** * Computes bounding box of all targets to speed up distance computation. */ function compute_bounding_box() { if (targets.len()>0) { local first = targets[0] boundingbox = { xmin = first.x, xmax = first.x, ymin = first.y, ymax = first.y } for(local i=1; i < targets.len(); i++) { local t = targets[i] if (boundingbox.xmin > t.x) boundingbox.xmin = t.x; if (boundingbox.xmax < t.x) boundingbox.xmax = t.x; if (boundingbox.ymin > t.y) boundingbox.ymin = t.y; if (boundingbox.ymax < t.y) boundingbox.ymax = t.y; } } } /** * Estimates distance to target. * Returns zero if and only if c is a target tile. */ function estimate_distance(c) { local d = 0 local curved = 0 // distance to bounding box local dx = boundingbox.xmin - c.x if (dx <= 0) dx = c.x - boundingbox.xmax; if (dx > 0) d += dx; else dx = 0; local dy = boundingbox.ymin - c.y if (dy <= 0) dy = c.y - boundingbox.ymax if (dy > 0) d += dy; else dy = 0; if (d > 0) { // cost to bounding box return cost_straight * d + (dx*dy > 0 ? cost_curve - cost_straight : 0); } else { local t = targets[0] d = abs(t.x-c.x) + abs(t.y-c.y) // inside bounding box for(local i=1; i < targets.len(); i++) { local t = targets[i] local dx = abs(t.x-c.x) local dy = abs(t.y-c.y) d = min(d, cost_straight * (dx+dy) + (dx*dy > 0 ? cost_curve - cost_straight : 0)) } } return d } } class ab_node extends ::astar_node { dir = 0 // direction to reach this node flag = 0 // flag internal to the route searcher constructor(c, p, co, d, di, fl=0) { base.constructor(c, p, co, d) dir = di flag = fl } } /** * Helper class to find bridges and spots to place them. */ class pontifex { player = null bridge = null constructor(pl, way) { player = pl local list = bridge_desc_x.get_available_bridges(way.get_waytype()) local len = list.len() local way_speed = way.get_topspeed() if (len>0) { bridge = list[0] for(local i=1; i bridge.get_topspeed()) { bridge = b } } else { if (way_speed < b.get_topspeed() && b.get_topspeed() < bridge.get_topspeed()) { bridge = b } } } } } function find_end(pos, dir, min_length) { return bridge_planner_x.find_end(player, pos, dir, bridge, min_length) } } /** * Class to search a route and to build a connection (i.e. roads). * Builds bridges. But not tunnels (not implemented). */ class astar_builder extends astar { builder = null bridger = null way = null function process_node(cnode) { local from = tile_x(cnode.x, cnode.y, cnode.z) local back = dir.backward(cnode.dir) for(local d = 1; d<16; d*=2) { // do not go backwards if (d == back) { continue } // continue straight after a bridge if (cnode.flag == 1 && d != cnode.dir) { continue } local to = from.get_neighbour(wt_all, d) if (to) { if (builder.is_allowed_step(from, to) && !is_closed(to)) { // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) // is there already a road? if (!to.has_way(wt_road)) { move += 8 } local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d) add_to_open(node, weight) } // try bridges else if (bridger && d == cnode.dir && cnode.flag != 1) { local len = 1 local max_len = bridger.bridge.get_max_length() do { local to = bridger.find_end(from, d, len) if (to.x < 0 || is_closed(to)) { break } local bridge_len = abs(from.x-to.x) + abs(from.y-to.y) local move = bridge_len * cost_straight * 3 /*extra bridge penalty */; // set distance to 1 if at a target tile local dist = max(estimate_distance(to), 1) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 1 /*bridge*/) add_to_open(node, weight) len = bridge_len + 1 } while (len <= max_len) } } } } function search_route(start, end) { prepare_search() foreach (e in end) { targets.append(e); } compute_bounding_box() foreach (s in start) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, 0, 0), dist+1) } search() if (route.len() > 0) { remove_field( route[0] ) // do not try to build in tunnels local is_tunnel_0 = tile_x(route[0].x, route[0].y, route[0].z).find_object(mo_tunnel) local is_tunnel_1 = is_tunnel_0 for (local i = 1; i= nodes.len()) { next_to_step = 0; return r_t(RT_DONE_NOTHING); } local ret = nodes[next_to_step].step() // take nodes report if (ret.report) { append_report(ret.report) } // delete child if ready if (ret.can_be_deleted()) { nodes.remove(next_to_step); } else if (ret.is_ready()) { next_to_step ++ } // successor node if (ret.node) { append_child(ret.node) } // our return code local rc = RT_PARTIAL_SUCCESS // want next call, too if (ret.has_failed()) { rc = RT_ERROR // propagate error } else if (next_to_step > nodes.len()) { rc = RT_SUCCESS // done with stepping all nodes } return r_t(rc) } } /** * Base class to report financial aspects of plans. */ class report_t { // tree that will be executed action = null // costs cost_fix = 0 cost_monthly = 0 // expected gain per month gain_per_m = 0 function merge_report(r) { action.append_child( r.action ) cost_fix += r.cost_fix cost_monthly += r.cost_monthly gain_per_m += r.gain_per_m } function _save() { return ::saveinstance("report_t", this) } } /** * Manager class. * Steps its child nodes, otherwise does some work(), generates reports. */ class manager_t extends node_seq_t { reports = null constructor(n = "manager_t") { base.constructor(n) reports = [] } function step() { dbgprint("stepping a child") local r = base.step() if (r.code == RT_DONE_NOTHING || r.code == RT_SUCCESS) { // all nodes were stepped dbgprint("doing some work") return work() } dbgprint("stepped a child") return r } function work() { } function append_report(r) { reports.append(r); } /** * Returns the best report available. */ function get_report() { if (reports.len() == 0) return null // find report that maximizes gain_per_m / cost_fix local i = -1 local best = null for(local j=0; j jps // 0x10 -> find flat place // 0x20 -> flat place (mark next step with 0x40) // 0x40 -> cannot go into water if (cnode.flag == 0x10) { process_node_to_land(cnode, from) return } local test_dir = cnode.previous ? (back ^ 0x0f) & (cnode.flag & 0x0f) : 0x0f for(local d = 1; d<16; d*=2) { // do not go backwards if (( d &test_dir) ==0 ) { continue } local to = from.get_neighbour(wt_all, d) if (to && !is_closed(to)) { local to_water = ::finder._tile_water_way(to) // water -> water // land -> land if (from_water == to_water) { // can we build way here? if (!from_water) { // empty space for station near a halt with harbour local halt = to.get_halt() if (halt && halt.get_owner().nr == our_player_nr && from.is_empty()) { // try to connect to this halt and to use its harbours process_node_to_land_halt(cnode, halt) } // can we build way here? if (!builder.is_allowed_step(from, to)) { // could be a halt on the other tile that has harbour that could be used continue; } } // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist // use jump-point search (see dataobj/route.cc) local jps = to_water && (cnode.previous) ? (water_dir ^ 0x0f) | d | cnode.dir | from.get_canal_ribi() : 0x0f if (cnode.flag & 0x20) jps = jps | 0x40; local node = ab_node(to, cnode, cost, dist, d, jps) add_to_open(node, weight) } else if (from_water) { // water -> land if (from.is_water() && to.get_halt()) { // check for existing harbour local halt = ship_connector_t.get_harbour_halt(to) if (halt) { // create node as end node of water route local harbour_node = ab_node(to, cnode, cnode.cost, cnode.dist, 0x0f, 0x0f) // now look for empty spots to connect to this halt process_node_to_harbour(harbour_node, halt) } } // we have to build ourselves if (!from.is_water() || !can_place_harbour(to, d) ) { continue } local move = cost_harbour local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 0x10) add_to_open(node, weight) } else { // land -> water if (!to.is_water() || !can_place_harbour(from, dir.backward(d)) || (cnode.flag & 0x60) ) { continue } if (cnode.previous) { local fromfrom = tile_x(cnode.previous.x, cnode.previous.y, cnode.previous.z) // want to build station here with one connecting road if (fromfrom == null || !fromfrom.is_empty() || fromfrom.get_slope()!=0 || cnode.previous.previous == null) { continue } } local move = cost_harbour local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 0x0f) add_to_open(node, weight) } } } } function can_place_harbour(tile, d_water_to_land) { return ship_connector_t.get_harbour_type_for_tile(tile, planned_harbour, planned_harbour_flat, d_water_to_land) > 0 } function process_node_to_land(cnode, from) { local pos = coord(cnode.x, cnode.y) for(local d = 1; d<16; d++) { // test all 8 neighbouring tiles if (!dir.is_threeway(d)) { local c = pos + dir.to_coord(d) try { local to = square_x(c.x, c.y).get_ground_tile() if (to && to.is_empty() && to.get_slope()==0) { // can place station here local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, 0x0f, 0x0f) add_to_open(node, weight) } } catch(ev) {} } } } function process_node_to_harbour(cnode, halt) { local visited = {} // process all tiles of this halt foreach(tile in halt.get_tile_list()) { // check all neighbouring tiles for empty spots for(local d = 1; d<16; d*=2) { local c = coord(tile.x, tile.y) + dir.to_coord(d) try { local to = square_x(c.x, c.y).get_ground_tile() if (to && to.is_empty() && to.get_slope()==0 && !(coord3d_to_key(to) in visited) ) { // can place station here local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, 0x0f, 0x0f) add_to_open(node, weight) // mark as visited visited[ coord3d_to_key(to) ] <- 1 } } catch(ev) {} } } } /** * Does steps land-tile -> halt -> harbour -> water * Last route tile is cnode, check if station can be placed. * Check for harbour tiles, put corresponding nodes to open list. */ function process_node_to_land_halt(cnode, halt) { // process all tiles of this halt foreach(tile in halt.get_tile_list()) { if (!tile.is_water() && ship_connector_t.get_harbour_halt(tile)!=null) { local harbour_node = ab_node(tile, cnode, cnode.cost, cnode.dist, 0x0f, 0x0f) local d = 0 if (tile.get_slope()) { // get direction from slope d = dir.backward(slope.to_dir(tile.get_slope())) } else { // flat dock, check all four neighbour tiles for water + harbour d = 1 } do { local to = coord3d(tile.x, tile.y, tile.z) + dir.to_coord(d) if (world.is_coord_valid(to)) { local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, harbour_node, cost, dist, d, 0x0f) add_to_open(node, weight) } d = d*2 } while (tile.get_slope()==0 && d<16) } } } function search_route(fsrc, fdest) { print("Search amphibious connection") // find station places local s = [] local e = [] c_harbour_tiles = {} s.append(::finder.find_station_place(fsrc, fdest) ) e.append(::finder.find_station_place(fdest, fsrc) ) s.append(::ship_connector_t.find_anchorage(fsrc, planned_harbour, planned_harbour_flat, c_harbour_tiles) ) e.append(::ship_connector_t.find_anchorage(fdest, planned_harbour, planned_harbour_flat, c_harbour_tiles) ) // init search prepare_search() for(local i=0; i<2; i++) { foreach (e in e[i]) { targets.append(e); } } if (targets.len() == 0) { route = [] return } compute_bounding_box() for(local i=0; i<2; i++) { foreach (s in s[i]) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, dist, 0), dist+1) } } search() print("End amphibious route search") } } simutrans-124.3/simutrans/ai/sqai/factorysearcher.nut000066400000000000000000000320171474050137200230450ustar00rootroot00000000000000/** * Class that searches for usefull unbuild factory connections. * Depending on player number uses two different methods: * 1) Method that tries to complete a factory tree (taken from the c++ implementation of the freight AI in player/ai_goods.cc * 2) A demand-driven method. */ class factorysearcher_t extends manager_t { froot = null // factory_x, complete this tree method = -1 factory_iterator = null constructor() { base.constructor("factorysearcher_t") debug = false ::factorysearcher = this } function get_next_end_consumer() { // iterate the factory_iterator, which is a generator if (factory_iterator == null || typeof(factory_iterator) != "generator") { // this is a generator factory_iterator = factory_iteration() } if (factory_iterator.getstatus() != "dead") { return resume factory_iterator } factory_iterator = null return null } function factory_iteration() { local list = factory_list_x() foreach(factory in list) { if (factory.output.len() == 0) { yield factory } } } function work() { if (method < 0) { method = our_player_nr % 2; froot = null } if (method == 0) { // traditional method, taken from C++ implementation // of Freight AI // root still has missing links? if (froot && count_missing_factories(froot) <= 0) { froot = null } // determine new root if (froot == null) { // find factory with incomplete connected tree local min_mfc = 10000; local fab while(fab = get_next_end_consumer()) { local n = count_missing_factories(fab) if ((n > 0) && (n < min_mfc)) { // TODO add some random here min_mfc = n froot = fab } } if (froot) { local fab = froot dbgprint("Choose consumer " + fab.get_name() + " at " + fab.x + "," + fab.y + ", which has " + min_mfc + " missing links") } } // nothing found?? if (froot==null) return r_t(RT_DONE_NOTHING); dbgprint("Connect " + froot.get_name() + " at " + froot.x + "," + froot.y) // find link to connect if (!plan_missing_link(froot)) { dbgprint(".. no missing link") // no missing link found - reset froot froot = null return r_t(RT_SUCCESS) } return r_t(RT_PARTIAL_SUCCESS) } else { // demand-driven method // plan root tree if (froot && plan_increase_consumption(froot) <= 0) { froot = null } // determine new root if (froot == null) { local fab if (fab = get_next_end_consumer()) { local n = plan_increase_consumption(fab) return r_t( n>0 ? RT_PARTIAL_SUCCESS : RT_SUCCESS) } } } return r_t(RT_SUCCESS) } /** * Creates the planner node */ static function plan_connection(fsrc, fdest, freight) { if (industry_manager.get_link_state(fsrc, fdest, freight) != industry_link_t.st_free) { dbgprint("Link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y + " state is " + industry_manager.get_link_state(fsrc, fdest, freight) ); return false } dbgprint("Close link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_planned); local icp = industry_connection_planner_t(fsrc, fdest, freight); append_child(icp) return true } /** * @returns -1 if factory tree is incomplete, otherwise number of missing connections */ // TODO cache the results per factory static function count_missing_factories(fab, indent = "") { // source of raw material? if (fab.input.len() == 0) return 0; local end_consumer = fab.output.len() == 0 // build list of supplying factories local suppliers = []; foreach(c in fab.get_suppliers()) { suppliers.append( factory_x(c.x, c.y) ); } local count = 0; local g_atleastone = false; // iterate all input goods and search for supply foreach(good, islot in fab.input) { // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() if (st[0] + st[1] + it[0] + it[1] > 0) { // something stored/in-transit in last and current month // no need to search for more supply g_atleastone = true continue } // there is a complete tree to produce this good local g_complete = false; // minimum of missing links for one input good local g_count = 10000; foreach(s in suppliers) { if (good in s.output) { // check state of connection local state = industry_manager.get_link_state(s, fab, good); if (state == industry_link_t.st_failed) { continue // foreach } if (state != industry_link_t.st_free) { // planned / built -> nothing missing g_complete = true g_count = 0 continue } local n = count_missing_factories(s, indent + " "); if ( n<0) { // incomplete tree } else { // complete tree g_complete = true; g_count = min(g_count, n+1) } } } if (!g_complete && !end_consumer) { dbgprint(indent + "No supply of " + good + " for " + fab.get_name()) // no suppliers for this good return -1 } g_atleastone = g_atleastone || g_complete if (!end_consumer) { count += g_count // sum missing links } else { if (g_count > 0 && (count == 0 || g_count < count)) { count = g_count; } } dbgprint(indent + "Supply of " + good + " for " + fab.get_name() + " has " + g_count + " missing links") } if (end_consumer && !g_atleastone) { dbgprint(indent + "No supply for " + fab.get_name()) count = -1 } dbgprint(indent + "Factory " + fab.get_name() + " at " + fab.x + "," + fab.y + " has " + count + " missing links") return count } /** * find link to connect in tree of factory @p fab. * sets fsrc, fdest, lgood if true was returned * @returns true if link is found */ function plan_missing_link(fab, indent = "") { dbgprint(indent + "Missing link for factory " + fab.get_name() + " at " + fab.x + "," + fab.y) // source of raw material? if (fab.input.len() == 0) return false; // build list of supplying factories local suppliers = []; foreach(c in fab.get_suppliers()) { suppliers.append( factory_x(c.x, c.y) ); } local count = 0; // iterate all input goods and search for supply foreach(good, islot in fab.input) { // check for current supply if ( 4*(islot.get_storage()[0] + islot.get_in_transit()[0]) > islot.max_storage) { dbgprint(indent + ".. enough supply of " + good) continue } // find suitable supplier foreach(s in suppliers) { if ( !(good in s.output)) continue; // connection forbidden? planned? built? local state = industry_manager.get_link_state(s, fab, good) if (state != industry_link_t.st_free) { if (state == industry_link_t.st_built || state == industry_link_t.st_planned) { dbgprint(indent + ".. connection for " + good + " from " + s.get_name() + " to " + fab.get_name() + " already " + (state == industry_link_t.st_built ? "built" : "planned") ) break } continue // if connection state is 'failed' } local oslot = s.output[good] dbgprint(indent + ".. Factory " + s.get_name() + " at " + s.x + "," + s.y + " supplies " + good) if (8*oslot.get_storage()[0] > oslot.max_storage || !plan_missing_link(s, indent + " ")) { // this is our link dbgprint(indent + ".. plan this connection") plan_connection(s, fab, good) } return true } } return false // all links are connected } /** * Estimates additional possible consumption at this end-consumer factory */ function plan_increase_consumption(fab, indent = "") { // initialize search if (fab.output.len() > 0) { return 0 } local planned = 0; foreach(good, islot in fab.input) { local tree = estimate_consumption(fab, good) // now do some greedy selection: for each producer select enough suppliers planned += plan_consumption_connection(tree, fab, good) } return planned } function plan_consumption_connection(tree, fdest, freight, indent = "") { local planned = 0; local needed = tree.increase while (needed > 0) { local best = null local best_supply = 0 foreach(supplier in tree.suppliers) { local supply = supplier.supply dbgprint(indent + "Needed " + needed + " Provided " + supply ) if (supply > needed ? (best_supply == 0 || supply < best_supply) : supply > best_supply) { best = supplier best_supply = supply } } // go down in tree foreach(good, supplier_slot in best.inputs) { planned += plan_consumption_connection(supplier_slot, best.supplier, good, indent + " ") dbgprint(indent + "Planned for " + best_supply + " (total = " + planned + ")") } // plan this connection if (planned==0) { if (plan_connection(best.supplier, fdest, freight)) { dbgprint(indent + "Planned to consumer ") planned++ } } // disable this tree needed -= best_supply best.supply = 0 } return planned } /** * Estimates additional possible consumption of good at this factory * * Returns tree: * tree.increase - Potential local consumption * tree.supply - Potential supply * tree.basec - Base consumption * tree.suppliers - Array of supplier nodes * [].supplier - Factory * [].supply - Potential production of supplier } - produced by estimate_production * [].inputs - Table Good -> Consumer tree } * * @returns estimated consumption increase */ static function estimate_consumption(fab, prod = null, indent = "") { dbgprint(indent + "Estimates for consumption of " + prod + " at factory " + fab.get_name() + " at " + fab.x + "," + fab.y) // estimate max consumption local islot = fab.input[prod] local max_c = islot.get_base_consumption() // estimate actual consumpion local est_c = estimate_actual_consumption(islot) local increase = max_c - est_c dbgprint(indent + " potential increase of consumption of " + prod + " is " + increase) // iterate suppliers: // calculate potential additional supply (and build it) local tree = { suppliers = [], basec = max_c } // search for supply local supply = 0 foreach(c in fab.get_suppliers()) { local s = factory_x(c.x, c.y) if (prod in s.output) { local state = industry_manager.get_link_state(s, fab, prod) if (state == industry_link_t.st_planned || state == industry_link_t.st_failed) { // failed / planned -> no improvement possible dbgprint(indent + " transport link for " + prod + " is failed/planned" ) continue } local s_tree = estimate_production(s, prod, state == industry_link_t.st_built, indent + " ") s_tree.supplier <- s local more = s_tree.supply supply += more tree.suppliers.append(s_tree) dbgprint(indent + " potential increase of " + prod + " is " + more + " (state =" + state + ")") } } dbgprint(indent + " total additional supply of " + prod + " is " + supply) tree.increase <- min(increase, supply) tree.supply <- supply return tree } /** * Estimates additional possible production of good at this factory * @returns tree, see estimate_consumption */ static function estimate_production(fab, prod, exists, indent = "") { dbgprint(indent + "Estimates for production of " + prod + " at factory " + fab.get_name() + " at " + fab.x + "," + fab.y) local oslot = fab.output[prod] local fac = oslot.get_production_factor() local est_p = estimate_actual_production(oslot, exists) local increase = oslot.get_base_production() - est_p dbgprint(indent + " potential increase of production of " + prod + " is " + increase) // build tree for later planning local tree = { inputs = {}, supply = 0 } if (increase <= 0) { return tree } if (fab.input.len() == 0) { // producer of raw materials tree.supply = ( increase*fac)/100; return tree } // iterate all input goods and search for supply foreach(good, islot in fab.input) { local c_tree = estimate_consumption(fab, good, indent + " ") tree.inputs[good] <- c_tree local con = c_tree.increase local est = (con * fac)/ islot.get_consumption_factor() increase = min(increase, est) } tree.supply = increase return tree } static function estimate_actual_consumption(islot) { local con = islot.get_consumed() local isnew = (con.reduce(sum) - con[0]) == 0; if (!isnew) { // established connection: report max return con.reduce(max) } else { if (con[0] == 0) { // non-existing connection return 0 } else { // new connection: report base return islot.get_base_consumption() } } } static function estimate_actual_production(oslot, exists) { local pro = oslot.get_produced() local isnew = (pro.reduce(sum) - pro[0]) == 0; if (!isnew) { // established connection: report max return pro.reduce(max) } else { if (pro[0] == 0 && !exists) { // non-existing connection return 0 } else { // new connection: report base return oslot.get_base_consumption() } } } } simutrans-124.3/simutrans/ai/sqai/industry_connection_planner.nut000066400000000000000000000203771474050137200255060ustar00rootroot00000000000000/** * Plans connections suggested by factory-searcher. */ // helper class to simulate ways on open water openwater <- { function get_cost() { return 0; } function get_maintenance() { return 0; } function get_name() { return "open water"} } function get_max_convoi_length(wt) { switch(wt) { case wt_road: return settings.get_max_road_convoi_length(); case wt_water: return settings.get_max_ship_convoi_length(); } return 4; } /** * Planer class. */ class industry_connection_planner_t extends manager_t { // Source factory fsrc = null // factory_x // Destination factory fdest = null // factory_x // Freight to be transported freight = null // string prod = -1 // integer constructor(s,d,f) { base.constructor("industry_connection_planner_t"); fsrc = s; fdest = d; freight = f; } /** * Evaluates transport by road and ships. * Returns the corresponding reports. * In addition, returns amphibious_connection_planner_t. * This planner will start to work if the connection by road or ship did not succeed. */ function step() { debug = true local tic = get_ops_total(); print("Plan link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y) // TODO check if factories are still existing // TODO check if connection is plannable // compute monthly production if (prod < 0) { prod = calc_production() } dbgprint("production = " + prod); // road local rprt = plan_simple_connection(wt_road, null, null) if (rprt) { append_report(rprt) } // water rprt = plan_simple_connection(wt_water, null, null) if (rprt) { append_report(rprt) } if (reports.len() == 0) { dbgprint("Set link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y + " to MISSING") industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } // deliver it local r = r_t(RT_READY) r.report = get_report() // append a chain of alternative connector nodes local rchain = r.report while (reports.len()>0) { local rep = get_report() if (rep == null) { // may happen if no nice reports are available break; } rchain.action.reports.append( rep ) rchain = rep } local r_amph = report_t() r_amph.action = amphibious_connection_planner_t(fsrc, fdest, freight) if (rchain) { rchain.action.reports.append( r_amph ) } else { r.report = r_amph } local toc = get_ops_total(); print("industry_connection_planner wasted " + (toc-tic) + " ops") return r } /** * Plans a connection using one mode of transport * * If start or target are null then use fsrc/fdest. */ function plan_simple_connection(wt, start, target, distance = 0) { // compute correct distance if (distance == 0) { foreach(i in ["x", "y"]) { distance += abs( (start ? start[i] : fsrc[i]) - (target ? target[i] : fdest[i])) } } if (distance == 0) { // still zero? avoid division by zero in the prototyper distance = 1 } // plan convoy prototype local prototyper = prototyper_t(wt, freight) prototyper.min_speed = 1 prototyper.max_vehicles = get_max_convoi_length(wt) prototyper.max_length = 1 if (wt == wt_water) { prototyper.max_length = 4 } local cnv_valuator = valuator_simple_t() cnv_valuator.wt = wt cnv_valuator.freight = freight cnv_valuator.volume = prod cnv_valuator.max_cnvs = 200 cnv_valuator.distance = distance local bound_valuator = valuator_simple_t.valuate_monthly_transport.bindenv(cnv_valuator) prototyper.valuate = bound_valuator if (prototyper.step().has_failed()) { return null } local planned_convoy = prototyper.best print("best " + planned_convoy.min_top_speed + " / " + planned_convoy.max_speed) // fill in report when best way is found local r = report_t() // plan way local planned_way = null if (wt == wt_water) { planned_way = openwater } else { local way_list = way_desc_x.get_available_ways(wt, st_flat) local best_way = null local best = null foreach(way in way_list) { cnv_valuator.way_maintenance = way.get_maintenance() cnv_valuator.way_max_speed = way.get_topspeed() local test = cnv_valuator.valuate_monthly_transport(planned_convoy) if (best == null || test > best) { best = test best_way = way } } dbgprint("Best value = " + best + " way = " + best_way.get_name()) // valuate again with best way cnv_valuator.way_maintenance = 0 cnv_valuator.way_max_speed = best_way.get_topspeed() planned_way = best_way } // valuate again with best way r.gain_per_m = cnv_valuator.valuate_monthly_transport(planned_convoy) // plan station local planned_station = null if (wt != wt_water) { local station_list = building_desc_x.get_available_stations(building_desc_x.station, wt, good_desc_x(freight)) planned_station = select_station(station_list, planned_convoy.length, planned_convoy.capacity) } else { local station_list = building_desc_x.get_available_stations(building_desc_x.harbour, wt, good_desc_x(freight)) planned_station = select_station(station_list, 1, planned_convoy.capacity) } // plan depot local planned_depot = null { local depot_list = building_desc_x.get_available_stations(building_desc_x.depot, wt, {}) if (depot_list.len()) { planned_depot = depot_list[0] } } if (planned_convoy == null || planned_way == null || planned_station == null || planned_depot == null) { return null } // successfull - complete report r.cost_fix = cnv_valuator.distance * planned_way.get_cost() + 2*planned_station.get_cost() + planned_depot.get_cost() r.cost_monthly = cnv_valuator.distance * planned_way.get_maintenance() + 2*planned_station.get_maintenance() + planned_depot.get_maintenance() r.gain_per_m -= r.cost_monthly // create action node local cn = null switch(wt) { case wt_road: cn = road_connector_t(); break case wt_water: cn = ship_connector_t(); break } cn.fsrc = fsrc cn.fdest = fdest cn.freight = freight cn.planned_way = planned_way cn.planned_station = planned_station cn.planned_depot = planned_depot cn.planned_convoy = planned_convoy if (start) { cn.c_start = [start] print("Connector from " + coord_to_string(start)) } if (target) { cn.c_end = [target] print("Connector to " + coord_to_string(target)) } r.action = cn dbgprint("Plan: way = " + planned_way.get_name() + ", station = " + planned_station.get_name() + ", depot = " + planned_depot.get_name()); dbgprint("Report: gain_per_m = " + r.gain_per_m + ", nr_convoys = " + planned_convoy.nr_convoys + ", cost_fix = " + r.cost_fix + ", cost_monthly = " + r.cost_monthly) dbgprint("Report: dist = " + cnv_valuator.distance+ " way_cost = " + planned_way.get_cost()) dbgprint("Report: station = " + planned_station.get_cost()+ " depot = " + planned_depot.get_cost()) return r } function calc_production() { local src_prod = fsrc.output[freight].get_base_production(); local dest_con = fdest.input[freight].get_base_consumption(); // TODO implement production boost factors dbgprint("production = " + src_prod + " / " + dest_con); return min(src_prod,dest_con) } static function select_station(list, length, capacity) { local station_length = (length + CARUNITS_PER_TILE - 1) / CARUNITS_PER_TILE local capacity = capacity local station_capacity = 0 local station_is_terminus = false local best_station = null foreach(station in list) { local ok = (best_station == null) local s_capacity = station_length * station.get_capacity() if (!ok && station_length == 1) { // prefer terminus ok = station.is_terminus() && !station_is_terminus if (!ok) { // then prefer stations with enough capacity ok = station_capacity < capacity ? station_capacity < s_capacity : capacity < s_capacity && s_capacity < station_capacity } } if (station_length > 1) { // force non-terminus ok = !station_is_terminus } if (ok) { best_station = station station_capacity = station.get_capacity() station_is_terminus = station.is_terminus() } } return best_station } } simutrans-124.3/simutrans/ai/sqai/industry_manager.nut000066400000000000000000000252641474050137200232420ustar00rootroot00000000000000/** * Classes to manage industry connections. */ /** * A link is a connection between two factories. * Save its state here. */ class industry_link_t { f_src = null // factory_x f_dest = null // factory_x freight = null // good_desc_x state = 0 lines = null // array // next check needed if ticks > next_check // state == st_missing: check availability again // state == st_build: check for possible upgrades next_check = 0 // only set for st_missing, next time availability has to be checked static st_free = 0 /// not registered static st_planned = 1 /// link is planned static st_failed = 2 /// construction failed, do not try again static st_built = 3 /// connection successfully built static st_missing = 4 /// missing infrastructure, try again later constructor(s,d,f) { f_src = s f_dest = d freight = good_desc_x(f) lines = [] } function append_line(l) { lines.append(l) } function _save() { return ::saveinstance("industry_link_t", this) } } /** * Manage the links operated by us. */ class industry_manager_t extends manager_t { link_list = null link_iterator = null constructor() { base.constructor("industry_manager_t") link_list = {} ::industry_manager = this } /// Generate unique key from link data static function key(src, des, fre) { return ("freight-" + fre + "-from-" + coord_to_key(src) + "-to-" + coord_to_key(des) ).toalnum() } function set_link_state(src, des, fre, state) { local k = key(src, des, fre) try { link_list[k].state = state } catch(ev) { // not existing - create entry local l = industry_link_t(src, des, fre) l.state = state link_list[k] <- l } if (state == industry_link_t.st_built) { link_list[k].next_check = world.get_time().next_month_ticks local text = "" text = "Transport " + translate(fre) + " from " text += coord(src.x, src.y).href(src.get_name()) + " to " text += coord(des.x, des.y).href(des.get_name()) + "
" } if (state == industry_link_t.st_missing) { link_list[k].next_check = world.get_time().next_month_ticks } } function get_link_state(src, des, fre) { local link = access_link(src, des, fre) return link ? link.state : industry_link_t.st_free } function access_link(src, des, fre) { local k = key(src, des, fre) local res try { res = link_list[k] } catch(ev) { res = null } return res } /** * Loop through all links. */ function work() { // iterate the link_iterator, which is a generator if (link_iterator == null) { // this is a generator link_iterator = link_iteration() } if (link_iterator.getstatus() != "dead") { resume link_iterator } else { link_iterator = null return r_t(RT_SUCCESS); } return r_t(RT_PARTIAL_SUCCESS); } function link_iteration() { foreach(link in link_list) { check_link(link) yield link } } /** * Check link: * - if state is st_missing set state to st_free after some time * - for working links see after their lines */ function check_link(link) { switch(link.state) { case industry_link_t.st_free: case industry_link_t.st_planned: case industry_link_t.st_failed: return case industry_link_t.st_built: if (link.lines.len()==0) return break case industry_link_t.st_missing: if (link.next_check >= world.get_time().ticks) return // try to plan again link.state = industry_link_t.st_free break } // iterate through all lines foreach(line in link.lines) { check_link_line(link, line) } } /** * Manages convoys of one line: withdraw if there are too many, build new ones, upgrade to newer vehicles */ function check_link_line(link, line) { dbgprint("Check line " + line.get_name()) // find convoy local cnv = null local cnv_count = 0 { local list = line.get_convoy_list() cnv_count = list.get_count() if (cnv_count == 0) { return } cnv = list[0] } if (cnv.is_withdrawn()) { // come back later return } // try to upgrade if (cnv.has_obsolete_vehicles() && link.next_check < world.get_time().ticks) { link.next_check = world.get_time().next_month_ticks if (upgrade_link_line(link, line)) { // update successful return } } local lf = link.freight // capacity of convoy local capacity = 0 { local lf = link.freight foreach(v in cnv.get_vehicles()) { local f = v.get_freight() if (lf.is_interchangeable(f)) { capacity += v.get_capacity() } } } dbgprint("Capacity of convoy " + cnv.get_name() + " = " + capacity) dbgprint("Speed of convoy " + cnv.get_name() + " = " + cnv.get_speed()) // iterate through schedule, check for available freight local freight_available = false { local entries = cnv.get_schedule().entries local i = 0; while(i < entries.len() && !freight_available) { local entry = entries[i] // stations on schedule local halt = entry.get_halt(our_player) if (halt == null) continue // next station on schedule local nexthalt = null i++ while(i < entries.len()) { if (nexthalt = entries[i].get_halt(our_player)) break i++ } if (nexthalt == null) { nexthalt = entries[0].get_halt(our_player) } // freight available ? local freight_on_schedule = halt.get_freight_to_halt(lf, nexthalt) local capacity_halt = halt.get_capacity(lf) dbgprint("Freight from " + halt.get_name() + " to " + nexthalt.get_name() + " = " + freight_on_schedule) // either start is 2/3 full or more good available as one cnv can transport freight_available = (3*freight_on_schedule > 2*capacity_halt) || (freight_on_schedule > capacity); } } // calc gain per month of one convoy local gain_per_m = 0 { local p = line.get_profit() gain_per_m = p.reduce(sum) / (p.len() * cnv_count) dbgprint("Gain pm = " + gain_per_m) } // check state if convoys (loading level, stopped, new) local cc_load = 0 local cc_stop = 0 local cc_new = 0 local cc_empty = 0 local cnv_empty_stopped = null { local list = line.get_convoy_list() foreach(c in list) { // convoy empty? local is_empty = c.get_loading_level() == 0 // convoy new? less than 2 months old, and not much transported local d = c.get_traveled_distance() local is_new = (d[0] + d[1] == c.get_distance_traveled_total()) if (is_new) { local t = c.get_transported_goods(); if (t.reduce(sum) >= 2*capacity) { is_new = false } } if (is_new) { cc_new ++ is_empty = false } // new convoys do not count as empty if (is_empty) { cc_empty++ } // convoy stopped? but not for loading local is_stopped = false if (c.get_speed() == 0) { if (c.get_loading_limit() > 0) { // loading cc_load ++ } else { cc_stop ++ is_stopped = true; } } if (is_empty && is_stopped && cnv_empty_stopped==null) { cnv_empty_stopped = c } } } dbgprint("Line: loading = " + cc_load + ", stopped = " + cc_stop + ", new = " + cc_new + ", empty = " + cc_empty) dbgprint("") if (freight_available && cc_new == 0 && cc_stop < 2) { if (gain_per_m > 0) { // directly append // TODO put into report local proto = cnv_proto_t.from_convoy(cnv, lf) local depot = cnv.get_home_depot() local c = vehicle_constructor_t() c.p_depot = depot_x(depot.x, depot.y, depot.z) c.p_line = line c.p_convoy = proto c.p_count = 1 append_child(c) dbgprint("==> build additional convoy") } } if (!freight_available && cnv_count>1 && 2*cc_empty >= cnv_count && cnv_empty_stopped) { // freight, lots of empty and of stopped vehicles // -> something is blocked, maybe we block our own supply? // delete one convoy cnv_empty_stopped.destroy(our_player) dbgprint("==> destroy empty convoy") } dbgprint("") } /** * Upgrade: plan a new convoy type with the prototyper, then * sell existing convoys, create new ones. */ function upgrade_link_line(link, line) { // find convoy local cnv = null { local list = line.get_convoy_list() if (list.get_count() == 0) { // no convois - strange return false } cnv = list[0] } local wt = cnv.get_waytype() // estimate transport volume local transported = line.get_transported_goods().reduce(max) // plan convoy prototype local prototyper = prototyper_t(wt, link.freight.get_name()) // iterate through schedule to estimate distance local dist = 0 { local entries = cnv.get_schedule().entries local halts = [] for(local i=0; i < entries.len(); i++) { if (entries[i].get_halt(our_player)) { halts.append( entries[i] ) } } if (halts.len() < 2) { // not enough halts?? return false } dist = abs(halts.top().x - halts[0].x) + abs(halts.top().y - halts[0].y) for(local i=1; i < halts.len(); i++) { dist = max(dist, abs(halts[i].x - halts[i-1].x) + abs(halts[i].y - halts[i-1].y) ) } } local wt = wt // TODO do something smarter prototyper.min_speed = 1 prototyper.max_vehicles = get_max_convoi_length(wt) prototyper.max_length = 1 if (wt == wt_water) { prototyper.max_length = 4 } local cnv_valuator = valuator_simple_t() cnv_valuator.wt = wt cnv_valuator.freight = link.freight.get_name() cnv_valuator.volume = transported cnv_valuator.max_cnvs = 200 cnv_valuator.distance = dist local bound_valuator = valuator_simple_t.valuate_monthly_transport.bindenv(cnv_valuator) prototyper.valuate = bound_valuator if (prototyper.step().has_failed()) { return false } local planned_convoy = prototyper.best // check whether different from current convoy local cnv_veh = cnv.get_vehicles() local pro_veh = planned_convoy.veh local different = cnv_veh.len() != pro_veh.len() for(local i=0; i=0 && y>=0) area.append( (x << 16) + y ); } } } // sort sleep() area.sort() return area } static function find_empty_place(area, target) { // find place closest to target local tx = target.x local ty = target.y local best = null local dist = 10000 // check for flat and empty ground for(local i = 0; i0 && h == area[i-1]) continue; local x = h >> 16 local y = h & 0xffff if (world.is_coord_valid({x=x,y=y})) { local tile = square_x(x, y).get_ground_tile() if (tile.is_empty() && tile.get_slope()==0) { local d = abs(x - tx) + abs(y - ty) if (d < dist) { dist = d best = tile } } } } return best } static function _find_places(area, test /* function */) { local list = [] // check for flat and empty ground for(local i = 0; i0 && h == area[i-1]) continue; local x = h >> 16 local y = h & 0xffff if (world.is_coord_valid({x=x,y=y})) { local tile = square_x(x, y).get_ground_tile() if (test(tile)) { list.append(tile) } } } return list.len() > 0 ? list : [] } static function find_empty_places(area) { return _find_places(area, _tile_empty) } static function _tile_empty(tile) { return tile.is_empty() && tile.get_slope()==0 } static function _tile_empty_or_field(tile) { return tile.get_slope()==0 && (tile.is_empty() || tile.find_object(mo_field)) } static function find_water_places(area) { return _find_places(area, _tile_water) } static function _tile_water(tile) { return tile.is_water() && (tile.find_object(mo_building)==null) && (tile.find_object(mo_depot_water)==null) } static function _tile_water_way(tile) { if (tile.is_water()) { return true // (tile.find_object(mo_building)==null) && (tile.find_object(mo_depot_water)==null) } else { foreach(obj in tile.get_objects()) { try { if (obj.get_type() != mo_way) continue; if (obj.get_waytype() == wt_water) { return obj.get_desc().get_topspeed() > 5 } } catch(ev) { // object gone, most likely vehicle that moved on } } } return false } static function find_station_place(factory, target, unload = false) { if (unload) { // try unload station from station manager local res = ::station_manager.access_freight_station(factory).road_unload if (res) { return [res] } } local can_delete_fields = factory.get_field_count() > factory.get_min_field_count() local area = get_tiles_near_factory(factory) if (can_delete_fields) { return _find_places(area, _tile_empty_or_field); } else { return find_empty_places(area) } } /** * Can harbour of length @p len placed at @p pos (land tile!) in direction @p d. */ static function check_harbour_place(pos, len, d /* direction */) { local from = pos for(local i = 0; i0 ? wt_water : wt_all, d) if (to && _tile_water(to) && to.can_remove_all_objects(our_player)==null) { from = to } else { return false } } return true } } simutrans-124.3/simutrans/ai/sqai/prototyper.nut000066400000000000000000000164271474050137200221170ustar00rootroot00000000000000/** * Classes to plan a convoy prototype given some constraints. */ /** * Prototype of a convoy. */ class cnv_proto_t { // properties weight = 0 // weight (fully loaded) power = 0 // total power min_top_speed = 0 // top speed when fully loaded max_speed = -1 // speed limit length = 0 // length of convoy in internal units (one tile = 16 units) capacity = 0 // capacity of convoy for desired freight maintenance = 0 // maintenance cost per month running_cost = 0 // running cost per tile price = 0 // price missing_freight = true // convoy misses vehicles to transport desired freight veh = null // the vehicles of the convoy (array) // set by valuator nr_convoys = 0 // number of convoys that should be built constructor() { veh = [] } /** * Append vehicle to this prototype. * Desired freight is given as parameter freight. */ function append(newveh, freight) { local cnv = getclass().instance() cnv.constructor() cnv.veh.extend(veh) cnv.veh.append(newveh) cnv.weight = weight + freight.get_weight_per_unit() * newveh.get_capacity() + newveh.get_weight() cnv.power = power + newveh.get_power() if (max_speed >= 0) { cnv.max_speed = min(max_speed, newveh.get_topspeed()) } else { cnv.max_speed = newveh.get_topspeed() } cnv.length = length + newveh.get_length() local fits = newveh.get_freight().is_interchangeable(freight) cnv.missing_freight = missing_freight && (newveh.get_capacity()==0 || !fits) cnv.min_top_speed = convoy_x.calc_max_speed(cnv.power, cnv.weight, cnv.max_speed) cnv.capacity = capacity + (fits ? newveh.get_capacity() : 0) cnv.maintenance = maintenance + newveh.get_maintenance() cnv.running_cost = running_cost + newveh.get_running_cost() cnv.price = price + newveh.get_cost() return cnv } static function from_convoy(cnv, freight) { local p = cnv_proto_t() local list = cnv.get_vehicles() foreach(v in list) { p = p.append(v, freight) } return p } function _save() { return ::saveinstance("cnv_proto_t", this) } } /** * Class to find the best prototype. * * Iterates through all possible combinations. * This can take a very long time for e.g. passenger trains. * Some means to shorten the computation are required. * * If a prototype is valid, it is passed to the function valuate. * The prototype with largest score wins (or the first one if valuate == null). */ class prototyper_t extends node_t { wt = 0 // way-type freight = 0 // freight to be transported max_vehicles = 0 // maximum of number of vehicles in this prototype max_length = 0 // maximum lenght of convoy in number of tiles min_speed = 0 // minimum speed valuate = null // valuate function, takes prototype, returns number (null -> first valid prototype is returned) best = null // the best prototype up to now best_value = 0 // and its score constructor(w, /*string*/f) { base.constructor("prototyper"); wt = w freight = good_desc_x(f) } /** * Depth-first search. * Takes constraints into account. Calls valuate. */ function step() { // list of all vehicles local list = vehicle_desc_x.get_available_vehicles(wt) // vehicles that can be put first local list_first = [] // other vehicles: powered, no capacity (tenders), matching freight local list_other = [] // preprocess foreach(veh in list) { local first = veh.can_be_first() local fits = veh.get_freight().is_interchangeable(freight) local pwer = veh.get_power()>0 local none = veh.get_freight().get_name()=="None" || veh.get_capacity()==0 // use vehicles that can carry freight // or that are powered and have no freight capacity if (fits || (pwer && none) ) { if (first) { list_first.append(veh) } list_other.append(veh) } } // array of lists we try to iterate local it_lists = []; it_lists.resize(max_vehicles+1) local it_ind = []; it_ind.resize(max_vehicles+1) // current convoy candidate - array of desc local cnv = []; cnv.resize(max_vehicles+1) // initialize cnv[0] = cnv_proto_t() it_ind[1] = -1 it_lists[1] = list_first // iterating ind-th position in convoy local ind = 1 while(true) { it_ind[ind] ++ // done with iterating? if (it_ind[ind] >= it_lists[ind].len() ) { if (ind>1) { ind-- continue // iterating position ind-1 } else { break // end of the iteration } } local test = it_lists[ind][ it_ind[ind] ] // check couplings if ( ind==1 ? !test.can_be_first() : !vehicle_desc_x.is_coupling_allowed(cnv[ind-1].veh.top(), test) ) { continue; } // append cnv[ind] = cnv[ind-1].append(test, freight) local c = cnv[ind] // check constraints // .. length local l = (ind > 1 ? cnv[ind-1].length : 0) + max( CARUNITS_PER_TILE/2, test.get_length()); if (l > CARUNITS_PER_TILE*max_length) { continue; } // check if convoy finished if (test.can_be_last() && !c.missing_freight && c.min_top_speed >= min_speed) { // evaluate this candidate if (valuate) { local value = valuate.call(getroottable(), c) if (best==null || value > best_value) { best = c best_value = value } } else { // no valuator function -> take first valid convoy and return best = c; break } } // move on to next position if (ind >= max_vehicles) { continue; } ind++ local list_succ = test.get_successors() it_lists[ind] = list_succ.len()==0 ? list_other : list_succ it_ind[ind] = -1 } if (best) { foreach(ind, test in best.veh) { print("Best[" + ind + "] = " + test.get_name()) } return r_t(RT_SUCCESS) } return r_t(RT_ERROR) } } /** * A simple valuate function. */ class valuator_simple_t { wt = 0 // way-type freight = null // freight to be transported volume = 0 // monthly transport volume max_cnvs = 0 // maximum number of convoys distance = 0 way_max_speed = -1 // speed limit of planned way way_maintenance = 0 // maintenance of planned way /** * Estimates gain per month */ function valuate_monthly_transport(cnv) { local speed = way_max_speed > 0 ? min(way_max_speed, cnv.min_top_speed) : cnv.min_top_speed local frev = good_desc_x(freight).calc_revenue(wt, speed) local capacity = cnv.capacity // tiles per month of one convoy local tpm = convoy_x.speed_to_tiles_per_month(speed) / 2 + 1 // needed convoys to transport everything local n1 = max(1, volume * 2 * distance / (tpm * cnv.capacity)) // realistic number of convoys local ncnv = min(n1, min(max_cnvs, max(distance / 8, 3) ) ) cnv.nr_convoys = ncnv if (way_max_speed > 0) { // correction factor to prefer faster ways: // factor = 0 .. if 2*distance < ncnv // factor = 1 .. if distance/3 > ncnv // linear interpolated in between // without scaling almost always the cheapest way is chosen ... local factor = max(0, min(10*distance, 6*(2*distance - ncnv) ) ); // rescale tiles per month tpm = (tpm*factor) / (10*distance); } // monthly costs and revenue local value = ncnv*( (frev*cnv.capacity+1500)/3000*tpm - cnv.running_cost*tpm - cnv.maintenance) - distance * way_maintenance return value } function _save() { return ::saveinstance("valuator_simple_t", this) } } simutrans-124.3/simutrans/ai/sqai/road_connector.nut000066400000000000000000000156271474050137200226700ustar00rootroot00000000000000class road_connector_t extends manager_t { // input data fsrc = null fdest = null freight = null planned_way = null planned_station = null planned_depot = null planned_convoy = null finalize = true // step-by-step construct the connection phase = 0 // can be provided optionally c_start = null // array c_end = null // array // generated data c_depot = null c_sched = null c_line = null c_cnv = null constructor() { base.constructor("road_connector_t") debug = true } function work() { // TODO check if child does the right thing local pl = our_player local tic = get_ops_total(); switch(phase) { case 0: // find places for stations if (c_start == null) { c_start = ::finder.find_station_place(fsrc, fdest) } if (c_start && c_end == null) { c_end = ::finder.find_station_place(fdest, c_start, finalize) } if (c_start.len()>0 && c_end.len()>0) { phase ++ } else { print("No station places found") return error_handler() } case 1: // build way { sleep() local d = pl.get_current_cash(); local err = construct_road(pl, c_start, c_end, planned_way ) print("Way construction cost: " + (d-pl.get_current_cash()) ) if (err) { print("Failed to build way from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) return error_handler() } phase ++ } case 2: // build station { local err = command_x.build_station(pl, c_start, planned_station ) if (err) { print("Failed to build station at " + coord_to_string(c_start)) gui.add_message_at(pl, "Failed to build road station at " + coord_to_string(c_start) + "\n" + err, c_start) return error_handler() } local err = command_x.build_station(pl, c_end, planned_station ) if (err) { gui.add_message_at(pl, "Failed to build road station at " + coord_to_string(c_end) + "\n" + err, c_end) print("Failed to build station at " + coord_to_string(c_end)) return error_handler() } if (finalize) { // store place of unload station for future use local fs = ::station_manager.access_freight_station(fdest) if (fs.road_unload == null) { fs.road_unload = c_end print( recursive_save({unload = c_end}, "\t\t\t", []) ) } } phase ++ } case 3: // find depot place { local err = construct_road_to_depot(pl, c_start, planned_way) if (err) { print("Failed to build depot access from " + coord_to_string(c_start)) return error_handler() } phase += 2 } case 5: // build depot { // depot already existing ? if (c_depot.find_object(mo_depot_road) == null) { // no: build local err = command_x.build_depot(pl, c_depot, planned_depot ) if (err) { print("Failed to build depot at " + coord_to_string(c_depot)) return error_handler() } if (finalize) { // store depot location local fs = ::station_manager.access_freight_station(fsrc) if (fs.road_depot == null) { fs.road_depot = c_depot } } } phase ++ } case 6: // create schedule { local sched = schedule_x(wt_road, []) sched.entries.append( schedule_entry_x(c_start, 100, 0) ); sched.entries.append( schedule_entry_x(c_end, 0, 0) ); c_sched = sched phase ++ } case 7: // create line and set schedule { pl.create_line(wt_road) // find the line - it is a line without schedule and convoys local list = pl.get_line_list() foreach(line in list) { if (line.get_waytype() == wt_road && line.get_schedule().entries.len()==0) { // right type, no schedule -> take this. c_line = line break } } // set schedule c_line.change_schedule(pl, c_sched); phase ++ } case 8: // append vehicle_constructor { local c = vehicle_constructor_t() c.p_depot = depot_x(c_depot.x, c_depot.y, c_depot.z) c.p_line = c_line c.p_convoy = planned_convoy c.p_count = min(planned_convoy.nr_convoys, 3) append_child(c) local toc = get_ops_total(); print("road_connector wasted " + (toc-tic) + " ops") phase ++ return r_t(RT_PARTIAL_SUCCESS) } case 9: // build station extension } if (finalize) { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_built) } industry_manager.access_link(fsrc, fdest, freight).append_line(c_line) return r_t(RT_TOTAL_SUCCESS) } function error_handler() { local r = r_t(RT_TOTAL_FAIL) // TODO rollback if (reports.len()>0) { // there are alternatives print("Delivering alternative connector") r.report = reports.pop() if (r.report.action && r.report.action.getclass() == amphibious_connection_planner_t) { print("Delivering amphibious_connection_planner_t") r.node = r.report.action r.report = null } } else { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_failed); } return r } function construct_road(pl, starts, ends, way) { local as = astar_builder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) as.bridger = pontifex(pl, way) if (as.bridger.bridge == null) { as.bridger = null } local res = as.search_route(starts, ends) if ("err" in res) { return res.err } c_start = res.start c_end = res.end } function construct_road_to_depot(pl, start, way) { local as = depot_pathfinder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) local res = as.search_route(start) if ("err" in res) { return res.err } local d = res.end c_depot = tile_x(d.x, d.y, d.z) } } class depot_pathfinder extends astar_builder { function estimate_distance(c) { local t = tile_x(c.x, c.y, c.z) if (t.is_empty() && t.get_slope()==0) { return 0 } local depot = t.find_object(mo_depot_road) if (depot && depot.get_owner().nr == our_player_nr) { return 0 } return 10 } function add_to_open(c, weight) { if (c.dist == 0) { // test for depot local t = tile_x(c.x, c.y, c.z) if (t.is_empty()) { // depot not existing, we must build, increase weight weight += 25 * cost_straight } } base.add_to_open(c, weight) } function search_route(start) { prepare_search() local dist = estimate_distance(start) add_to_open(ab_node(start, null, 1, dist+1, dist, 0), dist+1) search() if (route.len() > 0) { for (local i = 1; i0 && c_end.len()>0) { phase ++ } else { print("No station places found") return error_handler() } case 2: // find path between both factories { local err = find_route() if (err) { print("No way from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) return error_handler() } phase ++ } case 3: // build harbour { local key local err = null { key = coord3d_to_key(c_start[0]) if (key in c_harbour_tiles) { err = build_harbour(c_harbour_tiles[key], c_start) } } if (err == null) { key = coord3d_to_key(c_end[0]) if (key in c_harbour_tiles) { err = build_harbour(c_harbour_tiles[key], c_end) } } if (err) { print("Failed to build harbour at " + key + " / " + err) return error_handler() } c_harbour_tiles = null phase ++ } case 4: // find route again after harbour was built { if (c_start.len()>1 || c_end.len()>1) { local err = find_route() if (err) { print("No way2 from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) return error_handler() } } phase ++ } case 5: // build depot { // depot already existing ? if (c_depot.find_object(mo_depot_water) == null) { // no: build local err = command_x.build_depot(pl, c_depot, planned_depot ) if (err) { print("Failed to build depot at " + coord_to_string(c_depot)) return error_handler() } if (finalize) { // store depot location local fs = ::station_manager.access_freight_station(fsrc) if (fs.ship_depot == null) { fs.ship_depot = c_depot } } } phase ++ } case 6: // create schedule { local sched = schedule_x(wt_water, []) sched.entries.append( schedule_entry_x(c_start[0], 100, 0) ); sched.entries.append( schedule_entry_x(c_end[0], 0, 0) ); c_sched = sched phase ++ } case 7: // create line and set schedule { pl.create_line(wt_water) // find the line - it is a line without schedule and convoys local list = pl.get_line_list() foreach(line in list) { if (line.get_waytype() == wt_water && line.get_schedule().entries.len()==0) { // right type, no schedule -> take this. c_line = line break } } // set schedule c_line.change_schedule(pl, c_sched); phase ++ } case 8: // append vehicle_constructor { local c = vehicle_constructor_t() c.p_depot = depot_x(c_depot.x, c_depot.y, c_depot.z) c.p_line = c_line c.p_convoy = planned_convoy c.p_count = min(planned_convoy.nr_convoys, 3) append_child(c) local toc = get_ops_total(); print("ship_connector wasted " + (toc-tic) + " ops") phase ++ return r_t(RT_PARTIAL_SUCCESS) } case 9: // build station extension } if (finalize) { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_built) } industry_manager.access_link(fsrc, fdest, freight).append_line(c_line) return r_t(RT_TOTAL_SUCCESS) } function error_handler() { local r = r_t(RT_TOTAL_FAIL) // TODO rollback if (reports.len()>0) { // there are alternatives print("Delivering alternative connector") r.report = reports.pop() if (r.report.action && r.report.action.getclass() == amphibious_connection_planner_t) { print("Delivering amphibious_connection_planner_t") r.node = r.report.action r.report = null } } else { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_failed); } return r } static function find_anchorage(factory, planned_station, planned_harbour_flat, c_harbour_tiles) { // try to find tiles already covered by some harbours local tile_list = ::finder.find_water_places( ::finder.get_tiles_near_factory(factory) ) local halt_list = factory.get_halt_list() local anch = [] if (tile_list.len()>0 && halt_list.len()>0) { foreach(tile in tile_list) { local h = halt_x.get_halt(tile, our_player) if (h) { foreach(halt in halt_list) { if ( (h <=> halt) == 0) { anch.append(tile) } } } } } if (anch.len()>0) { return anch } // find places to build harbour if (tile_list.len()>0) { foreach(tile in tile_list) { for(local d = 1; d<16; d*=2) { local to = tile.get_neighbour(wt_all, d) if (to && get_harbour_type_for_tile(to, planned_station, planned_harbour_flat, d) > 0) { anch.append(tile) c_harbour_tiles[coord3d_to_key(tile)] <- to break } } } } return anch } /** * Checks whether we can build harbour: empty tile, slopes, enough space on water * returns type of harbour that can be placed here: 0 - nothing, 1 - harbour, 2 - flat harbour */ static function get_harbour_type_for_tile(tile, planned_harbour, planned_harbour_flat, d_water_to_land /*direction*/) { local type = 0 // 1 - harbour, 2 - flat harbour if (!tile.is_empty()) { return 0 } // first slope if (planned_harbour) { if (tile.get_slope() != 0) { // can place on slopes, target tile is sloped and empty -> we can terraform type = 1 } else if (planned_harbour_flat == null && command_x.can_set_slope(our_player, tile, dir.to_slope(d_water_to_land))==null) { // no slope, no flat dock, but terraforming possible type = 1 } } if (planned_harbour_flat) { if (tile.get_slope() == 0) { // flat place type = 2 } else if (planned_harbour == null && command_x.can_set_slope(our_player, tile, 0)==null) { // not flat, not harbour for slopes, can flatten type = 2 } } if (type == 0) { return 0 } // then space local size = type == 1 ? planned_harbour.get_size(0) : planned_harbour_flat.get_size(0) return finder.check_harbour_place(tile, size.x*size.y, dir.backward(d_water_to_land)) ? type : 0 } /** * Checks whether there is already a harbour on this tile. * @returns corresponding halt_x object (or null) */ static function get_harbour_halt(tile) { local halt = tile.get_halt() if (halt && halt.get_owner().nr == our_player_nr) { // our halt local harb = tile.find_object(mo_building) if (harb && (harb.get_desc().get_type()==building_desc_x.harbour || harb.get_desc().get_type()==building_desc_x.flat_harbour) ) { return halt } } return null } /** * Build harbour at @p tile, * replace water with an array containing all water tiles next to the harbour */ function build_harbour(tile, water_arr) { local water = water_arr[0] local err = null local len = 0 local dif = { x=tile.x-water.x, y=tile.y-water.y} print("Place harbour at " + coord3d_to_string(tile) + " to access " + coord3d_to_string(water) ) if (get_harbour_halt(tile)) { // already there } else { local d_water_to_land = coord_to_dir(dif) local type = get_harbour_type_for_tile(tile, planned_station, planned_harbour_flat, d_water_to_land) switch(type) { case 0: { err = "Cannot place harbour here" gui.add_message_at(our_player, "Cannot place any harbour at " + coord_to_string(tile), tile) break } case 1: { // harbour on slope local slope = dir.to_slope(d_water_to_land) // terraform ?? if (tile.get_slope() != slope && tile.get_slope() != 2*slope) { err = command_x.set_slope(our_player, tile, slope ) if (err) gui.add_message_at(our_player, "Failed to change slope at " + coord_to_string(tile) +"\n" + err, tile) } if (err == null) { err = command_x.build_station(our_player, tile, planned_station) if (err) gui.add_message_at(our_player, "Failed to harbour at " + coord_to_string(tile) +"\n" + err, tile) } local size = planned_station.get_size(0) len = size.x*size.y break } case 2: { // flat dock // flatten slope if (tile.get_slope() != 0) { err = command_x.set_slope(our_player, tile, 0 ) if (err) gui.add_message_at(our_player, "Failed to flatten slope at " + coord_to_string(tile) +"\n" + err, tile) } if (err == null) { local rotation = 0 switch (dir.backward(d_water_to_land)) { case 2: rotation = 1 break case 1: rotation = 2 break case 8: rotation = 3 default: } err = command_x.build_station(our_player, tile, planned_harbour_flat, rotation) if (err) gui.add_message_at(our_player, "Failed to build flat harbour at " + coord_to_string(tile) +"\n" + err, tile) } local size = planned_harbour_flat.get_size(0) len = size.x*size.y break } } } if (err) { return err; } // halt at this harbour local harbour_halt = halt_x.get_halt(tile, our_player) water_arr.clear() // all water tiles near harbour for(local l=0; lharbour_halt) != 0) ) { // we do not want to use this halt continue } water_arr.append(to) } } catch(ev) {/* ignore */} } } if (water_arr.len()==0) { // should not happen print("No non-harbour water tiles found near " + coord_to_string(water)) water_arr.append(water) } return null } function find_route() { local as = route_finder_water() local res = as.search_route(c_start, c_end) if ("err" in res) { return res.err } c_start = [res.start ] c_end = [res.end ] local asd = route_finder_water_depot() res = asd.search_route(as.route) if ("err" in res) { return res.err } local d = res.depot c_depot = tile_x(d.x, d.y, d.z) } function repair_keys() { local cht = {} foreach(key,val in c_harbour_tiles) { local rkey = repair_key(key) cht[rkey] <- val } c_harbour_tiles = cht } static function repair_key(key) { // replace ``dd:dd:dd'' by ``coord3d_dd_dd_dd'' local a = split(key, ":-") if (a.len() == 1) { return key } local rkey = "coord3d_" + a[0] for(local i=1; i 0) { return { start = route[ route.len()-1], end = route[0] } } print("No water depot route found") return { err = "No route" } } } class route_finder_water_depot extends route_finder_water { function estimate_distance(c) { local t = tile_x(c.x, c.y, c.z) if (t.is_water() && t.get_objects().get_count()==0) { return 0 } local depot = t.find_object(mo_depot_water) if (depot && depot.get_owner().nr == our_player_nr) { return 0 } return 10 } function add_to_open(c, weight) { if (c.dist == 0) { // test for depot local t = tile_x(c.x, c.y, c.z) if (t.get_objects().get_count()==0) { // depot not existing, we must build, increase weight weight += 25 * cost_straight } } base.add_to_open(c, weight) } function search_route(watertiles) { prepare_search() // do not place depot on route between harbours foreach(w in watertiles) { add_to_close(w) } // add neighboring tiles of route to open list for(local i=0; i 0) { return { depot = route[0] } } print("No water depot route found") return { err = "No route" } } } simutrans-124.3/simutrans/ai/sqai/station_manager.nut000066400000000000000000000024641474050137200230370ustar00rootroot00000000000000class freight_station_t { factory = null // factory_x road_depot = null // tile_x road_unload = null // tile_x ship_depot = null // tile_x constructor(f) { factory = f } function _save() { return ::saveinstance("freight_station_t", this) } } class freight_station_manager_t extends node_t { freight_station_list = null use_raw_names = 0 /// repair old savegames: use untranslated factory name as key constructor(urn) { base.constructor("freight_station_manager_t") freight_station_list = {} ::station_manager = this use_raw_names = urn } /// Generate unique key from link data static function key(factory) { return (factory.get_raw_name() + coord_to_string(factory)).toalnum() } /** * Access freight_station_t data, create node if not existent. */ function access_freight_station(factory) { local k = key(factory) local res try { res = freight_station_list[k] } catch(ev) { local fs = freight_station_t(factory) freight_station_list[k] <- fs res = fs } return res } /// Repair list: use untranslated factory names function repair_keys() { if (use_raw_names == 1) { return } local fsl = {} foreach(val in freight_station_list) { local rkey = key(val.factory) fsl[rkey] <- val } freight_station_list = fsl use_raw_names = 1 } } simutrans-124.3/simutrans/ai/sqai/vehicle_constructor.nut000066400000000000000000000045101474050137200237420ustar00rootroot00000000000000class vehicle_constructor_t extends node_t { // input data p_depot = null // depot_x p_line = null // line_x p_convoy = null // prototyper_t p_count = 0 p_withdraw = false // generated data c_cnv = null c_wt = 0 // step-by-step construct convoys phase = 0 constructor() { base.constructor("vehicle_constructor_t") debug = true } function step() { local pl = player_x(our_player) c_wt = p_convoy.veh[0].get_waytype() switch(phase) { case 0: // create the convoy (and the first vehicles) { p_depot.append_vehicle(pl, convoy_x(0), p_convoy.veh[0]) // find the newly created convoy // it should be the last in the list local cnv_list = p_depot.get_convoy_list() local trythis = cnv_list[cnv_list.len()-1] if (check_convoy(trythis)) { c_cnv = trythis } if (c_cnv == null) { foreach(cnv in cnv_list) { if (check_convoy(cnv)) { c_cnv = cnv break } } } phase ++ } case 1: // complete the convoy { local vlist = c_cnv.get_vehicles() while (vlist.len() < p_convoy.veh.len()) { p_depot.append_vehicle(pl, c_cnv, p_convoy.veh[ vlist.len() ]) vlist = c_cnv.get_vehicles() } phase ++ } case 2: // set line { c_cnv.set_line(pl, p_line) phase ++ } case 3: // withdraw old vehicles { if (p_withdraw) { local cnv_list = p_line.get_convoy_list() foreach(o_cnv in cnv_list) { if (o_cnv.id != c_cnv.id && !o_cnv.is_withdrawn()) { o_cnv.toggle_withdraw(pl) } } p_withdraw = false } phase ++ } case 4: // start { p_depot.start_convoy(pl, c_cnv) p_count -- if (p_count > 0) { phase = 0 return r_t(RT_PARTIAL_SUCCESS) } else { phase ++ } } } return r_t(RT_TOTAL_SUCCESS) } function check_convoy(cnv) { // check whether this convoy is for our purpose if (cnv.get_line() == null && cnv.get_waytype() == c_wt) { // now test for equal vehicles local vlist = cnv.get_vehicles() local len = vlist.len() if (len <= p_convoy.veh.len()) { local equal = true; for (local i=0; equal && i0 ? x : -x } // global variables our_player_nr <- -1 our_player <- null // player_x instance // for single run functions in month month_count <- false month_count_ticks <- world.get_time().next_month_ticks // build check for new lines build_check_month <- world.get_time().ticks // set factory strategie - 0 = traditional method, taken from C++ implementation factory_strategie <- 0 /* * different ticks per month for bits_per_month * * bits_per_month = 16 -> world.get_time().ticks_per_month = 65.536 * bits_per_month = 17 -> world.get_time().ticks_per_month = 131.072 * bits_per_month = 18 -> world.get_time().ticks_per_month = 262.144 * bits_per_month = 19 -> world.get_time().ticks_per_month = 524.288 * bits_per_month = 20 -> world.get_time().ticks_per_month = 1.048.576 * bits_per_month = 21 -> world.get_time().ticks_per_month = 2.097.152 * bits_per_month = 22 -> world.get_time().ticks_per_month = 4.194.304 * bits_per_month = 23 -> world.get_time().ticks_per_month = 8.388.608 * bits_per_month = 24 -> world.get_time().ticks_per_month = 16.777.216 * * set parameter for road lines check * */ road_line_check <- 500000 // convoy and citycar count convoy_count <- null road_convoy_count <- 0 citycar_count <- 0 // the AI is organized as a tree, // all the work is done in the nodes of the tree tree <- {} // nodes with particular jobs factorysearcher <- null industry_manager <- null station_manager <- null // stepping info s <- {} s._step <- 0 s._next_construction_step <- 0 // the table 'persistent' will be saved in the savegame persistent.s <- s // 2.. 14 = 13 names possible_names <- ["Petersil Cars", "Teumer Alp Dream Trucks", "Runk & Strunk Transports", "A. Nach B. Transports", "Interflug Fourwheelers", "Pfarnest International", "Suboptimal Transports", "Conveyor Belts & Braces", "Bucket Brigade Inc.", "Maggikraut AG", "Bugs & Eggs Unlimited", "S. Claus & R. Deer Worldwide", "Leiterwagn & Sons" ] /** * Start-routine. Will be called when AI is initialized. * Parameter: the number of the AI player. */ function start(pl_nr) { init(pl_nr) // set a funny name if (our_player_nr > 1 && our_player_nr-2 < possible_names.len()) { player_x(our_player_nr).set_name( possible_names[our_player_nr-2]); } gui.add_message_at(our_player, "### script version " + ai.version, world.get_time()) print("Act as player no " + our_player_nr + " under the name " + our_player.get_name()) local player_sai_count = 0 for ( local i = 2; i < 16; i++ ) { if ( player_x(i).is_valid() ) { if ( player_x(i).get_type() == 4 ) { player_sai_count++ } } } //build_check_month += abs(player_count / our_player_nr) build_check_month += (abs(player_sai_count / 2) * world.get_time().ticks_per_month) if ( ( player_sai_count % 2 ) == 0 ) { factory_strategie = 1 build_check_month -= world.get_time().ticks_per_month } else { factory_strategie = 0 } gui.add_message_at(our_player, "### player_sai_count " + player_sai_count + " # build_check_month " + build_check_month + " # factory_strategie " + factory_strategie, world.get_time()) } /** * Initialize the tree with basic nodes. */ function init_tree() { if (factorysearcher == null) { factorysearcher = factorysearcher_t() } if (industry_manager == null) { industry_manager = industry_manager_t() } if (!("tree" in persistent)) { tree = manager_t() tree.append_child(factorysearcher) tree.append_child(industry_manager) persistent.tree <- tree } else { if (persistent.tree.getclass() != manager_t) { // upgrade tree = manager_t() foreach(i in ["nodes", "next_to_step"]) { tree[i] = persistent.tree[i] } } else { tree = persistent.tree } } if (!("station_manager" in persistent)) { persistent.station_manager <- freight_station_manager_t(1) } } /** * Called after savegame is loaded. */ function resume_game(pl_nr) { init(pl_nr) s = persistent.s } function init(pl_nr) { debug.set_pause_on_error(true) our_player_nr = pl_nr our_player = player_x(our_player_nr) srand(our_player_nr * 4711) annotate_classes() // sets class name as attribute for all known classes (save.nut) init_tree() } /** * The heart beat of the player. * If the routine will take too much time, execution is suspended and later resumed. * This should be completely transparent to the script. * Then the main program is still responsive. */ function step() { if ( build_check_month <= world.get_time().ticks ) { tree.step() s._step++ // connector node may fail, but may offer alternative connector node local report = tree.get_report() if (report) { factorysearcher.append_report(report) } if (s._step > s._next_construction_step) { local r = factorysearcher.get_report() if (r && r.action) { /* gui.add_message_at(our_player, "####### r.retire_obj " + r.retire_obj, world.get_time()) gui.add_message_at(our_player, "####### world.get_time().raw " + world.get_time().raw, world.get_time()) */ if ( r.retire_time != null && r.retire_time < world.get_time().ticks ) { //gui.add_message_at(our_player, "####### report out of time ", world.get_time()) //gui.add_message_at(our_player, "####### r.retire_time " + r.retire_time, world.get_time()) //gui.add_message_at(our_player, "####### world.get_time().ticks " + world.get_time().ticks, world.get_time()) return } else if ( r.retire_obj != null && r.retire_obj <= world.get_time().raw ) { //gui.add_message_at(our_player, "####### object out of time ", world.get_time()) return } else { print("New report: expected construction cost: " + (r.cost_fix / 100.0)) //gui.add_message_at(our_player, "New report: expected construction cost: " + (r.cost_fix / 100.0), world.get_time()) tree.append_child(r.action) } } s._next_construction_step += 1 + (s._step % 3) } } else { //gui.add_message_at(our_player, " ai step() break : build_check_month = " + build_check_month, world.get_time()) month_check_message() sleep() } } /** * Helper routine: translate 3d-coordinate to string. * This can be used as key in tables. */ function coord3d_to_key(c) { return ("coord3d_" + c.x + "_" + c.y + "_" + c.z).toalnum(); } function coord_to_key(c) { return ("coord_" + c.x + "_" + c.y).toalnum(); } function equal_coord3d(a,b) { return a.x == b.x && a.y == b.y && a.z == b.z } function is_cash_available(cost /* in 1/100 cr */) { //gui.add_message_at(our_player, " ***** cash : " + our_player.get_current_cash(), world.get_time()) //gui.add_message_at(our_player, " ***** cost : " + cost, world.get_time()) return cost + 2*our_player.get_current_maintenance() < our_player.get_current_cash()*100 } /** * Called to save into savegame. * Returns string that will be saved. * Here: we turn the persistent table into a string using recursive_save (from script/script_base.nut). */ function save() { local str = "" local tic = get_ops_total() local rem = get_ops_remaining() str = "persistent = " + recursive_save(persistent, "\t", [ persistent ] ) local toc = get_ops_total() print("save used " + (toc-tic) + " ops, remaining = " + rem) return str } /** * Returns random number rand with 0 <= rand < upper */ function myrand(upper) { if (upper <= 1) { return upper-1 } local rem = (RAND_MAX % upper) + 1 local r do { r = rand() } while (r > RAND_MAX - rem) return r % upper } /** * Returns ticks for today + @p m months */ function today_plus_months(m) { local time = world.get_time() return time.ticks + m * time.ticks_per_month } /** * returns pakset name (lower case) * * */ function get_set_name() { local pakset = get_pakset_name() // full string from ground.outside.pak if ( pakset != null ) { local s = pakset.find(" ") pakset = pakset.slice(0, s) pakset = pakset.tolower() } else { pakset = "unknown" } return pakset } /* * set global variables citicar and convoy counts * * output = 0 -> no return * output = 1 -> return road_car_rate */ function set_map_vehicles_counts(output = 0) { sleep() local citycar_array = world.get_year_citycars() local convoy_array = world.get_convoys() convoy_count = convoy_array[0] citycar_count = citycar_array[0] road_convoy_count = 0 local list = world.get_convoy_list() foreach(cnv in list) { if ( cnv.is_valid() && cnv.get_waytype() == wt_road ) { road_convoy_count++ } } /* gui.add_message_at(our_player, "####### citycars " + citycar_count, world.get_time()) gui.add_message_at(our_player, "####### convoys " + convoy_count, world.get_time()) gui.add_message_at(our_player, "####### road convoys " + road_convoy_count, world.get_time()) */ if ( output == 1 ) { // citycars and road-cnv on map - rate per tile //local citycar_count = world.get_year_citycars() local map_size_tiles = world.get_size().x * world.get_size().y local map_citizens = world.get_citizens() local road_car_rate = (map_citizens[0]/10)/ max((citycar_count + road_convoy_count), 1) return road_car_rate } } simutrans-124.3/simutrans/ai/sqai_rail/astar.nut000066400000000000000000007752201474050137200220140ustar00rootroot00000000000000/** * Classes to help with route-searching. * Based on the A* algorithm. */ /** * Nodes for A* */ class astar_node extends coord3d { previous = null // previous node cost = -1 // cost to reach this node dist = -1 // distance to target constructor(c, p, co, d) { x = c.x y = c.y z = c.z previous = p cost = co dist = d } function is_straight_move(d) { return d == dir || (previous && previous.dir == d) } } /** * Class to perform A* searches. * * Derived classes have to implement: * process_node(node): add nodes to open list reachable by node * * To use this: * 1) call prepare_search * 2) add tiles to target array * 3) call compute_bounding_box * 4) add start tiles to open list * 5) call search() * 6) use route */ class astar { closed_list = null // table nodes = null // array of astar_node heap = null // binary heap targets = null // array of coord3d's boundingbox = null // box containing all the targets route = null // route, reversed: target to start // statistics calls_open = 0 calls_closed = 0 calls_pop = 0 // costs - can be fine-tuned cost_straight = 10 cost_curve = 14 constructor() { closed_list = {} heap = simple_heap_x() targets = [] } function prepare_search() { closed_list = {} nodes = [] route = [] heap.clear() targets = [] calls_open = 0 calls_closed = 0 calls_pop = 0 } // adds node c to closed list function add_to_close(c) { closed_list[ coord3d_to_key(c) ] <- 1 calls_closed++ } function test_and_close(c) { local key = coord3d_to_key(c) if (key in closed_list) { return false } else { closed_list[ key ] <- 1 calls_closed++ return true } } function is_closed(c) { local key = coord3d_to_key(c) return (key in closed_list) } // add node c to open list with give weight function add_to_open(c, weight) { local i = nodes.len() nodes.append(c) heap.insert(weight, i) calls_open++ } function search() { // compute bounding box of targets compute_bounding_box() local current_node = null while (!heap.is_empty()) { calls_pop++ local wi = heap.pop() current_node = nodes[wi.value] local dist = current_node.dist // target reached if (dist == 0) break; // already visited previously if (!test_and_close(current_node)) { current_node = null continue; } // investigate neighbours and put them into open list process_node(current_node) current_node = null } route = [] if (current_node) { // found route route.append(current_node) while (current_node.previous) { current_node = current_node.previous route.append(current_node) } } print("Calls: pop = " + calls_pop + ", open = " + calls_open + ", close = " + calls_closed) } /** * Computes bounding box of all targets to speed up distance computation. */ function compute_bounding_box() { if (targets.len()>0) { local first = targets[0] boundingbox = { xmin = first.x, xmax = first.x, ymin = first.y, ymax = first.y } for(local i=1; i < targets.len(); i++) { local t = targets[i] if (boundingbox.xmin > t.x) boundingbox.xmin = t.x; if (boundingbox.xmax < t.x) boundingbox.xmax = t.x; if (boundingbox.ymin > t.y) boundingbox.ymin = t.y; if (boundingbox.ymax < t.y) boundingbox.ymax = t.y; } } } /** * Estimates distance to target. * Returns zero if and only if c is a target tile. */ function estimate_distance(c) { local d = 0 local curved = 0 // distance to bounding box local dx = boundingbox.xmin - c.x if (dx <= 0) dx = c.x - boundingbox.xmax; if (dx > 0) d += dx; else dx = 0; local dy = boundingbox.ymin - c.y if (dy <= 0) dy = c.y - boundingbox.ymax if (dy > 0) d += dy; else dy = 0; if (d > 0) { // cost to bounding box return cost_straight * d + (dx*dy > 0 ? cost_curve - cost_straight : 0); } else { local t = targets[0] d = abs(t.x-c.x) + abs(t.y-c.y) // inside bounding box for(local i=1; i < targets.len(); i++) { local t = targets[i] local dx = abs(t.x-c.x) local dy = abs(t.y-c.y) d = min(d, cost_straight * (dx+dy) + (dx*dy > 0 ? cost_curve - cost_straight : 0)) } } return d } } /** * Class to search a route along existing ways. */ class astar_route_finder extends astar { wt = wt_all constructor(wt_) { base.constructor() wt = wt_ if ( [wt_all, wt_invalid, wt_water, wt_air].find(wt) ) { throw("Using this waytype is going to be inefficient. Use at own risk.") } cost_curve = cost_straight } function process_node(cnode) { local from = tile_x(cnode.x, cnode.y, cnode.z) local back = dir.backward(cnode.dir) // allowed directions local dirs = from.get_way_dirs_masked(wt) for(local d = 1; d<16; d*=2) { // do not go backwards, only along existing ways if ( d == back || ( (dirs & d) == 0) ) { continue } local to = from.get_neighbour(wt, d) if (to) { if (!is_closed(to)) { // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost //+ dist local node = ab_node(to, cnode, cost, dist, d) add_to_open(node, weight) } } } } // start and end have to be arrays of objects with 3d-coordinates function search_route(start, end) { prepare_search() foreach (e in end) { targets.append(e); } compute_bounding_box() foreach (s in start) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, 0, 0), dist+1) } search() if (route.len() > 0) { return { start = route[route.len()-1], end = route[0], routes = route } } print("No route found") return { err = "No route" } } } /** * Class to search a route along existing ways. */ class astar_route_finder extends astar { wt = wt_all constructor(wt_) { base.constructor() wt = wt_ if ( [wt_all, wt_invalid, wt_water, wt_air].find(wt) ) { throw("Using this waytype is going to be inefficient. Use at own risk.") } cost_curve = cost_straight } function process_node(cnode) { local from = tile_x(cnode.x, cnode.y, cnode.z) local back = dir.backward(cnode.dir) // allowed directions local dirs = from.get_way_dirs_masked(wt) for(local d = 1; d<16; d*=2) { // do not go backwards, only along existing ways if ( d == back || ( (dirs & d) == 0) ) { continue } local to = from.get_neighbour(wt, d) if (to) { if (!is_closed(to)) { // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost //+ dist local node = ab_node(to, cnode, cost, dist, d) add_to_open(node, weight) } } } } // start and end have to be arrays of objects with 3d-coordinates function search_route(start, end) { prepare_search() foreach (e in end) { targets.append(e); } compute_bounding_box() foreach (s in start) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, 0, 0), dist+1) } search() if (route.len() > 0) { return { start = route.top(), end = route[0], routes = route } } print("No route found") return { err = "No route" } } } class ab_node extends ::astar_node { dir = 0 // direction to reach this node flag = 0 // flag internal to the route searcher constructor(c, p, co, d, di, fl=0) { base.constructor(c, p, co, d) dir = di flag = fl } } /** * Helper class to find bridges and spots to place them. */ class pontifex { player = null bridge = null constructor(pl, way) { // print messages box // 1 = erreg // 2 = list bridges local print_message_box = 0 local wt_name = ["", "road", "rail", "water"] if ( print_message_box > 1 ) { gui.add_message_at(pl, "____________ Search bridge ___________", world.get_time()) } player = pl local list = bridge_desc_x.get_available_bridges(way.get_waytype()) local len = list.len() local way_speed = way.get_topspeed() local bridge_min_len = 5 if (len>0) { bridge = list[0] if ( print_message_box == 2 ) { gui.add_message_at(pl, " ***** way : " + wt_name[way.get_waytype()], world.get_time()) gui.add_message_at(pl, " ***** bridge : " + bridge.get_name(), world.get_time()) gui.add_message_at(pl, " ***** get_max_length : " + bridge.get_max_length(), world.get_time()) } for(local i=1; i bridge_min_len || b.get_max_length() == 0 ) { if (bridge.get_topspeed() < way_speed) { if (b.get_topspeed() > bridge.get_topspeed()) { bridge = b } } else { if (way_speed < b.get_topspeed() && b.get_topspeed() < bridge.get_topspeed()) { bridge = b } } } } } if ( print_message_box > 1 ) { gui.add_message_at(pl, " *** bridge found : " + bridge.get_name() + " way : " + wt_name[way.get_waytype()], world.get_time()) gui.add_message_at(our_player, "--------- Search bridge end ----------", world.get_time()) } } function find_end(pos, dir, min_length) { return bridge_planner_x.find_end(player, pos, dir, bridge, min_length) } } /** * Class to search a route and to build a connection (i.e. roads). * Builds bridges. But not tunnels (not implemented). */ class astar_builder extends astar { builder = null bridger = null way = null function process_node(cnode) { local from = tile_x(cnode.x, cnode.y, cnode.z) local back = dir.backward(cnode.dir) for(local d = 1; d<16; d*=2) { // do not go backwards if (d == back) { continue } // continue straight after a bridge if (cnode.flag == 1 && d != cnode.dir) { continue } local to = from.get_neighbour(wt_all, d) if (to) { if (builder.is_allowed_step(from, to) && !is_closed(to)) { // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) // is there already a road? if (!to.has_way(wt_road)) { move += 8 } local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d) add_to_open(node, weight) } // try bridges else if (bridger && d == cnode.dir && cnode.flag != 1) { local len = 1 local max_len = bridger.bridge.get_max_length() do { local to = bridger.find_end(from, d, len) if (to.x < 0 || is_closed(to)) { break } local bridge_len = abs(from.x-to.x) + abs(from.y-to.y) // long bridges bad local bridge_factor = 3 if ( bridge_len > 20 ) { bridge_factor = 4 }/* else if ( bridge_len > 8 ) { bridge_factor = 4 }*/ local move = bridge_len * cost_straight * bridge_factor /*extra bridge penalty */; // set distance to 1 if at a target tile local dist = max(estimate_distance(to), 1) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 1 /*bridge*/) add_to_open(node, weight) len = bridge_len + 1 } while (len <= max_len) } } } } function search_route(start, end, build_route = 1) { if ( start.len() == 0 || end.len() == 0 ) { if ( print_message_box > 0 ) { gui.add_message_at(our_player, " *** invalid tile : start or end ", world.get_time()) } return { err = "No route" } } prepare_search() foreach (e in end) { targets.append(e); } compute_bounding_box() foreach (s in start) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, 0, 0), dist+1) } search() local bridge_tiles = 0 local count_tree = 0 if (route.len() > 0) { remove_field( route[0] ) // do not try to build in tunnels local is_tunnel_0 = tile_x(route[0].x, route[0].y, route[0].z).find_object(mo_tunnel) local is_tunnel_1 = is_tunnel_0 local last_treeway_tile = null for (local i = 1; i 1 && i < (route.len()-1) ) { local tx_0 = tile_x(route[i-1].x, route[i-1].y, route[i-1].z) local tx_1 = tile_x(route[i+1].x, route[i+1].y, route[i+1].z) if ( tx_0.find_object(mo_way) != null && tx_1.find_object(mo_way) != null ) { //gui.add_message_at(our_player, " check tx_0 and tx_1 ", t) if ( test_exists_way == null ) { local ty = route[i] local cnv_count = tx_0.find_object(mo_way).get_convoys_passed()[0] + tx_0.find_object(mo_way).get_convoys_passed()[1] if ( last_treeway_tile != null && cnv_count == 0 ) { ty = route[last_treeway_tile] } err = test_select_way(tx_1, tx_0, ty, way.get_waytype()) //gui.add_message_at(our_player, " check tx_0 and tx_1 : test_select_way " + err, t) if ( err ) { check_build_tile = false } err = null } } else if ( test_exists_way != null && test_exists_way.get_waytype() == way.get_waytype() ) { check_build_tile = false } if ( tx_0.find_object(mo_signal) != null ) { check_build_tile = false } } if ( test_exists_way != null && test_exists_way.get_owner() != our_player.nr ) { //&& last_treeway_tile != null //gui.add_message_at(our_player, "test_exists_way " + test_exists_way + " last_treeway_tile " + last_treeway_tile + " test_exists_way.get_waytype() " + test_exists_way.get_waytype() + " !t.is_bridge() " + !t.is_bridge() + " t.get_slope() " + t.get_slope(), t) test_exists_way = null } if ( t.is_bridge() ) { //gui.add_message_at(our_player, " t.is_bridge() " + t.is_bridge(), t) last_treeway_tile = null } if ( i > 2 && test_exists_way != null && last_treeway_tile != null && test_exists_way.get_waytype() == wt_rail && t.get_slope() == 0 ) { //gui.add_message_at(our_player, " (624) ", t) err = test_select_way(route[i], route[last_treeway_tile], route[i-1], way.get_waytype()) if ( err ) { last_treeway_tile = null } else { test_exists_way = null last_treeway_tile = null } err = null } /*if ( way.get_waytype() == wt_rail && !t.is_bridge() && t.get_slope == 0 ) { t = tile_x(route[i-1].x, route[i-1].y, route[i-1].z) d = t.get_way_dirs(way.get_waytype()) if ( dir.is_threeway(d) ) { last_treeway_tile = i - 1 } else { last_treeway_tile = null test_exists_way = null } }*/ if ( test_exists_way != null && ( i < 2 || test_exists_way.get_waytype() == wt_road ) ) { test_exists_way = null } local build_tile = false if ( settings.get_pay_for_total_distance_mode == 2 && test_exists_way == null && check_build_tile ) { err = command_x.build_way(our_player, route[i-1], route[i], way, true) build_tile = true } else if ( test_exists_way == null && check_build_tile ) { err = command_x.build_way(our_player, route[i-1], route[i], way, false) build_tile = true } if (err) { //gui.add_message_at(our_player, "Failed to build " + way.get_name() + " from " + coord_to_string(route[i-1]) + " to " + coord_to_string(route[i]) +"\n" + err, route[i]) // remove way // route[0] to route[i] //err = command_x.remove_way(our_player, route[0], route[i]) remove_wayline(route, (i - 1), way.get_waytype()) } else { t = tile_x(route[i-1].x, route[i-1].y, route[i-1].z) d = t.get_way_dirs(way.get_waytype()) //gui.add_message_at(our_player, " (666) dir.is_threeway(d) " + dir.is_threeway(d), t) if ( dir.is_threeway(d) && way.get_waytype() == wt_rail && build_tile ) { last_treeway_tile = i - 1 } } } else if ( build_route == 0 ) { if ( tile_x(route[i].x, route[i].y, route[i].z).find_object(mo_tree) != null ) { count_tree++ } } //} } else if (route[i-1].flag == 1) { // plan build bridge local b_tiles = 0 // if ( route[i-1].x == route[i].x ) { if ( route[i-1].y > route[i].y ) { b_tiles = (route[i-1].y - route[i].y + 1) bridge_tiles += b_tiles } else { b_tiles = (route[i].y - route[i-1].y + 1) bridge_tiles += b_tiles } } else if ( route[i-1].y == route[i].y ) { if ( route[i-1].x > route[i].x ) { b_tiles = (route[i-1].x - route[i].x + 1) bridge_tiles += b_tiles } else { b_tiles = (route[i].x - route[i-1].x + 1) bridge_tiles += b_tiles } } if ( build_route == 1 ) { // check ground under bridge // check_ground() return true build bridge // check_ground() return false no build bridge local build_bridge = true // check whether the ground can be adjusted and no bridge is necessary // bridge len <= 4 tiles if ( b_tiles < 8 ) { build_bridge = check_ground(tile_x(route[i-1].x, route[i-1].y, route[i-1].z), tile_x(route[i].x, route[i].y, route[i].z), way) //gui.add_message_at(our_player, "check_ground(pos_s, pos_e) --- " + build_bridge, route[i-1]) } if ( build_bridge ) { err = command_x.build_bridge(our_player, route[i-1], route[i], bridger.bridge) if (err) { // check whether bridge exists sleep() local arf = astar_route_finder(wt_road) local res_bridge = arf.search_route([route[i-1]], [route[i]]) if ("routes" in res_bridge && res_bridge.routes.len() == abs(route[i-1].x-route[i].x)+abs(route[i-1].y-route[i].y)+1) { // there is a bridge, continue err = null gui.add_message_at(our_player, "Failed to build bridge from " + coord_to_string(route[i-1]) + " to " + coord_to_string(route[i]) +"\n" + err, route[i]) } else { remove_wayline(route, (i - 1), way.get_waytype()) // remove bridge tiles build by not build bridge } } } } else if ( build_route == 0 ) { } } if (err) { return { err = err } } } return { start = route.top(), end = route[0], routes = route, bridge_lens = bridge_tiles, bridge_obj = bridger.bridge, tiles_tree = count_tree } } print("No route found") return { err = "No route" } } } /* * * */ function test_select_way(start, end, t_end, wt) { //gui.add_message_at(our_player, "start " + coord3d_to_string(start) + " end " + coord3d_to_string(end) + " t_end " + coord3d_to_string(t_end), start) local asf = astar_route_finder(wt_rail) local wayline = asf.search_route([start], [end]) if ( "err" in wayline ) { //gui.add_message_at(our_player, "no route from " + coord3d_to_string(start) + " to " + coord3d_to_string(end) , start) } else { //gui.add_message_at(our_player, "exists route from " + coord3d_to_string(start) + " to " + coord3d_to_string(end) , start) local toolr = command_x(tool_remove_way) toolr.work(our_player, t_end, end, "" + wt) return true } return false } /* * check ground under bridges for terraform and remove bridge * * bridges ramp - ramp * * tiles = array -> way tile - bridge tiles - way tile */ function replace_bridge_to_land(tiles) { // test_tile_is_empty(tile) if ( (tiles[1].is_bridge() && tiles[1].y == tiles[0].y ) ) { if ( tiles[1].x > tiles[0].x ) { // 31-1 : 3-13 local tiles_ground = [] for ( local i = 2; i < tiles.len()-2; i++ ) { tiles_ground = square_x(t_tile[i].x, t_tile[i].y).get_ground_tile() } local terraform_grid_tiles = [] local terraform_action = null // 0 = down ; 1 = up if ( tiles_ground[0].get_slope() == 31 && tiles_ground[1].get_slope() == 1 ) { local tile_a1 = square_x(tiles_ground[0].x, tiles_ground[0].y-1).get_ground_tile() local tile_a1 = square_x(tiles_ground[1].x, tiles_ground[1].y-1).get_ground_tile() local tile_b1 = square_x(tiles_ground[0].x, tiles_ground[0].y+1).get_ground_tile() local tile_b2 = square_x(tiles_ground[1].x, tiles_ground[1].y+1).get_ground_tile() } } else { // 13-3 : 1-31 } } } /* * check ground under bridges * * */ function check_ground(pos_s, pos_e, way) { // 0 = off // 1 = terraform // 2 = ground bridge // 3 = local print_message_box = 0 //gui.add_message_at(our_player, "check_ground(pos_s, pos_e) --- " + coord_to_string(pos_s) + " - " + coord_to_string(pos_e), pos_s) local check_x = 0 local check_y = 0 local f_count = 0 local t_tile = [] if ( pos_s.x == pos_e.x ) { check_x = 0 check_y = 1 if ( pos_s.y > pos_e.y ) { f_count = pos_s.y - pos_e.y - 1 local t = tile_x(pos_e.x + check_x, pos_e.y + check_y, pos_e.z) t_tile.append(t) } else { f_count = pos_e.y - pos_s.y - 1 local t = tile_x(pos_s.x + check_x, pos_s.y + check_y, pos_s.z) t_tile.append(t) } //gui.add_message_at(our_player, "check_ground(pos_s, pos_e) --- pos_s.x == pos_e.x -> " + coord_to_string(t_tile[0]), t_tile[0]) } else if ( pos_s.y == pos_e.y ) { check_y = 0 check_x = 1 if ( pos_s.x > pos_e.x ) { f_count = pos_s.x - pos_e.x - 1 local t = tile_x(pos_e.x + check_x, pos_e.y + check_y, pos_e.z) t_tile.append(t) } else { f_count = pos_e.x - pos_s.x - 1 local t = tile_x(pos_s.x + check_x, pos_s.y + check_y, pos_s.z) t_tile.append(t) } //gui.add_message_at(our_player, "check_ground(pos_s, pos_e) --- pos_s.y == pos_e.y -> " + coord_to_string(t_tile[0]), t_tile[0]) } for ( local i = 1; i < f_count; i++ ) { local t = tile_x(t_tile[i-1].x + check_x, t_tile[i-1].y + check_y, t_tile[i-1].z) t_tile.append(t) } local start_end_slope = 0 if ( tile_x(pos_s.x, pos_s.y, pos_s.z).get_slope() == 0 && tile_x(pos_e.x, pos_e.y, pos_e.z).get_slope() == 0 ) { start_end_slope = 1 } else if ( tile_x(pos_s.x, pos_s.y, pos_s.z).get_slope() > 0 && tile_x(pos_e.x, pos_e.y, pos_e.z).get_slope() == 0 ) { start_end_slope = 1 } else if ( tile_x(pos_s.x, pos_s.y, pos_s.z).get_slope() == 0 && tile_x(pos_e.x, pos_e.y, pos_e.z).get_slope() > 0 ) { start_end_slope = 1 } if (print_message_box == 2) gui.add_message_at(our_player, "(800) start_end_slope " + start_end_slope, world.get_time()) local z = null local z1 = null local terraform_tiles = [] local terraform_grid_tiles = [] local grid_coord = [] local err = null if ( start_end_slope == 1 && pos_s.z == pos_e.z && f_count > 1 ) { for ( local i = 0; i < f_count; i++ ) { // find z coord z = square_x(t_tile[i].x, t_tile[i].y).get_ground_tile() if ( (i + 1) == f_count ) { z1 = square_x(t_tile[i-1].x, t_tile[i-1].y).get_ground_tile() } else { z1 = square_x(t_tile[i+1].x, t_tile[i+1].y).get_ground_tile() } if (print_message_box == 2) gui.add_message_at(our_player, "check_ground bridge - tile_tree = " + tile_tree + " || tile_groundobj = " + tile_groundobj + " tile_moving_object = " + tile_moving_object, z) if ( !z.is_ground() ) { // tile is water return true } else if ( !test_tile_is_empty(z) ) { // tiles not free -> build bridge //gui.add_message_at(our_player, "check_ground bridge - !z.is_empty() = " + !z.is_empty() + " || !z.is_ground() = " + !z.is_ground() + " tile = " + coord_to_string(z), z) return true } else if ( ((pos_s.z-2) == z.z || (pos_s.z-1) == z.z) && z.get_slope() > 0 ) { // tiles free no build bridges -> terraform terraform_tiles.append(z) if (print_message_box == 2) gui.add_message_at(our_player, "(832) check_ground bridge - terraform_tiles.append(z) " + coord3d_to_string(z), z) //gui.add_message_at(our_player, "(832) z.get_slope() " + z.get_slope(), z) // EW slope 37-39 : 13-31 : 31-1 : 3-13 // NS slope 13-39 : 31-37 local z_slope_nr = z.get_slope() local z1_slope_nr = z1.get_slope() local grid_tile = null if ( ((z_slope_nr == 39 || z_slope_nr == 31) && z1_slope_nr == 37) || (z_slope_nr == 37 && (z1_slope_nr == 39 || z1_slope_nr == 31)) ) { if ( z1_slope_nr == 39 ) { grid_tile = tile_x(z1.x, z1.y+1, z1.z) } else if ( z_slope_nr == 39 ) { grid_tile = tile_x(z.x, z.y+1, z.z) } if ( z1_slope_nr == 31 ) { grid_tile = tile_x(z1.x+1, z1.y, z1.z) } else if ( z_slope_nr == 31 ) { grid_tile = tile_x(z.x+1, z.y, z.z) } } if ( (z_slope_nr == 13 && (z1_slope_nr == 31 || z1_slope_nr == 39)) || ((z_slope_nr == 31 || z_slope_nr == 39) && z1_slope_nr == 13) ) { if ( z1_slope_nr == 13 ) { grid_tile = tile_x(z1.x, z1.y, z1.z) } else { grid_tile = tile_x(z.x, z.y, z.z) } } if ( (z_slope_nr == 1 && z1_slope_nr == 31) || (z_slope_nr == 31 && z1_slope_nr == 1) ) { if ( z1_slope_nr == 1 ) { grid_tile = tile_x(z1.x, z1.y, z1.z) } else { grid_tile = tile_x(z.x, z.y, z.z) } } if (print_message_box == 3) gui.add_message_at(our_player, "(862) grid_coord.find(coord3d_to_string(grid_tile)) " + grid_coord.find(coord3d_to_string(grid_tile)), grid_tile) if ( grid_tile != null && grid_coord.find(coord3d_to_string(grid_tile)) == null ) { terraform_grid_tiles.append(grid_tile) grid_coord.append(coord3d_to_string(grid_tile)) if (print_message_box == 3) gui.add_message_at(our_player, "(862) check_ground bridge - terraform_grid_tiles.append(grid_tile) " + coord3d_to_string(grid_tile), grid_tile) } /* if ( (z_slope_nr == 3 && z1_slope_nr == 9) || (z_slope_nr == 9 && z1_slope_nr == 3) ) { if ( z1_slope_nr == 9 ) { terraform_grid_tiles.append(tile_x(z1.x+1, z1.y, z1.z)) } else { terraform_grid_tiles.append(tile_x(z.x+1, z.y, z.z)) } } */ } } local terraform_action = 1 // 0 = down ; 1 = up if ( terraform_tiles.len() > 0 && terraform_tiles.len() < 7 ) { local terraform_field = false if ( terraform_grid_tiles.len() > 0 ) { if (print_message_box == 3) gui.add_message_at(our_player, "(873) terraform_grid_tiles.len() " + terraform_grid_tiles.len(), world.get_time()) for ( local i = 0; i < terraform_grid_tiles.len(); i++ ) { if ( pos_s.z > terraform_grid_tiles[i].z ) { err = command_x.grid_raise(our_player, coord3d(terraform_grid_tiles[i].x, terraform_grid_tiles[i].y, terraform_grid_tiles[i].z)) } else { err = command_x.grid_lower(our_player, coord3d(terraform_grid_tiles[i].x, terraform_grid_tiles[i].y, terraform_grid_tiles[i].z)) } if ( err != null ) { terraform_field = true } } } if ( terraform_field ) { for ( local i = 0; i < terraform_tiles.len(); i++ ) { local f = square_x(terraform_tiles[i].x, terraform_tiles[i].y).get_ground_tile() if ( f.z == pos_s.z ) { continue } do { f = square_x(terraform_tiles[i].x, terraform_tiles[i].y).get_ground_tile() err = command_x.set_slope(our_player, f, 82) if ( err != null ) { return false } f = square_x(terraform_tiles[i].x, terraform_tiles[i].y).get_ground_tile() } while(f.z < pos_s.z ) } } err = command_x.build_way(our_player, tile_x(pos_s.x, pos_s.y, pos_s.z), tile_x(pos_e.x, pos_e.y, pos_e.z), way, true) if ( err != null ) { return true } return false } else { return true } } else if ( start_end_slope == 1 && ((pos_s.z-1) == pos_e.z || (pos_s.z+1) == pos_e.z) && f_count < 5 ) { for ( local i = 0; i < f_count; i++ ) { // find z coord z = square_x(t_tile[i].x, t_tile[i].y).get_ground_tile() if (print_message_box == 2) gui.add_message_at(our_player, "(990) check_ground bridge - " + coord_to_string(z), z) if ( !z.is_ground() ) { // tile is water return true } else if ( !test_tile_is_empty(z) ) { // tiles not free -> build bridge if (print_message_box == 2) gui.add_message_at(our_player, "(997) check_ground bridge - !z.is_empty() = " + !z.is_empty() + " || !z.is_ground() = " + !z.is_ground() + " tile = " + coord_to_string(z), z) return true } else if ( ((pos_s.z+1) == z.z || (pos_s.z-1) == z.z || (pos_s.z) == z.z) && z.get_slope() > 0 ) { // tiles free no build bridges -> terraform terraform_tiles.append(z) if (print_message_box == 2) gui.add_message_at(our_player, "(1002) check_ground bridge - terraform_tiles.append(z) " + coord_to_string(z), z) } } if (print_message_box == 1) { local f = null for ( local i = 0; i < terraform_tiles.len(); i++ ) { gui.add_message_at(our_player, "(1009) ---=> terraform_tiles[" + i + "] tile : " + coord3d_to_string(terraform_tiles[i]), world.get_time()) } } /* slope up 83 slope down 82 slope ramp double high up high 1 n 4 s 36 e 28 w 12 slope ramp double high up high 2 n 8 s 72 e 56 w 24 */ if ( ((pos_s.z-1) == pos_e.z || (pos_s.z+1) == pos_e.z) && terraform_tiles.len() > 0 ) { if ( pos_s.is_bridge() ) { err = remove_tile_to_empty(pos_s, way.get_waytype(), 0) } if ( terraform_tiles[0].z == pos_s.z && pos_s.z > pos_e.z && terraform_tiles.len() > 1 ) { terraform_tiles.reverse() } else if ( terraform_tiles[0].z < pos_s.z && pos_s.z > pos_e.z && terraform_tiles.len() > 1 ) { terraform_tiles.reverse() } else if ( terraform_tiles[0].z == pos_s.z && pos_s.z < pos_e.z && pos_s.x > pos_e.x && terraform_tiles.len() > 1 ) { terraform_tiles.reverse() } local slope_id = 0 if ( pos_s.x == pos_e.x && pos_s.y < terraform_tiles[0].y ) { if (print_message_box == 1) gui.add_message_at(our_player, " ---=> (897) tile : " + coord3d_to_string(terraform_tiles[0]), world.get_time()) if ( terraform_tiles[0].z == pos_s.z ) { slope_id = 4 } else { slope_id = 36 } } else if ( pos_s.x == pos_e.x && pos_s.y > terraform_tiles[0].y ) { if (print_message_box == 1) gui.add_message_at(our_player, " ---=> (900) tile : " + coord3d_to_string(terraform_tiles[0]), world.get_time()) if ( terraform_tiles[0].z == pos_s.z ) { slope_id = 36 } else { slope_id = 4 } } else if ( pos_s.y == pos_e.y && pos_s.x < terraform_tiles[0].x ) { if (print_message_box == 1) gui.add_message_at(our_player, " ---=> (903) tile : " + coord3d_to_string(terraform_tiles[0]), world.get_time()) if ( terraform_tiles[0].z == pos_s.z ) { slope_id = 12 } else { slope_id = 28 } } else if ( pos_s.y == pos_e.y && pos_s.x > terraform_tiles[0].x ) { if (print_message_box == 1) gui.add_message_at(our_player, " ---=> (906) tile : " + coord3d_to_string(terraform_tiles[0]), world.get_time()) if ( terraform_tiles[0].z == pos_s.z ) { slope_id = 28 } else { slope_id = 12 } } if ( slope_id > 0 ) { err = command_x.set_slope(our_player, terraform_tiles[0], slope_id) if ( terraform_tiles.len() > 1 ) { err = command_x.set_slope(our_player, terraform_tiles[1], 82) } } err = command_x.build_way(our_player, tile_x(pos_s.x, pos_s.y, pos_s.z), tile_x(pos_e.x, pos_e.y, pos_e.z), way, true) if ( err == null ) { return false } //} else if ( (pos_s.z+1) == pos_e.z && terraform_tiles.len() > 0 ) { } return true }else { return true } } /** * check tile end of station * * direction = 1, 2, 4, 8 * count * s_tile = station tile : tile_x * * return tile_x or null */ function check_tile_end_of_station(direction, count, s_tile) { local tx = 0 local ty = 0 if ( direction == 1 || direction == 4 || direction == 5 ) { ty = count } else if ( direction == 2 || direction == 8 || direction == 10 ) { tx = count } local t_square = null switch(direction) { case 1: t_square = square_x(s_tile.x, s_tile.y + ty) break case 2: t_square = square_x(s_tile.x - tx, s_tile.y) break case 4: t_square = square_x(s_tile.x, s_tile.y - ty) break case 8: t_square = square_x(s_tile.x + tx, s_tile.y) break case 5: t_square = square_x(s_tile.x, s_tile.y - ty) break case 10: t_square = square_x(s_tile.x + tx, s_tile.y) break } local tile_coord = coord3d_to_string(s_tile) // debug local t_ground = null // tile out of map if ( !world.is_coord_valid(t_square) ) { return null } t_ground = t_square.get_ground_tile() if ( test_tile_is_empty(t_ground) && t_ground.z > (s_tile.z - 2) && t_ground.z < (s_tile.z + 2) ) { //t_ground.z > s_tile.z return t_ground } return null } /** * terraform tile * * tile = tile_x * ref_hight = target height * */ function terraform_tile(tile, ref_hight) { // messages set 2 local print_message_box = 0 local pl = our_player if ( print_message_box > 0 ) { if ( debug ) ::debug.set_pause_on_error(true) gui.add_message_at(our_player, " ---=> terraform_tile(tile, ref_hight) tile : " + coord3d_to_string(tile) + " target hight : " + ref_hight, world.get_time()) } if ( test_tile_is_empty(tile) && ( tile.get_slope() > 0 || tile.z != ref_hight ) ) { local err = null if ( print_message_box == 2 ) { gui.add_message_at(our_player, " ---=> terraform", world.get_time()) gui.add_message_at(our_player, " ---=> tile z " + tile.z + " to ref_hight " + ref_hight, world.get_time()) } if ( tile.z < ref_hight && tile.z >= (ref_hight - 2) ) { // terraform up if ( print_message_box == 2 ) { gui.add_message_at(our_player, " ---=> tile up to flat ", world.get_time()) } do { err = command_x.set_slope(our_player, tile, 82 ) if ( err != null ) { break } //z = square_x(tile.x, tile.y).get_ground_tile() } while(tile.z < ref_hight ) } else if ( tile.z >= ref_hight || tile.z <= (ref_hight + 1) ) { // terraform down if ( print_message_box == 2 ) { gui.add_message_at(our_player, " ---=> tile down to flat ", world.get_time()) } do { err = command_x.set_slope(pl, tile, 83 ) if ( err != null ) { break } //z = square_x(fields[i].x, fields[i].y).get_ground_tile() } while(tile.z > ref_hight ) // replace water to land if ( tile.is_water() ) { command_x.change_climate_at(our_player, tile, cl_temperate) } } if ( err ) { return false } return true } else if ( test_tile_is_empty(tile) && ( tile.get_slope() == 0 || tile.z == ref_hight ) ) { return true } return false } /** * * */ function set_marker(pos) { local m_tile = null if (type(pos) == "array") { m_tile = pos[0] } else { m_tile = pos } local tile = square_x(m_tile.x, m_tile.y).get_ground_tile() local tool = command_x(tool_set_marker) tool.work(our_player, tile) } /** * Helper class to remove a field at a factory. * Used if no empty spot is available to place a station. */ function remove_field(pos) { local tile = square_x(pos.x, pos.y).get_ground_tile() local tool = command_x(tool_remover) while(tile.find_object(mo_field)) { tool.work(our_player, pos) } } /** * remove way line * route = way line * pos = last field to build * wt = waytype */ function remove_wayline(route, pos, wt, st_len = null) { local tool = command_x(tool_remover) local toolr = command_x(tool_remove_way) //while(tile.find_object(mo_field)) { // tool.work(our_player, pos) //} local l = 0 if ( st_len == null ) { st_len = 6 } if ( debug ) ::debug.set_pause_on_error(true) local new_route_s = null local new_route_e = null local i = pos local test = 0 local tile_treeway = false local way_cnv_count = 0 for ( i; i >= 0; i-- ) { l++ local tile = square_x(route[i].x, route[i].y).get_ground_tile() local next_tile = null if ( i > 0 ) { next_tile = square_x(route[i-1].x, route[i-1].y).get_ground_tile() } local no_bridge = false if ( i > 0 && ( abs(tile.x-next_tile.x) > 1 || abs(tile.y-next_tile.y) > 1 )) { if ( tile.find_object(mo_bridge) == null ) { no_bridge = true gui.add_message_at(our_player, "#1304# remove way by not build bridge " + coord3d_to_string(tile), next_tile) } } local t_field = tile.find_object(mo_way) if ( t_field == null ) { continue } local cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] // test field has way if ( t_field != null && t_field.get_waytype() == wt ) { // test direction next tile // break by direction 7, 11, 13, 14, 15 if ( i > 0 ) { if (dir.is_threeway(next_tile.get_way_dirs(wt)) || t_field.get_owner().nr == 1) { test = 1 tile_treeway = dir.is_threeway(next_tile.get_way_dirs(wt)) gui.add_message_at(our_player, "(1320) dir.is_threeway(next_tile.get_way_dirs(wt) " + dir.is_threeway(next_tile.get_way_dirs(wt)), next_tile) //::debug.pause() } } if ( tile.find_object(mo_building) != null ) { // no remove station if ( l < st_len ) { continue } test = 1 } else if ( wt == wt_road ) { local test_way = tile.find_object(mo_way) //.get_desc() //local tile_coord = coord3d_to_string(tile) if ( test_way.get_owner().nr == our_player_nr ) { // remove player road from tile // not remove public player road from tile if ( (t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1]) == 0 ) { tool.work(our_player, tile) } } else { // break public way ( road ) test = 1 } } else { // if ( test == 0 ) { if ( l < st_len ) { way_cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] } // remove way from tile if ( cnv_count == way_cnv_count ) { //::debug.pause() tool.work(our_player, tile) } } /*} else if ( wt == wt_rail && dir.is_threeway(tile.get_way_dirs(wt)) ) { gui.add_message_at(our_player, "dir.is_threeway(next_tile.get_way_dirs(wt) " + dir.is_threeway(next_tile.get_way_dirs(wt)), next_tile) test = 1 */ // no remove tile } else if ( tile.find_object(mo_crossing) != null ) { // test crossing and remove local t_field = tile.get_way(wt) way_cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] //::debug.pause() if ( way_cnv_count == 0 ) { toolr.work(our_player, tile, tile, "" + wt) } //tool.work(our_player, tile) } // break by direction 7, 11, 13, 14, 15 or owner public player next tile if ( test == 1 ) { //::debug.pause() new_route_s = i - 1 i-- break } } if ( test == 1 ) { //test = 0 for ( local j = 0; j < i; j++ ) { test = 1 local tile = square_x(route[j].x, route[j].y).get_ground_tile() local next_tile = null if ( j < i ) { next_tile = square_x(route[j+1].x, route[j+1].y).get_ground_tile() } local t_field = tile.find_object(mo_way) // test field has way if ( t_field != null && t_field.get_waytype() == wt ) { // test direction: if in [7, 11, 13, 14, 15] then dir.is_threeway will find this //local tile_treeway = dir.is_threeway(next_tile.get_way_dirs(wt)) if ( tile.find_object(mo_building) != null ) { // no remove station if ( j < st_len ) { continue } test += 1 } else if ( wt == wt_road ) { //local tile_coord = coord3d_to_string(tile) if ( t_field.get_owner().nr == our_player_nr ) { // remove player road from tile // not remove public player road from tile if ( (t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1]) == 0 ) { toolr.work(our_player, tile, tile, "" + wt_road) } } else { // break public way ( road ) test += 1 } /*} else if ( wt == wt_rail && dir.is_threeway(tile.get_way_dirs(wt)) ) { test += 1 ::debug.pause()*/ // no remove tile } else { // remove way from tile local cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] if ( cnv_count == way_cnv_count && !tile_treeway ) { toolr.work(our_player, tile, tile, "" + wt_rail) } else { } } } if ( tile.is_crossing() ) { //::debug.pause() // test crossing and remove local t_field = tile.get_way(wt) way_cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] //gui.add_message_at(our_player, "(1133) crossing way_cnv_count " + way_cnv_count, tile) //::debug.pause() if ( way_cnv_count == 0 ) { toolr.work(our_player, tile, tile, "" + wt) } //tool.work(our_player, tile) } // break by direction 7, 11, 13, 14, 15 if ( test >= 2 ) { //::debug.pause() new_route_e = j + 1 break } } } // check tile pos to empty local tile = square_x(route[pos].x, route[pos].y).get_ground_tile() if ( tile.find_object(mo_way) != null && wt == wt_rail && test == 0 ) { tool.work(our_player, tile) } local route_status = "" local new_route = [] if ( new_route_s != null && new_route_e != null ) { new_route = route.slice(new_route_e, new_route_s) route_status = coord_to_string(new_route[0]) + " to " + coord_to_string(new_route[new_route.len()-1]) } if ( test == 0 ) { //gui.add_message_at(our_player, "removed way from " + coord_to_string(route[pos]) + " to " + coord_to_string(route[0]), route[0]) } else { //gui.add_message_at(our_player, "removed way not all " + route_status, route[0]) //optimize_way_line(new_route, wt) } } /** * remove station / tiles remove until it is empty * fields = field list * wt = waytype */ function remove_tile_to_empty(tiles, wt, t_array = 1) { local tool = command_x(tool_remover) local toolr = command_x(tool_remove_way) if ( t_array == 1 ) { // remove array tiles for ( local i = 0; i < tiles.len(); i++ ) { local tile_remove = 1 local tiles_r = square_x(tiles[i].x, tiles[i].y).get_ground_tile() local test_way = tiles_r.find_object(mo_way) //.get_desc() local tile_coord = coord3d_to_string(tiles_r) if ( test_way != null ) { if ( test_way.get_owner().nr != our_player_nr ) { tile_remove = 0 } } if ( tile_remove == 1 ) { //gui.add_message_at(our_player, "remove tile " + coord3d_to_string(tiles[i]), tiles[i]) if ( tiles_r.is_crossing() ) { //::debug.pause() // test crossing and remove toolr.work(our_player, tiles_r, tiles_r, "" + wt) //tool.work(our_player, tile) } else { while(true){ tool.work(our_player, tiles_r) if (tiles_r.is_empty()) break } //} } } } } else if ( t_array == 0 ) { // remove one tile local tile_remove = 1 local tiles_r = tile_x(tiles.x, tiles.y, tiles.z) local test_way = tiles_r.has_way(wt) //.get_desc() //gui.add_message_at(our_player, "test way tile " + tiles_r.has_way(wt), tiles) //gui.add_message_at(our_player, "crossing_tile " + tiles_r.is_crossing(), tiles) //gui.add_message_at(our_player, "tiles_r.find_object(mo_way).get_owner().nr " + tiles_r.find_object(mo_way).get_owner().nr, tiles) if ( test_way && tiles_r.find_object(mo_way).get_owner().nr != our_player_nr && !tiles_r.is_crossing() ) { tile_remove = 0 } if ( tile_remove == 1 ) { //gui.add_message_at(our_player, "crossing_tile " + tiles_r.is_crossing(), tiles) if ( tiles_r.is_crossing() ) { //::debug.pause() // test crossing and remove toolr.work(our_player, tiles_r, tiles_r, "" + wt) //tool.work(our_player, tile) } else { while(true){ tool.work(our_player, tiles_r) if (tiles_r.is_empty()) break } } return true } else { return false } } } /** * function for check station lenght * * pl = player * starts_field = tile station from plan_simple_connection * st_lenght = stations fields count * wt = waytype * select_station = station object * build = 0 -> test ; 1 -> build * combined_halt = true -> yes ; false -> no * * returns false (something failed) or array of station tiles (success) * in case of success, the value of starts_field maybe changed * */ function check_station(pl, starts_field, t_route, st_lenght, wt, select_station, build = 1, combined_halt = false) { // print messages box // 1 // 2 local print_message_box = 0 //if ( build == 1 ) { print_message_box = 2 } if ( print_message_box == 2 ) { gui.add_message_at(pl, " --- start field : " + coord3d_to_string(starts_field) + " # station lenght : " + st_lenght, world.get_time()) } // save tiles from route local tiles_st = t_route.slice(0, st_lenght) if ( print_message_box == 2 ) gui.add_message_at(pl, "tiles_st.len() = " + tiles_st.len(), tiles_st[0]) if ( starts_field == t_route[t_route.len()-1] ) { tiles_st.clear() tiles_st = t_route.slice((t_route.len()-st_lenght), t_route.len()) tiles_st.reverse() if ( print_message_box == 2 ) gui.add_message_at(pl, "replace tiles_st.len() = " + tiles_st.len(), tiles_st[0]) } local st_build = false local err = null local t = tile_x(starts_field.x, starts_field.y, starts_field.z) local d = t.get_way_dirs(wt) d = dir.backward(d) // now d points outside of the built route // otherwise stations on very short tracks overlap if ( print_message_box == 2 ) { gui.add_message_at(pl, " --- field test : " + coord3d_to_string(starts_field), world.get_time()) gui.add_message_at(pl, " ------ get_way_dirs : " + d, world.get_time()) } // test directions local d_quer = (d == dir.east || d == dir.west) ? dir.north : dir.east; local test_dirs = [d, d_quer, dir.backward(d_quer) ] // first check direction d and backwards // then both orthogonal directions for(local i = 0; i test : " + coord3d_to_string(b1_tile), b1_tile) gui.add_message_at(pl, " ---=> dir.double(d) : " + dir.double(current_d), world.get_time()) } if ( test_field(pl, b1_tile, wt, dir.double(current_d), starts_field.z) && test_tile_is_empty(b1_tile)) { if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> add tile : " + coord3d_to_string(b1_tile), world.get_time()) } b_tile.append(b1_tile) // increase step: if positive add +1, if negative add -1 step = step>0 ? step+1 : step-1 // also increase steps to end of station if (step>0) { step_end ++; } } else { if (step < 0) { // not enough space, fail break } if (i>0) { // do not search for backward directions if orthogonal to d break } // search in forward direction failed, now go backward step = -1 } } // check route tiles for station build if ( print_message_box == 2 && b_tile.len() > 0 ) { gui.add_message_at(pl, " coord3d_to_string(b_tile[0]) " + coord3d_to_string(b_tile[0]) + " - coord3d_to_string(starts_field) " + coord3d_to_string(starts_field), starts_field) } if ( b_tile.len() > 0 && ( coord3d_to_string(b_tile[0]) != coord3d_to_string(starts_field) || b_tile.len() < st_lenght ) ) { if ( print_message_box == 2 ) { gui.add_message_at(pl, " check station tiles to route tiles ", starts_field) } local rc = 1 if (starts_field.x == tiles_st[0].x ) { for ( local i = 1; i < st_lenght; i++ ) { if ( tile_x(tiles_st[i].x, tiles_st[i].y, tiles_st[i].z).has_ways() ) { local t = tile_x(tiles_st[i].x, tiles_st[i].y, tiles_st[i].z) local d = t.get_way_dirs(wt) if ( print_message_box == 2 ) gui.add_message_at(pl, " dir.double(d) " + dir.double(d), tiles_st[i]) if ( tiles_st[0].x == tiles_st[i].x && dir.double(d) && t.get_slope() == 0 ) { rc++ } } } } if (starts_field.y == tiles_st[0].y ) { for ( local i = 1; i < st_lenght; i++ ) { if ( tile_x(tiles_st[i].x, tiles_st[i].y, tiles_st[i].z).has_ways() ) { local t = tile_x(tiles_st[i].x, tiles_st[i].y, tiles_st[i].z) local d = t.get_way_dirs(wt) if ( print_message_box == 2 ) gui.add_message_at(pl, " dir.double(d) " + dir.double(d), tiles_st[i]) if ( tiles_st[0].y == tiles_st[i].y && dir.double(d) && t.get_slope() == 0 ) { rc++ } } } } if ( print_message_box == 2 ) { gui.add_message_at(pl, " rc " + rc + " - st_lenght " + st_lenght, starts_field) } if ( rc == st_lenght ) { // replace stations fields b_tile.clear() b_tile = tiles_st if ( print_message_box == 2 ) { gui.add_message_at(pl, " set station tiles to route tiles ", starts_field) } step_end = 0 } } // build station if ( b_tile.len() == st_lenght && build == 1) { // this will build station, missing ways, do terraform st_build = expand_station(pl, b_tile, wt, select_station, starts_field, combined_halt) } else if ( b_tile.len() == st_lenght && build == 0 ) { st_build = true } // correct first tile of station // (this will correct c_start/c_end if these are used in the call to this method) if (st_build && step_end > 0 && build == 1) { starts_field.x += step_end*dc.x starts_field.y += step_end*dc.y if ( print_message_box == 2 ) gui.add_message_at(pl, " ---> first tile of station reset : " + coord3d_to_string(starts_field), starts_field) } if (st_build) { break // leave for loop to test directions } } if ( st_build == false ) { // move station if ( print_message_box > 0 ) { gui.add_message_at(pl, " *#* ERROR => expand station failed", world.get_time()) gui.add_message_at(pl, " --- field test : " + coord3d_to_string(starts_field), starts_field) gui.add_message_at(pl, " ------ get_way_dirs : " + d, world.get_time()) } //::debug.pause() } return st_build } /** * test fields station * pl = player * t_tile = field to test * wt = waytype * rotate = northsouth ( 5 ) or eastwest ( 10 ) * ref_hight = z from start field * way_exists = 0 -> field expand new station * 1 -> field has way for expand exists station */ function test_field(pl, t_tile, wt, rotate, ref_hight, way_exists = 0) { local print_message_box = 0 local err = null local z = null // tile out of map if ( !world.is_coord_valid(t_tile) ) { return false } // find z coord z = square_x(t_tile.x, t_tile.y).get_ground_tile() if ( test_tile_is_empty(t_tile) && t_tile.get_slope() == 0 && ref_hight == z.z && way_exists == 0 ) { // tile is empty and is flat if ( t_tile.is_ground() ) { if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile is empty and is flat " + coord3d_to_string(t_tile), t_tile) } return true } } else if ( t_tile.has_way(wt) && !t_tile.has_two_ways() && dir.double(t_tile.get_way_dirs(wt)) == rotate && t_tile.get_slope() == 0 && !t_tile.is_bridge() ) { // tile has single way and is flat - no bridge ramp if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile has single way and is flat " + coord3d_to_string(t_tile), t_tile) gui.add_message_at(pl, " ---=> dir.double(t_tile.get_way_dirs(wt)) == rotate : " + dir.double(t_tile.get_way_dirs(wt)) + " == " + rotate, t_tile) } return true } else if ( t_tile.has_way(wt) && !t_tile.has_two_ways() && dir.double(t_tile.get_way_dirs(wt)) == rotate && t_tile.get_slope() > 0 && t_tile.is_bridge() ) { // tile has single way and has bridge start if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile has single way and is bridge " + coord3d_to_string(t_tile), t_tile) } return true } else if ( test_tile_is_empty(t_tile) && ( t_tile.get_slope() > 0 || ref_hight != z.z ) && way_exists == 0 ) { // terraform // return true and terraform befor build station if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile terraform befor build station " + coord3d_to_string(t_tile), t_tile) } return true } return false } /** * test tile is empty * removed objects for empty tiles: tree, ground_object, moving_object * */ function test_tile_is_empty(t_tile) { local tile = tile_x(t_tile.x, t_tile.y, t_tile.z) local tile_tree = tile.find_object(mo_tree) local tile_groundobj = tile.find_object(mo_groundobj) local tile_moving_object = tile.find_object(mo_moving_object) //gui.add_message_at(our_player, " ---=> test_tile " + coord3d_to_string(tile) + " | is_empty " + tile.is_empty() + " | tile_tree " + tile_tree + " | tile_groundobj " + tile_groundobj + " | tile_moving_object " + tile_moving_object, tile) if ( tile.is_empty() ) { return true } else if ( tile_tree != null || tile_groundobj != null || tile_moving_object != null ) { return true } return false } /** * function expand station() * * pl = player * fields = array fields * wt = waytype * select_station = station object * start_fld = c_start or c_end * combined_halt = true -> yes ; false -> no */ function expand_station(pl, fields, wt, select_station, start_fld, combined_halt) { local start_field = tile_x(start_fld.x, start_fld.y, start_fld.z) // 0 = off // 1 = extension build // 2 = messages // 3 = check dock/harbour local print_message_box = 0 local ref_hight = start_field.z local err = null local combined_station = false // extension field for connect station to factory/dock local r = tile_x(start_field.x, start_field.y, start_field.z) local d = r.get_way_dirs(wt) local extension_tile = null switch(d) { case 1: extension_tile = square_x(start_field.x, start_field.y + 1) break case 2: extension_tile = square_x(start_field.x - 1, start_field.y) break case 4: extension_tile = square_x(start_field.x, start_field.y - 1) break case 8: extension_tile = square_x(start_field.x + 1, start_field.y) break } //gui.add_message_at(pl, "(1496) ---=> extension_tile " + extension_tile, world.get_time()) if ( extension_tile != null && tile_x(extension_tile.x, extension_tile.y, extension_tile.get_ground_tile().z).is_water() ) { extension_tile = null } local t = fields.len() if ( t > 0 ) { // terrafom local i = 1 if ( fields[0].x != start_field.x || fields[0].y != start_field.y ) { i = 0 } for ( i; i < t; i++ ) { local z = square_x(fields[i].x, fields[i].y).get_ground_tile() local f = tile_x(fields[i].x, fields[i].y, z.z) if ( test_tile_is_empty(f) && ( f.get_slope() > 0 || ref_hight != z.z ) ) { if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> terraform", world.get_time()) gui.add_message_at(pl, " ---=> tile z " + z.z + " start tile z " + ref_hight, world.get_time()) } if ( z.z < ref_hight && z.z >= (ref_hight - 2) ) { // terraform up if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile up to flat ", world.get_time()) } do { err = command_x.set_slope(pl, tile_x(f.x, f.y, z.z), 82 ) if ( err != null ) { break } z = square_x(fields[i].x, fields[i].y).get_ground_tile() } while(z.z < ref_hight ) } else if ( z.z >= ref_hight || z.z <= (ref_hight + 1) ) { // terraform down if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> tile down to flat ", world.get_time()) } do { err = command_x.set_slope(pl, tile_x(f.x, f.y, z.z), 83 ) if ( err != null ) { break } z = square_x(fields[i].x, fields[i].y).get_ground_tile() } while(z.z > ref_hight ) // replace water to land if ( z.is_water() ) { command_x.change_climate_at(our_player, z, cl_temperate) } } if ( err ) { return false } } } // build way to tiles for ( local i = 1; i < t; i++ ) { if ( test_tile_is_empty(fields[i]) && fields[i].get_slope() == 0 ) { err = null // empty then build way err = command_x.build_way(pl, fields[i-1], fields[i], planned_way, true) if ( err != null ) { gui.add_message_at(pl, " ---=> not build way tile " + coord3d_to_string(fields[i-1]) + " to " + coord3d_to_string(fields[i]) + " - err :" + err, fields[i]) remove_tile_to_empty(fields, wt) return false } } } // check harbour/dock local st_dock = search_station(start_field, wt, 1) if ( !equal_coord3d( fields[0], start_field) ) { local extension = find_extension(wt) if ( extension ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "-*---> selectet extension: " + extension.get_name(), world.get_time()) } if ( st_dock && extension_tile != null ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "-*---> dock/harbour found at : " + coord3d_to_string(st_dock[0]), st_dock[0]) } //gui.add_message_at(pl, "(1596) ---=> abs(fields[0].x - st_dock[0].x) " + abs(fields[0].x - st_dock[0].x), fields[0]) //gui.add_message_at(pl, "(1596) ---=> abs(fields[0].y - st_dock[0].y) " + abs(fields[0].y - st_dock[0].y), fields[0]) if ( abs(fields[0].x - st_dock[0].x) > 1 || abs(fields[0].y - st_dock[0].y) > 1 ) { local tile = tile_x(extension_tile.x, extension_tile.y, extension_tile.get_ground_tile().z) if ( test_tile_is_empty(tile) ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "-*---> build extension at : " + coord3d_to_string(tile), world.get_time()) } err = command_x.build_station(pl, tile, extension) } } } else { err = command_x.build_station(pl, start_field, select_station) } } } if ( st_dock ) { //&& st_dock[0].find_object(mo_building).get_waytype() == wt_water local st_dock_wt = st_dock[0].find_object(mo_building).get_desc().get_waytype() if ( print_message_box == 3 ) { gui.add_message_at(pl, "(1593) ---=> st_dock " + st_dock, st_dock[0]) local b = tile_x(st_dock[0].x, st_dock[0].y, st_dock[0].z).find_object(mo_building) gui.add_message_at(pl, "(1593) ---=> b " + b, st_dock[0]) gui.add_message_at(pl, "(1593) ---=> b.get_desc().get_waytype() " + b.get_desc().get_waytype(), st_dock[0]) gui.add_message_at(pl, "(1593) ---=> b.get_desc().get_name() " + b.get_desc().get_name(), st_dock[0]) ::debug.pause() } if ( st_dock_wt == wt_water ) { combined_station = true } } // station not build to start_field /* local build_connection = 0 if ( combined_station && !equal_coord3d( fields[0], start_field) ) { err = command_x.build_station(pl, start_field, select_station) build_connection = 1 // build connect tile to dock }*/ if ( err == null ) { // build station to tile for ( local i = 0; i < t; i++ ) { local z = square_x(fields[i].x, fields[i].y).get_ground_tile() local f = tile_x(fields[i].x, fields[i].y, z.z) if ( tile_x(fields[i].x, fields[i].y, fields[i].z).is_bridge() && f.get_slope() > 0 ) { // bridge start field -> build to ground fields[i].z -= 1 } // set the rotation for build local rotation = 0 /* switch (fields[i].get_way_dirs(wt)) { case 2: rotation = 1 break case 1: rotation = 2 break case 8: rotation = 3 break default: }*/ local d = tile_x(fields[i].x, fields[i].y, fields[i].z).get_way_dirs(wt) if ( d == 2 || d == 8 || d == 10 ) { rotation = 1 } else if ( d == 1 || d == 4 || d == 5 ) { rotation = 0 } if (debug) gui.add_message_at(pl, "(1952) ---=> set the rotation for build " + rotation, fields[i]) err = command_x.build_station(pl, fields[i], select_station, rotation) if ( err ) { if ( print_message_box > 0 ) { gui.add_message_at(pl, "(1615) ---=> not build station tile at " + coord3d_to_string(fields[i]), fields[i]) } if ( equal_coord3d( fields[0], start_field) ) { fields.remove(0) } remove_tile_to_empty(fields, wt_rail) return false } if ( print_message_box == 2 ) { gui.add_message_at(pl, " ---=> build station tile at " + coord3d_to_string(fields[i]), fields[i]) } } } // station not build to start_field if ( !equal_coord3d( fields[0], start_field) ) { if ( start_field.find_object(mo_building) ) { if ( print_message_box == 2 ) { gui.add_message_at(pl, "(1756) ---=> combined_station " + combined_station, fields[0]) } // remove connect tile to dock local tool = command_x(tool_remover) tool.work(our_player, start_field) } // connect way to station err = command_x.build_way(pl, start_field, fields[0], planned_way, true) } // check station connect factory local st = halt_x.get_halt(fields[0], pl) local s_tiles = [] /* gui.add_message_at(our_player, "(1927) -*---> halt_x.get_halt(fields[0], pl) : " + st, fields[0]) gui.add_message_at(our_player, "(1927) -*---> combined_station : " + combined_station, fields[0]) gui.add_message_at(our_player, "(1927) -*---> combined_halt : " + combined_halt, fields[0]) gui.add_message_at(our_player, "(1927) -*---> extension_tile : " + extension_tile, fields[0]) gui.add_message_at(our_player, "(1927) -*---> st.get_factory_list().len() : " + st.get_factory_list().len(), fields[0]) */ if ( st != null && st.get_factory_list().len() == 0 && combined_halt == false ) { local fl_st = st.get_factory_list() if ( combined_station == false && fl_st.len() == 0 && extension_tile != null ) { local tile = tile_x(extension_tile.x, extension_tile.y, extension_tile.get_ground_tile().z) if ( print_message_box == 1 ) { gui.add_message_at(our_player, "-*---> build extension at : " + coord3d_to_string(tile), tile) } local extension = find_extension(wt) local new_tile = 0 if ( test_tile_is_empty(tile) ) { new_tile = 1 } else if ( tile.has_way(wt_road) && !tile.has_two_ways() ) { local tiles = [1, 2, 4, 5, 8, 10] local test = 0 // test direction from road for ( local i = 0; i < tiles.len(); i++ ) { if ( tile.get_way_dirs(wt_road) == tiles[i] ) { test++ } } if ( test == 1 ) { local stations_list = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x("Passagiere")) err = command_x.build_station(pl, tile, stations_list[0]) if ( err ) { gui.add_message_at(pl, " -##-=> WARNING not connect factory: " + coord3d_to_string(start_field), start_field) new_tile = 1 } } else { new_tile = 1 } } else { new_tile = 1 } if ( new_tile == 1 ) { // to do connection factory other rotations if ( print_message_box == 1 ) { gui.add_message_at(pl, "check connect factory : build extension", start_field) } //::debug.pause() s_tiles.append(fields[0]) s_tiles.append(start_field) local tool = command_x(tool_remover) local test_tiles = [] local factory_connect = 0 if ( start_field.get_way_dirs(wt_rail) == 3 ) { if ( start_field.x == fields[0].x ) { s_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } else if ( start_field.y == fields[0].y ) { s_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } } else if ( start_field.get_way_dirs(wt_rail) == 6 ) { if ( start_field.x == fields[0].x ) { s_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } else if ( start_field.y == fields[0].y ) { s_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } } else if ( start_field.get_way_dirs(wt_rail) == 9 ) { if ( start_field.x == fields[0].x ) { s_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } else if ( start_field.y == fields[0].y ) { s_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } } else if ( start_field.get_way_dirs(wt_rail) == 12 ) { if ( start_field.x == fields[0].x ) { s_tiles.append(square_x(start_field.x-1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } else if ( start_field.y == fields[0].y ) { s_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) test_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y-1).get_ground_tile()) test_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) factory_connect = build_extensions_connect_factory(pl, start_field, fields[0], test_tiles, extension) } } /* if ( tiles.len() == 3 ) { for ( local x = 0; x < 3; x++ ) { if ( halt_x.get_halt(tiles[x], pl) ) { fields.append(tiles[x]) } } }*/ /*if ( start_field.x < fields[0].x && start_field.y < fields[0].y ) { tile = square_x(start_field.x-1, start_field.y).get_ground_tile() if ( tile.is_empty ) { gui.add_message_at(pl, " --=> new extensions field: " + coord3d_to_string(tile), tile) s_tiles.append(fields[0]) s_tiles.append(start_field) if ( start_field.get_way_dirs(wt_rail) == 3 ) { s_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) } else if ( start_field.get_way_dirs(wt_rail) == 6 ) { s_tiles.append(square_x(start_field.x, start_field.y+1).get_ground_tile()) } rebuild = 1 } fields.append(tile) } else if ( start_field.x > fields[0].x && start_field.y > fields[0].y ) { tile = square_x(start_field.x+1, start_field.y).get_ground_tile() if ( tile.is_empty ) { gui.add_message_at(pl, " --=> new extensions field: " + coord3d_to_string(tile), tile) s_tiles.append(fields[0]) s_tiles.append(start_field) if ( start_field.get_way_dirs(wt_rail) == 9 ) { s_tiles.append(square_x(start_field.x, start_field.y-1).get_ground_tile()) } else if ( start_field.get_way_dirs(wt_rail) == 12 ) { s_tiles.append(square_x(start_field.x+1, start_field.y).get_ground_tile()) } rebuild = 1 } fields.append(tile) } else {*/ if ( factory_connect == 0 ) { local tile = square_x(fields[0].x, fields[0].y).get_ground_tile() if ( tile.find_object(mo_building) != null ) { local waytypes = test_halt_waytypes(tile) if ( waytypes > 1 || start_field.find_object(mo_building) != null ) { if ( print_message_box > 0 ) { gui.add_message_at(pl, " -#-=> combined station " + coord3d_to_string(start_field), start_field) } } else { gui.add_message_at(pl, " -###-=> WARNING not connect factory: " + coord3d_to_string(start_field), start_field) } } } } } } else if ( combined_halt ) { // build combined station } if ( start_field.is_empty() ) { // rebuild way err = command_x.build_way(pl, s_tiles[0], s_tiles[1], planned_way, true) err = command_x.build_way(pl, s_tiles[1], s_tiles[2], planned_way, true) } return fields } } /* * function build_extensions_connect_factory() * * pl = player * st_field = start field * hlt_field = halt field * tiles[] = test tiles for extensions to connect factory * extension = extensions object * * return * 1 = connect factory * 0 = not connect factory */ function build_extensions_connect_factory(pl, st_field, hlt_field, tiles, extension) { local factory_connect = 0 // check station connect factory local st = halt_x.get_halt(hlt_field, pl) local fl_st = null local err = null local tool = command_x(tool_remover) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[0]) + " tiles[0].is_empty() " + tiles[0].is_empty() + " - tiles[0].is_water() " + tiles[0].is_water() + " - tiles[0].has_ways() " + tiles[0].has_ways() + " - tiles[0].has_way(wt_water) " + tiles[0].has_way(wt_water), tiles[0]) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[1]) + " tiles[1].is_empty() " + tiles[1].is_empty() + " - tiles[1].is_water() " + tiles[1].is_water(), tiles[1]) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[2]) + " tiles[2].is_empty() " + tiles[2].is_empty() + " - tiles[2].is_water() " + tiles[2].is_water(), tiles[2]) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[0]) + " tiles[0].is_empty() " + tiles[0].is_empty() + " - tiles[0].is_water() " + tiles[0].is_water() + " - tiles[0].has_ways() " + tiles[0].has_ways() + " - tiles[0].has_way(wt_water) " + tiles[0].has_way(wt_water), tiles[0]) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[1]) + " tiles[1].is_empty() " + tiles[1].is_empty() + " - tiles[1].is_water() " + tiles[1].is_water() + " - tiles[1].has_ways() " + tiles[1].has_ways(), tiles[1]) //gui.add_message_at(pl, " -##-=> " + coord3d_to_string(tiles[2]) + " tiles[2].is_empty() " + tiles[2].is_empty() + " - tiles[2].is_water() " + tiles[2].is_water() + " - tiles[2].has_ways() " + tiles[2].has_ways(), tiles[2]) // test 1 -> rebuild 0 for (local i = 0; i < tiles.len(); i++ ) { if ( test_tile_is_empty(tiles[i]) && tiles[i].is_ground() ) { if ( i > 0 ) { tool.work(pl, st_field) command_x.build_station(pl, st_field, extension) } err = command_x.build_station(pl, tiles[i], extension) if ( err != null ) { gui.add_message_at(pl, " -##-=> build err tile " + i + " " + err, tiles[i]) } fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { factory_connect = 1 if ( i > 0 ) { tool.work(pl, st_field) } break } } else if ( tiles[i].has_way(wt_water) ) { //gui.add_message_at(pl, " -##-=> tiles["+i+"].get_way_dirs(wt_water) " + tiles[i].get_way_dirs(wt_water) + " - tiles["+i+"].find_object(mo_way).get_owner().nr " + tiles[i].find_object(mo_way).get_owner().nr, tiles[i]) if ( (tiles[i].get_way_dirs(wt_water) == 5 || tiles[i].get_way_dirs(wt_water) == 10 ) && tiles[i].find_object(mo_way).get_owner().nr == 16 ) { local station = find_station(wt_water) if ( station != false ) { err = command_x.build_station(pl, tiles[i], station) if ( err != null ) { gui.add_message_at(pl, " -##-=> build err tile " + i + " " + err, tiles[i]) } fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { factory_connect = 1 break } } } } else if ( (tiles[i].get_way_dirs(wt_road) == 5 || tiles[i].get_way_dirs(wt_road) == 10 ) && (tiles[i].find_object(mo_way).get_owner().nr == our_player.nr || tiles[i].find_object(mo_way).get_owner().nr == 1) ) { //gui.add_message_at(pl, " -##-=> build road station tile " + coord3d_to_string(tiles[i]), tiles[i]) //gui.add_message_at(pl, " -##-=> halt_x.get_halt(st_field, pl) " + halt_x.get_halt(st_field, pl), tiles[i]) local restor_way = 0 local station = find_station(wt_road) if ( station != false ) { if ( halt_x.get_halt(st_field, pl) == null ) { tool.work(pl, st_field) command_x.build_station(pl, st_field, extension) restor_way = 1 } err = command_x.build_station(pl, tiles[i], station) if ( err != null ) { gui.add_message_at(pl, " -##-=> build err tile " + i + " " + err, tiles[i]) } fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { factory_connect = 1 if (restor_way == 1) { tool.work(pl, st_field) } break } } } } return factory_connect } /* * tiles = field array * station_obj = building_desc_x.station */ function build_station(tiles, station_obj) { } /** * find signal tool * * sig_type = signal type (is_signal, is_presignal ... ) * wt = waytype */ function find_signal(sig_type, wt) { local list = sign_desc_x.get_available_signs(wt) local obj_sign = null foreach(o in list) { if (o.is_signal() && sig_type == "is_signal") { obj_sign = o } if ( o.is_traffic_light() && sig_type == "traffic_light" ) { obj_sign = o } } return obj_sign } /* * * */ function find_station(wt) { local list = building_desc_x.get_available_stations(building_desc_x.station, wt, good_desc_x(freight)) if ( list.len() > 0 ) { return list[0] } else { return false } } /** * find object tool * * obj = object type ( bridge, tunnel, way, catenary ) * wt = waytype * speed = speed */ function find_object(obj, wt, speed) { local list = [] switch(obj) { case "bridge": list = bridge_desc_x.get_available_bridges(wt) break case "tunnel": list = tunnel_desc_x.get_available_tunnels(wt) break case "way": list = way_desc_x.get_available_ways(wt, st_flat) break case "catenary": local li = wayobj_desc_x.get_available_wayobjs(wt) for (local j=0; j0) { obj_desc = list[0] //gui.add_message_at(our_player,"0 obj_desc " + obj_desc.get_name(), world.get_time()) for(local i=1; i obj_desc.get_topspeed() && b.get_topspeed() <= speed ) { obj_desc = b if ( obj_desc.get_topspeed() == speed ) { break } } else { if ( obj_desc.get_topspeed() >= speed ) { break } obj_desc = b //gui.add_message_at(our_player, i + " break obj_desc " + obj_desc.get_name(), world.get_time()) break } } } } } return obj_desc } /** * find extension building tool * * */ function find_extension(wt, tile_size = 1) { local print_message_box = 0 local select_extension = null // extension building from waytype for selected good local extension_list = building_desc_x.get_available_stations(building_desc_x.station_extension, wt, good_desc_x(freight)) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension_list " + extension_list.len(), world.get_time()) } if ( extension_list.len() > 0 ) { foreach(extension in extension_list) { local ok = (select_extension == null) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension " + extension.get_name() + " size " + extension.get_size(0), world.get_time()) } if ( !ok && coord_to_string(extension.get_size(0)) == "1,1" ) { if ( select_extension.get_capacity() > extension.get_capacity() ) { select_extension = extension } } else if ( coord_to_string(extension.get_size(0)) == "1,1" ) { select_extension = extension } } } if ( select_extension == null ) { extension_list.clear() // not find extension from waytype for selected good // search post extension from all waytypes extension_list = building_desc_x.get_available_stations(building_desc_x.station_extension, wt_all, good_desc_x(freight)) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension_list " + extension_list.len(), world.get_time()) } if ( extension_list.len() > 0 ) { foreach(extension in extension_list) { local ok = (select_extension == null) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension " + extension.get_name(), world.get_time()) } if ( !ok && coord_to_string(extension.get_size(0)) == "1,1" ) { if ( select_extension.get_capacity() > extension.get_capacity() ) { select_extension = extension } } else if ( coord_to_string(extension.get_size(0)) == "1,1" ) { select_extension = extension } } } } if ( select_extension == null ) { extension_list.clear() // not find extension from waytype for selected good // search post extension from all waytypes extension_list = building_desc_x.get_available_stations(building_desc_x.station_extension, wt_all, good_desc_x("post")) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension_list " + extension_list.len(), world.get_time()) } if ( extension_list.len() > 0 ) { foreach(extension in extension_list) { local ok = (select_extension == null) if ( print_message_box == 2 ) { gui.add_message_at(our_player, "extension " + extension.get_name(), world.get_time()) } if ( !ok && coord_to_string(extension.get_size(0)) == "1,1" ) { if ( select_extension.get_capacity() > extension.get_capacity() ) { select_extension = extension } } else if ( coord_to_string(extension.get_size(0)) == "1,1" ) { select_extension = extension } } } } if ( print_message_box == 2 ) { gui.add_message_at(our_player, "select_extension " + select_extension, world.get_time()) } return select_extension } /** * search existing depot on range to station * * field_pos = start field * wt = waytype * range = search range * */ function search_depot(field_pos, wt, range = 10) { local list_exists_depot = depot_x.get_depot_list(our_player, wt) if ( list_exists_depot ) { local tile_min = [field_pos.x - range, field_pos.y - range] local tile_max = [field_pos.x + range, field_pos.y + range] local depot_found = null foreach(key in list_exists_depot) { if ( key.x >= tile_min[0] && key.y >= tile_min[1] && key.x <= tile_max[0] && key.y <= tile_max[1] ) { depot_found = tile_x(key.x, key.y, key.z) return depot_found } } } return false } /** * search existing station on range to field * * field_pos = start field * wt = waytype * range = search range * */ function search_station(field_pos, wt, range) { if ( field_pos == null || type(field_pos) == "array" ) { return false } local tile_min = [field_pos.x - range, field_pos.y - range] local tile_max = [field_pos.x + range, field_pos.y + range] local station_found = false foreach(halt in halt_list_x()) { if (halt.get_owner().nr == our_player_nr) { // && halt.get_type == wt local tile = halt.get_tile_list() if ( tile[0].x >= tile_min[0] && tile[0].y >= tile_min[1] && tile[0].x <= tile_max[0] && tile[0].y <= tile_max[1] ) { station_found = tile break } } } return station_found } /** * build double way for more convoys to line * * */ function build_double_track(start_field, wt, station_len) { // 1 // 2 - terraform // 21 - terraform grid // 3 - double track diagonal local print_message_box = 0 if ( print_message_box > 0 ) { gui.add_message_at(our_player, " ### build_double_track ### " + coord3d_to_string(start_field), start_field) gui.add_message_at(our_player, " ### station_len ### " + station_len, start_field) } //local way_list = way_desc_x.get_available_ways(wt, st_flat) local way_obj = start_field.find_object(mo_way).get_desc() //way_list[0] if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, way_obj.get_topspeed()) } local b_player = our_player //way_obj.get_owner() local d = start_field.get_way_dirs(wt) local tiles = [] local tiles_build_l = [] local tiles_build_r = [] local t = 0 local way_len = station_len if ( way_len < 8 ) { way_len = 8 } local diagonal_st = 0 local way_len_d = 0 if ( d == 6 || d == 9 ) { way_len++ way_len_d = 1 diagonal_st = d } else if ( d == 3 || d == 12 ) { way_len++ way_len_d = 1 diagonal_st = d } local diagonal_x = 0 local diagonal_y = 0 local signal = [] // check way // 8 fields straight // 11 fields diagonal for ( local i = 0; i < (way_len + way_len_d); i++ ) { if ( d == 5 ) { // build from n to s // ns - r local ref_ground = square_x(start_field.x, start_field.y + i).get_ground_tile() local t = tile_x(start_field.x + 1, start_field.y + i, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x, start_field.y + i).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(start_field.x + 1, start_field.y + i, ref_ground.z)) } // ns - l t = tile_x(start_field.x - 1, start_field.y + i, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x, start_field.y + i).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(start_field.x - 1, start_field.y + i, ref_ground.z)) } tiles.append(ref_ground) } else if ( d == 10 ) { //gui.add_message_at(our_player, "tile r " + coord3d_to_string(tile_x(start_field.x + i, start_field.y + 1, start_field.z)) + " empty " + tile_x(start_field.x + i, start_field.y + 1, start_field.z).is_empty(), start_field) //gui.add_message_at(our_player, " -- tile l " + coord3d_to_string(tile_x(start_field.x + i, start_field.y - 1, start_field.z)) + " to empty " + tile_x(start_field.x - i, start_field.y + 1, start_field.z).is_empty(), start_field) // ew - r // build from w to e local ref_ground = square_x(start_field.x + i, start_field.y).get_ground_tile() local t = tile_x(start_field.x + i, start_field.y + 1, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x + i, start_field.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(start_field.x + i, start_field.y + 1, ref_ground.z)) } // ew - l t = tile_x(start_field.x + i, start_field.y - 1, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x + i, start_field.y).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(start_field.x + i, start_field.y - 1, ref_ground.z)) } tiles.append(ref_ground) } else if ( d == 6 || d == 9 ) { // build from ne to sw // nw - r if ( i > 0 ) { if ( tiles[i-1].get_way_dirs(wt) == 6 ) { diagonal_y++ } if ( tiles[i-1].get_way_dirs(wt) == 9 ) { diagonal_x++ } } local ref_ground = square_x(start_field.x - diagonal_x, start_field.y + diagonal_y).get_ground_tile() if ( print_message_box == 2 ) { gui.add_message_at(b_player, "6/9 ref_ground " + coord3d_to_string(ref_ground), ref_ground) } local t = null if ( tiles_build_l.len() == 0 && ref_ground.get_way_dirs(wt) == 9 ) { t = tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 1).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z)) } t = tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 2).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)) } } else if ( tiles_build_l.len() > way_len-2 && tiles_build_l.len() <= way_len ) { // no build tile } else if ( tiles_build_l.len() < way_len-2 ) { t = tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 2).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)) } } if ( tiles_build_r.len() == 0 && ref_ground.get_way_dirs(wt) == 6 ) { t = tile_x(ref_ground.x - 1, ref_ground.y, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x - 1, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x - 1, ref_ground.y, ref_ground.z)) } t = tile_x(ref_ground.x - 2, ref_ground.y, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x - 2, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x - 2, ref_ground.y, ref_ground.z)) } }else if ( tiles_build_r.len() > way_len-2 && i <= way_len ) { // no build tile } else if ( tiles_build_r.len() < way_len-2 ) { t = tile_x(ref_ground.x - 2, ref_ground.y, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x - 2, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x - 2, ref_ground.y, ref_ground.z)) } } tiles.append(ref_ground) if ( print_message_box == 30 && i < way_len-2 ) { gui.add_message_at(b_player, "tiles_build_r[" + i + "] " + coord3d_to_string(tiles_build_r[i]), world.get_time()) gui.add_message_at(b_player, "tiles_build_l[" + i + "] " + coord3d_to_string(tiles_build_l[i]), world.get_time()) } } else if ( d == 3 || d == 12 ) { // build from nw to se // nw - r if ( i > 0 ) { if ( tiles[i-1].get_way_dirs(wt) == 3 ) { diagonal_x++ } if ( tiles[i-1].get_way_dirs(wt) == 12 ) { diagonal_y++ } } local ref_ground = square_x(start_field.x + diagonal_x, start_field.y + diagonal_y).get_ground_tile() if ( print_message_box == 2 ) { gui.add_message_at(b_player, "3/12 ref_ground " + coord3d_to_string(ref_ground), world.get_time()) gui.add_message_at(b_player, "tiles_build_l.len() " + tiles_build_l.len() + " ref_ground.get_way_dirs(wt)" + ref_ground.get_way_dirs(wt), world.get_time()) } local t = null if ( tiles_build_l.len() == 0 && ref_ground.get_way_dirs(wt) == 3 ) { //gui.add_message_at(b_player, "test tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z)), world.get_time()) t = tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 1).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z)) //gui.add_message_at(b_player, "add tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 1, ref_ground.z)), world.get_time()) } //gui.add_message_at(b_player, "test tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)), world.get_time()) t = tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 2).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)) //gui.add_message_at(b_player, "add tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)), world.get_time()) } } else if ( tiles_build_l.len() > way_len-2 && tiles_build_l.len() <= way_len ) { // no build tile } else if ( tiles_build_l.len() < way_len-2 ) { //gui.add_message_at(b_player, "test tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)), world.get_time()) t = tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x, ref_ground.y + 2).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)) //gui.add_message_at(b_player, "add tile " + coord3d_to_string(tile_x(ref_ground.x, ref_ground.y + 2, ref_ground.z)), world.get_time()) } } if ( tiles_build_r.len() == 0 && ref_ground.get_way_dirs(wt) == 12 ) { t = tile_x(ref_ground.x + 1, ref_ground.y, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x + 1, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x + 1, ref_ground.y, ref_ground.z)) } t = tile_x(ref_ground.x + 2, ref_ground.y, ref_ground.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x + 2, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x + 2, ref_ground.y, ref_ground.z)) } }else if ( tiles_build_r.len() > way_len-2 && i <= way_len ) { // no build tile } else if ( tiles_build_r.len() < way_len-2 ) { t = tile_x(ref_ground.x + 2, ref_ground.y, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(ref_ground.x + 2, ref_ground.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(ref_ground.x + 2, ref_ground.y, ref_ground.z)) } } tiles.append(ref_ground) if ( print_message_box == 4 && i < way_len-2 ) { gui.add_message_at(b_player, " 12 tiles_build_r[" + i + "] " + coord3d_to_string(tiles_build_r[i]), world.get_time()) gui.add_message_at(b_player, " 3 tiles_build_l[" + i + "] " + coord3d_to_string(tiles_build_l[i]), world.get_time()) } } } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " tiles_build_r " + tiles_build_r.len(), tiles_build_r[0]) gui.add_message_at(b_player, " tiles_build_l " + tiles_build_l.len(), world.get_time()) } // test fields flat local tl = 0 local tr = 0 if ( ( ( tiles_build_r.len() == way_len || tiles_build_l.len() == way_len ) && diagonal_st == 0 ) || ( ( tiles_build_r.len() == (way_len-2) || tiles_build_l.len() == (way_len-2) ) && diagonal_st > 0 ) ) { if ( diagonal_st == 0 ) { // test straight way //gui.add_message_at(b_player, " -- slope test straight way ", world.get_time()) if ( tiles_build_r.len() == way_len ) { for ( local i = 0; i < way_len; i++ ) { if ( tiles_build_r[i].get_slope() == 0 ) { tr++ } } } if ( tiles_build_l.len() == way_len ) { for ( local i = 0; i < way_len; i++ ) { if ( tiles_build_l[i].get_slope() == 0 ) { tl++ } } } } else if ( diagonal_st == 6 || diagonal_st == 9 || diagonal_st == 3 || diagonal_st == 12 ) { // test diagonal way //gui.add_message_at(b_player, " -- slope test diagonal way ", world.get_time()) if ( tiles_build_r.len() == way_len - 2 ) { for ( local i = 0; i < way_len - 2; i++ ) { //gui.add_message_at(b_player, " -- tiles_build_r[" + i + "] " + coord3d_to_string(tiles_build_r[i]), world.get_time()) if ( tiles_build_r[i].get_slope() == 0 ) { tr++ } } } if ( tiles_build_l.len() == way_len - 2 ) { for ( local i = 0; i < way_len - 2; i++ ) { //gui.add_message_at(b_player, " -- tiles_build_l[" + i + "] " + coord3d_to_string(tiles_build_l[i]), world.get_time()) if ( tiles_build_l[i].get_slope() == 0 ) { tl++ } } } } //gui.add_message_at(our_player, " tiles r get_slope() = 0 " + tr, tiles_build_r[0]) //gui.add_message_at(our_player, " tiles l get_slope() = 0 " + tl, tiles_build_l[0]) //gui.add_message_at(our_player, " way_len " + way_len, world.get_time()) local tiles_build = null local err = null local terraform = 0 if ( ( tr == way_len && diagonal_st == 0 ) || ( tr == way_len - 2 && diagonal_st > 0 ) ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build flat right ", start_field) } tiles_build = tiles_build_r tr = way_len tl = 0 } else if ( ( tl == way_len && diagonal_st == 0 ) || ( tl == way_len - 2 && diagonal_st > 0 ) ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build flat left ", start_field) } tiles_build = tiles_build_l tl = way_len tr = 0 } else if ( (( tr < tiles_build_r.len() && tiles_build_r.len() == way_len && diagonal_st == 0 ) || ( tr < tiles_build_r.len() && tiles_build_r.len() == way_len - 2 && diagonal_st > 0 )) && tr >= tl ) { // check terraform tr if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build right check terraform", world.get_time()) } tiles_build = tiles_build_r tr = way_len tl = 0 terraform = 1 } else if ( ( tl < tiles_build_l.len() && tiles_build_l.len() == way_len && diagonal_st == 0 ) || ( tl < tiles_build_l.len() && tiles_build_l.len() == way_len - 2 && diagonal_st > 0 ) ) { // check terraform tl if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build left check terraform", world.get_time()) } tiles_build = tiles_build_l tl = way_len tr = 0 terraform = 1 } if ( terraform == 1 ) { // change terraform local g = terraform_way(tiles, tiles_build, tr, tl, way_len, d) if ( g != false ) { tr = g[0] tl = g[1] if ( way_len > g[2] ) { tiles_build.remove(tiles_build.len()-1) tiles.remove(tiles.len()-1) way_len = g[2] } } else { gui.add_message_at(b_player, "Error terraform", world.get_time()) return false } } // set build left or right /*if ( tr == way_len && tl == way_len ) { } else */ if ( tr == way_len ) { tiles_build = tiles_build_r } else if ( tl == way_len ) { tiles_build = tiles_build_l } // set diagonal start direction correct if ( diagonal_st > 0 ) { // tr = ribi 6 / // tl = ribi 9 / if ( ( tiles[0].get_way_dirs(wt) == 9 && tr == way_len ) || ( tiles[0].get_way_dirs(wt) == 6 && tl == way_len ) || ( tiles[0].get_way_dirs(wt) == 3 && tr == way_len ) || ( tiles[0].get_way_dirs(wt) == 12 && tl == way_len ) ) { //gui.add_message_at(b_player, "remove first tile from tiles[] ", world.get_time()) local n = tiles.slice(1) tiles.clear() tiles = n } else if ( tiles.len() > way_len ) { //gui.add_message_at(b_player, "remove last tile from tiles[] ", world.get_time()) local n = tiles.slice(0, way_len) tiles.clear() tiles = n } diagonal_st = tiles[0].get_way_dirs(wt) } if ( tr == way_len ) { if ( print_message_box == 3 ) { gui.add_message_at(b_player, "build flat right ", start_field) } if ( settings.get_drive_on_left() ) { if ( d == 10 ) { signal = [{coor=coord3d(tiles_build[1].x, tiles_build[1].y, tiles_build[1].z), ribi=8}, {coor=coord3d(tiles[tiles.len()-2].x, tiles[tiles.len()-2].y, tiles[tiles.len()-2].z), ribi=2}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals 10 tr " + coord3d_to_string(tiles_build[1]) + " & " + coord3d_to_string(tiles[6]), world.get_time()) } else if ( d == 5 ) { signal = [{coor=coord3d(tiles_build[tiles.len()-2].x, tiles_build[tiles.len()-2].y, tiles_build[tiles.len()-2].z), ribi=4}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=1}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals 5 tr " + coord3d_to_string(tiles_build[6]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } else if ( diagonal_st == 6 ) { // ribi 6 to 6 signal = [{coor=coord3d(tiles_build[0].x, tiles_build[0].y, tiles_build[0].z), ribi=2}, {coor=coord3d(tiles[way_len - 3].x, tiles[way_len - 3].y, tiles[way_len - 3].z), ribi=8}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals diagonal tr " + coord3d_to_string(tiles_build[0]) + " & " + coord3d_to_string(tiles[way_len - 2]), world.get_time()) } else if ( diagonal_st == 12 ) { signal = [{coor=coord3d(tiles_build[way_len - 3].x, tiles_build[way_len - 3].y, tiles_build[way_len - 3].z), ribi=4}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=1}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals diagonal tr " + coord3d_to_string(tiles_build[way_len - 3]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } } else { if ( d == 10 ) { signal = [{coor=coord3d(tiles_build[way_len - 2].x, tiles_build[way_len - 2].y, tiles_build[way_len - 2].z), ribi=2}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=8}] //gui.add_message_at(b_player, "signals 10 tr " + coord3d_to_string(tiles_build[6]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } else if ( d == 5 ) { signal = [{coor=coord3d(tiles_build[1].x, tiles_build[1].y, tiles_build[1].z), ribi=1}, {coor=coord3d(tiles[way_len - 2].x, tiles[way_len - 2].y, tiles[way_len - 2].z), ribi=4}] //gui.add_message_at(b_player, "signals 5 tr " + coord3d_to_string(tiles_build[1]) + " & " + coord3d_to_string(tiles[6]), world.get_time()) } else if ( diagonal_st == 6 ) { // ribi 6 to 6 signal = [{coor=coord3d(tiles_build[way_len - 3].x, tiles_build[way_len - 3].y, tiles_build[way_len - 3].z), ribi=4}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=1}] //gui.add_message_at(b_player, "signals diagonal tr " + coord3d_to_string(tiles_build[way_len - 3]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } else if ( diagonal_st == 12 ) { // ribi 12 to 12 signal = [{coor=coord3d(tiles_build[0].x, tiles_build[0].y, tiles_build[0].z), ribi=8}, {coor=coord3d(tiles[way_len - 2].x, tiles[way_len - 2].y, tiles[way_len - 2].z), ribi=2}] //gui.add_message_at(b_player, "signals diagonal tr " + coord3d_to_string(tiles_build[0]) + " & " + coord3d_to_string(tiles[way_len - 2]), world.get_time()) } } } else if ( tl == way_len ) { if ( print_message_box == 3 ) { gui.add_message_at(b_player, "build flat left ", start_field) } if ( settings.get_drive_on_left() ) { if ( d == 10 ) { signal = [{coor=coord3d(tiles_build[way_len - 2].x, tiles_build[way_len - 2].y, tiles_build[way_len - 2].z), ribi=2}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=8}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals 10 tl " + coord3d_to_string(tiles_build[6]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } else if ( d == 5 ) { signal = [{coor=coord3d(tiles_build[1].x, tiles_build[1].y, tiles_build[1].z), ribi=1}, {coor=coord3d(tiles[way_len - 2].x, tiles[way_len - 2].y, tiles[way_len - 2].z), ribi=4}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals 5 tl " + coord3d_to_string(tiles_build[1]) + " & " + coord3d_to_string(tiles[6]), world.get_time()) } else if ( diagonal_st == 9 ) { // ribi 9 to 9 signal = [{coor=coord3d(tiles_build[way_len - 3].x, tiles_build[way_len - 3].y, tiles_build[way_len - 3].z), ribi=8}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=2}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals diagonal tl " + coord3d_to_string(tiles_build[way_len - 3]) + " & " + coord3d_to_string(tiles[2]), world.get_time()) } else if ( diagonal_st == 3 ) { // ribi 3 to 3 signal = [{coor=coord3d(tiles_build[0].x, tiles_build[0].y, tiles_build[0].z), ribi=1}, {coor=coord3d(tiles[way_len - 2].x, tiles[way_len - 2].y, tiles[way_len - 2].z), ribi=4}] //gui.add_message_at(b_player, "settings.get_drive_on_left() signals diagonal tl " + coord3d_to_string(tiles_build[0]) + " & " + coord3d_to_string(tiles[way_len - 2]), world.get_time()) } } else { if ( d == 10 ) { signal = [{coor=coord3d(tiles_build[1].x, tiles_build[1].y, tiles_build[1].z), ribi=8}, {coor=coord3d(tiles[6].x, tiles[6].y, tiles[6].z), ribi=2}] //gui.add_message_at(b_player, "signals 10 tl " + coord3d_to_string(tiles_build[1]) + " & " + coord3d_to_string(tiles[6]), world.get_time()) } else if ( d == 5 ) { signal = [{coor=coord3d(tiles_build[way_len - 1].x, tiles_build[way_len - 1].y, tiles_build[way_len - 1].z), ribi=4}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=1}] //gui.add_message_at(b_player, "signals 5 tl " + coord3d_to_string(tiles_build[6]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } else if ( diagonal_st == 9 ) { // ribi 9 to 9 signal = [{coor=coord3d(tiles_build[0].x, tiles_build[0].y, tiles_build[0].z), ribi=1}, {coor=coord3d(tiles[way_len - 2].x, tiles[way_len - 2].y, tiles[way_len - 2].z), ribi=4}] //gui.add_message_at(b_player, "signals diagonal tl " + coord3d_to_string(tiles_build[0]) + " & " + coord3d_to_string(tiles[way_len - 1]), world.get_time()) } else if ( diagonal_st == 3 ) { // ribi 3 to 3 signal = [{coor=coord3d(tiles_build[way_len - 3].x, tiles_build[way_len - 3].y, tiles_build[way_len - 3].z), ribi=2}, {coor=coord3d(tiles[1].x, tiles[1].y, tiles[1].z), ribi=8}] //gui.add_message_at(b_player, "signals diagonal tl " + coord3d_to_string(tiles_build[way_len - 3]) + " & " + coord3d_to_string(tiles[1]), world.get_time()) } } } if ( tiles_build == null ) { //gui.add_message_at(b_player, " ERROR no double way found " + coord3d_to_string(tiles[0]), start_field) return false } // build way local err = null local sig_field = 0 local sig_tile_new = null if ( start_field.get_way_dirs(wt) == 5 || start_field.get_way_dirs(wt) == 10 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "5/10 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[0] " + coord3d_to_string(tiles_build[0]), start_field) } // connect diagonal way local b_tile = null local tile_a = null local tile_b = null local tile_check = 0 if ( tl == way_len ) { if ( start_field.get_way_dirs(wt) == 5 ) { tile_a = tile_x(tiles[0].x, tiles[0].y-1, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y-1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 12 && (tile_b.get_way_dirs(wt) == 3 || (tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 1 //gui.add_message_at(b_player, "(2765) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( start_field.get_way_dirs(wt) == 10 ) { tile_a = tile_x(tiles[0].x-1, tiles[0].y, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y-1, tiles[0].z) if ( (tile_a.get_way_dirs(wt) == 12 || tile_a.get_way_dirs(wt) == 3) && (tile_b.get_way_dirs(wt) == 3 || tile_b.get_way_dirs(wt) == 12 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 2 //gui.add_message_at(b_player, "(2773) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } } else if ( tr == way_len ) { if ( start_field.get_way_dirs(wt) == 5 ) { tile_a = tile_x(tiles[0].x, tiles[0].y-1, tiles[0].z) tile_b = tile_x(tiles[0].x+1, tiles[0].y-1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || (tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b sig_tile_new = "tr5" } tile_check = 3 //gui.add_message_at(b_player, "(2785) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( start_field.get_way_dirs(wt) == 10 ) { tile_a = tile_x(tiles[0].x-1, tiles[0].y, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y+1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b sig_tile_new = "tr10t" } tile_check = 4 //gui.add_message_at(b_player, "(2795) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } } if ( b_tile == null ) { err = command_x.build_way(b_player, tiles[0], tiles_build[0], way_obj, true) } else { err = command_x.build_way(b_player, b_tile, tiles_build[0], way_obj, true) } if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[0] " + coord3d_to_string(tiles_build[0]) + " to tiles_build[" + (way_len - 1) + "] " + coord3d_to_string(tiles_build[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[0], tiles_build[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles[0]) + " to tile " + coord3d_to_string(tiles_build[way_len - 1]), tiles[0]) err = null } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 1) + "] " + coord3d_to_string(tiles_build[way_len - 1]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } // connect diagonal way b_tile = null if ( tile_check == 1 ) { tile_a = tile_x(tiles[way_len - 1].x, tiles[way_len - 1].y+1, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x-1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 9 && (tile_b.get_way_dirs(wt) == 6 || tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0) ) { b_tile = tile_b sig_tile_new = "tl5" } //gui.add_message_at(b_player, "(2827) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 2 ) { tile_a = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y-1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0) ) { b_tile = tile_b sig_tile_new = "tl5" } //gui.add_message_at(b_player, "(2836) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 3 ) { tile_a = tile_x(tiles[way_len - 1].x, tiles[way_len - 1].y+1, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 3 && (tile_b.get_way_dirs(wt) == 12 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b sig_tile_new = "tr5t" } //gui.add_message_at(b_player, "(2844) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 4 ) { tile_a = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 12 && (tile_b.get_way_dirs(wt) == 3 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b sig_tile_new = "tr10" } //gui.add_message_at(b_player, "(2853) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } if ( b_tile == null ) { err = command_x.build_way(b_player, tiles_build[way_len - 1], tiles[way_len - 1], way_obj, true) /*if ( settings.get_drive_on_left() ) { local st = tile_x(signal[0].coor.x, signal[0].coor.y, signal[0].coor.z).get_way_dirs(wt) if ( st == 11 || st == 13 || st == 7 || st == 14 ) { sig_field = 1 } } else {*/ local st = tile_x(signal[1].coor.x, signal[1].coor.y, signal[1].coor.z).get_way_dirs(wt) if ( st == 11 || st == 13 || st == 7 || st == 14 ) { sig_field = 1 } //} } else { err = command_x.build_way(b_player, tiles_build[way_len - 1], b_tile, way_obj, true) } if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[way_len - 1]) + " to tile " + coord3d_to_string(tiles[way_len - 1]), tiles[0]) err = null // remove last tile local tool = command_x(tool_remover) tool.work(our_player, tiles_build[way_len - 1]) // build err = command_x.build_way(b_player, tiles_build[way_len - 2], tiles[way_len - 2], way_obj, true) /*if ( settings.get_drive_on_left() ) { local st = tile_x(signal[0].coor.x, signal[0].coor.y, signal[0].coor.z).get_way_dirs(wt) if ( st == 11 || st == 13 || st == 7 || st == 14 ) { sig_field = 1 } } else {*/ local st = tile_x(signal[1].coor.x, signal[1].coor.y, signal[1].coor.z).get_way_dirs(wt) if ( st == 11 || st == 13 || st == 7 || st == 14 ) { sig_field = 1 } /*if ( signal[0].coor.x == tiles_build[way_len - 2].x && signal[0].coor.y == tiles_build[way_len - 2].y && signal[0].coor.z == tiles_build[way_len - 2].z ) { // 4 signal[0].ribi = 8 }*/ //} } } else { return false } } else if ( tiles[0].get_way_dirs(wt) == 6 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "6 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[1] " + coord3d_to_string(tiles_build[1]), start_field) } err = command_x.build_way(b_player, tiles[0], tiles_build[1], way_obj, true) if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[1] " + coord3d_to_string(tiles_build[1]) + " to tiles_build[" + (way_len - 3) + "] " + coord3d_to_string(tiles_build[way_len - 3]), start_field) } err = command_x.build_way(b_player, tiles_build[1], tiles_build[way_len - 3], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[1]) + " to tile " + coord3d_to_string(tiles_build[way_len - 3]), tiles[0]) err = null } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 3) + "] " + coord3d_to_string(tiles_build[way_len - 3]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[way_len - 3], tiles[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[way_len - 3]) + " to tile " + coord3d_to_string(tiles[way_len]), tiles[0]) err = null } } else { return false } } else if ( tiles[0].get_way_dirs(wt) == 9 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "9 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[1] " + coord3d_to_string(tiles_build[1]), start_field) } err = command_x.build_way(b_player, tiles[0], tiles_build[1], way_obj, true) if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[1] " + coord3d_to_string(tiles_build[1]) + " to tiles_build[" + (way_len - 4) + "] " + coord3d_to_string(tiles_build[way_len - 4]), start_field) } err = command_x.build_way(b_player, tiles_build[1], tiles_build[way_len - 4], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[1]) + " to tile " + coord3d_to_string(tiles_build[way_len - 4]), tiles[0]) err = null } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 4) + "] " + coord3d_to_string(tiles_build[way_len - 4]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[way_len - 4], tiles[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[way_len - 4]) + " to tile " + coord3d_to_string(tiles[way_len - 1]), tiles[0]) err = null } } } else if ( tiles[0].get_way_dirs(wt) == 3 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "3 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[1] " + coord3d_to_string(tiles_build[1]), start_field) } err = command_x.build_way(b_player, tiles[0], tiles_build[1], way_obj, true) if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[1] " + coord3d_to_string(tiles_build[1]) + " to tiles_build[" + (way_len - 4) + "] " + coord3d_to_string(tiles_build[way_len - 4]), start_field) } err = command_x.build_way(b_player, tiles_build[1], tiles_build[way_len - 4], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[1]) + " to tile " + coord3d_to_string(tiles_build[way_len - 4]), tiles[0]) err = null } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 4) + "] " + coord3d_to_string(tiles_build[way_len - 4]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[way_len - 4], tiles[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[way_len - 4]) + " to tile " + coord3d_to_string(tiles[way_len - 1]), tiles[0]) err = null } } } else if ( tiles[0].get_way_dirs(wt) == 12 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "12 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[1] " + coord3d_to_string(tiles_build[1]), start_field) } err = command_x.build_way(b_player, tiles[0], tiles_build[1], way_obj, true) if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[1] " + coord3d_to_string(tiles_build[1]) + " to tiles_build[" + (way_len - 3) + "] " + coord3d_to_string(tiles_build[way_len - 3]), start_field) } err = command_x.build_way(b_player, tiles_build[1], tiles_build[way_len - 3], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[1]) + " to tile " + coord3d_to_string(tiles_build[way_len - 3]), tiles[0]) err = null } local t = 1 if ( tiles[way_len - t].get_way_dirs(wt) == 3 ) { t = 0 } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 3) + "] " + coord3d_to_string(tiles_build[way_len - 3]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[way_len - 3], tiles[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles_build[way_len - 3]) + " to tile " + coord3d_to_string(tiles[way_len - 1]), tiles[0]) err = null } } } // build signals if ( diagonal_st == 0 ) { // build signals // select signal tool local obj_sign = find_signal("is_signal", wt) local sig_1 = tile_x(signal[0].coor.x, signal[0].coor.y, signal[0].coor.z) local sig_2 = tile_x(signal[1].coor.x, signal[1].coor.y, signal[1].coor.z) if ( sig_1.find_object(mo_way) != null && sig_2.find_object(mo_way) != null ) { local test = 0 /*local tiles = [3, 5, 6, 7, 9, 10, 11, 12] for ( local i = 0; i < tiles.len(); i++ ) { if ( sig_1.get_way_dirs(wt) == tiles[i] ) { test++ } if ( sig_2.get_way_dirs(wt) == tiles[i] ) { test++ } } if ( test == 2 ) {*/ for ( local j=0; j < signal.len(); j++ ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "signal to tile " + coord3d_to_string(tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z)), start_field) } local fx = 0 local fy = 0 if ( j == 1 && d == 5 ) { //&& signal[j].coor.y == tiles[tiles.len()-2].y fy = sig_field } else if ( j == 1 && d == 10 ) { //&& signal[j].coor.x == tiles[tiles.len()-2].x fx = sig_field } local s_ribi = signal[j].ribi test = tile_x(signal[j].coor.x-fx, signal[j].coor.y-fy, signal[j].coor.z).get_way_dirs(wt) //gui.add_message_at(b_player, "signal set to ribi " + s_ribi, world.get_time()) if ( print_message_box == 3 ) { gui.add_message_at(b_player, "signal to tile " + coord3d_to_string(tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z)), world.get_time()) } local signal_build_tile = tile_x(signal[j].coor.x-fx, signal[j].coor.y-fy, signal[j].coor.z) if ( settings.get_drive_on_left() ) { } else { // set s_ribi new by double track lenght 7 if ( test == 9 && s_ribi == 2 ) { s_ribi = 1 } if ( test == 12 && s_ribi == 1 ) { s_ribi = 8 } if ( test == 3 && s_ribi == 4 ) { s_ribi = 2 } if ( test == 6 && s_ribi == 8 ) { s_ribi = 4 } if ( print_message_box == 1 && signal[j].ribi != s_ribi ) { gui.add_message_at(b_player, coord3d_to_string(tile_x(signal[j].coor.x-fx, signal[j].coor.y-fy, signal[j].coor.z)) + " signal set to ribi new " + s_ribi, world.get_time()) } //gui.add_message_at(b_player, "sig_tile_new " + sig_tile_new, world.get_time()) if ( (sig_tile_new == "tr10" && j == 0) || (sig_tile_new == "tl5" && j == 0) ) { signal_build_tile = tiles_build[way_len - 1] //} else if ( sig_tile_new == "tr5s" ) { } else if ( (sig_tile_new == "tl10" && j == 0) || (sig_tile_new == "tr5" && j == 0) ) { signal_build_tile = tiles_build[0] } else if ( (sig_tile_new == "tr10t" && j == 1) || (sig_tile_new == "tr5t" && j == 1) ) { signal_build_tile = tiles[0] } } // check ribi test = signal_build_tile.get_way_dirs(wt) if ( test == 3 && s_ribi == 4 ) { s_ribi = 2 } while(true){ local err = command_x.build_sign_at(b_player, signal_build_tile, obj_sign) local ribi = signal_build_tile.get_way_dirs_masked(wt) if (ribi == s_ribi) break } } //} } if ( sig_tile_new != null ) { //::debug.pause() } } else if ( diagonal_st == 6 || diagonal_st == 9 || diagonal_st == 3 || diagonal_st == 12 ) { // build signals local list = sign_desc_x.get_available_signs(wt) local obj_sign = null foreach(o in list) { if ( print_message_box == 2 ) { gui.add_message_at(b_player, "signals " + o.get_name(), start_field) } if (o.is_signal()) { obj_sign = o break } } local sig_1 = tile_x(signal[0].coor.x, signal[0].coor.y, signal[0].coor.z) local sig_2 = tile_x(signal[1].coor.x, signal[1].coor.y, signal[1].coor.z) if ( sig_1.find_object(mo_way) != null && sig_2.find_object(mo_way) != null ) { local tiles = [3, 5, 6, 9, 10, 12] local test = 0 for ( local i = 0; i < tiles.len(); i++ ) { if ( sig_1.get_way_dirs(wt) == tiles[i] ) { test++ } if ( sig_2.get_way_dirs(wt) == tiles[i] ) { test++ } } if ( test == 2 ) { for ( local j=0; j < signal.len(); j++ ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "signal to tile " + coord3d_to_string(tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z)), world.get_time()) } while(true){ local err = command_x.build_sign_at(b_player, tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z), obj_sign) local ribi = tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z).get_way_dirs_masked(wt) if (ribi == signal[j].ribi) break } } } } } print_message_box = 0 return true } } /* * start = start field line * end = end field line * wt = waytype * l = stations distance * c = count of double ways * c=0 -> no build double ways - return route array */ function check_way_line(start, end, wt, l, c, r_line) { /* * 1 = * 2 = straight * 3 = diagonal * 4 = */ if ( debug ) ::debug.set_pause_on_error(true) //debug.pause local print_message_box = 0 local print_message = 0 local message_text = [] if ( print_message_box > 0 ) { gui.add_message_at(our_player, " ### check_way_line ### " + coord3d_to_string(start), start) } local nexttile = [] //[tile_x(start.x, start.y, start.z)] local station_len = 0 //if (wt == wt_rail) { local asf = astar_route_finder(wt) local result = asf.search_route([start], [end]) // result is contains routes-array or error message // route is backward from end to start if ("err" in result) { //gui.add_message_at(our_player, " ### no route found: " + result.err, start) return nexttile } else { //gui.add_message_at(our_player, " ### route found: length = " + result.routes.len(), start) // route found, mark tiles local marked = {} local a = 0 foreach(node in result.routes) { local tile = tile_x(node.x, node.y, node.z) nexttile.append(tile) // count station len start/end if ( tile.find_object(mo_building) != null && a == 0 ) { station_len++ } else { if ( a == 0 ) { station_len += 2 } a = 1 } /* try { tile.mark(); marked.append(tile) } catch(ev) {}*/ } //::debug.pause() sleep() // unmark if game is unpaused again /* foreach(tile in marked) { tile.unmark(); } sleep()*/ } //} // optimize way line befor build double ways //optimize_way_line(nexttile, wt) /* gui.add_message_at(our_player, "end line " + coord3d_to_string(end), end) gui.add_message_at(our_player, "length " + l, world.get_time()) gui.add_message_at(our_player, "count " + c, world.get_time()) */ nexttile.reverse() if ( c == 0 ) { // return way line if ( l == 0 ) { // return way line len return nexttile.len() } else { // return way array return nexttile } } local d = 0 // count double ways local start_fields = [] local start_fields_id = [] local as = 0 local fc = 0 local dfcl = 0 local dfcr = 0 local dc = 0 local di = 0 local r = 0 local s = [] local l_split = 25 if ( station_len < 8 ) { station_len = 8 } else if ( station_len > 8 ) { l_split = station_len + 1 } if ( c > 0 ) { // distance double ways //local as = (l / (c + 1)).tointeger() as = (l / l_split).tointeger() //as = as - ( c * 16 ) if ( print_message_box > 0 ) { gui.add_message_at(our_player, c + " double way search", world.get_time()) message_text.append("l_split " + l_split + " as " + as + " l " + l + " c " + c) } for (local i = 0; i < as; i++ ) { if ( i == 0 ) { //if ( c == 1 ) { // s.append(15) //} else { s.append(l_split - (l_split * 0.3).tointeger() ) //} } else { s.append(s[i-1]+(l_split * 0.7).tointeger()) } message_text.append(" s[" + (i) + "] " + s[i]) } } else { s.append(1) } local sign = 0 local reset = 0 local stl = 0 local str = 0 local dst = 0 local i = 8 while ( i < (nexttile.len() - 1 - station_len) ) { i++ // check to signal local sig = nexttile[i-1].find_object(mo_signal) //gui.add_message_at(our_player, "find_object(mo_signal) " + sig, nexttile[i-1]) if ( sig != null && c > 0 ) { sign++ if ( sign == c ) { //gui.add_message_at(our_player, c + " double way found, no build ", world.get_time()) return true } print_message = 0 //gui.add_message_at(our_player, "signals " + sign, world.get_time()) } di = dc dc = d /*if ( i < station_len ) { st_tile = nexttile[i-1].find_object(mo_building) }*/ // len from double track local way_len = 8 if ( station_len > 8 ) { way_len = station_len if ( d == 6 || d == 9 || d == 3 || d == 12) { way_len = station_len + 1 } } else { if ( d == 6 || d == 9 || d == 3 || d == 12) { way_len = station_len + 1 } } d = nexttile[i].get_way_dirs(wt) // diagonal start ribi if ( ( dc == 5 && d == 6 ) || ( dc == 5 && d == 9 ) ) { dst = 5 } else if ( ( dc == 10 && d == 6 ) || ( dc == 10 && d == 9 ) ) { dst = 10 } else if ( ( dc == 5 && d == 3 ) || ( dc == 5 && d == 12 ) ) { dst = 5 } else if ( ( dc == 10 && d == 3 ) || ( dc == 10 && d == 12 ) ) { dst = 10 } else if ( d == 5 || d == 10 ) { dst = 0 } local t = nexttile[i] local st = 0 // st == 1 no field for double way if ( dst == 0 && fc == 0 && ( t.get_slope() > 0 || t.is_bridge() || t.has_two_ways() ) ) { // check slope, bridge and crossing to start field for double way if ( i >= s[r] && print_message_box == 2 ) { gui.add_message_at(our_player, " ### check first tile " + coord3d_to_string(t), t) } st = 1 } else if ( t.is_bridge() || t.has_two_ways() ) { // check bridge and crossing if ( i >= s[r] && print_message_box == 2 ) { gui.add_message_at(our_player, " ### check bridge " + coord3d_to_string(t), t) } st = 1 } else if ( t.get_way_dirs(wt) == 10 && t.find_object(mo_building) == null ) { local check_tile_str = tile_x(t.x, t.y + 1, t.z) local check_tile_stl = tile_x(t.x, t.y - 1, t.z) // check left & right ground and empty if ( world.is_coord_valid(check_tile_str) ) { // field right empty and ground if ( tile_x(t.x, t.y + 1, t.z).is_ground() && tile_x(t.x, t.y + 1, t.z).is_empty() ) { str++ } else { str = 0 } } else { str = 0 } if ( world.is_coord_valid(check_tile_stl) ) { // field left empty and ground if ( tile_x(t.x, t.y - 1, t.z).is_ground() && tile_x(t.x, t.y - 1, t.z).is_empty() ) { stl++ } else { stl = 0 } } else { stl = 0 } // end diagonal way dst = 0 dfcl = 0 dfcr = 0 } else if ( t.get_way_dirs(wt) == 5 && t.find_object(mo_building) == null ) { // check left & right out of map and ground and empty local check_tile_str = tile_x(t.x + 1, t.y, t.z) local check_tile_stl = tile_x(t.x - 1, t.y, t.z) if ( world.is_coord_valid(check_tile_str) ) { // field right empty and ground if ( check_tile_str.is_ground() && check_tile_str.is_empty() ) { str++ } else { str = 0 } } else { str = 0 } if ( world.is_coord_valid(check_tile_stl) ) { // field left empty and ground if ( check_tile_stl.is_ground() && check_tile_stl.is_empty() ) { stl++ } else { stl = 0 } } else { stl = 0 } // end diagonal way dst = 0 dfcl = 0 dfcr = 0 } else if ( dst > 0 && t.get_way_dirs(wt) == 6 || t.get_way_dirs(wt) == 9 ) { if ( print_message_box == 3 && i >= s[0] && i < (s[0] + way_len) && str == 0 && stl == 0 ) { gui.add_message_at(our_player, " # test 6/9 " + coord3d_to_string(t), t) gui.add_message_at(our_player, " diagonal start dst " + dst, world.get_time()) gui.add_message_at(our_player, " dc " + dc + " dfcl " + dfcl + " dfcr " + dfcr + " - stl " + stl + " - str " + str, world.get_time()) } if ( dst == 5 || dst == 10 ) { local check_tile_strs = null local check_tile_str = null local check_tile_stls = null local check_tile_stl = null if ( nexttile[i-2].x < nexttile[i-1].x || nexttile[i-2].y > nexttile[i-1].y ) { check_tile_strs = tile_x(t.x, t.y - 1, t.z) check_tile_str = tile_x(t.x, t.y - 2, t.z) check_tile_stls = tile_x(t.x + 1, t.y, t.z) check_tile_stl = tile_x(t.x + 2, t.y, t.z) //gui.add_message_at(our_player, " diagonal test A " + " i " + i + " - tile check_tile_str " + coord3d_to_string(check_tile_str), world.get_time()) } else { check_tile_strs = tile_x(t.x - 1, t.y, t.z) check_tile_str = tile_x(t.x - 2, t.y, t.z) check_tile_stls = tile_x(t.x, t.y + 1, t.z) check_tile_stl = tile_x(t.x, t.y + 2, t.z) //gui.add_message_at(our_player, " diagonal test B " + " i " + i + " - tile check_tile_str " + coord3d_to_string(check_tile_str), world.get_time()) } local tile_on_map_r = 0 local tile_on_map_l = 0 if ( world.is_coord_valid(check_tile_strs) && world.is_coord_valid(check_tile_str) ) { // tile is in range map tile_on_map_r = 1 } else { // tile is out of range map str = 0 } if ( world.is_coord_valid(check_tile_stls) && world.is_coord_valid(check_tile_stl) ) { // tile is in range map tile_on_map_l = 1 } else { // tile is out of range map stl = 0 } if ( ( dc == 6 && t.get_way_dirs(wt) == 9 ) || ( dc == 9 && t.get_way_dirs(wt) == 6 ) ) { if ( t.get_way_dirs(wt) == 6 && str == 0 ) { if ( print_message_box == 3 && i >= s[0] && i < (s[0] + way_len) ) { gui.add_message_at(our_player, " - check start ribi 6 " + coord3d_to_string(t), t) } if ( tile_on_map_r == 1 ) { if ( check_tile_strs.is_ground() && check_tile_strs.is_empty() ) { //&& tile_x(t.x, t.y - 2, t.z).is_ground() && tile_x(t.x, t.y - 2, t.z).is_empty() str++ } else { str = 0 } } else { //gui.add_message_at(our_player, " ERROR test tile out of map " + coord3d_to_string(check_tile_strs) + " / " + coord3d_to_string(check_tile_str), t) } } else if ( t.get_way_dirs(wt) == 9 && stl == 0 ) { if ( print_message_box == 3 && i >= s[0] && i < (s[0] + way_len) ) { gui.add_message_at(our_player, " - check start ribi 9 " + coord3d_to_string(t), t) } if ( tile_on_map_l == 1 ) { if ( check_tile_stls.is_ground() && check_tile_stls.is_empty() ) { //&& tile_x(t.x, t.y + 2, t.z).is_ground() && tile_x(t.x, t.y + 2, t.z).is_empty() stl++ } else { stl = 0 } } else { //gui.add_message_at(our_player, " ERROR test tile out of map " + coord3d_to_string(check_tile_stls) + " / " + coord3d_to_string(check_tile_stl), t) } } if ( t.get_way_dirs(wt) == 6 || t.get_way_dirs(wt) == 9 ) { if ( print_message_box == 3 && i >= s[0] && i < (s[0] + way_len) ) { gui.add_message_at(our_player, " - check ribi 6/9 l/r " + coord3d_to_string(t) + " d " + t.get_way_dirs(wt), t) } if ( tile_on_map_r == 1 ) { if ( str > 0 && str <= way_len - 3 ) { if ( check_tile_str.is_ground() && check_tile_str.is_empty() ) { //gui.add_message_at(player_x(1), " + str " + str, world.get_time()) str++ } else { str = 0 } } else if ( str > way_len - 3 && str <= way_len ) { //gui.add_message_at(player_x(1), " ++ str " + str, world.get_time()) str++ } } else { //gui.add_message_at(our_player, "(3320) ERROR test tile out of map ", t) } if ( tile_on_map_l == 1 ) { if ( stl > 0 && stl <= way_len - 3 ) { if ( check_tile_stl.is_ground() && check_tile_stl.is_empty() ) { //gui.add_message_at(player_x(1), " + stl " + stl, world.get_time()) stl++ } else { stl = 0 } } else if ( stl > way_len - 3 && stl <= way_len ) { //gui.add_message_at(player_x(1), " ++ stl " + stl, world.get_time()) stl++ } } else { //gui.add_message_at(our_player, "(3336) ERROR test tile out of map ", t) } } if ( print_message_box == 2 && i >= s[0] && i < (s[0] + way_len + 1) ) { gui.add_message_at(our_player, " -- stl " + stl + " - str " + str + " way_len " + way_len, world.get_time()) } } } // end straight way fc = 0 } else if ( dst > 0 && t.get_way_dirs(wt) == 3 || t.get_way_dirs(wt) == 12 ) { if ( print_message_box == 4 && i >= s[0] && i < (s[0] + way_len) && str == 0 && stl == 0 ) { // gui.add_message_at(our_player, " # test 3/12 " + coord3d_to_string(t), t) gui.add_message_at(our_player, " diagonal start dst " + dst, world.get_time()) gui.add_message_at(our_player, " dc " + dc + " dfcl " + dfcl + " dfcr " + dfcr + " - stl " + stl + " - str " + str, world.get_time()) } if ( dst == 5 || dst == 10 ) { local check_tile_strs = null local check_tile_str = null local check_tile_stls = null local check_tile_stl = null if ( nexttile[i-2].x > nexttile[i-1].x || nexttile[i-2].y > nexttile[i-1].y ) { check_tile_strs = tile_x(t.x - 1, t.y, t.z) check_tile_str = tile_x(t.x - 2, t.y, t.z) check_tile_stls = tile_x(t.x, t.y + 1, t.z) check_tile_stl = tile_x(t.x, t.y + 2, t.z) } else { check_tile_strs = tile_x(t.x, t.y - 1, t.z) check_tile_str = tile_x(t.x, t.y - 2, t.z) check_tile_stls = tile_x(t.x + 1, t.y, t.z) check_tile_stl = tile_x(t.x + 2, t.y, t.z) } local tile_on_map_r = 0 local tile_on_map_l = 0 if ( world.is_coord_valid(check_tile_strs) && world.is_coord_valid(check_tile_str) ) { // tile is in range map tile_on_map_r = 1 } else { // tile is out of range map str = 0 } if ( world.is_coord_valid(check_tile_stls) && world.is_coord_valid(check_tile_stl) ) { // tile is in range map tile_on_map_l = 1 } else { // tile is out of range map stl = 0 } if ( ( dc == 3 && t.get_way_dirs(wt) == 12 ) || ( dc == 12 && t.get_way_dirs(wt) == 3 ) ) { if ( t.get_way_dirs(wt) == 3 && str == 0 ) { if ( print_message_box == 4 ) { //&& i >= s[0] && i < (s[0] + way_len ) gui.add_message_at(our_player, " - check start ribi 3 " + coord3d_to_string(t), t) } if ( tile_on_map_r == 1 ) { if ( check_tile_strs.is_ground() && check_tile_strs.is_empty() ) { str++ } else { str = 0 } } else { //gui.add_message_at(our_player, "(3400) ERROR test tile out of map ", t) } } else if ( t.get_way_dirs(wt) == 12 && stl == 0 ) { if ( print_message_box == 4 && i >= s[0] && i < (s[0] + way_len) ) { // gui.add_message_at(our_player, " - check start ribi 12 " + coord3d_to_string(t), t) } if ( tile_on_map_l == 1 ) { if ( check_tile_stls.is_ground() && check_tile_stls.is_empty() ) { stl++ } else { stl = 0 } } else { //gui.add_message_at(our_player, "(3414) ERROR test tile out of map ", t) } } if ( t.get_way_dirs(wt) == 3 || t.get_way_dirs(wt) == 12 ) { if ( print_message_box == 4 && i >= s[0] && i < (s[0] + way_len) ) { gui.add_message_at(our_player, " - check ribi 3/12 l/r " + coord3d_to_string(t) + " d " + t.get_way_dirs(wt), t) } if ( tile_on_map_r == 1 ) { if ( str > 0 && str <= way_len - 3 ) { if ( check_tile_str.is_ground() && check_tile_str.is_empty() ) { //gui.add_message_at(player_x(1), " + str " + str, world.get_time()) str++ } else { str = 0 } } else if ( str > way_len - 3 && str <= way_len ) { //gui.add_message_at(player_x(1), " ++ str " + str, world.get_time()) str++ } } else { //gui.add_message_at(our_player, "(3436) ERROR test tile out of map ", t) } if ( tile_on_map_l == 1 ) { if ( stl > 0 && stl <= way_len - 3 ) { if ( check_tile_stl.is_ground() && check_tile_stl.is_empty() ) { //gui.add_message_at(player_x(1), " + stl " + stl, world.get_time()) stl++ } else { stl = 0 } } else if ( stl > way_len - 3 && stl <= way_len ) { //gui.add_message_at(player_x(1), " ++ stl " + stl, world.get_time()) stl++ } } else { //gui.add_message_at(our_player, "(3453) ERROR test tile out of map ", t) } } if ( print_message_box == 4 && i >= s[0] && i < (s[0] + way_len + 1) ) { gui.add_message_at(our_player, " -- stl " + stl + " - str " + str + " way_len " + way_len, world.get_time()) } } } // end straight way fc = 0 } if ( i >= s[r] && print_message_box == 2 ) { gui.add_message_at(our_player, "* st " + st + " dst " + dst + " stl " + stl + " str " + str + " fc " + fc + " * " + coord3d_to_string(t), t) } if ( t.get_slope() > 0 && nexttile[i-1].get_slope() > 0 ) { if ( i >= s[r] && print_message_box == 2 ) { gui.add_message_at(our_player, " last 2 tiles have slope - reset " + coord3d_to_string(t), t) ::debug.pause() } stl = 0 str = 0 fc = 0 } if ( dst == 0 && dc == d && i >= s[r] && st == 0 ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, " stl " + stl + " str " + str + " fc " + fc + " * " + coord3d_to_string(t), t) } if ( stl == fc + 1 || str == fc + 1 ) { fc++ dfcr = 0 dfcl = 0 } else { fc = 0 stl = 0 str = 0 } } else if ( dst > 0 && i >= s[r] && st == 0 ) { if ( print_message_box == 3 ) { gui.add_message_at(player_x(1), " stl " + stl + " str " + str + " fc " + fc + " * " + coord3d_to_string(t), t) gui.add_message_at(player_x(1), " dfcl " + dfcl + " dfcr " + dfcr, world.get_time()) } if ( stl == dfcl + 2 ) { dfcl++ fc = 0 } else { dfcl = 0 stl = 0 } if ( str == dfcr + 2 ) { dfcr++ fc = 0 } else { dfcr = 0 str = 0 } } else { fc = 0 stl = 0 str = 0 } if ( print_message_box == 4 ) { gui.add_message_at(player_x(0), " fc " + fc + " s[" + r + "] " + s[r] + " i " + i + " - " + l + " dc " + dc + " di " + di + " d " + d + " * " + coord3d_to_string(t), world.get_time()) } if ( i == s[r] ) { message_text.append(" s[" + r + "] " + s[r] + " i " + i + " is tile " + coord3d_to_string(t)) } if ( i >= s[r] && ( fc >= way_len || dfcl >= way_len || dfcr >= way_len ) ) { // && start_fields.len() < c if ( ( nexttile[i-1].x > nexttile[i].x && fc > 0 && nexttile[i-1].y == nexttile[i].y ) || ( nexttile[i-1].y > nexttile[i].y && fc > 0 ) || ( nexttile[i-1].y > nexttile[i].y && fc == 0 ) || ( nexttile[i-1].x < nexttile[i].x && fc == 0 && nexttile[i-2].y > nexttile[i].y ) ) { /* * * */ if ( nexttile[i].get_slope() == 0 ) { if ( print_message == 1 ) { gui.add_message_at(our_player, " (1) add nexttile[i] id = " + i + " " + coord3d_to_string(t), t) } //start_fields.append(nexttile[i]) start_fields_id.append(i) stl = 0 str = 0 fc = 0 } else if ( nexttile[i+1].get_slope() == 0 ) { // plan start tile has slope then next tile if ( print_message == 1 ) { gui.add_message_at(our_player, " (2) add nexttile[i+1] id = " + (i+1) + " " + coord3d_to_string(nexttile[i+1]), nexttile[i+1]) } //start_fields.append(nexttile[i+1]) start_fields_id.append(i-1) stl = 0 str = 0 fc = 0 } } else if ( nexttile[i-1].x > nexttile[i].x && fc == 0 && nexttile[i-2].y > nexttile[i].y ) { /* * * */ if ( nexttile[i].get_slope() == 0 ) { if ( print_message == 1 ) { gui.add_message_at(our_player, " (3) add nexttile[i] id = " + i + " " + coord3d_to_string(t), t) } //start_fields.append(nexttile[i]) start_fields_id.append(i) stl = 0 str = 0 fc = 0 } } else if ( nexttile[i-1].x < nexttile[i].x && fc > 0 && nexttile[i-2].y == nexttile[i].y ) { if ( nexttile[i-way_len].get_slope() == 0 && !nexttile[i-way_len].is_bridge() && nexttile[i-way_len].find_object(mo_crossing) == null ) { //start_fields.append(nexttile[i-way_len]) start_fields_id.append(i-way_len) if ( print_message == 1 ) { gui.add_message_at(our_player, " (4) add nexttile[i-way_len] id = " + (i-way_len) + " " + coord3d_to_string(t), t) } } else { //start_fields.append(nexttile[i-way_len+1]) start_fields_id.append(i-way_len+1) if ( print_message == 1 ) { gui.add_message_at(our_player, " (5) add nexttile[i-way_len+1] id = " + (i-way_len) + " " + coord3d_to_string(t), t) } } stl = 0 str = 0 } else { if ( ( nexttile[i-way_len].get_way_dirs(wt) == 3 || nexttile[i-way_len].get_way_dirs(wt) == 12 ) && nexttile[i-way_len].get_slope() == 0 && fc == 0 ) { //start_fields.append(nexttile[i-way_len]) start_fields_id.append(i-way_len) stl = 0 str = 0 if ( print_message == 1 ) { gui.add_message_at(our_player, " (6) add nexttile[i-way_len] id = " + (i-way_len) + " " + coord3d_to_string(t), t) } } else if ( nexttile[i-way_len-1].get_slope() == 0 ) { //start_fields.append(nexttile[i-way_len+1]) start_fields_id.append(i-way_len+1) stl = 0 str = 0 fc = 0 if ( print_message == 1 ) { gui.add_message_at(our_player, " (7) add nexttile[i-way_len+1] id = " + (i-way_len+1) + " " + coord3d_to_string(t), t) } } } if ( print_message_box == 2 ) { gui.add_message_at(our_player, " tile s[" + r + "] " + coord3d_to_string(start_fields[r]), start_fields[r]) gui.add_message_at(our_player, " i " + i + " r " + r + " s[" + r + "] " + s[r], world.get_time()) gui.add_message_at(our_player, "* " + coord3d_to_string(t), world.get_time()) } local dw_abs = 10 if ( station_len > 8 ) { dw_abs = 1 } if ( r < as ) { if ( r < s.len() - 1 ) { if ( i > s[r] ) { s[r] = i + dw_abs } else { s[r] = i } } else { if ( i > s[r] ) { s.append(i + dw_abs) } else { s.append(i) } } r++ } } //gui.add_message_at(our_player, " tile d " + d + " * " + coord3d_to_string(t), world.get_time()) } if ( print_message == 1 && print_message_box > 0 ) { for ( local j = 0; j < message_text.len(); j++ ) { gui.add_message_at(our_player, message_text[j], world.get_time()) } } if ( sign == c - 1 && c > 2 ) { //gui.add_message_at(our_player, (c-1) + " double way found, no build " + c, world.get_time()) return true } if ( start_fields_id.len() <= c ) { for ( local i = 0; i < start_fields_id.len(); i++ ) { start_fields.append(nexttile[start_fields_id[i]]) } } else { // start_fields selected if ( c == 2 ) { if ( start_fields_id.len() >= 5 ) { start_fields.append(nexttile[start_fields_id[1]]) start_fields.append(nexttile[start_fields_id[start_fields_id.len()-2]]) } else { start_fields.append(nexttile[start_fields_id[0]]) start_fields.append(nexttile[start_fields_id[start_fields_id.len()-1]]) } } else { local a = (l / (c + 1)).tointeger() //gui.add_message_at(our_player, " a " + a, world.get_time()) local l1 = 0 local l2 = 0 for ( local i = 0; i < c; i++ ) { //gui.add_message_at(our_player, " (a * (i+1)) " + (a * (i+1)), world.get_time()) for ( local j = 1; j < start_fields_id.len(); j++ ) { if ( start_fields_id[j-1] < (a * (i+1)) ) { //l1 = (a * c) - start_fields_id[j-1] if ( start_fields_id.len() < i && start_fields_id[j] < (a * (i+1)) && start_fields_id[j+1] > (a * (i+1)) ) { //l1 = j if ( ((a * (i+1)) - start_fields_id[j+1]) < (start_fields_id[j] - (a * (i+1))) ) { l1 = j+1 } else { l1 = j } } else { if ( ((a * (i+1)) - start_fields_id[j-1]) < (start_fields_id[j] - (a * (i+1))) ) { l1 = j-1 } else { l1 = j //break } // } }/* else { l1 = j-1 break }*/ if ( l1 > 0 && start_fields_id.len() > j && (l1 - l2) < (a-10) ) { } else if ( l1 > 0 ) { break } } //if ( l1 > l2 ) { //} else { start_fields.append(nexttile[start_fields_id[l1]]) //gui.add_message_at(our_player, " start_fields.append() " + start_fields_id[l1], nexttile[start_fields_id[l1]]) l2 = l1 l1 = 0 //} } } //gui.add_message_at(our_player, " start_fields.len() " + start_fields.len(), world.get_time()) } return start_fields } function optimize_way_line(route, wt, int_run, o_line) { // 0 = off // 1 = bridges // 2 = tunnel // 3 = crossing // 4 = terraform local print_message_box = 0 if ( print_message_box > 5 ) { //wt == wt_road && wt == wt_rail && gui.add_message_at(our_player, " optimize_way_line(route, wt) ", tile_x(route[0].x, route[0].y, route[0].z)) } //::debug.pause() local speed = tile_x(route[0].x, route[0].y, route[0].z).find_object(mo_way).get_desc().get_topspeed() local bridge_obj = find_object("bridge", wt, speed) local tunnel_obj = find_object("tunnel", wt, speed) local count_build = 0 local stations_awst = null local stations_awst_2 = [] // count station len start local station_len = 0 for ( local c = 0; c < 50; c++ ) { if ( route[c].find_object(mo_building) != null ) { station_len++ } else { break } } if ( station_len == 1 ) { station_len = 3 } //gui.add_message_at(our_player, " found bridge " + bridge_obj.get_name() + " tunnel " + tunnel_obj.get_name(), world.get_time()) for ( local i = 1; i < (route.len() - station_len); i++ ) { local tile_1 = tile_x(route[i-1].x, route[i-1].y, route[i-1].z) local tile_2 = tile_x(route[i].x, route[i].y, route[i].z) local tile_3 = tile_x(route[i+1].x, route[i+1].y, route[i+1].z) local tile_4 = null local tile_1_d = tile_1.get_way_dirs(wt) local tile_2_d = tile_2.get_way_dirs(wt) local tile_3_d = tile_3.get_way_dirs(wt) local tile_4_d = 0 local tile_2_speed = 0 // START :: remove diagonal double ways without spacing if ( dir.is_threeway(tile_1_d) && dir.is_threeway(tile_3_d) ) { tile_2_speed = tile_2.find_object(mo_way).get_desc().get_topspeed() local remove_tile = null switch(tile_2_d) { case 3: tile_4 = tile_x(tile_2.x+1, tile_2.y-1, tile_2.z) if ( tile_4.find_object(mo_way) != null ) { tile_4_d = tile_4.get_way_dirs(wt) if ( tile_2_speed >= tile_4.find_object(mo_way).get_desc().get_topspeed() && tile_4_d == 12 ) { remove_tile = tile_4 } else if ( tile_4_d == 12 ) { remove_tile = tile_2 } } break case 6: tile_4 = tile_x(tile_2.x+1, tile_2.y+1, tile_2.z) if ( tile_4.find_object(mo_way) != null ) { tile_4_d = tile_4.get_way_dirs(wt) if ( tile_2_speed >= tile_4.find_object(mo_way).get_desc().get_topspeed() && tile_4_d == 9 ) { remove_tile = tile_4 } else if ( tile_4_d == 9 ) { remove_tile = tile_2 } } break case 9: tile_4 = tile_x(tile_2.x-1, tile_2.y-1, tile_2.z) if ( tile_4.find_object(mo_way) != null ) { tile_4_d = tile_4.get_way_dirs(wt) if ( tile_2_speed >= tile_4.find_object(mo_way).get_desc().get_topspeed() && tile_4_d == 6 ) { remove_tile = tile_4 } else if ( tile_4_d == 6 ) { remove_tile = tile_2 } } break case 12: tile_4 = tile_x(tile_2.x-1, tile_2.y+1, tile_2.z) if ( tile_4.find_object(mo_way) != null ) { tile_4_d = tile_4.get_way_dirs(wt) if ( tile_2_speed >= tile_4.find_object(mo_way).get_desc().get_topspeed() && tile_4_d == 3 ) { remove_tile = tile_4 } else if ( tile_4_d == 3 ) { remove_tile = tile_2 } } break } if ( remove_tile != null ) { remove_tile_to_empty(remove_tile, wt, 0) } } // END :: remove diagonal double ways without spacing // START :: check station in line if ( tile_2.find_object(mo_building) != null && i > station_len && i < (route.len() - station_len) && wt == wt_rail && stations_awst == null ) { // station in line // set line.way_line_count o_line.way_line_count = 2 local li = tile_2.get_halt().get_line_list() // todo line_x -> my_line_t local s_line = select_linkline(li[0]) s_line.way_line_count = 2 /* local entries = r_line.get_schedule().entries if ( entries.len() == 2 ) { local sched = schedule_x(wt_rail, []) sched.entries.append( schedule_entry_x(entries[0], 100, 0) ); sched.entries.append( schedule_entry_x(t, 0, 0) ); sched.entries.append( schedule_entry_x(entries[entries.len()-1], 0, 0) ); r_line.change_schedule(our_player, sched); }*/ local t = null local r = null for (local j = 1; j < station_len; j++ ) { t = route[i+j] //gui.add_message_at(our_player, "st_awst ", t) if (t.find_object(mo_building) == null) { r = j break } } if ( (t.x == tile_2.x && t.y < tile_2.y) || (t.y == tile_2.y && t.x < tile_2.x) ) { stations_awst = t r = i + 9 } else if ( (t.x == tile_2.x && t.y > tile_2.y) || (t.y == tile_2.y && t.x > tile_2.x) ) { stations_awst = tile_1 r = i - 9 } for (local j = 1; j < 9; j++ ) { if ( r < 0 ) { break } stations_awst_2.append(route[r+j]) } } // END :: check station in line // START :: build bridges and tunnel - 2 to 4 tiles local build_bridge = 0 local build_tunnel = 0 local build_tile = null tile_4 = tile_x(route[i+2].x, route[i+2].y, route[i+2].z) tile_4_d = tile_4.get_way_dirs(wt) // tile 1 - 3 direction 5 or 10 -> way_d = 1 // tile 1 - 4 direction 5 or 10 -> way_d = 2 local way_d = 0 if ( tile_1_d == 5 || tile_1_d == 10 ) { if ( tile_1_d == tile_2_d && tile_2_d == tile_3_d && tile_3_d == tile_4_d && tile_1.z == tile_4.z && tile_1.get_slope() > 0 && tile_4.get_slope() > 0 ) { if ( our_player.get_current_cash() > 1000000 ) { if ( tile_1.z == tile_2.z && tile_2.z == tile_3.z && tile_1.is_bridge() != true ) { build_bridge = 2 build_tile = tile_4 } else if ( tile_1.z < tile_2.z && tile_2.z == tile_3.z ) { build_tunnel = 3 build_tile = tile_4 } } } else if ( tile_1_d == tile_2_d && tile_2_d == tile_3_d && tile_1.z == tile_3.z && tile_1.get_slope() > 0 && tile_3.get_slope() > 0 ) { if ( our_player.get_current_cash() > 500000 ) { if ( tile_1.z == tile_2.z && tile_2.z == tile_3.z && tile_1.is_bridge() != true ) { build_bridge = 2 build_tile = tile_3 } else if ( tile_1.z < tile_2.z ) { build_tunnel = 3 build_tile = tile_3 } } } else if ( tile_1_d == tile_2_d && tile_1.z == tile_2.z && tile_1.get_slope() > 0 && tile_2.get_slope() > 0 && tile_1.is_bridge() != true && tile_2.is_bridge() != true ) { // slope down - slope up -> bridge // slope up - slope down -> terraform down ( build_tunnel = 1 ) if ( (tile_1.get_slope() == 4 && tile_2.get_slope() == 36 && tile_1.y < tile_2.y) || (tile_1.get_slope() == 36 && tile_2.get_slope() == 4 && tile_1.y > tile_2.y) ) { build_tunnel = 1 } else if ( (tile_1.get_slope() == 12 && tile_2.get_slope() == 28 && tile_1.x < tile_2.x) || (tile_1.get_slope() == 28 && tile_2.get_slope() == 12 && tile_1.x > tile_2.x) ) { build_tunnel = 1 } else if ( (tile_1.get_slope() == 4 && tile_2.get_slope() == 36 && tile_1.y > tile_2.y) || (tile_1.get_slope() == 36 && tile_2.get_slope() == 4 && tile_1.y < tile_2.y) ) { build_bridge = 1 } else if ( (tile_1.get_slope() == 12 && tile_2.get_slope() == 28 && tile_1.x > tile_2.x) || (tile_1.get_slope() == 28 && tile_2.get_slope() == 12 && tile_1.x < tile_2.x) ) { build_bridge = 1 } build_tile = tile_2 } // check is way our player local tile_1_pl = tile_1.find_object(mo_way).get_owner().nr //.get_desc() local tile_2_coord = coord3d_to_string(tile_2) // not use for debug local tile_2_pl = tile_2.find_object(mo_way).get_owner().nr //.get_desc() if ( tile_1_pl != our_player_nr || tile_2_pl != our_player_nr ) { continue } if ( (way_d > 0 || build_bridge > 0) && print_message_box > 0 ) { // //gui.add_message_at(our_player, " optimize way way_d " + way_d, tile_1) gui.add_message_at(our_player, " optimize way build_bridge " + build_bridge, tile_1) } } if ( build_bridge > 0 && print_message_box == 1 ) { gui.add_message_at(our_player, " optimize way build_bridge " + build_bridge, tile_1) //::debug.pause() } if ( build_tunnel > 0 && print_message_box == 2 ) { gui.add_message_at(our_player, " optimize way build_tunnel " + build_tunnel, tile_1) //::debug.pause() } // way local way_obj = route[0].find_object(mo_way).get_desc() //way_list[0] if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, way_obj.get_topspeed()) } // catenary local catenary_obj = null if ( tile_1.find_object(mo_wayobj) != null ) { catenary_obj = tile_1.find_object(mo_wayobj).get_desc() if ( catenary_obj != null && !catenary_obj.is_available(world.get_time()) ) { catenary_obj = find_object("catenary", wt, catenary_obj.get_topspeed()) } } // slope up - slope down -> tunnel if ( build_tunnel == 1 ) { local step_ok = true local err = null // not build tunnel -> set slope down local tile_4 = tile_x(route[i-2].x, route[i-2].y, route[i-2].z) tile_4_d = tile_4.get_way_dirs(wt) /*if ( tile_4.find_object(mo_building) != null || tile_4.find_object(mo_bridge) != null ) { //dir.is_single(tile_4_d) local tool = command_x(tool_remover) err = tool.work(our_player, tile_3) if ( err == null ) { err = tool.work(our_player, tile_2) } } else { local tool = command_x(tool_remove_way) local err = tool.work(our_player, tile_3, tile_4, "" + wt) }*/ if ( tile_3.find_object(mo_bridge) == null && tile_4.find_object(mo_bridge) == null && tile_4.find_object(mo_building) == null && tile_3.find_object(mo_building) == null ) { local tool = command_x(tool_remove_way) err = tool.work(our_player, tile_4, tile_3, "" + wt) } else { remove_tile_to_empty(tile_1, wt, 0) remove_tile_to_empty(tile_2, wt, 0) } local way_obj = tile_4.find_object(mo_way).get_desc() if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, speed) } if ( err != null ) { // tile not remove -> restore way err = command_x.build_way(our_player, tile_4, tile_3, way_obj, true) step_ok = false } if ( step_ok ) { err = null // terraform down /*local t = [] t.append(tile_1) t.append(tile_2)*/ if ( check_tiles_for_terraform([tile_1, tile_2]) ) { // tiles left and right free -> terraform grid local cx = 0 local cy = 0 local terraform_tile = null if ( tile_1.y == tile_2.y ) { cy = 1 if ( tile_1.x > tile_2.x ) { terraform_tile = tile_1 } else { terraform_tile = tile_2 } } else if ( tile_1.x == tile_2.x ) { cx = 1 if ( tile_1.y > tile_2.y ) { terraform_tile = tile_1 } else { terraform_tile = tile_2 } } err = command_x.grid_lower(our_player, coord3d(terraform_tile.x, terraform_tile.y, terraform_tile.z)) if ( print_message_box == 4 ) { gui.add_message_at(our_player, " terraform terraform_tile " + coord3d_to_string(terraform_tile) + " : " + err, world.get_time()) } err = null err = command_x.grid_lower(our_player, coord3d(terraform_tile.x+cx, terraform_tile.y+cy, terraform_tile.z)) if ( print_message_box == 4 ) { gui.add_message_at(our_player, " terraform terraform_tile " + coord3d_to_string(tile_x(terraform_tile.x+cx, terraform_tile.y+cy, terraform_tile.z)) + " : " + err, world.get_time()) } } else { // tiles left and right not free -> terraform tile err = command_x.set_slope(our_player, tile_1, 83) err = command_x.set_slope(our_player, tile_2, 83) } // check ground is water after terraform if ( tile_1.is_water() ) { command_x.change_climate_at(our_player, tile_1, cl_temperate) remove_tile_to_empty(tile_2, wt, 0) } if ( tile_2.is_water() ) { command_x.change_climate_at(our_player, tile_2, cl_temperate) remove_tile_to_empty(tile_1, wt, 0) command_x.change_climate_at(our_player, tile_1, cl_temperate) } err = null err = command_x.build_way(our_player, tile_4, tile_3, way_obj, true) if (err != null ) { gui.add_message_at(our_player, " build tunnel " + coord3d_to_string(tile_4) + " - " + coord3d_to_string(tile_3) + ": " + err, world.get_time()) } else { count_build++ } } // restor exist catenary if ( catenary_obj != null ) { command_x.build_wayobj(our_player, tile_4, tile_3, catenary_obj) } } else if ( build_tunnel == 2 ) { err = null // build tunnel - not work tunnel tool script ai //local tile_4 = tile_x(route[i-2].x, route[i-2].y, route[i-2].z) local txt = coord3d_to_string(tile_1) local tool = command_x(tool_remove_way) local err = tool.work(our_player, tile_1, build_tile, "" + wt) err = command_x.build_tunnel_at(our_player, tile_1, tunnel_obj) if (err != null ) { gui.add_message_at(our_player, " build tunnel: " + err, world.get_time()) } else { count_build++ } // restor exist catenary if ( catenary_obj != null ) { command_x.build_wayobj(our_player, tile_1, build_tile, catenary_obj) } } else if ( build_tunnel == 3 ) { // build tunnel - not work tunnel tool script ai /*local tile_4 = tile_x(route[i-2].x, route[i-2].y, route[i-2].z) local txt = coord3d_to_string(tile_1) remove_tile_to_empty(tile_2, wt, 0) local err = command_x.build_tunnel_at(our_player, tile_1, tunnel_obj) if (err != null ) { gui.add_message_at(our_player, " build tunnel: " + err, world.get_time()) } else { count_build++ }*/ } // slope down - slope up -> bridge if ( build_bridge == 1 ) { local err = null local tile_4 = tile_x(route[i-2].x, route[i-2].y, route[i-2].z) //local err = remove_tile_to_empty(tile_2, wt, 0) if ( tile_3.find_object(mo_bridge) == null && tile_4.find_object(mo_bridge) == null && tile_4.find_object(mo_building) == null && tile_3.find_object(mo_building) == null ) { local tool = command_x(tool_remove_way) err = tool.work(our_player, tile_4, tile_3, "" + wt) } else { err = remove_tile_to_empty(tile_1, wt, 0) if ( err ) { err = remove_tile_to_empty(tile_2, wt, 0) } if ( err ) { err = null } else { continue } } if ( print_message_box == 4 && err != null ) { gui.add_message_at(our_player, "#4376# remove tile_1 " + coord3d_to_string(tile_1) + " : " + err, world.get_time()) gui.add_message_at(our_player, "#4376# remove tile_2 " + coord3d_to_string(tile_2) + " : " + err, world.get_time()) //::debug.pause() } if (err == null) { //err = null /*local t = [] t.append(tile_1) t.append(tile_2)*/ if ( check_tiles_for_terraform([tile_1, tile_2]) ) { // tiles left and right free -> terraform grid local cx = 0 local cy = 0 local terraform_tile = null if ( tile_1.y == tile_2.y ) { cy = 1 if ( tile_1.x > tile_2.x ) { terraform_tile = tile_1 } else { terraform_tile = tile_2 } } else if ( tile_1.x == tile_2.x ) { cx = 1 if ( tile_1.y > tile_2.y ) { terraform_tile = tile_1 } else { terraform_tile = tile_2 } } err = command_x.grid_raise(our_player, coord3d(terraform_tile.x, terraform_tile.y, terraform_tile.z)) //::debug.pause() if (err != null ) { if ( print_message_box == 4 ) { gui.add_message_at(our_player, "#4390# terraform fail -> build bridge : " + err, tile_1) ::debug.pause() } err = command_x.build_bridge(our_player, tile_1, build_tile, bridge_obj) } else { //gui.add_message_at(our_player, "#4344# terraform_tile : " + coord3d_to_string(terraform_tile), terraform_tile) err = command_x.grid_raise(our_player, coord3d(terraform_tile.x+cx, terraform_tile.y+cy, terraform_tile.z)) if ( err == null ) { err = command_x.build_way(our_player, tile_4, tile_3, way_obj, true) if (err != null ) { gui.add_message_at(our_player, "#4350# build way " + coord3d_to_string(tile_4) + " - " + coord3d_to_string(tile_3) + ": " + err, world.get_time()) } else { count_build++ } } else { gui.add_message_at(our_player, "#4403# err : " + err, tile_1) } } } else { // tiles left and right not free -> build bridge err = command_x.build_bridge(our_player, tile_1, build_tile, bridge_obj) } } // restor exist catenary if ( catenary_obj != null ) { command_x.build_wayobj(our_player, tile_1, build_tile, catenary_obj) } } else if ( build_bridge == 2 ) { local tool = command_x(tool_remove_way) local err = tool.work(our_player, tile_1, build_tile, "" + wt) //gui.add_message_at(our_player, " remove way: " + err, tile_1) if (err == null) { err = command_x.build_bridge(our_player, tile_1, build_tile, bridge_obj) if (err != null ) { gui.add_message_at(our_player, " build bridge: " + err, tile_1) // restore way err = command_x.build_way(our_player, tile_1, build_tile, way_obj, true) } else { count_build++ } } // restor exist catenary if ( catenary_obj != null ) { command_x.build_wayobj(our_player, tile_1, build_tile, catenary_obj) } } // END :: build bridges and tunnel - 2 to 4 tiles // START :: remove obsolete bridges if ( tile_2.is_bridge() && tile_1.z == tile_2.z && tile_2.get_slope() == 0 ) { local tile_way = tile_2.find_object(mo_bridge) local pl_check = tile_way.get_owner().nr local remove_bridge = 0 local bridge_len = 0 if ( tile_2_d == 5 && pl_check == our_player_nr ) { local t_tile = tile_2 if ( tile_2.y > tile_1.y ) { local check_gr = tile_x(t_tile.x, t_tile.y+1, t_tile.z) for ( local x = 1; route[i].is_bridge(); x++ ) { if ( check_gr.is_ground() && check_gr.is_empty() ) { remove_bridge++ } bridge_len = x i++ check_gr = square_x(route[i].x, route[i].y).get_ground_tile() } } else { local check_gr = tile_x(t_tile.x, t_tile.y-1, t_tile.z) for ( local x = 1; route[i].is_bridge(); x++ ) { if ( check_gr.is_ground() && check_gr.is_empty() ) { remove_bridge++ } bridge_len = x i++ check_gr = square_x(route[i].x, route[i].y).get_ground_tile() } } } else if ( tile_2_d == 10 && pl_check == our_player_nr ) { local t_tile = tile_2 if ( tile_2.x > tile_1.x ) { local check_gr = tile_x(t_tile.x+1, t_tile.y, t_tile.z) for ( local x = 1; route[i].is_bridge(); x++ ) { if ( check_gr.is_ground() && check_gr.is_empty() ) { remove_bridge++ } bridge_len = x i++ check_gr = square_x(route[i].x, route[i].y).get_ground_tile() } } else { local check_gr = tile_x(t_tile.x-1, t_tile.y, t_tile.z) for ( local x = 1; route[i].is_bridge(); x++ ) { if ( check_gr.is_ground() && check_gr.is_empty() ) { remove_bridge++ } bridge_len = x i++ check_gr = square_x(route[i].x, route[i].y).get_ground_tile() } } } if ( bridge_len == 4 && print_message_box == 1 ) { gui.add_message_at(our_player, " test bridge : bridge_len = " + bridge_len + " : remove_bridge = " + remove_bridge, tile_1) gui.add_message_at(our_player, " tile_4 " + coord3d_to_string(tile_4), world.get_time()) gui.add_message_at(our_player, " build_tile " + coord3d_to_string(tile_x(route[i-1].x, route[i-1].y, route[i-1].z)), world.get_time()) ::debug.pause() //sleep() } if ( remove_bridge > 0 && ( (remove_bridge+1) == bridge_len ) && bridge_len > 2 && bridge_len < 5 && pl_check == our_player_nr ) { build_tile = tile_x(route[i-1].x, route[i-1].y, route[i-1].z) if ( tile_2.z == build_tile.z ) { local err = remove_tile_to_empty(tile_2, wt, 0) if (err != null) { gui.add_message_at(our_player, " remove bridge: " + err, tile_1) } if (err) { err = check_ground(tile_2, build_tile, way_obj) build_tile = tile_x(route[i].x, route[i].y, route[i].z) err = command_x.build_way(our_player, tile_1, build_tile, way_obj, true) if (err != null ) { gui.add_message_at(our_player, " not build way: " + err, tile_1) // restore bridge err = command_x.build_bridge(our_player, tile_2, build_tile, bridge_obj) } else { count_build++ } } } else { local err = check_ground(tile_2, build_tile, way_obj) if (!err) { err = command_x.build_way(our_player, tile_1, tile_2, way_obj, true) } else { err = command_x.build_bridge(our_player, tile_2, build_tile, bridge_obj) } } } } // END :: remove obsolete bridges // START :: crossing // replace crossing to road bridge local check_crossing = tile_2.find_object(mo_crossing) if ( check_crossing != null ) { local tile_way = [tile_1.find_object(mo_way), tile_3.find_object(mo_way)] local pl_check = [tile_way[0].get_owner().nr, tile_way[1].get_owner().nr] local build_check = 0 if ( (pl_check[0] == our_player_nr || pl_check[0] == 1) && (pl_check[1] == our_player_nr || pl_check[1] == 1) ) { // no bridge by bridge and tunnel if ( !tile_1.is_bridge() && !tile_3.is_bridge() && !tile_1.is_tunnel() && !tile_3.is_tunnel() ) { build_check = 1 } } if ( wt == wt_road && build_check == 1 && world.get_time().year >= 1935 ) { if ( (tile_1_d == 5 && tile_3_d == 5) || (tile_1_d == 10 && tile_3_d == 10) ) { if ( print_message_box == 3 ) { gui.add_message_at(our_player, " test crossing = " + check_crossing, tile_2) gui.add_message_at(our_player, " find way = " + tile_2.find_object(mo_way), tile_2) gui.add_message_at(our_player, " way name = " + tile_2.find_object(mo_way).get_name() + " cnv count : " + tile_2.find_object(mo_way).get_convoys_passed()[1], tile_2) //gui.add_message_at(our_player, " crossing way = " + check_crossing., tile_2) //::debug.pause() } local cnv_count = tile_2.find_object(mo_way).get_convoys_passed()[1] if ( cnv_count > 100 ) { local tool = command_x(tool_remove_way) local err = tool.work(our_player, tile_1, tile_3, "" + wt) //gui.add_message_at(our_player, " remove way: " + err, tile_1) if (err == null) { err = command_x.build_bridge(our_player, tile_1, tile_3, bridge_obj) if (err != null ) { gui.add_message_at(our_player, " build bridge: " + err, tile_1) } else { count_build++ } } } } } } // END :: crossing } // build stations awst if ( stations_awst != null ) { station_aw(stations_awst, wt, stations_awst_2) } if (count_build > 0 ) { local cs = tile_x(route[route.len()-1].x, route[route.len()-1].y, route[route.len()-1].z)//route[route.len()] local ce = tile_x(route[0].x, route[0].y, route[0].z)//route[0] local cs_coord = coord_to_string(cs) local ce_coord = coord_to_string(ce) local msgtext = format(translate("%s optimize way line from %s (%s) to %s (%s)"), our_player.get_name(), cs.get_halt().get_name(), coord_to_string(cs), ce.get_halt().get_name(), coord_to_string(ce)) gui.add_message_at(our_player, msgtext, cs) return true } else { return false } } /* * check tiles free for terraform * * tiles = array tiles for check tiles left and right is free */ function check_tiles_for_terraform(tiles) { local tiles_free = true local cx = 0 local cy = 0 if ( tiles[0].x == tiles[1].x ) { cx = 1 } else if ( tiles[0].y == tiles[1].y ) { cy = 1 } for ( local x = 0; x < tiles.len(); x++ ) { //gui.add_message_at(our_player, "test_tile_is_empty tiles[x]+ " + test_tile_is_empty(tile_x(tiles[x].x+cx, tiles[x].y+cy, tiles[x].z)), tiles[x]) //gui.add_message_at(our_player, "test_tile_is_empty tiles[x]- " + test_tile_is_empty(tile_x(tiles[x].x-cx, tiles[x].y-cy, tiles[x].z)), world.get_time()) if ( !test_tile_is_empty(tile_x(tiles[x].x+cx, tiles[x].y+cy, tiles[x].z)) || !test_tile_is_empty(tile_x(tiles[x].x-cx, tiles[x].y-cy, tiles[x].z)) ) { tiles_free = false } } return tiles_free } /* * check double ways in new line * waytype: wt_rail * * */ function check_doubleway_in_line(route, wt) { //gui.add_message_at(our_player, " check_doubleway_in_line(route, wt) ", world.get_time()) local treeway_tiles = [] local nexttile = [] local t = 0 // count treeway tile to signal tile foreach(node in route.routes) { local tile = tile_x(node.x, node.y, node.z) nexttile.append(tile) // check route to treeways if ( t > 0 ) { t++ } // treeway if ( dir.is_threeway(tile.get_way_dirs(wt)) ) { treeway_tiles.append(tile) t++ if ( t <= 6 ) { t = 1 } } // test signals by rail if ( tile.find_object(mo_signal) != null && t < 6 ) { // connect in double way gui.add_message_at(our_player, " ## WARNING ## connect in double way ", tile) } else if ( t >= 6 ) { t = 0 } } //::debug.pause() //local asf = astar_route_finder(wt) //wayline = asf.search_route([start_l], [end_l]) } /* * destroy line complete * - destroy convoy * - remove line * check shedule/station connections befor * - destroy stations * - destroy depot by rail/ship * - destroy way line */ function destroy_line(line_obj, good, link_obj) { if ( debug ) ::debug.set_pause_on_error(true) // 1 = messages // 2 = debug.pause() // 3 = line check local print_message_box = 0 if ( print_message_box > 0 ) { gui.add_message_at(our_player, "+ destroy_line(line_obj, good, link) start line " + line_obj.get_name(), world.get_time()) } local line_name = line_obj.get_name() local cnv_list = line_obj.get_convoy_list() local cnv_count = cnv_list.get_count() local wt = line_obj.get_waytype() local cnv = null local depot = null local depot_t = null local start_l = null local end_l = null local start_h = null local end_h = null local nexttile = [] { local entries = line_obj.get_schedule().entries local entries_count = entries.len() if ( wt == wt_water ) { if ( entries.len() >= 2 ) { start_h = entries[0].get_halt(our_player) end_h = entries[entries.len()-1].get_halt(our_player) local t = start_h.get_tile_list() start_l = tile_x(t[0].x, t[0].y, t[0].z) t = end_h.get_tile_list() end_l = tile_x(t[0].x, t[0].y, t[0].z) } } else { if ( entries.len() >= 2 ) { start_l = tile_x(entries[0].x, entries[0].y, entries[0].z) end_l = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) start_h = start_l.get_halt() end_h = end_l.get_halt() } } } if ( print_message_box == 1 ) { gui.add_message_at(our_player, " " + line_obj.get_name(), world.get_time()) } local start_line_count = start_h.get_line_list().get_count() local end_line_count = end_h.get_line_list().get_count() local combined_s = test_halt_waytypes(start_l) local combined_e = test_halt_waytypes(end_l) if ( start_line_count >= 2 && end_line_count >= 2 && combined_s > 1 && combined_e > 1 ) { return false } local start_f = null local end_f = null //if ( wt != wt_water ) { start_f = start_h.get_factory_list() end_f = end_h.get_factory_list() //} if ( start_f.len() > 0 && (print_message_box == 1 || print_message_box == 3) ) { gui.add_message_at(our_player, " factory start " + start_f[0].get_name(), start_l) } else if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, " not connect factory start ", world.get_time()) } if ( end_f.len() > 0 && (print_message_box == 1 || print_message_box == 3) ) { gui.add_message_at(our_player, " factory end " + end_f[0].get_name(), end_l) } else if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, " not connect factory end ", world.get_time()) } local chk_link = 0 if ( start_f.len() > 0 && end_f.len() > 0 ) { chk_link = check_factory_links(start_f[0], end_f[0], good.get_name()) } //gui.add_message_at(our_player, "### check_factory_links(start_f[0], end_f[0], good.get_name()) " + check_factory_links(start_f[0], end_f[0], good.get_name()), world.get_time()) // check links if ( combined_s == 1 && combined_e == 1 && chk_link == 1 ) { local good_list_in = []; local g_count_in = 0 foreach(good, islot in start_f[0].input) { // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() //gui.add_message_at(our_player, "### " + fab.get_name() + " ## " + good + " ## get_storage() " + st[0] + " get_in_transit() " + it[0], world.get_time()) if (st[0] + st[1] + it[0] + it[1] > 0) { // something stored/in-transit in last and current month // no need to search for more supply good_list_in.append({ g = good, t = 1 }) g_count_in++ } else { good_list_in.append({ g = good, t = 0 }) } } if (good_list_in.len() == g_count_in ) { if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, "### last line connect factorys - stored/in-transit all goods > 0 factory start", world.get_time()) } if ( start_f[0].get_suppliers().len() == 0 && end_f[0].get_consumers().len() == 0 ) { if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, "### factory start generator && factory end end-consumers", world.get_time()) } } else { // 12 month no output goods -> line remove local output_count = 0 local list_halts_dest = end_f[0].get_halt_list() // check conected halts if ( list_halts_dest.len() == 1 ) { // one halt remove link if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, "### factory end : count halts = " + list_halts_dest.len(), world.get_time()) } //return true } else { /*foreach(good, islot in end_f[0].output) { // test for in-storage or in-transit goods local st = end_f[0].get_desc().get_outputs() foreach(t in st) { gui.add_message_at(our_player, "### foreach(t in st) - t.keys() " + t.keys(), world.get_time()) local tt = t.keys() for (local i = 0; i < tt.len(); i++) { gui.add_message_at(our_player, "**** keys() - tt["+i+"] " + tt[i], world.get_time()) } tt.clear() tt = t.values() for (local i = 0; i < tt.len(); i++) { if ( i == 2 ) { gui.add_message_at(our_player, "**** values() - tt["+i+"].get_name() " + tt[i].get_name(), world.get_time()) } else { gui.add_message_at(our_player, "**** values() - tt["+i+"] " + tt[i], world.get_time()) } } //output_count += t } }*/ if ( print_message_box == 1 || print_message_box == 3 ) { gui.add_message_at(our_player, "### factory end : count outputs good = " + output_count, world.get_time()) } return false } } } } if (cnv_list.get_count() > 0 ) { foreach(cnv in cnv_list) { if ( depot == null ) { depot = tile_x(cnv.get_home_depot().x, cnv.get_home_depot().y, cnv.get_home_depot().z) if ( print_message_box == 1 ) { gui.add_message_at(our_player, "depot " + coord3d_to_string(depot), world.get_time()) } } // mark convoy for destroying local cnv_trav_month = cnv.get_traveled_distance() local cnv_trav_month_count = 0 for (local i = 0; i < cnv_trav_month.len(); i++ ) { cnv_trav_month_count += cnv_trav_month[i] } if ( print_message_box == 3 ) { gui.add_message_at(our_player, "cnv_trav_month_count " + cnv_trav_month_count, world.get_time()) gui.add_message_at(our_player, "cnv.get_distance_traveled_total() " + cnv.get_distance_traveled_total(), world.get_time()) } if ( cnv.get_distance_traveled_total() < 3 && cnv_trav_month_count == cnv.get_distance_traveled_total() && !cnv.is_loading() && (link_obj != null && check_fsrc_input(link_obj.f_src)) ) { if ( print_message_box == 3 ) { gui.add_message_at(our_player, "return cnv/line new", world.get_time()) } return } if ( wt != wt_water && combined_s > 1 && start_line_count > 1 ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, "return start combined station, more lines ", world.get_time()) } return false } if ( wt == wt_water && combined_e > 1 && end_line_count > 2 ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, "return end combined station, more lines ", world.get_time()) } return false } cnv.destroy(our_player) //::debug.pause() // Prüfen warum next_vehicle_check nicht vorhanden bei Schiffslinien // line_x statt link.line //if ( wt != wt_water ) { line_obj.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 1) //} } // sleep - convoys are destroyed when simulation continues sleep() } // check convoy count cnv_list = line_obj.get_convoy_list() if ( cnv_list.get_count() == 0 ) { //::debug.pause() // destroy line line_obj.destroy(our_player) //industry_manager.access_link(fsrc, fdest, freight).remove_line(c_line) } else { gui.add_message_at(our_player, " --> ERROR not all convoys delete from line ", world.get_time()) return false } sleep() start_line_count = start_h.get_line_list().get_count() end_line_count = end_h.get_line_list().get_count() if ( print_message_box == 1 ) { gui.add_message_at(our_player, " combined station s waytypes = " + combined_s, start_l) gui.add_message_at(our_player, " combined station e waytypes = " + combined_e, end_l) } // check line way local wayline = null local treeways = 0 local double_ways = 0 // way station to next treeway by road local treeway_tile_s = [null, null] local treeway_tile_e = [null, null] // local double_way_tiles = [] if ( wt != wt_water && wt != wt_air ) { //gui.add_message_at(our_player, " search way line ", world.get_time()) local asf = astar_route_finder(wt) wayline = asf.search_route([start_l], [end_l]) local i = 0 // remove depot if ( depot == null ) { depot = search_depot(start_l, wt_road) if ( !depot ) { depot = search_depot(end_l, wt_road) } } if ( depot != false && check_home_depot(depot, wt) ) { // todo check vehicles in depot remove_tile_to_empty(depot, wt, 0) } //depot = search_depot(start_l, wt, 15) if ("err" in wayline) { gui.add_message_at(our_player, "ERROR search way line for remove", world.get_time()) } else { local sig_tile = 0 local t_t = 0 local treeway_tiles = [] foreach(node in wayline.routes) { local tile = tile_x(node.x, node.y, node.z) nexttile.append(tile) // check route to treeways // treeway tile other player, set next tile for remove if ( t_t == 1 ) { treeway_tile_s[1] = tile t_t = 0 } // one treeway ( depot ) then no split line way if ( dir.is_threeway(tile.get_way_dirs(wt)) ) { if ( treeways == 0 ) { treeway_tile_e[0] = tile treeway_tile_s[0] = tile } else { // if ( !(depot == false) && !(depot == null) ) { if ( tile.x == depot.x || tile.y == depot.y ) { depot_t = tile } else { treeway_tile_s[0] = tile } } else { treeway_tile_s[0] = tile } } treeways++ //gui.add_message_at(our_player, " ## treeway_tiles " + coord3d_to_string(tile), tile) treeway_tiles.append(tile) t_t = 1 // test signals by rail if ( sig_tile == 1 && wt == wt_rail ) { double_way_tiles.append(treeway_tiles.top()) sig_tile = 0 } } // treeway tile other player, set next tile for remove if ( treeway_tile_e[0] == null ) { treeway_tile_e[1] = tile } // test signals by rail if ( tile.find_object(mo_signal) != null && wt == wt_rail ) { //double_way_tiles.append(treeway_tile_s[0]) double_way_tiles.append(treeway_tiles.top()) sig_tile = 1 double_ways++ //gui.add_message_at(our_player, " ## treeway_tiles.top() " + coord3d_to_string(treeway_tiles.top()), tile) } /*else if ( dir.is_threeway(tile.get_way_dirs(wt)) && sig_tile == 1 && wt == wt_rail ) { double_way_tiles.append(tile) sig_tile = 0 }*/ } if ( wt == wt_rail && print_message_box > 0 ) { gui.add_message_at(our_player, " double_ways " + double_ways, world.get_time()) gui.add_message_at(our_player, " double_way_tiles.get_count() " + double_way_tiles.len(), world.get_time()) } } } // world.get_convoy_list() if ( wt == wt_rail ) { local remove_all = 0 if ( print_message_box == 1 ) { gui.add_message_at(our_player, " remove wt_rail line ", world.get_time()) } // remove combined station ( rail - water ) on start local tool = command_x(tool_remove_way) if ( start_line_count < 2 ) { // remove combined waytype halt water - not rail if ( combined_s > 1 ) { local t = start_h.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { local k = t[i].find_object(mo_building).get_desc().get_waytype() if ( print_message_box == 1 ) { gui.add_message_at(our_player, " station tile " + i + " waytype " + k, world.get_time()) } if ( k == wt_water ) { local tool = command_x(tool_remover) //tool.work(our_player, t[i]) // to do ship line destroy combined_s = 1 start_line_count = 0 break } } } if ( treeways == 0 && combined_s == 1 && combined_e == 1 && start_line_count == 0 && end_line_count == 0 ) { // remove all remove_all = 1 } /* // remove depot if ( check_home_depot(depot, wt) ) { remove_tile_to_empty(depot, wt, 0) } */ if ( print_message_box > 0 ) { gui.add_message_at(our_player, " treeways " + treeways + " combined_s " + combined_s + " combined_e " + combined_e, world.get_time()) gui.add_message_at(our_player, " start_line_count " + start_line_count + " end_line_count " + end_line_count + " remove_all " + remove_all, world.get_time()) gui.add_message_at(our_player, " double_ways " + double_ways, world.get_time()) //::debug.pause() } local cnv_count_start = start_l.get_way(wt_rail).get_convoys_passed()[0] + start_l.get_way(wt_rail).get_convoys_passed()[1] local cnv_count_end = end_l.get_way(wt_rail).get_convoys_passed()[0] + end_l.get_way(wt_rail).get_convoys_passed()[1] // remove way from start to first treeway if ( treeways > 1 && combined_s == 1 && combined_e == 1 && start_line_count == 0 && remove_all == 0 ) { // remove station and way to next treeway if ( print_message_box == 1 ) { gui.add_message_at(our_player, "treeway_tile_s[0] " + coord3d_to_string(treeway_tile_s[0]), treeway_tile_s[0]) } local err = tool.work(our_player, start_l, treeway_tile_s[0], "" + wt_rail) if ( err != null ) { gui.add_message_at(our_player, " ## ERROR remove way start_l" + coord3d_to_string(start_l), start_l) } //remove_tile_to_empty(depot, wt, 0) //remove_tile_to_empty(depot_t, wt, 0) } // remove way from end to first treeway if ( treeways > 1 && combined_s == 1 && combined_e == 1 && end_line_count == 0 && remove_all == 0 ) { // remove station and way to next treeway if ( print_message_box == 1 ) { gui.add_message_at(our_player, "treeway_tile_e[0] " + coord3d_to_string(treeway_tile_e[0]), treeway_tile_e[0]) } local err = tool.work(our_player, end_l, treeway_tile_e[0], "" + wt_rail) if ( err != null ) { gui.add_message_at(our_player, " ## ERROR remove way end_l" + coord3d_to_string(end_l), start_l) } } // remove double ways by rail if ( double_ways > 0 ) { local j = 0; local c = 0 if ( double_ways > 4 ) { c = 1 } for ( local i = 0; i < double_ways; i++ ) { // remove double way // local cnv_count = t_field.get_convoys_passed()[0] + t_field.get_convoys_passed()[1] local cnv_count_0 = double_way_tiles[j].get_way(wt_rail).get_convoys_passed()[0] + double_way_tiles[j].get_way(wt_rail).get_convoys_passed()[1] local cnv_count_1 = double_way_tiles[j+1].get_way(wt_rail).get_convoys_passed()[0] + double_way_tiles[j+1].get_way(wt_rail).get_convoys_passed()[1] if ( print_message_box > 0 ) { gui.add_message_at(our_player, " double_way_tiles[j] " + coord3d_to_string(double_way_tiles[j]) + " double_way_tiles[j+1] " + coord3d_to_string(double_way_tiles[j+1]), double_way_tiles[j]) gui.add_message_at(our_player, " j " + j, double_way_tiles[j+1]) gui.add_message_at(our_player, " cnv_count_0 " + cnv_count_0 + " cnv_count_1 " + cnv_count_1 + " cnv_count_start " + cnv_count_start + " cnv_count_end " + cnv_count_end, double_way_tiles[i]) //::debug.pause() } if ( cnv_count_0 == cnv_count_1 && (cnv_count_0 <= (cnv_count_start + c) || cnv_count_0 <= (cnv_count_end + c)) ) { tool.work(our_player, double_way_tiles[j], double_way_tiles[j+1], "" + wt_rail) tool.work(our_player, double_way_tiles[j+1], double_way_tiles[j], "" + wt_rail) if ( i < (double_ways-1) ) { // remove single way to next double way tool.work(our_player, double_way_tiles[j+1], double_way_tiles[j+2], "" + wt_rail) //::debug.pause() } } else if ( !dir.is_threeway(double_way_tiles[j].get_way_dirs(wt)) && !dir.is_threeway(double_way_tiles[j+1].get_way_dirs(wt)) ) { tool.work(our_player, double_way_tiles[j], double_way_tiles[j+1], "" + wt_rail) tool.work(our_player, double_way_tiles[j+1], double_way_tiles[j], "" + wt_rail) } j += 2; } } } if ( start_f.len() > 0 && combined_s > 1 && start_line_count > 0 ) { // check lines befor remove start local lines = start_h.get_line_list() local i = 1 foreach(line in lines) { if ( line.get_waytype() == wt_rail ) { i++ } } remove_all = i } if ( end_f.len() > 0 && combined_e > 1 && end_line_count > 0 ) { // check lines befor remove end local lines = end_h.get_line_list() local i = 1 foreach(line in lines) { if ( line.get_waytype() == wt_rail ) { i++ } } remove_all = i } // remove rail line way by single halt and no more treeways if ( remove_all == 1 ) { // remove line way if ( print_message_box == 1 ) { gui.add_message_at(our_player, " remove_all == 1 ", world.get_time()) } local tool = command_x(tool_remove_way) if ( start_l.is_empty() || end_l.is_empty() ) { local c1 = 0 local c2 = 0 for ( local i = 0; i > 10; i++ ) { if ( !nexttile[nexttile.len-i].is_empty() ) { start_l = nexttile[nexttile.len-i] c1++ } if ( !nexttile[i].is_empty() ) { end_l = nexttile[i] c2++ } if ( (c1+c2) == 2 ) { break } } } local t = start_l.get_halt().get_tile_list() tool.work(our_player, start_l, end_l, "" + wt_rail) // remove all tiles from halt start for ( local i = 0; i < t.len(); i++ ) { if ( t[i].find_object(mo_building) ) { t[i].remove_object(our_player, mo_building) } } } //::debug.pause() } // remove road line if ( wt == wt_road ) { // remove depot not other road stations in range // to do check other stations /*if ( check_home_depot(depot, wt) ) { remove_tile_to_empty(depot, wt, 0) }*/ // remove way line and station by 0 lines connected start_line_count = start_h.get_line_list().get_count() end_line_count = end_h.get_line_list().get_count() if ( print_message_box == 1 ) { gui.add_message_at(our_player, " treeway_tile_s " + treeway_tile_s[0] + " " + treeway_tile_s[1], world.get_time()) gui.add_message_at(our_player, " treeway_tile_e " + treeway_tile_e[0] + " " + treeway_tile_e[1], world.get_time()) } local tool = command_x(tool_remove_way) if ( start_line_count == 0 ) { // remove combined waytype halt water - not road if ( combined_s > 1 ) { local t = start_h.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { local k = t[i].find_object(mo_building).get_desc().get_waytype() if ( k == wt_water ) { local tool = command_x(tool_remover) tool.work(our_player, t[i]) break } } } // remove station and way to next treeway // treeway tile check player if ( treeway_tile_s[0] != null && treeway_tile_s[0].find_object(mo_way).get_owner() == our_player ) { tool.work(our_player, start_l, treeway_tile_s[0], "" + wt_road) } else if ( treeway_tile_s[1] != null && treeways > 0 ) { tool.work(our_player, start_l, treeway_tile_s[1], "" + wt_road) remove_tile_to_empty(treeway_tile_s[1], wt_road, 0) } } if ( end_line_count == 0 ) { // remove combined waytype halt water - not road if ( combined_e > 1 ) { local t = end_h.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { local k = t[i].find_object(mo_building).get_desc().get_waytype() if ( k == wt_water ) { local tool = command_x(tool_remover) tool.work(our_player, t[i]) //break } } } // remove station and way to next treeway // treeway tile check player if ( treeway_tile_e[0] != null && treeway_tile_e[0].find_object(mo_way).get_owner() == our_player ) { tool.work(our_player, end_l, treeway_tile_e[0], "" + wt_road) } else if ( treeway_tile_e[1] != null && treeways > 0 ) { tool.work(our_player, end_l, treeway_tile_e[1], "" + wt_road) remove_tile_to_empty(treeway_tile_e[1], wt_road, 0) } } if ( treeways == 0 ) { tool.work(our_player, end_l, start_l, "" + wt_road) } } // remove water line if ( wt == wt_water ) { local tool = command_x(tool_remover) // remove depot if ( check_home_depot(depot, wt) ) { local err = depot.remove_object(our_player, mo_depot_rail) if ( err != null ) { gui.add_message_at(our_player, "## ERROR depot remove " + depot + ": " + err, home_depot) } //tool.work(our_player, depot) } // remove way line and station by 0 lines connected start_line_count = start_h.get_line_list().get_count() end_line_count = end_h.get_line_list().get_count() if ( start_line_count <= 1 ) { // remove combined waytype halt water - not road/rail if ( combined_s >= 1 && combined_e == 1 ) { local t = start_h.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { if ( t[i].find_object(mo_building) != null ) { local k = t[i].find_object(mo_building).get_desc().get_waytype() if ( k == wt_water ) { tool.work(our_player, t[i]) //break } /*else if ( k == wt_rail ) { tool.work(our_player, t[i]) }*/ } } //t = start_h.get_tile_list() //tool.work(our_player, t[0]) } } if ( end_line_count <= 1 ) { // remove combined waytype halt water - not road/rail if ( combined_e <= 2 ) { local t = end_h.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { if ( t[i].find_object(mo_building) != null ) { local k = t[i].find_object(mo_building).get_desc().get_waytype() if ( k == wt_water ) { tool.work(our_player, t[i]) /* break } else if ( k == wt_rail ) { tool.work(our_player, t[i])*/ } } } } } } if ( print_message_box > 0 ) { gui.add_message_at(our_player, "+ destroy_line(line_obj, good, link) finish line " + line_name, world.get_time()) //::debug.pause() } local msgtext = format(translate("%s removes line: %s"), our_player.get_name(), line_name) gui.add_message_at(our_player, msgtext, world.get_time()) //link_obj.status = 4 //link_obj.next_check = today_plus_months(36) check_stations_connections() return true } /* * check waytypes from halt * tile = one tile from halt * return count waytypes */ function test_halt_waytypes(tile) { if ( tile.is_water() && tile.find_object(mo_building) == null ) { //gui.add_message_at(our_player, "halt is water tile " + coord3d_to_string(tile), tile) return 0 } local halt_tiles = tile.get_halt().get_tile_list() //gui.add_message_at(our_player, "halt has tiles " + halt_tiles.len(), tile) local test_rail = 0 local test_road = 0 local test_water = 0 for ( local i = 0; i < halt_tiles.len(); i++ ) { local building = halt_tiles[i].find_object(mo_building).get_desc() if ( building ) { switch (building.get_waytype()) { case wt_rail: test_rail++ break case wt_road: test_road++ break case wt_water: test_water++ break } } } local test_way = 0 if ( test_rail > 0 ) { test_way++ } if ( test_road > 0 ) { test_way++ } if ( test_water > 0 ) { test_way++ } return test_way } /* * check depot as home for other vehicles * tile = depot coord * wt = waytype * * return: true = no vehicles; false = other vehicles */ function check_home_depot(tile, wt) { // load vehicle list local list = world.get_convoy_list() foreach(cnv in list) { if ( tile.x == cnv.get_home_depot().x && tile.y == cnv.get_home_depot().y && tile.z == cnv.get_home_depot().z ) { return false } } return true } /* * check stations to valid link * * * * */ function check_stations_connections() { //gui.add_message_at(our_player, "####### check_stations_connections()" , world.get_time()) if ( debug ) ::debug.set_pause_on_error(true) local haltlist = [] // list player halts foreach(halt in halt_list_x()) { if (halt.get_owner().nr == our_player_nr) { // && halt.get_type == wt haltlist.append(halt) } } // halt no lines and convoys local halt_unused = [] // test factory connection foreach(halt in haltlist) { local s = halt.get_name() local halt_factory_connect = halt.get_factory_list().len() local halt_lines = halt.get_line_list() local halt_line = null local halt_cnv = halt.get_convoy_list() //if ( halt_lines.get_count() == 1 ) { gui.add_message_at(our_player, "####### halt_lines[0]: " + halt_lines[0].get_name(), world.get_time()) } //local tool = command_x(tool_remover) if ( halt_lines.get_count() == 0 && halt_cnv.get_count() == 0 ) { //gui.add_message_at(our_player, "####### halt name: " + halt.get_name(), world.get_time()) // halt no lines and convoys - remove local t = halt.get_tile_list() for ( local i = 0; i < t.len(); i++ ) { if ( t[i].has_way(wt_rail) ) { // remove way by wt_rail from halt tiles gui.add_message_at(our_player, "####### remove rail halt : " + halt.get_name(), t[i]) remove_tile_to_empty(t, wt_rail, 1) } else { //gui.add_message_at(our_player, "####### remove building halt name: " + halt.get_name(), t[i]) t[i].remove_object(our_player, mo_building) } } } else if ( halt_factory_connect == 0 && halt_lines.get_count() < 2 ) { local line_list = player_x(our_player.nr).get_line_list() foreach(line in line_list) { //gui.add_message_at(player_x(our_player.nr), "####### line check " + line.get_name(), world.get_time()) if ( halt_lines[0].id == line.id ) { halt_line = line break } } //gui.add_message_at(our_player, "####### halt name: " + halt.get_name(), world.get_time()) local home_depot = null local wt = null local good = null // combined station not finish if ( halt_cnv.get_count() > 0 ) { // remove convoys from halt local j = halt_cnv.get_count() home_depot = halt_cnv[0].get_home_depot() wt = halt_cnv[0].get_waytype() for ( local i = 0; i < j; i++ ) { halt_cnv[i].destroy(our_player) } } else if ( halt.get_line_list().get_count() == 1 ) { local link_list = industry_manager.link_list local search_line = null foreach(link in link_list) { // start_f[0], end_f[0], good.get_name() foreach(index, line in link.lines) { //gui.add_message_at(player_x(our_player.nr), "####### line check " + line.get_name(), world.get_time()) if ( line.is_valid() && line.get_owner().nr == our_player.nr && halt_line.get_name() == line.get_name() ) { search_line = line } } } if ( search_line != null ) { destroy_line(search_line, good, null) //halt_line } break } } } } function check_combined_station(halt) { local lines = halt.get_line_list() local factorys = halt.get_factory_list() local halt_tiles = halt.get_tile_list() local wts = test_halt_waytypes(halt_tiles[0]) if ( wts > 1 && lines.get_count() == 1 && factorys.len() > 0 ) { gui.add_message_at(our_player, "####### station more wt and one line - factory connect ", world.get_time()) local wt = null foreach(line in lines) { wt = line.get_waytype() } local replace_tiles = [] for ( local i = 0; i < halt_tiles.len(); i++ ) { local building = halt_tiles[i].find_object(mo_building).get_desc() if ( building ) { if ( building.get_waytype() != wt ) { replace_tiles.append(halt_tiles[i]) } } } local extension = find_extension(wt_road) if ( extension != null ) { for ( local i = 0; i < replace_tiles.len()-1; i++ ) { remove_tile_to_empty(replace_tiles[i], wt_road, 0) command_x.build_station(our_player, replace_tiles[i], extension) } } } } function station_aw(start_field, wt, awst_array) { local print_message_box = 0 local b_player = our_player //gui.add_message_at(b_player, "station_aw ", start_field) local way_obj = start_field.find_object(mo_way).get_desc() //way_list[0] if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, way_obj.get_topspeed()) } local way_len = 8 local d = start_field.get_way_dirs(wt) local tiles = [] local tiles_build_l = [] local tiles_build_r = [] for (local i = 0; i < way_len; i++) { if ( d == 5 ) { // build from n to s // ns - r local ref_ground = square_x(start_field.x, start_field.y + i).get_ground_tile() local t = tile_x(start_field.x + 1, start_field.y + i, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x, start_field.y + i).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(start_field.x + 1, start_field.y + i, ref_ground.z)) } // ns - l t = tile_x(start_field.x - 1, start_field.y + i, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x, start_field.y + i).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(start_field.x - 1, start_field.y + i, ref_ground.z)) } tiles.append(ref_ground) } else if ( d == 10 ) { //gui.add_message_at(our_player, "tile r " + coord3d_to_string(tile_x(start_field.x + i, start_field.y + 1, start_field.z)) + " empty " + tile_x(start_field.x + i, start_field.y + 1, start_field.z).is_empty(), start_field) //gui.add_message_at(our_player, " -- tile l " + coord3d_to_string(tile_x(start_field.x + i, start_field.y - 1, start_field.z)) + " to empty " + tile_x(start_field.x - i, start_field.y + 1, start_field.z).is_empty(), start_field) // ew - r // build from w to e local ref_ground = square_x(start_field.x + i, start_field.y).get_ground_tile() local t = tile_x(start_field.x + i, start_field.y + 1, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x + i, start_field.y).get_ground_tile().z == ref_ground.z tiles_build_r.append(tile_x(start_field.x + i, start_field.y + 1, ref_ground.z)) } // ew - l t = tile_x(start_field.x + i, start_field.y - 1, start_field.z) if ( t.is_valid() && test_tile_is_empty(t) ) { //&& square_x(start_field.x + i, start_field.y).get_ground_tile().z == ref_ground.z tiles_build_l.append(tile_x(start_field.x + i, start_field.y - 1, ref_ground.z)) } tiles.append(ref_ground) } } local tl = 0 local tr = 0 local tiles_build = null //way_len -= 1 if ( tiles_build_r.len() == way_len || tiles_build_l.len() == way_len ) { if ( tiles_build_r.len() == way_len ) { for ( local i = 0; i < way_len; i++ ) { if ( tiles_build_r[i].get_slope() == 0 ) { tr++ } } } if ( tiles_build_l.len() == way_len ) { for ( local i = 0; i < way_len; i++ ) { if ( tiles_build_l[i].get_slope() == 0 ) { tl++ } } } local err = null local terraform = 0 if ( tr == way_len ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build flat right ", start_field) } tiles_build = tiles_build_r tr = way_len tl = 0 } else if ( tl == way_len ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build flat left ", start_field) } tiles_build = tiles_build_l tl = way_len tr = 0 } else if ( ( tr < tiles_build_r.len() && tiles_build_r.len() == way_len ) && tr >= tl ) { // check terraform tr if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build right check terraform", world.get_time()) } tiles_build = tiles_build_r tr = way_len tl = 0 terraform = 1 } else if ( tl < tiles_build_l.len() && tiles_build_l.len() == way_len ) { // check terraform tl if ( print_message_box == 1 ) { gui.add_message_at(b_player, "build left check terraform", world.get_time()) } tiles_build = tiles_build_l tl = way_len tr = 0 terraform = 1 } if ( terraform == 1 ) { // change terraform local g = terraform_way(tiles, tiles_build, tr, tl, way_len, d) tr = g[0] tl = g[1] if ( way_len > g[2] ) { tiles_build.remove(tiles_build.len()-1) tiles.remove(tiles.len()-1) } /* if ( tr == way_len ) { tr-- } if ( tl == way_len ) { tl-- } way_len-- */ } // set build left or right /*if ( tr == way_len && tl == way_len ) { } else */ if ( tr == way_len ) { tiles_build = tiles_build_r } else if ( tl == way_len ) { tiles_build = tiles_build_l } if ( tiles_build == null ) { //gui.add_message_at(b_player, " ERROR no double way found " + coord3d_to_string(tiles[0]), start_field) return false } // build way local err = null if ( start_field.get_way_dirs(wt) == 5 || start_field.get_way_dirs(wt) == 10 ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, "5/10 build tiles[0] " + coord3d_to_string(tiles[0]) + " to tiles_build[0] " + coord3d_to_string(tiles_build[0]), start_field) } // connect diagonal way local b_tile = null local tile_a = null local tile_b = null local tile_check = 0 if ( tl == way_len ) { if ( start_field.get_way_dirs(wt) == 5 ) { tile_a = tile_x(tiles[0].x, tiles[0].y-1, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y-1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 12 && (tile_b.get_way_dirs(wt) == 3 || (tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 1 //gui.add_message_at(b_player, "(2765) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( start_field.get_way_dirs(wt) == 10 ) { tile_a = tile_x(tiles[0].x-1, tiles[0].y, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y-1, tiles[0].z) if ( (tile_a.get_way_dirs(wt) == 12 || tile_a.get_way_dirs(wt) == 3) && (tile_b.get_way_dirs(wt) == 3 || tile_b.get_way_dirs(wt) == 12 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 2 //gui.add_message_at(b_player, "(2773) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } } else if ( tr == way_len ) { if ( start_field.get_way_dirs(wt) == 5 ) { tile_a = tile_x(tiles[0].x, tiles[0].y-1, tiles[0].z) tile_b = tile_x(tiles[0].x+1, tiles[0].y-1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || (tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 3 //gui.add_message_at(b_player, "(2785) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( start_field.get_way_dirs(wt) == 10 ) { tile_a = tile_x(tiles[0].x-1, tiles[0].y, tiles[0].z) tile_b = tile_x(tiles[0].x-1, tiles[0].y+1, tiles[0].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } tile_check = 4 //gui.add_message_at(b_player, "(2795) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } } if ( b_tile == null ) { err = command_x.build_way(b_player, tiles[0], tiles_build[0], way_obj, true) } else { err = command_x.build_way(b_player, b_tile, tiles_build[0], way_obj, true) } if ( err == null ) { if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[0] " + coord3d_to_string(tiles_build[0]) + " to tiles_build[" + (way_len - 1) + "] " + coord3d_to_string(tiles_build[way_len - 1]), start_field) } err = command_x.build_way(b_player, tiles_build[0], tiles_build[way_len - 1], way_obj, true) if ( err != null ) { gui.add_message_at(b_player, " ERROR => build tile " + coord3d_to_string(tiles[0]) + " to tile " + coord3d_to_string(tiles_build[way_len - 1]), tiles[0]) err = null } if ( print_message_box == 1 ) { gui.add_message_at(b_player, " build tiles_build[" + (way_len - 1) + "] " + coord3d_to_string(tiles_build[way_len - 1]) + " to tiles[" + (way_len - 1) + "] " + coord3d_to_string(tiles[way_len - 1]), start_field) } // connect diagonal way b_tile = null if ( tile_check == 1 ) { tile_a = tile_x(tiles[way_len - 1].x, tiles[way_len - 1].y+1, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x-1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 9 && (tile_b.get_way_dirs(wt) == 6 || tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0) ) { b_tile = tile_b } //gui.add_message_at(b_player, "(2827) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 2 ) { tile_a = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y-1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 6 && (tile_b.get_way_dirs(wt) == 9 || tile_b.get_way_dirs(wt) == 10 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0) ) { b_tile = tile_b } //gui.add_message_at(b_player, "(2836) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 3 ) { tile_a = tile_x(tiles[way_len - 1].x, tiles[way_len - 1].y+1, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 3 && (tile_b.get_way_dirs(wt) == 12 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } //gui.add_message_at(b_player, "(2844) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } else if ( tile_check == 4 ) { tile_a = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y, tiles[way_len - 1].z) tile_b = tile_x(tiles[way_len - 1].x+1, tiles[way_len - 1].y+1, tiles[way_len - 1].z) if ( tile_a.get_way_dirs(wt) == 12 && (tile_b.get_way_dirs(wt) == 3 || (tile_b.get_way_dirs(wt) == 5 && !tile_b.is_bridge() && !tile_b.is_tunnel() && tile_b.get_slope() == 0)) ) { b_tile = tile_b } //gui.add_message_at(b_player, "(2853) tile_a " + coord3d_to_string(tile_a) + " tile_b " + coord3d_to_string(tile_b), start_field) } if ( b_tile == null ) { err = command_x.build_way(b_player, tiles_build[way_len - 1], tiles[way_len - 1], way_obj, true) } else { err = command_x.build_way(b_player, tiles_build[way_len - 1], b_tile, way_obj, true) } local staw = [] for ( local j = 0; j < tiles.len(); j++ ) { if ( tiles[j].find_object(mo_building) == null && ( tiles[j].get_way_dirs(wt) == 5 || tiles[j].get_way_dirs(wt) == 10 ) ) { staw.append(tiles[j]) } } remove_tile_to_empty(staw, wt, 1) } } } /* if ( tiles[0].x == tiles[1].x && tiles[0].y < tiles[1].y ) { // N -> S } else if ( tiles[0].x < tiles[1].x && tiles[0].y == tiles[1].y ) { // W -> E } */ //err = command_x.build_way(b_player, tiles_build[way_len - 1], tiles[way_len - 1], way_obj, true) //tiles_build[way_len - 1] // awst_array //gui.add_message_at(b_player, "(6663) tr " + tr + " tl " + tl, start_field) // Ausweichstelle nach Station if ( tl == way_len ) { //gui.add_message_at(b_player, "(6664) ", awst_array[0]) if ( awst_array[0].x == awst_array[awst_array.len()-1].x || awst_array[0].y == awst_array[awst_array.len()-1].y ) { local tile_c = tile_x(awst_array[0].x, awst_array[0].y-1, awst_array[0].z) //gui.add_message_at(b_player, "(6667) ", tile_c) local err = command_x.build_way(b_player, awst_array[0], tile_c, way_obj, true) gui.add_message_at(b_player, "(6088) err " + err, awst_array[0]) if ( err != null ) { remove_tile_to_empty(awst_array, wt_rail, 1) } else { err = command_x.build_way(b_player, tile_c, tiles_build[0], way_obj, true) gui.add_message_at(b_player, "(6093) err " + err, tiles_build[0]) if ( err != null ) { remove_tile_to_empty(awst_array, wt_rail, 1) } else { local obj_sign = find_signal("is_signal", wt) local signal = null local s_tile = tile_x(awst_array[1].x,awst_array[1].y-1, awst_array[1].z) if ( s_tile.get_way_dirs(wt) == 10 ) { // ew signal = [{coor=coord3d(awst_array[1].x,awst_array[1].y-1, awst_array[1].z), ribi=8}, {coor=coord3d(awst_array[awst_array.len()-2].x, awst_array[awst_array.len()-2].y, awst_array[awst_array.len()-2].z), ribi=2}] } else if ( s_tile.get_way_dirs(wt) == 5 ) { // ns signal = [{coor=coord3d(awst_array[1].x,awst_array[1].y-1, awst_array[1].z), ribi=1}, {coor=coord3d(awst_array[awst_array.len()-2].x, awst_array[awst_array.len()-2].y, awst_array[awst_array.len()-2].z), ribi=4}] } for ( local j=0; j < 2; j++ ) { local s_ribi = signal[j].ribi local signal_build_tile = tile_x(signal[j].coor.x, signal[j].coor.y, signal[j].coor.z) gui.add_message_at(b_player, "(6103) signal_build_tile " + coord3d_to_string(signal_build_tile), signal_build_tile) while(true){ err = command_x.build_sign_at(b_player, signal_build_tile, obj_sign) if ( err != null ) { break } local ribi = signal_build_tile.get_way_dirs_masked(wt) if (ribi == s_ribi) break } } if ( err != null ) { remove_tile_to_empty(awst_array, wt_rail, 1) } } } } } } function terraform_way(tiles, tiles_build, tr, tl, way_len, d) { local err = null local b_player = our_player // 21 message slope local print_message_box = 0 if ( print_message_box > 0 ) { gui.add_message_at(b_player, " ---=> terraform_way() ", world.get_time()) } for ( local i = 0; i < tiles_build.len(); i++ ) { //local r = square_x(tiles_build[i].x, tiles_build[i].y) local z = 0 //local f = tile_x(tiles_build[i].x, tiles_build[i].y, z.z) local build_hight = square_x(tiles_build[i].x, tiles_build[i].y).get_ground_tile() local ref_hight = square_x(tiles[i].x, tiles[i].y).get_ground_tile() local straight_slope = false if ( ref_hight.get_slope() == 4 || ref_hight.get_slope() == 12 || ref_hight.get_slope() == 28 || ref_hight.get_slope() == 36 ) { // single hight && double hight 1 straight_slope = true } else if ( ref_hight.get_slope() == 8 || ref_hight.get_slope() == 24 || ref_hight.get_slope() == 56 || ref_hight.get_slope() == 72 ) { // double hight 2 straight_slope = true } if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> tiles[i] ground " + coord3d_to_string(ref_hight), ref_hight) gui.add_message_at(b_player, " ---=> tiles_build[i] ground " + coord3d_to_string(build_hight), build_hight) gui.add_message_at(b_player, " ---=> ref_hight.get_slope() " + ref_hight.get_slope(), world.get_time()) gui.add_message_at(b_player, " ---=> straight_slope " + straight_slope, world.get_time()) } if ( build_hight.get_slope() == ref_hight.get_slope() ) { // slope ref_tile == slope build_tile -> not terraform if ( print_message_box == 21 ) { gui.add_message_at(b_player, " slope ref_tile == slope build_tile -> not terraform ", build_hight) } } else if ( build_hight.is_empty() && ( build_hight.get_slope() > 0 || ref_hight.z != build_hight.z ) ) { if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> terraform", world.get_time()) gui.add_message_at(b_player, " ---=> tiles_build.z " + build_hight.z + " tiles.z " + ref_hight.z, world.get_time()) } if ( (build_hight.z < ref_hight.z && build_hight.z >= (ref_hight.z - 2)) ) { //|| straight_slope == true // terraform up if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> terraform up ", world.get_time()) } local terraform_tile = 1 // terraform grid up if ( print_message_box == 21 ) { gui.add_message_at(b_player, " build_hight.get_slope() " + build_hight.get_slope(), build_hight) } local tile_build_slope = [37, 9, 31, 1, 3] if ( tile_build_slope.find(build_hight.get_slope()) != null ) { local cx = 0 local cy = 0 local build_side = 0 if ( d == 10 ) { cx = 1 if ( tiles_build[i].y > tiles[i].y ) { build_side = 1 } } else if ( d == 5 ) { cy = 1 if ( tiles_build[i].x > tiles[i].x ) { build_side = 1 } } local tile_a = square_x(tiles_build[i].x+cx, tiles_build[i].y+cy).get_ground_tile() local tile_a1 = null local tile_b1 = null if ( build_side == 1 ) { tile_a1 = square_x(tiles_build[i].x+cy, tiles_build[i].y+cx).get_ground_tile() tile_b1 = square_x(tile_a.x+cy, tile_a.y+cx).get_ground_tile() } else { tile_a1 = square_x(tiles_build[i].x-cy, tiles_build[i].y-cx).get_ground_tile() tile_b1 = square_x(tile_a.x-cy, tile_a.y-cx).get_ground_tile() } if ( print_message_box == 21 ) { gui.add_message_at(b_player, " tile_a.get_slope() " + tile_a.get_slope(), tile_a) gui.add_message_at(b_player, " tile_a1.get_slope() " + tile_a1.get_slope(), tile_a1) gui.add_message_at(b_player, " tile_b1.get_slope() " + tile_b1.get_slope(), tile_b1) } local tile_a_slope = [27, 36, 31, 1] if ( build_hight.get_slope() == 37 && tile_a_slope.find(tile_a.get_slope()) != null && test_tile_is_empty(tile_a1) && test_tile_is_empty(tile_b1) ) { err = command_x.grid_raise(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) if ( err == null ) { terraform_tile = 0 } } else if ( (build_hight.get_slope() == 31 || build_hight.get_slope() == 3) && (tile_a.get_slope() == 4 || tile_a.get_slope() == 13 || tile_a.get_slope() == 1) ) { local tile_a1 = null local tile_b1 = null if ( build_side == 1 ) { tile_a1 = square_x(tiles_build[i].x+cy, tiles_build[i].y+cx).get_ground_tile() tile_b1 = square_x(tile_a.x+cy, tile_a.y+cx).get_ground_tile() } else { tile_a1 = square_x(tiles_build[i].x-cy, tiles_build[i].y-cx).get_ground_tile() tile_b1 = square_x(tile_a.x-cy, tile_a.y-cx).get_ground_tile() } //tile_a1 = square_x(tiles_build[i].x, tiles_build[i].y-1).get_ground_tile() //tile_b1 = square_x(tile_a.x, tile_a.y-1).get_ground_tile() if ( test_tile_is_empty(tile_a1) && test_tile_is_empty(tile_b1) ) { err = command_x.grid_raise(our_player, coord3d(tile_a.x, tile_a.y, tile_a.z)) terraform_tile = 0 } } } // terraform tile if ( terraform_tile == 1 ) { do { err = command_x.set_slope(b_player, build_hight, 82 ) if ( err != null ) { break } z = square_x(tiles_build[i].x, tiles_build[i].y).get_ground_tile() } while(z.z < ref_hight.z ) } } else if ( build_hight.z >= ref_hight.z || build_hight.z <= (ref_hight.z + 1) ) { // terraform down if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> terraform down ", world.get_time()) } if ( (i == 0 && tiles[0].get_slope() > 0 ) || ( i == (way_len-1) && tiles[way_len-1].get_slope() > 0 ) ) { } else { local terraform_tile = 1 // terraform grid down if ( print_message_box == 21 ) { gui.add_message_at(b_player, " build_hight.get_slope() " + build_hight.get_slope(), build_hight) } local tile_build_slope = [3, 1, 9, 37, 39] if ( tile_build_slope.find(build_hight.get_slope()) != null ) { local cx = 0 local cy = 0 local build_side = 0 if ( d == 10 ) { cx = 1 if ( tiles_build[i].y > tiles[i].y ) { build_side = 1 } } else if ( d == 5 ) { cy = 1 if ( tiles_build[i].x > tiles[i].x ) { build_side = 1 } } local tile_a = square_x(tiles_build[i].x+cx, tiles_build[i].y+cy).get_ground_tile() local tile_a1 = null local tile_b1 = null local tile_a_slope = null local tile_a_slope_WE = null local tile_a_slope_NS = null if ( build_side == 1 ) { // x/y build way > exists way tile_a1 = square_x(tiles_build[i].x+cy, tiles_build[i].y+cx).get_ground_tile() tile_b1 = square_x(tile_a.x+cy, tile_a.y+cx).get_ground_tile() tile_a_slope = [12, 13, 1, 4] tile_a_slope_WE = [39, 27, 36, 31] tile_a_slope_NS = [9] } else { // x/y build way < exists way tile_a1 = square_x(tiles_build[i].x-cy, tiles_build[i].y-cx).get_ground_tile() tile_b1 = square_x(tile_a.x-cy, tile_a.y-cx).get_ground_tile() tile_a_slope = [9, 12, 13, 1, 4, 39] tile_a_slope_WE = [39, 27, 36] tile_a_slope_NS = [31] } if ( print_message_box == 21 ) { gui.add_message_at(b_player, " tile_a.get_slope() " + tile_a.get_slope(), tile_a) gui.add_message_at(b_player, " tile_a1.get_slope() " + tile_a1.get_slope(), tile_a1) gui.add_message_at(b_player, " tile_b1.get_slope() " + tile_b1.get_slope(), tile_b1) gui.add_message_at(b_player, " build_side " + build_side, tiles_build[i]) } if ( tile_build_slope.find(build_hight.get_slope()) != null && tile_a_slope.find(tile_a.get_slope()) != null && test_tile_is_empty(tile_a1) && test_tile_is_empty(tile_b1) ) { //gui.add_message_at(b_player, " #6414# --", world.get_time()) if ( straight_slope == true && build_side == 0 ) { err = command_x.grid_raise(our_player, coord3d(tile_a.x, tile_a.y, tile_a.z)) } else if ( straight_slope == true && build_side == 1 ) { err = command_x.grid_raise(our_player, coord3d(tile_a1.x, tile_a1.y, tile_a1.z)) } else { err = command_x.grid_lower(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } if ( err != null ) { gui.add_message_at(b_player, " #3047# err " + err, world.get_time()) } else { terraform_tile = 0 } } else if ( tile_build_slope.find(build_hight.get_slope()) != null && tile_a_slope_NS.find(tile_a.get_slope()) != null ) { //gui.add_message_at(b_player, " #6429# ", world.get_time()) if ( test_tile_is_empty(tile_a1) && test_tile_is_empty(tile_b1) ) { //gui.add_message_at(b_player, " #3065# straight_slope " + straight_slope + " -- build_side " + build_side, world.get_time()) if ( straight_slope == true && build_side == 0 ) { err = command_x.grid_lower(our_player, coord3d(tile_a.x, tile_a.y, tile_a.z)) } else if ( straight_slope == true && build_side == 1 ) { gui.add_message_at(b_player, " #3069# " + coord3d_to_string(tile_b1), world.get_time()) err = command_x.grid_lower(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } else { err = command_x.grid_lower(our_player, coord3d(build_hight.x, build_hight.y, build_hight.z)) } if ( err != null ) { gui.add_message_at(b_player, " #3076# err " + err, world.get_time()) } else { terraform_tile = 0 } } } else if ( tile_build_slope.find(build_hight.get_slope()) != null && tile_a_slope_WE.find(tile_a.get_slope()) != null ) { //gui.add_message_at(b_player, " #6447# ", world.get_time()) if ( test_tile_is_empty(tile_a1) && test_tile_is_empty(tile_b1) ) { if ( straight_slope == true || build_side == 0 ) { err = command_x.grid_lower(our_player, coord3d(tile_a.x, tile_a.y, tile_a.z)) } else if ( straight_slope == true || build_side == 1 ) { err = command_x.grid_raise(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } else { err = command_x.grid_lower(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } if ( err != null ) { gui.add_message_at(b_player, " #3070# err " + err, world.get_time()) } else { terraform_tile = 0 } } } else if ( tile_build_slope.find(build_hight.get_slope()) != null && tile_a_slope_WE.find(tile_a1.get_slope()) != null ) { //gui.add_message_at(b_player, " #6463# ", world.get_time()) if ( test_tile_is_empty(tile_a1) && test_tile_is_empty(build_hight) ) { if ( straight_slope == false || build_side == 1 ) { err = command_x.grid_lower(our_player, coord3d(tile_a1.x, tile_a1.y, tile_a1.z)) }/* else if ( straight_slope == true || build_side == 1 ) { err = command_x.grid_raise(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } else { err = command_x.grid_lower(our_player, coord3d(tile_b1.x, tile_b1.y, tile_b1.z)) } if ( err == null ) { terraform_tile = 0 } else { gui.add_message_at(b_player, " #3070# err " + err, world.get_time()) }*/ if ( err != null ) { //gui.add_message_at(b_player, " #6475# err " + err, world.get_time()) } else { terraform_tile = 0 } } } } // double hight 8, 24, 56, 72 // terraform tile //gui.add_message_at(b_player, " terraform_tile " + terraform_tile + " - !straight_slope " + !straight_slope + " - build_hight.get_slope() " + build_hight.get_slope(), build_hight) if ( terraform_tile == 1 || (!straight_slope && build_hight.get_slope() > 0) ) { //&& ref_hight.z < build_hight.z if ( print_message_box == 21 ) { gui.add_message_at(b_player, "#6492# terraform down ", build_hight) } do { err = command_x.set_slope(b_player, build_hight, 83 ) if ( err != null ) { gui.add_message_at(b_player, "#6498# Error terraform down: " + err, build_hight) break } z = square_x(tiles_build[i].x, tiles_build[i].y).get_ground_tile() } while(z.z > ref_hight.z ) // replace water to land z = square_x(tiles_build[i].x, tiles_build[i].y).get_ground_tile() if ( z.get_slope() == 0 && z.is_water() ) { command_x.change_climate_at(our_player, z, cl_temperate) } } } } if ( err != null ) { //gui.add_message_at(b_player, "#6510# Error terraform : " + err, build_hight) if ( i == (tiles_build.len()-1) ) { if ( tr == way_len ) { tr-- } if ( tl == way_len ) { tl-- } way_len-- } //return false } else { build_hight = square_x(tiles_build[i].x, tiles_build[i].y).get_ground_tile() } } if ( ref_hight.z == build_hight.z && ref_hight.get_slope() == build_hight.get_slope() ) { if ( print_message_box == 21 ) { gui.add_message_at(b_player, "#3135# ---=> slope tiles == tiles_build * tiles.z == tiles_build.z ", world.get_time()) } } else if ( build_hight.is_empty() && straight_slope == true ) { // set slope ramp if ( i < (tiles_build.len()-1) ) { if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> terraform slope ramp", world.get_time()) gui.add_message_at(b_player, " ---=> tiles_build.z " + build_hight.z + " tiles.z " + ref_hight.z, world.get_time()) } err = command_x.set_slope(b_player, build_hight, ref_hight.get_slope()) if ( err != null ) { gui.add_message_at(b_player, " ERROR " + err, world.get_time()) err = null } } else { if ( print_message_box == 21 ) { gui.add_message_at(b_player, " ---=> last tile slope ramp", world.get_time()) } //tiles_build.remove(tiles_build.len()-1) //tiles.remove(tiles.len()-1) if ( tr == way_len ) { tr-- } if ( tl == way_len ) { tl-- } way_len-- } } } if ( print_message_box == 21 ) { gui.add_message_at(b_player, "output: tr " + tr + " - tl " + tl + " - way_len " + way_len, world.get_time()) } local output = [] output.append(tr) output.append(tl) output.append(way_len) return output } /* * search my_line_t from line_x * * */ function select_linkline(s_line) { foreach(link in link_list) { foreach(index, line in link.lines) { if ( line.is_valid() ) { //local s_line_name = s_line.get_name() //local line_name = line.get_name() if ( s_line.get_name() == line.get_name() ) { return line } } } } } simutrans-124.3/simutrans/ai/sqai_rail/basic.nut000066400000000000000000000253111474050137200217500ustar00rootroot00000000000000/** * Classes for basic nodes in the tree, which represents our brain :) */ // return codes from step // enum return_code { const RT_DONE_NOTHING = 1 // Done nothing. const RT_PARTIAL_SUCCESS = 2 // Done something, want to continue next const RT_SUCCESS = 4 // Done something. const RT_ERROR = 8 // Some error occured. const RT_KILL_ME = 16 // Can be destroyed by parent. const RT_TOTAL_SUCCESS = 20 // RT_SUCCESS | RT_KILL_ME const RT_TOTAL_FAIL = 24 // RT_ERROR | RT_KILL_ME const RT_READY = 29 // RT_DONE_NOTHING | RT_SUCCESS | RT_ERROR | RT_KILL_ME // } /** * Class use as return value from the function step() * Signals success, contains additional data. */ class r_t { // return code composed of return_code constants above code = 0 // reports have to be handled report = null // run node immediately node = null constructor(c, r=null, n=null) { code = c; report = r; node = n } function is_ready() { return (code & RT_READY);} function can_be_deleted() { return (code & RT_KILL_ME); } function has_failed() { return (code & RT_ERROR);} } /** * Basic node class. */ class node_t { name = null debug = false /** * Main method of these nodes. Called from the global ::step() method. */ function step() { return r_t(RT_TOTAL_FAIL)} constructor(n = "node_t") { name = n } function dbgprint(t) { if (debug) print(name + ": " + t) } function _save() { return ::saveinstance(name, this) } } /** * Has array of nodes that will be executed / stepped sequentially. */ class node_seq_t extends node_t { nodes = null next_to_step = 0 constructor(n = "node_seq_t") { base.constructor(n) nodes = [] } function append_child(c) { nodes.append(c) } /// @returns value of type r_t function step() { if (nodes.len() == 0) return r_t(RT_SUCCESS); if (next_to_step >= nodes.len()) { next_to_step = 0; return r_t(RT_DONE_NOTHING); } local ret = nodes[next_to_step].step() if ( ret == null ) { gui.add_message_at(our_player, "####### nodes[next_to_step].step() is null; nodes.len() = " + nodes.len() + " # next_to_step " + next_to_step, world.get_time()) return r_t(RT_ERROR); } // take nodes report if (ret.report) { append_report(ret.report) } // delete child if ready if (ret.can_be_deleted()) { nodes.remove(next_to_step); } else if (ret.is_ready()) { next_to_step ++ } // successor node if (ret.node) { append_child(ret.node) } // our return code local rc = RT_PARTIAL_SUCCESS // want next call, too if (ret.has_failed()) { rc = RT_ERROR // propagate error } else if (next_to_step > nodes.len()) { rc = RT_SUCCESS // done with stepping all nodes build_check_month = world.get_time() + world.get_time().ticks_per_month } return r_t(rc) } } /** * Base class to report financial aspects of plans. */ class report_t { // tree that will be executed action = null // costs cost_fix = 0 cost_monthly = 0 // expected gain per month gain_per_m = 0 // distance = 0 points = 0 // retire plan retire_time = null // retire objects retire_obj = null function merge_report(r) { if (r.action) { action.append_child( r.action ) } cost_fix += r.cost_fix cost_monthly += r.cost_monthly gain_per_m += r.gain_per_m distance += r.distance points += r.points } function _save() { return ::saveinstance("report_t", this) } } /** * Manager class. * Steps its child nodes, otherwise does some work(), generates reports. */ class manager_t extends node_seq_t { reports = null constructor(n = "manager_t") { base.constructor(n) reports = [] } function step() { month_check_message() if ( build_check_month > world.get_time().ticks ) { // not plan link //if (debug) gui.add_message_at(our_player, " not plan link : build_check_month = " + build_check_month, world.get_time()) //if (debug) gui.add_message_at(our_player, " for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y, world.get_time()) //return RT_DONE_NOTHING } dbgprint("stepping a child") local r = base.step() if (r.has_failed()) { if ("error_handler" in this) { return error_handler() } } if (r.code == RT_DONE_NOTHING || r.code == RT_SUCCESS) { // all nodes were stepped dbgprint("doing some work") return work() } dbgprint("stepped a child") return r } function work() { /*if ( month_count ) { month_count = false month_count_ticks = world.get_time().next_month_ticks if ( our_player.is_valid() && our_player.get_type() == 4 ) { local operating_profit = player_x(our_player.nr).get_operating_profit() local net_wealth = player_x(our_player.nr).get_net_wealth() local message_text = format(translate("%s - last month: operating profit %d net wealth %d"), our_player.get_name(), operating_profit[1], net_wealth[1]) gui.add_message_at(our_player, message_text, world.get_time()) if ( operating_profit[1] < 0 ) { build_check_month = world.get_time().month + 1 if ( build_check_month > 11 ) { build_check_month = build_check_month - 11 } } local yt = world.get_time().year.tostring() // check all 5 years ( year xxx0 and xxx5 ) if ( world.get_time().month == 3 ) { #(yt.slice(-1) == "0" || yt.slice(-1) == "5") && // in april industry_manager.check_pl_lines() } // check all 5 years ( year xxx2 and xxx7 ) if ( (yt.slice(-1) == "2" || yt.slice(-1) == "7") && world.get_time().month == 4 ) { // in may // check unused halts check_stations_connections() } } } else if ( world.get_time().ticks > month_count_ticks ) { month_count = true } set_map_vehicles_counts()*/ month_check_message() } function append_report(r) { reports.append(r); } /** * Returns the best report available. */ function get_report() { if (reports.len() == 0) return null // find report that maximizes gain_per_m / cost_fix local i = -1 local best = null // [0] = cost_fix / 13 // [1] = gain_per_m * ( cost_fix / 13 ) * points local p_test = [0, 0] local p_best = [0, 0] for(local j=0; j month_count_ticks ) { month_count = true } set_map_vehicles_counts() } /* * * */ function build_check_time(build_cost) { local operating_profit = player_x(our_player.nr).get_operating_profit() local net_wealth = player_x(our_player.nr).get_current_net_wealth()/100 local cash = player_x(our_player.nr).get_current_cash() local maintenance = player_x(our_player.nr).get_current_maintenance()/100 local k = build_cost if ( cash > 0 ) { k -= cash + (net_wealth / 2) } //gui.add_message_at(our_player, "### k -= cash " + k, world.get_time()) local t = 0 if ( operating_profit[1] > 0 ) { t = abs(k / operating_profit[1]).tointeger() } else { t = 12 } //gui.add_message_at(our_player, "### build_cost " + build_cost, world.get_time()) //gui.add_message_at(our_player, "### operating_profit[1] " + operating_profit[1], world.get_time()) //gui.add_message_at(our_player, "### build_check_time(build_cost) " + t, world.get_time()) if ( t > 24 ) { t = 24 } return t } simutrans-124.3/simutrans/ai/sqai_rail/combined_connections.nut000066400000000000000000000461111474050137200250520ustar00rootroot00000000000000class amphibious_connection_planner_t extends industry_connection_planner_t { constructor(s,d,f) { base.constructor(s,d,f); name = "amphibious_connection_planner_t" } // print messages box // 1 = // 2 = // 3 = print_message_box_x = 0 function step() { local wt = null print("amphibious_connection_planner_t " + this) if ( print_message_box_x > 1 ) { gui.add_message_at(our_player, " ** amphibious_connection_planner_t " + this, world.get_time()) } // compute monthly production if (prod < 0) { prod = calc_production() } dbgprint("production = " + prod); // set link build cost 0 industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 0) // road - initial local rprt_road = plan_simple_connection(wt_road, null, null) if (rprt_road == null) { //return failed() } // rail - initial local rprt_rail = plan_simple_connection(wt_rail, null, null) if (rprt_rail == null) { //return failed() } // water - initial local rprt_water = plan_simple_connection(wt_water, null, null) if (rprt_water == null && ( rprt_road == null || rprt_rail == null )) { return failed() } if ( print_message_box_x == 1 ) { gui.add_message_at(our_player, " **** rprt_water - gain_per_m : " + rprt_water.gain_per_m + " # distance : " + rprt_water.distance, world.get_time()) gui.add_message_at(our_player, " **** rprt_rail - gain_per_m : " + rprt_rail.gain_per_m + " # distance : " + rprt_rail.distance, world.get_time()) gui.add_message_at(our_player, " **** rprt_road - gain_per_m : " + rprt_road.gain_per_m + " # distance : " + rprt_road.distance, world.get_time()) } if (rprt_water == null ) { return failed() //rprt_water = report_t() } // find flat harbour building local station_list = building_desc_x.get_available_stations(building_desc_x.flat_harbour, wt_water, good_desc_x(freight)) rprt_water.action.planned_harbour_flat = industry_connection_planner_t.select_station(station_list, 1, rprt_water.action.planned_convoy.capacity) local build_cost_lines = industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) // find amphibious path local marine = null if ( rprt_rail != null && ( rprt_road==null || rprt_rail.gain_per_m > rprt_road.gain_per_m ) ) { marine = amphibious_pathfinder_t(rprt_rail.action.planned_way, rprt_water.action.planned_station, rprt_water.action.planned_harbour_flat) build_cost_lines += rprt_rail.cost_fix industry_manager.set_link_build_cost(fsrc, fdest, freight, build_cost_lines, 0) local a = industry_manager.get_combined_link(fsrc, fdest, freight) + 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) wt = wt_rail if ( print_message_box_x == 1 ) { gui.add_message_at(our_player, " ---> rprt_rail ", world.get_time()) } } else if ( rprt_road != null ) { marine = amphibious_pathfinder_t(rprt_road.action.planned_way, rprt_water.action.planned_station, rprt_water.action.planned_harbour_flat) build_cost_lines += rprt_road.cost_fix industry_manager.set_link_build_cost(fsrc, fdest, freight, build_cost_lines, 0) local a = industry_manager.get_combined_link(fsrc, fdest, freight) + 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) wt = wt_road if ( print_message_box_x == 1 ) { gui.add_message_at(our_player, " ---> rprt_road ", world.get_time()) } } if (marine == null) { industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 0) industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 1) industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 2) industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 3) industry_manager.set_combined_link(fsrc, fdest, freight, 0) return r_t(RT_TOTAL_FAIL) } else { local a = industry_manager.get_combined_link(fsrc, fdest, freight) + 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) } // check build cost /*if ( wt == wt_rail && rprt_rail.cost_fix > our_player.get_current_cash() ) { return r_t(RT_TOTAL_FAIL) } else if ( wt == wt_road && rprt_road.cost_fix > our_player.get_current_cash() ) { return r_t(RT_TOTAL_FAIL) }*/ if ( wt == wt_rail ) { } else if ( wt == wt_road ) { } //gui.add_message_at(our_player, " ---> link " + fsrc + " " + fsrc.get_name() + " - " + fdest.get_name(), world.get_time()) //gui.add_message_at(our_player, " ---> build cost lines = " + build_cost_lines + " # industry_manager.get_combined_link(fsrc, fdest, freight) = " + industry_manager.get_combined_link(fsrc, fdest, freight), world.get_time()) local build_cash = player_x(our_player.nr).get_current_cash() + (((player_x(our_player.nr).get_current_net_wealth()/100) - player_x(our_player.nr).get_current_cash())/2) if ( build_cost_lines > build_cash ) { //industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 0) //industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 1) //industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 2) //industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 3) //industry_manager.set_combined_link(fsrc, fdest, freight, 0) build_check_month = world.get_time().ticks + (build_check_time(build_cost_lines) * world.get_time().ticks_per_month) return r_t(RT_TOTAL_FAIL) } marine.search_route(fsrc,fdest) local route = marine.route if (route.len() == 0) { return r_t(RT_TOTAL_FAIL) } // generate report local report = report_t() report.action = node_seq_t() if ( print_message_box_x == 1 ) { gui.add_message_at(our_player, " ---> marine.route.len(fsrc,fdest) " + route.len(), world.get_time()) gui.add_message_at(our_player, " ---> route[0] " + coord3d_to_string(route[0]) + " - route[route.len()-1] " + coord3d_to_string(route[route.len()-1]), world.get_time()) } // now loop through route backwards local i = route.len()-1; local from = tile_x(route[i].x, route[i].y, route[i].z) local on_water = ::finder._tile_water_way(from) local from_i = on_water ? i : i+1; i-- for(; i>=0; i--) { local to = tile_x(route[i].x, route[i].y, route[i].z) local to_water = ::finder._tile_water_way(to) local change = to_water != on_water if (change || i==0) { print("-- Plan arc from " + coord_to_string(from) + " to " + coord_to_string(route[i])) if ( print_message_box_x == 1 ) { gui.add_message_at(our_player, " **-- Plan arc from " + coord_to_string(from) + " to " + coord_to_string(route[i]), world.get_time()) } // change between land and sea local r = null if (on_water) { // from_i = first water tile // i = first land tile (or i==0) // plan between water tiles r = plan_simple_connection(wt_water, from_i < route.len()-1 ? from : null, change ? route[i+1] : null, from_i - (i+1)) // set harbour positions if (r) { local shipc = r.action if (from_i < route.len()-1) { local c = route[from_i+1] shipc.c_harbour_tiles[ coord3d_to_key(from) ] <- tile_x(c.x, c.y, c.z) } if (change) { shipc.c_harbour_tiles[ coord3d_to_key(route[i+1]) ] <- to } } } else { // from_i = first land tile, which is harbour slope // i = first water tile print("Try to catch index error") if (i+2 < route.len()) { r = plan_simple_connection(wt, route[from_i-1], change ? route[i+2] : null, from_i-1 - (i+2)) } else { // else: first tile of route but second already in water - no need to plan road r = report_t() } } if (r) { if (r.action) { r.action.finalize = !change } report.merge_report(r) } else { return failed() } from = to from_i = i on_water = to_water } } return r_t(RT_TOTAL_SUCCESS, report) } function failed() { //industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } } class amphibious_pathfinder_t extends astar { way = 0 builder = null planned_harbour = null planned_harbour_flat = null planned_harbour_len = 0 planned_harbour_flat_len = 0 cost_harbour = 333 cost_road_stop = 17 c_harbour_tiles = null // print messages box // 1 print_message_box_x = 0 constructor(way_, harbour_, harbour_flat_) { base.constructor() way = way_ builder = way_planner_x(our_player) builder.set_build_types(way) planned_harbour = harbour_ planned_harbour_flat = harbour_flat_ local size = planned_harbour.get_size(0) planned_harbour_len = size.x*size.y if (planned_harbour_flat) { local size = planned_harbour_flat.get_size(0) planned_harbour_flat_len = size.x*size.y } } function process_node(cnode) { local from = tile_x(cnode.x, cnode.y, cnode.z) local back = dir.backward(cnode.dir) local from_water = ::finder._tile_water_way(from) local water_dir = from.get_way_dirs(wt_water) // local message = [0, 0, 0] // flags // 0x0f -> jps // 0x10 -> find flat place // 0x20 -> flat place (mark next step with 0x40) // 0x40 -> cannot go into water if (cnode.flag == 0x10) { process_node_to_land(cnode, from) return } local test_dir = cnode.previous ? (back ^ 0x0f) & (cnode.flag & 0x0f) : 0x0f for(local d = 1; d<16; d*=2) { // do not go backwards if (( d &test_dir) == 0 ) { continue } local to = from.get_neighbour(wt_all, d) if (to && !is_closed(to)) { local to_water = ::finder._tile_water_way(to) // water -> water // land -> land if (from_water == to_water) { // can we build way here? if (!from_water) { // empty space for station near a halt with harbour local halt = to.get_halt() if (halt && halt.get_owner().nr == our_player_nr && from.is_empty()) { // try to connect to this halt and to use its harbours process_node_to_land_halt(cnode, halt) } // can we build way here? if (!builder.is_allowed_step(from, to)) { // could be a halt on the other tile that has harbour that could be used continue; } } // estimate moving cost local move = cnode.is_straight_move(d) ? cost_straight : cost_curve local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist // use jump-point search (see dataobj/route.cc) local jps = to_water && (cnode.previous) ? (water_dir ^ 0x0f) | d | cnode.dir | from.get_canal_ribi() : 0x0f if (cnode.flag & 0x20) jps = jps | 0x40; local node = ab_node(to, cnode, cost, dist, d, jps) add_to_open(node, weight) message[0] = 1 } else if (from_water) { // water -> land if (from.is_water() && to.get_halt()) { // check for existing harbour local halt = ship_connector_t.get_harbour_halt(to) if (halt) { // create node as end node of water route local harbour_node = ab_node(to, cnode, cnode.cost, cnode.dist, 0x0f, 0x0f) // now look for empty spots to connect to this halt process_node_to_harbour(harbour_node, halt) } } // we have to build ourselves if (!from.is_water() || !can_place_harbour(to, d) ) { continue } local move = cost_harbour local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 0x10) add_to_open(node, weight) message[1] = 1 } else { // land -> water if (!to.is_water() || !can_place_harbour(from, dir.backward(d)) || (cnode.flag & 0x60) ) { continue } if (cnode.previous) { local fromfrom = tile_x(cnode.previous.x, cnode.previous.y, cnode.previous.z) // want to build station here with one connecting road if (fromfrom == null || !fromfrom.is_empty() || fromfrom.get_slope()!=0 || cnode.previous.previous == null) { continue } } local move = cost_harbour local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, d, 0x0f) add_to_open(node, weight) message[2] = 1 } } } /* if ( print_message_box_x == 1 ) { if ( message[0] == 1 ) { gui.add_message_at(our_player, "---- water -> water", world.get_time()) gui.add_message_at(our_player, "---- found", world.get_time()) } if ( message[1] == 1 ) { gui.add_message_at(our_player, "---- water -> land", world.get_time()) gui.add_message_at(our_player, "---- found", world.get_time()) } if ( message[2] == 1 ) { gui.add_message_at(our_player, "---- land -> water", world.get_time()) gui.add_message_at(our_player, "---- found", world.get_time()) } } */ } function can_place_harbour(tile, d_water_to_land) { return ship_connector_t.get_harbour_type_for_tile(tile, planned_harbour, planned_harbour_flat, d_water_to_land) > 0 } function can_place_harbour(tile, d_water_to_land) { return ship_connector_t.get_harbour_type_for_tile(tile, planned_harbour, planned_harbour_flat, d_water_to_land) > 0 } function process_node_to_land(cnode, from) { local pos = coord(cnode.x, cnode.y) for(local d = 1; d<16; d++) { // test all 8 neighbouring tiles if (!dir.is_threeway(d)) { local c = pos + dir.to_coord(d) try { local to = square_x(c.x, c.y).get_ground_tile() if (to && to.is_empty() && to.get_slope()==0) { // can place station here local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, 0x0f, 0x0f) add_to_open(node, weight) } } catch(ev) {} } } } function process_node_to_harbour(cnode, halt) { local visited = {} // process all tiles of this halt foreach(tile in halt.get_tile_list()) { // check all neighbouring tiles for empty spots for(local d = 1; d<16; d*=2) { local c = coord(tile.x, tile.y) + dir.to_coord(d) try { local to = square_x(c.x, c.y).get_ground_tile() if (to && to.is_empty() && to.get_slope()==0 && !(coord3d_to_key(to) in visited) ) { // can place station here local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, cnode, cost, dist, 0x0f, 0x0f) add_to_open(node, weight) // mark as visited visited[ coord3d_to_key(to) ] <- 1 } } catch(ev) {} } } } /** * Does steps land-tile -> halt -> harbour -> water * Last route tile is cnode, check if station can be placed. * Check for harbour tiles, put corresponding nodes to open list. */ function process_node_to_land_halt(cnode, halt) { // process all tiles of this halt foreach(tile in halt.get_tile_list()) { if (!tile.is_water() && ship_connector_t.get_harbour_halt(tile)!=null) { local harbour_node = ab_node(tile, cnode, cnode.cost, cnode.dist, 0x0f, 0x0f) local d = 0 if (tile.get_slope()) { // get direction from slope d = dir.backward(slope.to_dir(tile.get_slope())) } else { // flat dock, check all four neighbour tiles for water + harbour d = 1 } do { local to = coord3d(tile.x, tile.y, tile.z) + dir.to_coord(d) if (world.is_coord_valid(to)) { local move = cost_road_stop local dist = estimate_distance(to) local cost = cnode.cost + move local weight = cost + dist local node = ab_node(to, harbour_node, cost, dist, d, 0x0f) add_to_open(node, weight) } d = d*2 } while (tile.get_slope()==0 && d<16) } } } function search_route(fsrc, fdest) { print("Search amphibious connection") if ( print_message_box_x > 0 ) { local fs = fsrc.get_tile_list() local fd = fdest.get_tile_list() gui.add_message_at(our_player, "____________ Search amphibious connection ___________", world.get_time()) gui.add_message_at(our_player, " line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ")", world.get_time()) } // find station places local s = [] local e = [] c_harbour_tiles = {} s.append(::finder.find_station_place(fsrc, fdest) ) e.append(::finder.find_station_place(fdest, fsrc) ) s.append(::ship_connector_t.find_anchorage(fsrc, planned_harbour, planned_harbour_flat, c_harbour_tiles) ) e.append(::ship_connector_t.find_anchorage(fdest, planned_harbour, planned_harbour_flat, c_harbour_tiles) ) // init search prepare_search() for(local i=0; i<2; i++) { foreach (e in e[i]) { targets.append(e); } } if (targets.len() == 0) { route = [] return } compute_bounding_box() for(local i=0; i<2; i++) { foreach (s in s[i]) { local dist = estimate_distance(s) add_to_open(ab_node(s, null, 1, dist+1, dist, 0), dist+1) } } search() print("End amphibious route search") if ( print_message_box_x > 0 ) { gui.add_message_at(our_player, "------------ End amphibious route search -------------", world.get_time()) } } } simutrans-124.3/simutrans/ai/sqai_rail/factorysearcher.nut000066400000000000000000000626471474050137200240700ustar00rootroot00000000000000/** * Class that searches for usefull unbuild factory connections. * Depending on player number uses two different methods: * 1) Method that tries to complete a factory tree (taken from the c++ implementation of the freight AI in player/ai_goods.cc * 2) A demand-driven method. */ class factorysearcher_t extends manager_t { froot = null // factory_x, complete this tree method = -1 factory_iterator = null factory_list = null constructor() { base.constructor("factorysearcher_t") debug = false ::factorysearcher = this } function get_next_end_consumer() { // iterate the factory_iterator, which is a generator if (factory_iterator == null || typeof(factory_iterator) != "generator") { // this is a generator factory_iterator = factory_iteration() } if (factory_iterator.getstatus() != "dead") { return resume factory_iterator } factory_iterator = null return null } function factory_iteration() { factory_list = [] // copy list of end-consumers foreach(factory in factory_list_x()) { if (factory.output.len() == 0) { factory_list.append(factory) } } // shuffle for(local i=0; i 0) && (n < min_mfc)) { // TODO add some random here min_mfc = n froot = fab } } if (froot) { local fab = froot dbgprint("Choose consumer " + fab.get_name() + " at " + fab.x + "," + fab.y + ", which has " + min_mfc + " missing links") } } // nothing found?? if (froot==null) return r_t(RT_DONE_NOTHING); dbgprint("Connect " + froot.get_name() + " at " + froot.x + "," + froot.y) // find link to connect if (!plan_missing_link(froot)) { dbgprint(".. no missing link") // no missing link found - reset froot froot = null return r_t(RT_SUCCESS) } return r_t(RT_PARTIAL_SUCCESS) } else { // demand-driven method if (froot == null) { froot = get_next_end_consumer() } if (froot) { local n = plan_increase_consumption(froot) if (n==0 && count_missing_factories(froot) <= 0) { froot = null } return r_t( n>0 ? RT_PARTIAL_SUCCESS : RT_SUCCESS) } } return r_t(RT_SUCCESS) } /** * Creates the planner node */ static function plan_connection(fsrc, fdest, freight) { if (industry_manager.get_link_state(fsrc, fdest, freight) != industry_link_t.st_free) { dbgprint("Link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y + " state is " + industry_manager.get_link_state(fsrc, fdest, freight) ); return false } dbgprint("Close link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_planned); local icp = industry_connection_planner_t(fsrc, fdest, freight); append_child(icp) return true } /** * @returns -1 if factory tree is incomplete, otherwise number of missing connections */ // TODO cache the results per factory static function count_missing_factories(fab, indent = "") { // source of raw material? if (fab.input.len() == 0) return 0; local end_consumer = fab.output.len() == 0 // build list of supplying factories local suppliers = []; foreach(c in fab.get_suppliers()) { suppliers.append( factory_x(c.x, c.y) ); } local count = 0; local g_atleastone = false; // iterate all input goods and search for supply foreach(good, islot in fab.input) { // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() //gui.add_message_at(our_player, "### " + fab.get_name() + " ## " + good + " ## get_storage() " + st[0] + " get_in_transit() " + it[0], world.get_time()) if (st[0] + st[1] + it[0] + it[1] > 0) { // something stored/in-transit in last and current month // no need to search for more supply g_atleastone = true continue } // there is a complete tree to produce this good local g_complete = false; // minimum of missing links for one input good local g_count = 10000; foreach(s in suppliers) { if (good in s.output) { // check state of connection local state = industry_manager.get_link_state(s, fab, good); if (state == industry_link_t.st_failed) { continue // foreach } if (state != industry_link_t.st_free) { // planned / built -> nothing missing g_complete = true g_count = 0 continue } local n = count_missing_factories(s, indent + " "); if ( n<0) { // incomplete tree } else { // complete tree g_complete = true; g_count = min(g_count, n+1) } } } if (!g_complete && !end_consumer) { dbgprint(indent + "No supply of " + good + " for " + fab.get_name()) //gui.add_message_at(our_player, " No supply of " + good + " for " + fab.get_name(), world.get_time()) // no suppliers for this good return -1 } g_atleastone = g_atleastone || g_complete if (!end_consumer) { count += g_count // sum missing links } else { if (g_count > 0 && (count == 0 || g_count < count)) { count = g_count; } } dbgprint(indent + "Supply of " + good + " for " + fab.get_name() + " has " + g_count + " missing links") if ( g_count > 0 ) { //gui.add_message_at(our_player, " Supply of " + good + " for " + fab.get_name() + " has " + g_count + " missing links", world.get_time()) } } if (end_consumer && !g_atleastone) { dbgprint(indent + "No supply for " + fab.get_name()) count = -1 } dbgprint(indent + "Factory " + fab.get_name() + " at " + fab.x + "," + fab.y + " has " + count + " missing links") return count } /** * find link to connect in tree of factory @p fab. * sets fsrc, fdest, lgood if true was returned * @returns true if link is found */ function plan_missing_link(fab, indent = "") { dbgprint(indent + "Missing link for factory " + fab.get_name() + " at " + fab.x + "," + fab.y) // source of raw material? if (fab.input.len() == 0) return false; // build list of supplying factories local suppliers = []; foreach(c in fab.get_suppliers()) { suppliers.append( factory_x(c.x, c.y) ); } local count = 0; // iterate all input goods and search for supply foreach(good, islot in fab.input) { // check for current supply if ( 4*(islot.get_storage()[0] + islot.get_in_transit()[0]) > islot.max_storage) { dbgprint(indent + ".. enough supply of " + good) continue } // find suitable supplier foreach(s in suppliers) { if ( !(good in s.output)) continue; // connection forbidden? planned? built? local state = industry_manager.get_link_state(s, fab, good) if (state != industry_link_t.st_free) { if (state == industry_link_t.st_built || state == industry_link_t.st_planned) { dbgprint(indent + ".. connection for " + good + " from " + s.get_name() + " to " + fab.get_name() + " already " + (state == industry_link_t.st_built ? "built" : "planned") ) break } continue // if connection state is 'failed' } local oslot = s.output[good] dbgprint(indent + ".. Factory " + s.get_name() + " at " + s.x + "," + s.y + " supplies " + good) if (8*oslot.get_storage()[0] > oslot.max_storage || !plan_missing_link(s, indent + " ")) { // this is our link dbgprint(indent + ".. plan this connection") plan_connection(s, fab, good) } return true } } return false // all links are connected } /** * Estimates additional possible consumption at this end-consumer factory */ function plan_increase_consumption(fab, indent = "") { // initialize search if (fab.output.len() > 0) { return 0 } local planned = 0; foreach(good, islot in fab.input) { local tree = estimate_consumption(fab, good) // now do some greedy selection: for each producer select enough suppliers planned += plan_consumption_connection(tree, fab, good) } return planned } function plan_consumption_connection(tree, fdest, freight, indent = "") { local planned = 0; local needed = tree.increase while (needed > 0) { local best = null local best_supply = 0 foreach(supplier in tree.suppliers) { local supply = supplier.supply dbgprint(indent + "Needed " + needed + " Provided " + supply ) if (supply > needed ? (best_supply == 0 || supply < best_supply) : supply > best_supply) { best = supplier best_supply = supply } } // go down in tree foreach(good, supplier_slot in best.inputs) { planned += plan_consumption_connection(supplier_slot, best.supplier, good, indent + " ") dbgprint(indent + "Planned for " + best_supply + " (total = " + planned + ")") } // plan this connection if (planned==0) { if (plan_connection(best.supplier, fdest, freight)) { dbgprint(indent + "Planned to consumer ") planned++ } } // disable this tree needed -= best_supply best.supply = 0 } return planned } /** * Estimates additional possible consumption of good at this factory * * Returns tree: * tree.increase - Potential local consumption * tree.supply - Potential supply * tree.basec - Base consumption * tree.suppliers - Array of supplier nodes * [].supplier - Factory * [].supply - Potential production of supplier } - produced by estimate_production * [].inputs - Table Good -> Consumer tree } * * @returns estimated consumption increase */ static function estimate_consumption(fab, prod = null, indent = "") { dbgprint(indent + "Estimates for consumption of " + prod + " at factory " + fab.get_name() + " at " + fab.x + "," + fab.y) // estimate max consumption local islot = fab.input[prod] local max_c = islot.get_base_consumption() // estimate actual consumpion local est_c = estimate_actual_consumption(islot) local increase = max_c - est_c dbgprint(indent + " potential increase of consumption of " + prod + " is " + increase) // iterate suppliers: // calculate potential additional supply (and build it) local tree = { suppliers = [], basec = max_c } // search for supply local supply = 0 foreach(c in fab.get_suppliers()) { local s = factory_x(c.x, c.y) if (prod in s.output) { local state = industry_manager.get_link_state(s, fab, prod) if (state == industry_link_t.st_planned || state == industry_link_t.st_failed) { // failed / planned -> no improvement possible dbgprint(indent + " transport link for " + prod + " is failed/planned" ) continue } local s_tree = estimate_production(s, prod, state == industry_link_t.st_built, indent + " ") s_tree.supplier <- s local more = s_tree.supply supply += more tree.suppliers.append(s_tree) dbgprint(indent + " potential increase of " + prod + " is " + more + " (state =" + state + ")") } } dbgprint(indent + " total additional supply of " + prod + " is " + supply) tree.increase <- min(increase, supply) tree.supply <- supply return tree } /** * Estimates additional possible production of good at this factory * @returns tree, see estimate_consumption */ static function estimate_production(fab, prod, exists, indent = "") { dbgprint(indent + "Estimates for production of " + prod + " at factory " + fab.get_name() + " at " + fab.x + "," + fab.y) local oslot = fab.output[prod] local fac = oslot.get_production_factor() local est_p = estimate_actual_production(oslot, exists) local increase = oslot.get_base_production() - est_p dbgprint(indent + " potential increase of production of " + prod + " is " + increase) // build tree for later planning local tree = { inputs = {}, supply = 0 } if (increase <= 0) { return tree } if (fab.input.len() == 0) { // producer of raw materials tree.supply = ( increase*fac)/100; return tree } // iterate all input goods and search for supply foreach(good, islot in fab.input) { local c_tree = estimate_consumption(fab, good, indent + " ") tree.inputs[good] <- c_tree local con = c_tree.increase local est = (con * fac)/ islot.get_consumption_factor() increase = min(increase, est) } tree.supply = increase return tree } static function estimate_actual_consumption(islot) { local con = islot.get_consumed() local isnew = (con.reduce(sum) - con[0]) == 0; if (!isnew) { // established connection: report max return con.reduce(max) } else { if (con[0] == 0) { // non-existing connection return 0 } else { // new connection: report base return islot.get_base_consumption() } } } static function estimate_actual_production(oslot, exists) { local pro = oslot.get_produced() local isnew = (pro.reduce(sum) - pro[0]) == 0; if (!isnew) { // established connection: report max return pro.reduce(max) } else { if (pro[0] == 0 && !exists) { // non-existing connection return 0 } else { // new connection: report base return oslot.get_base_consumption() } } } } /* * check factory chain befor build link * * return false = no build link * return true = build link */ function check_factory_link_line(f_src, f_dest, t_good) { local print_message_box = 0 local print_status = 0 local good_list_in = []; local g_count_in = 0 foreach(good, islot in f_dest.input) { // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() //gui.add_message_at(our_player, "### " + fab.get_name() + " ## " + good + " ## get_storage() " + st[0] + " get_in_transit() " + it[0], world.get_time()) if (st[0] + st[1] + it[0] + it[1] > 0) { // something stored/in-transit in last and current month // no need to search for more supply good_list_in.append({ g = good, t = 1 }) g_count_in++ } else { good_list_in.append({ g = good, t = 0 }) } } local o = true for ( local i = 0; i < good_list_in.len(); i++ ) { //gui.add_message_at(our_player, " good in " + good_list_in[i].g + " connect " + good_list_in[i].t, world.get_time()) if ( good_list_in[i].g == t_good && good_list_in[i].t == 1 && good_list_in.len() >= g_count_in ) { // check all goods connect yes o = false } } // check consumers if ( !o ) { if ( f_dest.output.len() > 0 ) { // test connect next consumer fab local consumers = []; foreach(c in f_dest.get_consumers()) { consumers.append( factory_x(c.x, c.y) ); } // list output goods local good_list_out = []; foreach(good, islot in f_dest.output) { good_list_out.append(good) } /* // 1 consumer if ( consumers.len() == 1 ) { for ( local j = 0; j < good_list_out.len(); j++ ) { if ( check_factory_links(f_dest, consumers[0], good_list_out[j]) == 0 ) { o = false } } }*/ if ( consumers.len() > 0 ) { for ( local j = 0; j < good_list_out.len(); j++ ) { local consumers_links = 0 for ( local i = 0; i < consumers.len(); i++ ) { if ( check_factory_links(f_dest, consumers[i], good_list_out[j]) == 0 ) { if ( print_message_box >= 1 ) { gui.add_message_at(our_player, " link check consumers " + consumers[i].get_name() + " good " + good_list_out[j], world.get_time()) } // test to other supliers for this good g_count_in = 0 foreach(good, islot in consumers[i].input) { //if ( good == t_good ) { if ( good == good_list_out[j] ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, " consumers " + consumers[i].get_name() + " good " + good, world.get_time()) } // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() //gui.add_message_at(our_player, "### " + fab.get_name() + " ## " + good + " ## get_storage() " + st[0] + " get_in_transit() " + it[0], world.get_time()) if (st[0] + st[1] + it[0] + it[1] > 0 && good_list_out[j] == good) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, " good_list_out[j] " + good_list_out[j] + " good " + good, world.get_time()) } // something stored/in-transit in last and current month // no need to search for more supply g_count_in++ } local suppliers = []; foreach(c in consumers[i].get_suppliers()) { suppliers.append( factory_x(c.x, c.y) ); } if ( print_message_box == 1 ) { gui.add_message_at(our_player, " suppliers " + consumers[i].get_name() + " count " + suppliers.len(), world.get_time()) } for ( local k = 0; k < suppliers.len(); k++ ) { if ( check_factory_links(consumers[i], suppliers[k], good_list_out[j]) > 0 ) { consumers_links++ } foreach(good, islot in suppliers[k].input) { //if ( good_list_out[j] == good ) { if ( print_message_box >= 1 ) { gui.add_message_at(our_player, " supplier " + suppliers[k].get_name() + " good " + good, world.get_time()) } // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() //gui.add_message_at(our_player, "### " + suppliers[k].get_name() + " ## " + good + " ## get_storage() " + st[0] + " get_in_transit() " + it[0], world.get_time()) if (st[0] + st[1] + it[0] + it[1] > 0 ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, "### " + suppliers[k].get_name() + " ## " + good + " ## get_storage() st[0] " + st[0] + " get_in_transit() it[0] " + it[0], world.get_time()) } // something stored/in-transit in last and current month // no need to search for more supply g_count_in++ } //} } } //} if ( print_message_box == 1 ) { gui.add_message_at(our_player, " g_count_in " + g_count_in + " consumers_links " + consumers_links, world.get_time()) } if ( g_count_in > 0 && consumers_links == 0 ) { o = false //::debug.pause() } } } } else { // all supplier and consumer for planned good connected // build second link supplier for this good o = true } } } } /* if ( g_count_in > 0 ) { o = false }*/ } else { o = true } } if ( print_message_box == 1 || print_status == 1 ) { local fs = f_src.get_tile_list() local fd = f_dest.get_tile_list() gui.add_message_at(our_player, "--> factory: " + f_src.get_name() + " (" + coord_to_string(fs[0]) + ") to factory " + f_dest.get_name() + " (" + coord_to_string(fd[0]) + ") --> good: " + t_good, world.get_time()) gui.add_message_at(our_player, "--> check_factory_link_line() return " + o, world.get_time()) } // check input f_src if ( o && f_src.input.len() > 0 ) { o = check_fsrc_input(f_src) } return o //get_delivered() //get_consumers() //get_suppliers() } /* * check factory link other goods of the same category * * */ function check_link_catg_goods(f_src, f_dest, t_good) { //gui.add_message_at(our_player, "--> check catg conect start (" + t_good + ")", world.get_time()) local line_catg = 0 local good_list_in = []; foreach(good, islot in f_dest.input) { if ( good != t_good && good_desc_x(good).get_catg_index() == good_desc_x(t_good).get_catg_index() ) { good_list_in.append(good) //gui.add_message_at(our_player, "-- input good " + good, world.get_time()) } } local good_list_out = []; foreach(good, islot in f_src.output) { if ( good != t_good && good_desc_x(good).get_catg_index() == good_desc_x(t_good).get_catg_index() ) { good_list_out.append(good) //gui.add_message_at(our_player, "-- output good " + good, world.get_time()) } } if ( good_list_out.len() > 0 && good_list_in.len() > 0 ) { //gui.add_message_at(our_player, "-- good_list_in.len() : " + good_list_in.len(), world.get_time()) //gui.add_message_at(our_player, "-- good_list_out.len() : " + good_list_out.len(), world.get_time()) for(local i = 0; i < good_list_out.len(); i++ ) { //gui.add_message_at(our_player, "-- good_list_in.find(good_list_out[i]) : " + good_list_in.find(good_list_out[i]), world.get_time()) if ( good_list_in.find(good_list_out[i]) != null ) { //gui.add_message_at(our_player, "-- conect good " + good_list_out[i], world.get_time()) line_catg += check_factory_links(fsrc, fdest, good_list_out[i]) //gui.add_message_at(our_player, "-- check pl link : " + industry_manager.get_link_state(fsrc, fdest, good_list_out[i]), world.get_time()) if ( industry_manager.get_link_state(fsrc, fdest, good_list_out[i]) == 3 ) { // no build - exists link from player return false } } } } //gui.add_message_at(our_player, "-- catg conect : " + line_catg, world.get_time()) if ( line_catg >= 2 ) { // no build - exists links from other player return false } //gui.add_message_at(our_player, "<-- check catg conect end", world.get_time()) return true } /* * check factory input storage * */ function check_fsrc_input(f_src) { // check input f_src if ( f_src.input.len() > 0 ) { local src_count_in = [] local j = 0 foreach(good, islot in f_src.input) { // test for in-storage or in-transit goods local st = islot.get_storage() local it = islot.get_in_transit() local count = 0 for ( local i = 0; i < 12; i++ ) { count += st[i] count += it[i] } src_count_in.append(count) local fs = f_src.get_tile_list() //gui.add_message_at(our_player, "### " + f_src.get_name() + " - " + coord_to_string(fs[0]) + " # " + good + " # src_count_in " + src_count_in[j], fs[0]) j++ } if ( src_count_in.find(0) != null && f_src.get_halt_list().len() > 0 ) { //local fs = f_src.get_tile_list() //gui.add_message_at(our_player, "### return false", fs[0]) return false } } return true } simutrans-124.3/simutrans/ai/sqai_rail/industry_connection_planner.nut000066400000000000000000001126561474050137200265170ustar00rootroot00000000000000/** * Plans connections suggested by factory-searcher. */ // helper class to simulate ways on open water openwater <- { function get_cost() { return 0; } function get_maintenance() { return 0; } function get_name() { return "open water"} } function get_max_convoi_length(wt) { switch(wt) { case wt_rail: return settings.get_max_rail_convoi_length(); case wt_road: return settings.get_max_road_convoi_length(); case wt_water: return settings.get_max_ship_convoi_length(); } return 4; } /** * Planer class. */ class industry_connection_planner_t extends manager_t { // Source factory fsrc = null // factory_x // Destination factory fdest = null // factory_x // Freight to be transported freight = null // string prod = -1 // integer // print messages box // 1 = vehicles // 2 = stations // 3 = depots // 4 = reports // 5 = factorys print_message_box = 0 wt_name = ["", "road", "rail", "water"] constructor(s,d,f) { base.constructor("industry_connection_planner_t"); fsrc = s; fdest = d; freight = f; debug = false } /** * Evaluates transport by road, rail and ships. * Returns the corresponding reports. * In addition, returns amphibious_connection_planner_t. * This planner will start to work if the connection by road, rail or ship did not succeed. */ function step() { local tic = get_ops_total(); // limit links to transport good local exists_links = check_factory_links(fsrc, fdest, freight, 0) local freight_input = fdest.input[freight].get_base_consumption() local freight_output = fsrc.output[freight].get_base_production() local fs = fsrc.get_tile_list() local fs_halt = fs[0].get_halt() if ( (fs_halt != null ) && exists_links == 1 ) { //|| fs_halt != false if (debug) gui.add_message_at(our_player, "fs_halt - " + fs_halt, fs[0]) // water factory - no more links than one if (debug) gui.add_message_at(our_player, " water factory - no more links than one ", fs[0]) return r_t(RT_TOTAL_FAIL) } if ( (freight_input < 700 || freight_output < 550) && exists_links >= 2 ) { return r_t(RT_TOTAL_FAIL) } else if ( (freight_input < 1500 || freight_output < 1250) && exists_links >= 3 ) { return r_t(RT_TOTAL_FAIL) } else if ( (freight_input > 1500 || freight_output > 1250) && exists_links >= 4 ) { return r_t(RT_TOTAL_FAIL) } else if ( exists_links > 4 ) { return r_t(RT_TOTAL_FAIL) } if ( build_check_month > world.get_time().ticks ) { // not plan link if (debug) gui.add_message_at(our_player, " not plan link : build_check_month = " + build_check_month, world.get_time()) if (debug) gui.add_message_at(our_player, " for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y, world.get_time()) return r_t(RT_TOTAL_FAIL) } print("Plan link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y) // TODO check if factories are still existing // TODO check if connection is plannable // compute monthly production if (prod < 0) { prod = calc_production() } dbgprint("production = " + prod); // rail local rprt = plan_simple_connection(wt_rail, null, null) if (rprt) { append_report(rprt) } // road rprt = plan_simple_connection(wt_road, null, null) if (rprt) { append_report(rprt) } // water rprt = plan_simple_connection(wt_water, null, null) if (rprt) { append_report(rprt) } if (reports.len() == 0) { dbgprint("Set link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y + " to MISSING") industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } // deliver it local r = r_t(RT_READY) r.report = get_report() // append a chain of alternative connector nodes local rchain = r.report while (reports.len()>0) { local rep = get_report() if (rep == null) { // may happen if no nice reports are available break; } rchain.action.reports.append( rep ) rchain = rep } local r_amph = report_t() r_amph.action = amphibious_connection_planner_t(fsrc, fdest, freight) if (rchain) { rchain.action.reports.append( r_amph ) } else { r.report = r_amph } local toc = get_ops_total(); print("industry_connection_planner wasted " + (toc-tic) + " ops") return r } /** * Plans a connection using one mode of transport * * If start or target are null then use fsrc/fdest. */ function plan_simple_connection(wt, start, target, distance = 0) { // set line build cost 0 industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 1) industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 2) industry_manager.set_link_build_cost(fsrc, fdest, freight, 0, 3) // compute correct distance if (distance == 0) { foreach(i in ["x", "y"]) { distance += abs( (start ? start[i] : fsrc[i]) - (target ? target[i] : fdest[i])) } } if (distance == 0) { // still zero? avoid division by zero in the prototyper // distance factorys distance = abs(fsrc.x - fdest.x) + abs(fsrc.y - fdest.y) // add 10% from distance distance + (distance / 100 * 10) } // plan convoy prototype local prototyper = prototyper_t(wt, freight) prototyper.min_speed = 1 prototyper.max_vehicles = get_max_convoi_length(wt) prototyper.max_length = prototyper.max_vehicles * 8 local freight_input = fdest.input[freight].get_base_consumption() local freight_output = fsrc.output[freight].get_base_production() prototyper.volume = min(freight_input, freight_output) if ( print_message_box == 5 ) { gui.add_message_at(our_player, "freight_input " + freight_input + " freight_output " + freight_output, world.get_time()) gui.add_message_at(our_player, "min(freight_input, freight_output) " + min(freight_input, freight_output), world.get_time()) } local cnv_valuator = valuator_simple_t() cnv_valuator.wt = wt cnv_valuator.freight = freight cnv_valuator.volume = prod cnv_valuator.max_cnvs = 200 // no signals and double tracks - limit 1 convoy for rail if (wt == wt_rail) { cnv_valuator.max_cnvs = 1 } cnv_valuator.distance = distance if ( print_message_box > 0 ) { gui.add_message_at(our_player, "___________________________ Start plan_simple_connection __________________________", world.get_time()) //gui.add_message_at(our_player, "plan way ", world.get_time()) local t = tile_x(fsrc.x, fsrc.y, 0) gui.add_message_at(our_player, "Plan " + wt_name[wt] + " link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y, t) } if ( debug ) { local t = tile_x(fsrc.x, fsrc.y, 0) gui.add_message_at(our_player, "Plan " + wt_name[wt] + " link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y, t) } local bound_valuator = valuator_simple_t.valuate_monthly_transport.bindenv(cnv_valuator) prototyper.valuate = bound_valuator if (prototyper.step().has_failed()) { if (debug) gui.add_message_at(our_player, "ERROR # no " + wt_name[wt] + " vehicle found for freight " + freight, world.get_time()) return null } local planned_convoy = prototyper.best print("best " + planned_convoy.min_top_speed + " / " + planned_convoy.max_speed) // fill in report when best way is found local r = report_t() // plan way local planned_way = null if (wt == wt_water) { planned_way = openwater } else { local way_list = way_desc_x.get_available_ways(wt, st_flat) local best_way = null local best = null foreach(way in way_list) { if ( !way.is_retired(world.get_time()) ) { cnv_valuator.way_maintenance = way.get_maintenance() cnv_valuator.way_max_speed = way.get_topspeed() local test = cnv_valuator.valuate_monthly_transport(planned_convoy) if (best == null || test > best) { best = test // max track speed 160 if (cnv_valuator.way_max_speed < 161 && wt == wt_rail ) { best_way = way } else { best_way = way } } } } dbgprint("Best value = " + best + " way = " + best_way.get_name()) // valuate again with best way cnv_valuator.way_maintenance = 0 cnv_valuator.way_max_speed = best_way.get_topspeed() planned_way = best_way } local planned_bridge = { cost = 0, montly_cost = 0, tiles = 0 } local tree_cost = 0 // cost remove tree local calc_route = null local p_start = null local p_end = null if (wt != wt_water && wt != wt_air) { /* plan build route */ p_start = ::finder.find_station_place(fsrc, fdest) if ( p_start.len() == 0 ) { calc_route = "No route" } else { p_end = ::finder.find_station_place(fdest, p_start, true) if ( p_end.len() == 0 ) { calc_route = "No route" } else { calc_route = test_route(our_player, p_start, p_end, planned_way) } } //gui.add_message_at(our_player, "calc_route: way tiles = " + calc_route.routes.len() + " bridge tiles = " + calc_route.bridge_lens, world.get_time()) //gui.add_message_at(our_player, "distance " + distance, world.get_time()) if ( calc_route == "No route" ) { // } else { cnv_valuator.distance = calc_route.routes.len() + calc_route.bridge_lens planned_bridge.cost = calc_route.bridge_lens * calc_route.bridge_obj.get_cost() planned_bridge.montly_cost = calc_route.bridge_lens * calc_route.bridge_obj.get_maintenance() planned_bridge.tiles = calc_route.bridge_lens // tree_desc_x.get_price() -> Simutrans r9528+ tree_cost = calc_route.tiles_tree * tree_desc_x.get_price() } } // valuate again with best way r.gain_per_m = cnv_valuator.valuate_monthly_transport(planned_convoy) if ( print_message_box == 1 ) { gui.add_message_at(our_player, "*** ", world.get_time()) gui.add_message_at(our_player, "plan station ", world.get_time()) } // plan station local planned_station = null local planned_harbour_flat = null if ( wt == wt_rail ) { //planned_convoy.length = 12 } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "wt " + wt_name[wt], world.get_time()) gui.add_message_at(our_player, "planned_convoy.length " + planned_convoy.length, world.get_time()) } if (wt != wt_water) { local station_list = building_desc_x.get_available_stations(building_desc_x.station, wt, good_desc_x(freight)) if ( wt == wt_rail ) { planned_station = select_station(station_list, 8, planned_convoy.capacity) } else { planned_station = select_station(station_list, planned_convoy.length, planned_convoy.capacity) } } else { // find harbour building local station_list = building_desc_x.get_available_stations(building_desc_x.harbour, wt, good_desc_x(freight)) planned_station = select_station(station_list, 1, planned_convoy.capacity) // find flat harbour building station_list = building_desc_x.get_available_stations(building_desc_x.flat_harbour, wt_water, good_desc_x(freight)) planned_harbour_flat = select_station(station_list, 1, planned_convoy.capacity) } // plan depot local planned_depot = null { local depot_list = building_desc_x.get_available_stations(building_desc_x.depot, wt, {}) if (depot_list.len()) { planned_depot = depot_list[0] } } if (planned_convoy == null || planned_way == null || planned_station == null || planned_depot == null) { return null } // create action node local cn = null switch(wt) { case wt_rail: cn = rail_connector_t(); break case wt_road: cn = road_connector_t(); break case wt_water: cn = ship_connector_t(); break } cn.fsrc = fsrc cn.fdest = fdest cn.freight = freight cn.planned_way = planned_way cn.planned_station = planned_station cn.planned_depot = planned_depot cn.planned_convoy = planned_convoy if (start) { cn.c_start = [start] print("Connector from " + coord_to_string(start)) // mark tile for station //set_marker(cn.c_start) } if (target) { cn.c_end = [target] print("Connector to " + coord_to_string(target)) // mark tile for station //set_marker(cn.c_end) } r.distance = cnv_valuator.distance // stations lenght local a = planned_convoy.length local count = 0 do { a -= 16 count += 1 } while(a > 0) // check planned way speed - planned convoy speed if ( wt == wt_air && wt != wt_water && planned_way.get_topspeed() < planned_convoy.min_top_speed ) { //gui.add_message_at(our_player, "-- planned way (" + planned_way.get_topspeed() + ") to low speed for convoy (" + planned_convoy.min_top_speed + ")", world.get_time()) planned_way = find_object("way", wt, planned_convoy.min_top_speed) } // build cost for way, stations and depot local build_cost = ((r.distance * planned_way.get_cost()) + ((count*2)*planned_station.get_cost()) + planned_depot.get_cost() + planned_bridge.cost)/100 + (tree_cost/100*2) // build cost / 13 months //build_cost = build_cost / 13 local rail_station = null if ( wt == wt_rail ) { // terraform cost local terraform_cost = 0 try { terraform_cost = command_x.slope_get_price(82)/100 } catch(ev) { // hat nicht funktioniert terraform_cost = 7500 } build_cost += count*terraform_cost // check build station rail if ( calc_route != "No route" ) { rail_station = check_station(our_player, calc_route.routes[calc_route.routes.len()-1], calc_route.routes, count, wt_rail, planned_station, 0, true) if (rail_station) { rail_station = check_station(our_player, calc_route.routes[0], calc_route.routes, count, wt_rail, planned_station, 0, true) //if (debug) gui.add_message_at(our_player, "-check build station rail- rail_station " + rail_station, calc_route.routes[0]) } //if (debug && !rail_station) gui.add_message_at(our_player, "-check build station rail- rail_station " + rail_station, calc_route.routes[0]) //if (debug) gui.add_message_at(our_player, "-check build station rail- calc_route " + calc_route, world.get_time()) } } // save build cost to link if ( wt == wt_rail ) { industry_manager.set_link_build_cost(fsrc, fdest, freight, build_cost, 1) } else if ( wt == wt_road ) { industry_manager.set_link_build_cost(fsrc, fdest, freight, build_cost, 2) } else if ( wt == wt_water ) { industry_manager.set_link_build_cost(fsrc, fdest, freight, build_cost, 3) } local conv_capacity = planned_convoy.capacity local input_convoy = freight_input/conv_capacity local output_convoy = freight_output/conv_capacity /** * Assessment for the different connections * points calculated in function get_report() (basic.nut) * */ r.points = 100 // to many convoys if ( output_convoy > 200 ) { r.points -= 25 } // low freight volume if ( freight_input < 700 || freight_output < 550 ) { switch (wt) { case wt_rail: r.points -= 15 break case wt_road: r.points += 12 break case wt_water: r.points += 0 break } } // high freight volume if ( freight_input > 2250 || freight_output > 1700 ) { switch (wt) { case wt_rail: r.points += 22 break case wt_road: r.points -= 15 break case wt_water: r.points += 0 break } } // factory distance direct local f_dist = abs(fsrc.x - fdest.x) + abs(fsrc.y - fdest.y) // + 22% for long distance local f_dist_long = f_dist + (f_dist / 100 * 22) // + 35% for short distance local f_dist_short = f_dist + (f_dist / 100 * 35) // cash buffer up to first ingestion - % local cash_buffer = 0 //gui.add_message_at(our_player, "-- world.get_time().year " + world.get_time().year, world.get_time()) // lower share of bridges year ago local bridge_year_factor = 1 if ( world.get_time().year < 1920 ) { if ( wt == wt_road ) { bridge_year_factor = 4 } } else if ( world.get_time().year < 1935 ) { if ( wt == wt_road ) { bridge_year_factor = 3 } } // higt distance if ( r.distance > 350 ) { switch (wt) { case wt_rail: if ( f_dist_long < r.distance ) { r.points += 10 cash_buffer = 20 } else { r.points += 20 cash_buffer = 10 } if ( world.get_time().year < 1935 && planned_bridge.tiles > 18 ) { //gui.add_message_at(our_player, "wt_road: world.get_time().year < 1935 && planned_bridge.tiles > 5", world.get_time()) r.points -= (34*bridge_year_factor) } else if ( planned_bridge.tiles > 40 ) { r.points -= (25*bridge_year_factor) } if ( planned_convoy.max_speed < 50 ) { //gui.add_message_at(our_player, "wt_rail planned_convoy.max_speed " + planned_convoy.max_speed, world.get_time()) r.points -= 20 } break case wt_road: if ( f_dist_long < r.distance ) { r.points -= 25 cash_buffer = 20 } else { r.points -= 10 cash_buffer = 20 } if ( planned_bridge.tiles > 15 ) { r.points -= (32*bridge_year_factor) } if ( planned_convoy.max_speed < 40 ) { //gui.add_message_at(our_player, "wt_road planned_convoy.max_speed " + planned_convoy.max_speed, world.get_time()) r.points -= 20 } break case wt_water: if ( f_dist_long < r.distance ) { r.points -= 20 cash_buffer = 20 } else { r.points += 0 cash_buffer = 20 } break } if ( r.distance > 450 ) { r.points -= 10 } else if ( r.distance > 550 ) { r.points -= 20 } } // low distance if ( r.distance < 120 ) { switch (wt) { case wt_rail: if ( f_dist_short < r.distance ) { r.points -= 20 cash_buffer = 5 } else { r.points -= 10 cash_buffer = 10 } if ( world.get_time().year < 1935 && planned_bridge.tiles > 8 ) { //gui.add_message_at(our_player, "wt_road: world.get_time().year < 1935 && planned_bridge.tiles > 5", world.get_time()) r.points -= (38*bridge_year_factor) } else if ( planned_bridge.tiles > 15 ) { r.points -= (25*bridge_year_factor) } break case wt_road: if ( f_dist_short < r.distance ) { r.points += 25 cash_buffer = 5 } else { r.points += 10 cash_buffer = 10 } if ( world.get_time().year < 1935 && planned_bridge.tiles > 5 ) { //gui.add_message_at(our_player, "wt_road: world.get_time().year < 1935 && planned_bridge.tiles > 5", world.get_time()) r.points -= (38*bridge_year_factor) } else if ( planned_bridge.tiles > 15 ) { r.points -= (32*bridge_year_factor) } break case wt_water: if ( f_dist_short < r.distance ) { r.points -= 20 cash_buffer = 5 } else { r.points -= 10 cash_buffer = 10 } break } } // middle distance if ( r.distance > 120 && r.distance < 350 ) { switch (wt) { case wt_rail: if ( world.get_time().year < 1935 && planned_bridge.tiles > 12 ) { //gui.add_message_at(our_player, "wt_rail: world.get_time().year < 1935 && planned_bridge.tiles > 5", world.get_time()) r.points -= (22*bridge_year_factor) } else if ( planned_bridge.tiles > 28 ) { r.points -= (15*bridge_year_factor) } break case wt_road: if ( world.get_time().year < 1935 && planned_bridge.tiles > 5 ) { //gui.add_message_at(our_player, "wt_road: world.get_time().year < 1935 && planned_bridge.tiles > 5", world.get_time()) r.points -= (22*bridge_year_factor) } else if ( planned_bridge.tiles > 15 ) { r.points -= (15*bridge_year_factor) } break } } // route <-> factory distance local dist_route_check = 0 if ( get_set_name() == "pak64.german" ) { //gui.add_message_at(our_player, "factorys: f_dist " + f_dist + " - f_dist * 2) " + (f_dist * 2) + " - route len " + r.distance, world.get_time()) dist_route_check = f_dist + (f_dist / 3 * 4) } else { //gui.add_message_at(our_player, "factorys: f_dist " + f_dist + " - f_dist + (f_dist / 3 * 2) " + (f_dist + (f_dist / 3 * 2)) + " - route len " + r.distance, world.get_time()) dist_route_check = f_dist + (f_dist / 3 * 2) } if ( dist_route_check < r.distance ) { switch (wt) { case wt_rail: r.points -= 40 break case wt_road: r.points -= 60 break } } // build rail station if ( rail_station == false ) { r.points -= 200 } // freight weight local g = good_desc_x(freight).get_weight_per_unit() g = (g * 50) / 1000 // weight hight if ( g > 32 ) { switch (wt) { case wt_rail: r.points += 22 break case wt_road: r.points -= 8 break case wt_water: break } } // weight low if ( g < 20 ) { switch (wt) { case wt_rail: r.points -= 12 break case wt_road: r.points += 14 break case wt_water: break } } local road_car_rate = set_map_vehicles_counts(1) if ( print_message_box > 0 && road_car_rate < 10 ) { // gui.add_message_at(our_player, "citycar_count " + citycar_count + " - road_convoy_count " + road_convoy_count + " - citycar_rate " + road_car_rate, world.get_time()) //gui.add_message_at(our_player, "world.get_time().ticks_per_month " + world.get_time().ticks_per_month, world.get_time()) } if ( road_car_rate < 10 ) { switch (wt) { case wt_rail: r.points += 25 break case wt_road: r.points -= 25 break case wt_water: break } } // Adjustments to the pakset //gui.add_message_at(our_player, "get_set_name() " + get_set_name(), world.get_time()) //::debug.pause() if ( get_set_name() == "pak128.german" ) { switch (wt) { case wt_rail: r.points += 20 break case wt_road: r.points -= 15 break case wt_water: break } } if ( get_set_name() == "pak128" ) { switch (wt) { case wt_rail: r.points -= 200 break case wt_road: //r.points -= 15 break case wt_water: break } } // successfull - complete report r.cost_fix = build_cost r.cost_monthly = (r.distance * planned_way.get_maintenance()) + ((count*2)*planned_station.get_maintenance()) + planned_depot.get_maintenance() + planned_bridge.montly_cost // fixed cost convoy local cnv_veh = planned_convoy.veh local cnv_fixed_cost = 0 for (local x = 0; x < cnv_veh.len(); x++ ) { cnv_fixed_cost += cnv_veh[x].get_maintenance() } r.cost_monthly += cnv_fixed_cost //gui.add_message_at(our_player, "cnv_fixed_cost " + cnv_fixed_cost, world.get_time()) r.gain_per_m -= r.cost_monthly sleep() // capital check local cash = our_player.get_current_cash() - r.cost_fix if ( calc_route != null && calc_route != "No route" ) { // if combined station from ship local t = calc_route.routes[calc_route.routes.len()-1] local st_dock = search_station(t, wt_water, 1) if ( st_dock ) { local st = halt_x.get_halt(st_dock[0], our_player) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() == 0 ) { cash = our_player.get_current_net_wealth() - r.cost_fix //gui.add_message_at(our_player, "combined station -> get_current_net_wealth() " + get_current_net_wealth(), world.get_time()) } else { } } } } local m = r.cost_fix/100*cash_buffer if ( r.distance > 350 ) { //gui.add_message_at(our_player, "connection planner r.distance > 350 -> " + r.distance, world.get_time()) m = r.cost_fix/40*cash_buffer } else if ( r.distance > 300 ) { //gui.add_message_at(our_player, "connection planner r.distance > 300 -> " + r.distance, world.get_time()) m = r.cost_fix/60*cash_buffer } else if ( r.distance > 250 ) { //gui.add_message_at(our_player, "connection planner r.distance > 250 -> " + r.distance, world.get_time()) m = r.cost_fix/80*cash_buffer } if ( (cash-m) < 0 ) { r.points -= 50 } // set retire time for report r.retire_time = world.get_time().next_month_ticks + world.get_time().ticks_per_month - 1 /* local txt_message = "Retire: Station " + planned_station.get_retire_date().month + "." + planned_station.get_retire_date().year if ( wt != wt_water && wt != wt_air ) { txt_message += ", Way " + planned_way.get_retire_date().month + "." + planned_way.get_retire_date().year } txt_message += ", Depot " + planned_depot.get_retire_date().month + "." + planned_depot.get_retire_date().year gui.add_message_at(our_player, txt_message, world.get_time()) txt_message = "Convoy " for ( local i = 0; i < planned_convoy.veh.len(); i++ ) { txt_message += " - " + planned_convoy.veh[i].get_retire_date().month + "." + planned_convoy.veh[i].get_retire_date().year } gui.add_message_at(our_player, txt_message, world.get_time()) */ // retire station local min_retire = planned_station.get_retire_date().raw // retire way if ( ( wt != wt_water && wt != wt_air ) && planned_way.get_retire_date().raw < min_retire ) { min_retire = planned_way.get_retire_date().raw } // retire depot if ( planned_depot.get_retire_date().raw < min_retire ) { min_retire = planned_depot.get_retire_date().raw } // retire vehicle convoy for ( local i = 0; i < planned_convoy.veh.len(); i++ ) { if ( planned_convoy.veh[i].get_retire_date().raw < min_retire ) { min_retire = planned_convoy.veh[i].get_retire_date().raw } } //gui.add_message_at(our_player, "retire " + min_retire_month + "." + min_retire_year, world.get_time()) r.retire_obj = min_retire /* gui.add_message_at(our_player, "Plan " + wt_name[wt] + " link for " + freight + " from " + fsrc.get_name() + " at " + fsrc.x + "," + fsrc.y + " to "+ fdest.get_name() + " at " + fdest.x + "," + fdest.y, world.get_time()) if ( calc_route != null && calc_route != "No route" ) { gui.add_message_at(our_player, "calc_route: way tiles = " + calc_route.routes.len() + " bridge tiles = " + calc_route.bridge_lens + " tree tiles = " + calc_route.tiles_tree, world.get_time()) } gui.add_message_at(our_player, " * Report: link points = " + r.points, world.get_time()) */ // successfull - complete report r.action = cn dbgprint("Plan: way = " + planned_way.get_name() + ", station = " + planned_station.get_name() + ", depot = " + planned_depot.get_name()); dbgprint("Report: gain_per_m = " + r.gain_per_m + ", nr_convoys = " + planned_convoy.nr_convoys + ", cost_fix = " + r.cost_fix + ", cost_monthly = " + r.cost_monthly) dbgprint("Report: dist = " + cnv_valuator.distance + " way_cost = " + planned_way.get_cost()) dbgprint("Report: station = " + planned_station.get_cost()+ " depot = " + planned_depot.get_cost()) if ( print_message_box == 4 || debug) { gui.add_message_at(our_player, "----- ", world.get_time()) gui.add_message_at(our_player, "Plan: way = " + planned_way.get_name() + ", station = " + planned_station.get_name() + ", depot = " + planned_depot.get_name(), world.get_time()) gui.add_message_at(our_player, "Report: gain_per_m = " + r.gain_per_m + ", nr_convoys = " + planned_convoy.nr_convoys + ", cost_build = " + r.cost_fix + ", cost_monthly = " + r.cost_monthly, world.get_time()) gui.add_message_at(our_player, "Report: dist = " + r.distance + " way_cost = " + planned_way.get_cost(), world.get_time()) gui.add_message_at(our_player, "Report: station = " + planned_station.get_cost() + " depot = " + planned_depot.get_cost(), world.get_time()) gui.add_message_at(our_player, "Report: bridge tiles = " + planned_bridge.tiles, world.get_time()) gui.add_message_at(our_player, " * Report: freight = " + freight + " convoy capacity = " + conv_capacity, world.get_time()) gui.add_message_at(our_player, " * Report: input amount = " + freight_input + " input amount / convoy capacity = " + input_convoy, world.get_time()) gui.add_message_at(our_player, " * Report: output = " + freight_output + " output / convoy capacity = " + output_convoy, world.get_time()) gui.add_message_at(our_player, " * Report: link points = " + r.points, world.get_time()) } if ( print_message_box > 0 ) { gui.add_message_at(our_player, "___________________________ End plan_simple_connection __________________________", world.get_time()) } return r } function calc_production() { local src_prod = fsrc.output[freight].get_base_production(); local dest_con = fdest.input[freight].get_base_consumption(); // TODO implement production boost factors local src_prod_faktor = fsrc.output[freight].get_production_factor(); local dest_con_faktor = fdest.input[freight].get_consumption_factor(); if ( print_message_box == 5 ) { gui.add_message_at(our_player, "----- factory info -----", world.get_time()) gui.add_message_at(our_player, " fsrc : " + fsrc.get_name(), world.get_time()) gui.add_message_at(our_player, "freight = " + freight + ", output = " + dest_con + ", factor = " + dest_con_faktor, world.get_time()) gui.add_message_at(our_player, "-----", world.get_time()) gui.add_message_at(our_player, " fdest : " + fdest.get_name(), world.get_time()) gui.add_message_at(our_player, "freight = " + freight + ", input = " + src_prod + ", factor = " + src_prod_faktor, world.get_time()) gui.add_message_at(our_player, "--- factory info end ---", world.get_time()) } dbgprint("production = " + src_prod + " / " + dest_con); return min(src_prod,dest_con) } static function select_station(list, length, capacity) { local station_length = (length + CARUNITS_PER_TILE - 1) / CARUNITS_PER_TILE local capacity = capacity local station_capacity = 0 local station_is_terminus = false local best_station = null if ( print_message_box == 2 ) { gui.add_message_at(our_player, "---- station list ----", world.get_time()) } foreach(station in list) { local ok = (best_station == null) local s_capacity = station_length * station.get_capacity() if ( print_message_box == 2 ) { gui.add_message_at(our_player, "station " + station.get_name() + ", type = " + station.get_type(), world.get_time()) } if (!ok && station_length == 1) { // prefer terminus ok = station.is_terminus() && !station_is_terminus if (!ok) { // then prefer stations with enough capacity ok = station_capacity < capacity ? station_capacity < s_capacity : capacity < s_capacity && s_capacity < station_capacity } } if (station_length > 1) { // force non-terminus ok = !station_is_terminus } if (ok) { best_station = station station_capacity = station.get_capacity() station_is_terminus = station.is_terminus() } } if ( print_message_box == 2 ) { gui.add_message_at(our_player, "----> selectet station: " + best_station.get_name(), world.get_time()) } return best_station } } /* * * */ function test_route(pl, starts, ends, way) { local as = astar_builder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) as.bridger = pontifex(pl, way) if (as.bridger.bridge == null) { as.bridger = null } local res = as.search_route(starts, ends, 0) if ("err" in res) { return res.err } return res } /** * check links factory src to factory dest * */ function check_factory_links(f_src, f_dest, good, show_msg = 0) { local print_message_box = 0 local print_status = 0 if ( show_msg == 1 ) { print_status = 1 } local fs = f_src.get_tile_list() local fd = f_dest.get_tile_list() if ( print_message_box == 1 || print_status == 1 ) { gui.add_message_at(our_player, "--> factory: " + f_src.get_name() + " (" + coord_to_string(fs[0]) + ") to factory " + f_dest.get_name() + " (" + coord_to_string(fd[0]) + ") --> good: " + good, world.get_time()) //gui.add_message_at(player_x(1), "--> good: " + good, world.get_time()) } local f_water = 0 local f_water_name = null local stations_fsrc = null local fs_tile = square_x(fs[0].x, fs[0].y).get_ground_tile() if ( fs_tile.is_water && fs_tile.get_halt() ) { stations_fsrc = fs_tile.get_halt().get_connections(good_desc_x(good)) f_water_name = fs_tile.get_halt().get_name() f_water = 1 if ( print_message_box == 2 ) { gui.add_message_at(player_x(1), "--> factory: " + f_src.get_name() + " to factory " + f_dest.get_name(), world.get_time()) gui.add_message_at(player_x(1), "**--> factory on water " + coord_to_string(fs[0]), world.get_time()) print_status = 1 gui.add_message_at(player_x(1), "**--> f_water_name " + f_water_name, world.get_time()) gui.add_message_at(player_x(1), "**--> stations_fsrc.len() " + stations_fsrc.len(), world.get_time()) } } else { // stations from factory src stations_fsrc = f_src.get_halt_list() } // stations from factory dest local stations_fdest = f_dest.get_halt_list() local link_count = 0 if ( stations_fsrc.len() > 0 && stations_fdest.len() > 0 ) { foreach(station in stations_fsrc) { local s = station.get_connections(good_desc_x(good)) if ( s.len() > 0 ) { local i = 0 if ( f_water = 1 && s[0].get_name() == f_water_name && s.len() > 1 ) { i = 1 } if ( print_message_box == 1 || print_status == 1 ) { gui.add_message_at(our_player, station.get_name() + " *--> to station " + s[i].get_name(), world.get_time()) } local f = s[i].get_factory_list() if ( f.len() == 1 || ( f_water == 1 && f.len() == 2 ) ) { local fd_t = f_dest.get_tile_list() local fs_t = f[0].get_tile_list() if ( fd_t[0].x == fs_t[0].x && fd_t[0].y == fs_t[0].y ) { link_count += 1 } } // to do check link by more combined station // test_halt_waytypes(tile) return count waytypes if ( f.len() == 0 ) { local c_station = s[i].get_connections(good_desc_x(good)) } } } } if ( print_message_box == 1 || print_status == 1 ) { gui.add_message_at(player_x(1), "check_factory_links() --> link count factory " + f_src.get_name() + " (" + coord_to_string(fs[0]) + ") to factory " + f_dest.get_name() + " (" + coord_to_string(fd[0]) + "): " + link_count + " # plan Player " + our_player.get_name(), f_src.get_tile_list()[0]) } return link_count } simutrans-124.3/simutrans/ai/sqai_rail/industry_manager.nut000066400000000000000000002725601474050137200242540ustar00rootroot00000000000000/** * Classes to manage industry connections. */ /** * Class to store lines plus extra data. * Derived from line_x, so it inherits all the methods from line_x. */ class my_line_t extends line_x { //dings_bums = 0 // extra data, you can put more such variables here. double_ways_count = 0 // count of double way build double_ways_build = 0 // double way build: 0 = no ; 1 = yes optimize_way_line = 0 // is way line optimize: 0 = no ; 1 = run 1 ; 2 = run 2 .... destroy_line_month = world.get_time().month // test month save line_way_speed = 0 // save way speed for line build_line = world.get_time() // create line next_vehicle_check = world.get_time().ticks + world.get_time().ticks_per_month // save ticks for next vehicle check next_check = world.get_time().ticks stuck_check = 0 // check stuck vehicles halt_length = 0 // tiles from halts add_convoy_time = world.get_time().ticks + world.get_time().ticks_per_month // save ticks for next add convoy - destroy convoy then add time line_bridges_count = 0 // count non player bridges from line line_bridges = [] // array bridge start/end from not player bridges way_line_count = 1 // more lines on way > 1 constructor(line /* line_x */) { base.constructor(line.id) // never change id ! } function _save() { return ::saveinstance("my_line_t", this) } } /** * A link is a connection between two factories. * Save its state here. */ class industry_link_t { f_src = null // factory_x f_dest = null // factory_x freight = null // good_desc_x state = 0 lines = null // array build_cost_link = 0 build_cost_rail = 0 build_cost_road = 0 build_cost_ship = 0 // 1 - link has combined lines combined_link = 0 /* double_ways_count = 0 // count of double way build double_ways_build = 0 // double way build: 0 = no ; 1 = yes optimize_way_line = 0 // is way line optimize: 0 = no ; 1 = yes destroy_line_month = null // test month save line_way_speed = 0 // save way speed for line build_line = 0 // create line next_vehicle_check = 0 // save ticks for next vehicle check */ // next check needed if ticks > next_check // state == st_missing: check availability again // state == st_build: check for possible upgrades next_check = 0 // if world.get_time().ticks > next_check then state is set to free (for state == failed, missing) static st_free = 0 /// not registered static st_planned = 1 /// link is planned static st_failed = 2 /// construction failed, do not try again static st_built = 3 /// connection successfully built static st_missing = 4 /// missing infrastructure, try again later constructor(s,d,f) { f_src = s f_dest = d freight = good_desc_x(f) lines = [] } function append_line(l) { lines.append(my_line_t(l)) } function remove_line(l) { foreach(idx, line in lines) { if (line.id == l.id) { lines.remove(idx) break } } } function _save() { return ::saveinstance("industry_link_t", this) } // upgrade elements in lines array from line_x to my_line_t function update_lines() { if (lines.len() > 0 && lines[0].getclass() == line_x) { local map_to_my_line_t = function(line) { return my_line_t(line); } lines.apply(map_to_my_line_t) } } } /** * Manage the links operated by us. */ class industry_manager_t extends manager_t { link_list = null link_iterator = null // print messages box // 1 = vehicles // 2 = // 3 = print_message_box = 0 constructor() { base.constructor("industry_manager_t") link_list = {} ::industry_manager = this debug = false } /// Generate unique key from link data static function key(src, des, fre) { return ("freight-" + fre + "-from-" + coord_to_key(src) + "-to-" + coord_to_key(des) ).toalnum() } function set_link_state(src, des, fre, state) { local k = key(src, des, fre) try { link_list[k].state = state } catch(ev) { // not existing - create entry local l = industry_link_t(src, des, fre) l.state = state link_list[k] <- l } switch(state) { case industry_link_t.st_built: link_list[k].next_check = today_plus_months(1) local text = "" text = "Transport " + translate(fre) + " from " text += coord(src.x, src.y).href(src.get_name()) + " to " text += coord(des.x, des.y).href(des.get_name()) + "
" if ( des.output.len() == 0 ) { build_check_month = world.get_time().ticks + (3 * world.get_time().ticks_per_month) //gui.add_message_at(our_player, "### " + des.get_name() + " ## end consumer set build_check_month = " + build_check_month, world.get_time()) } else { build_check_month = world.get_time().ticks + world.get_time().ticks_per_month //gui.add_message_at(our_player, "### " + des.get_name() + " ## set build_check_month = " + build_check_month, world.get_time()) } break case industry_link_t.st_missing: link_list[k].next_check = today_plus_months(3) //gui.add_message_at(our_player, "### link " + k + " ## state = " + state, world.get_time()) break case industry_link_t.st_failed: link_list[k].next_check = today_plus_months(12) link_list[k].state = 4 //gui.add_message_at(our_player, "### link " + k + " ## state = " + state, world.get_time()) } } function get_link_state(src, des, fre) { local link = access_link(src, des, fre) return link ? link.state : industry_link_t.st_free } /* * select * 0 - build_cost_link * 1 - build_cost_rail * 2 - build_cost_road * 3 - build_cost_ship * */ function set_link_build_cost(src, des, fre, cost, select) { local k = key(src, des, fre) local l = industry_link_t(src, des, fre) local i = 0 switch(select) { case 0: try { link_list[k].build_cost_link = cost } catch(ev) { // not existing - create entry l.build_cost_link = cost i = 1 } break case 1: try { link_list[k].build_cost_rail = cost } catch(ev) { // not existing - create entry l.build_cost_rail = cost i = 1 } break case 2: try { link_list[k].build_cost_road = cost } catch(ev) { // not existing - create entry l.build_cost_road = cost i = 1 } break case 3: try { link_list[k].build_cost_ship = cost } catch(ev) { // not existing - create entry l.build_cost_ship = cost i = 1 } break } if ( i == 1 ) { link_list[k] <- l } } function get_link_build_cost(src, des, fre, select) { local link = access_link(src, des, fre) switch(select) { case 0: return link.build_cost_link break case 1: return link.build_cost_rail break case 2: return link.build_cost_road break case 3: return link.build_cost_ship break } } function set_combined_link(src, des, fre, state) { local k = key(src, des, fre) try { link_list[k].combined_link = state } catch(ev) { // not existing - create entry local l = industry_link_t(src, des, fre) l.combined_link = state link_list[k] <- l } } function get_combined_link(src, des, fre) { local link = access_link(src, des, fre) return link.combined_link } function access_link(src, des, fre) { local k = key(src, des, fre) local res try { res = link_list[k] } catch(ev) { res = null } return res } /** * Loop through all links. */ function work() { month_check_message() set_map_vehicles_counts() // iterate the link_iterator, which is a generator if (link_iterator == null) { // this is a generator link_iterator = link_iteration() } if (link_iterator.getstatus() != "dead") { resume link_iterator } else { link_iterator = null return r_t(RT_SUCCESS); } return r_t(RT_PARTIAL_SUCCESS); } function link_iteration() { foreach(link in link_list) { if (!check_link(link)) { continue } yield link } } /** * Check link: * - if state is st_missing set state to st_free after some time * - for working links see after their lines * - @returns true if some work was done */ function check_link(link) { //gui.add_message_at(our_player, "#######" + link.f_src + " - " + link.f_src.get_name() + " - link.state " + link.state, world.get_time()) switch(link.state) { case industry_link_t.st_free: break case industry_link_t.st_planned: return false case industry_link_t.st_built: if (link.lines.len()==0) return false break case industry_link_t.st_failed: break case industry_link_t.st_missing: if (link.next_check >= world.get_time().ticks) return false // try to plan again link.state = industry_link_t.st_free link.next_check = 0 return false } // iterate through all lines foreach(index, line in link.lines) { if ( line.is_valid() ) { //gui.add_message_at(our_player, "####### valid line " + line.get_name(), world.get_time()) if ( line.next_vehicle_check < world.get_time().ticks ) { check_link_line(link, line) } } else { //gui.add_message_at(our_player, "####### invalid line " + line, world.get_time()) link.lines.remove(index) } } return true } /** * * * */ function check_pl_lines() { local line_list = player_x(our_player.nr).get_line_list() /* f_src = s f_dest = d freight = good_desc_x(f) */ local print_message_box = 0 local pl_lines = [] local line_ai_count = 0 foreach(link in link_list) { //gui.add_message_at(player_x(our_player.nr), " ####### link check: f_src " + link.f_src.get_name() + " f_dest " + link.f_dest.get_name() + " freight " + link.freight.get_name(), world.get_time()) foreach(index, line in link.lines) { //gui.add_message_at(player_x(our_player.nr), "####### line check " + line.get_name(), world.get_time()) if ( line.is_valid() && line.get_owner().nr == our_player.nr ) { line_ai_count++ pl_lines.append(line) } } } local ai_lines_missing = [] if ( pl_lines.len() > 0 ) { foreach(line in line_list) { local c = 0 for ( local i = 0; i < pl_lines.len(); i++ ) { if ( line.get_name() == pl_lines[i].get_name() ) { c = 1 break } } if ( c == 0 ) { ai_lines_missing.append(line) } } } //::debug.pause() //gui.add_message_at(player_x(our_player.nr), " ####### line check: line_list.get_count() " + line_list.get_count() + " ## line_ai_count " + line_ai_count, world.get_time()) // if ( line_list.get_count() > line_ai_count ) { for ( local i = 0; i < ai_lines_missing.len(); i++ ) { // rename line local line_name = ai_lines_missing[i].get_name() local str_search = ") " + translate("Line") local st_names = ai_lines_missing[i].get_schedule().entries local wt_name = ["", "road", "Train", "Ship"] local f_src = st_names[0].get_halt(our_player).get_factory_list() local f_dest = st_names[st_names.len()-1].get_halt(our_player).get_factory_list() local freight = "" if ( f_src.len() == 1 && f_dest.len() == 1 ) { // list output goods local good_list_out = [] foreach(good, islot in f_src[0].output) { good_list_out.append(good) } if ( good_list_out.len() == 1 ) { // one good output freight = good_list_out[0] } else { // more output goods - check good to f_dest //local good_list_in = [] foreach(good, islot in f_dest[0].input) { //good_list_in.append(good) for ( local i = 0; i < good_list_out.len(); i++ ) { if ( good_list_out[i] == good && freight == "" ) { freight = good } } } // todo more goods check } } else if ( f_src.len() == 0 || f_dest.len() == 0 ) { // combined line if ( f_src.len() == 0 && f_dest.len() == 1 ) { local connect_lines = st_names[0].get_halt(our_player).get_line_list() local cline_list = [] foreach(line in connect_lines) { if ( line.get_name() != line_name ) { cline_list.append(line) } } if ( cline_list.len() == 1 ) { local cline_st_names = cline_list[0].get_schedule().entries f_src = cline_st_names[0].get_halt(our_player).get_factory_list() if ( f_src.len() == 1 ) { local good_list_out = [] foreach(good, islot in f_src[0].output) { good_list_out.append(good) } if ( good_list_out.len() == 1 ) { // one good output freight = good_list_out[0] } else { // more output goods - check good to f_dest //local good_list_in = [] foreach(good, islot in f_dest[0].input) { ///good_list_in.append(good) for ( local i = 0; i < good_list_out.len(); i++ ) { if ( good_list_out[i] == good && freight == "" ) { freight = good } } } // todo more goods check } } } } }// todo check by more factorys // rename standard line name '(x) Line' if ( line_name.find(str_search) != null && freight != "" ) { local new_name = translate(wt_name[ai_lines_missing[i].get_waytype()]) + " " + translate(freight) + " " + st_names[0].get_halt(our_player).get_name() + " - " + st_names[st_names.len()-1].get_halt(our_player).get_name() //gui.add_message_at(player_x(our_player.nr), our_player.get_name() + " ####### line rename: " + line_name, world.get_time()) //gui.add_message_at(player_x(our_player.nr), our_player.get_name() + " ####### new name: " + new_name, world.get_time()) ai_lines_missing[i].set_name(new_name) } if ( freight != "" ) { //missing line add ai line list industry_manager.set_link_state(f_src[0], f_dest[0], freight, industry_link_t.st_built) industry_manager.access_link(f_src[0], f_dest[0], freight).append_line(ai_lines_missing[i]) } } } if ( line_list.get_count() > line_ai_count ) { if ( print_message_box == 1 ) { gui.add_message_at(player_x(our_player.nr), our_player.get_name() + " ####### line check: not all listet in ai lines ", world.get_time()) gui.add_message_at(player_x(our_player.nr), " ####### line check: line_list.get_count() " + line_list.get_count() + " ## line_ai_count " + line_ai_count, world.get_time()) } for ( local i = 0; i < ai_lines_missing.len(); i++ ) { gui.add_message_at(player_x(our_player.nr), "####### line missing " + ai_lines_missing[i].get_name(), world.get_time()) } } } /** * Manages convoys of one line: withdraw if there are too many, build new ones, upgrade to newer vehicles */ function check_link_line(link, line) { if ( debug ) ::debug.set_pause_on_error(true) // set first run as line build time /*if ( line.build_line == 0 ) { line.build_line = world.get_time() }*/ // set next check line.next_check = world.get_time().ticks + world.get_time().ticks_per_month // 0 = off // 1 // 2 = station expand // 3 // 4 = cnv status retired / all to old // 5 = electrified // 6 and pl 4 local print_message_box = 0 local wt = line.get_waytype() // find route local nexttile = [] if (wt != wt_water && wt != wt_air) { local entries = line.get_schedule().entries local start = null local end = null if ( entries.len() >= 2 ) { start = tile_x(entries[0].x, entries[0].y, entries[0].z) end = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) } local asf = astar_route_finder(wt) local result = asf.search_route([start], [end]) // result is contains routes-array or error message // route is backward from end to start if ("err" in result) { gui.add_message_at(our_player, " ### no route found: " + result.err, start) gui.add_message_at(our_player, " ### line: " + line.get_name(), world.get_time()) gui.add_message_at(our_player, " ### start: " + coord3d_to_string(start) + " ### end: " + coord_to_string(end), start) return //nexttile } else { //gui.add_message_at(our_player, " ### route found: length = " + result.routes.len(), start) // route found, mark tiles foreach(node in result.routes) { local tile = tile_x(node.x, node.y, node.z) nexttile.append(tile) } sleep() } } dbgprint("Check line " + line.get_name()) if ( our_player.nr == 6 && print_message_box == 6 ) { gui.add_message_at(our_player, "Check line " + line.get_name(), world.get_time()) } local line_new = 0 local bilanz_year = 0 if ( line.get_owner().nr == our_player.nr ) { // non profit in 5 months then destroy line //cnv.get_distance_traveled_total() > 3 && local profit_count = line.get_profit() //if ( cnv.get_distance_traveled_total() < 3 ) { return } local month_check = 0 for ( local i = 0; i < 12; i++ ) { bilanz_year += profit_count[i] if ( our_player.nr == 3 && print_message_box == 6 ) { //gui.add_message_at(our_player, "bilanz_year += profit_count["+i+"] " + bilanz_year, world.get_time()) } if ( i >= 4 ) { month_check += profit_count[i] } } if ( bilanz_year < 0 ) { /* gui.add_message_at(our_player, "Check line " + line.get_name(), world.get_time()) gui.add_message_at(our_player, "bilanz_year " + bilanz_year, world.get_time()) gui.add_message_at(our_player, "month_check " + month_check, world.get_time()) //::debug.pause()*/ } //profit_count[4] <= 0 && if ( profit_count[3] <= 0 && profit_count[2] <= 0 && profit_count[1] <= 0 && profit_count[0] <= 0 && month_check != 0) { //line.get_traveled_distance() > 1 && line.get_traveled_distance() < 25 && line.get_loading_level() == 0 && local chk_f_link = check_factory_links(link.f_src, link.f_dest, link.freight.get_name()) if ( bilanz_year <= 0 && print_message_box > 0 ) { gui.add_message_at(our_player, "(488) : Check line " + line.get_name(), world.get_time()) gui.add_message_at(our_player, "(488) : chk_f_link " + chk_f_link, world.get_time()) gui.add_message_at(our_player, "(488) : line.destroy_line_month " + line.destroy_line_month + " -#- " + (world.get_time().month+1), world.get_time()) //::debug.pause() } if ( line.destroy_line_month != (world.get_time().month+1) && (chk_f_link > 1 || (chk_f_link == 1 && link.f_src.get_suppliers().len() == 0 && link.f_dest.get_consumers().len() == 0) || (bilanz_year <= 0 && chk_f_link > 1)) ) { local erreg = destroy_line(line, link.freight, link) //gui.add_message_at(our_player, "(495) : destroy_line(line, link.freight, link) = " + erreg, world.get_time()) if ( erreg == false ) { line.destroy_line_month = world.get_time().month } else if ( erreg == true ) { link.state = 4 return } else if ( erreg == null ) { link.state = 4 return } // line not complete local entries = line.get_schedule().entries local start_l = null local end_l = null if ( wt == wt_water ) { if ( entries.len() >= 2 ) { local start_h = entries[0].get_halt(our_player) local end_h = entries[entries.len()-1].get_halt(our_player) local t = start_h.get_tile_list() start_l = tile_x(t[0].x, t[0].y, t[0].z) t = end_h.get_tile_list() end_l = tile_x(t[0].x, t[0].y, t[0].z) } } else { if ( entries.len() >= 2 ) { start_l = tile_x(entries[0].x, entries[0].y, entries[0].z) end_l = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) } } if ( test_halt_waytypes(end_l) == 1 && end_l.get_halt().get_factory_list().len() == 0 ) { local erreg = destroy_line(line, link.freight, link) /*if ( bilanz_year < 0 ) { gui.add_message_at(our_player, "line 490 : erreg = destroy_line " + erreg, world.get_time()) }*/ if ( erreg == false ) { line.destroy_line_month = world.get_time().month } else if ( erreg == true ) { link.state = 4 return } } } else { //gui.add_message_at(our_player, "return cnv/line new " + line.get_name(), world.get_time()) } if ( month_check == 0 ) { line_new = 1 } } } // find convoy local cnv = null local cnv_count = 0 local cnv_max_speed = 0 local cnv_retired = [] local new_cnv_add_line = false local stucked_cnv = [] { local list = [] // remove withdrawn convois foreach(cnv in line.get_convoy_list()) { if (cnv.is_valid() && !cnv.is_withdrawn()) { list.append(cnv); } } cnv_count = list.len() if (cnv_count == 0 || ( bilanz_year == 0 && cnv_count == 1 )) { // 0 convoy destroy line // 1 convoy and profit year 0 if ( line.get_owner().nr == our_player.nr ) { destroy_line(line, link.freight, link) sleep() } /*if ( bilanz_year < 0 ) { gui.add_message_at(our_player, "line 536 : destroy_line ", world.get_time()) }*/ return } local entries = line.get_schedule().entries local start_h = entries[0].get_halt(our_player) local end_l = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) // remove stucked convoy // cnv_count > 10 then remove cnv_count/2 local cnv_remove_count = cnv_count if ( cnv_count > 10 ) { cnv_remove_count = abs(cnv_count / 2) //gui.add_message_at(our_player, "(738) #### cnv_remove_count " + cnv_remove_count, world.get_time()) } local loading_cnv_stucked = 0 for ( local i = 0; i < cnv_count; i++ ) { if ( !list[i].is_withdrawn() && cnv == null ) { cnv = list[i] } // stucked convoy destroy local d = list[i].get_traveled_distance() if ( list[i].get_distance_traveled_total() > 0 && d[0] == 0 && d[1] == 0 && list[i].is_loading() == false && cnv_count > 1 && list[i].get_loading_level() == 0 && stucked_cnv.len() <= cnv_remove_count ) { //gui.add_message_at(our_player, "####### destroy stucked road vehicles " + cnv_count, world.get_time())list[i].get_waytype() == wt_road && stucked_cnv.append(list[i]) //remove_cnv++ } // destroy convoys in depots if ( list[i].is_in_depot() ) { stucked_cnv.append(list[i]) } // destroy no waiting goods if ( start_h != null ) { local d = start_h.get_waiting() if ( d[0] == 0 && list[i].is_loading() == false && stucked_cnv.len() <= cnv_remove_count && list[i].get_loading_level() == 0 ) { //gui.add_message_at(our_player, "(605) ####### " + start_h.get_name() + " - destroy waiting road vehicles ", world.get_time()) stucked_cnv.append(list[i]) //remove_cnv++ } } // stucked loaded convoy if ( d[0] == 0 && d[1] == 0 && list[i].get_loading_level() > 0 && loading_cnv_stucked == 0 && line.get_waytype() == wt_road ) { loading_cnv_stucked = 1 //gui.add_message_at(our_player, "(768) #### loading convoy stucked ", world.get_time()) local traffic_obj = find_signal("traffic_light", line.get_waytype()) if ( traffic_obj != null ) { // end_l local asf = astar_route_finder(wt) local result = asf.search_route([list[i].get_pos()], [end_l]) local route_tile = [] if ("err" in result) { } else { foreach(node in result.routes) { local tile = tile_x(node.x, node.y, node.z) route_tile.append(tile) } sleep() } local traffic_build = 0 for ( local s = 0; s < route_tile.len(); s++ ) { local test_way = route_tile[s].find_object(mo_way) local test_traffic_light = route_tile[s].find_object(mo_roadsign) if ( test_traffic_light == null && dir.is_threeway(route_tile[s].get_way_dirs(wt_road)) && (test_way.get_owner().nr == our_player_nr || test_way.get_owner().nr == 1) ) { local err = command_x.build_sign_at(our_player, route_tile[s], traffic_obj) traffic_build++ } else if ( test_traffic_light != null ) { traffic_build++ } if ( traffic_build >= 2 ) { continue } } } } } // stucked vehicle remove, not last vehicle if ( stucked_cnv.len() > 0 ) { local j = stucked_cnv.len() if ( cnv_count == j ) { j-- } for ( local i = 0; i < j; i++ ) { if ( stucked_cnv[i].is_valid() ) { stucked_cnv[i].destroy(our_player) } } sleep() local road_car_rate = set_map_vehicles_counts(1) local next_time = road_line_check if ( road_car_rate < 10 ) { next_time = road_line_check / 2 } if ( line.get_waytype() == wt_road ) { line.next_vehicle_check = world.get_time().ticks + next_time if ( cnv_remove_count < cnv_count ) { line.next_vehicle_check = world.get_time().ticks + (next_time * 4) } if ( line.stuck_check == 1 ) { // small check intervall line.next_vehicle_check = world.get_time().ticks + (next_time / 2) } } else { line.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 2) // set longer time for add convoy by remove convoy in last 6 month local cnv_line = line.get_convoy_count() local a = 0 for ( local x = 1; x < 8; x++ ) { if ( cnv_line[x] <= cnv_line[0] ) { a++ } } line.add_convoy_time = line.next_vehicle_check + (world.get_time().ticks_per_month * a) //gui.add_message_at(our_player, "#656# line.add_convoy_time : " + line.add_convoy_time + " -- a : " + a, world.get_time()) } local msgtext = format(translate("%s removes convoys from line: %s"), our_player.get_name(), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) return } if ( line_new == 1 ) { return } // check speed from convoys local a = convoy_max_speed(list[0]) cnv_max_speed = a // check cnv is retired first cnv if ( list[0].has_obsolete_vehicles() && !list[0].is_withdrawn() ) { if ( print_message_box == 4 ) { gui.add_message_at(our_player, " retired convoy " + list[0].get_name(), world.get_time()) } cnv_retired.append(list[0]) } local veh_count_line = line.get_convoy_count() if ( veh_count_line[0] > veh_count_line[1] ) { // not remove cnv from line by add cnv this month new_cnv_add_line = true //gui.add_message_at(our_player, "####### cnv new this month ", world.get_time()) } //&& !new_cnv_add_line local speed_count = 1 for ( local i = 1; i < cnv_count; i++ ) { local s = convoy_max_speed(list[i]) if ( a == s ) { speed_count++ } else if ( a < s ) { cnv_max_speed = s } // check cnv is retired all cnv if ( list[i].has_obsolete_vehicles() && !list[i].is_withdrawn() ) { if ( print_message_box == 4 ) { gui.add_message_at(our_player, " retired convoy " + list[i].get_name(), world.get_time()) } cnv_retired.append(list[i]) } } //gui.add_message_at(our_player, " max speed " + cnv_max_speed, world.get_time()) if ( speed_count < cnv_count && wt != wt_rail ) { // update convoys - retire slower convoys local k = 0 for ( local i = 0; i < cnv_count; i++ ) { if ( convoy_max_speed(list[i]) < cnv_max_speed && !list[i].is_withdrawn() ) { list[i].toggle_withdraw(our_player) k++ } } if ( k > 0 ) { local msgtext = format(translate("vehicles of the line %s were retired"), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) return } } else if ( cnv_count == cnv_retired.len() ) { // all cnv retired if ( print_message_box == 4 ) { gui.add_message_at(our_player, " all convoys to old -> upgrade_link_line", world.get_time()) } upgrade_link_line(link, line, cnv_max_speed, nexttile) return } if ( cnv_retired.len() > 0 && cnv_retired.len() < cnv_count ) { // update convoys - retire retired convoys local k = 0 for ( local i = 0; i < cnv_retired.len(); i++ ) { if ( !cnv_retired[i].is_withdrawn() ) { cnv_retired[i].toggle_withdraw(our_player) k++ } } if ( k > 0 ) { local msgtext = format(translate("vehicles of the line %s were retired"), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) return } } else if ( cnv_retired.len() == 1 && cnv_retired.len() == cnv_count ) { //gui.add_message_at(our_player, "*** cnv_upgrade = 1 -> line " + line.get_name(), world.get_time()) // create new convoy before retire retired convoy link.next_check = today_plus_months(1) if ( upgrade_link_line(link, line, cnv_max_speed, nexttile) ) { // update successful return } } } sleep() if ( cnv == null || !cnv.is_valid() ) { return } // find route //local nexttile = [] local nexttile_r = [] if (wt != wt_water && wt != wt_air) { local entries = cnv.get_schedule().entries local start = null local end = null if ( entries.len() >= 2 ) { start = tile_x(entries[0].x, entries[0].y, entries[0].z) end = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) } local asf = astar_route_finder(wt) if ( wt == wt_rail && line.double_ways_build > 0 ) { // return way for upgrade double ways local result = asf.search_route([end], [start]) if ("err" in result) { } else { foreach(node in result.routes) { local tile = tile_x(node.x, node.y, node.z) nexttile_r.append(tile) } sleep() } } } // check bridges other player in route if ( line.line_bridges.len() > 0 ) { local g = line.line_bridges for ( local x = 0; 0 < g.len(); x++ ) { local gt = g[x] if ( gt[0].is_bridge == false && gt[1].is_bridge == false ) { local bridge_obj = find_object("bridge", wt, line.line_way_speed) command_x.build_bridge(our_player, gt[0], gt[1], bridge_obj) if ( debug ) gui.add_message_at(our_player, "**** line 800 - build missing bridge in route ## ", gt[0]) } } //if ( debug ) gui.add_message_at(our_player, "**** line 816 - line_bridges_count = " + line.line_bridges_count + " ## ", g[0]) } if ( wt == wt_road && line.stuck_check == 0 ) { local way_count = nexttile.len() for ( local x = 1; x < 5; x++ ) { local t = nexttile[way_count-x]; local d = t.get_way_dirs(wt) if ( dir.is_threeway(d) ) { line.stuck_check = 1 gui.add_message_at(our_player, "**** line 1007 - set line.stuck_check = 1 ", t) break } } } // count bridges from other player if ( wt == wt_road && line.line_bridges_count == 0 ) { local tiles = nexttile local bridge_start = null local bridge_end = null for ( local x = 0; x < tiles.len(); x++ ) { if ( tiles[x].is_bridge() && bridge_start != null ) { local test_bridge = tiles[x].find_object(mo_bridge) //.get_desc() if ( test_bridge.get_owner().nr != our_player_nr && bridge_start == null ) { bridge_start = tiles[x] } } else if ( bridge_start != null && tiles[x].is_bridge() == false ) { bridge_end = tiles[x-1] line.line_bridges.append([bridge_start, bridge_end]) line.line_bridges_count++ bridge_start = null bridge_end = null } } if ( line.line_bridges.len() > 0 ) { local g = line.line_bridges[0] if ( debug ) gui.add_message_at(our_player, "**** line 828 - line_bridges_count = " + line.line_bridges_count + " ## ", g[0]) } } if (our_player.get_current_cash() > 50000 && wt != wt_water && wt != wt_air) { if ( line.optimize_way_line == 0 ) { // optimize way line befor build double ways local err = optimize_way_line(nexttile, wt, line.optimize_way_line, line) if ( err ) { line.optimize_way_line = 1 } } else if ( line.optimize_way_line == 1 && our_player.get_current_cash() > 500000 ) { local err = optimize_way_line(nexttile, wt, line.optimize_way_line, line) if ( err ) { line.optimize_way_line = 2 } } else if ( line.optimize_way_line == 2 && our_player.get_current_cash() > 1000000 ) { local err = optimize_way_line(nexttile, wt, line.optimize_way_line, line) if ( err ) { line.optimize_way_line = 3 } } else if ( line.optimize_way_line == 3 && our_player.get_current_cash() > 1000000 && world.get_time().year >= 1950 ) { local err = optimize_way_line(nexttile, wt, line.optimize_way_line, line) if ( err ) { line.optimize_way_line = 4 } } } if ( bilanz_year < 0 ) { //gui.add_message_at(our_player, " line 756 - bilanz_year < 0", world.get_time()) //::debug.pause() } // way speed //gui.add_message_at(our_player, " -##- " + link.line_way_speed + " old speed save line " + line.get_name(), world.get_time()) //gui.add_message_at(our_player, " cnv max speed " + cnv_max_speed, world.get_time()) if ( cnv_max_speed > line.line_way_speed && nexttile.len() > 3 ) { local way_speed = 500 local upgrade_tiles = 0 for ( local i = 0; i < nexttile.len(); i++ ) { local tile = tile_x(nexttile[i].x, nexttile[i].y, nexttile[i].z) local tile_way = tile.find_object(mo_way) if ( tile_way != null && (tile_way.get_owner().nr == our_player_nr || tile_way.get_owner().nr == 1) && ( !tile.has_two_ways() && !tile.is_bridge() ) ) { upgrade_tiles++ if ( tile_way.get_desc().get_topspeed() < way_speed ) { way_speed = tile_way.get_desc().get_topspeed() } if ( tile_way.get_desc().get_topspeed() == 45 && print_message_box == 1 ) { gui.add_message_at(our_player, way_speed + " way speed tile " + coord3d_to_string(tile_x(nexttile[i].x, nexttile[i].y, nexttile[i].z)), tile_x(nexttile[i].x, nexttile[i].y, nexttile[i].z)) } } } // check double ways by rail if ( wt == wt_rail && line.double_ways_build > 0 ) { for ( local i = 0; i < nexttile_r.len(); i++ ) { local tile = tile_x(nexttile_r[i].x, nexttile_r[i].y, nexttile_r[i].z) local tile_way = tile.find_object(mo_way) if ( tile_way.get_owner().nr == our_player_nr ) { //upgrade_tiles++ if ( tile_way.get_desc().get_topspeed() < way_speed && ( !tile.has_two_ways() && !tile.is_bridge() ) ) { way_speed = tile_way.get_desc().get_topspeed() } } } } line.line_way_speed = way_speed //gui.add_message_at(our_player, way_speed + " way speed line " + line.get_name(), world.get_time()) //gui.add_message_at(our_player, upgrade_tiles + " possible tiles for upgrading ", world.get_time()) //gui.add_message_at(our_player, " cnv max speed " + cnv_max_speed, world.get_time()) // upgrade way local way_obj = find_object("way", wt, cnv_max_speed) //gui.add_message_at(our_player, " way max speed new " + way_obj.get_topspeed(), world.get_time()) if ( cnv_max_speed >= way_speed && upgrade_tiles > 2 ) { local costs = (upgrade_tiles*(way_obj.get_cost()/100)) local count_build = 0 if ( wt == wt_rail && line.double_ways_build > 0 ) { costs += line.double_ways_count*8*(way_obj.get_cost()/100) } if ( our_player.get_current_cash() > costs ) { for ( local i = 1; i < nexttile.len(); i++ ) { local tile_way_1 = tile_x(nexttile[i-1].x, nexttile[i-1].y, nexttile[i-1].z) local tile_way_2 = tile_x(nexttile[i].x, nexttile[i].y, nexttile[i].z) if ( tile_way_2.find_object(mo_way) != null && (tile_way_2.find_object(mo_way).get_owner().nr == our_player_nr || tile_way_2.find_object(mo_way).get_owner().nr == 1) && tile_way_2.find_object(mo_way).get_desc().get_topspeed() < way_obj.get_topspeed() ) { command_x.build_way(our_player, tile_way_1, tile_way_2, way_obj, true) count_build++ } } // build double ways by rail if ( wt == wt_rail && line.double_ways_build > 0 ) { for ( local i = 1; i < nexttile_r.len(); i++ ) { local tile_way_1 = tile_x(nexttile_r[i-1].x, nexttile_r[i-1].y, nexttile_r[i-1].z) local tile_way_2 = tile_x(nexttile_r[i].x, nexttile_r[i].y, nexttile_r[i].z) if ( tile_way_2.find_object(mo_way) != null && (tile_way_2.find_object(mo_way).get_owner().nr == our_player_nr || tile_way_2.find_object(mo_way).get_owner().nr == 1) && tile_way_2.find_object(mo_way).get_desc().get_topspeed() < way_obj.get_topspeed() ) { command_x.build_way(our_player, tile_way_1, tile_way_2, way_obj, true) count_build++ } } } } local start_l = nexttile[nexttile.len()-1] local end_l = nexttile[0] if (count_build > 0 ) { local msgtext = format(translate("%s extends the route from %s (%s) to %s (%s)"), our_player.get_name(), start_l.get_halt().get_name(), coord_to_string(start_l), end_l.get_halt().get_name(), coord_to_string(end_l)) gui.add_message_at(our_player, msgtext, start_l) //gui.add_message_at(our_player, " upgrade way ", world.get_time()) } line.line_way_speed = way_obj.get_topspeed() } else { // set new way speed by not upgrade way line.line_way_speed = way_obj.get_topspeed() } } /*if ( bilanz_year < 0 ) { gui.add_message_at(our_player, " line 849 ", world.get_time()) //::debug.pause() }*/ if (cnv.is_valid() && cnv.is_withdrawn()) { // come back later if ( print_message_box > 0 ) { gui.add_message_at(our_player, "cnv.is_valid() && cnv.is_withdrawn() ", world.get_time()) } return } // try to upgrade /* if (cnv.has_obsolete_vehicles() && link.next_check < world.get_time().ticks) { link.next_check = today_plus_months(1) if (upgrade_link_line(link, line)) { // update successful gui.add_message_at(our_player, "*** upgrade_link_line -> line " + line.get_name(), world.get_time()) return } } */ local lf = link.freight // capacity of convoy local capacity = 0 { //local lf = link.freight foreach(v in cnv.get_vehicles()) { local f = v.get_freight() if (lf.is_interchangeable(f)) { capacity += v.get_capacity() } } } dbgprint("Capacity of convoy " + cnv.get_name() + " = " + capacity) dbgprint("Speed of convoy " + cnv.get_name() + " = " + cnv.get_speed()) // iterate through schedule, check for available freight local freight_available = false local start_l = null local end_l = null { local entries = line.get_schedule().entries if ( entries.len() >= 2 ) { start_l = tile_x(entries[0].x, entries[0].y, entries[0].z) end_l = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) } local i = 0; while(i < entries.len() && !freight_available) { local entry = entries[i] // stations on schedule local halt = entry.get_halt(our_player) if (halt == null) continue // next station on schedule local nexthalt = null i++ while(i < entries.len()) { if (nexthalt = entries[i].get_halt(our_player)) break i++ } if (nexthalt == null) { nexthalt = entries[0].get_halt(our_player) } // freight available ? local freight_on_schedule = halt.get_freight_to_halt(lf, nexthalt) local capacity_halt = halt.get_capacity(lf) dbgprint("Freight from " + halt.get_name() + " to " + nexthalt.get_name() + " = " + freight_on_schedule) // either start is 2/3 full or more good available as one cnv can transport freight_available = (3*freight_on_schedule > 2*capacity_halt) || (freight_on_schedule > capacity); } } /*if ( bilanz_year < 0 ) { gui.add_message_at(our_player, " line 927 ", world.get_time()) //::debug.pause() }*/ // calc gain per month of one convoy local gain_per_m = 0 { local p = line.get_profit() gain_per_m = p.reduce(sum) / (p.len() * cnv_count) dbgprint("Gain pm = " + gain_per_m) } // check state if convoys (loading level, stopped, new) local cc_load = 0 local cc_stop = 0 local cc_new = 0 local cc_empty = 0 local cnv_empty_stopped = null //local remove_cnv = 0 { local list = line.get_convoy_list() //local halt_len = line.halt_length local first_cnv = null local message_show = 0 foreach(c in list) { if (!c.is_valid() || c.is_withdrawn()) { // will be withdrawn, ignore it continue } if ( first_cnv == null ) { first_cnv = c } // convoy empty? local is_empty = c.get_loading_level() == 0 // convoy new? less than 2 months old, and not much transported local d = c.get_traveled_distance() local is_new = (d[0] + d[1] == c.get_distance_traveled_total()) if (is_new) { local t = c.get_transported_goods(); if (t.reduce(sum) >= 2*capacity) { is_new = false } } if (is_new) { cc_new ++ is_empty = false } // new convoys do not count as empty if (is_empty) { cc_empty++ } // convoy stopped? but not for loading local is_stopped = false if (c.get_speed() == 0) { if (c.get_loading_limit() > 0) { // loading cc_load ++ } else { cc_stop ++ is_stopped = true; } } if (is_empty && is_stopped && cnv_empty_stopped==null) { //gui.add_message_at(our_player, "### list.len() " + list.get_count() + " ### first_cnv.get_tile_length() " + first_cnv.get_tile_length() + " ### c.get_tile_length() " + c.get_tile_length(), world.get_time()) if ( list.get_count() == 2 && first_cnv.get_tile_length() < c.get_tile_length() ) { first_cnv.toggle_withdraw(our_player) } else { cnv_empty_stopped = c } } /* // stucked road vehicles destroy if ( c.get_distance_traveled_total() > 0 && d[0] == 0 && d[1] == 0 && c.is_loading() == false && c.get_waytype() == wt_road && cnv_count > 1) { //gui.add_message_at(our_player, "####### destroy stucked road vehicles " + cnv_count, world.get_time()) c.destroy(our_player) cnv_count-- message_show++ //remove_cnv++ }*/ } /*if ( message_show > 0 ) { local msgtext = format(translate("%s removes convoys from line: %s"), our_player.get_name(), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) return true }*/ } dbgprint("Line: loading = " + cc_load + ", stopped = " + cc_stop + ", new = " + cc_new + ", empty = " + cc_empty) dbgprint("") if ( print_message_box == 1 ) { gui.add_message_at(our_player, "freight_available " + freight_available + " cc_new " + cc_new + " cc_stop " + cc_stop + " cnv.is_valid() " + cnv.is_valid(), world.get_time()) } if ( (freight_available && cc_new == 0 && cc_stop < 2 && cnv.is_valid()) || bilanz_year < 0 ) { if ( bilanz_year < 0 ) { //gui.add_message_at(our_player, " line 1029 - bilanz_year < 0", world.get_time()) //::debug.pause() } // stations distance local l = 0 if ( wt == wt_water || wt == wt_air ) { l = abs(start_l.x - end_l.x) + abs(start_l.y - end_l.y) } else { l = check_way_line(start_l, end_l, wt, 0, 0, line) } local c = 0 local t = l % 80 //gui.add_message_at(our_player, "#### way len " + l + " % 80 = " + (l % 80), world.get_time()) //gui.add_message_at(our_player, "#### way len " + l + " / 80 = " + (l / 80), world.get_time()) if ( l > 30 && l <= 90 ) { c = 1 } else if ( l > 70 && l <= 140 ) { c = 2 } else if ( l > 140 && l <= 200 ) { c = 3 } else if ( l > 200 && l <= 330 ) { c = 4 } else if ( l > 330 && l < 460 ) { c = 5 } else if ( l >= 460 ) { c = (l / 80) } // no signals and double tracks - limit 1 convoy for rail if (wt == wt_rail && cnv_count == 1 && c > 0 && line.double_ways_build == 0 ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### cnv.get_waytype() " + cnv.get_waytype() + " cnv.name " + cnv.get_name(), world.get_time()) gui.add_message_at(our_player, "####### lenght " + l + " double ways " + c, world.get_time()) } // // check way for find fields for double track if ( line.optimize_way_line == 0 ) { local err = optimize_way_line(nexttile, wt, line.optimize_way_line, line) if ( err ) { line.optimize_way_line = 1 } } local s_fields = check_way_line(start_l, end_l, wt, l, c, line) local cc = 1 //gui.add_message_at(our_player, "####### type(s_fields) " + type(s_fields), world.get_time()) if ( type(s_fields) == "array" ) { //gui.add_message_at(our_player, "####### s_fields.len() " + s_fields.len(), world.get_time()) if ( s_fields.len() == 0 ) { s_fields = check_way_line(end_l, start_l, wt, l, c, line) } } /* * calculate build cost * */ local build_double_ways = false if ( s_fields != true && c > 0 && s_fields.len() > 0 ) { local obj_sign = find_signal("is_signal", wt) local way_obj = s_fields[0].find_object(mo_way).get_desc() local build_cost = s_fields.len()*(obj_sign.get_cost()*2) build_cost += s_fields.len()*(way_obj.get_cost()*8) // terraform 4 fields build_cost = build_cost+(command_x.slope_get_price(82)*4) // count double ways build_cost = build_cost*c if ( build_cost/100 < (our_player.get_current_cash()+(our_player.get_current_maintenance()/100*5)) ) { build_double_ways = true } else { //gui.add_message_at(our_player, "calculate build cost double ways " + build_cost/100 + " < " + (our_player.get_current_cash()+(our_player.get_current_maintenance()/100*5)), world.get_time()) } } //gui.add_message_at(our_player, "####### s_fields " + s_fields, world.get_time()) if ( s_fields == true ) { cc += c } else if ( build_double_ways == true ) { //gui.add_message_at(our_player, "####### s_fields.len() " + s_fields.len(), world.get_time()) local count_build = 0 local build = false if ( s_fields.len() == c || s_fields.len() == c - 1 ) { if ( s_fields.len() == c - 1 ) { c-- } // count station len start local station_len = 0 for ( local h = 0; h < 50; h++ ) { if ( nexttile[h].find_object(mo_building) != null ) { station_len++ } else { break } } station_len += 3 if ( station_len < 8 ) { station_len = 8 } for ( local i = 0; i < c; i++ ) { build = build_double_track(s_fields[i], wt_rail, station_len) if ( build ) { cc++ count_build++ build = false } } } if (count_build > 0 ) { local msgtext = format(translate("%s extends the route from %s (%s) to %s (%s)"), our_player.get_name(), start_l.get_halt().get_name(), coord_to_string(start_l), end_l.get_halt().get_name(), coord_to_string(end_l)) gui.add_message_at(our_player, msgtext, start_l) } } if ( cc > 1 ) { line.double_ways_count = cc line.double_ways_build = 1 } else { return } } else if (wt == wt_rail && (cnv_count > c || c == 0) ) { return null } //gui.add_message_at(our_player, " line 1384 " + line.get_name() + " - line.way_line_count : " + line.way_line_count + " - line.double_ways_count : " + line.double_ways_count, world.get_time()) if ( wt == wt_rail ) { if ( line.way_line_count == 1 ) { cnv_count = line.double_ways_count + 1 } else if ( line.way_line_count > 1 ) { if ( line.double_ways_count > 2 ) { cnv_count = line.double_ways_count - 1 } else { cnv_count = line.double_ways_count } } //gui.add_message_at(our_player, " line set cnv_count " + cnv_count, world.get_time()) } if ( bilanz_year < 0 ) { //gui.add_message_at(our_player, " line 1149 ", world.get_time()) //gui.add_message_at(our_player, " gain_per_m " + gain_per_m, world.get_time()) //::debug.pause() } // pak192.comic fix // line profit < 0 then not add cnv count > 3 // wt_water local line_profit = line.get_profit() //local line_cnv_count = line.get_convoy_count() //if ( wt == wt_water ) gui.add_message_at(our_player, "#1390# test (line_profit[1] + line_profit[2]) " + (line_profit[1] + line_profit[2]), world.get_time()) //if ( wt == wt_water ) gui.add_message_at(our_player, "#1390# test line.get_convoy_count() " + line_cnv_count[0], world.get_time()) //if ( wt == wt_water ) gui.add_message_at(our_player, "#1390# test cnv_count " + cnv_count, world.get_time()) if ( (line_profit[1] + line_profit[2]) < 0 && cnv_count >= 3 && wt == wt_water ) { //gui.add_message_at(our_player, "#1390# break add cnv ", world.get_time()) line.next_vehicle_check = line.next_vehicle_check + (world.get_time().ticks_per_month * 2) return true } if ( (gain_per_m > 0 || bilanz_year < 0 ) && line.next_vehicle_check < world.get_time().ticks && line.add_convoy_time < world.get_time().ticks ) { // directly append // TODO put into report if ( bilanz_year < 0 ) { // gui.add_message_at(our_player, " line 1161 ", world.get_time()) //::debug.pause() } local proto = cnv_proto_t.from_convoy(cnv, lf) if ( print_message_box == 1 ) { gui.add_message_at(our_player, "###---- check convoys line : " + line.get_name(), world.get_time()) } // plan convoy prototype local freight = lf.get_name() local prototyper = prototyper_t(wt, freight) local proto_speed = cnv_max_speed - 30 if ( proto_speed >= 100 ) { proto_speed = 60 } if ( proto_speed < 1 ) { prototyper.min_speed = 1 } else { prototyper.min_speed = proto_speed } prototyper.max_vehicles = get_max_convoi_length(wt) local expand_station = [] //local station_count = 0 local station_exist = 0 local expand_station_end_src = [] local expand_station_end_dest = [] if ( wt == wt_rail ) { for ( local i = 0; i < 6; i++ ) { //gui.add_message_at(our_player, "###---- nexttile[" + i + "].find_object(mo_building) : " + nexttile[i].find_object(mo_building), world.get_time()) if ( nexttile[i].find_object(mo_building) != null ) { station_exist++ } } expand_station = check_expand_station(nexttile, line) if ( print_message_box == 2 && expand_station.len() > 0 ) { gui.add_message_at(our_player, "#1262##---- station_exist : " + station_exist + " ## expand_station.len() : " + expand_station.len(), world.get_time()) } } if ( expand_station.len() > 0 ) { prototyper.max_length = CARUNITS_PER_TILE * (station_exist + (expand_station.len()/2)) } else if ( wt != wt_road && wt != wt_air && wt != wt_water ) { prototyper.max_length = CARUNITS_PER_TILE * station_exist } else { prototyper.max_length = CARUNITS_PER_TILE //prototyper.max_vehicles * 8 } if ( print_message_box == 2 ) { //gui.add_message_at(our_player, "###---- station_exist : " + station_exist, world.get_time()) //gui.add_message_at(our_player, "###---- prototyper.max_length : " + prototyper.max_length, world.get_time()) } if ( wt == wt_road && check_good_quantity(start_l, end_l, lf, line) ) { line.next_vehicle_check = world.get_time().ticks + (road_line_check * 2) return true } local cnv_valuator = valuator_simple_t() cnv_valuator.wt = wt cnv_valuator.freight = freight local fd = link.f_dest local fs = link.f_src local freight_input = fd.input[freight].get_base_consumption() local freight_output = fs.output[freight].get_base_production() prototyper.volume = min(freight_input, freight_output) //cnv_valuator.volume = line.get_transported_goods().reduce(max) cnv_valuator.max_cnvs = 200 // no signals and double tracks - limit 1 convoy for rail if (wt == wt_rail) { cnv_valuator.max_cnvs = cnv_count } local dist = 0 if ( wt == wt_water || wt == wt_air ) { // through schedule to estimate distance local entries = cnv.get_schedule().entries dist = abs(entries[0].x - entries[1].x) + abs(entries[0].y - entries[1].y) } else { // distance real route dist = nexttile.len() } if (wt == wt_road ) { if ( dist <= 50) { cnv_valuator.max_cnvs = dist/3 } else if ( dist > 50 && dist <= 250 ) { cnv_valuator.max_cnvs = dist/2 } //else if ( dist > 250 ) { cnv_valuator.max_cnvs = dist - 50 } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "### line : " + line.get_name() + " dist: " + dist + " cnv max: " + cnv_valuator.max_cnvs, world.get_time()) } } // add 10% from distance //dist += dist / 100 * 10 if ( wt == wt_rail ) { prototyper.electrified = check_catenary(line, dist, start_l, cnv_max_speed) } cnv_valuator.distance = dist local bound_valuator = valuator_simple_t.valuate_monthly_transport.bindenv(cnv_valuator) prototyper.valuate = bound_valuator if (prototyper.step().has_failed()) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, " ----> prototyper.step().has_failed() ", world.get_time()) } return null } local proto = prototyper.best if ( print_message_box == 1 ) { gui.add_message_at(our_player, " ----> proto : " + proto, world.get_time()) } // build convoy local stations_list = line.get_schedule().entries local depot = null //cnv.get_home_depot() for (local i=0; i station " + coord_to_string(c), c) gui.add_message_at(our_player, "####--> depot " + depot, world.get_time()) } break } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####--> not depot found", world.get_time()) } } if ( depot == null || depot == false ) { //depot = cnv.get_home_depot() local c = cnv.get_home_depot() depot = tile_x(c.x, c.y, c.z) if ( depot.get_depot() == null ) { local way_tile = [null, null, null, null] way_tile[0] = tile_x(depot.x-1, depot.y, depot.z) way_tile[1] = tile_x(depot.x+1, depot.y, depot.z) way_tile[2] = tile_x(depot.x, depot.y-1, depot.z) way_tile[3] = tile_x(depot.x, depot.y+1, depot.z) for ( local i = 0; i < 4; i++ ) { if ( way_tile[i].find_object(mo_way) != null ) { local way_obj = find_object("way", wt, cnv.get_speed()) local depot_obj = building_desc_x.get_available_stations(building_desc_x.depot, wt, {}) local err = command_x.build_way(our_player, depot, way_tile[i], way_obj, true) if ( err == null ) { err = command_x.build_depot(our_player, depot, depot_obj[0] ) } else { gui.add_message_at(our_player, "##-ERROR-##--> not depot found", depot) return false } break } } } } local c = vehicle_constructor_t() c.p_depot = depot_x(depot.x, depot.y, depot.z) c.p_line = line c.p_convoy = proto local cnv_payload = c.p_convoy.capacity if ( wt == wt_road && cnv_payload < 30 ) { // by road add 3 vehicles c.p_count = 3 } else { c.p_count = 1 /*if ( int_li == cnv_count ) { c.p_count = 0 }*/ } local int_li = 0 if ( wt == wt_rail ) { local li = line.get_convoy_list() foreach(cnv in li) { if ( cnv.is_valid() ) { int_li++ } } } // input storage f_src = 0 or waiting good = 0 then not add convoys local entries = line.get_schedule().entries local start_h = entries[0].get_halt(our_player) local d = start_h.get_waiting() sleep() if ( (check_fsrc_input(link.f_src) || d[0] > 0) && int_li < cnv_count ) { append_child(c) if ( cnv_retired.len() == 1 && cnv_retired.len() == cnv_count ) { cnv_retired[0].toggle_withdraw(our_player) } dbgprint("==> build additional convoy") if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### cnv_count " + cnv_count, world.get_time()) gui.add_message_at(our_player, "Line: " + line.get_name() + " ==> build additional convoy", world.get_time()) } //if ( wt == wt_rail ) gui.add_message_at(our_player, "####### expand_station.len() " + expand_station.len(), world.get_time()) if ( wt == wt_rail && expand_station.len() > 0 ) { // tiles for convoy local a = c.p_convoy.length local st_lenght = 0 do { a -= 16 st_lenght += 1 } while(a > 0) // expand station local ret = build_expand_station(nexttile, expand_station, st_lenght, link.freight.get_name(), line) if ( ret ) { line.halt_length = st_lenght // set new line entries local entries = line.get_schedule().entries if ( entries.len() >= 2 ) { start_l = tile_x(entries[0].x, entries[0].y, entries[0].z) end_l = tile_x(entries[entries.len()-1].x, entries[entries.len()-1].y, entries[entries.len()-1].z) } } } if ( wt == wt_rail && proto.veh[0].needs_electrification() ) { build_catenary(start_l, end_l, depot, line) } local msgtext = format(translate("%s build additional convoy to line: %s"), our_player.get_name(), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) // save ticks for next check local road_car_rate = set_map_vehicles_counts(1) local next_time = road_line_check * 4 if ( road_car_rate < 10 ) { next_time = road_line_check * 2 } if ( wt == wt_road ) { line.next_vehicle_check = world.get_time().ticks + next_time } else { line.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 2) } return true } else { line.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 2) } } } /* local veh_count_line = line.get_convoy_count() local new_cnv_add_line = false if ( veh_count_line[0] > veh_count_line[1] ) { // not remove cnv from line by add cnv this month new_cnv_add_line = true //gui.add_message_at(our_player, "####### cnv new this month ", world.get_time()) } //!new_cnv_add_line && */ if ( !freight_available && cnv_count>1 && 2*cc_empty >= cnv_count && cnv_empty_stopped && line.next_vehicle_check < world.get_time().ticks && !new_cnv_add_line ) { // freight, lots of empty and of stopped vehicles // -> something is blocked, maybe we block our own supply? // delete one convoy if ( cnv_empty_stopped.is_valid() ) { cnv_empty_stopped.destroy(our_player) dbgprint("==> destroy empty convoy") if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### cnv_count " + cnv_count, world.get_time()) gui.add_message_at(our_player, "Line: " + line.get_name() + " ==> destroy empty convoy", world.get_time()) } local msgtext = format(translate("%s removes convoys from line: %s"), our_player.get_name(), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) // save ticks for next check local road_car_rate = set_map_vehicles_counts(1) local next_time = road_line_check if ( road_car_rate < 10 ) { next_time = road_line_check / 2 } if ( wt == wt_road ) { line.next_vehicle_check = world.get_time().ticks + next_time } else { line.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 2) // set longer time for add convoy by remove convoy in last 6 month local cnv_line = line.get_convoy_count() local a = 0 for ( local x = 1; x < 8; x++ ) { if ( cnv_line[x] <= cnv_line[0] ) { a++ } } line.add_convoy_time = line.next_vehicle_check + (world.get_time().ticks_per_month * a) //gui.add_message_at(our_player, "#1511# line.add_convoy_time : " + line.add_convoy_time + " -- a : " + a, world.get_time()) } } } dbgprint("") if ( wt == wt_road ) { line.next_vehicle_check = world.get_time().ticks + road_line_check } else { line.next_vehicle_check = world.get_time().ticks + world.get_time().ticks_per_month } return true } /** * Upgrade: plan a new convoy type with the prototyper, then * sell existing convoys, create new ones. */ function upgrade_link_line(link, line, cnv_speed, route) { local print_message_box = 0 if ( print_message_box > 0 ) { gui.add_message_at(our_player, "### upgrade_link_line " + line.get_name(), world.get_time()) } //gui.add_message_at(our_player, "### cnv_speed " + cnv_speed, world.get_time()) // find convoy local cnv = null { local list = line.get_convoy_list() if (list.get_count() == 0) { // no convois - strange return false } cnv = list[0] } // estimate transport volume local transported = line.get_transported_goods().reduce(max) // plan convoy prototype local wt = line.get_waytype() local prototyper = prototyper_t(wt, link.freight.get_name()) // iterate through schedule to estimate distance local dist = 0 /*if ( wt != wt_water && wt != wt_air ) { dist = route.len() } else */ if ( route.len == 0 ) { local entries = line.get_schedule().entries local start_h = entries[0].get_halt(our_player) local end_h = entries[entries.len()-1].get_halt(our_player) local t = start_h.get_tile_list() start_l = tile_x(t[0].x, t[0].y, t[0].z) t = end_h.get_tile_list() end_l = tile_x(t[0].x, t[0].y, t[0].z) dist = abs(start_l.x - end_l.x) + abs(start_l.y - end_l.y) } else { dist = route.len() //dist = abs(route[0].x - route[route.len()-1].x) + abs(route[0].y - route[route.len()-1].y) } //local wt = wt // TODO do something smarter local proto_speed = cnv_speed - 25 if ( proto_speed >= 100 ) { proto_speed = 60 } if ( proto_speed < 1 ) { prototyper.min_speed = 1 } else { prototyper.min_speed = proto_speed } prototyper.max_vehicles = get_max_convoi_length(wt) prototyper.max_length = 1 local expand_station = [] if ( wt == wt_rail ) { expand_station = check_expand_station(route, line) if ( expand_station.len() > 0 ) { prototyper.max_length = CARUNITS_PER_TILE * (line.halt_length + (expand_station.len()/2)) } else { prototyper.max_length = CARUNITS_PER_TILE * line.halt_length } if ( print_message_box > 0 ) { gui.add_message_at(our_player, "### line.halt_length = " + line.halt_length + " ## expand_station.len() : " + expand_station.len(), world.get_time()) gui.add_message_at(our_player, "### prototyper.max_length = " + prototyper.max_length, world.get_time()) } prototyper.electrified = check_catenary(line, dist, route[route.len()-1], cnv_speed) } if (wt == wt_water) { prototyper.max_length = 4 } local cnv_valuator = valuator_simple_t() cnv_valuator.wt = wt cnv_valuator.freight = link.freight.get_name() cnv_valuator.volume = transported cnv_valuator.max_cnvs = 200 // no signals and double tracks - limit 1 convoy for rail if (wt == wt_rail) { cnv_valuator.max_cnvs = line.double_ways_count + 1 } cnv_valuator.distance = dist local bound_valuator = valuator_simple_t.valuate_monthly_transport.bindenv(cnv_valuator) prototyper.valuate = bound_valuator if (prototyper.step().has_failed()) { return false } local planned_convoy = prototyper.best // check whether different from current convoy local cnv_veh = cnv.get_vehicles() local pro_veh = planned_convoy.veh local different = cnv_veh.len() != pro_veh.len() for(local i=0; i 0 ) { // tiles for convoy local a = c.p_convoy.length local st_lenght = 0 do { a -= 16 st_lenght += 1 } while(a > 0) // expand station local ret = build_expand_station(route, expand_station, st_lenght, link.freight.get_name(), line) if ( ret ) { line.halt_length = st_lenght } } if ( wt == wt_rail && c.p_convoy.veh[0].needs_electrification() ) { build_catenary(route[0], route[route.len()-1], depot, line) } c.p_withdraw = true append_child(c) // save ticks for next check local road_car_rate = set_map_vehicles_counts(1) local next_time = road_line_check * 4 if ( road_car_rate < 10 ) { next_time = road_line_check * 2 } if ( wt == wt_road ) { line.next_vehicle_check = world.get_time().ticks + next_time } else { line.next_vehicle_check = world.get_time().ticks + (world.get_time().ticks_per_month * 2) } return true } // keys were broken for rotated maps, regenerate keys for all entries function repair_keys() { link_iterator = null local save_list = link_list link_list = {} foreach(link in save_list) { link_list[ key(link.f_src, link.f_dest, link.freight.get_name()) ] <- link } } function _save() { link_iterator = null // wont save return ::saveinstance("industry_manager_t", this) } function check_expand_station(nexttile, line) { // 0 = off // 1 // 2 = station expand // 3 local print_message_box = 0 local wt = line.get_waytype() local expand_station = [] local station_count = 0 local station_exist = 0 local expand_station_end_src = [] local expand_station_end_dest = [] // count exist station lenght for ( local i = 0; i < 6; i++ ) { if ( nexttile[i].find_object(mo_building) != null ) { station_count++ } } if ( line.halt_length == 0 ) { line.halt_length = station_count } // check expand station -> tiles direction end from way local tiles_end_src = [] local tiles_end_dest = [] local t = null // line end dest for ( local i = 1; i < 4; i++ ) { t = check_tile_end_of_station(nexttile[0].get_way_dirs(wt), i, nexttile[0]) if ( t != null ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile expand_station_end_dest : " + coord3d_to_string(t), t) } expand_station_end_dest.append(t) } else { break } } // line end src for ( local i = 1; i < 4; i++ ) { t = check_tile_end_of_station(nexttile[nexttile.len()-1].get_way_dirs(wt), i, nexttile[nexttile.len()-1]) if ( t != null ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile expand_station_end_src : " + coord3d_to_string(t), t) } expand_station_end_src.append(t) } else { break } } //prototyper.max_length = station_count line.halt_length = station_count station_exist = station_count local add_tile_src = 0 local add_tile_dest = 0 if ( station_count < 6 ) { // check expand station -> direction of the existing route/way // built cnv to new length end expand station befor create cnv //station_count++ for ( station_count; station_count < 6; station_count++ ) { //gui.add_message_at(our_player, "###---- nexttile[station_count-1] : " + coord3d_to_string(nexttile[station_count-1]) + " - " + nexttile[station_count-1].get_way_dirs(wt), nexttile[0]) //gui.add_message_at(our_player, "###---- nexttile[station_count] : " + coord3d_to_string(nexttile[station_count]) + " - " + nexttile[station_count].get_way_dirs(wt), nexttile[0]) //gui.add_message_at(our_player, "###---- nexttile[nexttile.len()-station_count-2] : " + coord3d_to_string(nexttile[nexttile.len()-station_count-1]) + " - " + nexttile[nexttile.len()-station_count-1].get_way_dirs(wt), nexttile[0]) //gui.add_message_at(our_player, "###---- nexttile[nexttile.len()-station_count-1] : " + coord3d_to_string(nexttile[nexttile.len()-station_count]) + " - " + nexttile[nexttile.len()-station_count].get_way_dirs(wt), nexttile[0]) /*if ( nexttile[station_count-1].get_way_dirs(wt) != nexttile[station_count].get_way_dirs(wt) || nexttile[nexttile.len()-station_count-1].get_way_dirs(wt) != nexttile[nexttile.len()-station_count].get_way_dirs(wt) || (nexttile[station_count].is_bridge() && nexttile[station_count].z == square_x(nexttile[station_count].x, nexttile[station_count].y).get_ground_tile().z) || (nexttile[nexttile.len()-station_count-1].is_bridge() && nexttile[nexttile.len()-station_count-1].z == square_x(nexttile[station_count].x, nexttile[nexttile.len()-station_count-1].y).get_ground_tile().z) ) { */ //if ( !test_field(our_player, nexttile[station_count], wt, nexttile[station_count].get_way_dirs(wt), square_x(nexttile[station_count].x, nexttile[station_count].y).get_ground_tile().z, 1) ) { local t1 = nexttile[station_count] local t2 = nexttile[(nexttile.len()-1)-station_count] local check_tile = 0 local check_src = 0 local check_dest = 0 if ( t1.get_way_dirs(wt) == 5 || t1.get_way_dirs(wt) == 10 ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile direction : " + coord3d_to_string(t1), t1) } if ( (t1.z == nexttile[station_exist-1].z && !t1.is_bridge() && !t1.is_tunnel() && test_tile_is_empty(t1) && !t1.has_two_ways()) || (t1.z < nexttile[station_exist-1].z && t1.is_bridge()) ) { //t1.get_slope() == 0 // dest if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile t1 z : " + t1.z, t1) gui.add_message_at(our_player, "###---- check tile nexttile[station_exist-1].z (" + coord3d_to_string(nexttile[station_exist-1]) + ") : " + nexttile[station_exist-1].z, nexttile[station_exist-1]) } check_tile++ check_src++ } else { check_dest++ } } if ( t2.get_way_dirs(wt) == 5 || t2.get_way_dirs(wt) == 10 ) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile direction : " + coord3d_to_string(t2), t2) } if ( (t2.z == nexttile[(nexttile.len()-1)-(station_exist-1)].z && !t2.is_bridge() && !t2.is_tunnel() && test_tile_is_empty(t2) && !t2.has_two_ways()) || (t2.z < nexttile[(nexttile.len()-1)-(station_exist-1)].z && t2.is_bridge()) ) { //t2.get_slope() == 0 // src if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check tile t2 z : " + t2.z, t2) gui.add_message_at(our_player, "###---- check tile nexttile[(nexttile.len()-1)-(station_exist-1)].z (" + coord3d_to_string(nexttile[(nexttile.len()-1)-(station_exist-1)]) + ") : " + nexttile[(nexttile.len()-1)-(station_exist-1)].z, nexttile[(nexttile.len()-1)-(station_exist-1)]) } check_tile++ check_dest++ } else { check_src++ } } if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- station_count-station_exist : " + (station_count-station_exist), world.get_time()) gui.add_message_at(our_player, "###---- check_tile: " + check_tile + " check_dest: " + check_dest + " check_src: " + check_src, world.get_time()) gui.add_message_at(our_player, "###---- add_tile_dest: " + add_tile_dest + " add_tile_src: " + add_tile_src, world.get_time()) } if (check_tile == 2) { if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- add tile nexttile[station_count]: " + coord3d_to_string(nexttile[station_count]), nexttile[station_count]) gui.add_message_at(our_player, "###---- add tile nexttile[nexttile.len()-(station_count+1)]: " + coord3d_to_string(nexttile[nexttile.len()-(station_count+1)]), nexttile[nexttile.len()-(station_count+1)]) } expand_station.append(nexttile[station_count]) expand_station.append(nexttile[nexttile.len()-(station_count+1)]) } else if (check_tile == 1 && check_dest >= 1 && expand_station_end_dest.len()-1 >= add_tile_dest) { // dest if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- add tile expand_station_end_dest[add_tile_dest]: " + coord3d_to_string(expand_station_end_dest[add_tile_dest]), expand_station_end_dest[add_tile_dest]) gui.add_message_at(our_player, "###---- add tile nexttile[nexttile.len()-(station_count+1)]: " + coord3d_to_string(nexttile[nexttile.len()-(station_count+1)]), nexttile[nexttile.len()-(station_count+1)]) } expand_station.append(expand_station_end_dest[add_tile_dest]) add_tile_dest++ expand_station.append(nexttile[nexttile.len()-(station_count+1)]) } else if (check_tile == 1 && check_src >= 1 && expand_station_end_src.len()-1 >= add_tile_src) { // src if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- add tile nexttile[station_count]: " + coord3d_to_string(nexttile[station_count]), nexttile[station_count]) gui.add_message_at(our_player, "###---- add tile expand_station_end_src[add_tile_src]: " + coord3d_to_string(expand_station_end_src[add_tile_src]), expand_station_end_src[add_tile_src]) } expand_station.append(nexttile[station_count]) expand_station.append(expand_station_end_src[add_tile_src]) add_tile_src++ } else if (check_tile == 0 && check_src <= 1 && check_dest <= 1 && expand_station_end_dest.len()-1 >= add_tile_dest && expand_station_end_src.len()-1 >= add_tile_src) { // src & dest if ( print_message_box == 2 ) { gui.add_message_at(our_player, "###---- add tile expand_station_end_dest[add_tile_dest]: " + coord3d_to_string(expand_station_end_dest[add_tile_dest]), expand_station_end_dest[add_tile_dest]) gui.add_message_at(our_player, "###---- add tile expand_station_end_src[add_tile_src]: " + coord3d_to_string(expand_station_end_src[add_tile_src]), expand_station_end_src[add_tile_src]) } expand_station.append(expand_station_end_dest[add_tile_dest]) add_tile_dest++ expand_station.append(expand_station_end_src[add_tile_src]) add_tile_src++ } else { station_count-- break } /* } else { station_count-- break }*/ } if ( station_exist < station_count && print_message_box == 2 ) { gui.add_message_at(our_player, "###---- check stations field : " + station_exist, nexttile[0]) gui.add_message_at(our_player, "###---- check stations field expand -> direction exist way : " + station_count, nexttile[0]) } } return expand_station } function build_expand_station(nexttile, expand_station, st_lenght, freight, line) { // 0 = off // 1 = station expand // 2 // 3 local print_message_box = 0 local wt = line.get_waytype() local start_l = nexttile[nexttile.len()-1] local end_l = nexttile[0] local station_exist = 0 // count exist station lenght for ( local i = 0; i < 6; i++ ) { if ( nexttile[i].find_object(mo_building) != null ) { station_exist++ } } local station_list = building_desc_x.get_available_stations(building_desc_x.station, wt, good_desc_x(freight)) local station_s_obj = nexttile[nexttile.len()-1].find_object(mo_building).get_desc() if ( !station_s_obj.is_available(world.get_time()) ) { local capacity = station_s_obj.get_capacity() station_s_obj = null foreach(station in station_list) { if ( station_s_obj == null ) { station_s_obj = station } if ( station.get_capacity() >= capacity && station.get_capacity() < station_s_obj.get_capacity() ) { station_s_obj = station } } } local station_e_obj = nexttile[0].find_object(mo_building).get_desc() if ( !station_e_obj.is_available(world.get_time()) ) { station_e_obj = null foreach(station in station_list) { if ( station_e_obj == null ) { station_e_obj = station } if ( station.cost < station_e_obj.cost ) { station_e_obj = station } } } local way_obj = start_l.find_object(mo_way).get_desc() //way_list[0] if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, way_obj.get_topspeed()) } local catenary_obj = null //find_object("catenary", wt, 100) local build_catenary = false if ( start_l.find_object(mo_wayobj) != null ) { catenary_obj = start_l.find_object(mo_wayobj).get_desc() if ( catenary_obj != null && !catenary_obj.is_available(world.get_time()) && !catenary_obj.is_overhead_line() ) { catenary_obj = find_object("catenary", wt, way_obj.get_topspeed()) } } else { //catenary_obj = find_object("catenary", wt, way_obj.get_topspeed()) } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### st_lenght > station_count : " + st_lenght + " > " + station_exist, expand_station[0]) } if ( st_lenght > station_exist ) { // expand station local sched = schedule_x(wt_rail, []) local sched_start = start_l local sched_end = end_l local b_count = st_lenght - station_exist switch(b_count) { case 2: b_count++ break case 3: b_count += 2 break case 4: b_count += 3 break case 5: b_count += 4 break } for ( local i = 0; i <= b_count; i++ ) { local station_obj = (i % 2) ? station_s_obj : station_e_obj if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### [i] " + i, expand_station[i]) } if ( expand_station[i].find_object(mo_way) == null ) { local build_tile = (i % 2) ? start_l : end_l if ( terraform_tile(expand_station[i], build_tile.z) ) { command_x.build_way(our_player, build_tile, expand_station[i], way_obj, true) command_x.build_station(our_player, expand_station[i], station_obj) if ( catenary_obj != null ) { command_x.build_wayobj(our_player, build_tile, expand_station[i], catenary_obj) } local entries = line.get_schedule().entries if ( build_tile == start_l ) { sched_start = expand_station[i] if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### expand stations tile schedule start_l ", expand_station[i]) } } else { sched_end = expand_station[i] if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### expand stations tile schedule end_l ", expand_station[i]) } } //::debug.pause() } //::debug.pause() } else { command_x.build_station(our_player, expand_station[i], station_obj) } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### expand stations tile " + coord3d_to_string(expand_station[i]), expand_station[i]) } } sched.entries.append( schedule_entry_x(sched_start, 100, 0) ); sched.entries.append( schedule_entry_x(sched_end, 0, 0) ); line.change_schedule(our_player, sched) //line.halt_length = st_lenght if ( print_message_box == 1 ) { gui.add_message_at(our_player, "####### expand stations ", expand_station[0]) } local message_text = format(translate("%s expand the station %s (%s) and station %s (%s)"), our_player.get_name(), start_l.get_halt().get_name(), coord_to_string(start_l), end_l.get_halt().get_name(), coord_to_string(end_l)) gui.add_message_at(our_player, message_text, start_l) //::debug.pause() return true } return false } function check_catenary(line, dist, start_l, cnv_max_speed) { local catenary_obj = null //find_object("catenary", wt, 100) local catenary_cost = 0 local int_return = 0 local wt = line.get_waytype() local print_message_box = 0 if ( start_l.find_object(mo_wayobj) != null ) { catenary_obj = start_l.find_object(mo_wayobj).get_desc() if ( catenary_obj != null && !catenary_obj.is_available(world.get_time()) && !catenary_obj.is_overhead_line() ) { catenary_obj = find_object("catenary", wt, cnv_max_speed) } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "###---- set electrified convoys " + line.get_name(), world.get_time()) gui.add_message_at(our_player, "###---- line has catenary ", world.get_time()) } int_return = 1 } else { catenary_obj = find_object("catenary", wt, cnv_max_speed) // build cost catenary_cost = (catenary_obj.get_cost() * (dist + (8 * line.double_ways_count))) + catenary_obj.get_cost() // + maintenance for 5 months catenary_cost += ((catenary_obj.get_maintenance() * (dist + (8 * line.double_ways_count))) + catenary_obj.get_maintenance()) * 5 // set electrified for vehicle by way len > xx tiles if ( dist > 80 && world.get_time().year >= 1935 && our_player.get_current_cash() > catenary_cost ) { if ( print_message_box == 1 ) { gui.add_message_at(our_player, "###---- set electrified convoys " + line.get_name(), world.get_time()) gui.add_message_at(our_player, "###---- line len " + nexttile.len(), world.get_time()) } int_return = 1 } } return int_return } function build_catenary(start_l, end_l, depot, line) { local print_message_box = 0 local wt = line.get_waytype() local way_obj = start_l.find_object(mo_way).get_desc() //way_list[0] if ( !way_obj.is_available(world.get_time()) ) { way_obj = find_object("way", wt, way_obj.get_topspeed()) } local catenary_obj = null //find_object("catenary", wt, 100) local build_catenary = false if ( start_l.find_object(mo_wayobj) != null ) { catenary_obj = start_l.find_object(mo_wayobj).get_desc() if ( catenary_obj != null && !catenary_obj.is_available(world.get_time()) && !catenary_obj.is_overhead_line() ) { catenary_obj = find_object("catenary", wt, way_obj.get_topspeed()) build_catenary = true } } else { catenary_obj = find_object("catenary", wt, way_obj.get_topspeed()) build_catenary = true } if ( build_catenary ) { command_x.build_wayobj(our_player, start_l, end_l, catenary_obj) command_x.build_wayobj(our_player, end_l, start_l, catenary_obj) command_x.build_wayobj(our_player, depot, start_l, catenary_obj) local msgtext = format(translate("%s electrified the line %s"), our_player.get_name(), line.get_name()) gui.add_message_at(our_player, msgtext, world.get_time()) } if ( print_message_box == 1 ) { //gui.add_message_at(our_player, "####### proto.veh[0].needs_electrification() : " + proto.veh[0].needs_electrification(), world.get_time()) gui.add_message_at(our_player, "####### cnv needs electrified " + catenary_obj.get_name(), depot) } return build_catenary } } function convoy_max_speed(cnv) { // convoy_x::calc_max_speed ( integer power, integer weight, integer speed_limit ) local pwr = 0 local weight = 0 local m_speed = 500 local veh_list = cnv.get_vehicles() for (local i = 0; i < veh_list.len(); i++) { pwr += veh_list[i].get_power() weight += veh_list[i].get_weight() + (veh_list[i].get_capacity()*veh_list[i].get_freight().get_weight_per_unit()) if ( m_speed > veh_list[i].get_topspeed() ) { m_speed = veh_list[i].get_topspeed() } } local a = cnv.calc_max_speed(pwr, weight, m_speed) return a } function convoy_is_retired(cnv) { local veh_list = cnv.get_vehicles() for (local i = 0; i < veh_list.len(); i++) { if ( veh_list[i].is_retired(world.get_time()) ) { return true } } } /* * check factory input + src station good quantity > max storage factory * * */ function check_good_quantity(start_l, end_l, good, line) { local f_dest = end_l.get_halt().get_factory_list() if ( f_dest.len() == 1 ) { local freight = good.get_name() foreach(freight, islot in f_dest[0].input) { if ( good.get_name() == islot.good ) { local st = islot.get_storage() local it = islot.get_in_transit() local good_src = start_l.get_halt().get_freight_to_halt(good, end_l.get_halt()) local max_storage = islot.max_storage //gui.add_message_at(our_player, "*** good halt src " + good_src + " " + line.get_name(), world.get_time()) //gui.add_message_at(our_player, "*** islot.good " + translate(islot.good) + " factory " + f_dest[0].get_name() + " input storage [" + max_storage + "]", world.get_time()) if ( st[0] < (max_storage/10) ) { return false } else if ( (st[0] + it[0] > max_storage && (max_storage/5) < st[0]) || it[0] > max_storage ) { // //gui.add_message_at(our_player, "*** good quantity [" + (st[0] + it[0]) + "] > factory " + f_dest[0].get_name() + " input storage [" + max_storage + "] " + line.get_name(), world.get_time()) return true } } } // todo more goods check } return false } simutrans-124.3/simutrans/ai/sqai_rail/info.txt000066400000000000000000000001331474050137200216260ustar00rootroot00000000000000Repo for deveoplement https://github.com/Andarix/simutrans-scenarios/tree/master/ai/sqaisimutrans-124.3/simutrans/ai/sqai_rail/placefinder.nut000066400000000000000000000113351474050137200231440ustar00rootroot00000000000000/** * Helper static functions to find places for stations, depots, etc. */ class finder { static function get_tiles_near_factory(factory) { local cov = settings.get_station_coverage() local area = [] // generate a list of tiles that will reach the factory local ftiles = factory.get_tile_list() foreach (c in ftiles) { for(local dx = -cov; dx <= cov; dx++) { for(local dy = -cov; dy <= cov; dy++) { if (dx==0 && dy==0) continue; local x = c.x+dx local y = c.y+dy if (x>=0 && y>=0) area.append( (x << 16) + y ); } } } // sort sleep() area.sort() return area } static function get_tiles_near_halt(halt) { local cov = 1 local area = [] // generate a list of tiles that will reach the halt for combined local ftiles = halt.get_tile_list() foreach (c in ftiles) { for(local dx = -cov; dx <= cov; dx++) { for(local dy = -cov; dy <= cov; dy++) { if (dx==0 && dy==0) continue; local x = c.x+dx local y = c.y+dy if (x>=0 && y>=0) area.append( (x << 16) + y ); } } } // sort sleep() area.sort() return area } static function find_empty_place(area, target) { // find place closest to target local tx = target.x local ty = target.y local best = null local dist = 10000 // check for flat and empty ground for(local i = 0; i0 && h == area[i-1]) continue; local x = h >> 16 local y = h & 0xffff if (world.is_coord_valid({x=x,y=y})) { local tile = square_x(x, y).get_ground_tile() if (tile.is_empty() && tile.get_slope()==0) { local d = abs(x - tx) + abs(y - ty) if (d < dist) { dist = d best = tile } } } } return best } static function _find_places(area, test /* function */) { local list = [] // check for flat and empty ground for(local i = 0; i0 && h == area[i-1]) continue; local x = h >> 16 local y = h & 0xffff if (world.is_coord_valid({x=x,y=y})) { local tile = square_x(x, y).get_ground_tile() if (test(tile)) { list.append(tile) } } } return list.len() > 0 ? list : [] } static function find_empty_places(area) { return _find_places(area, _tile_empty) } static function _tile_empty(tile) { return tile.is_empty() && tile.get_slope()==0 } static function _tile_empty_or_field(tile) { return tile.get_slope()==0 && (tile.is_empty() || tile.find_object(mo_field)) } static function find_water_places(area) { return _find_places(area, _tile_water) } static function _tile_water(tile) { return tile.is_water() && (tile.find_object(mo_building)==null) && (tile.find_object(mo_depot_water)==null) } static function _tile_water_way(tile) { if (tile.is_water()) { return true // (tile.find_object(mo_building)==null) && (tile.find_object(mo_depot_water)==null) } else { foreach(obj in tile.get_objects()) { try { if (obj.get_type() != mo_way) continue; if (obj.get_waytype() == wt_water) { return obj.get_desc().get_topspeed() > 5 } } catch(ev) { // object gone, most likely vehicle that moved on } } } return false } static function find_station_place(factory, target, unload = false) { if (unload) { // try unload station from station manager local res = ::station_manager.access_freight_station(factory).road_unload if (res) { return [res] } } local can_delete_fields = factory.get_field_count() > factory.get_min_field_count() local area = get_tiles_near_factory(factory) if (can_delete_fields) { return _find_places(area, _tile_empty_or_field); } else { return find_empty_places(area) } } /** * Can harbour of length @p len placed at @p pos (land tile!) in direction @p d. */ static function check_harbour_place(pos, len, d /* direction */) { local from = pos for(local i = 0; i0 ? wt_water : wt_all, d) if (to && _tile_water(to) && to.can_remove_all_objects(our_player)==null) { from = to } else { return false } } return true } } simutrans-124.3/simutrans/ai/sqai_rail/prototyper.nut000066400000000000000000000335671474050137200231320ustar00rootroot00000000000000/** * Classes to plan a convoy prototype given some constraints. */ /** * Prototype of a convoy. */ class cnv_proto_t { // properties weight = 0 // weight (fully loaded) power = 0 // total power min_top_speed = 0 // top speed when fully loaded max_speed = -1 // speed limit length = 0 // length of convoy in internal units (one tile = 16 units) capacity = 0 // capacity of convoy for desired freight maintenance = 0 // maintenance cost per month running_cost = 0 // running cost per tile price = 0 // price missing_freight = true // convoy misses vehicles to transport desired freight veh = null // the vehicles of the convoy (array) // set by valuator nr_convoys = 0 // number of convoys that should be built constructor() { veh = [] debug = false } /** * Append vehicle to this prototype. * Desired freight is given as parameter freight. */ function append(newveh, freight) { local cnv = getclass().instance() cnv.constructor() cnv.veh.extend(veh) cnv.veh.append(newveh) cnv.weight = weight + freight.get_weight_per_unit() * newveh.get_capacity() + newveh.get_weight() cnv.power = power + newveh.get_power() if (max_speed >= 0) { cnv.max_speed = min(max_speed, newveh.get_topspeed()) } else { cnv.max_speed = newveh.get_topspeed() } cnv.length = length + newveh.get_length() local fits = newveh.get_freight().is_interchangeable(freight) cnv.missing_freight = missing_freight && (newveh.get_capacity()==0 || !fits) cnv.min_top_speed = convoy_x.calc_max_speed(cnv.power, cnv.weight, cnv.max_speed) cnv.capacity = capacity + (fits ? newveh.get_capacity() : 0) cnv.maintenance = maintenance + newveh.get_maintenance() cnv.running_cost = running_cost + newveh.get_running_cost() cnv.price = price + newveh.get_cost() return cnv } static function from_convoy(cnv, freight) { local p = cnv_proto_t() local list = cnv.get_vehicles() foreach(v in list) { p = p.append(v, freight) } return p } function _save() { return ::saveinstance("cnv_proto_t", this) } } /** * Class to find the best prototype. * * Iterates through all possible combinations. * This can take a very long time for e.g. passenger trains. * Some means to shorten the computation are required. * * If a prototype is valid, it is passed to the function valuate. * The prototype with largest score wins (or the first one if valuate == null). */ class prototyper_t extends node_t { wt = 0 // way-type freight = 0 // freight to be transported max_vehicles = 0 // maximum of number of vehicles in this prototype max_length = 0 // maximum lenght of convoy in number of tiles min_speed = 0 // minimum speed electrified = 0 // 0 - not electrified vehicle; 1 - electrified vehicle volume = 0 // monthly transport volume valuate = null // valuate function, takes prototype, returns number (null -> first valid prototype is returned) best = null // the best prototype up to now best_value = 0 // and its score // print messages box // 1 = vehicle create data // 2 = vehicle found // 3 = convoy check lenght and wt_rail print_message_box = 0 wt_name = ["", "road", "rail", "water"] constructor(w, /*string*/f) { base.constructor("prototyper"); wt = w freight = good_desc_x(f) } /** * Depth-first search. * Takes constraints into account. Calls valuate. */ function step() { if ( print_message_box == 1 ) { local units = get_max_convoi_length(wt) gui.add_message_at(our_player, "**** ", world.get_time()) gui.add_message_at(our_player, "create convoy ", world.get_time()) gui.add_message_at(our_player, "wt " + wt_name[wt], world.get_time()) gui.add_message_at(our_player, "units: " + units, world.get_time()) gui.add_message_at(our_player, "CARUNITS_PER_TILE: " + CARUNITS_PER_TILE, world.get_time()) gui.add_message_at(our_player, "max_length: " + max_length, world.get_time()) gui.add_message_at(our_player, "electrified: " + electrified, world.get_time()) } //if ( wt == wt_rail ) gui.add_message_at(our_player, "max_length: " + max_length, world.get_time()) local date = world.get_time() // list of all vehicles local list = vehicle_desc_x.get_available_vehicles(wt) // vehicles that can be put first local list_first = [] // other vehicles: powered, no capacity (tenders), matching freight local list_other = [] local t = 0 // preprocess foreach(veh in list) { local first = veh.can_be_first() local fits = veh.get_freight().is_interchangeable(freight) local pwer = veh.get_power()>0 local power = veh.get_power() / 64 local speed = veh.get_topspeed() local none = veh.get_freight().get_name()=="None" || veh.get_capacity()==0 local timeline = !veh.is_retired(world.get_time()) local frev = good_desc_x(freight.get_name()).calc_revenue(wt, speed)/3 local t = frev*100 - veh.get_running_cost() // no build catenary -> no electrified vehicles //local electrified = !veh.needs_electrification() local electro = true if ( electrified == 0 && veh.needs_electrification() ) { electro = false } //gui.add_message_at(our_player, "timeline: " + veh.get_name() + " - " + timeline, world.get_time()) // use vehicles that can carry freight // or that are powered and have no freight capacity if ( (fits || (pwer && none)) && timeline && electro ) { if (first && (pwer || wt == wt_water) ) { /** * speed < 161 - max speed 160 for rail lines factory goods */ if ( speed < 161 && wt == wt_rail ) { list_first.append(veh) } else if ( wt != wt_rail ) { list_first.append(veh) } } else { list_other.append(veh) } if ( print_message_box == 2 && wt == wt_rail && pwer ) { gui.add_message_at(our_player, "* vehicle found: " + veh.get_name() + " power " + power + " speed " + speed + " ## " + t, world.get_time()) } } } // array of lists we try to iterate local it_lists = []; it_lists.resize(max_vehicles+1) local it_ind = []; it_ind.resize(max_vehicles+1) // current convoy candidate - array of desc local cnv = []; cnv.resize(max_vehicles+1) // initialize cnv[0] = cnv_proto_t() it_ind[1] = -1 it_lists[1] = list_first // iterating ind-th position in convoy local ind = 1 local count_cnv_length = false local show_mwssage = false //max_vehicles local a = 0 if ( wt == wt_water ) { a = CARUNITS_PER_TILE * 4 } else if ( wt == wt_rail ) { a = CARUNITS_PER_TILE * 3 if ( volume > 1200 && volume < 2200 ) { a = CARUNITS_PER_TILE * 4 } else if ( volume > 2200 ) { a = CARUNITS_PER_TILE * 5 } if ( show_mwssage ) { gui.add_message_at(our_player, "#prototyper 259# tiles_length: " + a + " - max_length: " + max_length, world.get_time()) show_mwssage = false } if ( get_set_name() == "pak64.german" ) { } else if ( a < max_length ) { a = max_length } } else { a = CARUNITS_PER_TILE } while(true) { it_ind[ind] ++ // done with iterating? if (it_ind[ind] >= it_lists[ind].len() ) { if (ind>1) { ind-- continue // iterating position ind-1 } else { break // end of the iteration } } local test = it_lists[ind][ it_ind[ind] ] // check couplings if ( ind==1 ? !test.can_be_first() : !vehicle_desc_x.is_coupling_allowed(cnv[ind-1].veh.top(), test) ) { continue; } // append cnv[ind] = cnv[ind-1].append(test, freight) local c = cnv[ind] // check constraints // .. length local l = (ind > 1 ? cnv[ind-1].length : 0) + max( CARUNITS_PER_TILE/2, test.get_length()); if ( print_message_box == 3 && wt == wt_rail ) { gui.add_message_at(our_player, "convoy l: " + l, world.get_time()) gui.add_message_at(our_player, "convoy length max: " + max( CARUNITS_PER_TILE/2, test.get_length()), world.get_time()) //show_mwssage = true } //max_vehicles /* local a = 0 if ( wt == wt_water ) { a = CARUNITS_PER_TILE * 4 } else if ( wt == wt_rail ) { a = CARUNITS_PER_TILE * 3 if ( volume > 1200 && volume < 2200 ) { a = CARUNITS_PER_TILE * 4 } else if ( volume > 2200 ) { a = CARUNITS_PER_TILE * 5 } if ( show_mwssage ) { gui.add_message_at(our_player, "#prototyper 259# tiles_length: " + a + " - max_length: " + max_length, world.get_time()) show_mwssage = false } if ( get_set_name() != "pak64.german" ) { max_length = 96 } if ( a < max_length ) { a = max_length } } else { a = CARUNITS_PER_TILE }*/ // no more by max length // no more by speed < max speed convoy if ((l + test.get_length()) > a || c["min_top_speed"] < c["max_speed"]) { //) { max_length CARUNITS_PER_TILE //gui.add_message_at(our_player, "c['min_top_speed']: " + c["min_top_speed"], world.get_time()) //gui.add_message_at(our_player, "c['max_speed']: " + c["max_speed"], world.get_time()) if ( (c["max_speed"]-c["min_top_speed"]) < 10 ) { count_cnv_length = true } else if ( (l + test.get_length()) > a ) { //gui.add_message_at(our_player, "#prototyper 277# tiles_length: " + a + " - (l + test.get_length()): " + (l + test.get_length()), world.get_time()) count_cnv_length = true } else { continue; } } // check if convoy finished if (test.can_be_last() && !c.missing_freight && c.min_top_speed >= min_speed) { // evaluate this candidate //gui.add_message_at(our_player, "valuate: " + valuate, world.get_time()) if (valuate) { local value = valuate.call(getroottable(), c) //if ( print_message_box == 2 ) { // gui.add_message_at(our_player, "evaluate this candidate: " + value, world.get_time()) //} if (best==null || value > best_value) { best = c best_value = value } } else { // no valuator function -> take first valid convoy and return best = c; break } } // move on to next position if (ind >= max_vehicles || count_cnv_length) { count_cnv_length = false continue; } ind++ local list_succ = test.get_successors() if (list_succ.len()==0) { it_lists[ind] = list_other } else{ it_lists[ind] = [] foreach(v in list_succ) { if (v.is_available(date)) { it_lists[ind].append(v) } } } it_ind[ind] = -1 } if (best) { foreach(ind, test in best.veh) { print("Best[" + ind + "] = " + test.get_name()) //if ( wt == wt_rail ) gui.add_message_at(our_player, "Best[" + ind + "] = " + test.get_name(), world.get_time()) } return r_t(RT_SUCCESS) } return r_t(RT_ERROR) } } /** * A simple valuate function. */ class valuator_simple_t { wt = 0 // way-type freight = null // freight to be transported volume = 0 // monthly transport volume max_cnvs = 0 // maximum number of convoys distance = 0 way_max_speed = -1 // speed limit of planned way way_maintenance = 0 // maintenance of planned way /** * Estimates gain per month */ function valuate_monthly_transport(cnv) { local speed = way_max_speed > 0 ? min(way_max_speed, cnv.min_top_speed) : cnv.min_top_speed local frev = good_desc_x(freight).calc_revenue(wt, speed)/2 local capacity = cnv.capacity // tiles per month of one convoy local tpm = convoy_x.speed_to_tiles_per_month(speed) / 2 + 1 // needed convoys to transport everything local n1 = max(1, volume * 2 * distance / (tpm * cnv.capacity)) // realistic number of convoys local ncnv = min(n1, min(max_cnvs, max(distance / 8, 3) ) ) cnv.nr_convoys = ncnv // double track and signals missing if (wt == wt_rail) { cnv.nr_convoys = 1 } if (way_max_speed > 0) { // correction factor to prefer faster ways: // factor = 0 .. if 2*distance < ncnv // factor = 1 .. if distance/3 > ncnv // linear interpolated in between // without scaling almost always the cheapest way is chosen ... local factor = max(0, min(10*distance, 6*(2*distance - ncnv) ) ); // rescale tiles per month tpm = (tpm*factor) / (10*distance); } // monthly costs and revenue local value = ncnv*( (frev*cnv.capacity+1500)/3000*tpm - cnv.running_cost*tpm - cnv.maintenance) - distance * way_maintenance /* // gain per field // station_maintenance missing local t = (frev*cnv.capacity) - cnv.running_cost - cnv.maintenance local i = 30000 // maintenance stations + bridges if ( wt == wt_rail ) { i += 50000 } if ( t <= way_maintenance*2 + i ) { return 0 } */ return value } function _save() { return ::saveinstance("valuator_simple_t", this) } } simutrans-124.3/simutrans/ai/sqai_rail/rail_connector.nut000066400000000000000000001056601474050137200236760ustar00rootroot00000000000000class rail_connector_t extends manager_t { // input data fsrc = null fdest = null freight = null planned_way = null planned_station = null planned_depot = null planned_convoy = null finalize = true // step-by-step construct the connection phase = 0 // can be provided optionally c_start = null // array c_end = null // array c_route = null // array // generated data c_depot = null c_sched = null c_line = null c_cnv = null t_start = [] t_end = [] st_lenght = 0 pl = null // print messages box // 1 = way // 2 = stations // 3 = depot print_message_box = 0 constructor() { base.constructor("rail_connector_t") debug = false } function work() { // TODO check if child does the right thing pl = our_player local tic = get_ops_total(); local fs = fsrc.get_tile_list() local fd = fdest.get_tile_list() local s_src = null local s_dest = null if ( phase == 0 ) { if ( !check_link_catg_goods(fsrc, fdest, freight) ) { //gui.add_message_at(pl, "no build line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") exists catg links", world.get_time()) return r_t(RT_TOTAL_FAIL) // } else if ( check_factory_links(fsrc, fdest, freight) >= 2 ) { //gui.add_message_at(pl, "no build line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") to many links", world.get_time()) return r_t(RT_TOTAL_FAIL) // } else { //gui.add_message_at(pl, "check line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") " + freight, world.get_time()) local st_dock = search_station(c_start, wt_water, 1) if ( !check_factory_link_line(fsrc, fdest, freight) && !st_dock ) { //gui.add_message_at(pl, " st_dock " + st_dock, world.get_time()) return r_t(RT_TOTAL_FAIL) } } local build_cash = player_x(our_player.nr).get_current_cash() + (((player_x(our_player.nr).get_current_net_wealth()/100) - player_x(our_player.nr).get_current_cash())/2) local build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 1) if ( industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) > 0 ) { build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) } if ( (build_check_month > world.get_time().ticks || build_cost > build_cash) && industry_manager.get_combined_link(fsrc, fdest, freight) == 0 ) { // not build link if ( debug ) gui.add_message_at(our_player, "#rail_conn# not build line : build_check_month = " + build_check_month + " or build cost link > cash : build cost line " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 1) + " | build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 0), world.get_time()) if ( debug ) gui.add_message_at(our_player, " ---> link " + fsrc + " " + fsrc.get_name() + " - " + fdest.get_name(), world.get_time()) //if ( debug ) gui.add_message_at(our_player, " ---> phase " + phase, world.get_time()) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } } local err = null switch(phase) { case 0: // find places for stations if ( print_message_box > 0 ) { gui.add_message_at(pl, "______________________ build rail ______________________", world.get_time()) gui.add_message_at(pl, " line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ")", world.get_time()) } if (c_start == null) { c_start = ::finder.find_station_place(fsrc, fdest) } if (c_start && c_end == null) { c_end = ::finder.find_station_place(fdest, c_start, finalize) } if (c_start.len()>0 && c_end.len()>0) { phase ++ } else { print("No station places found") return error_handler() } case 1: // build way { sleep() local d = pl.get_current_cash() local err = null local line_start = null if ( (abs(c_start[0].x - c_end[0].x) + abs(c_start[0].y - c_end[0].y)) < 13 && industry_manager.get_combined_link(fsrc, fdest, freight) > 0) { //gui.add_message_at(pl, "c_start " + coord_to_string(c_start[0]) + " c_end " + coord_to_string(c_end[0]), c_end[0]) local d = settings.get_station_coverage() local f = 0 for ( local i = 0; i < fd.len(); i++ ) { f = abs(c_start[0].x - fd[i].x) + abs(c_start[0].y - fd[i].y) if ( f <= d ) { local extension = find_extension(wt_rail) if ( extension != null ) { local err = command_x.build_station(our_player, c_start[0], extension) if ( err == null ) { return r_t(RT_TOTAL_SUCCESS) } } } } if ( debug ) { gui.add_message_at(pl, "c_start " + coord_to_string(c_start[0]) + " c_end " + coord_to_string(c_end[0]), c_end[0]) ::debug.pause } } // test route for calculate cost local calc_route = null local r1 = test_route(our_player, c_start, c_end, planned_way) local r2 = test_route(our_player, c_end, c_start, planned_way) if ( r1 == "No route" && r2 == "No route" ) { return r_t(RT_TOTAL_FAIL) } else if ( r1 == "No route" && r2 != "No route" ) { calc_route = r2 } else if ( r1 != "No route" && r2 == "No route" ) { calc_route = r1 } else if ( r1.routes.len() > r2.routes.len() ) { calc_route = r2 r1 = null } else { calc_route = r1 } local build_status = null if ( calc_route.routes.len() < 13 ) { //gui.add_message_at(pl, "route len < 13 tiles ", c_end) //gui.add_message_at(pl, "c_start " + coord_to_string(c_start) + " c_end " + coord_to_string(c_end), c_end) local extension = find_extension(wt_rail) //local start_h = tile_x(c_start.x, c_start.y, c_start.z).get_halt().get_name() //local end_h = tile_x(c_end.x, c_end.y, c_end.z).get_halt().get_name() return error_handler() } else { build_status = check_build_station(calc_route) //gui.add_message_at(pl, "(129) build_status : " + build_status, world.get_time()) //::debug.pause() if ( build_status != true ) { calc_route = test_route(our_player, c_end, c_start, planned_way) if ( calc_route == "No route" ) { return r_t(RT_TOTAL_FAIL) } build_status = check_build_station(calc_route) if ( build_status == true ) { local c = c_start c_start = c_end c_end = c line_start = t_end[0] } else { return r_t(RT_TOTAL_FAIL) } } else { if ( build_status == true ) { line_start = t_start[0] } else { return r_t(RT_TOTAL_FAIL) } } } //gui.add_message_at(pl, "(146) build_status : " + build_status, world.get_time()) sleep() local build_cost = (calc_route.routes.len() * planned_way.get_cost()) + ((st_lenght*2)*planned_station.get_cost()) + planned_depot.get_cost() + (calc_route.bridge_lens * calc_route.bridge_obj.get_cost()) local cost_monthly = (calc_route.routes.len() * planned_way.get_maintenance()) + ((st_lenght*2)*planned_station.get_maintenance()) + planned_depot.get_maintenance() + (calc_route.bridge_lens * calc_route.bridge_obj.get_maintenance()) build_cost = build_cost/100 //build_cost + build_cost += (calc_route.tiles_tree * ((tree_desc_x.get_price()/100)*2)) //gui.add_message_at(pl, "tree remove cost: " + tree_desc_x.get_price(), world.get_time()) //gui.add_message_at(pl, "terraform cost: " + command_x.slope_get_price(82), world.get_time()) // terraform cost local terraform_cost = command_x.slope_get_price(82)/100 build_cost += st_lenght*terraform_cost //gui.add_message_at(pl, "cash: " + pl.get_current_cash() + " build cost: " + build_cost + " montly cost: " + (cost_monthly/100), world.get_time()) cost_monthly = (cost_monthly/100)+(pl.get_current_maintenance()/100) //gui.add_message_at(pl, "cash: " + pl.get_current_cash() + " current_maintenance(): " + pl.get_current_maintenance() + " get_maintenance()[0]: " + (-pl.get_maintenance()[0]), world.get_time()) //gui.add_message_at(pl, " montly cost new: " + cost_monthly, world.get_time()) sleep() // if combined station from ship local cash = pl.get_current_cash() local st_dock = search_station(line_start, wt_water, 1) //gui.add_message_at(our_player, "search_station(t_start[0], wt_water, 1) " + st_dock + " t_start[0] " + coord3d_to_string(t_start[0]), world.get_time()) if ( st_dock ) { local st = halt_x.get_halt(st_dock[0], our_player) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() == 0 ) { cash = our_player.get_current_net_wealth() //gui.add_message_at(our_player, "rail: combined station -> get_current_net_wealth() " + (our_player.get_current_net_wealth()/100), world.get_time()) } else { } } } if ( (cash-build_cost) < (cost_monthly*4) ) { //remove_tile_to_empty(t_start, wt_rail, 1) //remove_tile_to_empty(t_end, wt_rail, 1) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) gui.add_message_at(pl, "Rail: Way construction cost to height: cash: " + cash + " build cost: " + build_cost, world.get_time()) build_check_month = world.get_time().ticks + (build_check_time(build_cost) * world.get_time().ticks_per_month) return error_handler() } /* if ( calc_route.routes.len() > 150 && (cash-build_cost-(build_cost/2)) < (cost_monthly*10) ) { //remove_tile_to_empty(t_start, wt_rail, 1) //remove_tile_to_empty(t_end, wt_rail, 1) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) gui.add_message_at(pl, "Way to long for rentabel build.", world.get_time()) return error_handler() } */ //gui.add_message_at(pl, "c_start.len() " + c_start.len() + " - c_end.len() " + c_end.len(), world.get_time()) //err = construct_rail(pl, c_start, c_end, planned_way ) if ( r1 == null ) { err = construct_rail(pl, c_end, c_start, planned_way ) local c = c_start c_start = c_end c_end = c } else { err = construct_rail(pl, c_start, c_end, planned_way ) } print("Way construction cost: " + (d-pl.get_current_cash()) ) if (err) { // fail, c_start, c_end still arrays //print("Failed to build way from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0])) gui.add_message_at(pl, "Failed to build way from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0]), world.get_time()) return error_handler() } else { // success, now c_start, c_end contain the start/end points where something was built if ( print_message_box == 1 ) { gui.add_message_at(pl, "Build rail from " + coord_to_string(c_start) + " to " + coord_to_string(c_end), world.get_time()) } // test connect in double way local asf = astar_route_finder(wt_rail) // check start -> end local wayline = asf.search_route([c_start], [c_end]) if ( "err" in wayline ) { // no route found } else { check_doubleway_in_line(wayline, wt_rail) // check end -> start wayline.clear() wayline = asf.search_route([c_end], [c_start]) check_doubleway_in_line(wayline, wt_rail) } } if ( line_start == t_end[0] ) { local c = c_start c_start = c_end c_end = c c_route.reverse() } phase ++ } case 2: // build station and extensions { /* local err = command_x.build_station(pl, c_start, planned_station ) if (err) { print("Failed to build station at " + coord_to_string(c_start)) if ( print_message_box == 2 ) { gui.add_message_at(pl, "Failed to build rail station at " + coord_to_string(c_start) + " error " + err, world.get_time()) } return error_handler() } */ if ( print_message_box == 2 ) { gui.add_message_at(pl, " planned_convoy.length " + planned_convoy.length, world.get_time()) } // stations lenght local a = planned_convoy.length local count = 0 do { a -= 16 count += 1 } while(a > 0) if ( print_message_box == 1 ) { gui.add_message_at(our_player, " rail_connector stations lenght: " + count, world.get_time()) } // check combined station or connect factory src local tiles_y = abs(fs[0].y - c_start.y) local tiles_x = abs(fs[0].x - c_start.x) // local fsrc_building = fs[0].find_object(mo_building).get_desc() local size = fsrc_building.get_size(0) //local size_x = size.slice(0, size.find(",")) //local size_y = size.slice(size.find(",")) local tiles_c = 0//(fs.len() / 2) + settings.get_station_coverage() + 2 if ( size.x == size.y ) { tiles_c = size.x + 2 } else if ( size.x > size.y ) { tiles_c = size.x + 2 } else if ( size.x < size.y ) { tiles_c = size.y + 2 } else { tiles_c = (fs.len() / 2) + settings.get_station_coverage() + 2 } //gui.add_message_at(pl, "fsrc tiles_c " + tiles_c, world.get_time()) local combined_halt = false if (tiles_x > tiles_c || tiles_y > tiles_c) { //gui.add_message_at(pl, "tiles_x = " + tiles_x + " - tiles_y = " + tiles_y + " - tiles_c = " + tiles_c, world.get_time()) combined_halt = true } // // check place and build station to c_start s_src = check_station(pl, c_start, c_route, count, wt_rail, planned_station, 1, combined_halt) if ( s_src == false ) { print("Failed to build station at " + coord_to_string(c_start)) if ( print_message_box > 0 ) { gui.add_message_at(pl, "Failed to build rail station at s_src " + coord3d_to_string(c_start), world.get_time()) } remove_wayline(c_route, c_route.len()-1, wt_rail) return error_handler() } // low cost station for line end local station_list = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x(freight)) local x = 0 local station_select = planned_station foreach(station in station_list) { if ( station.cost < station_select.cost ) { station_select = station } } // check combined station or connect factory dest tiles_y = abs(fd[0].y - c_end.y) tiles_x = abs(fd[0].x - c_end.x) // local fdest_building = fd[0].find_object(mo_building).get_desc() size = fdest_building.get_size(0) //size_x = size.slice(0, size.find(",")) //size_y = size.slice(size.find(",")) tiles_c = 0//(fs.len() / 2) + settings.get_station_coverage() + 2 if ( size.x == size.y ) { tiles_c = size.x + 2 } else if ( size.x > size.y ) { tiles_c = size.x + 2 } else if ( size.x < size.y ) { tiles_c = size.y + 2 } else { tiles_c = (fd.len() / 2) + settings.get_station_coverage() + 2 } //gui.add_message_at(pl, "fdest tiles_c " + tiles_c, world.get_time()) combined_halt = false if (tiles_x > tiles_c || tiles_y > tiles_c) { //gui.add_message_at(pl, "tiles_x = " + tiles_x + " - tiles_y = " + tiles_y + " - tiles_c = " + tiles_c, world.get_time()) combined_halt = true } // check place and build station to c_end s_dest = check_station(pl, c_end, c_route, count, wt_rail, station_select, 1, combined_halt) if ( s_dest == false ) { print("Failed to build station at " + coord_to_string(c_end)) if ( print_message_box > 0 ) { gui.add_message_at(pl, "Failed to build rail station at s_dest " + coord_to_string(c_end), world.get_time()) } build_check_month = world.get_time().ticks + world.get_time().ticks_per_month remove_wayline(c_route, c_route.len()-1, wt_rail, s_src.len()) remove_tile_to_empty(s_src, wt_rail) remove_tile_to_empty(c_start, wt_rail, 0) remove_tile_to_empty(c_end, wt_rail, 0) return error_handler() } //local if ( finalize ) { // store place of unload station for future use local fs = ::station_manager.access_freight_station(fdest) if (fs.rail_unload == null) { fs.rail_unload = c_end print( recursive_save({unload = c_end}, "\t\t\t", []) ) } } if ( print_message_box == 2 ) { //gui.add_message_at(our_player, " ... rotate " + rotate, world.get_time()) gui.add_message_at(pl, "Build station on " + coord3d_to_string(c_start) + " and " + coord3d_to_string(c_end), world.get_time()) } phase += 3 } case 5: // build depot { if ( print_message_box == 3 ) { gui.add_message_at(pl, "___________ exists depots rail ___________", world.get_time()) gui.add_message_at(pl," c_start pos: " + coord_to_string(c_start) + " : c_end pos: " + coord_to_string(c_end), world.get_time()) } // search depot to range start and end station local depot_found = search_depot(c_start, wt_rail) local starts_field = c_start if ( !depot_found ) { depot_found = search_depot(c_end, wt_rail) if ( !depot_found ) { } else { starts_field = c_end } } if ( !depot_found && print_message_box == 3 ) { gui.add_message_at(pl," *** depot not found *** ", world.get_time()) } else if ( print_message_box == 3 ) { gui.add_message_at(pl," ---> depot found : " + depot_found.get_pos(), coord_to_string(depot_found)) } // build rail to depot if ( depot_found ) { c_depot = depot_found local err = command_x.build_road(pl, starts_field, c_depot, planned_way, false, true) } else { local i = 0 if ( c_route.len() > 10 ) { i = c_route.len() - 5 - s_src.len() } local err = construct_rail_to_depot(pl, c_route[i], planned_way) //c_start if (err) { print("Failed to build depot access from " + coord_to_string(c_start)) return error_handler() } // depot already existing ? if (c_depot.find_object(mo_depot_rail) == null) { // no: build local err = command_x.build_depot(pl, c_depot, planned_depot ) if (err) { print("Failed to build depot at " + coord_to_string(c_depot)) return error_handler() } if (finalize) { // store depot location local fs = ::station_manager.access_freight_station(fsrc) if (fs.rail_depot == null) { fs.rail_depot = c_depot } } } if ( print_message_box == 1 ) { gui.add_message_at(pl, "Build depot on " + coord_to_string(c_depot), world.get_time()) } } phase ++ } case 6: // create schedule { //gui.add_message_at(pl, "c_start " + coord_to_string(c_start) + " - c_end " + coord_to_string(c_end), world.get_time()) local sched = schedule_x(wt_rail, []) sched.entries.append( schedule_entry_x(c_start, 100, 0) ); sched.entries.append( schedule_entry_x(c_end, 0, 0) ); c_sched = sched phase ++ } case 7: // create line and set schedule { pl.create_line(wt_rail) // find the line - it is a line without schedule and convoys local list = pl.get_line_list() foreach(line in list) { if (line.get_waytype() == wt_rail && line.get_schedule().entries.len()==0) { // right type, no schedule -> take this. c_line = line break } } // set schedule c_line.change_schedule(pl, c_sched); phase ++ } case 8: // append vehicle_constructor and set line { local c = vehicle_constructor_t() c.p_depot = depot_x(c_depot.x, c_depot.y, c_depot.z) c.p_line = c_line c.p_convoy = planned_convoy c.p_count = min(planned_convoy.nr_convoys, 1) append_child(c) local toc = get_ops_total(); print("rail_connector wasted " + (toc-tic) + " ops") // rename line local line_name = c_line.get_name() local str_search = ") " + translate("Line") local st_names = c_line.get_schedule().entries if ( line_name.find(str_search) != null ) { local new_name = translate("Train") + " " + translate(freight) + " " + st_names[0].get_halt(pl).get_name() + " - " + st_names[1].get_halt(pl).get_name() c_line.set_name(new_name) } phase ++ return r_t(RT_PARTIAL_SUCCESS) } case 9: // currently not used { } } //gui.add_message_at(pl, "finalize industry_manager.set_link_state ", world.get_time()) if (finalize) { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_built) if ( industry_manager.get_combined_link(fsrc, fdest, freight) > 0 ) { local a = industry_manager.get_combined_link(fsrc, fdest, freight) - 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) } } industry_manager.access_link(fsrc, fdest, freight).append_line(c_line) //gui.add_message_at(pl, "Build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 1), world.get_time()) local cs = tile_x(c_start.x, c_start.y, c_start.z) local ce = tile_x(c_end.x, c_end.y, c_end.z) /*if (c_start.len()>0 && c_end.len()>0) { local cs = c_start[0] local ce = c_end[0] }*/ local st = halt_x.get_halt(cs, pl) local f_name = ["", ""] if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[0] = fl_st[0].get_name() } else { f_name[0] = st.get_name() } } st = halt_x.get_halt(ce, pl) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[1] = fl_st[0].get_name() } else { f_name[1] = st.get_name() } } local msgtext = format(translate("%s build rail line from %s (%s) to %s (%s)"), pl.get_name(), f_name[0], coord_to_string(cs), f_name[1], coord_to_string(ce)) //gui.add_message_at(pl, pl.get_name() + " build rail line from " + f_name[0] + " (" + coord_to_string(cs) + ") to " + f_name[1] + " (" + coord_to_string(ce) + ")", c_start) gui.add_message_at(pl, msgtext, c_start) return r_t(RT_TOTAL_SUCCESS) } function error_handler() { local r = r_t(RT_TOTAL_FAIL) // TODO rollback if (reports.len()>0) { // there are alternatives print("Delivering alternative connector") r.report = reports.pop() if (r.report.action && r.report.action.getclass() == amphibious_connection_planner_t) { print("Delivering amphibious_connection_planner_t") r.node = r.report.action r.report = null } } else { print("Error during setup of rail connection.") industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_failed); } return r } function construct_rail(pl, starts, ends, way) { local as = astar_builder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) as.bridger = pontifex(pl, way) if (as.bridger.bridge == null) { as.bridger = null } local res = as.search_route(starts, ends) if ("err" in res) { return res.err } c_start = res.start c_end = res.end c_route = res.routes } function construct_rail_to_depot(pl, start, way) { local as = depot_pathfinder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) local res = as.search_route(start) if ("err" in res) { return res.err } local d = res.end c_depot = tile_x(d.x, d.y, d.z) } function check_build_station(calc_route) { local routes = calc_route.routes local err = null // count tiles test for station local nr_tile_test = 3 if ( routes.len() > 150 ) { //gui.add_message_at(our_player, "distance " + distance, world.get_time()) //gui.add_message_at(our_player, "calc route " + coord3d_to_string(c_start[0]) + " to " + coord3d_to_string(c_end[0]) + ": way tiles = " + calc_route.routes.len() + " bridge tiles = " + calc_route.bridge_lens + " tree tiles = " + calc_route.tiles_tree, world.get_time()) } local s = routes.len()-nr_tile_test t_start = routes.slice(s) t_start.reverse() //t_start.append(tile_x(c_start[0].x, c_start[0].y, c_start[0].z)) t_end = routes.slice(0, nr_tile_test) //t_end.append(tile_x(c_end[0].x, c_end[0].y, c_end[0].z)) // stations lenght local a = planned_convoy.length do { a -= 16 st_lenght += 1 } while(a > 0) if ( !planned_way.is_available(world.get_time()) ) { planned_way = find_object("way", wt_rail, planned_way.get_topspeed()) } // check exist way local check_way = [] for ( local j = 0; j < (nr_tile_test*2); j++ ) { check_way.append(0) } for ( local i = 0; i < (nr_tile_test*2); i++ ) { if ( i < nr_tile_test ) { // start if ( tile_x(t_start[i].x, t_start[i].y, t_start[i].z).has_way(wt_rail) ) { //find_object(mo_way) check_way[i] = 1 } } else { // end if ( tile_x(t_end[i-nr_tile_test].x, t_end[i-nr_tile_test].y, t_end[i-nr_tile_test].z).has_way(wt_rail) ) { //find_object(mo_way) check_way[i] = 1 } } } for ( local j = 0; j < t_start.len()-1; j++ ) { err = command_x.build_way(pl, t_start[j], t_start[j+1], planned_way, true) if ( err != null ) { //gui.add_message_at(pl, "check_station build_way " + err, t_start[0]) } } //err = command_x.build_way(pl, t_start[0], t_start[1], planned_way, true) //if ( err != null ) { gui.add_message_at(pl, "check_station build_way " + err, t_start[0]) } //err = command_x.build_way(pl, t_start[1], t_start[2], planned_way, true) //if ( err != null ) { gui.add_message_at(pl, "check_station build_way " + err, t_start[0]) } //::debug.pause() if ( err == null ) { err = check_station(pl, t_start[0], routes, st_lenght, wt_rail, planned_station, 0) if ( err == false ) { gui.add_message_at(pl, "check_station " + err, t_start[0]) } if ( err == true ) { // station start ok for ( local j = 0; j < t_end.len()-1; j++ ) { err = command_x.build_way(pl, t_end[j], t_end[j+1], planned_way, true) if ( err != null ) { gui.add_message_at(pl, "check_station build_way " + err, t_end[0]) } } //::debug.pause() //err = command_x.build_way(pl, t_end[0], t_end[1], planned_way, true) //if ( err != null ) { gui.add_message_at(pl, "check_station build_way t_end " + err, t_end[0]) } //err = command_x.build_way(pl, t_end[1], t_end[2], planned_way, true) //if ( err != null ) { gui.add_message_at(pl, "check_station build_way t_end " + err, t_end[0]) } //local tool = command_x(tool_remove_way) if ( err == null ) { err = check_station(pl, t_end[0], routes, st_lenght, wt_rail, planned_station, 0) if ( err == true ) { // station end ok // remove track -> error by build /*for ( local i = 0; i < (nr_tile_test*2); i++ ) { if ( i < nr_tile_test && check_way[i] == 0 ) { remove_tile_to_empty(t_start[i], wt_rail, 0) } else if ( i > (nr_tile_test-1) && check_way[i] == 0 ) { remove_tile_to_empty(t_end[i-nr_tile_test], wt_rail, 0) } }*/ remove_test_way(check_way, nr_tile_test, t_start, t_end, 1) //tool.work(our_player, t_start[0], t_start[2], "" + wt_rail) //tool.work(our_player, t_end[0], t_end[2], "" + wt_rail) } else { // failed station place end /*for ( local i = 0; i < (nr_tile_test*2); i++ ) { if ( check_way[i] == 0 && i < nr_tile_test ) { remove_tile_to_empty(t_start[i], wt_rail, 0) //gui.add_message_at(pl, "remove " + coord3d_to_string(t_start[i]), t_start[i]) } else if ( check_way[i] == 0 && i > (nr_tile_test-1) ) { remove_tile_to_empty(t_end[i-nr_tile_test], wt_rail, 0) //gui.add_message_at(pl, "remove " + coord3d_to_string(t_end[i-nr_tile_test]), t_end[i-nr_tile_test]) } }*/ remove_test_way(check_way, nr_tile_test, t_start, t_end, 1) return error_handler() } } else { // remove start and end /*for ( local i = 0; i < (nr_tile_test*2); i++ ) { if ( check_way[i] == 0 && i < nr_tile_test ) { remove_tile_to_empty(t_start[i], wt_rail, 0) } else if ( check_way[i] == 0 && i > (nr_tile_test-1) ) { remove_tile_to_empty(t_end[i-nr_tile_test], wt_rail, 0) } }*/ remove_test_way(check_way, nr_tile_test, t_start, t_end, 1) } } else { // failed station place start // remove start //::debug.pause() /*for ( local i = 0; i < nr_tile_test; i++ ) { if ( check_way[i] == 0 && i < nr_tile_test ) { remove_tile_to_empty(t_start[i], wt_rail, 0) } }*/ remove_test_way(check_way, nr_tile_test, t_start, t_end, 0) return error_handler() } } else { // no built way start -> remove start /*for ( local i = 0; i < nr_tile_test; i++ ) { if ( check_way[i] == 0 && i < nr_tile_test ) { remove_tile_to_empty(t_start[i], wt_rail, 0) } }*/ remove_test_way(check_way, nr_tile_test, t_start, t_end, 0) } if ( print_message_box > 0 ) { gui.add_message_at(pl, "plan station start " + t_start[0] + " - plan station end " + t_end[0], t_start[2]) } return true } function remove_test_way(check_way, nr_tile_test, t_start, t_end, s) { for ( local i = 0; i < (nr_tile_test*2); i++ ) { if ( check_way[i] == 0 && i < nr_tile_test ) { remove_tile_to_empty(t_start[i], wt_rail, 0) } else if ( s == 1 && check_way[i] == 0 && i > (nr_tile_test-1) ) { remove_tile_to_empty(t_end[i-nr_tile_test], wt_rail, 0) } } } } class depot_pathfinder extends astar_builder { function estimate_distance(c) { local t = tile_x(c.x, c.y, c.z) if (t.is_empty() && t.get_slope()==0) { return 0 } local depot = t.find_object(mo_depot_rail) if (depot && depot.get_owner().nr == our_player_nr) { return 0 } return 10 } function add_to_open(c, weight) { if (c.dist == 0) { // test for depot local t = tile_x(c.x, c.y, c.z) if (t.is_empty()) { // depot not existing, we must build, increase weight weight += 25 * cost_straight } } base.add_to_open(c, weight) } function search_route(start) { prepare_search() local dist = estimate_distance(start) add_to_open(ab_node(start, null, 1, dist+1, dist, 0), dist+1) search() if (route.len() > 0) { for (local i = 1; i= 2 ) { //gui.add_message_at(pl, "no build line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") to many links", world.get_time()) return r_t(RT_TOTAL_FAIL) // } else { //gui.add_message_at(pl, "check line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") " + freight, world.get_time()) local st_dock = search_station(c_start, wt_water, 1) if ( !check_factory_link_line(fsrc, fdest, freight) && !st_dock ) { return r_t(RT_TOTAL_FAIL) } } local build_cash = player_x(our_player.nr).get_current_cash() + (((player_x(our_player.nr).get_current_net_wealth()/100) - player_x(our_player.nr).get_current_cash())/2) local build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 2) if ( industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) > 0 ) { build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) } if ( (build_check_month > world.get_time().ticks || build_cost > build_cash) && industry_manager.get_combined_link(fsrc, fdest, freight) == 0 ) { // not build link if ( debug ) gui.add_message_at(our_player, "#road_conn# not build line : build_check_month = " + build_check_month + " or build cost link > cash : build cost line " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 2) + " | build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 0), world.get_time()) if ( debug ) gui.add_message_at(our_player, " ---> link " + fsrc + " " + fsrc.get_name() + " - " + fdest.get_name(), world.get_time()) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } } switch(phase) { case 0: // station places if ( print_message_box > 0 && print_message_box != 4 ) { gui.add_message_at(our_player, "______________________ build road ______________________", world.get_time()) gui.add_message_at(pl, " line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ")", world.get_time()) } // count trials, and fail if necessary if (c_trial_route > 3) { print("Route building failed " + c_trial_route + " times.") if (debug) gui.add_message_at(pl, "Failed to complete route from " + coord_to_string(fsrc) + " to " + coord_to_string(fdest) + " after " + c_trial_route + " attempts", fsrc) return error_handler() } c_trial_route++ // make arrays if necessary if (type(c_start) == "instance") { c_start = [c_start] } if (type(c_end) == "instance") { c_end = [c_end] } // find places for stations if (c_generate_start) { c_start = ::finder.find_station_place(fsrc, fdest) } if (c_generate_end) { c_end = ::finder.find_station_place(fdest, c_start, finalize) } if (c_start.len()>0 && c_end.len()>0) { phase ++ } else { print("No station places found") return error_handler() } case 1: // build way { sleep() local d = pl.get_current_cash(); // test route for calculate cost local calc_route = test_route(our_player, c_start, c_end, planned_way) //gui.add_message_at(our_player, "plan road from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0]), world.get_time()) if ( print_message_box == 1 && calc_route != "No route" ) { gui.add_message_at(our_player, "distance " + (calc_route.routes.len() + calc_route.bridge_lens), world.get_time()) } if ( calc_route == "No route" ) { return r_t(RT_TOTAL_FAIL) } //gui.add_message_at(our_player, "calc route " + coord3d_to_string(c_start[0]) + " to " + coord3d_to_string(c_end[0]) + ": way tiles = " + calc_route.routes.len() + " bridge tiles = " + calc_route.bridge_lens + " tree tiles = " + calc_route.tiles_tree, world.get_time()) sleep() local build_cost = (calc_route.routes.len() * planned_way.get_cost()) + (planned_station.get_cost()*2) + planned_depot.get_cost() + (calc_route.bridge_lens * calc_route.bridge_obj.get_cost()) local cost_monthly = (calc_route.routes.len() * planned_way.get_maintenance()) + (planned_station.get_maintenance()*2) + planned_depot.get_maintenance() + (calc_route.bridge_lens * calc_route.bridge_obj.get_maintenance()) build_cost = build_cost/100 build_cost = build_cost + (calc_route.tiles_tree * (tree_desc_x.get_price()/100)) //gui.add_message_at(pl, "tree remove cost: " + tree_desc_x.get_price(), world.get_time()) //gui.add_message_at(pl, "cash: " + pl.get_current_cash() + " build cost: " + build_cost + " montly cost: " + (cost_monthly/100), world.get_time()) cost_monthly = (cost_monthly/100)+(pl.get_current_maintenance()/100) //gui.add_message_at(pl, "cash: " + pl.get_current_cash() + " current maintenance: " + pl.get_current_maintenance(), world.get_time()) //gui.add_message_at(pl, " montly cost new: " + cost_monthly, world.get_time()) sleep() // if combined station from ship local cash = pl.get_current_cash() local st_dock = search_station(calc_route.routes[calc_route.routes.len()-1], wt_water, 1) if ( st_dock ) { local st = halt_x.get_halt(st_dock[0], our_player) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() == 0 ) { cash = our_player.get_current_net_wealth() if ( print_message_box == 4 ) { gui.add_message_at(our_player, "road: combined station -> get_current_net_wealth() " + (our_player.get_current_net_wealth()/100), world.get_time()) } } else { } } } if ( (cash-build_cost) < (cost_monthly*4) ) { //gui.add_message_at(pl, "Way construction cost to height: cash: " + pl.get_current_cash() + " build cost: " + build_cost, world.get_time()) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) build_check_month = world.get_time().ticks + (build_check_time(build_cost) + world.get_time().ticks_per_month) return error_handler() } if ( !planned_way.is_available(world.get_time()) ) { planned_way = find_object("way", wt_road, planned_way.get_topspeed()) } local err = construct_road(pl, c_start, c_end, planned_way ) print("Way construction cost: " + (d-pl.get_current_cash()) ) if (err) { if ( c_start.len()>0 && c_end.len()>0) { print("Failed to build way from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0])) } else if (err) { print("Failed to build way from " + coord_to_string(c_start) + " to " + coord_to_string(c_end)) } if (err == "No route") { print("No route found from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) // no point to try again return error_handler() } // try again return restart_with_phase0() } if ( print_message_box == 1 ) { gui.add_message_at(our_player, "Build road from " + coord_to_string(c_start) + " to " + coord_to_string(c_end), world.get_time()) } phase ++ } case 2: // build station and extensions { local err = null local obj_building = tile_x(c_start.x, c_start.y, c_start.z).find_object(mo_building) if ( obj_building != null && obj_building.get_owner() != our_player ) { if (debug) gui.add_message_at(pl, " --- tile to build station not free", c_start) build_check_month = world.get_time().ticks + world.get_time().ticks_per_month return restart_with_phase0() //return error_handler() } else if ( c_generate_start || obj_building == null) { err = build_road_station(c_start, planned_station) //err = command_x.build_station(pl, c_start, planned_station ) } if (err) { if (debug) gui.add_message_at(pl, "Failed to build road station at " + coord_to_string(c_start) + " [" + err + "]", c_start)// try again if ( print_message_box == 2 ) { gui.add_message_at(pl, "Failed to build road station at " + coord_to_string(c_start) + " error " + err, world.get_time()) } return restart_with_phase0() } else { c_generate_start = false // station build, do not search for another place } err = build_road_station(c_end, planned_station) //err = command_x.build_station(pl, c_end, planned_station ) if (err) { if (debug) gui.add_message_at(pl, "Failed to build road station at " + coord_to_string(c_end) + " [" + err + "]", c_end) // try again return restart_with_phase0() } else { c_generate_end = false // station build, do not search for another place } if (finalize) { // store place of unload station for future use local fs = ::station_manager.access_freight_station(fdest) if (fs.road_unload == null) { fs.road_unload = c_end } } if (debug && c_trial_route>1) { gui.add_message_at(pl, "Completed route from " + coord_to_string(c_start) + " to " + coord_to_string(c_end) + " after " + c_trial_route + " attempts", c_end) } if ( print_message_box == 2 ) { gui.add_message_at(our_player, "Build station on " + coord_to_string(c_start) + " and " + coord_to_string(c_end), world.get_time()) } // local asf = astar_route_finder(wt_road) local result = asf.search_route([c_start], [c_end]) if ( "routes" in result ) { } else { if ( debug ) ::debug.pause() sleep() return r_t(RT_TOTAL_FAIL) } if ( result.routes.len() <= 3 ) { //gui.add_message_at(pl, "route len < 3 tiles ", c_end) local extension = find_extension(wt_road) local start_h = tile_x(c_start.x, c_start.y, c_start.z).get_halt().get_name() local end_h = tile_x(c_end.x, c_end.y, c_end.z).get_halt().get_name() if ( extension != null && start_h == end_h ) { remove_tile_to_empty(c_start, wt_road, 0) command_x.build_station(our_player, c_start, extension) remove_tile_to_empty(c_end, wt_road, 0) command_x.build_station(our_player, c_end, extension) if ( result.routes.len() == 3 ) { foreach(node in result.routes) { local tile = tile_x(node.x, node.y, node.z) if ( tile.find_object(mo_building) == null ) { remove_tile_to_empty(tile, wt_road, 0) } } } } return r_t(RT_TOTAL_SUCCESS) } phase += 3 } case 5: // build depot { if ( print_message_box == 3 ) { gui.add_message_at(our_player, "___________ exists depots road ___________", world.get_time()) gui.add_message_at(our_player," c_start pos: " + coord_to_string(c_start) + " : c_end pos: " + coord_to_string(c_end), world.get_time()) } // search depot to range start and end station local depot_found = search_depot(c_start, wt_road) local starts_field = c_start if ( !depot_found ) { depot_found = search_depot(c_end, wt_road) starts_field = c_end } if ( !depot_found && print_message_box == 3 ) { gui.add_message_at(pl," *** depot not found *** ", world.get_time()) } else if ( print_message_box == 3 ) { gui.add_message_at(pl," ---> depot found : " + depot_found.get_pos(), coord_to_string(depot_found)) } local err = null // build road to depot if ( depot_found ) { c_depot = depot_found err = command_x.build_road(pl, starts_field, c_depot, planned_way, false, true) //err = construct_road(our_player, station_to_depot, c_depot, planned_way) } else { local i = c_route.len()-1 if ( i > 8 ) { i -= 8 } local trial = 0 local err = null do { // try 3x to find road to suitable depot spot err = construct_road_to_depot(pl, c_route[i], planned_way) trial ++ } while (err != null && err != "No route" && trial < 3) if (err) { // we do not like to fail at this phase, try to find another spot phase = 3 return r_t(RT_PARTIAL_SUCCESS) } // depot already existing ? if (c_depot.find_object(mo_depot_road) == null) { // no: build local err = command_x.build_depot(pl, c_depot, planned_depot ) if (err) { print("Failed to build depot at " + coord_to_string(c_depot)) return error_handler() } if (finalize) { // store depot location local fs = ::station_manager.access_freight_station(fsrc) if (fs.road_depot == null) { fs.road_depot = c_depot } } } if ( print_message_box == 3 ) { gui.add_message_at(our_player, "Build depot on " + coord_to_string(c_depot), world.get_time()) } } phase ++ } case 6: // create schedule { local sched = schedule_x(wt_road, []) sched.entries.append( schedule_entry_x(c_start, 100, 0) ); sched.entries.append( schedule_entry_x(c_end, 0, 0) ); c_sched = sched phase ++ } case 7: // create line and set schedule { pl.create_line(wt_road) // find the line - it is a line without schedule and convoys local list = pl.get_line_list() foreach(line in list) { if (line.get_waytype() == wt_road && line.get_schedule().entries.len()==0) { // right type, no schedule -> take this. c_line = line break } } // set schedule c_line.change_schedule(pl, c_sched); phase ++ } case 8: // append vehicle_constructor and set line { local c = vehicle_constructor_t() c.p_depot = depot_x(c_depot.x, c_depot.y, c_depot.z) c.p_line = c_line c.p_convoy = planned_convoy if ( world.get_time().year < 1935 && get_set_name() == "pak64.german" ) { c.p_count = min(planned_convoy.nr_convoys, 6) } else { c.p_count = min(planned_convoy.nr_convoys, 3) } append_child(c) local toc = get_ops_total(); print("road_connector wasted " + (toc-tic) + " ops") c_generate_start = c_start == null c_generate_end = c_end == null // rename line local line_name = c_line.get_name() local str_search = ") " + translate("Line") local st_names = c_line.get_schedule().entries if ( line_name.find(str_search) != null ) { local new_name = translate("road") + " " + translate(freight) + " " + st_names[0].get_halt(pl).get_name() + " - " + st_names[1].get_halt(pl).get_name() c_line.set_name(new_name) } phase ++ return r_t(RT_PARTIAL_SUCCESS) } case 9: // currently not used { } } if (finalize) { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_built) if ( industry_manager.get_combined_link(fsrc, fdest, freight) > 0 ) { local a = industry_manager.get_combined_link(fsrc, fdest, freight) - 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) } } industry_manager.access_link(fsrc, fdest, freight).append_line(c_line) //gui.add_message_at(pl, "Build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 2), world.get_time()) local cs = c_start local ce = c_end /* if (c_start.len()>0 && c_end.len()>0) { local cs = c_start[0] local ce = c_end[0] }*/ local st = halt_x.get_halt(cs, pl) local f_name = ["", ""] if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[0] = fl_st[0].get_name() } else { f_name[0] = st.get_name() } } st = halt_x.get_halt(ce, pl) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[1] = fl_st[0].get_name() } else { f_name[1] = st.get_name() } } local msgtext = format(translate("%s build road line from %s (%s) to %s (%s)"), pl.get_name(), f_name[0], coord_to_string(cs), f_name[1], coord_to_string(ce)) //gui.add_message_at(pl, pl.get_name() + " build road line from " + f_name[0] + " (" + coord_to_string(cs) + ") to " + f_name[1] + " (" + coord_to_string(ce) + ")", c_start) gui.add_message_at(pl, msgtext, c_start) return r_t(RT_TOTAL_SUCCESS) } function restart_with_phase0() { if (c_generate_start) { c_start = null } if (c_generate_end ) { c_end = null } phase = 0 return r_t(RT_PARTIAL_SUCCESS) } function error_handler() { local r = r_t(RT_TOTAL_FAIL) // TODO rollback if (reports.len()>0) { // there are alternatives print("Delivering alternative connector") r.report = reports.pop() if (r.report.action && r.report.action.getclass() == amphibious_connection_planner_t) { print("Delivering amphibious_connection_planner_t") r.node = r.report.action r.report = null } } else { print("Error during setup of road connection.") industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_failed); } return r } function construct_road(pl, starts, ends, way) { local as = astar_builder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) as.bridger = pontifex(pl, way) if (as.bridger.bridge == null) { as.bridger = null } local res = as.search_route(starts, ends) if ("err" in res) { return res.err } c_start = res.start c_end = res.end c_route = res.routes } function construct_road_to_depot(pl, start, way) { local as = depot_pathfinder() as.builder = way_planner_x(pl) as.way = way as.builder.set_build_types(way) local res = as.search_route(start) if ("err" in res) { return res.err } local d = res.end c_depot = tile_x(d.x, d.y, d.z) } function build_road_station(tile, station) { local err = null local d = tile_x(tile.x, tile.y, tile.z).get_way_dirs(wt_road) local rotation = 0 switch (d) { case 2: rotation = 1 break case 1: rotation = 2 break case 8: rotation = 3 break case 10: rotation = 1 break default: } err = command_x.build_station(our_player, tile, station, rotation ) return err } } class depot_pathfinder extends astar_builder { function estimate_distance(c) { local t = tile_x(c.x, c.y, c.z) if (t.is_empty() && t.get_slope()==0) { return 0 } local depot = t.find_object(mo_depot_road) if (depot && depot.get_owner().nr == our_player_nr) { return 0 } return 10 } function add_to_open(c, weight) { if (c.dist == 0) { // test for depot local t = tile_x(c.x, c.y, c.z) if (t.is_empty()) { // depot not existing, we must build, increase weight weight += 25 * cost_straight } } base.add_to_open(c, weight) } function search_route(start) { prepare_search() local dist = estimate_distance(start) add_to_open(ab_node(start, null, 1, dist+1, dist, 0), dist+1) search() if (route.len() > 0) { for (local i = 1; i= 1 ) { //gui.add_message_at(pl, "no build line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ") to many links", world.get_time()) return r_t(RT_TOTAL_FAIL) } local build_cash = player_x(our_player.nr).get_current_cash() + (((player_x(our_player.nr).get_current_net_wealth()/100) - player_x(our_player.nr).get_current_cash())/2) local build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 3) if ( industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) > 0 ) { build_cost = industry_manager.get_link_build_cost(fsrc, fdest, freight, 0) } if ( (build_check_month > world.get_time().ticks || build_cost > build_cash) && industry_manager.get_combined_link(fsrc, fdest, freight) == 0 ) { // not build link if ( debug ) gui.add_message_at(our_player, "#ship_conn# not build line : build_check_month = " + build_check_month + " or build cost link > cash : build cost line " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 3) + " | build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 0), world.get_time()) if ( debug ) gui.add_message_at(our_player, " ---> link " + fsrc + " " + fsrc.get_name() + " - " + fdest.get_name(), world.get_time()) industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_missing) return r_t(RT_TOTAL_FAIL) } } switch(phase) { case 0: { if ( print_message_box > 0 ) { gui.add_message_at(pl, "______________________ build ship ______________________", world.get_time()) gui.add_message_at(pl, " line from " + fsrc.get_name() + " (" + coord_to_string(fs[0]) + ") to " + fdest.get_name() + " (" + coord_to_string(fd[0]) + ")", world.get_time()) //::debug.pause() } // find flat harbour building if (planned_harbour_flat == null) { local station_list = building_desc_x.get_available_stations(building_desc_x.flat_harbour, wt_water, good_desc_x(freight)) planned_harbour_flat = industry_connection_planner_t.select_station(station_list, 1, planned_convoy.capacity) } if ( print_message_box == 2 ) { local flat = "----" if ( planned_harbour_flat ) { flat = planned_harbour_flat.get_name() } gui.add_message_at(pl," ... build station: " + planned_station.get_name() + " / " + flat, world.get_time()) } phase ++ } case 1: // find empty water tiles if (c_start == null) { c_start = find_anchorage(fsrc, planned_station, planned_harbour_flat, c_harbour_tiles) } if (c_end == null) { c_end = find_anchorage(fdest, planned_station, planned_harbour_flat, c_harbour_tiles) } if (c_start.len()>0 && c_end.len()>0) { if ( print_message_box == 2 ) { gui.add_message_at(pl, "Water way from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0]), world.get_time()) } phase ++ } else { if ( print_message_box == 2 ) { gui.add_message_at(pl, " ... ERROR No station places found ", world.get_time()) gui.add_message_at(pl, "---------------------- ship end -----------------------", world.get_time()) } print("No station places found") return error_handler() } case 2: // find path between both factories { local err = find_route() if (err) { print("No way from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) if ( print_message_box == 2 ) { gui.add_message_at(pl, "No way from " + coord_to_string(c_start[0]) + " to " + coord_to_string(c_end[0]), world.get_time()) } return error_handler() } phase ++ } case 3: // build harbour and extensions { local key local err = null { //if ( tile_x(c_start.x, c_start.y, c_start.z).is_empty() ) { key = coord3d_to_key(c_start[0]) if (key in c_harbour_tiles) { if ( c_harbour_tiles[key].get_halt() && c_harbour_tiles[key].get_halt().get_owner().nr == our_player_nr && c_harbour_tiles[key].find_object(mo_building) && c_harbour_tiles[key].find_object(mo_building).get_desc().get_type()==building_desc_x.station ) { // station from player exists - combined station if ( print_message_box == 2 ) { gui.add_message_at(our_player, "Cannot place any harbour at " + coord_to_string(c_harbour_tiles[key]) + " station exists :: search new place", c_harbour_tiles[key]) } // to do search new field c_start.clear() c_start = find_new_place(c_harbour_tiles[key].get_halt(), planned_station, planned_harbour_flat, c_harbour_tiles) key = coord3d_to_key(c_start[0]) if ( c_harbour_tiles[key].get_halt() && c_harbour_tiles[key].get_halt().get_owner().nr == our_player_nr && c_harbour_tiles[key].find_object(mo_building) && c_harbour_tiles[key].find_object(mo_building).get_desc().get_type()==building_desc_x.station ) { gui.add_message_at(our_player, "Cannot place any harbour at " + coord_to_string(c_harbour_tiles[key]), c_harbour_tiles[key]) return r_t(RT_TOTAL_FAIL) } else { err = build_harbour(c_harbour_tiles[key], c_start) } } else { err = build_harbour(c_harbour_tiles[key], c_start) if (err) { if ( c_start.len() > 1 ) { c_start.clear() c_start = find_anchorage(fsrc, planned_station, planned_harbour_flat, c_harbour_tiles) key = coord3d_to_key(c_start[0]) if ( c_start.len() > 0 ) { err = null err = build_harbour(c_harbour_tiles[key], c_start) } } } } } if (err) { print("Failed to build harbour at " + key + " / " + err) if ( print_message_box == 2 ) { gui.add_message_at(pl, " --- Failed to build harbour at " + key + " / " + err, world.get_time()) gui.add_message_at(pl, " --- c_start " + coord_to_string(c_start[0]), world.get_time()) } return r_t(RT_TOTAL_FAIL) } } // check station connection to factory or combined station if (err == null) { //remove_field(c_end[0]) key = coord3d_to_key(c_end[0]) if (key in c_harbour_tiles) { if ( c_harbour_tiles[key].find_object(mo_building) != null ) { if (debug) gui.add_message_at(pl, " --- tile to build harbour not free", world.get_time()) return r_t(RT_TOTAL_FAIL) } err = build_harbour(c_harbour_tiles[key], c_end) } } if (err) { print("Failed to build harbour at " + key + " / " + err) if ( print_message_box == 5 ) { gui.add_message_at(pl, " --- Failed to build harbour at " + key + " / " + err, world.get_time()) gui.add_message_at(pl, " --- c_end " + coord_to_string(c_end[0]), world.get_time()) } return error_handler() } c_harbour_tiles = null if ( print_message_box == 2 ) { gui.add_message_at(pl, "Build harbour on " + coord_to_string(c_start[0]) + " and " + coord_to_string(c_end[0]), world.get_time()) } phase ++ } case 4: // find route again after harbour was built { if (c_start.len()>1 || c_end.len()>1) { local err = find_route() if (err) { print("No way2 from " + coord_to_string(c_start[0])+ " to " + coord_to_string(c_end[0])) return error_handler() } } phase ++ } case 5: // build depot { // search depot to range start and end station local depot_found = search_depot(c_start[0], wt_water) local starts_field = c_start[0] if ( !depot_found ) { depot_found = search_depot(c_end[0], wt_water) starts_field = c_end[0] } if ( !depot_found && print_message_box == 3 ) { gui.add_message_at(pl," *** depot not found *** ", world.get_time()) } else if ( print_message_box == 3 ) { gui.add_message_at(pl," ---> depot found : " + depot_found.get_pos(), coord_to_string(depot_found)) } // build ship to depot if ( depot_found ) { c_depot = depot_found //local err = command_x.build_road(pl, starts_field, c_depot, planned_way, false, true) } else { // depot already existing ? local depot_tiles = [] local tile_range = 4 depot_tiles.append(tile_x(c_start[0].x-tile_range, c_start[0].y-tile_range, c_start[0].z)) depot_tiles.append(tile_x(c_start[0].x+tile_range, c_start[0].y-tile_range, c_start[0].z)) depot_tiles.append(tile_x(c_start[0].x-tile_range, c_start[0].y+tile_range, c_start[0].z)) depot_tiles.append(tile_x(c_start[0].x+tile_range, c_start[0].y+tile_range, c_start[0].z)) for ( local i = 0; i < depot_tiles.len(); i++ ) { //gui.add_message_at(pl, "depot_tiles[i].is_water() " + coord_to_string(depot_tiles[i]) + " " + depot_tiles[i].is_water(), depot_tiles[i]) //gui.add_message_at(pl, "depot_tiles[i].is_empty() " + coord_to_string(depot_tiles[i]) + " " + depot_tiles[i].is_empty(), depot_tiles[i]) local tile_halt = ::halt_x.get_halt(depot_tiles[i], player_x(1)) if ( tile_halt != null ) { //gui.add_message_at(pl, "tile_halt.get_halt() " + coord_to_string(depot_tiles[i]) + " " + tile_halt.get_halt(player_x(1)), depot_tiles[i]) } if ( depot_tiles[i].is_water() && tile_halt == null && depot_tiles[i].get_objects().get_count()==0 ) { // c_depot = depot_tiles[i] //gui.add_message_at(pl, "depot tile " + coord_to_string(c_depot), c_depot) break } } if (c_depot.find_object(mo_depot_water) == null) { // no: build local err = command_x.build_depot(pl, c_depot, planned_depot ) if (err) { print("Failed to build depot at " + coord_to_string(c_depot)) return error_handler() } if (finalize) { // store depot location local fs = ::station_manager.access_freight_station(fsrc) if (fs.ship_depot == null) { fs.ship_depot = c_depot } } } if ( print_message_box == 3 ) { gui.add_message_at(pl, "Build depot on " + coord_to_string(c_depot), world.get_time()) } } phase ++ } case 6: // create schedule { local sched = schedule_x(wt_water, []) sched.entries.append( schedule_entry_x(c_start[0], 100, 0) ); sched.entries.append( schedule_entry_x(c_end[0], 0, 0) ); if ( sched.entries[0].get_halt(pl).get_name() == sched.entries[1].get_halt(pl).get_name() ) { // set new start //gui.add_message_at(pl," ... start name (" + sched.entries[0].get_halt(pl).get_name() + ") == end name (" + sched.entries[1].get_halt(pl).get_name() + ")", world.get_time()) //gui.add_message_at(pl," ... c_start len = " + c_start.len(), world.get_time()) c_start.clear() c_start = find_anchorage(fsrc, planned_station, planned_harbour_flat, c_harbour_tiles) sched.entries[0] = schedule_entry_x(c_start[0], 100, 0); //gui.add_message_at(pl," ... new start name (" + sched.entries[0].get_halt(pl).get_name() + ")", world.get_time()) //::debug.pause() } c_sched = sched phase ++ } case 7: // create line and set schedule { pl.create_line(wt_water) // find the line - it is a line without schedule and convoys local list = pl.get_line_list() foreach(line in list) { if (line.get_waytype() == wt_water && line.get_schedule().entries.len()==0) { // right type, no schedule -> take this. c_line = line break } } // set schedule c_line.change_schedule(pl, c_sched); phase ++ } case 8: // append vehicle_constructor ans set line { local c = vehicle_constructor_t() c.p_depot = depot_x(c_depot.x, c_depot.y, c_depot.z) c.p_line = c_line c.p_convoy = planned_convoy c.p_count = min(planned_convoy.nr_convoys, 1) // 1 ship to begin append_child(c) local toc = get_ops_total(); print("ship_connector wasted " + (toc-tic) + " ops") // rename line local line_name = c_line.get_name() local str_search = ") " + translate("Line") local st_names = c_line.get_schedule().entries if ( line_name.find(str_search) != null ) { local new_name = translate("Ship") + " " + translate(freight) + " " + st_names[0].get_halt(pl).get_name() + " - " + st_names[1].get_halt(pl).get_name() c_line.set_name(new_name) } phase ++ return r_t(RT_PARTIAL_SUCCESS) } case 9: // currently not used { } } if (finalize) { industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_built) if ( industry_manager.get_combined_link(fsrc, fdest, freight) > 0 ) { local a = industry_manager.get_combined_link(fsrc, fdest, freight) - 1 industry_manager.set_combined_link(fsrc, fdest, freight, a) } } industry_manager.access_link(fsrc, fdest, freight).append_line(c_line) //gui.add_message_at(pl, "Build cost link " + industry_manager.get_link_build_cost(fsrc, fdest, freight, 3), world.get_time()) /* local cs = [] local ce = [] if (c_start.len()>0 && c_end.len()>0) { cs.append(tile_x(c_start[0].x, c_start[0].y, c_start[0].z)) ce.append(tile_x(c_end[0].x, c_end[0].y, c_end[0].z)) } else { cs.append(c_start[0]) ce.append(c_end[0]) } gui.add_message_at(pl, pl.get_name() + " build ship line from " + f_name[0] + " (" + coord_to_string(square_x(cs[0].x, cs[0].y)) + ") to " + f_name[1] + " (" + coord_to_string(square_x(ce[0].x, ce[0].y)) + ")", c_start) */ if (c_start.len()>0 && c_end.len()>0) { local st = halt_x.get_halt(c_start[0], pl) local f_name = ["", ""] if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[0] = fl_st[0].get_name() } else { f_name[0] = st.get_name() } } st = halt_x.get_halt(c_end[0], pl) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[1] = fl_st[0].get_name() } else { f_name[1] = st.get_name() } } local msgtext = format(translate("%s build ship line from %s (%s) to %s (%s)"), pl.get_name(), f_name[0], coord_to_string(c_start[0]), f_name[1], coord_to_string(c_end[0])) //gui.add_message_at(pl, pl.get_name() + " build ship line from " + f_name[0] + " (" + coord_to_string(c_start[0]) + ") to " + f_name[1] + " (" + coord_to_string(c_end[0]) + ")", c_start[0]) gui.add_message_at(pl, msgtext, c_start[0]) } else { local st = halt_x.get_halt(c_start, pl) local f_name = ["", ""] if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[0] = fl_st[0].get_name() } else { f_name[0] = st.get_name() } } st = halt_x.get_halt(c_end, pl) if ( st ) { local fl_st = st.get_factory_list() if ( fl_st.len() > 0 ) { f_name[1] = fl_st[0].get_name() } else { f_name[1] = st.get_name() } } local msgtext = format(translate("%s build ship line from %s (%s) to %s (%s)"), pl.get_name(), f_name[0], coord_to_string(c_start), f_name[1], coord_to_string(c_end)) //gui.add_message_at(pl, pl.get_name() + " build ship line from " + f_name[0] + " (" + coord_to_string(c_start) + ") to " + f_name[1] + " (" + coord_to_string(c_end) + ")", c_start) gui.add_message_at(pl, msgtext, c_start) } return r_t(RT_TOTAL_SUCCESS) } function error_handler() { local r = r_t(RT_TOTAL_FAIL) // TODO rollback if (reports.len()>0) { // there are alternatives print("Delivering alternative connector") r.report = reports.pop() if (r.report.action && r.report.action.getclass() == amphibious_connection_planner_t) { print("Delivering amphibious_connection_planner_t") r.node = r.report.action r.report = null } } else { print("Error during setup of ship connection.") industry_manager.set_link_state(fsrc, fdest, freight, industry_link_t.st_failed); } return r } static function find_anchorage(factory, planned_station, planned_harbour_flat, c_harbour_tiles) { // try to find tiles already covered by some harbours local tile_list = ::finder.find_water_places( ::finder.get_tiles_near_factory(factory) ) local halt_list = factory.get_halt_list() local anch = [] if (tile_list.len()>0 && halt_list.len()>0) { foreach(tile in tile_list) { local h = halt_x.get_halt(tile, our_player) if (h) { foreach(halt in halt_list) { if ( (h <=> halt) == 0) { anch.append(tile) } } } } } if (anch.len()>0) { return anch } // find places to build harbour if (tile_list.len()>0) { foreach(tile in tile_list) { for(local d = 1; d<16; d*=2) { local to = tile.get_neighbour(wt_all, d) if ( print_message_box == 2 && to != null && to.is_empty() ) { gui.add_message_at(our_player, " ... place finder: to.is_empty() " + coord3d_to_string(to) + " = " + to.is_empty(), world.get_time()) } if (to && get_harbour_type_for_tile(to, planned_station, planned_harbour_flat, d) > 0) { anch.append(tile) c_harbour_tiles[coord3d_to_key(tile)] <- to break } /*if (to && get_harbour_type_for_tile(to, planned_station, planned_harbour_flat, d) > 0) { anch.append(tile) c_harbour_tiles[coord3d_to_key(tile)] <- to break }*/ } } } return anch } static function find_new_place(halt, planned_station, planned_harbour_flat, c_harbour_tiles) { local tile_list = ::finder.find_water_places( ::finder.get_tiles_near_halt(halt) ) local anch = [] // find places to build harbour if (tile_list.len()>0) { foreach(tile in tile_list) { for(local d = 1; d<16; d*=2) { local to = tile.get_neighbour(wt_all, d) if ( print_message_box == 2 && to.is_empty() ) { gui.add_message_at(our_player, " ... place finder: to.is_empty() " + coord3d_to_string(to) + " = " + to.is_empty(), world.get_time()) } if (to && get_harbour_type_for_tile(to, planned_station, planned_harbour_flat, d) > 0) { anch.append(tile) c_harbour_tiles[coord3d_to_key(tile)] <- to break } /*if (to && get_harbour_type_for_tile(to, planned_station, planned_harbour_flat, d) > 0) { anch.append(tile) c_harbour_tiles[coord3d_to_key(tile)] <- to break }*/ } } } return anch } /** * Checks whether we can build harbour: empty tile, slopes, enough space on water * returns type of harbour that can be placed here: 0 - nothing, 1 - harbour, 2 - flat harbour */ static function get_harbour_type_for_tile(tile, planned_harbour, planned_harbour_flat, d_water_to_land /*direction*/) { local type = 0 // 1 - harbour, 2 - flat harbour if (!tile.is_empty()) { return 0 } // first slope if (planned_harbour) { if (tile.get_slope() != 0) { // can place on slopes, target tile is sloped and empty -> we can terraform type = 1 } else if (planned_harbour_flat == null && command_x.can_set_slope(our_player, tile, dir.to_slope(d_water_to_land))==null) { // no slope, no flat dock, but terraforming possible type = 1 } } if (planned_harbour_flat) { if (tile.get_slope() == 0) { // flat place type = 2 } else if (planned_harbour == null && command_x.can_set_slope(our_player, tile, 0)==null) { // not flat, not harbour for slopes, can flatten type = 2 } } if (type == 0) { return 0 } // then space local size = type == 1 ? planned_harbour.get_size(0) : planned_harbour_flat.get_size(0) return finder.check_harbour_place(tile, size.x*size.y, dir.backward(d_water_to_land)) ? type : 0 } /** * Checks whether there is already a harbour on this tile. * @returns corresponding halt_x object (or null) */ static function get_harbour_halt(tile) { local halt = tile.get_halt() if (halt && halt.get_owner().nr == our_player_nr) { // our halt local harb = tile.find_object(mo_building) if (harb && (harb.get_desc().get_type()==building_desc_x.harbour || harb.get_desc().get_type()==building_desc_x.flat_harbour) ) { return halt } } return null } /** * Build harbour at @p tile, * replace water with an array containing all water tiles next to the harbour */ function build_harbour(tile, water_arr) { local water = water_arr[0] local err = null local len = 0 local dif = { x=tile.x-water.x, y=tile.y-water.y} if ( print_message_box == 2 ) { gui.add_message_at(our_player, " --- Place harbour at " + coord3d_to_string(tile) + " to access " + coord3d_to_string(water), world.get_time()) } print("Place harbour at " + coord3d_to_string(tile) + " to access " + coord3d_to_string(water) ) if ( tile.get_halt() && tile.get_halt().get_owner().nr == our_player_nr && tile.find_object(mo_building) && tile.find_object(mo_building).get_desc().get_type()==building_desc_x.station ) { // gui.add_message_at(our_player, "Cannot place any harbour at " + coord_to_string(tile) + " station exists", tile) // to do search new field } if (get_harbour_halt(tile)) { // already there } else { local d_water_to_land = coord_to_dir(dif) local type = get_harbour_type_for_tile(tile, planned_station, planned_harbour_flat, d_water_to_land) switch(type) { case 0: { err = "Cannot place harbour here" gui.add_message_at(our_player, "Cannot place any harbour at " + coord_to_string(tile), tile) // no build dock on station tile destroy exists way line // to do break } case 1: { // harbour on slope local slope = dir.to_slope(d_water_to_land) // terraform ?? if (tile.get_slope() != slope && tile.get_slope() != 2*slope) { err = command_x.set_slope(our_player, tile, slope ) if (err) gui.add_message_at(our_player, "Failed to change slope at " + coord_to_string(tile) +"\n" + err, tile) } if (err == null) { err = command_x.build_station(our_player, tile, planned_station) if (err) gui.add_message_at(our_player, "Failed to harbour at " + coord_to_string(tile) +"\n" + err, tile) } local size = planned_station.get_size(0) len = size.x*size.y break } case 2: { // flat dock // flatten slope if (tile.get_slope() != 0) { err = command_x.set_slope(our_player, tile, 0 ) if (err) gui.add_message_at(our_player, "Failed to flatten slope at " + coord_to_string(tile) +"\n" + err, tile) } if (err == null) { local rotation = 0 switch (dir.backward(d_water_to_land)) { case 2: rotation = 1 break case 1: rotation = 2 break case 8: rotation = 3 default: } err = command_x.build_station(our_player, tile, planned_harbour_flat, rotation) if (err) gui.add_message_at(our_player, "Failed to build flat harbour at " + coord_to_string(tile) +"\n" + err, tile) } local size = planned_harbour_flat.get_size(0) len = size.x*size.y break } } } if (err) { return err; } // halt at this harbour local harbour_halt = halt_x.get_halt(tile, our_player) water_arr.clear() // all water tiles near harbour for(local l=0; lharbour_halt) != 0) ) { // we do not want to use this halt continue } water_arr.append(to) } } catch(ev) {/* ignore */} } } if (water_arr.len()==0) { // should not happen print("No non-harbour water tiles found near " + coord_to_string(water)) water_arr.append(water) } return null } function find_route() { local as = route_finder_water() local res = as.search_route(c_start, c_end) if ("err" in res) { return res.err } c_start = [res.start ] c_end = [res.end ] local asd = route_finder_water_depot() res = asd.search_route(as.route) if ("err" in res) { return res.err } local d = res.depot c_depot = tile_x(d.x, d.y, d.z) } function repair_keys() { local cht = {} foreach(key,val in c_harbour_tiles) { local rkey = repair_key(key) cht[rkey] <- val } c_harbour_tiles = cht } static function repair_key(key) { // replace ``dd:dd:dd'' by ``coord3d_dd_dd_dd'' local a = split(key, ":-") if (a.len() == 1) { return key } local rkey = "coord3d_" + a[0] for(local i=1; i 0) { return { start = route.top(), end = route[0] } } print("No water depot route found") return { err = "No route" } } } class route_finder_water_depot extends route_finder_water { function estimate_distance(c) { local t = tile_x(c.x, c.y, c.z) if (t.is_water() && t.get_objects().get_count()==0) { return 0 } local depot = t.find_object(mo_depot_water) if (depot && depot.get_owner().nr == our_player_nr) { return 0 } return 10 } function add_to_open(c, weight) { if (c.dist == 0) { // test for depot local t = tile_x(c.x, c.y, c.z) if (t.get_objects().get_count()==0) { // depot not existing, we must build, increase weight weight += 25 * cost_straight } } base.add_to_open(c, weight) } function search_route(watertiles) { prepare_search() // do not place depot on route between harbours foreach(w in watertiles) { add_to_close(w) } // add neighboring tiles of route to open list for(local i=0; i 0) { return { depot = route[0] } } print("No water depot route found") return { err = "No route" } } } simutrans-124.3/simutrans/ai/sqai_rail/station_manager.nut000066400000000000000000000026721474050137200240470ustar00rootroot00000000000000class freight_station_t { factory = null // factory_x road_depot = null // tile_x road_unload = null // tile_x ship_depot = null // tile_x rail_depot = null // tile_x rail_unload = null // tile_x constructor(f) { factory = f } function _save() { return ::saveinstance("freight_station_t", this) } } class freight_station_manager_t extends node_t { freight_station_list = null use_raw_names = 0 /// repair old savegames: use untranslated factory name as key constructor(urn) { base.constructor("freight_station_manager_t") freight_station_list = {} ::station_manager = this use_raw_names = urn } /// Generate unique key from link data static function key(factory) { return (factory.get_raw_name() + coord_to_string(factory)).toalnum() } /** * Access freight_station_t data, create node if not existent. */ function access_freight_station(factory) { local k = key(factory) local res try { res = freight_station_list[k] } catch(ev) { local fs = freight_station_t(factory) freight_station_list[k] <- fs res = fs } return res } /// Repair list: use untranslated factory names function repair_keys() { if (use_raw_names == 1) { return } local fsl = {} foreach(val in freight_station_list) { local rkey = key(val.factory) fsl[rkey] <- val } freight_station_list = fsl use_raw_names = 1 } } simutrans-124.3/simutrans/ai/sqai_rail/vehicle_constructor.nut000066400000000000000000000063321474050137200247550ustar00rootroot00000000000000class vehicle_constructor_t extends node_t { // input data p_depot = null // depot_x p_line = null // line_x p_convoy = null // prototyper_t p_count = 0 p_withdraw = false // generated data c_cnv = null c_wt = 0 // step-by-step construct convoys phase = 0 constructor() { base.constructor("vehicle_constructor_t") debug = false } function step() { local pl = our_player c_wt = p_convoy.veh[0].get_waytype() //local wt_name = ["", "road", "rail", "water"] //gui.add_message_at(our_player, "convoy " + p_convoy.veh[0].get_name() + " - " + wt_name[c_wt], world.get_time()) switch(phase) { case 0: // create the convoy (and the first vehicles) { p_depot.append_vehicle(pl, convoy_x(0), p_convoy.veh[0]) // find the newly created convoy // it should be the last in the list local cnv_list = p_depot.get_convoy_list() local trythis = cnv_list.top() if (check_convoy(trythis)) { c_cnv = trythis } if (c_cnv == null) { foreach(cnv in cnv_list) { if (check_convoy(cnv)) { c_cnv = cnv break } } } phase ++ } case 1: // complete the convoy { local vlist = c_cnv.get_vehicles() while (vlist.len() < p_convoy.veh.len()) { local old_length = vlist.len() local res = p_depot.append_vehicle(pl, c_cnv, p_convoy.veh[ old_length ]) vlist = c_cnv.get_vehicles() if (old_length == vlist.len()) { print("Appending vehicle failed.") // appending failed return r_t(RT_TOTAL_FAIL) } } phase ++ } case 2: // set line { c_cnv.set_line(pl, p_line) phase ++ } case 3: // withdraw old vehicles { if (p_withdraw) { local cnv_list = p_line.get_convoy_list() foreach(o_cnv in cnv_list) { if (o_cnv.id != c_cnv.id && !o_cnv.is_withdrawn()) { o_cnv.toggle_withdraw(pl) } } p_withdraw = false } phase ++ } case 4: // start { p_depot.start_convoy(pl, c_cnv) p_count -- if (p_count > 0) { phase = 0 return r_t(RT_PARTIAL_SUCCESS) } else { phase ++ } } } return r_t(RT_TOTAL_SUCCESS) } function check_convoy(cnv) { // check whether this convoy is for our purpose if (cnv.get_line() == null && cnv.get_waytype() == c_wt) { // now test for equal vehicles local vlist = cnv.get_vehicles() local len = vlist.len() if (len <= p_convoy.veh.len()) { local equal = true; for (local i=0; equal && i we set meaningful defaults here. # # load/save the files in the users or the program directory directory? (default: 0 = user directory) # ATTENTION! # will be only used if this file is located in the program directory at config/simuconf.tab! # #singleuser_install = 0 # #################################program stuff################################## # # # Do not delete these comment line! (Needed for installer) # Default pak file path - which graphics set you want to play with? # Nothing means automatic selection # # ATTENTION! # This value will only be used if this file is located in the data directory at config/simuconf.tab # and will be overwritten by the settings from simutrans/simuconf.tab in the user directory. # #pak_file_path = pak/ #pak_file_path = pak.german/ #pak_file_path = pak128/ #pak_file_path = pak.japan/ #pak_file_path = pak.winter/ #pak_file_path = pak.ttd/ # #################################routing stuff################################## # maximum number of position tested during a way search # 100000 should be ok even for large maps with ships # 10000 is ok for everything else (consumes 16*x Bytes main memory, no further harm) max_route_steps = 1000000 # # How many tiles to check before giving up on finding a free bay at a stop? (200 default) max_choose_route_steps = 250 # size of catchment area of a station (default 2) # older game size was 3 # savegames with another catch area will give strange results station_coverage = 2 # Max number of steps in goods pathfinding # This should be equal or greater than the biggest group # of interconnected stations in your game. # # If you set it too low, some goods might not find a route # if the route is too complex. If you set it too high, the # search will take a lot of CPU power, particularly if searches # often fail because there is no route. # # Depending on your CPU power, you might want to limit the search # depth. # # prissi: On a 512x512 map with more than 150000 people daily, the saturation # value for "no route" was higher, around 8000. Using 300 instead almost doubled # the value of "no route" # max_hops = 2000 # Passengers and goods will change vehicles at most "max_transfer" # times to reach their destination. # # It seems that in good networks, the number of transfers is below # 5. I think 6 is a good compromise that allows complex networks but # cuts off the more extreme cases # # You can set this lower to save a little bit of CPU time, but at some # point this means you'll get less passengers to transport # # This value is less critical than "max_hops" from above. # # T. Kubes: I would say 8 for now, but this definitely should be difficulty # dependent setting. # max_transfers = 9 # way builder internal weights (defaults) # a higher weight make it more unlikely # make the curves negative, and the waybuilder will built strange tracks ... # way_straight=1 way_no_way=3 way_curve=5 way_double_curve=10 way_90_curve=30 way_slope=20 way_tunnel=16 way_leaving_road=50 way_avoid_crossings=8 way_max_bridge_len=15 way_count_maximum=2000 # if defined, the default tool will try to calculate straight ways (like OpenTTD) straight_way_without_control = 0 # stop_halt_as_scheduled=1, trains stop at the scheduled tile (or advance until they fits) # stop_halt_as_scheduled=0 (default) trains will advance always to the end of a platform #stop_halt_as_scheduled=0 ###############################passenger stuff############################## # also pak dependent # town growth multiplier factors (electricity is not used at the moment) # A higher factor mean faster growth # passenger_multiplier = 40 mail_multiplier = 20 goods_multiplier = 20 electricity_multiplier = 0 # town growth is size dependent. There are three different sizes (<1000, 1000-10000, >10000) # the idea is, that area increase by square but growth is linear growthfactor_villages = 400 growthfactor_cities = 200 growthfactor_capitals = 100 # passenger generation (default is 16) Smaller values means less passengers passenger_factor=16 # amount of passengers that travel from/to factories or attractions # the remaining percentage is intercity and intracity travel factory_worker_percentage = 33 tourist_percentage = 16 # how much local destinations are preferred over time # 1 means almost local passengers/mail only, 10000 spreads them over the map # You can have up to ten entries, first is the year, next is the factor. # The increase between the year will increase first slow then fast towards # the final years locality_factor[0]=1835,1 locality_factor[1]=2050,2500 # A factory will be added as worker's destination to a town, if it has either # is within factory_worker_radius # or has less than factory_worker_minimum_towns next cities added # and has not more than factory_worker_maximum_towns added # The default settings connect to maximum four cities with 77 tiles radius; or at least to the closest one # Setting factory_worker_maximum_towns to zero will not connect factories to towns factory_worker_radius = 77 factory_worker_minimum_towns = 1 factory_worker_maximum_towns = 4 # if enabled (default = 0 off) stops may have different capacities for passengers, mail, and freight separate_halt_capacities = 0 # three modes (default = 0) # 1: the payment is only relative to the distance to next interchange, 2 to the trips destination (default 0 is distance since last stop) pay_for_total_distance = 0 # things to overcrowded destinations won't load if active (default off) avoid_overcrowding = 0 # do not create goods/passenger/mail when the only route is over an overcrowded stop no_routing_over_overcrowded = 0 # in beginner mode, all good prices are multiplied by a factor (default 1500=1.5) beginner_price_factor = 1500 # Construction speed of new AIs, the higher the faster (default 8000) #ai_construction_speed = 8000 ##################################factory stuff################################# # when a city reaches 2^n times of this number # then a factory is extended, or a new factory chain is spawned #industry_increase_every = 2000 # smallest distance between two adjacent factories min_factory_spacing = 6 # max distance for connected factories # if percentage>0, it will be in percent of the largest map dimension # percentage also overrides the absolute value max_factory_spacing_percentage = 25 #max_factory_spacing = 40 # allow all possible supplier to connect to your factories? # best to leave it in default position. (only on for simuTTD) crossconnect_factories = 0 # how big is the chance for crossconnections in percent # (100% will give nearly the same results as crossconnect_factories=1) crossconnect_factories_percentage = 33 # how much is the total electric power available (in relation to total production) in parts per thousand electric_promille = 330 # true if transformers are allowed underground (default) allow_underground_transformers = 1 # with this switch on overcrowded factories will not receive goods any more # There are three settings 0=off, 1=old_style (default), 2=new_style just_in_time = 1 # how much amount in transport is sent before further distribution stops # This is only enabled when "just_in_time=1" is enabled # The limit is given in percent of factory storage (0=off) # It should be not too low to allow big convoys fully loaded at more than one # factory (for medium sized maps 500 seems a reasonable number) maximum_intransit_percentage = 0 # use beginner mode for new maps (can be switched anyway on the new map dialog) first_beginner = 0 # number of periods for averaging the amount of arrived pax/mail at factories for boost calculation # one period represents a fixed interval of 2^18 ms in-game time # value can range from 1 to 16, inclusive; 1 means no averaging; default is 4 factory_arrival_periods = 4 # whether factory's pax/mail demands are enforced or not; default is on factory_enforce_demand = 1 ##################################display stuff################################# # You can use a system font. BUT you must specify the whole path to it! # This can be only set in the user defined simuconf.tab #fontname=C:\Windows\fonts\arial.ttf # if run on a mobile device, setting hide_keyboard=1 will only show the keyboard # when there is text to input in a dialog. Other than that textinput will not # be possible (no keyboard short cuts). # Currently only supported with SDL2 hide_keyboard = 0 # player color can be fixed for several players or set totally random # in the latter case each player will get unique but random coloring # (default 0) random_player_colors = 0 # when set here, the player will always get these player colors, even # if random colors were enabled. # color values range from 0 to 27 for first and second player color # and there are 0...15 player in the game player_color[1] = 1,4 # Should either account (default) or net wealth be shown below the screen? player_finance_display_account = 1 # remove companies without convoys after x month (0=off, 6=default) remove_dummy_player_months = 6 # remove password of abandoned companies (without any building activity) after x month (0=off default) unprotect_abandoned_player_months = 0 # (=1) drive on the left side of the road drive_left = 0 # (=1) signals on the left side signals_on_left = 0 # Do you want to have random pedestrians in town? Look nice but needs some # CPU time to process them. (1=on, 0=off) # Impact on frame time: ~10% (16 cities on a new standard map) random_pedestrians = 1 # Do you want to have random pedestrians after pax are reaching this # destination? May generate quite a lot. (1=on, 0=off) stop_pedestrians = 1 # there are some other grounds (like rocky, lakes etc. ) # which could be added to the map (default 10) # show random objects to break uniformity (every n suited tiles) random_grounds_probability = 10 # show random moving animals (n = every n suited tiles, default 1000) random_wildlife_probability = 1000 # animate the water each interval (if images available) # costs some time for the additional redraw (~1-3%) water_animation_ms = 250 # Show info windows for private cars and pedestrians? # (1=on, 0=off) pedes_and_car_info = 0 # How much citycars will be generated citycar_level = 5 # After how many month a citycar breaks (and will be forever gone) ... # default is ten years (at bits_per_month setting of 20) default_citycar_life = 36 # Show info on trees? # (1=on, 0=off) tree_info = 1 # Show info also on bare ground? # (1=on, 0=off) ground_info = 0 # Show passenger level of townhalls? # (1=on, 0=off) townhall_info = 0 # do not show the button to add an inverted schedule for rail based convoys # (1=hide, 0=show anyway) hide_rail_return_ticket = 1 # always open only a single info window for the ground, # even if there are more objects on this tile #only_single_info = 1 # show a tooltip on convoys at several conditions # 0 no messages # 1 (default) only no_route and stuck # loading and waiting at signals too #show_vehicle_states = 1 # If a convoi which you are following enters a tunnel, what to do # 0=do not change view, 1=switch to underground mode and back, 2=switch to sliced underground mode #follow_convoi_underground = 2 # show (default) tiles with a halt when editing a schedule #visualize_schedule = 1 # Should stations get numbered names? (1=yes, 0=no) #numbered_stations = 0 # Show name signs and statistic? # 0 = don't show anything # 1 = station names # 2 = statistics # 3 = names and statistics # The visual style is added to this number: # 0 = black name in color box # 4 = name in player color with outline # 8 = box left of name in yellow outline show_names = 3 # Draw the earth slope to mark the border (default 1 on) draw_earth_border = 1 # Tile the outside with the ground.ouside.pak (default 0 off) draw_outside_tile = 0 # Color of background outside the map, default: COL_GREY2 (210) #background_color = 210 # If and where to display a compass # 0=off (default for main screen) # 1=top, 2=vertical centre, 3=bottom, 4=left, 8=horizontal centre, 12=right # default for minimap is 1+12=13 compass_screen_position = 0 compass_map_position = 13 # if set to 1 (default) the numpad will always move the map. # if set to 0, it will always produce numbers numpad_always_moves_map = 1 # drag the minimap with the left mouse too instead dragging the main map position (1=default) #leftdrag_in_minimap=1 # Position of the main menu bar (0=left, 1=top[default], 2=right, 3=bottom) #menubar_position = 0 # 1=selecting a tool again will close it (0=will be topped/reinit) #reselect_closes_tool = 1 # 1=upon opening, all toolbars will be closed, toolbar will be top centered #single_toolbar = 0 # display scaling factor in percent or -1 for auto # dpi_scaling = 100 ###################################money stuff################################## # # These values are usually set in the pak files # You can adjust all the cost in the game, that are not inside some pak file # # show graphs old style (right to left, default) or rather left to right left_to_right_graphs = 0 # Starting money of the player. Given in Credit cents (1/100 Cr) #starting_money = 20000000 # New system of year dependent starting money. Up to ten triplets are # possible. The entries are of the form: # startingmoney[i]=year,money(in 1/100 credits),interpolate (1) or step(0) # starting_money[0]=1930,20000000,1 # starting_money[1]=2030,35000000,1 # allow buying obsolete vehicles (=1) in depot allow_buying_obsolete_vehicles = 1 # disable companies from making ways public with the appropiate tool # even when disabled companies can still make stops public # does not affect public service provider player disable_make_way_public = 0 # vehicle can loose a part of their value, when the are once used # the loss is given in 1/1000th, i.e 300 mean the value will be 70% used_vehicle_reduction = 0 # convois can have a maximum number of trailing vehicles (up to 250) # These are the dafult values. Pakset with airplanes with dual cargo holds # may need to increase the air counter! max_rail_convoi_length = 24 max_road_convoi_length = 4 max_ship_convoi_length = 4 max_air_convoi_length = 1 # lowest possible income with speedbonus (1000=1) default 125 (=1/8th) bonus_basefactor = 125 # if a convoy runs on a way that belongs to another player, toll may # be charged. The number given is the percentage of the running cost # of the convoy or the way cost (include electrification if needed). # (default 0) toll_runningcost_percentage = 0 toll_waycost_percentage = 0 # Maintenance costs of buildings #maintenance_building = 2000 # first stops: the actual cost is (cost*level*width*height) #cost_multiply_dock=500 #cost_multiply_station=600 #cost_multiply_roadstop=400 #cost_multiply_airterminal=3000 #cost_multiply_post=300 #cost_multiply_headquarter=1000 # cost for depots #cost_depot_air=5000 #cost_depot_rail=1000 #cost_depot_road=1300 #cost_depot_ship=2500 # maximum distance for merging non-adjacent stations allow_merge_distant_halt=2 # the cost to merge stations: the actual cost is (cost*2^distance) #cost_multiply_merge_halt=700 # other way related stuff #cost_signal=500 #cost_tunnel=10000 #cost_third_rail=80 # other construction/destruction stuff #cost_buy_land=100 #cost_alter_land=1000 #cost_set_slope=2500 #cost_alter_climate=5000 #cost_found_city=5000000 #cost_multiply_found_industry=20000 #cost_remove_tree=100 #cost_multiply_remove_haus=1000 #cost_multiply_remove_field=5000 #cost_transformer=2500 #cost_maintain_transformer=20 # how many months of maintainance the make public tool costs #cost_make_public_months=60 ##################################pak set stuff################################# # # how long is a diagonal (512: factor 2=1024/512, old way, 724: sqrt(2)=1024/724 # THIS WILL BE ONLY USED, WHEN THIS FILE IS IN THE pakxyz/config! #diagonal_multiplier = 724 # new height for old slopes when old single height savegame loaded with double height pak (default 1=single height, 2=double height) # THIS WILL BE ONLY USED, WHEN THIS FILE IS IN THE pakxyz/config! #height_conversion_factor = 1 # how height is a tile in z-direction (default 16, TTD 8) # THIS WILL BE ONLY USED, WHEN THIS FILE IS IN THE pakxyz/config! #tile_height = 16 # minimum/maximum allowed height level for the map (too high might cause display errors) # Also those number must no be the same #world_minimum_height = -12 #world_maximum_height = 32 # minimum distance between two townhalls #minimum_city_distance = 16 # Minimum distance of a city attraction to other special buildings #special_building_distance = 3 # Minimum clearance under bridges is 1 or 2 levels? (default = conversion factor) #way_height_clearance = 1 # Max. length of initial intercity road connections # If you want to speed up map creation, lower this value. # If you want more initial intercity roads, raise this value. # If the value is too large then very long bridges might be created. # 200 seems to be a good compromise between speed and road number # note: this will slow down map creation dramatically! # #intercity_road_length = 200 # Type of intercity roads - must be available as PAK file. # Intercityroad with timeline: intercity_road[number]=name,intro-year,retire-year # .. number = 0..9 - up to ten different intercity_roads possible # .. name = name of an existing pak file #intercity_road[0] = asphalt_road,0,1990 # default: city_road # (old, 102.2.2 and before) intercity_road_type = asphalt_road # Type of city roads - must be available as PAK file. # Cityroad with timeline: city_road[number]=name,intro-year,retire-year # .. number = 0..9 - up to ten different city_roads possible # .. name = name of an existing pak file #city_road[0] = dirt_road,1920,1940 # default: asphalt_road # (old, 102.2.2 and before) city_road_type = city_road # city road speed limit over time # A comma seperated list of year of change and new limit # without a timeline, the value will be 50 #cityroad_speeds=1,25,1910,30,1930,40,1950,50 # now river stuff # first river type (should be defined in pak dependent file) # The highest number is the smallest. A river with max_speed==0 is not navigable by ships. #river_type[0] = river #river_type[1] = small_river #river_type[2] = just_the source # river number (16 gives a few nicely branched rivers) #river_number = 16 # min length #river_min_length = 16 # max length #river_max_length = 320 ################################# forest stuff ################################# # please be careful in changing them, I spent lot of time finding optimals. # those values have impact on no. of spawned trees -> memory consumption # # Number of trees on square 2 - minimal usable, 3 good, 4 very nice looking max_no_of_trees_on_square = 3 # All following tree options are only active during map generation/extension. # Base forest size - minimal size of forest - map independent forest_base_size = 36 # Map size divisor - smaller it is the larger are individual forests forest_map_size_divisor = 38 # Forest count divisor - smaller it is, the more forest are generated forest_count_divisor = 16 # Determines how dense are spare trees going to be planted (works inversely) forest_inverse_spare_tree_density = 400 # climate with trees entirely (1: water, 2:desert, 4:tropic, 8:mediterranean, 16:temperate, 32:tundra, 64:rocky, 128:arctic) # zero (default) means no climate with at least one tree per tile tree_climates = 4 # climates with no trees at all (desert and arctic at the moment) no_tree_climates = 130 # 0: no trees will be created at all (save about 30% memory and # the season change will be much smoother on small machines) # 1: normal elliptic forest tree distribution # 2: if humidity climate generation is enabled, distribute trees based on humidity (else use 1) #tree_distribution = 2 # maximum height level for lake creation (0=no lakes) lake_height = 8 ###################################time stuff################################### # Enforce vehicle introduction dates? # 0 = all vehicles available from start of the game # 1 = use introduction dates # 2 = (default) use settings during game creation, new games off # 3 = use settings during game creation, new games on # use_timeline = 3 # Starting year of the game: # Setting it below 1850 is not recommended for pak64 set! # You will have problems with missing vehicles, do not complain if you do so! # Setting it above 2050 will render game bit boring - no new vehicles. # # other recommended value for pak64 is 1956 # starting_year = 1930 # Starting month of the game for people who want to start in summer (default 1=January) starting_month = 1 # Should month be shown in date? # 0=no, 1=yes # 2>=show day in japan format=2, us format=3, german=4 # 5>=show no season but everything else in japan format=5, us format=5, german=6 # This is most useful, if you use longer months than the default length (see below) #show_month = 1 # Global time multiplier (will be save with new games) # 2^bits_per_month = duration of a game month in milliseconds real time # default before 99.x was 18. For example, 21 will make the month 2^3=8 times longer in real time # production and maintenance cost will be adjusted accordingly. # bits_per_month = 20 #################################system stuff################################# # Set this for playing MIDI music with your preferred soundfont. # Need Fluidsynth support. # A recommended lightweight (30 MB) soundfont is PCLite: # http://www.personalcopy.com/sfarkfonts1.htm # https://src.fedoraproject.org/repo/pkgs/PersonalCopy-Lite-soundfont/PCLite.sf2/629732b7552c12a8fae5b046d306273a/ # But there are many more, including greater quality ones. # Set either the full path or the name of the .sf2 soundfont saved into the "music" directory soundfont_filename = PCLite.sf2 # File format for saved games # Uncompressed formats: # - binary Uncompressed binary data # - xml Uncompressed XML data (better error detection/correction but significantly larger files) # Compressed formats: # - zipped, xml_zipped Compressed with gzip # - bzip2, xml_bzip2 Compressed with bzip2 (smaller files but slower save/reload) # - zstd, xml_zstd Compressed with zstd (larger files than bzip2 but faster reload) # Not always available saveformat = bzip2 # Alternate format for faster autosaves autosaveformat = zipped # zip and zstd allow for finetuning their packaging versus speed with an additional # compression level parameter. # Zip form 1(fastest) to 9(smallest) with 6 a good compromise # zstd goes form -10 to 30 or so. Meaningful are mostly single digit values save_level = 6 autosave_level = 1 # autosave every x months (0=off) autosave = 0 # save the current game when quitting and reload it upon reopening #reload_and_save_on_quit = 1 # display (screen/window) width # also see readme.txt, -screensize option #display_width = 704 # display (screen/window) height # also see readme.txt, -screensize option #display_height = 560 # show full screen # 0: disable fullscreen # 1: enable fullscreen # 2: enable borderless fullscreen emulation (frameless window, screen size cannot be altered) #fullscreen = 0 # How many frames per second to use? Display may look pretty until 10 or so # (depends very much on computer, game complexity and graphics driver) frames_per_second = 25 # Same as frames_per_second, but for fast forward (default 10) #fast_forward_frames_per_second = 10 # during zooming out simutrans may get slow due to the very high number # of tiles visible. If the tiles become equal or smaller than the tile size # below, a simpler clipping algorithm will be used, which will give some # clipping errors, but is faster. (default size = 4) # However, during normal gaming this will be determined automatically, so you # usually you do not need to set this manually. simple_drawing_tile_size = 4 # you can force fast redraw for fast forward by this (default off) simple_drawing_fast_forward = 1 # How much faster should the game proceed with fast forward (limited by your computer and size of the map) fast_forward = 50 # How many threads to use (default 4) #threads = 4 ###################################network stuff############################## # # Synchronized networking is always a trade off between fast response and safe # connections. A more relaxed timing will cause delay of commands but is more # likely to compensate for clients running slightly faster than the rest. # # Sets the local addresses Simutrans should listen on and use for making outgoing connections # By default it will use all local IPv4 and IPv6 addresses # This setting has no effect if Simutrans has been compiled with the USE_IP4_ONLY flag set! # The addresses listed will be tried in the order specified # A DNS name may be specified, this will be resolved and Simutrans will attempt to listen # on all of the addresses returned. #listen = ::,0.0.0.0 # How much delay before commands are executed on the clients. # A larger number will catch even clients running slightly ahead but cause delay. # This is set by the server side. #server_frames_ahead = 4 # How much extra delay in command execution on the client side, on top of server_frames_ahead. # A larger number can compensate for larger fluctuations in communication latency to smooth out play. # This is set by the client side. #additional_client_frames_behind = 4 # In network mode, there will be a fixed number of screen updates before a step. # Reasonable values should result in 2-5 steps per second. #server_frames_per_step = 4 # The server sends after a fixed number of steps some information to the clients. # Large values here means: reduced server communication (if that is of importance...) # Small values should improve the timing of the clients. #server_frames_between_checks = 24 # Automatically announce server on the central server directory (http://servers.simutrans.org/) # 0 (default) = off, 1 = on #server_announce = 0 # Interval of server announcement (if enabled) # Value is number of seconds between server announcements, default is 900 (15 minutes) # Minimum value is 60 (1 minute), for accurate listing it is recommended not to increase # this value to greater than 3600 (1 hour) # To disable announcements set server_announce to 0 #server_announce_interval = 900 # Fully Qualified Domain Name (FQDN) or IP address of your server (IPv6 or IPv4) #server_dns = 127.0.0.1 # alternative server name (an or IP6) Use only if server_dns is set! #server_altdns = fe80::1 # Port address (usually set via command line) #server_port = 13353 # Name of server in server listing #server_name = My Simutrans Server # Additional information about your server (for display on the list server) #server_comments = Comments about my server # Email address of server maintainer (for display on the list server) #server_email = maintainer@your.server # Pakset download URL (for display on the list server) #server_pakurl = http://your.domain/pakset.zip # Server info URL (for display on the list server) #server_infurl = http://your.domain/server-info.html # Pause server when no clients are connected #pause_server_no_clients = 1 # Server saves savegame when being killed (default=0 off) #server_save_game_on_quit = 0 # Nickname when joining network games #nickname = John Doe # Chat window transparency (0=off, 25, 50 75 are possible) chat_transparency = 75 # Here you can add a message about your server (It will read this file on each joining anew) #server_motd_filename = simutrans-124.3/simutrans/copyright.txt000066400000000000000000000013701474050137200203520ustar00rootroot00000000000000Simutrans is copyright (C) 1997-2004 by Hj. Malthaner. (c) 2005-2012 Simutrans Team >>>>>>>>>>> NO WARRANTIES, EXPRESS OR IMPLIED. <<<<<<<<<<< Simutrans may not be sold or modified in any way without written permission by the author. Have lots of fun playing Simutrans! The version is built by Markus Pristovsek. All complains, or any other comments please report at: https://forum.simutrans.com The source code from the program is available under the Artistic License. This is a written permission as demanded for above for every right granted by the Artistic License. Note, however, that individual pak sets may come with their own license. Download the source from https://sourceforge.net/projects/simutrans or find out about our svn in the forum. simutrans-124.3/simutrans/font/000077500000000000000000000000001474050137200165465ustar00rootroot00000000000000simutrans-124.3/simutrans/font/Prop-Latin1.bdf000066400000000000000000000430261474050137200212760ustar00rootroot00000000000000STARTFONT 2.1 FONT -simutrans-prop-medium-r-normal--12-120-77-75-P-80-latin1-0 SIZE 12 77 75 FONTBOUNDINGBOX 8 11 0 -2 STARTPROPERTIES 9 POINT_SIZE 100 PIXEL_SIZE 10 RESOLUTION_X 77 RESOLUTION_Y 75 FONT_ASCENT 9 FONT_DESCENT 2 AVERAGE_WIDTH 80 SPACING "P" ENDPROPERTIES CHARS 174 STARTCHAR char10 ENCODING 10 SWIDTH 389 0 DWIDTH 5 BBX 5 1 0 0 BITMAP 00 ENDCHAR STARTCHAR char29 ENCODING 29 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP ba 44 aa 92 92 aa 44 ba ENDCHAR STARTCHAR char30 ENCODING 30 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 38 44 aa 82 aa 92 44 38 ENDCHAR STARTCHAR char31 ENCODING 31 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 38 44 aa 82 92 aa 44 38 ENDCHAR STARTCHAR char33 ENCODING 33 SWIDTH 312 0 DWIDTH 4 BBX 4 9 0 -1 BITMAP 60 60 60 60 60 60 00 60 60 ENDCHAR STARTCHAR char34 ENCODING 34 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 6c 6c d8 ENDCHAR STARTCHAR char35 ENCODING 35 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 6c 6c fe 6c 6c fe 6c 6c ENDCHAR STARTCHAR char36 ENCODING 36 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 10 78 d4 d0 d0 d0 d4 78 10 ENDCHAR STARTCHAR char37 ENCODING 37 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 72 b6 ac d8 36 6a da 9c ENDCHAR STARTCHAR char38 ENCODING 38 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 70 d0 d0 e0 74 fc d8 ec ENDCHAR STARTCHAR char39 ENCODING 39 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 5 BITMAP 60 60 c0 ENDCHAR STARTCHAR char40 ENCODING 40 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 c0 c0 c0 c0 60 30 ENDCHAR STARTCHAR char41 ENCODING 41 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 60 30 30 30 30 60 c0 ENDCHAR STARTCHAR char42 ENCODING 42 SWIDTH 623 0 DWIDTH 8 BBX 8 5 0 1 BITMAP 24 18 7e 18 24 ENDCHAR STARTCHAR char43 ENCODING 43 SWIDTH 545 0 DWIDTH 7 BBX 7 5 0 1 BITMAP 30 30 fc 30 30 ENDCHAR STARTCHAR char44 ENCODING 44 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 -1 BITMAP 60 60 c0 ENDCHAR STARTCHAR char45 ENCODING 45 SWIDTH 467 0 DWIDTH 6 BBX 6 1 0 3 BITMAP f8 ENDCHAR STARTCHAR char46 ENCODING 46 SWIDTH 234 0 DWIDTH 3 BBX 3 2 0 0 BITMAP c0 c0 ENDCHAR STARTCHAR char47 ENCODING 47 SWIDTH 545 0 DWIDTH 7 BBX 7 7 0 0 BITMAP 04 0c 18 30 60 c0 80 ENDCHAR STARTCHAR char48 ENCODING 48 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char49 ENCODING 49 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 70 30 30 30 30 30 fc ENDCHAR STARTCHAR char50 ENCODING 50 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc 0c 18 30 60 c0 fc ENDCHAR STARTCHAR char51 ENCODING 51 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc 0c 38 0c 0c cc 78 ENDCHAR STARTCHAR char52 ENCODING 52 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 60 6c cc cc fc 0c 0c ENDCHAR STARTCHAR char53 ENCODING 53 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 c0 c0 f8 0c 0c cc 78 ENDCHAR STARTCHAR char54 ENCODING 54 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 c0 c0 f8 cc cc cc 78 ENDCHAR STARTCHAR char55 ENCODING 55 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 0c 18 18 18 30 30 30 ENDCHAR STARTCHAR char56 ENCODING 56 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc 78 cc cc cc 78 ENDCHAR STARTCHAR char57 ENCODING 57 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc 7c 0c 78 ENDCHAR STARTCHAR char58 ENCODING 58 SWIDTH 312 0 DWIDTH 4 BBX 4 6 0 0 BITMAP 60 60 00 00 60 60 ENDCHAR STARTCHAR char59 ENCODING 59 SWIDTH 312 0 DWIDTH 4 BBX 4 7 0 -1 BITMAP 60 60 00 00 60 60 c0 ENDCHAR STARTCHAR char60 ENCODING 60 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 0c 38 e0 e0 38 0c ENDCHAR STARTCHAR char61 ENCODING 61 SWIDTH 467 0 DWIDTH 6 BBX 6 4 0 1 BITMAP f8 00 00 f8 ENDCHAR STARTCHAR char62 ENCODING 62 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP c0 70 1c 1c 70 c0 ENDCHAR STARTCHAR char63 ENCODING 63 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 78 cc 0c 18 30 30 00 30 30 ENDCHAR STARTCHAR char64 ENCODING 64 SWIDTH 701 0 DWIDTH 9 BBX 8 8 0 0 BITMAP 7e e3 cf db db cf e0 7e ENDCHAR STARTCHAR char65 ENCODING 65 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc fc cc cc cc cc ENDCHAR STARTCHAR char66 ENCODING 66 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc f8 cc cc cc f8 ENDCHAR STARTCHAR char67 ENCODING 67 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 c0 c0 c0 cc 78 ENDCHAR STARTCHAR char68 ENCODING 68 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc cc cc cc f8 ENDCHAR STARTCHAR char69 ENCODING 69 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP f8 c0 c0 f0 c0 c0 c0 f8 ENDCHAR STARTCHAR char70 ENCODING 70 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP f8 c0 c0 f0 c0 c0 c0 c0 ENDCHAR STARTCHAR char71 ENCODING 71 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 c0 dc cc cc 74 ENDCHAR STARTCHAR char72 ENCODING 72 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc fc cc cc cc cc ENDCHAR STARTCHAR char73 ENCODING 73 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 60 60 60 60 60 60 f0 ENDCHAR STARTCHAR char74 ENCODING 74 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 78 30 30 30 30 30 70 e0 ENDCHAR STARTCHAR char75 ENCODING 75 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c4 cc d8 f0 f0 d8 cc c4 ENDCHAR STARTCHAR char76 ENCODING 76 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP c0 c0 c0 c0 c0 c0 c0 f8 ENDCHAR STARTCHAR char77 ENCODING 77 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 82 c6 ee fe d6 c6 c6 c6 ENDCHAR STARTCHAR char78 ENCODING 78 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc ec ec dc dc cc cc ENDCHAR STARTCHAR char79 ENCODING 79 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char80 ENCODING 80 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc cc f8 c0 c0 ENDCHAR STARTCHAR char81 ENCODING 81 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc d4 d8 6c ENDCHAR STARTCHAR char82 ENCODING 82 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc f8 f0 d8 cc ENDCHAR STARTCHAR char83 ENCODING 83 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 78 0c 0c cc 78 ENDCHAR STARTCHAR char84 ENCODING 84 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 30 30 30 30 30 30 30 ENDCHAR STARTCHAR char85 ENCODING 85 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char86 ENCODING 86 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc 78 78 78 30 30 ENDCHAR STARTCHAR char87 ENCODING 87 SWIDTH 701 0 DWIDTH 9 BBX 8 8 0 0 BITMAP c3 db db 5a 7e 7e 34 34 ENDCHAR STARTCHAR char88 ENCODING 88 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc 78 30 30 78 cc cc ENDCHAR STARTCHAR char89 ENCODING 89 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc 78 38 30 70 e0 ENDCHAR STARTCHAR char90 ENCODING 90 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 0c 18 30 60 c0 c0 fc ENDCHAR STARTCHAR char91 ENCODING 91 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 c0 c0 c0 c0 c0 c0 f0 ENDCHAR STARTCHAR char92 ENCODING 92 SWIDTH 545 0 DWIDTH 7 BBX 7 7 0 0 BITMAP 80 c0 60 30 18 0c 04 ENDCHAR STARTCHAR char93 ENCODING 93 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 30 30 30 30 30 30 f0 ENDCHAR STARTCHAR char94 ENCODING 94 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 30 78 cc ENDCHAR STARTCHAR char95 ENCODING 95 SWIDTH 467 0 DWIDTH 6 BBX 6 1 0 -1 BITMAP f8 ENDCHAR STARTCHAR char96 ENCODING 96 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 5 BITMAP c0 c0 60 ENDCHAR STARTCHAR char97 ENCODING 97 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char98 ENCODING 98 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c0 c0 d8 ec cc cc ec d8 ENDCHAR STARTCHAR char99 ENCODING 99 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char100 ENCODING 100 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 0c 0c 6c dc cc cc dc 6c ENDCHAR STARTCHAR char101 ENCODING 101 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char102 ENCODING 102 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 70 c0 f0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char103 ENCODING 103 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 6c dc cc cc dc 6c 0c 78 ENDCHAR STARTCHAR char104 ENCODING 104 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c0 c0 d8 ec cc cc cc cc ENDCHAR STARTCHAR char105 ENCODING 105 SWIDTH 234 0 DWIDTH 3 BBX 3 8 0 0 BITMAP c0 00 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char106 ENCODING 106 SWIDTH 389 0 DWIDTH 5 BBX 5 10 0 -2 BITMAP 30 00 30 30 30 30 30 30 30 e0 ENDCHAR STARTCHAR char107 ENCODING 107 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP c0 c0 c8 d8 f0 f0 d8 c8 ENDCHAR STARTCHAR char108 ENCODING 108 SWIDTH 234 0 DWIDTH 3 BBX 3 8 0 0 BITMAP c0 c0 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char109 ENCODING 109 SWIDTH 701 0 DWIDTH 9 BBX 8 6 0 0 BITMAP b6 db db db db db ENDCHAR STARTCHAR char110 ENCODING 110 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP d8 ec cc cc cc cc ENDCHAR STARTCHAR char111 ENCODING 111 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc cc cc cc 78 ENDCHAR STARTCHAR char112 ENCODING 112 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP d8 ec cc cc ec d8 c0 c0 ENDCHAR STARTCHAR char113 ENCODING 113 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 6c dc cc cc dc 6c 0c 0c ENDCHAR STARTCHAR char114 ENCODING 114 SWIDTH 312 0 DWIDTH 4 BBX 4 6 0 0 BITMAP b0 e0 c0 c0 c0 c0 ENDCHAR STARTCHAR char115 ENCODING 115 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char116 ENCODING 116 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 c0 f0 c0 c0 c0 c0 70 ENDCHAR STARTCHAR char117 ENCODING 117 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP cc cc cc cc dc 6c ENDCHAR STARTCHAR char118 ENCODING 118 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP cc cc cc 78 78 30 ENDCHAR STARTCHAR char119 ENCODING 119 SWIDTH 701 0 DWIDTH 9 BBX 8 6 0 0 BITMAP 99 db db 7e 7e 34 ENDCHAR STARTCHAR char120 ENCODING 120 SWIDTH 467 0 DWIDTH 6 BBX 6 6 0 0 BITMAP 88 d8 70 70 d8 88 ENDCHAR STARTCHAR char121 ENCODING 121 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP cc cc cc 6c 78 38 30 60 ENDCHAR STARTCHAR char122 ENCODING 122 SWIDTH 467 0 DWIDTH 6 BBX 6 6 0 0 BITMAP f8 18 30 60 c0 f8 ENDCHAR STARTCHAR char123 ENCODING 123 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 60 c0 60 60 60 30 ENDCHAR STARTCHAR char124 ENCODING 124 SWIDTH 234 0 DWIDTH 3 BBX 3 10 0 -2 BITMAP c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char125 ENCODING 125 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 60 60 30 60 60 60 c0 ENDCHAR STARTCHAR char126 ENCODING 126 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 64 fc 98 ENDCHAR STARTCHAR char127 ENCODING 127 SWIDTH 389 0 DWIDTH 5 BBX 5 10 0 -2 BITMAP 88 18 30 60 c0 88 18 30 60 c0 ENDCHAR STARTCHAR char161 ENCODING 161 SWIDTH 312 0 DWIDTH 4 BBX 4 9 0 -1 BITMAP 60 60 00 60 60 60 60 60 60 ENDCHAR STARTCHAR char167 ENCODING 167 SWIDTH 623 0 DWIDTH 8 BBX 8 10 0 -2 BITMAP 1c 36 30 78 66 66 36 0c 6c 38 ENDCHAR STARTCHAR char171 ENCODING 171 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 24 6c d8 d8 6c 24 ENDCHAR STARTCHAR char176 ENCODING 176 SWIDTH 467 0 DWIDTH 6 BBX 6 4 0 2 BITMAP 70 d8 d8 70 ENDCHAR STARTCHAR char177 ENCODING 177 SWIDTH 389 0 DWIDTH 5 BBX 5 5 0 0 BITMAP 20 70 20 00 70 ENDCHAR STARTCHAR char178 ENCODING 178 SWIDTH 467 0 DWIDTH 6 BBX 6 5 0 3 BITMAP 70 d8 30 60 f8 ENDCHAR STARTCHAR char179 ENCODING 179 SWIDTH 467 0 DWIDTH 6 BBX 6 5 0 3 BITMAP 70 98 30 98 70 ENDCHAR STARTCHAR char181 ENCODING 181 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP cc cc cc cc dc f4 c0 c0 ENDCHAR STARTCHAR char183 ENCODING 183 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 3 BITMAP e0 e0 e0 ENDCHAR STARTCHAR char187 ENCODING 187 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 90 d8 6c 6c d8 90 ENDCHAR STARTCHAR char191 ENCODING 191 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 30 30 00 30 30 60 c0 cc 78 ENDCHAR STARTCHAR char192 ENCODING 192 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 78 cc cc fc cc cc ENDCHAR STARTCHAR char193 ENCODING 193 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc fc cc cc ENDCHAR STARTCHAR char194 ENCODING 194 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 78 84 78 cc fc cc cc ENDCHAR STARTCHAR char195 ENCODING 195 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 cc fc cc cc ENDCHAR STARTCHAR char196 ENCODING 196 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc cc fc cc cc ENDCHAR STARTCHAR char197 ENCODING 197 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc 78 78 cc fc cc cc ENDCHAR STARTCHAR char198 ENCODING 198 SWIDTH 701 0 DWIDTH 9 BBX 8 8 0 0 BITMAP 3f 6c 6c ff cc cc cc cf ENDCHAR STARTCHAR char199 ENCODING 199 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP 78 cc c0 c0 c0 c0 cc 78 30 60 ENDCHAR STARTCHAR char200 ENCODING 200 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 60 30 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char201 ENCODING 201 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 18 30 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char202 ENCODING 202 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 78 84 7c 60 78 60 7c ENDCHAR STARTCHAR char203 ENCODING 203 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP d8 00 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char204 ENCODING 204 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 60 00 f0 60 60 60 f0 ENDCHAR STARTCHAR char205 ENCODING 205 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 00 f0 60 60 60 f0 ENDCHAR STARTCHAR char206 ENCODING 206 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 20 70 88 f0 60 60 60 f0 ENDCHAR STARTCHAR char207 ENCODING 207 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 90 00 f0 60 60 60 60 f0 ENDCHAR STARTCHAR char208 ENCODING 208 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 7c 66 66 f6 66 66 66 7c ENDCHAR STARTCHAR char209 ENCODING 209 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 ec fc fc dc cc ENDCHAR STARTCHAR char210 ENCODING 210 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char211 ENCODING 211 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char212 ENCODING 212 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 cc cc cc 78 ENDCHAR STARTCHAR char213 ENCODING 213 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc b8 cc cc cc cc 78 ENDCHAR STARTCHAR char214 ENCODING 214 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 78 cc cc cc cc cc 78 ENDCHAR STARTCHAR char215 ENCODING 215 SWIDTH 545 0 DWIDTH 7 BBX 7 5 0 0 BITMAP 44 28 10 28 44 ENDCHAR STARTCHAR char216 ENCODING 216 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 04 78 cc dc cc ec cc 78 80 ENDCHAR STARTCHAR char217 ENCODING 217 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 cc cc cc cc cc 78 ENDCHAR STARTCHAR char218 ENCODING 218 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc cc cc cc 78 ENDCHAR STARTCHAR char219 ENCODING 219 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 78 84 cc cc cc cc 78 ENDCHAR STARTCHAR char220 ENCODING 220 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 cc cc cc cc cc 78 ENDCHAR STARTCHAR char221 ENCODING 221 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc 78 30 30 30 ENDCHAR STARTCHAR char222 ENCODING 222 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP c0 c0 f8 cc cc cc f8 c0 c0 ENDCHAR STARTCHAR char223 ENCODING 223 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 cc d8 cc cc d8 c0 c0 ENDCHAR STARTCHAR char224 ENCODING 224 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char225 ENCODING 225 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char226 ENCODING 226 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 0c 7c cc 7a ENDCHAR STARTCHAR char227 ENCODING 227 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 0c 7c cc 7a ENDCHAR STARTCHAR char228 ENCODING 228 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char229 ENCODING 229 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 38 6c 38 78 0c 7c cc 7a ENDCHAR STARTCHAR char230 ENCODING 230 SWIDTH 701 0 DWIDTH 9 BBX 8 6 0 0 BITMAP 76 1b 7f d8 db 76 ENDCHAR STARTCHAR char231 ENCODING 231 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 cc c0 c0 cc 78 30 60 ENDCHAR STARTCHAR char232 ENCODING 232 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char233 ENCODING 233 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char234 ENCODING 234 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 cc fc c0 78 ENDCHAR STARTCHAR char235 ENCODING 235 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char236 ENCODING 236 SWIDTH 312 0 DWIDTH 4 BBX 4 8 0 0 BITMAP c0 60 00 60 60 60 60 60 ENDCHAR STARTCHAR char237 ENCODING 237 SWIDTH 312 0 DWIDTH 4 BBX 4 8 0 0 BITMAP 60 c0 00 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char238 ENCODING 238 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 20 70 88 60 60 60 60 60 ENDCHAR STARTCHAR char239 ENCODING 239 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 90 00 60 60 60 60 60 60 ENDCHAR STARTCHAR char240 ENCODING 240 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP ec 38 38 0c 7c cc cc 78 ENDCHAR STARTCHAR char241 ENCODING 241 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 d8 ec cc cc cc ENDCHAR STARTCHAR char242 ENCODING 242 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char243 ENCODING 243 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char244 ENCODING 244 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 cc cc cc 78 ENDCHAR STARTCHAR char245 ENCODING 245 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 cc cc cc 78 ENDCHAR STARTCHAR char246 ENCODING 246 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc cc cc cc 78 ENDCHAR STARTCHAR char247 ENCODING 247 SWIDTH 545 0 DWIDTH 7 BBX 7 5 0 0 BITMAP 10 00 7c 00 10 ENDCHAR STARTCHAR char248 ENCODING 248 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -1 BITMAP 04 78 cc dc ec cc 78 80 ENDCHAR STARTCHAR char249 ENCODING 249 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 30 cc cc cc cc dc 6c ENDCHAR STARTCHAR char250 ENCODING 250 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc cc cc dc 6c ENDCHAR STARTCHAR char251 ENCODING 251 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 78 84 cc cc cc dc 6c ENDCHAR STARTCHAR char252 ENCODING 252 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 cc cc cc cc dc 6c ENDCHAR STARTCHAR char253 ENCODING 253 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 18 30 cc cc 78 30 60 c0 ENDCHAR STARTCHAR char254 ENCODING 254 SWIDTH 467 0 DWIDTH 6 BBX 6 10 0 -2 BITMAP c0 c0 c0 f0 d8 d8 f0 c0 c0 c0 ENDCHAR STARTCHAR char255 ENCODING 255 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP cc 00 cc cc cc cc 7c 0c cc 78 ENDCHAR ENDFONT simutrans-124.3/simutrans/font/Prop-Latin2.bdf000066400000000000000000000455671474050137200213130ustar00rootroot00000000000000STARTFONT 2.1 FONT -simutrans-prop-medium-r-normal--12-120-77-75-P-80-latin2-0 SIZE 12 77 75 FONTBOUNDINGBOX 8 11 0 -2 STARTPROPERTIES 9 POINT_SIZE 100 PIXEL_SIZE 10 RESOLUTION_X 77 RESOLUTION_Y 75 FONT_ASCENT 9 FONT_DESCENT 3 AVERAGE_WIDTH 80 SPACING "P" ENDPROPERTIES CHARS 187 STARTCHAR char10 ENCODING 10 SWIDTH 389 0 DWIDTH 5 BBX 5 1 0 0 BITMAP 00 ENDCHAR STARTCHAR char29 ENCODING 29 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP ba 44 aa 92 92 aa 44 ba ENDCHAR STARTCHAR char30 ENCODING 30 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 38 44 aa 82 aa 92 44 38 ENDCHAR STARTCHAR char31 ENCODING 31 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 38 44 aa 82 92 aa 44 38 ENDCHAR STARTCHAR char33 ENCODING 33 SWIDTH 312 0 DWIDTH 4 BBX 4 9 0 -1 BITMAP 60 60 60 60 60 60 00 60 60 ENDCHAR STARTCHAR char34 ENCODING 34 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 6c 6c d8 ENDCHAR STARTCHAR char35 ENCODING 35 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 6c 6c fe 6c 6c fe 6c 6c ENDCHAR STARTCHAR char36 ENCODING 36 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 10 78 d4 d0 d0 d0 d4 78 10 ENDCHAR STARTCHAR char37 ENCODING 37 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 72 b6 ac d8 36 6a da 9c ENDCHAR STARTCHAR char38 ENCODING 38 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 70 d0 d0 e0 74 fc d8 ec ENDCHAR STARTCHAR char39 ENCODING 39 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 5 BITMAP 60 60 c0 ENDCHAR STARTCHAR char40 ENCODING 40 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 c0 c0 c0 c0 60 30 ENDCHAR STARTCHAR char41 ENCODING 41 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 60 30 30 30 30 60 c0 ENDCHAR STARTCHAR char42 ENCODING 42 SWIDTH 623 0 DWIDTH 8 BBX 8 5 0 1 BITMAP 24 18 7e 18 24 ENDCHAR STARTCHAR char43 ENCODING 43 SWIDTH 545 0 DWIDTH 7 BBX 7 5 0 1 BITMAP 30 30 fc 30 30 ENDCHAR STARTCHAR char44 ENCODING 44 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 -1 BITMAP 60 60 c0 ENDCHAR STARTCHAR char45 ENCODING 45 SWIDTH 467 0 DWIDTH 6 BBX 6 1 0 3 BITMAP f8 ENDCHAR STARTCHAR char46 ENCODING 46 SWIDTH 234 0 DWIDTH 3 BBX 3 2 0 0 BITMAP c0 c0 ENDCHAR STARTCHAR char47 ENCODING 47 SWIDTH 545 0 DWIDTH 7 BBX 7 7 0 0 BITMAP 04 0c 18 30 60 c0 80 ENDCHAR STARTCHAR char48 ENCODING 48 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char49 ENCODING 49 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP e0 60 60 60 60 60 60 f0 ENDCHAR STARTCHAR char50 ENCODING 50 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc 0c 18 30 60 c0 fc ENDCHAR STARTCHAR char51 ENCODING 51 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc 0c 38 0c 0c cc 78 ENDCHAR STARTCHAR char52 ENCODING 52 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 60 6c cc cc fc 0c 0c ENDCHAR STARTCHAR char53 ENCODING 53 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 c0 c0 f8 0c 0c cc 78 ENDCHAR STARTCHAR char54 ENCODING 54 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 c0 c0 f8 cc cc cc 78 ENDCHAR STARTCHAR char55 ENCODING 55 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 0c 18 18 18 30 30 30 ENDCHAR STARTCHAR char56 ENCODING 56 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc 78 cc cc cc 78 ENDCHAR STARTCHAR char57 ENCODING 57 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc 7c 0c 78 ENDCHAR STARTCHAR char58 ENCODING 58 SWIDTH 312 0 DWIDTH 4 BBX 4 6 0 0 BITMAP 60 60 00 00 60 60 ENDCHAR STARTCHAR char59 ENCODING 59 SWIDTH 312 0 DWIDTH 4 BBX 4 7 0 -1 BITMAP 60 60 00 00 60 60 c0 ENDCHAR STARTCHAR char60 ENCODING 60 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 0c 38 e0 e0 38 0c ENDCHAR STARTCHAR char61 ENCODING 61 SWIDTH 467 0 DWIDTH 6 BBX 6 4 0 1 BITMAP f8 00 00 f8 ENDCHAR STARTCHAR char62 ENCODING 62 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP c0 70 1c 1c 70 c0 ENDCHAR STARTCHAR char63 ENCODING 63 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP 78 cc 0c 18 30 30 00 30 30 ENDCHAR STARTCHAR char64 ENCODING 64 SWIDTH 701 0 DWIDTH 9 BBX 8 8 0 0 BITMAP 7e e3 cf db db cf e0 7e ENDCHAR STARTCHAR char65 ENCODING 65 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc fc cc cc cc cc ENDCHAR STARTCHAR char66 ENCODING 66 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc f8 cc cc cc f8 ENDCHAR STARTCHAR char67 ENCODING 67 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 c0 c0 c0 cc 78 ENDCHAR STARTCHAR char68 ENCODING 68 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc cc cc cc f8 ENDCHAR STARTCHAR char69 ENCODING 69 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP f8 c0 c0 f0 c0 c0 c0 f8 ENDCHAR STARTCHAR char70 ENCODING 70 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP f8 c0 c0 f0 c0 c0 c0 c0 ENDCHAR STARTCHAR char71 ENCODING 71 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 c0 dc cc cc 74 ENDCHAR STARTCHAR char72 ENCODING 72 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc fc cc cc cc cc ENDCHAR STARTCHAR char73 ENCODING 73 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 60 60 60 60 60 60 f0 ENDCHAR STARTCHAR char74 ENCODING 74 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 78 30 30 30 30 30 70 e0 ENDCHAR STARTCHAR char75 ENCODING 75 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c4 cc d8 f0 f0 d8 cc c4 ENDCHAR STARTCHAR char76 ENCODING 76 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP c0 c0 c0 c0 c0 c0 c0 f8 ENDCHAR STARTCHAR char77 ENCODING 77 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 82 c6 ee fe d6 c6 c6 c6 ENDCHAR STARTCHAR char78 ENCODING 78 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc ec ec dc dc cc cc ENDCHAR STARTCHAR char79 ENCODING 79 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char80 ENCODING 80 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc cc f8 c0 c0 ENDCHAR STARTCHAR char81 ENCODING 81 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc cc cc cc d4 d8 6c ENDCHAR STARTCHAR char82 ENCODING 82 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP f8 cc cc cc f8 f0 d8 cc ENDCHAR STARTCHAR char83 ENCODING 83 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 78 cc c0 78 0c 0c cc 78 ENDCHAR STARTCHAR char84 ENCODING 84 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 30 30 30 30 30 30 30 ENDCHAR STARTCHAR char85 ENCODING 85 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc cc cc cc cc 78 ENDCHAR STARTCHAR char86 ENCODING 86 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc 78 78 78 30 30 ENDCHAR STARTCHAR char87 ENCODING 87 SWIDTH 701 0 DWIDTH 9 BBX 8 8 0 0 BITMAP c3 db db 5a 7e 7e 34 34 ENDCHAR STARTCHAR char88 ENCODING 88 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc 78 30 30 78 cc cc ENDCHAR STARTCHAR char89 ENCODING 89 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc cc 78 38 30 70 e0 ENDCHAR STARTCHAR char90 ENCODING 90 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP fc 0c 18 30 60 c0 c0 fc ENDCHAR STARTCHAR char91 ENCODING 91 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 c0 c0 c0 c0 c0 c0 f0 ENDCHAR STARTCHAR char92 ENCODING 92 SWIDTH 545 0 DWIDTH 7 BBX 7 7 0 0 BITMAP 80 c0 60 30 18 0c 04 ENDCHAR STARTCHAR char93 ENCODING 93 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP f0 30 30 30 30 30 30 f0 ENDCHAR STARTCHAR char94 ENCODING 94 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 30 78 cc ENDCHAR STARTCHAR char95 ENCODING 95 SWIDTH 467 0 DWIDTH 6 BBX 6 1 0 -1 BITMAP f8 ENDCHAR STARTCHAR char96 ENCODING 96 SWIDTH 312 0 DWIDTH 4 BBX 4 3 0 5 BITMAP c0 c0 60 ENDCHAR STARTCHAR char97 ENCODING 97 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char98 ENCODING 98 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c0 c0 d8 ec cc cc ec d8 ENDCHAR STARTCHAR char99 ENCODING 99 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char100 ENCODING 100 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 0c 0c 6c dc cc cc dc 6c ENDCHAR STARTCHAR char101 ENCODING 101 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char102 ENCODING 102 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 70 c0 f0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char103 ENCODING 103 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 6c dc cc cc dc 6c 0c 78 ENDCHAR STARTCHAR char104 ENCODING 104 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP c0 c0 d8 ec cc cc cc cc ENDCHAR STARTCHAR char105 ENCODING 105 SWIDTH 234 0 DWIDTH 3 BBX 3 8 0 0 BITMAP c0 00 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char106 ENCODING 106 SWIDTH 389 0 DWIDTH 5 BBX 5 10 0 -2 BITMAP 30 00 30 30 30 30 30 30 30 e0 ENDCHAR STARTCHAR char107 ENCODING 107 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP c0 c0 c8 d8 f0 f0 d8 c8 ENDCHAR STARTCHAR char108 ENCODING 108 SWIDTH 234 0 DWIDTH 3 BBX 3 8 0 0 BITMAP c0 c0 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char109 ENCODING 109 SWIDTH 701 0 DWIDTH 9 BBX 8 6 0 0 BITMAP b6 db db db db db ENDCHAR STARTCHAR char110 ENCODING 110 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP d8 ec cc cc cc cc ENDCHAR STARTCHAR char111 ENCODING 111 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 cc cc cc cc 78 ENDCHAR STARTCHAR char112 ENCODING 112 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP d8 ec cc cc ec d8 c0 c0 ENDCHAR STARTCHAR char113 ENCODING 113 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 6c dc cc cc dc 6c 0c 0c ENDCHAR STARTCHAR char114 ENCODING 114 SWIDTH 312 0 DWIDTH 4 BBX 4 6 0 0 BITMAP b0 e0 c0 c0 c0 c0 ENDCHAR STARTCHAR char115 ENCODING 115 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char116 ENCODING 116 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 c0 f0 c0 c0 c0 c0 70 ENDCHAR STARTCHAR char117 ENCODING 117 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP cc cc cc cc dc 6c ENDCHAR STARTCHAR char118 ENCODING 118 SWIDTH 545 0 DWIDTH 7 BBX 7 6 0 0 BITMAP cc cc cc 78 78 30 ENDCHAR STARTCHAR char119 ENCODING 119 SWIDTH 701 0 DWIDTH 9 BBX 8 6 0 0 BITMAP 99 db db 7e 7e 34 ENDCHAR STARTCHAR char120 ENCODING 120 SWIDTH 467 0 DWIDTH 6 BBX 6 6 0 0 BITMAP 88 d8 70 70 d8 88 ENDCHAR STARTCHAR char121 ENCODING 121 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP cc cc cc 6c 78 38 30 60 ENDCHAR STARTCHAR char122 ENCODING 122 SWIDTH 467 0 DWIDTH 6 BBX 6 6 0 0 BITMAP f8 18 30 60 c0 f8 ENDCHAR STARTCHAR char123 ENCODING 123 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 60 c0 60 60 60 30 ENDCHAR STARTCHAR char124 ENCODING 124 SWIDTH 234 0 DWIDTH 3 BBX 3 10 0 -2 BITMAP c0 c0 c0 c0 c0 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char125 ENCODING 125 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP c0 60 60 30 60 60 60 c0 ENDCHAR STARTCHAR char126 ENCODING 126 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 64 fc 98 ENDCHAR STARTCHAR char127 ENCODING 127 SWIDTH 389 0 DWIDTH 5 BBX 5 10 0 -2 BITMAP 88 18 30 60 c0 88 18 30 60 c0 ENDCHAR STARTCHAR char161 ENCODING 161 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP 78 cc cc fc cc cc cc cc 18 0c ENDCHAR STARTCHAR char162 ENCODING 162 SWIDTH 545 0 DWIDTH 7 BBX 7 3 0 5 BITMAP 24 3c 18 ENDCHAR STARTCHAR char163 ENCODING 163 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 60 68 78 70 e0 e0 60 7c ENDCHAR STARTCHAR char164 ENCODING 164 SWIDTH 467 0 DWIDTH 6 BBX 6 6 0 1 BITMAP 48 30 48 48 30 48 ENDCHAR STARTCHAR char165 ENCODING 165 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc d8 c0 c0 c0 c0 f8 ENDCHAR STARTCHAR char166 ENCODING 166 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char169 ENCODING 169 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char170 ENCODING 170 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP 78 cc c0 78 0c 0c cc 78 0c 38 ENDCHAR STARTCHAR char171 ENCODING 171 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 fc 30 30 30 30 30 ENDCHAR STARTCHAR char172 ENCODING 172 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 fc 0c 18 70 c0 fc ENDCHAR STARTCHAR char174 ENCODING 174 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 fc 0c 18 70 c0 fc ENDCHAR STARTCHAR char175 ENCODING 175 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 00 fc 0c 18 70 c0 fc ENDCHAR STARTCHAR char176 ENCODING 176 SWIDTH 467 0 DWIDTH 6 BBX 6 4 0 2 BITMAP 70 d8 d8 70 ENDCHAR STARTCHAR char177 ENCODING 177 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 -2 BITMAP 78 0c 7c cc cc 7a 18 0c ENDCHAR STARTCHAR char178 ENCODING 178 SWIDTH 545 0 DWIDTH 7 BBX 7 2 0 -2 BITMAP 18 0c ENDCHAR STARTCHAR char179 ENCODING 179 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 60 68 78 70 e0 e0 60 60 ENDCHAR STARTCHAR char180 ENCODING 180 SWIDTH 467 0 DWIDTH 6 BBX 6 2 0 6 BITMAP 18 30 ENDCHAR STARTCHAR char181 ENCODING 181 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc cc d8 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char182 ENCODING 182 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char185 ENCODING 185 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 78 c4 78 0c cc 78 ENDCHAR STARTCHAR char186 ENCODING 186 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 c4 78 0c cc 78 0c 38 ENDCHAR STARTCHAR char187 ENCODING 187 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP d2 cc f0 c0 c0 c0 c0 70 ENDCHAR STARTCHAR char188 ENCODING 188 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 18 30 f8 18 30 60 c0 f8 ENDCHAR STARTCHAR char190 ENCODING 190 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 48 30 f8 18 30 60 c0 f8 ENDCHAR STARTCHAR char191 ENCODING 191 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 30 00 f8 18 30 60 c0 f8 ENDCHAR STARTCHAR char192 ENCODING 192 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 f8 cc f8 f0 d8 cc ENDCHAR STARTCHAR char193 ENCODING 193 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc fc cc cc ENDCHAR STARTCHAR char194 ENCODING 194 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 30 78 84 78 cc fc cc cc ENDCHAR STARTCHAR char195 ENCODING 195 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 cc fc cc cc ENDCHAR STARTCHAR char196 ENCODING 196 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc cc fc cc cc ENDCHAR STARTCHAR char197 ENCODING 197 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 18 30 c0 c0 c0 c0 c0 f8 ENDCHAR STARTCHAR char198 ENCODING 198 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char199 ENCODING 199 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP 78 cc c0 c0 c0 c0 cc 78 30 60 ENDCHAR STARTCHAR char200 ENCODING 200 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char201 ENCODING 201 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 18 30 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char202 ENCODING 202 SWIDTH 467 0 DWIDTH 6 BBX 6 10 0 -2 BITMAP f8 c0 c0 f0 c0 c0 c0 f8 30 18 ENDCHAR STARTCHAR char203 ENCODING 203 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP d8 00 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char204 ENCODING 204 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 50 20 f8 c0 f0 c0 c0 f8 ENDCHAR STARTCHAR char205 ENCODING 205 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 30 60 00 f0 60 60 60 f0 ENDCHAR STARTCHAR char206 ENCODING 206 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 26 70 88 f0 60 60 60 f0 ENDCHAR STARTCHAR char207 ENCODING 207 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 68 30 f8 cc cc cc cc f8 ENDCHAR STARTCHAR char208 ENCODING 208 SWIDTH 623 0 DWIDTH 8 BBX 8 8 0 0 BITMAP 7c 66 66 f6 66 66 66 7c ENDCHAR STARTCHAR char209 ENCODING 209 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc ec ec dc dc cc ENDCHAR STARTCHAR char210 ENCODING 210 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 cc ec ec dc dc cc ENDCHAR STARTCHAR char211 ENCODING 211 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char212 ENCODING 212 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 cc cc cc 78 ENDCHAR STARTCHAR char213 ENCODING 213 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc b8 cc cc cc cc 78 ENDCHAR STARTCHAR char214 ENCODING 214 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 78 cc cc cc cc cc 78 ENDCHAR STARTCHAR char216 ENCODING 216 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 f8 cc f8 f0 d8 cc ENDCHAR STARTCHAR char217 ENCODING 217 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 20 50 ac cc cc cc cc 78 ENDCHAR STARTCHAR char218 ENCODING 218 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc cc cc cc 78 ENDCHAR STARTCHAR char219 ENCODING 219 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 2c 58 84 cc cc cc cc 78 ENDCHAR STARTCHAR char220 ENCODING 220 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 cc cc cc cc cc 78 ENDCHAR STARTCHAR char221 ENCODING 221 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc 78 30 30 30 ENDCHAR STARTCHAR char222 ENCODING 222 SWIDTH 545 0 DWIDTH 7 BBX 7 9 0 -1 BITMAP c0 c0 f8 cc cc cc f8 c0 c0 ENDCHAR STARTCHAR char223 ENCODING 223 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 cc d8 cc cc d8 c0 c0 ENDCHAR STARTCHAR char224 ENCODING 224 SWIDTH 312 0 DWIDTH 4 BBX 4 8 0 0 BITMAP 30 60 b0 e0 c0 c0 c0 c0 ENDCHAR STARTCHAR char225 ENCODING 225 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char226 ENCODING 226 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 0c 7c cc 7a ENDCHAR STARTCHAR char227 ENCODING 227 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 0c 7c cc 7a ENDCHAR STARTCHAR char228 ENCODING 228 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 0c 7c cc cc 7a ENDCHAR STARTCHAR char229 ENCODING 229 SWIDTH 234 0 DWIDTH 3 BBX 3 8 0 0 BITMAP 60 c0 00 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char230 ENCODING 230 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char231 ENCODING 231 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 cc c0 c0 cc 78 30 60 ENDCHAR STARTCHAR char232 ENCODING 232 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 78 cc c0 c0 cc 78 ENDCHAR STARTCHAR char233 ENCODING 233 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char234 ENCODING 234 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 -2 BITMAP 78 cc fc c0 cc 78 30 18 ENDCHAR STARTCHAR char235 ENCODING 235 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char236 ENCODING 236 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 78 cc fc c0 cc 78 ENDCHAR STARTCHAR char237 ENCODING 237 SWIDTH 312 0 DWIDTH 4 BBX 4 8 0 0 BITMAP 60 c0 00 c0 c0 c0 c0 c0 ENDCHAR STARTCHAR char238 ENCODING 238 SWIDTH 467 0 DWIDTH 6 BBX 6 8 0 0 BITMAP 20 70 88 60 60 60 60 60 ENDCHAR STARTCHAR char239 ENCODING 239 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 90 6c 0c 6c dc cc dc 6c ENDCHAR STARTCHAR char240 ENCODING 240 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP ec 38 38 0c 7c cc cc 78 ENDCHAR STARTCHAR char241 ENCODING 241 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 d8 ec cc cc cc cc ENDCHAR STARTCHAR char242 ENCODING 242 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 48 30 d8 ec cc cc cc cc ENDCHAR STARTCHAR char243 ENCODING 243 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 78 cc cc cc cc 78 ENDCHAR STARTCHAR char244 ENCODING 244 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 10 38 44 78 cc cc cc 78 ENDCHAR STARTCHAR char245 ENCODING 245 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 64 fc 98 78 cc cc cc 78 ENDCHAR STARTCHAR char246 ENCODING 246 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 78 cc cc cc cc 78 ENDCHAR STARTCHAR char247 ENCODING 247 SWIDTH 389 0 DWIDTH 5 BBX 5 5 0 0 BITMAP 60 00 f0 00 60 ENDCHAR STARTCHAR char248 ENCODING 248 SWIDTH 389 0 DWIDTH 5 BBX 5 8 0 0 BITMAP 90 60 b0 e0 c0 c0 c0 c0 ENDCHAR STARTCHAR char249 ENCODING 249 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 20 50 ac cc cc cc dc 6c ENDCHAR STARTCHAR char250 ENCODING 250 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 18 30 cc cc cc cc dc 6c ENDCHAR STARTCHAR char251 ENCODING 251 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP 2c 58 84 cc cc cc dc 6c ENDCHAR STARTCHAR char252 ENCODING 252 SWIDTH 545 0 DWIDTH 7 BBX 7 8 0 0 BITMAP cc 00 cc cc cc cc dc 6c ENDCHAR STARTCHAR char253 ENCODING 253 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP 18 30 cc cc cc 6c 78 38 30 60 ENDCHAR STARTCHAR char254 ENCODING 254 SWIDTH 467 0 DWIDTH 6 BBX 6 10 0 -2 BITMAP c0 c0 c0 f0 d8 d8 f0 c0 c0 c0 ENDCHAR STARTCHAR char255 ENCODING 255 SWIDTH 545 0 DWIDTH 7 BBX 7 10 0 -2 BITMAP cc 00 cc cc cc cc 7c 0c cc 78 ENDCHAR ENDFONT simutrans-124.3/simutrans/font/cyr.bdf000066400000000000000000013536341474050137200200370ustar00rootroot00000000000000STARTFONT 2.1 FONT -simutrans-prop-medium-r-normal--12-120-77-75-P-80-ISO10646-1 SIZE 12 77 75 FONTBOUNDINGBOX 10 11 0 -2 STARTPROPERTIES 17 POINT_SIZE 100 PIXEL_SIZE 10 RESOLUTION_X 77 RESOLUTION_Y 75 FONT_ASCENT 9 FONT_DESCENT 2 AVERAGE_WIDTH 70 SPACING "P" FOUNDRY "simutrans" FAMILY_NAME "prop" WEIGHT_NAME "medium" SLANT "r" SETWIDTH_NAME "normal" ADD_STYLE_NAME "" CHARSET_REGISTRY "ISO10646" CHARSET_ENCODING "1" _GBDFED_INFO "Edited with gbdfed 1.5." ENDPROPERTIES CHARS 2744 STARTCHAR char0 ENCODING 0 SWIDTH 389 0 DWIDTH 8 0 BBX 6 8 0 0 BITMAP FC 84 84 84 84 84 84 FC ENDCHAR STARTCHAR char29 ENCODING 29 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP BA 44 AA 92 92 AA 44 BA ENDCHAR STARTCHAR char30 ENCODING 30 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 38 44 AA 82 AA 92 44 38 ENDCHAR STARTCHAR char31 ENCODING 31 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 38 44 AA 82 92 AA 44 38 ENDCHAR STARTCHAR char32 ENCODING 32 SWIDTH 389 0 DWIDTH 5 0 BBX 5 0 0 0 BITMAP ENDCHAR STARTCHAR char33 ENCODING 33 SWIDTH 311 0 DWIDTH 4 0 BBX 4 9 0 -1 BITMAP 60 60 60 60 60 60 00 60 60 ENDCHAR STARTCHAR char34 ENCODING 34 SWIDTH 545 0 DWIDTH 7 0 BBX 7 3 0 5 BITMAP 6C 6C D8 ENDCHAR STARTCHAR char35 ENCODING 35 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 6C 6C FE 6C 6C FE 6C 6C ENDCHAR STARTCHAR char36 ENCODING 36 SWIDTH 545 0 DWIDTH 7 0 BBX 7 9 0 -1 BITMAP 10 78 D4 D0 D0 D0 D4 78 10 ENDCHAR STARTCHAR char37 ENCODING 37 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 72 B6 AC D8 36 6A DA 9C ENDCHAR STARTCHAR char38 ENCODING 38 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 70 D0 D0 E0 74 FC D8 EC ENDCHAR STARTCHAR char39 ENCODING 39 SWIDTH 311 0 DWIDTH 4 0 BBX 4 3 0 5 BITMAP 60 60 C0 ENDCHAR STARTCHAR char40 ENCODING 40 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 30 60 C0 C0 C0 C0 60 30 ENDCHAR STARTCHAR char41 ENCODING 41 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP C0 60 30 30 30 30 60 C0 ENDCHAR STARTCHAR char42 ENCODING 42 SWIDTH 623 0 DWIDTH 8 0 BBX 8 5 0 1 BITMAP 24 18 7E 18 24 ENDCHAR STARTCHAR char43 ENCODING 43 SWIDTH 545 0 DWIDTH 7 0 BBX 7 5 0 1 BITMAP 30 30 FC 30 30 ENDCHAR STARTCHAR char44 ENCODING 44 SWIDTH 311 0 DWIDTH 4 0 BBX 4 3 0 -1 BITMAP 60 60 C0 ENDCHAR STARTCHAR char45 ENCODING 45 SWIDTH 467 0 DWIDTH 6 0 BBX 6 1 0 3 BITMAP F8 ENDCHAR STARTCHAR char46 ENCODING 46 SWIDTH 233 0 DWIDTH 3 0 BBX 3 2 0 0 BITMAP C0 C0 ENDCHAR STARTCHAR char47 ENCODING 47 SWIDTH 545 0 DWIDTH 7 0 BBX 7 7 0 0 BITMAP 04 0C 18 30 60 C0 80 ENDCHAR STARTCHAR char48 ENCODING 48 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC CC CC CC CC 78 ENDCHAR STARTCHAR char49 ENCODING 49 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 30 70 30 30 30 30 30 FC ENDCHAR STARTCHAR char50 ENCODING 50 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC 0C 18 30 60 C0 FC ENDCHAR STARTCHAR char51 ENCODING 51 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC 0C 38 0C 0C CC 78 ENDCHAR STARTCHAR char52 ENCODING 52 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 60 6C CC CC FC 0C 0C ENDCHAR STARTCHAR char53 ENCODING 53 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP F8 C0 C0 F8 0C 0C CC 78 ENDCHAR STARTCHAR char54 ENCODING 54 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 C0 C0 F8 CC CC CC 78 ENDCHAR STARTCHAR char55 ENCODING 55 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP FC 0C 18 18 18 30 30 30 ENDCHAR STARTCHAR char56 ENCODING 56 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC 78 CC CC CC 78 ENDCHAR STARTCHAR char57 ENCODING 57 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC CC CC 7C 0C 78 ENDCHAR STARTCHAR char58 ENCODING 58 SWIDTH 311 0 DWIDTH 4 0 BBX 4 6 0 0 BITMAP 60 60 00 00 60 60 ENDCHAR STARTCHAR char59 ENCODING 59 SWIDTH 311 0 DWIDTH 4 0 BBX 4 7 0 -1 BITMAP 60 60 00 00 60 60 C0 ENDCHAR STARTCHAR char60 ENCODING 60 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 0C 38 E0 E0 38 0C ENDCHAR STARTCHAR char61 ENCODING 61 SWIDTH 467 0 DWIDTH 6 0 BBX 6 4 0 1 BITMAP F8 00 00 F8 ENDCHAR STARTCHAR char62 ENCODING 62 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP C0 70 1C 1C 70 C0 ENDCHAR STARTCHAR char63 ENCODING 63 SWIDTH 545 0 DWIDTH 7 0 BBX 7 9 0 -1 BITMAP 78 CC 0C 18 30 30 00 30 30 ENDCHAR STARTCHAR char64 ENCODING 64 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 0 0 BITMAP 7E E3 CF DB DB CF E0 7E ENDCHAR STARTCHAR char65 ENCODING 65 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC FC CC CC CC CC ENDCHAR STARTCHAR char66 ENCODING 66 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP F8 CC CC F8 CC CC CC F8 ENDCHAR STARTCHAR char67 ENCODING 67 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC C0 C0 C0 C0 CC 78 ENDCHAR STARTCHAR char68 ENCODING 68 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP F8 CC CC CC CC CC CC F8 ENDCHAR STARTCHAR char69 ENCODING 69 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP F8 C0 C0 F0 C0 C0 C0 F8 ENDCHAR STARTCHAR char70 ENCODING 70 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP F8 C0 C0 F0 C0 C0 C0 C0 ENDCHAR STARTCHAR char71 ENCODING 71 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC C0 C0 DC CC CC 74 ENDCHAR STARTCHAR char72 ENCODING 72 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC CC FC CC CC CC CC ENDCHAR STARTCHAR char73 ENCODING 73 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP F0 60 60 60 60 60 60 F0 ENDCHAR STARTCHAR char74 ENCODING 74 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 78 30 30 30 30 30 70 E0 ENDCHAR STARTCHAR char75 ENCODING 75 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP C4 CC D8 F0 F0 D8 CC C4 ENDCHAR STARTCHAR char76 ENCODING 76 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP C0 C0 C0 C0 C0 C0 C0 F8 ENDCHAR STARTCHAR char77 ENCODING 77 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 82 C6 EE FE D6 C6 C6 C6 ENDCHAR STARTCHAR char78 ENCODING 78 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC EC EC DC DC CC CC ENDCHAR STARTCHAR char79 ENCODING 79 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC CC CC CC CC 78 ENDCHAR STARTCHAR char80 ENCODING 80 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP F8 CC CC CC CC F8 C0 C0 ENDCHAR STARTCHAR char81 ENCODING 81 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC CC CC CC D4 D8 6C ENDCHAR STARTCHAR char82 ENCODING 82 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP F8 CC CC CC F8 F0 D8 CC ENDCHAR STARTCHAR char83 ENCODING 83 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC C0 78 0C 0C CC 78 ENDCHAR STARTCHAR char84 ENCODING 84 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP FC 30 30 30 30 30 30 30 ENDCHAR STARTCHAR char85 ENCODING 85 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC CC CC CC CC CC 78 ENDCHAR STARTCHAR char86 ENCODING 86 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC CC 78 78 78 30 30 ENDCHAR STARTCHAR char87 ENCODING 87 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 0 0 BITMAP C3 DB DB 5A 7E 7E 34 34 ENDCHAR STARTCHAR char88 ENCODING 88 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC 78 30 30 78 CC CC ENDCHAR STARTCHAR char89 ENCODING 89 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC CC CC 78 38 30 70 E0 ENDCHAR STARTCHAR char90 ENCODING 90 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP FC 0C 18 30 60 C0 C0 FC ENDCHAR STARTCHAR char91 ENCODING 91 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP F0 C0 C0 C0 C0 C0 C0 F0 ENDCHAR STARTCHAR char92 ENCODING 92 SWIDTH 545 0 DWIDTH 7 0 BBX 7 7 0 0 BITMAP 80 C0 60 30 18 0C 04 ENDCHAR STARTCHAR char93 ENCODING 93 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP F0 30 30 30 30 30 30 F0 ENDCHAR STARTCHAR char94 ENCODING 94 SWIDTH 545 0 DWIDTH 7 0 BBX 7 3 0 5 BITMAP 30 78 CC ENDCHAR STARTCHAR char95 ENCODING 95 SWIDTH 467 0 DWIDTH 6 0 BBX 6 1 0 -1 BITMAP F8 ENDCHAR STARTCHAR char96 ENCODING 96 SWIDTH 311 0 DWIDTH 4 0 BBX 4 3 0 5 BITMAP C0 C0 60 ENDCHAR STARTCHAR char97 ENCODING 97 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 78 0C 7C CC CC 7A ENDCHAR STARTCHAR char98 ENCODING 98 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP C0 C0 D8 EC CC CC EC D8 ENDCHAR STARTCHAR char99 ENCODING 99 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 78 CC C0 C0 CC 78 ENDCHAR STARTCHAR char100 ENCODING 100 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 0C 0C 6C DC CC CC DC 6C ENDCHAR STARTCHAR char101 ENCODING 101 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 78 CC FC C0 CC 78 ENDCHAR STARTCHAR char102 ENCODING 102 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 70 C0 F0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR char103 ENCODING 103 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 6C DC CC CC DC 6C 0C 78 ENDCHAR STARTCHAR char104 ENCODING 104 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP C0 C0 D8 EC CC CC CC CC ENDCHAR STARTCHAR char105 ENCODING 105 SWIDTH 233 0 DWIDTH 3 0 BBX 3 8 0 0 BITMAP C0 00 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR char106 ENCODING 106 SWIDTH 389 0 DWIDTH 5 0 BBX 5 10 0 -2 BITMAP 30 00 30 30 30 30 30 30 30 E0 ENDCHAR STARTCHAR char107 ENCODING 107 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP C0 C0 C8 D8 F0 F0 D8 C8 ENDCHAR STARTCHAR char108 ENCODING 108 SWIDTH 233 0 DWIDTH 3 0 BBX 3 8 0 0 BITMAP C0 C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR char109 ENCODING 109 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 0 0 BITMAP B6 DB DB DB DB DB ENDCHAR STARTCHAR char110 ENCODING 110 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP D8 EC CC CC CC CC ENDCHAR STARTCHAR char111 ENCODING 111 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 78 CC CC CC CC 78 ENDCHAR STARTCHAR char112 ENCODING 112 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP D8 EC CC CC EC D8 C0 C0 ENDCHAR STARTCHAR char113 ENCODING 113 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 6C DC CC CC DC 6C 0C 0C ENDCHAR STARTCHAR char114 ENCODING 114 SWIDTH 311 0 DWIDTH 4 0 BBX 4 6 0 0 BITMAP B0 E0 C0 C0 C0 C0 ENDCHAR STARTCHAR char115 ENCODING 115 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 78 C4 78 0C CC 78 ENDCHAR STARTCHAR char116 ENCODING 116 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP C0 C0 F0 C0 C0 C0 C0 70 ENDCHAR STARTCHAR char117 ENCODING 117 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP CC CC CC CC DC 6C ENDCHAR STARTCHAR char118 ENCODING 118 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP CC CC CC 78 78 30 ENDCHAR STARTCHAR char119 ENCODING 119 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 0 0 BITMAP 99 DB DB 7E 7E 34 ENDCHAR STARTCHAR char120 ENCODING 120 SWIDTH 467 0 DWIDTH 6 0 BBX 6 6 0 0 BITMAP 88 D8 70 70 D8 88 ENDCHAR STARTCHAR char121 ENCODING 121 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP CC CC CC 6C 78 38 30 60 ENDCHAR STARTCHAR char122 ENCODING 122 SWIDTH 467 0 DWIDTH 6 0 BBX 6 6 0 0 BITMAP F8 18 30 60 C0 F8 ENDCHAR STARTCHAR char123 ENCODING 123 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 30 60 60 C0 60 60 60 30 ENDCHAR STARTCHAR char124 ENCODING 124 SWIDTH 233 0 DWIDTH 3 0 BBX 3 10 0 -2 BITMAP C0 C0 C0 C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR char125 ENCODING 125 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP C0 60 60 30 60 60 60 C0 ENDCHAR STARTCHAR char126 ENCODING 126 SWIDTH 545 0 DWIDTH 7 0 BBX 7 3 0 5 BITMAP 64 FC 98 ENDCHAR STARTCHAR char127 ENCODING 127 SWIDTH 389 0 DWIDTH 5 0 BBX 5 10 0 -2 BITMAP 88 18 30 60 C0 88 18 30 60 C0 ENDCHAR STARTCHAR char160 ENCODING 160 SWIDTH 389 0 DWIDTH 5 0 BBX 5 0 0 0 BITMAP ENDCHAR STARTCHAR char161 ENCODING 161 SWIDTH 311 0 DWIDTH 4 0 BBX 4 9 0 -1 BITMAP 60 60 00 60 60 60 60 60 60 ENDCHAR STARTCHAR char167 ENCODING 167 SWIDTH 623 0 DWIDTH 8 0 BBX 8 10 0 -2 BITMAP 1C 36 30 78 66 66 36 0C 6C 38 ENDCHAR STARTCHAR char171 ENCODING 171 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 24 6C D8 D8 6C 24 ENDCHAR STARTCHAR char176 ENCODING 176 SWIDTH 467 0 DWIDTH 6 0 BBX 6 4 0 2 BITMAP 70 D8 D8 70 ENDCHAR STARTCHAR char177 ENCODING 177 SWIDTH 389 0 DWIDTH 5 0 BBX 5 5 0 0 BITMAP 20 70 20 00 70 ENDCHAR STARTCHAR char178 ENCODING 178 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 3 BITMAP 70 D8 30 60 F8 ENDCHAR STARTCHAR char179 ENCODING 179 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 3 BITMAP 70 98 30 98 70 ENDCHAR STARTCHAR char181 ENCODING 181 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP CC CC CC CC DC F4 C0 C0 ENDCHAR STARTCHAR char183 ENCODING 183 SWIDTH 311 0 DWIDTH 4 0 BBX 4 3 0 3 BITMAP E0 E0 E0 ENDCHAR STARTCHAR char187 ENCODING 187 SWIDTH 545 0 DWIDTH 7 0 BBX 7 6 0 0 BITMAP 90 D8 6C 6C D8 90 ENDCHAR STARTCHAR char191 ENCODING 191 SWIDTH 545 0 DWIDTH 7 0 BBX 7 9 0 -1 BITMAP 30 30 00 30 30 60 C0 CC 78 ENDCHAR STARTCHAR char192 ENCODING 192 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 78 CC CC FC CC CC ENDCHAR STARTCHAR char193 ENCODING 193 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 78 CC CC FC CC CC ENDCHAR STARTCHAR char194 ENCODING 194 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 30 78 84 78 CC FC CC CC ENDCHAR STARTCHAR char195 ENCODING 195 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 78 CC FC CC CC ENDCHAR STARTCHAR char196 ENCODING 196 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 78 CC CC FC CC CC ENDCHAR STARTCHAR char197 ENCODING 197 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 78 CC 78 78 CC FC CC CC ENDCHAR STARTCHAR char198 ENCODING 198 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 0 0 BITMAP 3F 6C 6C FF CC CC CC CF ENDCHAR STARTCHAR char199 ENCODING 199 SWIDTH 545 0 DWIDTH 7 0 BBX 7 10 0 -2 BITMAP 78 CC C0 C0 C0 C0 CC 78 30 60 ENDCHAR STARTCHAR char200 ENCODING 200 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 60 30 F8 C0 F0 C0 C0 F8 ENDCHAR STARTCHAR char201 ENCODING 201 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 F8 C0 F0 C0 C0 F8 ENDCHAR STARTCHAR char202 ENCODING 202 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 30 78 84 7C 60 78 60 7C ENDCHAR STARTCHAR char203 ENCODING 203 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP D8 00 F8 C0 F0 C0 C0 F8 ENDCHAR STARTCHAR char204 ENCODING 204 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP C0 60 00 F0 60 60 60 F0 ENDCHAR STARTCHAR char205 ENCODING 205 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 30 60 00 F0 60 60 60 F0 ENDCHAR STARTCHAR char206 ENCODING 206 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 20 70 88 F0 60 60 60 F0 ENDCHAR STARTCHAR char207 ENCODING 207 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 90 00 F0 60 60 60 60 F0 ENDCHAR STARTCHAR char208 ENCODING 208 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 7C 66 66 F6 66 66 66 7C ENDCHAR STARTCHAR char209 ENCODING 209 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 EC FC FC DC CC ENDCHAR STARTCHAR char210 ENCODING 210 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 78 CC CC CC CC 78 ENDCHAR STARTCHAR char211 ENCODING 211 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 78 CC CC CC CC 78 ENDCHAR STARTCHAR char212 ENCODING 212 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 10 38 44 78 CC CC CC 78 ENDCHAR STARTCHAR char213 ENCODING 213 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC B8 CC CC CC CC 78 ENDCHAR STARTCHAR char214 ENCODING 214 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 78 CC CC CC CC CC 78 ENDCHAR STARTCHAR char215 ENCODING 215 SWIDTH 545 0 DWIDTH 7 0 BBX 7 5 0 0 BITMAP 44 28 10 28 44 ENDCHAR STARTCHAR char216 ENCODING 216 SWIDTH 545 0 DWIDTH 7 0 BBX 7 9 0 -1 BITMAP 04 78 CC DC CC EC CC 78 80 ENDCHAR STARTCHAR char217 ENCODING 217 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 CC CC CC CC CC 78 ENDCHAR STARTCHAR char218 ENCODING 218 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 CC CC CC CC CC 78 ENDCHAR STARTCHAR char219 ENCODING 219 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 30 78 84 CC CC CC CC 78 ENDCHAR STARTCHAR char220 ENCODING 220 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 CC CC CC CC CC 78 ENDCHAR STARTCHAR char221 ENCODING 221 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 CC CC 78 30 30 30 ENDCHAR STARTCHAR char222 ENCODING 222 SWIDTH 545 0 DWIDTH 7 0 BBX 7 9 0 -1 BITMAP C0 C0 F8 CC CC CC F8 C0 C0 ENDCHAR STARTCHAR char223 ENCODING 223 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 78 CC D8 CC CC D8 C0 C0 ENDCHAR STARTCHAR char224 ENCODING 224 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 78 0C 7C CC CC 7A ENDCHAR STARTCHAR char225 ENCODING 225 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 78 0C 7C CC CC 7A ENDCHAR STARTCHAR char226 ENCODING 226 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 10 38 44 78 0C 7C CC 7A ENDCHAR STARTCHAR char227 ENCODING 227 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 78 0C 7C CC 7A ENDCHAR STARTCHAR char228 ENCODING 228 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 78 0C 7C CC CC 7A ENDCHAR STARTCHAR char229 ENCODING 229 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 38 6C 38 78 0C 7C CC 7A ENDCHAR STARTCHAR char230 ENCODING 230 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 0 0 BITMAP 76 1B 7F D8 DB 76 ENDCHAR STARTCHAR char231 ENCODING 231 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 78 CC C0 C0 CC 78 30 60 ENDCHAR STARTCHAR char232 ENCODING 232 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 78 CC FC C0 CC 78 ENDCHAR STARTCHAR char233 ENCODING 233 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 78 CC FC C0 CC 78 ENDCHAR STARTCHAR char234 ENCODING 234 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 10 38 44 78 CC FC C0 78 ENDCHAR STARTCHAR char235 ENCODING 235 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 78 CC FC C0 CC 78 ENDCHAR STARTCHAR char236 ENCODING 236 SWIDTH 311 0 DWIDTH 4 0 BBX 4 8 0 0 BITMAP C0 60 00 60 60 60 60 60 ENDCHAR STARTCHAR char237 ENCODING 237 SWIDTH 311 0 DWIDTH 4 0 BBX 4 8 0 0 BITMAP 60 C0 00 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR char238 ENCODING 238 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 20 70 88 60 60 60 60 60 ENDCHAR STARTCHAR char239 ENCODING 239 SWIDTH 389 0 DWIDTH 5 0 BBX 5 8 0 0 BITMAP 90 00 60 60 60 60 60 60 ENDCHAR STARTCHAR char240 ENCODING 240 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP EC 38 38 0C 7C CC CC 78 ENDCHAR STARTCHAR char241 ENCODING 241 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 D8 EC CC CC CC ENDCHAR STARTCHAR char242 ENCODING 242 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 78 CC CC CC CC 78 ENDCHAR STARTCHAR char243 ENCODING 243 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 78 CC CC CC CC 78 ENDCHAR STARTCHAR char244 ENCODING 244 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 10 38 44 78 CC CC CC 78 ENDCHAR STARTCHAR char245 ENCODING 245 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 78 CC CC CC 78 ENDCHAR STARTCHAR char246 ENCODING 246 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 78 CC CC CC CC 78 ENDCHAR STARTCHAR char247 ENCODING 247 SWIDTH 545 0 DWIDTH 7 0 BBX 7 5 0 0 BITMAP 10 00 7C 00 10 ENDCHAR STARTCHAR char248 ENCODING 248 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -1 BITMAP 04 78 CC DC EC CC 78 80 ENDCHAR STARTCHAR char249 ENCODING 249 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 60 30 CC CC CC CC DC 6C ENDCHAR STARTCHAR char250 ENCODING 250 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 18 30 CC CC CC CC DC 6C ENDCHAR STARTCHAR char251 ENCODING 251 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 30 78 84 CC CC CC DC 6C ENDCHAR STARTCHAR char252 ENCODING 252 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP CC 00 CC CC CC CC DC 6C ENDCHAR STARTCHAR char253 ENCODING 253 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 18 30 CC CC 78 30 60 C0 ENDCHAR STARTCHAR char254 ENCODING 254 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 -2 BITMAP C0 C0 C0 F0 D8 D8 F0 C0 C0 C0 ENDCHAR STARTCHAR char255 ENCODING 255 SWIDTH 545 0 DWIDTH 7 0 BBX 7 10 0 -2 BITMAP CC 00 CC CC CC CC 7C 0C CC 78 ENDCHAR STARTCHAR Abreve ENCODING 258 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 64 FC 98 78 CC FC CC CC ENDCHAR STARTCHAR abreve ENCODING 259 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 0 BITMAP 64 FC 98 78 0C 7C CC 7A ENDCHAR STARTCHAR Aogonek ENCODING 260 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 0 -2 BITMAP 78 CC CC FC CC CC CC CC 18 0C ENDCHAR STARTCHAR aogonek ENCODING 261 SWIDTH 545 0 DWIDTH 7 0 BBX 7 8 0 -2 BITMAP 78 0C 7C CC CC 7E 18 0C ENDCHAR STARTCHAR Cacute ENCODING 262 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 78 CC C0 C0 CC 78 ENDCHAR STARTCHAR cacute ENCODING 263 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 78 CC C0 C0 CC 78 ENDCHAR STARTCHAR Ccaron ENCODING 268 SWIDTH 701 0 DWIDTH 7 0 BBX 6 9 0 0 BITMAP 48 30 78 CC C0 C0 C0 CC 78 ENDCHAR STARTCHAR ccaron ENCODING 269 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 78 CC C0 C0 CC 78 ENDCHAR STARTCHAR Dcaron ENCODING 270 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 68 30 F8 CC CC CC CC F8 ENDCHAR STARTCHAR dcaron ENCODING 271 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 90 6C 0C 6C DC CC DC 6C ENDCHAR STARTCHAR Dcroat ENCODING 272 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 0 0 BITMAP 7C 66 66 F6 66 66 66 7C ENDCHAR STARTCHAR dcroat ENCODING 273 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP EC 38 38 0C 7C CC CC 78 ENDCHAR STARTCHAR Edotaccent ENCODING 278 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 40 00 F8 C0 F0 C0 C0 F8 ENDCHAR STARTCHAR edotaccent ENCODING 279 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 20 00 78 CC FC C0 CC 78 ENDCHAR STARTCHAR Eogonek ENCODING 280 SWIDTH 467 0 DWIDTH 6 0 BBX 5 10 0 -2 BITMAP F8 C0 C0 F0 C0 C0 C0 F8 30 18 ENDCHAR STARTCHAR eogonek ENCODING 281 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 -2 BITMAP 78 CC FC C0 CC 78 30 18 ENDCHAR STARTCHAR Ecaron ENCODING 282 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 50 20 F8 C0 F0 C0 C0 F8 ENDCHAR STARTCHAR ecaron ENCODING 283 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 78 CC FC C0 CC 78 ENDCHAR STARTCHAR Gbreve ENCODING 286 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 1 0 BITMAP 48 30 00 78 CC C0 DC CC CC 74 ENDCHAR STARTCHAR gbreve ENCODING 287 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 1 -1 BITMAP 48 30 00 6C DC CC DC 6C 0C 78 ENDCHAR STARTCHAR Iogonek ENCODING 302 SWIDTH 389 0 DWIDTH 5 0 BBX 4 10 0 -2 BITMAP F0 60 60 60 60 60 60 F0 20 10 ENDCHAR STARTCHAR iogonek ENCODING 303 SWIDTH 233 0 DWIDTH 3 0 BBX 3 10 0 -2 BITMAP C0 00 C0 C0 C0 C0 C0 C0 40 20 ENDCHAR STARTCHAR Idotaccent ENCODING 304 SWIDTH 467 0 DWIDTH 6 0 BBX 4 10 2 0 BITMAP 60 00 F0 60 60 60 60 60 60 F0 ENDCHAR STARTCHAR dotlessi ENCODING 305 SWIDTH 233 0 DWIDTH 3 0 BBX 2 6 1 0 BITMAP C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR Lacute ENCODING 313 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 18 30 C0 C0 C0 C0 C0 F8 ENDCHAR STARTCHAR lacute ENCODING 314 SWIDTH 233 0 DWIDTH 3 0 BBX 3 8 0 0 BITMAP 60 C0 00 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR Lcaron ENCODING 317 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP CC CC D8 C0 C0 C0 C0 F8 ENDCHAR STARTCHAR lcaron ENCODING 318 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP CC CC D8 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR Lslash ENCODING 321 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 60 68 78 70 E0 E0 60 7C ENDCHAR STARTCHAR lslash ENCODING 322 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 60 68 78 70 E0 E0 60 60 ENDCHAR STARTCHAR Nacute ENCODING 323 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 CC EC EC DC DC CC ENDCHAR STARTCHAR nacute ENCODING 324 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 D8 EC CC CC CC CC ENDCHAR STARTCHAR Ncaron ENCODING 327 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 CC EC EC DC DC CC ENDCHAR STARTCHAR ncaron ENCODING 328 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 D8 EC CC CC CC CC ENDCHAR STARTCHAR Ohungarumlaut ENCODING 336 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 64 FC B8 CC CC CC CC 78 ENDCHAR STARTCHAR ohungarumlaut ENCODING 337 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 64 FC 98 78 CC CC CC 78 ENDCHAR STARTCHAR Racute ENCODING 340 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 F8 CC F8 F0 D8 CC ENDCHAR STARTCHAR racute ENCODING 341 SWIDTH 311 0 DWIDTH 4 0 BBX 4 8 0 0 BITMAP 30 60 B0 E0 C0 C0 C0 C0 ENDCHAR STARTCHAR Rcaron ENCODING 344 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 F8 CC F8 F0 D8 CC ENDCHAR STARTCHAR rcaron ENCODING 345 SWIDTH 389 0 DWIDTH 5 0 BBX 4 8 0 0 BITMAP 90 60 B0 E0 C0 C0 C0 C0 ENDCHAR STARTCHAR Sacute ENCODING 346 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 78 C4 78 0C CC 78 ENDCHAR STARTCHAR sacute ENCODING 347 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 78 C4 78 0C CC 78 ENDCHAR STARTCHAR Scedilla ENCODING 350 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 1 -2 BITMAP 78 CC C0 78 0C 0C CC 78 30 E0 ENDCHAR STARTCHAR scedilla ENCODING 351 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 -2 BITMAP 78 C4 60 18 CC 78 30 60 ENDCHAR STARTCHAR Scaron ENCODING 352 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 78 C4 78 0C CC 78 ENDCHAR STARTCHAR scaron ENCODING 353 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 78 C4 78 0C CC 78 ENDCHAR STARTCHAR Tcaron ENCODING 356 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 48 30 FC 30 30 30 30 30 ENDCHAR STARTCHAR tcaron ENCODING 357 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 0 0 BITMAP D2 CC F0 C0 C0 C0 C0 70 ENDCHAR STARTCHAR Utilde ENCODING 360 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 64 FC 98 00 CC CC CC CC CC 78 ENDCHAR STARTCHAR utilde ENCODING 361 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 64 FC 98 00 CC CC CC CC DC 6C ENDCHAR STARTCHAR Umacron ENCODING 362 SWIDTH 545 0 DWIDTH 7 0 BBX 6 9 0 0 BITMAP 78 00 CC CC CC CC CC CC 78 ENDCHAR STARTCHAR umacron ENCODING 363 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 78 00 CC CC CC CC DC 6C ENDCHAR STARTCHAR Uring ENCODING 366 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 20 50 AC CC CC CC CC 78 ENDCHAR STARTCHAR uring ENCODING 367 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 20 50 AC CC CC CC DC 6C ENDCHAR STARTCHAR Uhungarumlaut ENCODING 368 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 2C 58 84 CC CC CC CC 78 ENDCHAR STARTCHAR uhungarumlaut ENCODING 369 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 2C 58 84 CC CC CC DC 6C ENDCHAR STARTCHAR Uogonek ENCODING 370 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 0 -2 BITMAP CC CC CC CC CC CC CC 78 10 0C ENDCHAR STARTCHAR uogonek ENCODING 371 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 -2 BITMAP CC CC CC CC DC 6C 08 04 ENDCHAR STARTCHAR Zacute ENCODING 377 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 18 30 FC 0C 18 70 C0 FC ENDCHAR STARTCHAR zacute ENCODING 378 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 18 30 F8 18 30 60 C0 F8 ENDCHAR STARTCHAR Zdotaccent ENCODING 379 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 0 0 BITMAP 30 00 FC 0C 18 70 C0 FC ENDCHAR STARTCHAR zdotaccent ENCODING 380 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 30 00 F8 18 30 60 C0 F8 ENDCHAR STARTCHAR Zcaron ENCODING 381 SWIDTH 545 0 DWIDTH 7 0 BBX 6 9 0 0 BITMAP 48 30 FC 0C 18 30 60 C0 FC ENDCHAR STARTCHAR zcaron ENCODING 382 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 0 0 BITMAP 48 30 F8 18 30 60 C0 F8 ENDCHAR STARTCHAR breve ENCODING 728 SWIDTH 545 0 DWIDTH 7 0 BBX 4 3 2 5 BITMAP 90 F0 60 ENDCHAR STARTCHAR ogonek ENCODING 731 SWIDTH 545 0 DWIDTH 7 0 BBX 3 2 3 -2 BITMAP C0 60 ENDCHAR STARTCHAR tonos ENCODING 900 SWIDTH 467 0 DWIDTH 6 0 BBX 3 2 2 7 BITMAP 60 C0 ENDCHAR STARTCHAR dieresistonos ENCODING 901 SWIDTH 467 0 DWIDTH 6 0 BBX 4 4 1 6 BITMAP 30 60 00 D0 ENDCHAR STARTCHAR Alphatonos ENCODING 902 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 78 CC CC FC CC CC CC ENDCHAR STARTCHAR anoteleia ENCODING 903 SWIDTH 467 0 DWIDTH 6 0 BBX 3 2 2 3 BITMAP E0 E0 ENDCHAR STARTCHAR Epsilontonos ENCODING 904 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 FC C0 C0 F8 C0 C0 FC ENDCHAR STARTCHAR Etatonos ENCODING 905 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 CC CC CC FC CC CC CC ENDCHAR STARTCHAR Iotatonos ENCODING 906 SWIDTH 467 0 DWIDTH 6 0 BBX 4 10 1 0 BITMAP 30 60 00 F0 60 60 60 60 60 F0 ENDCHAR STARTCHAR Omicrontonos ENCODING 908 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 78 CC CC CC CC CC 78 ENDCHAR STARTCHAR Upsilontonos ENCODING 910 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 CC CC 68 30 30 30 30 ENDCHAR STARTCHAR Omegatonos ENCODING 911 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 78 CC CC CC CC 68 EC ENDCHAR STARTCHAR iotadieresistonos ENCODING 912 SWIDTH 467 0 DWIDTH 6 0 BBX 5 10 1 0 BITMAP 30 60 00 D0 00 60 60 60 68 30 ENDCHAR STARTCHAR Alpha ENCODING 913 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 CC CC FC CC CC CC ENDCHAR STARTCHAR Beta ENCODING 914 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP F8 CC CC F8 CC CC F8 ENDCHAR STARTCHAR Gamma ENCODING 915 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR Delta ENCODING 916 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 30 30 68 68 CC CC FC ENDCHAR STARTCHAR Epsilon ENCODING 917 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC C0 C0 F8 C0 C0 FC ENDCHAR STARTCHAR Zeta ENCODING 918 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC 0C 18 30 60 C0 FC ENDCHAR STARTCHAR Eta ENCODING 919 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP CC CC CC FC CC CC CC ENDCHAR STARTCHAR Theta ENCODING 920 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 CC CC FC CC CC 78 ENDCHAR STARTCHAR Iota ENCODING 921 SWIDTH 467 0 DWIDTH 6 0 BBX 4 7 1 0 BITMAP F0 60 60 60 60 60 F0 ENDCHAR STARTCHAR Kappa ENCODING 922 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP CC D8 D0 E0 D0 D8 CC ENDCHAR STARTCHAR Lambda ENCODING 923 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 30 30 68 68 CC CC CC ENDCHAR STARTCHAR Mu ENCODING 924 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 82 C6 EE FE D6 C6 C6 C6 ENDCHAR STARTCHAR Nu ENCODING 925 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP CC CC EC EC DC DC CC CC ENDCHAR STARTCHAR Xi ENCODING 926 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC 00 00 78 00 00 FC ENDCHAR STARTCHAR Omicron ENCODING 927 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 CC CC CC CC CC 78 ENDCHAR STARTCHAR Pi ENCODING 928 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC CC CC CC CC CC CC ENDCHAR STARTCHAR Rho ENCODING 929 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP F8 CC CC F8 C0 C0 C0 ENDCHAR STARTCHAR Sigma ENCODING 931 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC 60 30 18 30 60 FC ENDCHAR STARTCHAR Tau ENCODING 932 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP FC 30 30 30 30 30 30 ENDCHAR STARTCHAR Upsilon ENCODING 933 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP CC CC 68 30 30 30 30 ENDCHAR STARTCHAR Phi ENCODING 934 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 30 78 D4 D4 D4 78 30 ENDCHAR STARTCHAR Chi ENCODING 935 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP CC CC 68 30 68 CC CC ENDCHAR STARTCHAR Psi ENCODING 936 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP D4 D4 D4 D4 78 30 30 ENDCHAR STARTCHAR Omega ENCODING 937 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 CC CC CC CC 68 EC ENDCHAR STARTCHAR Iotadieresis ENCODING 938 SWIDTH 467 0 DWIDTH 6 0 BBX 4 9 1 0 BITMAP D0 00 F0 60 60 60 60 60 F0 ENDCHAR STARTCHAR Upsilondieresis ENCODING 939 SWIDTH 467 0 DWIDTH 6 0 BBX 6 9 0 0 BITMAP 68 00 CC CC 68 30 30 30 30 ENDCHAR STARTCHAR alphatonos ENCODING 940 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 00 74 DC CC DC 74 ENDCHAR STARTCHAR epsilontonos ENCODING 941 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 00 78 CC 70 CC 78 ENDCHAR STARTCHAR etatonos ENCODING 942 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 -2 BITMAP 18 30 00 D8 EC CC CC CC 0C 0C ENDCHAR STARTCHAR iotatonos ENCODING 943 SWIDTH 467 0 DWIDTH 6 0 BBX 4 8 1 0 BITMAP 60 C0 00 C0 C0 C0 D0 60 ENDCHAR STARTCHAR upsilondieresistonos ENCODING 944 SWIDTH 467 0 DWIDTH 6 0 BBX 6 10 0 0 BITMAP 18 30 00 68 00 CC CC CC CC 78 ENDCHAR STARTCHAR alpha ENCODING 945 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP 74 DC CC DC 74 ENDCHAR STARTCHAR beta ENCODING 946 SWIDTH 467 0 DWIDTH 6 0 BBX 6 9 0 -2 BITMAP 70 D8 D8 F8 CC CC F8 C0 C0 ENDCHAR STARTCHAR gamma ENCODING 947 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP CC CC 68 68 30 30 30 ENDCHAR STARTCHAR delta ENCODING 948 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 C0 78 CC CC CC 78 ENDCHAR STARTCHAR epsilon ENCODING 949 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP 78 CC 70 CC 78 ENDCHAR STARTCHAR zeta ENCODING 950 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 -1 BITMAP FC 30 60 60 60 38 0C 38 ENDCHAR STARTCHAR eta ENCODING 951 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP D8 EC CC CC CC 0C 0C ENDCHAR STARTCHAR theta ENCODING 952 SWIDTH 467 0 DWIDTH 6 0 BBX 5 7 1 0 BITMAP 70 D8 D8 F8 D8 D8 70 ENDCHAR STARTCHAR iota ENCODING 953 SWIDTH 467 0 DWIDTH 6 0 BBX 4 5 1 0 BITMAP C0 C0 C0 D0 60 ENDCHAR STARTCHAR kappa ENCODING 954 SWIDTH 467 0 DWIDTH 6 0 BBX 5 5 1 0 BITMAP D8 D0 E0 D0 D8 ENDCHAR STARTCHAR lambda ENCODING 955 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 78 CC 0C 74 DC CC CC ENDCHAR STARTCHAR mu ENCODING 956 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP CC CC CC DC F4 C0 C0 ENDCHAR STARTCHAR nu ENCODING 957 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP CC CC 68 68 30 ENDCHAR STARTCHAR xi ENCODING 958 SWIDTH 467 0 DWIDTH 6 0 BBX 6 9 0 -2 BITMAP FC 30 60 78 C0 C0 78 0C 18 ENDCHAR STARTCHAR omicron ENCODING 959 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP 78 CC CC CC 78 ENDCHAR STARTCHAR pi ENCODING 960 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP FC 68 68 68 68 ENDCHAR STARTCHAR rho ENCODING 961 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP 78 CC CC EC D8 C0 C0 ENDCHAR STARTCHAR sigma1 ENCODING 962 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP 78 CC C0 C0 78 0C 38 ENDCHAR STARTCHAR sigma ENCODING 963 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP 7C D8 CC CC 78 ENDCHAR STARTCHAR tau ENCODING 964 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP FC 30 30 34 18 ENDCHAR STARTCHAR upsilon ENCODING 965 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP CC CC CC CC 78 ENDCHAR STARTCHAR phi ENCODING 966 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP 18 D4 D4 D4 78 30 30 ENDCHAR STARTCHAR chi ENCODING 967 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP CC CC 68 30 68 CC CC ENDCHAR STARTCHAR psi ENCODING 968 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 -2 BITMAP D4 D4 D4 D4 78 30 30 ENDCHAR STARTCHAR omega ENCODING 969 SWIDTH 467 0 DWIDTH 6 0 BBX 6 5 0 0 BITMAP 68 CC D4 D4 68 ENDCHAR STARTCHAR iotadieresis ENCODING 970 SWIDTH 467 0 DWIDTH 6 0 BBX 5 7 1 0 BITMAP D0 00 60 60 60 68 30 ENDCHAR STARTCHAR upsilondieresis ENCODING 971 SWIDTH 467 0 DWIDTH 6 0 BBX 6 7 0 0 BITMAP 68 00 CC CC CC CC 78 ENDCHAR STARTCHAR omicrontonos ENCODING 972 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 00 78 CC CC CC 78 ENDCHAR STARTCHAR upsilontonos ENCODING 973 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 00 CC CC CC CC 78 ENDCHAR STARTCHAR omegatonos ENCODING 974 SWIDTH 467 0 DWIDTH 6 0 BBX 6 8 0 0 BITMAP 18 30 00 68 CC D4 D4 68 ENDCHAR STARTCHAR U+0401 ENCODING 1025 SWIDTH 545 0 DWIDTH 7 0 BBX 6 9 1 0 BITMAP CC 00 FC C0 C0 F0 C0 C0 FC ENDCHAR STARTCHAR U+0404 ENCODING 1028 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 78 CC C0 F0 C0 C0 CC 78 ENDCHAR STARTCHAR U+0406 ENCODING 1030 SWIDTH 233 0 DWIDTH 3 0 BBX 2 8 1 0 BITMAP C0 C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0407 ENCODING 1031 SWIDTH 389 0 DWIDTH 5 0 BBX 4 9 1 0 BITMAP 90 00 60 60 60 60 60 60 60 ENDCHAR STARTCHAR U+040E ENCODING 1038 SWIDTH 623 0 DWIDTH 8 0 BBX 7 9 1 0 BITMAP 24 5A 46 2C 2C 18 18 D0 60 ENDCHAR STARTCHAR U+0410 ENCODING 1040 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 3C 6C CC CC CC FC CC CC ENDCHAR STARTCHAR U+0411 ENCODING 1041 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP FC C0 C0 F8 CC CC CC F8 ENDCHAR STARTCHAR U+0412 ENCODING 1042 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP F8 CC CC F8 CC CC CC F8 ENDCHAR STARTCHAR U+0413 ENCODING 1043 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP FC C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0414 ENCODING 1044 SWIDTH 701 0 DWIDTH 9 0 BBX 8 9 1 -1 BITMAP 1E 36 66 66 66 66 66 FF 81 ENDCHAR STARTCHAR U+0415 ENCODING 1045 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP FC C0 C0 F0 C0 C0 C0 FC ENDCHAR STARTCHAR U+0416 ENCODING 1046 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP B4 B4 78 30 30 78 B4 B4 ENDCHAR STARTCHAR U+0417 ENCODING 1047 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 78 CC 0C 18 0C 0C CC 78 ENDCHAR STARTCHAR U+0418 ENCODING 1048 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP CC CC CC CC DC EC CC CC ENDCHAR STARTCHAR U+0419 ENCODING 1049 SWIDTH 545 0 DWIDTH 7 0 BBX 6 9 1 0 BITMAP 48 B4 CC CC CC DC EC CC CC ENDCHAR STARTCHAR U+041A ENCODING 1050 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 1 0 BITMAP C8 D8 F0 E0 E0 F0 D8 C8 ENDCHAR STARTCHAR U+041B ENCODING 1051 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 3E 66 66 66 66 66 66 C6 ENDCHAR STARTCHAR U+041C ENCODING 1052 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP C6 EE FE D6 C6 C6 C6 C6 ENDCHAR STARTCHAR U+041D ENCODING 1053 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP CC CC CC FC CC CC CC CC ENDCHAR STARTCHAR U+041E ENCODING 1054 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 78 CC CC CC CC CC CC 78 ENDCHAR STARTCHAR U+041F ENCODING 1055 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP FC CC CC CC CC CC CC CC ENDCHAR STARTCHAR U+0420 ENCODING 1056 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP F8 CC CC CC F8 C0 C0 C0 ENDCHAR STARTCHAR U+0421 ENCODING 1057 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 78 CC C0 C0 C0 C0 CC 78 ENDCHAR STARTCHAR U+0422 ENCODING 1058 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP FC 30 30 30 30 30 30 30 ENDCHAR STARTCHAR U+0423 ENCODING 1059 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 46 46 2C 2C 18 18 D0 60 ENDCHAR STARTCHAR U+0424 ENCODING 1060 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 1 0 BITMAP 18 7E DB DB DB 7E 18 18 ENDCHAR STARTCHAR U+0425 ENCODING 1061 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP CC 48 78 30 30 78 48 CC ENDCHAR STARTCHAR U+0426 ENCODING 1062 SWIDTH 623 0 DWIDTH 8 0 BBX 7 9 1 -1 BITMAP CC CC CC CC CC CC CC FE 02 ENDCHAR STARTCHAR U+0427 ENCODING 1063 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP CC CC CC CC 7C 0C 0C 0C ENDCHAR STARTCHAR U+0428 ENCODING 1064 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 1 0 BITMAP C3 C3 DB DB DB DB DB FF ENDCHAR STARTCHAR U+0429 ENCODING 1065 SWIDTH 779 0 DWIDTH 10 0 BBX 9 9 1 -1 BITMAP C300 C300 DB00 DB00 DB00 DB00 DB00 FF80 0080 ENDCHAR STARTCHAR U+042A ENCODING 1066 SWIDTH 623 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP E0 60 60 7C 66 66 66 7C ENDCHAR STARTCHAR U+042B ENCODING 1067 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 1 0 BITMAP C3 C3 C3 FB CF CF CF FB ENDCHAR STARTCHAR U+042C ENCODING 1068 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP C0 C0 C0 F8 CC CC CC F8 ENDCHAR STARTCHAR U+042D ENCODING 1069 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 78 CC 0C 3C 0C 0C CC 78 ENDCHAR STARTCHAR U+042E ENCODING 1070 SWIDTH 701 0 DWIDTH 9 0 BBX 8 8 1 0 BITMAP CE DB DB FB DB DB DB CE ENDCHAR STARTCHAR U+042F ENCODING 1071 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 7C CC CC CC 7C CC CC CC ENDCHAR STARTCHAR U+0430 ENCODING 1072 SWIDTH 623 0 DWIDTH 8 0 BBX 7 6 1 0 BITMAP 78 0C 7C CC CC 7A ENDCHAR STARTCHAR U+0431 ENCODING 1073 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 04 78 C0 F8 CC CC CC 78 ENDCHAR STARTCHAR U+0432 ENCODING 1074 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 70 D8 D8 F0 F8 CC CC 78 ENDCHAR STARTCHAR U+0433 ENCODING 1075 SWIDTH 467 0 DWIDTH 6 0 BBX 5 6 1 0 BITMAP F8 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0434 ENCODING 1076 SWIDTH 701 0 DWIDTH 9 0 BBX 8 7 1 -1 BITMAP 3E 66 66 66 66 FF 81 ENDCHAR STARTCHAR U+0435 ENCODING 1077 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC FC C0 CC 78 ENDCHAR STARTCHAR U+0436 ENCODING 1078 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP B4 FC 30 78 FC B4 ENDCHAR STARTCHAR U+0437 ENCODING 1079 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC 18 0C CC 78 ENDCHAR STARTCHAR U+0438 ENCODING 1080 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP CC CC CC CC CC 74 ENDCHAR STARTCHAR U+0439 ENCODING 1081 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 48 30 CC CC CC CC CC 74 ENDCHAR STARTCHAR U+043A ENCODING 1082 SWIDTH 467 0 DWIDTH 6 0 BBX 5 6 1 0 BITMAP D8 D8 E0 F0 D8 D8 ENDCHAR STARTCHAR U+043B ENCODING 1083 SWIDTH 623 0 DWIDTH 8 0 BBX 7 6 1 0 BITMAP 3E 66 66 66 66 C6 ENDCHAR STARTCHAR U+043C ENCODING 1084 SWIDTH 623 0 DWIDTH 8 0 BBX 7 6 1 0 BITMAP C6 EE D6 C6 C6 C6 ENDCHAR STARTCHAR U+043D ENCODING 1085 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP CC CC FC CC CC CC ENDCHAR STARTCHAR U+043E ENCODING 1086 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC CC CC CC 78 ENDCHAR STARTCHAR U+043F ENCODING 1087 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP F8 CC CC CC CC CC ENDCHAR STARTCHAR U+0440 ENCODING 1088 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC CC F8 C0 C0 ENDCHAR STARTCHAR U+0441 ENCODING 1089 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC C0 C0 CC 78 ENDCHAR STARTCHAR U+0442 ENCODING 1090 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP FC 30 30 30 30 30 ENDCHAR STARTCHAR U+0443 ENCODING 1091 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 -2 BITMAP CC CC CC CC 7C 0C CC 78 ENDCHAR STARTCHAR U+0444 ENCODING 1092 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 1 0 BITMAP 18 7E DB DB 7E 18 ENDCHAR STARTCHAR U+0445 ENCODING 1093 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP CC 78 30 30 78 CC ENDCHAR STARTCHAR U+0446 ENCODING 1094 SWIDTH 623 0 DWIDTH 8 0 BBX 7 7 1 -1 BITMAP CC CC CC CC CC 7E 02 ENDCHAR STARTCHAR U+0447 ENCODING 1095 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP CC CC CC 7C 0C 0C ENDCHAR STARTCHAR U+0448 ENCODING 1096 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 1 0 BITMAP DB DB DB DB DB 7F ENDCHAR STARTCHAR U+0449 ENCODING 1097 SWIDTH 701 0 DWIDTH 9 0 BBX 9 7 1 -1 BITMAP DB00 DB00 DB00 DB00 DB00 7F80 0080 ENDCHAR STARTCHAR U+044A ENCODING 1098 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP E0 60 78 6C 6C 38 ENDCHAR STARTCHAR U+044B ENCODING 1099 SWIDTH 623 0 DWIDTH 8 0 BBX 7 6 1 0 BITMAP C6 C6 F6 DE DE 76 ENDCHAR STARTCHAR U+044C ENCODING 1100 SWIDTH 467 0 DWIDTH 6 0 BBX 5 6 1 0 BITMAP C0 C0 F0 D8 D8 70 ENDCHAR STARTCHAR U+044D ENCODING 1101 SWIDTH 467 0 DWIDTH 6 0 BBX 5 6 1 0 BITMAP 70 D8 18 38 98 70 ENDCHAR STARTCHAR U+044E ENCODING 1102 SWIDTH 701 0 DWIDTH 9 0 BBX 8 6 1 0 BITMAP CE DB DB FB DB CE ENDCHAR STARTCHAR U+044F ENCODING 1103 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC CC 7C CC CC ENDCHAR STARTCHAR U+0451 ENCODING 1105 SWIDTH 545 0 DWIDTH 7 0 BBX 6 8 1 0 BITMAP 48 00 78 CC FC C0 CC 78 ENDCHAR STARTCHAR U+0454 ENCODING 1108 SWIDTH 545 0 DWIDTH 7 0 BBX 6 6 1 0 BITMAP 78 CC C0 F0 C4 78 ENDCHAR STARTCHAR U+0456 ENCODING 1110 SWIDTH 233 0 DWIDTH 3 0 BBX 2 8 1 0 BITMAP C0 00 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0457 ENCODING 1111 SWIDTH 389 0 DWIDTH 5 0 BBX 4 8 1 0 BITMAP 90 00 60 60 60 60 60 60 ENDCHAR STARTCHAR U+045E ENCODING 1118 SWIDTH 545 0 DWIDTH 7 0 BBX 6 10 1 -2 BITMAP 48 30 CC CC CC CC 7C 0C CC 78 ENDCHAR STARTCHAR U+0490 ENCODING 1168 SWIDTH 545 0 DWIDTH 7 0 BBX 6 9 1 0 BITMAP 04 FC C0 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0491 ENCODING 1169 SWIDTH 467 0 DWIDTH 6 0 BBX 5 8 1 0 BITMAP 08 F8 C0 C0 C0 C0 C0 C0 ENDCHAR STARTCHAR U+0E01 ENCODING 3585 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 48 88 88 88 88 88 ENDCHAR STARTCHAR U+0E02 ENCODING 3586 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 1 0 BITMAP 48 A8 68 28 28 28 28 38 ENDCHAR STARTCHAR U+0E03 ENCODING 3587 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 54 AC 54 14 14 14 14 1C ENDCHAR STARTCHAR U+0E04 ENCODING 3588 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 78 84 94 AC 54 44 44 44 ENDCHAR STARTCHAR U+0E05 ENCODING 3589 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 58 A4 94 AC 54 44 44 44 ENDCHAR STARTCHAR U+0E06 ENCODING 3590 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 51 A9 51 11 11 1D 2B 11 ENDCHAR STARTCHAR U+0E07 ENCODING 3591 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 10 28 18 08 88 48 28 18 ENDCHAR STARTCHAR U+0E08 ENCODING 3592 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 08 28 58 28 08 08 ENDCHAR STARTCHAR U+0E09 ENCODING 3593 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 78 84 04 44 A4 66 3D 22 ENDCHAR STARTCHAR U+0E0A ENCODING 3594 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 04 48 B0 68 28 28 28 28 38 ENDCHAR STARTCHAR U+0E0B ENCODING 3595 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 10 0 0 BITMAP 01 02 54 A8 54 14 14 14 14 1C ENDCHAR STARTCHAR U+0E0C ENCODING 3596 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 72 8A 4A 8A 8A CA B6 4A ENDCHAR STARTCHAR U+0E0D ENCODING 3597 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 11 1 -2 BITMAP 64 94 54 94 94 D4 B4 5C 00 10 1C ENDCHAR STARTCHAR U+0E0E ENCODING 3598 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 11 1 -2 BITMAP 1C 22 12 22 22 62 A2 42 2A 52 2E ENDCHAR STARTCHAR U+0E0F ENCODING 3599 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 11 1 -2 BITMAP 1C 22 12 22 22 62 A2 42 52 AA 56 ENDCHAR STARTCHAR U+0E10 ENCODING 3600 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 11 1 -2 BITMAP 1C 22 18 04 12 2A 16 02 52 AA 56 ENDCHAR STARTCHAR U+0E11 ENCODING 3601 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 56 AD 55 19 19 11 11 11 ENDCHAR STARTCHAR U+0E12 ENCODING 3602 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 29 55 95 AD 95 AD 57 49 ENDCHAR STARTCHAR U+0E13 ENCODING 3603 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 64 94 54 94 94 D6 BD 52 ENDCHAR STARTCHAR U+0E14 ENCODING 3604 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 38 44 94 AC 94 A4 44 44 ENDCHAR STARTCHAR U+0E15 ENCODING 3605 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 28 54 94 AC 94 A4 44 44 ENDCHAR STARTCHAR U+0E16 ENCODING 3606 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 48 88 88 C8 A8 48 ENDCHAR STARTCHAR U+0E17 ENCODING 3607 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 44 AA 6A 32 32 22 22 22 ENDCHAR STARTCHAR U+0E18 ENCODING 3608 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 E0 18 88 88 88 F8 ENDCHAR STARTCHAR U+0E19 ENCODING 3609 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 44 A4 64 24 24 2E 35 22 ENDCHAR STARTCHAR U+0E1A ENCODING 3610 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 42 A2 62 22 22 22 22 3E ENDCHAR STARTCHAR U+0E1B ENCODING 3611 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 02 42 A2 62 22 22 22 22 3E ENDCHAR STARTCHAR U+0E1C ENCODING 3612 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 48 A8 C8 88 88 A8 D8 88 ENDCHAR STARTCHAR U+0E1D ENCODING 3613 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 10 3 0 BITMAP 08 08 48 A8 C8 88 88 A8 D8 88 ENDCHAR STARTCHAR U+0E1E ENCODING 3614 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 42 A2 62 22 22 2A 36 22 ENDCHAR STARTCHAR U+0E1F ENCODING 3615 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 02 42 A2 62 22 22 2A 36 22 ENDCHAR STARTCHAR U+0E20 ENCODING 3616 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 1C 22 12 22 22 62 A2 42 ENDCHAR STARTCHAR U+0E21 ENCODING 3617 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 42 A2 62 22 22 72 AA 46 ENDCHAR STARTCHAR U+0E22 ENCODING 3618 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 48 A8 C8 88 48 88 88 F8 ENDCHAR STARTCHAR U+0E23 ENCODING 3619 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 C8 20 10 10 30 50 20 ENDCHAR STARTCHAR U+0E24 ENCODING 3620 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 10 2 -2 BITMAP 70 88 48 88 88 C8 A8 48 08 08 ENDCHAR STARTCHAR U+0E25 ENCODING 3621 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 08 68 98 C8 A8 48 ENDCHAR STARTCHAR U+0E26 ENCODING 3622 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 -2 BITMAP 1C 22 12 22 22 62 A2 42 02 02 ENDCHAR STARTCHAR U+0E27 ENCODING 3623 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 08 08 08 18 28 10 ENDCHAR STARTCHAR U+0E28 ENCODING 3624 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 04 78 84 94 AC 54 44 44 44 ENDCHAR STARTCHAR U+0E29 ENCODING 3625 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 42 A2 6B 36 2A 22 22 3E ENDCHAR STARTCHAR U+0E2A ENCODING 3626 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 10 1 0 BITMAP 04 08 70 88 08 68 98 C8 A8 48 ENDCHAR STARTCHAR U+0E2B ENCODING 3627 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 42 A5 6E 32 22 22 22 22 ENDCHAR STARTCHAR U+0E2C ENCODING 3628 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 0A 14 4A A2 62 22 22 2A 36 22 ENDCHAR STARTCHAR U+0E2D ENCODING 3629 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 08 48 A8 C8 88 F8 ENDCHAR STARTCHAR U+0E2E ENCODING 3630 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 10 1 0 BITMAP 04 08 70 88 08 48 A8 C8 88 F8 ENDCHAR STARTCHAR U+0E2F ENCODING 3631 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 7 1 0 BITMAP 58 A8 48 08 08 08 08 ENDCHAR STARTCHAR U+0E30 ENCODING 3632 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 6 2 1 BITMAP 40 A8 70 40 A8 70 ENDCHAR STARTCHAR U+0E31 ENCODING 3633 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 3 2 9 BITMAP 40 A8 70 ENDCHAR STARTCHAR U+0E32 ENCODING 3634 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 8 2 0 BITMAP 70 88 08 08 08 08 08 08 ENDCHAR STARTCHAR U+0E33 ENCODING 3635 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 11 0 0 BITMAP 40 A0 40 1C 22 02 02 02 02 02 02 ENDCHAR STARTCHAR U+0E34 ENCODING 3636 SWIDTH 1000 0 DWIDTH 0 0 BBX 4 1 3 10 BITMAP F0 ENDCHAR STARTCHAR U+0E35 ENCODING 3637 SWIDTH 1000 0 DWIDTH 0 0 BBX 4 2 3 10 BITMAP 10 F0 ENDCHAR STARTCHAR U+0E36 ENCODING 3638 SWIDTH 1000 0 DWIDTH 0 0 BBX 5 3 2 10 BITMAP 10 28 F0 ENDCHAR STARTCHAR U+0E37 ENCODING 3639 SWIDTH 1000 0 DWIDTH 0 0 BBX 5 2 2 10 BITMAP 28 F8 ENDCHAR STARTCHAR U+0E38 ENCODING 3640 SWIDTH 1000 0 DWIDTH 0 0 BBX 2 2 4 -2 BITMAP C0 40 ENDCHAR STARTCHAR U+0E39 ENCODING 3641 SWIDTH 1000 0 DWIDTH 0 0 BBX 4 2 3 -2 BITMAP D0 70 ENDCHAR STARTCHAR U+0E3A ENCODING 3642 SWIDTH 1000 0 DWIDTH 0 0 BBX 2 2 3 -2 BITMAP C0 C0 ENDCHAR STARTCHAR U+0E3F ENCODING 3647 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 12 2 0 BITMAP 20 20 F0 A8 A8 F0 A8 A8 A8 F0 20 20 ENDCHAR STARTCHAR U+0E40 ENCODING 3648 SWIDTH 1000 0 DWIDTH 8 0 BBX 3 8 3 0 BITMAP 80 80 80 80 80 C0 A0 40 ENDCHAR STARTCHAR U+0E41 ENCODING 3649 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 8 1 0 BITMAP 90 90 90 90 90 D8 B4 48 ENDCHAR STARTCHAR U+0E42 ENCODING 3650 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 11 1 0 BITMAP 78 C0 20 20 20 20 20 20 30 28 10 ENDCHAR STARTCHAR U+0E43 ENCODING 3651 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 11 1 0 BITMAP 60 90 50 10 10 10 10 10 18 14 08 ENDCHAR STARTCHAR U+0E44 ENCODING 3652 SWIDTH 1000 0 DWIDTH 8 0 BBX 6 11 1 0 BITMAP B0 50 10 10 10 10 10 10 18 14 08 ENDCHAR STARTCHAR U+0E45 ENCODING 3653 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 10 2 -2 BITMAP 70 88 08 08 08 08 08 08 08 08 ENDCHAR STARTCHAR U+0E46 ENCODING 3654 SWIDTH 1000 0 DWIDTH 8 0 BBX 5 10 2 -2 BITMAP 50 A8 C8 A8 48 08 08 08 10 60 ENDCHAR STARTCHAR U+0E47 ENCODING 3655 SWIDTH 1000 0 DWIDTH 0 0 BBX 5 4 2 6 BITMAP 08 70 A8 50 ENDCHAR STARTCHAR U+0E48 ENCODING 3656 SWIDTH 1000 0 DWIDTH 0 0 BBX 1 3 6 6 BITMAP 80 80 80 ENDCHAR STARTCHAR U+0E49 ENCODING 3657 SWIDTH 1000 0 DWIDTH 0 0 BBX 4 3 3 6 BITMAP 90 50 E0 ENDCHAR STARTCHAR U+0E4A ENCODING 3658 SWIDTH 1000 0 DWIDTH 0 0 BBX 6 4 1 6 BITMAP 04 74 A8 50 ENDCHAR STARTCHAR U+0E4B ENCODING 3659 SWIDTH 1000 0 DWIDTH 0 0 BBX 3 3 3 6 BITMAP 40 E0 40 ENDCHAR STARTCHAR U+0E4C ENCODING 3660 SWIDTH 1000 0 DWIDTH 0 0 BBX 4 4 2 6 BITMAP 30 40 A0 40 ENDCHAR STARTCHAR U+0E4D ENCODING 3661 SWIDTH 1000 0 DWIDTH 0 0 BBX 3 3 3 6 BITMAP 40 A0 40 ENDCHAR STARTCHAR U+0E4E ENCODING 3662 SWIDTH 1000 0 DWIDTH 0 0 BBX 5 5 2 6 BITMAP 38 40 60 80 C0 ENDCHAR STARTCHAR U+0E4F ENCODING 3663 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 38 44 92 BA BA 92 44 38 ENDCHAR STARTCHAR U+0E50 ENCODING 3664 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 38 44 8A 9A B2 A2 44 38 ENDCHAR STARTCHAR U+0E51 ENCODING 3665 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 7 1 0 BITMAP 38 44 4A 4A 32 84 78 ENDCHAR STARTCHAR U+0E52 ENCODING 3666 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 8A 55 59 55 29 21 21 3F ENDCHAR STARTCHAR U+0E53 ENCODING 3667 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 8 1 0 BITMAP 6C 92 82 82 82 C2 A2 42 ENDCHAR STARTCHAR U+0E54 ENCODING 3668 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 04 38 40 88 94 88 88 44 3E ENDCHAR STARTCHAR U+0E55 ENCODING 3669 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 11 1 0 BITMAP 0A 14 08 30 40 88 94 88 88 44 3E ENDCHAR STARTCHAR U+0E56 ENCODING 3670 SWIDTH 1000 0 DWIDTH 8 0 BBX 8 9 0 0 BITMAP 80 5C 22 01 11 29 31 22 1C ENDCHAR STARTCHAR U+0E57 ENCODING 3671 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 08 04 52 AA 8A 8A 8A CA AC 48 ENDCHAR STARTCHAR U+0E58 ENCODING 3672 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 10 1 0 BITMAP 02 04 38 40 80 80 90 94 BA 4C ENDCHAR STARTCHAR U+0E59 ENCODING 3673 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 9 1 0 BITMAP 02 0A 54 A0 90 88 C4 A0 40 ENDCHAR STARTCHAR U+0E5A ENCODING 3674 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 7 1 0 BITMAP 5A AA 4A 0A 0A 0A 0A ENDCHAR STARTCHAR U+0E5B ENCODING 3675 SWIDTH 1000 0 DWIDTH 8 0 BBX 7 7 1 1 BITMAP 40 80 A8 AE B8 A0 40 ENDCHAR STARTCHAR U+203B ENCODING 8251 SWIDTH 960 0 DWIDTH 10 0 BBX 10 11 0 -2 BITMAP 0000 0800 4100 2200 1400 8880 1400 2200 4100 0800 0000 ENDCHAR STARTCHAR U+2639 ENCODING 9785 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 38 44 AA 82 92 AA 44 38 ENDCHAR STARTCHAR U+263A ENCODING 9786 SWIDTH 623 0 DWIDTH 8 0 BBX 8 8 0 0 BITMAP 38 44 AA 82 AA 92 44 38 ENDCHAR STARTCHAR U+300C ENCODING 12300 SWIDTH 960 0 DWIDTH 10 0 BBX 10 11 0 -2 BITMAP 0F00 0800 0800 0800 0800 0800 0800 0000 0000 0000 0000 ENDCHAR STARTCHAR U+300D ENCODING 12301 SWIDTH 960 0 DWIDTH 10 0 BBX 10 11 0 -2 BITMAP 0000 0000 0000 0000 0800 0800 0800 0800 0800 0800 7800 ENDCHAR STARTCHAR U+AC00 ENCODING 44032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0270 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+AC01 ENCODING 44033 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AC04 ENCODING 44036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AC07 ENCODING 44039 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+AC08 ENCODING 44040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AC09 ENCODING 44041 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+AC0A ENCODING 44042 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+AC10 ENCODING 44048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AC11 ENCODING 44049 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AC12 ENCODING 44050 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 2480 3C80 2540 1E20 ENDCHAR STARTCHAR U+AC13 ENCODING 44051 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+AC14 ENCODING 44052 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AC15 ENCODING 44053 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AC16 ENCODING 44054 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+AC17 ENCODING 44055 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+AC19 ENCODING 44057 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AC1A ENCODING 44058 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0440 1840 6040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+AC1B ENCODING 44059 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0470 1840 6040 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+AC1C ENCODING 44060 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 0520 0520 0520 09E0 0920 1120 6120 0120 0120 ENDCHAR STARTCHAR U+AC1D ENCODING 44061 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 0A00 0B80 0A00 3200 C200 0000 3F80 ENDCHAR STARTCHAR U+AC20 ENCODING 44064 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AC24 ENCODING 44068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 1920 6120 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+AC2C ENCODING 44076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+AC2D ENCODING 44077 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+AC2F ENCODING 44079 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+AC30 ENCODING 44080 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+AC31 ENCODING 44081 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+AC38 ENCODING 44088 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 0240 0240 0440 0470 0840 7040 0040 0040 ENDCHAR STARTCHAR U+AC39 ENCODING 44089 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 0240 0470 1840 6040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AC3C ENCODING 44092 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 0240 0470 1840 6040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AC40 ENCODING 44096 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 0440 1870 6040 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AC4B ENCODING 44107 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 0240 0470 1840 6040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+AC4D ENCODING 44109 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 0240 0470 1840 6040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AC54 ENCODING 44116 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 0520 0920 09E0 1120 6120 0120 0120 ENDCHAR STARTCHAR U+AC58 ENCODING 44120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 0520 1920 6120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AC5C ENCODING 44124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 05E0 1920 6120 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+AC70 ENCODING 44144 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 03C0 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+AC71 ENCODING 44145 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AC74 ENCODING 44148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AC77 ENCODING 44151 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+AC78 ENCODING 44152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 05C0 1840 6040 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AC7A ENCODING 44154 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 05C0 1840 6040 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+AC80 ENCODING 44160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AC81 ENCODING 44161 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AC83 ENCODING 44163 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+AC84 ENCODING 44164 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AC85 ENCODING 44165 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AC86 ENCODING 44166 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+AC89 ENCODING 44169 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 05C0 1840 6040 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AC8A ENCODING 44170 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0440 1840 6040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+AC8B ENCODING 44171 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 05C0 1840 6040 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+AC8C ENCODING 44172 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 09 09 0F 11 11 21 C1 01 01 ENDCHAR STARTCHAR U+AC90 ENCODING 44176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AC94 ENCODING 44180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 05A0 18A0 60A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+AC9C ENCODING 44188 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+AC9D ENCODING 44189 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+AC9F ENCODING 44191 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+ACA0 ENCODING 44192 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+ACA1 ENCODING 44193 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 07A0 04A0 18A0 60A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+ACA8 ENCODING 44200 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 0240 0240 05C0 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+ACA9 ENCODING 44201 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+ACAA ENCODING 44202 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+ACAC ENCODING 44204 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+ACAF ENCODING 44207 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+ACB0 ENCODING 44208 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0440 19C0 6040 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+ACB8 ENCODING 44216 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+ACB9 ENCODING 44217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+ACBB ENCODING 44219 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+ACBC ENCODING 44220 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+ACBD ENCODING 44221 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0240 05C0 1840 6040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+ACC1 ENCODING 44225 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 0440 19C0 6040 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+ACC4 ENCODING 44228 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 0F 09 09 17 11 21 C1 01 01 ENDCHAR STARTCHAR U+ACC8 ENCODING 44232 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 04A0 07A0 18A0 60A0 0000 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+ACCC ENCODING 44236 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 05A0 04A0 19A0 60A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+ACD5 ENCODING 44245 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 04A0 07A0 18A0 60A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+ACD7 ENCODING 44247 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 04A0 07A0 18A0 60A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+ACE0 ENCODING 44256 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 0040 0840 0840 0840 0800 FFC0 ENDCHAR STARTCHAR U+ACE1 ENCODING 44257 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+ACE4 ENCODING 44260 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0440 FFE0 0000 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+ACE7 ENCODING 44263 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+ACE8 ENCODING 44264 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0840 0840 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+ACEA ENCODING 44266 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0840 0840 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+ACEC ENCODING 44268 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0840 0840 FFE0 0000 7900 0900 7A80 4440 3820 ENDCHAR STARTCHAR U+ACEF ENCODING 44271 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0840 0840 FFE0 0000 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+ACF0 ENCODING 44272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+ACF1 ENCODING 44273 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+ACF3 ENCODING 44275 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+ACF5 ENCODING 44277 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+ACF6 ENCODING 44278 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0840 0840 FFE0 0000 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+ACFC ENCODING 44284 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0140 0140 0140 1170 1140 1140 1040 7F40 0040 0040 ENDCHAR STARTCHAR U+ACFD ENCODING 44285 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1270 1240 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AD00 ENCODING 44288 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0270 0A40 7F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AD04 ENCODING 44292 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 1240 1270 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AD06 ENCODING 44294 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 1240 1270 7FC0 0000 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+AD0C ENCODING 44300 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1270 1240 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AD0D ENCODING 44301 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1270 1240 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AD0F ENCODING 44303 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1270 1240 7F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+AD11 ENCODING 44305 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1270 1240 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AD18 ENCODING 44312 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 02A0 02A0 02A0 22E0 22A0 22A0 20A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+AD1C ENCODING 44316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 04E0 04A0 10A0 7EA0 00A0 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AD20 ENCODING 44320 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 24E0 20A0 7EA0 0000 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+AD29 ENCODING 44329 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 04E0 24A0 20A0 7EA0 00A0 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+AD2C ENCODING 44332 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 04E0 24A0 20A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AD2D ENCODING 44333 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 04E0 24A0 20A0 7EA0 00A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+AD34 ENCODING 44340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0140 0140 0140 1140 1140 1140 1040 7F40 0040 0040 ENDCHAR STARTCHAR U+AD35 ENCODING 44341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1240 1240 7F40 0040 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AD38 ENCODING 44344 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0A40 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AD3C ENCODING 44348 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 1240 1240 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AD44 ENCODING 44356 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1240 1240 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AD45 ENCODING 44357 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1240 1240 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AD47 ENCODING 44359 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1240 1240 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+AD49 ENCODING 44361 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 1240 1240 7F40 0040 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AD50 ENCODING 44368 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 2240 2240 2240 2240 2200 FFC0 ENDCHAR STARTCHAR U+AD54 ENCODING 44372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 1140 FFE0 0000 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+AD58 ENCODING 44376 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 2240 2240 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+AD61 ENCODING 44385 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 2240 2240 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+AD63 ENCODING 44387 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 2240 2240 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+AD6C ENCODING 44396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 0040 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+AD6D ENCODING 44397 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AD70 ENCODING 44400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 4400 4000 4000 3FC0 ENDCHAR STARTCHAR U+AD73 ENCODING 44403 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+AD74 ENCODING 44404 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+AD75 ENCODING 44405 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0400 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+AD76 ENCODING 44406 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+AD7B ENCODING 44411 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0400 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+AD7C ENCODING 44412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+AD7D ENCODING 44413 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+AD7F ENCODING 44415 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+AD81 ENCODING 44417 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+AD82 ENCODING 44418 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 0400 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+AD88 ENCODING 44424 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0240 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+AD89 ENCODING 44425 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 02C0 0240 0040 7F40 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AD8C ENCODING 44428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 02C0 0240 0040 7F40 0840 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+AD90 ENCODING 44432 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 02C0 0240 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AD9C ENCODING 44444 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 02C0 0240 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AD9D ENCODING 44445 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 02C0 0240 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+ADA4 ENCODING 44452 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP FD 05 05 05 05 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+ADB7 ENCODING 44471 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 05A0 04A0 00A0 7EA0 10A0 0100 0100 0680 3860 ENDCHAR STARTCHAR U+ADC0 ENCODING 44480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0240 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+ADC1 ENCODING 44481 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+ADC4 ENCODING 44484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 0840 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+ADC8 ENCODING 44488 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+ADD0 ENCODING 44496 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+ADD1 ENCODING 44497 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+ADD3 ENCODING 44499 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+ADDC ENCODING 44508 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 0040 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+ADE0 ENCODING 44512 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0000 FFE0 1100 5100 4000 4000 3FC0 ENDCHAR STARTCHAR U+ADE4 ENCODING 44516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+ADF8 ENCODING 44536 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 0040 0040 0040 0040 0000 FFC0 ENDCHAR STARTCHAR U+ADF9 ENCODING 44537 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+ADFC ENCODING 44540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+ADFF ENCODING 44543 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+AE00 ENCODING 44544 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+AE01 ENCODING 44545 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 FFE0 0000 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+AE08 ENCODING 44552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+AE09 ENCODING 44553 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+AE0B ENCODING 44555 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+AE0D ENCODING 44557 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 0040 0040 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+AE14 ENCODING 44564 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0140 0140 0140 0140 0140 0140 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+AE30 ENCODING 44592 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0240 0240 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+AE31 ENCODING 44593 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AE34 ENCODING 44596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AE37 ENCODING 44599 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+AE38 ENCODING 44600 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0440 1840 6040 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AE3A ENCODING 44602 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0440 1840 6040 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+AE40 ENCODING 44608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AE41 ENCODING 44609 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AE43 ENCODING 44611 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+AE45 ENCODING 44613 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AE46 ENCODING 44614 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+AE4A ENCODING 44618 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 0440 1840 6040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+AE4C ENCODING 44620 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 1170 1140 2140 2240 4240 0440 0040 ENDCHAR STARTCHAR U+AE4D ENCODING 44621 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AE4E ENCODING 44622 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+AE50 ENCODING 44624 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1270 2240 4440 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AE54 ENCODING 44628 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 2240 4440 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AE56 ENCODING 44630 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 2240 4440 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+AE5C ENCODING 44636 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AE5D ENCODING 44637 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AE5F ENCODING 44639 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+AE60 ENCODING 44640 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AE61 ENCODING 44641 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 1240 2240 4440 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AE65 ENCODING 44645 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1270 2240 4440 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AE68 ENCODING 44648 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FD20 2520 2520 2520 2520 25E0 4520 4920 8920 1120 0120 ENDCHAR STARTCHAR U+AE69 ENCODING 44649 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FE00 2600 2780 4A00 9200 2200 0000 3F80 ENDCHAR STARTCHAR U+AE6C ENCODING 44652 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AE70 ENCODING 44656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+AE78 ENCODING 44664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+AE79 ENCODING 44665 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+AE7B ENCODING 44667 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+AE7C ENCODING 44668 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+AE7D ENCODING 44669 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 1320 13E0 2520 4920 1120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+AE84 ENCODING 44676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1170 1140 1140 1140 2170 2240 4240 0440 0040 ENDCHAR STARTCHAR U+AE85 ENCODING 44677 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1270 1240 1270 2240 4440 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AE8C ENCODING 44684 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1270 1240 2270 4440 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AEBC ENCODING 44732 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 11C0 1140 1140 2140 2240 4240 0440 0040 ENDCHAR STARTCHAR U+AEBD ENCODING 44733 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AEBE ENCODING 44734 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+AEC0 ENCODING 44736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AEC4 ENCODING 44740 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 2240 4440 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AECC ENCODING 44748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AECD ENCODING 44749 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AECF ENCODING 44751 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+AED0 ENCODING 44752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AED1 ENCODING 44753 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 13C0 1240 2240 4440 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AED8 ENCODING 44760 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FCA0 24A0 24A0 24A0 27A0 24A0 44A0 48A0 88A0 10A0 00A0 ENDCHAR STARTCHAR U+AED9 ENCODING 44761 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FD00 2500 2700 4900 9100 2100 0000 3F80 ENDCHAR STARTCHAR U+AEDC ENCODING 44764 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 13A0 24A0 48A0 10A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+AEE8 ENCODING 44776 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 13A0 24A0 48A0 10A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+AEEB ENCODING 44779 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 13A0 24A0 48A0 10A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+AEED ENCODING 44781 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 13A0 24A0 48A0 10A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+AEF4 ENCODING 44788 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 11C0 1140 1140 11C0 2140 2240 4240 0440 0040 ENDCHAR STARTCHAR U+AEF8 ENCODING 44792 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 13C0 1240 13C0 2240 4440 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+AEFC ENCODING 44796 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 13C0 1240 23C0 4440 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AF07 ENCODING 44807 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 13C0 1240 13C0 2240 4440 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+AF08 ENCODING 44808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 13C0 1240 13C0 2240 4440 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AF0D ENCODING 44813 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 13C0 1240 23C0 4440 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AF10 ENCODING 44816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FCA0 24A0 27A0 24A0 24A0 27A0 44A0 48A0 88A0 10A0 00A0 ENDCHAR STARTCHAR U+AF2C ENCODING 44844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7BC0 0840 0840 0840 0840 1040 2040 4480 0400 FFC0 ENDCHAR STARTCHAR U+AF2D ENCODING 44845 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AF30 ENCODING 44848 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+AF32 ENCODING 44850 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0100 47E0 4240 4240 3980 ENDCHAR STARTCHAR U+AF34 ENCODING 44852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2440 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+AF3C ENCODING 44860 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+AF3D ENCODING 44861 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+AF3F ENCODING 44863 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+AF41 ENCODING 44865 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+AF42 ENCODING 44866 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2440 FFE0 0000 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+AF43 ENCODING 44867 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2440 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+AF48 ENCODING 44872 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 2170 4140 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+AF49 ENCODING 44873 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4170 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AF50 ENCODING 44880 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AF5C ENCODING 44892 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4170 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AF5D ENCODING 44893 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4170 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AF64 ENCODING 44900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 12A0 12A0 22E0 42A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+AF65 ENCODING 44901 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FD00 2500 4580 8500 2100 FD00 0100 3F80 ENDCHAR STARTCHAR U+AF79 ENCODING 44921 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 22E0 42A0 10A0 7EA0 00A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+AF80 ENCODING 44928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 2140 4140 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+AF84 ENCODING 44932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4140 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+AF88 ENCODING 44936 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AF90 ENCODING 44944 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4140 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+AF91 ENCODING 44945 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4140 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+AF95 ENCODING 44949 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 2140 4140 0840 7F40 0040 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AF9C ENCODING 44956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7BC0 0840 0840 0840 0840 1040 2040 5180 1100 FFC0 ENDCHAR STARTCHAR U+AFB8 ENCODING 44984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0840 0840 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+AFB9 ENCODING 44985 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+AFBC ENCODING 44988 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+AFC0 ENCODING 44992 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+AFC7 ENCODING 44999 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 FFE0 0400 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+AFC8 ENCODING 45000 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+AFC9 ENCODING 45001 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+AFCB ENCODING 45003 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+AFCD ENCODING 45005 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+AFCE ENCODING 45006 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0000 FFE0 0400 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+AFD4 ENCODING 45012 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 1140 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+AFDC ENCODING 45020 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 12C0 0040 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+AFE8 ENCODING 45032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 12C0 0040 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+AFE9 ENCODING 45033 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 12C0 0040 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+AFF0 ENCODING 45040 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP FD 25 25 25 25 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+AFF1 ENCODING 45041 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 2900 2B00 0100 0100 FD00 2100 1F80 ENDCHAR STARTCHAR U+AFF4 ENCODING 45044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 14A0 15A0 00A0 00A0 7EA0 08A0 2800 2000 2000 1FE0 ENDCHAR STARTCHAR U+AFF8 ENCODING 45048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 12A0 11A0 00A0 00A0 7EA0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B000 ENCODING 45056 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 14A0 15A0 00A0 00A0 7EA0 10A0 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B001 ENCODING 45057 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 14A0 15A0 00A0 00A0 7EA0 10A0 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B004 ENCODING 45060 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 14A0 15A0 00A0 00A0 7EA0 10A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B00C ENCODING 45068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 1140 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+B010 ENCODING 45072 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 0040 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+B014 ENCODING 45076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B01C ENCODING 45084 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 0040 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B01D ENCODING 45085 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 0040 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B028 ENCODING 45096 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 0840 0840 0840 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+B044 ENCODING 45124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7BC0 0840 0840 0840 0840 1040 2040 4080 0000 FFC0 ENDCHAR STARTCHAR U+B045 ENCODING 45125 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B048 ENCODING 45128 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B04A ENCODING 45130 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0100 47E0 4240 4240 3980 ENDCHAR STARTCHAR U+B04C ENCODING 45132 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2040 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B04E ENCODING 45134 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2040 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+B053 ENCODING 45139 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2040 FFE0 0000 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+B054 ENCODING 45140 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B055 ENCODING 45141 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B057 ENCODING 45143 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B059 ENCODING 45145 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 0840 1040 2040 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B05D ENCODING 45149 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 0840 1040 2040 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+B07C ENCODING 45180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 1140 1140 1140 1140 1140 2140 2240 4240 0440 0040 ENDCHAR STARTCHAR U+B07D ENCODING 45181 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B080 ENCODING 45184 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B084 ENCODING 45188 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 2240 4440 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B08C ENCODING 45196 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B08D ENCODING 45197 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B08F ENCODING 45199 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B091 ENCODING 45201 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1240 1240 1240 2240 4440 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B098 ENCODING 45208 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 4070 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B099 ENCODING 45209 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B09A ENCODING 45210 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+B09C ENCODING 45212 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4070 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B09F ENCODING 45215 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+B0A0 ENCODING 45216 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B0A1 ENCODING 45217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+B0A2 ENCODING 45218 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B0A8 ENCODING 45224 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B0A9 ENCODING 45225 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B0AB ENCODING 45227 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B0AC ENCODING 45228 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B0AD ENCODING 45229 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B0AE ENCODING 45230 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B0AF ENCODING 45231 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B0B1 ENCODING 45233 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B0B3 ENCODING 45235 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B0B4 ENCODING 45236 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 4120 4120 4120 41E0 4120 3D20 0120 0120 0120 ENDCHAR STARTCHAR U+B0B5 ENCODING 45237 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 8200 8200 8380 8200 7E00 0200 0000 3F80 ENDCHAR STARTCHAR U+B0B8 ENCODING 45240 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B0BC ENCODING 45244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B0C4 ENCODING 45252 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B0C5 ENCODING 45253 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B0C7 ENCODING 45255 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B0C8 ENCODING 45256 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B0C9 ENCODING 45257 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4120 4120 41E0 4120 3F20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B0D0 ENCODING 45264 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4070 4040 4040 4040 4070 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B0D1 ENCODING 45265 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4070 4040 4070 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B0D4 ENCODING 45268 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4070 4040 4070 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B0D8 ENCODING 45272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4070 4040 4070 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B0E0 ENCODING 45280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4070 4040 4070 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B0E5 ENCODING 45285 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4070 4040 4070 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B108 ENCODING 45320 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 41C0 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B109 ENCODING 45321 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B10B ENCODING 45323 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 3C80 0480 0540 0220 ENDCHAR STARTCHAR U+B10C ENCODING 45324 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B110 ENCODING 45328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B112 ENCODING 45330 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B113 ENCODING 45331 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 3D40 0540 3DC0 2140 1FC0 ENDCHAR STARTCHAR U+B118 ENCODING 45336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B119 ENCODING 45337 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B11B ENCODING 45339 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B11C ENCODING 45340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B11D ENCODING 45341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B123 ENCODING 45347 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B124 ENCODING 45348 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 81 81 81 81 87 81 81 79 01 01 01 ENDCHAR STARTCHAR U+B125 ENCODING 45349 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 8100 8100 8700 8100 7D00 0100 0000 3F80 ENDCHAR STARTCHAR U+B128 ENCODING 45352 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B12C ENCODING 45356 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B134 ENCODING 45364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B135 ENCODING 45365 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B137 ENCODING 45367 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B138 ENCODING 45368 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B139 ENCODING 45369 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 40A0 43A0 40A0 3EA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B140 ENCODING 45376 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 41C0 4040 4040 41C0 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B141 ENCODING 45377 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B144 ENCODING 45380 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B148 ENCODING 45384 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B150 ENCODING 45392 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B151 ENCODING 45393 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B154 ENCODING 45396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B155 ENCODING 45397 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B158 ENCODING 45400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 41C0 4040 41C0 3F40 0040 0000 3FC0 0040 3FC0 0040 ENDCHAR STARTCHAR U+B15C ENCODING 45404 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 81 81 87 81 81 87 81 79 01 01 01 ENDCHAR STARTCHAR U+B160 ENCODING 45408 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 40A0 43A0 40A0 43A0 3EA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B178 ENCODING 45432 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4000 4000 4000 4000 4000 3FC0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+B179 ENCODING 45433 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B17C ENCODING 45436 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B180 ENCODING 45440 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B182 ENCODING 45442 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+B188 ENCODING 45448 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B189 ENCODING 45449 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B18B ENCODING 45451 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B18D ENCODING 45453 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B192 ENCODING 45458 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0400 FFE0 0000 7FC0 1100 1100 7FC0 ENDCHAR STARTCHAR U+B193 ENCODING 45459 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0400 FFE0 0000 0E00 0000 7FC0 2080 1F00 ENDCHAR STARTCHAR U+B194 ENCODING 45460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3E70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B198 ENCODING 45464 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E70 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B19C ENCODING 45468 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 3E40 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B1A8 ENCODING 45480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E70 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B1CC ENCODING 45516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3E40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B1D0 ENCODING 45520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B1D4 ENCODING 45524 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 3E40 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B1DC ENCODING 45532 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E40 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B1DD ENCODING 45533 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E40 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B1DF ENCODING 45535 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E40 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B1E8 ENCODING 45544 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4000 4000 4000 4000 4000 3FC0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+B1E9 ENCODING 45545 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 1100 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B1EC ENCODING 45548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B1F0 ENCODING 45552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B1F9 ENCODING 45561 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 1100 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B1FB ENCODING 45563 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 1100 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B1FD ENCODING 45565 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B204 ENCODING 45572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+B205 ENCODING 45573 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B208 ENCODING 45576 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+B20B ENCODING 45579 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+B20C ENCODING 45580 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B214 ENCODING 45588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B215 ENCODING 45589 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B217 ENCODING 45591 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B219 ENCODING 45593 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B220 ENCODING 45600 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3F40 0040 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+B234 ENCODING 45620 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 40C0 3C40 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B23C ENCODING 45628 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 81 81 81 79 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+B258 ENCODING 45656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3F40 0040 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+B25C ENCODING 45660 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3C40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+B260 ENCODING 45664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 3C40 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B268 ENCODING 45672 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3C40 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B269 ENCODING 45673 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3C40 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B274 ENCODING 45684 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+B275 ENCODING 45685 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 1100 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B27C ENCODING 45692 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B284 ENCODING 45700 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B285 ENCODING 45701 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 1100 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B289 ENCODING 45705 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B290 ENCODING 45712 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4000 4000 4000 4000 4000 3FC0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+B291 ENCODING 45713 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B294 ENCODING 45716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B298 ENCODING 45720 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B299 ENCODING 45721 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0000 FFE0 0000 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+B29A ENCODING 45722 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 3FC0 0000 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+B2A0 ENCODING 45728 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B2A1 ENCODING 45729 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B2A3 ENCODING 45731 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B2A5 ENCODING 45733 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B2A6 ENCODING 45734 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+B2AA ENCODING 45738 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4000 4000 4000 3FC0 0000 FFE0 0000 7FC0 1100 1100 7FC0 ENDCHAR STARTCHAR U+B2AC ENCODING 45740 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3E40 0040 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+B2B0 ENCODING 45744 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 3E40 0040 7FC0 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B2B4 ENCODING 45748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 3E40 0040 7FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B2C8 ENCODING 45768 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B2C9 ENCODING 45769 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B2CC ENCODING 45772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B2D0 ENCODING 45776 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B2D2 ENCODING 45778 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B2D8 ENCODING 45784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B2D9 ENCODING 45785 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B2DB ENCODING 45787 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B2DD ENCODING 45789 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B2E2 ENCODING 45794 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 4040 4040 4040 3F40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+B2E4 ENCODING 45796 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 4070 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B2E5 ENCODING 45797 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B2E6 ENCODING 45798 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+B2E8 ENCODING 45800 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4070 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B2EB ENCODING 45803 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+B2EC ENCODING 45804 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B2ED ENCODING 45805 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+B2EE ENCODING 45806 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B2EF ENCODING 45807 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 3A40 0A40 3BC0 2240 1FC0 ENDCHAR STARTCHAR U+B2F3 ENCODING 45811 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+B2F4 ENCODING 45812 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B2F5 ENCODING 45813 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B2F7 ENCODING 45815 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B2F8 ENCODING 45816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B2F9 ENCODING 45817 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B2FA ENCODING 45818 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B2FB ENCODING 45819 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B2FF ENCODING 45823 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B300 ENCODING 45824 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7920 4120 4120 4120 4120 41E0 4120 3D20 0120 0120 0120 ENDCHAR STARTCHAR U+B301 ENCODING 45825 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 8200 8380 8200 7E00 0200 0000 3F80 ENDCHAR STARTCHAR U+B304 ENCODING 45828 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B308 ENCODING 45832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B310 ENCODING 45840 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B311 ENCODING 45841 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B313 ENCODING 45843 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B314 ENCODING 45844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B315 ENCODING 45845 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 41E0 4120 3F20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B31C ENCODING 45852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 4040 4040 4040 4070 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B354 ENCODING 45908 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 41C0 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B355 ENCODING 45909 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B356 ENCODING 45910 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+B358 ENCODING 45912 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B35B ENCODING 45915 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+B35C ENCODING 45916 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B35E ENCODING 45918 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B35F ENCODING 45919 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 3D40 0540 3DC0 2140 1FC0 ENDCHAR STARTCHAR U+B364 ENCODING 45924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B365 ENCODING 45925 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B367 ENCODING 45927 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B369 ENCODING 45929 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B36B ENCODING 45931 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B36E ENCODING 45934 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 3F40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+B370 ENCODING 45936 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F1 81 81 81 87 81 81 79 01 01 01 ENDCHAR STARTCHAR U+B371 ENCODING 45937 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 8100 8700 8100 7D00 0100 0000 3F80 ENDCHAR STARTCHAR U+B374 ENCODING 45940 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B378 ENCODING 45944 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B380 ENCODING 45952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B381 ENCODING 45953 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B383 ENCODING 45955 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B384 ENCODING 45956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B385 ENCODING 45957 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 43A0 40A0 3EA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B38C ENCODING 45964 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 4040 4040 41C0 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B390 ENCODING 45968 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 4040 41C0 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B394 ENCODING 45972 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 4040 41C0 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B3A0 ENCODING 45984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 4040 41C0 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B3A1 ENCODING 45985 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 4040 41C0 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B3A8 ENCODING 45992 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F1 81 87 81 81 87 81 79 01 01 01 ENDCHAR STARTCHAR U+B3AC ENCODING 45996 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 43A0 40A0 43A0 3EA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B3C4 ENCODING 46020 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 4000 4000 3FC0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+B3C5 ENCODING 46021 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B3C8 ENCODING 46024 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B3CB ENCODING 46027 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+B3CC ENCODING 46028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B3CE ENCODING 46030 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+B3D0 ENCODING 46032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0400 FFE0 0000 7900 0900 7A80 4440 3820 ENDCHAR STARTCHAR U+B3D4 ENCODING 46036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B3D5 ENCODING 46037 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B3D7 ENCODING 46039 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B3D9 ENCODING 46041 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B3DB ENCODING 46043 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0400 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+B3DD ENCODING 46045 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0400 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+B3E0 ENCODING 46048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3E70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B3E4 ENCODING 46052 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 3E70 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B3E8 ENCODING 46056 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 3E40 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B3FC ENCODING 46076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 40A0 40A0 40A0 3EE0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+B410 ENCODING 46096 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 40E0 3CA0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B418 ENCODING 46104 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3E40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B41C ENCODING 46108 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 3E40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B420 ENCODING 46112 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 3E40 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B428 ENCODING 46120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 3E40 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B429 ENCODING 46121 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 3E40 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B42B ENCODING 46123 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 3E40 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B434 ENCODING 46132 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 4000 4000 3FC0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+B450 ENCODING 46160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 4000 3FC0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+B451 ENCODING 46161 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B454 ENCODING 46164 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+B458 ENCODING 46168 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B460 ENCODING 46176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B461 ENCODING 46177 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B463 ENCODING 46179 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B465 ENCODING 46181 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B46C ENCODING 46188 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+B480 ENCODING 46208 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 40C0 3C40 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B488 ENCODING 46216 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 81 81 79 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+B49D ENCODING 46237 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 41A0 3CA0 00A0 7EA0 10A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B4A4 ENCODING 46244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+B4A8 ENCODING 46248 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 4040 3C40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+B4AC ENCODING 46252 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 3C40 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B4B5 ENCODING 46261 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 4040 3C40 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B4B7 ENCODING 46263 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 4040 3C40 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B4B9 ENCODING 46265 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 4040 3C40 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B4C0 ENCODING 46272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 4000 3FC0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+B4C4 ENCODING 46276 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+B4C8 ENCODING 46280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B4D0 ENCODING 46288 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B4D5 ENCODING 46293 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B4DC ENCODING 46300 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 4000 4000 3FC0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+B4DD ENCODING 46301 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B4E0 ENCODING 46304 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B4E3 ENCODING 46307 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+B4E4 ENCODING 46308 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B4E6 ENCODING 46310 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 3FC0 0000 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+B4EC ENCODING 46316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B4ED ENCODING 46317 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B4EF ENCODING 46319 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B4F1 ENCODING 46321 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 4000 3FC0 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B4F8 ENCODING 46328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3E40 0040 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+B514 ENCODING 46356 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B515 ENCODING 46357 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B518 ENCODING 46360 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B51B ENCODING 46363 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+B51C ENCODING 46364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B524 ENCODING 46372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B525 ENCODING 46373 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B527 ENCODING 46375 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B528 ENCODING 46376 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B529 ENCODING 46377 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B52A ENCODING 46378 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 4040 3F40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B530 ENCODING 46384 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 4870 4840 4840 4840 3F40 0040 0040 ENDCHAR STARTCHAR U+B531 ENCODING 46385 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B534 ENCODING 46388 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4870 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B538 ENCODING 46392 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B540 ENCODING 46400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B541 ENCODING 46401 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B543 ENCODING 46403 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B544 ENCODING 46404 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B545 ENCODING 46405 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B54B ENCODING 46411 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4870 4840 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B54C ENCODING 46412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 5120 5120 5120 5120 51E0 5120 5120 3D20 0120 0120 ENDCHAR STARTCHAR U+B54D ENCODING 46413 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FE00 9200 9380 9200 7E00 0200 0000 3F80 ENDCHAR STARTCHAR U+B550 ENCODING 46416 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B554 ENCODING 46420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B55C ENCODING 46428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B55D ENCODING 46429 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B55F ENCODING 46431 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B560 ENCODING 46432 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B561 ENCODING 46433 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F20 4920 49E0 4920 3F20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B5A0 ENCODING 46496 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 49C0 4840 4840 4840 4840 3F40 0040 0040 ENDCHAR STARTCHAR U+B5A1 ENCODING 46497 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B5A4 ENCODING 46500 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B5A8 ENCODING 46504 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B5AA ENCODING 46506 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B5AB ENCODING 46507 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 3D40 0540 3DC0 2140 1FC0 ENDCHAR STARTCHAR U+B5B0 ENCODING 46512 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B5B1 ENCODING 46513 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B5B3 ENCODING 46515 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B5B4 ENCODING 46516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B5B5 ENCODING 46517 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B5BB ENCODING 46523 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B5BC ENCODING 46524 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 A1 A1 A1 A7 A1 A1 A1 79 01 01 ENDCHAR STARTCHAR U+B5BD ENCODING 46525 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FD00 9100 9700 9100 7D00 0100 0000 3F80 ENDCHAR STARTCHAR U+B5C0 ENCODING 46528 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B5C4 ENCODING 46532 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B5CC ENCODING 46540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B5CD ENCODING 46541 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B5CF ENCODING 46543 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B5D0 ENCODING 46544 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B5D1 ENCODING 46545 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 4BA0 48A0 3EA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B5D8 ENCODING 46552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 49C0 4840 4840 49C0 4840 4840 3F40 0040 0040 ENDCHAR STARTCHAR U+B5EC ENCODING 46572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 49C0 4840 49C0 3F40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B610 ENCODING 46608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7BC0 4200 4200 4200 4200 39C0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+B611 ENCODING 46609 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 3BC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B614 ENCODING 46612 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B618 ENCODING 46616 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 3BC0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B625 ENCODING 46629 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 3BC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B62C ENCODING 46636 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B634 ENCODING 46644 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 3E40 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B648 ENCODING 46664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 48A0 48A0 48A0 3EE0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+B664 ENCODING 46692 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B668 ENCODING 46696 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B69C ENCODING 46748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 4200 39C0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+B69D ENCODING 46749 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B6A0 ENCODING 46752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+B6A4 ENCODING 46756 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 39C0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B6AB ENCODING 46763 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 39C0 0000 FFE0 0400 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+B6AC ENCODING 46764 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B6B1 ENCODING 46769 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+B6D4 ENCODING 46804 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP FD 91 91 7D 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+B6F0 ENCODING 46832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+B6F4 ENCODING 46836 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+B6F8 ENCODING 46840 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 3E40 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B700 ENCODING 46848 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B701 ENCODING 46849 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B705 ENCODING 46853 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B728 ENCODING 46888 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7BC0 4200 4200 4200 4200 39C0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+B729 ENCODING 46889 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B72C ENCODING 46892 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B72F ENCODING 46895 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+B730 ENCODING 46896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 39C0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B738 ENCODING 46904 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+B739 ENCODING 46905 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B73B ENCODING 46907 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 4200 4200 39C0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+B744 ENCODING 46916 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+B748 ENCODING 46920 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B74C ENCODING 46924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 3E40 0040 7FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B754 ENCODING 46932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B755 ENCODING 46933 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4840 4840 3E40 0040 7FC0 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B760 ENCODING 46944 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 4840 4840 4840 4840 3F40 0040 0040 ENDCHAR STARTCHAR U+B764 ENCODING 46948 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B768 ENCODING 46952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B770 ENCODING 46960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B771 ENCODING 46961 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B773 ENCODING 46963 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B775 ENCODING 46965 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 4840 4840 4840 3F40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B77C ENCODING 46972 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 4070 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B77D ENCODING 46973 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B780 ENCODING 46976 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4070 4040 3F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B784 ENCODING 46980 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B78C ENCODING 46988 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B78D ENCODING 46989 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B78F ENCODING 46991 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B790 ENCODING 46992 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B791 ENCODING 46993 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B792 ENCODING 46994 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B796 ENCODING 46998 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 4040 3F40 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+B797 ENCODING 46999 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 4040 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B798 ENCODING 47000 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 0520 7D20 4120 41E0 4120 3D20 0120 0120 0120 ENDCHAR STARTCHAR U+B799 ENCODING 47001 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 0A00 FB80 8200 8200 7A00 0000 3F80 ENDCHAR STARTCHAR U+B79C ENCODING 47004 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B7A0 ENCODING 47008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 3D20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B7A8 ENCODING 47016 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B7A9 ENCODING 47017 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B7AB ENCODING 47019 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B7AC ENCODING 47020 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B7AD ENCODING 47021 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 4120 4120 3D20 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B7B4 ENCODING 47028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 7E40 4040 4040 4070 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B7B5 ENCODING 47029 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 4070 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B7B8 ENCODING 47032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 4070 4040 3F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B7C7 ENCODING 47047 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 4070 4040 3F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B7C9 ENCODING 47049 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 4070 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B7EC ENCODING 47084 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7FC0 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B7ED ENCODING 47085 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B7F0 ENCODING 47088 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B7F4 ENCODING 47092 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B7FC ENCODING 47100 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B7FD ENCODING 47101 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B7FF ENCODING 47103 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B800 ENCODING 47104 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B801 ENCODING 47105 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B807 ENCODING 47111 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 4040 3F40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B808 ENCODING 47112 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 09 F9 87 81 81 79 01 01 01 ENDCHAR STARTCHAR U+B809 ENCODING 47113 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 0900 FF00 8100 8100 7900 0000 3F80 ENDCHAR STARTCHAR U+B80C ENCODING 47116 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 40A0 3CA0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B810 ENCODING 47120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 3CA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B818 ENCODING 47128 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 40A0 3CA0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B819 ENCODING 47129 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 40A0 3CA0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B81B ENCODING 47131 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 40A0 3CA0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B81D ENCODING 47133 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 40A0 40A0 3CA0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B824 ENCODING 47140 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 7E40 4040 41C0 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B825 ENCODING 47141 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B828 ENCODING 47144 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B82C ENCODING 47148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B834 ENCODING 47156 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B835 ENCODING 47157 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B837 ENCODING 47159 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+B838 ENCODING 47160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+B839 ENCODING 47161 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 41C0 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B840 ENCODING 47168 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 0F F9 81 87 81 79 01 01 01 ENDCHAR STARTCHAR U+B844 ENCODING 47172 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 7CA0 43A0 40A0 3CA0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B851 ENCODING 47185 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 7CA0 43A0 40A0 3CA0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B853 ENCODING 47187 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 07A0 7CA0 43A0 40A0 3CA0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B85C ENCODING 47196 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 7FC0 4000 4000 3FC0 0400 0400 FFC0 ENDCHAR STARTCHAR U+B85D ENCODING 47197 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+B860 ENCODING 47200 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B864 ENCODING 47204 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B86C ENCODING 47212 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B86D ENCODING 47213 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B86F ENCODING 47215 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+B871 ENCODING 47217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0400 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+B878 ENCODING 47224 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4070 3F40 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B87C ENCODING 47228 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4070 3E40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B88D ENCODING 47245 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4070 3E40 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+B8A8 ENCODING 47272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7CE0 40A0 3CA0 10A0 7EA0 0000 0880 1540 2220 ENDCHAR STARTCHAR U+B8B0 ENCODING 47280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+B8B4 ENCODING 47284 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+B8B8 ENCODING 47288 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B8C0 ENCODING 47296 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7F40 0000 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B8C1 ENCODING 47297 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7F40 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B8C3 ENCODING 47299 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7F40 0000 0100 0680 3860 ENDCHAR STARTCHAR U+B8C5 ENCODING 47301 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+B8CC ENCODING 47308 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 7FC0 4000 4000 3FC0 1100 1100 FFC0 ENDCHAR STARTCHAR U+B8D0 ENCODING 47312 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 1100 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B8D4 ENCODING 47316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 1100 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B8DD ENCODING 47325 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 1100 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B8DF ENCODING 47327 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 1100 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+B8E1 ENCODING 47329 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 1100 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+B8E8 ENCODING 47336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+B8E9 ENCODING 47337 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 7FC0 0040 0040 ENDCHAR STARTCHAR U+B8EC ENCODING 47340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 4400 4000 3FC0 ENDCHAR STARTCHAR U+B8F0 ENCODING 47344 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B8F8 ENCODING 47352 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B8F9 ENCODING 47353 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 4440 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B8FB ENCODING 47355 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 0200 0D00 70C0 ENDCHAR STARTCHAR U+B8FD ENCODING 47357 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0400 3F80 4040 3F80 ENDCHAR STARTCHAR U+B904 ENCODING 47364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+B918 ENCODING 47384 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7CC0 4040 3C40 0040 7F40 0840 0880 1540 2220 ENDCHAR STARTCHAR U+B920 ENCODING 47392 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 F9 81 79 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+B93C ENCODING 47420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+B93D ENCODING 47421 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3C40 0040 7FC0 0840 3FC0 0040 0040 ENDCHAR STARTCHAR U+B940 ENCODING 47424 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3C40 0040 7FC0 0840 2840 2000 1FC0 ENDCHAR STARTCHAR U+B944 ENCODING 47428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3FC0 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B94C ENCODING 47436 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3C40 0040 7FC0 0840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B94F ENCODING 47439 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3C40 0040 7FC0 0840 0100 0680 3860 ENDCHAR STARTCHAR U+B951 ENCODING 47441 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 4040 3C40 0040 7FC0 0840 1F80 2040 1F80 ENDCHAR STARTCHAR U+B958 ENCODING 47448 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+B959 ENCODING 47449 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 7FC0 0040 0040 ENDCHAR STARTCHAR U+B95C ENCODING 47452 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 5100 4000 3FC0 ENDCHAR STARTCHAR U+B960 ENCODING 47456 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B968 ENCODING 47464 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B969 ENCODING 47465 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 5140 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B96B ENCODING 47467 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 0200 0D00 70C0 ENDCHAR STARTCHAR U+B96D ENCODING 47469 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 1100 3F80 4040 3F80 ENDCHAR STARTCHAR U+B974 ENCODING 47476 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 7FC0 4000 4000 3FC0 0000 0000 FFC0 ENDCHAR STARTCHAR U+B975 ENCODING 47477 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+B978 ENCODING 47480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+B97C ENCODING 47484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+B984 ENCODING 47492 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B985 ENCODING 47493 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+B987 ENCODING 47495 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+B989 ENCODING 47497 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+B98A ENCODING 47498 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 7FC0 0A00 71C0 ENDCHAR STARTCHAR U+B98D ENCODING 47501 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+B98E ENCODING 47502 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 4000 3FC0 0000 FFE0 0000 7FC0 1100 7FC0 ENDCHAR STARTCHAR U+B9AC ENCODING 47532 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+B9AD ENCODING 47533 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B9B0 ENCODING 47536 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B9B4 ENCODING 47540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B9BC ENCODING 47548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B9BD ENCODING 47549 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B9BF ENCODING 47551 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B9C1 ENCODING 47553 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B9C8 ENCODING 47560 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 4270 4240 4240 4240 3E40 0040 0040 ENDCHAR STARTCHAR U+B9C9 ENCODING 47561 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+B9CC ENCODING 47564 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4270 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+B9CE ENCODING 47566 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+B9CF ENCODING 47567 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+B9D0 ENCODING 47568 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B9D1 ENCODING 47569 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+B9D2 ENCODING 47570 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+B9D8 ENCODING 47576 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+B9D9 ENCODING 47577 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+B9DB ENCODING 47579 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+B9DD ENCODING 47581 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+B9DE ENCODING 47582 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+B9E1 ENCODING 47585 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+B9E3 ENCODING 47587 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 3E40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+B9E4 ENCODING 47588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 4520 4520 4520 45E0 4520 4520 3D20 0120 0120 ENDCHAR STARTCHAR U+B9E5 ENCODING 47589 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 8A00 8B80 8A00 7A00 0200 0000 3F80 ENDCHAR STARTCHAR U+B9E8 ENCODING 47592 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+B9EC ENCODING 47596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+B9F4 ENCODING 47604 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+B9F5 ENCODING 47605 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+B9F7 ENCODING 47607 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+B9F8 ENCODING 47608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+B9F9 ENCODING 47609 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+B9FA ENCODING 47610 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4520 45E0 4520 3D20 0120 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BA00 ENCODING 47616 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4270 4240 4240 4240 4270 4240 3E40 0040 0040 ENDCHAR STARTCHAR U+BA01 ENCODING 47617 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4270 4240 4270 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BA08 ENCODING 47624 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4270 4240 4270 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BA15 ENCODING 47637 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4270 4240 4270 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BA38 ENCODING 47672 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 43C0 4240 4240 4240 4240 3E40 0040 0040 ENDCHAR STARTCHAR U+BA39 ENCODING 47673 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BA3C ENCODING 47676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BA40 ENCODING 47680 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BA42 ENCODING 47682 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BA48 ENCODING 47688 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BA49 ENCODING 47689 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BA4B ENCODING 47691 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BA4D ENCODING 47693 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BA4E ENCODING 47694 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BA53 ENCODING 47699 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 3E40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+BA54 ENCODING 47700 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 89 89 89 8F 89 89 89 79 01 01 ENDCHAR STARTCHAR U+BA55 ENCODING 47701 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 8900 8F00 8900 7900 0100 0000 3F80 ENDCHAR STARTCHAR U+BA58 ENCODING 47704 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+BA5C ENCODING 47708 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+BA64 ENCODING 47716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+BA65 ENCODING 47717 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+BA67 ENCODING 47719 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+BA68 ENCODING 47720 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+BA69 ENCODING 47721 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 44A0 47A0 44A0 3CA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+BA70 ENCODING 47728 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 43C0 4240 4240 43C0 4240 4240 3E40 0040 0040 ENDCHAR STARTCHAR U+BA71 ENCODING 47729 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BA74 ENCODING 47732 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BA78 ENCODING 47736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BA83 ENCODING 47747 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BA84 ENCODING 47748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BA85 ENCODING 47749 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BA87 ENCODING 47751 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 43C0 4240 43C0 3E40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BA8C ENCODING 47756 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 89 8F 89 89 8F 89 89 79 01 01 ENDCHAR STARTCHAR U+BAA8 ENCODING 47784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4040 4040 4040 4040 3FC0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+BAA9 ENCODING 47785 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BAAB ENCODING 47787 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 7880 0880 0940 0A20 ENDCHAR STARTCHAR U+BAAC ENCODING 47788 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BAB0 ENCODING 47792 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BAB2 ENCODING 47794 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+BAB8 ENCODING 47800 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BAB9 ENCODING 47801 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BABB ENCODING 47803 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BABD ENCODING 47805 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BAC4 ENCODING 47812 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+BAC8 ENCODING 47816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E70 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BAD8 ENCODING 47832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E70 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BAD9 ENCODING 47833 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E70 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BAFC ENCODING 47868 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+BB00 ENCODING 47872 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+BB04 ENCODING 47876 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 3E40 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BB0D ENCODING 47885 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E40 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BB0F ENCODING 47887 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E40 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BB11 ENCODING 47889 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 3E40 0840 7F40 0040 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BB18 ENCODING 47896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4040 4040 4040 4040 3FC0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+BB1C ENCODING 47900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BB20 ENCODING 47904 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BB29 ENCODING 47913 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 1100 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BB2B ENCODING 47915 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 1100 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BB34 ENCODING 47924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 4040 3FC0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+BB35 ENCODING 47925 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BB36 ENCODING 47926 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 7FC0 0440 0440 0440 ENDCHAR STARTCHAR U+BB38 ENCODING 47928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+BB3B ENCODING 47931 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+BB3C ENCODING 47932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BB3D ENCODING 47933 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0400 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+BB3E ENCODING 47934 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+BB44 ENCODING 47940 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BB45 ENCODING 47941 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BB47 ENCODING 47943 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BB49 ENCODING 47945 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BB4D ENCODING 47949 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+BB4F ENCODING 47951 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0400 0E00 0000 FFE0 2080 1F00 ENDCHAR STARTCHAR U+BB50 ENCODING 47952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+BB54 ENCODING 47956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 44C0 3C40 0040 7F40 0840 2800 2000 2000 1FC0 ENDCHAR STARTCHAR U+BB58 ENCODING 47960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 3CC0 0040 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BB61 ENCODING 47969 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 44C0 3C40 0040 7F40 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BB63 ENCODING 47971 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 44C0 3C40 0040 7F40 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BB6C ENCODING 47980 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 89 89 79 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+BB88 ENCODING 48008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+BB8C ENCODING 48012 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 4440 3C40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+BB90 ENCODING 48016 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4440 3C40 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BBA4 ENCODING 48036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 4040 3FC0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+BBA8 ENCODING 48040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+BBAC ENCODING 48044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BBB4 ENCODING 48052 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BBB7 ENCODING 48055 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 1100 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BBC0 ENCODING 48064 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4040 4040 4040 4040 3FC0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+BBC4 ENCODING 48068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BBC8 ENCODING 48072 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 3FC0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BBD0 ENCODING 48080 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BBD3 ENCODING 48083 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4040 4040 3FC0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BBF8 ENCODING 48120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 4240 4240 4240 4240 3E40 0040 0040 ENDCHAR STARTCHAR U+BBF9 ENCODING 48121 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BBFC ENCODING 48124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BBFF ENCODING 48127 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC00 ENCODING 48128 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BC02 ENCODING 48130 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BC08 ENCODING 48136 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BC09 ENCODING 48137 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BC0B ENCODING 48139 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+BC0C ENCODING 48140 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BC0D ENCODING 48141 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BC0F ENCODING 48143 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BC11 ENCODING 48145 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4240 4240 4240 3E40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BC14 ENCODING 48148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 4240 7E40 4270 4240 4240 3E40 0040 0040 0040 ENDCHAR STARTCHAR U+BC15 ENCODING 48149 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BC16 ENCODING 48150 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+BC17 ENCODING 48151 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 3C80 0480 0540 0220 ENDCHAR STARTCHAR U+BC18 ENCODING 48152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4270 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC1B ENCODING 48155 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC1C ENCODING 48156 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BC1D ENCODING 48157 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+BC1E ENCODING 48158 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BC1F ENCODING 48159 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 3A40 0A40 3BC0 2240 1FC0 ENDCHAR STARTCHAR U+BC24 ENCODING 48164 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BC25 ENCODING 48165 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BC27 ENCODING 48167 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+BC29 ENCODING 48169 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BC2D ENCODING 48173 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E70 4240 3E40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BC30 ENCODING 48176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 4520 7D20 4520 45E0 4520 3D20 0120 0120 0120 ENDCHAR STARTCHAR U+BC31 ENCODING 48177 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 8A00 8A00 FB80 8A00 7A00 0200 0000 3F80 ENDCHAR STARTCHAR U+BC34 ENCODING 48180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+BC38 ENCODING 48184 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+BC40 ENCODING 48192 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+BC41 ENCODING 48193 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+BC43 ENCODING 48195 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+BC44 ENCODING 48196 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+BC45 ENCODING 48197 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+BC49 ENCODING 48201 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4520 4520 7DE0 4520 3D20 0120 3FE0 2000 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+BC4C ENCODING 48204 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 4270 7E40 4240 4240 4270 3E40 0040 0040 0040 ENDCHAR STARTCHAR U+BC4D ENCODING 48205 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4270 7E40 4270 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BC50 ENCODING 48208 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4270 7E40 4270 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC5D ENCODING 48221 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4270 7E40 4270 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BC84 ENCODING 48260 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 4240 7FC0 4240 4240 4240 3E40 0040 0040 0040 ENDCHAR STARTCHAR U+BC85 ENCODING 48261 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BC88 ENCODING 48264 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC8B ENCODING 48267 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+BC8C ENCODING 48268 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BC8E ENCODING 48270 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BC94 ENCODING 48276 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BC95 ENCODING 48277 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BC97 ENCODING 48279 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BC99 ENCODING 48281 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BC9A ENCODING 48282 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7FC0 4240 3E40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BCA0 ENCODING 48288 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 89 89 89 F9 8F 89 89 79 01 01 01 ENDCHAR STARTCHAR U+BCA1 ENCODING 48289 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 8900 8900 FF00 8900 7900 0100 0000 3F80 ENDCHAR STARTCHAR U+BCA4 ENCODING 48292 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+BCA7 ENCODING 48295 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 3FE0 2000 2000 1FE0 ENDCHAR STARTCHAR U+BCA8 ENCODING 48296 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+BCB0 ENCODING 48304 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+BCB1 ENCODING 48305 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+BCB3 ENCODING 48307 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+BCB4 ENCODING 48308 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+BCB5 ENCODING 48309 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 44A0 7FA0 44A0 3CA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+BCBC ENCODING 48316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 43C0 7E40 4240 43C0 4240 3E40 0040 0040 0040 ENDCHAR STARTCHAR U+BCBD ENCODING 48317 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BCC0 ENCODING 48320 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BCC4 ENCODING 48324 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BCCD ENCODING 48333 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BCCF ENCODING 48335 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BCD0 ENCODING 48336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BCD1 ENCODING 48337 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BCD5 ENCODING 48341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 43C0 7E40 43C0 3E40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BCD8 ENCODING 48344 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 89 89 8F F9 89 8F 89 79 01 01 01 ENDCHAR STARTCHAR U+BCDC ENCODING 48348 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 47A0 7CA0 47A0 3CA0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+BCF4 ENCODING 48372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4040 4040 7FC0 4040 4040 3FC0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+BCF5 ENCODING 48373 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BCF6 ENCODING 48374 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 7FC0 0440 0440 0440 ENDCHAR STARTCHAR U+BCF8 ENCODING 48376 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BCFC ENCODING 48380 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 3F80 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BD04 ENCODING 48388 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BD05 ENCODING 48389 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BD07 ENCODING 48391 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BD09 ENCODING 48393 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BD10 ENCODING 48400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+BD14 ENCODING 48404 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E70 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BD24 ENCODING 48420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E70 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BD2C ENCODING 48428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 42A0 42A0 7EA0 42A0 3EE0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+BD40 ENCODING 48448 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 44A0 7CA0 44E0 3CA0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BD48 ENCODING 48456 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+BD49 ENCODING 48457 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E40 0840 7F40 0040 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BD4C ENCODING 48460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+BD50 ENCODING 48464 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 3C40 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BD58 ENCODING 48472 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E40 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BD59 ENCODING 48473 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 3E40 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BD64 ENCODING 48484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4040 4040 7FC0 4040 4040 3FC0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+BD68 ENCODING 48488 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BD80 ENCODING 48512 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 4040 3FC0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+BD81 ENCODING 48513 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BD84 ENCODING 48516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+BD87 ENCODING 48519 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+BD88 ENCODING 48520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3F80 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BD89 ENCODING 48521 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3F80 FFE0 0400 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+BD8A ENCODING 48522 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3F80 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+BD90 ENCODING 48528 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BD91 ENCODING 48529 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BD93 ENCODING 48531 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BD95 ENCODING 48533 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BD99 ENCODING 48537 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3F80 FFE0 0400 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+BD9A ENCODING 48538 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0400 7FC0 1100 1100 7FC0 ENDCHAR STARTCHAR U+BD9C ENCODING 48540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 4240 3E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+BDA4 ENCODING 48548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 44C0 3840 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BDB0 ENCODING 48560 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 44C0 3C40 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BDB8 ENCODING 48568 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 89 F9 89 79 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+BDD4 ENCODING 48596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 7E40 4240 4240 3E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+BDD5 ENCODING 48597 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 4440 3C40 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BDD8 ENCODING 48600 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 4440 3C40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+BDDC ENCODING 48604 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 4440 3840 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BDE9 ENCODING 48617 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4440 7C40 4440 3C40 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BDF0 ENCODING 48624 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 4040 3FC0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+BDF4 ENCODING 48628 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+BDF8 ENCODING 48632 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3F80 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BE00 ENCODING 48640 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BE03 ENCODING 48643 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 1100 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BE05 ENCODING 48645 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BE0C ENCODING 48652 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4040 4040 7FC0 4040 4040 3FC0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+BE0D ENCODING 48653 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BE10 ENCODING 48656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BE14 ENCODING 48660 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 3F80 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BE1C ENCODING 48668 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BE1D ENCODING 48669 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BE1F ENCODING 48671 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4040 7FC0 4040 3FC0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BE44 ENCODING 48708 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 4240 7E40 4240 4240 4240 3E40 0040 0040 0040 ENDCHAR STARTCHAR U+BE45 ENCODING 48709 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BE48 ENCODING 48712 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BE4C ENCODING 48716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BE4E ENCODING 48718 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BE54 ENCODING 48724 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BE55 ENCODING 48725 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BE57 ENCODING 48727 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+BE59 ENCODING 48729 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BE5A ENCODING 48730 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BE5B ENCODING 48731 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4240 4240 7E40 4240 3E40 0040 0100 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+BE60 ENCODING 48736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5570 5540 5540 3340 0040 0040 0040 ENDCHAR STARTCHAR U+BE61 ENCODING 48737 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BE64 ENCODING 48740 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5570 5540 3340 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BE68 ENCODING 48744 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 3340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BE6A ENCODING 48746 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 3340 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+BE70 ENCODING 48752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BE71 ENCODING 48753 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BE73 ENCODING 48755 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+BE74 ENCODING 48756 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BE75 ENCODING 48757 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 3340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BE7B ENCODING 48763 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 3340 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+BE7C ENCODING 48764 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP A920 A920 F920 A920 A920 A9E0 A920 F920 0120 0120 0120 ENDCHAR STARTCHAR U+BE7D ENCODING 48765 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP AA00 AA00 FB80 AA00 7A00 0200 0000 3F80 ENDCHAR STARTCHAR U+BE80 ENCODING 48768 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+BE84 ENCODING 48772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+BE8C ENCODING 48780 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+BE8D ENCODING 48781 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+BE8F ENCODING 48783 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+BE90 ENCODING 48784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+BE91 ENCODING 48785 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5520 5520 7DE0 5520 3D20 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+BE98 ENCODING 48792 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7770 5540 5540 5540 5570 3340 0040 0040 0040 ENDCHAR STARTCHAR U+BE99 ENCODING 48793 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5570 7740 5570 5540 3340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BEA8 ENCODING 48808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5570 7740 5570 5540 3340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BED0 ENCODING 48848 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 55C0 5540 5540 5540 3340 0040 0040 0040 ENDCHAR STARTCHAR U+BED1 ENCODING 48849 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BED4 ENCODING 48852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+BED7 ENCODING 48855 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+BED8 ENCODING 48856 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 3340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+BEE0 ENCODING 48864 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BEE3 ENCODING 48867 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BEE4 ENCODING 48868 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BEE5 ENCODING 48869 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 3340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BEEC ENCODING 48876 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP A8A0 A8A0 F8A0 A8A0 ABA0 A8A0 A8A0 F8A0 00A0 00A0 00A0 ENDCHAR STARTCHAR U+BF01 ENCODING 48897 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 54A0 54A0 7FA0 54A0 3CA0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+BF08 ENCODING 48904 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 77C0 5540 5540 55C0 5540 3340 0040 0040 0040 ENDCHAR STARTCHAR U+BF09 ENCODING 48905 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BF18 ENCODING 48920 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+BF19 ENCODING 48921 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+BF1B ENCODING 48923 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+BF1C ENCODING 48924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+BF1D ENCODING 48925 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 55C0 7740 55C0 5540 3340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+BF40 ENCODING 48960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4A40 4A40 7BC0 4A40 4A40 39C0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+BF41 ENCODING 48961 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 3BC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BF44 ENCODING 48964 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+BF48 ENCODING 48968 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 3180 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BF50 ENCODING 48976 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 3BC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BF51 ENCODING 48977 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 3BC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+BF55 ENCODING 48981 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 3BC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BF94 ENCODING 49044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3740 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+BFB0 ENCODING 49072 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4A40 4A40 7BC0 4A40 4A40 39C0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+BFC5 ENCODING 49093 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+BFCC ENCODING 49100 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 4A40 39C0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+BFCD ENCODING 49101 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+BFD0 ENCODING 49104 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+BFD4 ENCODING 49108 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 3180 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+BFDC ENCODING 49116 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+BFDF ENCODING 49119 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+BFE1 ENCODING 49121 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C03C ENCODING 49212 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 4A40 39C0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+C051 ENCODING 49233 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C058 ENCODING 49240 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 4A40 4A40 7BC0 4A40 4A40 39C0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+C05C ENCODING 49244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C060 ENCODING 49248 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 3180 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C068 ENCODING 49256 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C069 ENCODING 49257 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 4A40 7BC0 4A40 39C0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C090 ENCODING 49296 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 5540 5540 3340 0040 0040 0040 ENDCHAR STARTCHAR U+C091 ENCODING 49297 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C094 ENCODING 49300 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C098 ENCODING 49304 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 3340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C0A0 ENCODING 49312 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C0A1 ENCODING 49313 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C0A3 ENCODING 49315 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C0A5 ENCODING 49317 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 5540 5540 7740 5540 5540 3340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C0AC ENCODING 49324 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 0840 1470 1440 2240 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C0AD ENCODING 49325 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C0AF ENCODING 49327 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 3C80 0480 0540 0220 ENDCHAR STARTCHAR U+C0B0 ENCODING 49328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1470 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C0B3 ENCODING 49331 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C0B4 ENCODING 49332 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1470 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C0B5 ENCODING 49333 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1470 2240 4140 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+C0B6 ENCODING 49334 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1470 2240 4140 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C0BC ENCODING 49340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C0BD ENCODING 49341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C0BF ENCODING 49343 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C0C0 ENCODING 49344 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C0C1 ENCODING 49345 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C0C5 ENCODING 49349 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1470 2240 4140 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C0C8 ENCODING 49352 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 1120 1120 2920 29E0 4520 4520 8320 0120 0120 ENDCHAR STARTCHAR U+C0C9 ENCODING 49353 SWIDTH 935 0 DWIDTH 12 0 BBX 10 8 0 1 BITMAP 1100 1100 19C0 2500 4300 8100 0000 1FC0 ENDCHAR STARTCHAR U+C0CC ENCODING 49356 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C0D0 ENCODING 49360 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0920 0920 15E0 2320 4120 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C0D8 ENCODING 49368 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C0D9 ENCODING 49369 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C0DB ENCODING 49371 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C0DC ENCODING 49372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C0DD ENCODING 49373 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C0E4 ENCODING 49380 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0870 0840 1440 1440 2270 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C0E5 ENCODING 49381 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C0E8 ENCODING 49384 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C0EC ENCODING 49388 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 1440 2270 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C0F4 ENCODING 49396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C0F5 ENCODING 49397 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C0F7 ENCODING 49399 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C0F9 ENCODING 49401 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0870 0840 1470 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C100 ENCODING 49408 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 11E0 1120 2920 2920 45E0 4520 8320 0120 0120 ENDCHAR STARTCHAR U+C104 ENCODING 49412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C108 ENCODING 49416 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0920 0920 15E0 2320 4120 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C110 ENCODING 49424 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C115 ENCODING 49429 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 1120 19E0 2520 4320 8120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C11C ENCODING 49436 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 09C0 1440 1440 2240 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C11D ENCODING 49437 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C11E ENCODING 49438 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+C11F ENCODING 49439 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3C80 0480 0540 0220 ENDCHAR STARTCHAR U+C120 ENCODING 49440 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C123 ENCODING 49443 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C124 ENCODING 49444 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 15C0 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C126 ENCODING 49446 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 15C0 2240 4140 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C127 ENCODING 49447 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 15C0 2240 4140 0040 3D40 0540 3DC0 2140 1FC0 ENDCHAR STARTCHAR U+C12C ENCODING 49452 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C12D ENCODING 49453 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C12F ENCODING 49455 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C130 ENCODING 49456 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C131 ENCODING 49457 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C136 ENCODING 49462 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 1440 2240 4140 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C138 ENCODING 49464 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 10A0 10A0 2BA0 28A0 44A0 44A0 82A0 00A0 00A0 ENDCHAR STARTCHAR U+C139 ENCODING 49465 SWIDTH 935 0 DWIDTH 12 0 BBX 10 8 0 1 BITMAP 1080 1080 1B80 2480 4280 8080 0000 1FC0 ENDCHAR STARTCHAR U+C13C ENCODING 49468 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C140 ENCODING 49472 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 08A0 08A0 17A0 22A0 42A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C148 ENCODING 49480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C149 ENCODING 49481 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C14B ENCODING 49483 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C14C ENCODING 49484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C14D ENCODING 49485 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 1BA0 24A0 42A0 80A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C154 ENCODING 49492 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 09C0 0840 1440 15C0 2240 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C155 ENCODING 49493 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C158 ENCODING 49496 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C15C ENCODING 49500 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 1440 23C0 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C164 ENCODING 49508 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C165 ENCODING 49509 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C167 ENCODING 49511 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C168 ENCODING 49512 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C169 ENCODING 49513 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 09C0 0840 15C0 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C170 ENCODING 49520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 13A0 10A0 28A0 2BA0 44A0 44A0 82A0 00A0 00A0 ENDCHAR STARTCHAR U+C174 ENCODING 49524 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 13A0 18A0 27A0 42A0 80A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C178 ENCODING 49528 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 08A0 0BA0 14A0 23A0 42A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C185 ENCODING 49541 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 13A0 18A0 27A0 42A0 80A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C18C ENCODING 49548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 0400 0400 0400 0A00 3180 C040 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+C18D ENCODING 49549 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C18E ENCODING 49550 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 7FC0 0440 0440 0440 ENDCHAR STARTCHAR U+C190 ENCODING 49552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C194 ENCODING 49556 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C196 ENCODING 49558 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C19C ENCODING 49564 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C19D ENCODING 49565 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C19F ENCODING 49567 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C1A1 ENCODING 49569 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C1A5 ENCODING 49573 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0400 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+C1A8 ENCODING 49576 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 1440 2270 4140 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C1A9 ENCODING 49577 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4170 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C1AC ENCODING 49580 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4170 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C1B0 ENCODING 49584 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 6340 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C1BD ENCODING 49597 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4170 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C1C4 ENCODING 49604 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 08A0 08A0 08A0 14A0 24E0 42A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+C1C8 ENCODING 49608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 28E0 44A0 10A0 7EA0 00A0 2020 2000 2000 1FE0 ENDCHAR STARTCHAR U+C1CC ENCODING 49612 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 28A0 44E0 10A0 7EA0 0000 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C1D4 ENCODING 49620 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 28E0 44A0 10A0 7EA0 00A0 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C1D7 ENCODING 49623 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 28E0 44A0 10A0 7EA0 00A0 0100 0100 0680 3860 ENDCHAR STARTCHAR U+C1D8 ENCODING 49624 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 28E0 44A0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C1E0 ENCODING 49632 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 1440 2240 4140 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C1E4 ENCODING 49636 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4140 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+C1E8 ENCODING 49640 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 6340 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C1F0 ENCODING 49648 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4140 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C1F1 ENCODING 49649 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4140 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C1F3 ENCODING 49651 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 1440 2240 4140 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C1FC ENCODING 49660 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 0400 0400 0400 0A00 3180 C040 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+C1FD ENCODING 49661 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 1100 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C200 ENCODING 49664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C204 ENCODING 49668 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C20C ENCODING 49676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 1100 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C20D ENCODING 49677 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 1100 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C20F ENCODING 49679 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 1100 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C211 ENCODING 49681 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C218 ENCODING 49688 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 2080 C060 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+C219 ENCODING 49689 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C21C ENCODING 49692 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+C21F ENCODING 49695 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+C220 ENCODING 49696 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C228 ENCODING 49704 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C229 ENCODING 49705 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C22B ENCODING 49707 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C22D ENCODING 49709 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C22F ENCODING 49711 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 0400 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+C231 ENCODING 49713 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 0400 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+C232 ENCODING 49714 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 0400 7FC0 1100 1100 7FC0 ENDCHAR STARTCHAR U+C234 ENCODING 49716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 6340 0040 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+C248 ENCODING 49736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 28C0 4440 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C250 ENCODING 49744 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 21 21 51 89 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+C251 ENCODING 49745 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 2100 2100 5300 8900 0100 FD00 2100 1F80 ENDCHAR STARTCHAR U+C254 ENCODING 49748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 29A0 44A0 00A0 7EA0 08A0 2800 2000 2000 1FE0 ENDCHAR STARTCHAR U+C258 ENCODING 49752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 28A0 45A0 00A0 00A0 7EA0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C260 ENCODING 49760 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 29A0 44A0 00A0 7EA0 10A0 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C265 ENCODING 49765 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 10A0 29A0 44A0 00A0 7EA0 10A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C26C ENCODING 49772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 6340 0040 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+C26D ENCODING 49773 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C270 ENCODING 49776 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+C274 ENCODING 49780 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 2840 4440 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C27C ENCODING 49788 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C27D ENCODING 49789 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C27F ENCODING 49791 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C281 ENCODING 49793 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 1040 2840 4440 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C288 ENCODING 49800 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 2080 C060 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+C289 ENCODING 49801 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 1100 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C290 ENCODING 49808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C298 ENCODING 49816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C29B ENCODING 49819 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 1100 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C29D ENCODING 49821 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0400 1B00 60C0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C2A4 ENCODING 49828 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 0400 0400 0400 0A00 3180 C040 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+C2A5 ENCODING 49829 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C2A8 ENCODING 49832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C2AC ENCODING 49836 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C2AD ENCODING 49837 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 1B00 60C0 0000 FFE0 0000 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+C2B4 ENCODING 49844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C2B5 ENCODING 49845 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C2B7 ENCODING 49847 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C2B9 ENCODING 49849 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 0A00 1100 60C0 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C2DC ENCODING 49884 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 0840 1440 1440 2240 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C2DD ENCODING 49885 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C2E0 ENCODING 49888 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C2E3 ENCODING 49891 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C2E4 ENCODING 49892 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C2EB ENCODING 49899 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 1440 2240 4140 0040 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+C2EC ENCODING 49900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C2ED ENCODING 49901 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C2EF ENCODING 49903 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C2F1 ENCODING 49905 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C2F6 ENCODING 49910 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 0840 0840 1440 2240 4140 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C2F8 ENCODING 49912 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 2240 2270 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+C2F9 ENCODING 49913 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C2FB ENCODING 49915 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 3C80 0480 0540 0220 ENDCHAR STARTCHAR U+C2FC ENCODING 49916 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5570 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C300 ENCODING 49920 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 5570 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C308 ENCODING 49928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C309 ENCODING 49929 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C30C ENCODING 49932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C30D ENCODING 49933 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2270 5540 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C313 ENCODING 49939 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 5570 5540 8940 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+C314 ENCODING 49940 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2920 2920 2920 2920 2920 55E0 5520 9520 2320 0120 0120 ENDCHAR STARTCHAR U+C315 ENCODING 49941 SWIDTH 935 0 DWIDTH 12 0 BBX 10 8 0 1 BITMAP 2500 2500 25C0 5B00 9100 0100 0000 1FC0 ENDCHAR STARTCHAR U+C318 ENCODING 49944 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C31C ENCODING 49948 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C324 ENCODING 49956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C325 ENCODING 49957 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C328 ENCODING 49960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C329 ENCODING 49961 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2520 2520 25E0 5B20 9120 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C345 ENCODING 49989 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2270 2240 5570 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C368 ENCODING 50024 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 23C0 2240 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+C369 ENCODING 50025 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C36C ENCODING 50028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C370 ENCODING 50032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 55C0 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C372 ENCODING 50034 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 55C0 5540 8940 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C378 ENCODING 50040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C379 ENCODING 50041 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C37C ENCODING 50044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C37D ENCODING 50045 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 23C0 5540 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C384 ENCODING 50052 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 28A0 28A0 28A0 28A0 2BA0 54A0 54A0 94A0 22A0 00A0 00A0 ENDCHAR STARTCHAR U+C388 ENCODING 50056 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 24A0 24A0 27A0 5AA0 92A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C38C ENCODING 50060 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 24A0 24A0 27A0 5AA0 92A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C3C0 ENCODING 50112 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 24A0 27A0 24A0 5BA0 92A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C3D8 ENCODING 50136 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1080 1080 1080 3180 4A40 8400 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+C3D9 ENCODING 50137 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C3DC ENCODING 50140 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C3DF ENCODING 50143 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0400 FFE0 0000 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+C3E0 ENCODING 50144 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C3E2 ENCODING 50146 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C3E8 ENCODING 50152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C3E9 ENCODING 50153 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C3ED ENCODING 50157 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C3F4 ENCODING 50164 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5570 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C3F5 ENCODING 50165 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4970 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C3F8 ENCODING 50168 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4970 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C408 ENCODING 50184 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4970 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C410 ENCODING 50192 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 14A0 14A0 14A0 2AA0 52E0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+C424 ENCODING 50212 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 14A0 14A0 2CE0 52A0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C42C ENCODING 50220 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C430 ENCODING 50224 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4940 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+C434 ENCODING 50228 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 3640 4940 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C43C ENCODING 50236 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4940 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C43D ENCODING 50237 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4940 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C448 ENCODING 50248 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1080 1080 1080 3180 4A40 8400 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+C464 ENCODING 50276 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 2080 5140 8A20 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+C465 ENCODING 50277 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C468 ENCODING 50280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+C46C ENCODING 50284 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C474 ENCODING 50292 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C475 ENCODING 50293 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C479 ENCODING 50297 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C480 ENCODING 50304 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+C494 ENCODING 50324 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2840 2840 54C0 5440 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C49C ENCODING 50332 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 51 51 A9 A9 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+C4B8 ENCODING 50360 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+C4BC ENCODING 50364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2840 2840 5440 5440 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+C4E9 ENCODING 50409 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C4F0 ENCODING 50416 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1080 1080 1080 3180 4A40 8400 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+C4F1 ENCODING 50417 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C4F4 ENCODING 50420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C4F8 ENCODING 50424 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C4FA ENCODING 50426 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0000 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C4FF ENCODING 50431 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 5140 8A20 0000 FFE0 0000 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+C500 ENCODING 50432 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C501 ENCODING 50433 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2080 2080 5140 8A20 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C50C ENCODING 50444 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 0040 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+C510 ENCODING 50448 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4940 0040 7FC0 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C514 ENCODING 50452 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 3640 4940 0040 7FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C51C ENCODING 50460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1240 1240 2D40 4940 0040 7FC0 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C528 ENCODING 50472 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 2240 2240 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+C529 ENCODING 50473 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C52C ENCODING 50476 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C530 ENCODING 50480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 5540 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C538 ENCODING 50488 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C539 ENCODING 50489 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C53B ENCODING 50491 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C53D ENCODING 50493 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 2240 2240 2240 5540 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C544 ENCODING 50500 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 4270 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+C545 ENCODING 50501 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C548 ENCODING 50504 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4270 3C40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C549 ENCODING 50505 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 27C0 2100 2280 1C60 ENDCHAR STARTCHAR U+C54A ENCODING 50506 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+C54C ENCODING 50508 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C54D ENCODING 50509 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+C54E ENCODING 50510 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C553 ENCODING 50515 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+C554 ENCODING 50516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C555 ENCODING 50517 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C557 ENCODING 50519 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C558 ENCODING 50520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C559 ENCODING 50521 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C55D ENCODING 50525 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C55E ENCODING 50526 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 3C40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C560 ENCODING 50528 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 4520 4520 4520 45E0 4520 4520 3920 0120 0120 ENDCHAR STARTCHAR U+C561 ENCODING 50529 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 7200 8A00 8B80 8A00 7200 0200 0000 3F80 ENDCHAR STARTCHAR U+C564 ENCODING 50532 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C568 ENCODING 50536 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C570 ENCODING 50544 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C571 ENCODING 50545 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C573 ENCODING 50547 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C574 ENCODING 50548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C575 ENCODING 50549 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C57C ENCODING 50556 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4270 4240 4240 4240 4270 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+C57D ENCODING 50557 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C580 ENCODING 50560 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C584 ENCODING 50564 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C587 ENCODING 50567 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 3A40 0A40 3BC0 2240 1FC0 ENDCHAR STARTCHAR U+C58C ENCODING 50572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C58D ENCODING 50573 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C58F ENCODING 50575 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C591 ENCODING 50577 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C595 ENCODING 50581 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C597 ENCODING 50583 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4270 4240 4270 3C40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+C598 ENCODING 50584 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 4520 4520 45E0 4520 3920 0120 0120 ENDCHAR STARTCHAR U+C59C ENCODING 50588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C5A0 ENCODING 50592 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C5A9 ENCODING 50601 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 4520 45E0 4520 3920 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C5B4 ENCODING 50612 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 43C0 4240 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+C5B5 ENCODING 50613 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C5B8 ENCODING 50616 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C5B9 ENCODING 50617 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 27C0 2100 2280 1C60 ENDCHAR STARTCHAR U+C5BB ENCODING 50619 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C5BC ENCODING 50620 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C5BD ENCODING 50621 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+C5BE ENCODING 50622 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C5C4 ENCODING 50628 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C5C5 ENCODING 50629 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C5C6 ENCODING 50630 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 2480 3C80 2540 1E20 ENDCHAR STARTCHAR U+C5C7 ENCODING 50631 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C5C8 ENCODING 50632 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C5C9 ENCODING 50633 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C5CA ENCODING 50634 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+C5CC ENCODING 50636 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FC0 0040 3FC0 0040 ENDCHAR STARTCHAR U+C5CE ENCODING 50638 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 3C40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C5D0 ENCODING 50640 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 71 89 89 89 8F 89 89 89 71 01 01 ENDCHAR STARTCHAR U+C5D1 ENCODING 50641 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 7100 8900 8F00 8900 7100 0100 0000 3F80 ENDCHAR STARTCHAR U+C5D4 ENCODING 50644 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C5D8 ENCODING 50648 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C5E0 ENCODING 50656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C5E1 ENCODING 50657 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C5E3 ENCODING 50659 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C5E5 ENCODING 50661 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 47A0 44A0 38A0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C5EC ENCODING 50668 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 43C0 4240 4240 43C0 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+C5ED ENCODING 50669 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C5EE ENCODING 50670 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+C5F0 ENCODING 50672 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C5F4 ENCODING 50676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C5F6 ENCODING 50678 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C5F7 ENCODING 50679 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 3D40 0540 3DC0 2140 1FC0 ENDCHAR STARTCHAR U+C5FC ENCODING 50684 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C5FD ENCODING 50685 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C5FE ENCODING 50686 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 2480 3C80 2540 1E20 ENDCHAR STARTCHAR U+C5FF ENCODING 50687 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C600 ENCODING 50688 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C601 ENCODING 50689 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C605 ENCODING 50693 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C606 ENCODING 50694 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C607 ENCODING 50695 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 43C0 4240 43C0 3C40 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+C608 ENCODING 50696 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 71 89 8F 89 89 8F 89 89 71 01 01 ENDCHAR STARTCHAR U+C60C ENCODING 50700 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C610 ENCODING 50704 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C618 ENCODING 50712 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C619 ENCODING 50713 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C61B ENCODING 50715 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C61C ENCODING 50716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 47A0 44A0 47A0 38A0 00A0 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C624 ENCODING 50724 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 2080 4040 4040 2080 1F00 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+C625 ENCODING 50725 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C628 ENCODING 50728 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C62C ENCODING 50732 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C62D ENCODING 50733 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+C62E ENCODING 50734 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C630 ENCODING 50736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 7900 0900 7A80 4440 3820 ENDCHAR STARTCHAR U+C633 ENCODING 50739 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+C634 ENCODING 50740 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C635 ENCODING 50741 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C637 ENCODING 50743 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C639 ENCODING 50745 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C63B ENCODING 50747 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0400 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+C640 ENCODING 50752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C641 ENCODING 50753 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C644 ENCODING 50756 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C648 ENCODING 50760 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 3C40 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C650 ENCODING 50768 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C651 ENCODING 50769 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C653 ENCODING 50771 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C654 ENCODING 50772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C655 ENCODING 50773 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C70 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C65C ENCODING 50780 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3CA0 42A0 42A0 42A0 3CE0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+C65D ENCODING 50781 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 7100 8900 8980 7100 2100 FD00 0100 3F80 ENDCHAR STARTCHAR U+C660 ENCODING 50784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 44E0 38A0 10A0 7EA0 00A0 2020 2000 2000 1FE0 ENDCHAR STARTCHAR U+C66C ENCODING 50796 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 44E0 38A0 10A0 7EA0 00A0 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C66F ENCODING 50799 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 44E0 38A0 10A0 7EA0 00A0 0100 0100 0680 3860 ENDCHAR STARTCHAR U+C671 ENCODING 50801 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 44E0 38A0 10A0 7EA0 00A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C678 ENCODING 50808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C679 ENCODING 50809 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C67C ENCODING 50812 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+C680 ENCODING 50816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 3C40 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C688 ENCODING 50824 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C689 ENCODING 50825 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C68B ENCODING 50827 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C68D ENCODING 50829 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0840 7F40 0040 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C694 ENCODING 50836 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 2080 4040 4040 2080 1F00 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+C695 ENCODING 50837 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 1100 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C698 ENCODING 50840 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C69C ENCODING 50844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C6A4 ENCODING 50852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 1100 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C6A5 ENCODING 50853 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 1100 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C6A7 ENCODING 50855 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 1100 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C6A9 ENCODING 50857 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C6B0 ENCODING 50864 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+C6B1 ENCODING 50865 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C6B4 ENCODING 50868 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+C6B8 ENCODING 50872 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C6B9 ENCODING 50873 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0400 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+C6BA ENCODING 50874 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C6C0 ENCODING 50880 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C6C1 ENCODING 50881 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C6C3 ENCODING 50883 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C6C5 ENCODING 50885 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C6CC ENCODING 50892 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+C6CD ENCODING 50893 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C6D0 ENCODING 50896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 2800 2000 2000 1FC0 ENDCHAR STARTCHAR U+C6D4 ENCODING 50900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 38C0 0040 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C6DC ENCODING 50908 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C6DD ENCODING 50909 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C6E0 ENCODING 50912 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C6E1 ENCODING 50913 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 44C0 3840 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C6E8 ENCODING 50920 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 71 89 89 71 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+C6E9 ENCODING 50921 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 7100 8900 8B00 7100 0100 FD00 2100 1F80 ENDCHAR STARTCHAR U+C6EC ENCODING 50924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 45A0 38A0 00A0 7EA0 08A0 2800 2000 2000 1FE0 ENDCHAR STARTCHAR U+C6F0 ENCODING 50928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 39A0 00A0 00A0 7EA0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C6F8 ENCODING 50936 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 45A0 38A0 00A0 7EA0 10A0 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C6F9 ENCODING 50937 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 45A0 38A0 00A0 7EA0 10A0 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C6FD ENCODING 50941 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 44A0 45A0 38A0 00A0 7EA0 10A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C704 ENCODING 50948 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+C705 ENCODING 50949 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C708 ENCODING 50952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+C70C ENCODING 50956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 3840 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C714 ENCODING 50964 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C715 ENCODING 50965 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C717 ENCODING 50967 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C719 ENCODING 50969 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3840 4440 4440 3840 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C720 ENCODING 50976 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+C721 ENCODING 50977 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 1100 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C724 ENCODING 50980 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+C728 ENCODING 50984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C730 ENCODING 50992 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C731 ENCODING 50993 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 1100 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C733 ENCODING 50995 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 1100 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C735 ENCODING 50997 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C737 ENCODING 50999 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 1100 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+C73C ENCODING 51004 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 2080 4040 4040 2080 1F00 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+C73D ENCODING 51005 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C740 ENCODING 51008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C744 ENCODING 51012 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C74A ENCODING 51018 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0000 77C0 1280 7280 4280 3FC0 ENDCHAR STARTCHAR U+C74C ENCODING 51020 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C74D ENCODING 51021 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C74F ENCODING 51023 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C751 ENCODING 51025 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C752 ENCODING 51026 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+C753 ENCODING 51027 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+C754 ENCODING 51028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 7FC0 0040 7FC0 0040 ENDCHAR STARTCHAR U+C755 ENCODING 51029 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+C756 ENCODING 51030 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 4040 3F80 0000 FFE0 0000 7FC0 1100 1100 7FC0 ENDCHAR STARTCHAR U+C757 ENCODING 51031 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3F80 4040 3F80 0000 FFE0 0000 0E00 0000 7FC0 2080 1F00 ENDCHAR STARTCHAR U+C758 ENCODING 51032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+C75C ENCODING 51036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0040 7FC0 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C760 ENCODING 51040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 3C40 0040 7FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C768 ENCODING 51048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0040 7FC0 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C76B ENCODING 51051 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 3C40 0040 7FC0 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C774 ENCODING 51060 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 4240 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+C775 ENCODING 51061 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C778 ENCODING 51064 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C77C ENCODING 51068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C77D ENCODING 51069 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+C77E ENCODING 51070 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C783 ENCODING 51075 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 7880 0FE0 7A40 4240 3980 ENDCHAR STARTCHAR U+C784 ENCODING 51076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C785 ENCODING 51077 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C787 ENCODING 51079 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C788 ENCODING 51080 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C789 ENCODING 51081 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C78A ENCODING 51082 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+C78E ENCODING 51086 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 4240 4240 4240 3C40 0040 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C790 ENCODING 51088 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 0840 0870 1440 1440 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C791 ENCODING 51089 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C794 ENCODING 51092 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1470 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C796 ENCODING 51094 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+C797 ENCODING 51095 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C798 ENCODING 51096 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1470 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C79A ENCODING 51098 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1470 2240 4140 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C7A0 ENCODING 51104 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C7A1 ENCODING 51105 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C7A3 ENCODING 51107 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C7A4 ENCODING 51108 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C7A5 ENCODING 51109 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C7A6 ENCODING 51110 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 1440 2240 4140 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+C7AC ENCODING 51116 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 1120 1120 1120 29E0 2920 4520 4520 0120 0120 ENDCHAR STARTCHAR U+C7AD ENCODING 51117 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 2200 2380 5200 5200 8A00 0000 3F80 ENDCHAR STARTCHAR U+C7B0 ENCODING 51120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C7B4 ENCODING 51124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 29E0 2920 4520 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C7BC ENCODING 51132 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C7BD ENCODING 51133 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C7BF ENCODING 51135 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C7C0 ENCODING 51136 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+C7C1 ENCODING 51137 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C7C8 ENCODING 51144 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0870 0840 0840 1440 1470 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C7C9 ENCODING 51145 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 0840 1470 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C7CC ENCODING 51148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 0840 1470 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C7CE ENCODING 51150 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 0840 1470 2240 4140 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+C7D0 ENCODING 51152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 1440 2270 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C7D8 ENCODING 51160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 0840 1470 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C7DD ENCODING 51165 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0870 0840 1470 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C7E4 ENCODING 51172 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 1120 1120 2920 29E0 4520 4520 0120 0120 ENDCHAR STARTCHAR U+C7E8 ENCODING 51176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 11E0 2920 2920 4520 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C7EC ENCODING 51180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 1120 29E0 2920 4520 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C800 ENCODING 51200 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 09C0 0840 1440 1440 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C801 ENCODING 51201 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C804 ENCODING 51204 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C808 ENCODING 51208 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 15C0 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C80A ENCODING 51210 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 15C0 2240 4140 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C810 ENCODING 51216 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C811 ENCODING 51217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C813 ENCODING 51219 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C815 ENCODING 51221 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C816 ENCODING 51222 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 1440 2240 4140 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+C81C ENCODING 51228 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 21 21 21 27 51 51 89 89 01 01 ENDCHAR STARTCHAR U+C81D ENCODING 51229 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 2100 2700 5100 5100 8900 0000 3F80 ENDCHAR STARTCHAR U+C820 ENCODING 51232 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 13A0 28A0 28A0 44A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+C824 ENCODING 51236 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 2BA0 28A0 44A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+C82C ENCODING 51244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 13A0 28A0 28A0 44A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+C82D ENCODING 51245 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 13A0 28A0 28A0 44A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+C82F ENCODING 51247 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 13A0 28A0 28A0 44A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+C831 ENCODING 51249 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 10A0 13A0 28A0 28A0 44A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C838 ENCODING 51256 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 09C0 0840 0840 15C0 1440 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C83C ENCODING 51260 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 0840 15C0 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C840 ENCODING 51264 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 1440 23C0 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C848 ENCODING 51272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 0840 15C0 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C849 ENCODING 51273 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 0840 15C0 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C84C ENCODING 51276 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 0840 15C0 2240 4140 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C84D ENCODING 51277 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 09C0 0840 15C0 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C854 ENCODING 51284 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 21 27 21 21 57 51 89 89 01 01 ENDCHAR STARTCHAR U+C870 ENCODING 51312 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0400 0400 0A00 1100 60C0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+C871 ENCODING 51313 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C874 ENCODING 51316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C878 ENCODING 51320 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 60C0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C87A ENCODING 51322 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 60C0 0400 FFE0 0000 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C880 ENCODING 51328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C881 ENCODING 51329 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C883 ENCODING 51331 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C885 ENCODING 51333 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C886 ENCODING 51334 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0400 FFE0 0000 7FC0 0400 0A00 71C0 ENDCHAR STARTCHAR U+C887 ENCODING 51335 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 60C0 0400 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+C88B ENCODING 51339 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 60C0 0400 FFE0 0000 0E00 0000 7FC0 2080 1F00 ENDCHAR STARTCHAR U+C88C ENCODING 51340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1840 2440 2440 4270 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C88D ENCODING 51341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4170 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C894 ENCODING 51348 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 2240 5540 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C89D ENCODING 51357 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4170 0840 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C89F ENCODING 51359 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4170 0840 7F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C8A1 ENCODING 51361 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4170 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C8A8 ENCODING 51368 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 18A0 24A0 24A0 42E0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+C8BC ENCODING 51388 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 28A0 44E0 44A0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C8BD ENCODING 51389 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 28A0 44E0 44A0 10A0 7EA0 00A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+C8C4 ENCODING 51396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 1840 2440 2440 4240 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+C8C8 ENCODING 51400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4140 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+C8CC ENCODING 51404 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 2240 5540 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C8D4 ENCODING 51412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4140 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C8D5 ENCODING 51413 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4140 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C8D7 ENCODING 51415 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4140 0840 7F40 0040 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C8D9 ENCODING 51417 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 1440 2240 4140 0840 7F40 0040 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C8E0 ENCODING 51424 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0400 0400 0A00 1100 60C0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+C8E1 ENCODING 51425 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 1100 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C8E4 ENCODING 51428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C8F5 ENCODING 51445 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C8FC ENCODING 51452 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 1100 60C0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+C8FD ENCODING 51453 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C900 ENCODING 51456 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+C904 ENCODING 51460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 71C0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C905 ENCODING 51461 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 71C0 0000 FFE0 0400 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+C906 ENCODING 51462 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 71C0 0000 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+C90C ENCODING 51468 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C90D ENCODING 51469 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C90F ENCODING 51471 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C911 ENCODING 51473 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C918 ENCODING 51480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1440 2240 4140 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+C92C ENCODING 51500 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 44C0 4440 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C934 ENCODING 51508 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 21 51 89 01 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+C950 ENCODING 51536 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1440 2240 4140 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+C951 ENCODING 51537 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 4440 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C954 ENCODING 51540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 4440 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+C958 ENCODING 51544 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C960 ENCODING 51552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 4440 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C961 ENCODING 51553 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 4440 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C963 ENCODING 51555 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 4440 4440 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+C96C ENCODING 51564 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 1100 60C0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+C970 ENCODING 51568 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+C974 ENCODING 51572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 71C0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C97C ENCODING 51580 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0400 0A00 71C0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C988 ENCODING 51592 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0400 0400 0A00 1100 60C0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+C989 ENCODING 51593 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C98C ENCODING 51596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+C990 ENCODING 51600 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 60C0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+C998 ENCODING 51608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+C999 ENCODING 51609 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+C99B ENCODING 51611 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+C99D ENCODING 51613 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0A00 1100 60C0 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+C9C0 ENCODING 51648 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 0840 0840 1440 1440 2240 4140 0040 0040 ENDCHAR STARTCHAR U+C9C1 ENCODING 51649 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C9C4 ENCODING 51652 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C9C7 ENCODING 51655 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+C9C8 ENCODING 51656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1440 2240 4140 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C9CA ENCODING 51658 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1440 2240 4140 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+C9D0 ENCODING 51664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C9D1 ENCODING 51665 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C9D3 ENCODING 51667 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C9D5 ENCODING 51669 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C9D6 ENCODING 51670 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+C9D9 ENCODING 51673 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 1440 2240 4140 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C9DA ENCODING 51674 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0840 0840 1440 2240 4140 0000 3FE0 0880 0880 3FE0 ENDCHAR STARTCHAR U+C9DC ENCODING 51676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 2270 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+C9DD ENCODING 51677 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+C9E0 ENCODING 51680 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2270 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+C9E2 ENCODING 51682 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+C9E4 ENCODING 51684 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+C9E7 ENCODING 51687 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 5540 8940 0040 3A40 0A40 3BC0 2240 1FC0 ENDCHAR STARTCHAR U+C9EC ENCODING 51692 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+C9ED ENCODING 51693 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+C9EF ENCODING 51695 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+C9F0 ENCODING 51696 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+C9F1 ENCODING 51697 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+C9F8 ENCODING 51704 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 2920 2920 2920 55E0 5520 9520 2320 0120 0120 ENDCHAR STARTCHAR U+C9F9 ENCODING 51705 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 5200 5380 5200 AA00 AA00 0000 3F80 ENDCHAR STARTCHAR U+C9FC ENCODING 51708 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CA00 ENCODING 51712 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 5520 5520 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+CA08 ENCODING 51720 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+CA09 ENCODING 51721 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+CA0B ENCODING 51723 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+CA0C ENCODING 51724 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+CA0D ENCODING 51725 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 2920 29E0 2920 5520 5520 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CA14 ENCODING 51732 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2270 2240 2240 5540 5570 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+CA18 ENCODING 51736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2270 2240 2270 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CA29 ENCODING 51753 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2270 2240 2270 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CA4C ENCODING 51788 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 23C0 2240 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+CA4D ENCODING 51789 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CA50 ENCODING 51792 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CA54 ENCODING 51796 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CA5C ENCODING 51804 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CA5D ENCODING 51805 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CA5F ENCODING 51807 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+CA60 ENCODING 51808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CA61 ENCODING 51809 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CA68 ENCODING 51816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 28A0 28A0 28A0 2BA0 54A0 54A0 94A0 22A0 00A0 00A0 ENDCHAR STARTCHAR U+CA7D ENCODING 51837 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 28A0 2BA0 28A0 54A0 54A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CA84 ENCODING 51844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 23C0 2240 2240 55C0 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+CA98 ENCODING 51864 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 23C0 2240 23C0 5540 8940 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CABC ENCODING 51900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP FBC0 2080 2080 2080 5140 8A00 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+CABD ENCODING 51901 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CAC0 ENCODING 51904 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+CAC4 ENCODING 51908 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 2A80 4440 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CACC ENCODING 51916 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+CACD ENCODING 51917 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CACF ENCODING 51919 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+CAD1 ENCODING 51921 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CAD3 ENCODING 51923 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 2A80 4440 0400 FFE0 0000 0200 7FC0 0400 1B00 60C0 ENDCHAR STARTCHAR U+CAD8 ENCODING 51928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 8970 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+CAD9 ENCODING 51929 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 5540 4970 0840 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CAE0 ENCODING 51936 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 3640 4940 0870 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CAEC ENCODING 51948 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 5540 4970 0840 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CAF4 ENCODING 51956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 24A0 24A0 5AA0 52E0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+CB08 ENCODING 51976 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 28A0 54E0 54A0 10A0 7EA0 00A0 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CB10 ENCODING 51984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 8940 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+CB14 ENCODING 51988 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 5540 4940 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+CB18 ENCODING 51992 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 3640 4940 0840 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CB20 ENCODING 52000 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 5540 4940 0840 7F40 0040 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CB21 ENCODING 52001 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 5540 4940 0840 7F40 0040 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CB41 ENCODING 52033 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 1100 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CB48 ENCODING 52040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 2080 2080 5140 8A20 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+CB49 ENCODING 52041 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CB4C ENCODING 52044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+CB50 ENCODING 52048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 5140 8A20 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CB58 ENCODING 52056 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+CB59 ENCODING 52057 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CB5D ENCODING 52061 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CB64 ENCODING 52068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 5540 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+CB78 ENCODING 52088 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 54C0 5440 0040 7F40 0840 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CB79 ENCODING 52089 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 54C0 5440 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CB9C ENCODING 52124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 5540 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+CBB8 ENCODING 52152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7BC0 2080 2080 5140 8A20 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+CBD4 ENCODING 52180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP FBC0 2080 2080 2080 5140 8A00 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+CBE4 ENCODING 52196 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+CBE7 ENCODING 52199 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+CBE9 ENCODING 52201 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP FBE0 2080 5140 8A20 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CC0C ENCODING 52236 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 2240 5540 5540 5540 88C0 0040 0040 ENDCHAR STARTCHAR U+CC0D ENCODING 52237 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CC10 ENCODING 52240 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CC14 ENCODING 52244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 8940 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CC1C ENCODING 52252 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CC1D ENCODING 52253 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CC21 ENCODING 52257 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CC22 ENCODING 52258 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 2240 5540 8940 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+CC27 ENCODING 52263 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7740 2240 2240 5540 8940 0040 0700 0000 7FE0 1040 0F80 ENDCHAR STARTCHAR U+CC28 ENCODING 52264 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 0870 0840 1440 1440 2240 4140 0040 ENDCHAR STARTCHAR U+CC29 ENCODING 52265 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CC2C ENCODING 52268 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0870 1440 6340 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+CC2E ENCODING 52270 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+CC30 ENCODING 52272 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 0870 1440 6340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CC38 ENCODING 52280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CC39 ENCODING 52281 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CC3B ENCODING 52283 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+CC3C ENCODING 52284 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CC3D ENCODING 52285 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CC3E ENCODING 52286 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 1440 6340 0000 3FE0 0100 0680 3860 ENDCHAR STARTCHAR U+CC44 ENCODING 52292 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 0120 7D20 1120 1120 29E0 2920 4520 8320 0120 0120 ENDCHAR STARTCHAR U+CC45 ENCODING 52293 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 2200 FA00 2380 2200 5200 8A00 0000 3F80 ENDCHAR STARTCHAR U+CC48 ENCODING 52296 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CC4C ENCODING 52300 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 2920 4520 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+CC54 ENCODING 52308 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+CC55 ENCODING 52309 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+CC57 ENCODING 52311 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+CC58 ENCODING 52312 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+CC59 ENCODING 52313 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 7D20 11E0 1120 2920 4520 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CC60 ENCODING 52320 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F70 0840 0840 0840 1470 1440 2240 4140 0040 ENDCHAR STARTCHAR U+CC64 ENCODING 52324 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0070 7F40 0870 1440 6340 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CC66 ENCODING 52326 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0070 7F40 0870 1440 6340 0100 27E0 2240 2240 1D80 ENDCHAR STARTCHAR U+CC68 ENCODING 52328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F70 0840 1470 6340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CC70 ENCODING 52336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0070 7F40 0870 1440 6340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CC75 ENCODING 52341 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0070 7F40 0870 1440 6340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CC98 ENCODING 52376 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 09C0 0840 0840 1440 1440 2240 4140 0040 ENDCHAR STARTCHAR U+CC99 ENCODING 52377 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CC9C ENCODING 52380 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CCA0 ENCODING 52384 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 09C0 1440 6340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CCA8 ENCODING 52392 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CCA9 ENCODING 52393 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CCAB ENCODING 52395 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+CCAC ENCODING 52396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CCAD ENCODING 52397 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 1440 6340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CCB4 ENCODING 52404 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 00A0 7CA0 10A0 13A0 28A0 28A0 44A0 82A0 00A0 00A0 ENDCHAR STARTCHAR U+CCB5 ENCODING 52405 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP 2100 F900 2700 2100 5100 8900 0000 3F80 ENDCHAR STARTCHAR U+CCB8 ENCODING 52408 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 10A0 28A0 44A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CCBC ENCODING 52412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 28A0 44A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+CCC4 ENCODING 52420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 10A0 28A0 44A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+CCC5 ENCODING 52421 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 10A0 28A0 44A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+CCC7 ENCODING 52423 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 10A0 28A0 44A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+CCC9 ENCODING 52425 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 13A0 10A0 28A0 44A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CCD0 ENCODING 52432 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7FC0 0840 0840 09C0 1440 1440 2240 4140 0040 ENDCHAR STARTCHAR U+CCD4 ENCODING 52436 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 01C0 7F40 09C0 1440 6340 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CCE4 ENCODING 52452 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 01C0 7F40 09C0 1440 6340 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CCEC ENCODING 52460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 00A0 7FA0 10A0 10A0 2BA0 28A0 44A0 82A0 00A0 00A0 ENDCHAR STARTCHAR U+CCF0 ENCODING 52464 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7FA0 10A0 13A0 28A0 44A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CD01 ENCODING 52481 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7FA0 10A0 13A0 28A0 44A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CD08 ENCODING 52488 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 7FC0 0400 0A00 1100 2080 4440 0400 FFC0 ENDCHAR STARTCHAR U+CD09 ENCODING 52489 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+CD0C ENCODING 52492 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+CD10 ENCODING 52496 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CD18 ENCODING 52504 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CD19 ENCODING 52505 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CD1B ENCODING 52507 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+CD1D ENCODING 52509 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0400 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+CD24 ENCODING 52516 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1840 0040 7E40 1840 2470 2440 4A40 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+CD28 ENCODING 52520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2270 4140 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+CD2C ENCODING 52524 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2270 4140 0840 7FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CD39 ENCODING 52537 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2270 4140 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+CD5C ENCODING 52572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1840 0040 7E40 1840 2440 2440 4A40 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+CD60 ENCODING 52576 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+CD64 ENCODING 52580 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CD6C ENCODING 52588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7F40 0000 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CD6D ENCODING 52589 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7F40 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CD6F ENCODING 52591 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7F40 0000 0100 0680 3860 ENDCHAR STARTCHAR U+CD71 ENCODING 52593 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 1440 2240 4140 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+CD78 ENCODING 52600 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 7FC0 0400 0A00 1100 2080 5140 1100 FFC0 ENDCHAR STARTCHAR U+CD88 ENCODING 52616 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 1100 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CD94 ENCODING 52628 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0E00 0000 7FC0 0400 1B00 60C0 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+CD95 ENCODING 52629 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0400 7FC0 0040 0040 ENDCHAR STARTCHAR U+CD98 ENCODING 52632 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0400 4400 4000 3FC0 ENDCHAR STARTCHAR U+CD9C ENCODING 52636 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 1100 60C0 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CDA4 ENCODING 52644 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0400 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CDA5 ENCODING 52645 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 4440 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CDA7 ENCODING 52647 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0400 0200 0D00 70C0 ENDCHAR STARTCHAR U+CDA9 ENCODING 52649 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0400 3F80 4040 3F80 ENDCHAR STARTCHAR U+CDB0 ENCODING 52656 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 1440 6340 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+CDC4 ENCODING 52676 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 28C0 4440 4440 0040 7F40 0840 0880 1540 2220 ENDCHAR STARTCHAR U+CDCC ENCODING 52684 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP 21 F9 21 51 89 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+CDD0 ENCODING 52688 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 7CA0 29A0 44A0 44A0 00A0 7EA0 10A0 3020 2000 1FE0 ENDCHAR STARTCHAR U+CDE8 ENCODING 52712 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 1440 6340 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+CDEC ENCODING 52716 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 4440 0040 7FC0 0840 2840 2000 1FC0 ENDCHAR STARTCHAR U+CDF0 ENCODING 52720 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 3FC0 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CDF8 ENCODING 52728 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 4440 0040 7FC0 0840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CDF9 ENCODING 52729 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 4440 0040 7FC0 2840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CDFB ENCODING 52731 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 4440 0040 7FC0 0840 0100 0680 3860 ENDCHAR STARTCHAR U+CDFD ENCODING 52733 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 7C40 2840 4440 4440 0040 7FC0 0840 1F80 2040 1F80 ENDCHAR STARTCHAR U+CE04 ENCODING 52740 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0E00 0000 7FC0 0400 1B00 60C0 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+CE08 ENCODING 52744 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 1100 5100 4000 3FC0 ENDCHAR STARTCHAR U+CE0C ENCODING 52748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 1100 60C0 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CE14 ENCODING 52756 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 1100 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CE19 ENCODING 52761 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 1100 3F80 4040 3F80 ENDCHAR STARTCHAR U+CE20 ENCODING 52768 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 7FC0 0400 0A00 1100 2080 4040 0000 FFC0 ENDCHAR STARTCHAR U+CE21 ENCODING 52769 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+CE24 ENCODING 52772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+CE28 ENCODING 52776 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CE30 ENCODING 52784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CE31 ENCODING 52785 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CE33 ENCODING 52787 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+CE35 ENCODING 52789 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 7FC0 0A00 1100 60C0 0000 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+CE58 ENCODING 52824 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 0840 0840 1440 1440 2240 4140 0040 ENDCHAR STARTCHAR U+CE59 ENCODING 52825 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CE5C ENCODING 52828 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CE5F ENCODING 52831 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+CE60 ENCODING 52832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 0840 1440 6340 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CE61 ENCODING 52833 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 0840 1440 6340 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+CE68 ENCODING 52840 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CE69 ENCODING 52841 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CE6B ENCODING 52843 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+CE6D ENCODING 52845 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 0840 1440 6340 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CE74 ENCODING 52852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 0270 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+CE75 ENCODING 52853 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CE78 ENCODING 52856 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CE7C ENCODING 52860 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 7C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CE84 ENCODING 52868 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CE85 ENCODING 52869 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CE87 ENCODING 52871 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+CE89 ENCODING 52873 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E70 0240 0440 7840 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CE90 ENCODING 52880 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 0520 7D20 0520 09E0 0920 1120 6120 0120 0120 ENDCHAR STARTCHAR U+CE91 ENCODING 52881 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 0A00 FB80 1200 2200 C200 0000 3F80 ENDCHAR STARTCHAR U+CE94 ENCODING 52884 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CE98 ENCODING 52888 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0520 7920 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+CEA0 ENCODING 52896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+CEA1 ENCODING 52897 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+CEA3 ENCODING 52899 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+CEA4 ENCODING 52900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+CEA5 ENCODING 52901 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0520 7DE0 0920 1120 6120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CEAC ENCODING 52908 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0270 7E40 0240 0440 0470 0840 7040 0040 0040 ENDCHAR STARTCHAR U+CEAD ENCODING 52909 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 0270 0440 7840 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CEC1 ENCODING 52929 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0270 7E40 0270 0440 7840 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CEE4 ENCODING 52964 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 03C0 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+CEE5 ENCODING 52965 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CEE8 ENCODING 52968 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CEEB ENCODING 52971 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 3FC0 2000 2000 1FC0 ENDCHAR STARTCHAR U+CEEC ENCODING 52972 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 7C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CEF4 ENCODING 52980 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CEF5 ENCODING 52981 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CEF7 ENCODING 52983 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+CEF8 ENCODING 52984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CEF9 ENCODING 52985 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7FC0 0240 0440 7840 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CF00 ENCODING 52992 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 09 F9 0F 11 11 21 C1 01 01 ENDCHAR STARTCHAR U+CF01 ENCODING 52993 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 0900 FF00 1100 2100 C100 0000 3F80 ENDCHAR STARTCHAR U+CF04 ENCODING 52996 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 08A0 10A0 60A0 0000 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+CF08 ENCODING 53000 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7DA0 04A0 78A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+CF10 ENCODING 53008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 08A0 10A0 60A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+CF11 ENCODING 53009 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 08A0 10A0 60A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+CF13 ENCODING 53011 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 08A0 10A0 60A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+CF15 ENCODING 53013 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7FA0 08A0 10A0 60A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CF1C ENCODING 53020 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 03C0 7E40 0240 05C0 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+CF20 ENCODING 53024 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CF24 ENCODING 53028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 7C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CF2C ENCODING 53036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CF2D ENCODING 53037 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+CF2F ENCODING 53039 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+CF30 ENCODING 53040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+CF31 ENCODING 53041 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 03C0 7E40 03C0 0440 7840 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CF38 ENCODING 53048 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 0F F9 09 17 11 21 C1 01 01 ENDCHAR STARTCHAR U+CF54 ENCODING 53076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 7FC0 0840 0840 0840 0800 FFC0 ENDCHAR STARTCHAR U+CF55 ENCODING 53077 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 0800 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CF58 ENCODING 53080 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0400 FFE0 0000 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+CF5C ENCODING 53084 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CF64 ENCODING 53092 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 0800 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+CF65 ENCODING 53093 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 0800 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CF67 ENCODING 53095 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 0800 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+CF69 ENCODING 53097 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0840 0800 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CF70 ENCODING 53104 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 1270 1240 1240 1040 7F40 0040 0040 ENDCHAR STARTCHAR U+CF71 ENCODING 53105 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 1270 1040 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CF74 ENCODING 53108 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0270 0840 7F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+CF78 ENCODING 53112 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 1270 7FC0 0000 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CF80 ENCODING 53120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 1270 1040 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+CF85 ENCODING 53125 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 1270 1040 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+CF8C ENCODING 53132 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 02A0 02A0 7EA0 22E0 22A0 22A0 20A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+CFA1 ENCODING 53153 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7CE0 24A0 20A0 7EA0 00A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+CFA8 ENCODING 53160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 1240 1240 1240 1040 7F40 0040 0040 ENDCHAR STARTCHAR U+CFB0 ENCODING 53168 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 1240 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+CFC4 ENCODING 53188 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 7FC0 2240 2240 2240 2200 FFC0 ENDCHAR STARTCHAR U+CFE0 ENCODING 53216 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 7FC0 0040 0040 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+CFE1 ENCODING 53217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+CFE4 ENCODING 53220 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 4400 4000 4000 3FC0 ENDCHAR STARTCHAR U+CFE8 ENCODING 53224 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+CFF0 ENCODING 53232 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+CFF1 ENCODING 53233 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+CFF3 ENCODING 53235 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+CFF5 ENCODING 53237 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+CFFC ENCODING 53244 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0240 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+D000 ENCODING 53248 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7CC0 0440 0040 7F40 0840 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D004 ENCODING 53252 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7CC0 0440 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D011 ENCODING 53265 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7CC0 0440 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D018 ENCODING 53272 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 09 F9 09 09 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+D02D ENCODING 53293 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 04A0 7DA0 04A0 00A0 7EA0 10A0 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D034 ENCODING 53300 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0240 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+D035 ENCODING 53301 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D038 ENCODING 53304 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D03C ENCODING 53308 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D044 ENCODING 53316 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D045 ENCODING 53317 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D047 ENCODING 53319 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D049 ENCODING 53321 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0440 7C40 0440 0040 7FC0 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D050 ENCODING 53328 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 0040 7FC0 0040 0040 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+D054 ENCODING 53332 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 1100 5100 4000 4000 3FC0 ENDCHAR STARTCHAR U+D058 ENCODING 53336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D060 ENCODING 53344 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D06C ENCODING 53356 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0040 0040 0040 7FC0 0040 0040 0040 0000 FFC0 ENDCHAR STARTCHAR U+D06D ENCODING 53357 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D070 ENCODING 53360 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0000 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D074 ENCODING 53364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D07C ENCODING 53372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D07D ENCODING 53373 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D081 ENCODING 53377 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0040 7FC0 0040 0000 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+D0A4 ENCODING 53412 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 0240 7E40 0240 0440 0440 0840 7040 0040 0040 ENDCHAR STARTCHAR U+D0A5 ENCODING 53413 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D0A8 ENCODING 53416 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D0AC ENCODING 53420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 7C40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D0B4 ENCODING 53428 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D0B5 ENCODING 53429 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D0B7 ENCODING 53431 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D0B9 ENCODING 53433 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0240 7E40 0240 0440 7840 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D0C0 ENCODING 53440 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 7C40 4070 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+D0C1 ENCODING 53441 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D0C4 ENCODING 53444 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4070 4040 3F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D0C8 ENCODING 53448 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D0C9 ENCODING 53449 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 3F40 0040 3FC0 0440 3C40 2040 1C40 ENDCHAR STARTCHAR U+D0D0 ENCODING 53456 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D0D1 ENCODING 53457 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D0D3 ENCODING 53459 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D0D4 ENCODING 53460 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D0D5 ENCODING 53461 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C70 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D0DC ENCODING 53468 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 4120 7920 4120 41E0 4120 3D20 0120 0120 0120 ENDCHAR STARTCHAR U+D0DD ENCODING 53469 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 8200 F380 8200 8200 7E00 0000 3F80 ENDCHAR STARTCHAR U+D0E0 ENCODING 53472 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D0E4 ENCODING 53476 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 3F20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D0EC ENCODING 53484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D0ED ENCODING 53485 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D0EF ENCODING 53487 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D0F0 ENCODING 53488 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+D0F1 ENCODING 53489 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 4120 79E0 4120 4120 3F20 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D0F8 ENCODING 53496 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4070 7C40 4040 4040 4070 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+D10D ENCODING 53517 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4070 7C40 4070 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D130 ENCODING 53552 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 7DC0 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+D131 ENCODING 53553 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D134 ENCODING 53556 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D138 ENCODING 53560 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D13A ENCODING 53562 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 3F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+D140 ENCODING 53568 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D141 ENCODING 53569 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D143 ENCODING 53571 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D144 ENCODING 53572 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D145 ENCODING 53573 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7DC0 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D14C ENCODING 53580 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 81 81 F1 87 81 81 79 01 01 01 ENDCHAR STARTCHAR U+D14D ENCODING 53581 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 8100 F700 8100 8100 7D00 0000 3F80 ENDCHAR STARTCHAR U+D150 ENCODING 53584 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 40A0 3EA0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D154 ENCODING 53588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 3EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D15C ENCODING 53596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 40A0 3EA0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D15D ENCODING 53597 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 40A0 3EA0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D15F ENCODING 53599 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 40A0 3EA0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D161 ENCODING 53601 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 40A0 7BA0 40A0 40A0 3EA0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D168 ENCODING 53608 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 41C0 7C40 4040 41C0 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+D16C ENCODING 53612 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 7C40 41C0 4040 3F40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D17C ENCODING 53628 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 41C0 7C40 41C0 4040 3F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D184 ENCODING 53636 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 81 87 F1 81 87 81 79 01 01 01 ENDCHAR STARTCHAR U+D188 ENCODING 53640 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 43A0 78A0 43A0 40A0 3EA0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D1A0 ENCODING 53664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 7F80 4000 4000 3FC0 0400 0400 FFC0 ENDCHAR STARTCHAR U+D1A1 ENCODING 53665 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+D1A4 ENCODING 53668 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D1A8 ENCODING 53672 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D1B0 ENCODING 53680 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D1B1 ENCODING 53681 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D1B3 ENCODING 53683 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+D1B5 ENCODING 53685 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+D1BA ENCODING 53690 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0400 FFE0 0000 7FC0 1100 7FC0 ENDCHAR STARTCHAR U+D1BC ENCODING 53692 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4070 3E40 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D1C0 ENCODING 53696 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4070 3E40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D1D8 ENCODING 53720 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7EA0 40A0 7CA0 40A0 3EE0 00A0 10A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+D1F4 ENCODING 53748 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3E40 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D1F8 ENCODING 53752 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D207 ENCODING 53767 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0840 7F40 0000 0100 0680 3860 ENDCHAR STARTCHAR U+D209 ENCODING 53769 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+D210 ENCODING 53776 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 7F80 4000 4000 3FC0 1100 1100 FFC0 ENDCHAR STARTCHAR U+D22C ENCODING 53804 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 4000 7FC0 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+D22D ENCODING 53805 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0400 7FC0 0040 0040 ENDCHAR STARTCHAR U+D230 ENCODING 53808 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0400 4400 4000 3FC0 ENDCHAR STARTCHAR U+D234 ENCODING 53812 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D23C ENCODING 53820 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0400 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D23D ENCODING 53821 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 4440 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D23F ENCODING 53823 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0400 0200 0D00 70C0 ENDCHAR STARTCHAR U+D241 ENCODING 53825 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0400 3F80 4040 3F80 ENDCHAR STARTCHAR U+D248 ENCODING 53832 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+D25C ENCODING 53852 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 78C0 4040 3C40 0040 7F40 0840 0880 1540 2220 ENDCHAR STARTCHAR U+D264 ENCODING 53860 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 81 F1 81 79 01 FD 21 27 21 21 ENDCHAR STARTCHAR U+D280 ENCODING 53888 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+D281 ENCODING 53889 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3C40 0040 7FC0 0840 3FC0 0040 0040 ENDCHAR STARTCHAR U+D284 ENCODING 53892 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3C40 0040 7FC0 0840 2840 2000 1FC0 ENDCHAR STARTCHAR U+D288 ENCODING 53896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3FC0 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D290 ENCODING 53904 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3C40 0040 7FC0 0840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D291 ENCODING 53905 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3C40 0040 7FC0 2840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D295 ENCODING 53909 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 4040 7840 4040 3C40 0040 7FC0 0840 1F80 2040 1F80 ENDCHAR STARTCHAR U+D29C ENCODING 53916 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 4000 7FC0 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+D2A0 ENCODING 53920 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 1100 5100 4000 3FC0 ENDCHAR STARTCHAR U+D2A4 ENCODING 53924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D2AC ENCODING 53932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 1100 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D2B1 ENCODING 53937 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 1100 3F80 4040 3F80 ENDCHAR STARTCHAR U+D2B8 ENCODING 53944 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 4000 4000 7F80 4000 4000 3FC0 0000 0000 FFC0 ENDCHAR STARTCHAR U+D2B9 ENCODING 53945 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+D2BC ENCODING 53948 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D2BF ENCODING 53951 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0000 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D2C0 ENCODING 53952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D2C2 ENCODING 53954 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 FFE0 0000 7800 0800 7BC0 4240 3FC0 ENDCHAR STARTCHAR U+D2C8 ENCODING 53960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D2C9 ENCODING 53961 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D2CB ENCODING 53963 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 4000 7F80 4000 3FC0 0000 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+D2D4 ENCODING 53972 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3E40 0040 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+D2D8 ENCODING 53976 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0040 7FC0 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D2DC ENCODING 53980 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D2E4 ENCODING 53988 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0040 7FC0 0040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D2E5 ENCODING 53989 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3E40 0040 7FC0 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D2F0 ENCODING 54000 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 4040 7C40 4040 4040 4040 3F40 0040 0040 0040 ENDCHAR STARTCHAR U+D2F1 ENCODING 54001 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D2F4 ENCODING 54004 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D2F8 ENCODING 54008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 3F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D300 ENCODING 54016 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D301 ENCODING 54017 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D303 ENCODING 54019 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D305 ENCODING 54021 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 4040 7C40 4040 4040 3F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D30C ENCODING 54028 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2440 2440 2470 2440 2440 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D30D ENCODING 54029 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D30E ENCODING 54030 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 3FC0 0440 0440 0440 ENDCHAR STARTCHAR U+D310 ENCODING 54032 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2470 2440 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D314 ENCODING 54036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D316 ENCODING 54038 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 7F40 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+D31C ENCODING 54044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D31D ENCODING 54045 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D31F ENCODING 54047 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D320 ENCODING 54048 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D321 ENCODING 54049 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 2440 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D325 ENCODING 54053 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2470 2440 7F40 0040 3FC0 2000 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D328 ENCODING 54056 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 2920 2920 2920 29E0 2920 2920 7F20 0120 0120 ENDCHAR STARTCHAR U+D329 ENCODING 54057 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP FA00 0200 5380 5200 5200 FE00 0000 3F80 ENDCHAR STARTCHAR U+D32C ENCODING 54060 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D330 ENCODING 54064 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 7F20 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D338 ENCODING 54072 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D339 ENCODING 54073 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D33B ENCODING 54075 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D33C ENCODING 54076 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+D33D ENCODING 54077 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7D20 0120 29E0 2920 2920 7F20 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D344 ENCODING 54084 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2470 2440 2440 2440 2470 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D345 ENCODING 54085 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0070 2440 2470 2440 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D37C ENCODING 54140 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2440 25C0 2440 2440 2440 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D37D ENCODING 54141 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D380 ENCODING 54144 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D384 ENCODING 54148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D38C ENCODING 54156 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D38D ENCODING 54157 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D38F ENCODING 54159 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D390 ENCODING 54160 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D391 ENCODING 54161 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 25C0 2440 2440 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D398 ENCODING 54168 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 01 51 51 57 51 51 51 FD 01 01 ENDCHAR STARTCHAR U+D399 ENCODING 54169 SWIDTH 935 0 DWIDTH 12 0 BBX 9 8 1 1 BITMAP F900 0100 5700 5100 5100 FD00 0000 3F80 ENDCHAR STARTCHAR U+D39C ENCODING 54172 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 28A0 7EA0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D3A0 ENCODING 54176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 7EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D3A8 ENCODING 54184 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 28A0 7EA0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D3A9 ENCODING 54185 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 28A0 7EA0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D3AB ENCODING 54187 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 28A0 7EA0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D3AD ENCODING 54189 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 00A0 2BA0 28A0 28A0 7EA0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D3B4 ENCODING 54196 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 25C0 2440 2440 25C0 2440 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D3B8 ENCODING 54200 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 2440 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D3BC ENCODING 54204 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D3C4 ENCODING 54212 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 2440 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D3C5 ENCODING 54213 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 2440 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D3C8 ENCODING 54216 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 2440 7F40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D3C9 ENCODING 54217 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 01C0 2440 25C0 2440 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D3D0 ENCODING 54224 SWIDTH 935 0 DWIDTH 12 0 BBX 8 11 1 -2 BITMAP F9 01 57 51 51 57 51 51 FD 01 01 ENDCHAR STARTCHAR U+D3D8 ENCODING 54232 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 03A0 28A0 2BA0 7EA0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D3E1 ENCODING 54241 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 03A0 28A0 2BA0 28A0 7EA0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D3E3 ENCODING 54243 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7CA0 03A0 28A0 2BA0 28A0 7EA0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D3EC ENCODING 54252 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0000 1100 1100 1100 7FC0 0000 0400 0400 FFC0 ENDCHAR STARTCHAR U+D3ED ENCODING 54253 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0400 FFE0 0000 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D3F0 ENCODING 54256 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 0400 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D3F4 ENCODING 54260 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 0400 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D3FC ENCODING 54268 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0400 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D3FD ENCODING 54269 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0400 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D3FF ENCODING 54271 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0400 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+D401 ENCODING 54273 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0400 FFE0 0000 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+D408 ENCODING 54280 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2240 2240 7F70 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D41D ENCODING 54301 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2440 7F70 0840 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D440 ENCODING 54336 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2240 2240 7F40 0040 0840 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D444 ENCODING 54340 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2440 7F40 0840 7F40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D45C ENCODING 54364 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0000 1100 1100 1100 7FC0 0000 1100 1100 FFC0 ENDCHAR STARTCHAR U+D460 ENCODING 54368 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 1100 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D464 ENCODING 54372 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 1100 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D46D ENCODING 54381 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 1100 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D46F ENCODING 54383 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 1100 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+D478 ENCODING 54392 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 1100 7FC0 0000 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+D479 ENCODING 54393 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D47C ENCODING 54396 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 0000 FFE0 4400 4400 4000 3FC0 ENDCHAR STARTCHAR U+D47F ENCODING 54399 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 7FC0 4000 4000 3FC0 ENDCHAR STARTCHAR U+D480 ENCODING 54400 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 0000 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D482 ENCODING 54402 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 0000 FFE0 0400 7BC0 0A40 7A40 4240 3FC0 ENDCHAR STARTCHAR U+D488 ENCODING 54408 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D489 ENCODING 54409 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D48B ENCODING 54411 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+D48D ENCODING 54413 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 0400 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+D494 ENCODING 54420 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 7E40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+D4A9 ENCODING 54441 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0040 28C0 7C40 0040 7F40 0840 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D4CC ENCODING 54476 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 7E40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+D4D0 ENCODING 54480 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0040 2840 7C40 0040 7FC0 0840 2840 2000 2000 1FC0 ENDCHAR STARTCHAR U+D4D4 ENCODING 54484 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 2840 7C40 0040 0040 7FC0 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D4DC ENCODING 54492 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0040 2840 7C40 0040 7FC0 0840 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D4DF ENCODING 54495 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7C40 0040 2840 7C40 0040 7FC0 0840 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D4E8 ENCODING 54504 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 1100 7FC0 0000 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+D4EC ENCODING 54508 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 0000 FFE0 5100 5100 4000 3FC0 ENDCHAR STARTCHAR U+D4F0 ENCODING 54512 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 0000 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D4F8 ENCODING 54520 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 1100 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D4FB ENCODING 54523 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 1100 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+D4FD ENCODING 54525 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 0000 1100 7FC0 0000 FFE0 1100 3F80 4040 4040 3F80 ENDCHAR STARTCHAR U+D504 ENCODING 54532 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 7FC0 0000 1100 1100 1100 7FC0 0000 0000 0000 FFC0 ENDCHAR STARTCHAR U+D508 ENCODING 54536 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 0000 FFE0 4000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D50C ENCODING 54540 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 7FC0 0000 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D514 ENCODING 54548 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 FFE0 0000 7FC0 4040 4040 3FC0 ENDCHAR STARTCHAR U+D515 ENCODING 54549 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 FFE0 0000 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D517 ENCODING 54551 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7FC0 1100 1100 7FC0 0000 FFE0 0000 0400 0A00 1100 60C0 ENDCHAR STARTCHAR U+D53C ENCODING 54588 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7F40 0040 2440 2440 2440 2440 2440 7FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D53D ENCODING 54589 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D540 ENCODING 54592 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D544 ENCODING 54596 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 7F40 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D54C ENCODING 54604 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D54D ENCODING 54605 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D54F ENCODING 54607 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D551 ENCODING 54609 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 7E40 0040 2440 2440 2440 7F40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D558 ENCODING 54616 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 0040 FF40 0040 3C70 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+D559 ENCODING 54617 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2470 4240 4240 3C40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D55C ENCODING 54620 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4270 4240 3C40 0040 2040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D560 ENCODING 54624 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4470 4440 3840 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D565 ENCODING 54629 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4470 4440 3840 0040 3BC0 0A00 3BC0 2200 1FC0 ENDCHAR STARTCHAR U+D568 ENCODING 54632 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2470 4240 4240 3C40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D569 ENCODING 54633 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2470 4240 4240 3C40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D56B ENCODING 54635 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2470 4240 4240 3C40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D56D ENCODING 54637 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2470 4240 4240 3C40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D574 ENCODING 54644 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3920 0120 FF20 0120 3920 45E0 4520 4520 3920 0120 0120 ENDCHAR STARTCHAR U+D575 ENCODING 54645 SWIDTH 935 0 DWIDTH 12 0 BBX 10 8 0 1 BITMAP 1100 FF00 45C0 4500 3900 0100 0000 1FC0 ENDCHAR STARTCHAR U+D578 ENCODING 54648 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D57C ENCODING 54652 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D584 ENCODING 54660 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D585 ENCODING 54661 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D587 ENCODING 54663 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D588 ENCODING 54664 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0000 0840 0840 14A0 2310 ENDCHAR STARTCHAR U+D589 ENCODING 54665 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1120 FF20 45E0 4520 3920 0120 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D590 ENCODING 54672 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 0040 FF70 0040 3C40 4240 4270 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+D5A5 ENCODING 54693 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF70 2440 4270 4240 3C40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D5C8 ENCODING 54728 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 0040 FF40 01C0 3C40 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+D5C9 ENCODING 54729 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D5CC ENCODING 54732 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D5D0 ENCODING 54736 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 45C0 4440 3840 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D5D2 ENCODING 54738 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 45C0 4440 3840 0040 3DC0 0540 3D40 2140 1FC0 ENDCHAR STARTCHAR U+D5D8 ENCODING 54744 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D5D9 ENCODING 54745 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D5DB ENCODING 54747 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D5DD ENCODING 54749 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 25C0 4240 4240 3C40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D5E4 ENCODING 54756 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 00A0 FEA0 00A0 3BA0 44A0 44A0 44A0 38A0 00A0 00A0 ENDCHAR STARTCHAR U+D5E5 ENCODING 54757 SWIDTH 935 0 DWIDTH 12 0 BBX 10 8 0 1 BITMAP 1080 FE80 4780 4480 3880 0080 0000 1FC0 ENDCHAR STARTCHAR U+D5E8 ENCODING 54760 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D5EC ENCODING 54764 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D5F4 ENCODING 54772 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 0000 3FE0 2020 2020 1FE0 ENDCHAR STARTCHAR U+D5F5 ENCODING 54773 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D5F7 ENCODING 54775 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 0000 0080 0080 0340 1C30 ENDCHAR STARTCHAR U+D5F9 ENCODING 54777 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 47A0 44A0 38A0 00A0 0000 1FC0 2020 2020 1FC0 ENDCHAR STARTCHAR U+D600 ENCODING 54784 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 0040 FFC0 0040 3C40 43C0 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+D601 ENCODING 54785 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D604 ENCODING 54788 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D608 ENCODING 54792 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 4440 45C0 3840 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D610 ENCODING 54800 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D611 ENCODING 54801 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D613 ENCODING 54803 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 0200 0500 0880 3060 ENDCHAR STARTCHAR U+D614 ENCODING 54804 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 0880 0880 1540 2220 ENDCHAR STARTCHAR U+D615 ENCODING 54805 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FFC0 2440 43C0 4240 3C40 0000 1F80 2040 2040 1F80 ENDCHAR STARTCHAR U+D61C ENCODING 54812 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 00A0 FFA0 00A0 38A0 47A0 44A0 44A0 38A0 00A0 00A0 ENDCHAR STARTCHAR U+D620 ENCODING 54816 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FFA0 44A0 47A0 38A0 00A0 0020 2000 2000 2000 1FE0 ENDCHAR STARTCHAR U+D624 ENCODING 54820 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FFA0 44A0 47A0 38A0 00A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D62D ENCODING 54829 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FFA0 44A0 47A0 38A0 00A0 0000 2020 3FE0 2020 1FE0 ENDCHAR STARTCHAR U+D638 ENCODING 54840 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 FFC0 1100 2080 2080 1F00 0400 0400 FFC0 ENDCHAR STARTCHAR U+D639 ENCODING 54841 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+D63C ENCODING 54844 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D640 ENCODING 54848 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D645 ENCODING 54853 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0A00 7B80 4200 3FC0 ENDCHAR STARTCHAR U+D648 ENCODING 54856 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D649 ENCODING 54857 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D64B ENCODING 54859 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+D64D ENCODING 54861 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+D651 ENCODING 54865 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0400 FFE0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+D654 ENCODING 54868 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 1440 2270 2240 1C40 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D655 ENCODING 54869 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2270 1C40 0840 7F40 0000 3FC0 0040 0040 ENDCHAR STARTCHAR U+D658 ENCODING 54872 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2270 1C40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D65C ENCODING 54876 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2270 1C40 0840 7FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D667 ENCODING 54887 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2270 1C40 0840 7F40 0000 0100 0680 3860 ENDCHAR STARTCHAR U+D669 ENCODING 54889 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2270 1C40 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+D670 ENCODING 54896 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 38A0 00A0 FEA0 28A0 44E0 44A0 38A0 10A0 7EA0 00A0 00A0 ENDCHAR STARTCHAR U+D671 ENCODING 54897 SWIDTH 935 0 DWIDTH 12 0 BBX 10 9 0 0 BITMAP 1080 FE80 44C0 4480 3880 1080 7E80 0000 3FC0 ENDCHAR STARTCHAR U+D674 ENCODING 54900 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 44E0 44A0 38A0 10A0 7EA0 0020 2000 2000 1FE0 ENDCHAR STARTCHAR U+D683 ENCODING 54915 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 44E0 44A0 38A0 10A0 7EA0 0000 0100 0680 3860 ENDCHAR STARTCHAR U+D685 ENCODING 54917 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 44E0 44A0 38A0 10A0 7EA0 0000 1FC0 2020 1FC0 ENDCHAR STARTCHAR U+D68C ENCODING 54924 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 1440 2240 2240 1C40 0840 7F40 0040 0040 ENDCHAR STARTCHAR U+D68D ENCODING 54925 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7F40 0000 3FC0 0040 0040 ENDCHAR STARTCHAR U+D690 ENCODING 54928 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7F40 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D694 ENCODING 54932 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D69D ENCODING 54941 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7F40 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D69F ENCODING 54943 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7F40 0000 0100 0680 3860 ENDCHAR STARTCHAR U+D6A1 ENCODING 54945 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0840 7F40 0000 1F80 2040 1F80 ENDCHAR STARTCHAR U+D6A8 ENCODING 54952 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 FFC0 1100 2080 2080 1F00 1100 1100 FFC0 ENDCHAR STARTCHAR U+D6AC ENCODING 54956 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 1100 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D6B0 ENCODING 54960 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 1100 FFE0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D6B9 ENCODING 54969 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 1100 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D6BB ENCODING 54971 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 1100 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+D6C4 ENCODING 54980 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1F00 0000 FFE0 2080 2080 1F00 FFE0 0400 0400 0400 0400 ENDCHAR STARTCHAR U+D6C5 ENCODING 54981 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 0400 7FC0 0040 0040 ENDCHAR STARTCHAR U+D6C8 ENCODING 54984 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 0400 4400 4000 3FC0 ENDCHAR STARTCHAR U+D6CC ENCODING 54988 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 1F00 FFE0 0400 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D6D1 ENCODING 54993 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 1F00 FFE0 0400 7BC0 0A00 7B80 4200 3FC0 ENDCHAR STARTCHAR U+D6D4 ENCODING 54996 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 0400 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D6D7 ENCODING 54999 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 0400 0200 0D00 70C0 ENDCHAR STARTCHAR U+D6D9 ENCODING 55001 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 0400 3F80 4040 3F80 ENDCHAR STARTCHAR U+D6E0 ENCODING 55008 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7F40 0840 0BC0 0840 0840 ENDCHAR STARTCHAR U+D6E4 ENCODING 55012 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 44C0 4440 3840 0040 7F40 0840 2840 2000 1FC0 ENDCHAR STARTCHAR U+D6E8 ENCODING 55016 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 44C0 3840 7F40 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D6F0 ENCODING 55024 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 44C0 4440 3840 0040 7F40 0840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D6F5 ENCODING 55029 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 44C0 4440 3840 0040 7F40 0840 1F80 2040 1F80 ENDCHAR STARTCHAR U+D6FC ENCODING 55036 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 44A0 44A0 38A0 00A0 7EA0 10A0 13A0 10A0 10A0 ENDCHAR STARTCHAR U+D6FD ENCODING 55037 SWIDTH 935 0 DWIDTH 12 0 BBX 10 9 0 0 BITMAP 1080 FE80 4580 4480 3880 0080 7E80 1080 3FC0 ENDCHAR STARTCHAR U+D700 ENCODING 55040 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 45A0 44A0 38A0 00A0 7EA0 10A0 3020 2000 1FE0 ENDCHAR STARTCHAR U+D704 ENCODING 55044 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 45A0 44A0 3EA0 10A0 3FE0 0020 3FE0 2000 1FE0 ENDCHAR STARTCHAR U+D711 ENCODING 55057 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 10A0 FEA0 45A0 44A0 38A0 00A0 7EA0 10A0 1FC0 2020 1FC0 ENDCHAR STARTCHAR U+D718 ENCODING 55064 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7F40 0840 0840 0840 0840 ENDCHAR STARTCHAR U+D719 ENCODING 55065 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 0840 3FC0 0040 0040 ENDCHAR STARTCHAR U+D71C ENCODING 55068 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 0840 2840 2000 1FC0 ENDCHAR STARTCHAR U+D720 ENCODING 55072 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 3840 7FC0 0840 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D728 ENCODING 55080 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 0840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D729 ENCODING 55081 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 2840 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D72B ENCODING 55083 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 0840 0100 0680 3860 ENDCHAR STARTCHAR U+D72D ENCODING 55085 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 7FC0 0840 1F80 2040 1F80 ENDCHAR STARTCHAR U+D734 ENCODING 55092 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1F00 0000 FFE0 2080 2080 1F00 FFE0 1100 1100 1100 1100 ENDCHAR STARTCHAR U+D735 ENCODING 55093 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 1100 7FC0 0040 0040 ENDCHAR STARTCHAR U+D738 ENCODING 55096 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 1100 5100 4000 3FC0 ENDCHAR STARTCHAR U+D73C ENCODING 55100 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 1F00 FFE0 1100 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D744 ENCODING 55108 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 1100 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D747 ENCODING 55111 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 1100 0200 0D00 70C0 ENDCHAR STARTCHAR U+D749 ENCODING 55113 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 1100 2080 1F00 0000 FFE0 1100 3F80 4040 3F80 ENDCHAR STARTCHAR U+D750 ENCODING 55120 SWIDTH 935 0 DWIDTH 12 0 BBX 10 10 0 -1 BITMAP 1F00 0000 FFC0 1100 2080 2080 1F00 0000 0000 FFC0 ENDCHAR STARTCHAR U+D751 ENCODING 55121 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 7FC0 0040 0040 ENDCHAR STARTCHAR U+D754 ENCODING 55124 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 4000 4000 3FC0 ENDCHAR STARTCHAR U+D756 ENCODING 55126 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0080 47E0 4240 3980 ENDCHAR STARTCHAR U+D757 ENCODING 55127 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D758 ENCODING 55128 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 FFE0 0000 7FC0 0040 7FC0 4000 3FC0 ENDCHAR STARTCHAR U+D759 ENCODING 55129 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 FFE0 0000 7BC0 0840 7840 4040 3C40 ENDCHAR STARTCHAR U+D760 ENCODING 55136 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D761 ENCODING 55137 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 4040 7FC0 4040 3FC0 ENDCHAR STARTCHAR U+D763 ENCODING 55139 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 0400 1B00 60C0 ENDCHAR STARTCHAR U+D765 ENCODING 55141 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 1F00 0000 FFE0 0000 3F80 4040 3F80 ENDCHAR STARTCHAR U+D769 ENCODING 55145 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0400 FFE0 2080 2080 FFE0 0000 7FC0 4000 7F80 4000 3FC0 ENDCHAR STARTCHAR U+D76C ENCODING 55148 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1C40 0040 7F40 1440 2240 2240 1C40 0040 7FC0 0040 0040 ENDCHAR STARTCHAR U+D770 ENCODING 55152 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7FC0 0040 2000 2000 1FC0 ENDCHAR STARTCHAR U+D774 ENCODING 55156 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 7FC0 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D77C ENCODING 55164 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7FC0 0040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D77D ENCODING 55165 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7FC0 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D781 ENCODING 55169 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 0840 7F40 2240 2240 1C40 0040 7FC0 0040 1F80 2040 1F80 ENDCHAR STARTCHAR U+D788 ENCODING 55176 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 3C40 0040 FF40 0040 3C40 4240 4240 4240 3C40 0040 0040 ENDCHAR STARTCHAR U+D789 ENCODING 55177 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0000 3FC0 0040 0040 0040 ENDCHAR STARTCHAR U+D78C ENCODING 55180 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0040 2000 2000 2000 1FC0 ENDCHAR STARTCHAR U+D790 ENCODING 55184 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FE40 4440 4440 3840 0040 3FC0 0040 3FC0 2000 1FC0 ENDCHAR STARTCHAR U+D798 ENCODING 55192 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0000 3FC0 2040 2040 1FC0 ENDCHAR STARTCHAR U+D799 ENCODING 55193 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0000 2040 3FC0 2040 1FC0 ENDCHAR STARTCHAR U+D79B ENCODING 55195 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0000 0100 0280 0C40 3020 ENDCHAR STARTCHAR U+D79D ENCODING 55197 SWIDTH 935 0 DWIDTH 12 0 BBX 10 11 0 -2 BITMAP 1040 FF40 2440 4240 4240 3C40 0000 1F80 2040 2040 1F80 ENDCHAR ENDFONT simutrans-124.3/simutrans/history.txt000066400000000000000000014402711474050137200200530ustar00rootroot00000000000000Release of 124.3 (r11590 on 10-Jan-2025): FIX: open schedule get applied during rw (reload, quit, change language), line window crashes CHG: no way foreground drawn inside stations and depots (and other buildings) FIX: loading of roadsings broken for player >=8 and old versions CHG: create lost players during game loading to recover more from broken savegames FIX: handle focussed objects in tab correctly (like comboboxes) ADD: (from simutrans OTPR) tool 44 for generating macro building scripts including terrafroming and station and extension buildings (rebuilding may fail of connection station tiles had been deleted or are outside of the marked area) CHG: squirrel script can now also include any file in the script program directory ADD: pipette tool (started by ceeac, extended to copy and check for more objects) FIX: convoi length bar not so long to need immediately a scrollbar ADD: manually increase tool icon size in display settings window FIX: keep current tile's climate on lower/raise if climate mode is humidity based ADD: error message if digging below water table ADD: scenario can now allow and forbid specific way tools (also sped up the forbid list processing) CHG: Making the road in front of the city hall one tile longer to each side, so city growth works with any set cityrules FIX: also connect bridges to tunnels in pak128 double slope situations FIX: Station rotation preview ignored active player (always showed player 0 colours) FIX: if a convoi served a station but did not load anything (maybe full), another convoi did not check this stations and could get stuck even with waiting for zero load ADD: allow cubic rule that overrideds any forbidden cubic rules and explicit clear rules calls FIX: screnario allow and forbid rules were handling wildcard badly. Also, ignore_wt should be used for ignore this parameter (no enforced in rule creation) ADD: clear rules of a single player FIX: Possible crash when deleting stops during connection recalculation on large maps ADD: scaling of icon size is now in percent to be independent from actual icon sizes (icon_scaling = 100) FIX: Failed to find city- or streetlists for paksets installed in non-default locations (e.g. simutrans/paksets/) FIX: Removal tool removes powerlines of other players FIX: Player colours of scripted AIs appear to revert to the default colours on reload FIX: Tree distribution setting reverts to random when trees are disabled during new world generation FIX: some tools were not added in all neccesary places CHG: hm_city_tl, hw_way_tl, hm_house_tl, hm_set_owner_tl accepts now also coord instead coord3d Release of 124.2.2 (r11400 on 2-Sep-2024): ADD: Support for through depots (dims 2) FIX: proper building of parallel ways also for elevated ways FIX: no public chat after private FIX: halt are properly reconnected FIX: if convoi load in parralele without minimum load, the second convoi could leave empty FIX: again retire convois when empty FIX: obj_count() did not count ways and was a relict that may have caused rare strange errors in other places FIX: Longstanding bug with the size of scrollpanes with horizontal sliders FIX: company messages again, properly show messages in ticker, open chatframe for viewing on ticker click CHG: packing planqudrat_t reduces size by 2 byte (32 bit 12->10) or 6 byte (24->18) and accelerates sync_step by 10-20% (only on Intel on GnuC compatible compilers) FIX: rotation workin again Release of 124.2.1 (r11365 on 25-July-2024): FIX: player_ranking transport type was not set_rigid => crash on all general comparison FIX: do not carry over old chat messages to new games CHG: when merging stops, keep the name of the bigger stop FIX: insticky bottom on drag to allow scrolling of chat FIX: too many null mouse moving events in SDL2 broke double clicks CHG: double click copies chat text FIX: wrong colors and double messges for private chat messages FIX: was not iterating over all stops correctly => wrong passengers spawned Release of 124.2 (r11351 on 20-July-2024): FIX: BASE_DIR/config/simuconf.tab was not read when "-singleuser" was used FIX: right button scrolling on minimap was broken ADD: new option leftdrag_in_minimap in simuconf.tab to allow dragging in minimap with left mouse button (now default) FIX: reenable dragging of stations FIX: Cargo not always loading onto vehicles in large games CHG: Reconnect to network games unless kicked out with desync CHG: Allow again building roads through other people halts but do not take road ownership afterwards FIX: Always have topped or new windows on the screen FIX: Saving discarded the newest messages FIX: number of players online in chat window now correct (and also showing offline state) ADD: prefer to build parallel ways, if starting next to an existing way FIX: overflow in bits in private way sign could allow/deny unexpectant players FIX: loading pak from savegame again (so only savegame needed on commandline) CHG: Activate input field if chat is active or after sending message ADD: restore open windows when rejoining a network game ADD: restore pakset symbols after changing the gui skin CHG: don't save default player colours with the settings/game, use pakset simuconf.tab only CHG: if only_single_info=0 now tiling the info windows. If there is a convoi or halt, not way or other info will be shown (default for Android) CHG: Try to resize windows if they do not fit on screen CHG: Continue game on banner will really continue a game and not destroy the current one by loading an older version CHG: Better support for narrow but high (portrait) screens CHG: A new game always uses the settigns from the simuconf.tab. Use the buttons in the extended settings to load other values ADD: new simple tool 42 for toggle day night view CHG: line list, load dialoges and online game windows shrunk in width ADD: left moving minimap insted of dragging location to have easier use with touch devices Release of 124.1 (r11272 on 3-June-2024): FIX: Cannot build ship depots on dead-end canal or river tiles CHG: Freetype library is now a required dependency for non-server builds (previously it was optional) FIX: Possible crash for systems with more than 12 logical cores FIX: In-game pakset installer does not download paksets, caused by incorrect handling of HTTP response FIX: Required data directories not created on first installation on Windows FIX: passenger AI crashed the game FIX: renaming town crashed, and renaming factories was almost impossible, renaming convoys still required enter FIX: New world tool had wrong tooltip and hide building was never in selected state ADD: (ranran) new chat window (dialog tool 36) and chat message system using direct and company chat options as well CHG/FIX: Updating the line schedule of a convoi bound to this line will overwrite any pending changes from that schedule if open in the schedule window FIX: dimensions of info windows more approprioate again ADD: (ranran) player ranking frame as dialog tool 37 ADD: help files will be also searched in pak set text directories Release of 124.0 (r11164 on 5-May-2024): ADD: map view can be changed with any general tool by dragging the pointer above a threshold FIX: Cannot load PPM heightmaps ADD: new tool (and button in signal dialog) for removing signals only CHG: only load goods for a destination into a single convoi. This avoids loading in parallel of slow loading convois CHG: More search paths for paks, new parameters -set_base_dir, -set_pak_dir, -set_user_dir CHG: Simutrans tries for base files also in the current path without any parameter (also in program location) ADD: single toolbar mode: Enabled only one top-centered toolbar CHG: Mouse clicks etc. are now processed every frame (but maybe executed later) to avoid the lagging UI at large zoom out or with weak devices ADD: tooltip warning when trying to cross way without suitable crossing or curves on runways ADD: Pak files are now additionally searched for in up to 4 subdirectory levels within a pakset ADD: theme parameter gui_color_image_transparency to set transparency color for icons (Yona-TYT) CHG: messages, speed records, ticker use 3d coordinates CHG: a go-to-coordinate action will change to underground/normal view if the target is invisible FIX: Crash when using 'makeobj list ' in some cases FIX: Crash when using 'makeobj dump ' in some cases ADD: Signals can be replaced by overbuilding them using left-click FIX: Wrong brightness of colours in screenshots FIX: Graphical glitches related to translucent player colours FIX: Makeobj ignored switch images for tracks with no seasons (e.g. image[new2]=...) FIX: massive swallowing of touch event to keep the game responsive despite SDL2's denial of service flooding FIX: airplane convois do no longer crash the game (but are not working perfect yet ...) FIX: graphical glitches when road convois change direction in some cases and on overtaking with drive on left FIX: (THLeaderH) crossings upgrade when ways are upgraded CHG: state of switches (images) save during reloading ADD: new parameter in simuconf.tab "cityroad_speeds" for a timeline (year,new_speed) of speed limits of way with pavement ADD: rotate house tool will also switch railroad switches (eyecandy only) FIX: height map conversion version is ignored if it is selected after height map in the height map selection dialogue FIX: Withdraw All button in line window did not indicate withdraw status correctly in some cases FIX: Game lags when paused, especially on big maps FIX: Could connect elevated way to side of sloped elevated way FIX: more respone event handling at low frames per second FIX: consequently in lists left click->window richt click/Control+left click -> goto position ADD: obj_xxx_details in translation will display some more details on an obj, especially vehciles CHG: editing names or filter will become immediately active CHG: Windows installer no longer requiring admin rights ADD: Antialiased fonts and using TTF fonts of the system by default Release of 123.0.1 (r10421 on 29-Jan-2022): ADD: button to remove double entries in schedules FIX: up/down arrows in schedule broken FIX: Simulation speeds up uncontrollably in some cases if New World dialogue is open CHG: lang files are loaded if their name is *XX.tab or XX*.tab. The first is preferred to avoid confusion by name like ja-taken.tab ADD: selected convoi in minimap now magenta. Also network display properly updated when activating or closing windows ADD: Option to adjust screen scaling manually (either via display settings or '-screen_scale' command line option) ADD: All resizeable windows will have a minimize button in the title ADD: Illegal schedule entries are highlited and a button to clear them up will appear. ADD: Infinite mouse scrolling can be activated manually in the display settings; but it will fail with certain touch devices CHG: new versions of pak48.excentrique, pak64.german, pak128, pak128.German Release of 123.0 (r10317 on 30-Dec-2021): KNOWN BUG: ugly movement of pedestrians on diagonals/curves FIX: map enlargement crashes with new climate generator FIX: Wrong tooltip when building something with the finance window opened CHG: Sound now plays on GDI via Xaudio2 for individual volume control ADD: map only moves when numlock off, new tool to move to map view (simple_tool[36]=,keybinding,-1|0) ADD: new option in simuconf.tab "numpad_always_moves_map" regardsless of numlock state FIX: Wrong loading of 24 bit BMP heightmaps FIX: Wrong loading of 8 bit greyscale BMP heightmaps if width is not divisible by 4 ADD: New height conversion modes when loading heightmaps CHG: schedule/line now tab of convoi window instead independent window CHG: new line list, overhauled convoi list CHG: rivers now go to the sea and pass through lakes. A tiny stream becomes navigatable after a lake or merging with another stream FIX: MessageOptions can be three single images (id=0,1,2) instead of one large image FIX: Potential hang when loading zstd compressed save files when multi-threading is enabled CHG: crossing speed is now the max speed. No crossing, if one speed higher than maxspeed ADD: construction cost tooltip also for normal tunnel construction (clicking on slopes) FIX: Graphical glitches when resizing SDL2 window with -autodpi ADD: special key "SCORLLOCK", "DELETE", ESCAPE", BACKSAPCE" and "+" sign for shift as modifer in tools key binding ADD: waiting time in schedules is now entered in days hours minutes (but old games will still have the old steps) ADD: (Leartin) groundobj editor and totally overhauled edit windows FIX: Fatal error when querying servers running very old versions FIX: tunnel can now also connect to sidewards tunnel (as originally intended by the code) ADD: target tile for jumping to a position (via pos button, window icon or jump dialog) will be marked with the current cursor FIX: Crash when height difference between climate border and groundwater is >127 FIX: Crash on reload after lowering canal with a ship on a nearby tile FIX: Crash when liquidating company owning a non-empty underground depot FIX: Crash when liquidating company owning a house CHG: gradual unloading and loading if loading_time of a vehicle > 2000 CHG: schedule with load level zero and waiting time will force daparture at eaxactly this time ADD: chat window transparency in network mode now controlled by theme: gui_color_chat_window_network_transparency and gui_chat_window_network_transparency CHG: search dialoges now consistent design, text search, preserved during saveload ADD: menubar can be now top bottom left or right ADD: reselect a tool will close it (new default, set by reselect_closes_tool in menuconf.tab) FIX: Grid height not restored when removing building on a raised tile CHG: maintenance of powerline tunnel/underground transformer maintenance is now maintenance of powerline + that of tunnel ADD: reservation overlay now also shows single way directions and signal states (inspired from ranran) CHG: absolute departure time can be also more than once per month (repeats the time in equal intervals) FIX: Public player cannot make halts of other players public CHG: Smaller file sizes (~20% for forested maps) for single player saves CHG: Simutrans now allows more than one file per languange. The file must just ending in XX.tab, where XX is the language code ADD: Command line option '-scenario' starts requested scenario if available FIX: Trains brake two tiles too late when entering a terminal station via a long block signal CHG: window rollup also with double click CHG: stop_halt_as_scheduled=1 in simuconf.tab will stop trains at the desginated tile instead going to the end of the platform Release of 122.0 (r9274 on 10-Oct-2020): FIX: Rotation of multi-tile buildings at street corners ADD: different volumes for different sounds, realistic distance scaling (independent from screen size) CHG: Fade sounds with one over square root distance, and remove the dependency from display and tile size ADD: Depot list as dialog tool 32 FIX: city more strongly attempt to build double height bridges over navigable rivers ADD: Vehicle list as dialog tool 33 (to see also upcoming vehicles) ADD: goods waiting bar with now configurable: gui_waitingbar_width ADD: button to copy the last 20 messages to the clipboard CHG: factory smoke location now depended on factory. Four parameters smoketile[], smokeoffset[] (koord), and smokeuplift (16) and smokelifetime (2499) FIX: several list stored wrong coordinates after map rotation FIX: Too new pak file version check now enforced for all objects FIX: airplane should stuck much less upon runway rebuilds CHG: block reserver tool will also start a route search of any convoi on its tile (no matter the owner!) ADD: timeline switches off after 2999 to prevent retiring of everything ADD: new parameter for buildings "preservation_year" and "preservation_month" after that the building is excluded from renovation during town growth ADD: if shift is pressed during road building then city roads or faster ways will not be overbuilt ADD: more folders searched for fonts on non-windows systems FIX: broken connection could kill (especially server) games on Linux ADD: customisable loading bar colors with gui_color_loadingbar_inner and gui_color_loadingbar_progress CHG: record messages and some status messages are now not saved, while stuck and full stations expire after a month on server chat to keep overview ADD: new button in minimap to hide contour for higher contrast of other stuff CHG: Option to show convoi name and line name as overlay ADD: (inspired by Ranran) Option in city, curiosity, and factory lists to show only towns/factories already served by a player ADD: two more theme colors: gui_color_obsolete, gui_color_empty for lines and server ADD: (Yona-TNT) configurable offsets for player colors for gui elements ADD: convois (in convoi list and schedule) also show their next stop with a posbutton to jump there ADD: caseless matching in depots, lines, halt and convoi list dialogs even with umlaute CHG: fixed vehicle costs are now booked as running costs at the begin of a month, also convoi details changed to accomodate CHG: a server will pause without clients if '-pause' is set on the command line ADD: freight type filter on line window CHG: speedup of map generation by reorganising and multithreading lake code ADD: defining overlapping climate height limits will generate maps with climate patches at these heights FIX: (extremly old bug) after removing a house on a slope the world height grid was not restored FIX: factory extension during city growth could no cope with more than one supplier for two goods ADD: scripted tools (initial patch by THLeaderH) ADD: Humidity based climates (originally from kireon green) Attention, winter snowline set temperature at sea level, so important! ADD: (FrankP) happy signs for system fonts ADD: (ranran) new GUI element routebar FIX: space.w added in container not space.h for vertical distance CHG: On consequeutive traffic lights, only the first is obeyed to allow turns on four traffic lights crossings Release of 121.0 (r8870 on 1-Dec-2019): ADD: Map number is shown in the enlarge map window. FIX: Text area GUI components no longer suffer from line wrap around when displaying an extreme number of lines. FIX: Stop information window waiting list in "via (amount)" order will no longer count incorrectly when more than 8,388,607 units are headed to a single destination. FIX: SDL2 build running on Windows 10 in fullscreen mode now minimizes and maximizes responsively. CHG: gui overhaul: automatic placement and size calculation of elements ADD: use animated water graphics on shores FIX: Do not call DefWindowsProc for IME to mitigate crash on Windows1809 ADD: always use temporary save name *.sv_ during saving before deleting main file CHG: Make double pak warning translatable FIX: (ACarlotti) rotation of traffic light phases and overflow was broken for years FIX: fields now check for allowed climate, not same height ADD: (HyperSim inspired) new tool for merging distance stations (and lot of code cleanup of old merging tool) ADD: constrait[prev][0]=any require a vehile in front (and same for [next] to require a trailing vehicle) CHG: The acceleration tool now also alters the acceleration in fast forward mode ADD: Up to 3x3 size city buildings, all with up to 8 rotations (attention: New paks using this feature will crash old versions!) FIX: Prevent a crash when the schedule window is open with waypoints on bridges that were destroyed or had planning canceled. FIX: Goods List speed field will now allow selecting speeds appropiate for very fast vehicles. CHG: Revise Goods List for better clarity and usability. FIX: Construction of priority and longblock signals CHG: Start with random midi song ADD: Timeline for pedestrians FIX: IP4 address query for easyserver (to detect IP4 changes sometimes occuring for ADSL connections) ADD: new simuconf.tab parameter follow_convoi_underground to slice through grounds to follow a convoi in sliced mode oder full underground mode ADD: search for midi files first in pak folder, then user folder, then program folder ADD: GUI for pakset install script Release of 120.4.1 (r8600 on 23-Sep-2018): FIX: wrong graphics with greedy block signals FIX: world minimum height could not be set FIX: location forest could not work with factories smaller than 3x3, since not enough inner tiles were iterated Release of 120.4 (r8588 on 17-Sep-2018): FIX: properly handle dualstack servers by using both IPv4 and IP6 addresses (if no symbolic name is available) ADD: (HyperSim) sorting vehicles in depot ADD: system clipboard support now also with SDL2 FIX: underground slice view now correctly displays front tile walls when a tile infront is flat and 2 elevations below the underground slice OPT: significantly improved the performance of changing underground mode/slice when playing on very large maps ADD: More factory locations (shore, river, forest) to the existing city, water, land ADD: (THLeaderH) option to hide the revenue income messaging at stops ADD: (THLeaderH) configurable height setting for extremely heigh maps (use at own risk) ADD: (gauthier) "priority" signals (greedy multi block signals) FIX: different obj (ways, bridges, tunnels, ... ) with same name failed for checksum comparision Release of 120.3 (r8503 on 15-June-2018): ADD: new blue-white theme ADD: new general tool 40 which rotates buildings ADD: scenario_info now dialog tool nummer 31 ADD: Support Truetype fonts on windows up to 19 pts. For MAC and Linux support there is a way needed to find the font path. ADD: Server can be now started at the UI when loading a game. ADD: switch -easyserver on commandline to host a game with dynamic IP behind a router FIX: crash when resizing isometric minimap FIX: problems with scrolled lists ADD: (Ichou) force replacement of wayobj by holding ctrl key while building ADD: (THLeader) long convoi patch FIX: removed line management window memory leaks ADD: animated pedestrians, parameters: steps_per_frame (internal steps per frame, straight movement across tile is 256 steps) image[dir][a] (dir - direction, a - animation counter, a=0,1,..) CHG: pedestrian movement, new dat parameter: offset (of pedestrian image relative to right tile boundary, 0..255, default 20, 0 = on the right edge of tile, 128 = on center line of tile FIX: corrected container UI component focus logic (fixes http://forum.simutrans.com/index.php?topic=17277 ) FIX: added redraw logic for field removal (fixes http://forum.simutrans.com/index.php?topic=17308 ) FIX: added Unicode file path support for Windows builds FIX: removed Windows builds file search resource leak FIX: improved Windows build clipboard Unicode parsing ADD: sorting in depot (HyperSim) FIX: factories which gain or lose fields should no longer have a chance to break with JIT2 (fixes https://forum.simutrans.com/index.php?topic=17394 ) ADD: sync step barrier for multiplayer clients to prevent them running ahead of the server in the case of an unreliable connection CHG: various multiplayer related settings have been given more reliable default values FIX: fullscreen Windows GDI no longer alters display area when alt+tab cycled ADD: JIT2 demand based production rate scaling CHG: changed factory information view to be easier to understand, especially when operating with JIT2 CHG: speed can be directly selected in goods dialogue FIX: consistent and wider climate borders, also other waterlevels than -2 when loading a relief map Release of 120.2.2: (r8163 on 31-3-2017): ADD: Name filter in depot window FIX: Combo boxes now work much more reliable ADD: Shift+waybuilder on elevated ways selects the tile under the way (for upgrades) FIX: Crash when extending convoy length ADD: All configurable colors now rgb internally Release of 120.2.1: (r8121 on 26-Feb-2017): FIX: SDL2 with non-ASCII input FIX: crashes with SDL2 when resizing FIX: allow docks only next to water CHG: use almost no assembler any more, the compiler can do better than us Release of 120.2: (r8077 on 12-Feb-2016): FIX: sorting according to displayed name in house/cur/industry building lists ADD: scriptable AI players (folder AI which contains sqai now with distribution) ADD: (jk271) switch to load heightmaps with more height levels FIX: reload themes after restart FIX: demo.sve were never loaded, since the auto-load assumed existence even if there was none ADD/FIX: slopes for groundobj now working again. If there are groundobjs with climate water, then these will be used occasionally at the coastline ADD: ground name=shore with Image[slope][0,1=snow, if there] for display at shoreline FIX: smoke tile when rotated factory views ADD: length of max tiles checker after choose sign/signal configurable (max_choose_route_steps) CHG: update to squirrel 3.1 CHG: monthly fixed costs for vehicles now uint32 (needs makeobj 55.4) ADD: basic nearest pixel DPI awareness to prevent UI from being too small on high density displays FIX: no longer assert when duplicate tiles exists in convoy path list, instead it gets logged (please report log if it occurs) FIX: corrected hitbox and resize logic of scrolled list GUI element, which prevents crashes caused by invalid selection CHG: building cities, plant trees, make public, headquarters and artificial slope tools check for sufficient funds CHG: planting trees is no longer possible by companies when no_trees configuration is set CHG: make public tool now works on incline and tunnel entrance ways CHG: make public tool now treats way objects separately from ways ADD: make public tool can be dragged to rapidly make multiple objects public ADD: make public tool cost can be configured ADD: make public tool can be configured to not work on ways or way objects for companies CHG: notifications about ways being made public in multiplayer games are produced less frequently CHG: retained ways from liquidated companies are transferred to the public service player ADD: on multiplayer servers any client capable of using the public service player can bypass password checks for all companies FIX: network core correctly enumerates local bind addresses instead of repeatedly trying to bind to the first local address ADD: support service names for ports in network URNs CHG: cities can now build on tiles with bridge pillars, matching the logic that pillared bridges can be placed over city buildings FIX: incorrect scaling of electricity revenue with respect to month length FIX: electricity related information now accurately reflects the last tick of the network FIX: electricity networks are no longer prone to arithmetic overflow which could result in incorrect graphics or income FIX: electricity networks no longer skip a power tick or lose revenue accumulators during a save/load cycle CHG: simplified transformer information UI removing redundant or meaningless values CHG: factory power is solved in 1 tick instead of 2 CHG: various improvements to JIT2 to improve factory and electricity network stability CHG: factories which produce power log the amount of power production consumed instead of the amount of power produced CHG: factories which consume power log the amount consumed as negative FIX: F12 no longer brings up the ingame help window in the Steam version of Simutrans Release of 120.1.3: (r7753 on 2-Feb-2016): FIX: road vehicles search for new route when arriving at intersection and old route is invalid ADD: depot vehicle filter now uses selected good for weight/speed calculations when possible for multi-good carrying vehicles CHG:(Vladki) private road signs in the middle of a slope FIX: trains reserve blocks at positions of now removed signals, prevents step-by-step reserving coupled with ignoring red signal if signal is removed in front of a waiting train FIX: route search to next depot has to be done synchronous on all clients ADD: ctrl-click on flat-dock icon to choose orientation Release of 120.1.2: (r7720 on 7-Jan-2016): ADD: configurable compass for minimap, rotation tool, and main screen ADD: tool for last used tools FIX: improve bridge building FIX: (Ters) Map scrolling speed on Windows with high DPI displays FIX: (DrSuperGood) general JIT2 fixes CHG: better multiplayer client timing FIX: uninitialized variables leading to online desyncs Release of 120.1.1: (r7640 on 4-Nov-2015): FIX: corrected bookkeeping of stops and passengers, including walked ones which could lead to crashes Release of 120.1: (r7634 on 31-Oct-2015): FIX: sliced underground mode now ranges from lowest existing to highest existing ground FIX: several issues with bridge building and deletion at two vertical cliffs ADD: new industrial demand model just_in_time=2, which models factory ordering stuff ADD: new tool for trimming lines (linetool, parameter trim, line_id_id egal, linetype (integer), target percentage (integer): will delete lines until target met or less than four convois left on line ADD: configurable offsets for signs/signals (use offset_left = 0, for not moving, default 14) Release of 120.0.1: (r7373 on 15-Nov-2014): FIX: waypoints on runways to force certain runways for planes work finally (hopefully) FIX: some bridge starting on flat tile going done were not correct FIX: Unicode input under Windows 8 FIX: lot of issues with new landscape code Release of 120.0: (r7175 on 28-Apr-2014): CHG: zoom with mouse wheel zooms to the cursor position, not to the center of screen as it used to CHG: system events management rearranged, simutrans should more responsive to user events, specially on low framerates ADD: second_open_closes_win =1 in simuconf.tab will close open window instead top them on second call/click ADD: remember_window_positions=1 (default) will remember last window positions FIX: (S_N_C) net wealth was not consistent after buying vehicles ADD: (kierongreen) double heights (slopes), different water levels per tile, and per tile climates FIX: long block signals direct in front of stations gave deadlocks ADD: fixed maintenance for vehicles is now booked ADD: (jk271) way toll statistics now ADD: (neroden/kierongreen) stacked stations with different owners are now possible ADD: loading gui themes (designs) on runtime ADD: faster creating of hill ADD: matching pak is loaded automatically when no -objects is given with -load on commandline ADD: dragging map also with left mousebutton when the query tool is selected ADD: display also fixed cost in convoi details and depot (if set) ADD: enforce loading time (time will be long of all vehicles, default 1s) ADD: makeobj can now warn about unused entries (makeobj verbose pak... or makeobj debug pak...) CHG: Stretchable themes now in trunk CHG: use faster route search for ships (jump-point search) CHG: max in_transit now depends on the sum of all connected factories output storage times the in_transit percentage ADD: goods in transit are now recalculated whenever a game is reloaded CHG: overcrowded message no longer for factories supplied by producer but only interchanges CHG: Waypoints act no longer as signals ADD: server_motd_filename for file with a greeting message in online games ADD: more option to select network overlay in minimap Release of 112.3: (r6520 on 17-May-2013): CHG: Removed the restriction of having border heights at water level. Forces a savegame version step, new maps can't be properly shown in previous versions. CHG: Raise and Lower tools interact with the grid now, not with tiles. ADD: (jk271/Dwachs) finance history distinguishes transport type CHG: Added a new setting to simuconf.tab, background_color. Allows to change the color of the background. ADD: Departure and arrival times can be shown in the halt dialogue CHG: Updates to the in-game pointer mechanics, updates its position after using a tool, and hides when the pointer is outside the world. ADD: (neroden) clustering of houses, set "cluster_factor" in cityrules.tab to about 10 times the typical distribution weight ADD: Displaying the natural slope at the map border if requested (default on) Release of 112.2: (r6390 on 17-Mar-2013): ADD: maximum radius of factories of a chain configurable CHG: use more colors to show height levels in minimap CHG: loading screen reworked graphically and in functionality. Lowers the chance the OS will identify Simutrans as "not responding" when loading large files/paks. CHG: lots of extensions of scenarios Release of 112.1: (r6212 on 23-Dec-2012): ADD: transparent chat window in networkmode FIX: underground stations in networkmode ADD: (Markohs) Scenario and heightmap dialogs now support multi-directory ADD: (Markohs) File dialogs deletes now use the trash bin (by default) instead of a permanent delete in Windows platform. SHIFT overrides. FIX: waiting level in schedule dialog works with keys again FIX: convoi list filtering again in working order ADD: hide by default return ticket for rail based transport (enable by simuconf.tab) ADD: possibility to limit the amount of goods in transit (see simuconf.tab) ADD: city attractions and town halls can be defined to be build for more than 65535 citizens FIX: you will need a dock to connect to an oil rig => no islands or tunnel can be used any more => ships only load at docks ADD: display which factories supplied/received goods last month ADD: player without operations can be deleted after x month ADD: player without new building/replacing activities can lose password protection ADD: logging of ip/nickname of company creators ADD: nettool commands to lock, unlock, remove a company ADD: (Timothy) support for syslog (compile flag -DSYSLOG, command-line option -syslog) ADD: Restore city window on joining ADD: Restore chat window on joining ADD: Restore factory window on joining FIX: correctly remove stale freight from convois when stops are joined or tiles are deleted FIX: less desyncs when renaming, better processing server queue Release of 112.0: (r6000 on 22-Oct-2012): ADD: (wackdone) screenshots of topmost dialogue window only by CNTRL+screenshot tool click ADD: (wackdone) -pause on command line pauses the loaded game FIX: downgrading of stops using CONTRL works again ADD: scripted scenarios ADD: river algorithm faster and river number automatically scaled with map size CHG: proper support for non-rectangularly shaped factories, no dummy (0,0)-tiles ADD: support for non-rectangular shaped station extensions, attractions, monuments CHG: Allow to connect to channels built by anyone CHG: fields can now spawned in larger number than the initial min value CHG: number of factories in new world dialog is now indeed the total number of factories (too many newbie mistakes here) ADD: force a minimum distance between city attractions CHG: Bankruptcy check before subtracting maintenance ADD: Drag stops CHG: reduced memory consumption when compiled with COLOUR_DEPTH=0, no copies of object images kept in memory ADD: ctrl-click with link-factory tool actually removes links between factories ADD: station buildings can be restricted to above/under ground (parameter allow_underground, =0 only above, =1 only under, =2 both/default) CHG: rework scenario directory structure: scenario my_scen is in my_scen/, script file is my_scen/scenario.nut Release of 111.3.1 (r5843 on 31-Jul-2012): ADD: weight in dat fields are in tons but kg can be given as 1.350 CHG: goto / follow convoi functionality via window gadget CHG: no bridges over runways / taxiways ADD: check whether format specifiers of translated strings match those of the master string, start with -debug 2 to get error messages ADD: customize icon of toolbar separator (taken from menu.BarTools or extra menu object) FIX: crash when changing to other programs while in fullscreen with GDI version Release of 111.3 (r5772 on 10-Jun-2012): FIX: race condition with multithreads on GDI CHG: savegames will be saved as "_temp.sve" and only renamed after after success to the final name ADD: screen redraw will be now up to 50% faster when needed thanks to multi-threading ADD: hashtables for animations and smoke => much faster adding/removing ADD: (from yorkeiser/prissi) line display in minimap (toggle with show schedule together with pax, mail, freight button) CONTRL will use player colors CNG: Order and function of many minimap buttons rearranged ADD: enable dragging of lower & raise tools in network mode ADD: enable dragging of bridge, tunnel, elevated way tools in network mode ADD: zoomlevel in minimap from -16 to 16 ADD: Start paksetdownloader, when started without paksets FIX: (z9999+) Corrected speedbonus base factor calculations FIX: (z9999+) Nickname in chat also send to server for reloads FIX: (installer/pakset updater) better finding out if portable installation is needed ADD: change of waiting at stops option in minimap CHG: Withdraw all will not disassemble convois in depots for easier upgrading FIX: route search for runways with oneway signs was broken FIX: main menu was not updated when new modes of transport became available ADD: (kierongreen) powerline tunnels: allow_undergroud_transformers=1 (default) will allow transformers below ground FIX: deleting tunnel ground was booked twice FIX: deleting tunnel ground charged for way on tunnel, which is not charged when building CHG: Only founding a city when account is positive CHG: powerlines will connect in directions a powerline can be build on a tile ADD: threaded (but with graphic errors) tile redraw will by used automatically when fps too low FIX: AI used wrong factories for building chains and build too long routes Release of 111.2.2 (r5583 on 20-Mar-2012): CHG: Simutrans help will now always display left the help index and right the actual help => easier navigation and only one window always ADD: nickname for players, enable chat for observers, add messages when players join / change nick / leave FIX: deletion of stops on bridgehead with trams FIX: extended setting of bool was broken FIX: track reservation now saved with game (less deadlocks on load) Release of 111.2.1 (r5434 on 28-Feb-2012): (111.2 had a severe bug with zipped games) ADD: more info on bare ground ADD: show ownership in minimap ADD: bonus_basefactor = 125 incorporated, determines minimum income for slow vehicles in case of speedbonus ADD: hint text in empty schedules ADD: highlight (land)tiles, which are part of a schedule ADD: F1 open dialog help in all dialogs with a help ADD: only show line names which contains a pattern (optional) and other tuning of dialogues ADD: server-side authentication of players ADD: city, industry and attraction numbers scale with map size ADD: front images for ways ADD: goto-button to chat messages, coordinate taken from @x,y or (x,y) CHG: overhauled color choose dialog with ideas from Hajo FIX: lots of double free errors (mostly in network code) FIX: No new buying obsolete stuff, just allow appending Release of 111.1 (r5115 on 23-Jan-2012): FIX: owner of way gates were accidentally rotated ADD: speedbonus speed limited by way speedlimits and achievable convoi max speed ADD: record also walked pax FIX: CJK description of houses correctly breaking ADD: configure modes of transport for AIs FIX: better tree offsets on tiles, should give less errors with trees on roads, in water etc ADD: read (when with addon loading) also ~/Simutrans/pakxyz/config.simuconf.tab ADD: (falconne) hide only objects around cursor ADD: (falconne) hide factories and goods currently not on the map FIX: several bugs with airplanes and reservation ADD: cities build bridges over rivers FIX: clip buildings to not shine through bridges ADD: (falconne) filter vehicles in depots according to their freight FIX: pedestrians on crossings were considered cars after leading FIX: endless loop when fast forward and zooming out too much CHG: using old display routines for zoom out to speed up display CHG: cities will now grow gradually in time and size during creation, starting with 32 citizens in the first townhall year CHG: minimap now really isometric ADD: allow elevated ways over water with depth = 1 FIX: load savegames even if factory pak is missing CHG: pak addons now in folder addons, to have same structure in portable and normal installation ADD: warn about missing pak files after loading a game ADD: logging of speedbonus speed in line window Release of 111.0 (r4911 on 1-Nov-2011): ADD: factory charts ADD: storage capacities scale with base production for factories which do not support fields ADD: factory-going passengers/mail are handled separately ADD: new boost mechanism at factories for passenger, mail and electricity ADD: new factory expansion settings for factories without fields ADD: command-line tool NETTOOL to administer server ADD: start as many trains as you like in a depot without waiting CHG: when building artificial slopes on water, create underwater hill first ADD: cache information about savegames in save/_cached.xml to speed up savegame dialog FIX: presignal on last route index and crossing on last route index could stuck trains ADD: (neroden) display tiles/month equivalent for km/h in goods-list window ADD: way builder can use basic terraforming CHG: gui does not lose focus when new messages appear ADD: AI players use way builder with terraforming CHG: passengers and mail now prefer nearer attractions and cities as destinations, with attraction changing over the years CHG: enable building under flying aircrafts CHG: renovated factory dialog to include statistics and other indicators; preparation for factory renaming FIX: convoi reservation for street convois longer than one tile is now fixed CHG: road vehicles less likely to block intersections or drive through each other when turning ADD: traffic light phasing adjustment ADD: break (pause) button now internally handled as ASCII 16 (^P) ADD: coordinate display and goto button for almost any non-moving thing on the map ADD: loading convois will be overtaken ADD: new file streetlist_xx.txt will be used for stop names for cities. With one parameter the halt type will be used, with two the city name and the halt type ADD: configurable way toll for using other players way (see simuconf.tab) ADD: renaming of factories ADD: private way sign now blocking for specific players CHG: (Timothy) new serverlist without any registration needed ADD: new tool to show block reservations ADD: new tool to show owner of ways and all other objects Release of 110.0.1 (r4359 on 12-Mar-2011): ADD: try to build crossing that match maxspeed of the ways to be crossed ADD: sheep will not walk in cities anymore CHANGE: much smaller savegames in online mode with trees FIX: broken townhalls when the land was flattened before FIX: AI better cleans up when building of shipping lines fails FIX: line IDs are now tied to line handles => no double line ID any more FIX: crashes with window resizing under SDL FIX: convoys stuck after modifying schedule of line ADD: pak set specific pre-defined player colors and random player colors FIX: world enlargement FIX: loading lines with ID zero again Release of 110.0 (r4303 on 14-Feb-2011): CHANGE: default savegame now bzip2 (games 33% smaller) ADD: Odometer and distance per month available for convoys/lines ADD: (gerw) built tunnel without ways FIX: no longer possible for negative prices (cheat bus) ADD: (Dwachs) starting money per year ADD: lines will be listed numerically correct, if the contain a number ADD: bridge building with click-and-drag ADD: traffic light can set their phases now manually (in seconds) (new help text: trafficlight_info.txt, new string: -\nSet phases:-) ADD: some more network related settings like server_frames_ahead, network_ms_ahead, server_frames_per_step to control timing on the network ADD: translations are also search in user dir/scenario/text ADD: (gerw) auto-electrify depot added FIX: freelist sometimes returned wrong elements to free ADD (VS): makeobj ignored alpha channel now really CHANGE: (Knightly): Not scaling images displayed by gui_image_t anymore FIX: deleting tram signals again ADD: click-and-drag also for network games (except for building elevated ways, bridges, tunnels) ADD: tools should work on all clients regardless of underground mode ADD: tools work now correct with ctrl keys in networkmode FIX: a double block (presignal) robbed the following signal of its (pres/longblock/choosing) function CHANGE: no re-zooming in viewport FIX: text overflow in message boxes FIX: window resizing is triggered even if initial click is not in dragger area FIX: square button's clickable area not set according to accompanying text FIX: help text link's clickable area not correctly set FIX: pak file image data not trimmed according to x-offset and contains superfluous data ADD: factories now support multiple fields FIX: factory builder does not consider minimum fields in randomising production FIX: tooltip box hovering above viewport ADD: (mostly Dwachs) nicer crossing infos ADD: bridges/tunnel show their names in info window ADD: (inspired by gerw) choose signals will not choose if on the route is another choose signal or and end_of_choose FIX: text overflow in ground info CHANGE: ground info and thing info title bar color will change according to ownership ADD: allow_buying_obsolete_vehicles in simuconf.tab can disallow buying obsolete vehicles for better balancing FIX: forest density/size nor again reasonable dependent on map size ADD: factory stops can now get different names from building stops (%s factory %s %s must be new translated) FIX: build foundations only directly under elevated monorail depots FIX: ist_natur() return also false on halt tiles (like harbor) ADD: (gerw) broad tunnel patch (see pak64 sources: adding images [Nl] [Nm] [Nr] and so on) FIX: no longer no trees after 150 years ADD: no decimal point for very large amounts CHANGE: better displaying algorithm, should give much less clipping errors/graphics glitches with long vehicles/bridges/stations etc. ADD: configurable thousand exponent (like 10^4 for Japanese) by SEP_THOUSAND_EXPONENT FIX: Makeobj could not extract bridges (and possibly even more objects) under XP ADD: zooming in also for pak192 ADD: preparation for images larger than 64k resp 255*255 FIX: maintenance for ticks_per_month smaller 18 ADD: timeline for cityroads using 'city_road[0]=name[,intro][,retire]' in simuconf.tab ADD: winter image for PowerSource/ PowerDest: Image[2] and [3] as snowy versions of [0] and [1] ADD: winter image for sidewalk: Image[1],[4],[7],[10],[13] as snowy versions, Image [5][8][11][14] transition images ADD: minimum and maximum numbers of next towns to connect to a factory can be set too in simuconf.tab with factory_worker_minimum_towns/factory_worker_maximum_towns ADD: timeline for intercityroads using 'intercity_road[number]=name[,intro][,retire]' in simuconf.tab ADD: winter image and timeline for crossings: winter images of [image][0] are [image][1] ADD: powerline stabilisation pak which enforces a single transformer next to factories/power stations ADD: enable to use more than one powerline object ADD: texture for tunnel grounds (Obj=misc, Name=TunnelTexture, Image with numbers 0,3,6,9) ADD: simuconf.tab: add default values for cityroad ("city_road") and intercity road ("asphalt_road") CHANGE: TAB goes to next/Shift+TAB to previous edit box, moving and resizing now even when other windows open ADD: skinnable scrollbars ADD: setting dialogue tool (handle with care, should not be visible by default for pak sets!) ADD: resizer also part of skin CHANGE: also starts without any skin FIX: no signals to be built on switches, since they will not display correctly FIX: waiting time cycles also on left button ADD: (z9999+) limit size of toolbars in simuconf.tab FIX: (z9999+) loading old games before 88.00 CHANGE: forest settings moved to simuconf.tab ADD: delay and duration of tooltip configurable in simuconf.tab ADD: timeline for headquarters (pak-sets may need to be updated as the default intro date is 1900, default retire date is 2999) ADD: blinking cursor, selectable text and clipboard functions for text input fields ADD: industry increase and minimum city distance now also saved in savegame FIX: error in routing will clear itself after loading FIX: not restore fields if there is already a building on this tile CHANGE: minimap will center after zooming ADD: parameters of cityrules.tab saved in savegame (networkmode) ADD: active window title bar is highlighted (for options see simuconf.tab) CHG: canals cannot be built on canals of other players FIX: removed obsolete forest config parameters FIX: traffic light setting also network safe ADD: if present show copyright line from ground.outside.pak (which should contain pak set and revision) ADD: new general_tool[36] to build cityroad according to timeline FIX: (z9999) building a Barbour must check also for existing stops above/below FIX: (z9999) trains were braking on field too late after changing of route count FIX: (z9999) stopping before occupied crossings with a signal and many other signal fixes ADD: for text input, double-click to select a word and triple-click to select the whole text ADD: register lineless convoys at the halts and list them with links in the halt details dialog FIX: do not crash with prodbase 0 and ensure some basic production FIX: convoys did not properly looked up next signal for signals on closed crossings ADD: right-click on icon of selected toolbar closes the toolbar ADD: server uses a different savegame revision => testing already possible now ADD: savegame version can be set in settings ADD: simple chat system added (send message option in message window) ADD: semi-automatic announce of servers possible CHANGE: chat option now part of message center ADD: messages on joining and leaving CHANGE: renaming of stuff now in network games ADD: clients and server compare paksets before joining CHANGE: for two-click-tools: ctrl+click sets start marker, useful for point-to-point bridge building with two clicks in network games ADD: (gerw/Dwachs) build signals like ways; ctrl+click on icon opens dialogue to change parameters (help file: signal_spacing.h), in network games: ctrl+click and then drag ADD: station extensions can be built near public halts CHANGE: when joining with public station, the public station keeps its name CHANGE: Introduced symbols and tooltips for a much more compact status line ADD: dialogue can be changed (currently only minimap) ADD: possibility to compare pakset of client and server CHANGE: one year after bankrupt, clear slot for new player CHANGE: first load convoy waiting the longest time at a stop FIX: after bankruptcy, ways on public stops will remain unowned, so new people can connect to them FIX: transfer statistics too, when joining stops CHANGE: In order to lock a game the public player must be password protected. Unlocking the public player allows player change again. CHANGE: (Knightly) message system has now tabs for faster overview of categories CHANGE: cities try some terraforming to be able to build roads ADD: messages are saved in save games CHANGE: passwords are only checked/changed if is pressed in the password input box ADD: more messages for headquarters and making stops public CHANGE: application folder for simutrans now under /Library/Simutrans (default MAC standard) ADD: (TurfIt) right-click closes all toolbars, all dialogues and deselects all tools ADD: (TurfIt/Dwachs) Windows snap onto each other when they are close (controlled by window_snap_distance) ADD: server can do monthly announcements ADD: announcements can be configured on command line ADD: also schedules and line windows are kept during joining ADD: vehicles can immediately lose part of their value when starting running (used_vehicle_reduction) to make expensive vehicle unattractive when starting a game Release of 102.2.2 (r3131 on 8-Mar-2010): FIX: connecting upslope to upper way works in sliced mode (r2949) FIX: longer convoi's name could cause crash when entering depot FIX: lines were never freed upon deletion FIX: deleting factories/cities/attractions while those lists were open resulted in CTD FIX: stop types in station frame sometime painted on top of each other FIX: delete convoi only in next step if loading and return directly (and step reverse in karte_t) FIX: walk_city (for stop in towns with AI) was broken (r2990) FIX: distribute goods also on factories with less than 10 output FIX: latin2 characters with unicode>255 work again (via hack) FIX: (VS) do not buy same house twice FIX: (Knightly) only do action when mouse button release also on same button FIX: (Knightly) prevent pending mouse events when resizing ADD: support for townhalls with four rotations ADD: korean glyphs now in cyr.bdf (r2967/r3059) ADD: reading of bzip2 savegames from trunk ADD: (Dwachs) starting money per year FIX: crash when changing schedule after no_route on halt FIX: presignal before station failed FIX: wrong clipping of text FIX: (TurfIt) really empty factories input even in consumption factors not 100% FIX: stop factory building if more than 10 attempts failed FIX: (Dwachs) display correct length in depot FIX: isometric map repaired Release of 102.2.1 (r2928) 9-12-2009 FIX: minimap was not updated when a bridge was deleted FIX: AI could not built any lines FIX: grid slopes were not (re)set correctly FIX: min_building_density and harbour are now recognized in dat/tab files ADD: do not close load/save dialogue after deleting FIX: do not show more than the last 2000 messages in message center to prevent scrollbar malfunction FIX: margin calculation was wrong FIX: first halts are now first in connection list => consistently transfer at first possibility FIX: no money when selling convois at the depot FIX: (Knightly) inverse scrolling consistently for minimap and main view FIX: also ask when a single pakset with addons is present what to load FIX: game starts in normal mode (instead paused) again FIX: downgrading ways were cheaper than destruction => now downgrading will be as expensive as removal CHANGE: ignore empty entries and lines starting with # in citylists FIX: deleting line does not longer crash in halt_detail windows FIX: withdraw all with convois in depot causes crash (and maybe also not withdraw all) FIX: several issues with tram signals CHANGE: info windows now open less important first resp. for single window topmost object first (usually most important) ADD: toolbar, which did not fit their space can be scrolled (either manu menu or when toolbar_max_height = 1) ADD: new parameter for icons in windows title bars: gui_gadgetwidth and gui_gadget_height (although the latter is unused for now) FIX: Labelist with own player filter works again Release of 102.2 (r2785) 18-Oct-2009: CHANGE: cursor now works with full 3d-coordinates ADD: (mostly gerw) sparse data and overlay in main map for passenger destinations ADD: No connections found via overcrowded stops, if overcrowded flag active ADD: do not create goods/passenger/mail when the only route is over an overcrowded stop (simuconf.tab no_routing_over_overcrowded) ADD: more vehicle messages show in main screen CHANGE: ask for language only once (prepare for difficulty dialogue) ADD: UNDO for powerlines FIX: convoi details (and info- windows) were not always correctly (re)opened CHANGE: convoi, station and line handles autoextent their capacity FIX: changing schedule by stop mover did not work on open schedule windows CHANGE: climate dialogue now completely gui_numberinput_t CHANGE: convois will only choose stops that can fit their entire length FIX: (mostly gerw) tunnel maintenance costs ADD: (z9999) tunnel can have predefined way (new syntax, need new makeobj) ADD: completely ignore message button at beginning of dialogue CHANGE: faster map (non-isometric) on very large maps and no crashes with extremely large maps anymore ADD: paste letters under windows with CNTRL+V ADD: button "withdraw all" in line window CHANGE: simuconf.tab cost values can now go up to 48 bit (should be enough for insanely high starting capital) CHANGE: addons can be put now into the user folder with the same name than the main pak folder CHANGE: skins are now read first from program dir/skin then from own dir/skin and then from pak set ADD: (gerw) dragging of wayobj and many other tools, adding wayobj-remover CHANGE: (Dwachs) better intercityroad creation ADD: (Dwachs) sliced underground mode ADD: (z9999) 8 layout for city buildings allow also closed corners ADD: (Dwachs) buying cityhouse will protect them from renovation ADD: Underground slope (in principle even compatible to older savegames) using standard slope tool ADD: changing slopes now also with objects on top ADD: (Dwachs) tram track can be build in road tunnels ADD: (gerw) click-and-drag for tunnels ADD: (Nathan Samson) allow left_to_right_graphs (=1 in simuconf.tab) ADD: (z9999) better display of depots in minimap ADD: (Dwachs) zooming of map with mousewheel ADD: switches change graphics for diagonal going trains (only eyecandy) ADD: ambient sound effects (for all graphics + forest + beaches) CHANGE: less lagging updating/rerouting after schedule changes even with large stations ADD: (Dwachs) Public player can remove all ADD: two switches (-addons and -noaddons) to regulate loading of addons together with pakset CHANGE: (Dwachs) 2-5x faster city generation CHANGE: (Knightly) even faster routing of goods due to ignoring non-transfer stations in breath search ADD: switch to keep towns static ADD: (gerw) minimaps in city info window are clickable CHANGE: after 40 retries, factory construction will ignore climates to avoid broken chains (if possible at all) ADD: citygrowth parameter configurable in simuconf.tab ADD: setting dialog allow access to all settings also found in simuconf.tab before starting a game Release of 102.0 (r2366) 5-Mar-2009: FIX: connect stops again to public player FIX: marker had invalid position after loading a game => crash when adding new marker FIX: again income messages even with very many convois ADD: &#; for direct character input (but no unicode yet) to help files "HTML" ( happy face,  unhappy face) ADD: (z9999) capacity of a stop shown in tooltip ADD: (z9999) halt can have different storage capabilities for different good types (seperate_halt_capacities=1 in simuconf.tab) ADD: if pay_for_total_distance=1 in simuconf.tab, price is calculated for the distance you got nearer to destination ADD: (isidoro) jump to line window from halt_details FIX: mark deleted trees dirty when building roads CHANGE: message window now obeys also Simutrans UI (array/rightclick for goto on map, leftclick on text to show again) CHANGE: inactive tabs nor greyed out ADD: goto line also in convoi info window CHANGE: (z9999) finally useful marker with a simutrans consistent gui ADD: (gerw mostly) river are now created during map creation, new options in simuconf.tab ADD: no vehicle/cash sounds during fast forward ADD: (gerw/prissi) powerline remover FIX: lines always got id 1 => saving was not successful! CHANGE: language specific divider for amount possible (like million for most) using LARGE_NUMBER_STRING and LARGE_NUMBER_VALUE CHANGE: start at any month you like (parameter starting_month in simuconf.tab) FIX: fences and slopes in most situations now without graphic errors (some are currently unavoidable) ADD: (z9999) new sort option for good list by category FIX: (mostly Dwachs) way graphic for way in tunnel now matches speed and maintenance fixed ADD: avoid overcrowded stops (experimental, avoid_overcrowding=1 in simuconf.tab) Release of 101.0 (r2208) 3-Jan-2009: FIX: weg search stooped to early => not properly upgrading city road types in pak128 (z9999) FIX: crash of passenger AI before busses were available FIX: stop moving tool also deals with empty lines now FIX: retire dates again ignored during map creation FIX: no crashing when loading unavailable buildings FIX: crashes with movingobjects during creation FIX: planes were not always correctly descending FIX: harbour tile layout==16 tile were not calculated similar to stations CHANGE: -fullscreen command flag will try to detect current resolution => no need to specify size FIX: scrollbar text after resize now updated properly FIX: remember last selected tool FIX: preserve tick count after loading saved game => wait per month should be fine now FIX: allow harbours also on trees ... FIX: start on signal tile resp. drive through closed signals when open/close schedule dialogue ADD: multithread support for screen copy (max. 10% faster) for GDI FIX: new timing for idle and frame => fast forward speed more closely met, less CPU needed, smoother transitions FIX: too sensitive mouse repaired (moving during clicking) FIX: no crashes on power bridges at vertical slopes CHANGE: much faster town renovation/town growth => faster city generation FIX: only tools applicable in the current situation are visible CHANGE: savegame path instead .simutrans now ~/simutrans on Linux/BeOS, and ~/Documents/simutrans on MacOS FIX: fields next to a new station leads to crashes during name determination FIX: correct color for stops over townhalls for labels FIX: long block signals searched always on first leg too much and stuck trains which stop directly after them FIX: wayremover removed (partly) bridges even without permission FIX: bridges during removal removed too much maintenance ADD: make tooltips configurable (show_tooltips, tooltip_background_color, tooltip_text_color) in simuconf.tab ADD: (leopard) Native sound/midi support for MAC FIX: rotate also coordinates of messages ADD: target destinations in halt details now clickable FIX: raise and lower now also ok new border, better error messages FIX: (z9999) maglev and narrowgauge for everything, additional line symbols (MaglevStop, NarrowgaugeStop, ... ) for linemanager optional CHANGE: speed on diagonals only 20% faster => less gain, more realistic vehicle length FIX: no crossings on underground station tiles FIX: wayobj ignored replacement by compat.tab for catenaries CHANGE: now 16 syllables for town names %/&(0...9A...F)_CITY_SYLL CHANGE: maps got an own subdirectory, and format RLE compressed (usually less than 10% of ppm)/uncompressed 8-Bit and 24-Bit BMP allowed too FIX: trams were not using the max speed according to the trams speed table ADD: (z9999) daylight level now adjustable ADD: (isidoro/prissi) overtaking for road vehicles/citycars ADD: (z9999) right mouse button to minimize windows to title bar and restore CHANGE: payment is now only for the decrease in distance to the next transfer stop ADD: instead a number also a name of a menu object (with image zero) can be given for an icon in menuconf.tab ADD: (Gerd Wachsmuth) map enlargement during the game ADD: (VS) electric EMU/trolley bus tab added to depot CHANGE: AI now separate files, which would allow for a greater variety of AIs ADD: (Dwachs) depots remember last line FIX: construction of four layout stations and rotation of four layout buildings were completely broken FIX: graphic error with slopes next to bridges and tunnels ADD: new tool to make a stop a public one (to make public stops on map without player change) FIX: disabling sound and midi will be now saved and will disable them completely to avoid the SDL_mixer troubles FIX: x instead y offset written by makeobj ADD: (Dwachs) new object gui_numberinput_t for more convenient entering of numbers ADD: (gerw) sizeable loadsave frame CHANGE: savegame bump, no AI save state correctly, same for map extension, no koord saved anymore (up to 60% smaller savegames) CHANGE: settings are now saved for game relevant/user relevant to prepare for multiplayer (and do proper versioning) CHANGE: sea level now in single steps (before only double steps, but single steps in display) FIX: handling of wrongly defined fonts and unicode characters now correct again FIX: bridges could connect to "harbour" tunnels CHANGE: maximum map size now 16 million tiles FIX: overcrowded station messages again Release of 100.0 (r1867, stable) 28-June-2008: FIX: rotated townhalls could lead to crashes CHANGE: show connected stops at factory again ADD: factory edit modus after patch from z9999 FIX: removing of wayobj in tunnel or on bridges left wrong top speed. ADD: factory link tool from z9999 ADD: attraction built tool from z9999 ADD: citybuilding builder inspired by z9999 ADD: tree planting tool inspired by z9999 FIX: trees are now correctly sorted by the internal tile positions (before were shadow problems) CHANGE: smoother zoom out (experimental) FIX: x-offset for images should finally work ADD: following zoom-levels are now supported 1.5:1, 1.33:1, 1:1, 0.75:1, 0.66:1, 0.5:1, 0.33:1, 0.25:1 (maximum tile size zoomed in is 254!) FIX: no cars entering railroad crossings when they apparently cannot exit (may fail with crossings following immediately) FIX: no citycars entering a crossing, if there is no exit FIX: convois created by copying had no home depot FIX: during zoomout, the tiles were clipped 32 pixels too early FIX: rotation of buildings with layout>4 corrected ADD: more statistics for world (see in citylist) FIX: show signals again in minimap ADD: preliminary support for automatic configuration, clarification of the licence CHANGE: maintenance of player buildings now depends on its level FIX: reloading with no matching buildings for a climate could lead to crashes CHANGE: smoother movements of vehicles in all sizes and zoomlevels FIX: powerlines destroy on fields during loading CHANGE: all traffic lights have now synchronized phases ADD: new parameter in forestconf.tab: tree_climates for climates with at least one tree per tile and no_tree_climates for the reverse ADD: new parameter for cityrules.tab "minimum_building_desity" in percent: if the area covered by buildings is less than this, the city borders will not increase => more compact cities, not fading out along a single street (default: 25) CHANGE: completely renovated schedule entering window CHANGE: logarithmic traffic density display in minimap CHANGE: cst_depot_air for charging air_depot CHANGE: less subtypes for stops and depot (halfway) CHANGE: new customizable toolbars (90%) (see pak64/config/menuconf.tab) FIX: schedule window last line was not selectable ADD: waytypes narrowgauge_track and maglev_track now functional FIX: trains with freight_type but total load==0 were still creating connections (caotic) CHANGE: groundobj for new map again (z9999) CHANGE: seasons for groundobj and movingobj (z9999) CHANGE: enables all map edit tools again (z9999) FIX: random rotation building problem (z9999) FIX: initialize tool (z9999) FIX: check climate for tree (z9999) FIX: tree cost (z9999) FIX: power for low producing factory (z9999) ADD: Fill trees tool (z9999) ADD: Add forest tool (z9999) ADD: Add random city car tool (z9999) ADD: option to start without trees (z9999) ADD: max. speed information on depot window (z9999) CHANGE: allow any key for command, include #99999 (decimal code), ^A (Control A), F99 (F1-F15), COMMA (,) CHANGE: allow for < and > to be used in flowtexts ADD: stop mover tool (mostly z9999) tilewise for road, stopwise for water/air and platformwise for rail bound vehicles ADD: AI builds airports (sometimes still too close to border) and uses them more or less wisely FIX: no factories/attractions under monorail or powerlines and thus no disruption of them FIX: waypoints under/over stops were treated as stops for good routing CHANGE: all stops are now given more or less unique names. First factories, then buildings, then ?standard, where "?" is 1..9 or A...Z (if available) and standard is center, extern or suburb the later with one of the german directions nord, sued, west, ost, nordwest, ... If failed, it will be a numbered stop (translators: please translate on simutranslator!) CHANGE: deduct maintenance at the beginning of a month => no sudden dropping below zero any more CHANGE: no zooming in/out of vehicle images in depot and lists CHANGE: speedbonus taken now from config/speedbonus.tab (if present) ADD: scenarios (i.e. you can play for a goal), bankrupt only after net wealth is below zero CHANGE: scenario can have an additional factor for difficulty CHANGE: more description of files before loading (ppm/scenario) CHANGE: -debug parameter now takes a debug level (1,2,3,4 for errors only, warnings only, all messages,debug special messages) ADD: highlight selected toolbars/tools Release of 99.17.1 (r1550, stable) 17-Dec-2007: FIX: some errors concerning headquarters, AI and moneys frame CHANGE: again only first and last vehicle reserves block CHANGE: only producing factories are consuming power CHANGE: allow for offsets in the texture files => pak192 grounds possible CHANGE: new convoi filter for stuck convois 'clf_chk_stucked' FIX: could delete crossings under certain circumstances CHANGE: images in line tab, translation now tooltip, "TramStop" pak needed CHANGE: block reservation mode on will also enable "delete these reservations" cursor ADD: new obj named groundobj, new string "cost for removal" FIX: error with removing headquarters after rotation FIX: deleting non-continuous buildings and rotated buildings could crash simutrans, rotate factory base for rebuilding after loading FIX: invisible mousecursor by moving the mouse during right click scrolling outside of window fixed CHANGE: adding type to introduction/retirement message FIX: severe bug loading pedestrians or citycars Release of 99.17 (r1502) 19-Dec-2007: ADD: water animation (if images defined) animation images are just the second parameter in the definition; animation speed is set by water_animation_ms in simuconf.tab FIX: tiles in train middle at waypoints were not properly reserved FIX: sometimes planes were circling on the ground FIX: winter tile change for whole map also on large maps ADD: more statistics for cities / preparation for different growth models (strings now "citicens", "Growth", "Buildings", "Electricity", "Transported", "Passagiere", "Sended", "Post", "Arrived", "Goods") FIX: daynight cycle for show_month<=1 CHANGE: town growth is now stimulated by 40% passenger transport, 20% Mail transport, and 30% for not leaving storage of consumers with workers from this town empty FIX: powerlines and tunnel entries more intelligently handled during wayremoval CHANGE/FIX: close schedule windows when deleting a convoi or starting one from depot (removing the annoying error message when entering schedule is in progress) "Es wird bereits\nein Fahrplan\neingegeben\n" CHANGE: electricity production of a power station is now fixed at 4x nominal production (does not matter how much transformers => no cheating with solar plants) FIX: smoke offset revisited FIX: thing info is always redrawn => less redrawing errors FIX: headquarters was always added during drawing to money dialogue => to time left for event processing FIX: remove trees below monorail depot FIX: good filter now works with categories CHANGES: city cars spawn now only if neither passengers, mail, nor goods are transported CHANGES: to make list easier to navigate with left button only mouse, city list, attraction list, and factory list display jump to button FIX: two errors that could lead to stuck convois Release of 99.16 2-Dec-2007: FIX: image under fields were not recalculated after removal FIX: deleting a factory with an open info window lead to crash (also during map destroying) FIX: pak selector was not always shown FIX: crash when opening slopetools in underground mode FIX: windows gain not focus during dragging with mousebutton ADD: new error message 'Not possible in this rotation!' FIX: bridges ending on elevated monorail or flat tiles fixed ADD: screenshot under windows as png (if gdiplus.dll is present, i.e XP or .NET there) FIX: transparent/no season recognizing bridges FIX: double or "unknown" names for stations on bridges/tunnels for 99.14 and older games CHANGE: events now internally carry always the mousebutton states => fixing problem when scrolling with right mouse button (and so others too) ADD: airplanes now reserve the runway for the entire time of takeoff/landing (more realistic, smoother waiting circles) ADD: during world creation no tourist attractions newer than the current year will appear with timeline on FIX: under certain cases station (length!=8) stations loaded one vehicle too many FIX: old texts were not deleted from nonrotated hashtable during rotation ADD: 'pillar_asymmetric' for bridges with shorter pillars on north resp. west slopes and 'max_height' for bridges + new error message 'bridge is too high for its type!' ADD: new crossing logic: crossing is one object only (new strings: "invalid", "open", "request closing", "closed", "\nway1 reserved by" , "cars.\nway2 reserved by", "cars.\nstate") FIX: no stops on tunnel entries or on runways FIX: calc load and image correctly after leaving depot CHANGE: factory introduction dates (thus with older paks no factories before 1901) Release of 99.15 3-Nov-2007: FIX: AI terraforming was free of charge FIX: AI never changed convoi, when building does not succeeded FIX: powerlines did not disconnect during deletion CHANGE: road convois wait, if next tile is a crossing and they cannot pass CHANGE: if the stop of a factory is overcrowded and there is no goods waiting for a destination while there are some for other destination of this factory, the overflowing amount is rerouted. This avoids situations where nothing was delivered to a waiting convoi because a station was overflow and thus this convoi blocked everything. Now it will be gradually loaded. FIX: vehicle position was wrong after visit to depot => such convois will be vanish after reloading, sorry CHANGE: sort order for convois and halt match as default; also last setting is saved CHANGE: selection of map buttons is saved FIX: hausbauer now handles building deletion => complete deletion of stops and factories, even non-continuous and connected FIX: pax_transported, pax_erzeugt was not saved FIX (z9999): tree density setting form uint8 to uint16 FIX: empty schedule during loading for convois in depot => crash FIX: signal and missing roads where overlooked when leaving depots ADD: minimum factory distances more strongly enforced. Configurable via simuconf.tab (factory_spacing, default 6) ADD: new message category for warnings (like name of new player or traffic jams) ADD: AI now builds headquarters FIX: correctly building ways from/in depots and stops CHANGE: AI now announces headquarters construction with <<%s's\nheadquarter now\nat (%i,%i).>> FIX: redistribution of goods on stations with three destinations was faulty FIX: building taxiways again FIX: lines again automatically connect and detach from a stop FIX: depot closed, if there was only a single depot and the next/previous depot was searched FIX: reaching destination while just leaving depot will skip destination FIX: revenue will be only given for cars in station FIX: slope entering by a curve would not give slope penalty FIX: tram tracks on bridges were visible in underground mode FIX: build station extension building again on flattened slopes FIX (kierongreen): station layout patch supplied with some fixes ADD (kierongreen): powerline bridges FIX/CHANGE: window system was really a little broken FIX: remove tall buildings without residuals CHANGE: bus AI now tries to connect intown as well => less worse competition FIX: deletion of powerline was free up to now ... CHANGE: two less virtual functions in vehikel_t::sync_step() (most often called routine) => speedup FIX: convois with waypoints at bends were still jumping for certain vehicle lengths (sigh ...) CHANGE: GDI fullscreen mode correct and due to switching resolution ~50% faster redraws CHANGE: dragging during raising and lowering land enabled ADD: manufacturer name for each car shown in the convoi detail dialogue FIX: start/end way building under cars and filled depots CHANGE: preliminary map rotation (for these places behind a slope) with 'R' FIX: clear all old entries in the message list upon starting a new game FIX: text labels again on any height (did affect towns below bridges) FIX: frame delay time does now slower increase/decrease => smoother response CHANGE: all toolbars open directly below each others FIX: crash when zooming out images with negative y-offsets FIX: rotate map, when building a tree with nonrateable factories FIX: ground calculation fixed again FIX: smoke offsets FIX: more responsive interface by changing frame time calculation again for extreme cases ADD: frame around active window if requested (window_frame_active in simuconf.tab) FIX: toolbars now also change with underground mode ADD: new message for AI going bankrupt (Company bankrupt) FIX: no route message shown again FIX: roadsign rotation corrected FIX: snowline height fixed (automatically set be the end of the highest climate) CHANGE: if no pak defined in config or commandline then a) if only a single pak exists load this or b) display a dialog for choosing one Release of 99.14 31-July-2007: FIX: speed limit of channels for ships was never lifted FIX: again front images for traffic lights FIX: crash when building harbour outside of the map FIX: avoid jumping of trains when waypoint on first tile after a curve ADD: under windows nicer error messages for missing objects CHANGE: much better loading of games with missing objects CHANGE: stopping position of trains of length>12 FIX: factory positions in minimap FIX: screen resolution enlargement with GDI version resulted in crash FIX: crash when opening a depot, for that no vehicles exist FIX: town name management now like halt management FIX: player color for depot/color selection fixed ADD: ordering of menu entries for station buildings (level) and wayobjects (topspeed) CHANGE: money frame construction cost button name now 'Construction_Btn' CHANGE: enable UNDO always for active player FIX: convoi list can again hold more than 819 convois ADD: new buttons in display settings: 'show waiting bars' and 'show station names' for the previous '!' key function CHANGE: 'Q' now opens the options dialogue, where you can really quit the game FIX: factory crossconnection running amok hopefully solved (and some production values tweaked) ADD: (z9999) show current schedule/selected line in minimap (new strings: 'Show schedules', 'Shows the currently selected schedule', 'factory details', 'Shows consumer/suppliers for factories', 'CityLimit', '(%i)-') FIX: redraw problems after topping windows FIX: factory builder was tried to built the same factory always on the same region => now check next two regions in all directions => less incomplete chains CHANGE: AI deleted uneconomical vehicle and routes, if in trouble CHANGE: AI tries now also more or less successful ship route Release of 99.13 3-July-2007: FIX: airplanes got confused, when the ground under them changed FIX: (z9999) show factory detail info FIX: (kierongreen) Removing tram tracks from road caused crash FIX: restore speed limit after crossing deletion FIX: deletion of traffic lights led to crash with road deletion tool FIX: (z9999) traffic light position with drive on left fixed FIX: (z9999) filter overcrowded did not work in haltlist FIX: right map rotation in non-isometric view FIX: removing station from ground with other station one bridge/in tunnel could result in display/naming errors FIX: (marcr) minutes were wrong in no-month mode FIX: (robofish) underline error for help text H1 tags FIX: unreservation during convoi/track deletion fixed FIX: (z9999) factory reader and colors in minimap were wrong ADD: cityrules new parameter u/U ground is not/well suited for road ADD: cityrules new parameter renovation_percentage (default 12) to finetune new building/renovation ratio FIX: schedule was one off during reloading (and driving one field) due to missing initialisation of check_for_finish in vehikel_t(welt) FIX: convoi stuck on a slope, if pos_next was wrong CHANGE: calc_height only called if needed (about 5% faster game) ADD: (tomilepp) empty capacity line to freight_sorter CHANGE: sync_list changed from slist_tpl to ptrhashtable_tpl => remove from 5% to 0.3% game time for all sync-objects (cars, pedestrians, animated buildings, smoke, ... ) FIX: wrong outdated flag due to missing initialisation after loading of a convoi FIX: overflow in money frame color calculation ADD: now three lists for connecting stations, depending on the freight type => about 50% faster route search CHANGE: different (more compact) list of stations connected at a stop FIX: (kierongreen) station names in tunnels FIX: (z9999) monorail station extension buildings FIX: convoi could break up when during loadtime it was on its finally tile (also new detection for already broken convois) ADD: speed record for all kind of convois FIX: vehicles may have been saved with wrong pos_prev, which may caused errors at waypoints/stations FIX: blue night light finally working ADD: automatic line breaks in building description texts (inspired by tron) FIX: error with stale goods after deleting served stops FIX: no crashes with overlong headquarters strings CHANGE: more cpu-friendly wait for no route/waiting before a signal (and less fast stuck tooltips) FIX: finally really loading the Pxxx.bdf fonts (and generated new bdf-font based on old ones) ADD: (kierongreen) ways will look for replacement during loadtime in no matching besch found FIX: convoi speed reset to zero at traffic lights CHANGE: faster sorting in haltlist for waiting amount CHANGE: much faster scrolling with right mousebutton (previously this made an update for every pixel move) Release of 99.12 31-May-2007: FIX: explicitly check error codes when saving files FIX: cars now properly turn at road signs ADD: toggle grid now also in the visual settings dialogue "show grid" FIX: road remover fixed FIX: electric engine type was lost after saving CHANGE: UNDO now only denied, if something built on top of that way (including tunnels, bridges, stops, signals, electrifications ...) FIX: intended two way calculation during building of ways was calculating same route twice instead switching start and endpoints => strange routes could occur CHANGE: removed second route calculation and put a malus on a turn on the last field CHANGE: default way_double_curve=6 gives better results FIX: after showing bankrupt dialogue, fast forward is switched off FIX: crash, when a schedule had an illegal ground coordinate (new string: "Invalid coordinate") CHANGE: city car generation is now proportional to (log10(generated-transported+1)*density/16) Probability=1.00 mean on average one citycar per month FIX: wrong entry deleted during rerouting (vector_tpl will now assert there) FIX: waypoints work correctly with vehicles longer than 8 CHANGE: bits per month setting should now work up to 29, minutes are now displayed ADD: powerline category to money dialogue (and cleaned up, new string: This Month), also add headquarters to the dialogue FIX: powerline did not cost any maintenance (in simuconf.tab: cost_transformer=2500 and cost_maintain_transformer=100) ADD: b shows/hides reserved rails ADD: new roadsign type 'end_of_choose' to limit the range of free_route sings/signals FIX: construction over sidewalks did reset speed limit FIX: overflow when sorting vehicle list (defined signum for sint64) ADD: crossing between all ways (except air) are now allowed. See attached example. Priority will have the secondly defined way. FIX: do not show foreground for normal buildings FIX: starting long engines in a depot could cause all strange stuff Release of 99.11 4-May-2007: FIX: roads did repel each other too strongly. A little more clever handling has been introduced, but way_count_leaving_road is still too high. CHANGE: convois indicate error states also with tooltips FIX: factory crossconnection was one-sided ADD: midi shuffle will be remembered FIX: electric engines also recognized when not leading convoi FIX: advance savegame => field positions now saved ADD: more colors for convoi status: WHITE in depot, ORANGE: stuck/no route FIX: re-added city car info dialogue ("%s\nspeed %i\nmax_speed %i\ndx:%i dy:%i") FIX: speed of convois and city cars was frame rate dependent! FIX: deleting fields with factory CHANGE: vehicle now queue properly even on diagonal roads CHANGE: only the first vehicle in a traffic jam will report traffic jam conditions CHANGE: citycars are now only generated when there are not many passengers transported and the field is question is empty. Release of 99.10 17-Apr-2007: FIX: powerline connection fixed FIX: single slope up/down in one tile was broken FIX: powerline production AND consumption now based on factory production FIX: factory production per month now correctly displayed ADD: crossconnection for factories now switchable (crossconnect_factories_percentage in simuconf.tab) FIX: schedule sanity check could fail under certain circumstances (kierongreen) FIX: disallow going to depots if already under way (kierongreen) FIX: station with layout crash fixed (kierongreen) FIX: improved focus management FIX: vehicle filter list fixed for airplanes/ships (kierongreen) ADD: field support (kierongreen/prissi) (in simuconf.tab: cost_multiply_remove_field, in factory entry fields, new field with a number of image[x] definitions) ADD: miniwindow now shows also black background in underground mode (kierongreen) FIX: factories will now only smoke when producing, consuming or both FIX: crash related to building/replacing elevated ways FIX: loading wave sounds again CHANGE: simutrans now searches for data always in its root directory (-use_workdir to override this) CHANGE: simutrans user data on Unix now in "~/.simutrans" Release of 99.09.3 24-Mar-2007: ADD: jump to coordinate dialog added ("Jump to") called by "J" FIX: reloading games save in 99.09.2 from previous versions works could result in passengers without route FIX: colors in map window were still broken CHANGE: powerline now do not avoid slopes FIX: during building of powerlines the first tile had no net FIX: remove xyz strings were not translated Release of 99.09.2 16-Mar-2007: FIX: some errors with construction/deletion of oriented stations fixed FIX: bdf-fonts with more than 256 characters are loaded again FIX: tree with 3 seasons had same behaviour than the ones with two => ignore the third one FIX: loading demo-games with multiuser FIX: better compatibility with old save games (e.g. empty stops etc. ) FIX: reduce world size to (0,0) during deletion => less crashes, less complains in the log FIX: bus AI tries no longer to built on other players roads FIX: houses for stop names will be now selected in a fixed order => less double names ADD: you can limit the fast forward speed with fast_forward in simuconf.tab (but this is rather a course regulation) ADD: time multiplier for fast forward mode shown FIX: setting correct 2nd player color after reloading a game FIX: simu.log now saved in home directory FIX: automatic recognition of bitmap depth (failed with SDL on some old machines) => transparency fixed CHANGE: 16 bit color depth for GDI (may not work on all machines, please report) CHANGE: better recognition by the AI, if there is already a connection CHANGE: AI now built also tunnel and bridges, that are only one tile long FIX: also not altering old city roads (before only affected new city road) ADD: two more tweaks for the way builder: way_straight (cost for straight tile) and way_leave_road (to make existing roads more favourable) Release of 99.09.1 4-Mar-2007: FIX: time for pause/refresh interval now moved to sync_step() => handled internally each refresh => better responsiveness FIX: end of station with layout>4 in NS direction Release of 99.09 3-Mar-2007: FIX: on unix multiuser environments the path separator symbol was omitted FIX: marker did not work on elevated ways => no route, even if there was one FIX: no crash after deleting powerline crossing during game creation (but this was done by fixing symptoms, not the cause :() ADD: button for showing forest in minimap (new string "Forest") FIX: during rerouting of goods wrong entries were deleted FIX: singleuser_install in simuconf.tab was not read ADD: 8 player colors + second set of eight player colors, more colors to choose from, blue light color ADD: (kierongreen) possibility for automatic orientation (and facing of parallel) stops FIX: station coverage was wrongly detected FIX: ppm for all program for heightmaps (Photoshop created unexpected header) ADD: goods entries shrank further (now 12 Bytes pre packet) and saved lots of lookups ADD: obj=tree allows for seasons=3/5 with the third/fifth season having snowy winter tree image FIX: AI tried to built busstops in invalid positions FIX: InputSupplier[]=0 did not built new factories, even if required FIX: no depot on crossings or places with more than a single way CHANGE: a car will wait two months in a traffic jam, then it will complain. After three months it tries to turn; in unsuccessful, it will self-destruct. FIX: crash could occur with long_block_signals(); the fix will cause trains to slow down in front of long block signals similar to choose signals ADD: color for good in dat-file (color=index_nr, same as factory colors) CHANGE: category names now CATEGORY_xx and part of the pak set, replacing "piece goods", "bulk goods", "oil/gasoline", "cooled goods", "liquid food", "long goods" FIX: connection streets across slopes FIX: faster groundsearch also avoids artificial slopes Release of 99.08.1 6-Feb-2007: FIX: all tabs in depot show, if there was/is ever a matching vehicle FIX: all reserved signals after presignal or choose signals are now green CHANGE: save sound/midi volume FIX: midi now loaded correctly (first in usedir/music/music.tab, then program_dir/music/music.tab) FIX: unsigned long correctly loaded (i.e. load in schedules) FIX: correct baum types in the correct climate (hopefully final fix) CHANGE: bus AI will use always the cheapest road to survive a little longer FIX: games with failed to generate even a single town were saved wrongly FIX: houses without cities are again reconnected to the nearest city upon reloading FIX: length of string buffer for stations was 3 bytes too short Release of 99.08 4-Feb-2007: FIX: random_tree_for_climate was broken, and did return not always the right tree FIX: unmark map ground during underground deletion FIX: image for bridge ramps after reloading FIX: cities continue also ways on upslopes FIX: citycars properly turning, when there is no entry or only one tile after a crossing (and also make now 180° turns) FIX: (kierongreen) trains in small window are now correctly followed over bridges ADD: (kierongreen) withdraw of convois i.e. convoi is sold after it is empty (and no freight is loaded) 'withdraw' and 'Convoi is sold when all wagons are empty.' ADD: (kierongreen) no loading button to convoi info window added for manual control of a convois state FIX: crash when click on vehicle that is in a different depot than its home depot FIX: (kierongreen) underground mode resets not grid mode FIX: (kierongreen) height on slope during follow convoi was jumping CHANGE: shrank ware_t by eight bytes FIX: citycar destroyed themselves after a curve with a dead end FIX: wayremover in tunnel removed tunnel object also on starting and end tile CHANGE: goods now stored in an array instead of a list at stations => higher chances of joining => much faster (up to 50% for passenger/mail games) + less memory (up to 4MB); your mileage may vary. FIX: label were saved but not loaded FIX: crash when city tried to built new road to new townhall over existing player road CHANGE: only show goods which can be transported for status display at stations CHANGE: simuconf.tab is searched in pak/config/simuconf.tab after reading the main one in simuconf.tab (which is not needed) CHANGE: savegames and all other configuration stuff is now saved in the users home directory (resp. Eigene Dateien) if multiuser_install=1 (default) in simuconf.tab CHANGE: simuconf.tab files are now read in this order: program_dir/config/ then user_dir/config (for pak file path) than pak/config/ then user_dir/config for the rest CHANGE: new program option -singleuser to avoid using the users home directory (respective singleuser_install in simuconf.tab) CHANGE: removed maintenance_overhad, maintenance_ways from simuconf.tab, since it was not used FIX: forgot to charge for industry construction CHANGE: forrestconf.tab -> forestrules.tab, now maintained by the tree class itself FIX: building ways into depots again FIX: city does not build road through busstops, loading bays or depots FIX: underground depots are recognized again FIX: water image of artificial slopes fixed CHANGE: display of savegame pak-folder in the load/save dialog ADD: (kierongreen) long block signals: a train coming to this signal will only enter, if it can drive to the next signal, through all stops or waypoints (set is_longblocksignal=1 in the dat file) Release of 99.07 21-Jan-2007: FIX: crash when deleting empty tiles of middle parts of bridges FIX: wrong schedule entry pointer after loading FIX: crash when electrify before electrification FIX: citycars got stuck on slopes at height level -1 FIX: way remover with tunnels crashed at tunnel entry ADD: (prissi & kierongreen) transparent images for buildings, trees, and catchment area with an extended display dialogue (new strings: "hide transparent", "hide trees", "hide city building", "hide all building", "transparent station coverage", "show station coverage") FIX: improved citycar behaviour FIX: wayobj not dirty after creation => garbage on the screen ADD: shuffle for midis ADD: (kierongreen) colors for water height in minimap ADD: (kierongreen+prissi) better station coverage display in separate layer FIX: removing way was free of charge ADD: new label enables land buying (cost by 'cost_buy_land' in simuconf.tab, default -100), help file now possible ('label_frame.txt') FIX: wrong images after diagonal tile after bridges and crossings FIX: snowy bridges start on slope was wrong FIX: max midi volume now 255 => no overflow FIX: (kierongreen) pillar position was plainly wrong ADD: (kierongreen) using SDL_mixer for midi (now also with Linux, if possible) FIX: crash during deletion of bridges and tunnel (although just fixed symptoms) ADD: waterdepths (needs new ground obj "Water", with n images, n=0 is uppermost, 1=deeper, 2=even deeper, ... FIX/CHANGE: roads will not be overtaken, if they are not public property ADD: shadows for airplanes (still wrong at non-straight slopes) Release of 99.06 08-Jan-2007: (prissi) FIX: crash when closing the filter window before the main list window FIX: not zooming out menu icons FIX: drawing of single direction signs FIX: stations of AI were not added correctly FIX: some minimap setting were forgotten during season change FIX: curves in tunnel again FIX: way owner was lost after saving FIX: channels were not connected to the sea in all cases FIX: crash, when building has not tile (0,0) due to empty image on info FIX: diagonal wayobj again FIX: checked for wrong offsets in a schedule during load/save FIX: obey BBX completely in BDF-fonts FIX: landing airplanes now recognize the ground CHANGE: cleaned up midi code, now maximum 128 songs, "music.tab" now "music/music.tab" FIX: bug when loading stations etc. that were not animated but put into the animation list CHANGE: wayobj will be deleted before a station CHANGE: ground can no long be owned, only objects on it (need some tweaks with labels still) (kierongreen) CHANGE: snow for tunnel and bridges FIX: right mouse button scrolling in minimap Release of 99.05.1 17-Dec-2006: FIX: idle timer has eaten up all time doing additional frames FIX: issue with transformers FIX: crash in depot FIX: off-by-one error which can lead to non-unique city names FIX: DWITH in bdf-fonts was not used FIX: check for allowing artificial slopes was broken FIX: loading signals FIX: loading bridges FIX: display in depot for left hand driving CHANGE: depots now maintained in a list => underground and monorail depots are found again and shown in minimap FIX: crash when building tramways ADD: scrollbar for label frame (mip) FIX: now frames per second direct setable (refresh was not the right way for slow computer) new parameter "-fps", "-refresh" is obsolete; you can also use frames_per_second in simuconf.tab FIX: pillar of neighboring bridges now at the same positions FIX: depot search could crash game when pressed twice very fast Release of 99.05 03-Dec-2006: FIX: always ensure tile is empty before applying slopes (avoids wrong positions) FIX: deletion of thing not on the map FIX: buying cars with different predecessor/following numbers FIX: elevated tracks not shown FIX: waypoints for planes CHANGE: 4 bytes less per planquadrat, 4 less per ground (now down to 32 bytes per tile without objects from previous 48) CHANGE: koord3d is now only with 1 per height step => much less hassle with heights and again bytes saved CHANGE: squeezed another four bytes from tree structure => now only 20 bytes per tree => 16 MB less on 2048*2048 maps CHANGE: got rid of ding_t::step() => large maps should now be as fast as slow maps with the same factory, citycar and city count CHANGE: objects now take care of their image themselves => another four bytes off from ding_t (smaller is not possible, imho) FIX: larger than 1x1 building on slopes CHANGE: game will continue even while dragging (still little buggy) CHANGE: cityrules allow now up to 7x7; more fine control about the res/ind/com clustering too (see cityconf.tab) CHANGE: option to not showing vehicles which are not matching current action ('Show all' and 'Show also vehicles that do not match for current action.' strings added) CHANGE: zoom in and out 'map zoom' in the small map only with a control, more user friendly button positions 'Show legend', 'Show map scale', 'Show industry' ADD: auto-centering on minimap ADD: 45 rotated minimap 'isometric map' ADD: tunnel entrance only built with control key CHANGE: corner heights only bytes instead of long => less data to handle during savegames FIX: track remover for tunnel and monorails fixed FIX: building trough depots FIX: retire/intro messages for ways ('way %s now available:\n' and 'way %s cannot longer used:\n') ADD: winter ways form kierongreen Release of 99.04.2 20-Nov-2006: (prissi) FIX: images inside tunnel FIX: buying airplanes again FIX: minimap remembers size again FIX: old errors with too short vehicles CHANGE(tron): lots of cleaning up of data structures and doubtful code FIX: makeobj broken at several places, not really finished with fixing CHANGE: the same building must not be next to each other => nicer endgame towns FIX: AI no longer using elevated track or tramways as rails FIX: info window title for ways fixed Release of 99.04.1 15-Nov-2006: (prissi) FIX: in depot: articulated engines will be only bought forward respective backward from the current position on FIX: bridge/tunnel construction/deletion fixed FIX: retire messages for planes FIX: way maintenance was screwed up FIX: depots had no maintenance after reload FIX: button offsets Release of 99.04 13-Nov-2006: (prissi) FIX: elevated construction could only connect via straight connections FIX: tunnel rails were upgraded to even higher speeds than allowed FIX: no more accidental connection between bridges/tunnels FIX: no more upgrading track on bridges or in tunnels FIX: way search for ways below monorail fixed CHANGE: unified construction of rail, monorails, maglev, channels, airstrips by baue_schiene() FIX: position now nearly always centered for all zoom levels and pak sizes FIX: scrolling with right mouse button for all pak sizes FIX: rectangle in minimap now shows the real screen size (these three were in for ages ... ) CHANGE: (tron) assembler corrections, code cleanup, reader definition more C++ style CHANGE: tunnel code changed (might not load 99.03 savegames!) CHANGE: 6 byte less for planquadrat_t (i.e. per tile, although GCC gives us only four of them) CHANGE: 8 byte less for grund_t => 14 bytes less per tile (12 with GCC) => map requires ~ 15-25% less memory CHANGE: rewrote dingliste: always well defined position, about 10-20% faster insert of vehicles CHANGE: articulated vehicles are now always bought together, if there is only a single choice Release of 99.03 03-Nov-2006: (prissi) FIX: city creation on new map fixed (actually rectified deletion) FIX: tunnel can now properly handle all way types FIX: cost of tunnel construction FIX: left and right position of buttons (you may skin round buttons now ... ) FIX: translation now shows the correct signal type in info window FIX: button will update their translation every time a dialog is opened FIX 'convoi passed last\nmonth %i\n' '\nRibi (masked)' '\nRibi (unmasked)' 'km/h\n' translatable ADD: (kierongreen) underground mode (toggle with 'U') You can built depots and station, interrupt tunnels in the middle but not much more ADD: preliminary underground construction routines (user the tunnel icon in underground mode; must start on a tunnel!) ADD: elevated support for nearly all waytypes (but not tested) FIX: stations on slope got wrong height offsets CHANGE: maxspeed/friction calculation is now only done when entering a tile => 16x less function calls Release of 99.02.2 21-Oct-2006: (prissi) FIX: unreservation of tracks failed fatally if there was no ground connected to the next tile FIX: factory with there 0,0 on slopes did not recognized their position (not found by other factories, no production) CHANGE: if a city could not built a road at a certain slope, it built a house instead. FIX: button definitions for skins were ignored FIX: demo savegame loading at startup fixed CHANGE: same further optimisations of certain routines ADD: attribute for the help texts CHANGE: first delete station, then caternary Release of 99.02.1 03-Oct-2006: (prissi) FIX: game could lock up during creation when no matching tourist attractions were found for the available climates ADD: new flag in simuconf.tab "ground_info" to show info on ground tiles FIX: platzsucher did some meaningless comparisons and did not consider all suitable places (i.e. slopes) FIX: factory builder did add one too few to the distribution weight => with n factories with distribution_weight=1 the last was always forgotten FIX: wrong/missing foundation during construction on slopes FIX: if no townhall with bev=0 is available for a climate, no towns will be founded in this climate FIX: redraw problem when changing window size FIX: line remembers statistic settings in the line management window FIX: many warning with VC++ fixed, project included FIX: font may also have a maximum width of 12 pixel (was even faster than previous drawing routines) FIX: no longer support for animated ground (interfering with the texture code), removed "animated_grounds" from simuconf.tab Release of 99.02 27-Sep-2006: (prissi) FIX: display depots after reloading FIX: autoscrolling was still outcommented FIX: loading bar position in list display FIX: not roads on foundations CHANGE: progress bar now always half display width, two more messages "Loading map ..." and "Saving map ..." CHANGE: default setting for new map will be loaded from default.sve in the main directory. This file can be a savegame, but will be overwritten the next time a game is started. Release of 99.01.1 26-Sep-2006: (prissi) FIX: ground below houses was draw even if not needed FIX: crash when messages were generated at load time FIX: display error, when no passenger vehicles but engines were in a depot CHANGE: auto resize for scrollbars on all textarea objects (if they have some) FIX: building transformers, less reallocation of nets ADD: engine_type 'battery' added FIX: not loading passengers/mail at freight locations FIX: house where not recognized in old savegames CHANGE: after lot of tries settled now in binary heaps for pathfinding, up to 15% faster FIX: display of animated buildings fixed FIX: monorail and channel tunnels fixed FIX: (again) not connection through depots and 4-stops during city expansion Release of 99.01 18-Sep-2006: (prissi) FIX: redraw after window resize FIX: climate dialogue FIX: display in townhalls FIX: images in depot again FIX: pause at waypoints CHANGE: automatically loading pak/demo.sve (or whatever the pak folder is) on startup CHANGE: symbol.BigLogo.pak with maximum for image loaded during initial startup CHANGE: more complex tunnels, with cost=, maintenance=, topspeed=, waytype=, intro- and retire dates CHANGE: allowed tunnels for all but air, also removal or tunnel with tramrails should work FIX: city roads no longer destroy runways and the like FIX: more even house distribution with rotation Release of 99.00 10-Sep-2006: (prissi) CHANGE: full climate/season support CHANGE: sync_prepare removed Release of 90.00.1 3-Sep-2006: (prissi) FIX: unicode routine FIX: memory for citylist names was one too few FIX:/CHANGE: menus are now adapted during player change (in new module simmenu.cc) FIX: planes now also can do approaches with one way markers on them FIX: dummy vehicle for way removal/upgrades now always successful FIX: wrong prices after starting a map in beginner mode and next in normal mode Release of 90.00 2-Sep-2006: (prissi if not noted otherwise) FIX: clipping error at outmost right row for bitmaps FIX: forgot stop choose after closing schedule after line change FIX: force beginner/normal mode after loading ADD: (kierongreen) additionally freight image for vehicles (syntax 'freigthimage[no][direction]=' with the good definition in 'freightimagetype[no]=') FIX: more error check to makeobj pak for vehicles (wrong numbers etc.) FIX: missing cstring_t initialisation in slist_tpl; since cstring_t only used in translator.cc and searchfolder.cc, these two converted to slist_tpl ADD: color codes for lists of lines and convois (minus: red, not moving: yellow, obsolete: blue, no vehicles: white) FIX: slow building of ways with log of ~ding() error messages ADD: extract command for makeobj (also got rid of the need for ./ for defining the main file in most positions) FIX: restoring old signals was badly broken => many convois were stuck FIX: (tron) many errors fixed, working inline assembler for GCC 4.0, imported all old versions into SVN CHANGE: citycars lifetime now in ms => they will be more controllable, since generation is also linear with time (also cleanup of pedestrian code) FIX: overheadwires could be now replaced by a faster type, player was not check during destruction FIX: signals were always built without owner => everybody could destroy them FIX: problem with depots not found: saving and loading should solve this, no longer deleting other people depots Release of 89.03.2 21-Aug-2006: (prissi) FIX: just_in_time is saved with a map FIX: beginner mode properly set/reset with maps FIX: oneway signal on last tile of a route not a problem anymore FIX: height of bridgeheads fixed FIX: loading vehicle image display now matches state of the car FIX: loading vehicles just on their last tile (which also contains a signal) fixed FIX: next depot only finds own depots FIX: proper recalculations yearly income after loading FIX: only change game name if not autosaved FIX: powerlines over monorails and stations but not crossing bridges and elevated monorails in its height CHANGE: numbered station now numbered per town (two new strings '%s city %d %s' and '%s land %d %s') CHANGE: stops covering the townhall will be added monuments 'monument' and townhall/tourist attractions according to their name CHANGE: two more center names '6center' and '7center' Release of 89.03.1 17-Aug-2006: (prissi) FIX: reward for boats in harbours FIX: beginner mode restored after reloading FIX: selection for scrolled list (like in the line dialog) fixed FIX: some corrections for SimuTTD and half tile height in minimap and other places Release of 89.03 13-Aug-2006: (prissi) CHANGE: you can pak object with any size (smaller than 255). The tile size will be taken now from "ground.Outside.pak" (Go for big ships, Timothy) FIX: overhead maintenance take from pak, not from simuconf.tab any more FIX: code file cleaning up FIX: signal appearing immediately after direction changes FIX: mark dirty for higher buildings CHANGE: beginner mode 'Beginner mode' with 1,5times higher prices (can be configured in simuconf.tab) and no just in time factories FIX: under certain circumstances, the wayobj/wayremove found an electric engine and could not lay a caternary ... FIX: hopefully, convois will be no longer try to calculate a route to the position they are already FIX: only money for vehicles in stations FIX: correct number of vehicles reach into the station (hopefully) CHANGE: better progress indicator slowest process (city size growth and road connection) now take most of the bar FIX: full scrolling in map window FIX: no longer messing around in other players depot FIX: restored functionality of 'e' again ADD: generic names for city buildings: If no translation is available, they will be called 'residential house', 'industrial building', or 'shops and stores' Release of 89.02.4 12-Aug-2006: (prissi) FIX: images of bridges after built fixed CHANGE: company color for way and ground (but slower loading, since all images are scanned for company color) This was a heavy rework of the dirty system ... FIX: result of heavy renovation of tile dirty system: much less area copied during each redraw, less garbage pixels left FIX: citylists work again FIX: dummy roadsigns everywhere after reloading games (and info for debug purposes "\nwith sign/signal\n") => stuck trains FIX: coverage area signs now always refreshed after building/deletion FIX: Factorylistbuttontext translated twice Input -> Eingang -> Elevated station ... FIX: more error checking during parsing of help files, unlimited length (before maximum 8192 bytes) FIX: compile error on MAC spotted by Timothy FIX: convoi loosing its name after many actions in the depot ... FIX: choosing of bridges works again FIX: signal and roadsign position on slopes Release of 89.02.3 06-Aug-2006: (prissi) FIX: choose signals and convoi starting repaired FIX: waypoints in tunnels FIX: a little nicer vanishing in tunnels in westward direction ADD: new marker graph FIX: production of factories with large storage or high rates fixed Release of 89.02.2 06-Aug-2006: (prissi) FIX: loading pak translations fixed ADD: ids displayed for convois ("cl_btn_sort_id" sort by convoi ids) FIX: wayobj were not displayed FIX: minspeed signs (and many others) work again for cars (fixed the sprite sorter) FIX: trains ignoring signals after reloading ADD: trams rail over road bridges and through road tunnels FIX: public owner can now build stops anywhere; adjacent stop will be taken over by the public owner; the price is 36*monthly maint.*level! FIX: no depots for public service, since this player is not intended to run any convois FIX: display error with diagonal wayobjects ADD: generic help for factory window Release of 89.02.1 30-Jul-2006: (prissi) ADD: braking before red signals and at the end of stations in the following steps 200,100,50,25 (only stations) FIX: no airplanes servicing oil rigs any more ADD: new text "\nis reserved by:" for showing reservation on tracks FIX: bus checks for electric route Release of 89.02 24-Jul-2006: (prissi) FIX: roadsigns shown in the wrong menus FIX: not cost display for ways FIX: roadsigns error after loading FIX: wrong clipping for scrollbars ... still ... CHANGE: more than one translation for a language in pak/text/ possible CHANGE: if there is a file pak/compat.tab the names will be used to search for vehicles during loading => obsolete vehicles can be appropriately replace + better loading of 128 under 64 and vice versa FIX: correct sorting of goods by name CHANGE: no more railblocks => no signals on crossings (which did not worked well before too), but signals are now only a single tile! ADD: new object way-object for overheadwires or avalanche protection; allows for electric roads too ... top speed in wayobj is limited FIX: correct weight for attractions CHANGE: automatic align of city buildings to the next road, if there is more than one rotation FIX: tunnel construction FIX: clouds now better vanishing CHANGE: one way signs and signal discovered also during routing Release of 89.01 15-Jul-2006: (prissi) FIX: depot with wrongly initialize vehicle list could crash FIX: crash, when selling just under the last line FIX: crash when selling trains with PBS CHANGE: convoi list to array FIX: unreserve route when reserved track is deleted FIX: find route until station end without help FIX: AI now knows about short vehicles and can built smarter stations more often FIX: clipping of lists FIX: one way signals on platforms have been ignored ADD: dates and "waytype=" for signs (not only roadsigns, although only the no enter sign will work on all ways) FIX: crash when deleting world Release of 89.00 (preview) 1-Jul-2006: (prissi) ADD: path based signalling (PBS): There can be many trains in a block as long as their path do not intersect. Release of 88.10.5 (stable) 1-Jul-2006: (prissi) FIX: maintenance for bridges works again FIX: values in finance history init to zero at the start of new year ADD: fences at slopes Release of 88.10.4 24-Jun-2006: (prissi) FIX: margin calculation now (finally) taken into next month CHANGE: finance update only when dialog open or during new month FIX: monorail again above buildings FIX: remove ownership also with undo and track delete FIX: do not hide depots FIX: slopes where buildings are lower than the natural slope will be preserved FIX: signal at bridges now are drawn in the correct height and will not connect to tracks below FIX: open a schedule default mode now "add stop" also selected (not only button shown ... ) FIX: a convoi now only searches for depots that belongs to its owner CHANGE: color indicator now always go from zero to the actual maximum value in the minimap CHANGE: display value in chart under the mouse when clicking on it FIX: harbour under bridges fixed (only a single stop on a tile is now really enforced) CHANGE: search for stop now inline => likely faster search and routing of goods ADD: new error message concerning dock: "Dock must be built on single slope!" FIX: scrollbar in factory windows FIX: clipping errors when letters were vertical (top) clipped FIX: the "cost=" entry in the roadsign files were not correctly saved by makeobj FIX: forgot to add "needs_ground=" to the building section of makeobj. If needs_ground!=0, grass (or snow) will be drawn below a building Release of 88.10.3 19-Jun-2006: (prissi) FIX: wrong buildings on slopes, transparent bottoms FIX/CHANGE: forbid to delete a line assigned to convois (but you could do it without crash anyway again) FIX: set dirty of smoke CHANGE: only smoking chimneys when producing/consuming FIX: another try to fix the depot window to prevent wrong obsolete vehicles FIX: faster, less memory consuming route calculation (about factor of 10-50 for ships) FIX: waybuilder much faster calculation and finally builds diagonals as expected (may have one curve too much but is up to 4000% faster that way) FIX: waybuilder now only generates one sound per tile after finishing construction and you can read the total costs per tile (not painting over each other) CLEANUP: removed all support for savegames before 84.06 since they were not loadable anyway CHANGE: remember last name with that the game was saved CHANGE: hide all buildings (special up to five additional construction sites, if there) CHANGE: allows for non-square factories (leave the empty field out, not fully tested yet) Release of 88.10.2 10-Jun-2006: (prissi) FIX: trains/trams in depot reserved the according block automatically for convoi zero during reloading (even if this was a ship ... ) FIX: sprite sorter now inserts all sprites including pedestrians and citycars in the order they belong (drawing errors with trailer trucks fixed) CHANGE: hour glass during saving ADD: display of powerlines/depots in the map window FIX: delete road under the powerline of a different player CHANGE: after deleting everything from a tile one loses the ownership on this tile again FIX: when the number of vehicles changed during reopening of a depot dialog (either year or electrification) the game crashed ADD: you can create a roadsign which prevent citycars from entering. Use "is_private=1" in the roadsign definition (will be not part of the 64 set though!) ADD: draw way as a normal object by "draw_as_ding=1" in the definition of a way CHANGE: (internal) all defines now in simconst.h" Release of 88.10.1 4-Jun-2006: (prissi) FIX: textinput fields work again as expected, mouse sets cursor position FIX: several places were handling player colors incorrect or not at all FIX: several small clipping errors fixed CHANGE: compiles again with MS Visual C++ Express => better debugging, some little errors fixed, esp. overruns Release of 88.10 2-Jun-2006: (prissi) CHANGE: A* vehicle route finder strongly reworked, extensive tests with priority queues versus simple arrays => arrays are up to 10x faster (less lags with ships, no crashes any more) FIX: elevated monorail slopes during construction FIX: arrows with lines work again in the depot CHANGE: map array now displays always vehicles and is not updated when not open Release of 88.09.6 9-May-2006: (prissi) FIX: raising and lowering land works again as intended FIX: loading slopes for bridge heads FIX: assignment of more than 6 lines ... CHANGE: reader more endian compatible CHANGE: obsolete entry "2LIGHT_CHOOSE" FIX: translator looked words up twice (eating lots of performance with many dialogs open) FIX: line assignment during reloading fixed FIX: depot is updated once before showing it FIX: station ground name was copied on itself FIX: workaround for Linux 4.0.3 compiler bug (will use the C-routines for image display instead of assembler) FIX: several issues with unassigned values and fixed using valgrind Release of 88.09.3 4-May-2006: (prissi) FIX: recompiled with hopefully corrected files => bridges/marker correctly, line number ok again FIX: ownership of public owned road is taken when using trams FIX: last line in schedules selectable again CHANGE: slope now part of ground structure => less errors with monorail over houses CHANGE: gui-components and dialogs mostly separated, lots of code cleanup Release of 88.09.2 1-May-2006: (prissi) FIX: houses in cities on slopes again FIX: can again delete last town too FIX: translator automatically adds "\n" to stations => simutrans will remove this FIX: road under tramway works now as well ADD: scrollbars to save/load dialogs FIX: next month starting date could have been wrongly calculated FIX: age of old vehicles again calculated correctly FIX: depots have again an owner FIX: only clearing trees when building ways, stations and depots will remain (no planes etc. any more) FIX: block cleared correctly, when entering or leaving a depot FIX: no more building factories with distribution_weight=0 FIX: station bar indicator only at stop basis position FIX: bridges in miniwindow CHANGE: internally now allows cover tiles CHANGE: made redraw faster, but set refresh again to 1 for smoother movements. Use -refresh=2 for old speed FIX: engines shorter than 8 units stopped too early in a station => station tile indicator was wrong FIX: convoi mini world view scroll more smooth and displays planes correctly FIX: passengers from/to monuments after reloading FIX: one month too many after reloading FIX: player colors for AI changeable CHANGE: option window renovated (mostly internally, make much more consistent with current windowing system) Release of 88.09.1 23-Apr-2006: (prissi) FIX: signal on illegal coordinates now checked CHANGE: passenger generation now proportional to the inhabitants show ADD: passenger generation can be now adjusted using "passenger_factor" in simuconf.tab. 16 equals the old value. FIX: track deletion of bridges and tunnel now completely deletes them FIX: several errors/inconsistencies with the line management dialog fixed FIX: clipping error when switching players FIX: trees should now regrow at their intended rate FIX: map window needed sometimes a right click to activate CHANGE: mousewheel support for nearly all dialogs for the vertical scroll bar FIX: again normal number of pedestrians, since you can now built on them Release of 88.09 19-Apr-2006: (prissi) FIX: renovation townhall city update (again ...) FIX: lines were created double in depot and not shown in the selection CHANGE: city border are now recalculated after reloading => border can shrink again manually by this CHANGE: deleting a town now also deletes all houses within this town CHANGE: three stage map info window CHANGE: houses now indicate their town in the info "Town: %s\n" CHANGE: renovated player tool ADD: long tracks/monorails/road/channel removal tool FIX: choosesignal deletion was not handled on two places in the blockmanager CHANGE: scrollable help windows with "more intelligent" size calculation CHANGE: road construction also on used tiles, i.e. on top of pedestrians ... Release of 88.08.1 16-Apr-2006: (prissi) FIX: all unnecessary warnings corrected (and an error in the AI module found) FIX: some problem with initialized values fixed FIX: broken convoys after curves, much less "jumping" at waypoints FIX: line selector in depot now hopefully finally fixed FIX: wrong naming of industry stops with numbered stations FIX: 64er aircraft cost optimized for timeline Release of 88.08 14-Apr-2006: (prissi) FIX: line selection in depot window CHANGE: lines now sorted alphabetically CHANGE: new parameter for vehicles in dat files: length=xyz for the length i 1/16 of a tile (default: 8) => much easier stem engines with short tender etc.; but: vehicles with len!=8 better have 8 views, else ... The standard vehicle length are like this for 64: S or W: x=2*len, y=len SE: y=2*len SW: x=4*len CHANGE: no jumping at waypoint on diagonals CHANGE: depot window now displays minimum station tiles needed ("Station tiles:") FIX: signals on stations should now work as intended, even with pre- and choose-signals FIX: when current schedule entry is the current depot, not route message was show => now advance to next entry FIX: many wagon overlapping drawing errors with trains Release of 88.07 9-Apr-2006: (prissi) CHANGE: asynchronous updating of routes and rerouting to avoid lags when building stations/change schedules CHANGE: more CPU-friendly choosing for trains ADD: block tool (b) also checks for double or orphan block and block without signal and corrects it ADD: invalid block ids are now corrected during loading FIX: crash using (t) when no rails are available FIX: signal state in front of waiting train now always red, even for presignals and choose signals FIX: better check for double entries in schedule to avoid crashing CHANGE: line management convoi info more consistent color/names (removed string from translator: "Convois: %d\nProfit: %s"), added min size button FIX: minor display errors with line windows CHANGE: line now accessed via handles (more stable programming, less memory required) FIX: after changing max speed at depot the convoi info shows new max speed FIX: many errors with list management fixed FIX: no loading of smoke => no wrong images emerging after updates FIX: lower right border error when loading reliefdata fixed FIX: wrong speed on bridges after loading a saved game CHANGE: after creating a new line, this line is immediately selected in this schedule window (removed text: "New line created!\nYou can assign the line now\nby selecting it from the\nline selector above.") CHANGE: clicking somewhere else into the dialog will close the line drop down box in schedule and depot dialog FIX: construction of ship depots now again everywhere FIX: redraw error in depot (part of vehicle was visible in certain window sizes outside the box) Release of 88.06.3 ("stable") 18-Mar-2006: (prissi) FIX: deleting of a station did not update the corresponding routes FIX: sometimes route with itself as first interchange appeared FIX: choose signals at a corner now working FIX: more diagonals during road construction ADD: tramlines FIX: convoi changed in depot did not display correct capacity/loading info Release of 88.06.2 10-Mar-2006: (prissi) FIX: after passing a choose signal a single time, all presignals will stop the trains, if not the complete route is free FIX: faster rescheduling of goods now works on demand (after changing a schedule) FIX: error with choose signal fixed, if target tile was not a station FIX: changing ladegrad in schedule first selected invisible item on top of a scrolled list FIX: ladegrad was ignored, if absolutely nothing was there to load or unload CHANGE: choose signal will reserve the full way until the target location FIX: traffic light switched to seldom after reloading FIX: zoom out error with 128 pak and electrification Release of 88.06.1 05-Mar-2006: (prissi) FIX: one way signals/roadsigns work together with the choose points FIX: monorail ground saves slope (otherwise the slope could be changed by building below) CHANGE: schedules are now recalculated more often FIX: no tunnel or bridge destroyed by slopes anymore ADD: indicator for convois stuck for more than a month FIX: much less redraw troubles with slopes (will be drawn as foreground, if any object is behind them) ADD: season indicator FIX: UNDO did remove tracks but no electrification FIX: block reservation now saved CHANGE: made line chart more slim FIX: when vehicle braking was larger than acceleration in curves => acceleration to insane speeds FIX: removing halt with no ground during load FIX: only removing really empty bridges without stops FIX: several translator text adjusted with program texts 04-Mar-2006: (prissi) FIX: choose trains go to the end of a platform again FIX text changed to "Die Bruecke ist nicht frei!\n" FIX: correctly loading and saving monorails Release of 88.06 04-Mar-2006: (prissi) FIX: airplanes check for exit the map (although this should never happen) FIX: runways may only built up to four tiles next to the border FIX: no depots on top of depots FIX: too young trees with different timescales FIX: sort options in convoy dialog were not correctly remembered FIX: presignals works with monorail CHANGE: presignals now reserve needed blocks => hopefully less deadlocks (but may be screwed up during reloading) CHANGE: choose signals are possible (as result of the above change) CHANGE: buttons and labels are now translated, when the text is assigned Release of 88.05.1 01-Mar-2006: (prissi) FIX: townhall added wrong buildings during renovation => crash when generated passengers afterwards FIX: connecting to the end of an unconnected bridge (now again going through tunnel and bridges for way calculation) CHANGE: sync_prepare() only called one time before sync_step() => lost of useless objects are not called any more every frame FIX: trams find depots again CHANGE: built on top of cars or pedestrians (may cause graphics errors) FIX: oilrig and other water factories fixed when loading old sets FIX: wrong sound when closing tool bars FIX: again correct gear in convoi details FIX: several wrong sounds/smoke for vehicles FIX: more error checks for way builder FIX: change to entries to their translator entries: Oktober and Load game CHANGE: all list: left key info, right key goto Release of 88.05 25-Feb-2006: (prissi) CHANGE: runways now system_type=1, independent of max speed FIX: traffic density=0 => no cars generated FIX: townhall construction with uneven grounds FIX: maintenance adjusted according acceleration factor FIX: no longer roads through depots, bus stops or loading bays (hopefully) FIX: sound hashes were wrongly calculated => hopefully fixed FIX: player initialisation during map creation not allowed for passenger stations for player 0 and 1 24-Feb-2006: (prissi) FIX: crash in waybuilder when runway starts on streets or when a way costs no maintenance FIX: wrong slope display (was back to old state?!?) FIX: tunnel block connection FIX: connection rails with tram rails FIX: deleting bridges with roadsigns and stops CHANGE: extended bridge search for unknown bridges during loading CHANGE: all vehicles smoke, if requested FIX: stop of passenger generation when timer overflowed fixed CHANGE: only relative time steps used => much faster and more reliable for the game FIX: nearly complete renovation of blockmanager FIX: F12 key does not crash game anymore CHANGE: bridge may end at vertical slopes FIX: "harbour tunnel" works again (as some other complex tunnels too) 23-Feb-2006: (mip) ADD: citylist including sorting 21-Feb-2006: (prissi) FIX: checking all schedules during loading for illegal entries CHANGE: try even harder to find the right vehicle during loading (=> more chances of loading broken savegames/games from other paks) ADD: new type "monorailstop" for monorail stations and extension buildings (=> makeobj=33) ADD: slower timespeed possible (set bits_per_month in simuconf to values higher 18) and display of day possible (show_month>=2) see simuconf.tab Release of 88.04.4 19-Feb-2006: (prissi) FIX: saving depots FIX: display of attractions Release of 88.04.3 18-Feb-2006: (prissi) FIX: sum up freight of same catg again CHANGE: extended convoi detail dialog, mover kill button to details FIX: ugly tunnel bug changed translations: added: Leistung: %d kW removed: Transported Goods 15-Feb-2006: (prissi) FIX: track builder always failed in a station CHANGE: cleaned up the depot code code, monorail and trams are now classes FIX: monorails no go again to the end of a station FIX: expensive rails are no longer replaced by cheaper ones CHANGE: larger passenger destinations in city window CHANGE: unified color scheme for charts 13-Feb-2006: (prissi) FIX: error check when building stops on completely empty tiles FIX: deleting harbour: water again at correct position ... Release of 88.04.2 12-Feb-2006: (prissi) FIX: monorailine correct FIX: again tram depots FIX: again air stops FIX: remove unused vehicle list (that was really eating memory ... ) FIX: sell again vehicles in depots without removing them Release of 88.04.1 11-Feb-2006: (prissi) FINISHED: full monorail support including ramps (using a bridge) FIX: line financial calculation fixed FIX: line window 8-Feb-2006: (prissi) CHANGE: monorail line FIX: deleting habours CHANGE: goods (bonus) frame FIX: aircraft in depot broke savegame CHANGE: further monorail support 7-Feb-2006: (prissi) FIX: curiosity list was cutting names FIX: no passengers generated after loading of a map CHANGE: unified schedule routines FIX: convoy wait for loading on empty stations work again FIX: convoiinfo help window again FIX: connection neighbours rewritten to check all ground levels => should work with subways too (if they come) FIX: deleting busstops CHANGE: monorail now separate from rail vehicles CHANGE: blockmanager reworked in many aspects 6-Feb-2006: CHANGE: all station buildings routines unified => no crashes of no city there, only two error messages: "No terminal station here!" (4 layout) "No through station here!" (2 layout) => also terminal stations for bus stops, trains or channels CHANGE: all depot buildings routines unified => only one error messages: "Cannot built depot here!" CHANGE: cursor normal after building depot still not fixed: connection code 5-Feb-2006: FIX: line window crashed when opened twice ADD: covertiles over vertical trogs FIX: no vehicle beaming any more (was waiting in sync_step instead step!) Release of 88.04 3-Feb-2006(prissi): CHANGE: big code cleanup, german translation cleaned of all unnecessary strings => all official strings now there CHANGE: map legend now closes with main map FIX: linking order for gdi (=> again wav sound) ADD: error message, if a feature is not yet available. 2-Feb-2006(prissi): CHANGE: sound system now working; all sound are save under pak*/sound with a description either in sound.tab in the same folder or a wavefilename in the vehicle description CHANGE: new menu order, separated monorail and tram; Help button. New text RAILTOOLS, MONORAILTOOLS, TRAMTOOLS, ROADTOOLS, SHIPTOOLS, AIRTOOLS, Help and Fast forward CHANGE: loading indicator and dummy message if no simuconf.tab is found (to avoid 80% of the complains I get via mail!) 31-Jan-2006(prissi): ADD: cityrule T and t for not a stop/stop CHANGE: schedule do not allow waypoints for airplanes over stops FIX: deleting water bridges CHANGE: sound paks halfway done 30-Jan-2006(prissi): FIX: building/destroying bridges, wayfinder for bridges FIX: cost of houses FIX: crash when deleting stations FIX: go home button reactivated ADD: convoi details (new strings: "Manufactured:", "Power:", "Gear:") Release of 88.03.2 29-Jan-2006(prissi): FIX: display of number during new world dialog FIX: renovation townhall works again as intended FIX: convoi count during reloading fixed (leads to crash of line management window) Release of 88.03.1 29-Jan-2006(prissi): FIX: no crossings through stations/bus stops for normal tracks FIX: station naming with industry (%s building %s %s) for industry stops 28-Jan-2006(prissi): FIX: loading lines FIX: convoi info display: much less recalculations during loading/unloading CHANGE: now only the free load in terms of categories is given (not goods) FIX: removed several unused memory wasting variables from gebaeude_t CHANGE: now town passenger skips tourist attractions during town loop iteration => not iterated twice FIX: town statistics 27-Jan-2006(prissi): FIX: New year calculation for Autosave/timeline ... FIX: disable arrow buttons CHANGE: goods list design FIX: new world info some fixes FIX: bridge builder for channels 26-Jan-2006(prissi): FIX: init line ids when destroying maps CHANGE: order of buttons in halt list 25-Jan-2006(prissi): FIX: acceleration on slopes ADD: Repeatbuttons ADD: correctly routing through tunnels again FIX: wrong color in finance window FIX: monuments were not added to towns FIX: tunnel next slopes fixed 25-Jan-2006(mip): FIX: factory list and curiosity list Release of 88.03 23-Jan-2006(prissi): ADD: automatic alignment of station extension buildings (must be either defined with dim=x,y,layout (layout=1,2 or 4), x>=y and following order N E S W) 22-Jan-2006(prissi): CHANGE: now line management for every player 21-Jan-2006(prissi): CHANGE: station now have a capacity of 32*level; thus price reflect station capacity CHANGE: changed owner of several dialogues CHANGE: new world functional, new string "Intercity road len:", obsolete ones. "7WORLD_CHOOSE", "7WORLD_CHOOSE", " 18-Jan-2006(prissi): CHANGE: new town population/passenger destination system (takes into account only existing buildings) CHANGE: new world dialog renovated 17-Jan-2006(prissi): ADD: automatic slider recalculation at halt info and convoi info CHANGE: consistent colors for negative and positive amount in dialog (red/black) FIX: wrong maintenance calculation when replacing roads (include other players ones) 16-Jan-2006(mip): CHANGE: new attraction list ADD: overlooked the following translations: "\nelektrified", "\nnot elektrified", "\nRail block ", "\n\nRibi (unmasked) ", "\nRibi (masked) " 14-Jan-2006(prissi): FIX: building constants now configurable in simuconf.tab (see there) FIX: new player frame (mostly internal change) 13-Jan-2006(prissi): FIX: way is kept when building/removing bridges ADD: tooltip "Alters a schedule.", "loaded" for convoiinfo, further rearrangement CHANGE: goods in convois and stops are sorted by the same rules => same sorting options CHANGE: convoi freight info and stop freight info only updated when needed => saving lots of time ADD: translations "follow me", "Follow the convoi on the map", "Sort by" 11-Jan-2006(prissi): CHANGE: convoi_info new text "%i km/h (max. %ikm/h)" FIX: (un)loading in harbours CHANGE: following convois via convoi info FIX: crash building tracks under pillared roadbridge FIX: again schedules with only one stop possible 10-Jan-2006(prissi): CHANGE: following convois via convoi info FIX: crash building tracks under pillared roadbridge CHANGE: better error check before building harbours CHANGE: definition of wege FIX: first all down will flatten a tile (more intuitive), using a slope on identical couble slope will make it steeper 9-Jan-2006(prissi): CHANGE: convoi list: minus red, further polish of halt_info CHANGE: halt_info: obsolete strings "Akzeptiert" FIX: scroll_pane now clips correctly CHANGE: speed bonus now in percentage instead of absolute speed => higher bonus for earlier fast stuff, lower for new stuff (may require new balancing :() (but effect not too much, only very fast things get a little less) the formula is now speed_bonus_faktor = 100*speed/mean_speed-100 (i.e. the speed difference in percent) => goods_price*(1000+speed_bonus_faktor*bonus_faktor(10%=10))/1000; CHANGE: new good list, obsolete translations: "Preis", "Bonus", "Category", "Speed boni for road %i km/h, for rail %i km/h, for ships %i km/h, and for air %i km/h." CHANGE: new texts: "Speedbonus %i%%:\n road %i km/h, rail %i km/h, ships %i km/h, planes %i km/h.", "gl_txt_filter", "gl_speed_up", "gl_speed_down", "gl_btn_unsort", "gl_btn_sort_name", "gl_btn_sort_revenue" FIX: powerline construction now cost again money ... FIX: wrong tunnel slopes solved FIX: building on slopes not destroyed during reloading Release of 88.02.1 8-Jan-2006(prissi): FIX: error with slopes mostly fixed => you can even built a channel using slopes FIX: monorails now display again correctly FIX: no rails at tunnel start FIX: station alignment on bridge start fixed FIX: no automatic bridges and tunnels any more => no crashes for public road and other occasions Release of 88.02 7-Jan-2006(prissi): FIX: aircraft did not accelerate after reaching flight level CHANGE: "cooperate identity" exactly same dimensions for all list buttons started CHANGE: halt info, new text "Passengers %d %c, %d %c, %d no route\n\nCapacity: %i\n" instead "Passengers today:\n %d %c, %d %c, %d no route\n\n%s\n" CHANGE: elements of halt list rearranged => more compact design CHANGE: adjustable costs for many things, level for station buildings ... (see simuconf.tab) FIX: double character with GDI and numlock 1-Jan-2006(prissi): FIX: changed all income calculation to 64 bit => hopefully no overruns any more FIX: wayfinder check now for artificial slopes and starting tile CHANGE: cost of land changes more balanced, tunnels more expensive CHANGE: nicer indicator in lower line FIX: 8 bit SDL works again fine 31-Dec-2005(prissi): CHANGE: makeobj recognizes now all waytypes in all relevant objects FIX: way finder now takes care of powerlines when building bridges FIX: now slopes are correctly checked before built => more slopes possible FIX: selling airplanes do not delete a depot 29-Dec-2005 (prissi): FIX: deleting order change => no crashes when quitting a game with vehicles in depot that are assigned to a line CHANGE: ways now take care of their images themselves also for crossings CHANGE: new slope calculation working (needs new graphics) 28-Dec-2005 (prissi): CHANGE: way image is now calculated by the way, not by the ground => 4 Byte less per tile CHANGE: correct calculation of offset for double height slope building foundations 27-Dec-2005 (prissi): CHANGE: more flexible bridge search in wegebauer CHANGE: using existing bridges/tunnels when calculating new ways ADD: estimates cost for construction before building ADD: show difference to start location when building ways CHANGE: more prominent waiting display in the schedule window Release of 88.01.3 26-Dec-2005(prissi): FIX: cursor keys for SDL and Allegro FIX: mouse pointer for Allegro FIX: symbol alignment fixed for message options FIX: missed airplanes again included into 64 pak Release of 88.01.2 25-Dec-2005: two tiles drawing code operational; but, the effect is rather small and only seen in very hilly maps 22-Dec-2005: FIX(prissi): change factory precision to allow high-volume production FIX: redrawing title bar under not Allegro 21-Dec-2005 ADD(tron): new makefiles (all options now in config.default, copy config.template and edit this) ADD(prissi): citycars with destinations (not recommended, just to many which want to reach places without roads) FIX(prissi): Allegro now with mouse in menu bar 18-Dec-2005(prissi): ADD: colors for channels in minimap FIX: factory now consumes goods according to their setting (before: the number of products) If a factory produces less, it will consume less. FIX: 's' builds road again 13-Dec-2005(prissi): FIX: when deleting a line, the schedule from convois in depot will be deleted FIX: dinglist could cause a crash when asking for a single deleted object (i.e. on a road) ADD: factory added to stop names (when built close to it) 12-Dec-2005(prissi): FIX: powerlines again buildable FIX: route calculation of aircraft improved CHANGE: wait for loading percentage now several numbers with wrap around ADD: waypoints for planes ADD: aircraft circle during waiting for free stop Release of 88.01.1 10-Dec-2005(prissi): ADD: citylist with total inhabitants ADD: new switch in simuconf.tab "just_in_time" (default=1) which allows switching off just in time logistics CHANGE: new factory construction: try to connect always to an existing factory, and ignore the distance, if the connection factory is not an elemental source FIX: redraw error, when AI changed land height hopefully fixed CHANGE: map display updated also with several options on 6-Dec-2005(prissi): FIX: takeoff/landing direction FIX: overflow on large maps and long transport FIX: waybuilder now forbid curves on runway nearly 100% (only be deletion still possible) ADD: nl key file by stormoog FIX: no queuing over airstops for flying planes 3-Dec-2005(prissi): CHANGE: A* for ways (finally!) FIX: drive on left zoom out bug in 128 solved (this one was well hidden) FIX: key handling in SDL renovated FIX: more error checks when deleting signals to recover from orphan signals from before ... Release of 88.01 2-Dec-2005: FIX(prissi): fiddled a little around with the signal deletion routine. No crashes, after a some tries FIX(prissi): monorail again deletable FIX(prissi): identical blocks on different tracks when using undo fixed ADD(mip): Marko keys (set them with CNTRL+F2...F14) and recall them with simple F2...F14 FIX(prissi): tool bars again in more rows FIX(prissi): cleaned up sources, took in Allegro support (wow, is the fastest so far!) FIX(tron): nice makefiles 30-Nov-2005 (prissi): FIX: air depot/terminal alignment FIX: only straight runways FIX: power large than 65536 and gear larger than 255 are now handled correctly FIX: slower acceleration on runways FIX: when ground was changed, airplanes were stuck FIX: "nicer" calculation of speed during different flight positions FIX: made planes compatible with half height version FIX: error when zoomed out with different base tile sizes FIX: A* route calculation was actually wrong and very badly implemented FIX: AI even more biased towards networks FIX: fiddled a little around with the signal deletion routine. No crashes, after a some tries FIX: monorail again deletable FIX: identical blocks on different tracks when using undo fixed 28-Nov-2005: FIX(mip): curiosity list used strtok, which wrote into the read-only strings from translation! (also customize display: "%s (%i,%i) - (pax %i, post %i)" for translation) FIX(mip): FIX(hsiegeln): divers error messages around schedules and station buildings Release of 88.00 22-Nov-2005: FIX (hsiegeln): do not count vehicles in depot for line capacity FIX (hsiegeln): display in convoi and schedule list FIX (prissi): vehicles in depot are shown, even if obsolete (but apparently worked before too) FIX (prissi): speedboni are always initialized with default values CHANGE (prissi): zero number if goods waiting are omitted in haltlist FIX (prissi): vehicle going in wrong depots CHANGE (prissi): haltlist now also with CNTRL functionality (CNTRL+click = only jump to position) 20-Nov-2005 (prissi): FIX: no income generated at waypoints ADD: free chose of stops for cars after certain signposts (new sign flag "free_route=1") ADD: new entry for halt filter (type "hlf_chk_airport") ADD: indicator for city attraction in the attraction list FIX: cursor alignment for up/down fixed FIX: minimum income for any good is 1/8 of the normal income, even if speed bonus is negative 17-Nov-05 (hsiegeln/prissi): ADD: airplanes ADD: stations need support building for certain types. Now there are freight stations that needs a waiting hall to accept passengers. for the obj=building the type="" has been extended by the following types. station - Rail stop (2 dir) busstop - Road stop (2 dir) carstop - Road stop (4 dir) habour - in the sea (4 dir) wharf - channel stop (2 dir) airport - plane stop (4 dir) These can have additional flags strings: extension_building=1 - extents like the station buildings (1 dir) (cannot build on a way) enables_pax=1 - passengers can travel from here enables_post=1 - mail can start from here enables_ware=1 - good are accepted here Without these flags, a stop will not accept anything! A freight station must posses "type=station enables_ware=1" or it won't accept freight. For generic, not stop specific buildings, there are three entries left: hall - waiting hall (1 dir) post - post office (1 dir) shed - goods shed (1 dir) The halt list and halt dialogue are extended by a small symbol indicating what this station accepts. Release of 87.02 13-Nov-2005 (prissi) FIX: after reloading, check stations for post offices (was broken before) FIX: search for next station failed too often FIX: error message when AI failed building a route does not appear any more FIX: crossing channels with electric wires again ok FIX: going to end of station also on bridges FIX: avoid deleting parts of a bridge FIX: default filter state for convoi list is off CHANGE: A* for faster pathfinding and preference of faster ways for faster vehicles FIX: correct booking of roadsigns FIX: again sorted as intended by category amount transported engine type, speed, power, ... FIX: some further finetuning of cost, speeds etc. FIX: some goods were wrongly joined, if there were two goods for the same factory at the same final stop ADD: click on vehicle in depot will open depot window (should be like that from the beginning ... ) CHANGE: factory names for 64 changed again for compatibility with very old savegames (but 87.xx might not load!) CHANGE: renovated japan pak for timeline and consistent building names, many new trams ... Release of 87.01 4-Nov-2005 (prissi) FIX: loading old maps with obsolete docks FIX: no route next to attraction should now have a more meaningful number (so you can better guess how much you have to transport) FIX: mail from attractions and factories again 4x received mail CHANGE: some further small optimizations for faster drawing of dialogues CHANGE: vehicles now sorted in depot by intro year and engine type 3-Nov-2005 (mip) ADD: curiosity list 3-Nov-2005 (prissi) ADD: channels as waterways, habour as "...ChannelStop" FIX: mail flag correctly recalculated after changing a station FIX: deleting tunnels 30-Oct-2005 (prissi) FIX: builds again presignals FIX: under some circumstances, building on ways (e.g. all stations) were not correctly removed FIX: several data of pak64 vehicles finetuned, mail carriage added, busstop before 1900 added ADD: Fast forward (keycode W) ADD: indicator for fast forward and timeline (translatable "timeline" "no timeline") FIX: calculation of speed bonus changed => bonus not per car, but per passenger FIX: timeline was sometimes some years off; especially after loading old games Release of 87.00 27-Oct-2005 (prissi) CHANGE: train outside depot on same square are displayed first CHANGE: no goods are sent to overflowing industries CHANGE: halt status color also red, when goods are overflowing station CHANGE: accepts freight at all stops near factories (including bus stops) CHANGE: road, rail and ship bonus now depend on average speed, if timeline is on FIX: some errors loading older savegames fixed FIX: on animated tiles missing phases will return the tile at phase=0 (i.e. baumarkt) FIX: alignment error of up-/down slopepointer FIX: could remove a non-empty depot ... FIX: industry chain creation could crash without cities FIX: schedule is corrected for invalid entries after input ADD: full use of copyright entries for houses and vehicles 24-Oct-2005 (prissi) FIX: roadsign cost correctly display (and not free anymore) and now also on bridges FIX: return ticket finally working (was too easy to do it right?!?) CHANGE: close topmost window by ESC or DEL FIX: not replacing city roads below depots (fixed sending home error) FIX: removing overhead wires make now removes electrified status again CHANGE: Using Mersenne Twister algorithm for faster and better random numbers FIX: when renovating, check, if I can renovate something; if highest level reached: do nothing CHANGE: full building timeline for 64 pak with many new building (=> can play from 1900) CHANGE: era and copyright message for buildings ADD: many new trams, alignment corrected for existing ones ADD: new player1 tool: jump a year forward CHANGE: haltlist now member of planquadrat ADD: stations on bridges CHANGE: also for stops, station, schedule entries, roadsign signals: CNTRL is from up, normal from down Release of 86.10.5 16-Oct-2005 (prissi) FIX: time now corrected after loading (no jumps) CHANGE: city takes over city road ownership CHANGE: growth now size dependent (max 1.67 for <1000, max. 3 for <1000, max. 6 for other) FIX: good distribution always, when more than 10 produced: non-distributing factories should be gone FIX: passenger and mail coverage display fixed FIX: connection from factories and town were asymmetric and only passengers went to the last factory in the list CHANGE: train can drive now on any track (also on public owned roadcrossings ...) 15-Oct-2005 (prissi) FIX: deleting upper and lower objects tweaked a little FIX: also now deleting of tram rail on a road works out ADD: public stops for player 1 can be now constructed everywhere. New tiles of this stop will be also public. 14-Oct-2005 (prissi) FIX: timeline can be also altered afterwards on non-locked maps FIX: crash when lowering land at the lower right border CHANGE: selection of next building now via "chance=" (default 100) CHANGE: timeline enforced for ways, bridges, and buildings incl. stations and attractions (new makeobj needed, support now fully retire_year/retire_month and intro_year/intro_month) Release of 86.10.4 13-Oct-2005 (prissi) FIX: no power generation in foreign languages fixed FIX: after assigning the same line twice, convoi did not move anymore FIX: may be fixed problem in industry chain building FIX: current entry not changed when appending to a schedule FIX: vehicle will only load people up to the next time it reaches a stop CHANGE: CNTRL+roadbuilder will replace also fast by slower road FIX: first use of 's' for roadbuilding -> crashed program FIX: setting new schedule could crash on fast computers or long lines due to recursive calling ADD: two new settings to simuconf.tab "only_single_info" and "window_buttons_right" CHANGE: configure, that always a single window opens up CHANGE: for you arabic and hebrew writers and all brainwashed by gates: close button configurable to the right (goes best with Win98 skin ... ) ADD: timeline, starting year and cheating mode can be set in the starting menu (and will be fixed further one, allowing for competitions) ADD: new edit tool to protect a map from further change CHANGE: new spanish, portuguese, czech, and dutch translation for 64 set CHANGE: further reordering of deletion order ... FIX: if factories were connected via station areas, goods disappeared ... Release of 86.10.3 09-Oct-2005 (prissi) FIX: size of station coverage wrongly calculated FIX: order of object deletion a little adjusted CHANGE: can delete pedestrians (sound really like hitman on the nearby roof :() ADD: CNTRL+remove will remove ground objects first FIX: detail button in factory info was wrongly aligned FIX: error with construction site lookup some FIX: deleting signals should now work better than before Release of 86.10.2 5-Oct-2005 (prissi) FIX: fundament slope drawing errors corrected FIX: showing attraction in the minimap removed all attraction from the internal vector => crash FIX: crash when deleting the last stop of a schedule (revolved to increase the maxi-counter in fahrplan_t) => savegameversion 86.10 CHANGE: removed halt_list from factory, changed fpl to minivec_tpl (now max. 255 stops in a schedule) CHANGE: route of goods was calculated twice when delivering to a station FIX: stealing from competitor works now (and also more intelligent goods distribution from factories) ADD: status now also shown in factory image FIX: more than two near stops (error in inset template) FIX: correct translation (and maybe also player issues) solved with line management CHANGE: 't' and 's' remembers last used track/road type for construction FIX: update errors in depot 4-Oct-2005 (mip) ADD: factorylist (new entries in translation: fl_title, Fabrikname, Input, Output, Rating) Release of 86.10.1 3-Oct-2005 (prissi) FIX: city check now for all non-removable objects before expansion FIX: check with valgrind -> no errors left (apart from SDL and lost memory) ADD: preliminary monorail-support (vehicle needs still better alignment) ADD: waypoints on bridges (and other preparations for station on bridges) Release of 86.10 2-Oct-2005 (prissi) FIX: removed some out of bounds arry_tpl's access. FIX: error with deleting the last objects from a tile (errors in dingliste_t) FIX: traffic light graphics were wrongly ordered FIX: no longer burying ship depots under sea mountains CHANGE: ausflugsziele now weighted array (weighted_vector_tpl) -> faster selection of passengers CHANGE: cities now weighted array (weighted_vector_tpl) -> faster selection of passengers, more travellers to bigger cities CHANGE: intercity travellers will now also go back (=> more traffic from larger cities) CHANGE: goods will be now distributed to the stop which is a) not overflowing and b) has less in storage (so you can "steal" from another company) CHANGE: travellers destination cities are now weighted by their size FIX: minimap redrawing when changing grid ('#') fixed FIX: numbers in depot correctly updated FIX: no more crashes with pillars FIX: also when building stop after a schedule is set, this schedule will be recognized Release of 86.09.3 24-Sep-2005 (prissi) FIX: also loading games with too many objects on one tile (warning will be given) FIX: working again with factories with more than 30 destinations and 10 suppliers FIX: artificial slopes now nearly always ok (one case is not solvable) FIX: reloading streets with paveway are again 50km/h FIX: sending back pax was not trying original destination => too many no route FIX: forgotten comment: citycars deceased after 100 hops ... ADD: traffic lights Release of 86.09.2 23-Sep-2005 (prissi) FIX: citycar stopped also when passing a car FIX: correcting rail blocks when loading FIX: destroying building cost again money FIX: try to fix memory leak with powerlines FIX: not post for non-accepting stops (check for correct routing please) FIX: screenshot for windows again ADD: show accepted good types also in station details FIX: pillar show bridge info FIX: several alignment errors with yellow steel bridge ADD: brick rail viaduct ADD: length limit for certain bridges (max_lenght=) Release of 86.09.1 16-Sep-2005 (prissi) FIX: bridges now cost again money FIX: citycars and pedestrians behave now as intended FIX: citycars delete themselves at the end of their lifetime CHANGE: non-square buildings are allowed also without rotation FIX: click in town tool now on correct line FIX: overlarge windows now moved to left corner FIX: again water industries (was built in wrong order [pri=1]) ADD: resizeable depots ADD: preliminary support for pillars in bridges: "pillar_distance=1...x" (distance [0=default off]), backpillar[s]=..., backpillar[w]=.... Release of 86.09 13-Sep-2005 (prissi) ADD: Additional tool "natural slope" CHANGE: changing terrain becomes much more expensive (so use bridges and tunnels more often) FIX: some more drawing errors with slope fixed CHANGE: more equal distribution of tools in a toolbar CHANGE: citycars will no turn into a dead end (check 2 tiles ahead) FIX: again pedestrians (was broken since 86.07) CHANGE: new setting in simuconf.tab: "drive_left" will offset all citycars, trucks, roadsigns, ... to the other side of the road (there will be still some clipping errors) CHANGE: artificial slopes now includes the natural ones ADD: Isaac new roadsigns ADD: cityroad configurable "city_road_type" in simuconf.tab FIX: cars now also wait on diagonals CHANGE: new vehicle-sorter, thus trams look a little better and it know about left side driving 11-Sep-2005 (prissi) FIX: cursor keys with SDL working again FIX: remove obsolete keywords from translations, also small font will be ignored FIX: en.tab and de.tab for finances/map legend ADD: Some buildings from Moistboy and de/en translation texts ADD: road inside city limits will get a sidewalk after some time ADD: "Total inhabitants:" to citylist which shows the number of total inhabitants CHANGE: made dinglist to maximum size 255, and single objects are stored directly => much faster loading, saved another 2 bytes per tile and 32 byte per empty tile/one object tile CHANGE: removed fundament type from ding-types => 56 bytes less per building FIX: Some more error checking, when loading ways => can cope with unknown ways Release of 86.08.1 10-Sep-2005 (prissi) FIX: wrong engine types for obsolete rail type "electrified_track" in old packages FIX: SHIFT again dead key with SDL FIX: after removing stops from a schedule, the removed stop was not updates => passengers waiting for non-existent lines CHANGE: Allowing for 32 workers destinations (More would be easy, by may slowdown passenger generation a little.) CHANGE: haltlist to minivec_tpl => saved about 2 bytes per tile FIX: error check during scroll bar creation CHANGE: tried yet another set of routines for GDI which seems to work on all machines I could test CHANGE: newly arranged finance window, obsolete string now "Construction:", "New Vehicles:","Vehicle Running Costs:","Revenue:","Total:","Maintenance:","Balance:" Release of 86.08 3-Sep-2005 (prissi) FIX: convoi in depot which were assigned a line or a schedule started after reloading. CHANGE: Separated map and legend. Got rid of small font FIX: Closing button should check, if closing is ok. ADD: built straight ways by pressing control during mouseclick (just using a dumb minimizing distance algorithm) FIX: factory production calculation could overflow under bad circumstances. Release of 86.07.4 2-Sep-2005 (prissi) CHANGE: new map button "factories", no more clutter in the legend FIX: divers "delete" to "delete [] ", which are different operators. valgrind now only complains about SDL stuff. Release of 86.07.3 30-Jul-2005 (prissi) FIX: cursor alignment with 128 FIX: no money making by open schedule window during loading in a station FIX: message list now displays all messages again FIX: divers errors around the GDI display routines and further speed up + sound and midi FIX: cursor offset finally corrected for all display widths Release of 86.07.2 25-Jul-2005 (prissi) FIX: again correct train types for newer paks FIX: error during loading was using evt. uninitialised minimap CHANGE: order in railtools and tramstools roughly similar CHANGE: background for tunnel graphics (was returning always foreground) CHANGE: AI will always keep cityroads FIX: roads under harbour deleted FIX: AI now uses better calculation of income (before always the farthest factory won) CHANGE: zeiger now drawn on to of everything CHANGE: allow to crossconnect all factories (via crossconnect_factories=1 in conf/simuconf.tab) FIX: factories initiated more than one smoker instance during loading (could break savegames) FIX: cars and trains now really vanish in tunnels (more or less) CHANGE: wrote extremely simple direct copy in Windows-GDI. Seems 2x faster than SDL and the debugger works a little, yeah!!! Release of 86.07.1 15-Jul-2005 (prissi) FIX: fundament as subtype of grund was a bad idea: no more objects were detected! FIX: no new month after starting a new game! FIX: error in routings could led to a crash of the sort routines displaying the station info! CHANGE: extensive correction no done during loading of savegames. If you are lucky you may be able to load an 128 savegame (or a german) with the 64 and vice versa. CHANGE: weg_t are now the only waytypes (vehikel_besch_t::strasse no longer valid) CHANGE: made way for lower hills (actually there is a TTD-like graphic set under way ... ) Release of 86.07 13-Jul-2005 (prissi) Internal cleaning up of some data structures => more run-time memory, preparation for other machines/64 Bit Repaired/Changed some code to make it compatible with DevCpp Changed the list handling code: There was a lot of unneeded memory use (class instead struct) and some overhead. Also more friendly to different compilers. Changed the mempool code: Reuse the blocks also used for the list handling code (will be always size of 4, 8, 12, ... bytes up) CHANGE: removing now first deletes citycars, then roadsigns/signals, otherwise like before FIX: key help dialog is now a magic one (only open once) FIX: limit maximum speed even hill down to maximum_speed+20 (higher speed would likely cause a derailment in reality) FIX: now the absolute year is saved (avoid cheats) With saving and reloading every 500 years or so this should allow unlimited long games. CHANGE: Non-quadratic maps (my favorite is always 512x256) CHANGE: Unmagic cityinfo (so you can open more than one) and city info does not forget its settings anymore CHANGE: try to built a little more straighter road/tracks also for diagonals (not 100% working yet) ADD: presignals now possesses a third stage, i.e. next block free, but next one still not free FIX: Paranoia check during loading can partly repair broken savegames during loading/saving CHANGE: vehicle values drops now 50% in 20 years and changes monthly. CHANGE: passengers and goods are first loaded for the nearest stations the convoi goes. This allows to built local and station skipping highspeed lines. ADD: after three month not moving, citycars will turn around. If still stuck, they will report "To heavy traffic\nresults in traffic jam.\n" as a problem CHANGE: citycars will wait for next free hop in a step() (saving lots of calculation time) CHANGE: autosave value gives now interval in month (0=off) FIX: no more redraw errors with slopes behind buildings CHANGE: sorting by number of passenger for the next destination (i.e. connecting to xyz) 64 Graphics: ADD: new station building and new harbours from timeshock/converted 128px graphics Release of 86.06 6-Jul-2005 (prissi) FIX: calculation of slopes after lowering landscapes now correct FIX: connection with a near stop could fail for non-symmetrical station buildings FIX: full-window mode works more reliable FIX: crash, when the land on a route was removed FIX: From a stop under a bridge a vehicle can directly hop onto the bridge (error in koord3d comparison, might be also affected other places!) FIX: railwindow and editwindow excluded each other ADD: normal cars now also do not run over each other but wait like trucks etc. ADD: roadsigns for no entry and minimum speed ADD: name of current player in the bottom bar ADD: many new help texts from Gotthardlok Release of 86.05.1 23-Jun-2005 (prissi) FIX: now correct waytype when building tunnels CHANGE: mail now passenger tab in depots, wagons without payload (usually tender) also into engine tab FIX: delete of multi-tile buildings improved ADD: deleting industries works, if no station is connected ADD: deleting towns by deleting townhalls (the other houses are not affected by this; but only houses within city limits can generate passengers) FIX: avoid dropping of frame time below 10ms FIX: convoi info windows not correctly checked FIX: error message when raising/lowering tiles now correct (came never/too much) ADD: monthly autosave (option "autosave = 1" in simuconf.tab) as file autosaveXX.sve (XX=01..12) FIX: message repeat now changed a little: Now route/overcrowded messages will be repeated after one month 21-Jun-2005 (prissi) FIX: fullscreen mode from simuconf working. FIX: redraw error when raising water. ADD: 'P' to change player (player 0 is construction AI). ADD: Edit menu for player 0 (grow city, shrink city, build cityroad, build attraction) CHANGE: build industry now into edit menu Release of 86.05 17-Jun-2005 (prissi) FIX: no resize when dialog open FIX: AI busses waiting at tourist attractions were not added to routing tables (and updating tables now asynchronous process). FIX: passenger AI could cause random crashes. Also test for indirect connections was no working. Now only new route built, if more than three stations bypassed. CHANGE: rearranged icon in the slope tool CHANGE: 4 new slope graphs => much less drawing errors (backward compatible) CHANGE: forbid use of slopes on potentially dangerous tiles (message: "Tile not empty.") ADD: support for headquarters (in dat: obj=building, type=hq, parameters are level= 1,2,3,4,... and passengers=xyz) (Press 'H' to built) CHANGE: No stop at waypoints on straight tracks FIX: fullscreen-switch repaired Release of 86.04 11-Jun-2005 (prissi) FIX: Jumping trains with no route/wrong depot fixed. FIX: rotation for townhalls. CHANGE: add schedule will be reset after closing a window. ADD: Window resize of main window. ADD: Input conversion for non-latin languages. CHRxx (xx is hex between 80 and FF) will be translated from tab-file. Missing entry will give default. FIX: check when building docks Release of 86.03.4 03-Jun-2005 (prissi) FIX: crash during return to depot. FIX: problems at signals/depot exit to 75% solved. CHANGE: now a change for connecting even to distance industries. FIX: error with calculation of left over productivity of a factory. FIX: slower aging of messages. Release of 86.03.3 01-Jun-2005 (prissi) FIX: long routes also found on large maps by increasing the number of steps of the variable "max_route_steps" in simuconf.tab (default=100000, useful maximum size^2 [16 Byte/entry]) FIX: crash when town growth requires new industry, but nothing found. FIX: to fast disappearing of income messages. FIX: bug during entering a schedule when open multiple windows FIX: raise height until level 14. FIX: wrong season when loaded. Release of 86.03.2 25-May-2005 (prissi) CHANGE: station_coverage_size now saved with a savegame. For old map, default is 3. FIX: opening the minimap on faster systems yield FPS>1000. hopefully fixed (+ default refresh=2) FIX: retire messages now appear FIX: outdated or future vehicles now display with a blue bar instead crashing in a depot FIX: finetuning number of trucks for AI ADD: parameter "-fullscreen" for command line resp. "fullscreen = 0/1" in simuconf.tab Release of 86.03.1 23-May-2005 (prissi) FIX: overflow in vehicle array position (was not extended) CHANGE: made the drawing a little more fluid: everything will move smoother than before (just forced redraws before idle wait) With -refresh 2 even the 128 can be played very fast. FIX: Pause could cause a hangup/division by zero. FIX: Hopefully no longer factories on slopes or roads Release of 86.03 18-May-2005 (prissi) ADD: "citycar_life" to simuconf.tab (How many tiles can a simutrans car go, before it forever breaks ...) Answer about 2500 per year (depends on speed), default 35000 ADD: citycars now obey timeline (if switched on) ADD: sorting of road and bridges by their speed FIX: hopefully fixed some bugs relating to passengers at attractions FIX: some bug relation to AI and vehicles with trailer fixed? ADD: building post offices on slopes ADD: station buildings possible (name must end with "...StationBlg") Will also extend the storage by 128. ADD: allow larger maps (but will need lots of memory) and longer trains (up to 24 cars). ADD: display of station capacity ("Storage capacity") FIX: not starting up when japanese was selected CHANGE: calculation of FPS change to a real time based system to avoid very high FPS with high accelerations (downside: at very high stretch times vehicle movement less smooth) New entries for citycars are: speed, intro_year, intor_month, retire_year, retire_month 15-May-2005 (prissi) CHANGE: Trams only in tram depot (tram only if "waytype=schiene_tram") CHANGE: obsolete vehicles can be hidden if the timeline is on CHANGE: no electric units shown, if depot did not have catenaries CHANGE: new tab for passenger vehicles (to show EMU heads, use freigth=Passagiere and payload=0, to add them here) Name is "Pas_tab" (trains), "Bus_tab" (cars), and "Ferry_tab" for ships. FIX: depot window can be now redraw by clicking the obsolete button (will fix display after electrification or rezoom) FIX: second row should be selectable after rezoom in depots FIX: several small things increasing compatibility to standard C++ (compiles on GCC 2.95) FIX: citycar_writer fixed FIX: click with tool windows now obey used/unused images Release of 86.02.2 11-May-2005 (prissi) CHANGE: produced good go now first to the factories, which have a storage, that is not overcrowded CHANGE: removed the step-wise route recalculation at halts into a monthwise one. FIX: error, when good is already at target stop hopefully finally fixed CHANGE: retiring date for city cars and engines CHANGE: production now really the value in the dat-files => resetting several 64pak values FIX: factory location searcher works again as intended FIX: some things which placing bus stops FIX: no longer send cars to tram depots and vice versa FIX: no production during pause any more FIX: no longer many transparent pixels when zooming Release of 86.02.1 05-May-2005 (prissi) FIX: error when creating goods and all destinations were empty: only first was served FIX: no longer people waiting for transport to own stop FIX: numbers of created with no route at station display corrected corrected FIX: station type was not calculated after loading => station list empty FIX: presignal crashed, when deleted tiles of a calculated route FIX: pedestrian graphics fixed Release of 86.02 01-May-2005 (prissi) FIX: error when loading UTF8 citylists fixed FIX: rebuild destinations, when convoi was removed by x => no more stale freight waiting FIX: when convoi self_detructs, its value is booked back to the owner FIX: when station already is already destination => just happy ADD: vitus new pedestrians to 64-pak CHANGE: oilfield to Ravens oilfield 24-Apr-2005 (prissi) FIX: no route found, when factory was to close FIX: crashes, if delivery with unknown route?!? 20-Apr-2005 (prissi) FIX: ware could not unload at a dock => internal connect calculation no with halt basis_pos FIX: again detailed information from public stops CHANGE: allow more than one row in the tools CHANGE: color indicator on simloops and FPS CHANGE: random pedestrian now switch off also in dialog (6LIGHT_CHOOSE), 7WORLD_CHOOSE removed (identical) CHANGE: year now also updated in city chart FIX: UNDO repaired FIX/CHANGE: factory production from dat-files is now per whole factory and independent of the load of simutrans FIX/CHANGE: distribution now when more than 10 produced (instead 32) FIX: makeobj always appended a cursor and a symbol, even if none defined. CHANGE: factory list to vector_tpl, halt_list of grund_t now on demand -> should save lots of memory Release of 86.01 19-Apr-2005 (prissi) CHANGE: passenger to attraction/factory is equal to returning number; mail is 1/8 of returning. This comes for free and reduces the load considerably. CHANGE: when a ware was added to a station, the route was calculated again in case of pax CHANGE: passenger generation/routing cleaned up and reworked => much faster FIX: now really closing all windows before loading CHANGE: Building do not step anymore, if not necessary => much faster CHANGE: simloop/FPS system complete reworked to allow more time for other applications resp. a smoother scheduling all other times. But now no time stretch <1.0 possible CHANGE: factories are now built every 2^x*industry_increase_every 14-Apr-2005 (prissi) FIX: no more adding cities after loading corrected; also now in principle an unlimited number of cities should be possible (but something still breaks at 64 ... ) FIX/CHANGE: traffic to an attraction is now proportional to the level of this attraction FIX: ships could only unload under the harbour ... CHANGE: random now c instead of C++ => a little faster CHANGE: line in fillbox a little higher FIX: new GB citylist FIX: CMOCxx cause pre PentiumPro to crash => exchanged 10-Apr-2005 (prissi) CHANGE: trees have now also an distribution weight (default=3) FIX: transportation revenue also calculated, when vehicle was stopped for new schedule FIX: dirty_rect for vehicles was to small => traces were left! Release of 86.00.3 9-Apr-2005 (prissi) FIX/CHANGE: datatype for city array_tpl now vector_tpl -> more access checks CHANGE: townhall_info added to simuconf.tab to avoid passenger level info window of townhalls CHANGE: calculation intense station type is now only recalculated after construction work FIX: AI busses waited also on overcrowded lines and always created only one bus ... FIX: player images were displayed two times using slow and fast routines ... urg! FIX: tourist and city building passenger amount per time now comparable CHANGE: hopefully removed all spaces from pak64 file names (will break old savegames) FIX: mip_cobbelstone maintenance corrected FIX: trams corrected FIX: added new pedestrians from Vitus Release of 86.00.2 8-Apr-2005 (prissi) CHANGE: new signals for 64 CHANGE: different signal graphics for electrified and normal tracks (if more than 8 images defined) CHANGE: passenger AI will removed stuck or unused busses FIX: passenger AI will no longer build lines to unconnected factories FIX: pax at tourist attractions were added to all stops!?! 7-Apr-2005 (prissi) FIX: several routines replacing ground also destroyed binding to halt FIX: tourist attractions now generate mail again FIX: unhappy mail was also omitted FIX: presignals were not correctly removed CHANGE: 64pak: two rail roofed station added 5-Apr-2005 (prissi) CHANGE: assembler for display_text (17% faster) and display_fillbox (150% faster) FIX: variation of non-rotatable houses was ignored for special buildings CHANGE: tourist attraction are no longer built next to each other, but at least 1+b+h away Changes to Makeobj20 (prissi) (for Simutrans 86.xx and higher. Factories created with this version will crash Simutrans 85.04.1 and earlier.) CHANGE: pax_level for factories added. FIX: 96 and any other even size should work again. FIX: citycars were broken. CHANGE: "schiene_tram" added as waytype to accommodate for Trams. 3-Apr-2005 (prissi) FIX: station window display FIX: station bar indicator also included good None (therefore the color were one off) FIX: map crashed, when there was not a place for every town 29-Mar-2005 (prissi) FIX: removing a tile was killing all station info => station no longer connected FIX/CHANGE: tooltips are now only allowed for topmost windows CHANGE: some more assembler, now 999ms instead of 1462ms for display_img() (45% faster) CHANGE: added busstops to tram menu FIX: Finally nailed down bug of stealing goods from other companies FIX: Only own stops could be added to a schedule (so no stops where nobody could unload/load) FIX: factories tried to connect to overconnected suppliers => ok, there is then an error message, that too many pointers were added, but simutrans exists anyway Release of 86.00.1 27-Mar-2005 (prissi) FIX: coded the display_img new, now 40% faster than before FIX: city statistics were wrongly initialized FIX: docks: water ground left, catchment area now checked + dock removal possible FIX: makeobj allows now also for sizes != 64 and 128 26-Mar-2005 (prissi) FIX: factory catchment area was asymmetric (2x3) => change also to 2x2 FIX: tourist attraction display now normalized to biggest attraction CHANGE: another round of drawing optimizations: no redraw of menus or ticker background CHANGE: vertical clipping display further optimized, zoom on demand now working CHANGE: new parameter in simuconf.tab "station_coverage" sets the coverage area FIX: wrong factory catches ware of the same typ hopefully corrected CHANGE: added the tram-stuff for 64 Release of 86.00 20-Mar-2005 (prissi) NEW: statistics for towns FIX: all ground tiles were no properly initialized during loading! (weg1 and 2 could have a random image!) CHANGE: all images are loaded and coded to their proper values. Darkening is only on demand. (huge memory relief) CHANGE: zooming calculation change => drastic speed-up and in principle allows also for zooming by all integer factors (1,2,3,4,5, ... ) CHANGE: Debug message actually taken out, if compiled without debug support => leaner code and speed up. CHANGE: TramTools disabled, if no tram depot found CHANGE: Lots of german help files added (from Gotthardlok) 17-Mar-2005 (prissi) NEW: Season for grounds ("WinterGras" and "WinterShore") NEW: Seasons for trees (either all year (0-4) or summer/winter (0-4|5-9) or all four seasons with 20 images (sum|aut|win|spr) NEW: new parameter in simuconf.tab: "tree_info=0" switches tree info off 14-Mar-2005 (prissi) FIX: convois have again correct weight after loading a game FIX: AI wrongly fills undo array FIX: corrected some loadgame issues 11-Mar-2005 (prissi) CHANGE: quickstone_t shrank to unsigned short int (saves memory) CHANGE: vector_tpl now with removal and insert_at at certain position CHANGE: grund_t now remembers the 10 next stations (this seems like maximum number to me) This allows way faster search for stations. Furthermore, passenger now are preferably routed to a station of the player/passenger AI. CHANGE: 'v' to display the station coverage CHANGE: station coverage setting saved in simworld.cfg 9-Mar-2005 (prissi) CHANGE: Townhall also opens its info-window FIX: StalkeXRP changed to his real name in credits FIX: Austrian and finnish citylist had still old names FIX: Citycars again in dat files (was omitted during makeobj link, because commented in simwrite.cc ???) CHANGE: Savegame format now 86.00, since this will be 86 with trams and more CHANGE: Median citizen is again median ... CHANGE: New founded city has always 1/10 of median citizens at the beginning 4-Mar-2005 (prissi) FIX: factory and transformer builder now checks their building sites before more strictly 1-Mar-2005 (prissi) CHANGE: menu clean up: Post -> special tools NEW: cursor for slop tool (cursor.Slope.pak) NEW: large docks, as many as you like NEW: as many stations as you like NEW: as many busstops as you like CHANGE: factories now have a passenger level Following cursor.*.pak had become obsolete: BusStop, Crossing, Rail, Road, TrainStop, FreightTrainStop, TrainDepot, CarDepot, Post, ShipStop please define an icon and a cursor in your files! 24-Feb-2005 (prissi) NEW: larger ports possible NEW: passenger AI new also built lines to factories and attractions CHANGE: allow for higher initial mountains FIX: median citizens was actually maximum citizens 23-Feb-2005 (hsiegeln): NEW: presignals; -> trains will not enter a block, if the block to be entered thereafter is not free and they are waiting at a "presignal" NEW: presignals require the following PAK: misc.preSignals.pak TODO: presignals use old-signals icons on menu and for cursor; needs to be fixed TODO: gfx for preSignals currently use gantry-style; should use correct gfx; whatever that may be ... 22-Feb-2005 (hsiegeln): NEW: Margin graph in finance window NEW: Transported Goods graph in finance window FIX: net wealth initialization was missing for month graphs FIX: own vehicles couldn't be managed after loading game FIX: potential crash in line management window FIX: button enable/disable in line management window Release Simutrans 85.04.1 21-Feb-2005: FIX: cleaned up many images, removed many pixels => 200kB smaller base set CHANGE: added heavy ore truck by MHz CHANGE: doubled power needed for acceleration, but every car now only consumers kW equiv. to its weight CHANGE: passenger level added to factory window FIX: correct calculation and passenger display for all monuments FIX: string overflow for new monuments corrected FIX: tooltip corrected 19-Feb-2005: FIX: removed unnecessary pixels from cathedral and stadium FIX: night lights for stadium FIX: initial display width now 704 instead 702 CHANGE: added citycar pickup FIX: ship power values reworked FIX: clipping error for char display FIX: large map creation fixed CHANGE: now random map creates a map out of 9999 choices (theo. max 273025) CHANGE: removed blanks in ticker FIX: passenger generation from attraction and factories corrected FIX: passenger generation again level dependent: factories ~ 20 FIX: no transformers on water FIX: production could jump for very high timer loads (i.e. during zooming) => more performance FIX: new factories are again connected to stations CHANGE: bus AI added (player 2) including overcrowded lines => new message "Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n" CHANGE: mip_cobblestone now 50 km/h, cobblestone 60 CHANGE: AI can build now much more roads FIX: maintenance of city road reduced to 3.00, because difference is charged to player FIX: error with way replacement in AI (same way replaced was charged) FIX: no income generating by overbuilding roads Released Simutrans 0.85.04.0 11-Feb-2005: FIX: simultaneous AI now working without crash CHANGE: AI 1 always road only, AI 6 rail only FIX: more WF cars now in players and night colors FIX Book truck night colors and trailer FIX: MHz shipyard now in player colors FIX: fish wagon now in players color FIX: Again windows icon and version info FIX: clipping calculation for characters was faulty FIX: at some places wrong memory allocation repaired FIX: some windows were two times destroyed, now kill_list checked for doubles FIX: Linux binaries again linked with V5 libstdc++ CHANGE: added USA citylist CHANGE: cleaned up simuconf.tab (Tomas) FIX: Several help window texts reworked Released Simutrans 0.85.03.3 10-Feb-2005: CHANGE: Any "... Power Plant" or "...kraftwerk" will produce power => Wind Power Station (and Solar Power Station) possible CHANGE: Power production now proportional to factory production FIX: transformer was built and then immediately removed FIX: use libstdc++ version 3 under Linux Released Simutrans 0.85.03.2 9-Feb-2005: FIX: reduced passenger number again to initially intended value This is about 1/4 of the current value. Thus I doubled the number per building. FIX: no undo after bridges or tunnels FIX: UNDO failed for spieler=NULL (intercity roads) FIX: corrected season timing FIX: building transformer removes everything on that tile CHANGE: building powerline removes all trees on that tile CHANGE: finances also of the AI players "Finances of %s" FIX: since in current version, weight is only calculated during loading now the real weight 1000kg=1t is used Released Simutrans 0.85.03.1 7-Feb-2005: CHANGE: added UNDO for road and rail buildings ('z') +"UNDO failed!" error FIX: simworld.cfg was wrongly initialized => no messages at all FIX: city AI was also ignoring transformers during building FIX: for calculating of possible passengers only these who found a station near the destination was counted. Now also the one, who gave up, because no station was there are counted => city growth rates much lower, need a good service over whole map FIX: Renovation of townhalls: now all with roof texture and "real" grass FIX: Power station production increased after loading: check on load time FIX: error of an character allocation array (V. Meyer) FIX: superfluous parameters in check_for_crossing() removed. (V. Meyer) Released Simutrans 0.85.03 6-Feb-2005: FIX/CHANGE: replace building search in map window by simple gib_halt() FIX: No crowded stations messages from AI anymore FIX: Depot reached message was not in mailbox FIX: mailbox now starts always empty. FIX: after selecting a list, the info tool is selected back CHANGE: message settings will be save in simworld.cfg 5-Feb-2005: FIX: way building did not check for transformers CHANGE: when producing power, powerstations consumption raises 3x (to prevent building too many transformers) FIX: removing transformer when under power now reduced production again FIX: no more suicide divers at the fish_swarm FIX: factor for production increase could lead to very high values for low productions in 128 set Released Simutrans 0.85.02.1 4-Feb-2005: FIX: list windows were not open correctly (fixed by Markus Weber) FIX: tooltip for main menu CHANGE: citylist for dutch cities by AlienDNA FIX: could not connect to a road built by the AI FIX: effect of power on production was faulty FIX: new tourist attractions and factories announcement were not translated Released Simutrans 0.85.02.0 2-Feb-2005: CHANGE: german help files CHANGE: two new command line options "-timeline" and "-startyear" CHANGE: main menu again little different order and new icons CHANGE: list window toll added (after Markus Weber) CHANGE: vehicle image is now the loaded images (please comment) FIX/CHANGE: city do not grow until there is some transportation going on CHANGE: minimum now 1 city CHANGE: possible to set minimum citizen number CHANGE: removed tool for road/rail crossings since this is done automatically 30-Jan-2005: CHANGE: factory productions doubles with electricity CHANGE: indicator for transformer added for power status FIX: disallow building of city-AI on powerlines FIX: overcrowded station message again demi-FIX: on the expense of a small memory leak powerline now loads and connects under all conditions CHANGE: added mailbox (open with 'B') CHANGE: AI could now given a now int tab-file "player 5"->"H-Trans GmbH" CHANGE: central message manager, also added the following messages: "New factory chain\nfor %s near\n%s built with\n%i factories." "%s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants." "With a big festival\n%s built\na new monument.\n%i citicens rejoiced." "To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers." "%s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i)." "%s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i)." "Year %i has started." 25-Jan-2005 CHANGE: two new button to map windows added: "Powerlines" and "Tourists" 24-Jan-2005 FIX: powerline income was based on last consumption, now integrating and reduced FIX: during loading the AI was not marked as AI => convois had remove buttons again FIX: roadbuilder did not checked, whether I owned the ground or not => crossing with AI possible => removing road => strange things happened Released Simutrans 0.85.01.1 23-Jan-2005: FIX: loading old savegames again Released Simutrans 0.85.01.0 20-Jan-2005: FIX: linux: running in windows (again?) FIX: factories were not connected with cities FIX: tourist attractions again FIX: bridges obey speed limit again after loading (must be broken since before 0.84.17) CHANGE: animated cinema now with night colors CHANGE: some industrial building renovated, night pixels removed CHANGE: city factories have a minimum distance of 6 CHANGE: removed "BRIDGETOOL", "5WORLD_CHOOSE" CHANGE: now separate settings for land industry, city industry, and tourism called "Land industries", "City industries", "Tourist attractions" CHANGE: added a second power plant "Oil Power Plant" 18-Jan-2005: FIX: Adding transformer now connects more reliable with powerline FIX: powerline ground has no owner (unlike ways), so one can built a powerline on other grounds, like a bridge FIX: Romanian helpfile included FIX: AI won't destroy your powerlines any more FIX : AI now uses a little less trucks to prevent traffic jams and shift calculation a little towards trains FIX: factories belong to the player => could be removed CHANGE: Every second powerline is now just line, powerline bridges CHANGE: tool added "Plant tree" (key '/' now without function) CHANGE: removed drivables (key 'n') since they crashed anyway CHANGE: removed add pump (key 'P'), since now add transformer does the right type automatically CHANGE: removed unnecessary bridge menu pak-file Released Simutrans 0.85.00.0 16-Jan-2005: FIX: powerline works again (please, built from source to target!) FIX: powerline on slopes added CHANGE: new factory distribution code, distribution entirely by the same function, which built new suppliers CHANGE: added new concrete factory 11-Jan-2005: FIX: AI built railway tracks on water and over houses, disabled FIX: Create new industry (shift+i) new creates a random consumer instead of "Materialswholesale" FIX: New industries are crossconnected FIX: Producer and processing are now placed in cities, if requested in the dat file FIX: Several nightpixel removed, some buildings renovated, skyscrapers now with streetlights FIX: AI had problems which rectangular factories, if they were rotated FIX: AI crashed, when a factory was too close to the map borders CHANGE: "clean up" of the main menu CHANGE: new menu for "half documented" features: SPECIALTOOLS, Found new city, Build land consumer, Build city market, Build powerline, Build drain, Marker CHANGE: MHz shipyard, special cursor, new depot icon CHANGE: City builds new industry after some time (see cityconf.tab), also crossconnected CHANGE: complete hungarian and romanian translation, preliminary russian one 9-Jan-2005: FIX: vehicle selection was wrongly calculated (very good vehicles were also excluded) FIX: in translation a second pak-specific entry could not overlaid a previous entry => now their can be scenario-specific station and town names CHANGE: new city checks also for unique name CHANGE: in translation files all lines starting with '#' are ignored CHANGE: factory are constructed with their storage nearly full => AI can start immediately, less double lines Released Simutrans 0.84.22.0 3-Jan-2005: FIX: Route finding in station was faulty (ignored dead ends and electrification) FIX: Station did not grow properly together FIX: citylist is now loaded with the correct language FIX: clipping of small font in map window works again CHANGE: Many buildings nightpixel removed/exchanged CHANGE: Renovation of the KI - tries to built networks (factories missing a single good for production a rated higher) - checks more factories - always use the cheapest means of transport (only a little biased towards rails ;)) - all possible locations are now searched, including points near a previous built station - tries to built a single station - obeys timeline for vehicles - can electrify tracks CHANGE: Renovation of way/rail construction tool - automatically creates railroad crossings if possible - tunnels will always have the fastest way (not name dependent any more) CHANGE: Cities in a new map can now have a certain distance (see config/cityconf.tab) CHANGE: Japanese pak "Oil Power Plant" now have a powerline connection CHANGE: Full Unicode display support - renovation of all text displaying routines and therefore many dialogue boxes - support of BDF as an alternative font format (less than 256 chars of Unicode/ISO10626-1 coding only) - UTF8 encoded (2 Byte language) files are possible - 2 Byte output/editing works (no input due to SDL yet) - citylist can be either in text/ or pak/text/ (or where your pak-files are). Released Simutrans 0.84.20.0 28-Nov-04: FIX: fixed a crash if a vehicle was sold while the vehicle info window was open FIX: cities can now skip gaps in building levels (gaps up to 16 levels) -> this allows players to remove city building PAK files without unlinking higher level buildings from the chain unless they create gaps of 16 levels or more CHANGE: included MHz and Prissi in intro scroller and thanks.txt CHANGE: replaced animated fountain by better version created by MHz CHANGE: included reworked images by Prissi: - a0-townh-stage1.png: fixed roof edge - g0-houses01.png: grass and night color fix for one house - g0-industry.png * improved optics factory * fixed water cistern night colors * new industrial city building (fertilizer factory) * improved grid structure for cylindrical grey gas tank - ls-bridges*.png: fixed night colors - ls-shores.png: added one missing pixel 27-Nov-04: FIX: gear is now calculated correctly for all vehicles of a convoi (Prissi) FIX: station statistics are now shown correctly even if less than 16 goods are used in the scenario (Prissi) 26-Nov-04: CHANGE: included MHz new ship depot CHANGE: included updated czech translation by Ondrej Machulda Released Simutrans 0.84.19.0 ??-Nov-04: CHANGE: included Hendriks changes Released Simutrans 0.84.18.0 13-Nov-04: CHANGE: traffic density setting now ranges from 0 .. 16 CHANGE: replaced "old church" tourist attraction by better image from MHz FIX: traffic density 0 now creates no traffic at all FIX: tried to fix "unhappy passengers" counter (there was a fixed amount used instead of the actual number of passengers). Integrated Hendriks bug fixes: FIX: Sequence of "remove" and "update" in line management caused a crash FIX: finance window: text fixed FIX: finance window: debt warning is visible again FIX: line schedule updates now also affect convois waiting for freight FIX: depot windows sometimes displayed wrong vehicle information 10-Nov-04: FIX: fixed a bug that caused factories to stop producing goods if one of the outgoing storages became more than full (probably caused by another bug) Released Simutrans 0.84.17.0 06-Nov-04: Integrated Markus and Hendriks changes: FIX: "no connection" station list filter fixed (Markus Weber) FIX: rail stations without roof now have the type "rail station", too (Markus Weber) NEW: mouse wheel support (Hendrik Siegeln) FIX: combobox drop down list now can be closed by return (Hendrik Siegeln) FIX: fixed a memory leak in schedule list ui (Hendrik Siegeln) FIX: fixed a problem with line/schedule updates (Hendrik Siegeln) 05-Nov-04: CHANGE: replaced old rail depot by MHz' new rail depot CHANGE: replaced one more industrial building by a better version created by MHz 04-Nov-04: CHANGE: replaced three industrial buildings by better versions created by MHz CHANGE: replaced one residential building by a better version created by MHz CHANGE: improved two residential building images CHANGE: included updated hungarian translation by Ferencz Szekely CHANGE: included updated polish translation by Maciek Gajewski Released Simutrans 0.84.16.4 01-Nov-04: FIX: fixed some accesses to uninitialized values in relief map frame. -> A crash has been reported upon pressing 'm' but I couldn't reproduce it. I hope this was the reason and my changes will fix it. At least my memory debugger is happy now. Since I couldn't reproduce the crash I can't tell if it is fixed or not! Released Simutrans 0.84.16.3 31-Oct-04: FIX: depot maintenance cost is now calculated correctly after loading a saved game CHANGE: savegames are now sorted by date, newest on top of list 30-Oct-04: FIX: placing a marker and confirming by pressing OK no longer causes a crash -> this required quite a lot of changes to event handling, I hope I didn't break some other functionality Released Simutrans 0.84.16.2 25-Sep-04: NEW: included MHz new gasoline refinery FIX: opening the line management window now gives a click sound 24-Sep-04: FIX: included Hendriks fixes for the line management/button click problem FIX: tried to fix a freeze if the clock of the computer is set back NEW: included more Joachim Baums german texts about the trees 19-Sep-04: NEW: included MHZ' new car repair shop CHANGE: included updated czech translation by Ondrej Machulda 18-Sep-04: FIX: cities now build monuments again 08-Sep-04: NEW: included Joachim Baums german text about the beech trees Released Simutrans 0.84.16.1 06-Sep-04: FIX: clickable "world view" in factory info windows works again. FIX: color codes in goods list now match those in the station statistics. FIX: emergency vehicle remove button "X" now works again. FIX: furniture factory had miscolored edge (should've been transparent). FIX: schedule window scrollpane now behaves properly (Formerly it scrolled the contents out of the window if the "insert", "remove" etc. buttons were pressed) CHANGE: improved a few more german building descriptions. Released Simutrans 0.84.16.0 05-Sep-04: CHANGE: included MHZ' new furniture factory CHANGE: included updated slovak translation by Ján Krnác included updated prop-latin2.fnt (Ján Krnác ?) 04-Sep-04: CHANGE: included Hendriks depot window changes - Vehicle lists now have scrollbars 03-Sep-04: FIX: station statistics no longer show the special good "None" NEW: Added "Ballonstart" image painted by MHZ NEW: Added color codes to goods list CHANGE: tooltips of way building tools now show 2 decimals of the price and maintenance cost 01-Sep-04: CHANGE: replaced an industrial city building by a better version provided by MHZ CHANGE: improved a few city buildings NEW: new commercial city building "roof cafe" provided by MHZ CHANGE: improved a few german building descriptions 30-Aug-04: NEW: replaced one city building by a better version painted by MHZ NEW: tooltips for some of the schedule windows buttons FIX: yearly money chart root is now updated correctly (shows current year, not year of previously saved game) 28-Aug-04: CHANGE: finished including Hendriks update - factory info windows got scrollbars - schedules can be promoted to lines - finance window now stores monthly data for the past 12 months (savegames are converted automatically) - improved input focus handling NEW: new vehicle TPI Std 2-6-4T (steam) CHANGE: finance window now remembers size and settings if closed and reopened unless you load a saved game or start a new map. 28-Aug-04: CHANGE: started to include Hendriks update Released Simutrans 0.84.15.3 24-Aug-04: FIX: assigning a vehicle to a new line by using the choice box in the vehicles schedule window no longer causes a crash. FIX: fixed a crash if a way without an owner was built (this problem was introduced by the fix for correct maintenance cost after replacing a way with another type of way in 0.84.15.2) 23-Aug-04: CHANGE: back-ported 128 set basement images to 64x64 pixel set CHANGE: if a passenger destination is a water square, the destination is re-rolled. This doesn't avoid off-shore destinations entirely but reduces them a lot. CHANGE: factories now produce passengers (commuting workers) and mail properly CHANGE: theatre now has "Leuchtreklame" and lit windows 22-Aug-04: CHANGE: line management window now remembers size and settings if closed and reopened unless you load a saved game or start a new map. Released Simutrans 0.84.15.2 22-Aug-04: FIX: if a way is replaced by another way, maintenance costs are now calculated correctly FIX: finance window chart now considers starting year correctly CHANGE: improved some images - station floors - station roofs - loading bay images now have a few crates shown - new oak tree (slightly modified version from 128 set, original image by Tomas Kubes) - new mountain pine tree - improved fir image - improved cement mill image somewhat - added old roadster private car (slightly modified version from 128 set) CHANGE: tried to reduce the overall number of oil wells -> maybe the default industry density should be risen a little bit now CHANGE: added new city building rule for houses -> fills empty middle of 3x3 block of houses CHANGE: added translations for a few trees (don't know the names of some -> no description possible) 21-Aug-04: CHANGE: improved some images - some industrial town houses - some commercial town houses 20-Aug-04: CHANGE: improved some images - Townhall stage 0 and 1 - some residential town houses (night mode) - some industrial town houses (night mode) Released Simutrans 0.84.15.1 20-Aug-04: FIX: station can only store 128 units of goods per square -> this now also holds true for passengers generated by tourist attractions Released Simutrans 0.84.15.0 20-Aug-04: CHANGE: added a missing space to short freight info CHANGE: station can only store 128 units of goods per square and type for all types of goods -> for freight the limit was a total of 1000 before regardless of station size -> for passengers and mail it was 64/square before CHANGE: rectified and updated some of the german in-game help files. NEW: all depot window buttons now got tooltips NEW: display options window got a "?" gadget to open the associated help window. NEW: station details window got a "?" gadget to open the associated help window. FIX: fixed a bug in HTML (help) display if a link was the first word of a line, it couldn't be selected as a link. NEW: added factory details (optional) windows 15-Aug-04: NEW: most depot window buttons now got tooltips CHANGE: included updated slovak translation by Ján Krnác 14-Aug-04: CHANGE: continued to work on monorail track and vehicles 12-Aug-04: NEW: shaved off a few more CPU cycles from the graphics code 11-Aug-04: NEW: hand-optimized assembly routines for drawing tiles -> about 5% faster than previously used C code ??-Aug-04: CHANGE: continued to work on monorail track and vehicles Released Simutrans 0.84.14.0 06-Aug-04: CHANGE: added introduction dates for all ships CHANGE: added introduction dates for more busses 05-Aug-04: FIX: fixed a bug that caused signals to become partly transparent after zooming out and zooming in again FIX: fixed a bug that cause station names to be displayed in mini world view in some windows (e.g. station info) FIX: changed printers ink, chemicals and medicine from metric "tons" to metric "crates" NEW: "max_transfer" parameter added to simuconf.tab CHANGE: added introduction dates for all train engines 04-Aug-04: CHANGE: improved some images - pharmaceutical plant 03-Aug-04: CHANGE: improved some images - Serj Gaz 4 Goods truck is now a little bit larger - H-Trans Mail truck - Tree 1 was replaced by a better tree image - Commercial building "Office block" 02-Aug-04: NEW: introduction message for new vehicles 01-Aug-04: FIX: limited max distance for pathfinder to 480 steps. This fixes a crash of a route with almost 512 step was found and a train wants to add additional steps. The chosen parameters are safe for trains up to 31 carriages. This should be ok, since the player can't set up trains longer than 16 carriages. Released Simutrans 0.84.13.0 31-Jul-04: NEW: show up arrow for capped station statistic bars NEW: "show_names" parameter included in simuconf.tab CHANGE: included updated czech translation by Ondrej Machulda 29-Jul-04: NEW: on-map statistics for stations can now be toggled by pressing ! NEW: timeline can now be switched on/off for testing in simuconf.tab (default is off) 28-Jul-04: NEW: on-map statistics for stations NEW: improved city roads for 64x64 pixel tile set Released Simutrans 0.84.12.0 24-Jul-04: NEW: (Hajo) buildings mail and passenger levels now actually influence creation of mail and passengers FIX: one more bugfix to make Simutrans run past year 2612 CHANGE: I've tried a kind of 'optimization'. koord3d objects formerly had a size of 6 bytes, which is bad for both 32 bit and 64 bit systems. I've now squeezed them in 4 bytes -> this means they require less memory and are better aligned in memory, but the components now are 11 and 10 bits in size which adds some overhead to component accesses. Right now, I don't know if the tradeoff will be a win or a loss ... please let me know about your experiences. CHANGE: (DarioK) Passengers now check for destination station before doing pathfinding. This is slower for new games with only few stations, but faster for big games with a lot of interconnected stations FIX: (Hendrik) loading games with 0 factories works again 18-Jul-04: NEW: (Hajo) buildings now have separate mail and passenger generation levels Released Simutrans 0.84.11.0 10-Jul-04: CHANGE: language/translation file entries/translation facility now supports up to 4K of text per entry CHANGE: game time is now an unsigned 32 bit value. This change should allow to play Simutrans games beyond year 2612, the limit is now around year 3200 Included Hendriks updates: Bugfixes: - delete multiple lines in line management window, and immediate selection of other line could crash Simutrans - suppliers now get correctly registered, even for savegames - line management window "update line" selected wrong line Changes: - textinput supports clipping & scrolling & more - combobox uses new textinput component and is now inheriting gui_textinput_t - window titles now support clipping Released Simutrans 0.84.10.0 03-Jul-04: FIX: new map window now displays translated factory names Included Hendriks updates: Bugfixes: 1) now lists up to 24 suppliers of an industry (was 6 before) 2) improved focus handling of text input fields Bugfixes: the new "gueterbahnhof" was not shown in overview map overlays (coverage, etc) "operating profit" was adding vehicle's running cost to profit, rather than subtracting Change: added ev_key_mod to event struct (ev_key_mod holds key modifiers, such as SHIFT, ALT, STRG, etc); required for new features (see below) New: overview map enhancement (show connected industries; shows customers default, use SHIFT to show suppliers) map zooms in/out respecting SHIFT key Change: savegame version now 84007 (was required for new curve in finance window) if user clicks into the scrollbar, top-left or bottom-right the slider, now the scrollbar scrolls up/down accordingly 19-Jun-04: Included Hendriks updates: New: line filter in line management (all, truck, train, ship) using tabs New: introduced new curve to finance window: ops profit Change: simplified delete_line interface (now accepts simline_t *, too) fixed potential (very minor) memory leak in line management window (halt_list_item_t was instantiated always, now it is created if required, only); Change: savegame version now 84007 (was required for new curve in finance window) if user clicks into the scrollbar, above/left or below/right the slider, now the scrollbar scrolls up/down accordingly Released Simutrans 0.84.9.1 13-Jun-03 FIX: oil rigs are now initially linked to their stations again Released Simutrans 0.84.9.0 10-Jun-04 FIX: fixed an invalid memory read in image encoding (zooming from zoom level 2 to zoom level 1 could cause a crash) CHANGE: reduced output storage capacity of most factories CHANGE: default industry density is now 450 (was 420) 02-Jun-04 FIX: included Hendriks fix for an index problem in deleting a line CHANGE: improved a few buildings images CHANGE: replaced duckpond-park with tomas new park Released Simutrans 0.84.8.6 31-May-04 CHANGE/FIX: station<->factory link is now bidirectional, this means, situations in which a station was linked to a factory but the factory not linked to the station cannot occur anymore. In games with many stations and factories, this change should also save a little bit of CPU time for other tasks. Attention: the link has a length of 4 squares, this means, there can be at most 2 squares between the station and the factory (unless the station has an irregular shape, e.g. T-shaped). FIX: building powerlines no longer crashes the game FIX: new cities can only be built on empty, flat squares FIX: new cities no longer can be built on water FIX: added a missing space to station detail info string (indention of "goods needed by factories" list) CHANGE: splash screen now uses proportional font Released Simutrans 0.84.8.5 19-May-04 CHANGE: if user has not selected a language yet, Simutrans defaults to english now CHANGE: there are now 32 goods categories available for use in scenarios CHANGE: mouse pointer is now shown on splash screen FIX: added a missing space to station short freight info string (e.g. shown in line management) Released Simutrans 0.84.8.4 16-May-04 FIX: all road bridges can be used now FIX: stations can't be connected sideways anymore FIX: scenario specific translations now get packaged, too Released Simutrans 0.84.8.3 01-May-04 NEW: included Hendriks changes: - internal improvements in line management - fixed a crash if list and filter window were closed by pressing backspace FIX: fixed a bug in MakeObj that created all vehicles with engine type "steam" FIX: horses got engine type "bio" CHANGE: depot frame now deduces engine type from vehicle data instead from vehicle name (this means that in old translations, the type will be listed twice!) CHANGE: news ticker discards newly incoming messages that have the same text as the last shown message 15-Apr-04 CHANGE: moved scenario specific texts into scenario directory, and adapted translator to read them from there 14-Apr-04 CHANGE: cleaned up translation facility API Released Simutrans 0.84.8.2 11-Apr-04 FIX: lines entered from line management window now show up in depots again FIX: lines entered in another depot, are visible in all depots again after opening their info window 10-Apr-04 CHANGE: saved games of versions < 84006 became incompatible due to an accident. I can't revert this accident, so the game now treats such saved games as incompatible and gives an appropriate message instead of crashing Simutrans 0.84.8.1 for developers only 09-Apr-04 FIX: added a safety check to vehicle list, to avoid a crash if the entry of a just deleted vehicle is clicked FIX: button_t was missing an assignment operator which could cause a crash in certain circumstances Released Simutrans 0.84.8.0 04-Apr-04 NEW: freight train station - so far look only, no effect on gameplay yet 03-Apr-04 NEW: goods info window now shows weight per unit, too. 02-Apr-04 CHANGE: enabled -async option for SDL based Simutrans versions 01-Apr-04 CHANGE: adjusted weights of busses and trucks 31-Mar-04 CHANGE: adjusted 64x64 pixel tile set wagon weights CHANGE: AI now searches more locations for stations FIX: AI now properly raises/lowers land in order to build a station CHANGE: AI now uses "wait for 100%" setting if using trains 30-Mar-04 NEW: weight of freight is now considered in acceleration calculation CHANGE: small steam engine now has gear 1:2 CHANGE: big steam engine now has gear 1:1.2 CHANGE: pharma producer consumes 230% chemicals instead of 530% chemicals to produce medicine Released Simutrans 0.84.7.1 29-Mar-04 FIX: fixed a bug in loading engines with old style way type "electrified track" -> now they are listed in depots again, waytype is now silently changed to track FIX: included a fix by Hendrik to better initialize waiting goods statistic for less frequented stations NEW: included Stefan "MIP" Wuttichs cobblestone road 28-Mar-04 NEW: MakeObj now supports engine_type for vehicle DAT/PAK files: - diesel - electric - steam - bio - fuel_cell - hydrogene NEW: MakeObj now supports weight_per_unit for goods DAT/PAK files: - weight_per_unit NEW: steam engines now always produce steam clouds while driving FIX: fixed an array bounds violation in AI bridge building 27-Mar-04 NEW: cobblestone road FIX: 's' and 't' shortcuts work again 26-Mar-04 NEW: initial intercity road type can be configured in simuconf.tab NEW: added introduction date attribute for new ways types CHANGE: removed last reference to "Track" and "Road" (the old types) 25-Mar-04 FIX: fixed a bug in wegbauer_t that caused a crash if a way without description was to be built CHANGE: changed AI code to use new way types CHANGE: initial inter city roads now work properly with new road types 24-Mar-04 CHANGE: changed way builder to work with new way types CHANGE: changed city building code to work with new way types CHANGE: changed maintenance cost calculation to work with new way types CHANGE: road tools menu CHANGE: rail tools menu INTERN: restructured 64x64 pixel tile set way images and way descriptions 23-Mar-04 FIX: included Hendriks fix for typed lines NEW: prepared road tool icons NEW: road images for dirt road and gavel road INTERN: restructured 64x64 pixel tile set way images and way descriptions 22-Mar-04 CHANGE: continued to work on new way types (descriptions, menus, icons, cursors, DAT/PAK files) INTERN: reduced number of #includes in translator.h 21-Mar-04 CHANGE: continued to work on new way types: changed MakeObj and PAK loader classes to write and read new 'way' PAK files 20-Mar-04 FIX: included Hendriks bugfix for schedule list/waypoint crash released Simutrans 0.84.6.0 NEW: rail tools menu now shows costs of the actions NEW: road tools menu now shows costs of the actions CHANGE: changed error reporting mechanism for template (container) classes CHANGE: started to rework rail tools menu to allow several track types CHANGE: started to rework road tools menu to allow several road types 17-Mar-04 CHANGE: integrated Hendriks changes 15-Mar-04 FIX: industries are now created on all densities except density 0 14-Mar-04 CHANGE: pause only cancelled by key codes >= 32 CHANGE: pause now really stops game time (industries don't try to catch up with production after unpausing) 13-Mar-04 NEW: frameless window type CHANGE: changed news ticker to frameless window -> this means it can now receive click events NEW: ticker messages can now be bound to positions. If clicked an a position is bound the map is centered on the position. 12-Mar-04 CHANGE: reduced header file dependencies 11-Mar-04 FIX: fixed some GCC 3.2 compatibility issues in the template classes NEW: minimum industry density setting does not generate any industries at all released Simutrans 0.84.4.0 06-Mar-04 FIX: fixed a problem in removing a signal inside a station 05-Mar-04 CHANGE: included Hendriks changes - schedule window now has scrollbars - up to 32 stops per schedule allowed - minimize map doesn't leave buttons floating - minimize station and vehicle info window doesn't interfere with chart drawing anymore 04-Mar-04 FIX: "no route" vehicle list filter works again (was broken during introduction of new vehicle code between 0.83.x and 0.84.x released Simutrans 0.84.3.2 03-Mar-04 FIX: fixed a problem in removing signals FIX: fixed a text formatting problem in factory info window released Simutrans 0.84.3.1 29-Feb-04 NEW: city list window (hotkey 'T') 28-Feb-04 FIX: overhead wires no longer disable way info display CHANGE: finished to incorporate Hendriks new relief map CHANGE: way statistics now get saved with the game 27-Feb-04 CHANGE: started to incorporate Hendriks new relief map -> need to change the structure somewhat to fit better 22-Feb-04 CHANGE: fixed some mistakes that have been introduced while changing character arrays to the new buffer objects CHANGE: vehicle list now formats income with thousands separators CHANGE: included updated danish translation (now using ø) CHANGE: included updated japanese translation NEW: added toolbar icon for line management 21-Feb-04 CHANGE: reworked object info handling to use bounds-checked character buffer objects instead of plain character arrays. I hope this will help to solve some of the memory (i.e. buffer overrun) problems 20-Feb-04 NEW: added max_hops parameter (goods routing search depth) to simuconf.tab 19-Feb-04 CHANGE: changed city name list to use instead of released Simutrans 0.84.2.2 19-Feb-04 FIX: fixed a typo in simuconf.tab: display_height is now written properly (formerly the code checked for display_heigth) FIX: fixed a buf that made too fast vehicles miss the proper stopping point sometimes (could cause trains to get stuck near signals) released Simutrans 0.84.2.1 16-Feb-04 FIX: Bridge tools menu size now adapts properly to number of contained icons released Simutrans 0.84.2.0 15-Feb-04 FIX: added ø character to prop.fnt (needed for danish translation) CHANGE: included updated danish translation from Finn Rosenbech Jensen (not yet using ø, was made for former font version) NEW: included new, downscaled, oil rig from 128x128 pixel tileset made by James Starr WARNING: this one is 3x3 squares - the old one was 2x2 if you load old games, that have things near oil rigs, there might be bad effects if the new oil rigs overlap the existing things! WORKAROUND: get the old factory.Oelbohrinsel.pak from the 0.84.0.1 base package and use it instead of the new one. 14-Feb-04 FIX: fixed a bug that could cause a truck with a trailer to wait for itself to clear the road (= was stuck) NEW: added "topspeed" parameter to bridge dat files CHANGE: removed bridgepos parameter from bridge dat files NEW: speed limit for bridges (not really sure if that works for sure it won't affect existing bridges in old games, only newly built bridges) NEW: bridge tool tooltips now list additional information (price, speed limit) WARNING: the changes to the bridge DAT/PAK files introduced a slight incompatibility with former bridge PAK files: the old files do not store icon information for the menu. Thus if you use old PAK files with this version, the bridge tools menu will show empty icons. The tooltips will help to identify the correct sort of bridge. -> ATM this only affects the 128x128 pixel tile set and selfmade bridges. Both must be updated to include icon information and recompiled with MakeObj 0.1.6 -> See datfiles_15-Feb-04.zip for examples (MakeObj forum, examples section) 12-Feb-04 NEW: added more simuconf.tab entries NEW: new toolbar like tool chooser window (will be used to select bridge types and way types) CHANGE: changed bridge tool selector to use the new tool chooser 11-Feb-04 NEW (by Hendrik): line selection in depot window now got a drop-down list (click into the input field to open) CHANGE (by Hendrik): vehicle info window now shows total running cost NEW: a simple tree planting tool (hotkey /) CHANGE: vehicle info window shows top speed limit and max top speed of the pulling engine 09-Feb-04 FIX: added missing town hall upgrade at 3500 inhabitants released Simutrans 0.84.1.0 07-Feb-04 NEW: added 1% waiting time to schedule choices NEW: included japanese translation and fonts CHANGE: chosen language is no longer saved with game (this means that the chosen language won't be altered if you load a game that was created with a different language setting) CHANGE: improved coal mine image a little bit 06-Feb-04 FIX: fixed a problem that's been introduced during some changes while 0.83.x development: it is no longer possible to build roads or rails through a bridge abutment (was ok before 0.83.x, too). FIX: town hall upgrades no longer modify squares south of the new town hall if those squares are owned by a player CHANGE: factory info window now shows max production per day CHANGE: lowered coal consumption of power stations by 30% CHANGE: risen productivity of saw mill and material wholesale by 15% each 05-Feb-04 CHANGE: included new fi.tab provided by Antti Louko CHANGE: improved steel mill image 04-Feb-04 NEW: speed limits for ways (currently 50 km/h on city roads 130 km/h on other roads and 450 km/h on rails) released Simutrans 0.84.0.1 02-Feb-04 FIX: fixed a bug if a line was deleted while it had pending updates FIX: fixed a an access to an uninitialised variable if a line was deleted after loading a saved game released Simutrans 0.84.0.0 01-Feb-04 CHANGE: finished rework of convoi and vehicle class CHANGE: lowered productivity of coal mines CHANGE: improved townhall stage 1 image CHANGE: improved townhall stage 2 image NEW: vehicles now issue a message in the news ticker if they enter a depot FIX: fixed a bug in town hall expansion code FIX (by Hendrik): vehicle info window minimum size now considers chart width FIX (by Hendrik): station info window minimum size now considers chart width FIX (by Hendrik): list of lines stopping at a station is now properly updated after a change to the line NEW: included Paul Szczepaneks stadium NEW: included Danish translation by Finn Rosenbech Jensen 31-Jan-04 CHANGE: continued thorough rework of convoi and vehicle class 30-Jan-04 CHANGE: started thorough rework of convoi and vehicle class structures - moved route data from vehicle to convoi class - moved async step from vehicle to convoi class Code cleanup - moved strequ from simplan.cc to simstring.c, renamed to tstrequ released PAK update 28-Jan-04 CHANGE: - unified window colors - added shadows - reworked many building images 27-Jan-04 NEW: included Paul Szczepaneks tennis court, theatre and home market images. 26-Jan-04 CHANGE: improved car factory image CHANGE: improved steel mill image released Simutrans 0.83.7.1 25-Jan-04 CHANGE: replaced a residential city building with a better version from 128x128 pixel tile set (Modern house) CHANGE: replaced an industrial city building with a better version from 128x128 pixel tile set (Tools factory) CHANGE: adjusted city building AI to get better industrial and commercial city areas CHANGE: adjusted chart size and placement to allow bigger value ranges (line management, station info, vehicle info - suggestion by Hendrik Siegeln) CHANGE: improved oil field from 128x128 pixel tile set included CHANGE: increased probability to create a bookshop, car shop, or furniture shop in a city. 24-Jan-04 FIX: fixed an array bounds violation if loading a heightfield again after increasing the number of cities. FIX: fixed a problem in removing signals - now issues an error message if the signal combination cannot be removed safely. FIX: removed an erroneously lit pixel from one of the trees NEW: translatable thousand and fraction separators (language dependant number formatting) NEW: 4x7 font (map legend) now also available in latin-2 (needed for polish and czech translation) NEW: added lights to private cars 23-Jan-04 FIX: zooming now works reliably again (was broken due to introduction of skinning support) CHANGE: replaced wait loop by timer solution 22-Jan-04 NEW: continued to work on skin support -> support for user defined button skins released Simutrans 0.83.7.0 21-Jan-04 NEW: continued to work on skin support -> created example/default skin NEW: added tooltips to vehicle and station info window buttons CHANGE: changed some buttons shapes (factory info and depot info windows) 20-Jan-04 NEW: continued to work on non-darkening image drawing 19-Jan-04 NEW: started to work on non-darkening image drawing NEW: started to work on skin support released Simutrans 0.83.6.1 18-Jan-04 FIX: latin-2 font now also loaded if saved language setting needs latin-2 font FIX: intercity road offset can be 0,1 (64x64 pixel tileset) or 0,2 (128x128 pixel tile set) -> I hope it will make the intercity roads also work with the 128x128 pixel tile set CHANGE: intercity roads now have no owner anymore released Simutrans 0.83.6.0 18-Jan-04 NEW: support for latin-2 proportional font and new polish translation. The latin-2 font and polish translation update have been kindly provided by Maciek Gajewski CHANGE: included new italian translation and citylist. Both have been kindly provided by Stefano Bonzi CHANGE: small updates to chart layouts (station, vehicle and line management windows) 17-Jan-04 CHANGE: made line management window resizeable FIX: scrollbars in convoi and station info window now work again, even if the chart is hidden FIX: tried to fix the initial road connection problem with 128x128 pixel tile set 16-Jan-04 MERGE: included Hendriks changes - more vehicle statistics - more station statistics - heavily improved line management window - finance window 32 bit integer overflow fixed released Simutrans 0.83.5.0 14-Jan-04 NEW: initial road connections between cities. This slows down map creation noticeably. The maximum length of the roads (= time spent during map creation) can be configured with a simuconf.tab entry - if map creation is too slow now on your computer, edit simuconf.tab and lower the max road length. NEW: overhead wires now have a maintenance cost of 2 CR/month (configurable via simuconf.tab) 12-Jan-04 FIX: tried to get more information about PAK file loading problem on some Linux versions CHANGE: changed a commercial city building image+description 11-Jan-04 NEW: Debugging helper: buildings list window CHANGE: pak update - new old-style goods truck - two more high level industrial city buildings - one more high level commercial city building - replaced "Medium offices" with better image - changed levels of some buildings to achieve better look of cities - changed descriptions of some buildings - fixed two mismatched buildings descriptions 10-Jan-04 NEW: back ported Gaz-4 goods truck from 128x128 set to 64x64 09-Jan-04 NEW: started to work on introduction dates for vehicles Currently they are just stored in the PAK files and displayed in the depot window - no effect on gameplay yet. MakeObj 0.1.5 support two new attributes for vehicles: intro_year (int): Year of introduction intro_month (int): Month in year gear (int): gear of engines - will work as power multiplier. If you create PAK files, make sure to include them in your dat files!!! The gear value is an factor to distinguish freight train engines and passenger train engines - freight train engines use to have a larger gear value, this means they have less top speed but they can pull heavier trains. (Of course this is only an approximation to reality) I've assigned a few introduction dates and gear values to trucks, and some train engines, but I think I need help to assign proper values to all vehicles. CHANGE: risen max map size to 1024x1024 08-Jan-04 FIX: fixed a bug in rtrim() function that caused characters 128-255 to be treated as whitespace (effect: city names ending in umlauts or accented characters got those characters removed) released Simutrans 0.83.3.0 and upgraded food chain 08-Jan-04 FIX: Map legend now dynamically adapts to the number of configured factories (-> always big enough to list all factories) CHANGE: more finetuning on 64x64 image set and configuration CHANGE: rebalanced food chain configuration to better fit into the 64x64 object set 07-Jan-04 NEW: Goods overview/list now shows category of goods, too (Hotkey Shift-G) Back ported IL-209S goods truck and trailer released back-ported food chain Back-ported 128x128 food industry chain to 64x64 - Goods: canned_food, flour, beer, grain, meat, fish, food, milk - Factories: grain farm, fish_pond, fish swarm, cow farm, brewery, dairy, grain mill, bakery, food processing plant, cannery, supermarket - Vehicles: cooling wagon, milk wagon, cooling truck, milk tanker, fishing boat Updated 64x64 pixel tile set - lumber plantation size increased to 3x3 - further improved a few city buildings images 06-Jan-04 Updated 64x64 pixel tile set - improved a few city buildings images - included new printing works image - included new coal mine image - added Patricks Rock again (had been lost) - included improved sidewalks CHANGE: included new french translation by Dominique Gainche 04-Jan-04 CHANGE: included updated czech translation by Ondrej Machulda released Simutrans 0.83.2.2 04-Jan-04 FIX: included a fix by Hendrik to prevent a crash if the last vehicle of a convoi is removed from the convoi in the depot -> we are not 100% sure if this fix will not break something else 03-Jan-04 FIX: added missing variable initializers to convoi_t constructors (Hendrik, Hajo) -> This should fix a number of line-management related problems after loading a saved game -> This might also fix the trashed line names in the vehicle info window (the bug doesn't occur on my system, so I can't test if this fix really helps) released Simutrans 0.83.2.1 02-Jan-04 FIX: tried to fix the trashed line names in vehicle info window (the bug didn't occur on my system, so I can't test if this fix really helps). FIX: added 'special building' translation to de.tab FIX: uprising messages are now time-synced (raise equally fast on all computers) NEW: added 'w' key documentation to keyboard help CHANGE: changed behaviour of " key: only ordinary city buildings are hidden, special buildings stay visible CHANGE: line management window now opens fully inside screen/ window in default 800x600 resolution CHANGE: resolutions of width 1400 and 1600 now try to open in fullscreen mode (I can't test this on my system, so I don't know if it works well or not). 01-Jan-04 FIX: line numbers are now created in subsequent order again CHANGE: line 'name' is now initially set to all bytes 0 upon creating a new line. CHANGE: included citylist_pt.txt MERGE: included Hendriks changes: - Station info details window now list connected lines, too. released Simutrans 0.83.1.3 31-Dec-03 FIX: fixed a crash if the schedule of a line was changed (double free, Hendrik) FIX: fixed potential use of an uninitialized variable in schedule list ui released Simutrans 0.83.1.2 29-Dec-03 FIX: changed convoi waiting times from steps to real time -> with this fix, waiting times should consider the time lapse factor FIX: fixed a crash if station-connections are being rebuild while there is a vehicle without a schedule FIX: made two more entries of the lines management window translatable. FIX: fixed a bug that could produce the same line id twice (two lines with same id severely screw up the line management, this was an important fix). CHANGE: included new fi.tab provided by Antti Louko CHANGE: included citylist_en_gb.txt from the feedback forum CHANGE: added new entries for line management window to en.tab and de.tab released Simutrans 0.83.1.1 28-Dec-03 FIX: fixed this problem: 1. buy 4 wagons (without an engine) 2. add a waypoint to the schedule of the convoi 3. try to start the convoi 4. error message appears (convoi cannot drive, because it has no engine) 5. click on 'put in front' button 6. buy an engine => crash This fix required a major rework of the schedule handling. I'm not sure how stable the new code is. FIX: removing signals from circle-shaped rail blocks did not work properly. This is fixed now. CHANGE: road vehicles depot now has same spacing as rail vehicle depot (= 14 vehicles per row, 64x64 mode) CHANGE: re-added this to the 0.83 again (had been lost in early 0.83.x versions): passenger statistics in city window now shows unreachable passenger destinations in orange and reachable destination in yellow 27-Dec-03 CHANGE: added more debug/trace statements to PAK file loading code (hope this will some day help to track down the PAK file loading problems on some Linux systems) CHANGE: code cleanup released Simutrans 0.83.1.0 22-Dec-03 NEW: included Hendriks changes - Vehicle lines are now sorted - Fixed a crash due to an uninitialised variable in vehicle line list "press 'w' in new game, select "update" -> game crashes" -> now fixed. released Simutrans 0.83.0.1 released Simutrans 0.82.15.7exp 20-Dec-03 CHANGE: passenger statistics in city window now shows unreachable passenger destinations in orange and reachable destination in yellow 19-Dec-03 FIX: moved savegame format entry from forrestconf.tab to simuconf.tab released Simutrans 0.82.15.6exp 14-Dec-03 FIX: forest config is now read from 'config' subdirectory, too CHANGE: split forest config from simuconf.tab, now it read from forrestconf.tab FIX: tried to fix the goods distribution problem for factories bigger than 2x2 tiles released Simutrans 0.82.15.5exp 04-Dec-03 NEW: city names can now be read from name list files. Each language may have it's own city name list, i.e. text/citylist_cz.txt If no list file exists for a language the old city name creation scheme is used to create city names. released Simutrans 0.82.15.4exp 29-Nov-03 CHANGE: better distinguishable colors for finance window FIX: on slow computers it could happen that the vehicle starting sound was played several times. This should be fixed now. 28-Nov-03 FIX: fixed a variable overflow in finance window (Hendrik) FIX: finance window total money is now updated dynamically (Hendrik) CHANGE: replaced most strcpy() calls by a bounds checked, 0 terminating string copy function released Simutrans 0.82.15.3exp 27-Nov-03 FIX: fixed a potential buffer overflow is city building rules reading code FIX: fixed a potential crash if a curiosity building was removed released Simutrans 0.82.15.2exp 25-Nov-03 FIX: fixed a bug in city building rule evaluation code CHANGE: moved simuconf.tab to config subdirectory CHANGE: moved city building rules into config/cityrules.tab released Simutrans 0.82.15.1exp 24-Nov-03 FIX: fixed an uninitialized variable in station sorting code that could cause a program crash FIX: fixed an uninitialized variable in button display/event handling code CHANGE: added bounds checks to station sort mode text arrays access code CHANGE: changed Peters new city building rules to avoid cities only consisting of one single, extremely long road released Simutrans 0.82.15exp 22-Nov-03 FIX: fixed a potential crash if pressing the "X" button to remove vehicles from the map NEW: included Hendriks new finance window NEW: included Hendriks code to sort goods list in station info window. FIX: fixed a memory leak in Hendriks sorting code NEW: included catalan translation from Juan-Josep Bargues NEW: included updated czech translation from Ondrej Machulda 15-Nov-03 CHANGE: included Peters new city generation rules. They are about 30% slower than the old set of rules but create better cities, I think. 12-Nov-03 CHANGE: ships reference speed for speed bonus is now 40km/h. It was 80km/h before. Other vehicles still have a reference speed of 80km/h CHANGE: included Hendrik Siegeln in intro scroller FIX: vehicle list "no income" filter fixed (Hendrik) FIX: vehicle list "name" filter fixed (Hendrik) FIX: depot frame refresh after selling stored vehicles (Hendrik) FIX: adjusted sign height in 128x128 mode (Hendrik, Hajo) released Simutrans 0.82.14exp 01-Nov-03 NEW: buildings pak files (nodes) are now versioned NEW: support for "chance" value in special town buildings pak files. Chances are given in percent NEW: special city buildings are now built according to their chance value FIX: towns don't skip growth step anymore FIX: town halls are now always properly upgraded FIX: added missing translation for "Baumarkt" to de.tab CHANGE: cathedral is now a special city building with a 30% chance to be built for each city CHANGE: big stadiums now have a 40% chance to be built (was 100% chance before) CHANGE: drive in cinemas now have a 30% chance to be built (was 100% chance before) CHANGE: Deltic is now a diesel engine 31-Oct-03 CHANGE: got a saved game from Wolfgang Rufeger which crashed upon electrifying tracks. Reason for the crash: the track has no owner. I have no idea how that can happen. I've added an error check to rail block electrification routine - this at least avoids the crash, but it'd be better to know why the track lost the owner value CHANGE: changed a minor compatibility issue in ribi_t.h released Simutrans 0.82.13.1exp 21-Oct-03 FIX: fixed a minor glitch in scrolling/dragging the map if mouse pointer was close to the relief map CHANGE: vehicles now play their sound before departing instead of after arriving released Simutrans 0.82.13exp 19-Oct-03 FIX: good 'None' no longer shown in goods statistics NEW: Included updated czech translation by Ondrej Machulda NEW: improved two more building images 18-0ct-03 FIX: factories that don't produce anything now again consume input (got broken during of the changes for multiple products) FIX: plastics ship is available again (seems it was lost since the change to the pak file based configuration) CHANGE: updated keyboard help 16-Oct-03 NEW: statistics window, so far only displays transport fees and speed bonus for goods. (Press 'G' to open) NEW: speed bonus for fast transport of certain goods (see goods statistics window for details); 15-Oct-03 NEW: new locomotives: MJHN Deltic, MJHN Avocet, Light Br 5-7 CHANGE: improved window resizing 14-Oct-03 NEW: new city building new vehicle: Colin Motor Bus NEW: relief map is now draggable with right mouse button 13-Oct-03 CHANGE: improved a few building images CHANGE: included a new residential city building released Simutrans 0.82.12exp 12-Oct-03 NEW: new factory: Pharmaceuticals new shop: Chemist new good: Chemicals new good: Medicine CHANGE: further changes to factory code to distribute multiple products properly to all destinations CHANGE: adjusted income for some goods 11-Oct-03 NEW: researched how to version nodes in pak files. First tests implemented for factory pak files NEW: prepared factory code to support multiple products per factory NEW: new good: printers ink (produced by refinery) CHANGE: removed umlauts from pak file names -> this means old games cannot be continued because the names of factories and goods do no longer match 10-Oct-03 NEW: convoi info window now displays current destination FIX: buttons now ignore window resize events (made them flicker between pressed and unpressed state) CHANGE: improved a few building images CHANGE: included a new industrial city building CHANGE: reordered a few building images 09-Oct-03 CHANGE: implemented the faster movement code for private cars, too. CHANGE: lowered coal consumption of the power plants NEW: included better power plant image CHANGE: improved a few building images CHANGE: reordered a few building images released Simutrans 0.82.11exp 08-Oct-03 FIX: got a saved game with stuck vehicles. Changed vehicle movement code so that vehicles can drive again. -> side effect: new code is slightly faster than before and saves 4 bytes of memory per convoi :) CHANGE: continued work on new powerlines CHANGE: started to prepare better debugging support 03-Oct-03 CHANGE: continued work on new powerlines, fixed some bugs released Simutrans 0.82.10exp 17-Sep-03 FIX: ships can be started from depots again FIX: maintenance costs lowered and moved to simuconf.tab FIX: removed unnecessary waiting time for vehicles that wait for XY% full but already reached XY% CHANGE: continued work on new powerlines 16-Sep-03 CHANGE: continued work on new powerlines released Simutrans 0.82.9exp 15-Sep-03 FIX: fixed a very serious bug in AI station building. This bug was probably a long time there, but lately its effect caused a crash, due to changes to other program parts. Big thanks go to Duvelke for providing a saved game to reproduce this bug! 14-Sep-03 CHANGE: included updated italian, portuguese and dutch translations ??? CHANGE: added two more high level commercial buildings images CHANGE: removed one low quality commercial building image CHANGE: improved a few building images CHANGE: changed configuration of some engines and wagons 11-Sep-03 CHANGE: improved AI station building ability CHANGE: AI can now transport gasoline too - better said, it can now transport any good except mail an passengers 09-Sep-03 CHANGE: changed configuration of some trucks and trailers CHANGE: introduced new members of the tigress vehicles class released Simutrans 0.82.8exp 06-Sep-03 FIX: fixed a bug in heightfield loading code that sometimes created lines of land at the right and bottom map borders even if there was supposed to be sea there. CHANGE: Some config files now get closed immediately after reading - former Simutrans versions kept them open until the program ended. CHANGE: Adapted weight, prices and running costs of some wagons CHANGE: Changed some english and german translations entries 04-Sep-03 FIX: Another fix to load saved games with convois without vehicles but a schedule which are sometimes created by Volkers new depot code. Thanks go to Manfred Duesing for providing a saved game to reproduce this bug! CHANGE: risen height value range for heightfields from from -5...1 to -14...10 CHANGE: changed city building code to keep up with high growth factors. It was reported that the old code had problems with factory above +4, the new code should work well with higher factors, too 03-Sep-03 FIX: Fixed a type/range problem in getting heights from the map datastructure. This bug caused various height-related problems, including a crash if land was risen above 7 02-Sep-03 FIX: Fixed a bug in Volkers new depot code that allowed to remove depots which had vehicles stored in them. 01-Sep-03 CHANGE: Wagons and trailers now have speed limits, too NEW: High speed passenger and mail cars suitable for the Tigress I engine 31-Aug-03 CHANGE: new maps now can have cities up to size 3300 (was 1000 before) 30-Aug-03 CHANGE: separated coordinate and cstring classes again (Volker had tightly linked them) to get cleaner interfaces. released Simutrans 0.82.7exp 26-Aug-03 FIX: Got a saved game where convois had insanely high wait lock values. I don't know how that could happen - anyway the locks now have an upper bound of 1023 so that sooner or later such convois start to move again. CHANGE: Changed a potentially insecure instruction order in removing convois via the emergency button. Crashes have been reported, but couldn't be reproduced. I still hope this change will help. CHANGE: Reduced vehicle waiting time by another 5% CHANGE: Changed city information window to list unemployed and homeless people released Simutrans 0.82.6exp 23-Aug-03 FIX: Labels/signs now appear centered in 128x128 tile mode, too. CHANGE: Modified memory management: risen basic block size of pools to 16384 entries (had been 1024 before) This speeds up both allocation and deallocation of pooled objects. The overhead of partly used pools is small compared to Simutrans' overall memory consumption. (Currently this particularly speeds up map destruction, an operation that is performed before creating a new map, loading a new game and before quitting Simutrans). 21-Aug-03 FIX: Hajo: it seems Volkers new depot code sometimes saves convois without any vehicles. But Simutrans can't load them afterwards and crashes upon loading such a saved game. I've implemented a workaround that allows to load such games again, but I think this needs further investigation and testing. FIX: Fixed a temporary inconsistency of convoi data that lead to serious problems with the new reduced waiting time for vehicles. 20-Aug-03 FIX: Removing a mail office now resets a stations ability to collect, store and move mail. FIX: Car factory had input capacity 0/0t plastics. I'm not sure if this affected the game at all, but it's now set to 0/300t CHANGE: Only one mail office per station allowed CHANGE: Reduced overall loading time of vehicles. Trucks, busses and ships now need about 2 seconds to load, trains need 2 + (number_of_waggons/4) seconds to load. -> If you have a slow computer and Simutrans is near the max CPU power already, the vehicle loading times will grow. Try the -refresh n switch in that case (see readme.txt for details). 13-Aug-03 CHANGE: Reworked new vehicles/new pathfinding (not included in official release). released Simutrans 0.82.5exp 30-Jul-03 CHANGE: Limited max passenger search depth (route planning) to 300 stations (was 900 formerly) FIX: Heightfield loading now works well with artificial slopes - no extra support walls are created anymore 29-Jul-03 CHANGE: Lowered passenger rate for higher level buildings 28-Jul-03 FIX: Added missing initialization to slope array FIX: Added missing initialization to buildings after loading FIX: Fixed a 'race condition' in world destruction. In rare occasions, there was step() called on cities that just underwent destruction. CHANGE: lowered passenger rate for higher level buildings 27-Jul-03 NEW: UI button class got a tooltip feature. Added tooltips to some buttons that didn't have a meaningful label NEW: Passenger statistics for stations (happy, unhappy, no route found). Newly created passengers become unhappy if their chosen starting station has more than 64 passengers per segment already waiting there. Unhappy passengers will not use your transport service. "No route" in this case means that a passenger came to the station, couldn't find a route to his desired destination and went home. Included updated czech translation by Fast Ikarus Included updated polish translation by Lukasz Remis Included Tomas Kubes' monument 26-Jul-03 FIX: Fixed a crash if the height of a schedule entry (waypoint) was changed and the schedule window was opened after the height change FIX: Using the emergency button to remove vehicles now resets the rail block counters if the vehicle was a train NEW: tooltips for tool selection windows 22-Jul-03 FIX: Screenshot directory is now created with correct access permissions under Linux FIX: all 16 player color sets are loaded correctly again FIX: Fixed two minor bugs in world map creation that caused trouble if the water level was changed from default level 20-Jul-03 CHANGE: Continued work on artificial slopes - created menu icons and added slope tools to raise and lower land. NEW: Textures for slope support walls NEW: Added loading and saving of artificial slopes. FIX: Fixed a bug in heightfield loading (wrong filename suffix) (Heightfields are still searched in the "save" directory) 19-Jul-03 CHANGE: Continued work on artificial slopes - completed slope table, created a menu and tools 17-Jul-03 CHANGE: Continued work on artificial slopes - painted slope cut walls and implemented first version of slope mapping table. 16-Jul-03 CHANGE: Changed grid heights to sint8. This saves 65k for a standard 256x256 map CHANGE: Continued work on artificial slopes - grounds now have up to three images: artificial walls, the ground itself and a way image (this takes additional 128k of memory for a standard 256x256 map) 14-Jul-03 NEW: Started to work on artificial slopes 13-Jul-03 FIX: Fixed a bug in AI code that could crash the game if the AI was searching for suitable places to build a station near the map border CHANGE: Private cars speed risen to 60 km/h 12-Jul-03 CHANGE: Enlarged text buffer for convoi info window from 16k to 32k CHANGE: Lowered passenger generation at tourist attractions by 20% CHANGE: Included Tomas Kubes' sawmill in 64x64 image set NEW: Added emergency button to vehicle info window - it removes the vehicle from the map. This is useful to get rid of stuck vehicles. Be careful: the removed vehicle is gone forever! The button is labelled "X". NEW: AI will now remove vehicles if they have no suitable route (anymore) - i.e. due to a bug or player sabotage. 09-Jul-03 FIX: Tourist attractions are valid passenger destinations again - formerly this information was lost after loading a saved game FIX: Fixed bug in tourist attraction buildings own tourist generation code ... sometimes they produced insane amounts of tourists, followed by periods of no production at all. Generation rate is now set to 82 passengers per minute for perfect destination coverage (I never reached more than 30% coverage so far). 07-Jul-03 FIX: Fixed a bug in payment calculation while waiting for a given loading level (i.e. wait for 100%). CHANGE: During my tests it seems that maintenance costs are much too low. Thus I've doubled all maintenance costs. -> this is also an incentive to use ships. Unlike rails and roads, water doesn't need maintenance :) NOTE: Due to the changed payment calculation (introduced in 0.82.0exp), passenger transport gives higher revenues now. Maybe further adaptations must be made, but the new calculation scheme is correct, while the old scheme was wrong. 06-Jul-03 FIX: Compressed savegames work reliably now. (See simuconf.tab for details) CHANGE: Changed income calculation: now on every stop income is calculated for all transported goods, based on the distance since the last stop. Before, it happened that goods that stayed in the vehicle for several stops, only paid the last hop, instead of the full distance. CHANGE: Lowered (to 25%) amount of passengers generated at tourist attractions. Now up to 42 passengers are generated per minute (less if the player has not 100% destination coverage). Included new or updated language files: nl.tab - Martyn Minnis cz.tab - Kamil "FastIkarus" Ondrák fi.tab - Antti Louko pl.tab - Piotr Pietrzak sk.tab - Ján Krnác sv.tab - Julius Grantén pt.tab - Eric C. Olivera 28-Jun-03 Changes by Volker: CHANGE: New path structure - subfolders font, palette, save and screenshot are now used. Starting the new game will create them automatically and move the files there. Be careful: an old version will not find them afterwards. NEW: More work on new depot dialog (resizeable etc.) NEW: Speedbar for vehicles CHANGE: Removed old code - this can only read games saved with the prev. version. NEW: Savegames are now zipped by default - loading autodetects the savegame type. (Hajo: doesn't work on my system. Default seems to be set to binary, not zipped. Forcing zipped mode causes a crash). CHANGE: Trees are displayed small in hide-buildings-mode NEW: When using commandline "-load " the extension needs no longer be supplied. ??? CHANGE: industry distribution now generates larger average distances between industries 21-Jun-03 CHANGE: continued work on new vehicles and pathfinding 20-Jun-03 CHANGE: continued work on new vehicles and pathfinding 19-Jun-03 CHANGE: continued work on new vehicles and pathfinding 18-Jun-03 CHANGE: continued work on new vehicles and pathfinding 17-Jun-03 NEW: started to work on a new vehicle class that implements a different, more flexible pathfinding method About 0.82.pre1 This version is really just a preview. Volker told me he will further improve the depot dialog, but you can already try it a bit. Also Volker made a lot of internal changes that can affect stability but we hope that overall they will help further development. A few minor bug fixes are also included. You can use this version with the 0.81.35exp base package. 14-Jun-03 FIX: fixed a bug in player color tables (green color set got wrong values due to some wrong index calculations) FIX: fixed ground water level calculation in zoom modes with a raster width of less than 64 FIX: bridges can now be built on electrified track CHANGE: included Volkers changes (lots ... most notably the new depot window) 09-Jun-03 CHANGE: support for unzoomable images (icons ...) adapted MakeObj, display routines and dat files -> if image names in .dat files are prefixed with "> " they will not get zoomed in the game -> IMPORTANT NOTE: this changes makes all previous PAK files incompatible!!! 07-Jun-03 FIX: player color table initialisation wasn't executed after starting a new game. Table now gets initialised always. 29-May-03 CHANGE: enhanced MakeObj and Simutrans to use 7 shades of player colors (instead of 4). Also there are now 9 reserved player colors that can be used for future expansions -> This change introduces a slight incompatibility with old saved games. The player color settings will most likely become reset to color set 0 if loading an old game, some times a random other set can be chosen. This means you'll most likely have to choose your preferred color set again. 25-May-03 released 0.81.33exp 24-May-03 FIX: tourist generation now depends on real time (formerly it depended on simloops, but simloops vary too much to be a reliable measure) NEW: factory window now displays the category of produced goods if they are categorized goods 15-May-03 NEW: added category for cooled goods (category 4) CHANGE: changed calculation of town growth a bit (towns grow slower now) CHANGE: zoom level can now be changed by "page up" "page down" keys, too. (Zooming quality is still bad) 11-May-03 NEW: translations are now read from 'text' subdirectory. Simutrans can now read up to 40 translation files. Thanks to Adam Barclay for this nice addition. 08-May-03 CHANGE: cursor keys now scroll map, too 25-Apr-03 FIX: traced Simutrans for memory leaks and accesses of/to uninitialised memory 21-Apr-03 CHANGE: optimized some graphics routines (5% faster now) 20-Apr-03 CHANGE: reduced number of malloc()/free() calls for loading trees and buildings (-> games should load a bit faster now) 19-Apr-03 FIX: fixed a crash if the player or AI scheduled a new vehicle 18-Apr-03 FIX: after a schedule is changed, freight to stations that are no longer included in the schedule is removed from the vehicle FIX: saved games in which factories have negative amounts of input stored are now repaired (amount set to 0) upon loading. Also factories that have more than 15000 units of input are clipped to 15000 units. 15-Apr-03 FIX: fixed a memory leak in slist_tpl/nodelist 08-Apr-03 FIX: goods distribution didn't consider multiple destinations per station properly. This should be fixed now. 05-Apr-03 CHANGE: factories now distribute goods always to that station that currently has the least amount of that good stored CHANGE: reduced vehicle waiting time at stations by 15% in average. Unfortunately the waiting times vary strongly. CHANGE: improved shores images a bit FIX: tried to fix a bug in the AI code that sometimes created train stations with defective last tiles and then placed trains on those defective tiles with the effect that those trains never could move 29-Mar-03 CHANGE: removed last dependency to ADT package 23-Mar-03 CHANGE: optimized map lookup 22-Mar-03 CHANGE: optimized goods routing 21-Mar-03 CHANGE: optimized goods routing 20-Mar-03 CHANGE: optimized vehicle routing FIX: land vehicles now always find shortest path CHANGE: optimized routing of goods and passengers 16-Mar-03 CHANGE: changed ownership (player) management for things CHANGE: tried to reduce memory consumption, saved 8 bytes per map square that has no bridge or tunnel -> risen max map size to 768 for that people with powerful computers. FIX: fixed a potential buffer overflow in minivec_tpl FIX: fixed a potential buffer overflow in microvec_tpl 15-Mar-03 NEW: included Matthews changes for "min size" window gadget NEW: "new map" dialog now gives estimated memory requirement for chosen map size NEW: included 4 types of variant grass to break the uniformity if the landscape 13-Mar-03 FIX: fixed a problem if tunnels went under squares with name signs or bridges went over them FIX: fixed the dat file for TPI Class 26 engine 06-Mar-03 NEW: fixed another bug that caused a program freeze if a private car had gone 2^32 steps (overflow problem) 05-Mar-03 NEW: include Tomas' new forest creation routines 02-Mar-03 FIX: added some missing entries to german translation CHANGE: slightly risen productivity of gas stations 26-Feb-03 CHANGE: finance window now formats money as 1.000,00 FIX: negative total balance is now displayed in red 23-Feb-03 NEW: number of transported passengers now influences city growth (see +X in city info window. +1 means doubled growth, +2 means tripled growth rate. Will always be 0 after loading a new game and midnights. Needs a while to be recalculated.) NEW: new industry branch 'gasoline production' NEW: included Alberto Beccarias updated italian translation CHANGE: reenabled display/brightness control. Range is now -8 ... 0 0 being the brightest setting. 0 is default value. CHANGE: slightly risen the average distance of industries CHANGE: made church a special building released unofficial 0.81.23exp 22-Feb-03 NEW: tested -nosound and -nomidi switches on windows 20-Feb-03 NEW: -nosound and -nomidi switches to turn off sound and music 19-Feb-03 FIX: fixed a bug in building level-crossings on non-empty squares NEW: Materialwholesale now also accepts planks and steel NEW: Home market now also accepts planks 17-Feb-03 FIX: fixed a bug in help text viewer that caused a crash if more than two tags were included in the help text FIX: included Alberto Beccaria as italian translator into the intro scroller FIX: fixed a bug in image zooming if going back to zoom factor 1 CHANGE: included new help texts by Adam Barclay ??? Stopped development of zooming feature. Need to wait for Volkers new MakeObj with more flags for images (unzoomable images -> currently icons and other menu-images get zoomed, too). Very simple (fast) zoom routine is working now, zoom quality is bad. 12-Feb-03 NEW: continued to work on zooming feature 11-Feb-03 NEW: continued to work on zooming feature 10-Feb-03 NEW: started to work on zooming feature (use > and < keys to zoom in and out) 09-Feb-03 NEW: added legend to relief map window CHANGE: included Tomas Kubes' new english city name syllables in en.tab CHANGE: performance tuning - changed route_t and vector_tpl index parameters to unsigned, saving one if conditional on each access released unofficial 0.81.22exp 08-Feb-03 NEW: player starting money can now be configured in simuconf.tab NEW: factories now require different amounts of input to produce goods. I.e. to produce one ton of iron 2 tons of iron ore and 0.5 tons or coal are required CHANGE: included Tomas Kubes' new darkening (night mode) code FIX: fixed a wrong gridded grass tile that appeared to be invisible FIX: fixed landscape pointer position calculation in 128x128 tile mode FIX: fixed refresh area for landscape pointer movement in 128x128 tile mode FIX: level crossing only can be build on empty squares (this prevents a crash if you built them while a vehicle was passing this square) FIX: fixed input overflow problem in factories 06-Feb-03 CHANGE: more performance tuning - optimized dingliste bei(n) now takes an unsigned parameter, saving one if conditional - changed array_tpl and array2d_tpl parameters to to unsigned, saving one (two) if conditionals on each element access 05-Feb-03 CHANGE: more performance tuning - inlined ist_bruecke und ist_tunnel, added flags to grund_t - changed minivec get() parameter to unsigned, this saves one if condition - removed one if from karte_vollansicht_t::display_dinge - removed one if from grund_t::display_dinge - removed one if condition and one assignment from karte_t::sync_step - inlined grund_t::gib_weg, and optimized the routine slightly 04-Feb-03 CHANGE: tried to reduce the memory consumption - reduced by 8 bytes per ground. CHANGE: tried to optimize pedestrian routines CHANGE: profiling and overall performance tuning 01-Feb-03 FIX: mail office now has player colors FIX: overhead lines adapt their shape if tracks are removed or added FIX: fixed world/map scrolling in bigtile (128) mode FIX: fixed bridge icons for night mode with lights FIX: scrolling with numeric keypad works again FIX: Stadium 2, Layout 1 fixed (created invisible stadiums before) NEW: ESC closes all windows (BACKSPACE and DELETE do that too) 28-Jan-03 NEW: there is now a toggleable ground tile grid. Press # to switch the grid on/off. 27-Jan-03 NEW: finished buttons for the factory info window to jump to consumers, also added buttons to jump to the workers home towns 27-Jan-03 NEW: started to add buttons to the factory info window to jump to consumers conveniently 26-Jan-03 NEW: started to work on lights for the night mode released unofficial 0.81.20exp 25-Jan-03 FIX: road tunnels again get correct image after loading (was broken during migration to new pak files) FIX: private cars are no longer visible while passing a tunnel FIX: it is not longer possible to build rail stations twice on the same square if overhead lines are present CHANGE: saved 4 bytes of memory per convoy CHANGE: included improved paper mill from Tomas Kubes released 0.81.19exp 23-Jan-03 FIX: overhead lines on bridges are now (again) loaded correctly from saved games FIX: signals on bridges are now loaded correctly from saved games CHANGE: city building tool now included in toolbar FIX: city building cursor now has proper size FIX: removing roads and railroad track now costs 100 Cr 22-Jan-03 FIX: Again included this fix, it had somehow been lost: 07/13/02 - FIX: fixed a bug that caused an endless loop once a private car had gone more than 2**31 steps FIX: fixed overhead line images for diagonal track NEW: started work on line (route) management 20-Jan-03 CHANGE/FIX: also doubled running cost for 'Bennhardt' engines (had been overlooked yesterday) NEW: added Colins hong kong ferries NEW: added Bens industrial city buildings 19-Jan-03 FIX: fixed dat file entry for "large office building (by Trikky)" FIX: sand truck can now be used without trailer CHANGE: changed max map size from 576 to 640 (requires ~60MB ram and a whole lot CPU time plus memory bandwidth!) CHANGE: changed "Passenger %" for monuments from 150 to 60 CHANGE: enhanced capacity of all busses by about 5% CHANGE: changed capacity of mail wagon from 60 to 120 bags CHANGE: changed capacity of mail boat from 140 to 180 bags CHANGE: changed capacity of mail trucks to 50 and 60 bags CHANGE: doubled running costs of all vehicles. Lowered running costs for electric engines slightly. CHANGE: rose starting money to 150000 Cr CHANGE: newly generated passengers will not use stations where more than 64 passengers per square are already waiting Note: workers nevertheless use crowded stations! CHANGE: reduced passenger generation ratio from (building_level+2) to (building_level+4)/2 -> that is roughly the same as before for low-level buildings, but only have of the former rate for high-level buildings released 0.81.18exp 18-Jan-03 CHANGE: added updated italian translation from Alberto Beccaria released 0.81.17exp CHANGE: changed grounds to use memory pools (should save about 256K main memory for a 256x256 map, and also be faster) FIX: Ships can now be sent to depots again FIX: fixed a bug in restoring overhead line images when loading games that had been saved under a different OS or with a different set of PAK files - this also saves 4 bytes per saved overhead line tile 17-Jan-03 FIX: made some bugfixes for new bigtile mode FIX: fixed a bug in overhead line y-offset calculation that made overhead tiles on bridge ends move higher and higher if the overhead lines were re-built (again) NEW: added automatic tile size detection (PAK files reader) -> requires at least one full width image in tile set NEW: linked lists now allocate nodes from a pool. Slightly faster than before and conserves a little bit of memory CHANGE: changed toolbar window to work with 128 and 64 pak files CHANGE: additional station segments only cost half of a new segment CHANGE: new station segments now cost 2400Cr 16-Jan-03 TEST: made some tests with 128x128 tiles FIX: fixed a bug in MakeObj/PNG file reading FIX: fixed a bug in MakeObj image writing 15-Jan-03 NEW: preparation for configurable tile size 14-Jan-03 NEW: tried to implement a more efficient management for linked list nodes, try to reuse as many nodes as possible 12-Jan-03 FIX: fixed rail bridge images which seem to have been damaged during the conversion to the new multi-pak file approach. FIX: fixed a basement image which seems to have been damaged during the conversion to the new multi-pak file approach. 08-Jan-03 FIX: fixed a bug that sometimes move the city area out of map bounds if a town hall was renewed FIX: added correction code to read games with towns that suffer from the above mentioned problem 05-Jan-03 FIX: player cannot rename AI stations anymore FIX: VT95 and VT98 can be run as single cars again FIX: TPI F7A can be run on non-electrified track again FIX: hotkey 'e' used wrong landscape pointer image FIX: fixed VT95 images which seem to have been damaged during the conversion to the new multi-pak file approach. CHANGE: schedule window now displays destination coordinate (Schedules are platform-precise!) 04-Jan-03 CHANGE: bus stops now can be placed even if there are pedestrians there NEW: added monument inscriptions to en.tab FIX: fixed plastic wagon images (player color) which seem to have been damaged during the conversion to the new multi-pak file approach. FIX: overhead powerlines on bridge ramps on even ground have correct height offsets now FIX: overhead powerlines in tunnels are no longer visible FIX: removed extraneous second 'dock' button from ship tools menu 03-Jan-03 CHANGE: tried to reduce jitter in vehicle movement CHANGE: tried to optimize the updates of trees, buildings etc. overall this should help to run larger games, but I don't know how much improvement it will bring. FIX: fixed steel truck and steel trailer images which seem to have been damaged during the conversion to the new multi-pak file approach. 01-Jan-03 FIX: stations can now be built on electrified track, too FIX: Bennhardt BR140 now only runs on electrified track FIX: fixed a bug in AI code that tried to use electric engines on non-electrified track FIX: added missing STADIUM1 entry to en.tab and de.tab FIX: fixed mixed lines for 'Lade Spiel' in de.tab 22-Dec-02 CHANGE: lowered passenger % of townhalls. Now: 75, 75*4, 75*4, 75*4 CHANGE: added checks for two potential crashes in searching for locations of monuments and town halls CHANGE: repaired images for paper wagon, paper truck, paper trailer which seem to have been damaged during the conversion to the new multi-pak file approach. FIX: added missing wav files (lost since conversion ...) released unofficial 0.81.12exp 21-Dec-02 CHANGE: more work for overhead powerlines 20-Dec-02 CHANGE: more work for overhead powerlines 15-Dec-02 CHANGE: more work for overhead powerlines 12-Dec-02 NEW: started work on overhead powerlines for electrified track 11-Dec-02 NEW: non-station buildings can be hidden from display by pressing " (Shift-2 on a german keyboard). This is useful if large buildings block sight to something important. NEW: started to work on electrified, monorail and maglev track types electrified tracks work already, yet they still look the same as ordinary tracks 07-Dec-02 CHANGE: changed capacities: Furniture wagon: 20 crates Furniture truck: 16 crates Furniture trailer: 18 crates NEW: Option for semaphore signals released unofficial 0.81.11exp ??? released 0.81.10exp 30-Nov-02 CHANGE: improved/reworked H-Trans coal truck image FIX: fixed .dat file for furniture wagon 17-Nov-02 FIX: fixed some bugs in routing of goods (broken during changes for categorized goods) BUG: Station list filter for incoming/outgoing goods might work differently than before. I never used it, so my change is just a guess released unofficial 0.81.9exp 16-Nov-02 NEW: enlarged schedule window CHANGE: goods are now grouped into unique goods, parcel service and bulk goods. Vehicles that transport goods of the categories parcel and bulk goods can now transport _any_ good of those categories. I.e. a coal car can now also be used to transport iron ore. Parcel service: Books, Furniture Bulk goods: Sand, Stone, Coal, Iron Ore Due to this change the savegame format became incompatible. Sorry, no conversion is possible, even some of the pak files now have a different structure. CHANGE: enlarged text buffer for vehicle information window to reduce the danger of buffer overruns 26-Oct-02 FIX: After schedule changes, no-longer existing routes are checked and waiting goods are cleaned up. This should fix the long-standing bug that passengers and goods waited endlessly after a route was shut down and/or replaced by another route. This cleanup action is pretty time consuming. In games with many stations and vehicles, running on slow computers this will take several seconds to complete. released unofficial 0.81.8exp 20-Oct-02 FIX: Oil rigs now accept passengers and mail (again, was broken after 0.81.0) released unofficial 0.81.7exp 19-Oct-02 FIX: fixed a bug in loading saved games (height information was accessed before actually loaded) FIX: fixed a bug in AI bridge testing routines (AI tried to build bridges in unsuitable locations and ended up with broken routes) 12-Oct-02 FIX: random pedestrians can now actually be turned on and off in simuconf.tab FIX: fixed a bug which caused convois not being saved after visiting a depot without disassembling the convoi FIX: maintenance costs are now displayed in red CHANGE: relief map is now zoomable: right click into map to toggle zoom/unzoomed display released unofficial 0.81.6exp 06-Oct-02 CHANGE: tried to make relief map zoomable 06-Oct-02 FIX: updated/fixed more images/animations FIX: tried to fix the problem that some vehicles were not immediately visible after loading. FIX: fixed the problem of vehicles stored in depots being invisible after loading. released unofficial 0.81.5exp 05-Oct-02 FIX: updated/fixed more images FIX: italian translation is available again FIX: added Bennhardt train engines again CHANGE: message windows now appear above the mouse pointer and don't obstruct the players actions anymore. CHANGE: depot windows open in the top-left corner of the screen now. 04-Oct-02 FIX: fixed many mistakes in new config files and image set FIX: maintenance costs are now displayed correctly in finance window FIX: fixed a translation mistake in en.tab 03-Oct-02 FIX: fixed a bug in tree creation that was introduced with the new configuration system. FIX: fixed a bug in loading tunnel descriptions 20-Sep-02 CHANGE: Starting money again set to 100.000Cr CHANGE: made info windows for pedestrians and private cars configurable in simuconf.tab 29-Sep-02 CHANGE: changed passenger generation in cities (steps more frequently, but only every 8th row) 28-Sep-02 CHANGE: continued code cleanup -> all 'builder' classes now located in 'bauer' -> all 'searcher' classes now located in 'sucher' 26-Sep-02 CHANGE: continued code cleanup 25-Sep-02 MERGE: included Volkers changes to the config/object system CHANGE: started to move factory classes into a separate package CHANGE: did some code cleanup in simgraph16.c 22-Sep-02 NEW: station detail info now displays factory coordinates, too NEW: water (ground) animation can now be turned off in simuconf.tab (i.e. if you have a slow CPU and want to save some computation time for other tasks) They serve some useful purpose, though: the more you see around a spot, the better the place to build a station there. NEW: player/AI colors can now be configured by editing the file "special.pal" which is a text file containing 64 RGB colors in decimal values FIX: loading pedestrians works now FIX: fixed some problems in day&night mode: 1) vehicles/player properties darken now during nights 2) window title bars don't darken during nights CLEAN: did some more code cleanup in simgraph16.c CHANGE: interrupt routine now updates display first and then calculates next frame - i hope this will reduce the jitter in vehicle movement CHANGE: changed sync_step routine to be (hopefully) faster and more robust against the most common coding mistakes (deleting/removing a sync object while a sync step is running). CHANGE: tombstone arrays are now configurable in simuconf.tab 21-Sep-02 NEW: schedules are no longer lost if a vehicle enters a depot 20-Sep-02 FIX: repaired broken AI road/railroad building routines TIME: 2:00h 19-Sep-02 MERGE: continued merge of sources NEW: station detail info now includes connected industries CLEAN: cleanup in simgraph16.h and simgraph16.c TIME: 1:30h 18-Sep-02 MERGE: merged Volkers changes for new config system TIME: 2:00h 05-Sep-02 NEW: included italian translation from Alberto Beccaria NEW: built preview for BeOS CHANGE: updated thanks.txt TIME: 1:30h 02-Sep-02 CHANGE: changed layout of the ship depot. It looks a bit better than before, but some ships are just too oversized - why don't the artists follow the size guidelines? CHANGE: some trailers now fit to all trucks CHANGE: changed price, weight and running cost of the double decker busses FIX: fixed alignment of some ships TIME: 2:00h 01-Sep-02 FIX: bus stops are recolorable again FIX: changed and added some entries to de.tab FIX: changed and added some entries to en.tab FIX: included hu.tab fix from MrTLee CHANGE: tried to improve bus stop images CHANGE: changed sand wagon to be recolorable CHANGE: changed stone wagon to be recolorable TIME: 2:30h 31-Aug-02 CHANGE: raised starting money to 100000 Cr CHANGE: if a help text can't be found, the help text frame error now includes the filename of the missing file CHANGE: drive in cinema is now built at 600 inhabitants CHANGE: lowered productivity of coal mines and iron ore mines by 10% CHANGE: all of Bennhardts vehicles have reasonable prices and running costs TIME: 1:30h 30-Aug-02 CHANGE: changed tombstone implementation for stations to a more efficient variant CHANGE: removed brightness and contrast control from the display options dialog because they didn't work anymore since the transition to the 16 bit graphics code and those features most likely won't be implemented again. CHANGE: declared savegames previous to 0.80.10 incompatible because some vehicles couldn't be restored from such savegames properly. FIX: oil rigs don't raise the players maintenance costs anymore NEW: added missing stadium images TIME: 1:00h 29-Aug-02 CHANGE: included updated translations CHANGE: changed prices for "Bennhardt" train engines CHANGE: changed tombstone implementation for convois and railblocks to a more efficient variant FIX: fixed a crash if the vehicle list was left open and displaying a vehicle that enters a depot FIX: fixed stadium images for layout A FIX: fixed non-matching entries for Tigress I in language files and vehikel.tab, also removed an unused double entry for the Tigress I from vehikel.tab TIME: 3:00h 07/20/02 - FIX: fixed 2 wrong entries in gebaeude.tab - FIX: included Dennis' correction for en.tab TIME: 1:00h 07/14/02 - FIX: sped up buying vehicles in depots TIME: 1:00h 07/13/02 - FIX: fixed a bug that caused an endless loop once a private car had gone more than 2**31 steps TIME: 1:00h 07/11/02 - FIX: factory descriptions are restored after loading. This fixes a crash after loading saved games in 0.80.10a - FIX: (hopefully) oil rigs now accept passengers TIME: 1:00h 07/08/02 - FIX: heightfield loading now loads other files than "heightfield.ppm", too - FIX: confirming the heightfield file selector box with an invalid name no longer crashes the game. - FIX: better error messages for heightfield loading, errors no longer quit the program. - FIX: colors of the factories in the map window are now again the color configured in industry.tab TIME: 1:00h 07/07/02 - NEW: included 8 new train images painted by Benjamin "Bennhardt" Siegel - NEW: included the alignment-corrected trucks from Jens "JET" Emmel - NEW: included a new ship from Jens "JET" Emmel - FIX: buying a trailer or wagon without having an engine no longer crashes the game - KNOWN PROBLEMS: - ship depot display is messed up pretty much - all of Bennhardts engines have same price and running cost, sensible values will be discussed on the mailing list and included - released unofficial 0.80.10-16exp TIME: 2:00h 07/06/02 - NEW: finished heightfield loading - NEW: included the improved trees from Tomas Kubes (sorry Tomas I had to modify them slightly). - CHANGE: changed the toolbar icons TIME: 4:00h 07/05/02 - NEW: option to load heightfield (a PPM image where the brightness of a pixel determines the height for that spot on the map) TIME: 1:30h 07/01/02 - FIX: fixed a bug in Markus' patch for the depot window - when buying a new vehicle the cost of a lot of different vehicles was also withdrawn from the players account. - released unofficial 0.80.9a-16exp 06/30/02 - FIX: maintenance cost is now actually subtracted from players account every month. - FIX: fixed a wrong entry in gebaeude.tab - MERGE: included Owen Rudges Win32 midi playing routines - released unofficial 0.80.9-16exp 06/29/02 - NEW: maintenance costs for roads, railroads and buildings: - road/railroad: 5.00 Cr/month - each building: 50.00 Cr/month (There is a small bug here: ATM oil rigs belong to the player, and thus the player has to pay maintenance costs for them). - MERGE: merged Markus patch to display only matching carriages in the depot window TIME: 1:30h 06/23/02 - NEW: List of all schedules (also saved 4 bytes memory per schedule) - FIX: savegame frame shows local time instead of GMT - CHANGE: map frame now has a minimum sizeof 96x64 pixels TIME: 0:30h 06/15/02 - CHANGE: sped up graphics by another 2% - released unofficial 0.80.8-16exp TIME: 3:00h 06/14/02 - FIX: industries have several consumers again (Volker) - FIX: building a loading bay on a cities road sets the roads owner correctly now. - NEW: tunnels and bridges are displayed in the map (Volker) TIME: 1:00h 06/13/02 - FIX: window resizing bugs fixed TIME: 1:00h 06/09/02 - MERGE: merged Markus changes - station list now includes icons - MERGE: merged Volkers changes - internal changes to train and truck stations to streamline the class hierarchy - more and more strict tests for building roads/railroads - new industry distribution. Can consider weights, given by industry.tab, to prefer (or not) certain industry branches. - existing screenshots are preserved, new screenshots always get high enough numbers. - changed load/save dialog * Buttons for deleting files (take care!) * Displays save date and time (Just a proposal - test it, and let us know if you like it or not) - schedules: depots listed as depot and no longer as waypoint - TEST: tested Owens win32 media routines, but couldn't get them to work with my compiler - excluded in this release. - CHANGE: the Linux version now tries to open 640x480, 800x600 1024x768 and 1280x1024 in fullscreen. Use the -screensize option to force a windowed mode by using a different resolution. - released unofficial 0.80.7-16exp TIME: 4:00h 06/08/02 - NEW: map window remembers size and uses old size when open again - NEW: painted animated diesel smoke and steam (only used with vehicles currently) - CHANGE: smoke type is now read from current vehikel.tab instead from saved game. - CHANGE: included Volkers changes to allow processing an unlimited number of images with makepak16 TIME: 1:00h 06/07/02 - CHANGE: frame sync smoke is now a 5 frame animation TIME: 0:30h 06/05/02 - CHANGE: changed income calculation for transports to: distance * amount * price * (pow(0.97, distance)+0.4)/2.0 this is nearly linear for long distances and a bit better than linear for short distances. - CHANGE: vehicles only produce smoke while heavily accelerating TIME: 1:00h 06/02/02 - FIX: clicking a post office opens the station window again - FIX: fixed a memory leak during map destruction. TIME: 2:30h 06/01/02 - MERGE: merged Markus' changes for resizeable windows - CHANGE: adapted Markus' changes to fit better into Simutrans TIME: 1:30h 05/30/02 - NEW: help texts for relief map and finance window added - NEW: industry colors are now read from industry.tab - NEW: support for hyperlinks in help texts - CHANGE: better error messages for wrong entries in industry.tab TIME: 3:00h 05/29/02 - FIX: fixed "wait for xxx%" entry in en.tab so that the % number is always clearly visible in the schedule dialog - NEW: preparation for factory color configuration in industry.tab TIME: 1:00h 05/25/02 - CHANGE: restructured system dependant code - preparation to build system dependant media subsystems. Started to include Owen Rudges native win32 MIDI playing code. TIME: 1:00h 05/19/02 - FIX: Player color (object recoloring) feature works again. - CHANGE: removed colormap functions from HiColor system wrappers - CHANGE: buildings basements now use mempools - NEW: (Hellmade) included screenshot facility for 16 bit graphics engine - MERGE: Merged Volkers changes (Filter-Dialogs, many small patches) - released unofficial 0.80.6-16exp TIME: 3:00h 05/18/02 - FIX: (Hellmade) Double headed trains will be correctly disassembled in depots - FIX: (Hellmade) Buying more than 16 wagons for a train moves the additional wagons to the pool section TIME: 3:30h 05/09/02 - NEW: merged Volkers changes - FIX: fixed a clipping bug for coloured images in the 16 bit graphics engine. - CHANGE: info windows for buildings now carry title "Building" again. TIME: 1:30h 04/20/02 - NEW: integration of Flors new image set - FIX: fixed some display problems of the toolbar - FIX: building and removing tunnels costs some money now - FIX: building and removing bridges costs some money now - FIX: city building tool places townhall on the right spot now - FIX: industries productivity now varies (the range parameter from industry.tab is no longer ignored) - CHANGE: cementmill now requires stone - CHANGE: productivity/range entries in industry.tab updated - CHANGE: changed night to a more blueish color released unofficial 0.80.4-16exp TIME: 2:30h 04/18/02 - FIX: fixed a buffer overflow in simgraph16.c (dirty tiles list) - NEW: extended error checking capabilities for memory management -> can now detect overflows TIME: 1:30h 04/17/02 - FIX: F1 key now triggers general help in 16 bit version, too - NEW: internationalizeable help texts TIME: 0:45h 04/13/02 - CHANGE: "random map" buttons now generates a real random sequence of maps - FIX: tried to fix a bug that sometimes prevented the AI from building tunnels (the AI ended up with a broken route) - FIX: fixed a crash if a highest level building was build (crash only occurred in 0.80.2-16) TIME: 1:00h 04/11/02 - FIX: fixed a bug in player-triggered city building TIME: 0:30h 04/10/02 - NEW: player can found new cities - hotkey 'C' - CHANGE: hotkey for vehicle list changed from 'C' to 'V' TIME: 0:30h 04/07/02 - CHANGE: converted dirty tile list to bitfield. This saves some KB of memory. - FIX: fixed a potential access to an uninitialized route element - FIX: tried to fix the road vehicle lockup problem on level crossings TIME: 1:00h 04/06/02 - FIX: fixed some untranslated messages in bridge building - FIX: fixed some wrong entries in en.tab and de.tab - CHANGE: updated thanks.txt file TIME: 0:30h 04/04/02 - CHANGE: changed night darkness to be less dark - FIX: fixed a crash if land was raised from under a ship - FIX: fixed a crash if a stop outside the map was added or inserted into a schedule TIME: 0:30h 04/03/02 - FIX: fixed a bug in the 16 bit graphics code that caused a crash when a player-colored image with an invalid number was displayed. TIME: 0:30h 03/28/02 - CHANGE: merged Volkers 2nd update to house building - Release unofficial 0.80.2_16 TIME: 1:30h 03/27/02 - CHANGE: 16 bit graphics routines about 40% faster than before - FIX: fixed some typos in help texts TIME: 1:30h 03/26/02 - CHANGE: exchanged . and , keys for time lapse control - CHANGE: tried to optimize 16 bit graphics engine TIME: 1:30h 03/24/02 - FIX: pressing shift doesn't trigger keyboard help anymore - NEW: merged Volkers changes to house building - NEW: merged Markus changes to station list window TIME: 0:30h 03/09/02 - FIX: raising/lowering land at the border of the map no longer crashes. TIME: 0:30h 02/23/02 - NEW: included help texts for loading and saving games. TIME: 0:30h 02/22/02 - FIX: fixed a crash if a railroad track or road was build outside the map. TIME: 0:30h 02/17/02 - FIX: fixed a crash if a railroad track was built at the very edge of the map - CHANGE: news ticker is only displayed if there are news TIME: 0:30h 02/16/02 - NEW: added more help texts: language, options - FIX: fixed a bug in the flowtext display component TIME: 1:00h 02/15/02 - FIX: fixed the 'cloud offset overflow' problem - NEW: added more help texts: depot help TIME: 1:00h 02/13/02 - NEW: added more help texts TIME: 1:00h 02/11/02 - NEW: working on in-game helpsystem, added more help texts TIME: 1:00h 02/10/02 - NEW: working on in-game helpsystem, added more help texts TIME: 1:00h 02/09/02 - NEW: working on in-game help system TIME: 1:30h 02/07/02 - NEW: started working on in-game help system TIME: 1:30h 02/06/02 - CHANGE: made some changes for Markus Weber TIME: 0:30h 01/28/02 - FIX: Fixed a crash when a vehicle was sold. This bug was introduced during yesterdays changes to convoi routing. - FIX: Fixed a crash if vehicle.tab did not contain a vehicle that was required by depot.tab TIME: 1:00h 01/27/02 - CHANGE: Made convoi route preparation also an asynchronous task. - CHANGE: Because asynchronous tasks take longer to execute, vehicles stop longer at stations than before. To rebalance the game, the productivity of all industries was reduced by 10%. - CHANGE: Due to the new asynchronous parts in convoi setup vehicles may remain much longer in a inconsistent state. That problem is solved now. - NEW: released unofficial version 0.80.pre3 TIME: 2:00h 01/26/02 - CHANGE: Increased safety buffer in convoi info display. - CHANGE: Increased safety buffer in station info display. - CHANGE: Made convoi setup an asynchronous task. - CHANGE: Halved minimum acceleration. - CHANGE: Reduced uphill speed. - CHANGE: Reduced speed in curves. - CHANGE: Fiddled with frame time calculation to get smoother vehicle movement. TIME: 3:30h 01/24/02 - FIX: Fixed some bugs in asynchronous vehicle loading code. Overall asynchronous loading seems to allow to use quite some more vehicles than before. - FIX: Improved responsiveness to user input under high load. TIME: 2:00h 01/23/02 - FIX: Debugging - CHANGE: Made vehicle loading an asynchronous task. - CHANGE: Passengers and goods transfer at most 30 times from one transport to another to reach their destination. TIME: 2:00h 01/20/02 - CHANGE: Saved 8k memory per convoi. - CHANGE: Saved 8k memory per station. - CHANGE: Included a change from Markus Weber to display summary information in station info windows. - CHANGE: Changed layout of vehicle list to display vehicle with 3 figures (100+) better. - CHANGE: Using memory pools for water grounds - this saves 4 bytes per water square and speeds up allocation and deallocation of water grounds. It also helps to reduce memory fragmentation. - FIX: Fixed a possible buffer overflow in halt list. - FIX: Included a fix for setting the correct water level during loading a game. - NEW: released unofficial version 0.80.pre2 TIME: 3:00h 01/19/02 - FIX: Fixed a bug in clipped 16 bit image display routines - FIX: Fixed a bug in SDL sound routines that caused a crash in the windows version - FIX: Fixed a possible buffer overflow in route calculation of goods and passengers. - NEW: Fullscreen mode for Linux/SDL in 640x480, 800x600, 1024x768 and 1280x1024 (The Windows version always offered those as fullscreen modes) TIME: 3:00h 01/17/02 - NEW: RGB555 <-> RGB565 transform for 16 bit engine finished - NEW: optimized 16 bit engine TIME: 3:00h 01/16/02 - FIX: Fixed a bug that crashed Simutrans if the player managed to delete/destroy a private car. - NEW: Makepak16 reads 8/16/24 bit PNG files now. TIME: 1:00h 01/13/02 - MERGE: Andreas Rövers sound routines for SDL - TEST: Tested Simutrans with SDL 1.2 - NEW: updated 16 bit graphics routines (not complete yet) TIME: 4:00h 01/12/02 - NEW: -scenario option to make Simutrans read config files and daten.pak from that directory. TIME: 3:00h 01/09/02 - MERGE: included Markus' resizer component and the changes to the vehicle list -> Station list window and vehicle list window can be vertically resized now - CHANGE: changed look of resizer component to better fit the other gui components of Simutrans - NEW: released unofficial version 0.80.pre1 TIME: 1:00h 01/08/02 - FIX: automated test suite works again (was broken since Volkers changes during summer/autumn last year). - FIX: cities generate passengers to 2x2 squares sized tourist attractions, too. - CHANGE: using memory pools for trees - this saves 4 bytes per tree and speeds up allocation and deallocation of tress. It also helps to reduce memory fragmentation. - CHANGE: did some finetuning to make the framerate more constant - MERGE: include Markus' new station list window and button TIME: 5:00h 01/02/02 - MERGE: merged Volkers changes - Shift-M opens marker UI - Removing a bus stop from a square with a sidewalk keeps the sidewalk - Bugfixes for bridges and tunnels - Code cleanups - CHANGE: changed layout of the "options" dialog - CHANGE: changed layout of the "new world" dialog TIME: 2:30h 12/28/01 - CHANGE: Reverted some changes made by Volker: - city roads belong to nobody again - a square that the player builds a road or railroad on and that had no former owner belongs to the player again -> That fixes the 'bus station on city roads' problem - FIX: Included a bugfix from Volker to make bridges work again. It seems to work. - FIX: Added missing screen refresh after removing a long bridge TIME: 1:30h 12/20/01 - FIX: Trains can now be stopped while passing signals without bad effects, like corrupted signals and disrupted trains. - CHANGE: Reduced productivity of coal mines and oil fields. - Released unofficial version 0.79.11exp TIME: 2:00h 12/19/01 - CHANGE: Removed 'passenger X%' from industry info window - MERGE: Merged Volkers changes -> Bridges no longer need 'hills' to start/end but can be built on flat ground, too. - FIX: Goods with "error in routing", that means they cannot reach their destination any longer, are now removed from stations after a while. They are also removed from vehicles upon the next scheduled stop. - FIX: Fixed a bug in the AI code that sometimes prohibited the use of tunnels in the AIs routes - FIX: Partly loaded vehicles display the loaded/empty cars now. - NEW: Option in the schedule dialog to set a required loading grade. Vehicles can now wait for a minimum amount of loaded goods before departing. TIME: 6:30h 12/15/01 - MERGE: included Markus changes to world creation UI and convoi UI - CHANGE: Changed layout and text of the full load option in convoi info window. TIME: 1:10h 12/15/01 - CHANGE: prepared Makepak 1.07 for release TIME: 0:30h 12/12/01 - FIX: I got two savegames from beta testers that had an animation count of 0 for some factory buildings. That count should never be 0, even a non-animated building has a least one frame (image) to display. During loading of a game the count gets now set to 1, but how could there a 0 be saved? The 0 caused a crash after loading the game, so this 'fix' at least allows to load the saved games again. - FIX: fixed a crash after clicking the bridgebuilding tool twice - FIX: fixed a small display problem in the news ticker line - CHANGE: Changed lower bound of frame time to 28ms, this yields a frame rate of 35FPS which should be smooth display. - Released unofficial version 0.79.9exp TIME: 1:30h 12/09/01 - FIX: Passenger generation in cities is now bound to real time. I had wrongly assumed that the simulation loop is running always at the same speed but it varies too much. Now, passenger generation tends to be lower in the average case but it is constant regardless of your computers speed. - FIX: Volkers changes prevented the AI to build tunnels and bridges. I've repaired the AI's road/railroad building routines. I hope it works all ok again. - FIX: Newly built stations display world view camera, too. - CHANGE: Changed layout in station info and convoi info windows. - CHANGE: Optimized month change in city class. - CHANGE: Optimized routing of goods. - CHANGE: Optimized routing of vehicles. - CHANGE: Tried to reduce the jitter in frame rate. Frame time has now a lower bound of 30ms and a higher bound of 124ms. Interrupt checks were added to ensure a jitter of less than 5 ms in frame display; I've tested this on my system, slower systems might still have a larger jitter. (Timer precision is 5 ms, that means, the current jitter is below timer precision, more precision is impossible with this timer). - CHANGE: Waiting goods and passengers at station search a new route now and then. This is useful if a new shorter connection is build and the waiting goods/passengers are supposed to use it. - Released unofficial 0.79.8exp TIME: 7:00h 12/08/01 - CHANGE: Included Volkers changes - CHANGE: Signals can now be build near crossings - FIX: A few fixes to bridgebuilding - FIX: Unmasked ribis for ways were determined wrong - CHANGE: Tried to optimize Simutrans further but gained less than 1% overall - CHANGE: Changed news ticker to store only 4 messages instead of 10 - CHANGE: Increased capacity of furniture truck to 8 crates Increased capacity of furniture trailer to 10 crates - NEW: Included Jens 'JET wood trailer' - FIX: Changed some code in station info display to fix a buffer overflow. - FIX: Changed some code in vehicle info display to fix a buffer overflow. TIME: 2:00h 12/05/01 - CHANGE: changed some return types from value types to references. This seems to speed up execution. TIME: 1:00h 12/01/01 - FIX: oil rigs can no longer be removed using the 'raise land' tool. - FIX: oil rigs display a station info window again. - FIX: Fixed a bug that caused some landscape pointers to be displayed at wrong height - FIX: Fixed a bug that caused landscape pointers to be displayed twice - NEW: 'Game paused' splash message - NEW: Included Flor Wauters furniture trailer - CHANGE: reduced memory consumption of each water square by 4 bytes. - CHANGE: optimized screen refresh, gained about 10% speedup if many vehicles are visible TIME: 5:00h 11/29/01 - FIX: if the remover tool is applied to water, the water itself no longer gets removed - CHANGE: changed tree class to reduce the amount of memory modified per step TIME: 1:30h 11/28/01 - CHANGE: made mountain height and landscape roughness parametrizeable for Markus' new 'new world' dialog TIME: 0:45h 11/26/01 - FIX: fixed a crash if the bus station building tool was selected - FIX: included a fix from Volker: if a signals was to near to a crossing the rail block was not correctly traversed. Volkers change should fix that problem. - FIX: fixed a potential crash during map creation (placing power- connector for power plant sometimes failed. This is not fixed really, problematic power plants will just get no power connector. I'll change that once powerlines actually work ) - CHANGE: "Vehicle XY has no route" is only displayed for vehicles which the player actually owns. - CHANGE: Factory info window now carries the name of the industry as title. - PROBLEM: with the change from static to animated buildings the title of most building info windows changed from 'building' to 'house'. - Released unofficial 0.79.7exp TIME: 1:30h 11/25/01 - CHANGE: only wagons inside of a stations will be loaded/unloaded - CHANGE: loading/unloading has a base duration (32) and an additional duration for each wagon (8) - CHANGE: internal change: replaced many old 2d coordinates in paramterlists with 3d coordinates. - CHANGE: Added "Station XY is crowded" message to the newsticker - CHANGE: Factories don't check stations for good distribution as often. This should speed up the program. - FIX: rail block is marked 'left' if a train enters a depot - FIX: added missing screen refresh when saving a game per name - FIX: fixed a bug in blockmanager, which could cause and endless loop during world destruction - FIX: fixed several bugs in handle_as_id_tpl which caused crashes - FIX: fixed a crash when a vehicle with freight was sent to a depot and re-assigned to another convoi. - Released unofficial 0.79.6exp TIME: 8:00h 11/24/01 - NEW: minivec template, a very small vector type. - CHANGE: Reworked plan squares to use minivec type instead of a list type to store grounds. This saves at least 512K memory for a standard 256x256 squares map. In addition accesses should be faster now. - CHANGE: Removed an unused variable from ground class. It seems it was introduced by Volkers changes but actually not used. This saves 512K for a standard 256x256 square map. - CHANGE: Reordered variables in ground class, which saved another 4 bytes per ground. Why is the compiler too stupid to do this automatically? - CHANGE: Squeezed 4 bytes from every object of the thing class hierarchy (most numerous objects in Simutrans). This also shrinks the saved games. - CHANGE: Linked list templates now use a global list of free nodes. This shrinks each list object by 4 bytes, and it speeds up node allocation. - CHANGE: Depot window class and depot data class are now separated. - CHANGE: Code cleanup, reduced interdependencies of header files - CHANGE: Improved look of info windows - NEW: experimental support for multi-headed engines TIME: 6:15h 11/22/01 - CHANGE: Removed superclass infowin_t from weg_t. It was not needed and just consumed memory. - CHANGE: Removed superclass infowin_t from ding_t. It was not needed and just consumed memory. - NEW: Thing info window adapter class - CHANGE: Started to separate depot gui and depot model classes TIME: 2:10h 11/20/01 - NEW: Ground info window adapter class - CHANGE: Changed class hierarchy of ground classes to be independent from info window class -> this allows inlining of some functions and thus speeds up some things (3% speedup overall). - FIX: Info windows display correct ground name again, this feature was lost during Volkers changes. - FIX: Fixed a bug that crashed Simutrans if a ground was removed while the info window for this ground was still open. This also fixes a similar bug for things that are removed. TIME: 1:10h 11/18/01 - NEW: New engine: Tigress I (1144-1151) - CHANGE: Code cleanup - CHANGE: Trees are now generated according to their preferred placement on new maps. Some prefer lower terrain, some prefer the upper regions. - CHANGE: Trees generate up to three new trees during their lifetime. Formerly depending on the system Simutrans was running on sometimes much too many new trees were generated. - NEW: news ticker - CHANGE: Some smaller optimizations, avoided function calls, about 4% speedup in total for games with many vehicles TIME: 6:30h 11/17/01 - CHANGE: Merged Andreas' changes: - If a new schedule is set, only those goods are removed from a vehicle which cannot reach their destination anymore. Formerly all goods were removed. - CHANGE: Merged Markus' changes: - Ok and Cancel buttons for savegame file chooser. The new savegame chooser looks really cool :) - CHANGE: Merged Volkers changes: - fixed a small flaw in hashtable datatype - new class to load *.tab files, this loader should become standard in future for all *.tab files - new integer hashtable template - new bridgebuilder class which is responsible for building and removing bridges - New bridge types, new bridge building menu - Changes to pointer checking and memory management - CHANGE: Added comments for all methods of the convoi class - FIX: fixed a bug that left copies of the landscape pointer image visible when moving the landscape point uphill or downhill - CHANGE: Sped up routing (pathfinding) of goods, this allows to use larger transport networks - CHANGE: Routing of goods cannot be interrupted anymore this fixes a potential bug in routing, but also may cause a slowdown in really large games. I hope that the optimization of routing will reduce this problem. TIME: 4:30h 11/14/01 - NEW: Merged Markus Webers changes to the Simutrans UI - NEW: Merged Andreas' changes to the SDL system wrapper file - CHANGE: limited 'random map' to 0-999 - CHANGE: system wrapper can now choose between software or hardware cursor. Currently Allegro uses software cursor, SDL and X11 use hardware cursor. TIME: 1:15h 11/13/01 - FIX: fixed a bug in removing railroad tracks, which sneaked in with Andreas' changes - NEW: released unofficial 0.79.4exp TIME: 1:00h 11/12/01 - FIX: fixed a memory leak that sneaked in while optimizing vehicle routing - NEW: released unofficial 0.79.3exp TIME: 1:00h 11/11/01 - CHANGE: STL priority queue can't be used with Mingw32. Using self made priority queue. - FIX: fixed a bug in routing. The bug limited the usable distance of routes for all vehicles, and slowed routing down, especially if ships were routed. - CHANGE: changed routing of goods. It had a similar bug like routing of ships. I hope this change didn't break something. If it works it'll speed up routing of goods in complex networks quite a bit. - CHANGE: added tooltips for all tools of the toolbar - CHANGE: tripled text buffer size for station info. There were problems reported which might be related to a buffer overflow in station info display. New buffer size is 8192 bytes. Mingw32 does not support snprintf(), but with sprintf() I have no idea how to avoid buffer overflows. I just hope 12288 bytes is big enough. - CHANGE: doubled buffer size of convoi info text, too, just to be a bit more save. Now 8192 bytes buffer size. - CHANGE: included Flors updated drive in cinema included Flors general purpose ship included Flors updated furniture factory included Flors updated home market included Flors updated planks truck - CHANGE: included Volkers update: FIX: image calculation of single rail pieces on slopes fixed FIX: some problems with directional bits in rail block manager, simplified some code FIX: fixed problems when removing bridges and tunnels TIME: 6:00h 11/10/01 - FIX: fixed a typo in de.tab - FIX: included Andreas' fix for wrong curves in tracks - FIX: included Andreas' fix to remove trees if land is lowered - CHANGE: switched to STL priority queue for vehicle routing, this should speed routing up for long and complex routes, but is somewhat slower for short routes - CHANGE: optimized vehicle routing, now about 20% faster than before. This allows to use 20% more vehicles than before! Changes due to the switch to the STL priority queue are not included in this measurement. TIME: 3:00h 11/05/01 - CHANGE: included Tristans fixed vehikel.tab with better weight and power values for trucks, busses and ships - CHANGE: changed vehicle info display in road vehicle depot to display power and weight TIME: 0:15h 10/28/01 - CHANGE: changed vehicle routing. Fixed a bug in search for best route. Vehicles should now always find the shortest route. - CHANGE: cities build a stadium at a population of 2500, was formerly 2000. - NEW: cities build a drive in cinema at a population of 1500. - FIX: fixed a wrong entry in en.tab and de.tab ("Verkehrsteilnehmer") TIME: 3:00h 10/27/01 - FIX: removing ground from above tunnels works now - FIX: removing tunnels works now - FIX: removing bridges works now - CHANGE: removing bridges and tunnels no longer places rails on the end squares, but cuts the rails at the end of the former structure - CHANGE: added END markers to depot.tab sections and a check if given vehicle count matches actual vehicle count. - CHANGE: updated thanks.txt - NEW: included Jens wood transport ship TIME: 2:30h 10/21/01 - CHANGE: changes savegame format to load/store animated factories - CHANGE: enlarged scroll range in vehicle and station info windows - NEW: included Flors animated factories - NEW: included Flors new trucks 10/15/01 - NEW: animated factories - CHANGE: better animation support for all buildings 10/12/01 - CHANGE: changed makepak to read PNG images, converted all images to PNG format. 10/08/01 - NEW: added Flors new pause icon. - CHANGE: enlarged scrollable range in vehicle info windows 10/04/01 - FIX: if vehicles are stored in depots and the map was saved and loaded again, Simutrans crashed. This worked in former versions, I don't know why it was broken in between. Nevertheless this is fixed. (calc_bild() of the vehicle checked the ground of the map square which was not yet completely loaded at this moment, and this inconsistency made the game crash. Vehicles call calc_bild() often while moving. Theoretical there is a chance that the image of a vehicle is wrong now directly after loading, but I couldn't find any problems yet. - FIX: if a saved game from a Simutrans with a different vehicle.tab is loaded, some vehicle informations are not available. Formerly this caused a crash while loading the game. Now the information is replaced with 0 values. This has the result that the 'unknown' vehicles do not move (power and weight are set to 0), but the saved game can be loaded and all common vehicles (common in both vehicle.tab files from the saving and loading Simutrans) will work. - NEW: released unofficial 0.79.pre3 10/03/01 - FIX: fixed a buffer overflow in station name creation. - FIX: if the hardware clock is set back while Simutrans runs, the negative time difference is ignored. -> this change limits the time Simutrans can be run without stopping to about 23 days! -> this change saved 4 bytes memory in each goods-destination object both in main memory and saved games - FIX: due to Volkers changes, saved pedestrians didn't move anymore after loading. This is fixed, they move again. - NEW: The '!' key (Shift-1) toggles the display of station and town names. - NEW: The '.' and ',' keys can be used to change the time lapse setting. This is an experimental feature, if you want to be safe, do not use this. 09/30/01 - FIX: removing a building (or tree) sets ground to bare land (was broken due to Volkers changes) - FIX: factory owner is restored when loading a game (was broken due to Volkers changes) - FIX: vehicles are now displayed correctly (uncropped) again. (was broken due to Volkers changes) -> This fix does not work for vehicles on bridges, but since the problem only occurred with ships noticeably I think the fix is 'good enough'. We have no ships on bridges so far. - CHANGE: conserved about 160KB for a standard size map save file -> This change limits the number of players to 127. I guess, this isn't really a restriction. - CHANGE: changed text for "optionen > quit" to "New map", because it opens the new map dialog rather than quitting the program. - CHANGE: changed image for "Please wait, creating a new map" message window - NEW: released unofficial 0.79.pre2 09/29/01 - FIX: fixed a bug in Volker changes to routing; ships move again -> there is still a display problem in the graphics - FIX: if a text input field was active while the containing window is closed, the action bound to the input field is not triggered any more 09/26/01 - Merged Volkers changes -> binary save game format (saves about 30% space, saves and loads much faster, incompatible to previous versions) -> bugfixes for route calculation and object management in world map - FIX: fixed a problem in saving industries with Volkers new code: buildings no. 2 and 3 got mixed during saving - FIX: Volkers changes prohibited removing trees and town buildings It's now again possible to remove trees and houses - NEW: Released semi-official Simutrans version 0.79.pre1 09/23/01 - CHANGE: enabled producing industries to have more than one consumer. - NEW: More than one consumer per producer. This finally overcomes the strict 1:1 relation of producers and consumers and allows more flexibility in the game. - CHANGE: modified buttons of the schedule input window to match the look of most other buttons in Simutrans - FIX: fixed a display problem in train/convoi and station info windows 09/22/01 - CHANGE: instead of enabling all things as synchronous objects only a few are sync steppable now. This change should improve the performance of Simutrans, especially if many vehicles are used. - FIX: fixed a bug in route calculation that could crash the game 09/20/01 - CHANGE: cleaned up vehikel_t class. -> saved 4 bytes per vehicle -> removed two unneeded methods -> moved a method into convoi_t class where it belongs -> reduced number of method calls from convoi_t to vehikel_t during driving by 50%, this should speed up things a bit - FIX: fixed a wrong bounds check which could make the game crash in route_t 09/19/01 - FIX: if a game was loaded and right after loading saved all industry buildings showed up as construction areas forever after loading again. This problem is fixed now. - NEW: added a new industry: furniture factory 09/16/01 - FIX: textinput fields release focus now if the containing window is closed - FIX: it was possible to choose invalid color sets by clicking left or right of the color bars in the color chooser window. This problem is fixed now. - FIX: fixed a bug which crashed the game when a vehicle entered a depot while the vehicle info window was opened The following fixes fix problems introduced with the new tunnel and bridge data structures or were done by Volker who wrote the new data structures and associated code: - FIX: fixed visibility of vehicles entering and leaving tunnels - FIX: fixed visibility of vehicles driving uphill/downhill - FIX: fixed vehicle smoke creation for tunnels - FIX/NEW: Merged Volkers changes: - Fixes to compile Simutrans with MS Visual C++ - Fixed a problem in pipeline/powerline code - Positioning of the relief map works now with big maps, too - Added a replacement for 'opendir()' which is unknown to VC - Removed some printf's from blockmanager code - Optimized access to ground objects - Moved updates of the relief map into ground object class - Fixed an array bounds violation problem in vehicle routing code. This bug was probably very seldom triggered. - Removed unneeded methods from the squares objects - Changed vehicle movement a bit. - Fixed a problem in the bridge building tool 09/09/01 - CHANGE: World display in convoi and station windows fixed - FIX: Industries get a proper list of worker residential cities even after creating a new map. - FIX: Display of desired destinations in city info window fixed 09/08/01 - FIX: Renaming of newly build vehicles works now - BUG: The window title gets translated automatically. If by accident the vehicles new name is included as string in the language file the window title displays the translation for this string instead of the string itself. - NEW: Version stamp for saved games - NEW: Version check and error message when loading saved games - CHANGE: Cleaned up fahrer_t, vehikel_t hierarchies: removed methods which were no longer used after Volkers changes 09/06/01 - NEW: Released semi-official Simutrans version 0.78.12 - CHANGE: updated todo list - CHANGE: mail offices can no longer be build on roads and railroads - CHANGE: maps with invalid rail blocks can be loaded again (added Volkers hack). I'm not sure if this fixes the problem but at least you can load the maps again and try to go on with the game. -> This change is untested because I had no saved maps with invalid rail blocks. 09/04/01 - NEW: A limited file chooser for loading/saving games. Allows to enter names for games, up to 60 characters per game. Does not work on operating systems which have less than 60 chars per filename. This allows to have more than 5 different savegames. -> All existing savegame files need to be renamed to *.sve manually, because the new Simutrans version only detects *.sve files!!! - NEW: Clicking the entries of the vehicle list now opens the vehicle information window of the clicked vehicle. This way you can inspect your vehicle fleet very easily. 08/24/01 - FIX: "Bankrupt" message is displayed if a player is bankrupt (Was hidden due to some other changes in the code) - CHANGE: "You are in dept" messages now tell how many months are left to pay back the money. - CHANGE: updated todo list - NEW: Factories do not deliver goods to stations where more than 1000 units of the same good are already stored. This should support a fair distribution of goods if several routes exist and one route has only a tiny transport capacity. Formerly all routes got the same amount of goods and if the tiny routes transport capacity was below that, immense amounts of goods were piled up at the tiny routes source stop. Now the tiny route is capped once 1000 units are stored on it's stop and the other routes are preferred by the factory. - NEW: Released unofficial version 0.78.11exp 08/23/01 - NEW: new station info and station detail windows -> renaming stations is now possible -> station window now has scrollbars to scroll big goods/passenger lists - CHANGE: heavy workaround to get station name synced with displayed name (due to a design mistake in an earlier stage) - BUG: text input fields keep input focus if window gets closed. 08/22/01 - CHANGE: change convoi info window to use the new UI classes. This cleans up some code and streamlines more of the UI. - NEW: added text input facility for changing convoi name to convoi info window -> this allows to change vehicle names! - NEW: text area component (only used in new convoi window so far) 08/20/01 - FIX: Fixed a bug which crashed the game if a new map was created, then the game was quit and again a new map with more cities was created (caused by deleting the new number of cities instead of the old number). 08/17/01 - CHANGE: included Owens update for the money dialog Negative values are now displayed in red. - CHANGE: adapted a few more dialogs to the rule: unchangeable values -> black changeable/changing values -> white This way the player can see immediately which values are fixed and which are supposed to be changed/changing 07/01/01 - NEW: built a new BeOS release (0.78.10exp) 06/30/01 - NEW: merged Owens finance window update - NEW: (internal) label text can now have other colors than black - CHANGE: to unify the finance window look with existing dialogs all changing entries are displayed in white, all constant entries are displayed in black now 06/23/01 - NEW: assigned click sounds to more actions to give a better feedback to the user 06/22/01 - FIX: sometimes the interrupt routine was called while it was already running. In rare cases this could lead to a double free() of the same object. The second free was likely to crash the game (C++ standard says something about undefined behavior in that case) or do even worse. This is fixed now, the interrupt routine can't be called any more if it is running already. 06/20/01 - NEW: added command line switches -h, -?, -help and --help which all print a help message - NEW: added a few more debug (error and fatal error) messages to loading/saving railroad tracks with invalid rail block IDs. This won't help the player immediately but allows better bug reports. - NEW: added a -screensize option to choose arbitrary resolutions This also allows to run Simutrans windowed in multiple window sizes. - FIX: fixed a problem which crashed the game if a station building had its name set to NULL. This should not happen normally but NULL should be a allowed value for a name string (meaning 'no name'). Now the program should be able to cope with station building names which are NULL. Usually this problem was reported as "The game crashes if I click a station" - CHANGE: found some more printf calls and replaced them by calls to the new logging system. 06/17/01 - CHANGE: Info windows display a bit of the environment, too, now, instead of just the objects square. This required changes to the clipping check in simgraph.c - BUG: new clipping support for graphics isn't perfect. The last line of graphics in the main display is not drawn correctly. In general clipping for images seems to truncate the last line while other drawing functions are fine. Workaround: draw one additional line (this hides the effects). - NEW: finance statistics get loaded/saved. Old savegames can be read; all finance stats are set to 0 when reading old games. - NEW: finance statistics get reset to 0 every year - NEW: Released unofficial version 0.78.8exp 06/16/01 - NEW: Translated Owens finance window entries - NEW: Finished work on vehicle list window - NEW: Painted two icons (finances, vehicles) for the toolbar to open the new finances and vehicle list windows - FIX: Fixed two bugs in the scrollpane class which displayed scrollbars at wrong position if the scrollpane was not located at (0,0) - BUG: Finance statistics/informations are not yet loaded/saved - CHANGE: Increased max speed of private cars 06/15/01 - CHANGE: Merged Owens finance window routines - FIX: Finance window title bar is now displayed in player colors - NEW: Started working on vehicle list window 06/14/01 - NEW: Released official version 0.78.7exp 06/13/01 - NEW: Built official version 0.78.7exp 06/09/01 - FIX: building signals directly adjacent to tunnels/bridges works now. - FIX: removing signals near bridges/tunnels works now. - CHANGE: adjusted station timeout to new timeflow. It's now again 90 days (was less than 1 day) - BUG: The block repair tool does not work if there is a train waiting on a bridge and the block below the bridge shall be repaired. In this case the train on the bridge is counted as if it was on the ground block and the wagon counter of the ground block is set too high. 06/06/01 - FIX: fixed a problem during image calculation in the schiene class which could crash the game during destruction of a map, i.e. if a new game was loaded. 06/02/01 - CHANGE: Changed a lot more printf calls to calls to the new debug/logging class. I hope I have changed all of them! - CHANGE: Changed a suspicious piece of code in window management: if you had 31 or 32 windows open, and closed a window, the program read data behind the window array. This data was copied into the window array. In general there was too much data copied but usually within the window array. I don't know how harmful it is to read from behind arrays, but nevertheless this is fixed now. - CHANGE: Changed another suspicious piece of code in window management: similar to above but executed when a window was topped. - CHANGE: Increased the window array size from 32 to 64 entries, this means up to 64 subwindows can be displayed. - CHANGE: The behavior for "-log" was changed. The output is now written into the 'simu.log' file AND into the console window (was only 'simu.log' before). - CHANGE: Changed default resolution from 640x480 to 80x600. There were never ever problems with higher resolutions reported, so this seems to be fairly safe. - CHANGE: Stations without ground squares have name "Unnamed" until a ground is added to the station. This fixes a possible crash when inquiring stations to early or late. - FIX: fixed a bug which blocked the railway line if a one-way signal was removed. Now it's safe to remove one-way signals, too! 06/01/01 - CHANGE: Changed a lot of printf calls to calls to the new debug/logging class, rated as "Message", "Warning", "Error" and "Fatal error". Fatal error quit the program immediately. 05/27/01 - NEW: Added more error detections to the id_handle template (tombstone id checks). This checks should catch about 50% of all internal data corruption problems. (The other 50% can't be checked because in those cases the result of the corruption is a valid tombstone ID again). - CHANGE: changed "Warning: Convoi was saved in state 4 or 5" to "Message: Convoi was saved in state 4 or 5" because this is not an error, but normal program action. 05/26/01 - CHANGE: Tried to migrate to from Allegro 3.9.32 to Allegro 3.9.36 Compiled and installed new Allegro Library for Windows. -> Supports now DirectX up to version 7.0, hopefully this will save some of the "no suitable graphics driver found" problems. -> 'simuwin -res 5' runs Simutrans in a window nicely now (Windows version only, other versions have window by default) 05/24/01 - CHANGE: Translated debug messages in rail block manager - CHANGE: Loading a map now tells how many factories trains/convois are loaded - CHANGE: Improved id_handle_tpl for better checking if a handle is bound to an object - CHANGE: Adapted automatic tests for tombstone checking - CHANGE: Cleaned up code in rail block and rail block manager classes - CHANGE: Stations are now using handles and tombstones, too - CHANGE: Translated a few more messages from the tools 05/23/01 - NEW: Tombstone/id_handle templates allows to check for dangling pointer in all classes retrofitted with tomstone tables - CHANGE: Retrofitted rail block class with tombstone table - CHANGE: Split rail block classes and rail block management code into two files ------------------------------------------------------------------ Made a break to gather my thoughts and find new solutions for some problems with Simutrans. ------------------------------------------------------------------ 04/22/01 - NEW: Map preview in map selection window (new game window) - NEW: Included Tilli's new vehicle setup routines for smoother starting of vehicles. - CHANGE: relief map look changed 04/21/01 - CHANGE: Text input fields have a cursor now, changed handling of input focus a bit - CHANGE: rearranged ground and road images to allow multiple sets of ground images - FIX: renaming cities from loaded games works now 04/19/01 - NEW: Text input fields - CHANGE: City info window uses text input field 04/14/01 - FIX: found an array bounds violation in simgraph.c in a text drawing routine. This caused random crashes and other strange behavior if text was drawn half-outside the screen. - FIX: found an array bounds violation in simgraph.c in another text drawing routine. Nearly as evil as the bug mentioned above. - FIX: fixed an array bounds violation in simsound.cc If no sound card was detected the first MIDI title read from music.tab was read into midi_titles[-1] and overwrote an helper array of the AI. This made the game crash when the AI was using the values from this array. 04/13/01 - FIX: removing one of those smoke-clouds crashed the game. This is fixed now. This bug could be triggered either by using the 'remover' tool or by building something on squares which contained clouds. - CHECK: it was reported that removing rails or roads and thus breaking a vehicles route would crash the game. This could not be reproduced. - CHANGE: included new en.tab, fi.tab, fr.tab and es.tab (language files) 04/11/01 - FIX: fixed a bug which aborted the game if empty spaces in the depot were clicked while being in sell mode - FIX: midi playlist displays message "Musicplaying disabled/not available" if either no MIDI files could be loaded or if the soundcard could not be initialized successfully - FIX: Song name in playlist is updated if a new song starts playing 04/09/01 - Merged Owens new sound routines: a simple MIDI playlist UI for browsing the MIDI files forward and backward. - CHANGE: Unified look of playlist UI with other Simutrans UI 04/08/01 - Released 0.78.0 04/07/01 - CHANGE: en.tab and de.tab updated, included corrections from Seth and Dirk. - CHANGE: included new hungarian language file - CHANGE: translated a few more debug/info messages from german to english. - FIX: included Tilli's tree placement fix. 04/04/01 - FIX: clicking an empty entry in the engines area of a depot window no longer aborts the game. This bug was introduced during the changes in 0.77.6 when a bounds checked array was introduced as container for engines ... a failed bounds check aborted the game in this case. 04/01/01 - CHANGE: AI build trains of different length now - CHANGE: AI uses different engine types now - FIX: AI no longer buys trailers without trucks 03/31/01 - NEW: New industry: Bookshop (painted by Tuomas, tiled by me) - NEW: New vehicle: Book van (painted by Sergiu, modified by me) - NEW: New good: Books - NEW: New private car (painted by Dirk, recolored by me) - CHANGE: included new powerlines from Daniel - CHANGE: included new transformer station from Daniel - CHANGE: Doubled the running cost for all locos, they were smaller than the average truck running cost before. Now running costs for train engines are higher than truck running costs in average. - CHANGE: Raised the capacity of all trucks by 10-30%. Trucks should be able to compete (at least sometimes) with trains. - CHANGE: Power station has now upto three suppliers (was two formerly). I hope this is enough to produce electric energy more continuously. 03/28/01 - CHANGE: compiled a new Linux test version with a different setup of libraries (left out all DGA libs in Allegro setup). The new version runs on a wider range of Linux systems now. 03/23/01 - CHANGE: Cleanups for new map window, sets scroll positions to actual map coordinates when opening a new map window. - CHANGE: Text drawing routines can now choose from two fixed width fonts and one proportional font. - CHANGE: The image of the power connectors at power stations was changed to a grey power line segment. - CHANGE: Linux version can now be built with Allegro, sound and music works, mouse is self-managed as in windows fullscreen mode: - NEW: Sound effect for income/expenditure. 03/22/01 - NEW: Powerlines. Power stations get power connectors. The player can place transformer stations near other industries and connect power stations power connectors and the transformer stations with powerlines. Hotkeys: 'g' to place a transformer station 'l' to build a powerline - NEW: A 4x7 font, used in relief map to display town names. Small and hard to read. - CHANGE: Event handling during scrolling changed. Now the frame_time is no longer changed during dragging the map. This should prevent some possible problems (passenger rate) with a ridiculous fast looping main loop (which was the result of a map drag before). - CHANGE: Fixed width font drawing routines clip correctly now. 03/21/01 - CHANGE: Goods/destination objects changed from heap allocation to stack allocation and to value variables instead of pointers. The former solution (heap/pointers) was always a source of problems. The new implementation should be more robust against several error types (dangling pointers!). It's probably not more correct than before, but allows to keep playing even if an error occurred. This solution needs to copy more memory (16/24 bytes instead of four for each assignment but saves one indirection on each value access and saves calls to new/delete. All in all it seems to be roughly as fast as before (no measurable difference). I think, it's even faster now. - CHANGE: Changed event queue indices in simsys_d.c to unsigned types. They were always checked for higher bound, but not for lower bound. Making them unsigned prevents the occurrence of negative values, and a higher bound check is now sufficient to ensure values of valid range. Similar to the change above, this might not be more correct than before but it should be more robust against errors than before. - CHANGE: Changed a few more lists to list templates to gain type safe interfaces. Should allow better error checking by the compiler. - CHANGE: Changed memory allocation scheme of map squares. They prefer to keep memory instead of freeing it. They just free memory if they have space for more than 32 objects but contain less than 8 objects. In other cases they keep the allocated space. This reduces the number of calls to new/delete and should therefore speed up the program, but it might use up to four times more memory than before (couldn't verify this, the game needed 12 megs to play a 256x256 map before and still needs less than 13 megs for a 256x256 map). 03/20/01 - FIX: Fixed a bugs which destroyed the freelist of the node_container_t by accident. Cause was a freelist=0 in the constructor of the node_container while freelist is a static member and should not be nulled in the constructor.result was a memory leak. - CHANGE: Allow putback of node lists in node_container_t. This reduces the number of calls to new and delete and should be more efficient. It simplifies code and moved two implementations to a single source, thus enhancing maintainability. The queue_t and Stack classes benefit from this feature. - FIX: Fixed a memory leak in sound_frame_t. Sliders and labels are now data fields of the class instead allocated separately on the heap. This way they are automatically freed if the frame is deleted. - CHANGE: Updated two of my houses, adjusted window sizes and wall colors. Added a lamp (lit at night) to one of the houses. 03/19/01 - CHANGE: Some memory management changes started: - reduced number of calls to new/delete by reusing node objects (nodes are used in all linked data containers and are allocated/deallocated very frequently - changed HNode and KNode (goods routing and vehicle routing) memory management to use freelists. 03/18/01 - CHANGE: Image updates from Trikky and Oskari included - CHANGE: Mouse pointer no longer visible during loading, saving and while creating a new map. This prevents the 'footsteps' problem. 03/17/01 - CHANGE: Relative volumes of music/sound adjusted. - CHANGE: Sound volume has a wider adjustment range now. 03/15/01 - CHANGE: included Ricks updated images - FIX: Event handling problem in options dialog fixed, this fixes also event problems in the new savegame slot dialog. This also makes the buttons real 'pressable', not just 'touchable' as before. 03/14/01 - NEW: MIDI playing routines by Owen Rudge integrated - NEW: MIDI volume selector to sound control added - FIX: Saving games with Shift-S works again - CHANGE: Mouse position update changed, last change had a bug introduced 03/10/01 - NEW: A very simple savegame chooser. Allows to select one of five savegame slots for loading and saving a game - FIX: Fixed a bug in convoi (train) loading code. There was a little chance that convois (trains) were saved in an inconsistent state. This fix recovers the convoi state during loading the game. - CHANGE: added a new interface class for listening for button press events to the gui class hierarchy - CHANGE: tried to enhance timer precision from 5 ms to 2 ms (Only Windows version, other versions already had a precision of 1 ms); - CHANGE: replaced one of Trikkys buildings with an updated version - CHANGE: included steam loco sound - CHANGE: improved mouse pointer movement (only Windows version). 03/08/01 - CHANGE: idle_time now drops until below 50µs - CHANGE: passengers are routed in groups of up to 7 - CHANGE: passengers are appalled by crowded stations in groups of 8 (was 4 before) - CHANGE: passengers are appalled by not finding a route in groups of 4 (was 1 before) - CHANGE: tried to optimize haltestelle_t::suche_route() 03/05/01 - CHANGE: cities step only every fourth row per step (was every second row before) - CHANGE: buildings creates twice as much passengers as before to make up for the slower step frequency 03/04/01 - NEW: Sound control window (only volume control so far) - NEW: Label component for UI - CHANGE: Sped up display_img by another 3% with a tip from Frans - CHANGE: Included Frans in intro scroller and thanks.txt - FIX: If an animated building was renewed the animation count was not set correctly and a wrong image was displayed for some time. This is fixed now. - CHANGE: map window display maps <= 256x256 squares without scrolling, bigger maps are displayed in a scrollable window of 250x250 pixels in size. (Currently the scrollbars are just inactive during the display of smaller maps). - FIX: X-Windows: Exposure-event wird jetzt richtig verarbeitet 03/03/01 - NEW: Scrollpane class (scrolling canvas for UI components) - NEW: Container class for UI components - NEW: Frame class for UI components - CHANGE: Maximum map size is now 576x576 squares - CHANGE: Relief map got scrollbars 03/01/01 - CHANGE: A new private car - CHANGE: Improved some images (city buildings) 02/28/01 - CHANGE: Optimized the assembler routines even further with tips from Frans. Gained another 6-10% in speed. 02/24/01 - CHANGE: Large cities call INT_CHECK more frequently now. This makes vehicles movement smoother. - CHANGE: Passengers are routed in groups of three if possible, this enhances overall performance in games with big cities. - CHANGE: Drawing routines rewritten in assembly language, now at least 15% faster than before. - CHANGE: Route building for AI cleans up datastructures after route calculation. - CHANGE: Changed the AI and road/railroadbuilding code to reduce the 'stalls' in vehicle movement. 02/18/01 - FIX: 'waddling' trains fixed (by Till) - FIX: The pause mode is working correctly now Press 'p' to pause the game - CHANGE: Tree placement improved (by Till) - FIX: Cities no longer destroy bridges when building things below them - FIX: It's no longer possible to remove depots while there are vehicles in them - FIX: Off screen sounds are now muted (clipped) correctly even in higher screen resolutions - CHANGE: Sounds which are farther away are less loud than sounds from near things. - CHANGE: If an existing schedule is opened for editing, the default action should not be 'remove'. Now 'select' is the default action. 02/11/01 - CHANGE: Closing a tool window reverts the selected tool to the information tool. - FIX: Day/night switch on title screen works now. 01/28/01 - CHANGE: If there is no train/convoi yet, and a new engine is bought, a new train/convoi is automatically created and the engine is added. - FIX: VELO in en.tab changed to DIBU 01/24/01 - FIX: Clipping rectangle bug fixed 01/21/01 - FIX: Railway stations can't be built on level crossings anymore - FIX: TPDIesel entry corrected in de.tab/en.tab - CHANGE: included Dirks/Manfreds new de.tab 01/18/01 - FIX: There was a bug in the calculation of the direction of a newly built bus stop 01/14/01 - CHANGE: memory management for goods changed to list based management - CHANGE: included Oskaris new images - CHANGE: added Sounds for ship depot/harbour building tools - CHANGE: Cities build stadiums when they reach 2000 inhabitants - NEW: Basic support for animated buildings - FIX: The landscape pointer is only redrawn if really needed (shape changed or moved). This should save some percent of CPU time if the pointer isn't moved. 01/12/01 - FIX: level crossings can't be built on slopes anymore - FIX: bus stops can't be placed on level crossings anymore 01/10/01 - FIX: a bug in rail track display code (displayed end of lines under signals) - FIX: windows get events, even if the last mouse click was outside the window 01/07/01 - Added tools to create level crossings; this tool adds rails to roads. Together with the former level crossing tool, this gives a general purpose level crossing building tool. - Added infrastructure to bind sounds to tool selection and execution - Fixed bus-stop bug 01/05/01 - Added tools to create level crossings; this tool adds roads to railroads. This means you always need to build railroad tracks first. - Added icons for tool, a landscape pointer for tool and images for the crossings itself 01/04/01 - Changing the program to use the new ground and way classes - Ran some tests to see if the new ground classes work well 01/03/01 - Preparing the program for level crossings and combined traffic -> introduced a new class hierarchy for ground and way types which supersedes the old class hierarchy. 29.12.00 - Merge mit Niels Sourcen - Brücken und Tunnelwerkzeuge in Strassen- und Schienenbaufenster verschoben 28.12.00 - NEU: Tab-Panels für Depot-Fenster 24.12.00 - FIX: Falls Schienebau fehlgeschlagen wurde als Fallback Strasse gebaut ohne zu prüfen ob für die Waren überhaupt Strassenfahrzeuge verfügbar sind - CHANGE: Waren haben Koordinaten statt Koordinaten-Zeigern für die Ziele. Das behebt das Problem der mehrfachen Freigabe gleicher Koordinaten - CHANGE/FIX: Laden von Planquadraten ermittelt max_index jetzt anders. Das sollte das Problem max_index >= capacity beheben. Ist nach der Änderung nicht merh aufgetreten Ein assert() prüft diese Bedingung in der Debug-Version. 20.12.00 - CHANGE: Städte erzeugen beim renovieren keine neuen Gebaeude-Objecte sondern updaten die alten. Das behebt ein Speicherloch. 17.12.00 - CHANGE: GUI: Buttonlisten auf Vector-Template umgestellt - CHANGE: Fahrplan mit 0 Stops führt nicht mehr zum Absturz - CHANGE: Fahrplan benutzt jetzt auch array_tpl 16.12.00 - CHANGE: Beschleunigung wird jetzt aus dem Fahrzeuggewicht errechnet - CHANGE: Anheben von Wasser mit Konvertierung zu Land ist jetzt möglich - CHANGE: Endverbraucher (Fabriken) können jetzt in Städten platziert werden. - FIX: obj_ist_da() stürtze ab, wenn gar kein Objekt auf diesem Feld vorhanden war 10.12.00 - CHANGE: Ribi von Stadtstraßen werden jetzt richtig gesetzt - NEU: Kosten für Bau und Abriß von Tunnels und Brücken werden verrechnet - NEU: Gewicht und Leistung pro Convoi werden jetzt ermittelt 09.12.00 - NEU: Testfälle für Objektverwaltung im Planquadrat - FIX: "Überbauen" von nicht-entfernbaren Dingen ist jetzt nicht mehr möglich - CHANGE: Staedte steppen nur jede zweite Zeile, erzeugen dabei aber pro Gebaeude doppelt so viele Passagiere. Das sollte Rechenzeit sparen. 08.12.00 - CHANGE: Planquadrate haben dynamische Objektverwaltung und koennen bis zu 2^15 Objekte verwalten. 06.12.00 - CHANGE: diagonales Scrolling per Keyboard ist jetzt möglich - CHANGE: daten.pak enthält jetzt die Anzahl der gespeicherten Bilder - CHANGE: Städte bauen Stadien jetzt erst bei 1050 Einwohnern 05.12.00 - FIX: setRGB8multi wieder benutzt, ist bei Merge mit Niels sourcen am 30.11.00 entfallen 02.12.00 - FIX: 'done' Button im Fahrplan-Dialog öffnet nicht mehr das Infofenster eines darunterliegenden Objekts - CHANGE: Warteschleife fuer Wartezeiten von weniger als 1 ms - Freispielmodus eingebaut, ergänzt Testmodus - Pasis verbessertes Stadtinfo-Fenster eingebaut 30.11.00 - Merge mit Niels sourcen 29.11.00 - Hotkey q,x zu Q,X geändert - Hotkey t für Schienenbau - CHANGE: karte_t::destroy loescht alle Blocktrecken - CHANGE: 'max. 10/60 Passagiere' zu '10/60 Passagiere' geändert 27.11.00 Suche nach Fehler, der die Grafikstörungen hervorrufen könnte 2 Stunden erfolglos gesucht 26.11.00 - GUI um Tag und Nacht Modus an-/abzuschalten - FIX: Kennfarbe des Spielers wird bei Nacht richtig gespeichert/geladen 25.11.00 - weitere Arbeiten an Tag&Nacht Modus - CHANGE: mehr Lichter bei Nacht - FIX: Kennfarbe des Spielers bleibt bei Nacht erhalten 23.11.00 - weitere Arbeiten an Tag&Nacht Modus 22.11.00 - setRGB8multi fuer effizienteren Farbwechsel - mehr INT_CHECKS fuer besseres Fahrzeugfahren 20.11.00 - Merge mit Niels sourcen 19.11.00 - Tag-und-Nacht-Modus 16.11.00 - FIX: Fahrpläne haben jetzt Speicher für 16 Einträge - Merge mit Niels sourcen - FIX: Ricks Fabrik ist 599 statt 699 - Ricks toolbar 15.11.00 - einige casts durch dynamic_cast ersetzt - Vehikelbauer ist auf den vehbesch typen basiert statt auf tabellen. - KI prüft die Verfügbarkeit von Fahrzeugen vor dem Streckenbau - Abschluss der Industriekonfiguration, Einbau der Autofabrik 13.11.00 - slist_tpl: Typsicheres List-Template 12.11.00 - industry.tab fertig - Waren/Industrien sind jetzt frei konfigurierbar 11.11.00 - NEU: industry.tab (begonnen) 09.11.00 - NEU: Warendaten werden aus Datei gelesen, warenbauer als Factory-Klasse für Waren 08.11.00 - NEU: Pause-Funktion - NEU: Anzeige fuer Fracht in 'aktuell/maximal' 03.11.00 - NEU: eigene, einheitliche Random-Funktion, Plattformunabhängig - NEU: Reliefkarte "draggable" - NEU: Window wird bei Klick in Window-Koerper getoppt. 02.11.00 - NEU: Beschraenkungen fuer Fahrzeugkombinationen - FIX: Fahrzeuge auf Bruecken/Tunel werden jetzt von pruefer_ob_strecke_frei richtig gezaehlt - FIX: block_ersetzer behandelt Bruecken/Tunnel jetzt richtig - FIX: Signale entfernen funktioniert jetzt 01.11.00 - Window-Close Button wird richtig gedrueckt 31.10.00 - Repeat Buttons 30.10.00 - Merge abgeschlossen 29.10.00 - Merge mit Niels sourcen 28.10.00 - FIX: Umbau des GUI auf Komponenten 24.10.00 - FIX: Rückbau des Speichermanagements für gebäude_t - FIX: Einfahren in Bahnhof prüft jetzt auf Schienen - CHANGE: intro scroller text 23.10.00 - FIX: Anpassung Fenstergroesse an 11er LINESPACE - FIX: Zuege fahren über Bruecken statt untendurch - FIX: free_entries in memblock_t wurde nicht init, das ist jetzt behoben - CHANGE: Änderung im Speichermanagement für Gebäude 19.10.00 - NEU: Fenster können mit DEL und Backspace geschlossen werden - NEU: Wegpunkte werden mit Koordinaten aufgelistet - CHANGE: Textabstand auf 11 Zeilen erhöht - CHANGE: "Cr" wurde in creditszeichen umgeschrieben - CHANGE: Betriebskosten werden jetzt aus vehikel.tab gelesen und pro feld verrechnet. - FIX: Beim Entfernen eines Bahnhofs wird ein Schienenende wieder zu einem Schienenende 16.10.00 - FIX: beim Einfügen von Koordinaten in eine Route wurden die Hoehen nicht mit verschoben. Jetzt werden Hoehen von 0 eingefuegt - NEU: Scrolling per Tastatur 15.10.00 - NEU: Blickpunkt wird mit Karte gespeichert - NEU: neue Option "zeige passagiere" - NEU: Soundwerte in vehikel.tab und vehbesch.cc - NEU: Option -log schreibt logfile - NEU: Fortschrittanzeige beim Laden/Speichern und neuen Spiel 14.10.00 - CHANGE: neues memory management, wird von koord und sync_wolke_t benutzt, da diese Klassen sehr haeufig instanziiert und geloescht werden. 12.10.00 - FIX: Schienen über Schienen legen funktioniert jetzt richtig, Blockstrecken bleiben an den Signalen getrennt - Test geschrieben - FIX: Depots entfernen funktioniert jetzt richtig, im ersten Schritt wird das depot entfernt, im zweiten die Schiene - Test geschrieben - CHANGE: stepgruppen von 7 auf 14 hochgesetzt - CHANGE: Wasser stept jetzt jedesmal - CHANGE: Baeume steppen jedesmal und berechnen das Alter richtig, Baeume saemen an insgesamt drei tagen im Baumleben 08.10.00 - NEU: Sound-API begonnen 07.10.00 - FIX: Kontostand ist jetzt 64 bit Wert (long long) 05.10.00 - FIX: Post kann nur auf leerem Feld gebaut werden - FIX: besserer Text für Intro-Scroller 04.10.00 - NEU: Intro-Scroller 03.10.00 - FIX: routing um Faktor 35 beschleunigt - FIX: Kennfarbe wird gespeichert und geladen - NEU: Staedte bauen Stadien - TEST: Fussgaenger 30.09.00 - Züge halten in T-förmigen Bahnhöfen jetzt richtig - FIX: Routing von Waren zur Zielfabrik verbessert: statt entfernung halt->basis zu Fabrik wird jetzt die Fabrikliste der Haltestelle zu rate gezogen um zu sehen ob die ware abgeliefert werden kann. 27.09.00 - Automatische Tests für das Schienenverlegen begonnen - Testsuite ausgelagert 23.09.00 - simworld.cfg speichert einstellungen: Sprache 20.09.00 - Neues fr.tab integriert 19.09.00 - "delete void * considered harmful": der destructor wird nicht aufgerufen. Deswegen slist.delete_all entfernt und ersetzt. 17.09.00 - NEU: vector klasse und array template 16.09.00 - NEU: Testsuite begonnen 08.09.00 - FIX: bei Truecolor wird das Bild nach einer Änderung der Palette neu gezeichnet. 04.09.00 - FIX: Welt wird nach laden komplett neu gezeichnet - CHANGE: auflaufen der hinteren Waggons bei Halt vermieden - CHANGE: Züge klemmen nicht mehr nach halt in kurve, allerdings stimmt das setup nach dem Halt nicht mehr bis der Zug in einen Kopfbahnhof einfährt. - CHANGE: Fahrplan-UI selekiert add-mode oder remove, je nachdem ob der Fahrplan leer ist oder nicht 01.09.00 - Ungelöst: Haltestellen (docks?) um Ölfelder herum können nur geladen werden, wenn sie Spieler 0 gehören. Gehören sie Spieler 1 dann stürtzt das Programm beim zweiten Ladeversuch ab. - FIX: Züge mit mehr als 4 Waggons routen jetzt auch in Durchgangbahnhöfen richtig 31.08.00 - NEU: Oelfelder funktionieren jetzt - FIX: verteile_waren bedient meherer Haltetsellen jetzt richtig, hatte zuvor n-mal die Ware verteilt - FIX: uninit. Zeiger in simfab.cc behoben 30.08.00 - FIX: Verkehr fährt jetzt richtig über Hügel und Senken - CHANGE: Verkehr behindert Automobile 29.08.00 - FIX: Tunnel und Brückenbau funktioniert wieder - FIX: zwei möglicherweise uninit. zeiger in simplay.cc behoben. 28.08.00 - FIX: Bounds check bei raise_to/lower_to war falsch 24.08.00 - NEU: Anzeige der Mauskoordinaten (int Kartenkoordinaten) - CHANGE: Stadtnamen sind jetzt eindeutig. 23.08.00 - CHANGE: Auslagerung Depotdaten in "depot.tab" 20.08.00 - CHANGE: Auslagerung Gebaeudebeschreibungen in "gebaeude.tab" - FIX: X-Windows+dirty rectangle list jetzt auch in 16/32 bit - FIX: Redraw der Iconleiste nur wenn nötig - FIX: Kennfarbenumschaltung zeichnet ganzes Bild neu 19.08.00 - NEU: Altersangabe für Fahrzeuge - CHANGE: vehikel_t etwas überarbeitet - CHANGE: Berechnung von Restwert für verkaufte Fahrzeuge (ca. 70% nach erstem Jahr) 17.08.00 - FIX: Gebäudeindex für Gebeudearrays der Stadt wird in renoviere richtig geclipped - FIX: bug aus fahre() entfernt, der durch die Koordinatenumstellung verursacht worden war, eigentlich ein tippfehler - NEU: Vehikel können im Depot verkauft werden 16.08.00 - dirty rectangle list vervollständigt - FIX: maximal 8 Loks und 32 Fahrzeuge können in einem Dept eingelagert werden. 14.08.00 - dirty rectangle list weitergebaut 13.08.00 - dirty rectangle list weitergebaut - viele Umstrukturierungen - koords wo es sinn macht - einige vereinheitlichengen bei schreibweisen (setze) 12.08.00 - dirty rectangle list begonnen 09.08.00 - CHANGE: Züge fahren jetzt immer bis zum Bahnsteigende 07.08.00 - FIX: Stadt baut Gebäude nur auf Feldern ohne Besitzer. 04.06.00 - 32 Farben in der Palette sind jetzt zusätzlich verfügbar - GUI für farben aus simgui getrennt und nach gui verschoben 02.08.00 - generisches Makepak für alle Plattformen - Doppelte Info-Fenster für Haltestellen abgeschaltet 30.07.00 - FIX: Beim Trennen einer Ringstrecke wird jetzt die Blockbelegung richtig ermittelt 29.07.00 - Bugfixes - Riffe für unbefahrbares Wasser 26.07.00 - Abschliessende Arbeiten am Fahrplandialog - Einbau von Olufs Fähre 24.07.00 - Weitere Arbeit am Fahrplandialog - CHANGE: Fahrzeuge haben keinen eigenen Fahrplan mehr nur noch Zeiger auf den Convoi-Fahrplan - CHANGE: anderes Design für Fenstertitelleisten 23.07.00 - Weitere Arbeit am Fahrplandialog - Weitere Anpassungen für SDL - CHANGE: Statusanzeigende Buttons werden jetzt gedrückt dargestellt - CHNAGE: erweitertes event-handling für Info-Fenster 20.07.00 - Beginn Fahrplandialog (Fenster, Anzeige Fahrplan) 19.07.00 - Anpassungen für SDL (BeOS) 16.07.00 - FIX: start von convois mit nur einem Fahrzeug funktioniert wieder - CHANGE/FIX: Passagiererzeugungsrate pro stadt ist jetzt von der Stadtanzahl unabhängig, liegt bei ca. 1/4 der vorherigen Passagiererzeugungsrate; das limitiert jedoch die Stadtanzahl auf 64 Staedte insgesamt. 15.07.00 - FIX: Beim Absenken auf Wasserniveau werden alle Objekte des Planquadrates gelöscht 12.07.00 - CHANGE: Neues Gras - FIX: verbessertes/effizienteres clipping fuer display_img 09.07.00 - FIX: Softzeiger hinterlaesst keine Abdruecke mehr auf der Iconleiste - CHANGE: Gewinn wird jetzt nach route(max_n)-route(0) berechnet - FIX: Fahrplaene fuer Trabantenfahrzeuge werden vom Erstfahrzeug uebernommen 08.07.00 - Screenshot feature - FIX: Unzerreisbare Züge 06.07.00 - FIX: Verbesserung der Landschaftzeigerpositionierung vor allem bessere Platzierung des Signalzeigers - FIX: Wenn das Infofenster eines Fahrzeugs offen ist und man das Fahrzeug in ein Depot schickt erfolgt kein Absturz mehr - FIX: Signale entfernen nochmals korrigiert - FIX: Schienen entfernen nochmals korrigiert 05.07.00 - Fehlersuche in der Blockstreckenverwaltung - FIX: Bahnhoefe koennen nur auf eigenen Schienen gebaut werden 03.07.00 - FIX: laden kleinerer Karten jetzt möglich - CHANGE: Signale werden jetzt immer paarweise entfernt - Eddies Korrekturen zur en.tab eingefügt 29.06.00 - FIX: Entfernen von Privatfahrzeugen verboten - FIX: Depotnamen werden wieder i18n - Ricks engl. Stadtnamen eingebaut 28.06.00 - Finnische Übersetzung eingebaut - Sprachnamen stehen jetzt als 1. Zeile in den Sprachfiles 24.06.00 - FIX: Laden und Speichern des Warenziels, Erzeugung einer Warenzielkopie bei Teilen eines Warenpaketes - FIX: Waggons bekommen hat_fracht_bild wieder gesetzt, war Fehler im Vehikelbauer, fracht.is_empty() wird bei waggons richtig berücksichtigt. - FIX: Reliefkarte: Klick in die unteren 16 Zeilen funktioniert jetzt wieder - FIX: Lieferung von Waren mit Eingangsindex != 0 and Fabriken funktioniert jetzt wieder. - FIX: Baeume und Wolken rufen kein delete im step() auf. Das delete wird jetzt vom Planquadrat übernommen 23.06.00 - Passagiererzeugung in Fabriken - Passagiererzeugung in Staedten beruecksichtigt Fabriken - Passagiererzeugung in Staedten beruecksichtigt Ausflugsziele - Passagiererzeugung in Ausflugszielen - FIX: Kohlekraftwerk hatte ausgang[0] nicht allokiert - FIX: Warenendziel kann von Warenziel(Haltestelle) unterschiedlich sein, Vereinheitlichung verursachte Fehler im Routing. - FIX: Postgebaeude auf Fundament konnten den Boden nicht als Haltestellenboden setzten. Verzicht auf Fundament. 22.06.00 - FIX: Stadnamen internationalisiert - FIX: Haltestellennamen internationalisiert - neuer Fenstertyp w_info_autosize 21.06.00 - FIX: Bei der Teilung von Waren an Haltestellen werden die Zielkoordinaten der neuen Ware neu erzeugt - Speicherlöcher im Warenrouting behoben - Auslieferung von Waren an Fabriken funktioniert wieder 20.06.00 - Routing für Passagiere und waren funktioniert im Prinzip - CHANGE: altes, quotenbasiertes Passagiersammeln wurde aus dem Programm entfernt - Verdacht auf Speicherlöcher im Warenrouting - Erzeugung von Waren mit Zielen funktioniert jetzt im Prinzip 19.06.00 - Passagiererzeugung in den Städten begonnen - Stadtinfo-Fenster begonnen 18.06.00 - Ziele für Waren und Passagiere - Neue GUI-Hierarchie - CHANGE: Map-Window wurde zu einer eigenen Klasse 17.06.00 - Ziele für Waren und Passagiere, Ziellisten für Haltestellen - CHANGE: Haltestelleninfofenster werden über Boden geöffnet 15.06.00 - Interface comparable_t fuer ADT Menge - FIX: Plastiktransporter transportiert jetzt auch Plastik 14.06.00 - ADT "Menge" begonnen - CHANGE: Boden hat jetzt pointer auf Haltestellen - CHANGE: Haltestellen werden jetzt über Boden gesucht und gefunden - FIX: Boden hat virtuellen Destruktor, der Boden von Haltestelle abmeldet. 13.06.00 - FIX: Windows-Version laden/speichern funktioniert jetzt - Neues Statdgebaeude: Kirche 11.06.00 - Schiffe, Schiffsrouten - Tests und Bugfixes für Schiffe - FIX: laden der Fahrzeugtabelle lädt letztes Fahrzeug richtig - FIX: statt aussteigender Passagiere fahren die mitgefahrenen Pax 10.06.00 - Auslagerung der Fahrzeugdaten für alle Fahrzeugtypen vereinheitlicht - Bilder für Schiffsdepots + Zeiger - Schiffdepotwerkzeug - Schiffdepots - Schiffe (ungetestet) - Performanceoptimierungen in der Grafik 08.06.00 - Auslagerung der Fahrzeugdaten fertig - Bilder für Schiffsdepots begonnen 07.06.00 - Auslagerung der Fahrzeugdaten in vehikel.tab begonnen 04.06.00 - Erste Docks (Bilder + Werkzeug) 01.06.00 - FIX: top_win implementiert - Werkzeugwaehler Fenster 28.05.00 - Erste Version mit winallegro Einige Anpassungen an Windows-Spezifika - FIX: INT_CHECK wird in step jetzt nur noch alle 1024 planquadrate aufgerufen - step() von boden wird nur gerufen, wenn der boden will_step gesetzt hat 25.05.00 - FIX: Signale melden sich beim entfernen immer bei der Block- strecke ab. - Zugbilder um je 2 Pixel verbreitert, Depots angepasst 25.05.00 - Neue Diesellokomotive 22.05.00 - Lagerhaeuser zur Zwischenlagerung von Waren. 19.05.00 - Umstellung der Blockstrecken von Zug auf Wagenzählung macht Blockstreckenmanagement robuster - Info-Fenster der Signale zeigen jetzt die Blockbelegung an 17.05.00 - FIX: Brücken und Tunnels sind wieder befahrbar - Erzanhänger (für LKW) fertig 13.05.00 - FIX: Bug bei Entfernen von Brücken/Tunnels entfernt - FIX: Entfernen von Dingen ist wieder möglich 12.05.00 - FIX: Fahrzeuge fahren nicht mehr ueber Wiesen, falls der Verkehrsweg zwischendurch entfernt worden ist. - FIX: Verkehrsteilnehmer werden nur noch auf geraden Strassen erzeugt - FIX: Karte ist nach Start auf einer Stadt zentriert - Manfreds Denkmal eingebaut 11.05.00 - Baeume ueberarbeitet - Einige Haeuser ueberarbeitet - Erzbergwerk ueberarbeitet 10.05.00 - Alternative Landschaftserzeugung mit "Perlin Noise" 08.05.00 - Manfreds Staubkesselwaggon eingebaut - Autofabrik verbraucht jetzt Kunststoff - Fabrikfenster führt max. Prod jetzt separat auf 30.04.00 - Convois haben jetzt Zaehler fuer Jahresgewinn 29.04.00 - FIX: Schienentunnel/-bruecken entfernen funktioniert jetzt 24.04.00 - FIX: erstes/letztes wird bei Einlagerung in Depot geloescht - FIX: Halt mit/ohne beladen verhaelt sich jetzt gleich -> Zuege fahren vollstaendig in Bahnhoefe ein 23.04.00 - FIX: sync_steppable hat virtuellen destruktor - FIX: Depots ermitteln Fahrzeugnummern besser ??.04.00 - Umstellung DOS Version auf Allegro - Umstellung DOS Version auf DJGPP 2.03 18.04.00 - FIX: Land anheben/absenken unter Brücken ist verboten - FIX: es laesst sich nur noch ein kartenfenster oeffnen - FIX: Schienen unter Bruecken bauen laesst Bruecken intakt - FIX: moegliche Fehlerquellen beim Verbinden von Blockstrecken und beim Bau von Signalen in Ringstrecken korigiert 15.04.00 - FIX: delta_t bei asynchronem step wird jetzt richtig berechnet - FIX: int route.cc INT_CHECK Aufrufe eingefügt -> weniger ruckeln - CHANGE: markierungen von grund_t in karte_t verlegt - CHANGE: step steppt nur noch jedes 15. Objekt pro Durchlauf - CHANGE: step in grund_t wieder virtuell, ohne if 14.04.00 - FIX: laden und speichern von beliebig grossen Karten moeglich - Einstellung fuer Scrollgeschwindigkeit - Einstellung fuer Verkehrdichte 13.04.00 - FIX: display_img clipped jetzt oben wieder richtig - FIX: verkehrsteilnehmer_r "springen" nicht mehr - Vorbereitung "welt gui" zur interaktiven kartenwahl - Einstellungsobjekte für Spieleinstellungen 12.04.00 - Umbau des fabrikbauer_t fuer sinnvolle Platzierung der Industrien - kleine optimierung in display_img und display_color_img 09.04.00 - Umbau von vehikel_t zur Ableitung einer Klasse fuer den Individualverkehr 06.04.00 - Vorbereitungen fuer waehlbare Kartengroessen - Speichereinsparungen am Blockmanager (Markierungen als char statt bool) 05.04.00 - Speichereinsparungen an ding_t und grund_t (ca. 30%) 02.04.00 - Fahrzeuge werden auf der Reliefkarte angezeigt 01.04.00 - Umbau Fahrplaneingabe auf Werkzeugschnittstelle - KIs ebnen Land und entfernen Hindernisse beim Bahnhofsbau - FIX: Bahnhof entfernen setzt Blockstrecken richtig - FIX: Trennen von Blockstrecken verbessert - FIX: Fabriknamen werden sprachunabhängig gespeichert - FIX: Karte huepft nicht mehr bei erneutem Scrollen - FIX: KI orientiert sich am Lagerbestand bei Streckenplanung - FIX: "Gekaufte" Felder koennen nicht in der Hoehe veraendert werden 26.03.00 - Kunststoff- und Stahl-LKWs eingebaut - Manfred's Stahltransporter eingebaut - FIX: Convois werden aus Convoiliste entfernt, wenn sie ein Depot betreten - FIX: Gebeude koennen jetzt auch null-Texte speichern - FIX: Signale umstellen kostet kein Geld 25.03.00 - FIX: Tunnelmündungen erhalten richtigen Blockstreckenzeiger - FIX: Brueckenauffahrten erhalten richtigen Blockstreckenzeiger 22.03.00 - Verbesserte Grafikperformnce 30-40% schneller - Bessere Komprimierung des Daten.pak 21.03.00 - FIX: Zeiger laden funktioniert jetzt 19.03.00 - FIX: Signale aufstellen wird besser geprueft - FIX: KI berechnet gewinn jetzt richtig 18.03.00 - Helligkeits und Farbeinstellungen werden jetzt gespeichert - FIX: Brückenbau nur an Strassen/Schienenenden zugelassen - FIX: Fehlermeldung "... muss an einfachem Hang ..." uebersetzt - FIX: Zeiger fuer Brueckenbau stimmen jetzt - GUI fuer Laden, Speichern und Beenden - FIX: Kosten fuer Baeume faellen und Haeuser abreißen werden jetzt berechnet 17.03.00 - Neue Blockstreckenverwaltung abgeschlossen - Sehenswuerdigkeiten begonnen 13.03.00 - Mauszeiger Kann nun auch auf Linien plaziert werden Das ist für die neue Signalsetzfunktion notwendig - Ricks Korrekturen der en.tab integriert 12.03.00 - Blockstreckenverwaltung neu implementiert (Beginn) 11.03.00 - FIX: KI-Zustand wird gespeichert - Mehrere Farbpaletten zur Auswahl - Mehrere Helligkeitstufen zur Auswahl - FIX: Haltestelleninfo mit vielen Fabriken funktioniert jetzt - FIX: Fenster werden immer vollständig sichtbar geoeffnet 09.03.00 - FIX: Bahnhofsgrund verarbeitet ribis jetzt korrekt 04.03.00 - X-Windows: Pointer beim Scrollen unsichtbar - FIX: Entfernen fremder Strassen/Schienen nicht mehr moeglich - Fahrzeuge können in Depots zurückgeschickt werden - Hausbeschreibungen begonnen 28.02.00 - Verhindern mehrfacher Fahrplaneingabe. 27.02.00 - Anklicken des Bildes im Infofenster springt zum Objekt 26.02.00 - Französiche Übersetzung integriert - Ricks Bauwerke integriert - Fabriken haben jetzt info über abgegebene warenmenge - KI nutzt Warenabgabeinfo zur Streckenplanung - X-Windows version kann Pointer beim Scrollen im Window fixieren 21.02.00 - Bugfixes fuer KI -> tonnenweise Bugfixes!!! 20.02.00 - Baubaer kann jetzt lokale Optimierungen an Strecken vornehmen 19.02.00 - KI baut Strassen und Schienen automatisch - KI baut Bahnhöfe und Frachthöfe - Bugfixes fuer Schienenbau und Strassenbau - Bugfixes fuer Tunnel und Brueckenbau - Bugfix fuer zu viele sync_wolken 16.02.00 - Automatischer Brueckenbau fuer Baubaer funktioniert - KI schätzt Anzahl benötigter Fahrzeuge fuer Route 15.02.00 - Automatische Strassenueberbrueckung bei Schienenbau beggonnen 14.02.00 - Automatische Strassentunnelung bei Schienenbau begonnen 13.02.00 - Gebaeudenamen werden mit gespeichert - Bushaltestellen sind jetzt wg. Sichtbarkeit zweigeteilt - Frachthoefe sind jetzt wg. Sichtbarkeit zweigeteilt - Verbesserte Bilddarstellung im Infofenster - Verbesserung der KI; Strassenfahrzeuge werden 'sinnvoll' eingesetzt 12.02.00 - Pipelines prinzipiell fertig - Automobile fahren jetzt hintereinander - Automobile halten jetzt an belegten Kreuzungen 10.02.00 - Pipelines begonnen - Refactoring von simdings in Paket dings 09.02.00 - Entfernen von Strassenbruecken moeglich - Entfernen von Eisenbahnbruecken vorbereitet - Iconleiste wird nur gezeichnet wenn nötig (Performance +) 05.02.00 - Raffinerien - Maximalhoehe fuer Berge - Anzeige des sichtbaren Bereiches in der Reliefkarte - Fabriken: Produktion vom Lagerbestand abhängig - Masseinheiten fuer Waren - asynchrones Routing fuer convois - Reliefkarte zeigt sichtbaren Ausschnitt an - Neuer Bus 04.02.00 - Manfreds Oeltanker eingebaut - Raffinerien angefangen 30.01.00 - Grafiken überarbeitet - Neue timer-routinen beruecksichtigen wirklich verbrauchte zeit. - Strassen in den Staedten mit Gehweg - Kosten fuer Fahrzeuge werden verrechnet 29.01.00 - weitere i18n - makepak tool von simu getrennt - tooltips für Icons - Oelfeld - Synchrone Altersberechnung für Baeume und Gebaeude - Tabellen statt switch fuer Baeume und Vehikel 28.01.00 - FIX: Brücken "ins nichts" bauen stürtzt nicht mehr ab - Fenster aus Hauptfenster herausschiebbar 23.01.00 - Weitere i18n - Convoi fahren jetzt nach halt an Signal langsam an - aktuelle Sprache wird gespeichert 22.01.00 - "Neuer Fahrplan" Funktion für Convois - Erste Schritte zur Internationalisierung 20.01.00 - Overlay-Technik für Strassen und Schienen implementiert 19.01.00 - Fenster können automatisch nach Zeitspanne geschlosen werden 15.01.00 - FIX: Schienen über Schienen bauen kostet kein Geld - FIX: Schienen über Schienen bauen entfernt Züge nicht mehr - FIX: A* war fehlerhaft - Automatischer Brückenbau möglich - Darstellung von Schienen in der Reliefkarte verbessert - Makefile verbessert - Route ist jetzt eigenes Objekt, d.h. Routing ohne Fahrzeuge wird möglich - Passagiere steigen nicht mehr alle gleichzeitig aus, statistisch steigen bei n Haltestellen K/(n-1) Passagiere pro Haltestelle aus. - Haltestellenquote bezieht nun Anzahl wartender Pax/Post mit ein - FIX: Name der Fabriken weren jetzt gespeichert/geladen 14.01.00 - Verbesserungen im Stadtbau - FIX: Strassenbau in den Staedten erzeugt keine Phantomabzweigungen mehr - FIX: Richtige Positionierung der "Schwebetexte" - Wolken werden jetzt synchron entfernt 13.01.00 - Tunnels fertig - Convois bei "Halt ohne umdrehen" verbessert - Neue Diesellokomotive 10.01.00 - Tunnels; die Bilder für die Tunnelmündungen fehlen noch 08.01.00 - FIX: Laden/Speichern von Convois macht anz_ready persistent - SList für synchrone Objekte, damit beliebig viele sync. Obj. mgl. - Wolken als synchrone Objekte - FIX: Start-Button im Depot; Groesse wurde falsch berechnet - FIX: Frachtbildinformation wird jetzt gespeichert - Fehlermeldungen und Reaktion auf "OUT OF MEMORY" - Fehlermeldungen für Laden/Speichern 06.01.00 - Informationen für Fahrzeuge - Depotfenster überarbeitet 05.01.00 - Baugruben für Neubaus - FIX: Kennfarbe und Zeit speichern und laden - FIX: Rauchberechnung in Convoi, Zeitabhängig statt Geschwindigkeit - FIX: trennen von Ringstrecken jetzt moeglich 04.01.00 - Stahlwerk - Kohlebergwerk - FIX: Name von Haltestellen im Info-Fenster richtig - FIX: Frachtbild-Flag wird jetzt bei Fahrzeugen richtig gespeichert - Erzlaster - Dieselrauch fuer Dieselfahrzeuge 03.01.00 - Beschleunigung der Zeichenfunktionen - Animiertes Wasser - FIX: Lokomotive mit Fracht - FIX: Haltestellenkonstruktor - Wartezeitberechnung für Hauptschleife als PI-Regler 29.12.99 - Neues Bahnhofsdach - Depotinhalt wird gespeichert - Update der Reliefkarte nach laden - Neuer Haltestellenzeiger - Beschleunigung/Bremsen für Convois 25.12.99 - Neue Dampflokomotive - Erweiterungen für Laden/Speichern 23.12.99 - Erweiterungen für Laden/Speichern 18.12.99 - Neue Hierarchie für Depots (Bahndepot, Straßendepot) - Neue Hierarchie für Fahrpläne (Bahn, Auto) - Bugfixes für Vehikel, Convoi mit nur einem Vehikel - neues Verzeichnis dataobj 17.12.99 - Blockstrecken mit Brücken funktionieren jetzt (hoffentlich) evtl. Probleme mit Blockstrecken die mittels Brücke über sich selbst hinwegführen - Überarbeitung Brückenbau - Bugfixes für Vehikel beim Übefahren einer Brücke - Tests mit assert() - Berechnung der korrekten Kosten bei Landanheben/-absenken 16.12.99 - Haltestellen entfernen ist jetzt möglich - einige Sicherheitschecks eingebaut - Schatten für Bäume und Häuser 14.12.99 - Erstmals präzise Positionierung des Landschaftszeigers möglich 09.12.99 - asynchrone darstellung möglich - neue Image-Verwaltung ermöglicht kompakteres daten.pak 08.12.99 - Haltestellen mit SList für Grund und Fabriken, damit entfallen die Beschränkungen auf 16 Felder bzw. 16 Fabriken - Verbesserung von move_win durch offset zum Mauszeiger - Kleine Verschönerungen an Gebaeude-Bildchen 05.12.99 - Fahrzeuge mit variablen Geschwindigkeiten - Abbiegen mit nur einem Fahrzeug in der Kurve 04.12.99 - Verbessertes Clipping für Zeichenfunktionen - Verbesserte Window-Darstellung - Verbesserte Schilder-Darstellung - Softscrolling 03.12.99 - Convoi als Vehikel-Delegate 02.12.99 - Verbesserung convoi_t::ready() - Bahndepot 28.11.99 - Erster Versuch eines Dialoges für Zugzusammenstellung 27.11.99 - Algorithmus von Dijkstra zum Strassen/Schienenbau implementiert - Neue Gebaeude: Einkaufszentrum und Fabrik 5 - Automatisches Update der Reliefkarte 24.11.99 - Entfernen von Schienenenden möglich 22.11.99 - Entfernen von Signalen möglich - Entfernen von Scheinenstücken aus der Mitte von Blockstrecken ist möglich 21.11.99 - Shared Memory abschaltbar, neue Kommandozeile: "-net" schaltet Shared Memory ab "-map 34" startet karte 34 - Unterstützung für XWindows 24/32 Bit Farbtiefe (experimentell) - Unterstutzung für XWindows 16 Bit (565, 555) (experimentell) - Dialog für Wahl der Spielerfarben - FIX: Traversierung der Blockstrecken betritt jetzt nur Felder mit Schienen 20.11.99 - FIX: Signale rechts von den Schienen - FIX: Frachthof in Spielerfarbe - FIX: Convoi "ist_fahrend" init - FIX: Posthäuschen und Industrie werden beim Satdbau nicht mehr entfernt - FIX: Symbole in Iconleiste erscheinen jetzt in Spielerfarbe 16.11.99 - Weichen für Schienen 14.11.99 - Bugfix für Suche nach draw.fnt - Bugfix für fehlende "HOME" Umgebungsvariable - Bilder für Erzbergwerke vollständig - Buttons für Infofenster, es fehlt noch der Callback - Trennen/Vereinigen von befahrenen Blockstrecken jetzt möglich - Bugfixes für Blockstreckenverwaltung 13.11.99 - Alternative Push-Technologie als Ersatz für SIGNAL verfügbar - Strassenbau für Städte verbessert - neue größere und besser erkennbare Icons - verbesserte Werkzeuge für den Bau von Bahnhöfen, Bushaltestellen und Frachthöfen: automatische Richtungserkennung 06.11.99 - Blockstrecken jetzt auch für Convois (Züge) 03.11.99 - Bugfixes für Blockstrecken, alle Tests erfolgreich durchlaufen 02.11.99 - Einfach- und Doppelsignale - Bugfixes für Blockstrecken und Signalverwaltung 01.11.99 - Erste Blockstreckenverwaltung und Signale 09.09.99 - Simu jetzt unabhängig von draw - Simu 16 Bit-faehig 02.06.99 - Bild fuer Rathaus - Erzeugen und Verbrauchen von Waren in Fabriken funktioniert jetzt 31.05.99 - Anpassung Haltestellen an neue Waren - Neue Haltestelle Frachthof (n,s,w,o) - Bruecken jetzt auch mit Zug befahrbar 30.05.99 - Parametrisierbare Fabriken statt Klassenhierarchie - Fabrikbauer - Fahrzeugbauer 29.05.99 - Erste Industrie: Nutzwald und Saegewerk - Transportfahrzeug (LKW) fuer Holz 28.05.99 - Breitensuche statt Tiefensuche fuer Fahrwegsbestimmung (neue ADT Queue und Stack) ??? - Bruecken befahrbar 08.05.99 - Brueckenbau moeglich, aber Bruecken noch nicht befahrbar. neues bild "bridges.gif" fuer Tunnel und Brueckenbildchen 01.05.99 - simwin: Mausklick wirkt nur noch auf oberstes Fenster an dieser postion - Einfuehrung eines ADT SList fur bessere Kontrolle der Zugriffe und ohne Groessenbeschraenkung 15.04.99 - Bilder fuer Post, Postzeiger, Postlkw und Postlkwzeiger - neuer Warentyp: Post - grundlegendes Werkzeug wkz_postlinie - Bugfixes fuer vehikel_t beladen() beachtet jetzt warentyp speichern/laden existieren, aber nicht getestet - neue funktion fuer automobil_t set_has_fracht_bild() fuer Fahrzeuge ohne beladene Bilder 10.04.99 - display_img und display_color_img pruefen jetzt xmin < xmax und ymin < ymax (verursacht Abstuerze unter DOS) 02.04.99 - welt->lock sperrt jetzt events; notwendig fuer DOS-version - display_clear() eingespart, welt ist jetzt insel 20.03.99 - Passagierwaggon - korr. Bahnhof Ostwest - Verzicht auf rein virtuelle Methoden -> defensive Programmierung - Bugfix in kann_alle_entfernen(): beachtet jetzt Spieler - Frachthof neu 13.03.99 - Bessere Namensgebung fuer Haltestellen - Busse/Passagiere - Bushaltestelle - Bugfix Fenster verschieben - Passagiererzeugung 10.03.99 - Icons fuer Bahnhof Nordsued und Ostwest - Mauszeiger Bahnhof Nordsued und Ostwest - Grundlegende Namensvergabe fuer Bahnhoefe ("Boberg Bahnhof") - FIX: Stadtpositionen werden jetzt initialisiert - Grundlegendes Konzept fuer Bahnhofsbau: Module Problem bei Luecke -> neuer Bahnhof angenommen 07.03.99 - Icons fuer Raise, Lower, Abfrage und Remover - Mauszeiger: Abfrage, Remover - Eigene Datei fuer alle Werkzeuge -> Kapselung - Aenderung an der KI, aber Streckenplanung immer noch mangelhaft 06.03.99 - Neue Mauszeiger: Strassenbau, Schienenbau, Raise, Lower - Bessere Mauszeigerpositionierung - Icons fuer Reliefkarte, Strassenbau und Schienenbau written by Hj. Malthaner simutrans-124.3/simutrans/license.txt000066400000000000000000000156221474050137200177710ustar00rootroot00000000000000This is the simutrans source code. (c) 1997-2004 Hj. Malthaner (c) since 2005 The Simutrans Team Simutrans source code is provided by the current simutrans team (team64@simutrans.com) as copyright holder under the artistic license. This includes the translations from: https://translator.simutrans.com/ the documentation, images and .dat files included in the source distribution, the midi files and the fonts with the exception of the m+10r.bdf, which is taken from the M+ font project: https://mplus-fonts.osdn.jp/ ----------------------------------------------------------------------------- Third Party Libraries When downloading Simutrans, additional third party libraries may be included for compatibility purposes in the "lib" directory. Such files are not covered by the Artistic License. The list of included libraries and a link to their license text is listed below. libFLAC https://raw.githubusercontent.com/xiph/flac/master/COPYING.Xiph libbz2 http://sourceware.org/git/?p=bzip2.git;a=blob_plain;f=LICENSE;hb=HEAD libfluidsynth https://raw.githubusercontent.com/FluidSynth/fluidsynth/master/LICENSE libfreetype https://raw.githubusercontent.com/aseprite/freetype2/master/docs/LICENSE.TXT libglib https://raw.githubusercontent.com/GNOME/glib/main/COPYING libminiupnpc https://raw.githubusercontent.com/miniupnp/miniupnp/master/LICENSE libogg https://raw.githubusercontent.com/gcp/libogg/master/COPYING libpcre https://raw.githubusercontent.com/vmg/libpcre/master/LICENCE libpng https://sourceforge.net/p/libpng/code/ci/master/tree/LICENSE?format=raw libsndfile https://raw.githubusercontent.com/libsndfile/libsndfile/master/COPYING libvorbis-{enc} https://raw.githubusercontent.com/xiph/vorbis/master/COPYING libzstd https://raw.githubusercontent.com/facebook/zstd/dev/COPYING ----------------------------------------------------------------------------- The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: * "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. * "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. * "Copyright Holder" is whoever is named in the copyright or copyrights for the package. * "You" is you, if you're thinking about copying or distributing this Package. * "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) * "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End --------------------------------------------------------------------------- This means, translated to ebay terms: You may not charge for the program, if you charge shipping fees. simutrans-124.3/simutrans/license_squirrel.txt000066400000000000000000000021621474050137200217120ustar00rootroot00000000000000Copyright (c) 2003-2017 Alberto Demichelis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------- END OF COPYRIGHT simutrans-124.3/simutrans/music/000077500000000000000000000000001474050137200167205ustar00rootroot00000000000000simutrans-124.3/simutrans/music/01-Simutrans-Main-Theme.mid000066400000000000000000000630621474050137200235470ustar00rootroot00000000000000MThd`MTrkeÿCopyright (C)2006 shunterð~ ÷ÿJAZ2ÿ 2006.10.06ÿQ¡ ÿÿ/MTrk¦ÿ%shunter 2006 ÀÿJAZ2ÿ(My Song ÿ Simutrans AÿGeneral MIDIÿ @H° !dÿ/MTrk!ÀÿJAZ2ÿchord° "ÿchordÿ @°cÿGeneral MIDI`° @@E+<+@+*E<@<+@+E+*@<EE+<+@+*<E@@+E+<+*<°E@@@ @@EFC+>+;+*>C;>+;+C+*>C;C+;+>+*>C;;+C+>+*°C@ @>@;C>FA+<+E+*<EA<+E+A+*A<E<+E+A+*<EAE+<+A+*°E@ @E<A°A@F@+;+D+*D;@@+D+;+*D@;;+@+D+*;@D@+;+D+*°D@@@ @;@DFE+<+@+*<E@E+@+<+*<E@E+<+@+*<E@E+@+<+*E@<° @@@E@FE+>+B+*B>EB+>+E+*BE>>+E+B+*>EBE+>+B+*EB° @>°B@E@FE+>+B+*B>E>+B+E+*>BEB+>+E+*B>EB+>+E+*>°B@B° @E@EFB+>+E+*>BEB+E+>+*EB>B+>+E+*BE>E+>+B+*°B@B>E°E@ @F@+C+<+*@C<C+@+<+*C<@C+<+@+*<@C<+@+C+*@C<° @@@C@FC+@+<+*<C@@+C+<+*C@<C+@+<+*@<CC+<+@+*C° @C@<@°@@F@+;+D+*@;D;+@+D+*@;D;+D+@+*@D;D+;+@+*;@D° @@@D@F;+@+D+*;@D@+D+;+*D@;;+D+@+*D;@@+;+D+*°@@D°D@ @;@FD+@+;+*;D@D+;+@+*@;D;+@+D+*D;@D+;+@+*@D°@@;°D@ @FD+@+;+*@D;@+D+;+*;D@;+D+@+*;D@;+D+@+*@°@@ @D@D;FA+E+<+*E<AA+<+E+*<AE<+E+A+*<EA<+E+A+*°E@ @A@AE<FE+<+A+*<EAA+<+E+*<EAE+<+A+*EA<<+E+A+*EA<° @A@E@E+<+A+*AE<<+E+A+*<EAA+E+<+*E<A6<+A+E+*A<E<+E+A+*<EA<+E+A+*AE<0° @A@E@E+<+A+*<AEA+E+<+*E<A<+A+E+*<AE6<+E+A+*AE<E+<+A+*A<E<+A+E+*A<E0°E@A@ @;+>+C+*;>C;+>+C+*>C;C+>+;+*>;C6C+>+;+*>;CC+>+;+*>C;>+C+;+*>;C0°>@C@ @>+;+C+*>C;;+C+>+*;C>C+>+;+*>;C6;+C+>+*;C>>+;+C+*C;>;+C+>+*;C>0° @>@C@>+;+C+*;C>C+>+;+*>C;>+;+C+*>C;6;+C+>+*;C>;+>+C+*C>;>+C+;+*C;>0°>@ @C@;+C+>+*C;>C+;+>+*C>;C+;+>+*C;>6C+>+;+*>C;>+C+;+*>C;;+C+>+*>;C0°>@C@ @F@+=+E+*@=E@+=+E+*=@E=+E+@+*@E==+E+@+*°@@=@E°E@ @F@+=+E+*@=EE+=+@+*E=@=+@+E+*@E=E+=+@+*@=E° @E@@@FE+@+=+*@E=@+E+=+*E@=@+E+=+*@=EE+@+=+*=E@°@@E@ @FE+=+@+*@=E@+=+E+*@E==+@+E+*=@EE+=+@+*=@° @E°@@E@FE+B+>+*B>EE+>+B+*>BEB+E+>+*>EBE+B+>+*>°E@B@ @BEFB+>+E+*EB>B+E+>+*EB>B+E+>+*E>BB+>+E+*°E@>°B@B° @EFB+>+E+*B>E>+B+E+*B>E>+E+B+*E>BE+B+>+*E>° @E@B°B@FB+E+>+*>EBB+E+>+*E>B>+B+E+*BE>B+>+E+*>BE° @B@E@FC+<+@+*<C@<+C+@+*@C<@+<+C+*@C<C+<+@+*<@C°C@ @@@F<+C+@+*@<C<+C+@+*@<CC+@+<+*C@<<+C+@+*° @C@<°@@@CFC+@+<+*@C<<+C+@+*@<CC+@+<+*<C@C+<+@+*°@@C@ @C<@F@+C+<+*@C<C+@+<+*C<@C+<+@+*@C<@+C+<+*° @@@C@C@<F@+<+E+*E@<<+E+@+*E@<<+@+E+*<@E<+@+E+*°@@ @E@<@EF;+C+>+*;C>;+C+>+*>;C;+>+C+*C>;C+;+>+*°>@C@ @;C>FE+<+A+*<AEA+E+<+*AE<<+E+A+*AE<<+A+E+*<E°A@E@A° @F@+D+;+*;D@D+@+;+*;@D;+@+D+*@;D@+;+D+*;@D°D@ @@@F@+E+<+*@E<E+@+<+*@E<@+<+E+*E@<<+@+E+*°E@@E<° @@@FE+B+>+*BE>>+E+B+*>EBB+E+>+*E>BE+>+B+*°E@B>° @B@EF>+B+E+*E>BB+>+E+*BE>>+E+B+*B>EE+>+B+*E>B°E@ @B@FE+B+>+*EB>>+B+E+*BE>E+B+>+*BE>>+E+B+*E°B@ @>°E@BF<+@+C+*<C@@+C+<+*<@CC+@+<+*@C<<+@+C+*@° @@@C<°C@FC+@+<+*C@<<+@+C+*<@C@+C+<+*@<C@+C+<+*@° @C<°C@@@F;+@+D+*D@;;+D+@+*D@;@+;+D+*@;D@+;+D+*;@° @@@D°D@F@+;+D+*D@;;+D+@+*@;DD+;+@+*@D;D+;+@+*°@@ @D@;D@F@+;+D+*;@DD+;+@+*;D@;+D+@+*@;D@+D+;+*D°@@@;° @D@FD+@+;+*D@;;+@+D+*;@D;+@+D+*;@D;+D+@+*°D@@@@;D° @F<+A+E+*EA<A+<+E+*EA<E+<+A+*<AEE+<+A+*EA<°E@ @A@F<+A+E+*E<AE+<+A+*<EAA+E+<+*A<E<+A+E+*°E@A@<EA° @E+A+<+*<AEA+E+<+*E<AE+A+<+*<EA6<+A+E+*E<AE+A+<+*EA<A+<+E+*<EA0°E@ @A@<+A+E+*EA<E+A+<+*<AE<+E+A+*E<A6A+E+<+*EA<E+<+A+*<EA<+A+E+*A<E0°A@ @E@>+C+;+*C;>C+>+;+*>C;;+C+>+*>;C6;+C+>+*>;C>+C+;+*;>CC+;+>+*;>C0°C@>@ @;+C+>+*;C>>+C+;+*>C;C+>+;+*C>;6C+;+>+*C>;;+>+C+*>;CC+>+;+*C>;0°C@ @>@C+;+>+*C>;;+C+>+*>C;C+;+>+*;C>6C+;+>+*>;C;+C+>+*;C>;+>+C+*>C;0°C@>@ @C+;+>+*;C>;+>+C+*;C>>+;+C+*C>;6>+C+;+*;C>>+;+C+*C>;C+;+>+*;>C0°C@>@ @FE+=+@+*@=E@+=+E+*@E=E+=+@+*@=E=+@+E+*E=°E@ @@@@F@+E+=+*E@==+@+E+*=E@=+@+E+*E@=E+@+=+*=E@° @E@@@FE+=+@+*E=@E+@+=+*@=EE+=+@+*E=@E+=+@+*E°E@ @@@=@F@+=+E+*=@E@+=+E+*=E@@+E+=+*E@=@+E+=+*°E@@@ @E=@F>+E+B+*BE>E+>+B+*B>EB+>+E+*B>E>+B+E+*° @EB>°B@E@FE+B+>+*EB>B+>+E+*>BEB+>+E+*EB>B+E+>+*>° @B°B@E@EFE+B+>+*B>EB+E+>+*EB>E+>+B+*>EBE+B+>+*° @E@EB°B@>FE+>+B+*E>B>+E+B+*>BE>+E+B+*>BEB+>+E+*°B@ @E@BE>FC+<+@+*@<C@+C+<+*<C@<+@+C+*C@<C+<+@+*°C@ @<@C°@@F<+@+C+*@C<<+C+@+*@<C<+@+C+*<C@<+C+@+*C°C@ @@@<@F<+@+C+*@C<C+<+@+*<@C@+<+C+*C<@@+<+C+*°@@C@@<C° @F@+<+C+*@<CC+@+<+*<C@<+@+C+*C@<C+@+<+*°@@<@C° @C@F<+E+A+*EA<E+A+<+*A<E<+E+A+*<EA<+A+E+*°A@E@ @<AEF<+A+E+*AE<<+E+A+*AE<A+E+<+*E<AA+E+<+*<AE° @A@E@FE+A+<+*<EAE+A+<+*A<E<+A+E+*A<EE+<+A+*<°A@ @E@EAFE+<+A+*AE<<+A+E+*EA<<+E+A+*A<EE+A+<+*<E°E@A@ @AF<+C+@+*C@<C+<+@+*@C<C+<+@+*C<@C(<(@(*C@° @@@C@<F@<C*<@CC@<*@<CC < @ *@<C<C@*°@@@°C@ @<CFC;>*>;C>;C*;C>>C;*>C;>;C*;>° @>@C°C@F;C>*>;C>;C*;C>C>;*C>;>C;*C>;ÿ/MTrk h´Ä0ÿJAZ2ÿ @ÿGeneral MIDIÿAm´ jÿlead´`”H*HE(EL*LJ*JH*Ä0”HJ(JG(GÄ0”M(MM*MO*OM*ML*LÄ0”P(PL(LÄ0”QTQ P*PQ*QP*PQ*QPÿDM*”PQ*Ä0”QQTQ P*PN*NJ(Ä0”JJ(JITI JTJÄ0 ”B‚PÄ0”B0H*HC*CE*EG*GH*HC*CEÿEm*”EG*GÄ0”@(@C(Ä0”CP(PP*PS*SQ*QP*Ä0”PS‚PÄ”S0L*LNNPPLTL L*LNNPPLÿEMT”LÄ ”S~SQ*QPPQQPPNNLTÄ”L HTH HTH H*HF*FE*EC*CÄ”ETE ETE E*EC*CA*A@*@Ä0”H|H$F*FE*Ä0”EFTF ETE C`ÿGMH”CÄ0”JJHHGGCCJJHHGGCCJJHHGGCCJÿGM”JHHGGCCÄ0”JJHHGGCCJJHHGGCCJJHHGGCCJÿEm7”JHHGGCÄ0”CS*ST*TV*VX*XV*VT*TS*ST*TÄ0”S*SQ*QO*OQ*QS(SÄ0”LTL PTP QTQ P*PL*LÄ0”Q‚PÄ”Q0Q|Q$P*PQ*QÄ”S(SUTU STSÄ ”JJIIJ~JJJEEGGEEBBEEG*Ä”GE‚ ÿDM0Ä”E0J*JN*NQ*QJ*JN*NQ*QJ*JN*Ä”NLTL ITI J(JÄ”H*HT*TS*SQ*QO*OQ*QOÿCM*”OM*MÄ”L*LM*ML*LJ*JH(Ä0”HH(HGTG HTHÄ0 ”@‚P@Ä00”Q*QL*LM*MO*OL(LÄ0”O~OM*MJ(Ä0”JM(MM*MO*OM*ML*LÄ0”P(PL(LÄ0”QTQ P*PQ*QP*PQ*QPÿDM*”PQ*QÄ0”QTQ P*PN*NJ(JÄ0”J(JITI JTÄ0”J B‚PBÄ00”L(LL*LJJLLM*MQ*Ä0”QO~OM*ML(Ä0”LS*SQ*QPTP Q~QP*PÄ0”L‚PÄ”L0L(LL*LKKLLNNPPNNLÄ”LP(PP*PNNPPÿFdim”QQSSQQPPÄ”M*MOOQQMTM M*MOOQQÿFM”MTMÄ ”T~TR*RQQRRQQOOMÿFMT”MÄ0 ”MTM E*EF*FH(HÄ0”JTJ H*HF*FE`ÿGMHÄ0”EO*OS*SV*VO*OS*SV*VO*OS*SÄ0”QTQ NTN O(OÄ0”J(JJJGGHHJJH*HG*GÄ0”C~CB*BC`ÿAMH”CÄ0”ITI LTL Q(Ä0”QPTP NTN L(Ä”LQTQ S*SU*UV*VU*USÿAM*”SQ*Ä”QX*XV*VU*US*SQ(QÄ”Q~QJTJ L*LN*NO*Ä”OQ‚PÄ”Q0J*JQ*QJTJ J*JQ*QÿA7”JTJÄ ”V*VUUSSQ*QO*ON*NL*LÿGM”JTJÄ ”H*HT*TS*SQ*QO*OQ*QOÿCM*”OM*MÄ”L*LM*ML*LJ*JH(HÄ0”H*HG*GH*HG*GH(HÄ0”<‚PÄ0”<0M*MO*OQ*QM*MO*OQ*QÿFM”M*MT*Ä0”TY~YR*RQ`ÿDm7HÄ0”QMMLLJJHHE|EÄ0$”ETE ETE C*CA0ÿCMN”AÄ0”L*LM*MO*OHÿCM”HH|*Ä0”HLx*LMt*MOp*OTlÿD7”TT\*TÄ0”JX*JOT*ONP*NOL*OQH*QOD*ON@*NL<*Ä0”LJ8‚PJÿ/MTrk€µÅ ÿJAZ2ÿbaseÿ @µ[ ZÿGeneral MIDI`•-Pµ @*•--P*-4P*4-PT- 4P*4-P*-4P*4Å µ @•7P*77P*7>P*>7PT7 >P*>7P*7>P*>µ @Å •)P*))P*)0P*0)PT) 0P*0)P*)0P*Å •0µ @•4P*44P*4;P*;4PT4 ;P*;4P*4;P*;µ @Å •-P*--P*-4P*4-PT- 4P*4-P*-4P*µ @Å •42P*22P*29P*92PT2 9P*92P*29P*Å µ @•9&P*&&P*&-P*-&PT& -P*-&P*&-P*µ @Å •-&P*&&P*&-P*-&PT& -P*-&P*&-P*Å µ @•-$P*$$P*$+P*+$PT$ +P*+$P*$+P*Å µ @•+$P*$$P*$+P*+$PT$ +P*+$P*$+P*Å •+µ @•(P*((P*(/P*/(PT( /P*/(P*(/P*Å µ @•/(P*((P*(/P*/(PT( /P*/(P*(/P*Å •/µ @•(P*((P*(/P*/4PT4 8P*84P*4/P*/µ @Å •(P*((P*(/P*/4PT4 8P*84P*4/P*/µ @Å •)P*))P*)0P*05PT5 9P*95P*50P*0µ @Å •)P*))P*)0P*05PT5 9P*95P*50P*Å •0µ @•)P*))P*)0P*00P*05P*55P*50P*00P*0µ @Å •)P*))P*)0P*00P*05P*55P*50P*00P*0Å µ @•+P*++P*+2P*22P*27P*77P*72P*22P*Å •2µ @•+P*++P*+2P*22P*27P*77P*72P*22P*µ @•2Å •+P*++P*+2P*22P*27P*77P*72P*22P*Å •2µ @•+P*++P*+2P*22P*27P*77P*72P*22P*Å •2µ @•-P*--P*-4P*4-PT- 4P*4-P*-4P*Å •4µ @•-P*--P*-4P*4-PT- 4P*4-P*-4P*µ @Å •4-P*--P*-4P*4-PT- 4P*4-P*-4P*4µ @Å •-P*--P*-4P*4-PT- 4P*4-P*-4P*4µ @Å •&P*&&P*&-P*-&PT& -P*-&P*&-P*Å µ @•-&P*&&P*&-P*-&PT& -P*-&P*&-P*µ @•-Å •&P*&&P*&-P*-&PT& -P*-&P*&-P*µ @Å •-&P*&&P*&-P*-&PT& -P*-&P*&-P*µ @Å •-$P*$$P*$+P*+$PT$ +P*+$P*$+P*µ @•+Å •$P*$$P*$+P*+$PT$ +P*+$P*$+P*Å µ @•+$P*$$P*$+P*+$PT$ +P*+$P*$+P*+µ @Å •$P*$$P*$+P*+$PT$ +P*+$P*$+P*µ @Å •+-P*--P*-4P*4-PT- 4P*4-P*-4P*4Å µ @•7P*77P*7>P*>7PT7 >P*>7P*7>P*>Å µ @•)P*))P*)0P*0)PT) 0P*0)P*)0P*0Å µ @•4P*44P*4;P*;4PT4 ;P*;4P*4;P*Å µ @•;-P*--P*-4P*4-PT- 4P*4-P*-4P*µ @Å •42P*22P*29P*92PT2 9P*92P*29P*µ @•9Å •&P*&&P*&-P*-&PT& -P*-&P*&-P*-µ @Å •&P*&&P*&-P*-&PT& -P*-&P*&-P*Å µ @•-$P*$$P*$+P*+$PT$ +P*+$P*$+P*+µ @Å •$P*$$P*$+P*+$PT$ +P*+$P*$+P*+µ @Å •(P*((P*(/P*/(PT( /P*/(P*(/P*/µ @Å •(P*((P*(/P*/(PT( /P*/(P*(/P*µ @Å •/(P*((P*(/P*/4PT4 8P*84P*4/P*/Å µ @•(P*((P*(/P*/4PT4 8P*84P*4/P*Å µ @•/)P*))P*)0P*05PT5 9P*95P*50P*µ @Å •0)P*))P*)0P*05PT5 9P*95P*50P*0Å µ @•)P*))P*)0P*00P*05P*55P*50P*00P*Å µ @•0)P*))P*)0P*00P*05P*55P*50P*00P*0µ @Å •+P*++P*+2P*22P*27P*77P*72P*22P*µ @•2Å •+P*++P*+2P*22P*27P*77P*72P*22P*2Å µ @•+P*++P*+2P*22P*27P*77P*72P*22P*µ @Å •2+P*++P*+2P*22P*27P*77P*72P*22P*Å µ @•2-P*--P*-4P*4-PT- 4P*4-P*-4P*4Å µ @•-P*--P*-4P*4-PT- 4P*4-P*-4P*4Å µ @•-P*--P*-4P*4-PT- 4P*4-P*-4P*µ @•4Å •-P*--P*-4P*4-PT- 4P*4-P*-4P*Å µ @•4&P*&&P*&-P*-&PT& -P*-&P*&-P*Å •-µ @•&P*&&P*&-P*-&PT& -P*-&P*&-P*Å µ @•-&P*&&P*&-P*-&PT& -P*-&P*&-P*µ @Å •-&P*&&P*&-P*-&PT& -P*-&P*&-P*Å µ @•-$P*$$P*$+P*+$PT$ +P*+$P*$+P*µ @•+Å •$P*$$P*$+P*+$PT$ +P*+$P*$+P*µ @•+Å •$P*$$P*$+P*+$PT$ +P*+$P*$+P*+Å µ @•$P*$$P*$+P*+$PT$ +P*+$P*$+P*Å •+µ @•)P*))P*)0P*0)PT) 0P*0)P*)0P*µ @•0Å •)P*))P*)0P*0)PT) 0P*0)P*)0P*Å •0µ @•)P*))P*)0P*0)PT) 0P*0)P*)0P*0Å µ @•)P*))P*)0P*0)PT) 0P*0)P*)0P*0µ @Å •$P*$$P*$+P*+$PT$ +P*+$P*$+M*Å µ @•+$I*$$E*$+A*+$=T$ +5*+$1*$+-*µ @Å •++)*++%*+2!*2+T+ 2*2+*+2 *µ @Å •2+ *++*+2*2+T+ 2*2+*+2*2ÿ/MTrk. ¹ÉÿJAZ2ÿGeneral MIDI¹kÿdrumÿ @¹ `™#F.F#.*F#F*F**F#**(F*F*F*(*F#F*#F*#*F#**F**F**F#F#F#*F*(F*F#**(*F*F#F**F*#F##F*#.F#.*F*F*#F*#*F*F*(F*(*F*F*#F#**F#F#*F***F#F**F**F##F**F#(F(*F*#F**F#F#**F##F*.F#*F.*F*#F*F*#(F**F**F(#F**F##F**F#**F*F***F#F#*F*#F**F#(F*F*(*F*#F*#F#*F*#F#.F.*F#*F*#F*F*#*F*(F(**F*F*#F**F##F**F#**F#F*F*#F**F#(F*#*F*(*F*F*#F#*F*#F*#F#.F.#*F*F*#F#**F*F*(F(**F#F**F**F#F#**F#*F**F*#F##F**F**F#(F(**F#F**F#*F#F*#F.F#**F.#*F*#F**F#*F(F**F*(#F**F##F**F*#*F**F#F**F##F**F#(F**F*F*(*F*#F*#F#*F*.F##F#*F.*F*#F*#*F*F*(F*F(*#F**F##F*F*#**F*F*#F**F##F**F#(F**F*F(**F*#F##F**F#.F*#F#*F.#F**F*F*#(F**F(*F*#F**F*F#F*#*#*F*F*#F**F*#F#*F**F#(F*F*(#F**F#*F*#F##F*.F*F#.*F*#F*F*#*F*(F(*F**F*#F##F*F*#**F**F*F*#F#*F*#F#*F*(F(**F*F*#F#*F*#F*.F##F*F.#*F*#F#*F**F*(F(*F*#F**F*#*F#F*#*F**F#F**F**F##F#*F*(F*F*(*F*#F#*F*#F*.F##F*F.##F**F**F#(F**F(*F*#F**F*F*#F#*#*F**F*F*#F##F*F*(F*F*#**F(#F**F**F##F*#F#.F*F#.#F**F#**F*F*(F(**F#F**F##F**F*#*F*F***F#F**F##F*(F#*F*(*F#F**F**F##F*#F#.F.*F#*F*#F**F#*(F*F**F(*F*#F#F*#*F*#*F*F*#F**F**F##F#*F*(F**F(*F*#F**F##F#.F*#F.*F##F*F***F#*F*(F(*F*#F**F**F##F*#*F*F*#F**F##F**F#(F**F(*F*#F**F*#F#*F#.F*#F#.*F*F*#F*F#*(F**F*F*(#F**F*F#*#F*#*F**F#F**F**F##F#(F**F*F(*#F**F#*F*#F#.F*#F.*F##F*F**F*#*F*(F*F(**F*#F*F#F#**#*F**F#F**F**F##F#(F**F*F(**F*#F*#F#*F#.F*#F.*F#*F*#F#**F(F**F(**F#F**F*F#F#**#*F**F*F*#F##F**F#*F*(F*F*(*F*#F#*F*#F##F*.F.#*F#F**F*F*#*F*(F*F*(#F**F*F*#F##**F**F*F*#F*#F#*F**F#(F**F(*F*#F##F**F#.F*#F#.*F*F*#F#*F**F*(F*F*(#F**F*#F*F#*#*F**F#F**F##F**F*(F#*F*(*F#F**F#*F*#F##F*.F*F#.*F*#F**F#*F*(F(*F**F*#F*##F*F#**F**F#F**F#*F*#F#*F*(F(**F*F*#F*#F#*F*#F#.F.#*F#F**F**F#*F*(F*(*F*F*#F##F*F*#**F**F#F**F*#F#*F*(F#*F*(*F#F**F*#F#*F*#F#.F#.*F*F*#F**F#(F**F**F(*F*#F#F#*F**#*F**F#F**F#*F*#F#(F**F*(*F#F**F**F##F##F*.F.#*F*F*#F#*F*(F**F*(*F*F*#F#**F#F*#*F**F*F*#F*#F#*F**F#(F(**F#F**F*#F#*F*#F#.F*F.##F**F#*F**F*(F(*F*#F**F##F*F**#*F**F*F*#F#*F*#F#*F*(F*(*F*F*#F**F##F*.F##F#.*F*F*#F#**F(F**F*F*(#F**F#*F#F**#*F**F*F*#F**F##F#(F**F*(*F#F**F*#F#*F*.F##F*F.#*F*#F#*F**F(F*(*F**#F*F##F**F*#*F*F*#F**F**F##F*(F#*F*F*(*F*#F**F##F##F*.F.*F#*F*#F*#*F*F*(F(*F*#F**F*F*##F*#*F*F*#F**F#*F*#F*(F#*F*F*(*F*#F#*F*#F*.F##F#*F.#F**F**F#*F*(F(**F*F*#F#F*#*F#**F**F#F**F**F##F**F#(F(*F**F*#F**F##F#.F*#F#*F.#F**F*#*F*F*(F(*F*#F**F*#F*F#*#*F*F**F*#F*#F#*F#*F*(F*(*F*F*#F#*F*#F*#F#.F#.*F#F**F**F#*F*(F(**F#F**F#F#**F#**F**F*F*#F*#F#*F#(F**F*F*(#F**F##F**F*.F##F.#*F#F**F#**F(F**F**F(#F**F#F*F*#*#*F*F**F*#F**F##F**F#(F(**F*F*#F#*F*#F*#F#.F#*F.*F*#F#*F*(F**F(**F*F*#F*F*##F*#*F*F**F*#F##F**F#(F**F(**F#F**F##F**F*.F##F.#*F*F*#F#**F*F*(F(*F**F*#F#F*F#**#*F*F**F*#F**F##F**F#(F*F(**F*#F*#F#*F#.F*#F#.*F#F**F**F#(F**F(**F*F*#F#F*F*#*#*F*F*#F**F**F##F*(F#*F(**F*F*#F*#F#*F#.F*#F#*F.#F**F*F#**F*(F*(*F*F*#F##F*F**#*F*F**F*#F*#F#*F#*F*(F(**F#F**F#*F*#F*#F#.F#.*F#F**F**F#*F*(F*F*(#F**F*F#F#*#**F**F*F*#F*#F#*F#*F*(F*F*(#F**F#*F*#F#.F*#F#*F.#F**F**F#(F**F(**F#F**F*#F*F#*#*F*F*#F**F#*F*#F**F#(F*F*(#F**F#*F*#F*#F#.F*F#.*F*#F#*F**F*(F(*F**F*#F#F*F*#*#*F**F#F**F##F**F#*F*(F*F*(*F*#F*#F#*F#.F*#F.#*F#F**F**F#*F*(F*(*F*F*#F##F*F**#*F**F*F*#F*#F#*F#*F*(F*F*(*F*#F**F##F*#F#.F*F#.#F**F**F#(F**F**F(#F**F*F#F#*#**F**F*F*#F*#F#*F#*F*(F*F*(*F*#F*#F#*F#.F*#F.#*F#F**F**F#*F*(F*(*F#F**F*#F*F#*#*F**F*F*#F**F##F**F#(F*F*(#F**F#*F*#F*.F##F*F.##F**F**F#*F*(F(*F*#F**F*F#F#*#**F**F*F*#F*#F#*F#*F*(F*F*(#F**F#*F*#F*.F##F.#*F*F*#F#*F**F*(F*(*F*F*#F#*F#F*#**F**F*F*#F**F##F*(F#*F*F(**F*#F*#F#*F##F*.F*F#.#F**F**F#*F*(F(*F*#F**F*F#F#*#**F**F#F**F#*F*#F**F#(F*F*(*F*#F**F##F*.F##F.#*F#F**F**F#*F*(F*(*F*F*#F##F*F**#*F**F#F**F##F**F#(F**F*F(*#F**F##F**F##F*.F*F#.*F*#F#*F*(F**F**F(#F**F#F*F#**#*F**F*F*#F**F##F*(F#*F*F(*#F**F##F**F#.F*#F.#*F#F**F**F#(F**F(**F*F*#F##F*F**#*F**F*F*#F*#F#*F#*F*(F*F*(*F*#F**F##F*#F#.F*F#.*F*#F#*F*(F**F**F(*F*#F#F*F*#*#*F**F*F*#F*#F#*F#(F**F*F(**F*#F**F##F*#F#.F#.*F#F**F**F#*F*(F*(*F#F**F*#F*F#*#*F**F*F*#F**F##F**F#(F*F*(*F*#F*#F#*F#.F*#F*F.#*F*#F#*F*(F**F**F(*F*#F*F#F*##**F**F#F**F##F**F#(F**F*F(*#F**F#*F*#F*.F##F.#*F*F*#F#*F**F*(F*(*F#F**F**F#F##**F**F#F**F#*F*#F**F#(F*F*(#F**F#*F*#F*#F#.F*F#.#F**F**F#(F**F**F(*F*#F#F*F*#*#*F**F*F*#F**F##F*(F#*F*F(**F*#F**F##F*.F##F.#*F*F*#F#*F*(F**F(**F*F*#F#*F#F*#**F**F#F**F#*F*#F*(F#*F*F(**F*#F*#F#*F##F*.F*F#.#F**F**F#(F**F**F(*F*#F#F*F*#*#*F**F#F**F##F**F#*F*(F*F*(#F**F#*F*#F*.F##F.#*F*F*#F#*F*(F**F(**F#F**F**F#F##**F**F#F**F#*F*#F*(F#*F*F(*#F**F#*F*#F*.F##F*F.##F**F**F#*F*(F(*F*#F**F#F*F#**#*F**F*F*#F*#F#*F#*F*(F*F*(*F*#F*#F#*F#.F*#F.#*F#F**F**F#(F**F(**F#F**F**F#F##**F**F#F**F##F**F#(F**F*F(**F*#F*#F#*F##F*.F*F#.*F*#F#*F**F*(F(*F*#F**F#F*F#**#*F**F*F*#F**F##F*(F#*F*F(**F*#F*#F#*F##F*.F#.*F#F**F**F#*F*(F*(*F*F*#F##F*F**#*F**F#F**F#*F*#F**F#(F*F*(*F*#F**F##F*#F#.F*F#.#F**F**F#(F**F**F(*F*#F*F#F*##**F**F*F*#F*#F#*F#*F*(F*F*(*F*#F**F##F*#F#.F#.*F#F**F**F#*F*(F*(*F*F*#F#*F#F*#**F**F#F**F##F**F#(F**F*F(**F*#F*#F#*F##F*.F*F#.*F*#F#*F**F*(F(*F*#F**F*F#F#*#**F**F#F**F#*F*#F*(F#*F*F(**F*#F**F##F*.F##F.#*F#F**F**F#*F*(F*(*F#F**F**F#F##**F**F#F**F##F**F#(F**F*F(**F*#F**F##F*#F#.F*F#.#F**F**F#*F*(F(*F**F*#F#F*F*#*#*F**F#F**F##F**F#(F**F*F(**F*#F*#F#*F##F*.F#.*F*F*#F#*F**F*(F*(*F*F*#F#*F#F*#**F**F#F**F#*F*#F*(F#*F*F(**F*#F**F##F*.F##F*F.##F**F**F#(F**F**F(*F*#F#F*F*#*#*F**F*F*#F*#F#*F#(F**F*F(*#F**F##F**F##F*.F#.*F#F**F**F#*F*(F*(*F#F**F*#F*F#*#*F**F#F**F##F**F#*F*(F*F*(#F**F##F**F#.F*#F*F.##F**F**F#*F*(F(*F*#F**F#F*F#**#*F**F#F**F#*F*#F**F#(F*F*(#F**F#*F*#F*#F#.F#.*F#F**F**F#*F*(F*(*F*F*#F#*F#F*#**F**F*F*#F*#F#*F#(F**F*F(**F*#F*#F#*F##F*.F*F#.#F**F**F#(F**F**F(*F*#F*F#F*##**F**F#F**F#*F*#F**F#(F*F*(*F*#F**F##F*#F#.F#.*F*F*#F#*F*(F**F(**F*F*#F##F*F**#*F**F#F**F##F**F#*F*(F*F*(#F**F##F**F#.F*#F*F.##F**F**F#*F*(F(*F*#F**F#F*F#**#*F**F#F**F##F**F#*F*(F*F*(#F**F#*F*#F*.F##F.#*F#F**F**F#(F**F(**F*F*#F##F*F**#*F**F#F**F#*F*#F**F#(F*E*(*C*#C**A##A*#?#.?*=#.#;**;**9#*7*(7(*5*#3**3#1*1#**#*/**-#+**+##)**)#*'*('*%*(*#*##*#!#*!#.*#.#***##**(**(****##*#*#**** * *# *# #* #(***(***#**##*##.*#.#****#(****(**###***#***#***#*#*(*#(**#**##***#ÿ/MTrk8°ÿJAZ2ÿSimutrans Main themeÿ/simutrans-124.3/simutrans/music/02-Gotta-catch-that-train.mid000066400000000000000000000702641474050137200240520ustar00rootroot00000000000000MThd`MTrkfÿCopyright (C) 2006 shunterð~ ÷ÿJAZ2ÿQ âÿÿ 2006.10.06ÿ/MTrk¯ÿ(shunter 2006 ÿJAZ2ÿGotta catch that trainÿ(My Song ÿ @ÿGeneral MIDIÿ ÿ/MTrk(ä°0ÀÿJAZ2ÿAmÿ @° &ÿGeneral MIDIÿrythm`E;H;<;@;*H@E<E;<;@;H;*@EH<6<;@;E;H;*E@H<6E;H;<;@;*@H<E@;<;E;H;ÿEm7*@E<H@;H;E;<;*<HE@;;C;>;G;*G>;CG;C;;;>;*C;G>6G;C;>;;;*>;CG6;;G;>;C;*GC;>>;G;;;C;ÿG7*C>G;G;;;C;>;*;CG><;E;A;H;*E<HAE;A;H;<;*A<EH6<;A;E;H;*AHE<6E;<;H;A;*<HAE<;E;H;A;ÿFmaj7*<EAHA;H;<;E;*<EAH;;D;G;@;*;D@G@;D;;;G;*;D@G6;;D;G;@;*@G;D6D;G;@;;;*@;DGG;@;ÿAmD;;;*GD@;D;G;@;;;*@G;DH;E;<;@;*@E<HE;@;<;H;*<EH@6E;H;@;<;*E@H<6@;<;E;H;*<@EH@;H;<;ÿAmE;*E@H<<;H;E;@;*@<EH@;;;D;G;*G@D;G;@;D;;;*@GD;6;;D;G;@;*;@DG6G;@;D;;;*;@DGÿFmaj7G;;;D;@;*G@;D;;G;@;D;*@D;GH;<;E;A;*<EHA<;E;A;H;*EA<H6<;E;A;H;*A<EH6E;H;A;<;*EH<AE;<;H;ÿFmaj7A;*H<EAE;<;A;H;*H<EA;;G;@;D;*@G;D;;@;D;G;*;D@G6D;G;;;@;*@;DG6;;D;@;G;*@DG;G;@;ÿAm;;D;*;@DGD;G;@;;;*;GD@H;@;E;<;*<@HEE;<;H;@;*EH<@6<;E;H;@;*@<HE6H;<;@;E;*H@E<H;ÿEm7E;<;@;*<@EH<;H;@;E;*@<EHC;>;G;;;*G;>C;;G;C;>;*>GC;6C;;;G;>;*;>CG6G;C;>;;;*>GC;>;G;ÿG7;;C;*>G;C>;;;G;C;*C>;GA;H;<;E;*H<AEE;<;H;A;*HEA<6E;H;<;A;*AH<E6<;H;E;A;*H<EAH;A;E;ÿFmaj7<;*HAE<E;A;H;<;*EHA<;;G;D;@;*DG@;G;D;;;@;*@GD;6D;G;;;@;*;D@G6@;D;G;;;*@;GDG;ÿC#m7;;@;D;*G;D@D;G;;;@;*GD@;@;=;I;E;*@=EI@;I;E;=;*E=@I6I;@;=;E;*E@=I6I;E;@;=;*E=I@@;I;ÿFmaj7E;=;*IE@=I;@;E;=;*=EI@H;E;<;A;*EH<A<;A;H;E;*A<HE6<;H;E;A;*AHE<6E;H;A;<;*AH<EA;<;ÿFmaj7H;E;*<AHEH;E;A;<;*HA<E@;D;;;G;*G;@D@;;;D;G;*GD@;6G;;;@;D;*D;@G6@;D;;;G;*GD;@D;@;G;;;ÿEM*@;GDD;G;;;@;*D@G;@;G;;;D;*G;D@G;D;@;;;*D;@G6G;@;;;D;*;DG@6;;G;@;D;*G;@DG;ÿE7;;@;D;*D@G;D;;;G;@;*DG;@fB;>;E;J;TEB>JlÿDMJ;>;E;B;TBEJ>l>;J;E;B;TEBJ>lB;E;>;J;ÿD7TBE>JlC;@;H;<;T@HC<lÿCM@;C;<;H;T<CH@lC;<;H;@;TC<@HlH;@;C;ÿAm7<;T<C@HlE;<;A;H;THAE<lÿFM<;A;H;E;T<AHElH;A;<;E;THEA<lÿFmaj7<;A;E;H;THEA<lG;;;D;@;TDG;@lD;;;@;G;ÿEMTG;@DlG;;;D;@;TGD;@lÿE7@;G;D;;;TD;@G E;J;B;>;*EJB>E;B;>;J;*JEB>6>;J;B;E;*BEJ>6E;J;>;B;*J>BEE;>;ÿD7B;J;*>EJBJ;B;E;>;*EJ>B<;H;E;A;*<AHEA;<;H;E;*E<HA6E;A;<;H;*HE<A6A;H;E;<;*A<HEÿG7A;H;E;<;*EHA<E;<;H;A;*AE<H>;;;G;C;*;>CG;;C;G;>;*>;CG6C;;;G;>;*G>;C6C;>;G;;;*>G;C>;G;ÿGM;;C;*C;G>>;C;G;;;*C;G>>;;;C;G;*;>GCC;G;>;;;*;CG>6C;G;;;>;*C>G;6;;>;G;C;*;CG>G;C;;;ÿA7>;*;CG>C;G;;;>;*;C>GI;=;@;E;*@EI==;E;@;I;*@IE=6I;=;@;E;*@I=E6I;@;E;=;*E@I=I;ÿAM@;E;=;*I@E=E;I;@;=;*E@=I@;=;I;E;*IE=@@;=;E;I;*=I@E6=;@;I;E;*@E=I6I;E;@;=;*IE@=I;=;@;E;ÿC#m7*=@IE=;@;I;E;*EI=@;;D;G;@;*@GD;D;;;@;G;*@;GD6@;;;D;G;*D@G;6G;D;@;;;*G@;DD;ÿE7;;G;@;*DG@;D;@;;;G;*D;G@B;E;>;J;*JE>BB;E;>;J;*>EBJ6B;E;J;>;*>EJB6>;E;J;B;*E>BJJ;B;E;ÿDM>;*JB>E>;E;B;J;*>BEJE;J;>;B;*JEB>B;>;J;E;*JE>B6J;E;B;>;*>BEJ6E;B;>;J;*EJB>B;J;ÿD7E;>;*BJE>>;B;E;J;*BJ>EC;<;@;H;*C@H<H;C;<;@;*CH@<6<;H;@;C;*<@HC6@;H;C;<;*<C@HC;@;<;ÿCmaj7H;*<C@H@;H;<;C;*<@CH?;;;G;B;*?B;G;;B;?;G;*?B;G6B;G;;;?;*B?G;6?;;;B;G;*?;BG?;G;ÿB7B;;;*?;GBB;;;G;?;*BG?;E;I;=;@;*@I=EI;=;E;@;*E=I@6I;E;@;=;*@I=E6=;I;E;@;*@=EI@;E;=;I;ÿAM*I@E==;@;E;I;*=IE@I;@;=;E;*EI=@@;I;=;E;*E@=I6E;=;@;I;*=IE@6@;=;I;E;*E@=IÿA7I;=;E;@;*E=I@I;E;@;=;*=@IEG;>;;;C;*CG>;C;>;G;;;*>CG;6>;G;;;C;*CG;>6G;;;>;C;*C>;GG;;;>;ÿGMC;*;>GCC;G;;;>;*CG;>;;>;G;C;*>;GCC;>;;;G;*>;GC6C;G;;;>;*;CG>6;;G;C;>;*GC;>C;;;ÿG7G;>;*GC;>>;;;G;C;*C>;GA;E;<;H;*<EAHH;E;A;<;*H<EA6H;A;E;<;*H<AE6<;E;H;A;*AE<HH;E;<;ÿFmaj7A;*<HEA<;H;E;A;*EH<A@;H;<;E;*@EH<@;H;E;<;*E<@H6H;<;@;E;*<@EH6E;@;H;<;*@<EHE;@;<;ÿEm7H;*E@<H<;E;@;H;*<HE@G;>;C;;;*>GC;G;>;;;C;*GC>;6G;>;C;;;*C>G;6;;>;C;G;*;G>C;;>;C;G;ÿG7*C>;GC;G;>;;;*>GC;<;A;E;H;*<HAEE;A;<;H;*<HEA6H;E;A;<;*EA<H6H;E;A;<;*E<HAA;<;H;E;ÿFmaj7*EA<HE;<;H;A;*EA<H@;G;;;D;*@DG;D;G;;;@;*D;@G6D;@;;;G;*;@GD6;;G;D;@;*;G@DD;;;ÿAmG;@;*D@;G;;@;D;G;*D@;G@;H;<;E;*@EH<H;E;<;@;*<@HE6<;@;E;H;*@EH<6<;@;E;H;*@H<EÿAm<;H;E;@;*H@<E<;E;@;H;*@E<H@;;;D;G;*@G;DD;G;@;;;*@;DG6G;@;D;;;*@D;G6G;@;D;;;*@;GDD;ÿFmaj7;;@;G;*GD@;D;G;;;@;*;G@DH;E;A;<;*H<AEH;A;E;<;*H<EA6H;A;<;E;*EAH<6A;H;<;E;*<HEA<;H;A;E;ÿFmaj7*AH<EE;<;A;H;*A<EH@;D;G;;;*@;DG@;D;G;;;*G;@D6@;D;G;;;*DG;@6G;;;@;D;*;DG@ÿAmD;@;G;;;*;@DG;;@;G;D;*G@;DE;<;@;H;*EH<@E;<;@;H;*@HE<6@;<;H;E;*<HE@6@;E;<;H;*EH@<@;<;E;ÿEm7H;*HE@<<;E;H;@;*HE<@G;>;C;;;*G;>CG;C;;;>;*;>GC6C;>;;;G;*>;GC6;;>;G;C;*>C;GC;G;ÿG7>;;;*G;>CC;;;G;>;*;C>G<;E;A;H;*<HAEA;E;<;H;*HEA<6<;H;A;E;*EHA<6A;E;<;H;*HEA<ÿFmaj7<;A;H;E;*<AHEE;<;H;A;*HEA<G;;;@;D;*G@;D;;D;@;G;*D;G@6D;;;G;@;*@;DG6G;D;;;@;*D;G@G;@;D;;;ÿC#m7*G@D;G;@;;;D;*;G@DI;@;=;E;*E@=IE;=;@;I;*=EI@6E;I;@;=;*E=@I6I;@;E;=;*=@EI@;I;E;ÿFmaj7=;*=@IEE;I;=;@;*E=I@<;A;H;E;*<AHE<;E;H;A;*<AEH6A;H;<;E;*AE<H6H;E;A;<;*E<AHH;ÿFmaj7<;A;E;*E<AHA;H;E;<;*AHE<G;@;;;D;*DG;@@;D;G;;;*;GD@6;;G;@;D;*;G@D6D;@;;;G;*@DG;G;ÿEM;;D;@;*G@D;D;G;;;@;*;DG@;;D;@;G;*GD;@G;;;@;D;*D@G;6G;;;@;D;*G@;D6;;@;G;D;*D@;GG;@;;;D;ÿE7*;G@D@;D;G;;;*D@G;B;>;J;E;*EB>JE;>;J;B;*J>BE6E;>;B;J;*BJ>E6>;J;E;B;*B>JEB;>;E;J;ÿDM*JE>B>;E;B;J;*EBJ>J;E;B;>;*BJ>E>;B;J;E;*EJ>B6B;>;J;E;*>EBJ6E;J;B;>;*>JEBÿD7J;>;B;E;*>BEJB;J;>;E;*BE>J<;C;H;@;*C<@H@;<;H;C;*@CH<6<;@;C;H;*<CH@6C;@;H;<;*<C@HÿCMC;@;<;H;*C@<HC;H;<;@;*HC<@H;@;<;C;*H@<C@;C;<;H;*H@C<6<;@;H;C;*@<HC6@;<;H;C;*C<H@ÿAm7<;C;H;@;*H<C@C;H;@;<;*<@CHE;<;A;H;*HA<E<;A;E;H;*EH<A6E;H;A;<;*AHE<6A;<;H;E;*A<EHÿFM<;E;A;H;*EHA<<;A;H;E;*E<AH<;H;E;A;*EAH<A;<;E;H;*HEA<6H;A;E;<;*<HEA6E;A;H;<;*<HAEH;ÿFmaj7<;A;E;*EH<AH;E;<;A;*EH<AG;D;;;@;*G;D@D;G;;;@;*@;DG6@;G;D;;;*G;D@6;;@;G;D;*@G;D;;@;D;G;ÿEM*D@G;@;D;;;G;*@;GD;;D;@;G;*DG@;;;G;@;D;*G;@D6;;D;G;@;*D;@G6G;@;D;;;*G;@DG;D;ÿE7@;;;*G@;DD;@;;;G;*DG;@B;>;E;J;*BE>JJ;B;E;>;*>BEJ6>;B;E;J;*>BEJ6>;E;J;B;*JEB>ÿD7J;>;B;E;*JBE>E;>;J;B;*J>BEH;E;A;<;*AHE<A;E;<;H;*AEH<6E;<;A;H;*<EHA6E;H;<;A;*EAH<A;ÿG7<;E;H;*E<HAA;<;H;E;*AEH<G;>;C;;;*>G;C>;G;;;C;*>;CG6;;>;C;G;*G>;C6C;>;G;;;*;C>GÿGM>;G;C;;;*;>GC;;>;C;G;*;G>C>;C;;;G;*C>G;>;G;;;C;*G>;C6G;C;;;>;*;CG>6;;>;C;G;*;C>G;;C;>;G;ÿA7*C>;G>;C;;;G;*;GC>=;@;I;E;*@E=I@;E;I;=;*=@EI6I;E;@;=;*@IE=6I;E;=;@;*IE@=ÿAME;@;=;I;*I@E==9E9@9I9*I@=E=7@7E7I7*@=IEE5I5=5@5*E=@I6I1=1@1E1*E=I@6E-I-@-=-*=EI@@+E+=+I+ÿC#m7*@E=I@)E)I)=)*@=EI;'G'@'D'*G;D@@%G%;%D%*G@;D6;!G!@!D!*;D@G6;@GD*;G@DÿE7;GD@*D;G@GD@;*D@;GJB>E*BE>J>EJB*JB>E6EJB>*BJ>E6> J E B *EJ>BJ > ÿDME B *E>BJE J B > *JB>Eÿ/MTrk ôÄ0ÿJAZ2ÿ @HÿLeadÿGeneral MIDI´ @ƒTÄ0‚t0”QQOOMMLLM*MO*OQQOOMMLLM*MO*Ä0”OPPOONNMML*LJ*JL(LÄ0”Q(QQ*QLTL J*JÄ0”H(HG(GÄ0”Q*QM*MQ*QM*MQ*QM*MQ*QM*MÄ0”S*SL*LS*SL*LS*SL*LS*SL*Ä”LL~LO*OQ(QÄ”O~OQ*QJ(Ä”JQQOOMMLLM*MO*OQQOOMMLLM*MO*Ä”OPPOONNMML*LJ*JL(Ä”LLTL ETE ITI LTLÄ ”M(MOTO MTÄ”M P*PL*LP*PL*LP*PL*LP*PL*Ä”LS*SP*PS*SP*PS*SP*PS*SP*Ä0”PJ~JJ*JJ*JI*IJ*JL*LÄ0”M~MM*MM*ML*LM*MO*OÄ0”HTH GTG E(EÄ0”CTC E*EG*GH(HÄ0”M*ML*LJ*JM*ML*LJ*JM*ML*Ä0”LM*ML*LJ*JM(MM*Ä0”ML~LKKLLNNPPNNLLK*KL*Ä0”LP~PNNPPQQSSQQPPN*NP*PÄ0”J*JI*IJ*JL*LNTN L*LN*NÄ0”Q(QM(MÄ0”J(JJJGGHHJJH*HG*Ä0”GC~CB*BC(CÄ0”I*IG*GI*IJ~JITIÄ0 ”L‚PLÄ00”LTL PTP G(Ä0”GNTN Q*QP*PN(NÄ”NNLLJ*JNNLLJ*JNNLLJ*JNNLLJ*JÄ”NNLLJ*JNNLLJ*JO(OÄ0”KTK NTN PTP NTNÄ0 ”Q(QPTP NTNÄ0 ”LTL ITI Q(QÄ0”OTO NTN L(LÄ”O*ON*NO*OQ*QS(SÄ”T~TS*SQ(QÄ0”L~LO*OQ(QÄ0”O~OQ*QJ(Ä0”JQQOOMMLLM*MO*OQQOOMMLLM*MO*OÄ0”PPOONNMML*LJ*JL(Ä0”LL?L LLH?H HHE?E EEETEÄ0 ”G?G GGD?D DD@?@ @@@T@Ä0 ”Q*QM*MQ*QM*MQ*QM*MQ*QM*MÄ0”S*SL*LS*SL*LS*SL*LS*SL*Ä”LL~LO*OQ(Ä”QO~OQ*QJ(Ä”JQQOOMMLLM*MO*OQQOOMMLLM*MO*OÄ”PPOONNMML*LJ*JL(Ä”LLTL ETE ITI LTÄ”L M(MOTO MTÄ”M P(PP*PSTS U*UÄ”P‚PPÄ00”O*ON*NL*LN*NSTS QTQÄ0 ”OTO N*NL*LJ(JÄ0”M*ML*LJ*JL*LQTQ OTÄ0”O MTM L*LJ*JH(HÄ0”H(HH*HA*AC*CE*EÄ0”H‚PHÄ00”LTL KTK L*LD*DE*EI*IÄ0”G‚PÄ0”G0N(NJTJ L*LN*NÄ0”Q(QM(MÄ0”O*OJ*JL*LN*NJ(Ä0”JG*GH*HJ*JL*LJ(Ä0”JL*LJ*JITI J~JI}*Ä0”IE{‚PEÄ0ƒ*0ÿ/MTrk Å ÿJAZ2ÿBaseÿ @ÿGeneral MIDIµ Y`•-@*--@*-4@*4-@T- 4@*4-@*-4@*47@*77@*7>@*>7@T7 >@*>7@*7>@*>)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*44@*44@*4;@*;4@T4 ;@*;4@*4;@*;)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*47@*77@*7>@*>7@T7 >@*>7@*7>@*>)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*45@*55@*5<@*<5@T5 <@*<5@*5<@*<(@*((@*(/@*/(@T( /@*/(@*(/@*/(@*((@*(/@*/(@T( /@*/(@*(/@*/&@*&&@*&-@*-&@T& -@*-&@*&-@*-&@*&&@*&-@*-&@T& -@*-&@*&-@*-$@*$$@*$+@*+$@T$ +@*+$@*$+@*+$@*$$@*$+@*+$@T$ +@*+$@*$+@*+)@*))@*)0@*0)@T) 0@*0)@*)0@*0)@*))@*)0@*0)@T) 0@*0)@*)0@*0(@*((@*(/@*/(@T( /@*/(@*(/@*/(@*((@*(/@*/(@T( /@*/(@*(/@*/&@*&&@*&-@*-&@T& -@*-&@*&-@*-)@*))@*)0@*0)@T) 0@*0)@*)0@*0+@*++@*+2@*2+@T+ 2@*2+@*+2@*2+@*++@*+2@*2+@T+ 2@*2+@*+2@*2-@*--@*-4@*4-@T- 4@*4-@*-4@*4-@*--@*-4@*4-@T- 4@*4-@*-4@*4(@*((@*(/@*/(@T( /@*/(@*(/@*/2@*22@*29@*92@T2 9@*92@*29@*9&@*&&@*&-@*-&@T& -@*-&@*&-@*-0@*00@*07@*70@T0 7@*70@*07@*7/@*//@*/6@*6/@T/ 6@*6/@*/6@*69@*99@*9@@*@9@T9 @@*@9@*9@@*@-@*--@*-4@*4-@T- 4@*4-@*-4@*47@*77@*7>@*>7@T7 >@*>7@*7>@*>+@*++@*+2@*2+@T+ 2@*2+@*+2@*25@*55@*5<@*<5@T5 <@*<5@*5<@*<-@*--@*-4@*4-@T- 4@*4-@*-4@*47@*77@*7>@*>7@T7 >@*>7@*7>@*>)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*44@*44@*4;@*;4@T4 ;@*;4@*4;@*;)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*47@*77@*7>@*>7@T7 >@*>7@*7>@*>)@*))@*)0@*0)@T) 0@*0)@*)0@*04@*44@*4;@*;4@T4 ;@*;4@*4;@*;-@*--@*-4@*4-@T- 4@*4-@*-4@*45@*55@*5<@*<5@T5 <@*<5@*5<@*<(@*((@*(/@*/(@T( /@*/(@*(/@*/(@*((@*(/@*/(@T( /@*/(@*(/@*/&@*&&@*&-@*-&@T& -@*-&@*&-@*-&@*&&@*&-@*-&@T& -@*-&@*&-@*-$@*$$@*$+@*+$@T$ +@*+$@*$+@*+$@*$$@*$+@*+$@T$ +@*+$@*$+@*+)@*))@*)0@*0)@T) 0@*0)@*)0@*0)@*))@*)0@*0)@T) 0@*0)@*)0@*0(@*((@*(/@*/(@T( /@*/(@*(/@*/(@*((@*(/@*/(@T( /@*/(@*(/@*/&@*&&@*&-@*-&@T& -@*-&@*&-@*-)@*))@*)0@*0)@T) 0@*0)@*)0@*0+@*++@*+2@*2+@T+ 2@*2+@*+2@*2+@*++@*+2@*2+@T+ 2@*2+@*+2@*2-@*--@*-4@*4-@T- 4@*4-@*-4>*4-<*--:*-48*4-6T- 42*4-0*-4.*4(,*((**(/(*/(&T( /"*/( *(/*/2*22*29*92T2 9*92*29*9ÿ/MTrk0/ÉÿJAZ2¹ AÿDrumsÿ @ÿGeneral MIDI¹T`™#858*80.8#85#58*068(8*8#5.0#8.8*58(6(85.##8*8(58(8*#5(.858#80#*8(85.680(.8#8*5860.58*8#5#805#58#8*.80685(8.*8#06(#858*.8.(85#*8#8(58*(8#5.8#8(580#5(8*8.6806(#858*.80#.#8*855805.8#8#58*0.(8*8#6850*.8658(#8.(8#5*858#8(5*(8#.858(#80#568(8*8.0#8658*.8(0.(8*8##855805*(58#8.8#(80#.*868((850*6(8.858(#85(.#(8#8*858((8#5(*(8(8.858(#85.#(8(*8(8(68(*6(8#8.858((8.#(5(8#858(*80#5#8.8*580#68*8.5(80(6.858*#8#(85.*8#8(58*(85#.858(#80#(8*8.5680(6.8#8*5805.58#8#*80#*58#85.80#(8*8568.0(6.858*#8#(85.58*8(#8#(8*558.8(#805*8(8#68.0*6#8.8(580#.#8585*80#558.8*#80.#68*85(80*6#858(.8(85.#*858(#8(85#*#858(.80.568(8#*80*6#858(.80#5#8(8*8.580*#(.8(8585#80.(5*868#(80(*(8#8586.8(.#5(8*8#858((8#5*((8#858.8((8(.5(8#(868(*8*6(8(58.8(8#8((.5#(8*8(58#805*#8.8#580#5(8*8.680*(58.86#8.5#(8*858(#85*(8#58#8(.80#*8568.(80*(58#86.80#.*8#85580*#58#85.80#5*8(8.680*658#8(.85(8.#58*8(#85#(8*58#8(.80.568*8#(80*(.8#86580.#*8#855805*#858#.80.5*8(8#680(*.8#8658(8.#5*8#8(58#(85*#8.8(580.#(8685*806.8(58*#805#(858#8.*80#*(58#8.85(80#5.*868((80*658.8(8(#8.#5((858*8#8((8(5#*(8(8.858(#8#5(8.((8*8(686*((8.8#858((8(8#5(.#858(*80*5#858#.80.#68(85*80*(.8#8658#5(8.58*8(#8#5(8*#8(.8580.#*8(85680(*#8.865805.58*8##80*#58.85#80.#(8*85680(*58.86#85.(8##8*8(58(8#*558#8(.80#.68*85(80*658.8(#80#.*8#85580#*#8585.80#.68(85*80(6#8.8*58(8.5#58#8(*85(8*#.858(#80.#(8685*80*(58#86.80#*858#85(8.05#(58(8.8*#80(5.(8*8#680(*58(8#86.8(5#.(8*8(8#8(585#*((8.858(8(#8(8(5#.68*8((8*6((8.858#8((85(.#(8#8*8(580*#.8#85580.5(868#*80*58.86(#8(85.#*8#8(585#*(8.8#8(580.#68*85(80*6#858(.80#.58#85*80*#58.85#80#5*8(8.680*6#858(.85(8.#58*8(#8(8#5*58.8(#80.#*8685(806*#858(.805#58*8.#805#.858*#80.#68(85*80*658.8(#85.#(8*8#8(58#*(85.8#8(5805.68(8#*806*.858(#80#.*8#8(85580*#(58.8#85(80#5((8*8.6806(.8#858*(8.(5#(8#8*858((8#*(5(8.858(8(#8#5.(8(*8(8(68*(6(8#8.858((8(#(85.*8#8(580#5#858*.80.5(868#*80(*58#86.8.5#(8#858(*8(85*#58.8(#80#5*8(8.680*658#8(.80.#*8585#80#*.8585#805#68*8.(80(*58#86.8#.5(8*858(#8#5(8*#858(.80.#*8685(80*(.8586#80.#58#85*805*.8#8#5805#(868.*80(*.8586#8.#5(8#858(*8(8*5#.8#8(5805.68*8#(80(658.8*#80#5*858#8.(80*5#.858(8(#80#(.(8685*80(6.8#858*(8(5.#(8*8#8(8(58#5(*(8#858(8(.8(#5(8.*8(8(68*6((8#8.858((85(#(8.#8(58*805*#858#.80.#68(85*806*.8#8(58.5(8##8*8(58*#5(8#858(.80.5*8(8#680*(.8586#80.5#8*8#580*558.8##80#.(8685*80*(#8.8658(8#.5#8*8(58*(85#58.8(#80#.*8685(80*(58#86.80.558#8#*80*#.8#855805.68*8#(80*6.858(#8.#(85*8#8(585#*(858#8(.80.#68*85(806(58.8*#805##8*858.(805*(58(8#8#.80.5#68(8(*80*658(8.8(#8#(5.(8#858(8(*85#(*(8(858.8(#8(#(85.68(8(*8(6*(8.858#8((8.#5(8(58#8(*80*#58#85.805.*868#(80*658.8(#85(8#.58*8(#8#(85*#8.8(5805.*8(8#6806(.8#8*5805.58#8#*80*#58#85.80.5*8(8#6806(.858*#85.#(8#858(*8*(85#58#8(.80.#68*85(80*6.858(#80.5*8#8#5805*#858#.80#568*8.(80(6#858*.8(8#5.*8#8(585(8*#58#8(.80.#68(85*80*(.8586#80#5(8#8*8.580#(558#8.8*(80(.5(8*8#680(658#8.8*(85.(#(8(8#858(*8*#(5(8#8(8.8(585.(8(#*8(8(68*(6(8(8.858(#8.(#(8558#8(*80*558.8##80#5*868.(80*6.858(#8.#(85*858(#8#*(8558.8(#80#.*8(85680*658.8(#80#558*8.#80#5#858*.80.#*8685(80(*.8#86585(8#.58#8(*8(85#*#858(.80.568(8#*806(58#8*.80.5#858#*80#5#8.8*5805#(8*8.6806(.858*#85.#(8*8#8(58#5(8*#8.8(5805.68*8#(806*#8.8(580#5*858(8.#80#(5#858(8*.805.#68(8(*806*.8#8(8(58(5#.(8(8*858(#8#*(5(8.8(8#8(58(.5(8#68(8(*86(*(858.8(8(#8#(8(.5*858(#80#5.858*#80#.*8685(80(*58.86#8(8.5#*858(#85#(8*58.8(#805#*8(8.6806*.8#8(580#558*8.#80#5.8#8*580#568*8.(80(6#858*.85#.(858#8(*8#*(85.8#8(5805#68(8.*80*6.858(#80#.#8585*80#5.8#8*5805.68(8#*80(*.8#8658.5(8#58*8(#8*#(8558.8(#80.5(8*8#6806(.8#8*580.558#8(8#*80*(#.858#85(805(.*868#(80*(#8.8586(8(.#5(858(8*8(#8#(5*(8.8#8(8(58#.5(8(*8(8(68*(6(8(8.8#8(58.(5(8#58*8(#80#*.8#855805.68*8#(80(6#858*.85#.(858*8(#8*#(8558.8(#80#.(8685*80*(#8.865805##858.*805*#8.8#5805#68*8.(80*(.8586#8.#(8558*8(#8#(85*58#8(.80.#(8685*80*(58#86.80.5*8#8#5805*.8#8#5805.*868#(80(*58#86.8#5.(858*8(#8*#(85#8.8(5805.(8*8#6806(#858*.80#.58*8#85(80(#*.8(8#85580(5.*868#(80*(#858.86(8.(5#(858(8#8(*8*(5#(8(858#8(.85(.(8#(8*8(68(*6(858#8.8((8((8.#5#858(*80*558.8##80#5*868.(80(*#8.8658(8.#558*8(#8*#(85.8#8(580.568(8#*80*6#858(.805.58*8##80#558.8*#80.#68*85(80(6.858*#85.#(8#858(*85*(8##858(.80.568*8#(80(6.8#8*5805.#8*8#580#*.8585#80#.(8*85680*6.8#8(58.5(8##858(*85*(8##858(.805#*868.(80(*.8#86580.5(8*858##80#5*.8#858((80#(.68(85*806*(858#8(.8.5(#(858(8#8(*8*(5#(8(8#8.8(58#(5(8.*8(8(68*(6(8#858(8(.85#.(8(58*8(#80#*58.85#80#5(8*8.6806(.858*#85.#(8#8*8(58*5(8#.858(#80#5*868.(80(*.8#865805.58*8##80*#.8585#80#.68*85(80*(.8#8658.5(8#*858(#8#(8*558#8(.80.#*8685(80(*#8586.80.#58*85#80#558#8*.80.5*8(8#6806*58.8(#8.5#(858#8(*8#*(85#858(.80.568(8#*80*6.8#8(580.5*8#858#(80(5#.8(858*#80(#.68(85*806*.8#8(8(58(5#.(858(8*8(#8#(5*(8.8#8(8(58#.5(8(*868((8*6((8.858#8((8((8#5.#858(*80*5#858#.80.#68*85(80(658#8*.8(8#5.58*8(#8*#(8558.8(#805#(8*8.6806(.858*#805##858.*80*#.8#85580#5*8(8.6806*58#8(.8#5.(8#858(*85*(8##858(.80.568(8#*80*6.858(#80#.58#85*805##858*.80.#(8*85680*6#8.8(58#5(8.*8#8(58#5(8*.858(#805.*8(8#6806*#858(.80#.58#8*85(80(*#(8.8#85580.5(68*8#(806(58#8.8*(8(#5.(8(858*8(#8#5(*(8.8(858(#8(.#(85(868(*8(6*(8(8#8.8(58#(5(8.*8#8(5805#.8#8*5805.(8*8#6806(#858*.85#.(858#8(*8#*(85.8#8(5805#*868.(80(*58.86#80#5#8*8.580*5.8#8#5805.*8(8#680(6#8.8*58#5(8.58#8(*8*(85##8.8(5805.(8*8#6806(.8#8*5805.#8*8#5805##858*.80.#*8685(80(*58#86.8#5.(8#8*8(58*5(8#58#8(.80.#68*85(80(6.858*#80.#(8*8#855805#*58.8(8(#80.#5*868((80*(.8#8586(85(#.(858*8(8(#8#*5((858.8#8((8.5((8#(868(*8(6*(858#8(8(.8.(8(#5#8*8(5805*.858##80#.*8685(80(*.8586#8(85.##858(*85*(8##8.8(580#5(868.*80*(.8#86580#558#8.*80*5#8.8#580.5*868#(80(*58#86.8#5.(858*8(#8*#(85#8.8(5805.*8(8#6806*.858(#80#.#8585*80#5#8.8*5805#*8(8.680(6.858*#8.#(85#8*8(58*5(8#58.8(#80.5(868#*80*(58#86.805.58*8(8##80#(*#8.8585(80.(#*8(85680*6(8#8.8(585#(.(8#8*858((8(*#5(8.8#8(8(58#.5(8(68*8((86*((8(8#8.8(58#(5(8.58*8(#80#*58.85#80#5(868.*80*(58#86.8#5.(8*8#8(58#5(8*.858(#80#5*868.(80(*#8.865805##858.*805*58#8#.80.5(8*8#6806(.858*#8.#(85*8#8(58#5(8*.858(#80#5*8(8.6806*#8.8(5805#58*8.#80#558#8*.80.5(868#*80*(#8586.8#.(8558*8(#8*#(85.858(#80#5(8*8.6806(.858*#80.#(8*8#85580*(558#8.8#(80#(5(8*8.680(6.8#858*(8(#.5(8#858(8(*8*5#((8(8.8#8(58.(5(8#(868(*8(6*(8.8(8#8(58(.5(8##8*8(5805*#8.8#5805#68(8.*80*6.858(#8.#(85#8*8(58#*(85.858#8(0(8*8.68#50566.6*#6(054*4#45#.05#252.2#*05.60(0*0#0*#.5...6(#.(-5#,5,(*,5#*(+5*#*(.*0#5.*(6(((06*#&5&(.&0&$($,$$$3$##$5.&#(#(&3$#,("&($"#"&"(!#&!($&; # &(( , & $ 3 9 &3;($,9#&(((&&(&(&,17&((&;33,;17(&(&(&&$(#&($#&(,&(1&7(#$;33&;1($7,#(&&&#(($#$&((&&9($`$/9//0// - /- -0- -0+-++0+ÿ/MTrk:°ÿJAZ2ÿGotta catch that trainÿ/simutrans-124.3/simutrans/music/03-Sunday-drivers.mid000066400000000000000000000225421474050137200225570ustar00rootroot00000000000000MThd`MTrk.ÿCopyright (C)2006 shunterð~ ÷°ÀÿJAZ2ÿQ q°ÿSunday driversÿÿ 2006.10.06ÿX`ƒÿC M7ƒÿE 7ƒÿDm 7ƒÿDb 7ƒÿC M7ƒÿE 7ƒÿDm 7ƒÿDb 7ƒÿC M7ƒÿEm 7ƒÿAm 7ƒÿDm 7ƒÿC M7ƒÿEm 7ƒÿAm 7ƒÿDm 7ƒÿC M7†ÿBb 7†ÿAm 7ƒÿC M7@ÿBdim 7@ÿEm 7@ÿAm 7`ÿDm 7`ÿC M7@ÿBdim 7@ÿEm 7@ÿAm 7`ÿDm 7`ÿC M7ƒÿG 7@ÿC M7@ÿC M7ƒÿG 7@ÿC M7@ÿC M7†ÿF M7†ÿC M7†ÿC M7@ÿBdim 7ƒÿF M7@ÿC M7`ÿDm 7`ÿG 7@ÿC M7`ÿDm 7`ÿG 7@ÿC M7ÿ/MTrk3ð~ ÷ÁÿJAZ2ÿ @HÿGeneral MIDIÿChord± `[ÿX`±s]<JPG@H@I@K@†`‘D@=DL@LG@=GP@PJ@=J>@=>A@=AE@EJ@=JM@=MQ@QI@=I=@==A@=AD@=DI@=IP@=P„CD@=DL@LG@=GP@PJ@=J>@=>A@=AE@EJ@=JM@=MQ@QI@=I=@==A@=AD@=DI@=IP@=Pc@@@C@C@@ @C@ C@@=@H@=HC@=C;@=;@@=@C@=C@@=@G@GC@=CL@LH@=H<@<@@=@E@=E@@=@H@HE@=E9@=9A@=A>@=>E@=EJ@JE@ EJ@ JE@=Ec@@@C@C@@ @C@ C@@=@H@=HC@=C;@=;@@=@C@=C@@=@G@GC@=CL@LH@=H<@<@@=@E@=E@@=@H@HE@=E9@=9A@=A>@=>E@=EJ@JE@ EJ@ JE@=E‚H@=HL@=LH@=H@@=@H@=HC@=CH@=HL@=LJ@=JA@AF@ FA@ AF@=FA@=AJ@=JM@=MJ@=JA@=AF@=FA@=AJ@=JM@MJ@JH@=H@@=@E@=EH@=HE@=EL@=L‚#A@=AG@G;@=;@@=@G@=G<@=<@@@9@=9A@A‚#A@=AG@G;@=;@@=@G@=G<@=<@@@9@=9A@A…CH@=H…CH@=HcC@=CH@HC@=CL@=LH@=H<@=<C@C@@=@H@=HL@=LH@=HO@OH@H<@=<E@=EH@=HM@=MH@=HM@MH@=HA@=AE@=EH@=HM@=MH@=H<@=<C@=CH@=HC@=CL@ LH@ HL@=LO@OH@=H@@=@H@=HC@CL@=LH@=HO@OO@=OJ@=JG@=GS@=SM@ MS@ SM@=MS@=SJ@JH@=HM@=MQ@=Q‚#O@=OS@S‚#O@=OS@SS@]SQ@]QO@]OT0=Tÿ/MTrkÆÿJAZ2¶JPÿGeneral MIDIÿChord¶s[G@H@I@K@ÿ @¶]<‡@–;@=;@@@@@=@L@LA@=A5@=55@=5>@>E@=EJ@=JJ@J=@==5@=5=@==A@=A=@==I@=I„C;@=;@@@@@=@L@LA@=A5@=55@=5>@>E@=EJ@=JJ@J=@==5@=5=@==A@=A=@==I@=Ic7@77@77@ 77@ 77@=7<@=<<@=<4@=4;@=;;@=;7@=7;@;7@=7G@GE@=E4@4<@=<<@=<9@=9<@<9@=92@=25@=52@=2A@=AA@A>@ >>@ >9@=9c7@77@77@ 77@ 77@=7<@=<<@=<4@=4;@=;;@=;7@=7;@;7@=7G@GE@=E4@4<@=<<@=<9@=9<@<9@=92@=25@=52@=2A@=AA@A>@ >>@ >9@=9‚C@=CH@=H@@=@7@=7<@=<<@=<C@=CC@=CF@=F:@:A@ A:@ :A@=A:@=:>@=>J@=JF@=F:@=:A@=A:@=:>@=>J@JF@F@@=@9@=9@@=@@@=@<@=<@@=@‚#;@=;A@A4@=4;@=;C@=C4@=4<@<2@=25@5‚#;@=;A@A4@=4;@=;C@=C4@=4<@<2@=25@5…CC@=C…CC@=Cc<@=<C@C<@=<@@=@<@=<4@=4<@<7@=7C@=CC@=CC@=CL@L<@<5@=59@=9E@=EE@=EA@=AA@A<@=<9@=9A@=AE@=EA@=AA@=A4@=4<@=<C@=C7@=7C@ CC@ CC@=CC@CC@=C7@=7<@=<<@<H@=HC@=CC@CH@=HA@=AA@=AM@=MJ@ JJ@ JG@=GM@=MA@AA@=AH@=HH@=H‚#J@=JO@O‚#J@=JO@O00=0ÿ/MTrkìÄÿJAZ2´]<ÿGeneral MIDI´yÿLead´ G[JPÿ @´G@H@I@K@ƒ@”7@7<@=<@@=@C@=CH@=HC@C;@=;4@=4;@=;@@=@D@D@@=@L@LL@=LA@=A9@=9A@=AE@=EJ@=JJ@=JA@=A8@=8A@=AD@=DI@ID@DC7@7<@=<@@=@C@=CH@=HC@C;@=;4@=4;@=;@@=@D@D@@=@L@LL@=LA@=A9@=9A@=AE@=EJ@=JJ@=JA@=A8@=8A@=AD@=DI@ID@D7@=7<@=<7@=7@@=@;@=;4@=47@=7;@=;@@=@;@=;0@=09@=94@=4<@=<9@=9@@=@>@=>5@=59@=9>@=>9@=9>@=>7@=7<@=<7@=7@@=@;@=;4@=47@=7;@=;@@=@;@=;0@=09@=94@=4<@=<9@=9@@=@>@=>5@=59@=9>@=>9@=9>@=>C7@=7<@=<@@=@<@=<C@C@@@<@=<7@=7<@=<@@=@<@=<C@=C>@=>5@=5:@=:>@=>A@=A>@=>2@=2:@=:5@=5>@>:@=:A@=AF@F<@=<4@=4<@ <9@ 9<@=<@@=@<@=<E@EC4@=47@=72@=25@=52@=24@=4/@=/7@=70@=04@42@=25@5C4@=47@=72@=25@=52@=24@=4/@=/7@=70@=04@42@=25@5C0@=0+@=+4@=42@=2/@=/2@=24@40@=04@=40@0C0@=0+@=+4@=42@=2/@=/2@=24@40@=04@=40@0C<@=<@@=@C@=C<@=<4@=4<@=<7@=7@@=@C@=C<@=<5@=59@=9<@=<A@=A<@=<0@=09@=95@=5<@=<A@=A<@=<0@=07@=7<@=<7@=7@@=@C@=C<@=<4@=4<@=<7@7@@=@<@=<C@C34@ 40@=07@=72@=25@=52@=2;@=;5@=5;@=;0@=05@=50@=0C0@05@5-@=-7@=7/@=/;@=;C0@05@5-@=-7@=7/@=/;@=;;@];9@]97@]7<0=<ÿ/MTrk‰²Â ÿJAZ2²H@ÿGeneral MIDIÿBase²n[G@J@I@K@]<ÿ @ƒ’$@<$+@<+(@<(/@:G:C:*>;CGG:C:;:>:*;C>G6;:C:G:>:*>;CG6;:C:G:>:*C;G>>:;:G:C:*>G;C>:;:C:G:*>GC;°G > H:C:@:<:*<HC@H:C:@:<:*<HC@6@:H:<:C:*H@C<6H:<:@:C:*@<HCC:@:H:<:*@C<HC:@:H:<:*@H<C°@ H E:A:<:H:*EA<HE:<:A:H:*AE<H6A:H:E:<:*HA<E6A:H:<:E:*A<EHH:E:<:A:*H<AEA:E:<:H:*°A E<AH°H C:<:@:H:*HC<@<:C:@:H:*<CH@6<:@:H:C:*@<HC6H:@:C:<:*CH<@<:@:C:H:*H@<CC:H:<:@:*<H@C°@ H ;:>:G:C:*G>C;;:C:>:G:*C>;G6G:C:>:;:*>;CG6C:;:G:>:*C>;G>:C:G:;:*CG>;;:>:C:G:*C°G >°> ;GC:@:H:<:*C@<H@:H:C:<:*@<CH6H:@:C:<:*H@<C6@:<:C:H:*H<@C<:@:C:H:*@HC<C:@:H:<:*H<°H @C°@ <:@:C:H:*HC<@@:<:C:H:*@HC<6<:@:C:H:*CH<@6C:@:<:H:*HC<@@:C:H:<:*<@CH<:C:H:@:*<°@ H @HCH:<:C:@:*H@C<C:H:<:@:*CH@<6@:C:<:H:*H<C@6<:@:H:C:*H@C<H:C:@:<:*C@H<C:@:H:<:*C°H @ @<H;:G:C:>:*>CG;;:>:G:C:*C>;G6G:C:>:;:*;>CG6G:>:C:;:*C>G;;:C:>:G:*GC;>;:>:G:C:*G°G ;C°> >C:<:@:H:*H<@CH:<:C:@:*CH<@6@:H:C:<:*H<C@6<:H:@:C:*<C@HH:C:<:@:*CH<@C:H:@:<:*°H @ @<CH<:A:H:E:*HE<AE:<:A:H:*A<HE6H:E:<:A:*<AHE6H:A:E:<:*HA<E<:A:E:H:*HE<AA:H:<:E:*<E°A H AH<:C:H:@:*HC@<H:<:@:C:*C<H@6H:<:@:C:*<CH@6H:C:@:<:*@H<CH:C:@:<:*@C<HH:C:<:@:*CH<°@ @°H G:>:;:C:*C;>GC:G:>:;:*;>GC6;:C:G:>:*G>;C6C:>:G:;:*;>CG>:;:G:C:*;GC>C:G:>:;:*>CG;°G > @:C:H:<:*<C@H@:C:H:<:*H<@C6C:<:H:@:*<CH@6@:<:H:C:*C<H@<:@:H:C:*@<HCC:H:@:<:*H°@ H <C@C:<:@:H:*@<HC<:C:H:@:*@CH<6<:C:H:@:*@HC<6<:C:@:H:*<CH@C:@:<:H:*C@H<C:<:H:@:*@<HC°H @ H:<:@:C:*<@CHC:@:<:H:*@CH<6C:<:H:@:*<CH@6@:H:<:C:*@<HC<:@:H:C:*C<H@H:<:@:C:*HC<°H @ @>:C:;:G:*CG>;;:C:G:>:*>;CG6C:;:>:G:*CG;>6>:;:C:G:*;>CGC:G:;:>:*>GC;;:>:C:G:*°> G CG>;@:H:C:<:*<HC@H:<:@:C:*HC@<6C:<:H:@:*C<@H6<:C:H:@:*@HC<H:@:<:C:*C<@HH:<:@:C:*@C°@ H<°H A:E:<:H:*EAH<H:A:<:E:*H<AE6E:H:<:A:*AH<E6H:E:A:<:*HE<A<:E:A:H:*EHA<H:E:A:<:*H<A°H E°A H:C:<:@:*<HC@<:@:H:C:*C<@H6<:@:C:H:*@<CH6H:<:C:@:*@H<C<:H:C:@:*@<HCC:@:H:<:*°H <CH@°@ ;:>:G:C:*>G;CC:G:;:>:*>CG;6C:;:G:>:*C;>G6C:G:;:>:*>C;G>:;:C:G:*GC>;;:G:>:C:*C>G;°G > <:@:C:H:*<C@H<:H:C:@:*@CH<6H:<:@:C:*@<CH6C:<:@:H:*<C@HH:@:C:<:*<H@C<:H:@:C:*C@H<°H @ <:@:H:C:*@C<H@:C:<:H:*@H<C6@:H:C:<:*H<@C6<:@:C:H:*@HC<C:@:H:<:*C<H@C:H:@:<:*<@CH°H @ <:H:@:C:*H@C<H:C:<:@:*@HC<6@:<:H:C:*CH@<6C:@:H:<:*@<HCH:@:<:C:*C@H<H:C:<:@:*H@C<°@ H >:;:G:C:*;CG>G:>:;:C:*>;CG6G:>:C:;:*>CG;6C:;:G:>:*C;G>G:;:>:C:*>;CG;:G:>:C:*;>G°G > CC:<:H:@:*HC@<H:<:C:@:*@HC<6<:C:H:@:*<CH@6<:C:H:@:*<H@CH:<:@:C:*@CH<<:C:@:H:*@H<C°H @ E:H:A:<:*AEH<E:<:A:H:*EA<H6<:A:E:H:*E<HA6E:<:H:A:*<AEHA:<:H:E:*<EAH<:H:A:E:*A<EH°H A H:@:C:<:*C@H<@:H:<:C:*<H@C6C:<:H:@:*@C<H6<:H:C:@:*HC@<C:@:H:<:*H@C<C:<:H:@:*<°@ CH@°H G:>:;:C:*C;>GG:>:C:;:*>GC;6;:G:C:>:*>CG;6;:C:G:>:*CG;>G:;:C:>:*>C;GG:>:C:;:*;>°> G GC@:<:C:H:*<@CH<:C:H:@:*HC<@6@:<:H:C:*@C<H6C:@:H:<:*H<C@@:H:<:C:*@HC<@:H:C:<:*°@ H@°H C<<:H:C:@:*@H<CH:<:C:@:*HC<@6<:@:H:C:*C@H<6<:H:@:C:*C@<HC:<:@:H:*@CH<<:C:H:@:*HC@<°@ H <:@:H:C:*C<H@<:H:@:C:*H@C<6H:C:<:@:*C<@H6@:C:H:<:*C@<H@:C:<:H:*C<@H@:<:C:H:*CH°H @°@ <>:C:G:;:*;>CG>:;:C:G:*;C>G6G:>:;:C:*>;CG6>:G:;:C:*>GC;C:G:;:>:*CG;>;:G:>:C:*°G > ;>GCC:H:@:<:*<C@HC:<:@:H:*<@HC6H:<:C:@:*CH@<6C:<:H:@:*@<CHC:<:H:@:*C@<HH:@:<:C:*HC<°H @ @A:E:H:<:*A<HEE:H:<:A:*EH<A6A:H:<:E:*H<AE6E:H:A:<:*AEH<E:H:A:<:*AH<E<:A:E:H:*E<A°H H°A @:H:C:<:*@H<C@:<:H:C:*<HC@6@:H:C:<:*C<@H6H:C:@:<:*@CH<H:C:<:@:*<@HCC:H:<:@:*C°@ @H°H <C:>:G:;:*C;G>>:G:;:C:*GC;>6>:;:C:G:*;>CG6G:C:>:;:*GC>;C:;:G:>:*G;C>>:G:C:;:*>C;G°> G H:<:@:C:*@<HCC:@:<:H:*HC<@6H:<:@:C:*@CH<6H:<:@:C:*C<H@H:@:<:C:*<HC@<:H:@:C:*@°@ H H<CC:@:<:H:*@H<CC:<:@:H:*<@CH6@:<:C:H:*@H<C6C:H:@:<:*CH@<<:H:C:@:*<@CH@:C:<:H:*C@H°@ H <H:@:C:<:*HC<@H:@:<:C:*<CH@6@:H:C:<:*HC@<6@:C:H:<:*@<HCH:@:C:<:*<C@HH:@:C:<:*CH@°H <°@ G:;:C:>:*;C>GC:;:>:G:*C>;G6;:>:C:G:*;>GC6G:;:C:>:*GC>;G:;:C:>:*G;C>C:G:>:;:*C;>G°> G C:<:@:H:*H<@C@:H:C:<:*<@HC6<:@:C:H:*H<C@6<:H:@:C:*<HC@C:@:<:H:*<@HC<:C:H:@:*C<@°@ H°H E:H:<:A:*AHE<<:H:E:A:*EA<H6A:H:<:E:*<EHA6<:E:A:H:*HEA<<:E:H:A:*HEA<E:A:H:<:*A°A E<H°H @:H:C:<:*CH@<@:<:C:H:*C<@H6<:@:H:C:*@CH<6@:H:<:C:*CH<@C:@:<:H:*<@CHC:H:@:<:*C@<H°@ H ;:G:C:>:*CG;>C:>:G:;:*;CG>6G:C:;:>:*G;C>6G:>:;:C:*CG>;G:>:;:C:*;G>CC:G:>:;:*°G > C;G>@:H:<:C:*C<H@H:@:C:<:*@<CH6<:H:@:C:*C@H<6<:C:@:H:*HC@<<:C:H:@:*H@C<<:C:@:H:*H@°H @ C<@:H:<:C:*H<C@@:C:H:<:*H<C@6<:H:C:@:*C<H@6<:H:@:C:*<H@CC:H:<:@:*<C@HC:H:@:<:*°H @ H@C<@:H:<:C:*<CH@C:H:@:<:*CH<@6H:<:C:@:*@HC<6@:H:<:C:*<H@C@:C:H:<:*@H<C<:@:C:H:*C@°@ H <H;:G:C:>:*>;CGG:;:>:C:*>;GC6C:;:>:G:*;>CG6>:C:G:;:*;>CGG:>:;:C:*CG>;C:;:G:>:*>°> G CG;H:C:@:<:*<@CH<:H:@:C:*HC@<6@:<:H:C:*@H<C6H:<:C:@:*HC@<<:C:@:H:*<@HCH:C:@:<:*C<°@ @H°H H:E:<:A:*HA<EA:E:<:H:*E<HA6A:H:E:<:*A<HE6H:<:A:E:*<HEAA:<:E:H:*HAE<A:H:E:<:*°H A E<HAC:H:<:@:*H@<CC:@:<:H:*H<C@6@:<:C:H:*HC<@6C:<:@:H:*HC@<H:<:C:@:*C<H@@:H:<:C:*@<CH°@ H G:>:C:;:*C>G;>:C:;:G:*G>;C6C:>:;:G:*;C>G6G:;:C:>:*>;GCG:>:C:;:*C;>G;:C:>:G:*GC>;°> G <:C:H:@:*<C@HH:<:@:C:*<H@C6@:C:<:H:*H@<C6<:H:C:@:*H@C<C:@:<:H:*@<CH<:@:H:C:*@C°@ H<°H C:H:@:<:*<C@H@:C:H:<:*C<H@6C:<:@:H:*HC<@6@:<:H:C:*@C<HH:C:<:@:*H<@CC:@:H:<:*<HC@°H @ C:H:<:@:*<H@CH:<:C:@:*@H<C6<:@:H:C:*H<C@6@:C:<:H:*<C@H<:C:H:@:*CH@<<:C:H:@:*CH<@°H @ C:;:G:>:*C;G>G:;:C:>:*C;G>6>:C:;:G:*CG>;6;:C:>:G:*;G>CC:>:G:;:*>;GC>:G:;:C:*C>G;°G > H:@:C:<:*<H@C<:C:@:H:*C<H@6C:H:@:<:*@HC<6C:@:<:H:*<@HCH:@:C:<:*C@H<C:H:<:@:*°@ H<@°H CE:H:<:A:*EAH<<:E:H:A:*EAH<6H:<:E:A:*HAE<6H:<:A:E:*EHA<A:E:<:H:*<EAH<:E:H:A:*°H A HE<A<:C:@:H:*@H<CH:<:C:@:*<HC@6C:@:H:<:*<C@H6H:@:C:<:*C<H@<:@:H:C:*H<@C<:H:@:C:*CH@<°H @ ;:C:>:G:*C;G>>:G:;:C:*>CG;6;:G:>:C:*>;CG6G:>:C:;:*>;GC>:C:G:;:*C>G;>:G:C:;:*;GC>°G > @:<:H:C:*@C<H@:H:C:<:*<@CH6<:C:H:@:*<HC@6C:<:H:@:*<@CHH:C:@:<:*@HC<@:H:C:<:*<H@°H @ CC:<:H:@:*H<C@@:C:H:<:*C<H@6@:C:H:<:*HC@<6C:<:@:H:*@CH<@:H:C:<:*H@<C@:C:H:<:*°@ <H@C°H <:C:@:H:*C@H<C:H:@:<:*C<H@6<:@:C:H:*<@HC6@:H:C:<:*C<H@@:H:C:<:*CH@<<:@:C:H:*HC@<°@ H >:C:G:;:*>G;C>:C:G:;:*;>GC6;:G:C:>:*>;GC6;:>:G:C:*G>;CG:C:>:;:*>CG;G:;:C:>:*°G > GC;>@:C:H:<:*<CH@H:<:C:@:*CH@<6C:@:H:<:*@<CH6H:@:<:C:*H<C@H:@:C:<:*<HC@@:<:C:H:*HC°H @ <@A:H:E:<:*EA<HE:H:A:<:*EAH<6E:A:<:H:*E<HA6<:A:E:H:*AHE<E:A:<:H:*EHA<E:A:<:H:*AHE<°A H H:C:<:@:*<H@C<:H:@:C:*C@H<6H:C:@:<:*H<@C6H:<:C:@:*<@CH<:@:H:C:*C<@H@:C:<:H:*HC@<°@ H G:>:;:C:*G;C>>:;:C:G:*;GC>6;:>:G:C:*>GC;6>:;:C:G:*;G>C>:;:G:C:*;G>C;:G:C:>:*G;C>°G > @:H:C:<:*H<@C<:@:H:C:*<C@H6H:C:@:<:*C@<H6<:H:@:C:*@CH<C:H:@:<:*CH@<H:@:<:C:*°H @ <@CH@:<:H:C:*C<@H@:C:<:H:*<H@C6@:C:H:<:*H@C<6C:H:<:@:*C@H<@:C:<:H:*@H<CC9H9<9@9*°H H°@ C@<@8C8H8<8*@C<H<7@7C7H7*<@HC6@4<4C4H4*@CH<6<2@2H2C2*@<HC@1H1<1C1*H<C@@0H0<0C0*°@ C@H<°H <.@.H.C.*@<HC@-H-<-C-*@<CH6C+@+H+<+*C@<H6@(C(<(H(*H<@C@'H'<'C'*<CH@C&H&<&@&*°@ @<°H CH<%H%@%C%*CH@<H$@$C$<$*<HC@6C!T$ $<*$$:T$ $8*$$7*$$6*$Å"•$4T$ $2*$$1T$ $.*$$-*$$,*Å"•$$+T$ $(*$$'T$ $%*$$$*$$"*Å"•$$!T$ $*$$T$ $*$$*$$*$ÿ/MTrk1¹¹cb @cb!@ÉÿJAZ2ÿDrums¹oÿ @@ÿGeneral MIDI¹][( Q`™*959#90.959#9*5#05*9.#(9690.959#96*(#.5(9#9(*959(9*#5#9.9(590(9*9#569.0#9(59*.960##9*9.59505#9.9*59#0#569(9.*90*596.9(#9#(95.#959*9((9*#5#959(.905.*9(9#690.9596*#9(0#5*9#9.590*#.9#955905#(969.*90*6#959(.9(9.#5#9*9(59#*5(959.9(#905#(9*9.690*6.959(#90.*9#9(9559#05(*59.9(9##905.(69*9#(90*(9#9.9659(5.(#(9(59(9#9*9#*(95(59.9(#9(95(#.(9*9(9(696(9*(.9(9#9(59(9(.#5#9*9(5905#59.9*#90.(969#*950(*59.96#9#(95.59#9(*9#5*(959#9(.905.(969#*906*#959(.90#.*9595#90*5#9.9#590#5*969.(90(659.9*#9.#(95*9#9(59#*5(959.9(#905.*969#(90*(#9596.905.#9*9#590#*.9595#90#5*9(9.6906(59.9*#9.5#(9#959(*95*(9##959(.90#.69(95*90(659#9*.905#(9*9#9.590*(59#9(9#.9505(#(969.*90(*(9.9596#9#5(.(9(9#9*9(59*#(5(9.9(9#9(59(9#.5(*9(9(69(96*((9#959(.9#(95.(59*9(#90*5.959##905.(969#*90*659.9(#95.(9#59*9(#95#(9*59.9(#90#*9(9.5690(59#9*.960.*95#9#590*#959#.9505.69(9#*906(.9#9*59.5#(9#9*9(595(9#*#9.9(590.#69*95(90(659#9*.905.59#9#*905#.9#9*590#5*9(9.690(*59#96.95#.(959*9(#95#(9*#9.959(0(9#*9.6950*59#96.9(05*9#9#59.(90*5(#9(9.9#590(#5*969.(906*59(9.9(#9.#5((9#959((9*95(*#(959(9.9(#9.#5(9(69(9(*9(*6(959(9#9(.9#(9.5(59*9(#90#559.9*#90#.*9(956906*59.9(#95.(9##959(*95*#(959.9(#905.*969#(90*6#9.9(5905##959.*90*5.9#9#590.#69(95*90*(59.96#9.5(9#59#9(*9*(9#559#9(.90.#69(95*90(*.9#965905.#9*9#590#*.9#955905.(9*9#6906(#959*.9(9#.5#9*9(59#5*(959#9(.90#5(9*9.690(#9596.9*0##9*9595.(90*5((959#9#.90(.5*969#(90*(#9(9.9659#.(5(9*9(9#9(59#*(5(9(959#9(.9#.((95(969(*9(6*(959.9(9(#9(#5(9.*959(#905#59.9*#905.(9*9#6906(.959*#9.(95#*959(#9*#(95#959(.905#*9(9.690(6.959*#905#*9#9.5905*#9.9#5905#(9*9.6906(.959*#95#(9.#9*9(59*5#(9.959(#905.69(9#*90(*#9596.90&9.5#&9&&&9&9&&-9-9---9--9+9-+9+++9++9)9+)9)))9))9#9*9(9)590(#*#9.9(95590(#.*9(95690*((9.9#9659.#(5(9#9(959(*95*(#(9.9(9#9(59(9.(5#69(9(*96((9*#9(9.9(59.5#((9*959(#90#5#959*.90#569*9.(90*(.9596#9.#5(9#959(*9(95*#59.9(#905#69(9.*90*6.959(#905#59#9.*90#559.9*#90#.*9695(906(59#9*.9.(9#559#9(*95#*(9#959(.90#569(9.*90*(#9.96590.5#959#*905*#959#.90#.*9695(906(#959*.9#.5(959#9(*95(9#*.959(#90.#69(95*906(#9.9*590#.*9#9595(905(#(9#959*.905#(*969.(906(59(9#9*.9(.5#(959(9#9(*95*#((9(959#9(.9(#5(9.*969((9(9*6(.9#959((9.#((95#959(*90#*.9595#90.#69(95*906(#9.9*59.#(9559#9(*9#5*(9.9#9(590#.(9695*906*#9.9(590.*9595#9#0#5#9*59.90*9.(9695#0(*59.96#95(9.##959(*95*#(959#9(.905#(9*9.690*(#9.96590.#59*95#905*.959##90#569(9.*90(6#9.9*59.#5(9#959(*9*(95#59#9(.90#.*9695(906#959(.9*0.#(9*9#95590*(559(9.9##905#.(969(*90*(59(9.96#9.5(#(959*9#9((9#*5((959(9.9(#95#(9.(69(9(*9(6*(9.9#9(9(59.5((9#59#9(*90*5.9#9#590.569(9#*90(659#9*.95#.(959#9(*9#(95*59.9(#90#.*9695(90(659.9*#90.5#9*9#5905#.9#9*590#5*9(9.690(*59#96.9#5(9.59*9(#9#*(95#959(.90#.*9695(90(659.9*#90#559*9.#90*5#959#.905#*969.(906*#959(.9.(9#559#9(*9#(95*.9#9(5905.69*9#(906(#959*.905.#9(959#*90*#559#9(9(.905.((969#*90*(.959#96(9#.(5(9#9(959(*9(#*5(9.9#959((9(9#(.5*9(9(69*(6(9(959.9(#9.(95(#59#9(*90*5#9.9#590.*969#(9506*.959(#95(9#.#959(*9#*5(9.959(#90.569(9#*906(59.9*#90.5#959#*90*5.959##905.(9*9#6906(.9#9*595.(9#*9#9(595#(9*.959(#90.5*9(9#6906(59#9*.90#5#959.*90*5#959#.905#*9(9.690(*59.96#9(9.#5*959(#9*#5(959#9(.905#69*9.(90(*59.96#90#5#9*959.(905(.959#9#(9*0(5.*969#(906(#9.959*(9.#(5(9(9*959(#9(#*5(9#959(9(.95#.((9*969((96((9*59.9#9((9.5(#(959*9(#905*#9.9#590.#(9*95690*(59#96.9(9.#5*9#9(595#(9*59#9(.90.569*9#(90*6#9.9(590.#59#95*905*59#9#.90#5*969.(906*#9.9(59#(9.5#959(*9#*5(9#959(.90#5(9*9.6906*.9#9(590#.#9595*90*5#9.9#590.#69(95*90(6#9.9*59#(9.5*959(#9#5(9*#959(.905.69*9#(90*6#959(.90#5(9#9*9.590#5((9.9#9*5905.(69(9#*90(*59.9#96(9.5(#(9*9#9(9(59*(5#(9(959.9(#9#.(95((9*9(69(9(*6(9#9.9(59(5.(9#*959(#905##959*.905#*9(9.690(*59#96.9.5(9##959(*9(9#*5#959(.90#569*9.(906(59.9*#90.5*959##90*#.9#95590#.(9695*90(*59#96.9.5(9#59#9(*9*#(95.9#9(5905.(9*9#690*(59.96#90.5*959##90*#.9#95590#.(9695*906(#959*.9.#(95#959(*9(9#*559.9(#905.69(9#*906*59.9(#90#5*9(959.#90*5(#9(9.9#5905(#*969.(906(.9#9(9*59#.5((9*959#9((95#(*(959#9(9(.9(9#5.(*9(9(69(6(9*#959.9((95#(.(9*959(#90*5#959#.905#*969.(906*59#9(.9.5(9#59#9(*9*#(95#9.9(590.569*9#(90*6.9#9(590#.#9595*90#*#9595.905#69*9.(90*6#9.9(59#(9.559*9(#95#*(9#9.9(590#.(9*956906*.959(#905.*959##90#5#959*.905#(9*9.690*(59#96.95(9#.*959(#9#5(9*59.9(#90.#(9695*906(.9#9*590.#*9(9#95590(5*(9#959#.90.#((9*95690*6#9(959(.9(#.5(9(959#9(*9(#*5(9.959(9(#9#((95.69*9((9(96*(#959.9((9#(.(9559#9(*90#*59#95.90#5(9*9.690*(59.96#9#5(9.#9*9(59(9#5*#959(.90#569*9.(906(.9#9*590#.*9595#90*#.9595#905.*9(9#690*6.9#9(595.(9#*959(#9#5(9*.9#9(5905.69*9#(90*6#959(.905##9*9.590#5.959*#905.(9*9#690*(.9596#9#.(95#9*9(59(9#5*.9#9(590.#(9695*90(*#9.965905#59#9*9.(905*##9.959((90(.#*9(95690(6.9(9#9*59(.5#(9#9*9(9(59*(5#(9(959.9(#9(95(#.69(9(*9(*(96(959#9(.95(.#(9*9#9(590*##9.95590.#(9695*906(#9.9*595#(9.*959(#9#5(9*59#9(.90#.*9(95690(*#9.96590.#59#95*905*59#9#.90#5(969.*906(.9#9*59.(9#559*9(#95#*(959.9(#905.*9(9#6906(#9.9*590.##9*955905*59.9##90.5(969#*906(59.9*#95(9.#*959(#9#5(9*#959(.905.(969#*906(.959*#90.5(9#9*9#590#5(#9(9.9*5905(#*9(9.690(6(9#9.9*59#(5.(9(9*9#9(59(#5*(9(9.9#9(595#(9.((9*9(69(9(*6(9#9.9(59(5.(9##9*9(590*5.959##905.69(9#*90(6.959*#9#.(95#959(*9(9#*5#9.9(590#.*9(95690*6#9.9(590.#*9595#90*#59#95.90#5(969.*90(*.9#96595.(9#59*9(#9#*(95#959(.90.#(9695*906(#9.9*590.#59#95*905*59.9##90.5*9(9#690(*.9596#9#.(95#959(*9(9#*5.959(#90.569(9#*906*#959(.90.##9*9(95590#(*59#9.95(90(#569*9.(90*((959#96.95(.#(9*959(9(#95(#*(9#9.9(9(59(9.#5(69*9((9*((9659#9.9((9#5(.(959*9(#905*#959#.905#*969.(906*.959(#9#.(95*959(#9#5(9*.959(#905#69(9.*90(659.9*#90.559#9#*905*59.9##90.5*969#(906*#9.9(59#(9.5#9*9(59#5*(9.959(#90.5(9*9#6906*.9#9(590#.59#95*90*#.9#95590#.*9695(906*#959(.9#(95.#9*9(595*(9##9.9(590.569*9#(90*6#959(.90#5*9(959.#90(#*(959#95.90.5(*969#(906((9.9#9*59.(5#(959#9*9((95*(#(959.9(9(#9#((9.5*9(9(69(9*(6(9.959(#9(#5(9.59#9(*90#*59.95#90.5*9(9#690(*.9596#9#.(95*959(#9(9*#5.9#9(590.#(9695*90(*59.96#90.5*959##90*##9.95590.#*9(95690*6#959(.9.#(95*959(#9#5(9*59#9(.90.5*969#(906*.9#9(590#.59#95*905*59.9##90.569(9#*90(6.959*#9#.(95*9#9(59(9*5#.9#9(590.#*9695(90*(59.96#90#5(959*9.#90(*5(959.9##90#5((969.*906*.959(9(#95.#((9*9(9#9(59(#5*(9#959(9(.9(95#.(*9(9(69(6(9*(959#9(.95(.#(959*9(#905*.9#9#590#.*9695(906*.9#9(595.(9#*959(#9#5(9*#959(.905.*969#(906*#9.9(590.#59#95*905*.959##905.*9(9#690(*#9.9659#(9.5*959(#9*#5(9.959(#90.569*9#(90(*59.96#90.559#9#*90*#59#95.90#5(9*9.690*(#9.9659#(9.5*959(#9#5(9*.959(#905#69*9.(90*6#959(.90#5#9(959.*90(*#59(9#95.90.(5*969#(906((959.9*#95(#.(9*9#959((9*5(#(9#9.959((9(5(9.#(969(*9(9(6*58.8#8((85(#(8.#7*7(570*5#6.6#560.#65*55(50*6.3#3(535.(3#52*2(#2(25#*.1#1(510.#*0(05600*6#/./(5/0.#*-5-5#-05*5,.,##,0.5*+(+#6+0(*#*.*65*().5#5)*)(#)#*((5#'5'(.'0.#6&*&5(&0*65%.%(#%0.#5/$/#//)#0)!))!)) ))) +)++0+00/0//-/--#*5-`#5.5*#`6.5(*#`.#5*6(05#.(0(ÿ/MTrk5°ÿJAZ2ÿSimutrans B themeÿ/simutrans-124.3/simutrans/music/05-Boring-afternoon.mid000066400000000000000000002365661474050137200230700ustar00rootroot00000000000000MThdÀMTrkmÿ(c) shunter 2006ð~ ÷ÿJAZ2ÿQŠÿ 2006.10.06ÿ‡êÿQ 6…~ÿQŠÿ/MTrk_°cbrcb rcb rcbc@cbd@cbf@ed ÀÿJAZ2ÿ/MTrk k°ÀÿJAZ2°]ÿGeneral MIDIÿLead° >[gÿYÿÿÿ @@Q?Q‚Q?Qƒ@M?@M O?@O M?@M L?@L J?ˆJ…H‚>>?>@@?@@ A?@A`A?A@C?C@E?E@CHC@>?ˆ>‚<>H‚>>?>@@?@@ A?@A`C?C@E?E@J?J@H?ˆHƒ|J?J@J?@J J?@J`E?E@H?H@H?@H H?ƒH`G?G@F?@F F?@F`C?C@E?E@E?@E E?ƒE`>?‚>>?>@@?@@ A?@A`A?A@C?C@E?E@C?‚C@?`>?@> ? @†>Œ@>?‚>>?>@@?@@ A?@A`A?A@C?C@E?E@CHC@>6ˆ>‚<>?‚>>?>@@?@@ A?@A`C?C@E?E@J?J@H?ˆHƒ|J?J@J?@J J?@J`E?E@H?H@H?@H H?ƒH`G?G@F?@F F?@F F?F@C?C@E?E@E?@E E?ƒE`>?‚>>?>@@?@@ A?@A`A?A@C?C@E?E@C?‚CA?@@?@@ >? A†@>ŒJ?J@J?@J J?@J`L?L@MHM@L?@L J?@J`E?E@JHˆJƒ|H?H@H?@H H?@H`J?J@LHL@J?@J H?@H`FHF@E6ˆEƒ|C?‚CC?C@E?@E F?„F‚`H?‚HH?H@J?@J L?„L‚`J?J@J?‚JL?L@ML‚L?hM@LXJ?(JXL?ˆLƒ|J?J@J?@J J?@J`L?L@MHM@L?@L J?@J`E?E@J?ˆJƒ|H?H@H?@H H?@H`J?J@LHL@J?@J H?@H`FHF@E6ˆEƒ|C?‚CC?C@E?@E F?„F‚`H?‚HH?H@J?@J L?„L‚`J?J@J?‚J`M?M`LL‚J?dLDJ\H?(HPJ?†@J¯@>H‚>>?>@@?@@ A?@A`A?A@C?C@E?E@CHC@>6ˆ>‚<>?‚>>?>@@?@@ A?@A`C?C@E?E@JHJ@H?ˆHƒ|J?J@J?@J J?@J`E?E@H?H@H?@H H?ƒH`G?G@F?@F F?@F`C?C@E?E@E?@E E?ƒE`>?‚>>?>@@?@@ A?@A`A?A@C?C@E?E@CH‚C@H`>?@> ? @†>Œ@>H‚>>?>@@?@@ A?@A`A?A@C?C@E?E@CHC@>6ˆ>‚<>?‚>>?>@@?@@ A?@A`C?C@E?E@JHJ@H6ˆHƒ|J?J@J?@J J?@J`E?E@H?H@H?@H H?ƒH`G?G@F?@F F?@F F?F@C?C@E?E@E?@E E?ƒE`>?‚>>?>@@?@@ A?@A`A?A@C?C@E?E@C?‚CAH@@?@@ >? A†>Œ@J?J@J?@J J?@J`L?L@MHM@L?@L JH@J`E?E@J6ˆJƒ|H?H@H?@H H?@H`J?J@LHL@J?@J H?@H`FHF@E6ˆEƒ|C?‚CC?C@E?@E F?„F‚`H?‚HH?H@J?@J L?„L‚`J?J@J?‚JL?L@ML‚L?hM@LXJ?(JXL?ˆLƒ|J?J@J?@J J?@J`L?L@MHM@L?@L JH@J`E?E@J6ˆJƒ|H?H@H?@H H?@H`J?J@LHL@J?@J HH@H`FHF@E6ˆEƒ|C?‚CC?C@E?@E F?„F‚`H?‚HH?H@J?@J L?„L‚`J?J@J?‚J`M?M`LL‚J?dLDJ\H?(HPJ?†@J“Q?Q‚Q?Qƒ@M?@M O?@O M?@M L?@L J?ˆJ…±@‘4=04>±@‘=M4±@‘=04B=S±@‘4±@‘=04B±@‘=S4=±@0@‘4B=S4=±@0‘=S4B±@@‘=40->5M±@‘5-±@0‘5M±@‘->-±@‘50-:±@‘5H5±@‘-05H-:±@‘-±@‘5 ±@‘9E2:2±@‘909E±@‘2:9±@‘20±@‘2:9E2±@‘90±@‘2:9E±@‘9202:9E±@‘2±@‘902:9E±@@‘2909E2:±@‘29±@0@‘2:9E29±@ @‘-75E±@‘5-0-7±@‘5E5-±@0‘5E±@‘-7-5±@0@‘-75E±@‘-5027:E±@‘:±@‘2027:E±@‘2:±@0‘27±@‘:E2±@‘:027:E±@‘2±@‘: :E±@‘27±@‘:20±@‘:E27±@‘:20±@‘27:E:2±@0@‘27:E2±@‘: 47474±@P@‘>7±@‘>7 ±@‘7>P74C4±@P@‘C77C±@@‘C7P±@‘74>4@>±@‘77(±@‘>*±@‘7>P±@‘C474PC7±@‘C(±@‘7±@‘C7P@+9+±@P@‘9@@*9.±@‘9@±@0@‘@697P@±@‘99*±@‘@.P9@±@‘9+@(±@ ‘@0±@‘9p9*@7±@P‘9@±@@‘2"9.P±@‘292!±@‘9$9±@‘2 ±@‘912$P2±@‘9±@‘2090P92±@@‘9-2% 9±@‘2±@‘2+9%P2±@‘924±@‘94@92±@‘9 24±@@‘92P>4±@‘24@>±@‘2>"±@‘24>2±@P‘2494±@@‘2±@‘9 ±@‘2 9$2±@‘9P24>4±@@‘2±@‘>2>$±@@‘2>P94±@‘24P±@‘92±@‘2 99±@‘2P±@‘>424P2±@‘>2±@‘>>2±@P@‘2494@92±@‘9*2(±@@‘92P24>4±@P‘>±@‘2±@‘>(2>±@‘2P2797±@P@‘922"9±@‘9±@‘2P27±@‘>7P>2±@@‘2> 2±@‘>P2:±@‘9:@9±@‘2±@‘9/2-29±@P@‘>:2:P±@‘>2>-2±@‘>2±@P‘@494±@P@‘@9±@‘@2979@±@0‘@@±@‘9CP±@‘9@93@7±@P@‘9@94@0±@ ‘@0±@‘9p92±@‘@BP±@‘9@±@‘94@4P9±@‘@@,97±@P@‘9@@.9,±@P‘@9±@@‘@>97P@±@‘9±@‘@191P9@±@‘9±@‘@,P@±@‘9@.±@‘9,P9±@‘@9%@'±@Ô`‘93@3@9@@9±@‘93@±@‘9±@‘@PC3±@‘93@C9±@‘93±@‘C!C9±@P‘93@3±@@‘9@±@ @‘@#9@9±@P‘C393±@@‘9C±@@‘9C#±@‘C9P93@3±@@‘@9±@‘93±@‘@±@‘9@P93±@‘C3@C9±@@‘93C!9±@‘CP±@‘@393@@9±@ @‘9@#9@±@P@‘C393@9C±@‘C#±@‘9±@‘9CP9323±@@‘9±@‘223±@‘929±@P‘>3±@‘23@>2±@‘>!±@‘23>2±@P‘23±@‘93@92±@ ‘29#±@‘29±@P‘23>3±@@‘2±@‘>>#2±@‘>±@‘2P24±@‘94@9±@‘29 24±@‘92±@P‘24>4±@@‘>2±@@‘>"24>±@‘2P24±@‘94@±@‘29 9$±@‘2 2±@‘9P>424±@@‘2±@‘>2>$±@@‘2>P94±@‘24P±@‘92±@‘92 ±@‘92P>4±@‘24P±@‘2>>2±@‘>±@‘2P2494±@@‘92±@‘2(±@‘9*±@‘92P>424±@P‘2±@‘>2>(±@@‘2>P±@‘9424@92±@@‘249 92±@P‘>4±@‘24@>±@‘224>"±@@‘2>P±@‘2494@9±@‘2 9$±@‘2 92±@P‘>424±@@‘2>±@‘>$2±@@‘2>P54±@‘<4P<5±@‘5 <±@‘<±@‘5P±@‘A454PA5±@‘A5±@‘A5±@P@‘54<4@<±@‘55(<*±@@‘<5P±@‘A454PA5±@‘A(±@‘5±@‘A5P54<4±@@‘<5±@‘54< ±@‘<±@‘5P54A4±@@‘A±@‘5A"±@‘545A±@P@‘54<4@±@‘<5 <$±@‘5 <±@‘5PA4±@‘54@5±@‘A5A$±@‘A±@‘5P2494±@P‘2±@‘9±@‘92 29±@P‘24>4±@P‘>±@‘2±@‘2>2±@‘>P2494±@@‘92±@‘9*2(±@@‘92P24>4±@P@‘2>>(2±@‘>±@‘2P2494±@@‘9±@‘29 24±@@‘92P±@‘24>4@>±@‘2>"24±@‘2±@‘>P>424±@@@‘>2 ±@‘2 >$±@‘>2P>424±@@‘2±@‘>2±@‘>$>±@‘2P>4±@‘74P7>±@‘7 ±@‘>>±@‘7P±@‘C474P7C±@@‘7C±@‘C7P±@‘74C4@C±@‘77(±@‘C*±@‘C7P±@‘74C4PC7±@‘C(±@‘7C7±@P‘>4±@‘74@>7±@@‘> 747±@‘>P74±@‘C4@C±@‘774C"±@@‘C7P74±@‘>4@7>±@ @‘7 >$7±@‘>P74C4±@@‘7±@‘CC$7±@@‘7CP±@‘<4C4P±@‘<CC±@‘< C±@‘<P<4±@P@‘<±@‘<<±@P‘<4±@‘C4@C<±@‘C*<(±@‘C<±@P@‘<4P±@‘<<±@@‘<P94±@‘@4@@±@‘9@ 94±@@‘9@PE4±@‘94@E±@‘9E"94±@‘9E±@P‘94@4±@@@‘9@ @$9 ±@‘9±@‘@PC494±@@‘9C±@@‘C$9C9±@P@‘9424P2±@‘9±@‘2 9±@‘92P>424±@P‘2>±@‘2>±@@‘2>P2494±@@‘92±@@‘2(9*2±@‘9P±@‘>424P>±@‘2>(±@‘22±@‘>P93±@‘@3@@±@‘9±@‘@93±@‘9@PC393±@@‘C9±@@‘93C!±@‘9CP93@3±@@@‘9@ ±@‘9@#±@‘9@P93±@‘C3@9C±@‘C#9±@‘C9±@P‘93±@‘23@9±@‘2239±@‘92±@P‘23>3±@@‘>±@‘2±@‘23>!2±@‘>P± "@]2HK[2J<Cƒ‘2:±@‘9E29±@0‘9E±@‘2:2±@‘909E±@‘2:2±@‘909E2:±@‘29±@0‘-5691±@‘9±@‘5-P±@‘9:58-,P95-±@@‘58-#91-±@‘59P9?-,±@‘5?P5±@‘-959±@‘-/995±@‘-9P5;±@‘9;-/P±@‘-59-/9;5;±@@‘9-5T±@‘5J-;9J„45?-29?5-9O59±@‘--2±@‘5?9?±@‘59-T5O±@‘-?9OT9M2A99209M2A2909H2=92±@‘5-/±@‘2=9H29±@0‘->5M±@‘-5±@0‘->5M±@‘5-±@0‘-B±@‘5S5±@‘-0±@‘-B5S-±@‘5 -B5S±@@‘-50±@‘5S-B-5±@0‘5S-B±@‘-5±@0‘-B±@‘5S-±@‘5 4B=S±@‘=±@‘404B=S±@‘4±@‘=0±@‘4B=S4=±@0‘4B=S±@‘4=±@0@‘=S4B±@‘=404B=S±@‘4=±@0@‘=S4B±@‘4=04B=S±@‘=4±@0@‘5M->5±@‘-0±@‘5M->-5±@0@‘5H-:5-±@0‘-:±@‘5H-5±@ @‘9E2:29±@0‘9E±@‘2:2±@‘909E±@‘2:±@‘9209E2:±@@‘920±@‘7:>E>7±@0‘>E±@‘7:>7±@0‘>E7:±@‘>7±@0‘7:±@‘>E7±@‘> 27:E±@‘:2±@0‘27±@‘:E:2±@0‘:E±@‘27±@‘:20:E±@‘272:±@0@‘27:E2:±@0‘27:E±@@‘:2027:E±@‘:2±@0‘27±@‘:E2±@‘: >L±@‘7C@>7±@@‘7C>6±@‘>7P±@‘7KP7±@‘7K±@‘7±@P@‘7K@±@‘7 73±@‘7±@P@‘7K@7±@ @‘7/7±@P‘E7:>±@‘70±@‘7:>E>7±@0‘>E7:±@@‘>70±@‘>E7:7±@‘> @=±@‘419,49±@‘@ ±@‘47@E91 94±@‘@9,@=41±@‘49@±@ ‘@=±@‘9,419±@‘@40±@‘-75E5±@‘-0±@‘-75E±@‘-50-7±@‘5E-5±@0‘5E±@‘-7±@‘5-02:9E±@@‘2902:9E±@@‘9209E±@‘2:±@‘9202:9E±@‘9±@‘20@E±@‘9:±@‘9@09:@E±@@‘@90±@‘@E9:@9±@0‘@E9:±@‘9@±@ @‘5E-75±@‘-05E±@‘-7±@‘-505E±@‘-7±@‘-50-7±@‘5E5±@‘-0±@‘9/@A444±@‘@9 @H4:±@‘94 94@±@‘@E9147±@‘94@±@ ‘9147±@‘@E49@±@0‘4;@J95±@‘4@9±@ ‘@S4B±@‘9; 94±@‘@@J±@‘4;9549±@‘@ @J954;±@‘49@±@0‘->±@‘5M-±@‘50±@‘5M->5-±@0‘5H±@‘-:5±@‘-0±@‘-:5H-±@‘509E±@‘2:2±@‘909E±@‘2:±@‘2909E±@‘2:9±@‘209E2:±@@‘290±@‘7:>E7±@‘>0±@‘7:>E7>±@0‘7:±@‘>E>±@‘70±@‘7:>E7>±@ @‘:E27±@‘2:027±@‘:E±@‘:20±@‘27:E:2±@0‘27:E±@‘:2±@0‘:E27±@‘:2±@0@‘27:E2:±@0‘:E±@‘27:±@‘20±@‘:E272±@‘: 7C±@‘>L@>7±@@‘7C>6>±@‘7P±@‘7KP±@‘7±@‘7K±@‘7P7K±@@@‘7 73±@@‘7P±@‘7K@±@‘7 7/±@@‘7P±@‘E7±@‘>0±@‘7:>E±@‘>70>E7:±@‘>±@‘70±@‘7:>E7>±@ ‘9,@=±@‘414±@‘9@ ±@‘47@E91 94±@‘@9,@=±@‘4149±@‘@ 9,@=±@‘41±@‘94@05E-7±@‘5±@‘-05E±@‘-75-±@0@C]2[2HKJ< "ƒ@‘9424@9±@‘2249 ±@‘9±@‘2P±@‘24>4@>2±@‘24±@‘>">±@‘2P±@‘9424@92±@ @‘9$2 92±@P‘>4±@‘24@2>±@‘>$2±@‘2>±@P@‘9424P±@‘9292 ±@@‘29P>4±@‘24P±@‘>2>±@‘2±@‘>2P±@‘9424@92±@‘2(9*±@@‘92P>424±@P‘2±@‘>>(2±@‘2>±@P@‘2494@92±@@‘249 ±@‘92P24±@‘>4@>2±@‘24±@‘>"±@‘>2P9424±@@@‘92 2 9$±@‘92±@P@‘24>4@2±@‘>>$±@‘2>2±@P@‘95@5@@9±@@‘@ 95±@‘@9PC5±@‘95@C9±@‘95C"±@@‘9CP99@9±@@@‘9@ ±@‘@'9#±@‘9@P99C9±@@‘9C±@‘C'9±@‘9C±@P‘@=±@‘9=@@±@‘9@%±@‘9=9@±@P@‘C=9=@C9±@‘9=±@‘C'C±@‘9P@=9=±@@‘9±@‘@ ±@‘9%@*±@‘@9P±@‘9=C=@9C±@‘9!C*±@@‘9CP99±@‘29@9±@‘2299#±@‘2±@‘9P29±@‘>9@>2±@@‘>%29±@‘2>P25±@‘95@±@‘29 ±@‘9%2 2±@‘9P25>5±@@‘2>±@‘2>%±@‘>2±@P‘2494±@@‘9±@‘2249 ±@‘2±@‘9P±@‘24>4@>±@‘224>"±@@‘>2P24±@‘94@±@‘92 ±@‘9$2 92±@P‘24>4±@@‘2±@‘>>$±@‘22±@‘>P2494±@P@‘29±@‘92 9±@‘2P>4±@‘24P>±@‘2±@‘2>>2±@P‘94±@‘24@9±@‘22(9*±@@‘92P24>4±@P‘2>±@‘>(2±@‘>2±@P‘94±@‘24@9±@‘2±@‘249 ±@‘92P>424±@@‘>2±@@‘24>">2±@P@‘9424@2±@‘9 ±@‘2 9$±@‘29P24>4±@@‘2±@‘>>$±@‘2±@‘>2P<4±@‘54P<5±@@‘<5 5<±@P@‘54A4P±@‘5A5±@‘A±@‘5AP±@‘54<4@<5±@@‘5(<*<±@‘5P54A4±@P‘A5±@‘A(±@‘5A±@‘5P±@‘<454@<5±@‘54< ±@@‘<5P±@‘A454@A±@‘5±@‘A"545A±@P‘54±@‘<4@±@‘5< ±@‘<$5 5<±@P‘54±@‘A4@5±@‘A5±@‘A$5A±@P‘24±@‘94P2±@‘992 ±@‘2±@‘9P24>4±@P@‘2>2±@‘>2>±@P‘94±@‘24@92±@@‘2(9*2±@‘9P>424±@P@‘>2±@‘2>(>±@‘2P±@‘9424@92±@‘249 ±@‘2±@‘9P±@‘>424@>2±@‘24±@‘>"2>±@P‘24±@‘>4@±@‘>2 >$±@‘2 2±@‘>P24±@‘>4@2>±@‘2±@‘>$2>±@P‘>474±@P@‘>7>7 ±@‘7±@‘>P74C4±@P‘C±@‘7C7±@@‘C7P±@‘C474@C7±@@‘C*7(C7±@P‘74C4±@P‘C±@‘77C(±@‘C7±@P@‘>474@>7±@‘> ±@‘74>7±@P‘74±@‘C4@C7±@@‘74C"7±@‘CP>4±@‘74@±@‘7> ±@‘7 >$±@‘>7P±@‘74C4@7C±@@‘7C$±@‘C7P<4C4±@P‘C<±@‘< C±@@‘C<P±@‘<4P<±@@‘<<±@P‘C4<4±@@‘C±@‘<<(±@‘C*<±@‘CP±@‘<4P±@‘<<±@@‘<P±@‘@494@@9±@‘94±@‘@ 9@±@P‘94±@‘E4@E±@‘9E"±@‘94±@‘E9P@4±@‘94@@9±@ ‘@$9 ±@@‘@9PC494±@@‘9C±@‘9C$±@‘C±@‘9P94±@‘24P29±@@‘92 29±@P@‘>424P>2±@‘2>±@‘>±@‘2P24±@‘94@9±@‘2±@‘2(9*92±@P‘>424±@P@‘2>±@‘>(2>±@‘2P9424±@P‘9±@‘292 ±@@‘92P>4±@‘24P2±@‘>>±@‘2±@‘>2P9424±@@‘92±@‘9*2(±@‘29±@P‘>4±@‘24P>2±@‘2>(±@@‘2>P±@‘9+@+P9@±@@‘@*9.±@‘@90±@‘@697P±@‘@9@.9*±@P‘9@±@‘@(±@‘9+ @0±@‘9p±@‘9*@7P@±@‘99+±@‘@+P9±@‘@9.±@‘@*9@±@0‘@697±@P@‘@9±@‘@.9*P9@±@‘9+@(±@ ‘@0±@‘9p9*@7±@P‘@9±@@‘9.2"P29±@‘9$±@‘2!9±@‘2 ±@‘2$91P2±@‘92090±@P@‘922%±@‘9- 9±@‘22+±@‘9%P±@‘299424±@@‘92±@@‘9 249±@‘2P24>4±@@‘>2±@‘24±@‘>"2>±@P@‘2494@92±@ @‘9$2 92±@P‘24>4±@@‘2>±@‘>$±@‘2±@‘2>P±@‘2494P2±@‘92 ±@‘929±@P‘>4±@‘24P>2±@‘>2±@‘>±@‘2P±@‘2494@9±@‘29*2(±@@‘29P24±@‘>4P±@‘2>>(2±@@‘>2P±@‘9424@9±@‘29 24±@‘92±@P@‘>424@>2±@‘>"24±@‘2>±@P@‘9424@92±@ ‘9$2 ±@‘29±@P‘24>4±@@‘2±@‘>±@‘>$22>±@P‘<4±@‘54P<±@‘5<5 ±@‘5<±@P‘54A4±@P@‘A5±@‘A5±@‘A5P±@‘<454@<5±@@‘5(<*5±@‘<P±@‘54A4P±@‘A5A(±@‘55A±@P‘54<4±@@‘<±@‘5±@‘54< ±@‘5<P54A4±@@‘A5±@@‘A"54A±@‘5P<454±@@‘5<±@ ‘<$±@‘5 5<±@P‘A454±@@‘5A±@‘5A$±@‘5A±@P@‘9424P±@‘29±@‘2 929±@P@‘24>4P±@‘2>>2±@‘>±@‘2P94±@‘24@92±@@‘9*2(±@‘92P24>4±@P‘2>±@@‘2>(2±@‘>P±@‘2494@92±@‘9 24±@‘92±@P‘24±@‘>4@>±@‘2±@‘24>"±@‘2>P±@‘>424@2±@‘> ±@‘2 >$2±@‘>P>4±@‘24@2>±@@‘>$2>2±@P@‘>474P>7±@‘>7 ±@‘>±@‘7P±@‘C474P7C±@‘C±@‘7±@‘7CP74±@‘C4@C±@‘7C*±@‘7(7C±@P‘C474±@P@‘C7C(7±@‘C7±@P@‘>474@>±@‘774> ±@@‘7>P±@‘74C4@C7±@@‘74C"7C±@P‘>4±@‘74@7±@‘> >$±@‘7 >7±@P@‘C474@7C±@‘C$7±@‘7C±@P@‘<4C4PC<±@@‘C< ±@‘<CP±@‘<4P±@‘<<±@‘<±@P‘C4±@‘<4@C±@‘<<(±@‘C*<C±@P@‘<4P<±@‘<±@‘<±@P‘94@4±@@‘@9±@‘@ 94±@@‘@9PE494±@@‘E9±@@‘E"94E9±@P‘94±@‘@4@@±@‘9 9 @$±@@‘9@P±@‘C494@9C±@@‘9C$C9±@P‘24±@‘94P2±@‘92 9±@‘2±@‘9P±@‘24>4P2±@‘>2>±@@‘>2P24±@‘94@92±@‘9*±@‘2(±@‘92P±@‘>424P2±@‘>>(±@‘2>2±@P‘9+±@‘@+P±@‘@99.@*±@@‘@90@6±@‘97P±@‘@9±@‘@.9*P@±@‘9±@‘9+@( @0±@‘9p@79*±@P‘@±@‘92"9.±@P‘92±@‘9$±@‘2!9±@‘2 912$±@P‘2±@‘9±J<]2@[2 "HKCƒ‘9E±@‘2:92±@0@‘2:9E92±@0@‘9E2:±@‘9209E2:±@@‘29056-91±@‘5±@‘9-P58±@‘-,9:P5-9±@‘5891-#±@‘95-±@P‘9?5?-,±@P‘95-±@‘-/9959±@@‘59-P-/±@‘9;5;P-±@‘95-/±@‘5;9;9±@‘-5T5J±@‘-;9J„4-29?5?-95O-5±@‘95?±@‘-29?9-±@‘5T±@‘5O-?9OT9M2A99202A9M9209H2=92±@‘5-/9H±@‘2=±@‘920±@‘2:9E92±@0‘2:9E±@‘29±@0‘2:9E±@‘29±@0@‘9E2:29±@ ‘-75E±@@‘5-0±@‘-75E±@‘-50-7±@‘5E5-±@0‘5E-7±@‘-±@‘505E±@‘-7±@‘-50-75E±@‘5±@‘-0-75E±@‘-±@‘505E-7±@‘-±@‘5 ±@‘9L2C@92±@‘962C±@‘2±@‘9P±@‘2KP2±@‘2K±@@‘2P±@‘2K@±@‘2 23±@‘2±@P@‘2K@±@‘2 ±@‘2/±@‘2P±@‘9L2CP9±@‘22-±@‘919±@‘2P±@‘2KP±@‘2±@‘2,2±@P@‘2KP±@‘2±@‘2<±@‘2P±@‘2KP2±@‘2,±@‘2±@P‘-75E±@‘-5±@ ‘-7±@‘5E--1 -±@‘55E±@‘-1-5±@ ‘5E±@‘-75-±@0‘5E-7±@‘--15±@‘--7±@‘5E±@‘5-0±@‘-15E-±@‘5 5M±@‘-8-5±@ @‘5H-:-5±@0@‘5H-:±@‘5-05M->±@‘-±@‘50±@‘->5M-±@‘5 5S±@‘-B-5±@0‘5S-B±@‘5-±@0@‘-B5S±@‘-50-B5S±@‘-5±@ ‘7B±@‘@S7@±@0@‘@S7B@7±@0@‘7B@S±@‘7@0@S7B±@‘7@±@0‘@S7B±@@‘@70±@‘7B@S7±@‘@0±@‘7B@S@±@‘70@S±@‘7B±@‘7@05B-5±@†@@‘5-ÿ/MTrke²cb@cb @cb @cbc@cbd@cbf@edÂ!ÿJAZ2ÿ @²YJ<ÿGeneral MIDIÿBaseÿYÿYÿÿ²[ A@HK]}Cƒ[HK@J<]CÂ!Ý’$SP$$EP$$GP$$ZP$$GP$$LP$$WP$$GP$$SP$$EP$$GP$$ZP$$GP$$LP$$WP$$GP$+UP++GP++NP++ZP++GP++JP++SP++GP+$SP$$EP$$GP$$ZP$$GP$$LP$$WP$$GP$+SP++EP++GP++ZP++GP++LP++WP++GP+!UP!!GP!!NP!!ZP!!GP!!JP!!SP!!GP!&SP&&EP&&GP&&ZP&&GP&&LP&&WP&&GP&&UP&&GP&&NP&&UP&&GP&&JP&&SP&&UP&!SP!!EP!!GP!!WP!!GP!!LP!!SP!!GP!&SP&&EP&&GP&&ZP&&GP&&LP&&WP&&GP&![P!!LP!!TP!!`P!!PP!!RP!!^P!!PP!!eP!!UP!!]P!!kP!!UP!!XP!!cP!!UP!&^P&&NP&&PP&&eP&&LP&&QP&&]P&&LP&&UP&&GP&&NP&&UP&&GP&&JP&&SP&&UP&&SP&&EP&&GP&&WP&&GP&&LP&&SP&&GP&&UP&&GP&&NP&&ZP&&GP&&JP&&SP&&GP&+SP++EP++GP++ZP++GP++LP++WP++GP++SP++EP++GP++ZP++GP++LP++WP++GP+!UP!!GP!!NP!!ZP!!GP!!JP!!SP!!GP!!UP!!GP!!NP!!ZP!!GP!!JP!!SP!!GP!&SP&&EP&&GP&&ZP&²HKJ<@[]CÂ!ƒ’)NP))@P))GP))WP))@P))BP))LP))@P)+LP++>P++@P++UP++@P++EP++PP++@P+!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&JP&&P&&@P&&UP&&@P&&EP&&PP&&@P&&QP&&BP&&EP&&[P&&HP&&MP&&ZP&&HP&!YP!!IP!!^P!!RP!!YP!!LP!!aP!!NP!!aP!!RP!!gP!!ZP!!aP!(UP((MP(!k`!&\Ô&!NP!!@P!!GP!!WP!!@P!!BP!!LP!!@P!!NP!!@P!!GP!!WP!!@P!!BP!!LP!!@P!&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&&LP&&>P&&@P&&UP&&@P&&EP&&PP&&@P&&KP&&=P&&OP&&EP&&KP&&@P&&RP&&AP&)JP))P&&@P&&PP&&@P&&EP&&LP&&@P&&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&+LP++>P++@P++UP++@P++EP++PP++@P++NP++@P++GP++WP++@P++BP++LP++@P+$LP$$>P$$@P$$UP$$@P$$EP$$PP$$@P$!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&JP&&P&&@P&&UP&&@P&&EP&&PP&&@P&&KP&&=P&&OP&&EP&&KP&&@P&&RP&&AP&!SP!!EP!!LP!!]P!!HP!!JP!!UP!!HP!!\P!!MP!!UP!!hP!!MP!!OP!!ZP!!MP!&WP&&HP&&PP&&bP&&EP&&GP&&QP&&EP&&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&&LP&&>P&&@P&&UP&&@P&&EP&&PP&&@P&&KP&&=P&&OP&&EP&&KP&&@P&&RP&&AP&)JP))P&&@P&&PP&&@P&&EP&&LP&&@P&&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&+LP++>P++@P++UP++@P++EP++PP++@P++NP++@P++GP++WP++@P++BP++LP++@P+$LP$$>P$$@P$$UP$$@P$$EP$$PP$$@P$!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&LP&&>P&&@P&&UP&&@P&&EP&&PP&&@P&&LP&&>P&&@P&&UP&&@P&&EP&&PP&&@P&!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&JP&&P&&@P&&UP&&@P&&EP&&PP&&@P&&KP&&=P&&OP&&EP&&KP&&@P&&RP&&AP&)JP))P&&@P&&PP&&@P&&EP&&LP&&@P&&NP&&@P&&GP&&WP&&@P&&BP&&LP&&@P&+LP++>P++@P++UP++@P++EP++PP++@P++NP++@P++GP++WP++@P++BP++LP++@P+$LP$$>P$$@P$$UP$$@P$$EP$$PP$$@P$!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&LP&&>P&&@P&&UP&&@P&&EP&&PP&&@P&!KP!!=P!!OP!!EP!!KP!!@P!!RP!!AP!&JP&&/³@“7/P³@“>7>-³@“727³@“>0><7>³@P“7>³@“7-³@“>2P7>³@“7/>*³@ “>07³@p@“7->=P>7³@“C2³@“<$P<³@“C³@“C&2³@“7$P7³@“>7!>&³@“>7³@ “7%³@“>6P>³@“7³@“>474P³@“7>³@“>17' >³@“77/>'³@P“7>³@“9/³@“@/P³@“@992³@“@-9@³@0“@<³@“9>P³@“9@³@“9-@2P@³@“9³@“9/@* @09³@p@“@=9-P³@“@92$92³@P“92³@“9&³@“2!92³@ @“962%P2³@“99424³@P“9³@“291³@“2' 92³@“9'³@“2/P9³@“22/³@“9/P2³@“9229-³@“29³@0@“2>9P29³@@“2-92P³@“292/³@“9* 902³@p@“2-9=P29³@@“922$P92³@@“2!9&9³@“2 ³@“962%P³@“29³@“2494P³@“292'91³@ “92³@“9'2/³@P“2³@“92/³@“9/P92³@“9-³@“229³@“209<³@“2>P92³@@“2-92P29³@“9*³@“2/ 902³@p@“2-9=P9³@“2³@“7$>2P>7³@@“>&7!>³@“7 >6³@“7%P>7³@@“74>4P³@“7>³@“7'>1 >³@“77/³@“>'P³@“>7³@“>27$P7³@“>>&³@“7!>7³@ @“7%>6P³@“>7³@“74>4P>³@“7>17'³@ “>³@“77/>'³@P“>³@“7@/9/³@P“@9³@“@-92³@@“@909>³@“@³@P“@9³@@“9-@2P³@“9@³@“@*9/ @09³@p“9-@=³@P@“@92$³@“92P92³@“2!³@“9&92³@ “2%³@“96P³@“92³@HKJ< ^[2]2Cƒ“A%%7">C7³@P“>)³@“C)7"P³@“C7>>"7³@“C C>7³@P“7"³@“>3C,P>C7³@“>)C)7"³@“7C³@“>P>)³@“C)7"P7³@“>C7"³@“>)C)³@“C>7P³@“C)7">)P³@“>7C9³@“@(C$@C³@“9PC+³@“@)9#P³@“9C@@)9³@“C$9³@“C@P9#C.@.³@P“9@C³@“9#@(³@“C(@9C³@P“@)³@“9#C)P³@“9@CC)9#³@“@)³@“9C@P9#³@“@)C)P³@“9C@>$2³@“9$>29³@P“>)³@“9)2#P³@“>29>!9#2 ³@“29>³@P@“>)2#9)P9>2³@@“2+9->1³@“29>P2#³@“9)>)P³@“2>9>820³@“962³@“9>P9)2#³@“>)P³@“9>22>%³@“9!9³@“2>P³@“2$>*9*P92>³@“29>$³@“>9³@“2P>*2$³@“9*P³@“>299*>*2$³@“2>9³@P“>*2$³@“9*P>29³@@“9*>*2$>92³@P@“>*2$9*@>92³@“>%2!³@“9%>2³@“9P>*³@“9*2$P2>9³@“9"2"³@“>"³@“>29P>*³@“2$9*P³@“92>2$>*³@“9*92³@“>P9*³@“>*2$P³@“9>2>"³@“9%2!92³@“>@2$9*>*³@P“2³@“9>³@“> 9(2$29³@“>P³@“9+2$>+P>³@“929$>"2³@“>29³@P@“96>/2$P9³@“2>9.³@“>.2'9>2³@P@“9.2'>.P>³@“299.³@“2'>.>9³@“2P9.>.³@“2'P³@“>92³@“@09C,³@“9@CP@2C49*³@P“@³@“9C³@“9!C,@2C9³@“@P9*C8³@“@8P@C³@“9³@“C09*@09C@³@P“@2C29*³@P“@C9³@“@2³@“C29*³@“@9CP³@“9*@2C2P³@“9@C@0C,9³@“@C9³@P@“9*C4@2P³@“C9@@2³@“9!C,9³@“C@P9*C8³@“@8P³@“@9C@0C09*³@“9@C³@P“9*@2C2³@P@“9@C9*@2C2³@“9@C³@T“@>³@“94C>ÔT4$9@(@99@4P@)4+9#1C9@4³@@“@)4$9@94³@P“9#@.4.³@@“@4³@“942³@“9'@-9@ ³@“4/4)³@“9#@)P³@“9@4@)³@“4)9#³@“@94P4)9#@)³@P“@³@“499@(4$³@“@³@“49P@)³@“4+9#P94³@“@4$@)³@“9³@“@49P@.9#4.³@@“@4³@“942³@“@-9'@9 ³@“4/4)9#³@“@)P³@“94@@)9#4)³@“@94³@P“9#@)4)³@P“@94³@@“9)>"2"2>9³@P@“>+9)2"P92>³@“2³@“>99³@“2>P9.>.³@“2"P29>³@“>)³@“2"9)>³@“29P³@“>)2"9)P>92³@“9)>)³@“2"2³@“9>P2"³@“>)9)@9³@“2> 29!>%³@“>29³@P@“2$>*9*P>2³@“9³@“29>$2>³@“9P>*9*³@“2$P2>³@“92$³@“>*9*29>³@P“>*2$³@“9*P>³@“29>*³@“9*2$³@“9>2P9*2$³@“>*@9>2³@“9%2!>%³@“9>³@“2P>*2$³@“9*P9>2³@“9">"2"³@“29³@“>P2$³@“9*>*P9³@“>29*>*2$³@“>29³@P“2$>*³@“9*P³@“>299%>"³@“2!92³@“>@³@“9*>*2$P>29³@“29(>$³@“92³@“>P9)2#³@“>+P³@“>299)>$2³@@“>92P³@“>.2#9.P³@“29>>(2#³@“9(>2³@“9P9)³@“2#>)P>2³@“9³@“2#9)>)9³@“2>P9)³@“2#>)P>9³@“25³@“<$A$³@“A5<PA)³@“5#<)P5A³@“<³@“5 A!<#A<5³@P“A)<)³@“5#P³@“5A<$³@“29$>92³@P@“2#>)9)P³@“29>2 >!³@“9#9>³@“2P³@“2#9)>)P>³@“29>19-2+³@“9³@“2>P>)2#³@“9)P>³@“922096>8³@“>92³@P@“2#9)>)P>29³@“>%2³@“5!25>³@P“>*2$5*³@P@“5>225³@“>$2>³@“5P³@“>*5*2$P³@“52>>*2$³@“5*52³@“>P³@“5*>*2$P>³@“525*³@“2$>*5³@“2>P2$5*³@“>*@5>³@“27!C%:%³@“:³@“C7PC*7$:*³@P@“C7:7"³@“:"C":C7³@P“:*C*³@“7$P³@“C:7:*7$³@“C*:C³@“7P³@“C*:*7$P7C³@“:7!C"³@“:%7:C³@@“:*C*³@“7$P7³@“C:7C%>!³@“>C³@“7P7$³@“>*C*PC>7³@“7C$>³@“7³@“C>P7$C*>*³@P@“>C7C*³@“>*7$C7>³@P“>*C*7$³@P“C³@“7>>*7$³@“C*7C³@“>P³@“>*7$C*@C>7³@“C%<%³@“<C³@P@“<*C*P<³@“C³@“C"<"³@“<CP<*³@“C*P<³@“C<*C*³@“<³@“CPC*³@“<*PC³@“<<"C%³@“C<³@@@“<*C*PC<³@“E$@(9³@@“@E9PE+@)³@“9#PE9³@“@9E$@)³@“@³@“9EP9#E.@.³@P“@E9³@@“C(@(9#C@³@“9P9#³@“C)@)P³@“@9CC)³@“@)9#@³@“C9P³@“9#C)@)P@9C³@“>$9$2³@“>9³@“2P³@“9)2#>)P2>9³@“>!³@“9#2 ³@“2>9P2#³@“9)>)P9>³@“22-9/>-³@“2³@“9>P9)³@“2#>)P9³@“>22893³@“>-9>³@“2P2#9)³@“>)P³@“2>9³@“9@(4$94³@“@P³@“9#@)4+P94³@“@4$9³@“@)³@“@49P@.4.³@“9#@94@³@“42³@“@-9'9@ ³@“4/³@“@)9#4)P@³@“494)³@“@)9#4@9³@P“9#@)³@“4)P³@“4@9>"2"³@“9)92>³@P“2"³@“>+9)P2>9³@@“>29³@“2>9P>.³@“9.2"P>2³@“9³[2@J<CHK]2 ^ƒ“2/9/³@P“29³@@“229-92³@0“2>³@“9³@P“9³@“22194³@P“9³@“2³@“9F2>P³@“92³@“9:2:P92³@“94³@“2!P92³@“9824³@P“29³@“2,9/³@`“9ƒ`982#2P³@“29³@“9;28P2³@“9922/³@`“959225P2³@“928³@“9292³@0“9D2F³@P“92³@“9520³@P@“299,22³@ “90³@“2p³@“2/9AP³@“29³@“2(98P³@“92³@“2%9+92³@ “2*³@“9927$P>7³@@“>&7!>7³@ “>6³@“7%P7>³@@“>474P³@“7>>1³@“7' >7³@@“7/>'P7>³@“>/³@“7/P³@“>772³@“>->³@“70><7>³@P“7³@“>³@“7->2P7>³@“7/>*³@ “>07³@p@“>=7-P>7³@“>2³@“7$P7³@“>>&7!³@“>7³@ @“>67%P7³@“>>4³@“74P>³@“7³@“>17' >7³@@“7/>'P³@“>7³@“>/7/P7>³@@“>-72³@“>70³@“><7>P7>³@“7->2³@P“>7³@“7/³@“>* >0³@“7p>=7-³@P“>7³@“5$<2³@P@“<5³@“5!<&<³@“5 ³@“5%<6P<5³@@“<454P5<³@“<15'³@ “<³@“5<'³@“5/P<5³@“P<³@“5³@“5-<2P<5³@“<*5/³@ “<05³@p@“5-<=P5³@“<³@“922$P³@“292!³@“9&92³@ “2%³@“96P29³@“24³@“94P³@“922'³@“91 92³@@“2/9'P³@“295/P³@“<55-<2³@P@“5<5/<*³@ “<0³@“5p³@“<=5-P³@“<57$³@“>2P7>³@“7!³@“>&>7³@ “>67%³@P“>³@“7³@“74>4P7³@“>>17'³@ “>³@“7³@“7/>'P7>³@@“@/9/P@³@“992@-³@“@³@“90³@“@<9>P³@“9@³@“9-@2P@³@“9³@“@*9/ @09³@p“9-@=³@P“@9³@“2/³@“9/P29³@“9-22³@@“2902>³@“9³@“99<³@P@“922-92³@P“9³@“22/9*³@ “902³@p“2-³@“9=P2³@“9³@“@292P³@“9@@/95³@@“9@0@?9A³@P@“@9³@“93@8P³@“@9@0³@“95 @0³@“9p@E³@“92P@9³@“99@9³@P@“9@@6³@“9<@³@“90@H9K³@P“@9³@“@<96³@P@“9@99@3³@ “@0³@“9p96³@“@JP9@³@“2595³@P“2³@“992³@“2829³@0@“9D2FP2³@“920³@“95P³@“299,22³@ “902³@p“2/³@“9AP2³@“9³@“2/9/P9³@“2229-³@@“2909<³@“2>P³@“292-³@“92P³@“292/9*³@ “902³@p“2-9=³@P“29³@“>27$³@P@“>7³@“7!>&>7³@ “7%³@“>6P>³@“774>4³@P“>³@“7>1³@“7' >³@“7³@“7/>'P>³@“77/³@“>/P7>³@@“72>->³@“70><7>³@P“7³@“>>27-³@P@“>77/>*³@ “>07³@p@“>=7-P³@“>7³@“7$>2P>³@“77!³@“>&>³@“7 >67%³@P“>³@“7>474³@P“>7³@“7'>1³@ “>³@“7³@“7/>'P³@“>7>/³@“7/P7³@“>³@“72>->³@“707>³@“>7-³@“>2P³@“>77/³@“>* >0³@“7p7-³@“>=P7>³@“5$³@“<2P³@“5<5!³@“<&<³@“5 <65%³@P“5<³@@“<454P³@“5<³@“<15' <5³@@“5/<'P<5³@“5/³@“<³@P@“<5<25-³@P“5<³@“<*³@“5/ <0³@“5p<=5-³@P“5<³@“7$³@“>2P³@“7>7!>&³@“>7³@ “>6³@“7%P>³@“7³@“>474P7>³@“>17'³@ “>³@“7³@“>'7/P³@“>7³@“9/@/P@9³@@“92@-9@³@0@“@<9>P@³@“9³@“@29-P³@“9@@*³@“9/ @09³@p@“@=9-P³@“@9³@“9/2/P³@“929-22³@“92³@0@“9<2>P29³@ ^]2@C[2HKJ<ƒ@“9!2>%³@“29>P³@“>*9*2$P³@“9>229³@“>$³@“9>2P2$>*³@“9*P>9³@“2>*2$9*³@“2>9³@P“>*2$9*³@P“2>³@“9>*2$³@“9*>92³@P“9*³@“2$>*@>92³@“9%>%³@“2!>92³@P“9*2$>*³@P@“92>³@“2"9">"29>³@P“9*³@“>*2$P³@“92>9*2$³@“>*>9³@“2P>*³@“2$9*P>9³@“2³@“>"9%2!92³@“>@9*>*2$³@P“2>9³@“9(2³@“>$2³@“9>P9)>+³@“2#P>9³@“22>$9)³@“9>³@“2P9.>.³@“2#P>92³@“2#³@“9(>(9>2³@P@“>)2#9)P³@“2>9³@“9)>)2#2³@“>9P³@“>)2#9)P³@“>299³@“@*4'³@“@49P4.9%@,³@P“4@³@“94'³@“@,9@9³@“4P³@“@19%41@³@“49@³@“459,@2@9 ³@“4/9'@.4.³@P“@³@“49³@“4.@.9'@³@“94P4.³@“@.9'P@49³@@“94,@049@³@P“@29*³@“44P9@4³@“4,9!³@“@24³@“@9P@89*48³@@“49@³@@“4<9/@6@9 ³@“4/429*@2³@P@“@94³@“@2429*@49³@P“9*@242³@P“94³@“@9.>'³@“2'³@“92>P³@“>09.2'P>³@“29>"³@“9"2>9³@“2P94³@“>42'P29³@“>>+2$³@“9+92>³@P“>+2$³@“9+P2>9³@“>+2$³@“9+³@“9>2P9+³@“2$>+@³@“>29 29!³@“>%³@“2>9P2$³@“9*>*P2³@“>99>$2³@@“29>P9*³@“>*2$P³@“>929*2$>*³@“9>³@“2P2$³@“>*9*P92>³@“>*2$³@“9*92>³@P“9*³@“2$>*@9>³@“2³@“9%>%2!³@“2>9P>*9*³@“2$P>³@“29>"2"9"³@@“>29P³@“2$>*9*P>92³@“9*>*³@“2$³@“92>P9*2$³@“>*P92³@“>2!9%³@“>"29>³@@“2$³@“>*9*P2³@“9>³@“29(>$>³@“29P³@“9)2#>+P³@“92>2>$³@“9)³@“2>9P9.³@“2#>.P³@“>929(2#³@“>(9³@“2>P9)³@“>)2#P2³@“>99)³@“2#>)29>³@P“9)2#>)³@P“>9³@“2³@“5<$A$³@“<5APA)<)³@“5#PA³@“<5³@“5 <#A!<A³@“5PA)³@“<)5#PA5³@“<$29$9>³@“2P>)9)³@“2#P2>³@“9³@“2 9#>!9>³@“2P9)2#³@“>)P92>³@@“>19-2+>2³@“9P2#³@“>)9)P³@“9>22096³@“>8³@“92>P9)2#³@“>)P2³@“>9³@“>%25!³@“5>2P2$5*>*³@P@“52>>$5³@“2³@“>25P³@“>*5*2$P>25³@“2$5*³@“>*³@“>52P5*2$³@“>*P2>5³@“5*³@“>*2$³@“>25P5*>*2$³@@“>5³@“2:%C%³@“7!³@“7:CP7$:*³@“C*P7C:³@“C"7"³@“:"³@“C:7P³@“:*C*7$PC³@“7:C*7$:*³@“7C³@“:P:*³@“7$C*PC³@“7:³@“C":%7!7:³@“C@C*7$:*³@P“:C³@“7>!C%7³@@“7C>P>*C*7$³@P@“C7>³@“7>C$C7>³@P“7$>*C*³@P“C7>³@“>*7$C*³@“7>³@“CP³@“7$>*C*P³@“C7>C*7$>*³@@“>C7P7$³@“C*>*@>C³@“7<%C%³@“C<³@P“C*<*³@P“<C³@@“<"C"C³@“<PC*<*³@P“C<³@“<*³@“C*³@“C<P³@“<*C*P³@“C<C%<"³@“C³@“<@<*C*³@P“C³@“<³@“9E$@(9@³@“EPE+@)9#³@P“@³@“9E9@)³@“E$E@³@“9P³@“E.@.9#P³@“@9E9#³@“@(C(³@“9@CP³@“C)9#@)P@9C³@“@)³@“9#C)³@“@9CP³@“C)@)9#PC9³@“@9%³@“>2">92³@P@“>)2"9)P³@“2>99"> ³@“29>³@“2P³@“2">,93P>9³@“2³@“9)2">)>2³@“9P9)2">)³@P“9>³@“2³@“9)2">)>29³@P“>)2"³@“9)P>³@“292">³@“9%³@“>92P2"9)>)³@P“29³@“>29"³@“> >³@“92P>,2"³@“93P³@“>29³@“>)9)2"³@“>92P³@“2">)9)P2³@“9>9)>)2"³@“2>³@“9P9)>)2"³@P@“2>9@(C$³@“99C³@“@P³@“9#C+@)P@C9³@“@)C$³@“9³@“@9CP9#C.@.³@P“@C9³@@“9#@(C(³@“@9CP³@“C)9#@)P9³@“@C9#³@“@)C)C@9³@P“@)C)³@“9#PC9@³@“9C$³@“@(³@“9@CP@)9#³@“C+P³@“@C9³@“@)9C$9³@“C@PC.9#³@“@.P9@³@“C³@“@(9#C(@C9³@P“9#³@“@)C)PC@9³@“9#@)C)³@“C9@³@P@“9#@)C)P@9C³@“9$>$2³@@“2>9P>)9)³@“2#P92³@“>³@“2 9#>!>³@“29P2#>)³@“9)P2³@“9>>1³@“2+9-³@“29>P>)³@“2#9)P92>³@“9620>8³@@“92>P2#³@“>)9)P2³@“>9³@“>%29!>³@“92P³@“2$9*>*P29>³@@“>$922>9³@P“9*2$>*³@P“92³@“>9*2$>*³@“>2³@“9P2$³@“>*9*P29>³@“9*2$>*³@@“92>P9*2$>*³@@“>9³@“2³@“9%>%2!29³@“>P³@“>*9*2$P³@“92>³@“>"9"2"2³@“>9P9*2$>*³@P“>92³@@“2$>*9*³@“2>9P2$9*³@“>*P³@“>29>"9%2!³@“92>³@@“2$9*³@“>*P³@“2>9³@“>$29(2>9³@P“>+2#9)³@P“>29³@“>$9)2³@@“92>P>.9.³@“2#P>³@“29³@“9(>(2#9>2³@P@“>)9)2#P>9³@“29)³@“2#>)³@“29>P9)³@“2#>)P³@“92>³@“A$<$5³@“<5AP5#³@“A)<)P<A³@“5³@“A!5 <#³@“A5<PA)5#³@“<)P³@“5A<³@“A-$92³@“>P>)9)³@“2#P>92³@“>!2 9#³@“>2³@“9P2#9)>)³@P@“92>9->1³@“2+92>³@P@“2#9)>)P92>³@“96³@“>820³@“29>P2#9)³@“>)P³@“29>³@“>%5!2³@“5>2P³@“2$>*5*P5³@“>2³@“2>$5³@“>52P2$5*>*³@P“52>³@@“>*5*2$³@“5>2P³@“5*2$>*P5³@“2>5*2$>*³@@“>25P>*2$5*³@@“5>2³@“:%³@“C%7!C:7³@P“7$C*³@“:*P³@“C:7:"C"7"³@“7³@“C:P:*³@“C*7$PC:7³@“C*³@“7$:*³@“C:7P:*C*³@“7$P³@“:7CC"³@“:%7!:7³@“C@:*³@“7$C*PC7:³@“>!7³@“C%³@“C>7P³@“C*>*7$PC³@“>7C$>³@“7>7³@“CP³@“7$C*>*P>C³@“7C*7$³@“>*C³@“7>P³@“>*7$C*P7³@“>C7$>*³@“C*³@“C>7PC*³@“7$>*@>C7³@“<%C%³@“<C³@P“C*³@“<*P<³@“C³@“C"<"<C³@P“<*C*³@P“C³@“<<*C*³@“C<³@P“<*³@“C*PC<³@“C%<"³@“C<³@@@“<*C*PC³@“<@(E$9³@“@³@“E9PE+@)9#³@P“9@E³@“9³@“E$@)E³@“@9P9#³@“E.@.P@E9³@“@(9#³@“C(³@“@9CP9#C)³@“@)P³@“9@C@)³@“C)9#C9@³@P“9#C)@)³@P@“9C@>2"9%³@“29>³@P“2">)³@“9)P9>³@“2³@“29"> 9>2³@P“93>,³@“2"P³@“9>29)>)³@“2">92³@P“>)9)2"³@P“>³@“929)2">)³@“9>2³@P@“9)>)2"P>29³@“@(9³@“C$³@“C@9P³@“9#C+@)P³@“9@CC$9³@“@)@9³@“CP@.³@“C.9#PC9³@“@³@“@(9#C(C9@³@P@“9#@)C)P³@“@C99#³@“@)C)³@“9C@PC)@)9#³@P@“C9@2³@“>$9$2³@“9>P>)9)2#³@P“>92³@@“9#2 >!9³@“2>P³@“9)2#>)P9>2³@CHKJ<@]2[2 ^ƒ“2/³@“9/P³@“9222³@“9-9³@“202>9<³@P“92³@@“2-92P³@“299*2/³@ “902³@p“2-9=³@P“92³@@“9:2:P2³@“991³@“2>P92³@“2194³@P“92³@“9F2>³@P“92³@“2:9:³@P@“2994³@“2!P³@“299824³@P@“292,³@“9/„@98922#P9³@“2³@“9;28P2³@“9³@“922/`952259P2³@“928³@“9292³@0@“9D2FP³@“2995³@“20P92³@@“229, 902³@p“2/9A³@P“29³@“92³@“2$P³@“292!9&³@“92³@ “2%³@“96P29³@@“2494P29³@“91³@“2' 9³@“22/³@“9'P92³@@“2/9/P³@“92³@“9-22³@“9209<2>³@P@“92³@“2-92P92³@@“9*2/ 902³@p“9=2-³@P“2³@“92$³@“92P92³@“9&2!³@“9³@“2 2%96³@P“2³@“9³@“9424P92³@@“2'91 9³@“29'2/³@P“92³@“2/³@“9/P2³@“9229-³@“9³@“202>9<³@P“2³@“9³@“922-P9³@“29*2/³@ “902³@p“2-9=³@P@“2992³@“2$P³@“92³@“2!9&9³@“2 962%³@P“29³@“9424³@P@“92912'³@ “92³@“2/9'³@P@“292/³@“9/P³@“9222³@“9-³@“290³@“9<2>P³@“922-³@“92P9³@“22/³@“9* 90³@“2p³@“2-9=P³@“29³@“922$P92³@“2!³@“9&92³@ “2%³@“96P³@“92³@“2494P29³@“912'³@ “9³@“29'³@“2/P92³@@“2%95P³@“92³@“2#9(9³@“2 ³@“2'98P29³@“2;9;³@P“9³@“2982,³@ “9³@“2³@“9,25P³@“92³@“2+9JP>´@”A?C?J?´@”;?7?‚`;7 5[A0CJCP>C575J5:5‚0JC7:´@0”9C´@P”91GP1@JP@E?9?L?1?C?‚`91 7[C0EL2CP25C 705ECPE>555E525‚05E2>02CP2´@@”5CP5ECPEE55525>5‚`25 2C>02E9CP92CP2@CP@95L525E5‚0L2E902CP25CP5ECP´@”EE5>52555´@‚0”52E>09GP91JP1@MP@9BEBLBCB1B‚`91 7bC0EL9PP91S 701@VP@1I9ICILIEI‚`19´@ ”7g´@”C0EL2KP25K 705EKPE5<><2<E<‚0E2>502CP25CP5ECPE55>525E5‚`25 2C>02E2CP2´@@”7CP7ECPE75>5E525‚0>2E70E5A5>5´@”25´@p”>E2A0E5>5A525 2 -<EE<@- 2C@2 -C >EA - 7CP7:CP:>CP>J5C575:5‚0JC:7´@0@”7CP7:CP:>CP>75C5:5J5‚0C:7J09CP95`´]A @[ACHKJ<@ƒ”2>†5EJ070C0F0´@p”C´@”7JF0C0´@”J070F0@CFJ`7 F0J0>0C0@> :<@: 7<JCF@7 ´@‰”E222´@”A2>2p2E>A022E2>2A2@E>A`2 A6E6>6@E 5D@5 2D>A@2† E?L?C?I?9?p´@”CI9LE0´@”9P@9 E?C?´@”L?´@”9?I?@L9ECI 4H@H@4`@ 9?I?L?E?C?`I´@‚P”>K´@ ”AKEEK JKÑCL9C0´@”I090E0L0´@”E>A‚_JI9LCEI0E0C090L0…p9ELCIE0´@”20>0A0´@p”2A>E0E020A0>0 2 -6EE6@- 2<@2 -< A>E -Œ 20´@@”>0E0A0p2A>E0E8>828A8 2 ED-DE@- 2N@2 -R >AE - ´@”H0E0A0´@”50pE5AH0A0H050E0@EAH`5 A0E0H0<0@< 9<@9 EHA5<@5 H050A0´@”E0´@p”EA5H0A050H0E0 5 HH606@0 5<@5 0< EAH 0 20´@”>0E0´@”A0pAE2>0E0A020>0@E>A`2 >0A0E0@E 5<@5 >A2<@2 ´@‰@”L0E0I090pEL9I0L8I8E898 9 4DLLD@4 9N@9 4R ELI 4 ´@”A020´@”>0E0p2EA>0E020>0A0@EA>`2 A0>0E0@E 5<@5 A>2<@2 E0J0C090L0…pCJ9LE´@”E0A0>0´@”20p2EA>0E020>0A0`´C @J<HK[A]A@ƒ@”2CP25CP5ECPEE55525>5‚`52 2C>02EE828>8A8pA´@”2>E0´@”2G@2 2<´@”E<><A<´@@”2A>E EC-C@-`E A<2<><E<`>2AE‚P>>PA APEEPJP‚ >A/2P2KP25KP5EKE´@”J/E5<´@”><E<2<‚`52 2G>02E2KP25KP5EKPE2<E<><5<‚0>52E02PP25PP5EPPE2?>?5?E?‚0E52>´@0”9P´@P”91SP1@VP@1ILI9IEICI‚`19 7gC0EL9PP91S 701@VP@LI9I1IEICI‚`´@”91 7g´@”C0EL2KP25K 705EKPE2<E<5<><‚0>2E502CP25CP5ECPEE55525>5‚`52 2C>02E7CP´@”7:C´@P”:>CP>75J5C5:5‚0J:C70C5´@@”F575J5pCJF70F575C5J5 7 J2<J<@2 7C@7 2C CJF 2 75J5F5C5pCF7J02C@´@”2 J5´@”75F5C57CJF0F5J5C575`JFCP77CP7:CP:>CP>C5:575J5‚`:7 7CC07J5CP´@”59C´@P”95A525pE´@”>2A0´@”-C@- A5>5´@@”25E5AE2>0E5>5A525`E>AP25CP59CP9CP>J5:5C575‚0:J7C09CP91GP1@JP@L?C?E?9?1?‚`19 7[C0E7L2CP25CP5´@”EC´@P”E>555E525‚`52 2C>02E2CP25CP5ECPEE525>555‚`52 2C>02E9CP92CP2@CP´@”@E5L595´@”25‚092EL0>5´@”25A5E5´@p”EA>20>525E5A5 2 EE<-<@- 2C@2 -C A>E - 9GP91JP1@MP@9BLB1BEBCB‚`´@”91 7b´@”C0E7L9PP91SP1@VP@EI9ILI1ICI‚`91 7gC07EL2KP25KP5EKPEE<><2<5<‚`52´@ @”2G>02E2CP25CP5ECPE>52555E5‚`52 2C>02E7CP7:CP:>CP>75:5J5C5‚07JC:0C575´@”F5J5´@p”FJ7C0J575F5C5 7 JJ<2<@2 7C@7 2C JFC 2 J5F5C575p7FJC02C@2´@ ”C5J575F5´@”7FCJ0C5F5J575`CJFP77CP7:CP:>CP>:575J5C5‚`:7 7CC07J5CP´@”59C´@P”9525p´@”>EA20´@”-C@- A5´@”25>5´@”E5>E2A0E525A5>5`E>AP25CP59CP9CP>:575C5J5‚0J:7C09CP91GP1@JP@C?9?E?1?L?‚`91 7[C0E7L2CP25CP´@”5´@”ECPE25E555>5`´CJ<]A[A@HK @@”>0>5E2E020A0pAE>2028A8>8E8 2 -DEED@- 2N@2 -R >´@”AE - ´@”I2L292C2E2…pEILC9I8E898C8L8…pECL9I´@”26´@”>6A6E6pA>2E0A626>6E6 2 EE8-8@- 2@@2 -@ >EA -Œ A0´@”20>0´@”E0pA2>E0A828>8E8 2 -DEDE@- 2N@2 -R EA> - E0A050´@”H0´@p”HE5A0A050H0E0@EAH`5 A0<0E0H0@< 9<@9 HA5<E@5 50E0´@@”A0H0pHAE50E0H0A050 5 HH606@0 5<@5 0< EHA 0 ´@”A0´@”20E0>0p>AE20>0A020E0@EA>`2 >0A0E0@E 5<@5 A>2<@2 ´@‰@”L0E090I0p9LEI098I8L8E8 9 LDL4D@4 9N@9 4R ELI 4 ´@”A0´@”E020>0p2EA>0A0E020>0@>AE`2 >0E0A0@E 5<@5 2<>A@2 ´@”>0A020E0´@p”AE2>0>020E0A0@E>A`2 >0A0E0@E 5<@5 >A2<@2 ´@”A0>0´@”E020p2E>A0A8>828E8 2 ED-DE@- 2N@2 -R AE> - ´@”E0H050A0´@p”HE5A0E0H050A0@AEH`5 H0A0<0E0@< 9<@9 EH5<A@5 ´@”E0A0´@”H050p5HAE050A0E0H0 5 06H6H@0 5<@5 0< AEH 0 >0´@”A0E0´@”20pA>2E0E0A0>020@>EA`2 E0>0A0@E 5<@5 >A2<@2 ´@‰”I0L090E0´@p”EL9I098E8I8L8 9 L4DLD@4 9N@9 4R LEI 4 ´@@”E0A020>0p2A>E0E0A0>020@>AE`2 A0E0>0@E 5<@5 >A2<@2‰ ´[AHK@J< @]ACƒ@”2CP25CP5ECPEE5>55525‚`52´@ @”2C>02E>828A8E8p2EA>02G@2 ´@”A<><2<E<´@@”E>A2 EC-C@-`E E<A<><2<ƒ0A>P> APEJPEP‚ >A/2P2KP25KP5EKE´@”J/EE<´@”5<><2<‚`25 2G>02E2CP25CP5ECPEE555>525‚02E5>0´@”E5´@”25A5>5p2>AE0E5>5A525 2 E<-<E@- 2C@2 -C >EA - E5>5A525p2A>E0-C@-´@ @”25>5E5A5>2EA0A5>525E5`AE>P22CP25CP5ECPE5525>5E5‚`52 2C>02E2CP2´@@”5CP5ECPE5525>5E5‚052E>0´@”A5>5E525´@p”2>AE0A5>5E525 2 E-<E<@- 2C@2 -C EA> - A5E5>525pEA>20-C@-´@ ”>5´@”E525A52>EA0>525A5E5`A>EP22GP25GP5EGPE>8E82858‚02>5E02PP25PP5´@”EP´@P”E5?E?>?2?‚05E2>0%µcÿ @ÿGeneral MIDIÿ Echo-Part-01ÿYÿYÿÿµ[@CHK@}]J< ?Œ•>Q"†QM"†MJ"ŒQ"J†M"Q†V"MŒ>"V†>A"†>"A’C">ƒC"CƒH"CŒHJ"†JH"†HF"†E"F†>"E†>A"†@"Aƒ@"@ƒ>"@†9%>Œ>%9†A">†>"Aƒ>>"‰>">ƒ>">ƒ>C"†CH"ŒHJ"†H"J†F"H†FE"†E>"†>A"Œ>%A†9)>ŒJ%9˜H"JŒE"HŒEC"†CF"†FH"†L"HƒL"LƒJ"L†JM"†ML"ŒLJ"˜JH"ŒHE"ŒEC"†CF"†FH"†HL"ƒL"LƒJ"L†JL"ƒLL"ƒLJ"ªE)JŒE>%†>A"†>"A>">ƒ>C"†CH"ŒHJ"†JH"†HF"†FE"†>"E†A">†A@"ƒ@@"ƒ@>"†>9%Œ9>%†A">†>"A>">ƒ>C"†CH"ŒHJ"†JH"†HF"†FE"†>"E†A">ŒA>"†>9%Œ9J%˜JH"ŒHE"ŒC"E†F"C†H"F†HL"ƒLL"ƒLJ"†JM"†ML"ŒLJ"˜H"JŒE"HŒEC"†CF"†H"F†L"HƒLL"ƒLJ"†L"JƒL"LƒLJ"˜Q%J†QM"†MJ"ŒJQ"†QM"†V"M˜T)VŒTJ†@Jÿ/MTrk¶cb@cb @cb @cbc@cbd@cbf@edÆ0ÿJAZ2–>%ÿGeneral MIDIÿ Echo-Part-02ÿYÿYÿÿ¶ h[@CHKJ<@ÿ @¶]_}Œ–>Q"†M"Q†MJ"ŒQ"J†QM"„@Q"M`R"Q`V"RŒV>"†>A"†>"A’>C"ƒC"C@E"C`EF"`FH"ŒJ"H†H"J†F"H†FE"ƒC"E@CA"@A>"†A">†@"Aƒ@@"ƒ@>"„@<">`9"<`99%Š@9:)`:<)`>%<†>A"†A>"ƒ>>"‰>>"ƒ>">ƒC">„@CE"`EF"`H"FŒHJ"†JH"†HF"†FE"ƒC"E@A"C@A>"†A">ŒA>%„@><)`9)<`99)Œ9J%˜JH"ŒE"HŒEC"†CF"†H"F… HJ"`L"JƒLL"ƒLJ"†M"J†ML"ŒLJ"˜JH"ŒE"HŒEC"†CF"†H"F… HJ"`JL"ƒLL"ƒLJ"†JL"ƒLL"ƒLJ"¨@JH)`E)H`E)E‰EC)@CA)@A>%†>A"†A>">">ƒC">„@E"C`EF"`FH"ŒHJ"†JH"†HF"†FE"ƒC"E@A"C@A>"†>A"†A@"ƒ@@"ƒ@>"„@<">`9"<`9%9Š@9:)`:<)`<>%†>A"†A>">>"ƒC">„@E"C`EF"`FH"ŒHJ"†JH"†HF"†E"FƒC"E@A"C@A>"†>A"ŒA>"„@><"`<9"`99%ŒJ%9˜H"JŒHE"ŒEC"†CF"†FH"… HJ"`L"JƒL"LƒJ"L†JM"†ML"ŒLJ"˜JH"ŒHE"ŒEC"†F"C†H"F… HJ"`JL"ƒL"LƒJ"L†JL"ƒLL"ƒJ"L˜Q%J†QM"†J"MŒJQ"†QM"„@MQ"`QR"`V"R˜T)VŒTJ†@Jÿ/MTrkÓ·cb@cb @cb @cbc@cbd@cbf@edÇ0ÿJAZ2ÿ @·J<ÿGeneral MIDIÿ Echo-Part-03ÿYÿYÿÿ· "[@]@b}HKC—>%·—A%˜G"C">AŒGA"C>"Œ>G"C"A’>"A"GC†>G"AC"¹E"@"GC@A"E"E@@>"A"AEA>9"="ƒ9A">"=†E%C%A>‹ =)9)EC`=9>%A%˜F"AC">Œ9"FC<"Œ>"9<A"†E">A"A†C"F"EA‰@"E"FC@@EE"A"@A>"EA"˜>AE)C)ŒA%>%CE˜E"A">AŒAA"E>"Œ>AC"F"’F="C9"†A">"9=Œ>9"A="Œ9=A">"˜E"A"A>ŒA"EA>"ŒAC">F"’CF9"="†A">"=9‰9"=">Aƒ=9A">"ªE)>AC)‰@)E)EC@@E)EA)@EA>%A%ŒAF">C"˜CE"A"FŒEA>"A"†>AA"E"†AF"EC"‰@"E"FC@EE"@A"@EAA">">9"A="ƒ=>"A"9†>AC%E%‹ CE=)9)`=A%9>%ŒF"C"A>˜CA"FE"ŒAEA">"†>E"AA"†AC"F"E‰CFE"@"@E@E"A"@E>"AA"˜C%E%>AŒEA%C>%˜A>A"E"ŒEA"A>"Œ>C"F"A’CF9"="†9=A">"Œ9"A>="Œ=>"A"9˜A>A"E"ŒEA>"A"ŒF"C">A’="FC9"†A">"9=‰A>="9"ƒ9=>"A"¼>A—pH)C)ŒCH>†@>ÿ/MTrkS¸cb@cb @cb @cbc@cbd@cbf@edÈ0ÿJAZ2˜A%¸@ÿGeneral MIDIÿ Echo-Part-04ÿYÿYÿÿ¸ ^[@]CHK}_˜9%ÿ @¸J<’˜>"9"A9†>";"9>ŒA"9";>†>"9"A9„@9"A"9>`9":"A9`9;">":’9";>">†9;">>"’>>"C";ƒCA">>"@A>C">"@C"<"C>Œ<C>";"†>;C"<"†>"C"C<†C@">9"†9@9">"Œ99"@">†9@9">"„@9"A"9>@9A>%9%ž>9>"C"†>@"9"CŒ9">"@9†9"<">9†>"C"9<†>C@"9"†9">"@9–@99)>A)@9A9%>%˜99"><"˜<C">"9ŒC><"C"†@"C<9"†@>"99"Œ@"9">9Œ>"@99"˜>99"<"˜9>"<C"Œ<"C">C†C9"<@"†>"9"@9†>99"@"†9"@>"9¨@9>A)9)@A99%>%ž9C">>"†<"9"C>Œ99"<>"†9>9"<"†<C"9>"†>@"9"C†@9>"9"Œ>99"@"†99"@>"„@9"A"9>@A9%9>%ž9>>"C"†C9"><"Œ<9">"9†9>9"<"†9<>"C"†>9"C@"†9">"9@–@>9"9A"@9A9%>%˜><"99"˜9>"C"<Œ>CC"<"†C<9"@"†99"@>"Œ@"9"9>Œ9>"@9"˜>99"<"˜<C"9>"Œ><"C"C†<C9"@"†9@>"9"†9">9@"†@9">"9˜>9A%9%†9A9">"’9"A"9>†9"9A>"„@9"A">9`9A:"9"`9:9">"˜9<)C)>Œ<C>†@>ÿ/MTrk#¹ÉÿJAZ2ÿ/MTrk4°ÿJAZ2ÿBoring afternoonÿ/simutrans-124.3/simutrans/music/06-A-busy-day-at-the-depot.mid000066400000000000000000000744411474050137200240540ustar00rootroot00000000000000MThd `MTrkˆÿ-(c) shunter 2006 ð~ ÷ÿJAZ2ÿQ5yÿ(My Song ÿ/MTrk íÀÿJAZ2`° @<+T< <+T< <+*<<+*<<+*<<+*° @À<;+T; ;+T; ;+*;;+*;;+*;;+*À° @;<+T< <+T< <+*<<+*<<+*<<+*<À° @;+T; ;+T; ;+*;;+*;;+*;;+*À;° @<+T< <+T< <+*<<+*<<+*<<+*<À° @>+T> >+T> >+*>>+*>>+*>>+*À° @>>+T> >+T> >+*>>+*>>+*>>+*À° @>>+T> >+T> >+*>>+*>>+*>>+*À>° @<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*À° @<;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*À<° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*À° @;=+T= =+T= =+*==+*==+*==+*=° @À=+T= =+T= =+*==+*==+*==+*À° @==+T= =+T= =+*==+*==+*==+*=À° @=+T= =+T= =+*==+*==+*==+*À° @=>+T> >+T> >+*>>+*>>+*>>+*À° @>>+T> >+T> >+*>>+*>>+*>>+*À>° @>+T> >+T> >+*>>+*>>+*>>+*À° @>>+T> >+T> >+*>>+*>>+*>>+*À>° @<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*<À° @;+T; ;+T; ;+*;;+*;;+*;;+*;À° @<+T< <+T< <+*<<+*<<+*<<+*À<° @;+T; ;+T; ;+*;;+*;;+*;;+*À° @;<+T< <+T< <+*<<+*<<+*<<+*<À° @>+T> >+T> >+*>>+*>>+*>>+*>° @À>+T> >+T> >+*>>+*>>+*>>+*À° @>>+T> >+T> >+*>>+*>>+*>>+*>° @À<+T< <+T< <+*<<+*<<+*<<+*° @À<<+T< <+T< <+*<<+*<<+*<<+*<° @À;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*;° @À;+T; ;+T; ;+*;;+*;;+*;;+*À° @;;+T; ;+T; ;+*;;+*;;+*;;+*À;° @<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*<° @À<+T< <+T< <+*<<+*<<+*<<+*À<° @<+T< <+T< <+*<<+*<<+*<<+*<À° @;+T; ;+T; ;+*;;+*;;+*;;+*° @À;;+T; ;+T; ;+*;;+*;;+*;;+*À° @;;+T; ;+T; ;+*;;+*;;+*;;+*° @À;;+T; ;+T; ;+*;;+*;;+*;;+*° @;À=+T= =+T= =+*==+*==+*==+*° @À==+T= =+T= =+*==+*==+*==+*° @À==+T= =+T= =+*==+*==+*==+*=À° @=+T= =+T= =+*==+*==+*==+*À=° @>+T> >+T> >+*>>+*>>+*>>+*À>° @>+T> >+T> >+*>>+*>>+*>>+*À>° @>+T> >+T> >+*>>+*>>+*>>+*° @>À>+T> >+T> >+*>>+*>>+*>>+*>À° @<+T< <+T< <+*<<+*<<+*<<+*<° @À<+T< <+T< <+*<<+*<<+*<<+*° @À<<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*<À° @<+T< <+T< <+*<<+*<<+*<<+*<° @À<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*À<° @<+T< <+T< <+*<<+*<<+*<<+*° @<À<+T< <+T< <+*<<+*<<+*<<+*À° @<<+T< <+T< <+*<<+*<<+*<<+*° @<À;+T; ;+T; ;+*;;+*;;+*;;+*À° @;;+T; ;+T; ;+*;;+*;;+*;;+*À° @;;+T; ;+T; ;+*;;+*;;+*;;+*;À° @;+T; ;+T; ;+*;;+*;;+*;;+*° @;À;+T; ;+T; ;+*;;+*;;+*;;+*° @À;;+T; ;+T; ;+*;;+*;;+*;;+*;ÿ/MTrk íÁÿJAZ2`± @‘@+T@ @+T@ @+*@@+*@@+*@@+*± @Á‘@>+T> >+T> >+*>>+*>>+*>>+*Á± @‘>A+TA A+TA A+*AA+*AA+*AA+*AÁ± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á‘@± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘B+TB B+TB B+*BB+*BB+*BB+*Á± @‘BB+TB B+TB B+*BB+*BB+*BB+*Á± @‘BB+TB B+TB B+*BB+*BB+*BB+*Á‘B± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘A+TA A+TA A+*AA+*AA+*AA+*AÁ± @‘A+TA A+TA A+*AA+*AA+*AA+*Á± @‘AA+TA A+TA A+*AA+*AA+*AA+*AÁ± @‘A+TA A+TA A+*AA+*AA+*AA+*Á‘A± @‘>+T> >+T> >+*>>+*>>+*>>+*>Á± @‘>+T> >+T> >+*>>+*>>+*>>+*>Á± @‘>+T> >+T> >+*>>+*>>+*>>+*>Á± @‘>+T> >+T> >+*>>+*>>+*>>+*Á± @‘>@+T@ @+T@ @+*@@+*@@+*@@+*@± @Á‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@B+TB B+TB B+*BB+*BB+*BB+*Á± @‘BB+TB B+TB B+*BB+*BB+*BB+*Á‘B± @‘B+TB B+TB B+*BB+*BB+*BB+*Á± @‘BB+TB B+TB B+*BB+*BB+*BB+*Á‘B± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘>+T> >+T> >+*>>+*>>+*>>+*>Á± @‘A+TA A+TA A+*AA+*AA+*AA+*Á‘A± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘B+TB B+TB B+*BB+*BB+*BB+*B± @Á‘B+TB B+TB B+*BB+*BB+*BB+*Á± @‘BB+TB B+TB B+*BB+*BB+*BB+*B± @Á‘@+T@ @+T@ @+*@@+*@@+*@@+*± @Á‘@@+T@ @+T@ @+*@@+*@@+*@@+*@± @Á‘@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@± @Á‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*Á‘@± @‘A+TA A+TA A+*AA+*AA+*AA+*Á± @‘AA+TA A+TA A+*AA+*AA+*AA+*A± @Á‘A+TA A+TA A+*AA+*AA+*AA+*Á‘A± @‘A+TA A+TA A+*AA+*AA+*AA+*AÁ± @‘>+T> >+T> >+*>>+*>>+*>>+*± @Á‘>>+T> >+T> >+*>>+*>>+*>>+*Á± @‘>>+T> >+T> >+*>>+*>>+*>>+*± @Á‘>>+T> >+T> >+*>>+*>>+*>>+*± @‘>Á‘@+T@ @+T@ @+*@@+*@@+*@@+*± @Á‘@@+T@ @+T@ @+*@@+*@@+*@@+*± @Á‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘@+T@ @+T@ @+*@@+*@@+*@@+*Á‘@± @‘B+TB B+TB B+*BB+*BB+*BB+*Á‘B± @‘B+TB B+TB B+*BB+*BB+*BB+*Á‘B± @‘B+TB B+TB B+*BB+*BB+*BB+*± @‘BÁ‘B+TB B+TB B+*BB+*BB+*BB+*BÁ± @‘@+T@ @+T@ @+*@@+*@@+*@@+*@± @Á‘@+T@ @+T@ @+*@@+*@@+*@@+*± @Á‘@@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*@Á± @‘A+TA A+TA A+*AA+*AA+*AA+*A± @Á‘A+TA A+TA A+*AA+*AA+*AA+*Á± @‘AA+TA A+TA A+*AA+*AA+*AA+*Á‘A± @‘A+TA A+TA A+*AA+*AA+*AA+*± @‘AÁ‘@+T@ @+T@ @+*@@+*@@+*@@+*Á± @‘@@+T@ @+T@ @+*@@+*@@+*@@+*± @‘@Á‘>+T> >+T> >+*>>+*>>+*>>+*Á± @‘>>+T> >+T> >+*>>+*>>+*>>+*Á± @‘>>+T> >+T> >+*>>+*>>+*>>+*>Á± @‘>+T> >+T> >+*>>+*>>+*>>+*± @‘>Á‘>+T> >+T> >+*>>+*>>+*>>+*± @Á‘>>+T> >+T> >+*>>+*>>+*>>+*>ÿ/MTrk íÂÿJAZ2`² @’E+TE E+TE E+*EE+*EE+*EE+*² @Â’EC+TC C+TC C+*CC+*CC+*CC+*² @’CE+TE E+TE E+*EE+*EE+*EE+*E² @’D+TD D+TD D+*DD+*DD+*DD+*Â’D² @’E+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*Â’E² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*² @’CD+TD D+TD D+*DD+*DD+*DD+*D² @’D+TD D+TD D+*DD+*DD+*DD+*D² @’D+TD D+TD D+*DD+*DD+*DD+*D² @’D+TD D+TD D+*DD+*DD+*DD+*D² @’E+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*² @’CE+TE E+TE E+*EE+*EE+*EE+*E² @Â’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*Â’E² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*² @’CE+TE E+TE E+*EE+*EE+*EE+*E² @’C+TC C+TC C+*CC+*CC+*CC+*C² @’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’D+TD D+TD D+*DD+*DD+*DD+*² @’DE+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*E² @Â’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*E² @Â’C+TC C+TC C+*CC+*CC+*CC+*² @Â’CC+TC C+TC C+*CC+*CC+*CC+*C² @Â’D+TD D+TD D+*DD+*DD+*DD+*D² @’D+TD D+TD D+*DD+*DD+*DD+*D² @Â’D+TD D+TD D+*DD+*DD+*DD+*² @’DD+TD D+TD D+*DD+*DD+*DD+*Â’D² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*E² @Â’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*E² @’C+TC C+TC C+*CC+*CC+*CC+*² @Â’CC+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*² @Â’CC+TC C+TC C+*CC+*CC+*CC+*² @’CÂ’E+TE E+TE E+*EE+*EE+*EE+*² @Â’EE+TE E+TE E+*EE+*EE+*EE+*² @Â’EE+TE E+TE E+*EE+*EE+*EE+*E² @’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EÂ’E+TE E+TE E+*EE+*EE+*EE+*E² @’C+TC C+TC C+*CC+*CC+*CC+*C² @Â’C+TC C+TC C+*CC+*CC+*CC+*² @Â’CC+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*C² @’E+TE E+TE E+*EE+*EE+*EE+*E² @Â’E+TE E+TE E+*EE+*EE+*EE+*² @’EE+TE E+TE E+*EE+*EE+*EE+*Â’E² @’E+TE E+TE E+*EE+*EE+*EE+*² @’EÂ’C+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*² @’CÂ’C+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*² @’CC+TC C+TC C+*CC+*CC+*CC+*C² @’C+TC C+TC C+*CC+*CC+*CC+*² @’CÂ’C+TC C+TC C+*CC+*CC+*CC+*² @Â’CC+TC C+TC C+*CC+*CC+*CC+*Cÿ/MTrk íÃÿJAZ2`³ @“H+TH H+TH H+*HH+*HH+*HH+*³ @ÓHG+TG G+TG G+*GG+*GG+*GG+*ó @“GH+TH H+TH H+*HH+*HH+*HH+*Hó @“G+TG G+TG G+*GG+*GG+*GG+*ÓG³ @“H+TH H+TH H+*HH+*HH+*HH+*Hó @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*ó @“JJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ó @“JJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ÓJ³ @“H+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*ó @“HG+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“H+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*ÓH³ @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*ó @“GI+TI I+TI I+*II+*II+*II+*I³ @ÓI+TI I+TI I+*II+*II+*II+*ó @“II+TI I+TI I+*II+*II+*II+*Ió @“I+TI I+TI I+*II+*II+*II+*ó @“IJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ó @“JJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ÓJ³ @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*ó @“JJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ÓJ³ @“H+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*Hó @“G+TG G+TG G+*GG+*GG+*GG+*Gó @“H+TH H+TH H+*HH+*HH+*HH+*ÓH³ @“G+TG G+TG G+*GG+*GG+*GG+*ó @“GH+TH H+TH H+*HH+*HH+*HH+*Hó @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*J³ @ÓJ+TJ J+TJ J+*JJ+*JJ+*JJ+*ó @“JJ+TJ J+TJ J+*JJ+*JJ+*JJ+*J³ @ÓH+TH H+TH H+*HH+*HH+*HH+*³ @ÓHH+TH H+TH H+*HH+*HH+*HH+*H³ @ÓG+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*G³ @ÓG+TG G+TG G+*GG+*GG+*GG+*ó @“GG+TG G+TG G+*GG+*GG+*GG+*ÓG³ @“H+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*H³ @ÓH+TH H+TH H+*HH+*HH+*HH+*ÓH³ @“H+TH H+TH H+*HH+*HH+*HH+*Hó @“G+TG G+TG G+*GG+*GG+*GG+*³ @ÓGG+TG G+TG G+*GG+*GG+*GG+*ó @“GG+TG G+TG G+*GG+*GG+*GG+*³ @ÓGG+TG G+TG G+*GG+*GG+*GG+*³ @“GÓI+TI I+TI I+*II+*II+*II+*³ @ÓII+TI I+TI I+*II+*II+*II+*³ @ÓII+TI I+TI I+*II+*II+*II+*Ió @“I+TI I+TI I+*II+*II+*II+*ÓI³ @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*ÓJ³ @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*ÓJ³ @“J+TJ J+TJ J+*JJ+*JJ+*JJ+*³ @“JÓJ+TJ J+TJ J+*JJ+*JJ+*JJ+*Jó @“H+TH H+TH H+*HH+*HH+*HH+*H³ @ÓH+TH H+TH H+*HH+*HH+*HH+*³ @ÓHH+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*Hó @“H+TH H+TH H+*HH+*HH+*HH+*H³ @ÓH+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*ÓH³ @“H+TH H+TH H+*HH+*HH+*HH+*³ @“HÓH+TH H+TH H+*HH+*HH+*HH+*ó @“HH+TH H+TH H+*HH+*HH+*HH+*³ @“HÓG+TG G+TG G+*GG+*GG+*GG+*ó @“GG+TG G+TG G+*GG+*GG+*GG+*ó @“GG+TG G+TG G+*GG+*GG+*GG+*Gó @“G+TG G+TG G+*GG+*GG+*GG+*³ @“GÓG+TG G+TG G+*GG+*GG+*GG+*³ @ÓGG+TG G+TG G+*GG+*GG+*GG+*Gÿ/MTrk 0Ä0ÿJAZ2`´ @”Q~QS*ST(Ä0´ @”TX~XV*VV(Ä0´ @”VM~ML*LM*ML*LM*MO*Ä0´ @”OP~PQ*QS(´ @Ä0”SL?L MMO?O MML(L´ @Ä0”N?N OOQ?Q OON(´ @Ä0”NJ*JB*BC*CE*EJ*JB*BC*CE*Ä0´ @”EJ*JI*IJ*JI*IJ(Ä0´ @”JLLJJH~HLLJJH~H´ @Ä0”L~LJ*JH(HÄ0´ @”STS WTW XTX W*WS*Ä0”S´ @”X‚P´ @Ä”X0S(SS~SL*´ @”LÄ”N*NL|L$L*´ @”LÄ”M|M$L*LM*MÄ´ @”O(OQTQ OT´ @”OÄ0 ”HTH HHFFEEFFH*HM*MLLJJHHFF´ @Ä0”HTH HHFFEECCA(Ä0´ @”AJTJ JTJ J*JH*HG*GE*Ä0´ @”EGTG GTG G*GE*EC*CB*´ @Ä0”BOONNLLJJG|´ @”GÄ0$”GTG GTG E*EC~Ä0”C´ @”L*LQ*QP*PQ*QS*SQ*QP*PN*´ @Ä0”NL‚PL´ @Ä0”LLIIE(ED*DE*EG*GÄ´ @”I~IG*GE(´ @”EÄ”J(JJ*JITI J*´ @Ä”JB‚PBÄ´ @0”J*JV*VU*US*SQ*QS*SQ*QO*OÄ´ @”N*NO*ON*NL*LJ(JÄ´ @”HTH @*@A*AC(Ä´ @”CETE C*CA*A@(´ @”@Ä0”H*H@*@A*AC*CH*H@*@A*AC*C´ @Ä0”H*HG*GH*HG*GH(Ä0´ @”HL*LOTO QTQ O*OQTQÄ0´ @ ”Q*QOTO O(OO*OÄ0´ @”M~ML*LM*ML*LM*MO*OÄ0´ @”P~PQ*QS(S´ @Ä0”L?L MMO?O MML(Ä0´ @”LN?N OOQ?Q OON(Ä0´ @”NJ*JB*BC*CE*EJ*JB*BC*CE*´ @”EÄ0”J*JI*IJ*JI*IJ(´ @Ä0”JO*OH*HO*OH*HO*OH*HO*OH*Ä0”H´ @”L*LM*ML*LJ*JH(HÄ0´ @”PTP STS X(XÄ0´ @”WTW UTU S(´ @”SÄ”L(LL*LK*KI*ID*DÄ´ @”G*GE*ED*DB*B@(´ @”@Ä”M(MM*ML*LJ*JE*´ @Ä”EH*HF*FE*EC*CA(´ @Ä0”AMTM L*LJ*JH*HJ*JH*HJ*JÄ0´ @”MTM LTL M(Ä0”M´ @”O*OQQSSOTO O*OQQSSOTOÄ0´ @ ”V~VT*TSSTTSSQQOT´ @”OÄ0 ”O(OO*OQ*QS*ST*TÄ0´ @”V~VV*VV(´ @Ä0”VITI L*LI*II(I´ @Ä0”QTQ P*PN*NL(´ @Ä”LQ‚PÄ´ @”Q0Q*QP*PQ*QS*SUTU QTÄ”Q´ @ ”J*JL*LN|N´ @Ä$”N*NJ*JJ*JJ*JJ*JI*IJTJ´ @Ä ”Q~QJ*JL*LN*NJTJÄ´ @ ”Q~QJ*JL*LN*NQT´ @Ä”Q H|H$G*GH*Ä´ @”HJ(JLTL JTJ´ @Ä0 ”L*LH*HL*LH*HL*LH*HL*LH*Ä0´ @”HO*OL*LO*OL*LO*OL*LO*OL*´ @Ä0”LM(MHTH JT´ @Ä0”J E‚PÄ0´ @”E0Q(QOTO MT´ @Ä0”M T(TRTR QT´ @Ä0”Q HHGGEECC@|Ä0”@´ @$”@T@ @T@ >*><~Ä0”<´ @”JTJ CTC GTG CTC´ @Ä0 ”JTJ C|´ @Ä0”Cƒ´ @Ä0‚t0´ @ƒÄ0´ @ÿ/MTrk¸Å ÿJAZ2`µ @•-P*--P*-4P*44P*49P*99P*94P*44P*µ @Å •47P*77P*7>P*>>P*>CP*CCP*C>P*>>P*Å •>µ @•)P*))P*)0P*00P*05P*55P*50P*00P*Å •0µ @•4P*44P*4;P*;;P*;@P*@@P*@;P*;;P*Å •;µ @•-P*--P*-4P*44P*49P*99P*94P*44P*4µ @Å •2P*22P*29P*99P*9>P*>>P*>9P*99P*9Å µ @•&P*&&P*&-P*--P*-2P*22P*2-P*--P*µ @Å •-&P*&&P*&-P*--P*-2P*22P*2-P*--P*µ @Å •-$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @•+Å •$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @•+Å •(P*((P*(/P*//P*/4P*44P*4/P*//P*µ @•/Å •(P*((P*(/P*//P*/4P*44P*4/P*//P*Å •/µ @•(P*((P*(/P*//P*/4P*44P*4/P*//P*Å µ @•/(P*((P*(/P*//P*/4P*44P*4/P*//P*Å •/µ @•)P*))P*)0P*00P*05P*55P*50P*00P*Å µ @•0)P*))P*)0P*00P*05P*55P*50P*00P*Å •0µ @•)P*))P*)0P*00P*05P*55P*50P*00P*0Å µ @•)P*))P*)0P*00P*05P*55P*50P*00P*Å µ @•0+P*++P*+2P*22P*27P*77P*72P*22P*2Å µ @•+P*++P*+2P*22P*27P*77P*72P*22P*µ @Å •2+P*++P*+2P*22P*27P*77P*72P*22P*2Å µ @•+P*++P*+2P*22P*27P*77P*72P*22P*µ @•2Å •-P*--P*-4P*44P*49P*99P*94P*44P*4Å µ @•-P*--P*-4P*44P*49P*99P*94P*44P*µ @Å •4-P*--P*-4P*44P*49P*99P*94P*44P*µ @Å •4-P*--P*-4P*44P*49P*99P*94P*44P*Å µ @•4&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å µ @•-&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•$P*$$P*$+P*++P*+0P*00P*0+P*++P*+µ @Å •$P*$$P*$+P*++P*+0P*00P*0+P*++P*+µ @Å •$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @Å •+$P*$$P*$+P*++P*+0P*00P*0+P*++P*Å µ @•+-P*--P*-4P*44P*49P*99P*94P*44P*Å µ @•47P*77P*7>P*>>P*>CP*CCP*C>P*>>P*>µ @Å •)P*))P*)0P*00P*05P*55P*50P*00P*0µ @Å •4P*44P*4;P*;;P*;@P*@@P*@;P*;;P*µ @•;Å •-P*--P*-4P*44P*49P*99P*94P*44P*4Å µ @•2P*22P*29P*99P*9>P*>>P*>9P*99P*9µ @Å •&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•$P*$$P*$+P*++P*+0P*00P*0+P*++P*+µ @Å •$P*$$P*$+P*++P*+0P*00P*0+P*++P*Å •+µ @•(P*((P*(/P*//P*/4P*44P*4/P*//P*µ @Å •/(P*((P*(/P*//P*/4P*44P*4/P*//P*µ @Å •/(P*((P*(/P*//P*/4P*44P*4/P*//P*/Å µ @•(P*((P*(/P*//P*/4P*44P*4/P*//P*µ @•/Å •)P*))P*)0P*00P*05P*55P*50P*00P*µ @Å •0)P*))P*)0P*00P*05P*55P*50P*00P*µ @Å •0)P*))P*)0P*00P*05P*55P*50P*00P*µ @Å •0)P*))P*)0P*00P*05P*55P*50P*00P*µ @Å •0+P*++P*+2P*22P*27P*77P*72P*22P*2µ @Å •+P*++P*+2P*22P*27P*77P*72P*22P*µ @•2Å •+P*++P*+2P*22P*27P*77P*72P*22P*µ @Å •2+P*++P*+2P*22P*27P*77P*72P*22P*2µ @Å •-P*--P*-4P*44P*49P*99P*94P*44P*4µ @Å •-P*--P*-4P*44P*49P*99P*94P*44P*Å •4µ @•-P*--P*-4P*44P*49P*99P*94P*44P*4Å µ @•-P*--P*-4P*44P*49P*99P*94P*44P*Å µ @•4&P*&&P*&-P*--P*-2P*22P*2-P*--P*µ @Å •-&P*&&P*&-P*--P*-2P*22P*2-P*--P*-Å µ @•&P*&&P*&-P*--P*-2P*22P*2-P*--P*µ @•-Å •&P*&&P*&-P*--P*-2P*22P*2-P*--P*Å •-µ @•$P*$$P*$+P*++P*+0P*00P*0+P*++P*+µ @Å •$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @Å •+$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @Å •+$P*$$P*$+P*++P*+0P*00P*0+P*++P*Å µ @•+)P*))P*)0P*00P*05P*55P*50P*00P*µ @•0Å •)P*))P*)0P*00P*05P*55P*50P*00P*Å •0µ @•)P*))P*)0P*00P*05P*55P*50P*00P*µ @•0Å •)P*))P*)0P*00P*05P*55P*50P*00P*Å µ @•0$P*$$P*$+P*++P*+0P*00P*0+P*++P*+Å µ @•$P*$$P*$+P*++P*+0P*00P*0+P*++P*µ @•+Å •+P*++P*+2P*22P*27P*77P*72P*22P*Å •2µ @•+P*++P*+2P*22P*27P*77P*72P*22P*2Å µ @•+P*++P*+2P*22P*27P*77P*72P*22P*Å µ @•2+P*++P*+2P*22P*27P*77P*72P*22P*Å •2µ @•+P*++P*+2P*22P*27P*77P*72P*22P*Å µ @•2+P*++P*+2P*22P*27P*77P*72P*22P*2ÿ/MTrk#mÿJAZ2`™$F1F9F*F¹ @™&F09&**F$10$F&F**F0*F*$&0*&F*F$F0&*$*F0*F$F&F*0$&*F*0&F*F9F1F¹ @™$F*01*9&*F$0&F*$F*F0&*$*F0$F*&F*F0$*F&*0*$F&F*F0&*$*F0$F9F¹ @™**F&F1F0$&91**F0*F&F*$F0*F&$*0&F*F*$F0&*F*$0*$F*F&F0*&*F$0*1F¹ @™&F$F9F*F01$**F&90*F$F&F*0&**F$0*F&F$F*0*F*$&0*F&F*$F0*$*F&0*F1F&F¹ @™*$F9F0$&*19*F0*F*&F$F0$*&*F0*F$F*&F0*F&*$0$F*F*&F0&$**F09F&F*F1F*$F¹ @0™1$9*&*F0$F*F*&F0&*F$*0*F&F*$F0*$*F&0*&F$F*F0$*&*F0*F$F1F9F¹ @™*&F0$&9**F10&F$F*F*0*&*F$0$F&F**F0*&*F$0*F&F*$F0&$**F09F¹ @™$F*F1F&F*0&1$*9*F0$F*F*&F0&**F$0*F$F*&F0$*F*&0*F$F*&F0&$**F0*F*1F¹ @™9F&F$F0$1*9&*F0*F&F*$F0*$*F&0&F$F*F*0&$*F*0*F$F*&F0$&*F*0*&F9F¹ @™*F$F1F0*$19&*F0*F&F*$F0*F*&$0&F$F**F0&$**F0*F&F*$F0&*F$*0*9F*F1F¹ @™&F$F01*&$*F90$F*F*&F0$&**F0**F&F$F0*&*F$0&F**F$F0$**F&0*$F1F9F*F¹ @™&F091&*F*$0*$F&F*F0*$&*F0*F$F*&F0*$&*F0*F*$F&F0$*F&*0*9F$F1F&F*F¹ @0™91$*&*F0&F*F*$F0**F&$0*F$F*&F0*F*&$0*&F*F$F0$**F&0*&F*F¹ @™1F$F9F0*&$91*F0$F*F*&F0$*F&*0*$F&F*F0&**F$0&F$F*F*0*F*&$01F&F¹ @™$F*F9F*0*F1$*&90*F&F$F*0$&**F0$F&F*F*0$*&*F0*F$F*&F0$*&*F09F$F*¹ @™1F*F&F0$&*1*F90*F&F$F*0$&**F0**F$F&F0&*$*F0$F*F&F*0*$&*F0$F9F¹ @™1F*F*&F0&*F1$9*0*&F$F*F0*F*&$0&F*$F*F0$*&*F0$F*F*&F0*&$*F0¹ @™$F&F*9F*F1F0$*F*1&90*&F$F*F0*$&*F0*&F*F$F0**F$&0*F$F*&F0&**F$0¹ @™*$F*F9F&F1F0*$1&9*F0**F&F$F0*$&*F0$F*&F*F0*F$&*0*F*&F$F0$**F&0*F*&F¹ @™9F$F1F0*&1$9*F0*$F*F&F0&$**F0*F*&F$F0*$*F&0*$F*F&F0*F*$&0*$F¹ @™9F&F*F1F0*1$&9*F0*F*&F$F0$**F&0&F$F**F0*&$*F0*F$F&F*0&*$*F0&F$F*F*9F1F¹ @0™*1&$9*F0&F**F$F0&$**F0&F$F**F0*F*$&0$F*&F*F0$*F&*0$F&F1F**F¹ @™9F0$1**F&90$F*&F*F0**F&$0**F&F$F0*F*$&0*F*&F$F0$*F*&0*9F&F*F$F1F¹ @0™*F1&*9$0**F$F&F0*F$*&0*&F*F$F0$*&*F0*$F&F*F0$&*F*01F*&F9F*F$F¹ @0™91*F&$*0*F$F*&F0*&$*F0**F$F&F0**F&$0*F&F$F*0&$**F01F&F9F¹ @™*F$F*0&19$**F0*&F*F$F0*F$*&0**F$F&F0&$**F0$F&F*F*0*F*&$01F*¹ @™*F&F$F9F0$*F9*&10**F$F&F0&$**F0*F$F*&F0&**F$0*&F$F*F0*F&$*0¹ @™9F$F*F&F1F*09**F1$&0&F*F*$F0*F&*$0*$F*F&F0*F$&*0*&F$F*F0*$&*F0*$F*F¹ @™9F1F&F01&*$9*F0&F*F$F*0&$*F*0**F&F$F0&*$*F0*$F*F&F0$**F&0$F*¹ @™&F9F*F1F09&$*F*10*F$F*&F0$*&*F0$F**F&F0*$&*F0&F*F*$F0**F$&0¹ @™&F*F9F$F1F*01&$9**F0*F$F*&F0$&**F0&F$F*F*0$*&*F0$F*F&F*0*F*&$01F*F*¹ @™&F$F9F0$&*91*F0*&F$F*F0*&*F$0$F**F&F0$&**F0*F&F$F*0*F&*$0$F9F&F¹ @™**F1F0$*F&9*10&F$F*F*0$*&*F0&F*$F*F0&$**F0&F$F*F*0*F$&*09F¹ @™$F*1F*F&F01*&*F9$0**F&F$F0*$&*F0*$F*F&F0&$**F0$F&F*F*0$*&*F0*9F$F1F¹ @™*F&F09$1&**F0*&F$F*F0*&*F$0&F*F$F*0&$**F0$F&F*F*0&$*F*09F$F1F*F&F¹ @™*01$*F*9&0&F**F$F0*&$*F0*$F*F&F0&*$*F0&F$F*F*0&$**F0¹ @™1F9F*F*&F$F0*F9*$&10*&F$F*F0&*$*F0$F*F&F*0&*$*F0$F&F*F*0&*$*F0¹ @™1F&F$F*9F*F0*F*&$910*&F*F$F0&$**F0$F*F&F*0&*$*F0*F$F&F*0$&**F0$F1F*F¹ @™*9F&F0$*F1&*90*$F*F&F0*$*F&0*&F*F$F0$*&*F0$F&F*F*0$*&*F0*&F1F9F*F$F¹ @0™*F*91$&0*&F*F$F0&$**F0&F$F*F*0*$&*F0*F&F$F*0&$**F0*F$F1F9F*¹ @™&F0*F&$19*0**F&F$F0*$&*F0$F*F&F*0&*$*F0&F$F*F*0$*&*F0*F&F1F$F*¹ @™9F0$*F1&*90*$F*F&F0*F&$*0*$F*F&F0$*&*F0$F*F&F*0*F$*&0*&F¹ @™$F*F1F9F0*F*$&190*&F$F*F0&*$*F0&F$F*F*0*$&*F0$F*F&F*0*&$*F0¹ @™9F*F$F*1F&F0*$&1*F90**F$F&F0$*&*F0**F&F$F0$*F*&0*&F$F*F0&*F$*0&F1F*9F$F¹ @™*F0&1*F$9*0*F&F*$F0*F&*$0&F*F$F*0**F$&0**F&F$F0&$**F0*1F&F*F9F$F¹ @0™*&19*F$0&F*F*$F0*&*F$0*&F*F$F0*F&*$0*&F$F*F0$*&*F01F$F9F&F*F*¹ @0™*91$&*F0$F&F*F*0*F*&$0*$F*F&F0&*$*F0*F*&F$F0*$&*F0*9F1F¹ @™*F$F&F01$&*9*F0$F**F&F0$&*F*0&F*F$F*0**F$&0*&F*F$F0&$**F0*1F$F*F¹ @™9F&F091*F&*$0*$F&F*F0**F$&0$F&F*F*0&**F$0*F*&F$F0&$**F0¹ @™9F&F$F1F*F*0*9$1&*F0**F$F&F0*F*$&0**F$F&F0$&*F*0&F$F*F*0&$*F*0$F&F*F¹ @™*1F9F0*&1$9*F0**F&F$F0*F$&*0*&F*F$F0&*$*F0&F**F$F0*$&*F0*1F*F¹ @™&F9F$F01*F$*&90*$F&F*F0&*$*F0$F**F&F0&$*F*0*$F*F&F0*F*$&0*F$F¹ @™*&F1F9F0&*1$*F90**F$F&F0$*&*F0**F&F$F0$*F*&0*&F$F*F0&*F$*01F&F*$F¹ @™9F*F01&*F9$*0$F*F*&F0*F*$&0*$F*F&F0*&$*F0$F*F&F*0$&*F*09F*F&F*¹ @™$F1F0&*9*F$10$F&F*F*0&$**F0**F&F$F0$&**F0*F*$F&F0*F*$&0*F1F9F&F¹ @™$F*0*F*91&$0*F$F&F*0*$&*F0*F*&F$F0*$&*F0&F*F$F*0*F$*&09F¹ @™1F*F$F&F*0$19&**F0*$F*F&F0*F&*$0*&F$F*F0$**F&0*F$F&F*0*$&*F0$F1F*¹ @™*F9F&F09*&1$*F0**F&F$F0&*F$*0*$F*F&F0$&**F0*$F*F&F0$*&*F0¹ @™1F*9F$F*F&F0*&9*F$10*&F$F*F0&$*F*0**F&F$F0$*&*F0*&F$F*F0$&**F01F9F¹ @™**F&F$F09&*1$*F0&F$F**F0$*&*F0*&F*F$F0*&*F$0$F&F*F*0*&$*F01F*$F&F9F¹ @™*F0&9*$*F10$F*&F*F0$&*F*0&F$F**F0*F&$*0$F*F*&F0&*$*F0*1F*F$F9F&F¹ @0™9&*1*F$0*&F*F$F0*&$*F0&F*F*$F0&$*F*0$F&F**F0*&*F$0&F$F9F*¹ @™1F*F01&*$9*F0*F*&F$F0*F$&*0$F&F**F0*F&$*0$F&F**F0**F&$01F*F¹ @™*$F9F&F0*&1$9*F0*&F*F$F0*F$*&0$F*&F*F0*F$*&0*$F&F*F0$*&*F0*F¹ @™9F$F*&F1F0*F91$*&0*F&F$F*0$*&*F0&F*F*$F0&**F$0**F&F$F0*$&*F01F¹ @™9F*F$F*&F09*F*1&$0**F$F&F0*&$*F0**F&F$F0*F$&*0*F*$F&F0*F$*&0&F**F$F¹ @™9F1F09&*$1*F0*F$F&F*0*F$*&0&F**F$F0*F$*&0*F$F&F*0*F*&$0$F9F1F**F&F¹ @0™&1$9**F0**F$F&F0$**F&0&F*F*$F0*F*$&0&F*F$F*0$*&*F0&F9F*1F¹ @™*F$F0*F1$*&90*$F&F*F0$&*F*0&F*F$F*0&*$*F0$F*F*&F0*&$*F0&F*F$F*9F1F¹ @0™91$**F&0*F$F&F*0*$&*F0*$F&F*F0$*&*F0*&F$F*F0*&$*F09F*F¹ @™$F&F1F*0*F1&9*$0*$F&F*F0&*F*$0*F&F*$F0$*F&*0&F**F$F0*&$*F0¹ @™*F9F*$F1F&F0&**F19$0$F&F*F*0$&*F*0&F*F$F*0*$*F&0$F*&F*F0*&$*F0&F*1F9F$F¹ @™*F09$1&**F0*F$F&F*0*$*F&0&F*$F*F0&*F$*0$F*F&F*0&*$*F0&F¹ @™*F1F$F9F*0*F9*1$&0*&F*F$F0*&$*F0*$F*F&F0*$&*F0&F$F**F0$**F&0*¹ @™$F9F1F&F*F01&*F*9$0$F*F*&F0&*F*$0&F*F*$F0$*F&*0*&F*F$F0$*&*F0&F*F$F1F¹ @™*9F0*F9&*$10*&F$F*F0$*F&*0$F*&F*F0*$&*F0$F&F**F0*$&*F0*1F$F&F*F¹ @™9F0**F91&$0**F$F&F0&*F$*0&F*F$F*0*F&$*0**F&F$F0&*$*F0¹ @™1F**F9F&F$F01$&*F*90**F$F&F0*&$*F0&F**F$F0&*$*F0&F*F$F*0*&*F$01F&F*9F¹ @™$F*F0*F91$*&0&F**F$F0&$**F0*F$F&F*0&$*F*0$F*F&F*0*$&*F0&F#F¹ @™*&&F#*FH*&#F&F&HF#H#F&FHHF#*F&&FHF&*H0.F#F9F5F&FH`5&#9.ÿ/MTrk:°ÿJAZ2ÿA busy day at the dpotÿ/simutrans-124.3/simutrans/music/07-Transport-chaos.mid000066400000000000000000000455161474050137200227410ustar00rootroot00000000000000MThd`MTrk×ÿ(c) shunter 2006ð~ ÷ÿJAZ2ÿC 7ƒÿC 7@ÿF 7@ÿC 7†ÿC 7†ÿF 7†ÿC 7†ÿC 7†ÿF 7†ÿC 7@ÿG 7@ÿG 7@ÿF 7`ÿF 7`ÿC 7@ÿG 7@ÿG 7@ÿF 7`ÿF 7`ÿC 7ƒÿG 7ƒÿG 7ƒÿF 7ƒÿF 7ƒÿF 7ƒÿC 7@ÿC 7@ÿC 7@ÿF 7@ÿC 7@ÿC 7@ÿC 7@ÿF 7@ÿC 7@ÿG 7@ÿC 7ƒÿC 7@ÿG 7@ÿC 7ƒÿC 7@ÿG 7@ÿC 7ƒÿC 7@ÿG 7@ÿC 7ƒÿC 7`ÿC 7@ÿF 7`ÿC 7`ÿC 7@ÿF 7`ÿC 7`ÿC 7@ÿF 7`ÿC 7†ÿF 7†ÿX`ÿQ¡ ÿG 7ƒÿC 7ÿC 7@ÿC 7ƒÿG 7@ÿC 7@ÿC 7ƒÿG 7@ÿC 7`ÿG 7`ÿG 7`ÿC 7`ÿC 7`ÿG 7`ÿG 7`ÿC 7`ÿC 7`ÿG 7`ÿG 7`ÿC 7`ÿC 7ƒÿG 7ƒÿF 7ƒÿG 7ƒÿC 7ƒÿG 7ƒÿF 7ƒÿG 7ƒÿC 7ƒÿG 7ƒÿF 7ƒÿG 7ƒÿC 7ƒÿG 7ƒÿF 7ƒÿG 7ƒÿC 7`ÿG 7@ÿG 7`ÿC 7`ÿG 7@ÿG 7`ÿC 7@ÿC 7`ÿF 7`ÿC 7@ÿC 7`ÿF 7`ÿC 7`ÿF 7`ÿF 7`ÿG 7`ÿC 7`ÿF 7`ÿF 7`ÿG 7`ÿC 7@ÿC 7ƒÿC 7@ÿC 7ƒÿC 7@ÿC 7ƒÿC 7ÿ/MTrk ð~ ÷±ÁÿJAZ2@‘H@=HC@ CD@ DE@ EF@ F@@ @A@ AB@ BC@ C?@ ?>@ >=@ =<@ <F@=FE@ EH@=H‚#C@=CF@FC@C<@=<C@=C<@=<CC@=CF@FC@C<@=<C@=C<@=<C@=C<@=<F@=F<@=<D@ DD@ DD@ DD@ D@@ @?@ ?=@ =<@ <C@=C<@<F@=FC@C<@<?@?<@=<A@ AA@=AE@E<@=<?@=?A@=A#E@E‚C@=CF@FC@C<@=<C@=C<@=<CC@=CF@FC@C<@=<C@=C<@=<C@=C<@=<F@=F<@=<D@ DD@ DD@ DD@ D@@ @?@ ?=@ =<@ <C@=C<@<F@=FC@C<@<?@?<@=<A@ AA@=AE@E<@=<?@=?A@=A#E@EcC@=CF@FcC@=CJ@J>@=>C@=CJ@=JH@H?@=?<@=<A@AcC@=CF@FcC@=CJ@J>@=>C@=CJ@=JH@H?@=?<@=<A@A‚F@=FH@=HC@=C>@=>C@=CJ@=JC@CJ@ JC@ CJ@=JC@=C>@=>C@=CJ@ JC@ C‚A@=AE@=EH@=HE@=EK@KH@=H?@?A@=AE@=EH@=HE@=EK@KH@=H?@=?E@=EA@=AH@=HE@ EH@ HK@K…?@=?A@=A…?@=?A@=A<@=<C@=CH@ HT@ TR@RC<@=<C@=CH@=HT@=TO@=OF@=F<@=<C@=CH@ HT@ TR@RC<@=<C@=CH@=HT@=TO@=OF@=F<@=<C@=CH@ HT@ TR@RC<@=<C@=CH@=HT@=TO@=OF@=F<@=<C@=CH@ HT@ TR@RC<@=<C@=CH@=HT@=TO@=OF@=FC?@=?A@A?@=?A@=A?@=?E@E<@=<?@=?A@A?@=?A@=A?@=?E@E>@ >7@ 7>@=>±sK@ÿX`±]<JK‘C@±I@[<H@ @G@=‘C>@ >C@ C>@=>C@=C>@=>>@]><@]<C0=CF@=FO@=OT@=TJ@=J>@=>C@=CƒF@=FO@=OT@=TJ@=J>@=>C@=Cc>@=>C@ C>@ >7@=7C@C<@=<C@Cc>@=>C@ C>@ >7@=7C@C<@=<C@Cc>@=>C@ C>@ >7@=7C@C<@=<C@C„>@=>C@=C>@=>C@=C<@<9@ 9?@ ?<@=<B@ BA@ A@@ @?@ ?@@ @?@ ?=@ =<@ <?@=?E@ ED@ DB@ BA@ A7@=7>@=>7@=7C@=C>@>C@=C>@>„>@=>C@=C>@=>C@=C<@<9@ 9?@ ?<@=<B@ BA@ A@@ @?@ ?@@ @?@ ?=@ =<@ <?@=?E@ ED@ DB@ BA@ A7@=7>@=>7@=7C@=C>@>C@=C>@>„>@=>C@=C>@=>C@=C<@<9@ 9?@ ?<@=<B@ BA@ A@@ @?@ ?@@ @?@ ?=@ =<@ <?@=?E@ ED@ DB@ BA@ A7@=7>@=>7@=7C@=C>@>C@=C>@>„>@=>C@=C>@=>C@=C<@<9@ 9?@ ?<@=<B@ BA@ A@@ @?@ ?@@ @?@ ?=@ =<@ <?@=?E@ ED@ DB@ BA@ A7@=7>@=>7@=7C@=C>@>C@=C>@><@=<C@C7@=7c<@=<C@C7@=7‚#<@=<C@=C<@=<:@:?@=?<@<C<@=<C@=C<@=<:@:?@=?<@<<@=<H@Hc<@=<H@ HK@ KC@=C#<@=<H@Hc<@=<H@ HK@ KC@=CƒCO@=OT@=TR@ RT@ Tƒ#O@=OT@=TR@ RT@ Tƒ#O@=OT@=TR@ RT@ TT@]T[0=[ÿ/MTrk-¶ÆÿJAZ2@–C@=CC?@=?A@ A?@=?‚#<@=<:@:<@<3@=3<@=<3@=3C<@=<<@<7@73@=3<@=<3@=3<@=<3@=3C@=C3@=3<@=<3@3C@=C?@?5@53@35@=5<@ <5@=5<@<5@=53@=3<@=<#<@<‚<@=<:@:<@<3@=3<@=<3@=3C<@=<<@<7@73@=3<@=<3@=3<@=<3@=3C@=C3@=3<@=<3@3C@=C?@?5@53@35@=5<@ <5@=5<@<5@=53@=3<@=<#<@<c<@=<:@:c>@=>C@C7@=7?@=?C@=CA@A9@=95@=5<@<c<@=<:@:c>@=>C@C7@=7?@=?C@=CA@A9@=95@=5<@<‚?@=??@=?7@=77@=7?@=?C@=C7@7A@ A?@ ?C@=C7@=77@=7?@=?C@ C7@ 7‚<@=<9@=9A@=A<@=<A@A?@=?9@95@=5?@=?A@=A<@=<A@A<@=<9@=9?@=?<@=<A@=A<@ <E@ EE@E…9@=95@=5…9@=95@=57@=7<@=<F@ FK@ KO@OC3@=3<@=<F@=FK@=KH@=H<@=<7@=7<@=<F@ FK@ KO@OC3@=3<@=<F@=FK@=KH@=H<@=<7@=7<@=<F@ FK@ KO@OC3@=3<@=<F@=FK@=KH@=H<@=<7@=7<@=<F@ FK@ KO@OC3@=3<@=<F@=FK@=KH@=H<@=<C9@=95@59@=95@=59@=9?@?5@=53@=3<@<5@=55@=55@=5<@<¶[<–7@¶sG@JK]<I@K@H@ –7+@ +7@=7A@=A3@ 37@ 77@=7>@=>7@=700=0C?@=?C@=CO@=OC@=C7@=7?@=?ƒ?@=?C@=CO@=OC@=C7@=7?@=?c7@=7?@ ?7@ 7+@=+>@>0@=0?@?c7@=7?@ ?7@ 7+@=+>@>0@=0?@?c7@=7?@ ?7@ 7+@=+>@>0@=0?@?„7@=7?@=?7@=7?@=?5@53@ 39@ 95@=5<@=<C+@=+7@=7+@=+>@=>7@77@=77@7„7@=7?@=?7@=7?@=?5@53@ 39@ 95@=5<@=<C+@=+7@=7+@=+>@=>7@77@=77@7„7@=7?@=?7@=7?@=?5@53@ 39@ 95@=5<@=<C+@=+7@=7+@=+>@=>7@77@=77@7„7@=7?@=?7@=7?@=?5@53@ 39@ 95@=5<@=<C+@=+7@=7+@=+>@=>7@77@=77@77@=7<@<+@=+c7@=7<@<+@=+‚#7@=7<@=<3@=33@3<@=<5@5C7@=7<@=<3@=33@3<@=<5@57@=7C@Cc5@=5A@ AA@ A7@=7#7@=7C@Cc5@=5A@ AA@ A7@=7ƒCH@=HO@=OK@ KH@ Hƒ#H@=HO@=OK@ KH@ Hƒ#H@=HO@=OK@ KH@ H00=0ÿ/MTrkc´ÄÿJAZ2Š`”C@=CF@FH@=HH@=HC@=C<@=<C@=CF@=FH@=HH@=HC@=C<@=<C@=CF@=FH@=HH@=HA@=A<@=<A@=AE@=EH@=HH@=HA@=A<@=<A@=AE@=EH@=H„cC@=CF@FH@=HH@=HC@=C<@=<C@=CF@=FH@=HH@=HC@=C<@=<C@=CF@=FH@=HH@=HA@=A<@=<A@=AE@=EH@=HH@=HA@=A<@=<A@=AE@=EH@=H:@ :9@ 98@ 87@ 7>@=>7@7F@ FE@ ED@ DC@ C>@>4@ 45@ 56@ 67@ 7-@ -/@ /1@ 12@ 27@=7>@=>7@=7C@=C@@ @?@ ?=@ =<@ <3@32@ 23@ 34@ 45@ 59@=9<@=<?@=?A@A<@=<3@=39@=9<@=<?@=?A@=A<@ <0@ 03@=35@=59@9<@=<?@=?A@=A…9@=9?@=?…9@=9?@=?C7@7:@=:C@C>@=>7@=7>@=><@=<7@=7‚C7@7:@=:C@C>@=>7@=7>@=><@=<7@=7‚C7@7:@=:C@C>@=>7@=7>@=><@=<7@=7‚C7@7:@=:C@C>@=>7@=7>@=><@=<7@=7‚CC@C<@=<C@=C<@=<0@=0cC@C<@=<C@=C<@=<0@=0cC@C<@=<C@=C<@=<0@=0c7@=7<@=<C@=CF@=FC@=C<@=<7@=7<@=<C@CH@ HH@=HA@=A#E@=EH@HH@=HA@=A<@=<A@=AE@=EH@=H´J@[<H@]<s”>@´I@K@G@=”>7@=7>@=>C@=CJ@=JC@=CC@0@=0.@CH0.7@=70@=0.@H .7@=70@=07@=70@=0+@=+2@=2+@=+0@=0.@=.7@=70@=0.@=.7@=70@=07@=70@=0+@=+2@=2+@=+c2@2>@=>2@=2c2@2>@=>2@=2c2@2>@=>2@=20@=07@=7<@=<C@=CF@=FH@=Hƒ0@=0‚H@=HH@=H>@=>7@=7C@C>@>J@=JC@=C0@=07@=7<@=<C@=CF@=FH@=Hƒ0@=0‚H@=HH@=H>@=>7@=7C@C>@>J@=JC@=C0@=07@=7<@=<C@=CF@=FH@=Hƒ0@=0‚H@=HH@=H>@=>7@=7C@C>@>J@=JC@=C0@=07@=7<@=<C@=CF@=FH@=Hƒ0@=0‚H@=HH@=H>@=>7@=7C@C>@>J@=JC@=CC7@7+@=+7@=77@ 7>@ >C7@7+@=+7@=77@ 7>@ ><@=<0@=07@70@03@=3<@=<0@=07@70@03@=3c0@=09@9‚#0@=09@9ÿ/MTrk²Â ÿJAZ2’$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$"h>""h")h>))h)9h>90h0$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$"h>""h"-h-.h6..h.h>h)h>))h)'h>''h'&h&'h6''h'2h>20h0)h>))h)-h>-0h0&h&'h6''h'2h>20h0$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+)h>))h)-h>-0h02h23h633h3$h>$$h$)h>))h)-h>-0h02h23h633h32h>20h0$h>$$h$(h>(+h++h>++h+/h>/2h2+h>++h+;h>;2h2)h>))h))h>))h)$h>$$h$4h>4+h++h>++h+)h>))h)+h>++h+)h>))h))h>))h))h>))h)$h>$$h$"h>""h"-h-.h6..h.-h>-+h++h>++h+)h>))h)'h'(h6((h(&h>&&h&+h>++h+/h>/2h2'h'(h6((h(4h>42h2)h>))h)9h>90h0%h%&h6&&h&2h>20h0)h>))h)-h>-0h0&h&'h6''h'2h>20h0)h>))h)'h>''h'2h23h633h3$h>$$h$$h>$$h$"h>""h"$h>$$h$(h>(+h+$h>$$h$4h>4+h+)h>))h)9h>90h0$h>$$h$(h>(+h+$h>$$h$(h>(+h+$h>$$h$(h>(+h+)h>))h)-h>-0h0$h>$$h$(h>(+h++h>++h+/h>/2h2$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h++h>++h+/h>/2h2$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$4h>4+h++h>++h+;h>;2h2$h>$$h$"h>""h" h !h6!!h!-h>-+h+$h>$$h$(h>(+h++h>++h+/h>/2h2$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$$h>$$h$(h>(+h+)h>))h)$h>$$h$$h>$$h$(h>(+h+)h>))h)$h>$$h$$h>$$h$4h>4+h+)h>))h)$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+)h>))h)-h>-0h02h23h633h3$h>$$h$)h>))h)'h>''h'2h23h633h32h>20h0²K@J@[<G@H@]<UI@’+h>++h+)h>))h)(h>((h('h>''h')h$h>$)$h'h'$4h&h>4&$h+h+$h>$$h$$"h>""h"-h-.h6..h.h>h+h>++h+/h>/2h2$h>$$h$"h>""h"$h>$$h$(h>(+h+-h-.h6..h.-h>-+h++h>++h+/h>/2h2$h>$$h$+h>++h++h>++h+$h>$$h$$h>$$h$+h>++h++h>++h+$h>$$h$$h>$$h$+h>++h++h>++h+$h>$$h$$h>$$h$"h>""h"-h-.h6..h.-h>-+h++h>++h+/h>/2h2'h'(h6((h(4h>42h2)h>))h)'h>''h'2h23h633h32h>20h0+h>++h+/h>/2h24h45h655h5&h>&&h&$h>$$h$"h>""h"-h-.h6..h.-h>-+h++h>++h+/h>/2h24h45h655h54h>42h2)h>))h)9h>90h0&h&'h6''h'2h>20h0+h>++h+)h>))h)4h45h655h5&h>&&h&$h>$$h$(h>(+h+-h-.h6..h.-h>-+h++h>++h+;h>;2h24h45h655h5&h>&&h&)h>))h)-h>-0h0%h%&h6&&h&2h>20h0+h>++h+/h>/2h24h45h655h54h>42h2$h>$$h$4h>4+h+ h !h6!!h!-h>-+h++h>++h+/h>/2h2(h()h6))h)&h>&&h&)h>))h)-h>-0h0%h%&h6&&h&2h>20h0+h>++h+)h>))h)4h45h655h54h>42h2$h>$$h$+h>++h+)h>))h)+h>++h+$h>$$h$+h>++h+/h>/2h2+h>++h+$h>$$h$4h>4+h+$h>$$h$)h>))h)$h>$$h$(h>(+h+$h>$$h$)h>))h)$h>$$h$)h>))h))h>))h)+h>++h+$h>$$h$)h>))h))h>))h)+h>++h+$h>$$h$(h>(+h+$h>$$h$(h>(+h+ h !h6!!h!-h>-+h+$h>$$h$(h>(+h+$h>$$h$"h>""h" h !h6!!h!-h>-+h+$h>$$h$4h>4+h+$h>$$h$"h>""h"!h>!!h! h>  h )h>)'h'&h>&$h|$ÿ/MTrkKÿJAZ2™#Z*(*#*!**%*&P*(*&*"****(#Z*#* ****(&P&**#**$*#Z*(*#*&**#**(&P*&*$**&*#Z*(*#***"**(&P&****$**(#Z*#*$**#*&P*(&** **"**(#Z*#*$**%**(&P&**!**'**(#Z*#*%** *&P*(&**!**'*#Z*(#**$**%**(&P&****"**(#Z#**%**'*&P*(*&*%**!*#Z*(*#*&****(&P*&*&**!**(#Z*#* **%*&P*(&**$**"**(#Z#**'**#**(&P&** **$*#Z*(*#*$**&*&P*(*&*$****(#Z*#*"**!*&P*(&****'*#Z*(*#*%***&P*(*&*!**$*#Z*(#****&**(&P*&*#** **(#Z#**#**&*&P*(*&*!**!**(#Z#**'** **(&P*&*#**$*#Z*(#**"**%*&P*(*&***&**(#Z*#*&***&P*(&** **"*#Z*(#**&***&P*(&** **'**(#Z#**$**#**(&P*&*$**"*#Z*(#****!**(&P*&*%**'**(#Z*#*"**#*&P*(*&*!**#**(#Z*#*#**!**(&P&**!**!**(#Z#**$**&*&P*(&**#**'**(#Z#****$*&P*(*&*%**%**(#Z*#*%***&P*(*&***%**(#Z#****#**(&P&**"**&*#Z*(#****&**(&P&**'** *#Z*(#****!*&P*(*&* ****(#Z*#*!**"**(#Z*#***"*#Z*(#**"****(&P&****#**(#Z*#*!**#**(&P&**!**&**(#Z#**!** *&P*(&**'**%**(#Z*#*$**%**(#Z*#*%**%*#Z*(#** **!*&P*(*&***&**(#Z*#*&****(&P*&***&*#Z*(#**%**!*&P*(&**#**"**(#Z*#*!** *&P*(*&*"***#Z*(*#*'***&P*(&****%**(#Z*#*$***&P*(&*****#Z*(*#*$**%*&P*(*&*&** **(#Z*#* **$*&P*(*&*%**'**(#Z#**!**%*&P*(&**$**$*#Z*(*#***"*&P*(&****'**(#Z#**#**#**(&P&** ***#Z*(*#*"**"**(&P*&*"****(#Z*#*'****(&P*&*!****(#Z*#*%***&P*(&**#****(#Z#**%****(&P&**&**'*#Z*(*#*#**"*&P*(*&*#**%**(#Z#**"**#*&P*(&**!**#*#Z*(#**'** **(&P*&***&*#Z*(#******(&P&**&**&*#Z*(#****%*&P*(&**#***#Z*(#**'**"**(&P&**#**$*#Z*(#**%****(&P&** ****(#Z*#*%****(&P*&*%**#*#Z*(*#*****(&P&**** *#Z*(#**#***&P*(&****!**(#Z#** **&*&P*(*&*$**'**(#Z*#*"**$**(&P&**!**!**(#Z#**'**"*&P*(&**#***#Z*(*#*%**&**(&P*&*%**'*#Z*(*#*** **(&P&** **'**(#Z*#*"**$**(&P&****$**(#Z#** **&*&P*(&**'**$**(#Z#**#** *&P*(*&*'***#Z*(#****'*&P*(&**'****(#Z#****"*&P*(&**&**%**(#Z#**'***&P*(&**!***#Z*(#**!**"**(#Z#**&**$**(&P*&*&**%**(#Z#**** *#Z*(#**$**'**(#Z*#*#**%**(&P*&***"*#Z*(*#*$**&*#Z*(*#* **#*#Z*(*#* **'**(&P*&* **'**(#Z#**'**'**(#Z*#*'** *&P*(*&*%***#Z*(#**'**%*&P*(*&*"**#*#Z*(*#***'**(&P&**'**%*#Z*(#**&**!**(&P*&*"**!*#Z*(#**"**$**(&P*&***!*#Z*(*#*#***&P*(*&*&**%**(#Z#** **'*&P*(&****%**(#Z*#*%**%**(&P*&*'***¹d™#Z¹]<™*(¹J@H@K@I@[<G@™#** **#**(&P*&*#**%**(#Z#*****&P*(&** ****(#Z#**$**&**(&P*&*"**&*#Z*(*#*!****(&P*&***$**(#Z#**#**&**(&P*&*&** *#Z*(*#* ** *&P*(&**'**%**(#Z#**$****(&P*&***!**(#Z#**"**"**(&P*&***'*#Z*(*#***'**(&P*&***!*#Z*(*#*'**#*&P*(&** ** **(#Z#**'****(#Z*#***!*#Z*(*#*"** *#Z*(#**%**!**(#Z#**'** *#Z*(#**&**$*#Z*(*#***!**(#Z*#*$****(#Z#**#**%*#Z*(#*****#Z*(*#*****(#Z*#***!**(#Z#** ***&P*(&****&*#Z*(*#* **"**(&P*&*&***#Z*(*#*$**"*&P*(&**'**$*#Z*(*#*#**$**(&P*&***#**(#Z#**!** **(&P*&*!**!**(#Z#**!** *&P*(&**$**$**(#Z#**** **(&P*&***&**(#Z#**%**#*&P*(&**$**#**(#Z#**'****(&P*&*!**'*#Z*(*#*$** **(&P*&*$**$**(#Z#**$**#**(&P*&*'**'*#Z*(*#*$***&P*(&**$**%**(#Z#**#**"*&P*(&**"****(#Z#**$**!*&P*(&****'*#Z*(*#*!**!*&P*(&**'** *#Z*(*#*'**!**(&P*&*!**!**(#Z#**%****(&P*&*%**"**(#Z#****$*&P*(&**'**&*#Z*(*#*%**'*&P*(&****#**(#Z#**!***&P*(&**$**%**(#Z#**!**&*&P*(&****!*#Z*(*#*!**!*&P*(&**&**$*#Z*(*#***"*&P*(&**$***#Z*(*#*'**'*&P*(&**%***#Z*(*#*"** *&P*(&**%**#*#Z*(*#*$**#*&P*(&**$***#Z*(*#*#**#*&P*(&****'*#Z*(*#*#**$**(&P*&***!**(#Z#****!**(&P*&*&**'**(#Z#**&****(&P*&***!**(#Z#**!**$**(&P*&***&**(#Z#**&**%**(&P*&*!****(#Z#**"** *#Z*(#**$**"*&P*(*&***!*#Z*(#****'*#Z*(*#*'**"*#Z*(#**!** *&P*(*&*****(#Z*#*'**"*#Z*(*#*** **(&P*&*%***#Z*(*#*&**'**(#Z*#*$***#Z*(*#*&**!**(&P*&*%**$**(#Z#****"**(#Z*#***"**(#Z#**%**#*#Z*(#****"*#Z*(*#*"**$**(#Z*#*&** **(#Z#****"**(#Z*#*'**!**(#Z#**#**&**(#Z*#*&**$**(#Z#**$****(&P*&***!**(#Z#**!****(&P*&***&**(#Z#**#***&P*(&**"**$*#Z*(*#*!**%*&P*(&****#**(#Z#**"**#**(&P*&***%**(#Z#**%**%*&P*(&** **"*#Z*(*#*#***&P*(&**&**'**(#Z*#* **"**(&P*&* ***#Z*(#**$**'**(&P&****"*ÿ/MTrk3°ÿJAZ2ÿTransport chaosÿ/simutrans-124.3/simutrans/music/08-The-journey-home.mid000066400000000000000000000502221474050137200230000ustar00rootroot00000000000000MThd`MTrk\ÿshunter (c) 2006ð~ ÷ÿJAZ2ÿ 2006.10.06ÿQ 'Àÿÿ/MTrk”ÿ,shunter (c) 2006 ÿJAZ2ÿ @@ÿGeneral MIDIÿ(My Song ÿ/MTrk)ÀÿJAZ2°dÿ @ÿGeneral MIDIÿChord`° kH-°Hk<-C-°Ck@-°@k*HC@<@-<-H-C-*@<HC6<-@-H-C-*CH<@6C-<-@-H-*<HC@<-C-H-@-*C@H<<-H-@-C-*@° k@kHkHÀC°Ck<C-G->-;-*CG>;;-G-C->-*CG>;6G-;->-C-*>G;C6G-C-;->-*>GC;>-G-;-C-*>C;GG-;-C->-*°>kGkG>C;°CkÀ° k<-C-H-@-*HC@<<-H-C-@-*CH@<6<-H-@-C-*H@<C6<-@-C-H-*HC<@<-@-C-H-*H@C<H-@-<-C-*À°Ck k@H<C°@kHk;-G->-C-*>C;GC-G->-;-*GC;>6;->-G-C-*>;GC6G->-;-C-*;>GC>-C-G-;-*;C>G;-G-C->-*CG>;°CkÀ° k>kGk<-H-E-@-*<HE@H-E-@-<-*<@HE6E-H-<-@-*<@HE6@-E-H-<-*@<EHE-<-H-@-*E<H@E-@-<-H-*°@kHkH° k@ÀE<°EkC-;-@-G-*G@;C@-;-C-G-*@C;G6C-@-G-;-*@G;C6C-;-G-@-*C@;GG-C-@-;-*C;@GG-;-@-C-*°GkÀ;°CkC@G° k@kE-H-A-<-*<HEAH-<-A-E-*EH<A6E-<-A-H-*HEA<6E-H-<-A-*<AEH<-E-H-A-*E<HA<-E-H-A-*<AEH°EkAk kHkÀ;-G-C->-*>GC;G-;-C->-*>G;C6;-G-C->-*CG>;6G->-C-;-*;C>G;-G-C->-*G>C;;-G-C->-*°CkGC>;° kÀ°Gk>kH-C-@-<-*<H@C<-H-@-C-*<H@C6@-H-<-C-*C<@H6<-@-H-C-*@CH<C-H-@-<-*<C@HH-C-@-<-*À° kCk<°HkH@C°@k>-C-;-G-*>;GCG-C-;->-*;G>C6;-G-C->-*>G;C6G-;-C->-*;GC>;-C->-G-*>GC;>-G-C-;-*G;°CkGk k>kÀC>@-<-C-H-*H@C<H-C-<-@-*@<CH6@-H-<-C-*<HC@6C-H-<-@-*@HC<C-@-<-H-*C<@HC-<-@-H-*HC°Hk@kÀ°Ck k@<;->-C-G-*CG;>;-G->-C-*G>C;6C-G-;->-*C>;G6>-;-G-C-*>GC;;->-G-C-*;G>C>-C-G-;-*° kÀCG;>°>kGkCkH-@-E-<-*<EH@H-@-E-<-*@HE<6E-@-<-H-*@HE<6<-@-E-H-*H<E@<-E-H-@-*HE<@<-H-E-@-*H@E°Ek@k k<À°HkG-@-;-C-*CG@;;-@-G-C-*@G;C6@-;-C-G-*G@C;6;-@-G-C-*C@;G@-;-G-C-*;@CGG-@-;-C-*À° k@kCkGkG;C@E-H-A-<-*H<AE<-A-E-H-*<AHE6<-E-H-A-*HAE<6H-E-A-<-*HAE<<-E-H-A-*<EHAA-E-H-<-*AE<H°Hk kAkÀ°EkG->-;-C-*>;GC>-;-G-C-*G>C;6G->-;-C-*>GC;6C->-;-G-*>C;GG->-;-C-*>CG;;->-C-G-*°>kCkGkÀ° kC>;G@-C-H-<-*C@H<H-<-C-@-*@<HC6H-<-C-@-*<C@H6<-H-@-C-*H<C@C-H-@-<-*<CH@@-H-C-<-*°@kHkÀ°Ck k@CH<>-G-;-C-*C;G>>-G-C-;-*CG;>6G-;-C->-*;>GC6>-C-G-;-*;GC>>-C-;-G-*C;>G;-G->-C-*C>°GkÀ°CkG° k;°>kH-<-@-C-*C@H<C-<-H-@-*H@<C6C-H-<-@-*CH<@6C-<-@-H-*CH<@H-@-<-C-*<CH@@-C-H-<-*°CkÀ°@kCH@<°Hk kG-;-C->-*;C>G;->-G-C-*G;>C6;-G->-C-*GC>;6C-G->-;-*G;>C>-;-G-C-*C;G>;-G->-C-*>GC° kÀ°Ck>k;°Gk@-E-<-H-*E<@HE-H-@-<-*<HE@6@-<-E-H-*<EH@6<-E-H-@-*@HE<@-H-E-<-*<E@H@-<-E-H-*°@k kÀ°EkHkHE<@;-G-C-@-*;G@C;-C-@-G-*G;C@6C-@-G-;-*;GC@6C-@-G-;-*CG@;G-;-@-C-*@;CGC-;-G-@-*G;°Ck@C°@kÀ°Gk kE-H-<-A-*A<EH<-H-E-A-*EAH<6H-E-A-<-*A<EH6A-E-<-H-*<AEHA-H-E-<-*<EHA<-A-H-E-*° kÀHAE<°HkAkEk>-G-C-;-*G;>C;->-C-G-*G>C;6;->-C-G-*CG>;6;-G->-C-*;G>C>-;-C-G-*C;G>G->-C-;-*>C;°>kCkÀG° kGk@-<-H-C-*@HC<H-<-@-C-*<@CH6C-H-<-@-*HC@<6C-@-<-H-*C@H<<-H-C-@-*HC<@H-@-C-<-*HÀ°@k kHkCkC<@G->-;-C-*;>CG>-G-C-;-*C;G>6;-G-C->-*G>;C6;-C-G->-*>GC;;->-G-C-*G;>CG->-;-C-*G;>C°Gk kCk>kÀC-<-H-@-*@<HC<-C-@-H-*C<@H6H-<-@-C-*C<H@6@-C-<-H-*H@C<H-C-@-<-*C<@HC-<-H-@-*°HkH@À°@kCk k<C>-C-G-;-*G>C;;-G->-C-*;CG>6;->-G-C-*G>C;6;-G-C->-*>GC;;->-G-C-*GC;>C-;-G->-*>°Gk;G°Ck kÀC°>k<-H-@-E-*E<@H<-@-E-H-*E<@H6<-H-@-E-*H@<E6@-E-H-<-*@EH<E-@-H-<-*E<H@<-H-E-@-*@<HE°EkÀ°Hk k@kC-@-;-G-*@;CGC-;-G-@-*;@GC6@-;-C-G-*;CG@6;-@-C-G-*C;@G@-;-C-G-*CG@;G-C-;-@-*C°GkCkGÀ;@° k@k<-E-A-H-*HE<A<-H-E-A-*HEA<6H-A-E-<-*<AEH6E-A-<-H-*<EHAE-H-A-<-*AEH<<-H-E-A-*ÀAE<H°AkHkEk k;-G-C->-*G;C>>-G-C-;-*GC;>6>-G-;-C-*;G>C6>-G-C-;-*C>G;C->-;-G-*;>CG>-G-C-;-*;C°>k kCkGkÀ>GH-C-@-<-*C<H@C-<-H-@-*CH@<6C-<-@-H-*CH<@6@-<-H-C-*@<CHC-H-@-<-*<@HCC-<-H-@-*<@HÀC°CkHk k@kC->-;-G-*C;G>>-;-C-G-*CG>;6>-;-C-G-*CG>;6G-;->-C-*C>G;G-C->-;-*;>CG>-G-;-C-*>GÀC°Gk;° kCk>kH-@-<-C-*H<C@C-H-<-@-*@C<H6<-C-H-@-*H@<C6H-<-C-@-*C@<HC-<-H-@-*<HC@@-H-<-C-*H<@°Ck kCÀ°@kHkC-G-;->-*;G>C>-C-;-G-*C;G>6>-G-C-;-*>;GC6C-G->-;-*C>;GG->-C-;-*>CG;>-;-G-C-*°>k>CG;°CkGk kÀE-@-H-<-*<E@HE-<-H-@-*<EH@6@-<-H-E-*<EH@6<-@-E-H-*H<E@H-@-E-<-*E<H@H-E-@-<-*<@HE° kHk@kÀ°Ek;-@-C-G-*@G;C;-@-C-G-*@G;C6G-C-@-;-*;GC@6@-;-C-G-*@CG;;-@-C-G-*@GC;C-;-@-G-*°CkGk@°@k kÀ;CGA-E-H-<-*<AHEH-<-E-A-*EAH<6A-H-E-<-*AHE<6A-<-H-E-*<EHAH-E-A-<-*A<EHA-<-H-E-*°Ak<°HkAÀ°EkEH° kG-C->-;-*G;>C;-G-C->-*>GC;6;-C->-G-*GC;>6;->-C-G-*>;CG;-G-C->-*GC;>G-;->-C-*>°>kÀ° kGkG°Ck;C<-C-H-@-*<@HC<-H-C-@-*@<CH6H-<-@-C-*CH<@6@-C-H-<-*HC@<C-<-@-H-*<H@C<-H-C-@-*HÀ°Hk<° kCk@kC@;-G-C->-*>CG;;->-G-C-*G>;C6>-;-C-G-*C>;G6;-G-C->-*>;GC;-G-C->-*;C>GG-;-C->-*ÀC°CkGk k>k;G><-H-C-@-*CH@<<-H-C-@-*C<@H6H-C-<-@-*H@C<6<-H-C-@-*HC@<C-H-<-@-*<C@H<-H-C-@-*C°HkH@<° k@kÀ°Ck;-G->-C-*;>GCC-G-;->-*C;>G6;-C->-G-*C;G>6>-C-;-G-*;CG>>-G-;-C-*;G>CG-;->-C-*>°CkGk kÀG°>k;CH-@-<-E-*E<H@H-E-<-@-*<EH@6@-<-H-E-*E@H<6H-@-<-E-*E<@H<-E-@-H-*@E<H<-E-@-H-*<°@kHkH@E° kEkÀC-@-;-G-*GC;@;-C-G-@-*GC;@6@-C-G-;-*G;C@6;-@-G-C-*CG;@C-;-G-@-*C;G@C-;-@-G-*@ÀC°CkGk@kG;° kH-A-<-E-*HE<AA-<-E-H-*EA<H6<-E-H-A-*A<EH6<-A-H-E-*<AHEH-<-E-A-*EHA<H-E-A-<-*°AkÀ° kHkEkH<EA>-G-C-;-*>;GC;-C-G->-*GC>;6C-;-G->-*;G>C6C-G-;->-*G;>CC-G->-;-*GC;>G-;-C->-*° kÀ°>kG;>C°GkCkC-<-H-@-*@CH<H-C-<-@-*C@<H6@-H-C-<-*<@HC6C-@-H-<-*<C@HH-@-C-<-*@<HCH-@-<-C-*<C@H°HkÀ° kCk@kG-C->-;-*G;>C;-C-G->-*>GC;6G->-;-C-*>G;C6C->-G-;-*G;C>C-G->-;-*>;CGG-;->-C-*°>kC>;G° kÀ°GkCkC-H-<-@-*<HC@C-H-@-<-*CH@<6<-H-@-C-*CH@<6C-H-<-@-*@C<HH-C-@-<-*@C<H@-C-<-H-*ÀC°HkCk k@H<°@kG-C-;->-*C>G;C-;-G->-*;GC>6>-;-C-G-*>;CG6C-G->-;-*G;C>C->-G-;-*C;G>G-C->-;-*À°CkG°Gk k>k>;C<-E-H-@-*EH@<E-@-<-H-*E<H@6<-H-E-@-*HE@<6<-H-E-@-*<E@HE-H-<-@-*HE<@<-H-@-E-*À° k<°EkE@H°Hk@kC-@-;-G-*G;C@C-;-G-@-*G;C@6C-@-;-G-*GC;@6@-G-;-C-*CG;@C-@-G-;-*C;@GC-;-G-@-*°GkG° k@;CÀ°@kCkA-H-E-<-*AH<EH-A-E-<-*<AEH6H-A-E-<-*EA<H6H-A-<-E-*EH<AE-A-<-H-*AE<HA-H-<-E-*° k<°HkEkAkAEHÀC-;-G->-*G;>CG-;-C->-*;>CG6G-;->-C-*G;C>6>-G-C-;-*C>G;G->-C-;-*C>;GC-G-;->-*°Gk kÀ°Ck>°>kGC;C-@-H-<-*H<@CH-<-C-@-*@HC<6C-<-H-@-*<@HC6H-<-@-C-*CH<@<-@-C-H-*HC@<<-C-H-@-*H@°HkÀ°@kCk k<CG-C-;->-*GC>;;-G->-C-*GC>;6C-;-G->-*C>G;6G-C-;->-*C>G;>-G-;-C-*G>;CC-G-;->-*CÀ°Gk>k kG°Ck;><-H-@-C-*@C<H@-C-H-<-*@CH<6<-@-C-H-*<C@H6<-H-@-C-*CH@<C-<-H-@-*H<C@@-<-H-C-*À°Hk kH°@kCk<C@;->-G-C-*C>G;;-C-G->-*>;CG6G-C->-;-*;C>G6G->-;-C-*>CG;C-G->-;-*;C>GC->-;-G-*C;>G°GkCk>kÀ° kH-<-E-@-*<E@HE-<-@-H-*<@EH6E-<-@-H-*HE@<6<-H-@-E-*@E<HH-E-<-@-*<EH@E-H-<-@-*°Ek@kÀE° kH@°Hk<;-@-G-C-*;@GC@-;-G-C-*G@;C6@-;-C-G-*G@;C6;-C-@-G-*GC;@G-C-;-@-*GC;@;-@-G-C-*°GkCkÀ° k@kG@;CH-A-<-E-*HE<A<-E-H-A-*<EAH6<-E-H-A-*EHA<6E-H-<-A-*H<AEA-E-H-<-*<EHAA&<&E&H&*E°HkAH<° kEkÀ°AkC>G;*G;>C;CG>*>G;C6;GC>*CG>;6;C>G*>CG;;>GC*GC>;C>;G*;GC>ÿ/MTrkÇÄ0ÿJAZ2ÿGeneral MIDIÿLead´uÿ @`´ @”HTH JTJ L(Ä0´ @”LGTG HTH J(Ä0´ @”JH*HL*LJ*JL*LM*ML*LJTJ´ @Ä0 ”M*MO*OM*ML*LJ(J´ @Ä0”LTL E|´ @”EÄ0$”Lz*LJz*JLz|L´ @Ä0$”H~*HE~~EH~*HE~~E´ @Ä0‚b´ @Ä00”H*HH*HG*GHTH CTC C*Ä0´ @”CE*EC|C$C*´ @Ä0”CH*HG*GH*HG*GH*HLTL L*´ @”LÄ0”Q*QO*OO*OO(OO*Ä0”O´ @”Q~QTTSSQ(´ @”QÄ0”Q~QO*OL(Ä0´ @”LQ*QQ*QQ|QÄ0´ @ƒÄ´ @$”OTO TTT S*ST*TS*SQ*´ @Ä”QO(OJ(Ä”J´ @”LTL OTO Q*QO~OÄ´ @”L~LL*LJ(´ @Ä”JQ~QTTSSQ(Ä´ @”QQz~QOz*OLz(´ @Ä”LM~ML~LJ~JH~HM~(ML~*LM~*Ä´ @”MO*OM*MO*OM*MS*SQ*QS*SQ*Ä”Q´ @”HTH JTJ L(LÄ´ @”G|TG H|TH J|(´ @”JÄ”L{*LC{TC C{*CC{TC E{*EG{*´ @Ä”GHy*HGyTG Gy*GGy(´ @”GÄ”L}*LL}*LM}*ML}*LM}TM L}TLÄ´ @ ”O*OO*OL*LO*OL(´ @Ä”LMMLLJJHHM(ML*LM*MÄ´ @”O*OM*MO*OM*MS*SQ*QS*SQ*Ä”Q´ @”H(HLTL HT´ @Ä”H J~JH*HG(Ä´ @”GHTH CTC ETE @T@Ä´ @ ”C(C>(´ @”>Ä”Q~QTTSSQ(Q´ @Ä”Qz~QOz*OLz(LÄ´ @”M~ML~LJ~JH~HM~(ML~*LM~*´ @”MÄ”O*OM*MO*OM*MS*SQ*QS*SQ*Ä”Q´ @”HTH JTJ L(LÄ´ @”G|TG H|TH J|(J´ @Ä”L*LCTC C*CCTC E*EG*´ @”GÄ”H*HGTG G*GG(GÄ´ @”L*LL*LM*ML*LMTM LTL´ @Ä ”O*OO*OL*LO*OL(´ @”LÄ”MMLLJJHHM(ML*LM*Ä´ @”MO*OM*MO*OM*MS*SQ*QS*SQ*Ä0´ @”QHTH JTJ L(LÄ0´ @”GTG HTH J(´ @”JÄ0”H*HL*LJ*JL*LM*ML*LJTÄ0”J´ @ ”M*MO*OM*ML*LJ(´ @Ä0”JLTL E|EÄ0´ @$”Lz*LJz*JLz|LÄ0´ @$”H~*HE~~EH~*HE~~E´ @Ä0‚b´ @Ä00”H*HH*HG*GHTH CTC C*´ @Ä0”CE*EC|C$C*Ä0”C´ @”H*HG*GH*HG*GH*HLTL L*´ @”LÄ0”Q*QO*OO*OO(OO*Ä0´ @”OQ~QTTSSQ(Ä0´ @”QQp~QOX*OLP(LÄ0´ @ƒÄ0´ @ÿ/MTrkTÅ"ÿJAZ2µRÿ @ÿGeneral MIDIÿBase`•$@µ *•$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*Å"•2µ •$@*$$@*$+@*++@*+0@*00@*0+@*++@*Å"µ •++@*++@*+2@*22@*27@*77@*72@*22@*2µ Å"•-@*--@*-4@*44@*49@*99@*94@*44@*Å"•4µ •4@*44@*4;@*;;@*;@@*@@@*@;@*;;@*;µ Å"•)@*))@*)0@*00@*05@*55@*50@*00@*µ Å"•0+@*++@*+2@*22@*27@*77@*72@*22@*2µ Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*Å"µ •++@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •-@*--@*-4@*44@*49@*99@*94@*44@*4µ Å"•4@*44@*4;@*;;@*;@@*@@@*@;@*;;@*µ •;Å"•)@*))@*)0@*00@*05@*55@*50@*00@*µ •0Å"•+@*++@*+2@*22@*27@*77@*72@*22@*µ Å"•2$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*µ •2Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*2µ Å"•-@*--@*-4@*44@*49@*99@*94@*44@*µ Å"•44@*44@*4;@*;;@*;@@*@@@*@;@*;;@*µ •;Å"•)@*))@*)0@*00@*05@*55@*50@*00@*µ Å"•0+@*++@*+2@*22@*27@*77@*72@*22@*µ Å"•2$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*Å"µ •2$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*Å"•2µ •-@*--@*-4@*44@*49@*99@*94@*44@*µ •4Å"•4@*44@*4;@*;;@*;@@*@@@*@;@*;;@*;µ Å"•)@*))@*)0@*00@*05@*55@*50@*00@*Å"µ •0+@*++@*+2@*22@*27@*77@*72@*22@*µ •2Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*+µ Å"•+@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ •+Å"•+@*++@*+2@*22@*27@*77@*72@*22@*2µ Å"•-@*--@*-4@*44@*49@*99@*94@*44@*µ •4Å"•4@*44@*4;@*;;@*;@@*@@@*@;@*;;@*µ •;Å"•)@*))@*)0@*00@*05@*55@*50@*00@*0Å"µ •+@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •$@*$$@*$+@*++@*+0@*00@*0+@*++@*+µ Å"•+@*++@*+2@*22@*27@*77@*72@*22@*Å"µ •2$@*$$@*$+@*++@*+0@*00@*0+@*++@*Å"µ •++@*++@*+2@*22@*27@*77@*72@*22@*Å"µ •2-@*--@*-4@*44@*49@*99@*94@*44@*4Å"µ •4@*44@*4;@*;;@*;@@*@@@*@;@*;;@*;µ Å"•)@*))@*)0@*00@*05@*55@*50@*00@*Å"µ •0+@*++@*+2@*22@*27@*77@*72@*22@*µ •2Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*+µ Å"•+@*++@*+2@*22@*27@*77@*72@*22@*2µ Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •-@*--@*-4@*44@*49@*99@*94@*44@*Å"µ •44@*44@*4;@*;;@*;@@*@@@*@;@*;;@*µ •;Å"•)@*))@*)0@*00@*05@*55@*50@*00@*Å"µ •0+@*++@*+2@*22@*27@*77@*72@*22@*µ •2Å"•$@*$$@*$+@*++@*+0@*00@*0+@*++@*µ Å"•++@*++@*+2@*22@*27@*77@*72@*22@*Å"µ •2$@*$$@*$+@*++@*+0@*00@*0+@*++@*+µ Å"•+@*++@*+2@*22@*27@*77@*72@*22@*2Å"µ •-@*--@*-4@*44@*49@*99@*94@*44@*Å"µ •44@*44@*4;@*;;@*;@@*@@@*@;@*;;@*;µ Å"•)@*))@*)0@*00@*05@*55@*50@*009*Å"µ •0+1*++)*+2!*22*27*77 *72*22*2ÿ/MTrkùÉÿJAZ2¹ FÿDrumsÿ @@ÿGeneral MIDI¹x`™#0.0`&0#..00#0&.0.0#0#0.0.0&0#`.&#0.0`.&0.0#0&.#00#.00#0.0&0.0#`.0#0&.`#&0.0.0.#0&0#.00.#00.0#&0`&.0#0.`&0#.0.0&#0.0#.00.#00.0#&0`&#0..0`..0#&00&.#00#.00#0.0.0#&0`.#0&.0`#&0..00&.#00#.00#0.0.0#&0`.&.0#0`&0#.0.0#0&.0#.00.#00.0#&0`#T&.*T`*#*T0*#T0#T*T#&T#*&T&&&T&&T*T&&T&T&*.T&&T0..0&#0`#.0&0.0.&#00#.00#0.0.0&0#`#0.0.&`.0&0.#0#0.&0#.00.#00.0#&0`&#0..0`..0#&00.#0&0#.00.#00&0#.0`..0&#0`#.0.&00.#0&0#.00.#00.0#&0`&#0..0`.&0#.00#0&.0#.00.#00.0#&0`&.0.#0`.&0#.00#0.&0#.00.#00&0#.0`.#0&.0`#&0..00.&#00#.00#0.0&0#.0`..0&#0`..0#&00#0&.0#.00.#00&0#.0`.#0&.0`.&0#.00#0.&0#.00#0.0.0#&0`&.0.#0`..0#&00.&#00#.00.#00.0#&0`.#0&.0`#&0..00&.#00#.00.#00.0#&0`&.0.#0`..0#&00#0.&0#.00#0.0.0#&0`.#0&.0`.&0#.00#0.&0#.00.#00.0#&0`..0&#0`&0.0#.0&.#00#.00#0.0&0.0#`&#0.0.`&0#.0.0&#0.0#.00#0.0&0#.0`&.0.#0`#&0..00#0&.0#.00#0.0&0#.0`#0.&.0`..0#&00&.#00#.00#0.0&0#.0`&#0..0`#&0..00.#0&0#.00#0.0.0#&0`.#0&.0`..0#&00&.#00#.00#0.0&0#.0`..0&#0`#&0..00#0&.0#.00#0.0&0#.0`.#0&.0`.&0#.00.&#00#.00#0.0&0#.0`&#0..0`..0#&00.&#00#.00#0.0.0#&0`.#0&.0`#&0..00.&#00#.00#0.0&0#.0`.#0&.0`#&0..00#0.&0#.00#0.0.0#&0`..0&#0`.&0#.00.&#00#.00#0.0&0#.0`..0&#0`.&0#.00#0.&0#.00#0.0.0#&0`.#0&.0`#&0..00#0.&0#.00#0.0&0#.0`.#0&.0`#.0.&00#0&.0#.00#0.0&0#.0`&#0..0`#.0.&00#0&.0#.00#0.0&0#.0`.#0&.0`#.0.&00#0&.0#.00#0.0.0#&0`..0&#0`..0#&00#0&.0#.00#0.0&0#.0`..0&#0`..0#&00#0&.0#.00#0.0.0#&0`.#0&.0`#&0..00#0.&0#.00#0.0.0#&0`&#0..0`#.0.&00.#0&0#.00.#00.0#&0`..0&#0`.&0#.00#0.&0#.00#0.0.0#&0`..0&#0`..0#&00.#0&0#.00#0.0&0#.0`&.0.#0`..0#&00.#0&0#.00.#00.0#&0`..0&#0`#&0..00&#0.0#.00.#00&0#.0`&#0..0`#.0.&00.#0&0#.00.#00&0#.0`&.0.#0`#.0.&00.#0&0#.00.#00.0#&0`..0&#0`..0#&00.#0&0#.00.#00.0#&0`..0&#0`#.0.&00.#0&0#.00.#00.0#&0`..0&#0`.&0#.00&#0.0#.00.#00&0#.0`&#0..0`.&0#.00&#0.0#.00.#00&0#.0`&#0..0`#.0.&00.#0&0#.00.#00&0#.0`&#0..0`..0#&00.#0&0#.00.#00.0#&0`.#0&.0`#.0.&00.#0&0#.00.#00.0#&0`#T&*T.`#**T0#T*0&T#T#*T*#&T&&&T&T&&T&*T*&T&.T&&T0&#0..0`#&0..00&#0.0#.00#0.0&0#.0`&#0..0`#.0.&00.#0&0#.00#0.0.0#&0`.#0&.0`#.0.&00.#0&0#.00#0.0.0#&0`..0&#0`..0#&00.#0&0#.00#0.0.0#&0`.#0&.0`#.0.&00.#0&0#.00#0.0.0#&0`.#0&.0`#.0.&00&#0.0.0#0.#00.0&0#`&./T//T)T/0)T))T))T)))T)+T+T++0T0T00/T/Q//-M-I-3E-#E2E,E$E3$,2#2A$=2=&=(=#=20(,52#5#;5$$5&350595#;39,$0010-00-%,%3%0-!,3---#$0($)1,&9#;3$#-3))#;$&,91($ # ) )0$#)ÿ/MTrk4°ÿJAZ2ÿThe journey homeÿ/simutrans-124.3/simutrans/music/09-Simupolitan-Swing.mid000066400000000000000000000245501474050137200232400ustar00rootroot00000000000000MThdÀMTrkwÿ By ÿCopyright © 2006 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQȃ†ÿQ¡ ÿ/MTrk Vÿ!ÿStaffÀ8°° @LnLOn.OLnLHn.HJnJMn.MJnJGn.GHn…PH0n.>@n@An.ACnCEn.EGnGHn†H0n.>@n@An.ACnCEn‰E0EnECn.CAnACnŒC0GnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0LnLLn.LLnLLn.LLnLLn.LLnLLn.LLnLEn.EGnGHn.HJnJHn.HGnGHn†H0n.>@n@An.ACnCEn.EGnGHn†H0n.>@n@An.ACnCEn‰E0EnECn.CAnACnŒC0GnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0LnLLn.LLnLLn.LLnLLn.LLnLLn.LLnLEn.EGnGHn.HJnJHn.HGnGHnPH‚pn>@n.@An A EnEEnPE EnEHnPH HnHEnPE AnACnPC HnHCn.CHnHCn.CHnHLnPL LnLJn.JLnLJn.JGnGEn>EAn.AEnEAn.AMMn>MMn>M2LnLJn.JLnLJn.JGnGCn.CGnGJn.JLnLOn.OLnLHn.HJnJMn.MJnJGn.GHn…PH0n.>@n@An.ACnCEn.EGnGHn†H0n.>@n@An.ACnCEn‰E0EnECn.CAnACnŒC0GnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0LnLLn.LLnLLn.LLnLLn.LLnLLn.LLnLEn.EGnGHn.HJnJHn.HGnGHn†H0n.>@n@An.ACnCEn.EGnGHn†H0n.>@n@An.ACnCEn‰E0EnECn.CAnACnŒC0GnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0LnLLn.LLnLLn.LLnLLn.LLnLLn.LLnLEn.EGnGHn.HJnJHn.HGnGHn„@HpGnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0LnLLn.LLnLLn.LLnLLn.LLnLLn.LLnLJn.JHnHEn.ECnCEn.EGnGHn.HGnGJn.JGnGCnƒC0EnEHn.HEnEAnƒA0Cn‚PC0Hn‚PH0Ln‚PL0OnˆPOÿ/MTrk )ÿ!ÿStaff-1Á8±± @‡@‘n‘Cn‘Gn‚P‘>‘C‘G0‘;n‘>n‘Cn‚P‘;‘>‘Cp‘n‘Cn‘Gn‚P‘>‘C‘G0‘;n‘>n‘Cn‚P‘;‘>‘C0‘@n‘Cn‘Hn„‘@‘C‘Hp‘n‘Cn‘Gn‚P‘>‘C‘G0‘;n‘>n‘Cn‚P‘;‘>‘Cp‘n‘Cn‘Gn‚P‘>‘C‘G0‘;n‘>n‘Cn‚P‘;‘>‘C0‘@n‘Cn‘Hn„‘@‘C‘H0‘@n‘Cn‘Hn‘@‘C‘H‘Cn‘Gn‘JnP‘C‘G‘Jƒ ‘Cn‘Gn‘In‘C‘G‘I‘An‘En‘HnP‘A‘E‘Hƒ ‘An‘En‘Hn ‘A‘E‘H ‘™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3`™3n ™3`™3n ™3`™3n ™3ÿ/simutrans-124.3/simutrans/music/10-Easy-driving.mid000066400000000000000000001402051474050137200221740ustar00rootroot00000000000000MThd ÀMTrkBÿCopyright (C) 2006 shunterð~ ÷ÿJAZ2ÿ/MTrk ïÀÿJAZ2°ÿ$ÿRight°ÿGeneral MIDI°][i ?ÿ @H°]°LXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒJ@JX@J JX@J LXL@GXƒ@GLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒ@J JX@J JXJ@OXO@LXƒ@LQX@Q QXQ@QX Q OXO@JX`ÿDm‚JJX@J LX@L MX@M QX@Q ÿCMOX‚OOX@O OX@O LX@L HX„`H‚ÿBdimMXM@MXM@MXM@JX@J GX`ÿBdim‚GGX@G HX@H JX@J MX M LXƒ LˆLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒJ@JX@J JX@J LXL@GXƒ@GLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒ@J JX@J JXJ@OXO@LXƒ@LQX@Q QXQ@QX Q OXO@JX`ÿDm‚JJX@J LX@L MX@M QX@Q ÿCMOX‚OOX@O OX@O LX@L HX„`H‚ÿBdimMXM@MXM@MX@M JXJ@GX`ÿBdim‚GGX@G HX@H JX@J MX@M LX†L†ÿAm‚ @X@@ EX@E GX@G HX@H JX@J LX„@L`HX@H MX‚MMX@M JXJ@HX@H JXƒJ@CXC@LX„L‚LXƒL@HXH@MX‚MMX@M JXJ@HX@H OXƒO@LXL@QX„Q‚QXÿAm‚QLX@L HXH@EX@E MX‚MMXTM,JXTJ,HXTH,ÿGMGX‚GGX@G JXJ@CX@C LX„L‚ÿFmaj7QX@Q LXL@HX H EX@E MXƒ@MMX@M JXJ@HX`GX H`GGX@G JXJ@LX@L QX†@Q£@LXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒJ@JX@J JX@J LXL@GXƒ@GLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒ@J JX@J JXJ@OXO@LXƒ@LQX@Q QXQ@QX Q OXO@JX`ÿDm‚JJX@J LX@L MX@M QX@Q ÿCMOX‚OOX@O OX@O LX@L HX„`H‚ÿBdimMXM@MXM@MXM@JX@J GX`ÿBdim‚GGX@G HX@H JX@J MX M LXƒ LˆLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒJ@JX@J JX@J LXL@GXƒ@GLXL@LXL@LX@L JXJ@LX`ÿAm@L`@X@@ EX@E GX@G HX@H LX@L JXƒ@J JX@J JXJ@OXO@LXƒ@LQX@Q QXQ@QX Q OXO@JX`ÿDm‚JJX@J LX@L MX@M QX@Q OXÿCM‚OOX@O OX@O LX@L HX„`H‚MXÿBdimM@MXM@MX@M JXJ@GX`ÿBdim‚GGX@G HX@H JX@J MX@M LX†ÿAm`L@@X@@ EX@E GX@G HX@H JX@J LX„@L`HX@H MX‚MMX@M JXJ@HX@H JXƒJ@CXC@LX„L‚LXƒL@HXH@MX‚MMX@M JXJ@HX@H OXƒO@LXL@QX„Q‚ÿAmQX‚QLX@L HXH@EX@E MX‚MMXTM,JXTJ,HXTH,GXÿGM‚GGX@G JXJ@CX@C LX„L‚QXÿFmaj7@Q LXL@HX H EX@E MXƒ@MMX@M JXJ@HX`GX H`GGX@G JXJ@LX@L QX…Qÿ/MTrk8‰±ÁÿJAZ2±@ÿGeneral MIDI±HKÿY±}J<]2ÿY±C[2 "ÿLeft±ÿ @ƒ± "]2@J<HKÁ±C[2•@‘)'9%7(<'`±@‘)0'±@‘7<9`±@@‘7%9'<)0P79±@‘07<±@P‘0±@@[2CJ< "]2HKÁƒ‘>37(;1±@‘+"^207>; +/2±@‘>6±@‘;6<±@‘>;!7.±@.@‘71;9>=±@>@‘;>!24±@@‘2A±@‘>D;AN±@‘>;±@‘7>`C9@30$O@C77&^C9@0OC@<<`@7CB<07C@76^±@‘7±@‘CB@7`@‘7±@‘>,@'9%-,`±@‘9->±@‘4(@P4±@‘>'±@‘@,9#`±@‘@9>43±@0@‘40±@‘<%9&@%P9<±@‘4-±@‘@ ±@‘4@±@‘@,97;67-+'±@^‘21>;7O2>4;4=;>!2(/21;2>7C0:±@‘>;C!2.±@‘2A;6C/>8?C;>2.+O>.±@‘7&+ ±@‘;-2_;>72/`>>;>>>;76070>>;:20;> 26`;C>F`;>±@@‘7G02+±@‘7;$J&±@‘@,C'`;@±@@‘7+CJP7±@‘@-±@‘C%J+`±@‘@±@‘C73J07±@0‘H/±@‘@0C0P@7;HC±@‘7@H2@0C6±@0‘HHJ.7;JEH/@7CJ±@"‘C7<)±@‘@6H2;H71C@ <7±@ ‘H9±@‘C3@3±@‘7±@‘C7><7+;7>C;>2(=2!C9;/>7?C>;26?2A3;0>9>±@‘A;>2.±@‘7EA7*>7!A;72>0;±@@‘0(@(>"C#`0C>±@@‘7$@P7±@@‘> C)@$`C>@±@@‘7/0±@‘70±@‘@"<"C"P<@±@‘7(C±@ @‘7@@±@‘C)<`±@‘@<±@‘C7*`±@@‘)'<'77(9%`±@‘)<970'±@`‘9'7%<)0±@@P‘707±@@‘<9P±@‘09&<(5'±@@‘9±@‘<5 0.±@‘<1<±@‘0<A.5(±@ ‘5<.09+0-A < 09±@‘;1+"±@‘7(>3^20;>7 +/±@‘2>6±@‘;6<±@‘;>!±@‘7..±@‘7159±@‘9=>±@‘95!94±@@‘9A5A±@‘9DN±@‘952>±@`‘7(;1+">3^20;>72 +/2±@‘>6±@‘;6<±@‘>;!7.±@.@‘71±@‘>=;9>±@‘>;!24±@@‘2A>D;A±@N@‘;>7>±@`‘79437$$O477&]77940O470<`CB@70@C@76^±@‘7CB@7±@`‘±@‘0C7±@‘;77+><>C;>2(=2!C9;/>7?C>;26?2>39950>>±@‘95±@‘9.7A9>7*97!>57 90±@‘5;74-86±@‘('^;148; (/;±@‘;4±@‘84<±@‘;8!4+±@.@‘4182±@‘;7>±@‘;8!;.±@@‘;A;8±@‘86N±@‘;841±@`‘((88;=O;8;(];;880/4 ;849^±HK@C[2]2Á± "J<ƒ‘4-('86±@‘;7^;1±@@‘;84 (/;±@‘;4±@‘84<±@‘;8!±@‘4+.±@‘41;7±@‘82>±@‘8;!;.±@@‘;A86;8±@N@‘;841±@`‘((;=98O9;;(];;890/4 ;949`81;94@;8;.^±@‘;;68.±@`‘48/;±@‘84(+,±@‘9%;,>'(4_>+±@‘;9±@‘2(P2±@‘;'9#±@‘>,`23±@@‘;9>02±@0‘;%±@‘7&>%P;7>±@@‘2- 2±@@‘;!7>,±@`‘2.>7;±@@`@‘;(9+++±@‘>+2`±@@‘>;9+2+`9(>-±@‘;+2±@P‘9±@@‘;>2:P2±@‘;)±@‘>,7+@;>±@‘7 ±@‘21>6<±@‘2>±@‘C27+ 7>2021;/C > 2;±@‘<-C70'±@‘@6^71<C@O7C4@4=@C!7(/71C7@2H0:±@‘CH@!7.±@‘7AC8@6H/?H@C7.0O±@‘7C=@80(±@O‘C@7(^@0C8/7 @C76`C9@1HA70@HC7.^HA0C60@.±@‘7HC0@7);6±@‘>7C2;C21>; 72±@ ‘C9±@‘>3;3<±@‘C;>!2(±@.@‘2-C7±@‘>6;1/C±@‘>;!±@‘2-±@‘2A>7;4±@‘A7=A±@‘>;±@‘2.>±@‘2±@‘G7C<<+@7>GC@7(=7!@/G9C7?G@C76?7H3C9@0>H±@‘@C7.±@‘<EH7*C7!H@77C0@±@‘96<7)'±@‘5-^01<95 )/0±@@‘<494<±@‘<9!5+±@.@‘51±@‘<792>±@‘9<!±@‘0.±@‘0A96<8±@N@‘<9±@‘51^7&+ ;->.`2/7;>`>>;>/5>;760705:9>2±@0‘95 96±@`‘9F5C9`592G@+2±@‘>.±@‘7&+ ;-`2/>;7`>>;>>>;76070>>;:20;> 26`>F;C`>±@‘;±@‘7G02+7±@‘J&C'@,±@‘;$`±@‘;J±@‘@7+CP±@‘7C%@-J+±@`‘73±@@‘@CJ0±@‘70H/@0C0±@P‘@7;H7C±@@‘H2C6@0±@0‘HHJ.7;JEH/@C±@‘7J"5)<796±@‘A2;A019< 5±@‘0 A9±@‘<393±@‘0C7±@‘7+;7><>C;>2(=2!>7C9;/?C>;26?2A3>9;0>A±@‘>;±@‘2.7EA7*>7!A;72>0;±@‘@/C.<906G<±@_‘CG@7/?7!C+G6@(O@CG7@,>±@‘@HC±@‘7>7AHKCH@?_@CH<7M?7±@‘0 ±@‘5/0"A"E H#M,‚`±HK@[2C]2Á± "J<ƒ‘ME5A†0H‹±@‘7&+ >.;-`;>7±@@‘2/`>>;>>>;76070;:>>20>; 26`;C>F`7G>;02+7±@‘@,;$±@‘J&C'`JC;@7+±@@P@‘7C%@-J+±@`@@‘@JC730±@‘70H/±@‘C0@0P@7;HC±@‘7@@0H2C6±@0‘HHJ.JE7;H/@±@‘7JC"C7@6±@‘<)H2;H71C@ <7±@ ‘H9±@‘C3@3<±@‘H@C!±@‘7(.±@‘7-±@‘H7C6@1/H±@‘C@!7-±@@‘7AC7@4±@‘H7=H±@‘C@±@‘7.>±@‘7A7±@‘<<975+>A<90(=0!<79/A9?A<906?0A3>9<0>A±@‘<>2.±@‘5EA7*>7!A<72>0±@‘<0'±@‘C7<-@6^71C<@ 0/±@‘7±@‘C4@4<±@‘@C!±@‘<+.±@‘<1@2C7±@>@‘C@!7.±@@‘7A@6±@‘C8N±@‘C@±@‘<1`<=98)(<O<90(^<890O9<59`<991500<90.^±@‘09.<6±@`‘58/<±@‘)599,±@‘),7%<'`±@‘0(9)7±@‘<P±@‘09'<,±@‘7#`±@‘03±@‘<9700±@0@‘<%9%5&P950-±@‘<±@ @‘0@<,9!±@‘5`95<0.±@@`‘0)+9(7+<+±@@`‘)<7±@@‘0+9`9+7(0<-±@@P‘79<±@@‘0:P0±@‘<,5+±@‘9)@5<±@‘9 ±@‘01<6<0±@‘<5+±@‘A2 5<209/A01 < 09±@‘+'±@‘7-;6>7^21>7;O2>4;4=>;!2(/21>7;2A0:±@‘A;>!±@‘2.2AA/>8;6?A;>2.+O±@‘2±@‘@80(C=OC@7(^@0C8/7 C@76`@1C9HA70@HC7.^HA0C60@.±@‘7HC0@96<7±@‘5)A2;A01<9 50±@ ‘A9±@‘<393@‘0A7±@‘<<975+>A<90(=0!<79/A9?A9<06?0A390<9>A±@‘<90.±@‘5EA7*<7!A970<0±@‘9>77-±@‘+';6^217;> +/±@‘2±@‘>4;4<±@‘;>!±@‘7+.±@‘71;2±@‘>7>±@‘>;!±@‘2.±@‘2A±@‘>8;6N±@‘>;71±@`‘@=-(<8O<@4(^<0@8/7 @<99`<1@9904@<4.^±@‘4@6<.±@`‘98/@±@‘-<9-,<%@'±@`@@‘4(-<@P4±@‘@,±@‘<#`±@‘43<@±@0‘4±@0‘<%±@‘@%9&P9<@±@@‘4- 4±@@‘@,$±@‘C%±@‘@*4`7%±@@‘>0C@P±@‘7@&>!±@‘C+`±@‘72@±@‘>C07±@0‘<&±@‘C&@&P@<C7-±@@ ‘7±@@‘@"C-±@‘<`±@‘7/±@‘<C@`7/9,7).±@‘<^297;> +/2±@@‘>?;?<±@‘>;!75±@.@‘71;A±@‘>F>±@‘>;!±@‘2<±@‘2A±@‘>N;JN±@‘;>±@‘7F`;;707+)><^29>;7 +/±@‘2±@‘>?;?<±@‘;>!±@‘75.±@‘7/±HK]2C@ "Á±J<[2ƒ‘@9±@‘C?0(OC@7*^@5C?OC@@‘7±@‘C7;77+><>C>;2(=2!;/>7C9?C>;26?2C3>9;0>±@‘C>;±@‘2.7EC7*>7!C;72>0;±@‘>7±@‘7-;6+'^21>;7 +/2±@‘>4±@‘;4<±@‘>;!±@‘7+.±@‘71±@‘>7;2>±@‘;>!±@‘2.±@‘2A;6>8±@N@‘>;71±@`‘0(@8C=OC@77(^C8@0O@C<9`C9@1<07@C7.^±@‘7C6±@‘@.`<8/C±@‘@0<>%0,±@‘C'@,`0>C±@‘7(@±@P‘7±@‘>#@'±@‘C,`>C73±@@‘@07±@0‘C%@%<&±@P‘<@±@‘C7-±@ ‘7±@@@‘@!C,<`<@7.±@‘C±@`‘++;(>+±@@‘9+7`2+9+;>±@@`‘;+2>-9(±@@P‘9>;±@‘2:±@P@‘2>,7+±@‘;)@;>7±@ ‘21±@‘>6<±@‘2>±@‘C27+ 7>20;/21C > 2;±@‘0-±@‘77$'46^71704O77444=74!7(/71@2C7H0:±@‘@HC!±@‘7.7A@6C8H/?H@C7.$O±@‘7)(98<=±@O‘9<0(^90<8/0 9<06`<991AA00<A90.^AA0<609.±@‘0A<)9+ 7&±@‘;->.`7>2/;`>>;>>>;760709>5:2095 96`5C9±@@‘9F`952G@+2±@‘>.±@‘;-+ 7&`;7>2/`>>;>>>;76070>>;:20>; 26`>F;C`;>±@‘7G±@0‘2+±@‘7@,C';$J&±@`@@‘;CJ@7+P7±@@‘J+@-C%`±@‘C73±@‘J@0±@‘70C0±@‘@0H/P@7;H±@‘7C@C6H2@0±@0‘HHJ.JE7;H/@JC7±@"‘5)<796±@‘A2;A019< 50±@ @‘A9<393@‘0±@‘C7><7+;7>C;>2(=2!C9>7;/?C>;26?2>39950>>±@‘59±@‘9.7A9>7*97!>57 905±@‘4-±@‘;786('^;18;4 (/±@‘;±@‘;484<±@‘;8!4+±@.@‘41±@‘82;7>±@‘8;!±@‘;.±@‘;A±@‘;886N±@‘;8±@‘41`((;=88O8;;(];80;8/4 ;849^± "HK[2]2@J<CÁƒ‘86±@‘4-;7('^±@‘;1±@‘84; (/;±@@‘;484<±@‘;8!±@‘4+.±@‘41±@‘82;7>±@‘;8!;.±@@‘;A;8±@‘86N±@‘8;41±@`‘98((;=O9;;(];;890/4 ;949`;9814@;8;.^±@‘;;6±@‘8.`48/;±@‘(48+,9%>'±@‘;,4(_>±@‘2(+±@‘9;P±@‘2>,9#;'±@`‘23±@@‘;9>02±@0@‘>%7&;%P7;2-±@@‘> 2±@@‘7±@‘>,;!`±@‘7>2.;±@`‘++>+;(9+±@@‘2`;+>±@@‘2+9`;+±@‘9(±@‘2>-P9±@‘;>2:±@P‘2±@‘;)±@‘7+>,@;>±@‘7 21±@‘>6<±@‘2>C27+±@ ‘7>20C21;/ > 2±@‘;<-C70'@6±@^‘71@C<O7C4@4=@C!7(/71C7@2H0:±@‘@HC!7.±@‘7A@6H/C8?H@C7.0O±@‘7±@‘C=0(@8OC@7(^@0C8/7 @C76`@1C9HA70CH@7.^HA0C60@.±@‘7HC0@±@‘>77);6C2;C21>; 72±@ @‘C9>3;3!±@‘2(.±@‘2-C7±@‘;1>6/C±@‘>;!2-±@@‘2A±@‘>7;4A7=A±@‘;>±@‘2.>±@‘2±@‘C#0(>"@(`±@‘7$±@‘C>0@P±@‘7C)@$> ±@`@@‘7/@C>0±@‘70<"C"@"±@P‘@<±@‘7(C±@ @‘7@±@‘C)<@`7*<±@@‘@C`<')'9%±@@‘77(`±@@‘0'<9)7`09'±@‘7%<)±@P‘7±@‘07±@‘9<P0±@‘<(±@‘5'9&@±@‘95< ±@‘0.<1<±@‘0<5(±@‘A. 5<.00-A9+ < 0±@‘9±@‘>3+"7(;1^20>;7 +/2±@@‘>6;6<±@‘;>!7.±@.@‘71±@‘9=59>±@‘59!±@‘94±@‘9A9D5A±@N@‘592>±@`‘;1+"7(>3^20>72; +/2±@@‘>6;6<±@‘>;!7.±@.@‘71;9±@‘>=>±@‘;>!±@‘24±@‘2A;A±@‘>DN±@‘>;7>±@`‘43797$$O477&]74079O470<`CB@70@@C76^±@‘7@7±@‘CB`@‘0C7±@‘><7+;7>C>;2(=2!;/C9>7?C;>26?2A3;0>9>±@‘A;>±@‘2.7EA7*>7!A;72>0;±@‘@60'±@‘C7<-^71@C< 0/7±@@‘C4@4<±@‘C@!±@‘<+.±@‘</± "@J<C[2HK]2Áƒ‘@(>"±@‘C#0(`>C7$0@±@@P@‘7C)> @$±@`@‘C±@‘>7/@0±@‘70C"±@‘<"@"P@<±@‘C±@‘7( 7±@@‘@±@‘C)<`C<±@‘@±@‘7*`((7;#±@@‘7"`;7±@‘(;$±@P@‘;±@‘7 ;)`±@@‘;7;/0;±@0‘7"4";"±@P‘47±@‘;(±@‘; ±@‘;@74;)±@`‘4±@‘;*±@‘;7`;9%)'±@@‘7(<'`±@‘)79<±@‘0'`7%±@‘<)±@‘9'0P707<9±@@P@‘09&±@‘5'<(@<5±@‘9 0.±@‘<1<±@‘0<±@‘A.5( 5<.09+A0- < 09±@‘7(+">3;1±@^‘20;>7 +/2±@@‘>6;6<±@‘;>!7.±@.@‘71>=;9±@>@‘>;!±@‘24±@‘2A±@‘>D;AN±@‘;>±@‘7>`C9@30$O@C77&^C9@0O@C<<`CB@7<07@C76^±@‘7@7CB±@`‘@‘7A7±@‘5+<<97>A<90(=0!<7A99/?A<906?0A3>9<0>A±@‘><2.±@‘5EA7*>7!A<72>0<±@‘0'@6±@‘<-C7^71@C< 0/±@‘7±@‘C4@4<±@‘@C!<+±@.@‘<1@2±@‘C7>±@‘C@!±@‘7.±@‘7A±@‘C8@6N±@‘C@<1±@`‘)(<=<98O9<0(^90<8O9<59`<991500<90.^±@‘0<6±@‘9.`58/<±@‘9)5),9,<'7%±@`‘7)90(<±@@P@‘09'±@‘7#<,`0379±@@‘<0±@‘009%5&±@‘<%P59±@@‘0-< 0±@@‘5±@‘<,9!`9<0.±@@‘5`±@‘09(±@‘<+)+7+`)7<9±@@‘0+`±@‘<-±@‘9+7(0P7±@‘0:<9±@P@‘0<,±@‘9)5+@±@‘<95 01±@‘<6<0±@‘<±@‘5+A2 5<209/01A < 0±@‘9>77-;6+'±@^‘21>7;O2>4;4=;>!2(/21;2>7A0:±@‘>;A!2.±@‘2A>8;6A/?A;>2.+O±@‘2C=0(±@‘@8OC@7(^C8@0/7 C@76`@1C9HA70HC@7.^HA0C60@.±@‘7HC0@±@‘<#)(9(7"`±@‘0$)79±@‘<P±@‘07 <)9$±@`@@‘0/79<00±@0‘9"±@‘5"<"P59<±@‘0(±@ @‘0@±@‘9<)5`±@@‘0*9<5`)'9%7(±@@‘0<'`)0'±@‘7<9±@`‘07%9'±@@‘<)P707±@@‘<9P0±@‘<(9&5'±@@@‘9<5 ±@‘0.<1<0±@‘<±@‘5(A. 5<.0A9+0- < 0±@‘9±@‘7(>3+";1^20;>7 +/2±@@‘>6;6<±@‘>;!7.±@.@‘71±@‘;9>=>±@‘;>!24±@@‘2A±@‘>D;AN±@‘>;±@‘7>_7@*C.0†>±@‘C0@ÿ/MTrk¾²Â!ÿJAZ2²u}Cÿ @ÿYÿTrack3ÿGeneral MIDI²]HKJ<ÿY²@ @[ƒ @@[]HKÂ!²J<C˜[HKÂ!²J<] @@Cƒ’+K‹_+!K$K$!!5$=!$.$K² @HK@Â!²J<C[]q’$/$=0$2!K!!?!N!K‚3!O!K‚!!5!O!K‚! != !B+K++?+N+K‚3+Q+K++?+N+K‚C+A$K…_$!$K$$=0$.$Ks$/$=0$0+K‚++5#+?+K‚+ +=@+"$KŠ$)=0)2+K…++K‹_+!)K))=0).)Ks)/)=0)0+K‚++5#+?&K‚& &=@&"(K((=0(.(Ks(/(=0(0(K‚((5#(?²HKÂ!²C]J< @[@ƒ’(K((=0(.(Ks(/(=0(0(K‚((5#(?(K‚( (=@("+K++?+N+K‚3+O+K‚++5+O+K‚+ += +B$K$$?$N$K‚3$O$K‚$$5$O$K‚$ $= $B+K++=0+.+Ks+/+=0+0$K‚$$5#$?$K‚$ $=@$")K))=0).)Ks)/)=0)2+K++?+N+K‚C+A+K++?+N+K‚C+A$K…_$!)K))=0).)Ks)/)=0)0+K‚++5#+?+K‚+ +=@+"$K‚?$=$K‚#$c)K‚|²Â!²@]CJ<HK[ @ƒ’)’+K++?+N+K‚C+A$K…_$!$K$$=0$.$Ks$/$=0$0)K‚))5#)?+K‚+ +=@+"$K$$=0$.$Ks$/$=0$0)K‚))5#)?)K‚) )=@)")K))?)N)K‚3)O)K‚))5)O)K‚) )= )B+K++?+N+K‚3+O$K‚$$5$O$K‚$ $= $B)K))=0).)Ks)/)=0)0)K‚))5#)?)K‚) )=@)"+K++=0+.+Ks+/+=0+0!K‚!!5#!?!K‚! !=@!"!K!!?!N!K‚3!Q$PŠ$)H0)…P)H0)2+Z…++Z‚~²[ @CÂ!²HK]J<@‰’+$K$$=0$.$Ks$/$=0$0+K‚++5#+?+K‚+ +=@+"+K++=0+.+Ks+/+=0+0$K‚$$5#$?$K‚$ $=@$"$K$$?$N$K‚3$O+K‚++5+O+K‚+ += +B$K$$?$N$K‚3$O)K‚))5)O)K‚) )= )B+K++?+N+K‚C+A+K++?+N+K‚C+A$K…_$!)K))=0).)Ks)/)=0)0+K‚++5#+?&K‚& &=@&"(K((=0(.(Ks(/(=0(0(K‚((5#(?²]C@HK[ @Â!²J<ƒ’(K((=0(.(Ks(/(=0(0(K‚((5#(?(K‚( (=@("+K++?+N+K‚3+O+K‚++5+O+K‚+ += +B$K$$?$N$K‚3$O$K‚$$5$O$K‚$ $= $B+K++=0+.+Ks+/+=0+2$KŠ$)=0)2+K…++K‹_+!)K))=0).)Ks)/)=0)0+K‚++5#+?+K‚+ +=@+"$K$$=0$.$K²HK @C@Â!²]J<[‰’$(KŠ()=0)2+K‹_+!$K$$=0$.$Ks$/$=0$0)K‚))5#)?+K‚+ +=@+"$K$$=0$.$Ks$/$=0$0)K‚))5#)?)K‚) )=@)")K))?)N)K‚3)O)K‚))5)O)K‚) )= )B+K++?+N+K‚3+O$K‚$$5$O$K‚$ $= $B)KŠ))=0)2+K…+†?²@ÿ/MTrk(’³ÃÿJAZ2³uÿTrack4³}[2J<@Cÿ @ÿY³HK ^ÿGeneral MIDIÿY³]2“C746<)H2Z71`H9HCC3@3^77(\H7H³ ^óCHK[2]2J<@“CC6441`7-7`@@4C7CH7H^7.7^A7<5+97<7/67-^21b>>4;4^77+_0<2>>7`22.`<>>8<6`771^0(4(>"C#>/;+9_7$7_CC)> >@$`77/`C"<"C4"42<_7(7`<<C)@@C`7*7`<0>7)'7(<'9%`0'`<77%9'9<)`070`³[2HKCó]2 ^J<@ƒ“409@<7(;1+">3^20b>>6;6;^7.7`>=;>;9`224`>;>D;A`7>7^)+430$C9b7&7^CC9@0`<<_;>2CBC447`776`CB@7@C`<,9%@'-,<4_4(`>'9#>@@,`434`<%9&@9@%CH@_4-4`9@@<-+<(@+-7_4+4`<+@-<@`4:4`@9+<9@,<)`441@6@\9E29+0@2@041<477-+';6^21b>>4;;4^22(^E9>;2>7;C0\2.2`;6C/>8C;>`22.^>./-+ 7&+7>_2/2_>>>;>;^767`>/:/>>C_226`>F>;C;_7G7`C'+J&<$4,`77+`CC%J+@-J`773`H/C0>;2/C440`77;`H@0H2C6C@`77;JJE`<4CC7<)46HH2Z771`H9HCC3@3@^77(\H7H41C64C`77-`C7@4@CH7H^77.^C7J<C><7+;77b2(^CC9;;/>>7`226^A3H4@;;0>9>`22.`;>>6;-A7A:C#>"0(4(C7;A>_7$`C@$>> C)`77/`C"C<"44"2_7(7`CC)<<@@`7*7`07<><')'9%7(`0'`9'<)7%<79`070`C<@9<(9&45'`00.<<1\A.5(50<.</0-9+09`709);1+">37(^20b>6>;;6^7.7^5<A7599=`-4`9D955A`2>2_;+>7(+">3;1^202a>6>;;6^7.7_59-;>;9>=`224`;A>>D;`77>_+C9@3$$b7&7^C@C9@0`<<_2>;CBC@@7`776`@7CB@C`;/CC9>7`226^>3>A<99950`-.`95-965>7>;;C97>5/;74-('^/1b;4;`44+_2-;;7`/./`;;8`441_(((;=;b//(^;8;`494^³ ^ó[2J<CHK@]2ƒ“;74-('^/1b;4;`44+`;7;`//.`;8;`441_(((;=98;b//(^;890;9`494`;;9`/./`;;6`448^+,9%>';,494;(/(/;_2(`;'9#>,;>9`223`;%>%;>7&`2-2`7>7;;!>,`2.2`9+>++9+>+/(`2+2`9(;+;>>-9`2:2`/)>,7>7+/`221>6>\7+C270>2>/212;;/`+9;C0'<-46C7^717bC4C@4^77(^>/4C42C7H0\77.`H/@6C@C8H`7.7^2<0C=0(448Cb7(7^@C8C@0`767_H441C9CHA\7.7^HAH/C6C/@.@_@07>77);6CC2Z21`C9C>3>;;3^2(2\C7CH4;1;>>6`22-`>7;4;>A7^22.^H77C47C<<+b7(^C7CH9@/H`767^H3A;>HC9C404`7.7`@CC6@-HH7;<@2)'5-<796^01b<<4949^5+5_7492<9<7`0.0`9<<896`551^+ >.7&;-C)H_2/`>>>;;>^767`5:9>79<05_-6`599F5C`22G`;-++ >.7&>;_22/`>>>;;>^776`;:95>>>-;_226`;C;>F>`7G7`0$J&@,+C'`7+7`J+@-C%JC@`737`@C;C0></7b2(^C9;/C>7>`226^A39A<>9/0/>`22.`;-;>>6A7A;7AC;4/C.H<06<9`7/`@(H6CHC+`77<_2/@,H@H>CC;`7>7`@CHCH@?HK`7M7\0<4>5/0"A"E HH#M,‚`³]2[2HK@J<ó ^Cƒ“ME5A<)46C7H2Z71`H9HCC3@3^77(\HH7C441C6`77-`C7@4C@HH7^77.^@7H0@H<74;<4+77b/(^;77@9@;7/`/6/^@3@C7;9;70`/./`77-;;6@@7:@C4;@7796<75-)'^01b<4<994^55+_/<9<792`00.`<969<8`515^;-7&+ >.)_2/`>>>;>;^767`;:>>>;09<_226`;>>F;C`77G`+4,C'J&<$5_7+7`C%C@-JJ+`737`40H/2C0C4>;`7;7`@HCC6@0H2`JEJ7;7`<4C7C46<)H2HZ717`H9HCC3@@3^7(7\H7HCC6@@1`7-7`@4CC7@HH7^77.^JA7<45+<<97b0(^9/9<7A9<A`006^A3@CHA<>9<0`2.`><->6<AA7;795A00'<-C7@6<^71bC4C@@4^<<+_2CC742`7.7`C@@6C8`<<1_>0)(<=98<b0(^90<8<9`59_C47@919<9<`00.`<9.<69`558^9,7%),<'<9)_0(0_<99'77#<,`003`5&<%9%<95_0-0`<59<,59!`00.`97<)9()+<+7+`00+`99+<-7(<7`0:0`<,59)9<5+`001<6<\5+A250<2</099/01`)07/6>77-+'^21b>4>;4^22(^5<A;>>7;2A0\2.2`>8A;>A/;6`2.2^97+/C=0(48b7(^CC8@0`776_;>AC9441CHA\7.7^HAH/C6C/@.@_@20<7965)A2Z01`A9A<3<993^00(\AA7CH74<991<6`00-`<9<794AA7^0.0^A75A9<<97<5+b0(0^99/A<A9<7`060^A3A<99<90`0.0`9-<<69AA7;5A<+'7-/6>7^21b>>4;4^77+_0;;2>>7`22.`;>8;6>`771_/9+7<8-(@=b4(^@8<@<0`99_>;2@@9<1<`4.4`<@@6<.`998^@'<%-,-<@_4(4_<#@,@<`434`@%<@9&<%9_4-4`9@9$`7%`C>C+>!@@&`772`9@<&C&@&C<`77-`@"C@<C-<`77/`<77/09,>).<^29b>?>;?;^775^5A<;;A>>F`22<`>N;J>;`77F_+70+)>7><;;;^292a>>?;;?^775^³]2 ^[2@óCJ<HKƒ“;49C?0(b7*^@5C?C`+H7;7><7+b2(^>7;/>;CC9`226^C3@C4>;0>9;`22.`>>6;-;CC7;77->7/6+'>^212a>>4;4;^7+7`>>7//2`22.`>8;>;6`771_+C480(C=b7(7^CC8@0`<9_/>2;441CC9`77.`@C@.C6`<<8^>%0,C'4,C04_7(7_C,C>@'>#@_773`C<&C%44%<_7-7`<<@C@!C,`77.`9+>0;(++>+`2+`>9;+;9(>-`2:2`;>7+7@<;)>,C4`212>>6\C277+0>2>/;212;/`+9;0'C7C<-46^771bCC4@4^7(7^>4C7C42H0\7.7`@6C8H@H/C`7.7^2<0)(<=98b0(^<8909<`006_H@C4<991<9AA\0.0^AAA/<6</9.9_9;-+ >.7&)7_2/`>>>;>;^767`<A79>5:0_-6`99F5C5`2G2`;-7&+ >>.+;_2/2`>>>;>;^767`5->;:9>>;_226`;C>;>F`77G`+C'@,0$J&`7+7`C%@-@JCJ+`737`C@;@02>C07>CC9;/`226^>3A><99950`-.`59965->7>;5C;>97/;74-('^/1b;;4`44+_2-;7;`//.`;8;`441_(;((;=b/(/^;;8`449^³J<]2 ^HKó@C[2ƒ“(';74-^/1b;4;`44+`;;7`//.`;;8`414_(;=((98;b//(^;;8909`449`;;9`/./`;6;`448^9%+,;,>'4/9;4(;/(_2(`;'>,9#>;9`223`;%>;7&>%`22-`>,>;7;!7`22.`>9+++/(>+9+`2+2`;>->9;+9(`22:`7+/)/7>,>`212>>6\7C27+0>2>/21;2;/`+9;460'C<-C7^771bC4C@4^7(7^>/4CC742H0\7.7`@C8HH/@6C`77.^20<0(448CC=b7(7^C8@@0C`767_H4C41C9HA\7.7^HAH/C6C/@.@_@0>77)7;6C2CZ21`C9C>>3;;3^22(\CC7H4;>6;1>`22-`>7;>;4A7^22.^0(4(>"C#7>C_7$`>C> @$C)`77/`4"CC"4<";A_7(7`C<@<C)@`77*`<7)'0><'9%7(2_0'`<)9'79<7%`070`9<C4<(5'9&@`0.0<<1\5A.5(0<.</00-9+9`09)7>3;17(+"^20b>>6;;6^77.^<A579=59`-4`9D595A`22>_;>+>3;1+"7(^202a>>6;;6^7.7_95-;;9>>=`224`;>D>;A`77>_+@3C9$$b77&^C@0C9@`<<_>;2CB@@7C`776`C@7@CB`C;/>7C9`226^A3<A9/>>9/0`22.`>;;->6A7A;;C7A460'<-C7^71bCC4@4^<<+^³ ^]2HKC@ó[2J<ƒ“C#4(>"0(/_7$`C)@$> C>_77/`4"<"CC"4_77(`@C<C)@<_77*`<>>7"((07;#02_/$`;7;)7 `///`C4@;7<;"4"7"`/(/`47;7;)4`/*/`<'47(/@C)'(779%`0'`9'79<7%<)`007`;49<5'<(9&`0.0<<1\A.55(0<.</9+0-09`07)9;17(>3+"^20b>6>;6;^7.7^A5<;9>>=;`242`>D;A>;`7>7_+0$C943b77&^CC9@0`<<_>;2C447CB`767`CB@C@7`9<0<`2.`<<->6>AA7;759A<C7@6<-00'^71bCC4@@4^<<+_242CC7`77.`@C@6C8`<1<_>098<=)(<b0(^<990<8`59_47C@<9991<`00.`9.<<69`558^9,),7%<'<)9_0(0_7<9'7#9<,`003`<9<%5&9%5_0-0`<,9!95<5`00.`)<+)+7+9(7<9`00+`<-7(9<79+`00:`5+9)<,59<`010<6<\55+A20<2</09019/`0)7+'>77-/6^21b>>4;4^22(^5A<>;;2>7A0\2.2`A/>A;;6>8`22.^9+7/0(48C=b7(^CC8@0`776_>A;C41C94HA\77.^HAH/C6C/@.@_<#)(@9(7"207_0$`97<7 <)9$`00/`<"5"9"9HC<4_00(`<<)5995`0*0`77(9%<')'<9)`00'`<977%<)9'`007`5'9&<(59<`00.<<1\55(A.0<.</0-909+`7)07(+"/1>3^20b>>6;6^7.7^A<5>=;9;>`242`;A>D;>`77>^@,C,0,9+/2>;7†?0@C³@ÿ/MTrkíÄ0ÿJAZ2´ 0eÿGeneral MIDI´[(J<}@ÿTrack5´HKC](ÿYÿYÿ @ƒ´J<HKC[(@](’”H.†´@]([(J<CHKƒ”HƒC.‰Cƒ´J<]([(CHK@ž”H4@4‰G/>.@HƒG.>.G>ƒH.@.G†H.>.H†C.>‰CA.†>.A†>;8‰´J<[(@CHK](”;¹H4@4ƒH.<.HE/@†H;)G)C)<ƒC);)G)CG;ƒ<)C);GCH)E†A)<)HH)<ƒ´@HK](CJ<[(ƒ”A†H<†C@4H4‰E/<.H.@Hƒ<)C)H/H<EƒHCC)H)<<)†<HA)H)<)†CŒ>)G)AH<;)ƒ>G;G)>);)ƒ<)H)@);G†HH)<@ŒG.<;.H†E/;9/GŒH.E<.9†HH.<<.ƒA8†<Hƒ>.AƒC8†´HKC](@J<[(”>C¹H4@4ƒH@H.E/<.†H<;)G)C)ƒ>/;CJ/EE)Gƒ;)D)JE>G)‰´](@[(CHKJ<‰”D†G;¡H.†A.H†A>.†C.>‰A.C†>.A†>ƒ´J<[(C@HK](†”H.ƒHG8ƒ@.ƒ<8@ƒGA.†C.<A‰C†A.†C8A†CA.’A>.†>†<.ƒA.†<ƒ>.AƒC.ƒ@$C>C$†@@C´@ÿ/MTrk2ÉÿJAZ2¹J<wÿDrumsÿGeneral MIDI¹[™'$¹@™1$ÿ @¹}HK™#;,)ÿY¹C Lÿ¹] ™'#,1@,$ ,@0$'0&A,0 ,&0'@,$ ,@,)¹[@J<™#D¹]CHK ™#,@,#D ,#@,)'00$&2 '&,0@, ,@#;,) #,@,$ ,@,00$')&: '&0,@,$ ,@#D,) ,#@#D,$ ,#@&:,00$'0 0&,'@&+,$ &,&$ &1,$'#3 ',#1@, ,@')0,)&: '0,&@, ,@,$#; #,@#;, ,#@')&+0,$ '0&,&$ &, ,@1,$'#3 '1#,@, ,@&:')0,) ',&0@, ,@#;,$ #,@#;, ,#@,$&+0') ,&'0&$ &, ,@,#; ,#@, ,@0,$&:'$ &0,'@, ,@¹J<™,¹[HK]@C™#; ,#@#;, ,#@&:0,$') ',&0@, ,@,0#D #,@,$ ,@0+'5&H,0 ,'0&@,$ ,@#L,0 #,@'5#3,$ ,'#(',0'50+''0,& &'<,$ ,'&2 &1,$'#3 1',#@, ,@&:,)')0 0,'&@, ,@#;,$ #,@#;, ,#@&+,$0') '&,0&$ &, ,@,)1$#;'$#D,$ 1#,'#,@,,$ ,,@')0$&A,00$,)'0&A ,'0'&,0&@,$, ,,@¹J<C@[™#D,)¹HK™,$#D¹] ™#,,#@#;#D,, ,#,#@0$,)'0,)'0&A0$&2 ''0&&0,,@,, ,,@#D,$ ,#@, ,@&A0$,)') &,'0@, ,@,$#D #,@#;, ,#@,)&A0$'0 &,'0@, ,@,)#; #,@,$ ,@')&:0$,0 0,&'@,$ ,@,)#D #,@#D,$ #,@&:'00$,0 &0',@&+,$ ,&&$ &1$'$#;,) ',#1@,$ ,@&A'00$,0 0&',@,$ ,@#D,) #,@#D, ,#@&20$'0,) '&0,@, ,@,0#D ,#@,$ ,@0+&H,0'5 &0,'@,$ ,@#L,0 #,@'5#3,$ #',(',0'50+''0,& &'<,$ ',&2 &'1#3,$ ,'#1@, ,@&:,)0') &,0'@, ,@,$#; ,#@,#; ,#@&+0'),$ 0,&'&$ &, ,@'$#;1$,) 1',#@,$ ,@'0,0&A0$ &0',@,$ ,@,)#D ,#@,#D #,@,)'00$&2 ,'0&@, ,@1',$#3 1'#,@, ,@')&:0,) ,0&'@, ,@,$#; #,@,#; #,@&+0'),$ 0'&,&$ &, ,@#3,$'1 '#1,@, ,@0&:'),) 0'&,@, ,@,$#; ,#@#;, #,@,$&+')0 0'&,&$ &, ,@#;, ,#@, ,@&:0'$,$ 0',&@, ,@,#; ,#@#;, ,#@,$')0&: &,'0@, ,@,0#D ,#@,$ ,@,0&H'50+ 0',&@,$ ,@#L,0 ,#@#3'5,$ '#,(',0'50+'',0& &,$'< ',&2 &#D,0 #,@,$ ,@&H0+,0'5 '0,&@,$ ,@,0#L ,#@,$#3'5 ',#(',00+'5'',0& &,$'< ,'&2 &'1,$#3 ,'1#@, ,@&:,)0') ,'&0@, ,@,$#; #,@#;, ,#@0,$&+') &,0'&$ &, ,@1$#;,)'$ #1',@,$ ,@,00$&A'0 &',0@,$ ,@#D,) #,@#D, #,@,)'00$&2 '0&,@, ,@,)#; #,@,$ ,@0$&:'),0 ,0'&@,$ ,@,)#D ,#@#D,$ ,#@'0&:,00$ 0&',@&+,$ &,&$ &,)#; #,@, ,@&A'0,00$ 0,'&@,$ ,@,$#D #,@,$#; #,@&A0$,0'0 '0,&@,#* #,@#;,0 #,& &,$ ,@,0&A'00$ ,&0'@,$ ,@¹[@J<™#D,0¹]CHK ™,#@#D,$ #,@&A'),50$ ,'0&@,$ ,@#;,) ,#@, ,@,00$&A'0 0&,'@,$ ,@,$#D ,#@,$#; #,@&A0$'0,0 '0,&@#*, ,#@#D,$ ,#@, ,@0$,)&A') ',0&@, ,@#D,$ #,@,#; ,#@,)&A0$'0 ,'0&@, ,@,$#D #,@, ,@&A'),)0$ &0',@, ,@,$#D ,#@#;, #,@'0&A,)0$ 0&',@, ,@#;,) #,@,$ ,@&:,0')0$ ,0&'@,$ ,@#D,) ,#@#D,$ ,#@0$&:,0'0 &'0,@,$&+ ,&&$ &'$,)#;1$ ',#1@,$ ,@,0'0&A0$ &'0,@,$ ,@#D,) ,#@#D, #,@,)0$'0&2 &,0'@, ,@,)#; ,#@,$ ,@0$')&:,0 0,'&@,$ ,@#D,) #,@#D,$ #,@&:'00$,0 '&,0@&+,$ &,&$ &,)#; #,@, ,@,0&A0$'0 &',0@,$ ,@#D,$ ,#@#;,$ #,@0$,0'0&A &0',@,#* #,@#;,0 ,#& &,$ ,@&A0$'0,0 &'0,@,$ ,@#D,0 #,@,$#D #,@')&A,50$ &0,'@,$ ,@,)#; #,@, ,@'0,0&A0$ 0'&,@,$ ,@,$#D #,@,$#; #,@,0'0&A0$ ',0&@,#* ,#@,0#D ,#@,$ ,@,0'50+&H ,&0'@,$ ,@,0#L ,#@'5,$#3 ,'#(',0'50+''0,& &'<,$ ,'&2 &#D,0 #,@,$ ,@'5&H0+,0 '0&,@,$ ,@,0#L #,@,$'5#3 ',#(''50+,0''0,& &,$'< ',&2 &1',$#3 ,#1'@, ,@')0&:,) &0,'@, ,@,$#; #,@,#; ,#@')&+0,$ ',0&&$ &, ,@#;,)1$'$ #'1,@,$ ,@0$'0&A,0 0,&'@,$ ,@#D,) ,#@,#D #,@&20$,)'0 ,0&'@, ,@#;,) ,#@,$ ,@&:,00$') 0,'&@,$ ,@#D,) ,#@,$#D ,#@&:0$,0'0 ,0&'@,$&+ ,&&$ &#;,) ,#&$ &, ,@'00$,)&A '&,0@, ,@,)#D ,#@,#3 #,@,)'0&20$ ,'&0&+ &#3, ,#@1$'$#3&+ &'1#‚`¹J<[@HKC]`™#3, #,@&20$'0,) ,0&'&+ &,#3 ,#@#;1$,)'$ ',1#@,$ ,@&A,0'00$ &',0@,$ ,@,)#D ,#@,#D #,@&2'0,)0$ &,0'@, ,@#;,) #,@,$ ,@'),00$&: 0',&@,$ ,@#D,) ,#@,$#D ,#@0$&:'0,0 &',0@,$&+ ,&&$ &#;,) ,#@, ,@&A0$,0'0 &,'0@,$ ,@,$#D #,@#;,$ ,#@,0&A0$'0 ,0&'@#*, ,#@#D,0 #,@,$ ,@,0'5&H0+ '&,0@,$ ,@#L,0 #,@,$'5#3 '#,(''5,00+'',0& &,$'< ,'&2 &#3',$1 1#,'@, ,@,)')0&: ',&0@, ,@,$#; ,#@,#; #,@,$&+')0 &,0'&$ &, ,@,)1$'$#; ',1#@,$ ,@,0&A'00$ &,'0@,$ ,@,)#D ,#@#D, ,#@,)0$'0&2 ',0&@, ,@#;,) #,@,$ ,@&:0$,0') 0&,'@,$ ,@,)#D #,@,$#D ,#@,0&:'00$ 0',&@&+,$ ,&&$ &#;,) ,#@, ,@&A0$'0,0 '0,&@,$ ,@,$#D ,#@,$#; ,#@&A'00$,0 &0',@,#* ,#@#;,0 ,#& &,$ ,@0$,0'0&A 0',&@,$ ,@#D,0 ,#@#D,$ #,@&A0$,5') 0,&'@,$ ,@#;,) ,#@, ,@,00$'0&A '0&,@,$ ,@,$#D #,@,$#; #,@&A'00$,0 ,&'0@#*, ,#@#D,$ #,@, ,@'),)&A0$ 0'&,@, ,@#D,$ #,@#;, ,#@,)0$&A'0 ',0&@, ,@,$#D ,#@, ,@,)&A0$') ',&0@, ,@#D,$ #,@#;, ,#@&A0$'0,) &0',@, ,@,)#; ,#@,$ ,@0$,0')&: ,&0'@,$ ,@#D,) ,#@,$#D ,#@0$'0&:,0 ,0'&@,$&+ ,&&$ &'$#;,)1$ 1,'#@,$ ,@'0,00$&A ,&'0@,$ ,@#D,) ,#@,#D #,@,)0$'0&2 '&0,@, ,@,)#; ,#@,$ ,@0$&:'),0 '0&,@,$ ,@,)#D ,#@,$#D ,#@,0'0&:0$ ,'&0@,$&+ ,&&$ &#;,) #,@, ,@0$'0,0&A 0,'&@,$ ,@,$#D ,#@,$#; ,#@0$,0'0&A &,'0@,#* #,@,0#; #,& &,$ ,@0$&A,0'0 '&,0@,$ ,@#D,0 #,@#D,$ ,#@,50$')&A 0',&@,$ ,@,$'#31 ',#1@, ,@')0,)&: 0,&'@, ,@,$#; #,@,#; ,#@0&+'),$ ,0&'&$ &, ,@'#5,&1 #',1@, ,@0,,',&= ,0&'@, ,@#@,( ,#@#@, #,@,('/0 &0 0&',&' &, ,@#C,# #,@, ,@,*0!'*&C &',0@, ,@#C,# #,@#C, #,@,*'10!&C ,&0'@, ,@#C,# #,@, ,@,*0!&C'* &'0,@, ,@,##C #,@,#C #,@0!&C'1,* ,'&0@, ,@,9#M ,#@,* ,@,9'@&T02 0',&@,* ,@#V,9 ,#@#:'@,* ,#'(',9'@02'',0& &'G,* ,'&: &,9#M #,@,* ,@,9'@&T02 0&,'@,* ,@#V¹[]C™,9¹@J<HK ™#,@'@#:,* #,'('02'@,9'',0& &'G,* ',&: &,('!#71! ,'#1@,! ,@0 '/&@,/ '&0,@,! ,@,&#> #,@#>, ,#@0,&&.', ,0&'&& &, ,@1$#;,)'$ #'1,@,$ ,@,0&A'00$ '0&,@,$ ,@,)#D #,@#D, #,@0$&2'0,) &,0'@, ,@#;,) #,@,$ ,@0$')&:,0 &0,'@,$ ,@,)#D ,#@#D,$ ,#@&:,0'00$ ,&0'@,$&+ &,&$ &,)#; #,@, ,@&A'0,00$ '&,0@,$ ,@,$#D ,#@,$#; ,#@,00$'0&A &,'0@#*, ,#@,0#; ,#& &,$ ,@,0'00$&A 0,'&@,$ ,@,0#D #,@#D,$ #,@,5&A0$') 0&',@,$ ,@#;,) ,#@, ,@,0&A'00$ &',0@,$ ,@#D,$ ,#@,$#; ,#@0$'0&A,0 ,0'&@#*, #,@,$#D #,@, ,@&A,)0$') &'0,@, ,@,$#D #,@,#; #,@&A,)'00$ 0,'&@, ,@,$#D #,@, ,@,)')&A0$ '&,0@, ,@,$#D #,@#;, ,#@,)'00$&A &,'0@, ,@#;,) ,#@,$ ,@'),0&:0$ &,'0@,$ ,@,)#D ,#@,$#D #,@,0&:'00$ 0',&@,$&+ &,&$ &#D,0 #,@,$ ,@&H'50+,0 '&,0@,$ ,@#L,0 ,#@'5,$#3 ,#'(''50+,0'',0& &,$'< ',&2 &,0#D ,#@,$ ,@&H'50+,0 ',0&@,$ ,@,0#L #,@,$'5#3 #,'(''50+,0'',0& &,$'< ,'&2 &#31',$ #1',@, ,@,)&:')0 ,&0'@, ,@#;,$ #,@#;, #,@&+,$')0 ,&'0&$ &, ,@1$'$,)#; ,#1'@,$ ,@&A'00$,0 &0,'@,$ ,@#D,) ,#@#D, ,#@&2,)0$'0 0&,'@, ,@,)#; ,#@,$ ,@')&:,00$ 0,'&@,$ ,@,)#D #,@,$#D #,@'00$&:,0 ',0&@,$&+ &,&$ &,)#; #,@, ,@,00$&A'0 &0,'@,$ ,@,$#D ,#@,$#; ,#@,0&A0$'0 ,'&0@,#* #,@#;,0 ,#& &,$ ,@'0&A,00$ 0&,'@,$ ,@,0#D¹C][J<@HK ™#,@,$#D ,#@&A'),50$ 0&,'@,$ ,@#;,) #,@, ,@0$&A'0,0 '&,0@,$ ,@#D,$ ,#@#;,$ #,@0$'0,0&A &',0@#*, ,#@,$#D ,#@, ,@0$'),)&A 0,&'@, ,@,$#D ,#@#;, #,@'0&A,)0$ ',0&@, ,@#D,$ ,#@, ,@0$')&A,) &0',@, ,@#D,$ ,#@,#; #,@'00$,)&A '0,&@, ,@,)#; #,@,$ ,@,0&:0$') '0&,@,$ ,@,)#D #,@,$#D #,@'00$,0&: &0',@&+,$ ,&&$ &'$,)#;1$ 1,#'@,$ ,@0$'0&A,0 &'0,@,$ ,@,)#D #,@#D, ,#@'00$&2,) &'0,@, ,@#;,) #,@,$ ,@')0$,0&: ',&0@,$ ,@,)#D ,#@#D,$ #,@&:,00$'0 '0&,@,$&+ ,&&$ &',$#31 ,'#1@, ,@,)&:0') &0,'@, ,@#;,$ ,#@,#; ,#@&+')0,$ '&,0&$ &, ,@1',$#3 '1#,@, ,@')&:0,) ,'0&@, ,@#;,$ #,@#;, #,@&+0'),$ ,&0'&$ &, ,@,#; #,@, ,@'$0&:,$ 0,'&@, ,@#;, #,@,#; ,#@,$0')&: ,'0&@, ,@,0#D #,@,$ ,@'5&H0+,0 ,0&'@,$ ,@#L,0 ,#@#3,$'5 ',#(''50+,0'',0& &,$'< ',&2 &#D,0 ,#@,$ ,@,0'5&H0+ &',0@,$ ,@#L,0 #,@#3,$'5 ,'#(''5,00+''0,& &,$'< ,'&2 &1'#3,$ '#,1@, ,@,)')&:0 0&,'@, ,@#;,$ #,@,#; #,@0,$')&+ &,'0&$ &, ,@#;1$'$,) 1#,'@,$ ,@,00$&A'0 ,0&'@,$ ,@,)#D #,@#D, #,@'0&2,)0$ &0',@, ,@,)#; ,#@,$ ,@')&:,00$ ,0'&@,$ ,@#D,) #,@#D,$ #,@,0'0&:0$ &'0,@&+,$ &,&$ &,$'1#3 #',1@, ,@')&:,)0 '&,0@, ,@¹HK™,$#;¹J<][C@ ™#,@#;, #,@&+0'),$ &0,'&$ &, ,@#3,$1' ,1#'@, ,@0,)')&: ,0'&@, ,@,$#; ,#@,#; ,#@,$&+')0 ,&'0&$ &, ,@,$#3'1 #1',@, ,@')&:0,) 0&',@, ,@#;,$ ,#@#;, ,#@0&+'),$ ,'0&&$ &, ,@,#; ,#@, ,@,$&:0'$ 0,'&@, ,@#;, ,#@,#; #,@')0&:,$ 0,'&@, ,@#D,0 ,#@,$ ,@,0&H0+'5 &,'0@,$ ,@,0#L ,#@,$#3'5 '#,('0+,0'5''0,& &'<,$ ,'&2 &1,$#3' 1,#'@, ,@0'),)&: 0,&'@, ,@,$#; ,#@,#; ,#@0')&+,$ 0&,'&$ &, ,@#;,)'$1$ 1,#'@,$ ,@'0,00$&A ',&0@,$ ,@,)#D #,@#D, ,#@&20$,)'0 &0,'@, ,@#;,) ,#@,$ ,@0$,0')&: &,0'@,$ ,@#D,) ,#@,$#D #,@,00$&:'0 0&',@&+,$ &,&$ &,)#; ,#@, ,@'00$&A,0 ,'&0@,$ ,@#D,$ #,@,$#; ,#@&A,00$'0 &0',@#*, #,@#;,0 ,#& &,$ ,@0$&A,0'0 ,'&0@,$ ,@,0#D #,@#D,$ ,#@0$,5&A') 0,&'@,$ ,@,)#; ,#@, ,@,0'00$&A ,&0'@,$ ,@,$#D ,#@,$#; ,#@'0&A,00$ &,'0@#*, #,@,$#D ,#@, ,@&A,)')0$ 0,'&@, ,@#D,$ #,@#;, #,@,)&A'00$ 0&,'@, ,@,$#D ,#@, ,@,)&A0$') ,'0&@, ,@#D,$ #,@#;, ,#@'0&A,)0$ 0',&@, ,@,$#3'1 1'#,@, ,@&:0,)') ,'&0@, ,@#;,$ ,#@,#; #,@,$')&+0 ,0'&&$ &, ,@1,$'#3 #1,'@, ,@')&:0,) &'0,@, ,@#;,$ #,@#;, ,#@,$&+')0 '&0,&$ &, ,@#;, ,#@, ,@,$&:0'$ &'0,@, ,@#;, ,#@,#; #,@&:')0,$ ,'&0@, ,@#D,0 #,@,$ ,@0+'5,0&H ,'&0@,$ ,@#L,0 ,#@,$#3'5 ,#'('0+,0'5'',0& &'<,$ ,'&2 &1.#.,.'.†'$1$,$#$#,1'†,1#'ÿ/MTrkµµÅ1ÿJAZ2ÿGeneral MIDIÿPart-01µ[@ÿYµJ<ÿ @µ]}ÿYµC•Lµ@w HK†•ML†MGƒGFƒFL†LM†MJ†LJŒLLƒLL‰LJ†GJƒGGƒLGŒJLƒJJƒJL†LQ†QJƒJJƒOJ†HO†HM†GMƒGJƒJL’LLƒLLƒJL†JGƒGGƒLGŒLJƒJJƒLJ†LQ†QJƒJJƒJO†OH†HM†MGƒGGƒLG†LMƒMMƒ@M†L@†LM†JM†JLŒMLƒMMƒOM†OQŒMQ†MGƒGGƒGL†HL†HM†GM†GQŒQT†TMŒMOŒOLŒJL†GJƒGGƒGLŒLJƒJJƒJL†QL†JQƒJJƒJO†OH†HM†MGƒGJƒJL’LLƒLLƒLJ†JGƒGGƒGLŒLJƒJJƒLJ†QL†QJƒJJƒJO†OH†HM†MGƒGGƒLGŒLL†LM†JM†LJŒLMƒMMƒOM†QOŒQM†GMƒGGƒGL†LH†HM†GMƒGGƒGH†@Hÿ/MTrk•¶Æ1ÿJAZ2¶}J<HK–L¶@ hCÿPart-02¶[@ÿYÿYÿGeneral MIDI¶w]ÿ @@†–LMƒ`MJ@JG`FGƒFF@HF@HL†ML†MJ†JL‰`O@LO`LLLƒLL‰LJ†JGƒGG@GH`JH`LJŒJLƒJJƒJL„@ML`MO`QOƒQO@OM@MJƒJJ@JL`LM`MOƒOM@ML`LJ`JH„@JH@JM†MJƒJJƒLJ’LLƒLLƒLJ†GJƒGG@GH`HJ`JLŒLJƒJJƒLJ„@ML`MO`OQƒQO@MO@MJƒJJ@JL`LM`MOƒOM@ML`LJ`HJ„@JH@MJ„@JM@GJƒGG@GH`JH`JL†LMƒMMƒM@†@L†LM†MJ†JLŒMLƒMMƒMO†QO‰`OQ‚ OM„@MJ@JGƒGG@GH`HJ`LJ†HL„@HJ@JM„@MJ@JGƒ`GJ@MJ`QMŒTQƒ`TQ@QO`OMŒMOŒOLŒLJ†GJƒGG@GH`HJ`JLŒLJƒJJƒLJ„@ML`OM`OQƒQO@OM@MJƒJJ@JL`ML`OMƒOM@ML`LJ`JH„@HJ@MJ†JMƒJJƒJL’LLƒLLƒLJ†JGƒGG@HG`JH`JLŒLJƒJJƒJL„@LM`OM`QOƒOQ@OM@MJƒJJ@JL`LM`MOƒMO@LM`LJ`JH„@HJ@JM„@MJ@GJƒGG@HG`HJ`JLŒLL†LM†MJ†JLŒMLƒMMƒMO†OQ‰`OQ‚ MO„@MJ@JGƒGG@HG`HJ`LJ†LH„@HJ@JM„@MJ@GJƒGGƒGH†@Hÿ/MTrkã·ÇYÿJAZ2·w[@ÿY·]—L*·C}—H*ÿGeneral MIDIÿPart-03ÿY·J<@HK "ÿ @†—Q*HM*L†G*C*QM†GJ*H*C†JQ*HM*†QC*G*M†H*GCJ*‹ E*H*`JHŒEC*G*H†GG*CC*… GCG*C*`CGH*J*ŒHG*JC*†J*CGH*… HJL*H*`M*Q*HL†QG*MC*ƒGCM*J*‡@G*MJC*@CGL*H*†M*Q*HL†QMG*C*ƒJ*CM*GƒJML*P*˜PLG*C*†CGG*C*… C*G*CG`GCH*J*ŒHJC*G*†CJ*GH*… HH*L*J`HLM*Q*†G*QMC*ƒM*J*GC‡@G*MJC*@CGL*H*†LHM*Q*†QMC*G*… G*GCC*`CGH*J*†HJM*Q*ƒQO*MJ*‰JO*L*O†OLM*Q*†G*QC*M†H*CJ*GŒHJQ*M*ƒJ*O*MQƒOJH*L*†Q*LHM*’G*C*QM… GC*CG*`CGJ*H*†HM*JQ*ŒQG*C*Mƒ`GCG*C*@GCJ*O*`JQ*OL*ŒL,H,QL… HH.LL.`HLM.Q.ŒQJ.MO.˜OC*G*J†CGC*G*… CGG*C*`GJ*CH*ŒG*C*JH†CH*GJ*… HJH*L*`LM*HQ*†QC*G*MƒCGM*J*‡@MJG*C*@GH*CL*†M*Q*HL†QC*MG*ƒCGM*J*ƒJL*MP*˜PC*G*L†CGG*C*… GCG*C*`GJ*CH*ŒG*C*JH†CJ*GH*… JHL*H*`HQ*LM*†MC*G*QƒCGM*J*‡@MJG*C*@GH*CL*†M*Q*HL†QG*MC*… GCC*G*`GH*CJ*ŒJL*O*H†LOQ*M*†QMG*C*†H*GCJ*ŒJM*Q*HƒQMJ*O*ƒOJH*L*†M*Q*HL’G*MQC*… G*C*CG`GCJ*H*†HJQ*M*ŒQG*C*M†GCH†@Hÿ/MTrk ¸ÈYÿJAZ2ÿGeneral MIDIÿY¸}˜H*¸][@J<C ^@ÿYÿPart-04ÿ @˜C*¸HKw†˜H*M*HCƒ`MH*HE*@H*E*EH`HC*J*E†C*H*JC†M*HH*C†HC*MJ*†JCH*C*ŒCHŒJ*C*ŒC*JCH*ŒCJ*HC*†H*C*CJ†HCH*C*ƒH*HM*CƒMJ*C*HƒCJJ*E*ƒC*J*EJ†JCH*C*†HH*CM*†J*C*HMƒJCE*J*ƒL*JG*E˜GLC*J*ŒJH*C*CŒHCC*J*†C*H*CJ†CH*HC*ƒM*H*HCƒMC*J*HƒCE*JJ*ƒEJJ*C*†H*JCC*†CHH*M*„@E*MHH*@C*HJ*E†CJC*H*†CH*HM*ƒMHJ*C*ƒJCC*H*†G*L*CH†M*LGH*†HMJ*C*†JH*CC*ŒH*CHM*ƒHMJ*C*ƒJC*H*C†C*H*HC‰`CHM*H*†`E*H*MH@HEJ*C*†JCH*C*†CE*HH*„@HEE*H*@EHM*H*„@HE*MH*@HC*J*E†CJL*E*ŒLEC,H,ƒ`CL.HC.@H.C.LC`CH.HM.ŒHMC.J.ŒJC,CH,ŒHJ*C*CŒJCC*H*ŒCHC*J*†CH*JC*†H*C*HCƒCH*HM*ƒHMC*J*ƒJJ*CE*ƒEJ*C*J†JCC*H*†CHM*H*†MJ*HC*ƒE*J*JCƒJG*EL*˜GLJ*C*ŒCH*JC*ŒCC*J*H†CJC*H*†CHH*C*ƒHM*CH*ƒC*J*MHƒJE*CJ*ƒEJJ*C*†CH*JC*†CM*H*H„@MHH*E*@HEJ*C*†JC*CH*ŒL*G*CH†GM*LH*†MHC*J*†JC*CH*ŒHM*H*CƒMHJ*C*ƒJCC*H*†C*CHH*‰`HM*H*C†`HMH*E*@EHJ*C*†C*H*JC†E*CHH*„@E*H*HE@EHH*M*„@MHH*E*@HJ*C*E†JCH†@Hÿ/MTrki±ÁÿJAZ2± FÿGeneral MIDIÿ ÿ @ÿY±yr(ÿ Easy driving±xÿ/simutrans-124.3/simutrans/music/11-Stucked-Convoi.mid000066400000000000000000000512551474050137200224770ustar00rootroot00000000000000MThdÀMTrkÿ By ÿCopyright © 2006 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQ¡ ÿQ¡ ƒìÿQ±‰ÿQÂ:ÿQÓ4ÿQäyÿQö ÿQëÿQÿQ,¢ÿQ?|ÿQR®ÿQf:ÿQz#ÿQŽkÿQ£ÿQ¸$ÿQÍ›ÿQã|ÿQùËÿQ ‹ÿQ 'ÀÿQ ?lÿQ W”ÿQ p<ÿQ ‰hÿQ £ÿQ ½YÿQ Ø)ÿQ óÿQ ŒÿQ ,*ÿQ ImÿQ gZÿQ …÷ÿQ ¥JÿQ ÅZÿQ æ-ÿQ ËÿQ *;ÿQ M„ÿQ q°ÿ/MTrknÿ!ÿStaff-4Ë»» @‚Л@n›En…P›@›E0›An›Gn…P›A›G0›Cn›Hn…P›C›H0›En›Jn…P›E›J0›Ln.›L›Jn.›J›Hn.›H›Jn.›J›Hn.›H›Jn.›J›Hn.›H›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›>n.›>›@n.›@›An.›A›Cn.›C›En.›E›@n.›@›>n.›>›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›>n.›>›n.›>›n.›>›@n.›@›An.›A›Cn.›C›En.›E›Cn.›C›En.›E›Gn.›G›Hn.›H›Jn.›J›Ln.›L›Mn.›M›On.›O›Mn.›M›Ln.›L›Jn.›J›Hn.›H›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›An.›A›@n.›@›An.›A›Cn.›C›En.›E›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›>n.›>›@n.›@›An.›A›@n.›@›>n.›>›n.›>›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›An.›A›@n.›@›An.›A›Cn.›C›En.›E›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›Cn.›C›Gn.›G›Hn.›H›Gn.›G›En.›E›Cn.›C›En.›E›Cn.›C›An.›A›Cn.›C›En.›E›Gn.›G›Hn.›H›Gn.›G›En.›E›Cn.›C›An.›A›Cn.›C›En.›E›Gn.›G›Hn.›H›Jn.›J›Ln.›L›Mn.›M›Ln.›L›Jn.›J›Ln.›L›Jn.›J›Hn.›H›Gn.›G›Jn.›J›Ln.›L›Jn.›J›Hn.›H›Jn.›J›Hn.›H›Jn.›J›Hn.›H›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›>n.›>›@n.›@›An.›A›Cn.›C›En.›E›@n.›@›>n.›>›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›>n.›>›n.›>›n.›>›@n.›@›An.›A›Cn.›C›En.›E›Cn.›C›En.›E›Gn.›G›Hn.›H›Jn.›J›Ln.›L›Mn.›M›On.›O›Mn.›M›Ln.›L›Jn.›J›Hn.›H›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›An.›A›@n.›@›An.›A›Cn.›C›En.›E›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›>n.›>›@n.›@›An.›A›@n.›@›>n.›>›n.›>›@n.›@›An.›A›Cn.›C›An.›A›@n.›@›An.›A›@n.›@›An.›A›Cn.›C›En.›E›Gn.›G›En.›E›Cn.›C›An.›A›@n.›@›Cn.›C›Gn.›G›Hn.›H›Gn.›G›En.›E›Cn.›C›En.›E›Cn.›C›An.›A›Cn.›C›En.›E›Gn.›G›Hn.›H›Gn.›G›En.›E›An.›A›Cn.›C›En.›E›Gn.›G›Hn.›H›Jn.›J›Ln.›L›Mn.›M›Ln.›L›Jn.›J›Ln.›L›Jn.›J›Hn.›H›Gn.›G›Hn.›H›Jn.›J›Ln…P›Lÿ/MTrk [ÿ!ÿStaff-3ʺº @°šn.š>š@n^š@šAn^šAšCn^šCšEn^šEš@n^š@š@n^š@š@nƒ`š@0š>n.š>š@n^š@šAn^šAšCn^šCšAnPšA„0šEn.šEšLn^šLšJn^šJšHn^šHšEn^šEšEn^šEš@n.š@š@n^š@š@n^š@šDn.šDšEn.šEšEn^šEšEn^šEšEn^šEšEn^šEšEn^šEšHn^šHšJn^šJšLnƒšL‰0šnšBnšGn…Pš;š>šBšG0š:nš>nšAnšFn…Pš:š>šAšFž0šn.š>š@n^š@šAn^šAšCn^šCšEn^šEš@n^š@š@n^š@š@nƒ`š@0š>n.š>š@n^š@šAn^šAšCn^šCšAnPšA„0šEn.šEšLn^šLšJn^šJšHn^šHšEn^šEšEn^šEš@n.š@š@n^š@š@n^š@šDn.šDšEn.šEšEn^šEšEn^šEšEn^šEšEn^šEšEn^šEšHn^šHšJn^šJšLnƒšL‰0šnšBnšGn…Pš;š>šBšG0š:nš>nšAnšFn…Pš:š>šAšFž0šnšBnšGn…Pš;š>šBšG0š:nš>nšAnšFn‹Pš:š>šAšFÿ/MTrkUÿ!ÿStaffÀ!°° @!n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ $n^$0n^0.n^.0n^0ƒ#n^#/n^/-n^-/n^/ƒ"n^".n^.,n^,.n^.ƒ0n.0+n^+(n^(+n^+$n‚`$P!n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ $n^$0n^0.n^.0n^0ƒ#n^#/n^/-n^-/n^/ƒ"n^".n^.,n^,.n^.ƒ0n.0+n^+(n^(+n^+$n‚`$P!n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ !n^!-n^-+n^+-n^-b+n^+(n^(+n^+&n^&2n^20n^02n^2b+n‚+ $n^$0n^0.n^.0n^0ƒ#n^#/n^/-n^-/n^/ƒ"n^".n^.,n^,.n^.B,n^,.n^."n…P"ÿ/MTrkÄÿ!ÿStaff-1¹¹ @™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n ™* ™*n ™* ™*n ™* ™*n ™* ™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n ™* ™*n ™* ™*n ™* ™*n ™* ™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n.™*™*n.™*™*n^™*™*n^™*™*n^™*ÿ/MTrkþÿ!ÿStaff-2¹¹ @“@™#n ™# ™#n ™# ™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™#n ™# ™#n ™# ™#n ™# ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™#n ™# ™#n ™# ™#n ™# ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™&n ™& ™#n ™# ™&n™&™#n.™#™#n^™#™#n^™#™#n™&n^™#™&™#n™&n^™#™&™#n™&n^™&0™#ÿ/simutrans-124.3/simutrans/music/12-Steamin-across-the-prairies.mid000066400000000000000000002763661474050137200251410ustar00rootroot00000000000000MThd ÀMTrk(ÿ 2006.10.06ÿÿQ¡ ÿ/MTrkvÿ @ÿGeneral MIDIÿCopyright (C) 2006 shunterÿJAZ2ÿAÿ 2006.10.06ÿX`ÿ/MTrk%Ò°ÀÿJAZ2° @ÿGeneral MIDIÿMelodyÿY° x° x2T°[L]ÿ @H,24J‰ 4‚22T,2‹T2T,24J 4@4Q`2L4 2/G/2T\24H"4>4Nl42T.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVZX]`+à@(IJ(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ +R\+-M0.R-*./=0+M/8àBDGIJMORUWYZ]+àa@(C\(OPà& %+2 3 58>@l° %,79< = @C(@4=5* HJ0ITHO"OTtà+ 6 >@ IOLT0JTLJ GD&G L^$L JT&J GQ$G L^(LJR,JGR$G F\(FEL.ECP"Cà1E\à&4<?@2CL EC @J$@ E\0CPE&C@J*@CT0C@L*@>N$> ;L(;@\.@>R*>;M(;:T&: 9<*9à?9W7A7à /=>@097?$7 4M&4 9Z07R9&74Q&4 7P.79H0:J9:;H(;>Z*>@F*@>E,>:>,:OP9@Và?& %+2 39à58>@D° %,79< = @C(@4=5* HJO"ITH*OTtà+ 6 >@ IOLT0JTLJ GD&G L^$L JT&J GQ$G L^(LJR,JGR$G F\(FEL.ECP"à1CàE\à&4<?@2CL EC @J$@ E\0CPE&C@J*@CT0C@L*@>N$> ;L(;@\.@>R*>;M(;:T&: 9<*9à?7A9W7à /=>@097?$7 4M&4 9Z07R9&74Q&4 7P.79H0:J9:;H(;>Z*>@F*@>E,>:>,:9@.à?'<?@<9CTR@I@@A C C:@C@@CH@C@4CM@C@2CJ@C@ACI@C@<CI@ C@,CL@ C@.CP@C@: CM @C@<CACC4CC7@à% '.2 46;=?@N>J*C?T>,?@D0CT@>Q&C>?W(?@M.@CTl° *38=G QY:V SN@ 4 CEZ,EFRà/ )057:=?@FEP^ECT CETECD,CER,Eà>1GWà0 1=@°   >Q0?T>HGEDG0?‚0EGGXBXà=75;?@ƒ4N°? NW Z]6`pY4°2T.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVZX]`+à@(IJ(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ +R\+-M0.R-*./=0+M/8àBGDIJMORUWYZ]+àa@(C\(2T,24J 4@4Q°}^42L 2/G/2T\24H"4>4N°? NW Z]6`pY42T°.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVZX]+à`@(IJ(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ +R\+-M0.R-*./=0+M/8àBGDIJMORUWYZ]+àa@(C\(LdK\OX2K‚|ETELO N\JRNJPI^LXIL,K\ORL`K>OLEME OXLdK^KQ>à>;@Tà6/&%+06;@=6,!  #(-/.013579:84,'18<? =<:<@A@0>H@ > @X\@>@,>;@,;9@,9:Z,:9N,97A,74-à9/"4EZ à  #&+.13578:<?$° ")06<CHMQVZ]`bdfhiklnopqstuvxyz{*|} l~}{wsnh`WP@>;L";@^*@>T>;D;@b0@>Q$> ;Q;:Z&: 9"07T9740&4 9^097X"74M 49`07P974M 47Q,79P0:N 9:;F ;>\">@R@CLà<6+CàG\à  #&*-/24679:<=>?@<°  "$%')+-/247:=ADGJLOQSUWY[]_`bcdfghiklnprtuwyz|}~~}{zywvtrpmjgd_ZUOIB;4-& J\GGW JGEFEG@GJLG8JGEDEGAGJ<GFJGEIEGAGJRGCJGECEGFGJLGCJGE@EGCGJIG5JGE?EG=GJMG8JGE<G@EJ=G GJJE:GGDGJHG=EGJà=5( LWà   #&*.269<?@:°  !$'*-03579;<>ACEGJLPSVY[^`bcefgij hJA°fc_L°[UNF=4+"G=°J°EDGEGAGJX G9J GEHEGCGJRG: JGEN EF^FEC(CTEC@GC:@CEGCFEC@=@C3EA CC?E @LC@ CN$@WC><@>;@;CH@NC>P@>;R;:\:;F9I;7R974D47?9F7(:Q9 9C:7M974L42G2/G,/2T,24J 4@4Q°}^4°2L 2/G/2T\24H"4>4N°? NW Z]6`p4°Y2T.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVXZ]`+à@(IJ(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ +R\+-M0.R-*./=0+M/8àBDGIJMORUWYZ]+àa(Cà@\(OPà& %+2 3 58>@l° %,79< = @C(@4=5* HJ0ITHO"OTtà+ 6 >@ IOLT0JTLJ GD&G L^$L JT&J GQ$G L^(LJR,JGR$G F\(FEL.ECP"à1CàE\à&4<?@2CL EC @J$@ E\0CPE&C@J*@CT0@LC*@>N$> ;L(;@\.@>R*>;M(;:T&: 9<*9à?9W7Aà 7 à/=>@097?$7 4M&4 9Z07R9&74Q&4 7P.79H0:J9:;H(;>Z*>@F*@>E,>:>,:9@8à'<?@<9CTR@I@@A C C:@C@@CH@C@4CM@@2CCJ@C@ACI@C@<CI@ C@,CL@ C@.CP@C@: CM @C@<CACC4CC7@à% '.2 46;=?@N>J*C>?T,?@D0CT@>Q&C>?W(?@M.@CTl° *38=G QY:V SN@ 4 CEZ,EFRà/ )057:=?@EPF^ECT CETECD,CER,Eà>GWà10 1=@°   >Q0?T>HGG`ED?‚0E à=ƒG›G3G~ERC<C EG@HGGJXHJL\LMZMO\OQZSZQTZSVZTXXV„,V\ V@V`.VSWSBST0RZSR@R`.RQPQHQd@Q OZ4O\LdLDL^XLJ` J@J\.JLW*LfR`S` X\R`S XR^QRXTR,QO`OBQ`0Q0Q`.QOZ O@O`0L\OLHLbLO^(O8O^.OQ`0RTQ R SX*SVZXVTbUdXbT…8XU2W`[\X`W8X[ QPQZ^VXXZVQTQXTU\S\ S:UQWR\*R`XQXXO^TO L\XLBO^X`TOXLT L$X\O^VXO LRL(X^OZRXO LT L$XWO\XOXLTL"O^XZ`LXXOLPO`XbPXO LW L$X^O^RXO LTL"XXObNXOLTL"O\XT`LTXOL&X\O`\XL`OLJD HPJ HGR EZG CREATCAK\LdOX2K‚~ETE LO N\JRNJPLXI^IL,ORL`K\K>LOEME K^OXLdK4N°? NW Z]6`p4°Y2T°.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVXZ]+à`(Ià@J(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ +R\+-M0.R-*./=0+M/8àBGDIJMORUWYZ+à]a@(C\(2T,24J 4@4Q°}^2L4 2/G/2T\24H"4>4N°? NW Z]6`p4°Y2T°.24A$4<4L^42@*2/N(/+R`-N+*.L-(./M"/+N<àADHJLOQTVZX]`+(Ià@J(2W*24D"4>4Q\42G$2 /P,/2T\24H 4@4Q\428$2 /L\/2Z03L234N&°$; L` p z242H°,2/T&/ (e‚,àBGDIJMORUWYZ]a@0(ÿ/MTrk'E±ÁWÿJAZ2±[2ÿGeneral MIDIÿ1ÿYÿY±x "@]2ÿ @±HKJ<}Cƒ "x[2]2@HKJ<CÁWõ‘B-9-B9 9#B9B E&E B)B 9-B-B9 9!B 9B E'E B$B C-;-C; ;!CC; G(G CC ;-C-C; C;%C; G)G C$C H-@-@H @%H @H @&@ H)H H-@-@H H @%H@ @'@ H$H ;-C&C; ;%C!;C G(G CC C-;-C; C!;%C; G)G C$C H-@-H@ @#HH@ @&@ H)H @-H-H@ @!H H@ @'@ H$H ;-C-;C ;!CC; G(G CC C-;-;C ;%CC; G)G C$C H-@-@H @%H @H @&@ H)H H-@-H@ H @%H@ @'@ H$H ;-C&;C C!;%;C G(G CC ;-C-;C C!;%C; G)G C$C @-H-@H H@#@H @&@ H)H H-@-@H H @!@H @'@ H$H ;-C-;C ;!CC; G(G CC C-;-;C ;%CC; G)G C$C @-H-@H @%H H@ @&@ H)H H-@-@H @%H H@ @'@ H$H C&;-;C C!;%C; G(G CC C-;-C; C!;%;C G)G C$C @-H-@H @#HH@ @&@ H)H @-H-H@ @!H H@ @'@ H$H C-;-;C ;!C;C G(G CC C-;-C; ;%CC; G)G C$C H-@-@H H @%H@ @&@ H)H H-@-H@ @%H @H @'@ H$H ;-C&;C C!;%C; G(G CC C-;-C; ;%C!;C G)G C$C @-H-@H H@#H@ @&@ H)H @-H-H@ H @!@H @'@ H$H H-@-@H H@!@H @(@ HH @-H-@H H@%@H @)@ H$H @-H-H@ @#H@H @&@ H)H H-@-H@ @!H H@ @'@ H$H @-H-H@ @!H@H @(@ HH H-@-@H @%H@H @)@ H$H @-H-@H H@#H@ @&@ H)H @-H-@H H @!@H @'@ H$H H-@-@H @!H@H @(@ HH H-@-@H @%H@H @)@ H$H ;-C-C; C ;%;C G&G C)C C-;-;C ;%C ;C G'G C$C 7-@&@7 7%@!7@ C(C @@ 7-@-@7 @!7%7@ C)C @$@ <-E-E< <#EE< H&H E)E <-E-<E E -E-E> E>#>E >&> E)E E->-E> >!E E> >'> E$E >-5-5> 5!>5> A(A >> 5->->5 >5%>5 A)A >$> F->->F >#FF> >&> F)F F->-F> F >!F> >'> F$F F->-F> >!FF> >(> FF F->->F >%FF> >)> F$F E->-E> >%E >E >&> E)E E->-E> >%E E> >'> E$E 7-@&@7 7%@!@7 C(C @@ @-7-@7 7%@!@7 C)C @$@ >-E-E> >#EE> >&> E)E >-E-E> >!E >E >'> E$E <-E-<E E2>C8C H<HC0C H2H ±CxJ<HK[2@ "]2ÁWƒ‘HA@A@H @2H-H@ @4@ H8H @AHA@H H-@0@H @5@ H1H @=H=H@ H*@-H@ @3@ H'H @=H=@H @2H*@H @5@ H/H @9H9H@ H(@.H@ @/@ H3H @9H9@H H(@.H@ @0@ H,H H1@9@H @.H*@H @1@ H%H H9@9@H @.H*@H @3@ H-H H9@9@H @,H(H@ @/@ H3H @9H9@H @*H(@H @0@ H,H H9@9@H @*H(@H @1@ H%H @9H9@H H(@.@H @3@ H-H ;9C9C; ;.C(C; G/G C3C C9;9C; ;.C(;C G0G C,C C1;9;C ;.C*;C G1G C%C ;9C9C; C*;.C; G3G C-C @9H9H@ @,H(@H @/@ H3H H9@9H@ H(@*@H @0@ H,H @9H9@H @*H(@H @1@ H%H H9@9@H H(@.H@ @3@ H-H @9H9@H @.H(@H @/@ H3H H9@9@H @.H(@H @0@ H,H @9H1H@ H*@.H@ @1@ H%H H9@9@H H*@.H@ @3@ H-H H9@9@H H(@,@H @/@ H3H H9@9H@ @*H(@H @0@ H,H H9@9H@ @*H(H@ @1@ H%H @9H9H@ H(@.@H @3@ H-H @9H9@H @,H(@H @/@ H3H H9@9H@ @*H(@H @0@ H,H H9@9@H @*H(H@ @1@ H%H @9H9@H @.H(@H @3@ H-H H9@9@H @,H(@H @/@ H3H H9@9H@ @*H(H@ @0@ H,H @9H9H@ @*H(@H @1@ H%H @9H9@H H(@.H@ @3@ H-H @9H9H@ @.H(H@ @/@ H3H H9@9@H @.H(H@ @0@ H,H @9H1@H @.H*@H @1@ H%H H9@9H@ H*@.@H @3@ H-H H9@9@H @,H(@H @/@ H3H @9H9@H H(@*H@ @0@ H,H @9H9H@ @*H(H@ @1@ H%H @9H9@H @.H(@H @3@ H-H H9@9H@ H(@.H@ @/@ H3H H9@9@H @.H(H@ @0@ H,H @9H1@H H*@.H@ @1@ H%H @9H9H@ @.H*@H @3@ H-H @9H9@H @,H(@H @/@ H3H @9H9H@ @*H(@H @0@ H,H H9@9H@ @*H(@H @1@ H%H H9@9@H H(@.H@ @3@ H-H H9@9@H H(@.@H @/@ H3H @9H9@H @.H(@H @0@ H,H @9H1@H H*@.H@ @1@ H%H H9@9@H H*@.H@ @3@ H-H A999A9 A(9,9A E/E A3A 99A9A9 A(9*9A E0E A,A A999A9 9*A(9A E1E A%A A9999A 9.A(A9 E3E A-A @9H9H@ @.H(@H @/@ H3H @9H9@H @.H(H@ @0@ H,H ± "@xJ<CÁW±[2HK]2ƒ‘99B99B 9,B(9B E/E B3B 99B9B9 9*B(9B E0E B,B 99B9B9 9*B(9B E1E B%B B9999B B(9.9B E3E B-B C9;9C; ;.C(C; G/G C3C ;9C9;C C(;.C; G0G C,C C1;9C; ;.C*C; G1G C%C C9;9C; C*;.;C G3G C-C @9H9@H H(@,@H @/@ H3H @9H9H@ @*H(H@ @0@ H,H C9;9;C ;*C(;C G1G C%C C9;9C; C(;.;C G3G C-C @9H9@H H(@.@H @/@ H3H @9H9@H H(@.H@ @0@ H,H ;9C1;C C*;.C; G1G C%C ;9C9C; ;.C*;C G3G C-C H9@9@H H(@,@H @/@ H3H @9H9@H @*H(H@ @0@ H,H C9;9;C C(;*;C G1G C%C C9;9;C ;.C(C; G3G C-C @9H9H@ H(@.@H @/@ H3H H9@9H@ @.H(@H @0@ H,H C1;9;C C*;.C; G1G C%C ;9C9C; C*;.;C G3G C-C @9H9@H @,H(@H @/@ H3H @9H9H@ @*H(@H @0@ H,H C9;9;C ;*C(;C G1G C%C ;9C9C; ;.C(;C G3G C-C H9@9H@ @.H(@H @/@ H3H @9H9@H H(@.@H @0@ H,H ;9C1;C ;.C*;C G1G C%C ;9C9C; C*;.;C G3G C-C H9@9@H @,H(H@ @/@ H3H H9@9H@ H(@*H@ @0@ H,H C9;9C; ;*C(C; G1G C%C C9;9;C ;.C(;C G3G C-C @6H6±}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0‘@H±@ÿ/MTrk3°²ÂWÿJAZ2²J<ÿGeneral MIDIÿ2ÿYÿY²x ^[2]2@ÿ @²HK}Cƒ ^[2]2x@HKJ<CÂWõ’<"< B"B HEBBHE EHBBEH > C"C >GC>GC CG>>GC >> C C CG>>GC GC>>GC C"C H"H H@C@CH HC@C@H C!C H!H @HCHC@ @CHC@H >> C"C G>C>GC CG>>CG >> C C CG>CG> >GCCG> C"C H"H @CHHC@ C@HC@H C!C H!H @CH@CH H@CH@C >> C"C GC>>GC >CG>GC >> C C CG>GC> C>GCG> C"C H"H C@HHC@ HC@HC@ C!C H!H HC@@CH CH@HC@ >> C"C CG>G>C >GC>GC >> C C >CGG>C CG>C>G C"C H"H H@CH@C @CH@HC C!C H!H @CH@HC HC@H@C >> C"C GC>C>G >GCCG> >> C C G>C>CG GC>G>C C"C H"H CH@@CH H@CHC@ C!C H!H @HC@CH HC@H@C >> C"C C>GC>G >CGGC> >> C C GC>>CG >CGGC> C"C H"H H@CH@C C@H@HC C!C H!H @CH@HC CH@@CH >> C"C CG>CG> GC>C>G >> C C GC>C>G CG>>CG C"C H"H @HC@CH H@CHC@ C!C H!H @CHHC@ H@CHC@ >> C"C C>GC>G >GCCG> >> C C >GCC>G CG>>GC C"C H"H HC@C@H C@HCH@ C!C H!H H@C@CH @CHCH@ CC H"H H@C@CH C@HH@C CC H H HC@@CH H@CH@C C"C H"H CH@CH@ CH@@HC C!C H!H HC@CH@ @CH@HC CC H"H H@CC@H CH@H@C CC H H CH@CH@ HC@HC@ C"C H"H C@H@CH @CHCH@ C!C H!H H@C@CH CH@C@H CC H"H CH@C@H H@CH@C CC H H @CHCH@ H@CCH@ >"> C"C CG>>GC G>CG>C >!> C!C GC>CG> G>CC>G ;; @"@ @CGG@C @GC@GC ;; @ @ C@G@GC @GCC@G @"@ E"E @EHH@E @EHH@E @!@ E!E H@EEH@ @EHH@E @@ E"E E@HEH@ E@H@HE @@ E E H@EHE@ EH@@EH @"@ E"E H@E@EH @EH@EH @!@ E!E H@EE@H EH@EH@ @@ E"E HE@H@E @EH@EH @@ E E E@HE@H @HEE@H C"C H"H H@CHC@ H@C@HC C!C H!H C@HH@C C@HHC@ CC H"H HC@@CH C@H@HC CC H H HC@H@C HC@CH@ <"< B"B EBHBHE EBHBEH "> C"C CG>C>G >CGG>C >!> C!C C>GC>G CG>>CG >> C"C G>CG>C >GCGC> >> C C >CG>GC CG>>CG @"@ E"E >E@@E> @>EE>@ @!@ E!E >E@@E> >E@>@E 99 >"> >AE>AE AE>>AE 99 > > E>AE>A >EAEA> A"A F"F FA>AF> AF>>FA A!A F!F A>FAF> A>FFA> AA F"F >FA>FA F>AAF> AA F F F>AA>F >AFA>F @"@ E"E @E>>E@ >E@E>@ @!@ E!E >E@@>E @E>@>E ;; @"@ G@CG@C @CG@GC ;; @ @ C@GGC@ CG@C@G @"@ E"E >E@E@> >E@@>E @!@ E!E E>@E>@ @E>@>E @@ E"E @HEH@E H@EEH@ @@ E E H@EE@H @EH@EH 8"8 ="= =DA=AD DA=A=D 8!8 =!= AD=AD= =ADD=A 88 ="= A=DAD= D=AA=D 88 = = DA==DA A=DAD= 8"8 ="= DA=A=D D=ADA= 8!8 =!= AD=AD= =ADD=A 88 ="= AD=DA= DA=AD= 88 = = D=ADA= AD=AD= C"C H"H C@HC@H @CHH@C C!C H!H CH@C@H HC@@CH ÂW²C]2HK[2xJ< ^@ƒ’<*< A*A E$A"H"AHE H A E"HAE <(< A(A A"H%E%AEH A H E!AHE *> C*C G">%C#>GC > C G"CG> >(> C(C C"G%>%C>G C G"> GC> *> C*C C"G$>"C>G G"> C CG> >(> C(C C"G%>%>CG > C G!G>C >!> C*C C$>%G%>GC C > G!G>C >$> C(C C%G">%G>C C>G"G>C C*C H*H C%H#@"@CH C H @"H@C C(C H(H H"C%@%H@C @"C H HC@ *> C*C C">"G$>GC G"C > >CG >(> C(C G%C">%CG> G!> C GC> >!> C*C >%G%C$C>G C > G!CG> >$> C(C G">%C%CG> CG">>CG C*C H*H @"C%H#C@H C H @"CH@ C(C H(H @%H"C%@CH C H @"@CH >!> C*C C%>%G%>GC G">!C GC> >$> C(C >%G%C%GC> >!C!G"GC> C*C H*H @$H"C"C@H @"H C C@H C(C H(H H"C%@%C@H @!H C H@C >!> C*C >%C$G%>CG G!> C C>G >$> C(C G">%C%>GC CG">G>C C*C H*H H"@$C"@CH @"H C HC@ C(C H(H H"C%@%H@C H C @!H@C >!> C*C C$>%G%>CG G!C > CG> >$> C(C >%C%G">GC >CG"CG> C*C H*H @$H"C"@CH C H @"C@H C(C H(H @%H"C%@CH H C @!CH@ C!C H*H H$@%C%@HC H @!C @CH C$C H(H C%@"H%@HC C@"H@HC C*C H*H @"H#C%@CH H @"C HC@ C(C H(H C%@%H"HC@ @"C H H@C C!C H*H H%C%@%C@H @"H C!HC@ C$C H(H H%C%@%CH@ C!H!@"H@C 8*8 =*= ="D"A$=AD = A"D A=D 8(8 =(= ="A%D%D=A = A!D D=A *> C*C C#G">%GC> > G"C >CG >(> C(C C">%G%C>G G"C > C>G >!> C*C G%>%C%C>G C G">!G>C >$> C(C >%G%C%G>C >!G"C!GC> >*> C*C G$>"C">CG G"C > C>G >(> C(C C"G%>%G>C C G!> C>G >!> C*C C$G%>%G>C G!C > >CG >$> C(C >%C%G"C>G C>G"CG> >*> C*C C">"G$>CG > G"C CG> >(> C(C >%G%C"CG> G!> C >CG >!> C*C G%>%C$>GC G!> C >CG >$> C(C >%G"C%GC> >G"CGC> >*> C*C C"G$>">CG C > G"CG> >(> C(C G%C">%>CG G!C > >GC >!> C*C >%G%C$GC> C > G!CG> >$> C(C >%C%G"C>G G"C>C>G >*> C*C G">%C#GC> C G"> GC> >(> C(C C"G%>%GC> C G"> G>C >!> C*C >%G%C%GC> >!C G"CG> >$> C(C >%C%G%GC> G">!C!C>GPC,CPC!@!H$C@HPC+CPH$@!C!@CH @%@ C.C H)C)@)HC@ C#@%H&@HCPH,H @-H-@H @)H*@H H2H C8CH.H C1C²]2x[2 ^@HKCJ<ÂWƒ’C/C H/H @(H&C&H@C C#H#@&HC@ C-C H-H H&C)@)HC@ @%C#H#@CH C#C H,H H&@'C'CH@ H!@#C!@CH C%C H*H @$C'H'@HC @$C!H HC@ C*C H*H C%@"H#@HC C @"H @CH C(C H(H H"@%C%HC@ @"H C CH@ C!C H*H C%H%@%HC@ H C!@"CH@ C$C H(H C%@%H%C@H C!H!@"CH@ C*C H*H @$C"H"H@C @"C H CH@ C(C H(H H"@%C%HC@ H C @!@CH C!C H*H @%H$C%HC@ C @!H @CH C$C H(H C%H%@"C@H C@"HH@C >*> C*C G">%C#>GC C > G">CG >(> C(C C"G%>%CG> > G"C >GC >!> C*C G%>%C%CG> C >!G">GC >$> C(C G%>%C%GC> >!G"C!CG> C*C H*H @$C"H"CH@ @"C H C@H C(C H(H C%@%H"CH@ @!C H HC@ C!C H*H H$@%C%@HC H C @!CH@ C$C H(H H%@"C%H@C C@"HC@H C*C H*H @"H#C%C@H @"H C HC@ C(C H(H @%C%H"@HC H @"C C@H C!C H*H C%@%H%@HC C!@"H @CH C$C H(H @%H%C%@CH C!H!@"@HC C*C H*H H"C"@$H@C @"C H HC@ C(C H(H @%C%H"CH@ @!C H C@H C!C H*H @%C%H$@HC @!H C CH@ C$C H(H @"H%C%H@C @"HC@HC C*C H*H H"@$C"H@C C H @"@CH C(C H(H H"@%C%CH@ @!C H HC@ C!C H*H H$@%C%HC@ @!C H HC@ C$C H(H C%@"H%@HC H@"C@HC C*C H*H C"@$H"CH@ @"C H HC@ C(C H(H H"C%@%H@C @!H C H@C C!C H*H @%C%H$C@H H C @!@HC C$C H(H @"C%H%@CH CH@"@CH C*C H*H @"C%H#CH@ H C @"@CH C(C H(H C%H"@%H@C H @"C @HC C!C H*H @%C%H%@HC C!H @"@HC C$C H(H H%@%C%HC@ @"H!C!CH@ C*C H*H H"@$C"@CH C @"H @CH C(C H(H C%@%H"CH@ C H @!@HC C!C H*H H$@%C%@CH C H @!CH@ C$C H(H @"C%H%H@C CH@"@HC C*C H*H H#C%@"@HC C H @"@HC C(C H(H H"C%@%C@H C @"H H@C C!C H*H H%@%C%@CH @"H C!H@C C$C H(H @%C%H%@HC C!H!@"@HC C*C H*H H"@$C"@HC H @"C C@H C(C H(H C%@%H"H@C @!C H HC@ C!C H*H H$C%@%H@C @!C H HC@ C$C H(H C%@"H%@HC HC@"@CH C*C H*H @"C%H#CH@ @"H C H@C C(C H(H @%H"C%@CH @"C H HC@ C!C H*H H%@%C%C@H @"C!H CH@ C$C H(H C%@%H%H@C H!C!@"CH@ <*< A*A A"H"E$AHE A H E"EAH <(< A(A H%A"E%AEH E!A H HAE *> C*C >%G"C#G>C C > G"CG> >(> C(C >%C"G%C>G > C G"G>C >!> C*C G%>%C%>GC >!C G"GC> >$> C(C G%>%C%>GC C!>!G"C>G C*C H*H @$H"C"@HC H @"C @HC C(C H(H H"@%C%H@C H @!C C@H >!> C*C G%C$>%CG> G!C > >CG >$> C(C C%>%G"C>G >G"C>CG C*C H*H C%@"H#@CH @"H C C@H C(C H(H @%C%H"C@H H @"C C@H >!> C*C C%>%G%>CG >!C G">GC >$> C(C >%G%C%C>G G"C!>!CG> C*C H*H H"C"@$C@H @"H C CH@ C(C H(H C%@%H"H@C @!H C CH@ >!> C*C G%>%C$>GC C G!> C>G >$> C(C C%>%G">CG CG">>CG C*C H*H H#C%@"CH@ @"C H HC@ C(C H(H C%H"@%HC@ C @"H C@H >!> C*C G%>%C%G>C C >!G">CG >$> C(C C%G%>%CG> >!C!G"GC> C*C H*H @$C"H"C@H @"C H HC@ C(C H(H @%C%H"@CH H C @!H@C >!> C*C G%C$>%CG> C > G!GC> >$> C(C C%G">%GC> >G"CCG> C*C H*H @"H#C%H@C @"C H @HC C(C H(H C%H"@%HC@ H @"C C@H >!> C*C C%>%G%G>C >!C G"C>G >$> C(C >%G%C%>CG C!G">!>CG C*C H*H H"@$C"H@C C @"H CH@ C(C H(H H"C%@%CH@ C H @!@CH >!> C*C >%G%C$G>C C G!> >GC >$> C(C >%C%G"C>G >G"CC>G C"²}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0’C²@ÿ/MTrk>æ³Ã'ÿJAZ2³[AÿGeneral MIDIÿ3ÿYÿY³x @HK]A@ÿ @³J<}Cƒ @[A]A@xHKJ<CÃ'õ³@“*G **:³@@ “**G³@@“* ³@“*:³@“* ³@@“*G *³@@“*: **G³@@“* ³@@“*:* ³@“+G³@ “++:³@@ “+³@“+G³@“+ ³@“+:³@“+ ³@“+G³@ “+³@@“+: ++G³@@“+ ³@“+:³@“+ $G³@@ “$³@“$:³@ “$³@“0G³@“0 0:³@@“0 ³@“$G³@ “$³@@“$: $³@@“0G0 ³@“0:³@“0 ³@“+G³@ “++:³@@ “+³@“+G³@“+ ³@“+:³@“+ ³@“+G³@ “++:³@@ “+³@“+G³@“+ +:³@@“+ $G³@@ “$³@“$:³@ “$0G³@@“0 ³@@“0:0 ³@@“$G $³@@“$: $³@“0G³@“0 0:³@@“0 +G³@@ “+³@@“+: +³@“+G³@“+ ³@“+:³@“+ ³@@“+G ++:³@@ “++G³@@“+ ³@“+:³@“+ ³@“$G³@ “$$:³@@ “$0G³@@“0 ³@“0:³@“0 $G³@@ “$³@@“$: $0G³@@“0 0:³@@“0 +G³@@ “+³@@“+: +³@@“+G+ ³@@“+:+ +G³@@ “+³@“+:³@ “++G³@@“+ ³@@“+:+ ³@@“$G $$:³@@ “$³@@“0G0 ³@“0:³@“0 $G³@@ “$$:³@@ “$³@“0G³@“0 ³@@“0:0 +G³@@ “++:³@@ “+³@“+G³@“+ ³@“+:³@“+ +G³@@ “+³@“+:³@ “+³@“+G³@“+ ³@“+:³@“+ ³@“$G³@ “$³@@“$: $0G³@@“0 ³@@“0:0 ³@@“$G $³@“$:³@ “$0G³@@“0 ³@@“0:0 ³@“+G³@ “+³@@“+: ++G³@@“+ ³@“+:³@“+ ³@@“+G +³@“+:³@ “+³@“+G³@“+ ³@“+:³@“+ ³@“$G³@ “$³@@“$: $³@“0G³@“0 0:³@@“0 ³@@“$G $³@“$:³@ “$³@“0G³@“0 ³@@“0:0 +G³@@ “+³@“+:³@ “+³@“+G³@“+ +:³@@“+ ³@@“+G ++:³@@ “+³@@“+G+ +:³@@“+ ³@@“$G $$:³@@ “$0G³@@“0 0:³@@“0 ³@“$G³@ “$³@“$:³@ “$0G³@@“0 ³@@“0:0 ³@@“+G +³@“+:³@ “+³@“+G³@“+ ³@@“+:+ +G³@@ “+³@“+:³@ “+³@@“+G+ ³@@“+:+ $G³@@ “$$:³@@ “$0G³@@“0 0:³@@“0 $G³@@ “$³@“$:³@ “$³@“0G³@“0 ³@@“0:0 $G³@@ “$³@“$:³@ “$³@@“0G0 ³@@“0:0 ³@“$G³@ “$³@@“$: $0G³@@“0 0:³@@“0 ³@“$G³@ “$³@@“$: $0G³@@“0 ³@“0:³@“0 ³@@“$G $$:³@@ “$³@“0G³@“0 0<³@@“0 ³@@“$G $³@@“$; $0G³@@“0 ³@“0:³@“0 ³@“$G³@ “$$:³@@ “$³@@“0G0 ³@@“0:0 ³@“$G³@ “$$:³@@ “$0G³@@“0 0:³@@“0 $G³@@ “$³@@“$: $³@“0G³@“0 ³@@“0:0 $G³@@ “$³@@“$: $0G³@@“0 ³@“0:³@“0 $G³@@ “$³@@“$: $³@“0G³@“0 ³@@“0:0 +G³@@ “+³@@“+: +³@@“+G+ +:³@@“+ ³@“+G³@ “+³@“+:³@ “+³@@“+G+ ³@“+:³@“+ (G³@@ “(³@“(:³@ “((G³@@“( (:³@@“( (G³@@ “(³@@“(: ((G³@@“( ³@“(:³@“( ³@@“!G !!:³@@ “!³@@“-G- -:³@@“- ³@@“!G !³@@“!: !-G³@@“- ³@@“-:- !G³@@ “!³@@“!: !-G³@@“- ³@“-:³@“- !G³@@ “!³@@“!: !³@@“-G- ³@@“-:- !G³@@ “!!:³@@ “!-G³@@“- ³@@“-:- ³@@“!G !³@“!:³@ “!³@@“-G- ³@@“-:- ³@@“!G !!:³@@ “!³@@“-G- ³@“-:³@“- ³@“!G³@ “!³@@“!: !³@@“-G- ³@“-:³@“- ³@@“$G $³@“$:³@ “$³@@“0G0 ³@“0:³@“0 ³@@“$G $³@@“$: $0G³@@“0 0:³@@“0 ³@“$G³@ “$$:³@@ “$³@“0G³@“0 ³@“0:³@“0 ³@@“$G $$:³@@ “$³@“0G³@“0 0:³@@“0 *G³@@ “*³@“*:³@ “**G³@@“* ³@@“*:* *G³@@ “*³@“*:³@ “**G³@@“* ³@@“*:* ³@@“*G *³@“*:³@ “*³@“*G³@“* *:³@@“* ³@@“*G *³@@“*: *³@@“*G* ³@@“*:* ³@@“+G +³@“+:³@ “+³@@“+G+ +:³@@“+ +G³@@ “+³@“+:³@ “++G³@@“+ +:³@@“+ ³@“+G³@ “+³@“+:³@ “+³@@“+G+ +:³@@“+ ³@“+G³@ “+³@@“+: +³@“+G³@“+ ³@@“+:+ ³@“!G³@ “!³@“!:³@ “!³@@“-G- ³@“-:³@“- !G³@@ “!³@@“!: !-G³@@“- ³@“-<³@“- &G³@@ “&³@@“&; &&G³@@“& &:³@@“& ³@@“&G &³@@“&: &&G³@@“& &:³@@“& ³@@“"G "³@@“": "³@@“.G. ³@“.:³@“. ³@@“"G "³@“":³@ “"³@@“.G. .:³@@“. ³@@“"G "³@@“": "³@“.G³@“. .:³@@“. "G³@@ “"":³@@ “".G³@@“. ³@“.:³@“. !G³@@ “!³@@“!: !³@@“-G- -:³@@“- ³@@“!G !!:³@@ “!³@“-G³@“- ³@“-:³@“- ³@@“(G ((:³@@ “(³@@“(G( (:³@@“( ³@“(G³@ “(³@@“(: ((G³@@“( ³@“(:³@“( ³@@“!G !!:³@@ “!³@“-G³@“- -:³@@“- ³@@“!G !!:³@@ “!³@“-G³@“- ³@@“-:- ³@“!G³@ “!³@@“!: !³@“-G³@“- ³@@“-:- !G³@@ “!³@@“!: !³@“-G³@“- ³@@“-:- ³@“%G³@ “%³@“%:³@ “%³@“%G³@“% ³@“%:³@“% %G³@@ “%³@@“%: %³@@“%G% %:³@@“% ³@@“%G %%:³@@ “%³@“%G³@“% %:³@@“% %G³@@ “%³@“%:³@ “%%G³@@“% ³@“%:³@“% %G³@@ “%%:³@@ “%³@@“%G% ³@“%:³@“% ³@@“%G %³@@“%: %³@“%G³@“% %:³@@“% ³@“%G³@ “%³@@“%: %³@“%G³@“% ³@“%:³@“% %G³@@ “%³@“%:³@ “%³@@“%G% ³@@“%:% $G³@@ “$³@“$:³@ “$0G³@@“0 ³@“0:³@“0 $G³@@ “$³@“$:³@ “$³@@“0G0 ³@@“0:0 ³@J<[AHKx]AÃ'³C @ƒ@“)W )³@@“)F ))W³@@“) )F³@@“) ³@“)W³@ “)³@“)F³@ “)³@@“)W) ³@“)F³@“) ³@“)W³@ “))F³@@ “))W³@@“) ³@“)F³@“) ³@“)W³@ “)³@“)F³@ “)³@@“)W) ³@@“)F) +W³@@ “+³@@“+F ++W³@@“+ ³@@“+F+ ³@@“+W ++F³@@ “++W³@@“+ ³@“+F³@“+ )W³@@ “))F³@@ “)³@“)W³@“) ³@@“)F) )W³@@ “)³@@“)F )³@@“)W) ³@“)F³@“) ³@“+W³@ “++F³@@ “++W³@@“+ +F³@@“+ ³@“+W³@ “++F³@@ “+³@“+W³@“+ +F³@@“+ ³@@“+W +³@@“+F ++W³@@“+ +F³@@“+ ³@@“+W +³@@“+F +³@“+W³@“+ ³@“+F³@“+ $W³@@ “$$F³@@ “$³@“0W³@“0 ³@@“0F0 $W³@@ “$³@@“$F $0W³@@“0 0F³@@“0 ³@“)W³@ “)³@“)F³@ “)³@@“)W) ³@“)F³@“) ³@“)W³@ “)³@@“)F ))W³@@“) ³@“)F³@“) ³@“+W³@ “+³@@“+F +³@“+W³@“+ ³@@“+F+ +W³@@ “+³@“+F³@ “+³@“+W³@“+ +F³@@“+ ³@@“+W +³@@“+F +³@“+W³@“+ +F³@@“+ +W³@@ “+³@@“+F +³@@“+W+ ³@“+F³@“+ $W³@@ “$³@“$F³@ “$0W³@@“0 ³@@“0F0 ³@“$W³@ “$³@“$F³@ “$³@“0W³@“0 ³@“0F³@“0 ³@@“+W ++F³@@ “+³@@“+W+ ³@“+F³@“+ ³@@“+W +³@“+F³@ “+³@@“+W+ ³@“+F³@“+ ³@“$W³@ “$$F³@@ “$³@“0W³@“0 0F³@@“0 ³@@“$W $$F³@@ “$0W³@@“0 ³@“0F³@“0 ³@@“+W +³@“+F³@ “++W³@@“+ ³@“+F³@“+ +W³@@ “+³@@“+F +³@@“+W+ ³@@“+F+ $W³@@ “$³@@“$F $³@@“0W0 ³@@“0F0 $W³@@ “$$F³@@ “$³@@“0W0 ³@@“0I0 +W³@@ “++H³@@ “+³@@“+W+ ³@@“+F+ +W³@@ “++F³@@ “+³@“+W³@“+ ³@@“+F+ ³@@“$W $³@@“$F $³@@“0W0 ³@@“0F0 $W³@@ “$³@“$F³@ “$³@“0W³@“0 ³@@“0F0 ³@“$W³@ “$³@@“$F $³@@“0W0 0F³@@“0 ³@@“$W $³@@“$F $³@“0W³@“0 ³@@“0F0 $W³@@ “$$F³@@ “$³@@“0W0 0F³@@“0 ³@“$W³@ “$³@“$F³@ “$0W³@@“0 0F³@@“0 $W³@@ “$³@@“$F $0W³@@“0 ³@“0F³@“0 ³@“$W³@ “$$F³@@ “$³@“0W³@“0 ³@@“0F0 ³@@“%W %%F³@@ “%³@@“%W% %F³@@“% ³@“%W³@ “%³@“%F³@ “%%W³@@“% ³@“%F³@“% )W³@@ “))F³@@ “)³@“)W³@“) ³@“)F³@“) )W³@@ “)³@@“)F )³@“)W³@“) )F³@@“) ³@@“$W $$F³@@ “$$W³@@“$ ³@@“$F$ ³@@“$W $$F³@@ “$³@“$W³@“$ ³@“$F³@“$ ³@@“!W !³@@“!F !-W³@@“- ³@“-F³@“- !W³@@ “!³@“!F³@ “!³@@“-W- -F³@@“- ³@“)W³@ “)³@“)F³@ “)³@@“)W) )F³@@“) ³@“)W³@ “)³@“)F³@ “)³@@“)W) )F³@@“) )W³@@ “)³@“)F³@ “)³@@“)W) )F³@@“) ³@“)W³@ “))F³@@ “)³@“)W³@“) ³@“)F³@“) ³@“+W³@ “+³@“+F³@ “++W³@@“+ ³@“+F³@“+ +W³@@ “+³@@“+F +³@@“+W+ ³@“+F³@“+ +W³@@ “+³@“+F³@ “+³@“+W³@“+ ³@“+F³@“+ +W³@@ “+³@“+F³@ “+³@“+W³@“+ ³@“+F³@“+ ³@“+W³@ “++F³@@ “++W³@@“+ ³@@“+F+ +W³@@ “+³@“+F³@ “+³@“+W³@“+ ³@“+F³@“+ ³@“+W³@ “++F³@@ “++W³@@“+ ³@“+F³@“+ ³@@“+W ++F³@@ “+³@@“+W+ +F³@@“+ +W³@@ “++F³@@ “+³@“+W³@“+ +F³@@“+ +W³@@ “+³@“+F³@ “+³@“+W³@“+ ³@“+I³@“+ +W³@@ “+³@@“+H +³@@“+W+ ³@@“+F+ +W³@@ “++F³@@ “++W³@@“+ +F³@@“+ ³@“+W³@ “+³@@“+F +³@@“+W+ ³@@“+F+ ³@@“+W ++F³@@ “+³@“+W³@“+ ³@@“+F+ +W³@@ “++F³@@ “+³@“+W³@“+ ³@“+F³@“+ ³@“+W³@ “+³@“+F³@ “+³@@“+W+ ³@“+F³@“+ ³@@“+W +³@@“+F +³@“+W³@“+ +F³@@“+ ³@@“+W ++F³@@ “+³@“+W³@“+ ³@@“+F+ ³@@“+W +³@@“+F +³@@“+W+ ³@@“+F+ +W³@@ “+³@“+F³@ “++W³@@“+ +F³@@“+ ³@“$\³@ “$³@“$J³@ “$<\³@@“< #D,- ,2#a-?-#, 1J#g+@8DF>F#18+ F?+@#k+#F C$8.8#Q88C# ,$, C".2F+.CF 8.F+F8 #Q84&>,$D(,&8#D 8/,$,8 F+.2.F F+C%FC 8,$82#Q8,#8 C%,$,C F+.2.F 8/CF+C8F &>,$D'#Q#D,& ,$, F+8.D&.2D.F8 F+F ,$8#QD8.8#,D8 ,$, C".28%F+FC8. F+8.F8 #Q84,$&>C$C#&,8 8/,$,8 D$.2F+FD. C F+CF 8#Q82,$K-88,K# K+C$,$CK, K+.2F+.FK K+DF+8/K8FD #Q,$C$K+&>&#K,C ,$K+#D,K# #GF+K+.28.F8.K# F+&>#IK+F&#K #Q8.8C$88C# ,$, F+C".2.FC 8.F+F8 84#Q,$&>D(D#8&, ,$8/,8 .2F+F. C%F+FC ,$#Q88288,# C%,$C, F+.2.F 8/CF+C8F ,$D'&>#Q#&D, ,$, .2D&F+8..FD8 F+F 8,$#QD8.8D#8, ,$, C"F+8%.2F8.C F+8.8F ,$&>#Q84C$&#,C8 ,$8/,8 D$F+.2.DF C F+CF 8#Q82,$K-88,K# K+C$,$CK, K+.2F+.FK DF+K+8/8KDF &>,$#QK+C$K&#C, ,$K+#DK#, F+K+8..2#GF8#.K &>F+#IK+KF&# 8.8C$#Q88C# ,$, .2C"F+.CF F+8.8F ,$#QD(84&>D8#,& 8/,$,8 F+.2.F C%F+CF #Q882,$8,#8 C%,$,C .2F+F. F+8/C8FC &>,$D'#Q#D,& ,$, 8..2F+D&FD8. F+F 88.D,$#Q88D,# ,$, .28%C"F+F.C8 8.F+8F ,$C$#Q84&>&,8#C 8/,$,8 F+D$.2.FD F+C FC ,$#Q82K-888K,# K+C$,$K,C F+.2K+K.F K+DF+8/K8FD C$#Q&>,$K+KC,#& ,$#DK+,#K #GF+.2K+8.F8K.# F+&>K+#IF&K# #Q88.C$8#8C ,$, F+.2C"CF. F+8.8F #QD(&>84,$,D#8& 8/,$,8 .2F+.F F+C%FC 82,$#Q88,8# C%,$C, .2F+.F C8/F+C8F #QD'&>,$,#D& ,$, F+.2D&8..DF8 F+F #Q,$8D8#,D ,$, C$8'.5F.8C.F &B82F/F8& C(8:,(#Y,C#8 86,)8, &DF3.<D+F.&D C'F4FC 8K78?#`,-8K8,# K8,.C.KC, #^K9F9.B#.KF 8?&OD'K:F:F&K8D K<,1#gC2#,KC ,2&?K=K&, .IF>8DK?&Q8F.K& K@F?FK7M8.C$8#Q78C8# ,$, .2F+C"F.C F+8.8F D(&>,$84#Q,&D#8 8/,$,8 F+.2F. C%F+CF ,$#Q88288#, C%,$,C F+.2.F 8/F+CF8C &>D'#Q,$,#D& ,$, F+.2D&8.D8F. F+F 8#QD8.,$8#D8, ,$, .2F+C"8%8.CF 8.F+8F ,$C$#Q&>848,&#C ,$8/8, .2F+D$D.F C F+CF ,$#QK-8288K8,# ,$C$K+,KC F+K+.2.KF 8/K+F+D8DFK C$K+&>,$#Q#C,K& K+,$#DK,# K+8..2#GF+8F#.K K+&>F+#IFK&# 88.C$#Q88C# ,$, C".2F+CF. 8.F+8F D(#Q&>,$848#D,& 8/,$,8 F+.2F. F+C%FC #Q82,$888#, ,$C%,C .2F+F. F+8/C8FC ,$#QD'&>&D#, ,$, D&8.F+.2DF8. F+F #Q8.,$D88D,#8 ,$, C"F+8%.2F8.C 8.F+F8 C$&>#Q,$84&#C8, ,$8/,8 D$.2F+FD. C F+CF K-8#Q82,$8#8K, ,$C$K+K,C .2F+K+K.F D8/F+K+KFD8 C$#Q&>K+,$KC&,# ,$#DK+#K, .28.K+F+#G.K#F8 K+#I&>F+#K&F #Q8.C$88C8# ,$, F+C".2FC. 8.F+F8 ,$D(84#Q&>8#D,& ,$8/8, .2F+F. C%F+CF #Q82,$888#, C%,$,C .2F+F. F+C8/CF8 &>D'#Q,$,#D& ,$, D&8.F+.2F.D8 F+F D#Q8.,$88#D,8 ,$, F+.28%C"CF8. F+8.F8 C$84#Q&>,$,C&#8 ,$8/8, F+D$.2.FD C F+CF K-#Q82,$888,K# ,$C$K+,KC .2F+K+KF. 8/F+K+D8DKF K+&>#QC$,$,KC&# ,$K+#D,K# K+#GF+.28.#8.FK #IF+K+&>#FK& C$8#Q8.8#8C ,$, .2F+C"C.F F+8.8F 84,$D(#Q&>&,8#D 8/,$,8 .2F+.F F+C%FC #Q82,$888#, C%,$C, F+.2F. 8/CF+8CF #Q,$D'&>&#,D ,$, 8.F+D&.2FD8. F+F ,$#Q8D8,#D ,$, .5C$8'F.C.8F &BF/828F& #YC(8:,(8#,C 86,)8, F3&D.<D+&.FD C'F4FC ,-K7#`88?8#,8K ,.C.K8,KC .BK9#^F9.FK# F:D'K:8?&O&D8FK C2,1K<#gK,C# ,2K=&?&K, .IF>8DK?&Q8F.K& K@F?FK7M#QC$88.78C#8 ,$, .2F+C"F.C 8.F+F8 D(#Q84&>,$&8#D, ,$8/8, F+.2.F C%F+CF 82,$8#Q8,8# ,$C%C, F+.2.F F+8/C8FC &>D'#Q,$,#D& ,$, F+8.D&.2D.F8 F+F 8.#QD,$88#8,D ,$, C".28%F+FC8. 8.F+8F &>,$#QC$848&C#, 8/,$,8 D$.2F+FD. F+C FC K-,$882#Q8#K8, ,$K+C$,CK .2F+K+F.K 8/F+K+D8DKF K+#Q&>,$C$CK,#& #DK+,$#K, F+8.#G.2K+8K.#F #IF+&>K+KF#& #U882C&8#8C #G,&,# C$F.#J.5.F#C 82#MF.8F# D+#U&A949D&# ,&82,8 .5F..F C'F.FC 79#Y889,(0780#,87 05,(C),0C /5.9F0.F/ /585C F0F8/C D,18#Y-5#-1D ,(-4-, +4.984D*F08+.DF F0+3F+1*)D818)‚p,*¹x™#\¹@]C™8<¹ @[HK™7<80:¹J<™807,#8 07C,,*C0, /8.<F3/.F 88/8F3C"/C8F -7#\D/1;-#1D ,*-7-, 88D-.<+7F3D8.+F +6F3+F1-848#YC)818#C ,(, C&.9F0.FC 84F08F D-&D8:,(#YD&#8, ,(858, .9F0.F C)F0FC #U885,&8,8# ,&C'C, F..5.F C82F.CF8 &A#UD*,&D#,& ,&, 82D(F..58.FD F.F 8.8D,$#Q8,D8# ,$, F+.28%C"FC.8 F+8.F8 84C$#Q,$&>,&C8# 8/,$,8 F+.2D$.FD F+C CF 828,$#QK-88#K, K+,$C$C,K F+.2K+.KF F+8/DK+KFD8 ,$#Q&>C$K+K,&C# K+#D,$,#K #GF+8.K+.2.F8K# K+F+#I&>&KF# C$8#Q8.88C# ,$, .2F+C"C.F 8.F+F8 #QD(&>84,$D#&8, ,$8/,8 F+.2.F C%F+FC 8,$#Q828#,8 ,$C%,C .2F+F. CF+8/FC8 ,$#QD'&>,D#& ,$, D&F+.28.FD.8 F+F ,$D#Q88.8#8,D ,$, C"F+.28%C.8F 8.F+8F C$,$#Q&>84,C&8# 8/,$,8 .2D$F+DF. C F+FC #QK-882,$8K8,# K+C$,$,KC .2K+F+K.F F+8/K+DKDF8 ,$K+C$&>#QCK#&, #DK+,$#,K 8.F+K+#G.28.F#K #IK+F+&>KF#& 8C$8.#Q8#8C ,$, F+C".2.FC F+8.F8 D(84#Q&>,$#&,D8 8/,$,8 F+.2F. F+C%CF 82,$#Q88#,8 C%,$,C F+.2.F 8/F+C8CF ,$#Q&>D'D,&# ,$, 8.D&.2F+.DF8 F+F 8.8D,$#Q88#,D ,$, 8%F+.2C".FC8 8.F+8F ,$C$&>84#Q8#C,& 8/,$,8 F+.2D$.FD F+C CF #QK-828,$8#K,8 C$,$K+,CK F+K+.2F.K F+8/K+DKF8D &>C$#QK+,$#,KC& #DK+,$#K, #G.28.F+K+K8#F. K+&>F+#IF#K& #QC$88.88#C ,$, F+.2C"CF. 8.F+F8 84#QD(&>,$8,D#& ,$8/8, .2F+.F C%F+FC 828,$#Q8,#8 ,$C%,C .2F+.F 8/CF+CF8 ,$D'#Q&>D,#& ,$, 8.F+D&.2DF.8 F+F D8,$#Q8,D# ,$, C$F.8'.58.FC &B82F/8F& #Y8:,(C(8,C# 86,)8, D+&D.<F3&.FD F4C'FC 8?#`K78,-88,K# ,.K8C.,CK .B#^F9K9#F.K F:&OD'K:8?F8D&K C2#gK<,1C,#K &?,2K=K&, .IK?&QF>8DK.&F8 K@F?FK7M8.C$8#Q78#C8 ,$, F+.2C".FC 8.F+F8 84,$D(#Q&>8,D&# 8/,$8, .2F+F. F+C%CF ,$#Q88288,# C%,$,C .2F+.F F+C8/F8C &>D'#Q,$#D&, ,$, F+.2D&8..FD8 F+F ,$8.8D#Q8#D,8 ,$, .2F+C"8%.C8F F+8.F8 #Q84C$,$&>&C8,# ,$8/8, .2F+D$.FD F+C CF #QK-,$8288#8K, K+,$C$CK, F+K+.2KF. F+8/K+DKDF8 ,$K+&>#QC$&KC#, K+#D,$K,# F+.28.#GK+KF8#. &>#IF+K+FK&# C$#Q88.88C# ,$, C".2F+FC. 8.F+F8 84,$&>D(#Q&D8,# 8/,$,8 F+.2F. C%F+CF ,$8#Q828#,8 C%,$C, .2F+.F F+C8/F8C ,$#QD'&>D#,& ,$, D&.28.F+.D8F F+F 8D#Q8.,$88,#D ,$, F+C"8%.2F8.C F+8.8F 84C$#Q,$&>C#&,8 8/,$,8 F+D$.2F.D C F+FC ,$K-828#Q8#8K, K+,$C$CK, K+.2F+.KF K+F+D8/D8KF #QC$K+,$&>KC&,# ,$#DK+,K# #G8.F+.2K+#F.K8 F+&>K+#I#FK& #Q8.8C$88#C ,$, F+C".2FC. F+8.8F 84,$D(#Q&>D&8#, 8/,$,8 .2F+F. C%F+CF ,$882#Q8#,8 ,$C%C, F+.2.F C8/F+F8C D'#Q&>,$,&#D ,$, D&.28.F+.8DF F+F #Q,$D8.88,8#D ,$, C"F+8%.2.F8C 8.F+F8 C$&>,$#Q84,8&C# ,$8/8, D$F+.2.DF F+C FC K-,$828#Q8#,8K K+,$C$K,C .2K+F+F.K 8/DK+F+8DFK K+#Q,$&>C$,#C&K #D,$K+#K, .2F+8.#GK+8.F#K K+&>#IF+FK#& #QC$8.88C#8 ,$, F+C".2FC. F+8.F8 ,$D(&>84#Q8D#&, 8/,$8, .2F+F. F+C%FC #Q828,$8#,8 C%,$C, .2F+.F 8/CF+C8F &>#Q,$D',D#& ,$, 8.D&.2F+F8D. F+F #Q8K+,$D8K#,D K,,$K, .5F.C$K.K.FC F/K/FK #Y8:C(,(&DK1,C#8&K ,)86K28K, D+F3K4.<DF.K K5C'F4FCK 8?8#`-;¹C[@]x™1<¹J< @HK™,-881,-# /:#Z,.C.#C,/ .BF9/<#`.#F/ D'-=#dF:8?D-#8F ->,1D3#g-#D, -?#a,2#,- 1J+@#g8DF>8F+#1 #k+@F?#F+ 8.8#QC$8#C8 ,$, .2F+C"FC. 8.F+F8 84,$D(#Q&>#,8D& ,$8/,8 F+.2F. F+C%CF #Q,$82888#, C%,$C, F+.2F. F+8/CF8C ,$&>#QD',&#D ,$, D&8.F+.28FD. F+F D#Q8.8,$8#,D8 ,$, F+C".28%.FC8 8.F+8F &>84#Q,$C$,#&8C 8/,$8, .2F+D$F.D F+C FC 82,$8K-#Q8K#,8 ,$C$K+K,C F+.2K+KF. K+F+8/DKF8D ,$#Q&>K+C$C,K&# ,$#DK+,#K .28.#GK+F+8.KF# #IK+&>F+&#KF #QC$88.88#C ,$, .2C"F+CF. F+8.8F #Q&>84,$D(,&#8D ,$8/,8 F+.2F. C%F+FC 8,$#Q828#8, ,$C%,C F+.2F. C8/F+C8F D'#Q&>,$D#&, ,$, .2F+8.D&F8.D F+F 8.D,$8#Q8D#8, ,$, 8%.2C"F+C8.F F+8.F8 84#Q&>C$,$C&8#, ,$8/,8 F+D$.2DF. F+C FC 82#Q8K-,$8K,#8 K+,$C$CK, K+.2F+FK. K+DF+8/KDF8 C$#Q&>K+,$,CK&# #D,$K+#,K F+#GK+.28.#F.8K &>K+F+#IF&K# #QC$88.88#C ,$, F+C".2C.F 8.F+8F 84D(,$#Q&>D,#8& ,$8/,8 F+.2F. F+C%CF #Q8,$828#,8 C%,$C, F+.2F. CF+8/FC8 #Q&>,$D'#D&, ,$, F+D&8..2DF8. F+F 8,$K+#QD8,#DK K,,$K, K.C$F..5.CKF F/K/KF #Y&D8:K1,(C(&KC8,# K2,)86,8K .<F3K4D+.DFK K5F4C'FCK 8?1<#`8,--;8#8-,1 /:C.,.#ZC#/, #`.BF9/</#.F F:8?#d-=D'DF-8# #g->,1D3D,#- ,2-?#a-,# +@#g8DF>1J1F#8+ +@#kF?+#F C$8.#Q888#C ,$, .2C"F+.FC F+8.8F 84#QD(&>,$8,#&D ,$8/8, .2F+.F C%F+FC #Q82,$88,#8 ,$C%C, .2F+.F 8/CF+8FC ,$&>#QD'&D#, ,$, .2D&F+8..DF8 F+F #Q88.D,$8,8D# ,$, .2C"8%F+CF8. F+8.F8 #Q&>,$C$84C#,8& ,$8/,8 D$F+.2D.F F+C CF #QK-82,$88,#K8 K+,$C$C,K K+.2F+F.K K+DF+8/KD8F ,$&>C$#QK+,C&#K K+#D,$K#, #G.28.K+F+.K8#F F+#IK+&>#FK& 8.#Q8C$8#8C ,$, C"F+.2CF. F+8.F8 D(#Q84&>,$,#D&8 8/,$8, .2F+F. C%F+CF ,$#Q8828#,8 C%,$,C F+.2F. F+C8/FC8 #QD'&>,$,D#& ,$, .28.D&F+.8FD F+F D.K.#.,.†K$D$,$#$9K#D,†K#,9Dÿ/MTrkcµÅ1ÿJAZ2µ]ÿGeneral MIDIÿPart-01ÿYÿYµx [@}@HKJ<C}•4ÿ @ƒµxƒsƒn‚p•24µ}ƒ•2µ}•2ƒ20µ}ƒx‚p•4µ}•0ƒ2µ}•4ƒ42µ}ƒ}•42ƒµ}•42ƒµ}•24ƒ24µ}ƒx‚p•O4µ}ƒx‚p•Iµ}•OƒMµ}•Iƒµ}•M@ƒµ}•@@ƒµ}•9@ƒµx‚p•Oµ}•9ƒµx‚p}•IOƒIMµ}ƒ•@Mµ}ƒ•@µ}•@ƒµ}•@9ƒµx‚p}•C9ƒµxƒsƒnƒiƒd‚p}•GCƒµx‚p}•BGƒBAµ}ƒ•4µ}•Aƒ2µ}•4ƒµ}•42ƒµ}•24ƒ24µ}ƒ•24µ}ƒ}•42ƒ24µ}ƒ•4µ}•2ƒ42µ}ƒ•42µ}ƒ}•24ƒ4µ}•2ƒµ}•24ƒ24µ}ƒx‚p•O4µ}ƒxƒsƒn‚p•Gµ}•OƒGGµ}ƒ}•LGƒLµ}•LƒEµ}•Lƒµx‚p•EOµ}ƒx‚p•ONµ}ƒx‚p}•VNƒµx‚p•Vµ}•9ƒ99µ}ƒ•9:µ}ƒx‚p•:µ}•9ƒ;µ}•9ƒ;µ}•@ƒµ}•@@ƒµ}•@=ƒµxƒs‚p•=µ}•=ƒC=µ}ƒx‚p•C9µ}ƒx‚p•Gµ}•9ƒµ}•HGƒµ}•GHƒµ}•GGƒLµ}•Gƒµ}•LMƒCµ}•MƒCCµ}ƒ•C4µ}ƒ•42µ}ƒ•2µ}•4ƒ42µ}ƒ•24µ}ƒ•24µ}ƒ}•24ƒµx‚p•O4µ}ƒx‚p}•IOƒµ}•IMƒM@µ}ƒ•@@µ}ƒ•@µ}•9ƒµx‚p•Cµ}•9ƒµxƒsƒnƒiƒd‚p•GCµ}ƒxƒs‚p•GGµ}ƒ•Hµ}•Gƒµxƒsƒnƒiƒdƒ_ƒZ‚p•Xµ}•Hƒµx‚p•VXµ}ƒ}•VVƒXµ}•Vƒµxƒsƒnƒiƒdƒ_ƒZ‚p•Xµ}•Oƒµxƒsƒnƒiƒdƒ_ƒZ‚p}•OLƒµxƒsƒn‚p•Qµ}•Lƒµx‚p•Q[µ}ƒx‚p•Z[µ}ƒx‚p}•Zbƒµ}•bbƒµ}•4bƒµ}•24ƒ42µ}ƒ}•24ƒµ}•42ƒµ}•24ƒ2µ}•4ƒµ}•24ƒ2µ}•4ƒµ}•24ƒµ}•42ƒ42µ}ƒ•2µ}•4ƒµ}•24ƒµ}•<2µ|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0•<ÿ/MTrko¶Æ1ÿJAZ2–4ÿGeneral MIDIÿPart-02ÿYÿY¶x h[@]@HKJ<}}ÿ @¶Cƒxƒsƒn‚p–24¶}ƒ}–22ƒ20¶}ƒx‚p}–20ƒ¶}–22ƒ2¶}–2ƒ22¶}ƒ–2¶}–2ƒ2¶}–2ƒ¶}–42ƒ¶x‚p–O4¶}ƒx‚p–M¶}–Oƒ¶}–MMƒ@¶}–Mƒ>¶}–@@<>@¶}–9<ƒ¶x‚p}–9Oƒ¶x‚p}–MOƒ¶}–MMƒM@¶}ƒ–>@¶}@–><@9¶}–<ƒ`<¶}–9@<>`¶}–C>ƒ¶xƒsƒnƒi…–C¶}–E`G¶}–Eƒ`¶}–GE@CE`¶}–ACƒAA¶}ƒ–2A¶}ƒ}–22ƒ2¶}–2ƒ22¶}ƒ}–22ƒ2¶}–2ƒ¶}–22ƒ¶}–22ƒ2¶}–2ƒ2¶}–2ƒ2¶}–2ƒ22¶}ƒ–2¶}–2ƒ22¶}ƒ–4¶}–2ƒ¶x‚p–4O¶}ƒxƒs‚p}–MO@LM`LJ`JG¶}ƒ–GG¶}@–GH`JH`L¶}–Jƒ¶}–JL@JH@HE¶}ƒ`}–HE@JH`¶}–JOƒ¶x‚p–N¶}–O„@N¶}–Q@¶}–VQƒ¶x‚p}–9Vƒ9¶}–9ƒ¶}–9:ƒ9:¶}ƒ–;¶}–9ƒ¶}–;;@<;`><`>@¶}ƒ–@@¶}ƒ}–=@ƒ¶xƒs‚p–==¶}@–=>`>@`¶}–C@ƒC¶}–A`A@`@>`<>`<9¶}ƒx‚p–H¶}–9ƒHH¶}ƒ}–GHƒG¶}–G@HG`JH`¶}–MJƒM¶}–M`JM`HJ`GH`C¶}–GƒC¶}–Cƒ2¶}–Cƒ22¶}ƒ}–22ƒ2¶}–2ƒ22¶}ƒ–22¶}ƒ–24¶}ƒx‚p–4O¶}ƒx‚p–M¶}–Oƒ¶}–MMƒM¶}–@ƒ¶}–>@@<>@<9¶}ƒ`–<¶}–9@<>`C>¶}ƒxƒsƒnƒi…}–CE`E¶}–Gƒ¶xƒs‚p}–GGƒ¶}–HGƒ¶xƒsƒnƒiƒdƒ_ƒZ‚p}–XHƒ¶x‚p–X¶}–VƒV¶}–VƒX¶}–Vƒ¶xƒsƒnƒiƒdƒ_‚p}–VX@VT`TS`S¶}–Oƒ¶xƒsƒnƒiƒdƒ_ƒZ‚p–LO¶}ƒxƒs„0}–ML`OM`QO¶}ƒ`–T¶}–Q@VT`¶}–[Vƒ¶x‚p–Z[¶}„@–]¶}–Z@¶}–]bƒb¶}–bƒ¶}–2bƒ¶}–22ƒ22¶}ƒ–2¶}–2ƒ2¶}–2ƒ¶}–22ƒ¶}–22ƒ2¶}–2ƒ2¶}–2ƒ2¶}–2ƒ¶}–22ƒ¶}–22ƒ2¶}–2ƒ2¶}–2ƒ¶}–2<¶|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0–<ÿ/MTrk f·ÇYÿJAZ2—H"ÿGeneral MIDIÿPart-03ÿYÿY·x "[@]@HKJ<C}—L"·}ÿ @ƒ·xƒsƒn‚p—G"·}—C"HLƒ·x‚p—L"·}—H"GCƒ·xƒs‚p—G"C"·}—HLƒGL"H"C·}ƒ—LC"·}—HG"ƒ·}—H"L"CGƒHLG"·}—C"ƒJ"CH"·}—Gƒ·x‚p}—H"HJL"ƒ·x‚p—K"H·}—I"Lƒ·}—Q"M"KIƒJ"·}—H"MQƒH"E"·}—HJ@·}@—M"·}—Q"EHƒ·x‚p}—J"O"MQƒ·x‚p—I"·}—OK"JƒIQ"M"·}—KƒQMJ"H"·}ƒ—E"·}—H"JH@·}@—M"·}—EQ"Hƒ·x‚p—J"O"·}—MQƒ·xƒsƒnƒiƒd‚p—JO·}—C"G"ƒ`CGJ"O"·}@}`—N"OJ·}—M"ƒO"MN·}—J"ƒL"·}—JOH"ƒC"G"·}—LHƒGC·}—L"H"ƒC"·}—HLG"ƒ·}—CGL"H"ƒLHG"·}—C"ƒG·}—H"CL"ƒ·}—C"HLG"ƒH"·}—L"GCƒLC"·}—G"HƒCH"L"G·}ƒ—C"H·}—G"LƒL"·}—GH"CƒLHC"·}—G"ƒH"C·}—GJ"ƒ·x‚p—H"L"JH·}ƒxƒs‚p—LJ"·}—H"H@·}`—L"H"·}—HJ`HL·}—C"G"ƒCO"L"G·}@}`}`}—OLH"E"ƒH"·}—E"EH@·}@—EH·}—L"Q"ƒ`·}—LQE"H"@·}`}—L"HEH"ƒ·x‚p—Q"·}—N"LHƒ·x‚p—C"·}—G"QNƒ·x‚p}—GCL"Q"ƒLM"QJ"·}ƒ—MJR"·}—M"ƒ·x‚p}—RML"Q"ƒ·x‚p—H"LE"·}—Qƒ·x‚p—I"HM"E·}ƒxƒsƒn‚p—H"·}—IL"MƒJ"H"·}—HL`·}`—H"JH·}—L"`·}`—M"Q"·}—LHƒ·x‚p—E"M·}—C"Qƒ·}—Q"M"CEƒQG"·}—C"M… G"·}—C"GC`H"J"·}—CGƒ·}—Q"JHM"`·}`}`}`—O"MQJ"·}ƒx‚p—JOH"·}—L"ƒLG"·}—HC"ƒL"CH"·}—GƒL·}—HC"G"ƒCG·}—L"H"ƒHG"C"·}—Lƒ·}—H"CGJ"ƒ·x‚p—H"L"·}—JHƒ·x‚p—LH·}—I"K"ƒ·}—KIQ"M"ƒQMJ"·}—H"ƒHH"JE"·}@}@—M"HE·}—Q"ƒ·x‚p—M·}—J"O"Qƒ·xƒsƒnƒiƒd‚p—JOG"C"·}ƒxƒsƒn‚p—L$·}—H$GCƒ·xƒsƒnƒiƒdƒ_ƒZ‚p}—H"J"LHƒ·x‚p—G"·}—JC"Hƒ·x‚p—H"·}—J"CGƒ·xƒsƒnƒiƒdƒ_‚p—L"H"·}—JH@·}`}`}—L"HH"Lƒ·xƒsƒnƒiƒdƒ_ƒZ‚p—HJ"·}—H"Lƒ·xƒs…—H"L"·}—HJ`M"·}—LHQ"ƒ·x‚p—QMH"·}—L"ƒ·x‚p—LQ"·}—HN"ƒ·x‚p—G"N·}—C"Qƒ·x‚p—GCL"H"·}ƒ—C"HL·}—G"ƒ·}—GH"L"CƒG"C"LH·}ƒ—C·}—L"H"GƒL·}—C"G"HƒL"·}—H"GCƒC"G"L·}—Hƒ·}—L"H"CGƒC"G"·}—LHƒGH"·}—CL"ƒLC"HG"·}ƒ—L"·}—H"CGƒG"HL·}—C"ƒ·}—HCG·|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0—Hÿ/MTrk ߸ÈYÿJAZ2¸J<ÿGeneral MIDIÿPart-04ÿYÿY¸x ^[@]@HKC}ÿ @˜H"C"¸}ƒxƒsƒn‚p}˜C"J"HCƒ¸x‚p˜C"¸}˜H"CJƒ¸xƒs‚p˜J"¸}˜CC"HƒJCC"H"¸}ƒ}˜C"J"CHƒJCH"¸}˜C"ƒJ"C"C¸}˜HƒC"H"C¸}˜Jƒ¸xƒsƒn‚p}˜I"D"CHƒH"M"¸}˜IDƒC"H"¸}˜HMƒCHE"L"¸}@}@˜LC"H"¸}˜Eƒ¸xƒsƒn‚p}˜D"I"CHƒIM"DH"¸}ƒ}˜C"H"HMƒL"¸}˜E"HC@¸}@˜H"¸}˜EC"Lƒ`E"CH"H¸}@˜H"E¸}˜E"H`EHC"¸}˜J"ƒ¸xƒsƒnƒiƒdƒ_ƒZ‚p˜B"H"JC¸}ƒ˜C"¸}˜J"BHƒ¸}˜C"H"JCƒHC¸}˜J"C"ƒH"CJ¸}˜C"ƒC"¸}˜CHJ"ƒH"C"¸}˜JCƒHC"CJ"¸}ƒ˜H"CC"¸}˜JƒHC"J"C¸}ƒ˜J¸}˜C"CH"ƒJ"CHC"¸}ƒ˜C"H"¸}˜CJƒJ"HC"¸}˜CƒH"¸}˜C"CJƒ¸}˜HC"CJ"ƒC¸}˜H"C"Jƒ¸xƒsƒnƒiƒd‚p˜C"¸}˜J"CHƒC"¸}˜G"JC@G"CG¸}˜H"`HGG"C"¸}`˜L"G¸}˜E"Cƒ¸xƒsƒn‚p˜C"¸}˜EH"Lƒ¸x‚p˜HCH"B"¸}ƒx‚p}˜C"J"BHƒ¸x‚p}˜L"CE"Jƒ¸x‚p}˜F"M"LEƒ¸x‚p˜L"¸}˜FME"ƒG"ELC"¸}@˜H"GCG"¸}`˜G"C"H¸}˜G`¸}˜CL"E"Gƒ¸x‚p˜D"¸}˜LI"Eƒ¸xƒs„0}˜H"DID"`I"¸}˜D"DH`H"DI¸}˜C"ƒ¸x‚p˜CC"H"¸}˜Hƒ¸xƒs‚p˜CH"HE"¸}ƒ˜C"¸}˜HEJ"ƒ¸x‚p}˜H"JC"CƒCH"M"¸}˜H`E"H¸}˜H"M`E"H"¸}˜EH`¸}`˜EHJ"C"¸}ƒx‚p˜CJH"¸}˜C"ƒCC"¸}˜HJ"ƒC"JH"¸}˜CƒCC"HJ"¸}ƒ˜JC¸}˜H"C"ƒHC"J"¸}˜CƒC¸}˜H"C"Jƒ¸xƒsƒn‚p˜D"HCI"¸}ƒ˜DM"H"I¸}ƒ˜MHC"H"¸}ƒ˜H¸}˜E"L"C@¸}@˜EL¸}˜H"C"ƒ`CE"¸}˜H"H@HH"E¸}˜E"`J"HEC"¸}ƒxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p}˜JCH$C$ƒ¸xƒsƒnƒiƒdƒ_ƒZƒUƒP‚p˜J"¸}˜CHC"ƒ¸x‚p}˜H"C"JCƒ¸xƒsƒnƒiƒdƒ_…˜C"¸}˜G"CH`GH"C"C¸}ƒxƒsƒnƒiƒdƒ_ƒZƒUƒPƒKƒF‚p˜CC"H¸}˜H"ƒ`¸}˜E"H"HC@E"EH¸}˜H"p¸xƒs‚p˜EB"H¸}˜H"ƒ¸x‚p˜J"HC"B¸}ƒx‚p˜CC"J¸}˜H"ƒHC"C¸}˜J"ƒH"CJC"¸}ƒ}˜J"HCC"ƒCJ¸}˜H"C"ƒ¸}˜CJ"C"HƒJH"CC"¸}ƒ˜C"¸}˜J"HCƒ¸}˜C"H"JCƒC"¸}˜HJ"CƒH"J¸}˜CC"ƒJ"HC¸}˜C"ƒC"¸}˜H"CJƒHC"C¸}˜J"ƒHJ¸}˜C¸|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0˜Hÿ/MTrknÀÿJAZ2ÿSteamin' across the prairiesÿY°yx @r(ÿ @ÿGeneral MIDIÿ/simutrans-124.3/simutrans/music/13-Stephenson-blues.mid000066400000000000000000000271171474050137200231020ustar00rootroot00000000000000MThd`MTrk‹ÿ 2006.10.06ÿÿC 7ÿQ¡ ƒÿC 7ƒÿG 7ƒÿG 7ƒÿC 7ƒÿC 7ƒÿG 7ƒÿG 7ƒÿC 7ƒÿC 7ƒÿG 7ƒÿG 7ƒÿC 7ƒÿC 7ƒÿG 7ƒÿG 7ƒÿC 7ƒÿC 7ƒÿC 7ƒÿC 7ƒÿC 7ƒÿC 7ƒÿC 7ƒÿG 7ƒÿF 7ƒÿC 7ƒÿF 7@ÿC 7@ÿC 7@ÿF 7@ÿC 7ƒÿG 7ƒÿF 7ƒÿC 7ƒÿF 7@ÿC 7@ÿC 7@ÿF 7@ÿC 7ƒÿG 7ƒÿF 7ƒÿC 7ƒÿF 7@ÿC 7@ÿC 7@ÿF 7@ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7†ÿC 7@ÿC 7@ÿC 7@ÿC 7`ÿG 7`ÿC 7@ÿC 7@ÿC 7@ÿC 7`ÿG 7`ÿC 7ƒÿG 7ƒÿC 7ƒÿC 7ƒÿF 7@ÿC 7@ÿC 7@ÿG 7@ÿC 7ÿ/MTrkoÿ @ÿGeneral MIDIÿCopyright (C) 2006 shunterÿJAZ2ÿX`ÿ 2006.10.06ÿ/MTrkÀÿ @ÀÿJAZ2ÿGeneral MIDIÿTrack1ÿ 0P0@0LPEPFPEF0L$<@@FOLOLOLFDJPFPLPJLF<0@]07@]7@NFNMN<@MF@$@BFB@B@Fa<JGCGSG7@7@\CSJ7MSJS?@SS2@\SMJ?2C@SIJI>@LI\LSJCSPA@JPMP\SJMA>7@@GGQGMGQMG7?@2@@GDMDJDGJM?C@@MEGEGEGMC27@A@]7A0@=0<@@@JFJ@@J@Fa<0@]07@@FHCH@HF@C7@OFO<@MOM@F$@M@M@FM@Fa<7@]72@?@]?2C@TBMBGB>@MTGACA@]>A7@]72@?@]?C@@GGGGGMGMGC27@A@]A70@ @NCNFNF@C0<@@@RFR@R@F@a<@MGTACA@@QNMNGNQMG>A7@SIMISM$SLMLQLMSQ72@?@]?MKC@SKTKTMS$MRSRSRSMC2A@7@@MQQQQMSA70@@FJJJLJLJFa0<@=<CLLL0@@TAGAC@MTG$GCMCGGCGMCA@@MCGCQCGQM>A7@]7?@GMAM2@CMGACA?C@]2C7@@GOAOQOGAQ70@@LFL@F$@QFQJQ@FJa07@]7C@]C<@d@OFOF@@LFL@@LF@<C@]C@M<@CMX@C<@M7@CMFMTCF@@BCBDBDEBPE@C@GCGFGT@CF70@CI@LNJN7@\LGJ7JFMFGFC@\GJM>C?@<@=?3@MFLFFFMLF$LHFHLLHLF3<C@]C0@3@@FO@OJOJ@F3@]>C@]CO@]OJ@]J>@]>C@]CO@]OJ@]J†>@]>C@]CO@]OJ@]J>@]>C@]CO@]OJ@]J†>@]>C@]CO@]OJ@]J>@]>C@]CO@]OJ@]J†>@]>C@]CO@]OJ@]J>@]>C@]CO@]OJ@]J“CC@]CF@]F>@]>C@]C>@=><@]<A@‚A<@=<C@]CF@]F<@=<C@=C<@]<C@]C<@=<CC@]CF@]F>@]>C@]C>@=><@]<A@‚A<@=<C@]CF@]F<@=<C@=C<@]<C@]C<@=<CC@]CF@]F>@]>C@]C>@=><@]<A@‚A<@=<C@]CF@]F<@=<C@=C<@]<C@]C<@=<cC@]CO@=OH@]HC@]CO@]OT@]TT@‚TƒT@]TT@]TO@]OH@]HT@]TT@]TO@]OH@]HT@]TcC@]CO@=OH@]HC@]CO@]OT@]TT@‚TƒT@]TT@]TO@]OH@]HT@]TT@]TO@]OH@]HT@]TcC@]CO@=OH@]HC@]CO@]OT@]TT@‚TƒT@]TT@]TO@]OH@]HT@]TT@]TO@]OH@]HT@]TcC@]CO@=OH@]HC@]CO@]OT@]TT@‚TƒT@]TT@]TO@]OH@]HT@]TT@]TO@]OH@]HT@]T…#>@]>…#>@]>ƒ>@]>C@]C>@]>J@]JH@=H<@]<F@]F<@]<C@=CF@]F<@]<?@]?<@]<C@]C<@=<>@]>C@]CC@]CH0=Hÿ/MTrkç²Â ÿJAZ2²G@ÿGeneral MIDIÿBase²Z[<]<ÿ @²J@H@I@K@’$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$4h>4+h+-h-.h6..h.-h>-+h++h>++h+/h>/2h2'h'(h6((h(4h>42h2+h>++h+/h>/2h2(h()h6))h)4h>42h2$h>$$h$"h>""h" h !h6!!h!-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.h>h+h>++h+/h>/2h24h45h655h5&h>&&h&+h>++h+/h>/2h24h45h655h54h>42h2$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.h>h+h>++h+/h>/2h2(h()h6))h)4h>42h2+h>++h+;h>;2h2(h()h6))h)&h>&&h&$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.-h>-+h++h>++h+/h>/2h24h45h655h54h>42h2+h>++h+)h>))h)(h()h6))h)&h>&&h&$h>$$h$4h>4+h+-h-.h6..h.h>h$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$"h>""h" h !h6!!h!-h>-+h+$h>$$h$"h>""h"-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+ h !h6!!h!h>h$h>$$h$4h>4+h+ h !h6!!h!h>h+h>++h+)h>))h)4h45h655h54h>42h2)h>))h)-h>-0h02h23h633h3$h>$$h$$h>$$h$(h>(+h+ h !h6!!h!h>h)h>))h)-h>-0h0$h>$$h$(h>(+h+$h>$$h$"h>""h")h>))h)9h>90h0$h>$$h$(h>(+h+ h !h6!!h!-h>-+h++h>++h+/h>/2h2'h'(h6((h(4h>42h2)h>))h)9h>90h0&h&'h6''h'2h>20h0$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+)h>))h)'h>''h'$h>$$h$4h>4+h+$h>$$h$4h>4+h+)h>))h)'h>''h'$h>$$h$(h>(+h+-h-.h6..h.-h>-+h++h>++h+)h>))h)'h'(h6((h(&h>&&h&)h>))h)9h>90h0%h%&h6&&h&2h>20h0$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+)h>))h)'h>''h'$h>$$h$(h>(+h+$h>$$h$4h>4+h+)h>))h)9h>90h0$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$"h>""h"-h-.h6..h.h>h$h>$$h$4h>4+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+ h !h6!!h!-h>-+h+$h>$$h$"h>""h"-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.h>h$h>$$h$4h>4+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$(h>(+h+-h-.h6..h.h>h$h>$$h$(h>(+h+-h-.h6..h.-h>-+h+$h>$$h$"h>""h" h !h6!!h!h>h$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$"h>""h"-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+$h>$$h$4h>4+h+ h !h6!!h!-h>-+h+$h>$$h$(h>(+h+$h>$$h$4h>4+h+$h>$$h$(h>(+h+$h>$$h$+h>++h+$h>$$h$"h>""h"$h>$$h$"h>""h"$h>$$h$(h>(+h+$h>$$h$+h>++h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h++h>++h+/h>/2h24h45h655h54h>42h2$h>$$h$"h>""h" h !h6!!h!-h>-+h+$h>$$h$4h>4+h+-h-.h6..h.-h>-+h+)h>))h)-h>-0h0$h>$$h$(h>(+h+$h>$$h$(h>(+h++h>++h+)h>))h)(h>((h('h>''h')h>)'h'&h>&$h|$ÿ/MTrkLÿ @H°ÀÿJAZ2ÿGeneral MIDIÿÿ  ÿ/MTrkT¸È{ÿJAZ2¸H@ÿGeneral MIDI¸d[<]<J@I@ÿBirds¸K@˜0@¸G@ÿ @‚x˜0$@‚x$†0@‚x0+@‚x+ƒ$@‚x$†7@‚x70@‚x0‰0@‚x0†+@‚x+•0@‚x0H0@80H5@850@‚x0H5@85Œ0@…x00@…x0†0@…x0$@…x$0@…x0†0@…x0†$@…x$$@8$0@800@800@X0ƒh0@800@X0+@X+Œ5@85$@8$$@8$‡HH@‚Hÿ/MTrkOÿ @ÿGeneral MIDIÀÿJAZ2ÿStephenson bluesÿ/simutrans-124.3/simutrans/music/14-Last-journey-of-the-Niagara.mid000066400000000000000000002241731474050137200247620ustar00rootroot00000000000000MThd ÀMTrkyÿCopyright (C) 2006 shunterð~ ÷°ÿJAZ2ÿX`ÿAÿQ¡ ÿÿ 2006.10.06ÿ/MTrkyÀÿJAZ2° x SlÿMelodyÿGeneral MIDI° x[ÿ @°] xÀ@BKà ??BK°y àB@@&°BBwwuBu sBsqBq B B(BssBuBuwBwà@?B? °Bà@BEKàB@B==Bà@=E=E>>@>E>°Eyy àE??@?E?E@@4°EwwuEu sEsEqq Eoo Emm kEkEii E EE kEkEmEmoEoEqqEss:qEqoEoEmm  E EooEqEqàE?@?°Ess uEuàE??°EwwàE>@>°EEyà ?°yBKàE?°E à@B@ °B{{yBy BwwuBuBssBqq Boo BBmmB oBoqBqsBsB  uBuBwwà@?B? @=B@EK°BàB=Bà@=E=E>>°yàE>°Eyà@> E??°{E{àE?@?@E@(°yEy EwwEuuEssqEqEoomEmEkkEii Egg Eee E  EccEEEeeEgEgiEikEkmEm EooqEq8oEo Emm kEkiEi E  kEkmEmE oEoàE?@?°EqqsEsEuuà?E?°EwwàE>@>@°EyJKà@>J>°àE@°EyEàJ??@?J?@J@°wJwJuusJsqJq JJooJqJqJssuJuJwwà@@J@@?L?L>JLK°Jà >°àL==@=L=>L>@>L>L??L?@?@L@°uLuLLssLLuuàL?@?L=`=L>@>L??L=°wLwà=J=JKà@=°LLàJ> >J??J@@@?J?°JyyJ{{àJ@@°yJywJwJ uJu JsJs qJq JooJ Jmm J(($Jkk /J/*JmmoJo%J% Jqq J  sJs uJuJ wJwàL@LK°Jà@J?@?°J°LyyLww uLuLss LLLuu wLw à@?L?°LLyLJK°yà@J@°J{{JyyJwwJuuJssqJqJooJmm JJooqJqsJsJuuJwwàJ?@?°JàJ? ?°Jyyà@J@JIKà@I@°IwwIuuIssqIqIooIIIqqIssIuuIwwàI?°Ià@?`@IàI@A@G@IAGKà@G@8°yGy${G{GyGy wGwGuuGGssGqqGooGmmG0G<oGoqGqGssu#GuG#GwwnGuuGssG qGq  G GooGmmGà@?G?°GooGqGqàG??°Gssà@>G>°uGuGwà>°wàG>@=G=G? ?BKG°Byyà@B@.°BwwBuusBs BqBqBBssBuu B Bwwà@?B? @B°à=B@CKàB=°BàC= =C=`=C> >°yCyàC>`> ?C?°C{{ àC@@(°yCy CwwuCusCsCqqCooCmmCkkiCi Cgg Cee C cCcCCCeegCg CiCikCkCmm oCoCqq8Coo Cmm kCkiCi  C kCkCmCm CooàC?@?°qCqsCsuCuà?C?°wCwà@>C>°yàC?C°Cà ?°Cy@K à@@@ °@{{@yy w@wu@u @ssq@q o@o@@mm@@ooq@q@ss@  u@u@wwà@?@? @@=@=CK@à@°@à@=C=>C>C>@>°yCy àC??@?C?C@@°{C{$Cyy wCwuCuCssqCqoCoCmm kCk CiigCg C CCC CiikCkmCmCoo CqqsCs$qCqoCo mCmkCk  C mCm CoCo à@?°CqàC?°q sCsCuuàC??°Cwwà@>C>IKàI@°à@?C?@°CC°yIywIwIuusIsIqq I sIsIuuIwwà@?I?°Ià@I@GKI`àG@Gà`@EKà@E@@?E?°Eyy {E{}E} àE@@°{E{Eyy wEwuEuE  sEsEqqEoomEEmEkk Eii&E&HkEk Emm oEoEqEq EssEuEuwEw à@EKàE@°yàE?@?°EEyE,°wEw E uEu sEs Eqqà@?E?°EsàE??°sàE>°uEuà@>°wEwEEK°E°yEyà?E?E?@?@E@ °wE Ew Euu Ess EqqsEsEuuEEww@KEà@?@?@@@8°u@u@  0@@wwàB@@?@?@BK°@@°ByywBwuBu BssBqqBooBBqqsBBs uBuBwwBàB?°à@?@B@BKàB=Bà= =B= °yByàB=`=B> >B>`>B? ?°Bwwà@B@°Buu sBBs qBq B  oBoBBmmD B oBo BqBq Bss B uBuBFBssBqBqBooBmmBkk BBiiB Bkk mBmBoBoBqqsBsBuuwBw ByyBà ?BKàB?°B àB@@°B{{yBy wBwBuusBs qBqoBo mBmB  B"oBoqBqBsBsBuuwBwà@?B? @=°BàB=B@BEKàE= =`=E= >E> E>`>°yEy à ?E?@E@4°Eww uEu sEsEqqEoomEmEk kE EEEmEmEooqEqEssPEqqoEo,E  EqqEàE?°Esà@?°sEuuàE??°EwwàE>@> ?°EàE?BKE°ByyàB@@.°Bww BuuBsBsBqBqB"Bss Buu B wBwàB?@? °BàB=BàB@EK°à=@@=E=E>>°yàE>°Eyà@> E??°{E{à@?E?E@@(°Eyy EwwEuuEssqEqoEoEmmkEk iEi gEgEeeE  EEEEggEiikEkEmm EooEqq:oEo Emm kEkEii E kEkEmmE oEoàE?@?°EqqsEsuàE?°Euà?°wEwà@>E>°zà@E@E°EEzàE>JKà >°àJ>`>J? ?@J@°xJxJvvtJtJrrJppJnnJll J JJnnJpprJrtJtvJvàJ@@@°xJxàL>@?JàL?°Jà >LK°àL==L=@=L>>L>@>L??L?@?@L@°vLvtLtL!!rLrpLp LLrràL?°tLtà@?L>?@>L?°và`=L=°Lvà=L=@=J=L°LJK°à >J>J??°JxxàJ@@J?@?°Jzz|J|~J~àJ@@°J||JzzJxxJJvv tJtrJrJJppJnnlJlJjJjhJhJ((Jff 0J02JhhjJjJ%%Jll nJn  J Jpp rJrJJttvJvàJ?JJKàJ@°yà@?@°JJyJ{{JyyJwwJuusJsJqJqoJo Jmm à@?J?°JooàJ??°qJqà@>°sàJ>°JsuJJuwJwJyJKJ°yàJ??J?@?J@@°wJwJuJusJsJqqoJomJmJooqJqJssJJuuwJwIKJà@?I?@I@°yIywIw Iuu sIsI  qIqIssIuIuàIA°IGK°xàAI°Ixà@@G@G@@B°GzzG|G|zGz G xGxGvvGttrGrGpGpnGnGllGjjhGhG Gff&#G#GhhGjjlGlnGnGpprGr*G*GttGvvGxxPGvv G$$Gtt Grr pGp nGnlGl G GjjGhhGjGjàG?@?°GllnGnàG??°Gppà@>G>°rGrGttàG>>°Gvvxà@=G=°Gxà ?BK°GàG?G àB@@°BzzxBxBvv BttrBr  B pBpB rBr BttBvBvBxxàB?@? =B=Bà@°àB@°BCKà@=C=>C>C>@> C?? °zCzàC?@?C@@,°Cxx vCvCttrCrCppCnn lClCjj ChhCffCddCC0CfCfhChjCjCllCnnCpprCr$CppCnn CllCjj* C lClCCnnàC?@?°Cpp CrrCttàC??°CvvCxxàC>@>°C@Kà ?°CàC? @@@°@zz$@xxv@v@tt r@r p@p n@@n@"p@pr@r t@ @tv@và@?°@xà@?°x à@@@CKà=°@à@@=C=@=C>>C>@> ?C?°zCzàC?@?@C@*°xCxCvv tCtrCr Cpp Cnn lClCjjC  CCC  lClCnnpCpCrrC%%Ctt(CrrCppCnn C C  pCpC rCrà@?C? °tCt vCvà?C?°Cxxà@>C>C°CzGKàC>@C@°zà >°Cà`>G> ?G?G@@°GxxvGvGttGrrpGpnGnlGlGGGnnpGprGrtGtvàG@@@°GvxGxàI> >@?°GàI?°IKGà=I=@=I=I>>@>I>I??I?@?I@@°IvvtItIIrrIppIrIrà@?°tItàI?I=@>I>?I?`=I=°Ivvà=°à@=E>EKàE=Ià>°Ià`>E>°Exà ?E?@E@°xà@?E?°{E{ E}}à@E@°E{{ExxEvvEtEtrErEppEnEnEllEjj,E,Ehh2E2jEjlElE%En%n pEp ErrEEtt Eww EK°yà@?E°EyEàE?°à@E@°{E{yEyEwwE  uEuEssEqqoEoEmmà@?E?°Eoà?E?°oEqqà@>°EssàE>°uEuwEwEE°EyEK°yà?E?E?@?@E@°wEwE  uEuEssqEqEoomEmoEoqEqEssEuEuEwwEKEà@?E?@E@°EyywEw uEu EssE EqqEssEuEuEyàE? ?E=K°Eyà@=@°w=wu=us=s=qq ="s=s=uuw=w=à=?@?@=à=@===>K°y>yà>=@=>>>>>@> ?>?>?@?°>wwà>@@°>uu >ss q>>q >oo >m > mk>k> >ii>H> > >kkm>m>>oo>qq>s>s>0>""4q>q">oom>m>kk>ii>gg >ee>>cc >>ee>  >ggi>ik>k>mmo>>o>qqs>su>uw>wJKà =J=`=J=J> >°JyyàJ>`>J? ?J@@4°JwwuJu sJsqJq oJo Jmm Jkk iJiJ JJ JkkJJmmoJoqJqsJs>*°q>q>oo>mm  > o>o>>qqà>?@?°s>s u>uà>??°w>wà>>@>J?J°Jyyà ?LK°J à@L@ °L{{yLy wLwuLu LssLqq LooL  LmmLLooLqqsLsL  uLuLwwà@?L? `@Là@GK°LàL@G@°àALAG@@°Gyy0{G{&GyGywGwGuuGssGGqqGoomGmGkkGiiGGgg,G,iGiGkkmGm oGoGqqGssG!! Guu wGw^uGusGs GqqGGoo GmmG  Gkk Gii Gà@?G?°kGkmGGmàG??°Gooà@>°GqàG>°qGssà>°uwàG>°GuGwà@=G=Gà@?IKà@G?I@ °IyywIwIuuIssI  IqqIssuIuwIwàI?@?@JKI°IàI@`IKà`@J@JàI@@ @?I?°yIy{I{à@I@°IyywIwIIuu IIssIqqIIooI$$fIqqIssIIuuIwIwIyJKàI? ?°II°yàJ@@°{J{JyyJwwuJusJsJqqoJo mJmJoJo qJqJssuJuwJwàJ?°Jà@?IKà@J@JàI?@?°yIyàI@@°wIw Iuu sIsIqqIsIs IuuwIwà@?°IàI?°à@°yà ?I@I?°IyIGKà@G@°GwwuGuGGssqGq GG sGsGuuwGwà@?°GàG?°à@AEKàG@GàGAE@@@@E@ °yEy4{E{EyEy EwwuEusEsEEqqEoomEmEkkE0E!!8EmmEooEqqEss'E'uEu wEwfE"Eu"uEss qEq oEoE  mEmEkEkà@?E?°EmmoEoàE??°qEqà@>E>°EssEwEuàE>°uwà>E=@=°yEàE>E@ >@°EyCKEà`>C>C? ?C@@°wCwuCuCssCqqoCo C CmmCCooqCqCssCuuCwà@@°wàC@G>GKà@? >°CC°àG?G==@=G=G>>@>G>?G?@?G?@G@°uGuGsGs qGqGsGsàG?@?°uGuà?G?`=G>G=@>=°wàG=°GwG°àC=°Gà@=CKàC> >C??@C@@?C? °yCyC{{à@C@°yCyCwwCuCusCs CCqqoComCm#C#kCkiCiC//Cgg7C7(CiikCk*C*mCmoCo C qCqCssCCuuwCw àC=°CGKCà=G=@=>G>@>G>?G?G?@?G@@.°Guu GGwwGGG°CKà ?G?°yGyGàC@@°C{{CyyCwwCuuCssCCqqCoo CCCqqCssCuuCwwà@?°CàC?CBKàC@@@?B?°yByàB@@ °BwwBuu sBsBB BuuwBwBàB?@?@KàBA`@@@BàA@B@@@@@°@yy@&@ww@uu@@ssq@q@oo@0@!!Dq@q@ss@uu'@' w@wl"@" @uus@s@qq @ o@o @à@?@?°q@qà?@?°@ssà@>@>°u@uwà@>°@wà>@=@=@@Kà@@°@@`=K@`=à===@K à@=@= >@>@>@>°y@yà?@? °@{{à@?@?@@@°@yy@ww@uu@ss@qqo@o@mm@kk@iig@g  @ @ee@@g@g i@i k@k @mm o@o q@q @ssq@q o@o@mm@kk @ m@m o@oà@?@?°@@qq@ssà@?°uà?°@uw@wà@>@>@°@à ?°à@?=K°=yyà=@@°=ww =uu =ssq=q==ss u=uw=w=à@?°à=?@@?@K°=yyà=?=@=à@@@4°@ww u@u@s@sq@qo@oà@?@?°@qà?@?°qs@sà@>@>°@@uuw@w@y@K°y@à@??@?@?@@@°w@w@@uu s@s@qqo@o@qq@ssu@@uw@wEKà`9°@{à@9°{@ àE9 9 E9`9°yEy àE: : `:E:°wEwà@;E;E<<°uEuàE<@<°Essà=E=@=E=°qEqà>E>°oEoàE>@>°mEmàE??°kEk à@?E?°iEi àE@@°EE  EEkkEmEm8EooE  HE&&H+E+XmEmE""E EkkiEiE EggEee E à@?E?°EggEEiikEkEmàE??°moEoEqEqsEsuEuàE>@>E>>JKEàE=°Exà=°xàJ=@=J>>@>J> ?J?°Jzzà@?J?@J@*°xJxJvvJttrJrpJp nJn Jll JjjJJhhJJJjjJlJlJnnpJprJrtJt JrrJppnJnJllJ  JnnJJpp à@?J?°Jrr tJtJvà?J?°vJxxà@>J>J? ?°JLKJ à@L@°zLz$LxxvLvtLt rLr Lpp nL Ln L"LppLrrtLtLLvvàL?°Lxà@?°x àL@A°GKà@LA°LLàG@@@G@@D°zGz|G|GzGz GxxvGvGttGrGrpGpnGnGlljGjGhGh*"G"(jGjlGlGnn pGprGr G))tGt GvvGxxPGvv #G#Gtt rGr Gpp nGnG  Gll jGj GàG?@?°lGlnGnà?G?°pGpàG>@>°rGrtGtvàG>°Gvà>@=°xàG=°GxGàG?°IKà@@?°GàI@ °Ivv IttI  Ivv xIxàI?@?°IJKà@°àI@I`àJ@`@IKJà@I@ @?I?°Izz|I|àI@@°zIzxIxIvIv tItIrrI  IppnIn IllI Ijj IhIhHIjjlIlInn IppIIrr Itt IIvv Ixx àI? ?JKI°Ià@J@°JzzJxx vJv Jtt Jrr J"tJtJvvJJxàJ?°xà@?°JàJ@IKà@I?@?I@@°zIzIxxvIvtItrIrIppInnIpIprIrtItIvvà@?I?°IxxIGKà@ ?IàI@I?°GzàG@°zà@°xGxGvvGttGrGrpGpGnnlGlGGnGn GpprGrtGtvGvà@?°GàG?°xGxà@AG@EKàGAGà@@E@E@@B°Ezz|E|zEEzxExEvvtEtErrEpEpEnnlElEjjhEhE fEf&EhEhEjjlElEnnEpprErE!!EttEvvExxPEvvEtt ErrEpEp EnnEllE  jEjEhEhà@?E?°EjjEllEàE?°Ennà?°pEpàE>@>°ErrtEtEvà>E>°và@=°ExxàE=CKàE>@@>E@C> >Eà?C?C?@?@C@°CvvCttrCr  C C tCtCvvàC@@@°Cxxà@?G?GKC°à >G>°Cà=G=@=G=G>>G>@>G??G?@?@G@°vGvGGttGvàG?°Gvà@??G?@>G=`=G>G==°xà@=G°CxàC=°GCKà >C>?C?C@@C?@?°zCz à@C@°xCx CvCv CttCCrrCpp$C$Cnn C11Cll C992nCnC,,CpprCr C CttCCvv CxxGK°CàC==°CàG=@=G>>@>G>G??@?G?@G@"°vGvGtt GrrG GttvGvG""GxxGàG?°à ?CKG°Gà@C@°CzzCxxCvvtCtrCrpCpCnnCCCpprCrCttCvvàC?°Cxà@?°CxàC@ ?BKàC?@CàB@@°zBzBxxBvvtBtrBrBppnBnBpBpBrrBttBvvà@?°xBàB?°BxBà@@Kà`@BAB@@@A@@@N°@zz@ @ @xx @vvt@t@@rrp@pn@n@ @ll&$@$"@nn"p@p@rrt@t@++@vvx@xZ@vv@%%@ttr@rp@p @ @nn @à@?@?°@ppà@??°r@r@tà@>@>°tvà@>°@và>°@xà@=@=°xà@@@à@°@@K°`=K@`à===@Kà= @=@= @>>@>@> ?@?°@zzà@?@?@@@°@xx@vv@tt@rr@ppn@n@ll@jj@hhf@f @  @dd@f@f@ @hh @jj @ll @nn@pp@rrp@p @nn@ll @jj@  @ll n@nà@?°@pà@?°@pr@rt@tvà@??°@vx@xà@>@>E>@@°@à@>@°à@EKàE??E?@?@E@°vEvtEtErrpEpnEn Ell EEnEnpEprErEttEàE@@@°EvvxExàL>@LKà`>L@Eà`=L==L= L=@=L>>@>L>L??L?@?@L@°Lvv Ltt L Lr r pLpLLrrLtà@?L?°Ltà`>L>°và >`=°LvàL=L> =`<L<L=J=LàJ>°xà@=°Jxà`>JKàJ@@B°vJvJ  0Jxà?JK°JxJàJ?J?@?J@@ °zJzxJx JvvtJtJJrrJ  pJp2rJrJJtt(J$J$ rJrJppJJnn4pJp JrrJtJtJvvxJxàJ?@?@°àJ@°JƒJº8BK@°à@°EàB=B@EKà=BàE=@=E>>E>@>°yEy àE??E?@?E@@4°EwwuEu sEsEqq oEo mEm Ekk iEiE EE kEkEmEmEooqEqEss:EqqoEoEmm E  oEoEEqqà@?E?°Ess Euuà?E?°wEw EBKàE?°yà ?°ByB à@B@ °B{{Byy wBwuBuBssqBq oBo BmBmB oBoqBqsBs B uBuwBwàB?@? °EEKàB=E?°Eyà@Bà ?B@°yà= @E@@=E=>E>E>°Eyà@>°yEwEwàE??°uEu {E{àE?°sà@?°Esà@E@°qEqE  EyEy wEwEuuEssEqqEoEsosmEmEEuuEkkEwwà@?E?°iEi gEg eEe  E EccEEeEeEgEgiEikEkEmm oEoqEq8oEo Emm EkkiEi E  kEkEEmm oEoà@?E?°EqqsEsàE?°Euuà?°wEwà@>E>°yà@>J>JK°JyJàE@@Eà?J?J?@?@J@°JwwuJuJssqJq JJooJqJqJssJuuà@@°JwwàJ@L>LKà@?°LJà >°àL?=L=L=@=>L>L>@>L??L?@?L@@°uLuLLssLuLuà@?L?L>@>`=@>L?L>?L==°LwwàL=J=°à@=L°JJKàJ> >?J?J@@@?J?°yJy{J{à@J@°JyyJJww Juu JsJs qJq oJoJ mJm J(($kJk /J/*JmmJoo%J% Jqq  J Jss uJuJ wJwà@@?°LàL@J?°JLK°yLyLww uLusLs LLuLu wLw à@?L?°LJyyJKLà@J@°{J{JyywJwuJuJssqJqoJoJmm JJooJqqsJsJuuwJwJà@?J?J@°yJàJ? ?IKà@°IyàI@@°IwwuIuIssqIqoIoIIIqqIssuIuIwwà@?°àI?°IIGKàIAA@`@I@G@@G@8°Gyy$G{{GyGy wGwuGuGGssqGqGoomGmG0G@>°uGuà>°GwwàG>@=G= ?G?BKG°Byyà@B@.°BwwBuuBss BqBqBsBsuBuB  Bwwà@?B? BàB@@=°CCK°àB= =C=`=C= >C>°yCyà`>C> ?C?°{C{ à@C@(°Cyy wCwuCuCssCqqCooCmmkCkiCi Cgg eCe C CccCCCeeCgg CiCikCkmCm oCoqCq8oCo mCm kCkiCi  C CkkCCmm Cooà@?C?°CqqsCsuàC?°Cuà?°Cwwà@>C>°y@@Kà ?C?C°@y à@@@ °@{{@yy @ww@uu s@s@qq @oo@@mm@@oo@qqs@s@  @uu@wwà@?@? °C@à=CKà@°à@@@=C=@=C>>C>@>°Cyy à?C?C?@?C@@°{C{$Cyy CwwCuusCsqCqCoomCm Ckk CiigCgC  CCC iCikCkmCmoCo CqqCss$CqqoCo mCmCkk  C mCm CCoo àC?°Cqqà@? °CssuCuàC??°Cwwà@>C>I@°à@°ICà@?C?IK°yIyIwwIuusIsIqq I IssuIuwIwàI?@?°GKà@°GIàI@`G@Gà`@EKà@E@E?@?°yEy E{{}E} à@E@°E{{yEy wEwEuu E sEsEqqoEomEmEEkk Eii&E&HkEk mEm EooEEqq EssEEuuEww à@@?°EyEyE°àE?EKàE@,°wEw E Euu Ess qEqà@?E?E?°sà?°EsuEuàE>@>°wEwEEEK°EyyàE??@?E?@E@ ° wE EwEuu sEs EqqEssEuuEwEwE@Kà@?@?@@@8°@uu@  0@@wwà@@?@?BKàB@°B@°yBywBwuBu sBsqBqBooBqBqBsBs BuuwBwBàB?@?B=BKà=B@Bà@ =B= °yByà`=B=B> >B>`>B? ?°wBwàB@@°uBu sBsB qBq  B BooBmBmD B oBo BqBq sBsB  BBuuFsBsBqBqoBomBmBkk BiBiB kBk mBmBoBoqBqBssuBuBww ByBàB?°yBKBà ? @B@°{B{yBy BwwBuuBss BqqoBo Bmm B B"BooBqqsBBsuBuBwwàB?@? Bà@EKà=°àB=B@°EàE= =E=`=E> > E>`>°yEy àE? ?@E@4°Eww Euu EssqEqoEoEmmkE Ek EEEEmmEooEqqEssPEqqEoo,E  EqqEà@?°sàE?°EsEuuàE??°wEwà@>E>BK°àE?°Bà ?E°Byyà@B@.°wBw BuuBsBsBqBqB"sBs uBuB  wBwà@?B? =EK°à@B@B=°EBà@=E=>E>@>°yEyàE> E??°{E{à@?E?E@@(°Eyy EwwEuusEsEqqoEomEmEkk iEi gEgEee E EEEEggiEikEkmEm oEoqEq:Eoo mEm kEkiEiE  kEkmEmE oEoàE?@?°qEqEssà?°uàE?°EuwEwàE>@>°Jà@ >JK°zEàE@°JzàE>`>J>J? ?@J@°xJxvJvtJtrJrJppnJnJllJ  JnJnpJpJrrJttà@@°vàJ@°JvxJxJLKà@? >°LàL?L>L==@=L=L>>@>L>?L?@?L?@L@°vLvLttL!!LrrpLp LrLrLtà@?°tàL?L=L?°Lvà@>°và`=L>?=L=@=JKLàJ=°JàJ> >°Jxà?J?°xà@J@@?J?°Jzz|J|~J~àJ@@°J||zJzxJxJvJv tJtJrrJpJpJnnlJlJJjjhJhJ((Jff J002hJhjJj%J%lJl nJn  J Jpp JrrJJttvJvJyàJ@°Jà@?J?J°yà@JK°J{{yJywJwuJuJssJJqqoJo mJm à@?J?°oJoà?J?°JqqàJ>@>°JssJuJuJwwyJK°JyJàJ??J?@?@J@°JwwJJuusJsqJqoJomJmoJoqJqsJsJJuuwJwJIKàI?@?@I@°yIywIw Iuu IssI  qIqIssIIuuGK°àAI°xGxàIA°Gà@@G@@G@B°zGzGG|| zG GzxGxGvvGttrGrGpGpnGnlGljGjhGhG Gff&G##hGhGjjGllnGnpGpGrrG**GttvGvxGxPGvv $G$tGt rGr Gpp nGnlGl G jGjGGhhà@?G?°GjjGllàG?°Gnnà?°pGpà@>G>°rGrtGtvàG>°Gvà>@=G=°GxxBK°àG? ?°BG àB@@°zBzxBxvBv BttBrr  B BppB rBr BttBBvvà@?°xàB?°Bx B°à@=CKàB@B=°CàC=@=C>>@>C> ?C? °zCzàC?@?C@@,°Cxx vCvtCtCrrCppCnn lClCjj ChhCffdCdCC0CCffChhCjjlClCnnCppCrr$pCpnCn CllCjj* C lClCCnnà@?C?°Cpp CrrCttà?C?°CvvCxxàC>@> ?@K°àC?°@C à@@@°z@z$@xxv@v@tt @rr p@p n@@n@"p@p@rr @ t@t@vvà@?@?°x@x @CK°Cà@=°à@@@=@=C=C>>C>@> C??°Czzà@?C?C@@*°CxxvCv CttCrr Cpp Cnn ClljCj C CC C lClnCnCppCrr%C%tCt(rCrCppnCn C C  CppC rCràC?@? °tCt CvvàC??°xCxà@>C>°àC@C> >GKC°zà@°GGzàG>`>G? ?@G@°xGxGvvGttrGrGppGnnGllGGnGnpGprGrGttvà@@G@°GvxGxIIKGà@? >°àI?I>I==I=@=I>>@>I>I??@?I?I@@°vIvIttIIrrIppIIrrItàI?°tà@?@>`=I=?I>I?I==°vIvàE=>EK°à@=E>°EIà`>E>E?E@ ?@°xExà@?E?°{E{ }E}à@E@°E{{ExxEvvEtEtErrEppEEnnlElEjjE,,EhhE22EjjEllnEnE%% Epp rErEtEt Eww EKà@?E°yàE?°EyEàE@@°{E{EyywEwE Euu sEsEqqoEomEmàE?@??°EooàE?°Eqqà@>E>°EssEuuEwwEK°EyyEE°àE??E?@?@E@°EwwE  EuusEsqEqEooEmmEooEqqEssEEuuEwwEEKà@?E?@E@°EyywEw Euu EssE qEqsEsEEuuà ?°y=KEàE?°=y=à=@@°=ww=uus=s=qq ="=ssu=u=wwà@?=?°==à=@=>Kà==@°>yyà@=>=>>>>>@> ?>?@?>?°>wwà@>@°u>u >ss q>>q >oo  >m> mk>k> i>i>H>>  >kk>mm>>ooq>q>s>s>0>""4>qq"o>o>mmk>k>iig>g >ee>>cc >>ee > >ggi>i>kkm>mo>o>q>q>ssu>u>wwJKà@=>=>@J= =J=`= >J>°Jyyà`>J> ?J?J@@4°JwwJuu sJsJqq oJo Jmm JkkJiiJ  JJ JkkJmJmoJoJqqJss>6°q>qo>om>m >  o>o>q>qà@?>?°>ss >uuà?>?°>wwà>>@>°yLKà ?J°àJ?°LyL àL@@ °L{{yLy wLwuLu sLsqLq oLo L mLmLLooLqqLssL  uLuwLwàL?@? @GKà`@A°àLAL@G@°GLàG@@°yGy0{G{&GyGywGwGuuGssGGqqoGoGmmkGkGiiGGgg,G,GiiGkkmGm GooqGqGs!sG! uGu wGw^GuuGss qGqGoGo Gmm G Gkk iGi GàG?@?°kGkGmGmàG??°GooqàG>°Gqà@>°sGsuGuà>G>°wGwàG=@=Gà@?@G@IKàG? °IyyIwwuIusIs I qIqsIsIuuwIwà@?I?I@°JI°JKà@``@J@IKJàI@@ @?I?°yIy{I{à@I@°yIyIIwwIuu IsIsIqqIIoo$I$fqIqsIsIuIuIIwwJK°àI?°JJyà ?°yIà@J@°J{{yJywJwuJusJsqJqJoo mJmJoJo JqqsJsJuuwJwàJ?°Jà@?IKàJ@@Jà@?I?°yIyà@I@°Iww Iuu sIsqIqIsIs uIuwIwàI?°Ià@?@I?°Gyà ?GKàI@I°yà@G@°GwwGuuGsGsGqq GG GssGuuGwwàG?@?°GEKàAGAG@Gà@@@E@E@@ °Eyy4E{{EyEy wEwEuusEsEqEqEoomEmEkkE0E!!8mEmEooqEqsEs'E'Euu EwwfuE"Eu"sEs qEq EooE  EmmkEEkà@?E?°mEmEooàE??°EqqàE>@>°sEsà>°uwàE>°EuEwàE=@= >CK°yà@E>°CCyàE@EàC>`> ?C?C@@°wCwCuuCssqCqCoo C CmmoCCoqCqCssCuuCwwàC@@@CàG>@? >°àG?GK°GàG==G=@=G>>@>G>G??G?@?@G@°GuuGsGs qGqGGssà@?°uàG?°GuàG?@>`=?G>G==G=°GwwCKà@=°àC=°CGàC> >?C?@C@@?C? °yCy{C{àC@@°CyyCCwwuCuCss CqCqoCoCmm#C#kCkCiiC//gCgC77(iCiCkkC**mCmoCoC  CqqsCsCuCuCww à=°àC=°GGKCà@=G=G>>G>@>G??@?G?G@@.°uGu GGwwGGCCyGCK°yà ?G?@C@°{C{yCywCwuCuCssCqCqoCo CCqCqsCsuCuCwwà@?C?°CCàC@@BKàB?@?@B@°yBy wBwBuu BssBB uBuwBwBàB?@?°àB@@@@BA@Kà`@BàA@@@@°@yy@&@wwu@u@s@sq@q@oo@0!@!D@qqs@su@u'@' @wwl"@" @uus@sq@q@  o@o @à@?@?°@qqà@??°@ssà@>@>°u@uwà@>°@wà>@=@=@Kà@°@à@@@`@=K`à=@Kà=== à@=@= >@>@>@>°y@yà@?? °@{à@?°{à@?@@@°@yy@ww@uu@ssq@qo@o@mm@kki@i@gg @e@  e@@@gg i@i @kk m@m o@o q@q s@sq@q o@o@mmk@k@  @mm @ooà@?°@à@?°@qqs@suà?@?°@uw@wà@>@>=Kà@?°=à ?°@°y=yà@=@°=ww =uu =ssq=q==ss u=u=wwà@?°=à=?°yà=?=@=@Kà@?°@yà@@@@4°@ww u@u@s@s@qqo@oà@?@?°@qà@??°qs@sà@>@>°@u@uw@w@y@K°y@à?@?@?@?@@@°w@w@u@u @ssq@qo@o@qq@ss@@uu@ww{E{à`9EKà@9@ à 9E9 E9`9°yEy àE: : `:E:°wEwàE;@;E<<°uEuàE<@<°EssàE==E=@=°Eqqà>E>°EooàE>@>°EmmàE??°kEk àE?@?°Eii à@E@°EE  EkEkEEmm8Eoo E HE&&H+E+XEmm"E"E EkkEiiE EggEee E à@?E?°EggEEiikEkmà?E?°EmEooEqEqEssEuuàE>@>>E>=JK°xàE=°JxEàJ=@=>J>J>@> ?J?°JzzàJ?@?@J@*°xJxJvvtJtJrrJpp Jnn Jll JjjJhJhJJjJjJlJlJnnJppJrrJtt rJrJppJnnJllJ  JnnJJpp àJ?@?°Jrr tJtvàJ??°JvJxxàJ>@>°LJàJ?LKà ? L@@°Lzz$LxxLvvtLt Lrr pLp  LnL nL"pLprLrLtLtvLvLxàL?°xà@? °GàLAL@A°à@LGKàG@@@@G@D°Gzz|GG|zGz GxxvGvtGtGrGrpGpnGnlGljGjGhGh*"G"(jGjlGlnGn pGprGr G))tGt GvvxGxPvGv #G#tGt rGr Gpp nGnG  lGl Gjj Gà@?G?°GllGnnàG??°Gppà@>°ràG>°GrGttà>G>°Gvvà@=°GxàG=°xIKGà@?@°IàG?G@ °vIv tItI  vIv xIxàI?@?JKàI@°Jà@°I`à`@IKJàJ@I@@ @?I?°zIzI||àI@@°IzzIxxIIvv tItIrr I pIpInn lIlI Ijj IIhhHIjjIllInn IppIIrr Itt IvIv Ixx àI?I°JJKà ?J@@°JzzJxx vJv Jtt rJr J"JttvJvJàJ?°Jxà@?°xJIKà@J@I?@?I@@°zIzIxxvIvtItIrrpIpnInIpIpIrrIttIvvxIxIàI?@?@IàI? ?I@GK°Gzzà@G@°xGxGvvtGtGrGrGppGnnGllGGnGn pGpGrrGttvGvGxà@?°xàG?°GEKàAG@GA@Gà@@E@@E@B°EzzE||zEzExExvEvEttrErEpEpnEnlElEjjEhhE Eff&EhEhEjjlElnEnEpprEr!E!tEtvEvxExPvEvtEt rErEpEp EnnEllE  EjjhEEhEjàE?°jà@?°EllEà?°nEnàE?°pEpà@>E>°ErrtEtvà>°EvàE>E=°Exà@=°xEà >E>CKà@>E>E@@C??@?C?@C@°CvvCttrCr  C C CttvCvà@@C@°CxxCàG>@? >GK°àG?°GàG==G=@=>G>@>G>G??@?G?@G@°vGvGtGtGàG?°Gvvà@?G>@>`=G?G=?=G=°G°xàC=°CxCKà@=°CàC> >?C?C@@C?@?°zCz àC@@°Cxx CCvv CttCCrrCppC$$Cnn C11Cll 9C92CnnC,,pCprCrC  tCtCvCv CxxGKCàC=°Gà=G=@=>G>G>@>G??G?@?@G@"°vGvGtt GrrG GttvGvG""xGxGàG?CK°Cà ?GàC@@°CzzCxxvCvtCtCrrCppCnnCCCpprCrCttCvvà@?°xàC?°CCxà ?Cà@BKàC@C?B@@°BzzxBxBvvBttBrrBppBnnBBpprBrtBtBvvxàB?@?°BBxà@B@Kà`@BAB@A@@@@@N°@zz@@  @xx v@vt@t@r@rp@pn@n@ l@l&$@$"n@n"@pp@rrt@t+@+v@vx@xZv@v%@%@ttr@r@pp @ @nn @à@?@?°p@pà@??°r@rà@>°t@tà@>°và@>°@và>@=°@xxà@=@K°à@@@°@@`@=K`à===à=@K à@=@= >@>@>@> ?@?°@zzà@?@?@@@°x@xv@v@ttr@rp@pn@n@llj@jh@h@ff  @ @dd@f@f@ @hh j@j l@l n@np@pr@rp@p @nn@ll j@j @ l@l @nnpà@?°@@pà@?°@rrt@tv@và@??@>@>°x@x@àE>@°EKà@>@@°Eà?E?E?@?E@@°vEvEttErrpEpEnn Ell EEEnnEppErrtEtEvà@@°EvàE@°xExEàL@LKà@`>L>`==L=L= @=L=>L>L>@>?L?@?L?L@@°vLv tLt  rLrL LppLrLrLtà@?°tàL?°Là`>L> >°LvàL=`=°vàL> =L<`<L=@=°xà`>JKàJ=J>°JxLàJ@@B°JvvJ  0Jà?JK°xàJ?°JxJàJ?°JYà@?@J@ °JzzJX JxxJWJvJ[vJttJrJr JZ J JppJYJXrJrJJttJW JVJJUJ$$ JrrJTpJpJJnnJSJRpJp rJrJJQJttJvvJxàJ?°xà@?°JàJ@@° JPJO JN JMJL JK JJJI JH JGJF JE JDJC JB JAJ@ J? J>J= J<J;‚0JŸ@>>0>Œ0<0<Œ0<0<ÿ/MTrkACÊÿJAZ2ÿGeneral MIDIÿ @Hÿ  ºÿMelodyÀ@šBKê? B@&ºBBwBu BsBqB B(BsBuBBwêB? ºBêB=šEKBêB@E=E>E>ºEy êE?E?E@4ºEwEu EsEq Eo Em EkEiE EE EkEEmEoEqEs:EqEoEm E EoEEqêE?ºEs EuêE?ºEwêE>E?ºEyšBKºEšE êB@ ºB{By BwBuBsBq Bo BBmB BoBqBsB BuBwêB? šEKêB@ºBêB=šBêE=E>E>ºEy êE?ºE{êE?E@(ºEy EwEuEsEqEoEmEkEi Eg Ee E EcEEEeEEgEiEkEm EoEq8Eo Em EkEi E EkEmE EoêE?ºEqEsEuêE?ºEwêE>E@šJKºEyEêJ>šEêJ?J?J@ºJwJuJsJq JJoJJqJsJuêJ@ºJwêL?L>ºJšJLKêL=L=L>L>L?L?L@ºLuLLsLLuêL?L>L=L?ºLwêL=J=šLºLšJKêJ>J?J@J?ºJyJ{êJ@ºJyJJw Ju JJs Jq JoJ Jm J($Jk J/*JmJoJ% Jq J Js JuJ JwšJêL@ºJêJ?šLKºLyLw LuLs LLLu Lw LêL?ºLyšLJKêJ@ºJ{JyJwJuJsJqJoJm JJoJqJsJuJwJêJ?J?šJºJyšIKêJ@I@ºIwIuIsIqIoIIIqIsIuIwIêI?I@G@šGKêIAšIêG@8ºGy$G{GGy GwGuGGsGqGoGmG0GºGuêG>ºGwêG=G?šBKGºByêB@.ºBwBuBs BBqBBsBuB BwêB? B@šBêB=ºBšCKêC=C=C>ºCyêC>C?ºC{ êC@(ºCy CwCuCsCqCoCmCkCi Cg Ce C CcCCCeCg CCiCkCm CoCq8Co Cm CkCi C CkCCm CoêC?ºCqCsCuêC?ºCwêC>ºCyêC?šC@KºC ê@@ º@{@y @w@u @s@q @o@@m@@o@q@s@ @u@wê@? šCKê@@@=º@š@êC=C>C>ºCy êC?C?C@ºC{$Cy CwCuCsCqCoCm Ck CiCgC CCC CiCkCmCo CqCs$CqCo CmCk C Cm CCo CqêC? ºCsCuêC?ºCwêC>I@šIKCêC?ºCIyIwIuIsIqI IsIuIwêI?I@ºIšIGK`EKGêG@E@E?ºEy E{E} êE@ºE{Ey EwEuE EsEqEoEEmEk EiE&HEk Em EoEEq EsEEuEw šEEKêE@ºEêE?ºEy,EwE Eu Es EqêE?E?ºEsEuêE>ºEwšEEKºEEyêE?E?E@ ºEwE Eu Es EqEsEuEEwš@KEê@?@@8º@u@ 0@@w@šBKê@?š@êB@ºByBwBu BsBqBoBBqBBs BuBwêB?ºBšBêB=B@šBKêB= ºByêB=B>B>B?ºBwêB@ºBu BsB Bq B BoBBmDB Bo BBq BsB BuBFBsBBqBoBmBk BBiB Bk BmBBoBqBsBuBw šBKêB?ºByšBºB êB@ºB{By BwBuBs BqBo BmB B"BoBqBsBBuBwêB? šBêB@ºBšEKêB=E=E=E> E>ºEy êE?E@4ºEw Eu EsEqEoEmEkE EEEEmEoEqEsPEqEo,E EqEEsêE?ºEuêE?ºEwêE>ºEšEêE?šBKºByêB@.ºBw BuBBsBBqB"Bs BuB BwêB? ºBêB@šEKêB=šBêE=E>ºEyêE> E?ºE{êE?E@(ºEy EwEuEsEqEoEmEk Ei EgEeE EEEEgEiEkEm EoEq:Eo Em EkEiE EkEmE EoêE?ºEqEsEuêE?ºEwêE>šJKêE@ºEzEšEêE>J>J?J@ºJxJvJtJrJpJnJlJ JJnJpJrJtêJ@ºJvJxšJºJêL>šLKêL?L=L=L>L>L?L?L@ºLvLtL!LrLp LLrêL?ºLtêL=ºLvêL>L?L=šLêJ=šJKºLêJ>ºJxêJ?J@J?ºJzJ|J~êJ@ºJ|JzJxJJv JtJrJJpJnJlJJjJhJ(Jf J02JhJjJ%Jl Jn J Jp JrJJtJvšJêJ@šJKºJJyêJ?ºJ{JyJwJuJJsJqJo Jm êJ?ºJoêJ?ºJqêJ>ºJsJuJJwJyšJJKêJ?J?J@ºJwJJuJsJqJoJmJoJqJsJJuJwšJIKêI?I@ºIyIw Iu IsI IqIsIIuIxIšGKêIAšIêG@G@BºGzGG|GzG GxGvGtGrGGpGnGlGjGhG Gf&G#GhGjGlGnGpGrG*GtGvGxPGv G$Gt Gr Gp GnGlG GjGGhGjêG?ºGlêG?ºGnGpêG>ºGrGtêG>ºGvêG=ºGxêG?šBKºGšG êB@ºBzBxBv BtBr B BpB Br BtBBvêB?ºBx êB@ºBêB=šCKBêC=C>C> C? ºCzêC?C@,ºCx CvCtCrCpCn ClCj ChCfCdCC0CCfChCjClCnCpCr$CpCn ClCj*C ClCCnêC?ºCp CrCtêC?ºCvCxêC>C?š@KºCšC ê@@º@z$@x@v@t @r @p @n@@"@p@r@t@ @v@xê@? @@º@ê@=šCK@êC=C>C> C?ºCzêC?C@*ºCxCv CtCr Cp Cn ClCjC CCC ClCnCpCrC%Ct(CrCpCnC C CpC CrêC? ºCt CvêC?ºCxêC>C@šCêC>ºCzšGKºCêG>G?G@ºGxGvGtGrGpGnGlGGGnGpGrGtGvêG@ºGxšIKêI?ºGšGêI>I=I=I>I>I?I?I@ºIvItIIrIpIIrItêI?I=I?I>ºIvêI=šIEKêE>ºIêE=E>ºExêE@E?E?ºE{ E}êE@ºE{ExEvEEtErEpEEnElEjE,EhE2EjElE%En Ep ErEEt Ew EyêE?šEKEºEêE@ºE{EyEwEuE EsEqEoEmêE?E?ºEoEqêE>ºEsEuEwšEKºEEyšEêE?E?E@ºEwE EuEsEqEoEmEoEqEsEEuEwšEKEêE?E@ºEyEw Eu EsE EqEsEEušEºEêE?š=KºEyê=@º=w=u=s=q ="=s=u=w=ê=?=@==š>K=º>yê>=>>>> >?>?º>wê>@º>u >s >>q >o >m> >k> >i>H>> >k>m>>o>q>>s>0>"4>q">o>m>k>i>g >e>>c >>e> >g>i>k>m>>o>q>s>u>wšJKêJ=J=J>ºJyêJ>J?J@4ºJwJu JsJq Jo Jm JkJ JiJJ JkJJmJoJqJsš>*º>q>o>m > >o>>qê>?º>s >uê>?º>wê>>ºJêJ?šLKºJyšJ êL@ ºL{Ly LwLu LsLq LoL LmLLoLqLsL LuLwêL? G@L@šGKêLAºLšLêG@ºGy0G{&GGyGwGuGsGGqGoGmGkGiGGg,G,GiGkGm GoGqG!Gs Gu Gw^GuGs GqGGo GmG Gk Gi GêG?ºGkGGmêG?ºGoêG>ºGqGsêG>ºGwGuêG=G?šGêI@šIK ºIyIwIuIsI IqIsIuIwêI?I@ºIšJKI`êJ@šIKJêI@ I?ºIyI{êI@ºIyIIwIu IIsIqIIoI$fIqIsIIuIwIšJKºIIyêI?šIêJ@ºJ{JyJwJuJsJqJo JmJJo JqJsJuJwJêJ?šIKêJ@šJêI?ºIyêI@ºIw Iu IsIqIIs IuIwIêI?šIêI@ºIyêI?šGKêG@ºGwGuGGsGq GG GsGuGwêG?ºGšGêGAšEKêG@E@E@ ºEy4E{EEy EwEuEsEEqEoEmEkE0E!8EmEoEqEsE'Eu EwfEuE"Es Eq EoE EmEkEêE?ºEmEoêE?ºEqêE>ºEsEuêE>ºEwêE=E>šEºEyêE@šCKºEêC>C?C@ºCwCuCsCqCoC CmCCoCqCsCuCwêC@šCGKêG?G>ºCêG=G=G>G>G?G?G@ºGuGGs GqGGsGuêG?G>G=G?G=ºGwGšCKêC=šGêC>C?C@C? ºCyC{êC@ºCyCCwCuCs CCqCoCmC#CkCiC/CgC7(CiCkC*CmCoC CqCsCCuCw šGKCºCêC=G=G>G>G?G?G@.ºGu GGwGGšCKGêG?ºGGyêC@ºC{CyCwCuCsCCqCo CCCqCsCuCwêC?ºCêC@šCBKêB?ºByêB@ ºBwBu BsBB BuBwBêB?B@@@šB@KêBA@@@º@y@&@w@u@@s@q@o@0@!D@q@s@u@' @wl@" @u@s@q@ @o @ê@?º@qê@?º@sê@>º@uê@>º@wê@=š@@Kê@@º@`š=K@`ê==š=@K ê@= @>@>º@yê@? º@{ê@?@@º@y@w@u@s@q@o@m@k@i@g @e@ @@@g @i @k @m @o @q @s@q @o@m@k@ @m @oê@?º@@q@s@uê@?º@wê@>@?º@š@=Kº=yê=@º=w =u =s=q==s =u=wê=?º==yš=ê=?š@Kê=@@@4º@w @u@@s@q@oê@?@?º@q@sê@>º@u@@w@yš@@Kê@?@?@@º@w@@u @s@q@o@q@s@@u@w@{š@ê@9šEK êE9 E9ºEy êE: E:ºEwêE;E<ºEuêE<ºEsêE=E=ºEqêE>ºEoêE>ºEmêE?ºEk êE?ºEi êE@ºEE EEkEEm8EoE HE&HE+XEmE"E EkEiE EgEeE êE?ºEgEEiEkEmêE?ºEoEEqEsEuêE>E>ºExšEêE=šJKêJ=J>J> J?ºJzêJ?J@*ºJxJvJtJrJp Jn Jl JjJJhJJJjJJlJnJpJrJt JrJpJnJlJ JnJJp êJ?ºJr JtêJ?ºJvJxêJ>šLKºJêJ?šJ êL@ºLz$LxLvLt Lr Lp LnL L"LpLrLtLLvLxêL? LAºLšGKêL@šLêG@G@DºGzG|GGz GxGvGtGrGGpGnGlGjGGh*G"(GjGlGn GpGr G)Gt GvGxPGv G#Gt Gr Gp GnG Gl Gj GêG?ºGlGnêG?ºGpêG>ºGrGtêG>ºGvêG=ºGxêG?šGºGšIKêI@ ºIv ItI Iv IxêI?I@šJKºIšI`êJ@šJIKêI@ I?ºIzI|êI@ºIzIxIIv ItIrI IpIn IlI Ij IIhHIjIlIn IpIIr It IIv Ix šJKêI?ºIšIêJ@ºJzJx Jv Jt Jr J"JtJvJxêJ?ºJêJ@šJIKêI?I@ºIzIxIvItIrIpInIIpIrItIvêI?ºIIxšGKIêI?I@ºGzêG@ºGxGvGtGrGGpGnGlGGGn GpGrGtGvGxGêG?GAšEKêG@šGêE@E@BºEzE|EzEExEvEtErEEpEnElEjEhE Ef&EEhEjElEnEpErE!EtEvExPEvEt ErEEp EnElE EjEEhEjêE?ºElEEnêE?ºEpêE>ºErEtEvêE>ºExêE=E>E@C>šCKEêC?C?C@ºCvCtCr C C CtCvêC@ºCxêG?G>šGKºCšCêG=G=G>G>G?G?G@ºGvGGtGêG?ºGvêG>G?G=G=ºGšCKºCxêC=šGêC>C?C@C?ºCz êC@ºCx CCv CtCCrCpC$Cn C1Cl C92CnC,CpCrC CtCCv CxêC=šCGKºCêG=G>G>G?G?G@"ºGvGt GrG GtGvG"GxGšGCKºGêG?C@ºCzCxCvCtCrCpCnCCCpCrCtCvêC?ºCCxêC?šBKêC@šCêB@ºBzBxBvBtBrBpBnBBpBrBtBvBBxêB?š@Kê@@B@šBêBA@@Nº@z@@ @x @v@t@@r@p@n@ @l&@$"@n"@p@r@t@+@v@xZ@v@%@t@r@p@ @n @ê@?º@pê@?º@rê@>º@t@vê@>º@xê@=š@º@š@Kê@@`š@=K`=@Kê== @= @>@> @?º@zê@?@@º@x@v@t@r@p@n@l@j@h@f @ @d@@f@ @h @j @l @n@p@r@p @n@l @j@ @l @nê@?º@@p@r@tê@?º@v@xê@>@@šEKº@êE>š@êE?E?E@ºEvEtErEpEn El EEEnEpErEtEêE@ºEvExêL>šLKêL@šEêL=L= L=L>L>L?L?L@ºLv Lt LrL LpLLrêL?ºLtLêL>L>ºLvêL=L=L<J=ºJxêJ>šJKLêJ@BºJvJ 0JšJºJxšJKêJ?J?J@ ºJzJx JvJtJJrJ Jp2JrJJt(JJ$ JrJpJJn4Jp JrJJtJvêJ?ºJxJêJ@ƒšJº8BK@êB=B@ºEšBEKêE=E>E>ºEy êE?E?E@4ºEwEu EsEq Eo Em EkE EiEE EkEEmEoEqEs:EqEoEm E EoEEqêE?ºEs EuêE?ºEw šEêE?ºByšBKºB êB@ ºB{By BwBuBsBq Bo BBmB BoBqBsB BuBwêB? B@B=šEKBºEEyêE? E@E=E>E>ºEyEEwêE?ºEu E{êE?ºEsêE@ºEqE EEy EwEuEsEqEsEoEmEEuEkEwêE?ºEi Eg Ee E EcEEEeEEgEiEkEm EoEq8Eo Em EkEi E EkEEm EoêE?ºEqEsêE?ºEuEwêE>J>šJKEºJyêE@ºJêJ?J?J@ºJwJuJsJq JJoJJqJsJuJwêJ@šLKêL?šJêL>ºLêL=L=L>L>L?L?L@ºLuLLsLLuêL?L=L?L>L>L=ºLwêJ=šLJKºJêJ>J?J@J?ºJyJ{êJ@ºJyJwJ Ju JJs Jq JoJ Jm J($Jk J/*JmJoJ% Jq J Js JuJ JwêJ?L@ºLšJLKºLyLw LuLs LLLu Lw LêL?šLJKºJyêJ@ºJ{JyJwJuJsJqJoJm JJoJqJsJuJwJêJ?ºIyšIKêJ@J?šJêI@ºIwIuIsIqIoIIIqIsIuIwêI?ºIêG@IAšIGKêI@G@8ºGy$G{GGy GwGuGGsGqGoGmG0GºGuêG>ºGwêG=šGBKêG?ºByêB@.ºBwBuBs BBqBBsBuB BwêB? B=šBêB@šCKºCêC=C=C>ºCyêC>C?ºC{ êC@(ºCy CwCuCsCqCoCmCkCi Cg Ce C CcCCCeCg CCiCkCm CoCq8Co Cm CkCi C CkCCm CoêC?ºCqCsCuêC?ºCwêC>º@š@KêC?º@yšC ê@@ º@{@y @w@u @s@q @o@@m@@o@q@s@ @u@wê@? šCKê@=@@ºCš@êC=C>C>ºCy êC?C?C@ºC{$Cy CwCuCsCqCoCm Ck CiCgC CCC CiCkCmCo CqCs$CqCo CmCk C Cm CCo CqêC? ºCsCuêC?ºCwêC>C?I@šIKºIšCºIyIwIuIsIqI IsIuIwêI?šGKêI@ºGšI`êG@šEKGêE@E?ºEy E{E} êE@ºE{Ey EwEuE EsEqEoEmEEk EiE&HEk Em EoEEq EsEEuEw EšEêE?E@šEKºEy,EwE Eu Es EqêE?ºEsêE?E>ºEuEwEšEEKºEyêE?E?E@ ºEwE Eu Es EqEsEuEEwšE@Kê@?@@8º@u@ 0@@wBš@BKê@?B@ºByBwBu BsBqBoBBqBBs BuBwêB?ºBšBBKêB=B@B= ºByêB=B>B>B?ºBwêB@ºBu BsB Bq B BoBBmDB Bo BBq BsB BBuFBsBBqBoBmBk BBiB Bk BmBBoBqBsBuBw šBKêB?ºBšBºBy êB@ºB{By BwBuBs BqBo BmB B"BoBqBsBBuBwêB? ºEšEKêB=šBêB@E=E=E> E>ºEy êE?E@4ºEw Eu EsEqEoEmEkE EEEEmEoEqEsPEqEo,E EqEEsêE?ºEuêE?ºEwêE>šBKêE?ºBšEºByêB@.ºBw BuBBsBBqB"Bs BuB BwêB? B@ºEêB=šEKBêE=E>ºEyêE> E?ºE{êE?E@(ºEy EwEuEsEqEoEmEk Ei EgEeE EEEEgEiEkEm EoEq:Eo Em EkEiE EkEmE EoêE?ºEqEsêE?ºEuEwêE>šJKºJzêE>E@ºJšEêJ>J?J@ºJxJvJtJrJpJnJlJ JJnJpJrJtêJ@ºJvJxšLKêL?L>ºLšJêL=L=L>L>L?L?L@ºLvLtL!LrLp LLrLtêL?L?L>L=ºLvêL=ºJšJKêJ=šLêJ>ºJxêJ?J@J?ºJzJ|J~êJ@ºJ|JzJxJJv JtJrJJpJnJlJJjJhJ(Jf J02JhJjJ%Jl Jn J Jp JrJJtJvJêJ?J@šJKºJyšJºJ{JyJwJuJsJJqJo Jm êJ?ºJoêJ?ºJqêJ>ºJsJJuJwšJKºJyšJêJ?J?J@ºJwJJuJsJqJoJmJoJqJsJJuJwšJIKêI?I@ºIyIw Iu IsI IqIsIIuGxšGKêIAºGšIêG@G@BºGzGG|GzG GxGvGtGrGGpGnGlGjGhG Gf&G#GhGjGlGnGpGrG*GtGvGxPGv G$Gt Gr Gp GnGlG GjGGhêG?ºGjGlêG?ºGnGpêG>ºGrGtGvêG>G=ºGxšGêG?šBKºB êB@ºBzBxBv BtBr B BpB Br BtBBvBxêB? šBºCêB@šCKêB=C=C>C> C? ºCzêC?C@,ºCx CvCtCrCpCn ClCj ChCfCdCC0CCfChCjClCnCpCr$CpCn ClCj*C ClCCnêC?ºCp CrCtêC?ºCvCxêC>º@šCêC?š@K ê@@º@z$@x@v@t @r @p @@n@"@p@r@t@ @vê@?º@x šCKºCê@=@@š@êC=C>C> C?ºCzêC?C@*ºCxCv CtCr Cp Cn ClCjC CCC ClCnCpCrC%Ct(CrCpCnC C CpC CrêC? ºCt CvêC?ºCxêC>šCGKºGzGêC@C>G>G?G@ºGxGvGtGrGpGnGlGGGnGpGrGtGvêG@ºGxIêI>I?šIKGêI=I=I>I>I?I?I@ºIvItIIrIpIIrItêI?I>I?I=I=ºIvêE>ºEšEKIêE=E>E?ºExêE@E?ºE{ E}êE@ºE{ExEvEEtErEpEEnElEjE,EhE2EjElEnE% Ep ErEEt Ew EyEšEEKêE?E@ºE{EyEwEuE EsEqEoEmêE?ºEoêE?ºEqEsêE>ºEuEwEEyšEKEêE?E?E@ºEwE EuEsEqEoEmEoEqEsEEuEwšEKEêE?E@ºEyEw Eu EsE EqEsEEušE=Kº=y=êE?=@º=w=u=s=q ="=s=u=wê=?º=ê==š>Kê=@š=º>yê>=>>>> >?>?º>wê>@º>u >s >>q >o >m> >k> >i>H>> >k>m>>o>q>>s>0>"4>q">o>m>k>i>g >e>>c >>e> >g>i>k>m>o>>q>s>u>wšJKê>@>=J=J=J>ºJyêJ>J?J@4ºJwJu JsJq Jo Jm JkJ JiJJ JkJJmJoJqJsš>6º>q>o>m > >o>>qê>?º>s >uê>?º>wê>>šJºLyLšLKêJ? L@ ºL{Ly LwLu LsLq LoL LmLLoLqLsL LuLwêL? L@šLGKêG@ºGêLAG@ºGy0G{&GGyGwGuGsGqGGoGmGkGiGGg,G,GiGkGm GoGqGsG! Gu Gw^GuGs GqGGo GmG Gk Gi GêG?ºGkGmGêG?ºGoGqêG>ºGsGuGwêG>G=šIKêG?šGêG@ ºIyIwIuIsI IqIsIuIwêI?šJKºJêI@šI`JêJ@šIKêI@ I?ºIyI{êI@ºIyIwIIu IIsIqIIoI$fIqIsIIuIIwêI?ºJyšJKºJšIêJ@ºJ{JyJwJuJsJqJo JmJJo JqJsJuJwêJ?ºJêJ@šJIKêI?ºIyêI@ºIw Iu IsIqIIs IuIwêI?ºIšIêI?šGKºGyêI@G@ºGwGuGGsGq GG GsGuGwêG?ºGêG@šGêGAšEKêE@E@ ºEy4E{EEy EwEuEsEEqEoEmEkE0E!8EmEoEqEsE'Eu EwfEuE"Es Eq EoE EmEEkêE?ºEmEoêE?ºEqêE>ºEsêE>ºEwEuêE=šECKêE@ºCCyêE>C>C?C@ºCwCuCsCqCoC CmCCoCqCsCuêC@ºCwêG?šGKêG>ºGšCêG=G=G>G>G?G?G@ºGuGGs GqGGsêG?ºGuêG=G?G>ºGwêG=šCKºCšGêC=C>C?C@C? ºCyC{êC@ºCyCwCCuCs CCqCoCmC#CkCiC/CgC7(CiCkC*CmCoC CqCsCCuCw GšCGKêC=G=G>G>G?G?G@.ºGu GGwGGšCKGêG?ºCCyêC@ºC{CyCwCuCCsCqCo CCCqCsCuCwêC?ºCêC@šBKCêB?B@ºBy BwBu BsBB BuBwBêB?@@šBêBAB@š@Kê@@@º@y@&@w@u@@s@q@o@0@!D@q@s@u@' @wl@" @u@s@q@ @o @ê@?º@qê@?º@sê@>º@uê@>º@wê@=º@š@Kê@@š@`=K@`@Kê==š= ê@= @>@>º@yê@? @?º@{ê@@º@y@w@u@s@q@o@m@k@i@g @e@ @@@g @i @k @m @o @q @s@q @o@m@k@ @m @o@ê@?º@q@sê@?º@u@wê@>š@º=š=Kê@?º=yê=@º=w =u =s=q==s =u=w=ê=?=?š@Kº@yê=@š=ê@@4º@w @u@@s@q@oê@?º@qê@?º@sê@>º@u@@w@yš@K@ê@?@?@@º@w@@u @s@q@o@q@s@@u@wšEKê@9š@ºE{ êE9 E9ºEy êE: E:ºEwêE;E<ºEuêE<ºEsêE=E=ºEqêE>ºEoêE>ºEmêE?ºEk êE?ºEi êE@ºEE EEkEEm8EoE HE&HE+XEmE"E EkEiE EgEeE êE?ºEgEEiEkEmêE?ºEoEEqEsEuêE>E>ºJxšJKêE=šEêJ=J>J> J?ºJzêJ?J@*ºJxJvJtJrJp Jn Jl JjJJhJJJjJJlJnJpJrJt JrJpJnJlJ JnJJp êJ?ºJr JtJvêJ?ºJxêJ>šJLKêJ?ºL êL@ºLz$LxLvLt Lr Lp LnL L"LpLrLtLLvLxêL? LAšLGKºGêL@G@G@DºGzGG|Gz GxGvGtGrGGpGnGlGjGGh*G"(GjGlGn GpGr G)Gt GvGxPGv G#Gt Gr Gp GnG Gl Gj GêG?ºGlGnêG?ºGpGrêG>ºGtêG>ºGvGxêG=šIKGºIêG@G? ºIv ItI Iv IxêI?šIºJêI@šJK`JIKêJ@I@ I?ºIzI|êI@ºIzIxIIv ItIrI IpIn IlI Ij IIhHIjIlIn IpIIr It IIv Ix šIêI?šJKºJêJ@ºJzJx Jv Jt Jr J"JtJvJxêJ?ºJêJ@šIKJêI?I@ºIzIxIvItIrIpInIIpIrItIvIIxêI?I?šGKêI@šIêG@ºGzGxGvGtGrGGpGnGlGGGn GpGrGtGvêG?ºGGxšEKêG@šGêGAE@E@BºEzE|EEzExEvEtErEEpEnElEjEhE Ef&EEhEjElEnEpErE!EtEvExPEvEt ErEEp EnElE EjEhEêE?ºEjElEêE?ºEnEpêE>ºErEtêE>ºEvExêE=E@E>šEêE>šCKêC?C?C@ºCvCtCr C C CtCvêC@ºCxšCGKºGêG>G?G=G=G>G>G?G?G@ºGvGGtGGvêG?G=G>G?G=šGêC=ºCxCšCKêC>C?C@C?ºCz êC@ºCx CCv CtCCrCpC$Cn C1Cl C92CnC,CpCrC CtCCv CxGêC=šCGKêG=G>G>G?G?G@"ºGvGt GrG GtGvG"GxGšGºCšCKêG?C@ºCzCxCvCtCrCpCnCCCpCrCtCvCxêC?ºCšCêC@C?šBKêB@ºBzBxBvBtBrBpBnBBpBrBtBvBBxêB?šBêBAB@š@Kê@@@@Nº@z@@ @x @v@t@@r@p@n@ @l&@$"@n"@p@r@t@+@v@xZ@v@%@t@r@p@ @n @ê@?º@pê@?º@rê@>º@t@vê@>º@xê@=@@º@š@@K`=K@`=@Kê== @= @>@> @?º@zê@?@@º@x@v@t@r@p@n@l@j@h@f @ @d@@f@ @h @j @l @n@p@r@p @n@l @j@ @l @n@pê@?º@@r@t@vê@?@>º@xEšEKêE>@@š@êE?E?E@ºEvEtErEpEn El EEEnEpErEtEEvêE@ºExšLKêL@L>šEêL=L= L=L>L>L?L?L@ºLv Lt L Lr LpLLrêL?ºLLtêL>L>L=ºLvêL<L=J=J>ºJxšLJKêJ@BºJvJ 0JêJ?ºJxšJKJºJYêJ?J@ ºJzJX JxJWJ[JvJtJJr JZJ JpJYJXJrJJtJW JVJJ$JU JrJpJTJJnJSJRJp JrJJQJtJvêJ?ºJxêJ@ºJ JPJO JN JMJL JK JJJI JH JGJF JE JDJC JB JAJ@ J? J>J= J<J;‚0šJŸ@>>0>Œ0<0<Œ0<0<ÿ/MTrk¿±ÁÿJAZ2±@ÿGeneral MIDIÿ1ÿYÿY±x "[2]2}HKÿ @±J<Cƒ "[2HK]2@xJ<CÁ›`±@‘7'`;$`>)7;>±@0@‘71`;2`>HP>;7±@p‘7'±@`‘;$`>)7;±@‘>071±@`‘;2`>HP>±@‘;798±@`‘=(`@6 =@=9@CF‚ 998`=(=0@0@6 =@=9@CFC‚09 21063 =±@‘@09,=C±@`‘=06>GC@6M@9P±@‘>62±@‘9/:±@ "x]2CÁ±[2HKJ<‘9_7!±@`‘;`>#7;±@‘>07*±@`‘;*`>7p7!±@`‘;`>#;7>±@0@‘7*`;*`>±@‘7/±@`‘;"`>. ;@;0`;±@`‘C;±@‚ ‘9/7P="0>0@. =@=0@C;C‚09P2' =@06"`9%P6`96(`93 ±@‘C@>8±@P‘29±@‘6>20±@`‘62`95`>8‡ 2 2.6@96`9->P±@‘962>,±@‘B&2"`6.`>9)`>2P6B±@ ‘9`2 @,±@`‘2+@@ >6&P6>8`6 `6±@‘>@!±@`‘E5 E2±@‘@ ±@‘90@>2`B5`G8„@7!`;`>#>7;>9 7*PB;*`><GP;±@‘>7±@‘70`;2`>5`C8ƒ`CC6±@‘;±@`‘=9`C@:`C:`=@7 =.@ C >@$@@±@‘= ±@‘9"I&C,C06.`9)9`=2P6± "J<Á±]2HKx@[2Cƒ@‘70I=`;2`>5`C8`>Cƒ±@‘79ƒ`±@‘7.;P;`>-P±@‘>;7=&±@‘E,9"`==.`@)E`E2P=0@`9 B,`2+@B E6&P6>8`6 `±@‘9!>±@‘6P>5 2>9±@ @‘20@;2`>5`C8ƒ`C6±@@‘C;`=9`C@:`C:`=@2 =.@ C >@$@±@‘=@ ±@‘9"I&C,CPC6`=9`@:C`C:`=`=.@ C0@$@=@9 I9"C,I&C±@0‘6.±@`‘9)9`=2P609‚9,P=I9±@‘70±@`‘;2`>5`C8ƒ`±@‘7Cƒ`±@‘7.;@>;`>-P>;±@‘7±@‘9"E,=&`=.=`@)E`E2P=0@`9 B,`2+@B E6&P6>8`6 `>±@@‘9!6P>5 29±@‘> ±@‘20@;2`>5`C8ƒ`±@‘;±@‘C6C`=9`C@:`C:`=@2 =.@ C >@$@±@‘@= C,±@‘I&9"CPC6`=9`@:C`C:`=`=.@ C0@$@@=9 II&9"C,±@‘C06.±@`‘99)`=2P6±[2C@xHK]2Á±J< "ƒ‘=I02,±@0‘6.`>;9'`>06>D@6J@9P>6±@‘292±@:‘2=>FP>>G2906M`239_656@6>69;`>>2 621±@‘9P6(±@0‘209#`23P6965@6 9;6`>>>2 6219P6(0209#`6±@P‘97'±@`‘;$`>>)7;>±@0‘71±@`‘;2`>HP;>7±@p@‘7'`;$`>);7>±@0@‘71`;2`>HP>;7±@@‘98`=(`@6 =@=9@CF‚ 989`==(0@0@6 =@=9@CCF‚09P2/ =±@‘@06(±@`‘9,P6±@ "xÁ±]2J<[2CHKƒ‘C±@‘26`68`9;`>?‡ 2 2.6@96`9->P29±@‘6±@‘E&2B,96"`9.`B=)`B2P90=`6 9,`7+@9 B;&P;B8`; `±@‘B>!±@‘;PC5 7C>±@‘E ±@‘70@;2`>5`C8ƒ`C6C`;;9`>>:C`C:`;±@@‘7 =.±@‘> C0@$@=±@‘@ 9"C,±@‘I&CPC6`=9`@:C`C:`=`=.@ C0@$@9=@ I&C,I9"±@‘C06.±@`‘9)9`=2P609‚9,P=±@‘I9±@‘20`62`95`>8‡ 2 2.6@96`>9-P29±@‘6B&±@‘>,2"`6.`>9)`>2P6±@‘B 9`2 ±@‘@,`2+@@ 6&>P6>8`6 `±@@‘6>@!`E5 ±@‘2@E ±@‘90@>2`B5`G8‡ 9 7.>@B;`G>-P;7>±@‘C3;-±@@‘; 7-`;1CPC+G+;0;*0C0>,0; 7C/`±@‘GCC6±@@‘> =9`@:C`C:`=`=.@ C0@$@=±@‘@ C,±@‘I&9"C06.`99)`=2P6±]2CxHK@ "J<Á±[2ƒ@‘=I20`62`95`>8ƒ`±@‘6ƒ@2 7.±@P‘9;`>->P±@‘7;>9"9=&E,±@`‘=.=`E@)`E2P=0@`9 @,`2+@@ 6&EP6=8`6 `=9!±@@‘6P>5 2>±@‘9 ±@‘20@;2`>5`C8‡ 2 9.;@>=`@-CP9=@±@@‘=-E3@= 9-`=1EPI+E+=0=*0E0@,0= 9E/`9$@E@I=%`E4I%±@‘=P±@‘= `@#E`C4 =p@I9±@‘C±@‘20`62`95`=8ƒ`6±@‘=ƒ@2 7.±@P‘9;`>-P>;7±@‘=&9"±@‘E,`==.`E@)`E2P=0@`9 @,`2+@@ E6&P6=8`6 `=±@‘9!±@‘6P>5 ±@‘>29 20±@@‘;2`>5`C8‡ 2 9.;@>=`C@-P9=±@‘@E3=-±@@‘= 9-`=1EPI+E+=P±@‘I`>*±@0‘E0@,0> 9C/`2-@@C 6/@6 936`>72 62.9P6&0209!`2-P±@‘69±@‘6/@6 693`>7>2 62*9P6"0209`±@‘6P97"±@`‘; `>$>;7±@‘>07.±@`‘;/`>DP7>;±@p@‘7'`;$`>)7;>±@0‘71±@`‘;2`>HP7±@‘;>±@‘98`=(`@6 =@=9@CF‚09 910==30@0CC@,C`C0=CG@=M@@±@P‘9C=±@‘9/:± "J<]2@HKC[2xÁƒ‘23±@`‘65`98`>;ƒ`22-`6/6@6 9369_>7>2P69±@`‘4.±@‘9P7&040;!0;7<"`@ `C$@<C0<*`@*`C±@‘21`6$`90 6@63@>B‚ >69±}‘2±|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@ÿ/MTrk²Â!ÿJAZ2²]ÿGeneral MIDIÿ2ÿYÿY²x @[J<@HK}ÿ @²Cƒx[@HK] @J<CÂ!›’+L‚`+ &K‚P&0+L‚`+ &K‚P&0!T‚0!P(W‚@(@!T‚0!P(W‚@(@&@@&`&U &@!L‚0!P&D@&!G0!²@] @xHK[Â!²CJ<’+A‚`+ &?‚P&0+A‚`+ &?‚P&0+G‚0+P(L‚@(@!G‚0!P(L‚@(@&D‚p&!@ !@!/P!&]P&!H!P&G‚P&0!8‚ !`&A‚`& !?‚P!0&G‚0&P(?‚@(@&D‚p&(5 (@(%P(!GP!(6(P#G‚0#P!?‚@!@+A‚`+ &?‚P&0+G‚P+0&8‚ &`!G‚P!0(D‚ (`&;`&@&;0&0² @x@][CÂ!²J<HKƒ’+G‚P+0(8‚ (`#A‚`# &?‚P&0!G‚0!P*?‚@*@&D‚p&!5 !@!%P!&GP&!6!P+G‚0+P&?‚@&@!G‚P!0(D‚ (`!G‚P!0(D‚ (`&;`&@&;0&0!G`!@!<@! +G‚P+0(8‚ (`#A‚`# &?‚P&0!G‚0!P*?‚@*@&D‚p&!5 !@!%P!&GP&!6!P+G‚0+P&?‚@&@!G‚P!0(D‚ (`!G‚P!0(D‚ (`&;`&@&;0&0²J< @HKÂ!²Cx@][ƒ’&9@&`&M &@!H‚0!P&H@&!K0!&bP&‚0&T‚P&0!C‚ !`&T‚P&0!C‚ !`+L‚`+ &K‚P&0+L‚`+ &K‚P&0!T‚0!P(W‚@(@!T‚0!P(W‚@(@&P‚p&²J<[] @CÂ!²@HKxƒ’&O‚P&0!;‚ !`&A‚`& !?‚P!0*G‚0*P!?‚@!@+D‚p+&5 &@&%P&+GP+&6&P+G‚0+P&?‚@&@+G‚P+0(D‚ (`!G‚P!0(D‚ (`&;`&@&;0&0!G`!@!<@! &G‚P&0!8‚ !`&A‚`& !?‚P!0&G‚0&P(?‚@(@&D‚p&(5 (@(%P(!GP!(6(P#G‚0#P!?‚@!@+D‚p+&5 &@&%P&+GP+&6&P+G‚0+P&?‚@&@!G‚P!0(D‚ (`&;`&@&;0&0Â!²][CJ<@x @HKƒ’&G‚P&0!8‚ !`+A‚`+ &?‚P&0!G‚0!P(?‚@(@&D‚p&!5 !@!%P!&GP&!6!P+G‚0+P&?‚@&@!D‚p!(5 (@(%P(!GP!(6(P!G‚0!P(?‚@(@!D‚p!(5 (@(%P(+GP+(6(P&G‚P&0!8‚ !`+A‚`+ &?‚P&0!G‚0!P(?‚@(@&D‚p&!5 !@!%P!&GP&!6!P+G‚0+P&?‚@&@!D‚p!(5 (@(%P(!GP!(6(P!G‚0!P(?‚@(@&J‚P&0!?‚ !`&J‚P&0!8‚ !`+D‚`+ &G‚P&0+L‚`+ &K‚P&0!T‚0!P(W‚@(@!@@!`!U !@(L‚0(P&D@&!G0!²J<[xHK@ @Â!²C]ƒ’&J‚P&0!8‚ !`&J‚P&0#?‚ #`$D‚`$ +?‚P+0&J‚0&P!S‚@!@&:²}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0’&²@ÿ/MTrk ÿ³ÃÿJAZ2³J<ÿGeneral MIDI³ÿ3ÿYÿY³ ^[2ÿ @³@HKC}]2ƒ ^[2]2@HKCJ<Þ“J!³@‚p@“Jƒ³@“J!‚pJ³@@“I2`O@`L-`C@ƒ`I2I`O@O`LL-`C@CƒxE0B(=,…FCOLIB E_³@“=C@DE4³@“@B8-B @0'@+>;óCJ<[2 ^@]2HK‰“>†E‚J³@‚p@“Jƒ³@“J‚p³@“JG*³@`“O6`J&`C6`G³@ƒ“I*³@`“OO6`L&`C6CƒPJƒLL‚`CILO³@“@ B³@“E!>%†P@>p>.PB@ E B`LP@>BL³@ƒ`“O!LJ³@†“G ‚`LJGO³@p“G,³@`“J'`V!†`JJ‚GVp³@“JC%³@“J!E G†³@@“CCLGIPEpJ‚@LIC³@ “C%³@“I L!ƒ`³]2[2ó ^HKJ<C@ƒ“I³@“E GLJ!C%ƒCƒ³@“CPEp³@“GG.`JJ@GG`QPJGQ³@ƒ`“G!NJ³@†“@ ‚`JN@³@“GpC,³@`“G'`Q!ƒ`G³@“C³@“ILC…QCL³@“I L!³@“I C%`CIICLL…LCI³@ “C%L!I ³@…`@“LCIG³@“E J!C%†C³@P“Ep³@“G.G`JJ@GG`QPJQG³@ƒ`@“NJG!†@ ‚`N@JG³@p@“C,`G'`Q!ƒ`IC³@“GLC³@…@“ILCQ C%L!³@“I `CLILIC…³@“LIC ³@“I C%L!ƒ`³CHK@]2J<[2ó ^ƒ“IC³@“B$E*>'…gB E_³@“>CE7@G³@“@B;-B @3'@+>>E>³@“E‚/L`³@“>4`B.`L(„@>>4`B.B`LL(ƒ`B³@ƒ“J!³@‚p“JL>³@ƒ@“J!‚p³@“J³@“I2`O@`L-`C@ƒ`II2`O@O`L-L`CC@†`³]2@HKóC[2J< ^ƒ@“ICE%>*@$BO†P>@p>.PB@ E B`LP³@“@B>L`LƒI!³@“EBƒ³@“IƒE³@“E ‚`E³@“BC,³@`“G'`Q!ƒ`GCCJGEƒ³@“G‚QEJC C%³@“L!I `CLILIC…CLI³@ “C%I ³@“L!…`³@“ILC>%E!B@ ³@†P“>@p>.PB@ E B`LP@>L³@“Bƒ`LO!J³@†“G ‚`JGL³@“OpG,³@`“J'`V!†`JJ‚VJ³@“G`³@“C,`G'`Q!ƒ`LCIG³@“C³@…“LIC I C%L!PQƒ³C[2@ó ^J<HK]2ƒ“BE!@ CI³@“>%†LB³@P“>@p³@“C.`EE@G`QPEGC³@“Qƒ`I³@“O!L†@ ‚`IL@³@“OpC,³@`“G'`Q!†`L‚GLCQ³@`@“E,`I'`S!†`L‚pLES³@“I@ ³@“=%BE!†³@“=BP@p³@“C.`EE@G`QPE³@“GQCƒ`LIO!³@†“@ ‚`IL@³@“Op³@“C,`G'`Q!†`L‚³@“CGQL`³@“E,`I'`S!`I³@ƒ“S`>.³@`“B)`L#ƒPEp>>.`B)B`L#Lƒ`B³@ƒ“J³@‚p“>LJ³@ƒ“J!³@‚p@“J³@“I2`O@`L-`C@ƒpIL0CLI(C,…VOI L_³@“CC³@“E4@D@B8-B @0'@+>;³C@HK]2 ^[2óJ<ƒ“BE#³@“>'@!†P@>>.`BB)`L#!E?E³@“>BƒLƒ³@“O‚pO>³@“B,³@`“J8`E(`>8ƒ`BJE>†@³@ÿ/MTrk•´Ä6ÿJAZ2´HKÿ @ÿGeneral MIDIÿ4ÿYÿY´ @[(](C@J<}lƒJ<]([(HK@ @Cž”Ck‰C@NƒEqIq†@ƒIJNENE‰´](J<@[(CHK @‰”J†EƒCZŒI`E`C‰ENEJNI•JENJNEƒJJNENEƒINENJEƒIBNGJEƒJNBNGBƒJJNB>NƒCZ†J>ƒC@NƒE`I`ƒENEIJNƒ´J<]([(C@ @HKƒ”@ƒJƒE›I`E`‰ENEIJN†JCNJNƒ@NINJCƒE>NIGJ@ƒ>GGN>Nƒ>=NENƒ=E;JBNƒ>NGBN;B†B>>J†=N>ƒE`I`†=ƒENJNIEƒ´ @CHK[(@J<](Œ”>qBqƒEBJŒ>N>GXƒCk†>Gƒ@NCƒEqIq†@ƒENJNIEƒ´[(](@ @HKJ<C”JE•I`E`‰IEJNEN•JNENEJƒEJNJENƒEJINENƒGJEIBNƒBNJNGBƒJB>NJNŒJ>IN=NƒE`I`IƒIEJNENƒ´]( @C[(J<@HKƒ”=ŒJEÝCe‰@NCƒEqIq†@ƒENEJNIƒ´](J<HK@[( @CŒ”EJŒBk>kƒBDB>†@B´@ÿ/MTrk&ì¹ÿJAZ2™8ÿGeneral MIDIÿDrumsÿY¹x @[]@HKÿ @¹}J<™#:*'1'¹C™8#1*@* *@*2&6 &*@*#3 #*@#>¹HK]x™*$¹ @[ɹCJ<™8¹@™8#*@* *@*)&3 *&@* *@#78*$8*#@* *@&3*/ *&@#1* #*@*$8#>8#*@* *@*)&36/ &*6@. #+ .#@#7*$81$8*1#@* *@&3*) *&@*#1 #*@8#>*$8#*@* *@&3*) &*@*#+ #*@8#:1'*'8#1*@* *@*2&6 *&@*#3 *#@8*)#C8#*@* *@&8*. &*@* *@#>*,81,8#*1@*" *@*8&; &*@#7*" #*@8*,#F8#*@*" *@&;*1 &*@*" *@#>*,88#*@*" *@&;*8 *&@*'#7 #*@*,8#F8*#@*" *@&;68*1 &6*@#1*" #*@#>8*,8*#@*" *@&;*8 &*@*'#7 *#@#F8*,8*#@*" *@68&;*1 6*&@#1*" #*@8#>*,8#*@*" *@*8&; *&@*"#7 *#@*,&;8#F8*&#&) &&5 &&) &-5 --/ --; --/ -#>8*,8#*@*" *@*8&; &*@*"#7 #*@8&;*,#F8&*#&) &&5 &&) &-5 --/ --; --/ -#>81,*,8#*1@*$ *@*7&B &*@*)#? #*@*7#R88#*@#L*- #*@*D&N *&@*1#@ #*@8&88&@#F #@#I1/ 1# ¹[™8¹ @]ɹ@™#X1@¹HKCJ<x™81# &I*? &*@#<*. #*@#7*$1$88#*1@* *@&3*/ *&@#1* *#@8*$#>8#*@* *@&3*) &*@* *@#781$*$8#1*@* *@&3*/ *&@#1* *#@#>8*$8#*@* *@&3*) &*@* *@8*$#78#*@* *@*/&3 &*@#1* #*@8*$#>8#*@* *@&3*)6/ *&6@*#+ #*@#78*$8#*@* *@*/&3 *&@* #1 #*@#>8*$8#*@* *@6/&3*) 6*&@*#+ *#@#78*$8#*@* *@*/&3 *&@*#1 #*@*$8#>&38&#*&$ &&. &&$ &-. --) --3 --) -*$8#78#*@* *@&3*/ *&@#1* #*@*$&3#>88&#*&$ &&. &&$ &-. --) --3 --) -8*$1$#78*#1@* *@*)&3 *&@#1* *#@8#>*$8*#@* *@*)&3 &*@#+* *#@8*$#71$8#1*@* *@&3*/ *&@*#1 #*@8#>*$8*#@* *@*)&3 &*@* *@8*$#78*#@* *@&3*/ *&@#1* #*@*$8#>8#*@* *@&36/*) &*6@. #+ .#@#7*$88#*@* *@&3*/ &*@*#1 *#@#>*$88#*@* *@*)&3 &*@* *@#78*$8*#@* *@*/&3 *&@* #1 *#@#>8*$8#*@* *@6/&3*) &6*@*#+ #*@#7*$88*#@* *@*/&3 *&@*#1 *#@*$8#>8*#@* *@&3*) &*@* *. .*$#788#*@* *@&3*/ *&@#1* *#@*$#>88#*@* *@6/&3*) *&6@#+* #*@*$1$#788#*1@* *@&3*/ *&@#1* *#@#>8*$8*#@* *@&3*) &*@* *@#78*$8#*@* *@&3*/ *&@#1* #*@#>&38*$8*&#&$ &&. &&$ &-. --) --3 --) -#71$8*$8#*1@* *@*)&3 *&@#1* *#@¹ @J<HK[]™#>*$¹xC™8ɹ@™8#*@* *@&3*) &*@*#+ *#@*$8#71$8#*1@* *@&3*/ *&@*#1 #*@#>8*$8#*@* *@&3*) &*@* *@*$8#78*#@* *@*/&3 *&@#1* #*@*$8#>8*#@* *@&3*)6/ *6&@#+. .#@#7*$88#*@* *@*/&3 *&@#1* #*@#>*$88*#@* *@*)&3 *&@* *@#78*$8*#@* *@&3*/ *&@* #1 *#@#>*$88*#@* *@*)&36/ 6&*@#+* *#@8*$#78*#@* *@*/&3 &*@*#1 *#@8*$#>8#*@* *@&3*) &*@* *. .*$8#78#*@* *@*/&3 *&@*#1 #*@8*$#>&38&*#&$ &&. &&$ &-. --) --3 --) -*$8#78*#@* *@*/&3 *&@*#1 #*@*$&38#>8*&#&$ &&. &&$ &-. --) --3 --) -*$8#71$8*#1@* *@*)&3 &*@#1* *#@*$#>88*#@* *@*)&3 &*@*#+ #*@#7*$81$8#1*@* *@&3*/ &*@*#1 *#@*$#>88*#@* *@&3*) &*@* *@*$8#78#*@* *@&3*/ *&@#1* *#@*$#>88#*@* *@&36/*) &*6@#+. #.@*$8#78#*@* *@&3*/ &*@*#1 #*@#>8*$8#*@* *@&3*) *&@* *@8*$#78*#@* *@&3*/ &*@#1* *#@#>*$88#*@* *@6/*)&3 &6*@#+* *#@#7*$88#*@* *@*/&3 &*@#1* #*@*$#>88*#@* *@*)&3 *&@* *. .#78*$8*#@* *@*/&3 &*@#1* *#@#>&3*$88*&#&$ &&. &&$ &-. --) --3 --) -8*$#78#*@* *@*/&3 *&@*#1 *#@&3*$#>88&#*&$ &&. &&$ &-. --) --3 --) -1$8*$#781#*@* *@&3*) *&@*#1 *#@¹ @[É™8¹C@HKx™*$¹]™#>¹J<™8*#@* *@*)&3 &*@#+* #*@*'#:1'88*#1@*! *@*2&< &*@*%#; *#@*48#O8*#@#I*+ *#@*A&K *&@*/#> *#@&;88&@#I #@#L11 1# #^1F881# &N*D *&@*1#@ *#@#>81,*,8*1#@*" *@*8&; *&@#7*" #*@#F*,88*#@*" *@*1&; *&@*" *@*,1,8#>8#1*@*" *@*8&; &*@#7*" #*@#F8*,8*#@*" *@*1&; *&@*" *@*,#>88*#@*" *@*8&; &*@*'#7 #*@*,#F88#*@*" *@68&;*1 &*6@#1*" #*@*,#>88#*@*" *@&;*8 *&@#7*' *#@8*,#F8#*@*" *@&;68*1 *6&@*"#1 #*@*,8#>8*#@*" *@*8&; &*@*"#7 *#@8*,&;#F8&#*&) &&5 &&) &-5 --/ --; --/ -*,8#>8#*@*" *@&;*8 &*@*"#7 #*@&;8*,#F8*&#&) &&5 &&) &-5 --/ --; --/ -*,#>1,881*#@*" *@*1&; &*@#7*" *#@¹HK™#F¹[ɹx™*,¹]J<@C @™88*#@*" *@*1&; *&@*"#1 #*@*)#;81)8#1*@* *@&8*5 &*@#5* *#@*'8#A8*#@* *@&6*, *&@* *@#7*$88#*@* *@&3*/ *&@#1* *#@8#>*$8*#@* *@*)6/&3 &6*@. #+ .#@#7*$88#*@* *@*/&3 *&@#1* #*@8*$#>8#*@* *@&3*) &*@* *@*$#788*#@* *@*/&3 *&@#1* *#@#>8*$8*#@* *@&3*)6/ &6*@#+* #*@#78*$8#*@* *@&3*/ *&@#1* *#@#>8*$8*#@* *@&3*) *&@* *. .8*$#78#*@* *@&3*/ &*@*#1 #*@8#>&3*$8&*#&$ &&. &&$ &-. --) --3 --) -*$#788*#@* *@&3*/ *&@#1* #*@8#>&3*$8*#&&$ &&. &&$ &-. --) --3 --) -1$8*$#78#*1@* *@&3*) &*@*#1 #*@*$8#>8#*@* *@&3*) *&@#+* #*@8*$#71$8*#1@* *@*/&3 *&@#1* *#@*$8#>8#*@* *@*)&3 *&@* *@#7*$88#*@* *@*/&3 &*@*#1 *#@8*$#>8*#@* *@6/*)&3 *&6@. #+ #.@*$#788*#@* *@*/&3 &*@*#1 *#@#>*$88#*@* *@*)&3 &*@* *@8*$#78#*@* *@*/&3 *&@#1* *#@8*$#>8#*@* *@&36/*) *&6@#+* #*@*$#788*#@* *@*/&3 *&@#1* #*@#>*$88*#@* *@*)&3 &*@* *. .#78*$8#*@* *@*/&3 &*@* #1 #*@#>*$88#*@* *@*)6/&3 6&*@#+* *#@*$8#78#*@* *@*/&3 &*@#1* #*@8*$#>8#*@* *@*)&3 &*@* *@8*$#78*#@* *@&3*/ &*@*#1 *#@*$8#>&38&#*&$ &&. &&$ &-. --) --3 --) -*$1$8#78#1*@* *@&3*) *&@*#1 *#@8#>¹@xJ<[ @™*$¹]ɹHKC™8#*@* *@&3*) *&@*#+ *#@*$8#71$8#*1@* *@&3*/ &*@*#1 *#@#>*$88*#@* *@&3*) *&@* *@8*$#78*#@* *@*/&3 &*@*#1 #*@#>8*$8#*@* *@&36/*) 6&*@#+. #.@8*$#78*#@* *@&3*/ &*@#1* #*@*$#>88*#@* *@*)&3 &*@* *@#7*$88*#@* *@*/&3 &*@#1* #*@#>*$88#*@* *@&36/*) 6*&@#+* *#@8#7*$8*#@* *@*/&3 &*@#1* #*@8*$#>8*#@* *@&3*) &*@* *. .#78*$8#*@* *@*/&3 *&@* #1 *#@*$#>88#*@* *@*)6/&3 6*&@*#+ #*@*$#788*#@* *@&3*/ *&@#1* *#@#>8*$8#*@* *@&3*) &*@* *@*$#788*#@* *@*/&3 &*@*#1 #*@8#>*$8#*@* *@6/&3*) *6&@#+. #.@#781$*$8#1*@* *@*/&3 *&@#1* #*@#>8*$8#*@* *@*)&3 *&@* *@*$8#78*#@* *@&3*/ &*@#1* *#@*$#>88#*@* *@*)&36/ 6*&@. #+ #.@8#7*$8*#@* *@&3*/ &*@#1* *#@8#>*$8*#@* *@&3*) *&@* *@#78*$8*#@* *@&3*/ *&@* #1 #*@8#>*$8#*@* *@6/*)&3 6&*@#+* #*@8*$#78*#@* *@&3*/ &*@#1* #*@8#>*$8*#@* *@&3*) &*@* *. .#78*$8#*@* *@&3*/ &*@* #1 *#@*$8#>8*#@* *@6/*)&3 *&6@#+* *#@*$1$#788#1*@* *@*)&3 &*@*#1 *#@8#>*$8*#@* *@*)&3 *&@*#+ *#@*'1'8#:81#*@* *@*2&6 &*@#3* #*@*)8#C8#*@* *@&8*. *&@* *@#:*'1'881*#@* *@*2&6 *&@*#3 *#@#>*$88#*@* *@*)&3 *&@* *@*'8#:8#*@* *@&6*2 *&@#3*# *#@8*)#C8#*@* *@*.65&8 6&*@* #. #*@#>8*,8*#@*" *@&;*8 &*@#7*' #*@*,8#F8#*@*" *@*1&;68 *6&@#1*" *#@8*,#>8#*@*" *@&;*8 &*@#7*" *#@8#F*,&;8*&#&) &&5 &&) &-5 --/ --; --/ -1,8*,#>8*#1@*$ *@&B*7 &*@*)#? *#@#R8*78*#@*-#L *#@*D&N *&@*1#@ #*@8&88&@#F #@1/#I 1# ¹]@HK[ɹ @x™8¹C™#X¹J<™1@81# *?&I *&@#<*. *#@1$8*$#78#*1@* *@&3*) &*@#1* *#@#>*$88#*@* *@&3*) *&@*#+ *#@1'8#:*'81#*@* *@&6*2 &*@*#3 #*@*)#C88#*@* *@*.&8 *&@* *@#:8*'8#*@* *@&6*2 &*@*##3 #*@8#>*$8#*@* *@&36/*) &6*@#+* #*@8*'#:8#*@* *@&6*2 *&@*#3 #*@8*)&8#C8#&*&' &&2 &&' &-2 --- --8 --- -#&*&1&†*#1*#1†1*#ÿ/MTrkøµÅ6ÿJAZ2ÿ @ÿGeneral MIDIÿPart-01ÿYÿYµx [@]@HK}}C•>µJ<ƒxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p}•>Cƒµxƒsƒn‚p•Eµ}•Cƒµxƒsƒn‚p•>µ}•Eƒµx‚p}•B>ƒµx‚p•BEµ}ƒx‚p•Eµ}•Eƒµ}•EEƒJµ}•Eƒµx‚p}•GJƒµx‚p•Cµ}•GƒCCµ}ƒxƒs‚p•Cµ}•Eƒµx‚p•EBµ}ƒx‚p•Eµ}•Bƒµxƒs‚p•EEµ}ƒ}•JEƒµ}•JIƒµ}•IGƒGEµ}ƒ}•ECƒµxƒsƒn‚p}•ECƒµx‚p•E>µ}ƒx‚p•Jµ}•>ƒIJµ}ƒ•Iµ}•GƒGµ}•Gƒµ}•IGƒIGµ}ƒ•GEµ}ƒx‚p•CEµ}ƒx‚p•@Cµ}ƒxƒsƒn‚p•E@µ}ƒx‚p}•EJƒµ}•IJƒIµ}•Gƒµ}•GGƒµ}•GIƒµ}•IGƒµ}•EGƒµx‚p•CEµ}ƒx‚p•@µ}•Cƒµxƒsƒn‚p•Jµ}•@ƒµxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p}•JCƒµxƒsƒn‚p}•ECƒµxƒsƒn‚p}•>Eƒµx‚p•>µ}•Bƒµx‚p•BEµ}ƒx‚p•EEµ}ƒ}•EEƒJEµ}ƒx‚p•Jµ}•Gƒµx‚p•GCµ}ƒ}•CCƒµxƒs‚p•CEµ}ƒx‚p•EBµ}ƒx‚p}•BEƒµxƒs‚p}•EEƒµ}•EJƒJIµ}ƒ}•GIƒGµ}•Eƒµ}•ECƒµxƒsƒn‚p•Eµ}•Cƒµx‚p}•JEƒµxƒsƒn‚p}•JGƒµx‚p}•GIƒµ}•IIƒEµ}•Iƒµx‚p}•ECƒCµ}•CƒCµ}•@ƒµxƒsƒn‚p}•E@ƒµ}•EEƒJEµ}ƒx‚p}•GJƒµx‚p•Iµ}•GƒIIµ}ƒ•IEµ}ƒx‚p•ECµ}ƒ•CCµ}ƒ•Cµ}•@ƒµxƒs‚p•@@µ}ƒ•@µ}•>ƒµx‚p•J>µ}ƒx‚p}•CJƒµxƒsƒn‚p}•CEƒµxƒsƒn‚p}•>Eƒµxƒsƒnƒi‚p•;>µ}ƒ•;µ}•<ƒµx‚p•>µ}•<ƒµx‚p•>>µ}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0•>ÿ/MTrkû¶Æ6ÿJAZ2ÿ @ÿGeneral MIDIÿPart-02ÿYÿY¶x h[@]@HKJ<–>¶C}}ƒxƒsƒnƒiƒdƒ_ƒZƒU„0–@¶}–>@¶}–@Cƒ¶xƒsƒn‚p–E¶}–Cƒ¶xƒs‚p–EC¶}@–BC`B@`¶}–>@ƒ¶x‚p–>¶}–Bƒ¶x‚p–E¶}–Bƒ¶x‚p–E¶}–Eƒ¶}–EE@GE@GJ¶}ƒ–JI¶}ƒ–G¶}–I„@EG¶}@–E¶}–CƒCC¶}ƒxƒs‚p–CE¶}ƒx‚p–B¶}–Eƒ¶x‚p}–EBƒ¶xƒs‚p}–EE‚ GE`¶}–IGƒ¶}–II@IG@GE¶}ƒ–EE¶}ƒ–CE¶}ƒxƒsƒn‚p–C¶}–Eƒ¶}–CE@CB`B@`@¶}–>„@C>¶}@–I¶}–CƒI¶}–IƒIG¶}ƒ}–GGƒG¶}–Gƒ¶}–GGƒ¶}–GEƒ¶x‚p–C¶}–Eƒ¶}–BCƒ¶}–B@ƒ¶xƒs„0}–B@`BC`C¶}–E… E¶}–G`I¶}–GƒII¶}ƒ–GI¶}ƒ}–GGƒG¶}–Gƒ¶}–GGƒE¶}–Gƒ¶x‚p}–CEƒB¶}–Cƒ@¶}–Bƒ¶xƒs„0–@C¶}`–CE`JE¶}ƒxƒsƒnƒiƒdƒ_ƒZƒU„0}–GJ`EG`E¶}–Cƒ¶xƒsƒn‚p}–ECƒ¶xƒs‚p}–CE@CB`B@`¶}–>@ƒ¶x‚p}–B>ƒ¶x‚p}–EBƒ¶x‚p}–EEƒ¶}–EE@GE@JG¶}ƒ–JI¶}ƒ–GI¶}„@}–GE@E¶}–CƒCC¶}ƒxƒs‚p–E¶}–Cƒ¶x‚p–BE¶}ƒx‚p–B¶}–Eƒ¶xƒs‚p}–EE‚ EG`IG¶}ƒ–II¶}@–IG@G¶}–EƒE¶}–EƒE¶}–Cƒ¶xƒsƒn‚p–EC¶}ƒx‚p}–EJƒ¶xƒsƒn‚p}–GJƒ¶x‚p–G¶}–IƒI¶}–I@GI@G¶}–Eƒ¶x‚p}–CEƒC¶}–Cƒ@C¶}ƒxƒs„0–@B¶}`–BC`E¶}–CƒE¶}–E@EG@GJ¶}ƒx‚p}–GJƒ¶x‚p–IG¶}ƒ–II¶}@–IG@¶}–EGƒ¶x‚p–C¶}–EƒCC¶}ƒ–@C¶}ƒxƒs‚p}–@@ƒ@>¶}ƒx‚p}–J>„@J¶}–G`EG`¶}–CEƒ¶xƒsƒn‚p}–CEƒ¶xƒsƒn‚p–>¶}–Eƒ¶xƒsƒn‚p–;¶}–>ƒ¶}–;;ƒ¶}–;<ƒ¶x‚p}–><ƒ¶x‚p}–>>¶|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0–>ÿ/MTrk $·ÇYÿJAZ2·}ÿGeneral MIDIÿPart-03ÿYÿY·x "[@]ÿ @·HKJ<@C—>)B)·}ƒxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p—C,·}—BG,>ƒ·xƒsƒn‚p—E,@,·}—GCƒ·xƒs„0—=,·}—9,E@`·}`—>,·}—B,9=ƒ·xƒsƒn‚p—>'B'B>·}ƒxƒsƒn‚p—G'>B·}—C'ƒ·xƒsƒnƒi‚p}—CGE'@'ƒ·xƒs‚p—B'E@·}—>'ƒ·x‚p}—B'>'B>ƒ·x‚p—>>'B'·}—Bƒ·xƒs‚p—@'B>·}—E'‚ ·}—E'EC'@`>'C·}—B'Eƒ·}—B='9'>@=·}—E'@'9@G'·}—B'E@ƒ·x‚p—BG'·}—GC'ƒ·xƒsƒn‚p}—@'CGE'„@·}—='9'E@`·}`—B'=>'·}—9„@B>'·}—@'>@G'C'·}—@>ƒ9'·}—='GCƒG'=9·}—B'ƒBG'GC'·}ƒ—GCE'·}—@'ƒ@EB'·}—G'ƒ·xƒs‚p—G'GBC'·}ƒx‚p—9'·}—CG='ƒ·xƒs…—E'=9@'·}`—@>'E·}—B'ƒ·x‚p—G'C'·}—>Bƒ='·}—9'CGƒ9=B'·}—G'ƒG'G·}—C'BƒGC·}—E'@'ƒB'@·}—G'Eƒ·xƒs‚p—C'G'GB·}ƒx‚p—9'G·}—='Cƒ·xƒs„0—9E'@'·}—=`·}`}—B'>'E@ƒ·xƒsƒnƒiƒdƒ_ƒZƒU„0}—BB,>,>`·}`—C,·}—G,B>ƒ·xƒsƒn‚p—G@,·}—E,Cƒ·xƒs„0—=,@·}—9,E`·}`}—B,>,=9ƒ·xƒsƒn‚p—B'>·}—>'Bƒ·xƒsƒn‚p—C'G'B·}—>ƒ·xƒsƒnƒi‚p}—E'CG@'ƒ·xƒs‚p—@·}—B'>'Eƒ·x‚p—>B·}—>'B'ƒ·x‚p—B'>B>'·}ƒxƒs‚p—@'E'·}—>B‚ E'EC'·}—@`C·}—B'E>'ƒ>='9'B·}@—E'·}—=@'9@@B'·}—G'Eƒ·x‚p—C'G'G·}—Bƒ·xƒsƒn‚p—GC@'·}—E'ƒ·x‚p}—E@B'>'ƒ·xƒsƒn‚p—C'G'·}—B>ƒ·x‚p—9'·}—C='G„@E'·}—C'9=@C·}—B'>'Eƒ·x‚p—C'·}—G'B>ƒ·x‚p—CG9'·}—='ƒ·xƒs…}—@'E'9=p·x„0—C'@E'E·}@—CE>'·}—B'ƒ·x‚p—B>C'·}—G'ƒ·x‚p—9'·}—='CG„@E'C'=9·}@—EB'C·}—>'ƒ·x‚p—G'BC'>·}ƒx‚p—9'='GC·}ƒxƒs‚p—=99'<'·}ƒ—9B)·}—>)<ƒ·xƒs„0—>'B>·}—B'`·}`—C)·}—G)B>ƒ·xƒsƒn‚p}—E,CG@,ƒ·xƒsƒn‚p—E>)·}—B)@ƒ·xƒsƒn‚p}—B)>)>BƒC,@,·}—>Bƒ·xƒs‚p—>)·}—B)C@ƒ·x‚p}—>B>·|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0—>ÿ/MTrk¤¸ÈYÿJAZ2˜9)ÿGeneral MIDIÿPart-04ÿYÿY¸x ^[@]@HKJ<ÿ @¸C}˜B)¸}ƒxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p˜>,;,9¸}˜Bƒ¸xƒsƒn‚p˜>;9,¸}˜@,ƒ¸xƒsƒnƒiƒd‚p}˜9)>)9@ƒ¸xƒsƒn‚p}˜='B'>9ƒ=B9'>'¸}@}@}˜9>'>;'ƒ>'9'¸}˜;>ƒ>'¸}˜>9C'„@>'C;'>¸}Px‚p˜9';@'¸}˜>ƒ¸xƒs‚p˜>'9'¸}˜@9ƒ¸xƒsƒnƒiƒdƒ_‚p˜@'9'>¸}˜9‚ ¸}pxƒs‚p˜;'¸}˜9@B'ƒ¸}˜9';>'Bƒ¸xƒsƒnƒi‚p˜9@'>¸}˜9'ƒ¸xƒs„0˜@99'>'¸}@˜9'>>'9¸}ƒx‚p˜B'¸}˜;'9>ƒB;>'¸}˜C'ƒ9'¸}˜@'>Cƒ¸}˜;'@9B'ƒB¸}˜>'9';ƒ¸xƒsƒn‚p˜9@'9'¸}˜>ƒ¸xƒsƒn‚p}˜9'>'@9ƒ¸x‚p˜9>9'¸}˜>'ƒ¸x‚p}˜;'B'9>ƒ¸}˜>'BC';ƒ@'C>¸}˜9'ƒB'9@;'¸}ƒ˜;>'9'B¸}ƒxƒsƒn‚p}˜>9'@'9ƒ¸xƒsƒnƒiƒdƒ_ƒZƒUƒPƒKƒFƒA„0}˜>,9,9@`¸}pxƒsƒnƒi‚p˜@,¸}˜9,9>ƒ¸xƒsƒnƒiƒd‚p˜>)¸}˜9)@9ƒ¸xƒsƒn‚p˜9B'='¸}˜>ƒ>'¸}˜=9'B@¸}@˜9>;'¸}˜>'ƒ;>9'¸}˜>'ƒ¸}˜C'>9>'„@C>>'¸}˜;'P¸x‚p˜>;9'@'¸}ƒxƒs‚p˜>'@99'¸}ƒxƒsƒnƒiƒdƒ_‚p˜9'¸}˜@'>9‚ ¸}pxƒs‚p˜;'9@¸}˜B'ƒB;9'¸}˜>'ƒ¸xƒsƒnƒi‚p˜@'9¸}˜>9'ƒ¸xƒsƒnƒiƒd‚p}˜>'C'9@ƒ¸x‚p˜@'9'>C¸}ƒx‚p˜@9'¸}˜>'9ƒ¸xƒsƒn‚p˜9>¸}˜9'@'ƒ¸xƒsƒnƒiƒdƒ_ƒZ‚p˜@¸}˜>'C'9ƒ¸x‚p˜>C¸}˜9'@'ƒ¸x‚p˜9@¸}˜>'9'ƒ¸xƒsƒn‚p˜9>@'9'¸}ƒxƒsƒnƒiƒdƒ_„0}˜@9>'9'`¸}pxƒsƒnƒi‚p˜9,>¸}˜9@,ƒ¸xƒsƒnƒiƒdƒ_ƒZ‚p˜@¸}˜9>)9)ƒ@,¸}˜;,>9ƒC)<)¸}˜;@ƒ¸x‚p˜9)¸}˜B)C<ƒ¸x‚p˜>9¸}˜B¸|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0˜>ÿ/MTrkr°ÀÿJAZ2ÿYÿGeneral MIDI°r(ÿ @° @yxÿLast journey of the Niagaraÿ/simutrans-124.3/simutrans/music/15-The-Wayside-Blues.mid000066400000000000000000000316241474050137200230370ustar00rootroot00000000000000MThdÀMTrk‰ÿ By ÿCopyright © 2006 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQ¡ ÿX ƒ°ÿX„@ÿX ÿ/MTrkGÿ!ÿStaff-4ʺº @¸@šHn>šHšHn^šHšFn>šFšCn^šCšCn>šCššCšCn^šCšCn>šCšCn^šCš?n>š?ššCšCn^šCšAn>šAšCn^šCš?n>š?ššCšCn^šCšCn>šCšCn^šCš?n>š?ššGšJn^šJšJn>šJšLn^šLšGn>šGšCn^šCBšCn^šCšHn>šHšHn^šHšFn>šFšHn^šHšEn>šEšAn‚šAššHšHn^šHšFn>šFšCn^šCšCn>šCššCšCn^šCšCn>šCšCn^šCš?n>š?ššCšCn^šCšAn>šAšCn^šCš?n>š?ššCšCn^šCšCn>šCšCn^šCš?n>š?ššGšJn^šJšJn>šJšLn^šLšGn>šGšCn^šCBšCn^šCšHn>šHšHn^šHšFn>šFšHn^šHšEn>šEšAn‚šAššHšHn^šHšFn>šFšCn^šCšCn>šCššCšCn^šCšCn>šCšCn^šCš?n>š?ššCšCn^šCšAn>šAšCn^šCš?n>š?ššCšCn^šCšCn>šCšCn^šCš?n>š?ššGšJn^šJšJn>šJšLn^šLšGn>šGšCn^šCBšCn^šCšHn>šHšHn^šHšFn>šFšHn^šHšEn>šEšAn‚šAššGšJn^šJšJn>šJšLn^šLšGn>šGšCn^šCBšCn^šCšHn>šHšHn^šHšOn>šOšOn^šOšOn>šOšHn‚šHšHn^šHšHnˆPšH‚PšKn>šKšJnpšJÿ/MTrkvÿ!ÿStaff-2²² @Ì@’’A’C’G’"$n…$Š`n^"n>"$n…$Š`n^"n>"$n…$Š`n^"n>"$n…$„`+nˆP+0$n‚$ (n‚( +n‚+ (n ( +n^+)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& 'n‚' (n‚( )n‚) -n‚- 0n‚0 -n - 0n^0)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& (n‚( )n‚) +n‚+ &n‚& +n‚+ /n / 2n^2)n‚) $n‚$ )n‚) -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^+$n‚$ (n‚( +n‚+ (n ( +n^+)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& 'n‚' (n‚( )n‚) -n‚- 0n‚0 -n - 0n^0)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& (n‚( )n‚) +n‚+ &n‚& +n‚+ /n / 2n^2)n‚) $n‚$ )n‚) -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^++n^+$n‚$ (n‚( +n‚+ (n ( +n^+)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& 'n‚' (n‚( )n‚) -n‚- 0n‚0 -n - 0n^0)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& (n‚( )n‚) +n‚+ &n‚& +n‚+ /n / 2n^2)n‚) $n‚$ )n‚) -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^++n^++n^++n^++n^++n^++n^++n>+n^"n>"$n…$Š`n^"n>"$n…$„`+nˆP+0$n‚$ (n‚( +n‚+ (n ( +n^+)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& 'n‚' (n‚( )n‚) -n‚- 0n‚0 -n - 0n^0)n‚) -n‚- 0n‚0 -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^+$n‚$ &n‚& (n‚( )n‚) +n‚+ &n‚& +n‚+ /n / 2n^2)n‚) $n‚$ )n‚) -n - 0n^0$n‚$ (n‚( +n‚+ (n ( +n^++n^++n^++n^++n^++n^++n^++n‚+ &n‚& +n‚+ &n‚& +n‚+ /n / 2n^2)n‚) $n‚$ )n‚) -n - 0n^00n 0 0n^0.n . .n^.-n - -n^-,n , ,n^,+n‚+ %n>%$np$ÿ/MTrkÿ!ÿStaff-1¹¹ @™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™9n ™9 ™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™9n ™9 ™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™9n ™9 ™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™9n ™9 ™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™*n>™*™*n^™*™9n‚™9 ™9n>™9™9n^™9ÿ/MTrk èÿ!ÿStaff-3¹¹ @È™&n^™&™&n^™&™&n^™&™&n^™&™&n^™&™&n^™&™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#¤™&n^™&™&n^™&™&n^™&™&n^™&™&n^™&™&n^™&™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#™#n>™#™#n^™#™&n>™&™#n^™#ÿ/simutrans-124.3/simutrans/music/16-Midnight-Express2.mid000066400000000000000000001217331474050137200231220ustar00rootroot00000000000000MThd xMTrk(ÿ 2006.10.06ÿÿQ\ÿ/MTrk=ÿ @ÿGeneral MIDIÀ0ÿCopyright (C) 2006 shunterÿJAZ2ÿ~j @@ ÿ~j11'ÿ~j.@@ 'ÿ~j @1@ @@.ÿ~j@1@ ÿ~j' @@ ÿ~j @@ ÿ~j @@ @ÿ~j@ @@ ÿ~j @@ ÿ~j @@ ÿ~jÿ~j@@ @@ ÿ~j @ÿ.j@ ÿjGÿVjÿXÿYÿMidnight Expressÿ/MTrkˆÿ @ÿGeneral MIDI±Á ÿJAZ2±{@][(Z @ÿBassˆ8‘!Pk!!Ok!!Kk!!Vk!!Wk!!Pk!!MC!-^- !Xs!&QR&!WT!&L`&!T2<&+@p+/=|2U&/V'E2r'&Nt&*Gx-I&*N!HV-&&G"!^&P&l,>F&2*N",\*+Nt+/Gx2I&/N&HV2&+G"&^++Pl'>F+2%N"'\%&Xj& &;&H&&P&&[N&#Xj# #;%H&#P%&[N&(Nt,G(x/I&,N#HV/&(G"#^((Pl">F(2 N""\ !Nt!%Gx(I&%NHV(&!G"^!!Pl'>F!2%N"'\%&Nb&&4|#L&x!N#u!&Bp&*X|*-Lt&;-y&&Ex&*Xt+I"*V,C+|-R,V%?"-Z%&?t,O2&I,+Vp+/Wx2Q"/R/KJ22+K/x+(_x(&Cx+S&~+&Ex*X&t+I"*V,C+|-R,V%?"-Z%&?t,O2&I,+Vp+/Wx2Q"/R/KJ22+K/x+(_x&C(x&+S~+&G|&*Wb*-Up$F&-X$#Or##B#&Rl*Q&v*Xj ;H&P[N!Xj! !;#H&!P#%[N%&Y&Xt!Pt&X!w&&Y&Xt!Pt&X!w&+Vp+/Wx2Q"/R/KJ22+K/x+(_x&C(x+S&~++Vp+/Wx2Q"/R/KJ22+K/x+(_x&C(x+S&~+&G|&*Wb*-Up+F&-X+*Or**B*.Rl1Q.v1#Nt#&Gx*I&&NHV*&#G"^##Pl)>F#2'N")\' (Gp,L!(S/LF,6#G*/J(D"#^(?6(,((3n( (=b((Gx,W.(N/@.,B#E>/<#(@p(,=|/U&,V"E/r"!Ex!%Xt&I"%V'C&|(R'V ?"(Z!? t"O2!I"!Ex!%Xt&I"%V'C&|(R'V ?"(Z !?t'O2!I'&Gx*W.&N-@.*B!E>---<=M9+B+Q>B-9=C0;0@0>0YC>@;*7 =<9M6+@+P*@=96;0C0@0>0Y@;>C27 ><=M9+B++=9B>2 C0;0@0>0eC;>@ *7,=<9M6+B+j*96=BU>0;0@0C0Y;>@C27>2>9B;92E.>B9EE@>;B:92…BBE9>27EBA9.E+>;…)>2>?tE>9B +7>777;7†+;>7;27EBA9.E+>;…)>2>?t9B>E +7G3C0>8k²@xx6’+GC>z>?@C< >CR23²@M’B=>?9.E%9E>BhE@>9B49>A2!>B9E>767;7IBDz66B;3 >6;6 ;QD7@7;7>747†4;@D> -7914)7>=8ƒG²@:’-D46467X978l9D`9=7497²@’>76727†2;>96B0E3>827J²@xx8’2EB>x>?@B< >B1C1²@’>>+7G8;)ƒG²@:’+D;6;6>XC>8lCDCC>;G >>²@’9)27B1E8ƒG²@:’2D9696>XB>8lBDCBE9> >8+7²@’C0G3k²@xx6’+GC>z>?@C< >CR²@’23MB=>?9.E%9EB>hE@>9B49>A2!E>B9>767;7IBDz66B;3 >6;6 ;Q(3M;=8?4.>%4>8;h>@;44>89<;8>4(-77C-=59242ƒF7-=4927>C E5B292ƒ"B9>2E 272B592ƒF2<B>9C1;)G8>>+7ƒ&²@<’+D;4;6>XC>8lCD`CG>;;7+7²@’77>7†+;7;>23MB=>?9.E%9EB>hE@B4>99>A2!9B>E*7:C =2@562ƒH@:*6=>7/767;7†/;;>68>(7;1>84)ƒ&²@<’(D44468X;88l;D`;8>4>7²@’47;7D7@7†4>@D; -7914)=87>ƒG²@:’-D46467X978l9D`9=747>-7=8²@’4)91ƒ&²@<’-D44467X978l9D`9=7427²@’E8B19)>>ƒ&²@<’2D9496>XB>8lBD`BE>9E3²@’B0>827J²@xx8’2EB>x>?@B< >BR²@’+7ECA;.G+>;…)>+>?C;G>27EBA9.E+>;…)>2>?9B>E+7>+>9C;G.;2;C>GG@>;C:;2…BGC>;27>C E5B292ƒ"2>BE9 ;7>767jBDz66B;3 6>;6 ;0(78C->5;242ƒF(8>;4-7T44o-7DW7#964@/F@9/27EBA9.E+>;…)>2>?t9E>B E<2;9->BB5ƒG²@:’2D969:>XB>92;²@’E7B4>x>C@B@ >BR><²@’+;C4G7J²@xx8’+GC>x>C@C@ >CR²@’2;>2B?>=96E2B>9EED>?B>96…BE9> >;7;;;+;†+;;>72;>G E9B696ƒ">BE92 /8n>B;D63B*6B>;hBE;>>96C?/#6>;B(;E;E42>/8?…)8(8C84>;957B=<-;4-ƒ&²@<’-D444:7X97?…)>2>C>E9B><B4E72;J²@xx8’2EB>x>C@B@ >BR+;²@E’CE;2G/>?…)>+>C;>GCB;9;>;2;†2;9B>>;7;+;;;†+;>7;28MBB>D93E*9E>BhEE9CB9>>A2!>BE969;9>9IBFz68B;5 6;>6 ;Q(8M;B8D43>*4>;8h>E;94C8><>8;4(-;7G-=99646ƒF7-=942;>G E9B696ƒ"9>EB2 2;696ƒ"2B<9> +;fCE;2G/>?…)>+>C;GC>G<>B;-+;C5ƒ&²@<’+D;4;:>XC>;²@’2;>G B6E996ƒ"2>EB9 *8n=B:D63@*6@=:h@E=96C:>?*#@6:=/;>4B7;;x;C@>@ ;>1(;²@]’(;?8=>2468;4>>D8?;>46…>84; 8B><4-;5(;ƒG²@:’(D464:8X;8 -;²@f’9E42=/7?…)7-7C=479-;E9E42=/7?…)7-7C=4972;EBE92E/>?…)>2>Ct9EB> 2;]2B?>=E296B9>EED>?B>96…BE>9BG7+;C4>x>C@C@ >C1B59->BE<2;²@ƒG@:’2D969:>XB>9 +;²@’G<>B;-C5ƒG²@:’+D;6;:>XC>;C 2;²@’>G-E9B696ƒF>2EB9/;T68o/;HW;#>:6B3FB>/(;8G >9;646ƒH>(84;-;T48o-7HW7#9:4@3F@9/B4E7><2;J²@xx8’2EB>x>C@B@ >BR>7B72797²@†’2>B9 >72797B7†2;>B9;7>7+777†+;;7>>>E827B19)ƒ&²@<’2D9496>XB>8lBDCE>B9 +7²@f’CA;.G+>;…)>+>?C>G;27>C E5B292ƒH92>EB/7T64o/;DW;#>66B/FB>(7](;;8942>.8;4>>@8;;:42…B48>;E7=7@7C7-7†-;C@=E27EBA9.E+>;…)>2>?>B9E27E3B0>8J²@xx8’2EB>x>?@B< >BR77>7²@’;7+7†+;;>7>8E3B027J²@xx8’2EB>x>?@B< >BR+7²@E’CA;.G+>;…)>+>?;GC>23MB=>?9.E%9EB>hE@B4>99>A2!9EB>/3M>=;?6.B%6B>;hB@>4;96>A/!6>;B(78C ;2>542ƒ";4>(8 -77C-=59242ƒ"-79=4 23nB=>?9.E%9E>BhE@B4>99><9>BE2<7E7>7B7jEDz96 E<3 <>BE9 <Q+7ECA;.G+>;…)>+>?>;GCG3>8C0+7J²@xx8’+GC>x>?@C< >CR²@’23MB=>?9.E%9E>BhE@9>>9B4A2!B9E>@7B7F7=7IBDz66B:3 @=BF6 :Q;>/7>16)B8ƒ&²@<’/D6466;X>;8l>DC6>;B ²@’(7f;A4.>+8;…)8(8?4;8>(7E;A4.>+8;…)8(8?>4;8-7E9A4.=+7;…)7-7?t=749 E7@7C7-7=7†-;C@=E679727>7†2;9>627E3>8B0J²@xx8’2EB>x>?@B< >BR²@’+7>+C;>9;2G.C>;GG@>;C:;2…;C>G E827B19)>>ƒG²@:’2D9696>XB>8lBD`BE>9>>C1+7²@’G8;)ƒ&²@<’+D;4;6>XC>8lCD`C>G;23²@M’B=>?9.E%9E>BhE@B4>99>A2!B>9E>767;7IBDz66B;3 6;>6 ;Q(78C ;2>542ƒH8(;>4-7T44o-7DW7#964@/F@9/27>C E5B292ƒH>2EB927>C E5B292ƒ"B9E>2 2>;>,B,9,‚ 2AB-H9>x2>-B+>+9+T>B29&>BE>E9E09>B&*²@ÿ/MTrk.uÿ @ÿGeneral MIDI¶ÆÿJAZ2¶{@ÿGuitar¶[A] Tˆ2–2+93=3B3E32=9EBJ/(4+73>3@34/>7@J*(4393=3=*94J/(4+73>3@3@>47/J2+93=3B3E39=2EBF4'7.>.@.>47@G*$1'4.9.=.B.;4=*19B&4'7.>.@.>@47G2+93>3B3E3E>B29F2)91>1B1E1A22)>BE991>1B1E19>E2B~2%9,>,B,E, >9B2EF2)91>1B1E1E9B>2N2+93>3B3E3B9E2>J2)91>1B1E1'BE2>9?2%9,>,B,E,@991EB>2>1B1E19BE>OE#B(>(9#2)9>91>1BEB1E1>E2B9N+(2+73;3>3C3C7;+2>F+'2)71;1>1C1@++'2C;>72)71;1>1C1+C;72>~+#2%7,;,>,C,C2>7;+F+'2)71;1>1C1;7+2>C,23 22'6.9.>.B.<2B9>6*2'6/9/>/B/,B9>26:2+6393>3B38>B692 23 22+6393>3B30B26>96+(2+73;3>3C3C;>72+F+'2)71;1>1C1@+2+'C>7;2)71;1>1C1;+2>C7~+#2%7,;,>,C,7>C;2+F+'2)71;1>1C1;7>C+2,23 22'6.9.>.B.<29>B6*2'6/9/>/B/,6>92B:/(6+;3>3B3G3/GB6;>F/'6);1>1B1G1@/6/';B6)>G;1>1B1G16>G;/B~4'8.>.@.<@48>*4'8/>/@/,8@>4:4+83>3@384>@8.4+83>3@308@>46-(4+73=3@3E37=-4E@F-'4)71=1@1E1@-4-'=E@74)71=1@1E1@4=-E7~-#4%7,=,@,E,4E@7=-F-'4)71=1@1E1-47=@E,23 22'9.>.B.E.<>29EB*2'9/>/B/E/,EB92>:2+93>3B3E38BE29> 23 22+93>3B3E30B9>E223 22'6.9.>.B.<296B>*2'6/9/>/B/,9>6B2:2+6393>3B3869B>2 23 22+6393>3B30B>2966+(2+73;3>3C3;C>2+7F+'2)71;1>1C1@+2+'7>;2)C71;1>1C17;>2+C~+#2%7,;,>,C,>;72+CF+'2)71;1>1C12+C>7;N2+6393>3B32>69BF2)6191>1B1A22)>9B66191>1B1B692>~2%6,9,>,B, 6>29BF2)6191>1B196>B2J2'7.;.>.C.>;27CC2'7/;/>/C/>2C;7D2+73;3>3C37C;2>E2+73;3>3C327;>C@6.9.>.B.>6B9C6/9/>/B/B>69H/(6+;3>3B3G3>;/GB6F/'6);1>1B1G1@/6/';>BG6);1>1B1G1;/>B6G\43 44'8.>.@.<>@84*4'8/>/@/,84>@64'7.=.@.E.7=@4EC4'7/=/@/E/=4E@7&23 22'6.9.>.B.<2B69>*2'6/9/>/B/,>B96266.<.>.<>6C6//6<>H+(2+73;3>3C372+>;CF+'2)71;1>1C1@+2+'C7;>2)71;1>1C1;7+C>2~+#2%7,;,>,C,>C2;+7F+'2)71;1>1C1>;7+C2J2'7.;.>.C.;7C>2C2'7/;/>/C/C>72;D2+73;3>3C372C>;E2+73;3>3C3C>27;D2+93>3B3E3E9>B2F2)91>1B1E1A22)BE9>91>1B1E1BE92>~*$1'4.:.=.B.;:14B=***%1'4/:/=/B/+B41=:*/3 //'6.;.>.B.6/;*/'6/;/>/B/,B>6/;:/+63;3>3B38;6B>/ /3 //+63;3>3B306/;>B64+83>3@3>48@F4)81>1@1B44)>@881>1@1>@48~4%8,>,@, 48@>F4)81>1@148>@N4'8.>.@.<48>@*4'8/>/@/,>84@:4+83>3@3848>@.4+83>3@3084@>6-$4'7.=.@.E.;7E@4-=*-%4'7/=/@/E/+=74E@-:-(4+73=3@3E37=74E-@.-(4+73=3@3E3/=7-@E424'7.=.@.E.=7@4EC4'7/=/@/E/7E=@4D4+73=3@3E3@=47EE4+73=3@3E34E7=@D2'6.9.>.B.<>2B69*2'6/9/>/B/,6B9>2:2+6393>3B38>269B.2+6393>3B30629>B29.>.B.E.>9BEC9/>/B/E/B9E>D93>3B3E3>BE9E93>3B3E3 9>EB@2'7.;.>.C.C2;7>C2'7/;/>/C/7>;C2D2+73;3>3C3>2;7CE2+73;3>3C32>7C;D2+6393>3B39>62BJ2)6191>1B1'29B>6?2%6,9,>,B,@661B92>91>1B196>BOB#>(9(6#2)661991>B>1B1>9B62N+(2+73;3>3C37;>+2CF+'2)71;1>1C1@+2+'>7;C2)71;1>1C17;>+2C~+#2%7,;,>,C,+2;C>7F+'2)71;1>1C17;>C2+N2+93>3B3E392E>BJ2)91>1B1E1'B9>E2/0 //$6';.>.B.G.;;>B/6G*/%6';/>/B/G/+G/;B6>:4'8.>.@.<>@84*4'8/>/@/,84>@-0 --$4'7.=.@.E.;47=@-E*-%4'7/=/@/E/+-=@4E7:2+6393>3B3>296BJ2)6191>1B1'2B6>9?2%6,9,>,B,@661B>9291>1B19B6>OB#>(9(6#2)661991>B>1B19>26B&2'9.>.B.E.4EB29>^2&9->-B-E-…CBE9>2P2'6.9.>.B.469>2B^2&6-9->-B-…?+!2>692#B7*;*>*C*„7C>+;2+#2%7,;,>,C,7;>+2C+27%;%>%C%#7;>+2C>2#9*>*B*E*„ 9>E2B2%9,>,B,E,2B9>E29%>%B%E%$29BE>>+$2'7.;.>.C.F++(&773N;;8ƒ$+d+'7+.;&;*78;72>C26#9#>#B#ƒV>296BS/#x;2x>'(>;/n4'8.>.@.H44+&883N>>8ƒ$4d4)84.>&8>*88>@-47%=%@%E%„&77)-@=4E =.x@(n2'79.@=>.B.E.G22+&993N>>8ƒ$2d2)92.>&9>*89>EB2#6*9*>*B*„ 9>26B2%6,9,>,B,9>26B26%9%>%B%$B2>69‚+$2'7.;.>.C.37;>+2C^+$2&7-;->-C-…<22#7+;9*C>>*B*E*„ >B29E2%9,>,B,E,9>E2B29%>%B%E%$>B9E2>+!2#7*;*>*C*„+27>C;+#2%7,;,>,C,7;>+2C+27%;%>%C%#C72>;+>29%>%B%E%ƒVEB>92S;) >.x;>n4'8/>/@/@88'X@>84 -$4'7.=.@.E.3-47@E=^-$4&7-=-@-E-\42&79--@=E>-B-E-ƒM2299#BE><#B#E#ƒO+!22#97*B<E;*>*C*„27;C+>+#2%7,;,>,C,7;>+2C+27%;%>%C%#27;C+>>+$2&7-;->-C-„ 7;>+2C+(2+73;3>3C3 +27>C;+(2*72;2>2C2;+C72>J2&9->-B-E-ƒV92EB>S*#x42x:'(:4*n/#6*;*>*B*„ 6>/B;/%6,;,>,B,>/;6B/6%;%>%B%$/6B>;>4&8->-@-„@>844+83>3@3@>844*82>2@2@>84J48%>%@%„(88)@>4 >.x@(n-$4'8>7.@=.@.E.F--(&773N==8ƒ$-d-'7-.=&7=*8=7E@4m-$4'7.=.@.E.3@E-7=4^-$4&7-=-@-E-…<42&7-@6-=E9->-B-„ >B6922+6393>3B3 9>26B2*6292>2B2>B692J2&6-9->-B-„ 69B2>2+6393>3B3 9>6B22*6292>2B26>B29J+$2'7.;.>.C.F++(&773N;;8ƒ$+d+'7+.;&7;*8;72>Cm2'9.>.B.E.429BE>^2&9->-B-E-…?+$2B>2'9E7.;.>.C.F++(&773N;;8ƒ$+d+'7+.;&7;*87;C2>26%9%>%B%ƒVB>962S;) >.x>;n4&8->-@-ƒP-%44'8@7/>=/@/E/>77'X4=7E-@62#6*9*>*B*„ 9>26B2%6,9,>,B,692>B26%9%>%B%$69>B2‚23 22'9.>.B.E.<>B29E*2'9/>/B/E/,>B29E:2+93>3B3E38EB2>9 23 22+93>3B3E30EB>9229.>.B.E.B>9EC9/>/B/E/EB>9D93>3B3E3EB>9E93>3B3E3 EB>9"+0 ++$2'7.;.>.C.;C27;>+*+%2'7/;/>/C/+;C+27>:+(2+73;3>3C3727;>C+ +0 ++(2+73;3>3C3/>C+7;262'6.9.>.B.<9>26B*2'6/9/>/B/,B29>6:2+6393>3B389>26B.2+6393>3B3069B2>22'7.;.>.C.;>27CC2'7/;/>/C/;>27CD2+73;3>3C3>C7;2E2+73;3>3C3;>27CD2'9.>.B.E.2*2'9/>/B/E/,>B9E2:/$6';.>.B.G.;>BG6;/*/%6';/>/B/G/+>/6;GB43 44'8.>.@.<@>84*4'8/>/@/,>84@:4+83>3@38>@48 43 44+83>3@3048>@6-$4'7.=.@.E.;7=@-4E*-%4'7/=/@/E/+@E-7=4:-(4+73=3@3E37E-4=@7.-(4+73=3@3E3/47=E-@62+93>3B3E3>B29EF2)91>1B1E1A22)>EB991>1B1E1>B29E~2%9,>,B,E, BE9>2F2)91>1B1E1>B29EN2'6.9.>.B.<>B692*2'6/9/>/B/,9>26B:2+6393>3B3826>B9.2+6393>3B309>6B26+$2'7.;.>.C.;27;C+>*+%2'7/;/>/C/+7;>+2C:+(2+73;3>3C3727;C+>.+(2+73;3>3C3/7;>+2C62'9.>.B.E.<>B29E*2'9/>/B/E/,>B29E:2+93>3B3E38>B29E.2+93>3B3E30BE>296+$2'7.;.>.C.;7;>+2C*+%2'7/;/>/C/+7;>+2C:+(2+73;3>3C37+27>C;.+(2+73;3>3C3/;+C72>26.9.>.B.96B>C6/9/>/B/>B96H/$6';.>.B.G.;6;B/G>*/%6';/>/B/G/+/G>;6B68.>.@.>8@C8/>/@/@>8H-$4'7.=.@.E.;=@-74E*-%4'7/=/@/E/+-E=74@69.>.B.E.EB>9C9/>/B/E/EB>9D6.<.>.><6C6//6<>&+0 ++$2'7.;.>.C.;7;>+2C*+%2'7/;/>/C/+C+2;>7:+(2+73;3>3C377;>+2C +0 ++(2+73;3>3C3/+C;72>+0 ++$2'7.;.>.C.;7>C+2;*+%2'7/;/>/C/+C27;>+:+(2+73;3>3C37+7;>C2 +0 ++(2+73;3>3C3/27;C+>62'6.9.>.B.<9>6B2*2'6/9/>/B/,B69>2:*$1'4.:.=.B.;*4:=B1**%1'4/:/=/B/+B14:=*/3 //'6.;.>.B.<;>/6B*/'6/;/>/B/,;>/6B:/+63;3>3B38B>/;6 /3 //+63;3>3B30B>;6/28.>.@.@>8C8/>/@/>@8D83>3@3@8>E83>3@3"@>8D4'8.>.@.<84@>*4'8/>/@/,@>84:4+83>3@38@>84.4+83>3@30>@486-(4+73=3@3E37=@-4EF-'4)71=1@1E1@-4-'@=7E4)71=1@1E1-47@E=~-#4%7,=,@,E,7=@-4EF-'4)71=1@1E1@E-7=4J4'7.=.@.E.=@47EC4'7/=/@/E/@E7=4D4+73=3@3E3=@47EE4+73=3@3E3@E7=4D2+93>3B3E3>B29EF2)91>1B1E1A22)>EB991>1B1E1>B29E~2%9,>,B,E, 29BE>F2)91>1B1E1>B29EN2'6.9.>.B.<26>B9*2'6/9/>/B/,9>26B:2+6393>3B3869B2>.2+6393>3B309>6B26+(2+73;3>3C37;>+2CF+'2)71;1>1C1@+2+'>;7C2)71;1>1C127;C+>~+#2%7,;,>,C,7;>+2CF+'2)71;1>1C1C+2;>7N2'9.>.B.E.<>B29E*2'9/>/B/E/,BE9>2:2+93>3B3E38>B29E.2+93>3B3E30BE9>222'7.;.>.C.;>27CC2'7/;/>/C/27>C;D2+73;3>3C3;>7C2E2+73;3>3C3C27;>"23 22'6.9.>.B.<9>26B*2'6/9/>/B/,9>6B2:/(6+;3>3B3G3;>B/6GF/'6);1>1B1G1@/6/'B;6)G>;1>1B1G1>/G;6B~4'8.>.@.<84@>*4'8/>/@/,>@48:-(4+73=3@3E3-47@E=F-'4)71=1@1E1@-4-'@=7E4)71=1@1E1@E-7=4~2'6.9.>.B.<9>26B*2'6/9/>/B/,B29>6:2+93>3B3E3>B29EF2)91>1B1E1A22)B9E>91>1B1E1>B9E2V229;>;B;E; >E29BT23 22$9+>+B+E+>B29EN2,94>4B4E4E2>B9,299D>DBDED$92E>Bx23#2U¶@ÿ/MTrkFÿ @ÿGeneral MIDIÀ0ÿJAZ2ÿStringsÿ/MTrk (ÿ @HÿGeneral MIDI³ÃÿJAZ2³[P{ÿMelody³ J]–I“BzREoBE Bl3B?@eN@>u‚>P@c@PEc >eE&>M=K.=J>\<><=R@=>a0>HBh(EOB@E*GixJr GJZLeQJ`LGSJ,GEz.C]EqEnC-E$GdVGI=)LmIuJaLHEkJ‚bEBm @m B&@E>m.>BGPFRGFGpOGJe@J`G{PF\ GFGp,G$JwJGz(G!Bv0BH@l@BcG@S B@BmQB'CpTElCE Bm(B(ADA BY>B@hM@>XK>;T‚0;b;f; He&HG[y@LGgG\@eFb GEEZFƒ'E]BrJB A6$AB`QB9h‚9BkRBAO$BdAQBEi‚Eh>i>BsJB.EoCE5JnPJ(IjNIJp%JSIk(GdI3G.JpPITJI J^HI] JIJaxCkJbGe CkJhGuEkJEEEjvEG`n+>B>d>GjTGJfJIiPI)Ge4G9\9Bk4B"@`%@>dO9=>)9NBZ)Gh B]G EfTB^E#Bh@mQ@?@$?@kR@Bk$D`BOIrDIYHK*GeHkGCeUC@et@Ev|E!BhFB EbEBX)B&Ba'@fB@0>I(>B[@`@FBEdCEE[OEE>f:><>aT;8 >@[;I@;J%>];N;V>ƒ>;GGPFRGFGpOGJe@J`G{PF\ GFGp,G$JwJGz(GJEku>hEL@k>E@0Bc‚2B.Il%Jr I&JGJk6JBJrKJIQ%G^I/GBr+BMBr*BNBrcB:@]Z@Gm@FOG6G\FGFHG!GdFlG @jzDm@sGhD9G ;m ;Bm4B@c&>Z@2>;lƒ;pEzPGVEEp G&EHBs@BEh(AxE=A @rp9{@69aCm1CC`(BjC%B$BYB CmJC,EeEE Bm?B9@lp>m@H>@kK@Bm*B'Bm(@^B*@%@m(>m@&>(9mJ9.9l!9Bm9B=@mF@2>m+>'>X(>Bml>Cx7CAEi,ELGm7GAGhEG JlGJ1Ij(Jn I3J:Bt9BAp(BjA6BAu&ABXxElB,EHBsP@aB">l@,>>JpPITJI J^HI] JIJaxCkJbGe CkJhGuIoJ?JV IJLiPJa L‚JE[PGS EIwGOG[ IOG?L{CJK LJLpQLJf'GmJ/GJY#JIvCI8Ee=E:GeQGEj(GRE+G&>[„T>)B]RBBe$BGXRGGe$GEf^EðBzREoBE Bl3B?@eN@>u‚>P@c@PEc >eE&>M=K.=J>\<><=R@=>a0>HBh(EOB@E*GixJr GJZLeQJ`LGSJ,GEz.C]EqEnC-E$GdVGI=)LmIuJaLHEkJ‚bEBm @m B&@E>m.>BGPFRGFGpOGJe@J`G{PF\ GFGp,G$JwJGz(G!Bv0BH@l@BcG@S B@BmQB'CpTElCE Bm(B(ADA BY>B@hM@>XK>;T‚0;b;f; He&HG[y@LGgG\@eFb GEEZFƒ'E]BrJB A6$B`AQB9h‚9BkRBAO$BdAQBEi‚Eh>i>BsJB.EoCE5JnPJ(IjNIJp%JSIk(GdI3G.JpPITJI J^HI] JIJaxCkJbGe CkJhGuEkJEEEjvEG`n+>B>d>GjTJfGJIiPI)Ge4G9\9Bk4B"@`%@>dO9=>)9NBZ)Gh B]G EfTB^E#Bh@mQ@?@$@k?R@Bk$D`BOIrDIYHK*GeHkGCeUC@et@Ev|E!BhFB EbEBX)B&Ba'@fB@0>I(>B[@`@FBEdCEE[OEE>f:><>aT;8 >@[;I@;J%>];N;V>ƒ>;GGPFRGFGpOGJe@J`G{PF\ GFGp,G$JwJGz(GJEku>hEL@k>E@0Bc‚2B.Il%Jr I&JGJk6JBJrKJIQ%G^I/GBr+BMBr*BNBrcB:@]Z@Gm@FOG6G\FGFHG!GdFlG @jzDm@sGhD9G ;m ;Bm4B@c&>Z@2>;lƒ;pEzPGVEEp G&EHBs@BEh(AxE=A @rp9{@69aCm1CC`(BjC%B$BYB CmJC,EeEE Bm?B9@lp>m@H>@kK@Bm*B'Bm(@^B*@%@m(>m@&>(9mJ9.9l!9Bm9B=@mF@2>m+>'>X(Bm>l>Cx7CAEi,ELGm7GAGhEG JlGJ1Ij(Jn I3J:Bt9BAp(BjA6BAu&ABXxElB,EHBsP@aB">l@,>>JpPITJI J^HI] JIJaxCkJbGe CkJhGuIoJ?JV IJLiPJa L‚JE[PGS EIwGOG[ IOG?L{CJK LJLpQLJf'GmJ/GJY#JIvCI8Ee=E:GeQGEj(GRE+G&>[„T>)B]RBBe$BGXRGGe$GEf^Eÿ/MTrk6ÿ @ÿGeneral MIDI·ÇÿJAZ2·@ E{[P]ÿSolo·u‚‡C—;g%>j;>@t@ B&@uB>w@'>9g297}'76VO69PT6^96†G;~5;>t>=m2=9u!97[37;p.;9f(96g&6 4U847n)7 6Y46 2X421K@14e(4 2V52/W)/-26h 6 9n@96H 67EJ7;d;>pI>;:";=fG=„W<(<=u0=@ @>z3>996sM2P627}H7 55 6`$9`6 =l9=@F@>{/>DI{+IVBr"BUAhAB\DB0GwJG*>T]>=IX>m=)>‚6A!A BVCB En)EBJGB)=VA=7;Yy9H ;I;O9 ;dI=IGu(GETQG`E%ItGGI JpnJ0Gy\GBYNB Bh&Br@IC@ Bj&BET:EGz(G Ir(ILr4G^ L6GEI$EGi:GJn2ETJ(EBE)GqB4GEq2BWE=B@F @Cd5CEw)E BQ2B>X0=Q>3=@k/>V@1>9= 9 :F8:=u'=;SF; 6:"69@:98`&87B;7 6b%6 9Q596R+62HQ24[^44ac42*4E2M46X16]9SJ909TI939\Q9'>fQ>'9[Y97\U76NA6/7`'7 ;F=;>T%>9W09;c/;9H197`,768667d.76F>64Z)42O=2 4K,46E169s9;=;!=~C= :I:;0=S;#=>s">@t1@"AVA Bk=BAk&A@L9@ >i,>=BM=‚;xA;:4QQ4(;nK;9yP9.4PQ9j 4i94.:k4R:%;pC;/6UZ6(;v;†l1c'14p843h(32W)24g06Y4-69(97^7#9g,9;c;;>> @e8@>i%>=HG>b= >Ch4CBk"B A^1AB_,BF`8FJrJNq4NMu'M Ld6LKx&KJ\5JHe&HI`KI Lt LGSTGE'EGZGhGkDG HZ,IcHI7Lj3IQLLI!Ie[GSIoGIgSILb!IVLQLfI]Ly=Q+=>B9>Ba%B DZ.DIw&I GL=GB:'IsBbIGVWGBK)BJBfB C>"CGHGI^INtUNL@LNcUNLa%Lƒ4Lp KZL Jp K&JNz"NIb2IGe*GF^2FD[$DEi:EDt+DCR.CGh*GBU+BAs0A@W8@ >q'>=U4=:j-9N :79 7m+76SQ9g6*9;[5;>y'>=FG>f=>@tM@=)=>rS>=?!>q=A>@q%@BN6BC}$CD^9DGw"G EH3EGgGEY/ECb'CBDBETBELi=LIIIJcRJ GV$GƒSJz%JL>J:LGSJ&EfG4EC`'CB>RBƒE6EDpDCS5C Gl"GBf1BAk!A@R;@ ?^'? >P9>=R=@c=@=D= >_<>9=.:H 9:"=j'=;OI;>D!>Bk@B7El?EGfG Jg5JLi&LJiFJGVQGCEuC@}H@ >\(=D>j=>j<>7C@CBJ!B AUXABfFB I}*I GG(B:G >CBFs>@FGZ2G‚lHGH F?FHnDHEh|E#Bh+@WB&>A@> @_M@·@—>i>>ÿ/MTrkOÿ @ÿGeneral MIDIÀ0ÿJAZ2ÿMidnight Expressÿ/simutrans-124.3/simutrans/music/17-The-Benevolent-Dictators-March.mid000066400000000000000000000210031474050137200254350ustar00rootroot00000000000000MThd xMTrk½ÿCopyright (C) 2006 shunterð~ ÷°ÿJAZ2ÿYûÿQ¸$ÿ~j"")€ÿ~j)( . )€)@ ""c@Jÿ~j€@ "c"@J)€@)€J¸ $J ( .*@L€@ "ÿNj)€)( . )€)( *ÿj5ÿ<jÿX°[(]ÿThe Benevolent Dictators March° @ÿ/MTrk±Á!ÿJAZ2±2@ '{[2ÿBass±]­‘%F>%:)F>):*F>*:,F>,:*F>*:!F>!:"F>"::5C%F>%:)F>):*F>*:,F>,:*F>*:,F>,:%F>%: :5 ñ%F>%:)F>):*F>*:,F>,:*F>*:!F>!:"F>"::5C%F>%:)F>):*F>*:,F>,:*F>*:!F>!:"F>"::5C%LH%0 *A 7%FH%ÿ/MTrk r¹É ÿJAZ2¹]™&2#PÿDrums¹ @{[<™&#_#P&2#&_#P&2&#_#P&2&##&(&&(&#P&2#&_#P&2#&_#P&2&#_#P&2&##&(&&(&&2#P&#_#P&2&#_&2#P&#_&2#P#&#&(&&(&&2#P#&_#P&2#&_#P&2#&_&2#P&##&(&&(&#P&2#&_#P&2#&_#P&2#&_#P&2#&#&(&&(&#P&2#&_#P&2&#_#P&2&#_&2#P#&#&(&&(&#P&2&#_#P&2#&_&2#P#&_&2#P#&#&(&&(&#P&2&#_#P&2#&_&2#P#&_&2#P&##&(&&(&&2#P'F1P#'1&_&2#P'F&#'_'F#P&2&#'_&2'F#P&'##&(&&(&&2#P'F'&#_&2'F#P&#'_#P'F&2#&'_'F#P&2#'&#&(&&(&'F#P&21P#&'1_#P&2'F#'&_&2'F#P'&#_&2'F#P&#'#&(&&(&#P&2&#_#P&2#&_#P&2&#_&2#P#&#&(&&(&'F#P1P&2#'1&_'F#P&2&'#_#P&2'F'&#_&2'F#P&#'#&(&&(&#P'F&2&'#_&2'F#P'&#_'F&2#P#'&_#P&2'F&'##&(&&(&1P&2#P'F&1#'_&2#P'F#'&_&2#P'F'&#_'F#P&2&#'#&(&&(&#P&2#&_#P&2&#_#P&2&#_&2#P#&#&(&&(&#P&2#&_#P&2&#_#P&2&#_&2#P#&#&(&&(&&2#P#&_&2#P#&_&2#P#&_#P&2#&#&(&&(&#P&2&#_#P&2&#_#P&2#&_#P&2&##&(&&(&&2#P#&_#P&2&#_&2#P#&_&2#P&##&(&&(&#P&2#&_&2#P#&_#P&2#&_&2#P#&#&(&&(&#P&2#&_#P&2#&_&2#P#&_#P&2#&#&(&&(&&2#P#&_#P&2#&_#P&2&#_#P&2#&#&(&&(&#P&2#&_#P&2&#_&2#P#&_&2#P&##&(&&(&&2#P#&_#P&2#&_&2#P#&_&2#P&##&(&&(&&2#P#&_&2#P#&_#P&2&#_#P&2#&#&(&&(&&2#P#&_#P&2#&_#P&2&#_#P&2#&#&(&&(&#P&2#&_&2#P#&_&2#P#&_#P&2#&#&(&&(&#P&2&#_&2#P#&_&2#P#&_#P&2&##&(&&(&&2#P#&_&2#P&#_&2#P&#_#P&2#&#&(&&(&&2#P#&_&2#P#&_&2#P#&_&2#P&##&(&&(&#P&2&#_&2#P#&_&2#P#&_&2#P&##&(&&(&&2#P#&_&2#P#&_&2#P#&_#P&2&##&(&&(&#P&2&#_#P&2&#_#P&2&#_#P&2&##&(&&(&&2#P#&_&2#P&#_#P&2&#_&2#P&##&(&&(&&2#P#&_&2#P#&_#P&2&#_#P&2#&#&(&&(&#P&2&#_&2#P#&_#P&2&#_#P&2&##&(&&(&#P&2&#_#P&2#&_#P&2&#_&2#P&##&(&&(&#P&2&#_&2#P#&_&2#P#&_&2#P&##&(&&(&&2#P#&_#P&2#&_&2#P&#_#P&2#&#&(&&(&&2#P#&_&2#P&#_#P&2&#_#P&2&##&(&&(&&2#P#&_&2#P#&_#P&2#&_&2#P#&#&(&&(&&21P'F#P1#'&_'F#P&2&#'_#P'F&2&'#_#P&2'F#&'#&(&&(&'F#P&2#'&_#P&2'F'&#_&2#P'F'#&_'F#P&2#&'#&(&&(&#P1P&2'F1'&#_'F&2#P#&'_#P'F&2&'#_#P&2'F'#&#&(&&(&&2#P&#_#P&2#&_#P&2&#_#P&2#&#&(&&(&1P&2#P'F&'#1_#P'F&2#&'_&2#P'F'#&_'F&2#P&'##&(&&(&&2#P&#_#P&2#&_#P&2&#_&2#P&##&(&&(&1P'F&2#P'#&1_#P&2'F'&#_&2'F#P'&#_#P'F&2&'##&(&&(&#P&2#&_&2#P#&_&2#P#&_&2#P&##&(&&(&#F&P&##&<&&<&&F#P&##&F&#&P#Z1P&1#‚O181ÿ/MTrkð²ÂÿJAZ2²{UÿPiano²@] A["­’=/8>A<%513jA81%= ?AjA,8= 6/*5:<1>j:*16 6/<<3>-5j<3-6=B:?.>5?$5:=.M:==F5C.>.:.=5BDHAG=%15bAD1= 8I)>><=?:<?8)=H:G6%*5b:=*6=A8CAD,CW,=8A*>.I>1=6:1*6. 6A3CA<%5jA1%8= <>)5?/53D>1=6:16*.A<,5=/8>jA8,= :<*56/1>j:1*6 6A3C>8==:8=5%?/D<<>)553jD<5)?*>.I>1=6:16.*,>5I>8==:8=5,6/1>:<*5j:1*6 -5<<3>6/j<-36 FE.A=Eo=:0A<F5?;=3'=5.A:}AKIQDF=E1A‚=1ADIƒC²@ÿ/MTrkg¶ÆÿJAZ2ÿGuitar¶[2{ ^\@]­ –=EAQDP1L)1AD=EHPDQ?E5L)5DH?E:Q=P6E*L)*:=6EDPAQ=E,L),AD=E=P6E:Q*L)*:=6E6E?P:6=P.KAS0.:A=@DPAQ=E1L)1DA=EHPDQ?E5L)5HD?E=P6E:Q*L)*:=6EDPAQ=E,L),AD=E:Q=P6E*L)*:=6E?P6E=6AP1KDS01=DAñAQDP=E1L)1DA=EDQ?EHP5L)5DH?E=P6E:Q*L)*:=6EAQ=EDP,L),AD=E6E=P:Q*L)*=:6E:6.K=PAS0.:A=@=EDPAQ1L)1DA=E?EHPDQ5L)5HD?E:Q=P6E*L)*=:6E=EDPAQ,L),DA=E=P6E:Q*L)*:=6E:6=P.KAS0.:A=:=I8AI9DJAIVFMS‚ = IDAMƒ-¶@ÿ/MTrk+°ÿJAZ2ÿStringsÿ/MTrkà³Ã<ÿJAZ2“=R³ @ÿMelody³][^{“=,=H ==G=DU‚jIW I/IQ IIHIPT‚OD=X=L=QDY=‚`IYPIHIYIPT‚QD PIdD\DIBWGd BG(DTId DIGBSGQ BG BG=KB=,GXBVBG-IaDSƒDI BTGT BG GJBU GBDWI_0DGZBMIBG)DUI_D I GMBRBG'BT=H=B%GRBTBG+IaDWƒ(DI7IlhIHxFIHHJFIPHuABID9 AIGD=D@IlBGDD;BBED:AEBBEAAKB8?EAA:??CA2=G?ƒ&AG=-BFA*DDB:FEDrB?FoD<B‚iI5 D+HEI=HIO{D; IqFKDpD<F0B@D@BD?‚cBDD2ADB>BHAmDIBiFLDkHXFlIJHjKFIXKKO‚\K IZ)IHZ%HII„`Iÿ/MTrkB°ÿJAZ2ÿThe Benevolent Dictators Marchÿ/simutrans-124.3/simutrans/music/18-Ride-that-train.mid000066400000000000000000000765151474050137200226130ustar00rootroot00000000000000MThd xMTrkHð~ ÷ÿJAZ2ÿQÜÿ 2006.10.06ÿÿ/MTrkÿCopyright (C) 2007 shunter°À0ÿJAZ2ÿ @ÿGeneral MIDIÿj7ÿ_jÿ~j1*@*1 @*F$@*cF@ ÿ~j@ @$@ 1$(1@*@$@*1!1@*[@*(1@*@*@$ÿ~j@ 1$(@*@$@*$!@*[@ 1(1@ '@*1$!1@ @$ÿ~j@*1(@*[@ 1$(1@*@*1$(@ @$@ (1@*ÿvj!@  @ F@ cF@ cA A °ÿ~j[@*!@ @ @@ !@ @@ !@ [@ ÿXÿY°] @ÿRide that train°[(ÿ/MTrkv±Á ÿJAZ2± 4ÿGeneral MIDI±ZÿBass±][({@ÿ @‘"Dx"|Lr~"U"MPZ"UX"O~r"_I"/$PW$!%LX% &TS&&'Da'"Lr"~'UX'"Pn""Hy"wO e"Qv")Zo)&We&)IV)#Dx|Lrz'Dx'|.Lr.z"Dx"|)Lr)z"Ds")Sh)&L[&"Zh""O`"&Pl& )Hp) +Kl+ 'O`'+Pl+ .Hp. 0Kl0 "O`""Pl" 'O`'.Pl. O`Pl "O`")Pl) 'O`'+Pl+ .Hp.0Kl0 1Hn1 0Lq0.Hp.+Oo+ "O`"Pl 'O`'"Pl" (O`("Pl" "O`""Pl" 0O`0+Pl+ 'Hp'#Kl# 5O`5+Pl+ 'Hp'!Kl! "O`"Pl 'O`'.Pl. O`Pl "O`"Pl "O`"&Pl& )Hp) +Kl+ 'Hn' %Lq%"Hp"Oo "O`")Pl) 'O`''Pl' (O`(.Pl. "O`"&Pl& 'O`'+Pl+ .Hp.0Kl0 1Hn1 0Lq0.Hp.+Oo+ "O`")Pl) 'O`'"Pl" (O`("Pl" "O`")Pl) $O`$'Pl' +Hp+#Kl# 5O`5+Pl+ 'Hp'!Kl! "O`")Pl) 'O`''Pl' (O`("Pl" "O`"Pl +O`+.Pl. 2Hp2#Kl# $O`$'Pl' +Hp+!Kl! "O`"Pl 'O`'"Pl" (O`("Pl" "O`""Pl" 'O`'+Pl+ .Hp.0Kl0 1Hn1 0Lq0.Hp.+Oo+ "O`")Pl) 'O`''Pl' (O`(.Pl. "O`""Pl" $O`$'Pl' +Hp+#Kl# 5O`5+Pl+ 'Hp'!Kl! "O`""Pl" 'O`'.Pl. (O`("Pl" "O`""Pl" +O`+.Pl. 2Hp2#Kl# 0O`0+Pl+ 'Hp'!Kl! "O`"&Pl& 'O`''Pl' (O`("Pl" "O`""Pl" 'O`'+Pl+ .Hp.0Kl0 1Hn1 0Lq0.Hp.+Oo+ "O`"&Pl& 'O`''Pl' (O`(.Pl. "O`"Pl 0O`0+Pl+ 'Hp'#Kl# )O`)'Pl' +Hp+!Kl! "O`"&Pl& 'O`''Pl' (O`("Pl" "O`""Pl" .Hn. ,Lq,)Hp)&Oo& 'Hn' %Lq%"Hp"Oo "O`""Pl" 'O`'.Pl. (O`("Pl" "O`")Pl) 'O`'+Pl+ .Hp.0Kl0 1Hn1 0Lq0.Hp.+Oo+ "O`"Pl 'O`'"Pl" O`"Pl" "O`"Pl $O`$'Pl' +Hp+#Kl# )O`)'Pl' +Hp+!Kl! "O`""Pl" 'O`'"Pl" (O`("Pl" "O`")Pl)"Dx"{Lr~"U"M)PT)"Za"Ly"sN\"K".@!"QI",&RL&.'I 'M"Q%"P'QJ' 'F'"XW"#.Qp.!Mt!"Da"Lr~"UX"PnDx|Lrz'Dx'|'Lr'z"D"W$De$I#U I# ÿ/MTrk†¹ÉÿJAZ2¹ @ÿGeneral MIDI¹d™*8¹[(ÿ @¹{]™$LÿDrums™$*b*\&j*&[*J$U*$W*S&!&*T$P*E!$*U*F&!*&U*M$J"*$+&O#&&W"&.&0!&*8$L*$b&j*\*&[*J$U*$W*S&!&*U$L*> *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&$`1$1U&.b$\!$&.)&(&&.M$O$.X.v$`&$&.-.)&0#.&$P*E!$*U*F&!*&U*M$J"*$+&O#&&W"&.&0!&$P*C$*W*U&&*V*J$[*$V&*O*&Z.$`&~.$&/&!$&$^. .$.&j#&&$[$&/2#20$h$00-J -$L*8$*b*\&j*&[*J$U*$W*S&!&*T*E$P!$*U*F&!*&U*M$J"*$+&O#&&W"&.&0!&*8$L$*b&j*\*&[$U*J*$W*S&!&*U*J$M*$S*S&y* &O$R*9*$1&.& &P&2&!&$O.]!$.R,)&*1,*&U$S*.*$Y&*P*&Y$O*=*$W*X&m &*U*=$S"*$,&C& &b&h$P*C$*W*U&&*V*J$[*$V*O&*&Z$M*J*$_*S&y*&_$R*9*$7&.&&P&7&&$`1l&F$1&S3l&$\!$&3)&(&&3M$O$3X3i&$`$&3-3L&0#3&$^3t$3V&$\3m)3$&"3O3 $k3\"3$S$i3&3&$,3@3 $l3M!3$.&#&3g$h$3$Q3$i&&$3.&#& $b3j*3$#&&$f3`#$P33y&g$c!$-3&&H3Z#&33$o3$&C& && $e&&$&6&&|& $i1o!$1S$f&33&$-3C#33o$f 3$X$\3&3$&+3O 3$e3B3$W$h&3&$3-3F"3$f3`!3$S&$_3q)3$&"&X3J3&1$n1$W$h3&3$&.3<3 3W$b$3Y$h&3"3$&*3$c.$1&!&&$c&$1& & &9$`&$&1& && $c&!&$U1l$`&F$1&S3l&$\!$&3)&(&&3M$O$3X3i&$`$&3-3L&0#3&3t$^$3V$\&3m)3$&"3O3 $k3\"3$S$i3&3&$,3@3 $n11$W3$h&3$&.3<3 3W$b$3Y3$h&"3$&*3$c.$1&!&&$c&$1& & $`&9&$&1& && $c&!&$U$`1l&F$1&S&3l$\!$&3)&(&&$O3M$3X3i$`&$&3-3L&0#3&$^3t$3V&$\3m)3$&"3O3 $k3\"3$S$i3&3&$,3@3 $n11$W&$h33$&.3<3 $b3W$3Y$h3&"3$&*3$c.$1&!&$c&&$1& & $`&9&$&1& && $c&!&$U1$n1$W3$h&3$&.3<3 3W$b$3Y&$h3"3$&*3$L *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&*8$L*$b*\&j*&[*J$U*$W*S&!&*T$P*E!$*U*F&!*&U*M$J"*$+&O#&&W"&.&0!&*>$U *$U&*_&*X*5$P*$U&*Z*&[*>$L *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&$L*8*$b&j*\*&[$U*J*$W*S&!&*T*E$P!$*U*F&!*&U*M$J"*$+&O#&&W"&.&0!&*F$X$*W&*j&*Y*C$S!$*J&d&Z&d&ÿ/MTrk8²ÂÿJAZ2²]ÿGeneral MIDI²i "ÿPiano²[(ÿ @²@{y’I\ O\M\J\ I+OMAF JMWJYC[A2C JM3I\O\ J\IOJ>I\OPJ\I:O JTT:T X\\\Y\XY\AX\\\Y\!YYMX\\RYYH\\VYYM\$\\Y\YR$Y\\YA\Y\\\YN"\\ Y\G[\W\BW [RKR U\YX=U Y.W\Q\R\U\QU WKSR W\P\T\K4PWTKPKN\WURV!NO!OWR*WOTWP\:PT W-W\N\RXNOF:O R W‚pL\M\R\UYLM UR/L\RSMYU\ LMUR.L\RUMYU\*L#UMR%R[AR L\U\MZRP$LR.UMRP#U\M\L\R-LM US\T[YTWYSTYWFS\Y\TYW\8S TWY,R\YSVV1RVY0Q\R[WTUYQRWUFQ\RYW\U\8Q RUW,WSP\TV1PTW@^\X\Y\X^YYZ^@^YY\^\^Y!Y\^:^YX\^\Y\X Y^Y\ ^7^YY\^\Y^Y\^K^YY\^YX\X ^YY\^A^YY\^W^YY\^V^YX\^ZY\XY^YW ^@^YY\^\ ^YVRXL\MU LoR M%L\R\MYLdFNRMFK\R\=KR&WXQ\RU QoW R%Q\W\RYQdKNWRKW\P\=PWIXJNP\M\IaJMPV?\%?H\C\XCHI\OZLXIKLOP\MVI\ J\IBMP JJ\D\DJ J%M'DJM‚mQ\R[W[Z\QRZW;QXRRWUZ\Q$RZW*Q\RWWUZ\Q ZRWQ\RSW\ZTQXZRW#Q\WXR\Z\"QR WZ!IXJNP\M\IJPM(C\H\DHFCFIXO\L\I#OL(J\D\DJF%DFVR\K\H\KHR_O?O KVH\R\bRO\HK!OMK\O\$KK6'KOH?O\HR\=ORK\O["KZHKOHO\R\@RO1MVP\I\IJ\EADJMPAD\J\DJDO\KLH[HH\UKO H)LVO\I\II\E@DILO@I\C\DICqA\%AJ\D\XDJjP\J\F\JFP_M?M JVF\P\bPM\FJ!MJQ\W\UZRZQRWUAQ\U\WYR\%QRUW2PZWSTT0PTW4MVP\I\IJ\EADJMPAJ\D\DJDC\H\DHFCFLVO\I\II\E@DILOI\@C\DICqA\%AD\J\XDJqY:Y ]\^\a\]^aA]\a\^\!^^M]aaR^^HaaV^a^M$a\^a^R$^a\^Aa^a\a^N"a\ ^aG`\\\B\ `WKW Z\^X=Z ^+JNIXP\M\IJPM/KVO\H\ HBKO'H\C\DH HKCKHLVO\I\II\E@DILOI\@C\DICD\J\DJFDFK\O\$KK6'KOH?O\HR\=ORK\O["KZHKOHO\R\@ROR\K\H\KHR_O?O KVH\R\bRO\HK!OIJNIXP\M\IaJMPV?\%?C\H\XCHLVO\I\II\E@DILOI\C\@DICoMLP\I[IJ\UMP J+L\O\$LM6'MOJ?JO\R\=ORL\O[ MNLNM JKOJR\O\@RO3K\O\$KK6'KOH?HO\R\=ORK\O["KZHKOHR\O\@RO/JNIXP\M\IJPM(H\C\DHFCFIXO\L\I#OLMLP\I[IJ\UMP J‚Q\R\W\ZYQR ZW/Q\WSRYZ\ QRZW.Q\WURYZ\*Q#ZRW%W[AW Q\Z\RZWP$QW.ZRWP#R\Z\Q\W-QR Z!IXJNP\M\IaJMP}C\H\DHFCFIXO\L\I#OL(D\J\DJFDFVR\K\H\KHR_O?O KVR\H\bRO\HK!OMK\O\$KK6'KOH?HO\R\=ORK\O["KZHKOHO\R\@RO0I\PZJXMXIAJ MPZ?\%?C\H\XCHI\OZLXIKLOXMLP\I[IJ\UMP JzR\M\J\MJR_O?O MVJ\R\bRO\JM!OR\K\H\KHR_O?O KVR\H\bRO\HK!OKMVP\I\IJ\EADJMPD\J\ADJDH\C\DHFCFI\OZLXIKLOJ\D\DJF%DFR\U\Q\W\Q WUKJR"T\W[P\K2P TW3Q\W\R\QRW@Q\WTRDQ:W R{I\PZMXJXIAJ MPXO\KLH[HH\UKO H'IXO\L\I#OL/P\MVI\ J\IBMP JJ\D\DJ JMDJMK\O\$KK6'KOH?O\HR\=ORK\O["KZHKOHO\R\@RO3K\O\$KK6'KOH?O\HR\=ORK\O["KZHKOHO\R\@RO0I\PZMXJXIAJ MPO\KVH\ HBKO'H\C\DH H%K'CKHLVO\I\II\E@DILO@C\I\DICD\J\DJFDFL\R\PZMZLMRPAP\L\M\RY%LMRP2KZRSOT0KOR;WXQ\RU QoW R%Q\W\RYQdKNWRKP\W\=PWIXJNP\M\IJPM?\%?H\C\XCHIXO\L\I#OLMLP\I[IJ\UMP JƒQ\R[W[Z\QRZW;QXRRWUZ\Q$RZW*Q\RWWUZ\Q ZRWQ\RSW\ZTQXZRW#Q\WXR\Z\"QR WZ"I\PZJXMXI#PJMKLO\H[HH\UKO H)O\LVI\II\E@DILO@I\C\DICqA\%AJ\D\XDJK\O\$KK6'KOH?O\HR\=ORK\O["KZHKOHO\R\@ROR\K\H\KHR_O?O KVH\R\bRO\HK!OJI\PZMXJXI#JPMKLO\H[HH\UKO H(I\OZLXIKLOZA\%AD\J\XDJI\ M\O\J\ I+OMAF JMWJYC[A2C JM3O\I\ J\IOJ>I\OPJ\I:O J‚pL\M\R\UYLM UR/L\RSMYU\ LMUR.L\RUMYU\*L#UMR%R[AR L\MZU\RP$LR.UMRP#M\U\L\R-LM Uƒ Q\R[W[Z\QRZW;QXRRWUZ\Q$RZW*Q\RWWUZ\Q ZRWQ\RSW\ZTQXZRW#Q\WXR\Z\"QR WZƒ L\M[R[U\LMUR;LXMRRUU\L$MUR*L\MWRUU\L UMRL\MSR\UTLXMUR#L\RXM\U\"LM RUS\T[WYYTSTYWFS\Y\TYW\8S TYW,YSR\VV1RVY>OTRWU\:OUR-OYRWU\8UOROUR\UVoOUR%RZO\U\7O RU"I\PZMXJXIAJ MP O\K\F\/OFKCM\K\E\"MKETR\N\H\"RNH‡²@ÿ/MTrk6µÅÿJAZ2µ]ÿGeneral MIDIµ@[({ÿ @µiÿGuitarµ h•7]2[,72>7D2F*72I7\2d,72G297J*7 2D7J2R627@2H7G0272[7\72T2_7S!72a7Z2-72G.]4j5[4.5>.D5F*.5I7d.\,.7G79.-*. 7D5R.J65.@5H.G05..\7[.7T.S7_!.5a.Z7>5 .-:[3]9j93:>:F3D*3:I: 3-4[.N5I 4.5?.G5G4.5<.U7[:7.:7Y.]17.D5P.J15.65K.N@5 ..]7O&.7K.U7Y7. 5K.]'5.S5L;X`5[/5>C>R5K4>5A9j3]:[93:9:F3D*3:L7R0R-70:0R7R10 7>1R7R-71:7R1R11 72R8RI28+2"81$88R22R12 8;3N:I9[ 93:?3G:G43:<<[3U:<3:3]7R0R-70:0R7R10 7>7R1R-71:1R7R11 78R2RI28+812"$82R28R12 8;:[3Y,:3>:,3D*:&3b3:Z$:3T3':,$:3G:Q3*: 3B5M:`#5 :L:\5I&5:#5X7Z'5 7G5.:.!:55_7J*57N8R2R-82:8R2R12 8>0R7R-70:0R7R10 7>1R7R-71:7R1R11 78R2RI82+812"$88R2R212 8;5Q.KB. 5+5L.O=.55P.U<.5858.'5.5L.3(.5;:U3M6:3@:K3J0:3<^3_3<T3J7R0R-70:0R7R10 7>7R1R-71:1R7R11 78R2RI28+2"81$88R22R12 8;:I9[3N 93:?3G:G43:<3U<[:<3:0R7R-70:0R7R10 7>1R7R-71:7R1R11 78R2RI28+2"81$82R28R12 8;7\0^,07>0_7b*07I0]7e,07G0e7R*0 7D0^7\,07>0_7b*07I7e0],07G7R0e*0 7D2R8R-82:8R2R12 8>7R0R-70:0R7R10 7>1R7R-71:7R1R11 78R2RI28+812"$88R22R12 8;+M:`#+ :L:\+I&+:#7Z+X'+ 7G+.:.!:++_7J*7+N0^7\,07>0_7b*07I0]7e,07G7R0e*0 7D2R8R-82:2R8R12 8>0R7R-70:7R0R10 7>1R7R-71:1R7R11 78R2RI82+812"$88R22R12 8;3d:M=:3$3I:L83:<<_3W23<@3G7R0R-70:7R0R10 7>1R7R-71:7R1R11 72R8RI82+812"$82R28R12 8;3\:^,:3>3G:E*:3I38:G,:3G3::=*: 3D3Y:[,:3>:,3D*:&3:Z3b$3:T3':,$::Q3G3*: 3B2R8R-82:2R8R12 8>0R7R-70:7R0R10 7>1R7R-71:1R7R11 72R8RI28+812"$82R28R12 8;:^5\,:5>:E5G*:5I58:G,:5G5::=*: 5D:[3Y,:3>:,3D*:&3b:Z3$3:T3':,$:3:Q3G*: 3B2R8R-82:8R2R12 8>0R7R-70:0R7R10 7>7R1R-71:7R1R11 78R2RI82+812"$822R8R12 8=3K9W:M 93 :7:J3H*3:I<_3Z/3<C7R0R-70:7R0R10 7>1R7R-71:7R1R11 78R2RI82+812"$88R22R12 8;:`0M#0 :L:\0I&0:#7Z0X'0 7G:.0.!:00_7J*70N:[3Y,:3>:,3D*:&:Z33b$3:T:,3'$:3G3:Q*: 3B2R8R-82:8R2R12 8>0R7R-70:0R7R10 7>1R7R-71:7R1R11 78R2RI28+2"81$82R8R212 8;5[.]4j4.5>5F.D*.5I7d.\,.7G79.-*. 7D:U3M6:3@3J:K0:33_<^3<T0R7R-70:7R0R10 7>1R7R-71:7R1R11 72R8RI82+812"$88R22R12 8;9j:[3]93:>:F3D*3:I: 3-2R8R-82:8R2R12 8>0R7R-70:7R0R10 7>1R7R-71:1R7R11 78R2RI28+2"81$82R8R212 8;7\0^,07>7b0_*07I7e0],07G7R0e*0 7D0^7\,07>7b0_*07I7e0],07G0e7R*0 7D2R8R-82:8R2R12 8>0R7R-70:7R0R10 7>1R7R-71:7R1R11 78R2RI82+812"$82R28R12 8;7]2[,72>7D2F*72I2d7\,72G297J*7 2D7J2R627@7G2H0272[7\72T2_7S!77Z2a2-72G.]4j5[4.5>5F.D*.5I7d.\,.7G79.-*. 7D5R.J65.@.G5H05..\7[.7T7_.S!..Z5a7>5 ./3K9W:M 93 :7:J3H*3:I<_3Z/3<C5F.D*.5I7d.\,.7G.-79*. 7D.J5R65.@.G5H05.7[.\.7T7_.S!..Z75a>5 .25M/<5F5[>_%5>L>N5C,5>L:U3M6:3@3J:K0:3<^3_3<T:R3R-:3:3W9W#93UHMVCMJD#KUJMKHW>HVJTQMVJNM#O^2I\ODFHI*HIFRFAH‚IF7FTFQOa MWOMUFV6F=MV@M KT[K5JfPJMN)MJT*JJHO1H@HYKHM7*MG`+G$FS{F‚P?_*?Cd2CF_6H[FrFSHzFCSyCFWoJfFMJMN)JTM*JJHO1H@HYKHM7*MG`+G$FS{FCLTCH\8HKl#KJ9QJH>HMVCMJD#KUJMKHW>HVJTQMVJNM#O^2I\ODFHI*HIFRFAH‚IF7FTFÿ/MTrk*m·ÇÿJAZ2· "ÿGeneral MIDI·jÿSolo·[<y@@—"_·[({ÿ @—._·][({] "Z—"O.O.".e:e."Z:5G.)G,T58T)Z,%?81?%&h2h1'&25U)U')5+N7N7+"X.XZ"..A"A".i:i.Z)@:5@.5),M8MZ1A8,%A%2j1&j'5Q2)Q&'5)+P7P7+"W.WZ.".C"C.".b:bZ:)N5N.,P)58PZ%<1<,82b&b1%'&)O25O')5+T7T7+.["[Z"..I"I..`":`Z)G5G.:58Z),ZZ8,%?1?1%2j&j'5W)W&2')5+W7W+7Ç=—CkJk· ~ç(—AkFkç),-/0234· | {ç68:;<· yç>?· xç@B· u t q p l k h g e d b a ^ ] [ Z X W U T6 V) W Y [ ] ^ a b e f i k n o q r u vç@· xç?· yç>;9· {ç65· }ç42· ç-+)%# )—FCJAç· —CiJiAiç%—Fiç+-0@AB · } z x v s q n m j h f e b a ] \ Z Y W V S Q4 P Q S T V W Y [ ^ _ e g l mçA@· o pç@· sç?>=· tç<;· vç:· xç87· zç64· {ç20/-+)('· ~ç%$#· ç" —JFCAç%@ˆ· —Aiç—FiIiCiç #$'-.0· ~ç1357· |ç:;=?· y x u t q o l k a ^ \ [ Y W T Q M L I H% K L N O S U X Z _ a d f h i l n p r v wçA· z { ~ { ç@?><;:9861%—FICAç$ —IkAkCkFkç· ~ç&*./1469:=@· } { z w v t s p n i h e c a _ Z Y W U S R P N% P Q U V Y Z \ ] _ ` c e i j l m s u y zç@· |ç?· ~ç>· ç=<;:987643210.-,+—IFACç@Aˆ· ~—Io?oEoAoç"%'(· }ç*0357:;?@ · | { v u p n l k h g d b _ ^ \ [ W U R O K J J L N P R S V W [ ^ d h m o q s u wçA· y {ç@?>· ç=< ;:987653210/.,*)(—IAE? Akç—CkIkFk· ç!&+,/01>? · } { y x v t r q l k i g e c a ` ] \ X W T S M K K L N P R U W X \ ^ a c e f i j l kç>· mç=· oç<;· r sç:· uç9· vç86· x yç5· |ç4· }ç31· ç0/. -,+—CAIFç,$@‡d—Ac$A ç#'—F{· ~ç()*+· uç,/34· nç89:;=A· l o } 1—FF]I}F· sç"· nç&'· gç)156· hç9<=· kç?· m q { ~<—I IYç!· |—IFmç468:;=· dç?· eç@· j l u {  ~9—FFT· —CjFç /· yç0· sç12· jç345· cç6· eç8:<· iç=@· { ~ G—CAQ· |—FkAç#'+· yç,.· p lç1568· g iç9:=· qç>?· wç?· ~ ç@9—FF\Irç.—F· ç/0· ~ç2· |ç56· sç89· oç;<=· k hç>@· r z<—I IiFZI· ç!· |ç"$· tç*:· nç;=>?· lç@· n t y }9—F FXFCM· ç!"· {ç%)· vç+/4· oç5· iç8:<=?· h jç@· E—AHCFiAç!$· |ç&· xç()+/· mç0· jç46;>@· h {5—FuF/FyHnRnOnKnA—A F|· ~ }ç· v sç!#· oç'· nç*.2=>?· s v 1—F FaIyF· ç"· xç)3· tç579· oç;=?· pç@· w {=—I I^FqIç·  |ç · vç'· oç56· jç8:;· hç=>@· n |<—F FXFCbç · xç)-/· sç023· jç6· eç;· `ç=>@· d }B—CAJFqA· tç$&· q oç()· jç+· hç,-/· fç1:;?@· gçA· l ~5—FFWFIsç · ç!$· v mç(*0· jç2469<=>?· l 8—IITç!—IFq· zç0· kç14· jç56789;· lç>· mçA· x ;—F FUCr· —F· {ç#/0· mç568· gç:;?@· f g q |  |<—CA[FvAç-· ç1· wç3· uç578· nç;· kç=?· k l n o t v  }$—FxF.FyHmKmRmOm· r } 4—F Fbç—IxFç"· |ç$· xç&(*,· qç.· mç/2· hç4· gç9<>· iç@· k { | {7—I IbFu· —Iç$· oç(*· jç,-/· fç0· hç15· sç9· u zç:· {ç;<>· }ç@A>7—F FYFCoç· vç#$&· mç')· jç+/34569· gç=· lç?F—CATFrç—Aç· ç $· zç%· tç'+· nç-/17· dç9;<· bç>?· fç@· :—F F\IsF· vç· }ç· mç!#· hç%)/168· hç:· lç;· zç<>· ç@=—I I_FkIç!· oç"$· }ç(*345· iç8· kç9;· mç<· oç?B· ç@>—FFQç· n—CeFç!· iç&· fç+2356· aç9· _ç;=?· ]ç@· A—CANAFtç"#'· | zç+-· sç0· qç4· nç89· lç;<@· k m |2—FuF.FyOmHmKmRm· s tç=· v wç<;· yç9· zç8· | }ç7· ç543210/.- ,+*('&%#! —MORU(çA@óF—Ac$A F{ç'· ~ç()*+· uç,/3· nç489:;=A· l o } 1—FF]I}F· sç"&· nç'· gç)156· hç9<=· k mç?· q { ~<—I IYç!· |—FmIç468:;=· dç?· eç@· j l u {  ~9—FFTF· —Cjç · yç/0· sç123· jç45· cç68· eç:<· iç=@· { ~ G—CAQç#—Fk· |—Aç'+· yç,.· p lç156· gç8· iç9:=· qç>?· wç?· ~ç@· 9—FF\Irç.· —Fç/· ~ç02· |ç56· sç89;· oç<· kç=· hç>@· r z<—I IiIFZç!·  |ç"$· tç*:· nç;=>?@· l n t y }9—F FXCMF· ç!"· {ç%)· vç+/· oç45· iç8:<=?· hç@· j E—AHCç!—FiAç$· |ç&· xç()+/· mç04· jç6;>@· h {5—FuF/FyOnRnHnKnA—A F|· ~ }ç· v sç!· oç#· nç'*.2=>?· s v 1—F FaIyF· ç· xç")3· tç579· oç;=?· pç@· w {=—I I^FqIç·  |ç '· vç5· oç68· jç:;=· hç>@· n |<—F FXFCbç )· xç-/· sç023· jç6· eç;· `ç=>@· d }B—AJCFqA· tç$&· q oç()· jç+· hç,-/· fç1:;?@· gçA· l ~5—FFWFIsç !·  vç$· mç(*0· jç2469<=>?· l 8—IITç!· z—IFqç0· kç145· jç6789;· lç>· mçA· x ;—F FUCr· —F· {ç#/05· mç68· gç:;?@· f g q |  |<—A[CAFvç· ç-13· w uç57· nç8· kç;=?· k l n o t v  }$—FxF.FyHmKmRmOm· r } 4—F FbIxç—Fç"$· | xç&(*· qç,.· mç/2· h gç49<· iç>· kç@· { | {7—I IbIFu· ç$(· o jç*,-· fç/01· hç5· sç9· uç:· z {ç;<>· }ç@A>7—F FYCoFç· vç#$&'· mç)· jç+/3456· gç9=· lç?F—ATCFrç—A· ç $· zç%'· tç+· nç-/17· dç9;<· bç>?· fç@· :—F F\IsFç· v }ç· mç!· hç#%)/168· hç:· lç;· zç<· ç>@=—I I_IFkç!· oç"· }ç$(*345· iç89· kç;· mç<· oç?B· ç@>—FFQç· n—FCeç!· iç&+· fç235· aç69· _ç;=· ]ç?@· A—ANCç"—AFtç#'· | zç+· sç-0· qç4· nç89· lç;<@· k m |2—FuF.FyRmKmHmOm?· xç@B· u t q p l k h g e d b a ^ ] [ Z X W U T6 V) W Y [ ] ^ a b e f i k n o q r u vç@· xç?· yç>;9· {ç65· }ç4· ç2-+)%# )—JACFç· —Jiç%—AiFiCiç+-0@AB · } z x v s q n m j h f e b a ] \ Z Y W V S Q4 P Q S T V W Y [ ^ _ e g l mçA· oç@· pç@· sç?>=· tç<· vç;:· xç87· zç64· {ç20/-+)(· ~ç'%$· ç#" —JFAç—C%ç@…,—>eJeCeOeHeTe'T>CCeJe>eJOOeHTeHe'J>OTCHHe>eJeOeCeTe(O>HJTCB_G_J_>_S_N_'BG^NSB^>^J^J>N^S^G'BJN>SGN^G^>^S^B^J^(SBJNG>>WMWFWRWAWJW'F\JM>RAA\J\M\R\F>\'JRM>FA>bRbMbJbFbAb(MJ· —AR>FFiAiCiIiç #$'-.0· ~ç1357· |ç:;=?· y x u t q o l k a ^ \ [ Y W T Q M L I H% K L N O S U X Z _ a d f h i l n p r v wçA· z { ~ {ç@· ç?><;:9861%$—IFAC AkFkIkCkç&· ~ç*./1469:=@· } { z w v t s p n i h e c a _ Z Y W U S R P N% P Q U V Y Z \ ] _ ` c e i j l m s u y zç@· |ç?· ~ç>· ç=<;:987643210.-,+—ACFIç@A…1—TWOW>WCWHWJW'OXCJXHXCX>XTXJH>OT'TO>CHJHZJZTZ>ZOZCZ(O>THCJJQSQBQNQGQ>Q'NRJSSRJRBR>RGR>NGB'NSJBG>NUJUGUBU>USU(GB>SNJROJOFOAO>OMO'J\R>\FM\A\>AMR\JF\'MRJAF>>aJaAaMaFaRa&· ~—AF>RJMEoAo?oIoç"%'· }ç(*0357:;?@ · | { v u p n l k h g d b _ ^ \ [ W U R O K J J L N P R S V W [ ^ d h m o q s u wçA· y {ç@?>· ç=< ;:987653210/.,*)(—?IEA ç—FkCkIkAk· ç!&+,/01>? · } { y x v t r q l k i g e c a ` ] \ X W T S M K K L N P R U W X \ ^ a c e f i j l kç>· mç=· oç<;· rç:· s uç9· vç86· x yç5· |ç4· }ç31· ç0/. -,+—IFCAç,$@T—JEZJHAHFGZFD7DA<^H^…P>C@Hÿ/MTrkV°À0ÿJAZ2ÿGeneral MIDI°ÿRide that trainÿ @ÿ/simutrans-124.3/simutrans/music/19-Rockin-trucker.mid000066400000000000000000000464301474050137200225530ustar00rootroot00000000000000MThdxMTrkfÿCopyright (C) 2007 shunterð~ ÷ÿJAZ2ÿ 2006.10.06ÿÿQ“àÿ/MTrk¡À0ÿJAZ2ÿ @ÿGeneral MIDI°ÿ~j'@@@@!ÿ.j@ÿ~j1111@ÿ~j'@@@@!''ÿ~j@@@@ÿ~j@('@ÿ 2006.10.06ÿjÿVjÿXÿYÿRockin` truckerÿ/MTrk=±Á ÿJAZ2±@ÿGeneral MIDIÿBass±Z @]{ÿ @±[(„X‘NkTkNC+V+ LkVkNkRk]s$\Z$W3=$V $+$R.$Fq"bV""$YP$ ]) A"$XP$(&Z[&'T`'(Za()SF)*$TC$-)V1)?&R`&%\c%$X $eT:6$Z$$I6$M\+b[++Uq+~Y?2)V )+$M0$ R]Rp$^$kZ0@+IO+*+U;l +l&M,& TT$$_w$y+X+b)^)-)R8)!NZ!#VS#%$^$kZ0@$U@$0$_T$((Kh( )VI)'$ZF$*WM#Sc $YP$ ]) A"$XP$(&Z[&'T`'(Za(_wy&X&b)V )+$M0$ R]Rp$^$kZ0@W%J1 &Xo& So $\Z$W3=$V $+$R.$Fq"bV""$YP$ ]) A"$XP$(&Z[&'T`'(Za()SF)*$TC$-)V1)?&R`&%\c%$X $eT:6$Z$$I6$M\+b[+_wy&X&b)V )+$M0$ R]Rp$^$kZ0@W%J1 &Xo& So $_w$y+X+b)^)-)R8)!NZ!#VS#%$^$kZ0@$U@$0$U@$0)VI)'$ZF$*`;>$L<$;!\[!Lr$YP$ ]) A"$XP$(&Z[&'T`'(Za(_wy&X&b)V )+$M0$ R]Rp$X$!$N)$(Si()UM)+W%J1 &Xo& So $\Z$W3=$V $+$R.$Fq"bV""$YP$ ]) A"$XP$(&Z[&'T`'(Za()SF)*$TC$-)V1)?&R`&%\c%$\Z$W3=$V $+$R.$Fq"bV""_wy&X&b)V )+$M0$ R]Rp$^$kZ0@W%J1 &Xo& So $_w$y+X+b)^)-)R8)!NZ!#VS#%$^$kZ0@$U@$0$_T$((Kh( )VI)'$ZF$*`;>$L<$;!\[!Lr$\Z$W3=$V $+$R.$Fq"bV""_wy&X&b)V )+$M0$ R]Rp$^$kZ0@+IO+*+U;l +l&M,& TT$$`4$$O6$(]]()V`)*cU*#+L-+;:#I1# $h$ÿ/MTrk ¹ÉÿJAZ2¹]ÿGeneral MIDIÿDrums¹[7 @fÿ @¹{ƒ`™$X3E3$W3q&r!&3U$O3\3$Z&3r3&W3R$L3$[&3\&3X$V3K 3$W&z3m&3W3W$S$3[3]&_3&Z$U3i3$X3&&3X3$I3$#&&#&&#&&#22#2o2#00#-6-#$J3g$3Y3|&i3&W3\$M3$X&3v3&^$L3R3$[&3\&3X$V3K 3$W3m&z&3W$S3W$3[3]&_3&Z3i$U3$X&3&3X3\$M3$Y&3w&3Y3d$L $3W3l 33W&&3$J3g$3Y&i3|3&W$M3\3$X&3v3&^$M3\3$Y3w&&3Y$L3d $3W3l 33W&&3$X3E3$W&r3q!&3U$O3\3$Z&3r3&W3g$F3$&_&!&~&&!&&&!&&&&&b & && 3g$J$3Y&i3|3&W3\$M3$X&3v3&^3\$M3$Y3w&&3Y$L3d $3W3l 33W&&33K$P3$Y3w&&3\3v$O $3X3&&3[3$I3$#&&#&&#&&#22#2o2#00#-6-#1$V$1X3y&&335 33$O$33533z& &33E& &33\$[$33=3&3&33J3$U3o$3 3H3!3v&&3&o3E3&$S3R3$3B 3&3v3&3B3 3b$I$33B3!&3l3&&3='3&$D383$!38 3&3l&3 3J3 3M$P3$&&&&!&z&!1$^$1[3&3&3A3$P3_3$3H$3&i3w&33>& &33\$[$33=33&&33J33o$U3$ 3H3!3v&3&3E&o3&3g$M3$383 &3m&333 33$P3$ 3>!3&3&3 39&3&3m$S3$393!&3v &3332y32$P3e$30|3E033~&|3&--!3j$P3$36 3&w3t&3353$U3d$3 3E!3&3y&3&3P3&3S$P3$3O3 &3t!&33@33l$J$33C3 &3z&3 &3J&3 $R3X$3353 &3r&33A!3$S3r3$323 &3`&3&3M&3$R3b3$#3R&>3&#&]3j$F3$&#&3O&3#$L&3w&3$#0&w0&#0&, ,0&#0|&0&#1$V$1X3y&&335 33$O$3353&3z &33E& &33\$[$33=33&&33J33o$U$3 3H3!3v&3&&o3E3&3X$R$3353 &3r&33A!33r$S3$323 &3`&3&3M&33J$\3$3J 3&3i3&3> 3$`3E$33= 3&33&3R&&31$^$1[3&3&3A3$P3_3$3H$3&i3w&3&3> &3$P3S3$3O3 &3t!&33@3$J3l$33C3 &3z&3 &3J&3 3j$P3$36 3&w3t&3353$U3d$3 3E!3&3y&33P&&33m$S3$393!3v& 3&332y32$P3e$30|3E03&|3~3&--!3S$P3$3O3 &3t!&33@3$J3l$33C3 &3z&3 &3J&3 3S$P3$3O3 3t&!&33@3$J3l$33C3 3z&&3 &3J&3 $R3X$3353 &3r&33A!33r$S3$323 &3`&33M&&3$[3e$3#3E3#&3o3&#353#&33&#36$O3$#&3&3#353#1$V$1X&3y3&35 3$O3$33533z& &3&3E &33S$P3$3O3 &3t!&33@3$J3l$33C3 3z&&3 &3J&3 3S$P3$3O3 &3t!&33@3$J3l$33C3 &3z&3 &3J&3 $b3$33633&&336!33$f$3 &&000\ 0 ---$^1$1[3&3&3A33_$P3$3H$33w&i&33>& &3$P3S3$3O3 3t&!&33@3$J3l$33C3 &3z&3 3J&&3 $V1$1X3y&3&35 3$O3$33533z& &33E& &33b$R$3&>3R3&3j$F&]3&$3O&&33w&$L&3$0&w0 &&0, &,&0&0|&03j$P3$36 3&w3t&3353$U3d$3 3E!33y&&3&3P&33S$P3$3O3 &3t!&33@33l$J$33C3 &3z&3 &3J&3 3j$P3$36 3&w3t&33533d$U$3 3E!33y&&33P&3&$R3b3$#3R&>&3#$F&]3j3$&#&3O&3#&3w$L$&3#&w00&#&, 00&,#0|&&0#$P1o1$X&3&3Z3_$P$3&Z&&&&i &3\$M3$Y&3w&3Y$L3d $3W3l 33W&&33W$S$3[&_3]3&Z$U3i3$X3&&3X3]$X$3W3l&&3\3]$M3$-i-&3_3&&t&$X3E3$W3q&r!&3U3\$O3$Z3r&3&W3\$M3$Y3w&&3Y3d$L $3W3l 33W&&3$X3E3$W3q&r!&3U$O3\3$Z&3r3&W$L3C$3&g&&X &&&$S33$&m&-&q &&&3E$X3$W3q&r!&3U3\$O3$Z&3r3&W$M3\3$Y3w&&3Y$L3d $3W3l 33W&&33K$P3$Y3w&&3\$O3v $3X3&&3[3C$L$3#&g&#&X&#&&#$S3$3#&m&#&q&#&&#$V1$1X&3y&335 3$O3$33533z& &33E& &3$P3S3$3O3 3t&!&33@3$J3l$33C3 &3z&3 3J&&3 3R$S3$3B 33v&3&3B3 $I3b$33B3!3l&3&3=&'3&$P3S3$3O3 &3t!&33@3$J3l$33C3 &3z&3 3J&&3 $^1$1[3&3&3A33_$P3$3H$33w&i&3&3> &33S$P3$3O3 &3t!&33@3$J3l$33C3 &3z&3 3J&&3 3R$S3$3B 3&3v3&3B3 3b$I$33B3!&3l3&3=&'3&3`$P 3$333!&3d&33>3$U3b3$-V3H3-&|3d&33M&&33j$P3$36 3&w3t&33533d$U$3 3E!33y&&3&3P3&3S$P3$3O3 &3t!&33@3$J3l$33C3 &3z&3 &3J&3 $R3X$3353 &3r&33A!33r$S3$323 3`&&3&3M&33e$[3$#3E3#3o&&3#353#&33&#$O363$#3&&3#353#&&#&&#&!&#&&#22#22#00#00#--_&&A$t1Y1$ÿ/MTrk)-²ÂÿJAZ2²[2ÿGeneral MIDI² &wÿPiano²{]ÿ @²@ƒ`’ZUQU7U+UZXU[UX7++U7UK7X [+Q\U9UTU2U\YU]UX929U2UK9Y ]T2WUOU4U(UWVUXUX4((U4UK4V XO(2c9e;]UY[\JTYV\Y92]VT\]<TEVHYR9f2uTYV]!T^T2 9ZU7UQU0UXUZ[UHX Q[70XU9UQU0U[U.Q X[9 0\UTU9U2U\YU]UHY T]92YUTU`[47Y`[0]TX0T7`7D`RTL0>`T0 7 3g`]Zn'Z`34S[Y`H`4[7V`\0ZTX0T`77LTW0>`T`T07Zk3j`[$Z`34L[V`<`4[7W0V`bT`07 `T027C 07²@ ’3k3!Rh%R ²@’7H0F87Wp[l0XPW[X9N[ZX^0<[X 09[TX[[X7D[[0BXb"[X 07X\[M[X9N0I[bXi[X 90X_[Y[X7E0C[bXf[X 70 [UXYX[0E9D[_Xa[X 90[TX[ [XQR7I0D-7Q0 TZ&T0LVm9U09V T_TN]^5<`] 5>`T][`]N5I`b]i`] >5]_`Y`]D]a`] >5`T][ `]VRU5L5>V Y_Y7ZT^0[`\0T` 7 7-0G`UTL`T3kZn`` 07Z`[Q4O3`>`[47Y`[0]TX0T7`7D`RTL0>`T0 7 3g`]Zn'Z`34S[Y`H`[47V`\0ZTX0T`77LTW0>`T`T07Zk`[3j$Z`34L[V`<`4[7W0VT``b07 `T027C 07²@ ’3k3!Rh%R ²@’2T+P>OS+2ORh4T4RSS 4 S 2I+J[_8[OI2+O4RR^&RSV4 S]KL]59 b?`H c ]@b 5>`[Y][<\5R ]bcn+<5 ] bF`E ]Gcb5L[]>Y`]5[>YW Y$7T0P>TS07T9TWh4WXS 9 X 7I0J`_8`TI70T9RW^&WXV9 X2U+PJ2++^t4\Vk+NV^+^fVe4+V2Q^+FA^uVm2+.4\V^24 [a([ 0N7POVTR"OT07OBT2OT9W0JTYOc'09OT?Na7XTYO\0RN7O0T:9[0R8907]KL]59 b?`H c ]@b 5>`[Y][<\5R ]bcn+<5 ] bF`E ]Gcb5L[]>Y`]5>[YW Y#7T0M*07 [N^F`KZVZ`[^9Y0U[]Zg^:`SZ`[^ 09 [U`N^6ZYZ[`^`X7Y0R[V^FZcZ[`^07^=[SZc`IZ`[^9\^=0M`QZh[UZ`[^30 9ZU7URUTU0UXU[UZ270:0U7UK7 0 X[TR0c7e;[UX[ZJT\RYX70[TRZ[<THXRRE0n7f,[XTRH^0 7H0Z`])Ecgc`)0`NcTc`2_)U^nb`/)2bYC^ Y\f`U0T)H]\\)0] ` YO 0KY0bd^k)O2]"2)bYM2P^);)Y2*Q6S *6QNT5WNNEQTNW6ZWN*MT\NfQN66T*WQN9WNMdQN6[T\N_*UM6N*WQT:6^*U6*HN!H0N7POVTR"OT70OBT2OT9W0JTYOc'09OT?NaTY7XO\0RN7O0T:9[0R809NZOWTZ!N7MO0IT570TfObNb.N9O0COT,N`TbO`09NO7TT0ML07(9`0Wa0 9 ²@’2W+NG\:GOE&O+ .`Ff2O>O F/WO\GV..G/O2XCW+Q/CF`%F +.aGX2#. C]/R G/C `\T K4WT\LV3.L4THW7X0Q/HK`%K 03aLX7#3 H]4R L4H OYWj<[5@45OWQ=<Q8UM\Ve38M9MQ?V Q9 KZL]59 b?`H c ]@b 5>`[Y][<\5R ]bcn+<5 ] bF`E ]Gcb5L[]>Y`]5>[YW Y*W-*ZVWdQKTK*K/T*Q6`ZW 6QKWbZ`TKQ3XZWTTV23 *eT-NI"*N0N7POVTR"OT70OBT2OT9W0JTYOc'09OT?Na7XTYO\0RN7O0T:9[0R890NZTZOW!N7MO0IT570TfNbOb.N9O0COT,N`O`Tb09NO7TT0ML07(9`0Wa0 9 ²@’2WG\+N:GOE&O+ .`Ff2O>O F/WO\GV..G/O2XCW+Q/CF`%F +.aGX2#. C]/R G/C S5GTY,TdSdYf5>STd5[a5 >7T0M*07 ^F[N`KZVZ`[^9Y0UZg[]^:`SZ`[^ 09 `N[U^6ZYZ^[``X7Y0R^F[VZcZ[`^07Zc[S`I^=Z`[^9\^=0M`QZh[UZ`[^30 92W+OG+2'4^+MfTdZfbad`Wb_X`]^_][] ZF+4Z[!+F2KdBbZ`abd_a`]a_2]+[\ ZM[XDXZ4X+Lb^`V_Gb`]U_+4][Y [ZW ZXS XV`VTa S^TQ]SQ 7J0G=HX70HNc9LRTTN ONNTOR9RJT\OX3740:OTR5NjT\R]70OCN9F OTR4TYNiR] OV9N7J²@ ’OTR7E7Z²@’6lOa[h6O[OL[S[O77Y[`OXO[77I[cOY!O7[7H0F8[lWp70XPW[X9N[ZX^0<X[ 09[TX[[X7D[[0BXb"[X 70X\[M[X9N0I[bXi[X 90X_[Y[X7E0C[bXf[X 70 [UXYX[0E9D[_Xa[X 90[TX[ X[QR7I0D-7Q0 TZ&T0L9UVm09V T_TN`Z]^5<]` 5>`T][`]N5I`b]i`] >5]_`Y`]D]a`] >5`T][ `]VRU5L5>[ Y_Y+Z$E[]^g^[$+[N^T^[-_$UYn]`/$-]TCY TWf[U+T$HX\W$+X [ TO +KT+]d$OYk-]"$-]TM-P$;Y$T-Wc[O$H+RXPW $+X TM +M$9[T$+]`Yj-Y$U-$]YWe-b[S$LX^W$[X- $E+X+$#O`+c$N$ O+-dOC-O2TO\2OV_2R+JVG+24]+M;[\Rf4+RS7S2U+G[4[hRr+2 STR[4YS+P?+ 4-5Cf`\][Y^<> 5E]`Y,5>d ^[`SYZ>`Y^5D^`[][Y[5S(5>]`Y.7]T^HYN^0XRUORNHROT07THHPOKREHTOR9[HZTQ0GREOTHROT09TEHQOSRLHRTO7WH]TR0NOQRLHTOR7HHTEOTRI0THRO9\HdT^O^0ARRHORTHN0H92W+OG+2'4^+MfTdZbafd`Wb_X`_]^][] +ZF4Z[!+F2KdBbZ`abd_a`_]a2][\+ ZM[XDXZ+L4Xb^`Vb_G`]U_+4][Y [ZW ZXS XV`VTa S^TQ]SQ0Z7Q²@’[gOcO[OS[W[O 03e[`Wl7[W34I[EXW[X4[a7XWm0[W[ 07 [G0;7GWSW[ 07We3c[V W[ 3[LWY4P[W 4 ]KL]59 b?`H c ]@b 5>`[Y][<\5R ]bcn+<5 ] bF`E ]Gcb5L[]>Y`]5[>YW Y7N0JS5GTY,SdTdYf5>STd5[a5 >[[Xc7V0Y X0[77GWZ0A[H[W 03cXb[M7[ X34OWe[5[W4[T7WX^0Z([07X W^7G0+W3h[SX_ 073[X 4RW\!W4JHMHSHCH+W²@?’++²@’VMSC JOdC_C+`O C +O\CVOC²@’+XSCXO`+COCQOXCO²@’$\ZmT\[b`dZT[``HT@[>ZUZ`[T^]RX(P $ R ^[XOO[O)AN\Zc( NZMHYRMY)*SW`K]KWHbTcH T * [j+^Y)[YXQ+XVQTZVSYTSQQ OOQ MPO LSMJPLHSJGPENHCHG EC*$^ca>)W>>[?>Y.;^>D;7O-7R7:9[ 7b[aUC^<Ab CpAALd?L1H@*HJ^6JH?*HL`KL'H^I<>4VB>:?S4?@>SA>T/>@S;AR@1CSA3CEZ6EDCcJI>JHW/H_ca>)W>>[?>Y.;^>D;7O-7R7:9[ 7b[aUC^<Ab CpAALd?L1H@*HJ^6JH?*HL`KL'H^I<>4VB>:?S4?@>SA>T/>@S;AR@1CSA3CEZ6EDCcJI>JHW/H_)D I PBFBIBDBFeDFIIBFBDBPBP<%>"* IFD%PB8=B?B'M96D5=:B#6??>): B =B?B?BBFBe=B?FB?BFBB=B<">"' B?"=F1/;/B/D/rBDDRB)1LGEKE1BGKKMB81LGm1KBG 1LG8K8B8 BGK1B8K8G81L1GKBB+*D9=7+BBD(BF;=*F?+'D9:7+??D(?B;:'BD@B@H6,K9)=1GD B/*H9=;+BBH(BF?=*F@B1<DBIBsDB=BIBDI*@@B'1I=@D0$:?$B$r?BBG)?1DG B-*F9=9+BBF(BF==FFDID=DBDnFBI FDB=ID=!FBI=D&*=*<B<=.FB-KI1PGI1BKGG!KQ1PB)B*FI '<?<:.B)? G GB?BBBBKBe?BG?BBBGBKKB<*>"/ GB?*KBBF8?B'M9:D5??B#:BB>)? F ?BKBBBBFBe?BF?BBBKBKFB<">"' FB?"K,<?.D<G)=1DG *<B<=.F)@1DI ??09B?F?sB?:?FBF?*???'0F?:B)$9?$B$r?BBG)B*IF F8?BBB'M9:D5??B#:BB>)?'FB BBH8DB,M9)?,HD B/?P1H9;;+??H(BD?;?1DBB*<FBIBsFBIBIF=B)D,GK 1<B<;.D)D,KG =PA/1H9;;+==H(AD?;=1DB/*H9=;+BBH(BF?=*F@/1H9=;+@@H(@D?=1DF6?@B@0K9:B5?<@#:BB<)<0BF B@?@E6)K99B5?<@#9BB<)<)BE F6=@A@.K9:B5==@#:AA<)=.FA '$7=$?$r=??G)B*FI ?B'<BBFBsFB:BFBBB*??B''F?:BBB,<DBHBsDB)?,HD ?PB/1H9;;+??H(BD?;?1DI9FCBC*N9=E5BBC#=FF?)B I NCFBCICFCeBIF:C=CBCFCN<%?"* B:F*R%B2FC:2I2N2]=‚B:*NIFd²@ÿ/MTrk éµ Å?ÿJAZ2µ "{[(]l@ÿ Brass sectionx•=(:(6(‚b:=66(1(t?Ly?=Id6=6?c1 6GF;FkG;82D2xB2Da8B;B7K71KG71BKGG7B7K71KmGK1B K7G71KB7 BGK1B7K71KG7K1GB µ•=FIFÅ?k•=IF2:2xB2Fa:BC;(8(?(-;?8;(6(8(q68;}6(:(3(‚b36:;B71KG7K71BKG1KB7K7G7mK1BG 1KG7K7B7 BGK1B7G7K71K1GKB =(:(6(j=:6C3(:(6(-3:6<(6(tDLyDBId<B*(&&*.F#-#.>.2&2.&*F#7.F.*#>&F*(&*#-.6.#_*F%P*%=*(* #-*P*#_*P#-*#=*2* *F#-*#_%F*P%*?*(**P#-#*_%P*P%*?*2*#-*P*#_%F*Z*%>*(*#-*P#*_*Z%U*%>*2*#-*P#*_*Z%F*%?*(**P#-#*_%S*Z%*?*2**F#-#*_%F*P*%?*(**P#-*#_*P%P*%?*2*#-*F*#_%F*Z*%?*(**P#-#*_*Z%P%*?*2**P#-#*_%F*Z*%>*(*#-*P#*_*Z%U%*>*2**P#-#*:&& *Z*:&& *F#-*#:&#& *Z#7*#&!&&,& *F#-*#_*F%P%*=*(* *P#-*#_#-*P#*=*2* #-*F#*_%F*Z%*?*(**P#-#*_%P*Z*%?*2**F*_%P*F*%=*(* #-*P*#_#-*P#*=*2* #-*P*#_%F*Z*%>*(*#-*P*#>%Z%*Z*>*2**P#-*#_*Z%F*%>*(**P#-*#_%U*Z%*>*2*#-*F#*_%F*P*%?*(*#-*P*#_*P%P*%?*2**F#-*#_*Z%F%*?*(**P#-*#_*Z%P%*?*2**P#-*#_*Z*9&,& #-*P*#&&&& .Z#-&!.&#&,&&7& &#1P#2&#1_,Z3Z,3>3F3&3F&3_,Z3Z,3>3F33P3_,Z3Z3,?&3F3&&3P3&_,Z3Z3,?3F33P3_,Z3Z3,?3F3&3P3&_3Z,Z,3?3F33P3_3Z,Z3,?&3F3&3P3_,Z3Z3,?&3F&33F3_3Z,Z3,>32&&33P3_3Z,Z3,>32&&33P3_3Z,Z3,?3F3&3P3&_3Z,Z3,?3F33F3_,Z3Z,3?3F&3&3P3_3Z,Z,3?3F3&73F3&9#A# 3Z*F3*9&A& #K3P#39&-& 3Z*d3*&&0F&&0 #2&#1P#1&_,Z3Z3,>3F33F&3&_,Z3Z3,>3F33P3_3Z,Z3,?&3F3&&3P&3_,Z3Z,3?3F33F3_,Z3Z,3?3F&3&3P3?&#&,Z3Z,3?3F33P3_,Z3d,3?&3F3&3P3?32&-3&,Z3Z,3?3F&#&33F3_,Z3Z,3>&32&33P3_3Z,Z3,>&32&33P3_,Z3Z,3>3F&&33Z3_,Z3Z,3>3F33F3_,Z3Z3,>32&3&3P3_,Z3Z,3>&323&#73F#3_,Z3Z3,?&#3F&33P3?3(&-.(3&.3Z,d3,?&73F3&3d3_,Z3Z,3>3F3&3F&3_,d3Z,3>3F33P3_3Z,Z,3>3F&3&3Z3_,Z3Z3,>3F33P3_,Z3Z,3?3F3&3P3&_3Z,Z,3?3F33P3_,Z3Z3,?3F3&3P&3_,Z3Z3,?3F33F3_3Z,Z,3>32&3&3P3_,Z3Z,3>&323&3P3_,Z3Z3,>3F33Z3_3Z,Z,3>3F33P3_3Z,Z,3?3F3&3P&3_3Z,Z3,?3F33F&7&39#A# 3Z*F3*9&A& 3P#K#39&-& 3Z*d3*&&&0F&0 #(1F1#_3Z,Z3,<3F3 &3F3&_3Z,Z3,<3F3 3P3_3Z,Z3,?3F3&3P3&_,Z3Z3,?3F33F3_,Z3Z3,>32&3&3P3_3Z,Z,3>32&3&3P3_,Z3d,3?&3F3&3P3?&-323&3Z,Z,3?3F&#3&3P3_3Z,Z3,?3F33P&3&_,Z3Z3,?3F33P3_,Z3Z,3>3F33Z3_3Z,Z3,>3F33F3_,Z3Z3,>&32&33P3_,Z3Z3,>32&&3#73F#3_,Z3Z3,?&#3F&33P3?&-.(.&,d3Z3,?&73F&3#(1F1#<&#& 3Z,Z3,<3F3 &3F&3_,Z3Z,3<3F3 3P3_,Z3Z3,>3F&3&3Z3_,Z3Z,3>3F33F3_,Z3Z3,>32&3&3P3_3Z,Z,3>32&3&3P3_,Z3Z,3=#73F#3 3P3=&-& ,Z3Z3,=3F&#3& 3F3?&-&3Z,Z,3?3F&&33P3_3Z,Z3,?3F33P3_3Z,Z3,?&3F3&&3P3&_3Z,Z3,?3F33P3_3Z,Z3,?3F3&3P3&_,Z3Z,3?3F33F&7&3>#2#,Z3Z3,>&-3<&33F3>#<&-#&,d3Z3,>&3<3&#(1F#1_,Z3Z3,<&3F3& &3F3&_3Z,Z3,<3F3 3P3_,Z3Z3,?&3F&33P&&3_,Z3Z,3?3F33F3_,Z3Z3,?&3F&33P3_3Z,Z,3?3F33P3_,Z3Z3,?3F&&33P3_3Z,Z3,?3F33F3_3Z,Z3,>&32&33P3_,Z3Z,3>32&&33P3_3Z,Z3,?3F3&3P3&_3Z,Z3,?3F33P3_3Z,Z,3=3<&&3 3P3_3d,Z,3=&-3F3& &73F&3>#2#,Z3Z3,>&-3<&33F3>#<&-&#3Z,d,3>3<&&3*F#-*#_%F*Z%*?*(**P#-#*_*Z%P*%?*2###*#-*F*#_*Z%F*%?*(**P#-*#_*Z%P*%?*2**P#-*#_*Z%F*%>*(**P#-#*_*Z%U*%>*2**F#-#*_*Z%F*%?*(*#-*P*#_*Z%P*%?*2*#-*F#*_%P*Z%*=*(* #-*F*#_*Z%N*%=*2* #-*P*#_%F*Z%*>*(**P#-#*_*Z%U%*>*2**F#-#*_*P%F*%?*(**P#-#*_*P%P%*?*2###*#-.P.#_*<*>*(&&*#-.F.#>&2.2&.*F.F#7.#*>*(&F&**P#-*#_*Z%F*%=*(* *P#-#*_%U*Z*%=*2* *P#-#*_*Z%F*%>*(**P#-#*_*Z%U*%>*2*.6._*F%P*%=*(* #-*P*#_#-*P#*=*2* *P*_%F*Z%*>*(**P#-#*>%Z%*Z*>*2###*#-*F#*_*Z%F%*?*(**P#-#*_%P*Z%*?*2*.6#-#._*F%P*%=*(* *P#-#*_*P#-#*=*2* *F#-#*_%F*P%*?*(*#-*P*#_%P*P%*?*2*.P&#.&;#7# *P*;&#& #-*F*#;&*<&* .P&#&.& &&& #21P&#1&#_,Z3Z,3>3F33F&&3_3Z,Z3,>3F33P3_3Z,Z,3>3F33Z3_,Z3Z3,>3F33P3_,Z3Z,3?3F3&3P3&_,Z3Z3,?3F33P3_3Z,Z3,>3F33Z3_3Z,Z,3>3F33F3_3Z,Z3,>32&3&3P3_3Z,Z,3>&32&33P3_,Z3Z3,>3F33Z3_3Z,Z,3>3F33P3_3Z,Z3,?&3F3&3P&3&?&&,Z3Z3,?3F33F&73&>#2#,Z3Z,3>&-3<&33F3>#<&-&#,d3Z,3>&3<3&1F#(1#_3Z,Z,3<3F3 &3F3&_3Z,Z3,<3F3 3P3_,Z3Z3,>3F33Z3_3Z,Z,3>3F33F3_3Z,Z,3?3F&3&3P3_3Z,Z,3?3F33P3_3Z,Z3,>3F33Z3_3Z,Z3,>3F33F3_,Z3Z3,>32&&33P3_,Z3Z3,>32&3&3P3_,Z3Z,3?3F33P&&3_,Z3Z,3?3F33P3_3Z,Z,3=3<&3& 3P3_,Z3d,3=&-3F3& &-3Z3&7&#&#F3P,Z3,#&&020&.F&.&&)2)2F.P2.020)(#(#)#-1#1=&#& *P*=&& *F*=&-& .P.&&&& .F#7&F&.#7.<&&..F&-.&7##9(&P.Z&9.#_&&&&-#A&#&ÿ/MTrk–²ÂÿJAZ2ÿPiano²D T]@{[K’M4?MA8A P4V PVbD'M$GJ!V&P'MDGJVP`NE$:30R3NO,9$O3RQ>K)H9B2KQHBT]-< Q#%54%Q<5]]7<;Q75<Q<5]tNE+:50S3NO,9OS5+K)H9T>C2KTCHTZ-N#9 (34(N39ZZ7N79;3<N93ZrY-M#7 -24-M72YY7M77;2<M72YtME#:P320MM,9PM2# $&:370?3 $:?7^K)H9Q>C2KQCHQ"&7350>3 "7>5^P>G9J)A2JPGAOO4T OTbC'FK$H!T&O'CKFHOT[)&9350?3 )9?5UM4R MRbA'I$DF!R&M'AIDMFR]DAIFRM(2AFDIRMF3D)A3M-I/R IFADMR]0+ 0F7FK4F+K?7F?Y-M#9 (34(M39YY79;M73<M39YITLTM-MJA8JCT?E:JAETK$&:370?3 $:?7UM4T MTbA'K$EH!T&M'KAEHMT\M@J;.,:.MJJ+M+.* JM.+&;370A3 +;A7\NE$:30R3NO,9$3ROH9Q>K)C2KQCHXJ)R>F9A2JRAFTY-8 M#"24"M28YY78;M72<M82Yr[-O#: #34#O:3[[7:;O73<O3:[O)+ )E7EK4E+K?7E?fRLRM-MJA8R?ICD:IADRPNE$:30R3NN,9NR$3 M4T MTbA'EK$H!T&M'KAEHMTb>*F%?>F.?;F>G?F 5<5F2@A@F@F3AAAFwO4T OTbC'FK$H!T&O'KCFOHTbT>K)H9A2KTAHQ';ADFC>@'A>FP:126RKM?FCM|: 2RF22>-?DC?>?C+5‚x+ K4R KRb?'H$CF!R&K'H?CKRF`OE,:60T3OR,96T,RV>M)J9E2MVJEXV>J9M)C2MVJCT[-: O#*$54*O5:[[7O7:;5<O:5[‚]4(@1$-:.72:7@$4UOILHVKJIF6 LJVFO‚-O5KA&KOJ!N'$JN&KHO5$KJ'ONH9K)C2KTCHQ"&7350>3 "7>5UM4S MSbA'J$DG!S&M'AJDMGS[$&:370?3 $:?7‚7)+ )E7EK4E+K?7E?Y-M#8 -$14-M18YY7M78;1<M18Y‚dNE$:R330NN,9$N3RY-M#9 (34(M93YY7M79;3<M39YJRR)RDM1MRDKR M/M )&:370?3 ):?7\LE):30Q3LM,9M3)Ql.+ .C7CJ4C+J>7C>ME#:P320MM,9#2PM $&:370?3 $:?7UO4T OTbC'K$EH!T&O'KCEOHT^Y-7 M#-24-M72YY7M77;2<M27YrY-8 M#"24"M28YY7M78;2<M28Yr[-O#: #34#O:3[[7:;O73<O:3[o)&9350?3 )9?5\IE.$=%P3II,ƒ PI .= $&:360?3 $:?6\LE):Q330LM,9)3MQM$WM!A!rAU;L'OOULVG+K'L;K LVJ?R>ME>RMJ2NE$:R330NO,9RO$3 )&9350?3 )9?5ZM4?MA8A O4W OWbC'GM$K!W&O'MCGWOKYO4T OTbC'FK$H!T&O'CKFOHTYO4T OTbC'EK$H!T&O'CKETHO["&7350>3 "7>5^G9P>J)A2JPGAXK)H9T>C2KTCHXH9Q>K)C2KQCHW<-A?=D<=A)5‚x)T>K)H9B2KTHBOM4T MTbA'EK$H!T&M'AKEHTMYM4T MTbA'EJ$H!T&M'AJETHM]EAJHM(T2AHETJME)A3H3M-J/T JHAETMKC?K525 H?TC*TH5Y7(W4(T/(Q9(K7(H,YQKTWHbRLRM-MJA8R?JCC:JACRI3(?1$-:.72:7$?3UOIKHTKHIF6 HKTFOWK4R KRb?'CH$F!R&K'H?CRFK^^-R#< +64+R6<^^7<;R76<R6<^O2+ 2H7HM4H+MA7HA O4V OVbC'GM$J!V&O'MCGOJV[+&:370A3 +:A7ƒE@14($-:.72:7$4@UOILHVKJIF6 JLVFO‚3TLTO-OJC8T?KCF:KCFT‚!J$E7?#xYD Y\EJ]DE?\2]7`O(`M"&7350>3 "7>5\ME#:20P3MM,9M#2PH9K)T>C2KTCHXK)H9Q>C2KQCHOM4R MRbA'J$CF!R&M'JACRFM;/+ /D7DJ4D+J>7D> $&:370?3 $:?7^K)H9T>C2KTCHQ.;ADFC=@A.=FP:1M?16RKFCM|: 1RF11K)T>H9B2KTBHXH9K)Q>A2KQHATMWM!ArAUGLCO LOUR&RV7R6M=>RMV+O4T OTbC'K$FH!T&O'KCFHTOcKC?K)2) H?TC*TH;M4?MA8AY-8 M#"24"M28YY7M78;2<M28YO0+ 0F7FK4F+K?7F? O4T OTbC'EK$H!T&O'CKEHTO["&7350>3 "7>5^P>J)G9A2JPAGT[-O#: #34#O3:[[7O7:;3<O3:[vH9K)Q>C2KQCH‚,MR)MDF1FMDKM F/FZ-N#: #34#N:3ZZ7:;N73<N:3ZtLE):Q330LM,9QM3) 2(>1"-9.52952">UMIJHTKHIE6 HJTEMWO4T OTbC'K$FH!T&O'CKFTHO^Y-M#9 (34(M39YY79;M73<M39Yo"&7350>3 "7>5^S>K9M)C2MSCKOO4T OTbC'K$FH!T&O'CKFTHObH9T>K)C2KTHCTM4?MA8AME#:20P3MM,9MP2# O4T OTbC'K$FH!T&O'CKFOHTbK)Q>H9C2KQCHQ"&8350=3 "8=5ƒEN4T NTbB'FK$H!T&N'KBFNHTYM4T MTbA'K$EH!T&M'KAETHM`IE.$>%Q3IJ,ƒ QJ .> T7(R4(O/(K9(F7(C,FKTORCKC?K)2) H?TC*TH8'&7330>3 '7>3„KAO5&KOJ!N'$JN&KHO5$KJ'ONXKYM@CMTY-M#7 -24-M72YY77;M72<M27YvJ)P>G9A2JPAGT[-: O##34#O:3[[7O7:;3<O:3[tLE):30Q3LO,93OQ)Y-7 M#-24-M27YY7M77;2<M27YvP>G9J)A2JPAGXT>K)H9C2KTCHQ)&9350?3 )9?5‚2MR)MDF1FMDKM F/Fl0+ 0F7FK4F+K?7F?LE):30Q3LM,93QM)gMR)MDH1HMDKM H/H O4T OTbC'FK$H!T&O'KCFTOHcKC?K)2) TCH?*TH84L 5O 4G)P 5M)DKLTMUTL‚M>T ²@ÿ/MTrk($µÅÿJAZ2ÿGuitarµ[K{ 'Y]@•9/>/Ap997>>7AA"9>Ae5.,(µ@•;.>">;5,Tµ@•58;8># >5;l:.µ@•0(7.?C":C70?T:8µ@•?#78C# ?:C7lµ@•5(9.?.Aj95?A 50µ@•98?8A#?9A5cµ@•2(<.5.>">52<Tµ@•<858># <5>k+(5/;/>p557;;7>+>">;5d0(7/:/?Cp7:77?:7?"0CC":7C?e9.0(µ@•?.A"09?AT98µ@•?8A# 9A?k.(7/>/Ap777>>7A.A"A7>e/(8.>.µ@•A"8A>/Tµ@•>888A# 8A>l:.?.0(µ@•C":C0?Tµ@•?8:8C# :?Cl0(µ@•?.9.C"C?90Tµ@•?898C# 9?Cl.(µ@•7.>.Aj.A>7 µ@•.078>8A#A7.>c/(>.µ@•8.A"/8>ATµ@•88>8A# A8>lµ@•0(:.?.Cj?C0: µ@•00:8?8C#?0:Ccµ@•5(9.?.C"C?59Tµ@•98?8C# 9?Clµ@•8.=..(A".8=ATµ@•88=8A# 8=Alµ@•.(8.=.A".=8AT88µ@•=8A#8=Agµ@•0(:.?.BjB?0: µ@•00:8?8B#?:0Bcµ@•5(9.?.Aj?59A µ@•5098?8A#95A?b.(9/>/Ap997>A>7A".9>Ad.(9/>/Ap998>A.>8A# >9Ah0(:/?/Cp::7??7CC"0?C:e?.9.5(µ@•A"9?A5T?898µ@•A# ?9Ak.(7/>/Ap777>A>7A".A>7d+(5/;/?p557;?;7+?"5?;d0(7/:/?Cp7:77?:7?"0CC"?:C7d0(9/?/Cp997??7C0C"?C9e.(µ@•7.>.Aj7A.> µ@•.078>8A#7.A>cµ@•8./(>.A"/A8>Tµ@•>888A# >8Ak0(:/?/Cp::7?C?7C"0C?:eµ@•5(9.?.CjC59? µ@•5098?8C#59C?`.8 = Ak.A8=87=7A"=8Aa.!8&=&Ao.8A=88=8A#=8A_.(6//Ap997>A>7A".9>Ad.(9/>/Ap998>A.>8A# A>9iµ@•0(:.?.Cj:?C0 00µ@•:8?8C#:0C?b5(9/?/Ap997?A?75A"?A9e3+µ@•:2>2Cj>:C3 µ@•34:<><C%>:3Ccµ@•3+:2>2Co3C>:µ@•34:<><C%3:>Ca0+µ@•:2?2Cj?:0C 04µ@•:<?<C%?C0:cµ@•0+:2?2CoC:0?04µ@•:<?<C%0:?Ca72.+µ@•<2#.7<Tµ@•7<<< 7<lµ@•,+62<2?j6?<, ,4µ@•6<<<?%<6,?c2+µ@•52<2>j25<> µ@•245<<<>%<5>2cµ@•++52;2>j5>;+ µ@•+45<;<>%>;5+c++52µ@•:2>":+>5Tµ@•5<:<>% >:5l:252++µ@•>"5>:+T5<µ@•:<>%>:5d4$:*>*Ck:C>4:A>AC(:>Ca4):0>0Co4>:C:B>BC)C:>_0,:3?3C p::;?C?;0C%C?:d0,:3?3C p::<?0C?<C% :?Ch0,93?3A p9:;?A?;C%0:?Cd0,93?3A p99<0?A?<A% 9?Aiµ@•.+72>2A">.7ATµ@•><7<A% >7Ak/,83>3A p88;>A>;/A%>A8eµ@•0+:2?2Cj:?0C µ@•04:<?<C%0?C:cµ@•5+92?2Cj?59C µ@•549<?<C%59?Ccµ@•.+72>2Aj.7>A .4µ@•7<><A%.A>7cµ@•/+82>2Aj/A>8 µ@•/48<><A%/A>8b0,:3?3C p::;??;C0C%C:?e?25+92µ@•C"C95?Tµ@•9<?<C% ?9Ck.,83=3A p88;==;A.A%8=Ad,,53:3= p55<:,=:<=% 5=:i0+µ@•:2?Bj0:?B 04µ@•:<?%B%0:?Bc0+µ@•92?2AjA90? µ@•049<?<A%90?Acµ@•.+92>2Aj.>A9 µ@•.49<><A%>.9Acµ@•.+92>2AoA>9..4µ@•9<><A%A9.>a?2:2µ@•0+C"C?0:T?<:<µ@•C% C:?k5,93?3A p99;?A?;5A%9A?e.+µ@•72>2AjA>.7 µ@•.47<><A%.7>Ac/+µ@•82>2Aj/A>8 /4µ@•8<><A%>/A8c0+µ@•:2?2Cj?:C0 µ@•04:<?<C%:?C0c0+µ@•92?2CjC90? 04µ@•9<?<C%C?90b.,73>3A p77;>A>;.A%>A7d/,83>3A p88;>A>;A%/8>Ae0+µ@•:2?2Cj?:0C µ@•04:<?<C%C?:0cµ@•5+92?2Cj59?C 54µ@•9<?<C%9?C5b.,83=3A p88;==;AA%.=8Ad,,53:3= p55<:=,:<=% =:5iµ@•0+62:2?"60:?Tµ@•6<:<?% ?6:l5+µ@•92?2Aj9A?5 µ@•549<?<A%9?A5cµ@•.+92>2Aj>A.9 .4µ@•9<><A%.9>Acµ@•.+92>2AoA.9>µ@•.49<><A%9A>.`0,:3?3C p::;?C?;0C%?C:d5,93?3A p99;??;AA%5A?9e.+5+µ@•>2C">C5.Tµ@•><54C% C>5l++52;2µ@•?"+5?;T;<µ@•5<?% 5?;k0,73:3? C p7:7;?:;?%C0C%7C:?e5+µ@•92?2Cj5?C9 µ@•549<?<C%C5?9c.+µ@•5+>2C"5C>.T><54µ@•C% >5Cl/+µ@•82>2Aj8A/> µ@•/48<><A%>A/8b0,:3?3C p::;??;C0C%:C?d5,93?3C p99;??;C5C%C?9b.$8*=*AkA.8=8A=AA(8A=a,)50:0=o5,=:5B:B=):=5`:20+?µ@•B"0B?:Tµ@•:<?%B% B:?k5,93?3A p99;?A?;5A%A9?b.$9*>*Ak>9A.9A>AA(>9Aa.)90>0Ao9.A>9B>BA)>A9`0+µ@•:2?2Cj?C0: 04µ@•:<?<C%0:?Cc0+µ@•?292A"9A0?Tµ@•9<?<A% 9A?lµ@•723+:2>C"7:3>CTµ@•7<>%:<C% :>7Cl:2µ@•3+72>C"3>C7:T>%µ@•7<:<C%C>7:g?2µ@•0+:2C"C:0?Tµ@•:<?<C% C:?l?2µ@•0+:2C"?:C0T:<?<µ@•C%:C?gµ@•72.+<2#<7.T7<µ@•<< <7l62,+<2µ@•?",?<6T6<µ@•<<?% ?6<lµ@•2+52<2>j5>2< 24µ@•5<<<>%>25<cµ@•++52;2>j>+5; +4µ@•5<;<>%5;>+c:2µ@•52++>"5>:+T5<µ@•:<>% >5:l++52:2µ@•>"+5:>T5<:<µ@•>%>:5g0+µ@•42:2>j:>40 µ@•044<:<>%0:4>c0+µ@•42:2>o4:0>µ@•044<:<>%4:0>a0+µ@•72:2?Cj:70?C 04µ@•7<:<?%C%7:C0?c0+µ@•72:2?Co7:?C0µ@•047<:<?%C%0C:7?`5,93?3A p99;?A?;A%5?A9d5,93?3A p99<?A5?<A% A?9iµ@•.+5+>2Cj5>C. µ@•.454><C%>C5.cµ@•/+82>2Aj>A8/ µ@•/48<><A%/A>8c:20+?2µ@•C"0C:?T?<µ@•:<C% C:?l?25+92µ@•C"C?95Tµ@•9<?<C% C?9k.,73>3A p77;>>;A.A%7A>d/,83>3A p88;>A>;/A%8>Ad0,:3?3C p::;?C?;0C%?C:e92?25+µ@•C"9C5?Tµ@•9<?<C% 9?Ci.$8*=*Ak.=8A8A=AA(=8Aa,)50:0=o5,:=5B:B=):=5`?0+:2µ@•B":?0BT:<µ@•?%B% B?:lµ@•5+92?2A"A59?T?<µ@•9<A% A9?i.$9*>*Ak.>9A9A>AA(9>Aa.)90>0Ao9A.>9B>BA)A9>`0+?2µ@•:2C"C0:?T?<µ@•:<C% ?C:l5+µ@•92?2AjA?95 µ@•549<?<A%9A?5cµ@•.(7.>.AjA>7. .0µ@•78>8A#7>A.c8.>.µ@•/(A">A8/Tµ@•88>8A# 8A>k0(:/?/Cp::7?C?7C"0:?Ce5(µ@•?.9.C"95?CTµ@•?898C# 9C?l>.5(.(µ@•C">C5.Tµ@•>850C# 5>Cl/(>.µ@•8.A"A8>/T88>8µ@•A# >A8k0(:/?/Cp::7??7C0C"C:?e5(µ@•9.?.Cj9?5C µ@•5098?8C#9?C5c.(µ@•=.8.A".=8AT=888µ@•A# A=8l8.=.µ@•.(A"A.8=T=888µ@•A#A=8g0(µ@•:.?.Bj:B0? µ@•00:8?8B#?:0Bc9.?.µ@•5(A"?A95T98?8µ@•A# ?A9l.(µ@•:.>.A">:.ATµ@•:8>8A# A:>l.(9.>.µ@•A".9>ATµ@•98>8A#9>Af0(:/?/Cp::7??7C0C":C?d5(9/?/Ap997?A?7A"59?Ad.(7/>/Ap777>>7A.A">A7eµ@•+(5.;.?j5+?; µ@•+058;8?#?+5;cµ@•0(7.:.?Cj07:?C 00µ@•78:8?#C#7:?0Cc5(µ@•9.?.Cj59C? µ@•5098?8C#?C59cµ@•.(7.>.Aj>7.A µ@•.078>8A#.7>Ab/(8/>/Ap887>A>7/A">A8d0(:/?/Cp::7??7CC"0:C?eµ@•0(9.?.Cj9C?0 µ@•0098?8C#?9C0c8..(µ@•=.A".A8=Tµ@•=888A# A=8l=.8.µ@•.(A"=A.8T88µ@•=8A#=A8f0(:/?/Bp::7??7B0B"?B:d5(9/?/Ap997??7AA"5?9Aeµ@•.(9.>.Aj.9>A µ@•.098>8A#.A>9cµ@•.(9.>.Ao>.A9.0µ@•98>8A#>A9.`0(:/?/Cp::7?C?70C":C?d5(9/?/Ap997?A?7A"5?9Ad.,73>3q77;>>;.7>d.,73<3q77<.<<< <7f0$:*?*Ck:0C?:A?AC(:?Ca0):0?0CoC:?0:B?BC)?:C`<2µ@•3+72?"37<?Tµ@•<<7<?% ?<7l620+:2µ@•?"60?:Tµ@•6<:<?% 6:?l92µ@•<22+AE"E29A<TA%µ@•9<<<E% 9E<Ak+,53;3> p55;;>;;+=%;=5d+,53:3> p55;::;>>%+>:5d+,53:3> p55<>:+:<>% :>5f0$4*:*>k40>:4A:A>(4:>a0)40:0>o:0>44B:B>):>4]0$7*:*?Ck?7C:07A:A?(C(C?7:a0)70:0?Co:0C?77B:B?)C)?:7C`92µ@•?20+A"A?90Tµ@•:<?<C% ?C:l0+?2µ@•92A"09A?T?<µ@•9<A%A9?g72>2.+µ@•A".>A7Tµ@•7<><A% A>7l82>2/+µ@•A"8A/>Tµ@•><8<A% A>8l?2:2µ@•0+C":C?0T?<µ@•:<C% :C?l?2µ@•5+92C"5C?9T9<?<µ@•C% 9C?l.+µ@•5+>2C"5C.>T54µ@•><C% 5C>k/,83>3A p88;>A>;A%/>8Ad0,:3?3C p:8;?C>;0@%>@8eµ@•5+92?2CjC?95 54µ@•9<?<C%95?Ccµ@•.+82=2AjA=8. µ@•.48<=<A%8.A=c.+µ@•82=2Ao8A.=µ@•.48<=<A%A.=8aµ@•0+:2?2Bj0B:? µ@•04:<?<B%?0:Bb5,93?3A p99;?A?;5A%A?9eµ@•:2>2.+A".A>:Tµ@•><:<A% >:Al92>2µ@•.+A"A.>9T9<><µ@•A%9>Af0,:3?3C p::;??;C0C%:C?d5,93?3A p99;?A?;A%59A?d./97>7A"k9.A> .69?>?A' >9.Ah./97>7A"o.9A>.79@>@A( 9.A>h./97>7A"o>9.A.79@>@A( 9>A.F.>9H>HA-.9>Auµ@ÿ/MTrk¶Æ3ÿJAZ2ÿStrings–9 ¶ N{[U]@–>¶–5 . :2^¶@@–8+9;.52:>A1¶@#–:¶@–078;+A?1¶@#–?) 5 0?7¶@–9 :<3^¶@–9<A3<5)?¶@–5&E@¶@x6–5;+A¶@–E&5A<C@¶@x6–07:+¶@–5;CA?1¶@#–)07?:5¶@–9?1¶@#–"59)7?¶@–>2A@¶@x6–A¶@–5¶–/8"72>>1¶@#–>58/?3:$¶@–C@¶@x6–$3?9 ¶@–C:?5 ) >3^¶@–5)¶@–3>9?">27A@¶@x6–>"A5¶@–/¶–872>1¶@#@–: 0 ?7 8/5><3^¶@–) 5 ?9 ¶@–<0:73?>3^¶@–?3)"=158¶@–9>A@¶@xx.–1A="8¶@–:06?1¶@#–)96:0?¶@–5?1¶@#@–9.559?)>1¶@ƒ–$5>9¶@–3:.?C@¶@x6–C$9?¶@–3:3?)¶–A@¶@x6–)A3?9>7"¶@–2A@¶@x6–8 2>+ A7"¶@–; A?5^¶@–8?3:$¶@–5?A;+C@¶@x6–:¶@–5 3C9 $??) >3^¶@–>35?)9.75¶@–>1¶@#–7/5>85¶@–.>1¶@#–: 7 58/>0 ¶@–?>3^¶@–:?)¶@–93?07>3C@¶@x6–5.9¶@–C8)?3=1¶@ƒ–0 6 8.5?=: ¶@–<3^¶@–?:6950)¶@–3<?1¶@#–. 5 >9 5¶@–?9):2^¶@‚–>)3?.¶@–:29:5C@¶@x6–) ¶@–?C9 ¶–5 ?):3>3^¶@–>3¶@–JAC5?)9"F&2ƒ^A"C2FCRHJ: 0Kƒ^K0?CRHOF:H'7 nF'H?O7NHF'6M&nNJETM6'FH2M< n2TEMJ<CMG&5L&nCL&5MCJRGM: +ƒ^CFOBM:RJ+4$L&ƒ^FOLCFOB$4K&3$ƒ^$ENFBK3COK&)3ƒ^3OFA)EBKN7 .JnAPG7.FOJA/J8 nF8C/GAPJOK&3$nCFOE$3KCKH&$3nKEH3C$AMC2J&"nMCJAAG2"PJ/8 nFCO8AP/JG$3K&nQK$FCHO3CK9 )nQK9)MDHCA1I&"ƒ^AHRBDM"1I0K: nKEA0BRH:KI&$3n$EEMAI3AK"2J&ƒ^COF"EJMA2K&)3nENBOFCK3)3K&)n3KB)EFAON.7 JnJFOAGPA.7J/8 nAGF8J/PCOK&$3nCCKEO3$KF$H&3nAKEH$3FOCJ7 .nFA.7OJPGA/J8 nPFC/OAG8J3$K&n$K3OCCFKE$3H&n$CKEH3MDAI&1"ƒ^"IMDA1HBR0K: nI:KAQRBH09 )KnK9AQA)HIQ9 J.ƒ^HAQR.9JCH: K0n:CHKA0QIRK9 )n9IMAQ)CAK2"J&n"J2AGOCCMM&+5nGOCRH+5MC0: KnCJQ0:HRCK9 K)nC9QK)JOFA.J7 nMDAOA7F.JJ&#2nA2#MJDCRJ0: KnRCJEOCK0:3)K&nEK3)COFPAI.8 ƒ^F8IAF.BPNK&3$nAENFNK3$BK&)3n3)KANEEMA2"J&ƒ^A"J2EMRHC: K5nRC:EMCK5H3K&)nCJAMCK3)E"F&2ƒ^CJAF2R"CJK: 0ƒ^?OJFR:K0C'H7 nH?O'H7FRFN&6,n6RTHF,JEN2< Mn<M2EGCOJT5+M&nGCMEF+M5OJ&5&ƒ^QEFJ5FEM&L&$4ƒ^QLF$4EJRC0: Kƒ^HAQJCKR0:9 )Kƒ^QK)H9ACMA2"J&nMCAAGPJ2"/J8 nJ/GPOFCA83K&$nOC3QJKCF$)9 Kn9FAOCQJ)K.7 JnO7.AFJPGA8 /Jn/8JPFAOCG$3K&n3$KOCFCKE$J&3nAKMDE$3JCI&1"ƒ^NFBDM"I1A3K&$n3FNBKBEK$3$I&nEBK3$IHQAJ9 .ƒ^H9.QJCAOF)K&3nANOE)3KFCK&3)n3)AKE5.7N>1¶@#–/58¶@–>57.>1¶@#–>85: ¶@–/0 ?7 >3^¶@–5 :?) 03¶@–>?79 <3^¶@@–5 . >)7 59?3<:2^¶@@–8/2:7>.55>1¶@#–?8>7 ¶@–0 : /5<3^¶@–<:07?3¶@–)59?1¶@#–8"15)9¶@–?=A@¶@xx.–?0 A8"=16 : ¶@–<3^¶@–3<?:605¶@–9)?1¶@#–. 59>)¶@–5 9 ?:2^¶@‚–?$:2.¶@–3>59:C@¶@x6–3:C?$¶@–5 9 ?¶–) <3^¶@–5 7 . ?>¶@–93<5):2^¶@@–:; .2+ A78 >5?5^¶@–0 ?+A;87 5?: ¶@–>3^¶@–7:?3>05 9 ?¶@–) >3^¶@–2")¶@–>7359?>A@¶@x6–A7285¶–/¶@–>">1¶@#–>8/3?$5:¶@–C@¶@x6–:$?C35 ¶–?) ¶@–9 >3^¶@–85¶@–)95?>3.=1¶@ƒ–$=.58?:¶@–3B@¶@x6–9:¶@–)3B??3$¶–A@¶@x6–95¶@–.A?93)¶–>1¶@ƒ–>.5?9: 7 5 ¶@–>3^¶@–7?:33>5?9)¶@–A@¶@x6–J¶–A¶@–C?)9A3F&"2ƒ^C2F"JACFO$3K&ƒ^?HCFOC$K30"F&nF"0?HCFHN'M&6n6M'HNFTJEM< 2nEJT<M2CGM5&L&nJRE&GMCL5M: +ƒ^+:MREEJOFL&$4ƒ^RCJOFL$4E0K: ƒ^JCRIAQ:K0)K9 ƒ^9AOAFK)IQ.7 JnO7DFAM.JA2#J&nFMJ#2ADOC$K&3nEO3K$CFKCH&3$nOCKA$3HFE.J7 nFAOA7.MDJ2#J&nOFCM#JD2A$3K&nF$KJQOCC3K)9 n9AM)DKQCJ1I&"ƒ^"AHRD1IBMK0: nRBHQB:I0K9 K)n)HQIQABK99 .Jƒ^QH.9AJCRH: 5Kn5HEAKK:CR$3I&n3$IEJAAEK)H&2‡>EJAH)2¶@ÿ/MTrk ³ÃÿJAZ2³[Z ?]ÿVoice 1 (Melody) Up³c{z“Vw&VTG%TVS)YaVY Ww$WVN*WjVV_W"VWe,[^W2[1Yt&YXQ"XYg*\]Y\ [j#[ZG([HZ]Q["]^e-`N^Z`W_7W YSSYUmJUWgMWY]YUSYPWfU6WYSRY`Z&` YN7YYZ.[GY([[e2^Z[-^^X2^bS$bbLbe]ƒUe+Vw&VTG%TVS)YaVY Ww$WVN*WjVV_W"VWe,[^W2[1Yt&YXQ"XYg*\]Y\ [j#[ZG([HZ]Q["]^e-`N^Z`W_7W YSSYUmJUWgMWY]YUSYPWfU6WYSRY`Z&` YN7YYZ.[GY([[e2^Z[-^^X2^bS$bbLbe]ƒUe-Vw!VWX&WY_+VVY/V Rg'R VXpVYjDYRDRRN4NOa/ORm&RFkKFMZƒ>MPJS6JJl"JJ_HH_J!HJ_:J JgDJJj"JH_*QaH=Q QQQQf8QQQMQ*V_"VWQ:W VL0VW_MPJS6JJl"JJ_HH_J!HJ_:J JgDJJj"JH_*QaH=Q QQQQf8QQQMQ*V_"VWQ:W VL0VW_MPJS6JJl"JJ_HH_J!HJ_:J JgDJJj"JH_*QaH=Q QQQQf8QQQMQ*V_"VWQ:W VL0VW_OXOXAP>L6>A>XI>1>X:>.EZ@E‚wJX"JKJ:K>KXAP>L6>>e"> >X:>.EZ@E‚wJX"JKJ:Kƒ%H@ƒHWJp&J)JL)MZJM/JG*KcJK#K^,OWK2O1Mm&MSPVPWOA"OPTG\TKX7K MLSMMVYILMPK_I6Kƒ)MG7MMS4M8RQ2ROYVƒUY+Jp&J)JL)MZJM/JG*KcJKOOW7O1Mm&MSPVPWOA"O#R^-TGRZTKX7K MLSMIfJIRMVYILMPK_I6Kƒ)MG7M~RQ2RVL$VVEVYVƒUY+Jp&J)JL)MZJMYKc"K#K^,OWK2O1Mm&MSPVPWOA"OPTG\TKX7K MLSMMVYILMPK_I6Kƒ)MG7M~RQ2ROYVƒUY-Jp!JKQ&K,JO4J F`'F JQpJQF=RFKCZ/CFf&F:dK:ASƒ>AP>L6>A>XI>1>X:> >`D>>c">-EZ@Eƒ'KJ:K>KX% &Gq&!?a!!DP!(?(&G?&&= -?&k-Ab!PH!2±U"‘!Ab!&Ab&Ab!Ab!#B %<#"&F% &AT@PB!AB!%B%}!Rk!!^s!!Cp!(C:(%>%&Ew->&S-+Fk+&JP4&(Gq(#?a#(=TI(#= a#!Ew(>!S(&Fp-<&g-Ab!AB!%B%&Ab&#Ab#!Ab!&G?&&= -?&k-Ab!C*!!@"!@PB#Ab#(PH2(!AT!#Ab#(PH(2Ab!C*!!@"!~!Ok!![s!&Ew&!>S!!Ab!&@P&B&&AT!AT!Ab#Ab#(AB( B !G?!!= (?!k(#B %<#"&F% &(PH2(Ab!Ab!&@e& -Jx': -O'%B% &Fk&!JP±U"‘4!!B #<!"$F# $&C*&&@"&Ab!PH!±U"‘2!B #<!"$F# $&Ab&@PB!AB!"B"#AT#(AB('B'(Ab(!@P!B!!}!Zk!!]s!!Cp!(C:(%>%&Cp-C&:-*>*+Fp2<+g2DG#=N#*#B#(Hp#; (#9#B#!Hp; !9B&@p-C &G&@-& (AB( B !DP!(?(&Ab&#AB# B !AT!&AT&@PB!C*!!@"!@PB#AT#C*@"!C*!!@"!#Ab#@PB(PH2(!@P!!B!}!SC!-V- !Qs!&Ep-A&-1-:2G-!2&?/&ÿ/MTrk̹ÉÿJAZ2¹a YÿDrumsÿ @ÿGeneral MIDIp¹{]™#<ÿ Drums (BB)¹[(™,<#,_%F,P%,7,(#(,##<,F#,7#2#,P%F%,7#(,(,##<,<,#_,P%F,%7#(,(#,,F#<,#7#2#,P%F%,7,(#(#,,<#<#,_,P%F,%7,(#(,#,F#<#,7#2#%F,P%,7,(#(,##<,<,#_%F,P,%7#(#,F#<#,7,$,%F,P&<%&,7&$.(&.,<#<,#_%F,P%,7#(##<,F,#_%F,P,%7.#(#.,<#<#,_%F,P%,7#(#,F#<#,7,$,%F,P,%7.#(#.#<,<,#_,P%F%,7.#(#.#<,F#,_%F,P%,7#(.#.,<#<,#_%F,P,%7#(#,F#<#,_,P%F,%7#(..##<,<#,_,P%F%,7.#(.##<,F,#_,P%F,%7.#(.##<,<,#_,P%F,%7#(,(#,#<,F,#7#2#,P%F,%7,(#(#,,<#<#,_%F,P%,7#(##<,F,#_,P%F,%7#(..##<,<,#_%F,P,%7#(.(.#,F#<,#7&(&,P%F&<&%,7#(#,<#<#,_%F,P%,7#(,(#,#<,F,#7#2#,P%F%,7,(#(,#,<#<,#7,,,P%F,%7,(#(,##<,F#,7,#(,#,P%F%,7,(#(#,,<#<#,_%F,P,%7#(##<,F#,_%F,P,%7#(##<,<,#_,P%F,%7#(.#.,F#<#,_%F,P%,7#(#,<#<#,_,P%F,%7#(.#.#<,F,#_%F,P%,7#(##<,<,#_%F,P,%7#(#,F#<#,7&(&%F,P%,7#(.#.,<#<,#_,P%F,%7,(#(,#,F#<,#7#2#%F,P%,7,(#(#,,<#<#,_%F,P,%7#(#,F#<#,7&(&&<%F,P&%,7#(##C&219,C,&#1_,W%M%,7#/##C,M#,_%M,W%,7.(#/.#,B#B#,_,V%L%,7#.##B,L#,_,V%L,%7#.#,B#B,#7,,,V%L%,7#.,(,##B,L,#7,,%L,V%,7,(#.,#,D#D,#7,,%N,X%,7#0&(&##D,N#,7&2&,X%N,%7&<.#0&#.#B,B,#7,,,V%L%,7#.,(,##B,L,#7,,,V%L,%7,(#.#,,B#B,#_%L,V%,7#.#,L#B#,_,V%L%,7#..#.,B#B#,_%L,V%,7#.#,L#B,#_%L,V%,7.#.#.#D,D#,7,,,X%N%,7&(#0&##D,N#,7&2&%N,X,%7#0&<#&#<,<#,7,,%F,P%,7#(,(#,#<,F,#7#(,,#,P%F%,7#(,(#,,<#<#,_,P%F,%7#(##<,F,#7&(&,P%F,%7#(##<,<,#_%F,P,%7,(#(#,,F#<#,_,P%F,%7,(#(#,#<,<#,_,P%F%,7#(,(#,#<,F#,7#2#%F,P%,7#(,(,##<,<,#_%F,P,%7#(##<,F#,_%F,P,%7#(#,<#<,#7,,%F,P,%7#(,(,#,F#<#,7,,%F,P,%7#(,(,#,<#<#,7,,%F,P,%7,(#(#,,F#<#,7,#(,#,P%F%,7,(#(,##D,D#,_%N,X,%7#0##D,N#,7&0&,X&D%N&,%7#0#,<#<&212,#&1_,P%F%,7.##(.#,F#<#,_%F,P,%7#(#,<#<,#_%F,P,%7,(#(,##<,F,#_,P%F,%7#(,(,#,<#<#,7,,%F,P,%7#(,(#,,F#<#,7,,%F,P%,7,(#(#,#<,<#,_%F,P,%7#(..#,F#<#,_,P%F,%7.#(#.,<#<#,_,P%F%,7#(.#.#<,F,#_,P%F%,7#(..##<,<,#_%F,P,%7#(#,F#<,#_%F,P,%7#(#,<#<#,7,,,P%F%,7#(,(,#,F#<#,7#(,#,%F,P,%7#(,(#,,<#<#,_,P%F,%7#(#,F#<,#7,$,%F,P&<,&%7#(#,<#<#,7,,%F,P,%7,(#(,#,F#<#,7,#(,#%F,P,%7,(#(#,#<,<,#_%F,P%,7.#(#.#<,F#,_,P%F,%7#(##<,<,#7,,,P%F%,7,(#(#,#<,F,#7#(,#,%F,P,%7#(,(,#,<#<#,_%F,P%,7.#(#.#<,F,#_%F,P,%7#(#,<#<,#_,P%F%,7,(#(,#,F#<#,_,P%F%,7#(,(,##<,<#,_%F,P,%7.#(.#,F#<#,_,P%F,%7#(#,<#<,#_%F,P%,7,(#(#,#<,F#,7#2#%F,P%,7#(,(#,#<,<,#_%F,P%,7#(#,F#<,#7&(&&<,P%F&%,7.(#(#.,B#B#,_,V%L%,7#.#,L#B#,_,V%L,%7#.##B,B#,_%L,V,%7#.##B,L,#_%L,V,%7#...#,B#B,#_%L,V,%7#..#.#B,L,#_%L,V%,7#.##B,B#,7,,%L,V,%7#.,(,#,L#B#,7,,,V%L%,7#.,(,##B,B,#_%L,V,%7#.#,L#B#,_%L,V,%7#...#,D#D,#_%N,X,%7.#0.##D,N#,7&0&,X%N,%7#0##B,B#,_,V%L,%7#...##B,L#,_%L,V,%7#..#.#D,D#,_,X%N%,7#0##D,N#,7&0&,X%N&D%&,7.(#0.#&2#<12,<1,#&_,P%F,%7#(##<,F#,_,P%F%,7#(..#,<#<#,_,P%F,%7,(#(#,,F#<,#7#2#%F,P%,7,(#(,##<,<#,7,,,P%F,%7#(,(,##<,F,#7,,%F,P,%7,(#(,#,<#<#,_,P%F,%7#(,(,#,F#<,#_%F,P,%7#(,(,##<,<,#7,,,P%F%,7#(,(,#,F#<#,7,,%F,P,%7,(#(#,,<#<,#_,P%F,%7#(,(,#,F#<,#_%F,P,%7#(,(,#,<#<#,7,,%F,P%,7,(#(#,,F#<,#7,,%F,P%,7,(#(,#,<#<,#_%F,P,%7#(#,F#<,#7,$,%F,P,%7#(#,B#B#,_,V%L,%7#....##B,L,#_,V%L%,7#.#&,,@#@&#,7&6&+&&@,T%J#@&%#&,7#T&T1,1&#ÿ/MTrkà²ÂÿJAZ2² +ÿGeneral MIDI²VÿPianoÿ @p²{’29²[(]@ÿ Piano (BB)7’2LJ-=:LB0>+EA9,`=E>9B(FK(GD(;3>7427CP@A;4>7G@*<=P*79G='1*6-4Bs4196GD@->BL?75(C7G!CG@LG>7@ 2<EP27BGE'>-=B9*s9B>=GP4<47CGG'>B;*@-s@;C>*DP9A$9-C4JBK1?(=<B 9Z =-1*94(FK(GD(>7427C;3P>7;@A4G@L3I3&5²@’NC&\>96>98>96a²@’IL-1N²@’-/LNNL&²@’><9167%>96L NI.I@G9B-C(4E(B2CEG(9E(<>P+<+7;G>'7-2*4Bs72;4-?EEIQ-Z='4#7,9$E79=EI4.J(GCG(@=C#@>4@G-C9B(4E(7H=N@974-=/Ak/ >=G;699;"(IEGJPI >6;9J4974NJ-D0;,>:NGAB+`>GB;D4?OQLE4Z>,@$C';#E>@CL;O.-FK-ED(=77C9342P7=94@AE@2Gh2>;;S9;B>9;EIGGNKNG-1:E-NGG@(B/>=9.;GsNBG>;92IP2LE(>49-B/=>&LB>=9 E6#E-,LFC-LL@93B%=D>4LI=B>9-97-EJ-E<07:4,@A9+`7@49<2KH@(G2H 2E6GE@@<>64DPCA$CLK>J7C;?(G<L CZ G>74C;-LP99$9@S7J(=G@(9==#-79@D7BE?9-05(<7@!<@@@E709 2<EP27BGE'9*-s9<>B4DPCA$C>JLK;?7C(G<L CZ G4>7;C@D157BE?9-(@=7!=@@@E719 G?;-9BBD25(>7B!>B@BG92; GP4<47DGG'B->B;*s;D>B4Ak4 >9C=L;@";(NELOPN O@;>C-<@P-7=G@'7B4*9-s947=-IP-JE(>4;>9-B/&JB;>9 E6#E-,JFC-JJ@93;D>4B%JI;B>9@9E0-JH3?-HE@@)H0E,@EH4593<7+49<"EB(HEE(B((HE=(E@C(4:9<4/@2IPQC(BH.EG)(B>7;GJH(G3J(B<G+I(+(E)B%7+>567%B&(B>&67>E >4EPG84(GC:;-SO@1>H)NCC;@ >ORN /4J/.;*C:>K@;m@;>COS(Sb(7FC92=@,>9&> C@ 272#E@D>@@K#>_(7R2H;G$>,4F;@724-KC- EB(=:467G9-LZ!E74I>9=#LE?%IQV-DE;-LU(7@4&9-=)s74L9=Q2=s2L49/6<>/(96>E4(BEL'E-ALJ B-EEL(6794 96B<(>@E>B4DSL4Z;1C:@,>=;>C@;2S-DLL-Z9,=:7=41;79=42L>-65;BJ?ED(B7E!BE@EJ;6> /DP>A$>GK2C9J6?(B<G >Z B269>/EE-?HQ-Z7,9$<'4#E79<HE4.2972JJ-JB09,EA<:>+`<>E9B+<>P+7;G>'2*4B7-s472;E?9-7B@D15(@=7!=@@E@719 *?BEEQ*Z6$0#4,9'E4960BE./FK/HD(62<3?79CP96?<BAHB4LP@9$@>JGS(CGG(C@=#>@4-FK-ED(7C4293=7P479=@AE@/LP;9$;9JBS(>GB(>;=#9;/(FK(GD(8C42>7;3P;84>BAGB@->BL?75GD(C7G!CG@LG>7@ @P-<-7=G@'4*9-7Bs9=47-1$-²@+’GU%²@’> 906#6>G9E9E -AG[-5EDGE>=69*BK> 69B;F ;&>&@EQIW$6:9/>4!IE 9>6'B"BITE=-46E-IB4&B69>09/.>B69#BED$E-Ak- 79E;9"4<=(GEEHPG 947H<2C>BEG(9E(B2<E9+FK+JD(@7;C>372P@;CA7>JCIQEE-?-Z9$7,4#='E79=E4I.*FK*HD(<3629C@7P<9@BA6HB/FK/HD(9C?7<362P6<9?BAHB75@-GDL?>B(GC7!CG@LG>7@ -LP99$9@S7J(@=G(=9=#-79/DP>A$>2C6?GK9J(B<G >Z B962>/J@4K(I2J 4G6IG8:>DDY(B7 D@@B>@8GP4<47CGG'@-;*>Bs@;C>-<@P-7=G@'7B4*9-s=9472:P2EA(>(BE;C69)E?69;>GOB(E7G-DNB@E-EJ;C>(9/6-OB$>E96;&>&@IWEQ$6:9/>4!IE 96>'B"BITE=-46-EIB4&B69>09/.B6>9#BED$E-<@P-7$9#B'<,E<B>N9J.4LP@9$@GS>J(GCG(@=C#@4>-LP99$97J@S(=G@(=9=#7-9-FK-ED(7C42<793P94@A<7E@JENQ2?2Z<,B'>$9#E<>BJN9.>BGD@-L?75(C7G!CG@LG>7@ 159-7BE?@D(=7@!=@@@E719 BD9BG?;-25(>7B!>B@GB92; BG(C;B(4E(>N8H48B>(;GP4<47CGG'>B;*@-s;@C>-97-EJ-4,=0E7:@A9+`7@49=->-@EQGW$6:9/>4!GE 96>'B"BGTE=-46-EGB4&69B>09/.6>9B#EDB$E-Sb-C9@,0=7F<9&< C@ 072(E@D>@(<_@K(0H7R9G$<,4F9470@2EPE82(EB:9-?1#JE?%GQV+DE;+JU(6@;)2&7-s267QJ;L04JG9O3?L4OGG)O0L,GLO;5@3C7+;C@"LB(LOE/B(L=/O(LGC(C?@6;:>@C;/G²@’(5G3JCC3(\2>48;9;42aC²@’G#1J²@’#/GNJL&²@’;<2741%;42G JC.C=T-8(9*=9=0-=/D>H(;9> >,;/>?S0,*?4> B9N<JZQC(-DQNJ#-QIJ_NT%>8B/90N JQ>B9JC'EMJ#E4DPCA$C7C>JLK;?(G<L CZ GC47>;-Lx-764 90=6s47=965J?>-;BED(B7E!BE@JE;6> /<BP/7>GB'9B;-6*s;>69-DP-J?ED >D7-C?/54B(>;7!;>@>C4/7 EEIQ-?-Z='9$7,4#E7=9E4I.4BB?-5,E>C@OL;.-97-EJ-4,7:E=09+@A`749@=JQ/?GE/Z;$6#9,>'E9;>G6J.B->BGDN?85(D7G!DG@GN>8B 4LP@9$@>JGS(CGG(C@=#4@>-97-EJ-E7:@A9+=04,`74@9=-Fo- 96QFB.>;F(N2#>B;9JGQ$N-@JQH(N<-QJI!NB3J9'QP>3;=(N=!QJINJ>B9;2KT2$BA9>>?XQ'B>9 Q/XQ NJ-=5-NQO(>691B7,B>9 E3(Q2IISE/2D9:-@I- 9QGUTN,&>WUNQ&²@ÿ/MTrk.µÅÿJAZ2ÿGeneral MIDIµ ]ÿGuitarµ=ÿ @pµ@•=@ÿ Guitar (BB)µ{[(]•B(t2<=B9FB,=F9B2=e+<4F;Fp4;++<4F;F 4+;e*74@9@=(n*4*<4F99F==,=9*4c4<7F>Fq44<77F>>F>47\276@9@=(B(n262<96F9F=B=,B,=B269c4<7F>Fq44<77F>>F4>7\*74@9@=(r*4*<=4F99F=,*49=b477@>@@(n44<77F>@>F@,@74>c-76@r--<66F-6^-:6Co6--<6F6-]-<7F(r262<<>6F>,b+74@;@>(r+4+<>;4F;F>,>+4;b-77@=@@(n--<77F==F@@,=@-7c*<4F9Fq**<44F99F*49_*<3F9Fp9*3*<3F9F 9*3f/<7F>Fq//<77F>>F/7>\-77@=@@(r-7-<=@7F@,=F7=@-b/79@>@B(n/9/<9F>>FBB,/9B>c/<8F>Fq//<88F>>F/8>]4<7F>Fq44<77F>>F7>4\-77@=@@(n-7-<7F==F@@,7=-@e-<6Fq6--<6F -6i-<6Fq--<66F -6d276@9@=(B(r2962<=B9F6F=,B,2B9=6c2:6C9C=*B*l2B=962<9F6F=,B,B629=a-77@<@@(r-7-<@<7F@,@q44<77F>>F47>\-77@=@@(r-7-<=7F@=F@,-@=7c-<7F(n262<6F<>,2<6>e/<7F>Fp/>7/<7F>F /7>f-77@=@q--<77F==F=7-]/<9F>Fq//<99F>>F9>/\478@>@B(n44<88F>B>FB,4>B8b477@>@@(r474<>7F@>F@,>74@e-<7F=Fp7-=-<7F=F 7-=h2<6F9F=,o=6922<6F9F=, =296i2<6F9F=,o22<=696F9F=, 29=6e-=7GJp>/7/@7J>J 7>/i/@7J>Jp/>7/@7J>J >7/d4=7G>G@,n474B7M>@>M@047>@c4@7J>J@.l>@744B7M>M@0@4>7a-=7G=G@,r-7-B@=7M@0=M@-=7c-@7J=J@.l@-=7-B7M=M@0@=-7a2=6G9G=,B,n262B6M99M=B=0B0B629=c2@6J9J=.B.l=B2692B6M9M=0B09=B62a4=7G>G@,r474B@>7M>M@07>@4b-=7G=G@,n-7-B7M=@=M@0@7-=c-76@r--<66F-6_/<9F>Fp9>//<9F>F 9/>e-77@<@@(n--<77F<@@@(n44<77F>@>F@,7>4@b-77@=@@(n-7-<7F==F@@,=7-@c/<9F>Fq//<99F>>F>/9\478@>@B(r484<B>8FB,>F4B8>c4<7F>Fq44<77F>>F7>4]-<7F=Fq-.<77F==F.7=]279@=@q22<99F==F=29^2:9C=Cn=922<9F=F29=]279@=@q22<99F==F=92^2:9C=Cn=922<9F=F29=]-<7F(r+4+<>4F;;F>,;4+>c+<4F9Fq++<44F99F4+9\*74@9@<(r*4*<<94F9F<,<*94e/<3F9Fp9/3/<3F9F /39e477@>@@(r474<@>7F@,>F7>@4c-77@=@q--<77F==F=-7]/<9F>Fq//<99F>>F>/9]4<8F>Fq44<88F>>F4>8_4<7F>Fp>474<7F>F >47f-77@=@q--<77F==F=-7]-<6Fr--<66F6-^-<6Fo6--<6F-6_-<6Fq6--<6F 6-i-<6Fq-6-<6F 6-g-<7F@@(r474<@>7F>F@,@4>7c-77@=@q-+<74F=9F+49]-<7FFq44<77F>>F47>\-77@=@@(r-7-<@=7F@,=F-=@7b/79@>@B(n/9/<9F>>FBB,>9/Bc/<8F>Fq//<88F>>F/8>\477@>@@(r474<@7F>>F@,@>47b-77@=@@(r-7-<@=7F@,=F-7=@b276@9@=(B(n262<6F99F=B=,B,296=Bc2:6C9C=*B*l2=96B2<6F9F=,B,=296Bb-=7G,r+6+B;>6M;M>06>;+c+@6J;J>.l6;>++B6M;M>0+;6>d4@7J>Jp>744@7J>J 47>i4@7J>Jp4>4@77J>J 47>e4@7J>Jq44@77J>>J47>^4@7J>Jn>474@7J>J47>\-=7G=G@,r-7-B=@7M=M@07=@-c-@7J=J@.l@-7=-B7M=M@07@-=b2=6G9G=,p262B6M99M==0=269^2@6J9J=.m62=92B6M9M=09=62]+@4J;Jq++@44J;;J;+4_-@7J=Jp-=7-@7J=J =-7f276@;@q22<66F;;F6;2]-76@;@q--<66F;;F;-6]-<7F(n+4+<4F;;F>>,4>;+c-<7F=Fq--<77F==F7-=\*74@9@<(n*4*<4F9<9F<,4*9<e/<3F9Fp93//<3F9F /39f4<7F>Fq44<77F>>F4>7]-77@=@q--<77F==F-7=\/79@>@B(n//<99F>B>FB,>B9/c4<8F>Fq44<88F>>F>48\477@>@@(n474<7F>>F@@,>74@e-<7F=Fp=-70<9F?F 9?0e279@=@B(r292<=9FBB,=FB29=c2:9C=CB*l29B=2<9F=FB,29B=b2>6H9H=-B-p262>96H9H=B=-B-B2=96^2>6H9H=-B-m=296B2>6H9H=-B-9=62B`2>6H9H=-B-?269=B B@=I9I6@69B=2+6292=B6B=92?2P6H9H=-B- 629=Bmµ@ÿ/MTrk ¶Æ1ÿJAZ2ÿ @ÿGeneral MIDI¶ 2ÿStrings¶Kp{]@[(ÿ Strings (BB)–2'9 B2=6g29B=>2('764 i>(74@2*'966 i6@9*('4 >276g4(7>2'=6B29 g2=9B('4 76>2g>(47*'@26 96g6@9*('>2764 g7>4(B22'=69 ƒY=92B<2-'764 i<-74B22'<69 i<9B2+'@27 ;6g;@+7-'=24 76g-7=4@2*'966 i9@*6?2/'6 96i/9?6>2('764 i7(>4-'=2764 g4-=7>2/'966 i>69/>2('864 i(84>('>24 76g(>74-'76=24 g7-4=B22';69 ƒY9;2B2'B2=69 ƒW9=B2-'<24 76g<-74B22'<69 iB29<>2('4 76i4>(7-'=24 76g4-7=-'<24 76g4-7<2'<6B29 g<92B>2('764 i>7(4=2-'764 i-74=/'6 96>2g/6>9>2('4 86i>4(8('>24 76g7(4>=2-'764 i4=-7-';69 B2ƒW9B;-C6<2-'49ƒV<-4CH6B22'99ƒV92BHG6B2+'79ƒVG7B+>2('C649ƒY(4>CC6>2('49ƒVC4(>=2-'C649ƒYC4=-I6B22'99ƒVIB29>2('49C6iC4>(C6=2-'49fC4=-2';69 B2g9B2;/'6 >296g6/>9<2-'764 i<7-42'B2<69 g2<B9@2+';67 i7;@+-'=2764 g-47=*'@2966 g9@6*?2/'966 i9?/6>2('764 i>7(4=2-'764 i=-74/'6 96>2g69/>('864 >2g8(>4('764 >2g47>(-'764 =2g4-=7B2-'9 ;6ƒY9B;-2'9 =6B2ƒW2=9B-'4 76<2g47-<2'B2<69 gB29<+'7 ;6@2g;7@+-'=2764 g7-4=*'6 96@2g6*@9?2/'6 96i?/69>2('4 76i74>(-'764 =2g7-=4>2/'6 96i/69>>2('864 i8>(4>2('764 i7>4(-'4 =276g-=472';69 B2ƒW;92B2'=6B29 ƒW=29B<2-'764 i-74<B22'<69 i<B29>2('4 76i4>7(=2-'4 76i=-47-'76<24 g7<-4B22'9 <6i9B<2('764 >2g47>(-'76=24 g=-47/'>26 96g>/96>2('4 86i>(48('76>24 g7>(4-'=24 76g=-74-';6B29 ƒWB;9-C6<2-'49ƒV4C<-H6B22'99ƒV9H2BB2+'G679ƒYB+G7>2('49C6ƒYC4>(>2('49C6ƒY4>C(=2-'C649ƒY-C4=I6B22'99ƒV9IB2>2('C649iC>4(=2-'C649i=-C42'B2;69 gB;29/'96>26 g9/6><2-'4 76i-47<2'9 <6B2g<2B9@2+';67 i;@7+=2-'4 76i=-47*'6 96@2g69*@/'?2966 g?/69>2('764 i(74>=2-'4 76i4=-7/'6 >296g6/9>>2('4 86i>(48('4 76>2g47(>=2-'764 i7=4-B2-'9 ;6ƒY-9B;B22'99I6†I29B¶@ÿ/MTrkL³ÃÿJAZ2³\ ?ÿPiano 2ÿ @ÿGeneral MIDIp³[(]ÿVoice 1 (Melody) Up³{ÓQjQNgQHOQNHOQgNXQ OeN"OQ_1QQ_‚zQ Sy%UN SUVL#VV_PUgVFS_UNQQS‚7Q_G!_dZPbndTb]a?] [a[Y_!YZKRZ]gKZ? ]]FZ(]a]MadX d _t)_]F&[]]&ZN [EX_ZLZeX [aZ%]][‚o]mQjQNgQHOQNHOQgNXQ OeN"OQ_1QQ_‚zQ Sy%UN SUVL#VV_PUgVFS_UNQQS‚7Q_G!_dZPbndTb]a?] [a[Y_!YZKRZ]gKZ? ]Z]F(]a]MadX d _t)_]F&[]]&ZN [EX_ZLZeX [aZ%]][‚o];VjIV2Ql&QVVEVQA)V_Q'VWeWSg>SRaR_S_ZE$Z]e'][ay[XNNXVS‚]V-V]FVUeSSGU#SQL%QSVSOQ!ONV(NQ_QN_+NQ]&QNf6N__'aQ_]NaLZL]GZs_w+[A_E[XJ/VN XSRaR_S_ZE$Z]e'][ay[XNNXVS‚]V-V]FVUeSSGU#SQL%QSVSOQ!ONV(NQ_QN_+NQ]&QNf6N__'aQ_]NaLZL]GZs_w+[A_E[XJ/VN X$V.SZySPSL‚]S-SVFSXO@&O'OOOGJ!G-IXI‚KZJ ZLVEJVs[p+S:[ES5QGIQO?oO3NcQJ`NMJKN`$NMHX1HHX‚zH Jr.JMQXTQHJ‚9HW@W[SP_g[ _dUZ?U]VDRVZ`UZZ?(ZXVMX\Q \ [m)['VVVQGOUXQTUGZV‚uZmNcQE`NMEKN`$NMHX1HHX‚zH Or.OMQXPO`QJONHJ‚9H)[SP_g[ _dUZ?U]VDRVMV8'VZ?(ZXVMX\Q \ [m)[QQGOUXQTUGZV‚uZmNcWNN`$NMHX1HHX‚zH Or.OMQXPO`QJONHJ‚9H)[SP_g[ _0XZX3VDRVZ`KV8 ZV*XVMX\Q \ [m)[QQGRQZV‚uZ;OcIO‚!N:)NXN'NN^NvVLVS>$S.SZySPSL‚]S-SVFS%OOO\IXI1IV&ItZJ ZLVEJVS:HS5QGIQO?oO3NcWNN`JQN$J)HX1HHX‚zH Or.OMQXPO`QJONLJaL‚[SP_g[ _0XZX3VDRVZ`UZZ?(ZXVMX\Q \ [m)[QQGOUXQTUGZV‚uZÿ/MTrk¹³ÃÿJAZ2³_ÿPiano Harmony double³ @ÿ @ÿGeneral MIDIp³ @]{ÿMelody Doubled #1 ³[(“EcQB`EMBKE`BQE$B)EX1EEX‚zE Gr.G#JE#JJXPI`JJINEJ‚9E)XSPVgXTVQZ?Q OZO3NDRNtQ?(QUVMUXQ X Sm)SQNGOLXNTLGQV‚uQmEcQB`EMBKE`$EMEX1EEX‚zE Gr.G#JE#JJXPI`JJINEJ‚9E)XSPVgXTVQZ?Q]NDRNQ`UQQ?(QUVMUXQ X Sm)SQNGOLXNTLGQV‚uQ;JcIJ2Ee&EIE:)JXE'JK^KvSLSN>$N.OZyOPJL‚]J-JVFJXG@&G'GOGCJ!C-EXE‚KUJ ULNEJNsSp+O:SEO5JGIJI?oI3EcQB`EMBKE`$EMEX1EEX‚zE Gr.GMJXTJEJ‚9ES@!SXSPVgXTVQZ?Q]NDRNQ`UQQ?(QUVMUXQ X Sm)S'OV*NG OELXNTLGQV‚uQmEcQB`EMBKE`$EMEX1EEX‚zE Gr.GMJXPI`JJINEJ‚9E)XSPVgXTVQZ?Q]NDRNMN8'NQ?(QUVMUXQ X Sm)SQNGOLXNTLGQV‚uQmEcWEE`$EMEX1EEX‚zE Gr.GMJXPI`JJINEJ‚9E)XSPVgXTViOZO3NDRNQ`KN8 QN*UVMUXQ X Sm)SQNGRNQV‚uQ;JcIJ‚!E:)JXE'JK^KvSLSN>$N.OZyOPJL‚]J-JVFJ%GOG\EXE1EV&EtUJ ULNEJNO:HO5JGIJI?oI3EcWEE`BQE$B)EX1EEX‚zE Gr.GMJXPI`JJINEJ‚9E)XSPVgXTViOZO3NDRNQ`UQQ?(QUVMUXQ X Sm)SQNGOLXNTLGQV‚uQÿ/MTrk\°À0ÿJAZ2°Eÿ @ÿGeneral MIDI° ?ÿVariable Journeysÿ/simutrans-124.3/simutrans/music/23-Something-for-Silver-Sand.mid000066400000000000000000000610221474050137200245040ustar00rootroot00000000000000MThdxMTrkxÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿ~j@ @ @   @ @ @ˆ@ÿfj @   @ ÿ~j 8 A1 FFA1 €1 € .@1.@. @1 ÿ~j  @1@1. @ˆ@1ÿ~j. @  .@ €1 €1 .@1.@1ÿ~j.@1   @1 @1.@1ˆ@1.ÿ~j.@   @ € €  ÿjgÿljÿXÿQ âÿYÿSomething for Silver Sandÿ/MTrk ·±Á ÿJAZ2±P][({ ,ÿBass‘!P±@B‘!)Q *R)p#I*P*D# J*p!Jp$R!p#U$H7#±U"‘Jp!Ok!(SL±U"‘= (Rp#U GR# !Op(E!lN(xPd!K m#L!d!K#p(B !g-M (d(P-N( #J<#4#I %H#(&O%"(E&(5(E"/D($/ /N"$M/p#Y$H±U"‘;#Jp#U ±U"‘/ # #R #Rp!St!(SD±U"‘7( -X|-(Zt(%Kx%!G_!3±U"‘!Vp(M !g-X (d([-N( #Ok#*SL=±U" ‘*(Up(#U:#$P #V$ %P#"&Z%%&(PB("Q "#V %P#"&Z%%(U&H(7 [kRk\k[s&YY!(&!-Hi-*Px*&R3&&!<!Ex#Dy# ?yQ vWx Qj!S m!%Tx*K %m%D*r!Q %oT!j 2KX!>2!-Kx*O-H*2 !@~!&SR&!;!(Qt(*RX*!G!-LP-!; !#Lx%L#q%&Bx*E&U#B*##1Sx%M1e)Q %o,O)p,!Dx"J !k"#=x$O#^$%/%1Jt1%Ed%2KX!>2!-Kx*O-H*2 !@~&S!R!;&!(Qt(*RX!G*!-LP-!; !#Gx%I#d&D %m*E&d%G*x'I%d)D 'm,E)d,-KX->(Kx%O(H%%2% @~!SR;!#Qt#%RXG%(LP(; #Vx/E #o*Q/j&W*u&(Ex/C(b4I /o/T4O"</"!L-!#!T (D!(((A( (Pq(#Hf!O#p(E!l((Nk(#RP<#!Vp(M !g-X (d([-N( #J<#4#I %H#(&O%"&(Pq(#Hf##V %P#"&Z%%&Jp#F %E# %&S(&Rp!Vp(M !g-X (d([-N( !Kp(B !g-M (d(P-N( #Ok#*SL=±U" ‘*IpNx I k#H t#J#p#Jp#UH7#±U"‘JpxQkYkMkUs&Ox-M&b2S -o-^2W- )F)(NX#9(# *Lw*,SN, #=#/UP/#6 #Mx Gj!I m!%Jx*A %m%:*r!G %oJ!j &Nx'T &k(G'x)Y(^)*Fx+V*w,P+u-R,k-#JO# R±U"‘ %Jw%&6x*C&T*#H 1S#x%M1e)Q %o,O)p,!Dx"J !k#="x$O#^$%v! Dx@ P)O (N)X#9(# *Lw*,SN, #=#/UP/#6 #!P+!-!R -J!i(D-vH(g!J G!~!],!ÿ/MTrk7¹ÉÿJAZ2™*P#<¹][({ÿDrums¹ cZ™#*_*Z%F%*>*(**P#<*#_%U*Z*%>*2*#<*F*#_%F*Z*%?*(**P#<*#_%P*Z%*?#2*2*#*F#<*#_%P*Z*%=*(* *F#<*#_*Z%N%*=*2* *P*_%F*Z*%>*2**P*>&&&7*Z%U%*&>*2**F#<#*_%F*P%*?*(*#<*P*#_%P*P%*?*2**F#<*#_%F*Z*%?*(**P#<*#_%P*Z%*?*2**F#<*#_*Z%F%*?*(**P#<*#_%P*Z%*?*2**F&2&*;#F# *P*;&2& *F#<#*;&& *d&2*&&&&(& *F#<#*_%P*Z%*=*(* *F#<*#_*Z%N*%=*2* *F#<*#_%F*P*%?*(*#<*P*#_%P*P*%?*2**F#<*#_%P*Z%*=*(* #<*F*#_%N*Z*%=*2* *F#<*#_*Z%F*%?*(**P#<*#_%P*Z%*?*2**F#<*#?&F&%F*Z%*?*(**P#<#*_%P*Z*%?*2**F#<#*_%F*Z*%?*(**P#<#*_*Z%P%*?*2**F#<#*_%F*P*%?*(**P#<*#_*P%P*%?*2**P*_%F*Z*%>*2**P*>&&%U&7*Z*%&>*2*#<&2*F#&*_*P%P%*=*2* *P#<#*_%P*Z*%=*2* *P#<*#_*Z%F*%>*(**P#<*#_%U*Z*%>*2*#<*F*#_%F*Z*%?*(**P#<*#_%P*Z%*?#2*2*#*F#2#*_%<*P*%?*(**F#<#*?&<&*P%P#P%*#?*(**P#<*#_%F*Z%*>*(**P#<*#_%U*Z*%>*2#2*#*P#<*#_*Z%F%*>*(**P#<*#_%U*Z*%>*2*#<*F*#_%F*P*%?*(**P#<#*_%P*P*%?*2**P*_%F*Z*%>*2**P*>&&%U*Z&7%&*>*2*&2&_*P%F3Z%3*>3F33F&(&3_%F3Z*d%*3>3F33P3_*F%F3Z%3*>3F33Z3_*d3Z*3>3F33F3_%<3Z*Z*3%?&(3F&33P3_%F3Z*d*3%?3F33P3?&&%F3Z*P%3*?3F&(&33P3_%F3Z*d%*3?3F33F3?&<&*Z%<3Z*%3?3F&(3&3P3_%F3Z*d%*3?3F33P3_3Z*F%F3%*>3F33Z3_3Z*d3*>3F33P3_*P%F3Z%*3=&(3<3& 3P3_*d%P3d*%3=3F&<3& 3F#F3#_%<3Z*Z%*3?3F&23&3P3?3(&<3&%d*d3Z3*%?3F&F3&3F3_3Z*Z%<3%*?&(3F&33P3_3Z*d%F*%3?3F33P3_3Z%F*F3%*>3F33Z3_3Z*d*3>3F33P3_3Z%F*P%3*=3<&(&3 3P3_*d%P3d*3%=3F&<3& #F3F3#?&<&*Z%<3Z%3*?3F&23&3P3?.(&<&.*d%d3Z3%*?3F#<&F&3##<*P#*_%F*Z%*>*(**P#<*#_*Z%U*%>*2**F#<#*_%F*P*%?*(**P#<#*_*P%P*%?*2**P#<#*_%F*Z%*>*(*#<*P#*_%U*Z%*>*2**P*_%F*Z%*>*2**P*>&&&7*Z%U%*&>*2**P#<#*_%F*Z%*>*(**P#<*#_%U*Z%*>*2**P#<*#_*F%F%*=*(* *P#<#*_%U*F%*=*2* #<*F#*_%F*P%*?*(**P#<*#_%P*P*%?*2**F*_%F*P%*=*2* *F#<*#_%U*P%*=.<. *F#<*#_%F*P*%?*(**P#<#*_*P%P%*?*2**F#<#*_%F*P%*?*(*#<*P#*_%P*P%*?*2**F#<*#_%F*Z%*?*(*#<*P*#_%P*Z%*?*2**P#<#*=&(& *Z*=&(& *F#<*#=&2& *Z#F*#&&&2& &2#<1(*F#1&*_%P*P*%=*2* *P#<#*_*Z%P%*=*2#2#* *P#<#*_%F*Z%*>*(*#<*P*#_%U*Z%*>*2**F#<#*_%F*P*%?*(**P#<#*_%P*P%*?*2**F#<#*_*Z%F*%?*(**P#<#*_%P*Z%*?*2**F#<#*_%F*Z%*?*(**P#<#*_%P*Z%*?*2**P#<#*_%F*Z%*>*(**P#<#*_*Z%U%*>*2#2*#*P#<*#_%F*Z%*>*(*#<*P#*_%U*Z*%>*2**F&2*&;#F# *P*;&2& #<*F#*;&& *d&2*&&&&(& 1(&21&_3Z*P%F3%*>3F33F&(3&_%F3Z*d%3*>3F33P3_*P%F3Z3%*?3F33P&(3&?&(&*d%F3Z*%3?3F33F3_*d%F3Z*%3>&(32&33P3_*d%F3Z*%3>32&(3&3P3_%F3Z*P3*%?3F&(3&3P3?&&3Z*d%F3*%?3F33F3_3Z*d%F*%3>32&(&33P3_%F3Z*d3*%>32&(&33P3_%F3Z*F*%3>3F33Z3_3Z*d3*>3F33F3_*d%F3Z*%3>&(323&3P3_%F3Z*d%3*>32&(&3#Z#=&F& 3Z*P*3=3P&<&3 3P&P3&=#P&2#& 3Z*d3*&(&3P&<3& 3P3_3Z*P%F%*3?3F33P&(3&_3Z*d%F3*%?3F33P3_3Z*F%F*3%>3F33Z3_3Z*d3*>3F33F3?&<&%<3Z*Z%3*?3F&(3&3P3_3Z%F*d*%3?3F33F#F3#_*Z%<3Z%3*?&23F&33P3?&<&%d3Z*d*3%?&F3F#<&3##<*P*#_%F*Z%*=*(* *P#<#*_%U*Z*%=#2*2*# *P#<*#_%F*F%*=*(* *P#<#*_*F%U%*=*2* *F#<*#?&F&%F*Z*%?*(**P#<#*_%P*Z%*?*2**P#<#*_*Z*<&(*<*& *F#<*#<&2& *P*<*<&<&* #<*P*#_%F*Z*%>*(**P#<#*_%U*Z%*>*2*#<*F#*_%F*P%*?*(**P#<*#_*P%P%*?*2**F#<#*_%F*P*%?*(**P#<*#_*P%P*%?*2**P#<#*_%F*Z*%>*(*#<*P*#>%Z%*Z*>*2**F#<#*_%F*P%*?*(**P#<#*_%P*P%*?*2**F#<*#_*P%F*%?*(**P#<*#_%P*P%*?*2*.6#<#._*F%P%*=*(* *P#<*#_*P#<#*=*2* &2*F&*;#F# *P*;&2& *F#<*#;&& *d&2*&&&&(& *F#<*#_%F*Z%*?*(*#<*P#*_%P*Z%*?*2**F#<#*_%F*Z%*?*(*#<*P*#_%P*Z%*?*2**F#<#*_%P*F*%=*(* *P#<#*_*P#<*#=*2* *F#<*#_*Z%F*%?*(**P#<*#_%P*Z%*?*2*#<*F*#_%F*P*%?*(**P#<#*_%P*P%*?*2*#<.6.#_%P*F%*=*(* *P#<#*_*P#<*#=*2* *F#<*#_%F*Z%*?*(**P#<*#_*Z%P*%?*2**P#<*#=&(& *Z*=&(& #<*F#*=&2& *Z#F*#&&&2& 1(&2&1>&F&3Z*P%F%*3>3F3&(3F&3_*d%F3Z3*%>3F33P3_%F*F3Z%3*>3F33Z3_3Z*d3*>3F33F3_3Z*d%F3*%>32&(3&3P3_%F3Z*d%3*>32&(3&3P3_*P%F3Z%*3=3F#F3# 3P3=&<& *d%P3Z*%3=3F&2&3 3F3_%F3Z*d3*%>32&(&33P3_*d%F3Z%3*>&(323&3P3_%F3Z*F3%*>3F33Z3_*d3Z*3>3F33F3_3Z*Z%<3*%?3F&(3&3P3_3Z*d%F*%3?3F33F#F3#_3Z%<*Z3%*?3F&2&33P3?&<&%d3Z*d*3%?3F#<&F3#&3F3@&(&*Z%<3Z*%3@&(3<3&3P3_3Z*d%F%3*@3F33P3_*F3Z%F*%3>3F33Z3_*d3Z*3>3F33F3_%F3Z*d%3*>&(323&3P3_3Z*d%F*3%>&(323&#F3F#3_%<3Z*Z*%3?3F&23&3P3?.(&<.&3Z%d*d%*3?3F&F&3#<1(#1=&2& *P*=&(& *F*=&<& .P.&<&&2& &F#F#&7&&&<&7&F#2#&7&&&&#P&<&#ÿ/MTrkì²ÂÿJAZ2ÿPiano’=<G<²@][7{ ^Z’8<@<9><IBp=<G<@<8B8<>Ip4<=:<@G8E<>

D<:=<?<E9<4p?=8<><DB<9=ƒ38G@= ><G<B<9<„G>9B;<8<=<@<ƒ`@8=;x=,>,B,9,B>B9=>.9.B.=.$B==4B4>4>9497>=B9B=>=9===$BH=>HB=H>9H9;B>9==98E8=8@8DE=@9 44 =?9?@?.9@='=A9A@A6@9=B4$$@<=<49<*@9=*=I9I@I-=@9K4/4@*9*=*.9=@'464=?9?@?9@=9?><B<;<G<ƒ`;G>787>B7BI7‚8>IB->9;9D9@9u;D>@#><B<;><=<8<;B

=B<G<;<8><BpB;G<><8<GA<>F8GA> @898=8†@9=?=@9@@@E@=9@E@<9<=<E<‡@=E><B<G<@9;<ƒ`B>D5>5;5G@5;‚FD@;>8C>C@C;C @;8> B<;<G<>><B<I<B8><G<;<B8B

G;><A<H<B8 @8=898† =9@?9@=@@@E@@E=9E=6=>=D>E6 9!9 9D>DBD.9B>'>FBF9F69>BB><B<8<I<„I>8B6<=<9<B<‡@9=B6<9<6><‡@9>;<B<6><ƒ3>B; K=;=F=A=eF;AK :!: ADDD;D=D.;DA=';F=FAFDF6=A;DB:)#=7E7:L7DEL= 44 @>9>=>.=@9'=@9@@@69=@B4#$=;9;4@;*@=9*=H9H@H-9@=K4.49)@)=).=@9'454=>9>@>99@=?G<B<><ƒ`>BG<><D<GC<ƒ3DC>G L<=<G<D<„LDG=E<I<N<><ƒ`EN>=<D<G<IL<ƒ`GDLI7B7>7=E7DB>IE 44 E>B>>>;>.>EB;'E@B@;@>@6;BE>B4##@8=84E8D=@E 44 =?9?@?.=9@'=A9A@A6@9=B4$$9<@<4=<*@9=*9I=I@I-9@=K4/4=*@*9*.@=9'464=?9?@?9=9@><;<B<„B>;=<B<><8<ƒ`=8>><B<;<BG=<8<><GB B<G<;<><‚>;GB><A<H<8HA @898=8†=9@?=@9@@@E@9E=@98@8=8D=@9 44 @?9?=?.@9='9A=A@A6@=9B4$$9<=<4@<*9=@*=I9I@I-9=@K4/4=*@*9*.9@='4649?@?=?9=@9?G<><B<;<ƒ`G;B>5D5@5>;5‚F;>@D8CIC>CBCl8B>I B<;<G<>G;B 8<B<I<><‚8>IB><B<G<;

;G<<A<><B8

A898@8=8<E8D@E9= 44 =?@?9?.9=@'@A=A9A69=@B4$$9<@<4=<*9@=*9I@I=I-=@9K4/4=*9*@*.=@9'4649?@?=?99@=E<><6<ƒV6>E B<><I<8<ƒV8BI> =7B797e9B= 99 9>B>=>.B=9'=@9@B@6B9=B9#$=;9;9B;*=9B*=HBH9H-9B=K9.99)B)=).B9='959=>9>B>9=9BB<E<><‡aBE>N<><G<ƒ`G>A<K<F<N;<ƒ3AF;K @<=<E<‡aE=@G<;<B<><ƒ`;G>B<8<;<B><ƒ`8>B=<@<G<;8<ƒ3=G@8 9<I<><B<ƒV9B>I @<8<=<G<„=8@GI7>7B797‚I9B>-E9B9>9;9u>BE;#98E8=8@8D9@=E 44 9?=?@?.=@9'@A=A9A69=@B4$$=<@<49<*9=@*9I=I@I-@=9K4/4@*=*9*.@9='464@?9?=?9=9@?B<;<><G<ƒ`BG>87I7>7;B7‚IB8>-@9;9>9D9uD@>;#B<;<>

;I<8<B<B>IB ><G<B<;<‚>;BGB<><8<G

GB=<9<8@<‡@@=E8@8=8998D=@9E 44 @?=?9?.@=9'9A@A=A69=@B4$$9<=<4@<*9=@*=I@I9I-=9@K4/4=*9*@*.@9='464=?@?9?9=9@?><G<;<B<ƒ3>B;G%I,>,B,8,BB>I8I.B.8.>.$I>884I4B4B>47>8BII=B=>=8=$BI8>HIHBH>8H;I8>B;<><G<B;B 8<><=<B<‚B8=>;<><B;B ><8<A<<<‚><A8@<9<=<E<‡@=9E ><9<6<„69>B<8<><=<ƒ6>8=B B898=8†=9B?9@=@6@B@l=B96 ><6<E<‡a>6EB<;<><ƒ3>;B A<;<F<K<ƒVAF;K E<=<L<‡aL=EPG<;<B<>B;G ;7>7C787‚<;8C>/@9>9;9D9u@D;>#=@8L4.99xLQOL G9`GLK(LG3G948=C98LU458BGB=EL8G94 =%938E=6LIGA4+SK‚4G98S=L²@ÿ/MTrk ºÊÿJAZ2º{][F{ '][F{ 'P]P{ 'P][F{ 'P][F{ 'P[F[F{ '][F 'P@]PÿGuitarš=%n=-68?=?=-8X*4:s*4*24::::4:*]/#6)9)>l//469>6<9<>%#/69>K,#4);)m,,4;44<;<$4;,J- 8%=%n8-=-68?=?8-=Z4 :%>%p4:46:?>>?>4:\/ 9%=%p//69=9?=?9=/Z48>s48428:>>:84>\- 8%=%n=-8-68?=?8-=X-8"="k=-8-58====8-V-4s--644? 4-R-4"p--544= 4-Q-8=s-8-28:==:-8=\-8=s-8-189==9=-8U4;">"p446;;?>>?;>4W4;">"r445;;=>>=4;>Y-49s--244:99:-94\-49s-4-14999949-Y-49s-4-34;99;4-9\-&4,9,r--14499999-4Z/6v//266:6/\/6v//1669/6]48>p4846>8?>?8>4R48">"m48458=>>=4>8S2 ;%s226;;?;2\4 8%>%p4468>8?>?84>Z/ 6%q/6/66?/6X/8>s/8/28:>>:8/>]-#9)=)m--4=99<=<$-=9M- 9%=%e-=9-59===-=9R-9"="e=9- -59===!-9=L-#9)=)k9-=-49<=<=-9U-49p-4-694?9?-94R-4"9"m-4-594=9=-49U-49m-4-54=99=#4-9Q- 4%9%m-4-494<9<94-U/6s//666? 6/R/6"p//566= /6U48>p44688?>>?8>4R48">"m44588=>>=>48Q/ 6%q6//66?/6X4 8%>%n48>468?>?8>4X/6v//266:6/^2 8%;%p28268?;;?2;8\4 9%=%p4469=9?=?94=\4#9)=)p49459=====94\4 9%=%p49459====94=X4&9,=,p4449=9<=<=94Z2&6,9,n2962<6F9F962X2#6)9)k6292;6D9D692R/&8,>,n8/>/<8F>F>8/X/#8)>)k/8>/;8D>D8/>R*"1"6(9(=r*1*:61:6C9=9C=**16=9\*"1"6(9(=r*16*9196B9=9B=)=*691Y*"1"6(9(=r*1*;61;6D=99D=*=*169\*.1.6595=!q*16*9196B99B==)961*=^2"9(>(p22>99H>>H9>2R2%9+>+m292<>9F>F2>9U2 9%>%m292<>9F>F#9>2Q2(9.>.m292<>9E>E9>2S/$6*s//;66D6/\/(6.s//966B/6^,!5';'p,,=55G;;G;,5R/$8*=*m//<88E==E=8/Q-"9(=(s-9-:9C==C9-=\-"9(=(s--999B==B9-=Y-"9(=(s-9-;9D==D9=-\-.95=5r-9-9=9B=B-9=V/# ;)s//<;:F/:W/# 9)u//;98D8/[/$8*>*p//;89D>>D>9/\/(8.>.p/8/9>8B>B/8>^-8=p-8-6=8?=?8-=R-8"="m-8-58====-=8R-#4)p--444<'-4M- 4%h4--54= 4-S- 8%=%p--688?==?-8=\-#8)=)p--588=====-8Z/9>s/9/29:>>:9/>\/9>s/9/199>>99>/Y- 4%9%n9-4-64?9?-94X-4"9"k-94-54=9=4-9R-4"9"k-49-54=9=!-94N-4"9"m--4494<9<49-R/ 6%q/6/66?/6X/6"n/6/56= 6/S/#8)>)m//4>88<><$>8/M/ 8%>%e/>8/58=>=8/>S2 ;%s226;;?2;[/#8)>)m//4>88<><$/>8J2 ;%q;226;?2;Z2 8%;%p22688?;;?82;Z-9=s-9-29:==:-9=\-9=s--1999==99-=Y-9=s-9-39;==;-9=\-&9,=,r-9-1=99=9-=9V49"="p44699?==?49=W49"="r44599====4=9U4 9%=%r44599====94=Q4 9%=%p44499<==<4=9[/6v//266:/6\/6v//16696/Y/ 8%>%n/8>/68?>?/8>X/8">"k>/8/58=>=8>/R/ 6%q6//66?/6\48>p48468?>>?8>4N/6v//266:/6^4 8%>%p48468?>>?>84^49=p44699?==?49=R49"="m4945=9===4=9U49=m49459====#=49Q4 9%=%m49449<==<=49R2(6/9/m229966B9B$269M2%6+9+e6292:6C9C962R2(8/;/m2298;8B;B$;28M2%8+;+e28;2:8C;C2;8R1(9/=/m1199=9B=B$9=1M1%9+=+e=191:9C=C1=9R1"9(=(e9=1 1:9C=C!=91L1(9/=/k19=199B=B19=S2$9*>*p22;9>9D>D2>9\2(9.>.p29299B>>B2>9\2$9*>*p2929>9B>B29>X2*91>1p29289A>>A92>[/(6/p//966B'/6M/%6+h/6/:6C 6/R1(5/;/m1195;5B;B$51;M1%5+;+e;511:5C;C5;1S-$9*=*p--;9=9D=D9=-\-(9.=.p-9-9=9B=B=9-\-$9*=*p-9-99B==B=9-X-*91=1p-9-8=9A=A-=9[/(6/p//966B'6/M/%6+h/6/:6C 6/U4!8'>'p484=8G>>G84>R4$8*>*m44<8>8E>E84>U-8=p--688?==?8-=R-8"="m-8-58====8=-R/#9)>)m//49>9<><$/>9M/ 9%>%e/>9/59=>=>9/Q-8=s-8-28:==:8-=\-8=s--1889==9-=8U4;">"p446;;?>>?4>;W4;">"r445;;=>>=;>4Y- 9%=%n-=9-69?=?-9=X-9"="k9=--59===9=-R-9"="k=9--59===!-9=N-9"="m-=-499<=<=-9T/ 6%s//666?6/\/#6)s//566=/6V28";"p22688?;;?28;W28";"r22588=;;=;28]/6s//666? 6/R48>p4468>8?>?48>N/ 6%q/6/66?6/Z4 8%>%p48468?>>?>48Z- 4%9%n9-4-64?9?-94X-4"9"k4-9-54=9=-49R-4"9"k94--54=9=!49-N-4"9"m--4944<9<9-4V-49p-4-694?9?94-R-4"9"m-4-54=99=-49U-49m-4-594=9=#94-Q- 4%9%m--444<99<-49Q/6v//266:6/\/6v//16696/[/ 8%>%p//689?>>?9>/\/#8)>)p//588=>>=8/>Z/ 6%q/6/66?/6\48>p4846>8?>?84>N/ 6%q6//66?6/\/8>p/8/6>8?>?/8>J49"="p44699?==?=94W49"="r44599====94=U4 9%=%r44599====4=9Q4 9%=%p44499<==<=49\2(6/9/m229696B9B$629M2%6+9+e2962:6C9C692M/#8)>)p//<88F>>F>8/W/#8)>)r//;88D>>D/8>[*$1$6*9*=o*16*;1;6D9=9D=**=961\*(1(6.9.=o*1*9619=96B9B=)1=*69\*$1$6*9*=o*1*96196B9=9B=)1*96=X**1*6191=o*16*818=96A9A=(9=6*1Z2"9(>(s292:9C>>C92>\2"9(>(s29299B>>B92>Y2"9(>(s22;99D>>D>29\2.95>5r29299B>>B2>9\/$6*s//;66D/6\/(6.s//966B/6\,$5*;*p,5,;6D;;D;,6\,(5.;.p,,95;5B;B,5;\-$9*=*p-9-;=9D=D9-=\-(9.=.p--99=9B=B-=9\-$9*=*p-9-99B==B-=9X-*91=1p-9-8=9A=A-9=V/# 6)s//<66F/6W/# 6)u//;66D/6Y4&8,>,n>484<8F>F>84X4#8)>)k>844;8D>D84>W-$8*=*p-8-7=8@=@-8=\-8 = p-8-5=8>=>-8=a-+82=27=-8-98B=B#-8=iº@ÿ/MTrk¶¶Æ1ÿJAZ2¶[UÿStrings¶{ ,]@PÚ–J2B/ƒ]JBD2>/ƒ]D>I2B/‡9IBJ2B/‡9JBG2>/ƒ]G>G2A/ƒ]AGE2=/‡9E=G2>/ƒ]>GD2>/ƒ]>DËJ2B/ƒ]JBD2>/ƒ]D>I2B/‡9IBJ2B/‡9JBG2>/ƒ]G>G2A/ƒ]AGE2=/‡9E=G2>/ƒ]G>D2>/ƒ]>DËJ2B/ƒ]BJD2>/ƒ]>DI2B/‡9IBJ2B/‡9JBG2>/ƒ]>GG2A/ƒ]AGE2=/‡9E=G2>/ƒ]>GD2>/ƒ]D>D7=7†>= Dv¶@ÿ/MTrk r³ÃÿJAZ2³][Zd J{ÿMelodyf“@g"@ B^.BDn!DEc:E8DsAD9:>?X?9QG98;dO; 9 9>R?> @[+>H@,>;C; W">@V5@@BL:B9DQAD9E_3EHG\AGˆjErEGAGEHEBJ/BEKE BH)B@Y@B2'@PB!@=0= @Q%@=F = ;P#;=:(=;R#;9A9;A;9F(96@(6 9?96@"64H!463!64R%134)1%1K$12I 203V 3 4W046^)64J842I2 4\:4ƒd6H#68N.8:V:;=5;=O= >N.>@I&@BP-BLBR3BFB&C#&CBGBY)BRBV6B‚Hs$HIO I&==*=>9)> ?a?@82@D^$DG`:GD!DE[2EBV"B @C8@@LZ4LIE"I JZ3J"G1GIY2IE*EG`5GBBEY7E@#BD@0BEV(B@E>B;Ee;E;6$;6BEKBEBWKB A2ABIDB:IgTIH1!IKHA>B*B EWE GO0GJ\!JNU0NQYQU\3UXl)XUKFUS&SUaUVKV UR(USW(SQ^(QN#/NOQOPW'P,S[ SL?2L;LN;LLULZLU#NSL0NQHQTm3TEUe5UETi2TBUb:U9TeU/TIUX_GX QQ&Qƒ7Q7QTfKTQ/Q SEDS3QUINJQ)NeSZ,SR[RQA*QNN%NJB"JG=(GEA)E!CRCD0nDGCHGDDJG;JNV+NFMX$MNU:N2Lc;L4Jb;J+I[FI-KeL`K‚ILhQ`JQ SR%Q=S7QQU!QZQZ$QRTi"TUR'UV^,VTB,TU^/UQD+Q?LA>L?OeBOL)PSL4PQi&Q‚fQl:QQXQ QI/QGQW1QLQUSQSH"QLS5QP_*P†CLv;LL`LLc9LLfL Lb@L6LjLLM1M NU8NMd$M L0UD>…Z@d@A="ADAD GUGJu?J…E`3EBIW?I:LfML'NWANL0LQe4QQl4QjQk@Q„VS2VW\%WXI&XWL#W V7,VUR&US5?S@Q=:Q=SIISQ',UCQS‡Nb,NNSk.SFUc6UJVd I;LQa3I1QKL4I"LQ_JQ I))L5IHLQg>Q†-Le)LM`MNR(NMa%M LA5LK["KJE.JHT HIP4I!LU$ILL5IEB=>B;EWOEBHWBMHE,GJE;GCE98E3EYLE,Hb IPHID@9B@B(B DW+D%Ed'E D)NM*M NQ9NLZL I9)I EZ&EB1JB…SB?(B EF"EIZ(IJH J#NX&NQ>+QUY,U VZ*VSf$SQC$QNP"NJQ&JIF$IG:=G[!> ;F);%9a#955=5„"6[G68F'89d:9;j*;N=g#=P>q*>T:a+:C=a*=;[+; 6,6 9e:97<6[7/6M4O&4N6^26K4Q14K6e566D.5K6255U"5 4=344D4 5R;55O 56O266O'65J255I!54U:4ÿ/MTrk=°ÿJAZ2ÿSomething for Silver Sandÿ/simutrans-124.3/simutrans/music/24-needlessly-striking.mid000066400000000000000000001443121474050137200236420ustar00rootroot00000000000000MThdxMTrk`ÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿVj@ @ @ @ @ ÿ~j@ @ ÿ~j@@1@ '@ ÿ~j@ '@ @ @ ÿ~j@@1@ 'ÿ~j@ '@ @ @ @ ÿ~j@@ÿj#ÿjjÿXÿQ=ÿYÿNeedlessly Strikingÿ/MTrkñÁ!ÿJAZ2ÿBass±][{@ P…Q‘!Vt!%Y;%%Z&%(Wx%a(P(Q%&!X(w%f!@%%Z(([%u![( EOLIEYIPOJLM EOLIE3L>O-ID EILOO$L<I?E5 EOLIIGOGLKEN EOLII9O$E+L2 EIOLE8O)IAL; EOILLMOEERINELOIO%E,L5I;EIOLO&E7L9I> OELIIMERLMOL EOILI4L4E*O EIOLO'E7I@L< EOLIIIEIOBLG EOILI@L;E6O&OELIE?I@L=O-LOEIICE?LCO< EOILI8L=O*E/ OEILLEE;IFO8 ELOIEQOBIKLK EOILICL?O+E.EIOLL=O,E5IB EOLIOFLLIIEK EOLIO(E4L9I@ OEILE;IAL>O( EOLIOJLMEYIP EOLIE3IDO-L> EIOLO$I?E5L< EOLIENOGIGLK EOILI9L2E+O$ EOILO)E8IAL; EIOLOEINERLMEOLIO%I;L5E,ELOIO&I>E7L9 OELILMIMOLER EOILE*I4L4O ELOIO'L<I@E7 EOILEIIILGOB EOLII@L;E6O&EOLIE?I@L=O-LOEIO<ICLCE? EOILI8E/L=O* OEILLEO8IFE; EOLIIKOBEQLK EOILO+ICL?E.EOILL=O,IBE5 EOLIOFLLIIEK EOLIE4O(L9I@ EOILE;O(IAL> EOLILMIPEYOJ EOLIIDE3O-L> EIOLO$I?L<E5 EOILLKENIGOG EOLII9L2O$E+ EOILO)E8IAL; EIOLERINLMOEEOLIO%I;E,L5EILOE7O&L9I> OELIEROLIMLM EOILI4E*L4O EOLIE7L<O'I@ EOLILGEIIIOB EOLII@L;E6O&EOILE?L=O-I@LOIEICE?O<LC OEILI8L=E/O* OEILO8LEE;IF EOLIEQOBLKIK EIOLL?O+ICE.EOILL=IBO,E5 EOLIIILLOFEK EOLIO(L9E4I@ EOILE;O(IAL> EOLIOJLMEYIP EOLIE3L>IDO- EILOO$E5I?L< EOLIENIGOGLK EOILI9E+O$L2 EOILE8O)L;IA EOILINEROELMEOLIO%L5E,I;EILOO&L9I>E7 OELIIMERLMOL EOILE*L4I4O ELIOI@E7O'L< EOLIIIOBEILG EOILE6I@L;O&OEILE?L=O-I@LOEIO<ICLCE? OEILI8O*L=E/ OEILLEE;O8IF EOLIEQLKOBIK EOILO+L?ICE.EIOLL=IBE5O, EOLIOFLLIIEK EOLII@L9O(E4 OEILE;L>IAO( EOLILMOJEYIP EOLIE3O-IDL> EILOO$L<E5I? EOLIIGLKOGEN EOILI9E+L2O$ EIOLO)E8L;IA EIOLOEINLMERELOIO%I;E,L5EIOLE7O&I>L9 OELIEROLLMIM EOILI4E*L4O EIOLL<O'I@E7 EOLIIIOBEILG EOILL;E6I@O&EOILE?O-L=I@LOIEO<LCE?IC OEILI8E/O*L= OEILE;IFLEO8 EOLIIKLKOBEQ EOILICO+L?E.EOILL=IBE5O, EOLILLIIOFEK EOLIO(E4L9I@ OEILE;L>O(IA EOLILMIPEYOJ EOLIL>E3O-ID EILOO$E5L<I? EOLIOGENLKIG EOLII9L2E+O$ EOILO)E8IAL; EOILLMOEINEREOLIO%L5I;E,ELOIE7L9I>O& OELIIMLMEROL EOILI4E*L4O EOILI@E7L<O' EOILOBIIEILG EOILE6I@L;O&OELIE?L=O-I@LOIEICLCO<E? EOILI8E/O*L= OEILLEE;O8IF ELOIEQOBIKLK EIOLICL?O+E.EIOLL=E5IBO, EOLILLIIOFEK EOLIO(E4L9I@ EOILE;O(L>IA EOLIOJIPEYLM EOLIO-E3IDL> EILOO$I?L<E5 EOILLKENIGOG EOLII9L2O$E+ EIOLE8O)IAL; EOILEROEINLMEOLIO%L5E,I;EOLIO&E7L9I> OELIERLMOLIM EOILE*I4L4O ELIOI@O'E7L< EOILEILGIIOB EOLIE6I@L;O&OELIE?L=O-I@LOEIICE?O<LC EOILI8O*E/L= OEILLEE;O8IF EOLIIKLKEQOB EOILL?O+ICE.EIOLL=IBE5O, EOLIOFLLIIEK EOLII@L9E4O( OEILE;L>O(IA EOLIOJIPLMEY EOLIO-IDE3L> EILOO$I?E5L< EOLIENOGIGLK EOLII9O$E+L2 EOILO)E8IAL; EIOLERLMINOEELOIO%I;E,L5EIOLL9O&E7I> OELIIMERLMOL EOILL4E*I4O EOILL<I@O'E7 EOILEIOBLGII EOLIE6L;I@O&OEILE?L=O-I@LOEIQCT<NCJ? JTNQN8T*Q=J/ TJNQT8QEJ;NF JQTNNKQKJQTB JTNQNCQ?T+J.JNTQQ=T,J5NB JTQNNITFQLJK JTQNJ4T(Q9N@ TJNQJ;T(Q>NA JTQNTJJYQMNP JTQNT-J3Q>ND JNTQT$J5N?Q< JTQNQKJNTGNG JTQNN9Q2J+T$ JNTQJ8T)NAQ; JNTQTEQMJRNNJQTNT%N;Q5J,JNTQJ7T&Q9N> TJQNQMJRTLNM JTNQN4J*Q4T JQTNN@Q<J7T' JTNQJITBQGNI JTQNJ6Q;N@T&JTNQJ?N@Q=T-QTJNNCJ?QCT< TJNQN8J/T*Q= TJNQNFQEJ;T8 JQTNJQNKTBQK JTNQT+NCQ?J.JNTQQ=T,J5NB JTQNTFNIQLJK JTQNJ4N@Q9T( TJNQJ;Q>T(NA JTQNNPJYQMTJ JTQNQ>J3T-ND JNQTT$Q<N?J5 JTNQJNNGQKTG JTQNN9T$Q2J+ JNTQT)J8NAQ; JTNQTEQMJRNNJTQNT%J,Q5N;JNTQT&Q9N>J7 TJQNJRTLQMNM JTNQQ4J*N4T JNTQQ<N@T'J7 JTNQQGNITBJI JTQNQ;J6N@T&JTQNJ?T-N@Q=QTJNQCNCJ?T< JTNQN8J/Q=T* TJNQNFJ;QET8 JQTNNKJQQKTB JNTQQ?T+NCJ.JTNQQ=T,J5NB JTQNTFQLNIJK JTQNT(N@J4Q9 TJNQJ;NAT(Q> JTQNTJJYNPQM JTQNNDJ3Q>T- JNTQT$Q<J5N? JTQNTGQKNGJN JTQNN9T$Q2J+ JTNQT)J8Q;NA JTNQNNJRQMTEJQTNT%Q5N;J,JNTQQ9J7T&N> TJQNJRNMQMTL JTNQJ*N4Q4T JTQNJ7Q<N@T' JTNQTBQGNIJI JTNQQ;J6N@T&JTNQJ?T-Q=N@QTJNT;QBJ>NB TJNQN7T)Q<J. TJNQT7QDJ:NE JTQNJPTAQJNJ JNTQQ>T*NBJ-JTNQQ<NAJ4T+ JTQNQKTENHJJ JTQNJ3N?T'Q8 TJNQJ:Q=N@T' JTQNTIQLJXNO JTQNNCJ2T,Q= JNQTT#Q;N>J4 JTQNP;JBLBG> GPJLJ7P)G.L< PGJLP7LDJEG: GLPJGPJJLJPA GJPLJBL>P*G-GPJLL<G4JAP+ GPLJLKJHPEGJ GPLJL8J?G3P' PGJLG:L=J@P' GPLJLLJOPIGX GPLJG2JCL=P, GJPLP#L;J>G4 GPJLIBO;E>LB OEILI7E.L<O) OEILE:IEO7LD ELOIOAIJLJEP EIOLL>O*IBE-EOILL<E4IAO+ EOLILKIHOEEJ EOLIL8O'I?E3 EOILE:L=I@O' EOLIEXOILLIO EOLIE2L=O,IC EIOLO#E4L;I> EOILO<ICE?LC OEILI8O*E/L= OEILE;LEIFO8 EOLIEQLKOBIK EOILICL?O+E.EOILL=IBE5O, EOLIV<O?SC VOSS8O/V* VOSSEV8O; OSVSKVBOQ OVSV+SCO.OSVS=O5V, OVSO;IBLBE> EOILI7L<E.O) OEILE:O7LDIE EOLIIJOALJEP EIOLIBL>O*E-EOILL<E4IAO+ EOLILKIHOEEJ EOLIO'I?L8E3 OEILE:O'I@L= EOLIEXLLIOOI EOLIE2L=O,IC EIOLO#L;E4I> EOLILCICO<E? OEILI8O*E/L= OEILO8E;IFLE ELOIOBLKEQIK EOILICL?O+E.EOILL=O,E5IB EOLIO?SCV< OVSS8O/V* VOSO;SEV8 OSVOQVBSK OSVSCV+O.OVSS=O5V, OVSE>IBLBO; OEILI7E.L<O) OEILE:LDIEO7 ELOIIJLJOAEP EOILIBO*L>E-EIOLL<O+E4IA EOLIOEIHLKEJ EOLIL8I?E3O' OEILE:O'L=I@ EOLIIOEXOILL EOLIE2ICO,L= EIOLO#L;I>E4 EOLIO<ICLCE? OEILI8L=E/O* OEILE;O8LEIF EOLIOBEQIKLK EOILO+ICL?E.EOILL=O,E5IB EOLIO?SCV< OVSS8O/V* VOSO;V8SE OVSOQSKVB OVSV+SCO.OSVS=V,O5 OVSE?O<ICLC OEILI8L=E/O* OEILO8LEE;IF EOLIOBIKLKEQ EIOLL?O+ICE.EOILL=O,IBE5 EOLIIIOFLLEK EOLIL9E4I@O( OEILE;L>IAO( EOLIEYOJLMIP EOLIL>IDE3O- EILOO$I?E5L< EOLILKOGENIG EOLII9E+O$L2 EOILO)E8L;IA EOILERLMOEINEOLIO%I;E,L5EOILE7I>L9O& OELIERIMOLLM EOILL4I4E*O EILOO'I@L<E7 EOILIIEIOBLG EOILL;E6I@O&EOILE?O-I@L=LOEIIMOFEILM OEILIBO4LGE9 OEILLOEEIPOB ELOIE[IULUOL EIOLLIIMO5E8EOILLGO6ILE? EOLIOPISLVEU EOLIE>O2LCIJ EOILEELHIKO2 EOLIIZLWEcOT EOLILHE=O7IN EIOLO.LFIIE? EOLIIQEXLUOQ EOLIICL<E5O. EIOLEBO3IKLE EIOLIXOOLWE\EOLIO/E6IEL?EILOO0EALCIH OELILWIWOVE\ EOILE4I>L>O( EIOLIJLFO1EA EOLIESOLISLQ EOLIIJE@LEO0OELIEIIJLGO7LOEIOFIMEILM EOILIBLGO4E9 OEILOBEEIPLO EOLIIUE[OLLU EOILO5LIIME8EIOLLGILE?O6 EOLIOPISLVEU EOLIO2IJLCE> EOILEEO2LHIK EOLILWEcOTIZ EOLIE=LHINO7 EIOLO.E?IILF EOILLUOQIQEX EOILICO.L<E5 EOILEBO3LEIK EIOLE\IXOOLWEOLIO/IEE6L?EILOO0LCIHEA OELIOVIWLWE\ EOILL>I>E4O( ELOILFIJEAO1 EOILISLQESOL EOLILEIJE@O0EOILEILGIJO7LOIEIMOFEILM OEILIBE9LGO4 OEILLOIPOBEE ELOIE[LUOLIU EOILIMLIO5E8EIOLLGILE?O6 EOLIISLVOPEU EOLIE>IJO2LC EOILEELHO2IK EOLIIZEcOTLW EOLIE=INO7LH EILOO.IILFE? EOILLUOQEXIQ EOLIICE5L<O. EIOLEBO3IKLE EIOLIXE\LWOOELOIO/E6L?IEEOILEALCO0IH OELIIWOVLWE\ EOILI>L>E4O( ELOIEAO1LFIJ EOILESLQOLIS EOILLEIJE@O0OEILEIIJO7LGLOEIOFIMEILM EOILIBO4LGE9 OEILEEOBLOIP ELOIE[LUIUOL EIOLIMO5LIE8EOILLGO6ILE? EOLIISLVOPEU EOLIE>IJLCO2 OEILEEO2IKLH EOLIOTIZEcLW EOLIE=O7INLH EILOO.E?IILF EOILOQEXIQLU EOLIICO.E5L< EOILO3EBIKLE EIOLLWE\OOIXEOLIO/E6IEL?EILOLCO0IHEA OELIIWLWOVE\ EOILL>E4I>O( ELOIO1EAIJLF EOLIISOLESLQ EOILLEE@IJO0EOILEIIJLGO7LOEIEIOFIMLM OEILIBO4E9LG OEILOBIPEELO EOLIIUE[LUOL EOILIMLIO5E8EOILLGE?O6IL EOLIOPISLVEU EOLIO2E>LCIJ OEILEEO2LHIK EOLILWEcIZOT EOLILHO7INE= EILOO.LFIIE? EOLILUIQOQEX EOLIICO.L<E5 EOILEBO3LEIK EIOLE\IXLWOOELOIO/IEE6L?EILOLCO0IHEA OELILWE\IWOV EOILI>E4L>O( EOLIO1LFEAIJ EOILOLESLQIS EOILE@LEIJO0EOLIEIIJLGO7LOIEOFLMEIIM OEILIBLGO4E9 OEILEEIPOBLO EOLIOLIULUE[ EOILO5IMLIE8EIOLLGO6E?IL EOLIISLVOPEU EOLILCO2E>IJ OEILEELHO2IK EOLIIZOTEcLW EOLILHINO7E= EILOO.E?LFII EOLIEXLUIQOQ EOILICO.E5L< EIOLEBO3IKLE EOILE\IXOOLWELOIO/IEE6L?EIOLEAO0LCIH OELIIWOVLWE\ EOILL>E4I>O( EOILIJLFEAO1 EOLIOLISLQES EOILE@IJLEO0OELIEIO7IJLGLOIELMEIOFIM OEILIBO4E9LG OEILEEIPOBLO EOLIIUE[OLLU EIOLO5IMLIE8EIOLLGO6ILE? EOLIOPISLVEU EOLIE>LCO2IJ OEILEEO2IKLH EOLIEcOTIZLW EOLIO7E=INLH EIOLO.E?IILF EOILOQEXIQLU EOILICO.L<E5 EIOLO3EBIKLE EOILLWE\IXOOEOLIO/IEE6L?ELIOLCO0EAIH OELIE\OVIWLW EOILI>L>E4O( EOLILFO1IJEA EOLIOLESLQIS EOLIE@IJLEO0EOILEILGO7IJLOIEOFLMEIIM OEILIBO4E9LG OEILOBIPEELO EOLILUOLE[IU EIOLO5LIIME8EOILLGILE?O6 EOLIISOPLVEU EOLIIJE>O2LC EOILEEO2IKLH EOLIIZOTLWEc EOLIE=LHO7IN EILOO.IILFE? EOLIEXLUIQOQ EOLIICE5L<O. EOILO3EBLEIK EOILIXLWOOE\EOLIO/E6L?IEEOILIHEALCO0 OELIOVE\LWIW EOILL>E4I>O( EOILIJEAO1LF EOILESISLQOL EOLILEE@IJO0OELIEIIJLGO7LOIENMQMTFJI TJNQNBJ9T4QG TJNQQOJENPTB JQTNNUTLJ[QU JNTQT5NMQIJ8JNTQQGNLT6J? JTQNNSQVTPJU JTQNT2J>QCNJ JTNQJEQHT2NK JTQNJcNZQWTT JTQNQHNNT7J= JNQTT.QFJ?NI JTNQQUTQNQJX JTQNNCJ5T.Q< JTNQT3JBNKQE JNTQQWTOJ\NXJQTNT/J6NEQ?JTNQNHJAQCT0 TJQNJ\TVNWQW JTNQQ>N>J4T( JTNQNJQFJAT1 JTQNJSQQTLNS JTNQJ@NJQET0JTNQJINJT7QGQTNJJINMQMTF TJNQNBT4QGJ9 TJNQJENPTBQO JTQNQUJ[TLNU JTNQNMQIT5J8JNTQQGJ?T6NL JTQNNSQVTPJU JTQNJ>NJT2QC TJNQJET2NKQH JTQNTTNZJcQW JTQNT7J=NNQH JNTQT.J?QFNI JTQNTQNQQUJX JTNQNCQ<J5T. JTNQT3JBQENK JTNQNXJ\TOQWJQTNT/NEQ?J6JTNQT0QCNHJA TJQNJ\NWQWTV JTNQJ4N>Q>T( JTQNT1NJJAQF JTNQNSQQJSTL JTNQQEJ@NJT0TJQNJIQGNJT7QTNJJIQMNMTF JTNQNBJ9T4QG TJNQTBQOJENP JQTNNUTLJ[QU JNTQQINMT5J8JNTQQGT6NLJ? JTQNNSTPQVJU JTQNJ>NJQCT2 TJNQJET2QHNK JTQNJcNZQWTT JTQNQHJ=T7NN JNQTT.NIJ?QF JTQNNQQUTQJX JTNQNCQ<J5T. JTNQT3JBQENK JTNQQWJ\TONXJTQNT/J6NEQ?JTNQQCJANHT0 TJQNNWQWTVJ\ JTNQJ4N>Q>T( JTQNT1JANJQF JTNQNSJSTLQQ JTNQJ@QENJT0JTQNJINJT7QGQTNJNLQLJHTE TJNQNAJ8QFT3 TJNQQNNOTAJD JQTNTKQTNTJZ JTNQT4NLQHJ7JNTQQFT5NKJ> JTQNNRTOQUJT JTQNT1QBNIJ= JTNQJDQGT1NJ JTQNNYTSJbQV JTQNQGJ<NMT6 JNQTT-QENHJ> JTNQLLGHPEJL PGJLJAP3G8LF PGJLPAJOLNGD GPLJPKLTJTGZ GPJLJLLHP4G7GJPLLFJKG>P5 GPLJJRLUPOGT GPLJG=JILBP1 PGJLGDJJP1LG GPLJPSJYGbLV GPLJJMP6LGG< GJPLP-JHLEG> GPLJOEEHLLIL OEILIAO3LFE8 OEILIOLNOAED ELOIOKEZLTIT EOILLHO4ILE7EOILLFO5IKE> EOLIOOLUIRET EOLIE=O1LBII OEILEDO1LGIJ EOLIEbIYOSLV EOLIIME<LGO6 EILOO-IHLEE> EOLIOFLMIMEI OEILIBE9O4LG OEILIPEELOOB ELOIE[IULUOL EOILO5IMLIE8EIOLLGILE?O6 EOLIVFSMOI OVSSBV4O9 VOSVBSOOE OSVSUVLO[ OVSSMV5O8OSVSGV6O? OVSOEILEHLL OEILIAE8O3LF OEILLNEDOAIO EOLIEZOKITLT EIOLILLHO4E7EOILLFIKO5E> EOLIIROOLUET EOLIIIE=O1LB EOILEDIJLGO1 EOLIIYEbOSLV EOLILGO6E<IM EILOO-E>IHLE EOILEILMOFIM EOILIBLGO4E9 OEILEEIPLOOB EOLIOLIUE[LU EOILO5LIIME8EIOLLGILO6E? EOLIOIVFSM VOSSBO9V4 VOSOESOVB OVSSUVLO[ OVSV5SMO8OVSSGO?V6 OVSOELLILEH OEILIALFO3E8 OEILIOOALNED ELOIEZLTITOK EOILO4LHILE7EIOLLFO5IKE> EOLILUIROOET EOLIO1E=LBII EOILEDIJLGO1 EOLILVEbOSIY EOLIE<IMO6LG EIOLO-E>IHLE EOILOFEIIMLM OEILIBE9O4LG OEILEEIPLOOB EOLIIUOLE[LU EOILLIO5IME8EIOLLGILO6E? EOLISMOIVF OVSSBV4O9 VOSOEVBSO OVSSUO[VL OSVV5SMO8OVSSGV6O? OVSOFEILMIM OEILIBO4E9LG OEILLOEEIPOB EOLIOLLUE[IU EOILIMO5LIE8EOILLGE?ILO6 EOLIOPISLVEU EOLIO2E>LCIJ EOILEEIKLHO2 EOLILWOTEcIZ EOLIINE=O7LH EILOO.IIE?LF EOLIEXIQOQLU EOLIICL<O.E5 EOILO3EBIKLE EIOLE\IXLWOOEOLIO/L?E6IEEILOIHLCO0EA OELILWIWE\OV EOILE4L>I>O( EOILO1LFIJEA EOILLQISOLES EOLILEIJE@O0EOILEIIJO7LGLOIEE?ICO<LC EOILI8E/L=O* OEILO8LEIFE; EOLIEQOBLKIK EIOLL?O+ICE.EIOLL=E5O,IB EOLILLIIOFEK EOLIO(E4I@L9 EOILE;L>IAO( EOLIOJLMIPEY EOLIE3IDO-L> EIOLO$E5L<I? EOLIIGOGENLK EOLII9E+L2O$ EOILO)E8IAL; EIOLERLMINOEEOLIO%E,L5I;EILOI>L9O&E7 OELIIMERLMOL EOILL4I4E*O EOILL<O'I@E7 EOILIILGEIOB EOILI@L;E6O&EOLIE?O-L=I@LOIELCE?ICO< OEILI8L=O*E/ OEILIFLEO8E; EOLIOBLKEQIK EOILL?ICO+E.EOILL=O,IBE5 EOLIIIOFLLEK EOLIL9O(I@E4 OEILE;L>O(IA EOLIOJIPLMEY EOLIE3IDL>O- EIOLO$E5L<I? EOLIOGIGLKEN EOLII9O$L2E+ EOILO)E8L;IA EIOLERLMINOEEOLIO%I;E,L5ELIOO&I>L9E7 OELIIMOLERLM EOILE*L4I4O EOILI@E7O'L< EOLIIIOBLGEI EOLIE6L;I@O&EOILE?O-I@L=LOIEO<ICLCE? OEILI8L=E/O* OEILE;LEIFO8 ELOILKIKOBEQ EOILICL?O+E.EOILL=IBO,E5 EOLILLOFIIEK EOLII@O(L9E4 OEILE;L>O(IA EOLIEYOJLMIP EOLIL>IDO-E3 EIOLO$I?E5L< EOLILKIGENOG EOLII9L2E+O$ EOILO)E8IAL; EIOLOELMERINEOLIO%I;E,L5ELIOO&E7L9I> OELIOLERLMIM EOILE*L4I4O EOILE7O'L<I@ EOLIIIEILGOB EOLIE6I@L;O&OELIE?I@O-L=LOIEO<LCICE? OEILI8O*L=E/ OEILIFE;O8LE ELOIEQIKOBLK EOILO+ICL?E.EIOLL=E5IBO, EOLIIILLOFEK EOLII@L9O(E4 OEILE;L>IAO( EOLIEYOJLMIP EOLIL>IDE3O- EIOLO$L<E5I? EOILENIGLKOG EOLII9O$E+L2 EOILE8O)IAL; EIOLEROEINLMELOIO%I;L5E,EILOO&E7I>L9 OELIIMOLLMER EOILI4E*L4O EOLIL<E7O'I@ EOILEIOBLGII EOLIL;I@E6O&EOILE?O-L=I@LOIEICE?O<LC OEILI8E/O*L= OEILIFE;O8LE ELOIOBIKLKEQ EOILL?ICO+E.EOILL=IBO,E5 EOLILLOFIIEK EOLII@E4O(L9 EOILE;L>O(IA EOLIIPLMEYOJ EOLIO-IDL>E3 EILOO$L<I?E5 EOILOGIGENLK EOLII9O$E+L2 EOILO)E8L;IA EIOLLMOEINERELOIO%L5E,I;EILOL9O&I>E7 OELIERLMIMOL EOILI4L4E*O EOLII@L<O'E7 EOLILGEIIIOB EOILL;E6I@O&OEILE?L=I@O-LOIEO<ICE?LC OEILI8E/L=O* OEILLEE;O8IF EOLILKEQOBIK EOILO+ICL?E.EIOLL=E5IBO, EOLILLIIOFEK EOLII@L9E4O( EOILE;L>IAO( EOLIEYIPLMOJ EOLIIDE3L>O- EIOLO$L<I?E5 EOILENLKIGOG EOILI9L2O$E+ EOILE8O)IAL; EIOLINLMEROEEOLIO%L5I;E,ELIOE7O&I>L9 OELIIMERLMOL EOILI4E*L4O EOLII@L<E7O' EOLIEILGIIOB EOILL;E6I@O&EOILE?I@O-L=LOIELCICO<E? OEILI8O*L=E/ OEILLEIFO8E; ELOIOBEQLKIK EOILO+ICL?E.EIOLL=O,IBE5 EOLILLOFIIEK EOLII@E4O(L9 EOILE;IAL>O( EOLIEYLMOJIP EOLIIDO-L>E3 EILOO$E5I?L< EOILIGOGLKEN EOLII9O$E+L2 EOILE8O)L;IA EIOLINERLMOEEOLIO%E,L5I;EILOO&E7L9I> OELIIMEROLLM EOILL4E*I4O EOILL<I@E7O' EOILEIOBLGII EOLII@L;E6O&EOLIE?O-I@L=LOIEE?ICLCO< EOILI8L=O*E/ OEILE;IFLEO8 EOLIOBLKIKEQ EOILL?O+ICE.EIOLL=O,IBE5 EOLIOFLLIIEK EOLIL9I@O(E4 EOILE;L>IAO( EOLIEYOJIPLM EOLIL>O-IDE3 EILOO$E5L<I? EOLIOGLKIGEN EOILI9L2O$E+ EOILO)E8L;IA EIOLOEINERLMELOIO%I;L5E,EILOO&I>E7L9 OELIIMERLMOL EOILI4E*L4O EOLIO'E7L<I@ EOLILGOBEIII EOLIE6L;I@O&EOILE?L=I@O-LOIEJ?NCQCT< JTNQN8T*J/Q= TJNQNFT8J;QE JQTNQKTBJQNK JNTQQ?NCT+J.JTNQQ=T,J5NB JTQNQLTFNIJK JTQNJ4N@T(Q9 TJNQJ;T(Q>NA JTQNTJQMJYNP JTQNJ3Q>T-ND JNTQT$Q<J5N? JTNQQKTGJNNG JTNQN9T$J+Q2 JTNQT)J8Q;NA JNTQJRTENNQMJQTNT%N;Q5J,JNQTN>Q9T&J7 TJQNTLJRNMQM JTNQQ4J*N4T JTNQJ7Q<T'N@ JTNQQGNIJITB JTQNN@J6Q;T&JTQNJ?N@Q=T-QTNJT<J?NCQC TJNQN8T*Q=J/ TJNQNFQEJ;T8 JTQNNKTBJQQK JNTQT+Q?NCJ.JNTQQ=J5T,NB JTQNTFNIQLJK JTQNN@J4Q9T( TJNQJ;Q>NAT( JTQNNPJYQMTJ JTQNQ>T-NDJ3 JNTQT$N?Q<J5 JTQNQKNGJNTG JTQNN9T$J+Q2 JTNQT)J8Q;NA JNTQNNJRTEQMJQTNT%J,Q5N;JNQTT&N>J7Q9 TJQNJRQMTLNM JTNQQ4J*N4T JNQTN@T'J7Q< JTQNNIJITBQG JTNQQ;N@J6T&JTNQJ?T-Q=N@QTNJJ?NCQCT< JTNQN8T*Q=J/ TJNQT8QENFJ; JTQNNKJQQKTB JNTQNCT+Q?J.JTNQQ=J5T,NB JTQNQLNITFJK JTQNN@T(Q9J4 TJNQJ;NAQ>T( JTQNTJNPQMJY JTQNT-Q>J3ND JNTQT$J5N?Q< JTNQTGJNNGQK JTNQN9T$Q2J+ JTNQJ8T)NAQ; JNTQTENNQMJRJTQNT%N;Q5J,JNQTN>J7Q9T& TJQNQMJRNMTL JTNQN4J*Q4T JQNTQ<N@J7T' JTNQTBQGJINI JTNQQ;N@J6T&JTNQJ?T-Q=N@QTNJJ>QBNBT; TJNQN7T)J.Q< TJNQT7QDNEJ: JTQNJPTANJQJ JNTQT*NBQ>J-JTNQQ<T+J4NA JTQNNHTEQKJJ JTQNN?J3T'Q8 TJNQJ:T'N@Q= JTQNJXTIQLNO JTQNNCJ2Q=T, JNQTT#J4N>Q; JTNQG>P;LBJB GPJLJ7L<G.P) PGJLJEG:P7LD GLPJJJGPLJPA GJPLP*L>JBG-GJPLL<P+G4JA GPLJPELKJHGJ GPLJL8J?P'G3 GPJLG:J@P'L= GPLJGXPIJOLL GPLJP,JCG2L= GJLPP#J>G4L; GPLJIBLBE>O; OEILI7E.O)L< OEILE:LDO7IE EOLIIJEPOALJ EIOLL>O*IBE-EIOLL<IAE4O+ EOLIOEIHLKEJ EOLII?O'L8E3 OEILE:O'L=I@ EOLIIOEXLLOI EOLIL=O,E2IC EILOO#L;E4I> EOILO<ICE?LC OEILI8O*L=E/ OEILE;LEIFO8 EOLIEQIKOBLK EOILO+L?ICE.EIOLL=IBO,E5 EOLISCO?V< OVSS8V*O/ VOSSEO;V8 OSVSKVBOQ OVSSCV+O.OSVS=V,O5 OVSIBO;E>LB EOILI7E.L<O) OEILO7IEE:LD EOLIOALJIJEP EOILO*L>IBE-EIOLL<E4IAO+ EOLIOEIHLKEJ EOLIL8O'I?E3 OEILE:L=O'I@ EOLILLOIEXIO EOLIICE2O,L= EIOLO#I>L;E4 EOILLCE?O<IC OEILI8O*E/L= OEILIFE;LEO8 EOLIEQLKOBIK EOILO+ICL?E.EIOLL=E5IBO, EOLIO?SCV< OVSS8O/V* VOSO;V8SE OVSOQVBSK OVSV+SCO.OVSS=O5V, OVSO;LBE>IB OEILI7O)E.L< OEILO7LDE:IE EOLIEPLJIJOA EOILO*L>IBE-EIOLL<E4IAO+ EOLILKIHOEEJ EOLIE3L8O'I? OEILE:O'L=I@ EOLIOIIOLLEX EOLIO,L=ICE2 EIOLO#L;I>E4 EOILO<LCE?IC OEILI8O*E/L= OEILIFLEE;O8 EOLIEQIKLKOB EOILL?O+ICE.EIOLL=IBE5O, EOLIO?V<SC VOSS8V*O/ VOSV8SEO; OSVSKOQVB OSVSCV+O.OSVS=O5V, OVSE>IBO;LB OEILI7E.L<O) OEILIEO7LDE: EOLILJOAIJEP EIOLO*IBL>E-EIOLL<E4IAO+ EOLIIHLKOEEJ EOLII?L8O'E3 OEILE:L=O'I@ EOLILLOIEXIO EOLIE2L=O,IC EILOO#L;I>E4 EOILE>O;LBIB EOILI7E.L<O) OEILO7IELDE: EOLIIJEPLJOA EIOLIBO*L>E-EOILL<IAE4O+ EOLILKOEIHEJ EOLIE3L8O'I? OEILE:L=I@O' EOLIIOEXLLOI EOLIICL=O,E2 EILOO#E4I>L; EOILOIEHICLAIEOL OE*L$I4 IELOI.OL$E" EIOLLFINOEEP EILOE-I.O!L"LIEOI>L9E;O-EILOOHEPIPLKEILOO!E%I,L& IELOL4E:I9O'EIOLELLJIMOF EILOI3O!L-E'EILOE,L0I3O" IELOEOINLJOEvOIL9TEM=P@L7?CJ‚9=C@7²@ÿ/MTrkWºÊÿJAZ2º@][ 2][{ P][{ P][{ {][{ P][{ P][{ APÿGuitarºPýQš-OoD@H?-MMDEDHI@MNSECKGHILQEN„JLGC9S=9CKGOG=9Ch-/7F=: @D EB…~E -=7@-<=K7K4?EK@K@4-=E7>-6-,3366@<@?@D@',-934=67HD?<=H@HEH„m@=47E-7S=S4F-B@SES @E4=-7oE]tCNyBE CnAEBm@LA9E@2S)3\2E4Y;W3 ;?P 4>;? 9M<"7B97 9< =KCB G= L9‚YG9CL= JHA@E;7.;4 ;7EAJFF<5KK89BF8<BFK95=9C;GFLBƒIC=9LG -/7F=: @D EB…~E =-7@4?-<7K=K@KEK=4-7E@e-IM9X==CDHK…ZHC9=- 9M=;CKHK 9=CHi4A-99PR?T94-!@M?'ET@"@?E#H?@IEJLHIHPJ!EDH"CUE*CEMCDE@EC@ ?RER>G ?E #9G<9 9Z'2X9!3Y2%4\344V4 4R4 4Wa2949D D=AB@FGSEEQG„JE@<2SD=AB@FGSEEQG„JE@<2S@OKDBHGQ@I‚GB>-/7F=: @D EB‚4= E@-7=K(7F(-<$=7--3I7I==@B EF E7=@-+/7F ;: >DCBB>7+C;-/7F=: @D EB‚*@ = E-7@K(=F(7K-64977D@==D@DED 7=4-@E+6297D;D>DCD‚2+>7;C-OoD@H?-MMEDDHI@MNSkECKGHINLQGCL-6497D=D@DED 4-7=@E=B7B-448EB@B -E4=7@U+/7F;: >D CBI+C>;7-FOE])CNyBE CnAEBm@LAA-E@4S)7\4D4Y 74?P>;? 9M<"7B97ø+?H*@L?'EK&EH@&HJJ*HGJ%EB@H&@IE"?C@@;? ?@@:>P?$I9F<&7>9O4S9F-M7‚ 4-9º@ÿ/MTrk,³ÃÿJAZ2³][7{ ?ÿMelody³x‚g“@_x@B[xBEYEWHAI^H'I+HWHIJIIEXME(BI37E=EBEBEY=E7=B…VK]*KLU=LKMKJI*JHN&HES4ENE[xEBK4BE=GE[?G7G7?=E'ES1EBT.-F4F7F=F@BFEZyB74E-=8Ea0EBLMB@97@E]=I@I7I4E7@=…@_@@BN.BET8E=HU!HIH'I4HYHIRFIEY=E8BL4B37E=E@EEY=@E7"E[7G=G@G'=7E@ƒiJYJKOKL[†LO\/ONKR"KJR3JHX!HEO#ERJ`xJHVyHEWpEBJxB7@B@ET=@…1EE@>E;4H[7HEGAEC=/CEd@„v“XWO!WVP"VTOTQIQVaAVTY+T QLEQ'QUT[>@_I@#@O@@R&9K@=K@KC_99=@C E]AE=E\/EEET9E3EWE"EX8EE;EEQ"EEYEEK"EE[EEO"EEOE#ER"EEKE#EH"EE]EEV"EEVE#ES&EEUE#EI/E EPE'E@+EE`EKXQY4K QLK/LE[EJ->7>ER@>=>4>'@7-=4EMEQ'EE`EEOEEWEEM&EEVEET&EEVE'EKEEXE#EM"EESEEM+EEZE'LVHV/HLIK+IEQ+ERE_NE#BTZ4>\x>Y<> ?J3?@V?@CQ0C EV3EH\7HJK3JKX3KLSDLOM7OQ^@QOM+OQY8QAS]&STKZTQS8QO1OQYƒJQCLGLO`>L7L4OC7G> LO'L KU%KJS+JHT"H JSAJHZ0HEV8E=EY7E?E=E‚E7=?GJ[GGCG>G/JCG>LS"L O_'ORSbSTQ'T8Q`4Q OEO#Qb[Q"OU0OL?L"OaAOLKLJH'JK`8KJP'JHP#H J`8JHS'H=272@2EF+7=@E Hf4HEQ'ECDCEc4E CJ'C@E&@Cb7C@U4@>B>@b=@>Q0>c7>7me4M 7M7 9aI794ÿ/MTrk7°ÿJAZ2ÿNeedlessly Strikingÿ/simutrans-124.3/simutrans/music/25-Float-on-by.mid000066400000000000000000000653661474050137200217460ustar00rootroot00000000000000MThdxMTrk¡ÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿ 2006.10.06ÿÿvj ¸¸ ÿ~j''ÿ~j'1¸  ÿ~j¸  '''ÿ~j¸  1¸   ÿ~j*NL¸eº  ÿ~j   ÿjgÿnjÿXÿYÿ Float on byÿQ á¥@ÿQ ‹ÿ/MTrk£±Á'ÿJAZ2±]KÿGeneral MIDIÿBass±wÿ @±{[P@ @¡`‘&NO& 2R2 2N&V2&2F82@-KH-0&N@&2N22F2-V-2K22E2"-K- &J5&%RK+V++V+V"&Z5&%&N&XF2^U+Z+"+K+^#&X&%&G&'+X+Z9!&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!NO +R+ +N&V+&F8@+KH+0N@+N++F+&V&+K++E+"&KJ&A&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!RK+V++V+V"&Z5&%&N&XF2^U+Z+"+K+^#&X&%&G&'+X+Z9!&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!NO +R+ +NV++F8+@&KH&0N@+N++F+&V&+K++E+"&K& J5%WO #[# #W_#(O8(@TH0W@#W##O#_(T(@#N##T S#4!UO! -Y- -U-!]!-M8-@(RH(0!UO! -Y- -U-!]!-M8-@(RH(0RK(V((V(V"#Z5#%#N#XF2^U(Z("(K(^##X#%#G#'(X(Z9!!UO! -Y- -U!]-!-M8-@(RH(0!IK!-M--M-!M!"(Q5(%-E-!OF!2&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!NO &R& &N&V+F8+@KH0N@&N&&F&V+K+@&E&&K &J4&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!RK+V++V+V"&Z5&%&N&XF2^U+Z+"+K+^#&X&%&G&'+X+Z9!&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!NO +R+ +N+&V&F8@+KH+0N@+N++F+&V&+K++E+"&K&JA&RK&2V22V2&V&"-Z5-%-N-&XF&2&^U&2Z2"2K2&^&#-X-%-G-'2X2&Z9&!NO +R+ +N&V+&F8@+KH+0N@+N++F+&V&+K++E+"&KJ&AWO #[# #W_#(O8(@TH0W@#W##O#_(T(@#N##T S#4!IK!-M--M-!M!"(Q5(%-E-!OF!2!UO! -Y- -U!]-!-M8-@(RH(0WO ([( (W(#_#O8@(TH(0W@(W((O(#_#(T((N("#T#SA!UO! -Y- -U!]-!-M8-@(RH(0!UO! -Y- -U-!]!-M8-@(RH(0"WO" .[. .W."_".O8.@)TH)0"W@".W..O.)_).T..N.")T) "S5"%$WO$ 0[0 0W0$_$0O80@+TH+0$W@$0W00O0+_+0T00N0"+T+ $S5$%"UO" .Y. .U"].".M8.@)RH)0!UO! !Y! !U!$]$!M8!@!RH!0UO "Y" "U"]+M8+@RH0RO )V) )R)ZRO )V) )R)$Z$'RK'3V33V3'V'")Z5)%)N)'XF'2'^U'3Z3"3K3'^'#)X)%)G)'3X3'Z9'!'WO' 3[3 3W3'_'3O83@0TH00'W@'3W33O30_03T33N3"0T0 'S5'ž%"RK".V..V."V"")Z5)%)N)"XF"2"^U".Z.".K."^"#)X)%)G)'.X."Z9"!'NO' "R" "N±U"‘"V'F8'@'KH'0'N@'"N""F"±U"‘V'K'@"E""K "'J4'"RK".V..V."V"")Z5)%)N)"XF"2"^U".Z.".K."^"#)X)%)G)'.X."Z9"!'NO' 'R' 'N"V'"'F8'@'KH'0'N@''N''F'"V"'K''E'""K"'JA'"NO" .R. .N"V.".F8.@)KH)0"N@".N..F.)V).K..E.")K) "J5"%'NO' 3R3 3N3'V'3F83@.KH.0'N@'3N33F3.V.3K33E3".K. 'J5'%"RK".V..V."V"")Z5)%)N)"XF"2"^U".Z.".K."^"#)X)%)G)'.X."Z9"!'NO' 'R' 'N'"V"'F8'@'KH'0'N@''N''F'"V"'K''E'""K'J"A'$RK$0V00V0$V$"+Z5+%+N+$XF$2$^U$0Z0"0K0$^$#+X+%+G+'0X0$Z9$!UO )Y) )U$])$M8@)RH)0UO )Y) )U$])$M8@)RH)0$WO$ 0[0 0W$_0$0O80@+TH+0$W@$0W00O0+_+0T00N0"+T+ $S5$%IK)M))M)M"$Q5$%)E)OF2UO $Y$ $U$])M8)@RH0"WO" .[. .W."_".O8.@)TH)0"W@".W..O.)_).T..N.")T) "S5"ÿ/MTrk)ñ¹ÉÿJAZ2ÿGeneral MIDI¹ C{ÿDrums¹{]ÿ @¹[*¡`™#d*U*##*7*#&d#d*U'K*#'&#*A*#*U#d*##*7*#*U'U&d#d#'&*#*7*##d*U#*#*7*#'U&d*U#d&'*##*A*#*Z#d#*##U*H*###d'U&d*U#*&'#.K.##d*U#*#*7*##d'K&d*U'*#&#*A*##d*U*##*7*#'U*U#d&d'*&##*7*##d*U*##*7*#*U'U#d&d&#'*#*A*##d*U*##*7#U*###d'U&d*U#'*&#.K.##d*U#*#*6*##d'K&d*U&#'*#*A*##d*U*##*7*#&d#d'U*U'#*&#*7*#*U#d*##*7**K*#d'K&d*U*#'&#*A**d*#d*U*###U*7#*#'U*U#d&d&*#'#.K.#*U#d*##*7*##d&d*U'K#*&'#*A*##d*U*##*7*#*U&d#d'U*&#'#*7*#*U#d*#0700U0070#d0U'U#'0-7--d--7--U-&d&#U.d#.#&p'K'&&A&#U.d.##*U#d#*#*7*#&d*U#d'K*#'&#*Z*#*U#d#*#*7*#*U#d'U&d*'#&#*7*#*U#d#*#*7*##d'K*U&d*#&'#*A**d**U#d#*.7.#U*7#*#*U#d&d'U&'#*#.K.#*U#d#*#*7*#&d'K#d*U&*'##*Z*##d*U#*#*7*#&d'U*U#d&#*'#*7*#*U#d*##*7*##d&d*U'K#*'&#*A*##d*U*###U*7#*#*U&d'U#d*'&##.K.#*U#d*##*7*#'K&d*U#d#*'&#*Z*#*U#d*##*7*#&d#d*U'U#'&*#*7*##d*U*##*7*#'K#d*U&d&'*##*A*##d*U*##*7#U#*#*U'U&d#d'#&*#.K.#*U#d#*#*7*#*U'K#d&d#&*'#*A*##d*U*##*7*#&d*U'U#d&#*'#*H*##d*U#*&-&.d.&#&*U&d'U#d*'#&#*K*&-&&p#d#&#&A&#&p'U#d'#&&7&&p&##d1U*U1#*&#&.U6K6.&-&#d&d'K'#&&7&6U.E.6&-&*U#d*#&&.P6K.6&7&#d'U&d&#'&#&.K6U.6&&*U#d*#&#&6K.U.6&-&#d&d'U&#'&7&6U.E6.&-&#d*U#*&&.P6U6.&7&&d#d'K&'#&#&6K.K6.&&*U#d*#&&6K.U.6&-&&d'U#d#'&&7&6K.Z.6&-&*U#d#*&&._6K.6&7&#d'U&d#'&&#&#U.X6U.6#&&#d&A&##&K&#'K#d#'&U&#&K&#d&U#&&7&&U#U#&&7&'U&d#d#'&&p&#U.d#..A.*U1U#d1#*&#&6K.U6.&-&'K#d&d#'&&7&.E6U6.&-&#d*U#*&&.P6K6.&7&'U&d#d#&'&#&.K6U.6&&*U#d#*&#&6K.U6.&-&'U#d&d&'#&7&6U.E.6&-&*U#d*#&&.P6U.6&7&'K#d&d'&#&#&6K.K6.&&*U#d*#&#&.U6K.6&-&'U&d#d&'#&7&.E6U.6&-&#d*U#*&&.P6U6.&7&#d'K&d&#'&#&.K6K.6&&&A#d&##&K&##d'K'#&U&#&K&&U#d&#&7&#U&U#&&7&'U&d#d#&'&p&#U.d.#.A.*U#d*#*K**7*#'U&d*U#d*&'##.H.#*U#d*#.7.*7*#&d'U*U#d'*#&#*7*##d*U#*#*7*#*U#d'K&d&'#*#*A**d**U#d#*#*7#U*##*U'U#d&d'&*##.K.##d*U#*#*7*##d'U&d*U&'*##.H.##d*U#*#*7*#&d'U#d*U#&'*#*7*#*U#d*##*7*#'K&d#d*U*&'##*A*##d*U*##*7*#*U&d'U#d'*#&#*7*#*Z#d*##*7*#'K#d*U&d#&'*#*A*##d*U#*#*7*##d&d*U'U'#*&#*7*##d*U#*#*7*##d&d'K*U'&*##*A*##d*U*##*7*#*U&d'U#d#*'&#*7*#*U#d#*#*7*#'U*U&d#d&*#'#*A*##d*U#*#*7*#*U#d&d'U*&#'#*7*#&A#d&##&K&##d'K#'&U&#&K&#d&U&#&7&&U#U#&&7&'U#d&d#&'&p&.d#U.#.A.*U#d#*#*7*#'U#d&d*U*#&'#.H.##d*U#*#*7*#'U&d*U#d#&*'#*7*##d*U#*#*7*#'U*U#d&d#'&*#*A*##d*U*###U*7*##'K*U#d&d#&*'#*K*.U.*Z#d*##*7*#*U&d#d'K'&#*#*A*#*U#d*##*7*#'U&d#d*U*&#'#*H*#*U#d*##*6*#*U#d&d'K'#&*#*A*##d*U#*#*7*##d&d*U'U*#'&#*7*##d*U#*#*6*#'K&d*U#d*#'&#*Z*#*U#d*##*7*##d*U'U&d*'#&#*7*#*U#d*##*7*#'K#d*U&d*'&##*A*#*U#d#*#*7#U*##'U&d*U#d&*'##.K.#*U#d#*#*7*#&d'K#d*U*'#&#*A*##d*U*##*7*#'U#d&d*U&*#'#*7*#&A#d&##&K&##d'K'#&U&#&K&&U#d#&&7&&U#U&#&7&&d'U#d&'#&p&.d#U#..A.*U1U#d1*#&#&.U6K.6&-&&d'K#d&'#&7&.E6U.6&-&#d*U*#&&.P6K.6&7&'U#d&d'#&&#&.K6U.6&&#d*U#*&#&.U6K6.&-&'d#d&d#&'&7&.E6U.6&-&*U#d#*&&6K.P6.&7&&d'd#d#'&&#&6U.K.6&&*U#d*#&#&.U6K6.&-&#d&d'd&'#&7&6U.E6.&-&*U#d*#&&.P6K.6&7&#d'd&d'&#&#&.K6U.6&&#d*U#*&#&.U6U.6&-&&d'U#d&#'&7&6K.E.6&-&*U#d*#&&#U6K.P.6#&7&#d'U&d'#&&#&6U&d&6&U&#d*U*#&#&.U6K.6&-&#d'U&d&#'&7&.E6U.6&-&#d*U#*&&6U.P.6&7&'K#d&d#'&&#&.K6K.6&&#d*U#*&#&.U6U6.&-&#d&d'U'&#&7&.E6K.6&-&#d*U*#&&6K.P#U#.6&7&#d&d'U&'#&#&&d6U&6&U&#d*U#*&#&6K.U.6&-&'d#d&d#&'&7&6U.E6.&-&#d*U#*&&.P6K.6&7&&d'd#d'#&&#&6U.K.6&&#d*U#*0700U0070#d0U'U#0'-7--d--7--U-&d&#U.d#.#&p'K&'&A&#U.d.###d*U1U*1#&#&6K.U6.&-&&d'K#d#'&&7&.E6U.6&-&*U#d#*&&.P6K.6&7&&d#d'U#&'&#&.K6U.6&&*U#d#*&#&.U6U.6&-&&d#d'U&'#&7&.E6K.6&-&#d*U#*&&6K.P#U#6.&7&#d'U&d'&#&#&&d6U&6&U&#d*U#*&&6K.U6..Z.'U#d&d&'#&7&6K.Z.6&-&*U#d*#&&._6K6.&7&'U&d#d#&'&#&6U.X#U#6.&&*U#d#*&#&.U6K.6&-&#d'd&d&'#&7&6U.E6.&-&#d*U*#&&.P6K.6&7&'U#d&d#'&&#&6U&d6&&U&*U#d#*&#&6K.U6.&-&#d'd&d'#&&7&.E6U.6&-&#d*U*#&&.P6K.6&7&#d'd&d'#&&#&6U.K6.&&#d*U*#&#&6K.U6.&-&#d&d'd&#'&7&.E6U.6&-&*U#d#*&&6K.P6.&7&'U#d&d'&#&#&6U&d6&&U&#d*U*#&&.U6K.6&-&&d'U#d'&#&7&6K.Z.6&-&#d*U*#&&._6K.6&7&#d'U&d#'&&#&.X6U.6&&*U#d#*&#&6K.U6.&-&'d&d#d&'#&7&6U.E6.&-&#d*U*#&&6K.P6.&7&#d'U&d#&'&#&&d6U&6&U&#d*U*#&#&.U6K.6&-&&d'U#d'&#&7&.E6U6.&-&#d*U*#&&.P6U.6&7&#d'K&d#'&&#&.K6K.6&&*U#d*#&&.U6K.6&-&&d'U#d'&#&7&.Z6K.6&-&*U#d#*&&6K._6.&7&#d'U&d#'&&#&.X#U6U#.6&&#d*U*#&&.U6K.6.Z.'U#d&d&'#&7&6K.Z.6&-&*U#d*#&&._6K6.&7&#d'U&d#'&&#&.X6U6.&&#d*U#*#&d&##d'U#'&K&&d&&K&#d&d#&&7&-U--7--U#d'U#'--7-)U))K)ž*U#d#*#*7*##d&d*U'K'&*##*A*#*U#d#*#*7*##d'U&d*U*'&##*7*##d*Z*##*6*#'K#d*U&d&#*'#*Z*##d*U*##*7*#*U#d'U&d&#'*#*7*##d*U*##*6*##d*U&d'K'*&##*A*#*U#d*##*7*#&d*U'U#d#*'&#*7*#*U#d#*#*7**K**U'K#d&d&'#*#*A*#*U#d*##*7#U#*##d'U*U&d&'*##.K.#*U#d*##*7*#'U&d#d*U*&#'#*A*#*U#d#*#*7*#'U*U#d&d&*#'#*7*##d*U#*#*7*#*U#d&d'K'#&*#*A*#*U#d*###U*7*##*U#d&d'U'#&*#.K.##d*U#*#*7*#*U#d'U&d&#'*#.H.##d*U#*#*7*#*U'U&d#d&#'*#*7*##d*U*#0700U0070'U0U#d0#'-7--d--7--U-&d&#U.d#.#'K&p'&&A&.d#U.##*Z#d*##*6*##d*U'K&d#&*'#*A*##d*U#*#*7*#'U*U#d&d'&*##*7*#*U#d*##*7*#'U*U#d&d&*#'#*A*##d*Z*###U*7#*##d*U&d'U'*&##.K.##d*U#*#*6*#'K*U&d#d#*&'#*A*#*U#d*##*7*#'U#d*U&d&#*'#*7*#*U#d*##*7*##d'U&d*U*'&##*A*##d*U*##*7#U*##&d*U#d'K*'#&#*K*.U.#d*U*##*7*#&d*U'U#d#*'&#.H.#*U#d*##*7*##d*U&d'U'*&##*7*#*U#d*##*7*##d*U'U&d&*'##*A*##d*U*##*7#U*###d'K&d*U'&#*#*K*.U.#d*U#*#*6*#*U#d&d'K#&*'#*A*#*U#d*##*7*#*U'U&d#d#*'&#*7*#&d#d#&&7&&d&&-&'A#d'#070#0K0#d0U#0#0U0#'A-U#d'#--7-)U))7)#d*U1U#*1&#&.U6K6.&-&&d'K#d'#&&7&6U.E6.&-&*U#d#*&&.P6K.6&7&'U&d#d'&#&#&6U.K6.&&*U#d*#&&6K.U.6&-&'U&d#d&#'&7&.Z6K.6&-&*U#d#*&&6K._6.&7&&d'U#d#&'&#&.X6U#U.6#&&*U#d*#&&6K.U.6&-&#d'U&d'#&&7&6K.Z6.&-&#d*U*#&&6K._6.&7&&d#d'U'#&&#&6U#U.X#6.&&*U#d*##&d&##d'U'#&K&&d&&K&&d#d&#&7&-U--7-'U#d-U#'--7-)U))K)*U1U#d*1#&#&.U6K.6&-&&d'K#d'#&&7&.E6U.6&-&*U#d#*&&.P6K.6&7&'U&d#d'&#&#&6U.K6.&&*U#d*#&#&6K.U6.&-&&d'U#d&'#&7&6U.E6.&-&#d*U*#&&.P6U.6&7&'K&d#d&#'&#&6K.K6.&&*U#d*#&&6K.U6.&-&&d'U#d'#&&7&.Z6K.6&-&#d*U#*&&6K._.6&7&&d'U#d&'#&#&.X6U6.&&*U#d*#&-&.d.&#&*U#d'U&d&*#'#*K*&-&#d&p#&#&A&##d&p'U'#&&7&&p&##d1U*U1*#&#&6K.U6.&-&&d'K#d&'#&7&.E6K.6&-&*U#d#*&&.P6K.6&7&#d&d'U&#'&#&6K.K6.&&*U#d#*&#&.U6d.6&-&#d'd&d#'&&7&6d.E6.&-&#d*U#*#6d&p6&#'d#d&p&'#&d&6d6ÿ/MTrk ²ÂZÿJAZ2ÿPianoÿGeneral MIDI²p ,{[Oÿ @²]@¡`’B-E@12F‚+LE@59P‚\LH9L'<9MK92 E BL+$;E1B1>ƒ$70>XB#BXGBE+7>; >E1=B12$ƒ$90>XB#BXIBE9>2= B%E>-;1+F‚+GE;57P‚\GH7G'<7MK7+ E B>G2I@9E4BE‚g@4@3B‚ZBEE'E.025E B@ ;E1>B1+$ƒ$70>XB#BXGBE+7;> =1>-B%E2F‚+IE=59P‚\IHI'9<9MK92 E >BI>-B%E;1+F‚+GE;57P‚\GH7G'<7MK7+ E >BGBV;X>T(Fƒ^C@‚#>B;+;;>]4W CI(4;>@>>>9>-FƒX>9@-@E=J-FƒW@-=;X>TBV(Fƒ^C@‚#>B;+;;>]4W CI(4;>>>9>@>-FƒX@>9-=X@T-FƒW@=-E@1B-2F‚+LE@59P‚\LHL'9<9MK92 E BL;9+IB4>EE)‚f;4;3>‚Z>EE'E.0+5E >;B=92IB4>EE)‚f=4=3>‚Z>EE'E.025E =>BB%>-E;1+F‚+GE;57P‚\GH7G'<7MK7+ E >BGE1B@2$ƒ$9E1+$ƒ$70>XB#BXGBE7;+> EB%=1>-2F‚+IE=59P‚\IH9I'<9MK92 E B>IE1>+$;B1ƒ$70>XB#BXGBE>+7; BE;J>J(F†;B>%4`;J(B]q4B;>J@E-FƒW-@>@E=J-FƒW-@=BE>J;J(F†;B>%B]4`(;Jq;4B9>@>>>-FƒX9-@>@E=J-FƒW-@=>JAE.F†>A).A]5`>JqA5>C>?>:>>>0F†;:?C>c0!AT>X.FƒWA.>9><>A>-FƒX9-<A:>7>A>+FƒX7+:AAJFE)FgAF)EEAJ)Fg)AE>>:>5>3F†;>:5c3!AJEE'F†AE)'9`AJE]qA9Ež>-<1A.F‚+HE<55P‚\HH5H'<5MK5. A >H'I79>4:EA)‚f7473:‚Z:EA'A.0'5A :7>A1>1:.$9ƒ$5#>XE>A:9.5 A>%71:-'F‚+CE753P‚\CH3C'<3MK3' A :>C<1A>-.F‚+HE<55P‚\HH5H'<5MK5. A >H'I79>4:EA)‚f7473:‚Z:EA'A.0'5A 7:>.$A1:9>1ƒ$5#>XEA>9:5. 7A1:'$>1ƒ$3#>XC>A'37: >>:>C>?>0F†;>?:Cc0!AJFE)FƒWAF)EEAJ)FƒW)EA?T>XCV0Fƒ^F@‚#?C>+7W?]>; FI07>?:><>A>5FƒX<5:AAXET)FƒWE)AP.Fƒ[<>5..F5PP‚>5<>P5P.F5< F5F"XF5F"5><"Z5><" ²@ÿ/MTrk ëµÅZÿJAZ2ÿGuitarÿGeneral MIDIµk j]{[s@ÿ @ƒb•6.@.2F9.ƒ>2#2F12E@.+Fƒ>+#+F1E@+B;EEG7 9.B.2F@.29B@E9@9@e2E9>;.>.+FB.E.2;>BEE92#2F12E@@9@e2E9>+FE.B.>.;.ƒ>+#+F1+E@EG7 2F2E9.;.ƒ>+#+F1+E@G7E (FC.B.>.;.2CB9;>B.-F@.ƒ>->@9 -F=.@.9.ƒ>-=@9 ;.B.>.(FC.2B>C;B9.9.@.2>@9@92#2F12E@.+FE.;.ƒ>+#+F1E@+;BEG7 2F2E9.E.ƒ>+#+F1E@+;7EG2F3E9.B.2BE;>E92#2F12E@.B.;.2CB>;B9.9.2@9>@9.B.ƒ>(#(F1(B@CB;4BC -F2@9.:.ƒ>0#0F10C@7CF.F3A9'#'F1'E@.C.:.2:AC>A9..FE.H.A.2AHE>A9'#'F1'C@.'FC.A.2A:>CA9.9.ƒ>.#.F1.A@<9A5EA 'F2A9.:.ƒ>'#'F1'A@C:ACA3 .F2A9.:.C.ƒ>0#0F1C@0?7FC )F2F9US9SQ'Q UUQ QLL QQLLQ!Q L LƒF³@2@2“QYVSQUGVQKUUKQQ;UQU@UQ4QU2UQ1Q L%LQ6Q L'LQ1Q L #L‚O³@'“QZ³@“VRQUE VQJU UMQQ>UQUEQ6UQU:UQ5QSBSQ6QS:SQ3QL*Q9LQL(LQ3QL!L>J<"LNJJ6LJE4EJ3JE%EJ.J E"EJ$J L$L J J…=³@2@_“QiVPQUFVUQDQUJQ>UQUGUQ9 QUGUQ;QSCSQ;QL6LQ>Q L'LQ<Q L#L‚3³@ @“+/>i³@*“2M³@“9>29@9@BC?L9QLLV[QUCVUVUUFVQDUQUPQFUQL8LQDQ L0J:LBJ L=LJ1JE0EJ5J E$E B(BE)EB!B@@³@“+;³@“2:+2949;1;L>QO LURQQCUUPQQCUQL5LQ=Q L)J5LJL.LJ,J E%EJ+J E E;‚F³@,“CT(1³@“/*(/727CBC;*BCB>0CGc ; >4:GC<>0CGG4>;%G ;JS>7JJY >4<JNN4N;';NM>*NL<>L>*>L6>#L>J$JJEJ ³@“J_-B³@ “4<- JID4 II\919 IGF!@(GGD&9GE(E(E#@`9EƒO³@%“(;CY³@“/9(C /B?BCM7=CGT7 ;AGGc >E;GNKEHE;6N>NNEJ;E>9NC6L9 > CL;' C<LA ;L C41B/J1BJ4;"B+J.;JB‚^³@ “-7Ge ³@“4=-4;+ GGT;;5 G;ECEE= Ee->³@@“4:-49/9 ;.;$='=‚-³@ž“2J³@“9629>:>@@8LD@V\UHV UUSEBULQLQUZ E>3UQGQULUQ=QL7> QHLQ L,LJ3J L: E3 LEJ1J E+E>'>L³@“+?³@“2;+2999;B;LEQKLUWQ ;>>UQGVOQU>VUQ>Q L)>L Q.Q L,LJ1JL#LJ(J E$EJ$J E E‚³@!“&7³@“&-,-2524E;@H4EL@ JXEID JEDIIJEE;IE@?!EJ@E@:>9@>@7 20@>0>@=9&@>1>29E3 9E9>>8³@“+;³@“28+27.79@9VUKUQ5QSG>>+SQ:Q L0>LJ3>$JE% E >‚/@-@BFBCLEWCE(:G\³@@“(/4/ 76GEE7;$EC9>)C C65C >;.³@“N\ET4C ³@“;6E>B N;GPOO4O>;(G;>A NJEC>;2NE ;4:CCLFL>3C>;:4;B@JA;)JB;G9>3G>!-:>9³@“G>³@“G>47EG)EEG4-E E=9"E @+@9@D9.@9>X4; > 4 =>==8-:³@@“49- =>:4>@5@9) 9;04!; 4=#=O³@#“(26R³@2“// 7G6/,( /'/>G76/&/>BJ B;-;C: ; C; B&B>-> ;;Z4,;,>B@I>BQ4@BCP ; EXCGREILGJPILLJNLLOMNQJOSJQSUDUVJXEV³@“ZKX ³@/“-8 X>Z*- 4CX4]W ;-]; Q1:@I@$@2@;/Q ;;-;X;92X 9 U/UQI42QS6SL# 4Lb³@/“.6³@“52.5:2:AT<: <FW>HYF:':JFH:%: MCJ5(M5K<K:!: J2AJ F0FA&:- A<;:>I<AP>FMAFHTHJI JKEKMNOYMRQORTWTVRV$;VT³@@ “+7$+3?3V RM7BO8RORJ 7R 7-J>7KCJ>1KH1H>O/O?&F%FJ-? C(JCFF J#J‚w³@“.9Hg³@“5>.:,5HFJ ::%:HIF0HJ;-J A/A.³@“-DJ_³@“5B 5 -5@J5H\9;MWH<8MA89<<,YA< A 'AC2CEPE³@“+BFS³@“3./>>F6:->?F?:?X +3AJ?CHACE<³@“)0ABE³@“A01:/53::3>³@“94:4³@“0);5!91>K>³@“'8>Y³@"“37'>5A]:/:'35 :‚a?=FC JJMUR< VARVY.JYR-FR?M@³@ “QQTP ³@“TQ ?/"Q@?H;QH?0!?M7M#?* ?H/E1HE ?*? A&E&IE AƒP³@„<@M“e(e c4c bXcWbcbWb^9^Y,Y^5^Y(Y^*^ YY ^^ Y YlT*TVATRVVSTTDVTV0VT+TV$VTT‚mF.HCFJIHKNJMDKR>MRY/"T, ³@@2“TYƒ^GQ^]:;M-MY)];M YMV#V†M<R?)FFMRTSOJ;TFEOF R;M> RM)F1 FO0J08O J³@“MM³@ “.'M56.5:6: A*A/A6AH?HRX A@RQZAQ McACMOSAOJ<A:JM7AM H7HM\HLMHM\M H;H F0:5>2:>A6FAF7!<,F <H3A5HAJ+6³@“'>³@ “..'J. 5<570J7CJ7JM3MRSRQT:3Q MM:MH>HM[MH<H F3FH@HF6FHCHJ9JF/FA4?@?AMMMA-AA:³@“./³@ “57.5:-:<' Ar<$A.FWAF EU58EA:A>4>5CM: >-C>A7 : A525.-5>.:H5O5B > 5AJA:, C5:565M@C"M³@“'3JG³@ “.2'.5:J5HI977 H7F<#F:&A-:A?'? :C"Cq³@“:2³@“A6AC@C FMF:HMHJNJKMKMQM ORORMRTT³@“TV[³@“"? )2") 2D V‚ 2d³@“.<Tl³@ “5A.5;"MKRYQ>YMA@A M9VPVMM:³@“3:TGM³@“T :-3 R4J.JR?0"O,H&O H?MA1A HU :JPHJHOH HW:0 HFF ::' F : FF: F : A/:%A: ?;F=:.:?>9F>?<??S ³@“.;³@“?>>51><<5 . 5/<5>D535 >:-5-5:9.95)5r7,5579:9:E:O< ?S> <@?>H<?K>5- ?AE 5CJAENC FNE CA:3F :EPCAHECFA EICFJE FHL HKR:7KHFJIHKNJKMHOKM QFORMQRTK: TVJWGV WYE [LY ]R³@“[^@3G]]F³@“^F[Y]3:63b_[b:?7 ?THT^I^ VJ.9VTJT [W['F.RC YRR'.>YMIM.VZ7GVM@M R]7R :@ HHHO^:O7S!FN7MXF+;MK]³@“K$M+JT³@ “+<$+2GJFP 23EFA<JY3AJ7B?3?HS7 3;H>7> >G3>7>?S7? ?V0B?>>76>07?>72?7<271 <7>W>0D?S?CICCDC HWHHc7F0 H7JSJJRJKVK ³@“KQ)J³@“0C )05H5K MT:7A9AM F:: FFV<6FA3A MG<MMX<> MA5H>³@“I= HJFI J5=HN³@“<3<5 A<F@5&F<-H<E3E<9 <5: 5:³@ “?S0;>39³@“7> 3 ? 0FZ77=F<>7>9< >>B>$7$ <1<:$7Y<VIYTUVRNTROFOKCJNKJHK HFHFCKCAC$A?E ? >,< <><&<:3:7:³@“0/ 759³@ “57@7:80<=:>L<?O>?AHCHAFNC³@“);³@ “0= )0FHGH<4A,HH<MYH<9MH6AH<F1F<0³@ “E654³@ “Eg<5³@,@“TWVATVY9YR?R M1M J=JH/H FEFA7A >0><(< :%:$:-<2:<:#³@“.0 <A#„:". A<ÿ/MTrkK°ÿJAZ2ÿ Float on byÿ @ÿGeneral MIDIÿ/simutrans-124.3/simutrans/music/26-Tantalizingly-Unusual.mid000066400000000000000000001164121474050137200241300ustar00rootroot00000000000000MThdxMTrk{ÿCopyright (C) 2007 shunterð~ ÷ÿJAZ2ÿ~j    ÿ 2006.10.06ÿTantalizingly Unusualÿ~j  ÿ~j 1  ÿ~j   ÿ~j  ÿÿ~j  ÿVj   ÿj#ÿjjÿXÿQz#ÿYÿ/MTrk á± Á"ÿJAZ2± ÿGeneral MIDIÿBass±|@{][2ÿ @H‡@‘!W!\!B![!D'!Ha!Zq!(X(#!Z[!!W,!$C$"!S!!W!!X! C!C!!A!!K'!!W!a![`![0 X,!P!"!T!!X!!W!\!B![!D'!Ha!Zq!(X(#!Z[!!W,!C"!S!!W!![! !@!!F!!D!!H'!!L!a!^`!(^0( ![,!G"!W!([(!Z! !?!!E!!C!!G'!Ka!]`!![!#!][!!Z,!F"V!Z!!Y! !>!!D!!B!!L'!Xa!\`!(\0( !Y,!$E$"!U!!Y!![! !@!!F!!D!!H'!La!^!!^*!N![,!G"W![!!W!\!B!!@!!D'!Ha!Z!W(Z-(!W,!["!S!!W!&]$&$j<$&S4&$K<&V$/&$j;$&P&"&a`&&Y<&!_)! !Y/! !\*!F!c4!!D$!TM7!gP!(!g^!_4h<K$ X9b4<`)Ob>G !n!CN !`$!JA!Y/!]4!dn! $nr$&b4&$k<&N$$& $[9$&T&&$[<&Q$/&I&^,&L!h!Ca !d!Y*!`!G N!]V!"!mS!%)d$)$m$(G()P))G(\4(&e<(R&$(O(U((P!X'! Q<!R.!B!`/!i:!Rk! !`u!!\1!\<%<&< <6 <<'<$< <6< <7">[>:>R757(7%7 7=77'7)7%7 7E77%7)7*77577.7)7%7&7.7)7.7 7=77*7 7=77% 775775)7O7E&7R9?9,979,<0<< <<(< <( <<6<*<0<,<6<<-<<%< <# <767)7'7 7 77 7)7#77M7;=;Y;9,;L7J7 73 77*77( 77377/77*7 7* 77377/ 77(7 7,77/7 7/77(77:77B7 7377*7 7(77,7 7/77*7 7J7 7$7`7:&7R797,717,9*99 99"9 9" 9909*9*9,9099'9909 9- 97M 7/717,7)7,797-7H7h7H7h9R99) 99 99# 99# 99 99'99' 99) 99 99! 99 99# 99 99% 99/ 99899H99M 99;99;99/ 99;99; 99H#99C9.9M9b757(7%7 7=77'7)7%7 7E77%7)7*77577.7)7%7&7.7)7.7 7=77*7 7=77% 775775)7O7E&7R7>7%7&7 76 77/7&7&7 7677>7'7$7 767 7/7,7&7 767767$7&7 7>77/7%7&77+ 7 97"9[9:9R797,717,9*99 99"9 9" 9909*9*9,9099'9909 9- 97M 7/717,7)7,797-7H7h7H7h7I 77)77 77 77.77'7*7.77) 77' 77)7)7.7&7A7 9@9949 9299:9&9D9(94&9R9:59C757(7%7 7=77'7)7%7 7E77%7)7*77577.7)7%7&7.7)7.7 7=77*7 7=77% 775775)7O7E&7R9E9#9& 99 9999 99 99 9959*989,9E 99(99( 99(9929+9@9,9J995 99(99&99,9(989-9T9*90 9/>E>#>& >> >>>> >> >> >>5>*>8>,>E >>(>>( >>(>>2>+>@>,>J>>5 >>(>>&>>,>(>8>->T>*>E >/9E9#9& 99 9999 99 99 9959*989,9E 99(99( 99(9929+9@9,9J995 99(99&99,9(989-9T9*90 9/9P 99099 99 99599.9*95990 99. 9909)959&767)7'7 7 77 7)7#77M7;=;Y;9,;L7I 77)77 77 77.77'7*7.77) 77' 77)7)7.7&7A7 9@9949 9299:9&9D9(94&9R9:59C@>>4> >2>>:>&>D>(>4&>R>:5>C7D7*77,747 7477!77 77,7*7!7*7,7 7<77%77477<7+7!7)747 74 77477< 77K7^7<7`7%7&7 76 77/7&7&7 7677>7'7$7 767 7/7,7&7 767767$7&7 7>77/7%7&77+ 7 97"9[9:9R@Y@@Y@ @V@'@V@%@>>4> >2>>:>&>D>(>4&>R>:5>C9R99) 99 99# 99# 99 99'99' 99) 99 99! 99 99# 99 99% 99/ 99899H99M 99;99;99/ 99;99; 99H#99C9.9M9b<\<<3 <<' <<- <<- <<* <<1<<1 <<3 <<( <<+ <<# <<- <<& << <<' <767 737 7'7 7 77 7 7. 77#77M7;=;Y;9,;L7>7%7&7 76 77/7&7&7 7677>7'7$7 767 7/7,7&7 767767$7&7 7>77/7%7&77+ 7 97"9[9:9R7%7&7 76 77/7&7&7 7677>7'7$7 767 7/7,77 7%7 767)7'7 7 77 7)7#77M79=9Y99,9L<_*<@[@,@X@*@c@'@[@*959(959-9G9(9h&99K9 9;97C7"9F9‚²@ÿ/MTrk‹¶ Æ]ÿJAZ2¶VÿGeneral MIDI¶ 0ÿStringsÿ @¶{[7]@ƒ`–C*@<E#‡>CE@@<C*E#‡>@CE@<E#C*‡>C@E@<C*E#‡>CE@C*E#@<‡>EC@@<C*E#‡>C@EE#C*@<‡>E@CC*@<E#‡>@ECEGJ.H5‡>EJHC5@GE.‡>@ECCGE5H.ƒ`H@GECC5G.ƒ`E.C5CG@@G‡>E@CEGJ.H5‡>HEJE.@GC5‡>E@CH.CGE5ƒ`G.C5@GEHCƒ`@GCE.C5@G‡>C@EE.C5@G‡>@EC@GC5E.‡>EC@E.@GC5‡>EC@C5@GE.‡>@ECC5@GE.‡>@CEE.@GC5‡>CE@E.C5@G‡>E@CE.@GC5‡>@CEH5EGJ.‡>HJEC5@GE.‡>@CEH.CGE5ƒ`EC5CHG.@Gƒ`@G@CGC5E.‡>CE@J.H5EG‡>HJEE.C5@G‡>@CEH.CGE5ƒ`@GEHCG.C5ƒ`GC@GE.@C5‡>@ECE#C*@<‡>@CEE#@<C*‡>EC@@<E#C*‡>EC@@<C*E#‡>C@EC*@<E#‡>E@CE#C*@<‡>E@CE#C*@<‡>C@EC*E#@<‡>EC@EGJ.H5‡>HJE@GE.C5‡>@CECGE5H.ƒ`CEHC5@GG.ƒ`E.@GG@CC5‡>@CEJ.EGH5‡>HJEE.C5@G‡>@CEH.E5CGƒ`@GC5EG.HCƒ`CGE.@C5@Gƒ`E.C5@GEC@ƒ`CE@…C;H0‚,HC¶@ÿ/MTrk¥³ ÃkÿJAZ2ÿGeneral MIDIÿMelody³s T{]ÿ @³[…“E,BH\EOH.HHpHE(dE@+Z@ @@>(-@$>9@<"ƒ <2E^=GPE.GHXH!H6 H J* H9JHG9‚G0E_QECIQC@B„C@9B>%><(B9 <‚eE[ 9%ECK*CEYxE@D9@>:;>@?„ @EE+;EGX*GH`9HJM7JGP@GHA4HE;$EC19CE(ƒ!E@1;@>Ht><.r9/<…B9·8E,BH\EOH.HHpE(HdE@+Z@ @@>(-@$>9@<"ƒ <2E^=GPE.GHXH!H6 H J* H9JHG9‚G0E_QCIEQC@B„C@9B>%><(B9 <‚eE[ 9%ECK*CEYx@DE9@>:;>@?„ @EE+;EGX*GH`9HJM7JGP@GHA4HE;$EC19CE(ƒ!@1E;@>Ht><.r<9/…B9ÿ/MTrk=´ ÄhÿJAZ2´ HQÿSoloist´{[]ÿ @@ÿGeneral MIDIþk”CQCDZD JvJER1EGH EDHGYEGLeJaLGWJHSGHMvM LzLHHHJLJOlOQeQOnL\OLHJJmHJKaKLXL JzHTJHEAJrEJHbHGZGHVH LmL OqLNOLHHG^G%OO Q.Op Q LROL HyHGEGHkH L^LO{O!OO9LvL%HH G[GEKE GfGHiH J`J-HHGkG EgE@K@?u?>J> X@>@l>[@d><}<+@r@E`EGxGHgG_HGEOEHeQJtHJGk\GHzH+EzEC_C@e@>J!@R>@CvC!E)E0@eAU@ @S A@>_>`=>b>@D @>;@;<\<>Q>@L@ CzC EaEGjGHwH IrI JyJIdIHqH@FCU@ CGuGF@FD@DEyECbC@F@AhAEdEHdH JpJLrLJ[JJhJLqLJHJ LkL LzJ>LJLcLMx!LTML OxOMkMLfL HOHEVEC4C Hx C=HCEOE CYC>-@m>@<><>g> 7%7 <^<747>D>@zAT@A@[<\@74<7>Z<7,7<_<<>f>B;E;>L>C}CAiA@CAp@@SA@>G0>q>;J@k;!>T@> CzCE!E GxEwGE%@\@!CCEE@l@>s >!C}C'@m@ z>9T99S>9

{> 9P9y9W>9i>R!>:~>{> ;q> ?z@^?@?r@S?@ 9X9?z@[?@ ?f? NL>,>YX>…o@NM@+@YY@…nCHQC'C\\C…l@\H@0@`8@ÂANMA+AYYA…o@NM@+@YY@…o@HP@(@\[@…m@\G@1@`7@†ANMA+AYYA…o@L<@<@Y$@†$Cb>C:C\EC†@XP@(@][@…D@F‚@ÿ/MTrk§¼ ÌÿJAZ2¼]ÿGeneral MIDI¼ rÿEcho 3ÿ  ¼[(ÿ @¼{¿`œ`5>>$>>. >>B->>= >>=>>b>>:>\E>2 < <`->>1>>. >>B >>; >>= >>=>>HQ>'>\\><\ <<7 <<% <<$ < < <<:`5>>$>>. >>B->>= >>=>>HR>&>\]><\ <<7 <<% <<$ < < <` >>6 >>$>>. >>B >>; >>= >>=>>HR>&>\]> < <`5>>$>>. >>B->>= >>=>>HQ>'>\\>L&>>3 >>0 >>8 >>0>>3 >>0 >>L>>6 >>* >>: >>4 >>2 >>2>>,>>4->>? >>1 >>D >>7>>> >>F>>NO>)>Y[><\ <<7 <<% <<$ <<:7:7Y&7S9Y9#9* 99" 99;99 99'9 9)99:9 9- 99(99-9909 9-9 9.9 979}7HR7&7\]77\ 77/ 77! 77770 77$7 777% 77P77,77$77) 77077& 77"77) 77B 77777,77, 77;77) 771 77977L>7:7Y&7†"7NO7)7Y[77Y7#7* 77" 77;77 77'7 7)77:7 7- 77(77-7707 7-7 7.7 7777H7 7-77- 772 77F777 771 77;7 7NN7*7VE7†7NP7(7Y\77\ 77/ 77! 77770 77$7 777% 77P77,77$77) 77077& 77"77) 77B 77777,77, 77;77) 771 7797 7L?797Y'7†!7\J7.7`:7†7\J7.7`:7†7\J7.7`:7@7\ 77/ 77! 77770 77$7 777% 77P77,77$77) 77077& 77"77) 77B 77777,77, 77;77) 771 77977L>7:7Y&7† 9\K9-9`;9† 7\K7-7`;7† ;HT;$;\_;7\ 77/ 77! 77770 77$7 777% 77P77,77$77) 77077& 77"77) 77B 77777,77, 77;77) 771 77977L>7:7Y&7†"5NO5)5Y[5…k7NQ7'7Y]79Y9#9* 99" 99;99 99'9 9)99:9 9- 99(99-9909 9-9 9.9 979{;HT;$;\_;…i7\K7-7`;7Â9NP9(9Y\9…m7NO7)7Y[79Y9#9* 99" 99;99 99'9 9)99:9 9- 99(99-9909 9-9 9.9 979}7HR7&7\]7…i9\K9-9`;9† 9NQ9'9Y]97\ 77/ 77! 77770 77$7 777% 77P77,77$77) 77077& 77"77) 77B 77777,77, 77;77) 771 7797 7L?797Y'7S9\ 99/ 99! 99990 99$9 999% 99P99,99$99) 99099& 99"99) 9‚;b@;8;\G;27Y7#7* 77" 77;77 77'7 7)77:7 7- 77(77-7707 7-7 7.7 777}7XR7&7]]77F7%7>7'787)7?7(7A7)717,7?7*7>7,7N7)7D7,7N7:7F‚7ÿ/MTrkg¾ ÎÿJAZ2¾zÿGeneral MIDIÿEcho 5ÿ ÿ @¾ {[(]Å-ž2BP2(2IG2†4NJ4.4Q:4†4SA474NH4†4BP4(4K\4,4@?494K'4† 4=T4$4N_4*4BP4(4K\4…l4BO4)4IF4†4BQ4'4K]4…k4@@484K(4† 4NK4-4Q;4† 4NK4-4Q;4† 4NK4-4Q;4¤4@?494K'4†!2BP2(2K\2Ø+2BQ2'2K]2+4=T4$4N_4”i4@@484K(4†!4SA474NH4†4JS4%4O^4ÿ/MTrk¿ ÏÿJAZ2¿{ÿGeneral MIDI¿vÿEcho 5ÿ ¿ ÿ @¿[(]ÌmŸ-IK---L;-† /NB/6/II/…->Q-'-G]-+-<@-8-G(-`-<@-8-G(-† ->Q-'-G]-…k->P-(-DG-«A-<@-8-G(-œ`-<@-8-G(-† ->Q-'-G]-ßk->Q-'-G]-£k/NB/6/II/…-FT-$-J_-…/-9‚*-ÿ/MTrk9°ÿJAZ2ÿTantalizingly Unusualÿ/simutrans-124.3/simutrans/music/27-March-Winds.mid000066400000000000000000001353421474050137200217650ustar00rootroot00000000000000MThd ÀMTrkkÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿ March WindsÿAÿQ 5ÿX`ÿ/MTrkU°ed ÀÿJAZ2°]ÿGuitarÿY° @[lÎà@°&\_„@HK`àE K P LDà@HƒL`JK`HKJJKHHKJ0HEK`@K-KE`@EK`HKEHJKJLKH`-L2KJKƒ2K2J`JK`HKJHJKJHK0HEK`2K>KE2`AK2>`AEKHGKGHKE`GK(KHƒ(KG(HCKCEK`@KE`@K<0àE0@Dà@>`-K>K@-‚ 9K>KAKX>9->(KA`(>K`>AKHDKDEKA`(KDKE`DGK`@KG`>K@`(`4K0`K8K`8>(c`(-K05K04K5 45K 4K53K404K304K`>AK`EKA0HGKGHKEE`H2(KGKƒG((KHDKDEK`@KE`K<0àE0@D>à@`>K2K@‚ 9K>KAK`>2>A9)K`2K`5K20àEKP@59D`3K9)K@@K>>K@(K8KàEKP>(8à@K<;K9K;98K85K54K2K40K20/K/-K‚ 9K-`à@‰9K2K à@ B @EK> àB @ EàBEK à@ B EKEà@ B @ 2EàB2K>Kà@ @ B >à@AK àB @ AEKàB @ B HKEà@ BEK@PBLD-Kà@@2H à@ B @EK àB @ BE à@ B @ B @ (KàBL-à@`GKDK`GDGKDK`GKGDKD`DK(DG@K(K à@ B Dà@DK@GK àB @ DKGKàBGD à@ B DGGKà@DK àB @ @Kà@(KDK(àBDG à@ B @GK@DKD àB @ BDKGKDG à@ BGKDKGDGGKJKà@D àB @ JG(à@B-K@KEKHK à@ B @ B @ B @ B @ B @E-KH@ àB @ BEK à@ B @HKE àB @ BHLK à@ B @LJK2K-- à@B@ B JEKà@ B @ BEHK à@ B HLKà@ B @ L2àB@JKJLK2KLJK0JHK`EKH0à;50@AKE`-KA@K à@2àB @ B @ B @ B @ B @ -@àB@-K`HK`EKH`ADE`-K@KA- à@ B HK@à@ B @ EKHàB @ B @Kà@E àB @ B@>K@(K- à@ B à@ B @ <GKàB @ B @EKG àB @ -Kà@B(EKE à@ B @9K àB @ B9 à@ B @ B @ -àB @ B @ B @ BEà@’^À.bAK0EKA0DKE0EKD0AKE0EKA0EDK0EKD0AKE0AEK0DKE0DEK0E@K0@EK0EDK0DEK0E@K0EK@0DKE0DEK0@KE0@EK0EDK0DEK0E>K0>EK0EDK0DEK0>KE0>EK0EDK0EKD0>KE0>EK0EDK0DEK0EK0>AK0@KA0@>K0>K00;K<0>K;0>K>@K@AKA@K@AKDKADEKEGKHKGJDHGKJ0GHK0HKHHJDHDJHGK0GHK GKà@HàAB DEf@@GGKFàA BC D EGKà@G@HKG@HJK@Jà@GKàACDEHKà@G0à@GKHàACDEGGKà@0EKG0EGK0GGK`à@GGKàA BCD E@DCBA@4Gà@EK à@ B @ B @ B @ B @@E`9K K@@K>@à@>KàBCDFIJK,JIFDCB@2BDEFIK.@?K>@àK>K?CK>à@@KC>K@EK>à@@KE>K@>à@FK@F>KàK@KHKà@>&àIFDB@ACEGJK JIGFDCA@@@H>KàBDFIK&IFDB@ >>Kà@ @ B @ B @ @B @ B @ B>Kà@>&àE @K>à@0@@K0?D@0?K?0?@K0@K@0@K<0>K>0;K>0;K;0D<;K>K< à; >à@@K@K>@KàE@AD@A>K>@KAK@ àE @ACD@KC@AKCKA àE @EDCEAKCKACEK àE EGDà@0GHKGKHà@AB CDE`D BA@@GHK0à@HGKàCE @GHK J2H à@JGKàBDE@HKG JKH LKJ MDL MLD LJD HKJ HLKLJKJHK GKH GEK NKà@EàABCDEFGHI JK LM NO Pt@N@K@LK LMK JKM JMK HKM HMK GKM GMK MEK MKE MDKEKDGKEGHKHLKLKDKHKHGKGKDHKKHGKà@CE HKGà@@GKHàCE Gà@HKHGKà@CE GHKà@HJK0JHK à@ B @ B @ B @92àB9<2à@Hà@<@K DK@DCDCAD@DACK@AKC@KA?K@@K?AK@@DA9K@7D99D78D97D8>K7;K>K>@K@AD@DA@>K>K2K`AK>`AEK0HGKGEEHK`GKH2(Kƒ(K(GHDKDEK`E@K`K0àE0>@Dà@`>K@2K‚ AK>K9K`29A)K>>`2K`5K20àEKP@9D5`)93KK@K>8K@>K(KàEKP8`9K-K<098;E>AeE1>8A8;>EAuA1E3>1kE0A%ED+>EA6>8E2:±@‘E>AeE1>8A8±@;‘>EAuA1>1E3kE0A%ED+>E%G8>2D3@(H±@‘G@>Du@5>6±@‘GCD3{>GD@%D8>5@8G)KDG@>uG6>8D9@9:±@‘>@GDG8±@‘D3>2@(ID>G@u>6D3GC@5{G>D@%@8D8>5G)J±@‘D>@Gu>8G6D9@9±@;‘@G>DuL2E8H6;LEHeE8@1H8;@EHuE1H1@3j±@‘@0H%±@‘@D+E@%@8E(H3IE@HuH3@CE6{E@H%@)H8E8KH@EuE8H9L6:±@‘ELH@8±@‘H3E(I@HEu@CE6H3{@EH%E8@)H8K@HEuH9L6E8:±@‘ELHuE2A6>8±@;‘E>Ae>8E1A8;>EAuE3>1A1kE0A%ED+>E>8E2A6:±@‘E>Ae±@‘E1>8A8;E>AuA1>1E3kE0A%ED+>E%G8>2@(D3H±@‘G@>DuD3±@‘@5GC>6{G@D>%@8D8>5G)KG>D@uD9@9>8G6:±@‘G>@D±@‘G8@(D3>2ID@>GuGCD3@5>6{@D>G%D8>5G)@8J±@‘@G>DuG6±@‘D9>8@9;@G>D@HHCE8E@EHiHC@EEGwE@H)EH@:HI±@‘E@HI@H±@‘@)HBEN9<‚v±J<CHK]AÁ±@x "[AŒ‘Hƒ9EŒe±@‘>0E*A.<AeE*A0-:±@‘><EAu±@‘A*E+>*kE0A%E:+>E%G/D+@">*I@DG>u@-G9D+>.z±@‘>@GD%G#@/D0>-±@K‘>@GDu>/G.@0D0;@G>DuL*H.E/:±@‘LEHe@*H0E/±@;‘E@HuG+@*D*kG0D%G:+@G%@/E"H+IH@Eu@9E.H+z±@‘EH@%@#E/H0±@K‘EH@uE/H0L.;ELHuE/L*H.;LEHe@*E/H0:±@‘E@Hu@+E*H*±@k‘@0H%@:+E@%@/H+E"IHE@u@9E.H+{HE@%H0@#E/J±@‘H@EuL.±@‘H0E/;LEHuE*A.>0E<AeE*-A0:±@‘E><AuE+±@‘>*A*kE0A%E:+>E%@/H+E"I@HEuE.@9H+{HE@%E/H0@#J±@‘E@HuE/H0±@‘L.;ELHuE*A.0;>E<AeA0E*-:±@‘><EAuE+A*±@‘>*kE0A%E:+>E%E/>"A+IE>AuE9A+>.{>EA%E#A0>/J±@‘>AEuA0>/±@‘E.;E>AuL*H.E/;LEHe@*E/H0;E@HuE*H*@+j±@‘@0H%@:±@+‘E@)@=E0H9E@HEiH9@:E2±@‘C$G-IGC>uG-><C0{CG>%C4>'G5KGC>uG6J3C4:±@‘JCG±@‘>2C$G-IGC>uG-><C0{>GC%C/>#G0KGC>uC/J.G0:±@‘JCGuE.A/±@‘H*;HAEeE0<*A/;A<Eu<+A*E*k<0E%<:+A<%G2@$D.H±@‘@GDu±@‘@2D.G0{G@D%G(>2@5D6KGuG5 > @GD%@2E$H.H±@‘H@EuH.E2±@‘L0{HEL?±x@CHK]AJ<[A "Áƒ‘E/±@‘A+>"I>AEu>.A+E9{E>A%A0>/E#J±@‘E>Au±@‘E.>/A0;>EAuD.G*@/;G@DeG*@/D0;G@DuG+D*@*j±@‘G0D%G:±@+‘@G%G/D+@"I@GDu@.D+G9{DG@%D0>-G#@/J±@‘>DG@u>/@0D0G.±@;‘@G>D@=H9E0E@HEiE<@:H9wH@E)E=H=@1±@‘HE@I±@‘@=@%>/C"G+IGC>u>9G+C.{C>G%A0>/E#KEA>u>/E.A0:±@‘E>AuE.±@‘H*A/;HAEeE0A/<*;A<EuA*<+E*k<0E%<:+A<%G0@"D,H±@‘DG@u@/D,±@‘G-{G@D%G$@0>-D0KGuG0 > @DG%@0E"H,H±@‘EH@uH,±@‘E/L-{LHE%E0@$H0K@u@0+EH@)@@E2HE?v±@‘E@H)±@‘HDED@6H@EI@D@)ES9@HG‚vÁ±@HK "C[A]AxJ<ƒ@‘@4E&H0IEH@uH0E3@?z±@‘HE@%@%E2H2±@K‘@HEuE2H3L0;LEHuE/L*H.;LEHe@*E/H0:±@‘@EHu@+E*H*±@k‘@0H%@:+E@ EH9@/E"H+I@HEuE.H+@9{HE@%@#E/H0J±@‘HE@uH0L.E/±@;‘LEHu>/E*A.;E>Ae>/E*A0;>EAuH*E*@+j±@‘@0H%@:±@+‘E@%G/@">*D+I@DG>u>.G9D+@-{>DG@%@#H0E/J±@‘E@HuE/L.±@‘H0;ELHuA.E*>0<Ae>-EAuA*E+±@‘>*kE0A%E:+>E%G/D+@"ID@Gu@.D+G9{@GD%@/D0G#J±@‘G@Du±@‘G.@/D0;G@DuG*D.@/;G@DeG*@/D0;@GDuD*G+@*j±@‘G0D%G:±@+‘@G%G/@"D+I@DGuG9@.D+{@GD%@/C0G#>-J±@‘G>@CuC0G.>/±@‘@0;>@GCuH.L*E/;LEHeH0@*E/;@EHuH*L*C+j±@‘C0L%±@‘C:+HC%E/>"A+IE>AuA+E9>.{AE>%E#A0>/KA>EuE.A0>/:±@‘>EAuA.E*±@‘>/;E>Ae>/A0E*;E>AuA*E+>*kE0A%E:+>E%E/>"A+H±@‘>AEuE9±@‘>.A+{EA>%@/>-G#D0KD@>Gu@0>/G.D0:±@‘>@GDu±@‘L*E/H.;LEHeE/H0@*;@EHuA*>*E+kE0A%E:+>E%G/@"D+H±@‘D@GuG9D+±@‘@.{@DG%@/G#D0K@GDuD0@/G.;G@D>/G+C"H±@‘CG>u±@‘C.>9G+{GC>%G0C/>#KC>GuJ.G0C/;JCGB/G"J+H±@‘JGBuG.±@‘B9J+{BJG%D#=/A0KDA=uA0=/D.;D=AuI.E/L*:±@‘LEIeI0@*±@‘E/;@EIu@+E*I*k@0I%@:+E@%@/E"I+I@EIuE.I+@9z±@‘I@E%I0@#±@‘E/KIE@uI0L.E/;LEI=/E+B"I=BEu=9B.E+z±@‘EB=%=#±@‘B/E0K=BEuB/E0I.;BIEuB0I*E.?/;BI?Ee?/E0=*B-:±@‘?=BEu±@‘E*I*@+k@0I%@:+E@%@/H+E"IEH@u@9H+E.{@HE%@#H0E/J±@‘EH@uL.E/±@‘H0;LEHuH.E/L*;LEHe@*E/H0;E@HuE*@+H*j±@‘@0H%@:±@+‘E@%E/<*A+>"I><AEuE9<.>-A+{A<>E%>/A0E#J±@‘A>EuE.±@‘A0>/;>EAuH.L*E/;LEHeE/H0@*;@EHu@+H*E*j±@‘@0H%±@‘@:+E@%E/<*A+>"IAE><u<.A+>-E9{<EA>%>/A0E#J±@‘AE>u>/±@‘A0E.;E>Au>/A.E*;E>Ae>/A0E*;E>Au>*A*E+j±@‘E0A%E:±@+‘>E%@/I+E"II@EuI+E.@9{@EI%E/@#I0K@IEuI0L.E/:±@‘ELIuI.L*±@‘E/;LEIeI0E/@*;@EIu@+I*E*k@0I%@:+E@%@2I-E$H±@‘E@Iu±@‘I-@<E0{IE@%@'E4I5KEI@uI6E4L3;LEIu@6=8D2:±@‘D=@e±@‘=8@8D1;=D@u=1@1D3kD0@%DD+=D)BHKCG8EBKGiKCBEGGv±@‘GKB)B:GH±@‘KIGBKIBHB±}‘D'@$=±|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@‘=@Dÿ/MTrkK²Â'ÿJAZ2ÿBassÿYÿY²x @[2@]2HKJ<}Cƒx @[2]2@HKJ<CÂ'ƒ’&` &@&`& &T& &` &@&`& &O& &` &@&`& &O& &` &@&`& &W &&` &@&`& &T& &` &@&`& &O& &` &@&`& &O& &` &@&`& &W &(` (@(`( (X( (` (@(`( (`( (` (@(`( (\( (` (@(`( (W( (` (@(`( (X( (` (@(`( (`( (` (@(`( (\( (` (@(`( (W( !` !@!`! !T! !` !@!`! !O! !` !@!`! !O! !` !@!`! !W !!` !@!`! !X! !` !@!`! !`! !` !@!`! !\! !` !@!`! !W! !` !@!`! !X! !` !@!`! !`! !` !@!`! !\! !` !@!`! !W! &` &@&`& &T& &` &@&`& &O& &` &@&`& &O& &` &@&`& &W &&` &@&`& &T& &` &@&`& &O& &` &@&`& &O& &` &@&`& &W &(` (@(`( (X( (` (@(`( (`( (` (@(`( (\( (` (@(`( (W( (` (@(`( (X( (` (@(`( (`( (` (@(`( (\( (` (@(`( (W( !u0!P!o !@!` !@!y !@!` !D!b‚|²@]2 @CHKxJ<[2Â'’!‹&Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &(Q (@(Q( (J( (Q (@(Q( (Q( (Q (@(Q( (N( (Q (@(Q( (I( !Q !@!Q! !F! !Q !@!Q! !B! (Q (@(Q( (B( (Q (@(Q( (I (!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! &Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! &Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &&Q &@&Q& &J& &Q &@&Q& &Q& &Q &@&Q& &N& &Q &@&Q& &I& !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !!b0!P!] !@!Q !@!e !@!Q !@+V +@+V+ +O+ +V +@+V+ +V+ +[ +@+[+ +W+ +[ +@+[+ +R+ +V +@+V+ +O+ +V +@+V+ +V+ +Q +@+Q+ +N+ +Q +@+Q+ +I+ )Q )@)Q) )F) )Q )@)Q) )B) )Q )@)Q) )B) )Q )@)Q) )I )(V (@(V( (O( (V (@(V( (N( ([ (@([( (S( ([ (@([( (O( !V !@!V! !O! !V !@!V! !N! ²HK @[2]2CxJ<@Â'ƒ’&Q &@&Q& &J& &Q &@&Q& &Q& &Q &@&Q& &N& &Q &@&Q& &I& (Q (@(Q( (F( (Q (@(Q( (B( (Q (@(Q( (B( (Q (@(Q( (I ((Q (@(Q( (J( (Q (@(Q( (Q( (Q (@(Q( (N( (Q (@(Q( (I( !b0!P!] !@!Q !@!e !@!Q !@+Q +@+Q+ +J+ +Q +@+Q+ +Q+ &Q &@&Q& &N& &Q &@&Q& &I& )Q )@)Q) )F) )Q )@)Q) )B) )Q )@)Q) )B) )Q )@)Q) )I )(Q (@(Q( (J( (Q (@(Q( (I( (Q (@(Q( (J( (Q (@(Q( (F( !Q !@!Q! !J! !Q !@!Q! !I! !Q !@!Q! !J! !Q !@!Q! !F! !i0!P!i !@![ !@!r !@![ !D!h‚|²x]2[2HK @CJ<@Â'ƒ!’!?![! !S! ![ !@![! ![! !V !@!V! !S! !V !@!V! !N! !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! &Q &@&Q& &F& &Q &@&Q& &B& !Q !@!Q! !B! !Q !@!Q! !I !(Q (@(Q( (J( (Q (@(Q( (Q( !Q !@!Q! !N! !Q !@!Q! !I! &Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &(Q (@(Q( (J( (Q (@(Q( (Q( (Q (@(Q( (N( (Q (@(Q( (I( (Q (@(Q( (F( (Q (@(Q( (B( (Q (@(Q( (B( (Q (@(Q( (I ((Q (@(Q( (J( (Q (@(Q( (Q( (Q (@(Q( (N( (Q (@(Q( (I( !Q !@!Q! !F! !Q !@!Q! !B! $Q $@$Q$ $B$ $Q $@$Q$ $I $&Q &@&Q& &J& &Q &@&Q& &Q& &Q &@&Q& &N& &Q &@&Q& &I& &Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &&Q &@&Q& &J& &Q &@&Q& &Q& (Q (@(Q( (N( (Q (@(Q( (I( !Q !@!Q! !F! !Q !@!Q! !B! &Q &@&Q& &B& &Q &@&Q& &I &(Q (@(Q( (J( (Q (@(Q( (Q( (Q (@(Q( (N( (Q (@(Q( (I( +Q +@+Q+ +J+ +Q +@+Q+ +Q+ +Q +@+Q+ +N+ +Q +@+Q+ +I+ #Q #@#Q# #J# #Q #@#Q# #Q# %Q %@%Q% %N% %Q %@%Q% %I% !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! *Q *@*Q* *J* *Q *@*Q* *Q* *Q *@*Q* *N* *Q *@*Q* *I* *Q *@*Q* *F* *Q *@*Q* *B* !Q !@!Q! !B! !Q !@!Q! !I !!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !&Q &@&Q& &J& &Q &@&Q& &Q& &Q &@&Q& &N& &Q &@&Q& &I& !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !&Q &@&Q& &J& &Q &@&Q& &Q& &Q &@&Q& &N& &Q &@&Q& &I& &Q &@&Q& &F& &Q &@&Q& &B& &Q &@&Q& &B& &Q &@&Q& &I &!Q !@!Q! !J! !Q !@!Q! !Q! !Q !@!Q! !N! !Q !@!Q! !I! !Q !@!Q! !F! !Q !@!Q! !B! !Q !@!Q! !B! !Q !@!Q! !I !!V !@!V! !O! !V !@!V! !V! ![ !@![! !W! ![ !@![! !R! %` %@%`% %T% %` %@%`% %O% %` %@%`% %O% %` %@%`% %W %#u0#P#o #@#` #@#y #@#` #@²}’%J²|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0’%²@ÿ/MTrk°³ÃPÿJAZ2³@ÿYÿY³x ^[2]2ÿ Square wave³HKJ<}Cƒx ^[2]2@HKJ<CÃPƒ“A*@A J 0A A A*0E*JA AA A* EE A@> EA*> >> >* AE> E0>*@> E 0> > >*0A*E> >> >* AE >@> EA*> >> >* AE> E4@*\G*@@@ @*G @D*0@@ @*0G%D@@ @ G@D*0@@ @* DG%@T@* EA*> >> >* AE> E0>*@> E 0> > >*0EA*> >> >* AE >@> EA*> >> >* AE> E4@*\G*@@@ @*G @D*0@@ @*0DG%@@ @ G@D*0@@ @* DG%@T@* EA$> >> >$ AE> E4@$\G$@@@ @$G @D$0@@ @$0DG@@ @ GD$@0@@ @$ DG@P@$@G@ E0@@ @$0E@@$0@@@ @$0G @@@ GD$@ @@ @$ DG@ G4@$\E$@@@ @$E @@$0@@@ @$0E@@ @ E@@$0@@@ @$0E@P@$@E@ E0@@ @$0@@$E0@@@ @$09 @@@ 9@@$0@@@ @$0E@ E4@$\E$@@@ @$E @@$0@@@ @$0E@@ @ E@$@0@@@ @$0E@PA$@AE H0AA A$0E$HA AA A$ EE A@> EA$> >> >$ AE> E4@$\E$@@@ @$E @@$0@@@ @$0E@@ @ E@$@0@@@ @$0E@PA$@AE H0AA A$0HE$A AA A$ EE A@> EA$> >> >$ AE> E4>$\E$>>> >$E >A$0>> >$0EA@> > EA$>0>> >$ AE>P@$@@E E0@@ @$0E@$@0@@@ @$0E @@@ E@$@0@@@ @$0E@ E8@`E$ @'@ @'@ E @@$)@@ @'@09$9@'<9<@$ @4$<</4tC%\G%CCC C%G E%C0CC C%0G#E@C > G>C(0>> >( CG#>T>%>> >%G >C%0>> >%0;C@> > ;>C$0>> >$ CG>PGA$@A H0AA A$0HE$A AA A$ E9 A@< 9C$< << <$ CE< E4@%\G%@@@ @%G @D%0@@ @%0G#D@@ @ G@D(0;(0D; D#PD@%\E%@@@ @%E @@%0@@@ @%0³x ^HKC[2J<]2ÃP³@ƒ“@A$\J$AAA A$J E$A0AA A$0EE@A > EA$>0>> >$ AE>P@$@E@ G0@@ @$0GD$@ @@ @$ DG @@@ GD$@ @@ @$ DG@ G4@$\G$@@@ @$G @D$0@@ @$0D;@@ @ ;@D$0@@ @$ DG@X@8G(E$ @'@ @'@ E @@$)@@ @'@09$9@'<9<@$ @4$<</4tC$\G$CCC C$G CE$0CC C$0EC>`A >E$A0AA A$ EJAP<$J@< E0<< <$0C$E< << <$ C9 <@< 9C$< << <$ CE< E4@$\G$@@@ @$G D$@0@@ @$0GD@@ @ G@D$0;$0D; DPD@$\E$@@@ @$E @$@0@@@ @$0E@@ @ E@@$0<$0@< @P@@ `E% @'@ @'@ E @@%)@@ @'@ 0E(9@'<"E<@( @4(<"</4x4*@$<*‚x³ ^[2@HKx]2J<CÃPƒ“@(\E(@@@@(E @@(0@@@ @(0E!@@ @ E@@%0@@@ @%0E!@P@$@E@ E0@@ @$0E@@$0@@@ @$0E @@@ E@$@0@@@ @$0E@ E0@<4@$\E$@@@ @$E @$@0@@@ @$0E@@ @ E@$@0@@@ @$0E@PA$@EA J0AA A$0JE$A AA A$ EAE`@ E@@$0@@@ @$0E@ E4@$\G$@@@ @$G @D$0@@ @$0DE@@ @ E@$@0@@@ @$0E@PA$@EA H0AA A$0HE$A AA A$ EE A@> EA$> >> >$ AE> E4@$\G$@@@ @$G D$@0@@ @$0GD@@ @ G@D$0@@ @$ DG@P@$@@G G0@@ @$0GD$@ @@ @$ D; @@@ ;D$@ @@ @$ DG@ G4@$\G$@@@ @$G @D$0@@ @$0D;@@ @ ;@C$0@@ @$ CG@P@$@G@ E0@@ @$0E@@$0@@@ @$0C @@@ CC$@ @@ @$ CC@ C4A$\J$AAA A$J AE$0AA A$0EE@A > E>C$0>> >$ CE>P>$@E> E0>> >$0A$E> >> >$ AE >@> EA$> >> >$ AE> E4>$\E$>>> >$E A$>0>> >$0;A@> @ ;@D$0@@ @$ DG@P@$@@G E0@@ @$0@E@$0@@@ @$0J @@A JE$A AA A$ EJA J4@$\G$@@@ @$G D$@0@@ @$0;D@@ @ ;D$@0@@ @$ DG@T>$>> >$G >C$0>> >$0GC@> > GC$>0>> >$ CG>T@$$@>E E0>> >$0EB$> >> >$ B>G`@ G@@$0@@@ @$0G@ G4@$\E$@@@ @$E @@$0@@@ @$09@@ @ 9@@$0@@@ @$0E@P@$@E@ E0@@ @$0E@$@0@@@ @$0E @@@ E@@$0@@@ @$0E@ E4A$\H$AAA A$H AE$0AA A$0EE@A > E>A$0>> >$ AE>P@$@@E E0@@ @$0@@$E0@@@ @$0E @@@ E@$@0@@@ @$0E@ E4A$\H$AAA A$H AE$0AA A$0EE@A > E>A$0>> >$ AE>P>$@E> E0>> >$0A$E> >> >$ AE >@> EA$> >> >$ AE> E4@$\G$@@@ @$G @@$0@@@ @$0G@@ @ G@@$0@@@ @$0G@P@$@G@ G0@@ @$0@$@G0@@@ @$0G @@@ G@$@0@@@ @$0G@ G4@%\G%@@@ @%G @@%0@@@ @%0G#@@ @ G@@(0@@@ @(0G#@P@*@G@ I 0@ @ @*0ID*@ @@ @* DD @@@ DD*@ @@ @* DD@ D8?$`G* ?'?$ ?'?$ G ?B*0?$ ?'?$)BG*9?';$G;B* B6*;$;/6p³}“@ ³|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@“@ÿ/MTrkÅ´Ä3ÿJAZ2ÿ Synth stringsÿYÿY´x @[2]2HK@J<}Cƒ[2 @x]2@HKJ<CÄ3”;3>B@@…x;3;>@>B@@…y>…`@;@3EBEE@…x@@3EEBEE@‹YE@†;3>B@@…x;3;>@>B@@…y>@EB@3EE@…b;ƒÄ3´ @J<]2xHKC[2@‰”@†E‘;+>7@6…y>…`@;@+E7EE6‹YE@@+E7EE6ˆx@‚aE@+E7EE6ˆx@‚aE9+>7>>6…y>…o9@+E7EE6…r>.C:CC9„ E@_>>.CC:CC9…x>…aC;.@:@@9…Y@;@.E:EE9‚x´xC @[2]2@HKJ<Ä3ƒ”9+@>7>>6…yE…`>9;+@7@@6…y@@+E7EE6…b;>+C7CC6‚y@CEo>†;+@7@@6…Y@;@+E7EE6…YE@@.E:EE9ˆr´HK@x @[2J<]2CÄ3´ƒ”@0E>EE<‹YE@@+@EE7EE6…x@…aE;+>7@6‚y>‚;ƒ@‚;+@7@@6‹Y@;;+@7@@6ˆx;‚a@9+>7>>6‹Y>99+>7>>6…y>…o9;+@7@@6…x>+C7CC6…Y@;B+CG7GG6‚x>BˆaG@+E7EE6…x=+B7BB6…YE@…qB=@+E7EE6‹YE@9+<7>6…y>…`<99+<7>6‹Y<>9@+E7EE6‹YE@@.E:EE9‹YE@B3GBGG@…r´}”8#GB=-´|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0”8´@”=ÿ/MTrk?¹ÉÿJAZ2¹ÿY¹x @[]@HK™8¹}ÿDrums¹C™$J98*8¹J<™8$9**5 *!/ !R, R$J&A*8 $*&*5!/ !*./ .!5R, R!¹™!!¹[™$J¹@ɹC™8¹xHK @™*8¹]J<™8*$!!3*5 *!./!$ !.!/R, R!*8$J&A $&**5 *./!/ !.R,!! R!$J*888$**5 *!/./ !.R, R$J&A*8 $&**5!/ !*./ .R,!5 !R*88$J!!8!$*!3*5 *!./!$ !.R,!/ !R*8&A$J *&$*5 *./!/ .!!!R, !R*88$J8*$*5 *./!/ .!R, R$J&A*8 *$&!/*5 !*./ .R,!5 !R$J8!!*88$*!*5!3 !*./!$ .!!/R, !R$J&A*8 $*&*5 *./!/ .!!!R, !R8$K*98*$*6 *.0!9 .!R- R*9$K&B *&$!9&B*6 &*!.0&B &.R- R8&B$K*9!98$*&!*6&B!1 *!&!9&B.0 !&.R-!9&B &!R&B*9$K *&$*6 *&B.0!9 .&!!7R-&B !R&8$K*98$**6 *.0!9 !.R- R&B$K*9 *&$!9&B*6 &*!&B.0 &.R- R8!9*9$K&B8*!&$!1*6&B *!&!9&B.0 !&.!9&BR- R&!$K&B*9 $*&*6 *!9&B.0 &!.R-&B!7 &R!$J*898889*$*5 *!/ !R, R*8&A$J *&$*5!/ !*./ .R,!5 !R8$J!!*88$*!*5!3 !*!$./ !.!/R, !R&A*8$J *&$*5 *!/./ !.R,!! !R$J988*889*$*5 *!/ !R, R$J*8&A $&*!/*5 *!./ .!5R, !R*8!!8$J8!$**5!3 *!./!$ !.R,!/ !R*8&A$J &$**5 *./!/ !.!!R, !R988*8$J8*$9*5 *!/ !R, R*8&A$J $*&*5!/ !*./ .R,!5 !R$J!!*888$!**5!3 *!./!$ !.R,!/ R!&A*8$J $&**5 *./!/ .!!!R, R!8*8$J8*$*5 *./!/ .!R, R*8&A$J *$&!/*5 *!./ .R,!5 R!*8!!$J88$*!*5!3 !*./!$ .!!/R, R!*8&A$J &*$*5 *./!/ !.!!R, R!$J8*88*$*5 *./!/ !.R, R*8$J&A *&$*5!/ !*./ .R,!5 !R8!!*8$J8$!**5!3 !*./!$ .!R,!/ R!&A$J*8 *$&*5 *./!/ !.!!R, !R*98$K8*$*6 *!9.0 !.R- R$K*9&B $*&&B!9*6 !&*&B.0 .&R- R&B*9!98$K8&$!*!1&B*6 &!*&B.0!9 .!&R-!9&B R&!&B*9$K *&$*6 *!9&B.0 !&.!7&BR- !R&$K8*98*$*6 *.0!9 .!R- R*9$K&B &*$&B!9*6 &!*.0&B .&R- R$K&B*98!98*!$&*6!1&B &!*.0!9&B .!&!9&BR- R!&$K*9&B *$&*6 *&B!9.0 &.!&B!7R- &R!*D$ZED88*$E*DE1 *E.B!BE< .E!E1R? ERED$Z*D&O $E*&!B*DE1 E!*.BE< E.E1R?!D E!R$Z8!3ED*D8*!E$E1!D*D !*E!6E<.B E.!!BE1R? ER!*D$Z&OED $E*&E1*D E*!B.BE< !E.E1!3R? RE!8E6&J$U96*@8E9$*&‚`¹x@]HKJ<[Cɹ @™88?$R*=E=&H &*E$*=E+ E*!:.:E5 .!E!.R8E+ E!R8*0$A8*$*- *.(!( .!R% R*0&8$A *&$*-!( !*.( .!-R% R!!8$A*08$!**-!+ *!!.( !.R%!( !R&8$A*0 &$**- *!(.( !.!R% !R8$9*08*$*- *!(.$ !.R$ R&1$=*0 $&*!(*- !*.' .!-R! R!!*0$A88!*$!+*- !*!." .!!(R% !R&8*0$9 $*&*- *!(.$ .!!R$ !R$A*09088*9$*- *!( !R% R$A&8*0 $&**-!( !*.( .!-R% R!*0$A8!8$*!*-!+ *!.(! !.R%!( !R$A&8*0 &*$*- *!(.( .!!R% R!90*08$A8$9**- *!( !R% R*0$A&8 $&**-!( *!.( .R%!- R!!$A8*08$!*!+*- *!!.( !.!(R% R!&8$A*0 $*&*- *.(!( !.!R% R!8$A*08$**- *!(.( !.R% R*0$A&8 &$*!(*- *!.( .!-R% R!!$A*088*!$!+*- !*.(! !.!(R% R!&8*0$A $&**- *!(.( !.!R% R!8$B*08*$*- *!0.( .!R& R*0$B&9 *$&*-!0&9 !&*.(&9 .&R& R$B&98!0*08&$!**-!*&9 *!&&9!0.( &.!!0R&&9 !&R$B&9*0 $&**- *!0&9.( &!.!.R&&9 &!R90$A*088$9**- *!( !R% R&8$A*0 &$*!(*- *!.( .!-R% R!8*0$A!8!*$!+*- *!!.( .!R%!( R!*0&8$A *$&*- *.(!( !.R%! R!8*0$98$**- *.$!( .!R$ R&1*0$= &*$*-!( *!.' .R!!- !R8$A*0!8$!*!+*- !*!." !.R%!( !R&8*0$9 $*&*- *!(.$ .!R$! !R$A8*08*$*- *.(!( !.R% R$A&8*0 *&$*-!( *!.( .R%!- !R!8*0$A8!*$*-!+ *!!.( !.!(R% R!*0&8$A *&$*- *.(!( .!!R% !R8$9*08*$*- *!(.$ !.R$ R&1$=*0 *$&!(*- *!.' .!-R! R!*08!$A8!$*!+*- !*."! .!!(R% R!&8$9*0 &$**- *.$!( .!!R$ !R$A8*08*$*- *.(!( .!R% R$A*0&8 $*&!(*- !*.( .R%!- !R$A*08!8$*!!+*- !*.(! !.R%!( R!&8$A*0 $&**- *.(!( .!R%! !R*0$988*$*- *!(.$ !.R$ R&1$=*0 &$**-!( !*.' .R!!- !R*08!$A8*$!*-!+ *!!." !.R%!( !R&8*0$9 &*$*- *!(.$ .!R$! R!8*0$A8$**- *.(!( .!R% R&8*0$A &*$!(*- *!.( .!-R% R!8*0!$A8*!$!+*- *!.(! !.R%!( !R*0&8$A $*&*- *!(.( !.R%! R!$9*088*$*- *.$!( !.R$ R$=*0&1 *$&!(*- *!.' .R!!- R!*0!$A88*!$*-!+ *!."! !.R%!( R!&8*0$9 &*$*- *!(.$ .!!R$ R!*08$A8*$*- *.(!( !.R% R$A*0&8 $*&!(*- *!.( .!-R% R!8*0!$A8!$**-!+ !*.(! !.R%!( !R$A&8*0 *$&*- *.(!( !.!R% R!*:E:8$O8E*$*:E) *E.7E3!7 .E!R5E) RE&D*:$OE: E*&$*:!7E) E*!.7E3 .E!:E)R5 R!EE:$O!+8*:8$*E!*:E)!: *!E.7E3!. !E.!7R5E) !REE:$O*:&D &$*E*:E) E*E3.7!7 E.!R5E)!+ !ER8$D92*28$*9*/ *!* !R' R$D&;*2 $&*!**/ *!.* .R'!/ R!8$G*5!8*$!!0*2 !*.,!" .!R*!, R!&>*5$G &*$*2 *.,!, !.R*! R!$;8*28$**/ *.%!* .!R% R&4*2$@ $&**/!* !*.) .!/R" !R8$A*0!8!$**-!+ *!."! .!!(R% !R$9*0&8 $&**- *.$!( .!R$! R!*0$A88*$*- *!(.( !.R% R*0$A&8 &$*!(*- !*.( .!-R% R!*0!8$A8*$!*-!+ *!.(! .!R%!( R!&8*0$A $&**- *!(.( .!R%! !R$E*388*$*0 *!3.+ !.R( R$E&<*3 &$*!3*0&< *&!.+&< .&R( R!6&?$H8*68&!*$&?!.*2 &!*.-&?!6 .&!!6&?R* R!&$H&?*6 &$**2 *&?!6.- .&!&?R*!4 R&!8$D*29289$**/ *!* !R' R$D*2&; $&**/!* !*.* .R'!/ !R¹x @J<™!8¹HK[@ɹ]C™*0¹™$A8*$!*-!+ !*!.( !.!(R% R!$A&8*0 &$**- *.(!( !.!R% !R$98*08*$*- *.$!( .!R$ R$=*0&1 &$*!(*- !*.' .!-R! R!*0$A8!8$*!*-!+ !*."! !.R%!( !R$9*0&8 $*&*- *!(.$ .!!R$ R!$A8*08*$*- *!(.( .!R% R*0&8$A $*&!(*- !*.( .!-R% R!!$A8*08!$*!+*- !*!.( !.!(R% R!&8*0$A &*$*- *!(.( .!R%! !R*0$988*$*- *!(.$ !.R$ R*0$=&1 *&$!(*- *!.' .R!!- R!$A!8*08*!$*-!+ !*!." !.R%!( !R$9&8*0 *$&*- *!(.$ .!!R$ R!E:$O*:88*$EE)*: E*E3.7!7 !E.R5E) ER&D*:E:$O $E&*E)!7*: !*E.7E3 E.R5E)!: !RE*:8!+$OE:8$E*!!:*:E) *!E.7E3!. !E.R5!7E) R!E*:&DE:$O $E&*E)*: *EE3!7.7 !.EE)R5!+ !ER8$9*08$**- *.$!( !.R$ R&1*0$= &$*!(*- *!.' .!-R! R!!$A*088$!**-!+ !*!." !.!(R% R!$9*0&8 $*&*- *!(.$ !.R$! !R$A8*08*$*- *!(.( .!R% R$A*0&8 &*$!(*- *!.( .R%!- !R*08$A!8$*!!+*- *!.(! !.R%!( R!*0&8$A &*$*- *!(.( .!R%! R!*0$B88*$*- *!0.( .!R& R*0$B&9 &*$*-!0&9 &!*.(&9 .&R& R8!0$B*0&98!*&$!*&9*- !*&!0.(&9 !&.&9R&!0 R&!*0&9$B &$**- *!0&9.( &.!!.&9R& R!&*0$A9088*9$*- *!( !R% R&8*0$A *&$*-!( !*.( .!-R% R!*08$A!8*!$!+*- *!.(! !.R%!( R!$A*0&8 $*&*- *.(!( .!R%! !R8E=$R*=8*$EE+*= *E!:E5.: E.!R8E+ RE$RE=*=&H *$&E!:*=E+ !*EE5.: E.E+!=R8 !ER*@E@!0$V88$E*!!@*@E. E!*E8!3.> !.ER;E.!> !RE&KE@$V*@ *$&EE.*@ *EE8!>.> .E!E.R;!0 ER!8*DE9$Y99&N8*E9$&‚`¹]J<[ɹCx @™8¹@HK™8?*D&O$ZED &$*E*DE1 E*!B.BE< E.!R?!3E1 !RE*5$>88$**2 *.(!, .!R( R&6$B*5 *$&!,*2 !*., .R$!2 !R*28!$D8*!$*/!. !*! .$ .!!*R' !R*2&;$; *$&*/ *!*.% .!R%! R!8$A*08*$*- *.(!( .!R% R$A*0&8 *&$!(*- !*.( .!-R% R!$A8!*08*!$!+*- !*.(! !.R%!( R!*0$A&8 $*&*- *!(.( .!R%! R!$98*08$**- *!(.$ !.R$ R*0&1$= &*$!(*- !*.' .!-R! R!!*08$A8$*!!+*- *!!." .!!(R% !R$9*0&8 *$&*- *!(.$ .!R$! !R*08$A8*$*- *!(.( !.R% R$A*0&8 *&$!(*- *!.( .R%!- R!*0$A8!8!*$!+*- *!.(! !.R%!( !R$A*0&8 $&**- *!(.( .!!R% !R8*0$98*$*- *.$!( !.R$ R*0$=&1 &*$!(*- !*.' .!-R! !R8*0!$A8*!$*-!+ *!."! .!R%!( !R&8*0$9 *&$*- *.$!( .!!R$ R!$A8*08$**- *.(!( !.R% R*0$A&8 &*$!(*- !*.( .!-R% R!8*0$A!8*!$*-!+ !*.(! !.!(R% !R&8$A*0 $*&*- *!(.( .!!R% R!8$9*08$**- *!(.$ .!R$ R&1*0$= &*$!(*- !*.' .R!!- R!*0!$A88*!$!+*- *!!." !.!(R% R!*0$9&8 *&$*- *.$!( .!R$! !R8$A*08$**- *!(.( !.R% R*0&8$A *$&*-!( !*.( .!-R% R!$A!*088*$!*-!+ !*!.( !.!(R% !R&8$A*0 &*$*- *.(!( !.!R% R!*08$98$**- *.$!( !.R$ R&1$=*0 *&$*-!( *!.' .!-R! !R!$A*088!*$!+*- *!."! !.R%!( R!&8$9*0 &*$*- *!(.$ !.!R$ !R*0$A88*$*- *.(!( !.R% R*0&8$A *$&*-!( *!.( .R%!- !R*08!$A8$!*!+*- !*.(! !.!(R% !R&8$A*0 $&**- *!(.( .!!R% !R$9*088*$*- *!(.$ !.R$ R&1*0$= *&$*-!( *!.' .R!!- !R*0!8$A8$!*!+*- *!!." .!!(R% !R$9&8*0 &$**- *!(.$ .!R$! !R$A8*08$**- *!(.( !.R% R$A&8*0 &*$*-!( !*.( .R%!- R!*08$A!8$!*!+*- !*!.( .!!(R% !R*0$A&8 *&$*- *!(.( .!!R% !R*08$98$**- *.$!( !.R$ R$=*0&1 &$**-!( *!.' .R!!- R!*08$A!8*$!!+*- !*."! .!!(R% R!&8*0$9 *&$*- *!(.$ !.R$! R!$A*088$**- *!(.( !.R% R*0$A&8 *$&!(*- !*.( .R%!- !R*0!$A88!$*!+*- *!.(! .!!(R% R!*0&8$A *&$*- *!(.( !.!R% !R$98*08*$*- *!(.$ .!R$ R$=&1*0 $*&!(*- !*.' .!-R! !R*0$A8!8$*!!+*- *!."! .!R%!( !R*0$9&8 $&**- *.$!( .!!R$ R!$98*08$**- *!(.$ !.R$ R$=&1*0 $*&!(*- *!.' .R!!- !R$A*0!88!$**-!+ !*."! .!R%!( R!$9&8*0 $*&*- *.$!( !.R$! !R$98*08*$*- *.$!( !.R$ R$=*0&1 &$**-!( *!.' .R!!- R!!8*0$A8$*!*-!+ !*!." .!R%!( R!&8$9*0 &*$*- *!(.$ !.R$! R!*0$A88*$*- *!(.( .!R% R*0&8$A *$&!(*- !*.( .!-R% R!$A8!*08*!$*-!+ *!!.( .!!(R% !R&8*0$A *&$*- *!(.( .!!R% !R*08$98*$*- *!(.$ !.R$ R$=&1*0 &$**-!( *!.' .R!!- !R$A*08!8!*$*-!+ !*."! !.R%!( R!$9&8*0 &$**- *.$!( !.!R$ R!*08$98*$*- *!(.$ !.R$ R*0&1$= &$**-!( !*.' .!-R! !R*0$A8!8!*$*-!+ !*!." .!R%!( !R*0&8$9 *$&*- *!(.$ .!R$! R!$A8*08*$*- *.(!( !.R% R&8$A*0 *&$*-!( *!.( .R%!- R!8!$A*08!$*!+*- !*.(! .!!(R% R!$A&8*0 &$**- *!(.( !.R%! !R$98*08$**- *.$!( !.R$ R&1$=*0 *&$!(*- !*.' .!-R! R!!8*0$A8$*!*-!+ !*."! .!!(R% R!$9&8*0 $&**- *.$!( .!!R$ !R$A*088*$*- *!(.( .!R% R*0$A&8 *&$*-!( *!.( .!-R% !R8$A*0!8$!**-!+ !*!.( !.R%!( !R*0$A&8 *&$*- *.(!( .!!R% R!8*0$98*$*- *.$!( .!R$ R$=&1*0 $*&!(*- *!.' .R!!- R!8$A*0!8*!$!+*- *!!." !.!(R% !R$9&8*0 $*&*- *!(.$ .!R$! !R8*0$A8*$*- *.(!( !.R% R&8*0$A &*$!(*- *!.( .R%!- R!8*0!$A8*!$!+*- !*.(! !.R%!( R!*0&8$A *$&*- *.(!( .!R%! R!*0$988*$*- *!(.$ .!R$ R$=*0&1 $&*!(*- !*.' .!-R! R!8!$A*08*$!!+*- !*."! !.!(R% !R*0&8$9 &*$*- *!(.$ .!!R$ !R$A8*08$**- *!(.( !.R% R&8$A*0 $&*!(*- !*.( .R%!- !R$A*08!8!*$!+*- *!.(! !.!(R% !R&8$A*0 $&**- *!(.( .!R%! !R*0$988*$*- *.$!( .!R$ R&1*0$= *$&!(*- !*.' .!-R! R!8*0!$A8!$**-!+ *!."! .!!(R% R!&8*0$9 *&$*- *!(.$ .!!R$ R!8$A90*089*$*- *!( !R% R*0$A&8 *$&*-!( *!.( .R%!- R!!*0$A88!$**-!+ *!.(! !.R%!( !R$A*0&8 *$&*- *.(!( .!!R% R!928*2$D8$9**/ *!* !R' R$D&;*2 $*&*/!* *!.* .R'!/ !R8*5!$G8*!$*2!0 *!.,!" .!!,R* R!$G*5&> *$&*2 *.,!, !.!R* !R*8$J88*$*5 *!/./ !.R, R*8$J&A &*$!/*5 *!./ .R,!5 !R*88!!$J8$!**5!3 !*!$./ .!R,!/ !R&A*8$J $*&*5 *!/./ .!R,!! !R*D$ZED88$*E*DE1 *EE<!B.B E.!R?E1 RE&OED$Z*D $*&E!BE1*D E!*E<.B .E!DE1R? R!E!3*DED8$Z8!$*E*DE1!D !*E!6.BE< E.!!BR?E1 RE!&O$ZED*D *E$&*DE1 *E.B!BE< .E!R?!3E1 ER!96*6$6†*,9,$,9*$†$*9ÿ/MTrkµÅ ÿJAZ2µJ<ÿYÿYµx [@]@HK•E)µ}Cÿ Vibraphoneµ}ƒx‚p•>)Eµ}ƒxƒsƒn‚p•>@)µ}ƒxƒsƒn‚p}•E)@ƒµxƒsƒnƒiƒd‚p•>)µ}•Eƒµxƒsƒn‚p}•@)>ƒµxƒsƒn‚p}•@E)ƒµx‚p}•H%Eƒµx‚p}•L"HƒL"µ}•LƒJ"Lµ}ƒ•J"µ}•JƒJ2"µ}ƒx‚p•("µ}•2ƒµx‚p}•-"(ƒ-"µ}•-ƒ-µ}•("ƒµx‚p•<"(µ}ƒ•<@"µ}ƒ•@-"µ}ƒx‚p}•--"ƒ-"µ}•-ƒµxƒs‚p}•2"-ƒµ}•22"ƒµ}•2("ƒµx‚p•>"(µ}ƒ•>µ}•>"ƒ)"µ}•>ƒµx‚p}•)-"ƒµxƒsƒn‚p•-+%µ}ƒx‚p•+/%µ}ƒx‚p•/µ}•9"ƒµx‚p•4%µ}•9ƒ4)µ}•4ƒµ}•-%4ƒµx‚p•2"µ}•-ƒµx‚p•("µ}•2ƒµxƒs‚p•(µ}•("ƒ-"µ}•(ƒµx‚p•2"µ}•-ƒµ}•2"2ƒ2-"µ}ƒx‚p}•("-ƒ(µ}•("ƒµ}•(E"ƒµxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p•EE"µ}ƒx‚p}•E"EƒE"Eµ}ƒ•ED"µ}ƒ}•DE"ƒEE"µ}ƒ•E"Eµ}ƒ•Eµ}•@"ƒµx‚p•@µ}•G"ƒµxƒs‚p•G"Gµ}ƒ•E"Gµ}ƒ•Eµ}•C"ƒµ}•C>"ƒµ}•>>"ƒµ}•>">ƒµxƒs‚p}•>">ƒ>@"µ}ƒ•A"µ}•@ƒA;"µ}ƒx‚p•G"µ}•;ƒµx‚p•N"µ}•GƒP"Nµ}ƒ•Pµ}•H"ƒµ}•HI"ƒIµ}•@"ƒµx‚p}•@N"ƒµx‚p•-"µ}•Nƒ-"µ}•-ƒ-"-µ}ƒ}•-"-ƒµxƒs‚p•2"µ}•-ƒµ}•22"ƒµ}•("2ƒµx‚p•>"(µ}ƒ}•>">ƒ)">µ}ƒx‚p•)-"µ}ƒxƒsƒnƒiƒd‚p•-1)µ}ƒx‚p•/)µ}•1ƒµx‚p}•/1µ|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0•1ÿ/MTrkú¶Æ ÿJAZ2¶ÿYÿY¶x h[@]@HKJ<}ÿEcho¶}C–E)ƒ`¶}–EB)@B@)`¶}–>)@ƒ¶xƒsƒn‚p–@)>¶}ƒxƒs„0–@¶}–B)@¶}–E)Bƒ¶xƒsƒnƒiƒP}–B)E@B@)`¶}–>)@ƒ¶xƒsƒn‚p–>@)¶}ƒxƒs„0}–@B)@B¶}–E)ƒ¶x‚p–H%E¶}„@–HI"¶}@–L"I¶}ƒ–L¶}–L"ƒJ"L¶}ƒ–JJ"¶}ƒ–2"¶}–Jƒ`¶}–/"2`-"/`,"-`,¶}–("„@*"¶}–(@*¶}–-"ƒ¶}–-"-@*"-@¶}–("*ƒ¶x‚p–@"(¶}ƒ–@"¶}–@ƒ-"¶}–@ƒ¶x‚p}–--"ƒ-"¶}–-ƒ¶x„0–-¶}–/"@2"¶}–/ƒ2"2¶}`–2/"`-"/`,"-`,¶}–("ƒ¶x‚p–>"¶}–(ƒ¶}–>">ƒ)"¶}–>„@¶}–)*"@*-"¶}ƒxƒsƒn‚p–+%-¶}ƒx‚p–+/%¶}ƒx‚p}–/9"„@¶}–6"9@¶}–4%6ƒ¶}–4)4ƒ-%4¶}„@–/"-¶}@}–2"/ƒ¶x‚p}–2("ƒ¶xƒs‚p–(("¶}@–(*"@¶}–-"*„@/"¶}–-@¶}–/2"ƒ2"¶}–2@2/"@-"¶}–/ƒ¶x‚p}–("-ƒ("¶}–(ƒ¶}–E"(ƒ¶xƒsƒnƒiƒdƒ_ƒZƒUƒP‚p}–EE"ƒ¶x‚p–E"E¶}ƒ}–E"EƒE"E¶}ƒ–EE"¶}ƒ–E"¶}–Eƒ¶}–EE"@EB"@¶}–B@"ƒ¶x‚p}–G"@ƒ¶xƒs‚p}–G"GƒG¶}–C"ƒC"¶}–Cƒ>"C¶}ƒ}–>>"ƒ>>"¶}ƒxƒs‚p–>¶}–>"ƒ¶}–A">ƒA"¶}–A@?"A`?="`¶}–=;"ƒ¶x‚p}–;G"ƒ`I"¶}–G`IK"`L"K`¶}–P"Lƒ¶}–M"PƒI"¶}–MƒG"I¶}@–E"G`ED"`@"D¶}ƒx‚p–@N"¶}ƒx‚p–-"N¶}ƒ–--"¶}ƒ–-"¶}–-ƒ¶}–-"-ƒ¶x„0}–-/"@2"/¶}ƒ}–22"`2/"`/-"`,"-`¶}–,("ƒ¶x‚p–>"(¶}ƒ}–>">ƒ¶}–>)"„@¶}–*")@¶}–*-"ƒ¶xƒsƒnƒi…–-/)¶}`}–/1)ƒ¶x‚p–1/)¶}ƒx‚p}–/1¶|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0–1ÿ/MTrk[·ÇNÿJAZ2ÿWhistleÿYÿY·x "[@]@HK—E)·}J<C}—@)ƒ`·}—<)9)E@@·}`—A)>)·}—<9ƒ·xƒsƒn‚p—D)>A·}—@)ƒ·xƒsƒn‚p—D9)·}—@<)ƒ·xƒsƒnƒiƒP}—@)E)9<@·}`—A)@·}—E>)ƒ·xƒsƒn‚p—@)>·}—AD)ƒ·xƒsƒn‚p—9)·}—<)@Dƒ·xƒs„0—9"="·}—<9@9=>"·}—9"ƒ·}—E"9@">ƒ>"A"·}—@Eƒ·xƒs…—AA"·}—>">`@"E">·}—Aƒ·x‚p}—A"@E>"„@B"·}—>">A@D"@"·}—>Bƒ·xƒsƒn‚p—9"@D·}—<"ƒ·xƒsƒnƒiƒd‚p—A"9<·}—>"… A">·}—>"A`A>@"E"·}ƒx‚p}—A"E@>"ƒ·xƒs„0—B">"A>·}@—>·}—9"B<"ƒ·xƒsƒn‚p}—C%G%9<ƒ·xƒsƒn‚p—A"·}—GCE"„@E·}—AB"A"@@%AD%·}—Bƒ·x‚p}—<%@9%Dƒ·x‚p}—A">"<9ƒ·x‚p}—D"@">Aƒ·xƒsƒn‚p—<"D9"·}—@ƒ·x‚p—C"<9·}—G"ƒ>"A"·}—GC@·}@}—E"A">Aƒ·x‚p—D"@"·}—EAƒ·x‚p—9"<"·}—D@ƒ·xƒsƒnƒiƒdƒ_ƒZƒUƒPƒKƒF‚p—A">"·}—9<ƒ<"·}—A9">ƒ·}—@"D"<9ƒD9"<"·}—@ƒ<9A">"·}„@—>"B"A·}—>@D"@">B·}ƒxƒsƒnƒiƒdƒ_ƒZ‚p—>"DA"@·}ƒxƒsƒnƒi‚p}—>A@"D"ƒ·}—E"@DA"ƒEA·}—A">"@·}—?">">A`>A"·}—>"?`>D"@"·}—Aƒ·x‚p—@·}—C"G"Dƒ·x‚p—G·}—;"@"Cƒ="·}—?";@ƒ9";"=·}—?ƒ9=";9"·}@}`}`—9=="·}—9"ƒ·x‚p—=B"·}—9E"ƒ·xƒs‚p—B9"="·}—Eƒ·xƒsƒnƒi‚p—=A">"9·}… —>"·}—>AA"`E"A>@"·}ƒx‚p—>"@A"·}—Eƒ·xƒs„0—>">AB"·}@}—9"=">Bƒ·xƒsƒnƒiƒd‚p—@)·}—=)=9ƒ·x‚p—B)G)·}—@=ƒ·x‚p—BG·}—=·|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0—=ÿ/MTrkÒ¸ÈNÿJAZ2˜9)ÿYÿY¸x ^[@]@HKJ<}}ÿEcho¸C˜@)ƒ¸x‚p˜9>)9)¸}˜@ƒ¸xƒsƒnƒiƒdƒ_„0}˜;)>@)9@¸}˜9)@);@ƒ¸xƒsƒnƒiƒd‚p}˜9)>)@9ƒ¸xƒsƒnƒiƒdƒ_„0}˜;)@)9>@@)¸}˜@;9)ƒ¸xƒsƒnƒiƒd‚p˜9"¸}˜<"9@ƒ9¸}˜9"<>"ƒ¸xƒP}˜A">99"`¸}`˜A¸}˜9>"9"`9"@"¸}˜>9ƒ¸xƒs„0}˜9"@>"9P¸xƒs‚p˜>9¸}˜9"@"ƒ@";"¸}˜9@ƒ@"9"¸}˜;@ƒ¸xƒsƒnƒiƒd‚p}˜<"9"9@ƒ9<¸}˜9">"`A">9"¸}˜9`¸}`˜>"¸}˜9"9A`9"¸}˜@"9>ƒ¸x‚p˜@9<"¸}˜9"ƒ¸}˜<9"9>"ƒ¸xƒs‚p˜9>9"@"¸}ƒxƒsƒn‚p˜>%9¸}˜@7%ƒ¸x‚p˜9%>%7>¸}ƒx‚p˜9¸}˜<"7">„@<"A"¸}˜7<@¸}˜;%A<@%ƒ@¸}˜;>);)ƒ@%>¸}˜9%;ƒ¸x‚p˜9@¸}˜9">"ƒ¸x‚p˜@"9¸}˜>;"ƒ¸xƒs‚p˜;"@>";¸}@˜@";"¸}˜>;@;@¸}˜@"9"ƒ¸x‚p˜@;">"¸}˜9ƒ¸}˜>;9">"@>A"¸}˜99"@7"¸}˜9<"Aƒ¸x‚p˜@"¸}˜7;"<ƒ;"@¸}˜>";ƒ>9"@"¸}˜;ƒ¸xƒsƒnƒiƒdƒ_ƒZƒUƒPƒKƒFƒAƒ<ƒ7ƒ2ƒ-„0˜>"99"@¸}@˜>@"¸}˜;"9ƒ¸x‚p˜@;¸}˜;"8"ƒ¸xƒs‚p˜;"¸}˜89";ƒ¸x‚p˜C"9;<"¸}ƒ˜9">"<¸}˜Cƒ¸xƒsƒnƒi‚p}˜;"98">ƒ;8¸}˜@"9"ƒ@9>"9"¸}@}`˜9"9>="¸}`˜8";"¸}˜=9ƒ¸x‚p}˜9";>"8ƒ`;">"¸}˜>9`¸}˜>>"?";`>";"¸}˜>?`;;"¸}˜B">ƒ¸}˜="8"B;ƒ¸}˜9"@"8=… 8"@"9¸}˜@`¸}˜9"@"8@ƒ¸x‚p˜="B"¸}˜9@ƒ¸xƒs‚p˜B@"9"¸}˜=ƒ¸xƒsƒnƒi‚p˜@9¸}˜<"9"ƒ>"¸}˜9"9<`A">¸}˜9"9`¸}`˜9"¸}˜9A>"`9>¸}˜@"9"ƒ¸x‚p}˜@9<"9"ƒ9"9>"¸}˜<ƒ¸xƒs‚p˜@"¸}˜9">9ƒ¸xƒsƒnƒiƒd‚p˜8)¸}˜9@=)ƒ¸x‚p˜B)¸}˜=;)8ƒ¸x‚p˜;=¸}˜B¸|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0˜=ÿ/MTrkC°ÿJAZ2°yxr(ÿY° @ÿ March Windsÿ/simutrans-124.3/simutrans/music/28-Road-to-Warm-Places.mid000066400000000000000000001101461474050137200232630ustar00rootroot00000000000000MThdxMTrkÿCopyright (C) 2007 shunterð~ ÷ÿJAZ2ÿÿ 2006.10.06ÿRoad to Warm Placesÿ~j' .' (. ÿ~j  ''  .' ÿ~j ..' . ' .'ÿ~j !.  '  . ÿ~j'      ÿ~j !     ÿvj     ÿj'ÿnjÿXÿQÈÿYÿ/MTrkß±Á&ÿJAZ2±]ÿGeneral MIDI± ÿBass±f{[@ÿ @ƒ`‘$e<$$c4$$h9$$j#$Z$Z$ $g$"$f1$ \;$i<b$$q1$ $e0$ $e<$$c4$$h9$$j#$Z$Z$ $g$"$f1$ \;$i<b$$q1$ "e0" #e<##c4##h9##j##Z!Z! #g#"#f1# \;#i<b##q1# ,e0, b<+`4+e9+g#++h++d(+!a!!b!!f!!d8!!g!!C!&e<&2a22k2&d9&2d12 &c3& 2a92&f1& 2`<&h24&2`62&h0& 2_22k2&i,&2a62&j.&&c+&!f<-b!3- !e9!-e1- !d3! -b9-!g1! -a<-!i4!-a6-!i0! -`8-!j,!-b6-!k.!-d+-#e<#*`*/k/#d9#/d1/ #c3# /a9/#f1# /`<#h/4#/`6/#h0#*/k/#i,#/a6/#j.##c+#*f<6b*36 *e9*6e16 *d3* 6b96*g1* %a:%c<+a4+f9+h#+!^<-\!--m-!a9!-c--m-&f<&2b32 &e9&2e12 &d3& 2b92&g1& 2a<&i24&2a62&i0& 2`82&j,&2b62&k.&2d+2!e!b!!!f!!d8!!g!!q!&e<-`&-2k2&d9&2d12 &c3& 2a92&f1& 2`<&h24&2`62&h0&*2k2&i,&2a62&j.&&c+&!e2&282)2Q2 2P2 2B!22F2'2G2)2U2#-J--Z--A-&-5-'-P-!-.-'-8-&-M-$-@- -D--R-$->-&-8-)-g-)-B!--F-'-G-)-U-#/Q/)/I/./J//J//M//I//P/)/0/+/K/,/D/-/R/,/G/+/W/-/K//H//E/)/I/)/U/,/2/)*Q*)*I*.*J*.*M**I**P*)*?*+*K*,*/*-+Q+)+I+.+J+.+M++I+-J-$-A-&-5-'-0--6-2J2,2A2,2R2+2Q 22U22S2'2L2)2P2+2N2)2G2,2Y2)2E2*2n2&2,2.2D2,2\2)212,-J--Z--A-&-5-'-P-!-.-'-8-&-M-$-@- -D--R-$->-&-8-)-g-)-B!--F-'-G-)-3-#/J/,/A/,/R/+/Q //U//S/'/L/)/P/+/N/)/G/,/Y/)/E/*/n/&/,/./D/,/\/)/1/,*Q*)*I*.*J*.*M**I**P*)*?*+*K*,*/*-+Q+)+I+.+J+.+M++I+-S-,-A-,-R- -Z-$-U-/J//Z//A/&/5/'/P/!/./'/8/&/M/$/@/)/R/$/>/&/8/)/g/)/B!//F/'/G/)/U//Z/ +J+$+A+&+5+'+P+!+.+'+8+&+M+$+'+)-J-$-A-&-5-'-P-!-.-'-8-&-M-$--- -,-*J**Z**A*&*5*'*P*!*.*'*8*&*M*$*@*)*R*$*>*&*8*)*g*)*B!**F*'*G*)*3**6* +Q+)+I+.+J+.+M++I++P+)+?+++K+,+D+--S-,-A-,-R- -Z-$-U-.J.$.A.&.5.'.P.!/J/$/A/&/5/'/P/!/./'/8/&/M/$/'/)/Q/)/I/./J/./M//I//`/$/-////-J-$-)-&+Q+)+I+.+J+.+M++I++P+)+?+++K+,+D+--J-$-A-&-5-'-P--Z-J--$-K-&+;+$+1+&*J**Z**A*&*5*'*P*!*.*'*8*&*M*$*9*)*R*$*>*&*8*)*Q* *P* *B!**F*'*G*)*3*#+J+$+A+&+5+'+P+!+.+'+8+&+M+$+-+ +,+-S-,-A-,-R- -Z-$-U--S-'-S-)-P-+-N-)2J2,2A2,2R2+2Q 22U22S2'2L2)2P2+2N2)2G2,2Y2)2E2*2n2&2,2.2D2,2\2)2S2,-J--Z--A-&-5-'-P-!-.-'-8-&-M-$-@-)-R-$->-&-8-)-g-)-B!--F-'-G-)-3--6- /J//Z//A/&/5/'/P/!/./'/8/&/M/$/@/ /D//R/$/>/&/8/)/g/)/B!//F/'/G/)/3/#*S*,*A*,*R* *Z*$*U**S*'*S*)*P*+*.*)+J+$+A+&+5+'+P++Z+-J-$-A-&-5-'-P-!2J22Z22A2&252'2P2!2.2'282&2M2$2@2 2D22R2$2>2&282)2g2)2B!22F2'2G2)2U2#-J--Z--A-&-5-'-P-!-.-'-8-&-M-$-@- -D--R-$->-&-8-)-g-)-B!--F-'-G-)-3-#/J/,/A/,/R/+/Q //U//S/'/L/)/P/+/N/)/G/,/Y/)/E/*/n/&/,/./D/,/\/)/S/,*S*,*A*,*R* *Z*$*U**S*'*S*)*P*+*N*)+J+$+A+&+5+'+0+!-S-,-A-,-R- -Z-$-U-/J/,/A/,/R/+/Q //U//S/'/L/)/P/+/N/)/G/,/Y/)/E/*/n/&/,/./D/,/\/)/1/,+J+$+A+&+5+'+P+!+.+'+8+&+M+$+9+)-J-$-A-&-5-'-P-!-.-'-8-&-M-$-9-)*J*,*A*,*R*+*Q **U**S*'*L*)*P*+*N*)*G*,*Y*)*E***n*&*,*.*D*,*\*)*S*,+J+$+A+&+5+'+P+!+.+'+8+&+M+$+'+)-J-$-A-&-5-'-P-!.J.$.A.&.5.'.0.!/J/$/A/&/5/'/P/!/./'/8/&/M/$/9/)/J/$/A/&/5/'/P//Z//;/$/S/&-J-$-)-&+Q+)+I+.+J+.+M++I++P+)+?+++K+,+/+--J-$-A-&-5-'-P-!-J-$---&+;+$+1+&*J*$*A*&*5*'*P*!*.*'*8*&*M*$*9*)*R*$*>*&*8*)*Q* *P* *B!**F*'*G*)*U*#+J+$+A+&+5+'+P+!+.+'+8+&+M+$+-+ +,+-J-$-A-&-5-'-P-!-.-'-8-&-M-$--- -,-2J2$2A2&252'2P2!2.2'282&2M2$292)2R2$2>2&282)2Q2 2P2 2B!22F2'2G2)2U2#-J--Z--A-&-5-'-P-!-.-'-8-&-M-$-@- -D--R-$->-&-8-)-g-)-B!--F-'-G-)-3-#/J//Z//A/&/5/'/P/!/./'/8/&/M/$/@/)/R/$/>/&/8/)/g/)/B!//F/'/G/)/U//Z/ *J*$*A*&*5*'*P*!*.*'*8*&*M*$*'*)+J+$+A+&+5+'+P++Z-S+-,-A-,-R- -Z-$-3-2J22Z22A2&252'2P2!2.2'282&2M2$2@2)2R2$2>2&282)2g2)2B!22F2'2G2)2U22Z2 -Q-)-I-.-J--J--M--I--P-)-0-+-K-,-D---R-,-G-+-W---K--H--E-)-I-)-U-,-2-)/J//Z//A/&/5/'/P/!/./'/8/&/M/$/@/ /D//R/$/>/&/8/)/g/)/B!//F/'/G/)/U/#*Q*)*I*.*J*.*M**I**P*)*?*+*K*,*/*-+Q+)+I+.+J+.+.++++-J-$-A-&-5-'-P-!2S2,2A2,2R2 2Z2$2U22S2'2S2)2P2+2N2„ ²@ÿ/MTrk å¶ÆZÿJAZ2¶{QÿGeneral MIDI¶ ÿ Polysynthÿ @H¶[2]@Ï–ZGZGVGZGVG[GZGZGZGZGZGLRG‚"NVLwORNvQUOPQQT‚-VU QV URxSM UlQSSQQ\‚]Q VX3UUVzSL UlQTSQQY‚hS[ QSQSzLPQhNS L$NNO‚DN!NPfNNO=OTNkOQTiQQN Q*QXƒ$VWQwUSVtSLUoSQSQQYƒ%VUQuUQ VkQQUpSSQS Se‚zS(SUzQTScLPQtNRLNNUƒtNƒGTxJJGqJNOyLLN.NMLƒQPNtOJQqNL OoLON-NSLƒELNyIMEoNFItLK N(NO Lƒ N QSzOOQfNMOoNLO‚fJML7LCJ9NQLNNO2OPN=NQO‚$LNNiNNLqJKNJJM*J LM)LLMƒ"LIHxNSIN NV4OPN;NR O‚NLNyNMLuJJN!JJM0JGK>LRG‚"NVLwORNvQUOPQQT‚-VU QV URxSM UlQSSQQ\‚]Q VX3VUUzSL UlQTSQQY‚hS[ QSQSzLPQhNS L$NNO‚DN!NPfNNO=OTNkOQTiQQN Q*QXƒ$VWQwUSVtSLUoSQSQQYƒ%VUQuUQ VkQQUpSSQS Se‚zS(SUzQTScLPQtNRLNNUƒtNƒGTxJJGqJNOyLLN.NMLƒQPNtOJQqNL OoLON-NSLƒELNyIMEoNFItLK N(NO Lƒ N QSzOOQfNMOoNLO‚fJML7LCJ9NQLNNO2OPN=NQO‚$LNNiNNLqJKNJJM*J LM)LLMƒ"LIHxNSIN NV4OPN;NR O‚NLNyNMLuJJN!JJM0JGK>LRG‚"NVLwORNvQUOPQQT‚-VU QV URxSM UlQSSQQ\‚]Q VX3UUVzSL UlQTSQQY‚hS[ QSQSzLPQhNS L$NNO‚DN!NPfNNO=OTNkOQTiQQN Q*QXƒ$VWQwUSVtSLUoSQSQQYƒ%VUQuUQ VkQQUpSSQS Se‚zS(SUzQTScLPQtNRLNNUƒtNÿ/MTrk ‡µÅÿJAZ2ÿ @µgÿGeneral MIDIÿDistortion guitarÿ µ @{]@[Î$•9Z2\m92D9]2`V29ƒ 2U9U29!9U2U 29)2^9_629B2Y9Y292 4R-SR-4b-c4^ƒ-44\-_ 4-#-W4R-4#-W4S-4)4_-a2-4 6W/M`6/L/e6`ƒ/6"6R/[‚^/6 1W*Ym1*D1Z*]V1*V2U+[^2+24+92+Z-Y4Y4-%4Y-[o-42\9Z392B2`9]V92ƒ 9U2U29!9U2U 29)9_2^692B2Y9YY92-M4W&4-J4`-eƒ4-"4R-[ƒ -46]/c\/6/^6Z>/6‚f/\6Z 6/6S/[6/6Q/S6/*^1X\*11U*Y>1*n2U+[+2+`2W+2[4Y-Y4-#-Y4Y4-%4Y-[+-44Y-Y 4- -Y4Y -4 /c6]\/66Z/^>6/‚f6Z/\ 6/6S/[6//S6Q6/U2Y+Yƒ2+‚24\-W+-4*\1Z31*B*`1]V1*ƒ *U1U*1!*U1U *1)*^1_61*B1Y*Y21* +^2X+2+Y2U>+2n4U-[^-4-`4W4-Z4Y.Y4.%4Y.[o.46X/^\/6/Y6U>6/n6U/[H6/(/\6V6/-\4Ve4-2X+^\+22U+Y>+2n-i4c-44T-K-4(4S-Yd4--7474 -+Y2S*2++\2\2 +1\*b\*1*]1Y>1*‚f*[1Y *1*Z1R1**R1P1*!1]*_j*1 2V+L&2+J2_+d‚f+2>4T-^ 4-%4S-U-4#4Y-T4-'4`-c-4W9\2b\292]9Y>92‚f2[9Y 292Z9R929P2R92!2_9]j29 4\-b\4--]4Y>4-‚f-[4Y -4-Z4R4--R4P4-!4]-_j-4 6Z/\36/B/`6]V6/ƒ /U6U/6!6U/U /6)6_/^66/B/Y6YY6/1X*^\1*1U*Y>*1n2U+[^2++`2W2+4Y-Y4-#-Y4Y4-%-[4Y+-4-545 4-+2M9W&92J2e9`ƒ92"9R2[ƒ 29-S4R4-`-c4^ƒ-4-_4\ 4-#4R-W-4#-W4S4-)4_-au-4/S6R6/`6^/cƒ6/6\/_ 6/#6R/W/6#6S/W/6)6_/au/61V*\1*1_*_1*#*W1S>1*n2U+[+22W+`+2[4Y-Y4-#-Y4Y4-%4Y-[+-445-5 4-»o2b9\292]9Y>92‚f9Y2[ 929R2Z299P2R92!2_9]j29 -S4R-4`4^-cƒ-44\-_ 4-#4R-W-4#-W4S-4)4_-au-4/b6\\/6/]6Y>6/‚f/[6Y /6/Z6R6//R6P6/!/_6]j/6 *\1V1*1_*_1*#1S*W>1*n2U+[+22W+`+2[-Y4Y4-#4Y-Y4-%-[4Y+-44Y-Y 4- -Y4Y -4 9W2M&92J2e9`ƒ92"2[9R‚^29 -\4Zm4-D4]-`V4-ƒ 4U-U-4!-U4U -4)-^4_64-B4Y-YY4-6\/b\/6/]6Y>/6‚f6Y/[ /66R/Z6//R6P6/!/_6]j/6E1Y*Y‚^*1 2U+[^+2+`2W2+Z-Y4Y4-%4Y-[04-„#2W9P92$2a9] 29ƒµ@ÿ/MTrk7°ÿJAZ2ÿRoad to Warm Placesÿ/simutrans-124.3/simutrans/music/29-Runaway.mid000066400000000000000000000662011474050137200212760ustar00rootroot00000000000000MThdÀMTrkªÿ By ÿCopyright © 2007 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQ âÿY˜ÿQ ⃤ÿQ¡ ÿQ¡ ƒÿQR®`ÿQR®‚ ÿQ 'ÀÿQ 'Àÿ/MTrk éÿ!ÿStaffÀ°d° @°7n^77n^7>n^>7n^77n^7Fn^F7n^77n^7>n^>7n^77n^77n^7>n > @n @ 7n^77n^7>n^>7n^77n^7Fn^F7n^77n^7>n^>7n^77n^77n^77n 7 5n 5 7n^77n^7>n^>7n^77n^7Fn^F7n^77n^7>n^>7n^77n^77n^7>n > @n @ 7n^77n^7>n^>7n^77n^7Fn^F7n^77n^7>n^>7n^77n^77n^77n 7 5n 5 7n^77n^7:n : 7n^77n^7:n^:n^>n^>>n^>6n^6>n^>>n^>6n^6>n^>>n^>>n^>>n^>n^>n^>>n^>6n^6>n^>>n^>6n^6>n^>>n^>>n^>>n^>n^>n^>>n^>6n^6>n^>>n^>6n^6>n^>>n^>>n^>>n^>n^>n^>>n^>6n^6>n^>>n^>6n^6>n^>>n^>>n^>>n^>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>‘2n‘6n‘>n^‘2‘6‘>‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>‘2n‘6n‘>n^‘2‘6‘>‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>‘2n‘6n‘>n^‘2‘6‘>‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>‘2n‘6n‘>n^‘2‘6‘>‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>B‘2n‘6n‘>n^‘2‘6‘>‘2n‘6n‘>n^‘2‘6‘>‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>B‘7n‘:n‘>n^‘7‘:‘>‘5n‘:n‘>n ‘5‘:‘> ‘5n‘:n‘FE`>0>FAF0>‚ A0AF`>F0A`>F>0>F„>9F`AF09`@FAƒ`AF0@`A>F>=Fƒ`>F?F=0@F?>`>F0@`„@>F0<`>0>F‰>pHF`H0HFƒ`HEFHFE`H0JFHF0H„@JFFFFFƒ`F0FF0HF0HF0@F`EF0@„E0>F>AFCF0ACAF0CFA‚ AFC`F0C>@F`@>F@F0>09F@`909F`>F09`>AF0A`EF`FF0E`FFFEF0EEFF0E0>Fˆ >ƒ`VFˆPV0RF`R0RF`QF0R`VFQ„VTF`VF0T`OFV„TFOUFT`VF0Uƒ`VQF`TF0Q`LFT„LOF`PF0O`QFP…PQ„=F0=>F`>F>CF>„F0E0>F>@F>ƒ0@0@F0@AF`>F0A`9F>‡@9‚PJFJEF`MF0Eƒ0MLFJFLJQF„pOFQOFO„MFO`OF0MQF0O0LFQ„@QF0LXFQ@X0XFƒVF0X`YFV„pXFYVF0XV0VF‚ VFV`YF0V0RFY„R0QF`PF0Q`QFP„pYFQYUFƒ`WFU0XFW`UF0X`UVF‡pVƒ`JF0LFJ0JFLˆPJFF`F0FF`EF0F`JFE„JHF`JF0H`CFJƒ`HF0C`IFHJF0Iƒ`EF0J0HF0E`@FH„@CF`DF0C`EF0D†`Eƒ>F0>0>F>CFƒ`C0F`>F>@F>ƒ0@0@F0@AF`A>F9F>†09ƒ`JFJEF`MF0E0QF0M‚POF0Q`OMFMOF0QF0Q0QFOƒ`QOFOFO„MFO`OF0M0QFO0LF0Q„@QFLQXF@X0XFpX0XF`VF0X`VFV@YFVƒ0XF0Y`XVF‚PV0VFVFV`YF0V`YRF„QFR`PF0Q`QFP„pQYFUFYƒ`XF0U`UFXUVF‡pV•EFDFDxEFEƒ0E0EF>FE`>0>FAF0>‚ A0AF`>F0A`„@<>F„>ÿ/MTrkŒ±Á9ÿJAZ2±]2ÿGeneral MIDIÿTromboneÿYÿYÿÿ±o "[2ÿ @±@HKJ<}CƒHK "[2]2x@J<CÁ9§`‘F/>(A+ >AF A/F/>& AF> >(A.F)>AF F/A/J/PFJAp>+C/:( >:C C/:&>/ :>C C):(>.:>C F/>/C/PCF>p=(@+E/ @E= E/=&@/ =E@ @.=(E)=@E @/E/I/P@EIpE/=(@+ @=E =&@/E/ @E= @.=(E)=E@ E/I/@/PE@IpE$J$M(MJE@J"E M!MJE@JEMMEJ E$J$M$ JEMQ+J+M+0QMJ><905+>95 9/>/5& 59> 9.5(>)5>9 >/A/9/PA9>h><905+>95 5&>/9/ 59> 9.>)5(5>9 >/A/9/P>A9p>(A+F/ >FA >&A/F/ >FA A.F)>(>FA A/F/J/PAFJp@+E/<( @<E <&@/E/ @E< E)>(@.>E@ E/J/@/PE@JpJ$M(E$MJE@M!J"E MJE@MJEEMJ M$E$J$ EJMM+Q+J+0QMJE<@0=+E@= @/E/=& E=@ :(C)>.:>C C/F/>/PC>Fp@+=(E/ @=E @/E/=& E=@ 9.>)5(5>9 9/A/>/P>A9p<+A/9( 9A< 9&)9.59> 9/>/A/PA9>pA+F/>( A>F >&A/F/ >FA F)A.>(>FA J/F/A/PJAFhF<A0>+FA> >&A/F/ FA> F)>(A.>AF J/A/F/PJAFp@(C+H/ H@C @&C/H/ CH@ C.H)@(@CH C/H/L/PLCHp5(9+>/ 95> 5&9/>/ 59> >)5(9.5>9 A/9/>/PA9>pO$R(J$ORJ@O"J R!ROJ@RJORJO Q$L$U$ QLUX+Q+U+0QXU><905+>95 5&>/9/ 95> >)5(9.59> >/A/9/P>A9p:(C/>+ C:> >/C/:& >:C C)>.<(<C> >/C/H/PHC>0<00(+9)+?+C ++90+`-<‚ -`&<0&(-9)-?-C --90-`-<‚ -@J$E$M(MJE@M!E J"MJE@JMEEMJ E$J$M$ EJMQ+J+M+0MJQ0&B2B†&2&B2BƒÁ9±@J< "[2xHK]2CƒX‘><905+>59 >/5&9/ 95> 5(>)9.5>9 A/9/>/P9>A&B2B†2&02&(H<@+C0HC@ @&C/H/ @CH H)C.@(@CH H/C/L/PLCHpF/>(A+ >AF >&F/A/ FA> A.F)>(>FA A/F/J/PAFJ%<0%(-9)-?-C --90-`-<‚ -`%<0%(-9)-?-C --90-`-<‚ -@J$M(E$MJE@E J"M!MJE@JMEEMJ E$J$M$ EJMM+J+Q+0QJMC<<+>0C<> <&>/C/ >C< :(C)>.:C> F/>/C/P>FCp9(<+A/ 9<A A/9&/5( 95> 9/>/5& 59> =(E)@.=E@ E/I/@/PE@Ih><5+90>95 9/5&>/ 9>5 C)>.:(:C> >/C/F/P>FCpE/@+=( @E= @/E/=& @=E =(@.E)=@E E/I/@/PE@I&B2B†2B&B2&ƒÁ9±]2[2xHK "J<C@ƒX‘><905+>95 >/5&9/ 95> >)9.5(59> 9/>/A/P9>Ap9+>/5( 9>5 5&>/9/ >95 >)5(9.59> 9/>/A/P>A92&`:(>+C/ :C> C/:&>/ :>C >.:(C):C> >/C/F/PC>Fp=(@+E/ @=E @/E/=& @=E =(E)@.=@E I/@/E/P@EIhE<=+@0E=@ @/E/=& @=E E)@.=(=@E @/I/E/P@EIp>/5(9+ 59> >/9/5& 5>9 5(9.>)59> >/A/9/P>9ApA+>(F/ AF> >&A/F/ FA> F)A.>(>FA A/F/J/PJAFpO$R(J$ROJ@R!J O"ORJ@JORJRO R$J$O$ JORV+R+O+0RVO0%<0%(-9)-?-C --90-`-<‚ -`%<0%(-9)-?-C --90-`-<‚ -@J$M(E$MJE@E M!J"JME@JMEEMJ J$M$E$ JEMM+J+Q+0QJM><905+>95 5&9/>/ >95 5(>)9.59> A/9/>/PA9>p>/5(9+ >95 5&9/>/ 5>9 9.>)5(5>9 >/A/9/P>9Ap5(9+>/ >95 5&9/>/ 5>9 >)9.5(5>9 A/9/>/P>A9pF/>(A+ F>A >&A/F/ >FA F)A.>(>AF A/F/J/PAFJhC<<+>0C<> <&>/C/ C>< E)=(@.=@E I/@/E/PI@Ep5(9+>/ 5>9 5&9/>/ >59 :(>.C):C> >/C/F/P>CF%<0%(-9)-?-C --90-`-<‚ -@M(E$J$MJE@E J"M!JME@EJMEMJ E$J$M$ EJMM+Q+J+0MQJ><905+>59 5&9/>/ >59 >)5(9.59> A/>/9/P>9Ap<(>+C/ C<> >/C/<& C>< :(>.C):C> C/F/>/PC>Fp<+A/9( <9A 9&<905+>59 5&9/>/ >59 E)@.=(=@E I/@/E/P@EIp>/5(9+ 9>5 9/>/5& >95 >.C):(:>C >/C/F/P>FCp@+E/=( @=E @/E/=& =@E @.E)=(=E@ @/E/I/PIE@h><5+90>95 >/5&9/ >59 5(9.>)5>9 9/>/A/P9>Ap:(>+C/ :C> :&>/C/ C:> >.:(C):C> F/C/>/PC>Fp@+E/=( =@E @/E/=& E@= =(@.E)=E@ I/@/E/PIE@pJ$O(E$JOE@E O!J"JOE@JOEOEJ E$J$M$ JEMM+J+Q+0QMJC<>0:+C>: C/>/:& C:> >.:(C):C> F/>/C/P>CFp@+E/=( @E= =&@/E/ =@E @.E)=(=@E @/E/I/P@EIp=(@+E/ @E= E/=&@/ =@E =(E)@.=@E @/E/I/P@IEh><5+90>95 >/5&9/ 9>5 >)5(9.59> >/A/9/P9>ApF/>(A+ F>A A/F/>& >AF >(A.F)>FA F/J/A/PAFJp>+C/:( :C> :&>/C/ C>: >.C):(:C> >/C/F/PCF>pE/=(@+ E=@ E/=&@/ =@E @.E)=(=E@ @/E/I/P@IEp@+=(E/ E=@ =&E/@/ =@E @.=(E)=E@ E/@/I/PIE@pM(J$E$MJE@E M!J"MJE@JEMMEJ J$M$E$ JEMJ+M+Q+0JQM0&B2B†02&‚P±@x]2HKÁ9±C "J<[2ƒX‘><5+90>59 >/9/5& 9>5 5(>)9.5>9 >/A/9/P9>Ah><905+>59 >/9/5& >95 9.5(>)59> A/9/>/PA>9h><5+90>95 >/9/5& 59> 9.5(>)59> A/9/>/PA>9pF/>(A+ FA> A/F/>& >AF >(A.F)>AF F/J/A/PFAJp@(C+H/ HC@ @&H/C/ C@H C.@(H)@CH L/C/H/PLHC±}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@ÿ/MTrk (²Â!ÿJAZ2²[2ÿGeneral MIDIÿBassÿYÿYÿÿ²d @@]2ÿ @²HKJ<}Cƒ @[2x]2@HKJ<CÂ!§’"O@")O@)"Q@")M@)+O@+&O@&+Q@+&M@&!M@!(N@(!N@!(M@(!M@!(N@(!N@!(M@(&^P&p!] ! !^ !@!^0!0!^ ! &N@&!M@!&N@&!P@!&N@&!M@!&N@&!P@!"O@")O@)"Q@")M@)!M@!(N@(!N@!(M@(&^P&p!] ! !^ !@!^0!0!^ ! !N@!(M@(+N@+&P@&!O@!(O@(&Q@&!M@!)M@)$N@$&N@&!M@!"N@")PP)p"NP"p)NP)p"N@")M@)"N@")P@)$O@$+O@+$Q@$+M@+&M@&!N@!&N@&!M@!+^P+p&] & (^ (@(^0(0(^ ( &N@&!M@!&N@&!P@!+O@+&O@&+Q@+&M@&+X@++N+O+T+ +[@+P!X@! (N(P(T( ([@(P!X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P&^P&p!] ! !^ !@!^0!0!^ ! &^„&@&^&@&^ƒ²x @]2HKJ<[2@CÂ!ƒ@’&!M@!&N@&!P@!&^„&@&^&@$N@$+M@+$N@$+P@+"O@")O@)"Q@")M@)!X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P!X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P&^P&p!] ! !^ !@!^0!0!^ ! +N@+&M@&+N@+&P@&)O@)$O@$)Q@)$M@$!M@!(N@(!N@!(M@(&N@&!PP!p!NP!p(NP(p&N@&!M@!+N@+&P@&!O@!(O@(!Q@!(M@(&^„&@&^&@&^ƒ²@x[2CJ<Â!² @]2HKƒ@’&!M@!&N@&!P@!&O@&!O@!&Q@&!M@!+M@+&N@&+N@+&M@&!N@!(PP(p!NP!p(NP(p!N@!(M@(!N@!(P@(&O@&!O@!&Q@&!M@!"M@")N@)"N@")M@)+^P+p&] & &^ &@&^0&0&^ & !X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P!X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P&^P&p!] ! !^ !@!^0!0!^ ! &N@&!M@!&N@&!P@!&O@&!O@!&Q@&!M@!&M@&!N@!&N@&!M@!"N@")PP)p"NP"p)NP)p+N@+&M@&!N@!(P@(&O@&!O@!+Q@+&M@&!X@!!N!O!T! ![@!P!X@! (N(P(T( ([@(P&^P&p!] ! !^ !@!^0!0!^ ! &N@&!M@!&N@&!P@!+O@+&O@&+Q@+&M@&)M@)$N@$)N@)$M@$!N@!(PP(p!NP!p(NP(p&N@&!M@!!N@!(P@(&O@&!O@!+Q@+&M@&!M@!(N@(!N@!(M@(&N@&!M@!&N@&!P@!+O@+&O@&+Q@+&M@&!M@!(N@(!N@!(M@(&^P&p!] ! !^ !@!^0!0!^ ! +N@+&M@&+N@+&P@&!O@!(O@(!Q@!(M@(!M@!(N@(!N@!(M@(&N@&!M@!&N@&!P@!"O@")O@)"Q@")M@)+O@+&O@&+Q@+&M@&!M@!(N@(!N@!(M@(!M@!(N@(!N@!(M@(&^P&p!] ! !^ !@!^0!0!^ ! &^„&@&^&@&d &‚`² @]2@xÂ!²HK[2J<Cƒ’&N@&!M@!&N@&!P@!&N@&!M@!&N@&!P@!&N@&!M@!&N@&!P@!"O@")O@)"Q@")M@)$M@$+N@+$N@$+M@+²}’&T²|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0’&²@ÿ/MTrk f³Ã=ÿJAZ2³ÿGeneral MIDIÿBrassÿYÿYÿÿ³x ^]2ÿ @³@HKJ<}[2Cƒx ^[2]2@HKJ<CÃ=§`“5).2' 25.‚`.2'5) 25.‚`+.'2) .2+‚`+.'2) +2.ŽX)9-9&1&)-G-;)6&1&-)/&(),-/ &-)@.5)2' .52‚`5).2' .25ˆX&1)9-9&-)G-;)6&1&)-/&(),-/ )-&‰@-4)1' 4-1‚`-)&)' )&-ˆ`.2'5) 52.‚`5).2' 25.ˆ`7)04' 407‚`7)04' 407ˆX29+1.9+2.G.6+12;+2./1,4/-( 41-‰@.'2)+ +.2‚`0'+2) 2+0‚! 5>9@59% 59@9%2929%5 59p9!14 941@-4% 4-@4%-4-4* 4H&1-9)9-&)G-;)6&1-&)/-/&(), -)&‚`2<>B„ >2 28>:>2>;2;>22=>>2> 2>>@ >22<>Bƒ³@Ã=³ ^CxHK[2J<]2‰“2<>B„ >2 28>:>22;>;>2>>2=2> 2>>@ >22>†`2'5). 52.‚`2'5). 2.5‚=!49 94=@49% 94@19%919%4 49p419! 194@-4% 4-@4%-4-4* 4p=!49 4=9@49% 94@19%9149% 94p49!1 194@-4% -4@-4%4-4* 4H-9&1)9-)&G)6-;&1)-&/),&(-/ &)-‰@-')0) 0)-‚`-')0) 0)-ˆ`)'-)& &)-‚`-1'4) 4-1ˆ`-1'4) 41-‚`1'4)- 14-‚2<>B„ >2 28>:>22;>;>2>>2=>2 2>>@ 2>2<>Bƒ³x[2]2@HK ^Ã=³CJ<‰`“)'&-) -&)‚`&)'-) &)-‚2>†`-1'4) 14-‚`4)-1' 4-1ˆ`-)&)' )&-‚`)'-)& )&-ˆX+1.929.+2G.6+12;.+2/2/+(., 2+.‚`=!49 4=9@9%4 49@19%919%4 49p149! 149@4%- -4@4%-4-4* 4p91!4 941@9%4 49@19%919%4 94p%49! 94%@-4% -4@4%-4-4* 4H-9&1)9)-&G)6&1-;-)&/&(),-/ )-&‰@)'-)& )&-‚`-)&)' -&)ˆ`.2'5) 5.2‚`.5)2' .52ˆ`&)'-) )&-‚`+.'2) .2+‚9=!4 49=@9%4 94@9%19149% 49p9!14 941@4%- -4@4%-4-4* 4H)9-9&1)-&G&1-;)6&)-/),-/&( )&-‰@0'2)+ 2+0‚`.'2)+ +.2ˆ`1'4)- 14-‚`1'4)- 4-1ˆ`&)'-) )&-‚`+.'2) +.2Ž`+.'2) +.2‚`+.'2) 2+.ˆX&1+9-9+&-G-;+6&1+-&/),-/&( &)-‰@-1'4) 14-‚`-1'4) -41Ž`2'5). 2.5‚`2'5). .52‚`+.'2) +2.‚`+.'2) .2+ŽX)9-9&1&)-G&1-;)6&-)/-/&(), )-&‚`2<>B„ 2> >:28>2>;2;>2>>2=>2 2>>@ 2>>F2CP>2‚0³C@[2]2 ^xJ<HKÃ=•`“5).2' .52‚`.2'5) .52ˆ³}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@ÿ/MTrk/´Ä.ÿJAZ2´HKÿGeneral MIDIÿHarpÿYÿYÿÿ´x @[AC@]AJ<}ÿ @ƒ´]Ax @@[AHKJ<CÄ.¬ ”e ´@ ”e…`b b„ i%i0d d„ i%i0d d@V(VV% V/Y'Y ]&] V'V Y'Y]( ]/b&b V(VV% V/Y'Y´@ @”]&] V'V Y'Y ](] b&b„b%b0] ]„ b%b0] ]…`e e„ i%i0d d@V(VV% V/Y'Y ]&] V'V´@ ”Y'´@”Y]( ]/b&b V(VV% V/Y'Y ]&] V'V Y'Y ](] b&b„g%g0b b…`] ]„ b%b0] ]…`e ´@”e„ j%´@”j0e e…`g g„ b%b0] ]@[([[% [/^'^ b&b ['[ ^'^b( b/g&g ](]]% ]/a'a d&d´@ @”]'] a'a d(d i&i„b%b0] ]…`b b@`'`P['[P['[([' []']PX'XPX'X(U' Ub'bP]']´@P@”]'](]' ]]']PX'XPX'X(U' UV(VV% V/Y'Y ]&] V'V Y'Y]( ]/b&b V(VV% V/Y'´@”Y ´@”]&] V'V Y'Y ](] b&b ´@”b ´@ ”bbbbb] ][Y[YYYV VV VV´@@”QVOQOM MM MJ JJ JJ JE EC CA AA>V'A>>V>>>9V(9´@”7´@”V75V55 V52 V(2V ´@@”b bbbbb] ][Y[YYYV VV VV´HKC @x@J<Ä.´]A[A†`”b%´@”b0] ]@´@@”b bbbbb] ][Y[YYYVVV VV´@@”QVQOOM MM MJ JJ JJ JE EC CA AA>V'A>>V>>>9V(9V´@”7´@”57V55 V52 V(2VVƒ`l%l0g g…`e e@a'aP]']P]'](]' ]]']PX'XPX'X(U'´@”Ua'´@”aP]']P]'](]' ]]']PX'XPX'X(U' UV(VV% V/Y'Y ]&] V'V Y'Y]( ]/b&b V(´@”VV%´@ ”V/Y'Y ]&] V'V Y'Y ](] b&b„g%g0b b…`` `„ i%i0d d…`d d„ g%g0b b…`d d@´@”b ´@ ”bbbbb] ][Y[YYYV VV VVV´@”Q´@”QOOM MM MJ JJ JJ JE EC CA AA>AV'>>V>>>9V(´@@”79V57V55 5V2 V(2V ´@”b ´@ ”bbbbb] ][Y[YYYV VV VV´@x @[A]AHKJ<CÄ.†`”b%´@”b0] ]…`] ]@Vƒ`g%g0b b…`d d„ i%´@”i0d ´@ ”d…`] ]„ j%j0e e@[([[% [/^'^ b&b ['[ ^'^b( b/g&g [([[% [/^'^ b&b ['´@”[ ^'´@”^ b(b g&g a'aP]']P]'](]' ]]']PX'XPX'X(U' UU'UP]']P]'](]' ]]']PX'´@”XPX'´@”X(U' UV(VV% V/Y'Y ]&] V'V Y'Y]( ]/b&b V(VV% V/Y'Y ]&] V'V Y'Y ](´@”] b&´@”b„b%b0] ]…`] ]„ b%b0] ]…`e e„ i%i0d d…`b b@a'aP]']P]'](]' ]]']PX'XPX'X´@(@”U' UV(VV% V/Y'Y ]&] V'V Y'Y]( ]/b&b V(VV% V/Y'Y ]&] V'V Y'Y ](] b&b´@„@”b%b0] ]…`b b„ e%e0` `…`d d„ i%i0d d…`b b„ i%i0d d„ b%b0] ]…`b b„ i%i0d d@V(V´@@”V% V/['[ ]&] V'V ['[]( ]/b&b V(VV% V/Y'Y ]&] V'V Y'Y ](] b&b„g%g0b b´@…`”d ´@ ”d„ i%i0d d„ b%b0] ]…`e e…`b b„ i%i0d d„ i%i0d d@V(VV% V/Y'Y ]&] V'V Y'´@”Y](´@ ”]/b&b V(VV% V/Y'Y ]&] V'V Y'Y ](] b&b ´@”b ´@ ”bbbbb] ][Y[YYYV VV VV´@@”VQQOOM MM MJ JJ JJ JE EC CA AA>V'A>>V>>9>V(´@”9´@”7V75V55 5V2 V(2V V* V‚`´[AÄ.´CHKJ<x @@]A†`@”b%b0] ]„ b%b0] ]„ b%b0] ]…`e e„ l%l0g g@´}”V$´|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0@”V´@ÿ/MTrk$Œ¹ÉÿJAZ2¹}ÿGeneral MIDIÿDrums¹C™#W¹J<HK@]™8¹ @ÿ @H¹[™8#P3?663P#N#H63;63P¹[™8¹J<@x @™#Q¹C]ɹHK™8#H63C63P#O#H6$3I63P#O88#P63C63P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P3L6%63P#T88#P6#3H36P#K#P3I6$36P#V88#P6$3I63P#N#P3I6$63P8#P8#P3C663P#Q#P63>63P#W88#P63?36P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#h1 81#P3I636P#a1 #1H63I63P89#c1 891#H63C63&.&&7&&=#d&#H6$3>&V6&3H918#W819#P3?663P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P#O88#P63C36P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#O8#P3C636P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P8L%#GQ%8L#QP66PL!#AL#H6 6_1#BL!88L1#H6 6_L!#JL#H6$ 6W19#GL%Q%8981QL#P66P#AL!L#H6 6_81#BL!8#L1H6 6_#JL!#LH6$ 6W911 8#h819#1P63I63P#a1 1#H63I63P#c81 9819#H63C63&.&&7&&=#d&#H6$3>&V63&H91#W8891#P3?663P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P#W88#P3?663P#N#H63;63P#Q88#H63C63P#O#H6$3I63P8#O8#P3C636P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63PL%Q%8#G8L#QP66P#AL!L#H6 6_1#BL!881L#H6 6_#JL!#LH6$ 6W91#h81 198#1P63I63P1 #a#1H63I63P#c1 89819#H63C63&.&&7&&=#d&#H6$&V3>6&3H19#W8891#P63?36P#N#H63;63P#Q88#H63C63P#O#H6$3I63P8#O8#P3C636P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P6%3L36P8#T8#P3H6#63P#K#P6$3I63P8#V8#P3I6$63P#N#P3I6$36P#P88#P3C663P#Q#P63>63P8#W8#P3?663P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P3C636P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P3L6%36P#T88#P3H6#36P#K#P3I6$63P8#h1 81#P3I636P1 #a1#H63I63P8#c91 8#91H63C63&.&&7&&=#d&#H6$3>&V63&H91#W8918#P3?636P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P3C636P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P#GL%Q%88#QLP66P#AL!L#H6 6_18L!#B81#LH6 6_L!#JL#H6$ 6W19L%#G8Q%819LQ#P66P#AL!L#H6 6_81#BL!81L#H6 6_#JL!#LH6$ 6W198#h1 198#1P3I636P1 #a1#H63I63P1 98#c89#1H63C63&.&&7&&=#d#&H6$3>&V6&3H911 8998191‚h1 9889171 9&I(+91(& (0&D&( ($&8(& &L(8(& 91 8819‚h91 ¹]ɹx@ @HK[C™8¹J<™198791 (+&I19&( (0&D&( &8($(& (8&L(& #W88#P3?636P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P91 8891‚h91 8891791 &I(+91&( &D(0&( ($&8&( &L(8&( #W88#P3?636P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P#O88#P63C63P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63PL%#GQ%88QL#P66PL!#AL#H6 6_#B1L!88L#1H6 6_#JL!L#H6$ 6W918#GL%Q%198#LQP66PL!#AL#H6 6_1#B8L!8#1LH6 6_#JL!#LH6$ 6W911 #h89811#P3I663P#a1 #1H63I63P91 8#c819#H63C63&.&&7&#d&=&#H6$&V3>6&3H19#W8918#P3?663P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#O8#P63C36P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P3L6%63P8#T8#P3H6#36P#K#P3I6$63P#V88#P3I6$63P#N#P3I6$36P#P88#P63C36P#Q#P3>663P#W88#P63?63P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P63C36P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P81 9819‚h91 891871 9(+&I91(& &D(0(& ($&8&( &L(8&( 1 89819‚h1 9¹[xCɹJ<@™8¹] @HK™89171 9&I(+19(& (0&D&( ($&8(& (8&L&( 8#W8#P3?663P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P63C63P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P#Y88#H63A63P#U#P3L6%63P#T88#P3H6#36P#K#P6$3I63P8#V8#P6$3I63P#N#P6$3I63P8#P8#P63C36P#Q#P63>63P8#W8#P3?663P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P3C636P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P6%3L63P#T88#P3H6#63P#K#P6$3I63P81 #h81#P3I663P1 #a#1H63I63P#c81 9891#H63C63&.&&7&&=#d#&H6$&V3>6&3H918L%#GQ%198QL#P66P#AL!L#H6 6_1#BL!881#LH6 6_#JL!#LH6$ 6W19L%#G8Q%189QL#P66PL!#A#LH6 6_8#B1L!8L#1H6 6_L!#J#LH6$ 6W91#h1 8918#1P3I663P1 #a#1H63I63P#c81 98#91H63C63&.&&7&#d&=&#H6$3>&V63&H91#W8891#P3?663P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#O8#P63C63P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P6%3L63P#T88#P6#3H63P#K#P3I6$36P#V88#P6$3I36P#N#P6$3I63P#P88#P3C663P#Q#P63>63P#W88#P63?63P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#O8#P63C36P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63PL%8Q%#G8L#QP66P#AL!L#H6 6_#B81L!81#LH6 6_L!#JL#H6$ 6W91#h81 891#1P3I663P#a1 #1H63I63P#c1 89819#H63C63&.&&7&&=#d&#H6$3>&V63&H918#W198#P3?636P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P#O88#P63C63P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P8#Y8#H63A63P#U#P6%3L36P#T88#P3H6#36P#K#P3I6$36P#V88#P6$3I63P#N#P3I6$36P8#P8#P63C63P#Q#P3>663P8#W8#P3?636P#N#H63;63P#Q88#H63C63P#O#H6$3I63P#O88#P63C36P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P81 #h8#1P3I636P1 #a#1H63I63P81 #c989#1H63C63&.&&7&#d&=#&H6$&V3>63&H19#W8981#P63?63P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P#O88#P63C36P#O#H63C63P#G88#H6$3I63P#Q#H6)3L63P#GQ%L%88QL#P66P#AL!#LH6 6_L!8#B181L#H6 6_#JL!#LH6$ 6W191 #h89181#P3I636P#a1 #1H63I63P#c1 898#91H63C63&.&&7&#d&=&#H6$3>&V6&3H198#W819#P3?663P#N#H63;63P#Q88#H63C63P#O#H6$3I63P8#O8#P63C63P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P1 8#h8#1P63I63P1 #a#1H63I63P1 98#c891#H63C63&.&&7&#d&=#&H6$3>&V6&3H19#W8891#P63?36P#N#H63;63P#Q88#H63C63P#O#H6$3I63P8#O8#P3C636P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63P8#O8#P3C636P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63PL%#GQ%88L#QP66PL!#A#LH6 6_81L!#B81L#H6 6_#JL!L#H6$ 6W19#G8Q%L%198LQ#P66P#AL!L#H6 6_18#BL!8L1#H6 6_L!#J#LH6$ 6W9181 #h891#1P3I663P#a1 1#H63I63P81 9#c819#H63C63&.&&7&&=#d#&H6$3>&V6&3H191 8991819‚h1 98891791 &I(+19&( (0&D(& ($&8&( &L(8(& #l891"(5&J8#91(&‚p¹C @HKJ<™8ɹx@[]™871$9(/&P19(& (4&J(& &>(((& (>&T(& 1 #l881#P3M663P1 #e#1H63M63P9#c1 881#9H63C63&.&&7&#d&=#&H6$3>&V6&3H198#W189#P3?636P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#W8#P63?36P#N#H63;63P8#Q8#H63C63P#O#H6$3I63P8#O8#P63C36P#O#H63C63P8#G8#H6$3I63P#Q#H6)3L63PL%Q%8#G8LQ#P66P#AL!L#H6 6_L!18#B8L1#H6 6_L!#JL#H6$ 6W9116#619…#1ÿ/MTrk’µÅ4ÿJAZ2ÿ @ÿGeneral MIDIÿ Choir Aahs1ÿYÿYÿÿµx [@]@•J"µ}C}J<HKƒx‚p}•JQ"ƒµx‚p•Q"µ}•Qƒ`Q"µ}•Q‚ µ}•O"Qƒ`O"µ}•O‚ µ}•OL"ƒµx‚p•X"µ}•Lƒ`µ}•X"X‚ Xµ}•Y"ƒµx‚p•YV"µ}ƒx‚p•R"µ}•Vƒµx‚p}•Q"Rƒµx‚p•Qµ}•U"ƒµx‚p}•V"Uƒµxƒsƒn‚p•E"Vµ}ƒx‚p}•A"Eƒµx‚p•<"Aµ}ƒ`}•<"<‚ >"µ}•<ƒµx‚p•@"µ}•>ƒ`µ}•C"@‚ ="Cµ}ƒ`}•=>"‚ µ}•<">ƒ`<>"µ}‚ •>µ}•>"ƒµxƒsƒn‚p}•H">ƒµx‚p•Hµ}•J"ƒ`µ}•J"J‚ Jµ}•F"ƒ`Fµ}•I"‚ Iµ}•E"ƒµx‚p•EC"µ}ƒ`}•CC"‚ µ}•C"Cƒ`µ}•C"C‚ µ}•C9"ƒ`99"µ}‚ •9µ}•>"ƒµxƒsƒn‚p•>µ}•V"ƒµxƒsƒnƒiƒd‚p•Vµ}•O"ƒµx‚p•V"Oµ}ƒx‚p}•VL"ƒµx‚p•Q"µ}•Lƒ`Q"µ}•Q‚ Qµ}•>"ƒµx‚p•>µ}•C"ƒ`C"Cµ}‚ }•A"Cƒµx‚p•@"Aµ}ƒ`}•@"@‚ A"@µ}ƒ`•C"µ}•A‚ CE"µ}ƒ`•EF"µ}‚ }•@"Fƒ`µ}•@"@‚ µ}•9"@ƒµxƒsƒn‚p}•9M"ƒµx‚p•Q"µ}•Mƒµx‚p•O"µ}•Qƒ`O"µ}•O‚ µ}•L"Oƒµx‚p}•X"Lƒ`X"µ}•X‚ Y"µ}•Xƒµx‚p•YV"µ}ƒx‚p•Vµ}•R"ƒµx‚p•RQ"µ}ƒx‚p•Qµ}•U"ƒµx‚p}•V"Uƒµxƒsƒn‚p•J"µ}•Vƒµxƒsƒn‚p•J"Jµ}ƒx‚p•C"µ}•Jƒ`Cµ}•C"‚ CJ"µ}ƒ`}•JJ"‚ Jµ}•@"ƒµx‚p}•@E"ƒµxƒsƒn‚p•EC"µ}ƒ`•Cµ}•C"‚ CA"µ}ƒx‚p•@"µ}•Aƒ`µ}•@"@‚ µ}•A"@ƒ`µ}•C"A‚ CE"µ}ƒ`}•F"E‚ @"Fµ}ƒ`•@@"µ}‚ •9"@µ}ƒx‚p•9µ}•J"ƒµx‚p}•JQ"ƒµx‚p}•QQ"ƒ`µ}•Q"Q‚ µ}•QO"ƒ`OO"µ}‚ •Oµ}•L"ƒµx‚p•Lµ}•X"ƒ`X"Xµ}‚ •Xµ}•Y"ƒµx‚p•V"µ}•Yƒµx‚p•Vµ}•R"ƒµx‚p}•RQ"ƒµx‚p}•U"Qƒµx‚p•V"µ}•Uƒµxƒsƒnƒiƒdƒ_ƒZ‚p•E"Vµ}ƒxƒsƒn‚p}•A"Eƒµx‚p•Aµ}•<"ƒµx‚p•<>µ}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0•>ÿ/MTrkî¶Æ4ÿJAZ2–J"ÿGeneral MIDIÿ Choir Aahs2ÿYÿYÿÿ¶x h[@]Cÿ @¶@}HK}J<ƒ`}–L"J‚ Q"¶}–Lƒ¶x‚p}–QQ"ƒ`Q"Q¶}‚ –O"¶}–Qƒ`O¶}–O"‚ L"¶}–Oƒ¶x‚p–X"¶}–Lƒ`¶}–XX"‚ ¶}–XY"ƒ`X"Y¶}‚ }–V"Xƒ`V¶}–T"‚ ¶}–R"Tƒ¶x‚p–Q"¶}–Rƒ¶x‚p}–U"Qƒ¶x‚p–UV"¶}ƒxƒsƒn‚p–E"¶}–Vƒ¶x‚p}–A"Eƒ¶x‚p}–<"Aƒ`<¶}–<"‚ <>"¶}ƒx‚p}–>C"ƒ`¶}–A"C‚ A¶}–>"ƒ`¶}–>">‚ >"¶}–>ƒ`>>"¶}‚ –>¶}–>"ƒ¶xƒsƒP–>A"¶}‚ –A¶}–H"ƒ¶x‚p–J"¶}–Hƒ`J¶}–J"‚ J¶}–I"ƒ`¶}–II"‚ E"¶}–Iƒ¶x‚p–C"¶}–Eƒ`¶}–CC"‚ ¶}–CC"ƒ`C¶}–@"‚ 9"@¶}ƒ`}–99"‚ >"¶}–9ƒ¶xƒsƒn‚p–>V"¶}ƒxƒsƒnƒiƒP}–VT"‚ O"¶}–Tƒ`Q"¶}–O‚ ¶}–QV"ƒ`¶}–R"V‚ L"¶}–Rƒ¶x‚p–Q"¶}–Lƒ`Q"Q¶}‚ –>"¶}–Qƒ¶x‚p}–C">ƒ`¶}–C"C‚ A"¶}–Cƒ¶x‚p–@"A¶}ƒ`}–@"@‚ ¶}–C"@ƒ`C"¶}–C‚ ¶}–CF"ƒ`FF"¶}‚ –@"¶}–Fƒ`@¶}–>"‚ 9"¶}–>ƒ¶xƒsƒn‚p–M"9¶}ƒx‚p–Q"¶}–Mƒ¶x‚p–Q¶}–O"ƒ`¶}–O"O‚ ¶}–L"Oƒ¶x‚p}–X"Lƒ`¶}–XX"‚ ¶}–Y"Xƒ`X"Y¶}‚ }–V"Xƒ`VT"¶}‚ }–TR"ƒ¶x‚p}–Q"Rƒ¶x‚p–QU"¶}ƒx‚p}–UV"ƒ¶xƒsƒn‚p–J"¶}–Vƒ¶xƒsƒn‚p}–J"Jƒ`JH"¶}‚ –C"H¶}ƒ`–E"¶}–C‚ ¶}–EJ"ƒ`¶}–F"J‚ F¶}–@"ƒ¶x‚p}–@E"ƒ¶xƒsƒn‚p–EC"¶}ƒ`–C¶}–C"‚ A"¶}–Cƒ¶x‚p}–@"Aƒ`@"¶}–@‚ @C"¶}ƒ`–C"¶}–C‚ C¶}–F"ƒ`FF"¶}‚ –F¶}–@"ƒ`@¶}–>"‚ >9"¶}ƒx‚p–9J"¶}ƒ`–J¶}–L"‚ L¶}–Q"ƒ¶x‚p–Q"¶}–Qƒ`¶}–Q"Q‚ O"Q¶}ƒ`–OO"¶}‚ –O¶}–L"ƒ¶x‚p–X"¶}–Lƒ`X¶}–X"‚ ¶}–XY"ƒ`YX"¶}‚ –V"¶}–Xƒ`T"¶}–V‚ ¶}–R"Tƒ¶x‚p–RQ"¶}ƒx‚p–U"¶}–Qƒ¶x‚p}–V"Uƒ¶xƒsƒnƒiƒdƒ_ƒZ‚p}–VE"ƒ¶xƒsƒn‚p}–A"Eƒ¶x‚p–<"¶}–Aƒ¶x‚p–>¶}–<¶|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0–>ÿ/MTrk­·ÇYÿJAZ2·ÿGeneral MIDIÿ Warm Pad1ÿYÿYÿÿ·x "[@]—><ÿ @·J<}HKC—A<·}@ƒxƒsƒn‚p—C<·}—><A>ƒ`>A<><·}—C‚ C<·}—AF<>ƒ·x‚p—9<=<·}—FCƒ·xƒsƒn‚p}—=9A<><ƒ·x‚p—<<:<>·}—Aƒ`:·}—:<><<‚ C<F<·}—>:ƒ·xƒsƒn‚p—CF·}—=<9<ƒ·x‚p—><A<·}—9=ƒ·xƒsƒnƒiƒdƒ_ƒZ‚p—>·}—A9<<<ƒ·x‚p—9<A<><·}ƒx‚p—E<@<·}—A>ƒ`@EF<·}—C<‚ CF9<·}—><ƒ·x‚p—A<>·}—E<9ƒ`><A<·}—EA‚ >:<·}—<<Aƒ·xƒsƒP—<·}—:<:><‚ ·}—>H<:C<ƒ·x‚p}—H><A<Cƒ·x‚p—F<·}—C<A>ƒ`=<CF9<·}‚ —=·}—><A<9ƒ·x‚p—>AC<F<·}ƒxƒsƒP—CF=<·}—9<‚ ><·}—9=9<ƒ`>9·}—E<C<‚ ECA<><·}ƒxƒsƒnƒiƒdƒ_ƒZƒUƒP‚p}—<<@<>Aƒ·x‚p—:<·}—<<<@ƒ`:<·}—><<:‚ ·}—=<9<:>ƒ·x‚p}—9==<9<ƒ`E<=9·}—C<‚ A<><E·}—Cƒ·x‚p—>A·}—C<H<ƒ·x‚p—CA<H·}—E<ƒ·x‚p—9<·}—=<AEƒ·x‚p—A<9·}—><=ƒ`·}—@<E<A>‚ A<·}—><@Eƒ`C<F<·}—A>‚ F9<·}—=<Cƒ`><9<·}—=9‚0·xƒsƒnƒiƒdƒ_ƒZƒU‚p—C<F<9·}—>ƒ·x‚p—CF9<=<·}ƒxƒsƒn‚p—><A<9=·}ƒx‚p—:<·}—<<A>ƒ`:<·}—><:<‚ :F<·}—C<>ƒ·xƒsƒn‚p—9<·}—CF=<ƒ·x‚p—=9A<·}—><ƒ·xƒsƒnƒiƒdƒ_ƒZ‚p—A:<>·}—<<ƒ`:·}—:<<><‚ H<>:·}—C<ƒ·x‚p—H·}—><CA<ƒ`>F<·}—AC<‚ 9<·}—=<FCƒ·x‚p—A<·}—=9><ƒ·xƒsƒn‚p}—C<AH<>ƒ·x‚p—CHA<E<·}ƒx‚p—9<·}—EA=<ƒ·x‚p—=A<·}—><9ƒ`E<@<·}—>A‚ A<><@·}—Eƒ`AC<·}—F<>‚ =<·}—9<CFƒ`=9·}—><9<‚0·xƒs‚p—>C<F<9·}ƒxƒsƒnƒiƒP}—A<><FC‚ ·}—F<>AC<ƒ·x‚p—C=<·}—9<Fƒ·xƒsƒn‚p—=·}—><A<9ƒ·x‚p—>A<<:<·}ƒ`—><<:<·}—:‚ F<·}—>:C<ƒ·xƒsƒn‚p—=<C·}—9<Fƒ·x‚p—A<><·}—9=ƒ·xƒsƒnƒiƒdƒ_ƒZƒUƒPƒKƒFƒAƒ<‚p—H<·}—C<>Aƒ·x‚p—C>*·}—H·|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0—>ÿ/MTrk¼¸ÈYÿJAZ2¸CÿGeneral MIDIÿ Warm Pad2ÿYÿYÿÿ¸x ^[@]@HKJ<˜A<¸˜9<¸}ÿ @¸}ƒxƒsƒn‚p}˜9<A><9ƒ`¸}˜A<>99<‚ A<¸}˜A><9ƒ`AC<>¸}˜><‚ ¸}˜@<9<C>ƒ¸xƒsƒn‚p˜9<><9¸}˜@ƒ¸x‚p˜>9A<:<¸}ƒx‚p}˜><C<:Aƒ¸x‚p˜@<9<¸}˜>Cƒ¸xƒsƒn‚p˜@9¸}˜><9<ƒ¸xƒsƒn‚p˜A<9>9<¸}ƒx‚p˜:<A9A<¸}ƒx‚p˜A¸}˜:@<9<ƒ¸x‚p˜9<><¸}˜9@ƒ¸x‚p˜9>@<¸}˜9<ƒ`¸}˜><:<9@‚ ¸}˜:9<>@<ƒ`><@9<¸}˜9‚ ¸}˜9<<<>9ƒ`9<9<><¸}‚ ˜:<¸}˜9A<>ƒ¸xƒsƒn‚p}˜C<:A<<ƒ¸xƒsƒP˜9<><¸}˜<C‚ :<¸}˜9><>ƒ`¸}˜>:9<@<‚0¸xƒs‚p˜9><A<@¸}ƒ`˜C<¸}˜A>><‚0¸xƒP˜C@<>9<¸}‚0xƒs‚p}˜><9@9<ƒ¸xƒsƒnƒiƒdƒ_ƒZƒUƒP˜A<>9<¸}˜9‚ C<<<¸}˜A9ƒ¸x‚p˜A<¸}˜:<<Cƒ¸x‚p}˜:A@<9<ƒ¸xƒsƒn‚p˜9<@9¸}˜><ƒ¸x‚p}˜>C<><9ƒ¸x‚p˜<<A<C>¸}ƒx‚p}˜A<9<@<ƒ¸x‚p˜@¸}˜><99<ƒ`¸}˜9<@<>9‚ @9<9¸}˜:<ƒ`9><¸}˜C<:‚ ¸}˜9<@<C>ƒ¸xƒsƒnƒiƒd‚p˜><¸}˜99<@ƒ¸x‚p}˜9<A<>9ƒ¸x‚p˜A<¸}˜><9Aƒ`A>><¸}˜C<‚ @<¸}˜9<C>ƒ¸xƒsƒn‚p}˜><99<@ƒ¸x‚p˜>¸}˜A<9:<ƒ¸x‚p˜A:><¸}˜C<ƒ¸x‚p˜>C¸}˜@<9<ƒ¸xƒsƒn‚p˜@99<¸}˜><ƒ¸xƒsƒnƒiƒdƒ_ƒZ‚p}˜:<A<>9ƒ¸x‚p˜:><¸}˜AC<ƒ`>9<C@<¸}‚ ˜><@99<¸}ƒ`˜9>C<¸}˜><‚ ¸}˜@<9<>Cƒ¸xƒsƒnƒiƒd‚p˜C<9@¸}˜><ƒ¸x‚p˜A<¸}˜<<>Cƒ¸x‚p˜A@<9<¸}˜<ƒ¸x‚p˜@><9<¸}˜9ƒ`9<¸}˜@<9>‚ @9<¸}˜9:<ƒ`C<><¸}˜9:‚ 9<@<>¸}˜Cƒ¸xƒsƒn‚p˜:<><¸}˜9@ƒ¸x‚p}˜>@<:9<ƒ¸x‚p˜@9¸}˜><9<ƒ`9<A<¸}˜>9‚ ><9A<¸}˜Aƒ`A>C<><¸}‚ ˜@<>C¸}˜9<ƒ¸xƒsƒn‚p˜9<¸}˜9@><ƒ¸x‚p˜A<>:<9¸}ƒx‚p˜A¸}˜C<><:ƒ¸x‚p˜@<C9<>¸}ƒxƒsƒn‚p˜><9<9¸}˜@ƒ¸xƒsƒnƒiƒdƒ_ƒZ‚p˜9<¸}˜A<9>ƒ¸xƒsƒn‚p˜A<A¸}˜:<9ƒ¸x‚p}˜C<<<:Aƒ¸x‚p˜>*C¸}˜<¸|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONML0˜>ÿ/MTrke°À0ÿJAZ2ÿ @° @yÿYÿOn the WaterfrontÿGeneral MIDI°r(ÿ/simutrans-124.3/simutrans/music/31-Courtenay-Bridge.mid000066400000000000000000000306051474050137200230030ustar00rootroot00000000000000MThdÀMTrk›ÿCourtenay Bridgeÿ By ÿCopyright © 2007 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQ¸ØÈÿQ¸ØÿQ¸ØÈÿQ¸Øÿ/MTrkÕÿ!ÿStaffÀG°° @Jn‡ J Jn J Jn J Ln L Gn‚NGCn‡@C0>n>?n.?@n‡ @ Cn C Cn C EnECnŠ@C0CnCDn.DEn E >n > En E Dn D Cn‚PC0@n@Cn.C@n@7n‰7ƒ0Jn‡ J Jn J Jn J Ln L Gn‚NGCn‡@C0>n>?n.?@n‡ @ Cn C Cn C EnECnŠ@C0CnCDn.DEn E >n > En E Dn D Cn‚PC0@n@Cn.C@n@7n‰7Ë0Jn‡ J Jn J Jn J Ln L Gn‚NGCn‡@C0>n>?n.?@n‡ @ Cn C Cn C EnECnŠ@C0CnCDn.DEn E >n > En E Dn D Cn‚PC0@n@Cn.C@n@7n‰7ƒ0Jn‡ J Jn J Jn J Ln L Gn‚NGCn‡@C0>n>?n.?@n‡ @ Cn C Cn C EnECnŠ@C0CnCDn.DEn E >n > En E Dn D Cn‚PC0@n@Cn.C@n@7nŠ@70CnCDn.DEn E >n > En E Dn D Cn‚PC0@n@Cn.C@n@7n‰7ÿ/MTrk ­ÿ!ÿStaff-1Á±± @‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Bn‘Hn.‘>‘B‘HB‘>n‘Bn‘Hn ‘>‘B‘H`‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Bn‘Hn.‘>‘B‘HB‘>n‘Bn‘Hn ‘>‘B‘H`‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘Gƒ‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Ln‘L‘On.‘O‘Hn‘H‘Ln.‘L‘On‘O‘Hn.‘H‘Ln‘L‘On.‘O‘Hn‘H‘Ln.‘L‘On‘O‘Hn.‘H‘Ln‘L‘On.‘O‘Hn‘H‘Ln.‘L‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Qn‘Q‘Jn.‘J‘Nn‘N‘En.‘E‘Jn‘J‘Bn.‘B‘En‘E‘Gn.‘G‘Hn‘H‘Ln.‘L‘On‘O‘Hn.‘H‘Ln‘L‘On.‘O‘Hn‘H‘Ln.‘L‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘Gn‘G‘Jn.‘J‘On‘O‘Gn.‘G‘Jn‘J‘On.‘O‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Bn‘Hn.‘>‘B‘HB‘>n‘Bn‘Hn ‘>‘B‘H`‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Bn‘Hn.‘>‘B‘HB‘>n‘Bn‘Hn ‘>‘B‘H`‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gn.‘>‘C‘G„‘>n‘Bn‘Hn.‘>‘B‘HB‘>n‘Bn‘Hn ‘>‘B‘H`‘n‘Cn‘Gn.‘>‘C‘GB‘>n‘Cn‘Gn ‘>‘C‘G`‘>n‘Cn‘Gn ‘>‘C‘G0‘>n‘Cn‘Gnƒ‘>‘C‘Gÿ/MTrkþÿ!ÿStaff-2²² @’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’+n ’+ ’-n ’- ’/n ’/ ’0n ’0 ’4n ’4 ’0n ’0 ’.n ’. ’0n ’0 ’+n ’+ ’.n ’. ’(n ’( ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’) ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’+n ’+ ’-n ’- ’/n ’/ ’0n ’0 ’4n ’4 ’0n ’0 ’.n ’. ’0n ’0 ’+n ’+ ’.n ’. ’(n ’( ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’) ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’+n ’+ ’-n ’- ’/n ’/ ’0n ’0 ’4n ’4 ’0n ’0 ’.n ’. ’0n ’0 ’+n ’+ ’.n ’. ’(n ’( ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’) ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’+n ’+ ’-n ’- ’/n ’/ ’0n ’0 ’4n ’4 ’0n ’0 ’.n ’. ’0n ’0 ’+n ’+ ’.n ’. ’(n ’( ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’) ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’+n ’+ ’-n ’- ’/n ’/ ’0n ’0 ’4n ’4 ’0n ’0 ’.n ’. ’0n ’0 ’+n ’+ ’.n ’. ’(n ’( ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’) ’+n ’+ ’/n ’/ ’2n ’2 ’/n ’/ ’7n ’7 ’2n ’2 ’/n ’/ ’-n ’- ’2n ’2 ’-n ’- ’2n ’2 ’1n ’1 ’0n ’0 ’$n ’$ ’(n ’( ’)n ’)0’+n.’+B’+n ’+`’+n ’+0’+nƒ’+ÿ/MTrk _ÿ!ÿStaff-3¹¹ @™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3 ™3n~™3™3n>™3™3n ™3`™3n ™3`™3n ™30™3nƒ™3ÿ/MTrk Íÿ!ÿStaff-4¹¹ @™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n~™#™#n>™#™#n™1n ™#™1 ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n~™#™#n>™#™#n™1n ™#™1 ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n~™#™#n>™#™#n™1n ™#™1 ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n~™#™#n>™#™#n™1n ™#™1 ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™#n~™#™#n>™#™#n™1n ™#™1 ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n ™% ™#n ™# ™%n~™%™%n>™%™#n ™# ™%n~™%™%n>™%™1n ™10™1nƒ™1ÿ/simutrans-124.3/simutrans/music/32-incidental-skies.mid000066400000000000000000001043041474050137200230650ustar00rootroot00000000000000MThd xMTrkMÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿjÿ~j@'@@1@ÿ~j@@@@@@@1@$@@'ÿ~j1@1@@@@@ÿ~j@@@$@@'@1@@ÿfj@@@@@@@@@ÿNjÿXÿQãÿYÿIncidental Skiesÿ/MTrk رÁ#ÿJAZ2±[_ÿBass±@]{ @’`‘$Z6$$^C$ Q !8$!$W2$$Z-&a$#$^&$!'+$i!5$$eP$Q%!<*!$^@$$T8$T !D#!+Z6++^(#Q+/#!#B$#$W2$$Z$ %U-%#&L#&^5^S%8#a>e!W1$$Z6$$^C$ Q !8$!$W2$$Z-&a$#$^&$!'+!$i5$$eP$Q%!<*$^!@$$T8$T !/#!$T+$%$T<$T(!T'!$T*$&$T>$T(!T&!$T/$!$T/$!T'!T!!$T)$'$T-$#T(!T !)Z6))^()!QP!!B$!"W2""Z("#U6##L+$i#1$$e($&g(&(&=*&'^,'"'T(')T5))X#)$T+$%$T<$T(!T'!$T*$&$T>$T(!T&!$T/$!$T/$!T'!T!!$T)$'$T-$#T(!2 !+TD+ +T+]+T'+&TD& &T&[&2#&)a3))aH)$J"$&4(&)Z>))Z@)$W!$)?$)$T+$%$T((N$((((T((+T*+&+T +(F;(+T#+$a4$$^PM$$!G($^!%$$^M$!Q(Z!)b6))f(!Y)P!J!$!"_2""b("#]6##T+$q#1$$m($&o(&(&E*&'f,'"'\(')\5))`#)$^3$$^L$^ !^! $^*$&$^M$^!^! $^:$$^I$^!^!$^1$$^$&^$&$^$ !8!!)n3))nH)$W"$&A(&)g>))g@)$d!$)-$)(f>((j!(W(-$('^5''^S'%'^#'&i<&&i-&K&K#&!e8!!bA!&X(*4 &*+c#+ƒ=$k4$$r>$Q&!I($d!8$$kF$ I(!N$!$r8$$nJ$W$!8($k !$*$n*Z$&!N,&F!&$o7$$oE$ !^(Q!$k8$$hA$!^!!^! !$o:$$kA$T%!T*$o!0$$dL$N !a$!)^D) )^)])^')$^D$ $^$[$^&$)^I))^/)I)^!)$^I$$^()^$>))^ )$g4$$dPS$$!M($d!%$$dM$!W(`!'$k>$ $gG$ W%!W#!$k@$$gD$ !`! E$+e6++i(+#\/#!#M$#$b2$$e$ %`-%#&4#&)^3))^L)$^$ &^& )^*)&)^M)$^$&8& $n4$$u>$T&!L($g!8$$nF$ L(!Q$!$b6$$fC$ Y !@$!$_2$$b(+i$((f+#($:#$)f6))jC) $]$ &D$&)c2))f-+m)#)j+)&3+&)u5))qP$])%$&H*)j&@))`8)$` $&P#&$k4$$r>$Q&!I($d!8$$kF$ I(!N$!$r8$$nJ$W$!8($k !$*$n*Z$&!N,!&v&)n4))u>)$T&$&L()g&8))nF) $L($&Q$&(`>(#d!#WW$'`>'"d!"W±U"‘W$&T+&%&T(&*N(*(*T(-T**-&-T -*F;*-2#-m#ƒ=$a4$$^PM$$!G($^!%$$^M$!Q(Z!'$e>$ $aG$ Q%!Q#!$e@$$aD$ !Z! ,$$Z6$$^C$ Q!B$!$W2$$Z-$#^#!L+$i!1$$e(&g$(&(&<*'^&,'"'T((T'5((X#()T3))TL)$T$ &T& )T*)&)TM)$T$&T& )T:))TI)$T$&T&)T1))T)+T$+)T) &2!&$Z6$$^C$ Q !8$!$W2$$Z-$&a#$^&$!'+$i!5$$ePQ$%!<*$^!@$$T8$T !D#!+TD+ +T+]+T'+&TD& &T&[&2#&)TD) )T)])T')$TD$ $T$[$T#$$a4$$^PM$$!G($^!%$$^M$!Q(Z!$ZO$$^C$58$$W2$$Z($(&^#&(Z#()b6))f()!YP!J!$!"_2""b("#]6##T+$q#1$$m($&o(&(&E*'f&,'"'\(')\5))`#)$o7$$oE$ !^(Q!$k8$$hA$!^!!^! !$o:$$kA$T%!T*!$o0$$dL$N !a$!)^3))^L)$^$ &^& )^*)&)^M)$^$&8& ^5^S%8#'f>''j!'W'K$'&i<&&i-&K&K#&!e8!!bA!&X(*4 &*+m#+ƒA$W$7$WMW$!W!$W1$!$W5$)0W$+W0+$o6$$v)$L$o4$ÿ/MTrk;Á¹ÉÿJAZ2¹{ @x]ÿDrums¹[ƒ`™6Z#d*d*6#*<6<6*#d6Z*m*#6&s6<6&*V6Z6*6<*d6*6Z*h#d#*6*F6<*66Z*k#d6*#&s6<&6*P6Z6**d6<*6*s#d6Z#*6*<6<6*#d*m6Z#*6&s6<6&*V6Z*6*s6<6*6Z#d*h*6#6<*F*6#d6Z*k*6#&s6<6&6Z*P*6.d6<6.6Z*d#d6*#*<6<*6#d*m6Z*6#6Z&s6&*V6<6**d6Z6*6<#d*h*#6*F6Z6**k#d6<#6*&s6Z6&*P6<*6*d6Z6*6Z#d.Z#.66<*Z6*.d6Z#d#.66<&s6&6Z*V6*6<*d6*#d*h6Z6*#*F6<*66Z*k#d6*#&s6<&6*P6Z*6*d6<*66Z*d#d6#**<6<*6*m6Z#d*#66Z&s&66<*V6*6Z*d6**h6<#d6*#*F6Z*6#d*k6<6*#&s6Z6&6<*P6*6Z*d6*#d6Z*d*6#*<6<*6#d*m6Z*6#6<&s&6*V6Z6**d6<6*6Z#d*h*6#6<*F*6*k#d6Z6#*&s6<6&6Z*P6**d6<*6*d6Z#d6*#*<6<*6#d6Z*m#6*6Z&s&6*V6<6*6Z*d*66<#d*h6*#*F6Z6*6<#d*k*#66Z&s6&6<*P6*6Z*d*66Z#d*d*#6*<6<6**m6Z#d6*#6<&s6&6Z0F606<0d60#d-P6Z-6#-Z6<-6)P#d6Z6)#)Z6<&s6&)6Z6#Z6<1Z16##d*d6Z6*#*<6<6*6Z#d*m6#*6<&s&66Z*V6**d6<*66Z#d*h6#**F6<*6*k6Z#d#*66<&s6&6Z*P6**d6<*6*s6Z#d6#**<6<6*#d*m6Z6*#&s6<&66Z*V*6*s6<6*#d6Z*h#6**F6<*66Z#d*k*6#6<&s&6*P6Z*6.d6<6.#d*d6Z6*#6<.H.6#d*m6Z6*#6<&s6&*V6Z6**d6<6*#d*h6Z*#6*F6<*66Z#d*k*#6&s6<6&*P6Z6*6<*d6*6Z#d*d6#*6<*<*6#d*m6Z#*66Z&s6&6<*V*6*d6Z6*#d6<*h#*6*F6Z6*#d*k6<#6*6Z&s&6*P6<6*6Z*d6**d6Z#d6#*6<*<*66Z#d*m#6*6Z&s6&6<*V6**d6Z6*#d6<*h*#6*F6Z6*6<*k#d6*#6Z&s&66<*P6**d6Z6**d6Z#d6*#*<6<*6#d6Z*m#*6&s6Z6&6<*V*6*d6Z*6#d*h6<#*6*F6Z6**k#d6<#*66Z&s&66<*P*6*d6Z*66Z#d*d6*#*<6<6*#d6Z*m#6*&s6<6&6Z*V6*6<*d*6#d*h6Z6*#*F6<6*6Z#d*k#6*6<&s6&*P6Z6**d6<*6*d6Z#d*#66<*<*6*m#d6Z6#*&s6Z&66<*V*6*d6Z*6#d*h6<#6*6Z*F6*#d6<*k#*66Z&s6&6<*P6*6Z*d6*#d6Z*d*6#*<6<6*6Z*m#d6#*&s6<6&6Z*V*66<*d*6#d6Z*h#*6*F6<6*#d6Z*k#*66<&s&66Z*P6*6<*d*6*s#d6Z*#66<*<*6#d6Z*m#*66<&s&66Z*V6**s6<*66Z#d*h6#**F6<6*6Z*k#d#6*&s6<&6*P6Z*66<.d.6*d6Z#d#6**<6<*6*m6Z#d*#66Z&s6&6<*V*6*d6Z*6#d6<*h#*6*F6Z*6#d*k6<#6*6Z&s&66<*P6*6Z*d6*&s#d6Z&6#6<&Z&66Z&s#d6#&&6Z6&0d6<066Z0Z06#d0s6<60#6Z0Z606<-s-66Z-d-66<)s6))d6Z6)EdFs#d6d1d3sE6F31#FZ6<F6#dEd6d3sFs6E3F#Ed6<FZ&sF&6E3sFsEP6dE6F3FZ6<EdFE63s6dEd#dFs#6EF3FZ6<F66dEd#d3sFs#F63E&s6<FZEd&EF6Fs3sEP6dF6E3FZ6<F6#dFs3sEd6d#EF366<FZ6F3s6dFsEd#dE#F36&sEdFZ6<EF6&EP6d3sFsEF36FZEd#Z6<E6#F#dEd3s6dFsE6#3F6<FZ6FFs3s#d6dEdE#63F&sEd6<FZE6F&3sEP6dFs36EFFZ6<6FFsEd#d3s6d36E#F6<FZ6FFs6dEd3s#d36#FEEd&sFZ6<&6EF3s6dEPFs6E3F6<FZEdEF6Ed3s6d#dFs#EF36FZ6<6FFs3sEd6d#dFE36#FZ&sEd6<6&FE3sFsEP6d6EF36<FZ6FFs3s#dEd6dF3#6E6<FZF66dEd#d3sFs6#FE3EdFZ&s6<EF&66d3sEPFsFE366<EdFZ6EFFs3s#dEd6dE63#F6<FZF6Fs6d#d3sEdF6#E3FZ&sEd6<6&FEEP6d3sFsEF636<FZ6F3s6dEdFs#dF3#6EFZ6<F63s#dEdFs6d3#EF6&sFZEd6<6FE&6d3sEPFs63EF6<EdFZE6FFs3s#dEd6d3#EF66<FZ6F3s#dEdFs6d#F36E6<&sEdFZ&E6F3s6dFsEPE63FFZ6<F66dEdFs#d3s63EF#FZ6<F66d#d3sEdFs63EF#FZEd6<&sF6&EEPFs3s6d6EF3FZEd6<6EF6dEd3s#dFsFE#636<FZF6#dFsEd6d3sF63#E&sFZ6<Ed&6FE6dEPFs3s63EF6<FZ6FFs6d3s#dEdE6#F36<FZ6F3sEdFs6d#d36FE#&sEd6<FZFE6&Fs3sEP6d6E3F6<FZEdFE63sEd#d6dFs#3FE6FZ6<6FEdFs#d3s6d36EF#6<EdFZ&s6&FE3sEP6dFs3F6EFZ6<F6*d6Z#d*6#6<*<*6*m6Z#d*6#&s6<6&0F6Z606<0d606Z#d-P-6#-Z6<6-)P#d6Z6#))Z6<&s&6)6Z61Z6<#Z61#3sFs#d6d1dEd#FE136FZ6<F6EdFs6d#d3s36FE#Ed&s6<FZF6E&FsEP6d3s36FEEd6<FZ6FE3sFsEd#d6dF63#E6<FZF63sEdFs#d6d36EF#6<&sFZEdEF&66dFsEP3sF36E6<FZ6FFs#d6dEd3s3FE6#FZ6<F66d#d3sEdFsFE3#6&sEdFZ6<&6FEEPFs6d3sFE36FZ6<Ed#ZE#6FFs3s#dEd6dE#36F6<FZF66d3s#dEdFs#36EF6<&sEdFZ6F&E3s6dEPFsE3F6FZ6<6FFs#dEd3s6dF3E#6FZ6<6F3sEdFs6d#d3#EF6EdFZ6<&sE&6F6dEPFs3sF63EFZ6<Ed336FE3sFs6dEd#d3EF6#FZ6<6FEd6dFs3s#dE#36F&sEdFZ6<6FE&3sFs6dEP6F3E6<FZF66dFs#d3sEd63EF#FZ6<6FEd6dFs3s#dE#3F6&sEdFZ6<FE&6EPFs3s6dE63FFZEd6<E6FEd#dFs6d3s3E6#F6<FZF66d3sEd#dFs36E#F&sEdFZ6<F&E6Fs3sEP6d3E6FFZ6<6F#dEdFs3s6d3F#6E6<FZF63s#dEdFs6dF#36E&sFZ6<Ed&E6FFs3sEP6d63FEEd6<FZ6FEFs3sEd#d6d6F#E3FZ6<6F6d#d3sEdFs#E6F3&sEdFZ6<6FE&3sFs6dEP3F6EFZ6<F6Fs3s#dEd6d36FE#FZ6<6FEdFs6d3s#d#3F6E&sEdFZ6<&6FEEPFs6d3s36FE6<FZEdFE6#dEdFs6d3s#FE636<FZ6F3sEdFs6d#dE3#6F&sEd6<FZEF6&3sEPFs6d3FE6FZ6<6F#d6dFs3sEd6E#3FFZ6<6F#dFs6d3sEdF#E636<EdFZ&s6&FEEPFs6d3s6FE36<#ZFZEd#6FE3sEdFs6d#dE6#3F6<FZF63s#dEd6dFsF6E#3FZ6<&sEd6FE&EP3s6dFs3E6FFZ6<6FEdFs#d3s6dF6E3#6<FZF66dEd3s#dFsF#E63FZEd6<&sEF&66d3sEPFs6FE3FZEd6<6FE6d#dEd3sFs6FE3#6<FZF6Fs3s#dEd6dE#3F6FZ&s6<Ed6FE&6dEPFs3s36FEFZ6<6F#d6d3sEdFsE36F#6<FZF6Fs3s#d6dEd#3FE6FZEd6<&sF&6EEPFs3s6dE63FFZ6<EdEF6#d3sFsEd6dEF36#FZ6<6F6dFsEd#d3s63#EFEd&s6<FZEF6&6dFsEP3s36EFFZ6<F6#dEd6d3sFs6EF#3FZ6<6F3s#dEdFs6d6FE#36<FZ&sEd&F6E6d3sEPFs6FE3Ed6<FZE6F#d6d3sEdFsE6F#3FZ6<6FEd#dFs3s6d63F#EEdFZ&s6<&FE6EP6d3sFs6FE3FZ6<6F#d6d3sEdFs6F#E36<FZF6Fs#d6d3sEd36#FE&s6<EdFZE&F6EP3s6dFsEF636<3FZEd6FE3Ed3s#dFs6d6EF#36<FZF63sFs6dEd#d#E6F36<&sEdFZE&6F6dFsEP3sE36FFZ6<F66Z#d*d*6#*<6<*6*m#d6Z6*#&s6<6&6Z0F060d6<066Z-P#d-#6-Z6<-6)P6Z#d6)#)Z&s6<6&)6Z61Z6<#Z6#1Fs#dEd1d3s6d#6F31E6<FZF6FsEd6d3s#dEF#366<&sFZEdEF&6EPFs3s6d3FE6EdFZ6<F6E#dEdFs3s6dE6#3F6<FZF6Ed6d3sFs#dF36E#FZEd&s6<F6&EFs3sEP6dE36F6<FZF6Ed6dFs3s#d#E3F6FZ6<F6#d6dEdFs3sF6#3E6<&sFZEd6EF&3sFs6dEP3E6FFZ6<Ed6EFEdFs3s#d6d6E#3F6<FZ6FFs3s#dEd6d#3F6E&s6<FZEd&EF6Fs6dEP3s3FE6FZ6<F6Ed6dFs3s#d6#E3FFZ6<6F3s6dEdFs#d63#FEFZ6<&sEdFE&6Fs3s6dEPE63FEdFZ6<EF6#dFs6dEd3sFE3#66<FZF6Ed#d3s6dFs#EF63&s6<EdFZ&FE66dFsEP3s6EF3FZ6<6FEd#d3s6dFs#FE636<FZF6Fs6d#d3sEd3#6FEEd&s6<FZEF6&6dEP3sFs3E6FFZ3Ed6<3FE6#d6dEdFs3s6F3#EFZ6<6FFs#d3sEd6d6E3#FFZ6<&sEd&6FE6dFsEP3s36EF6<FZF6Fs6d#d3sEd6EF3#6<FZF63s6dFsEd#dEF63#Ed&s6<FZ&EF63s6dFsEP3EF6#Z6<EdFZ#EF66dEd3sFs#d3E#6F6<FZF66d#d3sFsEdEF3#6Ed&sFZ6<F&E6Fs6dEP3s63FEFZ6<6F6dEdFs3s#d63FE#6<FZF66d3sEd#dFs#E36FFZ&sEd6<F6E&6dFsEP3sEF636<&<FZEd6FE&6dFs#dEd3s6E#F36<FZF63s#dEdFs6dFE#366<&sEdFZ6FE&Fs6d3sEP36FE#Z6<FZ6F#Fs#dEd6d3s6E#3FFZ6<6F3s6dFsEd#dEF63#Ed&sFZ6<E6F&3sFsEP6dF36E6<3FZEd6FE3#dEd3sFs6dF3E6#FZ6<6FFs3sEd6d#d6E3F#&sEd6<FZ&F6E6dFs3sEP3FE6FZ6<F6*d#d6Z*#66<*<6*6Z#d*m6#*6<&s6&6Z0F060d6<066Z-P#d6-#-Z6<-6#d6Z)P)6#)Z&s6<&6)6Z61Z#Z6<#161d#d6Z1#6*<6<6*#d*m6Z#*66<&s6&*V6Z*6*d6<*6#d*h6Z#*66<*F6*#d6Z*k#6*&s6<6&6Z*P*6*d6<6*#d*d6Z#*6*<6<*6#d*m6Z#*66<&s&6*V6Z6**d6<*66Z#d*h*6#*F6<*6*k6Z#d*6#&s6<&6*P6Z6*6<*d6*#d*d6Z#*66<*<6*6Z*m#d6*#6Z&s&6*V6<6*6Z*d6*6<#d*h6#*6Z*F6**k6<#d*6#6Z&s&6*P6<6**d6Z*6#d*d6Z#*66<*<6*6Z#d*m6#*6Z&s&66<*V*6*d6Z*6#d*h6<#*66Z*F6**k6<#d#*6&s6Z6&6<*P*6*d6Z*6#d6Z*d#6**<6<*66Z#d*m*6#&s6<6&6Z*V*66<*d6*6Z*h#d#6*6<*F6*6Z#d*k6#*&s6<&6*P6Z6*6<*d6*#d6Z*s#6**<6<*6*m6Z#d*6#6<&s6&6Z*V6**s6<*6#d6Z*h#6**F6<6*6Z*k#d6*#&s6<&6*P6Z*66<.d6.6Z#d*d6#*6<*<6**m6Z#d6#*&s6<6&6Z*V*6*d6<*6*h#d6Z*#66<*F6*#d*k6Z*6#6<&s&6*P6Z6**d6<6*#d*d6Z#*66<*<6*6Z*m#d*#66Z&s&6*V6<6*6Z*d*6#d*h6<#*6*F6Z*6#d6<*k#6*6Z&s&6*P6<6**d6Z*6*d6Z#d#*66<*<6*6Z#d*m6#*6<&s6&6Z*V*66<*d6*#d6Z*h#6**F6<*6*k#d6Z*#6&s6<&66Z*P*66<*d6*6Z#d*s6#*6<*<6*6Z*m#d6*#6<&s&6*V6Z6**s6<*6*h6Z#d*6#*F6<*6*k6Z#d6#*&s6<6&6Z*P*66<.d.6*d6Z#d*6#*<6<*6*m6Z#d#*66Z&s&66<*V*66Z*d6*#d*h6<*6#*F6Z*6#d*k6<#*66Z&s6&6<*P*66Z*d6*#d6Z*d#6*6<*<*6#d*m6Z#*66<&s&66Z&d&6&s6<6&6Z&s&66<&d&6&s6Z6&6<&s&6&j6Z6&&s6<6&Ed1d3s6dFs#dEF631#FZ6<6F6d3s#dEdFsFE#36Ed&sFZ6<E6F&3sFs6dEP3E6FEdFZ6<F6E#d3s6dFsEd#F63EFZ6<6FFsEd#d3s6d3#EF6Ed6<FZ&sE&F63s6dEPFsF3E66<FZF66dEdFs3s#d6#3FEFZ6<3d63FEd3sFs#d6d3E6#F&s6<FZEdF6&E6dEPFs3s63FEFZ#ZEd6<#FE6#dFs6dEd3sF3#E6FZ6<6F3s6dFsEd#d63#EFEdFZ6<&sFE&66dFsEP3s36EF6<FZF66dFs#d3sEd63#FEFZ6<6F#d3s6dEdFsFE63#&s6<EdFZ&FE6EP3sFs6dE6F3FZ6<Ed6EF3s#dEdFs6d3FE#6FZ6<6F6dFs3s#dEd#3F6E6<FZEd&s6&EFFs3s6dEPEF63FZ6<6F#dFs6d3sEdE#36F6<FZF6EdFs6d3s#dE#36FEd&s6<FZ&EF66dEP3sFs6F3EFZEd6<E6FFs3s6dEd#d#FE63FZ6<6F#dFs3s6dEdE63F#FZEd&s6<F6&EEP6dFs3sE3F6#Z6<FZ6F#3s6dEd#dFs3F#E66<3dFZ3F63sFs#d6dEdF3E6#EdFZ&s6<&FE66dFs3sEP6E3FEd6<FZ#Z6EF#Fs#dEd6d3s#3F6E6<FZF6#dEdFs3s6dE#63F6<&sFZEdEF&63sFs6dEP6FE36<FZF6Fs#d6dEd3s3FE6#6<FZ6FEd6d3s#dFs36EF#6<FZ&sEd6E&F6dFsEP3sF63E#ZFZ6<Ed#6EF#d3s6dFsEdF63E#6<FZF6#dFs3sEd6d3F#6EEd&s6<FZEF6&3sFs6dEPFE366<FZF6Fs3sEd#d6d36F#EFZ6<6F#d6dFs3sEd6#E3F6<&sEdFZFE&6Fs6d3sEPFE366<FZEdFE66d3sEdFs#d3#6FEFZ6<F6Ed6dFs3s#d6E#3F6<&sEdFZE&6F6d3sEPFsF6E3FZ6<6F6Z#d*d6#*6<*<6**m6Z#d#*66<&s&6&d6Z6&&s6<&6&s6Z6&6<&d&66Z&s&66<&s6&&j6Z6&6<&s&6EdFs#d6d3s1d36#F1EFZ6<6FFsEd#d6d3s#EF36FZ&sEd6<F6E&EP6dFs3sF6E3FZ6<Ed6EF#dFs3s6dEd63FE#6<FZF6#d3sEd6dFs6E3#F&s6<EdFZ&FE63sFs6dEP6F3E6<FZ#ZF#66dEd#d3sFs#EF63FZ6<6F3s1P6dEdFs#d#FE6136<EdFZFE6EP6dFsEF66<Ed#d1d3dFZE#F136ÿ/MTrk tºÊÿJAZ2ÿ Muted Guitarº@_{[\]_ 1{[\]_ 1{[\] 1]{[\__ 1{[\]_ 1{[\]_ 1{[\] 1’`š0N?00=00@A00A00NA00A0000A00N>00=004<00$0+N6++= ++@8++A+ +N8++A+ +<8++;+ 5S655A 55D855)5 2S622A 22D822E2 0N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300= 00N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300= 05S?55A55DA55E55SA55E55?A55>55S@55E55E>55E55S>55A557<55'50N?00=00@A00A00NA00A0000A00N>00=004<00$0+N6++= ++@8++A+ +N8++A+ +<8++;+ 5S655A 55D855E5 5S855E5 5?855%5 0N?00=00@A00A00NA00A0000A00N>00=004<00$00N?00=00@A00A00NA00A0000A00N>00=004<00=05S655A 55D855E5 5S855E5 5?855%5 4S?44A44DA44E4.N6..= ..@8..'. 2S622A 22D822E2 2S822E2 2?822>2 +N?+ƒ!0N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300= 00N?00=00@A00A00NA00A0000A00N>00=004<00$00N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300$ 00N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300= 0+N6++= ++@8++A+ +N8++A+ +<8++#+ 5S655A 55D855E5 5S855E5 5?855%5 0N?00=00@A00A00NA00A0055S@55E55E>55E55S>55A557<55'50N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300$ 05S?55A55DA55E55SA55E55?A55%54S?44A44DA44)43S633A 33D833E3 2S622A 22D822E2 2S822E2 2?822%2 +N6+ƒ*0N600= 00@800A0 0N800A0 0<800;0 0N700A"0 0A500A0 0N500= 004300$ 00N?00=00@A00A00NA00A0000A00N>00=004<00=05S?55A55DA55E55SA55E55?A55>55S@55E55E>55E55S>55A557<55'50N?00=00@A00A00NA00A0000A00N>00=004<00=0+N6++= ++@8++A+ +N8++A+ +<8++;+ 5S655A 55D855E5 5S855E5 5?855%5 0N?00=00@A00A00NA00A0055S@55E55E>55E55S>55A557<55'57S?77A77DA77E77SA77E77?A77>77S@77E77E>77E77S>77A777<77'75S655A 55D855E5 5S855E5 5?855%5 4S?44A44DA44E43S?33A33DA33E32S622A 22D822E2 2S822E2 2?822>2 +N6+ƒ*0S?00A00>A00800SA00>00?A00>00;N00;00;&0*0;.0jº@ÿ/MTrkͺÊÿJAZ2º][({ ^Z][(@ ^Z][({ ^Z][({ ^Z][({ ^Z][({ ^Z][({ ^Zÿ Clean Guitarº{’[š7;<;@;E;C@7E<7HACAF>C5;2265@;@>@C@"5>C;5F25(7K<<>@E@>E>?<@E7 7A<<>@E@>E>?@E<7 7A?>A>@9A? 9A?AAAA9?VA8?89199B??BAAB@A9? A,?,9'#9?5;9FA?FAF#?59AO7AACAE2528;5BC>;B>BCB>;52CTC'>,;,5' 5275A;;AC>>ACAE223C5>;5=;=>=C=>C52;TC1>8;8515C>9D;?DADG99@A??@A@$?A9u9L?LALG99BA??BAB?A9{0<7K:J@JCJHJFHC:7@7<:G@GCGHG:H7@C{9I?IAIG99S?A?SASA?9]A0?09*99P??PAAPG99FA??FAF9?A8H>H@HH>8@8G>G@G$8@8M>8X:K=KCKFKF::G=CF=GCGFG#:C=FE9OPCPI>C5;2ƒ7I<>7677F<<77N7N@N5I;I>ICIE252F;>C5S;S>SCSC>25;]C*>0;05* 2D5;5P;P>>PCCPE22;C>;55F;F>FCF25;C>9H?HAHH?A99G?GAG(A?9q9N?NAN@9?A 9G?GAG#?A9F7O:J@JCJHJE7:7=:H@@HCHCHHHC7@H:TH3C;@;:3 @CH:P9Q?QAQA9?TA8?891A9?9L?LALG99J??JAAJ9A?TA0?09*99D??DAAD@A?9 9G?GAG9?ASA<?<9599H??HAAH@?9A A>?>9699L??LAAL9?AL0A7E:R@RHRCR5C@7:0H7?:K@KCKHKCH7:@|7::E@ECEHE>H7:C@ 7=:H@HCHHHHC7@:VH5C=@=:57>::I@@IHCCIHI>:@C7H H,C2@2:,":@0=CH7A:M@MCMHM#HC70@:O9H?HAHH9A?9G?GAG(A9?q9N?NAN@9?A 9G?GAG#?A9v8H>H@HH8@>8G>G@G$8@8M>8Q3>:ICI=IFI5FC=:3?6IIG66S><S<>6]>0<06*66P<>PG66F<>F6><2D5P;P>PCPI>;5C2ƒ7A<<>E@@>E>FEE-<7@@4<47-#E@08<77F@F<<>@E@>E>?7@E< 7A??>AA>GAA4?9?49-$A?9089F?FAF&9?0A'049B?BABu9?0A#089F?FAFA9?0b7;<;@;E;CE@<77HDCDE2265;C5@>;@>@C@"C2>5;u2@5L;L>LCLE2528;C>5B;B>BCB>2;5C{5?9K?KAK55A?99D?DAD9?A|7AX@X@8>T@/>/8)8@>:K=KCKFKF::G=FC=GCGFG#C:=Fu9IPCPI5C>2;ƒ7J:J@JCJF77K::K@C@KCK:7@CTC-@4:47-77J::J@C@JCJF77F:C@:F@FCFC@:7TC7@?:?7777G::GC@@GCGFCC3:@7@;:;73#70C:C@7O:O@OCO&@7:C0'0?7K:K@KCKt07:@Cº@ÿ/MTrkq¶Æ=ÿJAZ2¶[({ "ÿBrass¶@]fÓ8–KFEIAJCKEA KPENAMEAKEYKPAZ E AK…!CDFZLJ?CFL FPLJCGFCLCJLWFfCFL$EK?BAH? EAP?%E@A*AE?PAFEF?F(AE?‚FC.F;?.[? CFŒDEZCDLJ?CEL CGEPLJECLLWCJEfCELLCHEDHH>ECH HKEDCKHE CXETHNCRHCEƒ8Ca(EYC"ECH(<<C<„kAJKFEICEKA ENKPAMEAKAZKPEY E AKAELLFCIDECLELLICLECLLPEXCP!ELCƒ9OcCc2OC;CPMIGLBCGM CIMPGGGCMMSG\C]GCM]EFA@4EAEFA]AE‚JEKCH@B@ CEP@%E@C*CE@PEFCF@F(C@EpLDF1CHFFLCLDF[CRCFLaCBFDLDFCL…WADKJEZ?AEK EPAGKJEAKKWAJEfAEKLLNFMCN8FCLLNCQFMFCLLQFcC^F CLFCH HKCKFDHF CXFTCRHNHCFƒ8Ca(FYC"FCH(<<C<A@EF4EAEFA]AEƒHC.F;?.@CF?L¶@ÿ/MTrk´ÄnÿJAZ2ÿFiddle´v][n{ éw”H`BH KN&LIK>L MR&NSM9Nä?;=69512-/,*'&$# "”OZä !"#$'&+(-/0247;9=?@‚.”QZOWQO7O Ta{QRTGQKK#LOKRLOF$OQROQHR‚ HKVOK H1 HJSDJ HUuä?>=;:98654310/.-,+*('&%$#!   ”Hä  &:@ON(U@6?:B@ FA@@?U”?SD?6CSäBEC GLINP"R&T*V2Y8\<^Hd@`NgXlRi^ojudrpxv{z}~”Cäryz}^oxtPh4ZDb Q G@ ”EW>ECS)C??L?<'$<>NI> 9.9<@R<?L#?<6O< 909<@L<?O?F> W'VTG#WJT)WV;!VTD)TWM(V;WVT>#TWM&WV; VTF!TZ9#ZYEY WGW TJ!TR5,O7R#OP;!PQJ'TJQ#TVRDVTCT WK)XLWIXTPATOH&MFOGMH1HKNJKLN$LHLnHJRLJKM&KLCMLMR MOLROä?9<52/(,&$" ”QYä" &$(/,416;9=>@6”QOO.Oä?><;:8641,/(#%! ”QZä "%'+-0358:=?@&”Q OQ3Oä>=<;9:86513/,(#&!    ”Q[ä   !#&,(/3186:?=@/”QOSOO)JTäBEIN Q4Z(U:]@`DbJePhRiXlZm^o`pdrfsbq`pZm^oVkPhLfDb<^4ZN&THA@/”JHHmHJW_JJUbJJWGJEYäBEHKO"R(U6[0X:]Ba>_HdDb @`Db:]4Z(UL Q GB@G”ECUrä>=<:9865421./-+*('”Cä&% '(*-,0.1357:>@ÿ/MTrk:°ÿJAZ2ÿMelody Harmony (below)ÿ/MTrk7°ÿJAZ2ÿ Octaves (no Patch)ÿ/MTrk:³ÃÿJAZ2³[p]ÿJazz Guitar (melody)³ T{ A“3S#4L3.47@ 79K9W7G47 9NE9 7SX7‚ 8U8 97E9[1>(99]J> << ?QY<<>GQ>ZH> W\><@F<6>`=>>L>>Q4>>Q>>N.> 9Ps9 7Zf7Ëy3T*34F(7=4%79J9W7G47 9NE9 7SX7‚ 8U8 97E9[1>(99]J> << ?QY<<>GQ>ZH> W\><@F<6>`=>>L>>Q4>>Q>>N.> 9Ps9 7Zf7y3T*4F3(7=4%79J9E$!!$C7$$?G$('J#'(4W+=(+ -DE-ƒm,K, --E-0=02Q12(--0?V0#2SJ2 00 3GY002=Q20H30-GQ-+?-@+9-7'HW$' &B$Q&$:I$'K'(>7(>+E9+@+DH+.+FH+4+E<+0@(0+B:+)?%':)V$'$ &?K&$D8$,'H '(9K( +>"-E+1-ƒ60P10D3G13E5U?543GB3:5Wp5 3C?35S(5S0G 0T0;03K134>&3B4B34>"094B0+1#-G+K-++0ME0.2PH2 0GA0(080i3735P95:5KB577N<7:7R:7,06F062V=22B22G422G22D.2+Pf+Ëy'J*'(<(+3(%+-@-0K:0?-KE-7+HH+-H -Y$/ $‚$>E$!!$C7$$?G$('J#'(4W+=(+ -DE-ƒm,K, --E-0=02Q12(--0?V0#2SJ2 00 3GY002=Q20H30-GQ+?--@+9-7'HW$' &B$Q&$:I$'K'(>7(>+E9+@+DH+.+FH+4+E<+0@(0+B:+)?%':)V'$$ &?K&$D8$,'H '(9K( +>"+-E1-ƒ60P10D3G13E5U?543GB3:5Wp5 3C?35S(5S0G 0T0;03K134>&3B4B34>"094B0+1#-G+K-++0ME0.2PH2 0GA0(080i3735P95:5KB577N<7:7R:7,06F062V=22B22G422G22D.2+Pf+y'J*(<'(+3(%+-@-0P-0#0)(04:454B(5K4955P5 6B966P67PP9P7%;P92;W3<'T3'<'Wq'T'3'<'Wq,V'H,('L'V,KU,'Vq')VH)($L$V)KU)$Vq$"\T"QD)"XU""Sx"&Qr&'T3'<"Wr'N"p''Zi',\T,'QD'),XU,,Sx,,Qr,)\T)$QD$))XU))Sx)Q)r)"\T"QD)"XU""Sx&Q"r&'\T'"QD")'XU''Sx&Q'r&'W3'>'Z3'< W3 > Z3 <%^H%(,T,V%SU%,^q,W3<)Zq)"`T"Uv"Us""`T"Uv"Us"'`a')OW)+[d+,VH,('L'V,KU,'Vq'T3<$Wr)N$pZ)i"\T"Qv"Qs"'T3'>'W3'<,VH,('L'V,KU,'Vq',X3,<'[r R'p ,^i,)_T)$TD$))[U))Vx)!Tr!"_T"TD)"[U""Vx"&Tr&'X3'<"[r'R"p'^'i',_T,'TD'),[U,,Vx,T,r,)_T)$TD$))[U))Vx))Tr)"_T")TD))"[U""Vx"T"r"'_T'"TD")'[U''Vx&T'r&'W3'>'Z3'=,`T,'Uv,U's,%^H%(,T,V%SU%,^q,)Vp$Z)j$"`T"Uv"Us""gJB"'"\v"&\s&'W3'<'Zq,X'3,<'[r R'p,^ i,)_T)$TD$))[U))Vx!T)r!"W3">"Z3"='Vp"Z'j",_T,'TD'),[U,,Vx,+Tr+,\T,'QD'),XU,,Sx(Q,r()\T)$QD$))XU))Sx!Q)r!"\T")QD))"XU""Sx"Q"r"'T3'<"Wr'N"p'Z'i',\T,'QD'),XU,,Sx,(Qr()T3)<$WrN$p)Zi)"\T")QD))"XU""Sx""Qr"'VH'(.L.V'KU'.Vq.'W3'<'Zq' W3 <,Zq,%_T% TD )%[U%%Vx(T%r()W3)<Zq"`T"Uv"Us""W3">"Z3"='`T'"Uv"'Us',T3,<'Wr N'p ,Zi,)T3)<$WrN$p)Zi)"\J"7"'$Q"v$%Qs%']a')LW)",Xd,,Sp'W,j' T3 <,Wq,N,,S'N#'M,^O,! f ÿ/MTrkƹÉÿJAZ2¹{x][( @ÿDrumsƒ`™#<*P*#_&<*P&*_#<*P*#_&F*F*&7*<*#<*P#*_&<*P*&_#<*P*#_&F*F&*_#<*P#*_&<*P*&_#<*P#*_&F*F&*7*<*#2*P*#_&<*P*&_#2*P#*_&F*F&*7&Z*2*&#<*P*#_&<*P*&_#<*P*#_&F*F&*7*<*#<*P#*_&<*P&*_#<*P*#_&F*F&*7*<*#<*P#*_&<*P&*7*2*#<*P*#_&F*F*&7*<*#<*P*#_&<*P&*_#<*P#*_&F*F*&_#<*P#*_&<*P&*_#<*P#*_&F*F*&7*<*#<*P*#_&<*P*&_#<*P*#_&F*F&*7*<*#<*P*#_&<*P&*7*2*#<*P*#_&F*F&*_#2*P#*_&<*P*&_#2*P#*_&F*F&*7*2*#<&2*21<*#1&_*P&F*&_*P#<*#_&F*F*&7*P**P#<#*_*P&<&*_#<*P#*_&F*F&*_*P#<*#_*P&<&*_#<*P#*_&F*F&*7*<**P#<#*_*P&<&*_#<*P#*_&F*F*&7*<**P#<#*_*P&<*&7*2*#<*P*#_*F&F&*_*P#<*#_&<*P*&7*2*#<*P#*_*F&F&*_*P#<*#_&<*P*&_#<*P#*_&F*F*&7*<*#2*P*#_&<*P&*7*2*#2*P#*_&F*F*&7*2*#<1F&<1#&_3P&F&3733#F3<3#_&P3F3&7333<#2#3_&<3F3&73(3#<3F3#_3<&F&3733#23<#3_&<3F&37333F#<#3_3<&F&3733#23<#3_3F&<3&73(3#<3F#3_&F3<&37333<#23#_3F&<3&733#<3F3#_&F3<3&7333<#2#3_&<3F3&73(3#<3F#3_&F3<3&733#<3F#3_&F3P3&7333F#F3#_&F3P3&73(3#<3F#3_3P&F3&733#<3F#37&F&&Z3P3&73(&F3&*P#<#*_&<*P*&_#<*P*#_*F&F&*7*(**P#<*#_&<*P&*7*2**P#<#*_*F&F*&7*<*#<*P#*_&<*P*&_*P#<#*_*F&F&*_#<*P*#_&<*P*&_*P#<#*_*F&F*&7*<*#<*P*#_*P&<&*7*2**P#<*#_&F*F*&_*P#<#*_*P&<*&_#<*P*#_&F*F&*7*<**P#<#*_*P&<&*_#<*P#*_&F*F&*7*<**P#2#*_&<*P&*7*2*#2*P#*_*F&F*&7*2&Z*&#<&<1F#1&_3P&F3&7333<#F3#_&P3F&373(33F#<#3_&F3P&3733#F3F#3_&F3P3&73(33F#<#3_&F3P3&73(3#F3F3#_3P&F3&733#23<3#_&<3F&373(33F#<3#_&F3<&3733#<3F3#_3P&F&373(3#F3F3#_&F3P&373(33<#2#3_3F&<3&73(3#<3F3#_&F3<&37333<#2#3_&<3F&373(33F#<#3_3<&F3&733#<3F3#70203P&F&370<3033F-<3-7-<-&P3P3&7-P3-3#<&<1F&#1_&F3P3&73(33<#F3#_3F&P&373(3#<3F3#_3P&F3&73(33F#F3#_&F3P&37333F#<#3_&F3P&3733#F3F#3_&F3P&3733#<3F3#_3P&F3&733#F3F#3_3P&F3&73(33<#2#3_&<3F&373(3#<3F3#_3<&F3&733#23<3#_3F&<3&73(33F#<#3_&F3<&373(33F#<#3_3P&F3&73(3#F3F#3_3P&F3&73(33F#<3#7020&F3P3&70<3303F-<3-7-<-&P3P3&7-P3(-31F&<#<1&#_&F3P&373(33<#F3#_&P3F3&73(3#<3F3#_&F3P&373(3#F3F3#_3P&F3&733#<3F3#_3P&F3&7333F#F3#_&F3P3&7333<#2#3_&<3F&3733#<3F#3_&F3<&37333F#<#3_&F3P3&73(3#F3F3#_3P&F3&73(3#23<3#_&<3F&373(33F#<#3_&F3<&373(3#23<3#_3F&<3&73(3#<3F#3_&F3<&373(33F#<3#7020&F3P&373(0<033F-<3-7-<-3P&P&373(-P3-#<1F&<#1&_3P&F3&73(3#F3<3#_&P3F&37333F#<#3_&F3P3&733#F3F3#_&F3P&3733#23<#3_&<3F&373(3#<3F#3_&F3<&373(3#<3F3#_&F3P3&733#F3F3#_&F3P&373(3#23<#3_&<3F&3733#<3F#3_&F3<3&733#23<3#_&<3F&373(3#<3F#3_&F3<&373(3#<3F3#_&F3P3&73(33F#F#3_&F3P&373(3#<3F3#_3P&F3&733#<3F3#7&F&&Z3P3&73(3&2*21<#<&#1*_&F*P*&_*P#<*#_*F&F*&7*P*#<*P*#_*P&<*&_*P#<#*_&F*F&*7*<*#<*P*#7*(**P&<&*_#<*P*#_&F*F*&7*(**P#<*#7*(*&<*P&*_#<*P*#_*F&F&*_*P#<#*_&<*P&*_#<*P*#_*F&F*&_*P#<*#_&<*P&*7*2*#<*P#*_*F&F*&_*P#<#*_&<*P*&_*P#<*#_*F&F*&7*(*#<*P*#_&F*P&*_*P#<#*_*F&F*&7*P*#<*P#*_*P&<*&7*2*#<*P*#_&F*F*&7*<**P#<#*_*P&<*&7*2*#<*P*#_&F*F&*7*(**P#<*#_&<*P*&_#<*P*#_*F&F&*_*P#<#*_&<*P*&_#<*P#*_*F&F&*_*P#<#*_&<*P&*7*2*#<*P*#_*F&F&*_*P#<#*_&<*P*&_*P#<#*_&F*F&*_*P#<*#_&<*P*&_*P#<#*_&F*F*&7*<*#<*P*#_*P&F*&7*F**P#<#*_&F*F&*7*P*#<&<1F&1#_3P&F3&733#F3<3#_3F&P3&73(33F#<3#_&F3P&373(33F#F#3_&F3P3&73(3#23<3#_3F&<3&73(3#<3F3#_3<&F3&73(33<#23#_&<3F&37333F#<#3_&F3<3&733#<3F3#_3P&F3&733#F3F3#_3P&F3&7333<#23#_&<3F3&73(3#<3F3#_3<&F3&73(3#23<3#_3F&<3&73(33F#<#3_&F3<&37333F#<#3_&F3P&3733#<3F#37&F&3P&Z&37&F33&*2#<&21<*&1#_&F*P*&_#<*P*#_*F&F*&7*P**P#<#*_&<*P*&_#<*P*#_*F&F&*7*<*#<*P*#_&<*P&*7*2**P#<#*_*F&F*&7*<*#<*P*#_*P&<&*_*P#<#*_&F*F&*7*<**P#<#*_&<*P*&_*P#<#*_&F*F*&7*<**P#<#*_*P&<*&7*2*#<*P*#_*F&F*&7*<**P#<#*_*P&<&*_*P#<*#_*F&F*&7*<**P#2#*_*P&<*&7*2**P#2*#_*F&F*&7*2&Z&*3F#<#3_&F3P&37333F#<3#7&F&&Z3P&37&F3(&3#P*P#*7#F#*P&F*&_&212#P*P*1#&ÿ/MTrk ª²ÂÿJAZ2²_[]ÿPiano²{ O@ƒd’F9,%<1?GƒNF?,< :L3;73:71C9,%?;81=.5<8 ==:A5;8C.0ƒN8:.5==F:@30'+7EƒN3':=7?A:8…I<1F:!<F><;FL7<F?:?=FL<;7<F?:C;F50<@.+8EƒN<58.>=F50:@8E.+ƒN=8:5. =;7I';30:?ƒN²@L’3:'=7²@’F=<;?C,0‡.?<,F8K33),…8?CHSKRF],7FH K ,?²@ÿ/MTrkpºÊÿJAZ2ºZ][<{ 'Z][<{ 'Z][<{ 'Z][<{ZZ '[<{ '][<Z 'ÿGuitarº]][# '@{{„Oš338=<=?=D=D3<?8N388B³@“=$66³@“:8`4b A5A6 4*5 8&8V6b3Y836875Z8ZO58&3i8eI38'5F³@K“87,:L 8D8E+:.³@@“6d805:6H58V@58":ZV:'C_D5BVC,BAJ*DP,AENDFRE6MNBPYM7O_P5NVO,NMJ.PDFM%P&MOMM1K8sMRK7K MPPKIP)MQHKOM K‚3HZ6F=HFGDW=DFc1K:FrM[K6K% MKOQPFOCP P`HPM[0PZM3YX*W@YlYm-W4YPS\YW#R0 S$PJYRR^#PRT\7PFT9PMC#³@“OcMPIOLMcPGHY M#DgH*AQO³@ “=O#:B A =³@“=U:Dc³@=“?L³@ “A??=Aq=a.=<&$:0<)AN :?)A=6?F^=A8F%?=A$ALFH?C)A2?FCFOAT ?DAF FI?@@³@@0“? F‚P=aJ?Y+=+AT%?*ADUGFQI:FAO0=5A:=1³@ “=QFH?= F*³@“?^HH$?HIWAG³@'“A I;HK?U$?=NFDHR= FLb MWLJMLcMQL‚MOv.OKR_3OH R%OGK7IK³@“KQFK³@ “FINFGK³@3@-“FI%³@“IgFFQO³@ “BO#?B F B³@“?IBDK)?&=[ 8?8T==8:i³@“8NAK :@=`DY8=AD5Bk:Y+:3P8QB5>35 83U8N/0738Q³@“1^8W03= 1F38³@ “5\=dD³@@:“5=2?XAJ!?cA :V;P!:;89.8:^:\8r;8 7k57 5W352S3³@ “1Q:H2;1 :*³@“3^C_D5BVC,BAJ*DP,AENDFRE6MNBPYM7O_P5NVO,NMJ(Pk FM)P%PaWP PdOP^ P4P0PcIP2PaVP"Pa1PPUcPP`cPRJOP/R RKWFSFPTDSRTRDWW?S\ TWSRR>T`PK'R!³@@&“PKO7 W MEOKDM&KRGPQRO7 P8T.R:OT PFRPAMs)MKU3KHI?F? H-D FDSAs)A?U3?C'HC;Aa3AL?3(?AeBA?Y-;`?":5;!8=:":c?U818: ? 8?G:CP8H ?³@ “:8n³@ “B`DDA'B D?:yA[?6?% A?CQDFCCD D`HDA[7DUA-C_D5AFC*C_ A³@“KQFRCH1F F3H D: K F³@@Y“D1Dc?\ AF?+DA$?UDU@D?;DU?7AF?$A DDZ?Z³@@(“?D7_856V7,65J*8P,59N8:R96ANBDYA7C_D5BVC,BAJ)D>:A%D'D=o?7OA/ D?D?AFFEDD=FMDD@pDÿ/MTrk<°ÿJAZ2ÿJourney to Times Gone Byÿ/simutrans-124.3/simutrans/music/34-flyingaway.mid000066400000000000000000000150241474050137200220130ustar00rootroot00000000000000MThdÀMTrkwÿ By ÿCopyright © 2007 ÿAll Rights Reservedÿ Generated by NoteWorthy ComposerÿQ 'ÀœÿQ 'Àÿ/MTrk<ÿ!ÿStaffÀI°° @ŒJnˆPJ0Ln^LJn^JEn^EGn^GHn.HGn.GHn‡pH0Jn^JHn^HCn^CEn^EGn.GEn.EGnƒ0G0Jn J On„O0Sn S QnˆPQƒ0JnˆPJ0Ln^LJn^JEn^EGn^GHn.HGn.GHn‡pH0Jn^JHn^HCn^CEn^EGn.GEn.EGnƒ0G0Jn J On„O0Sn S TnˆPTƒ0On‹ONn^NOn‹PO0On‹OOn^OQn‹PQŒ0JnˆPJ0Ln^LJn^JEn^EGn^GHn.HGn.GHn‡pH0Jn^JHn^HCn^CEn^EGn.GEn.EGnƒ0G0Jn J On„O0Sn S QnˆPQƒ0JnˆPJ0Ln^LJn^JEn^EGn^GHn.HGn.GHn‡pH0Jn^JHn^HCn^CEn^EGn.GEn.EGnƒ0G0Jn J On„O0Sn S TnˆPTƒ0On‹ONn^NOn‹PO0On‹OOn^OQn‹PQŒ0On‹ONn^NOn‹PO0On‹OOn^OQn‹PQÿ/MTrkžÿ!ÿStaff-2ÂI²² @¼’GnˆP’G0’Hn^’H’Gn^’G’Bn^’B’Cn^’C’Cn.’C’@n.’@’Cn‡p’C0’Gn^’G’En^’E’@n^’@’Bn^’B’Cn.’C’>n.’>’Cnƒ0’C0’Gn ’G ’Jn„’J0’On ’O ’NnˆP’Nƒ0’Gn‹’G’Gn^’G’Hn‹P’H0’Hn‹’H’Hn^’H’Jn‹P’JŒ0’GnˆP’G0’Hn^’H’Gn^’G’Bn^’B’Cn^’C’Cn.’C’@n.’@’Cn‡p’C0’Gn^’G’En^’E’@n^’@’Bn^’B’Cn.’C’>n.’>’Cnƒ0’C0’Gn ’G ’Jn„’J0’On ’O ’NnˆP’Nƒ0’GnˆP’G0’Hn^’H’Gn^’G’Bn^’B’Cn^’C’Cn.’C’@n.’@’Cn‡p’C0’Gn^’G’En^’E’@n^’@’Bn^’B’Cn.’C’>n.’>’Cnƒ0’C0’Gn ’G ’Jn„’J0’On ’O ’NnˆP’Nƒ0’Gn‹’G’Gn^’G’Hn‹P’H0’Hn‹’H’Hn^’H’Jn‹P’JŒ0’Gn‹’G’Gn^’G’Hn‹P’H0’Hn‹’H’Hn^’H’Jn‹P’Jÿ/MTrk&ÿ!ÿStaff-4Ê!ºº @ìš(n…š(š(n^š(š(n…š(š&n^š&š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š&n…š&š&n^š&š&n…š&š&n^š&šn…ššn^ššn…ššn^ššn…ššn^ššn…ššn^šš$n…š$š$n^š$š$n…š$šn^ššn…ššn^ššn…ššn^šš&n…š&š&n^š&š&n…š&š&n^š&šn…ššn^ššn…ššn^šš$n…š$š$n^š$š$n…š$šn^ššn…ššn^ššn…ššn^šš&n…š&š&n^š&š&n…š&š&n^š&š(n…š(š(n^š(š(n…š(š&n^š&š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š&n…š&š&n^š&š&n…š&š&n^š&šn…ššn^ššn…šš&n^š&š(n…š(š(n^š(š(n…š(š&n^š&š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š$n…š$š$n^š$š&n…š&š&n^š&š&n…š&š&n^š&šn…ššn^ššn…Pšÿ/MTrk vÿ!ÿStaff-1Á±± @‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘‘@‘‘<‘@n^‘@‘4n^‘4‘7n^‘7‘‘@‘‘<‘@n^‘@‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘‘@‘‘<‘@n^‘@‘4n^‘4‘7n^‘7‘‘@‘‘<‘@n^‘@‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘/n^‘/‘4n^‘4‘7n^‘7‘;n>‘;‘7n>‘7‘;n^‘;‘0n^‘0‘7n^‘7‘;n^‘;‘‘<‘7n>‘7‘‘<‘7n>‘7‘‘@‘‘<‘@n^‘@‘4n^‘4‘7n^‘7‘‘@‘‘<‘@n^‘@‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘2n^‘2‘6n^‘6‘7n^‘7‘9n>‘9‘7n>‘7‘>n^‘>‘7n^‘7‘;n^‘;‘n>‘>‘;n>‘;‘>n^‘>‘Cn…P‘Cÿ/MTrkéÿ!ÿStaff-3¹¹ @œ™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™#n‚™# ™#n^™#™&n‚P™&0™9n…P™9ÿ/simutrans-124.3/simutrans/music/35-deep-ride.mid000066400000000000000000002014251474050137200215020ustar00rootroot00000000000000MThdxMTrk‡ÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿnjÿvj  ¸FK@@ (  L  ÿ~j€'*0$*$*$ * ÿ~j(**L *@ºS@$*  ¸'FK@@ÿ~j 0$ $ L  0$ $*$ÿ~j *0**L*@ºS@$* ¸'ÿ~jFK@@'*(  L   ( ÿ~j    (  L  @ºS@  ÿj'ÿXÿQÈÿYÿ Deep Ride°c @[(]ÿ/MTrk Q±Á ÿJAZ2±][{@ [ÿBass±Zp‘Rƒ[]ƒ8TVƒ8][ƒ["x"x$Z$+m+ $P$($P$(#P#(#x#'Z'.m. )x$)x"$x"x$Z$+m+ 'x"'x".""$C$ $L("$Z")m) $x$x'Z'.m. $Z$+m+ . " L" "Z"$Z$+m+ "Z")m) $.$"$"$+C+ +($+x$x$x$x'Z'.m. )x$)x$"x"x$Z$+m+ 'Z'.m. )x)$x"$Z")m) $Z$+m+ Oƒ[\ƒ[Z$m$ 'x'$x&$Z&)m) $Z$+m+ Z$m$ )x)$x'$Z'.m. "Z"#x#$Z$+m+ !Z!(m( Z 'm' +x+&x*&P*(!P!(*P*(!P!()x$)x+$x+&x&"Z")m) $Z$+m+ $x$x$x$x'x'"x)"x)$x"$x"x$Z$+m+ 'x'"x"Z$m$ "x"x$Z$+m+ Pƒ[Wƒ8^".""""")C) )()$x$x$P$(+P+($x$+P+('Z'.m. )x$)x"$.""""")C) )L($)x$x'x"'x"Z$m$ "x"x$x$x'x"'x$".$"$"$+C+ +(,+x",x$"Z$+m+ "Z")m) $x$x$x$x$x$x'Z'.m. )x$)x"$Z")m) $Z$+m+ 'x"'x"Z$m$ "Z")m) $Z$+m+ Mƒ[Qƒ[)x$)x'$.'"'"'0C0 0L(&0Z&)m) $Z$+m+ .""$C$ $()$x$)x$'x"'x""Z"#Z#$Z$+m+ !x!x Z 'm' +x&+x&*P*(!P!(*P*(!P!()x$)x$Z&m& ".""""")C) )L()$Z$+m+ $x$x$x$x'Z'.m. Z$m$ "Z")m) $Z$+m+ 'Z'.m. )x$)x"$x"x$Z$+m+ [ƒ[Sƒ["Z")m) $Z$+m+ $P$(+P+($x+$P+('Z'.m. Z$m$ "x"x$x$x'Z'.m. )x$)x$"x"x$Z$+m+ 'Z'.m. $Z$+m+ ,x",Z"$x$x"Z")m) $Z$+m+ $x$x$x$x'Z'.m. Z$m$ "Z")m) $x$x'Z'.m. )x$)x$"Z")m) $Z$+m+ \ƒ8MPƒ8XZ$m$ 'x$'x$&x&x$x$x)x$)x)$x$)x$'x"'x""."""L""#Z#$.$"$"$+C+ +(!+x!x,x,'x+'Z+2m2 *P*(!P!(*P*(!P!(Z$m$ Z&m& "Z")m) $Z$+m+ $P$($P$(#P#(#x'#Z'.m. Z$m$ "x"x$Z$+m+ 'Z'.m. )x$)x"$x"x$Z$+m+ Xƒ[Mƒ[$P$(+P+($x+$P+($Z$#2$D$ÿ/MTrk=¹ÉÿJAZ2¹{s]ÿDrums¹[ @p™$*@P**+(&*@$*P**+(*$*@(&(*+*($**@&P**+($&**@P*+*($&**@P**+($**@(&(**+(*@*$&P**+(*@$&*P*+*(*@&$*P*+*($*@*(&(*+*(&*$*@P*+*(&*$*@P**+(&$**@P*+*($**@(&(&*+*&$*@&*&;&*+*&$**@P*+*(*@*$&P*+*(*@*$(&(**+(&*$*@P**+($*&*@P*+*($*@&*P**+($*@*(&(&**+&*$&*@&;*&*+&*$*@P**+(&$*@*P*+*(*@$*(&(*+*(**@$&P**+($**@&P**+(*@*$&P*+*($**@(&(**+(&$**@P**+(*@&*$P**+(&*$*@P*+*($**@(&(*+*(*@$*&P**+(*@*&$P**+(&*$*@P**+(*@*$(&(**+(*@*&($(**+($&**@P**+(*@*&$P**+($**@(&(**+(&*$*@P*+*($&*@*P*+*(*@$*&P**+(*@*$(&(**+&&*@*$&&;&*+*&$**@P*+*(&$**@P*+*($&**@P*+*(*@$*&P**+(*@*&$P*+*(*@$*&P**+(*@*$(&(*+*(**@&($(**+($&**@P*+*(&$**@P*+*(*@*$(&(**+(&$**@P**+($&**@P*+*(*@$*&P*+*(*@*$(&(*+*(&*$*@P**+(*@*&$P*+*(&*$*@P*+*(*@*$(&(*+*(&*$*@P**+($&**@P**+(&*$*@P**+($**@(&(*+*(*@*&($(*+*(*$&*@P**+(*@*$&P*+*($*&*@P*+*(*@$*&P**+($&**@P**+(*@*$&P*+*($**@(&(**+&&*@*$&&;**+&&$**@P**+(*@*$&P*+*($**@(&(**+(*@*$&P*+*($*&*@P*+*(&$**@P*+*(*@*$(&(**+(*@$*&P**+($*&*@P**+(*@*$&P**+(*@&*$P**+(&$**@P**+($&**@P**+(&*$*@P**+($**@(&(**+(&$*@*P*+*(*@&*$P*+*(&*$*@P**+($**@(&(**+(&*$*@P*+*($&**@P**+(*@$*&P**+($**@(&(**+(&**@($(*+*(*@&*$P**+(*@$*&P**+(*@&*$P*+*(&$**@P**+(*@&*$P**+(&*$*@P**+($**@(&(**+(&$**@P*+*(*@&*$P**+(&$**@P**+($&**@P**+(*@*$&P**+(*@*&$P**+(&*$*@P*+*($**@(&(*+*(&$**@P*+*($&**@P**+(&*$*@P**+(*@*$(&(**+(&$**@P**+(*@&*$P*+*(*@*$&P*+*(*@*$(&(**+(*@$*&P**+($&**@P**+(&*$*@P*+*($**@(&(**+(*@*$&P*+*(&*@$*P**+(*$*@&P*+*(*@$*(&(**+(&*$*@P**+($*&*@P*+*($*@*&P*+*($**@(&(*+*(*@$*&P**+(*@*&$P**+(*@*$&P*+*(*@*$(&(*&*+&&*$*@&;*+&*&*@*$P**+(*@$*&P**+(*@&*$P*+*(&$**@P**+($&**@P**+(*@$*&P*+*(*@*$(&(**+(*@*&($(**+($*&*@P**+(*@*$&P**+($*&*@P**+(*@*$&P**+(*@*&$P**+(*@*$&P**+(*@*$(&(*+*(*@*&($(**+(*@*&$P**+(*@*$&P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P**+(*@*$&P*+*(*@*$(&(*+*(*@$*&P**+(*@&*$P**+(*@$*&P*+*(*@*$(&(**+(*@$*&P**+(*@*&$P**+(&$**@P*+*($**@(&(*+*(&**@($(*+*($*&*@P**+(&*$*@P**+(*@*$(&(**+(&*$*@P**+(*@&*$P**+(&*$*@P*+*($**@(&(*+*(*@*$&P**+(*@&*$P*+*(*@$*&P**+($**@(&(*+*(*@*$&P**+(*$&*@P**+(&*$*@P**+(*@*$(&(**+(*@*$&P**+(*@*&$P**+(*@*$&P**+(*@&*$P**+(*@*$&P**+(*@&*$P**+(*@*$&P*+*($**@(&(**+(&**@($(*+*(*@*&$P**+(&*$*@P*+*(*@*$(&(**+(&*$*@P*+*(*@*&$P**+(&$**@P*+*(*@*$(&(*+*(&**@($(*+*(*@*&$P**+(&*$*@P*+*(*@*$(&(**+(*@*$&P**+($*&*@P**+(&$**@P*+*($**@(&(*+*(*@*$&P**+($*&*@P*+*(*@*$&P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P**+(*@$*&P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P**+(&*$*@P*+*($**@(&(*+*(*@*$&P**+($*&*@P**+(&$**@P*+*($**@(&(*+*(&*$*@P*+*(*@*&$P**+(*@*$&P*+*(*@*$(&(**+(&*$*@P*+*(*@*&$P**+(*@*$&P*+*(*@*$(&(**+(&*$*@P*+*(*@*&$P**+(*@*$&P*+*(*@*$(&(**+(&*$*@P*+*(*@*&$P**+(&$**@P*+*($**@(&(**+(&**@($(*+*($*&*@P*+*(*@*$&P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P**+(&$**@P*+*($**@(&(*+*(*@*$&P**+(*@*&$P**+(*@*$&P*+*($**@(&(*+*(&*$*@P*+*($*&*@P**+(*@$*&P*+*($**@(&(*+*(&**@($(**+(*@&*$P**+(&*$*@P*+*(*@*$(&(*+*(&$**@P*+*($*&*@P**+(*@*$&P*+*($**@(&(*+*(&**@($(*+*($*&*@P**+(*@*$&P*+*(*@*$(&(*+*(*@$*&P**+(*@*&$P*+*(&$**@P*+*(*@*$(&(**+(*@*$&P**+($*&*@P*+*(*@*$&P*+*($**@(&(**+(&*$*@P*+*(*@*&$P*+*(*@$*&P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P*+*(*@$*&P**+(*@*&$P*+*(&$**@P*+*($*&*@P**+(*@*$&P*+*(*@*$(&(*+*(&**@($(*+*($*&*@P**+(*@*$&P*+*(*@*$(&(*+*(&$**@P*+*(*@*&$P*+*(*@$*&P*+*($**@(&(**+&&*@*$&&;**+&&*@*$P**+(*@*$&P**+($**@(&(*+*(&*$*@P**+(*@&*$P**+(*@*$&P*+*(*@*$(&(**+(&*$*@P**+(*@&*$P**+(&*$*@P**+($**@(&(*+*(*@*$&P**+($&**@P*+*(*@*$&P*+*($**@(&(*+*(&*$*@P**+(*@&*$P**+(&*$*@P**+(*@&*$P**+(&*$*@P**+($&**@P*+*(*@*$&P*+*(*@*$(&(*+*(&**@($(**+(*@&*$P**+(*@*$&P**+(*@*$(&(**+(&*$*@P**+(*@&*$P**+(*@*$&P**+(*@*$(&(&*+*&*@*$&&;&**+&$**@P*+*(*@*$&P*+*(*@*$(&(**+(&*$*@P*+*($*&*@P**+(*@$*&P*+*($**@(&(*+*(*@*&($(**+(*@*&$P**+(&*$*@P*+*(*@*$(&(**+(*@*$&P**+(*@*&$P**+(*@$*&P*+*($**@(&(*+*(&*$*@P*+*($*&*@P*+*(&*$*@P*+*($**@(&(*+*(&*$*@P*+*($*&*@P**+(&$**@P*+*(*@*$(&(**+(&*$*@P**+(*@&*$P**+(&*$*@P*+*($**@(&(**+(&*$*@P*+*($*&*@P**+(*@*$&P*+*(*@*$(&(**+(&*$*@P*+*(*@*&$P*+*(*@$*&P**+($*&*@P**+(*@*$&P**+($*&*@P**+(&*$*@P*+*($**@(&(*+*(&*$*@P*+*($*&*@P**+(*@*$&P*+*($**@(&(**+(&*$*@P*+*(*@*&$P*+*(&$**@P*+*(*@*$(&(*+*&&&*$*@&;**+&&*@*$P**+(*@*$&P**+(*@*$(&(**+(*@*$&P**+($&**@P*+*(*@*$&P*+*($**@(&(*+*(*@*$&P**+(*@*&$P*+*(*@$*&P**+($*&*@P*+*(*@*$&P**+($*&*@P*+*(&*$*@P*+*(*@*$(&(&**+&&$**@&;*+&*&$**@P**+(*@$*&P*+*(*@*$(&(*+*(&*@*$P*+*(&*@$*P*+*(*@&$*P*+**n&**ÿ/MTrkDí²ÂÿJAZ2²][ { <ZÿPiano²@p’@Z+Z>Z7Z7>@9>Z7Z@Z7>@7Z@Z>Z+7>@5>Z7Z+Z@Z7>@7Z>Z@Z7>@+1+Z@Z7Z>Z>7@@Z>Z7Z7>@ ++7Z>Z@Z+Z>7@+9Z+Z>Z<92>Z< Z<9>52>Z9Z5Z< >Z+92>Z9Z+Z+9 9Z5Z>Z<2Z9Z5Z<>95 0ZJZLZCZLJC8LZCZJZ0LJCCZLZJZ$ZLJC;JZCZLZ$CJLJZLZ0ZCZLCJ>LZJZCZ 0LJCCZJZ$ZLZL CJ;$CZLZJZ LCJ0ZCZLZJZLCJ=JZCZLZLJ0CJZLZ$ZCZJLC4$CZLZJZLJCLZCZ0ZJZLJC;CZJZLZLJ0CLZJZCZ$ZLCJ5$ J6L6C6 JCLJZ2ZAZFZAJF/JZFZAZ 2JAFAZ.ZFZJZJFA4AZJZFZ . JAF7ZZ5Z.Z>5:..Z5Z>Z:Z:>5.>Z:Z5Z)Z>5: ):6>656)6>:5 ) @Z7Z0Z@7 0.0Z@Z7Z@7 00Z@Z7Z7@00Z@Z7Z @77Z:Z3Z0?Z7?:3 3Z?Z:Z7Z7?: 3"Z:Z?Z7Z7?:""7Z?Z:Z"Z :7?"5ZZ5:>9>Z:Z5Z:5>:Z5Z>Z.5:>556:6>6.65:>HZCZ4Z.LZCLH/CZLZHZ 4LCHHZCZ0ZLZLHC4HZCZLZ 0 LCHCZ'ZKZFZKFC8CZFZKZ'KFCCZKZFZ'ZKFC;F6C6K6'CFK@ZZ5Z5:>9>Z5Z:Z5:>>Z5Z:Z.5:>5.6:6>6565:>@ZZ.Z> :5 .">Z5Z:Z.Z >:5.:Z>Z5Z)Z>5:))Z:Z>Z5Z>5:)LZ4ZHZCZCLH/CZHZLZ 4LCHHZLZ0ZCZLHC4HZLZCZ 0 LCHCZ3ZFZKZCKF/CZFZKZ 3KCFFZ'ZCZKZKFC4K6F6C6 ' KCFZ.Z5:>9:Z>Z5Z5:>>Z5Z:Z.5:>556>6.6:65:>7Z@Z.Z.Z>5:..6>6:656:>5.4Z@Z7ZZ:Z5Z.Z>5:..Z:Z>Z5Z:>5.;Z3Z?Z6Z6?;3 36;666?66?; 3@Z7ZZ +">Z<+CZZ&ZC<>&&ZCZ>Z&9Z6ZZ5Z.Z>5 ...Z>Z5Z>5 ..Z>Z5Z5>..Z5Z>Z >5CZHZ0Z.LZLHC8LZCZHZ0LHCLZ$ZCZHZLHC;LZHZCZ$CHL@Z7ZZ5Z.Z>5 ...Z>Z5Z>5 ..Z5Z>Z5>..656>6 >5@ZZ)5Z5:>9>Z:Z5Z:5>>Z:Z5Z.5:>5:6>656.65:>@Z7Z.0Z@7 0.0Z@Z7Z7@ 00Z7Z@Z7@006@676 @7KZFZCZ0+ZKFC8CZFZKZ+KFCKZ+ZFZCZKFC;CZKZFZ+CFKZ5Z.Z5:>95Z:Z>Z5:>7Z0Z@Z.Z.Z>5 ...Z5Z>Z5> ..Z5Z>Z5>..656>6 >57ZZ)5Z.Z>5 ...Z>Z5Z>5 ..Z>Z5Z5>..Z>Z5Z >5@Z7Z.0Z@7 0.0Z@Z7Z7@ 00Z7Z@Z7@00676@6 @7'ZCZKZ0FZKFC8CZFZKZ'KFCCZFZKZ'ZKFC;KZCZFZ'CFK@ZZ:Z.Z> :5 .":656>6.6 >:5.LZ4ZHZCZCLH/HZLZCZ 4LCH0ZLZCZHZLHC4LZCZHZ 0 LCH:Z5Z>Z.Z> 5: .">Z:Z5Z.Z >:5.5Z:Z>Z)Z>5:))Z>Z5Z:Z>5:)LZHZ4ZCZCLH/CZLZHZ 4LCH0ZHZLZCZLHC4CZLZHZ 0 LCHHZCZ4ZLZLCH=HZCZLZ4 LHCHZLZCZ0ZLCH9HZCZLZ 0CLHHZ4ZCZLZCLH=CZHZLZ 4LCHHZCZLZ0ZLCH70C6H6L6LHC?Z:Z7Z'Z? :7 '"?Z7Z:Z'Z ?:7'7Z?Z:Z"Z?7:""676?6:6?7:"9ZAZZ5Z.Z> 5: ."5Z>Z:Z.Z >:5.:Z5Z>Z)Z>5:))6:6>6565>:)Z.Z5Z:Z5:>95Z:Z>Z5:>Z2Z> 5: 2":Z5Z>Z2Z >:52>Z5Z:Z)Z>5:))6:656>6>5:)Z:Z.Z>5:..Z>Z5Z:Z:>5.KZBZGZ3ZBKG/G6K6B6 3KBGHZ0ZLZCZLHC8CZHZLZ0LHC$ZCZHZLZLHC;L6H6C6$CHLZ++Z>ZC<+>ZCZ &ZCZ&ZC>< & 9Z6ZBZZ.Z> 5: .">Z:Z5Z.Z >:5.>Z5Z:Z)Z>5:))Z:Z5Z>Z5>:)@ZZ:Z5Z5>:2 2Z:Z>Z5Z5>: 2)Z5Z:Z>Z5>:)":656>6)6 :5>)@ZZ5Z.Z> 5: .">Z:Z5Z.Z >:5.Z:Z.Z>5:..Z:Z>Z5Z:>5.5Z>Z:Z)Z>5: )5Z:Z>Z)Z>:5 ) CZLZ0ZHZLHC8HZCZLZ0LHCCZHZ$ZLZLHC;L6C6H6$CHL7Z?Z'Z?7 '.'Z?Z7Z?7 ''Z?Z7Z7?''6?676 ?7HZMZEZ'5ZEMH/MZEZHZ 5MEHHZ)ZEZMZMHE4M6H6E6 ) MEH.Z>Z:Z5Z5:>9>Z:Z5Z:5>:Z5Z>Z.5:>5:Z.Z>Z5Z5:>@Z7Z.Z.Z5Z:Z5:>9>Z5Z:Z5:>5Z:Z>Z.5:>55Z:Z.Z>Z5:>@Z.7Z0Z@7 0.0Z@Z7Z7@ 00Z@Z7Z7@006@676 @7:Z7Z0?Z'Z?7:''Z7Z:Z?Z:?7':Z?Z7Z"Z?7: ":6?676"6?:7 " MZEZHZ)ZMHE8MZEZHZ)MHE)ZMZEZHZMHE;E6M6H6)EHMFZAZJZ.ZJFA8AZJZFZ.JFAAZ"ZJZFZJFA;FZJZAZ"AFJ@ZZ5Z2Z>5 2.2Z5Z>Z>5 22Z5Z>Z5>226>656 >5HZLZ0Z2CZLHC8CZHZLZ0LHC$ZHZLZCZLHC;H6C6L6$CHLHZAZEZ)ZHEA8EZAZHZ)HEA)ZHZAZEZHEA;H6E6A6)AEHHZ)ZEZMZMHE8EZHZMZ)MHEHZ)ZMZEZMHE;M6H6E6)EHM7Z?Z'Z?7 '.'Z7Z?Z?7 ''Z7Z?Z7?''Z?Z7Z ?7AZ.ZJZ'FZJFA8J6A6F6.JFAKZ/ZGZBZKGB8BZGZKZ/KGB7Z@ZHZEZLZ 6LHE*ZHZLZEZL EH;*LZHZEZ LEH9Z)Z5Z?Z59?95Z?Z9Z59?9Z5Z?Z)59?5?69656)659?+ZGZJZ)CZJGC8JZCZGZ+JGCCZ+ZGZJZJGC;CZGZJZ+CGJ.Z>Z:Z5Z5:>9:Z5Z>Z:5>:Z>Z5Z.5:>5.6>6:6565:>CZ0ZHZ.LZLHC8CZHZLZ0LHC$ZHZCZLZLHC;HZCZLZ$CHLCZ0ZLZHZLCH=CZLZHZHL0CLZ$ZHZCZLHC4$CZLZHZLHCLZCZ0ZHZLHC;HZCZLZLH0CLZCZ$ZHZLHC5$ C6H6L6 HCLCZ3ZKZFZCKF/FZKZCZ 3KCFFZCZKZ'ZKFC4F6C6K6 ' KCF9ZAZL7L@L 7@>*@L>L7L7>@@LJ@L@C@7L>L7@LC>J'>L@L7L@>77L>L@L7@><>L7L@L@7>7LJ@C@@LL@>L@7>LCJ)7-@->->@79LL@L7L7@>*@L7L>L7@>7LL@>L@LC@J@7@C>LJ,>L@L7L>7@@L7L>L7@>47L>L@L7>@7LJ@C@L@@L>L7@>CLJ#@L7L>L7>@@L>L7L7@>6@L7L>L7@>@LJ@C@L@>L7L7@>CLJ'@L7L>L7@>7L@L>L@7>5>L@L7L7@>@L7LL@C@J@>L@7>LCJ@L7L>L>@75L>L:L5>:*>L5L:L5>:J@F@A@:L5L>L5>A:JF,>L5L:L:5>7LL5L:L>:595L>L:L>:55LA@J@:L>LF@>:5AFJ'5L:L>L:>57LL5L:L5>:*>L5L:L5>:J@F@5L>LA@:L5>A:JF,>L5L:L:5>L5>:*5->-:-5>:@LL5L5>:*>L5L:L5>:5LF@A@J@>L:L5>A:JF,:->-5-:5>@L7L@767L@L@77L@L7@9@L7L7@@L7LL>:59:L5L>L>:5A@J@:L5LF@>L>:5AFJ'>L5L:L>:5L:L5>:*>L5L:L5>:5LJ@:L>LA@F@5>A:JF,>-:-5-:5>@L7L@76@L7L@77L@L7@97L@L7@:L?L7L?:79?L:L7L?:7K@7LF@C@:L?L?:7CFK'7-?-:-?:77LL:L5>:*:L>L5L5>:7L@LL5>:*>L:L5L5>:5LJ@:L>LA@F@5>A:JF,>-:-5-:5>@LL5>:*:-5->-5>:?L;L6L6?;*6-?-;-6?;7LLCL*CLL<C>H@L<CH>OJ,C-<->-><CL>;79;L7L>L>;7;LG@J@C@>L7L>;7CJG';-7->->;7>L5L:L5>:*:L>L5L5>:5LA@>LF@J@:L5>A:JF,5L:L>L:5>7L@LL:L5L5>:*5L:L>L5>:5LA@J@>L:LF@5>A:JF,>L5L:L:5>@LL>56>L5L>55L>L5>9>-5->5@LL:L>:59>L:L5L>:5L5L5>:*>L5L:L5>::LA@5LF@>LJ@5>A:JF,>-5-:-:5>L:L5L5>:*>L5L:L5>::L>LJ@5LF@A@5>A:JF,5-:->-:5>L5L5>:*5L:L>L5>::L>LF@A@5LJ@5>A:JF,:L>L5L:5>L>565L>L>5L:L5>:*>L:L5L5>:J@5LA@>LF@:L5>A:JF,>L:L5L:5>7L@L@767L@L@7@L7L7@9@L7L@7@L7LL5>:*5L>L:L5>::LF@A@>LJ@5L5>A:JF,:->-5-:5>7L@LL>:595L>L:L>:5:LA@>LJ@F@5L:>5AJF'>L5L:L>:5@LL5L:L5>:*>-:-5-5>:L:L5L5>:*5L>L:L5>:>LA@5L:LF@J@5>A:JF,>L5L:L:5>@LL5>:*>L5L:L5>:6L?L?66?-6-?6L*LCL<C>>LJ@O@H@CLOJ,LCL><C9LL:L5L5>:*5L:L>L5>::LF@J@>LA@5L5>A:JF,:->-5-:5>@LL5L>:59>L5L:L>:5A@>LJ@F@5L:L:>5AJF'5L>L:L:>5@LL:L5L5>:*>L:L5L5>:>L5L:LA@J@F@5>A:JF,>-5-:-:5>L5L>:595L>L:L>:5@L7L@767L@L@7@L7L7@9@L7L7@5L>L:L5>:*>L5L:L5>:J@F@:L5L>LA@5>A:JF,5L:L>L:5>7L@LL5>:*:L>L5L5>:J@>L5LF@A@:L5>A:JF,5->-:-:5>L:L5L>:595L>L:L>:5:LF@>L5LA@J@>:5AJF':->-5->:5L:L>:59>-:-5->:57L@LL>:59:L5L>L>:5J@:L5LF@>LA@:>5AJF'5L:L>L:>57L@LL5>:*>L5L:L5>:5L:LF@>LJ@A@5>A:JF,:L5L>L:5>@L7LL:L5>:*5L:L>L5>::L5LJ@F@A@>L5>A:JF,5L:L>L:5>@LL:L5L5>:*>L5L:L5>:7L@L@767L@L@7@L7L7@9@L7L@7L:L5L5>:*:L5L>L5>:>L5L:LJ@A@F@5>A:JF,>L:L5L:5>@LL:L5L5>:*5->-:-5>:?L;L6L6?;*6L;L?L6?;7L@L@76@L7L@7@L7L7@9@L7L@7L*LCL<C>H@J@O@LCL<CH>OJ,CLL><CL;L>;79>L;L7L>;77LJ@;LC@>LG@;>7CGJ';L>L7L>;7:L>L5L5>:*>L:L5L5>:5L:LJ@>LA@F@5>A:JF,:L>L5L:5>7L@LL>565L>L>5>L5L5>95->-5>L>565L>L>5>L5L5>95->-5>@LL>56>L5L>57Ln7nOZ/>7>n7nOOZ4n]4!4nX4An5nOHn>n7>8A+n5HhE<A++n>n@ZB@+CnJZ0n>iJ 0JZ$n@njJ @+n@Z>n$Cƒ@+C>)n>nFZ@F>2nAnJZ)hJA2ABJ6.B(.A@nn5Z.nh2>5Z):nB>)An.nFZ:iF ."nFZ>n(>"FCnnEA>F.B>B.J6>'.0n@nCZJHZEC@H0n@n0LZ@J0L@BL6H6(HL2ZAn:n@>n5Z.nh2>+n@n.A5HZ:@H@4nCnLZ+hLC4LZ0nCn(0L@n0nTZC7nU7@T7nXZ@nT@7X7n@nTZ&7@@nT7nOZFO@730FZ?n"n@F?3nCnKZ"hKC3Cn'nKZ('CAnHZK$n@HAMZ5nEn$hME5MZ)nEn(EM)n:n>n)AZ9A ) :>.nFZAn>nf> .AFA6"B>B(">+nHZA@n@H@4nCnLZ+hLC40nCnLZ(LC?nFZ0"n@F?KZ3nCn"hKC3K6'BCB(K'$nAnEZCn:nAnE2Z5Z.nh2:.HZ@n>5A+n@H@Cn4nLZ+hLC4LZCn0n(L0FZ?nC"n@F?3nKZCn"hKC3K6+BCB(K+0nCZHZC@nEC@HLZ@n00n@J0LHZ@nLZ(@LDZ'nH?nBD'HBK6,B?%H,>n2Z:nKAn5Z.nq52AHZ+n:.>@n@H@Cn4nLZ+hLC4LZCn0n(C0n@F>AnJZ2n)hJA2J62BAB(2JZ?)nB>)AnFZ.n:%A.3Z;n?nBnF6Z/nq/36;?nCnH&n,D9H & >CCnJZ+nHnfC +HJHZCn+n(+HBnn(A>+>Z)nC:nB>).nFZAn:iF ."nFZ>n(A">+nHZF@n@H@CnLZ4n+hLC4L6CB0B(0CTZ0n7nL@nU7@T7n@nXZT@7XTZ7n@n&7@@nT7nOZFO@730"n?nCZ:n9C " :?FZ?n'nCnf? 'CF'n?nCZ('CnEA>F.nJZ.>n>J.J>BF6J6(>J+n@ZFnAn:n2Z<5Z.nh2A:5@nCn4Z7Z0nh4@0"n?n<C7FZ@F?3nCnKZ"hKC3Cn+nKZ(C+CZ@nZ:n8HPB>)F6.BAB:%AF@nHZCZ.0nEC@H@nLZ00n@J0L@nHZLZ(@L>n)nHFZ@F>JZ2nAn)hJA2AnJZ.n(J.4Z0nH4@n@Cnm@ 0C 'nCZ?nFZEC?F'nKZ'?n?J'K?nFZKZ(?Fn9A ) :>FZ.nAn>nf> .AFAZ>n"n("A+n@n9C + <@@nCn0nHZf@ 0CHC6$B@B(@$3Z?nCn:nC7Z'nh3?C':AnZB>)FZAn.n:iF ."B>BF6(AF"HZ+n>@n@H@CnLZ4n+hLC4CB0BL6(C0?Z:nL"nB?"FZCn'n:iF '?BF6'B(C?F4ZCnnFZ,)n@F>ABJ62B)!J2CZHZ@nA0nEC@H@nLZ00n@J0LLZ@nHZ(H@:n>n)nLAZ9A ) :>>nFZ.nAnf> .AF"n>nAZ(A>@nZ):nB>)An.nFZ:iF .>B"BF6(F"AHZ0n@n>CZEC@HLZ0n0@n@J0L@nHZLZ(@L"n:nCZH?n9C " :?Cn?n'nFZf? 'CF'n?nCZ(?'$nEZAnCnAZ)n):n9A ) :>.n>nFZAnf> .AF"n>nAZ(A>@n4Zn:nAZ?)n9A ) :>>B.BABF6(F>A+n@Z.nEA>FJZ>n22n>J2JJ6F6>B(JF@Z+n>n9A ) :>.BAB>BF6(AF.*n?n>GZ@G?K63BBB*!KBCZ@nnHAZBA&Cn+nGZ;>fG +>BG6AB+B(AG>+>nAZFZC.nEA>F>n.n.JZ>J.J>nJZFZ(FJ@n4Z7Z0nh4@<7CHn4n@n0>0nH4Cn@@nm@ 0C ?n"nFZ@F?3nCnKZ"hKC3CB'BK6(K'HZ)nEZCAnEEAHAnMZ))nAJ)MMZHZAn(AHFZAZ>nM.nEA>F.n>n.JZ>J.J>BF6J6(F>+n@nn:n2ZAnE5Z.nh2.A:0n@nCZ>5HZEC@H@n0n0LZ@J0L@nLZHZ(L@3Z?n:nHCn7Z+nh3+7@Z+n:?Cn9A ) :>.BAB>BF6(F.>@Z+nAnAn:n$5Z.nh25.>ACnnE5Z.nh2A:5>0nCZ@n.HZEC@HLZ@n00n@J0LHZ@nLZ(LHFZ"n@?n@F?CnKZ3n"hKC3KZ'nCn(C'Enn:n2ZE5Z.nh2.A>ZH?D:nB>).BABF6:%A.HZ0nCZF@nEC@H0n@n0LZ@J0L@nLZHZ(@H>nFZ.nLAZEA>F.nJZ.>n>J.JJZ>nFZ(J>+n@ZF0nH4Cn@@nm@ 0C ?n:n3ZCn7Z'nh3C?:7HZEZ)n'AnEEAH)nAn)MZAJ)MM6ABH6(MA:n>ZH)nB>).nFZAn:iF .F6>B"B(>AFCZ0n@n"HZEC@H0nLZ0@n@J0L@BH6L6(@H"n?ZL:nB?"Cn'nFZ:iF '?nFZ'n(?'FEZ$nnAZ))n9A ) :>FZ>nAn.nf> .AFAZ>n"n(A>+nZ<8?:nB>)AB.BF6:%.F@n+nAHZ@H@Cn4nLZ+hLC4L6CB0B(LC$nEZ0?n@E?KZ3nAn$hKA3HZAn)n(H)nA9'FZ@F>AnJZ2n)hJA2An2nJZ(J2n5Z.nq>2:GZ*nA5.?n@G?KZ3nBn*!B3@n4ZnCZD&nBC&+nHnJZ>iJ +J6+BCB(CJ+nAn+nCZ?GZECAGMZ+nJZ+An>J+AJ M>BG6ABJ6(J>AFZ)nG>n@F>2nJZAn)hJA2.BABJ6(.J@n0nCZAHZEC@HLZ@n00n@J0LHZLZ@n(HL4n@n@Hn8@40nH@nCnnEA>FJZ.n.>n>J.J>nFZJZ(F>CZHZ@nJ0nEC@H0nLZ0@n@J0LHZ@nLZ(L@"n?nCZH:n9C " :?CnFZ'n?nf? 'CFC6?B'B('?EZAn$nCn9A ) :>>n.nAnFZf> .AF"BA6>B("AHZ@n>+n@H@LZ4nCn+hLC4L6CB0B(L03Z:nCn?nC7Z+nh3:7C?@n4Zn@F>2BJ6AB)!2JHZ@nA+n@H@LZCn4n+hLC4LZ0nCn(C07nSZ0nLXA[0XT3OT3R=AR"R=MTCRYSTDT1YTyYbTc7TYƒMWIRTT>Rd´@9”RFW ´@”TTWOa RQPOZTThQ2TUm2TPUK[´@!”TK!´@”J:R2$JRT\EQA0O4 Q6OTZMFJ=4MJFHJM.M M-H6F´@ ”HJIAS ´@”AJMHW´@”@>:´@.@(”@H>gAcI><A <>UAZJA#<@?f@` ?ZC_@G@`C?O @;>A<B@9>%@>2q>AJ:HBA A-<6:!>J<4> A:F2$>FH\EEA0C4 E6CH#E>HHD/JQHFH,JJE H,JMV4QNM4QT@2TYTTYE VBTTD%T V6[7V W? YX=WV[X V&[6WEX3V W1´@@:”X["T3&TWdST* WTQ6>TbQ!TgTGQA9Oi QCKO#OPKT7OR_AR RQOa1SWORIS OhJ`FQ6LCOJ#LQJ*O0.JOLKH?(LH C7HUEF C#HE+HZCZ´@@"”CHEGO H7 G6KLH&´@@”KLWO[0LOQAMOAQM9L7XLNXRL* NN>LBNQQ/SJQBSN!.NMc[MM[JYIHI J"Gc HM%GOGE\+AT E!A@VG/AQ>S@ ´@@J”A>ƒ<>.<:6>@\,A[ @9CVA/?CC@?@f2?_@C? :@(:<1<?O!>7?IA=>.C_HYA D:DE3 C HE AJ:HBA A-<6:!>J<4> AAO H7F8HKMSHD5MHyMbHc/JbHM1RZJ5J>R4J$´@ ”KXCPLPKC LBAUJJ´@ ”JA´@”@EHP.@FD H T@R[T´@”RTXOVQCO&TQXgLTDH)>k+> <]‚R<7M 7#:q7:M=P> H)>k+> <]‚R<7M 7#:q7:M=P> `?Q>$?>Y+5<:N:X<>\>>n:><]<Z<Dc<9V 9;iV9`;Z97Y(7:U):&H)>k+> <]‚R<7M 7#:q7:M=P> H)>k+> <]‚R<7M 7#:q7:M=P> H)>k+> <]‚R<7M 7#:q7:M=P> `?Q>$?>Y+5<:N:X<>\>>n:><]<Z<Dc<9V 9;iV9`;Z97Y(7:U):&H)>k+> <]‚R<7M 7#:q7:M=P> R)>u+> W=P> <](<%R)>u+> W=P> <](<%j?[>$?>c+5<:X:b<>f>>x:>d<Dc<9` 9;sV9j;Z97c(7:_):&<}<{<*<$R)>u+> W=P> <](<%R)>u+> W=P> <](<%R)>u+> W=P> <](<%j?[>$?>c+5<:X:b<>f>>x:>d<Dc<9` 9;sV9j;Z97c(7:_):&<}<{<*<$R)>u+> W=P> <](<%/( (P(%N.%(0"(+Y2++U(#F +!#%#Y$#&B6&&W(#D&.#&L&&N7&&U(&F&)&&;)#F&0##D(!?#*!!J"!&RH&!H! &PK& !bU!!F"!!\7!!3!&J3&&P,*U&1**L(-R*!-$-R-*U-*#-R%-&Y/&!&R.&*[8**U'*-L2--P(-*Y8*-R -&N7&&U(&F&)&&;)#F&0##D(!?#*!!,"!&[2&&N!&*G3**;(-J*--E -*N?*&P&Y2U F+%Y$B6W(#D.#&L&+H9++N+R+/P(#] *##R(&Y#3&&["&&Y2&&U(&F &!&%&Y$&#B6##W(!D#.!!L!&H9&&N+&*R/**P(+] **++R(+-Y3--["-!Y0! !R(%R !,%%Y% (>/( (P(%N.%(P"(+Y2++U(#F +!#%#Y$#&B6&&W(#D&.#&L&&J3&&P,&*U1**L(-R*!-$-R-*U-*#-R"-&RH&!H! &PK& !bU!!F"!!\7!!U!&Y2&&U& &F+&%&Y$&&B6&&W(*D&.*-L-2H922N+&R2/&&P(*] &***R(-Y*3--["-&J3&&P,*U&1**L(-R*!-$-R-*U-*#-1"-&R1&&F((U&(!(R#()P7))B+*U):**4"*+Y2++U+ +F++%+Y$++B6++W(/D+./2L27H977N++R7/++P(/] +*//R(2Y/322["2&Y2&&U(&F &!&%&Y$&#B6##W(!D#.!!L!&H9&&N+*R&/**P(+] **++R(-Y+3--["-!Y0! !R(%R !,%%Y% (>/( (P(%N.%(P"(+Y2++U(#F +!#%#Y$#&B6&&W(#D&.#&-&&J3&&P,*U&1**L(-R*!-$-R-*U-*#-1"-&b4&&F"&&\7&&3&&i0& &1!&'i0' '1!'(c2((_( /P+/%/c$/,L6,,a(#N,.##V#4R944X+(\4/((Z(,g (*,,\(/c,3//<"/(c2((_( P (! % c$ #L6##a( N#. #V#(R9((X+ \(/  Z(#g *##\(c#3e"!b7!!i(!Z!)!!O)Z!0X(S*8"!h4!!]"!%J7%(6($h4$$]"$(J7(+[+(c2((_((P (!(%(c$(%L6%%a(#N%.##V#(R9((X+,\(/,,Z(-g ,*--\(/c-3//<"/#c0# #\('\ #,''c' *H/* *Z*'X.'*Z"*!c0! !\(%\ !,%%c% (H/( (Z(%X.%(6"(+e2++a(#R +!#%#e$#&N6&&c(#P&.#&4&u\p#U$p#$U&S3&&Y,&*^1**U(-[*!-$-[-*^-*#-[%-&b/&!&[.*d&8**^'*-U2--Y(*b-8*-6 -&b7&&i(&Z&)&&O)&#Z0##X(!S#*!!8"!&j2&&]!&*V3**J(-Y*--T -*]?*&_&+^5++g(+O+&+&+\$+(R*(&(X(&\(,&&K'&+r,+$+R(#^ +-##g# $^8$$V(&g$3& +X+&c2&&_(&P &!&%&c$&#L6##a(!N#.!!V!&R9&&X+*\&/**Z(+g **++\(-c+3--<"-!c0! !\(%\ !,%%c% (H/( (Z(%X.%(Z"(+e2++a(#R +!#%#e$#&N6&&c(#P&.#&X&&T3&&Z,*_&1**V(-\*!-$-\-*_-*#-\"-&h4&&]"&*J7*!fU!!J!!`7!!5!&S3&&Y,*^&1**U(-[*!-$-[-*^-*#-[%-&b/&!&[.&*d8**^'*-U2--Y(*b-8*-[ -&T3&&Z,&*_1**V(-\*!-$-\-*_-*#-\"-&]1&&Q((`&(!(]#()[7))M+*`):**:"*+c2++_(+P +!+%+c$+(L6((a(&N(.&&V&+R9++X++/\///Z(0g /*00\(2c0322<"2&^5&&g(&O&&&&&\$&#R*#&#X(!\#,!!K'!&r,&$&R(^ &-g ^8V(!g3! &4&!c0! !\(%\ !,%%c% (H/( (Z(%X.%(Z"(+e2++a(#R +!#%#e$#&N6&&c(#P&.#&X&&T3&&Z,&*_1**V(-\*!-$-\-*_-*#-\"-&RH&!H! &Pi&&k0& &H!&'k0' 'H!'(c2((_( (P+(%(c$((L6((a(,N(.,/V/4R944X+4(\/((Z(,g (*,,\(,/c3//e"/c2_ P+%c$L6a( N. #V#(R9((X+(\/Z( g *  \( #c3##<"#!b7!!i(!Z!)!!O)Z!0X(S*^"!f4!!J!!`7!!5!$h4$$]"$(J7(+[+(c2((_((P (!(%(c$(%L6%%a(#N%.##V#(R9((X+(,\/,,Z(-g ,*--\(-/c3//<"/#c0# #\('\ #,''c' *H/* *Z*'X.'*6"*!c0! !\(%\ !,%%c% (H/( (Z(%X.%(6"(+e2++a(#R +!#%#e$#&N6&&c(#P&.#&X&u\p#U$p#$U&Y2&&U& -F+-%-Y$-*B6**W(!D*.!!L!2H922N+&R2/&&P(*] &***R(-Y*3--6"-&J3&&P,*U&1**L(-R*!-$-R-*U-*#-R"-&R1&&F((U&(!(R#()P7))B+*U):**4"*+Y2++U(+F +!+%+Y$+(B6((W(&D(.&&L&+H9++N+/R+///P(0] /*00R(2Y03226"2&Y2&&U(&F &!&%&Y$&#B6##W(!D#.!!L!&H9&&N+*R&/**P(+] **++R(-Y+3--6"-!Y0! !R(%R !,%%Y% (>/( (P(%N.%(P"(+Y2++U(#F +!#%#Y$#&B6&&W(#D&.#&-&&N7&&U(&F&)&&;)#F&0##D(!?#*!!J"!&b4&&F"&&\#&2!bU!!W"!%D7%(U(&J3&&P,*U&1**L(-R*!-$-R-*U-*#-R%-&Y/&!&R.*[&8**U'*-L2--P(*Y-8*-1 -&J3&&P,*U&1**L(-R*!-$-R-*U-*#-R"-&R1&&F((U&(!(R#()P7))B+*U):**4"*+Y2++U+ +F++%+Y$++B6++W(/D+./2L27H977N++R7/++P(/] +*//R(2Y/322["2&W/&!&D& *Y)*'*5* +L$+,+D#+-W'-)-U(-&W/&!&W& &W1&&R"&#W-###P("i#6""=!"!Y0! !R(%R !,%%Y% (>/( (P(%N.%(P"(+Y2++U(#F +!#%#Y$#&B6&&W(#D&.#&L&&J3&&P,*U&1**L(-R*!-$-R-*U-*#-R"-&b4&&W"&*D7*-U-&i0& &F!&'i0' '1!'(S3((Y,,^(1,,U(/[,!/$/[/,^-,#/[%/(b/(!([.,d(8,,^',/U2//Y(,b/8,/[ /c2_ P+%c$L6a( N. #V#(R9((X+\(/Z( g *  \(#c 3##e"#!T3!!Z,%_!1%%V((\%!($(\(%_-%#(7"(!f4!!J!!`7!!5!$f4$$J$$`7$$Y$c2_ P+%c$L6a( N. #V#(R9((X+\(/Z( g *  \(#c 3##<"##c0# #\('\ #,''c' *H/* *Z*'X.'*6"*!c0! !\(%\ !,%%c% (H/( (Z(%X.%(6"(+e2++a(#R +!#%#e$#&N6&&c(#P&.#&4&u\p#U$p#$X&d(&-&b"& $f!$"$]$#L,#"#Y#"k"0"P" !bB! #[#%[I%&dE&a&ne&ÿ/MTrk$-¹ÉÿJAZ2ÿDrums¹s][{ rp™*d#F#*7*F&*&*s&Z&*7&&#F*d*#*2*&&*s&Z*&7&(&*d#F#*7&&*s&Z*&7&&*d#F*#7&&*s&Z*&7*d&(#<*&#*d#F#*7&&*s&Z*&7&&#F*d#*7&#<#&&Z*s&*7#<&(#&#F&Z*Z&#*7&F&*Z#F#*&<&*n&P&*0Z*P&F#F#*0&7-P-*Z#d#*)F))d)*d#F#*7&&*s&Z*&7&&*d#F*#7&&*s&Z&*7&(#<*d&#*#F*d*#7&&*s&Z*&7&&*d#F#*7&&*s&Z&*7*d#<&(*&##F*d*#7&&*s&Z&*7&&*d#F#*7&#<#&&Z*s&**Z*&(&*d#F#*7&&&Z*s*&7&&#F*d*#7&&&Z*s*&7&(#<&#*d#F*#7&&*s&Z*&7&&#F*d#*7&&*s&Z*&7&(*d&**d#F#*7&&&Z*s&*7&&*d#F#*7&&&Z*s&*7&(&*d#F*#7&&&Z*s*&7&&*d#F*#7&&*s&Z*&7.H.#F*d#*7&&*s&Z&*&F&*d*#F#*s*7.H&Z.&7.P.#F*d#*7&&*s&Z*&7&&#F*d*#7&&*s&Z*&7&(*d&*#F*d#*7&&*s&Z*&7&&#F*d#*7&#<&#&Z*s&**Z**d&(*&#F*d*#7&&*s&Z*&7&&#F*d*#7&&&Z*s&*7#<.H.#&P#Z*P*&#7&<&*Z&d&*7)F*n*)&Z*P&*7*<0P0*&Z*Z&*-Z-*<)Z)**d#F1Z*#17&&*s&Z&*7&&*d#F#*7&#<#&&Z*s&*7&(#<&##F*d*#7&&*s&Z&*7&&*d#F*#7&&*s&Z*&7&(&*d#F*#7&&*s&Z&*7&&*d#F#*7&6&&Z*s*&7.H.*d#F*#7&&&Z*s*&7&&*d#F*#7&&*s&Z*&7&(&#F*d#**<*&&*s&Z*&7&&#F*d*#7&#<&#*s&Z*&7.H#<#.#F*d*#7&&&Z*s*&7&&*d#F*#7&6&&Z*s*&7&(&#F*d#**<*&&&Z*s&*7&&#F*d*#7&#<#&*s&Z&*7&(#<#&*d#F#*7&&*s&Z&*7&&*d#F*#7&#<&#&Z*s&*7&(&*d#F*#7&&*s&Z&*7&&*d#F#*7&&*s&Z&*7&(&*d#F#*7&&*s&Z&*7&&#F*d*#7&&*s&Z*&7*d&(&**d#F*#7&&&Z*s&*7&&*d#F#*7&#<&#*s&Z&*7&(&#P&(*Z#&*&2&&d&*Z&d*&&(&&d&&2#P*Z&#*&s&&F&*Z&Z&*&d&&&1Z3Z#P#137&&&d3s3&7&(&3Z#P3#7&&3s&d3&7#<&(&##P3Z3#7&&3s&d3&73d&(&3#P#3d3&&3Z&d&37&(#<#&#P3Z#37&&&d3s3&7&(&#P#3d3#<&#&&d3Z3&7&(&3Z#P#37&&3s&d3&7&(&3Z#P3#7&&&d3s3&7#<&(&#3Z#P3#7&&&d3s3&7&(&#P#3d3&#<#&&d3Z&37#<3l3#3Z#P3#7&&&d3s3&7&(3d3&#P#3d3&&3Z&d&37#<&(&##P3Z3#7&&3s&d&37&(&3Z#P3#7#F&&#3s&d&37&(#<#&3Z#P3#7&&3s&d3&7&(&3Z#P#37#F&&#&d3s&37&(&#P3Z3#7&&&d3s&37&(&#P3Z3#7&&&d3s3&73l3#P3Z3#7&&&d3s&37&(&#P3Z#37&#F#&3s&d&37#<3l3##P3Z#37&&&d3s3&7&(&3Z#P3#7&&&d3s3&7&(#<&#*F#Z&s*&#&(&&(&&d*F&*&(&&d&*F#Z*#_*F*_#P1U1#7&&&d3s3&7&(&#P3Z#37&&3s&d3&7#<&(&#3Z#P3#7&&&d3s3&7&(&#P#3d3&&3Z&d&37&(#<#&#P3Z3#7&&3s&d&37&(3d&3#P#3d3&&3Z&d3&7&(&3Z#P#37&&3s&d3&7&(&#P#3d3&&&d3Z&37#<&(&#3Z#P3#7&&&d3s&37&(&#P3Z#37#F&&#&d3s3&7#<&(&#3Z#P3#7&&&d3s&37&(&#P#3d3&&3Z&d3&7&(&3Z#P3#7&&3s&d3&7&(&3Z#P3#7&&3s&d&37&(&3Z#P3#7&&&d3s&37&(3d&3#P#3d3&&3Z&d&37#<3l#3#P3Z#37&&&d3s&37&(&#P3Z#37&&3s&d3&7&(&#P3Z#37&&3s&d&37&(&3Z#P3#7&&&d3s&37&(&#P3Z#37&&&d3s&37&(&#P#3d3&&3Z&d&373l3#P*Z&(&#*&2&&d&&d*Z&*&(&&d*n&**Z&2#P*#&&s&&F&&Z*Z&*&d&&&1Z3Z#P#137&&3s&d3&7&(&3Z#P3#7&&3s&d3&7&(&#P3Z#37&&&d3s3&73d&(&3#P#3d3&&&d3Z3&7&(&#P3Z#37&&&d3s&37&(&#P#3d3&&3Z&d&37&(#<&#3Z#P3#7&&&d3s&37&(&3Z#P3#7&&3s&d&37&(#<&#3Z#P3#7&&&d3s3&7&(3d&3#P#3d3&&&d3Z&37&(&3Z#P#37&&3s&d3&7&(&#P3Z#37#F&&#&d3s3&7#<&(&#3Z#P3#7&&3s&d3&7&(&#P3Z3#7#F&&#3s&d3&7&(&3Z#P3#7&&3s&d3&7&(&#P#3d3#<&&#&d3Z3&7#<&(&#3Z#P3#7&&3s&d3&7&(&#P#3d3&&3Z&d3&7&(&#P3Z#37&&3s&d3&7&(&#P#3d3&&&d3Z3&7#<&(&#3Z#P3#7&&3s&d&373d&(&3#P#3d3&#<&#3Z&d&37&(#<&#&Z*Z#F*&#_#F*Z#*&2&&<&&F#F*Z&#*&P&&Z&&Z*Z#F&*#&d&&s&#P3Z1Z#317&&3s&d&37&(&3Z#P3#7&&&d3s3&73l#<#3#P3Z#37&&3s&d&37&(3d3&#P#3d3&&3Z&d&37&(#<#&3Z#P3#7&&3s&d3&7&(&3Z#P3#7&&&d3s3&73l#<#3#P3Z#37&&&d3s&37&(&3Z#P#37#F&#&3s&d&373l#<3#3Z#P#37&&3s&d3&7&(&#P3Z3#7&#F#&3s&d&373l#<3#3Z#P#37&&&d3s&37&(&#P3Z3#7&#F#&3s&d&37#<&(#&#P3Z#37&&3s&d3&7&(&#P3Z#37&&&d3s3&7#<&(#&3Z#P3#7&&3s&d&37&(&#P#3d3&&3Z&d3&73l33Z#P3#7&&3s&d3&7&(&3Z#P3#7&&&d3s&37&(&3Z#P3#7&&3s&d3&7&(&3Z#P#37&&3s&d3&7&(&3Z#P3#7&&3s&d3&7&(&#P3Z3#7&#F&#3s&d&37#<&(#&#F*Z&Z*&#7&F&*Z#F*#&<&&P&*P0Z#F0#*_*Z#d*#_1Z#F*d*1#7&&*s&Z*&7&&*d#F#*7&&*s&Z*&7&(&*d#F#*7&&&Z*s&*7&&*d#F*#7#<&&#&Z*s&*7.H.*d#F*#7&&*s&Z*&7&&#F*d#*7&&*s&Z*&7#<&(&##F*d#*7&&*s&Z&*7&&#F*d*#*2*&6&&Z*s*&7&(&#F*d#*7&&&Z*s*&7&&#F*d#*7&&*s&Z&*7*d#<.H*#.*d#F*#7&&*s&Z&*7&&*d#F*#7&&*s&Z&*7&(#<#&#F*d*#7&&&Z*s&*7&&#F*d#*7#<&6&#*s&Z&*7&(#<#&#F*d*#7&&*s&Z*&7&&*d#F*#7&#<&#*s&Z&*7#<&(&##F*d#**<*&&*s&Z*&7&&#F*d#*7&#<&#*s&Z&*7&(*d*&#F*d*#7&&*s&Z*&7&&#F*d#**2*&6&*s&Z&*7&(#<&#*d#F#*7&&&Z*s&*7&&*d#F#*7#<&&#&Z*s&**Z*&(&*Z&Z#Z*#&_*Z#<&<*#&&P&*n&d&*#Z*Z#*7&<&*Z&d#<#&*&(&#P&2#&#F*d1Z*#1*<*&&*s&Z&*7&&#F*d#**2*&&*s&Z&*7&(&#F*d*#7&*F&*&Z*s&*7&&#F*d*#7&6#<&#*s&Z*&7&(&*d#F*#7&&&Z*s*&7&&#F*d*#7#<&#&&Z*s&**Z*#<&(&#*d#F#*7&&*s&Z*&7&&*d#F#*7&&&Z*s&*7*d&(#<#*&*d#F#*7*F&&**s&Z&*7&&*d#F#*7#<&6&#*s&Z&*7&(#<#&#F*d#*7&&*s&Z*&7&&*d#F#**2*&6&&Z*s*&7&(&*d#F*#7&&*s&Z&*7&&*d#F*#7&&*s&Z*&7&(&*d#F*#7&&*s&Z&*&F&*d*#F#*s*7.H&Z&.7.P.*d#F*#7&&&Z*s*&7&&*d#F#*7&#<#&*s&Z*&*Z*&(&#F*d#*7&&*s&Z&*7&&#F*d*#7&#<#&*s&Z&*7&(#<#&#F*d*#7*F&*&&Z*s&*7&&*d#F#*7&#<&#&Z*s*&7#<&(#&&P#Z*P&*#7&<&&d*Z*&7*<)F)**P&Z*&7*<0P0*&Z*Z&*-Z-*<)Z*)1Z3Z#P13#7&&&d3s3&7&(&3Z#P3#7&&3s&d&373l#<#33Z#P3#7&&&d3s3&7&(&#P3Z#37&&3s&d&373l3#P3Z#37&&&d3s3&73d&(3&#P#3d3&#<&#3Z&d&37#<3l3#3Z#P#37&&3s&d3&7&(&#P#3d3&&&d3Z&37&(&#P3Z3#7&&&d3s&37&(&3Z#P3#7&#F#&&d3s&37&(#<&#3Z#P3#7&&&d3s&373d&(3&#P#3d3&&3Z&d&373l33Z#P3#7&&&d3s&37&(3d3&#P#3d3&&&d3Z&37&(&3Z#P#37&&&d3s&37&(&#P#3d3&&3Z&d3&73l33Z#P3#7&&3s&d3&7&(&#P3Z3#7&&&d3s&373l3#P3Z3#7&&3s&d3&7&(3d3&#P#3d3&&&d3Z&37&(#<&#3Z#P3#7&&3s&d&37&(&#P#3d3&&&d3Z&37&(&*P#Z&P*#&7&<&*Z&d*&7*<)F*)*P*_*Z*_*Z#d#*7&d&*Z*7&<&&s*Z*&7#Z#*Z&s*&7&<&&s&7&d&#d#7&s&#s1Z1#ÿ/MTrkv²ÂÿJAZ2²]{ ÿOrgan²i@[p’I9E;B.L7‚PBEENBALEBIL)LAG7ƒDGLhQ>J0NA`NJE>QNCQ<J.E1JNQE*ENBJ7CJN IBC7‚ CIJ+NB…(E1EQOEQJJBJ NNAJ7ƒDJNQ;H+J=N5H JNQ>1 >JHSJOD@SJO>@>Q+NFHJANHQ GHC1JA‚OCJG >$>C/LDB;G7H)BG0CLH&J9GDC->CGJ2LFHNCFELCH>+ >G7C=J;HJCG>3 >HSLQCU>HCLQ3N=J&†;QB7JN BNDJHQQCQJN5ICE8p@>LCEIKLE+@I# ELGI@PKL@uS=J9OI‚]O JS'Q;J=N5JNQ>1 >ODJHSJ@SJO>@>JJQ+NFANJQQDJ0NDsQNJ C=sE.sEC NIJ6Q4ƒBNQJN:QIJBN JQHB8#BN4J.Q0ANJQB8BJ6Q@N>KNJQ,NAJ7ƒ-NJ NEQ8J+H*/HJNQ;H8QPNAJ:JQNHSS8OEJ*/JOS;SPOAJ8OSJvJ.O4SA OJSJ>SUO>SOJrJ&Q3N=†QB7JNBQQJHNDCJNQ5E=I5L;EIL91 9NJJDEH@NEJ9@9IFL+EJAEILOAS>J0`OJSG>S<J.GOC1JOSQ8NEJ*/NJQ;J8QPNANQJvJ=PN.NJJ7NB[JNF7KBKKF GCLK…NGL%GALUPGXGLPP<GAL4KLPGPBLOG4/LGP;PZLKGBLPGvG8L>PK LGPLHP_GHPLGsL=IIE89ILE='=LKIRE;;I EL=I=LNITEKGIELwE:LNINLIEiLNH:ONLOHLTGKPK‚?GD3LPDPIG?LK1GLPPQLTG?LG PMD8 DPOLQGC;PGLD3 DGMLGPQ=GLPG?KN‚(GGCN9NKG ?1?GRNNK]0C'MC>A&A>C4>4A>CL:H@LHA<C>>8(FYJMFGRlG >AJCMQHF\MHHAML#HMUHALL#HL2NTQKJK‚`JE3NQEJ?QINK1JNQQQNTJ?NJ QME8 ENQQOJC;QJNE3 EJMNGQQ=JNQ7J2NGQ;‚ J E[*E&E^9E NQ2Q;JGH2N9‚ H E[*E&E^9E JNQSHJ:OK`OJGHSSFJ8GOM1OJSG4GSMO3(J/JSO SQOXJZOJSsJMNMƒJNJMQHJ QPE<ESKOFJHLSJE5O ESQJKOM>OJSINE?‚(EL9ECLIE =1=ERLNI]0C'A-,>CA$>4C4A>A>CH@L:LHA<>8C>(JMFYFGRlG C>JAH-E0J',EJH$E4J4H>EHJO@S:SOJ>H<E8(QMMYMNRNJHENQ JGsN8sJN CAILfCI QBNOJ4/NJQ;JBQZNKNQJvJ8N>QK NJQQ_NHJHQNJrJ2Q;NG‚ J E[*E&E^9E QN2H4QBJ5NOJHQN9QZNKJDHBJQNHSJ4OOSB/JOS;JBOKSZOSJvJ8O>SK OJSOHJHS_SOJrNKJC…-NJ#JANUQGXJNQQ<N4JAKNQJyLHIKE:`IE@HLLFIM@E81IEL@$@C'>0A-,C>A$C4>4A>>ACL:H@LHA<C>>8(JMFYFGRNGC>JA J?NN‚(JJCQ9QNJ B1BQNJRN]E4@CEN:J@NJE>@8C<(HYLMHIRlI LCE@EGPI8sEI HALLfLH LOPBG4/LGP;LKGBPZLPGvL>G8PK LGPP_LHGHPLGrG2N;KG‚ G B[*B&B^9B KNL=IIE8ZILE='=LKIRE;;I EL=I=LNITEKGIELzOKJ:SH`OJSGHOMGSFJ81OJSG$GMQHF\HMMLHA#HMULLHA#HLUQ4J6NIƒ!NQJQIN:JBN JQHB8#BN4J.Q0ANJQB8BN>J6Q@KNJQ'N3Q1J/‚6JQ>=N>JFQHNJFQJN1NEQ8H*J+JHQN9H8NAJ:QPJQNHvGHC1JA‚.CJG >$>G7C/H)B;LDBG0CLH&GDC-J9>CGJ2HNCFLFELCH>+ >C=G7J;HJCG>3 >HSCULQ>HCLQ6N8J1…2NQJB1$BQHJ8NBJQNJB0(JFN<BQHGNQJ6IAE7ƒDEIhS>J0OA`OJG>SJ.S<GOC1JOSGGQ7J.N9‚PJNNNJALNJQJ=sN.sJN}C0E9LDIDELCI#QRN]JXM? M(O3M!G=QJE OOGEMNOM? G/ E6MC6GEB2CB„NRJEJ NNRJP=N>JFNJQHFQJN1Q1H/N3J3‚6JQ>=H N>JFQHHANJFQHJN1J8OA„UOJ+OGJ09JOOAJ2AJO OPJPAJ2O NEQ8J* J&NQ;J8QPNANQJvN4J.QA NJQJ>QUN>QNJO@0C-E'M@CE&C>@4E4C@EN:J@NJE>@8C<(HYLMHIRlI @CELO9S7J.‚PJOJAONLOJSJ*Q8NE/JNQ;J8QPNANQJSJ=sN.NJ NBJ7[JNF7KBKFK GKD9LV!DƒbD,-GDGR,GD-LDLEGM(D< GLGRLODGGLGRLIBG LGTL8@G7LNGL@)@LVGR;GL=@0E'C-,@EC$E4C>@4C@EN:J@NJE>@8C<(LMHYHIRNELI@C EGsI8IE HGPL8LHXPAG<LA0LPGLRPEG=/GLPPKLRG:4PGLLOPRGC+LGPLEPAG=(D1 PGLDPMLTG?5LPGLTGEPO+LGPLCG9PC/PGD6LD LEP?GA5LGPG?PKLK1GLPDG2KGN;G‚5B[*B&B^9B KN5L=IIE89ILE='=LKIRE;;I EL=I=LNITEKGIELS=OIJ8ZOSJC'CSKORJ;;O JSCICSNOTJKGOJS'MQHF\HMMLHA#MHUHALL#HL,HKVRNVNQ4NAQVJKNHJG?V?MCM P=M=JP PGMJ LXF?ON0OFLV-JKNNEK&JNEBMA?8CIJIII4JICM?>KL8HIBK4HLB>V²@ÿ/MTrkáºÊÿJAZ2º[][{ &Z][{ &Z][{ &Z][{ &Z][{ &][{ &ÿGuitarºZ]{ &Z@Z‚dš9H=UBUEU!=EB9!9H=UBUEU=EB9t7E;R@RCR!;C@7!7I;V@VCV7;C@r2D9H>UBUEUJU B29>JE!2D9H>UBUEUJUE>92BJs2D9U>UBU!2>B9!-D4H7U=U@UEU E@4=-7h2H9[>[B[9>B222<9L>LBL9B>2w2H9[>[B[B>9222D9U>UBU92>B‚2D9H>UBUEUJU J29>BE!2D9H>UBUEUJUJE>9B2s2D9HUCUGUJU7JGC>-7H>UCUGUJU7JC>Gs7H>UCUGUJU>7JGC+7H>UCUGUJU>CJG7q2A9E>RBRERJR 92JBE>!2D9I>VBVEVJV>9EBJ2s2A9E>RBRERJR2>J9BE+2H9M>[B[E[J[>BE92Js-A4E9R=R@RER -94@=E!-D4I9V=V@VEV@4E=9-v7E>RCRGRJR >CJ7G!7I>VCVGVJVC>J7Gr2D9H>UBUEUJU 9JEB>2!2D9H>UBUEUJU>92BEJs2D9H>UBUEUJU BE2>9J!-D4H7U=U@UEU -7E@=4h2H9M>[B[E[J[ >BJE2922<9@>LBLELJLBE9>2Jw2H9M>[B[E[J[ JB>92E22D9H>UBUEUJU J9B>2E‚2A9E>RBRERJR EB>29J!2D9I>VBVEVJVJ2E9B>s2A9ERCRGR C;>7G!7I;V>VCVGV7>CG;s7E;R>RCRGR>7;CG+7M;[>[C[G[>CG7;m2H9M>[B[E[J[ JE>92B22<9@>LBLELJLB2E>J9w2H9M>[B[E[J[ B92>EJ22D9H>UBUEUJU 9BEJ2>-A4E9R=R@RER 9=@E4-!-D4I9V=V@VEV-=E49@u7H>UCUGUJU C7>JG!7H>UCUGUJU7>CGJt2A9E>RBRERJR B>2JE9!2D9I>VBVEVJVJE29>Br2D9H>UBUEUJU J92E>BUN).N3D:U?UCUD3C?:I4O;]@]D]G] GD4@;!4O;]@]D]G]GD4;@s4O;]@]D]G]G4;@D+4O;]@]D]G]GD@4;t4L;Z@ZDZGZ @GD;4!4O;^@^D^G^4@D;Gs4L;Z@ZDZGZD;@G4+4T;c@cDcGcD@G;4L-J4O9]=]@]E]'@94E=-n-J4O9]=]@]E]!E@=94-‚>-J4O9]=]@]E]'4=-9E@0J7O<]@]C]H]'70<@CHrLML6NYN‚L_L5N]N‚s/H6L;Z?ZBZGZ';?BG6//K6O;^?^B^G^!6;?BG/n-J4O9]=]@]E] @94E=-!-J4O9]=]@]E]94-=@Es7O>]C]G]J] GC>7J!7O>]C]G]J]C>JG7M6\MM.#MO0J7O<]@]C]H]07<@CHM2J9O>]B]E]J] B>9EJ2!2J9O>]B]E]J]9JB2E>s2J9O>]B]E]J]JB9E2>+2J9O>]B]E]J]>BEJ92M2J9]>]B](2B9>n2J9]>]B]">92B‚2J9O<]B]E]J]'9B2J<En2J9O<]B]E]J]!<92JEB‚?7L;Z>ZCZGZ 7G;>C!7O;^>^C^G^;7C>Gs7L;Z>ZCZGZ;7>GC+7T;c>cCcGc>;CG7p2H9L>ZBZEZJZ 2>BJE9!2K9O>^B^E^J^2BE9>Js2H9L>ZBZEZJZE2B>J9+2O9T>cBcEcJc2JB9>Es-H4L9Z=Z@ZEZ'9=4-E@-K4O9^=^@^E^!4@9=-Eo7L>ZCZGZJZ'>7CGJ7O>^C^G^J^!GJ>7Ci2H9L>ZBZEZJZ'B>J92E2K9O>^B^E^J^!J9B2>En2J9O>]B]E]J]'>J29BE-J4O7]=]@]E]'47=E-@@2J9O>]B]E]J]'9>BEJ2n2J9O>]B]E]J]!9J2>BE‚>2J9O>]B]E]J]EB2J9>$2J9O>]B]E]J]!2J9BE>m2H9L>ZBZEZJZ'B2JE9>2K9O>^B^E^J^!JEB2>9k2J9O<]B]E]J] JBE2<9!2J9O<]B]E]J]<J9BE2s7O;]>]C]G] 7GC>;!7O;]>]C]G];7>CGs7O;]>]C]G]GC7>;+7O;]>]C]G]>CG7;q2H9L>ZBZEZJZ B>92JE!2K9O>^B^E^J^2>JEB9s2H9L>ZBZEZJZ>92BEJ+2O9T>cBcEcJcJE>92BO-J4O9]=]@]E]'9E4=@-n-J4O9]=]@]E]!4@=E-9‚7O;]>]C]G]';7GC>n7O;]>]C]G]!;7>CG‚?2H9L>ZBZEZJZ'EB>9J22K9O>^B^E^J^!2J>BE9k2J9O>]B]E]J]'B92>JENN).N3J:]?]C]>3?:C)4O;]@]D]G]'4;@DGn4O;]@]D]G]!G;@D4‚>4O;]@]D]G]DG;@4$4O;]@]D]G]!4;@DGj4L;Z@ZDZGZ D@;G4!4O;^@^D^G^D@;G4s4L;Z@ZDZGZGD@;4+4T;c@cDcGcGD4;@v-H4L9Z=Z@ZEZ'4@E9=--K4O9^=^@^E^!4E-@9=k-J4O9]=]@]E]'-4E@=90J7O<]@]C]H]'<70@CH@4O;]@]D]G]'G@;4Dn4O;]@]D]G]!G4;D@‚>4O;]@]D]G]@DG4;$4O;]@]D]G]!4D;@GF/J6O;]?]B]G]'GB?;6/n/J6O;]?]B]G]!;?BG/6‚>-J4O9]=]@]E] E-49=@!-J4O9]=]@]E]-94@E=M7O>]C]G]J]'C7>GJn7O>]C]G]J]!7G>CJLM6\MM.#MO0J7O<]@]C]H]CH@7<0N2A9E>RBRERJR EB>J29!2D9I>VBVEVJVE29>BJs2A9E>RBRERJRB2EJ9>+2H9M>[B[E[J[JEB>92p2A9R>RBR!9>B2!2D9V>VBVB2>9u2D9H[C[G[J[JGC>727@>LCLGLJL>7JCGw7M>[C[G[J[JGC7>27H>UCUGUJU C>7JG|2H9M>[B[E[J[ 29>JBE22<9@>LBLELJL2J9>EBw2H9M>[B[E[J[ JEB>9222D9H>UBUEUJU EJB>92‚-A4E9R=R@RER E@9=4-!-D4I9V=V@VEV=9@E-4p7E>RCRGRJR CGJ>7!7I>VCVGVJV>7JGCv2A9E>RBRERJR JB9>E2!2D9I>VBVEVJVEB>J92r2D9H>UBUEUJU JEB>29!-D4H7U=U@UEU -E47=@n2A9E>RBRERJR J9EB>2!2D9I>VBVEVJV2BEJ9>s2A9E>RBRERJRBJ>E29+2H9M>[B[E[J[>2JB9Es2A9E>RBRERJR 9BEJ>2!2D9I>VBVEVJV>92JBEp2A9E[C[G[>C7G;27@;L>LCLGL;7GC>w7M;[>[C[G[7GC>;27H;U>UCUGU >C;G72A9E>RBRERJR 92>JBE!2D9I>VBVEVJV2E9B>Js2A9E>RBRERJRJB>E29+2H9M>[B[E[J[>92EBJv-A4E9R=R@RER E@94=-!-D4I9V=V@VEV@=9E-4p7E;R>RCRGR ;7>CG!7I;V>VCVGV;C>G7u2D9U>UBU!9>B2!2D9U>UBU29B>s2D9H>UBUEUJU >BEJ29UN).N3D:U?UCUD:3C?ULML6NYN‚L_L5N]N‚u4O;]@]D]G] G@;4D!4O;]@]D]G];@G4Ds4O;]@]D]G]4DG;@+4O;]@]D]G]GD4;@s-J4O9]=]@]E] 4@E9=-!-J4O9]=]@]E]4E-@9=s-J4O9]=]@]E]'-4E@=90J7O<]@]C]H]'<70@CH@4O;]@]D]G]'GD@4;n4O;]@]D]G]!G@D4;‚>4O;]@]D]G]@DG;4$4O;]@]D]G]!G4@D;j/H6L;Z?ZBZGZ'/GB?;6/K6O;^?^B^G^!GB6?/;l-H4L9Z=Z@ZEZ'@=E49--K4O9^=^@^E^!94-@=EH7O;]>]C]G]'CG;>7n7O;]>]C]G]!G;C>7LM6\MM.#MO0J7O<]@]C]H]7@HC<0M2J9O<]B]E]J] J2E9B<!2J9O<]B]E]J]<29BEJ{2J9O<]B]E]J]B<EJ29'2J9O<]B]E]J]92<BEJº@ÿ/MTrkH¶ÆÿJAZ2¶[ÿ Muted guitar¶ s@]{êp–;U4W&;4*;D4P4; =P4F4=44?=D= 44H;54;);<4F;44J=F4=-4P=@4= 4P;84;.4H;D;4 4N=64 =-4L=P4=4L;<4;44H;B$;44U=D = 46=441=4 4W;U&;4*4P;D4; =P4F4=44?=D4= 4H;54;*4F;<4;=F4J4=-4P=@4= 4P;84;.4H;D;4 =64N4 =-=P4L4=;<4L4;44H;B$;4=D4U = 464R=W=4 -W4U&4-*-P4D-4 6P-F-646D-?-6 -H45-4*-F4<4-6F-J-6--P6@-6 -W4U&4-*4D-P-4 -F6P-697U0WG07,0P7D07 9P0F0940,9/90;U4W&4;*4P;D4; 4F=P4=44?=D4= ;54H4;*;<4F4;=F4J4=-=@4P4= 4P;84;.4H;D;4 4N=64 =-=P4L4=;<4L4;4;B4H$;44U=D = 46=W4R=4 /W6U&6/*/P6D/6 /F8P/848D/?/8 65/H/6*6</F/6/J8F/8-8@/P/8 -W4U&4-*-P4D-4 -F6P-646D-?-6 45-H-4*4<-F4-6F-J-6-6@-P-6 2U+W&2+*2D+P+2 +F4P+444D+?+4 25+H+2*+F2<+2+J4F+4-4@+P+4 5a<_\5<_ :]6[“>\ã8\“Aã2Y(U$SPMHD@‚.?>=<;:9876543 210/.-,+*'&$# "“>ã #"$(&,0.5379;?=@f“>mQ>4AYKA E\ E G]FGJbƒ9J+L[ãABCD F GHJLNOP"R$S(U&T*V2Y0X6[4Z8\:]>_@`BaFcHdLfPhRiVk\nXl^o`p“Lãdr `p^oZmVkPhDbLf>_4Z:]$S*VPMJ GE“LVãCBA@ BCE G FILJONP"R Q&T(U*V0X2Y6[4Z:]<^@`>_BaFcDbLfHdNgRiPhVkXlZm\n“LãXlVkRiNgHd@`4Z:]P(UK FB@“J\wGHJQGJaã?>=;:9876543120-.,*('%"# “J ã'#,05:@?„]“E_#EG[1GJ`3JIJl‚GZJLG6LbãACDE GHJKMOP"R$S*V(U0X8\4Z:]>_@`HdDbLfRiPhXlVkZm\n ZmVkRiHdNgBa:]2Y“Lã&TPK GC@ “GSIG.JcQLPJ#GPLFGJd‚CaJ ãCHEKPN$S(U0X4Z8\<^@`DbHdNgLfPhTjVkXlZm\nZmXlVkTjPhRiNgHdLfDb>_@`:]6[2Y*V&T"RPNKH FBD@<“ARC9A >Srã?=<;:86752401/-,*('%#"! “>ã!#'%*/-4168:<>@[“A`.BXA(EXB#E9T#9 ;O8;>Q>!>L>0>Xx;C>;>`>*@d@!@hB`@BAElEEBWB@fv@>dC>3>Tƒ >V>[4>>?>@V<@ @D@BLCBEU ECZ>CBQ-CLB5CEj?E8GZ‚~Ga@B'@ B\YBEYxE>CJ@L>>@4BDƒ"BbEd+EGD#G CRxCB=:BC^qCEV}@OEa@ER.GbEEG/Jg?JE[uEB[xBEeƒ}ED\9D?D\3DFD\5D GF/D\G)D BH/@CB(@ B\6BABO0@[B7@5D\_:]<^6[4Z0X*V&T"ROMJ GD@A “ObNLPOLQd ãCA FD GKIMNP$S Q&T0X*V4Z8\:]@`>_HdDbLfTjPhXlZm^obqfsjurynwv{x|z}~ “Qãx|tznw`pxtVkNgDb*V8\N GA@“Oc+ãBADE F GHIKJMLN QP"R(U&T4Z0X6[<^8\>_@`BaDbFc Ba@`:]>_*V6[$SNHB@“OLRtLJ\NLaJ‚L Jf.GYJGE]#C_EãABD FE GIKJMNOP Q"R&T$S*V(U0X2Y4Z6[:]<^>_@`BaFcHdLfJeNgPhTjRiVkRiLfPhHd<^“CãBa“@bã4ZN&T F@‚!“@ @^&@C`6CEjãAC GEIKMOP$S&T*V6[2Y:]>_@`DbLfHdRiPhVk\nXlbq^odrjuxtnwpxtzz}x||~~x|~z}x|v{rytzpxnwlvjuxtfsbq`p^o\nZmXlVkRiPhNgLfJeDbFc@`Ba<^:]6[4Z0X*V(U&T$S Q"RPNMJKH GECA@ “CVECEiãACE GILPN"R(U0X8\4Z<^Fc@`LfVkPh`pZmfslvpx|~x|~“E ãnwx|drZmPhDb:]0XN$SI FD“EcãC DH FJMO(U"R2Y6[<^HdBaNgZmTj`pdrjuv{pxz}~%“Eãv{lvbqJeVk>_ Q2YJC@“EdãC G"RM*V8\BaRiJeZmdr`pjuxtlv fsxt^obqZmRiVkNgFcJeBa@`<^8\:]4Z2Y0X*V(U$S&TO QM GJD@B “CYEL@bC‚Cd@QC@K#Cc@KEiCwãABCD FEH GIJLMNOP Q"R$S(U*V0X2Y6[8\:]<^>_@`BaDbFcHdU“E….ãLfNgPhRiTjVkXlZm\n^o\nXlVkRiNgLfHdJeFcBa@`>_<^:]8\6[2Y0X(U&T"R$S QPONLKJI G F“EgãECAB@“EGlã>=<; “Gã<=>@?9“Jp„RF`JG[FdGE`OA]ETãA B C DE F GIJLN QO$S(U*V2Y4Z:]8\<^>_ :]“>\ã6[“Aã8\2Y(U$SPMH@D‚.?>=<;:9876543 210/.-,+*'$&# "“>ã "#$(&,.05379;?=@f“>mQ>4AYKA E\ E G]FGJbƒ9J+L[ãACBD F GJHLNOP"R$S(U&T*V0X2Y4Z6[8\>_:]@`FcBaHdLfPhVkRiXl\n^o`p“Lãdr ^o`pZmVkPhDbLf>_:]4Z$S*VPMJ GEC“LVãBA@ BCE G FILJNOP Q"R&T(U*V0X2Y4Z6[:]<^@`>_BaDbFcHdLfNgPhRiVkXlZm\n“LãXlRiVkNgHd@`:]4Z(UPKB F@“J\wJGHQGJaã?>=;:9867534210-.,*(%'"# “J ã'#,50:@?„]“E_#EG[1GJ`3JIJl‚GZJLG6LbãACD GEHJKOMP"R$S*V(U0X8\4Z:]>_@`HdDbLfPhRiXlVkZm\n VkZmRiHdNgBa:]“Lã2Y&TPKC G@ “GSIG.JcQLPJ#GPLFGJd‚CaJ ãCEHKNP$S0X(U4Z8\<^@`DbHdNgLfPhTjXlVkZm\nZmXlVkTjRiPhNgHdLfDb>_@`:]6[2Y&T*V"RPNKH FBD@<“ARC9A >Srã?=<;:86754210/,-*('%#"! “>ã!#%'*-/4168:><@[“A`.BXA(EXB#GYE,GJaIJJWJƒ@GlGWEb%EAP.ãABDE GHLJN"RP$S&T*V2Y0X4Z6[“Aã2Y0X*V&TP"RNKHEC@A “A_1ãABDE GHJNLO Q$S(U*V6[4Z8\<^>_@` <^:]6[2Y"R(UNHB“Aã@“>[‚d;R>N@e;ãABCDE F GIJLMNOP Q"R&T(U*V0X4Z6[:]>_<^@`DbFcHdJeLfPhNgRiTj Vk“@ãTjRiNgJeHdDb<^@`8\*V4Z"R(UPLN GIECB@X“Aa(AEQAE GZ+GJ__<^ <^6[:]2Y“Aã(U$SLO GC@ “>Y‚b;V>I@`;1ãABCED F GIJKLMNOP Q$S(U&T0X2Y4Z8\:]<^>_@`BaDb“@ãBa>_:]2Y8\$S*VPJN GDA@V“A^+ABO)BEV#EG](GJitGVJDG E5+EJ[dJGaIGELEL\)ãABED GHJNL QO"R(U&T*V2Y4Z8\6[:]<^>_“Lã@` >_<^8\6[2Y(U$SPMI FCA@“L\#ãABD FI GKOM Q$S(U*V2Y6[:]>_@`BaDbHdJeLfHdFcBa>_:]4Z*VO$SDJ“Lã@“J[qG\JQGJj„ã? >=<;:986543210/.-,(+&'$#" “J ã"$,'/38>@a“JkFJ1KhLK3KmKLb„ L.LdKL+O[P[ O6PS\&U]SFXjUƒSX*QqãABDE F GIJKNMOP Q$S&T(U0X*V4Z6[8\:]<^>_@`DbFcHdJeLfNgPhTjRiVkXl\n^o`pbqfsxtjulvnwpxrytzv{x|z}|~~‚z|~z}x|v{tzrypx nwlvjuxtfsdrbq`p^o\nZmXlVkRiNgPhLfJeHdFcDbBa@`>_:]<^4Z6[0X&T*V"ROMJ GDA@ “ObQNLPOLQd ãCAD F GIKNMP$S Q&T0X*V4Z8\:]@`>_HdDbLfPhTjXl^oZmbqfsjunwryv{z}x|~ “Qãx|tznw`pxtVkNgDb8\*V GNA@“Oc+ãBAED F GHIKJMLNP Q"R(U&T0X4Z6[8\<^@`>_BaDbFc Ba@`:]>_*V6[$SNHB@“OLRtLJ\NLaJ‚L Jf.GYJGE]#C_EãABDE F GIJKMONP Q"R$S&T(U*V0X2Y4Z6[:]<^>_@`FcBaHdLfJeNgPhTjRiVkRiPhLfHd<^“CãBa4Z“@bã&TN@ F‚!“@ @^&@C`6CEjãAC GEIKMOP$S&T*V2Y6[:]>_@`DbLfHdRiPhVkXl\nbq^odrjuxtnwtzpxx|z}|~~x|~z}x|v{rytzpxnwlvjuxtfsbq`p^o\nZmXlVkRiPhLfNgJeDbFcBa@`<^:]6[4Z0X*V(U$S&T Q"RPNMJK GHEAC@ “CVECEiãAEC GILNP"R0X(U8\4Z<^@`FcLfVkPhZm`pfslvpxx||~~“E ãx|nwdrZmPhDb0X:]N$SID“Ecã FC D FHJMO(U"R2Y<^6[HdBaNgTjZm`pdrjuv{pxz}~%“Eãv{lvbqJeVk>_ Q2YJ@C“EdãC G"RM*V8\BaRiJeZmdr`pxtjulv xtfsbq^oZmVkRiNgJeFc@`Ba<^:]8\4Z2Y0X*V(U$S&T QOM GJDB@ “CYEL@bC‚Cd@QC@K#Cc@KEiCwãABCD FE GHIJLMNOP Q"R$S(U*V0X2Y6[8\:]<^>_@`BaDbFcHdLfNgPhRiTjVkXlZm\n^o\nXlVkRiNgLfHdJeBaFc@`>_<^8\:]6[2Y0X(U&T$S"R QPONLKJI G FECAB@6>“Eã=<;<=>@?ÿ/MTrk‰´ÄÿJAZ2´{ O][ÿSolo˜Q”EI ELpäBDH FIMKNP Q"R$S&T1(U*V0X2Y4Z6[8\:]<^>_@`BaDbFc HdJeLf NgPh,Ri6Tj Vk)XlZmQ\ny^o\nZm#XlVkTjRi#PhNg LfJe&HdFc Db Ba@` >_<^:]8\6[2Y0X(U&T"R QPNOMLJIH G FDEC@B”JZLWJJa‚RJJ\LJOeäABED FIHKMO$S Q(U0X4Z:]8\>_Db@`JeHdNgTjPhVkZm\n`pbqdrxtjunwlvpxrytzv{x|z}|~~x|v{pxju”OädrXl^oRiJeBa4Z:]&TLPDHA@ ”OiäB FNJ$S0X:]@`HdPhTjXl\n^oZmVkRiLf>_Fc8\$S0XINC@”OQMONQMT OFJZM{J\E`.GQE%GJS#JL[+JaLDJ J\!JHA\-BPA)EWB!G^E(G>bG>->dN>#Ec0EGf1äBCD FEI GJKMNO Q"R&T(U*V0X4Z8\6[:]4Z6[0X"R(U”GäO GLC@ ”EW EG_ äABDEI GJLNO Q"R&T$S(U0X2Y4Z6[8\:]@`>_BaFcHdLfPhRiVkTjXl\nZm^o”Gä\nXlVkLfRiFc8\@`$S0XNDI@”EbiE FQGX F(GJ]+JL`äAEC GHKMP"R(U0X:]6[@`JeDbNgPhTjVkXlTjRiNg”LäHd>_Db8\$S0XOJ FB@”L_äCA FILO&T Q2Y*V6[>_:]@`HdDbNgLfPhRiPhNgJeFc@`6[<^”Lä*VM"RB G@”JcJG[TGJd‚ JOd äAC FDI GLNO Q$S*V2Y6[<^Db@`JeNgRiZmVk^o`pdrxtlvpxx|tzz}~‚o|~z}x|v{rytzpxnwlvjuxtdrbq`pZm^oXlRiVkPhHdLfDb@`<^8\2Y$S*V QKNHEC@”O!Qm+QSdCS.VdäBC FHKN$SP(U6[2Y<^@`FcLfPhVkZm`pxtdrnwv{ryx||~~”Väx|ryjubqTj\nNgDb>_6[0X$SLPHDA@d”VcäADBE GHJIKMNP"R&T*V2Y6[:]Db>_HdNgRiVk`p\njudrnwtzx||~~3z}x|nwryjudr`p\nVkPhLfFc:]@`4Z$S*VLOHEB@”V#VfmV!Vi+T\ VQYT)O_QLJRO.JM^LMO_ äACE GKINP"R&T*V4Z<^8\BaNgHdXlRi^olvdrry~x|”Oäx|tznw`pfsZmTjPhJeDb>_@`<^”Ofä@`BaJeFcNgRiXl\n`pfsnwjurytzv{pxryjufs`pTjZmNgBaHd<^6[0X Q&TNKI G FEDCBA@+”M\OAMJ[‚FJ!V`OY%äABCDE F GHI JKLMNOP Q$S&T*V(U2Y0X4Z:]8\<^@`BaDbHd”VäLfPhNgRiVkXlTjRiPhLfDbJe<^@`6[”Oä0X&T QNKD G@1”OV8O!M\%M)O^ äAC FILO Q&T0X:]6[@`LfFcPhVkZmdr`pxtlvpxrynwjufs`p”OäZmRiLf>_Db*V6[$SOK GDB”M\ä@3”MMT&MJIJO[1O Ob1OOY#OMSMMOQ\&äACDE FH GJKLMNOP Q"R$S&T(U*V2Y0X4Z6[8\:](<^>_ @`Ba Db Fc HdJeLfNg PhRiTjVkXlZm\n^o`pbqdrxtfslvnwryv{x|~|~”MQ,äx|tzxtpxbq\nVkPhBaJe6[<^0X&T QNKHC F@ ”Oc;OMb.MJS6JHb.H EQ;EC^.ASCFA >=>AblACdKCAQACbäBCD FI GLJMOP Q"R&T*V(U2Y6[8\<^@`BaLfHdNgVkRiZm^o`pxtdrjunwpxtzv{x||~~&”Cäz}lvrybqZm”EdäRiDb4ZN@<@C@.”EC_äBCEH GKMO Q$S(U2Y6[:]Db@`NgHdRiTjXl\n`pbqfsjulvnwpxnwjubqfs^oXlRiBaJe:]2Y&THN”Cä@ ”Ed.EC\(äACBE F GHKJMNP&T"R*V2Y6[<^@`DbHdLfPhTjXl\n`pdrjuxtnwpxtzv{rylvpx”Cäxtbq”Eaä^oPhVkFc:]*VI@>@:AC@3”E C\ äBCE GJIMNP"R&T(U0X2Y8\6[:]@`>_BaFcHdNgLfPhRiVkXlZm^obq`pjufslvnwtzryv{rypxnwjufs`p”Cä\nTjDbNg<^*VN@”Eeä;?@B@”E Ca&äBE GJOM Q(U$S0X4Z6[:]@`>_DbHdLfRiNgXlVk\nbq`pfslvjurypxv{x||~~ ”Cäv{”Egäz}jupxbq\nTjLfBa8\E$S@;<@C@”EC\äBD FIPM$S*V2Y<^8\@`HdDbLfPhRiVkXl\n`p^obqfsxtnwjupxrytzv{z}|~~”C äryx|lvdr\nRi”Ekä0XBaD7@5>@ F@?@ ”E C\äADC FHJOMP(U$S*V4Z8\:]>_BaFcHdNgLfRiVkTjXl\nZm^obqdrxtjulvnwpx”CälvfsjubqZm`p”EdäTjDbNg8\*VH@>;@C@”E#C`äBD GJNP$S(U2Y8\>_BaHdNgTjXl^obqlvfspxx|tz~z}#z}v{pxlvdr”Cä`pPhXlHd@`8\P*V”EXäIA@&”EE>_EEc9EE^EEd(EGVGJa#JE[&EGPGJbJ GO+IPGIL]#LGP)INGIL^#LGK&GINI L[#LGL&GIQILa#LGH+IOGIL]#LGN%IKG#ILZLL\.LLT1NaLFNLWLNJOPNNROLXN#LIRNIL\nLO`QLQOLäAB”QcäDC F GHIKLNO Q"R&T(U*V0X6[4Z8\>_:]@`BaDbHdFcPhLfRiVkXl\n`pdrnwxtpxz}v{~”Qäx|ryjubqVk\nPh”QiäDbJe@`8\<^6[4Z8\:]<^@`DbHdLfTjPhXl^o`pjufsnwrypxv{x|z}|~~&”Qäz}x|rynwxtbqVk\nPhJeDb”Qaä@`:]6[2Y*V(U&T (U0X4Z8\:]@`DbJeNgRi\nXl`pxtdrpxlvryx|v{z}~+”Q äryx|drju^oPhVkHd”Q^ä<^@`8\2Y4Z*V 2Y6[8\<^@`DbNgHdRi\nVk`pdrxtpxlvtzv{x||~~”Qäv{z}rylvfs`pRiZmLfDb<^(U”Qiä4ZPL GDA@ BDHMP(U4ZBa:]JePhVk`p\ndrnwxtpxryv{x|z}|~~‚x|tznwxt`pVk\nPhDbJe>_8\4Z*V$S QKNHEC@”QYQfäDB GJMP$S*V4Z8\>_BaFcPhLfTjXl\n`pfsbqxtjunw ju”Qäfsbq`pVk\nRiLfFc<^@`6[0X&T QOLI GD”QcäB@3”QO[&OLLLQfäBE GJOM&T"R*V6[2Y:]@`DbJeNgRi\nXlbqfslvpxtzz}x|~”Qäz}tzlvdr\nRiHd2Y>_"REL@ ”O`NO Laƒ=LXSS^ XSVjäB GDJMO&T"R*V8\4Z<^@`BaLfHdPhXlTjbq^ofslvpxx|tz|~~”Väx|fspx”Xaä^oRiHd<^2Y$SMA G@&”XVf äBEHK QN*V&T4Z<^8\Fc@`JeRiNgVkZm\nbq`pdrjuxtnwlvpxrytzv{z}~Apxx|”VädrJe”X\äXl<^*VPIC@ ”X äCL G Q6[(U”X]ä@`RiJebqZmxtv{px~z}Qz}tzx|nwrylvfsjudrbq`p^o!\nZmXlVkTjRiPhNgJeHdFcDbBa>_:]<^6[8\4Z*V0X&TP"RMOJH FD”V\äA@”XlV SboQbSTQScS(ScäBDI FN Q(U<^4ZDbTjLf\ndrlvz}ry~”Säx|ryjubqZmFcPh2Y<^"R GM@A”S\dSN_+äACDH FJMP(U"R0X:]6[Db@`JeTjPhXl`p\nxtdrlvrypxtzv{”Näpxrylvxtbq`pZmTjPhHdBa6[<^0X&TP”N[äJM GDECE FJHM"RO(U8\2Y@`<^FcJeNgPh LfHdBa<^6[*V"RHNC@”NL[xLLd(LJSJ GN!FaG#FER ECR#CEi&ECMC@L)C`@(C@Q$@>P>>\Fä>=;<:867432/0.,*&($#!”>ä#!&.*158>;@ÿ/MTrk0°ÿJAZ2ÿ Faded Thingsÿ/simutrans-124.3/simutrans/music/37-inevitably-engrossed.mid000066400000000000000000000647641474050137200240200ustar00rootroot00000000000000MThd xMTrk…ÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿjgÿ~j €1 €1  @1 F@1@1 @ @11 ÿ~j@ F @1@1ˆ@ @@@L@ÿ~j1  @1 F @1 @1ˆ@@11 @ F @1@ @ÿ~j@11  @11 F @1@1ˆ@@1@ @ÿ~jL@11  @ F  @ @ˆ@ @  @ F  @ÿ~j @ @ @  @ F  @ @ˆ@ @ÿvj@ @  L @  @ F  @ @ˆ@ @ ÿnjÿXÿQ âÿYÿInevitably Engrossedÿ/MTrk ±Á ÿJAZ2±@[({ @dÿBass±]ƒa‘!SpW!jT3<(Wq(!\J!7'!Qv'Q!s'(Sp#W(j#!TR!TR #Sf# Sf!TR!TR#Sp#Wj#Sf# Sf#TR# Sf !Sf! Sf#TR#TR !Sf! Sf #Sf# Sf !Sf!TR#Sp#Wj#TR#TR #Sf# SfUkLkXkRs&_T&!TD!)&[U&&Vx%T&r%&_T&!TD!)&[U&&Vx&&Tr&#`T#Uv#Us#XR #Xf# #Xf# Xf#XR# Xf !Sf! Sf #Sf# Sf!TR!TR#\J7#'#Qv#"Qs"#Sf#TR#TR#TR^kRkWk(Zs(!Sf! Sf #Sf# Sf!TR!TR#\T#Qv#Qs##TR# Sf#TR#TR !Sf!TR#TR#TR!TR! Sf #Sf#TR!TR! Sf#T3#>#W3#<#TR#TR #Sf#TR[kOkVkYs&_T&-TD-)&[U&&Vx&T&r&&^H&(!T!V&SU&!^q!#W3#>#Z3#>Xf#XR##XR# Xf #Xf#XR !Xf! Xf #Xf# Xf!XR!XR#Vp#Zj#XR#XR#XR# XfVk^kOkTs!Xf!XR #Xf#XR!XR! Xf #Vp#Zj#Xf# Xf#XR#XR !Xf!XR #Xf#XR!TR!TR #Sf# Sf!TR!TR#Sp#Wj#Sf# Sf#TR# SfPk\k]kZs&^H&(-T-V&SU&-^q-&_T&!TD!)&[U&&Vx&T&r&#W3#>#Z3#>Xf #Xf##XR#XR #Xf#XR!TR!TR #Sf#TR !Sf!TR#T3#>#W3#>#Sf# Sf #Sf#TRTk[k[C(e( Ws!N!SN#M!^O!!!fK!ÿ/MTrk¯¹ÉÿJAZ2¹ @]ÿDrums¹[({}ƒ`™#<*P#*_*P&<&*_#<*P*#_*F&F*&7*<*#<*P*#_*P&<*&7*2**P#<#*_*F&F*&_#<*P*#_*P&<*&7*2*#<*P#*_*F&F*&7*<**P#<*#_&F*P*&7*F**P#<#*_&F*F*&7&P*P*&*P#<#*_*P&<*&7*2*#<*P#*_*F&F&*_*P#<*#_*P&<&*_*P#<*#_*F&F*&7*(**P#<*#_*P&<&*_#<*P#*_&F*F&*_#<*P*#_*P&<&*_#<*P*#_*F&F*&7*(**P#<*#_&<*P*&7*2*#<*P*#_&F*F*&7*<*#<*P#*_&<*P&*7*2**P#<#*_*F&F&*_*P#<*#_*P&<&*_#<*P#*_&F*F&*7*<*#<*P#*_&F*P*&7*F**P#<#*_*F&F*&7*P**P#<#*_*P&<*&_#<*P#*_&F*F&*7*<**P#<#*_&<*P*&_*P#<*#_&F*F*&7*<**P#<#*_*P&<*&7*2**P#<#*_&F*F*&7*(**P#<#*_*P&<*&_*P#<#*_&F*F&*7*<**P#<#*_*P&<*&_*P#<*#_&F*F*&7*(*#<*P#*_*P&<*&_*P#<#*_&F*F&*7*(**P#<#*7*(**P&<*&_*P#<*#_&F*F&*7*(**P#2#*_*P&<*&_#2*P#*_*F&F*&7.H.&<1F#<1#&_&F3P3&73(3#F3<3#_3F&P3&73(3#23<#3_&<3F&373(33F#<3#_3<&F3&7333F#<3#_&F3P&373(33F#F3#_3P&F3&7333<#2#3_3F&<&373(3#<3F3#_&F3<3&73(3#<3F3#_3P&F&373(33F#F#3_&F3P3&73(33F#<3#_3P&F3&73(33F#F3#_&F3P&373(33F#<3#_&F3P3&733#F3F#3_3P&F&3733#<3F3#_3P&F3&733#<3F3#7&F&3P&Z3&73(3#<*P#*_*P&<*&_*P#<#*_*F&F*&7*(**P#<#*_&<*P&*_*P#<#*_&F*F&*7*<*#<*P*#_*P&<*&7*2**P#<#*_*F&F&*7*<**P#<#*_&<*P&*7*2**P#<#*_&F*F*&7*(**P#<#*_*P&<&*_*P#<*#_*F&F&*7*<**P#<#*_&<*P*&_*P#<*#_*F&F&*7*<**P#<*#_*P&<*&_#<*P#*_*F&F*&7*<*#<*P*#_*P&F&*_*P#<*#_&F*F*&7&P*P*&1<*2&2#<1&*#_&F*P*&7*F*#<*P#*_*F&F*&7*P**P#<*#_&<*P&*_*P#<#*_*F&F*&7*<**P#<#*_*P&<*&7*2*#<*P#*_*F&F*&7*(*#<*P#*_*P&<*&_*P#<#*_&F*F*&_*P#<#*_&<*P*&_*P#<*#_*F&F&*_#<*P#*_&<*P*&_*P#<*#_&F*F&*7*<**P#<#*_&<*P&*_*P#<*#_*F&F*&7*<**P#<#*_*P&F*&7*F**P#<#*_&F*F*&7*P*#<&21<*2#&1*_*P&F&*_#<*P*#_&F*F&*7*P**P#<#*_*P&<*&_*P#<*#_*F&F&*7*<**P#<*#_*P&<*&_*P#<#*_*F&F&*_#<*P*#_*P&<*&_*P#<#*_*F&F*&7*(*#<*P#*_&<*P*&_*P#<#*_*F&F*&7*<*#<*P*#_*P&<&*_*P#<#*_*F&F*&7*<**P#<#*_*P&<*&7*2*#<*P#*_&F*F*&7*<**P#2#*_&<*P&*_*P#2*#_&F*F*&7*2*#<1F&<#1&_&F3P3&73(3#F3<3#_&P3F&373(33<#23#_3F&<3&73(3#<3F#3_&F3<&37333F#<#3_&F3P3&73(33F#F#3_&F3P&373(3#23<#3_3F&<3&73(33F#<3#_3<&F3&7333<#2#3_3F&<&3733#<3F3#_3<&F3&73(3#23<#3_3F&<3&73(33F#<3#_&F3<&373(3#23<3#_&<3F3&73(3#<3F3#_&F3<&37333F#<#370203P&F&370<3(033F-<3-7-<-3P&P&373-P3-#<&<1F&1#_&F3P&373(33<#F3#_&P3F&373(33F#<3#_3P&F3&7333F#F#3_&F3P3&7333<#2#3_&<3F&373(33F#<3#_&F3<&373(3#23<3#_3F&<3&7333F#<#3_&F3<&3733#<3F#3_&F3P&373(3#F3F3#_&F3P3&73(33F#<#3_&F3P&3733#F3F#3_3P&F3&733#<3F3#_3P&F3&73(3#F3F3#_&F3P3&733#<3F3#_&F3P&373(3#<3F#37&F&3P&Z&37&F3&3&<#<1F1&#_&F3P&37333<#F3#_&P3F&373(33F#<#3_3P&F&37333F#F#3_3P&F3&73(33F#<3#_3P&F3&733#F3F#3_&F3P&373(33<#2#3_&<3F3&733#<3F3#_&F3<&37333F#<3#_3P&F3&733#F3F#3_3P&F3&73(33<#2#3_3F&<&37333F#<#3_3<&F3&7333F#<3#_3P&F3&73(33F#F3#_3P&F3&733#<3F#37020&F3P&370<330-<3F-37-<-&P3P&37-P3(3-*P#<#*_*P&<*&_*P#<#*_*F&F*&7*(*#<*P#*_&<*P&*7*2**P#<#*_*F&F&*7*<**P#<#*_*P&<*&7*2**P#<#*_&F*F&*7*<*#<*P*#7*(**P&<&*_#<*P*#_&F*F*&7*(*#<*P*#_&<*P&*7*2*#<*P*#_*F&F*&7*<*#<*P#*7*(**P&<&*_#<*P*#_&F*F&*_#<*P*#_*P&<*&_*P#<*#_&F*F&*7*<*#<*P*#_&F*P*&_#<*P*#_*F&F&*7*P&P*&1F&<#<&1#_3P&F3&73(33<#F#3_3F&P&373(3#23<3#_&<3F&37333F#<#3_&F3<&373(3#23<#3_3F&<&3733#<3F3#_3<&F3&733#23<#3_3F&<3&73(33F#<#3_3<&F&373(3#23<3#_&<3F&373(33F#<#3_&F3<&37333<#23#_3F&<&3733#<3F3#_&F3<&373(3#23<#3_3F&<3&73(33F#<#3_&F3<3&733#<3F#37020&F3P&3730<303F-<3-7-<-3P&P3&73(-P-3#<*P*#_&<*P*&_#<*P*#_*F&F*&7*<*#<*P*#_&<*P*&_#<*P*#_*F&F&*_*P#<#*_&<*P*&_*P#<#*_&F*F&*7*<*#<*P#*_&<*P*&_#<*P*#_&F*F*&_#<*P#*_*P&<&*_*P#<#*_*F&F*&7*<*#<*P#*7*(*&<*P&*7*2**P#<#*_*F&F&*_#<*P*#_&<*P*&_#<*P*#_&F*F*&_*P#2#*_*P&<&*_*P#2#*_&F*F*&7*2*3F#<3#70203P&F&370<330-<3F-37-<-3P&P3&73-P3-*P#P*#7#F#*P&F*&_*P#P&2121#&*ÿ/MTrkø²ÂÿJAZ2²@ O{[F]xÿPianoƒm’8K13-,ƒB8-1>F40;@(+9EƒN49>(;8K13-,ƒB8-1 >9(%;;9G41ƒ&4(>9; =F9@40'-+6E6-649=@;9I*;60=?‚@6*9=>F60;@/+9E6;/6>9>;8I(;40;?]>;48(:6K13-,*16-@;9I*;60=?]@=*96?;9I/;=?60ƒq²@L’/69?=²@’>F;@60/+9E^;>/69 >;8I(;40;?b;>4(8 >9;;/%9G61^/6>9;>F;@40(+8E6(>84;8A'18\81 =A@=:C6;*0^*:6@=9A28^92>F;@40(+8E^>(;48=F409@6E-+^6=94-9A48^94 >9/%;;9G616;69/>8I>;(;;?40](8;4>=99;-%(416G\9-=469K43*,R9*49K33/,ƒ9/3:9K23/,R29/8K23(,R2(89A28^29 >9;;(%418G6;>(84 =F9@40'8E\=948 @==A6;:C*0^6:*=@>F;@60/+9E6;>9/6:8K23(,R(28=K632,…8>ABC 9<9 >=B6 24>AA=;C9;20‡.>A;92?F;@609E/+ƒN/?6;99K43*,R9*4 ;A?=6;9C/0^;/69?9A28^92 @9*%=;61:G^6@*=:9A28^928K23(,*(286A'18661@9=;*%(9G61\=@*699A28^29 >9;;(%418G^4(8>; =9-%9;6G41^964-=9A486499I?;/;=?60ƒq²@L’?6=9/²@’;A>=6;9C/0^9/>6;>F;@408E(+^8;4(>9A28^92 >;8I(;40;?b;4(>8 =94%9;8G6=849@9*%=;(61:G\*=@:69K23/,R92/8A28^82=F409@-+6E6-469= @F=@60'9E*+\6=@9*9K23/,R/29 >9(%;;8G41^84(;>6K13-,R61-9K43*,R*94 ?9/%=;9G61ƒ&69/=? >F;@60'9E/+\6;>/9>F40;@8E(+^8(4;>>F;@60/+9E^6;>/9 >;8I(;40;?b84>;(8K13-,R18-:A48^4:9A28^928K23(,R82(=F9@40-+6E^94=6-@F=@609E*+^6@=*9 >=;A6;9C/0^>;69/ >=;A8C4;(06>8;(4=9-%9;(416G\=-964 @==A6;9C*0^=96@*9K33/,ƒB/399K23/,R92/8K23(,R82(9A28^92 >9(%;;418G^>(;84=F409@8E^84=9 @9=;*%61:G^6:=*@9K23/,R2/98K23(,R82( B;=I2;90>?ƒN²@y’9=>26-%B*9Cl=:6>FK=6>9²@’>AA=9;;C20‡;9A>2:9K33/,ƒB3/99A48^499K33/,R93/9K23/,R29/ =A@=6;:C*0^*6=@:9A28^29 >9(%;;418G6>(;84:6K13-,R-619A48^499A28^928K23(,R2(8 ==9A4;6C-06=964-@;9I*;=?60]6@9=*?;9I/;60=?ƒq²@L’=?9/6²@’>9;;/%9G61^/69;>>F40;@(+8E^8(;4>9K23/,R92/8A28^82 9A==8C4;b948=@F60=@:E*+^6:*=@ >=;A6;9C/0^9;6/> >9(%;;8G41^>(;84 9A==6C4;-066-=949I@;*;60=?‚=9*6@ >9/%;;619G^>9;/6>F;@40(+8E^(>4;8=F409@-+6E69-=46 @F=@60'*+9E\6=@9* ?==A9C6;/0ƒN?6=9/ >9;;/%619G696;/>>9(%;;(8G41\>;(48>F;@60/+9E^/6;9>8A28^828A18^81:K43*,*4*::9K23/,*/92:8K23(,R28(6K13-,*-16@==A6;9C'*0\@=96*9A28^298K23(,*(82:6K13-,R61-@F=@60*+9E^9*=6@9A38ƒN93>F60;@/+9E^/9;6>>F40;@(+8E^(84;> ;A>=9C6;/0^;96/>8A28^28 ==9A4;8C:49=8:I@;*;60=?‚=@:*69A28^29>F40;@(+8E^(8>4; B92%>;=G91…>B="BP=H2B=!9*2eA9>;2%;G91…;>A"AP;H2A;!9*2e?9/%;;619Gƒ&;/?969A'486499I?;/;60;?‚9/;6? ;A>=9C6;/06>/;69:I@;*;60=?]@*=:6:9K23/,*2/9 >F40;@'8E(+\;4>(86A18^619K43*,R9*49A286298I>;(;40;?‚>(;48 9A==6C4;-0^-94=69A486949I?;/;=?60ƒq²@L’/=6?9²@ ’9K23/,R/29 >;8I(;40;?b;48(>9K23/,*92/>;8I(;;?40];4(8> =F409@'8E6=894:A'48\:49A28^928K23(,*(28 =9974/8@-7„ 4 = 89--3-4;:4>45=N8R9?-794 8 =-#²@ÿ/MTrk´ºÊÿJAZ2º][<{ 'd][<{ 'd][<{ 'd]]{ 'd][<{ 'd[<{ÿGuitarº 'd][<{ 'd@[<„Rš4=8===@==@84Q4B8B=B@B@=48U2=9=;=@=2;@9327 (422B9B;B@B@92(;U4=8===@=8=@4347 4-84B8B=B@B4-8=@U2=9=;=@=@;92327 (422B9B;B@B(29;@U6===@==6@Q4=9===B==49BQ6=9=>=B=B>69[(+/-2686;6@6i//3282=8=;(@;=@=;/@28[-+66=6@6j66====@-@=@=6[*+1-4696=6B6i11344=99==B*==B=B941=[/-3696=6B6j33=99==/B==B=B93=S/83B9B=BBB3/9B=U9=;=B=9B;Q/32=8=;=@=;2@8/Q6=9=>=B=9>B6Q/32=8=;=@=8@/2;Q4=8===@=8@4=[*+1-46:6=6B6i11344=::=*=B==B==:4B1Q9=;=B=;9BQ/32=8=;=@=82@;/Q6===@=@=6Q134=9===B=9=41BQ6=9=>=B=B>69Q/32=8=;=@=@82;/[-+66=6@6j66====-@@=6=@Q134=9=@=B=1@9B4Q9===B=B9=S3B9B=BBB39=B_/-6696>6B6j66=99=>>=/BB=B9>6[(+/-2686;6@6i//322=88=;@(;=@=/@;82[/-6696>6B6j66=99=>/>=BB=69B>[(+/-2686;6@6i//322=88=@(;;=@=/82;@[--4686=6@6j44=88====-@@=4=8@Q134=:===B=:4=1BQ6=9=>=B=B>96[(+/-2686;6@6i//3282=8=(;@;=@=2@;8/Q9===B=9B=Q9B=BBB=9BU9;=;B;=B9H9@=@B@9=B[56<6>6E6j<<=>>=5EE=<>ES5BBEBE5<>U<;>;E;E<>'E/>6<65/5<5@><@>@EE@<5E>Q3=9=;=39;S/83B9B;B/39;U134=9===B=14=9B[/-3696;6j33=99=/;;=93;8/-6696>6B6 66=99=>/B>=B=69B>Q4=:===:4=Q6=9=>=B=9>6BQ/32=8=;=@=8@;2/Q6===@==6@Q134=9===B=1B=94Q6=9=>=B=96>BQ/32=8=;=@=/@82;[-+66=6@6j66====@-@=6=@Q134=9===B==14B9[/-3696=6B6j33=99==/==BB=39B=S/83B9B=BBB39/=B_/-6696>6B6j66=99=>>=B/B=9>B6Q/32=8=;=@=/2;8@[*+/-2696;6j//322=99=;*;=;9/2Q/32=8=;=@=/8@;2Q4=8===@==8@4Q134=:===B=:B=14[/-6696>6B6j66=99=>/>=BB=6B>9Q/32=8=;=@=;2@8/[-+66=6@6j66====@-@=@=6[*+1-4696=6B6i11344=99=B=*==B=4=1B9Q6=9=>=B=6>B9Q/32=8=;=@=/@8;2[-+66=6@6j66====@-@=@=6Q134=9===B=B=491Q3=9===B==3B9Q3B9B=BBB3=9BU6=9=>=B=>69BQ/32=8=;=@=;@2/8Q6=9=>=B=6>B9Q/32=8=;=@=@/;82Q4=8===@=8@=4Q134=:===B=4:B=1Q9=;=B=B9;Q/32=8=;=@=/8@2;Q6===@=@6=Q4=9====49[2696;6B6j99=;;=2BB=9B;[(+/-2686;6@6i//3282=8=;(@;=@=8/2;@Q6===@=@=6Q134=9===B==149B[3696=6B6j99====B3B=B=9S3B9B=BBB9B3=U9=;=B=;B9[(+/-2686;6@6i//3282=8=@(;;=@=8;2/@Q6=9=>=B=6>9B[(+/-2686;6@6i//3282=8=(;@;=@=28;/@Q4=8===@=84=@Q134=:===B=4B:=1[/-6696>6B6j66=99=>B/>=B=B9>6Q/32=8=;=@=@8/2;Q9===B=B=9Q9B=BBB=B9U9;=;B;9=BH9@=@B@B=9Q235=<=>=5<>2357 -45285BB2-5<>U225;<;>;<52>J-3265@<@>@>-25<Q6=9=?=B=6B?9367 6/86B9B?BBB6/?9BU134=9===B=49=B1Q6=9=?=B=?6B9Q9=;=B=;B9Q:===C=C=:Q6=9=>=B=69B>[(+/-2686;6@6i//3282=8=@(;;=@=/;28@[-+66=6@6j66====@-@=@6=Q134=9===B=941=BQ6=9=>=B=>B96[(+/-2686;6@6i//322=88=;@(;=@=8;2/@Q6===@=6=@Q134=9===B=B=194Q9===B==B9Q9B=BBB9=BU6=9=>=B=9B6>Q/32=8=;=@=@2;8/[/-6696>6B6j66=99=>/B>=B=69>B8(+/-2686;6@6 //322=@;8(8=;=@=@28/;[--4686=6@6j44=88==@-==@=4@8=Q134=:===B=B1:=4Q9=;=B=9B;Q/32=8=;=@=@;82/Q6===@=@=6Q134=9===B=49B=1Q9=;=B=9;BQ/32=8=;=@=82;/@[-+66=6@6j66====@-@==6@Q4=9===4=9Q9===B=9=BQ9B=BBB9B=U6=9=>=B=>9B6Q/32=8=;=@=82/;@Q6=9=>=B=9B>6[(+/-2686;6@6i//3282=8=;@(;=@=@;/82Q4=8===@=@48=Q134=:===B=B:=14Q9=;=B=;9BQ/32=8=;=@=28/;@Q6===@==6@Q4=9===B=4B=9[2696;6B6j99=;;=2BB=9B;Q/32=8=;=@=/8;2@Q6===@=6=@[*+4696=6B6j44=99====B*B=B=94Q3=9===B=39=BS/83B9B=BBBB93=/_/-6696>6B6j66=99=>>=B/B=9B6>Q/32=8=;=@=82@/;Q6=9=>=B=B>69[(+/-2686;6@6i//3282=8=;(@;=@=8;@2/Q4=8===@==8@4Q134=:===B=B:=14[*+/-2696;6j//322=9;*9=;=/2;9Q/32=8=;=@=;82/@82696=6B6 99==B==2B=9B=S2B9B=BBBB29=U9;=;B;B9='B/=6962/292@=9@B=@B@29=BQ<=>=E=<E>QBEB<>EU<;>;E;><EH<@>@E@>E<Q6=9=?=B=96B?S/86B9B?BBB?B6/9U4=9===B==94B8/-3696;6 33=9;/9=;=9;3Q9=;=B=;9BQ:===C=:=CQ9=;=B=9B;Q/32=8=;=@=8@2;/[-+66=6@6j66====@-@==@6Q134=9===B=1=94B[/-6696>6B6j66=99=>/>=BB=6B>9Q/32=8=;=@=8;@2/Q6===@==6@Q134=9===B=B4=91Q9===B==B9S3B9B=BBBB=93U6=9=>=B=6B9>Q/32=8=;=@=/@28;[2696;6B6j99=;;=2BB=;9BQ/32=8=;=@=;@/28Q4=8===@==84@Q134=:===B==:4B1Q9=;=B=;9B[(+/-2686;6@6i//322=88=;@(;=@=/8;@2Q4=8===@=@4=80@/=6864/-8484B8B=@=B@B-48=@b-.4787=7@7"-8=@4D-24;8;=;@; -48=@_º@ÿ/MTrkR¶Æ0ÿJAZ2¶]ÿStrings¶@[<{ hdÎ`–ZU ‚jZvZ(ƒPU ZS)Y‡3YSQ)WƒSQWQ XkXQQ)WcWQQ)VcVQR)XcXRVQ&kQVP&VkVPÚZU&ƒ!UU%ƒvU ZS)Y‡3YSQ)WƒSWQQ)XcXQQ)WcQWQ VkQVR)XcXRQ)VcQVP)VcPVN)UcNUQ)XcQXQ&VkQVP)VcVPN)UcUNQ)XcXQWQ&ƒ!QQ#QWQ)VcVQP)VcVPQ)VcVQP)VcVPP)UcUPR)XcRXQ)VcVQVP kPVN)UcUNXQ kXQQ&VkVQP)VcVPUN&kNUQ&XkQXQ)WƒSWQQ&VkVQP VkVPQ)VcQVVP kPVUP kPUR)XcXRQ)VcQVP)VcVPžU)Z‡3ZUS)Y‡3YSWQ ‚jWqQQ)XcXQWQ&kQWQ)VcVQR)XcRXVQ kVQP)VcPVžP UƒTUPƒe¶@ÿ/MTrkÿJAZ2ÿ/MTrk:°ÿJAZ2ÿMelody Harmony (below)ÿ/MTrk/°ÿJAZ2ÿ Piano (3Pt)ÿ/MTrkf³ÃÿJAZ2³[K{ EÿVoice 1 (Melody)³]’d“DaS@PDJ@DdL@ND@@=H,@Z=A@3@W4@3@bu@ @UG@ITKIE_6BCE>BGQGGFBZY>gB5=W >E>T =6@\>*BY@?B G`ZDLGnDET‚UEIQvIL[‚@L=cx@e=r@DQ'DL9Su@U9N@=Q_=BS0B@SD@BSIBDSMDESuEISDIDSƒHD>PT>!GVmG=W&>J=P>IWIGc^G9R.9>=U== @V@BP2B EetE,BT*B>T2>=7R;E=d;GgG E[7EB>W*>MGb7G?EU=EGB5(BIi9I;BPZG[B2G9GQLSG9LIO‚Iƒ]DaS@PDJ@DdL@ND@@=H,@Z=A@3@W4@3@bu@ @UG@ITKIE_6BCE>BGQGGFBZY>gB5=W >E>T =6@\>*BY@?B G`ZDLGnDET‚UEIQvIL[‚@L=cx@e=r@DQ'DL9Su@U9N@=Q_=BS0B@SD@BSIBDSMDESuEISDIDSƒHD>PT>!GVmG=W&>J=P>IWIGc^G9R.9>=U== @V@BP2B EetE,BT*B>T2>=7R;E=d;GgG E[7EB>W*>MGb7G?EU=EGB5(BIi9I;BPZG[B2G9GQLSG9LIO‚Iƒ]DaS@PDJ@DdL@ND@@=H,@Z=A@3@W4@3@bu@ @UG@ITKIE_6BCE>BGQGGFBZY>gB5=W >E>T =6@\>*BY@?B G`ZDLGnDET‚UEIQvIL[‚@L=cx@e=r@DQ'DL9Su@U9N@=Q_=BS0B@SD@BSIBDSMDESuEISDIDSƒHD>PT>!GVmG=W&>J=P>IWIGc^G9R.9>=U== @V@BP2B EetE,BT*B>T2>=7R;E=d;GgG E[7EB>W*>MGb7G?EU=EGB5(BIi9I;BPZG[B2G9GQLSG9LIO‚Iÿ/MTrkQ³ÃÿJAZ2³ E{[K]ÿVoice 2 (Harmony) ’d“@aS=P@J=@dL=N@@=9H,9Z9A939Wk98WD83;bu; =UG=ETKE@_$@?_ ?C?>?BQGBF>ZY9g>59W 9<98W;T 86=\;*>Y=?> B`Z>LBn>@T‚U@FQoFEQEE[dED[WD8cx=e8r=@Q'@L6Su=U6N=8Q_8=S0==SD==SI=@SM@@Su@ESDE?SƒH?9PT9!DVmD9W&9J9P9EWEDc^D4R.4>:U=: =V==P2= BetB,>T*>9T2997R8E9d8BgB B[7BB9W*9MBb7B?BU=B<=GW=6T6[9dO95NL5(9_.9I*Df>>D=5!=>5>Ei9E;>PZD[>2D9@QIS@9IFO‚ FEOEƒ]@aS=P@J=@dL=N@@=9H,9Z9A939Wk98WD83;bu; =UG=ETKE@_$@?_ ?C?>?BQGBF>ZY9g>59W 9<98W;T 86=\;*>Y=?> B`Z>LBn>@T‚U@FQoFEQEE[dED[WD8cx=e8r=@Q'@L6Su=U6N=8Q_8=S0==SD==SI=@SM@@Su@ESDE?SƒH?9PT9!DVmD9W&9J9P9EWEDc^D4R.4>:U=: =V==P2= BetB,>T*>9T2997R8E9d8BgB B[7BB9W*9MBb7B?BU=B<=GW=6T6[9dO95NL5(9_.9I*Df>>D=5!=>5>Ei9E;>PZD[>2D9@QIS@9IFO‚ FEOEƒ]@aS=P@J=@dL=N@@=9H,9Z9A939Wk98WD83;bu; =UG=ETKE@_$@?_ ?C?>?BQGBF>ZY9g>59W 9<98W;T 86=\;*>Y=?> B`Z>LBn>@T‚U@FQoFEQEE[dED[WD8cx=e8r=@Q'@L6Su=U6N=8Q_8=S0==SD==SI=@SM@@Su@ESDE?SƒH?9PT9!DVmD9W&9J9P9EWEDc^D4R.4>:U=: =V==P2= BetB,>T*>9T2997R8E9d8BgB B[7BB9W*9MBb7B?BU=B<=GW=6T6[9dO95NL5(9_.9I*Df>>D=5!=>5>Ei9E;>PZD[>2D9@QIS@9IFO‚Fÿ/MTrk˳ÃÿJAZ2ÿVoice 3 (Harmony) ³{ E][K’d“=aS8P=J8=dL9N=@94H46H6Z6A636Wk64WD438bu8 8UG8@TK@=_69C=>9?QG?F9ZY6g952W 6E8T 269\8*9Y9?9 >`Z;L>n;=T‚U=@Qo@BQBB[dB@[W@4cx8e4r89Q'9L2Su9U2N92Q_29S098SD88SI8=SM==Su=@SD@9SƒH96PT6!>Vm>4W46W6J6P6>W>>c^>1R.1>4U=4 :V::P2: >et>,9T*96T2647R2E4d2=g= =[7=B6W*6M=b7=?=U==<9GW91T1[5dO50NL0(5_.55T^59eh9?SHE[?…;E?>U_>>^@>:=Zv@G =L@>Qƒ9>!@[wE\@‚=E*B^(B=>C2>T >I>DYDX8hQ4R 8?4I 4J1X4;14O649[G9-9Od96Pc6c>b5>89I*>f9>>95(9>i9>;9PZ>[92>9=QDS=9D@O‚ @BOBƒ]=aS8P=J8=dL9N=@94H46H6Z6A636Wk64WD438bu8 8UG8@TK@=_69C=>9?QG?F9ZY6g952W 6E8T 269\8*9Y9?9 >`Z;L>n;=T‚U=@Qo@BQBB[dB@[W@4cx8e4r89Q'9L2Su9U2N92Q_29S098SD88SI8=SM==Su=@SD@9SƒH96PT6!>Vm>4W46W6J6P6>W>>c^>1R.1>4U=4 :V::P2: >et>,9T*96T2647R2E4d2=g= =[7=B6W*6M=b7=?=U==<9GW91T1[5dO50NL0(5_.55T^59eh9?SHE[?…;E?>U_>>^@>:=Zv@G =L@>Qƒ9>!@[wE\@‚=E*B^(B=>C2>T >I>DYDX8hQ4R 8?4I 4J1X4;14O649[G9-9Od96Pc6c>b5>89I*>f9>>95(9>i9>;9PZ>[92>9=QDS=9D@O‚ @BOBƒ]=aS8P=J8=dL9N=@94H46H6Z6A636Wk64WD438bu8 8UG8@TK@=_69C=>9?QG?F9ZY6g952W 6E8T 269\8*9Y9?9 >`Z;L>n;=T‚U=@Qo@BQBB[dB@[W@4cx8e4r89Q'9L2Su9U2N92Q_29S098SD88SI8=SM==Su=@SD@9SƒH96PT6!>Vm>4W46W6J6P6>W>>c^>1R.1>4U=4 :V::P2: >et>,9T*96T2647R2E4d2=g= =[7=B6W*6M=b7=?=U==<9GW91T1[5dO50NL0(5_.55T^59eh9?SHE[?…;E?>U_>>^@>:=Zv@G =L@>Qƒ9>!@[wE\@‚=E*B^(B=>C2>T >I>DYDX8hQ4R 8?4I 4J1X4;14O649[G9-9Od96Pc6c>b5>89I*>f9>>95(9>i9>;9PZ>[92>9=QDS=9D@O‚@ÿ/MTrk8°ÿJAZ2ÿInevitably Engrossedÿ/simutrans-124.3/simutrans/music/38-positive-thrill.mid000066400000000000000000000452651474050137200230150ustar00rootroot00000000000000MThdxMTrk^ÿCopyright (C) 2007 shunterð~ ÷°ÿJAZ2ÿjÿ~j'@'''@@@ÿ~j'@(@ @@@'ÿ~j'@@@'@(@ ÿ~j@'@@'ÿvj@@@@!@ @@ÿPjÿXÿQòäÿYÿPositive Thrillÿ/MTrk{±Á ÿJAZ2±[(]d ,{ÿBass±@‘+Qw+t&L&f+Rw+}&P&V+Ly+s&N&\+K+.&@!&+QI+,#RL#0$Qw$tLf$Rw$}+P+T+Qw+t&L&f+Rw+}&P&U2K2j&U&T$Dx$|$Lr$y+Hy+w&O &e+Qv+2Zo2/We/&IV&"$Hn$ "Lq"HpOo )Hn) 'Lq'$Hp$!Oo! $O`$(Pl( +Hp+ -Kl- +O`+&Pl& $O`$(Pl( )Hn) 'Lq'$Hp$!Oo! *O`*-Pl- 0Hp0#Kl# $O`$(Pl( +Hp+ -Kl- -Hn- +Lq+(Hp(%Oo% &O`&!Pl! HpKl +Hn+ )Lq)&Hp&#Oo# $@W$ (JZ(+DT+$-AR-'&Hn& $Lq$!Hp!Oo O`#Pl# &Hp&(Kl( )Hn) (Lq(&Hp&#Oo# O`#Pl# &Hp&(Kl( )Hn) (Lq(&Hp&#Oo# $O`$(Pl( +Hp+-Kl- .Hn. -Lq-+Hp+(Oo( O`#Pl# &Hp&(Kl( )Hn) (Lq(&Hp&#Oo# &O`&*Pl* -Hp- /Kl/ $@W$ (JZ(+DT+$-AR-'O`#Pl# &Hp&(Kl( )Hn) (Lq(&Hp&#Oo# $@W$ (JZ(+DT+$-AR-(O`!Pl! $Hp$ &Kl& $@W$ (JZ(+DT+$-AR-'O`Pl $O`$Pl O`!Pl! $Hp$ &Kl& *O`*-Pl- 0Hp0#Kl# $O`$(Pl( +Hp+ -Kl- -Hn- +Lq+(Hp(%Oo% &O`&)Pl) -Hp-*Kl* +@j+&Mq&Fj#Os#$Hn$ "Lq"HpOo &Hn& $Lq$!Hp!Oo +I +M&Q%&P+QJ+ +F+&XW&#2Qp2*Mt*+K+Z2P&2J+Q+X&Ps&#8k# $I $MQ%P$QJ$ $F$XW#+Qp+*Mt* +Ly+s&N&\+K+.&@!&+QI+,%RL%/&Dx&|!Lr!z$Dx$|Lry+I +M&Q%&P+QJ+ +F+&XW&#2Qp2#Mt#$O`$(Pl( +Hp+ -Kl- O`!Pl! $Hp$ &Kl& $@W$ (JZ(+DT+$-AR-'+O`+&Pl& $O`$+Pl+ O`!Pl! $Hp$ &Kl& *O`*-Pl- 0Hp0#Kl# $@W$ (JZ(+DT+$-AR-(!O`!%Pl% (Hp( *Kl* &O`&)Pl) -Hp-*Kl*+Oh+)Ye)(Iy(&So&$O`$(Pl( +Hp+ -Kl- &O`&*Pl* -Hp- /Kl/ YU#Zb#$\Z$!%eW%$&aZ&iiÿ/MTrkH¹É(ÿJAZ2¹ @™.]¹][({W™$OÿDrums!™$.R,)&*1,*&U*.$S*$Y&*P*&Y*E$P!$*U&*F!*&U*M$J"*$+&O#&&W"&.&0!&*8$L$*b*\&j*&[*J$U*$W*S&!&*U*>$L *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&.J$X.,$",.*\&J* &\$S*C *$V*Z&*&[$O*=*$W*X&m &*U$S*="*$,&C& &b&h$P*C$*W*U&&*V*J$[*$V&*O*&[$L*> *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&$L*8$*b&j*\*&[$U*J*$W*S&!&*T$O*=*$W*X&m &*U$S*="*$,&C& &b&h*F$X$*W&*j&*Y*C$S!$*T&v*E"*&T*C$J $*U&.` &.U$P.`!$.,&y& &`#&-&j& $`1l&F$1&S3l&$\!$&3)&(&&$O3M$3X3i$`&$&3-3L&0#3&$`3r 3$V&t$h3i3&$,&03@3&$[3r$3Y$_&3q&3$.3@#3$l3M!3$.&#&$h3g$3$Q3$i&&$3.&#& 3j$b*3$#&&$M3$3,&J"&&$c$&.22 $b!$.0e0 --Y1$n1$W&3$h3$&.3<3 3W$b$3Y3&$h"3$&*3$c.$1&!&&$c&$1& & &9$`&$&1& && $c&!&$U1l$`&F$1&S&3l$\!$&3)&(&&$O3M$3X3i&$`$&3-3L&0#3&3t$^$3V&$\3m)3$&"3O3 $k3\"3$S$i3&3&$,3@3 3M$l!3$.&#&$h3g$3$Q3$i&&$3.&#& 3j$b*3$#&&$c.>.$1&!&$c&&$1& & $`&9&$&1& && $c&!&$U$i1o!$1S$f3&3&$-3C#33o$f 3$X$\&33$&+3O 33r$` 3$V&t$h3i3&$,3@&03&3r$[$3Y$_&3q&3$.3@#3$n11$W&3$h3$&.3<3 $b3W$3Y3$h&"3$&*3.$1&!&&$c&$1& & $`&9&$&1& && $c&!&$U$L*8*$b&j*\*&[*J$U*$W*S&!&*T$P*E!$*U&*F!*&U*M$J"*$+&O#&&W"&.&0!&$O.]!$.R,)&*1,*&U*.$S*$Y*P&*&Z*>$L *$T&q*W*&2& & *j$I$*1&`$&&3 &&& &&$&*8$L$*b*\&j*&[*J$U*$W*S&!&*T*C$L $*U*H&!&*-*(%*$Y*H$*X*S&]*&-&z &*F$X$*W&*j&*Y*C$S!$*T&v*E"*&T*E$P!$*U&*F!*&U*M$J"*$+&O#&&W"&.&0!&$L*8*$b&j*\*&[$U*J*$W*S&!&*T$O*=*$W*X&m &*U$S*="*$,&C& &b&h$U*> *$U*_&&*X*5$P*$U&*Z*&Z.B$M!.$,&t!&$P.w$.2&!& $J.t.$&+ &&e!&&$M &$&;"&&M$&1l$`&F$1&S&3l$\!$&3)&(&&$O3M$3X3i&$`$&3-3L&0#3&$`3r 3$V$h&t3i3&$,&03@3&$[3r$3Y$_&3q&3$.3@#33M$l!3$.&#&$h3g$3$Q3$i&&$3.&#& $b3j*3$#&&$M3$3,&J"&&$c$&.22 $b!$.0e0 --Y1$n1$W&3$h3$&.3<3 $b3W$3Y&$h3"3$&*3.$1&!&&$c&$1& & $`&9&$&1& && $c&!&$U$n11$W$h&33$&.3<3 3W$b$3Y3&$h"3$&*3.$7&&$c&$&7&&&9$`&$&1&&&$c&&$_$Z&s&$_2s2_$s$7$s$2s2_-s&-&_,Z,7&s.s$s&$.7,2,ÿ/MTrkH²ÂÿJAZ2²[({ 1PÿPiano²@]’O\M\J\I\IM OCSJ O\H\L\C4HOLCPCF\OUJV!FG!GOJ*LWOOH\:HL O-O\F\JXFGF:G J OJ\I\M\O\I OMCJJ"O[L\H\C2H LO3O\I\J\IJO@I\OTJDI:O JTV:V Z\[\^\Z[^AZ\^\[\![[MZ^^R[[H^^V[[M^$^\[^[R$[^\[A^[^\^[N"^\ [^G]\Y\BY ]TKT W\[X=W [.O\CO5[\U\V\U[V7T\X\TX[IXUT[O\[X T9O+R\V\S\ R$VSUUJ\"V\J UVJHVDJJ?VVYJJVVV<JV&P\Q[TYVTPQVTFP\QYT\V\8P QTV,VSO\SV1OSV:T\O\K\KL#LOT HCHT\M\Q\,MQTT>O\K\)LHK3OLT:H\T\PH TƒI\J[O[R\IJRO;IXJROUR\I$JRO*I\JWOUR\I RJOI\JSO\RTIXRJO#I\OXJ\R\"IJ OR$N\O\R\NRO H(HM\Q\DQM0J\M\$JK6'KMH?M\HQ\=MQJ\M[ KNJNK HKMHM\Q\@QM3K\O\$KL6'LOH?O\HR\=ORK\O[ LNKNL HKOHO\R\@RO0L\RZMXOXLAM ORZC\%CL\F\XFLL\Q\$LM6'MQM?Q\MT\=QTL\Q[ MNLNM MKQMT\Q\@TQ3K\N\$KK6'KNH?N\HQ\=NQK\N["KZHKNHQ\N\@QN(N\O[TTRYNOTRFN\R\OYT\8N OTR,M\TSQV1MQT@QXK\LU KoQ L%K\Q\LYKdENQLEJ\Q\=JQ!M\Q\$MM6'MQJ?JQ\T\=QTM\Q["MZJKQJT\Q\@TQ1VS$VY\VBYVY\YVO"Y\ VYGX\T\BT XOLO R\VY=R V7VXJ\-J V8H\T\JTRNHRHVT\IHR\T&RfP\Q[VTTYPQVTFP\V\QYT\8P QVT,O\VSSV1OSV‚-I\J\O\RYIJ RO/I\OSJYR\ IJRO.OUI\JYR\*I#RJO%O[AO I\R\JZOP$IO.RJOP#R\J\I\O-IJ R$O\CO5[\U\V\U[V7T\X\TX[IXUT[O\[X T9O+R\V\S\ R$VSJ\UU"V\J UJHVVDJJ?VVYJJVVV<JVV:V Z\[\^\Z[^AZ\^\[\![[MZ^^R[[H^^V[^[M$^\[^[R$[^\[A^[^\^[N"^\ [^G]\Y\BY ]TKT W\[X=W [‚!I\J\O\RYIJ RO/I\OSJYR\ IJRO.OUI\JYR\*I#RJO%O[AO I\R\JZOP$IO.RJOP#J\R\I\O-IJ R"P\V\TZQZPQVTAP\T\Q\VY%PQVT2OZVSST0OSV3N\T\RZOZNOTRAR\N\TYO\%NOTR2MZTSQT0MQT8C\O\7OC6I\MZJ\OZIOMJ>O\H\L\8HL O1O\I\J\I"OJI\>\ J\>I>CJJQ>J>>JO>>E JJ?0J> N\O[TTRYNOTRFN\R\OYT\8N ORT,TSM\QV1MQT8S\Y\WZTZSTYWAS\W\T\YY%STYW2RZYSVT0RVY;TXN\OU NoT O%N\T\OYNdHNTOHT\M\=MTMNLXR\O\LaMORTOLR\K[KL\UOR L0`\T\B` TuM\X\Y\MXMMYMYSMFYYYMMOYYKMM;YMK\N\$KK6'KNH?N\HQ\=NQK\N["KZHKNHQ\N\@QN0N\T\OZRZNOTRAR\N\TYO\%NOTR2MZTSQT0MQT;QXK\LU KoQ L%K\Q\LYKdENQLEQ\J\=JQ!M\Q\$MM6'MQJ?JQ\T\=QTM\Q["MZJKQJQ\T\@TQ(I\J[MYOTIJOMFI\JYM\O\8I JMO,OSH\LV1HLO@[\O\B[ OuH\S\T\HSHMTHTSHFTTYHHOTTKHH;THP\VUQYY\*P#YQV%V[AV P\QZY\VP$PV.YQVP#Q\Y\P\V-PQ Y'C\O\7OC6I\MZJ\OZIMOJ>O\H\L\8HL O1O\I\J\I"OJI\>\ J\>I>CJJQ>J>>JO>>E JJ?0J>C\O\7OC6I\MZJ\OZIOMJ>O\H\L\8HL O1I\O\J\I"OJI\>\ J\>I>CJJQ>J>>JO>>E JJ?0J>T\CT5`\Z\[\Z`[7Y\]\Y]`I]UY[T\`] Y9T+W\[\X\ W$[XZUO\"[\O ZOH[[DOO?[[YOOV[[<O[-I\J\M\O\I,JMOCCCOYLYH\9HLOCLCOYF\JX5FG8_GOJC\O\|LFOCL O\C\ECOP\Q[TYVTPQVTFP\QYT\V\8P QVT,VSO\SV1OSV@TXN\OU NoT O%N\T\OYNdHNTOHM\T\=MTƒI\J[O[R\IJRO;IXJROUR\I$JRO*I\JWOUR\I RJOI\JSO\RTIXJRO#I\OXJ\R\"IJ OR{V9V Z\[\^\Z[^AZ\^\[\![[LZ^^Q[[G^^U[[L^$^\[^J\M\$JK6'KMH?M\HQ\=MQJ\M[ KNJNK HKMHQ\M\@QM2N\O\R\NRO H(HM\Q\DQM-L\RZOXMXL#ORMOLR\K[KL\UOR L0YXS\TU SoY T%S\Y\TYSdMNYTMY\R\=RYpQ\K\H\KHQ_N?N KVH\Q\bQN\HK!NJN\T\RZOZNOTRAN\R\TYO\%NOTR2MZTSQT0MQT;X\]YW\W ]XX\]A]XX\]W]XX\]V]XW\]ZX\WX]XW ]@]XX\]\ ]X T\M\J\MJT_Q?Q MVT\J\bTQ\JM!QS\M\J\MJS_O?O MVS\J\bSO\JM!OQT\CT/Z\`\ [\Z!`[:Y\]\ Y]`C ]OYUTV`] Y:T*Y\]\Z\ Y$]ZQ\\V"]\Q \QK]]\QQL]]\QQY]]?Q]/RZ QIOCRL?QOJ[ LJVO\H\I\#IOHFZ'CYF0C?C\OCv+\L+O²@ÿ/MTrkU¶ÆÿJAZ2¶[({ ^d@]ÿGuitar–+K1W2M 1+ 272J+H*+2I4_+Z/+4C4Q+J44+B+I5b,+ 5?5^+L35+4I+H&+4E4`+R3+42L+`-2 +91j+]2[1+2>+D2F*+2I+\4d,+4G+-49*+ 4D2R+J62+@+G2H02++\4[+4T4_+S!++Z42a>2 +-0K7W(07M7F0:J0G80:0U9] 90D0b9K$090^7g.07G+d2M=2+$+I2L8+2<4_+W2+4@+G4T.+4G5l+R&+5K5a+P:+5+D4I%+4N4b+W$++02N442 +?6j0]7[60797F0D*07L9d0\,09?990-*09E5b?K-? 5>5G?J85?5U>] >5D5b>K$5>d,5>G>95-*5 >D3Y9[,93>3D9,*9&3b9Z3$39T3'9,$99Q33G*9 3H6j0]7[60797F0D*07L9d0\,09?990-*09G-L3X4N 3- 474K-I*-4I6`-[/-6C6R-K46-;9\2^,29>2_9b*29I9e2],29G9R2e*2 9D5m+S&+5K+Q5b:+54J+E%+4N+%4B$+2c4+;(+ 2D:K0b-: 0>0G:J80:9]0U 90D0b9K$097g0^.07M8j2]9[82999F2D*29L;d2\,2;?;92-*2;E2I1[+N 1+2?+G2G4+2<4[+U:4+:4Y+]14+D+J2P12+6+N2K@2 ++]4O&+4K+U4Y4+ +]2K'2+Q2I1[+N 1+2?2G+G4+2<+U4[:4+:+]4Y14+D2P+J12+6+N2K@2 ++]4O&+4K+U4Y4+ +]2K'+2Q0K7W(07M7F0d5\,5>G>95-*5 >D0d7M=70-7L0I807<9_0W209@9T0G.09G:R5R-:5::R5R15 :4R:RI:4+:14"$:4R4:R14 :;5b?K-? 5>?J5G85?5U>] >5D5b>K$5>5G5J+G8+54]+U 4+D4K+b$+42g+^.+2G:m0S&0:K0Q:b:0:9J0E%09N0X9N$07^01947 0;2L8X9N 82 979K2I*29I;`2[/2;C;R2K4;2=+K1W2M 1+ 272J+H*+2I4_+Z/+4C+J4Q44+B+I5b,+ 5?5^+L35+4I+H&+4E4`+R3+42L+`-2 +9+d2M=2+$+I2L8+2<4_+W2+4@+G4T.+4G5l+R&+5K5a+P:+54I+D%+4N+W4b$+2N+0442 +97I6[0N 607?0G7G407<0U9[:90:0]9Y190D0J7P17060N7K@7 00]9O&09K9Y0U90 0]7K'70Q+N2I1[ 1+2?2G+G4+2<+U4[:4+:+]4Y14+D+J2P12+6+N2K@2 ++]4O&+4K+U4Y4+ +]2K'2+Q9Q2KB2 9+9L2O=299P2U<298982'929L23(29;7M0d=70-7L0I807<0W9_209@9T0G.09G2I+N1[ 1+2?2G+G4+2<4[+U:4+:4Y+]14+D+J2P12+6+N2K@2 ++]4O&+4K4Y+U4+ 2K+]'+2V7Y0M(07H7H0>/70F0[9_%09L9N0C,09L5b?K-? 5>?J5G85?>]5U >5D5b>K$5>5^3D9,*9&9Z3b3$93T9,3'$99Q3G3*9 3B7M0d=70-7L0I807<0W9_209@9T0G.09G-d4M=4--4L-I8-4<6_-W2-6@6T-G.-6G5Y<[,<5><,5D*<&[#[VSV?[4S9NSV[@µ@ÿ/MTrk±³ÃÿJAZ2³ @]ÿMelody³[({“Ob+OOb:O8OH0LWOG J`‚J GPƒ4J9GJ ORrOGZAG JLiJC_,LbCAL H^,HKJO(JL^mLOLR1OfL>O QJ,QOP+O#La_L6JTlGFJ.GJRJOVDO4JVsJGV.GAEZ!E(EFE"EWi<tC\>uETCyFZEwHPFƒH-CH#C @QA@ @H,C^@=CCX(CE^mECa7CAFfAF CJ-EJCFECa_CzEDEHb:H GD/EWG>E CW4ENCƒE C\,H[C8H JW1LNJ&LNFNO`>O J^SJ$Jk‚JOe@O QRuQLVxOPLzJJOuJLRwGOL1GfHb:H JK(J LbxOYL&O$QbDQ4NgGN3LaoJOLvJ7Ob+OOb:O8OH0LWOG J`‚J GPƒ4J9GJ ORrOGZAG JLiJC_,LbCAL H^,HKJO(JL^mLOLR1OfL>O QJ,QOP+O#La_L6JTlGFJ.GJRJOVDO4JVsJGV.GAEZ!E(EFE"EWi<tC\>uETCyFZEwHPFƒH-CH#C @QA@ @H,C^@=CCX(CE^mECa7CAFfAF CJ-EJCFECa_CzEDEHb:H GD/EWG>E CW4ENCƒE C\,H[C8H JW1LNJ&LNFNO`>O J^SJ$Jk‚JOe@O QRuQLVxOPLzJJOuJLRwGOL1GfHb:H JK(J LbxOYL&O$QbDQ4NgGN3LaoJOLvJ7Ob+OOb:O8OH0LWOG J`‚J GPƒ4J9GJ ORrOGZAG JLiJC_,LbCAL H^,HKJO(JL^mLOLR1OfL>O QJ,QOP+O#La_L6JTlGFJ.GJRJOVDO4JVsJGV.GAEZ!E(EFE"EWi<tC\>uETCyFZEwHPFƒH-CH#C @QA@ @H,C^@=CCX(CE^mECa7CAFfAF CJ-EJCFECa_CzEDEHb:H GD/EWG>E CW4ENCƒE C\,H[C8H JW1LNJ&LNFNO`>O J^SJ$Jk‚JOe@O QRuQLVxLOPzJJOuJLRwGOL1GfHb:H JK(J LbxOYL&O$QbDQ4NgGN3LaoJOLvJÿ/MTrk3°ÿJAZ2ÿPositive Thrillÿ/simutrans-124.3/simutrans/music/39-bangin-mover.mid000066400000000000000000001240371474050137200222370ustar00rootroot00000000000000MThdxMTrkkÿCopyright (C)2007 shunterð~ ÷°ÿJAZ2ÿj'ÿ~jq A'@ A'@@'1 @'@ÿ~j@' @'+@@'ÿ~j@@1 @'@@1 @ÿ~j@@' @'@@'ÿ~j@@ @@@ ÿ~j@@@ @@ÿfj@@@ @ÿljÿXÿQÈÿYÿ Bangin' Moverÿ/MTrk³ÃÿJAZ2³[(]ÿMelody³p '{V“Cl3CB@a+>\ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@obCl@2C59sEo9GECou@OC&AV @dA@n…x@‚Cl3CB@a+>\ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@obCl@2C59sEo9GECou@OC&AV @dA>OC> ic>@iU@CiRC9i!8P9E89>*_9>A@\7@@CaFCAqA@\1@LElFEH_XH,V5>E@sJ@Ee>E5@g?@6>i‚f>(>YE>@R#@AkJA \ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@ob@Cl2C59sEo9GECou@OC&AV @dAI@ƒ">kEE„+E$C_2CC@OM@,@JI@y<.RC>7E[wEVGb-GIE[.CQEBC0@L2@FGU/GEEK6E@C\NC I@ƒ">kEE„+E$C_2CC@OM@,@JI@y<.RC>7E[wES;>AdDAME`5EHZ„6> @RT@>T‚C>)CY‚rCEa>E>@ƒO>Gb-GIE[.CQEBC0@L2@FGU/GEEK6E@C\NC I@ƒ">kEE„+E$C_2CC@OM@,@JI@y<.RC>7E[wETCl3CB@a+>\ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@obCl@2C59sEo9GECou@OC&AV @dA@n…x@‚Cl3CB@a+>\ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@obCl@2C59sEo9GECou@OC&AV @dA>OC> ic>@iU@CiRC9i!8P9E89>*_9>A@\7@@CaFCAqA@\1@LElFEH_XH,V5>E@sJ@Ee>E5@g?@6>i‚f>(>YE>@R#@AkJA \ @K6<4;f9Y;39E;i9;9i>@U-@ @o@@i2@A@obCl@2C59sEo9GECou@OC&AV @dAZ+29+Q2Z+ 2 2a+F+282\+_+2E;>0g7m0717S0K079d0U9069\0O09@Z=M4ZEO-Q-49-Q4Z- 4 -F4a-48-_4\-4=E@2Q9ZJOAMEZ2999Z2Q2 9 2F9a2982_9\29AJE2Z+Q;MEO>Z2+92Z+Q+ 2 2a+F+282\+_+2;E>0QCZJO7Z@M7097Z0Q0 7 7a0F0787\0_077Z0O07:7\0Q0 77_0Z0 767U0O077Z0M07;7\0X070\7a0 720Z7Z07 0U7\0790Z7\070Z7\:70 0a7a 0@J7C2X9X092Q\VZ2ZNX9O QNV29;\2\1;22O;\;22Z9aNXVZQ\ QNV 922U9Z922_;\0;2;\2K;2NOVS2\Q_9a QNVNHVFQO9QV2NNM2K9QQMVK VQN29VMQS;_NK2U QNVVHNKQQ Q;VN2VZN\2Q;\Q_ QNV2;VZQ\2\NX9\ QNVVSNMQZ 9QNV22KNO9\VUQX QNV292ZVUQXNO;_ QVNNOQUVM;2QNVQ\;aNU2UVZ QNV; 2JO2Q9ZAMEZ2999Z2Q2 9 9a2F2989\2_299Z2O29:9\2Q2 92Z9_2 969U2O29 AEJ2SCj+dGaGCGMCO 2+CGGH2XCQ+dCG +2 AZ4\EU+gEAEHAF 4A+EAF+_4_EHAE+4@_2g+_CO@CCK@M2 +@C+a@H2ZCK@C+2+mA_4_>\A>>KAO4A+>A\4m+u>ZA> 4+0g7m0710K7S070U9d0969\0O09EOM@2G1+<GCZJO7Z0Q@M7097Z0Q0 7 7a0F0787\0_077Z0O07:0Q7\0 77_0Z0 760O7U070M7Z07;7\0X077a0\0 727Z0Z07 0U7\0797\0Z070Z7\:70 0a7a 07@CJ9X2X092NXVZQ\9O2Z QNV29;\2\1;2;\2O;29aVZQ\NX2Z QNV 922U9Z922_;\0;2;\2K2;9a2\Q_VSNO QNVQOVFNH9Q2NVNMVKQM9Q2K QVN92QSNK;_2UVM QNVQQNKVH ;QVN2N\2Q;\VZQ_ QNV2;NXVZ9\Q\2\ QNVVSQZNM 9QN2VQX9\2KVUNO QNV92VUNO2ZQX;_ QVNNOVMQU;Q2NVQ\NUVZ;a2U QNV; 22QJO9ZEZAM9292Q9Z2 9 9a2F2989\2_299Z2O29:2Q9\2 92Z9_2 962O9U29 JEA+Q2Z>ZCO;M+29+Q2Z+ 2 +F2a+28+_2\+22Z+O+2:2\+Q+ 22_+Z+ 26+O2U+2 C;>+QCZ7Z@MHO7+97Z+Q+ 7 +F7a+787\+_+7CH@4Z-QEO@ZM@G12+G<_5X4>5>_5a5>M\5_H\E__5_1>55aM0>_5>M QXTO<_5aMQMQTTFMKQK <5QTMT>\V\RMVVDRFM< >5RMVVHRH>\MH5dR5VM>TXQX5_<\MXQMT5QHT8<M:QMTT6<\M<Q>5d Q <M5TV_M\5_>SR_RMVVHMMRH>5RMV>p5pVKRKMHRMV>5 9U92HM2XEFJU;Z%JE ;2H\C>2\;ZH;C29ZE@JU2U8292a9\EJ92;U2\4;2;d2a;22\9\7292_9_922a;_22;2_;g;2 9ZAMEZJO2Q9292Q9Z2 9 2F9a2982_9\299Z2O29:9\2Q2 92Z9_2 969U2O29 JEA;M>Z2ZCO+Q2+92Z+Q+ 2 2a+F+282\+_+22Z+O+2:+Q2\+ 22_+Z+ 26+O2U+2 ;>CJO@M7ZCZ0Q7090Q7Z0 7 0F7a0787\0_070O7Z07:0Q7\0 77_0Z0 767U0O077Z0M07;0X7\070\7a0 727Z0Z07 0U7\0797\0Z070Z7\:70 0a7a 0@JC72X9X0922ZQ\9OVZNX QNV292\;\1;2;\2O;2Q\2Z9aNXVZ QNV 922U9Z922_;\0;2;\2K;2VSNOQ_2\9a QNVVFNHQO9QVN2QM2KNM9QVK VQN29QS2UVMNK;_ QNVNKVHQQ Q;VN2;\Q_N\VZ2Q QNV2;Q\2\9\VZNX QVNVSQZNM Q9N2VQXVUNO2K9\ QNV92NO2ZQXVU;_ QVNNOQUVM;Q2VN2UQ\;aNUVZ QNV; 29ZAMEZ2QJO9292Q9Z2 9 9a2F2989\2_292O9Z29:2Q9\2 99_2Z2 962O9U29 JEA2d+\)2+%+_2O+2 +a4_-4++a4a+42\+ZAUFQ,2FA+>K2\+_CU+24_+\04++a4\+4 C>0g7m0710K7S070U9d9069\0O09@Z-Q4ZM@2G1+G<7a0d2700_@Z7ZHUC\C07@H 9_0X4909_0a900_H\C\@_7ZC@H70#0\7X700_9_1909_H00a09H 0a7_HQLXOOHLOLKOFHK 70LOHO>H<LH0_7X7OH0L9\Q\M_H\0_MHQQDH<MF 90MHQQH0dHH9\MHMQ90H7\OX0_HXLXLHO0O8H:7LHLHOO60d7\L>H< L HO70H\9SQ_M_0_MHQQHHMMH90MHQMKQK0p9pHHMHQ90 9_2\/92 2Z9Z29 J\;_EZ2Z.;EJ22\;\JOEK;J2E 2XMZHK9_)MH922Z9UM:H>92HM2X;ZEFJU%JE ;2H\;Z2\C>HC2;JUE@2U9Z8929\2aJE922\;U4;2;d2a;29\2\7929_2_92;_2a2;22_;g;2 9ZAMEZ2QJO2999Z2Q2 9 2F9a2982_9\299Z2O29:2Q9\2 92Z9_2 962O9U29 AJE2Z;M>Z+QCO+292Z+Q+ 2 2a+F+28+_2\+22Z+O+2:2\+Q+ 2+Z2_+ 26+O2U+2 >C;@MCZHO7Z0Q7090Q7Z0 7 0F7a0780_7\07CH@-QM@G12+G<0d7a2077Z@Z0_C\HUC07@H 9_0X4909_0a907ZC\@_H\0_C@H70#0\7X700_9_1900a9_H009H 7_HQLX0aOOHLOLKOFHK 07LHOO>H<LH0_7X7OH0L0_9\H\M_Q\MHQQDMFH< 90MHQHHMHQH0d9\0MQ9H7\0_LXOXHXLHO0H:O87LHLHO7\H<O60dL> L 7O0H0_M_9SH\Q_MHQQHHMMH90MHQQK0p9pHHMKMHQ90 JO2Q9ZEZBM2992Q9Z2 9 2F9a2982_9\299Z2O29:2Q9\2 99_2Z2 962O9U299Z2M29;9\2X299a2\2 929Z2Z29 9\2U2992Z9\292Z9\:92 2a9a 2J9EBJO2QAMEZ9Z9299Z2Q2 9 2F9a2989\2_299Z2O29:2Q9\2 92Z9_2 962O9U29 EJA;MCO+Q>Z2Z+292Z+Q+ 2 +F2a+282\+_+22Z+O+2:2\+Q+ 2+Z2_+ 262U+O+2 ;C>7ZHO@M0QCZ0790Q7Z0 7 700F9a7 0989\0_09@CHEO-Q4Z@ZZ2+92Z+Q+ 2 2a+F+282\+_+2>;C5d_5X4>5>_5a>55_H\_1>55a>_M05>M <_TO5aMQQXMQTQKTFMK 5<QMTQH5_M<<QM5T>\R_M\5_V\RMVM<VDRF >5RMVVHMHRH>\5dRV5>MMX5_<\QXTXQMT5QHM:<T8QMT5dQ>M<<\T6 Q T<5M>S5_M\V_R_RMVMMRHVH>5RMVRKVK>p5pMHRMV>5 OO5Q2Z92HMJU2X;ZEF%JE ;2H\;Z2\C>H2;CJUE@2U9Z8299\2aJE922\;U4;2;d2a;29\2\7292_9_922a;_2;22_;g;2 AMEZJO2Q9Z2999Z2Q2 9 2F9a2989\2_299Z2O29:2Q9\2 99_2Z2 962O9U29 EJA;M>ZCO2Z+Q+292Z+Q+ 2 +F2a+282\+_+2+O2Z+2:2\+Q+ 2+Z2_+ 26+O2U+2 >;C0d7a2077Z@ZHUC\0_C07@H 0X9_4909_0a90@_0_C\H\7ZC@H70#0\7X700_9_1909_H00a09H OOLX7_HQ0aHLOLKHKOF 07LOH7XO>LHH<0_7LO0H9\Q\0_M_H\MHQQDMFH< 90MHQQH0d9\HHMHH0QM90_HXLXOX7\LHO0O8H:7LHLHO0d7\L>O6H< L 0H7OH\9SQ_0_M_MHQQHMHHM90MQHMK9p0pHHQKMHQ90 9X2X092Q\2ZNXVZ9O QNV29;\2\1;2;\2O;2NXVZ9aQ\2Z QNV 929Z2U922_;\0;2;\2K;2Q_VS2\NO9a QNVNHQOVF9Q2NVQM2K9QVKNM QVN29NKQS;_2UVM QNVNKQQVH Q;VN2N\;\2QQ_VZ QNV2;9\VZQ\2\NX QVNQZNMVS 9QN2V2KVUNO9\QX QNV922ZNO;_VUQX QVNNOQUVM;Q2VN;a2UNUQ\VZ QNV; 2AMJO2Q9ZEZ9299Z2Q2 9 2F9a2982_9\292O9Z29:2Q9\2 92Z9_2 969U2O29 AJE>Z2Z+Q;MCO2+9+Q2Z+ 2 +F2a+28+_2\+2+O2Z+2:2\+Q+ 2+Z2_+ 26+O2U+2 >C;+Q7ZCZHO@M+797Z+Q+ 7 7a+F+78+_7\+7@HC-Q4ZZ;MCO2Z+29+Q2Z+ 2 +F2a+28+_2\+2>;CJO7Z@MCZ0Q7097Z0Q0 7 7a0F0787\0_070O7Z07:7\0Q0 77_0Z0 767U0O070M7Z07;0X7\077a0\0 727Z0Z07 0U7\0790Z7\070Z7\:70 0a7a 0C@J7RB\J\E_,EBJyB\J\E_%EJBDB\JZE_EBJ!BZEdJ_!EBJTVpK2\+24_+\04+4\+a+4 >C0QHO@M7ZCZ0797Z0Q0 7 0F7a0787\0_07HC@EOZ2Z2+9+Q2Z+ 2 2a+F+282\+_+2;C>@M0QCZJO7Z7090Q7Z0 7 7a0F0787\0_077Z0O07:7\0Q0 77_0Z0 767U0O070M7Z07;0X7\077a0\0 727Z0Z07 0U7\0790Z7\070Z7\:70 0a7a 0C7J@RJ\B\E_,EJByB\E_J\%EJBDJZB\E_EBJ!BZJ_Ed!EBJTVp\4_A_A>>KAO4+A>>ZA\4m+uA> 4+@M7Z+QCZHO+797Z+Q+ 7 +F7a+78+_7\+7H@CEO@ZM@G12+G<5d_4>5>_5a>55__1>55aM0>_5>M TO<_MQ5aQXQMTQKTFMK 5<QMTM<5_QHT>\V\5_RMVRFVDM< >5RMV5d>\VHMHRH5MV>R5_TX<\QXMXQMT5M:T8<QHQMTM<5dT6Q><\ Q <5TMR_5_M\V_>SRMVVHMMRH>5RMV5pMHVKRK>pRMV>5 _5X4>5>_5a>5M\E__1>5M05a>_5>M 5aQXTO<_MQMQTQKMKTF 5<QTMM<5_T>\5_V\M\RMVRFVDM< >5RMVMHRH5d>\VH>RMV5MXTX5_QX<\QMT<T8M:5QHQMTQ><\T65dM< Q <5MTV_>S5_R_M\RMVRHVHMM>5RVM5pRKMH>pVKRMV>5 9X2X0929OVZ2ZQ\NX QNV29;\2\1;22O;\;2NX2ZVZ9aQ\ QNV 929Z2U922_;\0;2;\2K;2NO2\9aQ_VS QNVVFNHQO9QN2VNMVK9Q2KQM QVN29VM2UNKQS;_ QNVQQNKVH ;QVN2Q_VZ2QN\;\ QNV2;2\VZNX9\Q\ QNVQZVSNM 9QNV2VUQX2K9\NO QNV92VUNO;_2ZQX QVNVMQUNO;2QVNVZ2UQ\;aNU QNV; 2JO9Z2QAMEZ9292Q9Z2 9 9a2F2989\2_299Z2O29:9\2Q2 99_2Z2 969U2O29 JAE2ZCO;M+Q>Z+292Z+Q+ 2 +F2a+282\+_+2+O2Z+2:2\+Q+ 22_+Z+ 262U+O+2 C>;JO0Q7Z@MCZ0790Q7Z0 7 0F7a0787\0_070O7Z07:0Q7\0 70Z7_0 760O7U070M7Z07;7\0X070\7a0 720Z7Z07 0U7\0797\0Z070Z7\:70 0a7a 0C7@JRJ\B\E_,EJByB\E_J\%EJBDJZB\E_EBJ!BZEdJ_!EBJTVp\A_4_A>AO>K4A+>+u4m>ZA\A> 4+0g7m0717S0K079d0U0960O9\094ZM@2G1+G<JXCa@\ @JC,CU@KJO@CJAZJXE\"EAJ,AHJHEMAJECa@\JZ*C@J%@HCOJM@CJJZE_AU"EJA*JXASE_JAE@ZJZCa|C@JHO_VXL\iOLV+²@ÿ/MTrku¶ÆÿJAZ2¶@[(ÿGuitar¶{ ^U]–0I7I!077*7 0I9I#099/9 -:7I!-7R7I-:#7-W2I9I!299*9 2I;I#2;9/9 2I+I!+22*2 4I+I#+42/2 7I0I!077*7 9I0I#099/9 7I-:!-77*77I-:#-77/7 9I2I!299*9 2I;I#2;9/9 +:5I!+55*55I+:#+55/5 7I0>!077*77I0>#077/77I0>%707*77I0>!077'77I0>%077/!70>7I"707870>7I%707, 77I0>2077"7-:6I!-6R6I-:#-6T6I-:%6-S6I-:!-6Q6I-:$6-T-:6I!-6S-:6I%6-S6I-:2-6D9I2I!299*9 ;I2I#2;9/9 2I!077*77I0>#077/70>7I%707*77I0>!077'77I0>%077/!70>7I"707877I0>%707, 77I0>2077"72>9I!299*99I2>#299/92>9I%929*99I2>!299'99I2>%299/!92>9I"929892>9I%929, 99I2>2299"92I9I!299*9 ;I2I#2;9/9 2IP5P#5>>6> 5PP5P!5>>.>P">5>?>P5P25>>)>5PP5P#5>>6> 5PP5P!5>>.>P">5>?>5PP5P25>>)>2D9P!29R9P2D#92T9P2D%92S9P2D!29Q9P2D$92T2D9P!29S2D9P%92S9P2D229D2P9P!29919 2P;P#2;969 2P6I!266*66I2>#266/66I2>%626*66I2>!266'66I2>%266/!62>6I"626862>6I%626, 66I2>2266"62I9I!299*9 2I;I#2;9/9 2I!29R9I2>#29W5I+:!+5R5I+:#5+W7P0P!07717 0P9P#09969 0P7P@077179P0P!099.97P0P%0776!70P9P"909?90P7P%7073 79P0P2099)99P2P!29919 2P;P#2;969 2P!07R7I0>#07T0>7I%70S7I0>!07Q7I0>$70T0>7I!07S7I0>%70S7I0>207D2>6I!26R6I2>#26T6I2>%62S6I2>!26Q6I2>$62T2>6I!26S2>6I%62S6I2>226D2I9I!299*9 ;I2I#2;9/9 2I!29R9I2>#29W5I+:!+5R5I+:#5+W7I0I!077*7 0I9I#099/9 0I7I@707*79I0I!099'97I0I%077/!70I9I"909890I7I%707, 79I0I2099"92I9I!299*9 2I;I#2;9/9 2I!299*99I2>#299/92>9I%929*99I2>!299'9 5I+:!+5R5I+:#5+T5I+:%5+S5I+:!+5U7I0I!077*7 0I9I#099/9 -:7I!-7R7I-:#-7W9I2I!299*9 ;I2I#2;9/9 +I2I!+22*2 4I+I#+42/2 P5P#5>>6> 5PP5P!5>>.>P">5>?>5PP5P25>>)>5D9P!59R9P5D#59T9P5D%95S9P5D!59Q9P5D$95T5D9P!59S5D9P%95S9P5D259D2P9P!29919 ;P2P#2;969 2P!26R6I2>#26T6I2>%62S6I2>!26Q6I2>$62T2>6I!26S6I2>%62S6I2>226D9I2I!299*9 ;I2I#2;9/9 2Id;d9d2d+d‰0Bd=d9d4d/dp/=;9B2>9B+4pBd>d9d6d/dp/9B>6@d>d;d4d2d+d‡ °[] ‡v+>;@24Bd>d;d9d2d+d‹ +>;B29Bd=d9d4d/dƒ`/9B=4+d2d4d;d>d@d@24+>;Bd>d;d9d2d+d‰0Bd=d9d4d/dp/=;9B2>9B+4pBd>d9d6d/dp/9B>6@d>d;d4d2d+d+>;@24Bd>d;d9d2d+d‹ +>;B29Bd=d9d4d/dƒ`/9B=4+d2d4d;d>d@d@24+>;-d4d7dd;d9d2d+d‰0Bd=d9d4d/dp/=;9B2>9B+4pBd>d9d6d/dp/9B>6@d>d;d4d2d+d+>;@24Bd>d;d9d2d+d‹ +>;B29Bd=d9d4d/dƒ`/9B=4+d2d4d;d>d@d@24+>;Bd>d;d9d2d+d‰0Bd=d9d4d/dp/=;9B2>9B+4pBd>d9d6d/dp/9B>6@d>d;d4d2d+d+>;@24Bd>d;d9d2d+d‹ +>;B29Bd=d9d4d/dƒ`/9B=4+d2d4d;d>d@d@24+>;-d4d7ddƒ`>2+d7d‡@7+2d>d‡@>2-d9d‡@9-2d>dƒ`>24d@d‹ @4Cd7d‡@7C-d9d‡@9-0ddƒ`>2+d7d‡@7+2d>d‡@>2-d9d‡@9-4d@d‡@@47dCdƒ`C7‹ !d9d-d‹ -9!’`!d!QdEd9d9EQOdCd7d7COLd@d4d4@LQd9dEd‡@E9QTddƒ`>2+d7d‡@7+2d>d‡@>2-d9d‡@9-2d>dƒ`>24d@d‹ @4Cd7d‡@7C-d9d‡@9-0ddƒ`>2+d7d‡@7+2d>d‡@>2-d9d‡@9-4d@d‡@@47dCdƒ`C7‹ !d9d-d‹ -9!’`!d!QdEd9d9EQOdCd7d7COLd@d4d4@LQd9dEd‡@E9QTdd;d9d2d+d‹ +>;B29Šjµ[] b¥v•Bd>d;d9d2d+d‡@+>;B29¬@4d-d7ddCdGdLd…PL9>-GC˜04d-d9d>dCdGdLdLC-94G>¼-d9d@dCdHdLd…PL9@-HCò0@dd;d9d2d+d‹ +>;B29°`Bd>d;d9d2d+d‡@+>;B29¬@4d-d7ddCdGdLd…PL9>-GC˜04d-d9d>dCdGdLdLC-94G>¼-d9d@dCdHdLd…PL9@-HCò0@ddCdGdLd…PLC9>G¶09d>dCdGdLd…PLC9>G¶09d>dCdGdLd…PLC9>GÆ`NdIdXdSdpSNIXpZdJdNdSdpSZJNSdZdJdLdpLSZJpSdNdZdJdxJSNZ±XNdIdXdSdpSNIXpZdJdNdSdpSZJNSdZdJdLdpLSZJpSdNdZdJdxJSNZ˜hBdUdQdLdGddCdGdLd…PLC9>G¶09d>dCdGdLd…PLC9>G¶09d>dCdGdLd…PLC9>Gÿ/MTrk&[ÿSintÇQ·Z e©6Z e[]¯T[] eKáv—9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;CÄt9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cˆt9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C‚´t9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;CÄt9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cˆt9d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cƒ$7d;d>dCdJd7;C49d@dCdHdLddCdJd7;C47d;d>dCdJd7;C<7d;d>dCdJd7;C‚,7d;d>dCdJd7;Cÿ/MTrkIÿSolo 01È0¸n m©6n m[]Ÿ˜NdBdpBNLd@d…P9dEdxE9x@LNdBd‚,LdBN@d‚,L@>dJdv¸[] mn6˜>DdId=dJ‚EdJdD=I>d‚,EJ>@dGdLd‚,@@dBd9dEdLG‡,9BE@Ed9d 9E;dGdxId;=dG =IJd>d >J@dLdxId@=dLxI=BdEdJd>d‡@>BEJ9dEdxE9NdBdxBNJd>dx>JLd@dx@LJd>dx>JId=dx=IBd6dx6B@d4dx4@6d;d>d‹ >;6ƒ`9d=d@d4d‡@49=@;d>dBd6d‡@6;>B>d@dEd9d…P9>@EpEdJd>d…P>JEBdId=dx=IB@dGd;dx;G@;d>dBdEd9d…P9B;>E½0Ed9d-d-9ECd+d7d7+C@d(d4d4(@TdHd0dd&d2d<2J>&dx>VJ2xTdHd0ddx>VJ2xXdLd4d@dp]dQd9dEdx@4XL‚h]EQ9[dOd7dCd‚,XdLd4dC7[O@d‚,4LX@dx>VJ2xXdLd4d@dx@XL4x[dOd7dCdxC[O7x]dQd9dEdxE]Q9xXdLd4d@dx@XL4x[dOd7dCdxC[O7x]dQd9dEdxE]Q9xXd@dLdxL@XxTddx>2JHd0dd&d2dx2J>&Ld@d(d4dx4L@(OdCd+d7dx7OC+Ld@d(d4dx4L@(OdCd+d7dx7OC+QdEd-d9dx9QE-OdCd+d7dx7OC+QdEd-d9dx9QE-SdGd/d;dx;SG/QdEd-d9dx9QE-SdGd/d;dx;SG/TdHd0ddx>VJ2XdLd4d@dx@XL4[dOd7dCdxC[O7ÁNdBdpBNLd@d…P9dEdxE9x@LNdBd‚,LdBN@d‚,L@>dJd‚,>DdId=dJ‚EdJdD=I>d‚,EJ>@dGdLd‚,@@dBd9dEdLG‡,9BE@Ed9d 9E;dGdxId;=dG =IJd>d >J@dLdxId@=dLxI=BdEdJd>d‡@>BEJ9dEdxE9NdBdxBNJd>dx>JLd@dx@LJd>dx>JId=dx=IBd6dx6B@d4dx4@6d;d>d‹ >;6ƒ`9d=d@d4d‡@49=@;d>dBd6d‡@6;>B>d@dEd9d…P9>@EpEdJd>d…P>JEBdId=dx=IB@dGd;dx;G@;d>dBdEd9d…P9B;>E½0Ed9d-d-9ECd+d7d7+C@d(d4d4(@TdHd0dd&d2d<2J>&dx>VJ2xTdHd0ddx>VJ2xXdLd4d@dp]dQd9dEdx@4XL‚h]EQ9[dOd7dCd‚,XdLd4dC7[O@d‚,4LX@dx>VJ2xXdLd4d@dx@XL4x[dOd7dCdxC[O7x]dQd9dEdxE]Q9xXdLd4d@dx@XL4x[dOd7dCdxC[O7x]dQd9dEdxE]Q9xXd@dLdxL@XxTddx>2JHd0dd&d2dx2J>&Ld@d(d4dx4L@(OdCd+d7dx7OC+Ld@d(d4dx4L@(OdCd+d7dx7OC+QdEd-d9dx9QE-OdCd+d7dx7OC+QdEd-d9dx9QE-SdGd/d;dx;SG/QdEd-d9dx9QE-SdGd/d;dx;SG/TdHd0ddx>VJ2XdLd4d@dx@XL4[dOd7dCdxC[O7ÿ/MTrkIûÿBateriaÉ ™%0ƒ`%%ƒ`%%0ƒ`%%ƒ`%1o$Ft*py***A1/*B$7*p$n * *e*pw*,**n*pF$1*p$e*d*p*c**j**=$0$~*o**n*x* **a**?$1*p$p *m*px***l*+$M*p$x**g*.y*! **f*#4$D*p$`* *f* *o* *q*6$A*p$l **¹ @[]d™*z***o*E$4*p*$F *l*v*% **h**$M*j$t**b*y*** *f*p-$L*p$e* *e*pw* **l**@$0$~**pv*y***q*p*>$/&p*p$p*m*&Oy*** *&V&* *&P9$5*h$x*q*x* * *&J* *2_:$.*o$`*2z2U*p2o*< **k*2*/&$I*p$l /{/;2* *c1v**&O*n*<$/4*p$F* *31.*-&M* **_* *'$G*k$t&t6q*n*x*-*a*%&**&o68$6*i$e*m*y***&M*! *1$:$|*p*s*x**d* * * $@*k$p*o*x*% **e* *:$4*p6s$x&x*m*!w* *a**&&p *46$-*d$`v*&?*&*j*p *l*#0$G*o$l&l*&6l*m*x****n* *#&$6*j$C*p* y*!*b*# * *6$1*m$t&t6qq**j*(*e*1&*&o*8$ 6)*p$d*n*w* **"&M*2*@$-$|*m *n*'x*#* *g*<>$:*p$p**a*#x* *k*&* *:$0*p$x6r&xu*!*j*? * *d*5&&p*'$6-*p$`*q*&?&n*5*u*)* *2$4*n$l&l&6to* *c*3* *e*9*!&$-6*p$F*p*0x***d**9I$.*p$t&t6rs*!*r*% **f*)&&o*0$6%*p$e*k*/ *p*.*$&L*3$B$~*k**l*t*2*f*3**$F*p$p*o*7w*-**n*/G$0*p$w&x6q *e*'**d*-*q*&&p*@$-*k$`6o*0&?&*a*<* *e*: *$P*p$l&l&6lq** *j*y***&!$6 *p$F*r*5x*2 **i*0D$4*p$t&t6t * *c*9t* **b*&*&o7$68*p$ev*2**b*3,&L****$@$|*p *p*'w** *o*!G$1*p$p**n*x* **n*&* $R*p$x6p&xq**x* **g*&&p*6$67*p$` *m*#&?&o* **d*! *&&@0$@*a$l6p/yp* *h1b*&&O*m*8*($/6*p$F**710*+&K* **g*> *C$**W$t&t6kq*&*d***d*5&&o*!$6M*p$es* *d*6**"&L*8*>$0$~*px*& **h**q*( * $L*p$pw*( *j***q*A *:$6*p$x&x6n*m*x*&**m*&*&p5$¹[] @4™6*p$`*k*&?&o***a**/D$2*j$l&l&6sq* *m* **f*7*%&$ 6)*j$Fu*,*q*2 **f*0 *$W*p$t&t6qq**p*** *b*7&*&o6$G*p$es*"*i*,**!&L*1 *?$,$~*p*t*x*&**l**F$1*p$pr***p* *p**<$3*p$x&x6qq* *d** *c*#&&p*@$-*p$` 6i*5&?&*`* **m**0$A*p$l&l&6n*o*/w* * *e*# *&$&6*p$F*q*y*** x*& *B$-*p$t&t6kq* *o* **k*&&o*=$1*p$d6g*'*b***&M**7$8$|*gx*$ *m*#**k* *;$2*p$pw**u* **l*,9$>*p$x&x6s *d*:**n*!x**&&p*6$2*p$`v*6&?&*h* **e*+ *<$3*p$l&l&6lp*)* *g**n* *&"$6*k$Fu*0*u***n*+*I$&*p$t&t6nr* **l**q*&&&o*76$4*p$ev**b*( **&L*/6$?$~*p**p*x*$**d*&Z*8$3&p*p&$ps&&O*%*g* * *j&**&P4$<*p$x&x6n&l&;*.&*d* * *b* *2x 60$-*p$` 2q&X**e2*7*2v *2\** */$@*p$l6o2%2F* *i1~**-*&On**&6$4*p68$F2>1/* * &M*66* *d*, *:6 $)*p$t&t6ps*1*v*+66* *(6?*3&*&o%$J*l$e6%$6Q*8*c*p6 *6&L** *-$!6$~&~*m6pu*,*p60*+6**l*0!&%$2*p*$p67*6H*)t6*=6$ * *a**9$68*p$x&x6p*t**p*66; * 6`*+&*&p*$D*p6*$`96=*-&?&*E6$*2*6@*c**C$/*p$l&l6p&6d* * *H6*6**m*** &$6 *j60$Ft*$*a*06# **6V* *0$%6*p$t&t6pu**e6*6*6) *h*'&&o:6$1*o$e68**j*U6$*1*6-*&M**H$ 6$~&~*p6pu*!**l*$66&*q* * &$$0*p$p6%6b**g*6,**'6I* *6$9*k$x6p&x96<**_*=6.*6 *h*+&*&p7$6.*p$`6!v*&?&*;60*'64**j**=6 $)*p$l&l6p&s*3* *M6*0*6Ev*; *&$8*p$E6+6f*3*_6*6 **i*: *7$7*p$t&t6p*6S*\6*6D* *a*&*&oC$6*l6+$eu**s* 6* *6&M*H*9$ 6+$~&~*p6p*q*0i6*$6<**a*#*&$P*p$m6-6V**q6!*2**6P*3 *$!6,*p$x6p&xu* **g*56B*.6@*!&&p*A$,*o$^6*6Y*&?&* *B6!**6>u*$^*p$j6p&l&* 6Y*#*169*=66* *a* &&$06*p$F* * 6T*( *p*6"*#6L*(*J$+*p$r&t6p:6;*( *665*69*s*(&&o* *8$ 6&*p$b6*o*+}*-6 * *&6E*3F$6$}&~*p6p **h*9M6(&&\*6 **i*4*.p;$6"*p$p65v*-*&-.%*6*&K* *6F*+ *4$ 6*p$n&x6p&p&;**'&J6+**61* *c&* &p?6$**p$`6& 2*k*-*2s *2=6*6#*#&J**5 2{3$28*p$j6p262;* *F61~**'6 &O*a* K$.*p$F**2;1,*-*6&L*y*2**=$2*j$q *n*7x* **n*+*:$>*n$bs*:*f***j*E *@$*${*p *o*u*3 **o*A5$C*p$n**d*Cx***p*$*6$6*p$u*r*%x****e*4*E$-*p$\v*! *n*3**l*) *C$,*p$i*q*"y***a*# *&$G*p$Ct**b***r**@$1*p$ox*-*b*/ **l**+J$,*p$ev*4*b*6* *m*2*H$($~*pv*2*c*E* *f*+ *9$7*p$ow*0 * *f*u**; *8$5*p$ww* **a**u* **$A*p$_v*$**h*"*p*1$E1~*p$l&l*g*#**n**C10*#* &$66*k$F;69* 6 * *F6*/6*h6*6 *@$66p*p$t&tu6*5* *a6* *6 6E*1&6 *&o36 $6*p$b6/t*6 **:66 *0*6&+&)6$*?6*=$2$~&~*p6pF6-*$6 * *+66*96*o*36*&$666*p$nv*!6*366*)6*o**6 *5$3*p$w&x6p 6A66**P66*6**p*&6*&p$W*p6$`6 6j*=6 &?&*d6*6(* *%6<*?6 *1$F*p$k&l66p&*6a*;6 m6 *+6 6 *d*/6* *&$66*p66$Fu*06 **f6*+ *606:**+6 H$,*p$t6&t6p6_*96**I6"66*&*S6**5&6&o@$/*p6$e56A*76 *666*p6* *&6 6%*D*6?$2$~&~*p6p!6T*6 *5686*6**b*?*6 &!$66 *p$p6t6 *' **g*06*66c*6 8$ 66*p$u6p&x**f*86*F6 6 *6v*.6 &&p**$6$6&*p$]6 u*76&?&*m*6 ** 6'6;6*+$ 6+*p$l&l6p& *6`*66**@6-66**u*&6#& $F*p$F66*6X**;6t*6& * *66@*86*D$&*p$q&t6p6 6W*"6*X6 6 * 6&**n*!&6&o*A$,*p$d666O*96 6*B6 *6$* *&M*#6*3$6,$~6p&~*p-6K**6*Q6*66 * *g*36&$P*p$p68*66D*96 *U6*6**6^*"6*B$,6p*p$x6&x,6I*6*]6 *6$* *6R*&6*&p9$666*o$^O6'*6&?&* *c*6*76<*56C$6 *p$l&l6p&*6Z*26 *36+6 *6**k6*)'&$@*k6$F** 666:*%6 e6*6* *d**!6B$3*j$t&t6p6"6B*6 *g* 66* *6\* &6&o*3$:*p$`6*66J*76*C6/*'6*6*&K*=62$A$~&~*n6p**66a*(6 D64*6* *!6B*&6*&"$6*p$p6*%6O6*7&I* *g*6&K!6 6H*;&6&&P**2$6*p$x6p46B*26*2t *`* 6*2e66 &27*A*6 62l.2 $3*p$`6s*6/b* 6 6656***/x*:/2*866$7*l*$k6p*/z>/3*966g61~*p6*&O*6Q*,6*@6$6*p6$E /;10*6** &D6 * 66 *m*36 *>$.*k$t&t6p66M**6k6**"6 *6Z*5&6 &o;$ 6 6*p6 $b **g*26=665*6**'&K*6 *4$6${&~*p6p 6&6B*46 *e6*(6 * *6N6*#*6&$$(6 *p$p6*m* 6)6K*/6 **6J*)6 *6<$%6*p$t&x6pt*!6*e*"6 **66=6*"&&p&$66*p6$[*+6C*6 &?& *!66&* 6* *062*'6 H$,6p*p$i&l&*36/*'6*c*46* * 66A&Q*%&6*#$$6#6=*p$@.v*p*6 ,.666* 6 * &V*36* *4$&6*n$n6&t6pt6*6 *\66*6 * *c*0&6 &o*4$6"*p$`6+96<*6*b*#6)*6*&G6*-6 *76 $($x6&~*p6p*t*6 `6*p6 *(66&* 6 **&$$3*p$m6*/6D*6q6*6**6l*6*@$6**p$x&x6p 6j**6 <606**6 *m*!6&*6&p<$3*k$`6*a66* 6 &?*&*e*6*6a*D6*+$E6*j$e&l6p&56?*;6 *069*"6*6*l*$6 *&6$-*o$F6*16=*&626B* *6*%6I*'6 *666$4*p$t&t6p*p*6A62*6**6O*&&*6&o=6$6*p$d60t*;6*t*%6* *6& 6B*%6*,$A$~&~*p6p6m6*C6* *L66 * *6Q*66*$ &'6(6*p$p6'p**36*%6?*6*6X*-6*?$0*p$t6p&x66V*6 *_66*6**]*5&6 &p*+$B*p$`6/66&6**6 &?&n*"*6.*6#6-*46*9$7*p$k&l6p&6^*#6 **D6+*6 *#6N***6#&$$+6-*p$F6 6[6 *7**266*p6-U6 **6 * *=$**p$t&t6p6W6*#* *T66*p6t6*?&&o**:6$.*l6"$e6]6*-6*'69* 6* *&M*6 ?$!6$~&~*p66p*f*66 * *`6 *"6$ *6e6 * *&%$6 6*p$l6%o*&O*7 *Z6*6)*m&*0*6&P1$?*p$u6p66F*6**2z>6,*7636&K* 6*2 *0$2,*p$`6>6[*-6*6/~ 26+6**60 *k*+6! */t6 $6/$*j$i6pt*5*6 /*5/'6 **6A/v6-/)*86*/v+$ /601v*p6:$F*6V*&6 06/B6*6-* *116*C6*6$;*p$t&t6p*o6*6R6 6* * *6J*4&6 *&o(6$2*p6+$e 6i*6 *]66 *6 * *&J6**,6$68$~&~*p6pv*)6 *+67*6**6X*6 *&$'6*l$p6,&6O*6*.66-*(6"* *b*6*&$>6 *p$r6p&x*6g6 *x*+6% **66P*6 &&p*<$6-*l$_6%,6J*)6&?&*6T*6(* *f*26*6$'6-*j$l&l6p&*/6=*46h6 *.6(**26;*6*!&$2666W*p$Ft6 *2*D60*6* *"6?**/6G$6 6 *m$q&t6pv*56*+6868*+**6B*&6&o*:$4*p*6$$b6"6+6*;6 r*16/6**&M*#6L$ 6$~&~*p6p **!6E*,6 *Y6&*6'*-6C*6*1$66&p*p$pu*&O *m*** *&V&* *&P9$5*h$x*q*x* * *&J* *2_:$.*o$`*2z2U*p2o*< **k*2*/&$I*p$l /{/;2* *c1v**&O*n*<$/4*p$F* *31.*-&M* **_* *'$G*k$t&t6q*n*x*-*a*%&**&o68$6*i$e*m*y***&M*! *1$:$|*p*s*x**d* * * $@*k$p*o*x*% **e* *:$4*p6s$x&x*m*!w* *a**&&p *46$-*d$`v*&?*&*j*p *l*#0$G*o$l&l*&6l*m*x****n* *#&$6*j$C*p* y*!*b*# * *6$1*m$t&t6qq**j*(*e*1&*&o*8$ 6)*p$d*n*w* **"&M*2*@$-$|*m *n*'x*#* *g*<>$:*p$p**a*#x* *k*&* *:$0*p$x6r&xu*!*j*? * *d*5&&p*'$6-*p$`*q*&?&n*5*u*)* *2$4*n$l&l&6to* *c*3* *e*9*!&$-6*p$F*p*0x***d**9I$.*p$t&t6rs*!*r*% **f*)&&o*0$6%*p$e*k*/ *p*.*$&L*3$B$~*k**l*t*2*f*3**$F*p$p*o*7w*-**n*/G$0*p$w&x6q *e*'**d*-*q*&&p*@$-*k$`6o*0&?&*a*<* *e*: *$P*p$l&l&6lq** *j*y***&!$6 *p$F*r*5x*2 **i*0D$4*p$t&t6t * *c*9t* **b*&*&o7$68*p$ev*2**b*3,&L****$@$|*p *p*'w** *o*!G$1*p$p**n*x* **n*&* $R*p$x6p&xq**x* **g*&&p*6$67*p$` *m*#&?&o* **d*! *&&@0$@*a$l6p/yp* *h1b*&&O*m*8*($/6*p$F**710*+&K* **g*> *C$**W$t&t6kq*&*d***d*5&&o*!$6M*p$es* *d*6**"&L*8*>$0$~*px*& **h**q*( * $L*p$pw*( *j***q*A *:$6*p$x&x6n*m*x*&**m*&*&p5$46*p$`*k*&?&o***a**/D$2*j$l&l&6sq* *m* **f*7*%&$ 6)*j$Fu*,*q*2 **f*0 *$W*p$t&t6qq**p*** *b*7&*&o6$G*p$es*"*i*,**!&L*1 *?$,$~*p*t*x*&**l**F$1*p$pr***p* *p**<$3*p$x&x6qq* *d** *c*#&&p*@$-*p$` 6i*5&?&*`* **m**0$A*p$l&l&6n*o*/w* * *e*# *&$&6*p$F*q*y*** x*& *B$-*p$t&t6kq* *o* **k*&&o*=$1*p$d6g*'*b***&M**7$8$|*gx*$ *m*#**k* *;$2*p$pw**u* **l*,9$>*p$x&x6s *d*:**n*!x**&&p*6$2*p$`v*6&?&*h* **e*+ *<$3*p$l&l&6lp*)* *g**n* *&"$6*k$Fu*0*u***n*+*I$&*p$t&t6nr* **l**q*&&&o*76$4*p$ev**b*( **&L*/6$?$~*p**p*x*$**d*&Z*8$3&p*p&$ps&&O*%*g* * *j&**&P4$<*p$x&x6n&l&;*.&*d* * *b* *2x 60$-*p$` 2q&X**e2*7*2v *2\** */$@*p$l6o2%2F* *i1~**-*&On**&6$4*p68$F2>1/* * &M*66* *d*, *:6 $)*p$t&t6ps*1*v*+66* *(6?*3&*&o%$J*l$e6%$6Q*8*c*p6 *6&L** *-$!6$~&~*m6pu*,*p60*+6**l*0!&%$2*p*$p67*6H*)t6*=6$ * *a**9$68*p$x&x6p*t**p*66; * 6`*+&*&p*$D*p6*$`96=*-&?&*E6$*2*6@*c**C$/*p$l&l6p&6d* * *H6*6**m*** &$6 *j60$Ft*$*a*06# **6V* *0$%6*p$t&t6pu**e6*6*6) *h*'&&o:6$1*o$e68**j*U6$*1*6-*&M**H$ 6$~&~*p6pu*!**l*$66&*q* * &$$0*p$p6%6b**g*6,**'6I* *6$9*k$x6p&x96<**_*=6.*6 *h*+&*&p7$6.*p$`6!v*&?&*;60*'64**j**=6 $)*p$l&l6p&s*3* *M6*0*6Ev*; *&$8*p$E6+6f*3*_6*6 **i*: *7$7*p$t&t6p*6S*\6*6D* *a*&*&oC$6*l6+$eu**s* 6* *6&M*H*9$ 6+$~&~*p6p*q*0i6*$6<**a*#*&$P*p$m6-6V**q6!*2**6P*3 *$!6,*p$x6p&xu* **g*56B*.6@*!&&p*A$,*o$^6*6Y*&?&* *B6!**6>u*$^*p$j6p&l&* 6Y*#*169*=66* *a* &&$06*p$F* * 6T*( *p*6"*#6L*(*J$+*p$r&t6p:6;*( *665*69*s*(&&o* *8$ 6&*p$b6*o*+}*-6 * *&6E*3F$6$}&~*p6p **h*9M6(&&\*6 **i*4*.p;$6"*p$p65v*-*&-.%*6*&K* *6F*+ *4$ 6*p$n&x6p&p&;**'&J6+**61* *c&* &p?6$**p$`6& 2*k*-*2s *2=6*6#*#&J**5 2{3$28*p$j6p262;* *F61~**'6 &O*a* K$.*p$F**2;1,*-*6&L*y*2**=$2*j$q *n*7x* **n*+*:$>*n$bs*:*f***j*E *@$*${*p *o*u*3 **o*A5$C*p$n**d*Cx***p*$*6$6*p$u*r*%x****e*4*E$-*p$\v*! *n*3**l*) *C$,*p$i*q*"y***a*# *&$G*p$Ct**b***r**@$1*p$ox*-*b*/ **l**+J$,*p$ev*4*b*6* *m*2*H$($~*pv*2*c*E* *f*+ *9$7*p$ow*0 * *f*u**; *8$5*p$ww* **a**u* **$A*p$_v*$**h*"*p*1$E1~*p$l&l*g*#**n**C10*#* &$66*k$F;69* 6 * *F6*/6*h6*6 *@$66p*p$t&tu6*5* *a6* *6 6E*1&6 *&o36 $6*p$b6/t*6 **:66 *0*6&+&)6$*?6*=$2$~&~*p6pF6-*$6 * *+66*96*o*36*&$666*p$nv*!6*366*)6*o**6 *5$3*p$w&x6p 6A66**P66*6**p*&6*&p$W*p6$`6 6j*=6 &?&*d6*6(* *%6<*?6 *1$F*p$k&l66p&*6a*;6 m6 *+6 6 *d*/6* *&$66*p66$Fu*06 **f6*+ *606:**+6 H$,*p$t6&t6p6_*96**I6"66*&*S6**5&6&o@$/*p6$e56A*76 *666*p6* *&6 6%*D*6?$2$~&~*p6p!6T*6 *5686*6**b*?*6 &!$66 *p$p6t6 *' **g*06*66c*6 8$ 66*p$u6p&x**f*86*F6 6 *6v*.6 &&p**$6$6&*p$]6 u*76&?&*m*6 ** 6'6;6*+$ 6+*p$l&l6p& *6`*66**@6-66**u*&6#& $F*p$F66*6X**;6t*6& * *66@*86*D$&*p$q&t6p6 6W*"6*X6 6 * 6&**n*!&6&o*A$,*p$d666O*96 6*B6 *6$* *&M*#6*3$6,$~6p&~*p-6K**6*Q6*66 * *g*36&$P*p$p68*66D*96 *U6*6**6^*"6*B$,6p*p$x6&x,6I*6*]6 *6$* *6R*&6*&p9$666*o$^O6'*6&?&* *c*6*76<*56C$6 *p$l&l6p&*6Z*26 *36+6 *6**k6*)'&$@*k6$F** 666:*%6 e6*6* *d**!6B$3*j$t&t6p6"6B*6 *g* 66* *6\* &6&o*3$:*p$`6*66J*76*C6/*'6*6*&K*=62$A$~&~*n6p**66a*(6 D64*6* *!6B*&6*&"$6*p$p6*%6O6*7&I* *g*6&K!6 6H*;&6&&P**2$6*p$x6p46B*26*2t *`* 6*2e66 &27*A*6 62l.2 $3*p$`6s*6/b* 6 6656***/x*:/2*866$7*l*$k6p*/z>/3*966g61~*p6*&O*6Q*,6*@6$6*p6$E /;10*6** &D6 * 66 *m*36 *>$.*k$t&t6p66M**6k6**"6 *6Z*5&6 &o;$ 6 6*p6 $b **g*26=665*6**'&K*6 *4$6${&~*p6p 6&6B*46 *e6*(6 * *6N6*#*6&$$(6 *p$p6*m* 6)6K*/6 **6J*)6 *6<$%6*p$t&x6pt*!6*e*"6 **66=6*"&&p&$66*p6$[*+6C*6 &?& *!66&* 6* *062*'6 H$,6p*p$i&l&*36/*'6*c*46* * 66A&Q*%&6*#$$6#6=*p$@.v*p*6 ,.666* 6 * &V*36* *4$&6*n$n6&t6pt6*6 *\66*6 * *c*0&6 &o*4$6"*p$`6+96<*6*b*#6)*6*&G6*-6 *76 $($x6&~*p6p*t*6 `6*p6 *(66&* 6 **&$$3*p$m6*/6D*6q6*6**6l*6*@$6**p$x&x6p 6j**6 <606**6 *m*!6&*6&p<$3*k$`6*a66* 6 &?*&*e*6*6a*D6*+$E6*j$e&l6p&56?*;6 *069*"6*6*l*$6 *&6$-*o$F6*16=*&626B* *6*%6I*'6 *666$4*p$t&t6p*p*6A62*6**6O*&&*6&o=6$6*p$d60t*;6*t*%6* *6& 6B*%6*,$A$~&~*p6p6m6*C6* *L66 * *6Q*66*$ &'6(6*p$p6'p**36*%6?*6*6X*-6*?$0*p$t6p&x66V*6 *_66*6**]*5&6 &p*+$B*p$`6/66&6**6 &?&n*"*6.*6#6-*46*9$7*p$k&l6p&6^*#6 **D6+*6 *#6N***6#&$$+6-*p$F6 6[6 *7**266*p6-U6 **6 * *=$**p$t&t6p6W6*#* *T66*p6t6*?&&o**:6$.*l6"$e6]6*-6*'69* 6* *&M*6 ?$!6$~&~*p66p*f*66 * *`6 *"6$ *6e6 * *&%$6 6*p$l6%o*&O*7 *Z6*6)*m&*0*6&P1$?*p$u6p66F*6**2z>6,*7636&K* 6*2 *0$2,*p$`6>6[*-6*6/~ 26+6**60 *k*+6! */t6 $6/$*j$i6pt*5*6 /*5/'6 **6A/v6-/)*86*/v+$ /601v*p6:$F*6V*&6 06/B6*6-* *116*C6*6$;*p$t&t6p*o6*6R6 6* * *6J*4&6 *&o(6$2*p6+$e 6i*6 *]66 *6 * *&J6**,6$68$~&~*p6pv*)6 *+67*6**6X*6 *&$'6*l$p6,&6O*6*.66-*(6"* *b*6*&$>6 *p$r6p&x*6g6 *x*+6% **66P*6 &&p*<$6-*l$_6%,6J*)6&?&*6T*6(* *f*26*6$'6-*j$l&l6p&*/6=*46h6 *.6(**26;*6*!&$2666W*p$Ft6 *2*D60*6* *"6?**/6G$6 6 *m$q&t6pv*56*+6868*+**6B*&6&o*:$4*p*6$$b6"6+6*;6 r*16/6**&M*#6L$ 6$~&~*p6p **!6E*,6 *Y6&*6'*-6C*6*1$666Wy6 *;63666B6J6 6"6pw6<6p6ÿ/MTrk•ÿSinoÊfºZ ^©6Z ^[]™JšZdƒ`Z‹ ]dƒ`]ƒ*º[] ^P‡všZdƒ`Z‹ Vdƒ`VÎ`LdpLpOdpOpJdpJ²PLdpLpOdpOpJdpJçQdpQOdpOLdpLœXdpXVdpVQdpQØTdpTSdpSQdpQ›PXdpX…PVdpV‰0]dp]pQdpQçVdpV…P]dp]…Pbdpb£P[dp[…P]dp]`dp`bdpb«XdpXVdpVÉ]dp][dp[XdpXœ]dp][dp[XdpXœ]dp][dp[XdpXœ]dp][dp[XdpXÿ/MTrk ÿ PercussãoËv»F p›DdxD@dx@9» /›=d»   8›=9d»    + ›9,» …d ‹nF []ÎJ›DdxDxBdxB@dx@>d/» I›>x=dx=;dx;9d.» J›9xDdxDBdxB@dx@>dx>=dx=;dx;#» „D Ì#[]_ž6›DdxDBdxB@dx@>dx>=d» Z›=;dx;9dx98d,» L›8´@JdxJIdxIGd`» ›GxEdxExDdxD» _›@dx@’x» < 9 6 1* . , * (< & % #< "       ,  M 5 2    ( ™5›GdxGxEdxEDdxDBd»  J›B?» ( !›@d» *< -6›@>d» /( 3 4$›>» 5a 8‚} 5( 3c 0 . ,+ *( ' % #,   ƒ1  ! # 'ÇX›DdxDBdxB@dx@>d@» &8›>=dh» $ !%›=» ›;d» ( d›;9d@» `›9» < L " k  P ( ÇX›Gdd,» T›>» Q P O›Bdd» :( 8›>» 5 1 0›=d» , ' # ›=»        è)›GdxGxEdxExDdxD» ]›Bd»    %›B»  ( ! &›Ed» *< -"›EDd» 0 3P 7 ›DBdT» 8$›B@d» d.» 8 1( .›>=d» , ' %   ›=;d»     !›;» ›9d»  ( !›9˜7» < (  ( (  ^ #R '< - /‚, - * '÷›GdxGxEdxEDdxD» !`›Bd9»   ›B@d» u›@.» ( ›>dx>=dx=p;dx;9dx9ŠQ»     ƒ# ™  ! (  ; ½! — ›DdxDBdxB@dx@>dx>=dF»  ›=;d» < ( ›;9d » (  3›98d» !< %8›8» ' *( ,6 1H 4 5²›Jd» 3P 0›JIdxIGdxG» . , ' % ›Ed» ( @›E» ( M›Dd » P ›D» (   '›@dx@A» …V ­1›GdxGxEdxEDdxDBd» r›Bx@dx@>dx>a» Ñ_›DdxDBdxB@dx@>dx>=dQ» O›=;d ;9d 9#» É]›Gdd<>d<><=d<=édV» "›>=dx=;dx;9dC» 5›9ÿ/MTrkfÿBatera¹x =ˆ -\ /5 1( 4( 6( 9C <†P ?— d ?[]£:™EdxE„X6dx6ˆ8EdxE„X6dx6ˆ8EdxE„X6dx6•H4dx4xEdxE„X6dx6ˆ8EdxE„X6dx6ˆ8EdxE„X6dx6‰0dx‚h.dx.p,dx,xdxpEdxE;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6‚2¹[]d.™;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6‚h;dx;‚hEdxExEdxEx9dx9‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;„XEdxE‚hEdxE‚hEdxE¼x9dx9Ù4dx4;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx9d6dx69x;dx;xdx‚h1d;dx;1‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQx9dPdxP9x6dx6x;dx;xdxx1dx1x4d;dx;4‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdxÀXEdxE„X6dx6ˆ8EdxE„X6dx6ˆ8EdxE„X6dx6•H4dx4xEdxE„X6dx6ˆ8EdxE„X6dx6ˆ8EdxE„X6dx6‰0dx‚h.dx.p,dx,xdxpEdxE;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6‚h;dx;‚hEdxExEdxEx9dx9‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;‚h6dx6ƒ`;dx;p6dx6‚h;dx;„XEdxE‚hEdxE‚hEdxE¼x9dx9Ù4dx4;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;6¹ EB™dx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;¹ Bg™d¹ ?q™‚h;dx;‚hQdxQxPdxPx9d6dx69x;dx;xdx‚h1d;dx;1‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQx9dPdxP9x6dx6x;dx;xdxx1dx1x4d;dx;4‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx‚h;dx;‚hQdxQxPdxPx6dx6x;dx;xdx†HQdxQpPdxPp;dx;xdx†Hdx†Hdx†HQdxQpPdxPÿ/MTrkÂÿSint 02ÍS½P ©6P []™JSdJdNdBdƒ`BSJN’*½[] PávCdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ QdCdHdLdƒ`LQCH…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ CdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ CdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG„ã CdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ QdCdHdLdƒ`LQCH…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ CdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CG‹ CdHdLdQdƒ`QCHL…PCdHdLdQdpQCHLƒ`>dCdGdLdƒ`L>CGÿ/MTrk‘ÿFundoÎ1¾F e©6F e[]¡JžQdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@LdIdGdCd=d9d‡@9IGL=C–@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@LdIdGdCd=d9d‡@9IGL=C¬J¾[] ePávžQdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@QdLdHdCd@d9d‡@9LHQ@C‡@>dLdGdCd9d‡@9G>LC‡@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>Ã@QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d…P9LHQ@C¶0QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@LdIdGdCd=d9d‡@9IGL=C–@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@LdIdGdCd=d9d‡@9IGL=CŽ@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>‡@QdLdHdCd@d9d‡@9LHQ@C‡@>dLdGdCd9d‡@9G>LC‡@QdLdHdCd@d9d‡@9LHQ@C‡@LdGdCd>d9d‡@9CLG>Ã@QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d‹ 9LHQ@C°`QdLdHdCd@d9d…P9LHQ@Cÿ/simutrans-124.3/simutrans/music/41-Libertador.mid000066400000000000000000000703261474050137200217340ustar00rootroot00000000000000MThd xMTrk9ÿuntitledÿMarcos Antonio ÿXÿYÿQ 'Àÿ/MTrk ‡ÿPianoÀ° []ƒ`Dd-d@dIdEdpE@IDp-(d?dGdDdpDG?p(IdEdDd@d-dp@DIEp-?d(dGdDdpDG?p(IdEdDd@d-dp@DIE ° 9 6 4 1 / - +# *( ( '( &- '-GdDd?d(dp?GDp(HdCdAdd-d-A<H$CEJL>xNdKdGdBd=d/dƒ`/KGN=B‚h°@x(d4d8d;d?dDdxD48(?;‚,°@LdJd>d-dEd-$CH<A >ELJnKdGdBd=d/dNd‚-/d4d=dBd9dGd<94B=/Gw/GBNK=y9d=dDdId@dx@D9=I4=d@dDdId9d<9D=@I<8d?dBdGd;d<;B8?G‚,8d;dBdGd?dLdJd>d-dEd-$CH<A >ELJnKdGdBd=d/dNdƒ`NGBK/=oDd-d@dIdEdpE@IDp-(d?dGdDdpDG?p(IdEdDd@d-dp@DIEp-?d(dGdDdpDG?p(IdEdDd@d-dp@DIEp-GdDd?d(dp?GDp(HdCdAdd-d-A<H$CEJL>xNdKdGdBd=d/dƒ`/KGN=B‚h°@x(d4d8d;d?dDdxD48(?;‚,°@LdJd>d-dEd-$CH<A >ELJnKdGdBd=d/dNd‚-/d4d=dBd9dGd<94B=/Gw/GBNK=y9d=dDdId@dx@D9=I4=d@dDdId9d<9D=@I<8d?dBdGd;d<;B8?G‚,8d;dBdGd?dLdJd>d-dEd-$CH<A >ELJnKdGdBd=d/dNdƒ`NGBK/=ÿ/MTrk*ÿBaixo 01Á%± D[]ƒ`‘!dx!Z!d!± < 8 5 3 0 . ,-‘d± - 0Y‘Zdp!d(± +< * (‘!± ') & $‘!d ± % 3‘!pdxZd± 47 1 . , * (‘!dx!Z!d!pdxZdp$dx$d<>J@LExKdGd?dDdƒ`DKG?¡`PdLdIdEdxEPLI4PdLdIdEdd<>J@LEiKdGd?dDdƒ`DKG?yPdLdIdEdxEPLI4PdLdIdEdd<>J@LEiKdGd?dDdƒ`DKG?oPdIdEdDd@dx@EPID‚hPdLdGdDd?dx?GPLD‚hPdIdEdDd@dx@EPID‚hPdLdGdDd?dx?GPLD‚hPdIdEdDd@dx@EPID‚hPdLdGdDd?dx?GPLD‚hMdHdCdAdd<>J@LExKdGd?dDdƒ`DKG?¡`PdLdIdEdxEPLI4PdLdIdEdd<>J@LEiKdGd?dDdƒ`DKG?yPdLdIdEdxEPLI4PdLdIdEdd<>J@LEiKdGd?dDdƒ`DKG?ÿ/MTrköÿHarpÄf´P []0% &*4 ?BDF;UsV_”IdxILdd9d]dQdµNM•QE>9]JxXd4dKdGd@d;d_dSdµLKJIGFE7DCB•SX@4KG;_ƒsµWYZ[\]^ `ab cdeghi…UYMXWUR QP+NMƒ8L KJ IG FEDCDFGHI^G$Fp•;d$µGHI KMNOP•;;d µR•;µTU'V$W•;dµY•;µZB•;dµ[•;µ\=•=dTµ]^•==d=Z=d=Z=d=Z@d@µ`Z_^\ Z Y •BdµX •BµWU •Dd8d8DEd9d9E µVW•Gd;d;GµYZ [•Id=dµ\]•=Iµ^ `•Kd?dµab•?Kµc d•Ld@dµeg•@Lµhi j•NdBdµln•BNµopqs•PdDdµuv•DPµwxz|•XdSd@dIdLdµ}~•L@XSIµ(|j`\ZYXWUV•XdSdLdId@d@LXSIµUTS,•XdSd@dIdLdL@XSIµRi•XdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSG-adUdUa_dSdS_\dPdP\µT•XdLdµWY•LXµZ [\] ^` •PdDdDPµab•NdBdBNµc d•Ld@d µe•@LId=d=IGd;d;G7µca•GdLd;d;LGGdNd@d@NGGdPdDdDPGGdNdBd µ`•BNGµ_•GdLd_dSd@d@GLµ^•GdKd?dµ\ •?GKUdDdLdPdGdGLDUPQdBdIdNdEd µZ•EIBQNPd@dLdIdSdDdµY •DI@SPLµX •Nd?dGdKdBd µW•BG?NKS_DdLdPd_dUdId µU•ILDPUPdDdLdSdGdGPDLSPdDdDPSdGdµT •GS_µS7R#Q#PƒB•SdGd;dµSRQ PNM L7K•BdBµM NO•Dd8d µP•8DµR T•Ed9d9E µU•Gd;d;GµV•Id=d=IµW •;GSKd?d?KLd@d@LNdBdBNPdDdDPXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSG-adUdUa_dSdS_\dPdP\XdLdLX-PdDdDPNdBdBNLd@d@LId=d=IGd;d;GKGdLd;d;LGGdNd@d@NGGdPdDdDPGGdNdBdBNGGdLd_dSd@d@GLGdKd?d?GKUdDdLdPdGdGLDUPQdBdIdNdEdEIBQNPd@dLdIdSdDdDI@SPLNd?dGdKdBdBG?NKS_DdLdPd_dUdIdILDPUPdDdLdSdGdGPDLSPdDdDPSdGdGS_„XSdGd;dƒ`;GSo@d\dPdPZPdPLdGdd9d]dQdQE>9]JxXd4dKdGd@d;d_dSdƒ`SX@4KG;_–@;dx;;d;Z;d;Z;d;Z=dx==d=Z=d=Z=d=Z@d@%BdB-Dd8d8DEd9d9EGd;d;GId=d=IKd?d?KLd@d@LNdBdBNPdDdDPXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSG-adUdUa_dSdS_\dPdP\XdLdLX-PdDdDPNdBdBNLd@d@LId=d=IGd;d;GKGdLd;d;LGGdNd@d@NGGdPdDdDPGGdNdBdBNGGdLd_dSd@d@GLGdKd?d?GKUdDdLdPdGdGLDUPQdBdIdNdEdEIBQNPd@dLdIdSdDdDI@SPLNd?dGdKdBdBG?NKS_DdLdPd_dUdIdILDPUPdDdLdSdGdGPDLSPdDdDPSdGdGS_„XSdGd;d‚-BdB-Dd8d8DEd9d9EGd;d;GId=d=I;GSKd?d?KLd@d@LNdBdBNPdDdDPXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiXdSd@dIdLdL@XSIiXdSdLdId@d@LXSIiXdSd@dIdLdL@XSIiXdSd@dIdLdL@XSIiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSGiWdSd@dGdKdK@WSG-adUdUa_dSdS_\dPdP\XdLdLX-PdDdDPNdBdBNLd@d@LId=d=IGd;d;GKGdLd;d;LGGdNd@d@NGGdPdDdDPGGdNdBdBNGGdLd_dSd@d@GLGdKd?d?GKUdDdLdPdGdGLDUPQdBdIdNdEdEIBQNPd@dLdIdSdDdDI@SPLNd?dGdKdBdBG?NKS_DdLdPd_dUdIdILDPUPdDdLdSdGdGPDLSPdDdDPSdGdGS_„XSdGd;dƒ`;GSÿ/MTrk aÿMetalÆ=¶Q [Z]bR'TUVY[ Z[\] ^`ae[ g hi[ [j l n[ opq [ [['[[-–XdSdEdIdPdLd ¶[[–LSEXPI¶[! [&[*[/[3 [8[? [D  # 4 < ?[I B E[N H J N R V [Q X Z [T ][W ` [Y c[Z f i m>–Dd@dGdLdD@GLDd@dGdLdLD@G-Dd@dGdLdLD@G`¶ l f a ^ Y V S P K–XdSdPdDd@dGdLd¶ J B–L@SPXGD¶ : 0 ' $i # "       R 2  u–GdLdEd@d@GLE@dPdLdGd ¶]–G@PL¶] ] ] ] –LdGdDd;d@d@DLG;-¶ –XdSdPdLdGdBd¶ " * H–BSPXGL¶ P V] W X Y [ ] ^] _ ` a c d e] f]–Id@dSdPdNdLdGdDdDIN@SPLGƒy¶ e d bq d g i‚' l n q t–HdCdAdd ¶ "–>LJE¶ ! P ! " % & ( , . 1 4 76 ; < ?‡–@dDdGdKdK@DGŽq@dDdGdLdL@DGŽqEdIdLdPdPEILd>LJE…oEdIdLdPdPEILd>LJE‡]XdSdEdIdPdLdLSEXPIƒBDd@dGdLdD@GLDd@dGdLdLD@G-Dd@dGdLdLD@GXdSdPdDd@dGdLdL@SPXGD…AGdLdEd@d@GLE@dPdLdGdG@PL-LdGdDd;d@d@DLG;-XdSdPdLdGdBdBSPXGLId@dSdPdNdLdGdDdDIN@SPLG‡mHdCdAdd>LJEˆe@dDdGdKdK@DGŽq@dDdGdLdL@DGŽqEdIdLdPdPEILd>LJE…oEdIdLdPdPEILd>LJEÿ/MTrkÿSaxÇA¥@—DdxDGdd>EdE@d@AdADdDGdGHdHJdºU šJGd ºTšGHdºSRšHLdLJdJOdOQdQNdNLdLSdSTdTXdXVdVKdGdDd?dº@š;d4ºQPNM LKJ I GFE DCB@ ? >= ; 98š;DKG? º7 64 2 10/ -+ * )(&% $#" !     @      Ž- .8;FIK MN OP2A3 45 68B9:;?@A&B DF GH"š@d;dx@dx@?dºI K7Mš?;dºN[š;@;Dd=dx@dx@?dx?;d1ºMGš;=DEd9d4Gd;dºLš;E9GºKJIGFEDCB@šSd;dGd@d8dDd‚hD@;8xSGSd;dGd?d6dBd‚Jº?>šB?;67º=AšSGSd;d@dGd8dDd‚hD;@8xSGSd?d;dGd6dBd‚hB?;6xSGUd=d@dGd8dDd‚hD=@8xUGSdGd;d?d6dBdRXdPdPXWdNdNWUdLdLUSdKdKSQdIdIQS;?6BGPdGdGPNdEdENLdDdDLKdBdBKAdd>EdE@d@AdADdDGdGHdHJdJGdGHdHLdLJdJOdOQdQNdNLdLSdSTdTXdXVdVKdGdDd?dº@š;dƒ`;DKG?‚hº@“Xš@d;dx@dx@?dx?;dx;@;Dd=dx@dx@?dx?;dx;=DEd9d4Gd;d<;E9GpSd;dGd@d8dDd‚hD@;8xSGSd;dGd?d6dBd‚hB?;6xSGSd;d@dGd8dDd‚hD;@8xSGSd?d;dGd6dBd‚hB?;6xSGUd=d@dGd8dDd‚hD=@8xUGSdGd;d?d6dBdRXdPdPXWdNdNWUdLdLUSdKdKSQdIdIQS;?6BGPdGdGPNdEdENLdDdDLKdBdBKAdd>@d@DdDGdGIdIJdJ»@›LdLƒ$»@Z›LdLIdIGdGZGdGIdILdLNdNPdP–"Ldd>@d@DdDGdGIdIJdJ»@›LdLƒ$»@Z›LdLIdIGdGZGdGIdILdLNdNPdP’~PdxPNd‘!‘U.‘‘E#‘‘'L<‘'L‘'J‘'+‘'I1‘'‘&N2‘&‘&H‘& ‘&L<‘&L‘&J‘&+‘&I1‘&‘N2‘‘H‘ ‘N2‘‘H‘ ‘'L<‘'L‘'J‘'+‘I±U"1‘‘'L<‘'L‘'J‘'‘'(‘_ ‘'q‘&F‘3‘&‘"S<‘"‘F‘ ‘"Ko‘"E‘K5‘‘L<‘L‘J‘+‘I1‘‘S2‘‘=‘!‘T8‘‘M^‘‘G‘‘R2‘‘<‘!‘Sb‘ ‘&Ko‘&E‘"K5‘"‘N2‘‘H‘ ‘&T2‘&‘&>‘&!‘&U.‘&‘&E#‘&‘L<‘L‘J‘+‘I1‘‘'IX‘' ‘'P‘'‘"I‘"‘F‘‘'P‘'‘N2‘‘H‘ ‘"L<‘"L‘"J‘"+‘"I1‘"‘"L<‘"L‘"J‘"+‘"I1‘"‘"N2‘"‘"H‘" ‘'L<‘'L‘'J‘'+‘I±U"1‘‘&Ko‘& ‘Ko‘ ‘"T2‘"‘">‘"!‘"U.‘"‘"E#‘"‘"L<‘"L‘"J‘"+‘"I1‘"‘&L<‘&L‘&J‘&+‘&I1‘&‘&T2‘&‘&>‘&!‘&U.‘&‘&E#‘&‘$L<‘$L‘$J‘$+‘$I1‘$‘+L<‘&L‘+J‘&+‘I1‘‘R2‘‘<‘!‘Sb‘ ‘To‘E‘"T5‘"‘$U<‘$U‘$J‘$+‘$R1‘$‘"W<‘"W‘"J‘"+‘$T‘$‘&N‘&‘'W2‘'‘'Q‘' ‘&W2‘&‘&Q‘& ‘"W2‘"‘"Q‘" ‘'\2‘'‘'F‘'!‘']8‘'‘'V^‘'‘P±U"‘‘"W2‘"‘"Q‘" ‘W2‘‘Q‘ ‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘"W2‘"‘"Q‘" ‘U<‘U‘J‘+‘R1‘‘"]2‘"‘"G‘"!‘"^.‘"‘"N#‘"‘&Ko‘& ‘"Ko‘" ‘&Ko‘& ‘"Ko‘" ‘N ‘‘ ‘‘"_z‘)F‘"3‘)‘&S<‘&‘"F‘" ‘&N<‘&N‘&J‘&+‘&K‘&‘"E‘"‘"L<‘"L‘"J‘"+‘"I1‘"‘+N<‘+N‘+J‘++‘+K‘+‘'E‘'‘&J‘&‘-J‘-‘)G‘)‘&Q‘&‘"N2‘"‘"H‘" ‘Ko‘ ‘Ko‘ ‘"N2‘"‘"H‘" ‘L<‘L‘J‘+‘I1‘‘N2‘‘H‘ ‘)N<‘)N‘)J‘)+‘)K‘)‘$E‘$‘&Ko‘& ‘"Ko‘" ‘&L<‘&L‘&J‘&+‘I±U"1‘‘"U<‘"U‘"J‘"+‘"R1‘"‘W2‘‘Q‘ ‘&W<‘&W‘&J‘&+‘(T‘(‘)N‘)‘W2‘‘Q‘ ‘W2‘‘Q‘ ‘"U<‘"U‘"J‘"+‘"R1‘"‘!To‘! ‘&T2‘& ‘&_z‘-F‘&3‘-‘)S<‘)‘&F‘& ‘'W2‘'‘Q±U"‘ ‘To‘ ‘$To‘$ ‘\2‘‘F‘!‘]8‘‘V^‘‘P‘‘&U<‘&U‘&J‘&+‘&R1‘&‘'U<‘'U‘'J‘'+‘R±U"1‘‘"To‘" ‘'To‘' ‘"U<‘"U‘"J‘"+‘"R1‘"‘"U<‘"U‘"J‘"+‘"R1‘"‘&W<‘&W‘&J‘&+‘(T‘(‘)N‘)‘\2‘‘F‘!‘]8‘‘V^‘‘P‘‘"U<‘"U‘"J‘"+‘"R1‘"‘&U<‘&U‘&J‘&+‘&R1‘&‘"To‘"E‘!T5‘!‘U<‘U‘J‘+‘R1‘‘U<‘U‘J‘+‘R1‘‘"U<‘"U‘"J‘"+‘"R1‘"‘"U<‘"U‘"J‘"‘"(‘&_ ‘"q‘-F‘&3‘-‘)S<‘)‘&F‘& ‘'U<‘'U‘'J‘'+‘'R1‘'‘U<‘U‘J‘+‘R1‘‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘&To‘&E‘T5‘‘U<‘U‘J‘+‘R1‘‘"\2‘"‘"F‘"!‘"]8‘"‘"V^‘"‘"P‘"‘]2‘‘G‘!‘^.‘‘N#‘‘&To‘&E‘"T5‘"‘"U<‘"U‘"J‘"+‘"R1‘"‘"W2‘"‘"Q‘" ‘"W2‘"‘"Q‘" ‘!W ‘!‘! ‘!‘&_z‘-F‘&3‘-‘)S<‘)‘&F‘& ‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘&W<‘&W‘&J‘&+‘&T‘&‘"N‘"‘"W2‘"‘"Q‘" ‘!To‘! ‘To‘ ‘&W2‘&‘&Q‘& ‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘&To‘& ‘To‘ ‘To‘ ‘$To‘$ ‘'W2‘'‘'Q‘' ‘RX‘ ‘+Y‘+‘&R‘&‘"O‘"‘Y‘‘"\2‘"‘"F‘"!‘"]8‘"‘"V^‘"‘"P‘"‘To‘E‘'T5‘'‘U<‘U‘J‘+‘R1‘‘"U<‘"U‘"J‘"+‘"R1‘"‘&U<‘&U‘&J‘&+‘&R1‘&‘W2‘‘Q‘ ‘&U<‘&U‘&J‘&+‘&R1‘&‘W2‘‘Q‘ ‘&U<‘&U‘&J‘&+‘&R1‘&‘&W2‘&‘&Q‘& ‘$W2‘$‘$Q‘$ ‘"W<‘"W‘"J‘"+‘"T‘"‘$N‘$‘"W2‘"‘"Q‘" ‘"U<‘"U‘"J‘"+‘"R1‘"‘"To‘" ‘To‘ ‘\2‘‘F‘!‘]8‘‘V^‘‘P‘‘&U<‘&U‘&J‘&+‘&R1‘&‘&To‘& ‘"To‘" ‘&To‘& ‘"To‘" ‘W2‘‘Q‘ ‘&U<‘&U‘&J‘&+‘&R1‘&‘"W2‘"‘"Q‘" ‘U<‘U‘J‘+‘R1‘‘To‘ ‘To‘ ‘'U<‘'U‘'J‘'+‘'R1‘'‘"U<‘"U‘"J‘"+‘"R1‘"‘"]2‘"‘"G‘"!‘"^.‘"‘"N#‘"‘'W2‘'‘'Q‘' ‘To‘ ‘&To‘& ‘"[2‘"‘"E‘"!‘"\b‘" ‘&W2‘&‘&Q‘& ‘W2‘‘Q‘ ‘&W2‘&‘&Q‘& ‘To‘ ‘To‘ ‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘\2‘‘F‘!‘]8‘‘V^‘‘P‘‘U<‘U‘J‘+‘R1‘‘'W2‘'‘'Q‘' ‘"To‘"E‘T5‘‘W2‘‘Q‘ ‘&To‘&E‘T5‘‘RX‘ ‘+Y‘+‘&R‘&‘"O‘"‘Y‘‘W2‘‘Q‘ ‘&U<‘&U‘&J‘&+‘&R1‘&‘"U<‘"U‘"J‘"+‘"R1‘"‘&W2‘&‘&Q‘& ‘&W<‘&W‘&J‘&+‘(T‘(‘)N‘)‘U<‘U‘J‘+‘R1‘‘U<‘U‘J‘+‘R1‘‘RX‘ ‘+Y‘+‘&R‘&‘"O‘"‘Y‘‘U<‘U‘J‘+‘R1‘‘"W2‘"‘"Q‘" ‘To‘E‘&T5‘&‘&To‘& ‘"To‘" ‘U<‘U‘J‘+‘R1‘‘"W2‘"‘"Q‘" ‘W2‘‘Q‘ ‘W2‘‘Q‘ ‘W2‘‘Q‘ ‘"U<‘"U‘"J‘"+‘"R1‘"‘"W2‘"‘"Q‘" ‘)U<‘$U‘)J‘$+‘R1‘‘&Z2‘&‘&D‘&‘&[Q‘&‘&Z"‘&‘&G‘&'‘&Z9‘&‘&QT‘&#‘&^#‘&‘&To‘& ‘"To‘" ‘To‘ ‘&To‘& ‘[2‘‘E‘!‘\b‘ ‘W2‘‘Q‘ ‘&U<‘&U‘&J‘&+‘&R1‘&‘W2‘‘Q‘ ‘"W2‘"‘"Q‘" ‘"W2‘"‘"Q‘" ‘&W<‘&W‘&J‘&+‘&T‘&‘"N‘"‘!To‘!‘(‘_ ‘m‘$F‘3‘$‘!S<‘!‘F‘ ‘\2‘‘F‘!‘]8‘‘V^‘‘P‘‘"[2‘"‘"E‘"!‘"\b‘" ‘W2‘‘Q‘ ‘U<‘U‘J‘+‘R1‘‘To‘ ‘"T2‘" ‘&_z‘-F‘&3‘-‘)S<‘)‘&F‘& ‘U<‘U‘J‘+‘R1‘‘&To‘& ‘'To‘' ‘"]2‘"‘"G‘"!‘"^.‘"‘"N#‘"‘&\2‘&‘&F‘&!‘&]8‘&‘&V^‘&‘&P‘&‘&U<‘&U‘&J‘&+‘&R1‘&‘"U<‘"U‘"J‘"+‘"R1‘"‘"W2‘"‘"Q‘" ‘&U<‘&U‘&J‘&+‘&R1‘&‘"W2‘"‘"Q‘" ‘!To‘! ‘&To‘& ‘"]2‘"‘"G‘"!‘"^.‘"‘"N#‘"‘"\ƒP‘"‘"P‚i‘"ÿ/MTrk4‡ÿ @ÿGeneral MIDI²TÿPiano²² Âc² ;²{²[(²]²@‡B’0J’?E’8’:8’C8;’C2’C’AB’'’A’C’A’:’>’'G’A9’>9’:9’C93’A50’'’C’:’>’A’A’+B’A6’>6’:6’C6q’C’:’>’A’+’'D’A8’>8’:8’C8;’A2’CB’'’C’A’C’A’:’>’'E’AB’>B’:B’CB’C’:’>’A’A/’>/’:/’C/0’' ’C’:’>’A’+?’F:’C:’A:’J:m’J’A’C’F’+’+B’C6’A6’>6’F6q’F’>’A’C’+’'B’A6’>6’:6’C6q’C’:’>’A’'’+E’A=’>=’:=’C=3’C<’C’A2’+’C’:’>’A’A’+J’AE’>E’:E’CE’C’:’>’A’A6’>6’:6’C6w’C8 ’F8’C!’C5’A;’C’:’>’A’F’C ’A’+’'G’C9’A9’>9’F93’A50’'’F’>’A’C’A’2?’A:’>:’<:’E:m’E’<’>’A’2’2?’A:’>:’<:’E:m’E’<’>’A’2’+G’A9’>9’:9’C93’C50’+’C’:’>’A’C’+E’FB’CB’AB’JB’J’A’C’F’F/’C/’A/’J/0’+ ’J’A’C’F’'Q’C<’A<’><’F<9’F9’A9’C9’F’A’A52’'’C’A’C’F’>’A’'E’CB’AB’>B’FB’F’>’A’C’C/’A/’>/’F/0’' ’F’>’A’C’+?’A:’>:’::’C:m’C’:’>’A’+’.B’E6’A6’>6’H6q’H’>’A’E’.’+B’A6’>6’:6’C6q’C’:’>’A’+’+Q’A<’><’:<’C<9’J9’C9’F9’J’C’C52’+’F’C’C’:’>’A’+?’A:’>:’::’C:ƒ]’C’:’>’A’+’+?’C:’A:’>:’F:ƒ]’F’>’A’C’+’2B’A6’>6’<6’E6q’E’<’>’A’2’.B’E6’A6’>6’H6q’H’>’A’E’.’+G’F9’C9’A9’J93’C50’+’J’A’C’F’C’2B’A=’>=’<=’E=!’2’2@c’2’96;’9’23:’2’H@’5:’5’H’E@’E’<’>’A’E’+?’A:’>:’::’C:m’C’:’>’A’+’'G’C9’A9’>9’F93’A50’'’F’>’A’C’A’)G’A9’?9’<9’E93’A50’)’E’<’?’A’A’.Q’C<’A<’><’F<9’F9’A9’C9’F’A’A52’.’C’A’C’F’>’A’.E’CB’AB’>B’FB’F’>’A’C’C/’A/’>/’F/0’. ’F’>’A’C’.?’>:’<:’9:’A:m’A’9’<’>’.’'E’AB’>B’:B’CB’C’:’>’A’A/’>/’:/’C/0’' ’C’:’>’A’2B’A6’>6’<6’E6q’E’<’>’A’2’+D’A8’>8’:8’C8;’F2’F’CB’+’C’C’:’>’A’.?’>:’<:’9:’A:ƒ]’A’9’<’>’.’.G’E9’A9’>9’H93’A50’.’H’>’A’E’A’2?’A:’>:’<:’E:m’E’<’>’A’2’2?’A:’>:’<:’E:ƒ]’E’<’>’A’2’0?’?:’<:’::’C:m’C’:’<’?’0’+E’>=’<=’7=3’H<’H’H2’+’7’<’>’H’+J’>E’’>6’<6’76w’H8 ’J8’H!’H5’C;’7’<’>’J’H ’C’+’+J’>>’<>’7>q’7’<’>’+’.J’E>’A>’>>’H>q’H’>’A’E’.’0X’?D’A’HA3’A=0’.’H’>’A’E’A’'G’AB’>B’:B’CBm’C’:’>’A’'’&M’>J’:J’7J’7’:’>’>7’:7’770’& ’7’:’>’.O’CA’AA’>A’FA3’A=0’.’F’>’A’C’A’'R’AM’>M’:M’CM’C’:’>’A’A>’>>’:>’C>w’A@ ’C@’A!’A=’>C’A’C’:’>’C’A ’>’'’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’+G’AB’>B’:B’CBm’C’:’>’A’+’2G’AB’>B’’A’2’.M’EJ’AJ’>J’HJ’H’>’A’E’E7’A7’>7’H70’. ’H’>’A’E’+G’AB’>B’:B’CBm’C’:’>’A’+’.R’EM’AM’>M’HM’H’>’A’E’E>’A>’>>’H>w’A@ ’E@’A!’A=’>C’A’H’>’E’E’A ’>’.’2B’A6’>6’<6’E6q’E’<’>’A’2’.B’>6’<6’96’A6q’A’9’<’>’.’2B’A6’>6’<6’E6q’E’<’>’A’2’.B’E6’A6’>6’H6q’H’>’A’E’.’+G’A9’>9’:9’C93’C50’+’C’:’>’A’C’.G’E9’A9’>9’H93’A50’.’H’>’A’E’A’2?’A:’>:’<:’E:m’E’<’>’A’2’.E’E=’A=’>=’H=3’A<’A’>2’.’A’H’>’E’>’+E’AB’>B’:B’CB ’A’>’:’C’C’:’>’A’+ ’2Q’A<’><’<<’E<’C’:’>’Ae’J9’E9’H9’J’E’E50’2’H’<’>’A’E’E’.G’E9’A9’>9’H93’A50’.’H’>’A’E’A’)B’A6’?6’<6’E6q’E’<’?’A’)’+B’A6’>6’:6’C6q’C’:’>’A’+’.?’>:’<:’9:’A:m’A’9’<’>’.’+G’A9’>9’:9’C93’C50’+’C’:’>’A’C’+?’A:’>:’::’C:m’C’:’>’A’+’)P’C<’?<’<<’F<9’H8’C8’F8’H’C’C42’)’F’C’F’<’?’C’2B’A6’>6’<6’E6q’E’<’>’A’2’.B’E6’A6’>6’H6q’H’>’A’E’.’&G’>9’:9’793’F50’&’7’:’>’F’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’+G’CB’AB’>B’FBm’F’>’A’C’+’2O’AA’>A’’A’E’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’+G’FB’CB’AB’JBm’J’A’C’F’+’.G’EB’AB’>B’HBm’H’>’A’E’.’-J’C>’?>’<>’E>q’E’<’?’C’-’2J’A>’>>’<>’E>q’E’<’>’A’2’2O’AA’>A’’A’E’'O’AA’>A’:A’CA3’A=0’'’C’:’>’A’A’+J’F>’C>’A>’J>q’J’A’C’F’+’0L’?@’<@’:@’C@;’F:’F’CJ’0’C’C’:’<’?’+R’>M’:M’7M’7’:’>’>>’:>’7>w’F@ ’J@’F!’F=’CC’7’:’>’J’F ’C’+’2O’AA’>A’’A’E’'G’AB’>B’:B’CBm’C’:’>’A’'’.J’E>’A>’>>’H>q’H’>’A’E’.’'J’C>’A>’>>’F>1’F’>’A’C’' ’.N’EC’AC’>C’HCm’AE’A’>;’.’H’>’E’A’>’.O’>A’’A’2O’AA’>A’’A’E’+P’AK’>K’:K’CK!’+’+Nc’+’7>=’5H ’7/’5’C;’+D’+’A8’C’:’>’A’C’A’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’2O’AA’>A’’A’E’.J’E>’A>’>>’H>q’H’>’A’E’.’-J’C>’?>’<>’E>q’E’<’?’C’-’+G’AB’>B’:B’CBm’C’:’>’A’+’+O’CA’AA’>A’FA3’C=0’+’F’>’A’C’C’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’.G’EB’AB’>B’HBm’H’>’A’E’.’2G’AB’>B’’A’2’'M’AJ’>J’:J’CJ’C’:’>’A’A7’>7’:7’C70’' ’C’:’>’A’)O’FA’CA’?A’HA3’C=0’)’H’?’C’F’C’2R’AM’>M’’A’A>’>>’<>’E>w’E@ ’H@’E!’E=’AC’E’<’>’A’H’E ’A’2’2J’A>’>>’<>’E>q’E’<’>’A’2’+J’A>’>>’:>’C>q’C’:’>’A’+’)O’CA’?A’K’HK!’.’.Nc’.’5>=’2H ’5/’2’A;’.D’.’>8’A’H’>’E’A’>’)P’AK’?K’=’3H ’5/’3’A;’)D’)’?8’A’E’<’?’A’?’2J’A>’>>’<>’E>q’E’<’>’A’2’.J’>>’<>’9>’A>1’A’9’<’>’. ’.N’AC’>C’:Cm’AE’A’>;’.’:’>’A’>’.G’AB’>B’:Bm’:’>’A’.’.X’ED’AD’>D’HD9’H@’A@’E@’H’A’A<2’.’E’A’E’H’>’A’-M’CJ’?J’A’’A’E’2G’AB’>B’’A ’2O’AA’>A’’A’2 ’.N’EF’AF’>F’HF’Eg’HC’AC’EC’H’A’A?0’.’E’>’A’E’H’A’-J’C>’?>’<>’E>q’E’<’?’C’-’)J’A>’?>’<>’E>q’E’<’?’A’)’2O’AA’>A’’A’E’2G’AB’>B’’A’2’2J’A>’>>’<>’E>q’E’<’>’A’2’+J’C>’A>’>>’F>q’F’>’A’C’+’+J’A>’>>’:>’C>q’C’:’>’A’+’0L’?@’<@’:@’C@;’F:’F’CJ’0’C’C’:’<’?’'M’AJ’>J’:J’CJ’C’:’>’A’A7’>7’:7’C70’' ’C’:’>’A’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’.R’EM’AM’>M’HM’H’>’A’E’E>’A>’>>’H>w’A@ ’E@’A!’A=’>C’A’H’>’E’E’A ’>’.’+J’A>’>>’:>’C>q’C’:’>’A’+’'J’C>’A>’>>’F>q’F’>’A’C’'’+G’CB’AB’>B’FBm’F’>’A’C’+’.M’EJ’AJ’>J’HJ’H’>’A’E’E7’A7’>7’H70’. ’H’>’A’E’2O’AA’>A’’A’E’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’2O’AA’>A’’A’E’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’2X’AD’>D’’A’2G’AB’>B’’A’2’0O’?A’D’HD9’H@’A@’E@’H’A’A<2’.’E’A’E’H’>’A’.M’EJ’AJ’>J’HJ’H’>’A’E’E7’A7’>7’H70’. ’H’>’A’E’.J’>>’<>’9>’A>q’A’9’<’>’.’+J’A>’>>’:>’C>q’C’:’>’A’+’+T’AJ’>J’:J’CJ$’C’:’>’A’A9’>9’:9’C9w’CBY’C’F?0’C’:’>’A ’F’+’2O’AA’>A’’A’E’2J’A>’>>’<>’E>q’E’<’>’A’2’.L’E@’A@’>@’H@;’A:’EJ’.’E’A’E’A’H’>’2J’A>’>>’<>’E>q’E’<’>’A’2’.J’E>’A>’>>’H>q’H’>’A’E’.’+G’FB’CB’AB’JBm’J’A’C’F’+’2O’AA’>A’’A’2 ’.N’EF’AF’>F’HF’Eg’HC’AC’EC’H’A’A?0’.’E’>’A’E’H’A’)M’AJ’?J’’?>’<>’E>q’E’<’?’A’)’+L’A@’>@’:@’C@;’F:’F’CJ’+’C’C’:’>’A’'M’AJ’>J’:J’CJ ’A’>’:’C’C’:’>’A’' ’.N’EC’AC’>C’HC’C’:’>’A_’AE’A’>;’.’H’>’E’A’>’.T’EJ’AJ’>J’HJ$’H’>’A’E’E9’A9’>9’H9w’ABY’A’E?0’A’H’>’E ’E’.’'G’AB’>B’:B’CBm’C’:’>’A’'’)J’A>’?>’<>’E>q’E’<’?’A’)’2J’A>’>>’<>’E>q’E’<’>’A’2’.P’EK’AK’>K’HK!’.’.Nc’.’5>=’2H ’5/’2’A;’.D’.’>8’A’H’>’E’A’>’2M’AJ’>J’’A’A7’>7’<7’E70’2 ’E’<’>’A’+G’CB’AB’>B’FBm’F’>’A’C’+’&O’>A’:A’7A3’F=0’&’7’:’>’F’)J’F>’C>’?>’H>q’H’?’C’F’)’)L’A@’?@’<@’E@;’A:’EJ’)’E’A’E’A’<’?’2J’AE’>E’;’9’2;:’2’HH’5B’5’H’EH’E’<’>’A’E’+T’AJ’>J’:J’CJ$’C’:’>’A’A9’>9’:9’C9w’CBY’C’F?0’C’:’>’A ’F’+’+O’AA’>A’:A’CA ’C’C’:’>’A’+ ’'N’AF’>F’:F’CF’Cg’FC’AC’CC’F’A’A?0’'’C’:’>’A’C’A’.J’E>’A>’>>’H>q’H’>’A’E’.’)J’A>’?>’<>’E>q’E’<’?’A’)’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’2J’A>’>>’<>’E>q’E’<’>’A’2’+J’A>’>>’:>’C>/’C’:’>’A’+ ’+N’AF’>F’:F’CFu’JC’CC’FC’J’C’C?0’+’F’:’>’A’C’C’+O’AA’>A’:A’CA3’C=0’+’C’:’>’A’C’2X’CD’>D’9D9’O@’E@’J@’O’E’E<2’2’J’E’9’>’C’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’&G’>B’:B’7Bm’7’:’>’&’2O’AA’>A’’A’E’+G’AB’>B’:B’CBm’C’:’>’A’+’)O’AA’?A’C’:C’CC’A_’CE’C’A;’+’:’>’A’C’A’+M’FJ’CJ’AJ’JJ’J’A’C’F’F7’C7’A7’J70’+ ’J’A’C’F’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’)J’A>’?>’<>’E>q’E’<’?’A’)’2J’A>’>>’<>’E>q’E’<’>’A’2’2J’A>’>>’<>’E>q’E’<’>’A’2’.L’E@’A@’>@’H@;’E:’E’AJ’.’A’E’H’>’A’+G’AB’>B’:B’CBm’C’:’>’A’+’.O’>A’’A’+O’AA’>A’:A’CA ’C’C’:’>’A’+ ’)N’CC’?C’D’:D9’J@’A@’F@’J’A’A<2’.’F’A’:’>’A’.G’AB’>B’:Bm’:’>’A’.’)O’AA’?A’C’’A’A@’>@’<@’E@w’JFs’J’HF’E’<’>’A’2’H’2F’AF’>F’’A’A=’>=’<=’E=z’QF6’Q’HF9’H’JF’2’E’<’>’A’J’2J’A>’>>’<>’E>q’E’<’>’A’2’.J’>>’<>’9>’A>q’A’9’<’>’.’)J’C>’?>’<>’F>q’F’<’?’C’)’2L’A@’>@’<@’E@;’H:’H’EJ’2’E’E’<’>’A’+P’CK’AK’>K’FK!’+’+Nc’+’7>=’5H ’7/’5’C;’+D’+’A8’C’F’>’A’C’A’)M’AJ’?J’B’’A’2’)G’AB’?B’C’HCm’AE’A’>;’.’H’>’E’A’>’.M’>J’’>7’<7’97’A70’. ’A’9’<’>’2X’AD’>D’’A’-J’C>’?>’<>’E>q’E’<’?’C’-’)J’A>’?>’<>’E>1’E’<’?’A’) ’)N’AC’?C’B’:B’CB!’+’+Ec’+’7EY’7’+EN’+’C’:’>’A ’.G’CB’AB’>B’FB!’.’.Ec’.’5EY’5’.EN’.’F’>’A’C ’)G’AB’?B’A’:A’CA3’C=0’+’C’:’>’A’C’)J’A>’?>’<>’E>q’E’<’?’A’)’.J’E>’A>’>>’H>q’H’>’A’E’.’2G’AB’>B’’A’2’+M’AJ’>J’:J’CJ’C’:’>’A’A7’>7’:7’C70’+ ’C’:’>’A’2J’A>’>>’<>’E>q’E’<’>’A’2’'L’C@’A@’>@’F@;’A:’CJ’'’C’A’C’A’F’>’.R’AM’>M’:M’:’>’A’A>’>>’:>w’A@ ’F@’A!’A=’>C’A’:’>’F’A ’>’.’2G’AB’>B’’A’2’2M’AJ’>J’’<’E’E’<’>’A ’2 ’.N’EF’AF’>F’HF’E’<’>’Ag’HC’AC’EC’H’A’A?0’.’E’>’A’E’H’A’.O’EA’AA’>A’HA3’A=0’.’H’>’A’E’A’2X’AD’>D’’A’.G’>B’’.’-J’C>’?>’<>’E>q’E’<’?’C’-’2L’A@’>@’<@’E@;’E:’HJ’2’H’E’E’<’>’A’.T’EJ’AJ’>J’HJ$’H’>’A’E’E9’A9’>9’H9w’ABY’A’E?0’A’H’>’E ’E’.’.\’EW’AW’>W’HW’H’>’A’E’E@’A@’>@’H@2’EF’AG’E’HM’E’H’>’A’A’AF’.’H ’A’E6’.C’J0’EC’AC’>C’HC’M<‚Z’E ’H’>’A’E’J ’.’Mg²@ÿ/MTrk"ÿ @ÿGeneral MIDIÿTrack 8ÿ ¶¶ ƶK¶ @¶{¶[(¶]¶@˜0–>G–7;–A< †A–A>†>–>A†7–7.†>†7†A–:G–3;–>< †>–>>†:–:A†3–3.†:†3†>£–:G–5;–>< †>–>>†:–:A†5–5.†:†5†>Ж>G–9;–A< †A–A>†>–>A†9–9.†>†9†A´@¶@ÿ/MTrk2ÿ @ÿGeneral MIDIÿTrack 9ÿ  ºº ʺKº @º{º[(º]ˆvšCF‚"ŠCcšCEŠCzšCG‚aŠC†OšCEŠC„JšFEŠFˆfšCšEF‚"ŠEªšCEŠC†:šCG‚aŠC‘ošEEŠEjšEG‚aŠE“_šCG‚aŠC‘ošCEŠC‚ZšCEŠC„JšCEŠCEšEA5ŠE„@šCEŠC‚ZšCE6ŠC…šAEŠA…(šEGTŠE‚šEM{ŠE…FšCF‚"ŠCcšCG‚aŠC‡*šCA5ŠC‚PšEEŠE„JšFKŠFšFE"ŠF(šEG‚aŠE‡*šEA5ŠE„@šEG‚aŠE„&šEM‚_ŠEÿ/MTrk Ùÿ @ÿGeneral MIDIÿTrack 10ÿ  »» Ë»K» @»{»[(»]‡J›?G.‹?›?BB‹?K›?Bk‹?›?Hc‹?›AGm‹A}›>F0‹> ›>;q‹> ›>;5‹>›AGm‹A›>Hl‹>‹>‹> ›ADk‹>›>J‹>›>Jo‹> ›>:/‹>›>Hf‹>›AC$‹A›A3‹A$›AHf‹A›ABk‹A›AHc‹A›>Hf‹>s›CBk‹C›CHc‹C›AHf‹A›>Gm‹>`›AK‹A›>G%‹>:›>V‹>Z›><‚U‹>›AGm‹A‹AA›A<,‹A‹A)›A*5‹A›ADk‹A›AJ‹A›AJo‹A ›A:/‹Af›>K6‹>#›>Fj‹>›>;q‹>›>35‹>b›AK‹A›AC ‹A%›AA5‹A›CBk‹C‹CA›AF"‹CH‹A›A;q‹A›A35‹Ab›>K‹>›AGm‹A›AI$‹A ›ACA‹A›A@V‹A ›AH$‹A ›AL5‹A›>Bk‹>›>Hc‹>›><‚U‹>f›CK‹C›>Bk‹>›>Hc‹>›>I$‹> ›>CA‹>›>@V‹> ›>Gm‹> ›AGm‹A ›CHf‹> ›>Hf‹>^›>K‹>›CH$‹C ›CFA‹C›C?P‹C›AH$‹A ›AL5‹A›ABk‹A›AHc‹A›AI$‹A ›ACA‹A›A@V‹A ›AH$‹A ›AL5‹A›>Bk‹>›>Hc‹>›AH$‹A ›AFA‹A›A?P‹A ›AGm‹A ›AGm‹A ›>Gm‹> ›AGm‹A›AHl‹A‹A‹A ›AC^‹A›A1‹A›AF0‹A ›A;q‹A ›A;5‹A›ABk‹A›AHc‹A›>Hl‹>‹>‹> ›AFj‹A›A;q‹A›A35‹A›AHf‹A›AGm‹A\›AK6‹A#›><#‹>›>Ds‹>`›>K‹>‚›AGm‹A ›AGm‹A ›>Hf‹>^›AK‹A›AC$‹A›A3‹A›>Bk‹>‹>A›><"‹>‹>›>Ds‹> ›>H$‹> ›>L5‹>`›AK‹A›?Gm‹>‹?A›>F,‹>>‹>›>;q‹>›>35‹>›CBk‹C›CHc‹C›>Gm‹> ›CGm‹C›><‚U‹> ›ABk‹A›AHc‹A›C‹A›A;q‹A›A35‹A›ABk‹A›AHc‹A›AHf‹A ›>H$‹> ›>FA‹>›>?P‹>›AHf‹A ›>Hf‹>›AGm‹A ›?Gm‹?›>Bk‹>›>Hc‹>›>Hf‹>s›ABk‹A‹AA›>F"‹AH‹>›>;q‹>›>35‹>›>Bk‹>›>Hc‹>›AF0‹A ›A;q‹A ›A;5‹A›AN0‹A›A6q‹A›AIH‹Ab›>Gm‹>›>G.‹>›>BB‹>K›?<‚U‹?›>Gm‹> ›AGm‹A`›AK‹A›>Hf‹>›AC$‹A›A3‹A$›?Hf‹? ›AHf‹A ›AG.‹A›ABB‹AR›AH ‹A#›AGm‹> ›>Gm‹>›>Hl‹>‹>‹> ›>)›>*5‹>›ADk‹A›AJ‹A›AJo‹A ›A:/‹A›CGm‹Cb›>K‹>›AF0‹A ›A;q‹A ›A;5‹A ›AHf‹A ›>H ‹>#›AFj‹A›A;q‹A›A35‹A›>Bk‹>›>Hc‹>›AF0‹A ›A;q‹A ›A;5‹A ›AH$‹A ›AL5‹A›CBk‹C›CHc‹C›?Bk‹?›?Hc‹?›AHf‹A^›AK‹A›AGm‹A ›>Gm‹> ›ADk‹A›AJ‹A›AJo‹A ›A:/‹A›AH$‹A ›AL5‹A ›>Gm‹>›AGm‹A ›AGm‹A›AHf‹A ›>Hf‹> ›AHf‹A ›AH$‹A ›AL5‹A ›AGm‹A ›AGm‹A›>H$‹> ›>L5‹>›ABk‹A›AHc‹A›ADk‹A›AJ‹A›AJo‹A ›A:/‹Af›CK‹C›AGm‹A ›>Gm‹>›AG.‹A›ABB‹AR›AH$‹A ›AL5‹A ›>Hf‹> ›>H$‹> ›>L5‹> ›Dk‹>›>J‹>›>Jo‹> ›>:/‹>f›>K6‹>#›>)›>*5‹>›AGm‹A›>F0‹> ›>;q‹> ›>;5‹> ›AGm‹>‹AA›><,‹>‹>)›>*5‹>›>Hf‹> ›CHf‹C ›AHf‹A›>Bk‹>›>Hc‹>›AF0‹A ›A;q‹A ›A;5‹A›>Bk‹>›>Hc‹>›<#‹>›>Ds‹>›>Bk‹>›>Hc‹>›ABk‹>›>Hc‹>›ABk‹A›AHc‹A›>Bk‹>‹>A›<<"‹>%‹<)›<*5‹<›Bk‹>›>Hc‹>›>H$‹> ›>L5‹> ›Gm‹> ›AGm‹A›AGm‹A ›AGm‹A›AG.‹A›ABB‹AK›)›>*5‹>›>Hf‹>‚f‹<A›‹<›<;q‹<›<35‹<›ADk‹A›AJ‹A›AJo‹A ›A:/‹Af›CM‹C›CG"‹CT›AHf‹A›> ›>Ds‹>›>Gm‹>›ABk‹A›AHc‹An›>K‹>›AGm‹A ›CGm‹C›A<‚U‹A ›ADk‹A›AJ‹A›AJo‹A ›A:/‹A›>Hf‹> ›AHf‹A ›AHf‹A›AEoŒ>‚4œ:D‚Œ:œ:J)Œ:œ:=1Œ:œ:FeŒ: œB&Œ> œ:FeŒ: œ>IŒ>vœ:EoŒ:œ:<*Œ:œ:?eŒ:œ:86Œ: œ:EMŒ:xœ:<Œ:5œ:?eŒ:œ:B8Œ:œ:/'Œ:œ:B*Œ: œAœ:G.Œ>GŒ:œ:1Œ:@œG;Œ>œ>,Œ>@œ>BTŒ>#œ>CtŒ>œ>;qŒ>œ>*3Œ>œ:<*Œ:œ:?eŒ:œ:86Œ:œG.Œ>œ>4bŒ>œ>A1Œ> œ>F.Œ>œ>3/Œ>IœEoŒ>œ?GFŒ?œ?>JŒ?0œ?1Œ?@œ>B&Œ> œ:FeŒ: œ:FeŒ: œ:<*Œ:œ:?eŒ:œ:86Œ:œ>F.Œ>œ>0KŒ>'œ>I1Œ> œ>F.Œ>œ>3/Œ>Iœ:B&Œ: œF.Œ>œ>3/Œ>Iœ:B&Œ: œ>F.Œ>œ>0KŒ>'œ>I1Œ> œEoŒ> œEoŒ> œ:FsŒ:Œ:Œ:œ>FhŒ>œ>Œ>œB&Œ> œ:FsŒ:Œ:Œ:œ>CtŒ>œ>;qŒ>œ>*3Œ>œ>FeŒ> œ?EoŒ?Eœ:N9Œ:œ><*Œ>œ>?6Œ>Œ>Œ> œ:GŒ:œ:>JŒ:.œ:%Œ:œ:<*Œ:œ:?eŒ:œ:86Œ:œ:N.Œ:œ:;Œ:œEoŒ>œ:FeŒ: œ><*Œ>œ>?eŒ>œ>86Œ>œ:N.Œ:œ:;Œ:ZœJŒ:.œ:%Œ:œ:F.Œ:œ:3/Œ: œ><*Œ>œ>?eŒ>œ>86Œ>œB&Œ> œ:EoŒ: œ?EoŒ?Dœ:?eŒ:œ:B8Œ:œ:/'Œ:œ:B*Œ:HœGFŒ>œ>>JŒ>0œ>1Œ>œ>EoŒ>Œ>Aœ>C.Œ>FŒ>œ>;qŒ>œ>*3Œ>Eœ>B&Œ> œFeŒ> œEoŒ> œBTŒ>#œEoŒ>œ><*Œ>œ>?eŒ>œ>86Œ>œ:FeŒ: œ>N.Œ>œ>;Œ>œGuŒ>œ>1Œ>œD‚Œ>œ>J)Œ>œ>=1Œ>œ:IŒ:tœ>EoŒ> œ:<*Œ:œ:?eŒ:œ:86Œ:œ>Q:Œ>œ>;qŒ> œ>33Œ>œ>FeŒ> œ:FŒ:#œ>CtŒ>œ>;qŒ>œ>*3Œ>Eœ:B&Œ: œFeŒ> œ><*Œ>œ>?eŒ>œ>86Œ>œ>EoŒ> œ:EoŒ:Fœ:D‚Œ:œ:J)Œ:œ:=1Œ:œQ9Œ>œEoŒ> œ:FeŒ: œFeŒ> œ?F.Œ?œ?3/Œ? œ?EoŒ? œ:EoŒ: œ:F.Œ:œ:3/Œ:Iœ>B&Œ>Jœ>D‚Œ>œ>J)Œ>œ>=1Œ>œ><*Œ>œ>?eŒ>œ>86Œ>œ?EoŒ?œE;Œ>6œ>BŒ>œ>77Œ>œIŒ>vœ?EoŒ?œ:Q:Œ:œ:;qŒ: œ:33Œ: œFeŒ> œ>FeŒ>Hœ:B&Œ: œJŒ:.œ:%Œ:>œ:B&Œ: œ>GFŒ>œ>>JŒ>0œ>1Œ>œ?IŒ?vœEoŒ>Dœ:B&Œ:Jœ>B&Œ>Jœ:BTŒ:#œ:GuŒ:œ:1Œ:œ9FeŒ9Hœ:B&Œ: œ:F.Œ:œ:3/Œ: œ9FeŒ9 œEoŒ>œ?EoŒ? œAeŒ>œ>D8Œ>œ>1'Œ>œ>DaŒ>œ>:7Œ>œ?FeŒ? œ:GFŒ:œ:>JŒ:0œ:1Œ:œ9IŒ9vœ9EoŒ9DœEoŒ>Dœ>?eŒ>œ>B8Œ>œ>/'Œ>œ>B*Œ>HœFeŒ> œ>FeŒ> œJŒ<0œ<1Œ<œ>FeŒ> œD‚Œ>œ>J)Œ>œ>=1Œ>œ>P.Œ>œ>=‚Œ>œ>+‚~Œ>ÿ/MTrk³ÿ @HÿGeneral MIDIÿTrack 12ÿ  ½½ ͽK½ @½{½[(½]‡@79;7K7>/77H7&7?R7#7;Z759m5)7A37 7477E:77(u7765759m5)7A37 7477:s7775;B55>W559m5 :9m:‚5AR5#5=*55@@55*57:e7 9B.99599:e9+5?R5#5;Z55:55@/5‚:?R:#:;Z:5:e5 :=:t59m5+59V55EP5 59‚5$5\ 5559V55EJ55BH5583554H599m99A5;,955>W5#9AR9#9=*99@@99*9>59S55>795e77(u77;57&99V99EP9 7;77>W7799t99(u99;59&79V77EP7 99m9)5A35 545:;::Dy::>:::::C/:,5?R5#5;Z5!59V55EJ55BH5583554H51:9V::EP:+7?R7#7;Z77;77Dy77>779m7 99m9 :;::DP:+9?R9#9;Z97:77@/7‚59V55EP5 ::::@y::=:9:99C/9,5?R5#5;Z59;99Dy99>9::::C/:,5?R5#5;Z5::::@y::=:99m9 :9m: 59m5 99m9 5:s5559Bh99%9!9E:99(u99659$9?R9#9;Z95:s55599t99(u99;599:99@/9 99m9)5A35 545#99S99>5;9.55DP5*59V55EP5 3B.335399m9„c5B.5555?5?R55A5;5$55DP5 5:55C/5,:9V::EP: 79m75A59,5H55(u55;55&:?R:#:;Z:59m5 :9m:+79V77EJ77BH7783774H719?R9#9;Z9:;::DP: :9m::A99,:H99(u99;59v9:e9 5:55@y55=5t5:e5 99m9 79m7+5?R5#5;Z55:55@/5‚:?R::A59:[55(u55;55&7?R7#7;Z7:E:::(u::65:9@:99#z9‚ 9F99=9t59m5+39V33EP3 59;5K5>/55H5&59V55EJ55BH5583554H559m5 99m9+:9V::EP: 5:e5 :B.::5:7:77@/7 9:e9 99;9K9>/99H99:9#9;B99>W979m7 39m3+99V99EP9 9;99Dy99>999m9 59m5 59m5)7D37 7077:s7775;B55>W5#9AR9#9=*99@@99*95=5t:9m:+59V55EP5 :E:::(u::65:9:99@/9 5:5#99t99(u99;59&5?R5#5;Z59E:99(u996599:99C/9,:?R:#:;Z:!7?R7#7;Z79:e9+:9V::EP: :9m: 59m5+5AR5#5=*55@@55*59:99C/9 59m5):D3: :0:99m9 99m9 5:55@/5 5:e5 9:e9 9:99C/9 99m9 59m5 7:77C/7,:?R:#:;Z:!:AR:#:=*::@@::*:>:9V::EP: 99m9 59m5 99;9K9>/99H99:99C/9 5:e5{39m3 39m3 9:99@y99=9$5AR5#5=*55@@55*5>59S55>7;5377>W79=9t99m9 5E:55(u5565599m95A5;,555>W55:e5 9:e9 ::e:{9E:99(u99659$5?R5#5;Z53:3#5;=55DP5*5?R5#5;Z5:;::DP: 9=9t99m9 99m9 :9m:+5?R5#5;Z5!9?R9#9;Z9!5?R55A3;5)33>W33:33@/3,5?R5#5;Z55:55C/5 3:33@/3 9:99CO99?+99=99C9k9C!99C959m5:9m: 99m9 59;5K5>/55H53E:33(u33653$99V99EP9+39S33>5;3355>W55:e5{7=7o3A39,3H33(u33;53&5AR5#5=*55@@55*5ƒ~9:e9 5;55DP5 3=3t59m5+9?R9#9;Z9!59V55EP5 99m9 :9m:+:9V::EJ::BH::83::4H:19AR9#9=*99@@99*95:55@/5 9:99@/9 ::::@/: 9;99DP9 9:99@/9 79m7 99m9ƒk:D::M^::?1::B‚a:ÿ/MTrkdÿ @ÿGeneral MIDIÿTrack 14ÿ ¿¿ Ï¿K¿ @¿{¿[(¿]²oŸ+4+ƒvŸ.7‚v.ÿ/MTrklÿ @ÿGeneral MIDI¼ WÿTrack 18ÿ  ¼¼ ̼K¼{¼[(¼]³fœ:6Œ:¤oœ7H727L7=7K747j7H7K7= 7 5H5‚;7>7‚t7H7K7= 7G5B 55>55H5i7H7%5B 55>5"5A 5056 5N5?5i59 550 5c7>7"5A 5056 5F5B 55>5^5>5"5A 5056 5 :H:K:= :):A :0:6 : 5H5K5= 5ƒU5>55H5K5= 5O5@5e5! 535'5 5B 55>5H525L5=5K5459A 9‚5B 55>5^9>9H929L9=9K949j5H5K5= 5):A :0:6 :d9>9ƒ7A 7076 7 :H:K:= : :H:K:= :‚5H5i:H:K:= :O:@:e:! ::6::H:K:= :e5>5"9A 9096 9N9?9i99 990 9c:>:7H7K7= 7)7A 7076 7N7?7i79 770 7 7@79@ 9 :E ::A:^:F:"7S 707H 7…&7H 77D7H787L7C7K7:7&:E ::A:"5S 505H 5(9M 909B 9N9K9i9E 99< 9 :C:K:8 :e5F5"9M 909B 9N9K9i9E 99< 9 5H5‚w:A :(5>5":A :0:6 : 5H5K5= 5):A :0:6 :(5A 5056 5 9H9K9= 9)9A 9096 9(9A 9F9H9K9= 9G5B 55>5"5A 5056 5(3A 3036 3 9H9i:H:ƒ9E 99A95C5K58 5e9F9^5F5^5F5^9F97@7i9@9i9C9K98 9e7F75@5a7J7K7? 7O7B7e7# 7787#9S 909H 9F7E 77A79@97@ 7‚>:C:K:8 :e9F95J5K5? 5O5B5e5# 5585ƒ19E 99A9ƒN5F5^5F5@:E ::A:9C9K98 9G5E 55A5^7F7:C:K:8 : 5Q5K5F 5O5I5e5* 53505d9@9‚3E 33A35J5K5? 5O5B5e5# 5585A3H 33D3H383L3C3K3:3j5@5:S :0:H :(:S :0:H :F:E ::A:@7E 77A7@5E 55A5^5G5H5;5L5F5K5=59S 909H 9‚z7@7‚9E 99A9"9M 909B 9N9K9i9E 99< 9‚y5@57@ 7l:S :0:H : 5C5K58 5)9M 909B 9N9K9i9E 99< 9ƒ55E 55A5@:E ::A:^9F9^5F59M9K9B 9G5E 55A5"9S 909H 9d9F9@:E ::A:7C7K78 7 :C:K:8 :e:F:‚5@ 5l5M 505B 5N5K5i5E 55< 5E9E 99A9‚t9@9‚;5F59C9K98 9):S :0:H :d9F9ƒ07E 77A7^:F:@9H 99D9H989L9C9K9:9&:E ::A:|9@9…9E 99A9"5S 505H 5„j5Q5K5F 5O5I5e5* 53505>5G5H5;5L5F5K5=5D5F5@7E 77A7|9@95S 505H 5(9@ 9N5@55S 505H 5d5F5@9E 99A99C9K98 9ƒ9S 909H 9F5E 55A5@3E 33A3^5F5"5S 505H 5 :C:K:8 :‚9@9‚Y5C5K58 5 :C:K:8 :)5S 505H 5(3S 303H 3 3C3K38 3G5E 55A5^5F5"3S 303H 3d9G9H9;9L9F9K9=9D9C9H9<9K9E9‚89@9:@ :N9@9C5G5H5;5L5F5K5=5D3F3@5E 55A53M3K3B 3 5C5K58 5)5S 505H 5 9C9K98 9ƒU3F3@5H 55D5H585L5C5K5:57M 707B 7N7K7i7E 77< 7E9E 99A95C5K58 5)3@ 3F9C9K98 9 5C5K58 5 9@9a:J:K:? :O:B:e:# ::8:_9G9H9;9L9F9K9=9j9C9K98 9 :C:K:8 :):S :0:H :F9E 99A9":S :0:H :(7@ 7N9@9:M :0:B :N:K:i:E ::< :E9L 99@9R9<9L9G9K9>9ÿ/MTrkíÿ @ÿGeneral MIDIÿTrack 20ÿ ¾¾ ξK¾ ,¾{¾[(¾]‡|ž06Ž0ž0-Ž0Gž04Ž0ƒmž0? Ž0Ež37Ž3ž3' Ž3‚|ž36 Ž3Pž3-Ž3–-ž3? Ž3cž3Ž3iž2? Ž2 ž26 Ž2Pž2-Ž2†ž26Ž2ž2-Ž2Gž24Ž2…{ž26 Ž2Pž2-Ž2Gž2& Ž2ƒsž2& Ž2cž3Ž3ž56 Ž5Pž5-Ž5Gž5& Ž5‡Sž3? Ž3ž26 Ž2Pž2-Ž2Šž2Ž2qž23 Ž2‘[ž2; Ž2‹ž2Ž2qž2= Ž2Šuž27Ž2ž2' Ž2Œž2? Ž2†ž26Ž2ž2-Ž2Gž24Ž2…{ž26 Ž2Pž2-Ž2Gž2& Ž2ž2; Ž2Žsž5* Ž5‚ž2= Ž2Pž24Ž2Gž2- Ž2…cž5 Ž5Sž28Ž2ž20Ž2Gž27Ž2 ž5; Ž5‰#ž.A Ž.kž.?Ž.Lž.;Ž.–Jž5* Ž5‚=ž28Ž2ž20Ž2Gž27Ž2}ž2Ž2qž2= Ž2 ž2: Ž2Pž22Ž2„Ež3 Ž3†_ž3: Ž3Pž32Ž3ƒkž2= Ž2Pž24Ž2Gž2- Ž2ƒsž2* Ž2ƒSž2 Ž2Sž28Ž2ž20Ž2Gž27Ž2gž2>Ž2ž2. Ž2†>ž2; Ž2‚ž5= Ž5Pž54Ž5Gž5- Ž5mž5>Ž5ž5. Ž5‰ž38Ž3ž30Ž3Gž37Ž3gž5>Ž5ž5. Ž5‚^ž5Ž5qž5= Ž5Ež28Ž2ž20Ž2Gž27Ž2ƒmž2 Ž2Kž0>Ž0ž0. Ž0• ž28Ž2ž20Ž2Gž27Ž2‚ž2= Ž2Pž24Ž2Gž2- Ž2‚ž2 Ž2Sž28Ž2ž20Ž2Gž27Ž2‡kž5: Ž5Pž52Ž5?ž2>Ž2ž2. Ž2ž5: Ž5Pž52Ž5‰wž.8Ž.ž.0Ž.Gž.7Ž.+ž.= Ž.Pž.4Ž.Gž.- Ž.‚!ž2> Ž2Pž25Ž2Gž2- Ž2‚{ž2-Ž2Hž28 Ž2ež2>Ž2*ž2: Ž2Pž22Ž2už.; Ž.cž. Ž.iž2; Ž2‹mž58Ž5ž50Ž5Gž57Ž5ƒOž.>Ž.ž.. Ž.fž2; Ž2…Cž5A Ž5kž5?Ž5Lž5;Ž5…Zž2; Ž2„-ž28Ž2ž20Ž2Gž27Ž2ÿ/MTrk ÿ @ÿGeneral MIDIÿTrack 21ÿ ¿¿ Ï¿K¿ ,¿{¿[(¿]Ÿ.3 .PŸ.+.GŸ.$ .1Ÿ+3 +PŸ+++‚UŸ.$ .MŸ+3+Ÿ+++GŸ+1+‚WŸ+3+Ÿ+++GŸ+1+}Ÿ++qŸ+0 + Ÿ.3 .PŸ.+.GŸ.$ .‚Ÿ--SŸ-3-Ÿ-+-GŸ-1-+Ÿ+3 +PŸ+++GŸ+$ +‚Ÿ++‡WŸ+3 +PŸ+++GŸ+$ +‚Ÿ+$ +kŸ+:+kŸ+0 +„iŸ.3 .PŸ.+.GŸ+3+Ÿ+++GŸ+1+‹-Ÿ.< .cŸ..iŸ.< .…CŸ.< .kŸ.:.LŸ.6.zŸ.< .Ÿ-3 -PŸ-+-GŸ-$ -„Ÿ03 0PŸ0+0GŸ0$ 0‚Ÿ+< +cŸ++qŸ+0 +ƒ5Ÿ050Ÿ0-0GŸ040+Ÿ.9 .PŸ.1.GŸ.* .‚Ÿ..ƒYŸ.8 .MŸ.8.Ÿ.0.GŸ.6.‚WŸ.5.Ÿ.-.GŸ.4.}Ÿ++…IŸ.8 .Ÿ+9 +PŸ+1+GŸ+* +‚Ÿ..qŸ.9 .‚=Ÿ.4.Ÿ.$ .‚Ÿ+3 +PŸ+++GŸ+$ +‚Ÿ..iŸ-< -cŸ..iŸ++ƒYŸ..Ÿ+3 +PŸ+++]Ÿ.< .ƒSŸ++iŸ))„3Ÿ.5.Ÿ.-.GŸ.4.}Ÿ+8 +Ÿ-9 -PŸ-1-GŸ-* -1Ÿ+9 +PŸ+1+GŸ+* +1Ÿ+9 +PŸ+1+GŸ+* +1Ÿ.9 .PŸ.1.GŸ.* .„Ÿ.9 .PŸ.1.GŸ.* .)Ÿ07 0PŸ0/0]Ÿ+= +kŸ+<+LŸ+8+zŸ--SŸ.5.Ÿ.-.GŸ.4.…]Ÿ.8 .ƒSŸ+= +kŸ+<+LŸ+8+„Ÿ.7 .PŸ./. Ÿ-7 -PŸ-/- Ÿ+9 +PŸ+1+GŸ+* +1Ÿ+9 +PŸ+1+GŸ+* +mŸ.5.Ÿ.-.GŸ.4.}Ÿ.8 .MŸ-5-Ÿ---GŸ-4-+Ÿ.9 .PŸ.1.GŸ.* .ƒsŸ-+ -kŸ-A-kŸ-8 - Ÿ+7 +PŸ+/+GŸ)5)Ÿ)-)GŸ)4)„GŸ)8)Ÿ)0)GŸ)6)ƒŸ.7 .PŸ./.]Ÿ..iŸ..SŸ.5.Ÿ.-.GŸ.4.gŸ-5-Ÿ---GŸ-4-gŸ-5-Ÿ---GŸ-4-+Ÿ-: -PŸ-2-GŸ-+ -ƒsŸ--ƒ;Ÿ);)Ÿ), )†\Ÿ+7 +PŸ+/+…=Ÿ+8 +cŸ..qŸ.9 .EŸ+;+Ÿ+, +HŸ+5+Ÿ+-+GŸ+4+gŸ.5.Ÿ.-.GŸ.4.‚Ÿ+9 +PŸ+1+GŸ+* +‚]Ÿ+5+Ÿ+-+GŸ+4+‚Ÿ-9 -PŸ-1-GŸ-* -mŸ050Ÿ0-0GŸ040}Ÿ.8 .cŸ.8 .Ÿ.9 .PŸ.1.GŸ.* .1Ÿ.7 .PŸ./.‚UŸ++qŸ+9 +ƒqŸ.7 .PŸ./.?Ÿ.;.Ÿ., .Ÿ+9 +PŸ+1+GŸ+* +ƒsŸ..ƒ;Ÿ+;+Ÿ+, +PŸ.5.Ÿ.-.GŸ.4.+Ÿ.9 .PŸ.1.GŸ.* .mŸ.8.Ÿ.0.GŸ.6.Ÿ++‚Ÿ)7 )PŸ)/)‚UŸ-+ -kŸ-A-kŸ-8 -Ÿ+: +PŸ+2+GŸ++ +‚!Ÿ+9 +PŸ+1+GŸ+* +mŸ.5.Ÿ.-.GŸ.4.+Ÿ.7 .PŸ./.‚UŸ++ƒYŸ++Ÿ+9 +PŸ+1+GŸ+* +ƒsŸ.8 .†Ÿ)5)Ÿ)-)GŸ)4)+Ÿ+9 +PŸ+1+GŸ+* +‚Ÿ++iŸ.8 .…CŸ+8 +cŸ.8 .cŸ++iŸ))iŸ)8 )…CŸ))‹7Ÿ+: +PŸ+2+GŸ++ +‚!Ÿ)9 )PŸ)1)GŸ)* )mŸ-5-Ÿ---GŸ-4-}Ÿ)( )†Ÿ-;-Ÿ-, -PŸ);)Ÿ), )Ÿ)9 )PŸ)1)GŸ)* )mŸ+8+Ÿ+0+GŸ+6+ƒmŸ..qŸ.9 .„KŸ+8 +…CŸ+8 + Ÿ.7 .PŸ./.ƒkŸ-: -PŸ-2-GŸ-+ -…cŸ.8 .cŸ..ƒYŸ..ƒYŸ..qŸ.9 .EŸ.;.Ÿ.,.GŸ...‚'Ÿ.2‚j.ÿ/MTrkmÿ @ÿGeneral MIDIÿMelody³ >ÿ Ãf³³{³[(³]‡}“0d<ƒ0“7d<ƒ7“0d<ƒ0“7d4ƒ7“0d<ƒ0“3d<ƒ3“0d<ƒ0“7d4ƒ7“>d<ƒ>“3d<ƒ3“7d<ƒ7“3d<ƒ3“:d<ƒ:“7d<ƒ7“:d<ƒ:“7d<ƒ7“0d<ƒ0“3d<ƒ3“7d<ƒ7“3d<ƒ3“7d<ƒ7“>d<ƒ>“0d<ƒ0“7d4ƒ7“:dxƒ:“7d<ƒ7“3d<ƒ3“7d4ƒ7“>dxƒ>“7dxƒ7“3d<ƒ3“7d<ƒ7“:d<ƒ:“7dxƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“7d<ƒ7“:d<ƒ:“>d<ƒ>“:d<ƒ:“7dxƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“3d<ƒ3“7d<ƒ7“0d<ƒ0“7d<ƒ7“0d<ƒ0“7d<ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“3d<ƒ3“7dxƒ7“:d<ƒ:“3d<ƒ3“:dxƒ:“7dxƒ7“:d<ƒ:“>d<ƒ>“3d<ƒ3“:d<ƒ:“0d<ƒ0“7d<ƒ7“:d<ƒ:“7dxƒ7“:d<ƒ:“7dpƒ7“>d<ƒ>“:dxƒ:“>d<ƒ>“:d4ƒ:“7d4ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“7d<ƒ7“>dxƒ>“3d<ƒ3“:d<ƒ:“7d<ƒ7“:d<ƒ:“7dxƒ7“3d<ƒ3“:d<ƒ:“3d<ƒ3“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“7d<ƒ7“:dxƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“7d4ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“7d<ƒ7“:d4ƒ:“AdxƒA“>d<ƒ>“7d<ƒ7“:d4ƒ:“>d<ƒ>“7dxƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“Ad<ƒA“>dxƒ>“:dxƒ:“>d<ƒ>“Ad<ƒA“>d<ƒ>“Ed<ƒE“0d<ƒ0“3d<ƒ3“0d<ƒ0“7d4ƒ7“>d<ƒ>“0d<ƒ0“7dpƒ7“>d<ƒ>“0d<ƒ0“7d4ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“0d<ƒ0“7d<ƒ7“3d<ƒ3“7d<ƒ7“:dxƒ:“7dxƒ7“3d<ƒ3“7d<ƒ7“>d<ƒ>“7d<ƒ7“>dxƒ>“7d<ƒ7“:d4ƒ:“>d<ƒ>“7d<ƒ7“3dxƒ3“:d4ƒ:“>d<ƒ>“:d<ƒ:“7d<ƒ7“:d<ƒ:“7d<ƒ7“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d4ƒ>“7d<ƒ7“:d<ƒ:“3d<ƒ3“7dxƒ7“:d<ƒ:“3d<ƒ3“:d<ƒ:“0d<ƒ0“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“:dxƒ:“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“7dxƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d4ƒ>“:d4ƒ:“7d<ƒ7“:dxƒ:“7d<ƒ7“>dpƒ>“:d<ƒ:“>dxƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“:d<ƒ:“Ad<ƒA“3d<ƒ3“7d<ƒ7“:dxƒ:“7dxƒ7“>d<ƒ>“7d<ƒ7“:dxƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“Ad<ƒA“:d<ƒ:“Ad<ƒA“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“7d<ƒ7“>dxƒ>“:d<ƒ:“7d<ƒ7“:d<ƒ:“>d<ƒ>“:d<ƒ:“Ad<ƒA“7d<ƒ7“>dxƒ>“:d<ƒ:“>d<ƒ>“Ad<ƒA“>dxƒ>“7dxƒ7“>d4ƒ>“Ad<ƒA“>d<ƒ>“:dxƒ:“>d4ƒ>“Ed<ƒE“7d<ƒ7“>d<ƒ>“Ad<ƒA“>d<ƒ>“Ad<ƒA“Ed<ƒE“>d<ƒ>“3d<ƒ3“7d<ƒ7“3d<ƒ3“:d<ƒ:“7d<ƒ7“:d<ƒ:“0d<ƒ0“7d4ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“7d4ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“Ed<ƒE“3d<ƒ3“:d<ƒ:“7d<ƒ7“:dxƒ:“>d<ƒ>“3d<ƒ3“7d<ƒ7“:d4ƒ:“>d<ƒ>“Ad<ƒA“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“Ad<ƒA“>d<ƒ>“:d<ƒ:“7dxƒ7“:d4ƒ:“Ad<ƒA“>d<ƒ>“:dxƒ:“>dpƒ>“7d<ƒ7“:d<ƒ:“Ad<ƒA“:d<ƒ:“Ad<ƒA“Ed<ƒE“7dpƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“7d<ƒ7“>dxƒ>“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d4ƒ>“7d<ƒ7“>d<ƒ>“3d<ƒ3“:d4ƒ:“Ad<ƒA“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d‚,ƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“7d<ƒ7“>d<ƒ>“Ad<ƒA“:d<ƒ:“>dxƒ>“:d<ƒ:“>dxƒ>“:dxƒ:“AdxƒA“>d<ƒ>“AdxƒA“>d<ƒ>“Ad<ƒA“>d<ƒ>“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“:dxƒ:“>d<ƒ>“Ad<ƒA“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“Ed<ƒE“7d<ƒ7“>d4ƒ>“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d4ƒ>“Ed<ƒE“>d<ƒ>“Ad<ƒA“:d<ƒ:“Ad<ƒA“>d<ƒ>“Ad<ƒA“Ed<ƒE“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“:d<ƒ:“Ad<ƒA“>dxƒ>“Ad4ƒA“>dpƒ>“EdpƒE“0d<ƒ0“3d<ƒ3“7d<ƒ7“3d<ƒ3“7d<ƒ7“>d<ƒ>“0d<ƒ0“7d<ƒ7“3d<ƒ3“7d<ƒ7“:dxƒ:“7d<ƒ7“3d<ƒ3“:d<ƒ:“7d<ƒ7“:dxƒ:“>d<ƒ>“0d<ƒ0“7d<ƒ7“0d<ƒ0“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“3d<ƒ3“7dxƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“:d<ƒ:“7dxƒ7“:d<ƒ:“>d<ƒ>“:d<ƒ:“Ad<ƒA“0d<ƒ0“7d<ƒ7“:d<ƒ:“7d<ƒ7“:d<ƒ:“>d<ƒ>“7dpƒ7“>dpƒ>“:d4ƒ:“>dxƒ>“3d<ƒ3“:d<ƒ:“0d<ƒ0“7d<ƒ7“:d<ƒ:“7d<ƒ7“:dxƒ:“3d<ƒ3“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d<ƒ:“3d<ƒ3“:d4ƒ:“Ad<ƒA“7d<ƒ7“:d<ƒ:“7d4ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“7d<ƒ7“:d<ƒ:“>dxƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“7d<ƒ7“>dxƒ>“:d<ƒ:“>d<ƒ>“:dxƒ:“>d<ƒ>“:dxƒ:“AdxƒA“>dxƒ>“Ad<ƒA“7dxƒ7“:d<ƒ:“3d<ƒ3“7d<ƒ7“>d<ƒ>“3d<ƒ3“:d<ƒ:“>d<ƒ>“:d‚,ƒ:“>d<ƒ>“:d<ƒ:“Ad<ƒA“:d<ƒ:“>d<ƒ>“3d<ƒ3“:d4ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“:d4ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“:dxƒ:“Ad<ƒA“>d<ƒ>“Ad<ƒA“:d<ƒ:“Ad<ƒA“7d<ƒ7“:d<ƒ:“>dpƒ>“7d<ƒ7“:d<ƒ:“Ad<ƒA“:d<ƒ:“Ad<ƒA“Ed<ƒE“>dpƒ>“AdxƒA“>d<ƒ>“0d<ƒ0“7d4ƒ7“:dxƒ:“7dxƒ7“3d<ƒ3“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“3d<ƒ3“7d<ƒ7“:d4ƒ:“>d<ƒ>“Ad<ƒA“3d<ƒ3“7dxƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“0d<ƒ0“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d4ƒ>“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d4ƒ>“Ed<ƒE“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d<ƒ>“:d<ƒ:“>dxƒ>“7d<ƒ7“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“7d<ƒ7“>d4ƒ>“AdxƒA“7d<ƒ7“3d<ƒ3“7d4ƒ7“>dxƒ>“:dxƒ:“7d<ƒ7“:d<ƒ:“>d<ƒ>“:dxƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“Ad<ƒA“:d<ƒ:“7dxƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“7d<ƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“Ed<ƒE“:d<ƒ:“Ad<ƒA“:d<ƒ:“>dxƒ>“Ad<ƒA“7d<ƒ7“>dxƒ>“:dxƒ:“>d<ƒ>“Ad<ƒA“:d<ƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“Ad<ƒA“>dxƒ>“Ad<ƒA“>dpƒ>“Ed<ƒE“:dxƒ:“>d<ƒ>“:d‚hƒ:“Ad<ƒA“7d<ƒ7“>d<ƒ>“Ad<ƒA“:d<ƒ:“>d<ƒ>“Ad<ƒA“:d<ƒ:“>d<ƒ>“Ad<ƒA“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“7d<ƒ7“>dxƒ>“:d<ƒ:“Ad<ƒA“>d<ƒ>“Ad<ƒA“>dxƒ>“:d<ƒ:“Ad<ƒA“:d<ƒ:“Ad<ƒA“Hd<ƒH“>d<ƒ>“Ed<ƒE“:d<ƒ:“>dxƒ>“Ad<ƒA“:d<ƒ:“>dpƒ>“Ad<ƒA“Ed<ƒE“>d<ƒ>“Ed<ƒE“:d<ƒ:“Ad<ƒA“Ed<ƒE“Ad<ƒA“Ed<ƒE“Ad<ƒA“3d<ƒ3“7d4ƒ7“>dxƒ>“:d<ƒ:“7d<ƒ7“:d4ƒ:“>d<ƒ>“7dxƒ7“>d<ƒ>“7d<ƒ7“>d<ƒ>“Ad<ƒA“>dxƒ>“7dxƒ7“:d<ƒ:“>d<ƒ>“:d<ƒ:“Ad<ƒA“7d<ƒ7“:d<ƒ:“7d<ƒ7“>d4ƒ>“Ed<ƒE“7d<ƒ7“>dpƒ>“Ed<ƒE“3d<ƒ3“:d4ƒ:“Ad<ƒA“>d<ƒ>“Ad<ƒA“7d<ƒ7“>d<ƒ>“:d<ƒ:“>d<ƒ>“AdxƒA“>dxƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“>d<ƒ>“Ed<ƒE“>d<ƒ>“7d<ƒ7“:d4ƒ:“>d<ƒ>“:d<ƒ:“7dxƒ7“>d4ƒ>“Ad<ƒA“>d<ƒ>“:d<ƒ:“>d<ƒ>“:d<ƒ:“>d<ƒ>“Ed<ƒE“7d<ƒ7“>d<ƒ>“7d<ƒ7“:d4ƒ:ÿ/MTrk*1ÿ @ÿGeneral MIDIÿDrums¹ (¹Yÿ  ‡}™L4™Md™Fd™Kd<™IDx‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™IDx‰M‰K™Md™Kd<‰L‰I™L4™ID4‰M‰F‰K™Md™Fd™Kd<‰I™ID<‰M™Md<‰K‰I™ID™Kd<‰L™L4<‰M‰F‰K™Md™Fd™Kd<‰I™ID<‰K™Kd<‰L‰M‰F™L4™Md™Fd<‰I™ID<‰M‰K™Md™Kd<‰F‰I™ID™Fd<‰L™L4x‰L‰M™L4™Md<‰I™ID<‰L‰K™L4™Kd<‰M™Md<‰I™ID<‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰F™Fd<‰L™L4<‰M™Md<‰I‰K™ID™Kd<‰L‰M‰F™L4™Md™Fdp‰M‰I™ID™Md<‰K™Kd<‰L™L4<‰M‰F‰K™Md™Fd™Kd<‰L™L4<‰K™Kd<‰M™Md<‰I™ID<‰L‰M‰K™L4™Md™Kd<‰I‰F™ID™Fdx‰M™Md<‰K™Kd<‰L‰F™L4™Fd<‰M™Md<‰I‰K™ID™Kd<‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M‰K™Md™Kd<‰L‰F™L4™Fdx‰L‰M‰K™L4™Md™Kdx‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd<‰M™Md<‰L‰F™L4™Fd<‰I‰K™ID™Kdx‰L‰I‰M™L4™ID™Mdx‰I™ID<‰M‰F‰K™Md™Fd™Kdx‰I™ID<‰L‰M‰K™L4™Md™Kd<‰I™ID<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰L™L4<‰I‰F™ID™Fd<‰M™Md<‰I‰F‰K™ID™Fd™Kd<‰L™L4<‰I™ID<‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M‰F™Md™Fd<‰K™Kd<‰I™IDx‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™IDx‰M™Md<‰F™Fd<‰I™ID<‰M‰K™Md™Kd4‰I‰K™ID™Kd<‰L‰M™L4™Md<‰K™Kd<‰M™Md4‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fdx‰M‰F™Md™Fd<‰I™ID<‰M‰K™Md™Kdx‰L‰F™L4™Fdx‰I‰M‰K™ID™Md™Kd4‰L‰M‰K™L4™Md™Kdx‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kdx‰F™Fdx‰L‰M‰K™L4™Md™Kd<‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kd<‰I™IDx‰L™L4<‰M™Md<‰I™ID<‰L‰F‰K™L4™Fd™Kd<‰M™Md<‰I™ID<‰K™Kd<‰M™Md<‰I‰K™ID™Kd<‰M™Md<‰L‰F‰K™L4™Fd™Kdx‰L‰I‰M‰F™L4™ID™Md™Fdx‰F™Fd<‰M™Md<‰L‰I‰K™L4™ID™Kd4‰L‰M™L4™Md<‰I™ID<‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd4‰L‰M‰F‰K™L4™Md™Fd™Kd4‰I‰M™ID™Md<‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M‰K™Md™Kdx‰F™Fd<‰M‰K™Md™Kd<‰L‰I™L4™IDx‰M‰F™Md™Fd<‰L™L4<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fd<‰K™Kd<‰I‰M™ID™Md<‰L™L4<‰K™Kd<‰M™Md<‰L™L4x‰L‰M‰K™L4™Md™Kd<‰I™ID<‰L‰M‰F‰K™L4™Md™Fd™Kdx‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kd<‰F™Fd<‰L‰I™L4™ID<‰M™Md<‰I‰F™ID™Fdx‰I™ID<‰M‰K™Md™Kd<‰I™ID<‰M™Md<‰K™Kd<‰L‰I™L4™ID<‰M™Md<‰I‰K™ID™Kdx‰L‰I‰M‰F™L4™ID™Md™Fd<‰K™Kd<‰L‰M™L4™Md<‰I‰F™ID™Fdx‰L‰F‰K™L4™Fd™Kd<‰I‰M™ID™Mdx‰L‰I™L4™ID<‰M™Md<‰L‰F‰K™L4™Fd™Kd<‰I™ID<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰F™Fd<‰M™Md<‰I‰F™ID™Fd<‰K™Kdx‰I‰M™ID™Md<‰K™Kd<‰L™L4<‰M‰K™Md™Kd<‰L™L4<‰I‰K™ID™Kd<‰M™Mdx‰M‰F‰K™Md™Fd™Kd<‰I™ID<‰F™Fd<‰M™Md4‰L‰M‰F™L4™Md™Fd<‰I‰K™ID™Kdx‰I™ID<‰L‰M‰F‰K™L4™Md™Fd™Kdx‰L‰M‰K™L4™Md™Kd4‰L‰M‰F‰K™L4™Md™Fd™Kdx‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kdx‰L‰I‰M‰F‰K™L4™ID™Md™Fd™Kd4‰I™ID<‰L‰M™L4™Md<‰I‰K™ID™Kdx‰M‰K™Md™Kd<‰I™IDx‰L‰M‰K™L4™Md™Kd<‰I‰F™ID™Fd<‰M‰K™Md™Kdx‰L‰F™L4™Fd<‰I‰M™ID™Md<‰L‰F‰K™L4™Fd™Kd<‰I™ID<‰M‰F™Md™Fd<‰L™L4<‰I™ID<‰L™L4<‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M™Md<‰I™ID<‰K™Kdx‰L‰M‰F™L4™Md™Fd4‰L‰I‰M‰K™L4™ID™Md™Kd<‰F™Fdx‰L‰M™L4™Md<‰K™Kd<‰I‰F™ID™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M‰K™Md™Kdx‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰K™Kd<‰L‰M‰F™L4™Md™Fdx‰M™Md<‰L‰F™L4™Fd<‰K™Kd<‰I™ID<‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™IDx‰L‰M‰K™L4™Md™Kd4‰L‰M‰K™L4™Md™Kd<‰I™ID<‰L‰M‰F‰K™L4™Md™Fd™Kdx‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰I™ID<‰M™Md<‰I™ID<‰L™L4<‰I™ID<‰M‰K™Md™Kd<‰I‰F™ID™Fd<‰M™Md<‰K™Kd<‰L‰I™L4™ID<‰M‰K™Md™Kd<‰I™ID<‰L‰K™L4™Kd<‰I‰M‰F™ID™Md™Fd<‰L™L4<‰M‰K™Md™Kd<‰I‰F™ID™Fd<‰L™L4<‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰I™ID<‰L™L4<‰M™Md<‰L‰K™L4™Kd<‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰I™ID<‰L™L4x‰M‰K™Md™Kd<‰F™Fd<‰M™Md<‰I‰F™ID™Fd<‰L‰K™L4™Kdx‰M™Md<‰I‰K™ID™Kdx‰M‰K™Md™Kd<‰L™L4<‰I™ID<‰M™Md<‰K™Kd<‰M™Md<‰I‰F™ID™Fd<‰L™L4<‰M‰F™Md™Fd<‰K™Kdx‰M™Md<‰K™Kd<‰I™ID<‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰L‰M‰K™L4™Md™Kd<‰F™Fd4‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™IDx‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™ID<‰F™Fd<‰M‰K™Md™Kd<‰L‰I™L4™ID4‰L‰M™L4™Md<‰I‰F‰K™ID™Fd™Kd<‰M™Md<‰I™ID<‰K™Kd<‰L‰M™L4™Md<‰K™Kd<‰I‰F™ID™Fd<‰L‰M™L4™Md<‰F™Fd<‰I‰M‰K™ID™Md™Kd<‰F™Fd<‰L™L4<‰I™ID<‰L‰M™L4™Mdx‰L‰K™L4™Kd<‰I‰M™ID™Mdx‰L‰F‰K™L4™Fd™Kd<‰M™Md<‰I™ID<‰L‰F‰K™L4™Fd™Kdx‰M™Mdx‰L‰M‰F™L4™Md™Fdx‰K™Kd<‰I™ID<‰L‰M‰F™L4™Md™Fdx‰K™Kd<‰L‰I‰M™L4™ID™Md<‰K™Kdx‰L‰M™L4™Md<‰I‰K™ID™Kd<‰M™Md<‰F‰K™Fd™Kd<‰L™L4<‰I‰M™ID™Mdx‰L‰F™L4™Fd<‰M‰K™Md™Kdx‰I‰F‰K™ID™Fd™Kd<‰L™L4<‰M™Mdx‰L‰M‰K™L4™Md™Kd<‰I™ID<‰L™L4<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰I™ID<‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰I™IDx‰I‰M™ID™Mdx‰I‰K™ID™Kd<‰M‰F™Md™Fdx‰I‰K™ID™Kd<‰L‰M™L4™Md<‰I™ID<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fd<‰I‰M‰K™ID™Md™Kd<‰L™L4<‰F™Fd<‰I‰M™ID™Md<‰K™Kd<‰L‰I™L4™ID<‰F™Fd<‰I‰M‰K™ID™Md™Kd<‰L™L4<‰M™Md<‰L‰I‰F‰K™L4™ID™Fd™Kd4‰M‰K™Md™Kd<‰L‰I™L4™IDx‰M‰F‰K™Md™Fd™Kdx‰F™Fd<‰M™Md<‰K™Kd<‰I™IDx‰L‰M‰K™L4™Md™Kdx‰L‰M‰K™L4™Md™Kd<‰I™IDx‰M‰K™Md™Kd<‰I‰F™ID™Fdx‰M‰F™Md™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰F™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰F™Fd<‰L‰M‰K™L4™Md™Kd4‰L‰M‰K™L4™Md™Kd<‰I™ID<‰F™Fdx‰L‰M‰K™L4™Md™Kd<‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kd<‰I™ID4‰L‰M™L4™Md<‰I‰K™ID™Kd<‰F™Fd<‰M‰K™Md™Kd<‰I™IDx‰M‰K™Md™Kd<‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰L‰I™L4™ID<‰F™Fd<‰L‰M‰K™L4™Md™Kd<‰I™ID<‰F™Fd<‰L‰M™L4™Md<‰I‰K™ID™Kd<‰L™L4x‰L‰M™L4™Md<‰I™ID<‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd4‰M‰F‰K™Md™Fd™Kd<‰L‰I™L4™IDx‰M™Md<‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰I™ID<‰L™L4<‰K™Kd<‰M™Md<‰L‰I‰F‰K™L4™ID™Fd™Kd<‰M™Md<‰K™Kd<‰L™L4<‰M™Md<‰I‰K™ID™Kd<‰F™Fd<‰L‰M™L4™Md<‰I™ID<‰M‰K™Md™Kd<‰F™Fd<‰L™L4<‰K™Kd<‰I‰M‰F™ID™Md™Fd<‰L™L4<‰K™Kd<‰M™Md<‰L‰K™L4™Kdx‰L‰M™L4™Md<‰I‰K™ID™Kd<‰L‰M‰F™L4™Md™Fdx‰F‰K™Fd™Kd<‰I‰M™ID™Md<‰L‰F™L4™Fdx‰I‰M‰K™ID™Md™Kd<‰L‰F™L4™Fd<‰I™IDx‰I‰M™ID™Md<‰K™Kd<‰L‰M‰F™L4™Md™Fd<‰I™IDx‰L‰I‰M‰K™L4™ID™Md™Kdx‰I‰K™ID™Kd<‰M‰F™Md™Fd<‰L‰I™L4™ID<‰M‰K™Md™Kd<‰F™Fd<‰L‰I™L4™ID<‰F™Fd<‰I‰M‰K™ID™Md™Kdx‰L‰I™L4™ID<‰M™Md<‰F‰K™Fd™Kd<‰L‰I™L4™ID<‰M‰K™Md™Kd<‰I™ID<‰F™Fdx‰M™Md<‰I‰K™ID™Kd<‰L‰M‰F™L4™Md™Fd4‰K™Kd<‰I‰M™ID™Mdx‰L‰K™L4™Kd<‰M™Mdx‰I‰K™ID™Kd<‰M™Mdx‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™ID<‰F™Fd<‰M™Mdx‰I™ID<‰L‰M‰F™L4™Md™Fd<‰K™Kdx‰I™ID<‰L‰M‰K™L4™Md™Kdx‰L‰M‰K™L4™Md™Kd<‰F™Fd4‰L‰M‰F‰K™L4™Md™Fd™Kd<‰I™IDx‰L‰M‰F‰K™L4™Md™Fd™Kdx‰L‰I™L4™ID<‰M‰K™Md™Kdx‰L™L4<‰I™ID<‰M‰F™Md™Fd<‰K™Kd<‰I‰M™ID™Mdx‰L‰K™L4™Kd<‰I‰M™ID™Md<‰K™Kd<‰L‰F™L4™Fd<‰M™Md<‰L‰I‰F™L4™ID™Fd<‰M‰K™Md™Kd<‰I‰F™ID™Fdx‰L™L4<‰M™Md<‰I™ID<‰L‰K™L4™Kd<‰M™Md<‰I™ID<‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fdx‰M™Md<‰L‰F‰K™L4™Fd™Kd<‰M™Md<‰I‰F™ID™Fd<‰L™L4x‰I‰M™ID™Md<‰K™Kd<‰L™L4<‰M‰F‰K™Md™Fd™Kd<‰L™L4<‰K™Kd<‰M™Md<‰I™ID<‰M‰K™Md™Kd<‰F™Fd<‰L™L4<‰I‰M™ID™Mdx‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰K™Kd<‰L‰F™L4™Fd<‰M™Md<‰I™ID<‰L‰M‰K™L4™Md™Kdx‰L™L4<‰M‰K™Md™Kd<‰L™L4<‰I‰F™ID™Fd<‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd<‰M‰K™Md™Kd<‰L‰F™L4™Fdx‰I™ID<‰M™Md<‰I™ID<‰K™Kd<‰I‰M‰F™ID™Md™Fd<‰L™L4<‰K™Kd<‰I‰M™ID™Md<‰L™L4<‰I‰M‰K™ID™Md™Kdx‰I™ID<‰L‰M‰F‰K™L4™Md™Fd™Kdx‰I™ID<‰L‰M‰F™L4™Md™Fd<‰I‰K™ID™Kd<‰L™L4<‰I‰F™ID™Fd<‰M™Md<‰L‰I™L4™ID<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰I‰K™ID™Kdx‰M™Md<‰I™ID<‰K™Kd<‰M‰F™Md™Fd<‰L™L4<‰F™Fd<‰M‰K™Md™Kd<‰I™IDx‰I‰K™ID™Kd<‰M™Md<‰L‰K™L4™Kd<‰M™Md4‰M‰K™Md™Kd<‰I‰F™ID™Fdx‰L‰M‰F™L4™Md™Fdx‰M‰K™Md™Kd<‰I‰F™ID™Fd4‰I‰M‰K™ID™Md™Kd<‰L‰F™L4™Fdx‰L‰M‰K™L4™Md™Kdx‰I‰F™ID™Fd<‰L‰M‰K™L4™Md™Kdx‰L‰M‰F‰K™L4™Md™Fd™Kd4‰L‰I‰M‰F‰K™L4™ID™Md™Fd™Kdx‰I™ID<‰M‰K™Md™Kd<‰L™L4<‰I™IDx‰M‰K™Md™Kd<‰I‰F™ID™Fd<‰M™Md<‰I‰K™ID™Kd<‰L™L4<‰M‰K™Md™Kdx‰I‰F‰K™ID™Fd™Kd<‰L‰M™L4™Md<‰F™Fd<‰L‰I‰M™L4™ID™Md<‰F™Fdx‰L‰I‰K™L4™ID™Kd<‰M™Md<‰L‰I™L4™IDx‰L‰M™L4™Md<‰I‰K™ID™Kd<‰F™Fd<‰L‰M™L4™Md<‰I™ID<‰K™Kd<‰L‰F™L4™Fd<‰M™Mdx‰L‰M™L4™Md<‰F™Fd<‰K™Kd<‰I™ID<‰M™Md<‰I‰K™ID™Kd<‰L™L4<‰M‰F‰K™Md™Fd™Kd<‰L™L4<‰K™Kd<‰M™Md<‰I™ID<‰L‰M‰K™L4™Md™Kd<‰F™Fdx‰I‰M™ID™Md<‰K™Kd<‰L‰F™L4™Fd<‰M™Md<‰K™Kd<‰L‰I‰F™L4™ID™Fdx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰M™Mdx‰L‰K™L4™Kd<‰M™Md<‰L‰F‰K™L4™Fd™Kd<‰I™ID<‰M‰F™Md™Fd<‰I‰K™ID™Kd<‰L‰M‰F™L4™Md™Fdx‰I™IDx‰L‰I‰M™L4™ID™Mdx‰K™Kd<‰I‰M‰F™ID™Md™Fdx‰K™Kd<‰L‰I‰M™L4™ID™Md<‰K™Kd<‰I‰M™ID™Md<‰L‰K™L4™Kd<‰I‰F™ID™Fd<‰L‰M™L4™Md<‰K™Kd<‰I‰F™ID™Fd<‰L‰M™L4™Md<‰I‰F™ID™Fd<‰K™Kd<‰I™ID<‰L‰M™L4™Md<‰I™ID<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰I‰K™ID™Kdx‰M™Md<‰I™IDx‰M‰F‰K™Md™Fd™Kd<‰L™L4<‰F™Fd<‰M™Md<‰K™Kd<‰I™IDx‰L‰M‰K™L4™Md™Kd<‰I™ID<‰M™Md<‰K™Kdx‰M™Md<‰I‰K™ID™Kd<‰F™Fd<‰L‰M™L4™Md<‰F™Fd<‰M™Md<‰I™ID<‰K™Kdx‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fdx‰M‰K™Md™Kd<‰L™L4<‰I‰F™ID™Fd<‰M‰K™Md™Kdx‰L‰F™L4™Fdx‰M‰K™Md™Kd<‰L‰I‰F™L4™ID™Fd<‰M‰K™Md™Kd<‰I™IDx‰L™L4<‰M™Md<‰I‰K™ID™Kd<‰L‰F™L4™Fd<‰M‰K™Md™Kdx‰I™ID<‰M‰K™Md™Kd<‰L‰F™L4™Fd<‰M‰K™Md™Kd<‰I™ID<‰L‰F™L4™Fd<‰M™Md<‰I‰F‰K™ID™Fd™Kdx‰L‰M‰F™L4™Md™Fd<‰I™ID<‰L™L4x‰L‰M‰K™L4™Md™Kd<‰I™ID<‰M™Md<‰L‰I‰F‰K™L4™ID™Fd™Kd4‰L‰M‰F‰K™L4™Md™Fd™Kd4‰I‰M™ID™Md<‰L‰F™L4™Fdx‰M‰K™Md™Kdx‰L‰I‰F™L4™ID™Fdx‰M‰K™Md™Kd<‰L™L4<‰M‰K™Md™Kd<‰I™IDx‰M‰K™Md™Kd<‰L‰I™L4™ID<‰F™Fd<‰M™Md<‰L™L4<‰M‰K™Md™Kd<‰F™Fd<‰L™L4<‰I‰K™ID™Kd<‰M‰F™Md™Fdx‰K™Kd<‰L‰I‰M™L4™ID™Mdx‰L™L4<‰M‰K™Md™Kd<‰L‰I™L4™ID<‰L<‰Ix‰M<‰F<‰Kÿ/simutrans-124.3/simutrans/music/43-Driving-on-the-midnight-highway.mid000066400000000000000000001156531474050137200257030ustar00rootroot00000000000000MThdxMTrkËÿÿCopyright (C) 2015ÿyƒTƒCƒg–¼z URLÿQ q°ÿSetupÿX‚hÿintroA‘3ÿQB@<ÿQO€iÿQäyÿintroBŽ&ÿmainAžÿmainBDÿsabižÿmainA2žÿmainB2œLÿQÈò<ÿsabi24ÿQäy¿`ÿfineÿ/MTrkÇÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------°e°d°@°&ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ÿA---- Drum ’ljÁ --------------------------------------------------ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------ÿ/MTrk•ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------°y°° À° ^°d°[° °à@ÿG---- End of CH Setup --------------------------------------------------‚4Sdx€SQdTdxXdx€Q€T€XQdYdMdx]dx€Q€Y€M€]OdSd_d[dxbdx€O€S€_€[€bedTdXdOdxdd4[d(]d2`dF€dddZidƒ8€e€T€X€O€[€]€`€d€iZ]d<_d<€]€_]dYd`dxbdx€]€Y€`€bXdSd_dVdx[dx€X€S€_€V€[]dQdTd‡@€]€Q€T<[dVd€[€V]dXd€]€X[dTd€[€TXdQd€X€Q[dTd€[€T]dQd€]€Q`d€`]dQd€]€Q[dTd€[€TYdSd€Y€SXdTd€X€TTdMd€TQd€QSd€STd€M€TVdQd€VXd€Q€X[dOdXdSd€[€O€X€S[dOdXdSd€[€O€X€S[dOdXdSd€[€O€X€S[dOdXdSd€[€O€X€SEd€EHd€HEd€EEdOdLd<€E€O€LOdEdLd€O€E€LQdLd€Q€LTdJd€T€JOdLd€O€LQdHd€Q€HEd€EHdCd€H€CEd@d€E€@KdCd€K€CJdEd€J€EHd@d€H€@JdCd€J€CLdOdEdZ€L€O€ELdOdEd€L€O€EJd€JLd€LOd€OKd€KJd€JHd€HJd€JEdOdLd<€E€O€LOdEdLd€O€E€LQdLd€Q€LTdJd€T€JOdLd€O€LQdHd€Q€HEd€EHdCd€H€CEd@d€E€@KdCd€K€CJdEd€J€EHd@d€H€@JdCd€J€CHdEd@dd€>d€>d€>d€>'>Ÿ<"<Ÿ;";Ÿ99Ÿ77Ÿ55Ÿ44œ ŸjdjŸidiŸgdgŸedeŸdddŸbdbŸ`d`Ÿ_d_Ÿ]b]Ÿ[b[ŸY\YŸX\XŸVVVŸTVTŸSPSŸQKQŸOKOŸMEMŸL?LŸJ?JŸH9HŸG9GŸE3EŸC-CŸA-AŸ@'@Ÿ>">Ÿ<"<Ÿ;;Ÿ99Ÿ77Ÿ55®Ÿ.ƒ.Ÿ-~-Ÿ+~+Ÿ)~)Ÿ(~(Ÿ&~&Ÿ$~$Ÿ#~#Ÿ!Y!ŸYŸYŸYŸYŸYŸ3Ÿ3Ÿ3Ÿ3Ÿ3Ÿ3ƒ$ÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------³y³³ Ã0³ @³d³[³ ³ã@ÿG---- End of CH Setup --------------------------------------------------Ú|ÿ/MTrkEÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------´y´´ Ä$´ 1´d´[´ ´´e´d´ ä@ÿG---- End of CH Setup --------------------------------------------------– ´´ Ä%”!dp„!”dp„”dp„”dp„”!dp„!”dp„”dp„”d„”d„”d„”d„x´´ Ä$” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ x”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”!K„!”$K„$”!K„!”'K„'”&K„&”$K„$”&K„&”$K„$”K„”K„”K„” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ x”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”!K<„!”K<„”K<„”K<„”K<„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”#Kx„#”$Kx„$”&Kx„&”'Kx„'”(KZ„(”KZ„”(KZ„(”KZ„x”!Kx„!”!K<„!”$K<„$”Kx„”K<„”!K<„!”Kx„”K<„”#K<„#”$Kx„$”$K<„$”(K<„(”)Kx„)”Kx„”$Kx„$”Kx„”!Kx„!”$Kx„$”(Kp„(”!Kx„!”!K<„!”$K<„$”Kx„”K<„”!K<„!”Kx„”K<„”#K<„#”$Kx„$”$K<„$”(K<„(”Kx„”K<„”!K<„!”(Kx„(”Kx„”-K„-”!K„!”-K„-”!K„!”-K„-”!K„!p” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ x”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”K„”K„”K„”#K„#”!K„!”K„”!K<„!” K<„ ” K„ ”!K<„!”K<„”K<„”K<„”K<„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”K<„<”K„”K„”K„”!K„!”K„”K„”K„”K„”K„”!K„!”K„”K„”K<„<”K„”K„”K„”$K„$”K„”K„”K„”K„”K„”$K„$”K„”K„”#Kx„#”$Kx„$”&Kx„&”'Kx„'”(KZ„(”KZ„”(KZ„(R”!Kx„!”!K<„!”$K<„$”Kx„”K<„”!K<„!”Kx„”K<„”#K<„#”$Kx„$”$K<„$”(K<„(”)Kx„)”Kx„”$Kx„$”Kx„”!Kx„!”$Kx„$”(Kp„(”!Kx„!”!K<„!”$K<„$”Kx„”K<„”!K<„!”Kx„”K<„”#K<„#”$Kx„$”$K<„$”(K<„(”Kx„”K<„”!K<„!”(Kx„(”Kx„ƒ`”"Kx„"”"K<„"”%K<„%”Kx„”K<„”"K<„"” Kx„ ” K<„ ”$K<„$”%Kx„%”%K<„%”)K<„)”*Kx„*”Kx„”%Kx„%”Kx„”"Kx„"”%Kx„%”)Kp„)”"Kx„"”"K<„"”%K<„%”Kx„”K<„”"K<„"” Kx„ ” K<„ ”$K<„$”%Kx„%”%K<„%”)K<„)”Kx„”K<„”"K<„"”)Kx„)”Kx„”.K„.”"K„"”.K„.”"K„"”"K„"”.K„.”"K„"”.K„.ƒ~´´ Ä%”"dp„"” dp„ ”dp„”dp„”"dp„"” dp„ ”dp„”d„”d„”d„”d„”d„”"dƒä>ä7ä4ä1ä.ä,ä*ä&ä$ä"ä!ääääääääääääääääää ä ä ä ä ää ä äää ä ää„"ÿ/MTrk,ßÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------µyµµ ŵ "µdµ[µ µå@ÿG---- End of CH Setup --------------------------------------------------••4d•(dx…4…(•-d•!dp…-…!•d•+dp……+•)d•dp…)…•d•(dp……(•-d•!dp…-…!•+d•dp…+…•)d•dp…)…•(d•d…(…•d•(d……(•d•(d……(•d•(d……(x•4d•0d•-d<…4…0…-•-d•0d•4d…-…0…4•-d…-•4d…4•7d…7•9d…9•5d•2d•0d•-dZ…5…2…0…-•4d•/d•,dx…4…/…,•-d•0d•4dZ…-…0…4•4d•0d•-d…4…0…-•9d…9•4d…4•0d…0•-d…-•-d•2d•5dZ…-…2…5•,d•(d•4d…,…(…4•4d•,d•/d…4…,…/•4d•0d•-d<…4…0…-•-d•0d•4d…-…0…4•-d…-•4d…4•7d…7•9d…9•5d•2d•0d•-dZ…5…2…0…-•4d•/d•,dx…4…/…,•-d•0d•4dZ…-…0…4•4d•0d•-d…4…0…-•!d•&d•)dZ…!…&…)• d•d•(d… ……(•4d…4•7d•(d• d•#d…7…(… …#•4d…4•4d•0d•-d<…4…0…-•-d•0d•4d…-…0…4•-d…-•4d…4•7d…7•9d…9•5d•2d•0d•-dZ…5…2…0…-•4d•/d•,dx…4…/…,•-d•0d•4dZ…-…0…4•4d•0d•-d…4…0…-•9d…9•4d…4•0d…0•-d…-•-d•2d•5dZ…-…2…5•,d•(d•4d…,…(…4•4d•,d•/d…4…,…/•4d•0d•-d<…4…0…-•-d•0d•4d…-…0…4•-d…-•4d…4•7d…7•9d…9•5d•2d•0d•-dZ…5…2…0…-•4d•/d•,dx…4…/…,•-d•0d•4dZ…-…0…4•Ed•@d•d•4d•7d<…7…4•7d•4d…>…7…4•>d•7d•4d…>…7…4•d•4d•7d<…7…4•7d•4d…>…7…4•>d•7d•4d…>…7…4•d…>•d•0d•4d•7d…>…0…4…7•d•9d•5d…>…9…5•9d•5d•=d…9…5…=•>d•2d•7d•;d…>…2…7…;•;d•2d•7d…;…2…7•>d•7d•4d•0d…>…7…4…0•4d•7d•>d•0d…4…7…>…0•4d•7d•d…5…9…>•?d•9d•5d…?…9…5•@d•;d•8d•4d…@…;…8…4•;d•8d•4d•/d…;…8…4…/•,d•/d•4d•8d…,…/…4…8•4d•/d•,d•(dZ…4…/…,…(•9d•0d•4d•-d…9…0…4…-•0d•4d•-d…0…4…-•0d•4d•9d•-d…0…4…9…-•7d•4d•0d•+d…7…4…0…+•5d•-d•)d•0d…5…-…)…0•4d•-d•)d•0d…4…-…)…0•)d•-d•5d•0d…)…-…5…0•)d•-d•9d•0d…)…-…9…0•7d•/d•2d…7…/…2•2d•/d•6d…2…/…6•7d•2d•/d•5d…7…2…/…5•;d•/d•2d•5d•7d…;…/…2…5…7•>d•0d•4d•7d…>…0…4…7•d•4d•7d<…7…4•7d•4d…>…7…4•>d•7d•4d…>…7…4•d•4d•7d<…7…4•7d•4d…>…7…4•>d•7d•4d…>…7…4•d…>•d•0d•4d•7d…>…0…4…7•d•9d•5d…>…9…5•9d•5d•=d…9…5…=•>d•2d•7d•;d…>…2…7…;•;d•2d•7d…;…2…7•>d•7d•4d•0d…>…7…4…0•4d•7d•>d•0d…4…7…>…0•4d•7d•d…5…9…>•?d•9d•5d…?…9…5•@d•;d•8d•4d…@…;…8…4•;d•8d•4d•/d…;…8…4…/•,d•/d•4d•8d…,…/…4…8•4d•/d•,d•(dZ…4…/…,…(•9d•0d•4d•-d…9…0…4…-•0d•4d•-d…0…4…-•0d•4d•9d•-d…0…4…9…-•7d•4d•0d•+d…7…4…0…+•5d•-d•)d•0d…5…-…)…0•4d•-d•)d•0d…4…-…)…0•)d•-d•5d•0d…)…-…5…0•)d•-d•9d•0d…)…-…9…0•7d•/d•2d…7…/…2•2d•/d•6d…2…/…6•7d•2d•/d•5d…7…2…/…5•;d•/d•2d•5d•7d…;…/…2…5…7•>d•0d•4d•7d…>…0…4…7•d…:…6…>•?d•3d•8d•™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d™(d™9d‰$‰,‰(‰9d™1d™(d™$d‰1‰(‰$d™1d™4d™(d™$d‰1‰4‰(‰$ ™$d™(d‰$‰( ™$d™(d‰$‰( ™$d™(d‰$‰((™$d™(d‰$‰((™$d™(d‰$‰(z™Ed™7d ‰7 ‰E\™Ed™7d ‰7 ‰Ed™Ed™7d ‰7 ‰Ed™Ed™7d ‰7 ‰E\™Ed™7d ‰7 ‰Ed™Ed™7d ‰7 ‰Ed™Ed™7d ‰7 ‰E\™Ed™7d ‰7 ‰E ™,3™(3‰,‰( ™,<™(<‰,‰( ™,A™(A‰,‰( ™,J™(J™Ed™7d ‰7 ‰,‰(‰E ™,P™(P‰,‰( ™,Y™(Y‰,‰( ™,_™(_‰,‰( ™$d™(d™1d™,d‰$‰(‰1‰,z™$d™(d™1d‰$‰(‰1F™$d™(d™1d‰$‰(‰1(™$d™(d™1d‰$‰(‰1(™1d™4d™,d™$d‰1‰4‰,‰$ ™,d‰, ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™$d‰,‰$ ™1d™$d™(d‰1‰$‰((™1d™(d™$d‰1‰(‰$(™1d™(d™$d‰1‰(‰$(™1d™(d™$d‰1‰(‰$(™1d™(d™$d‰1‰(‰$F™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d™$d‰,‰(‰$ ™,d‰, ™,d™$d™(d‰,‰$‰( ™,d‰, ™$d™(d™1d™)d‰$‰(‰1‰)F™$d™(d™1d™)d‰$‰(‰1‰)F™$d™(d™1d™)d‰$‰(‰1‰)7™$d™(d™)d™1d‰$‰(‰)‰1M™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™$d™(d‰,‰$‰( ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d™$d‰,‰(‰$ ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™9d™,d‰$‰(‰9‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™1d™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™,d‰$‰(‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™$d™(d‰,‰$‰( ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d™(d™$d‰,‰(‰$ ™,d‰, ™$d™,d‰$‰, ™,d‰, ™$d™(d™9d™,d‰$‰(‰9‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™,d‰, ™$d™(d™1d™,d‰$‰(‰1‰, ™,d‰, ™$d™,d™(d™&d‰$‰,‰(‰&™$d™(d™,d™&d‰$‰(‰,‰&™(d™$d™,d™&d‰(‰$‰,‰&™(d™$d™,d™&d‰(‰$‰,‰&™(d™$d™,d™&d‰(‰$‰,‰&™(d™$d™,d™&d‰(‰$‰,‰& ™1d™(d™$d‰1‰(‰$d™1™4d™$d™,d‰1‰4‰$‰, ™,d‰, ™,d‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™(d™,d‰(‰, ™$d™,d‰$‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™,d‰, ™,d‰, ™$d™,d‰$‰, ™,d‰, ™,d‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™(d™,d‰(‰, ™$d™,d‰$‰, ™,d‰, ™(d™,d‰(‰, ™,d‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™(d‰,‰( ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d‰, ™,d‰, ™,d™$d‰,‰$ ™,d‰, ™,d™(d‰,‰( ™,d‰, ™,d™$d‰,‰$ ™,d™(d‰,‰( ™,d‰, ™,d™(d‰,‰( ™$™(™,‰$‰(‰, ™$™(™,‰$‰(‰, ™$™(™,‰$‰(‰, ™$™(™,‰$‰(‰, ™$™(™,‰$‰(‰, ™$™(™,™1™4™9™#d‰$‰(‰,‰1‰4‰9‰#ƒLÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ ºdº[º ºê@ÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------»y»» Ë» »d»[» »ë@ÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------¼y¼¼ ̼ ¼d¼[¼ ¼ì@ÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------½y½½ ͽ ½d½[½ ½í@ÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk ÿÿ!ÿD---- System Setup --------------------------------------------------/ÿ@---- CH Setup --------------------------------------------------¾y¾¾ ξ ¾d¾[¾ ¾î@ÿG---- End of CH Setup --------------------------------------------------ÿ/simutrans-124.3/simutrans/music/44-Above-the-sky.mid000066400000000000000000001441361474050137200222670ustar00rootroot00000000000000MThdàMTrkcÿÿCopyright (C) 2018ÿyƒTƒCƒg–¼z URLÿQB@ÿSetupÿXpÿQÿStartÿXÿ/MTrk¨ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------‘Žÿ/MTrk%Ñÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° ÀP° T°P°[° °°e°d°@°&°e°d°@°e°d° à@°e°dÿG---- End of CH Setup --------------------------------------------------NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D–@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D–@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D–@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D–@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@QdMdHd„X€Q€M€HxQdMdHdp€Q€M€H‡@GdJdOd„X€G€J€OxGdJdOdp€G€J€O‡@OdLdHd„X€O€L€HxOdLdHdp€O€L€H‡@LdHdCd„X€L€H€CxHdLdCdp€H€L€C‡@MdJdEd„X€M€J€ExMdEdJdp€M€E€J‡@LdGdDd„X€L€G€DxLdGdDdp€L€G€D‡@LdHdEd„X€L€H€ExLdEdHdp€L€E€H‡@EdIdLd„X€E€I€LxLdIdEdp€L€I€E‡@QdMdHd„X€Q€M€HxQdMdHdp€Q€M€H‡@GdJdOd„X€G€J€OxGdJdOdp€G€J€O‡@OdLdHd„X€O€L€HxOdLdHdp€O€L€H‡@LdIdEd„X€L€I€ExEdIdLdp€E€I€L‡@NdFdId„X€N€F€IxNdIdFdp€N€I€F‡@PdKdHd„X€P€K€HxHdKdPdp€H€K€P‡@IdDdNdpIxx€IxNxx€D€N€I€NxDdIdNdPxx€Px€D€I€NUxx€UxNdIdDdZxx€Zx€N€I€D\xx€\xDdIdMdaxx€ax€D€I€MNdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@QdMdHd„X€Q€M€HxQdMdHdp€Q€M€H‡@GdJdOd„X€G€J€OxGdJdOdp€G€J€O‡@OdLdHd„X€O€L€HxOdLdHdp€O€L€H‡@LdHdCd„X€L€H€CxHdLdCdp€H€L€C‡@MdJdEd„X€M€J€ExMdEdJdp€M€E€J‡@LdGdDd„X€L€G€DxLdGdDdp€L€G€D‡@LdHdEd„X€L€H€ExLdEdHdp€L€E€H‡@EdIdLd„X€E€I€LxLdIdEdp€L€I€E‡@QdMdHd„X€Q€M€HxQdMdHdp€Q€M€H‡@GdJdOd„X€G€J€OxGdJdOdp€G€J€O‡@OdLdHd„X€O€L€HxOdLdHdp€O€L€H‡@LdIdEd„X€L€I€ExEdIdLdp€E€I€L‡@NdFdId„X€N€F€IxNdIdFdp€N€I€F‡@PdKdHd„X€P€K€HxHdKdPdp€H€K€P‡@IdDdNdpIxx€IxNxx€D€N€I€NxDdIdNdPxx€Px€D€I€NUxx€UxNdIdDdZxx€Zx€N€I€D\xx€\xDdIdMdaxx€ax€D€I€MNdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@IdDd@d„X€I€D€@x@dDdGdp€@€D€G‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D–@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxPdLdGdDdp€P€L€G€D‡@UdPdLd„X€U€P€LxLdPdSdp€L€P€S‡@NdLdIdEd„X€N€L€I€ExPdEdIdLdp€P€E€I€L‡@NdEdIdLd„X€N€E€I€LxPdLdIdEdp€P€L€I€Eƒ`SdLdIdEdƒ`€S€L€I€ENdGdLdDd„X€N€G€L€DxLdGdDdp€L€G€D‡@@d;d8dEd„X€@€;€8€ExDd@d;d8dp€D€@€;€8¥@ÿ/MTrk =ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------±y±± ÁU± @±P±[± ±±e±d±@±&±e±d±@±e±d± á@±e±dÿG---- End of CH Setup --------------------------------------------------ðá@±± ÁU±P‘B‘6‘N‘Z„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$B6NZá@‘B‘6‘N‘Z„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$B6NZƒàá@±± ÁU±P‘N‘U„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$NUá@‘N‘U„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$NUƒàá@±± ÁU±P‘N‘U„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$NUá@‘N‘U„Xá@0á%B0áJD0áoF0áIá>J‡háBJ0á@H0á=F0á;D0á8B0á6@ á@ƒBá@0áB0áD0áF0áH0áJ áBJƒ`á_J0áN0á0Q0áXT0áX&áQZzáQZ0á U0áBO0á{I0á3D&á@ƒ`á@0á0á2<0áL:0áe80á~6(á>5—$NU‚Žÿ/MTrkgÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² ÂW² @²²[² ²²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------² ð ²² ÂW²’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚²² ÂW²’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’&d…P‚&’&d…P‚&’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’#dp‚#’$d…P‚$’$d…P‚$’dp‚’dp‚’$d…P‚$’$d…P‚$’dp‚’dp‚’d…P‚’d…P‚’dp‚’!dp‚!’ d…P‚ ’ d…P‚ ’dp‚’#dp‚#’!d…P‚!’!d…P‚!’!dp‚!’#dp‚#’%d…P‚%’%d…P‚%’!dp‚!’dp‚’&d…P‚&’&d…P‚&’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’#dp‚#’$d…P‚$’$d…P‚$’dp‚’dp‚’!d…P‚!’!d…P‚!’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’dp‚’ d…P‚ ’ d…P‚ ’ dp‚ ’$dp‚$’%d…P‚%’%dp‚%p’%dp‚%p’dp‚ƒ`â/4’%d0â<70âI:0âV=$â@ƒ$‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%²² ÂW²’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚²² ÂW²’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’&d…P‚&’&d…P‚&’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’#dp‚#’$d…P‚$’$d…P‚$’dp‚’dp‚’$d…P‚$’$d…P‚$’dp‚’dp‚’d…P‚’d…P‚’dp‚’!dp‚!’ d…P‚ ’ d…P‚ ’dp‚’#dp‚#’!d…P‚!’!d…P‚!’!dp‚!’#dp‚#’%d…P‚%’%d…P‚%’!dp‚!’dp‚’&d…P‚&’&d…P‚&’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’#dp‚#’$d…P‚$’$d…P‚$’dp‚’dp‚’!d…P‚!’!d…P‚!’!dp‚!’dp‚’d…P‚’d…P‚’dp‚’dp‚’ d…P‚ ’ d…P‚ ’ dp‚ ’$dp‚$’%d…P‚%’%dp‚%p’%dp‚%p’dp‚ƒ`â/4’%d0â<70âI:0âV=$â@ƒ$‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%’d<‚’%d<‚%²² ÂW²’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’!dp‚!’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚’dp‚‚Žÿ/MTrkÍÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ ÃV³ @³[³³ ³³e³d³@³&³ K³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------ð³³ ÃV³“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒDƒà³³ ÃV³“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒDƒà³³ ÃV³“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD“Ed“Ld“IdžƒEƒLƒI“@d“Gd“Ddžƒ@ƒGƒD‚Žÿ/MTrk¼ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ Ä`´[´ ´d´´e´d´@´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------ð´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Løx´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´´ Ä`´ ”Xd´dw„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx´ ”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„Lx”Xdx„Xx”Sdx„Sx”Udx„Ux”Qdx„Qx”Sdx„Sx”Ndx„Nx”Pdx„Px”Ldx„LÒx´ @”DPx„D”Dd•Cd„X…;…>…Cx•;d•>d•Cdp…;…>…C‡@•Cd•@d•d•9d„X…A…>…9x•9d•>d•Adp…9…>…A‡@•@d•;d•8d„X…@…;…8x•@d•;d•8dp…@…;…8‡@•@d•d•Cd„X…;…>…Cx•;d•>d•Cdp…;…>…C‡@•Cd•@d•d•Cd„X…;…>…Cx•;d•>d•Cdp…;…>…C‡@•Cd•@d•d•9d„X…A…>…9x•9d•>d•Adp…9…>…A‡@•@d•;d•8d„X…@…;…8x•@d•;d•8dp…@…;…8‡@•@d•d•Cd„X…;…>…Cx•;d•>d•Cdp…;…>…C‡@•Cd•@d•ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¶y¶¶ ƶ @¶d¶[¶ ¶¶e¶d¶@¶&¶e¶d¶@¶e¶d¶ æ@¶e¶dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------·y·· Ç· @·d·[· ··e·d·@·&·e·d·@·e·d· ç@·e·dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¸y¸¸ ȸ @¸d¸[¸ ¸¸e¸d¸@¸&¸e¸d¸@¸e¸d¸ è@¸e¸dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk4Þÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹¹ ɹ @¹¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------™#d‰#Z™#E‰#Z™#C‰#Z™#=‰#Z™#7‰#R™#I‰#‰™#d‰#Z™#B‰#Z™#>‰#Z™#:‰#Z™#8‰#R™#L‰#…2™#d‰#ƒB™#d‰#Z™#F‰#Z™#B‰#Z™#=‰#Z™#7‰#R™#d‰#‰™#d‰#Z™#C‰#Z™#?‰#Z™#9‰#Z™#4‰#R™#d‰#‰™#d‰#Z™#H‰#Z™#A‰#Z™#>‰#Z™#;‰#R™#d‰#‰™#d‰#Z™#F‰#Z™#@‰#Z™#;‰#Z™#9‰#R™#d‰#…2™#d‰#ƒB™#d‰#Z™#C‰#Z™#A‰#Z™#=‰#Z™#:‰#R™#d‰#‰™#d‰#Z™#F‰#Z™#B‰#Z™#?‰#Z™#<‰#R™#d‰#‰™#d‰#Z™#F‰#Z™#F‰#Z™#D‰#Z™(d‰(R™#d‰#Z™#F‰#Z™#D‰#Z™#B‰#Z™#@‰#Z™#>‰#Z™(Z‰(ƒB™#d‰#Z™#E‰#Z™#B‰#Z™#?‰#Z™(d‰(R™#d‰#Z™#C‰#Z™#A‰#Z™#>‰#Z™#<‰#Z™#8‰#Z™(Z‰(ƒB™#d‰#Z™#C‰#Z™#>‰#Z™#8‰#Z™(d‰(R™#d‰#Z™#E‰#Z™#B‰#Z™#@‰#Z™#=‰#Z™#:‰#Z™(Z‰(ƒB™#d‰#Z™#A‰#Z™#A‰#Z™#>‰#Z™(d‰(R™#d‰#Z™#E‰#Z™#C‰#Z™#A‰#Z™#?‰#Z™#<‰#Z™(Z‰(ƒB™#d‰#Z™#B‰#Z™#A‰#Z™#@‰#Z™(d‰(R™#d‰#Z™#d‰#Z™#A‰#Z™#?‰#Z™#>‰#Z™#;‰#Z™(Z‰(ƒB™#d‰#Z™#A‰#Z™#>‰#Z™#=‰#Z™(d‰(R™#d‰#Z™#C‰#Z™#=‰#Z™#;‰#Z™#9‰#Z™#8‰#Z™(Z‰(ƒB™#d‰#Z™#G‰#Z™#D‰#Z™#B‰#Z™(d‰(R™#d‰#Z™#E‰#Z™#D‰#Z™#A‰#Z™#@‰#Z™#>‰#Z™#=‰#Z™#;‰#Z™#;‰#Z™#:‰#Z™#:‰#Z™#8‰#Z™#6‰#Z™#5‰#Z™#5‰#Z™#3‰#Z™#2‰#Z™#1‰#Z™#0‰#Z™#/‰#Z™#-‰#Z™#,‰#Z™#+‰#Z™#)‰#Z™#'‰#Z™#%‰#Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#H‰#Z™#E™.E‰#‰.Z™#C‰#Z™#@‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d™9d‰(‰.‰9Z™(d‰(Z™(d‰(Z™(d‰(Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™/d™#d‰/‰#Z™-d™#d‰-‰#Z™+d™#d‰+‰#Z™)d™#d‰)‰#Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d™9d‰(‰.‰9Z™(d‰(Z™(d‰(Z™(d‰(Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™9d™/d‰9‰/R™#d™-d‰#‰-R™#d™+d‰#‰+R™#d™*d™1d™)d‰#‰*‰1‰)ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*R™#d‰#R™*d™(d‰*‰(R™#d‰#R™#d™*d™1d‰#‰*‰1ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d™1d‰#‰*‰1R™*d™#d‰*‰#R™*d™(d‰*‰(R™*d™#d‰*‰#R™*d™#d‰*‰#R™#d™*d‰#‰*R™*d™(d‰*‰(R™*d‰*R™#d™*d™1d‰#‰*‰1R™*d™#d‰*‰#R™*d™(d‰*‰(R™*d™#d‰*‰#R™*d™#d‰*‰#R™#d™*d‰#‰*R™*d™(d‰*‰(R™*d‰*R™#d™*d™2d™1d‰#‰*‰2‰1Z™0d‰0Z™/d™*d‰/‰*Z™-d‰-Z™*d™+d‰*‰+R™#d™*d™)d‰#‰*‰)ƒB™#d™*d™)d‰#‰*‰)ƒB™*d™#d™)d‰*‰#‰)‰™4d™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#‰4™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d™9d‰(‰.‰9Z™(d‰(Z™(d‰(Z™(d‰(Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™/d™#d‰/‰#Z™-d™#d‰-‰#Z™+d™#d‰+‰#Z™)d™#d‰)‰#Z™#d™1d™.d‰#‰1‰.ƒB™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™*d‰*‡"™(d™.d™9d‰(‰.‰9Z™(d‰(Z™(d‰(Z™(d‰(Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™9d™/d‰9‰/R™#d™-d‰#‰-R™#d™+d‰#‰+R™#d™*d™1d™)d‰#‰*‰1‰)ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*R™#d‰#R™*d™(d‰*‰(R™#d‰#R™#d™*d™1d‰#‰*‰1ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d‰#‰*ƒB™*d‰*R™#d‰#R™*d‰*ƒB™*d™(d‰*‰(ƒB™#d™*d™1d‰#‰*‰1R™*d™#d‰*‰#R™*d™(d‰*‰(R™*d™#d‰*‰#R™*d™#d‰*‰#R™#d™*d‰#‰*R™*d™(d‰*‰(R™*d‰*R™#d™*d™1d‰#‰*‰1R™*d™#d‰*‰#R™*d™(d‰*‰(R™*d™#d‰*‰#R™*d™#d‰*‰#R™#d™*d‰#‰*R™*d™(d‰*‰(R™*d‰*R™#d™*d™2d™1d‰#‰*‰2‰1Z™0d‰0Z™/d™*d‰/‰*Z™-d‰-Z™*d™+d‰*‰+R™#d™*d™)d‰#‰*‰)ƒB™#d™*d™)d‰#‰*‰)ƒB™*d™#d™)d‰*‰#‰)‰™4d™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#™#d‰#‰4™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d™9d‰(‰.‰9Z™(d‰(Z™(d‰(Z™(d‰(Z™#d™1d™.d‰#‰1‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d‰#Z™#d‰#Z™#d™.d‰#‰.Z™#d‰#Z™#d‰#R™(d™.d‰(‰.ƒB™#d™.d‰#‰.R™#d‰#R™(d™.d‰(‰.R™#d™4d‰#Z™#d‰#Z™#d™0d‰0‰#Z™#d™0d‰0‰#Z™#d™0d‰0‰#Z™#d™0d‰0‰#Z™/d™#d‰#‰/Z™-d™#d‰#‰-Z™+d™#d‰#‰+Z™)d™#d‰#‰)Z™1d™#d‰#‰1F‰4™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#ƒB™#d‰#R™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#Z™#d‰#R™#d‰#R™(d‰(R™#d‰#…2™9d™0d™(d‰9‰0‰(Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™0d™#d‰0‰#Z™#d™0d‰#‰0Z™1d™0d™(d‰1‰0‰(Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™#d™0d‰#‰0Z™/d™(d™9d‰/‰(‰9Z™#d™/d‰#‰/Z™#d™-d‰#‰-Z™#d™-d‰#‰-Z™#d™+d‰#‰+Z™#d™+d‰#‰+Z™#d™1d™)d™(d‰#‰1‰)‰(•bÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ @ºdº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------»y»» Ë» @»d»[» »»e»d»@»&»e»d»@»e»d» ë@»e»dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¼y¼¼ ̼ @¼d¼[¼ ¼¼e¼d¼@¼&¼e¼d¼@¼e¼d¼ ì@¼e¼dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------½y½½ ͽ @½d½[½ ½½e½d½@½&½e½d½@½e½d½ í@½e½dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¾y¾¾ ξ @¾d¾[¾ ¾¾e¾d¾@¾&¾e¾d¾@¾e¾d¾ î@¾e¾dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¿y¿¿ Ï¿ @¿d¿[¿ ¿¿e¿d¿@¿&¿e¿d¿@¿e¿d¿ ï@¿e¿dÿG---- End of CH Setup --------------------------------------------------‘Žÿ/simutrans-124.3/simutrans/music/45-Misty-Forest.mid000066400000000000000000001651601474050137200222170ustar00rootroot00000000000000MThdÀMTrk=ÿÿCopyright 2011 by GobanboshiÿQ p<ÿXÿYÿ/MTrk0ÿÿ!ÀY°e° @ÀY°e° @ÀY°K° @’þÿ/MTrk8ÿÿ!°e° @ÀY°e° @ÀY°e° @ÀY°K° @’þÿ/MTrkvÿÿ!ÀY°e° @ÀY°e° @ÀY°F<° D9d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2dž€9€6€2;d8d4dž€;€8€49d6d1d¼€9€6€19d6d2dž€9€6€2;d8d4dž€;€8€49d6d1d¼€9€6€19d6d2d¼€9€6€29d4d1d¼€9€4€19d6d2d¼€9€6€24d9d1d¼€4€9€19d6d2d¼€9€6€24d9d1d¼€4€9€19d6d2d¼€9€6€24d9d1d¼€4€9€19d6d2d¼€9€6€24d9d1d¼€4€9€19d6d2d¼€9€6€24d9d1d¼€4€9€19d6d2dž€9€6€28d;d4dž€8€;€46d9d1d¼€6€9€19d6d2dž€9€6€28d;d4dž€8€;€46d9d1d¼€6€9€19d6d2dž€9€6€28dƒ`;d4dš €8€;€46d9d1d´@€6€9€1‡@9d6d2dž€9€6€2;d8d4dž€;€8€46d9d1d¼€6€9€19d6d2d¼€9€6€29d4d1d¼€9€4€1°Z9d6d2d0°Y@°X@°W°V@°U°T@°S°R@°Q@°P°O@°N°M@°L°K@°J°I@°H@°G°F@°E°D@°C°B@°A@°@°?@°>°=@°<°;@°:@°9°8@°7°6@°5°4@°3°2@°1@°0°/@°.°-`€9€6€29d4d1d`°,°+@°*@°)°(@°'°&@°%°$@°#@°"°!@° °@°°@°°@°@°°@°°@°°@°@°°@°°@°° @° @° ° @° °@°°@°°@°@°°@°0€9€4€1Ã@°Zÿ/MTrkJËÿÿ!¹¹ ɹd¹¹ ɹd¹¹ ɹdž™$d™*d™,dp‰$‰*‰,™>dp‰>ƒ`™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Edp‰*‰E™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™Ed™$d™,d™>d™&dp‰E‰$‰,‰>‰&™,d™*dp‰,‰*™>d™,d™&dp‰>‰,‰&™Ed™$dp‰E‰$™*d™,d™,d™&dp‰*‰,‰,‰&™*d™,d™&dp‰*‰,‰&™,d™,d™>d™&dp‰,‰,‰>‰&™.Kp‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™$d™Edp‰>‰$‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,d™,d™&dp‰>‰,‰,‰&™,d™&d™.Kp‰,‰&‰.™,dp‰,™$d™,d™*dp‰$‰,‰*™>dp‰>™,d™.Kp‰,‰.p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>d™,d™&dp‰>‰,‰&™$d™,d™Ed™&dp‰$‰,‰E‰&™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,d™,d™&dp‰>‰,‰,‰&™$d™,d™&d™.Kp‰$‰,‰&‰.™,d™,d™&dp‰,‰,‰&™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™$d™Edp‰>‰$‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,d™,d™&dp‰,‰,‰&™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™$d™Edp‰>‰$‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,d™,d™&dp‰,‰,‰&p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™$d™,d™Ed™&dp‰>‰$‰,‰E‰&™*d™,dp‰*‰,™>d™,d™&dp‰>‰,‰&™$d™,d™Ed™&dp‰$‰,‰E‰&™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™,d™&d™.Kp‰,‰&‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™,d™$d™Ed™&dp‰>‰,‰$‰E‰&™*d™,dp‰*‰,™>d™,d™&dp‰>‰,‰&™Ed™$dp‰E‰$™*d™,d™,d™&dp‰*‰,‰,‰&™*d™,d™&dp‰*‰,‰&™>d™,d™,d™&dp‰>‰,‰,‰&™.Kp‰.™,d™,d™&dp‰,‰,‰&™,d™$d™*dp‰,‰$‰*™>dp‰>™,d™.Kp‰,‰.p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,d™,d™&dp‰>‰,‰,‰&™,d™&d™.Kp‰,‰&‰.™,dp‰,™,d™$d™*dp‰,‰$‰*™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™$d™>dp‰E‰$‰>™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>d™,d™&dp‰>‰,‰&™Ed™$d™,d™&dp‰E‰$‰,‰&™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™,d™$d™&d™.Kp‰,‰$‰&‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™$d™>dp‰E‰$‰>™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™$d™>dp‰E‰$‰>™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,d™,d™&dp‰,‰,‰&p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™$d™,d™>d™&dp‰E‰$‰,‰>‰&™,d™*dp‰,‰*™>d™,d™&dp‰>‰,‰&™Ed™$d™,d™&dp‰E‰$‰,‰&™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™,d™&d™.Kp‰,‰&‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™$d™Ed™>dp‰$‰E‰>™,d™*dp‰,‰*™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,d™&dp‰,‰&™*d™$d™,dp‰*‰$‰,™>dp‰>™,d™.Kp‰,‰.p™*d™,d™Ed™&dp‰*‰,‰E‰&™,dp‰,p™>d™$d™Edp‰>‰$‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™,d™*dp‰,‰*™*d™,d™&dp‰*‰,‰&™,d™>dp‰,‰>™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™Ed™>d™$dp‰E‰>‰$™,d™*dp‰,‰*™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,d™,d™&dp‰,‰,‰&p™*d™Ed™,d™&dp‰*‰E‰,‰&™,dp‰,p™>d™$d™,d™Ed™&dp‰>‰$‰,‰E‰&™*d™,dp‰*‰,™>d™,d™&dp‰>‰,‰&™$d™,d™Ed™&dp‰$‰,‰E‰&™*d™,dp‰*‰,™*d™,d™&dp‰*‰,‰&™>d™,dp‰>‰,™,d™&d™.Kp‰,‰&‰.™,d™,d™&dp‰,‰,‰&™$d™*d™,dp‰$‰*‰,™>dp‰>™,d™.Kp‰,‰.p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™$d™Edp‰$‰E™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™$d™*d™,dp‰$‰*‰,™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™$d™>d™Edp‰$‰>‰E™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,™*d™,d™$dp‰*‰,‰$™>dp‰>™,dp‰,p™*d™Edp‰*‰E™,dp‰,p™>d™Ed™$dp‰>‰E‰$™*d™,dp‰*‰,™>dp‰>™Ed™$dp‰E‰$™*d™,dp‰*‰,™*dp‰*™>d™,dp‰>‰,™.Kp‰.™,dp‰,¹d™$d™*d™,d0¹c¹b0‰$‰*‰,™>d`¹a‰>¹`™,d™.K@¹_0‰,‰.`¹^¹]™*d™Ed¹\`‰*‰E™,d0¹[@‰,¹Z¹Y`™$d™>d™Ed0¹X¹W0‰$‰>‰E™*d™,d¹V`‰*‰,™>d0¹U¹T0‰>™$d™Ed`¹S‰$‰E¹R™*d™,d@¹Q0‰*‰,™*d`¹P‰*¹O™>d™,d¹N`‰>‰,™.K0¹M@‰.¹L™,d¹K`‰,™*d™,d™$d0¹J¹I0‰*‰,‰$™>d¹H`‰>™,d0¹G¹F0‰,`¹E¹D™*d™Ed@¹C0‰*‰E™,d`¹B‰,¹A¹@`™Ed™>d™$d0¹?@‰E‰>‰$¹>™,d™*d¹=`‰,‰*™>d0¹<¹;0‰>™Ed™$d¹:`‰E‰$™*d™,d0¹9¹80‰*‰,™*d`¹7‰*¹6™>d™,d@¹50‰>‰,™.K`¹4‰.¹3™,d¹2`‰,™$d™*d™,d0¹1@‰$‰*‰,¹0™>d¹/`‰>™,d0¹.¹-0‰,`¹,™*d™Ed0¹+¹*0‰*‰E™,d`¹)‰,¹(@¹'0™$d™Ed™>d`¹&‰$‰E‰>¹%™,d™*d¹$`‰,‰*™>d0¹#@‰>¹"™$d™Ed¹!`‰$‰E™*d™,d0¹ ¹0‰*‰,™*d`¹‰*™>d™,d0¹¹0‰>‰,™.K`¹‰.¹™,d@¹0‰,™*d™,d™$d`¹‰*‰,‰$¹™>d¹`‰>™,d0¹@‰,¹¹`™*d™Ed0¹¹0‰*‰E™,d`¹‰,0¹¹0™Ed™>d™$d`¹ ‰E‰>‰$¹ ™,d™*d@¹ 0‰,‰*™>d`¹ ‰>¹ ™Ed™$d¹`‰E‰$™*d™,d0¹@‰*‰,¹™*d¹`‰*™>d™,d0¹¹0‰>‰,™.K`¹‰.™,d0¹¹0‰,Ã@¹dÿ/MTrk „ÿÿ!Â0²nÂ0²nÂ0²n² I…íD²`’]d’Qd<’U‚U4‚]‚Q’Pd’\d‡@‚P‚\’Nd’Zd‡@‚N‚Z’Ld’Xd‚L‚X²n’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‚S‚_’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‹ ‚S‚_’Qd’]dp‚Q‚]’Pd’\dp‚P‚\’Qd’]d†H‚Qx‚]²i’Id’Udp‚I‚U’Ld’Xdp‚L‚X’Nd’Zdp‚N‚Z’Pd’\dp‚P‚\’]d’Qd‚]‚Q’Pd’\d‡@‚P‚\’Nd’Zd‡@‚N‚Z’Ld’Xd‚L‚X²n’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‚S‚_’Pd’\d‡@‚P‚\’Qd’]d‡@‚Q‚]’Ud’ad<²n0²m`²l`²k`²j`²i0²h`²g`²f`²e`²d0²c`²b`²a`²``²_0²^`²]`²\`²[`²Z0²Y`²X`²W`²V`²U0²T`²S`²R`²Q`²P0²O`²N`²M`²L`²K0²J`²I`²H`²G`²F0²E`²D`²C`²B`²A0²@`²?`²>`²=`²<`²;0²:`²9`²8`²7`²60²5`²4`²3`²2`²10²0`²/`².`²-`²,0²+`²*`²)`²(`²'0²&`²%`²$`²#`²"0²!`² `²`²`²0²`²`²`²`²0²`²`²`²`²0²`²`²`²`²0² `² `² `² `² `²0²`²`²`²`²0²`²`²`‚U‚a‡@²n…Œ²`’Qd’]d<’U‚U4‚Q‚]’Pd’\d‡@‚P‚\’Nd’Zd‡@‚N‚Z’Ld’Xd‚L‚X²n’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‚S‚_’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‹ ‚S‚_’Qd’]dp‚Q‚]’Pd’\dp‚P‚\’Qd’]d†H‚Qx‚]²i’Id’Udp‚I‚U’Ld’Xdp‚L‚X’Nd’Zdp‚N‚Z’Pd’\dp‚P‚\’]d’Qd‚]‚Q’Pd’\d‡@‚P‚\’Nd’Zd‡@‚N‚Z’Ld’Xd‚L‚X²n’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‚S‚_’Pd’\d‡@‚P‚\’Qd’]d‡@‚Q‚]’Ud’ad‡@‚U‚a’Sd’_d‡@‚S‚_’Qd’]d‡@‚Q‚]’Sd’_d‡@‚S‚_²`’]d’Qd‚]‚Q’Pd’\d‡@‚P‚\’Nd’Zd‡@‚N‚Z’Ld’Xd‚L‚X²n’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‚S‚_’Ud’ad‡@‚U‚a’Qd’]d‡@‚Q‚]’Sd’_d‹ ‚S‚_’Qd’]dp‚Q‚]’Pd’\dp‚P‚\’Qd’]d†H‚Qx‚]²i’Ud’Idp‚U‚I’Xd’Ldp‚X‚L’Zd’Ndp‚Z‚N’\d’Pdp‚\‚P’]d’Qd‚]‚Q’\d’Pd‡@‚\‚P’Zd’Nd‡@‚Z‚N’Xd’Ld‚X‚L²n’ad’Ud‡@‚a‚U’]d’Qd‡@‚]‚Q’_d’Sd‚_‚S’\d’Pd‡@‚\‚P’]d’Qd‡@‚]‚Q’ad’Ud<²n0²m`²l`²k`²j`²i0²h`²g`²f`²e`²d0²c`²b`²a`²``²_0²^`²]`²\`²[`²Z0²Y`²X`²W`²V`²U0²T`²S`²R`²Q`²P0²O`²N`²M`²L`²K0²J`²I`²H`²G`²F0²E`²D`²C`²B`²A0²@`²?`²>`²=`²<`²;0²:`²9`²8`²7`²60²5`²4`²3`²2`²10²0`²/`².`²-`²,0²+`²*`²)`²(`²'0²&`²%`²$`²#`²"0²!`² `²`²`²0²`²`²`²`²0²`²`²`²`²0²`²`²`²`²0² `² `² `² `² `²0²`²`²`²`²0²`²`²`‚a‚U‡@²n¬@ÿ/MTrk ¤ÿÿ!ódódód…г Žã@Z“!dƒ!“-dƒ-<“+dƒ+“,dƒ,<“+dƒ+ãBA“*dãFEãGã(Hã9IãBJãKã'IãDCã@ãZ9ãD3ã7.ƒ*ãn)ãH%“)dƒ)ã@“(d*ãEDãGã*Jã;KãCKãKãhIãGãlDã6Bã@ã:=ãv7ã2ã,ã&ã] ã; ƒ( ã'0“'dƒ'ã@“&dƒ&Z“%dƒ%Z“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dpƒàD“*dƒ*“,dƒ,“-d4ƒ-<“,d4ƒ,<“*dƒ$ƒ*<“(dƒ$ƒ(<“&d4ƒ&<“%d4ƒ%<“&d™dƒ&<“%dƒ$ƒ%<“&d™dƒ&<“%d4ƒ%<“#d4ƒ#<“!d™dƒ!<“ dƒ$ƒ <“!dŠdƒ!“$dƒ$“%dpƒ%p“!d„Xƒ!x“%d„Xƒ%x“(dƒ$ƒ(<“&d™dƒ&<“%dƒ$ƒ%<“&d™dƒ&<“%d4ƒ%<“#d4ƒ#<“!d™dƒ!<“ dƒ$ƒ <“!dŠdƒ!<“ dƒ$ƒ <“!dƒ$ƒ!<“ d4ƒ <“-d‚hƒ-x“!d4ƒ!<“(dƒ$ƒ(<“&d™dƒ&<“%dƒ$ƒ%<“&d™dƒ&<“%d4ƒ%<“#d4ƒ#<“!d™dƒ!<“ dƒ$ƒ <“!dŠdƒ!“$dƒ$“%dpƒ%p“!d„Xƒ!x“%d„Xƒ%x“(dƒ$ƒ(<“&d™dƒ&<“%dƒ$ƒ%<“&d™dƒ&<“%d4ƒ%<“#d4ƒ#<“!d™dƒ!<“ dƒ$ƒ <“!dŠdƒ!<“*dpƒ*“%d,ƒ%&“!dƒ! ã@“-dƒ-Z“,dƒ,F“+dƒ+“*dãBAãHGã IãkJã]LãMãpKãIãNDã?ãZ7ã0ƒ*ãQ(ãw"(“)dƒ)ã@“(d*ãEDãGã*Jã;KãCKãKãhIãGãlDã6Bã@ã:=ãv7ã2ã,ã&ã] ã; ƒ( ã':“'dƒ'ã@“&dƒ&Z“%dƒ%Z“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“d4ƒ<“d4ƒ<“*dƒ$ƒ*<“(dƒ$ƒ(<“(dpƒ(“dpƒ“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“(dpƒ(“dn“dƒƒ"ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dƒ$ƒ&<“dƒ$ƒ<“&dpƒ&“dpƒ“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dƒ$ƒ(<“dƒ$ƒ<“(dpƒ(“dpƒ“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dxƒx“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dƒ$ƒ*<“dƒ$ƒ<“*dpƒ*“dpƒðÿ/MTrkÿÿ!Äk´U´ S…д ”9@0´ 0´ „9´ 0´ 0´ ”;D0´ 0´ „;´ 0´ 0´ ”=H0´ 0´ „=´ 0´ 0´ ”@M0´ 0´ „@´ 0´ ´ ´ ”=Q0´ 0´ „=´ 0´ 0´ ”@V0´ 0´ „@´ #0´ %0´ '”BZ0´ *0´ ,„B´ /0´ 10´ 3”E_0´ 60´ 8„E´ :0´ =0´ ?”@d´ 0´ #0´ %„@(”Bd´ (0´ *0´ -„B´ / ”Ed$´ 20´ 4$„E ´ 7”Bd´ :0´ <0´ ?„B(”Ed´ A0´ D0´ F„E´ I ”Gd$´ K0´ N$„G ´ Q´ @”Ed0´ C0´ G„E”Gd´ J0´ M0„G´ Q”Id0´ T0´ W„I”Ld´ [0´ ^´ `„L´ O”Id0´ T0´ Z„I”Ld´ _0´ e0„L´ j”Nd0´ p0´ u„N”Qd´ {$´ (´ „Q”B@´ ~0´ },„B´ |0´ {0´ z0´ y0´ x0´ w0´ v0´ u”E@´ t0´ r,„E´ q0´ p0´ o0´ n0´ m0´ l0´ k0´ j”I@´ i0´ h,„I´ g0´ f0´ e0´ d0´ c0´ b0´ a0´ `”E@´ _0´ ^,„E´ ]0´ \0´ [0´ Y0´ X0´ W0´ V0´ U0´ T0´ S0´ R0´ Q0´ P0´ O0´ N0´ M0´ L0´ K0´ J0´ I0´ H0´ G0´ F0´ E0´ D0´ C0´ A0´ @ƒt”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”E@x„E‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”E@x„E‚h”I@x„I‚h”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h´ A”I@0´ @0´ ?„I´ >0´ =0´ <0´ :0´ 90´ 80´ 70´ 6”E@0´ 50´ 4„E´ 30´ 20´ 10´ 00´ /0´ -0´ ,0´ +0´ *0´ )0´ (0´ '0´ &0´ %0´ $0´ #0´ "0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ ”E@0´ 0´ „E´ 0´ 0´ ”B@0´ 0´ „B´ 0´ 0´ ”9@0´ 0´ „9´ 0´ 0´ ”;D0´ 0´ „;´ 0´ 0´ ”=H0´ 0´ „=´ 0´ 0´ ”@L0´ 0´ „@´ 0´ ´ ´ ”=Q0´ 0´ „=´ 0´ 0´ ”@U0´ 0´ „@´ #0´ %0´ '”BY0´ *0´ ,„B´ /0´ 10´ 3”E^0´ 60´ 8„E´ :0´ =0´ ?”@d´ 0´ #0´ %„@(”Bd´ (0´ *0´ -„B´ / ”Ed$´ 20´ 4$„E ´ 7”Bd´ :0´ <0´ ?„B(”Ed´ A0´ D0´ F„E´ I ”Gd$´ K0´ N$„G ´ Q´ @”Ed0´ C0´ G„E”Gd´ J0´ M0„G´ Q”Id0´ T0´ W„I”Ld´ [0´ ^´ `„L´ O”Id0´ T0´ Z„I”Ld´ _0´ e0„L´ j”Nd0´ p0´ u„N”Qd´ {$´ (´ „Q´ ~0´ }0´ |0´ {0´ z0´ y0´ x0´ w0´ v0´ u0´ t0´ r0´ q0´ p0´ o0´ n0´ m0´ l0´ k0´ j0´ i0´ h0´ g0´ f0´ e0´ d0´ c0´ b0´ a0´ `0´ _0´ ^0´ ]0´ \0´ [0´ Y0´ X0´ W0´ V0´ U0´ T0´ S0´ R0´ Q0´ P0´ O0´ N0´ M0´ L0´ K0´ J0´ I0´ H0´ G0´ F0´ E0´ D0´ C0´ A0´ @…›T´ ”9@0´ 0´ „9´ 0´ 0´ ”;D0´ 0´ „;´ 0´ 0´ ”=H0´ 0´ „=´ 0´ 0´ ”@M0´ 0´ „@´ 0´ ´ ´ ”=Q0´ 0´ „=´ 0´ 0´ ”@V0´ 0´ „@´ #0´ %0´ '”BZ0´ *0´ ,„B´ /0´ 10´ 3”E_0´ 60´ 8„E´ :0´ =0´ ?”@d´ 0´ #0´ %„@(”Bd´ (0´ *0´ -„B´ / ”Ed$´ 20´ 4$„E ´ 7”Bd´ :0´ <0´ ?„B(”Ed´ A0´ D0´ F„E´ I ”Gd$´ K0´ N$„G ´ Q´ @”Ed0´ C0´ G„E”Gd´ J0´ M0„G´ Q”Id0´ T0´ W„I”Ld´ [0´ ^´ `„L´ O”Id0´ T0´ Z„I”Ld´ _0´ e0„L´ j”Nd0´ p0´ u„N”Qd´ {$´ (´ „Q”B@´ ~0´ },„B´ |0´ {0´ z0´ y0´ x0´ w0´ v0´ u”E@´ t0´ r,„E´ q0´ p0´ o0´ n0´ m0´ l0´ k0´ j”I@´ i0´ h,„I´ g0´ f0´ e0´ d0´ c0´ b0´ a0´ `”E@´ _0´ ^,„E´ ]0´ \0´ [0´ Y0´ X0´ W0´ V0´ U0´ T0´ S0´ R0´ Q0´ P0´ O0´ N0´ M0´ L0´ K0´ J0´ I0´ H0´ G0´ F0´ E0´ D0´ C0´ A0´ @ƒt”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”E@x„E‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”E@x„E‚h”I@x„I‚h”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h´ A”I@0´ @0´ ?„I´ >0´ =0´ <0´ :0´ 90´ 80´ 70´ 6”E@0´ 50´ 4„E´ 30´ 20´ 10´ 00´ /0´ -0´ ,0´ +0´ *0´ )0´ (0´ '0´ &0´ %0´ $0´ #0´ "0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ ”E@0´ 0´ „E´ 0´ 0´ ”B@0´ 0´ „B´ 0´ 0´ ”9B0´ 0´ „9´ 0´ 0´ ”;C0´ 0´ „;´ 0´ 0´ ”=E0´ 0´ „=´ 0´ 0´ ”@F0´ 0´ „@´ 0´ ´ ´ ”=H0´ 0´ „=´ 0´ 0´ ”@I0´ 0´ „@´ #0´ %0´ '”BK0´ *0´ ,„B´ /0´ 10´ 3”EL0´ 60´ 8„E´ :0´ =0´ ?”@N´ 0´ #0´ %„@(”BO´ (0´ *0´ -„B´ / ”EP$´ 20´ 4$„E ´ 7”BQ´ :0´ <0´ ?„B(”ER´ A0´ D0´ F„E´ I ”GS$´ K0´ N$„G ´ Q´ @”ET0´ C0´ G„E”GU´ J0´ M0„G´ Q”IV0´ T0´ W„I”LV´ [0´ ^´ `„L´ O”IW0´ T0´ Z„I”LX´ _0´ e0„L´ j”NY0´ p0´ u„N”QY´ {$´ (´ „Q”B@´ ~0´ },„B´ |0´ {0´ z0´ y0´ x0´ w0´ v0´ u”E@´ t0´ r,„E´ q0´ p0´ o0´ n0´ m0´ l0´ k0´ j”I@´ i0´ h,„I´ g0´ f0´ e0´ d0´ c0´ b0´ a0´ `”E@´ _0´ ^,„E´ ]0´ \0´ [0´ Y0´ X0´ W0´ V0´ U0´ T0´ S0´ R0´ Q0´ P0´ O0´ N0´ M0´ L0´ K0´ J0´ I0´ H0´ G0´ F0´ E0´ D0´ C0´ A0´ @ƒt”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”E@x„E‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”N@x„N‚h”I@x„I‚h”E@x„E†H”B@x„B‚h”E@x„E‚h”I@x„I‚h”E@x„EŽ”E@x„Ex”B@x„Bx”D@x„D‚h”G@x„G‚h”L@x„L‚h”G@x„GŽ”G@x„Gx”D@x„Dx”B@x„B‚h”E@x„E‚h´ A”I@0´ @0´ ?„I´ >0´ =0´ <0´ :0´ 90´ 80´ 70´ 6”E@0´ 50´ 4„E´ 30´ 20´ 10´ 00´ /0´ -0´ ,0´ +0´ *0´ )0´ (0´ '0´ &0´ %0´ $0´ #0´ "0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ 0´ ”E@0´ 0´ „E´ 0´ 0´ ”B@0´ 0´ „B´ 0´ 0´ ”9@0´ 0´ „9´ 0´ 0´ ”;D0´ 0´ „;´ 0´ 0´ ”=H0´ 0´ „=´ 0´ 0´ ”@L0´ 0´ „@´ 0´ ´ ´ ”=Q0´ 0´ „=´ 0´ 0´ ”@U0´ 0´ „@´ #0´ %0´ '”BY0´ *0´ ,„B´ /0´ 10´ 3”E^0´ 60´ 8„E´ :0´ =0´ ?”@d´ 0´ #0´ %„@(”Bd´ (0´ *0´ -„B´ / ”Ed$´ 20´ 4$„E ´ 7”Bd´ :0´ <0´ ?„B(”Ed´ A0´ D0´ F„E´ I ”Gd$´ K0´ N$„G ´ Q´ @”Ed0´ C0´ G„E”Gd´ J0´ M0„G´ Q”Id0´ T0´ W„I”Ld´ [0´ ^´ `„L´ O”Id0´ T0´ Z„I”Ld´ _0´ e0„L´ j”Nd0´ p0´ u„N”Qd´ {$´ (´ „Q´ ~0´ }0´ |0´ {0´ z0´ y0´ x0´ w0´ v0´ u0´ t0´ r0´ q0´ p0´ o0´ n0´ m0´ l0´ k0´ j0´ i0´ h0´ g0´ f0´ e0´ d0´ c0´ b0´ a0´ `0´ _0´ ^0´ ]0´ \0´ [0´ Y0´ X0´ W0´ V0´ U0´ T0´ S0´ R0´ Q0´ P0´ O0´ N0´ M0´ L0´ K0´ J0´ I0´ H0´ G0´ F0´ E0´ D0´ C0´ A0´ @ÙTÿ/MTrk>ÿÿ!Ç·dÇ·d…î—"d¡`‡"‡ž —"dž‡"Ò—"dš ‡"ƒÅ`ÿ/MTrkÂÿÿ!¸ @ȸx¸ @È`¸d¸ @Èb¸K¸ ;‚Š ˜adpˆa˜_dpˆ_˜]#˜adˆ]‡@ˆaƒ`˜_dpˆ_˜adpˆa˜bd…Pˆb˜ad…Pˆa˜adƒ`ˆa˜ad…Pˆa˜_d…Pˆ_˜]dpˆ]p˜_b‰0ˆ_p˜dd˜a2ƒ`ˆdˆa˜a2˜ddƒ`ˆa¡`ˆdƒ`˜adpˆa˜_dpˆ_˜ad–@ˆaƒ`˜_dpˆ_˜adpˆa˜bd…Pˆb˜ad…Pˆa˜adƒ`ˆa˜ad…Pˆa˜_d…Pˆ_˜]dƒ`ˆ]˜Zdƒ`ˆZ˜\dƒ`ˆ\˜]dƒ`ˆ]˜_dƒ`ˆ_˜adƒ`ˆa˜_dpˆ_˜_d…Pˆ_˜]d‚nˆ]r˜_d‡ˆ_9˜]d†oˆ]Q˜_d”Pˆ_p˜]d‡@ˆ]˜]d…Pˆ]˜\d…Pˆ\˜Zdƒ`ˆZ˜Xd‡@ˆX˜Zd‡@ˆZ˜Ud‹ ˆU˜UdpˆU˜VdpˆV˜Xd…PˆX˜Vd…PˆV˜Udƒ`ˆU˜Sd© ˆS‹ ˜]d‡@ˆ]˜]d…Pˆ]˜\dƒ`ˆ\p˜Zdƒ`ˆZ˜\d‹ ˆ\˜\dpˆ\˜ZdpˆZ˜X#˜\d…PˆXˆ\˜Z#˜]d…PˆZˆ]˜\#˜_dpˆ\ˆ_p˜]#˜ad‚hˆ]xˆa˜_d˜\#ƒ`ˆ_ˆ\˜\#˜_d†Hˆ\xˆ_˜]#˜ad‚hˆ]xˆa˜\#˜_dpˆ\ˆ_˜\#˜_d„Xˆ\xˆ_˜]#˜adƒ`ˆ]ˆa˜bd˜]#…Pˆbˆ]˜dd˜a#…Pˆdˆa˜dd˜a#ƒ`ˆdˆa˜dd˜a#‹ ˆdˆaƒà˜adpˆa˜_dpˆ_˜]#˜adˆ]‡@ˆaƒ`˜_dpˆ_˜adpˆa˜bd…Pˆb˜ad…Pˆa˜adƒ`ˆa˜ad…Pˆa˜_d…Pˆ_˜]dpˆ]p˜_d‰0ˆ_p˜dd˜a2ƒ`ˆdˆa˜a2˜ddƒ`ˆa£Pˆdp˜adpˆa˜_dpˆ_˜]d˜adˆ]‡@ˆaƒ`˜_dpˆ_˜adpˆa˜bd…Pˆb˜ad…Pˆa˜adƒ`ˆa˜ad…Pˆa˜_d…Pˆ_˜]dƒ`ˆ]˜Zdƒ`ˆZ˜\dƒ`ˆ\˜]dƒ`ˆ]˜_dƒ`ˆ_˜adƒ`ˆa˜_dpˆ_˜_d…Pˆ_˜]dpˆ]p˜_d‡@ˆ_˜]d‡@ˆ]˜_d‡@ˆ_˜]d‡@ˆ]˜]d…Pˆ]˜\d…Pˆ\˜Zdƒ`ˆZ˜Xd‡@ˆX˜Zd‡@ˆZ˜Ud‹ ˆU˜UdpˆU˜VdpˆV˜Xd…PˆX˜Vd…PˆV˜Udƒ`ˆU˜Sd© ˆS‹ ˜]d‡@ˆ]˜]d…Pˆ]˜\dƒ`ˆ\p˜Zdƒ`ˆZ˜\d‹ ˆ\˜\dpˆ\˜ZdpˆZ˜X#˜\d…PˆXˆ\˜Z#˜]d…PˆZˆ]˜\#˜_dpˆ\ˆ_p˜]2˜ad‚hˆ]xˆa˜_d˜\2pˆ_ˆ\p˜\2˜_d†Hˆ\xˆ_˜]2˜ad‚hˆ]xˆa˜\2˜_dpˆ\ˆ_˜\2˜_d„Xˆ\xˆ_˜]2˜adpˆ]pˆa˜]2˜bd…Pˆ]ˆb˜a2˜dd…Pˆaˆd˜a2˜ddƒ`ˆaˆd˜a2˜dd‹ ˆaˆd„˜aPpˆa˜dPpˆd˜fP…Pˆf˜dP…Pˆd˜aPƒ`ˆa˜dPƒ`ˆd˜fPpˆf˜fPpˆf˜_#˜hP…Pˆ_pˆh˜iP˜a#–@ˆiˆaÿ@ÿ/MTrk ÿÿ!Ê º2Ê º2Ê º2º Yž šBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠB‚€pšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšGdpŠGpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBƒðpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGpšIdpŠIpšBdpŠBpšGdpŠGRº2šBdRº1ŠBpšGdº0^ŠGBº/.šId"º.NŠIRº-šBdpŠBBº,.šGdrº+~ŠG"º*NšIdpŠIº)^šBdBº(.ŠBrº'~šGdRº&ŠGpšIdº%^ŠIrº$~šBd"º#NŠBRº"šGdpŠGBº!.šIdrº ~ŠIRºšBdpŠBº^šGdBº.ŠG"ºNšIdRºŠIpšBdº^ŠBrº~šGd"ºNŠGpšIdº^ŠIBº.šBdrº~ŠBRºšGdpŠGº^šIdBº.ŠI"ºNšBdRºŠBpšGdBº.ŠGrº~šId"º NŠIpšBdº ^ŠBBº .šGd"º NŠGRº šIdpŠIº^šBdrº~ŠB"ºNšGdRºŠGpšIdBº.ŠIrº~šBdRºŠBpšGdº^ŠGBºÄPº2ÿ/MTrk* ÿÿ!Ë »KË »KË »K» Jœ8ëG>R›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›B@›Ldp‹B‹Lp›E@›Idp‹E‹I›B@›Ldp‹B‹Lƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›B@›Ldp‹B‹Lp›E@›Idp‹E‹I›B@›Ldp‹B‹Lƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›B@›Ldp‹B‹Lp›E@›Idp‹E‹I›B@›Ldp‹B‹Lƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›B@›Ldp‹B‹Lp›E@›Idp‹E‹I›B@›Ldp‹B‹Lƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹B›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›Id›@@p‹I‹@p›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹B‡@›>@›Ldp‹>‹Lp›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›>@›Ldp‹>‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›Ld›>@p‹L‹>p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›Nd›E@p‹N‹Ep›B@›Ldp‹B‹Lp›E@›Ndp‹E‹N›B@›Idp‹B‹Iƒ`›@@p‹@p›Ld›=@p‹L‹=p›Id›@@p‹I‹@p›Ld›B@p‹L‹Bp›E@p‹Ep›Ld›B@p‹L‹Bp›Id›E@p‹I‹E›Ld›B@p‹L‹Bƒ`›@@p‹@p›=@›Ldp‹=‹Lp›@@›Idp‹@‹Ip›B@›Ldp‹B‹Lp›E@›Ndp‹E‹Np›Ld›B@p‹L‹Bp›Nd›E@p‹N‹E›Id›B@p‹I‹Bƒ`›@@p‹@R»K›Ld›>@»J^‹L‹>»I@»H›Id›@@"»GN‹I‹@r»F~›Ld›B@r»E~‹L‹BB»D.›E@»C^‹E»B@»A›Ld›B@"»@N‹L‹Br»?~›Id›E@r»>~‹I‹E›Ld›B@B»=.‹L‹B»@r»7~‹L‹>B»6.›Id›@@»5^‹I‹@»4@»3›Ld›B@"»2N‹L‹Br»1~›Nd›E@r»0~‹N‹EB»/.›B@›Ld».^‹B‹L»-@»,›E@›Nd"»+N‹E‹N›B@›Idr»*~‹B‹Ir»)@»(.›@@»'^‹@»&@»%›Ld›=@"»$N‹L‹=r»#~›Id›@@r»"~‹I‹@B»!.›Ld›B@» ^‹L‹B»@»›E@"»N‹Er»~›Ld›B@r»~‹L‹BB».›Id›E@»^‹I‹E›Ld›B@»@»‹L‹B"»@»~›@@r»~‹@B».›=@›Ld»^‹=‹L»@»›@@›Id"»N‹@‹Ir»~›B@›Ldr» ~‹B‹LB» .›E@›Nd» ^‹E‹N» @» ›Ld›B@"»N‹L‹Br»~›Nd›E@r»~‹N‹E›Id›B@B».‹I‹B»p»@»›@@"»N‹@r»Ä »Kÿ/MTrkòÿÿ!Ì2¼d¼ iž œQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdœLdpŒUŒQŒLpœVdœQdœNdpŒVŒQŒNpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdœLdpŒUŒQŒLpœVdœQdœNdpŒVŒQŒNpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdœLdpŒUŒQŒLpœVdœQdœNdpŒVŒQŒNpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdœLdpŒUŒQŒLpœVdœQdœNdpŒVŒQŒNpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdœLdpŒUŒQŒLpœVdœQdœNdpŒVŒQŒNpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœNdœQdœVd…PŒNŒQŒVpœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœQdœUdpŒQŒU…PœUdœQdpŒUŒQpœVdœQdpŒVŒQRœaKœQdœUdpŒUŒQ…PœQdœUdpŒUŒQ…PœQdœUdpŒUŒQ…PœQdœUdpŒUŒQ…2Œaœ_AœQdœUdpŒUŒQ…PœQdœUdpŒUŒQ…2Œ_œ]7œQdœUdpŒUŒQ…PœNdœQdœVd…PŒVŒQŒNRŒ]œZ2œQdœUdpŒUŒQ…PœQdœUdpŒUŒQ…2ŒZœ\<œQdœUdpŒUŒQ…2Œ\œQdœUdœaœQdœUd"¼=NŒQŒUB¼<¼;¼:¼9@¼8œNdœQdœVdr¼7¼6¼5¼4.ŒNŒQŒV¼3¼2NœQdœUdB¼1¼0ŒQŒUr¼/@¼.¼-¼,~œQdœUd¼+¼*NŒQŒUr¼)¼(¼'¼&¼%œQdœUd"¼$NŒQŒUB¼#¼"¼!¼ @¼œQdœUdr¼~ŒQŒU¼¼¼@¼¼NœQdœUdB¼¼ŒQŒUr¼@¼¼¼~œQdœUd¼¼NŒQŒUr¼¼¼¼ ¼ œQdœUd"¼ NŒQŒUB¼ ¼ ¼¼@¼œUdœQdœLdr¼~ŒUŒQŒL¼¼NœVdœQdœNdB¼.ŒVŒQŒN¼¼Ãp¼dÿ/MTrk­ÿÿ!ͽx½ ;‚Š UnpUSnpSUn–@Uƒ`SnpSUnpUVn…PVUnƒ`UpUnpUpUn…PUSn…PSQnpQpSn‰0SRVIVXnpXpXnXœUnpUSnpSUn–@Uƒ`SnpSUnpUVn…PVUnƒ`UpUnpUpUn…PUSn…PSQnƒ`QNnƒ`NPnƒ`PQnƒ`QSnƒ`SUnƒ`USn3S=Sn…PSQn‚nQrSn‡S9Qn†oQQSn‡@SQn…PQpQn…PQPn…PPNnƒ`NLn‡@LNn‡@NIn‰0IpInpIJnpJLn…PLJn…PJInƒ`IGnG§0Qn…PQpQn…PQPnƒ`PpNnƒ`NPn‹ PPnpPNnpNPnL-…PPLQnN-…PQNSnP-pSPpQ-Un‚hQxUSnP-pSPpP-Sn†HPxSQ-Un‚hQxUP-SnxPxSP-Sn„XPxSQ-UnxQ‚hUQ<V…2WIQVWU<Xnƒ`UXpUKXxpUXpUUX}‹ UXƒàUnpUSnpSUn–@Uƒ`SnpSUnpUVn…PVUnƒ`UpUnpUpUn…PUSn…PSQnpQpSn‰0SRVIVXnpXpXnXœUnpUSnpSUn–@Uƒ`SnpSUnpUVn…PVUnƒ`UpUnpUpUn…PUSn…PSQnƒ`QNnƒ`NPnƒ`PQnƒ`QSnƒ`SUnƒ`USnpSSn…PSQnpQpSn‡@SQn‡@QSn‡@SQn…PQpQn…PQPn…PPNnƒ`NLn‡@LNn‡@NIn‰0IpInpIJnpJLn…PLJn…PJInƒ`IGnG§0Qn…PQpQn…PQPnƒ`PpNnƒ`NPn‹ PPnpPNnpNPnL-…PPLQnN-…PQNSnP-pSPpQ<Un‚hQxUSnPdŸEd ŸIdH>E I‡½hŸ>dŸEd ŸIdH>E IõFŸPUPŸJ1ŸQd…PJxQxŸI/ŸLd…PIxLxŸJ.ŸQd…PJxQxŸJ*ŸPd…PJxPxŸL/ŸQd…PLxQxŸN+ŸSdpNxSxŸP(ŸUd…PPxUxŸS2ŸXdpSxXxŸN2ŸSd‰0NxSxŸQdŸN2xQxNŸSdŸP2xSxPŸQ2ŸUd…PQxUxŸQ2ŸVd…PQxVxŸS2ŸXd‰0SxXxŸVdŸQ2xVxQŸUdŸP2xUxPŸQ2ŸVd…PQxVxŸUdxUxŸSdxSxŸQdxQxŸPdxPxŸJ2ŸNd…PJxNxŸJ1ŸQd…PJxQxŸLd†HLxŸJ.ŸQd…PJxQxŸJ*ŸPd…PJxPxŸL/ŸQd…PLxQxŸN+ŸSdpNxSxŸP(ŸUd…PPxUxŸQdxQxŸSdxSxŸPdˆ8P‚hŸQdxQxŸSdxSxŸI*ŸPd…PIxPxŸE*ŸLd…PExLxŸI*ŸNdœIxNñÿ/simutrans-124.3/simutrans/music/46-House-in-the-station.mid000066400000000000000000002204731474050137200235760ustar00rootroot00000000000000MThdÀMTrkÿÿQSÿXÿYÿ/MTrkÿ System Setupÿ!•Èÿ/MTrk@ÿÿ!¼° iÀ°Nx€N° Nx€N° iN2x€N° NJx€N° iNcx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iž° ž° iž° ž° iž° ž° iž° ž° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° ž° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iNdx€N° Ndx€N° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iž° ž° iøÿ/MTrk?xÿÿ!±± ÁW¼±e±d±e±d±±d‘d‘#d± +\#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘(dp(p‘ d‘,d„á@á@á ?á ?áo>áo>á>á>á)=á)=á2<á2<á6;á6;á8:á8:áx8áx8áW7áW7á6á6á4á4á$0á$0á%+á%+á"%á"% ,áááádá@á@‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘(dp(p‘ d‘,d4 ,<‘d‘#d4#<‘c‘(c4(<‘ d‘,d4 ,<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘#dp#‘d‘%dp%p‘d‘%dx%Z‘d‘#d#á'&á'&‘%d‘1dá/.á/.á43á43áx7áx7á;á;áN=áN=á@á@áE@áE@(áFEáFEáGFáGFáGáGáZDáZDá-Bá-Bá@á@áy=áy=á;á;áh8áh8áM5áM5á~1á~1áU.áU.á~*á~*áP&áP&áw!áw!áHáHá/á/á á áWáWá0 á0 á á áPáPá(á(áTáT%1ájáj<áBAáBA‘d‘%dxá@á@x%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%d4%<‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dx)x‘d‘)dp)p‘d‘"dp"‘d‘)dp)‘"d‘.d4".<‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%d4%<‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dp)‘d‘*dp*p‘d‘*d4*<‘*d‘6d4*6<‘d‘*d4*<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#–^‘d‘+d+‘ d‘,d„Dá@á@á@á@á@á@á ?á ?áo>áo>áW>áW>á >á >ác<ác<á :á :á_5á_5áD/áD/át)át)á"á"á á < ,<á@á@‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘(dp(p‘ d‘,d4 ,<‘d‘#d4#<‘c‘(c4(<‘ d‘,d4 ,<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘!dp!‘d‘(dp(‘#d‘/d4#/<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘!dp!p‘d‘ dp ‘d‘!dp!p‘d‘#dp#p‘d‘#d4#<‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘ dp ‘d‘!dp!‘d‘(dp(p‘d‘!dp!‘d‘(dp(p‘d‘ dp ‘d‘#dp#‘d‘%dp%p‘d‘%dx%x‘%d‘1dp%1‘#d‘/dp#/‘d‘"dp"‘ d‘,d4 ,<‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#dp#‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dx)x‘d‘)dp)p‘d‘"dp"‘d‘)dp)‘"d‘.dp".‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#dp#‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dx)x‘d‘)dp)p‘d‘"dp"‘d‘)dp)‘"d‘.dp".‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#dp#‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dx)x‘d‘)dp)p‘d‘"dp"‘d‘)dp)‘"d‘.dp".‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#d4#<‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dp)‘d‘*dp*p‘d‘*d4*<‘*d‘6d4*6<‘d‘*d4*<‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#dp#‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dx)x‘d‘)dp)p‘d‘"dp"‘d‘)dp)‘"d‘.dp".‘d‘%dp%‘d‘'dp'‘"d‘.dp".p‘d‘'dp'‘"d‘.dp".p‘d‘%dp%‘d‘'dp'p‘d‘%dp%‘d‘'dp'p‘d‘%dp%p‘d‘%dp%‘d‘"dp"‘d‘#dp#‘d‘*dp*p‘d‘#dp#‘d‘*dp*p‘d‘"dp"‘d‘#dp#p‘d‘"dp"‘d‘#dp#p‘d‘%dp%‘d‘*dp*‘#d‘/dp#/‘d‘#dp#‘d‘%dp%‘ d‘,dp ,p‘d‘%dp%‘ d‘,dp ,p‘d‘#dp#‘d‘%dp%p‘d‘#dp#‘d‘%dp%p‘d‘#dp#p‘d‘#dp#‘d‘)dp)‘d‘*dp*‘%d‘1dp%1p‘d‘*dp*‘%d‘1dp%1p‘d‘)dp)‘d‘*dp*p‘d‘)dp)‘d‘*dp*p‘d‘*dx*x‘d‘*d4á@á@á@á@á@á@á8?á8?á ?á ?á?á?áo>áo>áW>áW>áK>áK>áB;áB;á=9á=9<*á@á@‚¬ÿ/MTrk¬ÿÿ!ÂQ²n² J² ‚¨ ’Ed4‚E<’Gd4‚G’Ld‚L’NcŽ‚Nx’IcŠ(‚Ix’Icx‚Ix’Icx‚Ix’Ic†H‚Ix’Kc†H‚Kx’Lc†H‚Lx’Nc†H‚Nx’Pc„X‚Px’Nc„X‚Nx’Pcp‚Pp’Pc„X‚PZ’Qd‚Q’Sd„X‚Sx’Qcp‚Qp’PcŽ‚PZ’O‚O’NcŽ‚Nx’Pc‰0‚Pp’Pcp‚Pp’Pc„X‚Px’Nc„X‚Nx’Sc‚h‚Sx’Qc„X‚Qx’Pc„X‚Px’Nc‚h‚Nx’Pc‰0‚Pp’Pcx‚Px’Pcx‚Px’Pc‰0‚Pp’Pcp‚Pp’Pc„X‚Px’Nc„X‚NZ’Qd‚Q’Sc‚h‚Sx’Lc† ‚L’Lc‚L’Nc† ‚N’Nc‚N’Qc† ‚Q’Qc‚Q’Pc…P‚PR’Lc‚L’NcŽ‚Nx’IcŠ(‚Ix’Icx‚Ix’Icx‚Ix’Ic†H‚Ix’Kc†H‚Kx’Lc†H‚Lx’Nc†H‚Nx’Pc„X‚Px’Nc„X‚Nx’Pcp‚Pp’Pc„X‚PZ’Qd‚Q’Sc„X‚Sx’Qcp‚Qp’Pc…‚P<’Qc…‚Q<’Scp‚Sp’Pc‚Pp’Pd…‚P<’Qd…‚Q<’Pdp‚Pp’Pd…‚P<’Nd…‚N<’Pdp‚Pp’NdŽD‚N<’LdŠ(‚Lx’Pdx‚Px’Pdx‚Px’Pd…‚P<’Qd…‚Q<’Ndp‚Np’Pd„X‚PZ’Pd‚P’Qd„X‚Qx’Sd‚,‚S’Pd‚P’QdŽD‚Q’Qd‚Q’Sd‡h²d(²c(²b²a(²`²_²^²]²[²Z²X²V²U²R²P²O²M²K²I²H‚S²F²D²A²?²<²:²8²4²2²/²,²)²&²"²²²²² ²²²(²dƒÜ ’Ed4‚E<’Gd4‚G’Ld‚L’NcŽ‚Nx’IcŠ(‚Ix’Icx‚Ix’Icx‚Ix’Ic†H‚Ix’Kc†H‚Kx’Lc†H‚Lx’Nc†H‚Nx’Pc„X‚Px’Nc„X‚Nx’Pcp‚Pp’Pc„X‚PZ’Qd‚Q’Sc„X‚Sx’Qcp‚Qp’PcŽ‚Px’NcŽ‚Nx’Pc‰0‚Pp’Pcp‚Pp’Pc„X‚Px’Nc„X‚Nx’Sc‚h‚Sx’Qc„X‚Qx’Pc„X‚Px’Nc‚h‚Nx’Pc‰0‚Pp’Pcx‚Px’Pcx‚Px’Pc‰0‚Pp’Pcp‚Pp’Pc„X‚Px’Nc„X‚NZ’Qd‚Q’Sc‚h‚Sx’Lc† ‚L’Lc‚L’Nc† ‚N’Nc‚N’Qc† ‚Q’Qc‚Q’Pc…P‚PR’Lc‚L’NcŽ‚Nx’IcŠ(‚Ix’Icx‚Ix’Icx‚Ix’Ic†H‚Ix’Kc†H‚Kx’Lc†H‚Lx’Nc†H‚Nx’Pc„X‚Px’Nc„X‚Nx’Pcp‚Pp’Pc„X‚PZ’Qd‚Q’Sc„X‚Sx’Qcp‚Qp’Pc…‚P<’Qc…‚Q<’Scp‚Sp’Pc‚Pp’Pd…‚P<’Qd…‚Q<’Pdp‚Pp’Pd…‚P<’Nd…‚N<’Pdp‚Pp’NdŽD‚N<’LdŠ(‚Lx’Pdx‚Px’Pdx‚Px’Pd…‚P<’Qd…‚Q<’Ndp‚Np’Pd„X‚PZ’Pd‚P’Qd„X‚Qx’Sd‚,‚S’Sd‚S’UdŽD‚U<’Sd„²dP²c(²b(²a(²`(²_<²^(²](²\²[(²Z²Y²X²W²V²U²T²S²R²Q²P²N²M²L²I²G²E²D²B²?²=²;²9²7²6²4²1²/²,²)²&²$²"²!(²²‚S²²²²²² ² ²²²d²d‡ûDÿ/MTrk#>ÿÿ!³³ ód³ O„”@“4d“;c“@c“Dcpƒ4ƒ`ƒ;ƒ@ƒDƒ`“Dc“=c“@cxƒDƒ=ƒ@„X“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=„X“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“Ec“@c“=c‚hƒEƒ@ƒ=‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG„X“Dc“=c“@cxƒDƒ=ƒ@„X“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=„X“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“Ec“@c“=c‚hƒEƒ@ƒ=‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG„X“@c“=c“Dcxƒ@ƒ=ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD„X“Dc“@c“=cxƒDƒ@ƒ=‚h“Dc“@c“=cxƒDƒ@ƒ=‚h“=c“@c“Dcxƒ=ƒ@ƒD„X“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“Ec“@c“=c‚hƒEƒ@ƒ=‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG„X“Dc“=c“@cxƒDƒ=ƒ@„X“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=‚h“Ec“@c“=cpƒEƒ@ƒ=…P“Ec“@c“=cpƒEƒ@ƒ=…P“=c“Dc“Acpƒ=ƒDƒAƒ`“=d“Gd“Dd“Ad<ƒ=ƒGƒDƒA4“Gc“=c“Ac“Dc…PƒGƒ=ƒAƒDp“?U“FU“BU‹ ƒ?ƒFƒBƒ`“?U“FU“BUpƒ?ƒFƒBƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“FU“BU“?UpƒFƒBƒ?p“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“GU“BU“?UpƒGƒBƒ?p“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“AU“DU“=UpƒAƒDƒ=p“FU“=U“BU‹ ƒFƒ=ƒBƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“=U“FU“AUpƒ=ƒFƒAp“FU“?U“BU‹ ƒFƒ?ƒBƒ`“?U“FU“BUpƒ?ƒFƒBƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“FU“BUpƒ?ƒFƒBp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“GU“BU“?UpƒGƒBƒ?p“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“AU“DUpƒ=ƒAƒDp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“BU“=U“FUpƒBƒ=ƒFƒ`“BU“FU“=UpƒBƒFƒ=p“82“12pƒ8ƒ1“Dc“=c“@cxƒDƒ=ƒ@„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=‚h“92“42pƒ9ƒ4“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“=c“@c“Ec‚hƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG‚h“82“12pƒ8ƒ1“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Ec“@c“=cpƒEƒ@ƒ=…P“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Gc“Bc“?c‚hƒGƒBƒ?‚h“Gc“Bc“?cxƒGƒBƒ?‚h“Gc“Bc“?c…PƒGƒBƒ?p“12“82pƒ1ƒ8“Dc“=c“@cxƒDƒ=ƒ@„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=‚h“42“92pƒ4ƒ9“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“=c“@c“Ec‚hƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG‚h“12“82pƒ1ƒ8“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Ec“@c“=cpƒEƒ@ƒ=…P“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Gc“Bc“?c‚hƒGƒBƒ?‚h“Gc“?c“BcxƒGƒ?ƒB‚h“Gc“Dc“@c…PƒGƒDƒ@ƒ`“Dc“=c“@cxƒDƒ=ƒ@„X“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=„X“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“Ec“@c“=c‚hƒEƒ@ƒ=‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG„X“Dc“=c“@cxƒDƒ=ƒ@„X“Dc“@c“=cxƒDƒ@ƒ=„X“Dc“@c“=cxƒDƒ@ƒ=„X“=c“@c“Dcxƒ=ƒ@ƒD‚h“=c“@c“Dcxƒ=ƒ@ƒD‚h“Dc“@c“=cxƒDƒ@ƒ=„X“Ec“@c“=cxƒEƒ@ƒ=„X“=c“@c“Ecxƒ=ƒ@ƒE„X“Ec“@c“=c‚hƒEƒ@ƒ=‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“=c“@c“Ecxƒ=ƒ@ƒE‚h“?c“Bc“Gcxƒ?ƒBƒG„X“@c“=c“Dcpƒ@ƒ=ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Ecpƒ=ƒ@ƒEƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=p“Ec“@c“=cpƒEƒ@ƒ=p“Gc“Bc“?cpƒGƒBƒ?ƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“Ec“@c“=cpƒEƒ@ƒ=…P“Ec“@c“=cpƒEƒ@ƒ=ƒ`“?c“Bc“Gcpƒ?ƒBƒGƒ`“Gc“?c“BcpƒGƒ?ƒBp“Dc“Gc“@c…PƒDƒGƒ@ƒ`“@c“=c“Dcpƒ@ƒ=ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Ecpƒ=ƒ@ƒEƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=p“Ec“@c“=cpƒEƒ@ƒ=p“Gc“Bc“?cpƒGƒBƒ?ƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=ƒ`“=c“@c“Ecpƒ=ƒ@ƒEƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=p“Ec“@c“=cpƒEƒ@ƒ=p“Gc“Bc“?cpƒGƒBƒ?ƒ`“@c“=c“Dcpƒ@ƒ=ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Ecpƒ=ƒ@ƒEƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=ƒ`“Ec“@c“=cpƒEƒ@ƒ=p“Ec“@c“=cpƒEƒ@ƒ=p“Gc“Bc“?cpƒGƒBƒ?ƒ`“@c“=c“Dcpƒ@ƒ=ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“=c“@c“Dcpƒ=ƒ@ƒDƒ`“Dc“@c“=cpƒDƒ@ƒ=p“Dc“@c“=cpƒDƒ@ƒ=p“=c“@c“Dcpƒ=ƒ@ƒDp“Ec“@c“=cpƒEƒ@ƒ=…P“Ec“@c“=cpƒEƒ@ƒ=…P“=c“Dc“Acpƒ=ƒDƒAƒ`“=d“Gd“Dd“Ad<ƒ=ƒGƒDƒA4“Gc“=c“Ac“Dc…PƒGƒ=ƒAƒDp“?U“BU“FU‹ ƒ?ƒBƒFƒ`“BU“FU“?UpƒBƒFƒ?ƒ`“BU“?U“FUpƒBƒ?ƒFƒ`“FU“?U“BUpƒFƒ?ƒBp“BU“GU“?U‹ ƒBƒGƒ?ƒ`“BU“?U“GUpƒBƒ?ƒGƒ`“BU“?U“GUpƒBƒ?ƒGƒ`“GU“?U“BUpƒGƒ?ƒBp“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“AU“DU“=UpƒAƒDƒ=p“FU“=U“BU‹ ƒFƒ=ƒBƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“=U“FU“AUpƒ=ƒFƒAp“FU“?U“BU‹ ƒFƒ?ƒBƒ`“?U“FU“BUpƒ?ƒFƒBƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“FU“BUpƒ?ƒFƒBp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“GU“BU“?UpƒGƒBƒ?p“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“AU“DUpƒ=ƒAƒDp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“AU“=U“FUpƒAƒ=ƒFp“?U“FU“BU‹ ƒ?ƒFƒBƒ`“?U“FU“BUpƒ?ƒFƒBƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“FU“BU“?UpƒFƒBƒ?p“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“GU“BU“?UpƒGƒBƒ?p“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“AU“DU“=UpƒAƒDƒ=p“FU“=U“BU‹ ƒFƒ=ƒBƒ`“FU“=U“BUpƒFƒ=ƒBƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“=U“FU“AUpƒ=ƒFƒAp“FU“?U“BU‹ ƒFƒ?ƒBƒ`“?U“FU“BUpƒ?ƒFƒBƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“FU“BUpƒ?ƒFƒBp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“GU“BU“?UpƒGƒBƒ?p“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“AU“DUpƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“AU“DUpƒ=ƒAƒDp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“BU“=U“FUpƒBƒ=ƒFƒ`“BU“=U“FUpƒBƒ=ƒFp“FU“BU“?U‹ ƒFƒBƒ?ƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGp“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“AU“FU“=UpƒAƒFƒ=p“?U“BU“FU‹ ƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGp“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“BU“=U“FUpƒBƒ=ƒFƒ`“BU“FU“=UpƒBƒFƒ=p“FU“BU“?U‹ ƒFƒBƒ?ƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGp“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAp“=U“BU“FU‹ ƒ=ƒBƒFƒ`“FU“BU“=UpƒFƒBƒ=ƒ`“AU“=U“FUpƒAƒ=ƒFƒ`“AU“FU“=UpƒAƒFƒ=p“?U“BU“FU‹ ƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFƒ`“?U“BU“FUpƒ?ƒBƒFp“GU“BU“?U‹ ƒGƒBƒ?ƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGƒ`“?U“BU“GUpƒ?ƒBƒGp“=U“AU“DU‹ ƒ=ƒAƒDƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAƒ`“=U“DU“AUpƒ=ƒDƒAÛpÿ/MTrk 3ÿÿ!Ä0´P´¼´ nƒØ"”Bd”Ndp„B„N”Dd”Pdp„D„P”Qd”Edp„Q„E”Gd”Sd4”Id”Ud<„G„SŽD„I„U”Wd”Kd‡@„W„K”Xd”Ld‡@„X„L”Zd”Nd‡@„Z„N”Xd”Ld‡@„X„L”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”\d”Pd„\„P”_d”Sd‡@„_„S”]d”Qd‡@„]„Q”Zd”Nd‡@„Z„N”]d”Qd‡@„]„Q”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”Xd”Ld„X„L”Zd”Nd‡@„Z„N”\d”Pd‡@„\„P”]d”Qd‡@„]„Q”Zd”Nd‡@„Z„N”\d”Pd‡@„\„P”]d”Qd‡@„]„Q”ad”UdŽ„a„Ux”_d”Sd‚h„_„Sx”]d”Qd‚h„]„Qx”\d”Pd‚h„\„Px”Zd”Nd‚h„Z„Nx”Xd”Ld„X„L”Wd”Kdƒ`„W„K”Ud”Idp„U„I”Sd”Gdp„S„G”Ud”Idp„U„I”Wd”Kdp„W„K”Zd”Ndp„Z„N”\d”Pdp„\„P”^d”Rd¥@„^„R”Z_”N_‡@„Z„N”cd”Wd‡@„c„W”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Zd”Nd„Z„N”^d”Rd„^„Rp”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”^d”Rd‡@„^„R”\d”Pd„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Wd”Kdš „W„K”Ud”Id<„U„I”Sd”Gd<„S„G”Rd”Fd<„R„F”Pd”Dd<„P„D”Nd”Bd<„N„BƒÚ0”Bd”Ndp„B„N”Dd”Pdp„D„P”Qd”Edp„Q„E”Gd”Sd4”Id”Ud<„G„SŽD„I„U”Wd”Kd‡@„W„K”Xd”Ld‡@„X„L”Zd”Nd‡@„Z„N”Xd”Ld‡@„X„L”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”\d”Pd„\„P”_d”Sd‡@„_„S”]d”Qd‡@„]„Q”Zd”Nd‡@„Z„N”]d”Qd‡@„]„Q”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”Xd”Ld„X„L”Zd”Nd‡@„Z„N”\d”Pd‡@„\„P”]d”Qd‡@„]„Q”Zd”Nd‡@„Z„N”\d”Pd‡@„\„P”]d”Qd‡@„]„Q”ad”Ud„a„U”_d”Sdƒ`„_„S”]d”Qdƒ`„]„Q”\d”Pdƒ`„\„P”Zd”Ndƒ`„Z„N”Xd”Ld„X„L”Wd”Kdƒ`„W„K”Ud”Idp„U„I”Sd”Gdp„S„G”Ud”Idp„U„I”Wd”Kdp„W„K”Zd”Ndp„Z„N”\d”Pdp„\„P”^d”Rd¥@„^„R”Z_”N_‡@„Z„N”cd”Wd‡@„c„W”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Zd”Nd„Z„N”^d”Rd„^„Rp”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”^d”Rd‡@„^„R”\d”Pd„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Wd”Kd–@„W„K”Id”Udp„I„U”Kd”Wdp„K„W”Nd”Zdp„N„Z”Pd”\dp„P„\”^d”Rd¥@„^„R”Z_”N_‡@„Z„N”cd”Wd‡@„c„W”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”ad”Ud‡@„a„U”^d”Rd‡@„^„R”\d”Pd‡@„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Zd”Nd„Z„N”^d”Rd„^„Rp”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”^d”Rd‡@„^„R”\d”Pd„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Wd”Kd–@„W„K”Id”Udp„I„U”Kd”Wdp„K„W”Nd”Zdp„N„Z”Pd”\dp„P„\”Rd”^d¥@„R„^”N_”Z_‡@„N„Z”Wd”cd‡@„W„c”Ud”ad‡@„U„a”Rd”^d‡@„R„^”Pd”\d‡@„P„\”Sd”_d‡@„S„_”Ud”ad‡@„U„a”Rd”^d‡@„R„^”Pd”\d‡@„P„\”Nd”Zd‡@„N„Z”Md”Yd‡@„M„Y”Zd”Nd„Z„N”^d”Rd„^„Rp”^d”Rd‡@„^„R”\d”Pd‡@„\„P”_d”Sd‡@„_„S”^d”Rd‡@„^„R”\d”Pd„\„P”Zd”Nd‡@„Z„N”Yd”Md‡@„Y„M”Wd”Kdš „W„K”Ud”Id<„U„I”Sd”Gd<„S„G”Rd”Fd<„R„F”Pd”Dd<„P„D”Nd”Bd<„N„B‚®ÿ/MTrk@ÿÿ!Å^µ2µ¼µ •8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=d…9…=ÿ•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=•9d•=dž…9…=•8d•=dž…8…=ƒþ•:d•?dž…:…?•;d•?dž…;…?•8d•=dž…8…=•=d•:dž…=…:•:d•?dž…:…?•;d•?dž…;…?•8d•=dž…8…=•=d•:dž…=…:•:d•?dž…:…?•;d•?dž…;…?•8d•=dž…8…=•=d•:dž…=…:•:d•?dž…:…?•;d•?dž…;…?•=d•8dž…=…8Úÿ/MTrk`ÿÿ!Æ`¶A¶ ,†„@–edp†ep–fdp†fp–hdp†h…P–cdp†c…P–edp†e‰0–hdp†hp–hdp†hƒ`–cdp†cƒ`–edp†e‰0–edp†ep–fdp†fp–hdp†h…P–jdp†jp–fdp†f…P–edp†ep–fdp†fp–hdp†hp–jdp†j…P–kdp†k…P–hdp†h…P–hdp†hp–jdp†jp–hdp†h…P–cdp†c…P–edp†e…P–jdp†j…P–hdp†hƒ`–cdp†cƒ`–edp†e…P–adp†ap–edp†ep–fdp†fp–edp†e…P–fdp†fp–edp†e…P–cdp†cp–adp†ap–cdp†cp–edp†eƒ`–edp†eƒ`–cdp†cp–cdp†c…ÕP–edp†ep–fdp†fp–hd–cdp†h†c…P–cdp†c…P–edp†e‰0–hdp†hp–hdp†hƒ`–cdp†cƒ`–edp†e‰0–edp†ep–fdp†fp–hdp†h…P–jdp†jp–fdp†f…P–edp†ep–fdp†fp–hdp†hp–jdp†j…P–kdp†k…P–hdp†h…P–hdp†hp–jdp†jp–hdp†h…P–cdp†c…P–edp†e…P–jdp†j…P–hdp†hƒ`–cdp†cƒ`–edp†e…P–adp†ap–edp†ep–fdp†fp–edp†e…P–fdp†fp–edp†e…P–cdp†cp–adp†ap–cdp†cp–edp†eƒ`–edp†eƒ`–cdp†cp–cdp†c‰0–e_–j_p†e†jp–hd–cdp†h†c…P–cd–^dp†c†^…P–ed–cdp†e†c‰0–hd–cdp†h†cp–hd–cdp†h†cƒ`–_d–cdp†_†cƒ`–cd–edp†c†e‰0–_d–edp†_†ep–cd–fdp†c†fp–ed–hdp†e†h…P–fd–jdp†f†jp–ad–fdp†a†f…P–ad–edp†a†ep–cd–fdp†c†fp–ed–hdp†e†hp–fd–jdp†f†j…P–hd–kdp†h†k…P–jd–mdp†j†mp–fd–jdp†f†jp–ed–hdp†e†hp–fd–kdp†f†kp–fd–jdp†f†j…P–ed–hdp†e†h…P–cd–fdp†c†f…P–fd–kdp†f†k…P–fd–kdp†f†kƒ`–hd–mdp†h†mƒ`–cd–fdp†c†f…P–^d–adp†^†ap–ad–edp†a†ep–cd–fdp†c†fp–ad–edp†a†e…P–cd–fdp†c†fp–ad–edp†a†e…P–^d–cdp†^†cp–\d–adp†\†ap–^d–cdp†^†cp–ad–edp†a†eƒ`–ad–edp†a†eƒ`–ad–fdp†a†fp–ad–fdp†a†f„©ÿ/MTrkÿÿ!Ç7·U•Èÿ/MTrk(ÿÿ!Èb¸d¸ ,Èb¸n¸ ,b˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜LKpˆ\ˆSˆL×P˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜LKpˆ\ˆSˆL×P˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜LKpˆ\ˆSˆL×P˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜MK˜Yd˜UdRˆ\ˆSˆM‚ˆYˆU˜Zd˜Udƒ`ˆZˆU˜\d˜Wd‡@ˆ\ˆW˜Wd˜Rd‡@ˆWˆR˜Wd˜Yd‹ ˆWˆY˜\d˜Wdƒ`ˆ\ˆW˜\d˜Wd…Pˆ\ˆW˜Sd˜Wd…PˆSˆW˜Wd˜Yd‹ ˆWˆY˜Sd˜Ydƒ`ˆSˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\d‡@ˆYˆ\˜Zd˜^dƒ`ˆZˆ^˜Ud˜Zd‡@ˆUˆZ˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\dƒ`ˆYˆ\˜Zd˜^d‡@ˆZˆ^˜\d˜_d‡@ˆ\ˆ_˜Yd˜\d‡@ˆYˆ\˜Yd˜\dƒ`ˆYˆ\˜Zd˜^dƒ`ˆZˆ^˜\d˜Wd‡@ˆ\ˆW˜Wd˜Rd‡@ˆWˆR˜Wd˜Yd‡@ˆWˆY˜Zd˜^d‡@ˆZˆ^˜\d˜Wd…Pˆ\ˆW˜Sd˜Wd…PˆSˆW˜Wd˜Yd‡@ˆWˆY˜Rd˜Udƒ`ˆRˆU˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜Yd‡@ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜YdƒB˜B$˜6ˆ6ˆBR˜F&˜:ˆ:ˆFR˜I'˜=ˆUˆYˆIˆ=˜Rd˜WdR˜N)˜BˆBˆNR˜B*˜6 ˆRˆWˆBˆ6˜Pd˜UdR˜F,˜: ˆ:ˆFR˜I-˜= ˆPˆUˆIˆ=˜Rd˜WdR˜N/˜B ˆBˆNR˜6 ˜B1ˆRˆWˆ6ˆB˜Ud˜YdR˜: ˜F2ˆFˆ:R˜= ˜I4ˆIˆ=R˜B˜N5ˆUˆYˆBˆN˜Ud˜YdR˜6˜B7ˆBˆ6R˜:˜F8ˆFˆ:R˜=˜I:ˆUˆYˆ=ˆI˜Rd˜WdR˜B˜N<ˆNˆBR˜6˜B=ˆRˆWˆ6ˆB˜Rd˜WdR˜:˜F?ˆFˆ:R˜=˜I@ˆIˆ=R˜B˜NBˆNˆBR˜6˜BCˆBˆ6R˜:˜FEˆFˆ:R˜=˜IGˆRˆWˆ=ˆIR˜B˜NHˆBˆNÓR˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜LKpˆ\ˆSˆL×P˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜LKpˆ\ˆSˆL×P˜@dpˆ@p˜EdpˆEp˜LdpˆLp˜SdpˆSp˜XdpˆXp˜]dpˆ]p˜\d˜SK˜MK˜Yd˜UdRˆ\ˆSˆM‚ˆYˆU˜Zd˜Udƒ`ˆZˆU˜\d˜Wd‡@ˆ\ˆW˜Wd˜Rd‡@ˆWˆR˜Wd˜Yd‹ ˆWˆY˜\d˜Wdƒ`ˆ\ˆW˜\d˜Wd…Pˆ\ˆW˜Sd˜Wd…PˆSˆW˜Wd˜Yd‹ ˆWˆY˜Sd˜Ydƒ`ˆSˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\d‡@ˆYˆ\˜Zd˜^dƒ`ˆZˆ^˜Ud˜Zd‡@ˆUˆZ˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\dƒ`ˆYˆ\˜Zd˜^d‡@ˆZˆ^˜\d˜_d‡@ˆ\ˆ_˜Yd˜\d‡@ˆYˆ\˜Yd˜\dƒ`ˆYˆ\˜Zd˜^dƒ`ˆZˆ^˜\d˜Wd‡@ˆ\ˆW˜Wd˜Rd‡@ˆWˆR˜Yd˜Wd‡@ˆYˆW˜Zd˜^d‡@ˆZˆ^˜\d˜Wd…Pˆ\ˆW˜Sd˜Wd…PˆSˆW˜Yd˜Wd‡@ˆYˆW˜Rd˜Udƒ`ˆRˆU˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜Yd‡@ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜Yd‡@ˆUˆY˜Rd˜Wdƒ`ˆRˆW˜Pd˜Udƒ`ˆPˆU˜Rd˜Wdƒ`ˆRˆW˜Ud˜Yd…PˆUˆY˜Ud˜Yd…PˆUˆY˜Rd˜Wdƒ`ˆRˆW˜Rd˜Wd‹ ˆRˆW˜Y_˜^_ƒ`ˆYˆ^˜\d˜Wd‡@ˆ\ˆW˜Wd˜Rd‡@ˆWˆR˜Yd˜Wd‹ ˆYˆW˜\d˜Wdƒ`ˆ\ˆW˜\d˜Wd…Pˆ\ˆW˜Sd˜Wdƒ`ˆSpˆW˜Wd˜Yd‹ ˆWˆY˜Sd˜Ydƒ`ˆSˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\d‡@ˆYˆ\˜Zd˜^dƒ`ˆZˆ^˜Ud˜Zd‡@ˆUˆZ˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Yd˜\dƒ`ˆYˆ\˜Zd˜^d‡@ˆZˆ^˜\d˜_d‡@ˆ\ˆ_˜^d˜adƒ`ˆ^ˆa˜Zd˜^dƒ`ˆZˆ^˜Yd˜\dƒ`ˆYˆ\˜Zd˜_dƒ`ˆZˆ_˜Zd˜^d‡@ˆZˆ^˜Yd˜\d‡@ˆYˆ\˜Wd˜Zd‡@ˆWˆZ˜Zd˜_d‡@ˆZˆ_˜Zd˜_d…PˆZˆ_˜\d˜ad…Pˆ\ˆa˜Wd˜Zd‡@ˆWˆZ˜Rd˜Udƒ`ˆRˆU˜Ud˜Ydƒ`ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜Yd‡@ˆUˆY˜Wd˜Zdƒ`ˆWˆZ˜Ud˜Yd‡@ˆUˆY˜Rd˜WdR˜N˜BˆBˆNR˜B˜6ˆRˆWˆBˆ6˜Pd˜UdR˜F˜:ˆ:ˆFR˜I˜=ˆPˆUˆIˆ=˜Rd˜WdR˜N˜BˆBˆNR˜B˜6ˆRˆWˆBˆ6˜Ud˜YdR˜F˜:ˆ:ˆFR˜I˜=ˆ=ˆIR˜N˜BˆUˆYˆNˆB˜Ud˜YdR˜B˜6ˆ6ˆBR˜F˜:ˆ:ˆFR˜I˜=ˆUˆYˆIˆ=˜Ud˜ZdR˜N˜BˆBˆNR˜B˜6ˆUˆZˆBˆ6˜Ud˜ZdR˜F˜:ˆ:ˆFR˜I˜=ˆ=ˆIR˜N˜BˆBˆNR˜B˜6ˆ6ˆBR˜F˜:ˆ:ˆFR˜I˜=ˆUˆZˆIˆ=R˜N ˜B ˆNˆBƒÃR˜BdpˆBp˜GdpˆGp˜NdpˆNp˜UdpˆUp˜ZdpˆZp˜_dpˆ_p˜^d˜NK˜UKpˆ^ˆNˆUÁnÿ/MTrk,ÌÿRhythmÿ!¹¹ ɹx¹ Dž™,Fx‰,†H™,P™>d™'F™(Fx‰,p‰>‰'‚h‰(™>d™'P™(Pp™,Zx‰,‰>‰'‚h‰(™>d™'d™(Z‚h‰>‰'x‰(™,d™(dx‰,‚h‰(™(xp‰(™(dp™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x‰(™*x™xx‰?x‰7‰'<‰.<‰>x™,x™?x™7x™'x™>xx‰?‰,x‰'‰7™*xx‰*‰>x™.x‚,‰.4™,xx‰,x™*xx‰*x™?x™'x™7x™.x™>xx‰?x‰7‰'<‰.<‰>x‰(™,x™?x™7x™'x™>x™(xx‰,x‰?‰7‰'™*xx‰*‰>x‰(™.x™(xp‰(™(x<‰.4™,x™4x™9xx‰,x™*xx‰*x™.xx‰44‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(wx‰,x‰(™*x™(Hx‰*x‰(™.x™(Tp‰(™(]<‰.4‰(™,x™(dx‰,x‰(™*x™(lx‰*x‰(™.x™(sp‰(™(x<‰.‚¹  ‰(™(x™x4¹ ‚,‰(‰™x<¹ e4‰™x‚|¹ d‰™x ¹ eP‰™xp™,x™9x¹ @d‰,x™*xx‰*x™.x‚,‰.4‰‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x‰(™.x™(xp‰(™(x<‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(;x‰,x‰(™*x™(Gx‰*x‰(™.x™(Sp‰(™(]<‰.4‰(™,x™(Ox‰,x‰(™*x™(Zx‰*x‰(™.x™(cp‰(™(k<‰.4‰(™,x™(^x‰,x‰(™*x™(gx‰*x‰(™.x™(pp‰(™(x<‰.4‰(™,x™(xx‰,x™*xx‰*x‰(™.x™(xp‰(™(x<‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰(‰9™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4‰(™,x™(xx‰,x‰(™*xx‰*x™.x‚,‰.4™,x™9xx‰,x™*xx‰*x™.x‚,‰.4‰9™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,x™*xx‰*x™.x‚,‰.4™,xx‰,†H™,x™'x™>xx‰,x‰'x‰>‚h™>x™'xp™,xx‰>‰'‰,‚h™>x™'xp‰'x‰>x™&x™'x™,xx™&wx‰&‰'‰,™&mx‰&x‰&™&Np‰&™&5p‰&¼ÿ/MTrk4ÿÿ!Ê ºnbš4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠPßnºº Ê`ŽXº  šu,&º `*Šuº Bº ?º @ šy,&º Y*Šyº rº  šu, º 0º fŠuº Mšy, º C0º UŠyº gšu,"º yº Šuº lšy,º Y0º FŠy º @šu,º f º Šuº fšy,º Mº AŠyº fšu, º º `*Šuº Bº ?º @ šy,&º Y*Šyº rº  šu, º 0º fŠuº Mšy, º C0º UŠyº gšu,"º yº Šuº lšy,º Y0º FŠy º @šu,º f º Šuº fšy,º Mº AŠyº fšu, º º 0º dŠu(šy,º H0º -Šyº šu+ º 0º Šuº )šy+"º =.Šyº R&šu* º f0º z º  Šu&º išy).º S"Šyº >šu)º (0º  Šuº  šy(&º '*Šyº M"šu'º rº 0º aŠu(šy'º C0º %Šyº º  šu&&º *Šuº '"šy%º :0º MŠyº ` šu$&º s º  Šu&º fšy$.º L"Šyº 3šu#º 0º Šu&º &šy".º L"Šyº rº  šu" º º ` º Šuº ]šy!º <0º Šyº  šu &º *Šuº %"šy º 60º HŠyº Z šu&º l*Šuº ~º šyº h0º PŠy"º 9šu*º !&Šu º º šy&º &*Šyº L"šuº rº 0º hŠu(šyº P0º 9Šyº !šuº º Šuº šyº /0º FŠy(šuº ^0º uº  Šu&º hšy.º P"Šyº 9šuº !0º Šu º šyº "0º DŠy"º fšuº º ` º  Šu&º ]šy.º <"Šyº šu º 0º Šuº -šyº A0º +Šy(šuº ,º Šuº šyº $0º 5Šyº B šu&º "*Šuº º šyº 0º 'Šy"º :šu º A0º -Šuº šy"º º Šyº šuº <º ?0º *Šu(šyº ,º Šyº šuº .,º C Šu&º /šy.º "Šyº º  šu &º *Šuº 4º A šy &º +*Šyº "šu º º 0º Šu(šy º =º @0º &Šyº šu º 0º Šuº !šy "º 2$º > Šy&º +šu .º "Šuº º šy &º *Šyº %"šu º 8º >º ?Šuº *šy º ,º  Šy&º šu .º 5º B Šu&º 4šy .º '"Šyº šu º º Šuº šy º 0º /Šy(šu º >º @0º -Šuº šy"º º Šyº šuº 3º @º @ Šu&º -šy.º "Šyº º šu&º *Šuº -"šy º A0º -Šyº šu"º º º Šu&º šy.º *"Šy º >šuº 30º 'Šu"º šy*º &Šy º º šu º 0º Šuº (šy"º <º BŠyº < º B šu&º  º  Šu&º šy.º '"Šyº 9º ? šu&º -*Šuº "šyº º 0º Šy(šuº *0º =º D Šu&º /šy.º "Šy º šuº 0º !Šu"º 0šy*º ?º AŠyº ,šuº ,º  Šu&º šy.º %"Šyº 5šu º B0º 5Šuº (šy"º .Šyº &šu º º 0º Šu(šyº 0º /Šyº >º A šu&º 2*Šuº $"šyº 0º º  Šy&º šu.º '"Šuº 9º ? šy&º ,*Šyº "šuº º 0º Šu(šyº +,º ?Šyº "šuº º 0º Šu(šyº 0º $Šyº 0šuº <º AŠu(šyFº C Šy º AÊ š4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠP×Pš4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠP×Pš4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠPÈPš6@xŠ6xš:BxŠ:xš=CxŠ=xšBExŠBxš6FxŠ6xš:HxŠ:xš=IxŠ=xšBKxŠBxš6LxŠ6xš:NxŠ:xš=OxŠ=xšBQxŠBxš6RxŠ6xš:TxŠ:xš=UxŠ=xšBWxŠBxš6XxŠ6xš:ZxŠ:xš=[xŠ=xšB]xŠBxš6^xŠ6xš:`xŠ:xš=axŠ=xšBcxŠBÛºº Ê`ŽXº  šu,&º `*Šuº Bº ?º @ šy,&º Y*Šyº rº  šu, º 0º fŠuº Mšy, º C0º UŠyº gšu,"º yº Šuº lšy,º Y0º FŠy º @šu,º f º Šuº fšy,º Mº AŠyº fšu, º º `*Šuº Bº ?º @ šy,&º Y*Šyº rº  šu, º 0º fŠuº Mšy, º C0º UŠyº gšu,"º yº Šuº lšy,º Y0º FŠy º @šu,º f º Šuº fšy,º Mº AŠyº fšu, º º 0º dŠu(šy,º H0º -Šyº šu+ º 0º Šuº )šy*"º =.Šyº R&šu* º f0º z º  Šu&º išy).º S"Šyº >šu)º (0º  Šuº  šy(&º '*Šyº M"šu(º rº 0º aŠu(šy'º C0º %Šyº º  šu'&º *Šuº '"šy&º :0º MŠyº ` šu&&º s º  Šu&º fšy%.º L"Šyº 3šu%º 0º Šu&º &šy$.º L"Šyº rº  šu$ º º ` º Šuº ]šy#º <0º Šyº  šu#&º *Šuº %"šy"º 60º HŠyº Z šu"&º l*Šuº ~º šy!º h0º PŠy"º 9šu!*º !&Šu º º šy &º &*Šyº L"šu º rº 0º hŠu(šyº P0º 9Šyº !šuº º Šuº šyº /0º FŠy(šuº ^0º uº  Šu&º hšy.º P"Šyº 9šuº !0º Šu º šyº "0º DŠy"º fšuº º ` º  Šu&º ]šy.º <"Šyº šu º 0º Šuº -šyº A0º +Šy(šuº ,º Šuº šyº $0º 5Šyº B šu&º "*Šuº º šyº 0º 'Šy"º :šu º A0º -Šuº šy"º º Šyº šuº <º ?0º *Šu(šyº ,º Šyº šuº .,º C Šu&º /šy.º "Šyº º  šu&º *Šuº 4º A šy&º +*Šyº "šu º º 0º Šu(šyº =º @0º &Šyº šu º 0º Šuº !šy"º 2$º > Šy&º +šu.º "Šuº º šy&º *Šyº %"šuº 8º >º ?Šuº *šyº ,º  Šy&º šu.º 5º B Šu&º 4šy.º '"Šyº šuº º Šuº šyº 0º /Šy(šu º >º @0º -Šuº šy "º º Šyº šu º 3º @º @ Šu&º -šy .º "Šyº º šu &º *Šuº -"šy º A0º -Šyº šu "º º º Šu&º šy .º *"Šy º >šu º 30º 'Šu"º šy *º &Šy º º šu º 0º Šuº (šy"º <º BŠyº < º B šu&º  º  Šu&º šy.º '"Šyº 9º ? šu&º -*Šuº "šyº º 0º Šy(šuº *0º =º D Šu&º /šy.º "Šy º šuº 0º !Šu"º 0šy*º ?º AŠyº ,šuº ,º  Šu&º šy.º %"Šyº 5šu º B0º 5Šuº (šy"º .Šyº &šu º º 0º Šu(šyº 0º /Šyº >º A šu&º 2*Šuº $"šyº 0º º  Šy&º šu.º '"Šuº 9º ? šy&º ,*Šyº "šuº º 0º Šu(šyº +,º ?Šyº "šuº º 0º Šu(šyº 0º $Šyº 0šuº <º AŠu(šyFº C Šy º AÊ š4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠP×Pš4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠP×Pš4dpŠ4pš9dpŠ9pš@dpŠ@pšGdpŠGpšLdpŠLpšQdpŠQpšPdpŠPƒ¸Pš6FxŠ6xš:GxŠ:xš=HxŠ=xšBIxŠBxš6JxŠ6xš:KxŠ:xš=LxŠ=xšBMxŠBxš6OxŠ6xš:PxŠ:xš=QxŠ=xšBRxŠBxš6SxŠ6xš:TxŠ:xš=UxŠ=xšBVxŠBxš6WxŠ6xš:XxŠ:xš=YxŠ=xšBZxŠBxš6[xŠ6xš:\xŠ:xš=^xŠ=xšB_xŠBƒÂxš6dpŠ6pš;dpŠ;pšBdpŠBpšIdpŠIpšNdpŠNpšSdpŠSpšRdpŠRÁnÿ/MTrk0ÿÿ!Ëb»d» ,»» Ë,»F» ,b›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›LKp‹\‹S‹L×P›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›LKp‹\‹S‹L×P›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›LKp‹\‹S‹L×P›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›MK›Yd›UdR‹\‹S‹M‚‹Y‹U›Zd›Udƒ`‹Z‹U›\d›Wd‡@‹\‹W›Wd›Rd‡@‹W‹R›Wd›Yd‹ ‹W‹Y›\d›Wdƒ`‹\‹W›\d›Wd…P‹\‹W›Sd›Wd…P‹S‹W›Wd›Yd‹ ‹W‹Y›Sd›Ydƒ`‹S‹Y›Wd›Zdƒ`‹W‹Z›Yd›\d‡@‹Y‹\›Zd›^dƒ`‹Z‹^›Ud›Zd‡@‹U‹Z›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Yd›\dƒ`‹Y‹\›Zd›^d‡@‹Z‹^›\d›_d‡@‹\‹_›Yd›\d‡@‹Y‹\›Yd›\dƒ`‹Y‹\›Zd›^dƒ`‹Z‹^›\d›Wd‡@‹\‹W›Wd›Rd‡@‹W‹R›Wd›Yd‡@‹W‹Y›Zd›^d‡@‹Z‹^›\d›Wd…P‹\‹W›Sd›Wd…P‹S‹W›Wd›Yd‡@‹W‹Y›Rd›Udƒ`‹R‹U›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›Yd‡@‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›YdƒB›B$›6‹6‹BR›F&›:‹:‹FR›I'›=‹U‹Y‹I‹=›Rd›WdR›N)›B‹B‹NR›B*›6 ‹R‹W‹B‹6›Pd›UdR›F,›: ‹:‹FR›I-›= ‹P‹U‹I‹=›Rd›WdR›N/›B ‹B‹NR›6 ›B1‹R‹W‹6‹B›Ud›YdR›: ›F2‹F‹:R›= ›I4‹I‹=R›B›N5‹U‹Y‹B‹N›Ud›YdR›6›B7‹B‹6R›:›F8‹F‹:R›=›I:‹U‹Y‹=‹I›Rd›WdR›B›N<‹N‹BR›6›B=‹R‹W‹6‹B›Rd›WdR›:›F?‹F‹:R›=›I@‹I‹=R›B›NB‹N‹BR›6›BC‹B‹6R›:›FE‹F‹:R›=›IG‹R‹W‹=‹IR›B›NH‹B‹NÓR›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›LKp‹\‹S‹L×P›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›LKp‹\‹S‹L×P›@dp‹@p›Edp‹Ep›Ldp‹Lp›Sdp‹Sp›Xdp‹Xp›]dp‹]p›\d›SK›MK›Yd›UdR‹\‹S‹M‚‹Y‹U›Zd›Udƒ`‹Z‹U›\d›Wd‡@‹\‹W›Wd›Rd‡@‹W‹R›Wd›Yd‹ ‹W‹Y›\d›Wdƒ`‹\‹W›\d›Wd…P‹\‹W›Sd›Wd…P‹S‹W›Wd›Yd‹ ‹W‹Y›Sd›Ydƒ`‹S‹Y›Wd›Zdƒ`‹W‹Z›Yd›\d‡@‹Y‹\›Zd›^dƒ`‹Z‹^›Ud›Zd‡@‹U‹Z›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Yd›\dƒ`‹Y‹\›Zd›^d‡@‹Z‹^›\d›_d‡@‹\‹_›Yd›\d‡@‹Y‹\›Yd›\dƒ`‹Y‹\›Zd›^dƒ`‹Z‹^›\d›Wd‡@‹\‹W›Wd›Rd‡@‹W‹R›Yd›Wd‡@‹Y‹W›Zd›^d‡@‹Z‹^›\d›Wd…P‹\‹W›Sd›Wd…P‹S‹W›Yd›Wd‡@‹Y‹W›Rd›Udƒ`‹R‹U›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›Yd‡@‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›Yd‡@‹U‹Y›Rd›Wdƒ`‹R‹W›Pd›Udƒ`‹P‹U›Rd›Wdƒ`‹R‹W›Ud›Yd…P‹U‹Y›Ud›Yd…P‹U‹Y›Rd›Wdƒ`‹R‹W›Rd›Wd‹ ‹R‹W›Y_›^_ƒ`‹Y‹^›\d›Wd‡@‹\‹W›Wd›Rd‡@‹W‹R›Yd›Wd‹ ‹Y‹W›\d›Wdƒ`‹\‹W›\d›Wd…P‹\‹W›Sd›Wdƒ`‹Sp‹W›Wd›Yd‹ ‹W‹Y›Sd›Ydƒ`‹S‹Y›Wd›Zdƒ`‹W‹Z›Yd›\d‡@‹Y‹\›Zd›^dƒ`‹Z‹^›Ud›Zd‡@‹U‹Z›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Yd›\dƒ`‹Y‹\›Zd›^d‡@‹Z‹^›\d›_d‡@‹\‹_›^d›adƒ`‹^‹a›Zd›^dƒ`‹Z‹^›Yd›\dƒ`‹Y‹\›Zd›_dƒ`‹Z‹_›Zd›^d‡@‹Z‹^›Yd›\d‡@‹Y‹\›Wd›Zd‡@‹W‹Z›Zd›_d‡@‹Z‹_›Zd›_d…P‹Z‹_›\d›ad…P‹\‹a›Wd›Zd‡@‹W‹Z›Rd›Udƒ`‹R‹U›Ud›Ydƒ`‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›Yd‡@‹U‹Y›Wd›Zdƒ`‹W‹Z›Ud›Yd‡@‹U‹Y›Rd›WdR›N›B‹B‹NR›B›6‹R‹W‹B‹6›Pd›UdR›F›:‹:‹FR›I›=‹P‹U‹I‹=›Rd›WdR›N›B‹B‹NR›B›6‹R‹W‹B‹6›Ud›YdR›F›:‹:‹FR›I›=‹=‹IR›N›B‹U‹Y‹N‹B›Ud›YdR›B›6‹6‹BR›F›:‹:‹FR›I›=‹U‹Y‹I‹=›Ud›ZdR›N›B‹B‹NR›B›6‹U‹Z‹B‹6›Ud›ZdR›F›:‹:‹FR›I›=‹=‹IR›N›B‹B‹NR›B›6‹6‹BR›F›:‹:‹FR›I›=‹U‹Z‹I‹=R›N ›B ‹N‹BƒÃR›Bdp‹Bp›Gdp‹Gp›Ndp‹Np›Udp‹Up›Zdp‹Zp›_dp‹_p›^d›NK›UKp‹^‹N‹UÁnÿ/MTrkPÿÿ!Ì0¼F¼ J¼ ‚¨ œEd4ŒE<œGd4ŒG<œNcŽŒNxœIcŠ(ŒIxœIcxŒIxœIcxŒIxœIc†HŒIxœKc†HŒKxœLc†HŒLxœNc†HŒNxœPc„XŒPxœNc„XŒNxœPcpŒPpœPc„XŒPxœSd„XŒSxœQcpŒQpœPcŽŒPxœNcŽŒNxœPc‰0ŒPpœPcpŒPpœPc„XŒPxœNc„XŒNxœSc‚hŒSxœQc„XŒQxœPc„XŒPxœNc‚hŒNxœPc‰0ŒPpœPcxŒPxœPcxŒPxœPc‰0ŒPpœPcpŒPpœPc„XŒPxœNc„XŒNxœSc‚hŒSxœLc† ŒL4œNc† ŒN4œQc† ŒQ4œPc…PŒPpœNcŽŒNxœIcŠ(ŒIxœIcxŒIxœIcxŒIxœIc†HŒIxœKc†HŒKxœLc†HŒLxœNc†HŒNxœPc„XŒPxœNc„XŒNxœPcpŒPpœPc„XŒPxœSc„XŒSxœQcpŒQpœPc…ŒP<œQc…ŒQ<œScpŒSpœPcŒPpœPd…ŒP<œQd…ŒQ<œPdpŒPpœPd…ŒP<œNd…ŒN<œPdpŒPpœNdŽDŒN<œLdŠ(ŒLxœPdxŒPxœPdxŒPxœPd…ŒP<œQd…ŒQ<œNdpŒNpœPd„XŒPxœQd„XŒQxœSd‚,ŒS4œQdŽDŒQƒë\œEd4ŒE<œGd4ŒG<œNcŽŒNxœIcŠ(ŒIxœIcxŒIxœIcxŒIxœIc†HŒIxœKc†HŒKxœLc†HŒLxœNc†HŒNxœPc„XŒPxœNc„XŒNxœPcpŒPpœPc„XŒPxœSc„XŒSxœQcpŒQpœPcŽŒPxœNcŽŒNxœPc‰0ŒPpœPcpŒPpœPc„XŒPxœNc„XŒNxœSc‚hŒSxœQc„XŒQxœPc„XŒPxœNc‚hŒNxœPc‰0ŒPpœPcxŒPxœPcxŒPxœPc‰0ŒPpœPcpŒPpœPc„XŒPxœNc„XŒNxœSc‚hŒSxœLc† ŒL4œNc† ŒN4œQc† ŒQ4œPc…PŒPpœNcŽŒNxœIcŠ(ŒIxœIcxŒIxœIcxŒIxœIc†HŒIxœKc†HŒKxœLc†HŒLxœNc†HŒNxœPc„XŒPxœNc„XŒNxœPcpŒPpœPc„XŒPxœSc„XŒSxœQcpŒQpœPc…ŒP<œQc…ŒQ<œScpŒSpœPcŒPpœPd…ŒP<œQd…ŒQ<œPdpŒPpœPd…ŒP<œNd…ŒN<œPdpŒPpœNdŽDŒN<œLdŠ(ŒLxœPdxŒPxœPdxŒPxœPd…ŒP<œQd…ŒQ<œNdpŒNpœPd„XŒPxœQd„XŒQxœSd‚,ŒSˆ›4ÿ/MTrkLÿÿ!½½ Í^½2½¼í@½ _Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@dD@ÿDd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@Dd@džD@ƒþFdBdžFBFdBdžFBAdDdžADBdFdžBFFdBdžFBFdBdžFBAdDdžADBdFdžBFFdBdžFBFdBdžFBAdDdžADBdFdžBFFdBdžFBFdBdžFBDdAdžDAÚÿ/MTrk&ÿÿ!Î ¾2¼¾ ipžNxŽNxžUxŽU‚hžNxŽNxžN xŽNxžI xŽI‚hžNxŽNxžNxŽNxžIxŽI‚hžNxŽNxžNxŽNxžIxŽI‚h¾ pžNxŽNxžUxŽU‚hžN xŽNxžN"xŽNxžI#xŽI‚hžN'xŽNxžN(xŽNxžI*xŽI‚hžN-xŽNxžN.xŽNxžI0xŽI‚h¾ ipžN5xŽNxžU6xŽU‚hžN9xŽNxžN;xŽNxžILŸ1d¿ =d1,¿ `¿ =Ÿ1dx1¿ <`¿ ;Ÿ1d¿ :`¿ 9x1¿ 8`¿ 7Ÿ1dx1¿ 6`¿ 5Ÿ1d¿ 4`¿ 3x1¿ 2`Ÿ1d0¿ 1H1¿ 0`Ÿ1d0¿ /`¿ .¿ -H1¿ ,`Ÿ1d0¿ +H1¿ *`Ÿ1d0¿ )`¿ (¿ 'H1¿ &`Ÿ1d0¿ %H1¿ $`Ÿ1d0¿ #H1¿ "`Ÿ1d0¿ !H1¿ `Ÿ1d0¿ H1¿ `Ÿ1d0¿ H1¿ `Ÿ1d0¿ `¿ ¿ H1¿ `Ÿ1d0¿ H1¿ `Ÿ1d0¿ `¿ ¿ H1H¿ 0Ÿ1d0¿ H1H¿ 0Ÿ1d0¿ ¿ `¿ H1H¿ 0Ÿ1d0¿ H1H¿ 0Ÿ1d0¿ H1H¿ `¿ ¿ `¿ ¿ `¿ ¿ `¿ ¿ …Ð0¿ Ÿ1dt¿ 1\¿ Ÿ1dt¿ 1\¿ Ÿ1dt¿ `¿ ¿ 1\¿ Ÿ1dt¿ 1\¿ Ÿ1dt¿ `¿ ¿ 1\¿ Ÿ1dt¿ 1xŸ1d¿ `¿ ¿ `¿ 1xŸ1d¿ `¿ 1xŸ1d¿ `¿ ¿ `¿ 1xŸ1d¿ `¿ 1xŸ1d¿ `¿ 1xŸ1d¿ `¿ 1xŸ1d¿ `¿ !1xŸ1d¿ "`¿ #1xŸ1d¿ $`¿ %¿ &`¿ '1xŸ1d¿ (`¿ )1xŸ1d¿ *`¿ +¿ ,`¿ -1xŸ1d¿ .d1,¿ /LŸ1d¿ 0¿ 1`¿ 2d1,¿ 3LŸ1d¿ 4d1,¿ 5LŸ1d¿ 6¿ 7`¿ 8d1,¿ 9LŸ1d¿ :d1,¿ ;LŸ1d¿ d1,¿ ?LŸ1d¿ @d1,¿ ALŸ1d¿ Bd1,¿ CLŸ1d¿ D¿ E`¿ Fd1,¿ GLŸ1d¿ Hd1,¿ ILŸ1d¿ J¿ K`¿ Ld1,¿ MLŸ1dD¿ N41,¿ OLŸ1dD¿ P`¿ Q¿ R41,¿ SLŸ1dD¿ T41,¿ ULŸ1dD¿ V`¿ W¿ X41,¿ YLŸ1dD¿ Z41,¿ [LŸ1dD¿ \41,¿ ]LŸ1dD¿ ^41,¿ _LŸ1dD¿ `41,¿ aLŸ1dD¿ b41,¿ cLŸ1dD¿ d`¿ e¿ f41,¿ gLŸ1dD¿ h41,¿ iLŸ1dD¿ j`¿ k¿ l41\¿ mŸ1dD¿ n41\¿ oŸ1dD¿ p¿ q`¿ r41\¿ sŸ1dD¿ t41\¿ uŸ1dD¿ v¿ w`¿ x41\¿ yŸ1dD¿ z41\¿ {Ÿ1dD¿ |41\¿ }Ÿ1dD¿ ~41\¿ ¿ Ÿ1d0¿ H1¿ `¿ Ÿ1d`¿ 1H¿ 0Ÿ1d0¿ `¿ `¿ `¿ 1¿ `¿ Ÿ1d`¿ 1H¿ 0Ÿ1d0¿ `¿ `¿ `¿ 1H¿ 0¿ Ÿ1d`¿ 1H¿ 0Ÿ1d0¿ `¿ `¿ `¿ 1H¿ 0¿ Ÿ1d`¿ 1H¿ 0Ÿ1d0¿ `¿ `¿ `¿ !1H¿ "0Ÿ1d0¿ #0¿ $1H¿ %0Ÿ1d0¿ &H1¿ '`¿ (Ÿ1d`¿ )1H¿ *0Ÿ1d0¿ +H1¿ ,0¿ -0Ÿ1d0¿ .H1¿ /`¿ 0Ÿ1d`¿ 1`¿ 2`¿ 3H1¿ 4`¿ 5Ÿ1d0¿ 6H1¿ 7`¿ 8Ÿ1d`¿ 9`¿ :`¿ ;H1¿ <`¿ =Ÿ1d`¿ >1¿ ?`¿ @Ÿ1d`¿ A`¿ B`¿ CH1¿ D`¿ EŸ1d`¿ F1¿ G`¿ HŸ1d`¿ I`¿ J`¿ KH1¿ L`¿ MŸ1d`¿ N1H¿ O0¿ PŸ1d`¿ Q1H¿ R0Ÿ1d0¿ SH1¿ T`¿ UŸ1d`¿ V1H¿ W0Ÿ1d0¿ X0¿ Y1H¿ Z0Ÿ1d0¿ [`¿ \`¿ ]`¿ ^1H¿ _0Ÿ1d0¿ `H1¿ a0¿ b0Ÿ1d0¿ c`¿ d`¿ e`¿ f1H¿ g0Ÿ1d0¿ hH1¿ i`¿ jŸ1d0¿ k`¿ l`¿ m`¿ n1H¿ o0Ÿ1d0¿ pH1¿ q`¿ rŸ1d`¿ s0¿ t`¿ u`¿ v1H¿ w0Ÿ1d0¿ xH1¿ y`¿ zŸ1d`¿ {1¿ |`¿ }Ÿ1d`¿ ~1H¿ ‹ú0ÿ/simutrans-124.3/simutrans/music/47-Salty-Breeze.mid000066400000000000000000001561011474050137200221550ustar00rootroot00000000000000MThdàMTrkãÿÿCopyright (C) 2018ÿ Salty Breezeÿ by RykSebÿQB@ÿSetupÿXpÿ Salty BreezeÿQ¡ ÿXžÿ by RykSebÚÿNightøÿNight2øÿDayøÿDay2øÿNight'øÿNight2'øÿDay'øÿDay2'øÿEnd1øÿEnd2ÿ/MTrk¨ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------Šâ@ÿ/MTrk3yÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° À° F°d°[° °°e°d°@°&°e°d°@°e°d° à@°e°dÿG---- End of CH Setup --------------------------------------------------'-(,6438F =F„!€=PDDƒ€8€4€-€,,>-C8P4@1@e€1€4€8€-€,-E,?4H1H8C?€8€1€4€,€-e€D3,B/?6K3MƒNBHqGBjLGo€3€6€,€/‚J/B,73<6N9€3€6€/€,€L@KA%€G€BLF€KY,=KO-D €L128M‚,D=‚bG3ƒ"€8€-€,€1>,0 -C174G8R8€4€1€8€,€-,?-c 8;1.4F)€4€1€8€,€-‚ ,>BE /? €D1@6R€K€G%D<ƒX=543@€14<€3)3F€4€B‚ €/!BA/K€Di€B@'€,€=:B3€3€@€/1,B@8€6€B1F-F 4F8F?P€@‚@4€?N;-ƒ3€8 €1 €4 €-€,#,4-18@1?4GX€4€1€8€-€,C€@9-M,F1C8E4Gh€4€8€1€,€-sBA €;=G.5,61:3;6ELFƒ2€LK6 /H€1…€G€B€6€/€,€3eGJ,5/H6V3CMB@€GgDCM€,5*24J1B-B €3€/€6‚G€K =K8€1€4€*€-7€B€Dk/M6R,=3K„€= 8a=E;€8.€3 €6€/€,"?V!€=,€?*@@X-D8N1D‚}BS€@€BL€1€-€8€*!;CGJ/E,C1B6K‚w€;?=LIa€64Rq€G€43TG€=€I!€/ €1€3€,U-(,643138Fˆ€8€1€4€-€,,>-C8P4@1@e€,€-€8€4€1-E,?4H1H8C?€8€1€4€,€-‚,B/?6K3Mˆ€3€6€,€/‚J/B,73<6N9€3€6€/€,‚ ,=-D128Mˆ0€8€,€-€1>,0-C174G8R9€4€8€1 €-€,!,?-c 8;1.4F)€4€1€8€,€-‚ ,>"/?1@6R†Z3@€104<€3)3F€4‚ €/)/K‚%€,O€3€/1,B €61F-F 4F8F‡]€8 €1 €4 €-€,,4-18@1?4Gh€,€-€8€1€4|-M,F1C8E4Gh€-€,€1€8€4o,6/;6E1:ƒ_3H€1†*€6€3€,€/|,5/H6V3Cƒ€,5*24J1B-B €3€/€6„ €1€4€*€-8/M6R,=3K‡€3 €6€/€,p*@-D8N1Dƒv€1€-€8€*F/E,C1B6KƒA;P|€6€;4Rs€43T|€/ €1€3€,U-(,643138Fˆ€8€1€4€-€,,>-C8P4@1@e€,€-€8€4€1-E,?4H1H8C?€8€1€4€,€-‚,B/?6K3M…DKZ?Hj€?€KL@@2tNKB;€@€Li€3LZ@H€B€N€6€,€/8€L€@ K\?IR€K€? /B,73<6NxLg@RA€3€6€/€@€L€,DE87u€D€8,=GO;?-D128M‚KIQ=@€;€G;€=€I…#€8€,€-€1>,0-C174G8R9€4€8€1 €-€,!,?-c 8;1.4F)€4€1€8€,€-,W#XB€W.€X,> YO/?1@6RZ]€YH€ZX?:€X:WM|X7 €WD€X"Sh3@€104<€3)3F€S€4\UIP„€8€I€1 €4 €-€,,4-18@1?4Gh€,€-€8€1€4|-M,F1C8E4Gh€-€,€1€8€4o,6/;6E1:ƒ_3H€1N`BL|€B€N~LP@@C€@€LKG?8€?€KELC@5s€6€@€LSfGQ€3€,€/|,5/H6V3C|€S€GaUCI5€I€U €,5*2POD?4J1B-B €3€/€6‚h€D€P$€1€4€*€-S]GJ /M6R,=3K†€S€G €3 €6GE;7€/€,gNKB< *@-D8N1D€G€;‚GPKD*9@3=7`€9€*€@€=9?@4*9=@3=A*@‚ €@€9<€=;>,<B>?B €*‚2€?€B€;€,,4;5??BIg€?€B€;€,,,;@?;BPe€,€;€?€B;F,:?6BGi€;€,€?€Bd;1,.B9?=B9<€G{€=€@€*2€9@?97*9=:[€* €@€=€9 *B9H@?=8e€*€9€@€=*E9G@G=:e€*€9€@€=l9I@]=I*EpGS€@j€=n€9€G,;BBA??€*‚€?4€B€,€;,4;JBc?G\€B€?€;€,,4;cBG?,\€,€;€B€?,7;8B9?9^€,€;€B€?w,6;W?JB]~IW€B€?e€,€;D€I3=A*9@Z9Su€@ €91€=€*%@K=?*798U€*€@€=€9==*E9D@Gf€=€*€9€@}*99A=?@Wp€*€9€=€@i9E*A@W=FQ€=‚€@€9,;9?MBW €*‚A€;€?€B€,,??BBO;]\€?€;€B€, ,CBA?C;Mh€,€B€?€;y,=B@?7;At€,€B€?€;lBS?G,?;Fy€?R€B€,€;=<*<D>@K9?‚1€D€=€@€*€9@D=;DA9A*Ak€=€@€9:€D €**:;=?9B<8Bp€*€;€?€B€8z8S*P;?BK?Ks€8€*€;€B€?fBM?S;**581‚R€?€;€8€B€* 9G@@>G*=‚G€*€@€>€9*E9M@O>P|€>€@€*€9s*<9E>F@Zh€*€9€>€@{*D>C9M@S\€*€9€> €@yBM;c,]?cq€B€;€,€?{,I;^BI?OK€;€B€? €, :7+5AH>@‚L€A€>€:€+:4A8+/>:S€>€A€+€::>+9A3>7`€:€+€A€>:?A4+9>p:>A3>A+@‚ €A€:<€><>-<C>@B €+‚2€@€C€<€--4<5@?CIg€@€C€<€--,<@@;CPe€-€<€@€C>B:<€H{€>€A€+2€:A?:7+9>:[€+ €A€>€: +B:HA?>8e€+€:€A€>+E:GAG>:e€+€:€A€>l:IA]>I+EpHS€Aj€>n€:€H-A+9AZ:Su€A €:1€>€+%AK>?+7:8U€+€A€>€:>=+E:DAGf€>€+€:€A}+9:A>?AWp€+€:€>€Ai:E+AAW>FQ€>‚€A€:-<9@MCW €+‚A€<€@€C€--?@BCO<]\€@€<€C€- -CCA@C<+<E>AK:?‚1€E€>€A€+€:AD>;EA:A+Ak€>€A€::€E €++:<=@9C<9Bp€+€<€@€C€9z9S+PFAZh€+€:€>€A{0D>C:MAS\€0€:€> €AyAM:c0]>c‚a€A€:€0€>-(,643138Fˆ€8€1€4€-€,,>-C8P4@1@e€,€-€8€4€1-E,?4H1H8C?€8€1€4€,€-‚,B/?6K3Mˆ€3€6€,€/‚J/B,73<6N9€3€6€/€,‚ ,=-D128Mˆ0€8€,€-€1>,0-C174G8R9€4€8€1 €-€,!,?-c 8;1.4F)€4€1€8€,€-‚ ,>"/?1@6R†Z3@€104<€3)3F€4‚ €/)/K‚%€,O€3€/1,B €61F-F 4F8F‡]€8 €1 €4 €-€,,4-18@1?4Gh€,€-€8€1€4|-M,F1C8E4Gh€-€,€1€8€4o,6/;6E1:ƒ_3H€1†*€6€3€,€/|,5/H6V3Cƒ€,5*24J1B-B €3€/€6„ €1€4€*€-8/M6R,=3K‡€3 €6€/€,p*@-D8N1Dƒv€1€-€8€*F/E,C1B6KƒA;P|€6€;4Rs€43T|€/ €1€3€,U-(,643138Fˆ€8€1€4€-€,,>-C8P4@1@e€,€-€8€4€1-E,?4H1H8C?€8€1€4€,€-‚,B/?6K3M…DKZ?Hj€?€KL@@2tNKB;€@€Li€3LZ@H€B€N€6€,€/8€L€@ K\?IR€K€? /B,73<6NxLg@RA€3€6€/€@€L€,DE87u€D€8,=GO;?-D128M‚KIQ=@€;€G;€=€I…#€8€,€-€1>,0-C174G8R9€4€8€1 €-€,!,?-c 8;1.4F)€4€1€8€,€-,W#XB€W.€X,> YO/?1@6RZ]€YH€ZX?:€X:WM|X7 €WD€X"Sh3@€104<€3)3F€S€4\USPGE„€8 €1 €4 €-€,,4-18@1?4Gh€4€1€8€-€,H€S€G(NO -M,F1C8E4Gh€N€-€,€1€8€4LCx€LFKN1,6/;6E1:i€KDC €DT3H€1N`BL|€B€N~LP@@C€@€LKG?8€?€KELC@5s€6€@€LSfGQ€3€,€/|,5/H6V3C|€S€GaUCI5€I€U €,5*2POD?4J1B-B €3€/€6‚h€D€P$€1€4€*€-S]GJ /M6R,=3K†€S€G €3 €6GE;7€/€,gNKB< *@-D8N1D€G€;‚GPKD*9@3=7`€9€*€@€=9?@4*9=@3=A*@‚ €@€9<€=;>,<B>?B €*‚2€?€B€;€,,4;5??BIg€?€B€;€,,,;@?;BPe€,€;€?€B;F,:?6BGi€;€,€?€Bd;1,.B9?=B9<€G{€=€@€*2€9@?97*9=:[€* €@€=€9 *B9H@?=8e€*€9€@€=*E9G@G=:e€*€9€@€=l9I@]=I*EpGS€@j€=n€9€G,;BBA??€*‚€?4€B€,€;,4;JBc?G\€B€?€;€,,4;cBG?,\€,€;€B€?,7;8B9?9^€,€;€B€?w,6;W?JB]~IW€B€?e€,€;D€I3=A*9@Z9Su€@ €91€=€*%@K=?*798U€*€@€=€9==*E9D@Gf€=€*€9€@}*99A=?@Wp€*€9€=€@i9E*A@W=FQ€=‚€@€9,;9?MBW €*‚A€;€?€B€,,??BBO;]\€?€;€B€, ,CBA?C;Mh€,€B€?€;y,=B@?7;At€,€B€?€;lBS?G,?;Fy€?R€B€,€;=<*<D>@K9?‚1€D€=€@€*€9@D=;DA9A*Ak€=€@€9:€D €**:;=?9B<8Bp€*€;€?€B€8z8S*P;?BK?Ks€8€*€;€B€?fBM?S;**581‚R€?€;€8€B€* 9G@@>G*=‚G€*€@€>€9*E9M@O>P|€>€@€*€9s*<9E>F@Zh€*€9€>€@{*D>C9M@S\€*€9€> €@yBM;c,]?cq€B€;€,€?{,I;^BI?OK€;€B€? €, :7+5AH>@‚L€A€>€:€+:4A8+/>:S€>€A€+€::>+9A3>7`€:€+€A€>:?A4+9>p:>A3>A+@‚ €A€:<€><>-<C>@B €+‚2€@€C€<€--4<5@?CIg€@€C€<€--,<@@;CPe€-€<€@€C>B:<€H{€>€A€+2€:A?:7+9>:[€+ €A€>€: +B:HA?>8e€+€:€A€>+E:GAG>:e€+€:€A€>l:IA]>I+EpHS€Aj€>n€:€H-A+9AZ:Su€A €:1€>€+%AK>?+7:8U€+€A€>€:>=+E:DAGf€>€+€:€A}+9:A>?AWp€+€:€>€Ai:E+AAW>FQ€>‚€A€:-<9@MCW €+‚A€<€@€C€--?@BCO<]\€@€<€C€- -CCA@C<+<E>AK:?‚1€E€>€A€+€:AD>;EA:A+Ak€>€A€::€E €++:<=@9C<9Bp€+€<€@€C€9z9S+PFAZh€+€:€>€A{0D>C:MAS\€0€:€> €AyAM:c0]>c‚a€A€:€0€>-(,643138Fˆ€8€1€4€-€,,>-C8P4@1@e€,€-€8€4€1-E,?4H1H8C?€8€1€4€,€-‚,B/?6K3M…DKZ?Hj€?€KL@@2tNKB;€@€Li€3LZ@H€B€N€6€,€/8€L€@ K\?IR€K€? /B,73<6NxLg@RA€3€6€/€@€L€,DE87u€D€8,=GO;?-D128M‚KIQ=@€;€G;€=€I…#€8€,€-€1>,0-C174G8R9€4€8€1 €-€,!,?-c 8;1.4F)€4€1€8€,€-,W#XB€W.€X,> YO/?1@6RZ]€YH€ZX?:€X:WM|X7 €WD€X"Sh3@€104<€3)3F€S€4\UIP„€8€I€1 €4 €-€,,4-18@1?4Gh€,€-€8€1€4|-M,F1C8E4Gh€-€,€1€8€4o,6/;6E1:ƒ_3H€1N`BL|€B€N~LP@@C€@€LKG?8€?€KELC@5s€6€@€LSfGQ€3€,€/|,5/H6V3C|€S€GaUCI5€I€U €,5*2POD?4J1B-B €3€/€6‚h€D€P$€1€4€*€-S]GJ /M6R,=3K†€S€G €3 €6GE;7€/€,gNKB< *@-D8N1D€G€;‚GPKD-C8P4@1@e€1€4€8€-€,-E,?4H1H8C?€8€1€4€,€-e€D3,B/?6K3MƒNBHqGBjLGo€3€6€,€/‚J/B,73<6N9€3€6€/€,€L@KA%€G€BLF€KY,=KO-D €L128M‚,D=‚bG3ƒ"€8€-€,€1>,0 -C174G8R8€4€1€8€,€-,?-c 8;1.4F)€4€1€8€,€-‚ ,>BE /? €D1@6R€K€G%D<ƒX=543@€14<€3)3F€4€B‚ €/!BA/K€Di€B@'€,€=:B3€3€@€/1,B@8€6€B1F-F 4F8F?P€@‚@4€?N;-ƒ3€8 €1 €4 €-€,#,4-18@1?4GX€4€1€8€-€,C€@9-M,F1C8E4Gh€4€8€1€,€-sBA €;=G.5,61:3;6ELFƒ2€LK6 /H€1…€G€B€6€/€,€3eGJ,5/H6V3CMB@€GgDCM€,5*24J1B-B €3€/€6‚G€K =K8€1€4€*€-7€B€Dk/M6R,=3K„€= 8a=E;€8.€3 €6€/€,"?V!€=,€?*@@X-D8N1D‚}BS€@€BL€1€-€8€*!;CGJ/E,C1B6K‚w€;+=LIa€64Rq€G€43T3€=(€I!€/ €1€3€,H%J1P 8;&;??8”8€;€?@€8B€%€1¤ÿ/MTrkEÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------±y±± Á@± X±s±[± ±±e±d±@±&±e±d±@±e±d± á@±e±dÿG---- End of CH Setup --------------------------------------------------û~± ± e‘KMiK‘LB|‘K<LGK‘GOUG;‘BOa‘D@B^Dt‘=N‚ =f‘BH‰{B‡f‘KUK‘LG‘NELk‘LZ NVL‘GWxG_‘KZ/KH‘DM‚DS‘BI‚Bu‘DP„5D‘=JƒM=…Z‘KUv‘LBKqL ‘KSZK‘GErG‘B@{‘DMBVD‚‘=L‚=b‘BS†~B1‘D]DT‘GO/GM‘BP‚DB8‘D^‚DY‘=O‚=M‘BO\B~‘@O‚f@u‘?Sq?‘@Sk@ ‘GG*G@‘IWIu‘DO‚5D‘BO„[B<‘@Dx@ƒ`± ± e‘KMiK‘LB|‘K<LGK‘GOUG;‘BOa‘D@B^Dt‘=N‚ =f‘BH‰{B‡f‘KUK‘LG‘NELk‘LZ NVL‘GWxG_‘KZ/KH‘DM‚DS‘BI‚Bu‘DP„5D‘=JƒM=…Z‘KUv‘LBKqL ‘KSZK‘GErG‘B@{‘DMBVD‚‘=L‚=b‘BS†~B1‘D]DT‘GO/GM‘BP‚DB8‘D^‚DY‘=O‚=M‘BO\B~‘@O‚f@u‘?Sq?‘@Sk@ ‘GG*G@‘IWIu‘DO‚5D‘BO„[B<‘@Dx@õE‘KTiK‘LI|‘KCLGK‘GVUG;‘BVa‘DGB^Dt‘=U‚ =f‘BO‰{B‡z‘KGk‘LMK}‘NEL`‘LX NiL ‘KOJK*‘DMDg‘I]I‘BUpB‘@DI@+‘BMGB‘;D‚;<‘=M‡z=…"‘KGy‘LMK\‘K]L@K‘G]LG4‘DRxD‘GJ[Gx‘BW‚B\‘DI‚Da‘=S‚C=A‘BP‚{B>‘GS1GA‘?R‚?C‘@S‚@N‘;]‚;`‘IUlIr‘GW^Gt‘GK2‘I5G/‘K@I‘L]KVL‘KWrK‘DODL‘IZfI‘DRnD}‘BCtB‘DC{‘;FDX;‘@Th@‚g‘NZdNZ‘POˆbPt‘NZjN‘PG~P‘SZvS‘PZ]P/‘NZNi‘PZPg‘Lf}‘ND LCN‘KOTK5‘LT‚ALA‘GX†mG#‘IR}I‘KO>K,‘DZ„&DC‘GM‚1G‘BWB]‘DW,DH‘=R=P‘BfBk‘BK>‘DYB‚wD9‘=Z†= ‘DcsDA‘I^lI*‘Kh_K6‘LS'L ‘KW+K‘G] G‘S]†S‘NcN(‘PiP‘SRS‘PW„VPl‘UL(UZ‘U[‡EUM‘SS SP‘UZU^‘PK*PL‘S[ Sb‘Pc Pq‘NXtN‘Pb‚P„›ÿ/MTrkÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² Â#² 4²P²[² ²²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ x’,dx‚,x’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ ’,dx‚,’%dx‚%’,dx‚,’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ x’,dx‚,x’dp‚x’%dx‚%’dx‚x’*dx‚*’ dx‚ x’,dx‚,’'dx‚'’ dx‚ ’,dx‚,x’ dx‚ x’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’ dx‚ ’,dx‚,’'dx‚'’ dx‚ ’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!x’-dx‚-x’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!’-dx‚-’&dx‚&’-dx‚-’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!x’-dx‚-x’dp‚x’&dx‚&’dx‚x’+dx‚+’!dx‚!x’-dx‚-’(dx‚(’!dx‚!’-dx‚-x’!dx‚!x’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’!dx‚!’-dx‚-’(dx‚(’!dx‚!’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ x’,dx‚,x’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ ’,dx‚,’%dx‚%’,dx‚,’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’dx‚x’*dx‚*x’ dp‚ x’'dx‚'’ dx‚ x’,dx‚,’ dx‚ x’ dx‚ ’,dx‚,’'dx‚'’ dx‚ x’,dx‚,x’dp‚x’%dx‚%’dx‚x’*dx‚*’ dx‚ x’,dx‚,’'dx‚'’ dx‚ ’,dx‚,x’ dx‚ x’dp‚x’%dx‚%’dx‚x’*dx‚*’dx‚x’dx‚’*dx‚*’%dx‚%’ dx‚ ’,dx‚,’'dx‚'’ dx‚ ’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!x’-dx‚-x’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!’-dx‚-’&dx‚&’-dx‚-’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’dx‚x’+dx‚+x’!dp‚!x’(dx‚(’!dx‚!x’-dx‚-’!dx‚!x’!dx‚!’-dx‚-’(dx‚(’!dx‚!x’-dx‚-x’dp‚x’&dx‚&’dx‚x’+dx‚+’!dx‚!x’-dx‚-’(dx‚(’!dx‚!’-dx‚-x’!dx‚!x’dp‚x’&dx‚&’dx‚x’+dx‚+’dx‚x’dx‚’+dx‚+’&dx‚&’!dx‚!’-dx‚-’(dx‚(’!dx‚!’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’%dx‚%’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’!d…P‚!x’-dx‚-x’(dx‚(’!dx‚!x’!dx‚!’-dx‚-’!dx‚!x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’%dx‚%’*dx‚*’,dx‚,’1dx‚1’d…P‚x’*dx‚*x’%dx‚%’dx‚x’dx‚’*dx‚*’dx‚x’ d…P‚ x’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’,dx‚,x’ dx‚ ’d…P‚’ dp‚ x’'dx‚'’ dx‚ x’ dx‚ ’'dx‚'’ dx‚ x’dp‚x’lx‚p’ dx‚ ’,dx‚,x’'dx‚'’ dx‚ x’ dx‚ ’ dx‚ x’ dx‚ ’%d•H‚%¤vÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ ÃP³ @³F³[³ ³³e³d³@³&³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrkÛÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ Ä0´ @´d´[´ ´´e´d´@´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------”_d´ %x´ &x´ (x´ )x´ +x´ ,x´ -x´ /x´ 0x´ 2x´ 3x´ 5x´ 6x´ 7x´ 9x´ #´ :x´ x´ @x´ Ax´ Cx´ Dx´ Fx´ Gx´ Hx´ Jx´ Kx´ Mx´ Nx´ Px´ Qx´ Rx´ Tx´ Ux´ Wx´ Xx´ Zx´ [x´ \x´ ^x´ _x´ ax´ bx´ dx´ ex´ fx´ hx´ ix´ kx´ lx´ nx´ ox´ px´ rx´ sx´ ux´ vx´ xx´ yx´ zx´ |x´ }x´ „_”_¬v´  ´ ~P´ }(´ |P´ {(´ z(´ y(´ w(´ v(´ u(´ s(´ q(´ p(´ n(´ l(´ j(´ g(´ e(´ c(´ `(´ ^(´ [(´ X(´ U(´ R(´ O(´ L(´ H(´ E(´ A(´ >(´ :(´ 6(´ 2(´ .(´ )(´ %(´ !(´ (´ (´ (´ (´ (´  „_´ \´ ö´  ”_¼„_”_¼„_”_¼„_”_¼„_”`¼„`”`¼„`”_´ \´ º„_”_»v´  „_”_¼„_”_¼„_”_¼„_”_¼„_”`¼„`”`¼„`”_¼„_”_»b´ „_´ ”_‡h´ ~…(´ }„´ |ƒ´ {‚@´ z‚@´ y‚´ xp´ wp´ vp´ uH´ tp´ sH´ r ´ qH´ p ´ oH´ n ´ m ´ l ´ k ´ jx´ i ´ h ´ gx´ fx´ e ´ dx´ cx´ b ´ ax´ `P„_”_(´ _x´ ^x´ ]x´ \x´ [P´ Zx´ Yx´ Xx´ WP´ Vx´ Ux´ TP´ Sx´ Rx´ QP´ Px´ OP´ NP´ Mx´ LP´ Kx´ JP´ IP´ Hx´ GP´ FP´ EP´ Dx´ CP´ BP´ AP´ @P´ ?x´ >P´ =P´ Dˆ…>‚~•CI:…C•A?F•@N…A„$…@-•V…r…>_•CO…Cm•ATG…A*•CT‚…CZ•@Lƒ:…@?•_†>^–DJ–Eb†D,†E'–CVB†C%–AK/†AR–CT†Cl–UJ†>=–9f'†9K–l†>]–>^†>@–Cf6†CB–C^Y†C&–E^h†E –_†>^–DJ–Eb†D,†E'–CVB†C%–AK/†AR–CT†Cl–UJ†>=–9f'†9K–l†>]–>^†>@–Cf6†CB–C^Y†C&–E^h†E –ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------·y·· Ç· @··[· ··e·d·@·&·e·d·@·e·d· ç@·e·dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¸y¸¸ ȸ @¸d¸[¸ ¸¸e¸d¸@¸&¸e¸d¸@¸e¸d¸ è@¸e¸dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrkR¨ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹¹ ɹ @¹d¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------‚™,UP‰, ™'dP‰' ™,UP‰,ƒ™,UP‰, ™'dP‰' ™,UP‰,ƒ™,UP‰, ™'dP‰' ™,UP‰,ƒ™,UP‰, ™'dP‰' ™,UP‰,ƒ™,UP‰, ™'dP‰' ™,UP‰,ƒ™,UP‰, ™'dP‰' ™,UP‰, ™&dP‰& ™,UP‰,(™&@P‰&(™&d™'dP‰&‰' ™,UP‰,(™&dP‰& ™&dP‰&(™,UP‰,(™&dP‰&(™$t™'d™3dP‰$‰'‰3 ™&d™.MP‰&‰. ™$t™*_™1dP‰$‰*‰1 ™.MP‰. ™$t™'d™&d™,U ‰,F‰$‰'‰&(™*_P‰*(™.MP‰. ™$t™*_P‰$‰* ™.MP‰. ™$t™&d™,U ‰,F‰$‰&(™*_™'dP‰*‰'(™.MP‰. ™$t™*_P‰$‰* ™.MP‰. ™$t™'d™&d™,U ‰,F‰$‰'‰&(™*_P‰*(™.MP‰. ™$t™*_P‰$‰* ™.MP‰. ™$t™&d™,U ‰,F‰$‰&(™*_™'dP‰*‰'(™.MP‰. ™$t™*_P‰$‰* ™.MP‰. ™$t™'d™&d™,U ‰,F‰$‰'‰&(™*_P‰*(™.MP‰. ™$t™*_P‰$‰* ™.MP‰. ™$t™&d™,U ‰,F‰$‰&(™*_™'dP‰*‰'(™#iP‰#(™,UP‰,(™$t™*_™3dP‰$‰*‰3‚™@FP‰@ ™Fd™?FP‰F‰?(™@F™3d™$tP‰@‰3‰$(™FdP‰Fƒ™@F™'dP‰@‰'(™$t™&d™,U™3d ‰,F‰$‰&‰3(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™#iP‰@‰#(™Fd™@FP‰F‰@(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.M™#iP‰.‰#(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.M™#iP‰@‰.‰#(™Fd™@F™KFP‰F‰@‰K(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U™8M ‰,F‰$‰'‰&‰8(™Fd™?F™*_P‰F‰?‰*(™@F™.M™2FP‰@‰.‰2(™Fd™#i™2F™'dP‰F‰#‰2‰'(™$t™*_P‰$‰*(™KF™/F™'dP‰K‰/‰'(™.M™'dP‰.‰'(™@F™'d™#i™-FP‰@‰'‰#‰-(™$t™&d™,U™3d ‰,F‰$‰&‰3(™?F™*_™'dP‰?‰*‰'(™@F™#iP‰@‰#(™KF™'dP‰K‰'(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.M™#iP‰.‰#(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.M™#iP‰@‰.‰#(™Fd™@F™KFP‰F‰@‰K(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U™8M ‰,F‰$‰'‰&‰8(™Fd™?F™*_P‰F‰?‰*(™@F™.M™2FP‰@‰.‰2(™Fd™#i™2F™'dP‰F‰#‰2‰'(™$t™*_P‰$‰*(™KF™/F™'dP‰K‰/‰'(™.M™'dP‰.‰'(™@F™'d™#i™-FP‰@‰'‰#‰-(™$t™&d™,U™3d ‰,F‰$‰&‰3(™?F™*_™'dP‰?‰*‰'(™@F™#iP‰@‰#(™KF™'dP‰K‰'(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.M™#iP‰.‰#(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.M™#iP‰@‰.‰#(™Fd™@F™KFP‰F‰@‰K(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U™8M ‰,F‰$‰'‰&‰8(™Fd™?F™*_P‰F‰?‰*(™@F™.M™2FP‰@‰.‰2(™Fd™#i™2F™'dP‰F‰#‰2‰'(™$t™*_P‰$‰*(™KF™/F™'dP‰K‰/‰'(™.M™'dP‰.‰'(™@F™'d™#i™-FP‰@‰'‰#‰-(™$t™&d™,U™3d ‰,F‰$‰&‰3(™?F™*_™'dP‰?‰*‰'(™@F™#iP‰@‰#(™KF™'dP‰K‰'(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.M™#iP‰.‰#(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.M™#iP‰@‰.‰#(™Fd™@F™KFP‰F‰@‰K(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U™8M ‰,F‰$‰'‰&‰8(™Fd™?F™*_P‰F‰?‰*(™@F™.M™2FP‰@‰.‰2(™Fd™#i™2F™'dP‰F‰#‰2‰'(™$t™*_P‰$‰*(™KF™/F™'dP‰K‰/‰'(™.M™'dP‰.‰'(™@F™'d™#i™-FP‰@‰'‰#‰-(™$t™&d™,U™3d ‰,F‰$‰&‰3(™?F™*_™'dP‰?‰*‰'(™@F™#iP‰@‰#(™KF™'dP‰K‰'(™$t™*_™1dP‰$‰*‰1 ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@F™'dP‰@‰'(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™&d™,U ‰,F‰$‰&(™Fd™?F™*_™'dP‰F‰?‰*‰'(™@F™.MP‰@‰.(™Fd™@F™KFP‰F‰@‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™FdP‰F(™$t™*_P‰$‰*(™KFP‰K(™.MP‰.(™@FP‰@(™$t™'d™&d™,U ‰,F‰$‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™.MP‰@‰.(™Fd™KFP‰F‰K(™$t™*_P‰$‰* ™.MP‰.(™@F™KFP‰@‰K(™'d™&d™,U ‰,F‰'‰&(™Fd™?F™*_P‰F‰?‰*(™@F™3d™#iP‰@‰3‰#(™Fd™&BP‰F‰&(™*_™&dP‰*‰&(™KFP‰K(™#i™&BP‰#‰&(™@F™'dP‰@‰'(™&dP‰&(™Fd™?F™'d™&dP‰F‰?‰'‰&(™@F™#i™&dP‰@‰#‰&(™Fd™@F™KF™#iP‰F‰@‰K‰#(™1d™$tP‰1‰$ ™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™FdP‰F ™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™Fd™KFP‰F‰K‚™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™FdP‰F ™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™Fd™@F™KFP‰F‰@‰K‚™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™FdP‰F ™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™Fd™KFP‰F‰K‚™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™FdP‰F ™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™Fd™?FP‰F‰?(™@F™,UP‰@‰,(™Fd™@F™KFP‰F‰@‰K(™3dP‰3 ™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™?FP‰?(™@F™,UP‰@‰,‚™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™?FP‰?(™@F™,UP‰@‰,(™KFP‰K‚™,UP‰,(™@F™KFP‰@‰K(™'dP‰'(™?FP‰?(™@F™,UP‰@‰,‚™KFP‰K(™,UP‰,(™@FP‰@(™'dP‰'(™?FP‰?(™@F™,UP‰@‰,(™@F™KFP‰@‰K‚™,UP‰,(™KFP‰K(™'dP‰' ™,UP‰,‚™KFP‰K(™,UP‰, ™'dP‰' ™,UP‰,(™KFP‰K‚™,UP‰,(™KFP‰K(™'dP‰' ™,UP‰,‚™KFP‰K‚™'dP‰' ™'d™,UP‰'‰,(™KF™#iP‰K‰#(™$t™1dP‰$‰1¡™$P‰$˜ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ @ºdº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------»y»» Ë» @»d»[» »»e»d»@»&»e»d»@»e»d» ë@»e»dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrkÀÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¼y¼¼ ÌX¼ j¼2¼[¼ ¼¼e¼d¼@¼&¼e¼d¼@¼e¼d¼ ì@¼e¼dÿG---- End of CH Setup --------------------------------------------------‚êœSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTó`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œSdxŒSpœSWxŒSƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒTƒ`œTdxŒTpœTWxŒT‚¬.ÿ/MTrk Žÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------½y½½ ͽ ½d½[½ ½½e½d½@½&½e½d½@½e½d½ í@½e½dÿG---- End of CH Setup --------------------------------------------------„ؽ =8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$>8<>‚,>-<><>=<>‚,>3<>4>?<>4>0<><>?<>ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,=-<=<==<=‚,=3<=4=?<=4=0<=<=?<=ƒ$=8<=‚,½ y=-<=<½ x==<=‚,½ u=3<=4½ s=?<=4½ q=0<=<½ p=?<=ƒ$½ m=8<=‚,½ j=-<=<½ i==<=‚,½ f=3<=4½ d=?<=4½ b=0<=<½ a=?<=ƒ$½ ]=8<=‚,½ Z=-<=<½ Y==<=‚,½ V=3<=4½ T=?<=4½ R=0<=<½ Q=?<=ƒ$½ N=8<=‚,½ K=-<=<½ J==<=‚,½ G=3<=4½ E=?<=4½ C=0<=<½ B=?<=ƒ$½ >=8<=‚,½ ;=-<=<½ :==<=‚,½ 7=3<=4½ 5=?<=4½ 3=0<=<½ 2=?<=ƒ$½ /=8<=‚,½ ,=-<=<½ +==<=‚,½ (=3<=4½ &=?<=4½ $=0<=<½ #=?<=ƒ$½ =8<=‚,½ =-<=<½ ==<=‚,½ =3<=4½ =?<=4½ =0<=<½ =?<=ƒ$½ =8<=‚,½ =-<=<½ ==<=‚,½ =3<=4½ =?<=4½ =0<=<½ =?<=½bÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¾y¾¾ ξ @¾d¾[¾ ¾¾e¾d¾@¾&¾e¾d¾@¾e¾d¾ î@¾e¾dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¿y¿¿ Ï¿ @¿d¿[¿ ¿¿e¿d¿@¿&¿e¿d¿@¿e¿d¿ ï@¿e¿dÿG---- End of CH Setup --------------------------------------------------Šâ\ÿ/simutrans-124.3/simutrans/music/48-Techno-movement.mid000066400000000000000000002074211474050137200227220ustar00rootroot00000000000000MThdàMTrk"ÿÿCopyright (C) 2018ÿ---Technological Movement---ÿ(C) 2018 RykSebÿCan be used anyÿways if you giveÿthe credit properly.ÿQB@ÿSetupÿXpÿQâ6ÿTechnological MovementÿX¼ÿ by RykSeb¼ÿA2øÿA3øÿBøÿB2øÿCøÿC2øÿDøÿD2øÿEøÿE2ÿ/MTrk¦ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------ÿ/MTrk{ÿKeysÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° À° *°d°[° °°e°d°@°&°e°d°@°e°d° à@°e°dÿG---- End of CH Setup --------------------------------------------------.4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7ES@F9D>0‹<€9€@€E€>ƒ,4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7ES@F9D>0‹<€9€@€E€>ƒ,4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7@SS9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7@SS9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I>J4?‡C€;€>%€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?>J‡Q€;€>€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I>J4?‡C€;€>%€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I>J4?‡C€;€>%€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I>J4?‡C€;€>%€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ƒ°U4/5;@N9H‡(€9€5.€4€@94<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I4?78>J‡Q€;€>€4€7/4K7S;A>G\€;€>€4€74C;D7G>]#€; €> €4 €7CS@F9D<0‹<€9€@€C€<ƒ$4/5;@N9H‡(€9€5.€4€@C4<9N@PF€9€@€44J@L9O5Q\€9€5€@€4>S9L5J4AŒg€5€9€4€>‚;I>J4?‡C€;€>%€4/4K;A>G\€;€>€44C;D>]#€; €> €4 ES@F9D>0‹<€9€@€E€>ÿ/MTrk ÖÿBellÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------±y±± ÁX± T±d±[± ±±e±d±@±&±e±d±@±e±d± á@±e±dÿG---- End of CH Setup --------------------------------------------------‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]ð‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]ð‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘VdpVp‘TdpTp‘VdpVp‘XdpXp‘TdpTp‘SdpSp‘LdpLp‘JdpJp‘HdpHp‘EdpEƒ`‘HdpH‘JdpJ‘LdpL‘TdpTp‘SdpSp‘JdpJp‘LdpLp‘SdpSp‘QdpQp‘SdpS‘UdpU‘XdpX‘]dp]ÿ/MTrk .ÿPadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² Â2² <²2²[² ²²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------»&² 8x’Ld’Xdx² 9…P² :ƒ$² ;‚,² p² ?4² @x² A4² B4² Cx² Dx² Ex² Fx² Gx² Hx² Ix² Jx‚J‚V² K’Od’[dx² Lx² M<² Nx² Ox² P<² Qx² R<² Sx² T<² Ux² V<² Wx² X<² Y<² Zx² [<² \<² ]x² ^<² _<² `<‚O‚[² a’Qd’]dx² b<² c<² d<² e<² f<² gx² h<² i<² j<² k<² l<² m<² n<² o<² p<² q ² q4² p4² o<² nx² m<² l<² k<² j<² i² h‚Q’Md’Xd‚X‚M’Od’Vd‚]‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Q’Md’Xd’]d‚M‚X’Od’Vd‚]‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Qø’]dž’[d‚[’Xd‚]‚X’]d’Vd’Md‚M‚V’[d’Od‚O‚[’Ld’Vd‚V‚L’Xd’Qd‚]‚X‚Q’Md’Xd‚M‚X’Od’Vd‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Q’Md’Xd‚M‚X’Od’Vd‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Q’Md’Xd‚M‚X’Od’Vd‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Q’Md’Xd‚M‚X’Od’Vd‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’Qd‚]‚U‚Q’Md’Xd‚M‚X’Od’Vd‚O‚V’[d’Ld’Sd‚S‚L’Qd’Xd‚[‚Q‚X’Md’Xd’]d‚M‚X‚]’Od’Vd’_d‚O‚V‚_’[d’Ld’Sd‚[‚L‚S’]d’Ud’QdŽv² h ‚]‚U‚Q’Md’Xdf² g4² f4² e4² d4² c4² bp² a4² `4² _4² ^ ‚M‚X’Od’Vd*² ]4² \p² [4² Z4² Y4² X4² W4² Vp² U4² T ‚O‚V’[d’Ld’Sd*² S4² R4² Q4² Pp² O4² N4² M4² L4² K4² JF‚S‚L’Qd’Xd*² I4² H4² G4² F4² E4² D4² CP² Bx² A4² @p² ?2‚[‚Q‚X’Ld’Xd² >4² =p² <4² ;4² :p² 94² 84² 7p² 6 ² 7<² 6d‚L‚X’Jd’Vd² 5x² 44² 3x² 2x² 14² 0x² /x² .x² -4² ,x² +x² *4² )x² (Z² * ‚J‚V’Od’[dn² +x² ,x² -x² .x² /x² 0<² 1x² 2x² 3x² 4x² 5x² 6x² 7x² 8x² 9x² :F‚O‚[’Qd’]d2² ;x² x² ?<² @x² Ax² Bx² Cx² Dx² Ex² Fx² Gx² Hx² Ix² Jx² K ‚Q‚]F² Lÿ/MTrkÿLeadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ ÃP³ L³d³[³ ³³e³d³@³&³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------ð#“@X“LX‚+ƒ@ƒLO“@Z“LZDƒ@ƒL“@V“LV9ƒ@ƒL>“@]“L]Sƒ@ƒL,“CQ“OQCƒCƒO/“>U“JU4ƒ>ƒJA“@Y“LY‚Rƒ@ƒL“>Z“JZ‚'ƒ>ƒJ.“>X“JXVƒ>ƒJ“>e“Je-ƒ>ƒJA“>Q“JQfƒ>ƒJ“@W“LWQƒ@ƒL(“>b“JbEƒ>ƒJ,“]“J]Eƒ>ƒJ8“@e“Leƒ@ƒL]“HV“TV/ƒHƒTD“G_“S_2ƒGƒSA“Hb“Tb.ƒHƒTH“Gc“Sc~ƒGƒSk“C`“O`?ƒCƒO5“>c“Jcƒ>ƒJX“Cf“Of ƒCƒO\“@]“L]‚vƒ@ƒLj“@X“LX‚$ƒ@ƒLE“@]“L]bƒ@ƒL“7]“C]9ƒ7ƒC?“9W“EW1ƒ9ƒE5“CO“OOAƒCƒO0“>W“JW@ƒ>ƒJ;“@]“L]3ƒ@ƒLD“]“J]3ƒ>ƒJD“>Z“JZ?ƒ>ƒJ4“@X“LX>ƒ@ƒL/“>]“J]4ƒ>ƒJ8“7[“C[-ƒ7ƒCO“;c“Gc7ƒ;ƒGB“]“J]9ƒ>ƒJ3“MP“AP1ƒMƒAB“@Z“LZ?ƒ@ƒL1“GZ“SZ?ƒGƒS8“JW“VW9ƒJƒV8“HZ“TZ?ƒHƒT8“G_“S_1ƒGƒS8“CZ“OZMƒCƒO#“JX“VXiƒJƒV“Oe“[eiƒOƒ[“CZ“OZIƒCƒO/“@Z“LZIƒ@ƒL/“LZ“XZiƒLƒX“J]“V]x“IZ“UZƒJƒV3ƒIƒU'“Ge“SeGƒGƒS)“Eb“Qb6ƒEƒQH“JZ“VZ;ƒJƒV/“IO“UO=ƒIƒU2“J`“V`DƒJƒV@“Lc“Xc&ƒLƒXT“EZ“QZ‚ƒEƒQìPã$“]d“Qd!ãX*(ã3(ãM8(ã<(ã}=(ã?(ãC?(ã]?(ãe?(ã@Wƒ]ƒQ“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“QK<ƒQ<“QK<ƒQ<“QK<ƒQ<“QK<ƒQ<“]K<ƒ]4“QK<ƒQ<“]K<ƒ]4“QK<ƒQ<“]K<ƒ]4“QK<ƒQ<“]K<ƒ]<“XK<ƒX<“]K<ƒ]<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[4“OK<ƒO<“[K<ƒ[<“]K<ƒ]<“[K<ƒ[<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO4“OK<ƒO<“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[4“OK<ƒO<“OK<ƒO<“OK<ƒO<“[K<ƒ[<“QK<ƒQ<“QK<ƒQ<“QK<ƒQ<“QK<ƒQ<“]K<ƒ]4“QK<ƒQ<“]K<ƒ]4“QK<ƒQ<“]K<ƒ]4ã$“]d“Qd!ãX*(ã3(ãM8(ã<(ã}=(ã?(ãC?(ã]?(ãe?(ã@P“XU“LUƒ]ƒQ5ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL4“QU“EU<ƒQƒE4“LU“@U<ƒLƒ@4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“YU“MU<ƒYƒM<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ4“VU“JU<ƒVƒJ4“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ“XU“LU<ƒXƒL“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“OU“CU<ƒOƒC<“]U“QU<ƒ]ƒQ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“LU“@U<ƒLƒ@<“QU“EU<ƒQƒE<“VU“JU<ƒVƒJ<“[U“OU<ƒ[ƒO“]U“QU<ƒ]ƒQ“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“XU“LU<ƒXƒL4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL4“QU“EU<ƒQƒE4“LU“@U<ƒLƒ@4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“YU“MU<ƒYƒM<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ4“VU“JU<ƒVƒJ4“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ“XU“LU<ƒXƒL“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“SU“GU<ƒSƒG<“_U“SU<ƒ_ƒS<“[U“OU<ƒ[ƒO<“SU“GU<ƒSƒG<“_U“SU<ƒ_ƒS<“SU“GU<ƒSƒG<“`U“TU<ƒ`ƒT<“TU“HU<ƒTƒH<“_U“SU<ƒ_ƒS<“XU“LU<ƒXƒL<“UU“IU<ƒUƒI<“XU“LU<ƒXƒL<“UU“IU<ƒUƒI<“SU“GU<ƒSƒG<“UU“IU<ƒUƒI<“SU“GU<ƒSƒG<“LU“@U<ƒLƒ@<“QU“EU<ƒQƒE<“UU“IU<ƒUƒI<“[U“OU<ƒ[ƒO“]U“QU<ƒ]ƒQ“dU“XU<ƒdƒX<“]U“QU<ƒ]ƒQ<“dU“XU<ƒdƒX4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL4“QU“EU<ƒQƒE4“LU“@U<ƒLƒ@4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“YU“MU<ƒYƒM<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ4“VU“JU<ƒVƒJ4“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ“XU“LU<ƒXƒL“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“OU“CU<ƒOƒC<“]U“QU<ƒ]ƒQ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“LU“@U<ƒLƒ@<“QU“EU<ƒQƒE<“VU“JU<ƒVƒJ<“[U“OU<ƒ[ƒO“]U“QU<ƒ]ƒQ“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ<“XU“LU<ƒXƒL4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL4“QU“EU<ƒQƒE4“LU“@U<ƒLƒ@4“XU“LU<ƒXƒL<“XU“LU<ƒXƒL<“QU“EU<ƒQƒE<“XU“LU<ƒXƒL<“YU“MU<ƒYƒM<“XU“LU<ƒXƒL<“VU“JU<ƒVƒJ4“VU“JU<ƒVƒJ4“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“JU“>U<ƒJƒ><“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ<“VU“JU<ƒVƒJ“XU“LU<ƒXƒL“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“OU“CU<ƒOƒC<“[U“OU<ƒ[ƒO<“VU“JU<ƒVƒJ<“SU“GU<ƒSƒG<“_U“SU<ƒ_ƒS<“[U“OU<ƒ[ƒO<“SU“GU<ƒSƒG<“_U“SU<ƒ_ƒS<“SU“GU<ƒSƒG<“`U“TU<ƒ`ƒT<“TU“HU<ƒTƒH<“_U“SU<ƒ_ƒS<“XU“LU<ƒXƒL<“UU“IU<ƒUƒI<“XU“LU<ƒXƒL<“UU“IU<ƒUƒI<“SU“GU<ƒSƒG<“UU“IU<ƒUƒI<“SU“GU<ƒSƒG<“LU“@U<ƒLƒ@<“QU“EU<ƒQƒE<“UU“IU<ƒUƒI<“[U“OU<ƒ[ƒO“]U“QU<ƒ]ƒQ“dU“XU<ƒdƒX<“]U“QU<ƒ]ƒQ<“dU“XU<ƒdƒX<“]O“QO<ƒ]ƒQ<“`O“TO<ƒ`ƒT<“[I“OI<ƒ[ƒO<“]G“QG<ƒ]ƒQ<“XE“LE<ƒXƒL<“[D“OD<ƒ[ƒO<“VB“JB<ƒVƒJ<“X@“L@<ƒXƒL<“T>“H><ƒTƒH<“V<“J<<ƒVƒJ<“S:“G:<ƒSƒG<“T9“H9<ƒTƒH<“Q7“E7<ƒQƒE<“S5“G5<ƒSƒG<“O3“C3<ƒOƒC<“Q1“E1<ƒQƒE<“L0“@0<ƒLƒ@<“O.“C.<ƒOƒC<“J,“>,<ƒJƒ><“L*“@*<ƒLƒ@<“H(“<(<ƒHƒ<<“J&“>&<ƒJƒ><“G%“;%<ƒGƒ;<“H#“<#<ƒHƒ<<“E!“9!<ƒEƒ9<“G“;<ƒGƒ;<“C“7<ƒCƒ7<“E“9<ƒEƒ9<“@“4<ƒ@ƒ4<“C“7<ƒCƒ7<“>“2<ƒ>ƒ2<“@“4<ƒ@ƒ4<“<“0<ƒ<ƒ0ÿ/MTrkEÿLead2ÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ Äd´ 1´d´[´ ´´e´d´@´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------‚è”Ldƒ`„L…P”Edp„E”Jdp„J”Ldp„Lp”Jdp„Jp”Edp„Ep”Gdp„G”Hdƒ`„H”Gdp„Gp”Cdp„Cp”@dp„@p”>dp„>”@dp„@‰0”Edp„E”Gdp„G”Hdp„H”Ldƒ`„L…P”Edp„E”Jdp„J”Ldp„Lp”Odp„Op”Jdp„Jp”Cdp„Cp”Qdp„Q”Odp„O”Cdp„Cp”Mdp„M”Ldp„L”Cdp„C”Gdp„G”Hdp„H…P”Tdp„T”Sdp„Sp”Odp„O”Jdp„J”Ldƒ`„L…P”Edp„E”Jdp„J”Ldp„Lp”Jdp„Jp”Edp„Ep”Gdp„G”Hdƒ`„H”Gdp„Gp”Cdp„Cp”@dp„@p”>dp„>”@dp„@‰0”Edp„E”Gdp„G”Hdp„H”Ldƒ`„L…P”Edp„E”Ldp„L”Odp„Op”Mdp„Mp”Ldp„Lp”Jdp„J”Sdp„S”Tdp„T”Odp„O”Cdp„C”Qdp„Q”Edp„E”Sdp„S”Gdp„G”Tdp„T”Hdp„H”Vdp„V”Jdp„J”Tdp„T”Hdx„H”Vdp„V”Jdx„J”Xdp„Xƒ`”[d„[‰0”Qdp„Q”Sdp„S”Tdp„T”[dƒ`„[”]dƒ`„]”Xdƒ`„X”[dp„[x”Td‚h„T‰0”Qdx„Q”Sdx„S”Tdx„T”Vdx„V”Xdƒ`„X”Vdƒ`„V”Odƒ`„Op”Xdp„X”Vdƒ`„V”Odƒ`„Oƒ`”Qdx„Q”Sdx„S”Tdx„T”]dx„]”[dƒ`„[”Vdƒ`„V”Sdƒ`„Sp”[dp„[”Vdƒ`„V”Udƒ`„U”Vdƒ`„V”Xdƒ`„X”Tdp„T…P”Odp„O”Tdp„T”]dp„]”[d‡@„[p”Odp„O”Tdp„T”]dp„]”[dƒ`„[”]dƒ`„]”Xdƒ`„X”[dp„[p”Sdx„S”Td‚h„Tˆ8”Odx„O”Qdx„Q”Sdx„S”Tdx„T”Vdx„V”Xdƒ`„X”Vdƒ`„V”Odƒ`„Op”Xdp„X”Vdƒ`„V”Odƒ`„Oƒ`”Qdx„Q”Sdx„S”Tdx„T”]dx„]”[dƒ`„[”Vdƒ`„V”Sdƒ`„S”[dƒ`„[”]dƒ`„]õPÿ/MTrkgÿGtÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------µyµµ ŵ Yµdµ[µ µµeµdµ@µ&µeµdµ@µeµdµ å@µeµdÿG---- End of CH Setup --------------------------------------------------•-7x…-•48x…4x•9Bx…9x•dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4dx…>•dx…>•\`…>•dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4dx…>•dx…>•=Yx…=•7Jx…7x•9Ux…9x•=Rx…=•9Mx…9•7Ax…7•9Ux…9•7Gx…7•4tˆ)‚˜)G‰ˆ)`˜$:ƒx˜(Oˆ$‡2ˆ(Y˜(Ziˆ(‚ ˜(P(ˆ(E˜!GŠAˆ!W˜-<ƒXˆ-˜)M‡rˆ)L˜)P"ˆ)˜)@sˆ)˜+W†\ˆ+V˜K†wˆs˜(K‡5ˆ(i˜(cqˆ( ˜(]oˆ( ˜!S‚Sˆ!p˜!Dxˆ!x˜!M‚ˆ!˜&8ˆ&˜(Rbˆ(5˜-Zx˜!d7ˆ-xˆ!A˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ-˜)P‡0ˆ)a˜)Jgˆ)‚˜)>tˆ)‚˜)G‰ˆ)`˜$:ƒx˜(Oˆ$‡2ˆ(Y˜(Ziˆ(‚ ˜(P(ˆ(E˜!GŠAˆ!W˜-<ƒXˆ-˜)M‡rˆ)L˜)P"ˆ)˜)@sˆ)˜+W†\ˆ+V˜K†wˆs˜(K‡5ˆ(i˜(cqˆ( ˜(]oˆ( ˜!S‚Sˆ!p˜!Dxˆ!x˜!M‚ˆ!˜&8ˆ&˜(Rbˆ(5˜-Zx˜!d7ˆ-xˆ!A˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ- ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜)Xmˆ) ˜)X˜$dmˆ) ˆ$p˜)Xmˆ) ˜)Xmˆ) ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜+Xmˆ+ ˜+X˜&dmˆ+ ˆ&p˜+Xmˆ+ ˜+Xmˆ+ ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜dxˆx˜(Xmˆ( ˜(X˜#dmˆ( ˆ#p˜(Xmˆ( ˜(Xmˆ( ˜!dxˆ!x˜-Xmˆ- ˜-Xmˆ-{˜-Xmˆ- ˜-Xmˆ- ˜!dxˆ!x˜-Xmˆ- ˜-X˜(dmˆ- ˆ(˜+dxˆ+x˜-Xmˆ- ˜-Xmˆ-ÿ/MTrkTÿDrumCÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹¹ ɹ @¹d¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------ƒ~™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'…x™'AP‰' ™'dP‰'(™$KP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰' ™$mP‰$ ™$m™&8P‰$‰&(™& P‰&(™& P‰&(™& P‰&(™$m™& ™'dP‰$‰&‰'(™&!P‰&(™&!P‰&(™&"P‰&(™$m™&#P‰$‰&(™&$P‰&(™&%P‰&(™&&P‰&(™$m™&'™'dP‰$‰&‰'(™&(P‰&(™&*P‰&(™&,P‰&(™$m™&-P‰$‰&(™&/P‰&(™$m™&1P‰$‰&(™&3P‰&(™$m™&6™'dP‰$‰&‰'(™&8P‰&(™$m™&:P‰$‰&(™&=P‰&(™$m™&@P‰$‰&(™$I™&BP‰$‰&(™&EP‰&(™$I™&H™'AP‰$‰&‰'(™$m™(d™3d™&LP‰$‰(‰3‰&(™&N™'dP‰&‰'(™$m™&MP‰$‰&(™&KP‰&(™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ ™$mP‰$ ™$m™'dP‰$‰' ™$mP‰$ ™$mP‰$‚™$m™'AP‰$‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$óP™4fƒ`‰4™$mP‰$ƒ™$m™''P‰$‰'ƒ™$mP‰$ƒ™$m™'1P‰$‰'ƒ™$mP‰$ƒ™$m™';P‰$‰'ƒ™$mP‰$ƒ™$m™'EP‰$‰'ƒ™$mP‰$ƒ™$m™'OP‰$‰'ƒ™$mP‰$ƒ™$m™'ZP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™$mP‰$(™'dP‰' ™$mP‰$(™'dP‰'(™$m™&9™1dP‰$‰&‰1 ™&9P‰& ™$m™&9™'dP‰$‰&‰' ™&9P‰& ™$m™&9P‰$‰& ™&9P‰& ™$m™&9™'dP‰$‰&‰' ™&9P‰& ™$m™&9™1dP‰$‰&‰1 ™&9P‰& ™$m™&9™'dP‰$‰&‰' ™&9P‰& ™$m™&9P‰$‰& ™&9P‰& ™$m™&9™'dP‰$‰&‰' ™&9P‰& ™$m™&8™1dP‰$‰&‰1(™&,P‰&(™&-P‰&(™&.P‰&(™$m™&/™'dP‰$‰&‰'(™&/P‰&(™&0P‰&(™&1P‰&(™$m™&1™1dP‰$‰&‰1(™&2P‰&(™&3P‰&(™&3P‰&(™$m™&4™'dP‰$‰&‰'(™&5P‰&(™&5P‰&(™&6P‰&(™$m™&7™1dP‰$‰&‰1(™&8P‰&(™&A™$mP‰&‰$(™&BP‰&(™$m™&C™'d™1dP‰$‰&‰'‰1(™&DP‰&(™&E™$mP‰&‰$(™&FP‰&(™$m™&G™1dP‰$‰&‰1(™&GP‰&(™&HP‰&(™$m™&IP‰$‰&(™&L™$m™'dP‰&‰$‰' ™$mP‰$ ™$m™1dP‰$‰1ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CGP‰C(™$m™(H™'dP‰$‰(‰'(™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™CFP‰C ™CS™'dP‰C‰'(™$m™(HP‰$‰((™D\™'dP‰D‰'(™C;P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CG™'dP‰C‰'(™$m™(HP‰$‰((™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™CFP‰C ™(H™CS™'AP‰(‰C‰'(™$mP‰$(™D\™'dP‰D‰'(™$m™(H™C;P‰$‰(‰C(™COP‰C(™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CGP‰C(™$m™(H™'dP‰$‰(‰'(™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™CFP‰C ™CS™'dP‰C‰'(™$m™(HP‰$‰((™D\™'dP‰D‰'(™C;P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CG™'dP‰C‰'(™$m™(HP‰$‰((™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™D@P‰D ™(H™CS™'AP‰(‰C‰'(™$mP‰$(™D\™'dP‰D‰'(™$m™(H™C;P‰$‰(‰C(™CO™'dP‰C‰'(™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CGP‰C(™$m™(H™'dP‰$‰(‰'(™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™CFP‰C ™CS™'dP‰C‰'(™$m™(HP‰$‰((™D\™'dP‰D‰'(™C;P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™COP‰C(™$m™(H™'dP‰$‰(‰'(™CFP‰C(™C&P‰C(™COP‰C(™$mP‰$ ™C.P‰C(™CGP‰C(™$m™(HP‰$‰((™C-™'dP‰C‰' ™CIP‰C(™$mP‰$ ™C'P‰C(™CG™'dP‰C‰'(™$m™(HP‰$‰((™CIP‰C(™C(P‰C(™CMP‰C(™$mP‰$(™CFP‰C ™(H™CS™'AP‰(‰C‰'(™$mP‰$(™D\™'dP‰D‰'(™$m™(H™C;P‰$‰(‰C(™COP‰C(™$m™&9P‰$‰& ™&9P‰& ™&9™(H™'dP‰&‰(‰' ™&9P‰& ™&9P‰& ™&9P‰& ™&9™(HP‰&‰((™'dP‰'(™&9P‰& ™&9™$mP‰&‰$ ™&9P‰& ™&9™(H™'dP‰&‰(‰' ™&9P‰& ™&9P‰& ™&9P‰&(™'dP‰'(™&9™(HP‰&‰((™'dP‰'(™&9P‰& ™&8™$mP‰&‰$(™&,P‰&(™&-P‰&(™&.P‰&(™&/™(H™'dP‰&‰(‰'(™&/P‰&(™&0P‰&(™&1P‰&(™&1™$mP‰&‰$(™&2P‰&(™&3P‰&(™&3P‰&(™&4™(HP‰&‰((™&5™'dP‰&‰'(™&5P‰&(™&6P‰&(™&7™$mP‰&‰$(™&8P‰&(™&AP‰&(™&B™'dP‰&‰'(™&C™$m™(HP‰&‰$‰((™&DP‰&(™&EP‰&(™&FP‰&(™&G™$mP‰&‰$(™&GP‰&(™&HP‰&(™&I™$m™(H™'AP‰&‰$‰(‰'(™&L™$mP‰&‰$(™&G™'dP‰&‰'(™$m™&G™(HP‰$‰&‰((™&HP‰&(™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$ƒ™$m™'dP‰$‰'ƒ™$mP‰$‚™'AP‰'(™$mP‰$(™'dP‰'(™$mP‰$ ™$mP‰$ƒ™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'…x™'AP‰' ™'dP‰'…x™'dP‰'†p™'dP‰'†p™'dP‰'†p™'dP‰'ƒ™&8P‰&(™& P‰&(™& P‰&(™& P‰&(™& ™'dP‰&‰'(™&!P‰&(™&!P‰&(™&"P‰&(™&#P‰&(™&$P‰&(™&%P‰&(™&&P‰&(™&'™'dP‰&‰'(™&(P‰&(™&*P‰&(™&,P‰&(™&-P‰&(™&/P‰&(™&1P‰&(™&3P‰&(™&6™'dP‰&‰'(™&8P‰&(™&:P‰&(™&=P‰&(™&@P‰&(™&BP‰&(™&EP‰&(™&H™'AP‰&‰'(™&LP‰&(™&N™'dP‰&‰'(™&MP‰&(™&KP‰&(™$QP‰$—`™P‰ÿ/MTrk<ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ @ºdº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk "ÿBass2ÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------»y»» ËP» @»i»[» »»e»d»@»&»e»d»@»e»d» ë@»e»dÿG---- End of CH Setup --------------------------------------------------¾›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›dp‹p›!dp‹!p›!dp‹!p›!dp‹!p›!dp‹!öÿ/MTrk<ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¼y¼¼ ̼ @¼d¼[¼ ¼¼e¼d¼@¼&¼e¼d¼@¼e¼d¼ ì@¼e¼dÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------½y½½ ͽ @½d½[½ ½½e½d½@½&½e½d½@½e½d½ í@½e½dÿG---- End of CH Setup --------------------------------------------------‡¿&ÿ/MTrkÿDrumLÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¾y¾¾ ξ ¾d¾[¾ ¾¾e¾d¾@¾&¾e¾d¾@¾e¾d¾ î@¾e¾dÿG---- End of CH Setup --------------------------------------------------‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF…žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF…žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF…žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1„žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF…žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF…žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF…žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF…žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1÷0ž1dPŽ1»0ž1dPŽ1Ž0ž1dPŽ1Ž0ž1dPŽ1†pž1dPŽ1†pž1dPŽ1ƒž1dPŽ1ƒž1dPŽ1ƒž1dPŽ1ƒž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1dPŽ1 žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF‚žF*PŽF(žFHPŽF žF@PŽF(žF#PŽF(žFHPŽF‚žF*PŽF(žFAPŽF žF)PŽF žFCPŽF‚žF$PŽF(žFAPŽF žFCPŽF(žF%PŽF(žFFPŽF žF@PŽF žFLPŽF žF\PŽF(žF6PŽF(žFHPŽF(ž1KPŽ1ÿ/MTrkÿDrumRÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¿y¿¿ Ï¿ X¿d¿[¿ ¿¿e¿d¿@¿&¿e¿d¿@¿e¿d¿ ï@¿e¿dÿG---- End of CH Setup --------------------------------------------------¾Ÿ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P* Ÿ7dP7 Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP.ûŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*ƒŸ*0P*ƒŸ*9P*ƒŸ*,P*ƒŸ*@P*…Ÿ7dP7 Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ7dP7 Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ7dP7 Ÿ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP* Ÿ7dP7 Ÿ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*ƒŸ*ZP*½ Ÿ7dP7 Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P*(Ÿ*CP*(Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP. Ÿ*@P* Ÿ.QP. Ÿ*0P* Ÿ.QP. Ÿ*9P* Ÿ.QP. Ÿ*,P* Ÿ.QP.(Ÿ*@P*(Ÿ*@P* Ÿ.QP.ƒŸ*2P*ƒŸ*IP*ƒŸ*7P*ƒŸ*AP*ƒŸ*2P*ƒŸ*IP*ƒŸ*7P*ƒŸ*AP*ƒŸ*2P*ƒŸ*IP*ƒŸ*7P*ƒŸ*AP*ƒŸ*2P*ƒŸ*IP*ƒŸ*7P*ƒŸ*IP*½ Ÿ7KP7ÿ/simutrans-124.3/simutrans/music/49-Last-Sunday.mid000066400000000000000000001555711474050137200220270ustar00rootroot00000000000000MThdàMTrkÿÿCopyright (C) 2018ÿ------ÿ---Last Sunday---ÿ(C) 2018 RykSebÿCan be used anyÿways if you giveÿthe credit properly.ÿ------ÿQB@ÿSetupÿXpÿQÿ Last SundayÿXžÿ by RykSebÚÿBøÿB2øÿCøÿC2øÿDøÿD2øÿEøÿE2øÿFÿ/MTrk¦ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------ÿ/MTrk*æÿEPÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° À° E°d°[° °°e°d°@°&°e°d°@°e°d° à@°e°dÿG---- End of CH Setup -------------------------------------------------- +=5C:P|€:€5€+Y5B+Z:]x€:€5€+n+O5C:]q€+€5€:5>+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^-O+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^2OAW6Gc€6€A€2rAS6D2]Z€6€2€A AM2S6Ft€A€2€6|6FAP2P~€6€A€2Q5F2f?fz€5v5Q=d€?€2=€5+=7C>Pr€= €>€7€+Y5B+Z:]x€:€5€+n+O5C:]q€+€5€:5>+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^-O+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^2OAW6Gc€6€A€2rAS6D2]Z€6€2€A AM2S6Ft€A€2€6|6FAP2P~€6€A€2Q5F2f?fz€5v5Q=d€?€2=€5+=7C>Pr€= €>€7€+Y5B+Z:]x€:€5€+n+O5C:]q€+€5€:5>+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^-O+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^2OAW6Gc€6€A€2rAS6D2]Z€6€2€A AM2S6Ft€A€2€6|6FAP2P~€6€A€2Q5F2f?fz€5v5Q=d€?€2=€5+B>M5Kq€=O€>€5€++I>F5D\€+€>€5{+\>J5H<€+€>€5!+D>D583€5€>€+‚#+]>N5Ky€>€5€+P)a>N5K‚€>€)€5I>Q5I)YA€> €5€))AK5N)p_€A€5 €)y5KAF)Z:€)€A€5‚ AF5J)ak9L€A{€5€)B€95N>L'Z‚+€>€' €517O>P'QM€>€'€7'N7H>@;€7€'€>,><'Q7M8€7€>€'‚ 'j7Q>O‚d€>€7%€'V>M9M&m‚)€> €&€9*&A>H9@‚€&€>€9F&K >L9Q>€& €>€9%&d>K9=Z€>€9€&^&M>O9Wp:Z#€>a€9p3N>?$S€&€:S€>€$€3D$U>J3KG€>€3 €$3O$Y>L6€> €3 €$'$P>J3M=€>€3€$}3\>N$a‚b€3€>w>25U&U%€$h€>€&€5:>85O&Fq€5€> €&q&O>C5C<€& €5€>5:>@&M€>€5€&T5K>E&i‚€5€>8>@'37E€&‚€> €7€'6>K7>'SM€7€>€')7C']>Wm€>€7€'x7A>F'Sg€>€7€'X7F>E'WY€>€7€'‚7>C8>E'R‚€C €'€> €707:'RC9>=i€C€>€7€'S9:>@C@ )Tx€C€>€9€)@9OCH>V)\m€C €9€>€)b)TCL9T>k‚!€9€C€)€>5$BFM>K‚@€F€>€$$IFF>D\€$€F€>{$\FJ>H<€$€F€>!$DFD>83€>€F€$‚#$]FN>Ky€F€>€$P&aENM9M)m‚)€> €)€9*)A>H9@‚€)€>€9F)K >L9Q>€) €>€9%>K)d9=Z€>€9€)^)M>O9W:Z‚€>€:N€9p3N>?$S€)k€>€$€3D$U>J3KG€>€3 €$3O$Y>L6€> €3 €$'$P>J3M=€>€3€$}3\>N$a‚b€3€>w>25U&U%€$h€>€&€5:>85O&Fq€5€> €&q&O>C5C<€& €5€>5:>@&M€>€5€&T5K>E&i‚€5€>8>@'37E€&‚€> €7€'6>K7>'SM€7€>€')7C']>Wm€>€7€'x7A>F'Sg€>€7€'X7F>E'WY€>€7€'‚7>C8>E'R‚€C €'€> €707:'RC9>=i€C€>€7€'S9:>@C@ )Tx€C€>€9€)@9OCH>V)\m€C €9€>€)b)TCL9T>k‚!€9€C€)€>1+=5C}€5€+EI9J`5B+Z€ID€J"€5€+_FY+O5Cr€5€+5>+;n€5 €+g5@+Sg€F&€5CO €+M€C -E7FiH[D€7€-B€H\H`-h7G€HH€7€-FS/€F?HN-S7Kq€7€-u7D-Zf€7€-€HYIk7O-h€I HMz€7€-FI'€H9F.WF€F-€9€.XIE .]9GJX€IA€J€9€.jFh9G.]u€9€.o9G.f€9€.BCP€F-€C`O_ 9D.Z€OYQs€9€.~€Q`-ORk7GX€R €7€-Tq)€T;Ob7D-]|€OMbG€7€-R€M!O\7F-Sx€-€7|7F-P~€7 €-Q5F2f:fz€5v7S€:€2€O>€75dz+=`=f€5€+\>E€=E€>!5B+ZjAh€5€+=€A1+O5C`=h€+€5b>E €=5>+;J€>$€5 €+UAb5@+S €Ax=n €5 €+Z>R€=gCq-E7F€>€C\Ch@€7€-=€CmCy-h7GZA@€C4€A1€7€-Cy -S7Km€C€-€7u7DFy-Zf€7€-€F|Hq`7O-h5€HVF|r€F €7€-ZH\9F.W€HIh[€IJkX€9€.c.]9G\€9€.9G.]u€9€.J€J%9G.frJP€9€.>€J$9D.ZM`r€MJ[m€9€.€J Mw€M#2O6GOu2€O Rw$€6€2€RT`]6D2]Z€6€2 2S6Fx€6€2}2P €2%S€T9Q> €SOP €Q MO €O LG€MJG€L5F2fHE+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^-O+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^2OAW6Gc€6€A€2rAS6D2]Z€6€2€A AM2S6Ft€A€2€6|6FAP2P~€6€A€2Q5F2f?fz€5v5Q=d€?€2=€5+B>M5Kq€=O€>€5€++I>F5D\€+€>€5{+\>J5H<€+€>€5!+D>D583€5€>€+‚#+]>N5Ky€>€5€+P)a>N5K‚€>€)€5I>Q5I)YA€> €5€))AK5N)p_€A€5 €)y5KAF)Z:€)€A€5‚ AF5J)ak9L€A{€5€)B€95N>L'Z‚+€>€' €517O>P'QM€>€'€7'N7H>@;€7€'€>,><'Q7M8€7€>€'‚ 'j7Q>O‚d€>€7%€'V>M9M&m‚)€> €&€9*&A>H9@‚€&€>€9F&K >L9Q>€& €>€9%&d>K9=Z€>€9€&^&M>O9Wp:Z#€>a€9p3N>?$S€&€:S€>€$€3D$U>J3KG€>€3 €$3O$Y>L6€> €3 €$'$P>J3M=€>€3€$}3\>N$a‚b€3€>w>25U&U%€$h€>€&€5:>85O&Fq€5€> €&q&O>C5C<€& €5€>5:>@&M€>€5€&T5K>E&i‚€5€>8>@'37E€&‚€> €7€'6>K7>'SM€7€>€')7C']>Wm€>€7€'x7A>F'Sg€>€7€'X7F>E'WY€>€7€'‚7>C8>E'R‚€C €'€> €707:'RC9>=i€C€>€7€'S9:>@C@ )Tx€C€>€9€)@9OCH>V)\m€C €9€>€)b)TCL9T>k‚!€9€C€)€>5$BFM>K‚@€F€>€$$IFF>D\€$€F€>{$\FJ>H<€$€F€>!$DFD>83€>€F€$‚#$]FN>Ky€F€>€$P&aENM9M)m‚)€> €)€9*)A>H9@‚€)€>€9F)K >L9Q>€) €>€9%>K)d9=Z€>€9€)^)M>O9W:Z‚€>€:N€9p3N>?$S€)k€>€$€3D$U>J3KG€>€3 €$3O$Y>L6€> €3 €$'$P>J3M=€>€3€$}3\>N$a‚b€3€>w>25U&U%€$h€>€&€5:>85O&Fq€5€> €&q&O>C5C<€& €5€>5:>@&M€>€5€&T5K>E&i‚€5€>8>@'37E€&‚€> €7€'6>K7>'SM€7€>€')7C']>Wm€>€7€'x7A>F'Sg€>€7€'X7F>E'WY€>€7€'‚7>C8>E'R‚€C €'€> €707:'RC9>=i€C€>€7€'S9:>@C@ )Tx€C€>€9€)@9OCH>V)\m€C €9€>€)b)TCL9T>k‚!€9€C€)€>1+=5C:P|€:€5€+Y5B+Z:]x€:€5€+n+O5C:]q€+€5€:5>+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^-O+;:]m€:€5 €+g5@+S:R‚ €:€5 €+Y-E7FR9F.Ws€9€>€.c.]9G>W\€>€9€.9G>O.]u€9€>€.o9G>P.f€9€>€.b9D>`.Z‚ €>€9€.^2OAW6Gc€6€A€2rAS6D2]Z€6€2€A AM2S6Ft€A€2€6|6FAP2P~€6€A€2Q5F2f?fz€5v5Q=d€?€2R€5p€=‚h+d2d5d>dL€2€5<€+Z€>ÿ/MTrk„ÿLeadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------±y±± ÁE± K±d±[± ±±e±d±@±&±e±d±@±e±d± á@±e±dÿG---- End of CH Setup --------------------------------------------------ùp‘>KE>3‘ER}E‘CRLC#‘>I#>G‘AD‘>RA~>]‘KŒ >…>‘>Mv>w‘DB‘EPDh‘CJEC:‘>M>H‘AR‘>DA>d‘W =‚A‘7F>ˆX7‡ ‘>S|>/‘E`E‘CSC‘>L->M‘AP\‘>\A`>7‘MŒ*>„d‘>M>P‘D;‘EWD]‘CRE1C‘>MG>,‘AM;A<‘>N>-‘AUtA2‘BK]B6‘CU9C‘>G‘‘>K<‡n>„^‘>KE>3‘ER}E‘CRLC#‘>I#>G‘AD‘>RA~>]‘KŒ >…>‘>Mv>w‘DB‘EPDh‘CJEC:‘>M>H‘AR‘>DA>d‘W =‚A‘7F>ˆX7‡ ‘>S|>/‘E`E‘CSC‘>L->M‘AP\‘>\A`>7‘MŒ*>„d‘>M>P‘D;‘EWD]‘CRE1C‘>MG>,‘AM;A<‘>N>-‘AUtA2‘BK]B6‘CU9C‘>G‘‘>K<‡n>‚ì^‘>KE>3‘ER}E‘CRLC#‘>I#>G‘AD‘>RA~>]‘KŒ >…>‘>Mv>w‘DB‘EPDh‘CJEC:‘>M>H‘AR‘>DA>d‘W =‚A‘7F>ˆX7‡ ‘>S|>/‘E`E‘CSC‘>L->M‘AP\‘>\A`>7‘MŒ*>„d‘>M>P‘D;‘EWD]‘CRE1C‘>MG>,‘AM;A<‘>N>-‘AUtA2‘BK]B6‘CU9C‘>G‘‘>K<‡n>ó ÿ/MTrk#ÿLead2ÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ Ä;´ /´x´[´ ´´e´d´@´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------‚è”HW|„Hw”H]u„H[”F]†*„Fr”CPA„C+”AF@„AM”H]‚?„Hg”HS‚„Hc”FO„'„F”CW‚:„C:”I.”JR„I‡„JI”MT„MN”JR„J(”HGu„H:”IO{„I(”JJ„J%”CFv„C&”FVs„F8”AL„A:”CS„„CH”>De„>$”AOJ„A”B:F„B”CGh„C”>W‰U„>K”CCz„C&”HOp„H4”JP]„J9”EM„E”FN5”ES„Fˆ~„E”AO„A)”BMu„B”CPs„C#”>Fv„>&”AR6„A”>EŒs„>‘o”HMe”J<„HL„J”MdH„M”HV”JI „HA„J”Mdj„M”HZu”JK„HK„J”Mh/„M2”HTp”JJ „HE„J*”M`‚„Mu”Rf/„RH”Rv„RP”Qr „Qi”Qfs„QX”Rlu„R”Mf†e„Mƒ7”Oo6„O<”Jl…„Jv”MoL„M"”Hn]„Hx”JcH„J)”Ef‚„EZ”Fo„FM”AS„A”C^„C ”>UŒ„>„+”7hz„7”Ra„> ”f…r„>a”7fJ„7-”S„>I”<`|„<3”>Sk„>4”]Œ„>g”H_z”JI „HO„J"”MR_„M_”HZ”JR„H9„J4”MZ‚!„MZ”Hf~”JG„Ho„J”M`X„M”HWx”J]„HF„J”Mh[„Mo”Ri?„RQ”Rr1„RJ”Qo „Qp”Qoa„Q>”Rn„R4”T]`„T8”Mo‡'„MZ”OfN„O8”Jl„=„J ”Mlw”Hi!„MR„Ho”Jr:„J'”Fh#„FS”HoG„H<”Ef „E5”F]„F”Cf…)„C”Aid„A”Ci-„CN”Ff,„FD”En‚D„E”Jl‰„JD”Hh „HB”Ic „I7”JW„J”CZ„C)”FW „FB”A];„A”CW‡I„CƒE”Mf{”NO„MC„N”Oam„O”Rnn„R”Ofp„O|”M_g”NS„M_”Ob„N„Onÿ/MTrkÆÿSeqÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² ÂP² @²:²[² ²²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------ð² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² `x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O7² x’OdA‚O7’OdA‚O7’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O/’CdA‚C7’OdA‚O7’CdA‚C7’RdF‚R2’RdF‚R2’FdF‚F2’RdF‚R2² @„Xÿ/MTrk¦ÿBellÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ Ã`³ @³F³[³ ³³e³d³@³&³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------ð³ `’`“TQxƒTx“RIxƒRx“QAxƒQx“RQxƒR“QNxƒQx“MIxƒMx“JCxƒJ’`“CQxƒC“HCxƒH“JMxƒJ“MWxƒMx“O?xƒO“THxƒT“VQxƒV“YZxƒY“[Uxƒ[”P“T@xƒT“VNxƒV“ROxƒR“TUxƒTx“QFxƒQ“RRxƒR“O^xƒO“QX ƒQ“MU ƒM“JQ ƒJ’`“MXxƒM“OLxƒO“TPxƒT“VUxƒVx“YXxƒYx“ZZxƒZx“[\xƒ[x“^_xƒ^ì`“RHpƒRp“Y[pƒYp“QKpƒQp“RUpƒR‹ “^Upƒ^“]Qpƒ]x“YKpƒY‰0“YBxƒY“[Opƒ[x“VMpƒVˆ8“YCpƒY“RLpƒRƒ`“VExƒV“QGpƒQx“RLxƒR“MNpƒMx“OTxƒOx“JHpƒJ‰0“^Tpƒ^p“]Rpƒ]p“YOpƒYp“TMpƒTp“VMpƒVp“[Upƒ[p“bVpƒbp“`Spƒ`p“^Ppƒ^ùp³ `’`“TQxƒTx“RIxƒRx“QAxƒQx“RQxƒR“QNxƒQx“MIxƒMx“JCxƒJ’`“CQxƒC“HCxƒH“JMxƒJ“MWxƒMx“O?xƒO“THxƒT“VQxƒV“YZxƒY“[Uxƒ[”P“T@xƒT“VNxƒV“ROxƒR“TUxƒTx“QFxƒQ“RRxƒR“O^xƒO“QX ƒQ“MU ƒM“JQ ƒJ’`“MXxƒM“OLxƒO“TPxƒT“VUxƒVx“YXxƒYx“ZZxƒZx“[\xƒ[x“^_xƒ^ì`“RHpƒRp“Y[pƒYp“QKpƒQp“RUpƒR‹ “^Upƒ^“]Qpƒ]x“YKpƒY‰0“YBxƒY“[Opƒ[x“VMpƒVˆ8“YCpƒY“RLpƒRƒ`“VExƒV“QGpƒQx“RLxƒR“MNpƒMx“OTxƒOx“JHpƒJ‰0“^Tpƒ^p“]Rpƒ]p“YOpƒYp“TMpƒTp“VMpƒVp“[Upƒ[p“bVpƒbp“`Spƒ`p“^Ppƒ^p³ `’`“TQxƒTx“RIxƒRx“QAxƒQx“RQxƒR“QNxƒQx“MIxƒMx“JCxƒJ’`“CQxƒC“HCxƒH“JMxƒJ“MWxƒMx“O?xƒO“THxƒT“VQxƒV“YZxƒY“[Uxƒ[”P“T@xƒT“VNxƒV“ROxƒR“TUxƒTx“QFxƒQ“RRxƒR“O^xƒO“QX ƒQ“MU ƒM“JQ ƒJ’`“MXxƒM“OLxƒO“TPxƒT“VUxƒVx“YXxƒYx“ZZxƒZ“[Qxƒ[“^dxƒ^“`_xƒ`“bdxƒbƒ`ÿ/MTrkÿPadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------µyµµ Å3µ @µ2µ[µ µµeµdµ@µ&µeµdµ@µeµdµ å@µeµdÿG---- End of CH Setup --------------------------------------------------ðµ 4•Rd•[d•^s…^•]s…]…[•Ys…Y•Vs…R…V•Rd•[d•^s…^•]s…]…[•YsŽ0µ <µ !…Y•Vs(µ $<µ '<µ *<µ -<µ 0<µ 3<µ 6<µ 8<µ ;<µ ><µ A<µ D<µ G<µ J<µ M<µ P<µ S<µ V<µ Y<µ \<µ _<µ b<µ e<µ g<µ j<µ m<µ p<µ s<µ v<µ y<µ |(•Qd•]<µ …R…V–…Q…]•Od•[<‡@…O…[•Vd•b<ž…V…b•Rd•^<…R…^•Qd•]<…Q…]•Od•[<–h…O…[•YA•Od†H…OP•Qd•]<(…Y–…Q…]•Od•[<‡@…O…[•Vd•b<ž…V…b•Rd•^<…R…^•Qd•]<…Q…]•Od•[<–h…O…[•YA•Qd‡•RL•JL(…Y…QŽX…R…J•TL•OL…T…O•VL•ML…V…M•TL•LL…T…L•RL•JL…R…J•TL•OL…T…O•VL•QL…V…Q•YL•QL…Y…Q(µ 4•Rd•[d•^s…^•]s…]•Ys…Y•Vs…R…[…V•Rd•[d•^s…^•]s…]•YsŽ0µ <µ !…Y…[•Vs(µ $<µ '<µ *<µ -<µ 0<µ 3<µ 6<µ 8<µ ;<µ ><µ A<µ D<µ G<µ J<µ M<µ P<µ S<µ V<µ Y<µ \<µ _<µ b<µ e<µ g<µ j<µ m<µ p<µ s<µ v<µ y<µ |(•Qd•]<µ …R…V–…Q…]•Od•[<‡@…O…[•Vd•b<ž…V…b•Rd•^<…R…^•Qd•]<…Q…]•Od•[<–h…O…[•YA•Od†H…OP•Qd•]<(…Y–…Q…]•Od•[<‡@…O…[•Vd•b<ž…V…b•Rd•^<…R…^•Qd•]<…Q…]•Od•[<–h…O…[•YA•Qd‡•RL•JL(…Y…QŽX…R…J•TL•OL…T…O•VL•ML…V…M•TL•LL…T…L•RL•JL…R…J•TL•OL…T…O•VL•QL…V…Q•YL•QL…Y…Qÿ/MTrkêÿBassÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¸y¸¸ È!¸ 5¸M¸[¸ ¸¸e¸d¸@¸&¸e¸d¸@¸e¸d¸ è@¸e¸dÿG---- End of CH Setup --------------------------------------------------˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜-Nxˆ-x˜-_xˆ-˜)dxˆ)x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜-Nxˆ-x˜-_xˆ-˜)dxˆ)x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜-Nxˆ-x˜-_xˆ-˜)dxˆ)x˜&dpˆ&˜2Ypˆ2˜+Xpˆ+p˜+dpˆ+x˜+Zxˆ+x˜Xxˆ˜&cpˆ&˜+dpˆ+˜&Xpˆ&˜)]pˆ)p˜$dpˆ$x˜)Zxˆ)x˜$Xxˆ$x˜!dxˆ!˜)dxˆ)˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'x˜.Zxˆ.x˜+Yxˆ+x˜'dpˆ'x˜"Yxˆ"˜'[xˆ'˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Vxˆ)x˜&Xxˆ&˜0dxˆ0˜2Xxˆ2x˜&Xxˆ&˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Yxˆ)x˜&dpˆ&x˜!Yxˆ!˜&[xˆ&˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'˜)Zxˆ)˜0Zxˆ0x˜-Vxˆ-x˜)dpˆ)˜+Xxˆ+x˜+Xxˆ+˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Yxˆ)x˜&dpˆ&x˜!Yxˆ!˜&[xˆ&˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜)Upˆ)p˜)dpˆ)x˜0Zxˆ0x˜-Vxˆ-x˜)dxˆ)x˜)mxˆ)˜+Zxˆ+x˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&]pˆ&p˜-dpˆ-x˜&Zxˆ&x˜!Xxˆ!x˜&dxˆ&˜-dxˆ-x˜2Vxˆ2x˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'˜)[xˆ)˜0Zxˆ0x˜-Vxˆ-x˜)dpˆ)˜+Xxˆ+x˜+Xxˆ+˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜*Nxˆ*x˜*_xˆ*˜)dxˆ)x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜-Nxˆ-x˜-_xˆ-˜)dxˆ)x˜&dpˆ&˜2Ypˆ2˜+Xpˆ+p˜+dpˆ+x˜+Zxˆ+x˜Xxˆ˜&cpˆ&˜+dpˆ+˜&Xpˆ&˜)]pˆ)p˜$dpˆ$x˜)Zxˆ)x˜$Xxˆ$x˜!dxˆ!˜)dxˆ)˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'x˜.Zxˆ.x˜+Yxˆ+x˜'dpˆ'x˜"Yxˆ"˜'[xˆ'˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Vxˆ)x˜&Xxˆ&˜0dxˆ0˜2Xxˆ2x˜&Xxˆ&˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Yxˆ)x˜&dpˆ&x˜!Yxˆ!˜&[xˆ&˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'˜)Zxˆ)˜0Zxˆ0x˜-Vxˆ-x˜)dpˆ)˜+Xxˆ+x˜+Xxˆ+˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&Upˆ&p˜&dpˆ&x˜-Zxˆ-x˜)Yxˆ)x˜&dpˆ&x˜!Yxˆ!˜&[xˆ&˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜)Upˆ)p˜)dpˆ)x˜0Zxˆ0x˜-Vxˆ-x˜)dxˆ)x˜)mxˆ)˜+Zxˆ+x˜$]pˆ$p˜+dpˆ+x˜$Zxˆ$x˜Xxˆx˜$dxˆ$˜+dxˆ+x˜0Vxˆ0x˜&]pˆ&p˜-dpˆ-x˜&Zxˆ&x˜!Xxˆ!x˜&dxˆ&˜-dxˆ-x˜2Vxˆ2x˜']pˆ'p˜.dpˆ.x˜"Zxˆ"˜'Xxˆ'p˜'dxˆ'˜.dxˆ.˜+Vxˆ+p˜'Upˆ'p˜'dpˆ'˜)[xˆ)˜0Zxˆ0x˜-Vxˆ-x˜)dpˆ)˜+Xxˆ+x˜+Xxˆ+˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜!]xˆ!p˜!apˆ!x˜-Nxˆ-x˜-_pˆ-x˜&dpˆ&˜2Ypˆ2˜Spˆp˜+apˆ+x˜+Nxˆ+x˜+_pˆ+˜&Ixˆ&˜dpˆp˜!Spˆ!p˜-apˆ-x˜-Nxˆ-x˜-_pˆ-x˜-dpˆ-˜&Ypˆ&˜"Spˆ"p˜.apˆ.x˜.Nxˆ.x˜._pˆ.˜)Ixˆ)˜"dpˆ"˜)Vxˆ)˜+`xˆ+x˜&]xˆ&p˜&apˆ&x˜2Nxˆ2x˜2_xˆ2˜-dxˆ-x˜&dpˆ&˜2Ypˆ2ƒ`˜+dŽˆ+ÿ/MTrk+(ÿDrumÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹¹ ɹ @¹d¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™3GP‰$‰3(™2@P‰2(™*8P‰*(™2RP‰2(™&dP‰&(™0@P‰0(™*U™0dP‰*‰0(™$XP‰$(™$d™*K™/dP‰$‰*‰/(™&cP‰&(™.dP‰.(™$AP‰$(™&q™-dP‰&‰-(™,EP‰,(™*UP‰*(™+QP‰+(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™3GP‰$‰3 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™1TP‰$‰1(™&;P‰&(™*8P‰*(™*J™&DP‰*‰& ™&LP‰&(™*UP‰*(™$X™&YP‰$‰&(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$A™2dP‰$‰2(™&v™0d™4PP‰&‰0‰4 ™-dP‰-(™+dP‰+(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™.OP‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&0P‰*‰&(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™*CP‰* ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3Q™&0P‰3‰&(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3aP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™.CP‰.(™$JP‰$(™3Q™,SP‰3‰, ™$g™.OP‰$‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&0P‰*‰&(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$J™&0P‰$‰&(™$d™*S™3QP‰$‰*‰3 ™*CP‰*(™&0P‰&(™&d™3?P‰&‰3(™,?P‰,(™*U™&0P‰*‰&(™$XP‰$(™3QP‰3(™$dP‰$(™*8™&GP‰*‰&(™*IP‰*(™3C™$Q™&UP‰3‰$‰& ™$E™*7P‰$‰*(™*P™&dP‰*‰&(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™.OP‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™*CP‰* ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$d™&0P‰$‰&(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3aP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™.CP‰.(™$JP‰$(™3Q™,SP‰3‰, ™$g™.OP‰$‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$J™&0P‰$‰&(™$d™*S™3QP‰$‰*‰3(™2DP‰2(™*C™2SP‰*‰2 ™0S™4E™$EP‰0‰4‰$ ™.?P‰.(™$X™/DP‰$‰/(™3Q™,\P‰3‰,(™$d™-DP‰$‰-(™-SP‰-(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&KP‰*‰&(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™3GP‰$‰3(™2@P‰2(™*8P‰*(™2RP‰2(™&dP‰&(™0@P‰0(™*U™0dP‰*‰0(™$XP‰$(™$d™*K™/dP‰$‰*‰/(™&cP‰&(™.dP‰.(™$AP‰$(™&q™-dP‰&‰-(™,EP‰,(™*UP‰*(™+QP‰+(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™1TP‰$‰1(™&;P‰&(™*8P‰*(™*J™&DP‰*‰& ™&LP‰&(™*UP‰*(™$X™&YP‰$‰&(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$A™2dP‰$‰2(™&v™0d™4PP‰&‰0‰4 ™-dP‰-(™+dP‰+(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™.OP‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&0P‰*‰&(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™*CP‰* ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3Q™&0P‰3‰&(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3aP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™.CP‰.(™$JP‰$(™3Q™,SP‰3‰, ™$g™.OP‰$‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&0P‰*‰&(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$J™&0P‰$‰&(™$d™*S™3QP‰$‰*‰3 ™*CP‰*(™&0P‰&(™&d™3?P‰&‰3(™,?P‰,(™*U™&0P‰*‰&(™$XP‰$(™3QP‰3(™$dP‰$(™*8™&GP‰*‰&(™*IP‰*(™3C™$Q™&UP‰3‰$‰& ™$E™*7P‰$‰*(™*P™&dP‰*‰&(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™.OP‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$JP‰$(™$d™*S™3QP‰$‰*‰3 ™*CP‰* ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$d™&0P‰$‰&(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3aP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™.CP‰.(™$JP‰$(™3Q™,SP‰3‰, ™$g™.OP‰$‰. ™&d™3?P‰&‰3(™,?P‰,(™*UP‰*(™$XP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*PP‰*(™$d™3QP‰$‰3 ™*8P‰*(™*JP‰*(™&d™3?P‰&‰3 ™*UP‰*(™$CP‰$(™3QP‰3(™$dP‰$(™*8P‰*(™*OP‰*(™&d™3CP‰&‰3 ™*CP‰*(™$J™&0P‰$‰&(™$d™*S™3QP‰$‰*‰3(™2DP‰2(™*C™2SP‰*‰2 ™0S™4E™$EP‰0‰4‰$ ™.?P‰.(™$X™/DP‰$‰/(™3Q™,\P‰3‰,(™$d™-DP‰$‰-(™-SP‰-(™*IP‰*(™&d™3CP‰&‰3 ™$E™*7P‰$‰*(™*P™&KP‰*‰&(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$XP‰$(™$d™*KP‰$‰*(™&cP‰&(™.dP‰.(™$AP‰$(™&qP‰&(™,EP‰,(™*UP‰*(™*7P‰*(™$d™1SP‰$‰1 ™*8P‰*(™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$(™*DP‰*(™$dP‰$(™*8P‰*(™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™*SP‰$‰* ™.OP‰. ™&dP‰&(™,?P‰,(™*UP‰*(™$XP‰$(™*\P‰*(™$dP‰$(™*8P‰*(™*IP‰*(™&dP‰& ™$E™*7P‰$‰*(™*PP‰*(™$d™*SP‰$‰*‚™*JP‰*(™&dP‰& ™*UP‰*(™$CP‰$ ™$d™*DP‰$‰* ™*OP‰*(™&dP‰& ™*CP‰*(™$JP‰$(™$d™3\P‰$‰3(™2@P‰2(™*8P‰*(™2RP‰2(™&dP‰&(™0@P‰0(™*U™0dP‰*‰0(™$XP‰$(™$d™*K™/dP‰$‰*‰/(™&cP‰&(™.dP‰.(™$AP‰$(™&q™-dP‰&‰-(™,EP‰,(™*UP‰*(™+QP‰+(™$dP‰$ƒ™$d™1AP‰$‰1–h™$P‰$ÿ/MTrkðÿParcÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ Xºdº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------„ØšFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF(šFQPŠF(šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF šFQPŠF‚šF:PŠF(šFOPŠF‚šF2PŠF(šFQPŠF šF:PŠF(šFQPŠF šF4PŠF(šFQPŠF(šFQPŠFƒšF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠF(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠFƒšF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠF(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠFƒšF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠF(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠFƒšF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQPŠF(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQPŠF(šK*PŠK(šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4PŠF(šFQšK*PŠFŠK šFQPŠF‚šF:šK*PŠFŠK(šFOPŠF šK*PŠK(šF2PŠF(šFQPŠF šF:PŠF(šFQšK*PŠFŠK šF4šK*PŠFŠK(šFQšK*PŠFŠK(šFQšK*PŠFŠKÿ/MTrkÛÿGtÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¼y¼¼ ̼ ¼-¼[¼ ¼¼e¼d¼@¼&¼e¼d¼@¼e¼d¼ ì@¼e¼dÿG---- End of CH Setup --------------------------------------------------‚ä>ì|8œ>2ì*:<ìE<<ìa> ì@‚,Œ>ñpœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7…Zœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7…Zœ:PxŒ:œ7PxŒ7nœ4PxŒ4œ7PxŒ7‚rœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7…Zœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7…Zœ:PxŒ:œ7PxŒ7nœ4PxŒ4œ7PxŒ7‚rœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7…Zœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Pœ5PxŒ5œ7PxŒ7…Fœ5PxŒ5œ7PxŒ7‚rœ>dxŒ>œ:cxŒ:xœ2ì*:<ìE<<ìa> ì@‚,Œ>ÿ/MTrkÿ Atmosphereÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------½y½½ Íc½ @½(½[½ ½½e½d½@½&½e½d½@½e½d½ í@½e½dÿG---- End of CH Setup --------------------------------------------------ø½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:7½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:7½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:7½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:‚é7½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:7½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ Cd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77CG719C7?Cd7F9C77½ hCd7F9C77CE709C7?CF719C7?Cd7F9C77CG719C7?CG719C7?Cd7F9C77CE709C7?Cd7F9C77FG:19F:?Fd:F9F:7½ #7Fx7>Fx>AFxAFFxFJFxJMFxMTFxTVFxV7Fx7>Fx>AFxAFFxFJFxJMFxMTFxTVFxV5Fx5Fx>CFxCFFxFJFxJOFxORFxR3Fx3:Fx:>Fx>CFxCFFxFJFxJOFxORFxR2Fx29Fx9>Fx>EFxEHFxHOFxOQFxQVFxV2Fx29Fx9>Fx>EFxEHFxHOFxORFxROFxOWdxWV^xVR\xROZxOVXxVRVxROUxOJSxJRQxROOxOJMxJHKxHOIxOJGxJHExHCCxCY_xYT]xTQ[xQMYxMTWxTQUxQMTxMHRxHQPxQMNxMHLxHEJxEMHxMHFxHEDxEABxA?Ex?CGxCFIxFJJxJOLxOJNxJOPxORRxRVTxV[Vx[VXxVRWxROUxOJTxJFRxFCQxC?Ox?CQxCFSxFJUxJOVxOJXxJOZxOR[xRY]xY[_x[TaxTV^xVRYxROTxOJOxJCJxC^]x^[[x[WYxWVWxVRUxROSxOKQxKJOxJ[Mx[VXxVTWxTRUxROSxOJRxJHPxHFNxFY\xYVZxVTXxTQUxQMSxMJQxJHOxHEMxEV]xVT[xTQYxQMWxMJUxJHSxHEQxEAOxA>Ox>?Qx?CSxCFUxFJWxJKYxKM[xMR]xRY_xYR[xRMYxMKVxKJTxJFRxFCPxC>Nx>Lx>ANxAEQxEHSxHJVxJMXxMQZxQV\xVQYxQMVxMJOxJHSxHEWxEA[xA>_x>WdxWV^xVR\xROZxOVXxVRVxROUxOJSxJRQxROOxOJMxJHKxHOIxOJGxJHExHCCxCY_xYT]xTQ[xQMYxMTWxTQUxQMTxMHRxHQPxQMNxMHLxHEJxEMHxMHFxHEDxEABxA?Ex?CGxCFIxFJJxJOLxOJNxJOPxORRxRVTxV[Vx[VXxVRWxROUxOJTxJFRxFCQxC?Ox?CQxCFSxFJUxJOVxOJXxJOZxOR[xRV]xVY_xY[ax[^ex^`ax`^]x^[Zx[YVxYVSxVTPxTRMxROJxOJHxJHDxHF@xFC4x><0x<7+x7ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¶y¶¶ ƶ @¶¶[¶ ¶¶e¶d¶@¶&¶e¶d¶@¶e¶d¶ æ@¶e¶dÿG---- End of CH Setup --------------------------------------------------ˆ¸ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------·y·· ÇP· @·F·[· ··e·d·@·&·e·d·@·e·d· ç@·e·dÿG---- End of CH Setup --------------------------------------------------‰¬ÿ/MTrk<ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------»y»» Ë» @»d»[» »»e»d»@»&»e»d»@»e»d» ë@»e»dÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk<ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¾y¾¾ ξ @¾d¾[¾ ¾¾e¾d¾@¾&¾e¾d¾@¾e¾d¾ î@¾e¾dÿG---- End of CH Setup --------------------------------------------------ÿ/MTrk<ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¿y¿¿ Ï¿ @¿d¿[¿ ¿¿e¿d¿@¿&¿e¿d¿@¿e¿d¿ ï@¿e¿dÿG---- End of CH Setup --------------------------------------------------ÿ/simutrans-124.3/simutrans/music/50-Snowy-Road.mid000066400000000000000000001314331474050137200216440ustar00rootroot00000000000000MThd àMTrkÿ Snowy Roadÿ#Copyright (C) 2018 AnoKTOK / RykSebÿyƒTƒCƒg–¼z URLÿQB@ÿSetupÿXpÿQ/ÿAÿX‡ÿA2å ÿQЉ0ÿQâ7ƒ`ÿQ'”PÿBÿQ/øÿB2øÿCøÿC2øÿDƒ`ÿQÈÎ ÿQR®…PÿQ 5…PÿQ 5ÿQ!莃`ÿQ/ÿEøÿE2øÿFøÿF2øÿF3øÿF4ÿ/MTrk¦ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------ÿ/MTrk ýÿIce Rainÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° À`° @°d°[° °°e°d°C°&°e°d°@°e°d° à@°e°dÿG---- End of CH Setup --------------------------------------------------‡`Ax€`eAx€e`Aœ€`^@x€^c@x€c^@œ€^\@x€\a?x€a\?œ€\[?x€[`?x€`[?œ€[‚÷`dx€`x^dx€^xWdx€Wx`dx€`^dx€^xWdx€W‚hVdx€VWdx€W`dx€`^dx€^xWdx€WxRdx€RxRdx€RYdx€YxWdx€WxVdx€VWdx€WxRdx€Rx`dx€`x^dx€^xWdx€Wx`dx€`^dx€^xWdx€W‚hVdx€VWdx€WRdx€RYdx€YxRdx€RYdx€YxRdx€RYdx€YWdx€WVdx€VWdx€WxRdx€RxMdx€MOdx€ORdx€RWdx€WxVdx€VxOdx€OxWdx€WVdx€VxOdx€Oƒ`Mdx€MOdx€OKdx€K‚hTdx€T[dx€[Tdx€TRdx€RxTdx€TxOdx€ORdx€RTdx€TOdx€ORdx€RMdx€MxOdx€OxHdx€HxMdx€MOdx€OxHdx€HxMdx€MOdx€OMdx€MHdx€HxCdx€CHdx€HJdx€JMdx€MOdx€OTdx€TVdx€VYdx€Y[dx€[^dx€^[dx€[Ydx€YWdx€WRdx€RMdx€MHdx€Hƒº6° >`° M`° Z`° e`° l`° n`° k`° d`° Y`° Lj° =V° .`° !`° `° `° `° `° `° $`° 2`° A`° O`° \`° f`° l`° n`° j`° c`° W`° J`° ;`° ,`° `° `° `° `° `° `° &`° 4B° >(° >`° M`° Z`° e`° l`° n`° k`° d0[!0° YH€[[5° L`€[° =[N`° .€[H° !0YN0° H€Y° `° WN`° €WH° 0YNg0° $H€Y€gRNg'° 2`€g° Ag:`° O€R€gH° \0e:0° fH€e° l`° nc:`° j€cH° c0e:0° WH€e^:° J`° ;`° ,€^H° `° `° `° `° `° `° &`° 4B° >° >`° M`° Z`° e`° l`° n`° k`° d0V!0° YH€VV5° L`€V° =VN`° .€VH° !0WN0° H€W° `° VN`° €VH° 0bRN0° $H€b€RMNb'° 2`€b° Ab:`° O€M€bH° \0c:0° fH€c° l`° nb:`° j€bH° c0^:0° WH€^Y:° J`° ;[N`° ,€YH° 0€[0° `° `° `° `° `° &`° 4B° >° >TNg:`° M`° Z0€T€g0° e`° l`° n`° k`° d`° Y`° L`° =° .YN`:`° !€YH° 0€`WN0° H€W° `° VN`° €VH° $0WN0° 2H€WRN° A`° Oe:`° \€R€eH° f0c:0° lH€c° n`° jb:`° c€bH° W0c:0° JH€c^:° ;`° ,`° €^H° 0WN0° H€W° `° VN`° €VH° &0WN0° 4B° >€W"° >V^N ° M`° Z€^R° e&c::° l>€c"° nVb:[N ° k`° d€b€[R° Y&c::° L>€cx° .j:bN`° !€j€bH° `° `° `° cNg:`° €c€gH° $`° 2`° A`° O^Nb:`° \€^€bH° f`° l`° n`° j`° c`° W`° J`° ;`° ,`° `° `° `° `° `° `° &`° 4B° >(° >`° M`° Z`° e`° l`° n`° k`° d`° Y&[!:° L>€[[5F° C2€[° =[NV° ."€[>° !:YN&° R€Y° `°  WNV° "€W>° :YNg&° $R€Y€gRNg'° 2`° A €gg:V° O"€R€g>° \:e:&° fR€e° l`° n c:V° j"€c>° c:e:&° WR€e^:° J`° ;`° ,"€^>° `° `° `° `° `° `° &`° 4B° >(° >`° M`° Z`° e`° l`° n`° k`° d0Y!0° YH€YY5° L`€Y° =YNV° ."€Y>° !:[N&° R€[° `°  YNV° "€Y>° :eVN&° $R€e€Ve'RN° 2`° A €ee:V° O"€R€e>° \:g:&° fR€g° l`° n e:V° j"€e>° c:b:&° WR€b^:° J`° ; [NV° ,"€^>° :€[&° `° `° `° `° `° &`° 4B° >(° >`° M`° Z`° e`° l`° n`° k`° d0W!0° YH€WW5° L`€W° =WNV° ."€W>° !:RN&° R€R° `°  WNV° "€W>° :YNc&° $R€Y€c^Nc'° 2`° A €cc:V° O"€^€c>° \:^:&° fR€^° l`° n c:V° j"€c>° c:e:&° WR€ej:° J`° ; €jc:[NV° ,"€c€[>° `° `° `° `° `° `° &`° 4B° >(° >b:YN`° M€b€YH° Z`° e`° l`° n`° k`° d`° Y`° L`° =à@^:VNV° ."€^€V>° !`° `° `° `° `° `° $`° 2`° A à<@f:_NV° O"€f€_>° \`° f`° l`° n`° j`° c`° W`° J`° ; à@V° ,`° `° `° `° `° `° `° &`° 4B° >(° >`° M`° Z`° e`° l`° n`° k`° d`° Y`° Lø`cNx€c†HdNx€d†H_Nx€_Ž\Nx€\†HcNx€c†HdNx€dŽdNx€d†H_Nx€_†HhNx€hŽfNx€fÂHÿ/MTrkçÿStringsÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------±y±± Ád± N±d±[± ±±e±d±C±&±e±d±@±e±d± á@±e±dÿG---- End of CH Setup --------------------------------------------------‹¯‘UFU‘\F\‘ZFZ‘WFW‘XFX‘SFS‘XFX‘_F_‘aFa‘\F\‘ZFZ‘_F_‘ZFZ‘XFX‘SFS‘NFN‘KFK‘IFŸpIÿ/MTrk!ÉÿEPianoÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² ² 3²d²[² ² ²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------‚Ž’7?x‚7’7?x‚7’7?ƒ`‚7’7?x‚7’7?x‚7’7?x‚7’7?x‚7’7?ƒ`‚7’7?x‚7’7?x‚7’7?x‚7’7?x‚7’7?ƒ`‚7’7?x‚7’7?x‚7’7?x‚7’7?x‚7’7?ƒ`‚7’7?x‚7’7?x‚7’5?x‚5’5?x‚5’5?ƒ`‚5’5?x‚5’5?x‚5’5?x‚5’5?x‚5’5?ƒ`‚5’5?x‚5’5?x‚5’5?x‚5’5?x‚5’5?ƒ`‚5’5?x‚5’5?x‚5’5?x‚5’5?x‚5’5?ƒ`‚5’5?x‚5’5?x‚5’3?x‚3’3?x‚3’3?ƒ`‚3’3?x‚3’3?x‚3’3?x‚3’3?x‚3’3?ƒ`‚3’3?x‚3’3?x‚3’3?x‚3’3?x‚3’3?ƒ`‚3’3?x‚3’3?x‚3’3?x‚3’3?x‚3’3?ƒ`‚3’3?x‚3’3?x‚3’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’2?x‚2’2?x‚2’2?ƒ`‚2’2?x‚2’2?x‚2’2?x‚2’2?x‚2’2?ƒ`‚2’2?x‚2’2?x‚2’7?’0:x‚7‚0’7?’0:x‚7‚0’7?’0:ƒ`‚7‚0’7?’0:x‚7‚0’7?’0:x‚7‚0’7?’0:x‚7‚0’7?’0:x‚7‚0’7?’0:ƒ`‚7‚0’7?’0:x‚7‚0’7?’0:x‚7‚0’7@’0:x‚7‚0’7@’0:x‚7‚0’7@’0:ƒ`‚7‚0’7@’0:x‚7‚0’7@’0:x‚7‚0’7@’0:x‚7‚0’7@’0:x‚7‚0’7@’0:ƒ`‚7‚0’7@’0:x‚7‚0’7@’0:x‚7‚0’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:ƒ`‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:ƒ`‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:ƒ`‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’5@’.:ƒ`‚5‚.’5@’.:x‚5‚.’5@’.:x‚5‚.’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:ƒ`‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:ƒ`‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:ƒ`‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’3@’,:ƒ`‚3‚,’3@’,:x‚3‚,’3@’,:x‚3‚,’0@’):x‚0‚)’0@’):x‚0‚)’0@’):ƒ`‚0‚)’0@’):x‚0‚)’0@’):x‚0‚)’0@’):x‚0‚)’0@’):x‚0‚)’0@’):ƒ`‚0‚)’0@’):x‚0‚)’0@’):x‚0‚)’2@’+:x‚2‚+’2@’+:x‚2‚+’2@’+:ƒ`‚2‚+’2@’+:x‚2‚+’2@’+:x‚2‚+’2@’+:x‚2‚+’2@’+:x‚2‚+’2@’+:ƒ`‚2‚+’2@’+:x‚2‚+’2@’+:x‚2‚+’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’.?x‚.’.?x‚.’.?ƒ`‚.’.?x‚.’.?x‚.’.?x‚.’.?x‚.’.?ƒ`‚.’.?x‚.’.?x‚.’.?x‚.’.?x‚.’.?ƒ`‚.’.?x‚.’.?x‚.’.?x‚.’.?x‚.’.?ƒ`‚.’.?x‚.’.?x‚.’,?x‚,’,?x‚,’,?ƒ`‚,’,?x‚,’,?x‚,’,?x‚,’,?x‚,’,?ƒ`‚,’,?x‚,’,?x‚,’,?x‚,’,?x‚,’,?ƒ`‚,’,?x‚,’,?x‚,’,?x‚,’,?x‚,’,?ƒ`‚,’,?x‚,’,?x‚,’+?x‚+’+?x‚+’+?ƒ`‚+’+?x‚+’+?x‚+’+?x‚+’+?x‚+’+?ƒ`‚+’+?x‚+’+?x‚+’+?x‚+’+?x‚+’+?ƒ`‚+’+?x‚+’+?x‚+’+?x‚+’+?x‚+’+?ƒ`‚+’+?x‚+’+?x‚+’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0?x‚0’0?x‚0’0?ƒ`‚0’0?x‚0’0?x‚0’0@x‚0’0@x‚0’0@ƒ`‚0’0@x‚0’0@x‚0’0@x‚0’0@x‚0’0@ƒ`‚0’0@x‚0’0@x‚0’.@x‚.’.@x‚.’.@ƒ`‚.’.@x‚.’.@x‚.’.@x‚.’.@x‚.’.@ƒ`‚.’.@x‚.’.@x‚.’.@x‚.’.@x‚.’.@ƒ`‚.’.@x‚.’.@x‚.’.@x‚.’.@x‚.’.@ƒ`‚.’.@x‚.’.@x‚.’,@x‚,’,@x‚,’,@ƒ`‚,’,@x‚,’,@x‚,’,@x‚,’,@x‚,’,@ƒ`‚,’,@x‚,’,@x‚,’,@x‚,’,@x‚,’,@ƒ`‚,’,@x‚,’,@x‚,’,@x‚,’,@x‚,’,@ƒ`‚,’,@x‚,’,@x‚,’+@x‚+’+@x‚+’+@ƒ`‚+’+@x‚+’+@x‚+’+@x‚+’+@x‚+’+@ƒ`‚+’+@x‚+’+@x‚+’+@x‚+’+@x‚+’+@ƒ`‚+’+@x‚+’+@x‚+’+@x‚+’+@x‚+’+@ƒ`‚+’+@x‚+’+@x‚+’$d’0U‡H’::’>B%’?Q†b‚>^’AC*‚:ƒy‚?7‚Ag’?W‚D’>@;‚?2‚$‚0R’?N)‚>N’)2(’,-’3M’CV ’0A‚?Š‚)‚3 ‚0‚,%‚CƒW’+6’.1 ’5>’29’CX„’AIW‚C‚p’?H%‚AƒK’AH'‚? ‚2‚+‚.C‚5 ’>; ’$S'’FH‚A‚,’HH]’0Q ‚>2‚F=’:6’>;’CH’?P‚4‚H‚r‚?‚CF‚>’AB’FU‚:ƒ6‚A‚F‚Y‚$/‚0’?\‚’>J1‚?d’?E‚>t’AP+‚?'’3E’)C’0>’B<4‚A’CX‚B‡‚08‚3‚)‚6‚CN’5E’.:’+Cƒ’C8'’FV^‚Cƒ’HW‚F‚`’CC‚HƒX’AC]‚Ch‚A9‚5‚+,‚.’0Q<’7J2’>Vo’Kn‚S’JM#‚K’?s‚F\’CA’AJ ’Fn1‚C/‚?L’HO4‚F'‚H?’C@ ‚A’>J|’AJC‚C_‚AB‚>…4’>Ct‚>’?SJ’>S ’:E%‚?ƒ’†y’7GF’CG{‚7 ‚<‚:‚C?’5F(’8F2’?FD’AU‚‚A'’CYO‚C2’Fjp‚FI’HK‚1‚HB‚5!‚8‚?x’7F’IU’:F’Jd!‚I’AF‚f‚J’Kn‚F‚K6’MS|‚M4’ND6’O^’5F‚N!’8F2’?Fx’FF.‚7‚:‚A‚O‚5‚8‚?‚Fé8’7?’:?’>?ƒ`‚7‚:’0?x‚0’5?x‚5’7?x‚7’:?x‚>‚:’<9’??x‚<’<9x‚<’<9ƒ`‚<’<9x‚<’<9x‚<’<9x‚<’<9x‚<’<9ƒ`‚<’<9x‚<’<9x‚?‚<’<9x‚<’<9x‚<’<9ƒ`‚<’<9x‚<’<9x‚<’<9x‚<’<9x‚<’<9ƒ`‚<’<9x‚<’<9x‚<’:9’>?x‚:’:9x‚:’:9ƒ`‚:’:9x‚:’:9x‚:’:9x‚:’:9x‚:’:9ƒ`‚:’:9x‚:’:9x‚>‚:’:9x‚:’:9x‚:’:9ƒ`‚:’:9x‚:’:9x‚:’:9x‚:’:9x‚:’:9ƒ`‚:’:9x‚:’:9x‚:’?9x‚?’?9x‚?’?9ƒ`‚?’?9x‚?’?9x‚?’?9x‚?’?9x‚?’?9ƒ`‚?’?9x‚?’?9x‚?’?9x‚?’?9x‚?’?9ƒ`‚?’?9x‚?’?9x‚?’?9x‚?’?9x‚?’?9ƒ`‚?’?9x‚?’?9x‚?’C?’79x‚C‚7’C?’79x‚C‚7’C?’79ƒ`‚C‚7’C?’79x‚C‚7’C?’79x‚C‚7’C?’79x‚C‚7’C?’79x‚C‚7’C?’79ƒ`‚C‚7’C?’79x‚C‚7’C?’79x‚C‚7’A?’:9x‚A‚:’A?’:9x‚A‚:’A?’:9ƒ`‚A‚:’A?’:9x‚A‚:’A?’:9x‚A‚:’>?p‚>’F’7Fp‚>‚7’?Fx‚?’?Fx‚?’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?ƒ`‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?ƒ`‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’F?ƒ`‚<‚F’<9’F?x‚<‚F’<9’F?x‚<‚F’<9’??x‚<‚?’<9’??x‚<‚?’<9’??ƒ`‚<‚?’<9’A?x‚<‚A’<9’C?x‚<‚C’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’A?ƒ`‚:‚A’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’A?ƒ`‚:‚A’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’>?x‚:‚>’:9’>?x‚:‚>’:9’>?ƒ`‚:‚>’:9’>?x‚:‚>’:9’>?x‚:‚>’:9’A?x‚:‚A’:9’A?x‚:‚A’:9’A?ƒ`‚:‚A’:9’??x‚:‚?’:9’A?x‚:‚A’69’??x‚6‚?’69’??x‚6‚?’69’??ƒ`‚6‚?’69’??x‚6‚?’69’??x‚6‚?’69’??x‚6‚?’69’??x‚6‚?’69’??ƒ`‚6‚?’67’=?x‚6‚=’??’87x‚?‚8’F?’69x‚F‚6’F?’69x‚F‚6’F?’69ƒ`‚F‚6’F?’69x‚F‚6’F?’69x‚F‚6’F?’69x‚F‚6’F?’69x‚F‚6’F?’69ƒ`‚F‚6’D?’69x‚D‚6’C?’69x‚C‚6’??’59x‚?‚5’??’59x‚?‚5’??’59ƒ`‚?‚5’??’59x‚?‚5’??’59x‚?‚5’??’59x‚?‚5’??’59x‚?‚5’??’59ƒ`‚?‚5’C?’5?x‚C‚5’A?’4?x‚A‚4’F?’A?x‚F‚A’F?’A?x‚F‚A’F?’A?ƒ`‚F‚A’F?x‚F’F?x‚F’??’G?p‚?‚G’;?p‚;’8?’@Kp‚8‚@’6?’BKp‚6‚B’=9’D?x‚=’=9x‚=’=9ƒ`‚=’=9x‚=’=9x‚=’=9x‚=’=9x‚=’=9ƒ`‚=’=9x‚=’=9x‚D‚=’=9x‚=’=9x‚=’=9ƒ`‚=’=9x‚=’=9x‚=’=9’D?x‚=’=9x‚=’=9ƒ`‚=’=9x‚=’=9x‚D‚=’;9’B?x‚;’;9x‚;’;9ƒ`‚;’;9x‚;’;9x‚;’;9x‚;’;9x‚;’;9ƒ`‚;’;9x‚;’;9x‚B‚;’;9x‚;’;9x‚;’;9ƒ`‚;’;9x‚;’;9x‚;’;9’B?x‚;’;9x‚;’;9ƒ`‚B‚;’;9’@?x‚;‚@’;9’B?x‚;‚B’@?x‚@’@9x‚@’@9ƒ`‚@’@9x‚@’@9x‚@’@9x‚@’@9x‚@’@9ƒ`‚@’@9x‚@’@9x‚@’@9x‚@’@9x‚@’@9ƒ`‚@’@9x‚@’@9x‚@’@9x‚@’@9x‚@’@9‚h‚@’;?x‚;’@?x‚@’B?x‚B’D?’89x‚D‚8’D?’89x‚D‚8’D?’89ƒ`‚D‚8’D?’89x‚D‚8’D?’89x‚D‚8’D?’89x‚D‚8’D?’89x‚D‚8’D?’89ƒ`‚D‚8’D?’89x‚D‚8’D?’89x‚D‚8’B?’;9x‚B‚;’B?’;9x‚B‚;’B?’;9ƒ`‚B‚;’B?’;9x‚B‚;’B?’;9x‚B‚;’;?’??p‚?’=Fp‚;‚=’?F’8?p‚?’@Fx‚@’@Fx‚8‚@’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?ƒ`‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?ƒ`‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’G?ƒ`‚=‚G’=9’G?x‚=‚G’=9’G?x‚=‚G’=9’@?x‚=‚@’=9’@?x‚=‚@’=9’@?ƒ`‚=‚@’=9’B?x‚=‚B’=9’D?x‚=‚D’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’B?ƒ`‚;‚B’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’B?ƒ`‚;‚B’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’??x‚;‚?’;9’??x‚;‚?’;9’??ƒ`‚;‚?’;9’??x‚;‚?’;9’??x‚;‚?’;9’B?x‚;‚B’;9’B?x‚;‚B’;9’B?ƒ`‚;‚B’;9’@?x‚;‚@’;9’B?x‚;‚B’79’@?x‚7‚@’79’@?x‚7‚@’79’@?ƒ`‚7‚@’79’@?x‚7‚@’79’@?x‚7‚@’79’@?x‚7‚@’79’@?x‚7‚@’79’@?ƒ`‚7‚@’77’>?x‚7‚>’@?’97x‚@‚9’;9’G?x‚;‚G’;9’G?x‚;‚G’;9’G?ƒ`‚;‚G’;9’G?x‚;‚G’;9’G?x‚;‚G’;9’G?x‚;‚G’;9’G?x‚;‚G’;9’G?ƒ`‚;‚G’;7’D?x‚;‚D’G?’?7x‚G‚?’@9’L?x‚@‚L’@9’L?x‚@‚L’@9’L?ƒ`‚@‚L’@9’L?x‚@‚L’@9’L?x‚@‚L’@9’L?x‚@‚L’@9’L?x‚@‚L’@9’L?ƒ`‚@‚L’L?’D?x‚L‚D’K?’B?x‚K‚B’G?’B?…P‚G‚B’??’G?x‚?‚G’??’G?x‚?‚G’??’G?p‚?‚G’;Fp‚;’8?’@Kp‚8‚@’?K’6?p‚?‚6’;d’-d’4P‚4’8P’=P h‚=‚8‚;x‚-ÿ/MTrkAÿArpÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ ÃP³ d³@³[³ ³³e³d³C³&³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------ˆ‹“O dƒO“M dƒM“O dƒO“R dƒR“O dƒO“M dƒM“O dƒO“R dƒR“O dƒO“M dƒM“OdƒO“RdƒR“OdƒO“MdƒM“OdƒO“RdƒR“OdƒO“MdƒM“OdƒO“RdƒR“OdƒO“MdƒM“OdƒO“RdƒR“OdƒO“MdƒM“OdƒO“RdƒR“WdƒW“VdƒV“RdƒR“^dƒ^“YdƒY“WdƒW“YdƒY“RdƒR“YdƒY“WdƒW“YdƒY“RdƒR“YdƒY“WdƒW“YdƒY“RdƒR“YdƒY“WdƒW“YdƒY“RdƒR“YdƒY“WdƒW“YdƒY“R dƒR“Y dƒY“W!dƒW“Y!dƒY“R!dƒR“Y"dƒY“W"dƒW“Y#dƒY“R#dƒR“[$dƒ[“Y$dƒY“W%dƒW“R%dƒR“O%dƒO“M&dƒM“O&dƒO“T'dƒT“O'dƒO“M(dƒM“O(dƒO“T)dƒT“O)dƒO“M)dƒM“O*dƒO“T*dƒT“O+dƒO“M+dƒM“O,dƒO“T,dƒT“O-dƒO“M-dƒM“O-dƒO“T.dƒT“O.dƒO“M/dƒM“O/dƒO“T0dƒT“O0dƒO“M0dƒM“O1dƒO“T1dƒT“W2dƒW“V2dƒV“R3dƒR“O3dƒO“M4dƒM“K4dƒK“M4dƒM“R5dƒR“M5dƒM“K6dƒK“M6dƒM“R7dƒR“M7dƒM“K8dƒK“M8dƒM“R8dƒR“M9dƒM“K9dƒK“M:dƒM“R:dƒR“M;dƒM“K;dƒK“MdƒR“M>dƒM“K?dƒK“M?dƒM“V@dƒV“W@dƒW“V@dƒV“RAdƒR“^Adƒ^“[Bdƒ[“YBdƒY“[Cdƒ[“TCdƒT“[Ddƒ[“YDdƒY“[Ddƒ[“TEdƒT“[Edƒ[“YFdƒY“[Fdƒ[“TGdƒT“[Gdƒ[“YGdƒY“[Hdƒ[“THdƒT“WIdƒW“VIdƒV“WJdƒW“RJdƒR“WKdƒW“VKdƒV“WKdƒW“RLdƒR“WLdƒW“VMdƒV“WMdƒW“RNdƒR“WNdƒW“VOdƒV“WOdƒW“ROdƒR“YPdƒY“WPdƒW“YQdƒY“RQdƒR“YRdƒY“WRdƒW“YSdƒY“RSdƒR“YSdƒY“WTdƒW“YTdƒY“RUdƒR“YUdƒY“WVdƒW“YVdƒY“RYdƒR“YZdƒY“V[dƒV“Y\dƒY“R\dƒR“Y]dƒY“V^dƒV“Y^dƒY“R_dƒR“F`dƒF“MadƒM“RadƒR“TbdƒT“VcdƒV“YcdƒY“^ddƒ^“bedƒb“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“[ddƒ[“^ddƒ^“[ddƒ[“RddƒR“[ddƒ[“RddƒR“OddƒO“RddƒR“[ddƒ[“^ddƒ^“[ddƒ[“RddƒR“[ddƒ[“RddƒR“OddƒO“RddƒR“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“RddƒR“MddƒM“RddƒR“FddƒF“MddƒM“RddƒR“TddƒT“VddƒV“YddƒY“^ddƒ^“bddƒb“cndƒc“bndƒb“^ndƒ^“[ndƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“cddƒc“bddƒb“^ddƒ^“[ddƒ[“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“bddƒb“cddƒc“bddƒb“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“^ddƒ^“cddƒc“^ddƒ^“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“[ddƒ[“^ddƒ^“[ddƒ[“RddƒR“[ddƒ[“RddƒR“OddƒO“RddƒR“[ddƒ[“^ddƒ^“[ddƒ[“RddƒR“[ddƒ[“RddƒR“OddƒO“RddƒR“YddƒY“^ddƒ^“YddƒY“RddƒR“YddƒY“RddƒR“MddƒM“RddƒR“GddƒG“NddƒN“SddƒS“UddƒU“WddƒW“ZddƒZ“_ddƒ_“cddƒc“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“\ddƒ\“_ddƒ_“\ddƒ\“SddƒS“\ddƒ\“SddƒS“PddƒP“SddƒS“\ddƒ\“_ddƒ_“\ddƒ\“SddƒS“\ddƒ\“SddƒS“PddƒP“SddƒS“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“SddƒS“NddƒN“SddƒS“GddƒG“NddƒN“SddƒS“UddƒU“WddƒW“ZddƒZ“_ddƒ_“cddƒc“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“dddƒd“cddƒc“_ddƒ_“\ddƒ\“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“cddƒc“dddƒd“cddƒc“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“_ddƒ_“dddƒd“_ddƒ_“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“\ddƒ\“_ddƒ_“\ddƒ\“SddƒS“\ddƒ\“SddƒS“PddƒP“SddƒS“\ddƒ\“_ddƒ_“\ddƒ\“SddƒS“\ddƒ\“SddƒS“PddƒP“SddƒS“ZddƒZ“_ddƒ_“ZddƒZ“SddƒS“ZddƒZ“SddƒS“NddƒN“SddƒS“GddƒG“NddƒN“SddƒS“UddƒU“WddƒW“ZddƒZ“_ddƒ_“cddƒc“dddƒd“cddƒc“_cdƒ_“\bdƒ\“d`dƒd“c_dƒc“_^dƒ_“\\dƒ\“d[dƒd“cYdƒc“_Xdƒ_“\Wdƒ\“dUdƒd“cTdƒc“_Sdƒ_“\Qdƒ\“dPdƒd“cNdƒc“_Mdƒ_“\Ldƒ\“dJdƒd“cIdƒc“_Hdƒ_“\Fdƒ\“dEdƒd“cCdƒc“_Bdƒ_“\Adƒ\“d?dƒd“c>dƒc“_=dƒ_“\;dƒ\“d:dƒd“c9dƒc“_7dƒ_“\6dƒ\“d4dƒd“c3dƒc“_2dƒ_“\0dƒ\“d/dƒd“c.dƒc“_,dƒ_“\+dƒ\“d)dƒd“c(dƒc“_'dƒ_“\%dƒ\“d$dƒd“c#dƒc“_!dƒ_“\ dƒ\“ddƒd“cdƒc“_dƒ_“\dƒ\“ddƒd“cdƒc“_dƒ_“\dƒ\“ddƒd“cdƒc“_dƒ_“\dƒ\ÿ/MTrkÿArp2ÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ ÄP´ ´2´[´ ´´e´d´E´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------ˆ‹F”[ d„[”Y d„Y”[ d„[”^ d„^”[ d„[”Y d„Y”[ d„[”^ d„^”[ d„[”Y d„Y”[d„[”^d„^”[d„[”Yd„Y”[d„[”^d„^”[d„[”Yd„Y”[d„[”^d„^”[d„[”Yd„Y”[d„[”^d„^”[d„[”Yd„Y”[d„[”^d„^”cd„c”bd„b”^d„^”jd„j”ed„e”cd„c”ed„e”^d„^”ed„e”cd„c”ed„e”^d„^”ed„e”cd„c”ed„e”^d„^”ed„e”cd„c”ed„e”^d„^”ed„e”cd„c”ed„e”^ d„^”e d„e”c!d„c”e!d„e”^!d„^”e"d„e”c"d„c”e#d„e”^#d„^”g$d„g”e$d„e”c%d„c”^%d„^”[%d„[”Y&d„Y”[&d„[”`'d„`”['d„[”Y(d„Y”[(d„[”`)d„`”[)d„[”Y)d„Y”[*d„[”`*d„`”[+d„[”Y+d„Y”[,d„[”`,d„`”[-d„[”Y-d„Y”[-d„[”`.d„`”[.d„[”Y/d„Y”[/d„[”`0d„`”[0d„[”Y0d„Y”[1d„[”`1d„`”c2d„c”b2d„b”^3d„^”[3d„[”Y4d„Y”W4d„W”Y4d„Y”^5d„^”Y5d„Y”W6d„W”Y6d„Y”^7d„^”Y7d„Y”W8d„W”Y8d„Y”^8d„^”Y9d„Y”W9d„W”Y:d„Y”^:d„^”Y;d„Y”W;d„W”Yd„^”Y>d„Y”W?d„W”Y?d„Y”b@d„b”c@d„c”b@d„b”^Ad„^”jAd„j”gBd„g”eBd„e”gCd„g”`Cd„`”gDd„g”eDd„e”gDd„g”`Ed„`”gEd„g”eFd„e”gFd„g”`Gd„`”gGd„g”eGd„e”gHd„g”`Hd„`”cId„c”bId„b”cJd„c”^Jd„^”cKd„c”bKd„b”cKd„c”^Ld„^”cLd„c”bMd„b”cMd„c”^Nd„^”cNd„c”bOd„b”cOd„c”^Od„^”ePd„e”cPd„c”eQd„e”^Qd„^”eRd„e”cRd„c”eSd„e”^Sd„^”eSd„e”cTd„c”eTd„e”^Ud„^”eUd„e”cVd„c”eVd„e”^Yd„^”eZd„e”b[d„b”e\d„e”^\d„^”e]d„e”b^d„b”e^d„e”^_d„^”R`d„R”Yad„Y”^ad„^”`bd„`”bcd„b”ecd„e”jdd„j”ned„n”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”bdN„b*”edN„e*”bdN„b*”YdN„Y*”bdN„b*”YdN„Y*”VdN„V*”YdN„Y*”bdN„b*”edN„e*”bdN„b*”YdN„Y*”bdN„b*”YdN„Y*”VdN„V*”YdN„Y*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”YdN„Y*”TdN„T*”YdN„Y*”RdN„R*”YdN„Y*”^dN„^*”`dN„`*”bdN„b*”edN„e*”jdN„j*”ndN„n„ ”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”jdN„j*”idN„i*”edN„e*”bdN„b*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”idN„i*”jdN„j*”idN„i*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”edN„e*”jdN„j*”edN„e*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”bdN„b*”edN„e*”bdN„b*”YdN„Y*”bdN„b*”YdN„Y*”VdN„V*”YdN„Y*”bdN„b*”edN„e*”bdN„b*”YdN„Y*”bdN„b*”YdN„Y*”VdN„V*”YdN„Y*”`dN„`*”edN„e*”`dN„`*”YdN„Y*”`dN„`*”YdN„Y*”TdN„T*”YdN„Y*”SdN„S*”ZdN„Z*”_dN„_*”adN„a*”cdN„c*”fdN„f*”kdN„k*”odN„o*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”cdN„c*”fdN„f*”cdN„c*”ZdN„Z*”cdN„c*”ZdN„Z*”WdN„W*”ZdN„Z*”cdN„c*”fdN„f*”cdN„c*”ZdN„Z*”cdN„c*”ZdN„Z*”WdN„W*”ZdN„Z*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”ZdN„Z*”UdN„U*”ZdN„Z*”SdN„S*”ZdN„Z*”_dN„_*”adN„a*”cdN„c*”fdN„f*”kdN„k*”odN„o„ ”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”kdN„k*”jdN„j*”fdN„f*”cdN„c*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”jdN„j*”kdN„k*”jdN„j*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”fdN„f*”kdN„k*”fdN„f*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”cdN„c*”fdN„f*”cdN„c*”ZdN„Z*”cdN„c*”ZdN„Z*”WdN„W*”ZdN„Z*”cdN„c*”fdN„f*”cdN„c*”ZdN„Z*”cdN„c*”ZdN„Z*”WdN„W*”ZdN„Z*”adN„a*”fdN„f*”adN„a*”ZdN„Z*”adN„a*”ZdN„Z*”UdN„U*”ZdN„Z*”SdN„S*”ZdN„Z*”_dN„_*”adN„a*”cdN„c*”fdN„f*”kdN„k*”odN„o*”kdN„k*”jdN„j*”fcN„f*”cbN„c*”k`N„k*”j_N„j*”f^N„f*”c\N„c*”k[N„k*”jYN„j*”fXN„f*”cWN„c*”kUN„k*”jTN„j*”fSN„f*”cQN„c*”kPN„k*”jNN„j*”fMN„f*”cLN„c*”kJN„k*”jIN„j*”fHN„f*”cFN„c*”kEN„k*”jCN„j*”fBN„f*”cAN„c*”k?N„k*”j>N„j*”f=N„f*”c;N„c*”k:N„k*”j9N„j*”f7N„f*”c6N„c*”k4N„k*”j3N„j*”f2N„f*”c0N„c*”k/N„k*”j.N„j*”f,N„f*”c+N„c*”k)N„k*”j(N„j*”f'N„f*”c%N„c*”k$N„k*”j#N„j*”f!N„f*”c N„c*”kN„k*”jN„j*”fN„f*”cN„c*”kN„k*”jN„j*”fN„f*”cN„c*”kN„k*”jN„j*”fN„f*”cN„cÿ/MTrk*ÿLeadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------µyµµ Åpµ µnµ[µ µµeµdµDµ&µeµdµ@µeµdµ å@µeµdÿG---- End of CH Setup --------------------------------------------------‚Ž•Tdp…T•Rdp…R•Tdp…T•Ydx…Y•Tdx…T–@•Rdp…R•Pdp…P•Rdp…R•Wdx…W•Rdx…R–@•Pdp…P•Odp…O•Pdp…P•Udx…U•Pdx…P–@•Odp…O•Pdp…P•Odp…O•Mdx…M•Kdx…K–@•Tdp…T•Rdp…R•Tdp…T•Ydx…Y•Tdx…T–@•Rdp…R•Pdp…P•Rdp…R•Wdx…W•Rdx…R–@•Pdp…P•Odp…O•Pdp…P•Udx…U•Pdx…P–@•Odp…O•Pdp…P•Odp…O•Mdx…M•Kdx…K…P•Fdp…F•Mdp…M•Kdp…K•Mdp…M•Odx…O•Rdx…R…P•Tdx…T•Vdx…V•Wdp…W•Vdx…V•Odx…O—8•Tdx…T•Vdx…V•Wdx…W•Ydx…Y•Rdx…R•Rdx…R…P•^dx…^•^dx…^…P•[dx…[•[dp…[•Ydp…Y•Wdp…W•Ydx…Y•Rdx…R†H•[dx…[•Ydp…Y•Wdp…W•Vdp…V•Wdx…W•Rdx…R†H•Odx…O•Rdx…R†H•Ydx…Y…P•^dx…^•^dx…^†H•edx…e…P•jdx…j•jdx…jŽ•Rdx…R…P•Wdx…W•Wdx…W…P•Ydx…Y•Ydx…YŽ•^dx…^†H•Vdx…V‚h•Wdx…Wp•Rdx…R•Rdx…R™(•Rdx…Rp•Ydx…Y•Ydx…Y…P•^dx…^•^dx…^…P•edx…e•edx…ep•cdx…c•cdx…cp•bdx…b•bdx…bp•[dx…[•[dx…[ƒÆX•T(p…T•T-p…T•T2p…T•T9p…T•TBp…T•TMp…T•TZp…T•Tdp…T•Rdp…R•Tdp…T•Ydx…Y•Tdx…T–@•Rdp…R•Mdp…M•Rdp…R•Wdx…W•Ydx…Y‡@•Rdp…R…P•^dp…^…P•[dp…[•Ydp…Y•Wdp…W•Ydx…Y•Rdx…R•Od‚h…Oƒ`•Rdx…R•Rdp…R•^dp…^…P•edp…e…P•Tdp…T•Rdp…R•Tdp…T•Ydx…Y•Tdx…T–@•Rdp…R•Mdp…M•Rdp…R•Wdx…W•Ydx…Y‡@•Rdp…R…P•^dp…^…P•[dp…[•Ydp…Y•Wdp…W•Ydx…Y•Rdx…R–@•[dp…[•Ydp…Y•Wdp…W•Ydx…Y•Rdx…R–@•Udp…U•Sdp…S•Udp…U•Zdx…Z•Udx…U–@•Sdp…S•Ndp…N•Sdp…S•Xdx…X•Zdx…Z‡@•Sdp…S…P•_dp…_…P•\dp…\•Zdp…Z•Xdp…X•Zdx…Z•Sdx…S•Pd‚h…Pƒ`•Sdx…S•Sdp…S•_dp…_…P•fdp…f…P•hdp…h•Sdp…S•Udp…U•Zdx…Z•Udx…U–@•Sdp…S•Ndp…N•Sdp…S•Xdx…X•Zdx…Z‡@•Sdp…S…P•_dp…_…P•\dp…\•Zdp…Z•Xdp…X•Zdx…Z•Sdx…S–@•\dp…\•Zdp…Z•Xdp…X•Zdx…Z•_dx…_‡@•\d(…\‡•_d(…_‡•dd…dÿ/MTrk :ÿLead2ÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¶y¶¶ Æ ¶ h¶n¶[¶ ¶¶e¶d¶B¶&¶e¶d¶@¶e¶d¶ æ@¶e¶dÿG---- End of CH Setup --------------------------------------------------‚Ž–Td–C,p†T–Rdp†R–Tdp†C†T–Yd–C,x†Y†C–Td–C,x†T†C–C,‡@†C–C,…P†C–C,x†C–C,x†C–C,‡@†C–Rd–A,p†R–Pdp†P–Rdp†A†R–Wd–A,x†W†A–Rd–A,x†R†A–A,‡@†A–A,…P†A–A,x†A–A,x†A–A,‡@†A–Pd–?,p†P–Odp†O–Pdp†?†P–Ud–?,x†U†?–Pd–?,x†P†?–?,‡@†?–?,…P†?–?,x†?–?,x†?–?,‡@†?–Od–>,p†O–Pdp†P–Odp†>†O–Md–>,x†M†>–Kd–>,x†K†>–>,‡@†>–>,…P†>–>,x†>–>,x†>–>,‡@†>–Td–C,p†T–Rdp†R–Tdp†C†T–Yd–C,x†Y†C–Td–C,x†T†C–C,‡@†C–C,…P†C–C,x†C–C,x†C–C,‡@†C–Rd–A,p†R–Pdp†P–Rdp†A†R–Wd–A,x†W†A–Rd–A,x†R†A–A,‡@†A–A,…P†A–A,x†A–A,x†A–A,‡@†A–Pd–?,p†P–Odp†O–Pdp†?†P–Ud–?,x†U†?–Pd–?,x†P†?–?,‡@†?–?,…P†?–?,x†?–?,x†?–?,‡@†?–Od–A,p†O–Pdp†P–Odp†A†O–Md–A,x†M†A–Kd–A,x†K†A–A,…P–Fdp†A†F–Md–C,p†M–Kdp†K–Mdp†C†M–Od–C,x†O†C–Rd–C,x†R†C–C,…P–Tdx†T–Vdx†C†V–Wd–C,p†W–Vdx†V–Odx†Op†C–C,x†C–C,x†C–C,‡@†C–C,…P†C–C,x†C–C,x†C–C,„X–Tdx†T–Vdx†V–Wdx†C†W–Yd–A,x†Y„X†A–A,x†A–A,x†A–A,†H–Rdx†A†R–Rd–A,x†R„X†A–A,x†A–^d–A,x†^†A–^d–A,x†^…P–[dx†A†[–[d–A,p†[–Ydp†Y–Wdp†A†W–Yd–A,x†Y†A–Rd–A,x†R†A–A,†H–[dx†A†[–Yd–A,p†Y–Wdp†W–Vdp†A†V–Wd–A,x†W†A–Rd–A,x†R†A–A,†H–Odx†A†O–Rd–<,x†R„X†<–<,x†<–<,x†<–Yd–<,x†Y…P–^dx†<†^–^d–<,x†^„X†<–<,x†<–<,x†<–ed–<,x†e…P–jdx†<†j–jd–C,x†j„X†C–C,x†C–C,x†C–C,‡@†C–C,–Rdx†R„X†C–C,x†C–C,–Wdx†C†W–C,–Wdx†W…P–Ydx†C†Y–A,–Ydx†Y„X†A–A,x†A–A,x†A–A,‡@†A–A,–^dx†^„X†A–A,x†A–A,x†A–A,–Vdx†V‚h–Wdx†Wp–Rdx†A†R–A,–Rdx†R„X†A–A,x†A–A,x†A–A,‡@†A–A,…P†A–A,x†A–A,x†A–A,ƒ`–Rdx†Rp–Ydx†A†Y–<,–Ydx†Y„X†<–<,x†<–<,–^dx†<†^–<,–^dx†^…P–edx†<†e–<,–edx†ep–cdx†c–cdx†cx†<–<,x†<–<,–bdx†<†b–<,–bdx†bp–[dx†<†[–[dx†[ƒÆX–T(p†T–T-p†T–T2p†T–T9p†T–TBp†T–TMp†T–TZp†T–Tdp†T–Rdp†R–Tdp†T–Ydx†Y–Tdx†T–@–Rdp†R–Mdp†M–Rdp†R–Wdx†W–Vdx†V‡@–Rdp†R…P–Vdp†V…P–[dp†[–Ydp†Y–Wdp†W–Ydx†Y–Rdx†R–Od‚h†Oƒ`–Rdx†R–Rdp†R–^dp†^…P–edp†e…P–Tdp†T–Rdp†R–Tdp†T–Ydx†Y–Tdx†T–@–Rdp†R–Mdp†M–Rdp†R–Wdx†W–Vdx†V‡@–Rdp†R…P–Vdp†V…P–[dp†[–Ydp†Y–Wdp†W–Ydx†Y–Rdx†R–@–[dp†[–Ydp†Y–Wdp†W–Ydx†Y–Rdx†R—8–Udp†U–Sdp†S–Udx†U–Zdx†Z–Udx†U—8–Sdp†S–Ndp†N–Sdx†S–Xdx†X–Wdx†W‡@–Sdp†S…P–Wdp†W†H–\dp†\–Zdp†Z–Xdx†X–Zdx†Z–Sdx†S–Pd‚h†Pƒ`–Sdx†S–Sdp†SŽ–_dp†_…P–fdp†f…P–Udp†U–Sdp†S–Udx†U–Zdx†Z–Udx†U—8–Sdp†S–Ndp†N–Sdx†S–Xdx†X–Wdx†W‡@–Sdp†S…P–Wdp†W†H–\dp†\–Zdp†Z–Xdx†X–Zdx†Z–Sdx†S—8–\dp†\–Zdp†Z–Xdx†X–Zdx†Z–_dx†_‡@–dd(†d‡–fd(†f‡–kd†kÿ/MTrk òÿBassÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------·y·· Ç!· H·d·[· ··e·d·@·&·e·d·@·e·d· ç@·e·dÿG---- End of CH Setup --------------------------------------------------ÿ^—+d‡@‡+—$dƒ`‡$p—$d…P‡$p—$Up‡$p—$d…P‡$—+dƒ`‡+—$Zƒ`‡$—"dƒ`‡"p—"d…P‡"p—"Up‡"p—"d…P‡"—)dƒ`‡)—"Zƒ`‡"— dƒ`‡ p— d…P‡ p— Up‡ p— d…P‡ —'dƒ`‡'— Up‡ —dp‡—dƒ`‡p—d…P‡p—Up‡p—d…P‡—&Zƒ`‡&—+Z„‡+ŽD—$d‡$—"d‡"‡@—.d‡@‡.— d‡ —+d‡@‡+—d‡@‡—d‡—d‡—$d‡$p—+d‡@‡+—$d‡@‡$—"d‡"p—)d‡@‡)—.d‡@‡.— d‡ p—'d‡@‡'— d‡@‡ —d‡—d‡—$d‹ ‡$p—dp‡—$i‚h‡$—Z‚h‡—$d‡2çC?ç7>ç+=ç<ç;ç:ç{8ço7çc6çB6‡$ç@—"d‡"—Zp‡—"d†H‡"xçk9—.dçP:ç5; ç^;ç'<çp<ç8=ç}=ç>ç>>ç^>ç>ç? ç@„l‡.—3dƒ`‡3ç=—.dç|=ça>çF?ç@‚‡.—'Z†H‡'—dp‡— Z†H‡ ç=—'dç>ç{>ç@ƒ~‡'— Zƒ`‡ —d‡@‡—&d‡@‡&—+Z…P‡+ç=—&Zç|=ça>çF?ç@ƒw‡&—d„X‡—$d‡$—+Zp‡+—0d‡@‡0—$d‡@‡$—"d‡"—)Zp‡)çT=—.dçE=ç>çc>ç1?ç@†4‡.—"d‡@‡"— d‹ ‡ —'dƒ`‡'—,d‡@‡,— d‡@‡ —d‹ ‡—&dƒ`‡&—+dŠ2çx?çç>çJ=ç= çz<çV;ç2:ç9çk7çG6 ‡+ç#5ç64ç91ç=.çA+çD(çH% çI$ ç'ç@—$d—`ç-?çw<çA:ç 8çT5ç3çg0ç1.ç{+çE)ç'çX$ç""çk ç ‡$ç@p—d‹ ‡ƒ`—d‰0‡—"Z‚h‡"—#d‚h‡#—$Zç3>çW>ç{>ç?ç@އ$ƒ`çT=—"Zç=ç|=ça>çF?ç@p‡"—$d‚h‡$—'Z‚h‡'ç <—+dIç>ç@‚‡+—)Zˆ8‡)‚h—dއx—"Zƒ`‡"—$d‡@‡$—+Z…xç@çi=çR;ç;9ç$7ç 5çv2 ç2 ‡+ç@‡h—$P‡@‡$P—Z‡@‡—U‡”n—Z„X‡ç<;—+dç0;<ç0<<ç0=<ç/><ç/?<ç/@ç@‚k· ƒ8ç?<ç><ç9=(·çS<—)d ‡+ç8>çh><ç@‚J·ƒt—dƒ·ƒ8‡ ‡)øZ— d‰0‡ p—'Zƒ`‡'—,d…P‡,— d…P‡ ƒ`—d‰0‡p—&Zƒ`‡&—+d…P‡+—d…P‡ƒ`· —d‰0‡p—$dƒ`‡$—)dƒ`‡)—Z…P‡p—)dƒ`‡)—d‰0‡p—&Zƒ`‡&—+dƒ`‡+—$Zp‡$—&iƒ`‡&—"Zp‡"—nƒ`‡— d‹ ‡ p—'dp‡'—,d†H‡,x— d†H‡ x—d‹ ‡p—&dp‡&—+d†H‡+x—dƒ`‡—&dƒ`‡&—d‹ ‡—%Zƒ`‡%—*d‡@‡*—d‡@‡—d‡@‡—$Zƒ`‡$—dƒ`‡—dƒ`‡—&Zƒ`‡&—Zp‡—&Zp‡&çU<—.d<çe=<çv><ç@<‡.—+Zp‡+— d‹ ‡ p—'dp‡'—,d†H‡,x— d†H‡ x—d‹ ‡p—&dp‡&—+d†H‡+x—Zƒ`‡—&dƒ`‡&—d‹ ‡—%Zƒ`‡%—*d‡@‡*—d‡@‡—d…P‡—$Zp‡$—)d„X‡)‚h—dƒ`‡—&dƒ`‡&—,dp‡,— Zp‡ —,d‚çQ?<ç0><ç=<ço;‡,ç@—!d‹ ‡!p—(dp‡(—-d†H‡-x—!d†H‡!x— d‹ ‡ p—'dp‡'—,d†H‡,x— dƒ`‡ —'dƒ`‡'—d‹ ‡—&Zƒ`‡&—+d‡@‡+—Zƒ`‡—#dƒ`‡#—d‡@‡—%Zƒ`‡%—*dƒ`‡*— dƒ`‡ —'Zƒ`‡'— Zp‡ —'Zp‡'—/dp‡/—3Zp‡3—!d‹ ‡!p—(dp‡(—-d†H‡-x—!dƒ`‡!—-dƒ`‡-— d‹ ‡ p—'dp‡'—,d†H‡,x— dƒ`‡ —'dƒ`‡'—n‹ ‡—&dƒ`‡&—+n‡@‡+—n‡@‡—n‡@‡—*dƒ`‡*—dƒ`‡— n‡@‡ —,n…P‡,p—-d‡-—!d¡`‡!ÿ/MTrk »ÿPadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¸y¸¸ Èf¸ @¸n¸[¸ `¸¸e¸d¸@¸&¸e¸d¸@¸e¸d¸ è@¸e¸dÿG---- End of CH Setup --------------------------------------------------˜$d‰¸ a…d˜E˜AE˜FE‰¸ d$ˆ$˜+d\¸ e…dˆ:ˆ>ˆAˆFˆ+˜8F˜F˜CF˜.dˆ$¸ h¸ i†\ˆ$ˆ7ˆ:ˆ>ˆCˆ.˜E˜AE˜FE†>¸ lˆBˆ0˜2dŒ¸ m‚rˆ:ˆ>ˆAˆFˆ2˜8F˜F˜AFˆ+ˆ7ˆ:ˆ>ˆA˜E˜AE˜FE˜.džˆ:ˆ>ˆAˆFˆ.˜8F˜F˜AFˆ+ˆ7ˆ:ˆ>ˆA˜?E˜HE˜FE˜CE˜0džˆ?ˆHˆFˆCˆ0˜>E˜AE˜FE˜JE˜.dˆJ˜KEˆ>ˆAˆFˆ.ˆK˜F˜7d˜AF˜MEˆ:ˆ>ˆ7ˆAˆM˜0F˜7F˜>F˜FF˜?Fžˆ0ˆ7ˆ>ˆFˆ?˜.F˜5F˜FF˜AF˜>Fžˆ.ˆ5ˆFˆAˆ>˜,F˜?F˜CF˜5F˜:Fžˆ,ˆ?ˆCˆ5ˆ:˜AF˜+F˜2F˜:F˜5FžˆAˆ+ˆ2ˆ:ˆ5˜0F˜7F˜>F˜FF˜?Fžˆ0ˆ7ˆ>ˆFˆ?˜.F˜5F˜FF˜AF˜>Fžˆ.ˆ5ˆFˆAˆ>˜,F˜5F˜:F˜KF˜CFžˆ,ˆ5ˆ:ˆKˆC˜AF˜+F˜2F˜:F˜5F˜MF›ˆAˆ+ˆ2ˆ:ˆ5‚hˆMḠ`˜CF˜5F˜8F˜FˆAˆ3ˆ:ˆ.ˆ>˜3F˜1d˜FF˜AF˜7Fˆ7˜F†4¸ f<¸ g4¸ hp¸ i4¸ jp¸ k4¸ lˆ7˜:F\¸ mp¸ n4¸ op¸ p4¸ qp¸ r4¸ sp¸ t4¸ uˆ)ˆ0ˆ?ˆ>ˆ:˜+d˜FF˜?F˜5F˜:F\¸ v4¸ w¸ wx¸ x4¸ yp¸ zp¸ {p¸ |4¸ }>ˆ?˜>F2¸ ~„l¸ ‰bˆ+ˆFˆ5ˆ:ˆ>¸ s˜HF˜,d˜3F˜7F˜F˜5F˜7Fžˆ+ˆFˆ>ˆ5ˆ7˜*d˜?F˜6F˜:F˜FFžˆ*ˆ?ˆ6ˆ:ˆF˜)d˜CF˜?F˜J˜FP‹ ˆ7ƒ`ˆ+ˆ>ˆF˜,d˜3F˜7F˜HFˆHˆ7˜CF˜5Fˆ,ˆ3ˆCˆ5˜+d˜>F˜5F˜7F˜FFˆFˆ7˜JF˜:Fˆ+ˆ>ˆ5ˆJˆ:˜*d˜:F˜AF˜KFˆKˆA˜?F˜FFˆ*ˆ:ˆ?ˆF˜)d˜CF˜?F˜8Fˆ)ˆCˆ?ˆ8è@˜+d˜>F˜CF†HˆCˆ>xˆ+è-@¸ x˜?F˜DF˜,d†Hˆ?ˆDxˆ,è@¸ z˜IF˜-d˜8F˜@FžˆIˆ-ˆ8ˆ@˜,d˜GF˜?F˜6Fžˆ,ˆGˆ?ˆ6˜+d˜@F˜7F˜;F˜GFžˆ+ˆ@ˆ7ˆ;ˆG˜*d˜DF˜@F˜=F˜9Fˆ*ˆDˆ@ˆ=ˆ9˜,d˜8F˜;F˜?F˜GFˆ,ˆ8ˆ;ˆ?ˆG˜-d˜4F˜8F˜IFˆIˆ8˜DF˜6Fˆ-ˆ4ˆDˆ6˜,d˜?F˜6F˜8F˜GFˆGˆ8˜KF˜;Fˆ,ˆ?ˆ6ˆKˆ;˜+d˜7F˜;F˜BF˜LFˆLˆB˜@F˜GFˆ+ˆ7ˆ;ˆ@ˆG˜*d˜DF˜=F˜9Fˆ*ˆDˆ=ˆ9˜,d˜8F˜BF˜;Fˆ,ˆ8ˆBˆ;˜-d˜4?˜8?˜=?˜DF°`ˆ-ˆ4ˆ8ˆ=ˆDÿ/MTrk¦ÿDrumÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹ ɹ @¹n¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------¹ n‡@™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*L™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*…™,:<‰,‡|™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*L™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*‚,™.J<‰.4™,J<‰,<™*:<‰*<™$U<‰$‡™*J™%U<‰*‰%4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*4™%U<‰%<™*:<‰*„™*:<‰*<™$7<‰$<™$U<‰$‡™*J™%U<‰*‰%4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*4™%U<‰%<™*:<‰*‚,™$U<‰$<™*:<‰*<™.H<‰.4™$U™,H<‰$‰,‚,™*:<‰*„™*J™%U<‰*‰%4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*4™%U<‰%<™*:<‰*‚,™*4<‰*‚,™,:™$7<‰,‰$<™$U™3Z<‰$‰3‡™*J<‰*4™*<<‰*4™*J<‰*4™$B<‰$4™*J™$U™3Z<‰*‰$‰3‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*‚,™.J<‰.’$¹ u™$c™7c<‰$‰7‡™$c™37<‰$‰3ƒ$™*;<‰*ƒ$™$c™3@<‰$‰3ƒ$™*;<‰*4™$<<‰$<™*;<‰*<™$c™37<‰$‰3‡™$c™3@<‰$‰3‡™$c™37<‰$‰3ƒ$™*;<‰*ƒ$™$c™3@<‰$‰3ƒ$™*;<‰*‚,™$<™*;<‰$‰*<™$c™37<‰$‰3ƒ$™.B<‰.4™$B<‰$<™37<‰3<™$c™3@™,B<‰$‰3‰,‡™$c™37™*B<‰$‰3‰*ƒ$™*;<‰*ƒ$™$c™3@<‰$‰3ƒ$™*;<‰*4™$<<‰$<™*;<‰*<™$c™37<‰$‰3ƒ$™*2<‰*ƒ$™$c™3@™.B<‰$‰3‰.‡™$c™37™*;<‰$‰3‰*4™*2<‰*4™*;<‰*ƒ$™$c™3@™*;<‰$‰3‰*ƒ$™*;<‰*‚,™*;™$c<‰*‰$<™%c™.B™7B<‰%‰.‰74™$B<‰$4™$c™,;<‰$‰,4™*M<‰*<™$B™37™%;<‰$‰3‰%<™$c™7c™,;<‰$‰7‰,4™*;™%G<‰*‰%4™-2<‰-<™*2<‰*‚,™$c™.B™37<‰$‰.‰34™,;<‰,4™*2<‰*4™*2<‰*<™%;<‰%<™$c™3@<‰$‰3<™*2<‰*<™%G<‰%4™.B<‰.4™$<™,2<‰$‰,<™*B<‰*<™$c™37<‰$‰34™*B<‰*4™*2<‰*<™/2<‰/4™%;<‰%<™$c™3@™,;<‰$‰3‰,4™%G™*;<‰%‰*4™-2<‰-<™*2<‰*‚,™$c™.B™37<‰$‰.‰34™,;<‰,4™*2<‰*4™*2<‰*<™%;<‰%<™$c™3@<‰$‰3<™*2<‰*<™%G<‰%4™.B<‰.4™,2<‰,<™$<™*B<‰$‰*<™$c™37<‰$‰34™*B<‰*4™*2<‰*4™$B™&G<‰$‰&<™&@™37<‰&‰3<™$c™7M™,;<‰$‰7‰,4™*;™%G<‰*‰%4™-2<‰-<™*2<‰*‚,™$c™37™.B<‰$‰3‰.4™,;<‰,4™*2<‰*4™*2<‰*<™%;<‰%<™$c™3@<‰$‰3<™*2<‰*<™%G<‰%4™.B<‰.4™$<™,2<‰$‰,<™$<™*B<‰$‰*<™$c™37<‰$‰34™*B<‰*4™*2<‰*<™/2<‰/4™$<™%;<‰$‰%<™$c™,;™7M<‰$‰,‰74™%G™*B<‰%‰*4™-8<‰-<™*8<‰*4™&L<‰&<™$c™37<‰$‰3<™*8<‰*<™&R™.M<‰&‰.4™$c<‰$<™,8<‰,<™/M<‰/<™$<<‰$<™$c™7c<‰$‰7<™&A<‰&<™&h<‰&<™*c<‰*<™4M<‰44™0c<‰0<™$<™&R<‰$‰&<™$c™-c<‰$‰-<™&h<‰&4™.c™$c<‰.‰$<™7c<‰74™$B™,c<‰$‰,<™&h<‰&<¹ n™$c™1c<‰$‰1‚,™*c<‰*<™%c<‰%4™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™$c™,M<‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™)M<‰)<™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™$c™,M<‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™)M<‰)<™$c™7c<‰$‰7‚,™*c<‰*<™%c<‰%4™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™$c™,M<‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™)M<‰)<™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$‚,™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M™$<<‰.‰$4™$c™,M<‰$‰,<™&L<‰&4™*c™$c<‰*‰$<™%c<‰%4™$c<‰$4™7c<‰7<™*c<‰*<™%c<‰%<™$c<‰$<™/X<‰/<™&R<‰&<™$<™+M<‰$‰+<™)M<‰)<¹ s™$c™1c<‰$‰1‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™3h™$c™,M<‰3‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™)M<‰)<™$c™7M<‰$‰7‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™3h™$c™,M<‰3‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™$<™)M<‰$‰)<™$c™7M<‰$‰7‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™.M<‰.<™$<<‰$<™3h™$c™,M<‰3‰$‰,‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™+M<‰$‰+<™)M<‰)<™7M™$c<‰7‰$‚,™*c<‰*<™%c<‰%4™$c<‰$4™3]<‰3<™*c<‰*<™%c<‰%4™$c<‰$<™*M<‰*<™$<™.M<‰$‰.<™&R<‰&<™$c™4c<‰$‰4<™&R<‰&4™&]<‰&<™$X<‰$4™$c<‰$<™&]<‰&<™3]<‰3<™&]<‰&<™$X<‰$4™$c™0B<‰$‰0™0B<‰0™0X<‰0™-X<‰-<™-M<‰-<™$c™7c<‰$‰7è™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*L™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*…™,:<‰,‡|™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*L™*J<‰*4™*<<‰*4™*J<‰*ƒ$™*J<‰*‚,™*8<‰*‚,™*G<‰*‚,™*:<‰*‚,™.J<‰.4™,J™$7<‰,‰$<™*:<‰*<™$U™3Z<‰$‰3‡™%U™3@<‰%‰34™*<<‰*4™*J<‰*ƒ$™*J™3R<‰*‰3‚,™*8<‰*‚,™*G<‰*4™%U™3@<‰%‰3<™*:<‰*„™*:<‰*<™$7<‰$<™$U™3Z<‰$‰3‡™%U™3@<‰%‰34™*<<‰*4™*J<‰*ƒ$™*J™3R<‰*‰3‚,™*8<‰*‚,™*G<‰*4™%U™3@<‰%‰3<™*:<‰*4¹ yx™$U<‰$<™*:<‰*<™.H<‰.4™$U™,H™3Z<‰$‰,‰3‚,™*:<‰*„™%U™3@<‰%‰34™*<<‰*4™*J<‰*ƒ$™*J™3R<‰*‰3‚,™*8<‰*‚,™*G<‰*4™%U™3@<‰%‰3<™*:<‰*‚,™*4<‰*‚,™,:™$7<‰,‰$<¹ }™$U™7U<‰$‰7ƒ$™*J<‰*4™$7<‰$4™3Z™.J<‰3‰.4™&L<‰&™&12™,J ‰&2‰,4™$B™*J<‰$‰*4¹ ™*J™$U™7U<‰*‰$‰74™/c<‰/<™*8<‰*‚,™*G™-c<‰*‰-<™+c<‰+ ™&12™&h™.c ‰&2‰&‰.4™$U<‰$4™,c<‰,<™)c<‰)<™$B™&h<‰$‰&4™1c™$c<‰1‰$…™$J<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*ƒ$™$c™3Z<‰$‰3ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™.M<‰.4™$U<‰$4™$c™3Z™,J<‰$‰3‰,ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*ƒ$™$c™,J™7U<‰$‰,‰7ƒ$™*J<‰*4™$U<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$U<‰$4™$c™3R™,J<‰$‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™,J™7M<‰&‰,‰74™$U™/c<‰$‰/4™-c™.M<‰-‰.4™$U™+c<‰$‰+4™1U™$c™,M<‰1‰$‰,…™$U<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*ƒ$™$c™3Z™,J<‰$‰3‰,ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™.M<‰.4™$U<‰$4™$c™1U™,J<‰$‰1‰,ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$U<‰$4™$c™1U<‰$‰1ƒ$™*J<‰*4™$U<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$U<‰$4™$c™,J™1M<‰$‰,‰1ƒ$™$c™*J<‰$‰*ƒ$™&h™,J™7M<‰&‰,‰74™$U™/c<‰$‰/<™/c<‰/<™-c™.M<‰-‰.4™$U™+c<‰$‰+4™1n™$c™,J<‰1‰$‰,…™$U<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*ƒ$™$c™3Z<‰$‰3ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™.M<‰.4™$U<‰$4™$c™3Z™,J<‰$‰3‰,ƒ$™*J<‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$c<‰$4™3R™,J<‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*ƒ$™$c™,J™7U<‰$‰,‰7ƒ$™*J<‰*4™$U<‰$4™&h™3@™,J<‰&‰3‰,ƒ$™*J<‰*4™$U<‰$4™$c™3R™,J<‰$‰3‰,ƒ$™$c™*J<‰$‰*ƒ$™&h™3@™,J<‰&‰3‰,4™$U™/c<‰$‰/4™-c™.M<‰-‰.4™$U™+c<‰$‰+4™1U™$c™,M<‰1‰$‰,…™$J<‰$4™&h™,J™7;<‰&‰,‰7ƒ$™*J<‰*4™$c<‰$4™,J™7M<‰,‰7ƒ$™$c™*J<‰$‰*ƒ$™&h™,J™7;<‰&‰,‰7ƒ$™*J<‰*ƒ$™$c™,J™1U<‰$‰,‰1ƒ$™*J<‰*ƒ$™&h™,J™7;<‰&‰,‰7ƒ$™*J<‰*4™$c<‰$4™,J™7M<‰,‰7ƒ$™$c™*J<‰$‰*ƒ$™&h™,J™7;<‰&‰,‰7ƒ$™.M<‰.4™$U<‰$4™$c™1U<‰$‰1ƒ$™*J<‰*ƒ$™&h™,J™7G<‰&‰,‰7ƒ$™*J™$c<‰*‰$ƒ$™,J™1U<‰,‰1ƒ$™*J™$c<‰*‰$ƒ$™&h™,J™7R<‰&‰,‰7ƒ$™.J<‰.4™$U<‰$4™$c™1U™,J<‰$‰1‰,…™$U<‰$4™&h™,J<‰&‰,…™$U<‰$4™$c™7c™,J<‰$‰7‰,ƒ$™$U<‰$ƒ$™&s<‰&4™/c<‰/4™-c<‰-4™+c<‰+4™1n<‰1ÿ/MTrk>ÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ʺ @ºº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------‡Îhÿ/simutrans-124.3/simutrans/music/51-Summer-Intersection.mid000066400000000000000000001567721474050137200235740ustar00rootroot00000000000000MThd ÀMTrkÿÿQö ÿXÿ/MTrk?ÿdrÿ!¹¹ ɹdž™$d™1d™,dp‰$‰1‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dƒ`‰3™,dp‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dƒ`‰3™,dp‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dp™6p‰3‰6™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.™$d™&dp™*dp‰$‰&‰*p™3d™&d™$dp™,dp‰3‰&‰$‰,™,dp‰,™*dp‰*™.dp‰.p™*dp‰*™3dp™$d™6p‰3‰$‰6™,dp‰,™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6p‰.‰6p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™$d™3dp‰5‰$™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&dp‰*‰&™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*‰$‰&™3dp™5d™$dp‰3‰5‰$™,d™&dp‰,‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6™$dp‰.‰6‰$p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™6™3dp‰5‰6™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&d™1p‰*‰&‰1™.d™5d™$dp‰.‰5‰$™6p‰6™*d™$d™&d™12p‰*‰$‰&™&d™3dp‰1‰&™5d™$dp‰3‰5‰$™,d™&dp‰,‰&™,d™$d™1dp‰,™*dp‰$‰1‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&™1p‰3‰1™,dp‰,™,d™$dp‰,™*dp‰$‰*™.d™1#™&dp‰.‰1p‰&™*d™$dp‰*™1(™&dp‰$‰1™3dp‰&™,dp‰3‰,™,d™&d™12™$dp‰,‰&‰1™*d™&dp‰$‰*‰&™.d™&dp‰.‰&™1d™&d™'dp‰1‰&‰'‡@™,d™1d™$dp‰,‰1™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3d™'dp™,d™&dp‰3‰'‰,‰&™,dp‰,™,d™*dp‰,‰*™.d™&dp‰.‰&™,dp‰,™*dp‰*™,dp‰,™'d™6™3dp‰'‰6p‰3™,d™5d™1d™$dp‰,‰5‰1™*dp‰$‰*™.d™6p‰.‰6p™*d™5d™&d™$dp‰*‰5p‰&‰$™5d™3dp‰5™,dp‰3‰,™,d™6™$dp‰,‰6™*dp‰$‰*™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.d™,d™&dp‰6‰.‰,p‰&™5d™*d™$dp‰5‰*™,d™&dp‰$‰,‰&™5d™3dp‰5™,dp‰3‰,™6™1™&d™-d™,dp‰6‰1‰&‰-‰,™,d™$d™1dp‰,™*dp‰*‰$™.dp‰.p™*d™&d™$dp‰1‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$d™&dp‰,™*dp‰$‰&‰*™.dp‰.™&d™$dp‰&™*dp‰$‰*™3dp™$d™&dp‰3‰$‰&™,dp‰,™,dp‰,™*dp‰*™.d™'dp‰.‰'p™*d™$dp‰*‰$p™$d™3d™&dp‰$™,dp‰3‰&‰,™,dp‰,™*dp‰*™.d™'dp‰.‰'p™*d™$dp‰*‰$™3dp™$d™&dp‰3‰$™,dp‰&‰,™,dp‰,™*dp‰*™.d™&d™'dp‰.‰&‰'p™*d™$d™&dp‰*p‰$‰&™&d™3dp‰&™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.d™&dp‰.‰&p™*d™&d™$dp‰*‰&™&d™3dp‰$‰&p‰3™,d™&dp‰,‰&™,d™$d™5dp‰,‰$‰5™*dp‰*™.d™6p‰.‰6p™*d™5d™&d™$dp‰*‰5‰&‰$p™$d™5d™3dp‰$‰5™,dp‰3‰,™,d™$d™6p‰,‰$‰6™*d™&dp‰*‰&™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*‰$‰&™3dp™$d™5dp‰3‰$‰5™,d™&dp‰,‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6™$dp‰.‰6‰$p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™6™3dp‰5‰6™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&d™1p‰*‰&‰1™.d™5d™$dp‰.‰5‰$™6p‰6™*d™$d™&d™12p‰*‰$‰&™&d™3dp‰1‰&™5d™$dp‰3‰5‰$™,d™&dp‰,‰&™,d™1d™$dp‰,‰1™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*™3dp‰$‰&p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™$d™&dp‰*p‰$‰&™3d™'dp™,d™&dp‰3‰'‰,‰&™,dp‰,™,d™*dp‰,‰*™.d™&dp‰.‰&™,dp‰,™*dp‰*™,dp‰,™'d™6™3dp‰'‰6p‰3™,d™5d™1d™$dp‰,‰5‰1™*dp‰$‰*™.d™6p‰.‰6p™*d™5d™&d™$dp‰*‰5p‰&‰$™5d™3dp‰5™,dp‰3‰,™,d™6™$dp‰,‰6™*dp‰$‰*™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.d™,d™&dp‰6‰.‰,p‰&™5d™*d™$dp‰5‰*™,d™&dp‰$‰,‰&™5d™3dp‰5™,dp‰3‰,™6™1™&d™-d™,dp‰6‰1‰&‰-‰,…P™&d™,dp‰&‰,™$d™.dp‰$‰.™$d™&d™3dp‰$‰&‰3™,dp‰,™,d™$d™1dp‰,™*dp‰*‰$™.dp‰.p™*d™$d™&dp‰1‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.d™'dp‰.‰'p™*d™$d™&dp‰*™$d™3dp‰$‰&‰$™6™'dp‰3‰6‰'™,dp‰,™,d™5d™1d™$dp‰,‰5‰1™*dp‰$‰*™.d™6p‰.‰6p™*d™5d™&d™$dp‰*‰5p‰&‰$™5d™3dp‰5™,dp‰3‰,™,d™6™$dp‰,‰6™*dp‰$‰*™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.dp‰6‰.p™5d™*d™$d™&dp‰5‰*p‰$‰&™5d™3dp‰5™,dp‰3‰,™6™,d™$dp‰6‰,™*dp‰$‰*™5d™.dp‰5‰.™6p‰6™*d™$d™&dp‰*™3dp‰$‰&™5dp‰3‰5™,dp‰,™5d™,d™$dp‰5‰,™*dp‰$‰*™6™.d™,d™&dp‰6‰.‰,p‰&™5d™*d™$dp‰5‰*™,d™&dp‰$‰,‰&™5d™3dp‰5™,dp‰3‰,™6™&d™-d™'d™,d™1p‰6‰&‰-‰'‰,‰1™,d™$d™1dp‰,™*dp‰*‰$™.dp‰.p™*d™$d™&dp‰1‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$d™1dp‰,™*dp‰*‰$™.dp‰.p™*d™$d™&dp‰1‰*p‰$‰&™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*™3dp‰&‰$p‰3™,dp‰,™,d™$dp‰,™*dp‰$‰*™.dp‰.p™*d™&d™$dp‰*p‰&‰$™3dp™,dp‰3‰,™,d™&d™$dp‰,™*dp‰&‰$‰*™.dp‰.™&d™$dp‰&™*dp‰$‰*™3dp™&d™$dp‰3‰&‰$™,dp‰,™,dp‰,™*dp‰*™.d™'dp‰.‰'p™*d™$dp‰*‰$p™$d™3d™&dp‰$™,dp‰3‰&‰,™,dp‰,™*dp‰*™.d™'dp‰.‰'p™*d™$dp‰*‰$™3dp™$d™&dp‰3‰$™,dp‰&‰,™,dp‰,™*dp‰*™.d™&d™'dp‰.‰&‰'p™*d™$d™&dp‰*p‰$‰&™&d™3dp‰&™,dp‰3‰,™,d™$dp‰,™*dp‰$‰*™.d™&dp‰.‰&p™*d™&d™$dp‰*‰&™&d™3dp‰$‰&p‰3™,d™&dp‰,‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6p‰.‰6p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™$d™3dp‰5‰$™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&dp‰*‰&™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*‰$‰&™3dp™5d™$dp‰3‰5‰$™&dp‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6p‰.‰6p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™$d™3dp‰5‰$™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&dp‰*‰&™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*‰$‰&™3dp™5d™$dp‰3‰5‰$™&dp‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6p‰.‰6p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™$d™3dp‰5‰$™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&dp‰*‰&™.d™5dp‰.‰5™6p‰6™*d™$d™&dp‰*‰$‰&™3dp™5d™$dp‰3‰5‰$™,d™&dp‰,‰&™,d™5d™$dp‰,‰5‰$™*dp‰*™.d™6™$dp‰.‰6‰$p™*d™&d™$d™5dp‰*‰&‰$‰5p™5d™6™3dp‰5‰6™,dp‰3‰,™,d™6™$dp‰,‰6‰$™*d™&d™1p‰*‰&‰1™.d™5d™$dp‰.‰5‰$™6p‰6™*d™$d™&d™12p‰*‰$‰&™&d™3dp‰1‰&™5d™$dp‰3‰5‰$™,d™&dp‰,‰&™$d™1d™,dp‰$‰1‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dƒ`‰3™,dp‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dƒ`‰3™,dp‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*p™3dp™,dp‰3‰,™$d™,dp‰$‰,™*dp‰*™.dp‰.p™*dp‰*™3dƒ`‰3™,dp‰,™*d™$dp‰*p‰$p™,d™$dp‰,p‰$p™3d™.d™$dp‰3‰.p‰$Ëÿ/MTrk1‚ÿ chodpianoÿ!À°f° @žEd=d@dDdƒ`€E€=€@€DpEd=d@dDdƒ`€E€=€@€DpDdGd=d@d„Z€D€G€=€@‚fGd@d=dDd‰0€G€@€=€DpBd=d>dEdƒ`€B€=€>€EpEd=d>dBdƒ`€E€=€>€BpGg>g@gEg„I€G€>€@€E‚wGd>d@dDd‰0€G€>€@€Dp=dEdDd@dƒ`€=€E€D€@pEd=d@dDdƒ`€E€=€@€DpDdGd=d@dƒ`€D€G€=€@ƒ`Bd?dGdEd‰0€B€?€G€EpEd=d>dBdƒ`€E€=€>€Bp=dDdBd@dƒ`€=€D€B€@pAdFdBd=dp€A€F€B€=pGdd‹ €;€B€G€>ƒ`@dEddEdBdp€<€>€E€Bƒ`;dBdGd>d…P€;€B€G€>pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep@dBd=dƒ`€@€B€=p=d?dDd…P€=€?€DpDd9d@d?dp€D€9€@€?pBd?d;dp€B€?€;pDd@d;dƒ`€D€@€;ƒ`Dd@d;dp€D€@€;p=d@dEdƒ`€=€@€Eƒ`Dd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;p;d?dBd…P€;€?€Bp;dDd@d…P€;€D€@pEd?dBdƒ`€E€?€Bp=dBdEdƒ`€=€B€Ep=d@dDd‰0€=€@€Dp=dEd@d…P€=€E€@p8dp€8;d@dDdp€;€@€DpBd?d;dp€B€?€;ƒ`Bd?d;dp€B€?€;pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep@dBd=dƒ`€@€B€=p=d?dDd…P€=€?€DpDd9d@d?dp€D€9€@€?pBd?d;dp€B€?€;pDd@d;dƒ`€D€@€;ƒ`Dd@d;dp€D€@€;p=d@dEdƒ`€=€@€Eƒ`Dd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;p;d?dBd…P€;€?€Bp;dDd@d…P€;€D€@pEd?dBdƒ`€E€?€Bp=dBdEdƒ`€=€B€Ep=d@dDd‰0€=€@€Dp=dEd@d…P€=€E€@p8dp€8Dd@d;dƒ`€D€@€;p;d?dBdp€;€?€BpBd?d;dp€B€?€;pDd9d=d@d…P€D€9€=€@pBd=d9d?d…P€B€=€9€?pEd;d?dBdp€E€;€?€B…PEd?d;dBdp€E€?€;€BpEd@d;dBdp€E€@€;€Bp?d@dDd;dƒ`€?€@€D€;p;dDd@dƒ`€;€D€@p=dAdDd;dp€=€A€D€;p=dDdAd;d‹ €=€D€A€;ƒ`Fd;d?dBd…P€F€;€?€BpDd?d;dAd…P€D€?€;€ApGd=dAdDdp€G€=€A€D…PGdAd=dDdp€G€A€=€DpGdBd=dDdp€G€B€=€Dp?dAdDdGd‰0€?€A€D€Gp;dFdBd?dp€;€F€B€?pAd=dBdFd…P€A€=€B€Fp=dFdCd?d…P€=p€F€C€?:dEdAd>dƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:p7d:dp€7€:p:dCd?dƒ`€:€C€?pCdEd:d?dp€C€E€:€?ƒ`9dEdAd>dƒ`€9€E€A€>pEd9d>dAdp€E€9€>€Aƒ`FdAd>d9dp€F€A€>€9pAdFd>d:dCdp€Ap€F€>€:€Cp:d>dFdCdp€:€>€F€Cƒ`:d>dEdCdp€:€>€E€Cp9dp€9@dEddƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:pHdd9dEdCdƒ`€>€9€E€Cp:dFdCd>dp€:€F€C€>ƒ`CddAdƒ`€E€9€>€ApFd9d>dAdp€F€9€>€Aƒ`d€<€E€Ap:d>dAdFdp€:€>€A€Fƒ`d‹ €;€B€G€>ƒ`@dEddEdBdp€<€>€E€Bƒ`;dBdGd>d…P€;€B€G€>pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;pDd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep@dBd=dƒ`€@€B€=p=d?dDd…P€=€?€DpDd9d@d?dp€D€9€@€?pBd?d;dp€B€?€;pDd@d;dƒ`€D€@€;ƒ`Dd@d;dp€D€@€;p=d@dEdƒ`€=€@€Eƒ`Dd@d=dƒ`€D€@€=ƒ`Dd?d;dƒ`€D€?€;ƒ`=d@dEdƒ`€=€@€Ep?dBd;dƒ`€?€B€;p=d@dDd…P€=€@€Dp=d@dDdp€=€@€Dp=d@dBdp€=€@€B=d@dDdp€=€@€Dp=dƒ`€=Dd@d=dp€D€@€=p=dDd@dp€=€D€@=dBdEdp€=€B€Ep?dDd;dp€?€D€;p;d?dBd…P€;€?€Bp;dDd@d…P€;€D€@pEd?dBdƒ`€E€?€Bp=dBdEdƒ`€=€B€Ep=d@dDd‰0€=€@€Dp=dEd@d…P€=€E€@p8dp€8Dd@d;dƒ`€D€@€;p;d?dBdp€;€?€BpBd?d;dp€B€?€;pDd9d=d@d…P€D€9€=€@pBd=d9d?d…P€B€=€9€?pEd;d?dBdp€E€;€?€B…PEd?d;dBdp€E€?€;€BpEd@d;dBdp€E€@€;€Bp?d@dDd;dƒ`€?€@€D€;p;dDd@dƒ`€;€D€@p=dAdDd;dp€=€A€D€;p=dDdAd;d‹ €=€D€A€;ƒ`Fd;d?dBd…P€F€;€?€BpDd?d;dAd…P€D€?€;€ApGd=dAdDdp€G€=€A€D…PGdAd=dDdp€G€A€=€DpGdBd=dDdp€G€B€=€Dp?dAdDdGd‰0€?€A€D€Gp;dFdBd?dp€;€F€B€?pAd=dBdFd…P€A€=€B€Fp=d?dCdFd…P€=€?€C€FpDd?dAdHdƒ`€D€?€A€HpDd?dAdHdƒ`€D€?€A€HpId?dFdCd€I€?€F€Cƒ`dFdAdƒ`€D€>€F€Aƒ`Ad>dFdDdƒ`€A€>€F€Dƒ`Id?dFdCdƒ`€I€?€F€CpId?dFdCdƒ`€I€?€F€CpHdCd?dDdp€H€C€?€DpDdHddAdp€:€E€>€Aƒ`:dEdAd>dp€:€E€A€>p:dAdEd>dp€:€A€E€>pDd9d=d@d…P€D€9€=€@pBd=d9d?d…P€B€=€9€?pEd;d?dBdp€E€;€?€B…PEd?d;dBdp€E€?€;€BpEd@d;dBdp€E€@€;€Bp?d@dDd;dƒ`€?€@€D€;p;dDd@dƒ`€;€D€@p=dAdDd;dp€=€A€D€;p=dDdAd;d‹ €=€D€A€;ƒ`Fd;d?dBd…P€F€;€?€BpDd?d;dAd…P€D€?€;€ApGd=dAdDdp€G€=€A€D…PGdAd=dDdp€G€A€=€DpGdBd=dDdp€G€B€=€Dp?dAdDdGd‰0€?€A€D€Gp;dFdBd?dp€;€F€B€?pAd=dBdFd…P€A€=€B€Fp=d?dCdFd…P€=€?€C€Fp:dEdAd>dƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:p7d:dp€7€:p:dCd?dƒ`€:€C€?pCdEd:d?dp€C€E€:€?ƒ`9dEdAd>dƒ`€9€E€A€>pEd9d>dAdp€E€9€>€Aƒ`FdAd>d9dp€F€A€>€9pAdFd>d:dCdp€Ap€F€>€:€Cp:d>dFdCdp€:€>€F€Cƒ`:d>dEdCdp€:€>€E€Cp9dp€9@dEddƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:pHdd9dEdCdƒ`€>€9€E€Cp:dFdCd>dp€:€F€C€>ƒ`dƒ`€9€F€A€>pHdCd?ddHdEdAdƒ`€>€H€E€Aƒ`HdEdAd>d…P€H€E€A€>p>dHdEdAdp€>€H€E€Ap:dEdAd>dƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:p7d:dp€7€:p:dCd?dƒ`€:€C€?pCdEd:d?dp€C€E€:€?ƒ`9dEdAd>dƒ`€9€E€A€>pEd9d>dAdp€E€9€>€Aƒ`FdAd>d9dp€F€A€>€9pAdFd>d:dCdp€Ap€F€>€:€Cp:d>dFdCdp€:€>€F€Cƒ`:d>dEdCdp€:€>€E€Cp9dp€9@dEddƒ`€:€E€A€>pAd:d>dEdp€A€:€>€Eƒ`d:dp€F€A€>€:ƒ`:dFd>dAdp€:€F€>€Aƒ`Fd>dCd:dƒ`€F€>€C€:pFdCd>d:dp€F€C€>€:pEdCd>d:dp€E€C€>€:pHdd9dEdCdƒ`€>€9€E€Cp:dFdCd>dp€:€F€C€>ƒ`CddAdƒ`€E€9€>€ApFd9d>dAdp€F€9€>€Aƒ`d€<€E€Ap:d>dAdFdp€:€>€A€Fƒ`d‹ €;€B€G€>ƒ`@dEdd€<€B€Ep@dGdd‹ €;€B€G€>ƒ`@dEddEdBdp€<€>€E€Bƒ`;dBdGd>d…P€;€B€G€>ÛpEd=d>dBdƒ`€E€=€>€Bp=dDdBd@dƒ`€=€D€B€@pAdFdBd=dp€A€F€B€=½pÿ/MTrkÇÿbassÿ!Á'±nž‘-dp-p‘-dp-‘,dp,p‘,dp,‘*dp*p‘*dp*ƒ`‘,dp,ƒ`‘*d…P*p‘*dp*‘(dp(p‘%dp%‘&dp&p‘(dp(ƒ`‘&dp&ƒ`‘*dp*‘,dp,‘-dp-p‘-dp-‘,dp,p‘,dp,‘*dp*p‘*dp*p‘'dp'‘-dp-ƒ`‘/dp/p‘-dp-p‘&dp&‘*dp*p‘%dp%‘*dƒ`*p‘*dp*‘%dp%p‘*dp*p‘*dp*‘%dp%‘$dp$p‘&dp&‘(dp(p‘$dp$‘+dp+p‘#dp#‘&dp&p‘#dp#‘*dp*‘#dp#p‘#dp#‘!dp!p‘#dp#‘$dp$p‘$dp$‘-dp-‘(dp(‘#dp#‘*dƒ`*‘/dp/‘-dp-‘&dp&p‘!dp!‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*dƒ`*p‘%d…P%p‘'dp'p‘*dp*p‘(d…P(p‘/dp/p‘-dp-‘,dp,‘(dp(p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘#dp#p‘*dp*p‘(dp(p‘,dp,p‘-dp-‘'dp'p‘*dp*ƒ`‘,d…P,p‘*dp*p‘(dp(p‘,dp,p‘(dp(‘/dp/p‘/dp/‡@‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*dƒ`*p‘%d…P%p‘'dp'p‘*dp*p‘(d…P(p‘/dp/p‘-dp-‘,dp,‘(dp(p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘#dp#p‘*dp*p‘(dp(p‘,dp,p‘-dp-‘'dp'p‘*dp*ƒ`‘,d…P,p‘*dp*p‘(dp(p‘,dp,p‘/dp/‘-dp-‘,dp,‘(dp(‘-dp-‘*dp*‘#dp#‘dp‘!dp!p‘-dp-p‘*dp*p‘-dp-p‘#dp#p‘(dp(‘*dp*ƒ`‘-dp-p‘(dp(p‘(dp(p‘,dp,p‘#dp#p‘%dp%‘,dp,p‘%dp%ƒ`‘'dp'p‘#dp#p‘/dp/p‘,dp,p‘/dp/p‘%dp%p‘*dp*‘,dp,ƒ`‘/dp/p‘*dp*p‘*dp*p‘.dp.p‘'dp'p‘*d…P*‰0‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘+dp+p‘+dp+p‘2dp2p‘+dp+p‘(dp(‘4dp4p‘-dp-ƒ`‘$dp$p‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘'dp'p‘'dp'p‘0dp0p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)‘+dp+‘.dp.p‘5dp5p‘+dp+p‘3dp3p‘&dp&p‘-dp-‘.dp.ƒ`‘0d0p‘'d'p‘,d…P,p‘0dp0p‘+dp+p‘*d…P*p‘.dp.p‘,dp,‘.dp.p‘%dp%‘$dp$p‘&dp&‘(dp(p‘$dp$‘+dp+p‘#dp#‘&dp&p‘#dp#‘*dp*‘#dp#p‘#dp#‘!dp!p‘#dp#‘$dp$p‘$dp$‘-dp-‘(dp(‘#dp#‘*dƒ`*‘/dp/‘-dp-‘&dp&p‘!dp!‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*dƒ`*p‘%d…P%p‘'dp'p‘*dp*p‘(d…P(p‘/dp/p‘-dp-‘,dp,‘(dp(p‘%dp%p‘,dp,p‘ dp p‘,dp,p‘!dp!p‘#dp#‘*d„f*j‘%d…P%p‘,dp,p‘*dp*‘(dp(p‘%dƒ`%p‘,dp,p‘*dp*p‘/dp/p‘#dp#p‘*dp*p‘(dp(p‘,dp,p‘-dp-‘'dp'p‘*dp*ƒ`‘,d…P,p‘*dp*p‘(dp(p‘,dp,p‘/dp/‘-dp-‘,dp,‘(dp(‘-dp-‘*dp*‘#dp#‘dp‘!dp!p‘-dp-p‘*dp*p‘-dp-p‘#dp#p‘(dp(‘*dp*ƒ`‘-dp-p‘(dp(p‘(dp(p‘,dp,p‘#dp#p‘%dp%‘,dp,p‘%dp%ƒ`‘'dp'p‘#dp#p‘/dp/p‘,dp,p‘/dp/p‘%dp%p‘*dp*‘,dp,ƒ`‘/dp/p‘*dp*p‘*dp*p‘.dp.p‘'dp'p‘*d‚d*„\‘-dp-‘,dp,‘+dp+‘*dp*‘)dp)p‘5dp5p‘3dp3p‘5dp5p‘'dp'p‘,dp,‘.dp.ƒ`‘1dp1p‘,dp,p‘,dp,p‘0dp0p‘'dp'p‘)dp)‘0dp0p‘)dp)ƒ`‘+dp+p‘%dp%p‘1dp1p‘,dp,p‘0dp0p‘"dp"p‘&dp&‘)dp)ƒ`‘,dp,p‘'dp'p‘.dp.p‘3dp3p‘+dp+p‘,dp,‘0dp0p‘)dp)p‘'dp'p‘$dp$‘)dp)p‘5dp5p‘3dp3p‘5dp5p‘'dp'p‘,dp,‘.dp.ƒ`‘1dp1p‘,dp,p‘,dp,p‘0dp0p‘'dp'p‘)dp)‘0dp0p‘)dp)ƒ`‘+dp+p‘%dp%p‘1dp1p‘,dp,p‘0dp0p‘$dp$p‘(dp(‘)dp)ƒ`‘.dp.p‘#dp#p‘/dp/p‘*dp*p‘.dp.p‘,dp,‘)dp)p‘.dp.‘,dp,‘&dp&p‘"dp"‘!dp!p‘-dp-p‘*dp*p‘-dp-p‘#dp#p‘(dp(‘*dp*ƒ`‘-dp-p‘(dp(p‘(dp(p‘,dp,p‘#dp#p‘%dp%‘,dp,p‘%dp%ƒ`‘'dp'p‘#dp#p‘/dp/p‘,dp,p‘/dp/p‘%dp%p‘*dp*‘,dp,ƒ`‘/dp/p‘*dp*p‘*dp*p‘.dp.p‘'dp'p‘*d…P*‰0‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘+dp+p‘+dp+p‘2dp2p‘+dp+p‘(dp(‘4dp4p‘-dp-ƒ`‘$dp$p‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘'dp'p‘'dp'p‘0dp0p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)‘+dp+‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘+dp+p‘+dp+p‘2dp2p‘+dp+p‘(dp(‘4dp4p‘-dp-ƒ`‘$dp$p‘"dp"p‘.dp.p‘!dp!p‘$dƒ`$p‘$dp$‘"dp"p‘)dp)p‘!dp!p‘&dp&p‘+dp+p‘&dp&p‘.dp.p‘)dp)‘+dp+p‘&dp&ƒ`‘"dp"p‘'dp'p‘'dp'p‘.dp.p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)p‘'dp'p‘'dp'p‘0dp0p‘'dp'p‘&dp&‘2dp2p‘-dp-ƒ`‘)dp)‘+dp+‘.dp.p‘5dp5p‘+dp+p‘3dp3p‘&dp&p‘-dp-‘.dp.ƒ`‘0d0p‘'d'p‘,d…P,p‘0dp0p‘+dp+p‘*d…P*p‘.dp.p‘,dp,‘.dp.p‘%dp%‘$dp$p‘&dp&‘(dp(p‘$dp$‘+dp+p‘#dp#‘&dp&p‘#dp#‘*dp*‘#dp#p‘#dp#‘!dp!p‘#dp#‘$dp$p‘$dp$‘-dp-‘(dp(‘#dp#‘*dƒ`*‘/dp/‘-dp-‘&dp&p‘!dp!‘$dp$p‘&dp&‘(dp(p‘$dp$‘+dp+p‘#dp#‘&dp&p‘#dp#‘*dp*‘#dp#p‘#dp#‘!dp!p‘#dp#‘$dp$p‘$dp$‘-dp-‘(dp(‘#dp#‘*dƒ`*‘/dp/‘-dp-‘&dp&p‘!dp!´ÿ/MTrk’ÿguitarÿ!²nŒŽ²â@<’?d‚h‚?x’Adx‚Ax’Ddx‚Dx²’Fdp‚F²’Hdp² p² p²’Idp‚H²p²p²’Up²#ƒ`‚Ip²’Fdx‚Ux‚Fp’Kd‚h‚Kx’Fdx‚Fx’Cdx‚Cx’Dd„X‚Dx’Fdƒ`²x‚Fx²’Hdp²!p²+p²;p²I„X‚H‚,â@<²’Ddx‚Dx’Fdx‚Fx²’Idp²*p²-‚h‚Ix²’Fdp²ƒ`²x‚FZ’Jd²#’Kd<‚J4²Ep²Qp²j‚K’Dd’8cx‚D‚8x’Dd’8cx‚D‚8x’Fdx‚Fx’Hdx‚Hx’Id‚h‚Ix’Hd‚h‚Hx’Fd‚h‚Fx’Cd‚h‚Cx’Ddx‚Dx’Cd‚h‚Cx’Acp² p²p²„X‚Ax²p’?dx‚?x’Adx‚Ax’Cd‚h‚Cx’Ddx‚Dx’Fd„X‚Fx’Cd‚h‚Cx’Ad‚h‚Ax’Cd‚h‚Cx² ’Adƒ`² x‚Ax²’?dƒ`²'p²*p²-p²4p²;p²Bp²Ep²M†H‚?x²ƒ`’?dx‚?x’Adx‚Ax’Cd‚h‚Cx’Ddx‚Dx’Fd„X‚Fx’Cd‚h‚Cx’Ad‚h‚Ax’Dd‚h‚Dx’:d’Fd<‚:‚,‚Fx’8d’Dd<‚8<‚Dx’Fd’:d‚Fv‚:x’Fd’:dx‚F‚:x’Id4‚I<’Gdƒ$‚G<’Ed…‚E<’Fdƒ$‚F<’Fd4‚F<’Hdƒ$‚H<²’Idp²(p²+p²4p²;p²>p²E…P²4‚I<’Kdƒ$‚K<’Idƒ$‚I<’Edƒ$‚E<’Gd…‚G<’Idƒ`²4‚I<²’Gdp² p²#p²(‡‚G<²p’Id4‚I<’Gd4‚G<’Fd‚h‚Fx’Fd4‚F<’Hd…‚H<’Id4‚I‚,’=d’Id<‚=x‚I<’;d’Gdp‚;4‚G<’Dd4‚D<’;d’Gd<‚;x‚G<’:d’Fdp‚:4‚F<’Bd4‚B<’Dd‡‚D<’Ad4‚A<’Dd4‚D<’Fd4‚F<’Gd4‚G<²’Idp²#p²5’U#p²@p²Lp²Q4‚I‚,‚U²†çpÿ/MTrkaÿhitÿ!³ jÃ7³Z³ jø“9d“Edpƒ9ƒEƒ`“8d“Ddpƒ8ƒDƒ`“:d“FdŠ(ƒ:xƒF‡@“CdpƒC…P“CdpƒCp“CdxƒCx“CdpƒCp“BdpƒBƒ`“BdpƒBp“BdxƒBx“BdpƒB“@dpƒ@…P“@dpƒ@p“@dxƒ@x“@dpƒ@p“9d“Edpƒ9ƒEƒ`“Gd“;d…PƒGƒ;âp“Ed“9dƒ`ƒEƒ9p“Ed“9dpƒEƒ9æP“Dd“8d‚hƒDƒ8x“Dd“8dxƒDƒ8x“Dd“8dxƒDƒ8x“Dd“8dxƒDƒ8ˆ8“Ed“9d…PƒExƒ9דGd“;dƒ`ƒGƒ;p“:d“Fdƒ`ƒ:ƒFp“Fd“:dƒ`ƒFƒ:‹ “:d“Fdƒ`ƒ:ƒFp“Jd“>dpƒJƒ>ð@“:d“Fd‚ƒ:ƒF‚Q“Jd“>dpƒJƒ>ÿ@“Jd“>dpƒJƒ>ƒ`“Kd“?dpƒKƒ?ƒ`“Md“Adƒ`ƒMƒA¼“CdpƒC…P“CdpƒCp“CdxƒCx“CdpƒCp“BdpƒBƒ`“BdpƒBp“BdxƒBx“BdpƒB“@dpƒ@…P“@dpƒ@p“@dxƒ@x“@dpƒ@p“9d“Edpƒ9ƒEƒ`“Gd“;d…PƒGƒ;á“Dd“8d‚hƒDƒ8x“Dd“8dxƒDƒ8x“Dd“8dxƒDƒ8x“Dd“8dxƒDƒ8ˆ8“Ed“9d…PƒExƒ9דGd“;dƒ`ƒGƒ;p“:d“Fdƒ`ƒ:ƒFp“Fd“:dƒ`ƒFƒ:‚Ù“Gd“;dƒ`ƒGƒ;p“:d“Fdƒ`ƒ:ƒFp“Fd“:dƒ`ƒFƒ:‹ “:d“Fdƒ`ƒ:ƒFp“Jd“>dpƒJƒ>ð@“:d“Fd‚ƒ:ƒF‚Q“Jd“>dpƒJƒ>ð@“:d“Fdƒ`ƒ:ƒFp“Jd“>dpƒJƒ>ð@“:d“Fd‚ƒ:ƒF‚Q“Jd“>dpƒJƒ>ÿ@“Jd“>dpƒJƒ>ƒ`“Kd“?dpƒKƒ?ƒ`“Md“Adƒ`ƒMƒA¼“CdpƒC…P“CdpƒCp“CdxƒCx“CdpƒCp“BdpƒBƒ`“BdpƒBp“BdxƒBx“BdpƒB“@dpƒ@…P“@dpƒ@p“@dxƒ@x“@dpƒ@p“EdpƒEƒ`“EdxƒEx“EdxƒEx“EdpƒEp“CdpƒC…P“CdpƒCp“CdxƒCx“CdpƒCp“BdpƒBƒ`“BdpƒBp“BdxƒBx“BdpƒB“@dpƒ@…P“@dpƒ@p“@dxƒ@x“@dpƒ@p“9d“Edpƒ9ƒEƒ`“Gd“;d…PƒGƒ;µpÿ/MTrk †ÿsignleadÿ!´´ Ä>´n´Õ$”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„Bp”Bd† „Bx”F<„F”Gdƒ`„G”Dd‹ „D”Gdƒ`„G”Bdƒ`„B”Edƒ`„E”Dd‡@„D”Bd‡@„B”@d…„@”A<„A”Bdƒ`„Bp”?dŽ„?”@2<„@”B2<„B”Dd‹ „DŠd”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„Bp”Bd† „B<”E<„E”F<„F”Gdƒ`„G”Dd”Dd‹ „D„D”Bdƒ`„B”@dƒ`„@”Edƒ`„E”Bd‡@„B”@d‡@„@”?d…P„?”@dƒ`„@4”<<„<”=dƒ`„=ƒ`”;dp„;ƒ`”=dp„=ƒ`”=Wp„=”;Mp„;”9Fp„9”?;p„?p”;+p„;”Bp„B”?p„?ƒ$”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„B4”D<„D”Bd† „B<”E<„E”F<„F”Gdƒ`„G”Dd‹ „D”Gdƒ`„G”Bdƒ`„B”Edƒ`„E”Dd‡@„D”Bd‡@„B”@d…”A<„@„A”Bdƒ`„Bp”?dŽ„?”A<„A”B<„B”Dd‹ „DŠd”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„B4”D<„D”Bd† „Bx”F<„F”Gdƒ`„G”Dd‹ „D”Edp„E”Bdp„B”Ddp„D”@dp„@”9dp„9”=dp„=”Bd‡@„B”@d‡@„@”?d…P„?”@dƒ`„@4”?<”=d<„?ŽD„=‹ ”-p„-”;dp„;”=dp„=”?dp„?”@d‡@„@”=d‡@„=”9d‡@„9”?dƒ`„?”@dƒ`„@”?d‹ „?”=dƒ`„=”=d‡@„=ƒ`”=dp„=”?dp„?”Bd‡@„B”?d‡@„?”Dd…P„Dp”Bd…P„Bp”Adƒ`„Ap”Bd„X„Bx”Dd4„D<”Ddp„D”Fd…P„F…P”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Fdƒ`„Fp”Fd‡@„F‡@”Fdp„F”Edp„E”Cd„f„C‚Z”Ed…P„Ep”Adƒ`„Ap”Hdƒ`„Hp”Fdp„Fp”Fd‰0„Fp”Edp„Ep”Edˆ6„E‚j”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Jdƒ`„Jp”Fd‹ „Fƒ`”Edp„E”Fdp„F”Hd…P„Hp”Fd…P„Fp”Edƒ`„Ep”Fdƒ`„Fp”Hd…P„Hp”Hd‚h„Hx”Fdƒ`„F”?dp„?p”Edƒ`„Ep”Fdƒ`„Fp”Hd…P„Hp”Hd‚h„Hx”Fd‚x„Fh”Fdp„Fp”Edƒ`„ER”E”Fd<„Eƒ$„Fp”Cd’`„Cì$”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„B4”D<„D”Bd† „B<”E<„E”F<„F”Gdƒ`„G”Dd‹ „D”Gdƒ`„G”Bdƒ`„B”Edƒ`„E”Dd‡@„D”Bd‡@„B”@d…”A<„@„A”Bdƒ`„Bp”?dŽ„?”A<„A”B<„B”Dd‹ „DŠd”B2<„B”Ddƒ`„D”Bd‡@„B”@d…P„@”Bdƒ`„B4”D<„D”Bd† „Bx”F<„F”Gdƒ`„G”Dd‹ „D”Edp„E”Bdp„B”Ddp„D”@dp„@”9dp„9”=dp„=”Bd‡@„B”@d‡@„@”?d…P„?”@dƒ`„@4”?<”=d<„?ŽD„=‹ ”-p„-”;dp„;”=dp„=”?dp„?”@d‡@„@”=d‡@„=”9d‡@„9”?dƒ`„?”@dƒ`„@”?d‹ „?”=dƒ`„=”=d‡@„=ƒ`”=dp„=”?dp„?”Bd‡@„B”?d‡@„?”Dd…P„Dp”Bd…P„Bp”Adƒ`„Ap”Bd„X„Bx”Dd4„D<”Ddp„D”FdŽ„F‚å”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Fdƒ`„Fp”Fd‡@„F‡@”Fdp„F”Edp„E”Cd„f„C‚Z”Ed…P„Ep”Adƒ`„Ap”Hdƒ`„Hp”Fdp„Fp”Fd‰0„Fp”Edp„Ep”Edˆ6„E‚j”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Jdƒ`„Jp”Fd‹ „Fƒ`”Edp„E”Fdp„F”Hd…P„Hp”Fd…P„Fp”Edƒ`„E”Fdp„F”Ad…P„A”Hdƒ`„H”JdŠI„JW”Hd‚a„H”Hd‰0„Hp”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Fdƒ`„Fp”Fd‡@„F‡@”Fdp„F”Edp„E”Cd„f„C‚Z”Ed…P„Ep”Adƒ`„Ap”Hdƒ`„Hp”Fdp„Fp”Fd‰0„Fp”Edp„Ep”Edˆ6„E‚j”Adp„A”Cdp„C”Edp„Ep”Cdp„Cp”Adp„Ap”Hd…P„Hp”Fdp„Fp”Edp„Ep”Hdp„Hp”Hdƒ`„Hp”Jdƒ`„Jp”Fd‹ „Fƒ`”Edp„E”Fdp„F”Hd…P„Hp”Fd…P„Fp”Edƒ`„Ep”Fdƒ`„Fp”Hd…P„Hp”Hd‚h„Hx”Fdƒ`„F”?dp„?p”Edƒ`„Ep”Fdƒ`„Fp”Hd…P„Hp”Hd‚h„Hx”Fd‚x„Fh”Fdp„Fp”Edƒ`„ER”E”Fd<„Eƒ$„Fp”Cd’`„C‚Ùÿ/MTrkÿkiiinÿ!µ @Åpµdµ @–•kU•_2p…k…_…’•Q2•]dƒ`…Q…]ô •Q2•]Kp…Q…]Е_U•S#p…_…Sƒ¢•P2•\dp…P…\î•P#•\2p…P…\ö•Q2•]dƒ`…Q…]ô •Q2•]Kp…Q…]ö•Q2•]dƒ`…Q…]ô •Q2•]Kp…Q…]Е_U•S#p…_…Sö•Q#•]Up…Q…]²ÿ/MTrkCÿbell01ÿ!Æ ¶Zì`–Gdp†Gp–Idp†I…P–Jdp†Jƒ`–Ldp†Lƒ`–Ndp†Np–Sd–Gdp†S†G…P–Ld–@dp†L†@…P–Nd–Bdp†N†B…P–Jd–>dp†J†>…P–Hd–dp†J†>…P–Hd–dp†>p–Cdp†Cp–?dp†?p–Cdp†Cp–Fdp†Fp–Ddp†D…P–dp†J†>…P–Hd–dp†J†>…P–Hd–bp‡>—Ebp‡E—Jbp‡J—Fbp‡F—Mbp‡M—Rbp‡R—Tbp‡Tƒáp—Adp‡Ap—?dp‡?p—Adp‡Ap—Fdp‡Fp—Cdp‡C…P—?dp‡?p—Adp‡Ap—Cdp‡Cp—?dp‡?p—Cdp‡Cp—Fdp‡Fp—Ddp‡D…P—dp‡>p—Cdp‡Cp—?dp‡?p—Cdp‡Cp—Fdp‡Fp—Ddp‡D…P—Fp‡>p—EFp‡E…P—AFp‡Ap—AFp‡Ap—EFp‡Ep—EFp‡Eƒ`—CFp‡Cƒ`—CFp‡CÁP—Qcp‡Q—Mcp‡M—Hcp‡H—Ccp‡C—@cp‡@—Fp‡>p—EFp‡E…P—AFp‡Ap—AFp‡Ap—EFp‡Ep—EFp‡Eƒ`—FFp‡Fƒ`—CFp‡CÛp—>cp‡>—Ecp‡E—Jcp‡J—Fcp‡F—Mcp‡M—Rcp‡R—Tcp‡Tµp—@dƒ`‡@—Ddƒ`‡D—Gdƒ`‡G—Id‹ ‡Iƒ`—Idp‡I—Jdp‡J—Ndƒ`‡N—Ld…P‡Lp—Kd…P‡Kp—Gd…P‡Gp—Ddƒ`‡D—@dƒ`‡@—Ddƒ`‡D—Gdƒ`‡G—Id…P‡Ip—Kdƒ`‡K—Md‡@‡M—Nd…P‡N—Pd…P‡P—Rd‡@—Fdp‡F‚`‡R‚p—Ddp‡Dp—Bdp‡Bš —<p‡<žÿ/MTrk ÿstrÿ!È4¸Pž˜Pd‹ ˆP˜Qd‹ ˆQ˜Sd‡@ˆS˜Ud‹ ˆU˜Sd‹ ˆS˜Qd‡@ˆQ˜Pd‹ ˆP˜Qd‹ ˆQ˜Sd‡@ˆS˜Ud…PˆU˜Sd…PˆS˜RdˆR˜PdpˆPp˜OdˆOp˜Jd˜NdˆJˆNp˜LdˆLp˜NdˆNƒ¥p˜KR‡@ˆK˜LS‡@ˆL˜NU…PˆN˜PV…PˆP˜NW‡@˜LXxˆNpˆLx˜LYˆL‰0˜QdˆQ˜Sd‡@ˆS˜Qd†KˆQu˜Pd…PˆP˜Nd…PˆN˜Pdƒ`ˆP˜Md…PˆM˜Nd…PˆN˜Pdƒ`ˆP˜RdˆR˜Sd‡@ˆS˜Nd‡@ˆN˜PdˆP˜Rdƒ`ˆRƒ`˜OpˆO˜Q!pˆQ˜R0pˆR˜T7pˆT˜VdˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜Qd‡@ˆQ˜Rd‡@ˆR˜Vd…PˆV˜Td…PˆT˜Ydƒ`ˆY˜Vd‡@ˆV˜Qd‡@ˆQ˜Rd…PˆR˜Td…PˆT˜Odƒ`ˆO˜VdˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜RdˆR˜Td…PˆT˜Vdƒ`ˆVp˜Vd’`ˆV˜Wd…PˆW˜Ydƒ`ˆYp˜Td‹ ˆT˜Vdƒ`ˆV˜Wdƒ`ˆW˜Yd…PˆY˜Vd…PˆV˜TdxˆT˜RdˆRp˜PdŽ ˆPv˜Rd‰0ˆRp˜Nd…PˆNp˜OdˆOp˜Jd˜NdˆJˆNp˜LdˆLp˜NdˆNµp˜KR‡@ˆK˜LS‡@ˆL˜NU…PˆN˜PV…PˆP˜NW‡@˜LXxˆNpˆLx˜LYˆL‰0˜QdˆQ˜Sd‡@ˆS˜Qd†KˆQu˜Pd…PˆP˜Nd…PˆN˜Pdƒ`ˆP˜Md…PˆM˜Nd…PˆN˜Pdƒ`ˆP˜RdˆR˜Sd‡@ˆS˜Nd‡@ˆN˜PdˆP˜Rdƒ`ˆRƒ`˜IdpˆI˜KdpˆK˜MdpˆM˜OdpˆO˜Pd‡@ˆP˜Od‡@ˆO˜MdˆM˜Od‡@ˆO˜Md‡@ˆM˜Pd‹ ˆP˜Odƒ`ˆO˜Md†VˆMj˜Kdƒ`ˆK˜Mdƒ`ˆM˜Pd‡@ˆP˜Md‡@ˆM˜KdˆK˜Md…PˆMp˜Mdƒ`ˆM˜Odƒ`ˆO˜Pd‡@ˆP˜Od‡@ˆO˜MdˆM˜Od‡@ˆO˜Md‡@ˆM˜Pd‹ ˆP˜Odƒ`ˆO˜Md‡@ˆM˜Kdƒ`ˆK˜Mdƒ`ˆM˜Od‡@ˆO˜Pdƒ`ˆP˜Rdƒ`ˆR˜Pa‡@ˆP˜Raƒ`ˆR˜Saƒ`ˆS˜Qa‡@ˆQ˜Ma‡@ˆM˜QdˆQ˜Sd‡@ˆS˜Qd†KˆQu˜Pd…PˆP˜Nd…PˆN˜Pdƒ`ˆP˜Md…PˆM˜Nd…PˆN˜Pdƒ`ˆP˜RdˆR˜Sd‡@ˆS˜Nd‡@ˆN˜PdˆP˜Rdƒ`ˆR‹ ˜VdˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜Qd‡@ˆQ˜Rd‡@ˆR˜Vd…PˆV˜Td…PˆT˜Ydƒ`ˆY˜Vd‡@ˆV˜Qd‡@ˆQ˜Rd…PˆR˜Td…PˆT˜Odƒ`ˆO˜VdˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜RdˆR˜Td…PˆT˜Vdƒ`ˆVp˜Vd’`ˆV˜Wd…PˆW˜Ydƒ`ˆYp˜Tdƒ`˜Vd‡@ˆT‡@ˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜Qd‡@ˆQ˜Rd‡@ˆR˜Vd…PˆV˜Td…PˆT˜Ydƒ`ˆY˜Vd‡@ˆV˜Qd‡@ˆQ˜Rd…PˆR˜Td…PˆT˜Odƒ`ˆO˜VdˆV˜Td‡@ˆT˜Yd‡@ˆY˜Vd‹ ˆV˜Tdƒ`ˆT˜Rd‡@ˆR˜Od‡@ˆO˜RdˆR˜Td…PˆT˜Vdƒ`ˆVp˜Vd’`ˆV˜Wd…PˆW˜Ydƒ`ˆYp˜Td‹ ˆT˜Vdƒ`ˆV˜Wdƒ`ˆW˜Yd…PˆY˜Vd…PˆV˜TdxˆT˜RdˆRp˜PdŽ ˆPv˜Rd‰0ˆRp˜Nd…PˆNp˜OdˆOp˜NdˆNp˜LdˆLp˜NdˆNp˜OdˆOp˜NdˆNp˜LdˆLp˜NdˆNp˜Pd‹ ˆP˜Qd‹ ˆQ˜Sd‡@ˆS˜Ud‹ ˆU˜Sd‹ ˆS˜Qd‡@ˆQ˜Pd‹ ˆP˜Qd‹ ˆQ˜Sd‡@ˆS˜Ud…PˆU˜Sd…PˆS˜Rd’`ˆR¼ÿ/MTrkÒÿfaffaÿ!Êcºe”PºcßPºfƒ`šIdšNdšQd‚hŠIŠNŠQ‚hšLdšIdšPd‚hŠLŠIŠP‚hšRdšIdšMdƒ`ºdxº^xº\xºYxºZxºaxºdxºkxºq‚hŠRŠIŠMxºešIdšFdxŠIŠFxšKdšFdxŠKŠFxšHdšLdšCd‚hŠHŠLŠC„XšHdšLdšCd‚hŠHŠLŠCxšLdšHdšCdxŠLŠHŠCxšCdšGdšLdpŠCŠGŠLpšGdšBdšJd‚hŠGŠBŠJ‚hšGdšBdšJd‚hŠGŠBŠJxšJdšBdšGdxŠJŠBŠGxšIdšBdšGdxŠIŠBŠGxšEdš@dšHd‚hŠEŠ@ŠH„XšEdš@dšHd‚hŠEŠ@ŠHxš@dšHdšEdxŠ@ŠHŠExšJdš@dšCdšEdpŠJŠ@ŠCŠEpšEdšJd‚hŠEŠJ‚hšSdšJdšZdšGdšNd…PŠSŠJŠZŠGŠN£PšDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠUéšDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠU­šQdšIdšLd‚hŠQŠIŠL‚hšIdšLdšQd‚hŠIŠLŠQ‚hšQdšLdšId‚hŠQŠLŠI‚hšIdšLdšQd‚hŠIŠLŠQ¨(šDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠUéšDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠU¶0šDdšGdšLdpŠDŠGŠLpšLdšGdšDdxŠLŠGŠDxšLdšGdšDdxŠLŠGŠDxšLdšGdšDdxŠLŠGŠDæšIdšSdšMdšPdšGd‚hŠIŠSŠMŠPŠG‚hšKdšFdšRdšNd‚hŠKŠFŠRŠN‚hšRdšNdšMdšIdšFd‚hŠRŠNŠMŠIŠFŒšJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFá@ºc‡@ºhxº`xºZxº^xºbxºfxºjxºoxºcšJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFû`ºfƒ`šJdšAdšEd‚hŠJŠAŠE‚hšKdšAdšFd‚hŠKŠAŠF‚hºfšMdšHdšCdxºaxºYxºVxºZxºcxºgxºqxºrxºsxºtxºkxºp‚hºoxŠMºmxºjxºgxºdxº[xºUxºNxºJxº@xº9xº6xº0‚hºxºxºŠ(ŠHƒ`ŠCŠ(ºfƒ`šAdšHdšFdxŠAŠHŠFxšIdšFdšAdxŠIŠFŠAxšKdšFdšAdxŠKŠFŠAxšHdšLdšCd‚hŠHŠLŠC„XšHdšLdšCd‚hŠHŠLŠCxšLdšHdšCdxŠLŠHŠCxšLdšGdšCdxŠLŠGŠC‚hšGdšBdšJd‚hŠGŠBŠJ‚hšGdšBdšJd‚hŠGŠBŠJxšJdšBdšGdxŠJŠBŠGxšIdšBdšGdxŠIŠBŠGxšEdš@dšHd‚hŠEŠ@ŠH„XšEdš@dšHd‚hŠEŠ@ŠHxš@dšHdšEdxŠ@ŠHŠExšJdš@dšCdšEdpŠJŠ@ŠCŠEpšEdšJd‚hŠEŠJ‚hšSdšJdšZdšGdšNd…PŠSŠJŠZŠGŠN£PšDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠUéšDšIpŠDŠIpšI$šN$pŠIŠNpšLdšPdšUd‡@ŠLŠPŠU¶0šDdšGdšLdpŠDŠGŠLpšLdšGdšDdxŠLŠGŠDxšLdšGdšDdxŠLŠGŠDxšLdšGdšDdxŠLŠGŠDæšIdšSdšMdšPdšGd‚hŠIŠSŠMŠPŠG‚hšKdšFdšRdšNd‚hŠKŠFŠRŠN‚hšRdšNdšMdšIdšFd‚hŠRŠNŠMŠIŠF‚ÙxšIdšSdšMdšPdšGd‚hŠIŠSŠMŠPŠG‚hšKdšFdšRdšNd‚hŠKŠFŠRŠN‚hšRdšNdšMdšIdšFd‚hŠRŠNŠMŠIŠFŒšJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFð@šJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFð@šJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFð@šJdšMdšFdšEdƒ`ŠJŠMŠFŠEpšJdšMdšEdšFdpŠJŠMŠEŠFÿ@šEdšAdšJd‚hŠEŠAŠJ‚hšFdšAdšKd‚hŠFŠAŠK‚hºsšMdšHdšCdpºqpºixºcxºgxºqxºrxºsxºtxºkxºp‚hºoxŠMºmxºjxºgxºdxº[xºUxºNxºJxº@xº9xº6xº0‚hºxºxºŠ(ŠHƒ`ŠCŠ(ºfƒ`šAdšHdšFdxŠAŠHŠFxšIdšFdšAdxŠIŠFŠAxšKdšFdšAdxŠKŠFŠAxšHdšLdšCd‚hŠHŠLŠC„XšHdšLdšCd‚hŠHŠLŠCxšLdšHdšCdxŠLŠHŠCxšLdšGdšCdxŠLŠGŠC‚hšGdšBdšJd‚hŠGŠBŠJ‚hšGdšBdšJd‚hŠGŠBŠJxšJdšBdšGdxŠJŠBŠGxšIdšBdšGdxŠIŠBŠGxšEdš@dšHd‚hŠEŠ@ŠH„XšEdš@dšHd‚hŠEŠ@ŠHxš@dšHdšEdxŠ@ŠHŠExšJdš@dšCdšEdpŠJŠ@ŠCŠEpšBdšEdšJd‚WŠBŠEŠJ‚hšBdšLdš>dšEdxŠBŠLŠ>ŠExšBdšLdš>dšEdxŠBŠLŠ>ŠExšBdšLdš>dšEdxŠBŠLŠ>ŠE‚hšHdšLdšCd‚hŠHŠLŠC„XšHdšLdšCd‚hŠHŠLŠCxšLdšHdšCdxŠLŠHŠCxšLdšGdšCdxŠLŠGŠC‚hšGdšBdšJd‚hŠGŠBŠJ‚hšGdšBdšJd‚hŠGŠBŠJxšJdšBdšGdxŠJŠBŠGxšIdšBdšGdxŠIŠBŠGxšEdš@dšHd‚hŠEŠ@ŠH„XšEdš@dšHd‚hŠEŠ@ŠHxš@dšHdšEdxŠ@ŠHŠExšJdš@dšCdšEdpŠJŠ@ŠCŠEpšEdšJd‚hŠEŠJ‚hšSdšJdšZdšGdšNd…PŠSŠJŠZŠGŠNغf’`ºdxº^xº\xºYxºZxºaxºdxºkxºqƒ`ºe¿`ÿ/MTrk1ÿsynth01ÿ!Ë »Už›Ldp‹Lp›Pdp‹Pp›Sdp‹Sp›Ud‹ ‹Uƒ`›Udp‹U›Vdp‹V›Zdp‹Zp›Xd…P‹Xp›Wd…P‹Wp›Sd…P‹Sp›Pdp‹Pp›Ldp‹Lp›Pdp‹Pp›Sdp‹Sp›Ud…P‹Up›Wdp‹Wp›Yd…P‹Yp›Zdƒ`‹Zp›\aƒ`‹\p›^d‰0‹^†Š›QFp‹Q›MFp‹M›HFp‹H›CFp‹C›@Fp‹@›Fp‹>›EFp‹E›JFp‹J›FFp‹F›MFp‹M›RFp‹R›TFp‹Tƒáp›Adp‹Ap›?dp‹?p›Adp‹Ap›Fdp‹Fp›Cdp‹C…P›?dp‹?p›Adp‹Ap›Cdp‹Cp›?dp‹?p›Cdp‹Cp›Fdp‹Fp›Ddp‹D…P›dp‹>p›Cdp‹Cp›?dp‹?p›Cdp‹Cp›Fdp‹Fp›Ddp‹D…P›Fp‹>›EFp‹E›JFp‹J›FFp‹F›MFp‹M›RFp‹R›TFp‹Tµp›Ldp‹Lp›Pdp‹Pp›Sdp‹Sp›Ud‹ ‹Uƒ`›Udp‹U›Vdp‹V›Zdp‹Zp›Xd…P‹Xp›Wd…P‹Wp›Sd…P‹Sp›Pdp‹Pp›Ldp‹Lp›Pdp‹Pp›Sdp‹Sp›Ud…P‹Up›Wdp‹Wp›Yd…P‹Yp›Zdƒ`‹Zp›\aƒ`‹\p›^d‰0‹^Å0ÿ/simutrans-124.3/simutrans/music/52-Dreamy-Oriental-Nights.mid000066400000000000000000002215741474050137200241000ustar00rootroot00000000000000MThd àMTrkHÿDreamy Oriental NightsÿCopyright (C) 2018 RykSebÿyƒTƒCƒg–¼z URLÿQB@ÿSetupÿXpÿQ ãÔÿDreamy Oriental NightsÿX‰0ÿQ ãÔ£Pÿmusic by RykSebÚÿQ 6‹ ÿQDƒ`ÿB‡ÿB2øÿCøÿC2øÿD3‡ÿD4øÿB'øÿB'2øÿC'øÿC'2øÿD'‡ÿD'2‡ÿD'3øÿD'4øÿB''øÿB''2‡ÿQŽÿQ¸#ÿ/MTrk¨ÿ System Setupÿ!ÿ=---- Reset --------------------------------------------------ð~ ÷<ð AB@A÷<ÿ@---- ‘S‘ÌÝ’è --------------------------------------------------ð÷ÿA---- Drum ’ljÁ --------------------------------------------------ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@÷ð AB@ ÷ð AB@ ÷ÿ@---- CH Setup --------------------------------------------------ÿ=---- Layer --------------------------------------------------ÿK---- End of System Setup --------------------------------------------------ë/ÿ/MTrk ÿKotoÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------°y°° Àk° H°l°[° °°e°d°@°&°e°d°@°e°d° à @°e°dÿG---- End of CH Setup --------------------------------------------------‰N:Yp€:<]p€<?Rp€?Adƒ`€AC]ƒ`€C>_ƒ`€>:Xƒ`€:?dƒ`€?>dp€>:[p€:7dp€7p:dp€:7dp€75dƒ`€55\p€53Up€35dp€57[p€73\p€35\p€57_‡@€7p:[p€:<[p€<?dp€?Adƒ`€ACXƒ`€CFdƒ`€FCYƒ`€CKdƒ`€KJdp€JF\p€FCXp€Cp?Xp€?Cdp€CAYp€Ap?Xp€?C\p€CAcp€A?]p€?a‚B€>:]‚5€:+?a‚2€?.>\p€>:]€:Y7U‚4€7,:dp7Z"€:O5R€7~€5C5[l€53Xq5Z€3i7U€5R3T€7Y5X+€3F7Z8€5†]€7‚:\qZ‚*€>8:X‚5€:)?Y‚J€?>Xs:R€>f7O €:‚€7B:`p7[€:[5T#€7‚€545at3L €5f5T€3}€5W7Xt€75Vy3\*€5g€3`5\p7V€5‡o€7!:cq€:(áb;á{:(á\6(á=2(á.(á)($á`%(áB!(á#áá@‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘"dƒ`"‘ `‚h x‘ dp x‘ Vx x‘ qx p‘ dƒ` ‘`‚hx‘dpx‘Vxx‘qxp‘dƒ_‘$`‚g$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘"dƒ`"‘ `‚h x‘ dp x‘ Vx x‘ qx p‘ dƒ` ‘`pw‘lpx‘dpx‘lpx‘"pp"‘#`p#‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘.dp.‘"dp"‘ `‚h x‘ dp x‘ Vx x‘ qx x‘'dx'‘,dp,‘ dp x‘`py‘dpx‘Vxx‘qxp‘do‘+do+‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘.dp.‘"dp"‘ `‚h x‘ dp x‘ Vx x‘ qx x‘'dx'‘,dp,‘ dp ‘`pw‘+lp+x‘dpx‘+lp+x‘"pp"‘#`p#‘$do$q‘$dp$‘)dx)‘+Zx+x‘$dx$x‘Ux‘$d‚h$x‘"do"q‘"dp"‘)dx)‘"Zx"x‘dxp‘"d‚h"x‘ do q‘ dp ‘$dx$‘+Zx+x‘$dx$p‘ d‚h x‘doq‘dp‘&dx&‘)Zx)x‘"dx"p‘dp‘+dp+‘doq‘dp‘"dx"‘$Zx$x‘dxx‘$Zx$‘d‚hx‘doq‘dp‘&Zx&‘dxx‘"dx"x‘&Zx&‘dp‘"dp"‘ do q‘ dp ‘'dx'‘+Zx+x‘$dx$p‘ d‚h x‘doy‘dpx‘dx‘&Zx&‘)nx)‘"_x"x‘dp‘+dp+‘Zx‘$do$q‘$dp$‘)dx)‘+Zx+x‘$dx$x‘Ux‘$d‚h$x‘"do"q‘"dp"‘)dx)‘"Zx"x‘dxp‘"d‚h"x‘ do q‘ dp ‘$dx$‘+Zx+x‘$dx$p‘ d‚h x‘doq‘dp‘&dx&‘)Zx)x‘"dx"p‘dp‘+dp+‘doq‘dp‘"dx"‘$Zx$x‘dxx‘$Zx$‘d‚hx‘doq‘dp‘&Zx&‘dxx‘"dx"x‘&Zx&‘dp‘"dp"‘ do q‘ dp ‘'Zx'‘ dx x‘,dx,‘'Zx'x‘ dp ‘,dp,‘+dp+x‘&dp&x‘dpx‘nx‘&dx&x‘nx‚h‘ Z‹ á@‘,d\áx=á =áH<áo;á;á?:ág9á9á78,á@‘d‡@‘ d‡@ ‘%d‡@%‘(d‡@(‘*d‡@*‘#d‡@#‘(d‡@(‘#d‡@#‘d‡@‘ d‡@ ‘%d‡@%‘(d‡@(‘*d‡@*‘,d‡@,‘%d‡@%‘ d‡@ ‘d‡@‘ d‡@ ‘%d‡@%‘(d‡@(‘*d‡@*‘#d‡@#‘(d‡@(‘#d‡@#‘d‡@‘ d‡@ ‘%d‡@%‘(d‡@(‘*dp*‘dx‘*dx*x‘%dx%‘dx‘%dx%‘,dp,‘ dx ‘,dx,x‘ dx ‘'dx'‘,dx,‘%dx%x‘%dx%p‘%dp%x‘%dx%x‘%dx%p‘%dx%x‘%dx%‘%dx%x‘*dx*‘,dx,x‘%dx%‘ dx x‘%dx%‘ dx x‘"dx"‘%ddá@(áQ=(á!;(ár8(áB6(á4(ád1(á4/(á-(áU*%á@‘_px‘Yxx‘Zx‘*Vx*‘%^x%‘ ip x‘ [x ‘,\x,‘'Up'‘ \x ‘%dx%x‘%\x%x‘%fp%‘(`x(‘%Vx%x‘#lx#‘%bx%x‘ fx ‘#Sx#‘%\p%‘Zxx‘Zxx‘%bx%‘*^p*‘ bx x‘ rx x‘ _x ‘,fx,‘#fx#‘%bx%‘'lx'‘(^x(x‘(fp(‘#Xp#‘(cx(‘#Ox#‘ Xx x‘#dx#‘%Rx%‘(\x(x‘,fx,‘#Kx#‘apx‘[xx‘^x‘*fx*‘%`x%‘ Yp x‘ dx ‘,Zx,‘'Ux'‘#`x#‘ Px ‘%]x%x‘%Xx%x‘%[x%‘ Nx ‘*Vx*‘,dx,x‘ ^x ‘%bx%x‘ Zx ‘#_x#‘%fp%‘Wxx‘Vx‘%]x%‘*dp*‘Xx‘*\x*x‘ _x x‘ Qx ‘,dx,‘'Tx'‘#[x#‘ Tx ‘%dx%x‘%Ux%‘*]x*‘,dx,x‘/lx/‘,bx,x‘%Xx%‘,qx,‘#`x#‘%mp%‘ [p ‘_px‘Yxx‘Zx‘*Vx*‘%^x%‘ ip x‘ [x ‘,\x,‘'Up'‘ \x ‘%dx%x‘%\x%x‘%fp%‘,`x,‘%Vx%x‘#lx#‘%bx%x‘ fx ‘#Sx#‘%\p%‘Zxx‘Zxx‘%bx%‘*^p*‘ bx x‘ rx x‘ _x ‘,fx,‘#fx#‘%bx%‘'lx'‘(^x(x‘(fp(‘#Xp#‘(cx(‘#Ox#‘ Xx x‘#dx#‘%Rx%‘(\x(x‘,fx,‘#Kx#‘apx‘[xx‘^x‘*fx*‘%`x%‘ Yp x‘ dx ‘,Zx,‘'Ux'‘#`x#‘ Px ‘%]x%x‘%Xx%x‘%[x%‘ Tx ‘*Vx*‘,dx,x‘ ^x ‘%bx%x‘ Zx ‘#_x#‘%fp%‘dxx‘bx‘%Xx%‘*fp*‘Tx‘*ix*x‘ rx x‘ ax ‘,qx,‘'bx'‘#hx#‘ \x ‘%dp%x‘%dx%x‘%dp%‘,dx,‘%dx%x‘%dx%x‘%d<á@(áJ=(á;(á_8(á)6(át3(á>1(á /% á -(áD&(ágá9 á@‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘"dƒ`"‘ `‚h x‘ dp x‘ Vx x‘ qx p‘ dƒ` ‘`‚hx‘dpx‘Vxx‘qxp‘dƒ_‘$`‚g$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘"dƒ`"‘ `‚h x‘ dp x‘ Vx x‘ qx p‘ dƒ` ‘`pw‘lpx‘dpx‘lpx‘"pp"‘#`p#‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘.dp.‘"dp"‘ `‚h x‘ dp x‘ Vx x‘ qx x‘'dx'‘,dp,‘ dp x‘`py‘dpx‘Vxx‘qxp‘do‘+do+‘$`‚h$x‘$dp$x‘$Vx$x‘$qx$p‘$dƒ`$‘"`‚h"x‘"dp"x‘"Vx"x‘"qx"p‘.dp.‘"dp"‘ `‚h x‘ dp x‘ Vx x‘ qx x‘'dx'‘,dp,‘ dp ‘`pw‘+lp+x‘dpx‘+lp+x‘"pp"‘#dp#á@± `‘$x‡h± aP± bP± cP± dP± ex± fP± gP± hP± ix± jP± kP± lP± mx± nP± oP± pP± qx± rP± sP± tP± ux± vP± wP± xx± yP± zP± {P± |xá3?± }(á ;(áa6± ~(á82(á.(áe)(á<%(á!át(á$ á) áÿ/MTrkVÿPadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------²y²² Â0² A²M²[² ²²e²d²@²&²e²d²@²e²d² â@²e²dÿG---- End of CH Setup --------------------------------------------------‡^² `†>² "<² #F’Rd’Fd2² $4² %x² &x² 'x² (4² )x² *x² +4² ,x² -x² .x² /4² 0x² 1x² 24² 3x² 4x² 5x² 64² 7x² 8x² 9x² :4² ;x² x² ?x² @x² A4² Bx² Cx² D4² Ex² Fx² Gx² H4² Ix² Jx² Kx² L4² Mx² Nx² O4² Px² Qx² Rx² S4² Tx² Ux² V4² Wx² Xx² Yx² Z4² [F‚R‚F’Wd’Kd‚W‚K’Yd’Hdƒ`‚Y’Wdƒ`‚W’Vdƒ`‚V’Wdƒ`‚H‚W’Td’Ad’Od‡@‚T‚A‚O’Rd’Cd’Md‡@‚R’Td’<² =2² < ² <<² ?<² A<² D<² G<² J<² L<² O<² R<² T<² W<² Z<² ]<² _<² b<² e<² g<² j2² l2² p<² s<² v<² y<² ‚C‚M‚T‚<‚² m<² c<² Y<² N<² D<² 9<² /<² $ ² !<² <² ² `‡@² M’Rd’Fd’d’7d‚F‚>‚7’Rd’Fd’d’7d‚F‚>‚7² i’d’Fd‚:‚>‚F’Cd’8d’d’Fd’Ad‚7‚>‚F‚A’Hd’8d’?d’Cd‚H‚8‚?‚C’7d’>d’Jd’Fd‚7‚>‚J‚F’d’Fd’Md‚:‚>‚F‚M’Cd’8d’d’Ad’Fd‡@‚7‚>‚A‚Fx’Fd’>d’7dx‚F‚>‚7p’Fd’7d’>dx‚F‚7‚>‚O² X’7d’>d’Fd#² U<² Q<² N<² JA² H<² F<² Cƒ[² D ² D<² F<² G<² H<² J<² K<² M<² N<² O<² Q<² R<² T(² U<² W<² Z<² \<² _<² a² c‚7‚>‚F² c’5d’d’7d’:d‡@‚:’0d‡@‚>’?d’Cd‡@‚C‚7‚0’>d’8d’Fd‡@‚?‚>‚8’:d’Ad‡@‚F’3d’Cd‡@‚:‚A’?d‡@‚3‚C’Dd’5d‡@‚?‚D‚5’Jd’7d’Fd’Ad‡@‚A‚J‚7’Md’d’0d’:d‡@‚F‚>’?d’Hd‡@‚0‚:‚?‚H’8d’Cd’Rd’5d‡@‚5‚8‚C’:d’Ad’7d‡@‚R‚:‚A‚7’Od’>d’’?d’7d‡@‚7‚?‚O’Td’8d’Cd‡@‚C‚8‚<’Ad’:d’7d‡@‚7‚T‚A’Vd’Fd’3d‡@‚F‚V’Wd’?d‡@‚:‚3‚W‚?’[d’d’7d‚F‚>‚7’Rd’Fd’d’7d‚F‚>‚7² i’d’Fd‚:‚>‚F’Cd’8d’d’Fd’Ad‚7‚>‚F‚A’Hd’8d’?d’Cd‚H‚8‚?‚C’7d’>d’Jd’Fd‚7‚>‚J‚F’d’Fd’Md‚:‚>‚F‚M’Cd’8d’i’Ai’Fi‡@‚7‚>‚A‚Fx’Fi’>i’7ix‚F‚>‚7p’Fi’7i’>ix‚F‚7‚>‚T² A’8d’?d’Gd² @(² ?(² >(² =(² <(² ;(² :(² 9(² 8(² 7(² 6(² 5(² 4² 3 ² 2P² 3(² 4(² 5(² 6(² 7(² 8(² 9P² :(² ;(² <(² =(² >(² ?(² @(² AP² B(² C(² D(² E(² F(² G(² H(² IP² J(² K(² L(² M(² N(² O² P ² P‚8‚?‚G’6d’=d’9d‡@‚6‚=‚9’?d’8d’;d‡@‚;’1d‡@‚?’@d’Dd‡@‚D‚8‚1’?d’9d’Gd‡@‚@‚?‚9’;d’Bd‡@‚G’4d’Dd‡@‚;‚B’@d‡@‚4‚D’Ed’6d‡@‚@‚E‚6’Kd’8d’Gd’Bd‡@‚B‚K‚8’Nd’=d’Dd‡@‚G‚N’Ld’;d‡@‚;‚L‚=’Id’9d‡@‚D‚I‚9’8d’Bd’Gd‡² P(‚8‚B’?d’1d’;d² Qx² R<² Sx² Tx² U<² Vx² Wx² Xx² Y<² Z(‚G‚?’@d’IdP² [x² \<² ]x² ^x² _x² `<² ax² bx² c(‚1‚;‚@‚I’9d’Dd’Sd’6d‡@‚6‚9‚D’;d’Bd’8d‡@‚S‚;‚B‚8’Pd’?d’=d’1d‡@‚1‚?’@d’8d‡@‚8‚@‚P’Ud’9d’Dd‡@‚D‚9‚=’Bd’;d’8d‡@‚8‚U‚B’Wd’Gd’4d‡@‚G‚W’Xd’@d‡@‚;‚4‚X‚@’\d’=d’9d’Dd‡@‚\‚=‚9‚D’Zd’;d’Bd’8d‡@‚Z‚;‚B‚8’Xd’8d’Gd’=d‡@‚=‚8’8d’@dƒ`‚8‚G’Dd’=dƒ`‚=‚D‚X’Ud’6d’Ed‡@‚@‚U‚6‚E’Sd’8d’Gd’Bd‡@‚S‚8‚G’Ud’Gd’=d’?d² bp² a‚@² `‚@² _‚@² ^‚² ]‚@² \<² \‚?‚G‚B’@d ² ]P² ^P² _(² `P² aP² bP² cP² dP² e(² fP² gP² hP² iP² j(² kP² lP² mP² nP² oP² p‚U‚=‚@ ² qP² rP² sP² tP² u(² vP² w² h’6d’=d’9d‡@‚6‚=‚9’?d’8d’;d‡@‚;’1d‡@‚?’@d’Dd‡@‚D‚8‚1’?d’9d’Gd‡@‚@‚?‚9’;d’Bd‡@‚G’4d’Dd‡@‚;‚B’@d‡@‚4‚D’Ed’6d‡@‚@‚E‚6’Kd’8d’Gd’Bd‡@‚B‚K‚8’Nd’=d’Dd‡@‚G‚N’Ld’;d‡@‚;‚L‚=’Id’9d‡@‚D‚I‚9’8d’Bd’Gd‡@‚8‚B’?d’1d’;d‡@‚G‚?’@d’Id‡@‚1‚;‚@‚I’9d’Dd’Sd’6d‡@‚6‚9‚D’;d’Bd’8d‡@‚S‚;‚B‚8’Pd’?d’=d’1d‡@‚1‚?’@d’8d‡@‚8‚@‚P’Ud’9d’Dd‡@‚D‚9‚=’Bd’;d’8d‡@‚8‚U‚B’Wd’Gd’4d‡@‚G‚W’Xd’@d‡@‚;‚4‚X‚@’\d’=d’9d’Dd‡@‚\‚=‚9‚D’Zd’;d’Bd’8d‡@‚Z‚;‚B‚8’Xd’8d’Gd’=d‡@‚=‚8’8d’@dƒ`‚8‚G’Dd’=dƒ`‚=‚D‚X’Ud’6d’Ed‡@‚@‚U‚6‚E’Sd’8d’Gd’Bdƒ$² cH² d\² e2² e² f2‚S‚8‚G’Ud’Gd’=dF² gd² hd² id² jx² kd² ld² md² nx² od² pd² qd² rx² s<² u<² v<² wP² x<² y<² zP² {<² |F‚=‚G‚B² c’Rd’Fd’d’7d‚F‚>‚7’Rd’Fd’d’7d‚F‚>‚7™-ÿ/MTrk íÿKeysÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------³y³³ ó X³\³[³ ³³e³d³@³&³e³d³@³e³d³ ã@³e³dÿG---- End of CH Setup --------------------------------------------------¥“0dpƒ0“Cd“?P“P“:P“AdSƒ>ƒ:ƒA“.Pxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“.Zxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“>d“:P`ƒ5ƒ>ƒ:“5P“>d“:P“+dpƒ+“&d`ƒ5ƒ>ƒ:ƒ&“+dxƒ+“.dxƒ.“0dpƒ0“Cd“?P“P“:PSƒCƒ>ƒ:“.Pxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“.Zxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“>d“:P`ƒ5ƒ>ƒ:“5X“>n“:X“+n‚Pƒ5ƒ>ƒ:ƒ+ƒðp“0dpƒ0“Cd“?P“P“:P“AdSƒ>ƒ:ƒA“.Pxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“.Zxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“>d“:P`ƒ5ƒ>ƒ:“5P“>d“:P“+dpƒ+“&d`ƒ5ƒ>ƒ:ƒ&“+dxƒ+“.dxƒ.“0dpƒ0“Cd“?P“P“:PSƒCƒ>ƒ:“.Pxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“.Zxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“>d“:P`ƒ5ƒ>ƒ:“5X“>n“:X“+n‚Pƒ5ƒ>ƒ:ƒ+…ïp“0dpƒ0“Cd“?P“P“:P“AdSƒ>ƒ:ƒA“.Pxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“.Zxƒ.“>L“:L“A_Sƒ>ƒ:ƒA“.dxƒ.“>P“:P“AdSƒ>ƒ:ƒA“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“>d“:P`ƒ5ƒ>ƒ:“5P“>d“:P“+dpƒ+“&d`ƒ5ƒ>ƒ:ƒ&“+dxƒ+“.dxƒ.“0dpƒ0“Cd“?P“P“:PSƒCƒ>ƒ:“.Pxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“.Zxƒ.“C_“>L“:LSƒCƒ>ƒ:“.dxƒ.“Cd“>P“:PSƒCƒ>ƒ:“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:“+Pxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:PSƒ5ƒ>ƒ:“+Zxƒ+“5L“>_“:LSƒ5ƒ>ƒ:“+dxƒ+“5P“>d“:P“.dSƒ5ƒ>ƒ:%ƒ.“/dxƒ/“0dpƒ0“Cd“?P“PSƒ:ƒFƒ>“.Pxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“.Zxƒ.“:L“F_“>LSƒ:ƒFƒ>“.dxƒ.“:P“Fd“>PSƒ:ƒFƒ>“,dpƒ,“8P“d“:PSƒ5ƒ>ƒ:%“+dpƒ+“5P“>d“:P“&dSƒ5ƒ>ƒ:%ƒ&“)dxƒ)“*dxƒ*“+dxƒ+“5P“:P“>d`ƒ5ƒ:ƒ>“5X“:X“+n“>n‚Pƒ>ƒ5ƒ:ƒ+x“+Z“2Z“:Z“Adžxƒ+ƒ2ƒ:ƒAÿ/MTrkÿBellÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------´y´´ Äb´ ,´V´[´ ´´e´d´@´&´e´d´@´e´d´ ä@´e´dÿG---- End of CH Setup --------------------------------------------------‚¤^”Fd‡@„F”Kd‡@„K”Md‡@„M”Rd‡@„Rƒ`”Tdƒ`„T”Odƒ`„O”Rdƒ`„R”Mdƒ`„M”Odƒ`„O”Kdƒ`„K‡@”Wdƒ`„W”Vdƒ`„Vƒ`”Rdƒ`„Rƒ`”Odƒ`„O‡@”Tdƒ`„T”Rdƒ`„R„ù`”Fd‡@„F”Kd‡@„K”Md‡@„M”Rd‡@„Rƒ`”Tdƒ`„T”Odƒ`„O”Rdƒ`„R”Mdƒ`„M”Odƒ`„O”Kdƒ`„K‡@”Wdƒ`„W”Vdƒ`„Vƒ`”Rdƒ`„Rƒ`”Odƒ`„O‡@”Tdƒ`„T”Rdƒ`„Rƒ‚ ´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ p”_4x„_”_Kx„_´ `x”_4x„_”_Kx„_x´ x”_4x„_”_Kx„_x´ `”_Kx„_‚êh´ ,‡@”Fd‡@„F”Kd‡@„K”Md‡@„M”Rd‡@„Rƒ`”Tdƒ`„T”Odƒ`„O”Rdƒ`„R”Mdƒ`„M”Odƒ`„O”Kdƒ`„K‡@”Wdƒ`„W”Vdƒ`„Vƒ`”Rdƒ`„Rƒ`”Odƒ`„O‡@”Tdƒ`„T”Rdƒ`„R”(”^E(”jdP„^(„j…F”YE(”edP„Y(„eˆÿ/MTrk-ÿChordÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------µyµµ ŵ .µhµ[µ µµeµdµ@µ&µeµdµ@µeµdµ å@µeµdÿG---- End of CH Setup --------------------------------------------------¥•Px…5…>x•5D•>Px…5…>p•5D•>Px…5…>x•7D•?Px…7…?x•7D•?Px…7…?p•7D•?Px…7…?p•7D•?Px…7…?x•7D•?Px…7…?p•7D•?Px…7…?p•:P•5Dx…:…5x•:P•5Dx…:…5p•:P•5Dx…:…5p•:P•5Dx…:…5x•:P•5Dx…:…5p•:P•5Dx…:…5p•3D•Px…5…>x•5D•>Px…5…>p•5D•>Px…5…>p•3D•>Px…3…>x•3D•>Px…3…>p•3D•>Px…3…>p•>P•3Dx…>…3p•>P•3Dx…>…3p•>P•3Dx…>…3•?P•7Dx…?…7•AP•8Dx…A…8x•AP•8Dx…A…8p•AP•8Dx…A…8p•7D•CPx…7…Cx•7D•CPx…7…Cp•7D•CPx…7…Cp•5D•>Px…5…>x•5D•>Px…5…>p•5D•>Px…5…>p•5D•?Px…5…?x•5D•?Px…5…?p•5D•?Px…5…?p•5D•Px…5…>x•5D•>Px…5…>p•5D•>Px…5…>p•3D•>Px…3…>x•3D•>Px…3…>p•3D•>Px…3…>p•>P•3Dx…>…3p•>P•3Dx…>…3p•>P•3Dx…>…3•?P•7Dx…?…7•5D•Px…7…>x•7D•>Px…7…>p•7D•>Px…7…>p•5D•APx…5…Ax•5D•APx…5…Ap•5D•APx…5…Ap•5D•?Px…5…?x•5D•?Px…5…?p•5D•?Px…5…?p•5D•CPx…5…Cx•5D•CPx…5…Cp•5D•CPx…5…Cp•5D•APx…5…Ax•5D•APx…5…Ap•5D•APx…5…Ap•5D•Px…5…>x•5D•>Px…5…>p•5D•>Px…5…>x•7D•?Px…7…?x•7D•?Px…7…?p•7D•?Px…7…?p•7D•?Px…7…?x•7D•?Px…7…?p•7D•?Px…7…?p•:P•5Dx…:…5x•:P•5Dx…:…5p•:P•5Dx…:…5p•:P•5Dx…:…5x•:P•5Dx…:…5p•:P•5Dx…:…5p•3D•Pœ`…7…:…>ÿ/MTrk©ÿLeadÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¶y¶¶ ÆP¶ T¶`¶[¶ ¶¶e¶d¶C¶&¶e¶d¶@¶e¶d¶ æ@¶e¶dÿG---- End of CH Setup --------------------------------------------------‚ˆN–Md–HAx†M†H–Od–JAx†O†J–Rd–MAx†R†M–Od–JAx†O†Jx–Kd–FAx†K†F–Md–HA`†M†H–Kd–FA`†K†F–Md–HAx†M†H–Od–JA`†O†J–Jd–EA\†J†E–Hd–CA\†H†C–Fd–AAx†F†A–Hd–CA`†H†C–Ad–Ax†C†>–Fd–AA‚h†F†A–Hd–CA`†H†C¶H–Od–JAx†O†J–Md–HAx†M†H–Fd–AA‚h†F†A–Hd–CA`†H†C§H–Ad–Ax†C†>–Fn–AG‚h†F†A–Hd–CA`†H†C–Fn–AGp†F†A–Hd–CA`†H†C–Os–JJp†O†J–Mc–H?`†M†H–Kh–FCx†K†F–Mn–HG`†M†H–On–JG`†O†J¶–Rn–MGx¶e¶d¶ p¶ Œ†R†Mx–Mn–HGŒ†M†Hx–Kn–FG`†K†F–Mn–HG`†M†H–On–JG æk=æP? æ@:†O†Jx–Hn–CGp†H†Cx–Cn–>Gp†C†>x–Fn–AG`†F†A–Hn–CG`†H†C–Kn–FG`†K†F–Mn–HG`†M†H–On–JG`†O†J–Rn–MG`†R†M–Vn–QGæ">æ*>æ>>æR>æf>æz>æ?æ"?æb?æ@ˆG†V†QR–VG–Q.æq?–Wn–RG†V†QV†W†Ræ@–Vn–QGp†V†Q–On–JGp†O†Jx–Mn–HG„X†M†Hp–Hn–CGp†H†C–Jn–EGp†J†E–Kn–FGp†K†F–Rn–MGp†R†Mx–On–JG„X†O†Jp–Fn–AGp†F†A–Hn–CGp†H†C–Jn–EGp†J†E–Kn–FGp†K†Fxæv?–Fn–AG„X†F†Aƒ`æ@–Rn–MGp†R†M–Tn–OGp†T†O–[n–VGX†[†V–Yn–TG`†Y†T–Yn–TG`†Y†T–Wn–RG`†W†R–Yn–TG`†Y†T–Rn–MG`†R†M–Tn–OG`†T†O–On–JG`†O†J–Mn–HG`†M†H–On–JG`†O†J–Rn–MG†H†R†Mx–Fn–AG†H†F†Ax–Wn–RG†H†W†Rx–Kn–FGƒ`†K†Fx–Jn–EGx†J†E–Kn–FGx†K†F–Mn–HGx†M†H–[n–VGæY=æ2>æ ?æc? æ@…_†[†Vp–On–JGp†O†Jx–Rn–MGp†R†Mx–On–JGp†O†Jxæ@–Mn–HGp†M†Hxæ@–On–JGp†O†J–Fn–AGx†F†Ax–FG–Knp†F†Kx–Jn–EGp†J†Ex–Fn–AG`†F†A–An–Gƒ`†C†>x–Hn–CG`†H†C–Hn–CGp†H†C–Kn–FG`†K†F–Hn–CG`†H†C–Kn–FG`†K†F–Mn–HG`†M†H–On–JGƒ`†O†Jx–Tn–OG`†T†O–Tn–OGp†T†O–Wn–RGp–Tn–OG†W†RP†T†O–Wn–RG`†W†R–Yn–TG`†Y†Tæw;–[n–VGæ7<æw<æ6=æv=æ6>æv>æ6?æu?æ@s¶@‹ †[†V¶x–Yn–TG`†Y†T–Wn–RG`†W†R–Rn–MG`†R†M–On–JG`†O†J–Mn–HG`†M†H–Kn–FG`†K†F–Hn–CG`†H†C–Fn–AG`†F†A–Cn–>G`†C†>–On–JG`†O†J‚–On–JG`†O†J‚‚¶æ@p¶e¶d¶ Ò@–Md–HAx†M†H–Od–JAx†O†J–Rd–MAx†R†M–Od–JAx†O†Jx–Kd–FAx†K†F–Md–HA`†M†H–Kd–FA`†K†F–Md–HAx†M†H–Od–JA`†O†J–Jd–EA\†J†E–Hd–CA\†H†C–Fd–AAx†F†A–Hd–CA`†H†C–Ad–Ax†C†>–Fd–AA‚h†F†A–Hd–CA`†H†C¶H–Od–JAx†O†J–Md–HAx†M†H–Fd–AA‚h†F†A–Hd–CA`†H†C§H–Ad–Ax†C†>–Fn–AG‚h†F†A–Hd–CA`†H†C–Fn–AGp†F†A–Hd–CA`†H†C–Os–JJp†O†J–Mc–H?`†M†H–Kh–FCx†K†F–Mn–HG`†M†H–On–JG`†O†J¶–Rn–MGx¶e¶d¶ p¶ Œ†R†Mx–Mn–HGŒ†M†Hx–Kn–FG`†K†F–Mn–HG`†M†H–On–JG æP=æL? æ@:†O†Jx–Hn–CGp†H†Cx–Cn–>Gp†C†>x–Fn–AG`†F†A–Hn–CG`†H†C–Kn–FG`†K†F–Mn–HG`†M†H–On–JG`†O†J–Rn–MG`†R†M–Vn–QGæ >æ>æ+>æA>æW>æm>æ?æ?æ_?æ@ˆG†V†QR–VG–Q.–Wn–RG†V†QV†W†R–Yn–TGp†Y†T–Vn–QGp†V†Q–Wn–RGx†W†R–Rn–MG„X†R†Mp–Kn–FGp†K†F–Tn–OGp†T†O–Rn–MGp†R†M–Mn–HGp†M†H–Fn–AGx†F†A–On–JG„X†O†Jp–Hn–CGp†H†C–Jn–EGp†J†E–Mn–HGp†M†H–Kn–FGp†K†Fxæ@–Cn–>G…iæ@æs?æf?æX?æK?æ=?æ0?æ#?æ?æ?æz>æm>æ`>æR>æD>æ7>æ*>æ>æ>æ >æi=æG=æ%=æ=æb<æ@<æ<æ{;æY;æ7;æ;æs:æQ:æ/:æ :æk9æI9æ@9æ^8æ|7æ7æ86æ+5Š(æ#4æy3æP3æ'3æ~2æT2æ+2æ2æX1æ/1æ1æ]0æ30æ 0æ=0æJ/æV.æb-æn,æz+æ+æ*æ)æ ) æz'æ 'æ&æ9%!æ+%‚e†C†>æ@–?n–:G‚h†?†:–Fn–AG…P†F†Ax–Hn–CGx†H†C–Jn–EGx†J†E–Kn–FGƒ`†K†F–Fn–AG‚h†F†A–Mn–HG„X†M†Hx–Rn–MGx†R†M–Tn–OGx†T†O–Vn–QGx†V†Q–Wn–RGæ<=æ>æ>æa? æ@‚w†W†R–Rn–MG‚h†R†M–Yn–TGp†Y†Tp–Rn–MGp†R†Mæ8>–`n–[GæW>æ?æ^? æ@ æ @/†`†[æ@–^n–YG‡@†^†Yxæ|=–cn–^Gæ>æS>æ?æQ?æ|?æ@ƒ`†c†^x–bn–]Gx†b†]–[n–VG†H†[†Vx–`n–[G…P†`†[x–^n–YGx†^†Y–Wn–RG†H†W†Rx–Rn–MGƒ`†R†M–^n–YGƒ`†^†YæC;–[n–VGæ <æP<æ=æ\=æ">æi>æ/?æt?æ@s¶@‰qæ?æ{?æx?æu?æq?æn?æj?æg?æd?æ`?æ]?æY?æV?æS?æO?æL?æH?æE?æB?æ>?æ;?æ8?s†[†Vƒ”¶ ¶ Tæ@–Sn–NG„X†S†Nx–Sn–NGN†S†N*–Sn–NG…D†S†N–Sn–NGN†S†N*–Sn–NGC†S†Ni–Tn–OG;†T†O–Un–PGN†U†P*–Pn–KGN†P†K*–Sn–NGN†S†N*–Nn–IGN†N†I*–Pn–KGN†P†K*–Kn–FGN†K†F*–Ln–GGN†L†G*–Gn–BGN†G†B*–In–DGN†I†D*–Dn–?GN†D†?*–Gn–BGN†G†B*–Bn–=GN†B†=*–Dn–?GN†D†?*–=n–8Gx†=†8–Xn–SGT†X†S$–Gn–BGT†G†B$–Wn–RGT†W†R$–Gn–BGT†G†B$–Xn–SGd†X†S–Gn–BGT†G†B$–Sn–NGT†S†N$–Xn–SGT†X†S$–Gn–BGT†G†B$–Wn–RGT†W†R$–Gn–BGT†G†B$–Xn–SGd†X†S–Gn–BGT†G†B$–Nn–IGT†N†I$–Zn–UGT†Z†U$–_n–ZGx¶e¶d¶„L†_†Z–an–\GT†a†\$–\n–WG†<†\†W –Sn–NGT†S†N$–Wn–RGT†W†R$–Xn–SGT†X†S$–Gn–BGT†G†B$–Wn–RGT†W†R$–Gn–BGT†G†B$–Xn–SGT†X†S$–Sn–NGT†S†N$–Gn–BGT†G†B$–Xn–SGT†X†S$–Gn–BGT†G†B$–Wn–RGT†W†R$–Gn–BGT†G†B$–Xn–SGT†X†S$–Sn–NGT†S†N$–Gn–BGT†G†B$–Xn–SGT†X†S$–Gn–BGT†G†B$–Wn–RGL†W†R$–Xn–SGT†X†S–Zn–UGT†Z†U$–Gn–BGT†G†B$–\n–WGT†\†W$–Xn–SG(†X†SH–Xn–SG:†X†S>–Xn–SG:†X†S>–Xn–SG:†X†S>–Ln–GGm†L†G –Xn–SG:†X†S>–Xn–SG:†X†S>–_n–ZG†H†_†Z–Sn–NGx†S†Næ @–an–\G‚h†a†\æ@–In–DGx†I†D–Nn–IG`†N†I–Sn–NG`†S†Næ@–Xn–SG`†X†Sæ @–dn–_Gx†d†_¶e¶d¶æ&?–cn–^G<æD?<æX?<æh?<æp?<æx?<æ|?<æ@xæ@<æ@ƒ`æ @‡@æ @‡@æ@pæ@fæn?æZ?æG?æn>(æ=(æ4;(æW9æ18æU5æ"3æn0æ;.æ=-æ[(æz#æ ægæ9æQæi†c†^æææææ@p¶e¶d¶ ÐP¶ Tp–Md–HAx†M†H–Od–JAx†O†J–Rd–MAx†R†M–Od–JAx†O†Jx–Kd–FAx†K†F–Md–HA`†M†H–Kd–FA`†K†F–Md–HAx†M†H–Od–JA`†O†J–Jd–EA\†J†E–Hd–CA\†H†C–Fd–AAx†F†A–Hd–CA`†H†C–Ad–Ax†C†>–Fd–AA‚h†F†A–Hd–CA`†H†C¶H–Od–JAx†O†J–Md–HAx†M†H–Fd–AA‚h†F†A–Hd–CA`†H†C§H–Ad–Ax†C†>–Fn–AG‚h†F†A–Hd–CA`†H†C–Fn–AGp†F†A–Hd–CA`†H†Cæ:?–Os–JJ<æX?<æ@x†O†J–Mc–H?`†M†H–Kh–FCx†K†F–Mn–HG`†M†H–On–JG`†O†J¶æj>–Rn–MG æ?<æ2?<æ^?næ@†H¶† ¶ŽD†R†Mÿ/MTrk{ÿArpÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------·y·· ÇQ· .·i·[· ··e·d·B·&·e·d·@·e·d· ç@·e·dÿG---- End of CH Setup --------------------------------------------------ŒìN—GdT‡G$—SdT‡S$—IdT‡I$—UdT‡U$—LdT‡L$—XdT‡X$—NdT‡N$—ZdT‡Z$—NdT‡N$—ZdT‡Z$—PdT‡P$—\dT‡\$—PdT‡P$—\dT‡\$—KdT‡K$—WdT‡W$—KdT‡K$—WdT‡W$—GdT‡G$—SdT‡S$—GdT‡G$—SdT‡S$—LdT‡L$—XdT‡X$—LdT‡L$—XdT‡X$—KdT‡K$—WdT‡W$—GdT‡G$—SdT‡S$—DdT‡D$—PdT‡P$—IdT‡I$—IdT‡I$—SdT‡S$—IdT‡I$—PdT‡P$—IdT‡I$—NdU‡N#—BdU‡B#—NdU‡N#—BdU‡B#—BdU‡B#—NdU‡N#—LdU‡L#—BdU‡B#—NdU‡N#—BdU‡B#—PdU‡P#—DdU‡D#—LdU‡L#—@dU‡@#—NdU‡N#—BdU‡B#—DdU‡D#—PdU‡P#—DdU‡D#—PdU‡P#—DdU‡D#—PdU‡P#—DdU‡D#—PdU‡P#—DdU‡D#—PdU‡P#—GdT‡G$—SdT‡S$—IdT‡I$—UdT‡U$—LdT‡L$—XdT‡X$—NdT‡N$—ZdT‡Z$—UdT‡U$—NdT‡N$—PdT‡P$—\dT‡\$—WdT‡W$—PdT‡P$—SdT‡S$—_dT‡_$—\dT‡\$—SdT‡S$—PdT‡P$—\dT‡\$—WdT‡W$—PdT‡P$—XdT‡X$—ddT‡d$—\dT‡\$—SdT‡S$—WdT‡W$—cdT‡c$—SdT‡S$—_dT‡_$—PdT‡P$—\dT‡\$—UdT‡U$—XdT‡X$—UdT‡U$—\dT‡\$—XdT‡X$—UdT‡U$—NdT‡N$—ZdT‡Z$—NdT‡N$—ZdT‡Z$—LdT‡L$—XdT‡X$—PdT‡P$—\dT‡\$—ZdT‡Z$—NdT‡N$—XdT‡X$—LdT‡L$—UdT‡U$—IdT‡I$—SdT‡S$—GdT‡G$—IdT‡I$—UdT‡U$—IdT‡I$—UdT‡U$—IdT‡I$—UdT‡U$—IdT‡I$—PdT‡P$ç{?—IdT‡I$—DdT‡D$—=dT‡=$—8dT‡8$çv?—1dT‡1$—=dT‡=$—8dT‡8$—1dT‡1ƒQÿ/MTrkÿÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¸y¸¸ ÈQ¸ 9¸8¸[¸ ¸¸e¸d¸@¸&¸e¸d¸@¸e¸d¸ è@¸e¸dÿG---- End of CH Setup --------------------------------------------------…‡è@…¸ è¸ ˜FP2ˆFF¸ 9˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆFF¸ ˜FP2ˆFF¸ \˜FF2ˆFF¸ 9˜Fd*ˆF2¸ ¸ ˜FP2ˆF2¸ {¸ \˜FF2ˆF2¸ w¸ 9˜Fdd¸ sFˆF2¸ o¸ ˜FP2ˆF2¸ k¸ \˜FF2ˆF2¸ h¸ 9˜Fdd¸ dFˆF2¸ `¸ ˜FP2ˆF2¸ \¸ \˜FF2ˆF2¸ X¸ 9˜Fdd¸ TFˆF2¸ P¸ ˜FP2ˆF2¸ L¸ \˜FF2ˆF2¸ H¸ 9˜Fdd¸ DFˆF2¸ @¸ ˜FP2ˆF2¸ =¸ \˜FF2ˆF2¸ 9¸ 9˜Fdd¸ 5FˆF2¸ 1¸ ˜FP2ˆF2¸ -¸ \˜FF2ˆF2¸ )¸ 9˜Fdd¸ %FˆF2¸ !¸ ˜FP2ˆF2¸ ¸ \˜FF2ˆF2¸ ¸ 9˜Fdd¸ FˆF2¸ ¸ ˜FP2ˆF2¸ ¸ \˜FF2ˆF2¸ ¸ 9˜Fdd¸ FˆF2¸ <¸ ‰Øÿ/MTrkMQÿDrumÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------¹y¹¹ ɹ @¹¹[¹ ¹¹e¹d¹@¹&¹e¹d¹@¹e¹d¹ é@¹e¹dÿG---- End of CH Setup --------------------------------------------------Ë™3<<‰3‡™36™SA<‰3‰S‡™3<<‰3‡™36™SA<‰3‰S‡™3<<‰3‡™36™SA<‰3‰S†4™39<‰3 ™3F ™QA2‰3 ‰Q ™3[<‰3œ~™&j<‰&<™&M<‰&4™&L<‰&<™&j<‰&<™&N<‰&<™.O<‰.<™&O<‰&<™2d™,O™4d™$d<‰2‰,‰4‰$4™0d<‰0<™0d™$F<‰0‰$<™&d<‰&<™/d™$d<‰/‰$<™+d™:Z<‰+‰:4™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™5d<‰$‰54™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™.d™PF<‰.‰P<™$_<‰$<™,d<‰,<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o<‰&<™0d™PF<‰0‰P<™+d<‰+<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™7d<‰$‰7<™&d<‰&<™&d<‰&<™$P™QA<‰$‰Q<™&d<‰&<™PF<‰P<™$_<‰$<™&d<‰&<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o™4d<‰&‰4<™0d<‰0<™+d™PF<‰+‰P<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™$P™QA<‰$‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k™3I<‰&‰3<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd™3I<‰$‰&‰P‰3<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™7d<‰$‰74™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™.d™PF<‰.‰P<™$_<‰$<™,d<‰,<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o™3I<‰&‰3<™0d<‰0<™+d™PF<‰+‰P<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™$P™QA<‰$‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k™3I<‰&‰3<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd™3I<‰$‰&‰P‰3<™$d™1d<‰$‰14™*W<‰*<™QA™*J<‰Q‰*<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™QA™*J<‰Q‰*<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™1d<‰$‰*‰14™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™QA™*T<‰Q‰*<™&d™3I<‰&‰3<™PF™*D<‰P‰*<™.d<‰.<™$F<‰$<™$d™1d<‰$‰1<™&K<‰&<™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P4™&K<‰&<™$d™1d<‰$‰1<™&K<‰&<™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P4™&K<‰&<™2d™7d™$d<‰2‰7‰$™2Z<‰2™2Z<‰2™0Z™$F<‰0‰$<™QA™0d<‰Q‰0<™/Z<‰/<™PF™/d<‰P‰/<™+d™$F<‰+‰$<™&;<‰&<™$d<‰$<™&l™.d<‰&‰.<™$F<‰$<™QA<‰Q<™&z™,d™1d<‰&‰,‰14™PF<‰P<™&O<‰&<™*O<‰*<™&<<‰&<™&F<‰&<™*O<‰*<™&F<‰&<™$O<‰$<™&8<‰&<™$O<‰$<™&U<‰&<™0O<‰0<™&J<‰&<™$_™/O<‰$‰/<™&_™._™7U<‰&‰.‰74™$F<‰$<™&U<‰&<™$d™1_<‰$‰14™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™*K<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™*7<‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™*7<‰*<™&_™3P<‰&‰34™*U<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*<™*7<‰*<™&_™3P<‰&‰34™.d<‰.<™$F<‰$<™$d™3b™,K<‰$‰3‰,4™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™$F™*K<‰$‰*4™$d™3Z™*U<‰$‰3‰*4™*U<‰*4™&_™3P<‰&‰34™$F™*7<‰$‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™$P™*7<‰$‰*<™&_™3P<‰&‰34™$_™*U<‰$‰*<™&F<‰&<™3Z™*U<‰3‰*<™&F<‰&<™$d™*U<‰$‰*<™*7<‰*<™&_™._™3P<‰&‰.‰34™.d<‰.<™&F™$F<‰&‰$<™1_™$d™,_<‰1‰$‰,4™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™*K<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™*7<‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™*7<‰*<™&_™3P<‰&‰34™*U<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*<™*7<‰*<™&_™3P<‰&‰34™.d<‰.<™$F<‰$<™$d™3b<‰$‰34™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™$_™*K<‰$‰*<™$F<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™$F™*7<‰$‰*<™*7<‰*<™$_™7_<‰$‰7<™2P<‰24™&F™2_<‰&‰2<™&_™$_<‰&‰$<™0_<‰0<™&F™0P<‰&‰0<™&7<‰&<™&_™$_<‰&‰$™0_<‰0™/_<‰/™+_<‰+<™$_™*U<‰$‰*<™&_™4_<‰&‰4<™*7<‰*<™._<‰.4™1_™,_™$_<‰1‰,‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™3b™$_<‰3‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™*U<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™$F<‰$<™3b™$_<‰3‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™3b™$_<‰3‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™$U™*U<‰$‰*<™&F<‰&<™3Z™*U<‰3‰*<™&F<‰&<™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™&F<‰&<™1b™$_<‰1‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™1b™$_<‰1‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™*U<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™&F™$F<‰&‰$<™1b™$_<‰1‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™$U™*K<‰$‰*<™&F<‰&<™1Z™$b™*U<‰1‰$‰*4™2_<‰2<™2_<‰2<™3P™0_™$b<‰3‰0‰$<™0_<‰0<™+_<‰+<™$F<‰$<™$_™1n<‰$‰14™*_<‰*ƒ$™*_<‰*ƒ$™/F™*_<‰/‰*™+F<‰+™+F<‰+™&P™4P<‰&‰4<™&d<‰&<™.d™$_<‰.‰$<™&P<‰&<™$d™1d™7d<‰$‰1‰74™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™5d<‰$‰54™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™.d™PF<‰.‰P<™$_<‰$<™,d<‰,<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o<‰&<™0d™PF<‰0‰P<™+d<‰+<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™7d<‰$‰7<™&d<‰&<™&d<‰&<™$P™QA<‰$‰Q<™&d<‰&<™PF<‰P<™$_<‰$<™&d<‰&<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o™4d<‰&‰4<™0d<‰0<™+d™PF<‰+‰P<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™$P™QA<‰$‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k™3I<‰&‰3<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd™3I<‰$‰&‰P‰3<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™7d<‰$‰74™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™.d™PF<‰.‰P<™$_<‰$<™,d<‰,<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o™3I<‰&‰3<™0d<‰0<™+d™PF<‰+‰P<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d™3I<‰&‰3<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d™3P<‰$‰,‰34™*W<‰*<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™*J™QA<‰*‰Q<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™3P<‰$‰*‰34™.d<‰.<™$P™QA<‰$‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k™3I<‰&‰3<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd™3I<‰$‰&‰P‰3<™$d™1d<‰$‰14™*W<‰*<™QA™*J<‰Q‰*<™&d™3I<‰&‰3<™PF<‰P<™*L<‰*<™$_<‰$<™*d™3P<‰*‰34™$d<‰$<™QA™*J<‰Q‰*<™&d™3I<‰&‰3<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S™1d<‰$‰*‰14™.d<‰.<™QA<‰Q<™&d™,d™3I<‰&‰,‰3<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d™3P<‰*‰34™$d™*?<‰$‰*<™QA™*T<‰Q‰*<™&d™3I<‰&‰3<™PF™*D<‰P‰*<™.d<‰.<™$F<‰$<™$d™1d<‰$‰1<™&K<‰&<™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P4™&K<‰&<™$d™1d<‰$‰1<™&K<‰&<™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P4™&K<‰&<™7d™$d™2d<‰7‰$‰2™2Z<‰2™2Z<‰2™$F™0Z<‰$‰0<™QA™0d<‰Q‰0<™/Z<‰/<™PF™/d<‰P‰/<™+d™$F<‰+‰$<™&;<‰&<™$d<‰$<™&l™.d<‰&‰.<™$F<‰$<™QA<‰Q<™&z™,d™1d<‰&‰,‰14™PF<‰P<™&O<‰&<™*O<‰*ƒ$™*O<‰*ƒ$™*O<‰*ƒ$™*O<‰*4™$F<‰$4™7_™$d<‰7‰$ÙS_<‰SŽD™S_<‰SŽD™S_<‰SŽD™S_<‰S‡™*_<‰*ƒ$™*<<‰*ƒ$™S_™%F™*F<‰S‰%‰*ƒ$™,<<‰,ƒ$™*_<‰*ƒ$™*<<‰*ƒ$™S_™%F™*F<‰S‰%‰*ƒ$™,<<‰,4™*<<‰*4™*_<‰*ƒ$™*<<‰*ƒ$™S_™%F™*F<‰S‰%‰*ƒ$™,<<‰,ƒ$™*_<‰*ƒ$™*<<‰*ƒ$™S_™%F<‰S‰%‚,™$F<‰$<™,<™&F<‰,‰&4™*F™$F<‰*‰$<™*<<‰*<™$_™*_<‰$‰*ƒ$™*<<‰*ƒ$™&P™S_™$_<‰&‰S‰$ƒ$™$F™,<<‰$‰,ƒ$™$_™*_<‰$‰*ƒ$™*<<‰*ƒ$™&P™S_™$_<‰&‰S‰$ƒ$™._<‰.ƒ$™$_™,<™&_™1_<‰$‰,‰&‰1‚,™$_<‰$<™&P<‰&4™$_<‰$4™$_™&_<‰$‰&4™$F<‰$4™&P<‰&4™$F™&_<‰$‰&<™&P<‰&<™$_™4_<‰$‰44™&_<‰&<™&_<‰&<™$_™2_<‰$‰2<™2_<‰2<™0_<‰0<™0_<‰0<™$_™3_<‰$‰3<™/_™._<‰/‰.<™+_<‰+<™$_™,_<‰$‰,<™7_™&_<‰7‰&<™&_<‰&<™$_™._<‰$‰.4™$_™1_™,_™&_<‰$‰1‰,‰&4™&n<‰&4™$_™2_<‰$‰2<™2_<‰2<™0_<‰0<™&_<‰&<™$_™7_<‰$‰7<™+_<‰+<™$_™._<‰$‰.4™$_™4_™,_<‰$‰4‰,™*_<‰*™*C<‰*™*=<‰*<™&_<‰&<™$d™1_<‰$‰14™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™*K<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™*7<‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™*7<‰*<™&_™3P<‰&‰34™*U<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*<™*7<‰*<™&_™3P<‰&‰34™.d<‰.<™$F<‰$<™$d™3b™,K<‰$‰3‰,4™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™$F™*K<‰$‰*4™$d™3Z™*U<‰$‰3‰*4™*U<‰*4™&_™3P<‰&‰34™$F™*7<‰$‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™$P™*7<‰$‰*<™&_™3P<‰&‰34™$_™*U<‰$‰*<™&F<‰&<™3Z™*U<‰3‰*<™&F<‰&<™$d™*U<‰$‰*<™*7<‰*<™&_™._™3P<‰&‰.‰34™.d<‰.<™&F™$F<‰&‰$<™1_™$d™,_<‰1‰$‰,4™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™*K<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™*7<‰*<™*7<‰*<™$d™3b<‰$‰34™*K<‰*<™*7<‰*<™&_™3P<‰&‰34™*U<‰*<™$_<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*<™*7<‰*<™&_™3P<‰&‰34™.d<‰.<™$F<‰$<™$d™3b<‰$‰34™*d<‰*<™*K<‰*<™&_™3P<‰&‰34™$_™*K<‰$‰*<™$F<‰$<™3Z™*U<‰3‰*4™$d™*U<‰$‰*4™&_™3P<‰&‰34™$F™*7<‰$‰*<™*7<‰*<™$_™7_<‰$‰7<™2P<‰24™&F™2_<‰&‰2<™&_™$_<‰&‰$<™0_<‰0<™&F™0P<‰&‰0<™&7<‰&<™&_™$_<‰&‰$™0_<‰0™/_<‰/™+_<‰+<™$_™*U<‰$‰*<™&_™4_<‰&‰4<™*7<‰*<™._<‰.4™1_™,_™$_<‰1‰,‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™3b™$_<‰3‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™*U<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™$F<‰$<™3b™$_<‰3‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™3b™$_<‰3‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™$U™*U<‰$‰*<™&F<‰&<™3Z™*U<‰3‰*<™&F<‰&<™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™&F<‰&<™1b™$_<‰1‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™*K<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*4™3P™&_<‰3‰&4™*7<‰*<™*7<‰*<™1b™$_<‰1‰$4™*K<‰*<™*7<‰*<™3P™&_<‰3‰&4™*U<‰*<™$U<‰$<™3Z™*U<‰3‰*4™$b™*U<‰$‰*<™*7<‰*<™3P™&_<‰3‰&4™.d<‰.<™&F™$F<‰&‰$<™1b™$_<‰1‰$4™*d<‰*<™*K<‰*<™3P™&_<‰3‰&4™$U™*K<‰$‰*<™&F<‰&<™1Z™$b™*U<‰1‰$‰*4™2_<‰2<™2_<‰2<™3P™0_™$b<‰3‰0‰$<™0_<‰0<™+_<‰+<™$F<‰$<™$_™1n<‰$‰14™*d<‰*<™$_<‰$<™&_™7P<‰&‰74™$_<‰$<™*d<‰*<™$_™7n<‰$‰7<™&_™*U<‰&‰*<™/F<‰/™+F<‰+™+F<‰+™&n™4n™7P<‰&‰4‰7<™$_<‰$<™.d<‰.<™+_<‰+<™$d™1d™7d<‰$‰1‰74™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™5d<‰$‰54™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™.d™PF<‰.‰P<™$_<‰$<™,d<‰,<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o<‰&<™0d™PF<‰0‰P<™+d<‰+<™$F™&n<‰$‰&<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™$P™QA<‰$‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&k<‰&<™&T™*D™PF<‰&‰*‰P<™.d<‰.<™$F™&n™Pd<‰$‰&‰P<™$d™1d<‰$‰14™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™*S<‰$‰*4™.d<‰.<™QA<‰Q<™&d™,d<‰&‰,<™PF<‰P<™*[<‰*<™$_™*=<‰$‰*<™*d<‰*4™$d™*?<‰$‰*<™*T™QA<‰*‰Q<™&d<‰&<™*D™PF<‰*‰P<™.d<‰.<™$F<‰$<™$d™,d<‰$‰,4™*W<‰*<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*L<‰*<™$_<‰$<™*d<‰*4™$d<‰$<™*J™QA<‰*‰Q<™&d<‰&<™PF<‰P<™*X<‰*<™*B<‰*<™$d™7d<‰$‰7<™&d<‰&<™&d<‰&<™$P™QA<‰$‰Q<™&d<‰&<™PF<‰P<™$_<‰$<™&d<‰&<™*d<‰*<™$d<‰$<™*?<‰*<™2d™QA<‰2‰Q<™&o™4d<‰&‰4<™0d<‰0<™+d™PF<‰+‰P<™$F™&n<‰$‰&<™$d™1d<‰$‰1¤ ™<‰ÿ/MTrk*ÿFXÿ!ÿD---- System Setup --------------------------------------------------<ÿ@---- CH Setup --------------------------------------------------ºyºº ÊPº @ºdº[º ººeºdº@º&ºeºdº@ºeºdº ê@ºeºdÿG---- End of CH Setup --------------------------------------------------Ù^º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠTÚ<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT„É<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠTÚ<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT‚<º `šašU<ŠaŠU<º šašU<ŠaŠU<º `ša%šU%<ŠaŠU<º ša+šU+<ŠaŠU<º `ša1šU1<ŠaŠU<º ša6šU6<ŠaŠU<º `šaDšUD<ŠaŠU<º šaRšUR<ŠaŠU<º `šafšUf<ŠaŠU<º šaXšUX<ŠaŠU<º `šaQšUQ<ŠaŠU<º šaJšUJ<ŠaŠU<º `šaDšUD<ŠaŠU<º ša>šU><ŠaŠU<º `ša8šU8<ŠaŠU<º ša3šU3<ŠaŠU<º `ša.šU.<ŠaŠU<º ša)šU)<ŠaŠU<º `ša%šU%<ŠaŠU<º ša šU <ŠaŠU<º `šašU<ŠaŠU<º šašU<ŠaŠU<º `šašU<ŠaŠU<º šašU<ŠaŠU„”|º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠTÚ<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`%šT%<Š`ŠT<º š`+šT+<Š`ŠT<º `š`1šT1<Š`ŠT<º š`6šT6<Š`ŠT<º `š`DšTD<Š`ŠT<º š`RšTR<Š`ŠT<º `š`fšTf<Š`ŠT<º š`XšTX<Š`ŠT<º `š`QšTQ<Š`ŠT<º š`JšTJ<Š`ŠT<º `š`DšTD<Š`ŠT<º š`>šT><Š`ŠT<º `š`8šT8<Š`ŠT<º š`3šT3<Š`ŠT<º `š`.šT.<Š`ŠT<º š`)šT)<Š`ŠT<º `š`%šT%<Š`ŠT<º š` šT <Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT<º `š` šT <Š`ŠT<º š` šT <Š`ŠT<º `š` šT <Š`ŠT<º š`šT<Š`ŠT<º `š`šT<Š`ŠT<º š`šT<Š`ŠT¿)ÿ/simutrans-124.3/simutrans/music/53-Where-Thomassons-Lie.mid000066400000000000000000000506141474050137200235630ustar00rootroot00000000000000MThd àMTrk\ÿXÿYÿT ÿQ¯*xÿ1ÿXÿQ¯*­xÿ2­xÿ3­xÿ4 ­xÿ5 ­xÿ6­xÿ7ÿ/MTrk‘ÿXÿInst 1x° À ° P?PZ;4‘?Z>4‘>Z?4‘?Z>4‘AZ?<‘?ZA<‘>Z?4‘:Z>4‘6Z:4‘4Z64‘3Z4<‘1Z3<‘7Z14‘8Z74‘7Z84‘8Z74‘:Z8<‘;Z:<‘7Z;4‘8Z74‘7Z8x‘7Z7x‘8Z7x‘:Z8<‘;Z:<‘7Z;x‘8Z7x‘:Z8<‘;Z:x‘7Z;<‘8Z7x‘:Z8<‘;Z:x‘=Z;x‘?Z=<‘@Z?<‘?Z@<‘=Z?<‘?Z=4‘=Z?4‘;Z=4‘:F;x‘8F:<‘7F8x‘:F7<‘;F:<‘:F;x‘:F:x‘:F:x‘8F:<‘5F8x‘6F5<‘5F64‘6F54‘6F6x‘6F6x‘:F6<‘7F:4‘8F74‘7F84‘5F74‘3F5<‘7F3x‘7F7x‘3F74‘7F34‘3F74‘1F3<‘3F1<‘.F3<‘/F.x‘7F/<‘;F7x‘.F;<‘;F.x‘;F;x‘;F;<‘xÂI² $­x’OP† ‚O(’KP† ‚K(’QP† ‚Q(’OP…<‚O’MPp’SP‚M„X’UP‚SH‚U(’OPR‚O’MP„X‚Mx’KPp’DP‚K‚@‚D(’BH† ‚B(’HH† ‚H(’GH† ‚G(’FH‚h’KH‚F‚h’PH‚K‚h’OH‚Pp’PH‚Ox’KH‚P‚h’JH‚Kp’KH‚Jx’UH‚Kp’KH‚Ux’UH‚Kp’OH‚Ux’NH‚Ox’OH‚N<’LH‚O<’KH‚L<’DH‚K<’CH‚D<’DH‚C<’BP‚D<’CP‚B<’PP‚Cx‚P<’NP<’KP‚N<‚K<’IP<’UP‚Ix’NP‚U<’UP‚N<’NP‚U<’MP‚N<’NP‚M<’ZP‚Nx‚Z<’TP<’ZP‚T<’TP‚Z<’SP‚Tx’RP‚S<’NP‚R<’DP‚N<’EP‚D<’CP‚E<’PP‚C<’OP‚P<’KP‚O<’JP‚K<’KP‚J<‚K<’IP<’UP‚I<’TP‚U<’OP‚T<’NP‚O<’OP‚N<‚O<’LP<’TP‚L<’XP‚T<’HP‚Xx’OP‚H<’[P‚O<’OP‚[<’HP‚Ox’OP‚H<’[P‚O<’OP‚[<’XP‚O<’GP‚X<’WP‚G<’PP‚Wx’OP‚P<’PP‚O<‚P<’PP<‚P<’PP<’OP‚P<’PP‚O<’LP‚Px’KP‚L<’LP‚K<’UP‚L4’SP‚U4’RP‚S<’SP‚R<’PP‚S<’QP‚P<’PP‚Q<’OP‚P<‚O<’PP<’QP‚P<’PP‚Q<’OP‚P<’LP‚O<‚L<’KP<’LP‚K<’PP‚L<’OP‚P<’KP‚O<’IP‚K<’JP‚I<’RZ‚J4’SZ‚R4’RZ‚S4’SZ‚R4’UZ‚S<’SZ‚U<’VZ‚S4’WZ‚V4’VZ‚W4’WZ‚V4’YZ‚W<’WZ‚Y<’VZ‚W4’RZ‚V4’NZ‚R4’LZ‚N4’KZ‚L<’IZ‚K<’OZ‚I4’PZ‚O4’OZ‚P4’PZ‚O4’RZ‚P<’SZ‚R<’OZ‚S4’PZ‚O4’OZ‚P<‚O<’OZx’PZ‚Ox’RZ‚P<’SZ‚R<’OZ‚Sx’PZ‚Ox’RZ‚P<’SZ‚R<‚S<’OZ<’PZ‚Ox’RZ‚P<’SZ‚R<‚S<’UZx’WZ‚U<’XZ‚W<’WZ‚X<’UZ‚W<’WZ‚U ‚W’UZ ‚U’SZ ‚S’RFx’PF‚R<’OF‚Px’RF‚O<’SF‚R<’RF‚Sd‚R’RFd‚R’RFd‚R’PF<’MF‚Px’NF‚M<’MF‚Nx‚M<’NFx‚N<’NFd‚N’NFd‚N’RF<’OF‚R4’PF‚O4’OF‚P4’MF‚O4’KF‚M<’OF‚Kn‚O ’OFx’KF‚O‚K’OF‚O’KF‚K’IF<’KF‚I<’FF‚K<’GF‚Fn‚G ’OF<’SF‚Od‚S’FF<’SF‚FZ‚S’SFZ‚S’SF(‚S’TF<’PF‚T<’UF‚Pi‚U’SFd‚S’RF<’PF‚R<‚P<’UF ‚U’SFx’RF‚S<’XF‚R ‚X’WF ‚W’UF ‚U’SF<’JF‚Sd‚J’SF<’JF‚SZ‚J’KP4’NP‚K4’KP‚N4’NP‚K4’PP‚N<’QP‚P<’OP‚Q4’PP‚O4’OP‚P4’PP‚O4’RP‚P<’SP‚R<’PP‚S<’QP‚P<’RP‚Q<’SP‚R<‚S<’PP<’SP‚P<‚S<’PP<’SP‚P<‚S<’PP<’SP‚P<’TP‚S<’UP‚T4’SP‚U4’UP‚S4’SP‚U4’RP‚S<’PP‚R<’OP‚P<’UP‚O<’WP‚U<’OP‚Wx’KP‚Ox’WP‚Kx’KP‚W<’WP‚K<’UP‚W<’SP‚U<’RP‚S<’PP‚R<’OP‚P<’PP‚O<’SP‚P4’RP‚S4‚R<’PP4‚Px’OP<’PP‚Ox’OP‚P<’PP‚O<’RP‚P<’SP‚R<’OP‚S<’PP‚O<‚P<’PP‚Pÿ/MTrkÛÿHÿInst 1xÃ<° oÛp“CP† ƒC(“?P† ƒ?(“EP† ƒE(“CP…<ƒC“APp“GPƒA„X“IPƒGHƒI(“CPRƒC“AP„XƒAx“?Pp“8Pƒ?‚@ƒ8(“6H† ƒ6(“Hƒ?p“?Hƒ>x“IHƒ?p“?HƒIx“IHƒ?p“CHƒIx“BHƒCx“CHƒB<“@HƒC<“?Hƒ@<“8Hƒ?<“7Hƒ8<“8Hƒ7<“6Pƒ8<“7Pƒ6<“DPƒ7xƒD<“BP<“?PƒB<ƒ?<“=P<“IPƒ=x“BPƒI<“IPƒB<“BPƒI<“APƒB<“BPƒA<“NPƒBxƒN<“HP<“NPƒH<“HPƒN<“GPƒHx“FPƒG<“BPƒF<“8PƒB<“9Pƒ8<“7Pƒ9<“DPƒ7<“CPƒD<“?PƒC<“>Pƒ?<“?Pƒ><ƒ?<“=P<“IPƒ=<“HPƒI<“CPƒH<“BPƒC<“CPƒB<ƒC<“@P<“HPƒ@<“LPƒH<“Pƒ=<“FZƒ>4“GZƒF4“FZƒG4“GZƒF4“IZƒG<“GZƒI<“JZƒG4“KZƒJ4“JZƒK4“KZƒJ4“MZƒK<“KZƒM<“JZƒK4“FZƒJ4“BZƒF4“@ZƒB4“?Zƒ@<“=Zƒ?<“CZƒ=4“DZƒC4“CZƒD4“DZƒC4“FZƒD<“GZƒF<“CZƒG4“DZƒC4“CZƒD<ƒC<“CZx“DZƒCx“FZƒD<“GZƒF<“CZƒGx“DZƒCx“FZƒD<“GZƒF<ƒG<“CZ<“DZƒCx“FZƒD<“GZƒF<ƒG<“IZx“KZƒI<“LZƒK<“KZƒL<“IZƒK<“KZƒI ƒK“IZ ƒI“GZ ƒG“FFx“DFƒF<“CFƒDx“FFƒC<“GFƒF<“FFƒGdƒF“FFdƒF“FFdƒF“DF<“AFƒDx“BFƒA<“AFƒBxƒA<“BFxƒB<“BFdƒB“BFdƒB“FF<“CFƒF4“DFƒC4“CFƒD4“AFƒC4“?FƒA<“CFƒ?nƒC “CFx“?FƒCƒ?“CFƒC“?Fƒ?“=F<“?Fƒ=<“:Fƒ?<“;Fƒ:nƒ; “CF<“GFƒCdƒG“:F<“GFƒ:ZƒG“GFZƒG“GF(ƒG“HF<“DFƒH<“IFƒDiƒI“GFdƒG“FF<“DFƒF<ƒD<“IF ƒI“GFx“FFƒG<“LFƒF ƒL“KF ƒK“IF ƒI“GF<“>FƒGdƒ>“GF<“>FƒGZƒ>ÿ/MTrk1ÿEÿInst 1xÄE´ E‰h”OP† „O(”KP† „K(”QP† „Q(”OP…<„O”MPp”SP„M„X”UP„SH„U(”OPR„O”MP„X„Mx”KPp”DP„K‚@„D(”BH† „B(”HH† „H(”GH† „G(”FH‚h”KH„F‚h”PH„K‚h”OH„Pp”PH„Ox”KH„P‚h”JH„Kp”KH„Jx”UH„Kp”KH„Ux”UH„Kp”OH„Ux”NH„Ox”OH„N<”LH„O<”KH„L<”DH„K<”CH„D<”DH„C<”BP„D<”CP„B<”PP„Cx„P<”NP<”KP„N<„K<”IP<”UP„Ix”NP„U<”UP„N<”NP„U<”MP„N<”NP„M<”ZP„Nx„Z<”TP<”ZP„T<”TP„Z<”SP„Tx”RP„S<”NP„R<”DP„N<”EP„D<”CP„E<”PP„C<”OP„P<”KP„O<”JP„K<”KP„J<„K<”IP<”UP„I<”TP„U<”OP„T<”NP„O<”OP„N<„O<”LP<”TP„L<”XP„T<”HP„Xx”OP„H<”[P„O<”OP„[<”HP„Ox”OP„H<”[P„O<”OP„[<”XP„O<”GP„X<”WP„G<”PP„Wx”OP„P<”PP„O<„P<”PP<„P<”PP<”OP„P<”PP„O<”LP„Px”KP„L<”LP„K<”UP„L4”SP„U4”RP„S<”SP„R<”PP„S<”QP„P<”PP„Q<”OP„P<„O<”PP<”QP„P<”PP„Q<”OP„P<”LP„O<„L<”KP<”LP„K<”PP„L<”OP„P<”KP„O<”IP„K<”JP„I<”RZ„J4”SZ„R4”RZ„S4”SZ„R4”UZ„S<”SZ„U<”VZ„S4”WZ„V4”VZ„W4”WZ„V4”YZ„W<”WZ„Y<”VZ„W4”RZ„V4”NZ„R4”LZ„N4”KZ„L<”IZ„K<”OZ„I4”PZ„O4”OZ„P4”PZ„O4”RZ„P<”SZ„R<”OZ„S4”PZ„O4”OZ„P<„O<”OZx”PZ„Ox”RZ„P<”SZ„R<”OZ„Sx”PZ„Ox”RZ„P<”SZ„R<„S<”OZ<”PZ„Ox”RZ„P<”SZ„R<„S<”UZx”WZ„U<”XZ„W<”WZ„X<”UZ„W<”WZ„U „W”UZ „U”SZ „Sÿ/MTrk¤ÿTÿInst 1xÅ:µ x·`•7P† …7(•3P† …3(•9P† …9(•7P…<…7•5Pp•;P…5„X•=P…;H…=(•7PR…7•5P„X…5x•3Pp•,P…3‚@…,(•*H† …*(•0H† …0(•/H† …/(•.H‚h•3H….‚h•8H…3‚h•7H…8p•8H…7x•3H…8‚h•2H…3p•3H…2x•=H…3p•3H…=x•=H…3p•7H…=x•6H…7x•7H…6<•4H…7<•3H…4<•,H…3<•+H…,<•,H…+<•*P…,<•+P…*<•8P…+x…8<•6P<•3P…6<…3<•1P<•=P…1x•6P…=<•=P…6<•6P…=<•5P…6<•6P…5<•BP…6x…B<•H†?p–?H†>x†?p–?Hx†?p–CHx–BH†Cx–CH†B<–@H†C<–?H†@<–8H†?<–7H†8<–8H†7<†8ÿ/MTrkÁÿBÿInst 1xÇ· ‚“P—CXOX† ‡CO(—?XKX† ‡?K(—EXQX† ‡EQ(—CXOX…<‡CO—AXMXp—GXSX‡AM„X—IXUX‡GSH‡IU(—CXOXR‡CO—AXMX„X‡AMx—?XKXp—8XDX‡?K‚@‡8Dÿ/MTrknÿPÿInst 1xÉ ™$P<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P1P‰&<™,P‰$1<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<™$P‰&<™,P‰$<™%P‰,<™$P‰%<™,P‰$<™%P‰,<™$P‰%<™%P‰$<™,P‰%<™$P.P‰,<‰$.<™$P,P<™(P‰$,<™&P‰(<‰&ÿ/simutrans-124.3/simutrans/music/music.tab000066400000000000000000000063511474050137200205350ustar00rootroot00000000000000# music.tab # Format: # 1. Path to file (relative to simutrans base dir) # 2. Song Title # 3. Song Composer # 4. Song Arranger(s). Set to "-" if none. music/01-Simutrans-Main-Theme.mid Main Theme shunter - music/02-Gotta-catch-that-train.mid Gotta catch that train shunter - music/03-Sunday-drivers.mid Sunday drivers shunter - music/04-Simutrans-B-Theme.mid Simutrans B Theme shunter - music/05-Boring-afternoon.mid Boring Afternoon shunter - music/06-A-busy-day-at-the-depot.mid A busy day at the depot shunter - music/07-Transport-chaos.mid Transport Chaos shunter - music/08-The-journey-home.mid The Journey Home shunter - music/09-Simupolitan-Swing.mid simupolitan swing Lmallet - music/10-Easy-driving.mid easy driving shunter - music/11-Stucked-Convoi.mid stucked convoi Lmallet - music/12-Steamin-across-the-prairies.mid Steamin' across the prairies shunter - music/13-Stephenson-blues.mid Stephenson blues shunter - music/14-Last-journey-of-the-Niagara.mid Last journey of the Niagara shunter - music/15-The-Wayside-Blues.mid The Wayside Blues Lmallet - music/16-Midnight-Express2.mid Midnight Express2 shunter - music/17-The-Benevolent-Dictators-March.mid The Benevolent Dictators March shunter - music/18-Ride-that-train.mid Ride that train shunter - music/19-Rockin-trucker.mid Rockin` trucker shunter - music/20-Last-Trip.mid Last Trip shunter - music/21-Dusty-Eyes.mid Dusty Eyes shunter - music/22-Variable-Journeys.mid Variable Journeys shunter - music/23-Something-for-Silver-Sand.mid Something for Silver Sand shunter - music/24-needlessly-striking.mid needlessly striking shunter - music/25-Float-on-by.mid Float on by shunter - music/26-Tantalizingly-Unusual.mid Tantalizingly Unusual shunter - music/27-March-Winds.mid March Winds shunter - music/28-Road-to-Warm-Places.mid Road to Warm Places shunter - music/29-Runaway.mid Runaway Lmallet - music/30-On-the-waterfront.mid On the waterfront shunter - music/31-Courtenay-Bridge.mid Courtenay Bridge Lmallet - music/32-incidental-skies.mid incidental skies shunter - music/33-Journey-to-times-gone-by.mid Journey to times gone by shunter - music/34-flyingaway.mid flying away Lmallet - music/35-deep-ride.mid deep ride shunter - music/36-faded-things.mid faded things shunter - music/37-inevitably-engrossed.mid inevitably engrossed shunter - music/38-positive-thrill.mid positive thrill shunter - music/39-bangin-mover.mid bangin mover shunter - music/40-alternative.mid alternative Marcos Maestro - music/41-Libertador.mid Libertador Marcos Maestro - music/42-Stranger-Echoes.mid Stranger Echoes (Multitrack slow) vilvoh shunter music/43-Driving-on-the-midnight-highway.mid Driving on the Midnight Highway Kayoko - music/44-Above-the-sky.mid Above the sky Kayoko - music/45-Misty-Forest.mid Misty Forest Gobanboshi Phystam, Reti_N music/46-House-in-the-station.mid House in the station Gobanboshi Phystam, Reti_N music/47-Salty-Breeze.mid Salty Breeze RykSeb - music/48-Techno-movement.mid Techno-movement RykSeb - music/49-Last-Sunday.mid Last Sunday RykSeb - music/50-Snowy-Road.mid Snowy Road anoKTOK RykSeb music/51-Summer-Intersection.mid Summer Intersection Gobanboshi Phystam, Reti_N music/52-Dreamy-Oriental-Nights.mid Dreamy Oriental Nights RykSeb - #music/53-Where-Thomassons-Lie.mid #Where Thomassons Lie #Shingoushori #- simutrans-124.3/simutrans/music/readme.txt000066400000000000000000000104501474050137200207160ustar00rootroot00000000000000You can put your own music files here. Edit music.tab to list them and Simutrans will read and play them. Credits: ---|---------------------------------|----------------|-----------------| Nº | Title | Composer | Arranger(s) | ---|---------------------------------|----------------|-----------------| 01 | Simutrans Main Theme | shunter | - | 02 | Gotta catch that train | shunter | - | 03 | Sunday drivers | shunter | - | 04 | Simutrans B Theme | shunter | - | 05 | Boring Afternoon | shunter | - | 06 | A busy day at the depot | shunter | - | 07 | Transport Chaos | shunter | - | 08 | The Journey Home | shunter | - | 09 | Simupolitan Swing | Lmallet | - | 10 | Easy Driving | shunter | - | 11 | Stucked Convoi | Lmallet | - | 12 | Streamin' Across the Prairies | shunter | - | 13 | Stephenson Blues | shunter | - | 14 | Last Journey of the Niagara | shunter | - | 15 | The Wayside Blues | Lmallet | - | 16 | Midnight Express 2 | shunter | - | 17 | The Benevolent Dictators March | shunter | - | 18 | Ride That Train | shunter | - | 19 | Rockin' Trucker | shunter | - | 20 | Last Trip | shunter | - | 21 | Dusty Eyes | shunter | - | 22 | Variable Journeys | shunter | - | 23 | Something for Silver Sand | shunter | - | 24 | Needlessly Striking | shunter | - | 25 | Float On By | shunter | - | 26 | Tantalizingly Unusual | shunter | - | 27 | March Winds | shunter | - | 28 | Road to Warn Places | shunter | - | 29 | Runaway | Lmallet | - | 30 | On the Waterfront | shunter | - | 31 | Courteay Bridge | Lmallet | - | 32 | Incidental Skies | shunter | - | 33 | Journey to Times Gone By | shunter | - | 34 | Flying Away | Lmallet | - | 35 | Deep Ride | shunter | - | 36 | Faded Things | shunter | - | 37 | Inevitably Engrossed | shunter | - | 38 | Positive Thrill | shunter | - | 39 | Banging Mover | shunter | - | 40 | Alternative | Marcos Maestro | - | 41 | Libertador | Marcos Maestro | - | 42 | Stranger Echoes | vilvoh | shunter | 43 | Driving on the Midnight Highway | Kayoko | - | 44 | Above the Sky | Kayoko | - | 45 | Misty Forest | Gobanboshi | Phystam, Reti_N | 46 | House in the Station | Gobanboshi | Phystam, Reti_N | 47 | Salty Breeze | RykSeb | - | 48 | Techno-movement | RykSeb | - | 49 | Last Sunday | RykSeb | - | 50 | Snowy Road | anoKTOK | RykSeb | 51 | Summer Intersection | Gobanboshi | Phystam, Reti_N | 52 | Dreamy Oriental Nights | RykSeb | - | 53 | Where Thomassons Lie | Shingoushori | - | ---|---------------------------------|----------------|-----------------| Musical Project Leader from songs 43 to 53: Reti_N. simutrans-124.3/simutrans/problem_report.txt000066400000000000000000000015441474050137200214000ustar00rootroot00000000000000This is a form for reporting problems with Simutrans. Please report any problems, crashes, and bugs to the forum https://forum.simutrans.com Try to provide as much information as possible. The following list may serve as a guide line: 1.) System specs (CPU, memory, graphics, sound, operating system, preferred screen resolution): -> 2.) Simutrans version: -> 3.) Description of the found problem: -> 4.) How can this problem be reproduced? (Note: if the problem can't be reproduced, there is only a very small chance that it can be fixed.) -> 5.) What did you/the game do when the problem occurred? (Only needed if (4) is left blank.) -> 6.) Effect on gameplay of the found problem? -> 7.) Did you discover a workaround for the problem? -> 8.) Severity of the problem/urgency to fix it? (One of high, medium, low or a more detailed description) -> simutrans-124.3/simutrans/readme.txt000066400000000000000000000231201474050137200175740ustar00rootroot00000000000000----------------------------------------------------------------------------- The most common error is the attempt to start the program without installing a graphics set. This is not possible! *** PLEASE MAKE SURE TO HAVE INSTALLED A PAK-SET TOO! *** Simutrans cannot start without the graphics in the pak set! ----------------------------------------------------------------------------- The purpose of this document is to explain the configuration options of Simutrans. There are currently two styles of options: 1) entries in the simuconf.tab file 2) command line options Simuconf.tab ------------ Simuconf.tab contains a rather large number of general configuration settings for Simutrans. Simuconf.tab can be found at several locations. First searched is config/simuconf.tab. Next is pak/config/simuconf.tab (or whatever pak-path your specified. Finally, simutrans/simuconf.tab in your home directory ("My Documents" under Windows resp. "~" under Unix). It is a text file and can be edited with a text editor. Each entry has a comment explaining what the entry is good for and what values are allowed for this entry. cityrules.tab ------------- cityrules.tab is either located pak/config/cityrules.tab or in simutrans/cityrules.tab in your user directory. It is a text file and can be edited with a text editor. cityrules.tab contains the set of rules which determines the extension of towns during city growth. There are two city related settings in the top, the minimum distance between cities (minimum_city_distance) and the step whenever a new industry will be founded (industry_increase_every). Set this to zero, if no new industry should be founded during a game. The actual rules are of two types: house building rules and road building rules. Each rule has a probability (house_xyz.chance) between -1 and -7 and a square with describes allowed surroundings for this house rule. The square is composed by ASCII rows, with each symbol standing for: S = must not be road s = must be road n = must be bare land H = must not be house h = must be house T = must not be a stop t = must be a stop U = way must not be buildable on slope u = way must be buildable on slope . = matches anything Simutrans command line options ------------------------------ Alphabetical list of options: -addons -announce -debug n=1..4 -freeplay -fullscreen -help -lang en -load bla[.sve] -log n=0|1 -noaddons -nomidi -nosound -objects path/ -pause -res n=1..5 -screensize 600x350 -server -server_dns IP/name -server_name text -server_admin_pw pwd -singleuser -timeline n=0|1 -use_workdir Detailed Description -------------------- 1.) Choose a resolution: 1a.) Choose a 'standard' resolution simutrans -res n where n is one of 1,2,3,4,5 The switch -res chooses the resolution at program start: 1 = 640x480 2 = 800x600 3 = 1024x768 4 = 1280x1024 Resolution no. 5 runs Simutrans in a window instead of fullscreen mode (Windows version only) THIS SWITCH IS DEPRECATED AND ONLY KEPT FOR COMPATIBILITY! Please use -screensize WxH instead (see section 1b) ! Use this switch at your own risk! Using a wrong resolution may damage your monitor! Up to date monitors should support all resolutions, but older monitors may have problems with the higher resolution settings. Don't expect all resolutions to be available with your graphics card. The program will abort the starting process if the graphics card doesn't support the chosen resolution. The default resolution was 640x480. Simutrans version 0.78.4 and newer have a default resolution of 800x600. Please note that bigger resolutions slow down the game. If Simutrans runs too slowly on your system, use a smaller screen resolution. Windowed mode (-res 5 on Windows) may be slower than fullscreen, but this depends strongly on your resolution and machine. 1b.) Choose an arbitrary resolution simutrans -screensize 900x400 More general the syntax is -screensize WIDTHxHEIGHT where width and height are integral values separated by a small x. This format is strict. Simutrans will not tolerate spaces or other format elements. I suggest only to use widths being a multiple of 16 and even heights, other may cause problems. Full screen support by -fullscreen. Use with care! I'm sure you can screw up things if you use values which are not supported by your system. Use on your own risk ... i.e. using -screensize 1600x1400 might damage your monitor if the graphics card switches to that resolution, but your monitor cannot! I give absolutely no warranty for any results of using that option!!! Please note that if width is set below 640, parts of the toolbar will not be visible and can't be used. In general setting width to less than 640 and height to less than 400 will most likely cause trouble ... the program does not check the values! As said above, use with care, no warranties are given! 2.) Copy output messages into a logfile: simutrans -log 1 This writes all messages which are output after the game switches to graphics mode to a file named "simu.log". This file might be helpful when reporting problems, you might consider to log a replay of the problem and attach the log file to your bug report at the simutrans forum. Please zip (compress) large log files before sending them. Don't forget your explanation of the problem is much more important than the log file when reporting problems. The -debug switch turns on additional debug messages. The recommended combination is "-log 1 -debug 3" Behind -debug you can give a debug level. 1 only errors [default], 2 logs also warnings, 3 all messages and 4 will generate a division by zero on a fatal error to allow for a backtrace. 3.) Run Simutrans in free playing mode (bankrupt check turned off): simutrans -freeplay 4.) Getting help simutrans -h simutrans -? simutrans -help simutrans --help All print a quick help message, which contains all supported command line options. 5.) starting a server (without port number, it will be on port 13353 simutrans -server [portnr] It is recommended to start server-games without addons with the pak set without modifications. If you want to announce your server, you need to supply a valid dns name or IPv4 or IPv6 [] number via the commandline option like "-server_dns myserver.homunix.org:13355" Similarly you can set server name via -server_name "Testserver". More server related settings can be specified in simuconf.tab. 6.) Use alternative PAK files If you have an alternative PAK file set for Simutrans, such as the winter scenario, you can use the following command line argument: simutrans -objects winter_pak/ [-addons|-noaddons] "winter_pak" is the directory where the PAK files are stored. Use the name of your setup instead! The trailing slash is mandatory. If you have a non-portable installation (i.e. no single user mode), then you can have additional add-ons in your personal simutrans directory. That way those are kept, when updating the main pak sets. You can additionally specify "-addons" or "-noaddons" to force loading or prevent addons to be loaded with a pakset. This overrides the setting in simuconf.tab. "-noaddons" is default. If you specify "-use_workdir" the simutrans environment from the current directory will be taken. Otherwise simutrans will take the environment from the directory where the executable is located. 7) Turn sound and music off (as of Simutrans 0.81.23exp) 7a) Turn sound off simutrans -nosound 7b) Turn music off simutrans -nomidi This also helps if Simutrans crashes on startup due to buggy or incompatible sound drivers. This is a problem especially in 64 bit Linux. 8) Switch on/off multiplayer -singleuser Will not search for files in your home directory. Simutrans will write all files in its data directory (usually the same directory as the directory containing the executable), which must not be write protected. 9) Timeline and startyear Example: simutrans -timeline 1 -startyear 1950 9b) Timeline simutrans -timeline <1 or 0> 0 = all vehicles are available from the start of the game 1 = More realistic. In 1930 are only some historical vehicles available. New vehicles will be introduced from time to time. Example: simutrans -timeline 1 -startyear 1930 Default value: setting use_timeline in simuconf.tab 9b) Start year simutrans -startyear Sets the starting year of the game Example: simutrans -timeline 1 -startyear 1950 Default value : setting starting_year in simuconf.tab 10) load a game and do not show the initial window simutrans -load mygame.sve If you use -pause, then the loaded game will be paused. Same would happen as a server when using the pause without connections feature. 11) define a language on startup using the iso codes simutrans -lang en All the above mentioned options can be combined, i.e. simutrans -res 2 -log -objects winter_pak/ runs Simutrans in test mode, writes output to "simu.log", switches to a resolution of 800x600 pixels and uses the winter pak files. Not all options are available on all platforms, i.e. -async and -net are only supported on Linux/X-Windows. If you run into problems, or if you have questions, please visit the feedback forum: https://forum.simutrans.com/ Suggestions how to improve Simutrans are also always welcome. If you're unsure how to report problems or change request, there are two example forms packaged with simutrans. Use "problem_report.txt" for problem reports and "change_request.txt" for change requests if you send reports by email. There are some Simutrans related web pages, you may want to visit them: The official Simutrans home page: https://www.simutrans.com This readme file was written by Hansjörg Malthaner, November 2000, Updated 8-Sep-2010 by Markus Pristovsek Last update 16-Dec-2011 by Dwachs simutrans-124.3/simutrans/script/000077500000000000000000000000001474050137200171045ustar00rootroot00000000000000simutrans-124.3/simutrans/script/ai_base.nut000066400000000000000000000010301474050137200212110ustar00rootroot00000000000000/** * Base file for AI players */ /** * initialization, called when AI player starts * @param pl player number of our AI player */ function start(pl) { } /** * the heart-beat of the AI player, * called regularly, does not need to finish */ function step() { } /** * initialization, called when savegame is loaded * default behavior: calls start() * @param pl player number of our AI player */ function resume_game(pl) { start(pl) } /** * Happy New Month and Year! */ function new_month() { } function new_year() { } simutrans-124.3/simutrans/script/hm_lib/000077500000000000000000000000001474050137200203365ustar00rootroot00000000000000simutrans-124.3/simutrans/script/hm_lib/hm_bridge_tl.nut000066400000000000000000000025121474050137200235050ustar00rootroot00000000000000include("hm_lib/hm_global") include("hm_lib/hm_functions") include("hm_lib/hm_find_obj") include("hm_lib/hm_obj_selector") class hm_bridge_tl extends hm_base_tl { desc_name = null start = null ziel = null wtype = null constructor(d_name, s, z, wt = null) { desc_name = d_name start = coord3d(s[0],s[1],s[2]) ziel = coord3d(z[0],z[1],z[2]) wtype = wt hm_commands.append(this) } // returns [error_message, desc] // selector and finder are not available // because get_desc() does not exist for a bridge object. function _get_desc(){ local d = hm_get_bridge_desc(desc_name, wtype) if(d==null) { local message = format(translate("Bridge %s (%s) is not found!"), translate(desc_name), desc_name) return [message, null] } return [null, d] } function exec(player, origin) { local dr = _get_desc() if(dr[0]!=null) { return dr[0] // there was a error in obtaining the desc } local desc = dr[1] local err = command_x.build_bridge(player, origin+start, origin+ziel, desc) if(err!=null) { //calc_route() failed to find a path. local message = format(translate("Bridge building path from (%s) to (%s) is not found!"), (origin+start).tostring(), (origin+ziel).tostring()) return message } else { return null } } } simutrans-124.3/simutrans/script/hm_lib/hm_city_tl.nut000066400000000000000000000035351474050137200232270ustar00rootroot00000000000000include("hm_lib/hm_global") class hm_city_tl extends hm_base_tl { population = 0 desc_name = 0 pos = null rotation = 0 constructor(pop, dn, p, r) { population = pop desc_name = dn pos = coord3d(p[0],p[1],0) rotation = r hm_commands.append(this) } function exec(player, origin) { local tp = origin + pos local tile = square_x(tp.x,tp.y).get_ground_tile() if(tile) { return command_x(tool_add_city).work(player, tile, format("%d,%s,%d", population, desc_name, rotation)) } return "No suitable ground!" } } class hm_city_set_population_tl extends hm_base_tl { pos = null population = 0 constructor(pop, p) { pos = coord(p[0],p[1]) population = pop hm_commands.append(this) } function exec(player, origin) { local tp = origin+pos local tile = square_x(tp.x,tp.y).get_ground_tile() if(tile) { return command_x(tool_change_city_size).work(player, tile, format("%d", population)) } return "No suitable ground!" } } class hm_set_owner_tl extends hm_base_tl { pos = null ownerid = 0 has_z = false constructor(o, p) { pos = coord3d(p[0],p[1],0) if(p.len()>2) { pos.z = p[2] has_z = true } ownerid = o hm_commands.append(this) } function exec(player, origin) { local tp = origin+pos local tile = square_x(tp.x, tp.y).get_tile_at_height(tp.z) if(tile == null && !has_z) { tile = square_x(tp.x, tp.y).get_ground_tile() } if(tile) { local pl = player_x(ownerid) return command_x(tool_set_owner).work(player, tile, format("%d,0",ownerid)) // foreach(obj in tile.get_objects()) { // // owner to0l // } } if(tile.has_ways() && ownerid == 15) { // no way to convert to pavement roads right now } return null } } simutrans-124.3/simutrans/script/hm_lib/hm_depot_tl.nut000066400000000000000000000035431474050137200233710ustar00rootroot00000000000000include("hm_lib/hm_global") class hm_depot_tl extends hm_base_tl { desc = null desc_name = null pos = null wtype = null constructor(sta_name, p, wt = null) { desc_name = sta_name pos = coord3d(p[0],p[1],p[2]) wtype = wt // find descriptor /* foreach (d in building_desc_x.get_building_list(building_desc_x.depot)) { if(d.get_name()==desc_name) { desc = d break } }*/ hm_commands.append(this) } // returns [error_message, desc] function _get_desc(){ if(desc_name.slice(0,2)=="?f") { local key_str = "d" + desc_name.slice(2) local d = hm_found_desc.get(key_str) if(d==null) { local message = format(translate("Depot key %s is not defined."), desc_name.slice(2)) return [message, null] } else if(d[0]==null) { local message = format(translate("No depot was detected between %s."), hm_found_desc.get_pos_str(key_str)) return [message, null] } return [null, d[0]] } else if(desc_name.slice(0,2)=="?s") { local idx = desc_name.slice(2).tointeger() local d = hm_depot_selector().get_desc(idx) if(d==null) { local message = format(translate("Selected depot %s is not available."), desc_name.slice(2)) return [message, null] } return [null, d] } else { local d = hm_get_building_desc(desc_name, wtype, building_desc_x.depot) if(d==null) { local message = format(translate("Depot %s (%s) is not found!"), translate(desc_name), desc_name) return [message, null] } return [null, d] } } function exec(player, origin) { local dr = _get_desc() if(dr[0]!=null) { return dr[0] // there was a error in obtaining the desc } local desc = dr[1] return command_x.build_depot(player, origin+pos, desc); } } simutrans-124.3/simutrans/script/hm_lib/hm_find_obj.nut000066400000000000000000000025761474050137200233360ustar00rootroot00000000000000include("hm_lib/lib_obj_finder_v2") // get(key) returns [desc, start_pos, end_pos] class hm_found_desc { found_descs = {} function set(key, desc, start, end) { found_descs[key] <- [desc, start, end] } function get(key) { if(key in found_descs) { return found_descs[key] } return null } function get_pos_str(key) { if(key in found_descs) { local e = found_descs[key] return "("+e[1][0]+","+e[1][1]+","+e[1][2]+") and ("+e[2][0]+","+e[2][1]+","+e[2][2]+")" } return null } } // key prefix: "w" function hm_find_way(key, start, end) { local desc = ObjFinder(player, [start, end]).findWay() hm_found_desc().set("w" + key, desc, start, end) } // key prefix: "s" function hm_find_sign(key, start, end) { local desc = ObjFinder(player, [start, end]).findSign() hm_found_desc().set("s" + key, desc, start, end) } // key prefix: "p" function hm_find_station(key, start, end) { local desc = ObjFinder(player, [start, end]).findPlatform() hm_found_desc().set("p" + key, desc, start, end) } // key prefix: "c" function hm_find_wayobj(key, start, end) { local desc = ObjFinder(player, [start, end]).findWayObj() hm_found_desc().set("c" + key, desc, start, end) } // key prefix: "d" function hm_find_wayobj(key, start, end) { local desc = ObjFinder(player, [start, end]).findDepot() hm_found_desc().set("d" + key, desc, start, end) } simutrans-124.3/simutrans/script/hm_lib/hm_functions.nut000066400000000000000000000137641474050137200235750ustar00rootroot00000000000000 this.hm_all_waytypes <- [wt_road,wt_rail,wt_water,wt_monorail,wt_maglev,wt_tram,wt_narrowgauge,wt_air,wt_power] this.hm_all_systemtypes <- [st_flat, st_elevated, st_tram, st_runway] function hm_get_way_desc(desc_name, wt, st) { local obj = null //gui.add_message_at(player, "hm_get_way_desc " + desc_name + " wt " + wt + " st " + st, world.get_time()) if ( wt == null || st == null ) { // not set waytype and/or systemtype // object not found, break script foreach(wt in hm_all_waytypes) { foreach (st in hm_all_systemtypes) { foreach (w in way_desc_x.get_available_ways(wt, st)) { if(w.get_name()==desc_name) { obj = w break } } } } } else { // set waytype and systemtype // object not available then replace local list = way_desc_x.get_available_ways(wt, st) foreach (w in list) { //gui.add_message_at(player, "w.get_name() " + w.get_name(), world.get_time()) if(w.get_name()==desc_name) { obj = w //gui.add_message_at(player, "found desc_name " + obj.get_name(), world.get_time()) break } if ( obj == null ) { obj = w //gui.add_message_at(player, "fallback " + obj.get_name(), world.get_time()) } } } return obj } function hm_get_bridge_desc(desc_name, wt) { local obj = null if ( wt == null ) { // not set waytype // object not found, break script foreach(wt in hm_all_waytypes) { foreach (b in bridge_desc_x.get_available_bridges(wt)) { if(b.get_name()==desc_name) { obj = b break } } } } else { // set waytype // object not available then replace local list = bridge_desc_x.get_available_bridges(wt) foreach (b in list) { if(b.get_name()==desc_name) { obj = b break } if ( obj == null ) { obj = b } } } return obj } function hm_get_sign_desc(desc_name, wt, sigtype) { local obj = null if ( wt == null || sigtype == null) { // not set waytype // object not found, break script foreach(wt in hm_all_waytypes) { foreach (s in sign_desc_x.get_available_signs(wt)) { if(s.get_name()==desc_name) { obj = s break } } } } else { // set waytype and signal type // object not available then replace local list = sign_desc_x.get_available_signs(wt) foreach (s in list) { if(s.get_name()==desc_name) { obj = s break } if ( obj == null ) { local found = false switch ( sigtype ) { case 1 : found = s.is_one_way() break case 2 : found = s.is_choose_sign() break case 4 : found = s.is_private_way() break case 8 : found = s.is_signal() break case 10 : // signal and choose found = s.is_choose_sign() break case 16 : found = s.is_pre_signal() break case 64 : found = s.is_longblock_signal() break case 128 : found = s.is_end_choose_signal() break case 256 : found = s.is_priority_signal() break case 512 : found = s.is_traffic_light() break default : // does not know how to handle that combination (like minimum speed and oneway) } if ( found ) { obj = s } } } } return obj } function hm_get_wayobjs_desc(desc_name, wt, overhead) { local obj = null if ( wt == null ) { // not set waytype // object not found, break script foreach(wt in hm_all_waytypes) { foreach (s in wayobj_desc_x.get_available_wayobjs(wt)) { if(s.get_name()==desc_name) { obj = s break } } } } else { // set waytype // object not available then replace local list = wayobj_desc_x.get_available_wayobjs(wt) foreach (s in list) { if(s.get_name()==desc_name) { obj = s break } if ( obj == null ) { obj = s } else if ( obj.get_topspeed() < 90 && s.get_topspeed() > 90 ) { obj = s } if ( overhead == 1 && !obj.is_overhead_line() ) { obj = null } } } return obj } /** * search player building object * * @param desc_name object name * @param wt waytype * @param building_type building_desc_x::building_type * * @todo harbour, flat_harbour, station_extension */ function hm_get_building_desc(desc_name, wt, building_type) { local obj = null local goods = {} local list = null if ( building_type == building_desc_x.depot ) { // depot list all waytypes list = building_desc_x.get_building_list(building_desc_x.depot) } else if ( wt != null && building_type == building_desc_x.station ) { // station list waytype and available list = building_desc_x.get_available_stations(building_desc_x.station, wt, goods) } if ( wt != null ) { // searche waytypes foreach (b in list ) { if(b.get_name()==desc_name && (b.is_available(world.get_time()) || world.use_timeline() == false) ) { obj = b break } if ( obj == null && (b.is_available(world.get_time()) || world.use_timeline() == false) ) { //gui.add_message_at(player, "waytype: " + b.get_waytype(), world.get_time()) if ( b.get_waytype() == wt ) { obj = b //gui.add_message_at(player, "fallback " + obj.get_name(), world.get_time()) } } } } if ( obj == null && wt == null && building_type == building_desc_x.station ) { // not set waytype -> 0 searches all ways foreach (b in building_desc_x.get_building_list(building_desc_x.station)) { if(b.get_name()==desc_name && (b.is_available(world.get_time()) || world.use_timeline() == false) ) { obj = b break } } } return obj } simutrans-124.3/simutrans/script/hm_lib/hm_global.nut000066400000000000000000000004611474050137200230130ustar00rootroot00000000000000this.hm_commands <- [] // array to store the commands this.player <- null class hm_slope { FL = 0 N1 = 4 N2 = 8 S1 = 36 S2 = 72 E1 = 28 E2 = 56 W1 = 12 W2 = 24 UP = 82 //UP2 = 92 DOWN = 83 //DN2 = 93 } class hm_base_tl { function exec(player, origin) { return null } } simutrans-124.3/simutrans/script/hm_lib/hm_house_tl.nut000066400000000000000000000021201474050137200233670ustar00rootroot00000000000000include("hm_lib/hm_global") class hm_headquarter_tl extends hm_base_tl { level = 0 pos = null constructor(l, p, r) { level = l pos = coord3d(p[0],p[1],p[2]) // rotation ignored for now hm_commands.append(this) } function exec(player, origin) { local hq_builder = command_x(tool_headquarter) if(player.get_headquarter_level() <= level) { return hq_builder.work(player, pos+origin, null) } return format("Headquarter already at higher level %d versus %d", player.get_headquarter_level(), level) } } class hm_house_tl extends hm_base_tl { desc_name = 0 pos = null z = 256 rotation = 0 constructor(dn, p, r) { desc_name = dn pos = coord(p[0],p[1]) rotation = r hm_commands.append(this) } function exec(player, origin) { local tp = pos + origin local tile = square_x(tp.x,tp.y).get_ground_tile() // house only on ground if(tile) { return command_x(tool_build_house).work(player, tile, format("1%d%s", rotation, desc_name)) } return "No suitable ground!" } } simutrans-124.3/simutrans/script/hm_lib/hm_misc_tl.nut000066400000000000000000000017571474050137200232160ustar00rootroot00000000000000include("hm_lib/hm_global") class hm_rotate_building_tl extends hm_base_tl { pos = null constructor(p) { pos = coord3d(p[0],p[1],p[2]) hm_commands.append(this) } function exec(player, origin) { local tl = command_x(tool_rotate_building) return tl.work(player, origin+pos) } } class hm_error_message_tl extends hm_base_tl { text = null constructor(s) { text = s hm_commands.append(this) } function exec(player, origin) { return text } } class hm_chat_message_tl extends hm_base_tl { text = null pos = null constructor(s, p) { text = s pos = coord3d(p[0], p[1], p[2]) hm_commands.append(this) } function exec(player, origin) { gui.add_message_at(player, text, origin+pos); return null } } class hm_exec_func_tl extends hm_base_tl { func = null param = null constructor(f, p) { func = f param = p hm_commands.append(this) } function exec(player, origin) { return func(player, origin, param) } } simutrans-124.3/simutrans/script/hm_lib/hm_obj_selector.nut000066400000000000000000000055111474050137200242260ustar00rootroot00000000000000 class hm_selector_base { messages = [] // text to show when users select the way descs = [] function get_desc(idx) { // given idx can be out of range. return idx <= descs.len() ? descs[idx-1] : null } function need_selection() { return descs.len()tp.z && err == null) { err = command_x.set_slope(player, tile, hm_slope.DOWN) tile = square_x(tp.x, tp.y).get_ground_tile() } if(err) { return err } return command_x.set_slope(player, tp, slope) } } /** * * */ class hm_test_area_tl extends hm_base_tl { start = null ziel = null terraform = null constructor(s, z, t = null) { start = coord3d(s[0],s[1],s[2]) ziel = coord3d(z[0],z[1],z[2]) terraform = t hm_commands.append(this) } function exec(player, origin) { // ground check local s_tile = origin+start local e_tile = origin+ziel local count_x = abs(s_tile.x - e_tile.x) + 1 local count_y = abs(s_tile.y - e_tile.y) + 1 local check_z = false if ( terraform == 0 ) { check_z = true } //gui.add_message_at(player_x(1), "count_x " + count_x, world.get_time()) //gui.add_message_at(player_x(1), "count_y " + count_y, world.get_time()) local test_st = s_tile if ( s_tile.x >= e_tile.x && s_tile.y >= e_tile.y ) { test_st = e_tile } local err = null for ( local i = 0; i < count_x; i++ ) { local t = square_x(test_st.x+i, test_st.y).get_ground_tile() //gui.add_message_at(player, "tile " + coord3d_to_string(t), world.get_time()) for ( local j = 0; j < count_y; j++ ) { local tile = square_x(t.x, test_st.y+j).get_ground_tile() local tile_tree = tile.find_object(mo_tree) local tile_groundobj = tile.find_object(mo_groundobj) local tile_moving_object = tile.find_object(mo_moving_object) if ( tile.is_empty() ) { // tile is empthy //err = null } else if ( tile_tree != null || tile_groundobj != null || tile_moving_object != null ) { // tile have tree, groundobj or moving_obj // These are optical objects and do not prevent construction. //err = null } else { // The tile has objects that prevent construction. err = "not_free" //gui.add_message_at(player_x(1), "tile is not free " + coord3d_to_string(tile), world.get_time()) break } if ( check_z ) { //gui.add_message_at(player_x(1), "tile terraform test " + coord3d_to_string(tile), world.get_time()) if ( s_tile.z != tile.z || tile.get_slope() > 0) { err = "terraform" break } } } if ( err != null ) { break } } if ( err == "not_free" ) { // tile is not free local message = translate("Selected area not free for build!") return message } else if ( err == "terraform" ) { // terraform necessary local message = translate("The terrain is not suitable for construction.") return message } else { return null } } } simutrans-124.3/simutrans/script/hm_lib/hm_station_tl.nut000066400000000000000000000033431474050137200237350ustar00rootroot00000000000000include("hm_lib/hm_global") class hm_station_tl extends hm_base_tl { desc = null desc_name = null pos = null wtype = 0 rotation = 15 constructor(sta_name, p, wt = 0, r = 15) { desc_name = sta_name pos = coord3d(p[0],p[1],p[2]) wtype = wt rotation = r hm_commands.append(this) } // returns [error_message, desc] function _get_desc(){ if(desc_name.slice(0,2)=="?f") { local key_str = "p" + desc_name.slice(2) local d = hm_found_desc.get(key_str) if(d==null) { local message = format(translate("Station key %s is not defined."), desc_name.slice(2)) return [message, null] } else if(d[0]==null) { local message = format(translate("No station was detected between %s."), hm_found_desc.get_pos_str(key_str)) return [message, null] } return [null, d[0]] } else if(desc_name.slice(0,2)=="?s") { local idx = desc_name.slice(2).tointeger() local d = hm_station_selector().get_desc(idx) if(d==null) { local message = format(translate("Selected station %s is not available."), desc_name.slice(2)) return [message, null] } return [null, d] } else { local d = hm_get_building_desc(desc_name, wtype, building_desc_x.station) if(d==null) { local message = format(translate("Station %s (%s) is not found!"), translate(desc_name), desc_name) return [message, null] } return [null, d] } } function exec(player, origin) { local dr = _get_desc() if(dr[0]!=null) { return dr[0] // there was a error in obtaining the desc } local desc = dr[1] return command_x.build_station(player, origin+pos, desc, rotation); } } simutrans-124.3/simutrans/script/hm_lib/hm_tunnel_tl.nut000066400000000000000000000020271474050137200235570ustar00rootroot00000000000000include("hm_lib/hm_global") include("hm_lib/hm_functions") include("hm_lib/hm_find_obj") include("hm_lib/hm_obj_selector") class hm_tunnel_tl extends hm_base_tl { desc_name = null start = null ziel = null constructor(d_name, s, z) { desc_name = d_name start = coord3d(s[0],s[1],s[2]) ziel = coord3d(z[0],z[1],z[2]) hm_commands.append(this) } function exec(player, origin) { local tool = command_x(tool_build_tunnel) local sp = origin+start local tile = tile_x(sp.x, sp.y, sp.z); local moWay = tile.find_object(mo_tunnel); local err = null if(!moWay) { // build tunnel entrance tool.set_flags(2) err = tool.work(player, sp, desc_name) } if(!err) { err = tool.work(player, origin+start, origin+ziel, desc_name) } if(err!=null) { //calc_route() failed to find a path. return "Tunnel building path from (" + (origin+start).tostring() + ") to (" + (origin+ziel).tostring() + ") is not found!" } else { return null } } } simutrans-124.3/simutrans/script/hm_lib/hm_way_tl.nut000066400000000000000000000052731474050137200230600ustar00rootroot00000000000000include("hm_lib/hm_global") include("hm_lib/hm_functions") include("hm_lib/hm_find_obj") include("hm_lib/hm_obj_selector") class hm_way_tl extends hm_base_tl { desc_name = null start = null startz = 256 finish = null finishz = 256 wtype = null stype = null constructor(d_name, s, z, wt = null, st = null) { desc_name = d_name start = coord3d(s[0],s[1],0) if(s.len()>2) { start.z = s[2] startz = 0 } finish = coord3d(z[0],z[1],0) if(z.len()>2) { finishz = finish.z = z[2] } wtype = wt stype = st hm_commands.append(this) } // returns [error_message, desc] function _get_desc(){ if(desc_name.slice(0,2)=="?f") { local key_str = "w" + desc_name.slice(2) local d = hm_found_desc.get(key_str) if(d==null) { local message = format(translate("Way key %s is not defined."), desc_name.slice(2)) return [message, null] } else if(d[0]==null) { local message = format(translate("No way was detected between %s."), hm_found_desc.get_pos_str(key_str)) return [message, null] } return [null, d[0]] } else if(desc_name.slice(0,2)=="?s") { local idx = desc_name.slice(2).tointeger() local d = hm_way_selector().get_desc(idx) if(d==null) { local message = format(translate("Selected way %s is not available."), desc_name.slice(2)) return [message, null] } return [null, d] } else { local d = hm_get_way_desc(desc_name, wtype, stype) //gui.add_message_at(player, "_get_desc - hm_get_way_desc() " + d, world.get_time()) if(d==null) { local message = format(translate("Way %s (%s) is not found!"), translate(desc_name), desc_name) return [message, null] } return [null, d] } } function exec(player, origin) { local dr = _get_desc() if(dr[0]!=null) { return dr[0] // there was a error in obtaining the desc } local desc = dr[1] local stp = start+origin if(startz==256) { local tile = square_x(stp.x,stp.y).get_ground_tile() if(tile == null) { return "No suitable ground!" } stp = coor3d(tile); } local ftp = finish+origin if(finishz==256) { local tile = square_x(ftp.x,ftp.y).get_ground_tile() if(tile == null) { return "No suitable ground!" } ftp = coord3d(tile); } local err = command_x.build_way(player, stp, ftp, desc, true) if(err!=null) { //calc_route() failed to find a path. local message = format(translate("Way building path from (%s) to (%s) is not found!"), (stp).tostring(), (ftp).tostring()) return message } return null } } simutrans-124.3/simutrans/script/hm_lib/hm_wayobj_tl.nut000066400000000000000000000042241474050137200235460ustar00rootroot00000000000000include("hm_lib/hm_global") // valid only for wt_rail class hm_wayobj_tl extends hm_base_tl { desc_name = null start = null ziel = null wtype = null overhead = null constructor(d_name, s, z, wt = null, oh = null) { desc_name = d_name start = coord3d(s[0],s[1],s[2]) ziel = coord3d(z[0],z[1],z[2]) wtype = wt overhead = oh hm_commands.append(this) } // returns [error_message, desc] function _get_desc(){ if(desc_name.slice(0,2)=="?f") { local key_str = "c" + desc_name.slice(2) local d = hm_found_desc.get(key_str) if(d==null) { local message = format(translate("Wayobj key %s is not defined."), desc_name.slice(2)) return [message, null] } else if(d[0]==null) { local message = format(translate("No wayobj was detected between %s."), hm_found_desc.get_pos_str(key_str)) return [message, null] } return [null, d[0]] } else if(desc_name.slice(0,2)=="?s") { local idx = desc_name.slice(2).tointeger() local d = hm_wayobj_selector().get_desc(idx) if(d==null) { local message = format(translate("Selected wayobj %s is not available."), desc_name.slice(2)) return [message, null] } return [null, d] } else { local d = hm_get_wayobjs_desc(desc_name, wtype, overhead) //gui.add_message_at(player, "_get_desc - hm_get_way_desc() " + d, world.get_time()) if(d==null) { local message = format(translate("Wayobj %s (%s) is not found!"), translate(desc_name), desc_name) return [message, null] } return [null, d] } } function exec(player, origin) { local dr = _get_desc() if(dr[0]!=null) { return dr[0] // there was a error in obtaining the desc } local desc = dr[1] local err = command_x.build_wayobj(player, origin+start, origin+ziel, desc) if(err!=null) { //calc_route() failed to find a path. local message = format(translate("Wayobj building path from ($s) to (%s) is not found!"), (origin+start).tostring(), (origin+ziel).tostring()) return message } else { return null } } } simutrans-124.3/simutrans/script/hm_lib/lib_obj_finder_v2.nut000066400000000000000000000100301474050137200244160ustar00rootroot00000000000000// originally obtained from https://github.com/128na/sugoi-simutrans-squirrel-scripts/blob/master/lib_obj_finder_v2.nut at 2021/01/20 // some functions were modified by himeshi class ObjFinder { player = null; area = null; constructor(pl, a = [ [0, 0, -2], [10, 10, 2] ]) { player = pl; area = a; } // æŒ‡å®šå€¤é–“ã®æ•°å€¤ã‚’イテレートã™ã‚‹ function _stepGenerator(from, to) { if (from < to) { for (local i = from; i <= to; i++) { yield i; } } else { for (local i = from; i >= to; i--) { yield i; } } } // 指定座標空間をイテレートã™ã‚‹ function _coord3dGenerator() { foreach(x in _stepGenerator(area[0][0], area[1][0])) { foreach(y in _stepGenerator(area[0][1], area[1][1])) { foreach(z in _stepGenerator(area[0][2], area[1][2])) { yield coord3d(x, y, z); } } } } // 指定åã®ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆãŒæŒ‡å®šåº§æ¨™ç©ºé–“ã«ãªã„ã¨ãã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’返㙠function getMissingObjText(type) { return "範囲" + "[" + coord3d(area[0][0], area[0][1], area[0][2]) + "] - [" + coord3d(area[1][0], area[1][1], area[1][2]) + "]" + "ã«" + type + "ãŒã‚りã¾ã›ã‚“。"; } // 軌é“を指定座標空間ã‹ã‚‰æŽ¢ã™ function findWay() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); gui.add_message_at(player, "findWay() coord :" + coord3d_to_string(tile), world.get_time()) local moWay = tile.find_object(mo_way); local hasOwnedWay = moWay && moWay.get_owner().get_name() == player.get_name(); if (hasOwnedWay) { return moWay.get_desc(); } } } // 架線を指定座標空間ã‹ã‚‰æŽ¢ã™ function findWayObj() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); local moWobj = tile.find_object(mo_wayobj); local hasOwnedWay = moWobj && moWobj.get_owner().get_name() == player.get_name(); if (hasOwnedWay) { return moWobj.get_desc(); } } } // 標識を指定座標空間ã‹ã‚‰æŽ¢ã™ function findSign() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); local moSign = tile.find_object(mo_signal); if (moSign) { return moSign.get_desc(); } local moRSign = tile.find_object(mo_roadsign); if (moRSign) { return moRSign.get_desc(); } } } // プラットフォームを指定座標空間ã‹ã‚‰æŽ¢ã™ function findPlatform() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); local moBld = tile.find_object(mo_building); local hasOwnedPlatform = moBld && moBld.get_owner().get_name() == player.get_name(); if (hasOwnedPlatform) { return moBld.get_desc(); } } } // マーカーを指定座標空間ã‹ã‚‰æŽ¢ã™ function findLabel() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); local obj = tile.find_object(mo_label); local hasOwnedWay = obj && obj.get_owner().get_name() == player.get_name(); if (hasOwnedWay) { return obj; } } } // depot function findDepot() { foreach(pos in _coord3dGenerator()) { local tile = tile_x(pos.x, pos.y, pos.z); local moBld = tile.find_object(mo_depot); local hasOwnedDepot = moBld && moBld.get_owner().get_name() == player.get_name(); if (hasOwnedDepot) { return moBld.get_desc(); } } } } simutrans-124.3/simutrans/script/hm_toolkit_v3.nut000066400000000000000000000015151474050137200224170ustar00rootroot00000000000000 include("hm_lib/hm_way_tl") include("hm_lib/hm_wayobj_tl") include("hm_lib/hm_bridge_tl") include("hm_lib/hm_tunnel_tl") include("hm_lib/hm_slope_tl") include("hm_lib/hm_sign_tl") include("hm_lib/hm_station_tl") include("hm_lib/hm_depot_tl") include("hm_lib/hm_remove_tl") include("hm_lib/hm_find_obj") include("hm_lib/hm_misc_tl") include("hm_lib/hm_obj_selector") include("hm_lib/hm_house_tl") include("hm_lib/hm_city_tl") function init(pl) { this.player = pl hm_build() return true } function work(pl, pos) { local os = hm_obj_selector() if(os.need_selection()) { return os.select_obj(pl, pos) } // obj selection eneded or is not needed. foreach (cmd in hm_commands) { local err = cmd.exec(pl, pos) if(err!=null && err.len()>0) { return err } } return null } function exit(pl) { return true } simutrans-124.3/simutrans/script/new_scenario_template.nut000066400000000000000000000055421474050137200242110ustar00rootroot00000000000000/** * Template file for scenarios * it contains a minimal interface */ /// specify the savegame to load map.file = "savegame.sve" /// short description to be shown in finance window /// and in standard implementation of get_about_text scenario.short_description = "Template Scenario" scenario.author = "User" scenario.version = "0.0" scenario.translation = "The Unknown Translators" /// scenario relies on this version of the api scenario.api = "120.0" /** * These functions should return text strings (or ttext instances) * the text is shown in the corresponding tab in the scenario info window * all text can be dynamic and change with progress in scenario * * These information can be customized per player. * Players are identified by their numbers: pl == 0 is the first player slot, * pl == 1 is the 'Public player' */ function get_info_text(pl) { // General information } function get_rule_text(pl) { // Rules to be obeyed } function get_result_text(pl) { // Display current standing } function get_goal_text(pl) { // Describe the goals to be achieved to win } // Commented out: Will use implementation of scenario_base.nut, // which needs scenario.short_description, scenario.author, scenario.version // // function get_about_text(pl) // { // // Information about author, version, etc // } // Commented out: Will use implementation of scenario_base.nut, // which needs scenario.short_description // // function get_short_description(pl) // { // // Short string will be displayed in finance window // } /** * Called upon start of scenario, initialize global variables here */ function start() { } /** * Main function: returns percentage of completion * If returned value >= 100 then scenario is won * If less than zero scenario is lost */ function is_scenario_completed(pl) { return 100 // complete } /** * Called after loading a savegame of a played scenario */ function resume_game() { } /** * Called at the beginning of a new month */ function new_month() { } /** * Called at the beginning of a new year */ function new_year() { } /** * Table that contains data that will be saved in savegame * only plain data is saved: no classes / instances / functions, no cyclic references */ persistent = {} // Attention: do not call API functions here in global scope. // If you do so, they will be called before the savegame is loaded, // and result in undefined behavior. /** * Called when user clicks to build. * Error messages are sent back over network to clients. * Does not work with waybuilding, use the rules.forbid_* functions in this case. * * @param pos is a table with coordinate { x=, y=, z=} * @param tool is a table with current tool properties {coord3d start_pos, bool is_drag_tool, bool is_ctrl, bool is_shift} * @return null if allowed, an error message otherwise */ function is_work_allowed_here(pl, tool_id, pos, tool) { return null } simutrans-124.3/simutrans/script/scenario_base.nut000066400000000000000000000062011474050137200224300ustar00rootroot00000000000000/** * Base file for scenarios */ // declare arrays and slots map <- {} map.file <- "" map.settings <- {} // some meta info scenario <- {} scenario.short_description <- "This is a random scripted scenario" scenario.author <- "" scenario.version <- "" scenario.translation <- "" scenario.api <- "112.3" // table to hold routines for forbidding/allowing player tools rules <- {} // table containing all waytypes all_waytypes <- [wt_road, wt_rail, wt_water, wt_monorail, wt_maglev, wt_tram, wt_narrowgauge, wt_air, wt_power] // placeholder array for all the map editing tools map.editing_tools <- [ tool_add_city, tool_change_city_size, tool_land_chain, tool_city_chain, tool_build_factory, tool_link_factory, tool_lock_game, tool_build_cityroad, tool_increase_industry, tool_step_year, tool_fill_trees, tool_set_traffic_level, dialog_edit_factory, dialog_edit_attraction, dialog_edit_house, dialog_edit_tree, dialog_enlarge_map] // forbidden tools // default: map editing tools, switch player scenario.forbidden_tools <- [tool_switch_player] foreach(tool_id in map.editing_tools) { scenario.forbidden_tools.append(tool_id) } /** * Called when filling toolbars, activating tools * Results are not transferred over network, use the rules.forbid_* functions in this case * * @param name is parameter (string) i.e. description for way tools * @return 1 if allowed, null otherwise */ function is_tool_allowed(pl, tool_id, wt, name) { if (pl == 1) return true return scenario.forbidden_tools.find( tool_id )==null; // null => not found => allowed } /** * Called when user clicks to build etc. * Error messages are sent back over network to clients. * Does not work with waybuilding etc use the rules.forbid_* functions in this case. * * @param name is parameter (string) i.e. description for way tools * @param pos is a table with coordinate { x=, y=, z=} * @return null if allowed, an error message otherwise */ function is_work_allowed_here(pl, tool_id, name, pos, tool) { return null } function is_schedule_allowed(pl, schedule) { return null } // declare getter functions function get_map_file() { return map.file; } function get_short_description(pl) { return scenario.short_description; } function get_api_version() { return ("api" in scenario) ? scenario.api : "112.3" } function get_about_text(pl) { return "Scenario: " + scenario.short_description + "

Author: " + scenario.author + "

Version: " + scenario.version + "

Translation: " + scenario.translation } function get_rule_text(pl) { return "Do what you want." } function get_goal_text(pl) { return "The way is the target." } function get_info_text(pl) { return "Random scenario." } function get_result_text(pl) { return "You are owned." } function get_debug_text(pl) { return debug.get_forbidden_text() } /** * initialization, called when scenario starts */ function start() { } /** * initialization, called when savegame is loaded * default behavior: calls start() */ function resume_game() { start() } /** * Happy New Month and Year! */ function new_month() { } function new_year() { } simutrans-124.3/simutrans/script/script_base.nut000066400000000000000000000256661474050137200221510ustar00rootroot00000000000000/** * Base file for scripting */ // table to hold routines for debug debug <- {} function min(a, b) { return a < b ? a : b } function max(a, b) { return a > b ? a : b } /** * load / save support * the persistent table will be written / restored during save / load * only plain data is saved: no classes / instances / functions, no cyclic references */ persistent <- {} /** * writes the persistent table to a string */ function save() { if (typeof(persistent) != "table") { throw("error during saving: the variable persistent is not a table") } local str = "persistent = " + recursive_save(persistent, "\t", [ persistent ] ) return str } function is_identifier(str) { return (str.toalnum() == str) && (str[0] < '0' || str[0] > '9') } function recursive_save(table, indent, table_stack) { local isarray = typeof(table) == "array" local str = (isarray ? "[" : "{") + "\n" foreach(key, val in table) { str += indent if (!isarray) { if (typeof(key)=="string") { if (is_identifier(key)) { str += key + " = " } else { str += "[\"" + key + "\"] = " } } else { str += "[" + key + "] = " } } while( typeof(val) == "weakref" ) val = val.ref switch( typeof(val) ) { case "null": str += "null" break case "integer": case "float": case "bool": str += val break case "string": str += "@\"" + val + "\"" break case "array": case "table": if (!table_stack.find(val)) { table_stack.push( table ) str += recursive_save(val, indent + "\t", table_stack ) table_stack.pop() } else { // cyclic reference - good luck with resolving str += "null" } break case "generator": str += "null" break case "instance": default: if ("_save" in val) { str += val._save() break } str += "\"unknown(" + typeof(val) + ")\"" } if (str.slice(-1) != "\n") { str += ",\n" } else { str = str.slice(0,-1) + ",\n" } } str += indent.slice(0,-1) + (isarray ? "]" : "}") + "\n" return str } ///////////////////////////////////// /** * translatable texts */ class ttext { text_raw = "" // raw text text_tra = "" // translated text // tables with information to replace variables {key} by their values var_strings = null var_values = null // these cannot be initialized here to {}, otherwise // all instances will refer to the same table! constructor(k) { if (type(k) != "string") { throw("ttext must be initialized with string") } text_raw = k text_tra = k var_strings = [] var_values = {} find_variables(text_raw) } function get_translated_text() { return translate(text_raw) } function find_variables(k) { var_strings = [] // find variable tags local reg = regexp(@"\{([a-zA-Z_]+[a-zA-Z_0-9]*)\}"); local start = 0; while (start < k.len()) { local res = reg.capture(k, start) if (res) { local vname = k.slice(res[1].begin, res[1].end) var_strings.append({ name = vname, begin = res[0].begin, end = res[0].end }) start = res[0].end } else { start = k.len(); } } } function _set(key, val) { var_values[key] <- val } function _tostring() { // get translated text local text_tra_ = get_translated_text() if (text_tra_ != text_tra) { text_tra = text_tra_ // new text, search for identifiers find_variables( text_tra ) } // create array of values, sort it per index in string local values = [] foreach(val in var_strings) { local key = val.name if ( key in var_values ) { local valx = { begin = val.begin, end = val.end, value = var_values[key] } values.append(valx) } } values.sort( @(a,b) a.begin <=> b.begin ) // create the resulting text piece by piece local res = "" local ind = 0 foreach( e in values) { res += text_tra.slice(ind, e.begin) res += e.value ind = e.end } res += text_tra.slice(ind) return res } } /** * text from files */ class ttextfile extends ttext { file = null constructor(file_) { file = file_ base.constructor("") } function get_translated_text() { return load_language_file(file) } } ///////////////////////////////////// function _extend_get(index) { if (index == "rawin" || index == "rawget") { throw null // invoke default delegate return } local fname = "get_" + index if (fname in this) { local func = this[fname] if (typeof(func)=="function") { return func.call(this) } } throw null // invoke default delegate } /** * this class implements an extended get method: * everytime an index is not found it tries to call the method 'get_'+index */ class extend_get { _get = _extend_get } ///////////////////////////////////// class coord { x = -1 y = -1 constructor(_x, _y) { x = _x; y = _y } function _add(other) { return coord(x + other.x, y + other.y) } function _sub(other) { return coord(x - other.x, y - other.y) } function _mul(fac) { return coord(x * fac, y * fac) } function _div(fac) { return coord(x / fac, y / fac) } function _unm() { return coord(-x, -y) } function _typeof() { return "coord" } function _tostring() { return coord_to_string(this) } function _save() { return "coord(" + x + ", " + y + ")" } function href(text) { return "
" + text + "" } } class coord3d extends coord { z = -1 constructor(_x, _y, _z) { x = _x; y = _y; z = _z } function _add(other) { return coord3d(x + other.x, y + other.y, z + getz(other)) } function _sub(other) { return coord3d(x - other.x, y - other.y, z - getz(other)) } function _mul(fac) { return coord3d(x * fac, y * fac, z * fac) } function _div(fac) { return coord3d(x / fac, y / fac, z / fac) } function _unm() { return coord3d(-x, -y, -z) } function _typeof() { return "coord3d" } function _tostring() { return coord3d_to_string(this) } function _save() { return "coord3d(" + x + ", " + y + ", " + z + ")" } function href(text) { return "" + text + "" } function getz(other) { return ("z" in other) ? other.z : 0 } } /** * class that contains data to get access to an in-game factory */ class factory_x extends coord { _get = _extend_get function _tostring() { return "factory_x@" + coord_to_string(this) } /// input / output slots, will be filled by constructor input = {} output = {} // constructor is implemented in c++ } /** * class that contains data to get access to an production slot of a factory */ class factory_production_x extends extend_get { /// coordinates of factory x = -1 y = -1 good = "" /// name of the good to be consumed / produced index = -1 /// index to identify an io slot max_storage = 0 /// max storage of this slot scaling = 0 constructor(x_, y_, n_, i_) { x = x_ y = y_ good = n_ index = i_ } } /** * class to provide access to the game's list of all factories */ class factory_list_x { /// meta-method to be called in a foreach loop function _nexti(prev_index) { } /// meta method to retrieve factory by index in the global C++ array function _get(index) { } } /** * class that contains data to get access to an in-game player company */ class player_x extends extend_get { nr = 0 /// player number function _tostring() { return "player_x@" + nr } constructor(n_) { nr = n_ } } /** * class that contains data to get access to an in-game halt */ class halt_x extends extend_get { id = 0 /// halthandle_t function _tostring() { return "halt_x@" + id } constructor(i_) { id = i_ } } /** * class that contains data to get access to a line of convoys */ class line_x extends extend_get { id = 0 /// linehandle_t function _tostring() { return "line_x@" + id } constructor(i_) { id = i_ } } /** * class to provide access to line lists */ class line_list_x { halt_id = 0 player_id = 0 } /** * class that contains data to get access to a tile (grund_t) */ class tile_x extends coord3d { _get = _extend_get function _tostring() { return "tile_x@" + coord3d_to_string(this) } function get_objects() { return tile_object_list_x(x,y,z) } } class tile_object_list_x { /// coordinates x = -1 y = -1 z = -1 constructor(x_, y_, z_) { x = x_ y = y_ z = z_ } } /** * class that contains data to get access to a grid square (planquadrat_t) */ class square_x extends coord { _get = _extend_get function _tostring() { return "square_x@" + coord_to_string(this) } } /** * class to provide access to convoy lists */ class convoy_list_x { use_world = 0 halt_id = 0 line_id = 0 } /** * class that contains data to get access to an in-game convoy */ class convoy_x extends extend_get { id = 0 /// convoihandle_t function _tostring() { return "convoy_x@" + id } constructor(i_) { id = i_ } } /** * class to provide access to the game's list of all cities */ class city_list_x { /// meta-method to be called in a foreach loop function _nexti(prev_index) { } /// meta method to retrieve city by index in the global C++ array function _get(index) { } } /** * class that contains data to get access to a city */ class city_x extends coord { _get = _extend_get function _tostring() { return "city_x@" + coord_to_string(this) } } /** * class to access in-game settings */ class settings { } /** * base class of map objects (obj_t) */ class map_object_x extends coord3d { _get = _extend_get function _tostring() { return "map_object_x@" + coord_to_string(this) } } class schedule_entry_x extends coord3d { function _tostring() { return "schedule_entry_x@" + coord3d_to_string(this) } /// load percentage load = 0 /// waiting wait = 0 } class dir { static none = 0 static north = 1 static east = 2 static northeast = 3 static south = 4 static northsouth = 5 static southeast = 6 static northsoutheast = 7 static west = 8 static northwest = 9 static eastwest = 10 static northeastwest = 11 static southwest = 12 static northsouthwest = 13 static southeastwest = 14 static all = 15 static nsew = [1, 4, 2, 8] } class slope { static flat=0 static north = 3+1 ///< North slope static west = 9+3 ///< West slope static east = 27+1 ///< East slope static south = 27+9 ///< South slope static northwest = 27 ///< NW corner static northeast = 9 ///< NE corner static southeast = 3 ///< SE corner static southwest = 1 ///< SW corner static raised = 80 ///< special meaning: used as slope of bridgeheads static all_up_slope = 82 ///< used for terraforming tools static all_down_slope = 83 ///< used for terraforming tools } class time_x { raw = 1 year = 0 month = 1 } class time_ticks_x extends time_x { ticks = 0 ticks_per_month = 0 next_month_ticks = 0 } /** * The same metamethod magic as in the class extend_get. */ table_with_extend_get <- { _get = _extend_get } /** * table to hold routines to access the world */ world <- {} world.setdelegate(table_with_extend_get) // table to hold routines for gui access gui <- {} simutrans-124.3/simutrans/script/script_compat.nut000066400000000000000000000023411474050137200225030ustar00rootroot00000000000000/** * File with compatibility functions to run scripts written for earlier versions of the api. */ function compat(version) { if (version == "*") { return; // wants bleeding edge stuff } local f = type(version)=="string" ? version.tofloat() : 112.3; // default version if (f <= 112.3) { f = 112.3 } // sorted in descending order w.r.t. api version local all_versions = [ { v = 120.1, f = compat_120_1}, { v = 112.3, f = compat_112_3}, ] foreach(vt in all_versions) { if (f - 0.01 <= vt.v) { vt.f.call(this) } } } function compat_112_3() { print("Compatibility mode for version 112.3 in effect") // convoy_list_x() deprecated, set default value to iterate through global list convoy_list_x.use_world <- 1 } function compat_120_1() { print("Compatibility mode for version 120.1 in effect") // 120.1 broke player_x::is_active (r7603) player_x.is_active <- function() { try { this.get_name() // will throw if no player with this number exists return true } catch(ev) { return false } } // gui.add_message got extra parameter (r7890) gui.add_message_new <- gui.add_message gui.add_message <- function(text) { gui.add_message_new( player_x(-1) /*will be set to active player*/, text) } } simutrans-124.3/simutrans/script/tool_base.nut000066400000000000000000000024221474050137200216030ustar00rootroot00000000000000// stubs for functions needed by scripted tools function init(player) { return true } function exit(player) { return true } // one-click tools function work(player, pos) { return null } // two-click tools function do_work(player, start, end) { return null } function mark_tiles(player, start, end) { } /** * Can the tool start/end on pos? If it is the second click, start is the position of the first click * 0 = no * 1 = This tool can work on this tile (with single click) * 2 = On this tile can dragging start/end * 3 = Both (1 and 2) * */ function is_valid_pos(player, start, pos) { return 2 } // dummy auxiliary function, will be regularly called function step() { // do not implement } // check whether all functions support the flags parameter function correct_missing_flags_argument() { if (work.getinfos().parameters.len() == 3) { work_old <- work work = function(player, pos, flags) { return work_old(player, pos) } } if (do_work.getinfos().parameters.len() == 4) { do_work_old <- do_work do_work = function(player, start, end, flags) { return do_work_old(player, start, end) } } if (mark_tiles.getinfos().parameters.len() == 4) { mark_tiles_old <- mark_tiles mark_tiles = function(player, start, end, flags) { mark_tiles_old(player, start, end) } } } simutrans-124.3/simutrans/text/000077500000000000000000000000001474050137200165645ustar00rootroot00000000000000simutrans-124.3/simutrans/text/be.tab000066400000000000000000000567031474050137200176550ustar00rootroot00000000000000§Belaruskaja PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: be Belaruskaja # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable выкл. cl_btn_filter_enable укл. cl_btn_filter_settings ÐаÑтаўленні cl_btn_sort_asc узыходна cl_btn_sort_desc Ñыходна cl_btn_sort_income даход cl_btn_sort_name назва cl_btn_sort_type тып clf_btn_alle уÑÑ‘ clf_btn_invers інв. clf_btn_keine нічога gl_btn_sort_bonus прÑÐ¼Ñ–Ñ gl_btn_sort_name назва gl_btn_sort_revenue прыбытак gl_btn_unsort неÑартаваны hl_btn_filter_disable выкл. hl_btn_filter_enable укл. hl_btn_filter_settings ÐаÑтаўленні hl_btn_sort_asc узыходна hl_btn_sort_desc Ñыходна hl_btn_sort_name назва hl_btn_sort_type тып hl_btn_sort_waiting груз hlf_btn_alle уÑÑ‘ hlf_btn_invers інв. hlf_btn_keine нічога #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Das Feld gehoert\neinem anderen Spieler\n УчаÑтак ужо\nналежыць іншаму гульцу!\n Der Besitzer erlaubt das Entfernen nicht Уладальнік\nне дазвалÑе\nзнеÑці гÑтага.\n Diese Zusammenstellung kann nicht fahren!\n ГÑты ÑаÑтаў не можа ехаць!\n Flugzeughalt muss auf\nRunway liegen!\n Ðемагчыма размÑÑціць\nпункту прыпынка\nÑамалёта па-за дарогай!\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Ðемагчыма размÑÑціць\nбудынка аÑрапорта\nÑž абраным меÑцы!\n Hier kann kein\nSignal aufge-\nstellt werden!\n Тут немагчыма\nÑžÑтанавіць\nÑветлафора!\n Monorails are not available yet! МанарÑйкавы транÑпарт\nÑÑˆÑ‡Ñ Ð½Ðµ даÑтупны! Post muss neben\nHaltestelle\nliegen!\n Дадатак трÑба\nбудаваць лÑ\nпрыпынку/Ñтанцыі!\n Schiffhalt muss im\nWasser liegen!\n Караблі могуць\nÑпынÑцца толькі\nна вадзе!\n Zughalt muss auf\nSchiene liegen!\n Ð§Ñ‹Ð³ÑƒÐ½Ð°Ñ‡Ð½Ð°Ñ ÑтанцыÑ\nпавінна размÑшчацца\nна Ñ€Ñйках!\n #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s\nвозіць турыÑтаў паміж\n%s ды\n%s Ð»Ñ (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s\nперавозіць цÑпер\nрабочых з %s\nда прадпрыемÑтва\n%s\nÐ»Ñ (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s цÑпер\nпрацуе з %i а/м паміж\n%s (%i,%i)\nды %s\nÐ»Ñ (%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s мае цÑпер\nчыгуначную\nлінію паміж %s\nÐ»Ñ (%i,%i) ды\n%s\nÐ»Ñ (%i,%i)\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Прылады Ñ€ÑÐ´Ð°Ð³Ð°Ð²Ð°Ð½Ð½Ñ Ð¼Ð°Ð¿Ñ‹ LISTTOOLS СпіÑÑ‹ MONORAILTOOLS МанарÑйка RAILTOOLS Чыгунка ROADTOOLS Ðўтадарога SHIPTOOLS СуднаходÑтва SLOPETOOLS ЗмÑненне Ñ€Ñльефу SPECIALTOOLS Ð”Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ð±ÑƒÐ´Ð°ÑžÐ½Ñ–Ñ‡Ñ‹Ñ Ð´Ñ‹ Ñ–Ð½ÑˆÑ‹Ñ Ð¿Ñ€Ñ‹Ð»Ð°Ð´Ñ‹ TRAMTOOLS Трамвай #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ New factory chain\nfor %s near\n%s built with\n%i factories. Ðовы прамыÑловы ланцуг:\nÐ´Ð»Ñ Ð¿Ñ€Ð°Ð´Ð¿Ñ€Ñ‹ÐµÐ¼Ñтва %s\nÐ»Ñ %s\nÑтвораны ÑÑˆÑ‡Ñ %i\n. New vehicle now available:\n%s\n З'ÑвілаÑÑ\nÐ½Ð¾Ð²Ð°Ñ Ñ‚Ñ€. адзінка:\n\n"%s" !\n\n Remove vehicle from map. Use with care! ÐÑцÑрожна! ВыдалÑе транÑпарт з мапы. Screenshot\ngespeichert.\n Здымак запіÑаны.\n Sends the convoi to the last depot it departed from! ÐдпраўлÑе тр. адзінку Ñž найбліжÑйшае дÑпо! With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s ÑвÑткуе\nÑžÑталÑванне новага помніка.\nУ Ñ„ÑÑце бÑруць\nудзел %i грамадзÑн. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ \nBauzeit bis да \nBauzeit von \nÐб'екты гÑтага тыпу\nмогуць з'ÑўлÑцца\nз \nCan't open heightfield file.\n \nÐемагчыма адкрыць файла з мапай вышыні.\n \nelektrified \nЭлектрыфікаваны \nHeightfield has wrong image type.\n \nÐÑправільны тып графічнага файла.\n \nnot elektrified \nÐеÑлектріфікаваны \nRibi (masked) \nRibi (masked) \nRibi (unmasked) \n\nRibi (unmasked) %d buildings\n Будынкі: %d \n %d convois %d (ÑаÑтавы) %d Einzelfahrzeuge im Depot %d тр. адзінак у дÑпо %i km/h (max. %ikm/h) %i км/гадз (макÑ. %i км/гадз) %s building %s %s %s %s %s %s has entered a depot. %s\nчакае\nÑž дÑпо. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Горад %s\nз павелічÑннем\nнаÑельніцтва да %i\nмае цÑпер новую ратушу. %s\nis crowded. СтанцыÑ\n%s\nперапоўнена! <нÑма лініі> 1 convoi 1 тр. ÑаÑтаў 1 Einzelfahrzeug im Depot 1 тр. адзінка Ñž дÑпо 1LIGHT_CHOOSE ЯркаÑць: 1WORLD_CHOOSE ÐаÑтаўленні новай мапы: 2LIGHT_CHOOSE КалÑроваÑць: 2WORLD_CHOOSE Ðумар мапы: 3LIGHT_CHOOSE Хутк. пракр.: 4LIGHT_CHOOSE ÐÐ´Ð²Ð°Ñ€Ð¾Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð°ÐºÑ€ÑƒÑ‚ÐºÐ° 5LIGHT_CHOOSE Пешах. Ð»Ñ Ð¿Ñ€Ñ‹Ð¿Ñ‹Ð½ÐºÐ°Ñž 5WORLD_CHOOSE Гарады: 6LIGHT_CHOOSE Пешаходы Ñž горадзе 6WORLD_CHOOSE ІнтÑнÑіўнаÑць д/руху: 8WORLD_CHOOSE Змена дню Ñ– ночы Abfrage РÑжым аглÑду Abnehmer Спажывец About ЗвеÑткі Abriss Выдаліць/знеÑці Absenken Чарпануць зÑмлі Add Stop Дадаць Add stops for backward travel Дадаць прыпынкі Ð´Ð»Ñ Ð²ÑÑ€Ñ‚Ð°Ð½Ð½Ñ aircraft_tab Ð“Ñ€ÑƒÐ·Ð°Ð²Ñ‹Ñ Airport ÐÑрапорт AIRTOOLS Паветраны транÑпарт All УÑе Allow player change Гульца можна мÑнÑць Alters a schedule. ЗмÑнÑе раÑклад. Angenommene Waren Грузы Ð´Ð»Ñ Ð½Ð°Ð²Ð°ÐºÐ¾Ð»ÑŒÐ½Ñ‹Ñ… прадпрыемÑтваў Anhaenger_tab ПрычÑпы Anheben ÐаÑыпаць зÑмлі Apply Line Ðа лінію April КраÑавік Arbeiter aus: Ð Ð°Ð±Ð¾Ñ‡Ñ‹Ñ Ð·: Arrived Прыбыло грузу Assets Рухомы капітал August Жнівень Bahndepot ДÑпо (цÑгнікі) Bankrott:\n\nDu bist bankrott.\n Банкрот:\n\nÐ’Ñ‹ банкрот.\n Baum ДрÑва Baustelle Пабудовы Beenden ВыйÑці BF Ч bio БіÑлагічны Blockstrecke ist\nbelegt\n \nУчаÑтак занÑты іншай\nтр. адзінкай!\n Boden ЗÑÐ¼Ð»Ñ Bridge is too long for this type!\n Ðельга пабудаваць маÑта\nабранага тыпу гÑткай\nвелькай даўжыні!\n Bruecke МоÑÑ‚ Bruecke muss an\neinfachem\nHang beginnen!\n МоÑÑ‚ павінен пачынацца\nад роўнага Ñхілу!\n Build city market Пабудаваць гандлёвае прадпрыемÑтва Build drain ТранÑфарматар Build land consumer Пабудаваць новае прадпрыемÑтва Build monorail depot МонарÑйкавае дÑпо Build powerline Будаваць лініі Ñлектраперадачы Build presignals ПапÑÑ€ÑÐ´Ð½Ñ–Ñ Ñемафоры Build ship depot Карабельнае дÑпо Build signals Семафоры Build train depot Чыгуначнае дÑпо Build tram depot Трамвайнае дÑпо Build truck depot Ðўтамабільнае дÑпо Built artifical slopes Будаваць штучны Ñхіл Built random attraction Пабудаваць новую ÑлавутаÑць Bus_tab ÐўтобуÑÑ‹ Cancel СкаÑаваць Capacity: %d%s %s\n Груз: %3d%s, %s\n Capacity: %s\nLoad: %d (%d%%) Груз: %s\n» %d (%d%%) Cash Ðа рахунку Change player ЗмÑніць гульца Chart ДыÑграма Choose operation executed on clicking stored/new vehicles Ðбраць дзеÑнне пры пÑтрыканні на Ñ–Ñнуючым/новым транÑпарце citicens жыхары City industries ГарадÑкі гандаль: City list Ð¡Ð¿Ñ–Ñ Ð³Ð°Ñ€Ð°Ð´Ð¾Ñž City size ÐаÑель-\nніцтва city_road ГарадÑÐºÐ°Ñ Ð´Ð°Ñ€Ð¾Ð³Ð° cl_title Ð¡Ð¿Ñ–Ñ Ñ‚Ñ€Ð°Ð½Ñпартных адзінак cl_txt_sort Сартаванне: clf_chk_cars ÐўтатранÑпарт clf_chk_indepot у дÑпо clf_chk_name_filter Па назве: clf_chk_noincome без прыбытку clf_chk_noline без лініі clf_chk_noroute нÑма шлаху clf_chk_noschedule без раÑкладу clf_chk_ships Караблі clf_chk_spezial_filter Па Ñтану: clf_chk_trains ЦÑгнікі clf_chk_type_filter Па тыпу: clf_chk_waren Па грузе: clf_title ÐаÑтаўленні ÑпіÑу тр. адзінак COLOR_CHOOSE\n Калі лаÑка,\nабÑрыце\nВаш колер: Constructed by Ðўтар: Constructed by %s Ðўтар: %s Construction_Btn Будаўніцтва convoi %d of %d тр. ÑаÑтаў %d з %d Convoi has been sent\nto the nearest depot\nof appropriate type.\n Тр. адзінка\nадпраўлена Ñž\nнайбліжÑйшае дÑпо.\n Convois: %d\nProfit: %s СаÑтаваў: %d\nПрыбытак: %s Convoys СаÑтавы Copy Convoi Капіраваць Copy the selected convoi and its schedule or line Капіраваць абраны ÑаÑтаў, захоўваючы раÑклад Ñ– лінію Create a new line based on this schedule Стварыць новую лінію па гÑтаму раÑкладу curlist_title СлавутаÑці Ð´Ð»Ñ Ñ‚ÑƒÑ€Ñ‹Ñтаў December Снежань Del Stop Выдаліць Delete Line Выдаліць лінію Delete this file. Выдаліць гÑты файл. Denkmal Помнік Departed Ðдпраўлена гр. Destination меÑца прызн. Details ЗвеÑткі diesel Дызель Direkt erreichbare Haltestellen Прамы маршрут да прыпынкаў Display settings Ð’Ñ–Ð´Ð°Ñ€Ñ‹Ñ Dock Док Durchsatz МакÑ. Eigenbesitz\n ГрамадÑкаÑ\nулаÑнаÑць\n\n Ein %s\npasst hier nicht.\n "%s"\nÑюды не паÑуе.\n Einstellungen aendern ЗмÑніць наÑтаўленні electric Электрычны Electrify track Ð­Ð»ÐµÐºÑ‚Ñ€Ñ‹Ñ„Ñ–ÐºÐ°Ñ†Ñ‹Ñ Erzeuge neue Karte.\n Калі лаÑка, \nпачакайце,\nÑтвараецца\nÐ½Ð¾Ð²Ð°Ñ Ð¼Ð°Ð¿Ð°...\n\n (Пры велькім памеры\nможа ÑпатрÑбіцца\nнекалькі мінут.)\n Es wird bereits\nein Fahrplan\neingegeben\n РаÑклад ужо абраны.\nСпачатку закончыце\nпланаваць гÑты!\n Fabrikanschluss ЗвÑÐ·Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð´Ð¿Ñ€Ñ‹ÐµÐ¼Ñтвы Fabrikname Ðазва Factories Прадпр-вы Fahrplan РаÑклад Fahrzeuge koennen so nicht entfernt werden Ðельга ўбраць\nтранÑпарту\nгÑткім чынам!\n Fahrzeuge: Тр. адзінкі: Farbe Колер Fast forward ПаÑкорыць Ñ‡Ð°Ñ February Люты Ferry_tab ПаÑажырÑÐºÑ–Ñ Fertig Гатова Filename Ð†Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°: Filter: Фільтр: Finanzen ФінанÑÑ‹ fl_title Ð¡Ð¿Ñ–Ñ Ð¿Ñ€Ð°Ð´Ð¿Ñ€Ñ‹ÐµÐ¼Ñтваў Flug_tab ПаÑажырÑÐºÑ–Ñ follow me Ñачыць Follow the convoi on the map. Рухаць камеру ÑžÑлед за ÑаÑтавам. Found new city ЗаÑнаваць новы горад Fracht Груз Free Capacity Свабодны аб'ём Full load Чакаць загр.: Fussgaenger Пешаход GAME PAUSED Ð“ÑƒÐ»ÑŒÐ½Ñ Ð¿Ñ€Ñ‹Ð¿Ñ‹Ð½ÐµÐ½Ð° Gear: Прывод: Gebaeude Будынак Gewicht Вага Gewinn Даход Give the selected vehicle(s) an individual schedule Даць абранаму транÑпарту аÑабіÑты раÑклад gl_title Ð¡Ð¿Ñ–Ñ Ð³Ñ€ÑƒÐ·Ð°Ñž go home Дадому Goods list Ð¡Ð¿Ñ–Ñ Ð³Ñ€ÑƒÐ·Ð°Ñž Gross Profit Гадавы прыбытак Grow city ПавÑлічыць колькаÑць жыхароў Growth роÑÑ‚ H Ð Happy Ð—Ð´Ð°Ð²Ð¾Ð»ÐµÐ½Ñ‹Ñ Ð¿Ð°Ñ. Helligk. Ð’Ñ–Ð´Ð°Ñ€Ñ‹Ñ Help Дапамога Hier warten/lagern: Тавары Ñ– паÑажыры\nна Ñтанцыі:\n hl_title Ð¡Ð¿Ñ–Ñ Ð¿Ñ€Ñ‹Ð¿Ñ‹Ð½ÐºÐ°Ñž/Ñтанцый hl_txt_filter Фільтр: hl_txt_sort Сартаванне: hlf_chk_airport ÐÑрапорт hlf_chk_anleger Докі hlf_chk_bahnhof Вакзалы hlf_chk_bushalt Прыпынкі hlf_chk_frachthof Пагруз. плÑцоўкі hlf_chk_keine_verb без ÑувÑзі hlf_chk_name_filter Па назве: hlf_chk_spezial_filter Па Ñтану: hlf_chk_type_filter Па тыпу: hlf_chk_waren_abgabe ПаÑтаўлÑе: hlf_chk_waren_annahme Прынімае: hlf_title Фільтр ÑпіÑу Ñтанцый Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Ðдпаведнага дÑпо Ð½Ñ Ð·Ð½Ð¾Ð¹Ð´Ð·ÐµÐ½Ð°!\nЗмÑніце раÑклад\nÑк трÑба Ñамі. Homeless БÑÐ·Ð´Ð¾Ð¼Ð½Ñ‹Ñ hydrogene Вадародны Input Спажыта Ins Stop УÑтавіць Intercity road len: Ð”Ð°ÑžÐ¶Ñ‹Ð½Ñ Ð¿Ñ€Ñ‹Ð³Ð°Ñ€. дарог: Intro. date: ВыпуÑк. ад: January Студзень July Ліпень June ЧÑрвень Kann Spielstand\nnicht laden.\n Ðемагчыма прачытаць\nÑтану гульні!\n Kann Spielstand\nnicht speichern.\n Ðемагчыма запіÑаць\nÑтану гульні!\n keine нічога Keine Einzelfahrzeuge im Depot ÐÑма тр. адзінак у дÑпо Lade Relief Загруз. Ñ€Ñльеф Laden Загрузіць Land industries ПрадпрыемÑтвы: LANG_CHOOSE\n Калі лаÑка,\nабÑрыце мову:\n Last Year ЛетаÑÑŒ: leer пуÑты Legend ТлумачÑнне знакаў Leistung МагутнаÑць Leitung Ð›Ñ–Ð½Ñ–Ñ Ñлектр. letzen Monat: diesen Monat: папÑÑ€Ñднім меÑÑцы: гÑтым меÑÑцы: Line Ð›Ñ–Ð½Ñ–Ñ Line Management Кіраванне лініÑмі Lines serving this stop Прыпынак ліній LKW_tab Грузавікі loaded загружаны loaded passenger/freight Загружана паÑ./грузу Lock game Забараніць змену гульца Lokomotive_tab ЦÑгнікі Mailbox ÐŸÐ°ÑˆÑ‚Ð¾Ð²Ð°Ñ Ñкрынка Mailbox Options ÐаÑтаўленні пошты Maintenance Утрыманне Manufactured: Выраблены: Map roughness ГарыÑтаÑць: March Сакавік Margin (%%) Маржа Marker Знак Max. speed: МакÑ. хутк.: Maximum 254 stops\nin a schedule!\n Ðе дазвалÑецца\nмець болей за 254 прыпынка Ñž раÑкладзе!\n May Травень Median Citizen per town СÑÑ€Ñдні памер гарадоў: Meldung Паведамленне Menge колькаÑць MessageOptionsText \nÐовы год\n\nДзейнаÑць Ш.І.\n\nГарадÑÐºÑ–Ñ Ð½Ð°Ð²Ñ–Ð½Ñ‹\n\nÐÑма маршруту\n\nÐÐ¾Ð²Ñ‹Ñ Ð¿Ñ€Ð°Ð´Ð¿Ñ€Ñ‹ÐµÐ¼.\n\nболтать\n\nÐовы транÑпарт\n\nПерапаўненне ÑÑ‚.\n\nПапÑÑ€Ñджанні\n\nTraffic jams\n\nScenario Modify the selected line ЗмÑніць раÑклад абранай лініі Months МеÑÑцы Mountain height Ð’Ñ‹ÑˆÑ‹Ð½Ñ Ð³Ð¾Ñ€: Music playing disabled/not available Музыка адключана/нÑма файлаў. Music volume: ГучнаÑць муз.: Net Wealth УвеÑÑŒ капітал Neue Karte ÐÐ¾Ð²Ð°Ñ Ð¼Ð°Ð¿Ð° Neue Welt Ðовы Ñвет new convoi Ðовы ÑаÑтаў New Line ÐÐ¾Ð²Ð°Ñ Ð»Ñ–Ð½Ñ–Ñ New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Створана Ð½Ð¾Ð²Ð°Ñ Ð»Ñ–Ð½Ñ–Ñ!\nМожна назначыць лінію,\nабраўшы Ñе\nÑž ÑпіÑе вышÑй. New Vehicles Ðовы транÑпарт no convois нÑма транÑпарту no goods waiting нÑма нічога Ð´Ð»Ñ Ð¿ÐµÑ€Ð°Ð²Ð¾Ð·ÐºÑ– No Route Без маршруту Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Ðбраны транÑпарт не мае раÑкладу.\n Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Ðе магчыма зараз змÑніць\nраÑкладу руху!\nПаўтарыце пазней! November ЛіÑтапад Now active as %s.\n ЦÑпер Ð’Ñ‹ -\n%s.\n Ok Добра On this map, you are not\nallowed to change player!\n Мапа замкнёна!\nЗмена гульца\nна гÑтай мапе\nзабаронена.\n Operation БÑÐ³ÑƒÑ‡Ñ‹Ñ Ð²Ñ‹Ð´. Ops Profit Прыбытак Optionen ÐаÑтаўленні Origin МеÑца Ð°Ð´Ð¿Ñ€Ð°ÑžÐ»ÐµÐ½Ð½Ñ Output Выраблена paletten (Ñшчыкі) Pas_tab ПаÑажырÑÐºÑ–Ñ Passagiere паÑажыры Passagierrate \nПопыт\nна паÑажыраў Passagierziele ПаÑажыры/пошта Ñž Pause Прыпыніць Plant tree ДрÑвы player -1 чалавек player 0 бог player 1 Napik 128 AS player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG Post пошта Postrate \nПопыт\nна пошту Power Эл. Ñ‚. Power: МагутнаÑць: Powerlines Лініі Ñлектр. Produktion ВытворчаÑць Profit Прыбытак promote to line ÐÐ¾Ð²Ð°Ñ Ð»Ñ–Ð½Ñ–Ñ q1 Ð’ÑÑна q2 Лета q3 ВоÑень q4 Зіма Random map Ð’Ñ‹Ð¿Ð°Ð´ÐºÐ¾Ð²Ð°Ñ Ð¼Ð°Ð¿Ð° Rating ЗабеÑп. Reliefkarte Мапа Restore natural slope Ðднавіць натуральны Ñхіл Restwert: Кошт продажу: Retire. date: Спын. вытв.: return ticket +Ðдваротны шлÑÑ… Revenue Выручка sack (мÑшкі) sail Вецер Schienentunnel Чыгуначны тунÑль Schiff_tab Ð“Ñ€ÑƒÐ·Ð°Ð²Ñ‹Ñ Schiffdepot Суднавае дÑпо Schleppkahn_tab Баржы Screenshot Здымак Sell the selected vehicle(s) Прадаць абраны транÑпарт SEP_FRACTION , SEP_THOUSAND . September ВераÑень Serves Line: Ðа лініі: Service Ðд/Ð¿Ñ€Ñ‹Ð±Ñ‹ÑžÑˆÑ‹Ñ Ship Судна Show also vehicles no longer in production. Паказваць тр. адзінкі, ÑÐºÑ–Ñ ÑžÐ¶Ð¾ не выраблÑюцца. Show obsolete +ÑаÑтарÑÐ»Ñ‹Ñ Show/hide statistics Паказаць/Ñхаваць ÑтатыÑтыку Shrink city Паменшыць колькаÑць жыхароў Size (%d MB): Памер (%d MБ): Sort by Сартаваць Sort waiting list by КатÑÐ³Ð¾Ñ€Ñ‹Ñ ÑÐ°Ñ€Ñ‚Ð°Ð²Ð°Ð½Ð½Ñ ÑпіÑу: Sound Гук Sound settings Ð“ÑƒÐºÐ°Ð²Ñ‹Ñ Ð½Ð°Ñтаўленні Sound volume: ГучнаÑць: special freight Ñпец. груз Speedlimit МакÑ. хутк. Speichern Захаваць Spieler Гулец Spieler(mz) Гульцы Spielstand wurde\ngeladen!\n \nСтан гульні\nбыў прачытаны!\n Spielstand wurde\ngespeichert!\n \nСтан гульні\nбыў запіÑаны!\n Sprache Мова Stadtinformation ЗвеÑткі пра горад Start ПуÑк Start the selected vehicle(s) ЗапуÑціць абраны транÑпарт Starte Spiel Пачаць гульню Status Стан steam Пара Step timeline one year ПраÑкочыць праз год Storage capacity ЗмÑшчальнаÑць Strassendepot Ð/м дÑпо Strassentunnel ÐўтатунÑль Tage alt (узроÑÑ‚, дні) There are still vehicles\nstored in this depot!\n У гÑтым дÑпо ÑшчÑ\nзнаходзіцца транÑпарт!\n This Year ГÑты год: Tile not empty. Ðельга выпаўніць,\nбо поле занÑтае.\n tl_title Ð¡Ð¿Ñ–Ñ Ð³Ð°Ñ€Ð°Ð´Ð¾Ñž To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %s\nпабудаваў %s\nз дапамогай %i падатка-\nплацельшчыкаў, каб прыцÑгнуць\nбольш турыÑтаў.\n To heavy traffic\nresults in traffic jam.\n Шчыльны дарожны рух:\nÐ´Ð°Ñ€Ð¾Ð¶Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð±ÐºÐ°.\n tonnen Ñ‚ Total inhabitants: ÐаÑельніцтва: Tourist attractions СлавутаÑці мÑÑцінаў: Tourists СлавутаÑці Towns Гарады Tracks РÑйкі Traffic Дарожны рух Train ЦÑгнік Transported перавезена Truck Ðўто Tunnel muss an\neinfachem\nHang beginnen!\n ТунÑль павінен пачынацца\nад роўнага Ñхілу!\n Unemployed БеÑÐ¿Ñ€Ð°Ñ†Ð¾ÑžÐ½Ñ‹Ñ Unhappy ÐÐµÐ·Ð´Ð°Ð²Ð¾Ð»ÐµÐ½Ñ‹Ñ Ð¿. units/day адзінак/дзень Update Line ЗмÑніць лінію Use timeline start year Год пачатку гульні: Vehicle %s can't find a route! %s\nÐ½Ñ Ð¼Ð¾Ð¶Ð° знайÑці\nдарогі! Vehicle details ПадрабÑÐ·Ð½Ñ‹Ñ Ð·Ð²ÐµÑткі пра ÑаÑтаў. Verbrauch Спажыванне verkaufen Продаж Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n ЗапазычанаÑць:\n\nМеÑÑцаў\nвыплаціць доўг: %d \n via прамеж. пункт via Menge транзіт, кольк. voranstellen д-не ўперад Waggon_tab Вагоны waiting Чакае перав. Water level Узровень вады: Wegpunkt пункт на мапе Wert Кошт WRONGSAVE \nÐеÑумÑÑˆÑ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑÑ–Ñ Ð·Ð°Ð¿Ñ–Ñу Ñтану гульні. \nГульні загрузіць немагчыма.\n Year %i has started. ПачаўÑÑ %i год. Years Гады Zielort меÑца прызн. Zu nah am Kartenrand Заблізка ад канца мапы,\nкаб нешта будаваць. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ 1center %s %s 1extern %s СельÑкі %s 2center %s Галоўны %s 2extern %s Блізкі %s 3center %s ЦÑнтральны %s 3extern %s Прыгарад %s 4center %s СÑÑ€Ñдні %s 4extern %s Дальні %s 5center %s Рабочы %s simutrans-124.3/simutrans/text/bg.tab000066400000000000000000000071521474050137200176510ustar00rootroot00000000000000§Bulgarian PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: bg Bulgarian # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic ÐрктичеÑки климат desert ПуÑÑ‚Ð¸Ð½Ñ temperate Умерен #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Тук не можеш да депо(гараж) Not enough money! ÐедоÑтатъчно ÑредÑтва(пари) #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ air Въздух airplane Самолет Airport Летище Apply Line използвай Ð»Ð¸Ð½Ð¸Ñ April Ðприл Arbeiter aus: Работниците живеÑÑ‚ в: Arrivals from\n приÑтигане от\n Arrived ДоÑтавено Assets Ðвтомобили ÑтойноÑÑ‚ August ÐвгуÑÑ‚ Boost (%%) Увеличете (%%) Build air depot ПоÑтрой хангар Build maglev depot ПоÑтрой МагЛев депо Build narrowgauge depot ПоÑтрой теÑнолинейно депо Build powerline ПоÑтрой далекопровод follow me Ñледвам Forest Гора Found new city ОÑнови град fuel_cell Горивна клетка Full load Пълен товар Fundament ОÑнова go home в депо Goods Стоки Goods AI Стоки на AI Goods list СпиÑък на Ñтоки Growth РаÑтеж Hangar Хангар Happy ЩаÑтливи / РадоÑтни Help Помощ Help text not found ТекÑтът не е намерен hide all building Скрий вÑички Ñгради hide city building Скрий жилищните Ñгради hide station names Скрий имената на гарите(Ñпирките) hide trees Скрий дърветата Homeless Бездомен hydrogene Водород industrial building ИндуÑтриална Ñграда Invalid coordinate Ðевалидни кординати January Януари join game ПриÑъедини Ñе July Юли June Юни Load scenario Зареди Ñценарий Lokomotive_tab Локомотиви Neue Karte Ðова карта Stadtinformation ÑтатиÑтика на града Start Ñтарт Start the selected vehicle(s) Отправи избраното превозно ÑредÑтво Starte Spiel Старт игра simutrans-124.3/simutrans/text/ca.tab000066400000000000000000001313611474050137200176440ustar00rootroot00000000000000Catala PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: ca Catala # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Desactivat cl_btn_filter_enable Activat cl_btn_filter_settings Opcions cl_btn_sort_asc Ascendent cl_btn_sort_desc Descendent cl_btn_sort_id Identificació interna cl_btn_sort_income Ingressos cl_btn_sort_name Nom cl_btn_sort_type Tipus clf_btn_alle tot clf_btn_invers inv. clf_btn_keine res gl_btn_sort_bonus per bonus gl_btn_sort_name per nom gl_btn_sort_revenue per ingressos gl_btn_unsort desordenat hl_btn_filter_disable Desactivat hl_btn_filter_enable Activat hl_btn_filter_settings Opcions... hl_btn_sort_asc Ascendent hl_btn_sort_desc Descendent hl_btn_sort_name Nom hl_btn_sort_type Tipus hl_btn_sort_waiting En espera hlf_btn_alle tot hlf_btn_invers inv. hlf_btn_keine res Networks Xarxes Queueing Cua d'espera Road toll Peatge Scenario Escenari Transfers Transbordaments #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic clima molt fred desert clima desèrtic mediterran Mediterrani rocky Alpí temperate Templat tropic Tropical tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed No s'ha pogut carregar\nel script de l'escenari!\n Can't buy obsolete vehicles! No es poden comprar vehicles obsolets! Cannot alter water No es pot alterar l'aigua Cannot built depot here! No puc construir una cotxera aquí. Cannot built this station/building\nin underground mode here. L'edifici no es\npot construir sota terra.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. No puc crear una línia genèrica!\nSeleccioneu el tipus de línia\nemprant el filtre. Cannot create socket No s'ha pogut crear el socket Convoi handles exhausted! Els controladors de combois estan esgotats! Convoy already deleted! El comboi ja ha estat eliminat! Das Feld gehoert\neinem anderen Spieler\n Aquesta parcel·la\nés propietat\nd'un altre jugador!\n Der Besitzer erlaubt das Entfernen nicht El propietari no dóna\npermís per a\neliminar-ho.\n Diese Zusammenstellung kann nicht fahren!\n No puc conduirn\naquesta combinació!\n Flugzeughalt muss auf\nRunway liegen!\n Una aturada d'avió\nha de col·locar-se sobre una pista de\nrodatge! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Aquest edifici aeroportuari\n\nno es pot construir aquí!\n Hier kann kein\nSignal aufge-\nstellt werden!\n ¡No podeu\ninstal·lar senyals\naquí!\n In order to lock the game, you have to protect the public player by password! Per a protegir la partida ha de crear una contrasenya pel jugador Servei Públic! Lost connection\nto server! S'ha perdut la connexió\namb el servidor! Lost synchronisation\nwith server. S'ha perdut la sincronització\namb el servidor. Maglevhalt muss auf\nMaglevschiene liegen!\n L'estació de monocarril ha d'estar\nsobre una via de monocarril Monorailhalt muss auf\nMonorail liegen!\n Una estació de monocarril\ns'ha de construir sobre una\nvia de monocarril! Monorails are not available yet! Els monocarrils encara no estan disponibles! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n L'estació s'ha de construir sobre una via estreta! No suitable way on the ground! Les estacions s'han de construir sobre un tram de via recta! No through station here! No es pot construir l'estació aquí!\nEs necessita una secció recta de via! Not enough money! No tens prou diners\nper a construir això! On narrowgauge track only!\n Només per via estreta! Only public player can lock games! Només el jugador Servei Públic pot protegir la partida! Out of funds No tens prou diners\nper a això! Post muss neben\nHaltestelle\nliegen!\n ¡Ubiqueu una oficina postal\nprop d'una estació!\n Protocoll error (expecting game) Error de protocol (s'esperava una partida) Schiffhalt muss im\nWasser liegen!\n ¡Sols podeu col·locar\nestacions marítimes\na l'aigua!\n Server busy Servidor ocupat. Terraforming not possible\nhere in underground view No és possible modificar el\nterreny en mode subterrani.\n Upgrade must have\na higher level L'actualització ha de tenir\nun nivell superior. Vehicle %s cannot choose because stop too short! El vehicle %s no pot escollir perquè l'estació és massa curta! Zughalt muss auf\nSchiene liegen!\n ¡Sols podeu col·locar\naturades de\nferrocarril a\nles vies!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Ajuda

Índex

Sobre Simutrans

%1$s

Com es fa servir

%2$s

Com començar una partida

%4$s

Com jugar

%5$s

Eines

%3$s

Altres finestres

%6$s Keyboard Help\n

Keyboard Help

\n Teclat\n

Ajuda del teclat

\n

\nL'ajuda del teclat mostra les funcions per a les tecles que es poden prémer.\n

\n

\nL'ajuda del teclat s'obre quan es prem una tecla no assignada a l'ajuda general.\n

\n

\nLes tecles premudes diferencien les majúscules (fent servir [Shift] per a aquestes lletres).\n

\n

\nLes tecles que tenen funcions assignades són:\n

\n

\n[Tecles de direcció]: desplaça la pantalla del joc en la direcció de la fletxa.
\n[Esborrar]: tanca totes les finestres, barres de tasques i ajudes contextuals del joc en curs.
\n[Esborrar], o [Escape]: tanca la finestra d'un nivell superior, barres de tasques o ajuda contextual del joc en curs.
\n[Introduïu]: s'empra per a confirmar accions.
\n[Pàgina amunt], o [>]: amplia la imatge.
\n[Pàgina baix], o [símbol "menor que"]: allunya la imatge.\n[F1]: obre l'ajuda de Simutrans.

\n

\n[1]: desplaça el joc cap al sud.
\n[2]: desplaça el joc cap al sudest.
\n[3]: Desplaça el joc cap a l'est.
\n[4]: desplaça el joc cap al sudoest.
\n[6]: desplaça el joc cap al nordest.
\n[7]: desplaça el joc cap a l'oest.
\n[8]: desplaça el joc cap al nordoest.
\n[9]: desplaça el joc cap al nord.\n

\n

\n[Shift] + ratolí: empreu-ho per al mapa per a veure les connexios de lacadena industrial.
\n[CTRL] + eina: construeix (senyals i aturades) a un nivell superior; o carreteres de baixa velocitat damunt una de més ràpida; o carreteres i vies rectes (sobretot diagonals).
\n[CTRL] + ([F2] a [F12]): memoritza l'eina activa a una de les tecles de [F2] Decrease water height Drenar l'aigua un nivell Highlight railroad tracks Destacar ferrocarrils Highlite depots Destacar cotxeres Highlite electrical transmission lines Destacar línies elèctriques Highlite factories Destacar indústries Highlite forests Destacar boscos Highlite tourist attraction Destacar atraccions turístiques Increase water height Augmentar l'aigua un nivell Overlay city limits Veure límits de ciutats Overlay passenger destinations when a town window is open Destacar els destins dels passatgers quan s'obre una finestra d'una població Overlay schedules/network Veure línies/xarxes Overlay town names Veure noms de poblacions Please click on the map to add\nwaypoints or stops to this\nschedule. Faci clic sobre el mapa\nper afegir punts de pas o\nparades a la línia. Set tile climate %s Convertir aquest terra en clima %s. Show capacity and if halt is overcrowded Veure capacitat i estacions plenes Show how many convoi reach a station Veure quans combois passen per les estacions Show how many people/much is waiting at halts Veure quanta gent o mercaderies esperen a les estacions Show initial passenger departure Veure origen dels passatgers Show level of city buildings Veure nivell dels edificis Show mail service coverage/mail network Veure cobertura/xarxa del servei de correus Show passenger coverage/passenger network Veure cobertura/xarxa del servei de passatgers Show speedlimit of ways Veure els límits de velocitats de les infraestructures Show the change of waiting at halts Veure el canvi del temps d'espera des de l'últim mes Show the owenership of infrastructure Veure els propietaris de les infraestructures Show transported freight/freight network Veure xarxa de transport de mercaderies Show usage of network Veure l'ús de les xarxes Shows a listing with all industries on the map. Veure totes les indústries al mapa Sum of departure/arrivals at halts Veure total de sortides i arribades a les estacions #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s ara\nofereix serveis de bus\nentre %s\ni l'atracció\n%s\na (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s ara\nofereix serveis de bus\nentre %s\ni la indústria\n%s\na (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s ara\nofereix servei de\n%i camions entre\n%s a (%i,%i)\ni %s\na (%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nha obert una línia\nferroviària entre\n%s a (%i,%i)\ni %s\na (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Línia aèria per\n%s\nara en servei entre\n%s \ni %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Línia de Ferry per\n%s\nara en servei entre\n%s \ni %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Ara els viatgers\nagafen els autobusos\nde %s entre\n %s\ni %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Eines de mapa LISTTOOLS Llistes MAGLEVTOOLS Eines de maglev MONORAILTOOLS Eines de monocarril NARROWGAUGETOOLS Eines de ferrocarril de via estreta RAILTOOLS Ferrocarrils ROADTOOLS Carreteres SHIPTOOLS Vaixells SLOPETOOLS Eines d'alçades i talussos SPECIALTOOLS Eines especials de construcció TRAMTOOLS Eines de tramvia #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s ha construït una nova base d'operacions. Factory chain extended\nfor %s near\n%s built with\n%i factories. L'economía creix:\n%s prop de %s s'hi afegeixen a la cadena de producció.\n%i noves indústries establertes. New %s now available:\n%s\n Nou %s ara disponible:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Nova cadena industrial\nper %s\naprop de %s\nconstruïda amb\n%i indústries. New vehicle now available:\n%s\n \n Nou vehicle disponible:\n\n\n » %s «\n\n Now %u clients connected. Actualment hi ha %u client(s) connectat(s). Remove vehicle from map. Use with care! Eliminar vehicle del mapa. Fes-ho servir amb precaució! Screenshot\ngespeichert.\n Fotografia\nsalvada.\n Sends the convoi to the last depot it departed from! Envia el comboi a la cotxera d'on va sortir l'última vegada. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Fent-hi una festassa, a\n%s\nhan inaugurat un nou monument.\nHan fet feliços a %i ciutadans. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Buscar línia #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (a la cotxera) [CTRL] CTRL [END] FI [HOME] INICI \nBauzeit bis fins a \nBauzeit von \n hi apareix amb data \nCan't open heightfield file.\n \nNo puc obrir el plànol\ntopogràfic.\n \ndirection: \ndestinacions: \nelektrified \nelectrificat\n \nHeightfield has wrong image type.\n \nEl plànol té un tipus d'imatge incorrecte.\n \nis reserved by: \nreservat pel tren \nminimum speed: \nvelocitat mínima: \nnot elektrified \nsense electrificar\n \nRibi (masked) \ndestinacions\m (ocultat): \nRibi (unmasked) \ndestinacions\n (visibles): \nSet phases: \nAjustar fase: \nsingle way \nSentit únic \nway1 reserved by L'accés 1 està reservat per \nL'accés 1 està reservat per \nway2 reserved by L'accés 2 està reservat per \n L'accés 2 està reservat per \nwith sign/signal\n \nNo té senyalètica\n %d buildings\n %d edificis\n %d Einzelfahrzeuge im Depot %d vehicles aturats aquí. %i km/h (max. %ikm/h) %i km/h (màx. %ikm/h) %i years %i months old. %i anys %i mesos d'antiguitat. %s at (%i,%i) now public stop. %s a (%i,%i) és ara una estació pública. %s building %s %s %s %s %s %s city %d %s %s ciutat %d %s %s factory %s %s %s - Estació %s %s has entered a depot. %s ha entrat a la cotxera. %s land %d %s %s comarca %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s\nha construït\nun nou ajuntament\nen arribar\nals %i habitants %s\nis crowded. %s\nestà saturada! %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nvelocitat %i\nv.màxima %i\ndx:%i dy:%i %s\nwas liquidated. %s\ ha aturat la seva activitat. %u Player (%u locked)\n %u jugadors (%u bloquejats)\n Crear línia nova 1 Einzelfahrzeug im Depot Aquí roman 1 vehicle. 1LIGHT_CHOOSE Lluentor: 1WORLD_CHOOSE Opcions del nou mapa: 2LIGHT_CHOOSE Colors: 2WORLD_CHOOSE Número de mapa: 3LIGHT_CHOOSE Vel. desplaç.: 4LIGHT_CHOOSE Inverteix desplaçament 5LIGHT_CHOOSE Mostra peatons a aturades 5WORLD_CHOOSE Número ciutats: 6LIGHT_CHOOSE Peatons a les ciutats 6WORLD_CHOOSE Dens. de trànsit: 8WORLD_CHOOSE Usa mode dia i nit A bridge must start on a way! Sols podeu construir\nponts a vies existents\no rampes buides. Abfrage Explora Abnehmer Consumidor About Quant a About scenario Copyright Abriss Elimina Absenken Rebaixa terreny Abspanntransformator Transformador industrial Accelerate time Accelera temps Act. load: %u MW\n Càrrega actual: %u MW\n Active player only Només jugador actiu Add forest Afegir bosc Add random citycar Afegir cotxe privat add server Afegir servidor Add Stop Afegeix aturada. Add stops for backward travel Afegeix aturades per a la tornada. aircraft_tab Avions de càrrega airplane avió Airport Aeroport AIRTOOLS Eines d'aeroport All Totes all convoi tooltips Estat dels combois Allow city growth Permetre creixement urbà Allow player change Permet canvi de jugador allowed climates:\n Climes disponibles:\n Alters a schedule. Afegir/treure aturades a/d'una ruta Angenommene Waren Indústries properes demanden anhaengen Afegeix Anhaenger_tab Remolcs Anheben Eleva terreny Appends stops at the end of the schedule Afegeix parades al final de la línia Apply Line Aplica línia April Abril Arbeiter aus: Treballadors de: Arrived Ha arribat Assets Actius Aufloesen Desassembla Aufspanntransformator Transformador August Agost Autohalt muss auf\nStrasse liegen!\n Les aturades\nhan d'estar\ndamunt una calçada. Available Disponible Bahndepot Cotxera ferrocarril Bankrott:\n\nDu bist bankrott.\n Bancarrota:\n\nEsteu en bancarrota.\n battery Bateria Baum Arbre baum builder Sembra arbres Baustelle Lloc en\nconstrucció Bauzeit Període de construcció Beenden Surt Beginner mode Mode novell Besonderes Gebaeude Atracció turística BF - Estació bio biològic Blockstrecke ist\nbelegt\n Un altre tren\nempra\naquest segment de via\n Boden Terra Bonusspeed: %i km/h Màxima velocitat real: %i km/h Boost (%%) Incrementar producció (%%) bridge is too high for its type! No puc construir un pont d'aquest tipus a tanta alçària. Bridge is too long for this type!\n La distància entre pilars és massa llarga per a aquest tipus de pont. Bruecke Pont Bruecke muss an\neinfachem\nHang beginnen!\n El pont deu\ncomençar a un\npendent recte!\n Brueckenboden pont Build air depot Construir hangar build choosesignals Posa un senyal de selecció d'andana Build city market Posa un mercat a la ciutat més propera Build drain Transformador elèctric build HQ Obre la base d'operacions Build land consumer Posa una central elèctrica Build maglev depot Posa una cotxera de tren levitant Build monorail depot Posa una cotxera de monorail Build narrowgauge depot Construir cotxera de via estreta Build powerline Posa una línia elèctrica Build presignals Posa senyals de bloqueig Build road depot Posa un garatge Build ship depot Posa unes drassanes Build signals Instal·la senyals Build train depot Construeix cotxera de trens Build tram depot Posa una cotxera de tramvia Build truck depot Construeix cotxera de camions Building costs estimates Cost estimat de construcció Buildings Edificis Built artifical slopes Construeix rampes artificials Built random attraction Construeix una atracció aleatòria Bus_tab Autobusos Can only move from halt to halt or waypoint to waypoint. Només es pot moure entre aturades o punts de pas. Cancel Cancel·la Cannot connect to offline server! No es pot connectar a un servidor apagat! Capacity: Capacitat: Capacity: %.0f MW Capacitat: %.0f MW\n Capacity: %d%s %s\n Capacitat: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capacitat: %s\n? %d (%d%%) Cars are not available yet! Els cotxes encara no estan disponibles. cars.\nstate cotxes\n Cash Balanç Change player Canvia de jugador Chart Gràfic Chat_msg Xat Choose direction Escollir direcció Choose operation executed on clicking stored/new vehicles Trieu quina operació voleu fer quan feu clic a vehicles nous o emmagatzemats. chooses a random map Tria un mapa a l'atzar. citicens Ciutadans City attraction Atracció turística de ciutat City industries Indústries urbanes City list Llistat de ciutats City size Mida de la ciutat city_road Carrer citybuilding builder Constructor d'edificis CityLimit Límits de la ciutat cl_title Llistat de vehicles cl_txt_sort Ordena per: Clear block reservation Mostra/oculta les vies reservades clf_chk_aircrafts avions clf_chk_cars Autobús/camió clf_chk_indepot és a cotxeres clf_chk_maglev Tren levitant clf_chk_monorail Monorail clf_chk_name_filter Nom filtre: clf_chk_narrowgauge Trens de via estreta clf_chk_noincome Sense ingressos clf_chk_noline no té línia assignada clf_chk_noroute no troba el camí clf_chk_noschedule Sense ruta assignada clf_chk_obsolete Obsolet clf_chk_ships Vaixells clf_chk_spezial_filter Filtre especial: clf_chk_stucked embussat clf_chk_trains Trens clf_chk_trams Tramvies clf_chk_type_filter Tipus: clf_chk_waren Tipus de càrrega: clf_title Mostra sols aquests vehicles: Climate Control Canvia el clima closed tancat. COLOR_CHOOSE\n Per favor, trieu\nun color de la\ntaula:\n Company bankrupt Companyia en fallida Company_msg Competència Comparing pak files ... Comparant arxius pak... Configure AI Configuració IA Configure AI setttings Propietats Configuració IA Congratulation\nScenario was complete in\n%i months %i years. Enhorabona!\nHeu complet l'objectiu en \%i mesos i %i anys! Connected stops Estacions connectades Connected with server Connectat amb servidor Constructed by Fet per Constructed by %s Fet per %s construction speed Velocitat de construcció Construction_Btn Cost de construcció Consumed Consumit convoi %d of %d Comboi %d de %d convoi error tooltips Textos d'error en combois Convoi has been sent\nto the nearest depot\nof appropriate type.\n He enviat el convoi\na la cotxera adient.\n Convoi is sold when all wagons are empty. Vendré el vehicle quan estigui buid. convoi mouseover tooltips Textos de ratolí en combois convoi passed last\nmonth %i\n \nconvois que circularen\nel mes passat: %i\n Convois combois Convois: %d\nProfit: %s Vehicles: %d\nBenefici: %s Convoys Convois Copy Convoi Copia el convoi Copy the selected convoi and its schedule or line Copia el convoi i la seva ruta cost for removal cost de demolició Costs Costos Create a new line based on this schedule Crea una nova línia basada en aquesta ruta curiosity builder Constructor de monuments curlist_title Llistat d'atraccions Currently playing: Llista de pistes: Customers live in: Els clients viuen a: deactivated in online mode Desactivat en mode online Deccelerate time Desaccelera el temps December Desembre decrease underground view level baixar nivell subterrani Del Stop Elimina Delete Line Esborra la línia Delete the current stop Eliminar aquesta parada Delete the selected line (if without associated convois). Eliminar la línia seleccionada (si no té combois associats) Delete this file. Esborra aquest fitxer. Delivered Subministrats Demand Demanda Demand: %.0f MW Demanda: %.0f MW\n Denkmal Monument Departed Va sortir Depots Cotxeres Der Tunnel ist nicht frei!\n El túnel no està buid.\n Destination Destinació Destroying map ... Destruint mapa... Details Detalls Die Bruecke ist nicht frei!\n El pont no està lliure!\n diesel dièsel Direkt erreichbare Haltestellen Aturades connectades directament disable midi Lleva la música MIDI Display settings Ajustaments pantalla Distance Distància Dock Moll Dock must be built on single slope! Els molls només poden bastir-se damunt un pendent. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Teniu %d mesos per a pagar allò que deveu. Durchsatz Màx. prod. Economy Economia i ciutats Eigenbesitz\n Propietat pública\n Ein %s\npasst hier nicht.\n Un '%s'\nno es pot emprar aquí.\n Einstellungen aendern Canvia opcions electric elèctric Electricity Electricitat Electricity producer\n\n Productor d'electricitat\n\n Electrics_tab Elèctrics Electrify track Electrifica la línia enlarge map Eixamplar mapa enter a value between %i and %i entri un valor entre %i i %i Enter address Introduir adreça Enter Password Introduir contrasenya Error Errada Erzeuge neue Karte.\n Per favor, espereu.\nEstic creant un\nmapa nou ...\n\n (Pot trigar-se\n alguns minuts\n per a mapes grans.)\n Es wird bereits\nein Fahrplan\neingegeben\n Esteu planificant\nuna ruta.\nFinalitzeu-la abans\nde tornar-ne a crear!\n Fabrikanschluss Indústries connectades Fabrikname nom de la fàbrica Factories Fàbriques factory details Detalls de la fàbrica factorybuilder Constructor d'indústries Fahrplan Enruta Fahrtziel Destinació: Fahrzeuge koennen so nicht entfernt werden No podeu eliminar\nels vehicles\naquí.\n Fahrzeuge: Vehicles: Farbe Color jugador Fast forward Accelerar temps February Febrer Ferry_tab Vaixells Fertig Fet Filename Fitxer: Filter: Filtre: Finances of %s Finances de %s Finanzen Finances find mismatch Comparant paks fl_title Llistat d'indústries Flug_tab Passatgers d'avió follow me Seguiu-me. Follow the convoi on the map. Segueix el convoi en el mapa. Forest Boscos Found new city Crear una nova població Fracht Mercaderia Frame time: Retard: Free Capacity Capacitat freeplay mode Sense fallida Friction: quoeficient de fricció: fuel_cell pila de combustible Full load Càrrega mínima Fundament Cimentació Fussgaenger Vianant Game info Informació de la partida GAME PAUSED JOC EN PAUSA Game_msg General Gear: Marxa: Gebaeude Edifici Generated Generat Generation: %.0f MW Generació: %.0f MW\n Gewicht Pes Gewinn Ingressos Give the selected vehicle(s) an individual schedule Atorga al(s) vehicle(s) seleccionat(s) un itinerari individual. gl_btn_sort_catg per categoria gl_title Llistat de béns go home Vés a cotxera. Goods Mercaderies Goods AI Mercaderies IA Goods list Llistat de béns Gross Profit Benefici brut Groundobj Objecte Grow city Amplia la ciutat. Growth Creixement urbà H - Parada Happy Content Haus kaufen Comprar casa Helligk. Pantalla Help Ajuda Help text not found No trobo el text d'ajuda. hide all building Amaga tots els edificis hide city building Amagar edificis urbans hide objects under cursor Amagar objectes sota el cursor hide station names amagar noms d'estacions hide transparent transparents, no amagats hide trees Amagar àrbres Hier warten/lagern: Passatge/mercaderia esperant: Higher transport fees, crossconnect all factories Taxes de transport més grans, desactivar Just-in-Time Highlite schedule Destacar parades d'itineraris hl_title Llistat d'estacions hl_txt_filter Filtre: hl_txt_sort Ordena per: hlf_chk_airport Aeroports hlf_chk_anleger Vaixells hlf_chk_bahnhof Estació de ferrocarril hlf_chk_bushalt Parada d'autobús hlf_chk_frachthof Zona de càrrega hlf_chk_keine_verb Sense connexió hlf_chk_maglevstop Estació de maglev hlf_chk_monorailstop Estació de monocarril hlf_chk_name_filter Nom filtre: hlf_chk_narrowgaugestop Estació via estreta hlf_chk_overflow Saturat hlf_chk_spezial_filter Filtre especial: hlf_chk_tramstop Estació de tramvia: hlf_chk_type_filter Tipus transport: hlf_chk_waren_abgabe Producció: hlf_chk_waren_annahme Tipus de càrrega: hlf_title Mostra sols aquestes estacions: Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Cotxera inicial no trobada!\nHa d'enviar manualment\nel comboi a la cotxera. Homeless Sense sostre: hydrogene Hidrògen Idle: Inactiu: ignore climates ignorar climes In the industry legend show only currently existing factories Només indústries existents Increase Industry density Afegir cadena industrial increase underground view level pujar nivell subterrani industrial building Edifici industrial Init map ... Iniciar mapa... Input Subministrament Ins Stop Inserta Insert stop before the current stop Inserta una parada abans d'aquesta parada. Intercity road len: Long. carretera interurbana: Intro. date: Introducció: invalid no vàlid. Invalid coordinate Ordre no vàlida isometric map Mapa isomètric January Gener join game Jugar online July Juliol Jump to Anar a June Juny Kann Spielstand\nnicht laden.\n ¡És impossible llegir/obrir\nl'arxiu guardat!\n Kann Spielstand\nnicht speichern.\n ¡És impossible obrir\nl'arxiu per a\nguardar-lo!\n Kein Besitzer\n Sense propietari keine res Keine Einzelfahrzeuge im Depot No hi ha vehicles emmagatzemats. Keyboard_Help\n Ajuda del teclat\n koord Coordenades Kreuzung Cruïlla labellist_title Llista de marcadors Lade Relief Carrega topografia Laden Carrega Land attraction Atracció turística d'interior Land industries Cadenes industrials: LANG_CHOOSE\n Per favor, trieu\nun idioma:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Mes passat: Last Year Any passat: Leaving depot! Sortint de la cotxera! leer buit Legend Llegenda del mapa Leistung Potència Leistung: %d kW Potència: %d kW Leitung Línia elèctrica letzen Monat: diesen Monat: darrer mes: aquest mes: Line Línia Line Management Administració de línies Lineless convoys serving this stop Comboi sense línia servint aquesta parada: Lines serving this stop Línies servint aquesta parada LKW_tab Camions Load game Carregar joc load height data from file Carregar topografia des d'arxiu Load scenario Carrega escenari loaded carregat loaded passenger/freight Ordenar passatgers/mercaderia per Loading (%i->%i%%)! Carregant (%i->%i%%) Loading addon paks ... Carregant objectes extra ... Loading map ... Carregant el mapa... Loading paks ... Carregant paks ... Loading skins ... Carregant temes d'aparença ... Lock game Bloquejar canvi de jugador (demana confirmació) Lokomotive_tab Màquines de tren m3 m³ maglev vehicle vehicle maglev maglev_track via maglev Maglevdepot Cotxera de maglev Mail Demand %d\n Demanda de correu %d\n Mailbox Bústia Mailbox Options Opcions de la bústia Maintenance Manteniment make stop public (or join with public stop next) costs %i per tile and level Fer pública la parada (o fusionar-la amb la següent) costa %i$ per quadricula i nivell Manual (Human) Manual (Humà) Manufactured: Fabricat: Map roughness Terreny abrupte: map zoom ampliar mapa March Març Margin (%%) Marge (%%) Marker Col·loca un cartell max màx. Max Boost (%%) Augment máx.(%%) Max income: Ingressos màx. Max. speed: Vel. màx. Maximum 254 stops\nin a schedule!\n Màxim 254 parades\nper línia!\n maximum length of rivers long. màxima rius Maximum tile height difference reached. La diferència total\nd'alçada entre dos\ncaselles ha de ser\ninferior a dos nivells. Maxspeed Velocitat màxima May Maig Median Citizen per town Població per ciutat: Meldung Missatge Menge quantitat MessageOptionsText \nAny nou\n\nNotícies AI\n\nNotícies Ciutats\n\nSense Ruta\n\nNoves Indústries\n\nXat\n\nNous Vehicles\n\nEstacions Saturades\n\nProblemes\n\nEmbussos\n\nEscenari min mín. minimum length of rivers long. mínima rius Missing pakfiles Falten objectes (pak)! Modify the selected line Modificar la línia seleccionada. Monate alt Mesos d'antiguitat Monorail Monocarril monorail vehicle vehicle de monocarril monorail_track via de monocarril Monorailboden Suport de monocarril Monoraildepot Cotxera de monocarril month wait time Espera (mesos) Months Mesos Mountain height Alçada muntanyes: Movingobj Objecte mòbil Music playing disabled/not available Música desactivada o no disponible Music volume: Volum de la música: mute sound treure so Name Nom Narrowgauge Via estreta Narrowgauge are not available yet! Encara no estan disponibles els vehicles de via estreta! narrowgauge vehicle vehicles de via estreta narrowgauge_track Via estreta Narrowgaugedepot Cotxera de trens de via estreta Net ID: %p ID xarxa: %p\n Net Wealth Valor net Net wealth near zero Valor net prop de zero Neue Karte Nou Neue Welt Crea un nou món new convoi Nou comboi New Line Nova línia New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nova línia creada!\nPots assignar la línia\nseleccionant-la des del\ndesplegable 'línia' d'adalt. New Vehicles Vehicles nous Nickname: Nick: no buildings hidden no hi ha edificis ocults no convois sense combois No goods are loaded onto this convoi. Aquesta configuració no transporta mercaderies no goods waiting No hi ha mercaderia esperant no load Sense càrrega No Route Sense ruta No stop here! Aquesta eina s'ha de fer servir sobre una parada! No suitable ground! No és el terreny adient! No terminal station here! No hi ha estació terminal! no timeline tots temps no tree sense arbres Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n ¡Assigneu una ruta\nal vehicle abans\nde donar-li l'ordre\nde sortida!\n none res nord Nord nordost Nord-est nordwest Nord-oest Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! No està permès!\nLa línia ferroviaria no pot\ncambiar-se ara.\nProvi-ho més tard. Not enough fields would remain. No hi ha prou\nespai al voltant\d'aquesta granja. November Novembre Now active as %s.\n Ara actiu com %s.\n Number of rivers rius Object Objecte Odometer: %s km Quilometratge: %s km Ok Acceptar Oktober Octubre On loan since %i month(s) En números vermells durant %i mesos On this map, you are not\nallowed to change player!\n La partida està bloquejada!\nNo es pot canviar de jugador!\n Only city chains Només indústries de ciutat Only first %d differing paks reported. There are probably more. Només els primers %d paks diferents reportats. Probablement n'hi hagi més. Only land chains Només cadenes industrials de ciutat Only one transformer per factory! Cada fàbrica només pot tenir un transformador! Only show goods which are currently handled by factories Només mostrar mercaderies processades actualment per les indústries open obert Operation Costos d'operació Ops Profit Benefici operació Optionen Opcions Or enter a server manually: O entri un servidor manualment: Origin Origen ost Est Output Producció Ownership Propietari Pak which may cause severe errors: Els següents objectes (pak) falten, cosa que pot provocar errors en les xarxes de transport: Pak which may cause visual errors: Els següents objectes (pak) han estat substituïts per objectes semblants: Pak(s) different: Pak(s) diferents: Pak(s) missing on client: Pak(s) no trobats al cliente: Pak(s) not on server: Pak(s) no trobats al servidor: Pakset differences Diferències de paksets paletten paquets Pas_tab Trens de passatgers Passagiere Passatgers Passagierrate Nivell de passatgers Passagierziele Destinació del passatge/correu Passenger AI IA de passatgers Passenger Demand %d\n Demanda de passatgers: %d\n Passengers %d %c, %d %c, %d no route Passatgers %d %c, %d %c, %d sense ruta Passengers %d %s, %d %s, %d no route Passatgers %d %s, %d %s, %d sense ruta Password Contrasenya Pause Pausa Pax <%i> Mail <%i> Passatgers <%i> Correu <%i> PaxDest Destins Percent Electricity Producció elèctrica (%% demanda): Planes are not available yet! Encara no estan disponibles els avions! Plant tree Plantar un arbre player Jugador player -1 Humà player 0 servei públic player 1 Napik 128 AS player 10 jugador 10 player 11 jugador 11 player 12 jugador 12 player 13 jugador 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG player 7 jugador 7 player 8 jugador 8 player 9 jugador 9 Please choose vehicles first\n Si us plau, seleccioneu primer els vehicles!\n Post Correu Postrate Nivell de correu Power Potència Power (MW) Potència (MW) Power: Potència: Powerlines Línies elèctriques Problems_msg Problemes Produced Produït Production of %s has been stopped:\n%s\n El %s %s\ns'ha deixat de fabricar\n Production/Boost Producció/Augment Produktion Producció Profit Benefici promote to line Passar a línia\n\n q1 Primavera q2 Estiu q3 Tardor q4 Hivern Query server Contactar servidor rail car Vagó random aleatori Random age Període a l'atzar Random map Mapa l'atzar Rathaus Ajuntament Rating Qualificació ratio_pax rati pass. Relevant Filtrats Reliefkarte Mapa Remove Eliminar remove airstrips Eliminar pistes remove channels Eliminar canals remove interm. signals Eliminar senyals intermitges remove maglev tracks Eliminar vies de maglev remove monorails Eliminar monocarril remove narrowgauge tracks Eliminar trams de via estreta remove powerlines Eliminar línies elèctriques remove roads Eliminar carreteres remove tracks Eliminar vies de tren Remove wayobj %s Eliminar objecte %s replace other signals Substituir altres senyals: replace stop Actualitzar parada request closing Petició de tancament residential house Edifici residencial Restore natural slope Restaurar pendent natural Restwert: Valor de venda: Retire. date: Descatalogat: return ticket Viatge tornada Revenue Ingressos Revision: Revisió: road carretera road vehicle vehicle de carretera Roadsign Senyal de trànsit Rotate map Girar mapa Rotation Rotació Routing Encaminant sack sacs sail vent Saving map ... Guardant mapa... Scenario complete: %i%% Escenari completat: %i%% Scenario Debug Depurar Scenario Error Log Errors de script Scenario Goal Objectius Scenario Info Informació Scenario information Informació Scenario Result Resultat Scenario Rules Normes Schedule changing! Canviant ruta! Schienentunnel Construeix túnel ferroviari Schiff_tab Vaixells Schiffdepot Drassana Schleppkahn_tab Barcasses Screenshot Captura de pantalla Seasons Estacions Sehenswuerdigkeit Atracció turística Select a server to join: Seleccionar un servidor per connectar-hi: Sell the selected vehicle(s) Ven els vehicles seleccionats sended enviat SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September Setembre Server did not respond! El servidor no ha respòs! Serves Line: Serveix la línia: Service Servei set signal spacing Establir espai entre senyals Setting Configuració Ship Vaixell shops and stores Botigues i oficines Show all Veure tot show all building Veure tots els edificis Show also vehicles no longer in production. Veure també els vehicles obsolets. Show also vehicles that do not match for current action. Veure també vehicles que no poden fer-se servir en l'acció seleccionada. Show even servers with wrong version or pakset Veure fins i tot servidors amb versions i paksets no compatibles. show grid Veure quadrícula Show industry Llista d'indústries Show legend Llegenda Show map scale Escala Show mismatched Veure incompatibles Show obsolete Veure obsolets Show offline Veure apagats Show only used Veure només els usats Show schedules Veure itineraris Show servers that are offline Veure servidors apagats Show servers where game version or pakset does not match your client Veure servidors amb versions o paksets no compatibles show station coverage Veure cobertura d'estacions show station names Veure noms d'estacions show waiting bars Veure barres d'estat show/hide block reservations Veure/amagar reserves de blocs show/hide object owner Veure/amagar propietari Show/hide statistics Veure/amagar estadístiques Shows buttons on special topics. Mostra els botons de la llegenda del mapa Shows consumer/suppliers for factories Mostra consumidors/proveïdors de les indústries Shows the color code for several selections. Representa al mapa la selecció fent servir una escala de colors Shows the currently selected schedule Mostra l'itinerari seleccionat\n Shrink city Reduïr ciutat shuffle midis barrejar midis Signal Senyal signal spacing Espai entre senyals Sim: Cicles: Similar view as the main window Vista semblant a la principal del joc Size (%d MB): Mida de mapa (%d MB): sliced underground mode Vista per alçades slot empty Slot buit Smart hide objects Amagar sota el cursor Sort by ordenar per Sort waiting list by Ordenar la llista d'espera per Sound So Sound settings Ajustaments de so Sound volume: Volum dels efectes: special freight Càrrega especial Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus per velocitat\nCarretera %i km/h, Ferrocarril %i km/h\nVaixells %i km/h, Avions %i km/h.\n\n Speedlimit Límit velocitat Speichern Guarda Spieler Jugador Spieler(mz) Jugadors Spielerliste Llista de jugadors Spielstand wurde\ngeladen!\n \n¡Partida carregada!\n Spielstand wurde\ngespeichert!\n \n¡Partida salvada!\n Sprache Idioma Sprachen Idiomes Stadtinformation Estadístiques de la població Start Arrenca Start the selected vehicle(s) Arrencar els vehicles seleccionats. Starte Spiel Començar Station tiles: Caselles d'estació: Station_msg Estacions Status Estat parades steam vapor Step timeline one year Avançar cronologia un any. Stops Parades Storage Magatzem Storage capacity Capacitat d'emmagatzematge Strassendepot Cotxera camió/bus Strassentunnel Construeix túnel de carretera street car tramvia sued Sud suedost Sud-est suedwest Sud-oest Summer snowline Cota estival Supplied: %.0f %% Subministrat: %.0f %% Suppliers Proveïdors Tage alt dies antiguitat There are still vehicles\nstored in this depot!\n Encara hi ha vehicles\napartats en aquest dipòsit\n This Month Aquest mes: This Year Aquest any: Tile not empty. La casella no és buida\nSi us plau, elimini tot\nabans de construir\nun nou talús. timeline Cronologia tl_title Llista de totes les ciutats To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %s ha construït\nun %s\namb l'ajuda de\n%i contribuents.\nEs preveu un augment\ndel turisme! To heavy traffic\nresults in traffic jam.\n L'excés de transit ha\nprovocat un embús!\n Toggle day/night view Activar vista dia/nit Toggle vehicle tooltips Activar missatges de vehicles tonnen t Total inhabitants: Població: Tourist attractions Zones de turisme: Tourists Zones de turisme Town_msg Nous destins Town: %s\n Ciutat de %s.\n Towns Ciutats track via Tracks Vies Traffic Trànsit Train Tren Trains are not available yet! Els trens encara no estan disponibles! Tram Tramvia tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tramvia %i km/h, monocarril %i km/h\nmaglev %i km/h, via estreta %i km/h. tram_track via de tramvia Tramdepot Cotxera de tramvia Trams are not available yet! Els tramvies encara no estan disponibles! Transferring game ... Transferint partida... Transformer only next to factory! Els transformadors s'han d'ubicar al costat d'una indústria! Translation Traducció transparent station coverage cobertura transparent Transported Viatges TrolleyBus_tab troleibús Truck Camió Tunnel muss an\neinfachem\nHang beginnen!\n ¡El túnel ha de\ncomençar a una\npendent recta!\n Tunnel must start on single way! Un túnel ha de començar en una sola carretera! Tunnelboden Túnel underground mode vista subterrània UNDO failed! No es pot desfer.\nNomés es pot desfer la\nconstrucció d'una ruta si\nno s'han construït sobre la\ncarretera senyals, estacions,\nparades ni cap altra cosa. Undo last ways construction Desfer la darrera via/carretera creada Unemployed Aturats Unhappy Descontents units/day unitats/dia Update Line Modificar itinerari upgrade HQ Millorar seu central Usage: %.0f %% Ús: %.0f %% Usage/Output Consum/Producció Use beginner mode Activar mode lliure Use timeline start year Cronologia des de Vehicle %s can't find a route! El vehicle %s\nno pot trobar l'itinerari! Vehicle %s is stucked! El vehicle %s està embussat! Vehicle details Detalls del vehicle Verbrauch Consum Vergroessere die Karte\n Expandir el mapa.\n verkaufen Vendre Verkehrsteilnehmer cotxes de ciutat Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n ¡Teniu un deute!\n\n¡Us resten %d mesos\nper a pagar-lo!\n via per (detall) via %s\n per %s\n via Menge per (quantitat) voranstellen Posar al davant Waggon_tab Vagons waiting esperant Waiting for clearance! Esperant via lliure! Walked caminant Warnings_msg Avisos Wasser Aigua Water Canal Water level Nivell de l'aigua: water vehicle Vaixell way %s cannot longer used:\n El tipus de via %s ja no es pot fer servir.\n way %s cannot longer used:\n%s\n el tipus de via %s ja no es pot utilitzar:\n way %s now available:\n Nou tipus de via disponible: %s\n Ways not connected Les vies no estan connectades Wegpunkt Punt de pas Wert Valor west Oest Winter snowline Cota hivernal withdraw Vendre Withdraw All Vendre tot WRONGSAVE La versió salvada és\nincompatible. No se pot llegir\nl'arxiu.\n Year %i has started. Ha començat l'any %i. Years Anys Your primary color: El seu color primari: Your secondary color: El seu color secundari: Zielort destí zooming in apropar zooming out allunyar Zu nah am Kartenrand Massa prop de\nl'extrem del mapa\nper a construir.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nou rècord mundial de maglevs: %.1f km/h per %s. New world record for monorails: %.1f km/h by %s. Nou rècord mundial de monocarrils: %.1f km/h per %s. New world record for motorcars: %.1f km/h by %s. Nou rècord mundial d'automòbils: %.1f km/h per %s. New world record for narrowgauges: %.1f km/h by %s. Nou rècord mundial de trens de via estreta: %.1f km/h per %s. New world record for planes: %.1f km/h by %s. Nou rècord mundial d'avions: %.1f km/h per %s. New world record for railways: %.1f km/h by %s. Nou rècord mundial de ferrocarrils: %.1f km/h per %s. New world record for ship: %.1f km/h by %s. Nou rècord mundial de vaixells: %.1f km/h per %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL de Mar &1_CITY_SYLL d'Avall &2_CITY_SYLL de Túria &3_CITY_SYLL -roja &4_CITY_SYLL d'Ebre &5_CITY_SYLL castell &6_CITY_SYLL marxant &7_CITY_SYLL d'Amunt &8_CITY_SYLL cor &9_CITY_SYLL ssa &A_CITY_SYLL dels Reis &B_CITY_SYLL per &C_CITY_SYLL Això no existeix! &D_CITY_SYLL Això no existeix! &E_CITY_SYLL Això no existeix! %0_CITY_SYLL Això no existeix! %1_CITY_SYLL Vila %2_CITY_SYLL La Pobla %3_CITY_SYLL Murada %4_CITY_SYLL Santa %5_CITY_SYLL Riba %6_CITY_SYLL Cala %7_CITY_SYLL Mana %8_CITY_SYLL Massia %9_CITY_SYLL Nova %A_CITY_SYLL Casa %B_CITY_SYLL Beni %D_CITY_SYLL Això no existeix! %E_CITY_SYLL Això no existeix! %F_CITY_SYLL Això no existeix! 1center %s %s 1extern %s%s Eixample 1suburb %s %s %s 2center %s%s Centre 2extern %s%s Baixador 2suburb %s Camps verds %s %s 3center %s%s Principal 3extern %s%s Extrarradi 3suburb %s vila %s %s 4center %s%s Avinguda 4extern %s%s Bosc 4suburb Això no existeix! 5center %s%s Passeig 5extern Això no existeix! 5suburb Això no existeix! 6center %s Connexió %s 6extern Això no existeix! 6suburb Això no existeix! 7center %s ciutat %s Acenter %s central %s Aextern %s barri %s Asuburb %s, zona suburbana %s Bcenter %s centre de %s Ccenter %s centre %s %s Csuburb %s afores %s simutrans-124.3/simutrans/text/cn.tab000066400000000000000000001142731474050137200176640ustar00rootroot00000000000000§Sim. Chinese PROP_FONT_FILE wenquanyi_9pt.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: cn Sim. Chinese # # Encoding: UTF-8 # # Font: wenquanyi_9pt.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable ç¦ç”¨ cl_btn_filter_enable å¯ç”¨ cl_btn_filter_settings 设置 cl_btn_sort_asc å‡åº cl_btn_sort_desc é™åº cl_btn_sort_id 内部ID cl_btn_sort_income æ”¶å…¥ cl_btn_sort_name åç§° cl_btn_sort_type 类型 clf_btn_alle 全选 clf_btn_invers å选 clf_btn_keine å–æ¶ˆé€‰æ‹© gl_btn_sort_bonus 红利 gl_btn_sort_name åç§° gl_btn_sort_revenue 收益 gl_btn_unsort æœªæŽ’åº hl_btn_filter_disable ç¦ç”¨ hl_btn_filter_enable å¯ç”¨ hl_btn_filter_settings 设置 hl_btn_sort_asc å‡åº hl_btn_sort_desc é™åº hl_btn_sort_name åç§° hl_btn_sort_type 类型 hl_btn_sort_waiting 等待 hlf_btn_alle 全选 hlf_btn_invers å选 hlf_btn_keine å–æ¶ˆé€‰æ‹© Networks 交通网络 Queueing 排队中 Scenario åœºæ™¯ä¿¡æ¯ Transfers å®¢æµ #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic æžåœ°æ°”候 desert 沙漠气候 mediterran 地中海气候 rocky 高山气候 temperate 温带气候 tropic 热带气候 tundra 苔原气候 #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed 载入场景脚本失败 Can't buy obsolete vehicles! ä¸èƒ½è´­ä¹°å·²æ·˜æ±°çš„è½¦è¾†ï¼ Cannot alter water è¿™æ¡æ²³æµä¸èƒ½è¢«æŽ’干或填埋 Cannot built depot here! 无法在这里建造车库 Cannot built this station/building\nin underground mode here. 该建筑ä¸èƒ½å»ºäºŽåœ°åº• Cannot create generic line!\nSelect line type by\nusing filter tabs. ä¸èƒ½åˆ›å»ºã€Œå…¨éƒ¨ã€ç±»åž‹çš„路线\n请选择åˆé€‚的类型,å†åˆ›å»ºè·¯çº¿ Cannot create socket 未能建立通讯 Convoi handles exhausted! 车辆总数已达到最大 Convoy already deleted! 车辆已移除 Das Feld gehoert\neinem anderen Spieler\n 该陆地属于其他玩家 Der Besitzer erlaubt das Entfernen nicht 该建筑拥有者拒ç»ç§»é™¤å»ºç­‘\n汽车或行人在路上,无法移除 Diese Zusammenstellung kann nicht fahren!\n éžæ³•ç»„åˆ Flugzeughalt muss auf\nRunway liegen!\n 飞机必须放置在滑行é“上 Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n 无法在这里建造飞机场 Hier kann kein\nSignal aufge-\nstellt werden!\n ä¸èƒ½åœ¨è¿™é‡Œæ”¾ç½®é“路标志 In order to lock the game, you have to protect the public player by password! 想è¦é”定游æˆï¼Œå¿…须设置密ç ä»¥é˜²å…¶ä»–çŽ©å®¶ç»§ç»­æ¸¸æˆ Lost connection\nto server! 与æœåŠ¡å™¨å¤±åŽ»è¿žæŽ¥ Lost synchronisation\nwith server. 与æœåŠ¡å™¨å¤±åŽ»åŒæ­¥ Maglevhalt muss auf\nMaglevschiene liegen!\n ç£æ‚¬æµ®è½¦ç«™å¿…é¡»å»ºé€ åœ¨ç£æ‚¬æµ®è½¨é“上 Monorailhalt muss auf\nMonorail liegen!\n å•轨车站必须建造在å•轨轨é“上 Monorails are not available yet! å•轨é“路还ä¸å¯ç”¨ Narrowgaugehalt muss auf\nNarrowgauge liegen!\n 窄轨车站必须建造在窄轨轨é“上 No suitable way on the ground! 车站åªèƒ½è¢«å»ºé€ åœ¨\nstraight等适åˆçš„地方 No through station here! 车站必须建造在路的尽头或é“路直线段上 Not enough clearance. 两æ¡é“路之间需è¦ç•™æœ‰è¶³å¤Ÿçš„空间(高度过于接近) Not enough money! 资金ä¸è¶³ On narrowgauge track only!\n åªé€‚用于窄轨轨é“上 Only public player can lock games! åªæœ‰å…¬å…±çީ家å¯ä»¥é”å®šæ­¤æ¸¸æˆ Out of funds 没有足够的钱购买此物件 Post muss neben\nHaltestelle\nliegen!\n 车站扩展建筑必须建设在车站或ç å¤´é™„è¿‘ Protocoll error (expecting game) 传输åå®šé”™è¯¯ï¼ˆç­‰ä¾æ¸¸æˆï¼‰ Schiffhalt muss im\nWasser liegen!\n 轮船åœé ç‚¹åªèƒ½å»ºé€ åœ¨é è¿‘ç å¤´çš„æ°´é¢ä¸Š Server busy æœåС噍ç¹å¿™ Terraforming not possible\nhere in underground view 无法在地底修整地形 Upgrade must have\na higher level éœ€è¦æ›´é«˜çº§åˆ«æ‰èƒ½å‡çº§ Zughalt muss auf\nSchiene liegen!\n ç«è½¦è½¦ç«™å¿…须建造在é“路轨é“上 #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s 帮助索引\n关于模拟交通(simutrans)\n\n%1$s\n如何使用\n\n%2$s\n如何开始游æˆ\n\n%4$s\n如何æ“作游æˆ\n\n%5$s\n\n工具\n%3$s\n其他窗å£\n\n%6$s Keyboard Help\n

Keyboard Help

\n 键盘帮助\n

键盘帮助

\n

\n键盘帮助 显示快æ·é”®åŠŸèƒ½\n

\n

\n键盘帮助 å½“æŸæœªå®šä¹‰å¿«æ·é”®æŒ‰ä¸‹æ—¶æˆ–从一般帮助打开\n

\n

\nå¿«æ·é”®åŒºåˆ†å¤§å°å†™ (使用[Shift]转æ¢å¤§å°å†™)\n

\n

\n被引用的键包括:\n

\n

\n[æ–¹å‘é”®]: 游æˆåœ°å›¾æŒ‰å…¶æ–¹å‘移动
\n[Backspace]: 关闭游æˆç•Œé¢ä¸­æ‰€æœ‰çš„窗å£ã€å·¥å…·æ å’Œå¸®åŠ©æ–‡æ¡£
\n[Delete]或[Escape]: 关闭游æˆç•Œé¢ä¸­æœ€ä¸Šå±‚的窗å£ã€å·¥å…·æ æˆ–帮助文档
\n[Enter]或[Return]: 确认æ“作
\n[Page-Up]或[>]: 放大游æˆåœ°å›¾
\n[Page-Down]或[<]: ç¼©å°æ¸¸æˆåœ°å›¾
\n[F1]: 打开Simutrans帮助

\n

\n[1]: æœå—移动游æˆåœ°å›¾
\n[2]: æœä¸œå—æ–¹å‘移动游æˆåœ°å›¾
\n[3]: æœä¸œç§»åŠ¨æ¸¸æˆåœ°å›¾
\n[4]: æœè¥¿å—æ–¹å‘移动游æˆåœ°å›¾
\n[6]: æœä¸œåŒ—æ–¹å‘移动游æˆåœ°å›¾
\n[7]: æœè¥¿ç§»åŠ¨æ¸¸æˆåœ°å›¾
\n[8]: æœè¥¿åŒ—æ–¹å‘移动游æˆåœ°å›¾
\n[9]: æœåŒ—移动游æˆåœ°å›¾\n

\n

\n[Shift] + 鼠标: 在地图中打开工业产业链
\n[CTRL] + 工具: 建设慢速公路ã€é“轨或更直的公路ã€é“轨
\n

Decrease water height 使水é¢é™ä½Žä¸€çº§é«˜åº¦ Highlight railroad tracks 高亮标记é“è·¯ Highlite depots 高亮标记车厂 Highlite electrical transmission lines 高亮标记电力线 Highlite factories 高亮标记工厂 Highlite forests 高亮标记森林 Highlite tourist attraction 高亮标记旅游景点 Increase water height 将水é¢å‡é«˜ä¸€çº§é«˜åº¦ #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s 现在在\n%s 和景点 %s(%i,%i)\n之间æä¾›å·´å£«æœåŠ¡ %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s 现在在\n%s 和工厂 %s(%i,%i)\n之间æä¾›å·´å£«æœåŠ¡ %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s 现在è¿è¥ %i 货车往返于\n%s(%i,%i) å’Œ %s (%i,%i) 之间 %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s 在\n%s(%i,%i) å’Œ %s(%i,%i)\nä¹‹é—´å¼€è®¾äº†ä¸€æ¡æ–°é“路线 Airline service by\n%s\nnow between\n%s \nand %s.\n %s 现在在\n%s å’Œ %s\n之间æä¾›èˆªç©ºæœåŠ¡ Ferry service by\n%s\nnow between\n%s \nand %s.\n %s 现在在\n%s å’Œ %s\n之间æä¾›èˆ¹è¿æœåŠ¡ Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s 现在在\n%s å’Œ %s\nä¹‹é—´å¼€è®¾äº†ä¸€æ¡æ–°å·´å£«çº¿ #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS 地图编辑工具 LISTTOOLS åˆ—è¡¨ç®¡ç† MAGLEVTOOLS ç£æ‚¬æµ®é“路工具 MONORAILTOOLS å•轨/ç£æ‚¬æµ®é“路工具 NARROWGAUGETOOLS 窄轨é“路工具 RAILTOOLS é“路工具 ROADTOOLS é“路工具 SHIPTOOLS 船è¿å·¥å…· SLOPETOOLS 地形工具 SPECIALTOOLS 其他工具 TRAMTOOLS 电车/轻轨工具 #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s 建设了一个新总部 Factory chain extended\nfor %s near\n%s built with\n%i factories. ç»æµŽé€æ¸ç¹è£\n%s 扩大产业, 于 %s 附近建设了 %i 间工厂 New %s now available:\n%s\n æ–° %s 现在å¯ç”¨:\n%s New factory chain\nfor %s near\n%s built with\n%i factories. 工业å‘展: %s 新工业链\n于 %s 附近建立了 %i 工厂 New vehicle now available:\n%s\n 新交通工具现在å¯ç”¨\n\n -- %s -- Now %u clients connected. 现在有 %u 个用户已连接 Remove vehicle from map. Use with care! 移除该è¿è¾“工具(请å°å¿ƒä½¿ç”¨!) Screenshot\ngespeichert.\n æ¸¸æˆæˆªå›¾å·²ä¿å­˜ Sends the convoi to the last depot it departed from! å°†è¿è¾“队调回最åŽçš„å‘车库 With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s 为æŸç››å¤§çš„节日建立了纪念馆\n%i 個市民感到å分高兴 #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (在车库) \nBauzeit bis 直到 \nBauzeit von 出现于 \nCan't open heightfield file.\n 无法使用高度图 \ndirection: æ–¹å‘ \nelektrified 电气化 \nHeightfield has wrong image type.\n é«˜åº¦å›¾å›¾åƒæ ¼å¼ä¸æ­£ç¡® \nis reserved by: 已被ç«è½¦å ç”¨ \nminimum speed: 最低时速: \nnot elektrified 未电气化 \nRibi (masked) 通行方å‘(å³): \nRibi (unmasked) 通行方å‘(å·¦): \nSet phases: 调节å—北/ä¸œè¥¿çš„ç»¿ç¯æŒç»­ç§’æ•°: \nsingle way å•å‘é“è·¯ \nway1 reserved by é“è·¯1被å ç”¨: \nway2 reserved by é“è·¯2被å ç”¨: \nwith sign/signal\n 标志/ä¿¡å· %d buildings\n %d 建筑 %d convois %d è¿è¾“队 %d Einzelfahrzeuge im Depot %d 车辆存放在这 %i km/h (max. %ikm/h) %ikm/h(最高 %ikm/h) %i years %i months old. 树龄为 %i å¹´ %i 个月 %s at (%i,%i) now public stop. %s å·²æˆä¸ºå…¬å…±è¿è¾“中转站 %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s %s has entered a depot. %s 已回到车库 %s land %d %s %s %d %s 外 %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s 的居民达到 %i\n因此兴建了一个新市政厅 %s\nis crowded. %s 过度拥挤 %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\n时速 %i\n最高时速 %i\ndx:%i dy:%i %s\nwas liquidated. %s 已清盘 %u Client(s)\n %u 用户 %u Player (%u locked)\n %u 个玩家 (%u 个已é”定) <车辆未指定路线> 1 convoi 1 è¿è¾“队 1 Einzelfahrzeug im Depot 1辆车存放在这 1LIGHT_CHOOSE 亮度: 1WORLD_CHOOSE 新游æˆçš„设置: 2LIGHT_CHOOSE 颜色: 2WORLD_CHOOSE 地图编å·: 3LIGHT_CHOOSE é¼ æ ‡å·åŠ¨é€Ÿåº¦: 4LIGHT_CHOOSE 鼠標逆å‘å·åЍ 5LIGHT_CHOOSE 车站的行人 5WORLD_CHOOSE 城市总数: 6LIGHT_CHOOSE 镇上的行人 6WORLD_CHOOSE 交通密度: 8WORLD_CHOOSE æ—¥å¤œæ¨¡å¼ A bridge must start on a way! 这桥的两端åªèƒ½å»ºäºŽè‡ªå·±æ‹¥æœ‰çš„平地上且需在一æ¡çº¿ä¸Š Abfrage 视察工具 Abnehmer 消费者 About 关于 Abriss æ‘§æ¯/移除 Absenken é™ä½Žåœ°å½¢ Abspanntransformator å˜åŽ‹ç«™ Accelerate time 加快游æˆé€Ÿåº¦ Act. load: %u MW\n 实际负è·: %u MW Active player only 仅陿´»è·ƒçީ家 Add forest 扩大森林 Add random citycar éšæœºæ–°å¢žç§å®¶è½¦è¾† add server 新增æœåС噍 Add Stop 追加站 Add stops for backward travel 为回程路段增设车站 aircraft_tab 货机 airplane 飞机 Airport 机场 AIRTOOLS 航空工具 All 所有 all convoi tooltips 显示所有交通工具的æç¤º Allow city growth å…许城市增长 Allow player change å…许更æ¢çީ家 allowed climates:\n å…许气候:\n Alters a schedule. 从列车时间表增加/å‡å°‘车站 Angenommene Waren 附近工厂所需è¦çš„货物: anhaengen 添加 Anhaenger_tab 拖车 Anheben æé«˜åœ°å½¢ Appends stops at the end of the schedule 为时间表的åŽé¢å¢žæ·»è½¦ç«™ Apply Line 应用路线 April 4月 Arbeiter aus: 工人居ä½åœ¨: Arrivals from\n 出å‘地:\n Arrived 抵达 Assets 资产 Aufloesen 解散 Aufspanntransformator å˜åŽ‹ç«™ August 8月 Autohalt muss auf\nStrasse liegen!\n 巴士ã€è½¦è¾†åœé ç«™å¿…须建在é“路上 Available å¯ç”¨ Bahndepot ç«è½¦è½¦åº“ Bankrott:\n\nDu bist bankrott.\n 破产:\n\nä½ å·²ç»ç ´äº§, 游æˆç»“æŸ battery 电池 Baum æ ‘ baum builder æ ½ç§æ ‘木 Baustelle 建筑地 Bauzeit 建筑时间: Beenden ç»“æŸæ¸¸æˆ Beginner mode åˆå­¦è€…æ¨¡å¼ Besonderes Gebaeude 旅游景点 BF ç«™ bio 天然生物 Blockstrecke ist\nbelegt\n \n这段é“路正被其他列车使用。\n Boden 地 Bonusspeed: %i km/h 设计最高时速:%i km/h Boost (%%) 查看大图 bridge is too high for its type! 无法在这里建造\n因为离地é¢çš„高度超出了其桥脚的高度é™åˆ¶ Bridge is too long for this type!\n æ¡¥æ¢è·¨åº¦å¤ªå¤§\nè¯·é€‰æ‹©å…¶ä»–æ¡¥æ¢æˆ–分段建造 Bruecke æ¡¥ Bruecke muss an\neinfachem\nHang beginnen!\n 桥必须建在平直的斜å¡ä¸Š Brueckenboden æ¡¥ Build air depot 建造飞机舱 build choosesignals 建月å°é€‰æ‹©ä¿¡å· Build city market 在最近的城市建一个新市场。 Build drain 电力转化站 build HQ 建设总部 Build land consumer 建立一个新的å‘电厂 Build maglev depot å…´å»ºç£æµ®åˆ—车厂 Build monorail depot 建一个å•轨列车库 Build narrowgauge depot 兴建窄轨列车厂 Build powerline 建电线 Build presignals 建åŒé˜»ä¿¡å· Build road depot 建车库 Build ship depot 建船厂 Build signals å»ºä¿¡å· Build train depot 建ç«è½¦åº“ Build tram depot 建有轨电车库 Build truck depot 建货车库 Building costs estimates 建筑预算 Buildings å»ºç­‘ç‰©æ•°é‡ Built artifical slopes å»ºäººé€ æ–œå¡ Built random attraction éšå»ºä»»ä½•景点 Bus_tab 巴士 Can only move from halt to halt or waypoint to waypoint. åªå¯ä»¥ä»Ž \n一个站到å®ä¸€ä¸ªç«™æˆ– \n一个åœé¡¿ç‚¹åˆ°å®ä¸€ä¸ªåœé¡¿ç‚¹ç§»åŠ¨ã€‚ Cancel å–æ¶ˆ Capacity: %.0f MW è´Ÿè½½é‡ï¼š %.0f MW\n Capacity: %d%s %s\n è¿è½½é‡: %3d%s %s Capacity: %s\nLoad: %d (%d%%) 容é‡: %s\n? %d (%d%%) Cars are not available yet! è½¦è¾†ä»æœªåˆ¶é€ ã€‚ cars.\nstate 车辆\n Cash è´¦æˆ·ä½™é¢ Change player æ¢çީ家 Chart 图表 Chat_msg èŠå¤© Choose direction é€‰æ‹©æ–¹å‘ Choose operation executed on clicking stored/new vehicles 请为新交通工具/在库的交通工具,选择制定æ“作。 chooses a random map éšé€‰åœ°å›¾ã€‚ citicens å±…æ°‘ City attraction 城市景点 City industries 城市市场: City list 城市列表 City size åŸŽå¸‚å¤§å° city_road 城市é“è·¯ citybuilding builder 城市建筑工具 CityLimit 城市范围é™åˆ¶ cl_title 车辆列表 cl_txt_sort 排åº: Clear block reservation 显示/é‡ç½®å ç”¨è·¯æ®µ clf_chk_aircrafts 飞机 clf_chk_cars 巴士/å¡è½¦ clf_chk_indepot 在车库 clf_chk_maglev ç£æ‚¬æµ®åˆ—车 clf_chk_monorail å•轨é“è·¯ clf_chk_name_filter 筛选器åç§°: clf_chk_narrowgauge 窄轨é“è·¯ clf_chk_noincome æ— æ”¶å…¥ clf_chk_noline 无指定路线 clf_chk_noroute 无适当路线 clf_chk_noschedule 无行程表 clf_chk_ships 船 clf_chk_spezial_filter 特殊筛选器: clf_chk_stucked å›°ä½ clf_chk_trains 列车 clf_chk_trams 电车 clf_chk_type_filter ç¦æ˜¾ç¤ºç±»åˆ«: clf_chk_waren ç¦æ˜¾ç¤ºè´§ç‰©ç±»: clf_title äº¤é€šå·¥å…·åˆ—è¡¨ç¦æ˜¾ç¤ºå·¥å…· Climate Control 设置气候 closed æ æˆª COLOR_CHOOSE\n 请从以下选择一个颜色:\n Company bankrupt 你的公å¸å·²ç»ç ´äº§! Company_msg 竞争对手 Comparing pak files ... 正在比对游æˆèµ„料档案... Congratulation\nScenario was complete in\n%i months %i years. æ­å–œ!\nåŽ†ç» %i 月 %i å¹´, 此游æˆåœºæ™¯å·²å®Œæˆ! Connected stops 使用的站: Connected with server 已连接到伺æœå™¨ Constructed by 绘画者: Constructed by %s 绘画者:%s Construction_Btn 建设开支 convoi %d of %d 交通工具 %d / %d convoi error tooltips 显示交通工具的错误æç¤º Convoi has been sent\nto the nearest depot\nof appropriate type.\n 交通工具已ç»è¢«å¬å›žåˆ°æœ€è¿‘\nåŒç±»çš„库。\n\n Convoi is sold when all wagons are empty. 当交通工具完全空时,它将会被å–。 convoi mouseover tooltips 滑鼠指标下的交通工具显示æç¤º convoi passed last\nmonth %i\n \n上月交通æµé‡: %i\n Convois 交通工具 Convois: %d\nProfit: %s 车辆: %d\n利润: %s Convoys 交通工具 Copy Convoi å¤åˆ¶æ­¤äº¤é€šå·¥å…· Copy the selected convoi and its schedule or line å¤åˆ¶æ­¤äº¤é€šå·¥å…·çš„与路线/行程表 cost for removal 清除费 Costs æˆæœ¬ Create a new line based on this schedule 于这个行程表开设一个新的路线 curiosity builder 景点工具 curlist_title 景点列表 Currently playing: 进行中: deactivated in online mode ä¸é€‚ç”¨äºŽè¿žçº¿æ¸¸æˆ Deccelerate time 放慢时间 December 12月 decrease underground view level å°†åˆ‡é¢æŽ¨è½ä¸€å±‚ Del Stop 删除 Delete Line 删除路线 Delete the current stop 清除此站 Delete this file. 删除此文件 Demand: %.0f MW 需求: %.0f MW\n Denkmal å¤è¿¹ Departed å·²å‡ºå‘ Depots 车库 Der Tunnel ist nicht frei!\n éš§é“内仿œ‰è½¦è¾†åœ¨è¡Œé©¶ Destination 到达 Details 详情 Die Bruecke ist nicht frei!\n 桥上存在其他玩家的所有物 diesel 柴油 Direkt erreichbare Haltestellen 从这里开始的直达路线 disable midi å…³é—­èƒŒæ™¯éŸ³ä¹ Display settings 显示设置 Distance 行走è·ç¦» Dock ç å¤´ Dock must be built on single slope! ç å¤´åªèƒ½å»ºé€ åœ¨æ²¿æµ·å•颿–œå¡ä¸Š Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen ä»…ä½™ %d 个月还清债务 Durchsatz 最大 Economy ç»æµŽåŠåŸŽå¸‚ Eigenbesitz\n 公共财产 Ein %s\npasst hier nicht.\n 空间ä¸è¶³, 无法建造 %s Einstellungen aendern å˜æ›´é€‰é¡¹ electric 电 Electricity 电力 Electricity producer\n\n 电力供应商 Electrics_tab 电气化 Electrify track 电气化路轨 enlarge map 扩大地图 enter a value between %i and %i 请输入介乎于%i与%i之间的数值 Enter Password 更改玩家åç§°åŠå¯†ç  Error 错误 Erzeuge neue Karte.\n 新地图创建中, 请ç¨å€™\n(大地图耗时会ç¨ä¹…一些) Es wird bereits\nein Fahrplan\neingegeben\n 正在安排车辆计划表\nè¯·åœ¨é‡æ–°å®‰æŽ’å‰å…ˆå®Œæˆè®¾å®š Fabrikanschluss 相关厂商 Fabrikname 工厂åç§° Factories 工厂 factory details 工厂详情 factorybuilder 工厂工具 Fahrplan 车辆计划表 Fahrtziel 目的地 Fahrzeuge koennen so nicht entfernt werden éžæ³•移除è¿è¾“工具 Fahrzeuge: 车辆 Farbe 玩家颜色 Fast forward 快速进行 February 2月 Ferry_tab 渡轮 Fertig å·²å®Œæˆ Filename 文件å Filter: 筛选: Finances of %s %s 的资产 Finanzen 资产 find mismatch 比对游æˆèµ„料档 fl_title 工厂列表 Flug_tab 客机 follow me è·Ÿéš Follow the convoi on the map. 在地图上跟éšè¿è¾“队 Forest 森林 Found new city 开呿–°åŸŽå¸‚ Fracht 货物 Frame time: 帧时 Free Capacity ç©ºè½½é‡ freeplay mode è‡ªç”±æ¨¡å¼ Friction: 当剿‘©æ“¦ç³»æ•° fuel_cell 燃料箱 Full load 最å°è´Ÿè½½ Fundament 地基 Fussgaenger 行人 Game info ä¸å­˜åœ¨ GAME PAUSED 游æˆå·²æš‚åœ Game_msg 一般 Gear: 齿轮 Gebaeude 建筑 General 一般 Generation: %.0f MW å‘电é‡: %.0f MW\n Gewicht é‡é‡ Gewinn æ”¶å…¥ Give the selected vehicle(s) an individual schedule 给所选的车辆制定独立的车辆计划表 gl_btn_sort_catg 类别 gl_title 商å“列表 go home 回车库 Goods 货物 Goods AI 电脑玩家ï¼è´§è¿ Goods list è´§ç‰©æ¸…å• Gross Profit 资金æµåЍ Groundobj 目标 Grow city å‘展城市 Growth 城市å‘展 H 车站 Hangar 飞机库 Happy å¿«ä¹ Haus kaufen 购买房屋 Helligk. 显示 Help 帮助 Help text not found 帮助文档ä¸å­˜åœ¨ hide all building éšè—所有建筑 hide city building éšè—城市建筑 hide station names éšè—车站åç§° hide transparent 逿˜ŽåŒ–éšè—建筑 hide trees éšè—树木 Hier warten/lagern: å¾…è¿ä¹˜å®¢/货物 Higher transport fees, crossconnect all factories æé«˜è¿è¾“费用, å…³é—­åŠæ—¶åˆ¶åº¦ hl_title 车站列表 hl_txt_filter 分类: hl_txt_sort æŽ’åºæ–¹æ³•: hlf_chk_airport 机场 hlf_chk_anleger ç å¤´ hlf_chk_bahnhof é“路车站 hlf_chk_bushalt 公共汽车站 hlf_chk_frachthof zai hlf_chk_keine_verb 未连接 hlf_chk_maglevstop ç£æ‚¬æµ®åˆ—车站 hlf_chk_monorailstop å•轨é“路车站 hlf_chk_name_filter å称: hlf_chk_narrowgaugestop 窄轨é“路车站 hlf_chk_overflow è¶…è½½ hlf_chk_spezial_filter 特殊: hlf_chk_tramstop 有轨电车åœé ç‚¹ hlf_chk_type_filter 类别: hlf_chk_waren_abgabe 生产: hlf_chk_waren_annahme 物资 hlf_title 车站列表筛选 Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. 找ä¸åˆ°è½¦åº“\n请手动设置车辆行程表令其回到车库 Homeless æµæµªè€… hydrogene 氢气 Idle: 空闲 ignore climates 忽略气候é™åˆ¶ Increase Industry density 增加工业 increase underground view level å°†åˆ‡é¢æŽ¨ä¸Šä¸€å±‚ industrial building 工业建筑 Init map ... åˆå§‹åŒ–地图中... Input 原料 Ins Stop æ’入站 Insert stop before the current stop 在此车站å‰å¢žåŠ è½¦ç«™ Intercity road len: 城际é“路长度 Intro. date: 开呿—¥æœŸ invalid 未定义 Invalid coordinate 指令无效 isometric map ç­‰è·è§†å›¾ January 1月 join game è¿žçº¿æ¸¸æˆ July 7月 Jump to 跳至 June 6月 Kann Spielstand\nnicht laden.\n æ— æ³•è½½å…¥å­˜å‚¨çš„æ¸¸æˆ Kann Spielstand\nnicht speichern.\n 无法打开目标文件 Kein Besitzer\n 无物主 keine 没有 Keine Einzelfahrzeuge im Depot 无车辆åœç•™åœ¨æ­¤ Keyboard_Help\n å¿«æ·é”®å¸®åŠ© koord 座标 Kreuzung åå­—è·¯å£ labellist_title 玩家标记列表 Lade Relief 载入高度图 Laden 载入 Land attraction 郊外景点 Land industries 工业链 LANG_CHOOSE\n 请选择界é¢è¯­è¨€ LARGE_NUMBER_STRING 亿 LARGE_NUMBER_VALUE 百万 Last Year 上年度 Leaving depot! 正离开车库 leer 空的 Legend 图例 Leistung 功率 Leistung: %d kW 功率: %d kW Leitung 电线 letzen Monat: diesen Monat: 上月 本月 Line 路线 Line Management è·¯çº¿ç®¡ç† Lineless convoys serving this stop é€”ç»æœ¬ç«™çš„车辆 Lines serving this stop é€”ç»æœ¬ç«™çš„路线 LKW_tab 货车 Load game è½½å…¥æ¸¸æˆ load height data from file 从文档载入高度图 Load scenario 载入场景 loaded 承载 loaded passenger/freight 排列乘客/è´§è¿,按 Loading (%i->%i%%)! 载入中 (%i->%i%%) Loading addon paks ... 正在载入附加的游æˆèµ„料档... Loading map ... 载入地图中... Loading paks ... 正在载入游æˆèµ„料档... Loading skins ... 正在载入样å¼... Lock game ç¦æ­¢åˆ‡æ¢çީ家 (需确认) Lokomotive_tab 机车 m3 立方米 Maglev ç£æµ®é“è·¯ maglev vehicle ç£æµ®é“路车辆 maglev_track ç£æµ®è·¯è½¨ Maglevdepot ç£æµ®åˆ—车厂 Mailbox 消æ¯ä¸­å¿ƒ Mailbox Options 消æ¯ä¸­å¿ƒé€‰é¡¹ Maintenance ç»´ä¿® make stop public (or join with public stop next) costs %i per tile and level 公有化车站(或与邻接的公共车站åˆå¹¶ï¼‰æ¯æ ¼æ¯ç­‰çº§çš„æˆæœ¬ä¸º$%i Manual (Human) 人类玩家 Manufactured: 制造商 Map roughness 地图粗糙度 map zoom 缩放 March 3月 Margin (%%) 利润 Marker 设定标记 max 最高 Max income: 最高收入 Max. speed: 最高速度 Maximum 254 stops\nin a schedule!\n 一个车辆计划表最多能容纳254个途径点 maximum length of rivers æ²³æµæœ€é•¿é•¿åº¦ Maximum tile height difference reached. 两个地形之间的高度差已达到最大 May 5月 Median Citizen per town 城市平å‡äººå£ Meldung æ¶ˆæ¯ Menge æ€»é¢ MessageOptionsText \n新年度\n\n玩家消æ¯\n\n城市消æ¯\n\n沒有路线\n\n新目标\n\nèŠå¤©\n\n新车辆\n\n车站爆满\n\n问题\n\n交通拥挤 min 最低 minimum length of rivers æ²³æµæœ€çŸ­é•¿åº¦ Modify the selected line 修改所选路线 Monate alt 个月 Monorail å•轨é“è·¯ monorail vehicle å•轨列车 monorail_track å•轨路轨 Monorailboden 高架é“è·¯ Monoraildepot å•轨列车车厂 month wait time 最大等候时间(月) Months 月份 Monument 纪念碑 Monuments 纪念碑 Mountain height 山高: Movingobj 移动物体 Music playing disabled/not available 背景音ä¹ä¸å¯ç”¨ã€‚ Music volume: 背景音ä¹éŸ³é‡: mute sound é™éŸ³ Name åç§° Narrowgauge 窄轨 Narrowgauge are not available yet! 窄轨é“路还ä¸å¯ç”¨ narrowgauge vehicle 窄轨é“路车辆 narrowgauge_track 窄轨é“è·¯ Narrowgaugedepot 窄轨é“路车库 Net ID: %p 电网编å·ï¼š %p\n Net Wealth 净资产 Neue Karte 新地图 Neue Welt æ–°å»ºæ¸¸æˆ new convoi 新车队 New Line 新路线 New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. 已开设新路线ï¼\n请在路线列表中选择该路线,\n并修改其资料 New Vehicles 新交通工具 no buildings hidden æ— éšè—建筑物 no convois æ— è¿è¾“工具 No goods are loaded onto this convoi. è¿è¾“队无载货 no goods waiting 无积压货物 no load å–æ¶ˆè£…è½½ No Route 无路线 No stop here! 该工具需è¦ä½¿ç”¨åœ¨ä¸€ä¸ªåœé ç‚¹ä¸Šã€‚ No suitable ground! 地形ä¸åˆé€‚ï¼ No terminal station here! 无法在此建设总站ï¼è¯·å»ºè½¦å»º\n设地点是å¦åœ¨å¯¹åº”路线的末端。 no timeline ä¸ä½¿ç”¨æ—¶é—´è½´ no tree 没有树林 Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "我该去哪里?"\n在派出车辆å‰ï¼Œå¿…须先给其制定行程表或者安排到已有的行程表 none æ—  nord 北 nordost 东北 nordwest 西北 Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! 路线寻找期间,无法修改车辆计划表 Not enough fields would remain. 此处场地预留空间ä¸è¶³ã€‚ November 11月 Now active as %s.\n 当å‰çŽ©å®¶æ˜¯%s\n Number of rivers æ²³æµæ•°é‡ Object 物体 Odometer: %s km %s åƒç±³ Ok 确认 Oktober 10月 On loan since %i month(s) 负债状况已ç»ç»´æŒäº†%i个月 On this map, you are not\nallowed to change player!\n 游æˆå·²é”定, 无法切æ¢çީ家\n Only city chains åªæ˜¾ç¤ºåŸŽå¸‚的工业链 Only first %d differing paks reported. There are probably more. åªæ˜¾ç¤ºé¦–%d个ä¸ç›¸åŒçš„æ¸¸æˆèµ„料档。å¯èƒ½ä¼šæœ‰æ›´å¤šã€‚ Only land chains åªæ˜¾ç¤ºéƒŠå¤–的工业链 Only one transformer per factory! 一间工厂åªèƒ½è®¾ç½®ä¸€ä¸ªå˜åދ噍 open 通行 Operation è¿è¥è´¹ç”¨ Ops Profit è¿è¥åˆ©æ¶¦ Optionen 选项 Origin 出å‘地 ost 东 Output 输出 Pak(s) different: ä¸ç›¸åŒçš„æ¸¸æˆèµ„料档: Pak(s) missing on client: 用户端所欠缺的游æˆèµ„料档: Pak(s) not on server: 伺æœå™¨ä¸Šæ‰€æ²¡æœ‰çš„æ¸¸æˆèµ„料档: Pakset differences 游æˆèµ„料集之间的差别 paletten 装货箱 Pas_tab 客è¿ç«è½¦ Passagiere 乘客 Passagierrate ä¹˜å®¢é‡ Passagierziele 乘客/邮件目的地 Passenger AI 电脑玩家ï¼å®¢è¿ Passengers %d %c, %d %c, %d no route 乘客 %d %c, %d %c, %d 无路线 Passengers %d %s, %d %s, %d no route 乘客 %d %s, %d %s, %d 无路线 Password å¯†ç  Pause æš‚åœ PaxDest 目的地 Percent Electricity 供电率(%%需求) Planes are not available yet! 飞机还ä¸å¯ç”¨ Plant tree ç§æ¤æ ‘木 player 玩家 player -1 人 player 0 公共æœåŠ¡ player 1 Napik 128 AS player 10 玩家10 player 11 玩家11 player 12 玩家12 player 13 玩家13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 è´§è¿ä»£ç†äºº VM player 5 H-Transå…¬å¸ player 6 PSK & Co KG player 7 玩家7 player 8 玩家8 player 9 玩家9 Please choose vehicles first\n 请先选择车辆 Post 邮件 Postrate é‚®ä»¶é‡ Power 电力 Power: 功率 Powerlines 电缆 Problems_msg 问题 Production of %s has been stopped:\n%s\n %s å·²åœäº§\n%s Produktion 生产 Profit 利润 promote to line 改进路线 q1 春季 q2 å¤å­£ q3 ç§‹å­£ q4 冬季 rail car ç«è½¦ random éšæœº Random age éšæœºæ ‘龄 Random map éšæœºåœ°å›¾ Rathaus 市政府 Rating 评价 ratio_pax 乘客è¿è½½çއ(%%) Reliefkarte 地图 Remove 移除标签 remove airstrips 拆除飞机跑é“å’Œæ»‘è¡Œé“ remove channels ç§»é™¤è¿æ²³ remove interm. signals æ‹†é™¤ä¸­é—´çš„ä¿¡å· remove maglev tracks æ‹†é™¤ç£æµ®è·¯è½¨ remove monorails 拆除å•轨é“è·¯ remove narrowgauge tracks 拆除窄轨é“è·¯ remove powerlines 拆除电缆 remove roads 拆除é“è·¯ remove tracks 拆除路轨 Remove wayobj %s 拆除é“è·¯ %s replace other signals ç½®æ¢å…¶ä»–标志 replace stop æ›´æ¢è½¦ç«™ request closing è¯·æ±‚æ‹’ç» residential house 居民房 Restore natural slope 还原原æ¥çš„æ–œå¡ Restwert: 转售价格 Retire. date: 退休日期 return ticket å¤åˆ¶æ­¤å›žç¨‹ Revenue æ”¶å…¥ Revision: 修正 road é“è·¯ road vehicle é“路车辆 Roadsign é“路标记 Rotate map 旋转地图 Rotation 旋转 Routing 寻找路线中 sack 袋 sail 风 Saving map ... 地图存储中... Scenario complete: %i%% 场景已完æˆ: %i%% Scenario Debug 调试 Scenario Error Log è„šæœ¬é”™è¯¯ï¼ Scenario information 当å‰åœºæ™¯è¯¦æƒ… Scenario Result 进度 Scenario Rules 规则 Schedule changing! æ­£åœ¨æ›´æ–°è·¯çº¿è¡¨ï¼ Schienentunnel 建造é“è·¯éš§é“ Schiff_tab 船 Schiffdepot 造船厂 Schleppkahn_tab 驳船 Screenshot 截图 Seasons 季节 Sehenswuerdigkeit 旅游胜地 Sell the selected vehicle(s) å–出所选车辆 sended 邮件已å‘é€ SEP_FRACTION . SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September 9月 Server did not respond! æœåŠ¡å™¨æ— å›žåº” Serves Line: æœåŠ¡è·¯çº¿ Service æœåŠ¡ set signal spacing 设定信å·é—´è· Setting 设置 Ship 船 shops and stores 商店和办公楼 Show all 全部显示 show all building 显示所有建筑 Show also vehicles no longer in production. åŒæ—¶æ˜¾ç¤ºä¸å†ç”Ÿäº§çš„车辆 Show also vehicles that do not match for current action. åŒæ—¶æ˜¾ç¤ºä¸ç¬¦åˆæ‰€é€‰æŒ‡ä»¤çš„车辆 Show even servers with wrong version or pakset åŒæ—¶æ˜¾ç¤ºä½¿ç”¨é”™è¯¯æ¸¸æˆç‰ˆæœ¬æˆ–资料集的æœåС噍 show grid 显示网格 Show industry 显示工业 Show legend 显示图例 Show map scale 显示地图比例 Show obsolete 显示已淘汰的 Show schedules 显示路线表 show station coverage 显示车站æœåŠ¡èŒƒå›´ show station names 显示车站åç§° show waiting bars 显示等候图表 Show/hide statistics 显示/éšè—æ•°æ®ç»Ÿè®¡ Shows consumer/suppliers for factories 显示工厂的客户和供应商 Shows the currently selected schedule æ˜¾ç¤ºå½“å‰æ‰€é€‰çš„路线表 Shrink city 缩å°åŸŽå¸‚ shuffle midis éšæœºéŸ³ä¹ Signal ä¿¡å· signal spacing ä¿¡å·é—´è· Sim: 模拟周期 Size (%d MB): å¤§å° (%d MB): sliced underground mode 切é¢åœ°å›¾æ¨¡å¼ slot empty 空槽 Sort by 排列按 Sort waiting list by 排列等候列表,按 Sound 音效 Sound settings 音效设置 Sound volume: éŸ³æ•ˆéŸ³é‡ special freight 特殊货物 Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. 速度加æˆ\né“è·¯ %i km/h é“è·¯ %i km/h\nèˆ¹è¿ %i km/h ç©ºè¿ %i km/h Speedlimit 速度é™åˆ¶ Speichern ä¿å­˜ Spieler 玩家 Spieler(mz) 玩家 Spielerliste 玩家列表 Spielstand wurde\ngeladen!\n 游æˆè½½å…¥æˆåŠŸ Spielstand wurde\ngespeichert!\n 游æˆå­˜å‚¨æˆåŠŸ Sprache 语言 Sprachen 语言 Stadtinformation åŸŽå¸‚ç»Ÿè®¡æ•°æ® Start 开始 Start the selected vehicle(s) æ´¾é£æ‰€é€‰è½¦è¾† Starte Spiel å¼€å§‹æ¸¸æˆ Station tiles: ç«™å°é•¿åº¦ Station_msg 车站 Status è½¦ç«™çŠ¶æ€ steam 蒸汽 Step timeline one year 跳至下一年 Stops 车站 Storage capacity å®¹é‡ Strassendepot 车库 Strassentunnel 建造é“è·¯éš§é“ street car 電車 sued å— suedost ä¸œå— suedwest è¥¿å— Summer snowline å¤å­£é›ªçº¿ Supplied: %.0f %% 已供应:%.0f %% Suppliers 供应商 Tage alt 天 There are still vehicles\nstored in this depot!\n 车库内还有车辆 This Month 本月 This Year 本年度 Tile not empty. 在使用斜å¡å·¥å…·å‰, 请先清除地é¢ç‰©ä»¶ timeline éµä»Žæ—¶ä»£ tl_title 城市列表 To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %s 为了å¸å¼•更多的旅客\n兴建了 %s\n(在 %i 纳税人的支æŒä¸‹) To heavy traffic\nresults in traffic jam.\n 交通过于ç¹å¿™å¯¼è‡´äº¤é€šé˜»å¡ž Toggle day/night view åˆ‡æ¢æ—¥/夜视图 Toggle vehicle tooltips 切æ¢è½¦è¾†å·¥å…·æç¤º tonnen å¨ Total inhabitants: 居民总数 Tourist attractions 旅游景点 Tourists 景点 Town_msg 新目的地 Town: %s\n %s 市 Towns 城市 track 路轨 Tracks 路轨 Traffic 交通 Train ç«è½¦ Trains are not available yet! ç«è½¦è¿˜ä¸å¯ç”¨ Tram 电车 tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. 电车 %i km/h, å•轨列车 %i km/h\nç£æ‚¬æµ®åˆ—车 %i km/h, 窄軌列车 %i km/h tram_track 电车路轨 Tramdepot 电车车库 Trams are not available yet! 电车还ä¸å¯ç”¨ Transferring game ... æ­£åœ¨ä¼ é€æ¸¸æˆ... Transformer only next to factory! å˜åŽ‹ç«™å¿…é¡»å»ºé€ åœ¨ä¸Žå·¥åŽ‚æ¯—è¿žçš„å¹³å¦ç©ºåœ°ä¸Š Translation 翻译 transparent station coverage 逿˜Žæ˜¾ç¤ºè½¦ç«™è¦†ç›–范围 Transported 路程 TrolleyBus_tab 无轨电车 Truck 货车 Tunnel muss an\neinfachem\nHang beginnen!\n éš§é“å…¥å£å¿…须建造在斜å¡ä¸Š Tunnel must start on single way! éš§é“å…¥å£å¿…须连接é“路或é“è·¯ Tunnelboden éš§é“ underground mode 地下视图 UNDO failed! 无法撤销上次æ“作\n仅当æŸè·¯æ®µä¸Šæ²¡æœ‰ä¿¡å·æ ‡å¿—ã€è½¦ç«™æˆ–其他建筑物时, æ‰èƒ½ä½¿ç”¨æ’¤é”€é“路建设æ“作 Undo last ways construction å–æ¶ˆä¸Šæ¬¡é“路建设 Unemployed 失业 Unhappy ä¸é«˜å…´ units/day ä»¶/月 Update Line 更新路线 upgrade HQ å‡çº§æ€»éƒ¨ Usage: %.0f %% 使用率: %.0f %% Use beginner mode ä¸å­˜åœ¨ Use timeline start year 使用时间轴: 从 Vehicle %s can't find a route! 车辆 %s 无法找到路綫 Vehicle %s is stucked! 车辆 %s 被å¡ä½äº† Vehicle details 车辆详情 Verbrauch æ¶ˆè€—é‡ Vergroessere die Karte\n 扩大地图 verkaufen è´©å”®æ¨¡å¼ Verkehrsteilnehmer 城市车辆 Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n ä»…ä½™ %d 个月还清债务 via 通过(细节) via %s\n 通过 %s via Menge 通过(æ•°é‡) voranstellen å‰ç½® Waggon_tab 车辆 waiting 等待中 Waiting for clearance! 等待清ç†ä¸­ Warnings_msg 交通状况 Wasser æ°´ Water è¿æ²³ Water level æ°´å¹³é¢ water vehicle èˆ¹åª way %s cannot longer used:\n 无法å†å»ºé€  %s è·¯ way %s cannot longer used:\n%s\n 无法å†å»ºé€  %s è·¯ way %s now available:\n %s 路现在å¯ç”¨ Ways not connected é“路未连接 Wegpunkt 途径点 Wert ä»·æ ¼ west 西 Winter snowline 冬季雪线 withdraw 撤销 Withdraw All 全部撤销 WRONGSAVE 档案å¯èƒ½å·²æŸå, æ— æ³•è½½å…¥æ¸¸æˆ Year %i has started. %i 年已开始 Years å¹´ Zielort 目的地 zooming in 放大 zooming out ç¼©å° Zu nah am Kartenrand 过于é è¿‘地图边缘, 无法建造 #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. %2$s åˆ›é€ äº†æ–°ç£æ‚¬æµ®åˆ—车世界纪录: %1$.1f km/h New world record for monorails: %.1f km/h by %s. %2$s 创造了新å•轨世界纪录: %1$.1f km/h New world record for motorcars: %.1f km/h by %s. %2$s 创造了新车辆世界纪录: %1$.1f km/h New world record for narrowgauges: %.1f km/h by %s. %2$s 创造了新窄轨世界纪录: %1$.1f km/h New world record for planes: %.1f km/h by %s. %2$s 创造了新航空世界纪录: %1$.1f km/h New world record for railways: %.1f km/h by %s. %2$s 创造了新é“路世界纪录: %1$.1f km/h New world record for ship: %.1f km/h by %s. %2$s åˆ›é€ äº†èˆ¹è¿æ–°ä¸–界纪录:\n%1$.1f km/h #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL 油绳 &1_CITY_SYLL 切斯特 &2_CITY_SYLL å¨ &3_CITY_SYLL 市 &4_CITY_SYLL 集èšåœ° &5_CITY_SYLL 行政区 &6_CITY_SYLL ç«è…¿ &7_CITY_SYLL 域 &8_CITY_SYLL å£ &9_CITY_SYLL é” &A_CITY_SYLL 穿过 &B_CITY_SYLL ç”± &C_CITY_SYLL åŸ‹è— &D_CITY_SYLL 用处 &E_CITY_SYLL 井 %0_CITY_SYLL æ¾æ ‘ %1_CITY_SYLL è‰¾åª %2_CITY_SYLL 马利 %3_CITY_SYLL ç° %4_CITY_SYLL 泉 %5_CITY_SYLL 大选 %6_CITY_SYLL å·´çµ %7_CITY_SYLL 赫普 %8_CITY_SYLL 布伦特 %9_CITY_SYLL 仿© %A_CITY_SYLL æ—§ %B_CITY_SYLL 山丘 %C_CITY_SYLL æ–° %D_CITY_SYLL 岩山 %E_CITY_SYLL 沃尔 %F_CITY_SYLL æ©¡æ ‘ 0center ä¸å­˜åœ¨! 0extern ä¸å­˜åœ¨! 0suburb ä¸å­˜åœ¨ 1center %s %s 1extern %s 分支 %s 1suburb %s %s %s 2center %s 中心 %s 2extern %s 外 %s 2suburb %s è‰åœ° %s %s 3center %s 主 %s 3extern %s 土地 %s 3suburb %s æ‘庄 %s %s 4center %s 里 %s 4extern %s 外围 %s 4suburb %s å†œæ‘ %s 5center %s 市中心 %s 5extern %s è½¬æ¢ %s 5suburb %s 镇 %s 6center %s 中心 %s 6extern %s äº¤æ¢ %s 6suburb %s 郊外 %s %s 7center %s 城市 %s 7extern %s 平原 %s 7suburb %s 公园 %s 8center %s 商业 %s 8extern %s %s è¾¹ %s 8suburb %s 嫿˜Ÿ %s 9center %s è½´ %s 9extern %s æ—é“ %s 9suburb %s 中部 %s Acenter ä¸å­˜åœ¨ Aextern ä¸å­˜åœ¨ Asuburb ä¸å­˜åœ¨ Bcenter ä¸å­˜åœ¨ Bextern ä¸å­˜åœ¨ Bsuburb æ—¥å…‰æµ´åœºæ‘ Ccenter ä¸å­˜åœ¨ Cextern ä¸å­˜åœ¨ Csuburb ä¸å­˜åœ¨! Dcenter ä¸å­˜åœ¨ Dextern ä¸å­˜åœ¨ Dsuburb ä¸å­˜åœ¨ Ecenter ä¸å­˜åœ¨ Eextern ä¸å­˜åœ¨ Esuburb ä¸å­˜åœ¨ Fcenter ä¸å­˜åœ¨ Fextern ä¸å­˜åœ¨ Fsuburb ä¸å­˜åœ¨ Gcenter ä¸å­˜åœ¨ Gextern ä¸å­˜åœ¨ Gsuburb ä¸å­˜åœ¨ Hcenter ä¸å­˜åœ¨ Hextern ä¸å­˜åœ¨ Hsuburb ä¸å­˜åœ¨ Icenter ä¸å­˜åœ¨ Iextern ä¸å­˜åœ¨ Isuburb ä¸å­˜åœ¨ Jcenter ä¸å­˜åœ¨ Jextern ä¸å­˜åœ¨ Jsuburb ä¸å­˜åœ¨ Kcenter ä¸å­˜åœ¨ Kextern ä¸å­˜åœ¨ Ksuburb ä¸å­˜åœ¨ Lcenter ä¸å­˜åœ¨ Lextern ä¸å­˜åœ¨ Lsuburb ä¸å­˜åœ¨ Mcenter ä¸å­˜åœ¨ Mextern ä¸å­˜åœ¨ Msuburb ä¸å­˜åœ¨ Ncenter ä¸å­˜åœ¨ Nextern ä¸å­˜åœ¨ Nsuburb ä¸å­˜åœ¨ Ocenter ä¸å­˜åœ¨ Oextern ä¸å­˜åœ¨ Osuburb ä¸å­˜åœ¨ Pcenter ä¸å­˜åœ¨ Pextern ä¸å­˜åœ¨ Psuburb ä¸å­˜åœ¨ Qcenter ä¸å­˜åœ¨ Qextern ä¸å­˜åœ¨ Qsuburb ä¸å­˜åœ¨ Rcenter ä¸å­˜åœ¨ Rextern ä¸å­˜åœ¨ Rsuburb ä¸å­˜åœ¨ Scenter ä¸å­˜åœ¨ Sextern ä¸å­˜åœ¨ Ssuburb ä¸å­˜åœ¨ Tcenter ä¸å­˜åœ¨ Textern ä¸å­˜åœ¨ Tsuburb ä¸å­˜åœ¨ Ucenter ä¸å­˜åœ¨ Uextern ä¸å­˜åœ¨ Usuburb ä¸å­˜åœ¨ Vcenter ä¸å­˜åœ¨ Vextern ä¸å­˜åœ¨ Vsuburb ä¸å­˜åœ¨ Wcenter ä¸å­˜åœ¨ Wextern ä¸å­˜åœ¨ Wsuburb ä¸å­˜åœ¨ Xcenter ä¸å­˜åœ¨! Xextern ä¸å­˜åœ¨! Xsuburb ä¸å­˜åœ¨! Ycenter ä¸å­˜åœ¨! Yextern ä¸å­˜åœ¨! Ysuburb ä¸å­˜åœ¨! Zcenter ä¸å­˜åœ¨! Zextern ä¸å­˜åœ¨! Zsuburb ä¸å­˜åœ¨! simutrans-124.3/simutrans/text/cn/000077500000000000000000000000001474050137200171645ustar00rootroot00000000000000simutrans-124.3/simutrans/text/cn/baum_build.txt000066400000000000000000000015701474050137200220330ustar00rootroot00000000000000

æ¤æ ‘

此问题å¯åˆ†ä¸º4å„部分

·左上角是å¯ä¾›é€‰æ‹©çš„æ ‘的类型的列表

·左下角是显示被选择的树的图片

·å³ä¸Šè§’是一些å¯ä»¥è¢«è®¾ç½®çš„选项

·å³ä¸‹è§’是显示被选择的树的相关信æ¯

选择列表

选择列表æä¾›äº†æ‰€æœ‰æ ‘的类型,通过å³ä¸Šè§’的选项å¯ä»¥èŽ·å¾—ã€‚æœ‰ä¸¤ä¸ªæ ‡ç­¾å¯ä»¥è¢«ç”¨æ¥æ”¹å˜æ ‘的类型是如何被区别的。

· 翻译: 使用当å‰è¯­è¨€æ˜¾ç¤ºæ ‘çš„å称,如果没有被翻译æˆå½“å‰è¯­è¨€ï¼Œå¯¹è±¡çš„å称将被使用

· 对象: 树的类型用模拟交通内部对象的åå­—

选项

· 忽视天气: 此选项使得天气对ä¸åŒæ ‘的类型的é™åˆ¶è¢«è§£é™¤

· éšæœºå¹´ä»½: å°†è¦è¢«ç§æ¤çš„æ ‘çš„å¹´é¾„æ˜¯éšæœºçš„

simutrans-124.3/simutrans/text/cn/color.txt000066400000000000000000000013401474050137200210410ustar00rootroot00000000000000

玩家颜色

玩家颜色 设置公å¸çš„颜色

交通工具,建筑物和其他项目显示公å¸çš„颜色

玩家颜色 使用游æˆé€‰é¡¹æ‰“å¼€

ç‚¹å‡»é¢œè‰²æ¡æ¥ä¿®æ”¹å…¬å¸çš„颜色

玩家颜色的åç§°æ¡çš„æ”¹å˜ï¼ˆæ–°çš„å…¬å¸çš„åç§°æ¡çš„颜色ä¸ä¼šæ”¹å˜ï¼‰æ„å‘³ç€æ–°çš„颜色被选出

默认的人类玩家的颜色是淡è“色

一些项目没有为颜色编ç &这些项目ä¸éœ€è¦é€‰æ‹©é¢œè‰²

(æç¤ºï¼šä½¿ç”¨çŽ©å®¶åˆ—è¡¨æˆ–è€…P+ Change Player改å˜ç”µè„‘玩家的颜色之å‰å…ˆé€‰æ‹©ç”µè„‘玩家 )。

simutrans-124.3/simutrans/text/cn/enlarge_map.txt000066400000000000000000000004261474050137200222010ustar00rootroot00000000000000地图扩展帮助

扩展地图

å¯ä»¥å‘å³å’Œå‘下扩展地图. 如果想è¦å‘左或å‘上扩展地图, 必须先将地图旋转, 冿‰©å±•, 最åŽå†æ—‹è½¬å›žåŽ».
åœ°å›¾æ‰©å±•é¢„è§ˆåœ¨å¯¹è¯æ¡†çª—å£çš„å³ä¸Šæ˜¾ç¤º.

simutrans-124.3/simutrans/text/cn/labellist_filter.txt000066400000000000000000000003231474050137200232430ustar00rootroot00000000000000标记列表帮助

玩家标记列表

这里列出了地图上所有的标记.
仅显示活跃玩家选项 åªæ˜¾ç¤ºæ´»è·ƒçŽ©å®¶è®¾ç½®çš„æ ‡è®°.

simutrans-124.3/simutrans/text/cn/save.txt000066400000000000000000000034721474050137200206710ustar00rootroot00000000000000<strong>存档</strong>

å­˜æ¡£ï¼šæŠŠå½“å‰æ¸¸æˆè®°å½•到文件中(为了å¯ä»¥åœ¨ä»¥åŽç»§ç»­è¿›è¡Œæ¸¸æˆï¼‰& 这些文件å¯ä»¥è¢«åˆ é™¤ã€‚

存档打开游æˆé€‰é¡¹æˆ–者按[S]é”®;& 列出游æˆçš„å称,日期&之剿¸¸æˆçš„æ—¶é—´ã€‚

如果所有的游æˆéƒ½çœ‹ä¸è§ï¼›ä½¿ç”¨å³è¾¹çš„æ»šåЍæ¡å°†å字滚出。

当剿¸¸æˆå¯ä»¥è¢«å‚¨å­˜æ‰“一个新的文件或者覆盖一个已ç»å­˜åœ¨çš„æ¸¸æˆæ–‡ä»¶ã€‚

为了储存游æˆåˆ°ä¸€ä¸ªæ–°çš„æ–‡ä»¶ï¼Œè¯·åœ¨å­˜æ¡£é”®ä¸Šæ–¹çš„ç›’å­é‡Œå¡«å†™ä¿å­˜æ–‡ä»¶çš„å称,输入åç§°&按回车键或者返回键或者点击OKï¼› 新的文件å称被列出æ¥ã€‚

注æ„:如果列出的文件å称是使用过的:以å‰çš„æ–‡ä»¶å†…容被当å‰çš„æ¸¸æˆæ–‡ä»¶å†…容替代,&以å‰çš„内容丢失。

é»˜è®¤å½“å‰æ¸¸æˆå‡ºçŽ°åœ¨æ–‡ä»¶åç§°ç›’å­é‡Œï¼Œç‚¹å‡»OK ä¿å­˜è¿™ä¸ªæ–‡ä»¶ï¼ˆä»¥å‰çš„æ•°æ®è¢«å½“剿•°æ®æ›¿ä»£è¢«ä¸¢å¤±ï¼‰

为了将以å‰çš„æ¸¸æˆæœ‰å½“å‰çš„æ¸¸æˆæ–‡ä»¶è¦†ç›–,点击文件列表中的文件å(以å‰çš„æ¸¸æˆå°†è¦è¢«å½“å‰çš„æ¸¸æˆæ–‡ä»¶æ›¿ä»£ï¼‰

文件åå¯ä»¥æ˜¯ä¸€ä¸ªç”±å­—æ¯ï¼Œæ•°å­—,符å·ç»„æˆçš„æœ€å¤§ä¸è¶…过57个字符。ä¿å­˜åŽï¼ˆæœ€å¤š)åªæœ‰20个字符å¯ä»¥è¢«çŽ°å®žåœ¨ä¿å­˜æ–‡ä»¶&装载文件中。

警告:通过文件å点击X键游æˆå°†è¢«ç«‹å³æœ‰å°±åˆ é™¤ï¼Œæ–‡ä»¶å将被移除列表。使用此功能è¦å°å¿ƒã€‚

{æç¤ºï¼šä»Žè½½å…¥æ¸¸æˆä¸­é‡æ–°å¼€å§‹ä¸€ä¸ªå·²ç»è¢«ä¿å­˜è¿‡çš„æ¸¸æˆï¼Œ

改å˜è‡ªåЍä¿å­˜{自动游æˆä¿å­˜}到simuconf.tab文件中}。

ç‚¹å‡»å–æ¶ˆé”®ç”¨æ¥å…³é—­å­˜æ¡£é”®ï¼›æˆ–者点击左上角的X;或者使用键盘关闭。

simutrans-124.3/simutrans/text/cn/scenario.txt000066400000000000000000000003221474050137200215250ustar00rootroot00000000000000剧本帮助

剧本

Simutrans支æŒå‰§æœ¬æ¨¡å¼. 在剧本中, 必须完æˆä¸€å®šçš„目标: 连接æŸä¸ªå·¥åŽ‚, 迅速å˜å¯Œ, æˆ–å»ºé€ ä¸€ä¸ªä¸æœ½çš„æ€»éƒ¨.

simutrans-124.3/simutrans/text/cn/settings.txt000066400000000000000000000010511474050137200215620ustar00rootroot00000000000000扩展设置帮助

扩展设置

扩展设置å…许改å˜åœ¨æ¸¸æˆå¼•擎中æ¯ä¸€ä¸ªå‚æ•°(几乎), 如åŒä¿®æ”¹ä¸­å¿ƒé…置文件simuconf.tab. å› æ­¤æ‰€æœ‰å‚æ•°çš„命å与他们在simuconf.tabä¸­ç›¸åº”å‚æ•°çš„命å相åŒ.

如果你修改æŸä¸ªæ­£åœ¨è¿›è¡Œçš„æ¸¸æˆ, 你需è¦é‡æ–°è½½å…¥æ¸¸æˆä»¥ä¾¿åº”用设置. æŸäº›è®¾ç½®(比如工厂连接)åªä¼šå½±å“新创建的项目.

注æ„:
ä¸é€‚å½“çš„å‚æ•°è®¾ç½®æžæ˜“æŸå游æˆ!

simutrans-124.3/simutrans/text/cn/simutrans.txt000066400000000000000000000053401474050137200217540ustar00rootroot00000000000000åºè¯—

欢迎使用 Simutrans。。。

Simutrans 有好几åƒä¸ªæ¸¸æˆåœ°å›¾ã€‚您å¯ä»¥ä»»é€‰ä¸€ä¸ªï¼Œæˆ–自己创造一个(从高度图建起)。接ç€ï¼Œæ‚¨ä»¥ä¸€ä¸ªå¹´è½»ä¼ä¸šå®¶çš„身份,担负ç€ç¥–父æ¯çš„一些资产,一心想为他们争光,建立一个æˆåŠŸçš„è¿è¾“å…¬å¸ã€‚您目å‰çš„æŒ‘战,就是创造一个蓬勃的ä¼ä¸šã€‚

éšç€æ—¶å…‰çš„æŽ¨ç§»ï¼Œæ—¶ä»£çš„å˜åŒ–,您得将公å¸å‘展æˆä¸€ä¸ªè¿è¾“王国,庞大江山。在æ¯ä¸€ä¸ªé˜¶æ®µï¼Œæ‚¨éƒ½å¿…须得通过货è¿ï¼Œå’Œæ¯æœˆä¸Šç™¾ä¸‡ä¹˜å®¢çš„å®¢è¿æœåŠ¡ï¼Œè€Œç²¾å¿ƒç»´æŒæœ¬åœ°åŒºç»æµŽçš„顺畅è¿ä½œã€‚
您的客è¿ã€é‚®è¿ã€è´§è¿è¡ŒåŠ¨ï¼Œå¯åœ¨é“ã€è·¯ã€ç©ºè¿›è¡Œã€‚

æ¯ä¸€ä¸ªæ¸¸æˆåœ°å›¾éƒ½å‘ˆçްä¸åŒçš„良机与挑战。仔细观察您的周围。。。您环境的未æ¥å‘展ã€å˜åŒ–,都由您和其他竞争者塑造。

èµ·åˆï¼Œæ‚¨å¯èƒ½å¯ä»¥ä»Žå•å•为一个电厂æä¾›å®ƒéœ€è¦çš„物å“开始。然åŽï¼Œä¸ºå®ƒä¸Žå…¶ä»–工厂打通连接。甚至设一些中央集线站,以便åšå¤§èŒƒå›´æ€§çš„物å“供应。
但一点您得关注。为å°é•‡ã€åŸŽå¸‚ä»…æä¾›è´§è¿ï¼Œæ˜¯ä¸ä¼šä½¿å®ƒä»¬æˆé•¿æ‰©å¤§çš„。也因这é™åˆ¶ï¼Œå®ƒä»¬ä¹Ÿä¸ä¼šäº§ç”Ÿæ–°çš„行业。(人还是最主è¦çš„资产å§ï¼Ÿï¼ï¼‰

å¦ä¸€ç§èµ·æ­¥æ–¹å¼ï¼Œä¹Ÿè®¸æ˜¯å…ˆä¸“注与客è¿ï¼ˆå¹¶ä¸”也邮è¿ï¼‰ã€‚è¿™ç§èµ·æ­¥æ–¹å¼è¾ƒå›°éš¾ï¼Œå› ä¸ºæ¯ä¸€ä¸ªä¹˜å®¢çš„目的地都ä¸ä¸€æ ·çš„ï¼
有些乘客å¯èƒ½è¦åˆ°å·¥åŽ‚ä¸Šç­ã€‚有些è¦åˆ°é‡ç‚¹é•‡çš„大商场购物。还有些å¯èƒ½è¦åŽ»è§‚å…‰ã€æ—…游的。

如果您的客è¿è·¯çº¿ä¸ä¸ºä»–们的始终点åšè¿žæŽ¥çš„è¯ï¼Œä»–们压根ä¸ç”¨æ‚¨çš„å®¢è¿æœåŠ¡ã€‚æ‰€ä»¥ï¼Œæ‚¨çš„å®¢è¿è·¯çº¿æœ€å¥½æ˜¯èƒ½è¿žæŽ¥åˆ°å¾ˆå¤šç›®çš„地,越多越好,至少也è¦åŒ…括æ¯ä¸ªè¾ƒå¸¸ç”¨çš„é‡ç‚¹ç›®çš„地。当您的客è¿è·¯çº¿ç½‘络已建起之åŽï¼Œæ‚¨ä¹Ÿå¾—ç»å¸¸å‡çº§è¿™ç½‘络,赶上需求é‡çš„增长。把视线放远,好好计划ï¼
å¦‚æžœä¹˜å®¢å¯¹æ‚¨çš„å®¢è¿æœåŠ¡æ»¡æ„çš„è¯ï¼Œæ‚¨ç½‘络所æœåŠ¡çš„é•‡ä¼šæˆé•¿ï¼Œæ–°çš„è¡Œä¸šä¼šå‡ºçŽ°ï¼Œè€Œç»æµŽä¹Ÿèƒ½é¡ºç•…è¿ä½œï¼Œå¹¶ä¸”会有创新ã€å¢žé•¿ã€è¿›æ­¥ã€‚

è¿™æ¸¸æˆæ²¡æ—¶é—´é™åˆ¶ï¼Œæ¯ç›˜æ¸¸æˆæ‚¨éƒ½å¯ä»¥çŽ©åˆ°ä»»ä½•æ—¶ä»£ã€ç»ˆç‚¹ã€‚从 1880 年到 2050 年,通过时代的å˜åŒ–,新的交通工具和建筑ç§ç±»ä¼šå‘ˆçŽ°æ–°çš„è‰¯æœºï¼ŒåŠ©äºŽæ–°çš„ç­–ç•¥ã€‚
您å¯ä»¥ä¸Žç”µè„‘玩家对抗,也å¯ä»¥è‡ªå·±ä¸€ä¸ªå…¬å¸ä¸Žæ—¶é—´èµ›è·‘。åªè¦æ‚¨çš„资金ä¸è¿žç»­ 3 个月都在 0 之下,您就ä¸ä¼šè¢«å®£å¸ƒç ´äº§ï¼Œè€Œæ¸¸æˆå°±ä¸ä¼šç»“æŸã€‚您å¯ä»¥åœ¨èµ„äº§çª—å£æŸ¥çœ‹æ‚¨çš„资产。

我们 Simutrans-组 和相关å‚与者(玩家ã€ç¿»è¯‘者ã€ç­‰ï¼‰ç¥æ‚¨åœ¨ Simutrans 有一个美好有趣的时光ï¼

simutrans-124.3/simutrans/text/cn/trafficlight_info.txt000066400000000000000000000003001474050137200233770ustar00rootroot00000000000000äº¤é€šç¯æŽ§åˆ¶å¸®åŠ©

äº¤é€šç¯æŽ§åˆ¶

控制红绿ç¯çš„å˜æ¢é¢‘率. å…¶å¯é€‰çš„æ•°å­—是绿ç¯åœ¨åŒ—/å—和东/è¥¿æ–¹å‘æŒç»­çš„ç§’æ•°.

simutrans-124.3/simutrans/text/cz.tab000066400000000000000000001373231474050137200177010ustar00rootroot00000000000000§Cestina PROP_FONT_FILE prop-latin2.fnt ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: cz Cestina # # Encoding: UTF-8 # # Font: prop-latin2.fnt # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Ne cl_btn_filter_enable Ano cl_btn_filter_settings Nastavení cl_btn_sort_asc VzestupnÄ› cl_btn_sort_desc SestupnÄ› cl_btn_sort_id Interní ID cl_btn_sort_income Příjmu cl_btn_sort_name Jméno cl_btn_sort_type Typu clf_btn_alle vÅ¡e clf_btn_invers inv. clf_btn_keine nic gl_btn_sort_bonus Podle bonusu gl_btn_sort_name podle názvu gl_btn_sort_revenue podle příjmu gl_btn_unsort nesetřídÄ›no hl_btn_filter_disable Ne hl_btn_filter_enable Ano hl_btn_filter_settings Nastavení hl_btn_sort_asc VzestupnÄ› hl_btn_sort_desc SestupnÄ› hl_btn_sort_name Jméno hl_btn_sort_type Typu hl_btn_sort_waiting ÄŒeká hlf_btn_alle vÅ¡e hlf_btn_invers inv. hlf_btn_keine nic Networks Schéma sítÄ› Queueing ZmÄ›na Äek. zásob Road toll Mýto Scenario Info. o scénáři Transfers PÅ™estupy #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Polární klima desert Poušť mediterran StÅ™edomoří rocky Skaliska temperate Mírné tropic Tropy tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Nahrávání scénáře selhalo Can't buy obsolete vehicles! Nákup zastaralých vozidel není možný! Cannot alter water Tato plocha nemůže být vysuÅ¡ena Äi zaplavena Cannot built depot here! Zde nemůžete\npostavit depo! Cannot built this station/building\nin underground mode here. Budova nesmí stát\npod zemí.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Nelze vytvoÅ™it linka typu 'VÅ¡e'!\n\nVyberte typ linky\naktivací přísluÅ¡né karty.\n Cannot create socket Neni možno vytvoÅ™it Socket! Convoi handles exhausted! PoÄet souprav dosáhl maximální hodnotu. Convoy already deleted! Konvoj byl již zruÅ¡en! Das Feld gehoert\neinem anderen Spieler\n Tuto Äást zemÄ›\nvlastní jiný hráÄ!\n Der Besitzer erlaubt das Entfernen nicht OdstranÄ›ní není dovoleno!\n Diese Zusammenstellung kann nicht fahren!\n Tato kombinace\nje nepojízdná!\n Flugzeughalt muss auf\nRunway liegen!\n Letadlo může vykládat\npouze na stojánce! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Tato letiÅ¡tní budova\nsem nepasuje Hier kann kein\nSignal aufge-\nstellt werden!\n Zde nemůžete postavit\nnávÄ›stidla!\n In order to lock the game, you have to protect the public player by password! Pro zamÄení hry je nutné veÅ™ejné služby zablokovat heslem! Lost connection\nto server! Server neodpovídá1\nHra pokraÄuje na lokálním poÄítaÄi! Lost synchronisation\nwith server. Hra mimo synchronizaci se serverem!\nProsím, restartujte! Maglevhalt muss auf\nMaglevschiene liegen!\n Zastávka maglevu musí být umístÄ›na na přísluÅ¡ném druhu trati! Monorailhalt muss auf\nMonorail liegen!\n Zastávka musí\nležet na trati!\n Monorails are not available yet! JeÅ¡tÄ› nelze stavÄ›t jednokolejku/visutou železnici! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Stanice úzkokolejky musí být\nna trati úzkokolejky No suitable way on the ground! Nevhodný úsek pro stavbu stanice nebo zastávky! No through station here! Zde nelze umístit stanici! Not enough clearance. Mezi cestami musí být výškový rozdíl alespoň dvou úrovní. Not enough money! Stavba pÅ™ekráÄí finanÄní možnosti! On narrowgauge track only!\n Pouze na úzkokolejné trati!\n Only public player can lock games! Pouze hrÃ¡Ä 'VeÅ™ejné služby' smí uzamknout hru. Out of funds Málo penÄ›z! Post muss neben\nHaltestelle\nliegen!\n Tato budova musí\nbýt umístÄ›na\nvedle existující\nzastávky stanice! Protocoll error (expecting game) Chybný protokol (Äekající hru) Schiffhalt muss im\nWasser liegen!\n Zastávky lodí mohou\nležet pouze na vodÄ›\npÅ™ed přístavem!\n Server busy Server je zaneprázdnÄ›n. Terraforming not possible\nhere in underground view Úprava terénu neni možná v podzemí! This tunnel branches. You can try Control+Click to remove. V tunelu je kÅ™ižovatka - tunel je nutné zbourat jiným způsobem. Upgrade must have\na higher level Nová stanice musí být vyšší úrovnÄ› Vehicle %s cannot choose because stop too short! Vozidlo %s si nemůže vybrat zastávku, protože je příliÅ¡ krátká! Zughalt muss auf\nSchiene liegen!\n Zastávky vlaku mohou\nležet pouze na\nželeniÄní trati!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s

Rejstřík

*: pouze v angliÄtinÄ›

Obecné

%s

Použití

%s

Nástroje

%s

ZaÄínáme

%s

Jak hrát

%s

Ostatní:

%s Keyboard Help\n

Keyboard Help

\n Klávesové zkratky\n

Klávesové zkratky

\nSimutrans zná následující klávesové zkratky :

\nCtrl + kliknutí - Skrýt informaÄní okno (obÄasnÄ›)
\nCtrl + tool - pracovat na vršní úrovni
\n\nEsc, Delete: Zavřít přední okno
\nBackspace: Zavřít vše okna
\nPage-up/Page-down, </>: Zoom zvětšit/zmenšit
\nF1 - Přehled Simutrans Pomoc
\n1 - Posunout mapu jihozápadně
\n2 - Posunout mapu jižně
\n3 - Posunout mapu jihovýchodně
\n4 - Posunout mapu západně
\n6 - Posunout mapu východně
\n7 - Posunout mapu severozápadně
\n8 - Posunout mapu severnÄ›
\n9 - Posunout mapu severovýchodně
\n

\nNásledující zkratky jsou volně použitelný
\n Decrease water height Snížit vodní hladinu Highlight railroad tracks Zvýrazní na mapÄ› železniÄní tratÄ› Highlite depots Zvýrazní na mapÄ› depa Highlite electrical transmission lines Zvýrazní elektrické rozvodné sítÄ› vysokého napÄ›tí. Highlite factories Zvýrazní/skryje na mapÄ› továrny Highlite forests Zobrazí na mapÄ› lesy Highlite tourist attraction Zobrazí/skryje na mapÄ› turistické cíle Increase water height Zvednout vodní hladinu Overlay city limits Zobrazí/skryje na mapÄ› hranice (limity) mÄ›sta. Overlay passenger destinations when a town window is open PÅ™ekrýt cíle cestujících, pokud je otevÅ™ené okno mÄ›st Overlay schedules/network Zobrazí/skryje schéma dopravní sítÄ› Overlay town names Zobrazí/skryje na mapÄ› názvy mÄ›st. Please click on the map to add\nwaypoints or stops to this\nschedule. PÅ™idejte stanice a kontrolní body do jízdního řádu. Set tile climate %s ZmÄ›nit klima na %s Show capacity and if halt is overcrowded Zobrazí velikost a stav zastávky. Show how many convoi reach a station Zobrazí, kolik souprav dorazilo do stanice. Show how many people/much is waiting at halts Zobrazí kolik Äeká na zastávkách Show initial passenger departure Zobrazí místa nástupu cestujících do dopravní sítÄ›. Show level of city buildings Zobrazí stupeň (level) u mÄ›stských budov Show mail service coverage/mail network Zobrazí dosah poÅ¡tovní sítÄ› Show passenger coverage/passenger network Zobrazí dosah sítÄ› pro pÅ™epravu cestujících Show speedlimit of ways Zobrazí maximální povolenou rychlost na komunikacích. Show the change of waiting at halts Zobrazí souÄet poÄtu příjatých a odbavených cestujících (odbaveného nákladu) na zastávce Show the owenership of infrastructure Zobrazí vlastníka infrastruktury Show transported freight/freight network Zobrazí/skryje množství pÅ™epraveného nákladu nebo schéma nákladní dopravní sítÄ› Show usage of network Zobrazí na mapÄ› hustotu provozu Shows a listing with all industries on the map. Seznam továren na mapÄ› Sum of departure/arrivals at halts SouÄet množství pÅ™ijatáho a odbaveného zboží (cestujících, poÅ¡ty) na zastávce. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s zřídil\npro turisty nové auto-\nbusové spojení mezi\n%s a\n%s\n(na %i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s\nnyní pÅ™epravuje praco-\nvníky z %s\ndo továrny\n%s\n(na %i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s nyní\nvyužívá %i\nnáklaÄáky k pÅ™epravÄ›\nmezi %s\n(na %i,%i) a\n%s (na %i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\notevírá novou železnici\nmezi %s\n(na %i,%i) a\n%s\n(na %i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n %s zajiÅ¡tuje nýni letecké spojení\n mezi mÄ›stami %s a %s Ferry service by\n%s\nnow between\n%s \nand %s.\n HráÄ\n%s\nzahájil lodní provoz mezi\n%sa%s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nzavedl novou přímÄ›stskou\nautobusovou linku mezi\n%s a\n%s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Editace mapy LISTTOOLS Seznamy MAGLEVTOOLS Nástroje pro maglev MONORAILTOOLS Nástroje pro jednokolejku/visutou železnici NARROWGAUGETOOLS Nářadí pro úzkokolejky RAILTOOLS ŽelezniÄní doprava ROADTOOLS SilniÄní doprava SHIPTOOLS Lodní doprava SLOPETOOLS Úprava terénu SPECIALTOOLS Speciální stavby TRAMTOOLS Tramvaje #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s vybudoval nové Å™editelství. Factory chain extended\nfor %s near\n%s built with\n%i factories. Ekonomický růst! ŘetÄ›zec průmyslu pro %s poblíž %s byl rozšířen o %i továren. New %s now available:\n%s\n Nové %s je nyní k dispozici\n'%s'\n New factory chain\nfor %s near\n%s built with\n%i factories. Postaven nový Å™etÄ›z průmyslu\n pro %s u\n%s, Äítající\n%i továren\n New vehicle now available:\n%s\n Je dostupné\nnové vozidlo:\n\n' %s '\n\n Now %u clients connected. PrávÄ› je pÅ™ipojeno %u hráÄů. Remove vehicle from map. Use with care! Odstranit vozidlo z mapy. Používejte jen pÅ™i problémech! Screenshot\ngespeichert.\n Screenshot uložen.\n Sends the convoi to the last depot it departed from! Poslat soupravu do nejbližšího vhodného depa With a big festival\n%s built\na new monument.\n%i citicens rejoiced. S velikou slávou\nv %s odhalili\nnovou atrakci.\n%i obÄanů jásá. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter filtr #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (v depu) \nBauzeit bis do \nBauzeit von \nDostupné od \nCan't open heightfield file.\n \nSoubor s terénem nelze naÄíst.\n \ndirection: \nsmÄ›ry: \nelektrified elektrifikováno \nHeightfield has wrong image type.\n \nÅ patný formát obrázku.\n \nis reserved by: \nrezervován pro vlak \nminimum speed: \minimální rychlost: \nnot elektrified \nnení pod proudem \nRibi (masked) \n (maska): \nRibi (unmasked) \n\nSmÄ›ry\n\n (bez masky): \nSet phases: \ndélka semafórové fáze rovnÄ›/příÄnÄ› \nsingle way \nJednosmÄ›rka \nway1 reserved by Trasa 1 rezervována hráÄem\nTrasa 1 rezervována hráÄem \nway2 reserved by Trasa 1 rezervována hráÄem\nTrasa 1 rezervována hráÄem \nwith sign/signal\n \nse znaÄkou/semaforem\n %d buildings\n %d budov\n %d convois %d souprav %d Einzelfahrzeuge im Depot %d vozidel zde parkuje. %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. Stáří: %i roků a %i mÄ›síců %s at (%i,%i) now public stop. %s je od teÄ veÅ™ejnou zastávkou %s building %s %s %s, %s %s city %d %s %s mÄ›sta %d %s %s factory %s %s %s - %s %s %s has entered a depot. Vozidlo "%s"\nzajelo do depa. %s land %d %s %s, Venkov %d %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Ve mÄ›stÄ› %s si úředníci nechali postavit\nnovou budovu,\nkdyž jejich mÄ›sto pÅ™esáhlo\n%i obyvatel. %s\nis crowded. %s\nje pÅ™eplnÄ›na. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nrychlost %i\nmaximální rychlost %i\ndx:%i dy:%i %s\nwas liquidated. SpoleÄnost %s zbankrotovala a byla zlikvidována. Provoz byl zastaven a majetek byl prodán. %u Client(s)\n %u hráÄ(ů)\n %u Player (%u locked)\n %u hráÄů (z toho %u zamknutých)\n <> <> <> <žadná linka> <> 1 convoi 1 souprava 1 Einzelfahrzeug im Depot 1 vozidlo zde parkuje. 1LIGHT_CHOOSE Jas: 1WORLD_CHOOSE Nastavení pro novou hru: 2LIGHT_CHOOSE Barvy: 2WORLD_CHOOSE Číslo mapy: 3LIGHT_CHOOSE Rychlost posuvu: 4LIGHT_CHOOSE Inverze posuvu 5LIGHT_CHOOSE Chodci na zastávkách 5WORLD_CHOOSE PoÄet mÄ›st: 6LIGHT_CHOOSE Chodci ve mÄ›stÄ› 6WORLD_CHOOSE Hustota provozu: 8WORLD_CHOOSE Střídat den a noc A bridge must start on a way! Most musí zaÄínat na cestÄ›! Abfrage InspekÄní lupa Abnehmer OdbÄ›ratelé About O objektu About scenario Autor scénáře Abriss Odstranit Absenken Snížit zemi Abspanntransformator Trafostanice továrny Accelerate time Zrychlený Äas Act. load: %u MW\n Aktuální pÅ™enos: %u MW\n Active player only Pouze aktivní hrÃ¡Ä Add forest Zasadit les Add random citycar VytvoÅ™it náhodné vozidlo add server PÅ™idat server Add Stop PÅ™idat zast. Add stops for backward travel PÅ™idat zastávky pro jízdu nazpÄ›t air ranvej aircraft_tab Nákladní letadla airplane letadlo Airport LetiÅ¡tÄ› AIRTOOLS Stavba letiÅ¡tÄ› All VÅ¡e all convoi tooltips Zobrazit vÅ¡echny nápovÄ›dy souprav Allow city growth Dovolit růst mÄ›sta Allow player change Umožnit zmÄ›nu hráÄe allowed climates:\n Dostupné v podnebí:\n Alters a schedule. PÅ™idat/Odstranit zastávky z jízdního řádu Angenommene Waren Zboží vyžadované pro okolní průmysl anhaengen PÅ™ipoj Anhaenger_tab PřívÄ›sy a návÄ›sy Anheben Zvýšit zemi Appends stops at the end of the schedule PÅ™idat zastávku na konec linkového vedení Apply Line PÅ™iÅ™adit linku April Duben Arbeiter aus: ZamÄ›stnanci bydlí v: Arrivals from\n Příjezdy\n Arrived PÅ™ijato Assets Majetek Aufloesen Rozebrat Aufspanntransformator Trafostanice elektrárny August Srpen Autohalt muss auf\nStrasse liegen!\n Nelze postavit mimo silnici! Available K dispozici Bahndepot Vlakové depo Bankrott:\n\nDu bist bankrott.\n Bankrot:\n\nVaÅ¡e firma zkrachovala.\n battery pohon: baterie Baum Strom baum builder Zasadit stromy Baustelle StaveniÅ¡tÄ› Bauzeit Stavební doba Beenden Konec Beginner mode zaÄáteÄnický mód Besonderes Gebaeude Turistická atrakce BF Stanice bio pohon: bio Blockstrecke ist\nbelegt\n V tomto železniÄním\núseku je jiný vlak\n Boden ZemÄ› Bonusspeed: %i km/h Nejvyšší možná rychlost: %i km/h Boost (%%) Zvýšení produkce (%%) bridge is too high for its type! Tento typ neumožňuje takovouto výšku mostu! Bridge is too long for this type!\n Most tohoto typu nemůže být tak dlouhý! Bruecke Most Bruecke muss an\neinfachem\nHang beginnen!\n Mosty musí zaÄínat na\nrovinÄ› nebo na sklonu!\n Brueckenboden most Build air depot Postavit hangár build choosesignals Postavit staniÄní signalizaci Build city market Postavit v nejbližším mÄ›stÄ› obchodní síť Build drain Postavit transformátorovu stanici build HQ Postavit sídlo Build land consumer Postavit novou elektrárnu Build maglev depot Postavit depo maglevu Build monorail depot Postavit depo jednokolejné dráhy Build narrowgauge depot Postavit depo úzkokolejky Build powerline Napnout dráty vysokého napÄ›tí Build presignals Postavit pÅ™ednávÄ›stidla Build road depot Postavit silniÄní depo Build ship depot Postavit lodÄ›nici Build signals Postavit návÄ›stidla Build train depot Postavit železniÄní depo Build tram depot Postavit tramvajovou vozovnu Build truck depot Postavit garáže Building costs estimates Příbližná cena stavby Buildings Budovy Built artifical slopes Upravit svah Built random attraction PÅ™idat turistickou atrakci Bus_tab Autobusy Can only move from halt to halt or waypoint to waypoint. PÅ™ehození možno jenom\nod stanice k stanici nebo\nod bodu k bodu Cancel Ne Cannot connect to offline server! K nedostupnému serveru se nelze pÅ™ipojit. Capacity: Kapacita: Capacity: %.0f MW Kapacita sítÄ›: %.0f MW\n Capacity: %d%s %s\n Kapacita: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapacita: %s\n>> %d (%d%%) Cars are not available yet! Automobily nelze zatím stavÄ›t!\nJeÅ¡tÄ› nebyly vynalezeny. cars.\nstate vozidla\n Cash Zůstatek Change player ZmÄ›nit hráÄe Chart Graf Chat_msg Chat Choose direction Zvolte orientaci! Choose operation executed on clicking stored/new vehicles Vybrat operaci provedenou pÅ™i kliknutí na zaparkovaná/nová vozidla v depu chooses a random map Vyber náhodnou mapu citicens Obyvatelé City attraction MÄ›stské památky City industries Průmysl ve mÄ›stÄ› City list Seznam mÄ›st City size Velikost city_road MÄ›stská silnice citybuilding builder PÅ™idat mÄ›stskou budovu CityLimit Hranice mÄ›sta cl_title Seznam vozidel cl_txt_sort Řadit podle: Clear block reservation Odstranit rezervaÄní znaÄky clf_chk_aircrafts Letadla clf_chk_cars Bus/TIR clf_chk_indepot V depu clf_chk_maglev MagLevy clf_chk_monorail Jednokolejky clf_chk_name_filter Jméno: clf_chk_narrowgauge Úzkokolejky clf_chk_noincome Bez příjmu clf_chk_noline Bez linky clf_chk_noroute Ztracen cíl cesty clf_chk_noschedule Bez řádu clf_chk_obsolete zastaralé clf_chk_ships LodÄ› clf_chk_spezial_filter Speciální filtr: clf_chk_stucked Uvízlé clf_chk_trains Vlaky clf_chk_trams Tramvaje clf_chk_type_filter Typ vozidla: clf_chk_waren Náklad: clf_title Nastavení filtru pro seznam vozidel Climate Control Nastavení podnebí closed ZavÅ™eno. COLOR_CHOOSE\n Vyberte si, prosím,\nVaÅ¡i barvu:\n Company bankrupt SpoleÄnost zbankrotovala Company_msg ProtihráÄi Comparing pak files ... Porovnávání *.pak souborů ... Configure AI Nastavit umÄ›lou inteligenci Configure AI setttings Nastavení UI Congratulation\nScenario was complete in\n%i months %i years. Gratulace!\n\nScénář byl úspěšnÄ› dodehrán za %i mÄ›síc(e) a %i rok(y) Connected stops Zastávky v dosahu objektu: Connected with server Spojen s serverem Constructed by Postavil: Constructed by %s Postavil: %s construction speed rychlost výstavby Construction_Btn Stavby Consumed SpotÅ™ebováno convoi %d of %d Souprava Ä. %d z %d convoi error tooltips Zobrazit jen varovné nápovÄ›dy Convoi has been sent\nto the nearest depot\nof appropriate type.\n Souprava byla poslána do nejbližšího depa vhodného typu. Convoi is sold when all wagons are empty. Souprava je prodána, jakmile jsou vÅ¡echna její vozidla vyprázdnÄ›na. convoi mouseover tooltips NápovÄ›da souprav na požádání convoi passed last\nmonth %i\n \nSouprav za poslední\nmÄ›síc: %i\n Convois Soupravy Convois: %d\nProfit: %s Souprav: %d\nZisk: %s Convoys Soupravy Copy Convoi Kopírovat Copy the selected convoi and its schedule or line Kopírovat vybranou soupravu vÄetnÄ› jízdního plánu Äi linky cost for removal Cena za odstranÄ›ní Cost: %8s (%.2f$/km %.2f$/m)\n Cena: %s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Cena: %8s (%.2f/km)\n Costs Výdaje Create a new line based on this schedule VytvoÅ™it novou linku, založenou na tomto jízdním plánu curiosity builder PÅ™idat kuriozitu curlist_title Turistické cíle Currently playing: PrávÄ› se pÅ™ehrává: Customers live in: Zákazníci žijí v: deactivated in online mode Neaktivní Deccelerate time Zpomalit Äasovou osu December Prosinec decrease underground view level Snížit úroveň Å™ezu skrz terén Del Stop Smazat Delete Line Smazat linku Delete the current stop Smazat aktivní zastávku Delete the selected line (if without associated convois). ZruÅ¡it vybranou linku (není-li obsluhována) Delete this file. Smazat tento soubor. Delivered DoruÄeno Demand Poptávka Demand: %.0f MW SpotÅ™eba: %.0f MW\n Denkmal Pomník Departed Odbaveno Departure board Příjezdy/Odjezdy Departures to\n Odjezdy\n Depots Depa Der Tunnel ist nicht frei!\n Tunel nelze zasypat! Destination Míření Destroying map ... Ruším mapu ... Details Detaily Die Bruecke ist nicht frei!\n Most neni volný! diesel pohon: dieslový Direkt erreichbare Haltestellen PÅ™eprava odkud, kam a Äeho disable midi Vypnout Midi Display settings Nastavení zobrazení Distance Délka/MÄ›síc Dock Přístav Dock must be built on single slope! Doky lze postavit pouze na rovném pobÅ™eží! dp_title Seznam dep Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Máte jeÅ¡tÄ› %d mÄ›síc(e) na splacení dluhu. Durchsatz Max. Economy Hospodářství a mÄ›sta Eigenbesitz\n VeÅ™ejný majetek\n Ein %s\npasst hier nicht.\n '%s'\nse sem nehodí!\n Einstellungen aendern ZmÄ›na nastavení electric pohon: elektrický Electricity ElektÅ™ina Electricity producer\n\n Výrobce elektÅ™iny\n\n Electrics_tab Trakce Electrify track Elektrifikovat traÅ¥ enlarge map ZmÄ›nit velikost mapy enter a value between %i and %i Vložte hodnotu mezi %i a %i Enter address Zadejte adresu Enter Password ZmÄ›na hráÄova jména a hesla Error CHYBA Erzeuge neue Karte.\n Prosím vyÄkejte,\nvytvářím novou mapu...\n\nČím je vÄ›tší mapa,\nhustota průmyslu,\ndopravy apod., tím\ndéle trvá vytváření\nmapy. Es wird bereits\nein Fahrplan\neingegeben\n Jízdní řád už\nse upravuje!\n Fabrikanschluss Spojení s průmyslem Fabrikname Název továrny Factories Továrny factory details Detaily o továrnÄ› factorybuilder PÅ™idat továrnu Fahrplan Jízdní řád Fahrtziel Místo urÄení: Fahrzeuge koennen so nicht entfernt werden Vozidla nemohou být\nodstranÄ›na touto\ncestou!\n Fahrzeuge: Vozidla: Farbe Barva Fast forward Zrychlit Äas February Únor Ferry_tab Trajekty Fertig Hotovo Filename Soubor: Files from: Soubory: Filter: Filtrovat: Finances of %s Finance %s Finanzen Finance find mismatch Porovnat VaÅ¡e *.pak soubory fl_title Seznam továren Flug_tab Osobní letadla follow me Následuj Follow the convoi on the map. Následuj soupravu po mapÄ›. Forest Les Found new city Založit nové mÄ›sto Fracht Náklad Free Capacity Volná kapacita freeplay mode Freeplay Friction: okamžitý koeficient tÅ™ení: fuel_cell pohon: palivové Älánky Full load ÄŒekat na: Fundament Podklad Fussgaenger Chodec Game info Informace o hÅ™e GAME PAUSED HRA POZASTAVENA Game_msg VÅ¡eobecné Gear: PÅ™evod: Gebaeude Budova General VÅ¡eobecnÄ› Generated Vyprodukováno Generation: %.0f MW Výroba: %.0f MW\n Gewicht Hmotnost Gewinn Příjem: Give the selected vehicle(s) an individual schedule PÅ™iÅ™adit vybranému(ým) vozidlu(ům) zvláštní jízdní řád gl_btn_sort_catg podle kategorii gl_title Seznam zboží go home Do depa Goods Zboží Goods AI AI (Zboží) Goods list Seznam zboží Gross Profit Hosp. výsledek Groundobj Objekt groundobj builder PÅ™idat krajinný objekt Grow city ZvÄ›tÅ¡it mÄ›sto Growth Růst mÄ›sta H Hangar Hangár Happy Spokojeno Haus kaufen Koupit dům Helligk. Zobrazení Help Pomoc Help text not found NápovÄ›da neexistuje hide all building Skryté vÅ¡echny budovy hide city building Skryté mÄ›stské budovy hide objects under cursor Skrýt objekty pod kursorem hide station names Skryté názvy stanic hide transparent Průhledné skrývání objektů hide trees Skryté stromy Hier warten/lagern: ÄŒekající zboží a osoby: Higher transport fees, crossconnect all factories Zvýšit pÅ™epravní poplatky, spojit vÅ¡echny továrny Highlite schedule Zvýraznit jízdní řád hl_title Seznam stanic hl_txt_filter Filtrovat: hl_txt_sort Řadit podle: hlf_chk_airport LetiÅ¡tÄ› hlf_chk_anleger Přístav hlf_chk_bahnhof Nádraží hlf_chk_bushalt Autobus hlf_chk_frachthof Naklád hlf_chk_keine_verb Mimo provoz hlf_chk_maglevstop MagLev hlf_chk_monorailstop Jednokolejka hlf_chk_name_filter Jméno: hlf_chk_narrowgaugestop Úzkokolejka hlf_chk_overflow PÅ™eplnÄ›ný hlf_chk_spezial_filter Speciální filtr: hlf_chk_tramstop Tramvaj hlf_chk_type_filter Typ stanice hlf_chk_waren_abgabe Dodává: hlf_chk_waren_annahme Příjme: hlf_title Filtrovat Seznam stanic podle: Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depo nenalezeno!\nSouprava je tÅ™eba poslat\ndo depa ruÄnÄ›. Homeless Bezdomovců hydrogene pohon: vodíkový Idle: NepÅ™iÅ™azeno: ignore climates Ignorovat podnebí In the industry legend show only currently existing factories Zobrazit pouze existující továrny In Transit Na cestÄ› Increase Industry density Zahustit průmysl increase underground view level Zvýšit úroveň Å™ezu skrz terén industrial building Továrna Init map ... Vytvářím mapu... Input Příjem Ins Stop Vložit Insert stop before the current stop PÅ™idat zastávku nad oznaÄenou zastávkou Intercity road len: MezimÄ›stské vazby: Intro. date: Dostupnost od: invalid neurÄeno. Invalid coordinate Neplatné souÅ™adnice isometric map Izometrická mapa January Leden join game Hrát on-line July ÄŒervenec Jump to Posunout na June ÄŒerven Kann Spielstand\nnicht laden.\n Uloženou hru nelze naÄíst!\n Kann Spielstand\nnicht speichern.\n Do souboru s uloženou\nhrou nelze zapisovat!\n Kein Besitzer\n Bez majitele\n keine žádný Keine Einzelfahrzeuge im Depot Žádná zaparkovaná vozidla Keyboard_Help\n Klávesové zkratky\n koord souÅ™adnice Kreuzung PÅ™ejezd labellist_title Seznam znaÄek Lade Relief NaÄíst terén Laden NaÄíst Land attraction Venkovská památka Land industries Průmysl mimo mÄ›sta LANG_CHOOSE\n Vyberte si, prosím,\nVáš jazyk:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Minulý mÄ›síc Last used tools Naposledy použité nástroje Last Year Minulý rok: Leaving depot! OpouÅ¡tí depo! leer prázdný Legend Legenda Leistung Výkon Leistung: %d kW Výkon: %d kW Leitung Vedení letzen Monat: diesen Monat: minulý mÄ›síc: tento mÄ›síc: Line Linka Line Management Správa linek Lineless convoys serving this stop Vozidla bez zadané linky, která obsluhují tuto stanici Lines serving this stop Linky obsluhující tuto stanici LKW_tab NáklaÄáky Load game Nahrát hru load height data from file Nahrát výškovou mapu ze souboru Load scenario Nahrát scénář loaded naloženo loaded passenger/freight SeÅ™adit náklad dle Loading (%i->%i%%)! Naloženo %i z %i%% Loading addon paks ... --- NaÄítám rozšíření --- Loading map ... --- Nahrávám mapu --- Loading paks ... --- Nahrávám základní grafiku --- Loading skins ... --- Nahrávám grafické rozhraní --- Lock game Znemožnit další zmÄ›nu hráÄů Lokomotive_tab Lokomotivy maglev vehicle magnetické vozidlo maglev_track TraÅ¥ maglevu Maglevdepot Depo maglevu Mail Demand %d\n Poptávaná poÅ¡ta Mailbox PoÅ¡tovní schránka Mailbox Options Nastavení zpráv Maintenance Údržba make stop public (or join with public stop next) costs %i per tile and level ZveÅ™ejnit zastávku za %i? na políÄko a úroveň Manual (Human) Nový hrÃ¡Ä Manufactured: Vyrobeno: Map roughness Zaoblení mapy: map zoom PÅ™iblížení March BÅ™ezen Margin (%%) VýdÄ›lek (%%) Marker ZnaÄka Max Boost (%%) Max. zvýšení produkce (%%) Max income: Max. zisk: Max. speed: Max. rychlost: Maximum 254 stops\nin a schedule!\n Nanejvýš 254 zastávek\nv jízdním řádu!\n maximum length of rivers Max délka Å™ek Maximum tile height difference reached. Výška okolních polí je příliÅ¡ odliÅ¡ná! Maxspeed Nejvyšší rychlost May KvÄ›ten Median Citizen per town PrůmÄ›rná velikost mÄ›sta Meldung Zpráva Menge PoÄet merge stop SlouÄit zastávky MessageOptionsText \nNový rok\n\nNovinky AI\n\nZe mÄ›st\n\nBloudÄ›ní\n\nNový průmysl\n\nDiskuse\n\nNová vozidla\n\nPÅ™eplnÄ›ní\n\nProblémy\n\nZácpy\n\nScénář minimum length of rivers Min. délka Å™ek Missing pakfiles Chybí nÄ›které soubory grafické sady (paku) Modify the selected line ZmÄ›nit vybranou linku Monate alt mÄ›síců starý Monorail Jednokolejka monorail vehicle vozidlo jednokolejky monorail_track TraÅ¥ monorailu Monorailboden Nosník magnetické dráhy Monoraildepot Depo jednokolejky month wait time mÄ›síce Äeká Months MÄ›síce Monument Památník Monuments Památníky Mountain height Výška hor: Movingobj pohyblivý objekt Music playing disabled/not available PÅ™ehrávání hudby deaktivováno/nedostupné Music volume: Hlasitost hudby: mute sound Vypnout zvuk Name Jméno Narrowgauge Úzkokolejná dráha Narrowgauge are not available yet! Úzkokolejka není dosud k dispozici! narrowgauge vehicle úzkokolejné vozidlo narrowgauge_track TraÅ¥ úzkokolejky Narrowgaugedepot Depo úzkokolejné dráhy Net ID: %p Síť: %p\n Net Wealth JmÄ›ní Net wealth near zero VaÅ¡e jmÄ›ní se blíží k nule. Neue Karte Nová mapa Neue Welt VytvoÅ™it novou mapu new convoi Nová souprava New Line Nová linka New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. VytvoÅ™ena nová linka!\nMůžete jí nyní pÅ™iÅ™adit\njejím zvolením v\nhorní Äásti okna. New Vehicles Nová vozidla Nickname: PÅ™ezdívka no buildings hidden Ukázat budovy no convois Žádné konvoje No goods are loaded onto this convoi. V tomto konvoji není naloženo žádné zboží no goods waiting žadné zboží na odbavení no load nenakládat No Route NenaÅ¡lo spoj No stop here! Nářadí je pouze přístupné na stanicích! No suitable ground! Nevhodný terén! No terminal station here! Zde nelze postavit\nkoncovou stanici! no timeline Bez Äasové osy no tree Bez stromů No. of Factories Továrny a obchody Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Nejprve nastavte\njízdní řád!\n none nic nord Severní nordost Severovýchodní nordwest Severozápadní Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Nepovoleno!\nJízdní řád nemůže\nbýt právÄ› zmÄ›nÄ›n.\nZkuste to pozdÄ›ji! Not enough fields would remain. Kolem této farmy zbývá\nmálo políÄek. November Listopad Now active as %s.\n Nyní aktivní jako %s.\n Number of rivers PoÄet Å™ek Object Podle ID Odometer: %s km Kilometrovník: %s km Ok Ano Oktober Říjen On loan since %i month(s) Jste zadlužen již %i mÄ›síc(ů)! On this map, you are not\nallowed to change player!\n V této hÅ™e\nnemůžete hrát\nza jiného hráÄe!\n Only city chains Pouze mÄ›stský průmysl Only first %d differing paks reported. There are probably more. Ohlášeno jen %d odliÅ¡ných souborů. Ale je jich asi více. Only land chains Pouze venkovský průmysl Only one transformer per factory! U továrny smí být jen jedna trafostanice! Only show goods which are currently handled by factories Zobrazit jen zboží dodávané nebo odebírané nÄ›kterou z továren na stávající mapÄ›. open otevÅ™eno Operation Provoz vozidel Ops Profit Zisk vozidel Optionen Nastavení Or enter a server manually: Nebo zadejte adresu serveru ruÄnÄ› Origin Odbaveno ost Východní Output OdbÄ›r Ownership Vlastnictví Pak which may cause severe errors: Následující objekty chybí a mohou způsobit chybu v průmyslu Pak which may cause visual errors: Pak, který může způsobit chyby v zobrazení Pak(s) different: OdliÅ¡né soubory: Pak(s) missing on client: Soubory chybÄ›jící u hráÄe: Pak(s) not on server: Soubory chybÄ›jící na serveru: Pakset differences Rozdíly mezi sestavami paletten palet Pas_tab Osobní a poÅ¡tovní vozy Passagiere cestujících Passagierrate Vzrůst osob Passagierziele Cíle cestujících/poÅ¡ty Passenger AI AI (Osobní) Passenger Demand %d\n Poptávka po cestujících Passengers %d %c, %d %c, %d no route osob %d %c, %d %c, %d bez spoje Passengers %d %s, %d %s, %d no route osob %d %s, %d %s, %d bez spoje Password Heslo: Pause Pauza Pax <%i> Mail <%i> Cestující <%i> PoÅ¡ta <%i> PaxDest Cíl cesty Percent Electricity Elektrifikováno (%%) Planes are not available yet! Letadla nejsou zatím dostupná!\nŽádné komerÄnÄ› využitelné stroje\nnebyly jeÅ¡tÄ› vynalezeny. Plant tree Zasadit strom player HrÃ¡Ä player -1 ÄŒlovÄ›k player 0 VeÅ™ejné služby player 1 Napik 128 a.s. player 10 HrÃ¡Ä 10 player 11 HrÃ¡Ä 11 player 12 HrÃ¡Ä 12 player 13 HrÃ¡Ä 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG player 7 HrÃ¡Ä 7 player 8 HrÃ¡Ä 8 player 9 HrÃ¡Ä 9 Please choose vehicles first\n Nejprve vyberte vozidlo!\n Post poÅ¡ty Postrate PoÅ¡ta Power Výkon Power (MW) Dodaná el. enegrie (MW) Power: Výkon: Power: %4d kW\n Výkon: %4d kW\n Powerlines Dráty v. n. Problems_msg UpozornÄ›ní Produced Vyrobeno Production of %s has been stopped:\n%s\n Zastavena výroba %s '%s' Production/Boost Výroba/Zvýšeno Produktion Výroba Profit Zisk promote to line VytvoÅ™it linku q1 Jaro q2 Léto q3 Podzim q4 Zima Query server Dotázat se serveru rail car železniÄní vozidlo random náhodnÄ› Random age Náhodné stáří Random map Náhodná mapa Rathaus Radnice Rating Stav ratio_pax %% osob Relevant Použitelné Reliefkarte Mapa Remove Odstranit znak remove airstrips Odstranit pojíždÄ›cí dráhu remove channels Zbourat plavební kanály remove interm. signals Odstranit vložené semafory remove maglev tracks Odstranit traÅ¥ MagLevu remove monorails Odstranit traÅ¥ jednokolejky remove narrowgauge tracks Odstranit traÅ¥ úzkokolejky remove powerlines Odstranit vedení vysokého nápÄ›ti remove roads Zbourat silnice remove tracks Odstranit traÅ¥ Remove wayobj %s Odstranit dopravní stavbu %s replace other signals Nahradit ostatní semafory replace stop Prohodit zastávky request closing ZavÅ™ení požadovano residential house Obytný dům Restore natural slope Obnovit přírodní terén Restwert: Cena za prodej: Retire. date: Zastaralé od: return ticket ZpÄ›tná jízda Revenue Příjmy Revision: Revize: road Silnice road vehicle silniÄní vozidlo Roadsign SilniÄní znaÄka Rotate Building OtoÄit budovu (nástupiÅ¡tÄ›) Rotate map Rotace mapy Rotation Rotace Routing Spojení sack balíků sail vítr Saving map ... Ukládám mapu ... Scenario complete: %i%% SplnÄ›ní scénáře: %i%% Scenario Debug LadÄ›ní scénáře Scenario Error Log Chyby ve scénáři Scenario Goal Cíl scénáře Scenario Info Základní informace o scénáři Scenario information Podrobnosti scénáře Scenario Result SplnÄ›no Scenario Rules Podmínky pro splnÄ›ní cíle scénáře Schedule changing! ZmÄ›na linkového vedení! Schienentunnel Postavit tunel Schiff_tab Nákladní lodÄ› Schiffdepot LodÄ›nice Schleppkahn_tab ÄŒluny Seasons RoÄní období Sehenswuerdigkeit Turistická atrakce Select a server to join: Zvolte server, ke kterému se chcete pÅ™ipojit. Select a theme for display Vybrat motiv rozhraní Sell the selected vehicle(s) Prodat vybrané(á) vozidlo(a) sended PoÅ¡ta Äeká SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September Září Server did not respond! Server neodpovídá! Serves Line: Obsluha linky: Service Vozidla set signal spacing Nastavení vzdálenosti semaforů Setting Nastavení Ship LodÄ› shops and stores Obchody a kanceláře Show all Zobrazit vÅ¡e show all building Zobrazit vÅ¡echny budovy Show also vehicles no longer in production. Zobrazovat také zastaralá vozidla Show also vehicles that do not match for current action. Zobrazuj i vozidla nevhodná pro nastavenou akci. Show even servers with wrong version or pakset Ukázat rovněž servery s Å¡patnou verzí Äi Å¡patnými sestavami show grid Zobraz mřížku Show industry Průmysl Show legend Legenda Show map scale Å kála Show mismatched i jiné verze Show obsolete Zobrazovat zastaralá Show offline zobrazit nedostupné Show only used Zobrazit jen používané Show schedules Zobraz jízdní řády Show servers that are offline Zobrazí též nedostupné servery. Show servers where game version or pakset does not match your client Zobrazí též servery s jinou verzí programu nebo paku než má váš program. show station coverage Zobrazit dosah stanice show station names Zobrazit názvy stanic show waiting bars Zobrazení Äekajících nákladů show/hide block reservations zobrazit/skrýt rezervate traÅ¥ových úseků Show/hide estimated arrival times Zobrazit/skrýt pÅ™edpokládáané Äasy příjezdů show/hide object owner zobrazit/skrýt vlastníka objektu Show/hide statistics Zobraz/schovej grafy Shows buttons on special topics. Zobrazení tlaÄítek možností minimapy Shows consumer/suppliers for factories Zobraz dodavatele/odbÄ›ratele pro továrny Shows the color code for several selections. Zobrazí barevné měřítko nÄ›kterých možností minimapy Shows the currently selected schedule Zobraz aktuálnÄ› vybraný plán Shrink city ZmenÅ¡it mÄ›sto shuffle midis Náhodné poÅ™adí Signal Semafor signal spacing Vzdálenost mezi semafory Sim: Simloops: Similar view as the main window Podobný náhled jako v hlavním oknÄ› Size (%d MB): Velikost (%d MB): sliced underground mode Zobrazení vrstvy Ä. slot empty Volný Smart hide objects Chytré skrývání objektů Sort by SeÅ™adit náklad podle Sort waiting list by Řadit seznam Äekajícího zboží podle Sound Zvuk Sound settings Nastavení zvuku a hudby Sound volume: Hlasitost zvuku: special freight spec. zboží Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus za rychlost\nSilnice %i km/h, Železnice %i km/h\nVoda %i km/h, Vzdůch %i km/h Speedlimit Max. rychlost Speichern Uložit Spieler HrÃ¡Ä Spieler(mz) HráÄi Spielerliste Obchodní rejstřík Spielstand wurde\ngeladen!\n \nHra úspěšnÄ› naÄtena!\n Spielstand wurde\ngespeichert!\n \nHra úspěšnÄ› uložena!\n Sprache Jazyk Sprachen Jazyk Stadtinformation Statistiky mÄ›sta Start the selected vehicle(s) Vyjet s vybraným(i) vozidlem(y) Starte Spiel ZaÄít hru Station tiles: ZastavÄ›ná plocha: Station_msg Stanice Status Stav steam pohon: parní Step timeline one year PÅ™idej jeden rok Stops Zastávky Storage Zásoby Storage capacity Úložná kapacita Strassendepot SilniÄní depo Strassentunnel Postavit tunel street car tramvajový vůz sued Jižní suedost Jihovýchodní suedwest Jihozápadní Summer snowline Sněžná Äára v létÄ› Supplied: %.0f %% Dodáno: %.0f %% Suppliers Dodavatelé Tage alt dní starý There are still vehicles\nstored in this depot!\n V tomto depu stále\nparkují vozidla!\n This Month Tento mÄ›síc This Year Tento rok: Tile not empty. Pole není volné.\nPÅ™ed úpravou terénu\nodstraňte stavby. timeline ÄŒasová osa tl_title Seznam mÄ›st To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Aby pÅ™ilákali návÅ¡tÄ›vníky,\nradní ve mÄ›stÄ› %s postavili\n %s z financí svých\n%i daňových poplatníků. To heavy traffic\nresults in traffic jam.\n NadmÄ›rný provoz způsobil\ndopravní kolaps.\n Toggle day/night view MÄ›nit den/noc Toggle vehicle tooltips PÅ™epnout nápovÄ›du pro vozidla tonnen tun Total inhabitants: Celkem obyvatel: Tourist attractions Turistické atrakce Tourists Turisté Town_msg MÄ›sto Town: %s\n Obec: %s\n Towns MÄ›sta track traÅ¥ Tracks TratÄ› Traffic Provoz Train Vlaky Trains are not available yet! Vlaky jeÅ¡tÄ› nebyly\nvynalezeny! Tram Tramvaj tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. Tramvaje %i km/h, Jednokolejky %i km/h\nMagLevy %i km/h, Úzkokolejky %i km/h tram_track tramvajová traÅ¥ Tramdepot Depo tramvají Trams are not available yet! Tramvaje jeÅ¡tÄ› nebyly\nvynalezeny! Transferring game ... PÅ™evádÄ›ní hry... Transformer only next to factory! MÄ›nírny jsou dostupné pouze\n na prázdních a plochých políÄkách\nsousedujících k továrnám Translation Podle jména transparent station coverage Průhledný dosah stanice Transported PÅ™epraveno TrolleyBus_tab Trolejbusy Truck NáklaÄáky tt_Other Ostatní Tunnel muss an\neinfachem\nHang beginnen!\n Tunely musí zaÄínat\ni konÄit na sklonu!\n Tunnel must start on single way! Tunel musí zaÄínat\nna volném konci cesty!\n Tunnelboden Tunel underground mode Zobrazení celého podzemí UNDO failed! Nelze vzít zpÄ›t Undo last ways construction Vymazat poslední krok stavby cesty Unemployed NezamÄ›stnaných Unhappy Nespokojeno units/day /den Update Line ZmÄ›nit linku upgrade HQ VylepÅ¡it sídlo Usage: %.0f %% Využito: %.0f %% Usage/Output Využito/Výkon Use beginner mode Použít zaÄáteÄnický mód Use timeline start year ZaÄít od roku Vehicle %s can't find a route! Souprava %s\nnemůže pokraÄovat v jízdÄ›!\n Vehicle %s is stucked! Souprava %s uvízla! Vehicle details Podrobnosti Verbrauch SpotÅ™eba Vergroessere die Karte\n ZvÄ›tÅ¡it mapu Verkauf Odstranit verkaufen Prodávat Verkehrsteilnehmer Osobní auta Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Jste v mínusu!\n\nMáte %d mÄ›síc(e)\nna zaplacení dluhu!\n vh_title Katalog vozidel via PÅ™es via %s\n pÅ™es %s\n via Menge PÅ™es + PoÄet voranstellen Na zaÄátek Waggon_tab Vagóny waiting ÄŒeká Waiting for clearance! ÄŒeká na uvolnÄ›ní úseku Walked OdeÅ¡lo Warnings_msg Doprava Wasser Voda Water voda Water level Úroveň vody: water vehicle vodní vozidlo way %s cannot longer used:\n Typ trati %s nemůže být dále používán.\n way %s cannot longer used:\n%s\n Typ trati %s nemůže být dále používán:\n%s\n way %s now available:\n Typ trati %s je nyní k dispozici. Way toll Mýtné Ways not connected Možno jen na spojených cestách! Wegpunkt Bod Weight: Hmotnost: Wert Cena west Západní Winter snowline Sněžná Äára v zimÄ› withdraw VyÅ™adit Withdraw All VyÅ™adit vÅ¡e WRONGSAVE \nNekompatibilní verze\nsouboru. Tuto uloženou hru nelze\nnaÄíst.\n Year %i has started. ZaÄal rok %i! Years Roky Your primary color: VaÅ¡e primární barva Your secondary color: vaÅ¡e sekundární barva Zielort Cíl zooming in PÅ™iblížit zooming out Oddálit Zu nah am Kartenrand PříliÅ¡ blízko\nk okraji mapy!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nový svÄ›tový rychlostní rekord maglevu: %.1f km/h soupravou %s. New world record for monorails: %.1f km/h by %s. Nový svÄ›tový rychlostní rekord monorailu: %.1f km/h soupravou %s. New world record for motorcars: %.1f km/h by %s. Nový svÄ›tový rychlostní \nrekord vozidla: %.1f km/h \nsoupravou %s. New world record for narrowgauges: %.1f km/h by %s. Nový svÄ›tový rychlostní rekord úzkokolejky: %.1f km/h soupravou %s. New world record for planes: %.1f km/h by %s. Nový svÄ›tový rychlostní\n rekord letadla:\n %.1f km/h\n strojem %s. New world record for railways: %.1f km/h by %s. Nový svÄ›tový rychlostní\n rekord vlaku:\n %.1f km/h\n soupravou %s. New world record for ship: %.1f km/h by %s. Nový svÄ›tový rychlostní\n rekord lodÄ›:\n %.1f km/h\n plavidlem %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL eÅ¡ov &1_CITY_SYLL ovice &2_CITY_SYLL ichov &3_CITY_SYLL onín &4_CITY_SYLL oviÄky &5_CITY_SYLL inÄ›ves &6_CITY_SYLL any &7_CITY_SYLL nice &8_CITY_SYLL otín &9_CITY_SYLL kov &A_CITY_SYLL edly &B_CITY_SYLL asy &C_CITY_SYLL áňky &D_CITY_SYLL aň &E_CITY_SYLL áňka &F_CITY_SYLL avice &G_CITY_SYLL iÄina &H_CITY_SYLL ec &I_CITY_SYLL ice &J_CITY_SYLL iÄka &K_CITY_SYLL iÄky &L_CITY_SYLL ín &M_CITY_SYLL ínka &N_CITY_SYLL ina &O_CITY_SYLL ivice &P_CITY_SYLL ivín &Q_CITY_SYLL ov &R_CITY_SYLL ová &S_CITY_SYLL ové &T_CITY_SYLL ovec &U_CITY_SYLL oves &V_CITY_SYLL ovice &W_CITY_SYLL oslav &X_CITY_SYLL oslavice &Y_CITY_SYLL oslaviÄky &Z_CITY_SYLL ůvka %0_CITY_SYLL Bab %1_CITY_SYLL Bor %2_CITY_SYLL Dobr %3_CITY_SYLL Dol %4_CITY_SYLL Host %5_CITY_SYLL Hrad %6_CITY_SYLL Chot %7_CITY_SYLL Kamen %8_CITY_SYLL Král %9_CITY_SYLL Rad %A_CITY_SYLL Slav %B_CITY_SYLL Str %C_CITY_SYLL TÅ™eb %D_CITY_SYLL BeÄ %E_CITY_SYLL BlÅ¡ %F_CITY_SYLL BÅ™ez %G_CITY_SYLL Čím %H_CITY_SYLL Drozd %I_CITY_SYLL Hal %J_CITY_SYLL Kost %K_CITY_SYLL Kudl %L_CITY_SYLL Kras %M_CITY_SYLL Les %N_CITY_SYLL Mohel %O_CITY_SYLL Mohyl %P_CITY_SYLL Mysl %Q_CITY_SYLL Olbram %R_CITY_SYLL OleÅ¡ %S_CITY_SYLL Příbraz %T_CITY_SYLL Rud %U_CITY_SYLL Val %V_CITY_SYLL Vedr %W_CITY_SYLL Vod %X_CITY_SYLL VÅ¡erub %Y_CITY_SYLL Žár %Z_CITY_SYLL DaleÄ 0center %s 0extern %s - %s planina 0suburb %s - Pod Kosířem 1center %s - StaromÄ›stská 1extern %s - %s okraj %s 1suburb %s - %s příkopy %s 2center %s - Centrum 2extern %s - %s okres %s 2suburb %s - %s sídliÅ¡tÄ› %s 3center %s - %s mÄ›sto 3extern %s - KÅ™ižovatka 3suburb %s - %s pÅ™edmÄ›stí %s 4center %s - %s námÄ›stí %s 4extern %s - Chaty 4suburb %s - %s ÄtvrÅ¥ %s 5center %s - hÅ™bitov 5extern %s - Rozcestí 5suburb %s - Nová Kolonie 6center %s - Hostinec 6extern %s - %s kraj %s 6suburb %s - %s Průmyslový park %s 7center %s - Å kola 7extern %s - %s lesy %s 7suburb %s - %s sady %s 8center %s - Obchodní dům 8extern %s - %s pole %s 8suburb %s - PoÅ¡ta 9center %s - Zahradní mÄ›sto 9extern %s - Hájovna 9suburb %s - Sokolovna Acenter %s - Achátová Aextern %s - %s polesí %s Asuburb %s - Kachní kámen Bcenter %s - Barvířská Bextern %s - Háje Bsuburb %s - K Borku Ccenter %s - BÄ›lidlo Cextern %s - Hluchov Csuburb %s - LuÄní Dcenter %s - Hedvábnická Dextern %s - K rokli Dsuburb %s - Malý val Ecenter %s - Hradební Eextern %s - Na Strouze Esuburb %s - Mezi Mlaty Fcenter %s - HrnÄířská Fextern %s - Na Blatech Fsuburb %s - Na Baterii Gcenter %s - Hůrka Gextern %s - U Brůdku Gsuburb %s - Na Hatích Hcenter %s - Kolářka Hextern %s - Hliňák Hsuburb %s - Na Láni Icenter %s - Křížový vrch Iextern %s - Na kopeÄku Isuburb %s - Na Obci Jcenter %s - Na hradbách Jextern %s - U Hložku Jsuburb %s - Na Písku Kcenter %s - Na Mlejnku Kextern %s - Na Holé pláni Ksuburb %s - U Průhonu Lcenter %s - Oskol Lextern %s - V Sadech Lsuburb %s - Na Å ancích Mcenter %s - Provaznická Mextern %s - Na skalách Msuburb %s - Na Valech Ncenter %s - Sedlářská Nextern %s - Na stráni Nsuburb %s - Na Výsluní Ocenter %s - Soukenická Oextern %s - Na Vyhlídce Osuburb %s - PíseÄná Pcenter %s - Å pitálská Pextern %s - Kozí vrch Psuburb %s - PekaÅ™ská Qcenter %s - U Slunců Qextern %s - Soumarská Qsuburb %s - Pod Hradbami Rcenter %s - Park Rextern %s - U dubu Rsuburb %s - Průhonek Scenter %s - Solný Trh Sextern %s - U palouku Ssuburb %s - Kovárna Tcenter %s - Å pejchar Textern %s - U studánky Tsuburb %s - U lip Ucenter %s - Velký val Uextern %s - VÄ›trná Usuburb %s - V Aleji Vcenter %s - Pod věží Vextern %s - Pastviny Vsuburb %s - V Hlinách Wcenter %s - Zákostelní Wextern %s - Zahájí Wsuburb %s - Vodní Xcenter %s - Zelinářská Xextern %s - TÅ™ešňovka Xsuburb %s - V pecích Ycenter %s - Ztracenka Yextern %s - LuÄní Ysuburb %s - Vystrkov Zcenter %s - Nekázanka Zextern %s - Újezd Zsuburb %s - Za Humny simutrans-124.3/simutrans/text/cz/000077500000000000000000000000001474050137200172005ustar00rootroot00000000000000simutrans-124.3/simutrans/text/cz/airtools.txt000066400000000000000000000151051474050137200215770ustar00rootroot00000000000000NápovÄ›da - letecká doprava

Letecká doprava

Panel stavba letiště obsahuje nástroje pro výstavbu letecké dopravní sítě - pojížděcí dráhy, ranveje, stání pro letadla, hangáru a dalších budov.

Nabídku s nástroji pro leteckou dopravu zobrazíte kliknutím na ikonu letadla v menu v horní Äásti hrací plochy.

Podržíte-li kurzor nad ikonou nástroje, (po té, co jste otevÅ™eli nabídlu pomocí kliknutí na symbol s letadlem) zobrazí se popisek obsahující název, náklady na výstavbu, v závorce mÄ›síÄní náklady na údržbu a další doplňující text. U ranveje a pojíždÄ›cí dráhy je to maximální rychlost, u stání pro letadla a terminálů je to kapacita.

Jestliže jste pÅ™i výbÄ›ru nové hry použili volbu zaÄít roku, pak se s postupem Äasu budou ve hÅ™e objevovat nové typy ranveje a letiÅ¡tních budov.

Postup, jak na stavbu jednoduchého letiště:
(i) Postavte ranvej.
(ii) PÅ™ipojte k ranveji pojíždÄ›cí dráhu. PojíždÄ›cí dráhu nepÅ™ipojujte ke koncům ranveje. Letadla by pak nemusela vzlétnout. PÅ™ipojte ji mezi druhé a pÅ™edposlední políÄko (vÄetnÄ›).
(iii) Na pojížděcí dráhu umístěte stání pro letadlo.
(iv) Postavte hangár, popřípadě další budovy podle vašich požadavků.

Menu stavba letiště obsahuje tyto nástroje (z leva do prava):

Pojížděcí dráha

Pojížděcí dráha umožňuje letadlům pohyb mezi hangárem, přistávací drahou a stáními pro letadla. Pojížděcí dráhu je možné postavit jen vodorovné ploše, stavba ve svahu není možná.

Pojížděcí dráhu postavíte stejným způsobem, jako silnici nebo železnici:
(i) Klikněte na ikonu s symbolem pojížděcí dráhy. (Kurzor se změní na pojížděcí dráhu.)
(ii) KliknÄ›te na políÄko, kde má pojíždÄ›cí dráha zaÄínat. (Kurzor se zmÄ›ní na buldozer a v pravém dolním rohu na stavové liÅ¡tÄ› se zobrazí rozdíl souÅ™adnic mezi takto zvoleným poÄátkem a aktuální polohou kurzoru.)
(iii) KliknÄ›te na pole, kde má pojíždÄ›cí dráha konÄit.

UPOZORNÄšNÃ: Jestliže je pojíždÄ›cí dráha pÅ™ipojena ke koncům ranveje, nebo se vyskytuje na poli ve smÄ›ru pÅ™istávání nebo startu, letadla mohou odmítat vzlétat nebo pÅ™istávat.

Tip: K odstranÄ›ní jednotlivých Äástí pojíždÄ›cí plochy použijte tlaÄítko Odstranit nebo Klávesovou zkratku [z] (zpÄ›t). Oboje vám nenahradí vynaložené prostÅ™edky ale pÅ™i použití klávesové zkratky [z] nepÅ™ijdete peníze za odstranÄ›ní.

Ranvej

Ranvej slouží letadlům pro přistání a vzlet. Ranvej je možné postavit jen na vodorovné ploše, nelze ji postavit na svahu. Ranveje se mohou navzájem křížit.

Ranvej musí být rovná. Ranvej lze postavit ve směrech sever/jih a východ/západ. Diagonální ranveje nejsou povoleny.

Stavba ranveje:
(i) Klikněte na nástroj. (Kurzor se změní na ranvej).
(ii) KliknÄ›te na poÄáteÄní pole. (Kurzor se zmÄ›ní na buldozer.)
(iii) KliknÄ›te na koncové políÄko.

Tip: Konce ranveje nechte volné, nepřipojujte k nim pojížděcí dráhu. Letadla by pak nemusela vzlétat nebo přistávat.

Odstranit pojížděcí dráhu

Nástroj odstraňuje úseky pojíždÄ›cí dráhy nebo ranveje, pokud na ní nejsou přítomna žádná letadla. Peníze za odstranÄ›ní se také úÄtují do položky výstavba.

Odstranění ranveje nebo pojížděcí plochy:
(i) KliknÄ›te na nástroj (Kurzor se zmÄ›ní na Äervený křížek.)
(ii) KliknÄ›te na políÄko, odkud se má zaÄít odstraňovat a jeÅ¡tÄ› jednou kliknÄ›te na políÄko, kde se má skonÄit s odstraňováním.

Tip: Dejte pozor, jesli se mezi na cestÄ› mezi obÄ›ma políÄky nenalézá znaÄka zakazující vjezd v jednom ze smÄ›rů. Nástroj pro odstraňování tento smÄ›r následuje. Mohlo by se vám stát že omylem odstraníte jinou než zamýšlenou Äást.

Hangár

Hangár je budova v níž lze nakupovat, pÅ™echovávat a prodávat letadla a vzducholodÄ›, stejnÄ› jako vlaky v depu. Hangár lze postavit na konci pojíždÄ›cí dráhy. Každý hangár má také mÄ›síÄní náklady na údržbu, proto nestavte více hangárů, než potÅ™ebujete.

Stavba hangáru:
(i) Klikněte na nástroj. (Kurzor se změní na hangár.)
(ii) Klikněte na konec pojížděcí dráhy.

Tip: Hangár odstraníte pomocí tlaÄítka Odstranit. Hangár musí být prázdný, jinak nejde odstranit.

Stání pro letadlo

Stání pro letadlo je místo, kde do letadel nastupují a z letadel vystupují cestující nebo je nakládáná a vykládána pošta nebo náklad.
Pokud není stání pro letadlo postaveno vedle jiného stání nebo letištní budovy, vytvoří novou zastávku
Stání pro letadlo se staví na konec pojížděcí dráhy, má náklady na údržbu a spádové území.

Stavba stání pro letadla:
(i) Klikněte na nástroj z nabídky. Kurzor se změní na stání pro letadlo a zvýrazní se spádová oblast pole pod kurzorem.
(ii) Klikněne na konec pojížděcí dráhy.

Tip: Velikost spádové oblasti můžete změnit při vytváření nové hry v nastavení (záložka Spojení, volba station_coverage)
Stání pro letadlo odstraníte tlaÄítkem Odstranit.
Klávesou [v] Zobrazíte/skryjete spádové území.
Letadla mohou přistávat, pouze pokud je na letišti dostatek volných stání pro letadla. Jinak krouží nad letištěm a spotřebovávají palivo (a peníze).

Letištní budova

LetiÅ¡tní budova zvyÅ¡uje kapacitu letiÅ¡tÄ› stejným způsobem, jako nádražní budova kapacitu železniÄní stanice.

Stavba budovy:
(i) Klikněte na ikonu požadovaného rozšíření. (Kurzor se změní na ikonu obsahující rozšíření.)
(ii) KliknÄ›te na požadovanou pozici vedle stávající zastávky/stání pro letadlo. Budova se od teÄ považuje za souÄást letiÅ¡tÄ›.

Tip: Budovu lze odstanit pomocí ikony Odstranit.
Stiskem tlaÄítka [v] na klávesnici zobrazíte, respektive skryjete spádové území letiÅ¡tÄ›.

Nápověda odpovídá verzi 111.4, poslední úprava 21.10.2012.

simutrans-124.3/simutrans/text/cz/baum_build.txt000066400000000000000000000023041474050137200220430ustar00rootroot00000000000000Nápověda - zasadit stromy

Zasadit stromy

Dialog vám umožňuje hrát si na zahradníka a sázet stromy.

Dialog je dostupný, pokud jste se pÅ™epli na hráÄe VeÅ™ejné služby.

Okno dialogu je rozdÄ›leno na ÄtyÅ™i Äásti:
V levém horním rohu jsou dva panely umožňující vybírat mezi dostupnými druhy stromů. Můžete vybírat stromy podle názvu nebo podle ID.

Pokud zvolíte nějaký strom, pak se v levém dolním rohu zobrazí jeho obrázek.
V pravém horním rohu jsou zobrazeny volby.

Volba Ignorovat podnebí umožňuje sázet stromy bez ohledu na podnebný pás. Pokud ji povolíte, můžete sázet třeba tropické palmy do sněhu.

Volba Náhodné stáří umožňuje sázet stromy různé velikosti. Pokud není povolena, sázíte jen malé stromeÄky.

Pod volbami jsou informace o daném stromu: název, podnebný pás nebo podnebné pásy a kdo daný stromek nakreslil.

Tip: Celý les zasadíte pomocí tlaÄítka Zasadit les z menu editace mapy.

Nápověda odpovídá verzi 112.1, poslední úprava 31.12.2012.

simutrans-124.3/simutrans/text/cz/bridges.txt000066400000000000000000000056271474050137200213720ustar00rootroot00000000000000Nápověda - stavba mostů

Stavba mostů

Mostem lze překlenout údolí nebo jiná překážka.

Každý most má urÄenu maximální možnou délku. Pro pÅ™emostÄ›ní delších úseků nezbyde než v nabídce hledat jiný, nebo si pomoci ostrůvky a celkovou vzdálenost rozdÄ›lit na více Äástí. Mosty lze stavÄ›t i pÅ™es hluboká údolí s nerovným terénem, omezení je kladeno jen na poÄáteÄní a koncové pole. Most musí zaÄínat a konÄit na vodorovné ploÅ¡e, svahu Å¡ikmém ve smÄ›ru mostu nebo na umÄ›lé vyvýšeninÄ›. ZaÄátek a konec mostu nemusí být ve stejné výšce, může mezi nimi být rozdíl jedné úrovnÄ›. Mosty lze stavÄ›t jen ve smÄ›ru hranic políÄek, tj. nelze je (zatím) stavÄ›t diagonálnÄ›. Existuje vÅ¡ak druh železniÄní trati, který pÅ™ipomíná most, neboÅ¥ je nad terénem. Tuto traÅ¥ lze stavÄ›t i diagonálnÄ›.

VÅ¡echny mosty, aÅ¥ železniÄní, silniÄní, pro lodní dopravu, nebo pro dráty vysokého napÄ›tí se staví stejným způsobem. SilniÄní most má jednu výjimku: lze na nÄ›j navíc pÅ™idat i koleje pro tramvaj.

Stavíme most

Následující postup lze uplatnit pro všechny typy mostů, pokud je zde psáno silnice, můžete si místo ní dosadit železnici, nebo jiný druh dopravy mající mosty:
(i) Postavte silnici k obÄ›ma pÅ™edpokládaným koncům mostu, pÅ™iÄemž silnice bude i a prvním a posledním políÄku budoucího mostu.
(ii) Klikněte na symbol mostu. Zvolte si ten který vám bude svými parametry nejvíce vyhovovat.
(iii) KliknÄ›te na pole se zamýšleným poÄátkem mostu a tlaÄítko držte stisknuté.
(iv) NajeÄte kurzorem myÅ¡i nad políÄko, kde má most konÄit, a pusÅ¥te tlaÄítko. Most je hotov.

Existuje také alternativní postup. Musíte vÅ¡ak mít pÅ™edem správnÄ› pÅ™ichystané oba konce silnice, jinak se může stát, že utratíte peníze za dlouhý most, který nechcete. Místo kroků (iii) a (iv) kliknÄ›te na zaÄátek zamýšleného mostu a pusÅ¥te tlaÄítko. Most se vystaví sám až ke kusu silnice na druhé stranÄ›.

ÄŒastu chybou pÅ™i stavbÄ› mostu je, že není na koncích pÅ™ipojen k silnici (nebo železnici). PÅ™etáhnÄ›te silnici (železnici) i na poÄáteÄní a koncové pole mostovky, jinak pÅ™es nÄ›j auta (vlaky) nebudou jezdit.

Tip: Někdy se most nevyplatí stavět. Mosty mají obecně vyšší náklady na údržbu než je u běžné silnice (trati, elektrického vedení, ..). Podívejte, jestli se u menších terénních nerovností nevyplatí prohlubeň zasypat.

Odstranění mostu

KliknÄ›te na tlaÄítko Odstranit a pak kliknÄ›te na zaÄátek nebo na konec mostovky.

->Nápověda pro stavbu silnic
->Nápověda pro stavbu železnic

->Informace o překladu

simutrans-124.3/simutrans/text/cz/citybuilding_build.txt000066400000000000000000000042021474050137200236040ustar00rootroot00000000000000Nápověda - přidání městské budovy

Přidat městskou budovu

Dialog umožňuje ruÄnÄ› umísÅ¥ovat mÄ›stké budovy.

Okno je rozdÄ›leno do ÄtyÅ™ Äástí.
V levém horním rohu je seznam budov.
V levém dolním rohu se zobrazí obrázek zvolené budovy.
V pravém horním rohu jsou tlaÄítka pro zapnutí/vypnutí jednotlivých filtrů pro množinu budov.
Pod tlaÄítky se nachází Äást obsahující podrobné informace o daném domu: název, doplňující text, údaje o množství cestujících a poÅ¡ty, období, ve kterém je budova dostupná, a jméno nebo pÅ™ezdívka autora.

Seznam budov

Seznam odsahuje všechny dostupné městské budovy.
Budovy je možné Å™adit podle jména nebo podle identifikátoru. VýbÄ›r budov lze omezit na urÄitou skupinu pomocí tlaÄítek nacházejících se v pravém horním rohu.

Jména a identifikátory mají barvu v závislosti na typu budovy:
Modrá barva je pro obytné budovy.
Zelená barva oznaÄuje obchody a kanceláře.
ÄŒerná barva je urÄena pro průmyslové budovy.

TlaÄítka voleb

Ignorovat podnebí: TlaÄítko ruší omezení budovy na přísluÅ¡ný podnebný pás, budovu pak můžete umístit kamkoliv.
ZaÄít roku: TlaÄítko zapíná omezení výbÄ›ru budov podle data. Pokud je volba zapnuta, neuvidíte budovy, které se již nestaví, protože jsou zastaralé. Také neuvidíte budovy, které bude možno postavit v budocnosti.
Zobrazit zastaralé: Povolí zobrazit zastaralé typy budov.
Obytný dům: Zobrazí obytné budovy.
Obchody a kanceláře: Zobrazí obchody a kanceláře.
Továrna: Zobrazí továrny.
Předchozí volby tři lze libovolně kombinovat: například nechat zobrazit jen obytné budovy a kanceláře.
Rotace: Má-li budova obrázky pohledů z více úhlů, potom pomocí šipek můžete měnit náhled budovy zobrazený v levém dolním rohu.

Nápověda odpovídá verzi 112.1, poslední úprava 2.1.2013.

simutrans-124.3/simutrans/text/cz/citylist_filter.txt000066400000000000000000000037161474050137200231610ustar00rootroot00000000000000Nápověda - seznam měst

Seznam měst

Seznam mÄ›st obsahuje podrobné údaje statistické údaje o mÄ›stech, poÄtu obyvatel, budov, pÅ™epravnených cestující, poÅ¡tÄ› apod.

Seznam měst otevřeme kliknutím na ikonu Seznamy následovným kliknutím na ikonu Seznam měst. Seznam měst lze též otevřít klávesou [T].

Číslo za textem Celkem obyvatel sdÄ›luje celkový poÄet obyvatel ve hÅ™e. Je to souÄet obyvatel vÅ¡ech obcí. Číslo v závorkách znázorňuje růst vÅ¡ech mÄ›st.

Vlevo pod textem Å™adit podle se nachází dvÄ› tlaÄítka ovlivňující Å™azení. První tlaÄítko umožňuje seÅ™adit mÄ›sta podle názvu (Jméno), poÄtu obyvatel (Obyvatelé) nebo přírůstku obyvatel (Růst mÄ›sta). Druhým tlaÄítkem pÅ™epínáme mezi vzestupným a sestupným Å™azením.

Kliknutím na název města zobrazíte okno s podrobnými informacemi o daném městě.

Kliknutím na trojúhelníkovité tlaÄítko pÅ™ed názvem mÄ›sta se pÅ™emístíte na pozici daného mÄ›sta.

V seznamu mÄ›st jsou tyto položky: název mÄ›sta, poÄet obyvatel a v kulatých závorkách se nachází přírůstek obyvatel.

Název města můžete změnit v dialogu města. Dialog města otevřete kliknutím na název města nebo na příslušnou radnici.

Růst mÄ›sta je zde poÄítán jako vážený aritmetický průmÄ›r přírůstku obyvatel mÄ›sta za poslední mÄ›síce s vahami 5,4 a 1 zaokrouhlený na desetiny.

TlaÄítkem Graf zobrazíte graf a přísluÅ¡ná tlaÄítka umožňující zobrazit v grafu odpovídající položky. Máte na výbÄ›r mezi grafem za posledních 12 mÄ›síců nebo posledních 12 let.

Nápověda odpovídá verzi 112.1, poslední úprava 2.1.2013.

simutrans-124.3/simutrans/text/cz/citywindow.txt000066400000000000000000000120221474050137200221360ustar00rootroot00000000000000Nápověda - dialog města

Dialog města

Dialog mÄ›sta zobrazuje statistické údaje o zvoleném mÄ›stu nebo vesnici, dvÄ› mapy a graf zobrazující veliÄiny v závislosti na přísluÅ¡ných tlaÄítkách. Umožňuje také zmÄ›nit název. Dialog lze otevřít kliknutím na radnici nebo na název v seznamu mÄ›st.

Dialog obsahuje následující položky:

První položkou je název města nebo vesnice. Je zobrazen na titulku okna můžete jej nalét v Seznamu měst. Název města je použit při vytváření jmen stanic a zastávek uvnitř hranic města.
Název mÄ›sta zmÄ›níte kliknutím do pole s názvem a pÅ™epsáním na jiný název. Názvy mÄ›st jsou naÄítány ze soubory text/citylist_cz.txt z adresáře přísluÅ¡ného paku. Zachováte-li kódování, máte možnost si do seznamu doplnit své oblíbené mÄ›sto.

Tip: Pomocí klávesy [!] lze přepnout způsob zobrazení názvu města nad radnicí.

Velikostukazuje poÄet obyvatel. V závorkách je přírůstek obyvatelstva. (Je to průmÄ›rný přírůstek obyvatel za poslední tÅ™i mÄ›síce, pÅ™iÄemž každý mÄ›síc má jinou váhu.)

Číslice pÅ™ed nápisem Budov ukazuje poÄet budov daného mÄ›sta.

Dva páry Äísel o řádek níže jsou mapové souÅ™adnice hranic mÄ›sta. První souÅ™adnice oznaÄuje levý horní roh, druhá pravý dolní. SouÅ™adnice se mÄ›ní s růstem mÄ›sta a mohou se pÅ™ekrývat.

Čísla za nápisy nezmÄ›stnaných a bezdomovců oznaÄují poÄet obyvatel bez zamÄ›stnání a bydliÅ¡tÄ›. Tato Äísla ovlivňují, jaké budovy (obytné/odchodní/průmyslové) se budou stavÄ›t.

Volbou Dovolit růst města povolujeme nebo zakazujeme růst města. Když volba není povolena, město neporoste.

Mapy v dialogu mÄ›sta ukazují cílová místa pro dopravu cestujících a poÅ¡ty z tohoto mÄ›sta. Mapa v pravo ukazuje data pro aktuální mÄ›síc, na mapÄ› vlevo jsou data z minulého mÄ›síce. Cílová místa, jednotlivé teÄky na mapÄ›, jsou vybarvena následovnÄ›:

- žlutá teÄka: Cesta k cíli existuje a nástupní stanice/zastávka není pÅ™eplnÄ›ná (usmÄ›vavý smajlík v dialogu zastávky).
- oranžová teÄka: K cíli neexistuje cesta.
- Äervená teÄka: K cíli existuje cesta, ale nástupní zastávka je pÅ™eplnÄ›ná (neveselý smajlík v dialogu zastávky).

Pod mapami se nachází graf ukazující statistiku pro dané mÄ›sto. Na vodorovné ose je zobrazen Äas, na svislé ose množství. Máte na výbÄ›r mezi zobrazením po mÄ›sících nebo po letech.
Roky: zobrazí roÄní hodnoty za 12 let
MÄ›síce: zobrazí mÄ›síÄní hodnoty za posledních 12 mÄ›síců

Kliknutím na tlaÄítka pod grafem zobrazíte nebo skryjete odpovídající kÅ™ivku grafu. Barva kÅ™ivky odpovídá barvÄ› tlaÄítka:

Obyvatelé: PoÄet obyvatel žijících ve mÄ›stÄ›.
Růst mÄ›sta: ZmÄ›na poÄtu obyvatel.
Budovy: PoÄet budov ve mÄ›stÄ›.
Osobní auta: Kolik bylo generováno osobních aut.
Přepraveno: Kolik cestujících vstupilo do dopravní sítě (veselý smajlík) v dialogu stanice/zastávky
Cestující: Celkový poÄet cestujících vygenerovaných v daném mÄ›stÄ›.
PoÅ¡ta Äeká: PoÅ¡ta, která vstoupila do dopravní sítÄ›.
Pošta: Celkové množství pošty vygenerované v daném městě.
Přijato: Kolikráte bylo zjištěno, že továrna ve městě má na skladě zboží, které odebírá.
Zboží: PoÄet kontrol, pÅ™i kterých bylo zjišťováno, zda-li má továrna ve mÄ›stÄ› zboží, které odebírá.

Tip: Nastavení týkající se měst může být měněno v souborech simuconf.tab a cityrules.tab.

Růst mÄ›sta je podporován pÅ™epravou cestujících a poÅ¡ty a dodáváním zboží do továren uvnitÅ™ hranic mÄ›sta. Růst mÄ›sta zahrnuje stavbu nových silnic. MÄ›sto také pÅ™ebírá stávající silnice v blízkosti novÄ› postavených budov do vlastnictví, tj. hráÄe nazývaného VeÅ™ejné služby.

Tip: Zamýšlíte-li hrát dlouho a nechat mÄ›sto vyrůst, vyplatí se postavit mÄ›stu základní síť přímých rovných ulic, nÄ›kdy i o šíři 2 polí. Až se mÄ›sto rozroste, po rovných ulicích budou jezdit autobusy mnohem rychleji, než v kÅ™ivolakých uliÄkách. Na Å¡irokých ulicích (o dvou polích) snadno postavíte obousmÄ›rnou tramvajovou traÅ¥. Navíc nepotÅ™ebujete bourat budovy a tak nepÅ™icházíte o obyvatele. Tyto budoucí ulice stavte tou nejlevnÄ›jší silnicí s co nejmenšími náklady na údržbu. MÄ›sto si je samo vylepší, až je bude potÅ™ebovat.

Nápověda odpovídá verzi 112.1, poslední úprava 2.1.2013.

simutrans-124.3/simutrans/text/cz/climates.txt000066400000000000000000000047731474050137200215550ustar00rootroot00000000000000Nápověda - nastavení podnebí

Nastavení podnebí

Dialog Nastavení podnebí umožňuje nastavit terén a podnebné pásy. Dialog otevÅ™ete kliknutím na tlaÄítko Nastavení podnebí v dialogu s názvem VytvoÅ™it novou mapu.

Hodnoty upravíte kliknutím na Å¡ipku vedle políÄka.

Nastavení terénu

úroveň vody - Nastavuje úroveň vody na mapÄ›. Vyšší Äíslo znamená více vodních ploch a ménÄ› pevné zemÄ›.

Výchozí hodnota -2

Nastavení výšky hor urÄuje maximální výšku terénu.

Výchozí hodnota 160

Zaoblení mapy - UrÄuje Älenitost terénu. Čím vyšší Äíslo, tím ÄlenitÄ›jší terén s mnoha prohlubnÄ›mi a malými vyvýšeninami.

Nastavení sněhu

Obsahuje nastavení týkající se sněžné Äáry. Sněžná Äára je zde výška, od které se objevuje na mapÄ› sníh.

Sněžná Äára v létÄ› - výška sněžné Äáry v létÄ›.

Sněžná Äára v zimÄ› - výška sněžné Äáry v zimÄ›.

Nastavení podnebí

Umožňuje nastavit na mapě podnebné pásy.
Hodnota vedle jednotlivých podnebných pásů urÄuje výšku, ve které se daný podnebný pás objeví. Podnebný pás vypnete nastavením hodnoty na 0 (nulu).

Poušť - Velmi málo srážek, vysoké rozdíly v teplotách, málo stromů.

Tropy - Typické pro území okolo rovníku. Relativně stálá vysoká teplota.

StÅ™edomoří - MírnÄ› promÄ›nlivé teplé poÄasí.

Mírné - Podnebný pás se střídáním vÅ¡ech ÄtyÅ™ roÄních období.

Tundra - Nízké teploty, hranice polárních ÄepiÄek.

Skaliska - Suché klima, chladné zimy.

Ostatní nastavení

Bez stromů - Kliknutím na tlaÄítko zamezíte vytváření stromů. Vykreslování stromů spotÅ™ebovává strojový Äas. Tuto vylbu použijte, máte-li pomalejší procesor nebo málo operaÄní pamÄ›ti.

PoÄet Å™ek - Nastavuje maximální poÄet Å™ek, které mohou být vytvoÅ™eny pÅ™i tvorbÄ› nové mapy.

Min. délka Å™ek - Nastavuje minimální délku Å™ek (poÄet políÄek).

Max délka Å™ek - Nastavuje maximální délku Å™ek (poÄet políÄek).

Nápověda odpovídá verzi 112.1, poslední úprava 4.1.2013.

simutrans-124.3/simutrans/text/cz/color.txt000066400000000000000000000005421474050137200210600ustar00rootroot00000000000000Nápověda - výběr barev

Výběr barev

Zde si můžete vybrat barvu Vaší spoleÄnosti. Je to barva, kterou bude mít Váš majetek, jako jsou vlaky, nákladní auta, depa, stanice atd.
Ovšem není to pravidlem, některý majetek tuto barvu mít nebude.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/convoi.txt000066400000000000000000000024511474050137200212400ustar00rootroot00000000000000Nápověda - seznam vozidel

Seznam vozidel

Seznam vozidel obsahuje vÅ¡echna vozidla daného hráÄe. OtevÅ™ete jej z nabídky seznamy.

Seznam nabízí tyto možnosti:

1.) Řazení:
Postupným klikáním na první pÅ™epínací tlaÄítko mÄ›níte kritéria, podle kterých bude seznam Å™azen: jméno, příjem, typ nebo interní ID.
Vedlejším tlaÄítkem nastavujete, zda má být Å™azen sestupnÄ› nebo vzestupnÄ›.

2.) Filtr:
Kliknutím na tÅ™etí tlaÄítko aktivujete, nebo deaktivujete filtr.
Možnosti tohoto filtru můžete mÄ›nit po kliknutí na tlaÄítko nastavení.

Barva textu s názvem vozidla poskytuje další informace:
- Äerná - VÅ¡e je vpořádku
- Äervená - Provoz soupravy je prodÄ›leÄný.
- bílá - Souprava je v depu.
- žlutá - Od zaÄátku roku stojí ve stanice a Äeká na náklad.
- oranžová - Zaseklé v dopravní zácpě nebo nemůže najít cestu k cíli.

->Nápověda pro filtr

->Informace o překladu

Nápověda odpovídá verzi 112.1, poslední úprava 21.1.2013.

simutrans-124.3/simutrans/text/cz/convoi_filter.txt000066400000000000000000000021751474050137200226100ustar00rootroot00000000000000Nápověda - filtr seznamu vozidel

Filtr seznamu vozidel

Filtr nabízí tyto možnosti:

1.) Filtrovat jméno:
V seznamu budou zobrazena pouze vozidla, která se jmenují podle zadání.

2.) Filtrovat typ:
V seznamu budou zobrazena pouze vozidla zvoleného typu.

3.) Speciální filtrování:
V seznamu budou zobrazena pouze vozidla, která nemají příjem, nemají definován jízdní plán, nemouhou nalézt trasu dle jízdního plánu, jsou v depu nebo nemají přiřazenou žádnou linku.

4.) Podle přepravovaného zboží:
V seznamu budou zobrazena pouze vozidla, která pÅ™epravují zvolené komodity. TlaÄítko vÅ¡e vybere vÅ¡echny komodity, tlaÄítko nic naopak vÅ¡echny odvybere. TlaÄítkem inv obrátíte aktuální výbÄ›r.

->Nápověda pro seznam vozidel

->Informace o překladu

Nápověda odpovídá verzi 112.1, poslední úprava 4.1.2012.

simutrans-124.3/simutrans/text/cz/convoidetail.txt000066400000000000000000000041001474050137200224140ustar00rootroot00000000000000Nápověda - detaily soupravy

Detaily soupravy

Dialog detaily soupravy poskytuje informace o soupravÄ›/konvoji.

Dialog otevÅ™ete kliknutím na tlaÄítko Detaily v dialogu s informacemi o soupravÄ›.

Tip: Jestliže nejsou všechny položky viditelné změnte velikost okna myší.

Informace zobrazené v levém horním rohu zahrnují:
Výkon soupravy (souÄet výkonu vÅ¡ech vozidel v soupravÄ›).
Kilometrovník ukazuje poÄet ujetých kilometrů za celou dobu životnosti soupravy.
ZastavÄ›ná plocha je poÄet políÄek potÅ™ebných ke správnému naložení/vyložení celé soupravy.
Cena za prodej je množství peněz získané při prodeji soupravy.
Nejvyšší možná rychlost je nejvyšší rychlost, jaké může souprava dosáhnout, aniž by pÅ™ekroÄila nejvyšší rychlost kteréhokoliv z vozidel.

UPOZORNÄšNÃ: PÅ™i kliknutí na tlaÄítko Prodávat je celá souprava okamžitÄ› prodána. Žádná další potvrzení není požadováno.

Detaily vozitel v soupravÄ›

V seznamu jsou ukaždého z vozidel zobrazeny následující iformace:
- obrázek vozidla je stejný obrázek, jaký můžete vidět v depu).
- název vozidla je název, pod jakým jste vozidlo kupovali v depu.
- Vyrobeno ukazuje měsíc a rok výroby.
- Cena za prodej jsou peníze získané okamžitým prodejem.
- Výkon je výkon jednotlivých vozidel.
- PÅ™evod je Äíslo, kterým se násobí výkon.
- Okamžitý koeficient tÅ™ení ukazuje jak moc jsou vozidla brždÄ›na. PÅ™i průjezdu zatáÄkami a pÅ™i stoupání je vyšší, než pÅ™i jízdÄ› po rovinÄ›.
- Max. zisk je maximální možný výnos z typu zboží naloženého v tomto vozidle
- naložené položky vÄetnÄ› množství.

Nápověda odpovídá verzi 112.1, poslední úprava 21.1.2013.

simutrans-124.3/simutrans/text/cz/convoiinfo.txt000066400000000000000000000141751474050137200221220ustar00rootroot00000000000000Nápověda - informace o soupravě

Informace o soupravÄ›

Dialog informace o soupravÄ› poskytuje údaje o soupravÄ›/konvoji a pÅ™epravovaném nákladu, obsahuje tlaÄítka sloužící k ovládání nebo sledování konvoje a zobrazuje náhled.

Soupravou/konvojem je myšleno vozidlo nebo skupina vozidel spřažených v jeden celek. Konvoj se skládá z aspoň jednoho vozidla opatřeného pohonem (motorizované jednotky) a několika tažených vozidel. Konvojem je například vlak, auto s přívěsem nebo autobus.

Dialog otevÅ™ete kliknutím levým tlaÄítkem myÅ¡i na vozidlo. Také jej lze zobrazit ze seznamu vozidel nebo ze seznamu linek.

Konvoje se sestavují a kupují v depu, které odpovídá příslušnému druhu přepravy.

Poznámka: PoÄet vozidel v konvoji je omezen. Jeden konvoj může osahovat maximálnÄ› 24 železniÄních vozidel, u silniÄní dopravy jsou to 4 vozidla.

V titulku okna je zobrazen jedineÄný identifikátor a jméno konvoje. Horní Äást dialogu informace o soupravÄ› obsahuje tyto údaje:

vnitřní ID: ID je identifikátor přiřazený při sestavení konvoje v depu.

název: Pole umožňuje zmÄ›nu názvu. Jako výchozí jméno je použito oznaÄení prvního vozidla zakoupeného nebo sestaveného v depu.

rychlost: Rychlost v km/h, jakou vozidlo právÄ› jede. V závorce je maximální dovolená rychlost (maximální rychlost nejpomalejšího vozidla). Zelená Äára je grafické procentuální znázornÄ›ní aktuální rychlosti.

příjem: Jsou peníze vydÄ›lané provozem konvoje (příjmy po odeÄtení provozních nákladů) v aktuálním kalendářním roce. V závorce jsou provozní náklady na 1km.

hmotnost: souÄet hmotnosti vozidla a hmotnosti nákladu, v závorkách je hmotnost nákladu (v metrických tunách). Zelená Äára ukazuje aktuální obsazenost, žlutá obsazenost požadovanou podle nastavení v jízdním řádu.

místo urÄení: Ukazuje název příští zastávky nebo bodu na cestÄ› v jízdním řádu konvoje. Zelený progress-bar ukazuje, kolik zbývá cesty do dalšího bodu.

obsluha linky: Linka, ke které je konvoj pÅ™iÅ™azen. TlaÄítko na zaÄátku řádku zobrazí správu linek. (Je dostupné pouze u vozidel pÅ™iÅ™azených k lince.)

náhled: Kliknutím na náhled se přemístíte na pozici konvoje.

Tip: K nastavení nebo zmÄ›nÄ› Äekání pro vÅ¡echna vozidla dané linky použijte dialog správa linek. Ke zmÄ›nÄ› jízdního řádu jen u tohoto vozidla použijte tlaÄítko jízdní řád. Používejte linky, je to pÅ™ehlednÄ›jší a jednodušší na správu.

tlaÄítka uprostÅ™ed

jízdní řád: Kliknutí otevÅ™e okno s nastavením jízdního řádu. Zde nastavíte délku Äekání a jak moc musí být vozidlo naloženo.

do depa: PoÅ¡le konvoj do nejbližšího vhodného depa. PÅ™i vjezdu do depa pÅ™ijdete o vÅ¡echny pÅ™evážené položky. Peníze za pÅ™epravu jsou poÄítány jako pÅ™i pÅ™epravÄ› do místa s depem.
V depu si konvoj zachová svůj jízdní řád a přiřazenou linku.

nenakládat: Zakáže do vozidla nakládat, zboží je v zastávkách/stanicích pouze vykládáno. TlaÄítko je výhodné použít, když chcete například poslat osobní vlak do depa (a pÅ™idat k nÄ›mu nÄ›kolik vagonů) a nechcete, aby vám ze stanice zmizeli cestující.

následuj: Zapne nebo vypne sledování pohybů vozidla.
Sledování vypnete opÄ›tovným kliknutím na tlaÄítko nebo kliknutím na mapu.

graf: Kliknutím na tlaÄítko zobrazíte/skryjete graf.
Graf obsahuje údaje za posledních 12 mÄ›síců. Jednotlivé kÅ™ivky zobrazíte kliknutím na přísluÅ¡né tlaÄítko pod grafem. Barva Äáry v grafu odpovídá barvÄ› tlaÄítka pod grafem.
- Volná kapacita nevyužité místo v konvoji.
- Přepraveno množství zboží, cestujících a pošty, které bylo přepraveno.
- Příjem peníze zaplacené za přepravu.
- Provoz vozidel náklady na provoz vozidel.
- Zisk zisk z přepravy ( příjem minus provoz).
- Délka/MÄ›síc poÄet ujetých kilometrů v daném mÄ›síci.
- Nejvyšší rychlost Teoretická rychlost soupravy, pokud vezmeme v úvahu rychlostní limity vozidel a cesty/kolejí. Je to minimum z maximální rychlosti komunikace a maximální rychlosti soupravy. Používá se k výpoÄtu bonusu za rychlost pÅ™epravy.

Detaily: Otevře dialog detaily soupravy obsahující podrobné informace o jednotlivých vozidlech. Umožňuje také prodat celou soupravu.

Řadit zboží dle

Obsahuje informace o přepravovaném množství, kapacitě konvoje, typ položek, cílové stanici a první přestupní stanici.
TlaÄítko pÅ™epíná mezi tÄ›mito způsoby Å™azení:
- cíl: Setřídí *) převážené položky podle názvu cílové stanice.
- přes: Setřídí *) převážené položky podle jména první přestupní stanice.
- pÅ™es+poÄet: Setřídí pÅ™evážené položky podle množství směřujícího do první pÅ™estupní stanice.
- poÄet: Setřídí položky podle poÄtu.

*) Pozn: Položky jsou Å™azeny podle ASCII-kódu, tedy v poÅ™adí: Äísla, velká písmena bez diakritiky, malá píslena bez diakritiky. Znaky s diakritikou nejsou v ASCII tabulce ale jen v jejích rozšířeních (napÅ™. latin2) a mají pÅ™iÅ™azena vyšší Äísla. Proto jsou pÅ™i Å™azení bude Ostrava pÅ™ed ÄŒeskými BudÄ›jovicemi.

Nápověda odpovídá verzi 112.1, poslední úprava 17.2.2012.

simutrans-124.3/simutrans/text/cz/curiosity_build.txt000066400000000000000000000047251474050137200231620ustar00rootroot00000000000000Nápověda - přidat kuriozitu.

Stavba památek

Dialog slouží k ruÄnímu pÅ™idání památek do krajiny. Je rozdÄ›len na ÄtyÅ™i Äásti.

V levém horním rohu je seznam dostupných budov.
Vlevo dole je zobrazen obrázek vybrané budovy.
Vpravo nahoÅ™e jsou tlaÄítka sloužící k rozšíření nebo zúžení výbÄ›ru dostupných památek.
Vpravo dole jsou zobrazeny podrobnosti o vybrané budově.

Seznam budov

V seznamu jsou vypsány vÅ¡echny zvláštní budovy a památky, které jsou dostupné podle kritérií nastavených na pravé stanÄ› dialogu (mÄ›stské památky, venkovské památky, památníky). ObÄ› záložky obsahují stejné památky, jen jinak oznaÄené.
- Podle jména: Záložka obsahuje budovy setříděné podle názvu uvedeného v překladu. Pokud není překlad dostupný, použije se identifikátor.
- Podle ID: Pod touto záložkou jsou budovy řazené podle vnitřního identifikátoru pro daný objekt.

Budovy jsou rozlišeny pomocí rozdílné barvy textu:
- modrá barva: památky, které lze postavit jen ve městě
- zelená barva: památky, které lze postavit jen na venkově
- Äerná barva: památníky; na každé mapÄ› může být jen jeden

Volby

- ignorovat podnebí: Každá památka má omezení, ve kterých podnebných pásech může být postavena. Tímto tlaÄítkem lze omezení vypnout.
- ZaÄít roku: Seznam bude obsahovat pouze budovy které jsou již v daném roce dostuné. V seznamu nebudou budovy, které se objeví v příštích letech.
- Zobrazit zastaralá: V seznamu se zobrazí i budovy v dané době považované již za zastaralé.
- Městské památky: Zobrazí v seznamu památky, které lze postavit ve městě.
- Venkovské památky: Zobrazí v seznamu památky, které lze postavit mimo území města.
- Památník: Zobrazí v seznamu památníky (budovy, které mohou být na mapě jen jedenkrát).
- rotace: Jestliže daná budova umožňuje pohled z více úhlů, můžete pomocí šipek mezi nimi přepínat. Tím se bude měnit obrázek v levém dolním rohu. Jestliže je zobrazen nápis náhodně, použije se náhodně vybraný pohled.

Nápověda odpovídá verzi 112.1, poslední úprava 5.1.2012.

simutrans-124.3/simutrans/text/cz/curiositylist_filter.txt000066400000000000000000000036451474050137200242440ustar00rootroot00000000000000Nápověda - turistické cíle

Turistické cíle

Seznam turistických cílů obsahuje informace o všech památkách. Památky jsou zdrojem cestujících a pošty i jejich cílem.

Dialog otevřete z panelu seznamy.

Řadit podle: Seznamy jsou Å™azeny podle různých kritérií. Způsob Å™azení zmÄ›níte kliknutím na přísluÅ¡né tlaÄítko.

- Jméno Setřídí seznam podle názvu.
- Vzrůst osob řazeno podle množství cestujících a pošty.

- Vzestupně / sestupně Přepíná mezi vzestupným a sestupným řazením seznamu.

Kliknutím text položky ze seznamu zobrazíte okno s podrobnými informacemi o daném objektu.

Kliknutím na tlaÄítko na zaÄátku řádku se pÅ™emístíte k dané památce.

U každé památky jsou uvedeny následující informace:

Barevný indikátor znázorňuje dosažitelnost.

- žlutá barva: ve spádovém území se nenachází žádná stanice nebo zastávka.
- zelená barva: U památky se nachází aspoň jedna zastávka pro cestující.
- modrá barva: U památky se nachází aspoň jedna zastávka odbavující poštu.
- tyrkysová (světle modrozelená) barva: U památky je aspoň jedna zastávka pro cestující a aspoň jedna zastávka pro poštu.
- oranžová barva: Zastávka u památky je přeplněná.
- Äervená barva: VÅ¡echny zastávky u památky jsou pÅ™eplnÄ›né.

Ikona budovy pÅ™ed názven památky oznaÄuje mÄ›stskou památku.

název památky

vzrůst osob: Hodnota v závorkách oznaÄuje relativní oblíbenost památky jako cíl cesty pro cestující.

Nápověda odpovídá verzi 112.1, poslední úprava 5.1.2012.

simutrans-124.3/simutrans/text/cz/depot.txt000066400000000000000000000102701474050137200210540ustar00rootroot00000000000000Depo

Dialog depa

V depu můžete nakupovat, prodávat, spojovat Äi pÅ™epojovat do konvojů (souprav) vÅ¡echna vozidla zaparkovaná v depu. Dialog depa vám zobrazuje, jaká vozidla můžete nakoupit a jaká jste již nakoupil.

Směrem shora dolů se okno depa skládá z několika pruhů s různými funkcemi.

ÚplnÄ› nahoÅ™e je poÄitadlo, zobrazující pozici v celkovém seznamu konvojů v depu. Å ipkami u prvního textového pole lze mezi zaparkovanými konvoji pÅ™epínat. Textové pole zobrazuje jejich název, který je zde možno i upravit.

Pod tímto se nalézá totožný prvek, umožňující výběr linky. Více o linkách viz dále.

V oblasti mezi textovými poli a záložkami je zobrazen právÄ› aktivní konvoj a podrobnosti o nÄ›m. Udán je zde poÄet vozidel v konvoji, potÅ™ebná délka stanice, hodnota konvoje pÅ™i prodeji, dosažitelná rychlost naprázdno (a s nákladem) a nakonec linka, kterou konvoj obsluhuje.

Kliknutím na nÄ›které vozidlo zobrazeného konvoje je toto vozidlo "zakonzervováno" - pÅ™estává být souÄástí konvoje a je vidÄ›t pouze jako Äíslice nad jeho druhem v tabulce dostupných vozidel. Odtud může být znovu vzato a zaÅ™azeno do jiného konvoje.

Dále je zde sada tlaÄítek pro práci s vybraným konvojem. ÚplnÄ› nalevo je tlaÄítko start, kterým konvoj "pustíte" z depa - pokud již má nastaveno jízdní plán. Dalším tlaÄítkem jízdní řád jej lze upravit individuálnÄ› pro vybraný konvoj. TlaÄítkem rozebrat můžete celý konvoj rozpojit a jednotlivá vozidla zakonzervovat. TlaÄítkem prodat prodáte celý aktuální konvoj.

Druhá řádka tlaÄítek usnadňuje práci pÅ™i tvorbÄ› vÄ›tšího množství konvojů. TlaÄítko nová linka založí novou linku, otevÅ™e okno pro úpravu jejího jízdního plánu a vybere ji v seznamu výše. TlaÄítkem pÅ™iÅ™adit linku je aktuální konvoj pÅ™iÅ™azen na vybranou linku. ZmÄ›nit linku umožňuje upravit jízdní řád vybrané linky. Kopírovat vytvoří duplikát aktuálního konvoje z vozidel dostupných v depu nebo novÄ› nakoupených, vÄetnÄ› pÅ™iÅ™azení linky nebo nastavení jízdního plánu.

V tabulce uprostřed se záložkami jsou zobrazena koupitelné druhy vozidel. Seznam může mít celkem 4 karty:
* vozidla pro osobní dopravu,
* elektrické osobní soupravy (tramvaje, trolejbusy, el. jednotky...),
* pohonná vozidla (lokomotivy, tahaÄe apod.) a
* připojitelná vozidla (vagóny a přívěsy).
Pokud nejsou v nÄ›kterých z tÄ›chto kategorií dostupná žádná vozidla, přísluÅ¡ná záložka nemusí být zobrazena. Zakonzervovaná vozidla jsou zde zobrazena velkou Äíslicí nad ikonou vozidla.

Pod tabulkou je trojice prvků mÄ›nících její obsah a zacházení s ním. Zobrazit vÅ¡e pÅ™epíná mezi zobrazením vÅ¡ech vozidel Äi pouze tÄ›ch, která lze zaÅ™adit na konce aktuálního konvoje. Zobrazovat zastaralá ukáže v depu i již nevyrábÄ›né druhy vozidel.

TlaÄítko pÅ™epíná druh zacházení s tabulkou koupitelných vozidel pÅ™i kliknutí na její položku. PÅ™idat koupí daný druh vozidla a pÅ™ipojí jej na konec aktuálního konvoje. Pokud je k dispozici zakonzervovaný kus, je použit namísto nákupu nového. další režim je na zaÄátek, který je totozžný, ale vozidlo se pÅ™idá na zaÄátek místo na konec. Poslední možnost je prodat, která umožňuje prodávat vozidla zakonzervovaná ve vaÅ¡em depu.

Úplně dole jsou zobrazeny informace o vozidle, jehož ikona je pod kurzorem.

K vytvoření konvoje je vhodné postupovat od předu ke konci, tedy např. nejprve koupit lokomotivy a poté přikupovat vagóny. Najednou je možné pracovat pouze s jedním konvojem. Přesun vozidel mezi konvoji je možný pomocí zakonzervování (viz výše).

Viz také: ->Nápověda k jízdnímu plánu

simutrans-124.3/simutrans/text/cz/display.txt000066400000000000000000000023761474050137200214160ustar00rootroot00000000000000Nápověda - nastavení zobrazení

Nastavení zobrazení

Dialog "Nastavení zobrazení" nabízí možnost změny zobrazování různých vizuálních prvků v Simutrans.

Jas - Přidá nebo ubere jas
Barvy - Testovací prvek, bez efektu
Rychlost posuvu - Velikost tohoto Äísla udává rychlost posuvu obrazovky (pomocí myÅ¡i nebo pomocí Å¡ipek)

Inverze posuvu - Způsobí, že posuv nahoru posune obrazovku dolu, posuv doleva ji posune doprava atd.
Zobrazovat chodce - Způsobí, že se ve městech nebudou na ulicích zobrazovat chodci (ti kteří chodí do nebo ze zastávek autobusu).
Výhodné, napÅ™. pokud máte pomalejší poÄítaÄ. Náhodné chodce lze vypnout v konfiguraÄním souboru simuconf.tab.
Střídat den a noc - Aktivuje střídání simulace dne a noci v průběhu hry. Při simulaci noci některé objekty ve hře (vozidla, domy...) svítí.

Dolní Äást dialogu obsahuje různé informace o souÄasném stavu hry, které jsou zde hlavnÄ› z testovacích a vývojářských důvodů.

->Nápověda pro nastavení hry

->Informace o překladu

simutrans-124.3/simutrans/text/cz/edittools.txt000066400000000000000000000120451474050137200217510ustar00rootroot00000000000000Nápověda - ediatace Mapy

Editace mapy

Nástroje pro editaci mapy slouží k úpravÄ› již hotové mapy. Nástroje umožňují zmÄ›nu poÄtu obyvatel mÄ›st, stavbu mÄ›ststých silnic, památek, elektráren a průmyslu, zmÄ›nu aktuálního hráÄe a pÅ™idání jednoho roku ke stávajícímu datu.

Nabídku s nástroji otevÅ™ete pokud jsete pÅ™ihlášen jako hrÃ¡Ä VeÅ™ejné služby. K pÅ™epínání mezi hráÄi slouží tlaÄítko P+ v nabídce se speciálními stavbami nebo klávesa [P]).
Po najetí kurzorem myši nad jednotlivé nástoje se zobrazí název nástroje, popřípadě i doplňující informace, k danému nástroji.

Nástroje zahrnují,tyto položky. Pořadí položek se může lišit v závislosti na jednotlivých grafických sadách (anglicky paksets).

ZvÄ›tÅ¡it mÄ›sto: Nástroj zvýší poÄet obyvatel mÄ›sta pÅ™ibližnÄ› o 100 obyvatel. Jsou postaveny nové silnice a budovy.
Použití: Klikněte na nástroj a pak klikněte na město.

ZmenÅ¡it mÄ›sto: Nástroj umožňuje snížit poÄet obyvatel daného mÄ›sta. PoÄet obyvatel se sníží o 100.
Použití: Klikněte na nástroj a pak klikněte na město.

Založit nové město: Nástroj slouží k založení nového města.
Použití: Klikněte na nástroj a pak klikněte na pole, kde chcete mít nové město. Město se postaví na zvoleném poli nebo v jeho blízkosti.

Zasadit strom *: Nástroj umožňuje osázet terén stromy. Klikněte na nástroj a pak na místo v krajině.

Založit les * Nástroj slouží k výsadbě lesa. Klikněte na nástroj a pak dvakrát klikněte na různá místa v terénu. Prostor mezi nimi bude osázen tromy.

MÄ›stská silnice: Nástroj slouží ke stavbÄ› mÄ›stské silnice. PÅ™i umístÄ›ní kurzoru nad ikonu se zobrazí cena a v závorce cena za údržbu. Použití: MÄ›stská silnice se staví stejným způsobem, jako ostatní silnice. KliknÄ›te na symbol mÄ›stské silnice, pak kliknÄ›te na zaÄátek a výstavbu dokonÄete kliknutím na konec. Cestu se nepodaří vytvoÅ™it, pokud se mezi zaÄátkem a koncem nachází pÅ™ekážka (Å™eka, železnice, Älenitý terén atd.)
Tip: Nerovnosti odstraníte pomocí nástrojů na úpravu terénu, Å™eku pÅ™ekonáte mostů, skrz kopec se dostavete pomocí tunelu. Druhým možný způsob: Po kliknutí na zaÄátek držte levé tlaÄítko myÅ¡i. UmístÄ›te kurzor na konec budoucí cesty a pusÅ¥e tlaÄítko.

Tip: Nechcete-li, aby se souběžné cesty spojovaly, mÄ›jte v průbÄ›hu pokládání stlaÄenu klávesu Ctrl.

Řeka *: Nástroj umožňuje přidat do krajiny řeku. Máte na výběr z více možností, od potoka po veletok.

Zahustit průmysl: Po kliknutí na tlaÄítko se objeví na mapÄ› další továrny.

PÅ™idat továrnu: Kliknutí na tlaÄítko otevÅ™e dialog pro pÅ™idání továrny.

Propojení továren: Aby bylo mezi továrnami dodáváno zboží, musejí mít továrny mezi sebou spojení (uzavÅ™ený kontrakt). Automaticky vytvoÅ™ené továrny toto spojení mezi sebou mají. Pokud ruÄnÄ› pÅ™idáte do hry továrnu, potÅ™ebujete také nastavit, odkud má odebírat suroviny a kam dodávat výrobky. K tomu slouží toto tlaÄítko.
KliknÄ›te na tlaÄítko (zmÄ›ní se kurzor). Pak kliknÄ›te postupnÄ› na obÄ› továrny, které mají uzovřít kontrakt.

Přidat kuriozitu: Nástroj slouží k přidání památek, pomníků a jiných zajímavostí do krajiny. Tyto objekty přitahují turisty a poštu.
Po kliknutí na ikonu se zobrazí okno s výběrem konkrétní budovy.

Přidat městskou budovu: Kliknutím otevřete dialog s nabídkou městských budov.

Znemožnit další zmÄ›nu hráÄů: Nástroj slouží k zamezení pÅ™epínání mezi různými hráÄi. Aby Å¡el tento nástroj použít, musí mít hrÃ¡Ä nazývaný VeÅ™ejné služby nastavené heslo.
Použití: Klikněte na ikonu nástroje a pak klikněte kamkoliv na herní plochu.

PÅ™idej jeden rok: PÅ™idá jeden rok ke stávajícímu letopoÄtu. Pokud jste použili volbu zaÄít roku, mohou se objevit nová dostupná vozidla a nÄ›která ze stávajících vozidel mohou být oznaÄena za zastaralá. Pomalejší vozidla mohou snížit zisk a nebo zaÄít prodÄ›lávat, protože výnos z pÅ™epravy závisí na průmÄ›rné rychlosti.
Pro použití kliknÄ›te na tlaÄítko.

Změnit velikost mapy: Kliknutí na nástroj otevře dialog sloužící ke zvětšení rozměrů mapy.

* Nástroj není dostupný ve všech grafických sadách (anglicky paksets).

simutrans-124.3/simutrans/text/cz/enlarge_map.txt000066400000000000000000000016401474050137200222140ustar00rootroot00000000000000Nápověda - Změnit velikost mapy

Změnit velikost mapy

Dialog slouží k rozšíření již vytvořené mapy.

Mapu lze rozšířit smÄ›rem vpravo a smÄ›rem dolu. Pokud chcete mapu rozšířit jiným smÄ›rem, otoÄte ji, zvÄ›tÅ¡ete ji a otoÄte zpÄ›t.
Tip: K otoÄení použijte klávesu R.

Budoucí velikost mapy lze zadat pomocí klavesnice nebo Å¡ipkami na stranách políÄka.
Horní políÄko slouží k zadání rozmÄ›ru zleva doprava, druhé políÄko k zadání rozmÄ›ru shora dolu.

NejvÄ›tší Ätvercová mapa má delku strany 4096 políÄek, nejvÄ›tší obdélníková mapa má delku strany 8192 polí (pÅ™i délce kratší strany 2048 polí).

PoÄet mÄ›st je poÄtem novÄ› vytvoÅ™ených mÄ›st.

Medián ovlivňuje poÄet obyvatel v novÄ› vytvářených mÄ›stech.

simutrans-124.3/simutrans/text/cz/factory_build.txt000066400000000000000000000045431474050137200225750ustar00rootroot00000000000000Nápověda - přidat továrnu

Přidat továrnu

Dialog umožňuje různě umisťovat továrny na mapu. Otevřete jen z menu editace mapy.

Okno dialogu je rozdÄ›leno do ÄtyÅ™ Äástí.
V levém horním rohu se nachází seznam továren.
V levém dolním rohu se zobrazí obrázek naposledy zvolené továrny
V pravém horním rohu jsou tlaÄítka pro zapnutí/vypntí filtrů jednotlivých druhů továren.
V pravém dolním rohu (pod tlaÄítky) se nachází podrobné informace o vybrané továrnÄ›.

Seznam továren

V seznamu jsou vypsány všechny továrny. Obě záložky obsahují stejné továrny, seznamy se liší jen pořadím.
- Podle jména: Záložka obsahuje továrny setříděné podle názvu uvedeného v překladu. Pokud není překlad dostupný, použije se identifikátor (ID).
- Podle ID: Zde jsou továrny řazené podle vnitřního identifikátoru daného objektu.

Barvy textu mají následující význam:
- zelený text: Továrna zboží pouze vytváří, nic není nutno dovážet.
- Äerný text: Továrna spotÅ™ebovává suroviny a produkuje výrobky.
- modrý text: Továrna je pouze spotřebitelem zboží.

Volby

Ignorovat podnebí: Vypne omezení, ve kterých podnebných pásech lze továrnu postavit.

ZaÄít roku: V seznamu jsou zobrazeny pouze továrny dostupné v danou dobu.

Zobrazovat Zastaralá: V seznamu jsou zobrazeny i již zastaralé továrny.

Pouze městský průmysl: Zobrazí se továrny, které lze postavit pouze ve městě.

Pouze venkovský průmysl: Zobrazí se pouze továrny stavěné mimo města. Když je zatrženo, staví se celý řetěz průmyslu. To znamená, že kromě zvolené továrny se postaví i její dodavatelé.

Rotace: Jestliže má daná továrna umožňuje pohled z více úhlů, můžete mezi nimi přepínat pomocí šipek. Přepínání ovlivňuje obrázek v levém dolním rohu. Jestliže je zobrazen nápis náhodně, použije se náhodně zvolený podled.

Výroba: Zde nastavíte rozsah výroby. Číslo urÄuje poÄet vyrobených/spotÅ™ebovaných kusů/tun/metrů krychlových za jeden mÄ›síc.

simutrans-124.3/simutrans/text/cz/factorylist_filter.txt000066400000000000000000000053141474050137200236540ustar00rootroot00000000000000Seznam továren

Seznam továren

Seznam továren obsahuje informace o všech továrnách umístěných na herní ploše.

Seznam továren otevřete z menu Seznamy.

Řadit podle: Volba ovlivňuje pořadí zobrazených továren.
Kliknutím na tlaÄítko pÅ™epínáte mezi následujícími možnostmi:

- Název továrny Řadí se abecedně podle názvu.
- Příjem Řadí podle množství přijatého zboží na skladě.
- OdbÄ›r Řadí podle množsví výrobků Äekajících na odvoz.
- Výroba Pořadí je podle aktuální výrobní kapacity.
- Stav Seřadí továrny podle barevného indikátoru stavu.
- Výkon Seřadí továrny podle zvýšení výkonu způsobeného dodáním elektrické energie.

- Vzestupně / sestupně: Přepíná mezi vzestupným a sestupným řazením seznamu.

továrny

Kliknutím na položku v seznamu zobrazíte podrobnější informace o dané továrně.

U každé továrny jsou zobrazeny následující položky:

barevný indikátor stavu: Barvy vypovídají o výrobě v dané továrně. Stejné barvy jsou užity v informacích o továrně.
- bílá barva: Továrna nic nepožaduje nebo nemá kontrakt s žádným dodavatelem.
- žlutá barva: Továrna má odběratele, ale nikdo od ní nedopravuje zboží.
- zelená barva: Optimální stav, továrna vyrábí.
- oranžová barva: V provozu, sklad s aspoň jednou surovinou je plný, ale zatím je pro koho vyrábět a ve skladu s výrobky je volné místo.
- Äervená barva: HodnÄ› surovin na skladu a není kam dodávat výrobky (mají plno).

Äervený blesk je zobrazen u továren pÅ™ipojených k elektrické síti.

symbol cestujících: Továrna leží ve spádové oblasti aspoň jedné zastávky pro cestující.

symbol pošty: Továrna leží ve spádové oblasti aspoň jedné zastávky pro poštu.

název továrny: Název továrny uvedený v překladu.

Hodnoty uvedené v závorkách mají následující význam:
- pÅ™ijaté zboží: Množství vstupních surovin Äekajících na zpracování.
- Äeká na odvoz: Množství hotových výrobků Äekajících na odvoz.
- aktuální produkce: aktuální míra produkce - kolik výrobků pÅ™i souÄasném tempu výroby je továrna schopna vyrobit za mÄ›síc.

simutrans-124.3/simutrans/text/cz/finances.txt000066400000000000000000000056401474050137200215340ustar00rootroot00000000000000Nápověda - finance

Finance (klávesová zkratka: f)

V dialogu finance naleznete tabulku rozpisu vašich příjmů a výdajů za tento a minulý rok, a také graf vybraných položek.

Tabulku příjmů lze zobrazit po měsících nebo po letech. Údaje lze zobrazit i jen pro jednotlivé způsoby přepravy (od verze 112.3). Hodnoty jednotlivých následujících položek jsou zobrazitelné v grafu.

levý sloupec

Přepraveno - Kolik zboží, cestujících a pošty jste přepravili.

Příjmy - SouÄet penÄ›z, vydÄ›laných pÅ™epravou zboží a cestujících

Provoz vozidel - Provozní náklady za všechna vozidla

Údržba - Výdaje za udržování vaÅ¡ich staveb v dobrém stavu - opravy, úklid atd. Čím více tratí, cest, mostů, tunelů a staveb, tím je vÄ›tší tato Äástka.
Jak vysoká je tato Äástka na tento mÄ›síc, je uvedeno na posledním řádku dialogu.
Tato Äástka vám bude odeÄtena najednou, na zaÄátku každého mÄ›síce. Vozidel se tato položka (zatím) netýká.
(MÄ›síÄní náklady na údržbu vozidel jsou v simutrans experimental).

Mýto - Mýtné za jízdu vaÅ¡ich vozidel po silnicích jiných hráÄů (platíme) a za jízdu cizích vozidel po vaÅ¡ich silnicích (je nám placeno). Výši mýtného lze ovlivnit v nastavení pÅ™i vytváření nové mapy v záložce Hospodářství a mÄ›sta volbami toll_running_cost_percentage a toll_waycost_percentage.

Zisk z vozidel - SouÄet pÅ™edchozích ÄtyÅ™ položek vÄetnÄ› znaménka. (Příjmy + provoz vozidel + údržba + mýto)

Nová vozidla - Příjmy a výdaje za prodaná Äi zakoupená vozidla

Stavby - SouÄet výdajů za vÅ¡e co jste postavili - železnice, silnice, stanice atd.

Hosp. výsledek - Celkový souÄet příjmů a výdajů za tento popÅ™. minulý rok

pravý sloupec

Zůstatek - Váš celkový zůstatek peněz - stav vašeho konta.

Majetek - souÄet cen vÅ¡eho vaÅ¡eho majetku - vozidel. Budovy, silnice, železnice, apod. se nepoÄítají. Cena každého objektu postupnÄ› Äasem klesá.

Výdělek - zisk z vozidel dělený příjmy

JmÄ›ní - souÄet zůstatku a hodnot vÅ¡ech vozidel

Grafy

Stiskem tlaÄítek v pravé horní Äásti dialogu můžete zobrazit vývoj zvolené hodnoty za souÄasný rok a pÅ™edcházejících 24 let. (Od verze 112.3, dříve jen 11 let)
Význam hodnot v grafu po stisknutí patÅ™iÄných tlaÄítek je stejný jako v tabulce příjmů a výdajů.

->Informace o překladu

Nápověda odpovídá verzi 112.3, poslední úprava 31.12.2013.

simutrans-124.3/simutrans/text/cz/goods_filter.txt000066400000000000000000000057351474050137200224330ustar00rootroot00000000000000Seznam zboží

Seznam zboží

Seznam zboží obsahuje informace o různých věcí, které je možné transportovat po mapě. Dále je možné ovládat výdělek za jednotlivé zboží.

Seznam je dostupný: BuÄ kliknutím na nářadí 'Seznam zboží' ve skupinÄ› Seznamy nebo tlaÄením [G].

Listina přístupných zboží na transport obsahuje detaily: Příjem, % bonus za rychlost, kategorie zboží a váhu.
{Tip: Když neni celý text zobrazený, pomůže zvětšení okna Seznam zboží anebo použití posuvníků.}

Bonus za rychlost: Dostupnost bonusu je závislá na typu vozidla. Listina obsahuje rychlosti, které jsou nutné dosáhnout soupravou, aby byl vyplacen zvláštní příjem za rychlou dodávku za zboží nebo za cestující (jsou dokonce i případy, že je příjem odebran za pomalou dodávku).
Když hrajete s Äasovou osou, Simutrans nutnÄ› upravuje rychlosti kvůli dostupnosti nových, rychlejších vozidlech.
Šipky naladějí příjmy a rychlosti bonusového systemu.

Řadit podle: zmožnuje změnění řazení záznamů listiny.
KliknÄ›te tlaÄítka na zvolení Å™azení (nápis tlaÄítka se zmÄ›ní):

- Nic netřídí záznam.
- Podle názvu třídí jména podle abecedy.
- Podle příjmu třídí podle vydÄ›lku za transport jednotky zboží o jedno políÄko.
- Podle bonusu třídi podle % bonusu za rychlost (% dodateÄného příjmu, když použitá souprava dosáhne nutnou rychlost pro získání bonusu).

- Vzestupně / Sestupně mění pořadí třízení.

Jsou zobrazené detaily pro každý záznam:

Barevný Ätverec má stejnou barvu jako hrana nad stanicí ve hÅ™e, ukazující příjem zboží a Äekajicí zboží.
{Tip: Tiskněte [!] ve hře na střídání hran na příjem zboží nad stanicemi.}

Příjem znamená výdÄ›lek za transport jednotky zboží o jedno políÄko.
{Tip: Hrajte zaÄáteÄnický mód na zvýšení příjmu až do 150% (můžete nastavit v simuconf.tab)}

% Bonus je % dodateÄného příjmu, když souprava pÅ™ekroÄí nutnou rychlost na získ rychlostného bonusu.
KalkulaÄní vzorec na příjem je komplexní a bere ohled na maximální rychlost soupravy a srovnává jí s maximalní rychlosti vÅ¡ech dostupnćh vozidel (nejen existujicí ve hÅ™e).

Kategorie zboží ukazujicí specifikované typy vozidla na transport tohoto zboží.
{Tip: Kapacita vozidel naznaÄuje, které zboží mohou transportovat.}

Hmotnost v kilogramech.

simutrans-124.3/simutrans/text/cz/haltlist.txt000066400000000000000000000012341474050137200215650ustar00rootroot00000000000000seznam stanic

Seznam stanic

Seznam nabízí tyto možnosti:

1.) Řazení:
Postupným klikáním na první pÅ™epínací tlaÄítko mÄ›níte kritéria, podle kterých bude seznam Å™azen.
Vedlejším tlaÄítkem nastavujete, zda má být Å™azen sestupnÄ› nebo vzestupnÄ›.

2.) Filtr:
Kliknutím na tÅ™etí tlaÄítko aktivujete, nebo deaktivujete filtr.
Možnosti tohoto filtru můžete mÄ›nit po kliknutí na tlaÄítko nastavení.

->Nápověda pro filtr

->Informace o překladu

simutrans-124.3/simutrans/text/cz/haltlist_filter.txt000066400000000000000000000021151474050137200231310ustar00rootroot00000000000000Filtr seznamu stanic

Filtr seznamu stanic

Filtr nabízí tyto možnosti:

1.) Filtrovat jméno:
V seznamu budou zobrazeny pouze stanice, které se jmenují podle zadání.

2.) Filtrovat typ:
V seznamu budou zobrazena pouze stanice zvoleného typu.

3.) Speciální filtrování:
V seznamu budou zobrazeny pouze stanice, které nemají spojení nebo jsou přeplněné.

4.) Podle vyžadovaného průmyslu:
Seznam zobrazí pouze stanice, které vyžadují pro průmysl na který jsou napojeny zvolené komodity. *

5.) Podle produkovaného průmyslu:
Seznam zobrazí pouze stanice, které produkují zvolené komodity. *

* TlaÄítko vÅ¡e vybere vÅ¡echny komodity, tlaÄítko nic naopak vÅ¡echny odvybere. TlaÄítkem inv obrátíte aktuální výbÄ›r.

->Nápověda pro seznam stanic

->Informace o překladu

simutrans-124.3/simutrans/text/cz/industry_info.txt000066400000000000000000000135741474050137200226470ustar00rootroot00000000000000Informace o továrně

Informace o továrně

Dialog informace o továrně zobrazuje detaily o vybrané továrně, jejích dodavatelích a odběratelích a umožňuje přemístit se na pozice s továrnou.

Dialog vyvoláte kliknutím inspekÄní lupou na továrnu nebo na název v seznamu továren.

Továrny mohou fungovat osamocenÄ› (napÅ™. vÄ›trná elektrárna) nebo být souÄástí rozsáhlého průmyslového Å™etÄ›zu. Mohou výt ÄistÄ› producenty primárních surovin (uhlí, železná ruda, ...), zpracovatelé (ocelárna, pila) nebo koncoví spotÅ™ebitelé.
Továrny jsou také cílem cesty pro cestující a poštu.

{Tip: StaÄí, aby ve spádové oblasti stanice/zastávky bylo jen jedno pole továrny.}

PoÄáteÄní množství Å™etÄ›zů průmyslu lze zadat pÅ™i vytváření nové mapy. Jak mÄ›sta rostou, objevují se další továrny. O kolik musí vzrůst poÄet obyvatel, aby se na mapÄ› objevila další továrna závisí na nastavení.

V titulku je název vybrané továrny.

V poli na prvním řádku lze měnit název továrny, např. Uhelný důl Adéla.

Za textem Max. se nachází maximální produkce továrny za jeden mÄ›síc. (Nebo den, záleží na nastavení zobrazení Äasu.) Množství vyprodukovaných výrobků můžete zvýšit dodáním elektrické energie cestujících a poÅ¡ty. Zda-li ke zvýšení produkce (a o kolik) dojde záleží na konkrétní továrnÄ›. Tyto informace zjistíte po kliknutí na tlaÄítko graf v záložce výroba/zvýšeno

Výroba: Informace o typech výrobků a jejich množství.
Informace obsahují název výrobku, množství výrobku na skladÄ›, kapacitu skladu pro daný výrobek, kategorii (v Äem se dá zboží pÅ™epravovat) a procentuelní pomÄ›r v jakém je vyrábÄ›n.

spotřeba: Informace o vstupních surovinách a jejich množství.
Informace obsahují název suroviny, množství na skladu, kapacitu skladu pro danou surovinu, kategorii zboží a procentuelní poměr vstupních surovin.

Kliknutí na Obrázek továrny vás přemístí se na pozici s továrnou.

barevný indikátor stavu pod obrázkem továrny má stejný význam jako v seznamu továren:
- bílá barva: Továrna nic nespotřebovává nebo nemá uzavřen kontrakt s žádným dodavatelem.
- žlutá barva: Továrna má uzavřeny kontrakty, ale není u ní žádná stanice nebo zastávka.
- zelená barva: Optimální stav, továrna vyrábí.
- oranžová barva: V provozu, sklad s aspoň jedním výrobkem je plný, ale zatím je pro koho vyrábět nebo je dost místa ve skladu na hotové výrobky.
- Äervená barva: U továrny jsou zastávky ale zboží se z nich nedopravuje nebo odbÄ›ratelé mají plné sklady surovin nebo v provozu ale sklady surovin jsou pÅ™eplnÄ›né.

TlaÄítko graf zobrazí nebo skryje panely s grafy k přísluÅ¡né továrnÄ›.

TlaÄítko detaily otevÅ™e okno s podrobnostmi o daném typu továrny; pokud typ továrny nemá nápovÄ›du, tlaÄítko není zobrazeno.

Odběratelé: Seznam odběratelů zboží z dané továrny. V závorkách za názvem továrny jsou její souřadnice.
Kliknutím na Å¡ipku na zaÄátku řádku vás pÅ™emístí k zvolenému odbÄ›rateli.

Dodavatelé: Seznam dodavatelů surovin pro danou továrnu. V závorkách za názvem továrny jsou uvedeny její souřadnice.
Kliknutím na Å¡ipku na zaÄáku řádku se pÅ™emístíte k přísluÅ¡nému dodavateli.

Zaměstnanci bydlí v: Ukazuje ve kterých okolních městech žijí zaměstnanci. Z těchto měst můžete k továrně dopravovat cestující a poštu.
Šipky před názvy měst služí k přemístění do příslušného města.

Zastávky v dosahu objektu: Zastávky, v jejichž spádovém území se továrna nachází. Na ně lze dopravovat cestující, poštu a suroviny pro továrnu.

graf - zboží

Pod grafem je tabulka, v vprním sloupci je název vyrobeného zboží nebo spotÅ™ebované suroviny. V dalších sloupcích jsou tlaÄítka sloužící k zobrazení/skrytí hodnot v grafu.
- zásoby: množství suroviny/výrobku na skladu
- došlá pošta !?(přijato): množství suroviny přivezené v daném měsíci
- spotřebováno: množství spotřebované suroviny v daném měsíci
- doruÄeno: množství zboží vyexpedovaného na okolní zastávky
- vyrobeno: množství vyrobeného zboží

graf - výrobky/zvýšeno

Záložka spotÅ™eba/zvýšeno obsahuje tato tlaÄítka:
- výroba: Kolik výrobků je továrna schopna mÄ›síÄnÄ› vyrobit
- využito/výkon: Kolik bylo využito elektrické energie.
- zvýšení produkce: Jak moc (o kolik procent) byl výkon továrny zvýšen dodáním elektrické energie, cestujících a pošty
- Max.zvýšení produkce: O kolik procent lze nejvíce ovlivnit výkon továrny dodáním elektrické energie, cestujících, pošty.
- poptávka: Kolik MW přikonu elektrické energie, cestujících a pošty elektrárna potřebuje pro optimální výkon.
- cestující: Množství vyprodukovaných, odbavených a přijatých cestující.
- pošta: Množství vyprodukované, odbavené a přijaté pošty.

simutrans-124.3/simutrans/text/cz/inspection_tool.txt000066400000000000000000000150521474050137200231540ustar00rootroot00000000000000InspekÄní lupa

InspekÄní lupa

Nástroj inspekÄní lupa se používá k otevírání dialogů, k zobrazení informací nebo výbÄ›ru z voleb.

Nástroj vyberete kliknutím na ikonu se zavětšujícím sklem v hlavním menu nebo stiskem klávesy [a]. Pokud je nástroj zvolený, kurzor má tvar lupy.

{Tip: Kliknete-li inspekÄní lupou na zastávku s vlakem, zobrazí se nejprve okno s informacemi o zastávce. Budete-li vÅ¡ak držet klávesu Ctrl, zobrazí se nejprve okno s informacemi o vlaku.}

Poznámka k užití: Vyskytuje-li se na stejné pozici více objektů, které pÅ™i kliknutí inspekÄí lupou zobrazí dialog, pak opÄ›tovné kliknutí otevÅ™e další dialog v poÅ™adí.
{Tip: Které dialogu se budou otevírat a které nikoliv lze urÄit v nastavení nebo v souboru simuconf.tab}

Kliknutím inspekÄní lupou na objekty ve hÅ™e otevÅ™e přísluÅ¡né dialogy:

Depo : Nástojem otevřete dialog depa sloužící k nákupu a správě vozidel.

Zastávka/stanice: Otevře dialog s informacemi o zastávce.

Konvoje : Otevře informace o konvoji.

Radnice : Otevře dialog s informacemi o městu.
{Tip: Volba townhall_info umožňuje povolit zobrazení informací též o budově radnice. viz nastavení (záložka všeobecné) nebo simuconf.tab}

Továrna : Otevře dialog s informacemi o továrně.

Městská budova : Otevře dialog poskytují informace o městské budově. Dialog obsahuje následující informace:
- majitel: Obvykle je zde napsáno: bez majitele, pokud budovy koupíte bude zde vaše jméno.
- popisek: Informace o budově. Pokud budova nemá přiřazený žádný doplňující popisek, je zobracen nápis 'obytný dům', 'továrna', nebo 'obchody a kanceláře'.
- Obec: Název města/vesnice kam dům patří.
- Vzrůst osob: Relativní obliba u cestujících.
- Pošta: Relativní obliba u pošty.
- dostupné od ~ do ~ : Interval, ve kterém je daná budova dostupná, pokud jste pÅ™i vytváření mapy zadali volbu zaÄít roku.
- Cena: Kolik bude stát koupě nebo odstranění budovy.
- Postavil: Jméno autora, který budovu nakreslil.

Pomníky / Turistické atrakce: Otevře dialog poskytující informace o památce. V titulku je napsáno jestli se jedná o pomník nebo o turistickou atrakci.
- VeÅ™ejný majetek znamená, že objekt není vlastnÄ›n hráÄovou spoleÄností.
- Popisek poskytuje informace o památce.
- Vzrůst osob je relativní obliba mezi cestujícími.
- Pošta je relativní obliba u poštovních zásilek.
- Dostupné od: Odkdy se budova objeví ve hÅ™e, pokud hrajete s volbou zaÄít roku.
- postavil: Kdo to pro simutrans nakreslil.

Silnice a železnice: Otevře dialog poskytující informace o železnici, silnici, plavebním kanálu ...
Pokud se jedná o tramvajovou traÅ¥ na silniÄním podkladu, okno dialogu obsahuje informace o obou.
Informace obsažené v dialogu:
- Max. rychlost: Maximální povolená rychlost.
- (bez masky): Äíslo jehož jednotlivé bity ukazující smÄ›ry cesty.
- (maska): Äíslo, jahož jednotlivé bity ukazují smÄ›r cesty pokud se bere ohled na povolený smÄ›r jízdy.
Pozn. ribi nejsou ryby ale zkratka pro Richtungsbits.
- elektrifikováno/nelektrifikováno oznamuje, jestli je cesta elektrifikovaná.
- souprav za poslední mÄ›síc poÄet souprav, které použily cestu v minulém mÄ›síci.
- rezervován pro oznamuje, že zde něco pojede.
- mapové souředanice zobrazeny v titulku okna

silniÄní semafory OtevÅ™e dialog semaforu.

železniÄní návÄ›stidla OtevÅ™e dialog s železniÄními návÄ›stidly.
Informace obsažená v dialogu zahrnuje:
- směry bitová maska směrů.

vedení: Kliknutím na elektrické vedení zobrazíte s informacemi o aktuálním stavu sítě:
- jméno majitele sítě
- síť: identifikátor sítě
- kapacita sítě: větší množství elektrické energie vám jedna síť dopravovat nepovolí.
- spotřeba: aktuální spotřeba v síti - poptávané množství el. enegrie, může být i vyšší než množství dodávané el. energie
- výroba: Množství aktuálně vyráběné elektrické energie.
- aktuální přenos: aktuálně dodávané množství el. energie.
- dodáno % : Kolik % vyrobené el. energie je spotřebováváno

trafostanice u elektrárny Otevře okno s informacemi o právě dodávaném množství elektrické energie továrnou do sítě.
- majitel
- výroba

trafostanice u továrny Otevře okno s informacemi o právě dodávaném množství elektrické energie továrnou do sítě.
- síť: identifikátor sítě elektrické sítě.
- spotřeba: Kolik MW el. energie továrna potřebuje.
- aktuální přenos: Kolik MW je aktuálně dodáváno do továrny.
- dodáno % : Kolik procent el. energie požadované továrnou je dodáno.

strom otevře dialog s nápisem 'Strom'. Zobrazené informace zahrnují:
- název druhu stromu.
- věk stromu v rocích a měsících.
{Pozn: musí být povoleno v nastavení (položka tree_info). Pokud není povoleno, dialog se stromem se neotevře.}

zemský povrch otevře okno 'země'). Zobrazené informace zahrnují:
- klimatický pás v závislosti na nadmořské výšce.
- mapové souřadnice zobrazené v ditulku okna.
Pozn: musí být povoleno v nastavení (položka ground_info) .

simutrans-124.3/simutrans/text/cz/labellist_filter.txt000066400000000000000000000017731474050137200232710ustar00rootroot00000000000000Seznam nápisů

Seznam nápisů

Zde jsou vypsány všechny nápisy vyskytující se na mapě.

Seznam nápisů otevřete z menu seznamy.

{Tip: Nápisy lze použít například pro pojmenování řek nebo místo nástěnky v hře po síti. }

Dialogu umožňuje nápisy řadit podle:
- hráÄ: Řadí podle hráÄe.
- jméno: Řadí nápisy podle textu.
- souřadnice: Nápisy jsou řazeny podle souřadnic.

Druhé tlaÄítko pÅ™epíná mezi vzestupným a sestupným způsobem Å™azení.

TlaÄítko oznaÄené pouze aktivní hrÃ¡Ä umožňuje zobrazit nápisy pouze od právÄ› aktivního hráÄe.

Kliknutí na Å¡ipku na zaÄátku řádku vás pÅ™emístí k nápisu.

Kliknutí na text nápisu zobrazí okno s obrázkem místa, kde se nápis nachází.

simutrans-124.3/simutrans/text/cz/language.txt000066400000000000000000000014411474050137200215240ustar00rootroot00000000000000Nápověda - výběr jazyka

Jazyk

Simutrans je vícejazyÄná hra, a tak pokud existuje pÅ™eklad do VaÅ¡eho jazyka, můžete si jej zvolit.
Po zmÄ›nÄ› jazyka zaÄne hra vypisovat vÅ¡echny (pÅ™eložené) texty, ve Vámi zvoleném jazyce. Stávající otevÅ™ená okna je tÅ™eba znovu otevřít, aby v nich doÅ¡lo k vypsání textů ve zvoleném jazyce.

U stávajících měst zůstanou jejich jména, která byla vytvořena podle jazyka při generování nové mapy. Proto je výhodné vybrat si jazyk ještě před generováním nové mapy, abyste v něm měli jména měst.

->Informace o překladu

Chcete-li pomoci s překladem Simutranů do vašeho jazyka,
navštivte https://translator.simutrans.com

simutrans-124.3/simutrans/text/cz/linemanagement.txt000066400000000000000000000146621474050137200227360ustar00rootroot00000000000000Nápověda - správa linek

Správa linek

Dialog správa linekposkytuje informace o linkách a umožňuje je spravovat.

Linka je tvoÅ™ena jednou nebo více soupravami a spoleÄným jízdním plánem.

Dialog správa linek otevÅ™ete kliknutím na ikonu v hlavním menu, stiskem klávesy [w] nebo kliknutím na tlaÄítko pÅ™ed názvem linky v dialogu informace o soupravÄ›.

Vlevo nahoře je seznam existujících linek. Linky mohou být filtrovány podle způsobu přepravy:
Vše: seznam linek všech druhů dopravy.
jednokolejka: seznam linek jednokolejky.
vlaky: seznam železniÄních linek.
úzkokolejka: seznam úzkokolejných železniÄních linek.
tramvaj: seznam tramvajových linek
náklaÄáky: seznam linek silniÄní dopravy.
lodě: seznam linek lodní dopravy.
letadla: seznam linek letecké dopravy

{Poznámka: Ne všechny způsoby přepravy jsou vždy v dané grafické sadě dostupné.}

Barva názvu linky v seznamu má následující význam:
bílá barva - linka nemá přiřazeno žádné vozidlo
žlutá barva - není v provozu, nevytváří zisk ani ztrátu
Äerná barva - linka je v zisku
modrá barva - linka obsahuje zastaralá vozidla
Äervená barva - linka prodÄ›lává

tlaÄítka pod seznamem

Pod seznamem existujících linek jsou tlaÄítka voleb pro správu linek
Aby bylo možné linku změnit nebo smazat, musí být nějaká linka vybrána. Linku vyberete kliknutím na její název v seznamu v levém horním rohu.

TlaÄíka pod seznamem linek nabízejí tyto možnosti:

nová linka:TlaÄítkem otevÅ™ete nový jízdní plán. Jízdní plán obsahuje trasu, minimální množství nákladu a maximální dobu Äekání u jednotlivých stanic.
Nový jízdní plán přiřadíte zavřením okna s jízdním plánem.
{Poznámka: Musíte vytvářet linku pro konktétní typ dopravního prostředku (např tramvaj), abstraktní linku nejde vytvořit.}
{Poznámka: Body v jízním plánu mimo zastávky a stanice jsou pouze průjezdné, nic se na nich nenakládá ani nevykládá. Body ovliňují rezervování tratě pro vlaky.}

ZmÄ›nit linku: TlaÄítkem otevÅ™ete stávající jízdní plán. ZmÄ›na se projeví pÅ™i uzavÅ™ení okna s jízním plánem.
Dříve než kliknete na tlaÄítko, vyberte požadovanou linku kliknutím na její název v seznamu.

Smazat linku: Odstraní vybranou linku. Žádné další potvrzení není vyžadováno.

seznam stanic

Pokud je zvolena libovolná linka, pak se v levém dolním rohu zobrazí seznam stanic.
Položky zobrazené u každé stanice zahrnují:

barevný indikátor stavu: Barva ukazuje, jestli stanice není přeplněna. Stejné barevné schéma je použito i v seznamu stanic a zastávek a také u zastávek ve na herní ploše.
- žlutá: zatím bez provozu.
- zelená: v provozu, existuje dostateÄná volná kapacita.
- oranžová: zastávka zaÄíná být pÅ™eplnÄ›na.
- Äervená: pÅ™eplnÄ›no, aspoň pro jeden typ pÅ™epravovaných položek není volná kapacita.

jméno přiřazené k zastávce.

Äíslo zastávky (jako souÄást názvu), je tÅ™eba povolit v nastavení nebo v simuconf.tab.

ikona vozidla ukazuje které druhy dopravy mohou zastávku použít (vlak, silniÄní doprava, ...)

ikona(y) zboží zobrazuje, které položky (cestující, pošta, náklad) je zastávka schopna odbavit.

Äeká množství Äekajících cestující, poÅ¡ty a zboží.

graf vpravo

Na pravé straně od seznamu linek se nachází graf, pole pro změnu názvu linky a seznam vozidel zvolené linky.

Hodnoty v grafu zobrazíte kliknutím na odpovídající políÄko pod grafem. Na vodorovné ose je zobrazen Äas v mÄ›sících.

volná kapacita - Množství volného prostoru (který by mohl být využit pro přepravu ale zůstal nevyužitý).

přepraveno - množství přepraveného zboží / přepravených cestující.

příjmy - peníze za dopravu.

provoz vozidel - provozní náklady.

zisk - peníze za dopravu po odeÄtení provozních nákladů.

soupravy - poÄet souprav pÅ™iÅ™azených k dané lince.

délka/mÄ›síc - PoÄet kilometrů ujetých vozidly dané linky.

Maxspeed - teoretická maximální rychlost - jsou z ní poÄítány bonusy za rychlejší pÅ™epravu.

Editovatelné pole s názvem linky slouží ke změně názvu. {Tip: Pokud si linky vhodně pojmenujete lépe se v seznamu budete orientovat i při větším množství linek. Např.: Louny 31415
Pojmenované linky využijete hlavně v autobusové dopravě. }

seznam souprav

Pokud je vybrána nějaká linka, v pravé dolním rohu se zobrazí seznam souprav přiřazených k lince.
Více informací o konkrétní soupravě získáte, pokud na ni v seznamu kliknete.
U souprav jsou zobrazeny následující položky:
název který byl přiřazen soupravě (výchozí název je vytvořen podle prvního vozidla soupravy při koupi v depu).
poÄet souprav pÅ™iÅ™azených k daná lince
kapacita všech souprav linky dohromady
zisk/ztráta (oznaÄená příjem) provozní zisk/ztráta (příjem po odeÄtení provozních nákladů)
Poznámka: Pozor vozidla také platí mýto a to zde zatím (ve verzi 111.1) není zapoÄítáno.
naložené množství položek
procentuální naložení souprav linky v závorkách
linka: ke které lince je souprava přiřazena.
obrázek zobrazení řazení vozidel v soupravě.

simutrans-124.3/simutrans/text/cz/list.txt000066400000000000000000000023751474050137200207230ustar00rootroot00000000000000Nápověda - seznamy

Seznamy

Menu seznamy je rozcestníkem k dostupným seznamům. Díky nim máte přehled.

Menu otevÅ™ete kliknutím na ikonu seznamy v horní Äásti obrazovky.

Menu obsahuje následující položky:

seznam stanic: Seznam vÅ¡ech stanic a zastávek aktuálního hráÄe. V seznamu nejsou zahrnuty přístavy s pouze lodní dopravou (napÅ™. ropné ploÅ¡iny).

správa linek: Seznam všech linek.

seznam vozidel: Seznam vÅ¡ech silniÄních a železniÄních vozidel, letadel a lodí.

seznam měst: Seznam všech měst.

seznam zboží: Seznam všech dostupných typů přepravovatelného zboží. Pomůže v rozhodování, co se vyplatí přepravovat.

seznam továren: Seznam všech továren na hrací ploše.

turistické cíle: Všechny památky, památníky a jiné turistické zajímavosti.

seznam znaků: Seznam všech nápisů umístěných do hry.

simutrans-124.3/simutrans/text/cz/load.txt000066400000000000000000000013621474050137200206620ustar00rootroot00000000000000NápovÄ›da - naÄíst

NaÄíst

PÅ™es dialog naÄíst můžete naÄíst dříve uloženou hru a pokraÄovat v ní. Ovládání dialogu je velice podobné jako u dialogu ukládání.
JednoduÅ¡e vyberete hru, ve které chcete pokraÄovat, a kliknÄ›te na její jméno. Dialog se zavÅ™e, hra se naÄte, a pokud vÅ¡e probÄ›hne bez problému, zobrazí se potvrzovací zpráva.

Pozor: Hry uložené z jiných verzí Simutrans nemusejí být kompatibilní s touto verzí. Pokud se takovouto nekompatibilní hru pokusíte naÄíst, obdržíte chybové hlášení.

->Nápověda pro ukládání

->Informace o překladu

simutrans-124.3/simutrans/text/cz/load_relief.txt000066400000000000000000000021161474050137200222060ustar00rootroot00000000000000NápovÄ›da - naÄíst terén

NaÄíst terén

Dialog slouží k naÄtení výškové mapy z obrázku. Může být také použit k odstranÄ›ní již nepotÅ™ebných obrázků.

DialognaÄíst terém otevÅ™ete z dialogu VytvoÅ™it novou mapu tlaÄítkem naÄíst terén.

Kliknutím na jméno souboru vyberete a otevřete soubor.

Soubor můžete vybrat také napsáním názvu do pole nahoÅ™e a následovným kliknutím na tlaÄítko ano.

Kliknutím na tlaÄítko ne dialog zavÅ™ete bez naÄtení Äehokoliv.

Znak x slouží ke okamžitému smazání souboru s mapou. Pozor, na nic se neptá.

Některé předpřipravené terény jsou dostupné online na http://maps.simutrans.com.

Nové soubory musí být ve formátu .ppm nebo .bmp (nejlépe 256 bareb RLE compressed) a musí mýt umístěny v adresáři simutrans/maps/.

{Tip: Ke tvorbě nových map můžete použít například program gimp.}

simutrans-124.3/simutrans/text/cz/mailbox.txt000066400000000000000000000037461474050137200214060ustar00rootroot00000000000000Nápověda - poštovní schránka

Poštovní schránka

PoÅ¡tovní schránka obsahuje seznam zpráv a umožňuje urÄit, které zprávy se budou zobrazovat také na herní ploÅ¡e.

Dialog poštovní schránky otevřete z hlavního menu nebo stiskem klávesy [B].

TlaÄítko nastavení otevÅ™e dialog s nastavením, které zprávy se mají zobrazovat.

Pod jednotlivými záložkami se skrývají roztříděné zprávy.

Nastavení

Volby obsahují tÅ™i sloupce Ätvercových tlaÄítek.

První tlaÄítko zobrazí zprávu dole na liÅ¡tÄ›, druhé v novém oknÄ› a tÅ™etí tlaÄítko zobrazí zprávu v novém oknÄ› nastálo (dokud ji hrÃ¡Ä sám nezavÅ™e).

Nový rok: ZaÄal nový rok.

Novinky AI: Umělá inteligence otevřela novou linku.

Z měst: Obec staví novou radnici.

BloudÄ›ní: Vozidlo nemůže najít cestu do dalšího bodu v jízdním plánu. Mezi nejÄastÄ›jší příÄiny patří nespojené cesty, Å¡patnÄ› postavený semafor Äi chybÄ›jící elektrifikace.

Nový průmysl: Stavba nové továrny, Å™etÄ›zu továren nebo nové propojení továren způsobené vzrůstem poÄtu obyvatel.

Diskuse: Zprávy od ostatních hráÄů (pÅ™i hÅ™e po síti).

Nová vozidla: Je dostupné nové vozidlo nebo dříve dostupné vozidlo se stalo zastaralým a už se nevyrábí (pokud jste pÅ™i vytváření hry povolili zaÄít roku).

Přeplnění: Stanice nebo zastávka je přeplněna.

Problémy: HráÄova spoleÄnost je zadlužená nebo jiné závažné zprávy.

dopravní zácpy: Vozidla někde uvízla.

simutrans-124.3/simutrans/text/cz/mainmenu.txt000066400000000000000000000071161474050137200215570ustar00rootroot00000000000000Nápověda - hlavní menu

Hlavní menu

Hlavní menu je liÅ¡ta s nástroji nacházející se na horní stranÄ› okna. Vzhled ikon v hlavním menu a jejich poÅ™adí se liší v závislosti na grafické sadÄ›. NÄ›které ikony nemusejí být dostupné v závislosti na na Äase. Například v 19. století není zobrazena ikona s nástroji pro jednokolejku.

V hlavním menu naleznete ikony s těmito nástroji:

nastavení hry: Za disketou se nachází nastavení jazyka, barev, způsobů zobrazení, hráÄů stejnÄ› jako možnost uložení, uložení nebo ukonÄení hry.

mapa: Zobrazí dialog s mapou. Obsahuje rozliÄné volby pro různá zobrazení informací o objektech nacházejících se na povrchu i pod ním.

lupa: InspekÄní lupu využijete pÅ™i zjišťování informací o objektech. Můžete s ní klikat na cokoliv, aniž by bylo nÄ›co rozbito.

úprava terénu: Nástroje pro úpravu terénu slouží k urovnání terénu pro výstavbu železniÄní sítÄ› a také k výstavbÄ› stoupajících a klesajících tunelů.

menu s konstrukÄními nástroji je znaÄnÄ› promÄ›nlivé v závislosti na grafické sadÄ›, ne vÅ¡e je vždy dostupné. Naleznete v nÄ›m nástroje pro výstavbu:
- železnice
- jednokolejky/visutá železnice
- tramvajové trati
- silniÄní dopravy
- lodní dopravy
- letecké dopravy

speciální nástroje: Nabízejí nástroje, které se jinam nevešly, například pro stavbu elektrické sítě.

odstranit: Nástroj k odstraňování objektů ze hry.

editace mapy: Nástoj slouží k úpravÄ› stávající mapy. Nástroj je dostupný jen hráÄi oznaÄenému jako VeÅ™ejné služby.

správa linek: Obsahuje seznam linek, nástoje pro jejich správu a statistické údaje o nich.

seznamy Menu je rozcestníkem k jednotlivým seznamům:
- seznam zastávek
- seznam vozidel
- seznam měst
- seznam zboží
- seznam továren
- seznam turistických cílů

poÅ¡tovní schránka: Hlášení, zprávy, informace o novinkách a dopisy od spoluhráÄů najdete ve své poÅ¡tovní schránce. Reklamních letáků netÅ™eba se obávat.

finance: Přehled o hospodaření vaší firmy.

screenshot: Sejme snímek z obrazovky a uloží jej do adresáře screenshot.

Pauza: Pozastaví bÄ›h Äasu ve hÅ™e. I pÅ™i pauze můžete stavÄ›t a kupovat vozidla.

zrychlit: Zrychlí řádovÄ› bÄ›h Äasu. UžiteÄné, když nechcete Äekat. Vypnete opÄ›tovným stisknutím.
{Tip: Rychlost plynutí Äasu zmÄ›níte klávesami Äárka [,] a teÄka [.].}

simutrans-124.3/simutrans/text/cz/map.txt000066400000000000000000000023051474050137200205160ustar00rootroot00000000000000Nápověda - mapa

Mapa

V tomto oknÄ› můžete prohlížet vaÅ¡i mapu z ptaÄí perspektivy, a to vÄetnÄ› vÄetnÄ› mÄ›st, průmyslu, dopravy a dalších volitelných údajů.

Každý typ průmyslu je oznaÄen jinou barvou, s vysvÄ›tlivkami v dolní Äásti okna s mapou. Pokud nad nÄ›jaký objekt průmyslu pÅ™emístíte ukazatel myÅ¡i, zobrazí se jeho název a vyznaÄí se i s názvy odbÄ›ratelé.

Pokud chcete vidÄ›t více detailů, kdekoliv v oknÄ› s mapou kliknÄ›te pravým tlaÄítkem myÅ¡i, což způsobí pÅ™iblížení mapy (až do 2 stupňů). Oddálení je možné stisknutím tlaÄítka SHIFT a pravého tlaÄítka myÅ¡i.

V dolní Äásti okna se nalézají tlaÄítka, po jejichž stisknutí se na mapÄ› zobrazí (barvou dle intenzity) vybraná volba.
PÅ™i volbách "Cestujících" a "PoÅ¡ty" bude jednou barvou zobrazeno území, které obsluhují vaÅ¡e stanice pro cestující nebo pro poÅ¡tu. PÅ™i volbÄ› "TratÄ›" budou barevnÄ› zvýraznÄ›ny a odliÅ¡eny různé druhy železniÄních traťí - bílou normální, Äervenou elektrifikované, žlutou budou zvýraznÄ›ny semafory.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/monorailtools.txt000066400000000000000000000037401474050137200226460ustar00rootroot00000000000000Nápověda - nástroje pro jednokolejku a maglev

Nástroje pro jednokolejku/visutou železnici

Nástroje pro jednokolejku/visutou železnici slouží k výstavbě dopravní sítě pro přepravu cestujících.

Pokud jste pÅ™i vytváření mapy zadali volbu zaÄít roku, nástroje mohou být do urÄitého data nedostupné.

Menu s nástroji otevÅ™ete kliknutím na ikonu oznaÄenou nástroje pro jednokolejku/visutou železnici v hlavním menu.

Podržíte-li kurzor myÅ¡i na ikonou s nástroji zobrazí se název, cena, (mÄ›síÄní náklady na úrdžbu) a maximální rychlost.

Nástroje obsahují (zleva doprava):

přízemní jednokolejka: Trať postavíte stejným způsobem, jako železnici.

visutá jednokolejka: Může vést i nad domy a silnicemi.

návěstidla: Použití návěstidel je stejné jako u železnice a tramvají.

Odstranit visutou dráhu/jednokolejku: Nástroj odstraní trať visuté dráhy nebo jednokolejky. Při odstraňování dejte pozor na jednosměrné semafory.

mosty: Mosty slouží k přemostění údolí a jiných překážek.

depo: Vozidla pro jednokolejku/visutou dráhu koupíte v depu. Depo postavíte na konci dráhy.

zastávky: Nástroj slouží k výstavbě stanic. Klikněte na nástroj a pak pole s dráhou jednokolejky.

základy jednokolejky: Pomocí nástroje postavíte rozšíření stanice. Do stanice se vejde více cestujících. Také se zvýší náklady na údržbu.

simutrans-124.3/simutrans/text/cz/mouse.txt000066400000000000000000000007421474050137200210740ustar00rootroot00000000000000Nápověda - myš

Myš

levé tlaÄítko slouží ke klikání na objekty pomocí inspekÄní lupy, výstavbÄ› a veÅ¡kerému ovládání hry.

pÅ™i stisknutém pravém tlaÄítku myÅ¡i můžete posouvat s mapou.

koleÄko myÅ¡i slouží k pÅ™iblížení se k terénu nebo k oddálení se od nÄ›j.

Chování myši může být ovlivněnou stisknutím klávesy [Ctrl]

simutrans-124.3/simutrans/text/cz/new_world.txt000066400000000000000000000052541474050137200217470ustar00rootroot00000000000000Nápověda - nová mapa

Nová mapa

Dialog nová mapa vám poskytuje možnost vytvoÅ™it si mapu podle vlastních pÅ™edstav. Můžete ovlivnit reliéf mapy, hustotu průmyslu, poÄet mÄ›st aj.

Níže následuje krátký popis jednotlivých nastavení nové mapy:

Číslo mapy - UrÄuje reliéf mapy - kde jsou hory, voda atp.

Velikost mapy - UrÄuje, jak bude mapa velká, tzn. kolik bude mít ÄtvereÄků. Od 8x8, až po 4096x4096. StandardnÄ› je nastaveno 256x256. Mapa může být i obdélníková, například 256x8064. Obdélníkové mapy mohou mít jeden rozmÄ›r vÄ›tší než 4096 polí.
Důležité: Velké mapy jsou hodnÄ› nároÄné na paměť, zvažte proto, zda máte dostateÄnÄ› velkou operaÄní paměť, aby hra fungovala plynule.

Hustota průmyslu - UrÄuje, jaká bude hustota průmyslu - továren, obchodů aj. - na generované mapÄ›. Pokud si chcete hru ztížit, nastavte malé Äíslo, bude potom obtížnÄ›jší propojit průmysl.

PoÄet mÄ›st - UrÄuje poÄet mÄ›st na mapÄ›. Dostupné nastavení je od 0 až do 999 mÄ›st. StandardnÄ› je nastaveno 16.

Hustota provozu - Hustota soukromých aut ve mÄ›stech. StandardnÄ› je nastaveno 8. DoporuÄujeme si zvolit malé Äíslo, příliÅ¡ná hustota není vhodná. PozdÄ›ji mohou pÅ™ekážet vaÅ¡im vozidlům.

Úroveň vody - Nastavuje, jak vysoko bude voda nad dnem. PÅ™i nízkém Äísle moho být na mapÄ› zálivy a průlivy.

Výška hor - UrÄuje velikost nejvyšších hor na mapÄ›. Dostupné nastavení je od 0 až do 160. Nízké nastavení vytvoří malé kopce a průsmyky.

Zaoblení mapy - Hodnota, která urÄuje, jak hladké bude pÅ™echody mezi hranami reliéfu.

Náhodná mapa - Vybere náhodnou mapu (Äíslo mapy). Neovlivňuje ostatní nastavení.

Zobrazovat chodce - Nastaví, zda budou zobrazováni chodci. Toto nastavení je možné změnit během hry v dialogu zobrazení.

Střídat den a noc - Zapne mód střídání dne a noci. Toto nastavení je možné změnit během hry v dialogu zobrazení.

NaÄíst - Zobrazí dialog pro naÄtení hry.

ZaÄít hru - Vytvoří novou mapu podle nastavení. Pokud je nastavena velká mapa Äi jsou nastaveny velké hodnoty napÅ™. poÄtu mÄ›st Äi husoty průmyslu, vytváření zabere delší dobu.

Konec - UkonÄí hru bez dalšího potvrzení.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/options.txt000066400000000000000000000022571474050137200214420ustar00rootroot00000000000000Nápověda - nastavení hry

Nastavení hry

Dialog nastavení je branou pro nastavení rozliÄných možností chování Simutrans bÄ›hem hraní.
Následuje seznam voleb (s odkazy na detailnější informace), a krátký popis každého nastavení.

Jazyk - Umožňuje nastavit jazyk pro Simutrans.
Barva hráÄe - MÄ›ní barvu vaší spoleÄnosti.
Zobrazení - ZmÄ›ní nastavení obrazovky, jako denní a noÄní mód aj.
Zvuky - Nastavení voleb pro zvuky v Simutrans.
HráÄi - Nastaví vaÅ¡e poÄítaÄové konkurenty.
NaÄíst - NaÄte dříve uloženou hru.
Uložit - Uloží právě hranou hru.
Nová mapa - ZaÄít novou hru (nemůže být pÅ™eruÅ¡eno žádným dalším dialogem)
Konec - UkonÄí hru bez dalšího potvrzení.

Více informací o každé položce najdete přímo v její nápovědě nebo po kliknutí na odkaz výše.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/password.txt000066400000000000000000000006321474050137200216040ustar00rootroot00000000000000NápovÄ›da - zmÄ›na hráÄova jména a hesla

zmÄ›na hráÄova jména a hesla

Dialog slouží ke zmÄ›nÄ› názvu spoleÄnosti a nastavení hesla.

Dialog vyvoláte kliknutím na Ätverec vpravo vedle hráÄova jména v obchodním rejstříku (seznamu hráÄů)

Jesliže je za hráÄovým jménem Äervený Ätverec, je chránÄ›n heslem.

simutrans-124.3/simutrans/text/cz/players.txt000066400000000000000000000011411474050137200214150ustar00rootroot00000000000000NápovÄ›da - seznam hráÄů

Seznam hráÄů

V dialogu seznamu hráÄů můžete aktivovat a deaktivovat poÄítaÄové hráÄe, a prohlížet stav jejich kont.

K aktivaci/deaktivaci urÄitého poÄítaÄového hráÄe jednou kliknÄ›te na tlaÄítko vedle jména (barvy) hráÄe. Pokud hráÄe jednou aktivujete a pozdÄ›ji deaktivujete, tak nic co postavil se nezmÄ›ní, tzn. že jeho dopravní spoje budou dále fungovat. HráÄe pouze 'uspíte', takže nebude stavÄ›t nic nového, ani zavádÄ›t nové spoje.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/privatesign_info.txt000066400000000000000000000012561474050137200233130ustar00rootroot00000000000000Závora

závora

Závora umožňuje zakázat nebo povolit ostatním hráÄům vstup na silnici nebo železniÄní traÅ¥. Je užiteÄná k odfitrování aut veÅ™ejného hráÄe, která by jinak bránila vjezdu nákladních vozidel k nákladové rampÄ›.

Závoru postavíte pomocí nástojů pro stavbu železnice nebo silnice.

V levém horním rohu dialogu je napsáno, komu závora patří.

ZamáÄklé tlaÄítko pÅ™ed jménem hráÄe znamená vstup povolen.

Tip: Vozidel veřejné správy se lze zbavit kombinací závory a jednosměrky (na výjezdu).

simutrans-124.3/simutrans/text/cz/railtools.txt000066400000000000000000000070621474050137200217560ustar00rootroot00000000000000ŽelezniÄní doprava

ŽelezniÄní doprava

Tento dialog obsahuje nástroje pro stavbu kolejí, tunelů, návěstidel, stanic, dep, přejezdů a elektrifikování trati.

První jsou symboly různých druhů železniÄních tratí: Kliknutím na nÄ›který z nich se kurzor zmÄ›ní v obrázek odpovídajícího druhu železniÄní tratÄ›. Různé druhy tratí se liší v max. rychlost, cenÄ›, a cenÄ› za údržbu. Parametry každého druhu se zobrazí po najetí kurzorem nad jeho obrázek. Cena v závorce je cena z údržbu.
Pro stavbu železnice kliknete na místo, kde má traÅ¥ zaÄínat - musí být prázdné - a poté si vyberete místo, kde má traÅ¥ konÄit. Nesmí být moc daleko a musí být spojitelné (nesmí například pÅ™ekážet silnice). Problém se silnicemi Å™eší pÅ™ejezdy.

Symbol stanice: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek Äásti stanice. Stanice jsou používány pro naložení vÅ¡ech druhů výrobků a surovin, ale i cestujících a poÅ¡ty. Nádraží může být jakkoliv velké, ale jeho jednotlivé Äásti spolu musí sousedit a navíc nádraží delší než 8 ÄtvereÄků jsou zbyteÄná, protože takto dlouhý vlak ani nelze postavit. StavÄ›jte nádraží kdekoliv na trati, mimo stoupání, zatáÄek a jiných nerovností. Kapacita Äekajícího zboží a lidí je neomezená, avÅ¡ak pokud je od jednoho produktu na nádraží více než 1000 kusů, továrna, která jej produkuje pÅ™estane dodávat. ZaÄne až tehdy, když poÄet opÄ›t klesne pod 1000 kusů.

Symbol návÄ›stidel: Ty se používají, pokud potÅ™ebujete na jedné trati jezdit s více soupravami. Základní tvar je obousmÄ›rný, postaví se jedním kliknutím na existující železnici. Pokud kliknete podruhé na to samé místo,semafor uÄiní traÅ¥ jednosmÄ›rnou z jedné strany. TÅ™etím kliknutím obrátíte semafory a traÅ¥ je jednosmÄ›rná na druhou stranu. Takto je možné urÄovat, po jaké koleji pojedou vlaky z jedné strany a naopak. Když semafory zbouráte a budete mít traÅ¥ elektrifikovanou, elektrifikace zůstane nepoÅ¡kozená.

Symbol tunelu: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek tunelu. Tunely se používají pro protnutí hory v místech, kde by objížÄka znaÄnÄ› prodloužila dobu cesty vlakové soupravy. Pro stavbu tunelu musíte nÄ›jprve postavit na místÄ›, kde chcete zaÄít železnici. Místo, kde má tunel konÄit musí být pÅ™esnÄ› naproti zaÄátku tunelu. Tunel také nemůže stoupat, jeho konec musí být ve stejné výšce jako zaÄátek.

Symbol pÅ™ejezdu: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek železniÄního pÅ™ejezdu. Používá se v místÄ›, kde se silnice protíná se železnicí. PÅ™ejezd musí být postaven na již existují rovné Äásti železnice nebo silnice.

Symbol železniÄního depa: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek depa. Depa umožňují nakoupit vÅ¡echna dostupná kolejová vozidla, spojovat soupravy a vytvářet Äi pÅ™iÅ™azovat jízdní plány. Ke stavbÄ› si vyberte místo, kde konÄí železnice - nejlepší je tedy postavit si odboÄku.

Pozor: Každá Äást nádraží má kapacitu dvou kusů vozidel. Pokud je vlak delší než nádraží, zadní Äást vlaku nemůže být vyložena ani naložena. Dávejte proto pozor, aby nádraží bylo dostateÄnÄ› veliké.

->Stavba mostů
->Nápověda pro depo

->Informace o překladu

simutrans-124.3/simutrans/text/cz/removal_tool.txt000066400000000000000000000006731474050137200224510ustar00rootroot00000000000000Odstranit

odstranit

Nástroj odstranit použijte k odstranění nežádoucích věcí z jednoho pole.

Nástroj najdete v hlavním menu pod ikonou s Ärveným křížkem nebo buldozerem (pak128).

Nástroj vyvoláte též klávesou [r].

Nástroj může být použit i k odstanění chodců a městských vozidel.

simutrans-124.3/simutrans/text/cz/roadtools.txt000066400000000000000000000052261474050137200217540ustar00rootroot00000000000000NápovÄ›da - silniÄní doprava

SilniÄní doprava

PÅ™es dialog silniÄní doprava můžete stavÄ›t silnice, tunely, zastávky, nakládací místa aj.

První jsou symboly různých druhů silnic: Kliknutím na některý z nich se kurzor změní v obrázek odpovídajícího druhu silnice. Různé druhy silnic se liší v max. rychlost, ceně, a ceně za údržbu. Parametry každého druhu se zobrazí po najetí kurzorem nad jeho obrázek. Cena v závorce je cena z údržbu.
Pro stavbu silnice kliknete na místo, kde má silnice zaÄínat - musí být prázdné - a poté si vyberete místo, kde má silnice konÄit. Nesmí být moc daleko a musí být spojitelné (nesmí například pÅ™ekážet železnice). Problém se železnicí Å™eší pÅ™ejezdy.

Symbol zastávek: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek autobusové zastávky. Mohou zde tedy stavÄ›t pouze autobusy a také dodávky na poÅ¡tu. Pokud chcete pÅ™epravovat poÅ¡tu, musí být u zastávky postavena budova poÅ¡ty. Kapacita zastávky je jeden autobus (poÅ¡tovní dodávka) v každém smÄ›ru a 64 cestujících na jedno políÄko zastávky (poÄítá se i budova poÅ¡ty). Pro stavbu vyberte jakékoliv rovné místo na silnici.

Symbol nakládacího depa: Kliknutím na něj se kurzor změní v obrázek tohoto depa. Nakládací depa jsou používány pro naložení všech druhů výrobků a surovin. Nakládací depo má kapacitu dvou aut a 1000 kusů každého druhu zboží.

Symbol tunelu: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek tunelu. Tunely se používají pro protnutí hory, v místech, kde by objížÄka znaÄnÄ› prodloužila dobu cesty vozidla. Pro stavbu tunelu musíte nejprve postavit silnici. Místo, kde má tunel konÄit musí být pÅ™esnÄ› naproti zaÄátku tunelu. Tunel také nemůže stoupat, jeho konec musí být ve stejné výšce jako zaÄátek.

Symbol pÅ™ejezdu: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek železniÄního pÅ™ejezdu. Používá se v místÄ›, kde se silnice protíná se železnicí. PÅ™ejezd musí být postaven na již existují rovné Äásti železnice nebo silnice.

Symbol silniÄního depa: Kliknutím na nÄ›j se kurzor zmÄ›ní v obrázek depa. Depa umožňují nakoupit vÅ¡echna dostupná vozidla, spojovat přívÄ›sy a vytvářet Äi pÅ™iÅ™azovat jízdní plány. Ke stavbÄ› si vyberte místo, kde konÄí silnice - nejlepší je tedy postavit si odboÄku.

->Stavba mostů
->Nápověda pro depo

->Informace o překladu

simutrans-124.3/simutrans/text/cz/save.txt000066400000000000000000000022761474050137200207060ustar00rootroot00000000000000Nápověda - uložit

Ukládání hry

Pokud chcete uložit VaÅ¡i rozehranou hru, abyste jí mohli pozdÄ›ji naÄíst a pokraÄovat v ní, lze tak uÄinit pÅ™es dialog uložit. V tomto dialogu (stejnÄ› jako v dialogu naÄíst) také můžete smazat dříve uložené hry.

Hru můžete uložit do nového souboru, Äi pÅ™epsat soubor již existující. Pro uložení do nového souboru musíte nejprve vložit jméno tohoto souboru, a poté kliknout na tlaÄítko uložit. Dialog se zavÅ™e, hra se uloží, a pokud vÅ¡e probÄ›hne bez problému, zobrazí se potvrzovací zpráva.

PÅ™i mazání a pÅ™episování souborů dbejte zvýšené opatrnosti, protože pokud soubor jednou smažete (Äi pÅ™epíšete novou hrou), již nelze obnovit.
Ke smazání tedy kliknÄ›te na tlaÄítko X, umístÄ›né vedle jména souboru, který chcete smazat.
Pro přepsání dříve uložené hry pouze klikněte na jméno souboru k přepsání.
Hra bude bez dalšího potvrzení smazána (nebo přepsána).

->NápovÄ›da pro naÄítání

->Informace o překladu

simutrans-124.3/simutrans/text/cz/scenario.txt000066400000000000000000000007671474050137200215560ustar00rootroot00000000000000Nápověda - scénář

Scénář

Můžete hrát se scénářem - máte stanoveny cíle, jež musíte dosáhnout. Cílem může být dosáhnout urÄitého poÄtu pÅ™epravených cestující, pÅ™ipojit továrnu, mít na úÄtu nÄ›jaký pÅ™edem stanovený finanÄní obnos.

Okno dialogu obsahuje seznam scénářů sÄetnÄ› jejich popisu.

Kliknutím na název scénáře spustíte novou hru.

TlaÄítkem ne zavÅ™ete dialog.

simutrans-124.3/simutrans/text/cz/schedule.txt000066400000000000000000000043651474050137200215450ustar00rootroot00000000000000Nápověda - jízdní plán

Jízdní plán

Jízdní plán je možné vytvářet třemi způsoby:

1.)Klasicky v nÄ›jakém depu koupíte dopravní prostÅ™edek a zmáÄknete tlaÄítko jízdní plán. Zobrazí se vám tabulka. PÅ™idejte si zastávky kliknutím kurzoru na požadované místo zastavení. Je možné je zase odstraňovat tlaÄítkem smazat. Kliknete na hotovo a můžete dopravní prostÅ™edek vypustit tlaÄítkem start.

2.)PÅ™es funkci Nová linka. Po kliknutí na nÄ›j se vám zobrazí stejná tabulka jako v pÅ™edchozím případÄ›, postup je stejný, až na to, ze linka se uloží a je možné ji pojmenovat (tÅ™eba Praha 456), pozdÄ›ji vyvolat (řádek nahoÅ™e) a tlaÄítkem nastavit linku pÅ™iÅ™adit její zastávky dalšímu libovolnému vozidlu.

3.)StisknÄ›te klávesu "w", což je správa linek, o tom byla trochu Å™eÄ v minulém případe. Tam můžete pÅ™idat novou linku, smazat linku, Äi zmÄ›nit pro vÅ¡echna vozidla linky najednou(!). Postup operací je stejný, jako v pÅ™edchozích případech.

Nastavení Äekat na x% urÄuje, na kolik procent musí být vozidlo plné, aby mohlo vyjet. Tímto zabráníte zbyteÄnému ježdÄ›ní poloprázdných Äi úplnÄ› prázdných vozidel.

TlaÄítkem ZpÄ›tná jízda vložíte na konec jízdního plánu aktuální zastávky, avÅ¡ak v obráceném poÅ™adí a bez poslední a první. Vozidlo se tak nebude od poslední zastávky vracet k první hned, ale pojede postupnÄ› pÅ™es ostatní zastávky v jízdním plánu v obráceném poÅ™adí.

DoporuÄujeme využívat pouze linky a ne staré formy jízdních řádů, je to neefektivní pÅ™i pÅ™idávání nových vozidel na stejnou trasu. Linky jsou také pÅ™ehlednÄ›jší a v dialogu správy linek můžete také sledovat mnoho statistických údajů.
Pokud ale neÄekáte že by se mohla linka pozdÄ›ji rozšířit na více než 1 vozidlo, v nepoužívání linek vám samozÅ™ejmÄ› nic nebrání.

->Nápověda pro depo

->Informace o překladu

simutrans-124.3/simutrans/text/cz/server.txt000066400000000000000000000015541474050137200212540ustar00rootroot00000000000000Hra po síti

Hra po síti

Okno Informace o hÅ™e poskytuje údaje o herních serverech dostupných pro hru po síti, souÄasném stavu hry na nich, a to vÄetnÄ› detailů jako je datum, poÄet hráÄů, souprav apod.

V horní Äásti okna je zobrazen seznam herních serverů. Server vyberete kliknutím na text.

Po ním jsou tlaÄítka omezující výbÄ›r na servery se stejnou verzí programu a servery se stejným pakem.

Pokud požadovaný server není v seznamu, zadejte jeho ip adresu do políÄka.

TlaÄítkem dotázet se serveru se serveru zeptáte na informace o právÄ› probíhající hÅ™e.

Pomocí tlaÄítka hrát online se pÅ™ipojíte k vámi zvolenému serveru. PoÄkáte si, až se naÄte mapa a můžete hrát.

simutrans-124.3/simutrans/text/cz/settings.txt000066400000000000000000000430701474050137200216050ustar00rootroot00000000000000Nápověda - nastavení

Nastavení

V nastavení můžete zmÄ›nit takÅ™ka každý parametr hry, který byste mohli zmÄ›nit ruÄní úpravou souboru simuconf.tab. Každý parametr má stejný význam jako jemu odpovídající řádek v souboru simuconf.tab. Tam také naleznete aktuální verzi domumentace (v angliÄtinÄ›).

Upozornění:
Neuváženou zmÄ›nou parametrů můžete snadno udÄ›lat hru příliÅ¡ obtížnou až nehratelnou nebo naopak příliÅ¡ lehkou až vás nebude bavit. NÄ›které volby mÄ›ní nároÄnost hry na výkon poÄítaÄe.

Všeobecně

savegame_version: Verze formátu, v jakém má být hra uložena.

Výchozí hodnota: Nejnovější verze hry, např. 112.1.

drive_left: Povolením přepnete na levostraný provoz.

Výchozí hodnota: Vypnuto

signals_on_left: Semafory a silniÄní znaÄky se budou zobrazovat na levé stanÄ› komunikace.

Výchozí hodnota: Vypnuto

autosave: Jak Äasto se má hra automaticky ukládat:
- 0: neukládat
- 1: ukládat mÄ›síÄnÄ›
- 3: ukládat ÄtvrtletnÄ›
- 12: ukládat roÄnÄ›

Výchozí hodnota: 0

fast_forward: Jak moc to poběží rychle po kliknutí na ikonu zrychlit Äas.

Výchozí hodnota: 50

numbered_stations: Použije pÅ™i vytváření názvů stanic Äísla. Pokud zakážete, zastávky mají názvy složené z názvu mÄ›sta a názvů okolních budov (památek, továren) apod. DoporuÄuji nepovolovat.

Výchozí hodnota: Vypnuto

show_names: Způsoby zobrazení názvů stanic:
- 0: Jména měst a zastávek nejsou zobrazena.
- 1: Jména mÄ›st jsou v Å¡edivém rámeÄku, jména zastávek v modrém.
- 2: Jména mÄ›st nejsou zobrazena, nad zastávkou je zobrazen barevný indikátor stavu a grafické znázorníní množství Äekajících položek.
- 3: Jsou zobrazena jména měst a zastávek (jako při hodnotě 1) a navíc indikátor (jako při hodnotě 2)
Pozn: Způsob zobrazení názvů měst a zastávek je možné měnit i v průběhu hry pomocí klávesy [!].

Výchozí hodnota: 3

bits_per_month: Parametr urÄuje, jak rychle ve hÅ™e plyne Äas. Zvýšení hodnoty o jedna prodlouží délku mÄ›síce ve hÅ™e na dvojnásobek. Protože mÄ›síc trvá dvakrát déle, továrny mají dvojnásobnou produkci a infrastruktura vás stojí dvojnásobek na údržbu. Ale pÅ™epravíte dvakrát tolik.
Výchozí hodnota: 20

Tip: PÅ™ipadá-li vám, že se vlaky pohybují jako hlemýžÄ, ale nechcete, aby Äas plynul moc rychle? ZvyÅ¡te bits_per_month o 1 a pak hrajte pÅ™i dvojnásobné rychlosti.

add_player_name_to_message
Ve verzi 112.0 tato volba už chybí.

use_timeline:
- 0: Vypne zaÄít roku, zaÄít roku nepůjde zapnout.
- 1: Zapne zaÄít roku, zaÄít roku nepůjde vypnout.
- 2: Vypne zaÄít roku
- 3: Zapne zaÄít roku

Výchozí hodnota: 2

Tip: nastavte na 1 nebo 3.

starting_year: Rok, kdy bude zaÄínat nová hra. Pokud nastavíte příliÅ¡ nízké Äíslo, nemusí být dostupná žádná vozidla. Vhodné nastavení závisí na grafické sadÄ›.

Výchozí hodnota: 1930

Tip: Pokud jste zaÄali moc brzy a nejsou dostupná vhodná vozidla, pÅ™epnÄ›te se na hráÄe VeÅ™ejné služby a v menu editace mapy pÅ™idejte (i opakovanÄ›) jeden rok.

starting_month: MÄ›síc, v jakém zaÄne nová hra. Leden je 0, únor 1, atd.

Výchozí hodnota: 0

show_month: Ovlivňuje způsob zobrazení data v levém dolním rohu obrazovky. Hodnoty mají následující význam:
- 0: roÄní období (léto 1876)
- 1: mÄ›síc (Äerven, léto 1876 3:47h)
- 2: japonské datum (léto 1876/Äerven/2 3:56h)
- 3: americké datum (léto, Äerven 2 1876 3:47am)
- 4: Äeské datum (léto, 2. Äerven 1876 3:47h)
- 5: japonské datum bez roÄního období (1876/Äerven/12 2:47h)
- 6: americké datum bez roÄního období (Äerven 2 1876 3:47am)
- 7: Äeské datum bez roÄního období (18. Äerven 1876 3:47h)

Výchozí hodnota: 3

Pozn: V originále jsou volby 4 a 7 nazvány "německé datum".
Tip: Nastavte 4 nebo 7.

random_grounds_probability: Nastavuje Äetnost výskytu nepohybujících se objektů zpestÅ™ujících krajinu (groundobj), jako jsou balvany, kvÄ›tiny, krtiny, jezíka, kamení apod.
0 - vypnuto
jiná hodnota - na 1 pole s groundobj pÅ™ipadne n políÄek bez groundobj. Tj. pÅ™i random_grounds_probability=4 bude pÅ™ipadat na každá 4 políÄka bez groundobj jedno pole s 1 groungobj.

Výchozí hodnota: 10

random_wildlife_probability: Podobné jako předchozí, ale pro pohybující se objekty: ovce, husy, kamzíky apod.

Výchozí hodnota: 1000

pedes_and_car_info: Zapne zobrazování informací o chodcích a automobilech veÅ™ejné správy. Může být užiteÄné, pokud chcete vÄ›dÄ›t, jaká osobní auta jezdí po silnicích, ale může obtěžovat, chcete-li infornace o vlastních vozidlech nebo zastávkách.

Výchozí hodnota: Vypnuto

tree_info: Zapne/vypne, že pÅ™i kliknutí inspekÄní lupou na strom se zobrazí informace.

Výchozí hodnota: Zapnuto

grounf_info: Zapne zobrazení informací o terénu. Při kliknutí na zemský povrch se pak zobrazí souřadnice a název příslušného podnebného pásu.

Výchozí hodnota: Vypnuto

townhall_info: Povolí zobrazení informací o budově radnice (po kliknutí na budovu). Pokud není povoleno, kliknutí na budovu radnice zobrazí pouze informace o městě.

Výchozí hodnota: Vypnuto

only_single_info:

Výchozí hodnota: Zapnuto


Zobrazení

frames_per_second: Kolikrát je za 1s překreslována obrazovka.
Pozn.: Do 112.0 bylo k nalezení pod záložkou Všeobecně.

Výchozí hodnota: 25

simple_drawing_tile_size:

Výchozí hodnota: 24

simple_drawing_fast_forward:

Výchozí hodnota: Zapnuto

water_animation_ms:
Pozn.: Do 112.0 bylo k nalezení pod záložkou Všeobecně.

Výchozí hodnota: 250

window_buttons_right: TlaÄítka umístÄ›ná v záhlaví okna se zobrazí na pravé stranÄ›.

Výchozí hodnota: Vypnuto

window_frame_active:

Výchozí hodnota: Vypnuto

front_window_bar_color:

Výchozí hodnota: 1

front_window_text_color:

Výchozí hodnota: 215

bottom_window_bar_color:

Výchozí hodnota: 4

bottom_window_text_color:

Výchozí hodnota: 209

show_tooltips: Zapne zobrazování kontextové nápovÄ›dy - textu, co se objeví pÅ™i najetí myší nad tlaÄítko.

Výchozí hodnota: zapnuto

tooltip_background_color:

Výchozí hodnota: 4

tooltip_text_color:

tooltip_delay: Za jak dlouho se po najetí myÅ¡i nad tlaÄítko s kontextovou nápovÄ›dou zobrazí nápovÄ›da (v milisekundách).

Výchozí hodnota: 500

tooltip_duration: Jak dlouho bude zobrazena kontextová nápověda. (v milisekundách)

Výchozí hodnota: 5000

cursor_overlay_color

left_to_right_graphs: Mění směr osy x v grafech.
Pozn.: Do 112.0 bylo k nalezení pod záložkou Všeobecně.
DoporuÄuji zapnout.

Výchozí hodnota: Vypnuto

Hospodářství a města

remove_dummy_player_months:
Pozn.: Nové, od verze 112.1

Výchozí hodnota: 6

unprotect_abandoned_player_months:
Pozn.: Nové, od verze 112.1

Výchozí hodnota: 0

starting_money: Množství penÄ›z, s jakým zaÄínáte.

pay_for_total_distance:
0 - platba za rozdíl vzdálenosti zbývající do cíle (může být záporná)
1 - platba za rozdíl vzdálenost do příští přestupní stanice
2 - platba za rozdíl vzdálenosti od minulé stanice

Obtížnost zvýšíte nastavením hodnoty na 1 nebo 0 (ještě těžší).

Výchozí hodnota: 2

bonus_base_factor:
Pozn.: Nové, od verze 112.1

Výchozí hodnota: 125

first_beginner

Výchozí hodnota: Vypnuto

beginner_price_factor: Kolikrát má zaÄáteÄník dostat víc zaplaceno za pÅ™epravu. Údaj je v promile, tj. 1000 je stejnÄ› jako normálnÄ›.

Výchozí hodnota: 1500, tj 1,5 krát.

allow_buying_obsolete_vehicles: Povolí kupovat i již zastaralá vozidla.
Tip: DoporuÄuji povolit, v nÄ›kterých grafických sadách jsou mezery, a tak můžete používat aspoň zastaralá vozidla.

Výchozí hodnota: Zapnuto

used_vehicle_reduction: Ovlivňuje snižování hodnoty vozidel s přibývajícím věkem.

Výchozí hodnota: 0

toll_running_cost_percentage: Nastavuje výši mýta v závislosti na provozních nákladech vozidla/soupravy. K celkové výši mýta je pÅ™ipoÄítána i následující položka. Mýto se platí majiteli komunikace. Je to jeden z mála způsobů, jak může veÅ™ejná správa získat finance.
U nÄ›kterých grafických sad bývá nastaveno na 10 (Äti 10% z provozních nákladů).
Tip: Zapnutím výběru mýta můžete trochu přidat hře na obtížnosti.

Výchozí hodnota: 0

toll_waycost_percentage: Nastavuje procentuelní výši mýta v závislosti na mÄ›síÄních nákladech na údržbu komunikace (pÅ™i bits_per_month=18). Takto získaná Äástka je pÅ™ipoÄítána k pÅ™edcházející položce (toll_runnin_cost_percentage). Obvyklá hodnota je 5.

Výchozí hodnota: 0

just_in_time: Pokud má odbÄ›ratel plné sklady, dodavatel pÅ™estane dodávat zboží. Když ve skladu objejí volné místo, dodavatel opÄ›t zaÄne todávat zboží.
Poznámka: Pokud má dodavatelův sklad kapacitu vÄ›tší než 15000, pak funguje jako "Äerná díra" pro vÅ¡echno dodané zboží které pÅ™esáhne hodnotu 15000.

Výchozí hodnota: Zapnuto

maximum_intransit_percentage:
Pozn.: Nové, od verze 112.1

Výchozí hodnota: 0

crossconnect_factories

Výchozí hodnota: Vypnuto (Pro hru skompilovanou s volnou OTTD_LIKE je to Zapnuto)

crosconnect_factories_percentage

Výchozí hodnota: 33 (Pro hru skompilovanou s volnou OTTD_LIKE je to 100)

industry_incerase_every: PÅ™i jakém růstu obyvatel dojde i k růstu průmyslu. (Postaví se nová(é) továrna(y), novÄ› se propojí stávající.) Nižší Äíslo znamená víc továren.

Výchozí hodnota: 2000

factory_spacing: Minimální vzdálenost mezi továrnami.
Tip: Máte-li rádi dlouhé vlaky nebo nechcete-li mít výrobce a spotÅ™ebitele nalepené na sebe, doporuÄuji zvýšit. Aspoň na dvojnásobek. PÅ™i příliÅ¡ném zvýšení hodnoty nebude dost místa vhodného pro výstavbu továren.

Výchozí hodnota: 6

electric_promile

Výchozí hodnota: 330

allow_undeground_transformers:
Pozn.: Od verze 112.0

Výchozí hodnota: Zapnuto

passenger_factor

Výchozí hodnota: 16

minimum_city_distance: Minimální vzdálenost mezi městy.
Tip: DoporuÄuji zvýšit na dvojnásobek.

Výchozí hodnota: 16

special_building_distance:
Pozn.: Od verze 112.0

Výchozí hodnota: 3

factory_worker_radius: Z jakého okolí dojíždí do továrny zaměstnanci.

Výchozí hodnota: 77

factory_worker_minimum_towns: Z kolika minimálně měst dojíždí do továrny zaměstnanci.

Výchozí hodnota: 1

factory_worker_maximum_towns: Z kolika nejvýše měst budou do továrny dojíždět zaměstnanci.

Výchozí hodnota: 4

factory_arrival_periods

Výchozí hodnota: 4

factory_enforce_demand

Výchozí hodnota: Zapnuto

factory_worker_percentage

Výchozí hodnota: 33

tourist_percentage

Výchozí hodnota: 16

locality_factor[].year

locality_factor[].factor

passenger_multiplier

Výchozí hodnota: 40

mail_multiplier

Výchozí hodnota: 20

goods_multiplier

Výchozí hodnota: 20

growth_factor_villages

Výchozí hodnota: 400

growth_factor_cities

Výchozí hodnota: 200

growth_factor_capitals

Výchozí hodnota: 100

random_pedestrians

Výchozí hodnota: Zapnuto

stop_pedestrians

Výchozí hodnota: Zapnuto

citycar_level

Výchozí hodnota: 5

default_citycar_life

Výchozí hodnota: 36

Spojení

separate_halt_capacities

Výchozí hodnota: Vypnuto

avoid_overcrowding

Výchozí hodnota: Vypnuto

no_routing_over_overcrowded: Vypne pÅ™epravu Äehokoliv pÅ™es pÅ™eplnÄ›né zastávky.
Pokud se zastávka stane přeplněnou (je na ní více cestujících/pošty/zboží, než má kapacitu), nebude cestujícími použita jako přestupní stanice.
Tip: Zapněte pro zvýšení obtížnosti.

Výchozí hodnota: Vypnuto

station_coverage: Ovlivňuje velikost spádové oblasti stanice - kolik polí od zastávky bude pokryto.
Pozn: Nastavení se liší v závislosti na grafické sadÄ›, 2 je obÄas málo (pÅ™i více hráÄích není pomalu kam dávat ve mÄ›stech zastávky), 4 může být pro nÄ›koho příliÅ¡ moc, 3 je dobrý kompromis.

Výchozí hodnota: 2

max_route_steps

Výchozí hodnota: 1 000 000

max_hops

Výchozí hodnota: 2000

max_transfers

Výchozí hodnota: 9

Následující parametry jsou využívány pÅ™i automatické výstavbÄ› silnic na zaÄátku hry. Toto neměňte, pokud nevíte, co dÄ›láte!!!
way_straight (1)
way_curve (2)
way_double_curve (6)
way_90_curve (15)
way_tunnel (8)
way_max_bridge_length (15)
way_leaving_road (25)

Výdaje

maintenance_building

cost_multiply_dock: Náklady na výstavbu přístavu.

cost_multiply_station: Náklady na výstavbu železniÄní stavice.

cost_multiply_road_stop: Náklady na výstavbu silniÄní zastávky. Výsledná cena vzniká vynásobením této konstanty úrobní zasávky. (Vyšší úroveň znamená vyšší kapacitu)

cost_multiply_airterminal: Náklady na výstavbu letištního terminálu.

cost_multiply_post: Náklady na výstavbu pošty.

cost_multiply_headquarter: Náklady na výstavbu sídla spoleÄnosti.

cost_depot_air: Náklady na výstabu hangáru.

cost_depot_rail: Náklady na výstavbu železniÄního depa.

cost_depot_road: Náklady na výstavbu silniÄního depa.

cost_depot_ship: Náklady na výstavbu doků.

cost_buy_land: Náklady na umístění cedulky.

cost_alter_land: Náklady na změnu terénu pouhým nasypáním zeminy nebo vykopáním jámy.

cost_set_slope: Náklady na změnu terému, změny však potřebují opěrné zdi.

cost_found_city: Cena za založení nového města.

cost_multiply_found_industry

cost_remove_tree: Náklady na odstranění jednoho stromu.

cost_multiply_remove_haus: Náklady za odstranění domu. Číslo se pak násobí úrovní domu.

cost_multiply_remove_field: Náklady na odstranÄ›ní jednoho políÄka s polem.

cost_transformer: Cena za výstavbu trafostanice.

cost_maintain_transformer: Cena za údržu trafostanice.

Nastavení podnebí

Viz samostný dialog nastavení podnebí

forest_base_size

forest_map_size_divisor

forest_inverse_spare_tree_density

max_no_of_trees_on_square: Kolik stromů se může maximálně vyskytovat na jednom poli.
Pozn: PÅ™ekreslování stromů je nároÄné na výkon.

Výchozí hodnota: 3

tree_climates

Výchozí hodnota: 0

no_tree_climates

Výchozí hodnota: 0

Nápověda odpovídá verzi 112.1, poslední úprava 1.1.2013

simutrans-124.3/simutrans/text/cz/shiptools.txt000066400000000000000000000024121474050137200217640ustar00rootroot00000000000000Nápověda - lodní doprava

Lodní doprava

Tento dialog vám umožňuje stavět doky a přístavy.

První je symbol přístavů. Kliknutím na nÄ›j se vám kurzor zmÄ›ní v obrázek přístavu. Přístavy dovolují naloÄovat cestující a zboží z nedalekých továren a mÄ›st. Ke stavbÄ› přístavu si vyberte místo na konci pevniny, které pÅ™echází na vodu. Lze také stavÄ›t velké přístavy - musí se vÅ¡ak navzájem dotýkat, Äi být jinak spojeny - napÅ™. železniÄní zastávkou.

K nastavení lodní zastávky musíte vybrat políÄko, které je přímo pÅ™ed přístavem, ne vÅ¡ak samotný přístav!BuÄte rozvážní se stavbou přístavů, odstraňování přístavů jeÅ¡tÄ› není zcela funkÄní!

Dva podobné symboly jsou pro stavbu doku, rozdíl je pouze v jejich orientaci, severní nebo východní. Kliknutím na jeden z nich se vám kurzor zmÄ›ní v obrázek doku. Doky jsou urÄeny pro nákup vÅ¡ech dostupných typů lodí, a pro správu lodí zde zaparkovaných (prodávání, nastavování linek a jízdního plánu aj.). Ke stavbÄ› si vyberte místo na vodÄ›, které chcete, může to být jakýkoliv vodní Ätverec.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/signal_spacing.txt000066400000000000000000000017261474050137200227300ustar00rootroot00000000000000Nápověda - nastavení vzdálenosti semaforů

Nastavení vzdálenosti mezi semafory

Dialog slouží k nastavení vzdálenosti mezi semafory, pokud jsou umisťovány pomocí tažení.

Dialog vyvoláte kliknutím myši na ikonu se semaforem v nabídce s nástroji pro železnici, tramvaje nebo jednokolejku při stisknuté klávese [Ctrl].

Semafory můžete umísťovat tažením na již existující trať. Tj. stejným způsobem jako když jste stavěli koleje.

vzdálenost mezi semafory: Nastavuje, na kolik polí připadá jeden semafor.

Odstranit vložené semafory: Odstraní semafory které pÅ™esahují nastavené množství jednoho semaforu na n políÄek.

Nahradit vložené semafory: (zatím nic nedělá??)

simutrans-124.3/simutrans/text/cz/signals.txt000066400000000000000000000074311474050137200214060ustar00rootroot00000000000000Nápověda - semafory

semafory

Text popisuje způsob, jak umisťovat semafory pro železnici, úzkokolejku, tramvaje a jednokolejku.

PÅ™i prvním kliknutí se umístí návÄ›stidlo pro oba smÄ›ry, pÅ™i dalším kliknutí se zmÄ›ní na jednosnmÄ›né, pÅ™iÄemž průjezd opaÄným smÄ›rem je zakázán. Dalším kliknutím zmÄ›níte smÄ›r. ÄŒtvrtým kliknutím se vrátíte k návÄ›stidlu pro oba smÄ›ry.

návÄ›stidlo traÅ¥ováho bloku (Äervené)
Pouští vlak pokud je následující blok volný.
Příklad: V bloku U1 a U4 se nachází vlaky. Na návÄ›stidlu S1 je Äervená, protože v bloku U1 je vlak. Na návÄ›stidlech S2 resp. S3 je zelená, protože bloky U2 resp. U3 jsou prázdné. Vlak nacházející se v bloku U4 bude pokraÄovat až k návÄ›stidlu S1 a tam bude Äekat do té doby, než bude blok U1 volný. Používejte jej pro dvoukolejné tratÄ› nebo na výhybnách u jednokolejných tratí.
-[--U1---S1---U2---S2---U3---S3---U4----
---------S---------S---------S--------]-
S . . návěstidlo
U . . blok mezi návěstidly
[ ] . směr jízdy (vlevo, vpravo)

návěstidlo vlakové cesty (žluté)
NávÄ›stidlo navíc kopíruje stav následujícího návÄ›stidla. Je užiteÄné například u křížení dlou tratí.

návÄ›stidlo úseky s více zastávkami: Toto návÄ›stidlo použijete pÅ™i slepých odboÄkách s více zastávkami. UžiteÄné například v tramvajové dopravÄ›.

návÄ›stidlo volby staniÄní koleje
Používejte pÅ™ed stanicemi s více kolejemi, návÄ›stidlo vlaku vybere volnou kolej. Vlaky projíždÄ›jící stanicí se na tomto návÄ›stidlu zastaví, pokud nemají volnou celou cestu do svého cíle. Tomu lze pÅ™edejít umístÄ›ním návÄ›stidla zákazu volby staniÄní koleje na každý z výjezdů ze stanice.
_ _ _ _ x------x
-[--ZV-x--------x-C---
----C--x--------x-ZV--]-
_ _ _ _ x------x
C . . návÄ›stidlo volby staniÄní koleje
ZV .. návÄ›stidlo zákazu volby staniÄní koleje
x . . křížení kolejí
[ ] . směr jízdy vlaků (vlevo, vpravo)

návÄ›stidlo zákazu volby staniÄní koleje Toto návÄ›stidlo automaticky vybere pro vlak vhodnou volnou kolej. Viz ukázky užití návÄ›stidel v železniÄních stanicích.

ukázky použití návěstidel ve stanicích

legenda:
--- koleje
-+- koleje s křížením
-E- zákaz volby koleje
PS návěstidlo vlakové cesty (žluté)
PS[ PS] návěstidlo vlakové cesty (žluté) průjezdné jedním směrem
CS návěstidlo volby koleje
CS[ CS] návÄ›stidlo volby koleje průjezdné jedním smÄ›rem (smÄ›r je osnaÄen závorkou)
S S[ S] návěstidlo traťového bloku, průjezdné vlevo, průjezdné vpravo
[ ] směr jízdy u dvoukolejné trati [[ ]] jednosměrka

dvou- a vícekolejné nádraží na jednokolejné trati
----+--E-[[--+---PS---Nástupiště--PS--+--CS[---+----
_ _ +---CS]--+---PS---Nástupiště--PS--+--E-]]--+
Pozn: pokud není dostupné [[ a ]], můžete je v tomto schématu nahradit za PS[ a PS]

dvoukolejné nádraží na dvoukolejné trati
-[--S[----E---+---PS---Nástupiště--PS--+--CS[---S[---[-
-]--S]---CS]--+---PS---Nástupiště--PS--+---E----S]---]-

vícekolejné nádraží s průjezdnými kolejemi na dvoukolejné trati
_ _ _ _ _ _ _ +---PS---Nástupiště---PS---+
-[--S[---E---+-+---PS[---------------E----+--CS[---S[---[-
-]--S]--CS]--+-+---E-----------------PS]--+---E----S]---]-
_ _ _ _ _ _ _ +---PS---Nástupiště---PS---+

simutrans-124.3/simutrans/text/cz/simutrans.txt000066400000000000000000000014621474050137200217710ustar00rootroot00000000000000Nápověda - o překladu

O překladu

Překlad je organizován online komunitou pomocí webové aplikace - https://translator.simutrans.com/.
Původní verze OndÅ™ej Machulda a Jiří VoseÄek.

Oficiální stránky Simutrans se nacházejí na adrese http://www.simutrans.com. Zde naleznete poslední verze, odkazy, a další informace...
Aktuální informace o dění okolo Simutransu naleznete na blogu - http://blog.simutrans.com.
Velké množství informací obsahuje fórum - http://forum.simutrans.com.
Addons - "přídavky" do Simutrans lze najít na http://addons.simutrans.com a na fóru.

Simutrans (c) Hj. Malthaner & Simutrans team

simutrans-124.3/simutrans/text/cz/slopetools.txt000066400000000000000000000031511474050137200221440ustar00rootroot00000000000000Nápověda - úprava terénu

úprava terénu

Nástroje pro úpravu terénu umožňují zvýšit nebo snížit terén, tytvořit za pomoci opěrných zdí rovinu nebo jen udělat svah šikný v požadovaném směru. Slouží také k tvorbě stoupajících a klesajících tunelů.

Menu s nástroji otevřete kliknutím na ikonu úprava terénu v hlavním menu.

Nástroj můžete použít na polích bez silnic, železnic, budov apod. Výjimku tvoří nástroj upravit svah použitý na koncích komunikací.

Nástroj vyberete kliknutím n příslušnou ikonu.

zvýšit zemi/snížit zemi: zvýší/sníží terén
Kursor se změní na šipku nahoru nebo dolu.
Ke zvýšení resp. snížení lze též použít klávesové zkratky [u] resp. [d].
{Tip: Pokud místo klikání budete držet levé tlaÄítko myÅ¡i, můžete snadno vytvoÅ™it velkou plochu terénu o stejné nadmoÅ™ské výšce.

upravit svah: upraví svah do požadovaného tvaru za pomoci opěrných zdí. Maximální rozdíl mezi sousedními poli je omezený na rozdíl 2 výškových stupnů.
Pozn: pomocí tohoto nástroje se dá vytvořit stoupání a klesání v tunelu.

obnovit přírodní terén: Obnoví na daném políÄku pÅ™irozený snah, odstraní opÄ›rné zdi.

{Tip: Úprava terénu se provádí snáze se zapnutou mřížkou, zapnete ji klávesou [#] }

simutrans-124.3/simutrans/text/cz/sound.txt000066400000000000000000000016701474050137200210750ustar00rootroot00000000000000Nápověda - zvuk a hudba

Zvuk a hudba

Zde můžete podle svého přizpůsobit zvuky, které uslyšíte, a také hudbu, která bude hrát na pozadí hry.

Nastavení hlasitosti zvuků a hudby se provádí pomocí liÅ¡ty, pÅ™i pohybu doprava se zvyÅ¡uje hlasitost, pÅ™i posunu doleva se hlasitost snižuje. Hlasitost zvuku ovlivňuje hlasitost zvuků pÅ™i stavÄ›ní a hlasitost zvuků vozidel. Hlasitost hudby ovlivňuje hlasitost právÄ› pÅ™ehrávané písniÄky.
Poslední tlaÄítka slouží k pÅ™evíjení hudby. Levé tlaÄítko pÅ™evine písniÄku na zaÄátek, pravé na konec. Pokud nejsou nakonfigurovány žádné písnicky, jsou tyto tlaÄítka neaktivní.

Pozor: Hudba není dodávána spoleÄnÄ› se Simutrans, musíte si ji sami do adresáře Music nakopírovat. Tam také najdete další nápovÄ›du (anglicky).

->Informace o překladu

simutrans-124.3/simutrans/text/cz/special.txt000066400000000000000000000037131474050137200213650ustar00rootroot00000000000000Nápověda - speciální stavby

Speciální stavby

Panel s nástroji speciálních staveb obsahuje stavbu, které nejsou přímo spojené s konkrétním způsobem přepravy.

Panel se speciálními stavbami otevřete z hlavního menu.

Speciální stavby obsahují nástroje:

Pošta: Nástrojem postavíte poštu. Poštu lze posstavit jen vedle již existující stanice.

Rozšíření stanice: Ke stanici lze přistavět budovy rozšiřující její kapacitu, jako například překladiště automobilů, stáje pro dobytek, sklady, zásobník plynu, zásobník na kapaliny apod. Tyto budovy jsou v každé grafické sadě trochu jiné.

P+: ZmÄ›ní hráÄe. Stejného efektu dosáhnete klávesovou [P]. Existuje-li více hráÄů, zobrazte si klávesou [k] obchodní rejstřík a v nÄ›m vyberte požadovaného hráÄe.

založit nové město: Nástrojem postavíte nové město.

Zasadit strom: Nástrojem umístíte na mapu náhodný strom.

elektrické vedení: Nástrojem postavíte vedení vysokého napětí.

Transformátorová stanice: Nástrojem postavíte trafostanici. Trafostanice postavená u továrny může zvýšit produkci továrny.

ZnaÄka: Nástroj umístí na herní ploch nápis. Může sloužit například k pojmenování Å™eky nebo jako nástÄ›nka pro ostatní hráÄe v síťové hÅ™e.

prohodit zastávky:Prohodí v jízních řádech dvě pole na mapě. Nespleťte si ji s následujícím nástrojem, mají podobné ikony.

ZveÅ™ejnit zastávku: PÅ™evede zastávku na hráÄe VeÅ™ejné služby.

simutrans-124.3/simutrans/text/cz/station.txt000066400000000000000000000031621474050137200214240ustar00rootroot00000000000000Stanice

Dialog stanice

InformaÄní dialog lze zobrazit po kliknutí na libovolnou stanici. Poskytuje různé užiteÄné informace o stanici, vÄetnÄ› možnosti zobrazení grafů. Můžete také u každé vaší stanice kdykoliv zmÄ›nit název.

Dialog se skládá ze seznamu, nÄ›kolika ovládacích tlaÄítek nahoÅ™e, a popřípadÄ› také z Äásti s grafy (viz níže).
Vstupní pole nahoÅ™e vám umožňuje zmÄ›nit název. TlaÄítko detaily zobrazí detaily o stanici - jaké je odsud přímé spojení, jaké linky obsluhují tuto stanici nebo tÅ™eba jaké zboží je napojeným průmyslem produkováno a vyžadováno.

Hlavní informace jsou zobrazeny uprostÅ™ed a v dolní Äásti dialogu. Na seznamu se ukazují komodity, které Äekají na odvezení ze stanice. Komodity lze Å™adit pomocí tlaÄítka pÅ™es/poÄet/cíl.

Seznam zobrazuje komodity již třídÄ›né podle druhu, každý druh komodit je pohromadÄ› v jedné Äásti.

Dále jsou komodity uvnitÅ™ každé Äásti třídÄ›ny podle toho, kam má být která odvezena, pÅ™es jakou pÅ™estupní stanici Äi dle poÄtu (závisí na tlaÄítku pÅ™es/poÄet/cíl).

TlaÄítkem Chart lze zapnout zobrazení grafů. Zde si pomocí tlaÄítek můžete vybrat, jakou statistickou informaci o stanici chcete zobrazit.

Poznámka: Dialog je neustále obnovován, proto vidíte vždy aktuální informace o stanici, bez potřeby dialog znovu zavírat a otevírat.

->Informace o překladu

simutrans-124.3/simutrans/text/cz/station_details.txt000066400000000000000000000016331474050137200231320ustar00rootroot00000000000000Detily stanice

detaily stanice

Detaily stanice obsahují informace o stanici, které se nevešly do dialogu stanice.

Okno obsahuje následující informace:

Připojené továrny: Továrny nacházející se ve spádové oblasti dané stanice
{Tip: Spádovou oblast zobrazíte klávesou [v].}

Zboží vyžadované pro okolní průmysl: Zboží, které můžete prostřednictvím této zastávky dovážet.

linky obsluhující tuto stanici: Seznam linek obsluhujících tuto stanici.

Vozidla bez zadané linky ...: Pokud používáte linky, tak by zde nemělo být nic.

PÅ™eprava odkud, Äeho a kam: Seznam zboží dopravovaného z této stanice vÄetnÄ› míst kam je dopravováno.

simutrans-124.3/simutrans/text/cz/trafficlight_info.txt000066400000000000000000000016611474050137200234260ustar00rootroot00000000000000NápovÄ›da - silniÄní semafory

silniÄní semafory

SilniÄní semafory slouží k řízení dopravy na kÅ™ižovatkách.

Nástroj pro umístÄ›ní silniÄního semaforu naleznete v menu silniÄní dopravy.

Okno s nastavením silniÄních semaforů získáte kliknutím inspekÄní lupou na pole se semaforem. U semaforů lze nastavit délku fáze pro jednotlivé smÄ›ry z Äasový posun sepnutí.

V prvním poli (zleva) se nachází délka fáze (v sekundách) pro průjezd severojižním směrem (z pravého horního rohu do levého dolního rohu).

V druhém poli nastavíte délku fáze (v sekundách) pro průjezd od východu na západ a od západu na východ.

V tÅ™etím poli upravíte Äasový posuv, v jakém mají semafory spínat, aby byl co nejplynulejší průjezd.

simutrans-124.3/simutrans/text/cz/tramtools.txt000066400000000000000000000042431474050137200217700ustar00rootroot00000000000000Nápověda - tramvaje

tramvaje

Nabídka obsahuje nástroje ke stavbě tramvajové přepravní sítě - kolejí, troleje, zastávek a depa.

Tramvaje mají nižší provozní náklady než autobusy což je vÅ¡ak vyváženo vysokými náklady na údržbu tramvajových tratí. Provozovat tramvaje se vyplatí pÅ™i pÅ™epravÄ› vyššího poÄtu cestujících nebo ve mÄ›stech s velkým poÄtem aut.

Nabídku s nástroji k výstavbě tramvajové tratě otevřete kliknutím na ikonu tramvaje v hlavním menu.

Najedete-li kurzorem myÅ¡i nad ikonu s naástrojem, zobrazí se popisek obsahující oznaÄení nástroje, náklady na výstavbu, (náklady za údržbu) a maximální rychlost. Menu obsahuje tyto nástroje:

tramvajová trať: Nástroj slouží k výstavbě tramvajové trati. Tramvajovou trať je možné umístit i na existující silnice. Většina tramvají jezdí na elektrickou energii, trať bude potřeba ještě elektrifikovat.

mosty: Tramvajový most obvykle moc nevyužijete. Tramvajovou traÅ¥ postavíte i na silniÄním mostu.

tunel: Nástroj použijete pro výstovbu tunelu, trati pro podzemní šalinu.

trolej: Nástrojem elektrifikujete tramvajovou trať. Bez elektrifikace byste mohli používat jen koňmi takžené tramvaje.

odstranit traÅ¥: Nástroj odstraňuje traÅ¥ vÄetnÄ› elektrifikace. PÅ™i odstraňování dejte pozor na jednosmÄ›rné semafory, aÅ¥ odstraníte jen to, co chcete.

semafory: Nástroj slouží k umístění semaforů na trať.

tramvajové depo: V depu koupíte tramvaje. Nezapomeňte jej elektrifikovat, jinak elektrické tramvaje nebudou dostupné.

tramvajová zastávka: Nástrojem postavíte tramvajovou zastávku. Tramvaje mohou zastavovat i na autobusových zastávkách.

simutrans-124.3/simutrans/text/cz/underground.txt000066400000000000000000000042671474050137200223060ustar00rootroot00000000000000Nápověda - tunely a podzemí

tunely a podzemí

Tunely můžeme stavÄ›t dvÄ›ma způsoby: buÄ rovné přímo z povrchu nebo komplikovanÄ›jší za pomoci podzemního módu.

přímé tunely

Přímý tunel postavíte kliknutím na ikonu tunelu a následovným kliknutím na svah kopce, kde má tunel zaÄínat. Aby se tunel postavil, musejí být svahy u ústí tunelu správnÄ› Å¡ikmé.

komplikovanější tunely

KomplikovanÄ›jší tunely je nutno stavÄ›t poÄástech. Nejprve postavíme stup pod zem. Klikneme na nástroj s tunelem a pak držíme stisknutou sklávesu [Ctrl] a myší klikneme na místo s zamýšleným poÄátetkem tunelu. Pak se pÅ™epneme do podzemního modu.

V podzemním modu nebo při zobrazení jednotlové výškové vrstvy stavíte podzemní trať stejným způsobem, jako nadzemní, pouze používáte ikonu tunel.

Tunely mohou stoupat a klesat. Postavte tunel k místu zamýšleného stoupání/klesání. V menu úprava terénu kliknÄ›te na upravit svah (to s opÄ›rnou zdí). Pak kliknÄ›te na konec železniÄní trati v tunelu. A máte v tunelu kopec.

V tunelu můžete umisťovat stanice, semafory a depo stejným způsobem jako na povrchu.

podzemní mód(y)

Ve hře existují dva způsoby, jak zobrazit komunikace pod zemským povrchem.

podzemní mód: Stiskem klávesy [U] se zobrazí jen terén bez vÅ¡ech budov a stromů. Krom toho se zobrazí vÅ¡echny tunely. To je užiteÄné, pokud se chcete podívat, co vÅ¡e se nachází pod zemí. Umožňuje stavÄ›t tunely pod mÄ›stem, k výstavbÄ› tunelů pod vysokohostkým masivem je vhodnÄ›jší použít zobrazení po vrstvách.

zobrazení po vrstvách: Slouží k zobrazení komunikací v jednostlivých výškových vrstvách. Použijete jej nejen v podzemí ale i pÅ™i stavbÄ› železniÄní trati pod mostem.
NajeÄte kurzorem myÅ¡i na pole v úrovni, kterou chcete zobrazit. StistnÄ›te [Ctrl U].

simutrans-124.3/simutrans/text/cz/window.txt000066400000000000000000000021411474050137200212460ustar00rootroot00000000000000Nápověda - uživatelské rozhraní

uživatelské rozhraní

Hra simutrans se ovládá pomocí myši a klávesových zkratek.

Uživatelské rozhraní je rozdÄ›leno na tÅ™i Äásti: hlavní menu, zobrazení herní plochy a stavovou liÅ¡tu.

stavová liÅ¡ta: Stavová liÅ¡ta v dolní Äásti zobrazuje důležité aktuální informace:

- datum a Äas: Aktuální datum a Äas, způsob zobrazení data a Äasu upravíte v nastavení.

- jméno hráÄe: Je jméno právÄ› aktivního hráÄe. Mezi hráÄi lze pÅ™epínat klávesou P.

- stav konta: Kolik penÄ›z máte na úÄtu.

- souřadnice: Souřadnice aktuální polohy kurzoru myši.

- rychlost plynutí Äasu: Jak rychle ve hÅ™e plyne Äas. Plynutí Äasu zmÄ›níte klávesami [.] a [,].

simutrans-124.3/simutrans/text/de.tab000066400000000000000000001640441474050137200176550ustar00rootroot00000000000000Deutsch PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: de Deutsch # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Abfahrtszeiten als Datum im Monat AMBIENT_SOUND Umgebungsgeräusche CASH_SOUND Kassenklingeln cl_btn_filter_disable aus cl_btn_filter_enable an cl_btn_filter_settings einstellen cl_btn_sort_asc aufsteigend cl_btn_sort_desc absteigend cl_btn_sort_id ID-Nummer cl_btn_sort_income Gewinn cl_btn_sort_name Bezeichnung cl_btn_sort_type Typ clf_btn_alle alle clf_btn_invers inv. clf_btn_keine keine climate area percentage Größe Klimaregion Continue Game Weiterspielen CROSSING_SOUND Bahnübergänge FACTORY_SOUND Fabriklärm Find matching convois Finde gleiche Fahrzeuge gl_btn_sort_bonus nach Bonus gl_btn_sort_name nach Namen gl_btn_sort_revenue nach Erlös gl_btn_unsort unsortiert height based Klima nach Höhe hl_btn_filter_disable aus hl_btn_filter_enable an hl_btn_filter_settings einstellen hl_btn_sort_asc aufsteigend hl_btn_sort_desc absteigend hl_btn_sort_name Bezeichnung hl_btn_sort_type Typ hl_btn_sort_waiting Wartend hlf_btn_alle alle hlf_btn_invers inv. hlf_btn_keine keine humidities Feuchtigkeitgrenzen Install Installiere Paks Lake See Lake height Maximale Seehöhe Maximize height levels Mehr Höhenstufen moisture land Anstieg über Land moisture water Anstieg über Wasser Networks Transportnetz Num pad keys always move map Numlock ignorieren Open Sea Meer Queueing Tendenz Wartend rainfall Luftfeuchte Reselect closes tools Werkzeug abwählen durch erneute Auswahl Return to menu Neues Spiel Road toll Maut Scenario Missionsstatus sea maritim Single GUI Einfenstermodus Sound range: Reichweite: Start this as a server Dieses Spiel als Server starten. temperature borders Temperaturgrenzen temperature-humidity based Klima nach Wetter TOOL_SOUND Werkzeuggeräusche TRAFFIC_SOUND Verkehrslärm Transfers Durchsatz #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Polarklima desert Wüstenklima mediterran Mittelmeerklima rocky Alpines Klima temperate gemäßigtes Klima tropic Tropenklima tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Das Laden des Szenarioskripts ist fehlgeschlagen A building blocks the construction Ein Gebäude ist im Weg! Bridge blocked by way below or above. Die Höhe der Brücke über dem Weg darunter reicht nicht aus. Can't buy obsolete vehicles! Es können keine veralteten Fahrzeuge gekauft werden! Cannot alter water Das Becken kann nicht gefüllt bzw. geleert werden. Cannot build on a double slope! Kann nur auf flachem Hang oder Ebenem Grund gebaut werden! Cannot built depot here! Hier kann kein Depot gebaut werden!\n\nEin Depot kann nur auf einem Wegende\n\nmit dem passenden Typ gebaut werden.\n Cannot built this station/building\nin underground mode here. Dieses Gebäude / Haltestelle kann nicht\nim Untergrund gebaut werden. Cannot connect to the\ncenter of a double slope! Eine Brücke kann nicht in der Mitte eine steilen Kachel enden!\nEvt. kann man dies mit den Erdbewegungswerkezugen ändern. Cannot create generic line!\nSelect line type by\nusing filter tabs. Kann keine Linie vom Typ\n'Alle' erzeugen.\n\nWählen Sie einen\nanderen Linientyp aus Cannot create socket Kann Netzwerk nicht initialisieren! Cannot rotate this building! Dieses Gebäude kann nicht gedreht werden! Client closed connection during transfer Die Verbindung wurde vom Client während des Herunterladens getrennt. Convoi handles exhausted! Maximale Fahrzeugzahl (Convois) erreicht. Convoy already deleted! Fahrzeuge wurden schon gelöscht! Corrupt file Die Datei ist kaputt oder zu kurz. Could not open file Konnte nicht auf die Datei zugreifen. Das Feld gehoert\neinem anderen Spieler\n Das Grundstück\ngehört einem\nanderen Spieler!\n Depots cannot be built on runways! Ein Hangar kann nicht auf Landebahnen gebaut werden! Depots must be built on flat dead-end way tiles! Ein Depot kann nur auf einem flachen Wegenden gebaut werden! Der Besitzer erlaubt das Entfernen nicht Der Besitzer\nerlaubt das\nEntfernen nicht.\n Diese Zusammenstellung kann nicht fahren!\n Diese Zusammenstellung\nkann nicht fahren!\n Failed to write file Konnte die Datei nicht schreiben. Flugzeughalt muss auf\nRunway liegen!\n Flugzeuge können\nnur auf Flughäfen landen!\n Forbidden by scenario Verboten in diesem Szenario Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Hier kann dieses\nFlughafengebäude nicht\ngebaut werden!\n In order to lock the game, you have to protect the public player by password! Um die Karte gegen Spielerwechsel zu schützen, muß die Öffentliche Hand passwortgeschützt sein! Loading a new game will end the current server session! Das Laden eines neuen Spieles wird das laufende Netzwerkspiel beenden! Lost connection\nto server! Server antwortet\nnicht mehr!\n\nSpiel ist nur\nnoch lokal! Lost synchronisation\nwith server. Spiel ist nicht\nmehr synchron zum\nServer!\n\nBitte neu\nladen!\n Maglevhalt muss auf\nMaglevschiene liegen!\n Magnetbahnhalt muss auf Magnetschiene liegen. Monorailhalt muss auf\nMonorail liegen!\n Monorailhalt muss auf\nMonorailschiene liegen!\n Monorails are not available yet! Noch keine Monorailbahn verfügbar! More than one possibility to build this dock found. Mehrere Ausrichtungen für Bau des Docks möglich. Dock noch einmal mit Strg+Klick auswählen und die Ausrichtung im folgenden Fenster wählen. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Schmalspurbahnhalt muss auf\nSchmalspurbahnschienen liegen!\n No bridges over runways! Keine Brücken über Landebahnen bitte! No curves on runways Keine Kurven auf Startbahnen! No suitable crossing Keine passende Kreuzung! (Weg zu schnell?) No suitable way on the ground! Halte können nur auf\ngeraden ebnen geeigneten\nWegen gebaut werden! No through station here! Hier kann kein Bahnhof oder\neine Haltestelle\ngebaut werden. Not allowed to copy object. Kann diese Ding nicht kopieren!\n(Braucht anderen Benutzer oder ist veraltet.) Not enough bytes transferred Vorzeitiges Übertragungsende! Not enough clearance. Zwischen zwei Wegen müssen zwei Höhenstufen liegen! Not enough empty space Nicht genug freier Platz zum Speichern. Not enough money! Zum Bauen reicht das\nGeld nicht mehr! Not initialized Konnte die Bibliothek nicht initialisieren. On narrowgauge track only!\n Ein Schmalspurhalt muss auf Schmalspurgleisen liegen. Only public player can lock games! Spieler können nur durch die öffentliche Hand geschützt werden. Only up and down movement in the underground! Eine Kachel im Untergrund muss kann nur mit dem Absenken/Anheben-Werkzeugen verändert werden! Out of funds Dein Geld reicht nicht mehr dafür! Post muss neben\nHaltestelle\nliegen!\n Ein Stationsgebäude (z.B. \nPostfiliale, Lager)kann \nnur auf einem freien Feld \nneben einer Haltestelle \ngebaut werden! Protocoll error (expecting game) Protokollfehler Server busy Server antwortet nicht! Server version too new Der Server benutzt eine neuere Programmversion. Ship depots must be built on water! Eine Werft muss auf dem Wasser gebaut werden! Show all revenue messages Alle Buchungen an Halten Show no revenue messages Keine Buchungen an Halten Show only player's revenue Nur eigene Buchungen anzeigen Terraforming not possible\nhere in underground view Diese Landschaftsveränderung ist\nnur auf dem Kartenboden möglich.\n This tunnel branches. You can try Control+Click to remove. Dies ist ein Tunnelsystem. Evt. kann es mittels Strg+Klick gelöscht werden! Too far away to merge stations! Halt zu weit entfernt zum Verbinden. Unknown error Allgemeiner Fehler Upgrade must have\na higher level Neue Station muss ein\nhöheres Level haben. Vehicle %s cannot choose because stop too short! Die Haltsuche von %s scheitert an zu kurzen Halten! Watertable reached Kann das Land nicht unter das\nGrundwasserniveau absenken. #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s

Inhalt

%1$s

Hinweise zur Bedienung

%2$s

Spiel starten

%4$s

Wie spiele ich?

%5$s

Werkzeuge

%3$s

weitere Dialoge

%6$s Keyboard Help\n

Keyboard Help

\n Tastaturbefehle\n

Tastaturbefehle

\nDie folgenden Tastaturbefehle kennt Simutrans:

\nCtrl(Strg) + Klick - unterdrücke Infofenster (nur an einigen Orten)
\nCtrl(Strg) + Werkzeug - auf oberer Ebene agieren bzw. nur gerade Wege bauen.
\n\nEsc, Delete: Oberstes Fenster schließen
\nBackspace: Alle Fenster schließen
\nBild hoch/Bild runter, </>: Zoom kleiner/größer
\nCursortasten und Ziffernblock verschieben die Karte\n

\nFolgende Befehle sind frei belegbar:
\n At least one stop is connected to the town. Mindestens ein Halt des Spielers ist an ein Gebäude in der Stadt angebunden. At least one tile is connected to one stop. Mindestens ein Gebäude ist mit einem Halt eines Spielers verbunden. Color according to transport capacity left Farbe zeigt freie Transportkapazität an. Color-coded terrain according to altitude. Zeige/Verstecke Geländehöhenrelief. Decrease water height Wasser ablassen Highlight railroad tracks Schienewege hervorheben Highlite depots Zeige alle Depots. Highlite electrical transmission lines Hochspannungslinien hervorheben. Highlite factories Zeige Fabriken. Highlite forests Zeige Wälder. Highlite tourist attraction Zeige Sehenswürdigkeiten. Increase water height Wasserstand um eins erhöhen Open station/stop details Stationsdetails anzeigen Overlay city limits Zeige Stadtgrenzen. Overlay passenger destinations when a town window is open Falls Stadtfenster göffnet: Zeige Passagier-/Postziele der Stadt. Overlay schedules/network Lege Plan alle bestehenden Verbindungen über die Karte. Overlay town names Zeige Stadtenamen. Please click on the map to add\nwaypoints or stops to this\nschedule. Wegpunkte und Halte werden durch\nAnklicken der Ziele auf der Karte\nhinzugefügt. Remove double stops from schedule Aufeinanderfolgende Doppeleinträge entfernen Set tile climate %s %s für diesen Boden Show capacity and if halt is overcrowded Zeige Haltkapazität und -status. Show how many convoi reach a station Zeige Anzahl haltender Fahrzeuge. Show how many people/much is waiting at halts Zeige Anzahl wartend. Show initial passenger departure Zeige Fahrtantritt Passagiere/Post. Show level of city buildings Zeige Stadtgebäude entsprechend der Passagiererzeugung. Show mail service coverage/mail network Zeige Stationsabdeckung/Verbindungen Post. Show passenger coverage/passenger network Zeige Stationsabdeckung/Verbindungen Passagiere. Show speedlimit of ways Zeige Höchstgeschwindigkeit von Wegen. Show the change of waiting at halts Zeige die Veränderung wartend/lagernd. Show the owenership of infrastructure Färbe Infrastruktur entsprechend dem Besitzer ein. Show transported freight/freight network Zeige Frachtransport/Frachtverbindungen. Show usage of network Zeige die Zahl der Fahrzeuge pro Weg. Shows a listing with all industries on the map. Zeigt eine Legende der Industriezweige. Sum of departure/arrivals at halts Zeige die Summe Ankünfte + Abfahrten. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n Touristen nutzen nun\n%ss\nVerbindung zwischen\n%s und\n%s bei (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s\nschafft nun Arbeiter\naus %s\nzur Fabrik\n%s\nbei (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s fährt\nnun mit %i LKW zwischen\n%s (%i,%i)\nund %s\nbei (%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s hat eine\nneue Bahnverbindung\nzwischen %s\nbei (%i,%i) und\n%s\nbei (%i,%i) eingeweiht.\n Airline service by\n%s\nnow between\n%s \nand %s.\n %s hat\neine Flugverbindung zwischen\n%s und\n%s eingerichtet. Ferry service by\n%s\nnow between\n%s \nand %s.\n Schiff Ahoi!\n%s Kreuzfahrten\nbringt nun Passagiere von\n%s nach %s. Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nhat eine neue\nReisebusverbindung\nzwischen %s\nund %s\neröffnet.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Karteneditor LISTTOOLS Listenverwaltung MAGLEVTOOLS Magnetbahnbau MONORAILTOOLS Monorailbau NARROWGAUGETOOLS Schmalspurbahnbau RAILTOOLS Eisenbahnbau ROADTOOLS Straßenbau SHIPTOOLS Kanäle, Häfen und Werften SLOPETOOLS Gelände verändern SPECIALTOOLS Weitere Werkzeuge TRAMTOOLS Straßenbahnbau #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). Neuer Firmensitz von %s eröffnet. Factory chain extended\nfor %s near\n%s built with\n%i factories. Wirtschaft brummt:\n%s bei %s erweitert:\n%i neue Fabriken. Net wealth less than 10%% of starting capital! Gesamtvermögen ist weniger als 10%% des Startkapitals! New %s now available:\n%s\n %s '%s'\nist nun verfügbar. New factory chain\nfor %s near\n%s built with\n%i factories. Gründerzeit:\nDurch %s\nbei %s\nentstehen %i weitere\nFabriken.\n New vehicle now available:\n%s\n Ein neues Fahrzeug ist\nab jetzt verfügbar:\n\n»%s«\n\n Now %u clients connected. Aktuell %i Mitspieler. overtaking überholend Remove vehicle from map. Use with care! Fahrzeug wird vom Bildschirm entfernt. Verkaufswert wird als Gewinn gutgeschrieben. Sends the convoi to the last depot it departed from! Schickt den Fahrzeugverband in das nächste Depot. Server preparing game ... Server bereitet Kartenübertragung vor ... Trees Bäume With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s ehrt die \nwackeren Pioniere von Simutrans \nmit einem neuen Denkmal.\n%i Zuschauer sind mit dabei. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Linienfilter #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/Monat) (%.2f$/km) (%.2f$/km) (%i)- (%i) (in depot) (im Depot) [0] south-facing (0) südwärts [1] east-facing (1) ostwärts [2] north-facing (2) nordwärts [3] west-facing (3) westwärts [4] southeast corner (4) Südostecke [5] northeast corner (5) Nordostecke [6] northwest corner (6) Nordwestecke [7] southwest corner (7) Südwestecke [CTRL] Strg [END] Ende [HOME] Pos1 /month /Monat \nBauzeit bis bis \nBauzeit von \nGebaut ab \nCan't open heightfield file.\n \nKann Reliefdatei nicht lesen.\n \ndirection: \nRichtungen: \nelektrified \nelektrifiziert\n \nHeightfield has wrong image type.\n \nFalscher Dateityp.\n \nis reserved by: \nreserviert von Zug: \n \nminimum speed: \nMindestgeschwindigkeit: \nnot elektrified \nnicht elektrifiziert\n \nRibi (masked) \nRichtungen (erl.) \nRibi (unmasked) \nRichtungen (alle) \nSet phases: \nAmpelphasen:\n / dann \\ dann Offset \nsingle way Keine Einfahrt! \nway1 reserved by \nWeg 1 besetzt von \nway2 reserved by \nWeg 2 besetzt von \nwith sign/signal\n \nHat Verkehrszeichen/Signal\n %d buildings\n %d Gebäude\n %d convois %d Fahrzeuge %d Einzelfahrzeuge im Depot %d Einheiten im Depot %i car(s), %i Wagen, %i years %i months old. %i Jahre und %i Monate alt. %s at (%i,%i) now public stop. %s ist nun öffentlicher Umsteigepunkt. %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s Betriebshof %s has entered a depot. %s\nhat das Depot erreicht. %s has left. %s hat den Server verlassen. %s land %d %s %s %d Land %s %s now known as %s. %s heißt jetzt %s. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Bürgermeister will\nnicht mehr frieren:\n%s\nbaut ein neues Rathaus.\n %s\nis crowded. %s\nist überfüllt. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\nHöchstgeschwindigkeit %3$i km/h\n\nFährt gerade %2$i km/h.\n\n %s\nwas liquidated. %s is bankrott gegangen.\nDie Firma wurde aufgelöst,\nund alles verkauft. %u Client(s)\n %i Mitspieler\n %u days ago vor %u Tagen %u hours ago vor %u Stunden %u minutes ago vor %u Minuten %u Player (%u locked)\n %i Unternehmen (%i mit Passwort)\n %u years ago vor %u Jahren

Error

Fehler: Doppelte Objekte im Hauptverzeichnis

Im

Warning

addons for

Warnung: Doppelte Objekte im Addon-Verzeichnis

Addons für 1 convoi 1 Fahrzeugverband 1 minute ago gerade eben 1 year ago vor einem Jahr 100 km/h = %i tiles/month 100 km/h = %i Felder/Monat 1LIGHT_CHOOSE Helligkeit: 1th 1. 1WORLD_CHOOSE Einstellungen für neue Karte: 21th 21. 22th 22. 23th 23. 2LIGHT_CHOOSE Farbigkeit: 2th 2. 2WORLD_CHOOSE Kartennummer: 31th 31. 3LIGHT_CHOOSE Scrollgeschwindigkeit: 3th 3. 4LIGHT_CHOOSE Inverses Kartenscrolling 5LIGHT_CHOOSE Fußgänger (Haltestellen) 5WORLD_CHOOSE Anzahl Städte: 6LIGHT_CHOOSE Fußgänger (Stadt) 6WORLD_CHOOSE Verkehrsdichte: 8WORLD_CHOOSE Tag und Nacht wechseln A bridge must end on a way! Eine Brücke muss auf einem Weg enden! A bridge must start on a way! Eine Brücke darf nur\nauf einem eigenen Wegende\noder einem freien Hang\nBeginnen oder enden!\n Abfrage Abfragewerkzeug Abnehmer Verbraucher About Details About scenario Copyright Abriss Abrisswerkzeug Absenken Land absenken Abspanntransformator Umspannwerk (Fabrik) Accelerate time Spielablauf beschleunigen Act. load: %u MW\n Verbrauch: %u MW\n Active player only nur eigene Marker Add forest Wald aufforsten Add random citycar zufälliges Stadtfahrzeug erstellen add server Server hinzufügen Add Stop Halt anfügen Add stops for backward travel Füge Stops für Rückfahrt hinzu air Roll-/Startbahn Aircraft Fluglinie aircraft_tab Frachtflugzeuge airplane Flugzeug Airport Flughafen AIRTOOLS Flughafenbau All Alle all convoi tooltips Fahrzeuge: alle Tooltips Allow city growth Stadt darf wachsen Allow player change Spieler darf wechseln allowed climates:\n Klimazonen\n Alters a schedule. Fahrplan verändern and arranged by und arrangiert von Angenommene Waren -- Waren, die hier angeliefert werden können anhaengen Anhängen Anhaenger_tab Anhänger Anheben Land anheben Appends stops at the end of the schedule Halt am Fahrplanende hinzufügen Apply Line Linie zuweisen Arbeiter aus: Arbeiter wohnen in: Arrivals from\n Ankunft aus\n Arrived Angekommen Assets Fahrzeugwert Aufloesen Auflösen Aufspanntransformator Umspannwerk (Kraftwerk) auto automatisch Autohalt muss auf\nStrasse liegen!\n Autohalt muss auf\nStraße liegen!\n Available Verfügbar Available at custom date Verfügbar nach based on Simutrans 84.22.1 aufbauend auf Simutrans 84.22.1 battery Akkumulator baum builder Pflanze Baum Beginner mode Anfängermodus Besonderes Gebaeude Touristenattraktion BF Bahnhof bio Bio Blockstrecke ist\nbelegt\n \nBlockstrecke ist\nbelegt!\n Boden Land Bonus Multiplier: %i%% Bonus-Multiplikator: %i%% Bonus Speed: %i km/h Bonus-Geschwindigkeit: %i km/h Bonusspeed: %i km/h Referenzgeschwindigkeit: %i km/h (für Speedbonus) Boost (%%) erhöht um (%%) Borderless (disabled on fullscreen) Bildschirmfüllend (Softwaremode) bridge is too high for its type! Tal ist zu tief für\ndiesen Brückentyp!\n Bridge is too long for this type!\n Diese Brücke hat nicht die\nbenötigte Spannweite!\n Bruecke Brücke Bruecke muss an\neinfachem\nHang beginnen!\n Die Brücke muss an\neinem geraden\nHang beginnen!\n Brueckenboden Brücke Build air depot Flughafenhangar bauen build choosesignals Einfahrtsignale Build city market Neues Stadtgeschäft Build drain Umspannwerk build HQ Firmensitzbau Build land consumer Auf dem Land wird eine neue Industriekette gebaut Build maglev depot Magnetbahndepot wird gebaut - Kosten pro Depot: Build monorail depot Baue Depot für Monorail Build narrowgauge depot Schmalspurbahndepot bauen Build powerline Überlandleitung wird gebaut - Kosten pro Feld: Build presignals Zwei-Block-Signal Build road depot Bus- und LKW-Depot wird gebaut - Kosten pro Depot: Build ship depot Schiffsdepot wird gebaut - Kosten pro Depot: Build signals Signale Build train depot Bahndepot wird gebaut - Kosten pro Depot: Build tram depot Straßenbahndepot wird gebaut - Kosten pro Depot: Build truck depot Bus- und LKW-Depot wird gebaut - Kosten pro Depot: Building costs estimates ungefähre Baukosten Buildings Stadtgebäude Built artifical slopes Aufschüttungen Built random attraction Neue Sehenswürdigkeit Bus_tab Busse Can be overgrown kompatibel mit Bäumen Can only move from halt to halt or waypoint to waypoint. Kann nur von Halt zu Halt\noder von Wegpunkt zu\nWegpunkt verschieben Cancel Abbrechen Cannot connect to offline server! Server ist offline und nicht erreichbar. Capacity Kapazität Capacity: Kapazität Capacity: %.0f MW Kapazität: %.0f MW Capacity: %d%s %s\n Zuladung: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapazität: %s\n» %d (%d%%) Cars are not available yet! Es gibt noch nicht einmal Pferde!\nBitte erst nach dem Urknall starten ... cars.\nstate Fahrzeugen\n Cash Kontostand Category Warenart Change label style Stil der Orts- und Haltsnamen Change player Spielerwechsel Chart Statistik Chat_msg Chat Choose direction Ausrichtung auswählen Choose operation executed on clicking stored/new vehicles Wähle, was mit angeklickten gelagerten/neuen Fahrzeugen geschehen soll. chooses a random map Wählt eine Zufallskarte aus citicens Einwohner Cities can only be built on flat empty ground! Eine Stadt kann nur auf flachen Boden gegründet werden! City attraction Stadtattraktionen City industries Stadtgeschäfte City list Stadtliste City size Größe city_road Stadtstraße citybuilding builder Stadtgebäude bauen CityLimit Stadtgrenzen cl_title Fahrzeugliste cl_txt_sort Sortiert nach: clamp Wertebereich begrenzen Cleanup schedule Doppelhalte entfernen Clear block reservation Reservierte Wege anzeigen/löschen clf_chk_aircrafts Flugzeuge clf_chk_cars Busse/LKWs clf_chk_indepot im Depot clf_chk_maglev Magnetbahnen clf_chk_monorail Monorails clf_chk_name_filter Namen filtern: clf_chk_narrowgauge Schmalspurbahnen clf_chk_noincome kein Gewinn clf_chk_noline ohne Linie clf_chk_noroute ohne Route clf_chk_noschedule ohne Fahrplan clf_chk_obsolete veraltet clf_chk_ships Schiffe clf_chk_spezial_filter Spezialfilter: clf_chk_stucked blockiert clf_chk_trains Züge clf_chk_trams Straßenbahn clf_chk_type_filter Typen filtern: clf_chk_waren Waren filtern: clf_title Fahrzeugliste - Einstellungen Click to open the finance dialog. Anlicken öffnet die Finanzen des Spielers Climate Klimazone Climate Control Einstellungen Landschaft Climates Klimazonen closed Geschlossen Closes topmost line window when new line selected. Schliesst das oberste Linienfenster, wenn eine neue Line gewählt wurde. COLOR_CHOOSE\n Bitte wählen Sie\nzwei Kennfarbe\ndurch Anklicken:\n Company bankrupt Die Firma ist pleite! company_chat Firmeninterner Chat Company_msg Konkurrenz Comparing pak files ... Abgleich der pak-Dateien läuft ... Composed by Komponiert von Configure AI KI-Einstellungen Configure AI setttings Parameter für Computergegner anpassen Congratulation\nScenario was complete in\n%i months %i years. Glückwünsche\n\nDas Spielziel wurde in\n\n%i Monat(en) und %i Jahr(en)\n\nerreicht!\n Connect factory Industrieanlagen mit Verträgen verbinden Connected stops Haltestelle (mit dieser Fabrik verbunden): Connected with server Mit Server verbunden Connections Verbindungen Constructed by Gemalt von Constructed by %s Gemalt von %s construction speed Baugeschwindigkeit Construction_Btn Ausgaben Bau Consumed Verbraucht contains the following doubled objects:

enthält folgende Objekte mehrfach:

convoi %d of %d Fahrzeugverband %d von %d convoi error tooltips Fahrzeuge: Fehlertooltips Convoi following mode Verfolgtes Fahrzeug im Tunnel Convoi has been sent\nto the nearest depot\nof appropriate type.\n Fahrzeug wurde zum nächsten\npassenden Depot geschickt.\n Convoi is sold when all wagons are empty. Fahrzeugverband wird vom Bildschirm entfernt, sobald dieser leer ist. Verkaufswert wird dem Kontostand gutgeschrieben. convoi mouseover tooltips Fahrzeuge: Maustooltips convoi passed last\nmonth %i\n \nIm letzten Monat vorbeigefahrene \nFahrzeuge: %i\n Convois Fahrzeuge Convois: %d\nProfit: %s Fahrzeuge: %d\nProfit: %s Convoys Fahrzeuge Copy Convoi Kopieren Copy the selected convoi and its schedule or line Der Fahrzeugverband wird mit Fahrplan oder Linienzugehörigkeit kopiert. Copy to clipboard Text in die Zwischenablage kopieren. Cost Betriebskosten cost for removal Kosten für Entfernung Cost per unit Kosten/Einheit Cost: %8s (%.2f$/km %.2f$/m)\n Kosten: %s (%.2f$/km, %.2f$/Monat)\n Cost: %8s (%.2f$/km)\n Kosten: %8s (%.2f$/km)\n Costs Kosten Create a new line based on this schedule Eine neue Linie mit diesem Fahrplan anlegen. curiosity builder Sehenswürdigkeiten bauen curlist_title Touristenziele Current game Spiel in Hintergrund Currently playing: Gerade abgespielt wird: Customers live in: Kunden kommen aus: Date format Datums- und Uhrzeitformat deactivated in online mode funktionslos im Onlinemode Dec. Dez. Deccelerate time Spielablauf verlangsamen December Dezember decrease underground view level Ebene durch Karte tiefer Del Stop Löschen Delete Line Linie löschen Delete the current stop ausgewählten Halt löschen Delete the selected line (if without associated convois). Linie löschen (Nur möglich ohne Fahrzeuge!) Delete this file. Diese Datei löschen. Delivered Geliefert Demand Bedarf Demand: %.0f MW Last: %.0f MW Denkmal Monument Departed Abgefahren Departs at Abfahrt um (TT:SS:MM) Departure after %% geladen oder Wartezeit (TT:SS:MM) Departure board Fahrtanzeiger Departures per month Abfahrten pro Monat Departures to\n Abfahrt nach\n Destination Zielort Destroying map ... Kartenspeicher wird freigegeben ... Developed by the Simutrans Team Entwickelts von dem Simutrans-Team Die Bruecke ist nicht frei!\n Die Brücke ist nicht frei!\n diesel Diesel direct_chat_to: Direktnachricht an directmail Wurfsendung Direkt erreichbare Haltestellen -- direkte Verkehrsverbindungen: disable midi Midi-Musik ausschalten Display bars above factory to show the status Zeigt über Fabriken deren Name, Warenmengen und Produktion an. Display settings Anzeigeoptionen Distance Strecke/Monat distributing cities Erzeuge Städte distributing factories Verteile Fabriken Do not show Nichts anzeigen Dock Hafen Dock must be built on single slope! Ein Hafen muss an einem\ngeraden Ufer gebaut werden!\n Downloading Herunterladen dp_title Depotliste Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Du hast %d Monate Zeit, deine Schulden zurückzuzahlen Durchsatz Max. Economy Wirtschaft & Städte Eigenbesitz\n Öffentl. Eigentum\n Ein %s\npasst hier nicht.\n Ein '%s'\npaßt hier nicht.\n Einstellungen aendern Einstellungen ändern electric Elektrisch Electricity Strom Electricity producer\n\n Stromerzeuger\n\n Electrics_tab Elektrotraktion Electrify track Fahrleitung enlarge map Kartenfläche vergrößern enter a value between %i and %i Erlaubte Werte zwischen %i und %i Enter address Serveradresse eingeben Enter Password Spielernamen und Passwort ändern Error Auch der Computer irrt... Erzeuge neue Karte.\n Bitte warten,\nerzeuge neue\nKarte...\n\n (Kann bei großen\n Karten ein paar\n Minuten dauern.)\n Es wird bereits\nein Fahrplan\neingegeben\n Es wird bereits\nein Fahrplan\neingegeben!\n Extract files Packe Zip-Archiv aus. Fabrikanschluss -- Fabriken, mit dieser Haltestelle verbunden Factories Fabriken factory details Fabrikverbindungen factorybuilder Industrieanlagen bauen Fahrtziel Fahrtziel: Fahrzeuge koennen so nicht entfernt werden Fahrzeuge können so\nnicht entfernt werden.\n Farbe Spielerfarbe Fast forward Schnelllauf February Februar Ferry_tab Fähren Filename Dateiname: Files from: Dateien aus: Finances of %s Finanzen von %s find mismatch Abweichende Paks fl_title Fabrikliste Flug_tab Passagierflugzeuge follow me verfolgen Follow the convoi on the map. Dem Fahrzeug folgen. font size Zeichengröße For questions and support please visit: Fragen und Support gibt es via Forest Wälder Found new city Gründe neue Stadt FPS: Bildrate: Frame time: Bildfrequenz: Free Capacity Freie Kapazität freeplay mode Ohne Bankrott Freight Fracht Friction: Momentaner Bremswert: fuel_cell Brennstoffzelle Full load Warten auf Mindestbeladung Fullscreen (changed after restart) Bildschirmfüllend (Hardware mode, wechsel braucht Neustart) Fussgaenger Fußgänger Game info Kurzinformation / Netzwerkspiele GAME PAUSED Spiel angehalten Game_msg Allgemeines Gear: Übersetzung: Gebaeude Gebäude General Allgemeines generate script Infrastrukturmakro erstellen Generated Erzeugt Generation: %.0f MW Erzeugung: %.0f MW Gewinn Gewinn Give the selected vehicle(s) an individual schedule Gib dem ausgewählten Fahrzeug einen eigenen Fahrplan. gl_btn_sort_catg nach Kategorie gl_title Warenliste go home zum Depot Goods Waren Goods AI Fracht-KI Goods list Warenübersicht Gross Profit Bruttogewinn Groundobj Objekt groundobj builder Landschaftsobjekte bauen Grow city Einwohnerzahl erhöhen Growth Wachstum GUI settings Oberfläche Happy Zufrieden Has slope graphics auch auf Hanglagen Has Snow mit Schnee Helligk. Anzeige Help Hilfe Help text not found Er kann nur die Hilfetexte\nanzeigen, die schon geschrieben\nsind. Wenden Sie sich\nmit ihren Fragen an eines\nder Simutrans-Foren. hide all building alle Gebäude minimieren hide city building Stadtgebäude minimieren Hide labels Ort- und Haltnamen nicht anzeigen hide objects under cursor Dinge im Umkreis um den Mauszeiger minimieren. hide station names Stationsnamen ausblenden hide transparent Transparenz statt minimieren hide trees Bäume minimieren Hier warten/lagern: Wartende Passagiere/Güter: Higher transport fees, crossconnect all factories höhere Transportgewinne, keine Produktionsstopps wenn überfüllt Highlite schedule Fahrplanhalte hervorheben hl_title Haltestellenliste hl_txt_filter Filter: hl_txt_sort Sortiert nach: hlf_chk_airport Flughäfen hlf_chk_anleger Häfen hlf_chk_bahnhof Bahnhöfe hlf_chk_bushalt Bushaltestellen hlf_chk_frachthof Frachthöfe hlf_chk_keine_verb keine Verbindung hlf_chk_maglevstop Magnetbahnhof hlf_chk_monorailstop Monorailhalt hlf_chk_name_filter Namen filtern: hlf_chk_narrowgaugestop Schmalspurbahnhof hlf_chk_overflow überfüllt hlf_chk_spezial_filter Spezialfilter: hlf_chk_tramstop Tramhaltestelle hlf_chk_type_filter Typen filtern: hlf_chk_waren_abgabe Gibt ab: hlf_chk_waren_annahme Nimmt an: hlf_title Haltestellenliste - Einstellungen Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Kein Heimdepot gefunden!\nÄndern Sie den\nFahrplan entsprechend\nmanuell. Homeless Obdachlos hydrogene Wasserstoff Icon size: Werkzeugsymbolgröße Idle: Leerlauf: ignore climates alle Klimazonen In the industry legend show only currently existing factories Zeige Legende nur für existierende Fabriken. In Transit Unterwegs Increase Industry density Industriedichte erhöhen increase underground view level Ebene durch Karte höher industrial building Industriegebäude Industry overlay Industriestatusanzeige Infinite mouse scrolling Unbegrenzte Kartenbewegung Infinite scrolling using mouse Funktioniert nicht mit manchen Touchpens! Init map ... Kartenfelder initialisieren ... Input Eingang Ins Stop Halt Einfügen Insert stop before the current stop Halt vor aktueller Fahrplanposition einfügen Install graphics Grafikset hinzufügen Install paks Paksets werden heruntergeladen und installiert. Insufficient funds! Zu wenig Geld! Intercity road len: Verbindungstraßenlänge: Intro. date Einführung Intro. date: Einführung: invalid undefiniert Invalid coordinate ungültiger Eintrag Invert stops Reihenfolge umdrehen isometric map isometrische Anzeige January Januar join game Online spielen July Juli Jump to Zentrieren auf June Juni just now jetzt Kann Spielstand\nnicht laden.\n Kann Spielstand\nnicht laden!\n Kann Spielstand\nnicht speichern.\n Kann Spielstand\nnicht speichern!\n Kein Besitzer\n kein Besitzer\n\n Keine Einzelfahrzeuge im Depot Keine Fahrzeuge im Depot Keyboard_Help\n Tastaturkürzel\n koord nach Orten labellist_title Markierungsliste Lade Relief Lade Höhenkarte Laden Spielstand auswählen und laden Land attraction Ausflugsziel Land industries Industriezweige LANG_CHOOSE\n Bitte wählen Sie\nIhre Sprache:\n LARGE_NUMBER_STRING Mio. LARGE_NUMBER_VALUE 1e6 Last Month Vormonat Last used tools Zuletzt verwendete Werkzeuge Last Year Vorjahr Leaving depot! Verlässt Depot! Left button drags minimap too Linke Maustaste bewegt auch Reliefkartenausschnitt legacy (large heights) Alter Modus (Doppelte Höhen) legacy (small heights) Alter Modus (Halbe Höhen) Legend Kartenlegende Leitung Stromleitung length: %d Länge %d letzen Monat: diesen Monat: letzten Monat: diesen Monat: Line Linie Line Management Linienverwaltung line name mouseover tooltips Fahrzeuge: Linie und Fahrzeugnamen linear Linear Lineless convoys serving this stop Einzelfahrzeuge, die hier halten Lines serving this stop -- Linien, die diese Haltestelle anfahren List of industries on the map Industrieliste LKW_tab LKW Load game Lade Spiel load height data from file Lade Relief aus Datei Load mode: Höheberechnungä Load scenario Wähle Mission Load script tool Skript-Werkzeug laden Load Scripted AI Skript-KI laden Load settings from Einstellungen übernehmen von loaded geladen. loaded passenger/freight Sortiere Passagiere/Güter nach Loading (%i->%i%%)! Beladen (%i->%i%%) Loading (%i%%) departure %s! Lädt (%i%%), Abfahrt %s! Loading (%i%%)! Beladen (%i%%) Loading addon paks ... zusätzliche Addons laden ... Loading map ... Lade Karte ... Loading paks ... Grafikset laden ... Loading skins ... eigene Skins laden ... Loading time: Voll Beladen in: Lock Control key Steurungstaste einrasten Lock game Karte gegen weiteren Spielerwechsel schützen. Lokomotive_tab Loks m3 m³ Maglev Magnetbahn maglev vehicle Magnetbahnfahrzeug maglev_track Magnetbahnstrecke Maglevdepot Magnetbahndepot Mail Demand %d\n max. Postaufkommen %d\n Mail level Postaufkommen Mailbox Meldungen anzeigen Mailbox Options Meldungsauswahl Maintenance Instandhaltung make stop public (or join with public stop next) costs %i per tile and level Erzeugen/verbinden mit öffentlichem Stop (%i$ pro Feld und Level) Make way or stop public (will join with neighbours), %i times maintainance In öffentliche Haltestelle umwandeln (mit Nachbarn verbinden), %i-fache Wartungskosten. Manual (Human) Mensch (keine KI) Manufactured: Hergestellt: Map roughness Bergigkeit map view Ansicht map zoom Vergrößerung Mar. März March März Margin (%%) Marge Marker Markierung Max Boost (%%) max. erhöht (%%) Max income: Maximaler Gewinn: Max. speed Maximalgeschwindigkeit Max. speed: Höchstgeschwindigkeit: Max. waiting time Max. Wartezeit (TT:SS:MM) Maximum 254 stops\nin a schedule!\n Nicht mehr als 254\nStopps pro Fahrplan!\n maximum length of rivers max. Länge Maximum tile height difference reached. Die Höhendifferenz\nzweier benachbarter Böden\ndarf nicht größer sein\nals zwei Stufen. Maxspeed Geschwindigkeit May Mai Median Citizen per town Mittlere Stadtgröße: merge stop Haltestelle zusammenlegen MessageOptionsText \nNeues Jahr\n\nKI baut\n\nStadtnachrichten\n\nKeine Route\n\nNeue Industrie\n\nMitteilungen\n\nNeue Fahrzeuge\n\nBahnhof voll\n\nProbleme\n\nStaus\n\nSzenario\n\nÖffentlicher Chat\n\nFirmeninterner Chat\n\nPrivate Nachrichten\n\n minimum length of rivers min. Länge Minimum load Mindestbeladung (%%) Missing pakfiles Es fehlen Objekte im Spiel! Modify the selected line Ändere den Fahrplan der gewählten Linie. Monate alt Monate alt. monorail vehicle Monorailfahrzeug monorail_track Monorailbahn Monorailboden Erhöhter Verkehrsweg Month Monat month wait time max. Wartezeit Monthly departures Feste Abfahrtzeiten Months Monate Monument Denkmal Monuments Denkmäler Mountain height Berghöhe Move the map Verschiebt Kartenausschnitt Movingobj bewegliches Objekt Music playing disabled/not available Musik nicht verfügbar/abgeschaltet Music volume: Musiklautstärke: mute sound Klänge aus Narrowgauge Schmalspurbahn Narrowgauge are not available yet! Noch keine Schmalspurbahnen verfügbar! narrowgauge vehicle Schmalspurbahnfahrzeug narrowgauge_track Schmalspurstrecke Narrowgaugedepot Schmalspurbahndepot Net ID: %p Netz-ID: %p\n Net Wealth Gesamtvermögen Net wealth near zero Firmenvermögen nahezu verbraucht! Neue Karte Neues Spiel Neue Welt Eine Neue Welt new convoi Neuer Fahrzeugverband New Line Neue Linie New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Neue Linie erzeugt!\nDie Linie kann nun oben\nfür diesen Fahrzeugverband\nausgewählt werden. New Vehicles Neue Fahrzeuge Nickname: Chatname: no buildings hidden keine Gebäude minimieren no convois Keine Fahrzeuge zusammengestellt No goods are loaded onto this convoi. Nichts mehr einladen. no goods waiting keine Güter vorhanden no load nicht laden No player Kein Transportunternehmen No Route Keine Route No stop here! Werkzeug wirkt nur auf Haltestellen! No suitable ground! Dieser Boden ist ungeeignet. No suitable townhall available for this climate! Kein Rathaus für dieses Klima vorhanden! No terminal station here! Ein Endhalt kann nur\nauf einem Endstück\ngebaut werden!\n no timeline alle Epochen no tree ohne Wälder No vehicles are available for purchase. Keine Fahrzeuge zum Kauf verfügbar. No. of Factories Fabriken und Geschäfte Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Noch kein Fahrplan\nvorhanden!\n none keine nord Nord nordost Nordost nordwest Nordwest Not allowed to make publicly owned ways! Das Bauen von Wegen der öffentlichen Hand ist nicht erlaubt. Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Nicht möglich!\nDer Fahrplan kann zur Zeit\nnicht geändert werden.\nVersuchen Sie es später\nnoch einmal! Not enough fields would remain. Um jeden Hof muss eine\nMindestanzahl von Feldern\nübrigbleiben. Not online Nicht Online now jetzt Now active as %s.\n Du bist jetzt der Spieler:\n %s. nowhere nirgendwo Number of rivers Anzahl Flüsse Object Objekt Oct. Okt. Odometer: %s km Kilometerstand: %s On loan since %i month(s) %i Monat(e) Konto überzogen On mouseover Wenn unter Mauszeiger on the Abfahrten/Monat, erste am (TT:HH:MM) On this map, you are not\nallowed to change player!\n Spiel geschützt!\nSpielerwechsel ist auf dieser\nKarte nicht möglich.\n Only city chains Fabrikkette (Stadt) bauen Only first %d differing paks reported. There are probably more. Nur die ersten %d abweichenden Objekte sind aufgelistet. Es können noch weitere Differenzen bestehen. Only full Unicode fonts nur komplette Unicodezeichensätze Only land chains Fabrikkette (Land) bauen Only one transformer per factory! Es ist nur ein Transformator je Industrie erlaubt! Only show goods which are currently handled by factories Nur Güter anzeigen, die gerade verarbeitet werden können open Geöffnet Operation Betriebskosten Ops Profit Betriebsgewinn Or enter a server manually: Oder gebe eine Serveradresse ein: Origin Abfahrtsort ost Ost Output Ausgang Ownership Besitzer Pak which may cause severe errors: Es fehlen folgende Objekte (pak), die zum Versagen von Transportketten führen können: Pak which may cause visual errors: Folgende Objekte (pak) wurden durch ähnliche ausgetauscht: Pak(s) different: unterschiedliche Objekte: Pak(s) missing on client: Folgende Objekte fehlen dir: Pak(s) not on server: Folgende Objekte sind dem Server unbekannt: Pakset differences Abweichenden pak-Objekte paletten Paletten Pas_tab Passagierzüge Passagierrate Passagieraufkommen Passagierziele Passagier-/Postziele Passenger AI Passagier-KI Passenger Demand %d\n max. Passagieraufkommen %d\n Passengers %d %c, %d %c, %d no route Fahrgäste %d %c, %d %c, %d ohne Route Passengers %d %s, %d %s, %d no route Fahrgäste %d %s, %d %s, %d ohne Route Password Passwort Pax <%i> Mail <%i> Passagiere <%i> Post <%i> Pax level Passagieraufkommen PaxDest Reiseziele Percent Electricity Anteil Kraftwerke (%%) personal_chat Direktnachrichten Pipette Diese Ding noch einmal bauen Planes are not available yet! Noch keine Fluggeräte erfunden! Plant tree Baum player Spieler player -1 Simutrans-Spieler player 0 Öffentliche Hand player 1 Napik 128 AS player 10 Spieler 10 player 11 Spieler 11 player 12 Spieler 12 player 13 Spieler 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG player 7 Spieler 7 player 8 Spieler 8 player 9 Spieler 9 Player ranking Spielerrangfolge Please choose vehicles first\n Bitte wählen sie zuerst einen Fahrzeugverband aus. Postrate Postaufkommen Power Strommenge Power (MW) Leistung (MW) Power: Leistung: Power: %4d kW\n Leistung: %4d kW\n Powerlines Freileitungen Price Kaufpreis Problems_msg Warnungen Produced Erzeugt Produces: %.1f units/minute Produziert %.1f Einheiten pro Minute Production of %s has been stopped:\n%s\n %s '%s'\nwird nicht mehr hergestellt. Production/Boost Produktionskennzahlen promote to line Neue Linie public_chat Allgemeiner Chat q1 Frühling q2 Sommer q3 Herbst q4 Winter Query server Server abfragen rail car Schienenfahrzeug random Zufällig Random age Zufallsjahr Random map Zufallskarte Rating Status ratio_pax Verhältnis Relevant Nur Benötigte Remove Label löschen remove airstrips Landebahnen und Rollfeld entfernen remove channels Kanal zuschütten remove interm. signals Sign. an Zwischenstellen entf. remove maglev tracks Magnetbahnstrecke löschen remove monorails Monorailbahnstrecken löschen remove narrowgauge tracks Schmalspurbahnstrecke entfernen remove powerlines Übertragungsleitung entfernen remove roads Straßenzug löschen remove signal Signal entfernen remove tracks Eisenbahnstrecken entfernen Remove wayobj %s Wegzusatz von %s entfernen. replace other signals Andere Signale entfernen replace stop Haltepunkt verlegen request closing Schließung vorbereitet residential house Wohnhaus Restore natural slope Natürliche Neigung wiederherstellen Restwert: Verkaufswert: Retire date Außerdienststellung Retire. date: Außerdienststellung: return ticket Rückfahrkarte Revenue Einnahmen Revenue/unit/100 tiles Gewinn pro 100 Kacheln Revert schedule Änderungen verwerfen Revision: Revision: road Straße road vehicle Straßenfahrzeug Roadsign Verkehrsschild Rotate Building Gebäude drehen Rotate map Karte um 90° drehen Routing Verbindungen Running cost Betriebskosten sack Sack sail Wind Save Spiel speichern Saving map ... Speichere Karte ... Scenario complete: %i%% Mission zu %i%% erfüllt. Scenario Debug Debug Scenario Error Log Skriptfehler Scenario Goal Missionsziele Scenario Info Zusammenfassung Scenario information Missionsstatus Scenario Result Spielstand Scenario Rules Regeln Scenario_ Scenario Schedule changing! Fahrplan geändert! Schiff_tab Schiffe Schleppkahn_tab Schleppkähne Screen scale: Bildschirmskalierung: Screenshot Bildschirmfoto Scroll threshold Kartenbewegungstoleranz Search: Suche: Seasons Jahreszeiten Sehenswuerdigkeit Sehenswürdigkeit Select a server to join: Wähle einen Server aus: Select a theme for display Visuelles Design ändern Select display font Zeichensatzauswahl Select one or more graphics to install (Ctrl+click): Wählen Sie eine oder mehrere Grafiksets zur Installation aus (Strg + Klick): Select soundfont Wähle MIDI Soundfont Sell the selected vehicle(s) Verkaufe das ausgewählte Fahrzeug. Selling of the program is forbidden. Simutrans darf nicht verkauft werden. sended abgeschickt SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Sept. Sep. Served by Angebunden von Served by me Wenn von mir bedient Server did not respond! Server antwortet nicht! Serves Line: Bedient Linie: Service An-/Abfahrten set signal spacing Signalabstand festlegen Setting Einstellungen Ship Schiff shops and stores Gewerbegebäude Show all Alle zeigen show all building Alle Gebäude wieder anzeigen. Show also vehicles no longer in production. Auch Fahrzeuge anzeigen, die nicht mehr produziert werden. Show also vehicles that do not match for current action. Auch Fahrzeuge anzeigen, die im Moment nicht passen. Show always Immer anzeigen Show climates Klimazonen Show contour Geländreflief Show even servers with wrong version or pakset Auch Server anzeigen, die die falsche Programmversion bzw. das falsche Pak-Set haben. Show finances for transport type Zeige Finanzen für Transportart: Show future Auch zukünftige zeigen show grid Gitternetz einblenden Show industry Industrieliste Show legend Datenauswahl Show map scale Werteskala Show mismatched Zeige inkompatible Show networks Netzplan Show obsolete Auch veraltete zeigen Show offline Zeige offline Show only used unbenutzte ausblenden Show outline ohne Gelände Show schedules Linienpläne Show servers that are offline Zeige auch Server an, die zur Zeit offline sind. Show servers where game version or pakset does not match your client Zeigt auch Server an, deren Programm oder Pakset-Version nicht mit dem Client übereinstimmt. show station coverage Stationsabdeckung anzeigen show station names Stationsnamen anzeigen show waiting bars Güterwartebalken anzeigen show/hide block reservations reservierte Blöcke anzeigen Show/hide estimated arrival times Zeige ungefähre Ankunfts- und Abfahrtszeiten show/hide object owner Dinge in Besitzerfarbe anzeigen Show/hide statistics Zeige/verberge Statistik Shows buttons about networks overlay. Zeigt Transportnetzeinstellungen. Shows buttons on network overlay. Zeigt die Einstellungen für Netzpläne. Shows buttons on special topics. Zeigt Auswahlfelder z.B. für Benutzung oder Industrien. Shows consumer/suppliers for factories Zeigt Abnehmer (bzw. mit Shift: Versorger) der Fabrik unter dem Mauszeiger Shows the color code for several selections. Zeigt die verwendete Farbskala z.B. für Wegnutzung an. Shows the currently selected schedule Zeigt den aktuell ausgewählten Fahrplan als Liniengrafik. Shrink city Einwohnerzahl verringern shuffle midis Zufallsauswahl signal spacing Signalabstand Sim: Simloops: Similar view as the main window Kippt die Ansicht analog zur großen Ansicht. Single toolbar only Nur eine Werkzeugleiste anzeigen Size (%d MB): Größe (%d MB): Size (area) Grundfläche sliced underground mode Ebene durch Karte slot empty unbelegt Smart hide objects Mauszeiger freihalten Sort by sortiert nach Sort by: Sortiert nach: Sort waiting list by Sortiere Warteliste nach Sound settings Soundeinstellungen Sound volume: Klanglautstärke: Soundfonts are located in the music directory. Soundfonts die sich im Musikverzeichnis befinden: special freight Sonderfracht Speed Bonus Expressbonus Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus in Prozent:\nMindestgeschwindigkeit Straße %i km/h,\nSchiene %i km/h, Wasser %i km/h, Luft %i km/h.\n Speedlimit Tempolimit Spieler(mz) Spieler Spielstand wurde\ngeladen!\n \nSpielstand wurde geladen!\n Spielstand wurde\ngespeichert!\n \nSpielstand wurde\ngespeichert!\n\n Sprachen Sprachauswahl Start Starten Start the selected vehicle(s) Starte das ausgewählte Fahrzeug. station labels Halte Station tiles: min. Haltlänge: Station_msg Überfüllungen Status Haltstatus steam Dampf Step timeline one year Jahr überspringen Stops Haltestellen Storage Auf Lager Storage capacity Lagerkapazität Strassendepot Bus und LKW Depot Strassentunnel Straßentunnel street car Straßenbahnwagen sued Süd suedost Südost suedwest Südwest Summer snowline Sommerschnee ab Supplied: %.0f %% Geliefert: %.0f %% Suppliers Lieferanten The following graphics are unmaintained: Die folgenden Grafiksets werden nicht mehr betreut: The generated script was saved!\n Makro erfogreich gespeichert.\nKann jetzt mit Skriptwerkezug gebaut werden. The gradient does not fit a tunnel Die Steigung passt nicht für einen Tunnel. The script cannot be saved!\n Konnte Marko nicht speichern. Theme selector Auswahl Oberfläche There are still vehicles\nstored in this depot!\n Es sind noch Fahrzeuge\nin diesem Depot!\n This Month Laufender Monat This Year Laufendes Jahr Tile not empty. Das Feld ist besetzt\nund kann daher nicht\nverändert werden.\n timeline mit Epochen tl_title Stadtliste To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Der Verkehr in %1$s nimmt zu:\n%3$i waren bei der Eröffnung\nvon %2$s. To heavy traffic\nresults in traffic jam.\n Verkehrsmeldung:\nStau seit Monaten.\n To: %s An: %s Toggle day/night view Tag/Nachtmodus umschalten Toggle vehicle tooltips Tooltips für Fahrzeuge umschalten tonnen t Toolbar position: Position der Menüleiste: Total inhabitants: Gesamtbevölkerung: Tourist attractions Touristenattraktionen Tourists Attraktionen Town_msg Stadtwachstum Town: %s\n Teil der Stadt: %s\n Towns Städte track Eisenbahnstrecke Tracks Gleistrassen Traffic Verkehr traffic settings Verkehr Train Zug Trains are not available yet! Züge sind noch nicht verfügbar! Tram Straßenbahn tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. Straßenbahnen %i km/h, Monorailbahnen %i km/h\nMagnetbahnen %i km/h, Schmalspurbahnen %i km/h. tram_track Straßenbahnstrecke Tramdepot Straßenbahndepot Trams are not available yet! Noch keine Straßenbahnen verfügbar! Transferring game ... Karte wird übertragen ... Transformer only next to factory! Umspannwerke können nur auf\neinem freien geraden Feld\ndirekt neben einer Fabrik\ngebaut werden! Translation Übersetzung transparencies Sichtbarkeit transparent background transparenter Hintergrund transparent station coverage transparente Stationsabdeckung Transported Beförderungen Trees disabled! Bäume ausgeschalten! TrolleyBus_tab Trolleybusse Truck Straße tt_Other Sonstige Tunnel muss an\neinfachem\nHang beginnen!\n Der Tunnel muss an\neinem Hang beginnen!\n Tunnel must start on single way! Der Tunnel muss an\n einem Gleis oder\ einer Straße beginnen Tunnelboden Tunnel under the Artistic License OS unter der Artisitc License underground mode Untergrundansicht UNDO failed! Diese Aktion kann nicht\nmehr rückgänging gemacht \nwerden. Das geht nur \nunmittelbar nach dem \nWegebau! Undo last ways construction Letzten Wegebau rückgängig machen. Unemployed Arbeitslos Unhappy Unzufrieden units/day Einheiten pro Monat Unloading (%i%%)! Entladen (%i%%) Update Line Linie ändern upgrade HQ Firmensitzumbau Usage: %.0f %% Auslastung: %.0f %% Usage/Output Strom Use beginner mode Anfängermodus Use timeline start year Mit Epoche ab Jahr Vehicle %s can't find a route! %s\nfindet keinen Weg\nmehr! Vehicle %s is stucked! %s\nsteckt fest!\n Vehicle count: Anzahl Fahrzeuge: Vehicle details Fahrzeugdetails Vehicle Name Name Vehicle Power Leistung vehicles stored Fahrzeuge im Depot Vergroessere die Karte\n Kartenfläche vergrößern.\n Verkauf Entfernen! verkaufen Verkaufen Verkehrsteilnehmer Stadtautos Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurückzuzahlen.\n vh_title Liste aller Fahrzeuge via %s\n über %s\n voranstellen Voranstellen Waggon_tab Waggons waiting wartend Waiting for clearance! Wartet auf freie Strecke! Walked zu Fuß walking Zu Fuß Warnings_msg Verkehrsmeldungen Water Kanal Water level Meereshöhe water vehicle Wasserfahrzeug way %s cannot longer used:\n Weg %s darf\nnicht mehr gebaut werden!\n way %s cannot longer used:\n%s\n %s steht nicht mehr zur Verfügung:\n way %s now available:\n Weg %s kann\nab sofort gebaut werden. Way toll Maut Ways not connected Wege sind nicht verbunden!\n waytype Fahrweg Wegpunkt freier Wegpunkt Weight Gewicht Weight: Gewicht: Weight/unit Gewicht Welcome to Simutrans Willkommen zu Simutrans Welcome, %s! Willkommen %s! west West Wind direction Windrichtung Winter snowline Winterschnee bis withdraw Ausmustern Withdraw All alle ausmustern WRONGSAVE \nInkompatible Spielstands-\nversion. Das Spiel kann\nnicht geladen werden.\n Year Jahr Year %i has started. Das Jahr %i hat\nbegonnen. Years Jahre Your primary color: Kennfarbe 1 Your secondary color: Kennfarbe 2 zooming in Darstellung vergrößern zooming out Darstellung verkleinern Zu nah am Kartenrand Zu nah am Kartenrand!\nBitte es weiter weg\nnochmal versuchen!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Neuer Weltrekord für Magnetbahnen: %.1f km/h by %s. New world record for monorails: %.1f km/h by %s. Neuer Weltrekord\nfür Monorailbahnen: %.1fkm/h\ndurch %s. New world record for motorcars: %.1f km/h by %s. Bernd Bleifuß erreicht\n%.1fkm/h auf\n%s. \nNeuer Weltrekord! New world record for narrowgauges: %.1f km/h by %s. Neuer Weltrekord für Schmalspurbahnen: %.1f km/h von %s. New world record for planes: %.1f km/h by %s. Lilienthals Erben melden\nneuen Weltrekord:\n%.1f km/h flog\n%s. New world record for railways: %.1f km/h by %s. Da fliegt die Pleuelstange\nweg. Lokführer Braun holt\n%.1fkm/h heraus aus\n%s. New world record for ship: %.1f km/h by %s. Blaues Band mit\n%.1fkm/h vergeben\nan %s. #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s erhöht die Fahrzeugzahl der Linie: %s %s build rail line from %s (%s) to %s (%s) %s baut Eisenbahn-Linie von %s (%s) nach %s (%s) %s build road line from %s (%s) to %s (%s) %s baut Lkw-Linie von %s (%s) nach %s (%s) %s build ship line from %s (%s) to %s (%s) %s baut Schiffslinie von %s (%s) nach %s (%s) %s extends the route from %s (%s) to %s (%s) %s baut die Strecke von %s (%s) nach %s (%s) aus %s optimize way line from %s (%s) to %s (%s) %s optimiert Strecke von %s (%s) nach %s (%s) %s removes convoys from line: %s %s reduziert die Fahrzeugzahl der Linie: %s vehicles of the line %s were retired Fahrzeuge der Linie %s wurden ausgemustert #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. Finde Fahrzeuge mit gleichen Zielen und füge sie hinzu. Attach current coordinate to the comment Hefte die aktuelle Position auf der Karte an die Nachtricht an. Enter intervall in days, hours, minutes Zeitspanne in Tagen, Stunden und Minuten eingeben. Mirrors order of stops Reihenfolge der Halte invertieren. Revert to original schedule Alle Änderung des Fahrplans zurücknehmen. Tutorial not available for this pakset. Please try loading Pak128. Es gibt kein Tutorial für dieses Pakset. Pak, Pak128 und pak192 und vielleicht schon mehr haben ein Tutorial. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL brigg &1_CITY_SYLL bach &2_CITY_SYLL berg &3_CITY_SYLL borstel &4_CITY_SYLL bronn &5_CITY_SYLL bruck &6_CITY_SYLL burg &7_CITY_SYLL büttel &8_CITY_SYLL dorf &9_CITY_SYLL essen &A_CITY_SYLL feld &B_CITY_SYLL steig &C_CITY_SYLL hagen &D_CITY_SYLL hausen &E_CITY_SYLL haven &F_CITY_SYLL heim &G_CITY_SYLL hofen &H_CITY_SYLL holz &I_CITY_SYLL horn &J_CITY_SYLL kirchen &K_CITY_SYLL kloster &L_CITY_SYLL leben &M_CITY_SYLL lingen &N_CITY_SYLL missen &O_CITY_SYLL moor &P_CITY_SYLL mühl &Q_CITY_SYLL reuth &R_CITY_SYLL rode &S_CITY_SYLL ruhe &T_CITY_SYLL stadt &U_CITY_SYLL stede &V_CITY_SYLL stein &W_CITY_SYLL stetten &X_CITY_SYLL tal &Y_CITY_SYLL trup &Z_CITY_SYLL weiler %0_CITY_SYLL Kehr %1_CITY_SYLL Alten %2_CITY_SYLL Alves %3_CITY_SYLL Breit %4_CITY_SYLL Bruch %5_CITY_SYLL Frei %6_CITY_SYLL Friedrichs %7_CITY_SYLL Fürsten %8_CITY_SYLL Gross %9_CITY_SYLL Kalten %A_CITY_SYLL Karls %B_CITY_SYLL Klein %C_CITY_SYLL Lauen %D_CITY_SYLL Ludwigs %E_CITY_SYLL Michel %F_CITY_SYLL Neuen %G_CITY_SYLL Norder %H_CITY_SYLL Ober %I_CITY_SYLL Olden %J_CITY_SYLL Tuna %K_CITY_SYLL Pfullen %L_CITY_SYLL Rast %M_CITY_SYLL Rosen %N_CITY_SYLL Schön %O_CITY_SYLL Schram %P_CITY_SYLL Sommer %Q_CITY_SYLL Steinen %R_CITY_SYLL Söder %S_CITY_SYLL Unter %T_CITY_SYLL Wald %U_CITY_SYLL Wasser %V_CITY_SYLL Wessel %W_CITY_SYLL Bo %X_CITY_SYLL Wies %Y_CITY_SYLL Wilhelms %Z_CITY_SYLL Winter 0extern %s Wald %s 0suburb %s %ssiedlung %s 1center %s %s 1extern %s Zweig %s 1suburb %s %s %s 2center %s Haupt %s 2extern %s Neben %s 2suburb %s Ausbau %s %s 3center %s Zentral %s 3extern %s Land %s 3suburb %s Vorstadt %s %s 4center %s %s Mitte 4extern %s Außen %s 4suburb %s, %s Kolonie 5center %s Transfer %s 5extern %s Wiesengrund %s 5suburb Entwicklungsgebiet %s %s %s 6center %s Zentrum %s 6extern %s Industriepark %s 6suburb %s %sring %s 7center %s Stadt %s 7extern %s Schutzhütte %s 7suburb %s %spark %s 8center %s Knoten %s 8suburb Neu-%s %s %s 9center %s Ring %s 9extern %s Wildfütterung %s 9suburb Bad %s %s Acenter %s Markt %s Bcenter %s Neustadt %s Ccenter %s Vorstadt %s %s Csuburb %s Brunnen %s Dcenter %s Kreisel %s Eextern %s Forellenteich %s Fextern %s Jungbrunnen %s Gextern %s Felsengrund %s Ksuburb %s %stangente %s Lcenter %s Oberstadt %s Mcenter %s Allee %s Ncenter %s %sstern %s Nsuburb %s An der %sbahn %s Oextern Am Ende Qcenter %s Oberstadt %s Rsuburb %s %sseite %s Ssuburb %s Promenade %s Vextern %s Westblick %s Wsuburb Nieder-%s %s Yextern %s Waldkindergarten %s simutrans-124.3/simutrans/text/de/000077500000000000000000000000001474050137200171545ustar00rootroot00000000000000simutrans-124.3/simutrans/text/de/airtools.txt000066400000000000000000000027011474050137200215510ustar00rootroot00000000000000Flughafenbau

Flughafenbauwerkzeuge

Diese Werkzeugleiste dient dem Bau von Rollfeldern, Startbahnen, Hangars, Gangways und Nebengebäuden. Bei der Auswahl eines Werkzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Rollfelder und Startbahnen bilden die Verkehrswege des Flughafens. Sie werden wie Strassen gebaut, damit ein funktionstüchtiger Flughafen entsteht, müssen folgende Regeln eingehalten werden:
- Startbahnen müssen immer gerade sein, dürfen sich aber kreuzen,
- Rollfelder müssen mit der Startbahn verbunden sein, dürfen aber nicht an das Ende einer Startbahn anschliessen, sonst finden Flugzeuge keinen Weg mehr zum Ziel.

Im Hangar kannst Du Flugzeuge bauen sowie Linien einrichten und die Flugzeuge nach der Zuordnung zu Linien starten. Das Depot kann nur auf einem ebenen Rollfeldende platziert werden.

Gangways stellen die Haltepunkte der Flugzeuge zum Ein- und Ausladen dar. Wie ein Hangar kann eine Gangway nur auf ein Endstück des Rollfelds gesetzt werden, und erst mit dessen Bau wird der Flughafen als Haltestelle errichtet. Soll der Flughafen an eine bestehende Haltestelle angeschlossen werden, muss die Gangway diese direkt erweitern.

Nebengebäude für Flughäfen haben dieselben Funktionen wie alle anderen Nebengebäude.

simutrans-124.3/simutrans/text/de/baum_build.txt000066400000000000000000000020651474050137200220230ustar00rootroot00000000000000Bäume pflanzen

Bäume pflanzen

Der Dialog ist in vier Bereiche aufgeteilt.
· oben links befindet sich die Auswahlliste mit den Bäumen
· unten links wird das Bild des ausgewählten Baums angezeigt
· oben rechts befinden sich einige Optionen
· unten rechts werden die Informationen des ausgewählten Baums angezeigt

Auswahlliste

In der Auswahlliste werden alle zur Verfügung stehenden Bäume angezeigt. Oben befinden sich zwei Reiter, die die Anzeige umschalten.
· Übersetzung: Zeigt die Namen so an, wie diese im Spiel verwendet werden. Dies ist abhängig von der eingestellten Sprache. Wenn keine Übersetzung für die eingestellte Sprache vorhanden ist, wird der Objektname angezeigt.
· Objekt: Zeigt die internen Objektnamen an.

Optionen

· alle Klimazonen: Diese Option deaktiviert die Klimazonenzuordnung beim Pflanzen des Baums.
· Zufallsjahr: Es wird beim Pflanzen des Baums ein zufälliges Baumalter gewählt.

simutrans-124.3/simutrans/text/de/chat.txt000066400000000000000000000067211474050137200206420ustar00rootroot00000000000000Das Chatfenster

Das Chatfenster

Das Chatfenster kann, während Multiplayer-Spielen über die Haupt-Werkzeugleiste aufgerufen werden. Nachrichten können mit allen aktiven Mitspielenden ausgetauscht werden.

Zuoberst befindet sich ein Kontrollkästchen 'transparenter Hintergrund', mit dem die Sichtbarkeit des Chat-Fensters gesteuert werden kann. Dies kann zB. bei kleinflächigen Bildschirmen nützlich sein.
Darunter erscheinen die drei Reiter, mit denen zwischen den verschiedenen Chat-Arten gewechselt werden kann:
- Allgemeiner Chat
- Firmeninterner Chat
- Direktnachrichten (Privater Chat)
Danach folgt in Sprechblasen-Form der Chat-Verlauf.
Wurden noch keine Nachricht gesendet, ist das Feld einfach leer.
Zuunterst befinden sich die Eingabezeile für Nachrichten und links davon ein Pfeil-Symbol, für das beifügen der gegenwärtigen Koordinaten an die Nachricht. Angefügte Koordinaten werden durch ein Pfeil-Symbol direkt neben der Sprechblase vor dem Datum im Chat-Verlauf angezeigt.

Zum senden einer Nachricht, klickt man in die Eingabezeile, tippt die Nachricht ein und sendet durch Drücken von Eingabe/Enter ab.
Die gesendete Nachricht erscheint nun im Chatverlauf.
Um das leere Eingabefeld zu verlassen kann erneut Eingabe/Enter. gedrückt werden oder mit der Maus an einen beliebigen anderen Ort geklickt werden.
Durch Drücken von esc wird das aktive Fenster geschlossen.

Erhaltene Nachrichten werden ausser im Chat-Fenster, auch im News-Ticker, am unteren Bildschirmrand angezeigt und durch eine weisse Zahl in einem roten Punkt auf dem Chat-Button in der Werkzeugleiste.

Nachrichten im allgemeinen Chat sind für alle Mitspielenden lesbar.
Ausserdem bleibt dieser Chatverlauf über die gesamte Dauer der aktuellen Multiplayer-Karte bestehen.

Nachrichten im Firmeninternen Chat sind "nur" für Mitspielende sichtbar, die in derselben Firma aktiv sind. Theoretisch können jedoch alle eine bestimmte Firma auswählen und den Chat einsehen, auch wenn diese Passwortgeschützt ist.
Dieser Chatverlauf bleibt über die ganze Dauer der Karte bestehen.

Direktnachrichten können zwischen zwei Mitspielenden ausgetauscht werden, ohne dass diese Nachrichten für dritte ersichtlich sind.
Unter dem entsprechen Reiter kann eine aktiver Mitspielender ausgesucht, und anschliessend angeschrieben werden.
Alternativ kann auch im Chat-Verlauf das Pfeil-Symbol, neben des Namens eines Mitspielenden, angeklickt werden, um in den Direktnachricht-Chat mit dieser Person zu wechseln.
Der Chatverlauf wird bei verlassen der Sitzung gelöscht.

Beachte bitte:
- Das Drücken der Tab Taste bewirkt ebenfalls ein Absenden der Nachricht. Ausserdem kommt es vor, dass ein vorbestehender Text in der Eingabezeile unbeabsichtigt abgesendet wird, wenn gerade ein neues Spielmitglied beitritt.
- Nachrichten sind auf maximal 226-Zeichen begrenzt. Das Senden von Grafiken, wie zB. Emojis, ist nicht möglich. Ebenso ist das Einfügen von Zeilenumbrüchen nicht möglich.
- Durch Doppelklicken auf eine Sprechblase, wird deren Text in die Zwischenablage kopiert und durch ein kleines Meldefenster bestätigt (kopiert/copied). Dies ist beispielsweise beim Austausch von URL's zu Forum-Artikeln besonders praktisch.

simutrans-124.3/simutrans/text/de/citybuilding_build.txt000066400000000000000000000042471474050137200235710ustar00rootroot00000000000000Stadtgebäude bauen

Stadtgebäude bauen

Der Dialog ist in vier Bereiche aufgeteilt.
· oben links befindet sich die Auswahlliste mit den Stadtgebäuden
· unten links wird das Bild des ausgewählten Stadtgebäudes angezeigt
· oben rechts befinden sich einige Optionen
· unten rechts werden die Informationen des ausgewählten Stadtgebäudes angezeigt

Auswahlliste

In der Auswahlliste werden alle zur Verfügung stehenden Stadtgebäude angezeigt, wenn die entsprechenden Optionen aktiviert (Wohnhaus, Gewerbegebäude, Industriegebäude) sind. Oben befinden sich zwei Reiter, die die Anzeige umschalten.
· Übersetzung: Zeigt die Namen so an, wie diese im Spiel verwendet werden. Dies ist abhängig von der eingestellten Sprache. Wenn keine Übersetzung für die eingestellte Sprache vorhanden ist, wird der Objektname angezeigt.
· Objekt: Zeigt die internen Objektnamen an.

Die Schriftfarben haben folgende Bedeutung:
· blaue Schrift kennzeichnet Wohnhäuser.
· grüne Schrift kennzeichnet Gewerbegebäude.
· schwarze Schrift kennzeichnet Industriegebäude.

Optionen

· alle Klimazonen: Diese Option deaktiviert die Klimazonenzuordnung beim Bau des Stadtgebäudes.
· Mit Epoche ab Jahr: Es werden nur die Gebäude in der Auswahlliste angezeigt, die im aktuellem Spieljahr zur Verfügung stehen.
· Auch veraltete zeigen: Es werden auch die Gebäude in der Auswahlliste angezeigt, die in früheren Spieljahren mal zur Verfügung standen.
· Wohnhaus: Es werden die Wohnhäuser in der Auswahlliste angezeigt.
· Gewerbegebäude: Es werden die Gewerbegebäude in der Auswahlliste angezeigt.
· Industriegebäude: Es werden die Industriegebäude in der Auswahlliste angezeigt.
· Rotation: Sofern das ausgewählte Stadtgebäude mehrere Ansichten hat, kann hier eine bestimmte Ansicht ausgewählt werden. Die Grafik unten links wird entsprechen gewechselt. Bei der Auswahl von Zufällig, wird beim Bau des Stadtgebäudes irgendeine Ansicht gewählt.

simutrans-124.3/simutrans/text/de/citygrowth.txt000066400000000000000000000217671474050137200221350ustar00rootroot00000000000000Details zu Stadtwachstum

Stadtwachstum

Dieser Text erläutert wie es zum Stadtwachstum kommt. Wie es berechnet wird. Welche Gebäude entstehen und warum. Und wie man über die diversen Parameter Einfluss auf die Stadtentwicklung nehmen kann.

Eine Stadt wächst dann wenn Personen und Post an ihr Ziel befördert werden.
Und sie wächst auch dann wenn zur Stadt gehörende Märkte, Kraftwerke und Fabriken mit Waren versorgt werden.

Wachstumsfaktor Personenverkehr
Die relevanten Werte zum berechnen stehen im Stadtinformation Dialog
· Beförderungen: Anzahl Passagiere ihre Reise angetreten haben. Das sind die lächelnden Passagiere in den Haltestellen.
· zu Fuß: Anzahl Passagiere die zu Fuß gehen.
· Passagiere: Alle Passagiere die befördert werden wollen.
Wachstumsfaktor = (Beförderungen + zu Fuß) / Passagiere * passenger_multiplier
Der passenger_multiplier wird in der simuconf.tab oder im den Einstellungen gesetzt.
Standartwert wenn nicht geändert ist 40.
Der Wachstumsfaktor bewegt sich dann im Bereich 0 bis 40.

Wachstumsfaktor Post Transport
· abgeschickt: Anzahl Postsendungen die unterwegs sind.
· Wurfsendungen: Anzahl Postsendungen die vom Absender zu Fuß zugestellt worden sind.
· Post: Alle in der Stadt anfallenden Postsendungen.
Wachstumsfaktor = (abgeschickt + Wurfsendungen) / Post * mail_multiplier
Der mail_multiplier wird in der simuconf.tab oder im den Einstellungen gesetzt.
Standartwert wenn nicht geändert ist 20.
Der Wachstumsfaktor bewegt sich dann im Bereich 0 bis 20.

Wachstumsfaktor Waren Transport
· Angekommen: Anzahl gefüllter Eingangs-Lager von Fabriken die zur Stadt gehören.
· Waren: Anzahl Eingangs-Lager der Fabriken die zur Stadt gehören.
Achtung: Die Werte "Angekommen" und "Waren" sind etwas schwer Verständlich. Es werden die Eingangslager der Fabriken gezählt, aber nur bei Kraftwerken und Endverbrauchern. Mit Endverbraucher sind hier z.B. Märkte gemeint, aber Vorsicht auch eine verarbeitende Fabrik kann als Endverbraucher gelten, wenn sie mit keinem Abnehmer verbunden ist. Des weiteren zählen Fabriken ohne verbunden Lieferanten nicht. Es werden die Eingangslager bei jedem Tick gezählt, das sind nicht Tage eines Monats sondern im Pak128.german z.B. hat der Monat 50 Ticks. Wenn Arbeiter aus mehreren Städten in einer Fabrik arbeiten, dann wird diese Fabrik jeder dieser Städte als zugehörig betrachtet. Das gilt auch, wenn die Fabrik im Stadtgebiet einer anderen Stadt steht. Für das Stadtwachstum zählt letztlich das Verhältnis von gefüllten zu leeren Eingangslagern der Endverbraucher. Für ein hohes Stadtwachstum, könnte man auch die ungenutzte Fabriken mittels Öffentliche Hand entfernen.

Wachstumsfaktor = (Angekommen) / Waren * goods_multiplier
Der goods_multiplier wird in der simuconf.tab oder im den Einstellungen gesetzt.
Standartwert wenn nicht geändert ist 20.
Der Wachstumsfaktor bewegt sich dann im Bereich 0 bis 20.

Wachstum der Einwohner in der Stadt
Die Wachstumsfaktoren von Passagieren, Post und Waren werden addiert und durch den growthfactor_? geteilt.
Zum Teilen verwendet werden je nach Stadtgröße:
Dorf kleiner 1000 Einwohner growthfactor_villages=400
Stadt mit 1000 bis 10.000 Einwohner growthfactor_cities=200
Großstädte größer 10.000 Einwohner growthfactor_capitals=100
Die growthfactor_? werden in der simuconf.tab oder im den Einstellungen gesetzt.
Um den hier errechneten Wert werden die Arbeitslosen und Obdachlosen erhöht.
Erst wenn die Stadt Wohngebäude errichtet erhöht sich die Zahl der Einwohner.

Durch die gestaffelte Regelung bleiben Dörfer länger Dörfer. Beziehungsweise wird ein eher quadratisches Wachstum nachempfunden, da die Einwohnerzahl in Simutrans linear wächst.

Niedrigere Werte bei growthfactor_? oder höhere bei den ?_multiplier erhöhen das Wachstum.

Jedes pak kann eine eigene simuconf.tab mit eigenen Werten haben. Aus den Standartwerten ergibt sich bei 50 Ticks pro Monat.
Eine Dorf wächst bei optimaler Versorgung um maximal 10 Einwohner pro Monat, oder um 120 Einwohner pro Jahr.
Eine Stadt wächst um 20 Einwohner oder 240 pro Jahr.
Eine Großstadt um 40 pro Monat oder 480 pro Jahr.
Diese theoretischen Wachstumszahlen werden in der Praxis nicht ganz erreicht, weil es der Stadt nicht immer gelingt neue Häuser zu platzieren. Beim Bau von besonderen Gebäuden kann es auch zu Ausreißern nach oben im Wachstum kommen.

Entstehung Stadtautos
Anzahl = random((citycar_level / 16) * log10(Einwohner * (1 - max(Faktor beförderte Personen, Post, Waren))))
Der citycar_level wird in der simuconf.tab oder im den Einstellungen gesetzt.
Kurz: aus den Kategorien Personen, Post oder Waren wird die mit den meisten Transporten genommen und davon die nicht transportieren mit der Einwohnerzahl und citycar_level verrechnet ergibt die Anzahl Stadtautos.

Zusammenhang von Stadtwachstum, Arbeits- und Obdachlosenzahlen
Bei einer neu gegründeten Stadt sind zunächst alle Einwohner arbeitslos und obdachlos.
Die Arbeits- und Obdachlosigkeit bekämpft die Stadt (und nur sie!) mit dem Bau von Stadtgebäuden.
Sie baut neue Gebäude oder ersetzt Gebäude durch solche mit einem höheren Level.
Die Zahl der Arbeits- oder Wohnungslosen sinkt dann um Level * 10 des neuen Gebäudes.
Je besser das Verhältnis von zufriedenen zu generierten Passagieren (und Post) ist, desto schneller wachsen die Städte. Und je schneller sie wachsen, desto schneller steigen Arbeits- und Obdachlosenzahlen an, und desto schneller muss die Stadt wieder bauen, und umso mehr Kunden wollen Deinen Service nutzen. Ein Trugschluss ist es, mit der Beförderung von Arbeitern zu einer Fabrik die Arbeitslosigkeit senken zu wollen, im Gegenteil: Viele Passagiere werden zufrieden, und über das dadurch beschleunigte Wachstum steigen die Arbeitslosenzahlen sogar noch schneller an!
Die Titelzeile des Infofensters ist orange wenn die Arbeits- oder Obdachlosenzahlen über 70 steigen.

Entstehung der Gebäude in der Stadt
- Industrie: (ind) Industriegebäude dienen als Arbeitsstätten innerhalb der Stadt. Ihr Bau oder ihre Erneuerung verringert die Arbeitslosenzahl. Ihre Postrate ist halb so gross wie ihre Passagierrate. Diese Gebäude sind normale Stadthäuser und kennen keinen Warenverkehr.
- Wohngebäude: (res) In den Wohngebäuden leben die Einwohner. Ihr Bau oder ihre Erneuerung verringert die Obdachlosenzahl. Ihre Postrate ist gleich der Passagierrate.
- Gewerbeobjekte: (com) Zu den Gewerbeobjekten zählen u.a. Ladengeschäfte, Lokale, Freizeiteinrichtungen und Bürogebäude. Die Gebäude sind oft auch mit Wohnungen kombiniert. Ihr Bau oder ihre Erneuerung verringert sowohl die Arbeitslosen- wie Obdachlosenzahl. Ihre Postrate ist doppelt so hoch wie ihre Passagierrate.
· Monumente: (mon) Monumente werden zufällig, aber nur einmalig auf der Karte gebaut.
· Öffentliche Gebäude: (tow, cur) Für die Errichtung von öffentlichen Gebäuden wie grössere Rathäuser, Denkmäler und Stadtattraktionen sind die Schwellenwerte in den paks mit dem Parameter build_time=? festgelegt, ebenso eine Wahrscheinlichkeit, mit der die Attraktion gebaut wird.

Auswahl welches Gebäude gebaut wird: (ind, res, com)?:
Berechnung der Score Werte von denen der Typ des Stadtgebäudes abhängt. Die Parameter sind in der cityrules.tab zu finden.
defaults von Simutrans (res_start_score usw.)
--- ( start, near ind, near com, near res)
res ( 0, -8, 0, 8)
com (-10, 1, 8, 1)
ind ( 0, 8, 0, -8)

Erzeugung neuer Industrieketten:
· Industrieketten/Fabriken: Diese können vom Spieler mit Waren beliefert werden, oder liefern Waren.
Wächst die Stadt über industry_increase_every hinaus, werden zusätzlich Fabriken oder auch ganze Ketten gebaut. Diese Schwelle verdoppelt sich jedes mal. Wird der verdoppelte Wert überschritten, werden erneut Fabriken gebaut. Der Wert 0 verhindert das bauen von Fabriken. ?Die Fabrik kann in der auslösenden Stadt stehen, kann aber auch an einem beliebigen anderen Ort stehen.?
Der Wert von industry_increase_every kann in der simuconf.tab oder im den Einstellungen gesetzt werden.
Die Errichtung von Fabriken hat keine Auswirkung auf die Arbeitslosen- oder Obdachlosenzahl.

simutrans-124.3/simutrans/text/de/citylist_filter.txt000066400000000000000000000022311474050137200231240ustar00rootroot00000000000000Stadtliste

Stadtliste

Die Stadtliste wird mit Shift+T oder über die Listenverwaltung aufgerufen.
Im Fenster sind alle Städte der Karte gelistet zusammen mit ihrer Einwohnerzahl und dem aktuellen Wachstum. Die Liste kann nach Name, Einwohnerzahl und Wachstum sortiert werden. Das Feld Statistik öffnet einen Graphen, auf dem Informationen über die Karte abgefragt werden können, so zum Beispiel die Entwicklung der Gesamteinwohnerzahl.

Listeneinträge: Klickst Du einen Stadtnamen an, wird die Karte auf die Stadt zentriert, das Fenster der Stadtinformation öffnet sich.
· Stadtname: Den Namen der Stadt kannst Du in der Stadtinformation ändern.
· Einwohnerzahl: Die Zahl der Einwohner wird angezeigt.
· Wachstumsfaktor: Der Wachstumsfaktor lässt Rückschlüsse auf die Wachstumsrate der Stadt und deren Beförderungsversorgung zu. Je höher der Wert ist, desto geringer ist die Differenz zwischen Beförderungsbedarf und der erbrachten Beförderungsleistung.

simutrans-124.3/simutrans/text/de/citywindow.txt000066400000000000000000000111171474050137200221160ustar00rootroot00000000000000Stadtinformation

Stadtinformation

Die Stadtinformation zeigt Statistiken über die ausgewählte Stadt. Du kannst sie durch anklicken des Rathauses mit der Lupe öffnen. Das anklicken des Stadtnamens in der Stadtliste öffnet die Stadtinformation ebenfalls.

· Name der Stadt: Hier kannst du den Stadtname ändern. Bei Stadtgründung wird ein zufälliger aus der Datei pak/text/citylist_de.txt gewählt.
Vom Stadtnamen werden die Haltestellennamen abgeleitet.

· Größe: Die Einwohnerzahl der Stadt wird angezeigt.
· Bevölkerungszunahme: Die Zahl in Klammern hinter der Größe gibt das derzeitigen Wachstum der Bevölkerung an.
· Gebäude: Anzahl der Häuser in der Stadt.
· Stadtgebiet: Das Gebiet der Stadt umfasst das Quadrat, welches durch die beiden Koordinatenpaare (links oben und rechts unten) gebildet wird. Innerhalb der Stadtgrenzen realisiert die Stadt ihre Bauvorhaben. Mit dem Wachstum der Stadt erweitern sich deren Grenzen. Stadtgebiete können sich überlappen.
· Die Stadt generiert Passagiere und Post zunächst für Bebauungen entsprechend den in den Gebäudeinfofenstern angegebenen Passagier- und Postraten. Reise- und Versandziele können alle Felder der Stadtgebiete (also auch der Ausflug zu den Grünflächen der Städte), der Ausflugziele und Fabriken sein.

· Anzahl Arbeitslose und Obdachlose Mit diesen Werten entscheidet die Stadt ob sie baut und wenn ja, ob sie Wohnhäuser, Industrie- oder Gewerbegebäude baut.
· Stadt darf wachsen: Ein nicht gedrückter Knopf blockiert das Wachstums. Dann werden Häuser und Straßen nicht erneuert oder verändert. Nützlich bei manuell gebauten Städten.

Minikarten mit Passagier- und Postziele: Die beide Weltkarten zeigt die Ziele der Stadtbürger. Links für den letzten und damit für einen kompletten Monat, rechts bisher aufgelaufene Ziele im aktuellen Monat.
- gelber Punkt: Für jede angetretene Reise und für jede abgesandte Postsendung wird das Ziel mit einem gelben Punkt markiert.
- Dunkel oranger Punkt: Dieser wird an das beabsichtigte Ziele platziert, wenn keine Route gefunden wurde.
- Hell oranger Punkt: Dieser markiert das Ziel, wenn der Passagier unglücklich ist, weil bereits die Starthaltestelle überfüllt ist. Er sucht nicht im Fahrplan nach einer Route sondern geht sofort wieder nach Hause.

Statistiken: Die Farben der Kurven entsprechen jenen der Statistikschalter. Werte werden je nach der Einstellung der Anzeigezeiträume jahresweise oder monatweise aufaddiert. Die neuesten Werte stehen links. Klickt man einen Punkt der Kurve an, so wird der genaue Wert angezeigt.
· Einwohner: Die Entwicklung der Einwohnerzahl wird dargestellt.
· Wachstum: Das Bevölkerungswachstum der Stadt wird dargestellt.
· Stadtgebäude: Anzahl der Stadt Gebäude in der Stadt.
· Stadtautos: Passagiere die nicht befördert werden, fahren mit dem eigenen Auto.
· Beförderungen: Anzahl Passagiere die ihre Reise angetreten haben. Das sind die lächelnden Passagiere in den Haltestellen.
· zu Fuß: Anzahl Passagiere die zu Fuß gehen.
· Passagiere: Alle Personen der Stadt die befördert werden wollen.
Je näher beieinander die Graphen für "Beförderungen" und "Passagiere" liegen, desto schneller wächst die Stadt.
· abgeschickt: Anzahl Postsendungen die unterwegs sind.
· Wurfsendungen: Anzahl Postsendungen die vom Absender zu Fuß zugestellt worden sind.
· Post: Alle in der Stadt anfallenden Postsendungen.
Je näher beieinander die Graphen für "abgeschickt" und "Post" liegen, desto schneller wächst die Stadt.
· Angekommen: Anzahl Eingangs-Lager der Fabriken die zur Stadt gehören und die Waren enthalten. Es wird bei jedem Tick gezählt.
· Waren: Anzahl Eingangs-Lager der Fabriken die zur Stadt gehören.
Je näher beieinander die Graphen für "Angekommen" und "Waren" liegen, desto schneller wächst die Stadt.
Die Eingangslager zählen für diese Stadt, wenn auch Arbeiter der Fabrik in dieser Stadt wohnen. Das wird in der erste Tab der Fabrik angezeigt.

Stadtwachstum:
Nun bist Du als Spieler gefragt: Erschließe die Stadt mit dem öffentlichen Verkehr für Personen und Post. Versorge die Märkte mit Waren.
Ohne Versorgung kein Wachstum in der Stadt.
Detaillierte Informationen zum Stadtwachstum findest du hier

simutrans-124.3/simutrans/text/de/climates.txt000066400000000000000000000040731474050137200215220ustar00rootroot00000000000000Klimazonen

Kliamzonen Hilfe

Dieser Dialog erscheint immer zusammen mit dem Neue Welt Dialog. Mit ihm können diverse Details zu den Klimazonen und Bergen der neuen Karte eingestellt werden.

· Grundwasser: Den Pegel des Grundwassers kannst Du von 0 bis 5 festlegen. Je niedriger der Pegel ist, desto mehr Land erscheint und umgekehrt. Die Vorgabe ist 4.

· Berghöhe: Der Maximalwert für die Höhe der höchsten Berge beträgt 320. Die Vorgabe ist 160.

· Bergigkeit: Dieser Wert bestimmt, wieviel kleinere Hügel und Täler generiert werden. Mögliche Werte sind 0 bis 4. Die Vorgabe ist 2. Eine zu rauhe Karte wird eventuell nicht so viele Städte, Insdustrien oder Verbindungsstraßen erzeugen können, wie eingestellt.

Im folgenden werden die Grenzen der Schneezone festgelegt. Im Laufe des Jahres sinkt und steigt die Schneegrenze in Simutrans entsprechend der gewählten Einstellung.

· Sommerschnee: Ab dieser Höhe beginnt der ewige Schnee. Dort gibt es sehr wenige Städte, Industrien und Vegetation.

· Winterschnee: Bis zu dieser Höhe fällt im Winter Schnee. Das hat keine Auswirkungen auf das Spiel sondern dient allein der Optik.

Im nächsten Block werden die Grenzen der einzelnen Klimazonen bestimmt. Diese werden in Höhenstufen ab Grundwasser gerechnet. Die Anzeige der Klimazonen geht von Null bis zur eingestellten Höhe. Höhere Klimazonen werden dabei von niedrigeren Klimazonen im unteren Bereich überdeckt. Du kannst also Wüste in Tundra und dann in Tropen übergehen lassen.
Achtung:
Gebäude, Industrien und Vegetation können bestimmten Klimazonen zugeordnet sein. In welchen Klimazonen was vorkommt, liegt in den Händen der Pakset- und Addon-Ersteller.

Ist die Schaltfläche Keine Bäume aktiviert, werden auf der neuen Karte keine Bäume generiert.

Als letztes können Parameter eingestellt werden, um die Erzeugung von Flüssen auf der neuen Karte zu beeinflussen.

simutrans-124.3/simutrans/text/de/color.txt000066400000000000000000000004741474050137200210400ustar00rootroot00000000000000Farbauswahl

Farbauswahl

Du kannst die eigene Spielerfarbe festlegen. Die Farbe wird für die meisten Fahrzeuge und Gebäude des Spielers genutzt. Es gibt zwei Farben, eine Primäre und eine Sekundäre.

Die Standardfarbe ist primär hellblau und sekundär gelb.

simutrans-124.3/simutrans/text/de/convoi.txt000066400000000000000000000053551474050137200212220ustar00rootroot00000000000000Fahrzeugliste

Fahrzeugliste

Die Fahrzeugliste wird über die Listenverwaltung oder mit Shift+V aufgerufen und beinhaltet alle Fahrzeugverbände, also Züge, Busse, LKWs, Trams, Flugzeuge, Schiffe und Magnetbahnen des Spielers. In die Liste sind eine Sortier- und eine Filterfunktion eingebaut, um unter vielen Fahrzeugverbänden den gesuchten schneller auffinden zu können.
Der Filter kann entweder "an" oder "aus" sein. Wenn Du einen Fahrzeugverband nicht findest, wähle die Filtereinstellung "aus". Die Voreinstellung ist "aus". Über einstellen können die Filterkriterien ausgewählt werden.

Anzeigen in der Fahrzeugliste:
· Eine Ordnungszahl. Diese nummeriert nur die Liste durch und hat keinen Bezug zum Fahrzeugverband dahinter.
· Der Name (per Vorgabe der Name des ersten Fahrzeugs, das in den Fahrzeugverband eingereiht wurde).
· Der Gewinn des Fahrzeugverbandes für das laufende Jahr.
· Die Linie, welche dem Fahrzeugverband zugewiesen ist. Ist dem Fahrzeugverband keine Linie zugewiesen, wird auch nichts angezeigt. Bei Fahrzeugverbänden, die sich im Depot befinden, wird hier "(in depot)" angezeigt.
· Ein Bild des Fahrzeugverbandes, mit einem Balken für den aktuellen Ladegrad (siehe Fahrezugfenster).

Die Farbe des Names des Fahrzeuges hat folgende Bedeutung:
- schwarz: alles ok.
- rot: Erwirtschaftet keinen Profit.
- weiß: Steht in einem Depot.
- gelb: Steht seit Jahresbeginn (vermutlich an einer Haltestelle und wartet auf Fracht).
- orange: Steckt fest oder findet keine Weg zum Ziel.

Sortierkriterien: Die Sortierung der Fahrzeugliste kann nach 3 Sortierkriterien erfolgen. Die Anzeige-Reihenfolge wird nur beim Öffenen des Fensters und bei der Änderung der Sortierkriterien aktualisiert.

· Bezeichnung: Die Sortierung erfolgt in der Namensreihenfolge. Sie orientiert sich am ASCII-Code der Zeichen, also Zahlen, danach Großbuchstaben, danach Kleinbuchstaben, jeweils in numerischer bzw. alphabetischer Reihenfolge.
· Gewinn: Die Fahrzeugverbände werden nach ihrem im laufenden Jahr erzielten Gewinn (Einnahmen-Betriebskosten) sortiert.
· Typ: Die Liste wird nach Fahrzeugtypen sortiert. Die Typreihenfolge ist: Straßenfahrzeuge, Schienenfahrzeuge, Schiffe, Flugzeuge. Gleiche Zugmaschinen werden zusammengefasst. Innerhalb einer Fahrzeugkategorie wird alphanumerisch sortiert.
· aufsteigend/absteigend: Stellt die Liste auf den Kopf. Bei aufsteigend stehen die kleinsten Werte oben, bei absteigend die größten.

simutrans-124.3/simutrans/text/de/convoi_filter.txt000066400000000000000000000045351474050137200225660ustar00rootroot00000000000000Fahrzeuglistenfilter

Filtereinstellungen zur Fahrzeugliste

Im Fenster der Fahrzeugliste - Einstellungen können die Filteroptionen für die Anzeige in der Fahrzeugliste gesetzt werden. Ein eingedrückter Knopf bedeutet, dass das Kriterium erfüllt sein muss, um durch den Filter zur Anzeige zu gelangen. Dabei werden die Eigenschaften innerhalb einer Hauptgruppe mit logischem "OR" (eines der angewählten Kriterien muss erfüllt sein) und zwischen den Hauptmenüs mit logischem "AND" (alle angewählten Kriterien müssen erfüllt sein) verknüpft. Die Wirkung der Filtereinstellungen ist positiv, es werden nur Fahrzeugverbände angezeigt, welche die eingestellten Kriterien erfüllen.

Namen filtern: Im Textfeld kann der Name eines Fahrzeugverbandes bzw. mehrerer Fahrzeugverbände angegeben werden. Es werden nur diejenigen Fahrzeugverbände in die gefilterte Liste aufgenommen, deren Bezeichner mit dem Name des Filters in allen Zeichen (inkl. Leerzeichen) identisch ist. Achtung: Platzhalterfunktionen wie * oder ? werden nicht unterstützt.

Typen filtern: Die gefilterte Liste zeigt nur Fahrzeugverbände an, welche dem gefilterten Typ entsprechen. Trams und Magnetbahnen sind den Zügen zugeordnet.

Spezialfilter:
· ohne Route: Derzeit ist diese Funktion außer Betrieb.
· ohne Fahrplan: Fahrzeugverbände ohne Fahrplan werden gelistet.
· kein Gewinn: Fahrzeugverbände ohne positiven Profit im aktuellen Jahr werden gelistet.
· im Depot: Fahrzeugverbände, die in einem Depot stehen werden gelistet.
· ohne Linie: Fahrzeugverbände, die keiner Linie zugeordnet sind, werden gelistet.

Waren filtern: Fahrzeugverbände werden nach ihrer transportierten Warenart ausgewählt. Der Filter berücksichtigt teilweise nicht das Ladegut, sondern orientiert sich nach den Fahrzeugeigenschaften. So kann etwa ein Erzzug unter Steine auftauchen, wenn er Steinwagen benutzt.

Filterschalter:
· alle: Alle Güterarten ausgewählt.
· keine: Alle Güterarten abgewählt.
· inv.: Bei Betätigung wird die Güterauswahl umgekehrt.

Warenschalter: Über die Schalter der Warenarten kannst Du eine beliebige Filterauswahl treffen.

simutrans-124.3/simutrans/text/de/convoidetail.txt000066400000000000000000000017621474050137200224030ustar00rootroot00000000000000Erweiterte Fahrzeuginformationen

Erweiterte Fahrzeuginformationen

Dieses Fenster erreicht man durch Auswahl von Details im Konvoifenster. Es werden weitere technische Daten angezeigt, wie Leistung, insgesamt gefahrene km und der aktuelle Zeitwert.

Die Angabe min. Haltlänge gibt an, wie lang Stationen an denen gehalten werden soll sein müssen, damit alle Fahrzeuge geladen/entladen werden.

Die Angabe Maximalgeschwindigkeit gibt an, ........

Mit Entfernen! kann der Fahrzeugverband sofort an dieser Position verkauft werden, ohne zuvor in ein Depot fahren zu müssen.

Weiterhin gibt es noch Ausmustern, danach lädt der Fahrzeugverband nur noch seine Waren ab und wird verkauft, sobald er leer ist.

Darunter folgten alle Einzelfahrzeuge mir ihren technischen Daten. Bei Fahrzeugen mit Laderaum wird auch deren aktuelle Beladung angezeigt.

simutrans-124.3/simutrans/text/de/convoiinfo.txt000066400000000000000000000122621474050137200220710ustar00rootroot00000000000000Fahrzeugfenster

Fahrzeugfenster

Wählst Du mit dem Lupenwerkzeug einen Fahrzeugverband an, wird dessen Infofenster geöffnet. Du kannst das Fenster auch aus der Linienverwaltung oder Fahrzeugliste heraus aufrufen. Wähle dazu einen Eintrag in der Liste an. Das Fenster zeigt Dir einige technische Daten, eine Statistik und die Beladeliste.

Namensfeld: Der Name des Fahrzeugverbandes entspricht per Vorgabe der Bezeichnung des Fahrzeugs, das als erstes in den Konvoi aufgenommen wurde.

Aktuelle Daten:
· Geschwindigkeit, Wartungskosten: Die erste Geschwindigkeitsangabe ist die Höchstgeschwindigheit des Fahrzeugverbandes, die zweite die des Zugfahrzeugs. Der Wert in Klammern stellt die Laufkosten pro zurückgelegtem Feld des gesamten Fahrzeugverbandes dar. Die grüne Säule rechts daneben gibt die aktuelle Geschwindigkeit in relativ zur Höchstgeschwindigkeit an. Wird die aktuelle Geschwindigkeit nie erreicht, ist der Fahrzeugverband eventuell überladen oder der Weg lässt gerade keine höhere Geschwindigkeit zu.
· Leistung: Mit der Leistung wird die gesamte Antriebsleistung der aller Zugfahrzeuge in kW angegeben.
· Gewicht: Die erste Angabe stellt das Leergewicht des Fahrzeugverbandes dar, der Wert in Klammern ist das Gewicht der Ladung. Für das Gesamtgewicht müssen beide Werte zusammengezählt werden.
· Gewinn: Der Gewinn seit dem 1. Januar des Jahres wird angegeben. Ist der Wert negativ, fährt der Fahrzeugverband mit Verlust.
· Ladegrad: Der grüne Farbbalken gibt Dir Aufschluss über die aktuelle prozentuale Beladung des Fahrzeugverbandes. Ein (teil)gelber Balken bedeutet, dass der Fahrzeugverband auf die im Fahrplan eingestellte Mindestbeladung wartet.
· Fahrtziel: Das aktuelle Fahrplanziel wird angezeigt. Ist das Ziel eine Haltestelle, gibt Dir der erste Wert in Klammer darüber Auskunft, auf welchen minimalen Beladegrad der Fahrzeugverband warten wird. Du kannst den Wert für den Fahrzeugverband im Fahrplan ändern. Sollen alle Fahrzeuge der Linie von der Änderung betroffen sein, suche die Linie in derLinienverwaltung auf. Der farbige Balken dahinter gibt die Entfernung bis zum nächsten Halt an.
· Bedient Linie: Der Fahrzeugverband fährt nach dem Plan der angegebenen Linie. Weicht der Fahrplan nach einer Änderung vom Linienplan ab, oder fährt der Fahrzeugverband in keiner Linie, wird die Zeile nicht angezeigt. Mit dem Dreieck kann man direkt die Linie in der Linienverwaltung öffnen.

Fahrplan: Über die Schaltfläche kannst Du den Fahrplan des Fahrzeugverbandes aufrufen.

Sichtfenster: Den Fahrzeugverbandes siehts Du im Kartenausschnitt rechts daneben. Klickst Du ins Sichtfenster, springt die Kartenansicht und zentriert die aktuelle Position. Soll der Fahrzeugverband dauerhaft in Bildmitte zu sehen sein, benutze den Knopf verfolgen unter dem Kartenausschnitt.

nach Hause: Bedienst Du den Schalter, bricht der Fahrzeugverband seinen Weg im Fahrplan ab und steuert auf dem kürzesten Weg das nächstgelegene geeignete Depot an. Beim Erreichen des Depots geht sämtliche Fracht verloren; immerhin wird Dir der Ertrag für die geleistete Strecke ausbezahlt. Die Linie bzw. der Fahrplan sowie der letzte angesteuerte Fahrplanpunkt bleiben weiterhin gültig.

nicht laden: Der Fahrzeugverband wird ab sofort alle Mindestladung ignorieren und nur noch Fracht abladen.

Chart: Nach der Bedienung des Schalters öffnet bzw. schließt sich ein Statistikbereich mit grafischer Anzeige. Die Kurven entsprechen in den Farben jenen der selektierten Schalter und gewähren eine statistische Übersicht (monatsweise) über die letzten 12 Monate. Der aktuelle Monat steht links.
· Freie Kapazität: Der nicht genutzte Laderaum. Addiert für jeden Fahrplanabschnitt.
· Beförderungen: Der genutzte Laderaum. Addiert für jeden Fahrplanabschnitt.
· Einnahmen: Die Transporterlöse des Fahrzeugverbandes.
· Betriebskosten: Die anfallenden Kosten für den Betrieb des Fahrzeugverbandes. Die Schwankungen entstehen durch die unterschiedliche Laufleistung des Fahrzeugverbandes im Monat. Es entstehen nur Kosten, wenn der Fahrzeugverband sich bewegt.
· Profit: Der Profit ergibt sich aus Einnahmen minus Betriebskosten.
· Strecke/Monat: Die zurückgelegt Strecke aller Fahrzeuge der Linie.
· Geschwindigkeit:
· Maut: Kosten die durch Nutzung von Verkehrswegen anderer Spieler angefallen sind.

Beladeliste: Zeigt die Anzahl aller geladen Güter/Passagiere auf, geordnet nach Art. Diese Liste kann sortiert werden, nach Zielort, via (nächstes Ziel), via Menge (wieviel hat insgesamt den nächsten Halt als Ziel) oder Menge (am meisten zuerst). Diese Einstellung wird dann beim nächsten Öffnen für alle Fahrzeugverbände gemerkt.

simutrans-124.3/simutrans/text/de/curiosity_build.txt000066400000000000000000000047431474050137200231360ustar00rootroot00000000000000Sehenswürdigkeiten bauen

Sehenswürdigkeiten bauen

Der Dialog ist in vier Bereiche aufgeteilt.
· oben links befindet sich die Auswahlliste mit den Sehenswürdigkeiten
· unten links wird das Bild der ausgewählten Sehenswürdigkeit angezeigt
· oben rechts befinden sich einige Optionen
· unten rechts werden die Informationen der ausgewählten Sehenswürdigkeit angezeigt

Auswahlliste

In der Auswahlliste werden alle zur Verfügung stehenden Sehenswürdigkeit angezeigt, wenn die entsprechenden Optionen aktiviert (Stadtattraktionen, Ausflugsziel, Denkmal) sind. Oben befinden sich zwei Reiter, die die Anzeige umschalten.
· Übersetzung: Zeigt die Namen so an, wie diese im Spiel verwendet werden. Dies ist abhängig von der eingestellten Sprache. Wenn keine Übersetzung für die eingestellte Sprache vorhanden ist, wird der Objektname angezeigt.
· Objekt: Zeigt die internen Objektnamen an.

Die Schriftfarben haben folgende Bedeutung:
· grüne Schrift kennzeichnet Sehenswürdigkeiten, deren Standort sich außerhalb von Städten befindet.
· blaue Schrift kennzeichnet Sehenswürdigkeiten, deren Standort sich innerhalb von Städten befindet.
· schwarze Schrift kennzeichnet Denkmäler. Denkmäler können nur einmal pro Karte gebaut werden.

Optionen

· alle Klimazonen: Diese Option deaktiviert die Klimazonenzuordnung beim Bau der Sehenswürdigkeit.
· Mit Epoche ab Jahr: Es werden nur die Sehenswürdigkeiten in der Auswahlliste angezeigt, die im aktuellem Spieljahr zur Verfügung stehen.
· Auch veraltete zeigen: Es werden auch die Sehenswürdigkeiten in der Auswahlliste angezeigt, die in früheren Spieljahren mal zur Verfügung standen.
· Stadtattraktionen: Es werden die Sehenswürdigkeiten in der Auswahlliste angezeigt, deren Standort sich in Städten befindet.
· Ausflugsziel: Es werden die Sehenswürdigkeiten in der Auswahlliste angezeigt, deren Standort sich außerhalb von Städten befindet.
· Denkmal: Es werden die Denkmäler in der Auswahlliste angezeigt.
· Rotation: Sofern die ausgewählte Sehenswürdigkeit mehrere Ansichten hat, kann hier eine bestimmte Ansicht ausgewählt werden. Die Grafik unten links wird entsprechen gewechselt. Bei der Auswahl von Zufällig, wird beim Bau der Sehenswürdigkeit irgendeine Ansicht gewählt.

simutrans-124.3/simutrans/text/de/curiositylist_filter.txt000066400000000000000000000040371474050137200242140ustar00rootroot00000000000000Touristenzielliste

Touristenzielliste

Die Touristenzielliste wird über die Listenverwaltung geöffnet.
In der Touristenzielliste sind alle Sehenswürdigkeiten aufgeführt. Geplant ist die Erweiterung um Denkmäler. Ein Klick auf einen Eintrag öffnet den Gebäudetext (wir hoffen, sie haben Spaß daran) und stellt die Karte dar. Es gibt keine Sortierfunktionen.

· Status: Die Statusfarben sind
- Grün: Die Attraktion ist für den Passagierverkehr erschlossen.
- Blau: Die Attraktion ist für den Postverkehr erschlossen.
- Türkis: Die Attraktion ist für den Passagier- und Postverkehr erschlossen.
- Orange: Eine Haltestelle, die die Attraktion erschließt, ist überfüllt.
- Rot: Alle Haltestellen, die die Attraktion erschließen, sind überfüllt.
· Ein Gebäude neben dem Statusquadrat bedeutet, dass es sich um eine Stadtattraktion handelt.

· Name: Die Bezeichnung der Attraktion, gefolgt von den Kartenkoordinaten

· Passagierlevel: Nach dem Bindestrich folgen noch Passagier- und Postlevel. Attraktionen erzeugen von sich aus keine Passagiere, doch jeder Tourist, der dorthin will, erzeugt gleichzeitig seine Rückreise. Post wird ebenfalls nicht von sich aus erzeugt, doch eine geringe Anregung genügt, und die Touristen senden massenweise Ansichtskarten in die Welt hinaus.

· Erschliessung der Touristenziele: Einige Touristenziele bedecken eine grosse Landfläche. Um eine Fabrik anzuschließen reicht es aus, dass ein einziges Fabrikfeld im Bereich einer Haltestelle liegt. Im Gegensatz dazu werden von Attraktionen nur die Felder erschlossenen, die tatsächlich im Einzugsbereich von Haltestellen liegen. Um das Passagieraufkommen einer Attraktion vollständig zu nutzen, müssen also alle zugehörigen Felder durch den Einzugsbereich von Haltestellen abgedeckt werden. Touristen, deren Ziel auf einem nicht erschlossenen Feld liegt, finden sonst keine Route.

simutrans-124.3/simutrans/text/de/depot.txt000066400000000000000000000223651474050137200210400ustar00rootroot00000000000000Depots, Werften und Hangar

Depotfenster

Depotarten: Die Depots für Züge, Straßenfahrzeuge, Schiffe, Trams, Flugzeuge und Magnetschwebebahnen halten die jeweiligen Fahrzeugarten bereit. Im Depotfenster kannst Du Fahrzeuge kaufen und verkaufen sowie Fahrzeugverbände zusammenstellen, Zusammenstellungen ändern und auflösen. Im Aufbau unterscheiden sich die Depotfenster nicht.

Fenstertitelleiste: Rechts neben dem Fragezeichen befinden sich 2 Pfeilschaltflächen. Mit den Pfeilen kannst Du nacheinander zu den anderen Depots des gleichen Typs wechseln.

Fahrzeuglisten: Fahrzeugverbände, die sich im Depot befinden, werden in Fahrzeuglisten erfasst. Die Zeile gibt Aufschluss darüber, wieviele Fahrzeugverbände sich im Depot befinden. Sie zeigt auch an, welche Liste gerade ausgewählt ist.

Auswahl eines Fahrzeugverbandes: Mit den beiden Pfeilschaltflächen links und rechts des Edit-Feldes kannst Du allen Fahrzeugverbände durchschalten, die sich derzeit im Depot befinden. Möchtest Du einen neuen zusammenstellen, schalte bis zum Eintrag "Neuer Fahrzeugverband".
Im editierbaren Feld kannst Du den Namen des Fahrzeugverbandes nach Belieben ändern. Klicke mit der Maus in das Feld. Bestätige den Abschluss der Arbeit mit RETURN.

Linienauswahl: Du kannst eine bestehende Linie auswählen. Für die Durchschaltung der Linien stehen Dir die Pfeilschalter links und rechts der Linienauswahl zur Verfügung. Ein Klick in das Anzeigefeld öffnet ein Auswahlliste. In ihr kannst Du mit der Maus den gewünschten Eintrag auswählen. Es ist auch möglich, dort den Liniennamen zu editieren; aus eigener Erfahrung des Autors wird empfohlen, dies in der Linienverwaltung zu machen.

Fahrzeugansicht: Ein Fahrzeugverband besteht aus mindestens einem Einzelfahrzeug. Flugzeuge erlauben sind immer solo, Straßen- und Schiffsfahrzeugverbände können bis zu 4 Fahrzeuge, Schienenfahrzeugverbände bis zu 24 Einzelfahrzeuge enthalten. Der ausgewählte Fahrzeugverband wird in dem Feld darunter grafisch dargestellt.
· Wenn Du die Maus über ein Einzelfahrzeug führst, werden im unteren Bereich des Fensters dessen Fahrzeugdaten angezeigt.
· Klickst Du ein Einzelfahrzeug an, wird es aus dem Fahrzeugverband entfernt und im Depot eingelagert. Eine Ordnungszahl im Einzelfahrzeugdepot zeigt an, wie viele Fahrzeuge des Typs Du eingelagert hast.
· Unter der grafischen Ansicht des Fahrzeugverbandes werden die Anzahl der Fahrzeuge, die benötigte Haltenstellenlänge, der Verkaufswert und die bediente Linie angezeigt.

Die Funktionen der gruppierten Schaltflächen:
Start: Schicke einen Fahrzeugverband mit Fahrplan auf die Reise, es wird der im Fahrplan ausgewählte Halt angefahren.
Fahrplan: Das Fahrplan-Fenster wird geöffnet, in welchem Du einen individuellen Fahrplan erstellen kannst.
Auflösen: Der aktuelle Fahrzeugverbandes wird aufgelöst, alle Fahrzeuge werden ins Depot eingelagert.
Verkauf: Der aktuelle Fahrzeugverbandes wird zum aktuellen Verkaufswert verkauft.

Neue Linie:Das Linienplan-Fenster wird geöffnet, in welchem Du die Haltepunkte einer neuen Linie eintragen kannst.
Linie zuweisen: Weise dem Fahrzeugverbandes die aktuelle Linie der Linienauswahl zu.
Linie ändern: Im Linienplan-Fenster kannst Du die oben angezeigte Linie bearbeiten.
Kopieren: Kaufe einen Fahrzeugverbandes, der in seiner Zusammenstellung dem aktuellen Fahrzeugverbandes entspricht. Der Name und ein zugewiesener Fahrplan/Linie werden übernommen.

Einzelfahrzeugdepot: Im Depot sind alle derzeit verfügbaren Fahrzeuge des Depottyps nach ihrem Ladevermögen sortiert abgebildet. Mittels der Tab-Reiter sind sie nach Personen- und Postbeförderung, angetriebene und nicht angetriebene Fahrzeuge eingeteilt.
· Elektrisch betriebene Fahrzeuge werden nur angezeigt, wenn das Feld, auf welchem das Depot steht, elektrifiziert ist.
· Wenn Du die Maus über ein Fahrzeug führst, werden im unteren Bereich des Fensters dessen Fahrzeugdaten angezeigt.
· Fahrzeuge werden erst ab einem bestimmten Datum verfügbar. Einige Fahrzeuge veralten und werden außer Dienst gestellt. Du kannst sie, über den Knopf Auch veraltete Fahrzeuge zeigen, rechts unten, anzeigen lassen und sie kaufen.
· Möchtest Du, dass alle Fahrzeuge unabhängig von deren Einführungs-Datum verfügbar sind, dann wähle die Einführungsdaten bei der Welterstellung ab.

Depotaktionen

Aktionsschalter: Der Schalter rechts unten wechselt bei der Betätigung zwischen 3 Funktionseinstellungen.
· anhängen: Das angeklickte Einzelfahrzeug wird am Schluss des Fahrzeugverbandes angehängt.
· voranstellen: Das angewählte Einzelfahrzeug wird an der Spitze des Fahrzeugverbandes vorangestellt.
· verkaufen: Verkaufe ein eingelagertes Einzelfahrzeug. Der Verkaufswert aller eingelagerter Einzelfahrzeug des Typs ist bei den Fahrzeugdaten ersichtlich.

Die Farbbalken unter den Einzelfahrzeug im Depot ändern sich je nach Schalterstellung. Wenn der Farbbalken auf einer Seite gelb ist, gehört ein weiteres Einzelfahrzeug zur betriebsfähigen Zusammenstellung. Wird dieses Einzelfahrzeug gekauft, wird auch das zugehörige Einzelfahrzeug dazugekauft.

Die Farben bedeuten:
· grün: Das Einzelfahrzeug kann verwendet werden.
· rot: Das Einzelfahrzeug ist für die Aktion nicht verwendbar.
· gelb links: Ein anderes Einzelfahrzeug muss vorangestellt werden.
· gelb rechts: Ein anderes Einzelfahrzeug muss folgen.
· blau: Das aktuelle Jahr liegt außerhalb der Einsatzzeit des Einzelfahrzeug. Das Einzelfahrzeug kann verwendet werden.

Ein Fahrzeugverband ist einsatzbereit, wenn er für alle Einzelfahrzeug grüne Balken zeigt. Verbleiben teilgelbe Balken, sind noch Einzelfahrzeug beizustellen, etwa Zugmaschine, Tender oder Schlussfahrzeug.

Achtung Beachte bei Schienenfahrzeugverbänden, dass alle Fahrzeuge des Fahrzeugverbandes in die angefahrenen Haltestellen passen, sonst werden nur die Fahrzeuge beladen, die in der Haltestelle stehen. Das bedeutet, wenn eine Mindestbeladung eingestellt ist, die größer ist als die Ladekapazität der in der Haltestelle stehenden Einzelfahrzeuge ist, fährt der Fahrzeugverband niemals ab. An jedes Haltestellensegment passen in der Regel 2 Fahrzeuge.

Die Anzahl von eingelagerten Einzelfahrzeugen eines Typs ist an einer weißen Zahl links über dem Einzelfahrzeuge ersichtlich. Du kannst die Einzelfahrzeuge verkaufen oder in diesem Depot zu neuen Fahrzeugverbänden wiederverwenden.

Unter dem Einzelfahrzeugdepot wird die Anzahl aller hier eingelagerter Einzelfahrzeuge angezeigt.

Einzelfahrzeugdaten: Führst Du die Maus über ein Einzelfahrzeugen im Fahrzeugverband (oben) oder im Einzelfahrzeugdepot (mittig), werden dessen Daten im unteren Teil des Fensters eingeblendet:

Linke Spalte angetriebene Fahrzeuge:
· Typbezeichnung und in Klammern die Betriebsart (Dampf, Diesel, Elektrisch).
· Neupreis und in Klammern die Betriebskosten je Streckenkilometer.
· Leistung in KW und die Höchstgeschwindigkeit.
· Fahrzeuggewicht.
· Zuladung (wenn möglich) mit Transporteinheiten und Art des Gutes.
Linke Spalte antriebsloser Fahrzeuge:
· Typbezeichnung .
· Neupreis und in Klammern die Betriebskosten je Streckenkilometer.
· Zuladung mit Transporteinheiten und Art des Gutes.
· Fahrzeuggewicht.
· Höchstgeschwindigkeit.

Rechte Spalte:
· Einführungsdatum.
· Außerdienststellungsdatum (nicht bei allen Fahrzeugen).
· Bei angetriebenen Fahrzeugen das Übersetzungsverhältnis.
· Bei gekauften Fahrzeugen der Verkaufspreis.

Frachteinheiten:
Den Warenarten sind 5 Beladeeinheiten zugeordnet:
· Flüssigkeiten: m³
· Lose Güter: Tonnen (t)
· Größere Objekte: Stück
· Palettierte Güter: Paletten
· Lose Gebindeeinheiten: Sack
Bei Passagieren wird die Anzahl angegeben.

Güterarten:
Güter sind bei Simutrans nach 6 Kategorien klassifiziert:
· Gefriergut, Öl/Benzin, Schüttgut, Sonderfracht, Langholz und Stückgut.

· Einigen Güterarten können in den verschiedenen Paks unterschiedliche Frachteinheiten und Güterarten zugewiesen sein.
· Sonderfrachten benötigen zum Transport immer spezielle Fahrzeuge.
· Andere Fahrzeuge können jedes Gut aus ihrer Kategorie laden.
· Aus historischen Gründen haben einige Fahrzeuge immer noch irreführende Bezeichnungen. Das Kohleschiff kann heute nicht nur für Kohle, sondern für jegliches Schüttgut verwendet werden.
· Die Fabriken- und Lagerinfos zeigen an, welche Güter zu welcher Kategorie zählen und welche Fahrzeuge dafür geeignet sind. Ist keine Kategorie angegeben sondern ein Spezialfahrzeugtyp, wird ein Spezialfahrzeug benötigt.

simutrans-124.3/simutrans/text/de/depotlist.txt000066400000000000000000000007551474050137200217330ustar00rootroot00000000000000Depotliste

Depotliste

Die Depotliste zeight alle Garagen, Hangar, Werften, Bahnbetriebwerke und natürlich auch Depots, also jene Orte wo man Fahrzeuge kaufen oder neu zusammenstellen kann. Mit dem Tab kann man bestimmte Transportmittel auswählen. Wie bei allen Listen, springt ein Rechtsklick, Klick mit Control, oder ein Linksklick auf das Dreieck an die Stell der Karte mit dem Depot. Ein Linksklick auf eine Zeile öffnet dirkt das Depot.

simutrans-124.3/simutrans/text/de/display.txt000066400000000000000000000141221474050137200213620ustar00rootroot00000000000000Anzeigeeinstellungen

Anzeigeeinstellungen

Der Dialog Anzeige ist in die Reiter Oberfläche, Kartendarstellung, Bäume & Gebäude, Stationen und Verkehr unterteilt.

Oberfläche

· Auswahl Oberfläche öffnet ein Fenster wo Darstellung der Oberfläche geändert werden kann.
· Zeichensatzauswahl öffnet ein Fenster wo die Größe und die Art der Schrift geändert werden kann.
· Position Hauptmenü legt fest, wo sich das Hauptmenü (oben, links, rechts, unten) befindet.
· Vollbildmodus legt fest, ob Simutrans im Vollbild ausgeführt wird.
· rahmenloser Fenstermodus legt fest, das Simutrans als Fenster im Vollbild ohne Fensterelementen ausgeführt wird.
· Tool deaktivieren mit erneuter Auswahl legt fest, das ein erneuter Klick auf den Button das Tool wieder deaktiviert.

Auslastungsanzeigen
Im unteren Teil des Dialogs werden einige Information zur Auslastung des Computers angezeigt:
· Bildfrequenz: zeigt die tatsächliche Zeit zwischen zwei Frames.
· Leerlauf: Zeigt an, wie lange der Computer zwischen zwei Bildschirmupdates pausiert.
· Bildrate: Je höher der Wert, desto gleichmäßiger (ruckelfrei) bewegen sich die Fahrzeuge. Der Wert stellt die Bildfolgen pro Spielsekunde dar. Im Schnellen Vorlauf und im Netzwerkmodus ist die Bildrate fixiert, ansonsten wird sie nach Rechenlast angepasst. Den Wert kann man mit dem Kommandzeilenparameter -fps oder in der simuconf.tab einstellen.
· Simloops: Anzahl der Simulationsschleifen pro Spielsekunde. Wenn der Wert dauerhaft unter 5 fällt, ist der Computer voll ausgelastet. Einige Funktionen in Simutrans können aussetzen, zum Beispiel fahren Züge nicht mehr ab. In dem Fall sollte eine kleinere Karte mit weniger Städten gespielt werden.

Kartendarstellung

· Gitternetz einblenden: Blendet in der Welt ein Gitternetz ein und aus.
· Untergrundansicht: In diesem Modus kann man Tunnelstrecken bauen, sofern schon eine Strecke unter der Erde besteht. Die Tunnelstrecken aller Ebenen werden zusammen angezeigt.
· Ebene durch Karte: Auch in diesem Modus kann man Tunnelstrecken bauen. Die Karte wird auf der eingestellten Ebene aufgeschnitten und nur Tunnelstrecken auf der jeweiligen Ebene werden angezeigt. Mit den Pfeilen kann die Ebene eingestellt werden. Es kann aber auch direkt die Nummer der Ebene eingegeben werden.
· Tag und Nacht wechseln: Soll es nachts dunkel werden in Simutrans? Gebäudefenster, Fahrzeuge und Signalmittel zeigen sich in Nachtbeleuchtung.
· Helligkeit: Lege mit den Pfeilen die Helligkeit des Spiels fest. Nutze auch die Tasten ) (heller) und ( (dunkler). Werte über 0 lassen sich nur über die Tastatur einstellen. ACHTUNG: Die Einstellbarkeit ist nach oben und unten nicht begrenzt, es kommt aber sehr bald zu einer Falschfarbenanzeige.
· Inverses Kartenscrolling: Kehre die Scrollrichtung bei Bedarf um, die Karte bewegt sich dann in Mausrichtung.
· Zifferntasten bewegen immer die Karte
· Scrollgeschwindigkeit: Diese Einstellung erhöht die Kartenscrollgeschwindigkeit.
· Datums- und Uhrzeitformat ändert die Darstellung der Spielzeit unten links in der Statuszeile.

Bäume & Gebäude

· Transparent statt minimieren: Wählt den Modus aus, der benutzt werden soll, um Häuser oder Bäume zur besseren Übersicht zu verstecken. Diese Einstellung hat Auswirkungen auf die beiden nächsten Einstellungen.
· Bäume minimieren: Zeigt nur ganz kleine bzw. transparent Bäume an.
· Gebäudeanzeigemodus: Es kann mit Hilfe der Pfeile ausgewählt werden, ob keine Gebäude, nur Stadtgebäude oder alle Gebäude minimiert werden.
· Mauszeiger freihalten: Je nach Einstellung werden eine bestimmte Anzahl von Feldern um den Mauszeiger minimiert bzw. tranparent. Die Anzahl der Felder kann mit den Pfeilen oder direkt durch Eingabe eingestellt werden.
· Industriestatusanzeige: Blendet den Industrienamen sowie Wareneingang (blau) und Warenausgang (orange) auf der Hauptkarte ein.

Stationen

· transparente Stationsabdeckung: Wählt den Modus aus, der benutzt werden soll, um die Reichweite von Halten anzuzeigen. Ist transparent gewählt färbt sich der Boden entsprechend der ersten Spielerfarbe des Besitzers, während ausgeschaltet je Fliese nur ein Kästchen in Spielerfarbe zu sehen ist.
· Stationsabdeckung anzeigen: Zeigt die Stationsabdeckung an oder blendet sie aus.
· Markierungen auf der Hauptkarte: Legt den Modus fest, wie Markierungen bzw. Schilder im Spiel angezeigt werden. Diese können mit der ersten Spielerfarbe im Hintergrund, mit transparentem Grund und als Schriftfarbe die Spielerfarbe, in Standardschriftfarbe mit einem spielerfarbenen Feld davor oder überhaupt nicht angezeigt werden.
· Güterwarenbalken anzeigen: Blendet die Anzeige für wartende Waren an den Halten ein oder aus.

Verkehr

· Fußgänger (Stadt): Wenn aktiviert werden sich Fußgänger durch die Städte bewegen.
· Fußgänger (an Halten): Wenn aktiviert werden Fußgänger an Haltestellen aus Fahrzeugen aussteigen.
· Verkehrsdichte: Dieser Wert beeinflusst die Anzahl der privaten PKWs in den Städten.
· Fahrzeuge: Tooltipps: Je nach Modus werden Tooltipps verschieden angezeigt. Wenn Maustooltipps gewählt ist werden Tooltipps nur auf dem Feld angezeigt, wo sich die Maus befindet. Sind alle Tooltipps ausgewählt werden immer alle Tipps angezeigt. Fehlertooltipps werden nur bei Zwischenfällen angezeigt.
· Fahrzeugverfolgung im Tunnel
· Fahrplanhalte hervorheben: Ist diese Funktion aktiviert werden bei geöffneten Fahrplan alle Halte- und Wegpunkte angezeigt.
· Finanzbewegungen auf der Hauptkarte

simutrans-124.3/simutrans/text/de/edittools.txt000066400000000000000000000067271474050137200217370ustar00rootroot00000000000000Karteneditor

Karteneditor

Mit den Werkzeugen des Karteneditors kannst Du in den natürlichen Wachstumsprozess von Städten und Industrien eingegreifen. Das Menü lässt sich über einen Button im Menü Spezialwerkzeuge öffnen.

Eine zu leicht spielbar organisierte Welt wird Dir bereits mit wenig Spielerfahrung jeden Anreiz und jeden Spielspaß rauben. Setze die Werkzeuge gar nicht oder überlegt ein. Realisiere bauliche Situationen, wie sie bei der Autogenerierung praktisch nicht erreicht werden können. Ein dichtes und schwer handhabbares Industrierevier auf einer Insel, der Fremdenverkehrsort mit seiner Attraktion in der schwer zugänglichen Gebirgslage, der Erlebnispark in der Nähe einer kleinen Stadt, die Erdölförderung nur an ausgewählten Küstenstreifen oder die Landwirtschaft als Schwerpunkt in einer ländlichen Umgebung stellen nur einige Beispiele aus der reichen Möglichkeitenpalette dar.

· Stadtwachstum: Setze eines der beiden Werkzeuge in dem Gebiet der Stadt ein, deren Einwohnerzahl Du ändern möchtest. Nutzt Du das Werkzeug im Überschneidungsgebiet von Städten, wirkt sich die Aktion nur auf eine Stadt aus.
- Einwohnerzahl erhöhen: Das Wachstumswerkzeug stellt einen nach oben weisen Pfeil dar. Bei jeder Werkzeugnutzung wird die Stadt um 100 Einwohner wachsen. Es werden sofort Gebäude erneuert oder frisch gebaut, da mit der Aktion die Arbeits- und Obdachlosenzahlen steigen.
- Einwohnerzahl verringern: Das Wachstumswerkzeug stellt einen nach unten weisen Pfeil dar. Die Einwohnerzahl der Stadt wird bei jeder Werkzeugnutzung um 100 schrumpfen. Alle Gebäude bleiben erhalten. Die Werte für Arbeitslose und Obdachlose geraten in negative Bereiche. Die Stadt wird erst wieder bauliche Entwicklung zeigen, wenn durch Wachstum Bedarf an Baumaßnahmen entstanden ist.

· Gründe neue Stadt: Hast Du zu wenige Städte auf Deiner Karte, kannst Du mit diesem Werkzeug neue Städte gründen. Die Stadt entsteht dort, wo Dumit dem Werkzeug hinklickst. Aber Vorsicht, jede Stadtgründung kostet Dich eine Menge Geld.

· Stadtstraße bauen: Das Bauwerkzeug stellt eine Straße dar. Straßen, die Du mit dem Werkzeug baust, können von allen Spielern kostenlos genutzt werden.

· Industriedichte erhöhen: Es wird eine zufällige Industriekette gebaut.

· Industrieanlagen bauen: Öffnet den Dialog Industrieanlagen bauen.

· Industrieanlagen verbinden: Mit diesem Werkzeug können Industrien verbunden werden. Dies funktioniert nur dann, wenn eine Warenverbindung möglich ist.

· Sehenswürdigkeiten bauen: Öffnet den Dialog Sehenswürdigkeiten bauen.

· Stadtgebäude bauen: Öffnet den Dialog Stadtgebäude bauen.

· Pflanze Baum: Öffnet den Dialog Pflanze Baum.

· Wald aufforsten: Markiere eine Fläche, auf die kreisförmig ein Wald aufgeforstet wird.

· Jahr überspringen:Die Simutrans-Zeit wird um ein Jahr nach vorne gestellt. Neue Fahrzeuge werden verfügbar, wenn ihr Einführungsjahr erreicht wird.

· Spielerwechsel sperren: Klicke mit dem Werkzeug auf eine beliebigen Kartenposition. Dadurch ist der Wechsel zur öffentlichen Hand oder zu den Computerspielern nicht mehr möglich.

simutrans-124.3/simutrans/text/de/enlarge_map.txt000066400000000000000000000007001474050137200221640ustar00rootroot00000000000000Kartenfläche vergrößern

Kartenfläche vergrößern

In diesem Dialog kann die bestehende Spielkarte nach Rechts und Unten vergrößert werden. Möchte man nach links / oben erweitern, muss erst die Karte gedreht und dann mit diesem Dialog vergrößert werden. Nach dem Vergrößern kann man die Karte wieder zurück drehen.
In der rechten oberen Ecke wird eine Vorschau der vergrößerten Karte angezeigt.

simutrans-124.3/simutrans/text/de/factory_build.txt000066400000000000000000000047031474050137200225470ustar00rootroot00000000000000Industrieanlagen bauen

Industrieanlagen bauen

Der Dialog ist in vier Bereiche aufgeteilt.
· oben links befindet sich die Auswahlliste mit den Industrien
· unten links wird das Bild der ausgewählten Industrie angezeigt
· oben rechts befinden sich einige Optionen
· unten rechts werden die Informationen der ausgewählten Industrie angezeigt

Auswahlliste

In der Auswahlliste werden alle zur Verfügung stehenden Industrien angezeigt. Oben befinden sich zwei Reiter, die die Anzeige umschalten.
· Übersetzung: Zeigt die Namen so an, wie diese im Spiel verwendet werden. Dies ist abhängig von der eingestellten Sprache. Wenn keine Übersetzung für die eingestellte Sprache vorhanden ist, wird der Objektname angezeigt.
· Objekt: Zeigt die internen Objektnamen an.

Die Schriftfarben haben folgende Bedeutung:
· grüne Schrift kennzeichnet Industrien, die Waren nur erzeugen
· schwarze Schrift kennzeichnet Industrien, die Waren benötigen und daraus neue Waren produzieren
· blaue Schrift kennzeichnet Industrien, die Waren nur benötigen

Optionen

· alle Klimazonen: Diese Option deaktiviert die Klimazonenzuordnung beim Bau der Industrie.
· Mit Epoche ab Jahr: Es werden nur die Industrien in der Auswahlliste angezeigt, die im aktuellem Spieljahr zur Verfügung stehen.
· Auch veraltete zeigen: Es werden auch die Industrien in der Auswahlliste angezeigt, die in früheren Spieljahren mal zur Verfügung standen.
· Stadtgewerbekette bauen: Es werden nur die Industrien in der Auswahlliste angezeigt, deren Standort sich in Städten befindet. Außerdem wird, so möglich, eine ganze Kette, d.h. alle davon abhängigen Farbiken erstellt.
· Fabrikkette auf dem Land: Es werden nur die Industrien in der Auswahlliste angezeigt, deren Standort sich außerhalb von Städten befindet. Außerdem wird, so möglich, eine ganze Kette, d.h. alle davon abhängigen Farbiken erstellt.

· Rotation: Sofern die ausgewählte Industrie mehrere Ansichten hat, kann hier eine bestimmte Ansicht ausgewählt werden. Die Grafik unten links wird entsprechen gewechselt. Bei der Auswahl von Zufällig, wird beim Bau der Industrie irgendeine Ansicht gewählt.
· Produktion: Hier kann die vordefinierte Produktionsrate der ausgewählten Industrie geändert werden.

simutrans-124.3/simutrans/text/de/factorylist_filter.txt000066400000000000000000000023051474050137200236250ustar00rootroot00000000000000Fabrikliste

Fabrikliste

Die Fabrikliste wird über die Listenverwaltung geöffnet.
In der Fabrikliste sind alle Fabriken der Welt gelistet. Die Sortierung ist nach allen aufgeführten Kriterien möglich; klicke zum Wechseln auf den Button. Ein Klick auf einen Eintrag öffnet das Infofenster zur Fabrik und zentriert die Karte auf diese.

· Status: Zeigt den Status der Fabrik an.
Die Farben bedeuten:
- Weiss: Industrie produziert nicht
- Gelb: Industrie ist nicht angeschlossen
- Grün: Industrie hat Optimum
- Orange: Industrie funktioniert, aber Verbesserungen sind möglich
- Rot: Industrie muß überprüft werden

· Strom: Zeigt an, ob die Fabrik ans Stromnetz angeschlossen ist. Dies wird durch einen roten Blitz dargestellt.

· Fabrikname: Die Bezeichnung für die Fabrik.

· Eingang: Die Summe aller im Rohstofflager der Fabrik wartenden Güter.

· Ausgang: Die Summe aller im Fertigwarenlager transportbereiter Güter.

· Produktion: Die Produktionsrate der Fabrik.

simutrans-124.3/simutrans/text/de/finances.txt000066400000000000000000000077231474050137200215140ustar00rootroot00000000000000Finanzen

Finanzen

Die Finanzen können im Finanzfenster betrachtet werden. Dieses kann durch Drücken von f oder über die Hauptmenüleiste geöffnet werden.
Dort sind die Informationen über die Finanzen zusammengefasst.

Im unteren Teil des Fensters ist eine Grafik, die den Verlauf eines oder mehrer Werte anzeigt. Welche diese anzeigen soll, kannst Du mit den farbigen Schaltflächen darüber auswählen. Du kannst die Ansicht zwischen Jahren und Monaten umschalten.

Mit der Schaltfläche Firmensitzbau kann ein Firmensitz gebaut werden. Gibt es bereits einen Firmensitzes, heißt die Schaltfläche Firmensitzumbau. Unterhalb der Schaltfläche wird ein Kartenausschnitt mit dem Standort des Firmensitzes angezeigt.
Der Firmensitzbau/-umbau steht nur zur Verfügung, wenn das verwendete Pakset Firmensitzgebäude enthält.

Die Positionen und Schaltflächen der linken Hälfte sind wie folgt:

Einnahmen - Die gesamten Einnahmen aus dem Transport von Passagieren und Gütern.
Betriebskosten - Die Kosten für den Betrieb aller Fahrzeuge. Die Betriebskosten pro gefahrenem Kilometer je Fahrzeugtyp können im Depot eingesehen werden, für Fahrzeugverbände im Fahrzeugfenster.
Instandhaltung - Die angefallenen Kosten für die Instandhaltung der Infrastruktur. Die Kosten der Instandhaltung pro Monat werden rechts angezeigt und jeweils am letzten des Monats fällig, also dann immer soviel auf dem Konto vorrätig haben!
Maut - Wenn Fahrzeuge auf fremden Wegen (zum Beispiel Straßen anderer Spieler) unterwegs sind, kann ein Maut (Wegzoll) anfallen. Dies hängt vom Pakset ab. Je nachdem, ob andere Spieler deine Wege benutzen oder umgekehrt, kann man so Geld verdienen oder muss bezahlen.
Freileitungen - Der Gewinn durch den Verkauf von Strom.
Betriebsgewinn - Der operative Gewinn (exkl. Abschreibungen auf Fahrzeuge), also was mit der Transporttätigkeit, Maut, Freileitung an sich verdient wird minus der Betriebskosten und Instandhaltung. Summe aller obigen Positionen.

Neue Fahrzeuge - Alle Ausgaben (Einnahmen) für den Kauf (Verkauf) von Fahrzeugen.
Ausgaben Bau - Hier steht der Betrag, der für den Bau von Schienen, Strassen, Signalen usw. ausgegeben wurde. Auch Abrisskosten zählen zu den Baukosten.
Bruttogewinn - Die Summe aller Einnahmen (Geldzuflüsse) und Ausgaben (Geldabflüsse), der sogenannte Cash-Flow. Summe aller obigen Positionen.

Beförderungen - Die Summe aller Einheiten, die transportiert worden sind.

Die Positionen und Schaltflächen der rechten Hälfte sind wie folgt:

Kontostand - Der aktuelle Kontostand. Dieses Geld steht zur Verfügung, um zu bauen oder Fahrzeuge und Züge zu kaufen. Der Kontostand steht auch in der Statusleiste unten in der Mitte. Ist der Kontostand negativ erscheint monatlich eine Warnung.
Fahrzeugwert - Der Wert Deiner Fahrzeugflotte per Ende des letzten Monats.
Marge - Die erzielte Nettomarge (Betriebsgewinn/Kosten). Je höher diese ist, desto mehr wird aus den angefallenen Kosten herausgeholt. Die Werte werden laufend aktualisiert, sind aber unter dem Monat wegen fehlender Unterhaltskosten zu hoch. Aussagekräftiger sind Zahlen des Vormonats oder Vorjahres. Achtung: Es kann durchaus sinnvoll sein, Linien mit geringer Marge zu betreiben, z.B. um eine Industrie zu versorgen.
Gesamtvermögen - Die Summe von Kontostand und Fahrzeugwert, also der Firmenwert. Ist das Gesamtvermögen am Ende eines Monats negativ, ist die Firma pleite und das Spiel verloren. Sinkt das Gesamtvermögen unter 10% des Startkapitals, erscheint am Monatsersten eine Warnung.

Mission-Spiele

Bei Mission-Spielen wird zusätzlich der Mission-Auftrag und der erreichte Mission-Status (in %) angezeigt.

simutrans-124.3/simutrans/text/de/general.txt000066400000000000000000000056231474050137200213400ustar00rootroot00000000000000Simutrans

Simutrans Hilfe

Hilfe zum Spiel
·Simutrans
·Nutzung der Hilfe
·Spielsteuerung
··Untergrund
·Tastaturbelegung
·Hauptmenü
·Neue Welt

Hauptmenü (siehe auch Hauptmenü)
·Reliefkarte
·Optionen (s.u.)
· Abfragewerkzeug
·Geländewerkzeuge
·Eisenbahnbauwerkzeuge
·Monorailbauwerkzeuge
·Trambauwerkzeuge
·Straßenbauwerkzeug
·Häfen und Werft
·Flughafenbauwerkzeuge
·Spezialbauwerkzeuge
· Löschwerkzeug

·Linienverwaltung
·Listenverwaltung
· ·Haltestellenliste mit Filtereinstellungen
· · öffnet Haltestellenfenster und Haltestellen Detailinformation
· ·Fahrzeugliste mit Filtereinstellungen zur Fahrzeugliste
· · öffnet Fahrzeugfenster und Fahrzeugdetailfenster
· ·Stadtliste
· · öffnet Stadtinformation
· ·Warenliste
· · öffnet Fabrikfenster
· ·Fabrikliste
· ·Touristenzielliste
·Mailbox und Mailbox Optionen
·Finanzen

· Bildschirm speichern
· Pause
· Simulation maximal beschleunigen (kann zu ruckeln führen)!

Dialoge unter Optionen
·Einstellungen
·Sprachauswahl
·Farbauswahl
·Anzeigeeinstellungen
·Sound- & Musikeinstellungen
·Spieler Menü
·Lade Menü
·Speichern Menü
·Neue Welt und Lade Relief Menü

Weitere Dialoge
·Karteneditor
·Depotfenster
·Fahr- und Linienplanfenster

simutrans-124.3/simutrans/text/de/goods_filter.txt000066400000000000000000000034411474050137200223770ustar00rootroot00000000000000Warenliste

Warenliste

Die Warenliste wird mit Shift+G oder über die Listenverwaltung aufgerufen.
In der Warenliste sind Passagiere sowie alle Güter, die Dir im gespielten Grafikset ( pak ) zum Transport anvertraut werden können, gelistet. Dabei können momentan nicht vorhandene Güter ausgeblendet werden.

· Fracht: Passagiere und alle Güterarten in Simutrans werden nach einer internen Sortierung gelistet. Vor jeder Frachtart befindet sich ein Farbquadrat. Die gleichen Farben findest Du auch an den Säulen über den Haltestellennamen wieder. Sie zeigen dort an, wieviel Einheiten je Güterart an den Haltestellen gelagert sind. Die Anzeige läßt sich über die Taste ! ein- und ausblenden.

· Preis: Der Transporterlös pro Einheit eines Gutes für ein zurückgelegtes Feld.

· Bonus: Werden Güter, und vor allem Passagiere und Post auf einem Verkehrsträger schneller als oben angezeigt befördert, wird auf den Grundumsatz pro weitere 10 km/h der Bonus aufgerechnet; ist das Fahrzeug langsamer, kann der Umsatz auch sinken. Die Berechnungsformel ist komplex. Maßgebend für die Höhe des Bonus ist die zulässige Höchstgeschwindigkeit des Konvois. Die Höchstgeschwindigkeit der befahrenen Strecke und die tatsächliche Beförderungszeit finden keine Berücksichtigung.

· Kategorie: Jede Frachtart ist einer Güterkategorie zugeordnet. Für jede Güterkategorie ist ein bestimmter Fahrzeugtyp vorgesehen. Alle Sonderfrachten können nur mit spezifischen Fahrzeugen transportiert werden. Im Depotfenster kannst Du die Güterarten unter "Zuladung" einsehen.

· Gewicht: Das Gewicht einer Einheit eines Gutes in kg.

simutrans-124.3/simutrans/text/de/haltlist.txt000066400000000000000000000061211474050137200215410ustar00rootroot00000000000000Haltestellenliste

Haltestellenliste

Die Haltestellenliste beinhaltet alle Haltestellen, also Bahnhöfe, Frachthöfe, Bus- und Tramhaltestellen, Anlegestellen sowie Flughäfen des aktiven Spielers. In die Liste ist eine Sortierfunktion eingebaut. Über einen Filter kannst Du Haltestellen nach definierten Kriterien anzeigen lassen.
Der Filter kann entweder "an" oder "aus" sein. Wenn Du eine Haltestelle nicht findest, prüfe, ob der Filter "aus" ist. Die Voreinstellung ist "an". Über einstellen können die Filterkriterien ausgewählt werden.

Sortieren nach: Der Schalter verfügt über 4 Stellungen, welche Du nacheinander wählen kannst.
· Bezeichnung: Die Liste wird in der Namensreihenfolge alphanumerisch sortiert.
· Wartend: Die Haltestellen werden nach der Anzahl wartender Personen und Güter sortiert. Dabei werden die Werte aller wartenden Einheiten addiert.
· Typ: Die Sortierung der Liste erfolgt nach Fahrzeugtypen in folgender Reihenfolge: Lastwagen, Schienenfahrzeuge, Schiffe, Busse und Flugzeuge. Bohrinseln haben keinen Typ.
· Nr.: Die Liste wird nach den Ordnungszahlen der Haltestellen sortiert.
· aufsteigend/absteigend: Die Liste wird bei jeder Schalterbedienung in umgedrehter Reihenfolge dargestellt.

Listeneinträge
· Ordnungszahl: Vom Spiel werden für alle Haltestellen Ordnungszahlen vergebenen.
· Name der Haltestelle: Die Namen entsprechen jenen, welche über den Haltestellen angezeigt werden. Mit einem klick auf den Haltestellennamen öffnet sich das Haltestellenfenster und die Hauptkarte zentriert auf die Haltestelle. Im Haltestellenfenster kannst Du den Namen der Haltestelle ändern.
· Angenommene Kategorien: Unter der Ordnungsnummer können drei Symbole für Passagiere, Post und Güter erscheinen. Fehlen Symbole, so werden die entsprechenden Kategorien nicht angenommen. Dies kann durch Erweiterung der Haltestelle mit zusätzlichen Haltestellengrafiken oder Nebengebäuden geändert werden.
· Wartende Güter und Passagiere: Personen und jede Güterart sind in einer Zeile gelistet.
· Statusanzeige der Haltestelle:
- Grün: Bei der Haltestelle ist alles in Ordnung.
- Gelb: Die Haltestelle ist nicht erschlossen (kein Fahrzeug kam vorbei, nichts warted).
- Orange: Die Haltestelle ist mäßig überfüllt mit Umsteigepassagieren/Waren.
- Rot: Die Haltestelle ist völlig überfüllt (mehr als 1,5fache Kapaziät) bzw. mehr als 200 Personen/Briefe haben ihre Reise wegen Überfüllung nicht angetreten oder eine Fabrik konnte ihre Waren nicht loswerden und musste deswegen die Produktion einstellen.

· Symbol des Haltestellelentyps: Die Symbole ermöglichen Dir eine schnelle Orientierung über die Fahrzeugtypen der Haltestellen. Die Symbole sind Bus, Lastwagen, Lok, Schiff, Flugzeug, Magnetbahn. Liegt eine Tram-Haltestelle auf einer Straße, ist deren Symbol eine Straßenbahn, ansonsten ist es eine Lok.

simutrans-124.3/simutrans/text/de/haltlist_filter.txt000066400000000000000000000036271474050137200231160ustar00rootroot00000000000000Haltestellenlistenfilter

Filtereinstellungen zur Haltestellenliste

Im Fenster für die Einstellungen zur Haltestellenliste können die Filteroptionen für die Anzeige der Haltestellen gesetzt werden. Ein eingedrückter Knopf bedeutet, das Kriterium muss erfüllt sein, um durch den Filter zur Anzeige zu gelangen. Dabei werden die Eigenschaften innerhalb eines Hauptmenüs mit logisch "OR" (eines der angewählten Kriterien muss erfüllt sein) und zwischen den Hauptmenüs mit logisch "AND" (alle angewählten Kriterien müssen erfüllt sein) verknüpft.

Namen filtern: Du kannst im Textfeld einen Name angeben. Es werden nur diejenigen Stationen in die gefilterte Liste aufgenommen, deren Namen dem Eintrag genau entsprechen. Achtung Platzhalterfunktionen wie * oder ? werden nicht unterstützt.

Typen filtern: Es gelangen nur Haltestellen in die gefilterten Liste, welche mindestens ein Element des selektierten Typs enthalten. Haltestellen von Industrien im Wasser sind keinem Typ zugeordnet. Sie werden durch den Filter nicht erfasst, werden also auch nicht unter Anlegestelle angezeigt.

Spezialfilter:
· überfüllt: Die Funktion ist derzeit außer Betrieb.
· keine Verbindung: Unter die Kategorie fallen Haltestellen, die an keine Linie angeschlossen sind.

Güterarten:
· Nimmt an: Alle Haltestellen werden gelistet, welche die selektierten Güterarten annehmen können.
· Gibt ab: Alle Haltestellen werden gelistet, von welchen aus die selektierten Güterarten abfahren können.
Umladehaltestellen werden in beiden Spalten nicht berücksichtigt!

Auswahlschalter:
· alle: Alle Güterarten werden ausgewählt.
· keine: Alle Güterarten werden abgewählt.
· inv.: Bei Betätigung wird die Güterauswahl umgekehrt.

simutrans-124.3/simutrans/text/de/industry_info.txt000066400000000000000000000051721474050137200226160ustar00rootroot00000000000000Fabrikdetails

Fabrikfenster

Das Fabrikfenster erscheint, sobald auf eine Fabrik geklickt wird. Es enthält verschiedene Informationen über diese Farbik.

Fabriken können Verbraucher, Produzenten oder verarbeitende Industrie sein. Reine Verbraucher sind zum Beispiel Kraftwerke oder ein Supermarkt, reine Produzenten eine Kohlegrube oder eine Müllhalde; ein Stahlwerk oder eine Raffinerie sind verarbeitende Fabriken.

Unter dem Namensfeld findet sich die akteulle Produktion pro Monat (für 100%). Sind danben Symbole für Passagiere/post/Strom, dann kann die Produktion auch durch Transport von Arbeitern, Post bzw. Elektrizitätsversorgung erhöht werden. (Ist dies momentan der Fall, erschient das jeweilige Symbol auch im Bild der Fabrik rechts daneben.)
Unter dem Bild zeigt ein Balken den Status der Fabrik an. Die Farben bedeuten:
- Weiss: Industrie produziert nicht
- Gelb: Industrie ist nicht angeschlossen
- Grün: Industrie hat Optimum
- Orange: Industrie funktioniert, aber Verbesserungen sind möglich
- Rot: Industrie muß überprüft werden

Bei Produzenten listet Produktiondie Warenmengen auf, die auf Lager ist / und die maximale Lagermenge je Ware.
Bei Verbrauchern werden unter Verbrauch die Vorräte, / die unterwegsbefindlichen Waren / und die maximale Lagerkapazität je Ware angezeigt.
Stauen sich produzierte Waren, dann sind alle Abnehmer überfüllt oder es gibt keine Verbindung. Ist das Lager für ankommende Waren überfüllt, dann fordert die Fabrik auch keine neuen Waren mehr an. (Diese Verhalten kann mit dem Eintrag "just_in_time" in der simuconf.tab angepasst werden.)

Da in Simutrans eine Fabrik feste Verträge mit anderen Fabriken hat, sind in dem Dialog als nächstes die Verbraucher aufgelistet. Nur diese nehmen Waren dieser Fabrik an. Ein Klick auf das Dreieck springt zu der jeweiligen Fabrik. Bei reinen Verbrauchern fehlt dieses Feld.

Als nächstes kommen die Lieferanten, die diese Fabrik mit Rohstoffen versorgen. Nur von diesen werden Waren angenommen. Auch hier kann man mit dem Dreieck wieder zu der jeweiligen Fabrik springen.

Darunter findet man die Städte, aus denen die Arbeiter für diese Fabrik kommen mit dem Passagier- und Postaufkommen der Fabrik. Ist die Liste leer, dann sind die Städte zu weit entfernt.

Als letztes findet man noch eine Liste der Stationen, die mit dieser Fabrik verbunden sind.

Rechts unter dem Bild der Fabrik findet man eine Knopf um eine detaillierte Statistik zu der Fabrik zu sehen.

simutrans-124.3/simutrans/text/de/labellist_filter.txt000066400000000000000000000010141474050137200232310ustar00rootroot00000000000000Markerliste

Markerliste

In der Markerliste werden alle gesetzten Marker der Karte angezeigt.
Mit der Option nur eigene Marker wird die angezeigte Liste auf die eigenen Marker eingeschränkt.

Es stehen 2 Schaltflächen zum sortieren der Liste zur Verfügung. Die linke Schaltfläche sortiert nach: · Bezeichnung · nach Orten · Spieler Die rechte Schaltfläche sortiert jeweils nach aufsteigend und absteigend.

simutrans-124.3/simutrans/text/de/language.txt000066400000000000000000000011411474050137200214750ustar00rootroot00000000000000Sprachauswahl

Sprachauswahl

Über die Sprachauswahl kannst Du die Sprache einstellen, in der Simutrans angezeigt wird. Wenn die Sprache vor dem Erzeugen einer neuen Karte ausgewählt wird, werden auch die Ortsnamen in der entsprechenden Sprache erstellt.

Die Sprache kann jederzeit geändert werden. Geöffnete Dialoge behalten teilweise die alte Sprache bei und werden erst nach erneutem Öffnen in der neuen Sprache angezeigt.

Du kannst helfen, Simutrans in andere Sprachen zu übersetzen.
Gehe dafür auf https://translator.simutrans.com

simutrans-124.3/simutrans/text/de/linedetails.txt000066400000000000000000000052321474050137200222140ustar00rootroot00000000000000Linienfenster

Linienfenster

· Liniennamen ändern: Der Name der Linie wird angezeigt. Klicke zum Editieren des Namens ins Namensfeld und bestätige die Änderung mit RETURN.

Linienstatistik: Die wichtigsten statistischen Daten der Linie werden unterhalb des Linien-Namens angezeigt.
· Fahrzeuge: Anzahl der Fahrzeugverbände der Linie.
· Auslastungsbalken: Im Balken wird die prozentuale Auslastung der Linie grafisch dargestellt.
· Profit: Der Profit der Linie im aktuellen Monat.
· Kapazität: Die genutzte Ladekapazität der Linie, in Klammern die prozentuale Auslastung.

Darunter sind vier Reiter mit weiteren Einstellungen.

Fahrplan ändert den Fahrplan für alle Fahrzeugverbände, die zur Linie gehören. Die Änderung wird bei Schießen des Fensters oder bei Anwählen eines anderen Reiters übernommen.

Statistik: zeigt die monatsweise Statistiken der Linie der letzten 12 Monate as Kurven. Der aktuelle Monat steht links. Die Farben der Kurven entsprechen den Farben der Schalter.
· Freie Kapazität: Der nicht genutzte Laderaum aller Fahrzeugverbände der Linie, summiert für jeden Fahrplanabschnitt.
· Beförderungen: Der genutzte Laderaum alle Fahrzeugverbände der Linie, summiert für jeden Fahrplanabschnitt.
· Einnahmen: Die Erlöse aller Fahrzeugverbände dieser Linie.
· Betriebskosten: Die anfallenden Kosten für den Betrieb aller Fahrzeugverbände der Linie.
· Profit: Der Profit ergibt sich aus Einnahmen minus Betriebskosten.
· Fahrzeuge: Die Anzahl der Fahrzeugverbände, welche die Linie befahren.
· Strecke/Monat: Die zurückgelegt Strecke aller Fahrzeuge der Linie.
· Geschwindigkeit:
· Maut: Kosten die durch Nutzung von Verkehrswegen anderer Spieler angefallen sind.

Halltestellenliste: Alle angefahrenen Haltestellen der Linie sind hier aufgeführt. Jeweils nur einmal, auch wenn sie im Fahrplan mehrmals angefahren werden. Freie Wegpunkte werden nicht angezeigt. Die ANzeige is wie in der Haltestellenliste.

Fahrzeugliste: All hier aufgeführte Fahrzeuge gehören zu dieser Linie. Fehlt ein dort vermuteter Fahrzeugverband, ist es möglich, dass sein Fahrplan geändert worden ist und er dadurch aus der Linienzugehörigkeit gefallen ist. Die Liste verhält sich wie die Fahrzeugliste. Zum Auswählen eines Fahrzeugverbandes auf diesen klicken.

simutrans-124.3/simutrans/text/de/linemanagement.txt000066400000000000000000000060611474050137200227040ustar00rootroot00000000000000Linienverwaltung

Linienverwaltung

Die Linienverwaltung wird über die Hauptmenüleiste oder mit der Taste w aufgerufen. Je nach verwendeten Grafikset kann sich der Button auch in anderen Menüs befinden und die Tastenkombination kann anders sein.
In der Linienverwaltung werden alle eingerichteten Linien des aktiven Spielers aufgelistet.

Im oberen Teil befinden sich Filterelemente.
Ganz oben befindet sich ein Eingabefeld um Linien mit Namen bzw. Namensteilen zu filtern. Darunter befindet sich ein Auswahlfeld um die Linien nach Waren zu filtern.
Darunter befindet sich eine Sortierung. Die Liste kann mit den Entsprechenden Einträgen sortiert werden. Der Button hinter dem Auswahlfeld legt die Richtung (aufsteigend/absteigend) der Sortierung fest.

Darunter können Linienaktionen ausgeführt werden:
· Neue Linie: Ein neues Linienfenster öffnet sich. Der Button ist nur aktiv, wenn die Linienauswahl (Reiter über der Liste) nicht auf alle steht.
· Linie löschen: Die markierte Linie wird ohne Rückfrage gelöscht. Der Button ist nur aktiv, wenn der Linie keine Fahrzeugverbände zugewiesen sind (weißer Linienname).

Die Option einzelne Linienfenster rechts daneben bewirkt, das beim anklicken einer anderen Linie das gerade aktive Linienfenster geschlossen wird. Ist die Option nicht aktiv, werden die Linienfenster gleichzeitig geöffnet. Geöffnete Linienfenster sind in der Liste markiert.

Auflistung im unteren Teil: Hier sind die Linien mit ihren Bezeichnungen alphanumerisch gelistet. Wird eine Linie angeklickt, dann öffnet sich das Linienfenster der Linie. Erneutes anklicken schließt das Fenster wieder.
Über die Reiter lässt sich die Liste filtern:
· Alle: Alle Linien werden angezeigt.
· Zug: Alle Zug-Linien (Bahn, Trams und Magnetbahnen) werden angezeigt.
· Monorail: Alle Magnetbahnen-Linien werden angezeigt.
· Tram: Alle Straßenbahn-Linien werden angezeigt.
· Straße: Alle LKW-Linien (Busse, Posttransporter, LKW) werden angezeigt.
· Schiff: Alle Schiffslinien werden angezeigt.
· Flug: Alle Fluglinien werden angezeigt.
Je nach verwendetem Grafikset kann die Anzahl und die Bezeichnung abweichen.

Die Farbe des Liniennamen hat folgende Bedeutung:
· scharz Alles ok.
· weiß: Dieser Linie sind keine Fahrzeugverbände zugeordnet.
· gelb: Auf dieser Linie hat sich kein Fahrzeugverband bewegt (Betriebskosten gleich 0).
· rot: Der Profit dieser Linie ist negativ.
· blau: Mindestens ein Fahrzeugverband auf dieser Linie ist veraltet. Wird von Rot überlagert.
· orange: Mindestens ein Fahrzeugverband auf dieser Linie steht im Stau.

Verweilt der Mauszeiger länger über einem Liniennamen, werden einige Daten der Linie eingeblendet.

simutrans-124.3/simutrans/text/de/list.txt000066400000000000000000000015361474050137200206750ustar00rootroot00000000000000Listenverwaltung

Listenverwaltung

Die Listenverwaltung wird über die Hauptmenüleiste aufgerufen.
Im Listenverwaltungsmenü gibt es mehrere Einträge. Je nach Grafikset können Einträge fehlen.

Linienverwaltung
Fahrzeugliste Spieler
Haltestellenliste
Depotliste
vorhandene Fahrzeuge Spiel
Stadtliste
Warenliste
Fabrikliste
Touristenzielliste
Markerliste
Spielerliste

simutrans-124.3/simutrans/text/de/load.txt000066400000000000000000000033361474050137200206410ustar00rootroot00000000000000Lademenü

Spielauswahldialog (Ladedialog)

Der Ladendialog öffnet ein gespeichertes Spiel zum Weiterspielen.
Achtung: Das aktuelle Spiel (welches gerade im Hintergrund läuft) wird beim Laden eines anderen Spiels ohne Rückfrage beendet.

Eingabefeld Dateiname: Durch Eingabe eines Dateinames kann der Spielstand geladen werden. Es muss die Entertaste oder der OK Button gedrückt werden.

X - Löschen: Achtung: Das X vor jedem Namen löscht den entsprechenden Spielstand. Es wird nicht nachgefragt sondern sofort gelöscht. Das X wird nur angezeigt, wenn in der simuconf.tab der Parameter show_delete_buttons = 1 gesetzt ist.

Schaltfläche mit Namen: Durch einen Klick auf einen Button wird der entsprechende Spielstand geladen. Der Spielstand muss mit dem gestartetem pak (Grafikset) und der Simutrans-Version kompatibel sein.

Information des paks (Grafiksets): Gibt an mit welchem pak (Grafikset) der Spielstand gespeichert wurde.

Datum und Uhrzeit: Gibt an zu welchem Datum und welcher Uhrzeit der Spielstand gespeichert wurde.

Dieses Spiel als Server starten. Wird diese Option gesetzt, dann startet das ausgewählte Spiel als Serverspiel und kann über das Netzwerk/Internet erreicht werden.

OK Läd das Spiel was im Feld Dateiname angegeben wird.

Abrechen Schließt den Dialog ohne ein Spiel zu laden.

Autosave
Spielstände, die durch die autosave-Option gespeichert wurden, tragen den Namen 'autosave' mit 2 angehängten Ziffern. Die Ziffern geben den gespeicherten Monat an.

simutrans-124.3/simutrans/text/de/load_relief.txt000066400000000000000000000011221474050137200221560ustar00rootroot00000000000000Höhenkarte-Lademenü

Höhenkarte-Lademenü

Im Höhenkarte-Lademenü werden alle Relief-Karten gelistet, welche sich im Verzeichnis simutrans/maps bzw. Benutzerverzeichnis/simutrans/maps befinden. Es handelt sich um Graustufenbilder, die Du in verschiedenen Grafik- und Bildbetrachtungsprogrammen aus farbigen Bitmapdateien oder aus Graustufenbitmaps erstellen kannst. Sie werden im Format .ppm gespeichert.

Weitere Details zur Nutzung von Lade-Menüs findest Du in der Hilfe zum Lademenü.

simutrans-124.3/simutrans/text/de/mailbox.txt000066400000000000000000000033161474050137200213530ustar00rootroot00000000000000Mailbox und Mailbox Optionen

Mailbox und Mailbox Optionen

In der Mailbox sammeln sich alle Meldungen, die seit dem Spielstart bzw. dem letzten Laden eines Spielstandes angefallen sind.
Bei einigen Meldungen kannst Du den Bildschirm auf den Ort zentrieren, welcher die Meldung ausgelöst hat. Klicke dazu die Meldung an.

Optionen: Über den Optionen-Schalter gelangst Du zum Dialog mit den Mailboxeinstellungen. Dort kannst Du für jede Mitteilung einstellen, ob und wie sie angezeigt werden soll. Anzeigekombinationen sind möglich.

Mitteilungen:
· Neues Jahr: Ein neues Jahr hat begonnen.
· KI baut: Ein Computergegner hat eine neue Linie in Betrieb genommen.
· Stadtnachrichten: Die Stadt baut ein größeres Rathaus.
· Keine Route: Das in der Meldung angegebene Fahrzeug findet keinen Weg mehr.
· Neue Industrie: Durch das Stadtwachstum wurde eine neue Industriekette mit Stadtgeschäft gebaut.
· Neue Attraktion: Ein neues Touristenziel oder Denkmal wurde errichtet.
· Neue Fahrzeuge: Ein neues Fahrzeug ist verfügbar, oder ein Fahrzeug ist veraltet.
· Bahnhof voll: Die angegebene Haltestelle ist überfüllt.
· Warnungen: Du hast 3 Monate Zeit, deine Schulden zurückzuzahlen, etc.

Bedeutungen der Schalter:
· linke Spalte: Die Meldung wird im Ticker (Lauftext über der Statusleiste) ausgegeben.
· mittlere Spalte: Ein Dialog erscheint für kurze Zeit und beendet sich dann selbst.
· rechte Spalte: Ein Dialog informiert Dich. Er wird solange angezeigt, bis Du ihn schließt.

simutrans-124.3/simutrans/text/de/mainmenu.txt000066400000000000000000000150011474050137200215230ustar00rootroot00000000000000Hauptmenü

Hauptmenü, die Buttonleiste

Einstellungen: Über die Diskette gelangst Du zu den Einstellungen sowie zum Laden und Speichern. Du kannst auch eine neue Karte generieren lassen bzw. das Spiel beenden.

Reliefkarte: Die Übersichtskarte über die Welt mit ihren Objekten zeigt die Bewegungen der Spielerfahrzeuge an und gestattet Dir einige statistische Ansichten. Wenn Du einen Punkt auf der Reliefkarte anwählst, springt die Spielkarte zum entsprechenden Bildausschnitt.

Lupe: Die Lupe symbolisiert das Abfragewerkzeug. Ist es aktiv, wird der Cursor ebenfalls zur Lupe. Wählst Du mit ihr ein Objekt an (Gebäude, Fahrzeug), werden Angaben (Infofenster) darüber eingeblendet. Empfehlenswert ist es, immer wieder zu der Abfrage zurückzuwechseln, vor allem, wenn Du gerade mit dem Abrisswerkzeug gearbeitet hast. So vermeidest Du, ein Objekt aus Versehen abzureissen, anstatt die Objektinformationen aufzurufen.

Geländewerkzeuge: Die Rampe öffnet ein Menü, mit welchem Du die Höhen- und Hanglagen in der Karte verändern kannst. Gelände anheben/absenken sind links auch im Hauptmenü verfügbar.

Bauwerkzeugmenüs: Hinter den Werkzeugen verbergen sich die jeweiligen Baumenüs.
· Eisenbahnen
· Magnetbahnen/Monorails
· Straßenbahnen
· Straßen
· Häfen und Werften
· Flughäfen

An Fahrzeuge gelangen: Jedes der Baumenüs enthält ein Depotwerkzeug (s. Hilfen zu den Baumenüs). Nach dem Bau eines Depots wird bei dessen Anwahl das Depotfenster geöffnet.

Spezialbauwerkzeuge: Das sich öffnende Menü enthält verschiedene Bauwerkzeuge, die den Aufbau der Transportnetze ergänzen.

Abrisswerkzeug: Nach der Auswahl des Werkzeuges wird der Cursor zur durchkreuzten Wolke. Ein mit dem Werkzeug angewähltes Objekt wird ohne weitere Warnung von der Karte entfernt, sofern Du zu dessen Abriss berechtigt bist. Bei Abrissarbeiten entstehen unterschiedliche Kosten, die sofort von Deinem Kassenbestand abgebucht werden.
· Eigene Bauwerke sowie Stadtstraßen und private Gebäude wie Wohn- , Büro- und Gewerbeliegenschaften (oranger Fensterbalken im Infofenster) können abgerissen werden. Beachte, dass beim Gebäudeabriss auch die Gebäudekosten als Unkosten anfallen.
· Spezielle Gebäude wie Rathäuser oder Sehenswürdigkeiten sowie Einrichtungen anderer Spieler können nur durch den jeweiligen Eigentümer abgerissen werden (Vorsicht bei erschlossenen Industrien und Rathäusern).
· Auf Schienen und Straßen sind bestimmte Abrissreihenfolgen festgelegt. Sofern auf der Abrisskachel vorhanden, werden zuerst Signale, danach Haltestellen, schliesslich eine ggf. vorhandene Fahrleitung, und zuletzt der Betriebsweg selbst abgerissen.
· Sollen Abrissarbeiten auf Brücken oder Schwebebahnen durchgeführt werden, muss beim Abreissen die Ctrl(Strg)-Taste gedrückt gehalten werden. Sonst werden die Objekte auf der unteren Ebene, z.B. ein Haus unter einer Brücke, entfernt.

Linienverwaltung: Linien können eingerichtet, geändert und gelöscht werden, sowie Informationen über die Linien eingesehen werden.

Listenverwaltung: Das Symbol des Listenblattes führt zu einem Untermenü mit sechs Listen:
· Haltestellenliste
· Fahrzeugliste
· Stadtliste
· Warenliste
· Fabrikliste
· Touristenzielliste

Briefkasten: Alle Meldungen, die seit dem Spielstart bzw. seit dem letzten Laden eines Spielstandes angefallen sind, werden in einer Liste aufgeführt.

Finanzfenster: Das Kontefei von Hajo, dem Initiator von Simutrans, schmückt die Geldnote, welche in Simutrans die Finanzkraft repräsentiert. Das sich öffnender Fenster zeigt alles Wissenswerte über Deine momentane Finanzlage.

Screenshot: Bei der Nutzung des Kamera-Buttons wird ein Schnappschuss des aktuellen Kartenausschnittes als Bitmap-Datei im Verzeichnis simutrans/screenshot gespeichert.

Pause: Falls Du Dir eine Pause vom harten Alltag des Transportunternehmers gönnen möchtest, bestelle über den Button ruhig eine heiße Tasse Tee oder Kaffee. Der Service ist in Simutrans natürlich gratis.
Vorlauf:Falls Dir Simutrans zu langsam läuft, kannst Du hier beschleunigen. Es kann auch zu ruckeln führen, speziell mit Schiffen!

Statusleiste

Über der Statuszeile, am unteren Hauptfensterrand, werden gelegentlich Nachrichten angezeigt. Welche Meldungen erscheinen sollen, lässt sich in den Mailbox-Optionen festlegen. Die Statusleiste enthält Anzeigen, die sich im Spielverlauf permanent aktualisieren:
· Datum und Uhrzeit: In Simutrans ist ein Jahr in 12 Monate und ein Monat in 24 Stunden unterteilt. Über das Datum wird die Verfügbarkeit von Fahrzeugen und Gebäuden gesteuert, wenn die 'timeline' aktiviert ist (siehe unten). Vor der Jahreszahl werden die meteorologischen Jahreszeiten angezeigt. In einigen Szenarien kann sich der Untergrund mit den Jahreszeiten ändern.
· Spieler: Der Name des aktuellen Spielers wird in dessen Spielerfarbe angezeigt, sofern es ein Computerspieler ist.
· Kasse: Der Kassenbestand des aktuell agierenden Spielers wird angezeigt und permanent aktualisiert.
· Positionskoordinaten: In der Klammer werden die X- und Y-Koordinaten sowie die Höhenebene der Kachel angezeigt, über welcher sich der Cursor gerade befindet.
· Spielgeschwindigkeit: Der Wert (T=1.00) gibt die momentane Spielgeschwindigkeit an, siehe unter Spielsteuerung, Abschnitt Spielgeschwindigkeit. Bei Vorlauf wird die T-Anzeige durch zwei Pfeile ersetzt.
· mit Epochen: Zeigt an, ob die timeline aktiviert ist oder nicht, siehe Neue Welt erstellen.

simutrans-124.3/simutrans/text/de/map.txt000066400000000000000000000103541474050137200204750ustar00rootroot00000000000000Kartenfenster

Kartenfenster

Das Kartenfenster öffnest Du entweder mit dem m auf der Tastatur oder über das Kartensymbol in der Hauptmenüleiste.

Die Reliefkarte zeigt die Welt mit allen Objekten wie Industrien, Verkehrswegen, Städten und Fahrzeugen. Du kannst schnell zu jedem beliebigen Ort auf der Karte springen, indem Du die Position in der Reliefkarte anklickst.

Auswahl

Blendet die farbigen Schaltflächen ein, mit denen verschiedene Informationen in der Karte hervorgehoben werden können. Wenn nicht anders beschrieben, werden Anzeigen nach einem Farbschema von rot bis blau relativ zueinander eingefärbt.

Städtenamen blendet die Städtenamen weiss in der Karte ein. (Kann auch durch Drücken der Strg-Taste erreicht werden.
Passagiere markiert grob alle Gebiete in Spielerfarbe, welche im Einzugsgebiet von Haltestellen mit Personenverkehr liegen. Eine genaue Anzeige auf der Hauptkarte liefert die Taste v.
Postmarkiert grob alle Gebiete in Spielerfarbe, welche im Einzugsgebiet von Haltestellen mit Briefkästen bzw. Postämtern liegen.
Fracht zeigt, wieviel Fracht (Einheiten von Passagieren und Gütern) auf den Verkehrswegen transportiert wird.
Haltstatus zeigt an, ob an einer Haltestelle unzufriedene Passagiere erzeugt werden. Die gleiche Anzeigefarbe wird auch in der Haltestellenliste und im Statusbalken beim Haltestellennamen verwendet.
An-/Abfahrten zeigt an, wieviele Fahrten zu und ab einer Haltestelle gegangen sind.
Verkehr zeigt die Auslastung einer Strecke an.
Abfahrtsort zeigt an, wieviele Waren und Personen diese Haltestelle als Ausgangspunkt haben.
Zielort zeigt an, wieviele Waren und Personen diese Haltestelle als Endpunkt haben.
Wartend zeigt an, wieviele Waren und Personen an einer Haltestelle auf Beförderung warten.
Gleistrassen hebt Eisenbahnlinien weiß hervor; elektrifizierte Bahnstrecken werden braun hervorgehoben. Signale werden mit gelben Punkten markiert.
Tempolimit zeigt Höchstgeschwindigkeiten auf Straßen und Schienen an.
Freileitungen trägt die Hochspannungsleitungen in die Karte ein. Die Farbe kodiert die aktuelle Stromleistung beim öffnen der Karte (wird nicht automatisch aktualisiert!).
Attraktionen vergrößert die eingetragenen Touristenattraktionen in der Karte und färbt sie nach ihrem Passagieraufkommen ein.
Fabriken vergrößert die Anzeige der Industrien in der Karte.

Depots Hebt alle Depots in orange, gelb, rot und rosa hevor, je nach Wegtyp.
Wälder Geschlossene Waldgebiete (mit mehr als zwei Bäumen pro Kachel) werden hellgrün hervorgehoben.
Stadtgrenzen: Umrahmungen der Stadtgebiete, d.h. alle Gebiete, die zu einer Stadt direkt gehören.
Reiseziele: Falls eine Stadt ausgewählt ist, werden die Reiseziele dieser Stadt auf der Karte angezeigt (analog zu der kleinen Karte der Stadtinformation.

Werteskala
Blendet den Balken ein, der die Farben zeigt, nach denen einige Objektauswahlen bestimmte Kartenbereiche entsprechend dem dargestellten Wert einfärben.

Industrieliste
Farbskala der Industrien.

Vergrößerung
Wähle die Vergrößerung von 1:6 bis 16:1 Pfeilschalter oder Mausrad.
Bei 1:1 entspricht eine Kachel einem Pixel auf der Karte.

Isometrische Anzeige:
Die Reliefkarte wird analog zur Spielfeld-Ausrichtung ausgerichtet.

Fabrikverbindungen:
Abnehmer der Industrien Mit der Maus auf eine Industrie zeigen (weisse Linien).
Zulieferer der Industrien Shift + mit der Maus auf eine Industrie zeigen (rote Linien).
Hinweis: Sollte nichts angezeigt werden, dann einmal in das Kartenfenster klicken.

Linienpläne
Bei geöffneter Linienverwaltung wird die dort markierte Linie in der Reliefkarte angezeigt.

simutrans-124.3/simutrans/text/de/monorailtools.txt000066400000000000000000000015251474050137200226210ustar00rootroot00000000000000Monorailbau

Monorailbauwerkzeuge

Diese Werkzeugleiste dient dem Bau von Monorailgleisen, Brücken, usw. Wird Simutrans in einem kleineren Fenster gespielt, können die letzten Symbole auf die nächste Zeile umgebrochen sein. Bei der Auswahl eines Werkzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Monorails gibt es im Unterschied zur normalen Eisenbahn auch als Hochbahn. Sie lässt sich über einstöckige Häuser und oberhalb von Straßen bis in die Innenstädte legen. Um ein Hochbahngleis mit einem ebenerdigen zu verbinden, baut man eine Brücke. Hinweis: Die Positionierung der Maus bei Hochbahnen erfolgt auf dem Feld darunter.

Für die weiteren Erläuterungen siehe die Eisenbahnbauwerkzeuge.

simutrans-124.3/simutrans/text/de/new_world.txt000066400000000000000000000127141474050137200217220ustar00rootroot00000000000000Neue Welt

Erstelle eine neue Welt

Der Neue Welt-Dialog erscheint bei jedem Spielstart. Im laufenden Spiel kann man ihn nach dem Anwählen der Schaltfläche Neue Karte im Dialog Einstellungen aufrufen. Dieser wird mit dem Diskettensymbol in der Hauptmenüleiste geöffnet.

Im Dialog werden die Parameter eingestellt, die für die Generierung der Karte gelten sollen. Die Einstellungen erfolgen über die Pfeilschaltflächen der Einstelloptionen. Ein Klick auf einen Pfeil nach links verringert, ein Klick auf einen Pfeil nach rechts erhöht den entsprechenden Wert.

Einstellungen für neue Karte:

· Kartennummer: Es stehen 10.000 Simutrans-Karten zur Auswahl. Über sie werden die groben Strukturen der Welt festgelegt.

· Vorschaubild: Das Bild zeigt die ausgewählte Karte und aktualisiert sich bei jeder Änderung der Kartenparameter.

· Kartengröße: Wähle mit den Pfeilschalter, welche Abmessungen die Karte haben soll. Die obere Zahl gibt die Breite (x-Richtung), die untere die Höhe (y-Richtung) der Karte an. Die Einstellbereiche liegen zwischen 64 bis 4096. Der Vorgabewert ist 256x256. Unterscheiden sich die Werte, wird das Vorschaubild verzerrt dargestellt.
Die Angabe in Klammern zeigt Dir, wieviel Arbeitsspeicher ein Spiel der eingestellten Kartengröße mindestens belegen wird.

· Zufallskarte: Wähle eine zufällige Karte aus. Die oben gemachten Einstellungen werden nicht verändert.

· Lade Relief: Die getroffenen Einstellungen werden anstatt auf die angezeigte Karte auf ein im Verzeichnis simutrans/maps bzw. Benutzerverzeichnis/simutrans/maps gespeichertes Relief übertragen. Der Relief laden Dialog wird eingeblendet.

· Anzahl Städte: Bestimmt die Anzahl der Städte auf der Karte. Der Vorgabewert ist 16. Ist eine Karte zu rauh, oder ist die Zahl der Städte zu hoch, werden weniger als die eingestellte Anzahl von Städten generiert. (Der Mindestabstand der Städte ist in der Datei simutrans/config/cityrules.tab als Wert der Variablen minimum_city_distance angegeben).

· Mittlere Stadtgröße: Der Wert stellt eine mittlere Bezugsgröße dar. Beim Vorgabewert von 1600 bei 16 Städten werden ca. eine Stadt mit 8000-16000 Einwohnern, ein oder zwei mit 1000-5000 und die übrigen mit 200-600 generiert. Es ist durchaus erwünscht, dass immer mal wieder auch einige sehr große Städte erzeugt werden.

· Verbindungsstraßenlänge: An Anfang werden alle Städte miteinander verbunden, wenn dies mit einer Straße kleiner als die angegebenen Zahl möglich ist. Dabei ist eine gerade Straße 2 Einheiten teuer, Kurven und Steigungen mehr.

· Industriezweige: Der Wert gibt an, wieviele Industriezweige beim Kartenstart erzeugt werden sollen. Durch das Wachstum von Städten werden weitere Industriezweige erzeugt. Wann jeweils ein neuer Industriezweige erzeugt wird, regelt der Wert der Variablen industry_increase_every in der simucon.tab. Der dortige Vorgabewert 2000 bedeutet, dass jeweils, wenn eine Stadt die Größe von 2000, 4000, 8000 usw. Einwohnern erreicht, ein neuer Industriezweig entsteht. Mit dem Wert 0 wird die Errichtung neuer Industriezweige ausgeschaltet. Hat ein Endverbraucher mehrere Waren (z.B. die Apotheke: Medizin und Chemikalien), dann gilt jeder als eigene Industriekette.
Die Vielfalt an Industriezweigen kann durch Ergänzungspaks erhöht werden.

· Touristenattraktionen: Stelle die Anzahl von Ausflugszielen wie Burgen, Jahrmarktattraktionen usw. ein.

· Mit Einführungsdaten ab: Drücke den Schalter ein, wenn Fahrzeuge und Gebäude erst ab ihrem Entwicklungsjahr verfügbar sein sollen. Das Startjahr wird mit den beiden Pfeilschaltern geändern. Die Vorgabe ist in der simutrans/config/simuconf.tab als Wert der Variablen starting_year eingetragen. Sinnvolle Werte sind z.B. 1910, 1930, 1950. Vor 1835 gibt es nur Pferdefuhrwerke.

· Anfängermodus: In diesem Modus liefern alle Fabriken an alle geeigneten Abnehmer für diese Waren. Außerdem sind die Frachtgewinne um den Faktor 1,5 erhöht.

· Einstellungen: Ruft die Erweiterten Einstellungen auf, wo sich fast alle Parameter von Simutrans beinflussen lassen können.

· Einstellungen Landschaft: ruft die Landschaftseinstellungen auf, wo Klimazonen, Bergigkeit, Grundwasserspiegel, Flüsse und vieles mehr vorgegeben werden kann.

· Lade Spiel: Lade einen bereits vorhandenen Spielstand. (siehe Lade Menü)
Achtung: Der laufende Spielstand wird nicht gespeichert und geht verloren.

· Lade Szenario: Es stehen verschiedene Szenarien zur Auswahl. (siehe Szenario Menü)
Achtung: Der laufende Spielstand wird nicht gespeichert und geht verloren.

· Starte Spiel: Eine neue Karte wird entsprechend den Einstellungen generiert, und ein neues Spiel startet.
Achtung: Der laufende Spielstand wird nicht gespeichert und geht verloren.

· Beenden: Das Spiel wird beendet.
Achtung: Der laufende Spielstand wird nicht gespeichert und geht verloren.

simutrans-124.3/simutrans/text/de/options.txt000066400000000000000000000030071474050137200214100ustar00rootroot00000000000000Einstellungen

Einstellungen, Laden, Speichern

Der Dialog Einstellungen ist zweigeteilt. Auf der linken Seite befinden sich die Spieleinstellungen. Auf der rechten Seite kannst Du Spielstände laden, speichern, eine neue Karte starten, Missionen laden sowie das Spiel beenden.

·Sprache: Wähle die Sprache, welche Simutrans nutzen soll. Die Sprachdateien befinden sich im Verzeichnis simutrans/text. In den Unterverzeichnissen sind die Hilfetexte der Sprachen abgelegt.
·Spieler: Stelle die Anzahl der Computerspieler ein.
·Spielerfarbe: Einstellen der eigenen Spielerfarbe.
·Anzeige: Einstellungen für Grafik und Maus sowie Angaben über die Auslastung des Computers.
·Sound: Einstellungen für Sound und Musik.

·Neues Spiel: Starte eine neue Karte.
·Laden Spiel: Spielstand laden.
·Speichern: Spielstand speichern.
·Wähle Mission: Öffnet das Auswahlfenster der vorhandenen Missionen.
·Missionsstatus: Diese Schaltfläche ist nur aktiv, wenn eine Mission gespielt wird. Sie öffnet das Missionsinformationsfenster.

· Beenden: Das Spiel wird beendet (ohne den Spielstand zu sichern).

simutrans-124.3/simutrans/text/de/password.txt000066400000000000000000000020461474050137200215610ustar00rootroot00000000000000Spielernamen und Passwort ändern

Spielernamen und Passwort ändern

Es gibt zwei Möglichkeiten, warum du diesen Dialog siehst:

1.) Du hast auf das Kästchen rechts vom Spielernamen in der Spielerliste geklickt.
2.) Der aktive Spieler ist passwortgeschützt und du wolltest ein Kommando ausführen.

Ist im Dialog der Name nicht änderbar, dann ist der Spieler passwortgeschützt und du musst das Passwort eingeben. (Die Passwörter werden lokal gespeichert; solange du Simutrans nicht neu startest, musst du das Passwort nicht mehr eingeben.)

Kannst du sowohl Namen wie Passwort eingeben, dann ist der Spieler für dich verfügbar. Sobald der Name geändert oder ein neues Passwort eingeben wurde, wird dies nun für den Spieler verwendet.

Den Status eines Spieler kannst du in der Spielerliste erkennen. Ist dort eine grüne Box, ist der Spieler für dich zugänglich. Ist sie Rot, muss hier ein korrektes Passwort eingegeben werden.

simutrans-124.3/simutrans/text/de/players.txt000066400000000000000000000036421474050137200214010ustar00rootroot00000000000000Spielerliste

Spieler Menü

Im Spieler-Menü sind alle Spieler aufgelistet.
Ganz oben befindet sich der menschliche Spieler.
Darunter befindet sich die Öffentliche Hand. Die öffentliche Hand kümmert sich nur um den Ausbau der Städte und Industrien sowie Sehenswürdigkeiten und Denkmälern.

Wenn Du auf den Pfeil vor dem jeweiligen Spieler klickst, dann wechselst Du zu diesem Spieler. Voraussetzung dafür ist, das der Spielerwechsel nicht deaktiviert wurde.

Darunter befinden sich mehrere Felder, wo weitere Spieler (KI-Spieler) ausgewählt werden können. Ist das Feld grau, so ist noch kein Spieler ausgewählt. Nach der Auswahl eines Spielers, erscheint vor dem Feld eine kleine Schaltfläche, mit der der Spieler aktiviert und deaktiviert werden kann.

Aktivierte Computerspieler (KI-Spieler) werden sich alsbald auf die Suche nach neuen Transportmöglichkeiten machen und eigene Linien eröffnen. Wenn Du den KI-Spieler wieder deaktivierst, wird er keine neuen Verbindungen mehr suchen, den bisherigen Betrieb aber weiterführen.

KI-Spieler: Die Firmennamen der KI-Spieler stehen auf Schaltflächen, die die Spielerfarben des entsprechenden KI-Spielers tragen. Drücke eine dieser Schaltflächen, um dessen Finanzfenster einzusehen. Das aktuelle Barvermögen der KI-Spieler wird rechts angezeigt.

Unter der Liste mit den Spielern befindet sich die Option Ohne Bankrott. Aktivierst Du diese Option, dann gehen die Spieler (und du selbst) nicht Pleite, wenn das Gesamtvermögen negativ wird.

Für Spiele im Netzwerkmodus können Spieler passwortgeschützt werden. Ein passwortgeschützter Spieler ist durch ein rotes Kästchen neben dem Namen markiert. Ist kein Passwort gesetzt oder der Spieler freigeschaltet, ist dieses Kästchen grün. Durch Klick auf das Kästchen öffnet sich ein Dialog zur Passworteingabe.

simutrans-124.3/simutrans/text/de/privatesign_info.txt000066400000000000000000000011631474050137200232640ustar00rootroot00000000000000Privatweg

Privatweg

Mit diesem Schild kann festgelegt werden, wer auf diesem Weg passieren darf. Die einzigen Fahrzeuge der öffentlichen Hand sind die Stadtautos. Alle anderen Felder betreffen die anderen Spieler.

Spieler aktiviert, heißt dass Fahrzeuge des Spieler passieren dürfen. Dieser Spieler sieht dann auch ein offenes Tor oder wie immer auch die Durchfahrt angezeigt wird.

Dieses Verkehrzeichen gibt es in den Wegebauwerkzeugen, z.B bei den Eisenbahnwerkzeugen oder den Straßenbauwerkzeugen.

simutrans-124.3/simutrans/text/de/railtools.txt000066400000000000000000000236251474050137200217350ustar00rootroot00000000000000Eisenbahnbau

Eisenbahnbauwerkzeuge

Diese Werkzeugleiste dient dem Bau von Eisenbahngleisen, Fahrleitungen, Brücken, Tunneln, Signalen, Depots und Bahnhöfen. Wird Simutrans in einem kleineren Fenster gespielt, können die letzten Symbole auf die nächste Zeile umgebrochen sein. Bei der Auswahl eines Werkzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Gleise können mit unterschiedlichen Höchstgeschwindigkeiten befahren werden. Ist die Timeline aktiviert, werden Gleise mit schnellerer Höchstgeschwindigkeit erst nach und nach verfügbar. Höchstgeschwindigkeit und Baukosten werden in den Tooltips angezeigt. Der Abriss kostet genausoviel wie das Bauen; einzige Ausname ist, wenn direkt nach einer Bauaktion, die Taste z für Rückgängigmachen betätigt wurde (siehe weiter unten).
Simutrans benutzt nur leere Felder oder bereits vorhandene Gleise. Brücken, Tunnel, Straßen usw. werden nicht benutzt. Allerdings werden automatisch Bahnübergänge gebaut. Am Hang kann nur in Neigungsrichtung gebaut werden.
Beim ersten Platzieren des Gleisbauwerkzeuges in der Weltkarte wird der Anfang der Strecke festgelegt, beim zweiten der Endpunkt. Das Spiel baut zwischen beiden Punkten die kürzestmögliche Strecke. Wenn keine Verbindung gefunden wird, passiert nach dem Anklicken des Endpunktes nichts. Eine Bauaktion lässt sich mittels z gratis rückgängig machen (ohne Baukostenerstattung), solange nichts anderes gebaut wurde.
Hinweis: Um eine diagonale Strecke oder parallel zu einem bestehenden Gleis zu bauen, beim zweiten Klick die Ctrl(Strg)-Taste gedrückt halten.

Fahrleitungen sind zum Betrieb von E-Loks und Trams notwendig. Im Depotfenster werden verfügbare E-Loks bzw. Trams nur angezeigt, wenn der Block des Depots elektrifiziert ist. Die Linienstrecken, welche von E-Loks bzw. Trams befahren werden sollen, musst Du komplett elektrifizieren, da die E-Konvois ansonsten keinen Weg finden. Sie verlassen dann das Depot nicht oder bleiben am letzten Linienpunkt vor der Fehlersituation stehen.
Das Fahrleitungswerkzeug funktioniert ähnlich wie das Gleisbauwerkzeug. Der erste Klick definierte den Startpunkt und der zweite Klick den Endpunkt. (Dabei beachtet das Werkzeug allerdings alle Einrichtungssignale!)

Eisenbahnbrücken beginnen immer an Gleisenden. Für das Brückenende sucht Simutrans in der geraden Weiterführung des Gleisendes ein vorhandenes Gleisende, welches in die Richtung des Anfangspunktes weist. Wird eine passende Hanglage vorgefunden, so wird die Brücke an sie angelehnt. Das weiter führende Gleis kann in dem Fall auch nachträglich gebaut werden, muss aber bis auf das Brückenende gebaut werden. Um eine Brücke an einem Hang beginnen zu lassen, das Gleis bis auf den Hang bauen und dann das Brückenbauwerkzeug benutzen. (In neueren Versionen kann eine Brücke auch an einer senkrechten Wand enden. Dazu sollte vorher dort schon eine Schiene gelegt worden sein.)

Eisenbahntunnel können nur gerade und nur in einer Höhenebene gebaut werden. Als Startpunkt des Tunnels muss das Gleisende in einer Hanglage enden. Setze das Tunnelbauwerkzeug auf das Gleisstück in der Hanglage. Der Tunnel wird komplett gebaut, wenn Simutrans in der gegenüberliegneden Bergflanke eine gerade Hanglage vorfindet. Der Gleisbau ist dann auf dem Tunnelausgang fortzusetzen. Erhältst Du eine Hinweismeldung, war das gegenüberliegende Hangstück nicht gerade oder ist bebaut. Eine wichtige Bauhilfe stellt die Nutzung des Gitternetzes dar (in der größten Kartenansicht schaltet die Taste # es ein und aus); mit ihm lässt sich der Durchstoßpunkt besser finden.
Willst du nur ein Tunnelportal bauen, dann kannst du einen Ctrl (Strg)+Mausklick machen. Danach kann du dann in den Untergrundmodus wechseln (mit U oder unter Anzeigeeinstellungen) und mit dem Tunnelwerkzeug weitere Strecken bauen.

Signale werden genutzt, um die Bewegungen der Züge zu kontrollieren. Die Grundstellung von Signalen bei Simutrans ist "Halt" (rotes Signal). Erreicht ein Zug ein Signal, dann bekommt er nur grün, wenn die Strecke bis zum nächsten Signal auf seiner Route frei ist und auch für keinen anderen Zug reserviert wurde. Die Strecke ist dann für diesen Zug reserviert. Die Reservierung wird hinter dem Zug aufgelöst. Diese Streckenteile können danach für Querende oder Abzweigende Züge genutzt werden. ACHTUNG: Bahnhöfe enthalten unsichtbare Signale, denn ein Zug reserviert die Strecke nur bis zu seiner Haltestelle. Soll die Strecke bis zum nächsten echten Signal reserviert werden, müssen Langstreckensignale (s.u.) verwendet werden!
- Signalbau Signale können nur auf Gleisen gebaut werden, aber nicht auf Kreuzungen. Beim Bau eines Signals wird auf jeder Gleisseite ein Signal aufgestellt. Die Strecke kann in beiden Richtungen befahren werden. Klickst Du die Platzierungsstelle erneut mit dem Signalwerkzeug an, wird ein Signal entfernt, die Strecke kann nur in Signalrichtung befahren werden. In der Regel befinden sich die Signale in Simutrans rechts vom Gleis. Beim nächsten Klick auf die Positionierungsstelle wird ein Signal auf der Gegenseite plaziert. Die Strecke kann nun nur in der Gegenrichtung befahren werden. Beim nächsten Klick erscheinen wieder beide Signale, die Strecke ist wieder in beide Richtungen befahrbar.
Wird ein Signal mit Strg+Maustaste ausgewählt, kann mit dem Multisignalwerkzeug eine ganze Reihe von Signalen auf einmal gebaut werden.
- Wegfindung Wurden auf einer Strecke Richtungssignale in der verkehrten Richtung aufgestellt, können die Züge der Linie keinen Weg finden und verlassen das Depot oder den Bahnhof nicht bzw. bleiben am letzten Linienpunkt vor dem nicht passierbaren Signal stehen. Es ist somit empfehlenswert, dem Verhalten der Züge auf neu eingerichteten Strecken anfänglich etwas erhöhte Aufmerksamkeit zu widmen.
- Signalarten:
-- einfaches Signal Es ist das normale Signal, oft Formsignal, Standardlichtsignal, oder einfach nur Signal genannt. Erreicht ein Zug das Signal, dann wird versucht die Strecke bis zum nächsten Signal, oder der nächsten Haltestelle des Zugs, zu reservieren. Gelingt das, dann bekommt er grün. Ansonsten bleibt das Signal rot und der Zug muss er warten bis die Strecke frei wird.
-- Zweiblocksignal Zwei-Block-Signale (gelegentlich auch Vorsignal genannt) geben die Fahrt erst frei, wenn das nächsten Signal ebenfalls frei zeigt. Es werden zwei freie Blöcke zur weiterfahrt benötigt. Sie sind prädestiniert für verschiedene Deckungsaufgaben.
Als Einfahrsignale regeln sie, dass ankommende Züge den Weichenbereich nicht befahren, solange sich noch ein Zug im Bahnhofsblock befindet. Bei mehrgleisigen Kreuzungen kann durch Zwei-Block-Signalen erreicht werden, dass Züge erst dann den Kreuzungsbereich befahren, wenn danach noch 1 Block frei ist. So vermeidest Du Situationen, in denen Züge auf Kreuzungen stehen bleiben.
-- Auswahlsignal Auswahlsignale (Einfahrtsignale) geben die Fahrt erst frei, wenn sie für den Zug einen freien Weg bis zum Zielbahnhof, das ist der nächste im Fahrplan angegebene Halt, reservieren konnte. Wenn der im Fahrplan angegebene Bahnsteig nicht frei ist, dann wird der nächste ausreichend lange Bahnsteig des Zielbahnhofs ausgewählt. ACHTUNG: Der Zielbahnhof ist nicht zwingend der nächste nach dem Auswahlsignal kommende Bahnhof. Ein Zug bleibt solange vor einem Auswahlsignal stehen, bis ein passender Bahnsteig des Zielbahnhofs und die ganze Strecke bis dorthin frei ist! Man kann das umgehen, indem man für Züge, bei denen dies nicht erwünscht ist, einen Wegpunkt hinter das Auswahlsignal setzt. Damit ist der nächste im Fahrplan angegebene Halt ein Wegpunkt und das Auswahlsignal arbeitet dann für diesen Zug wie ein normales Signal.
-- Auswahl-Ende-Signal Beendet die Suche des Auswahlsignals für dieses Gleis. Bahnsteige hinter diesem Signal werden bei der Suche nach einem freien Bahnsteig nicht berücksichtigt.
-- Langstreckensignale geben die Fahrt erst frei, wenn sie für einen Zug einen freien Weg bis zum nächsten echten Signal (auch durch mehrere Bahnhöfe hinweg) reservieren konnten. Dies ist z.B. für lange eingleisige Abschnitte mit einem oder mehreren Bahnhöfen nötig, um Blockaden zu vermeiden.
-- VorrangsignalDieses Signal reserviert über mehrere Vorrangsignale hinweg so viele Streckenabschnitte wie möglich. Es wird bis zu einer Haltestelle oder einem normalen Signal reserviert. Damit ist es möglich Ausweichgleise zu bauen. Die Hauptstrecke erhält Vorrangsignale, das Ausweichgleis erhält eine Haltestelle oder ein normales Signal. Fährt nun ein langsamer Zug auf die Ausweiche, kann sich der nachfolgende schnelle Zug die Hauptstrecke an der Ausweichstelle vorbei reservieren und der langsame Zug muss warten bis der schnelle Zug vorbei ist.

Im Depot kannst Du Züge zusammenstellen sowie Linien einrichten und die Züge nach der Zuordnung zu Linien starten. Das Depot kann nur auf einem ebenen Gleisende platziert werden. Für E-Loks muss das Gleis zudem elektrifiziert sein. (siehe Depotfenster)

Bahnhöfe sind detailiert in der Hilfe zum Haltestellenfenster beschrieben. Die verschiedenen Haltestellengrafiken können die Haltestelle veranlassen, Passagiere, Post oder Güter umzuschlagen; es macht später jedoch keinen Unterschied mehr, auf welcher Grafik welcher Zug hält, er wird immer be- und entladen, wenn die Station für den Umschlag eingerichtet ist.

Bahnhofseingang und -vorplatz können verwendet werden, wenn der Bahnhof auf erhöhtem Gelände mit Mauer gebaut ist. Sie werden vor die Mauer gebaut. Sie gehören zu den Nebengebäuden.

Nebengebäude siehe Spezialbauwerkzeuge

simutrans-124.3/simutrans/text/de/roadtools.txt000066400000000000000000000115021474050137200217220ustar00rootroot00000000000000Straßenbau

Straßenbauwerkzeuge

Diese Werkzeugleiste dient dem Bau von Straßen, Brücken, Tunneln, Signalisationen, Depots und Haltestellen. Bei der Auswahl eines Wergzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Wege und Straßen können mit unterschiedlichen Höchstgeschwindigkeiten befahren werden. Ist die Timeline aktiviert, werden Strassen mit schnellerer Höchstgeschwindigkeit erst nach und nach verfügbar. Höchstgeschwindigkeit und Baukosten werden in den blauen Tooltips angezeigt. Der Abriss kostet für alle Straßen genausoviel wie deren Bau.

Simutrans benutzt nur leere Felder bzw. bereits vorhandene Straßen. Brücken, Tunnel, Eisenbahnstrecken usw. werden nicht in die Bauaktion mit einbezogen. Allerdings werden automatisch Bahnübergänge gebaut. Am Hang kann nur in Neigungsrichtung gebaut werden.

Beim ersten Platzieren des Strassenbauwerkzeuges in der Weltkarte wird der Anfang der Strecke festgelegt, beim zweiten der Endpunkt. Das Spiel baut zwischen beiden Punkten die kürzestmögliche Strecke. Wenn keine Verbindung gefunden wird, passiert nach dem Anklicken des Endpunktes nichts. Eine Bauaktion lässt sich mittels z gratis rückgängig machen (ohne Baukostenerstattung), solange nichts anderes gebaut wurde.

Straßenbrücken beginnen immer an Straßenenden. Für das Brückenende sucht Simutrans in der geraden Weiterführung des Straßenendes ein vorhandenes Straßenende, welches in die Richtung des Anfangspunktes weist. Wird eine passende Hanglage vorgefunden, so wird die Brücke an sie angelehnt. Die weiter führende Straße kann in dem Fall auch nachträglich gebaut werden, muss aber bis auf die Brücke fortgebaut werden. Um eine Brücke an einem Hang beginnen zu lassen, die Straße bis auf den Hang bauen und dann das Brückenbauwerkzeug benutzen. (In neueren Versionen kann eine Brücke auch an einer senkrechten Wand enden. Dazu sollte vorher dort schon eine Straße gebaut worden sein.)

Straßentunnel können nur gerade und nur in einer Höhenebene gebaut werden. Als Startpunkt des Tunnels muss ein Straßenende in einer Hanglage verbaut sein. Setze das Tunnelbauwerkzeug auf das Straßenstück. Der Tunnel wird komplett gebaut, wenn Simutrans in der gegenüberliegneden Bergflanke eine gerade Hanglage vorfindet. Erhältst Du eine Hinweismeldung, war das gegenüberliegende Hangstück nicht gerade. Eine wichtige Bauhilfe stellt die Nutzung des Gitternetzes dar (in der größten Kartenansicht schaltet die Taste # es ein und aus); mit ihm lässt sich der Durchstoßpunkt besser finden.
Willst du nur ein Tunnelportal bauen, dann kannst du einen Ctrl (Strg)+Mausklick machen. Danach kann du dann in den Untergrundmodus wechseln (mit U oder unter Anzeigeeinstellungen) und mit dem Tunnelwerkzeug weitere Strecken bauen.

Die Verkehrssignalisation wird genutzt, um die Bewegungen der Strassenfahrzeuge zu kontrollieren. Die meisten Schilder sind selbsterklärend. Eine Besonderheit ist das Schild Privatweg, das nur Fahrzeuge bestimmte Spieler passieren lässt.

Der Wegweiser dient zur Verteilung von Fahrzeugen auf gleichartige Halteplätze an der selben Haltestelle, wenn (bei Vorbeifahrt am Wegweiser) der vom Fahrplan festgelegte Halteplatz besetzt ist. Er wird in Fahrtrichtung vor der Haltestelle aufgestellt.
Die Ampeln können an Kreuzungen und Einmündungen aufgestellt werden und regeln den Verkehr. Durch geschicktes Einstellen der Ampelphasen lassen sich grüne Wellen realisieren.
Die Baustellenabschrankung sorgt dafür, dass kein Fahrzeug mehr ein Strassenstück befährt. Die Straße wird ganz oder einseitig gesperrt. Bei der einseitigen Sperrung mehrmals klicken um die Straßenseite zu wechseln.
Das Einfahrt verboten Schild macht eine Strasse zur Einbahnstrasse, der Verkehr rollt dort nur noch in Gegenrichtung.
Das Schild Mindestgeschwindigkeit lässt auf einem Strassenstück nur noch Fahrzeuge fahren, die mehr als 80 km/h erreichen können.

Mit den beiden letzten Signalen zusammen kann man Autobahnen nachbilden.

Im Depot kannst Du Bus-, Post- und Güterkonvois zusammenstellen sowie Linien einrichten und die Konvois nach der Zuordnung von Linien starten. Das Depot kann nur auf einem ebenen Straßenende platziert werden.

Haltestellen sind detailiert in der Hilfe zum Haltestellenfenster beschrieben. Es gibt unterschiedliche Typen von Haltestellen: Bushaltestellen ermöglichen den Passagierverkehr; Frachthöfe den Güterverkehr; Posthaltestellen (wenn vorhanden) den Postverkehr, diese können das Postgebäude ersetzen. Wo welches Fahrzeug letztlich hält, macht keinen Unterschied.

simutrans-124.3/simutrans/text/de/save.txt000066400000000000000000000024551474050137200206610ustar00rootroot00000000000000Speichern

Dialog Speichern

Gib zum Speichern des Spielstandes einen Namen in das Textfeld Dateiname ein und bestätige mit ENTER oder drücke den OK Button.

Achtung: Wählst Du einen bereits bestehenden Eintrag an, wird der vorhandene Spielstand ohne weitere Meldung überschrieben.
Autosave-Spielstände werden bei aktivierten Autosave automatisch überschrieben.

X - Löschen: Achtung: Das X vor jedem Namen löscht den entsprechenden Spielstand. Es wird nicht nachgefragt sondern sofort gelöscht. Das X wird nur angezeigt, wenn in der simuconf.tab der Parameter show_delete_buttons = 1 gesetzt ist.

Schaltfläche mit Namen: Durch einen Klick auf einen Button wird der entsprechende Spielstand geladen. Der Spielstand muss mit dem gestartetem pak (Grafikset) und der Simutrans-Version kompatibel sein.

Information des paks (Grafiksets): Gibt an mit welchem pak (Grafikset) der Spielstand gespeichert wurde.

Datum und Uhrzeit: Gibt an zu welchem Datum und welcher Uhrzeit der Spielstand gespeichert wurde.

Abbrechen: Schließt den Dialog ohne das Spiel zu speichern.

simutrans-124.3/simutrans/text/de/scenario.txt000066400000000000000000000024241474050137200215220ustar00rootroot00000000000000Missionen

Spielziele

Simutrans hat normalerweise kein bestimmtes Ziel. Es gibt jedoch die Möglichkeit, Spiele mit Spielziel zu definieren. Im Spielzieldialog werden Spiele mit einem Spielziel aufgelistet. Nach der Anwahl eines Eintrages wird eine neue Karte mit Spielziel ohne weitere Rückfrage geladen.

Achtung! Das aktuelle Spiel wird verworfen und nicht automatisch gesichert!

Der aktuelle Stand in Prozent kann im Finanzdialog eingesehen werden. Wird das Spielziel am Ende eines Monates erreicht (also 100%) und das Konto ist nicht überzogen, erscheint eine Mitteilung. Das Spiel kann aber trotzdem normal fortgesetzt werden. Folgende Spielziele gibt es:


· Beliefere eine Fabrik (und alle ihre Zulieferer).
· Erreiche den vorgegebenen Kontostand.
· Baue ein Hauptquartier und die vorgegebene Anzahl profitabler Züge.
· Transportiere mondestens die vorgegebene Anzahl von Reisenden pro Monat.

Weitere Spielziele können hinzugefügt werden. Die Dateien befinden sich im Verzeichnis scenario. Dieses befindet sich im Verzeichnis des verwendeten Paksets. Die Szenarios bestehen jeweils aus einem Spielstand und einer Beschreibungsdatei mit dem Spielziel.

simutrans-124.3/simutrans/text/de/schedule.txt000066400000000000000000000111251474050137200215110ustar00rootroot00000000000000Fahrplaneingabe

Fahrplanfenster

Im Fahrplanfenster kannst Du den Fahrplan für den ausgewählten Fahrzeugverband oder den Linienfahrplan für die ausgewählte Linie bearbeiten. Ein Fahrzeugverband, dessen Fahrplan aufgerufen wurde, hält an und wartet, bis das Fahrplanfenster wieder geschlossen ist.

Bedient Linie (nur bei Fahrzeugverbänden ausserhalb des Depots): Das Textfeld zeigt die Linie an, in welcher der Fahrzeugverband fährt. Klicke zum Ändern der Linie ins Feld. Es öffnet sich eine Auswahlliste, in welcher alle verfügbaren Linien gelistet sind. Du kannst auch den Eintrag "keine Linie" wählen und den Fahrzeugverband nach einem individuellen Fahrplan fahren lassen.
Die Schaltfläche Neue Linie erstellt eine neue Linie mit dem aktuellen Fahrplan.

Wartezeit: Die Wartezeit ist nur aktiv, wenn das Fahrzeug auf eine Mindestbeladung in diesem Fahrplanhalt warten soll. Die Wartezeit ist in Teilen pro Monat angegeben, also von ganzer Monat (1/1), halber Monat (1/2), ... 1 Tag (1/32), ... usw. Ist die Wartezeit überschirtten, fährt das Fahrzeug weiter, auch wenn die Mindestbeladung noch nicht erreicht wurde.

Mindestbeladung: Die Mindestbeladung wird nur in Fahrplanhalten abgefragt. Du kannst mittels der Pfeilschalter für jede Haltestelle des Fahrplans einen der verfügbaren Werte zwischen 0% und 100% einstellen. Der Fahrzeugverband wartet an der Haltestelle, bis der eingestellte Wert der Mindestbeladung erreicht ist. Zum Auswählen der Haltestelle klicke auf diese, achte aber darauf das der Schalter "Löschen" nicht eingedrückt ist.

Fahrplanhalte: Die gelisteten Haltestellen und freien Wegpunkte werden vom Konvoi der Reihe nach angefahren. Die Fahrplanhalte sind durchnummeriert. Der eingedrückte Pfeil vor einer Zeile zeigt an, zu welchem Fahrplanhalt der Fahrzeugverband momentan unterwegs ist. Wartet er auf Beladung, zeigt der Pfeil auf die aktuelle Haltestelle. Beim Verlassen des letzten Fahrplanhaltes wird wieder der erste Fahrplanhalt angesteuert.


Fahrplanbearbeitung

Die Schaltfächen haben folgende Bedeutung:
· Hinzufügen: Der neue Fahrplanhalt wird am Ende der Liste angefügt.
· Einfügen: Der neue Fahrplanhalt wird vor dem mit eingedrücktem Pfeil gekennzeichneten Fahrplanhalt eingefügt.
· Löschen: Der per Mausklick angewählte Fahrplanhalt wird aus der Liste gelöscht. Nach löschen eines Fahrplanhaltes wird die Schaltfläche Hinzufügen wider aktiviert.

· Rückfahrkarte: Alle Fahrplanhalte werden bis zum Maximum von 254 Gesamteinträgen in umgekehrter Reihenfolge (ohne 1. und letzten Halt) an den bestehenden Fahrplan angefügt. Bei Verwendung von Richtungsstrecken (einseitige Signale bei Eisen-, Straßen- und Einschienenbahnen) wird die Rückfahrkarte allerdings nicht einsetzbar sein, da der Haltepunkt bei der Rückfahrt nicht direkt angefahren werden kann. Wenn ein Weg gefunden wird, erfolgt dieser dann mit einem großen Umweg.

Bei der Nutzung einer der Schaltflächen "Hinzufügen" oder "Einfügen" ändert sich der Cursor in einen Haltepunktmarker. Klickst Du mit dem Werkzeug auf ein Haltestellenfeld oder auf einen freien Wegpunkt, welcher vom Fahrzeugverband befahren werden kann (je nach Fahrzeugart zBsp. Straßen-, Wasser-, oder Gleisfeld), wird der Punkt als Fahrplanhalt in die Liste der Fahrplanhalte aufgenommen.
· Haltepunkte werden mit dem Namen der Haltestelle, der eingestellten Mindestbeladung und den Koordinaten des Feldes in die Liste eingetragen.
· Freie Wegpunkte werden mit der Bezeichnung "freier Wegpunkt" und den Koordinaten des Feldes in die Liste eingetragen. Ein Halt erfolgt nicht. Die Strecke bis zum nächsten Fahrplanhalt wird eingelesen, ein kurzes Abbremsen des Konvois ist möglich. Vermeide nach Möglichkeit die Platzierung von Wegpunkten in Kurven. Es wird zwar keine Störung verursacht, doch ordentliches Fahrverhalten kann nicht gewährleistet werden.
· Bis zu 254 Fahrplanhalte können je Fahrplan eingerichtet werden.

· Wenn du fertig bist, dann schließe einfach das Fahrplanfenster. Der Fahrzeugverband liest den Fahrplan neu ein und setzt die Reise zum dann als nächsten Halt markierten Punkt fort. Wird eine Linie als ganzes geändert, halten alle ihr zugewiesenen Fahrzeuge an, lesen den neuen Fahrplan ein und fahren weiter. Sind Zwischenhalte eingefügt worden, kann dies dazu führen, dass einige Konvois umkehren, da an derselben Position ihres Fahrplans nach der Änderung ein anderer Fahrplanhalt steht.

simutrans-124.3/simutrans/text/de/server.txt000066400000000000000000000023371474050137200212300ustar00rootroot00000000000000Kurzinformation / Netzwerkspiele

Kurzinformation / Netzwerkspiele

Hier wird kompakt über einen Spielstand informiert. Neben einer kleinen Karte wird das Datum, die Kartengröße und die Zahl der Städte, Fabriken, Bewohner, Fahrzeuge usw. angezeigt.

Falls das aktuelle Spiel kein Netzwerkspiel ist, kann man aus einer Liste oben Server auswählen, deren Programmversion und Pakset zu dem gerade Laufendem passt. Ist die Liste leer, gibt es gerade keinen passenden Server. Dann kann man sich durch Alle zeigen alle Server anzeigen lassen.

Nach dem Auswählen eines Server wird dieser angefragt. Läuft der Server gerade nicht, kann dies einen Moment dauern bis eine Fehlermeldung erscheint und der Eintrag rot unterlegt wird. Im Regelfall wird der Server aber mit seinen Kurzinformationen antworten. (s.o.)

Stimmen Programmversion und Pakset überein, dann sind diese Einträge schwarz. Mittels Online spielen tritt man dem Server bei und kann dann mitspielen. Ist dagegen der Pakset-Eintrag rot, dann sind in deinem Pakset Dateien zuviel, unterschiedlich oder fehlen. In diesem Fall kann man sich mit Abweichende Paks die Abweichung anzeigen lassen.

simutrans-124.3/simutrans/text/de/settings.txt000066400000000000000000000034411474050137200215570ustar00rootroot00000000000000Erweiterte Einstellungen

Erweiterte Einstellungen

In den erweiterten Einstellungen können alle Parameter verändert werden, die auch dauerhaft per in der Konfigurationsdatei (simuconf.tab) gespeichert sind. Der Name des jeweiligen Parameter ist identisch mit dem in der Konfigurationsdatei.

Achtung! Wenn die Bedeutung eines Parameters nicht bekannt ist, dann sollte dieser nicht verändert werden. Einige Parameterkombinationen können Simutrans unspielbar machen oder zu Abstürzen führen.

Die Parameter können mittels simuconf.tab auf die Standardwerte zurückgesetzt werden. Mittels Default.sve wird der Stand des letzten gestarteteten Spiels wieder geladen.

Es gibt dabei vier Unterkategorien:

· Allgemeines:
Einstellungen zur Anzeige und zum Zeitablauf. Nützlich dürfte insbesondere autosave sein, welches den Abstand zwischen automatisch gespeicherten Spielständen in Monaten angibt.

· Wirtschaft & Städte:
Hier befinden sich alle Einstellungen für das Wirtschaftsystem und das Wachstum von Städten.

· Verbindungen:
Hier können die Einstellungen für Waren- und Passagierverbindungen, sowei für den Wegebau eingestellt werden.

· Kosten:
Diese Seite enthält alle Kosten, die in Simutrans nicht durch pak-Dateien vorgegeben sind. Dies sind vor allem Instandhaltungs- und Wartungskosten sowie Kosten für Aufschüttungen.

Die komplette Beschreibung aller Einstellungen findet sich in der Konfigurationsdatei simuconf.tab in Verzeichnis config im Programmverzeichnis.

Die meisten Parameteränderungen nur vor dem Start eines Spieles möglich. Einige können auch durch Speichern und erneutes Laden aktiviert werden.

simutrans-124.3/simutrans/text/de/shiptools.txt000066400000000000000000000047341474050137200217510ustar00rootroot00000000000000Häfen und Werften

Häfen und Werften

Diese Werkzeugleiste dient dem Bau von Kanälen, Hafenanlagen und Werften. Bei der Auswahl eines Werkzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Kanäle erlauben es Schiffen, ins Binnenland vorzudringen. Simutrans benutzt nur leere Felder oder bereits vorhandene Kanalstücke. Am Hang kann nur in Neigungsrichtung gebaut werden, Schleusengrafiken werden automatisch erstellt.
Beim ersten Platzieren des Kanalbauwerkzeuges in der Weltkarte wird der Anfang der Strecke festgelegt, beim zweiten der Endpunkt. Das Spiel baut zwischen beiden Punkten die kürzestmögliche Strecke. Wenn keine Verbindung gefunden wird, passiert nach dem Anklicken des Endpunktes nichts. Eine Bauaktion lässt sich mittels z gratis rückgängig machen (ohne Baukostenerstattung), solange nichts anderes gebaut wurde.

Hafenanlagen dienen als Schiffsanlegestellen. An Häfen werden Schiffe be- und entladen.

Hafenbau Binnenhäfen können auf geraden Kanalstücken, Meerhäfen nur an geraden Stränden gebaut werden. Plaziere zur Errichtung eines Meerhafens das Hafenbauwerkzeug auf einer Strandkachel. Zur Errichtung größerer Hafenanlagen ist es möglich, mehrere Häfen direkt aneinander zu bauen. In einigen Simutrans-Versionen stehen Dir mehrteilige Hafenanlagen zur verfügung, welche Du in beliebiger Anordnung platzieren kannst.

Fahrplanhalte Schiffe gehen im Wasser vor Anker. Bei Binnenhäfen ist der Haltepunkt im Kanal, Setze die Fahrplanhalte bei Meerhäfen nicht auf den Hafen, sondern auf Wasserfelder, die an den Hafen direkt angrenzen.

Haltestelle Weiteres zum Aufbau von Haltestellen ist detailiert in der Hilfe zum Haltestellenfenster beschrieben.

Werften dienen zum Bau von Schiffen. Die angebotenen Schiffstypen stehen Dir zum Kauf zur Verfügung. Richte Schifflinien ein, weise sie den georderten Schiffen zu, lasse die Schiffe auslaufen. Die verschiedenen Werfttypen unterscheiden sich lediglich in ihrer Ausrichtung. Platziere sie im freien Wasser, Es ist nicht möglich, eine Werft auf dem Strand oder in einem Kanal zu bauen. Auch weit draußen auf See kannst Du Werften errichten. Berücksichtige bei der Plazierung aber die Kartengrenzen. Deine Spielwelt ist immer von Wasser umgeben. Die Ränder stehen der Nutzung allerdings nicht zur Verfügung. Sie dienen dem gefälligen Kartenabschluss.

simutrans-124.3/simutrans/text/de/signal_spacing.txt000066400000000000000000000024101474050137200226730ustar00rootroot00000000000000Signalabstand festlegen

Hinweise zur Benutzung:


Strg+Mausklick auf ein Signalwerkzeug öffnet dieses Fenster.

Ähnlich wie beim Bauen von Schienen oder Straßen wird mit Klick-und-Ziehen auf der Strecke eine Vorschau der Signale gezeigt, ung gebaut, sobald die Maustaste losgelassen wird.

Die Durchfahrtsrichtung der Signale wird durch die Richtung vorgegeben, in die die Maus gezogen wurde. Stehen schon Signale in entgegengesetzter Richtung, dann wird gar kein Signal gebaut.


Einstellungen in diesem Fenster:

Signalabstand: Abstand in Kacheln, der zwischen den Signalen eingehalten wird. Diagonalen zählen als eine halbe Kachel. Dieser Wert wird auf dem Signal-Icon gezeigt, falls das entsprechende Werkzeug aktiv ist.

Signale an Zwischenstellen entfernen: Falls aktiviert, werden andere Signale, die auf dem Weg stehen, entfernt.

Andere Signale ersetzen: Falls aktiviert, werden andere Signale entfernt, die auf Stellen stehen, wo mit diesem Werkzeug ein Signal gesetzt werden würde.

Diese Einstellungen können für jedes Signal und Verkehrszeichen unabhängig gesetzt werden.

simutrans-124.3/simutrans/text/de/simutrans.txt000066400000000000000000000070501474050137200217440ustar00rootroot00000000000000Über Simutrans

Simutrans

Versetze Dich in die Situation eines jungen Transportunternehmers. Du startest mit einem geringen, jedoch ausreichenden Grundkapital. Wähle eine der 10'000 verfügbaren Simutrans-Karten oder lade eine Reliefkarte. Die gleiche Ausgangskarte wird sich bei mehrmaligem Laden immer wieder mit einem anderen Szenario generieren. Als Basis der Generierungen dienen Deine getroffenen Grundeinstellungen.

Beurteile die angetroffene Situation. Die Entwicklung der kleinen Welt liegt nun in Deiner Hand. Du kannst etwa den einen oder den anderen Industriezweig erschließen, also Fertigungsbetriebe mit den Produkten der vertragsverbundenen Rohstoffproduzenten beliefern. Baue die benötigten Transportverbindungen. Dir stehen Schiene, Straße und Schifffahrt als Verkehrsträger zur Verfügung. Natürlich können Passagiere und Güter zwischen Verkehrsträgern umsteigen bzw. umgeladen werden.

Der Vorteil der Strategie des anfänglichen Gütertransportes besteht darin, mit oft wenig Aufwand nach kurzer Zeit die Mittel für kostenträchtigere Vorhaben zur Verfügung zu haben. Der Nachteil soll nicht verschwiegen werden: Die Städte zeigen derzeit keinerlei Wachstum.

Eine andere Strategie besteht darin, vom Spielbeginn an das Wachstum der Städte anzuregen. Werden den Stadtbewohnern Beförderungsmöglichkeiten zur Verfügung gestellt, können sie nun ihre Reiselust ausleben. Doch jeder potentielle Reisende interessiert sich unabhängig von Deinen Linienangeboten für ein ganz bestimmtes Reiseziel. Versuche also, so viele Städte wie möglich zu erschließen, sorge für Verbindungen der Städte untereinander. Achte auch auf die Erschließung der öffentlichen Einrichtungen wie Vergnügungseinrichtungen, Ruinen und sagenumwobene Königschlösser. Viele Touristen werden zu den Sehenswürdigkeiten strömen, ohne die Mären und die Legenden, welche um die oft düsteren Gemäuer ranken, je zerstören zu können. Transportiere auch die anfallende Post der Einwohner.

Guter Service spricht sich rum. Je mehr Reisende mit deinem Service zufrieden waren und je mehr Post Du befördern konntest, desto zügiger werden die Städte wachsen. Neuer Wohnraum wird gebaut. Komplette Produktionsketten werden aus dem Boden schießen, als bestände die ganze Welt nur aus Maurern und Polieren. Die Betriebe handeln untereinander Abnahmeverträge aus. Für den expansionsbereiten Transportunternehmer und erfahrenen Logisten entwickeln sich ungeahnte Möglichkeiten.

Eine gute Wegeplanung wird Dich bei der optimalen Nutzung der Straßen- und Schienennetze unterstützen. Lass nicht mehr Fahrzeuge in einer Linie fahren, als Bedarf besteht. Knauser aber auch nicht. Vermeide nach Kräften Angebotsengpässe im Reiseverkehr. Ein zur Hälfte ausgelastetes Fahrzeug fährt immer noch profitabel.

Es besteht keine zeitliche Beschränkung. Spiele, bis Deine gesteckten Ziele auch wirklich erreicht sind. Du kannst mit bis zu 6 KI-Spielern im Kampf um Märkte und Transportaufträge wetteifern. Schnappe anderen Spielern Passagiere und Güter vor der Nase weg. Vielleicht magst Du auch ganz auf KI-Spieler verzichten? Die Entscheidungen liegen bei Dir. Doch verausgab Dich vor allem in der Frühphase Deines aufstrebenden Unternehmens nicht. Auch Transportunternehmern droht der Konkurs, wenn sie Schulden nicht fristgerecht tilgen können.

Das Simutrans-Team und die nach Kräften mitwirkende Community wünschen Dir viel Langzeitspaß und grauzellen-trainierende Knobelkuren bei der Erkundung und der Erschließung völlig individueller Welten.

simutrans-124.3/simutrans/text/de/slopetools.txt000066400000000000000000000025441474050137200221250ustar00rootroot00000000000000Aufschüttungen und Böschungen

Gelände verändern

Wenn eine Bahnlinie/Straße durch unwegsames Gelände geführt werden soll, empfehlen sich die Erdbewegungswerkzeuge. Sie können nur eingesetzt werden, wenn alle betroffenen Felder unbebaut sind.

Gelände anheben/absenken Der Cursor verwandelt sich in einen nach oben/unten zeigenden Pfeil. Mit dem Werkzeug wird das Gelände am Gitterpunkt unter dem Cursor angehoben/abgesenkt. Das Gitternetz (nur in der größten Kartenansicht) lässt sich mittels der Taste # ein- und ausschalten.

Rampen legenDie nächsten vier Werkzeuge legen Rampen in südlicher, nördlicher, westlicher und östlicher Richtung an. Mit einem fünften Tool werden Hangfelder eingeebnet. Über so bearbeitetes Gelände können dann normal Wege gebaut werden.

Beim Einsatz der Geländewerkzeuge können senkrechte Böschungen entstehen. Über diese Klippen können keine Wege gebaut werden, sie können aber Endpunkte Brücken sein.

Niveau absenken/anheben Senkt oder hebt das Grundniveau eines Feldes. Mit diesem Werkzeug kann man im Untergrundmodus Rampen erzeugen.
Achtung: Auf dem Kartenboden erzeugt Absenken auf das neue Niveau des Meeresspiegel einen Kanal.

Renaturierung Stellt den ursprünglichen Zustand wieder her.

simutrans-124.3/simutrans/text/de/sound.txt000066400000000000000000000022711474050137200210470ustar00rootroot00000000000000Sound- und Musikeinstellungen

Sound- & Musikeinstellungen

Zum Abspielen von Sounds und Musik muss die SDL-Version von Simutrans installiert sein. Unter Windows wird die sdl.dll benötigt. Sounds (WAV-Format) und Musikstücke (MIDI-Format) werden im Verzeichnis simutrans/sound abgelegt.
Wird Simutrans mit -nosound oder -nomidi gestartet, dann sind Sound bzw. Musik nicht benutztbar.
ACHTUNG: Insbesondere Musik funktioniert nur auf bestimmten Systemen.

Durch Verschieben der Regler nach links oder rechts kannst Du die Lautstärke der Musik und der Geräusche festlegen. Je weiter rechts die Regler stehen, desto lauter erfolgt die Ausgabe.

Klanglautstärke: Lautstärke der Klänge im Spiel. Die Klänge können, mit dem Knopf Klänge aus, ganz ausgeschalten werden.
Musiklautstärke: Lautstärke der Musik im Spiel. Die Musik kann, mit dem Knopf Musik aus, ganz ausgeschlaten werden.

Das Musikstück, das gespielt werden soll, kannst Du mit den Pfeilknöpfen auswählen, sofern Musik verfügbar ist.

Wenn die Zufallsauswahl aktiviert ist werden die Musikstücke in zufälliger Reihenfolge abgespielt.

simutrans-124.3/simutrans/text/de/special.txt000066400000000000000000000160461474050137200213440ustar00rootroot00000000000000Spezialbauwerkzeuge

Spezialbauwerkzeuge

In dieser Werkzeugleiste sind Bauwerkzeuge zusammengefasst, die nicht direkt mit den Transportnetzen zu tun haben. Bei der Auswahl eines Wergzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Nebengebäude Für die Gestaltung der Haltestellen stehen Dir verschiedene Nebengebäude zur Verfügung. Platziere sie entsprechend Deinen kreativen Vorstellungen direkt neben beliebige Haltestellenobjekte. Mit ihnen kannst Du auch flächige Haltestellenverbünde erreichen. Sie erweitern das Einzugsgebiet und das Fassungsvermögen der Haltestelle. Die meisten Nebengebäude bringen Haltestellen auch dazu, Passagiere, Post oder Güter umzuschlagen, besonders seien die Postgebäude erwähnt. Einige Nebengebäude sind auch in den anderen Bauwerkzeugen zu finden, unterscheiden sich aber in ihrer Funktion nicht von denen in diesem Menü.

Spielerwechsel Bei der Betätigung der Schaltfläche P+ oder der Tastenkombination Shift+P wechselst Du zunächst zum Spieler "öffentliche Hand". Das Menü Karteneditor wird geöffnet. Beim Weiterschalten gelangst Du nacheinander zu den KI-Spielern, danach wieder zum menschlichen Spieler. Hattest Du das Menü des Karteneditors geöffnet gelassen, kannst Du es nun auch als Spieler nutzen. Du erhältst weitreichende Gestaltungsmöglichkeiten des Spiels. Kreative Aspekte werden Dich mit etwas Übung sehr interessante Aufgabenstellungen finden und verwirklichen lassen.

Stadtgründungswerkzeug Wo immer auf der Karte Du das Werkzeug platzierst, wird eine neue Stadt entstehen. Doch Vorsicht, von Deinem Kassenbestand werden ohne Vorwarnung 5.000.000 Credits abgezogen.

Aufforstwerkzeug Während Rodungsarbeiten mit Unkosten verbunden sind, stellt Dir Simutrans Setzlinge für Aufforstungen gratis zur Verfügung. Die Landschaftsverschönerung kann eine reizvolle Aufgabe sein. Ökologische Aspekte sind derzeit aber nicht im Spiel implementiert.

Stromnetz Einige der Produktionsstätten könnten ruhig mehr produzieren? Versorge sie mit Strom, und sie werden es tun. Platziere je ein Umspannwerk direkt angrenzend an ein Kraftwerk und dem Betrieb, den Du versorgen möchtest. An jedes Kraftwerk und jeden Betrieb kann nur ein Umspannwerk angeschloßene werden. Ein Kraftwerk kann aber mehrere Betriebe mit Strom versorgen. Durch die Verbindung der beiden Umspannwerke durch eine Überlandstromleitung wird der Betrieb mit Strom versorgt. Der Stromtransport stellt auch eine interessante Einnahmequelle dar. Solange Strom fließt, erhöht sich die Produktion jedes versorgten Betriebs. Ob eine Fabrik genug Strom erhält, sieht man im Spiel an einem roten Blitz auf dem Umspannwerk. Je nach Grafikset können Umspannwerke auch im Untergrund gebaut werden. Dazu muß man in den Untergrundmodus (mit U oder unter Anzeigeeinstellungen) wechseln und das Umspannwerk-Werkzueg ausgewählt haben. Dann erscheint unter den Betrieben eine rote Grundfläche auf der das Umspannwerk plaziert werden muß.



Überlandstromleitungen Baukosten werden in den blauen Tooltips angezeigt. Der Abriss kostet für Überlandstromleitungen genausoviel wie deren Bau.

Simutrans benutzt nur leere Felder bzw. bereits vorhandene Überlandstromleitungen. Brücken, Tunnel, Eisenbahnstrecken usw. werden nicht in die Bauaktion mit einbezogen. Allerdings werden automatisch Bahn- und Straßenübergänge gebaut. Am Hang kann nur in Neigungsrichtung gebaut werden.

Beim ersten Platzieren des Stromleitungswerkzeuges in der Weltkarte wird der Anfang der Strecke festgelegt, beim zweiten der Endpunkt. Das Spiel baut zwischen beiden Punkten die kürzestmögliche Strecke. Wenn keine Verbindung gefunden wird, passiert nach dem Anklicken des Endpunktes nichts. Eine Bauaktion lässt sich mittels z gratis rückgängig machen (ohne Baukostenerstattung), solange nichts anderes gebaut wurde.

Strombrücken beginnen immer an einem Stromleitungsenden. Für das Strombrückenende sucht Simutrans in der geraden Weiterführung des Stromleitungsendes ein vorhandenes Stromleitungsende, welches in die Richtung des Anfangspunktes weist. Wird eine passende Hanglage vorgefunden, so wird die Brücke an sie angelehnt. Die weiter führende Stromleitung kann in dem Fall auch nachträglich gebaut werden, muss aber bis auf die Brücke fortgebaut werden. Um eine Strombrücke an einem Hang beginnen zu lassen, die Stromleitung bis auf den Hang bauen und dann das Strombrückenbauwerkzeug benutzen. (In neueren Versionen kann eine Strombrücke auch an einer senkrechten Wand enden. Dazu sollte vorher dort schon eine Stromleitung gebaut worden sein.)

Stromtunnel / Untergrundstromleitungen können nur gerade und nur in einer Höhenebene gebaut werden. Als Startpunkt des Stromtunnels muss ein Stromleitungsende in einer Hanglage verbaut sein. Setze das Tunnelbauwerkzeug auf das Stromleitungsstück. Der Stromtunnel wird komplett gebaut, wenn Simutrans in der gegenüberliegneden Bergflanke eine gerade Hanglage vorfindet. Erhältst Du eine Hinweismeldung, war das gegenüberliegende Hangstück nicht gerade. Eine wichtige Bauhilfe stellt die Nutzung des Gitternetzes dar (in der größten Kartenansicht schaltet die Taste # es ein und aus); mit ihm lässt sich der Durchstoßpunkt besser finden.
Willst du nur ein Stromtunnelportal bauen, dann kannst du einen Ctrl (Strg)+Mausklick machen. Danach kann du dann in den Untergrundmodus wechseln (mit U oder unter Anzeigeeinstellungen) und mit dem Stromtunnelwerkzeug weitere Strecken bauen.

Marker Den Marker kannst Du für die Einrichtung von Gedächtnisstützen nutzen. Plaziere ihn auf einer beliebigen Kachel. Editiere das sich öffnende Textfeld, bestätige dann mit "OK". Bei wiederholter Plazierung des Markers auf dem gleichen Feld kannst Du dich auch für die Entfernung des Markers entscheiden.
Ein markiertes Feld geht in das Spielereigentum über. Es bleibt Dein Eigentum, auch wenn Du den Marker wieder entfernst. So ist es möglich, Felder vor der Bebauung zu schützen.

Haltepunkt verlegen: Mit diesem Tool können Sie einen Halt oder Wegpunkt in den Fahrplänen aller Linien und Einzelfahrzeugen, die diesen verwenden, verschieben. Der Haltepunkt ist die rot markierte Kachel, wenn der Fahrplan geöffnet ist. Der Fahrplan des Fahrzeugs oder der Linie darf jedoch nicht geöffnet sein, sonst wird diese nicht mit verschoben. Es kann damit die Haltestelle oder auch die geplante Kachel innerhalb einer Haltestelle geändert werden. (z. B. um alle Linien von einem Bahnsteig zu einem anderen Bahnsteig eines Bahnhofs zu verschieben). Klicken Sie nach Auswahl des Werkzeugs auf den Haltepunkt oder Bahnsteig, den Sie in den Linienplänen ersetzen möchten, und dann auf den Haltepunkt oder Teil einer Haltestelle, den Sie in Zukunft verwenden möchten. Die Fahrpläne werden sofort geändert, jedoch nicht die Fahrziele der Fahrzeuge die bereits unterwegs sind.

simutrans-124.3/simutrans/text/de/station.txt000066400000000000000000000215511474050137200214020ustar00rootroot00000000000000Haltestellen

Haltestellenfenster

Das Haltestellenfenster wird angezeigt, wenn Du mit dem Abfragewerkzeug (Lupe) auf ein Feld mit einer Haltestelle oder einem Erweiterungsgebäude klickst. Haltestellen sind Ausgangs-, Ziel- oder Umschlagplätze für Passagiere, Post und Güter. Hält ein Fahrzeug an einer Haltestelle, dann werden automatisch Passagiere, Post und Güter aus, um- bzw. eingladen. Haltestellen können aus einem oder mehreren Elementen wie Bahnhöfen, Bus- oder Tramhalten, Häfen, Flughäfen sowie Erweiterungsgebäuden bestehen.

Baust Du eine Bushaltestelle auf einer Straße, Hafen im Kanal oder an der Küste, Bahnhofshalle auf der Schiene oder ein Terminal für ein Flugzeug, so entsteht dort automatisch eine neue Haltestelle. Baust Du ein Element auf eine Kachel unmittelbar neben oder über eine bestehende Haltestelle (auch schräg über Eck) wird die bereits bestehende Haltestelle erweitert. Auf diese Weise können U-Bahn-Station, ebenerdiger Bahnhof, Hochbahn, Anlegestellen für Schiffe oder auch Flughafenterminals in einer einzigen Haltestelle vereinigt werden, an der Passagiere von einem Verkehrsmittel ins andere umsteigen können. Der Weg muss im Bereich der Haltestelle gerade, kreuzungsfrei und eben sein, darf aber auch auf Brücken, Hochstrecken oder in Tunnels liegen. Einige Elemente können zusätzliche Einschränkungen haben und zum Beispiel nur auf Wegenden gebaut werden.

An einer Haltestelle dürfen nur Fahrzeuge halten, die den gleichen Besitzer wie die Haltestelle haben. Eine Ausnahme sind Haltestellen, die der öffentlichen Hand gehören. Hier können alle Spieler halten und so gegenseitig Passagiere, Post und Güter austauschen.

Auf der rechten Seite des Haltestellenfensters siehst Du ein Bild der Haltestelle. Klicke darauf, um das Hauptfenster auf die Haltestelle zu zentrieren.

Jede Haltestelle hat drei wesentliche Eigenschaften: Kapazität, Einzugsgebiet und Akzeptanz. Neben den Halten gibt es Erweiterungsgebäude die die Kapazität der Haltestelle erhöhen, das Einzugsgebiet vergrößern, und/oder den Umschlag weiterer Kategorien (Passagiere, Post, Güter) ermöglichen.

Haltestellen haben ein begrenztes Einzugsgebiet. Du kannst es mittels v oder unter Anzeigeeinstellungen ein- oder ausblenden. Passagiere, Post und Güter werden nur für Ziele innerhalb dieses Gebietes angenommen. Sehenswürdigkeiten müssen über ihre ganze Baufläche von Haltestellen erschlossen sein, sonst wird ein Teil der Passagiere, die einen Ausflug dorthin planen, unzufrieden. (s.u.)

Der Name einer Haltestelle kann in dem Feld oben direkt geändert werden. Jede Änderung erscheint sofort auf der Karte. Unter dem Namensfeld befindet sich eine Reihe von Icons. Links ist der Statusbalken (s. u.). Die Icons daneben zeigen Dir, welche Kategorien (Passagiere, Post, Güter) die Station akzeptiert. Damit eine dieser drei Kategorien akzeptiert wird, muss mindestens ein Element der Haltestelle diese akzeptieren. Welche Akzeptanz ein Haltestellenelement ermöglicht, kannst Du an den Symbolen auf den Icons in den entsprechenden Baumenüs erkennen. Die folgenden Symbole zeigen an, welche Verkehrsmittel (Straßenfahrzeug, Zug, Schiff, etc.) die Haltestelle anfahren.

Rechts davon steht die Lagerkapazität für Passagiere, Post und Fracht. Sind an einer Station mehr Einheiten eines Gutes vorhanden als die Kapazität, werden keine neuen mehr angenommen, die Haltestelle ist überfüllt. Die Kapazität steigt mit jedem Element, das an die Haltestelle angebaut wird. Welche Kapazität ein bestimmtes Element hat, wird in den Baumenus angezeigt. Die Auslastung der Haltestelle zeigt der Statusbalken ganz links an (derselbe, der auch auf der Karte über dem Namen steht). Er hat folgende Bedeutung:
- Grün: Bei der Haltestelle ist alles in Ordnung.
- Gelb: Die Haltestelle ist nicht erschlossen (kein Fahrzeug kam vorbei, nichts wartet).
- Orange: Die Haltestelle ist mäßig überfüllt.
- Rot: Die Haltestelle ist völlig überfüllt (mehr als 200 Einheiten über Limit) oder mehr als 200 Passagiere/Post haben ihre Reise wegen Überfüllung nicht angetreten oder eine Fabrik konnte ihre Waren nicht loswerden und musste deswegen die Produktion einstellen. In der Mailbox kannst Du einrichten, ob und wie Simutrans Dich jeweils am Monatsersten über solche Haltestellen informieren soll.

Akzeptiert eine Haltestelle Passagiere oder Post, stehen unterhalb der Symbole weitere Informationen. Das zufriedene Gesicht () gibt an, wieviel Passagiere/Post von dieser Haltestelle aus ihre geplante Reise angetreten haben. Das unzufriedenen Gesicht () zählt die Passagiere/Post, die wegen Überfüllung ihre Reisepläne fallengelassen haben. ohne Route zählt die, die keine Verbindung zu ihrem Ziel gefunden und die Reise somit nicht angetreten haben. Es gibt mehrere mögliche Ursachen:
- Das Reiseziel liegt nicht im Einzugsbereich einer Haltestelle, oder diese nimmt keine Passagiere/Post an;
- Es besteht keine Verbindung zum Ziel;
- Es wären mehr Umstiege notwendig, um das Ziel zu erreichen, als sich die Passagiere gefallen lassen. Die maximale Zahl der Umstiege, die für die Passagiere (und auch Güter) zumutbar ist, ist in der Variablen max_transfers in der Datei simutrans/config/simuconf.tab festgelegt.

Je mehr zufriedene Passagiere pro Monat befördert wurden, umso schneller werden die Städte auf der Karte wachsen. Für weitere Information siehe Stadtinformation.

Im unteren Bereich des Haltestellenfensters befindet sich die Passagier- und Warenliste. Hier sind sämtliche Passagiere und Güter aufgelistet, die an der Haltestelle auf den Weitertransport warten.
Zuerst wird die Gesammtmenge der Ware angezeigt, z.B.

·83 Passagiere warten

Diese wird dann weiter aufgeschlüsselt nach den einzelnen Zielen. Ist zum Erreichen des Ziels einer oder mehrere Umstiege notwendig, wird die nächste Umsteigehaltestelle angehängt.

··27 Passagiere > Berlin Mitte H über Berlin Hauptbahnhof
··11 Passagiere > Stuttgart Bahnhof

Es gibt verschiedene Arten der Auflistung und Sortierung. Du kannst sie über die linke der drei Schaltflächen oberhalb der Liste ändern. Die Einstellung wird gespeichert und für alle anderen Haltestellenfenster übernommen.
via:
Die Liste wird nach den ersten Transferhaltestellen alphabetisch sortiert.
via Menge:
Die Aufschlüsselung erfolgt nach der ersten Transferhaltestelle. Die Liste wird nach der Menge sortiert.
Menge:
Die Listensortierung erfolgt nach der Menge der Passagiere/Güterarten, die das gleiche Ziel haben.
Zielort:
Die Einträge werden alphabetisch nach Zielorten sortiert.

Die Schaltfläche Details öffnet das Fenster Haltestellendetails. Dort findest Du zusätzliche Informationen über die Haltestelle.

Über die Schaltfläche Statistik kannst Du einen grafischen Statistikbereich ein- und ausblenden. Die Statistik zeigt die Entwicklung einiger Werte über die letzten 12 Monate. Über die Schaltflächen unter der Statistik lassen sich die entsprechenden Werte ein- und ausblenden.
Zufrieden / Unzufrieden / Keine Route:
Alle zufriedenen / unzufriedenen Passagiere, bzw. Passagiere, die keine Route gefunden haben.
Angekommen / Abgefahren:
Alle angekommenen / abgefahrenen Passagiere und Güter, unabhängig davon, ob die Haltestelle das Endziel oder Umsteigepunkt war.
Wartend:
Die Gesammtzahl aller wartenden Passagiere und Güter.
Fahrzeuge:
Die Zahl aller Fahrzeuge, welche die Haltestelle angefahren haben.



Über einer Haltestelle in der Welt befinden sich mehrere Anzeigeelemente. Unter Anzeigeeinstellungen oder durch mehrmalige Betätigung von ! kannst Du die einzelnen Elemente ein- oder ausblenden.

Der Name der Haltestelle steht in einem Kasten in der Farbe des Spielers, dem sie gehört. Er kann im Haltestellenfenster geändert werden.

Über dem Haltestellennamen befindet sich ein waagrechter Statusbalken. Hier kannst Du den Status der Haltestelle erkennen (s.o).

Über dem Statusbalken befinden sich senkrechte Farbsäulen. Jede Säule steht für eine bestimmte Ware. Die Farben der Säulen entsprechen jenen der Farbquadrate in der Warenliste. Je höher die Säule, desto mehr Einheiten dieser Ware warten auf den Weitertransport. Befindet sich ein kleiner weißer Pfeil über der Säule, warten mehr Einheiten des Gutes als die Haltestelle aufnehmen kann. Es werden nur Säulen von Waren (bzw. Warengruppen) angezeigt, die auch tatsächlich umgeschlagen werden.

simutrans-124.3/simutrans/text/de/station_details.txt000066400000000000000000000023621474050137200231060ustar00rootroot00000000000000Haltestellendetails

Haltestellen Detailinformation

Angeschlossene Fabriken: Alle im Einzugsgebiet der Haltestelle befindlichen Fabriken werden alphabetisch gelistet. Die Einzugsgebiete kannst Du mittels der Taste v anzeigen lassen.

Angenommene Waren: Alle Warenarten, welche von an die Haltestelle angeschlossenen Fabriken benötigt werden, sind alphabetisch gelistet.

Linien, die diese Haltestelle anfahren: Alle Linien, welche die Haltestelle anfahren, sind alphanumerisch gelistet. Ein Klick auf den Pfeil öffnet die Linienverwaltung.

Einzelfahrzeuge, die hier halten: Alle Fahrzeuge, die keiner Linie zugeordnet sind, aber die Haltestelle anfahren, sind alphanumerisch gelistet. Ein Klick auf den Pfeil öffnet das Fahrzeugfenster.

Verkehrsverbindungen (direkt): Alle Haltestellen sind gelistet, welche direkt über Linien von der Haltestelle aus angefahren werden. Dem Namen der Haltestelle folgt jeweils in einer weiteren Zeile nach einem Bindestrich die Beförderungsart. Über den Pfeil vor dem Haltestellennamen kannst du direkt zu dieser Haltestelle springen.

simutrans-124.3/simutrans/text/de/trafficlight_info.txt000066400000000000000000000007041474050137200233770ustar00rootroot00000000000000Ampelphasen einstellen

Ampelphasen einstellen

Mit diesem Dialog werden die Ampelphasen eingestellt. Dabei gibt es zwei Richtungen: Nord-Süd (erstes Feld) und Ost-West (zweites Feld). Da alle Ampel auf der Karte synchron schalten, kann man im dritten Feld eine Verschiebung angeben, um eine grüne Welle zu realisieren.

Ampeln gibt es in den Straßenbauwerkzeugen.

simutrans-124.3/simutrans/text/de/tramtools.txt000066400000000000000000000024041474050137200217410ustar00rootroot00000000000000Straßenbahnbau

Straßenbahnbauwerkzeuge

Diese Werkzeugleiste dient dem Bau von Straßenbahngleisen, Fahrleitungen, Depots und Haltestellen. Bei der Auswahl eines Werkzeuges verwandelt sich der Cursor in das jeweilige Symbol.

Straßenbahnschienen: Der Bau von Schienennetzen ist in der Hilfe zu den Eisenbahnbauwerkzeugen beschrieben. Straßenbahngleise können auch auf Straßen und durch Straßentunnel und über Straßenbrücken gebaut werden. (Falls das Verlegen durch Tunnel/über Brücken nicht klappt, hilft evt. beim Bauen die Ctrl-Taste gedrückt zu halten.) Die Benutzung von Eisenbahngleisen neben Straßen ist möglich.

Fahrleitungen und Signale: Entsprechen denen in den Eisenbahnbauwerkzeugen.

Im Depot kannst Du Straßenbahnen zusammenstellen sowie Linien einrichten und die Fahrzeuge nach der Zuordnung von Linien starten. Das Depot kann nur auf einem ebenen Gleisende platziert werden.

Straßenbahnhaltestellen: Der Bau von Haltestellen ist in der Hilfe zum Haltestellenfenster beschrieben. Auf Straßen ist die Bushaltestelle zu verwenden, neben Straßen benutzt Du die Bahnhöfe.

simutrans-124.3/simutrans/text/de/underground.txt000066400000000000000000000050531474050137200222540ustar00rootroot00000000000000Bauen im Untergrund

Bauen im Untergrund

Es gibt 2 mögliche Untergrundansichten.
vollständige Untergrundansicht
Mit U schaltest Du in die vollständige Untergrundansicht. In dieser Ansicht werden alle Oberflächenobjekte ausgeblendet.
Untergrundansicht als Ebene
Mit Strg + U schaltest Du in die Untergrundansicht mit Ebenen. In dieser Ansicht werden alle Objekte ausgeblendet, die sich über der ausgewählten Ebene befinden. Das sind alle Oberflächenobjekte und auch alle Objekte im Untergrund, die sich oberhalb der ausgewählten Ebene befinden.

Der Ebenenwechsel erfolgt mit + (höher) und - (tiefer) oder über die Anzeigeeinstellungen.

Mauszeiger (Cursor)
volle Untergrundansicht
Bei der vollen Untergrundansicht wird das Raster der Oberfläche angezeigt. Bei unbebauten Feldern possitioniert sich der Mauszeiger an diesem Raster. Bei bebauten Feldern possitionirt sich der Mauszeiger auf die bebauten Felder.
Da das Possitionieren des Mauszeigers über das Oberflächenraster recht schwierig ist, sollte beim bauen im Untergrund die Ebenenansicht verwendet werden.

Untergrundansicht als Ebene
Bei der Ebenenansicht wird ein Raster auf der aktiven Ebene eingeblendet. Der Mauszeiger possitioniert sich an diesem Raster. Da sich der Mauszeiger immer in der aktiven Ebene befindet, ist das Bauen sehr viel leichter.

Streckenbau

allgemein


Im allgemeinen werden Strecken im Untergrund mit den Bauwerkzeugen für Tunnel gebaut. Um im Untergrund bauen zu können, muss ein Tunnel oder ein Tunneleingang (Taste Strg + Klick mit Tunnelwerkzeug auf Hangfeld) gebaut werden.

Ebenenwechsel
Um die Ebene im Untergrund zu wechseln, sind die Werkzeuge Niveau absenken/anheben aus dem Menü Geländewerkzeuge zu verwenden. Um die Ebene zu wechseln, einfach mit dem entsprechenden Werkzeug auf das Streckenende klicken.

Sonderfall Straßenbahn


Straßenbahnschienen werden auch im Untergrund mit den normalen Schienenwerkzeugen auf die Straße gebaut.

Stationen und Nebengebäude
Nur eigene Stationen können übereinander gebaut werden.

Nebengebäude können nicht im Untergrund gebaut werden.

Signale
Können verwendet werden wie an der Oberfläche.

simutrans-124.3/simutrans/text/de/vehiclelist.txt000066400000000000000000000013551474050137200222340ustar00rootroot00000000000000Liste aller Fahrzeuge

Auflistung aller im Spiel vorhanden Fahrzeugtypen

Standardmäßig werden alle derzeit aktuellen und zukünftig noch kommenden Fahrzeuge gezeigt. Das zeigen der Zukünftigen ist auch der eigentliche Sinn dieser Liste. In den Depots sind die kommenden Fahrzeuge nicht einsehbar. Der Spieler kann damit besser für die Zukunft planen.

Auch zukünftige zeigen Durch Abwahl, kann die Liste eingegrenzt werden, auf die derzeit kaufbaren Fahrzeuge.
Auch veraltete zeigen erweitert die Liste um die bereits veralteten Fahrzeuge. Diese Funktion ist gleich der in den Depots.
Dahinter bei Alle kann auf die Warenart sowie Passagiere oder Post eingeschränkt werden.

simutrans-124.3/simutrans/text/de/window.txt000066400000000000000000000103071474050137200212250ustar00rootroot00000000000000Spielsteuerung

Spielsteuerung

Allgemeines
Simutrans lässt sich über die Maus und teilweise auch über die Tastatur steuern; die Tastaturbelegung ist über den gleichnamigen Menüpunkt im Hilfemenü (Taste F1) verfügbar und erscheint auch jedesmal, wenn eine Taste ohne Funktion gedrückt wird (z. B. 5).
Die Tasten sind in der Hilfe weiß hervorgehoben. Achtung es wird zwischen Groß- und Kleinschreibung unterschieden.

Auswahlen und Platzierungen
Die Nutzung der Schaltflächen und Objektauswahlen sowie Objektplazierungen im Spiel erfolgen über Klicken mit der linken Maustaste. In der Hilfe werden die Begriffe "auswählen" und "platzieren" bzw. Begriffe mit vergleichbarem Sinn benutzt.

Bewegen der Spielkarte
· Halte die rechte Maustaste gedrückt und verschiebe die Karte in beliebiger Richtung zu Deiner Wunschposition. In der Grundeinstellung verschiebt sich die Karte entgegen der Mausbewegung. Du kannst das Verhalten über die Einstellungen ändern.
· Die Karte lässt sich auch über die Tastatur (Ziffern auf dem Nummernblock) bewegen.
· Du hast auch die Möglichkeit, den gewünschten Kartenausschnitt durch Anwahl des entsprechenden Punktes auf der Reliefkarte direkt anzuspringen.

Ändern der Kartenansicht (zoomen)
Die Ansicht der Karte lässt sich in 4 Größenstufen darstellen. Verfügt Deine Maus über ein Mausrad, kannst Du die Größenstufe durch drehen des Mausrades einstellen. Mit den Tasten Page Up und Page Down erreichst Du den gleichen Effekt.

Spielgeschwindigkeit
Die in der Statusleiste angezeigte Spielgeschwindigkeit (T=1.00) entspricht der Standardgeschwindigkeit. Alle Aktivitäten im Spiel laufen wirklichkeitskonform.

Mitunter mag Dir eine höhere Geschwindigkeit sinnvoll erscheinen, vor allem, wenn der Kassenbestand knapp wird und Du auf Belieferung und das Kassieren der Frachten wartest. Ändere die Geschwindigkeit bei Bedarf mit den Tasten . (schneller) und , (langsamer). Einiges an Tempo wird das Spiel problemlos umsetzen. Bei Geschwindigkeiten, die die Leistung Deines Computers überschreiten, sind Unregelmäßigkeiten im Spielablauf, wie etwa in den Bahnhöfen stehenbleibende Züge, zu geringe Passagiererzeugung oder fehlerhafte Beladung bis hin zum Einfrieren des Spiels, nicht ausgeschlossen. Bei denAnzeigeeinstellungen befinden sich diesbezügliche Kontrollmöglichkeiten. Ein automatischer schneller Vorlauf lässt sich über die Taste W oder das Vorlaufsymbol in der Hauptenüleiste ein- und ausschalten.

Einstellung der Helligkeit
Zur Regulierung der Helligkeit siehe Anzeigeeinstellungen.

Editieren von Namen
Die Namensfelder in einigen Fenstern, wie Haltestellen-, Fahrzeug- und Liniennamen, sind editierbar. Sie sind von der Fensteroberfläche zurückgesetzt und zeigen glatte Beschriftungsflächen. Zum editieren, klicke mit der Maus in das Namensfeld. Bearbeite nun den Text. Editierungen werden unmittelbar wirksam. Drücke zum Verlassen des Feldes die Taste RETURN.

Pfeilschalter
In vielen Fenstern findest Du Wertangaben zwischen zwei Pfeilschaltern. Mit einem Klick auf den linken Schalter verringerst Du den Wert, mit einem Klick auf den rechten erhöhst Du den Wert. Halte die linke Maustaste gedrückt, wenn Du größere Wertebereiche durchlaufen möchtest.

Auswahlmenüs
Linienauswahlmenüs in den Depotfenstern und in den Fahrplanfenstern sind wie die Namensfelder zurückgesetzt und zusätzlich mit Pfeilschaltern versehen. Wenn Du auf eine Menüfläche klickst, wird das Auswahlmenü geöffnet. Wählst Du einen Eintrag aus, springt er in die Anzeigezeile und stellt nun die neue Auswahl dar. Die Zeile kann auch editiert werden, aus eigener Erfahrung rät der Autor, Editierungen bevorzugt in speziell dafür vorgesehenen Fenstern vorzunehmen.

Untergrund
siehe bauen im Untergrund

simutrans-124.3/simutrans/text/dk.tab000066400000000000000000000256161474050137200176640ustar00rootroot00000000000000§Dansk PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: dk Dansk # # Encoding: UTF-8 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable inaktivt cl_btn_filter_enable aktivt cl_btn_filter_settings indstil filter cl_btn_sort_asc stigende cl_btn_sort_desc faldende cl_btn_sort_income indtægt cl_btn_sort_name navn cl_btn_sort_type type clf_btn_alle alle clf_btn_invers inv. clf_btn_keine ingen hl_btn_filter_disable inaktivt hl_btn_filter_enable aktivt hl_btn_filter_settings indstil filter hl_btn_sort_asc stigende hl_btn_sort_desc faldende hl_btn_sort_name navn hl_btn_sort_type type hl_btn_sort_waiting varelager hlf_btn_alle alle hlf_btn_invers inv. hlf_btn_keine ingen #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Das Feld gehoert\neinem anderen Spieler\n Dette område\nejes allerede af\nen anden spiller!\n Der Besitzer erlaubt das Entfernen nicht Ejeren tillader\nikke at\nfjerne dette.\n Diese Zusammenstellung kann nicht fahren!\n Denne sammensætning\nkan ikke køre!\n Hier kann kein\nSignal aufge-\nstellt werden!\n Her kan ikke\nbygges et jernbanesignal!\n Post muss neben\nHaltestelle\nliegen!\n Et postkontor skal\nplaceres nær ved\nrutemål/station!\n Schiffhalt muss im\nWasser liegen!\n Skibsrutemål\nskal placeres\ni vandet\nnær en havn!\n Zughalt muss auf\nSchiene liegen!\n Togrutemål\nskal placeres\npå jernbanespor!\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ RAILTOOLS Jernbaneanlæg ROADTOOLS Vejanlæg SHIPTOOLS Havneanlæg SLOPETOOLS Rampeanlæg #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ Remove vehicle from map. Use with care! Fjern køretøjet fra kortet. Forsigtig brug tilrådes! Screenshot\ngespeichert.\n Skærmbilledet\ner gemt.\n #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ \nCan't open heightfield file.\n \nKan ikke åbne relieffilen.\n \nHeightfield has wrong image type.\n \nRelieffelt har\nforkert format.\n %d convois %d køretøjer i listen %d Einzelfahrzeuge im Depot %d enkeltkøretøjer i depotet %s has entered a depot. %s er tilbage i depot. %s\nis crowded. %s er overfyldt. 1 convoi 1 køretøj i listen 1 Einzelfahrzeug im Depot 1 enkeltkøretøj i depotet 1LIGHT_CHOOSE Lysstyrke: 1WORLD_CHOOSE Indstillinger for ny verden: 2LIGHT_CHOOSE Farver: 2WORLD_CHOOSE Kortnummer: 3LIGHT_CHOOSE Scrolltempo: 4LIGHT_CHOOSE Omvendt scrollning 5LIGHT_CHOOSE Vis fodgængere 5WORLD_CHOOSE Antal byer: 6WORLD_CHOOSE Trafiktæthed: 8WORLD_CHOOSE Dag og nat indstilling Abfrage Inspektionsværktøj Abnehmer Aftagere Abriss Fjern/riv ned Absenken Sænk landniveau Add Stop Tilføj Angenommene Waren Modtager følgende varer Anhaenger_tab Anhængere Anheben Hæv landniveau Apply Line Tilknyt rute Arbeiter aus: Ansatte bosat i: Arrived Ankommet Assets Aktiver Bahndepot Togdepot Bankrott:\n\nDu bist bankrott.\n Bankerot:\n\nDu er bankerot.\n Baum Træ Baustelle Byggeplads Beenden Afslut BF station Blockstrecke ist\nbelegt\n Sporstrækningen er\noptaget af\net andet tog\n Boden Mark/land Bruecke Bro Bruecke muss an\neinfachem\nHang beginnen!\n Broer skal\nbegynde på\nskråninger!\n Build ship depot Byg skibsdepot Build signals Byg jernbanesignal Build train depot Byg togdepot Build truck depot Byg vejdepot Cancel Fortryd Capacity: %d%s %s\n Kapacitet: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapacitet: %s\n» %d (%d%%) Cash Kassebeholdning Chart Statistik City size Størrelse cl_title Køretøjsliste cl_txt_sort Sorteret efter: clf_chk_cars busser/lastbiler clf_chk_name_filter Filtrer på navn: clf_chk_noincome ingen indtægt clf_chk_noroute ingen rute clf_chk_noschedule ingen ruteplan clf_chk_ships skibe clf_chk_spezial_filter Specialfilter: clf_chk_trains tog clf_chk_type_filter Filtrer på type: clf_chk_waren Filtrer på varer: clf_title Køretøjsliste filter COLOR_CHOOSE\n Vælg venligst en\nfarve fra paletten:\n Construction_Btn Byggeudgifter convoi %d of %d Køretøj %d af %d Convois: %d\nProfit: %s Køretøjer: %d\nProfit: %s Convoys Konvojer Currently playing: Afspiller aktuelt: Del Stop Fjern Delete Line Slet rute Delete this file. Slet denne fil Denkmal Mindesmærke Departed Afgået Details Detaljer Direkt erreichbare Haltestellen Direkte ruter herfra Display settings Udseende Dock havn Durchsatz Max. Eigenbesitz\n Offentlig ejendom\n Ein %s\npasst hier nicht.\n En '%s'\npasser ikke her.\n Einstellungen aendern Ændr indstillinger Electrify track Byg el-master Erzeuge neue Karte.\n Vent et øjeblik.\nSkaber ny verden...\n\nDet kan tage lidt tid\nfor store kort.\n\n Es wird bereits\nein Fahrplan\neingegeben\n Der bliver allerede\nplanlagt en ruteplan.\nGør denne færdig først! Fabrikanschluss Forbundne industrier Fahrplan Ruteplan Fahrzeuge koennen so nicht entfernt werden Køretøjer kan ikke\nfjernes på denne måde.\n Fahrzeuge: Køretøj: Farbe Spillerfarve February Februar Fertig Færdig Filename Filnavn: Finanzen Finanser Found new city Byg en ny by Fracht fragt Free Capacity Fri kapacitet Full load Min. last: GAME PAUSED PAUSE Gebaeude Bygning Gewicht Vægt Gewinn Indtægt Goods list Vareoversigt Gross Profit Overskud H stoppested Happy Tilfredse Helligk. Udseende Hier warten/lagern: Ventende varer og passagerer: hl_title Rutemålsliste hl_txt_filter Filter: hl_txt_sort Sorteret efter: hlf_chk_anleger havn hlf_chk_bahnhof jernbanestation hlf_chk_bushalt busstoppested hlf_chk_frachthof lastplads hlf_chk_keine_verb ingen forbindelse hlf_chk_name_filter Filtrer på navn: hlf_chk_spezial_filter Specialfilter: hlf_chk_type_filter Filtrer på type: hlf_chk_waren_abgabe Producerer: hlf_chk_waren_annahme Forbruger: hlf_title Rutemålsliste filter Homeless Hjemløse Ins Stop Indføj Intro. date: Indførsel: January Januar July Juli June Juni Kann Spielstand\nnicht laden.\n Kan ikke finde\ndet angivne spil!\n Kann Spielstand\nnicht speichern.\n Kan ikke gemme\nspillet!\n keine ingen Keine Einzelfahrzeuge im Depot Ingen enkeltkøretøjer i depotet Lade Relief Indlæs reliefkort Laden Indlæs LANG_CHOOSE\n Vælg venligst dit\nforetrukne sprog:\n Last Year Sidste år leer tom Leistung Ydelse letzen Monat: diesen Monat: sidste måned: denne måned: Line rute Line Management Rute administration Lines serving this stop Rutemål for rute LKW_tab Køretøjer Lokomotive_tab Lokomotiver m3 m³ Maintenance Vedligeholdelse Map roughness Bjergstejlhed: March Marts Max. speed: Tophastighed: May Maj Meldung Meddelelse Menge Mængde Mountain height Kuperet terræn: Music playing disabled/not available Musik slået fra/ikke tilgængelig Music volume: Musik lydstyrke: Net Wealth Samlet formue Neue Karte Ny verden Neue Welt Skab ny verden new convoi New Line Ny rute New Vehicles Nye køretøjer no convois Ingen køretøjer i listen no goods waiting ingen ventende varer No Route Ingen rute Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Giv køretøjerne\nen ruteplan, før\ndu vælger "Start"\n Ok OK Operation Driftsomk. paletten paletter Passagiere passagerer Passagierrate passagerer Passagierziele Passager/post destinationer player 2 Trikky Transport player 3 Meyer Moving Co. Please choose vehicles first\n Vælg venligst et køretøj først\n Post post Power Strømstyrke q1 forår q2 sommer q3 efterår q4 vinter Random map Tilfældigt kort Reliefkarte Reliefkort Restwert: Salgsværdi: Revenue Indkomst sack sække Schienentunnel Byg jernbanetunnel Schiff_tab Skibe Schiffdepot Skibsdepot SEP_FRACTION , SEP_THOUSAND . Serves Line: Følger rute: Show/hide statistics Vis/skjul statistik Size (%d MB): Størrelse (%d MB): Sort waiting list by Sorter ventelisten efter Sound Lyd Sound settings Lydindstillinger Sound volume: Lydstyrke: special freight Specialgods Speichern Gem Spieler Spiller Spieler(mz) AI-spillerliste Spielstand wurde\ngeladen!\n \nSpillet er indlæst!\n Spielstand wurde\ngespeichert!\n \nSpillet er gemt!\n Sprache Sprog Stadtinformation Byinformation Starte Spiel Start Strassendepot Vejdepot Strassentunnel Byg vejtunnel Tage alt dage gammelt There are still vehicles\nstored in this depot!\n Der er stadig køretøjer\nparkeret i depotet!\n This Year Dette år tonnen t. Towns Byer Train Tog Tunnel muss an\neinfachem\nHang beginnen!\n Tunneler skal\nbegynde på\nskråninger!\n Unemployed Arbejdsløse Unhappy Utilfredse units/day enheder/dag Update Line Opdater rute Verbrauch Forbrug verkaufen Sælge Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Du har gæld!\n\nDu har %d måneder til\nat betale din gæld! voranstellen Sætte foran Waggon_tab Togvogne waiting Venter Water level Vand niveau: Wegpunkt rutemål Wert Værdi WRONGSAVE Inkompatibel spil-\nversion. Kan ikke indlæse\nfilen.\n Zielort Destination Zu nah am Kartenrand En havn skal\nbygges på\net lige kyststykke\n #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL by &2_CITY_SYLL borg &3_CITY_SYLL huse &4_CITY_SYLL bro &5_CITY_SYLL købing &6_CITY_SYLL skov &7_CITY_SYLL strup &8_CITY_SYLL dal &9_CITY_SYLL mose &A_CITY_SYLL kær %1_CITY_SYLL Frederiks %2_CITY_SYLL Christians %3_CITY_SYLL Mølle %4_CITY_SYLL Kirke %5_CITY_SYLL Bonde %6_CITY_SYLL Ravn %7_CITY_SYLL Ege %8_CITY_SYLL Gammel %9_CITY_SYLL Ny %A_CITY_SYLL Lille %B_CITY_SYLL Store 1center %s %s 1extern %s lokal %s 2center %s Central %s 2extern %s rand %s 3center %s Hoved %s 3extern %s provins %s 4center %s Midt %s 4extern %s omegns %s 5center %s Centrums%s Ucenter Alt-%s %s simutrans-124.3/simutrans/text/dk/000077500000000000000000000000001474050137200171625ustar00rootroot00000000000000simutrans-124.3/simutrans/text/dk/color.txt000066400000000000000000000007451474050137200210470ustar00rootroot00000000000000Farve vælger

Farve vælger

Udseende:
Dialogen består af en tekst med tilhørende farvepalette, hvor en farve vælges ved at venstreklikke på farven.

Beskrivelse:
Her kan du vælge din firmafarve. Firmafarven er den farve, som alle dine besiddelser såsom toge, bygninger etc. vil have. Bemærk venligst, at ikke alle objekter vil være "farvekodet". Det er et valg, der er overladt til den respektive designer.

simutrans-124.3/simutrans/text/dk/convoi.txt000066400000000000000000000040711474050137200212220ustar00rootroot00000000000000Køretøjsliste dialog

Køretøjsliste dialog

Beskrivelse:
Køretøjsliste dialogen giver et overblik over samtlige køretøjer (lastbiler, busser, hestevogne, toge og skibe) med mulighed for at sortere og/eller filtrere disse efter parametre såsom navn, indtægt og type.

Udseende:
Øverst i dialogen er overskrifterne: 'Sorteret efter:' og 'Filter:'.
Til 'Sorteret efter:' er knyttet to "tilstands-knapper", der som default indstilling henholdsvis har tilstandende 'navn' samt 'stigende'.
Til 'Filter:' er der knyttet en 'tilstands-knap' med default tilstanden 'inaktiv' samt en knap med titlen 'indstil filter'.
Resten af dialogen består af en liste indeholdende samtlige dine køretøjer. For alle køretøjer er angivet dets nummer, navn og fortjeneste.

Ved at venstreklikke på et køretøj i listen kan man få dets
køretøj dialog frem.

Køretøjerne i listen kan sorteres ved hjælp af "tilstandsknapperne" under 'Sorteret efter:' overskriften.
Knappen til venstre giver sorteringstypen og knappen til højre angiver, om denne sortering skal foretages 'stigende' eller 'faldende'.
De tre sorteringstyper er:

Navn - Sorterer køretøjerne efter navn. Enten alfabetisk eller omvendt alfabetisk alt efter indstillingen af knappen til venstre.

Indtægt - Sorterer køretøjerne efter størrelsen af køretøjets indtjening. Stigende eller faldende alt efter højre-knappens tilstand.

Type - Sorterer køretøjerne efter deres type, hvor rækkefølgen: biler, toge, skibe anses for stigende.

For at lette overblikket af listen kan køretøjerne filtreres efter forskellige kriterier. Dette sker ved hjælp af knapperne under 'Filter:' overskriften.
Knappen til venstre er en "tilstands-knap". Denne knap kontrollerer filteranvendeksen med tilstandene 'inaktivt' og 'aktivt'. Knappen til højre med teksten 'indstil filter'
Ã¥bner forfilter dialogen

simutrans-124.3/simutrans/text/dk/convoi_filter.txt000066400000000000000000000046131474050137200225710ustar00rootroot00000000000000Køretøjsliste filter

Køretøjsliste filter dialog

Beskrivelse:
Denne filter dialog anvendes til at udvælge (filtrere) de køretøjer, som du ønsker at betragte i
Køretøjsliste dialogen

Udseende:
Til venstre findes tre filteroverskrifter, henholdsvis 'Filtrer på navn:', 'Filtrer på type:' og 'Specialfilter:'. Til højre for disse findes en liste med overskriften 'Filtrer på varer:'. Under denne overskrifter findes tre knapper med teksterne 'alle', 'ingen' og 'inv.'. Listen består af en trykknap for samtlige varetyper.

Samtlige fire overskrifter har en chechbox-knap tilknyttet.

Bemærk - For at få foretaget en filtrering med en eller flere af de fire filtrerings muligheder skal:
a) Chechbox-knappen til venstre for overskriften trykkes ned.
b) Tilstandsknappen under overskriften 'Filter:' i
Køretøjsliste dialogen sættes til 'aktivt'

De tre filtreringsmuligheder til venstre er:

Filtrer på navn:
Her er der mulighed for at udvælge køretøjer med et fælles navn. Dette gøres ved at skrive en del af eller hele det ønskede navn i listboksen under overskriften. F.eks vil en indtastning af 'Ben' give alle toge, hvis navn begynder med Bennhardt. Bemærk at søgningen er "case-sensitive"

Filtrer på type:
Her er der mulighed for at udvælge køretøjer efter deres type. De mulige typer er Busser/lastbiler, tog, og skibe.

Special filter:
Her er der mulighed for at udvælge køretøjer, der opfylder følgende:
- Ingen rute (ikke kan finde en forbindelse)
- Ingen ruteplan har (ikke har fået en ruteplan tilknyttet)
- Ingen indtægt (i indeværende år)

Listen til højre giver mulighed for at udvælge køretøjer udfra de varer, der transporteres på køretøjet. Bemærk at dette filter ikke er helt up-to-date, idet der for bulkgods og stykgodsvarer filtreres efter køretøjsbetegnelsen fremfor varetypen. Dvs. hvis der transporteres kul i en stenvogn, vil køretøjet fremgå under varetypen "sten" i stedet for "kul". De tre knapper under overskriften anvendes til at vælge henholdsvis alle eller ingen af de mulige varetyper samt til at foretage den "inverse" trykknap udvælgelse.

simutrans-124.3/simutrans/text/dk/convoiinfo.txt000066400000000000000000000024631474050137200221010ustar00rootroot00000000000000Køretøj dialog

Køretøj dialog

Beskrivelse:
For alle køretøjer (busser, lastbiler, toge og skibe) kan denne dialog åbnes ved at klikke på køretøjet. Dialogen giver nyttig information om køretøjet, dets forbindelser og dets aktuelle lastgrad.

Udseende:
Øverst i dialogen er køretøjets navn. Derefter følger en række oplysninger om køretøjet. Under disse oplysninger er en knap med teksten 'Statistik'. Herefter er et visningsareal, hvor oplysninger om den aktuelle last såsom mængde og destination fremgår.
Øverst til højre i dialogen er en knap med teksten 'Ruteplan' og herunder et billedudsnit med køretøjet. Ved at klikke på dette billedudsnit, vil køretøjet blive centreret på kortet. Sluttelig er der en slet-knap, der vil fjerne køretøjet uden at spørge først.

De to knapper har følgende funktion:

Statistik
Statistik knappen udvider dialogen med et grafisk visningsareal og en række trykknapper, der hver repræsenterer et køretøjsnøgletal. Ved at trykke på en knap bliver udviklingen af det ønskede nøgletal illustreret grafisk i visningsarealet.

Ruteplan
Denne knap åbner en køretøjets ruteplan dialog.

simutrans-124.3/simutrans/text/dk/depot.txt000066400000000000000000000125201474050137200210360ustar00rootroot00000000000000Depot

Depot Dialog

I det følgende benyttes betegnelsen "køretøj" som samlebetegnelse for såvel enkeltkøretøjer som sammensatte køretøjer, toge og skibe.

Beskrivelse:
I et depot har du mulighed for at købe, sælge og lave ruteplaner for diverse køretøjer alt efter depottype. F.eks vejkøretøjer og anhængere i et vejdepot, toge og togvogne i et togdepot samt skibe i et skibsdepot.
Depot dialogen indeholder information om de køretøjer, du er i færd med at købe samt de køretøjer, som du allerede har købt, men endnu ikke har startet.

Udseende:
Øverst er en liste, der indeholder alle de købte køretøjer, som endnu ikke er blevet sendt ud af depotet (har fået tildelt ruteplan og er blevet startet). Det aktuelle køretøj er vist og de andre køretøjer fås frem ved at benytte scroll-knapperne ved siden af listen
Herunder er en analog liste, der indeholder alle de ruter, der er defineret. Den aktuelle rute er vist og de øvrige ruter fås ved at benytte scroll-knapperne
Dernæst følger et areal, hvor et billede af det aktuelle køretøj er vist.
Herunder er fire knapper, der er tilknyttet køretøjslisten: 'Start' 'Ruteplan', 'Adskil' og 'Sælg'. Disse knapper giver mulighed for at starte, at lave ruteplan til, at adskille samt at sælge det aktuelle køretøj.
Derunder er fire knapper, der er tilknyttet rutelisten: 'Ny rute' 'Tilnyt rute', 'Opdater rute' og 'Slet rute'. Disse knapper giver mulighed for at oprette en ny rute, at tilknytte den aktuelle rute til det aktuelle køretøj, at opdatere samt at slette den aktuelle rute. Derunder er to faneblade der indeholder de køretøjer og anhængere (Lokomotiver/togvogne, skibe), der kan købes
Herunder er et areal, der bruges til visning af oplysninger for køretøjerne på fanebladene. For at se oplysningerne om et køretøj, skal musen holdes over det pågældende køretøj på fanebladet.
Til højre på visningsarealet er en tilstands-knap, der ved tryk skifter imellem tre tilstande, henholdsvis: 'koble på', 'sætte foran' og 'sælge'.

Køb køretøj:
For at købe et køretøj, må der ikke være valgt et aktuelt køretøj - køretøjslisten "klikkes fremad" indtil den viser 'vælg nyt køretøj'. Derefter købes køretøjet ved at venstreklikke på det i fanebladet. Køretøjet vil derefter være vist som det aktuelle køretøj i det øverste visningsareal. Ved at anvende tilstands-knappen nederst til højre er det muligt at se hvilke køretøjer/anhængere, der henholdsvis kan "sættes foran/kobles på" det købte køretøj (dette markeres ved grønne bjælker i fanebladet under de mulige køretøjer)
Når det aktuelle køretøj er færdigsammensat, kan det tildeles en ruteplan og startes, eller du kan købe og sammensætte et nyt køretøj ved at "klikke fremad" på køretøjslisten foroven i dialogen.

Start køretøj:
Efter tildeling af ruteplan kan det aktuelle køretøj startes ved at trykke på 'Start' knappen.

Tildel ruteplan:
For at tildele det aktuelle køretøj en "individuel "ruteplan trykkes på 'Ruteplan' knappen, hvorefter ruteplanen defineres vha. den fremkomne ruteplansdialog. Dette er kun fordelagtigt, hvis du ved, at køretøjet er det eneste, der vil benytte denne rute. Ifald du vil indsætte flere køretøjer på den samme rute, er det bedre først at definere ruten ved et trykke på 'Ny rute' og udfylde den fremkomne ruteplansdialog. Derefter figurerer ruten, som den aktuelle rute i rutelisten og kan tilknyttes det aktuelle køretøj ved at trykke på 'Tilknyt rute' knappen.

Adskil køretøj:
Det er muligt at adskille det aktuelle køretøj ved at trykke på 'Adskil' knappen. Køretøjet vil blive opdelt (f.eks i en lastbil og en anhænger) og derefter optræde som til rådighed stående enkeltkøretøjer på fanebladene. Disse enkeltkøretøjer kan benyttes til nye køretøjssammensætninger eller sælges ved at vælge "sælge-tilstanden" på tilstandsknappen nederst til højre og venstreklikke på enkeltkøretøjet i fanebladet.

Sælg køretøj:
For at sælge (hele) det aktuelle køretøj trykkes på 'Sælg' knappen.

Opret ny rute:
For at oprette en ny rute trykkes på 'Ny rute' knappen og derefter benyttes ruteplansdialogen.

Tilknyt rute til køretøj:
For at tilknytte en rute til et køretøj vælges køretøjet som det aktuelle køretøj i køretøjslisten. Dernæst vælges den ønskede rute i rutelisten (eventuelt oprettes den først som nævnt ovenfor) og herefter trykkes på 'Tilknyt rute' knappen.

Opdater eller slet rute:
For at opdatere eller slette en rute vælges den ønskede rute i rutelisten og herefter trykkes enten på Opdater rute' knappen, hvorefter ruteplansdialogen fremkommer eller på 'Slet rute' knappen, hvorefter ruten slettes fra rutelisten.

For senere at sende et køretøj tilbage i depotet, skal du indføje depotet i køretøjets ruteplan - f.eks som næste rutemål. Efter køretøjet er kommet tilbage i depotet figurerer det i køretøjslisten og kan efter behag udbygges, adskilles, tildeles rute eller sælges.

simutrans-124.3/simutrans/text/dk/display.txt000066400000000000000000000033661474050137200214000ustar00rootroot00000000000000Udseende dialog

Udseende dialog

Beskrivelse:
Udseende dialogen giver mulighed for at ændre diverser indstillinger vedrørende Simutrans' udseende.

Udseende:
Øverst i dialogen er tre lister med teksterne 'Lysstyrke:', 'Farver:' og 'Scrolltempo:'. Hver liste har "scroll-knapper" tilknyttet. Herunder er tre "checkbokse" med tilhørende tekster 'Omvendt scrollning', 'Vis fodgængere' og Dag og nat indstilling. Nederst er en række aktuelle belastningsoplysninger vist.

Følgende indstillinger er mulige:

Lysstyrke:
Gør kortet lysere eller mørkere.

Farver:
Ingen effekt

Scrolltempo:
Jo højere indstilling, desto hurtigere vil skærmenbilledet scrolle.

Omvendt scrollning
Her kan indstilles om kortet skal bevæge sig op eller ned, når der scrolles opad og analogt med hensyn til venstre og højre. (fly-lignende kontroller). Det er nemmere at afprøve, end at skulle forklare :-)

Vis fodgængere
Her kan indstilles om computeren skal skabe og vise fodgængere i byerne og omkring rutemål. Hvis din makine døjer med at opdatere skærmbilledet, så slå denne indstilling fra.

Dag og nat indstilling
Her indstilles om der alt efter tidspunktet skal skiftes imellem dag (lyst) og nat (mørkt) indstilling. Prøv det af !

Den nederste halvdel af dialogen indeholder information omkring hvorledes din computer klarer den aktuelle belastning. Disse værdier er ikke interessante med mindre du ved, hvad de står for.
VigtigtDu kan blive bedt om at nævne disse værdier, når du diskuterer performance problemer og andre bugs.

simutrans-124.3/simutrans/text/dk/finances.txt000066400000000000000000000045371474050137200215220ustar00rootroot00000000000000Finanser dialog hjælp

Finanser (f)

Beskrivelse:
Finanser dialogen viser dig såvel din aktuelle finansielle status som din status for sidste år. Dette giver dig indblik i din samlede profit eller tab !
Dialogen indeholder forskellige kategorier og viser den finansielle status for hver enkelt.

Udseende:
Øverst til venstre er for kategorierne: Byggeudgifter, Nye køretøjer, Driftsomkostninger, Vedligeholdelse, Indkomst og Overskud vist to kolonner med resultaterne for henholdsvis dette år og sidste år.
Herunder er to linier, der henholdvis viser Kassebeholdning og vedligeholdelsesudgifterne pr. måned.
Nederst i dialogen er et grafisk visningsareal, hvor en enkelt, flere eller alle kategorier kan afbildes grafisk. Dette gøres for hver enkelt kategori ved at vælge kategorien på knapperne øverst til højre i dialogen.

Kategorierne er følgende:

Byggeudgifter:
De samlede udgifter for alt du har bygget: Jernbaner, bygninger, veje, signaler, havne etc.

Nye køretøjer:
De samlede udgifter for alle køretøjer: Toge, togvogne, lastbiler/busser, anhængere eller skibe, som du har købt.

Driftsomkostninger:
De samlede kørselsomkostninger for alle dine køretøjer.
For hvert enkelt køretøj kan omkostninger pr. kørt km. ses under oplysningerne for køretøjet i depotdialogen.

Vedligeholdelse:
Det beløb du skal betale for at vedligeholde dine jernbaner/veje/bygninger.

Indkomst:
Den samlede indtjening for alle køretøjer.
Fortjenesten (indtjening - driftsomkostninger) for hvert enkelt køretøj kan ses i menuen: Køretøjsliste.

Overskud:
Det samlede overskud. Udregnes som summen af de ovennævnte kategorier.

Kassebeholdning:
Din kontante kassebeholdning.
Hvis dette beløb ved udgangen af en måned er negativt tre (3) gange i træk, er du bankerot og har "tabt" spillet.
Bemærk at vedligeholdelsesudgifter betales pr. måned ved udgangen af måneden

Aktiver:
Dette udregnes som den samlede salgsværdi af alle dine køretøjer.

Samlet formue:
Dette udregnes som summen af aktiver og kassebeholdning.

simutrans-124.3/simutrans/text/dk/haltlist.txt000066400000000000000000000043421474050137200215520ustar00rootroot00000000000000Rutemålsliste dialog

Rutemålsliste dialog

Beskrivelse:
Rutemålsliste dialogen giver et overblik over samtlige rutemål (lastepladser, jernbanestationer og busstoppesteder) med mulighed for at sortere og/eller filtrere disse efter parametre såsom type, varer og varelager.

Udseende:
Øverst i dialogen er overskrifterne: 'Sorteret efter:' og 'Filter:'.
Til 'Sorteret efter:' er knyttet to "tilstands-knapper", der som default indstilling henholdsvis har tilstandende 'navn' samt 'stigende'.
Til 'Filter:' er der knyttet en "tilstands-knap" med default tilstanden 'inaktiv' samt en knap med titlen 'indstil filter'.
Resten af dialogen består af en liste indeholdende samtlige dine rutemål. For alle rutemål er angivet dets nummer, navn, type (markeret ved et lastbil-, bus-, tog- eller skibssymbol) samt hvilket varelager, der afventer afhentning.

Ved at venstreklikke på et rutemål i listen kan man få dets rutemåls dialog frem.

Rutemålene i listen kan sorteres ved hjælp af "tilstandsknapperne" under 'Sorteret efter:' overskriften.
Knappen til venstre giver sorteringstypen og knappen til højre angiver, om denne sortering skal foretages 'stigende' eller 'faldende'.

De fire sorteringstyper er:

Navn
Sorterer rutemålene efter navn. Enten alfabetisk eller omvendt alfabetisk alt efter indstillingen af knappen til venstre.

Varelager
Sorterer rutemålene efter størrelsen af rutemålets varelager. Stigende eller faldende alt efter højre-knappens tilstand.

Type
Sorterer rutemålene efter deres type, hvor rækkefølgen: Biler, busser, toge, skibe anses for stigende.

Nummer
Sorterer rutemålene efter deres nummer.

For at lette overblikket af listen kan rutemålene filtreres efter forskellige kriterier. Dette sker ved hjælp af knapperne under 'Filter' overskriften.
Knappen til venstre er en "tilstands-knap". Denne knap kontrollerer filteranvendeksen med tilstandene 'inaktivt' og 'aktivt'. Knappen til højre med teksten 'indstil filter'
Ã¥bner forfilter dialogen

simutrans-124.3/simutrans/text/dk/haltlist_filter.txt000066400000000000000000000040441474050137200231160ustar00rootroot00000000000000Rutemålsliste filter dialog

Rutemålsliste filter dialog

Beskrivelse:
Denne filter dialog anvendes til at udvælge (filtrere) de rutemål, som du ønsker at betragte i
Rutemålsliste dialogen

Udseende:
Til venstre findes tre filteroverskrifter, henholdsvis 'Filtrer på navn:', 'Filtrer på type:' og 'Specialfilter:'. Til højre for disse findes to lister med overskrifterne 'Forbruger:' og 'Producerer:'. Under begge disse overskrifter findes tre knapper med teksterne 'alle', 'ingen' og 'inv.'. Listerne består af en trykknap for samtlige varetyper.

Samtlige fem overskrifter har en checkbox-knap tilknyttet.

Bemærk - For at få foretaget en filtrering med en eller flere af de fem filtrerings muligheder skal:
a) Checkbox-knappen til venstre for overskriften trykkes ned.
b) Tilstandsknappen under overskriften 'Filter:' i
Rutemålsliste dialogen sættes til 'aktivt'

De tre filtreringsmuligheder til venstre er:

Filtrer på navn:
Her er der mulighed for at udvælge rutemål med et fælles navn. Dette gøres ved at skrive en del af eller hele det ønskede navn i listboksen under overskriften. F.eks vil en indtastning af 'Gam' give alle rutemål, hvis navn begynder med Gammel. Bemærk at søgningen er "case-sensitive"

Filtrer på type:
Her er der mulighed for at udvælge rutemål efter deres type. De mulige typer er lastepladser, busstoppesteder, jernbanestationer og havne.

Special filter:
Her er der mulighed for at udvælge rutemål, der er overfyldte og rutemål, der ikke er forbundne.

De to lister giver mulighed for at udvælge rutemål udfra de varer, der forbruges eller produceres på rutemålet. De tre knapper under overskriften anvendes til at vælge henholdsvis alle eller ingen af de mulige varetyper samt til at foretage den "inverse" trykknap udvælgelse.

simutrans-124.3/simutrans/text/dk/language.txt000066400000000000000000000022131474050137200215040ustar00rootroot00000000000000Sprog dialog hjælp

Sprog dialog

Beskrivelse:
Simutrans er et multilingualt spil, der tillader spilleren at vælge sit foretrukne sprog for alle viste tekster. (forudsat en oversættelse eksisterer)

Udseende:
Dialogen består af en række radio-knapper. En radioknap for hvert muligt sprog.

Når du vælger et sprog i radioknap-menuen vil samtlige tekster blive vist på dette sprog - med to undtagelser:

1) De fleste åbne dialoger skifter først sprog, når de genåbnes.

2) Eksisterende byer vil ikke ændre navn.

For at give byer navne på dit foretrukne sprog, skal du vælge sprog før du skaber et nyt kort.

Hvis dit foretrukne sprog skulle mangle, findes der et par oversættelser på:

http://www.simustation.de.vu og
http://www.simutrans.de
Disse oversættelser er dog ikke altid fuldstændige og up-to-date.

En anden mulighed ville selvfølgelig være, at du selv lavede en oversættelse ;-)

For at hjælpe med at oversætte Simutrans på dit sprog,
besøg https://translator.simutrans.com

simutrans-124.3/simutrans/text/dk/load.txt000066400000000000000000000022751474050137200206500ustar00rootroot00000000000000Indlæs hjælp

Indlæs dialog

Beskrivelse:
Indlæs dialogen giver mulighed for at fortsætte et tidligere gemt spil. Indlæs dialogen er opbygget analogt til
Gem dialogen

Udseende:
Øverst i dialogen er overskriften 'Filnavn:' med en tilhørende tekstboks. Denne tekstboks giver mulighed for at indtaste navnet på et tidligere gemt spil. Derunder er en liste bestående af de spil, der befinder sig i simutrans/save mappen. For alle spil er vist en slet-knap, spillets navn samt "gem-tidspunktet".
Nederst er en 'OK' og en 'Fortryd' knap.

Et spil indlæses enten ved at taste navnet på spillet i tekstboksen og trykke på 'OK' knappen eller ved at trykke på spillets navn i listen. Hvis du prøver at indlæse et gemt spil, som ikke eksisterer vil du få en fejlmeddelelse, der fortæller dette.

Vigtigt !
Gamle gemte spil fra tidligere Simutrans versioner kan være inkompatible.
Læs venligst "release notes" for hver ny version, du anvender for at se, om dette er tilfældet.
Imellem "major versions" vil inkompabilitet højst sandsynlig være tilfældet.

simutrans-124.3/simutrans/text/dk/map.txt000066400000000000000000000007661474050137200205110ustar00rootroot00000000000000Reliefkort dialog hjælp

Reliefkort dialog

Beskrivelse:
Reliefkort dialoget giver et fugleperspektivs overblik over verden, med informationer om byer, industrier, veje, jernbanespor o.l.

Hver industritype er markeret med sin egen farve. Et overblik over denne farvekodning findes nedenunder kortet.

Hvis du ønsker at "se nærmere" på verden, kan du højreklikke på kortet, hvorved der skiftes imellem to forskellige zoom niveauer.

simutrans-124.3/simutrans/text/dk/new_world.txt000066400000000000000000000063541474050137200217330ustar00rootroot00000000000000Skab verden dialog hjælp

Skab verden dialog (X/Q)

Beskrivelse:
Skab verden dialogen giver mulighed for at skabe et nyt kort (spil) med indstillinger, der vil influere på, hvorledes den nye verden vil se ud. Disse indstillinger kan være alt fra kortstørrelse til industritæthed.

Udseende:
Øverst til venstre findes otte indstillingsmuligheder for det nye kort.
Til højre herfor er et "preview" areal, der viser, hvorledes det nye kort vil se ud.
Under disse indstillinger er en knap til valg af tilfældigt kortnummer.
Nederst i dialogen findes fire knapper til indlæsning af gemte spil eller reliefkort, til at starte et nyt spil og til at afslutte Simutrans.

Indstillingsmulighederne for et nye kort er følgende:

Kortnummer:
Bestemmer hvordan verden vil se ud inklusiv beliggenheden af byer, vand og land. I "preview" arealet kan hvert enkelt kort ses (opdateret med de andre valgte indstillinger).

Størrelse:
Bestemmer hvor mange kvadrater kortet vil bestå af. Størrelsen varierer fra 128*128 til 640*640 kvadrater. Default størrelsen er 256*256.
Vigtigt - Jo større et kort desto mere memory bliver benyttet. Vær opmærksom på om du har tilstrækkelig memory til at spille et spil med den valgte kortstørrelse.

Industritæthed:
Tætheden af industrier. Jo lavere tæthedesværdi desto sværere vil spillet blive, da der bliver færre industrier at transportere imellem. Default værdien er 125.

Antal byer:
Bestemmer hvor mange byer, der placeres på kortet. Værdierne går fra 2 til 64 med 32 som default værdi.

Trafiktæthed:
Tætheden af private biler i byerne. Default værdien er 8.

Vand niveau:
Afspejler hvor højt grundvandsspejlet er (hvor mange vandfelter, der vil være). Jo lavere værdi desto flere landfelter vil kortet indeholde. Default værdien er 4

Kuperet terræn:
Bestemmer højden af det højeste bjerg. Jo lavere værdi desto færre og lavere bjerge og dale. Værdierne går fra 0 til 160 med default værdi 160.

Bjergstejlhed:
Angiver hvor stejle bjergene vil være. Jo lavere værdi desto "jævnere" vil bjergstigningerne være.

Tilfældigt kort:
Vælger et tilfældigt kortnummer (opdateret med de valgte indstillinger)

Vis fodgængere
Bestemmer om fodgængere skal være synlige eller ej. Indstillingen kan ændres under spillet
ved at benytte Udseende dialogen.

Dag og nat indstilling
Bestemmer om der alt efter klokkeslet skal skiftes imellem dag og nat belysning. Denne indstilling kan ligeledes ændres under spillet
ved at benytte Udseende dialogen.

De fire knapper er:

Indlæs spil:
Indlæser et tidligere gemt spil.
Se Indlæs dialogen for nærmere information

Indlæs reliefkort:

Start spil
Starter et nyt spil med de valgte indstillinger.

Afslut
Afslutter Simutrans - "no questions asked".

simutrans-124.3/simutrans/text/dk/options.txt000066400000000000000000000022561474050137200214230ustar00rootroot00000000000000Indstillinger dialog hjælp

Indstillinger dialog

Beskrivelse:
Denne dialog er en indgang til alle andre dialoger i Simutrans.

Udseende:
Dialogen består af ni (9) knapper, der hver aktiverer en ny dialog.

Nedenfor er en liste over de mulige dialoger med en kort beskrivelser af, hvad den aktiverede dialog indeholder.

Sprog
Tillader valg af hvilket sprog Simutrans benytter til tekster og navne.

Spillerfarve
Giver mulighed for valg af firmafarve.

Udseende
Ændr udseende indstillinger såsom "dag og nat indstilling"

Lyd
Vælg dine lyd- og musikpræferencer.

Spillerliste
Kontroller AI-spillerne i spillet.

Indlæs
Indlæs et tidligere gemt spil.

Gem
Gem det aktuelle spil.

Nyt kort
Start et nyt spil.

Afslut
Afslut spillet. Bemærk at der ikke først bliver spurgt om det aktuelle spil skal gemmes.

For en mere detaljeret beskrivelse, vælg venligst "hjælp" i den enkelte dialog.

simutrans-124.3/simutrans/text/dk/players.txt000066400000000000000000000013061474050137200214020ustar00rootroot00000000000000AI-spillerliste dialog hjælp

AI-spillerliste dialog

Beskrivelse:
AI-spillerliste dialogen giver mulighed for at bestemme antallet af computerstyrede spillere i spillet.

Udseende:
Dialogen består af seks (6) checkbox-knapper med angivelse af den enkelte spillers firmafarve.

For at aktivere/stoppe en AI-spiller skal den pågældende checkbox markeres. Bemærk at selvom en AI-spiller "deaktiveres" vil vedkommendes eksisterende ruter fortsat modtage indtægter. Deaktivering af en AI-spiller får blot vedkommende "til at sove".

Dialogen giver ligeledes et overblik over kassebeholdningen for hver enkelt konkurrent.

simutrans-124.3/simutrans/text/dk/railtools.txt000066400000000000000000000120111474050137200217260ustar00rootroot00000000000000Jernbaneanlæg

Jernbaneanlæg dialog

Beskrivelse:
Denne dialog indeholder værktøjer til at bygge jernbanespor, signaler, tunneller, el-master, stationer, depoter og jernbaneovergange.

Udseende:
Dialogen består af syv (7) symboler, der hver repræsenterer et byggeværktøj.

Gående fra venstre mod højre samt oppefra og ned er de forskellige symboler:

Byg jernbaneanlæg:
Dette værktøj vil bygge et jernbanespor imellem to kort-kvadrater. Ved venstreklik på symbolet forandres cursoren til et jernbanekryds-symbol. For at bygge et jernbanespor venstreklikkes på start-kvadratet. Cursoren forandres derved til en bulldozer. Venstreklik derefter på slut-kvadratet. Simutrans vil nu bygge et jernbanespor imellem de to kvadrater.
Der bliver kun bygget på frie kvadrater. Veje og andre spilleres jernbanespor vil ikke blive krydset. Benyt jernbaneovergange, broer eller tunneller til at krydse disse "forhindringer".
Hvis der ikke kan findes en forbindelse imellem de to kvadrater vil der ikke blive bygget noget overhovedet.

Byg jernbanesignal:
Dette værktøj benyttes til at bygge jernbanesignaler på jernbanespor. Ved venstreklik på symbolet forandres cursoren til et signalsymbol.
For at bygge et signal venstreklikkes på et jernbanespor, hvor signalet skal placeres. Signaler bygges på kvadrat-grænser, men faktisk bygges et signal på begge tilstødende kvadrater. Der kan kun bygges et signal på et kvadrat.
For at fjerne et signal benyttes "Fjern/riv ned" menuen. Dette vil fjerne signalet men lade jernbanesporet intakt.
Signaler benyttes til at begrænse toges rutemuligheder. De kan f.eks benyttes til at tillade to toge at benytte den samme sporstrækning.
Ensrettede signaler kan benyttes til at tvinge tog i en bestemt retning.
Et ensrettet signal fås ved at placere et normalt signal og derefter venstreklikke på signalet igen. Ved et yderligere venstreklik bliver retningen for det ensrettede signal ændret og endnu et venstreklik får signalet tilbage til et normalt "tovejs-signal"
Check omhyggelig om et ensrettet signal vender rigtigt, da togene i modsat fald ikke vil kunne finde en rute.

Byg jernbanetunnel:
Dette værktøj benyttes til at bygge jernbanetuneller. Ved venstreklik på symbolet ændres cursoren til et tunnelsymbol.
Tunneller benyttes til at lave lige jernbanestrækninger igennem et bjerg. Benyt tunneller til at undgå at skulle bygge udenom eller over bjerget.
For at bygge en tunnel skal jernbanesporene, der skal forbindes, bygges først. Byg de to jernbanespor så de ender overfor hinanden og opad en skråning på det bjerg, tunnellen skal gå igennnem. Det er vigtigt, at sporene er på samme niveau på hver side af bjerget.
Venstreklik derefter på en af spor-enderne, hvorefter de vil blive forbundet med en tunnel.

Byg el-master:
Dette værktøj benyttes til at bygge el-master på en jernbanestrækning. Ved venstreklik på symbolet ændres cursoren til et el-mastsymbol.
For at elektrificere en jernbanestrækning venstreklikkes på et vilkårligt jernbanespor på strækningen.
El-master er nødvendige for at kunne benytte toge, der har el som drivmiddel. Hvis der mangler el-master, vil et sådant tog ikke kunne finde en rute.

Byg jernbanestation:
Dette værktøj benyttes til at bygge en jernbanestation på en jernbanestrækning. Ved venstreklik på symbolet ændres cursoren til et stationssymbol.
Stationer benyttes af toge til at hente eller aflevere varer. Stationer bygges af stationselementer og kan være af vilkårlig størrelse.
For at bygge et stationselement venstreklikkes på det jernbanespor-kvadrat, hvor elementet skal placeres. Stationselementer kan ikke bygges på skråninger, i kurver eller på sporkryds.
Ethvert stationselement, der placeres ved siden af en eksisterende station, vil blive en del af denne station. Ethvert element kan indeholde to (2) togvogne.
Kontroller at en station kan indeholde det længste tog, der skal stoppe der. Togvogne, der ikke er inde i stationer vil ikke blive lastet eller losset.

Byg togdepot:
Dette værktøj benyttes til at bygge et togdepot på en jernbanestrækning. Ved venstreklik på symbolet ændres cursoren til et depotsymbol.
Depoter benyttes til at købe, sælge og opdatere toge og togvogne.
For at bygge et depot venstreklikkes på et eksisterende jernbanespor-afslutning, hvor depotet ønskes placeret.

Byg jernbaneovergang:
Dette værktøj benyttes til at bygge en jernbaneovergang over en vej. Ved venstreklik på symbolet ændres cursoren til et jernbaneovergangssymbol.
For at bygge en jernbaneovergang venstreklikkes på et lige vejstykke. Jernbaneovergange benyttes til at krydse egne veje. For at krydse andre spilleres veje skal benyttes tuneller eller broer.

simutrans-124.3/simutrans/text/dk/roadtools.txt000066400000000000000000000064061474050137200217370ustar00rootroot00000000000000Vejanlæg dialog hjælp

Vejanlæg dialog

Beskrivelse:
Denne dialog indeholder værktøjer til at bygge veje, busstoppesteder, tunneller, lastepladser, vejdepoter og jernbaneovergange.

Udseende:
Dialogen består af seks (6) symboler, der hver repræsenterer et byggeværktøj.

Gående fra venstre mod højre samt oppefra og ned er de forskellige symboler:

Byg vejanlæg:
Dette værktøj vil bygge en vej imellem to kort-kvadrater. Ved venstreklik på symbolet forandres cursoren til et vej-symbol. For at bygge en vej venstreklikkes på start-kvadratet. Cursoren forandres derved til en bulldozer. Venstreklik derefter på slut-kvadratet. Simutrans vil nu bygge en vej imellem de to kvadrater.
Der bliver kun bygget på frie kvadrater og over egne og andre spilleres veje. Andre spilleres jernbanespor vil ikke blive krydset. Benyt jernbaneovergange, broer eller tunneller til at krydse disse "forhindringer".
Hvis der ikke kan findes en forbindelse imellem de to kvadrater vil der ikke blive bygget noget overhovedet.

Byg busstoppested:
Dette værktøj benyttes til at bygge busstoppesteder på veje. Ved venstreklik på symbolet forandres cursoren til et stoppestedssymbol. Venstreklik derefter på en vej, hvor du vil have stoppestedet placeret.

Byg tunneller:
Dette værktøj benyttes til at bygge tuneller. Ved venstreklik på symbolet ændres cursoren til et tunnelsymbol. Tunneller benyttes til at lave lige vejstrækninger igennem et bjerg. Benyt tunneller til at undgå at skulle bygge udenom eller over bjerget.
For at bygge en tunnel skal vejene, der skal forbindes, bygges først. Byg de to veje så de ender overfor hinanden og opad en skråning på det bjerg, tunnellen skal gå igennnem. Det er vigtigt, at vejene er på samme niveau på hver side af bjerget.
Venstreklik derefter på en af vejafslutningerne, hvorefter de vil blive forbundet med en tunnel.

Byg lasteplads:
Dette værktøj benyttes til at bygge lastepladser. Lastepladser benyttes af dine lastbiler til at laste eller aflevere varer. En lasteplads bygges ved at venstreklikke på symbolet, hvorved cursoren forandres til et lastepladssymbol, og derefter venstreklikke på en vejafslutning, hvor du vil have lastepladsen placeret. Bemærk at der højest kan være to køretøjer på en lastplads af gangen

Byg vejdepot:
Dette værktøj benyttes til at bygge
vejdepoter. Depoter benyttes til at købe, sælge og opdatere dine køretøjer. Depoter bygges, ligesom lastepladser på vejafslutninger ved at venstreklikke på symbolet, hvorved cursoren forandres til et depotsymbol, og derefter venstreklikke, hvor depotet skal placeres,

Byg jernbaneovergang:
Dette værktøj benyttes til at bygge en jernbaneovergang over et jernbanespor. Ved venstreklik på symbolet ændres cursoren til et jernbaneovergangssymbol. Jernbaneovergange benyttes til at krydse jernbanespor. For at bygge en jernbaneovergang venstreklikkes på et lige sporstykke, hvorefter veje via jernbaneovergangen kan krydse jernbanesporet.

simutrans-124.3/simutrans/text/dk/save.txt000066400000000000000000000022721474050137200206640ustar00rootroot00000000000000Gem Help

Gem dialog hjælp

Beskrivelse:
Hvis du ønsker at spille et spil over et længere tidsrum, bliver du nødt til at gemmme det på et tidspunkt. Simutrans giver mulighed for at gemme alle aktuelle data i en fil, der kan indlæses på et senere tidspunkt.

Udseende:
Øverst i dialogen er overskriften 'Filnavn:' med en tilhørende tekstboks. Denne tekstboks giver mulighed for at indtaste et navn, som spillet skal gemmes under. Derunder er en liste bestående af de spil, der befinder sig i simutrans/save mappen. For alle spil er vist en-slet knap, spillets navn samt "gem-tidspunktet".
Nederst er en 'OK' og en 'Fortryd' knap.

Et spil gemmes enten ved at taste et navn for spillet i tekstboksen og trykke på 'OK' knappen eller ved at gemme under et tidligere navn. Det sidste gøres ved trykke på spillets navn i listen, hvorved det tidligere gemte spil overskrives.

Det er muligt at slette gemte spil ved at trykke på slet-knappen. Bemærk at dette sletter spillet uden mulighed for at genskabe det !! Efter der er trykket på slet-knappen lukkes dialogen uden yderligere meddelelser.

simutrans-124.3/simutrans/text/dk/schedule.txt000066400000000000000000000045421474050137200215240ustar00rootroot00000000000000Ruteplan dialog

Ruteplan dialog

Beskrivelse:
Ruteplan dialogen benyttes til at definere ruter imellem bustoppesteder, lastepladser, jernbanestationer, havne eller olieplatforme. Til en rute kan et eller flere køretøjer tilknyttes og startes, hvorefter de vil blive med at gennemkøre ruten, indtil de sendes tilbage i depot.

Udseende:
Øverst i dialogen er en liste med overskriften 'Min. last'. Til listen er to scroll-knapper tilknyttet.
Derunder følger et visningsareal, der viser navne, nummer, Min. lastningsgrad samt koordinater for de forskellige rutemål.
Nederst er fire knapper med teksterne 'Tilføj', 'Indføj', 'Fjern' og 'Færdig'. Som default indstilling er knappen 'Tilføj' trykket ned.

Opret en rute:
For at oprette en rute trykkes på 'Tilføj' knappen, hvorved cursoren forandres til et rutemål-symbol. Derefter venstreklikkes på de ønskede rutemål (ved en havn klikkes i vandet lige ved havnen) i den ønskede rækkefølge. Bemærk at der pt. er en maksimusgrænse på seksten (16) rutemål
For samtlige rutemål kan der indstilles en "Minimums lastgrad". Minimum lastgraden er den procentsats af den samlede lastevne, som mindst skal være fyldt på køretøjet, før det fortsætter til næste rutemål. For at foretage denne indstilling klikkes til venstre for rutemålet i visningsarealet. Herved bliver rutemålet markeret som det aktuelle rutemål. Den ønskede minimums lastgrad indstilles derefter ved at bruge listens scroll-knapper. Bemærk at et køretøj, der endnu ikke har fået påfyldt den ønskede minimums lastgrad, vil vente til dette er tilfældet og kan derved spærre rutemålet for andre køretøjer. Tilsidst trykkes på 'Færdig' knappen, hvorved ruten er defineret og dialogen lukkes.

Opdater en rute:
En rute kan opdateres på følgende måde:
- Ved at trykke på 'Tilføj' knappen og tilføje yderligere rutemål bagest i rækkefølgen af rutemål
- Ved at trykke på 'Indføj' knappen hvorefter en nyt rutemål indføjes før det aktuelt markerede rutemål i listen. Dette er den nemmeste måde at sende køretøjer tilbage i depot på.
- Ved at trykke på 'Fjern' knappen, hvorefter det aktuelt markerede rutemål kan fjernes fra listen ved at klikke på det.

simutrans-124.3/simutrans/text/dk/shiptools.txt000066400000000000000000000025571474050137200217600ustar00rootroot00000000000000Havneanlæg dialog hjælp

Havneanlæg dialog

Beskrivelse:
Denne dialog indeholder værktøjer til at bygge havne og skibsdepoter.

Udseende:
Dialogen består af tre (3) symboler, hvoraf et repræsenterer havnebygning og de to andre skibsdepoter.

Gående fra venstre mod højre samt oppefra og ned er de forskellige symboler:

Byg havn:
Dette værktøj benyttes til at bygge havne. Ved venstreklik på symbolet forandres cursoren til et havnesymbol. Herefter kan der bygges en havn ved at venstreklikke på en lige kyststrækning. Havne benyttes af skibe til at laste eller losse varer.
Bemærk at havne pt. ikke kan fjernes direkte. Det kan gøres ved fjerne havnen, hæve landniveauet og derefter sænke landniveauet.

Byg skibsdepot:
Et skibsdepot benyttes til at bygge, sælge og tilknytte ruter til skibe. Der er to symboler til bygning af skibsdepoter. Disse er dog pånær udseendet fuldstændig ens. Et skibsdepot bygges ved at venstreklikke på symbolet, hvorved cursoren forandres til et skibsdepot symbol, og derefter venstreklikke på et hvilket som helst vandfelt, hvor depotet ønskes placeret. Som regel er det en fordel at placere depotet i nærheden af et eller flere fremtidige rutemål.

simutrans-124.3/simutrans/text/dk/sound.txt000066400000000000000000000021051474050137200210510ustar00rootroot00000000000000Lydindstillinger dialog hjælp

Lydindstillinger dialog

Beskrivelse:
I denne dialog kan du såvel ændre indstillingerne for lyden og musikken, der afspilles under spillet, som det musikstykke, der aktuelt afspilles.

Udseende:
Øverst i dialogen er to scrollbars med overskrifterne: 'Lydstyrke:' og 'Musik lydstyrke:'
Derunder er overskriften 'Afspiller aktuelt:' med to scroll-knapper tilknyttet.

Lydstyrken for diverse lydeffekter (toge, bulldozers ol.) indstilles med den øverste scrollbar. Lydstyrken for baggrundsmusikken indstilles med den nederste scrollbar.

Nederst i dialogen vises det aktuelt afspillede musikstykke. Der kan vælges tidligere eller senere musiknumre ved at benytte scroll-knapperne.

Bemærk at Simutrans ikke inkluderer baggrundsmusik. Denne må tilføjes manuelt. Oplysninger om hvorledes dette gøres, kan findes på Simutrans hjemmesiden : www.simutrans.org

For helt at slå lyden fra kan Simutrans startes med en -nosound option.

simutrans-124.3/simutrans/text/dk/station.txt000066400000000000000000000047171474050137200214150ustar00rootroot00000000000000Rutemål

Rutemål dialog

Beskrivelse:
For alle rutemål (busstoppesteder, lastepladser, jernbanestationer og havne) på kortet kan denne dialog åbnes ved at klikke på rutemålet. Bemærk, hvis der er køretøjer på rutemålet, vil en køretøjs dialogligeledes blive åbnet for hvert køretøj. Dialogen giver nyttig information om rutemålet, dets forbindelser og den aktuelle varesituation.

Udseende:
Øverst i dialogen er rutemålets navn og nummer. Derefter følger en oversigt over passagerer befordret fra rutemålet denne dag. Dernæst kommer en oversigt over aktuelt ventende varer (og passagerer). Hertil er knyttet to knapper med teksten 'Statistik' og 'Destination' samt et visningsareal, der giver oplysninger om mængden af og destinationen for de ventende varer.
Øverst til højre i dialogen er en knap med teksten 'Detaljer' og herunder et billedudsnit af rutemålet. Ved at klikke på dette billedudsnit, vil rutemålet blive centreret på kortet.

De tre knapper har følgende funktion:

Statistik:
Statistik knappen udvider dialogen med et grafisk visningsareal og en række trykknapper, der hver repræsenterer et rutemålsnøgletal. Ved at trykke på en knap bliver udviklingen af det ønskede nøgletal illustreret grafisk i visningsarealet.

Destination:
Dette er en "tilstandsknap" til sortering af oplysningerne om ventende varer i visningsarealet. De mulige sorteringsmuligheder (tilstande) er efter 'Destination', 'via' og 'Mængde'

Detaljer:
Denne knap åbner en ny dialog med følgende yderligere rutemålsoplysninger:

- Forbundne industrier:
Angiver hvilke nærliggende industrier, der benytter dette rutemål til at modtage eller aflevere varer. Denne oplysning er et glimrende check for, om et rutemål "er placeret tæt nok" på en industri til at kunne betjene denne. Et rutemål kan udmærket betjene flere industrier samtidigt

- Modtager følgende varer:
Angiver hvilke varer, der kan leveres til rutemålet.

- Direkte ruter herfra:
Angiver hvilke andre rutemål, der er direkte forbindelse til samt hvilke varer, der leveres til eller fra dette rutemål.

- Stoppested for rute:
Angiver hvilke definerede (nummererede) ruter, der har dette rutemål som stoppested.

simutrans-124.3/simutrans/text/en.tab000066400000000000000000001076411474050137200176670ustar00rootroot00000000000000English PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: en English # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Display times as day:hh:mm of the month AMBIENT_SOUND ambient sounds CASH_SOUND cashing sound cl_btn_filter_disable Disabled cl_btn_filter_enable Enabled cl_btn_filter_settings Settings cl_btn_sort_asc Ascending cl_btn_sort_desc Descending cl_btn_sort_id Internal ID cl_btn_sort_income Income cl_btn_sort_name Name cl_btn_sort_type Type clf_btn_alle all clf_btn_invers inv. clf_btn_keine none climate area percentage Size single climate CROSSING_SOUND crossing warnings FACTORY_SOUND factory noises gl_btn_sort_bonus Bonus gl_btn_sort_name Name gl_btn_sort_revenue Revenue gl_btn_unsort Unsorted height based Climate from height hl_btn_filter_disable Disabled hl_btn_filter_enable Enabled hl_btn_filter_settings Settings hl_btn_sort_asc Ascending hl_btn_sort_desc Descending hl_btn_sort_name Name hl_btn_sort_type Type hl_btn_sort_waiting Waiting hlf_btn_alle all hlf_btn_invers inv. hlf_btn_keine none humidities humidity borders Lake height max. lake height moisture land increase over land moisture water increase over water Queueing Waiting Trend rainfall humidity Reselect closes tools Re-selecting a tool de-selects it Road toll Road Toll Scenario Scenario Info sea marine climate Start this as a server Start a server using this game. temperature-humidity based Climates from weather TOOL_SOUND tool action sounds TRAFFIC_SOUND traffic noises Transfers Passing through #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Arctic desert Desert mediterran Mediterranean rocky Alpine (rocky) temperate Temperate tropic Tropical tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot alter water This basin cannot be further drained or filled. Cannot build on a double slope! Can be only built on a single slope or flat ground! Cannot built depot here! Cannot build a depot here. Cannot built this station/building\nin underground mode here. This station/building cannot be built underground. Cannot connect to the\ncenter of a double slope! A brige cannot connect to the middle of a double slope!\nUse landscaping tool to fix this. Convoi handles exhausted! Maximum number of convoys reached. Corrupt file File corrupt or truncated. Could not open file Could not access file. Maybe check permissions? Das Feld gehoert\neinem anderen Spieler\n This piece of\nland is owned by\nanother player!\n Der Besitzer erlaubt das Entfernen nicht The owner refuses\npermission to\nremove this!\n Diese Zusammenstellung kann nicht fahren!\n This combination\ncannot start!\n Failed to write file Could not write out file. (Permissions?) Flugzeughalt muss auf\nRunway liegen!\n Plane stand must\nbe on a taxiway. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n You cannot build\n\nairport building here.\n Hier kann kein\nSignal aufge-\nstellt werden!\n You cannot place\nrail signals here.\n Maglevhalt muss auf\nMaglevschiene liegen!\n A maglev stop must be placed on maglev track! Monorailhalt muss auf\nMonorail liegen!\n Monorail stops must\nbe on monorail track. Monorails are not available yet! Monorails are not yet available. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n A narrowgauge stop must be placed on narrowgauge track No curves on runways Runways cannot make turns! No suitable crossing No suitable crossing! (max speed too fast?) No suitable way on the ground! Stops can be built only on\nstraight level matching ways! No through station here! Stations must be placed on dead-end ways or straight sections with no intersections. Not allowed to copy object. You cannot build that object!\n(Reason: Wrong player or obsolete) Not enough clearance. Between two ways a minimum height difference of two is needed. Not enough empty space Not enough free space left. Not enough money! You do not have enough\nmoney to buy this! Not initialized Could not initialize library. On narrowgauge track only!\n Must be placed on narrow gauge track only! Only public player can lock games! Only a public player can lock games! Only up and down movement in the underground! An underground tile can be only raised and lowered using the all up/down tools! Out of funds You don't have enough money left for this! Post muss neben\nHaltestelle\nliegen!\n A station extension building\n(ex. post office, warehouse)\nmust be placed on a free tile\nnext to an existing stop/station.\n Protocoll error (expecting game) Protocol error (expecting game) Schiffhalt muss im\nWasser liegen!\n A ship stop can only\nbe placed on water\nnear a dock!\n Server version too new The server uses a more recent program version. Terraforming not possible\nhere in underground view Terraforming is not possible underground. This tunnel branches. You can try Control+Click to remove. This tunnel has more than 2 entrances. You can try ctrl+click to remove this tunnel. Watertable reached Cannot lower tile any further!\nReached the water table. Zughalt muss auf\nSchiene liegen!\n Rail stations must\nbe placed on the\nrailroad track.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Help

Help Index

About Simutrans

%1$s

How to use

%2$s

How to start a game

%4$s

How to play

%5$s

Tools

%3$s

Others windows

%6$s Keyboard Help\n

Keyboard Help

\n Keyboard Binding\n

Keyboard Help

\n

\n

Keyboard Help opens when an unassigned key is pressed or from General Help.\n

\n

\nKey presses are case sensitive (use [Shift] for upper-case letters).\n

\n

\nKeys with assigned functions include:\n

\n

\n[Arrow Keys]: scroll game-view in direction of arrow.
\n[Backspace]: close all windows, toolbars and help-texts.
\n[Delete], or [Escape]: close top window, toolbar or help-text.
\n[Page-Up], or [>]: zoom-in game-view.
\n[Page-Down], or [<]: zoom-out game-view.\n[CTRL] + tool: build straighter ways (even over faster ways) or reverse selection order during query or deletion.
\n

Color-coded terrain according to altitude. Show/hide terrain contour shading. Decrease water height Drain water one level Highlite depots Highlight depots Highlite electrical transmission lines Highlight electrical transmission lines Highlite factories Highlight factories Highlite forests Highlight forests Highlite tourist attraction Highlight tourist attraction Increase water height Raise the water by one level Open station/stop details Show station details Set tile climate %s Convert this ground into %s zone Show how many convoi reach a station Show how many convoys reach a station Show how many people/much is waiting at halts Show how many/much is waiting Show initial passenger departure Show the passenger and post origin. Show mail service coverage/mail network Show mail service coverage Show passenger coverage/passenger network Show passenger network coverage Show the change of waiting at halts Show how waiting changed since last month Show the owenership of infrastructure Show ownership of infrastructure Show usage of network Show vehicles per tile and month Sum of departure/arrivals at halts Show the number of arrived and departed vehicles #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s\nat (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s\nat (%i,%i). Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nopens a new overland\nbus service between\n%s and\n%s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Map Editing Tools LISTTOOLS Lists MAGLEVTOOLS Maglev Tools MONORAILTOOLS Monorail Tools NARROWGAUGETOOLS Narrow-gauge Railroad Tools RAILTOOLS Railroad Tools ROADTOOLS Road Tools SHIPTOOLS Shipping Tools SLOPETOOLS Landscaping Tools SPECIALTOOLS Special Construction Tools TRAMTOOLS Trams/light rail Tools #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s's has built a new headquarter. Factory chain extended\nfor %s near\n%s built with\n%i factories. Economy going strong:\n%s near %s extends chain.\n%i new factory founded. New factory chain\nfor %s near\n%s built with\n%i factories. Industry growth: New factory chain\nfor %s near\n%s built with\n%i factories. New vehicle now available:\n%s\n \n A new vehicle is\n now available:\n\n\n -- %s --\n\n Now %u clients connected. Right now %u client(s) are connected. Remove vehicle from map. Use with care! Remove vehicle from map. (Use with care!) Screenshot\ngespeichert.\n Screenshot\nsaved.\n Sends the convoi to the last depot it departed from! Sends the convoy to the last depot it departed from. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. With a big festival,\n%s built\na new monument.\n%i citizens rejoiced. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/month) (%.2f$/km) (%.2f$/km) (%i)- (%i) \nBauzeit bis until \nBauzeit von \nAppears from \nCan't open heightfield file.\n \nCannot open height map.\n \ndirection: \ndirections: \nelektrified \nelectrified\n \nHeightfield has wrong image type.\n \nHeightfield has wrong\nimage type.\n \nis reserved by: \nreserved by train \nminimum speed: \nminimum speed: \nnot elektrified \nnot electrified\n \nRibi (masked) \ndirections\m (masked): \nRibi (unmasked) \ndirections\n (unmasked): \nSet phases: \nSet phases time\n / then \\ then offset \nsingle way \nSingle Way \nway1 reserved by \nway 1 reserved by \nway2 reserved by \nway 2 reserved by %d convois %d convoys %d Einzelfahrzeuge im Depot %d vehicles stored here. %i car(s), %i cars, %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. Age: %i years and %i months %s at (%i,%i) now public stop. %s has become public interchange. %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s yard %s land %d %s %s %d outer %s %s now known as %s. %s is now known as %s. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \nbuilt a\nnew townhall\nwhen it reached\n%i inhabitants. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nmaximum speed %3$i km/h\n\ncurrent speed %2$i km/h.\n\n %s\nwas liquidated. %s went bankrupt and\nhas been liquidated.\nAll operation was halted,\nand all assets have been sold. %u Player (%u locked)\n %u Players (%u locked)\n %s - %s
\n [%s]: %s
\n

Error

Error: Double objects in main pak directory

In

Warning

addons for

Warning: Doubled objects in the addon directory

Addons for 1 convoi 1 convoy 1 Einzelfahrzeug im Depot 1 vehicle stored here. 1 minute ago one minute ago 1LIGHT_CHOOSE Brightness: 1WORLD_CHOOSE Settings for a New Game: 2LIGHT_CHOOSE Colours: 2WORLD_CHOOSE Map number: 3LIGHT_CHOOSE Scroll Speed: 4LIGHT_CHOOSE Scroll Inverse 5LIGHT_CHOOSE Pedestrians at stops 5WORLD_CHOOSE Number of cities: 6LIGHT_CHOOSE Pedestrians in towns 6WORLD_CHOOSE Traffic density: 8WORLD_CHOOSE Day and Night cycle A bridge must start on a way! You do not own the ends of this bridge's path, or the path is obstructed.\n Abfrage Inspection Tool Abnehmer Consumer: About scenario Copyright Abriss Destroy/Remove Absenken Lower land Abspanntransformator Transformer Add random citycar Add random city car add server Add server Add stops for backward travel Add stops for backward travel. air runway/taxiway Aircraft Airline aircraft_tab Freight planes AIRTOOLS Airport Tools all convoi tooltips all convoy tooltips allowed climates:\n Allowed climates:\n Alters a schedule. Add/removes stops to/from a schedule Angenommene Waren Goods needed by nearby industries anhaengen Append Anhaenger_tab Trailers Anheben Raise land Appends stops at the end of the schedule Add stop at end of schedule Apply Line Assign line Arbeiter aus: Workers live in: Aufloesen Disassemble Aufspanntransformator Transformer Autohalt muss auf\nStrasse liegen!\n Bus or car stops\nmust be\nplaced on the road. Bahndepot Train depot Bankrott:\n\nDu bist bankrott.\n Bankrupt:\n\nYou are bankrupt!\n battery Battery Baum Tree baum builder Plant trees Baustelle Construction site Bauzeit build time Beenden Quit Beginner mode Beginner Mode Besonderes Gebaeude Tourist attraction BF station bio biological Blockstrecke ist\nbelegt\n \nRail block is in use\nby another train!\n Boden Ground Bonusspeed: %i km/h Max. possible speed: %i km/h bridge is too high for its type! The bridge is too high for its type! Bridge is too long for this type!\n Bridge span is too\nlong for this type of\nbridge.\n Bruecke Bridge Bruecke muss an\neinfachem\nHang beginnen!\n Bridges must\nstart on a\nstraight slope!\n Brueckenboden bridge Build air depot Build aircraft hanger build choosesignals Build platform choose signals Build city market Build a new market in the nearest city. Build drain Transformer station build HQ Build HQ Build land consumer Build a new power station. Build powerline Build Power Transmission Line Build presignals Build twoblock signals Build road depot Build Garage Build ship depot Build Shipyard Build truck depot Build Garage Building costs estimates Estimated construction cost Buildings City buildings Built artifical slopes Build artificial slopes Built random attraction Build a random attraction. Bus_tab Buses Can only move from halt to halt or waypoint to waypoint. Can only move \nfrom halt to halt or \nfrom waypoint to waypoint. Capacity: %.0f MW Capacity: %.0f MW\n Capacity: %d%s %s\n Capacity: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capacity: %s\n\nProportion: %d (%d%%) Cars are not available yet! Cars are not yet available. cars.\nstate cars\n Cash Account Balance Chat_msg Chat chooses a random map Chooses a random map. citicens Citizens City industries Markets in cities City list City List city_road City road citybuilding builder Build urban buildings CityLimit City limits cl_title Vehicle List cl_txt_sort Sort by: Cleanup schedule Remove double entries Clear block reservation Show/reset reserved ways clf_chk_aircrafts Airplanes clf_chk_cars Buses/trucks clf_chk_indepot in a depot clf_chk_maglev Maglevs clf_chk_monorail Monorails clf_chk_name_filter Filter names: clf_chk_narrowgauge Narrow-gauge trains clf_chk_noincome Make a loss clf_chk_noline No line clf_chk_noroute No route clf_chk_noschedule No schedule clf_chk_obsolete Obsolete clf_chk_ships Ships clf_chk_spezial_filter Special filter: clf_chk_stucked Stuck clf_chk_trains Trains clf_chk_trams Trams clf_chk_type_filter Filter types: clf_chk_waren Filter goods: clf_title Vehicle List Filter Climate Control Landscape Settings closed closed. COLOR_CHOOSE\n Please choose two\ncolours from the\nimage on the right: company_chat Company chat Company_msg Competitors Congratulation\nScenario was complete in\n%i months %i years. Congratulations!\nThe scenario had been \ncompleted within \n%i months and %i years! Connected stops Connected Stops: Connected with server Connected to server Constructed by Painted by Constructed by %s Painted by %s Construction_Btn Construction Costs contains the following doubled objects:

contains the following objects more than once:

convoi %d of %d Convoy %d of %d convoi error tooltips convoy error tooltips Convoi has been sent\nto the nearest depot\nof appropriate type.\n Convoy has been sent\nto the nearest depot\nof appropriate type.\n Convoi is sold when all wagons are empty. The vehicle will be sold as soon as it is completely empty. convoi mouseover tooltips convoy mouseover tooltips convoi passed last\nmonth %i\n \nconvoys passed last\nmonth: %i\n Convois Convoys Convois: %d\nProfit: %s Vehicles: %d\nProfit: %s Copy Convoi Copy convoy Copy the selected convoi and its schedule or line Copy the selected convoy and its schedule or line cost for removal Cost to remove Cost: %8s (%.2f$/km %.2f$/m)\n Cost: %s (%.2f$/km %.2f$/month)\n curiosity builder Curiosity builder curlist_title List of Tourist Destinations deactivated in online mode Not active while online Deccelerate time Decelerate time Del Stop Remove Delete Line Delete line Delete the selected line (if without associated convois). Delete selected line (if no convoys are associated) Demand: %.0f MW Demand: %.0f MW\n Denkmal Monument Departs at Departs at (dd:hh:mm) Departure after %% load or waiting for (dd-hh-mm) Departure board Departure time Der Tunnel ist nicht frei!\n Tunnel is not empty.\n Destination Arrivals Destroying map ... Destroying old map ... Die Bruecke ist nicht frei!\n The bridge is not free!\n direct_chat_to: Direct message to directmail Leaflets Direkt erreichbare Haltestellen Direct routes from here disable midi Mute MIDI music Dock dock Dock must be built on single slope! Docks must be built on a single-sloped tile. dp_title Depot list Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen You have %d months to repay your debt. Durchsatz Max. Economy Economy and cities Eigenbesitz\n Public property\n Ein %s\npasst hier nicht.\n A '%s'\ndoesn't fit here!\n Einstellungen aendern Options Electrics_tab Electrics enlarge map Enlarge map Enter Password Change player name and password Erzeuge neue Karte.\n Please wait while a new\nmap is being created.\n\n(This may take a few \nminutes for big maps.)\n Es wird bereits\nein Fahrplan\neingegeben\n A schedule is\nbeing planned.\nFinish it first\nbefore re-scheduling!\n Extract files Extract pak files from zip. Fabrikanschluss Connected factories Fabrikname Factory name factory details Factory links factorybuilder Factory builder Fahrplan Schedule Fahrtziel Destination: Fahrzeuge koennen so nicht entfernt werden Vehicles cannot be\nremoved this way!\n Fahrzeuge: Vehicles: Farbe Player Colour Fast forward Fast Forward Ferry_tab Ferries Fertig Done Filename Filename: Finanzen Finances find mismatch Compare your pak fl_title Factory List Flug_tab Passenger Aircraft follow me Follow Follow the convoi on the map. Follow the convoy on the map. font size Font size (only .ttf and .otf fonts) Found new city Found a new city Fracht Freight Frame time: Frame Time: Friction: current friction factor: fuel_cell fuel cell Full load Wait for minimum load Fundament Foundation Fussgaenger Pedestrian GAME PAUSED Game Paused Game_msg General Gebaeude Building generate script Generate an infrastruktur macro script Generation: %.0f MW Generation: %.0f MW\n Gewicht Weight Gewinn Income: Give the selected vehicle(s) an individual schedule Edit the selected vehicle(s) individual schedule or assigned line gl_btn_sort_catg Category gl_title Goods List go home Go to Depot Gross Profit Cash Flow Groundobj Object Growth City Growth GUI settings GUI H stop Haus kaufen Buy house Helligk. Display Help text not found The help text is missing. hide all building hide all buildings hide city building hide city buildings hide transparent Transparent instead of hidden hide trees Hide trees Hier warten/lagern: Goods and passengers waiting: Higher transport fees, crossconnect all factories Higher transport fees, disable Just-in-time. Highlite schedule Highlight stops in schedule hl_title Station List hl_txt_filter Filter: hl_txt_sort Sorted by: hlf_chk_airport Airports hlf_chk_anleger Dock hlf_chk_bahnhof Railway station hlf_chk_bushalt Bus stop hlf_chk_frachthof Loading bay hlf_chk_keine_verb No connection hlf_chk_maglevstop Maglev station hlf_chk_monorailstop Monorail stop hlf_chk_name_filter Filter names: hlf_chk_narrowgaugestop Narrow-gauge station hlf_chk_overflow Overcrowded hlf_chk_spezial_filter Special filter: hlf_chk_tramstop Tramway stop hlf_chk_type_filter Filter types: hlf_chk_waren_abgabe Goods out: hlf_chk_waren_annahme Goods in: hlf_title Station List Filter Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depot cannot be found.\nYou must send the\nvehicle there manually. hydrogene Hydrogen ignore climates Ignore climates In the industry legend show only currently existing factories Show only currently existing factories in the industry legend Increase Industry density Increase industry density industrial building Industrial buildings Infinite mouse scrolling Infine map scrolling Infinite scrolling using mouse May not work with touch screens! Init map ... Initializing map ... Ins Stop Insert Stop Insert stop before the current stop Insert stop before current stop Install paks Pak sets are downloaded and installed. Intercity road len: Intercity road length: invalid undefined. Invalid coordinate Invalid Order isometric map Isometric view join game Play Online Kann Spielstand\nnicht laden.\n Cannot load saved game! Kann Spielstand\nnicht speichern.\n Cannot open\ntarget file\nfor writing! Kein Besitzer\n Without owner\n keine none Keine Einzelfahrzeuge im Depot No vehicles stored here. Keyboard_Help\n Keyboard Help\n koord Coordinates Kreuzung Crossing labellist_title List of Markers Lade Relief Load Height Map Laden Load a new game Land industries Industry Chains: LANG_CHOOSE\n Please choose your\npreferred language:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Last Month: Last Year Last Year: leer empty Legend Map legend Leistung Power Leistung: %d kW Power: %d kW Leitung Power line letzen Monat: diesen Monat: last month: this month: LKW_tab Trucks Load game Load Game load height data from file Load height data from file. Load scenario Load Scenario Load settings from Apply settings from loaded passenger/freight Sort passengers/freight by Loading (%i->%i%%)! Loading (%i->%i%%) Loading time: fully loaded in: Lock game Disallow player changes (requires confirmation). Lokomotive_tab Locomotives m3 m³ maglev_track Maglev Track Maglevdepot Maglev Depot Mailbox Messages Mailbox Options Message Options make stop public (or join with public stop next) costs %i per tile and level Make stop public (or join with neighbouring public stop), costs %i$ per tile and level Map roughness Map roughness: map view Map map zoom zoom Margin (%%) Margin Marker Place Marker Max income: Max. Income: Max. waiting time Max. Waiting time (dd:hh:mm) Maximum 254 stops\nin a schedule!\n Maximum of 254 stops\nin a schedule!\n maximum length of rivers Max. length of rivers Maximum tile height difference reached. The maximum height\ndifference between\ntwo tiles has\nbeen reached. Maxspeed Maximum Speed Median Citizen per town Median citizens per city: Meldung Message Menge amount MessageOptionsText \nNew Year\n\nPlayers News\n\nCity News\n\nNo Route\n\nNew Destinations\n\nNotification\n\nNew Vehicles\n\nStation Full\n\nProblems\n\nTraffic Jams\n\nScenario\n\nGeneral Chat\n\nCompany Chat\n\nPrivate Chat\n\n min min. minimum length of rivers Min. length of rivers Minimum load Minimum load (%%) Missing pakfiles Objects are missing! Monate alt months old. monorail_track Monorail Track Monorailboden Elevated way Monoraildepot Monorail Depot Monthly departures Fixed departure times Mountain height Mountain height: Movingobj moving object Music playing disabled/not available Music disabled/unavailable. mute sound Mute sound Narrowgauge Narrow-gauge Narrowgauge are not available yet! Narrow gauge tracks are not available yet. narrowgauge_track Narrowgauge Track Narrowgaugedepot Narrow-gauge depot Net ID: %p Net ID: %p\n Neue Karte New Game Neue Welt Create a New Game new convoi New convoy New Line New line no convois No convoys No goods are loaded onto this convoi. No goods will be loaded onto this convoy no load Unload only No stop here! Tool must be used on stop tiles. No terminal station here! Can't build a terminal \nstation here! An end piece \nof flat road/track is needed. no timeline all eras no tree No trees No. of Factories Factories and shops: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "Where do I go?"\nYou must give this convoy a schedule or assign it to a line before giving it the go order. nord North nordost Northeast nordwest Northwest Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! The vehicle's schedule\nmust not be changed\nduring route-finding. Not enough fields would remain. Not enough fields would\nremain around this farm. Ok OK Oktober October on the departure/month first at (dd-hh-mm) On this map, you are not\nallowed to change player!\n This game is locked.\nNo player changes are possible.\n Only city chains Build city industry chain Only land chains Build land industry chain open open. Operation Operation Costs Ops Profit Operational Profit Optionen Options ost East Pak which may cause severe errors: Following objects (pak) are missing, which may cause failure of transport chains: Pak which may cause visual errors: The following objects (pak) were replaced by similar objects: Pak(s) different: Different pak(s): paletten crates Pas_tab Passenger Trains Passagiere Passengers Passagierrate Passenger level Passagierziele Pass./mail destinations Password Password: Pause Pause/Unpaused Pax <%i> Mail <%i> Passengers <%i> Mail <%i> PaxDest Destinations Percent Electricity Electricity output (%% demand): personal_chat Private chats Pipette Rebuild the selected object Planes are not available yet! Aircrafts are not yet available. Plant tree Plant trees player Player player -1 Human player player 0 public service player 1 Napik 128 AS player 11 Player 11 player 12 Player 12 player 13 Player 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Freight Forwarder VM player 5 H-Trans Ltd player 6 PSK & Co KG player 7 Player 7 player 8 Player 8 player 9 Player 9 Please choose vehicles first\n Please choose vehicles first!\n Post Mail Postrate Mail level Problems_msg Problems Production of %s has been stopped:\n%s\n Production of %s has been discontinued:\n%s\n Produktion Production: promote to line Promote to line public_chat General chat q1 Spring q2 Summer q3 Fall q4 Winter Random map Random Map Rathaus City Hall ratio_pax Pass. Ratio Reliefkarte Map Remove Remove label remove airstrips Remove runway or taxiway remove channels Remove channels remove interm. signals Remove interm. signals remove maglev tracks Remove maglev tracks remove monorails Remove monorails remove narrowgauge tracks Remove narrowgauge tracks remove powerlines Remove powerlines remove roads Remove roads remove tracks Remove tracks replace other signals Replace other signals replace stop Replace stop residential house Residential houses Restwert: Resale Value: Retire. date: Retire Date: return ticket copy backward Revenue Vehicle Earnings Revert schedule Revert changes Roadsign Road Sign Rotate Building Rotate building Running cost Running costs sack bags sail wind Save Save game Scenario Debug Debug Scenario Error Log Script Errors Scenario Info Short Info Scenario information Current scenario details Scenario Result Progress Scenario Rules Rules Scenario_ Scenario Schienentunnel Build railroad tunnel Schiff_tab Ships Schiffdepot Shipyard Schleppkahn_tab Barges Sehenswuerdigkeit Tourist attraction Sell the selected vehicle(s) Sell the selected vehicle(s). sended Sent Mail SEP_FRACTION . SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 Serves Line: Serves line: set signal spacing Set signal distance Setting Settings shops and stores Shops and offices show all building Show all buildings Show also vehicles no longer in production. Show also vehicles that are no longer in production. Show also vehicles that do not match for current action. Show also vehicles that can't be used by the selected action. Show contour Show heights Show even servers with wrong version or pakset Show also servers providing the wrong version or pakset. show grid Show grid Show industry Industry List Show legend Selections Show map scale Colour Codes Show outline infrastructure only show station coverage Show station coverage show waiting bars Show waiting bars Show/hide statistics Show/Hide Statistics Shows buttons on network overlay. Show option to overlay a connection network. Shows consumer/suppliers for factories Show consumers/suppliers for factories Shows the currently selected schedule Show the currently selected schedule shuffle midis Shuffle tracks signal spacing Signal spacing Sim: Simloops: sliced underground mode Sliced map view Sort by sort by special freight Special freight Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Speedbonus in percent\nrequires minimum speed for road %i km/h,\nrail %i km/h, ships %i km/h, planes %i km/h, Speedlimit Speed limit Speichern Save Spieler Player Spieler(mz) Players Spielerliste Player List Spielstand wurde\ngeladen!\n \nGame successfully loaded.\n Spielstand wurde\ngespeichert!\n \nGame successfully saved.\n Sprache Language Sprachen Languages Stadtinformation City Statistics Start the selected vehicle(s) Dispatches the selected vehicle(s). Starte Spiel Start Game station labels Stations Station tiles: Station Tiles: Station_msg Stations Status Stop status Step timeline one year Step time-line by a year. Strassendepot Garage Strassentunnel Build road tunnel sued South suedost Southeast suedwest Southwest Suppliers Suppliers: Tage alt days old. The generated script was saved!\n Marko saved sucessfully.\nCan be replayed with script tool. There are still vehicles\nstored in this depot!\n There are vehicles\nin this depot!\n This Month This month: This Year This Year: Tile not empty. Clear the tile before\nusing a Slope Tool. timeline Obey era tl_title City List To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Traffic in %1$s on the rise:\n%3$i tax payer made the construction\nof %2$s reality. To heavy traffic\nresults in traffic jam.\n Heavy traffic\ncauses a traffic jam.\n tonnen t Total inhabitants: Total inhabitants: Tourist attractions Tourist attractions: Tourists Attractions Town_msg New Destinations Town: %s\n City of %s.\n Towns Cities traffic settings Traffic Trains are not available yet! Trains are not yet available. tram_track tram track Tramdepot Tram depot Trams are not available yet! Trams are not yet available. Transformer only next to factory! Transformers must be on\nempty flat ground\nadjacent to a factory! transparencies Transparency transparent station coverage Transparent station coverage Transported Trips TrolleyBus_tab Trolleybuses tt_Other Other Tunnel muss an\neinfachem\nHang beginnen!\n Tunnels must\nstart on a straight\nslope!\n Tunnel must start on single way! Tunnels must start on a single way. Tunnelboden Tunnel underground mode Underground view UNDO failed! Undo is not possible anymore.\nYou can undo a route \nconstruction only as long as \nno signals/stations/stops or \nanything else was built on \nthe way. units/day units/month Update Line Edit line upgrade HQ Upgrade HQ Use timeline start year Use timeline from year: Vehicle %s can't find a route! Vehicle %s\ncan't find a route! Vehicle %s is stucked! Vehicle %s is stuck! Vehicle details Vehicle Details Verbrauch Consumption: Vergroessere die Karte\n Enlarge map.\n Verkauf Remove Now! verkaufen Sell Verkehrsteilnehmer City Cars Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n You have %d months\nto pay off your debt.\n vh_title List of all vehicles via via (detail) via %s\n via %s\n via Menge via (amount) voranstellen Put in front Waggon_tab Cars walking Walking Warnings_msg Traffic Wasser Water Water Canal Water level Water level: way %s cannot longer used:\n Way-type %s can no longer be used.\n way %s cannot longer used:\n%s\n way-type %s can no longer be used:\n way %s now available:\n Way-type %s is available now.\n Wegpunkt Waypoint Wert Value west West withdraw Retire WRONGSAVE \nIncompatible saved game.\nCannot load file.\n Zielort destination zooming in Zoom in zooming out Zoom out Zu nah am Kartenrand You cannot build\nso close to the\nedge of the map. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Levitating on magnets at\n%.1f km/h by %s:\nNew world record! New world record for monorails: %.1f km/h by %s. One rail built for speed:\nExactly %.1f km/h\nreached by %s\nmakes this a new world record! New world record for motorcars: %.1f km/h by %s. Only skid marks are left\nfrom speeding at %.1f km/h\nby %s\nto reach a new world record! New world record for planes: %.1f km/h by %s. Shrinking distances again:\n%2$s flew %1$.1f km/h.\nNew world record! New world record for railways: %.1f km/h by %s. Thundering over the tracks\nat %.1f km/h.\n%s sets a new world record for trains.\m New world record for ship: %.1f km/h by %s. Blue Riband for cruising\nat %.1f km/h was won by\n%s. #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Mirrors order of stops Invert stop order Revert to original schedule Revert all schedule changes. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL wick &1_CITY_SYLL chester &2_CITY_SYLL ton &3_CITY_SYLL ville &4_CITY_SYLL den &5_CITY_SYLL borough &6_CITY_SYLL ham &7_CITY_SYLL field &8_CITY_SYLL mouth &9_CITY_SYLL lock &A_CITY_SYLL cross &B_CITY_SYLL by &C_CITY_SYLL bury &D_CITY_SYLL stead &E_CITY_SYLL well %0_CITY_SYLL Pine %1_CITY_SYLL Apping %2_CITY_SYLL Malli %3_CITY_SYLL Ash %4_CITY_SYLL Spring %5_CITY_SYLL Polling %6_CITY_SYLL Baring %7_CITY_SYLL Hepp %8_CITY_SYLL Brent %9_CITY_SYLL Ren %A_CITY_SYLL Old %B_CITY_SYLL Hill %C_CITY_SYLL New %D_CITY_SYLL Tor %E_CITY_SYLL Wal %F_CITY_SYLL Oak 1center %s %s 1extern %s branch %s 1suburb %s %s %s 2center %s central %s 2extern %s external %s 2suburb %s Greenfields %s %s 3center %s main %s 3extern %s land %s 3suburb %s village %s %s 4center %s inner %s 4extern %s outer %s 4suburb %s rural %s 5center %s downtown %s 5extern %s transfer %s 5suburb %s town %s 6center %s hub %s 6extern %s exchange %s 6suburb %s outskirt %s %s 7center %s city %s 7extern %s plains %s 7suburb %s park %s 8center %s business %s 8extern %s %s margin %s 8suburb %s satellite %s 9center %s axis %s 9extern %s bypass %s 9suburb %s mezzo %s simutrans-124.3/simutrans/text/en/000077500000000000000000000000001474050137200171665ustar00rootroot00000000000000simutrans-124.3/simutrans/text/en/airtools.txt000066400000000000000000000107511474050137200215670ustar00rootroot00000000000000Airport Tools

Airport Tools

Airport Tools contain tools to construct an air transport network. Tools may build or remove: taxiways & runways for aircraft, Airstops (used to pick-up & drop-off, cargo or passengers), aircraft depots (to purchase and manage air transport vehicles) and and various airport buildings. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click airplane-icon at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, maintenance cost in brackets, and maximum speed limit.

{Tips: One way to build a simple airport is:
i) construct and connect Taxiway(s) and Runway(s);
ii) place airstop(s) on end(s) of taxiway(s);
iii) add airport buildings as required.}

Tools may include, from left to right:

Taxiway: tool builds ground movement areas for aircraft to go from an Airstop to a Runway. Taxiways are built on level ground in game-view.
IMPORTANT: If Taxiways are connected to the end of Runways aircraft may not take-off and land.
To build a Taxiway: click on tool to select (changes cursor to taxiway), then click on terrain for start-point (shows a bulldozer in game-view and displays map co-ordinates at bottom right of display), & finally click on terrain or runway for end-point.
{Tips: Use Destroy/Remove to remove individual pieces of Taxiway. Undo [z] does not refund constructions costs.}

Runway: tools build an airstrip, used by aircraft to take-off and land. Runways are built on level ground in game-view and may cross each other.
To build a Runway: click on tool to select (changes cursor to way), then click on terrain for start-point (shows a bulldozer in game-view), & finally click on terrain for end-point.
{Tips: Leave ends of Runways unconnected otherwise aircraft may not take-off or land. Use Destroy/Remove to remove individual pieces of Runway. Undo [z] does not refund constructions costs.}

Remove airstrips: tool removes a segment of Taxiway or Runway, when no aircraft are present, between two points in game-view. Use of tool incurs a construction cost.
To remove an airstrip: click on tool (changes cursor to a red-cross); then click on strip that is to be deleted (selects deletion-point shown by a red-cross in game-view); & finally click at another point on strip, to remove portion up to first deletion-point. {Tips: Leave end of Runways unconnected otherwise planes may not take-off or land. Use Destroy/Remove to remove individual pieces of airstrips.}

Air Depot: tools build hangars for purchasing & managing aircraft. Hangars have a maintenance cost & are built on the end of a piece taxiway.
To build a Hangar: click on tool (changes cursor to a depot), then click on an end of a taxiway.
{Tips: Remove depots with Destroy/Remove.}

Airstops&boarding bridge: tools build Stops in game-view, for aircraft to pick-up and drop-off passengers or cargo.
An Airstop when not built adjacent to an existing Stop will create a new Stop.
Airstops are built on the end of a piece taxiway; and have a maintenance cost and catchment area for goods, passengers & mail. An aircraft will only land at an airport if there is an free Airstop available.
To build an Airstop: click on tool to select and then click on an end of a taxiway.
{Tips: Remove Airstops with Destroy/Remove. Press [v] to show/hide catchment area for goods & passengers in game-view.}

Airport buildings: tools construct extensions for Stops which may increase maintenance costs and the capacity & catchment area for goods & passengers. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the extension enables the Stop to handle.
To build an extension: click on tool to select extension (changes cursor to extension), then click required position, next to an existing Stop in game-view. The new extension is now considered to be part of the Stop.
{Tips: Remove extensions with the Destroy/Remove. Press [v] to show/hide catchment area for goods & passengers in game-view.}

simutrans-124.3/simutrans/text/en/baum_build.txt000066400000000000000000000042411474050137200220330ustar00rootroot00000000000000Plant trees

Plant trees

The Plant trees window allows planting of individual trees. It is a map customisation option, available if you switch to public service player and then open the Map Editing Tools.
TIP: There is also an Add forest button available on this bar, used to add forests at once.

The dialogue is divided into four sections:
1) Top left: Filter and sort options.
2) Bottom left: A selection list of available trees.
3) Top right: Placement options.
4) Bottom right: Information and picture of the chosen tree.

1 - Filter and sort options

· Climate: Filter by allowed climates.
· Sort by: Sort the list by any of the following parameters:
·· Translation: Show and sort by names in the given language as defined in the pakset. If there is no translation available, the object name will be used.
·· Object: Show and sort by Simutrans internal object name.

2 - Selection list

In the selection list are shown all urban buildings that are available with the options specified. Click on a tree in the list to see more information about that particular tree. To plant the tree, click in the game-world window on the desired location after selecting it from the list.

3 - Placement options

· Ignore climates: This option deactivates the climate restrictions, allowing you to plant the tree on non-allowed climates.
· Random age: If active, the age of the tree to be planted will be randomized. Normally, they are planted at the youngest age, they will grow to maturity and then die over the course of many years.

4 - Information

Information about trees contains:
· Name: Name of the tree.
· Allowed climates: Climates where the tree is allowed to be planted (if "Ignore climates" option is not set).
· Seasons: Number of seasons.
· Author: The name of the author who painted the object (if available).
· Image: Image of the tree.

simutrans-124.3/simutrans/text/en/chat.txt000066400000000000000000000061421474050137200206510ustar00rootroot00000000000000The Chat Window

The Chat Window

The chat window can be accessed during multiplayer-games, via the main toolbar. Messages can be exchanged with all active players.

On top, you will find the 'transparent background' checkbox, by which the see-through feature can be toggled on and off. This can be especially helpful on small-screen-devices.
Following, the three tabs are listed, housing the three different chat types:
- General chat
- Company chat
- Private chat
Afterwards the message log is shown, where all messages are displayed as speech bubbles. If nothing is displayed in this area, then simply no messages have been sent yet.
At the bottom are placed the input line and next to it an arrow-symbol, which allows you to add the current view's coordinates to your message. Attached coordinates will be shown as an arrow-symbol in the chat log, next to your speech bubble.

For to send a message, click in the input line and type your text and send it by pressing the enter key.
Your message will immediately appear in the log.
For the cursor to leave the input line simply hit enter again or just click anywhere.
The esc key will close the chat window, if still active.

Received messages are displayed, other than in the log only, also prompted in the news bar at the bottom of the screen and are indicated by a white number on a red dot within the chat-window-button in the tool bar.

Messages in the general chat are public, so any member of the game can see them.
Further, the general chat's log will persist for the hole duration of the current multiplayer map.

Company chat messages are visible "but" for players active in the same company. Tough anybody can select any given company and therefore read their company chat, even if the company is password protected.
This chat log will be conserved throughout the duration of the map as well.

The private chat allows two co-players to exchange messages without anyone else being able to read along.
While in this tab any currently active co-player can be selected and texted to.
Alternatively the arrow-symbol next to a player's name in any log can be clicked on to, to directly transit to the private-chat.
The private chat's log will be erased when leaving the multiplayer session.

Please note:
- hitting the tabulator key will send any existing text in the input line as well. Further, typed in text can unintentionally get send, when simultaneously a new player gets connected to the current game. >
- Message length is limited to 226 characters. Word wrap (paragraphs) or emoji-graphics cannot be inserted respectively be displayed.
- Double-clicking on any bubble will copy it's contained text to your clipboard, accompanied by a notification 'copied'. This is especially helpful when exchanging article URLs from the forum for instance.

simutrans-124.3/simutrans/text/en/citybuilding_build.txt000066400000000000000000000077041474050137200236040ustar00rootroot00000000000000Build urban buildings

Build urban buildings

The Build urban buildings window allows placement of individual building. It is a map customisation option, available if you switch to public service player and then open the Map Editing Tools.

The dialogue is divided into four sections:
1) Top left: Filter and sort options.
2) Bottom left: A selection list of available buildings.
3) Top right: Placement options.
4) Bottom right: Information and picture of the chosen building.

1 - Filter and sort options

· Obey era: The selection list will only contain buildings that are available at the current Simutrans year. This is mutually exclusive with "Available at custom date" option.
· Available at custom date: The selection list will only contain buildings that are available at the specified date. This is mutually exclusive with "Obey era" option.
· Show obsolete: Expand the selection list to also contain buildings that are obsolete at the current Simutrans year.
· Climate: Filter by allowed climates.
· Sort by: Sort the list by any of the following parameters:
·· Translation: Show and sort by names in the given language as defined in the pakset. If there is no translation available, the object name will be used.
·· Object: Show and sort by Simutrans internal object name.
·· Pax Level: Sort by quantity of passengers generated or demanded.
·· Mail Level: Sort by quantity of mail generated or demanded.
·· Intro. date: Sort by date of introduction (when the building starts appearing).
·· Retire date: Sort by date of retirement (when the building stops appearing).
·· Size (area): Sort by size of building in tiles (Note: some paksets may only have buildings of one tile).
· Residential houses: Show/hide residential buildings.
· Shops and offices: Show/hide commercial buildings.
· Industrial buildings: Show/hide industrial buildings.

2 - Selection list

In the selection list are shown all urban buildings that are available with the options specified. Click on a building in the list to see more information about that particular building. To place the building, click in the game-world window on the desired location after selecting it from the list.

The color of the text has the following meaning:
· Blue text signifies a residential building.
· Green text signifies a shop or office building.
· Black text signifies an industrial building.

3 - Placement options

· Ignore climates: This option deactivates the climate restrictions, allowing you to plant the tree on non-allowed climates.
· Rotation: If the chosen building can be shown from different angles, then it is possible to chose a specific view of it here. The image will change to reflect this. If this option is set to random a random view of the building will be used.

4 - Information

Information about buildings contains:
· Type: Building type (Residential, Industrial, or Shop and offices).
· Name and Description: It will display only the description if it has no name. It will display the object name only if it has no name and no description.
· Allowed climates: Climates where the tree is allowed to be planted (if "Ignore climates" option is not set).
· Passenger level: Metric of quantity of passengers generated or demanded.
· Mail level: Metric of quantity of mail generated or demanded.
· Introduction date: Date since the building appears.
· Author: The name of the author who painted the object (if available).
· Image: Image of the building.

simutrans-124.3/simutrans/text/en/citylist_filter.txt000066400000000000000000000043561474050137200231500ustar00rootroot00000000000000City List

City List

The City List provides information about cities. This window consists of two separate tabs: one for a list of cities and another for charts.
Open the list by clicking on City List in the Lists menu or by pressing [T].

- Total inhabitants: the total number of citizens on the map (the total population of all cities). Recent increase in population is shown in brackets.

The City List tab lists every city on the map, displaying their names, population and growth factor.

Sorted by: provides options on how the list is sorted.

- Name sorts the list alphabetically by city name.
- Citizens sorts the list by population.
- City Growth sorts the list by growth rate.

- ascending / descending reverses the order of the list.

Click on an item in the list to reveal more information about that city.

The Charts tab provides information about the cities collectively.

- Citizens: total population of all cities (same as Total inhabitants).
- City Growth: total combined city growth of all cities.
- Cities: total number of cities on the map.
- Factories: total number of factories on the map.
- Convoys: total number of transport vehicles.
- City Cars: total number of city cars.
- Pass. Ratio: percentage of total passengers transported.
- Passengers: total number passengers generated (including those who have not been transported).
- Sent Mail: percentage of total mail delivered.
- Mail: total mail generated (including that which has not been transported).
- Arrived: the number of times the storage of every factory was checked where that storage was not empty.
- Goods: the number of times the storage of every factory was checked.

simutrans-124.3/simutrans/text/en/citywindow.txt000066400000000000000000000112441474050137200221310ustar00rootroot00000000000000City Statistics

City Statistics

City Statistics shows statistics about a selected urban area and can be used to change the name of it. An urban area is a city, town or village; below the term city is used for any urban area.

Each city has its own Town Hall around which it grows. Transportation of passengers and mail furthers growth, which involves roads being built or taken over by the public service player; new city buildings and industries appearing; and city limits extending.

Click on a Town Hall in game-view with the Inspection Tool or a city listed in City List to open City Statistics. Here you can see and modify the name of the city, some statistics, two mini-maps, and a graph where you can display the development over time for certain factors pertaining to the city.

Name: the assigned name of a city, town or village appears in a box at the top of City Statistics.
Names of such urban areas are used to create names for stops within the city limits. To change the name simply click on the box and type in a new name.
{Tip: Use [!] to toggle the display of the name of a city above the Town Hall in game-view. See readme_citylist.txt (in ...simutrans/text/) for more information on how city names are generated}.

Under the name box are given some basic city statistics:
City size: its current number of citizens. The recent increase in population is shown in brackets.
Buildings: number of city buildings (residential/commercial/industrial) in the city.
Map co-ordinates: indicating the boundary of city limits (these will change as the city grows). The first pair of values indicates the top left corner, and the second the lower right corner. As cities grow, city limits may overlap.

Current numbers of unemployed and homeless inhabitants of the city. These will increase when the city expands its limits, and decrease when new city buildings are erected. The balance between these counters determines which type of city building (residential/commercial/industrial) will be constructed.

The Allow city growth button allows you to toggle city growth on and off.

Mini-maps of the game world in City Statistics show the destinations of passengers and mail generated within the city as coloured dots.
The right hand mini-map shows values for the current game calendar month, and the left one for the last game calendar month. The colour of each dot indicates if the destination can be reached or not:
- yellow dot: there is a route and an uncrowded stop to start journey (happy face shown in Stop Information).
- dark orange dot: there is no route to this destination.
- orange dot: the stop at the start of the journey was overcrowded (unhappy face in Stop Information). There is no check for a route if station is overcrowded.

Below the mini-maps there is a graph showing statistics for the city.
On the y-axis quantity is shown and on the x-axis time. Click on graph index tabs to change the scale of the x-axis:
Years: shows annual values for last 12 game calendar years.
Months: shows monthly values for last 12 game months

By clicking on the graph option buttons, you activate and deactivate the curve for each given button. When a button is selected it is shown indented.
The curves match the colour of the corresponding option button:
Citizens: The number of people that live in the city
City growth: Changes in population (dependent on city size and transport service provided for passengers and mail).
No. of buildings: How many city buildings there are in the city.
City cars: How many city cars have been generated
Trips: How many passengers that have entered the transport network (shown as a happy face in Stop Information)
Passengers: The total number of passengers generated in the city.
Sent mail: Mail that has entered the transport network
Mail: Total number of mail generated in the city.
Supply:Number of times there were goods in storage at city factories
Goods:Number of times storage of city factories have been checked.

{Tip: Settings related to cities can be changed in simuconf.tab and cityrules.tab}.

simutrans-124.3/simutrans/text/en/climates.txt000066400000000000000000000065671474050137200215460ustar00rootroot00000000000000Landscape Settings

Landscape Settings

The Landscape Settings window sets options for topographical and meteorological aspects of the game-world. It opens along with Create a New Game window.

To adjust each setting, click the arrow-buttons on the side of each option, or input a number in the box.

Map Options

Water level - Sets how high the water is on the map (default -2). Higher values provide less land and more water bodies.

Mountain height - Sets the maximum height of terrain.

Map roughness - Sets the roughness of the terrain. A higher number creates more undulations in the coastal areas (they look more realistic). Very rough maps may not be able to generate as many cities, industries or roads as intended.

WARNING: Height levels larger that 33 should be avoided (they are not accesible by the player). More ground levels can be generated, if needed, by lowering the water level.

Snowline Options
Snowline is the height on the map above which snow appears. During a year, the snowline in Simutrans varies according to the next settings.

Summer snowline - The snowline during summer (eternal snow). This value is the highest terrain value selected in the climate options. Arctic climate begins from here.

Winter snowline - Sets the minimum height of snowline in winter. To have snow appear in larger areas on the map, keep this value low.

Climate Options
Sets different climate types for the new map.

The value next to each climate type sets the height in the terrain map up to where the climate appears. Higher climate zones are covered by lower climate zones in the lower areas. To turn off a particular climate, set its value to the same as a climate further up in the list (or to water level in case of Desert).

NOTE: Buildings, industries and vegetation have been assigned specific climates by their creators.

Desert climate - Very little precipitation, extremes in temperature. Very few trees. Flat landscape.

Tropical climate - Typical of non-arid areas around equator, constant high temperature at sea level and low elevations.

Mediterranean climate - Moderate changeable wet weather.

Temperate climate - Found in areas between tropics and polar caps, changing weather.

Tundra climate - Low temperatures, edges of polar caps.

Alpine (rocky) climate - Dry climate, cold winters.

Other Options

No trees - Enable this option to prevent Simutrans from drawing trees. Trees take up CPU time to render. Use this option on PCs with slower CPU or low RAM.

Lakes - Enable this option to let Simutrans create lakes throughout the map by filling some pits in the ground with water.

Number of rivers - Sets the maximum number of rivers that can be generated and used in a terrain map. Narrow rivers cannot be navigated by boats or ships of any kind.

Min. length of rivers - Sets the minimum length of rivers on the map (in tiles).

Max. length of rivers - Sets the maximum length of rivers on the map (in tiles).

simutrans-124.3/simutrans/text/en/color.txt000066400000000000000000000013521474050137200210460ustar00rootroot00000000000000Player Colour

Player Colour

Player Colour sets the colour of the company.
Vehicles, buildings & other items show company colour.

Player Colour opens from Game Options.

Click on colour-bar to change company colour.
Titlebar of Player Colour changes (not to new company colour) to indicate new colour is selected.

Default human player colour is light blue.
Some items are not colour-coded & may not display chosen colour.

{Tips: To change AI player colour use Player List or P+ Change Player to select AI player first}.

simutrans-124.3/simutrans/text/en/convoi.txt000066400000000000000000000060141474050137200212250ustar00rootroot00000000000000Vehicle List

Vehicle List

Vehicle List shows information and has controls to filter and list different Convoys (a Convoy is made up of an operational vehicle or combination of vehicle units).

To open: click on vehicle-list tool in List Management or press [V]. Vehicle List has four option buttons: two are used to order items in the list and two are used to change settings for what is shown in the list.
Below buttons is a list of Convoys that fit criteria for filter options.
{Tips: If no Convoys are listed change Filter options. If items in list are only partially visible, then re-size Vehicle List or scroll list using slider-bar.}

Click on option-buttons to cycle through options (changes name of option-button) or open Filter Settings controls :

Sorted by: Two option buttons determine the order of Convoys shown in list.

- Type orders by type of transport (in ascending order of road vehicle, rail vehicle, boat and aircraft)
- Name orders by assigned name, alphanumerically within ASCII-code order: capital letters before lower case letters (by default this is make of first vehicle unit purchased or assembled for Convoy).
- Income orders by profit (income generated minus operating costs).
- Internal ID orders by unique ID number of convoy (assigned by default when Convoy is first purchased or assembled in a depot and shown in titlebar of Convoy Information).

- ascending / descending reverses order of list.

Filter: Two option buttons, switch on/off selection criteria for list and access controls to change criteria.

- enabled / disabled click to toggle filter criteria for Convoys in list.

- Settings opens controls to change filter criteria.

Click on a item listed to see more information about that Convoy.

Items listed for each Convoy include:

Internal ID: a unique ID number of convoy (assigned by default when Convoy is first purchased or assembled in a depot and shown in titlebar of Convoy Information).

name that has been assigned (by default this is make of first vehicle when Convoy is purchased or assembled).

income shows profit (income generated minus operation costs incurred).

Line: shows assigned Line and indicates if the Convoy is in a depot.

graphics show the composition and the current load level.

simutrans-124.3/simutrans/text/en/convoi_filter.txt000066400000000000000000000035041474050137200225730ustar00rootroot00000000000000Vehicle List Filter

Vehicle List Filter

Vehicle List Filter has options to determine which Convoys, are shown in Vehicle List.

Click on Settings in Vehicle List to open Vehicle List Filter.

Option-buttons select Convoys to be listed in Vehicle List when filter option is enabled. Only Convoys that fit all criteria set, are listed.

Click on a square-button to set criteria for filter (button is indented when selected):

Filter names: selects Convoy by name. To use: click on button to select, then click on name-box and type required name exactly (option is case sensitive).

Filter types: will list Convoys by type of transport if selected. To use: click on button to select, then click on transport type(s): road, rail, water and air.

Special filter: selects Convoys to list by following criteria (click on button to select, then click on):
- no route - cannot find a path to next destination.
- no schedule - not assigned a route.
- no income - not generating profit.
- in a depot - those in a depot.
- no line - not assigned a Line.

Filter goods: selects Convoys by ability to transport different goods & passengers. Click on button next to name to select item(s). Use slider-bar to scroll item(s) in list. Options include:
- all selects all items.
- none no items are selected.
- inv. inverses current selection of items.

simutrans-124.3/simutrans/text/en/convoidetail.txt000066400000000000000000000034441474050137200224140ustar00rootroot00000000000000Convoy Details

Convoy Details

Convoy Details provides more information about a Convoy (an operational vehicle or combination of vehicle-units) and can be used to sell the Convoy immediately.

Convoy Details can be opened from the Details option-button in Convoy Information.
If not all vehicle-units are visible re-size Convoy Details or use the slider-bars to scroll.

At the top of Convoy Details, the information shown includes:

Power: of Convoy (combined power of all vehicle-units in Convoy).

Resale Value: money received if Convoy is sold (purchase price of Convoy less any depreciation).

WARNING: Click on Sell mode option-button to sell Convoy immediately. No further confirmation is required. The Convoy is removed from the game and the player balance credited with the selling price.

Convoy Details lists all the vehicle-units in Convoy.
Information listed for each vehicle-units includes:
- vehicle-unit-graphic a picture of the vehicle-unit (also used in depots)
- Manufactured: month and year of manufacture, and introduction date if playing with timeline
- Resale Value: amount received if sold
- Power: power generated (by motorised vehicle-units)
- Friction: current friction level
- Max income: Maximum possible income of this vehicle-unit based on type of item transported by this Convoy
- items on board amount and destination of items currently carried by this vehicle-unit.

simutrans-124.3/simutrans/text/en/convoiinfo.txt000066400000000000000000000154021474050137200221020ustar00rootroot00000000000000Convoy Information

Convoy Information

Convoy Information provides information about a Convoy (an operational vehicle or combination of vehicle-units) which is used to transport goods and passengers.
It lists items carried by a Convoy and also has controls to access further details and sell the Convoy; follow the Convoy in game-view; and change the name and Schedule of the Convoy.

A Convoy is composed of at least one powered (motorised) vehicle-unit and any attached trailers/carriages.
Examples of Convoys include: a team of horses pulling a carriage; or a train engine attached to a tender and carriages; or a bus; or a van; or a truck attached to a trailer; or connected tram cars; or a ship; or a tugboat pulling a barge; or an aircraft.
Convoys are assembled and purchased from the depot for their type of transport.
{Tips: ?A Convoy has a maximum limit to number of vehicle-units in its composition: trains, 24; road vehicles, 4.}

Click on a Convoy in game-view with the Inspection Tool or click on a Convoy listed in Vehicle List or Line Management to open Convoy Information.
The title-bar of Convoy Information shows the name and the unique ID number of the Convoy (see below for more about these).
Convoy Information contains a name-box; a mini-view; information about the Convoy; option buttons; and a list of all items currently carried (if not all items are visible re-size Convoy Information or use the slider-bars to scroll).

Information shown at the top of Convoy Information includes:

Internal ID: a unique ID number for the Convoy (assigned by default when the Convoy is first purchased or assembled in a depot).

- name: shows the assigned name of the Convoy (by default this is the make of the first vehicle-unit purchased or assembled in a depot for the Convoy).
Click on the name-box and type the new name to change the name of the Convoy.

- speed: The current speed is shown in km/h.
The maximum possible speed of the Convoy is in parentheses (determined by the slowest vehicle unit in the Convoy).
A green progress-bar indicates the current speed relative to the maximum speed.

- Income: profit made by vehicle (income generated less operation costs) in current game-calendar-year.
The operational cost of the Convoy in Hajo Credits per game square is in parentheses.

- Weight: current combined weight of the Convoy and items carried by it, in tonnes.
The current weight of items carried is in parentheses.
A green progress-bar indicates the percentage of capacity used to carry goods and passengers.
A yellow bar indicates a Wait For level (minimum quantity of goods and passengers required by Convoy to proceed) set in Schedule Controls.
{Tips: To set or change Wait For levels for all Convoys on a Line, use the Update Line option-button in Line Management or Depot Controls. To set or change the Wait For level for a Convoy and no other Convoy on its assigned Line, use the Schedule option-button in Convoy Information or Depot Controls.}

- Destination: The next stop or waypoint in the Convoy's Schedule.
A green-progress-bar indicates the progress by Convoy to its next destination.

- Serves line: Line assigned to this Convoy. The triangle opens the line in the Line management window. (Only visible if a line is assigned.)

- mini-view shows this Convoy. Click on the mini-view to centre the game-view on this Convoy.

Click on buttons in Convoy Information to open controls or select options:

Schedule: opens controls to change the route and the minimum quantity of goods and passengers required by Convoy to proceed.

go to depot: sends Convoy to the nearest appropriate depot. Any items being carried are lost, though income is received for transportation to depot.
In the depot the Convoy keeps its Schedule and assigned Line.

follow me: button when indented moves game-view with Convoy.
To deselect this option, click on the button again or left-click on the main Map.

Chart: click this option-button to toggle the graph (button is indented when graph is visible) in Convoy Information.
The graph shows statistics for the last 12 months (x-axis) when a graph-option is selected.
Click on a graph-option-button to see the selected information on the graph (button is indented when option selected).
The colours of lines on the graph correspond to the colours of the graph-option-buttons:
- Free Capacity indicates unused space in the Convoy.
- Traveled indicates the number of goods, passengers and mail transported.
- Proceeds indicates income generated by transportation.
- Operation Costs indicates costs incurred by Convoy when in transit.
- Profit indicates profit received from transportation (Proceeds less Operation Costs).

Details opens Convoy Details which contains more information and an option to sell the Convoy immediately.

Sort Passengers/freight by: lists items currently carried by the Convoy.
Information shown includes quantity carried, capacity of Convoy, type of item, final destination and next transfer stop.
The option-button (which changes its name with your selection) sorts the list of items (passengers, mail, and goods) carried:
- destination: sorts items by assigned name of final destination stop, alphanumerically by ASCII-code order (capital letters before lower case letters).
- via (detail): sorts items carried by assigned name of first transfer stop, alphanumerically by ASCII-code order (capital letters before lower case letters).
- via (amount): sorts items carried by quantity headed to first transfer stop.
- amount: sorts items carried by quantity in descending order.

simutrans-124.3/simutrans/text/en/curiosity_build.txt000066400000000000000000000042061474050137200231420ustar00rootroot00000000000000Build attraction buildings

Build attraction buildings

The dialogue is divided into four sections.
· top left is a selection list of available buildings
· bottom left is shown a picture of the chosen building
· top right some options may be set
· bottom right is information about the chosen city building given

Selection list

In the selection list are given all special buildings and landmarks that are available with the options specified top right (City attractions, Land attractions, Monuments). There are two tabs that will allow you to change how the attraction buildings are identified.
· Translation: Shows the name of the building in the given language. If there is no translation available in the given language, the object name will be used.
· Object: Shows the Simutrans internal object name for the building type.

The color of the text has the following meaning:
· blue text attraction has to be built in cities
· green text attraction has to be built on the countryside
· black text monuments: can only be built once

Options

· ignore climates: This option deactivates the climate restrictions associated with various building types.
· Use timeline year: The selection list will only contain buildings that are available the current Simutrans year.
· Show obsolete too: Expand the selection list to also contain buildings that are obsolete the current Simutrans year.
· City attraction: There will be city attractions in the selection list.
· Land attraction: There will be land attractions in the selection list.
· Monuments: There will be monuments in the selection list.
· Rotation: If the chosen building can be shown from different angles, then it is possible to chose a specific view of it here. The image bottom left will change to reflect this. If this option is set to random a random view of the building will be used.

simutrans-124.3/simutrans/text/en/curiositylist_filter.txt000066400000000000000000000041261474050137200242250ustar00rootroot00000000000000Attraction List

Attraction List

Attraction List has information about all tourist attractions that are both a destination and an origin for passengers and mail.

To open Attraction List: click on attraction-list-tool in List Management.
{Tips: If items in list are only partially visible, then re-size Attraction List or scroll list using slider-bar.}

Sorted by: has options to determine the order of tourist attractions shown.
Click on buttons to cycle through options (changes name of option-button):

- Name orders alphabetically by name.
- Passenger level orders by relative popularity as a destination for passengers and mail.

- ascending / descending reverses order of list.

Click on a item listed inAttraction Listto see more information about that tourist attraction.
{Tips: click on picture of tourist attraction in more information to move game-view to that attraction.}

Items listed for each tourist attraction include:

status-colour-bar colours indicate the rating of the attraction:
- yellow:does not fall in the catchment area of a Stop.
- green: has associated Stop(s) for passengers.
- blue: has associated Stop(s) for mail.
- turquoise: has associated Stop(s) for passengers and mail.
- orange: an associated Stop is overcrowded.
- red: all associated Stops are overcrowded.

building-graphic indicates if it is a city attraction.

name of the tourist attraction.

passenger level in brackets is a value that indicates the relative popularity as a destination for passengers and mail.

{Tips: For provision of an optimum service the whole tourist attraction must fall within the catchment area of either one or several Stops.}

simutrans-124.3/simutrans/text/en/depot.txt000066400000000000000000000166361474050137200210560ustar00rootroot00000000000000Depots

Depot Controls

Depots are used to purchase and manage vehicles. Different types of transport have their own depot. Depots only show electric vehicle-units if on electric tracks.
If playing with timeline, then as time passes in Simutrans more vehicle-units may appear.

Tools for the construction of different depots are available from the construction toolbar for the type of transport: Train Depot; Monorail Depot; Tram Depot; Road Depot; Ship Depot and Aircraft Hangar.

Click on a depot in game-view with the Inspection Tool to open Depot Controls that give information about and allow the purchase and management of Convoys (an operational vehicle or combination of vehicle-units).
The titlebar of Depot Controls indicates which type of vehicle transport the depot serves.

Depot Controls can be re-sized (click on down-arrow on titlebar of controls to return to original size).
Click on left/right-arrows on titlebar to cycle through depots of the same transport type (centres game-view on depot).

At the top of Depot Controls the number of Convoys in depot, Convoy name and Line is shown.

Convoy Name: Click on left/right-arrow-buttons by Convoy Name to cycle through Convoys in depot.
To change Convoy Name: click on convoy-name-box and type new name (by default this is make of first vehicle-unit purchased or assembled for a new Convoy).

Line Name: Click on left/right-arrow buttons by name to select Lines for transport type of depot or click on line-name-box to open a drop-down-list of Lines (click on Line in drop-down-list to select).
To change Line Name: click on line-name-box and type new name. (by default this is assigned number when Line is created).

convoy-graphic Below the Convoy and Line name-boxes, a graphic of any selected Convoy is shown.
Move mouse over a vehicle-unit-graphic in the selected Convoy to see details about the vehicle-unit (shown at bottom of Depot Controls).
Click on a vehicle-unit in the convoy-graphic to remove it from the selected Convoy and store it in the depot.

Below the graphic the number of vehicle-units in the selected Convoy, length of tiles of the Convoy (all vehicle-units must fit into an appropriate Stop to pick-up and drop-off goods and passengers), and assigned Line are shown.

Option-buttons (click to use) for Depot Controls include:

Start: sends the selected Convoy out of the depot if a route can be found. You can hold Ctrl to start all convoys.

Schedule: opens controls to change the route and quantity of items that a Convoy will wait for at a Stop.

Disassemble: puts the vehicle unit(s) in selected Convoy into storage.

Sell: sells the current Convoy, account balance is credited with Resale Value. You can hold Ctrl to sell all convoys.

New Line: opens controls to define a Schedule (a route and minimum quantity of items that a Convoy will wait for at a Stop), which may be used for multiple Convoys.

Assign Line: assigns Line displayed in line-name-box at top of Depot Controls to selected Convoy.

Update Line: opens controls to change the Schedule (a route and minimum quantity of items that a Convoy will wait for at a Stop) of selected Line.

Copy Convoy: purchases and assembles another Convoy with the same compostion, Schedule and Line as the selected Convoy.

Below option-buttons graphics of all vehicle-units available for purchase are shown.
vehicle-unit-graphics: vehicle units are split into categories, which can be viewed by clicking on the index-tabs. Index-tabs divide vehicle-units into following groups: vehicle-units for passengers and mail, other powered (motorised) vehicle-units, and other trailers/carriages.
A white number over vehicle-unit-graphic indicates quantity stored if a Convoy has been disassembled. Stored vehicle-units can be sold or are used when a new Convoy is assembled.

Move mouse over a vehicle-unit-graphic to see information about vehicle:
Name: and in brackets type of power used for motorised vehicles.
Cost: purchase price and in brackets operation cost per kilometre
Power: engine power and maximum speed for motorised vehicle-units.
Capacity: quantity and goods category that can be carried by vehicle-unit.
Weight: in tonnes.
top speed: of non-motorised vehicle-units.
Intro. date: date when vehicle unit becomes available if timeline is on.
Retire date: date vehicle-unit becomes obsolete.
Constructed by: person who created vehicle-unit for Simutrans.
Gear: ? power ratio.
Resale Value: amount of money received if a previously purchased vehicle-unit is sold.

Click on a vehicle-unit-graphic under index-tabs to either purchase or sell it depending on setting of vehicles-option-button which is found at bottom-left of Depot Controls. The vehicles-option-button cycles through three options:
Append: purchases a vehicle-unit and adds it to a selected Convoy, or creates a new Convoy.
Put in front: purchases a vehicle-unit and adds it to front of current Convoy, or creates a new Convoy.
Sell Mode: sells stored vehicle units.

color bars under the vehicle-unit-graphics indicate which vehicle-units and the order vehicle-units can be attached to each other, to form an operational Convoy (colour bars may change with different settings of the vehicle-option button).
Colours indicate:
- green: vehicle-unit can be used.
- red: vehicle-unit can not be used
- yellow another vehicle-unit must be placed in front or behind to make an operational Convoy.
- blue: vehicle-unit can be used but is obsolete.
{Tips: a Convoy is operational, if it shows green-bars for all vehicle-units; if a part-yellow-bar remains then a missing component vehicle-unit is required.}

Show obsolete: if playing with timeline, square-button when indented (click to use) displays vehicle-units that have been retired.

simutrans-124.3/simutrans/text/en/depotlist.txt000066400000000000000000000005221474050137200217350ustar00rootroot00000000000000Depot list

Depot list

This dialog lists all the depots on the map. By using a tab, they could be filtered by the vehicle types. Right click on an entry or click on the arrow to change the position on the map to the depot area or left click on the entry to open the dialog of the depot.

simutrans-124.3/simutrans/text/en/display.txt000066400000000000000000000115111474050137200213730ustar00rootroot00000000000000Display Settings

Display Settings

Display Settings window has controls for how the game appears and provides information on computer performance.

Click on Display button in Game Options menu to open Display Settings window.

Click on square buttons to select options (buttons are indented when the relevant option is selected), or use the arrow-buttons to adjust settings:

Show grid: shows the lines between individual tiles; can be useful when terraforming.

Underground view: reveals beneath the ground; here you can build transport networks using tunnels; all levels of underground are displayed together.

Sliced map view: in this mode you can also build underground; the map is cut at the specified level and only tunnels on the respective level are displayed; the level can be adjusted with the arrows, or entered directly as a number in the box.

Day and Night cycle: if selected, game will cycle between day and night.

Brightness: sets how light/dark view of game appears; higher values are darker; too low or high values produce problems.

Scroll Inverse: reverses the direction of scroll for game-view in Game Window.

Scroll Speed: sets the scroll-speed for game-view.

Transparent instead of hidden: objects that are selected as hidden (trees or certain buildings) will instead appear semi-transparent.

Hide trees: all trees are hidden.

Buildings display mode: you can select with the help of arrows whether 'no buildings', 'only city buildings' or 'all buildings' are hidden.

Smart hide objects: depending on the setting, objects across a certain number of tiles around the mouse pointer are hidden; the number of tiles can be set with the arrows or directly by entering a number in the box.

Transparent station coverage: shows the catchment area of stops/stations as transparent, rather than as a grid; colored in player's own color.

Show station coverage: displays the catchment area for each stop/station.

Show station names: toggles the style in which the name of each stop/station is displayed.

Show waiting bars: toggles whether the miniature bar graphs showing the proportion of waiting goods/passengers as against the station's total capacity is displayed or not.

Pedestrians in towns: toggles the display of pedestrians moving across urban areas.

Pedestrians at stops: toggles the display of pedestrians getting off a vehicle at stops.

Traffic density: determines the amount of private cars in urban areas.

The number of new private cars generated in urban areas is dependent on size of urban area and on traffic density setting; higher values create more private traffic, while '0' generates none.

Convoy tooltips: customizes the amount of information displayed about convoys in game-view.

Show schedule's stops: if activated, all stops and waypoints are displayed when a vehicle's schedule is open.

TIP: More options and default values for when Simutrans starts can be changed in simuconf.tab file, located in simutrans/config/ folder.

Display performance information

Below these settings, information is shown on computer performance when running Simutrans. Numbers are white when everything is working well; if they are red or yellow then you may need to change your settings.

If you change how fast time passes in the game, by using Fast Forward icon >> at the top of game-view, or [,] / [.] keys, this may also change the number colour.

Frame Time: Shows the actual time between frames.

Idle: Shows how long the computer pauses between two screen updates. When above 0, the computer has capacity to run other tasks along Simutrans.

FPS: Higher values mean vehicles appear to move more smoothly. In Fast Forward and Network mode the frame rate is fixed, otherwise it varies according to the workload. A default value can be set with the command line parameter '-fps' or in simuconf.tab file. If this number remains red, the computer is too slow for current settings (try reducing the size of the game-view window).

Simloops: Number of simulation loops per second. If number remains red, the computer is too slow for current settings (try a smaller map with fewer urban areas).

simutrans-124.3/simutrans/text/en/edittools.txt000066400000000000000000000120441474050137200217360ustar00rootroot00000000000000Game and map editing tools

Game and map editing tools

Game edit tools allow further customisation of the current game world.
Tools can: change populations of urban areas; build urban roads, attractions, power plants & industry; remove option to operate as another player company; and also advance the game by one year.

The toolbar opens when option to operate as public service player is selected from either Players or P+ in Special Contruction Tools (or by keypress [P]). The toolbar remains open even if option to change player is used again.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & more information for some tool-options.

Tool-options include, from left to right:

Grow city: tool increases the population of an urban area by 100, constructing new roads and buildings if necessary.
To use: click on tool to select, changes cursor to an red-up-arrow, then click on urban area.

Shrink city: tool reduces the population of an urban area by 100. Urban areas will only continue to grow if homeless and unemployment levels rise.
To use: click on tool to select, changes cursor to an red-down-arrow, then click on urban area.

City road: tool builds an urban road between two points, as the public service player that every player may use. City-roads may not be built on areas occupied by other buildings, & may not find a path across rough terrain, water and obstructions. City-road built between points, may use existing road in its path.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name, construction and maintenance cost incurred by public service player and maximum speed limit. To build a City-road: click on tool to select (changes cursor to city-road), then click on game-view for start-point of road (shows a bulldozer in game-view and map co-ordinates on right of bottom-bar under game-view), & finally click on terrain for end-point for road.
{Tips: Different types of roads may connect. Use bridges & tunnels to connect roads across rough terrain, or to avoid obstructions. Use Terraforming tools to change terrain, to enable paths for road. Use Destroy/Remove to remove city-road & some obstructions. Use [Ctrl] at same time for extra functions.}

Build a random attraction: tool constructs an attraction that passengers will want to visit. Different attractions also generate diffferent amounts of passengers and mail. The type of attraction built is random and only appears if suitable space free of obstructions is found.
To build an attraction: click on tool to select (changes cursor to red-drop-in-yellow-circle-icon), then click on required position on terrain in game-view.
{Tips: Use Destroy/Remove as the public service player to remove attractions. Use Destroy/Remove and/or Landscape tools to create suitable places for attractions.}

Build a new power station: tool constructs a power station (and possible suppliers). The type of power plant built is random and only appears if suitable space free of obstructions is found.
To build a power plant: click on tool or press [I] to select (changes cursor to red-drop-in-yellow-circle-icon), then click on required position on terrain in game-view.
{Tips: Use Destroy/Remove as the public service player to remove power stations. Use Destroy/Remove and/or Landscape tools to create suitable places for power stations.}

Build a new market in the nearest city: tool constructs an end-consumer of goods in an urban area (and possible suppliers not necessarily in the urban area). The type of industry built is random and only appears if suitable space free of obstructions is found.
To use: click on tool to select (changes cursor to red-drop-in-yellow-circle-icon), then click in game-view to build consumer in nearest urban area.
{Tips: Use Destroy/Remove as the public service player to remove power stations. Use Destroy/Remove and/or Terraforming tools to create suitable places for industry.}

Disallow further player change: tool removes option to operate as other player companies and to open Game (map) edit tools.
To use: click on tool to select (changes cursor to a padlock), then click anywhere in game-view, no confirmation is required.

Step time-line by a year: advances date in game by one year. If playing with timeline, as time passes more transport and construction options may become available and slower vehicles are not as profitable (as income is calculated by average speed of available transport) .
To use: click on tool, no further confirmation is required (date changes on left of bottom-bar under game-view).

simutrans-124.3/simutrans/text/en/enlarge_map.txt000066400000000000000000000005071474050137200222030ustar00rootroot00000000000000Map enlargement

Enlarge map

Here, one can extend the map to the right and the bottom. If one wants to extend to the left / top, one has to rotate the map first, enlarge then, and rotate back.
A preview of the enlarged map is shown in the top-right of the dialoge window.

simutrans-124.3/simutrans/text/en/factorylist_filter.txt000066400000000000000000000044351474050137200236450ustar00rootroot00000000000000Factory List

Factory List

Factory List shows information about all factories (suppliers and consumers of goods) in the current game.

To open factory List: click on factory-list-tool in List Management.
{Tips: If items in list are only partially visible, then re-size Industry/factory List or scroll list using slider-bar.}

Sorted by: has options to determine the order of listed ndustries listed.
Click on buttons to cycle through options (changes name of option-button):

- factory name orders alphabetically by name.
- input orders by input storage capacity.
- output orders by output storage capacity.
- Production orders Industry by production capability.
- Rating orders Industry by status-colour-bar (see below).
- Power orders Industry by electricity supplied.

- ascending / descending reverses order of list.

Click on a item listed inFactory Listto see more information about that Industry.
Items listed for each Industry include:

status-colour-bar colours indicate operation of the Industry (also used in Industry Information):
- white: does not require supplements.
- yellow: connected by transport, but Industry Supply Chain has poor supply.
- green: at optimum status.
- orange: operational but improvements possible.
- red: operational but part of Industry Supply chain has excess supply.

red-lightning-strike-icon is shown if the Industry has electricity supplied through transformer.

factory name: name of the industry.

In brackets 3 values represent:
current input: amount of goods stored ready to be processed.
current output: amount of goods that are ready for transportation.
total production: production rate of the factory (maximum amount of goods produced per month)

simutrans-124.3/simutrans/text/en/finances.txt000066400000000000000000000076041474050137200215240ustar00rootroot00000000000000Finances

Finances

The Finances window provides an overview of the financial status of a player's company.

To open, click the money icon at top of main view, press [f], or click on a player's name in the Players dialog.

Values are in Hajo Credits and are listed for present and past calendar months or years. Click on the corresponding tab to change the timespan of the graph.
- Years: shows annual values.
- Months: shows monthly values.

The graph displays the y-axis as quantity and the x-axis as time. You can have several curves displayed at the same time and if you hover the cursor over a point on the graph, a tooltip will display the number.

The Build HQ button in the upper-right corner allows you to build or upgrade your company headquarters (if the graphics are provided by the pakset). The headquarters will serve as a high-level attraction and may be required for some scenarios.


Values (click on name-button to view details on graph), include:

Vehicle Earning - total income from the transport of passengers, goods, and mail.

Operation Costs - total cost incurred by all convoys when in transit.
{Tips: The operation cost per kilometer for vehicles can be seen in a depot and from Convoy Information.}

Maintenance - total cost incurred maintaining the transportation network.
{Tips: The cost per month for maintaining the network (Maintenance (monthly) shown on the right of Finances) is deducted at the end of the game calendar month.}

Road toll - when running convoys over foreign way, a cost may occur. If you are using other players ways, you have to pay. But if you provide are very good road connection, you may also earn from others.

Powerlines - income generated from the selling of electricity from high power transmission.

Operational Profit - profit from transportation, road toll, high power transmission less the maintenance and operational costs (sum of everything above).

New Vehicles - expenditure on and income received from the purchase and sale of vehicles.

Construction site - total cost incurred by construction of transport networks, landscaping, high power transmission lines, and using Destroy/Remove and other removal tools for ways (tracks, road, canals and airstrips).

Cash Flow - total income (sum of everything above this).

Trips - number of everything moved (counting passengers, mail, and goods). Transfers are counted once per leg.


In the second row four additional values are seen. Those are accumulated values:

Account Balance - the current cash available for construction or purchasing vehicles (also shown in the centre of bottom-bar under game-view.

Assets - the value of all company vehicles at the end of the last calendar month.
{Tips: each month the value of operational vehicles depreciate slightly, current selling value for vehicles can be seen in Convoy Details or when vehicle is in a depot.}

Margin - is the ratio of Operational Profit to Proceeds.

Net Wealth - Account Balance plus Assets. This is the company value. If the net wealth becomes negative, your company is bankrupt and you loose the game.

{Tips: Some costs, starting balance and finances in game can be changed in simuconf.tab}

Scenario information

If you play a scenario, then the scenario goal and the percentage of the progress is displayed.

simutrans-124.3/simutrans/text/en/general.txt000066400000000000000000000061131474050137200213450ustar00rootroot00000000000000Simutrans Help

General Help

- Welcome
- Game Interface
- Mouse Help (to be written)
- Keyboard Help
Game Options
- Language
- Player Colour
- Display Settings
- Sound & Music
- Players
- Load Game
- Save Game
- New Game
- - Climate Control
- - Load Height Map

Main Menu
- Game Options
- Map
- Inspection Tool
- Landscaping Tools
- Railroad/Train Tools
- Monorail Tools
- Tram Tools
- Road Tools
- Harbour Tools
- Airport Tools
- Special Construction Tools
- Game Edit Tools
- Destroy/Remove

Management Menu
- Line Management
- Lists
- - Stops/Station List
- - - Stops/Station List Filter
- - Vehicle List
- - - Vehicle List Filter
- - City List
- - Goods List
- - Industry List
- - Attractions List
- Message Centre
- Finances

Other Options
- Save Screenshot
- Pause
- Fast Forward
- Help

Other Dialogs
-Depot Controls
-Schedule Controls
- Stop Information
- - Stop Details
- Convoy/Vehicle Information
- - Convoy/Vehicle Details
- City Information
- Industry Information

If no help is found here, try
http://guide.simutrans.com, or
http://wiki.simutrans.com, or
http://simutrans-tips.com, or
http://forum.simutrans.com.

simutrans-124.3/simutrans/text/en/goods_filter.txt000066400000000000000000000057411474050137200224160ustar00rootroot00000000000000Goods List

Goods List

Goods List contains information on the different items that can be transported in game and how much income transporting them will produce.

To open: click on goods-list-tool in List Management or press [G].

A list of items available for transport in the game indicates: revenue received, % speed bonus, goods category, weight.
{Tips: If items in list are only partially visible, then re-size Goods List or scroll list using slider-bar.}

Speedbonus: shows the Convoy average maximum speed for different transport types required to earn the listed revenues. If average maximum speed is faster than the listed speed some items may earn more but if it is slower they may earn less.
When timeline setting is enabled the speed values may change as time progresses. The change usually follows the introduction of faster or more economical Convoys
The arrow-buttons can be used to adjust the speed by a percentage and update all the displayed revenues. This is useful when wanting to find out what revenue a Convoys gets when its average maximum speed is not exactly at the speedbonus speed without having to do the calculation manually.

Sorted by: shows which order the item list is displayed in.
Click on option-buttons to cycle through various sorting options (changes name of option-button):

- by name in alphabetical order.
- by revenue orders by income received.
- by bonus orders by % for speedbonus.

- ascending / descending reverses the order of the list.

Details listed for each item include:

colour square is the same colour displayed in goods-colour-bars in game-view above a Stop to indicate quantity of items that are awaiting transport.
{Tips: Use [!] to toggle goods-colour-bars above a Stop in game-view.}

revenue is the income received for transporting one unit a distance of one tile in the current payment model.
It is calculated by {(base revenue) * (1 + ((average maximum speed) / (speedbonus) - 1) * (% bonus))}.

% bonus is % revenue change linearly with Convoy maximum speed inversely with speedbonus around the speedbonus speed.

goods category indicates type of vehicle needed for transport. Special freight requires specific vehicles.
{Tips: The capacity of vehicles shows which items a vehicle can transport}.

Weight shows how much one unit of cargo weighs in kilogrammes.
This is added to vehicle weight during transport making the vehicle require more power to move than when empty.

simutrans-124.3/simutrans/text/en/haltlist.txt000066400000000000000000000072601474050137200215600ustar00rootroot00000000000000Station List

Station List

Station List shows information and has controls to filter and list different Stops (but not Stops just for water transport vehicles), where vehicles pick-up and drop-off goods & passengers.

To open: click on station-list-tool in List Management. Station List has four option buttons, two are used to order items in a list and two are used to apply options to select items to show in list. Below buttons is a list of Stops that fit criteria for filter options.
{Tips: If no Stops are listed change Filter options. If items in list are only partially visible, then re-size Station List or scroll list with slider-bar.}

Click on buttons to cycle through options (changes name of option-button) or open Filter Settings controls:

Sorted by: two option-buttons determine the order of Stops shown in list:

- Type orders by type of vehicle that is accepted.
- unsorted ?orders in random order.
- Name orders alphanumerically within ASCII-code order (capital letters before lower case letters) of assigned name.
- waitingorders by amount of goods & passengers present in relation to waiting capacity and transport service provided.

- ascending / descending reverses order of list.

Filter: Two option buttons, switch on/off selection criteria for list and access controls to change criteria.

- enabled / disabled click to toggle filter criteria.

- Settings click to open controls to change filter criteria.

Click on a item listed inStation Listto see more information about that Stop.
Items listed for each Stop include:

status-colour-bar: colours indicate operation of Stop with regards to how overcrowded it is. The colour-bar is also used in Stop Information and Line Management and is the same colour displayed in the colour-bar above Stop in game-display:
- yellow: no service and nothing waitung.
- green: no improvements necessary.
- orange: stop is slightly overcrowded (with transfer goods mostly).
- red: stop hold more than 1.5 of its capacity, or more than 200 unhappy passengers, or a factory must stop its production because the station is overcrowded.
{Tips: Use [!] to toggle colour-bar above Stop in game display.}

name that has been assigned {Tips: Option to assign numbers in Stop name available in simuconf.tab}.

vehicle icon(s) indicate which types of vehicle can use Stop (also used in Stop Information and Line Management).
Icons include: bus (for road passenger vehicles), truck (for road goods vehicles), train, boat and airplane. Trams can be indicated by a bus-icon or a train-icon depending on type of Stop.

freight icon(s) indicate which items (passengers, goods and/or mail) the Stop can handle (also used in Stop Information and Line Management).
{Tips: adding appropriate extensions changes the category of items a stop can handle. Post offices may be added to Stops to enable handling of mail}.

waiting details of different goods and passengers at Stop.

simutrans-124.3/simutrans/text/en/haltlist_filter.txt000066400000000000000000000040711474050137200231220ustar00rootroot00000000000000Station List Filter

Station List Filter

Station List Filter has options to determine which Stops (but not Stops just for water transport vehicles), where vehicles drop-off and pick up passengers, are shown in Station List .

Click on Settings in Station List to open Station List Filter.

Option-buttons select Stops to be listed in Station List when filter option is enabled. Only Stops that fit all criteria set, are listed.

Click on a button to select/deselect criteria for filter (button is indented when selected):

Filter names: selects Stops by name. To use: click on button to select, then click on name-box and type required name exactly (option is case sensitive).

Filter types: will list Stops that have at least one of the following items if selected. To use: click on button(s). (Stops just for water transport vehicles are not listed in Station List)

Special filter:
- overflowing ?not in use.
- no connection selects Stops with no transport service.

Goods needed: refers to Stops where selected item(s) end their journey. Click on button next to name to select item(s). Use slider-bar to scroll items list. Options include:
- all selects all items.
- none no items are selected.
- inv. inverses current selection of items.

Production: refers to Stops where the selected item(s) start their journey. Click on button next to name to select item(s). Use slider-bar to scroll items list. Options include:
- all selects all items.
- none no items are selected.
- inv. inverses current selection of items.

simutrans-124.3/simutrans/text/en/industry_info.txt000066400000000000000000000112531474050137200226250ustar00rootroot00000000000000Industry Information

Industry Information

Industry Information shows details about a selected Industry (a supplier or consumer of goods) and allows game-view to be moved to related positions in game-world.

Suppliers and consumers of goods link to provide an Industry Supply Chain which terminates in an end-consumer. Some Industry is both a consumer and supplier and lies in the middle of an Industry Supply Chain. If not playing in beginners mode, Industry will cease supply if consumer has excess supply.
Industries may also be a destination for and origin of passengers and mail. Vehicles collect and deliver goods and passengers to an Industry through Stops if the catchment area of the Stop covers any portion of the Industry building and if the Stop can handle the item. {Tips: Off-shorestops/Oil rigs/fish farms/catchment area/oil/mail/passengers/not listed in station list}

The intial number of Industry Supply Chains can be set in Create New World. As urban areas grow more industry may appear. New industry appears each time the population of an urban area doubles from about 2000 onwards.
{Tips: Add Industry to an urban area using Build a new market in the nearest city tool in ?Game Edit Tools. Change when new industries are generated in cityrules.tab (industry_increase_every = 0 generates no new industry)}.

Click on an Industry in game-view with the Inspection Tool or an Industry listed in ?Industry List to open Industry Information.
Use slider-bar to scroll items if all are not visible.

Name of selected Industry is shown in the titlebar of Industry Information.
Other information about selected Industry and options include:

Production: maximum rate of goods the Industry will supply (if a supplier) or consume (if it is an end-consumer) in units per ?month/day.
{Tips: Adding transformer stations and adding supplying electricity to an Industry increases rate of goods produced/consumed}.

Industry picture shows a view of Industry building. Click on picture to move game-view to Industry building.

status-colour-bar under picture indicates operation of Industry (also used in ?Industry List):
- white: does not require input.
- yellow: connected by transport, but Industry Supply Chain has poor supply.
- green: at optimum status.
- orange: operational but improvements possible.
- red: operational but part of Industry Supply chain has excess supply.

Consumer: lists destinations in Industry Supply Chain for goods produced by selected Industry.
Destination industries and their map co-ordinates are listed by an arrow-button. Click on arrow-button to move game-view to destination.

Suppliers: shows origin of goods in Industry Supply Chain required by selected Industry.
Supplier industries and their map co-ordinates are listed by an arrow-button. Click on arrow-button to move game-view to supplier.

Workers live in: shows in which nearby urban areas employees live. Passengers and mail from these urban areas will need to reach the selected Industry.
Urban areas and their map co-ordinates are listed by an arrow-button. Click on arrow-button to move game-view to supplier.

Passenger level: is the relative popularity as a destination for passengers .
Mail level: is the relative popularity as a destination for mail.
{Tips: only one square of an Industry building need fall in the catchement area of a Stop to provide an optimum service for passengers and mail}.

Production: gives details on output of Industry.
Information shown includes: name of item; quantity currently stored by maximum storage capacity for item; goods category; and percentage level of output compared to input.

Consumption: gives details on input of industry.
Information shown includes: name of item; quantity currently stored by maximum storage capacity for item; goods category; and percentage level of input compared to output.

Stops which serve the Industry are listed at the bottom of Industry Information.

simutrans-124.3/simutrans/text/en/inspection_tool.txt000066400000000000000000000125451474050137200231460ustar00rootroot00000000000000Inspection Tool

Inspection Tool

Inspection Tool is used to open dialogues that provide information or option-controls for various items.

Click magnifying-glass-icon at top of game-view or press [a] to open Inspection Tool (changes cursor to a magnifying-glass).

To use Inspection Tool: position magnifying-glass-cursor in game-view at required postion and click to open dialogue. If more than one item is at required postion, a further click will open a second dialogue. {Tips: Option to open one dialogue or all dialogues for a given cursor position available in simuconf.tab}

Click on following items in game-view with tool to open various dialogues:

Depots - opens controls to purchase and manage vehicles at that depot.

Stops - opens Stop Information for that Stop.

Vehicles - opens ?Convoy/Vehicle Information for that vehicle.

Town Hall - opens City ?Information for that urban area. {Tips: Option to open dialogue providing information about Town Hall available in simuconf.tab}

Industry - opens Industry Information for that industry.

City Buildings opens a dialogue that gives information about the building (titlebar of dialogue is 'Building'). Information contained in the dialogue includes:
- description provides information about the building. If no description is available then either 'residential house', or 'industrial building', or 'shops and stores' (for commercial buildings) is shown.
- City of: indicates which urban area the City Building is part of.
- Passenger level: is the relative popularity as a destination for passengers .
- Mail level: is the relative popularity as a destination for mail.
- Appears from: indicates year the building appears if playing with timeline.
- Value:: indicates cost incurred if building is removed with Destroy/Remove Tool.
- Painted by: name of person who drew building for Simutrans

Monuments / Tourist Attractions opens a dialogue that gives information about the attraction (titlebar of dialogue indicates whether it is a monument, or tourist attraction). Information contained in the dialogue includes:
- Public property indicates that item is not owned by a player company.
- description provides information about the attraction.
- Passenger level: is the relative popularity as a destination for passengers .
- Mail level: is the relative popularity as a destination for mail.
- Appears from: indicates year the building appears if playing with timeline.
- Painted by: name of person who drew attraction for Simutrans

Roads and Tracks opens a dialogue that gives information about the Road or Track (titlebar of dialogue indicates what type of way it is - in the case of tram tracks built on road titlebar indicates type of Road).
Information contained in dialogue:
- Max Speed: maximum speed limit allowed on road or track.
- Ribi (unmasked):
is an internal counter that indicates direction of way.
- Ribi (masked): is an internal counter that indicates direction of way taking into consideration any signals or signs.
- with sign/signal is shown if there is a signal or sign present.
- electrified/not electrified indicates whether way is electrified.
- convoi passed last month indicates number of Vehicles that used way in the previous game-calendar-month.
- reserved by indicates which vehicle has reserved a track for use till it has passed.
- wayslope indicates direction of slope if any
- map-coordinates as shown on bottom-bar
In the case of tram tracks constructed on road: information is shown twice, first for the road and then for the tram track.

Signals/Signs opens a dialogue, the titlebar of the dialogue indicates whether it is a signal or a road sign. Information contained in dialogue includes:
- direction ?is an internal counter that indicates direction to which signal applies.

Powerlines / Transformer stations opens dialogue that provides information about electricity supply grid (titlebar of dialogue is 'Power Lines'). Information shown includes current demand and supply.

Trees opens a dialogue (the titlebar is 'Tree'). Information shown includes:
- name which provides species of tree.
- age age of tree in months.

Land opens a dialogue (the titlebar is 'Land'). Information shown includes:
- slope which provides species of tree.
- map co-ordinates as shown in bottom-bar.

{Tips: Option to open dialogues on private road users and pedestrians available in simunconf.tab}.

simutrans-124.3/simutrans/text/en/jump_frame.txt000066400000000000000000000010521474050137200220520ustar00rootroot00000000000000Jump to

Jump to

Dialog opens with [J] key and enables jumping to the specified coordinates. This is useful to move quickly to certain positions on the game-world.

Every tile on the game-world has two coordinates (x,y), with (0,0) located on the top-left corner of the map. Cursor coordinates are permanently displayed on the status bar.
NOTE: A map rotation (performed with [R] key) will rotate all tile coordinates.

simutrans-124.3/simutrans/text/en/labellist_filter.txt000066400000000000000000000004061474050137200232470ustar00rootroot00000000000000List of Signs

List of player signs

Here, all signs on the map are listed.
The option Active player only shows only signs of the active player.

By clicking on a entry, you can edit the text there. simutrans-124.3/simutrans/text/en/language.txt000066400000000000000000000016251474050137200215160ustar00rootroot00000000000000Languages

Languages

The Languages window changes the language used in the game.

It opens from the Game Options window and with the Create a New Game windows.

The default language for Simutrans is English. To play the game in a different language, select the button next to the language you would like to play in.

Language can be changed any time during game play. To change the language, select Game Options -> Language.

Language change happens immediately when creating a new game and on closing the Languages window when changing mid game.

If a translation is not available in the selected language, it may appear in English.

To help in translating Simutrans in your language,
visit https://translator.simutrans.com/

simutrans-124.3/simutrans/text/en/linedetails.txt000066400000000000000000000110751474050137200222300ustar00rootroot00000000000000Line Information

Line Information

The Line Information show and can edit the properties of a single Line (a group of Convoy that share the same route). The Line Information is either opened from the Depot, the Convoy Information, or the Line List.

At the top is the name of the line. CLick in the box to change it. Below are the number of Convoy, the used capacity, and the profit.Below are four tabs.

Schedule is the leftmost tab. Here the Schedule for all Convoy in this line can be altered. Their schedule will be replaced with the new as soon as the tab is changed or the Line Information is closed. The tab will be seletced automatically, if the Line Information was opened from the Depot or the Convoy Information.

Chart shows various information about this Line and the vehicles assigned to it, on a graph (the x-axis is time in months):

- Free Capacity - amount of spare space in vehicle(s) for goods & passengers.
- Travelled - amount of goods and passengers that used Line.
- Proceeds - amount of income generated by vehicles.
- Operation Costs - cost incurred by vehicles when in transit.
- Profit - income generated less costs incurred (Proceeds less Operational Costs).
- Convoys - number of Convoys assigned to Line.

Vehicle List shows all Convoys assigned to this Line. If a Convoy is missing, this Convoy was probbably assinged a new schedule manually and thus was removed from the Line.

There are three management buttons:
- Delete Line deletes this Line, and closes this window. All connected Convoys will continue with the current schedule.
- Withdraw All retires all Convoys in the Line outside a Depot. The Convoys will not longer take any new load and will be sold whenever they become empty. This can be used to update the Convoys of this Line: Open a Depot that serves this Line, assemble a new Convoy, and assign it to this Line. Then select Withdraw All, copy the new Convoy in the Depot as often as needed, and start all new Convoys.

The Convoys of this line are listed below the buttons. Click on an item listed to see more information about that Convoy (use slider-bar to scroll list).
Items listed for each Convoy include:
name that has been assigned (by default this is make of first vehicle unit purchased or assembled for Convoy).
income shows profit (income generated less operation costs).
Line: shows the name of Line assigned to Convoy and indicates if it is in a depot.
graphics show the compostion and the current level of items on board.

Station List shows the Stops. Click on a Stop listed to open its Stop Information.
Items listed for each Stop include:
name of that stop (waypoints are not shown.). The colour indicate the operation of the Stop with regards to how overcrowded it is. The colour is also used in Station List and Stop Information and is the same colour displayed in the colour-bar above a Stop in game-display:
- yellow: not in service.
- green: no improvemments required.
- orange: improvements possible.
- red: improvements recommended.
The name is followed by the vehicle icon(s) indicating which types of vehicles can use Stop (also used in Stop Information and Station List). Icons include: bus (for road passenger vehicles), truck (for road goods vehicles), train, boat and airplane. Trams can be indicated by a bus-icon or a train-icon depending on type of station.
The next line contains the freight icon(s) which indicate the items (passengers, goods, and mail) a Stop can handle (also used in Stop Information and Station List) followed by a summary text of the waiting amounts of passengers or goods.
{Tips: adding appropriate extensions can change the category of items a Stop can handle. Post offices can be added to Stops to enable handling of mail}.

simutrans-124.3/simutrans/text/en/linemanagement.txt000066400000000000000000000044741474050137200227240ustar00rootroot00000000000000Line List

Line List

Line List manage Lines (a group of Convoy that share the same route)

Lines consist of Stops where vehicles pick-up and drop-off goods & passengers (water-transport vehicles may use any square of water in the catchment area of a dock) and waypoints (used to direct vehicles if more than one option is possible or provide interim destination points).

Click on network-icon at top of game-view or press [w] to open Line Management, which can be re-sized (click on down-arrow in titlebar to return to original size).

The Line List lists existing Lines (to scroll list: use slider-bar on right of list), which can be filtered by name or by transport type (click on a index-tab above list to select):
All: lists Lines for all vehicles.
Train: lists Lines for all railroad vehicles.
Monorail: lists Lines for all Monrail/maglev vehicles.
Tram: lists Lines for all trams.
Truck: lists Lines for all road vehicles.
Ship: lists Lines for all water transport vehicles.
Air: lists Lines for all aircraft.

Colour of name of Line that appears in List indicates following:
white - no vehicle assigned to Line
yellow - not operational, not generating profit or loss
black - making profit
blue - has obsolete vehicles
red - line making loss

If you hover over a Line, some more info will be shown. Click on a Line in list to open the Line and see information about Stops, income, and Convoys on this Line or change the schedule.

Two management option are available:

New Line: creates a new Line window. This requires that a transport type is selected.
Delete Line: removes the current line from the game. All convois belonging to that line will driving with an individual schedule similar to the line.

Single GUI: if activated and a Line is clicked, the topmost Line window will be replaced by the selected Line.

simutrans-124.3/simutrans/text/en/list.txt000066400000000000000000000034041474050137200207030ustar00rootroot00000000000000Lists

Lists

Lists has options to open controls for information about the current status of the game (and also a control to adjust relative income recieved from the transport of different goods, passengers & mail).

Information is available for a player in lists about: Stops; Convoys; urban areas; incomes received from different goods, passengers & mail; industry; and tourist attractions.

Click on list-icon at top of game-view to open Lists.
Hover mouse-cursor, after opening or clicking on toolbar, over list-tool-option to see name.

Click on tool-option to open controls for information, from left to right, about:

Station List: Stops, where vehicles pick-up and drop-off goods & passengers (but not Stops just for water-transport-vehicles).

Vehicle List: road and rail vehicles, aircraft and boats.

List of all towns: urban areas (villages, towns and cities).

List of all goods: incomes received from different goods, passengers & mail (includes control to adjust relative income).

Factory List: industry (consumers and suppliers of goods).

Attraction List: tourist attractions.

simutrans-124.3/simutrans/text/en/load.txt000066400000000000000000000024031474050137200206450ustar00rootroot00000000000000Load

Load

Load re-starts a saved game (to continue play) & can be used to delete these games. A game that is re-started replaces the current world which is lost.

Load opens from Create New World & Game Options or by pressing [L]; & list names, date & time (of save) of available games.
If all games are not visible: use slider-bar on right-side of list to scroll names.

Click on name in list to re-start game; or enter name into box at top of Load: click on box, type name, & press [Enter] or [Return] or click on OK.
An incorrect name will receive an error message: close message, try again.

WARNING: Click x-button by name to DELETE game immediately & permanently.
Use this function carefully.

IMPORTANT: New releases of Simutrans appear regularly & games from previous releases of Simutrans may not work with later versions; please read release notes for later version to see if old games are compatible.

Click on Cancel to close Load; or x in top-left-corner; or use keyboard.

simutrans-124.3/simutrans/text/en/load_relief.txt000066400000000000000000000030251474050137200221740ustar00rootroot00000000000000Load Height Map

Load Height Map

Load Height Map window is used to open a file of a custom-made terrain (for use when creating a new game) & can also be used to delete these files. It opens from Create a New Game window and it lists the names, dates & times (of save) of available custom-terrain files. If not all filenames are visible, use the slider-bar on the right-side of list to scroll through the names.

Click the name in the list to load a custom-terrain map, or enter a name into the text box at the top of the window: click on box, type name & press [Enter] or [Return], or click on OK (an incorrect name will have no effect, try again).

WARNING: Click x-button (if enabled in simuconf.tab) on the left of the name to DELETE the file immediately & permanently; the filename is removed from list and Load Height Map window closes. Use this function carefully!

Some custom-made terrains are available online at http://maps.simutrans.com. The new file must be in .ppm or .bmp format (best 256 colors RLE compressed) and placed in the personal directory (or folder) named simutrans/maps/

TIP: Information on how to create custom terrains is available online at http://wiki.simutrans.com

Click on Cancel to close Load Height Map window, or x-button in the top-left corner, or use the keyboard.

simutrans-124.3/simutrans/text/en/mailbox.txt000066400000000000000000000042021474050137200213600ustar00rootroot00000000000000Message Centre & Message Centre Options

Message Centre

Message Centre lists messages from game and opens controls to select how messages are shown in game.

Click on mailbox-icon at top of game-view or press [B] to open Message Centre, which lists messages from game.
Click on a message to move game-view to a related position.

Options button (click to use) opens Message Centre Options which has controls to determine how messages are displayed.


Message Centre Options

Message Centre Options has three columns of square-buttons which select how messages are displayed.

From left to right, the columns select whether messages are shown as: a scroll-text at bottom of game-view; a temporary message; or a permanent message.
{Tips: Click on x in top-left-corner of message or use keyboard to close permanent messages.}

Click on square-buttons to select message options (buttons are indented when selected) for following messages:

New Year: a new year has started.

AI News: an AI player has opened a new line.

City News: an urban area is building a bigger townhall.

No Route: a vehicle can not find a route to its next destination (a Stop or waypoint).

New Industries: a new industry chain (an end-consumer and any necessary suppliers) has been built due to town growth.

Tourist: a city attraction or memorial has been built.

New Vehicles: a new vehicle becomes available, or a vehicle is retired (if timeline is used).

Station full: a Stop is overcrowded.

Problems: player company is in debt and other critical messages.

simutrans-124.3/simutrans/text/en/map.txt000066400000000000000000000144461474050137200205150ustar00rootroot00000000000000Map Window

Map Window

The Map provides a map of the current world giving information on terrain, important locations, and transport networks. It also provides a way to move the view on the world.

Click on map-icon at the top menu or press [m] to open Map, which can be re-sized or minimised. The three topmost buttons enable further options
 Selections show various buttons to overlay further information on the map
 Color Codes shows a min-max colour scale that shows activity level for some of the options.
 Industry List open s table with the colours of industries seen on the map.

The map has different zoom levels: use mouse-wheel, page up/down or the buttons to change them. You can also tilt the map to match the display using the isometric map button.

On the map, water is blue and lower land is darker than higher land. The currently visible part of the world on the screen is indicated by a yellow-square outline. To move this field of vision across the world, left-click on map at desired location or left-click-drag the yellow-square. With right-click drag you can move the area in the map window without using the scrollbars.

On the default map (when not using the options) urban areas and attraction are grey, powerlines turquoise, tunnels are brown, elevated ways light brown, and bridges light grey. On the ground ways have their distinct colors: Roads appear nearly black; rail and tram tracks are dark brown; canals are blue; and runways are dark yellow. All other ways (like narrow gauge, maglev, or monorail tracks) are light red. Stops are red. Vehicles on ways are yellow.

The button Networks will overlay an abstract line network like a subway map over the map. Using the yellow button, you can restrict it to only show passenger, Mail or freight connections.

Using the selection button many additional informations can be overlaid. Those fall in three groups. White and yellow buttons are exclusive and will disable any other white option. Green buttons are for overlays that can be combined with any other. The third group are the red buttons for stops. From this stop group only one can be active at a time.

The following options exist:
Cities names of urban areas.
City Limits show the city limits; new houses and roads are only built inside the city limits.
No. of buildings colors each city building according to its level. The level determines the probability to generate passengers or mail here.
Destinations If a town selected, this option overlays the current passenger destinations (similar to the small map in the City Information.)
Attractions draws circles on the location of tourist attractions. The color and size will indicate the amount of traffic this tourist attractions generates (use min-max scale).
Factories: highlights industry (consumers and suppliers). If this overlay is active and the mouse pointer hovers over an industry on map, it will show the name and white lines linking customers; hold down [Shift] to show red line to suppliers. The color is the color of the industry can be seen fro the Industry List.
Passengers colors the catchment area for passengers by Stops with the color of the respective owner. If the network overlay is active, it will only show passenger connections.
Mail colors catchment area for mail by Stops with the color of the respective owner. If the network overlay is active, it will only show passenger connections.
Freightlevel of goods and passengers transported on alls ways (uses min-max scale). If the network overlay is active, it will only show freight connections.
Stop Status (and all following red options) highlight the stops by circles. Stop Status color indicate how overcrowded a stop is. The same colour is shown in status-colour-bars in Station List, in the Stop Information, Line Management and finally in the color-bar above the name of a stop. The size indicates the capacity of a stop for passengers.
Waiting shows the amount of passengers, mail and goods waiting for transport at a Stop. Color as and size indicate the amount waiting (uses min-max scale).
Queing shows how much the amount of passengers, mail and goods waiting has changed within this month. The size indicates the total change, while the colors are green for decreasing and red for increasing (uses min-max scale).
Service color and size indicate how many vehicles served a station in this months (uses min-max scale).
Transfers size and color indicate how many arrived/departed at a station (uses min-max scale).
Origin color and size show how many passengers and mail wanted to start their journey at a Stop, i.e. the sum of happy, unhappy and no route passengers (uses min-max scale).
Traffic colors ways by the number of vehicles passed within a month (uses min-max scale).
Tracks rail amd tram tracks, bridges, and tunnels are shown as white (red if electrified). Signals are shown as yellow.
Speed Limit colors all ways with respect to their maximum speed allowed (uses min-max scale).
Depots highlights depots. Colors indicate transport types: ship, yellow; road, orange; rail, red; aircraft, green; trams, blue; and monorail, grey.
Powerlines show the load on power transmission lines.
Forest shows forests in bright green.
Ownership colors all things on the map with the color of their owner (orange for unowned).

simutrans-124.3/simutrans/text/en/monorailtools.txt000066400000000000000000000154701474050137200226370ustar00rootroot00000000000000Monorail/maglev Tools

Monorail/maglev Tools

Monorail/maglev Tools construct a Monorail/maglev transport network. Tools may build or remove: monorail and maglev track; bridges; tunnels; signals; depots; station-platforms; & extensions. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click monorail/maglev-icon at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, maintenance cost in brackets, maximum speed limit & maximum length.

Monorail/maglev Tools include, from left to right:

Monorail/maglev Track: tools build Tracks, for monorail/maglev vehicles between two points. Tracks can only be built on slopes in the direction of the slope & may not find a path across rough terrain, water and obstructions. New Track built may use existing Track in its path.
To build Track: click on tool to select Track (changes cursor to track), then click on game-view for start-point of Track (shows a bulldozer in game-view and map co-ordinates at on right of bottom-bar under game-view), & finally click on game-view for end-point for Track.
{Tips: Different types of Tracks may connect (however not when built by some other players). Use Landscape tools to change terrain, to enable paths for Track. Use Destroy/Remove to remove individual pieces of Track & some obstructions. Use [Ctrl] at same time for extra functions. Undo last route construction, [z], does not refund constructions costs.}

Remove monorails: tool removes monorail/maglev Track, when no vehicles are present, between two points in game-view (platforms and signals in path are removed too).
Use of tool incurs a construction cost.
To remove Track: click on tool (changes cursor to a red-cross); then click on Track that is to be deleted (selects deletion point shown by a red cross in game-view); & finally click at another point on track, to remove portion up to first deletion point.
{Tips: Operate as another player to remove their Tracks.}

Ramps and Bridges: tools build straight bridges, for monorail/maglev vehicles to pass, between two pieces of monorail/maglev Track in game-view. Bridges have a maximum span. Tools build bridges from an end of a Track to a suitable place (another Track-end or slightly higher land, within span).
To build a ramp or bridge: click on tool to select (changes cursor to bridge), then click on the end of a Track (start-point of bridge) to build. Some obstructions or lack of a suitable place for bridge-ends will prevent bridge being built: place Track at both sides that is to be bridged, & try again.
{Tips: Use Destroy/Remove to remove bridges (click on bridge-end) & some obstructions to bridge building. Use Track tools to connect bridge-ends to Track.}

Monorail Signals: tools build signals for monorail and maglev vehicles on a Track in game-view. Signals direct & regulate flow of vehicles on Tracks & bridges, junctions & Stops (where vehicles pick-up and drop off passengers).
Two-way & one-way versions of signals can be built. To build a two-way signal on Track: click on tool to select signal (changes cursor to signals); then click on Track. To build a one-way signal: click again at same point, with signals-cursor, to cycle through one-way signals, back to a two-way signal.
IMPORTANT: Take care not to place one-way signals that prevent vehicles reaching their destination, by default vehicles drive on the right (can be changed in simuconf.tab).
- Signals: vehicles proceed only if Track ahead up to next signal or destination in Schedule (a Stop or waypoint) is not occupied by another vehicle. In one-way mode vehicles pass in one direction only.
- PreSignals: vehicles proceed if area of Track ahead (either between three consecutive signals or to next destination in Schedule) is not occupied by another vehicle. In one-way mode they let vehicles pass in one direction only.
- ChooseSignals: direct vehicles to an empty station-platform, at a multi-platform Stop: a vehicle passing this signal may use any empty platform at its next destination, and not just the one assigned in its schedule. If no empty platform or clear route to next destination is found, then vehicles wait at signal.
{Tips: Remove signals with Destroy/Remove. Hold down [Ctrl] to place signals on bridges over lower Tracks.}

Monorail Depot: tool builds a depot for purchasing & managing monrail/maglev vehicles and carriages. Depots have a maintenance cost & are built on the end of monorail/maglev Track in game-view.
To build a monorail depot: click on tool (changes cursor to a depot), then click on end of Track.

Train-stops: tools build station-platforms, used by monorail/maglev vehicles to pick-up and drop-off passengers & mail.
A station-platform when not built adjacent to an existing Stop will create a new Stop.
Train-stops have a maintenance cost & are built on track (but not at bends and junctions in track).
Train-stops have a catchment area for goods, passengers & mail. Different station-platforms may have different capacities for goods, passengers & mail. . In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the station-platform allows a Stop to handle.
To build a a station-platform: click on tool to select (changes cursor to a platform), then click on Track.
{Tips: Remove train-stops with Destroy/Remove. Extend station-platforms & build multi-platform Stops (by building more platform sections on adjacent track) to accommodate longer and more vehicles, increase capacity & catchment area. Press [v] to show/hide catchment area for goods & passengers in game-view. Hold down [Ctrl] to build on bridges or elevated Track above lower Tracks.}

Monorail Foundation: tool constructs an extension to a Stop and increases the capacity of the Stop. Monorail foundations are built on ends of monorail/maglev Track and have a maintenance cost.
To build an monorail foundation: click on tool to select (changes cursor to foundation), then click required position on the end of a track.
{Tips: Remove monorail foundations with Destroy/Remove.}

simutrans-124.3/simutrans/text/en/new_world.txt000066400000000000000000000121711474050137200217310ustar00rootroot00000000000000Create a New Game

Create a New Game

The Create a New Game window sets options for a new game. This creates a new map with the selected settings. You can configure many game variables including the size of terrain, initial number of urban areas and the number of industries. A preview of the selected terrain is also displayed in the Create a New Game window.

When this window is open all other game-options are disabled. To return to current game by closing the Create a New Game window, click the x-button located on the titlebar.

Arrow-buttons adjust settings and buttons switch on/off options or open new controls.

Map number - Selects a terrain to use for the game.
Click on number-box and type the required map number or use the arrow-buttons to cycle through the terrains. The preview area shows the selected terrain as it would appear in the game (water is blue, lower land is darker than higher land).

Size - Sets the map size as W x H. The number-box on top is the width, and the one below it is the height. The memory required for the map is displayed in brackets.
NOTE: Large maps need more memory and take more time to generate. The game and other graphics require an extra 88MB in pak64 and 144MB in pak128. As a general rule of thumb, on a computer with 256MB RAM do not try maps much larger than 512 x 512 squares.

Random Map - Selects a new terrain at random. Other settings do not change.

Load Height Map - Loads a custom terrain. Opens the Load Height Map window.

Number of cities - Sets the initial number of urban areas in your game. If the map is too small or too rough, less cities will be created. Further new cities can be added manually by switching to public player.

Median citizens per city - Sets the average initial population of all urban areas. Simutrans will try to generate more small villages than large cities.

Intercity road length - Sets the maximum length of public roads between urban areas at the start of the game. Set this to a higher value to connect urban areas further appart.

Factories and shops - Sets the initial number of industry supply chains outside urban areas. More industry chains will appear automatically as the urban area's population increases.
NOTE: If the terrain is very hilly, suitable flat space may not be found for creating industry chains, therefore less industries appear.

Tourist attractions - Sets the inital number of sites outside of urban areas that attract passengers and mail. Tourist attractions appear outside urban areas in addition to any attractions generated with new towns or cities at the start of the game.

Use timeline from year - Sets the start year for your game. Click the square-button to play your game with time based constraints. As time passes in the game, more vehicles, buildings and industries appear.

When this option is not selected, all vehicles, buildings, and industries are available and used in your game. Urban areas appear with buildings from all eras and slower vehicles are not as profitable as faster ones, as income is calculated by the average speed of transport vehicle used.

Use beginner mode - Sets the option that allows a higher level of income to be received in game-play from transporting goods and passengers. By default, when played in 'beginner mode', you will receive 150% of value as received when playing in normal mode. Furthermore, industry will not cease supply when consumer(s) have excess supply.

Settings - Opens the Extended Settings window. Here all parameters can be accessed that are available also in simuconf.tab file.

Landscape Settings - Opens the Landscape Settings window, which controls various map settings: roughness, water level, climates, forests, and rivers.

Load Game - Loads a saved game. This displays the Load Game window with controls to re-start a previously saved game. When a saved game is loaded, it replaces the current game without confirmation.

Load Scenario - Loads a scenario, i.e. a game where a certain goal must be fulfilled. This is an alternative to the usual, open-ended Simutrans playing style.
NOTE: Some paksets may not have any scenarios.

Start Game - Starts a game by creating a new world, using the selected settings. Click this button to start playing Simutrans. Good Luck and Enjoy your Game!

Quit - Click this button to exit game.

TIP: To change default values when starting Simutrans or to change other global properties, modify values in the simuconf.tab file.

simutrans-124.3/simutrans/text/en/options.txt000066400000000000000000000027461474050137200214330ustar00rootroot00000000000000Game Options

Game Options

Game Options opens controls for the operation & presentation of the game; exit Simutrans from Game Options.

Click on floppydisc-icon at top of game-view to open Game Options.

Click on button to open new controls:

Language: sets the language used in game.

Players: opens a list of different player companies.

Player Colour: sets the colour of the player's company.

Display: settings for how the game appears in Simutrans.

Sound: settings for sound & music in the game.

New Game: opens controls to start a new game (closes other toolbars, texts & options in current game).

Load Game: opens controls to re-start a saved game.

Save: opens controls to store the current game, that can be played later.

Load Scenario: opens controls to play a scenario, i.e. a game where a certain goal must be fulfilled.

Scenario Info: Normally disabled, it shows current scenario details when one is loaded.

Quit: exits Simutrans, current game is not saved!

simutrans-124.3/simutrans/text/en/password.txt000066400000000000000000000022211474050137200215660ustar00rootroot00000000000000Change Player Name and Password

Change player name and password

Change player name and password is invoked in two ways:

·Either by clicking on the box to the right of a player's name in the Player List or
·By changing to a password protected player and issued a command.

If the player has a green box to the right of the name, it is not password protected, and can be claimed and password protected by pressing the green box and entering a password. If the name is not selectable, you must specify a valid password.

You can change the name of any player that does not have a password or that you have unlocked by entering the password by editing the text in the top line.

A password protected player will have a red box right of the name in the Player List. Once you enter the correct password, the box will turn green and you will be able to play as that player. The entered password to unlock is kept locally, so you have to enter the password only a single time, as long as you do not restart the program.

simutrans-124.3/simutrans/text/en/players.txt000066400000000000000000000047311474050137200214130ustar00rootroot00000000000000Player List

Player List

Player List provides information & has controls for different player companies.

Click on Players-button in Game Options or press [k] to open Player List which shows player names & Account Balances.

There are fourteen players: human, public service and twelve empty slots. The can be either filled by other players (human) or by two types of AI.

Click on the square-button will enable a player. If this player is an AI, it can be stopped or continued to expand by this button. Switching off an AI player during a game will not remove its transport network.

Click on arrow-button to operate as that player company in the current game. A confirmation message appears that player has been changed: click on x in top-left corner of message or use keyboard to close.

Click on player name to see their Finances. If the player slot is not assigned, you can select what kind of player should occupy this slot. To activate it, use the leftmost square box.

Players can be protected by passwords. If you play as a protected player you have access to many statistics but are not allowed to change anything game relevant for this player.
A protected player is marked by a red box to the right of his name. If no password is set or the player is unlocked, this box is shown in green. Click on the box to open the password dialog, where the passwort can be typed or set.

For network games cooperation between players may be desirable. You can make you stops public. Any player can either connect or directly drive to a public stop. Also tracks can be shared, by making the connection tiles public. Control over which companies are allowed to run on such a track can be done via gates.

Players may not build items or place waypoints on another player's track or road, or remove items built by another player (however some items built by the public service player may be removed using Destroy/Remove).

At the bottom is an option to enable freeplay mode (if the public player is not locked). In this mode you will never get bankrupt. Otherwise after getting a negative company values, a player will be eliminated and the slot freed after a year.

simutrans-124.3/simutrans/text/en/privatesign_info.txt000066400000000000000000000010701474050137200232730ustar00rootroot00000000000000Private Way Entrace Gate

Private Way Entrance Gate

With this dialogue you can exclude all unchecked players from entering your way with their vehicles through this gate. (The public player setting will affect the city cars.) The player, which is allowed to pass, will see an open gate or barrier, and the excluded player will see a closed gate or barrier.

This sign is built from one of the way building tool bars (like railroad tools or road tools).

simutrans-124.3/simutrans/text/en/railtools.txt000066400000000000000000000204031474050137200217360ustar00rootroot00000000000000Railroad Tools

>Railroad/Train/Rail Tools

Railroad Tools construct a train transport network. Tools may build: railtrack (and electrify or remove it); bridges; tunnels; signals; depots; station platforms; & extensions. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click train-icon at top of game-view to open toolbar. Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, maintenance cost in brackets, maximum speed limit & maximum length.

?Railroad Tools include, from left to right:

Rail Track: tools build Tracks for rail vehicles between two points. Tracks can only be built on slopes in the direction of the slope & may not find a path across rough terrain, water and obstructions. New Track built, may use existing Track in its path.
To build Track: click on tool to select Track (changes cursor to Track), then click on game-view for start-point of Track (shows a bulldozer in game-view and map co-ordinates on right of bottom-bar under game-view), & finally click on game-view for end-point for Track.
{Tips: Different types of Tracks may connect (however not when built by some other players). Use bridges & tunnels to connect tracks across rough terrain, or to avoid obstructions. Use Landscape tools to change terrain, to enable paths for Track. Use Destroy/Remove to remove individual pieces of Track & some obstructions. Use [Ctrl] at same time for extra functions. Press [t] to select last Track tool used.}

Electrify Track: tools electrify Track, bridges and tunnels between two points in game-view, for electric vehicles.
To electrify Track: click on tool or press [e] (changes cursor to electric-track-icon) to select, then click on Track in game-view for start-point of electrification (places a electric-track-icon in game-view), & finally click on a second point on track, to electrify portion of track up to start-point.
{Tips: Use Destroy/Remove to change back to non-electric tracks.}

Remove Tracks: tool removes Track & electric Track, when no vehicles are present, between two points in game-view (Please note: platforms, signals, tunnels & bridges in path are removed too). Use of tool incurs a construction cost.
To remove Track: click on tool (changes cursor to a red-cross); then click on Track (selects deletion-point shown by a red-cross in game-view); & finally click at second point on track, to remove portion up to first deletion-point.
{Tips: Operate as another player to remove their Tracks.}

Rail Bridge: tools build straight bridges, for rail vehicles to pass, between two pieces of Track in game-view. Bridges have a maximum span.
Tools build bridges from an end of a Track to a suitable place (another Track-end or slightly higher land, within span).
To build a bridge: click on tool to select (changes cursor to bridge), then click on the end of a Track (start-point of bridge) to build.
Some obstructions or lack of a suitable place for bridge-ends will prevent bridge being built: place Track at both sides that is to be bridged, & try again.
{Tips: Use Destroy/Remove to remove bridges (click on bridge-end) & some obstructions to bridge building. Use Track tools to connect bridge-ends to Track.}

Rail Tunnel: tool builds a straight tunnel, for rail vehicles to pass through land, between two pieces of Track in game-view. Tunnels cannot incline: vehicles enter & leave at the same height.
The tool builds a tunnel, on an end of Track placed on a slope. To build a tunnel: click on tool (changes cursor to a tunnel), then click on Track-end on slope for the tunnel entrance.
If a tunnel cannot find a suitable exit (a slope free from obstructions), it will not be built: place Track on both sides that is to be connected, & try again.
{Tips: Use Landscape tools & Destroy/Remove to create suitable places for tunnel entrances and exits. Use Track tools to connect tunnel-exits to Track.}

Rail Signals: tools build signals for rail vehicles on a Track in game-view. Signals direct & regulate flow of vehicles on Tracks & bridges, junctions & Stops.
Two-way & one-way versions of signals can be built. To build a two-way signal on Track: click on tool to select signal (changes cursor to signals); then click on Track. To build a one-way signal: click again at same point, with signals-cursor, to cycle through one-way signals, back to a two-way signal.
IMPORTANT: Take care not to place one-way signals that prevent vehicles reaching their destination, by default vehicles drive on the right (can be changed in simuconf.tab).
If you hold the control key when clicking on a signal, the multiple signal builder is activated.
- Signals: vehicles proceed only if Track ahead up to next signal or destination in Schedule (a Stop or waypoint) is not occupied by another vehicle. In one-way mode vehicles pass in one direction only.
- RailClose: vehicles do not proceed beyond signal (available in one-way mode only).
- PreSignals: vehicles proceed if area of Track ahead (either between three consecutive signals or to next destination in Schedule) is not occupied by another vehicle. In one-way mode they let vehicles pass in one direction only.
- ChooseSignals: direct vehicles to an empty station-platform, at a multi-platform Stop: a vehicle passing this signal may use any empty platform at its next destination, and not just the one assigned in its schedule. If no empty platform or clear route to next destination is found, then vehicles wait at signal.
{Tips: Remove signals with Destroy/Remove. Hold down [Ctrl] to place signals on bridges over lower Tracks.}

Train Depot: tool builds a depot for purchasing & managing trains and carriages. Depots have a maintenance cost & are built on the end of Track in game-view.
To build a train depot: click on tool (changes cursor to a depot), then click on end of track.
{Tips: Remove depots with Destroy/Remove. Depots show electric vehicles only if on electric track.}

?Rail-stops: tools build station-platforms, used by rail vehicles to pick-up and drop-off goods, passengers & mail.
A station-platform when not built adjacent to an existing Stop will create a new Stop.
Rail-stops have a maintenance cost & are built on Track (but not at bends and junctions in Track).
Rail-stops have a catchment area for goods, passengers & mail. Different station-platforms may have different capacities for goods, passengers & mail. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the station-platform allows a Stop to handle.
To build a station-platform: click on tool to select (changes cursor to a platform), then click on Track.
{Tips: Remove Rail-stops with Destroy/Remove. Extend station-platforms & build multi-platform Stops (by building more platform sections on adjacent track) to accommodate longer and more vehicles, increase capacity & catchment area. Press [v] to show/hide catchment area for goods & passengers in game-view. Hold down [Ctrl] to build on bridges above lower Tracks.}

Extensions:tools construct extensions & buildings for Stops which may increase capacity, catchment area and maintenance cost.
In the corner of some tool-options an icon (also used in Station List & Stop Information) shows which items the extension allows the Stop to handle.
To build an extension: click on tool to select (changes cursor to extension), then click required position, beside an existing Stop, in game-view. The new extension is now considered to be part of the Stop.
{Tips: Remove extensions with Destroy/Remove.}

simutrans-124.3/simutrans/text/en/removal_tool.txt000066400000000000000000000042361474050137200224360ustar00rootroot00000000000000Removal Tool

Destroy/Removal Tool

Removal Tool is used to destroy and remove unwanted items and obstructions to construction on a single game-tile in the game-view.

To Use: Click red-cross-icon (bulldozer-icon in pak128) at top of the game-view or press [r] key to open Removal Tool (it changes cursor to a red-cross-over-dust-cloud). Position cursor in game-view, a yellow outline indicates position on which tool will operate (map coordinates are indicated in the bottom-bar). Then click on object in the game-view to remove it. If you are authorized for removal, the object will be removed from the map without warning.

Cost incurred is displayed immediately in game-view and appears also under Construction Costs item in Finances window. The cost of removal is equivalent to the cost of construction (for player items). The cost of destroying city buildings is the same as their value as shown in dialogue opened with Inspection Tool. There is also a cost for destroying trees.

Removal Tool can be used to remove individual pedestrians and private citycars as well.

The order in which items are removed from a single road/track tile: pedestrian or private citycar, signals, stop/station platform, electrification of way, bridge or tunnel, way itself (track first if on road).

TIPS:
· To remove a player vehicle, sell/retire it from Convoy Details window.
· To remove an industry, attraction or town hall, switch to public service player first.
WARNING: When removing a town hall, all city buildings from that urban area are also removed.
· To destroy/remove another player items, select to play as other player first.
· To remove segments of track or road use Remove tracks tool (also found in Tram tools) or Remove roads tool.

simutrans-124.3/simutrans/text/en/roadtools.txt000066400000000000000000000212611474050137200217370ustar00rootroot00000000000000Road Tools

Road Tools

Road Tools construct a road transportation network for goods and passengers. Tools may build or remove: roads, bridges, tunnels, signals, depots, extensions, & Stops. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click truck-icon at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, maintenance cost in brackets, maximum speed limit & maximum length.

Road Tools include, from left to right:

Road: tools build road between two points for road vehicles. Roads may not be built on areas occupied by other buildings. Roads can only be built on slopes in the direction of the slope & may not be built across rough terrain or water. New road built may use existing road in its path.
To build road: click on tool to select road type (changes cursor to road), then click on in game-view for start-point of road (shows a bulldozer in game-view and map co-ordinates on right of bottom-bar under game-view), & finally click on game-view for end-point for road.
{Tips: Different types of roads may connect even when built by different players . Use bridges & tunnels to connect roads across rough terrain, or to avoid obstructions. Use terraform tools to change terrain, to enable paths for road. Use Destroy/Remove to remove individual pieces of road & some obstructions. Use [Ctrl] at same time for extra functions. Undo [z] does not refund constructions costs. Press [s] to select last roadway tool used.}

Remove roads: tool removes road, when no vehicles are present, between two points in game-view (Road-stops, signals, tunnels in bridges in path are removed too). Use of tool incurs a construction cost.
To remove road: click on tool (changes cursor to a red-cross); then click on track that is to be deleted (selects deletion point shown by a red-cross in game-view); & finally click at another point on track, to remove portion of track up to first deletion point.
{Tips: Operate as another player to remove their roads.}

Road Bridge: tools build straight bridges, for vehicles to pass, between two pieces of road in game-view. Bridges have a maximum span. Tools build bridges from an end of a road to a suitable place (another road-end or slightly higher land, within span).
To build bridge: click on tool to select bridge (changes cursor to bridge), then click on the end of a road, (starting-point of bridge). Some obstructions or lack of a suitable place for bridge-ends may stop bridge being built: build road at both sides that is to be bridged, & try again.
{Tips: Use Destroy/Remove to remove bridges (click on bridge-end) & some obstructions to bridge building. Use Roadway tools to connect bridge-ends to road.}

Road Tunnel: tool builds a straight tunnel, for vehicles to pass through land, between two pieces of road in game-view. Tunnels cannot incline: vehicles enter & leave at the same height.
Tool builds a tunnel, on an end of a road placed on a slope. To build a tunnel: click on tool (changes cursor to a tunnel), then click on road-end on slope for the tunnel entrance. If a tunnel cannot find a suitable exit (a slope free from obstructions), it will not be built: place road on both sides that is to be connected, & try again.
{Tips: Use Landscape tools & Destroy/Remove to create suitable places for tunnel entrances and exits. Use Roadway tools to connect tunnel-exits to roads.}

Road signals & barriers: tools build signals & barriers, for road vehicles, in game-view. Signals & barriers direct & regulate flow of vehicles on roads & bridges, and at junctions & stops (where goods and passengers are picked-up and dropped-off). Two-way & one-way versions of some signals can be built.
IMPORTANT: Take care signals not place signals that prevent vehicles reaching their destination, by default vehicles drive on the right (can be changed in simuconf.tab).
- Traffic lights: tool builds signals in game-view to regulate the flow of road vehicles at junctions, either allowing them to proceed or making them wait for a while. Click on tool to select (changes cursor to signal), then click on road to build. Click again at junctions to change orientation of signals.
- single barrier: tool builds a barrier to prevent road vehicles using one side of a road. Click on tool to select (changes cursor to barrier), then click on road to build, click again at same position to change side of road to which barrier applies.
- road closed: tool builds a barrier to prevent road vehicles proceeding. Click on tool to select (changes cursor to barriers), then click on road to build.
- no entry: tool builds a signal to prevent road vehicles proceeding on one side of a road (similar to a single barrier. Click on tool to select (changes cursor to signal), then click on road to build, click again at same position to change side on road that signal is placed. There is also a variant called private way entrance gate which only let pass traffic of certain players.
- minimum 80km/h tool builds a signal to prevent road vehicles proceeding if their maximum speed is below 80km/h. Click on tool to select (changes cursor to signal), then click on road to build, click again at same position to change side of road to which signal applies.
- Choose Point: tool builds a signal to direct a road vehicle to an empty Road-stop to pick-up or drop-off goods and passengers at a Stop with multiple Road-stops: a vehicle passing this signal may use any free Road-stop at its next destination, and not just the one assigned in its schedule. If no empty Road-stop or clear route to next destination is found, then vehicles wait at signal. Click on tool to select (changes cursor to signal), then click on road to build, click again at same position to change side of road to which signal applies.
- highways: (available only in pak128) tools build a signal that only allow vehicles to proceed in one direction on a road if their maximum speed limit is over 80km/h.
Click on tool to select (changes cursor to signal), then click on road to build, click again at same position to change direction on road to which signal applies.
{Tips: Remove signals with Destroy/Remove. Use [Ctrl] to place signals on bridges over lower roads.}

Road Depot: tool builds a depot for purchasing & managing road vehicle and trailers. Depots have a maintenance cost & are built on the end of road in game-view.
To build a Road Depot: click on tool (changes cursor to a depot), then click on end of road.
{Tips: Remove depots with Destroy/Remove.}

Car Parking: (available only in pak 128) tools construct extensions for Stops which increase capacity & catchment area for goods & passengers, and maintenance cost.
To build an extension: click on tool to select extension (changes cursor to extension), then click required position on a road, beside an existing Stop in game-view. The new extension is now considered to be part of the Stop.
{Tips: Remove extensions with the Destroy/Remove.}

?Road-Stops: tools build places for road vehicles to pick-up and drop-off goods & passengers.
A Road-stop when not built adjacent to an existing Stop will create a new Stop.
Road-stops are built onroad& have a maintenance cost and a catchment area for goods, passengers & mail. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the Road-stop allows a Stop to handle. Different Road-stops may have different capacities for goods, passengers & mail.
To build a Road-stop: click on tool to select (changes cursor to roadstop), then click required position on a road in game-view.
{Tips: Remove Road-stops with Destroy/Remove. Press [v] to toggle catchment area for goods & passengers in game-view. Roadstops cannot be placed on road built by some other players. Use [Ctrl] to build on bridges over lower roads. Create Stops with multiple places for vehicles to increase capacity and catchment area.}

simutrans-124.3/simutrans/text/en/save.txt000066400000000000000000000032161474050137200206670ustar00rootroot00000000000000Save

Save

Save stores the current game to a file (to continue play at a later time) & can be used to delete these files.

Save opens from Game Options or by pressing [S]; & list names, date & time of previous games.
If all games are not visible: use slider-bar on right-side of list to scroll names.

The current game can be saved to a new file or over an existing game.
To save game to new file, enter new name into box at top of Save: click on box, type name & press [Enter] or [Return] or click on OK; the new filename is listed.
IMPORTANT: If a listed filename is used: old game is replaced, by current game, & lost.

By default the current game appears in filename box, to save to this file: click OK (old data is lost and replaced with current data).
To save game to file over an old game: click on a name in list (old game is replaced by current game).

Filenames can be a combination of letters, numbers & symbols to a maximum length of 57 characters; after save, only 20 (approx.) characters are shown in Save & Load.

WARNING: Click x-button by filename to DELETE game immediately & permanently, the filename is removed from list. Use this function carefully.

{Tips: Re-start a saved game from Load.
Change autosave (automatic game save) in simuconf.tab}.

Click on Cancel to close Save; or x in top-left-corner; or use keyboard.

simutrans-124.3/simutrans/text/en/scenario.txt000066400000000000000000000003521474050137200215320ustar00rootroot00000000000000Scenario

Scenarios

You can play scenarios with simutrans. Here you have to fulfill certain goals: connect a factory, get rich as soon as possible, or erect a monumental headquarter.

simutrans-124.3/simutrans/text/en/schedule.txt000066400000000000000000000103531474050137200215250ustar00rootroot00000000000000Schedules

Schedule Controls

Schedule Controls sets the Schedule (route and minimum quantity of goods and passengers required by a Convoy to proceed) for a Convoy or a Line.
It listsStops (where Convoys pick-up and drop-off goods and passengers) and waypoints (which can be used to direct Convoys to a path if more than one is available or provide interim destination points) with their map co-ordinates.

Schedule Controls for a Convoy opens from Schedule option-button in Convoy Information and Depot Controls.
Controls for the Schedule of a Line open from New Line and Update Line option-buttons in Line Management and Depot Controls.

When Schedule Controls is opened from Convoy Information the assigned Line (if any) is shown at top of controls.
Line Name: Click on left/right-arrow buttons by name to cycle through Lines or click on name-box to open a drop-down-list of Lines (click on Line in drop-down list to select).
Click on name-box and type new name to change name of Line.

Wait For: sets the minimum quantity of goods and passengers required by a Convoy to proceed. The percentage figure refers to the total capacity of the Convoy and not an indiviual type of item carried.
A Convoy will wait at Stop until required percentage is on board.
To use: click on Stop in list to select (> by name shows that Stop has been selected), then use arrow-buttons to cycle through percentages.
{Tips: To set or change Wait For levels for all Convoys on a Line, use Update Line option-button in Line Management or Depot Controls. To set or change the Wait For level for a Convoy and no other Convoy on assigned Line, use Schedule option-button in Convoy Information or Depot Controls.}

Option-buttons (click to use, button is indented when selected) include:

Add Stop: option places a Stop used by vehicles to pick-up or drop-off goods and passengers (water transport vehicles may use any square of water in the catchment area of a dock) or waypoint on route.
To add a Stop or waypoint: click on option to select (changes cursor to halt-arrow), then click required point in game-view for Stop or waypoint (point on road, track or water as appropriate for type of vehicle). The Stop or waypoint, is now listed in Schedule Controls.
{Tips: Vehicles do not pick-up or drop-off goods & passengers at waypoints.}

Insert: option places a Stop or waypoint on route, before an existing Stop/waypoint.
To insert a Stop or waypoint: click on an existing stop/waypoint in list to select (> by name shows Stop/waypoint is selected), then click on Insert option-button (changes cursor to halt-arrow), then click required point in game-view for Stop or waypoint (point on road, track or water as appropriate for type of vehicle).
The new Stop or waypoint is listed in Schedule Controls before the previously selected Stop/waypoint.
{Tips: Vehicles do not pick-up or drop-off goods or passengers at waypoints.}

Remove: option deletes a Stop or waypoint from the route.
Click on option-button to select, then click on item in list to remove.

replicate backwards: option adds existing Stops and waypoints in reverse order to route. Wait For levels are also replicated. Click on option-button to use: Schedule Controls lists new route.

Promote to Line: (only available when Schedule Controls is opened from Convoy Information) creates a new Line using current Schedule. The new Line is assigned a number and listed in Line Management.

simutrans-124.3/simutrans/text/en/server.txt000066400000000000000000000022041474050137200212330ustar00rootroot00000000000000Game information / Server

Game information / Server

Game information / Server will show you the current state of the game running, including the date, map size, number of companies, towns, citizens, factories, vehicles running, and so on.

If your current game is not already an online game, it will show you a dropdown list with other servers to connect. If this list is empty, there are no servers for your pak version or program version. You can then use the show all button to see all existing servers.

Upon selection of a server you will see a game information overview of the state of the server. (If the server is down, it may take a while to confirm this.) It will also display the pak set and program version of the server. If both are black, then your pak set and program version match the server and you can join by pressing Play online.

If there is a mismatch of the pak set, the entry will be red. You can then use the button Compare your pak to get a report on missing, different, or extra paks. (This may take a while.)

simutrans-124.3/simutrans/text/en/settings.txt000066400000000000000000000012701474050137200215670ustar00rootroot00000000000000Extended Settings

Extended settings

Extended settings allows to modify nearly every parameter of the game engine in the same way editing the central configuration file simuconf.tab. Therefore all parameters have exactly the same name as their counterpart in simuconf.tab, where you can also find the documentation of these parameters.

If you modify an existing game, you may need to solve and reload to apply the settings. Some settings (like factory connections) will only affect newly created objects.

Attention:
You can easily create an unplayable game or make you ruin game.

simutrans-124.3/simutrans/text/en/shiptools.txt000066400000000000000000000123701474050137200217560ustar00rootroot00000000000000Dock/harbour tools

Dock/harbour tools

Dock/harbour tools construct a marine and waterway transport network. Tools may build or remove: canals, locks, various docks, and a ship depot. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click boat-icon at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, maintenance cost in brackets, and maximum speed limit.

Dock/harbour tools include, from left to right:

Canal: tool builds waterways, for boats and barges, between two points in game-view.
Canals can only be built on slopes in the direction of the slope & may not find a path across rough terrain. Canals built between points, may use existing canal in its path.
To build a canal: click on tool to select (changes cursor to canal), then click on terrain for start-point (shows a bulldozer in game-view and map co-ordinates on right of bottom-bar under game-view), & finally click on terrain for end-point.
{Tips: Canals built by different players may not connect. Use Landscape tools to change terrain, to enable paths for canals. Use Destroy/Remove to remove individual pieces of canal & some obstructions. Undo last route connection [z] does not refund constructions costs.}

Remove channels: tool removes portion of canal, when no vehicles are present, between two points in game-view (NB: Channel-stops in path are removed too). The tool has an associated construction cost.
To remove canal: click on tool (changes cursor to a cross); then click on canal that is to be deleted (selects deletion-point shown by a red cross in game-view); & finally click at another point on canal, to remove portion up to first deletion-point.

Ship Hoist: tool builds a canal lock and bridge to raise/lower a boat or barge by one level on a canal in game-view. The bridge has a maximum span and is built on the end of a canal to a suitable place (another canal-end or slightly higher land, within span).
To build bridge: click on tool to select bridge (changes cursor to hoist), then click on the end of a canal, (starting-point of bridge). Some obstructions or lack of a suitable place for bridge-ends may stop hoist being built: build canal at both sides that is to be bridged, & try again.
{Tips: Use Destroy/Remove to remove bridges (click on hoist-end) & some obstructions to bridge building.
Use Canal tools to connect bridge-ends to water ways.}.

Wharf (Canal Quay in pak128) tool builds a dock on a canal in game-view for water-transport-vehicles to pick-up and drop-off cargo and passengers.
A dock when not built adjacent to an existing Stop will create a new Stop.
A dock has a catchment area for goods, passengers & mail. In the corner of the tool-option is an icon (used in Station List & Stop Information) shows which items the dock allows a Stop to handle.
To build a dock: click on tool (changes cursor to a channelstop); then click on a canal in game-view to construct.
{Tips: Remove docks with Destroy/Remove. Press [v] to show/hide catchment area for goods and passengers in game-view.
Stops just for water transport vehicles will not be listed in ?Stops/Station list}.

Ship-stops: tools build various items that construct docks in game-view for water-transport-vehicles to pick-up and drop-off cargo and passengers.
Docks are built at edges of straight coast.
A dock when not built adjacent to an existing Stop will create a new Stop.
Docks have a catchment area for goods, passengers & mail. In the corner of the tool-option is an icon (used in Station List & Stop Information) that shows which items the dock allows a Stop to handle. Different docks may have different capacities for goods, passengers & mail.
To build a dock: click on tool to select (changes cursor to a dock) and then click on a slope by water to build
{Tips: Remove docks with Destroy/Remove.
Size of docks can be increased by building on adjacent squares. Water-transport vehicles may use any square of water in the catchment area of a dock.
Stops just for water transport vehicles will not be listed in ?Stops/Station list.
Off-shore Industry such as Oil Rigs do not require a dock, water-transport vehicles may use any square of water in the catchment area of an off-shore Industry.
Press [v] to show/hide catchment area for goods and passengers in game-view.}

Ship Depot: tool builds a depot for purchasing & managing ships, boats and barges. Depots have a maintenance cost & are built on water in game-view.
To build a ship depot: click on tool (changes cursor to a depot), then click on water in game-view.
{Tips: Remove depots with Destroy/Remove.}

simutrans-124.3/simutrans/text/en/signal_spacing.txt000066400000000000000000000020011474050137200227010ustar00rootroot00000000000000Signal spacing

General usage:


-- Ctrl-click on signal icon brings up this gui.
-- Click-and-drag on track brings preview of signals to be built, release the mouse button to build. Signals will be built allowing trains to pass only in the direction you dragged the mouse.
-- In network games: first ctrl-click on the track and release mouse button. While you hold down mouse button and move the mouse, you see preview. Release button again to build.

Parameters in this window:

-- Signal spacing: how many tiles apart consecutive signals should be placed (diagonal count as 1/2 tile). This value is shown on the icon if the signal is selected.
-- Remove interm. signals: if toggled, other signals on the way will be deleted.
-- Replace other signals: if toggled, other signal on tiles we would like to build our signals on will be deleted.

These parameters can be set for all different signals independently.

simutrans-124.3/simutrans/text/en/simutrans.txt000066400000000000000000000047521474050137200217640ustar00rootroot00000000000000About Simutrans

Welcome to Simutrans!

First, select a map: either choose one of Simutrans' thousands of maps or create a new one from a height map. Then put yourself in the shoes of a young entrepreneur with some money from your grandparents: eager to make them proud, with ambitions of establishing a successful transport company, your challenge now is to build a prosperous transport empire.

As time passes, develop your company into a successful enterprise, whilst at the same time keeping the economy running smoothly by delivering freight & satisfying the travel requirements of millions of passengers. You can transport passengers, mail and goods by rail, road, ship and even air.

Every map has something different to offer. Take a good look at your surroundings: their future lies in the hands of you and your competitors.

You may find it easiest to begin by supplying a power station with the goods it needs. With the money you've made, gradually expand by supplying other factories - maybe even using central hubs where goods are reloaded. The disadvantage of only transporting goods is that towns and cities won't grow and new industries will not appear.

Alternatively, you may immediately go for passenger (and mail) transport. This is more challenging, as the inhabitants of the Simutrans world all wish to travel to specific destinations Some need to go to factories to work, some want to go shopping in the city centre, and others want to visit tourist attractions. But if you don't offer a connection to their desired destination, passengers will not travel with you at all.

You will need to build a transport network where as many popular destinations as possible are reachable. When your network is established, you will need to continuously upgrade it to keep abreast of demand, so plan ahead! If passengers like your service, towns will grow, new industries will be established, and only then will the economy run smoothly.

You can play as long as you like. Start in 1880 and finish in 2050, or set a start time anywhere between these dates. There will be new vehicles and buildings throughout this time. Play against the AI or on your own. But watch out: if your net wealth is negative for three months in a row, you will go bankrupt and the game is over. Check your net wealth in the Finances window.

The Simutrans Team and the community wish you an enjoyable time playing Simutrans!

simutrans-124.3/simutrans/text/en/slopetools.txt000066400000000000000000000044211474050137200221330ustar00rootroot00000000000000Landscaping Tools - raise/lower land

Landscaping Tools

Landscaping Tools raise & lower terrain and may be used to provide suitable places for construction.

Click on sloping-land-icon at top of the game-view to open toolbar. After opening or clicking on toolbar, hover the mouse cursor over the tools to see the names and construction costs.

Tools operate on areas empty of obstructions (e.g. roads, tracks, buildings, stops & stations).

Click on the tool icon to select it, changing cursor, then position the cursor on terrain in the game-view and click to use:

Raise land/Lower land: raises/lowers terrain. Cursor is an upward/downward arrow. Tools also open with [u] and [d] keys.

Build artificial slopes: creates a slope, in direction indicated by a toolbar icon. May create an artificial vertical surface in the process. Cursor is a yellow-cube outline which positions slope.

Raise square/Lower square: raises/lowers a specific square (tile) of terrain. May create an artificial vertical surface in the process. Cursor is a yellow-cube outline which selects square.

Restore natural slope: returns terrain to a natural landscape, removing artificial vertical surfaces in the process. Cursor is a yellow-cube outline which positions tool.

TIPS:
· Landscaping Tools are easier to use with grid, press [#] and zoom-in the game-view.
· Use Destroy/Removal Tool to remove some obstructions.
· Depending on map, tools can raise land into/out of water.
· Lowering the land to a certain level creates a channel.
· Slope tools can be used to create tunnel slopes underground.
· Depending on the pakset you play, Landscaping Tools toolbar may contain additional tools (usually used by public service player): raise/drain water in lakes, convert ground to a specific climate zone, etc. See also Game and map editing tools.

simutrans-124.3/simutrans/text/en/sound.txt000066400000000000000000000030301474050137200210530ustar00rootroot00000000000000Sound Settings

Sound Settings

Sound Settings window has controls for sound effects & background music. It opens from Game Options menu.
NOTE: To get better sounds in Windows an SDL-compiled version of Simutrans is recommended.

Use arrow-buttons to adjust settings or slider-bars to decrease/increase volume.

Sound volume: sets volume of sound effects in game. Sounds can be switched off completely with the Mute sound button.

Many Simutrans objects are able to produce sounds: ambiental (at cursor position after several seconds of no movement), way crossings (when approached by vehicles), factories (when producing goods), vehicles (when departing stop/stations). It depends on the pakset you play what sounds are implemented.

Music volume: sets volume of background music. Music can be switched off completely with the Mute MIDI music button. If no music is available then controls will not function.
Music tracks (in MIDI format) are stored in folder simutrans/music/.

Currently playing: changes music; arrow-buttons cycle through available music tracks.

Shuffle tracks: music tracks are played at random.

NOTE: If Simutrans is started with command-line option '-nosound' or '-nomidi', sound or music will not be used.

For more information about music in Simutrans visit http://wiki.simutrans.com

simutrans-124.3/simutrans/text/en/special.txt000066400000000000000000000140471474050137200213550ustar00rootroot00000000000000Special Construction Tools

Special Construction Tools

Special Construction Tools construct items that are not traffic related and also allow you to operate as another player in the game.

Click red-drop-in-yellow-circle-icon (crane-icon in pak128) at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: constructioncost.

Special Construction Toolsinclude, from left to right:

Post Office: tools build a post office that enable a Stop to handle mail. Post Offices increase the capacity and catchment area of the Stop and have a maintenance cost.
To build a post office: click on tool to select, then click in game-view by an existing Stop. The new Post Office is now considered to be part of the Stop.
{Tips: Remove Post Offices and some obstructions with Destroy/Remove.}

Station Extensions: tools construct extensions & buildings for Stops. Extensions may increase capacity & catchment area for goods & passengers, and maintenance costs. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the extension allows the Stop to handle.
To build an extension: click on tool to select (changes cursor to extension), then click required position, beside an existing Stop, in game-view. The new extension is now considered to be part of the Stop.
{Tips: Remove extensions with Destroy/Remove.}

P+ Change Player: allows game-play as another player if Allow player change was selected at the start of the game. Extra options are available as the public service player.
Click on tool (or press [P]) to cycle through players. A confirmation message appears that player has been changed: click on x in top-left corner of message or use keyboard to close.

found a new city: tools establishes a new urban area.
To build a new city: click on tool or press [C] to select (changes cursor to town hall), then click required position, in game-view. The new city costs 5 million credits and will be built without further confirmation.
{Tips: Click on the town hall in game-view with Destroy/Remove to remove the new city buildings.}

Plant trees: tool places a tree in game-view.
To plant a tree: click on tool to select (changes cursor to tree), then click required position.
{Tips: Remove trees with Destroy/Remove.}

Build Power Transmission Line: tool builds powerlines that supply power between transformer stations at power plants and industry (to increase productivity). The supply of power generates income. These powerlines cannot cross diagonal tracks and roads.
To build a high power transmission line: click on to tool or press [l] to select (changes cursor to power lines), then click on a transformer station placed next to a power station, & finally click on a transformer station at an industry to supply it with power to increase production.

Transformer station tool builds a transformer station at power plants or industry for connection to high power transmission lines.
To build a transformer station: click on tool or press [g] to select (changes cursor to a red-drop-in-yellow-circle), then click required position beside an industry or power plant, in game-view.
Transformer stations built at power plants must be connected to transformer stations at industry with powerlines to supply electricity.
If no electricity is being supplied, the transformer station in game-view shows a yellow-lightning-strike, when electricity is being supplied it shows a red-lightning-strike.
{Tips: Industry and power plants can have multiple transformer stations to increase electricity supply. Remove transformer stations with Destroy/Remove.}

Make a sign: tool opens controls to place a sign with personalised text in game-view and can be used to move game-view to a different point.
Click on tool to select or press [M], changes cursor to a text-marker, then click at required point in game-view to open Make a Sign controls. At the top of Make a Sign controls are co-ordinates on map of selected position and an empty box, enter required text in to box (click on box, type the text and click OK or press [Enter] or [Return]) to place sign. The new sign is shown in game-view and listed in Make a Sign controls (with map co-ordinates) when re-opened.
To move game-view to a sign point: open Make a Sign controls and click on required position in list.
To remove a Sign: click on Make a Sign tool or press [M] to select, changes cursor to a text-marker; then click on co-ordinates of sign in game-view; then click on Remove in Make a Sign controls.
To close Make a Sign controls: click on x in top-left-corner of controls; or click onCancel; or use keyboard.
{Tips: Map co-ordinates of cursors can be seen on right of bottom-bar under game-view. Use [!] to toggle texts of signs in game-view.}

Replace a stop: This tool can be used to replace a stop in the schedules of all of the convoys and lines that use it. It can also be used to change the scheduled tile within a stop (for example, to move all the lines to a different platform of a railway station). After selecting the tool, click on the stop (or part of a stop) that you wish to remove from the schedules and then on the stop (or part of a stop) that you wish to use in future. All the convoys that previously used the first stop will now use the second stop. Depending on the setup of your schedules, there may be some disruption to convoys travelling to the first stop at the moment of the change.

simutrans-124.3/simutrans/text/en/station.txt000066400000000000000000000163541474050137200214210ustar00rootroot00000000000000Stop Information

Stop Information

Stop Information provides information about a Stop (where vehicles pick-up and drop-off goods and passengers). It also has controls to access further details and change the name of the Stop.

A Stop consists of a place where a Convoy can pick-up or drop-off goods and passengers and any extension buildings.

Tools for the construction of places where Convoys can accept or deliver are available from the toolbar for the respective type of transport: ?station-platforms; monorail/maglev train stops; Tram Stops; Road-stops; Docks ; and Airstops.
{Tips: Water-transport vehicles may use any square of water in the catchment area of a dock to pick-up and drop off goods and pasengers. Larger Stops can be built by constructing on adjacent squares. Stops can be built that accomodate more than one type of transport}.

Click on a Stop in game-view with the Inspection Tool or click on a Stop listed in Station List or Line Management to open Stop Information which shows the name of the Stop in its titlebar.
Stop Information contains a name-box; a mini-view of Stop; information about the Stop; option buttons; and a list of all items ready for transport at Stop (if all items are not visible re-size Stop Information or use slider-bars to scroll items):

name: assigned name of Stop is shown in name-box at top of Stop Information.
By default name is assigned automatically when the Stop is first built and depends on urban area related to Stop and any industry within catchment area of Stop.
To change name: click on name-box and type new name.
{Tips: Use [!] to toggle view of name above a Stop in game-view. Use [v] to toggle view of catchment area of Stop in game-view. Option to number Stops available in simuconf.tab}

status-colour-bar: colours indicate operation of Stop with regards to how overcrowded it is. The status-colour-bar is also used in Station List and Line Management and is the same colour displayed in the colour-bar above a Stop in game-display:
- yellow: no service and nothing waitung.
- green: no improvements necessary.
- orange: stop is slightly overcrowded (with transfer goods mostly).
- red: stop hold more than 1.5 of its capacity, or more than 200 unhappy passengers, or a factory must stop its production because the station is overcrowded. These stops will be reported as overcrowded at the beginning of a months.
{Tips: Use [!] to toggle view of status-colour-bar (that indicate how crowded Stop is) above a Stop in game-view.}

Graphic Icons are also used in Station List and Line Management:
- freight icon(s) indicate which items (passengers, goods and mail) a Stop can handle.
{Tips: adding appropriate extensions can change the category of items a Stop can handle. Post offices can be added to Stops to enable handling of mail}.
- vehicle icon(s) indicate which types of vehicle can use Stop. Icons include: bus (for passengers), truck (for goods), train (for rail), boat and airplane. Trams can be indicated by a bus-icon or a train-icon depending on type of Stop.

Storage capacity: amount of each item (goods, passengers and mail) the Stop can accommodate.

Stop picture: is a mini-view of the Stop and any visible Convoys.
Click on the picture to centre game-view on Stop.

Passengers numbers indicate amount of following passengers who start their journey at the Stop:
- happy face indicates number of passengers, who have arrived at an uncrowded Stop as a result of its catchment area and have found a route to their destination and waited for transport.
- unhappy face indicates number of passengers who have arrived at Stop as a result of its catchment area but did not wait for transport as it was overcrowded.
- no route indicates number of passengers who have arrived at Stop as a result of its catchment area but left as they did not find a route to their destination.
{Tips: Keeping passengers happy helps growth of urban areas. Change maximum number of transfers allowed for goods and passengers in simuconf.tab}.

Goods and passengers waiting: lists items that wait for transport at Stop in groups of: passengers; mail; and type of goods.
Information shown for items includes quantity, type, final destination and first transit Stop.
Option-button (changes name with selection) sorts of items within groups:
- destination: sorts items, alphanumerically within ASCII-code order (capital letters before lower case letters), by assigned name of final destination Stop.
- via (detail): sorts items, alphanumerically within ASCII-code order (capital letters before lower case letters), by assigned name of first transfer Stop.
- via (amount): ?sorts items by quantity headed to first transfer Stop.
- amount: sorts items by quantity in descending order.
{Tips: goods-colour-bars above a Stop in game-view (use [!] to toggle) indicate quantity of items that wait for transport and are the same colour as colour-squares in Goods List.}

Chart: click option-button to toggle graph (button is indentented when graph is visible) in Stop Information.
The graph shows statistics for the last 12 months (x-axis) when a graph-option is selected.
Click on graph-option-button to see information on graph (button is indented when option selected).
Colours of lines on graph correspond to colours of graph-option-buttons:
- Happy indicates number of passengers/mails, who have arrived at an uncrowded Stop as a result of its catchment area and have found a route to their destination and waited for transport.
- Unhappy indicates number of passengers who have arrived at Stop as a result of its catchment area but did not wait for transport as it was overcrowded.
- No Route indicates number of passengers who have arrived at Stop as a result of its catchment area but left as they did not find a route to their destination.
- waiting: amount of goods and passengers at Stop that wait for transport.
- Arrived: amount of goods and passengers dropped-off by a Convoy at Stop as a final destination or transfer point.
- Departed: amount of goods and passengers picked-up at Stop by a Convoy.
- Vehicles: amount of Convoys that have departed from Stop.

Details: option-button opens Stop Details that provides further information about Stop.

simutrans-124.3/simutrans/text/en/station_details.txt000066400000000000000000000031131474050137200231130ustar00rootroot00000000000000Stop Details

Stop Details

Stop Details provides more information about a Stop (where vehicles pick-up and drop-off goods and passengers).

Stop Details opens from Details option-button in Stop Information.
If all items are not visible re-size Stop Details or use slider-bars to scroll items)

Information listed includes:
Connected factories: names and map co-ordinates (in brackets) of industry in catchment area of Stop.
{Tips: Use [v] to toggle view of catchment area of stops in game.}

Goods needed by nearby industries: types of goods required by industry in catchment area of Stop.

Lines serving this Stop: Lines that use this Stop.
Lines are listed alphanumerically within ASCII-code order (capital letters before lower case letters).

Lineless convoys serving this stops: Convoy not assigned to a line, which stop here.

Direct routes from here:lists name of Stops that can be reached without a transfer and type of items (goods and passnegers) that can be delivered.
Stops are listed alphanumerically within ASCII-code order (capital letters before lower case letters) by ?type of transport, name of Stop, and type of item that can be delivered (which is also shown for each Stop).

simutrans-124.3/simutrans/text/en/trafficlight_info.txt000066400000000000000000000011201474050137200234020ustar00rootroot00000000000000Traffic light control

Traffic light control

You can control the frequency of red and green phases for traffic lights. The numbers you can choose here, is the duration of the green phase in seconds for north/south and east/west directions.

Since all traffic lights will switch in phase, you can give an extra offset in the third field to realize an unobstructed traffic flow in certain directions through subsequent traffic lights.

A traffic light is built from the road construction toolbar.

simutrans-124.3/simutrans/text/en/tramtools.txt000066400000000000000000000170211474050137200217540ustar00rootroot00000000000000Tram/light rail tools

Tram/light rail tools

Tram/light rail tools construct a tram transport network. The tools may build: tramtrack (and electrify or remove it), signals, a tram depot, and tram stops. If playing with timeline, then as time passes in Simutrans more tool-options may appear.

Click tram-icon at top of game-view to open toolbar.
Hover mouse-cursor over tool-option (after opening or clicking on toolbar) to see name & where appropriate: construction cost, & maximum speed limit.

Tram/light rail tools include, from left to right:

Tram Track: tools build Track, for rail vehicles between two points.
Tram Track can be built along roads and in urban areas, but not on areas occupied by other buildings. Tracks can only be built on slopes in the direction of the slope & not over rough terrain, water and obstructions. New Track built may use existing track in its path.
To build Track: click on tool to select Track (changes cursor to track); then click on game-view for start-point of Track (shows a bulldozer in game-view and displays map co-ordinates on right of bottom-bar under game-view); & finally click on game-view for end-point for Track.
{Tips: Different types of tracks may connect (however not when built by some other players). Use bridges & tunnels to connect tracks across rough terrain or to avoid obstructions. Use Destroy/Remove to remove individual pieces of Track & some obstructions. Use [Ctrl] at same time for extra functions. Undo [z] does not refund constructions costs.}

Electrify Track: tools electrify Track, bridges or tunnels between two points in game-view, for use by electric vehicles.
To electrify Track: click on tool or press [e] (changes cursor to electric-track-icon) to select, then click on Track in game-view for start-point of electrification (places a electric-track-icon in game-view), & finally click on a second point on Track, to electrify portion of Track up to start-point.
{Tips: Use Destroy/Remove to change back to non-electric Tracks.}

Remove Tracks: tool removes Track & electric Track, when no vehicles are present, between two points in game-view (station-platforms, road-stops, signals, tunnels & bridges in path are removed too). Use of tool incurs a construction cost.
To remove Track: click on tool (changes cursor to a red-cross); then click on track that is to be deleted (selects deletion-point shown by a red cross in game-view); & finally click at a second-point on connected Track, to remove portion up to first deletion-point.
{Tips: Operate as another player to remove their Tracks.}

Rail Signals: tools build signals for rail vehicles on a Track in game-view. Signals direct & regulate flow of vehicles on tracks & bridges, junctions & Stops (where vehicles pick-up and drop-off goods and passengers).
Two-way & one-way versions of signals can be built. To build a two-way signal on track: click on tool to select signal (changes cursor to signals); then click on track. To build a one-way signal: click again at same point, with signals-cursor, to cycle through one-way signals, back to a two-way signal.
IMPORTANT: Take care not to place one-way signals that prevent vehicles reaching their destination, by default vehicles drive on the right (can be changed in simuconf.tab).
- Signals: vehicles proceed only if Track ahead up to next signal or destination in Schedule (a Stop or waypoint) is not occupied by another vehicle. In one-way mode vehicles pass in one direction only.
- RailClose: vehicles do not proceed beyond signal (available in one-way mode only).
- PreSignals: vehicles proceed if area of Track ahead (either between three consecutive signals or to next destination in Schedule) is not occupied by another vehicle. In one-way mode they let vehicles pass in one direction only.
- ChooseSignals: direct vehicles to an empty station-platform, at a multi-platform Stop: a vehicle passing this signal may use any empty platform at its next destination, and not just the one assigned in its schedule. If no empty platform or clear route to next destination is found, then vehicles wait at signal.
{Tips: Remove signals with Destroy/Remove. Hold down [Ctrl] to place signals on bridges over lower Tracks.}

Tram Depot: tool builds a depot for purchasing & managing trams.
Depots have a maintenance cost & are built on the end of track in game-view.
To build a tram depot: click on tool (changes cursor to a depot), then click on end of Track.
{Tips: Depots only show electric vehicles if they are on electric Track. Remove depots with Destroy/Remove.}

Rail-stops: tools build station-platforms, used by rail vehicles to pick-up and drop-off goods, passengers & mail.
A station-platform when not built adjacent to an existing Stop will create a new Stop.
Rail-stops have a maintenance cost & are built on Track (but not at bends and junctions in Track).
Rail-stops have a catchment area for goods, passengers & mail. Different station-platforms may have different capacities for passengers and mail. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the station-platform allows a Stop to handle.
To build a a station-platform: click on tool to select (changes cursor to a platform), then click on Track.
{Tips: Remove Rail-stops with Destroy/Remove. Extend station-platforms & build multi-platform Stops (by building more platform sections on adjacent Track) to accommodate longer and more vehicles, increase capacity & catchment area. Press [v] to show/hide catchment area for goods & passengers in game-view. Hold down [Ctrl] to build on bridges above lower Tracks.}

Car Parking: (available only in pak 128) tools construct extensions for Stops which increase capacity & catchment area for goods & passengers, and maintenance cost.
To build an extension: click on tool to select extension (changes cursor to extension), then click required position on a road, beside an existing Stop in game-view. The new extension is now considered to be part of the Stop.
{Tips: Remove extensions with the Destroy/Remove.}

?Road-stops: tools build places for trams and road vehicles to pick-up and drop-off goods, mail, and passengers.
A Road-stop when not built adjacent to an existing Stop will create a new Stop. Road-stops are built onroad& have a maintenance cost and a catchment area for goods, passengers & mail. In the corner of some tool-options an icon (used in Station List & Stop Information) shows which items the Road-stop allows a Stop to handle. Different Road-stops may have different capacities for goods, passengers & mail.
To build a Road-stop: click on tool to select (changes cursor to roadstop), then click required position on a road in game-view.
{Tips: Remove Road-stops with the Destroy/Remove. Hold down [Ctrl] to build on bridges above lower roads.}

simutrans-124.3/simutrans/text/en/underground.txt000066400000000000000000000037001474050137200222630ustar00rootroot00000000000000Building Underground

Building Underground

There are two possible underground views in Simutrans, and both can be accessed from Display Settings window or using key shortcuts.

Underground view: By pressing the [U] key, all underground levels are revealed at once and all objects that are above ground are hidden. The surface grid is displayed by default, but it is quite difficult to place objects at desired location using this grid pattern, and therefore next map view is recommended for underground construction.

Sliced map view: With [Ctrl+U] you can choose to display a single elevation level of what is underground in Simutrans. This view hides all objects that are over the selected layer, either underground or on surface. The current view level can be adjusted from Display Settings window, or using some keys which are pakset specific. A grid pattern of the active layer is shown. Since the mouse pointer can only be moved within the current level, construction work is easier.

In general, underground routes are built using tunnel building tools. In order to build underground, a tunnel or a tunnel entrance (Ctrl + click with tunnel tool on a slope) must be built first.

To build on another layer underground, use Build artificial slopes tools from the Landscaping Tools menu. Simply click on the end of the road/track with the desired tool.

Tram tracks can be laid underground with the normal Tram/light rail tools on existing roads.

Only own stop/station can be built on top of each other. Station extensions cannot be built underground.

NOTE: If cannot build further underground, check on surface for obstacles.

simutrans-124.3/simutrans/text/en/vehiclelist.txt000066400000000000000000000012111474050137200222350ustar00rootroot00000000000000List of all vehicle

List of all in the game Vehicle types

By default, all vehicles currently coming current and future will be shown. Show the future is also the real sense of this list. In the depots, the upcoming vehicles are not visible. The player can better plan for the future.

Show future by deselection, the list can be limited to the currently purchasable vehicles.
Show obsolete expands the list with the already outdated vehicles. This feature is the same in the depots.
Behind it at All can be restricted to the type of goods as well as passengers or post.

simutrans-124.3/simutrans/text/en/window.txt000066400000000000000000000217541474050137200212470ustar00rootroot00000000000000Game Interface Usage

Game Interface

Simutrans is played through the Game Interface, which provides information about the current game, access to toolbars & game-controls and a view of the current game-world. Simutrans can be controlled via mouse and via keyboard. The keyboard layout is available in the help menu at Keyboard Binding section, or pressing [F1] key, and also appears every time a key without function is pressed.
IMPORTANT: Keys are case-sensitive.

Game Window

Shows a portion of the current game-world. You can zoom-in and zoom-out using the mouse wheel, or [PgUp]/[PgDown] keys, or two dedicated icons found on the main toolbar. Scroll the map in several ways:
· Hold down the right mouse button and scroll the map in any direction towards your desired position. In the default setting, the map scrolls against the movement of the mouse. You can change this behaviour in Display Settings window.
· Use the numeric keypad.
· Jump directly to a desired map section by selecting the appropriate point on the Map Window.
· Jump to specific coordinates using Jump to dialog (press [J] key).

The names of several objects are editable, such as towns, factories, stations, vehicles and transport lines. To edit, click with the mouse in the name field of the dialog opened by the Inspection Tool (see below). Edits become effective immediately. Press [Return] to exit the field.

Title Bar

The left part of the titlebar shows the version and release date of Simutrans that is currently running. The right hand side of the titlebar contains controls to minimize, maximize the Game Interface and also to exit Simutrans.

At the top of the game window is a row of icons (main toolbar) used to access game-toolbars and game-controls when playing Simutrans. Icons (click to use) are grouped in several menus:

Main Menu

Options: The floppy-disk-icon opens a dialogue from where you can load, save or start a new game.

Map: The overview map of the world with its objects shows the movements of the player vehicles and allows seeing some statistical views. If you select a point on this map, the game window jumps to the corresponding image section.

Inspection Tool: The magnifying-glass-icon symbolizes the query tool. If it is active, the cursor also becomes a magnifying glass. If you select an object with it (building, vehicle, etc.), an information window will be displayed above it. It is advisable to always return to magnifying glass, especially if you have just worked with the Removal Tool. So you avoid destroying an object accidentally, instead of calling up the object information.

Landscaping Tools: The sloping-land-icon opens a toolbar from where you can alter the map by changing the slope of each tile.

Building Toolbars: Opens a set of building toolbars for each type of transportation.
· Railroad Tools
· Monorail/Maglev Tools
· Tram/light rail Tools
· Road Tools
· Shipping Tools
· Airport Tools

NOTE: Some paksets may contain additional building toolbars, e.g. Narrow Gauge Railroad Tools.
Each toolbar has a depot icon. Once a depot is built, you can enter the depot window to access vehicles.

Special Construction Tools: The toolbar that opens by clicking red-drop-in-yellow-circle-icon (crane-icon in pak128) contains a variety of construction tools that complement the construction of transportation networks.

Destroy/Removal Tool: The red-cross-icon (bulldozer-icon in pak128) is used to remove various objects from the map.

Management Menu

Line Management: Transport lines can be set up here (network-icon), changed or deleted, as well as information about them can be viewed.

Lists: The symbol of the list sheet leads to a submenu with seven lists:
· Station List
· Vehicle List
· City List
· Goods List
· Factory List
· List of Tourist Destinations
· List of Markers

Message Centre: All messages that have been generated since the start of the game or since the last time a game was loaded will be listed when clicking this mailbox-icon.

Finances: This money-icon opens a window that shows everything worth knowing about your current financial situation.

Other Menus

Screenshot: When using the camera-icon button, a snapshot of the current game window (including toolbars, but without titlebar) is saved as a .png image in folder simutrans/screenshot/. An image can also be captured with [c] key.

Pause: If you want to take a break from the hustle and bustle of the transport company, order a hot cup of tea or coffee over this coffee-mug-icon. The service is of course free in Simutrans!
The key [p] can also be used to pause/unpause game.

Fast Forward: If time in Simutrans passes too slow for you, you can accelerate it, by pressing this >> icon. Fast forward can also be selected/deselected with key [W].
WARNING: In fast forward mode, game may not run smoothly. Display performance information section at the bottom of Display Settings window indicates if the computer can cope with the change.

Help: The ?-icon opens the help index, also with [F1] key.

NOTE: Depending on pakset you play, there might be more icons on the main toolbar: Zoom in/Zoom out, Show grid, Rotate map, etc.

Status Bar

The status bar at the bottom of game-world window contains some information that is constantly updating as the game progresses. Information provided, from left to right on the status bar includes:
· Date and Time: In Simutrans, one year is divided into months, days and hours. The date controls the availability of vehicles and buildings when the 'timeline' is activated (see below). In front of date an icon with meteorological season is displayed. For some climate settings, the ground may change with the seasons.
· Player: The name of the current player is displayed in its player color.
· Account balance: The cash of current player is displayed and permanently updated. It takes into account construction and other costs (purchasing vehicles, maintaining transport infrastructure and operation costs of running vehicles).
· Position coordinates: Inside brackets is displayed the x and y coordinates and the height of the tile over which the cursor is currently located. The coordinates (0,0) are located in the top-left corner of the map and the height zero is at water level or above it (depends on water level settings at the creation of the map)
· Game speed: The value (T=1.00) indicates the current game speed. You can accelerate/decelerate time in small increments using [,]/[.] keys. Display performance information section at the bottom of Display Settings window indicates if the computer can cope with the change. In fast forward mode, an additional icon >> is displayed.
· Obey era: Indicates by a calendar-icon whether a timeline has been selected in the current game.

Scroll Bar

Occasionally, messages are displayed above the status bar at the bottom of the game-world window. The messages to be displayed can be defined in the Message Centre Options.
TIP: Click on a message to center game-view to a related position.

simutrans-124.3/simutrans/text/eo.tab000066400000000000000000001323131474050137200176620ustar00rootroot00000000000000§Esperanto PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: eo Esperanto # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Nevalidigita cl_btn_filter_enable Validigita cl_btn_filter_settings Agordoj cl_btn_sort_asc Kreske cl_btn_sort_desc Malkreske cl_btn_sort_id ID nombro cl_btn_sort_income Enspezo cl_btn_sort_name Nomo cl_btn_sort_type Tipo clf_btn_alle Ĉiuj clf_btn_invers Inverse clf_btn_keine Nenio gl_btn_sort_bonus Kromenspezo gl_btn_sort_name Nomo gl_btn_sort_revenue Enspezo gl_btn_unsort Neordigite hl_btn_filter_disable Neebligite hl_btn_filter_enable Ebligite hl_btn_filter_settings Agordoj hl_btn_sort_asc Kreske hl_btn_sort_desc Malkreske hl_btn_sort_name Nomo hl_btn_sort_type Tipo hl_btn_sort_waiting Atendantoj hlf_btn_alle Ĉio hlf_btn_invers Inverse hlf_btn_keine Neniu Maximize height levels Maksimumigi altecon Networks Transportretoj Queueing Atendantoj Road toll Vojimposmo Scenario Scenaro Start this as a server Komenci servilon per ĉi tiu ludo. Transfers TransvagoniÄantoj #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Polusa klimato desert Dezerta klimato mediterran Mediteranea klimeto rocky Altmonta klimato temperate Mezvarma klimato tropic Tropika klimato tundra Tundra klimato #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Malsukcesis legi scenaron Bridge blocked by way below or above. Ponto estas malhelpata de vojo supre aÅ­ sube.\n Can't buy obsolete vehicles! Ne povas aĉeti elservigitajn veturilojn. Cannot alter water Ĉi tiu terkavo ne povas esti plenigita nek malplenigita. Cannot build on a double slope! Povas konstrui nur sur unuobla deklivo aÅ­ ebenejo. Cannot built depot here! Ne povas konstrui veturilejo ĉi tie. Cannot built this station/building\nin underground mode here. Ne povas konstrui ĉi tiun stacidomon en subtero.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Ne povas krei universalan linion. Elektu linian tipon uzante tabon. Cannot create socket Ne povas krei ingon. Cannot rotate this building! Ne povas turni ĉi tiun konstruaĵon. Client closed connection during transfer Kliento ĵus malkonektis dum transdoni. Convoi handles exhausted! Atingis maksimumajn nombrojn de veturilo. Convoy already deleted! Veturilo jam estas eliminita! Could not open file Ne povas malfermi la dosieron Das Feld gehoert\neinem anderen Spieler\n Ĉi tiu loko estas okupita\nde alia ludanto!\n Der Besitzer erlaubt das Entfernen nicht La proprulo malpermesas malkonstrui ĉi tion!\n Diese Zusammenstellung kann nicht fahren!\n Ĉi tiu kombinado ne povas ekveturi!\n Flugzeughalt muss auf\nRunway liegen!\n Aviadila haltejo devas esti sur kurejo.\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Vi ne povas konstrui hangaron ĉi tie.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Ne povas meti signalilon ĉi tie.\n In order to lock the game, you have to protect the public player by password! Por Ålosi la ludon, vi devas protekti la publikan ludanton de pasvorto! Loading a new game will end the current server session! Malfermi novan ludon finigos la nunan servilan ludon! Lost connection\nto server! Perdis konektadon al servilo. Lost synchronisation\nwith server. Perdis sinkronigon kun servilo. Maglevhalt muss auf\nMaglevschiene liegen!\n Magnetvoja stacio devas esti sur magnetvojo! Monorailhalt muss auf\nMonorail liegen!\n Unurela stacio devas esti sur unurelo! Monorails are not available yet! Unurela ankoraÅ­ ne estas uzebla! More than one possibility to build this dock found. Trovis pli ol unu eblecon por konstrui la dokon. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n EtÅpura fervoja stacio devas esti sur etÅpura fervojo! No bridges over runways! Ne povas konstrui ponton super kurejo! No suitable way on the ground! Oni ne povas konstrui ion ĉi tie. No through station here! Oni ne povas konstrui haltejon ĉi tie! Not enough bytes transferred Malsukcesis sendi datumon. Not enough clearance. Minimuma alteca diferenco necesas inter du vojoj. Not enough money! Mankas mono al vi. On narrowgauge track only!\n Nur sur EtÅpura vojo! Only public player can lock games! Nur publika ludanto rajtas Ålosi ludon. Out of funds Mankas mono al vi! Post muss neben\nHaltestelle\nliegen!\n Oni devas konstrui stacidomon kaj poÅtejon apud haltejo. Protocoll error (expecting game) Protokola eraro Schiffhalt muss im\nWasser liegen!\n Åœipa povas halti sur nur akvo ĉirkaÅ­ doko aÅ­ haveno! Server busy Servilo okupita Server version too new La servilo uzas pli novan version. Show all revenue messages Montri enspezoj de ĉiuj ludantoj Show no revenue messages Malmontri enspezoj de ĉiuj ludantoj Show only player's revenue Montri nur enspezo de tiu ĉi ludanto Terraforming not possible\nhere in underground view Oni ne povas terformi subteron. This tunnel branches. You can try Control+Click to remove. Ĉi tiu tunelo havas pli ol du enirejon. Vi povas forigi ĉi tiu tunelon per Ctrl+alklaki. Upgrade must have\na higher level Promocio devas havi pli altan nivelon. Vehicle %s cannot choose because stop too short! Veturilo %s ne povas trovi por halti pro tro mallongeca haltejo. Zughalt muss auf\nSchiene liegen!\n Fervoja stacio devas esti sur fervojo. #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s

Enhavo

*: nur la angla

Äœeneralo

%s

Uzado

%s

Iloj

%s

Komenci

%s

Kiel ludi

%s

aliaj:

%s Keyboard Help\n

Keyboard Help

\n Klavara helpo\n

Klavara helpo

\n Color according to transport capacity left Koloro laÅ­ resto de transporta enhaveco Decrease water height Malaltigi akvan nivelon Highlight railroad tracks Emfazi fervojojn Highlite depots Emfazi veturilejojn Highlite electrical transmission lines Emfazi elektroretojn Highlite factories Emfazi fabrikojn Highlite forests Emfazi arbarojn Highlite tourist attraction Emfazi altiraĵojn Increase water height Altigi akvan nivelon Open station/stop details Malfermi haltejan detelon Overlay city limits Montri urblimojn Overlay passenger destinations when a town window is open Montri pasaÄeraj celejoj kiam urba fenestro malfermiÄas Overlay schedules/network Montri transportreton Overlay town names Montri urbnamojn Please click on the map to add\nwaypoints or stops to this\nschedule. Bonvolu klaki sur la mapo por aldoni vojpunktojn aÅ­ haltejojn al la liniplano. Set tile climate %s ÅœanÄi ĉi tiean klimaton je %s Show capacity and if halt is overcrowded Montri enhavecon kaj ĉu haltejo estas superenhaveca. Show how many convoi reach a station Montri kiom da veturiloj atingis stacion Show how many people/much is waiting at halts Montri kiom atendas Show initial passenger departure Montri pasaÄeran kaj poÅtaĵan elirpunkton Show level of city buildings Montri nivelon de domoj Show mail service coverage/mail network Montri poÅtan kovrareon Show passenger coverage/passenger network Montri pasaÄerservan kovrareon Show speedlimit of ways Montri rapidecan limon Show the change of waiting at halts Montri kiom da atindantoj kreskis/malkreskis ekde lasta monato Show the owenership of infrastructure Montri proprulon de substrukturo Show transported freight/freight network Montri transportitajn frajtojn Show usage of network Montri trafikon pokahele kaj pomonate Shows a listing with all industries on the map. Montri liston de ĉiuj fabrikoj ekzistantaj sur la mapo Sum of departure/arrivals at halts Montri kiom da veturiloj alvenitaj kaj eliritaj #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s nun\nofertas busan servon\ninter %s\nkaj altiraĵo\n%s\nĉe (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s nun\nofertas busan servon\ninter %s\nkaj fabriko\n%s\nĉe (%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nmalfermis novan fervojon\ninter %s\nĉe (%i,%i) kaj\n%s\nĉe (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Aerlinia servo de\n%s\nnun estas ofertata inter\n%s \nkaj %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n PramÅipa servo de\n%s\nnun estas ofertata inter\n%s \nkaj %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n VojaÄantoj nun\nuzas busoj de\n%s inter\n%s \nkaj %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Mapaj ÅanÄiloj LISTTOOLS Listoj MAGLEVTOOLS Magnetvojaj iloj MONORAILTOOLS Unurelaj uloj NARROWGAUGETOOLS EtÅpuraj fervojaj iloj RAILTOOLS Fervojaj iloj ROADTOOLS Vojaj iloj SHIPTOOLS Åœipaj iloj SLOPETOOLS Terformiloj SPECIALTOOLS Specialaj iloj TRAMTOOLS Tramaj iloj #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s ĵus konstruis novan ĉefsidejon. Factory chain extended\nfor %s near\n%s built with\n%i factories. "%s" grandigis sian aferon apud %s, kaj konstruis novajn %i fabrikojn. Net wealth less than 10%% of starting capital! Via riĉeco estas nun malpli ol 10%% de komenco! New %s now available:\n%s\n Nova %s estas nun uzebla:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Nova fabriko %s ĉirkaÅ­ %s konstruis kun %i fabrikoj. New vehicle now available:\n%s\n Nova veturilo estas nun uzebla:\n%s\n Now %u clients connected. Nun %u ludantoj estas en ĉi tiu servilo. overtaking Preterpasi Remove vehicle from map. Use with care! Atentu! Forigos veturilon el mapo! Screenshot\ngespeichert.\n Ekranfotis. Sends the convoi to the last depot it departed from! Sendas la veturilon al la plej proksima veturilejo. Server preparing game ... Servilo preparas ludon ... With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Kun granda festo, %s konstruis novan monumenton, kaj %i loÄantoj Äojis. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Linia filtrilo #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (En veturilejo) \nBauzeit bis Äis \nBauzeit von \nAperas de \nCan't open heightfield file.\n \nNe povas malfermi altecan mapon.\n \ndirection: \ndirekto: \nelektrified \nelektrizita\n \nHeightfield has wrong image type.\n \nLa alteca mapo havas malÄustan tipon.\n \nis reserved by: \nrezervita de \nminimum speed: \nminimuma rapideco: \nnot elektrified \nneelektrizita\n \nRibi (masked) \nDirekto\m (maskita): \nRibi (unmasked) \Direkto\m (nemaskita): \nSet phases: \nAgordi faza tempo\nSurd-nordo Orient-Okcidento: \nsingle way \nUnudirekto \nway1 reserved by \nUnua vojo estas rezervita de \nway2 reserved by \nDua vojo estas rezervita de \nwith sign/signal\n \nkun trafiksigno/signalilo\n %d buildings\n %d domoj\n %d convois %d vagonaroj %d Einzelfahrzeuge im Depot %d veturiloj enmetiÄas ĉi tie. %i car(s), %i aÅ­toj, %i km/h (max. %ikm/h) %i km/h (maks. %i km/h) %i years %i months old. AÄo: %i jaroj kaj %i monatoj %s at (%i,%i) now public stop. %s ĵus fariÄis publika haltejo. %s building %s %s %s %s %s %s city %d %s %s %d-a %s %s factory %s %s %s %s %s %s has entered a depot. %s ĵus revenis veturilejen.\n %s land %d %s %s %d-a ekstera %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \nkonstruis \nnovan urbdomon\nkiam Äi atingis \n%i loÄantojn. %s\nis crowded. %s amasas. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nmaksimuma rapideco %3$i km/h\n\nnuna rapideco %2$i km/h.\n\n %s\nwas liquidated. %s bankrotis kaj estis likvidita .Tiu operacio estis haltita, kaj ĉiuj aktivaĵoj estis venditaj. %u Client(s)\n %u Kliento(j)\n %u Player (%u locked)\n %u Ludanto (%u Ålosita)\n

Error

Averton: Duoblaj objektoj en ĉefa paka dosierujo

En

Warning

addons for

Averton: Duoblaj objektoj en ĉefa paka dosierujo

Aldonoj por 1 convoi 1 veturilo 1 Einzelfahrzeug im Depot 1 veturilo enmetiÄas ĉi tie. 100 km/h = %i tiles/month 100 km/h = %i ĉeloj/monato 1LIGHT_CHOOSE Heleco: 1WORLD_CHOOSE Agordoj por nova mapo: 2LIGHT_CHOOSE Koloroj: 2WORLD_CHOOSE Mapa nombro: 3LIGHT_CHOOSE Ruluma rapideco: 4LIGHT_CHOOSE Inversigi rulumi 5LIGHT_CHOOSE Montri piedirantojn 5WORLD_CHOOSE Nombro de urboj: 6LIGHT_CHOOSE Montri piedirantojn 6WORLD_CHOOSE Trafika denseco: 8WORLD_CHOOSE Mallumigi dum nokto A bridge must end on a way! Ponto devas fini sur vojo! A bridge must start on a way! Bonvolu konstrui ponton sur senkurba vojo. Abfrage Inspektilo Abnehmer Konsumanto: About Klarigo About scenario Pri scenaro Abriss Malkonstrui Absenken Malaltigi teron Abspanntransformator Transformilejo Accelerate time Rapidigi tempon Act. load: %u MW\n Sendkvanto: %u MW\n Active player only Montri nur aktivan ludanton Add forest Fari arbaron Add random citycar Meti aÅ­ton sur vojo add server Aldoni servilon Add Stop Aldoni Add stops for backward travel Aldoni reveturajn haltejojn air Aviadilo aircraft_tab Aviadilo airplane Aviadilo Airport Flughaveno AIRTOOLS aviadilaj iloj All Montri ĉion all convoi tooltips Montri veturilajn statojn ĉiam Allow city growth Permesi al urbo kreski Allow player change Permesi al ludanto ÅanÄi allowed climates:\n Permesitaj klimatoj:\n Alters a schedule. Administri liniplanon Angenommene Waren Fabrikaĵoj bezonataj de apudaj fabrikoj anhaengen Aldoni Anhaenger_tab Postveturiloj Anheben Altigi teron Appends stops at the end of the schedule Aldoni haltejon fine de liniplano Apply Line Asigni linion April Aprilo Arbeiter aus: Laboristoj loÄas en: Arrivals from\n Alvenoj de\n Arrived Alvenintoj Assets Aktivo Aufloesen Malkunigi Aufspanntransformator Transforma stacio Aug. AÅ­g. August AÅ­gusto Autohalt muss auf\nStrasse liegen!\n Busoj kaj veturiloj devas esti konstruitaj sur la strato\n Available Uzebleco Bahndepot Trajna veturilejo Bankrott:\n\nDu bist bankrott.\n Bankroto:\n\nVi Bankrotis!\n battery Baterio Baum Arbo baum builder Plantilo Baustelle Konstruejo Bauzeit Konstrutempo Beenden Fini ludon Beginner mode Mi estas komencanto! Besonderes Gebaeude Altiraĵo BF Stacio bio Vivaĵo Blockstrecke ist\nbelegt\n \nBloksekcio estas uzata de alia veturilo!\n Boden Tero Bonusspeed: %i km/h Maks. ebla rapideco: %i km/h Boost (%%) Pliigite (%%) bridge is too high for its type! Ne povas konstrui tian ponton je tiel alta nivelo. Bridge is too long for this type!\n La distanco estas tro longa por konstrui tian ponton.\n Bruecke Ponto Bruecke muss an\neinfachem\nHang beginnen!\n Ponto devas ekkonstrui sur rekta vojo.\n Brueckenboden Ponto Build air depot Konstrui hangaron build choosesignals Konstrui elektsignalilon Build city market Fari novan bazaron en la plej proksima urbo. Build drain Konstrui ĉefsidejon build HQ Konstrui ĉefsidejon Build land consumer Konstrui novan centralon Build maglev depot Konstrui magnetvojan veturilejon Build monorail depot Konstrui unurelan veturilejon Build narrowgauge depot Konstrui etÅpuran veturilejon Build powerline Konstrui elektran draton Build presignals Konstrui ekssignalilon Build road depot Konstrui aÅ­tan veturilejon Build ship depot Konstrui Åipfarejon Build signals Konstrui signalilon Build train depot Konstrui fervojan veturilejon Build tram depot Konstrui traman veturilejon Build truck depot Konstrui aÅ­tan veturilejon Building costs estimates Kosto Buildings Urba konstruaĵo Built artifical slopes Konstrui deklivojn Built random attraction Konstrui hazardan altiraĵon Bus_tab Buso Can only move from halt to halt or waypoint to waypoint. Oni povas nur movgi linplanon \nde haltejo al haltejo aÅ­ \nde vojpunkto al vojpunkto. Cancel Nuligi Cannot connect to offline server! Oni ne povas aliri al nekonektita servilo! Capacity Enhaveco Capacity: Enhaveco: Capacity: %.0f MW Enhaveco: %.0f MW\n Capacity: %d%s %s\n Enhaveco: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Enhaveco: %s\nEnhavo: %d (%d%%) Cars are not available yet! AÅ­to ... eĉ ĉevalo ankoraÅ­ ne ekzistas... cars.\nstate aÅ­toj\n Cash Kotantaĵo Change player ÅœanÄi ludanton Chart Grafikaĵo Chat_msg Retbabilado Choose direction Elektu direkton Choose operation executed on clicking stored/new vehicles Elekti agon farotan al alklakita veturilo chooses a random map Elekti hazardan mapon citicens LoÄantoj City attraction Urba altiraĵo City industries Bazaroj en urboj City list Urbolisto City size Urba grandeco city_road Urba vojo citybuilding builder Konstrui urbajn domojn CityLimit Urblimo cl_title Veturilolisto cl_txt_sort Klasi de: Clear block reservation Refari rezervitajn vojojn clf_chk_aircrafts Aviadiloj clf_chk_cars AÅ­toj clf_chk_indepot En veturilejo clf_chk_maglev Magnetvojaj vagonaroj clf_chk_monorail Unurelaj vagonaroj clf_chk_name_filter Filtro de namo: clf_chk_narrowgauge EtÅpuraj fervojaj vagonaroj clf_chk_noincome Malenspezo clf_chk_noline Senlino clf_chk_noroute Senvojo clf_chk_noschedule Senliniplano clf_chk_obsolete Malnovaĵoj clf_chk_ships Åœipoj clf_chk_spezial_filter Speciala filtro: clf_chk_stucked Haltado clf_chk_trains Trajnoj clf_chk_trams Tramoj clf_chk_type_filter Tipa filtrilo: clf_chk_waren ÅœarÄaĵa Filtrilo: clf_title Veturilolista Filtrilo Climate Control Klimetaj agordoj closed fermita COLOR_CHOOSE\n Elektu du kolorojn./n Company bankrupt Kompanio bankrotis Company_msg Konkuruloj Comparing pak files ... Komparas pakseton ... Configure AI Agordi AI Configure AI setttings Agordi AI Congratulation\nScenario was complete in\n%i months %i years. Graturon!\nScenaro finiÄis komplete dum %i monatoj kaj %i jaroj. Connected stops Korespondaj haltejoj: Connected with server Eniris al selvilo. Constructed by Kreita de Constructed by %s Kreita de %s construction speed Rapideco de konstruo Construction_Btn Konstruaj kostoj Consumed Konsumaĵo contains the following doubled objects:

enhavas sekvantajn objectojn pli ol unu:

convoi %d of %d Veturilo %d de %d convoi error tooltips Montri nur veturilo kun problemo Convoi has been sent\nto the nearest depot\nof appropriate type.\n Tiu ĉi Veturilo estas sendita al la plej proksima veturilejo.\n Convoi is sold when all wagons are empty. Vendi la veturilon post kiam Äi malpleniÄos. convoi mouseover tooltips Montri veturilan staton surmontrile convoi passed last\nmonth %i\n \ntrafiko de lasta monato: %i\n Convois Vagonaroj Convois: %d\nProfit: %s Veturiloj: %d\nEnspezo: %s Convoys Vagonaroj Copy Convoi Kopii vagonaron Copy the selected convoi and its schedule or line Kopii elektitan veturilon kaj liniplanon Cost Kosto cost for removal Kosto por malkonstrui Cost per unit Unuopa kosto Cost: %8s (%.2f$/km %.2f$/m)\n Kosto: %s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Kosto: %8s (%.2f$/km)\n Costs Kostoj Create a new line based on this schedule Krej novan linon surbaze de tiu ĉi liniplano curiosity builder Altiraĵa konstruilo curlist_title Altiraĵolisto Currently playing: Nuna muziko: Customers live in: Klientoj loÄas en: deactivated in online mode Oni ne rajtas uzi en interreta ludo Deccelerate time Malrapidigi tempon December Decembro decrease underground view level Malaltigi subteran nivelon Del Stop Forigi Delete Line Foriri linion Delete the current stop Forigi la elektotan haltejon Delete the selected line (if without associated convois). Forigi elektotan linion (se neniu veturiloj havas) Delete this file. Forigi tiun ĉi dosieron Delivered Liveraĵoj Demand Mendaĵoj Demand: %.0f MW Bezono: %.0f MW\n Denkmal Monumento Departed Elirintoj Departure board Horaro Departures to\n Eliroj al\n Depots Veturilejoj Der Tunnel ist nicht frei!\n Tunelo ne estas malplena.\n Destination Celoj Destroying map ... Finas malnovan mapon ... Details Detaloj Die Bruecke ist nicht frei!\n La ponto estas ne libera!\n diesel Dizelo directmail Rektaj poÅtaĵoj Direkt erreichbare Haltestellen Haltejoj ireblaj de tie ĉi disable midi Malsoni MIDI-muzikon Display settings Vidigaĵaj agordoj Distance Distanco distributing cities Dismetas urbojn distributing factories Dismetas fabrikojn Dock doko Dock must be built on single slope! Oni devas fari dokojn sur unuobla deklivo. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Vi devas repagi vian Åuldon %d monatojn. Durchsatz Maks. Economy Ekonomio Eigenbesitz\n Publikaĵo\n Ein %s\npasst hier nicht.\n '%s' \nne adaptiÄas ĉi tie!\n Einstellungen Agordoj Einstellungen aendern Opcioj electric Elektro Electricity Elektra povumo Electricity producer\n\n Elektrika fonto\n\n Electrics_tab Elektra motorvagono Electrify track Elektrizi fervojon enlarge map Grandigi mapon enter a value between %i and %i %i Äis %i Enter address Enigi adreson Enter Password ÅœanÄi nomon de ludanto kaj pasvorton Error Eraro Erzeuge neue Karte.\n Bonvolu atendi Äis novan mapon kreis.\n\n Eble bezonas kelkajn minutojn por vastaj mapoj.\n Es wird bereits\nein Fahrplan\neingegeben\n Linplano nun estas planata. \nFinu Äin unue antaÅ­ re-linplani.\n Fabrikanschluss Konektitaj fabrikoj Fabrikname Fabriknomo Factories Fabrikoj factory details Fabrikaj ĉenoj factorybuilder Konstruilo de fabriko Fahrplan Linplano Fahrtziel Venonta haltejo: Fahrzeuge koennen so nicht entfernt werden Oni ne povas forigi veturilojn tiel!\n Fahrzeuge: Veturiloj: Farbe Ludantkoloro Fast forward Rapidigi tempon February Februaro Ferry_tab Pramo Fertig Foriri Filename dosiernomo: Files from: Dosiernomo: Filter: Filtrilo: Finances of %s Financoj de %s Finanzen Financoj find mismatch Kompari vian pakseton fl_title Fabrikolisto Flug_tab Aviadilo follow me Sekvi Follow the convoi on the map. Sekvi la veturilon sur la mapo. font size Grando de tiparo Forest Arbaro Found new city Fondi novan urbon Fracht Frajtaĵo Frame time: Frama tempo: Free Capacity Libera enhaveco freeplay mode Liberludo Friction: faktoro: fuel_cell Hidrogeno Full load Minimuma ÅarÄo: Fundament Tero Fussgaenger Piedirantoj Game info Ludinformo GAME PAUSED PaÅ­zas Game_msg Äœeneralo Gear: Poveca proporcio: Gebaeude Konstruaĵo General Generalo Generated Faritaj Generation: %.0f MW Farkvanto: %.0f MW\n Gewicht Pezeco Gewinn Enspezo: Give the selected vehicle(s) an individual schedule Agordi apartan liniplanon al la elektita(j) veturilo(j) gl_btn_sort_catg Kategorio gl_title Fabrikaĵolisto go home Irigi al veturilejo Goods Fabrikaĵo Goods AI Frajta AI Goods list Fabrikaĵolisto Gross Profit Malneta profito Groundobj Terobjekto Grow city Kreski urbon Growth Kreskado H haltejo Hangar Hangaro Happy Feliĉuloj Haus kaufen Aĉeti domon Helligk. Vidigaĵo Help Helpo Help text not found AnkoraÅ­ ne estas helpteksto. hide all building Malaperigi ĉiujn domojn hide city building Malaperigi urbajn domojn hide objects under cursor Malaperigi objektojn sub montrilo hide station names Malaperigi stacidomajn nomojn hide transparent Diafanigi anstataÅ­ malgrandigi hide trees Malaperigi arbojn Hier warten/lagern: Atendanta fabrikaĵoj kaj pasaÄeroj: Higher transport fees, crossconnect all factories Plimultigi enspezojn, kaj nevalidigi ĵus-en-tempo. Highlite schedule Montri liniplanajn haltejojn hl_title Haltejolisto hl_txt_filter Filtrilo: hl_txt_sort Ordigitaj de: hlf_chk_airport Flughavenoj hlf_chk_anleger Doko hlf_chk_bahnhof Fervoja stacio hlf_chk_bushalt Busa haltejo hlf_chk_frachthof ÅœarÄejo hlf_chk_keine_verb Neniu korespondado hlf_chk_maglevstop Magnetvoja stacio hlf_chk_monorailstop Unurela stacio hlf_chk_name_filter Noma filtrilo: hlf_chk_narrowgaugestop EtÅpura fervoja stacio hlf_chk_overflow Saturita hlf_chk_spezial_filter Speciala filtrilo: hlf_chk_tramstop Trama haltejo hlf_chk_type_filter Tipa filtrilo: hlf_chk_waren_abgabe Fabrikaĵo: hlf_chk_waren_annahme Konsumaĵo: hlf_title Filtrilo de stacilisto Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Ne povas trovi veturejon.\nVi devas sendi mane la veturilon tien. Homeless Senhejmuloj hydrogene Hidrogeno Idle: Senfari: ignore climates Ignori klimatojn In the industry legend show only currently existing factories Montri nur fabrikaĵojn, kiuj estas uzata de fabrikoj ekzistaj nuntempe. In Transit Transitantoj Increase Industry density Multigi fabrikojn increase underground view level Altigi subteran nivelon industrial building Fabrikoj Init map ... Preparas mapon ... Input Materialo Ins Stop EnÅovi Insert stop before the current stop EnÅovi haltejon antaÅ­ elektita haltejo Insufficient funds! Mankas mono al vi! Intercity road len: Longeco de interurba vojo: Intro. date Enkonduka dato Intro. date: Enkonduka dato: invalid Nedifinita Invalid coordinate ★MalÄusta alteco★ isometric map Turnita mapo January Januaro join game Partopreni al interreta ludo July Julio Jump to MoviÄi al aldifinita koordinato June Junio Kann Spielstand\nnicht laden.\n Ne povas malfermi la ludon! Kann Spielstand\nnicht speichern.\n Ne povas sekurigi la ludon. Kein Besitzer\n Sen proprulo\n keine Nenio Keine Einzelfahrzeuge im Depot Neniu veturilo enmetiÄas ĉi tie. Keyboard_Help\n Klavara Helpo\n koord Koordinatoj Kreuzung Nivelpasejo labellist_title Markolisto Lade Relief Malfermi altecan mapon Laden Rekomenci ludon Land attraction Altiraĵo Land industries Fabrikaj ĉenoj: LANG_CHOOSE\n Bonvolu elekti vian Åatatan lingvon.\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Lasta monato Last used tools Ilo uzita laste Last Year Lasta jaro: Leaving depot! Eliras el veturilejo! leer malplena Legend Enhavo Leistung Povumo Leistung: %d kW Povumo: %d kW Leitung Povuma linio length: %d Longeco: %d letzen Monat: diesen Monat: Lasta monato: Ĉi-monato: Line Linio Line Management Linia administrado Lineless convoys serving this stop Senliniaj veturiloj servantaj tiun ĉi haltejon Lines serving this stop Linioj servantaj tiun ĉi haltejon List of industries on the map Listo de fabrikoj sur la mapo LKW_tab ÅœarÄaÅ­toj Load game Malfermi mapon load height data from file Uzi mapan dosieron. Load scenario Malfermi scenaron loaded ÅœarÄitaj loaded passenger/freight Ordigi pasaÄeroj/frajtoj de Loading (%i->%i%%)! ÅœarÄas (%i->%i%%) Loading addon paks ... Legas aldonitaj pakoj ... Loading map ... Legas mapon ... Loading paks ... Legas pakojn ... Loading skins ... Legas haÅ­tojn ... Lock game Åœlosi ludanto Lokomotive_tab Lokomotivo m3 m³ Maglev Magnetvojo maglev vehicle Magnetvoja veturilo maglev_track Magnetvojo Maglevdepot Magnetvoja veturilejo Mail Demand %d\n PoÅtaĵa mendado %d\n Mailbox MesaÄoj Mailbox Options MesaÄaj opcioj Maintenance Bontenado make stop public (or join with public stop next) costs %i per tile and level Igi haltejon publika (aÅ­ unuigi al ĉirkaÅ­a publika haltejo) kostos po %i$ por kehalo kaj nivelo Make way or stop public (will join with neighbours), %i times maintainance Unuigi vojon aÅ­ haltejon kiel publika kun ĉirkaÅ­a publika stacio. Äœi kostos %i-oblan konservan elspezon. Manual (Human) Ludanto (homo) Manufactured: Fablikita en: Map roughness Mapa malebeneco: map zoom Zomi March Marto Margin (%%) Profiteco (%%) Marker MEti signon max maks Max Boost (%%) Plifabrikeco (%%) Max income: Maksimuma enspezo: Max. speed Maks. rapideco Max. speed: Maks. rapideco: Maximum 254 stops\nin a schedule!\n Maksimume 254 haltejojn oni povas aldoni!\n maximum length of rivers Maks. longeco de riveroj Maximum tile height difference reached. La maksimuma diferenco de alteco inter du apudaj kehaloj estas 2 gradoj.\n Maxspeed Maksimuma rapideco May Majo Median Citizen per town Mezaj loÄantoj po-urbe: Meldung MesaÄo Menge Kiomo MessageOptionsText \nNovjaro\n\nLudantaj novaĵoj\n\nUrbaj novaĵoj\n\nSenvojo\n\nNovaj celoj\n\nBabilado\n\nNovaj veturiloj\n\nPlenaj haltejoj\n\nProblemoj\n\ntrafikÅtopiÄoj\n\nScenaro min min. minimum length of rivers Min. longeco de riveroj Missing pakfiles Mankas objektoj! Modify the selected line Modifii la elektitan linion Monate alt Monata aÄo Monorail Unurelo monorail vehicle Unurela veturilo monorail_track Unurela trako Monorailboden Altigita vojo Monoraildepot Unurela veturilejo month wait time monata atenda tempo Months Monatoj Monument Monumento Monuments Monumentoj Mountain height Monta alteco: Movingobj Vivaĵo Music playing disabled/not available Muziko estas neebligita. Music volume: Muzika laÅ­teco: mute sound Nuligi sonon Name Nomo Narrowgauge EtÅpura fervojo Narrowgauge are not available yet! EtÅpura fervojo ankoraÅ­ ne estas farita! narrowgauge vehicle EtÅpura fervoja veturilo narrowgauge_track EtÅpura fervojo Narrowgaugedepot EtÅpura fervoja veturilejo Net ID: %p Reto ID: %p\n Net Wealth Tuta aktivo Net wealth near zero Via riĉeco estas preskaÅ­ nula. Neue Karte Nova mapo Neue Welt Krei novan mondon new convoi Nova veturilo New Line Nova linio New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nova linio estas kreita!\nVi povas asigni la linion de selekti Äin el la liniselektilo supre. New Vehicles Novaj veturiloj Nickname: Salutnomo: no buildings hidden Montri ĉiujn domojn no convois Neniu vagonaro No goods are loaded onto this convoi. Igi ĉi tiun veturilon nur malÅarÄi. no goods waiting Neniu fabrikaĵo atendas no load Nur malÅarÄi No Route Senvojo No stop here! Ĉi tie ne estas haltejo. No suitable ground! Ĉi tie ne estas uzebla kahelo! No terminal station here! Oni ne povas konstrui finhaltejon ĉi tie! Vojfinejo necesas. no timeline NelaÅ­jare no tree Ne fari arbojn No. of Factories Fabrikoj kaj butikoj: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Åœargu linplanon antaÅ­ ekveturigi la veturilon.\n none nenio nord Nordo nordost Nordoriento nordwest Nordokcidento Not allowed to make publicly owned ways! Estas ne permesita publikigi! Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Ne povas ÅanÄi la veturilan liniplanon dum vojtrovado. Not enough fields would remain. Nesufiĉaj kampoj restos ĉirkaÅ­ tiu ĉi farmo. November Novembro now nun Now active as %s.\n Nun aktivas kiel %s.\n nowhere Nenie Number of rivers Nombro de riveroj Object Objekto Oct. Okt. Odometer: %s km Veturdistanco: %s km Ok Akcepti Oktober Oktobro On loan since %i month(s) Åœuldas %i monatojn On this map, you are not\nallowed to change player!\n Ĉi tiu ludo estas Ålosita.\nNeniu ludanto povas interÅanÄi viajn rolojn. Only city chains Konstrui urban fabrikan ĉenon Only first %d differing paks reported. There are probably more. Nur unuan %d malsamajn pakojn raportis. VerÅajne estas pli. Only full Unicode fonts Montri nur sufiĉe Unikodan tiparon Only land chains Fari fabrikan ĉenon Only one transformer per factory! Nur unu substacio por fabriko! Only show goods which are currently handled by factories Montri nur fabrikaĵojn, kiuj estas uzitaj de fabrikoj nuntempe open Malfermita Operation Kuradaj kostoj Ops Profit Servada profito Optionen Opcioj Or enter a server manually: Entajpi servilnomon: Origin Ekirejo ost Oriento Output Fabrikaĵo Ownership Proprulo Pak which may cause severe errors: Mankas sekvantaj pakoj, kiuj eble kauzos malordon de transportaj ĉenoj: Pak which may cause visual errors: La sekvantaj objektoj estas anstataÅ­igitaj per similaj objektoj: Pak(s) different: Malsamaj pakoj: Pak(s) missing on client: Mankaj pakoj: Pak(s) not on server: Kromaj pakoj: Pakset differences Pakseta diferenco paletten paledoj Pas_tab PasaÄera vagono Passagiere PasaÄeroj Passagierrate PasaÄera nivelo Passagierziele Celoj Passenger AI PasaÄera AI Passenger Demand %d\n PasaÄera postulo: %d\n Passengers %d %c, %d %c, %d no route PasaÄeroj %d %c, %d %c, %d senvoje Passengers %d %s, %d %s, %d no route PasaÄeroj %d %s, %d %s, %d senvoje Password Pasvorto: Pause PaÅ­zi Pax <%i> Mail <%i> PasaÄeroj <%i> PoÅtaĵoj <%i> PaxDest Celoj Percent Electricity Elektra eligo (%%): Planes are not available yet! Aviadilo ankoraÅ­ ne estas farita. Plant tree Arbumi player Ludanto player -1 Homludanto player 0 Publika servo player 1 Napiko 128 AS player 10 Ludanto 10 player 11 Ludanto 11 player 12 Ludanto 12 player 13 Ludanto 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Freight Forwarder VM player 5 H-Trans Ltd player 6 PSK & Co KG player 7 Ludanto 7 player 8 Ludanto 8 player 9 Ludanto 9 Please choose vehicles first\n Bonvolu elekti veturilojn unue!\n Post PoÅtaĵoj Postrate PoÅta nivelo Power Elektra povumo Power (MW) Elektra povumo (MW) Power: Povumo: Power: %4d kW\n Povumo: %4d kW\n Powerlines Elektrolinioj Price Prezo Problems_msg Problemoj Produced Produktitaj Produces: %.1f units/minute Produktaĵoj: %.1f /minuto Production of %s has been stopped:\n%s\n %s "%s" ne plu estas aĉetebla. Production/Boost Produkto/pliigo Produktion Produktado: Profit Profito promote to line Promocii al linio q1 Printempo q2 Somero q3 AÅ­tuno q4 Vintro Query server Montri servilan informon rail car Vagono random Hazarde Random age Hazarda aÄo Random map Hazarda mapo Rathaus Urbdomo Rating Takso ratio_pax PasaÄera Rilatumo Relevant rilataj Reliefkarte Mapeto Remove Malkonstrui remove airstrips Malkonstrui kurejojn remove channels Malkonstrui kanalojn remove interm. signals Malkonstrui interajn signalilojn remove maglev tracks Malkonstrui magnetvojojn remove monorails Malkonstrui unurelojn remove narrowgauge tracks Malkonstrui etÅpurajn fervojojn remove powerlines Malkonstrui elektroliniojn remove roads Malkonstrui vojojn remove tracks Malkonstrui fervojojn Remove wayobj %s Malkonstrui vojobjektojn %s replace other signals AnstataÅ­igi aliajn signalilojn replace stop AnstataÅ­igi haltejon request closing fermita residential house Hejmoj Restore natural slope Reigi deklivon Restwert: Vendprezo: Retire. date: RetiriÄa dato: return ticket Kopii malantaÅ­en Revenue Veturilaj enspezoj Revision: Revizio: road vojo road vehicle Voja veturilo Roadsign Trafiksigno Rotate map Turni mapon Rotation Direkto Routing Vojplano sack sakoj sail vento Saving map ... Sekurigas mapon ... Scenario complete: %i%% Scenara progreso: %i%% Scenario Debug Sencimigo Scenario Error Log Eraroj Scenario Goal Celo Scenario Info Informo Scenario information Scenaria informo Scenario Result Rezulto Scenario Rules Reguloj Schedule changing! ÅœanÄas liniplanon! Schienentunnel Konstrui fervojan tunelon Schiff_tab ÅœarÄoÅipoj Schiffdepot Åœipfarejo Schleppkahn_tab BarÄoj Screenshot Foti ekranon Search: Serĉi: Seasons Sezonoj Sehenswuerdigkeit Altiraĵo Select a server to join: Elekti servilon: Select a theme for display Elekti haÅ­ton Select display font Elekti tiparon Sell the selected vehicle(s) Vendi elektota(j)n veturilo(j)n sended Liveritaj poÅtaĵoj SEP_FRACTION , SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September Septembro. Server did not respond! Servilo ne respondis! Serves Line: Servas la linion: Service Servo set signal spacing Agordi signalilan distancon Setting Agordoj Ship Åœipo shops and stores Butikoj Show all Montri ĉion show all building Montri ĉiujn domojn Show also vehicles no longer in production. Montri ankaÅ­ veturilojn, kiuj ne plu estas produktitaj. Show also vehicles that do not match for current action. Montri ankaÅ­ veturilojn, kiuj ne povas esti uzataj al sekvanta pozicio. Show even servers with wrong version or pakset Montri ankaÅ­ servilojn, kiuj ne adaptiÄas kun via versio aÅ­ pakseto. show grid Montri kradon Show industry Fabrikolisto Show legend Montri enhavon Show map scale Kolorskalo Show mismatched Montri neuzeblajn servilojn Show obsolete Montri malaktualaĵojn Show offline Montri senkonektajn servilojn Show only used Montri ekzistantajn aĵojn Show schedules Montri liniplanojn Show servers that are offline Montri senkonektajn servilojn Show servers where game version or pakset does not match your client Montri servilojn, kiuj havas malsamajn versiojn aÅ­ paksetojn show station coverage Montri haltejoareon show station names Montri haltejonamojn show waiting bars Montri atendbastonojn show/hide block reservations Montri/malmontri blokrezervadojn Show/hide estimated arrival times Montri/malmontri taksitajn alvenajn tempojn show/hide object owner Montri/malmontri proprulon Show/hide statistics Montri/malmontri statistikojn Shows buttons on special topics. Montri butonojn pri specialaj temoj. Shows consumer/suppliers for factories Montras konsumantojn/ofertantojn por fabrikoj Shows the color code for several selections. Montri la kolornombron por kelkaj elektoj. Shows the currently selected schedule Montri la elektitan liniplanon Shrink city Malkreski urbon shuffle midis Senorde Signal Signalilo signal spacing Distanco inter signaliloj Sim: Kalkulfojo: Similar view as the main window Turni mapeton kiel ĉefmapo Size (%d MB): Grandeco (%d MB): sliced underground mode Tranĉi nivelon de la mapo slot empty Smart hide objects Malmontri ĉirkaÅ­ kursoro Sort by Ordigi per Sort by: Ordigi per: Sort waiting list by Ordigi atendolisto per Sound Sono Sound settings Agordoj de sono Sound volume: LaÅ­teco de sono: special freight Speciala frajtaĵo Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Kromenspezo laÅ­ rapideco procente\npostulas almenaÅ­a rapideco por vojo %i km/h,\nfervojo %i km/h, Åipoj %i km/h, aviadiloj %i km/h, Speedlimit Rapidolimo Speichern Sekurigi mapon Spieler Ludanto Spieler(mz) Ludantoj Spielerliste Ludantolisto Spielstand wurde\ngeladen!\n \nSukcese malfermis ludon.\n Spielstand wurde\ngespeichert!\n La ludo estas sukcese sekurigita. Sprache Lingvo Sprachen Lingvoj Stadtinformation Urba statistiko Start Ekveturigi Start the selected vehicle(s) Ekveturigi la elektitan veturilon. Starte Spiel Komenci ludon Station tiles: Longo de haltejo: Station_msg Stacidomoj Status Halteja stato steam vaporo Step timeline one year Flugi al venonta jaro Stops Haltejoj Storage Enhavaĵo Storage capacity Enhaveco Strassendepot Veturilejo Strassentunnel Konstrui vojtunelon street car Tramo sued Sudo suedost Sudoriento suedwest Sudokcidento Summer snowline Somera neÄnivelo Supplied: %.0f %% Oferto: %.0f %% Suppliers Ofertantoj: Tage alt tage aÄas. Theme selector Elekti temon There are still vehicles\nstored in this depot!\n Estas veturiloj en la veturilejo!\n This Month Ĉi-monato: This Year Ĉi-jaro: Tile not empty. Nuligu la kahelon antaÅ­ konstrui deklivon. timeline LaÅ­jare tl_title Urbolisto To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Por altiri pli turistojn al %s, %s estis konstruita je helpo de loÄantoj. To heavy traffic\nresults in traffic jam.\n Multe da trfariko kaÅ­zas trafikan ÅtopiÄon.\n Toggle day/night view ÅœanÄi inter tago kaj nokto Toggle vehicle tooltips ÅœanÄi montri staton de veturiloj tonnen t Total inhabitants: Tutaj loÄantoj: Tourist attractions Altiraĵoj: Tourists Altiraĵoj Town_msg Urbo Town: %s\n Urbo: %s\n Towns Urboj track fervojo Tracks Fervojo Traffic Trafiko Train Vagonaro Trains are not available yet! Fervojo ankoraÅ­ ne estas farita. Tram Tramo tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tramo %i km/h, unurelo %i km/h\nmagnetvojo %i km/h, EtÅpura fervojo %i km/h. tram_track Tramo Tramdepot Trama veturilejo Trams are not available yet! Tramo ankoraÅ­ ne estas farita. Transferring game ... Transdonas ludon ... Transformer only next to factory! Transforma stacio devas esti apud fabriko! Translation Traduko transparent station coverage Surmontri efektareon de haltejoj Transported Transportitaj Trees disabled! Arboj ne estas uzeblaj! TrolleyBus_tab Trolebusoj Truck ÅœarÄaÅ­to tt_Other Aliaj Tunnel muss an\neinfachem\nHang beginnen!\n Tuneloj devas esti sur rekta deklivo! Tunnel must start on single way! Tuneloj devas esti sur rekta vojo. Tunnelboden Tunelo underground mode Subtera vido UNDO failed! Vi ne rajtas malfari. Vi povas malfari vojon nur kiam vi ne konstruis signarilojn, staciojn, haltejojn aÅ­ ion ajn sur la vojo. Undo last ways construction Malfari lastan vojon Unemployed Senlaboruloj Unhappy Malfeliĉuloj units/day unuopoj/monato Update Line Modifii linion upgrade HQ Promocii ĉefsidejon Usage: %.0f %% Uzado: %.0f %% Usage/Output Uzado/Eligo Use beginner mode Mi estas komencanto. Use timeline start year Komenci ludon de la jaro: Vehicle %s can't find a route! Veturilo %s ne povas trovi vojon! Vehicle %s is stucked! Veturilo %s haltadas! Vehicle details Veturilaj dataloj Vehicle Name Veturila nomo Vehicle Power Povumo Verbrauch konsumo: Vergroessere die Karte\n Vastigas mapon ... Verkauf Forvendi tuj verkaufen Vendi Verkehrsteilnehmer PrivataÅ­toj Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Vi havas Åuldon. Bonvolu pagi tion Äis post %d monatoj. via tra via %s\n tra %s\n via Menge Tra (kiomo) voranstellen Meti antaÅ­en Waggon_tab ÅœarÄvagonoj waiting Atendas Waiting for clearance! Haltigita! Walked Piediri walking Piedirante Warnings_msg Trafiko Wasser Akvo Water Kanalo Water level Akva nivelo: water vehicle akvoveturilo way %s cannot longer used:\n Vojtipo %s ne plu povi esti uzota.\n way %s cannot longer used:\n%s\n Vojtipo %s ne plu povi esti uzota:\n%s\n way %s now available:\n Vojtipo %s estas uzebla nun.\n Way toll Paspago Ways not connected Vojo ne estas konektita. Wegpunkt Vojpunkto Weight Pezeco Weight: Pezeco: Wert Valoro west Okcidento Winter snowline Vintra neÄnivelo withdraw Retiri Withdraw All Retiri ĉion WRONGSAVE MalÄusta dosiero. Year %i has started. La jaro %i ĵus komencis. Years Jaroj Your primary color: Via unua koloro Your secondary color: Via dua koloro Zielort celejo zooming in Zomi zooming out Malzomi Zu nah am Kartenrand Vi ne povas konstrui tro proksima al la rando de mapo. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nova monda rekordo de magnetvojo: ĉe %.1f km/h de %s! Gratulon! New world record for monorails: %.1f km/h by %s. Nova monda rekordo de unurelo: ĉe %.1f km/h de %s! Gratulon! New world record for motorcars: %.1f km/h by %s. Nova monda rekordo de aÅ­to: ĉe %.1f km/h de %s! Gratulon! New world record for narrowgauges: %.1f km/h by %s. Nova monda rekordo de etÅpura fervojo: ĉe %.1f km/h de %s! Gratulon! New world record for planes: %.1f km/h by %s. Nova monda rekordo de avadilo: ĉe %.1f km/h de %s! Gratulon! New world record for railways: %.1f km/h by %s. Nova monda rekordo de fervojo: ĉe %.1f km/h de %s! Gratulon! New world record for ship: %.1f km/h by %s. Nova monda rekordo de Åipo: ĉe %.1f km/h de %s! Gratulon! #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL ejo &1_CITY_SYLL ponto &2_CITY_SYLL kampo &3_CITY_SYLL vilaÄo &4_CITY_SYLL urbo &5_CITY_SYLL monteto &6_CITY_SYLL insulo &7_CITY_SYLL fonteto &8_CITY_SYLL plato &9_CITY_SYLL monto &A_CITY_SYLL eto &B_CITY_SYLL ego &C_CITY_SYLL rivero &D_CITY_SYLL rivereto &E_CITY_SYLL fonto &F_CITY_SYLL kastelo &G_CITY_SYLL Åtono &H_CITY_SYLL bano &I_CITY_SYLL urbato &J_CITY_SYLL valo &K_CITY_SYLL bordo &L_CITY_SYLL valeto &M_CITY_SYLL kabo &N_CITY_SYLL marĉo &O_CITY_SYLL haveno &P_CITY_SYLL golfo &Q_CITY_SYLL deklivo &R_CITY_SYLL lago &S_CITY_SYLL lageto &T_CITY_SYLL hotelo %0_CITY_SYLL Herb %1_CITY_SYLL Arbar %2_CITY_SYLL Grand %3_CITY_SYLL Verd %4_CITY_SYLL Blu %5_CITY_SYLL RuÄ %6_CITY_SYLL Brun %7_CITY_SYLL Flav %8_CITY_SYLL Flor %9_CITY_SYLL Ĉef %A_CITY_SYLL Nov %B_CITY_SYLL Arb %C_CITY_SYLL AntaÅ­ %D_CITY_SYLL Vic %E_CITY_SYLL AmbaÅ­ %F_CITY_SYLL Bird %G_CITY_SYLL Alt %H_CITY_SYLL La %I_CITY_SYLL Vast %J_CITY_SYLL Riz %K_CITY_SYLL AnÄel %L_CITY_SYLL Post %M_CITY_SYLL Tra %N_CITY_SYLL Eben %O_CITY_SYLL Unu %P_CITY_SYLL Du %Q_CITY_SYLL Tri %R_CITY_SYLL Kvar %S_CITY_SYLL Kvin %T_CITY_SYLL Ses %U_CITY_SYLL Sep %V_CITY_SYLL Ok %W_CITY_SYLL NaÅ­ %X_CITY_SYLL Dek %Y_CITY_SYLL Cent %Z_CITY_SYLL Mil 1center %s %s 1extern %s ekstera %s 1suburb %s ĉirkaÅ­a %s 2center %s centra %s 2extern AntaÅ­ %s %s 2suburb %s %s simutrans-124.3/simutrans/text/es.tab000066400000000000000000001671621474050137200177000ustar00rootroot00000000000000Espanol PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: es Espanol # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Muestra fechas como día:hh:mm del mes AMBIENT_SOUND Sonidos ambientales CASH_SOUND Sonido de facturación cl_btn_filter_disable Desactivado cl_btn_filter_enable Activado cl_btn_filter_settings Opciones cl_btn_sort_asc Ascendente cl_btn_sort_desc Descendente cl_btn_sort_id ID interno cl_btn_sort_income Ingresos cl_btn_sort_name Nombre cl_btn_sort_type Tipo clf_btn_alle Todo clf_btn_invers Invertir clf_btn_keine Nada climate area percentage Tamaño de un clima único Continue Game Continuar Partida CROSSING_SOUND Advertencias de cruce FACTORY_SOUND Sonidos de fábricas Find matching convois Encuentra convoyes coincidentes gl_btn_sort_bonus Bonificación gl_btn_sort_name Nombre gl_btn_sort_revenue Ingresos gl_btn_unsort Sin ordenar height based Clima desde altura hl_btn_filter_disable Desactivado hl_btn_filter_enable Activado hl_btn_filter_settings Opciones hl_btn_sort_asc Ascendente hl_btn_sort_desc Descendente hl_btn_sort_name Nombre hl_btn_sort_type Tipo hl_btn_sort_waiting En espera hlf_btn_alle Todo hlf_btn_invers Invertir hlf_btn_keine Nada humidities Límites de humedad Install Instalar paksets Lake Lago Lake height Máxima altura del lago Maximize height levels Maximizar niveles de altitud moisture land Aumentar sobre la tierra moisture water Aumentar sobre el agua Networks Redes Num pad keys always move map El teclado numérico siempre mueve el mapa Open Sea Mar Abierto Queueing Cola de espera rainfall Humedad Reselect closes tools Re-seleccionar una herramienta la cierra Return to menu Volver al menú Road toll Peaje Scenario Información de Escenario sea Marino Single GUI Interfaz Única Sound range: Rango de sonido: Start this as a server Comienza un servidor usando esta partida temperature borders Límites de temperatura temperature-humidity based Climas desde la meteorología TOOL_SOUND Sonidos de Herramientas TRAFFIC_SOUND Sonidos de Tráfico Transfers Transbordos #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Ártico desert Desértico mediterran Mediterráneo rocky Alpino temperate Templado tropic Tropical tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed ¡No se ha podido cargar\nel script del escenario!\n A building blocks the construction Un edificio bloquea la construcción. Bridge blocked by way below or above. Puente obstruído por otra vía debajo o encima. Can't buy obsolete vehicles! ¡No se pueden comprar vehículos obsoletos! Cannot alter water No se puede alterar el agua Cannot build on a double slope! ¡Sólo se puede construir en una única pendiente o en terreno llano! Cannot built depot here! ¡Aquí no se puede construir un depósito! Cannot built this station/building\nin underground mode here. El edificio/estación no se puede construir bajo la superficie. Cannot connect to the\ncenter of a double slope! ¡No se puede conectar a la\nmitad de una pendiente doble! Cannot create generic line!\nSelect line type by\nusing filter tabs. ¡No se puede crear una línea genérica!\nSeleccione el tipo de línea\nutilizando las pestañas de filtro. Cannot create socket No se pudo crear el socket Cannot rotate this building! ¡No se puede rotar este edificio! Client closed connection during transfer El cliente cerró la conexión durante la transferencia Convoi handles exhausted! Se ha alcanzado el máximo número de convoys. Convoy already deleted! ¡El convoy ya ha sido eliminado! Could not open file No se pudo abrir el archivo Das Feld gehoert\neinem anderen Spieler\n ¡Esta parcela\nes propiedad\nde otro jugador!\n Depots cannot be built on runways! ¡Los depósitos no pueden construirse en pistas de aterrizaje! Depots must be built on flat dead-end way tiles! ¡Los depósitos deben construirse en la casilla final de una vía! Der Besitzer erlaubt das Entfernen nicht El propietario no da\npermiso para\neliminarlo.\n Diese Zusammenstellung kann nicht fahren!\n ¡Esta combinación\nno puede arrancar!\n Flugzeughalt muss auf\nRunway liegen!\n ¡La parada del avión debe\ncolocarse sobre una pista de\naterrizaje! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n No puedes construir\nun aeropuerto aquí.\n Hier kann kein\nSignal aufge-\nstellt werden!\n No puedes colocar\n señales de tren aquí\n In order to lock the game, you have to protect the public player by password! ¡Para proteger la partida debe crear una contraseña para el jugador Servicio Público! Loading a new game will end the current server session! ¡Cargar un juego nuevo finalizará la sesión actual del servidor! Lost connection\nto server! ¡La conexión con el\n servidor se ha perdido! Lost synchronisation\nwith server. Se ha perdido la sincronización\n con el servidor. Maglevhalt muss auf\nMaglevschiene liegen!\n ¡La estación de monorriel debe estar sobre una vía de monorriel! Monorailhalt muss auf\nMonorail liegen!\n ¡Una parada de monorriel\ndebe colocarse sobre una\nvía de monorriel! Monorails are not available yet! ¡Aún no están disponibles los monorrieles! More than one possibility to build this dock found. Se encontró más de una forma de construir este muelle. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n ¡La estación debe estar en una vía estrecha! No bridges over runways! ¡No se puede construir un puente sobre una pista de aterrizaje! No curves on runways ¡Las pistas de aterrizaje no pueden tener curvas! No suitable crossing ¡No es un cruce adecuado! (¿La velocidad máxima es demasiado alta?) No suitable way on the ground! ¡Las estaciones deben construirse sobre una superfície plana! No through station here! ¡Sin estación intermedia aquí! Not enough bytes transferred No se transmitieron bytes suficientes. Not enough clearance. Entre dos vías, se necesita una diferencia de altura mínima de dos. Not enough money! ¡No tienes suficiente dinero\npara construir esto! On narrowgauge track only!\n ¡Sólo permitido en vía estrecha!\n Only public player can lock games! ¡Solo el jugador Servicio Público puede proteger la partida! Only up and down movement in the underground! ¡En el subsuelo sólo se puede subir y bajar usando las herramientas de arriba / abajo! Out of funds ¡No tienes suficiente dinero\npara esto! Post muss neben\nHaltestelle\nliegen!\n ¡Un edificio de extensión\n(oficina postal, almacén)\ndebe ubicarse junto\na una estación!\n Protocoll error (expecting game) Error en protocolo (se esperaba una partida) Schiffhalt muss im\nWasser liegen!\n ¡Sólo puedes colocar\nestaciones marítimas\nen el agua!\n Server busy Servidor ocupado. Server version too new El servidor usa una versión más reciente del programa. Ship depots must be built on water! ¡Los depósitos de barcos deben construirse sobre el agua! Show all revenue messages Mostrar todos los mensajes de ingresos. Show no revenue messages No mostrar mensajes de ingresos. Show only player's revenue Mostrar sólo ingresos del jugador. Terraforming not possible\nhere in underground view No es posible modificar el\nterreno en modo subterráneo.\n This tunnel branches. You can try Control+Click to remove. Este túnel tiene más de 2 entradas. Puede probar Ctrl+clic para eliminar este túnel. Too far away to merge stations! ¡Demasiado lejos para fusionar las paradas! Upgrade must have\na higher level La actualización debe tener\nun nivel superior. Vehicle %s cannot choose because stop too short! El vehículo %s no puede escoger porque la estación es demasiado corta! Zughalt muss auf\nSchiene liegen!\n ¡Sólo puedes colocar\nparadas de\nferrocarril en\nlas vias!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Ayuda

Índice

Acerca de Simutrans

%1$s

Cómo usar

%2$s

Cómo empezar una partida

%4$s

Cómo jugar

%5$s

Herramientas

%3$s

Otras ventanas

%6$s Keyboard Help\n

Keyboard Help

\n Atajos de Teclado\n

Ayuda de Teclado

\n

\n

Ayuda de Teclado Se abre cuando una tecla sin asignar es presionada.\n

\n

\nSe distingue entre mayúsculas y minúsculas (usa [Mayús] para teclas mayúsculas).\n

\n

\nLas teclas con funciones asognadas incluyen:\n

\n

\n[Teclas de dirección]: Mueven la cámara del juego en dirección de la flecha.
\n[Retroceso]: Cierra todas las ventanas, barras de herramientas, y textos de ayuda.
\n[Suprimir], o [Escape]: Cierra la ventana superior, barra de herramientas, o texto de ayuda.
\n[AvPág], o [>]: Acercar la cámara.
\n[RePág], o [<]: Aleja la cámara.\n[CTRL] + herramienta: construye vías rectas (incluso sobre vías más rápidas), o selección inversa durante inspección o eliminación.
\n

At least one stop is connected to the town. Al menos una parada está conectada a la ciudad. At least one tile is connected to one stop. Al menos una parada se encuentra conectada a la fábrica. Color according to transport capacity left Color según capacidad de transporte restante Color-coded terrain according to altitude. Mostrar/ocultar sombreado del contorno del terreno. Decrease water height Drenar el agua un nivel Highlight railroad tracks Resaltar vías de tren Highlite depots Resaltar depósitos Highlite electrical transmission lines Resaltar líneas eléctricas Highlite factories Resaltar industrias Highlite forests Resaltar bosques Highlite tourist attraction Resaltar atracciones turísticas Increase water height Aumentar el agua un nivel Open station/stop details Mostrar detalles de la estación Overlay city limits Superponer límites de ciudades Overlay passenger destinations when a town window is open Superponer destinos de los pasajeros cuando se abre una ventana de una ciudad Overlay schedules/network Superponer itinerarios/redes Overlay town names Superponer nombres de ciudades Please click on the map to add\nwaypoints or stops to this\nschedule. Pulse sobre el mapa\npara añadir puntos de ruta o paradas\na al itinerario. Remove double stops from schedule Eliminar paradas duplicadas del itinerario Set tile climate %s Ajustar el clima de la casilla %s Show capacity and if halt is overcrowded Mostrar capacidad y estaciones llenas Show how many convoi reach a station Mostrar cuántos convoys pasan por las estaciones Show how many people/much is waiting at halts Mostrar cuánta gente o mercancías esperan en las estaciones Show initial passenger departure Mostrar origen de pasajeros y correo. Show level of city buildings Mostrar nivel de los edificios Show mail service coverage/mail network Mostrar cobertura del servicio de correos Show passenger coverage/passenger network Mostrar cobertura de la red de pasajeros Show speedlimit of ways Mostrar los límites de velocidad de las infraestructuras Show the change of waiting at halts Mostrar variación del tiempo de espera desde el último mes Show the owenership of infrastructure Mostrar propietario de infraestructura Show transported freight/freight network Mostrar red de transporte de mercancías Show usage of network Mostrar vehículos por casilla y mes Shows a listing with all industries on the map. Mostrar todas las industrias en el mapa Sum of departure/arrivals at halts Total de salidas y llegadas a las estaciones #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n Ahora %s\nofrece servicios de autobús\nentre %s\ny la atracción turística\n%s\nen (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n Ahora %s\nofrece servicios de autobús\nentre %s\ny la fábrica\n%s\nen (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nopera ahora\n%i camiones entre\n%s en (%i,%i)\ny %s\nen (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nha abierto un nuevo\nferrocarril entre\n%s\nen (%i,%i) y\n%s\nen (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Línea aérea por\n%s\nahora en servicio entre\n%s \ny %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n El servicio de Ferry por\n%s\nestá ahora en servicio entre\n%s \ny %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s ha abierto un servicio\n de autobús entre\n %s\ny %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Herramientas de Edición de Mapa LISTTOOLS Listas MAGLEVTOOLS Herramientas de Maglev MONORAILTOOLS Herramientas de Monorriel NARROWGAUGETOOLS Herramientas de Trenes de Vía Estrecha RAILTOOLS Herramientas de Trenes ROADTOOLS Herramientas de Carreteras SHIPTOOLS Herramientas de Barcos SLOPETOOLS Herramientas de Terreno SPECIALTOOLS Herramientas Especiales de Construcción TRAMTOOLS Herramientas de Tranvía/Tren Ligero #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s ha construido una nueva sede Factory chain extended\nfor %s near\n%s built with\n%i factories. La economía crece:\n%s cerca de %s se añade a la cadena de producción.\n%i nueva fábrica establecida. Net wealth less than 10%% of starting capital! ¡Patrimonio neto inferior al 10%% del capital inicial! New %s now available:\n%s\n Nuevo %s ya disponible:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Crecimiento industrial: Nueva cadena industrial\npara %s\ncerca de %s\nconstruida con\n%i fábricas. New vehicle now available:\n%s\n \n Un nuevo vehículo está disponible:\n\n\n -- %s -- \n\n Now %u clients connected. Actualmente hay %u cliente(s) conectado(s). overtaking Adelantamiento Remove vehicle from map. Use with care! Eliminar vehículo del mapa. ¡Úselo con precaución! Screenshot\ngespeichert.\n Captura de pantalla\nguardada.\n Sends the convoi to the last depot it departed from! Envía el convoy al último depósito del que salió. Server preparing game ... El servidor está preparando el juego... Trees Árboles With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Con un gran festival\n%s\ninauguró un nuevo monumento.\n%i ciudadanos contentos. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Filtro de Línea #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/mes) (%i)- (%i) (in depot) (en el depósito) [0] south-facing [0] orientado hacia el sur [1] east-facing [1] orientado hacia el este [2] north-facing [2] orientado hacia el norte [3] west-facing [3] orientado hacia el oeste [4] southeast corner [4] esquina sureste [5] northeast corner [5] esquina noreste [6] northwest corner [6] esquina noroeste [7] southwest corner [4] esquina suroeste [DELETE] [SUPRIMIR] [END] [FIN] [HOME] [INICIO] [SCROLLLOCK] [BLOQ DESPL] [SHIFT] [MAYÚS] /month /mes \nBauzeit bis hasta \nBauzeit von \nAparece desde \nCan't open heightfield file.\n \nImposible abrir plano\ntopográfico.\n \ndirection: \nDirecciones: \nelektrified \nelectrificado \nHeightfield has wrong image type.\n \nEl plano es un tipo de imagen incorrecto.\n \nis reserved by: \nreservado por el tren \nminimum speed: \nvelocidad mínima \nnot elektrified \nSin electrificar \nRibi (masked) \nDirecciones\m (ocultas): \nRibi (unmasked) \nDirecciones\n (visibles): \nSet phases: \nAjustar tiempo de fases\n / luego \\ y luego desplazamiento \nsingle way \nVía Única \nway1 reserved by \nVía 1 reservada por \nway2 reserved by \nVía 2 reservada por \nwith sign/signal\n \ncon la señal\n %d buildings\n %d Edificios\n %d convois %d Convoyes %d Einzelfahrzeuge im Depot %d Vehículos almacenados aquí. %i car(s), %i Coches, %i km/h (max. %ikm/h) %i km/h (máx. %ikm/h) %i years %i months old. Antigüedad: %i años y %i meses. %s at (%i,%i) now public stop. %s se ha convertido en intercambio público. %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s - Parada %s %s has entered a depot. %s ha llegado al depósito. %s has left. %s se ha ido. %s land %d %s %s tierra %d %s %s now known as %s. %s ahora se conoce como %s. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s derrochó su dinero en un\nnuevo ayuntamiento\ncuando se alcanzaron los\n%i habitantes. %s\nis crowded. ¡%s\n está saturada! %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nVelocidad máxima %3$i km/h\n\nVelocidad actual %2$i km/h.\n\n %s\nwas liquidated. %s cayó en bancarrota y\n ha sido liquidado.\nSe interrumpieron todas su operaciones,\n y todos sus activos han sido vendidos. %u Client(s)\n %u Cliente(s)\n %u Player (%u locked)\n %u Jugadores (%u con contraseña)\n %s - %s
\n [%s]: %s
\n

Error

Error: Objetos duplicados en el directorio principal del pak

En

Warning

addons for

Advertencia: Objetos duplicados en el directorio del addon

Addons para 1 convoi 1 convoy 1 Einzelfahrzeug im Depot 1 vehículo almacenado aquí 100 km/h = %i tiles/month 100 km/h = %i casillas/mes 1LIGHT_CHOOSE Luminosidad: 1th 1. 1WORLD_CHOOSE Opciones para una Nueva Partida: 21th 21. 22th 22. 23th 23. 2LIGHT_CHOOSE Colores: 2th 2. 2WORLD_CHOOSE Número de mapa: 31th 31. 3LIGHT_CHOOSE Velocidad de desplazamiento: 3th 3. 4LIGHT_CHOOSE Invertir Desplazamiento 5LIGHT_CHOOSE Peatones en paradas 5WORLD_CHOOSE Número ciudades: 6LIGHT_CHOOSE Peatones en ciudades 6WORLD_CHOOSE Densidad de tráfico: 8WORLD_CHOOSE Ciclo Día y Noche A bridge must end on a way! ¡Un puente debe terminar en un camino! A bridge must start on a way! No eres dueño del final del camino de este puente, o el camino está obstruído.\n Abfrage Herramienta de Inspección Abnehmer Consumidor: About Acerca de About scenario Copyright Abriss Destruir/Eliminar Absenken Rebajar terreno Abspanntransformator Transformador Accelerate time Acelerar Act. load: %u MW\n Consumo eléctrico: %u MW\n Active player only Solo jugador activo Add forest Añadir bosque Add random citycar Añadir coche privado aleatorio add server Añadir servidor Add Stop Añadir Parada Add stops for backward travel Añadir paradas para el viaje de vuelta. air aéreo Aircraft Aerolínea aircraft_tab Aviones de carga airplane Avión Airport Aeropuerto AIRTOOLS Herramientas de Aeropuertos All Todo all convoi tooltips Toda la información sobre convoyes Allow city growth Permitir crecimiento urbano Allow player change Permitir cambio de jugador allowed climates:\n Climas disponibles:\n Alters a schedule. Añade/quita paradas a/de un itinerario. and arranged by con arreglos de Angenommene Waren Bienes demandados por industrias cercanas anhaengen Añadir Anhaenger_tab Remolques Anheben Elevar terreno Appends stops at the end of the schedule Añade parada al final del itinerario Apply Line Asignar línea Apr. Abr. April Abril Arbeiter aus: Los trabajadores viven en: Arrivals from\n Llegadas desde\n Arrived Llegó Assets Activos Aufloesen Desmontar Aufspanntransformator Transformador Aug. Ago. August Agosto auto Automático Autohalt muss auf\nStrasse liegen!\n ¡Las paradas de autobús/camión deben situarse en la carretera! Available Disponible Available at custom date Disponible en fecha personalizada Bahndepot Depósito de Trenes Bankrott:\n\nDu bist bankrott.\n Bancarrota:\n\nEstás en numeros rojos.\n based on Simutrans 84.22.1 basado en Simutrans 84.22.1 battery Batería Baum Árbol baum builder Plantar árboles Baustelle Sitio en construcción Bauzeit Tiempo de construcción Beenden Salir Beginner mode Modo Principiante Besonderes Gebaeude Atracción turística BF Estación bio biológico Blockstrecke ist\nbelegt\n \nEste segmento de\nvia está en uso\npor otro tren\n Boden Tierra Bonus Multiplier: %i%% Multiplicador de bonificación: %i%% Bonus Speed: %i km/h Bonificación por Velocidad: %i km/h Bonusspeed: %i km/h Velocidad máxima posible: %i km/h Boost (%%) Incremento de producción (%%) Borderless (disabled on fullscreen) Ventana sin bordes (deshabilitado en pantalla completa) bridge is too high for its type! ¡El puente es demasiado alto para su tipo! Bridge is too long for this type!\n ¡El tramo de puente es\n demasiado largo para\n este tipo de puente! Bruecke Puente Bruecke muss an\neinfachem\nHang beginnen!\n ¡El puente debe\nempezar en una\npendiente recta!\n Brueckenboden Puente Build air depot Construir Hangar build choosesignals Construir señales de selección de andén. Build city market Construir un nuevo mercado en la ciudad más cercana. Build drain Subestación transformadora build HQ Construir Sede Build land consumer Construir una nueva central eléctrica. Build maglev depot Construir depósito de maglev Build monorail depot Construir depósito de monorriel Build narrowgauge depot Construir depósito de vía estrecha Build powerline Construir tendido eléctrico Build presignals Construir señales de bloqueo de dos tramos (pre-señales) Build road depot Construir depósito de carretera Build ship depot Construir Astillero Build signals Construir señales Build train depot Construir depósito de trenes Build tram depot Construir depósito de tranvías Build truck depot Construir depósito de camiones Building costs estimates Coste de construcción estimado Buildings Edificios de la ciudad Built artifical slopes Construir pendiente artificial Built random attraction Construir atracción turística aleatoria Bus_tab Autobuses Can be overgrown Puede ser demasiado grande Can only move from halt to halt or waypoint to waypoint. Desplazamiento solo entre paradas o puntos de paso. Cancel Cancelar Cannot connect to offline server! ¡No se puede conectar a un servidor desconectado! Capacity Capacidad Capacity: Capacidad: Capacity: %.0f MW Capacidad: %.0f MW\n Capacity: %d%s %s\n Capacidad: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capacidad: %s\n\nProporción: %d (%d%%) Cars are not available yet! ¡Todavía no están disponibles los automóviles! cars.\nstate Coches\n Cash Efectivo Category Categoría Change label style Cambiar estilo de nombres Change player Cambiar de jugador Chart Gráfica Chat_msg Chat Choose direction Elegir dirección Choose operation executed on clicking stored/new vehicles Elija la operación a ejecutar al pulsar sobre vehículos nuevos o almacenados chooses a random map Elige un mapa al azar. citicens Ciudadanos Cities can only be built on flat empty ground! ¡Las ciudades solo pueden construirse sobre terreno llano! City attraction Atracción turística de ciudad City industries Mercados en las ciudades City list Lista de ciudades City size Tamaño de la ciudad city_road Carretera urbana citybuilding builder Construir edificios urbanos CityLimit Límites de la ciudad cl_title Lista de Vehículos cl_txt_sort Ordenar por: clamp Limitar rango Cleanup schedule Eliminar entradas duplicadas Clear block reservation Mostrar/Ocultar vías reservadas clf_chk_aircrafts Aviones clf_chk_cars Autobuses/camiones clf_chk_indepot en un depósito clf_chk_maglev Maglevs clf_chk_monorail Monorrieles clf_chk_name_filter Filtrar nombres: clf_chk_narrowgauge Trenes de vía estrecha clf_chk_noincome Con pérdidas clf_chk_noline Sin línea clf_chk_noroute Sin ruta clf_chk_noschedule Sin itinerario clf_chk_obsolete Obsoleto clf_chk_ships Barcos clf_chk_spezial_filter Filtro especial: clf_chk_stucked Atascado clf_chk_trains Trenes clf_chk_trams Tranvías clf_chk_type_filter Filtrar tipos: clf_chk_waren Filtrar bienes: clf_title Filtro de la Lista de Vehículos: Climate Clima Climate Control Ajustes de Terreno Climates Climas closed Cerrado. Closes topmost line window when new line selected. Cierra la ventana de la línea superior cuando se selecciona una nueva línea. COLOR_CHOOSE\n Por favor elige\ndos colores de la\nimagen de la derecha:\n Company bankrupt Compañía en bancarrota Company_msg Competencia Comparing pak files ... Comparando archivos pak... Composed by Compuesta por Configure AI Configuración IA Configure AI setttings Propiedades Configuración IA Congratulation\nScenario was complete in\n%i months %i years. ¡Felicidades!\nCompletaste el escenario en\n%i meses y %i años. Connected stops Paradas conectadas: Connected with server Conectado al servidor Connections Conexiones Constructed by Creado por Constructed by %s Creado por %s construction speed Velocidad de construcción. Construction_Btn Costes de Construcción Consumed Consumido contains the following doubled objects:

contiene los siguientes objetos repetidos:

convoi %d of %d Convoy %d de %d convoi error tooltips Información de error en convoyes Convoi following mode Modo seguir al convoy Convoi has been sent\nto the nearest depot\nof appropriate type.\n El convoy ha sido enviado\nal depósito apropiado\nmás cercano. Convoi is sold when all wagons are empty. Se venderá el vehículo cuando esté completamente vacío. convoi mouseover tooltips Información de convoyes al pasar el ratón por encima convoi passed last\nmonth %i\n \nConvoyes durante el último mes: %i\n Convois Convoyes Convois: %d\nProfit: %s Vehículos: %d\nBeneficio: %s Convoys Convoyes Copy Convoi Copiar convoy Copy the selected convoi and its schedule or line Copia el convoy seleccionado y su itinerario o línea. Copy to clipboard Copiar al portapapeles Cost Coste cost for removal Coste de demolición Cost per unit Coste por unidad Cost: %8s (%.2f$/km %.2f$/m)\n Coste: %s (%.2f$/km %.2f$/mes)\n Cost: %8s (%.2f$/km)\n Coste: %8s (%.2f$/km)\n Costs Costes Create a new line based on this schedule Crear una nueva línea a partir de este itinerario curiosity builder Constructor de monumentos curlist_title Lista de Atracciones Turísticas Currently playing: Reproduciendo actualmente: Customers live in: Los clientes viven en: Date format Formato de fecha deactivated in online mode Desactivado en modo online Dec. Dic. Deccelerate time Decelerar December Diciembre decrease underground view level Bajar nivel de vista subterránea Del Stop Eliminar Delete Line Eliminar línea Delete the current stop Eliminar esta parada Delete the selected line (if without associated convois). Eliminar línea seleccionada (si no tiene convoyes asociados) Delete this file. Eliminar este archivo. Delivered Entregados Demand Demanda Demand: %.0f MW Demanda: %.0f MW\n Denkmal Monumento Departed Salió Departs at Sale el (dd:hh:mm) Departure after %% de carga o esperar durante (dd-hh-mm) Departure board Hora de salida Departures per month Salidas al mes Departures to\n Salidas hacia\n Depot Depósito Depots Depósitos Der Tunnel ist nicht frei!\n ¡El túnel no está vacío!\n Destination Llegadas Destroying map ... Destruyendo viejo mapa... Details Detalles Developed by the Simutrans Team Desarrollado por el equipo de Simutrans Die Bruecke ist nicht frei!\n ¡El puente no está libre!\n diesel Diésel directmail Correo Directo Direkt erreichbare Haltestellen Rutas directas desde aquí disable midi Silenciar música MIDI Display bars above factory to show the status Muestra barras sobre las fábricas que indican la cantidad almacenada de producción Display settings Ajustes de pantalla Distance Distancia distributing cities Distribuyendo ciudades distributing factories Distribuyendo industrias Do not show No mostrar Dock Muelle Dock must be built on single slope! ¡El muelle debe construirse sobre una única casilla en pendiente! Downloading Descargando dp_title Lista de Depósitos Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Te quedan %d meses para saldar tu deuda. Durchsatz Máximo Economy Economia y ciudades Eigenbesitz\n Propiedad pública\n Ein %s\npasst hier nicht.\n Un '%s'\nno puede usarse aquí.\n Einstellungen Opciones Einstellungen aendern Opciones electric Eléctrico Electricity Electricidad Electricity producer\n\n Productor de electricidad\n\n Electrics_tab Eléctricos Electrify track Electrificar vía enlarge map Agrandar mapa enter a value between %i and %i Introduce un valor entre %i y %i Enter address Introducir dirección Enter Password Cambiar nombre del jugador y contraseña Erzeuge neue Karte.\n Por favor, espera,\ncreando un\nmapa nuevo ...\n\n (Puede tardar\n algunos minutos\n para mapas grandes.)\n Es wird bereits\nein Fahrplan\neingegeben\n Se está planificando\nun itinerario.\n¡Termínalo antes\nde crear un nuevo itinerario!\n Extract files Extrayendo archivos Fabrikanschluss Fábricas conectadas Fabrikname Nombre de fábrica Factories Fábricas factory details Enlaces de la fábrica factorybuilder Constructor de fábricas Fahrplan Itinerario Fahrtziel Destino: Fahrzeuge koennen so nicht entfernt werden ¡No se pueden\neliminar vehículos\nde esta forma!\n Fahrzeuge: Vehículos: Farbe Color del Jugador Fast forward Acelerar February Febrero Ferry_tab Ferris Fertig Hecho Filename Archivo: Files from: Archivos de: Filter: Filtro: Finances of %s Finanzas de %s Finanzen Finanzas find mismatch Comparar paks fl_title Lista de Fábricas Flug_tab Aviones de Pasajeros follow me Seguir Follow the convoi on the map. Sigue al convoy en el mapa. font size Tamaño de la fuente (sólo fuentes .ttf y .otf) For questions and support please visit: Para preguntas o apoyo técnico, visite: Forest Bosque Found new city Fundar una nueva ciudad Fracht Mercancía Frame time: Retardo: Free Capacity Capacidad Libre freeplay mode Modo libre Freight Carga Friction: Fricción actual: fuel_cell Pila de combustible Full load Esperar a carga mínima del Fullscreen (changed after restart) Pantalla completa (aplicado tras reiniciar) Fundament Cimientos Fussgaenger Peatón Game info Información del juego GAME PAUSED Partida En Pausa Game_msg General Gear: Marcha: Gebaeude Edificio Generated Generado Generation: %.0f MW Generación: %.0f MW\n Gewicht Peso Gewinn Ingresos: Give the selected vehicle(s) an individual schedule Editar el itinerario invididual o asignar línea a los vehículos seleccionados gl_btn_sort_catg Categoría gl_title Lista de Bienes go home Ir al Depósito Goods Bienes Goods AI IA de Bienes Goods list Lista de Bienes Gross Profit Beneficio bruto Groundobj Objeto groundobj builder Constructor de objetos del terreno Grow city Ampliar ciudad. Growth Crecimiento Urbano GUI settings GUI H Parada Happy Felices Has slope graphics Tiene gráficos de pendiente Has Snow Tiene nieve Haus kaufen Comprar casa Helligk. Pantalla Help Ayuda Help text not found Texto de ayuda no encontrado. hide all building Ocultar todos los edificios hide city building Ocultar edificios urbanos Hide labels Ocultar nombres de lugares y paradas hide objects under cursor Ocultar objetos bajo el cursor hide station names Ocultar nombres de estaciones hide transparent Transparentar en lugar de ocultar hide trees Ocultar árboles Hier warten/lagern: Bienes y pasajeros esperando: Higher transport fees, crossconnect all factories Tarifas de transporte mayores, desactivar Justo-a-tiempo Highlite schedule Destacar paradas en el itinerario hl_title Lista de Estaciones hl_txt_filter Filtro: hl_txt_sort Ordenar por: hlf_chk_airport Aeropuertos hlf_chk_anleger Muelle hlf_chk_bahnhof Estación de tren hlf_chk_bushalt Parada de Autobús hlf_chk_frachthof Muelle de carga hlf_chk_keine_verb Sin conexión hlf_chk_maglevstop Estación de Maglev hlf_chk_monorailstop Estación de Monorriel hlf_chk_name_filter Nombre filtro: hlf_chk_narrowgaugestop Estación de tren de vía estrecha hlf_chk_overflow Saturado hlf_chk_spezial_filter Filtro especial: hlf_chk_tramstop Parada de tranvía hlf_chk_type_filter Filtrar tipos: hlf_chk_waren_abgabe Bienes salientes: hlf_chk_waren_annahme Bienes entrantes: hlf_title Filtro de Lista de Estaciones Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. No se encuentra el depósito.\nDebes enviar manualmente\nel convoy al depósito. Homeless Sin techo hydrogene Hidrógeno Idle: Inactivo: ignore climates Ignorar climas In the industry legend show only currently existing factories Mostrar sólo las fábricas existentes en la leyenda de industrias In Transit En Tránsito Increase Industry density Incrementar Tejido Industrial increase underground view level Subir nivel de vista subterránea industrial building Edificios industriales Industry overlay Interfaz de Industria Infinite mouse scrolling Desplazamiento infinito con el ratón Infinite scrolling using mouse ¡El desplazamiento infinito puede fallar con ciertos dispositivos! Init map ... Iniciando mapa... Input Entrada Ins Stop Insertar Insert stop before the current stop Inserta una parada antes de la parada actual. Install graphics Instalar gráficos Install paks Los paksets se descargarán e instalarán. Insufficient funds! ¡Fondos insuficientes! Intercity road len: Long. carretera interurbana: Intro. date Fecha intro. Intro. date: Fecha intro.: invalid indefinido. Invalid coordinate Orden no válida Invert stops Invertir paradas isometric map Vista Isométrica Jan. Ene. January Enero join game Partida Online July Julio Jump to Saltar a June Junio Kann Spielstand\nnicht laden.\n ¡Imposible leer/abrir\nla partida guardada!\n Kann Spielstand\nnicht speichern.\n ¡Imposible abrir\nel achivo para\nguardar!\n Kein Besitzer\n Sin propietario\n keine Nada Keine Einzelfahrzeuge im Depot No hay vehículos almacenados. Keyboard_Help\n Ayuda del Teclado\n koord Coordenadas Kreuzung Cruce labellist_title Lista de Marcadores Lade Relief Cargar Mapa Topográfico Laden Cargar una nueva partida Land attraction Atraccion turística de interior Land industries Cadenas Industriales: LANG_CHOOSE\n Por favor escoge\ntu idioma preferido:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Último Mes Last used tools Últimas herramientas usadas Last Year Último año: Leaving depot! ¡Saliendo del Depósito! leer Vacío legacy (large heights) Legado (Doble altura) legacy (small heights) Legado (Altura única) Legend Leyenda del mapa Leistung Potencia Leistung: %d kW Potencia: %d kW Leitung Línea eléctrica length: %d Longitud: %d letzen Monat: diesen Monat: último mes: este mes: Line Línea Line Management Administración de Líneas line name mouseover tooltips Información sobre el nombre de línea al pasar el cursor por encima linear Linear Lineless convoys serving this stop Convoyes sin línea sirviendo en esta parada: Lines serving this stop Líneas sirviendo a esta parada. List of industries on the map Lista de industrias en el mapa LKW_tab Camiones Load game Cargar Partida load height data from file Cargar topografía desde archivo. Load mode: Cargar modo: Load scenario Escenario Load script tool Cargar herramienta desde script Load Scripted AI Cargar IA desde script loaded cargado loaded passenger/freight Ordenar pasajeros/mercancía por Loading (%i->%i%%)! Cargando (%i->%i%%) Loading (%i%%) departure %s! ¡Cargando (%i%%) salida %s! Loading (%i%%)! Cargando (%i%%) Loading addon paks ... Cargando objetos extra ... Loading map ... Cargando el mapa... Loading paks ... Cargando paks ... Loading skins ... Cargando temas... Loading time: Completamente cargado en: Lock Control key Mantener presionada tecla Control Lock game Impedir cambio de jugador (exige confirmación). Lokomotive_tab Locomotoras m3 m³ maglev vehicle vehículo maglev maglev_track Vía de Maglev Maglevdepot Depósito de Maglev Mail Demand %d\n Demanda de correo %d\n Mail level Nivel de correo Mailbox Buzón Mailbox Options Opciones de Buzón Maintenance Mantenimiento make stop public (or join with public stop next) costs %i per tile and level Hacer pública la parada (o unirla con una parada pública vecina) cuesta %i$ por casilla y nivel Make way or stop public (will join with neighbours), %i times maintainance Convertir a vía o parada pública (conectará con las vecinas), %i veces el mantenimiento Manual (Human) Manual (Humano) Manufactured: Fabricado: Map roughness Terreno abrupto: map view Mapa map zoom Ampliar March Marzo Margin (%%) Margen (%%) Marker Colocar Marcador max máximo Max Boost (%%) Incremento máximo(%%) Max income: Ingresos Máximos: Max. speed Velocidad máxima Max. speed: Velocidad Máxima: Max. waiting time Tiempo de Espera Máx. (dd:hh:mm) Maximum 254 stops\nin a schedule!\n ¡Máximo 254 paradas\npor itinerario!\n maximum length of rivers Longitud máxima de ríos Maximum tile height difference reached. La máxima diferencia\nde altitud entre dos\ncasillas ha sido\nalcanzada. Maxspeed Velocidad Máx. May Mayo Median Citizen per town Media de población por ciudad: Meldung Mensaje Menge Cantidad merge stop Fusionar parada MessageOptionsText \nAño Nuevo\n\nNoticias de Jugadores\n\nNoticias de Ciudades\n\nSin Ruta\n\nNuevos Destinos\n\nChat\n\nNuevos Vehículos\n\nEstaciones Saturadas\n\nProblemas\n\nAtascos\n\nEscenario min mín. minimum length of rivers Longitud mínima de rios Minimum load Carga mínima (%%) Missing pakfiles ¡Faltan objetos (pak)! Modify the selected line Modificar la línea seleccionada. Monate alt Meses de antigüedad. Monorail Monorriel monorail vehicle Vehículo de Monorriel monorail_track Vía de Monorriel Monorailboden Vía Elevada Monoraildepot Depósito de Monorriel Month Mes month wait time Tiempo de Espera (Meses) Monthly departures Horarios de salida fijos Months Meses Monument Monumento Monuments Monumentos Mountain height Altura de montañas: Move the map Mover el mapa Movingobj Objeto móvil Music playing disabled/not available Música desactivada/no disponible. Music volume: Volumen de la música: mute sound Silenciar sonido Name Nombre Narrowgauge Vía estrecha Narrowgauge are not available yet! ¡Aún no están disponibles los vehículos de vía estrecha! narrowgauge vehicle Vehículo de vía estrecha narrowgauge_track Vía estrecha Narrowgaugedepot Depósito de trenes de vía estrecha Net ID: %p ID de red: %p\n Net Wealth Valor neto Net wealth near zero Valor neto cerca de cero Neue Karte Nueva Partida Neue Welt Crear Partida Nueva new convoi Nuevo convoy New Line Nueva línea New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. ¡Nueva línea creada!\nPuedes asignar la línea\nseleccionándola desde el\ndesplegable 'línea' de arriba. New Vehicles Nuevos Vehículos Nickname: Apodo: no buildings hidden Sin edificios ocultos no convois Sin convoyes No goods are loaded onto this convoi. Este convoy no cargará bienes ninguno no goods waiting Sin bienes esperando no load Sólo descarga No player Sin jugador No Route Sin ruta No stop here! ¡Debes usar esta herramienta en paradas! No suitable ground! ¡No es el terreno adecuado! No suitable townhall available for this climate! ¡No hay un edificio de ayuntamiento apropiado para este clima! No terminal station here! ¡No se puede construir una estación\n terminal aquí! Se necesita un tramo\n final de carretera/vía. no timeline Todas las épocas no tree Sin árboles No vehicles are available for purchase. No hay vehículos disponibles para su compra. No. of Factories Fábricas y tiendas: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n ¡Asigna una ruta\nal vehículo antes\nde darle la orden\nde partida!\n none Nada nord Norte nordost Nordeste nordwest Noroeste Not allowed to make publicly owned ways! ¡No se permite hacer vías públicas! Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! ¡No está permitido!\nLa línea ferroviaria no puede\ncambiarse ahora.\nPruebe más tarde. Not enough fields would remain. No habrá suficientes\ncampos alrededor de esta\ngranja. November Noviembre now ahora Now active as %s.\n Ahora activo como %s.\n nowhere en ningún sitio Number of rivers Número de ríos Object Objeto Odometer: %s km Kilometraje: %s km Ok Aceptar Oktober Octubre On loan since %i month(s) Numeros rojos desde %i mes(es) On mouseover Al pasar por encima el ratón on the salida(s) al mes, comenzando el (dd-hh-mm) On this map, you are not\nallowed to change player!\n ¡Esta partida está bloqueada!\n¡No se puede cambiar de jugador!\n Only city chains Construir cadena industrial urbana Only first %d differing paks reported. There are probably more. Sólo se informa de los primeros %d paks diferentes. Probablemente haya más. Only full Unicode fonts Sólo fuentes Unicode completas Only land chains Construir cadena industrial de interior Only one transformer per factory! ¡Cada fábrica solo puede tener un transformador! Only show goods which are currently handled by factories Mostrar sólo bienes procesados actualmente por fábricas open Abierto. Operation Costes de Op. Ops Profit Beneficio Operacionales Optionen Opciones Or enter a server manually: O introduce un servidor manualmente: ORDINAL_DAY_SYMBOL º Origin Orígen ost Este Output Producción Ownership Propietario Pak which may cause severe errors: Los siguientes objetos (pak) faltan, lo que puede provocar errores en las redes de transporte: Pak which may cause visual errors: Los siguientes objetos(pak) han sido reemplazados por objetos similares: Pak(s) different: Pak(s) diferentes: Pak(s) missing on client: Pak(s) no encontrados en el cliente: Pak(s) not on server: Pak(s) no encontrados en el servidor: Pakset differences Diferencias entre paksets paletten Paquetes Pas_tab Trenes de Pasajeros Passagiere Pasajeros Passagierrate Nivel de pasajeros Passagierziele Destinos de pasajeros/correo Passenger AI IA de pasajeros Passenger Demand %d\n Demanda de pasajeros: %d\n Passengers %d %c, %d %c, %d no route Pasajeros %d %c, %d %c, %d sin ruta Passengers %d %s, %d %s, %d no route Pasajeros %d %s, %d %s, %d sin ruta Password Contraseña Pause Pausa Pax <%i> Mail <%i> Pasajeros <%i> Correo <%i> Pax level Nivel de pasajeros PaxDest Destinos Percent Electricity Producción de electricidad (%% demandada): Planes are not available yet! ¡Todavía no están disponibles los aviones! Plant tree Plantar árboles player Jugador player -1 Jugador Humano player 0 Servicio Público player 1 Ricos sobre Rieles player 10 Jugador 10 player 11 Jugador 11 player 12 Jugador 12 player 13 Jugador 13 player 2 Transportes Triunfales player 3 Moviéndose Mucho S.A. player 4 Mercancía a Mogollón S.L. player 5 Rey de la Carretera S.L. player 6 Compañía Muevelotodo player 7 A Todo Tren S.A. player 8 Viajes Justo a Tiempo player 9 Jugador 9 Please choose vehicles first\n ¡Jugador, selecciona primero los vehículos!\n Post Correo Postrate Nivel de Correo Power Potencia Power (MW) Potencia (MW) Power: Potencia: Power: %4d kW\n Potencia: %4d kW\n Powerlines Tendido eléctrico Price Precio Problems_msg Problemas Produced Producido Produces: %.1f units/minute Produce: %.1f unidades por minuto Production of %s has been stopped:\n%s\n La producción de %s ha sido descontinuada:\n%s\n Production/Boost Producción/Incremento Produktion Producción: Profit Beneficio promote to line Convertir en línea q1 Primavera q2 Verano q3 Otoño q4 Invierno Query server Contactar servidor rail car Vagón random Aleatorio Random age Edad aleatoria Random map Mapa al azar Rathaus Ayuntamiento Rating Calificación ratio_pax Ratio Pasajeros Relevant Relevante Reliefkarte Mapa Remove Eliminar etiqueta remove airstrips Eliminar pistas de aterrizaje o rodaje remove channels Eliminar canales remove interm. signals Eliminar señales intermedias remove maglev tracks Eliminar vías de maglev remove monorails Eliminar monorrieles remove narrowgauge tracks Eliminar tramos de vía estrecha remove powerlines Eliminar tendido eléctrico remove roads Eliminar carreteras remove signal Eliminar señal remove tracks Eliminar vías Remove wayobj %s Eliminar objeto %s replace other signals Sustituir otras señales replace stop Reemplazar parada request closing Petición de cierre residential house Edificios residenciales Restore natural slope Restaurar pendiente natural Restwert: Valor de Reventa: Retire date Fecha de retirada Retire. date: Fecha de Retirada: return ticket Viaje de vuelta Revenue Ingresos Revenue/unit/100 tiles Ingresos por unidad y 100 casillas Revert schedule Deshacer cambios Revision: Revisión: road Carretera road vehicle Vehículo de carretera Roadsign Señal de tráfico Rotate Building Rotar edificio Rotate map Rotar mapa Rotation Rotación Routing Calculando ruta Running cost Coste operacional sack Sacos sail Viento Save Guardar Saving map ... Guardando mapa... Scenario complete: %i%% Escenario completado: %i%% Scenario Debug Depurar Scenario Error Log Errores de script Scenario Goal Objetivo Scenario Info Información Scenario information Detalles del escenario Scenario Result Progreso Scenario Rules Normas Scenario_ Escenario Schedule changing! ¡Cambio de itinerario! Schienentunnel Construir túnel ferroviario Schiff_tab Barcos Schiffdepot Astillero Schleppkahn_tab Barcazas Screen scale: Escala de pantalla: Screenshot Captura de pantalla Scroll threshold Umbral de desplazamiento Search: Buscar: Seasons Estaciones Sehenswuerdigkeit Atracción turística Select a server to join: Selecciona un servidor para unirte: Select a theme for display Selecciona un tema para mostrar Select display font Selecciona una fuente de texto Select one or more graphics to install (Ctrl+click): Selecciona uno o más paksets para instalar (Ctrl+click): Select soundfont Seleccionar soundfont Sell the selected vehicle(s) Vender los vehículos seleccionados Selling of the program is forbidden. Está prohibida la venta de este programa. sended Correo enviado SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Sept. Sep. September Septiembre Served by Servido por Served by me Servidas por mi empresa Server did not respond! ¡El servidor no respondió! Serves Line: Sirve en línea: Service Servicio set signal spacing Establecer espacio entre señales Setting Configuración Ship Barco shops and stores Tiendas y oficinas Show all Mostrar todo show all building Mostrar todos los edificios Show also vehicles no longer in production. Mostrar también vehículos obsoletos. Show also vehicles that do not match for current action. Mostrar también vehículos que no pueden ser empleados en la acción seleccionada. Show always Mostrar siempre Show climates Mostrar climas Show contour Mostrar alturas Show even servers with wrong version or pakset Mostrar también servidores con versiones o paksets incompatibles. Show finances for transport type Mostrar finanzas del tipo de transporte Show future Mostrar futuros show grid Mostrar cuadrícula Show industry Lista de Industrias Show legend Selecciones Show map scale Escala Show mismatched Mostrar incompatibles Show networks Redes Show obsolete Mostrar obsoletos Show offline Mostrar offline Show only used Mostrar sólo los utilizados Show outline Mostrar infraestructura Show schedules Mostrar itinerarios Show servers that are offline Mostrar servidores offline Show servers where game version or pakset does not match your client Mostrar servidores con versiones o paksets que no concuerdan con los tuyos show station coverage Mostrar cobertura de estaciones show station names Mostrar nombres de estaciones show waiting bars Mostrar barras de espera show/hide block reservations Mostrar/ocultar reservas de tramos Show/hide estimated arrival times Mostrar/ocultar horarios estimados de llegada show/hide object owner Mostrar/ocultar propietario Show/hide statistics Mostrar/ocultar Estadísticas Shows buttons about networks overlay. Muestra los botones de configuración de la vista de redes. Shows buttons on network overlay. Mostrar opción para superponer una red de conexión. Shows buttons on special topics. Mostrar los botones de la leyenda del mapa Shows consumer/suppliers for factories Mostrar consumidores/proveedores de las fábricas Shows the color code for several selections. Representa en el mapa la selección usando una escala de colores Shows the currently selected schedule Mostrar el itinerario seleccionado Shrink city Reducir ciudad shuffle midis Música Aleatoria Signal Señal signal spacing Distancia entre señales Sim: Ciclos: Similar view as the main window Vista similar a la principal del juego Single toolbar only Barra de herramientas única Size (%d MB): Tamaño (%d MB): Size (area) Tamaño (área) sliced underground mode Vista subterránea por capas slot empty Casilla vacía Smart hide objects Ocultación inteligente de objetos Sort by Ordenar por Sort by: Ordenar por: Sort waiting list by Ordenar lista de espera por Sound Sonido Sound settings Ajustes de sonido Sound volume: Volumen del sonido: Soundfonts are located in the music directory. Las fuentes de sonido se guardan en el directorio 'music'. special freight Mercancía especial Speed Bonus Bonificación por Velocidad Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. La bonificación por velocidad en porcentaje\nrequiere velocidad mínima de carretera %i km/h,\n de tren %i km/h, de barcos %i km/h, de aviones %i km/h, Speedlimit Límite de velocidad Speichern Guardar Partida Spieler Jugador Spieler(mz) Jugadores Spielerliste Lista de Jugadores Spielstand wurde\ngeladen!\n \n¡Partida cargada con éxito!\n Spielstand wurde\ngespeichert!\n \n¡Partida guardada con éxito!\n Sprache Idioma Sprachen Idiomas Stadtinformation Estadísticas de la Ciudad Start Arrancar Start the selected vehicle(s) Arrancar los vehículos seleccionados. Starte Spiel Comenzar Partida station labels Estaciones Station tiles: Casillas de Estación: Station_msg Estaciones Status Estado de las paradas steam Vapor Step timeline one year Avanzar un año en la cronología. Stops Paradas Storage Almacén Storage capacity Capacidad de almacenamiento Strassendepot Depósito de carretera Strassentunnel Construir túnel de carretera street car Tranvía sued Sur suedost Sureste suedwest Suroeste Summer snowline Cota estival Supplied: %.0f %% Suministrado: %.0f %% Suppliers Proveedores Tage alt días de antigüedad. The following graphics are unmaintained: Los siguientes paksets están abandonados: The gradient does not fit a tunnel ¡La pendiente no tiene la altura adecuada para un túnel! Theme selector Selector de temas There are still vehicles\nstored in this depot!\n ¡Hay vehículos\nen este depósito!\n This Month Este mes: This Year Este año: Tile not empty. Limpia la casilla antes de usar\n una Herramienta de Pendiente Artificial. timeline Usar cronología tl_title Lista de Ciudades To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. El tráfico en %1$s está aumentando:\n%3$i contribuyentes hicieron posible\nla construcción de %2$s. To heavy traffic\nresults in traffic jam.\n El exceso de tráfico pesado\nprovoca un atasco.\n Toggle day/night view Alternar vista día/noche Toggle vehicle tooltips Alternar información sobre vehículos tonnen t Toolbar position: Posición de la barra: Total inhabitants: Población: Tourist attractions Atracciones turísticas: Tourists Atracciones turísticas Town_msg Nuevos Destinos Town: %s\n Ciudad de %s\n Towns Ciudades track Vía Tracks Vías Traffic Tráfico traffic settings Tráfico Train Tren Trains are not available yet! ¡Todavía no están disponibles los trenes! Tram Tranvía tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tranvía %i km/h, monoriel %i km/h\nmaglev %i km/h, vía estrecha %i km/h. tram_track Vía de tranvía Tramdepot Depósito de tranvías Trams are not available yet! ¡Todavía no están disponibles los tranvías! Transferring game ... Transfiriendo partida... Transformer only next to factory! ¡Los transformadores deben estar junto a una fábrica! Translation Traducción transparencies Transparencia transparent background Fondo transparente transparent station coverage Cobertura de estación transparente Transported Viajes Trees disabled! ¡Árboles deshabilitados! TrolleyBus_tab Trolebuses Truck Camión tt_Other Otro Tunnel muss an\neinfachem\nHang beginnen!\n ¡Los túneles deben\ncomenzar en una\npendiente recta!\n Tunnel must start on single way! ¡Los túneles deben comenzar en una sola carretera! Tunnelboden Túnel under the Artistic License bajo la Artistic License underground mode Vista subterránea UNDO failed! No es posible deshacer.\nSólo puede deshacerse la\nconstrucción de una ruta si\nno se construyeron sobre la\ncarretera señales, estaciones,\nparadas ni ninguna otra cosa. Undo last ways construction Deshacer última construcción de vías Unemployed Desempleados Unhappy Descontentos units/day Unidades/mes Unloading (%i%%)! Descargando (%i%%) Update Line Editar línea upgrade HQ Mejorar Sede Usage: %.0f %% Uso: %.0f %% Usage/Output Consumo/Producción Use beginner mode Usar modo libre Use timeline start year Usar cronología desde el año: Vehicle %s can't find a route! ¡El vehículo %s\n no puede encontrar una ruta! Vehicle %s is stucked! ¡El vehículo %s está atascado! Vehicle count: Número de vehículos: Vehicle details Detalles del Vehículo Vehicle Name Nombre del Vehículo Vehicle Power Potencia del Vehículo vehicles stored vehículos almacenados Verbrauch Consumo: Vergroessere die Karte\n Agrandar mapa.\n Verkauf ¡Eliminar ahora! verkaufen Vender Verkehrsteilnehmer Coches Ciudad Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n ¡Te quedan %d meses\npara pagar tu deuda!\n vh_title Lista de todos los vehículos via por (detalle) via %s\n por %s\n via Menge por (cantidad) voranstellen Poner al frente Waggon_tab Vagones waiting esperando Waiting for clearance! ¡A la espera de vía libre! Walked Caminados walking Caminando Warnings_msg Tráfico Wasser Agua Water Canal Water level Nivel del agua: water vehicle Vehículo acuático way %s cannot longer used:\n El tipo de vía %s ya no se puede usar.\n way %s cannot longer used:\n%s\n el tipo de vía %s ya no se puede usar:\n way %s now available:\n Vía %s disponible.\n Way toll Peaje Ways not connected Las vías no están conectadas waytype Tipo de vía Wegpunkt Punto de paso Weight Peso Weight: Peso: Weight/unit Peso/unidad Welcome to Simutrans Bienvenido a Simutrans Welcome, %s! ¡Te damos la bienvenida, %s! Wert Valor west Oeste Wind direction Dirección del viento Winter snowline Cota invernal withdraw Retirar Withdraw All Retirar todo. WRONGSAVE \nPartida guardada\nincompatible. Imposible leer\nel archivo.\n Year Año Year %i has started. Ha comenzado el año %i. Years Años Your primary color: Tu color primario: Your secondary color: Tu color secundario: Zielort Destino zooming in Acercar cámara zooming out Alejar cámara Zu nah am Kartenrand No puedes construir\nedificios tan cerca\ndel borde del mapa.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Levitando sobre imanes a \n%.1f km/h por %s:\n ¡Nuevo récord mundial! New world record for monorails: %.1f km/h by %s. Un riel construido para la velocidad: \nExactamente %.1f km/h \nalcanzado por %s.\n,¡se convierte en el nuevo récord mundial! New world record for motorcars: %.1f km/h by %s. Sólo quedan marcas de derrape\n de tanto correr a %.1f km/h\n alcanzado por %s.\n,¡ha logrado un nuevo récord mundial! New world record for narrowgauges: %.1f km/h by %s. Nuevo récord mundial para trenes de vía estrecha: %.1f km/h por %s. New world record for planes: %.1f km/h by %s. Disminuyendo distancias otra vez:\n%2$s voló a %1$.1f km/h.\n¡Nuevo récord mundial! New world record for railways: %.1f km/h by %s. Tronando sobre las vías\n a %.1f km/h.\n%s consigue un nuevo récord mundial para trenes.\n New world record for ship: %.1f km/h by %s. ¡A toda máquina!\n%.1f km/h de velocidad récord\n alcanzada por %s. #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s construye convoy adicional en la línea: %s %s build rail line from %s (%s) to %s (%s) %s construye una vía de tren desde %s (%s) a %s (%s) %s build road line from %s (%s) to %s (%s) %s construye una línea de carretera desde %s (%s) a %s (%s) %s build ship line from %s (%s) to %s (%s) %s construye una línea de barcos desde %s (%s) a %s (%s) %s extends the route from %s (%s) to %s (%s) %s extiende la ruta desde %s (%s) a %s (%s) %s optimize way line from %s (%s) to %s (%s) %s optimizar la línea desde %s (%s) a %s (%s) %s removes convoys from line: %s %s elimina convoys de la línea: %s vehicles of the line %s were retired vehículos de la línea %s fueron retirados #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. Añade convoyes con itinerarios similares a esta línea. Enter intervall in days, hours, minutes Introduce el intervalo en días, horas, y minutos. Mirrors order of stops Invierte el orden de las paradas. Revert to original schedule Deshace los cambios al itinerario. Tutorial not available for this pakset. Please try loading Pak128. Tutorial no disponible para este pakset. Pruebe a cargar otros como el Pak128, Pak192,... #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL del Mar &1_CITY_SYLL del Monte &2_CITY_SYLL de Abajo &3_CITY_SYLL de Arriba &4_CITY_SYLL de la Vereda &5_CITY_SYLL de la Frontera &6_CITY_SYLL de la Cañada &7_CITY_SYLL del Valle &8_CITY_SYLL del Río &9_CITY_SYLL de la Reina &A_CITY_SYLL del Rey &B_CITY_SYLL de la Torre &C_CITY_SYLL de la Cruz &D_CITY_SYLL de la Campiña &F_CITY_SYLL hogar &I_CITY_SYLL hielo %0_CITY_SYLL Peligros %1_CITY_SYLL Sordillos %2_CITY_SYLL Peleas %3_CITY_SYLL Villaviciosa %4_CITY_SYLL Cenicero %5_CITY_SYLL El Ciego %6_CITY_SYLL La Pera %7_CITY_SYLL Alcantarilla %8_CITY_SYLL Meadero %9_CITY_SYLL Codos %A_CITY_SYLL Montón %B_CITY_SYLL Brincones %C_CITY_SYLL Calaveras %D_CITY_SYLL Malcocinado %E_CITY_SYLL Consuegra %F_CITY_SYLL Tembleque %G_CITY_SYLL Albaricoques %H_CITY_SYLL Melón %I_CITY_SYLL Matagorda %J_CITY_SYLL El Golfo %K_CITY_SYLL Moscardón %L_CITY_SYLL El Payo %M_CITY_SYLL Cotillas 0center %s centro %s 0extern %s aldea %s 0suburb %s suburbios %s 1center %s %s 1extern %s %s Ensanche 1suburb %s %s %s 2center %s %s Central 2extern %s %s Apeadero 2suburb %s Verdes Praderas %s %s 3center %s %s Principal 3extern %s %s Afueras 3suburb %s villa %s %s 4center %s %s Rambla 4extern %s %s Bosque 4suburb %s Colonia %s %s 5center %s %s Alameda 5extern %s Pradera %s 5suburb Parque Tecnológico %s %s %s 6center %s Conexión %s 6extern %s Parque Industrial %s 6suburb %s afueras %s %s 7center %s ciudad %s 7extern %s llanuras %s 7suburb %s parque %s 8center %s Nodo %s 8extern %s %s margen %s 8suburb %s satélite %s 9center %s Circunvalación %s 9extern %s bypass %s 9suburb %s medio %s Acenter %s central %s Aextern %s barrio %s Asuburb %s, zona suburbana %s Bcenter %s centro de %s Bextern ¡No existe! Bsuburb ¡No existe! Ccenter %s centro %s %s Cextern ¡No existe! Csuburb %s afueras %s Dcenter ¡No existe! Dextern ¡No existe! Dsuburb ¡No existe! simutrans-124.3/simutrans/text/es/000077500000000000000000000000001474050137200171735ustar00rootroot00000000000000simutrans-124.3/simutrans/text/es/airtools.txt000066400000000000000000000133131474050137200215710ustar00rootroot00000000000000Ayuda sobre Herramientas de Aeropuertos

Herramientas de Aeropuertos

Herramientas de Aeropuertos contiene herramientas para construir una red de transporte aéreo. Las herramientas pueden construir o eliminar: Pistas de Rodaje y Pistas de Aterrizaje para aviones, Paradas Aéreas (usadas para dejar o recoger mercancías y pasajeros), hangares de aviones (para comprar y gestionar los aviones) y algunos edificios más de aeropuertos. Si tienes activa la cronología, entonces a medida que pase el tiempo en Simutrans aparecerán más opciones.

Pulsa el icono del avión en la parte superior de la pantalla para abrir el menú.
Posiciona el ratón sobre cada icono de la barra (tras abrir el menú) para ver el nombre y otros datos: coste de construcción, coste de mantenimiento entre paréntesis, y límite de velocidad máxima.

{Consejos:Una forma sencilla de construir un aeropuerto simple es:
1) Construir y conectar Pistas de Rodaje y Pistas de Aterrizaje;
2) Construir Paradas Aéreas al final de las Pistas de Rodaje;
3) Construir las extensiones del aeropuerto (por ejemplo, Torres o Terminales).}

Las herramientas pueden incluir, de izquierda a derecha:

Pista de Rodaje: Herramienta que construye los pasillos por donde se moverán los aviones para ir de las Paradas Aéreas a las Pistas de Aterrizaje. Las Pistas de Rodaje son construidas al nivel del suelo en el juego.
IMPORTANTE: Si las Pistas de Rodaje están conectadas al final de las pistas de aterrizaje, puede que los aviones no puedan despegar ni aterrizar.
Para construir una Pista de Rodaje: pulsa en la herramienta para seleccionar (el cursor cambiará a pista de rodaje), después pulsa en el terreno para marcar el punto de inicio (muestra una excavadora y las coordenadas del punto en la parte inferior derecha de la pantalla), finamente pulsa en el terreno o en la Pista de Aterrizaje para marcar el punto de finalización.
{Consejo: Usa Eliminar para quitar partes individuales de una Pista de Rodaje. La opción Deshacer[z] no reembolsa los costes de construcción.}

Pista de Aterrizaje: Herramienta para construir pistas, usadas por los aviones para despegar y aterrizar. Las pistas de aterrizaje son construidas al nivel del suelo, y se pueden cruzarse entre sí.
Para construir una pista de aterrizaje: pulsa en la herramienta para seleccionar(el cursor cambiará a vía), después pulsa en el terreno para indicar el punto de inicio (muestra un excavadora), finalmente pulsa en el terreno para indicar el punto de finalización.
{Consejo: Deja el final de las pistas de aterrizaje sin conexión, porque sino los aviones no podrán despegar ni aterrizar. Usa Eliminar para quitar partes individuales de las pistas de aterrizaje. La opción Deshacer [z] no reembolsa los costes de construcción.}

Eliminar pistas: Herramienta que elimina un segmento de Pista de Rodaje o de una Pista de Aterrizaje, cuando no hay aviones presentes, entre dos puntos. El uso de esta herramienta supone un coste de construcción.
Para eliminar una pista: pulsa en la herramienta (el cursor cambiará a un X roja); después pulsa en la pista que quieres eliminar (en el tramo a borrar se muestra una X roja); finalmente pulsa en otro punto de la pista, para eliminar un tramo desde el punto inicial. {Consejo: Deja el final de las Pistas de Aterrizaje sin conexión, ya que sino los aviones no podrán despegar ni aterrizar. Usa Eliminar para quitar partes individuales de las pistas.}

Hangar: Herramienta para crear hangares para comprar y gestionar aviones. Los hangares tienen costes de mantenimiento y deben ser construidos en el tramo final de una Pista de Rodaje.
Para construir un hangar: pulsa en la herramienta (el cursor cambiará a un depósito), después pulsa en el tramo final de una Pista de Rodaje.
{Consejo: Elimina hangares con la herramienta Eliminar.}

Paradas Aéreas & puertas de embarque: Herramientas para construir Paradas, para que los aviones embarquen o dejen pasajeros o mercancías.
Una Parada Aérea, cuando no es construida adyacente a una Parada ya existente, creará una nueva Parada.
Las Paradas Aéreas deben ser construidas sobre el final de un tramo de Pista de Rodaje; y tienen un coste de mantenimiento y áreas de cobertura para pasajeros, correo y mercancías. Un avión solo aterrizará en un aeropuerto si hay una Parada Aérea libre y disponible.
Para construir una Parada Aérea: pulsa en la herramienta elegida,y después pulsa sobre el tramo final de una Pista de Rodaje.
{Consejos: Elimina Paradas Aéreas con la herramienta Eliminar. Pulsa [v] para mostrar/ocultar el área de cobertura para pasajeros y mercancías.}

Edificios de Aeropuertos: Herramientas para construir extensiones para Paradas las cuales podrían incrementar los costes de mantenimiento, así como la capacidad y el área de cobertura de pasajeros y mercancías. En la esquina de algunas herramientas, un icono (usado en Lista de Estaciones e Información sobre la Parada) muestra qué elementos podrá aceptar la Parada si se añade dicha extensión.
Para construir una extensión: Pulsa en la herramienta de extensión seleccionada (el cursor cambiará a extensión), después pulsa en el lugar elegido, cerca de una parada existente. La nueva extensión será considerada parte de la parada.
{Consejo: Elimina extensiones con la herramienta Eliminar. Pulsa [v] para mostrar/ocultar el área de cobertura de pasajeros y mercancías.}

simutrans-124.3/simutrans/text/es/baum_build.txt000066400000000000000000000046721474050137200220500ustar00rootroot00000000000000Ayuda sobre Plantar Árboles

Plantar Árboles

La ventana de Plantar Árboles te permite plantar árboles individuales. Es una opción de personalización del mapa, disponible si cambias al jugador del servicio público, y abres las Herramientas de Edición de Mapa.
CONSEJO: También puede estar disponible el botón Añadir Bosque en esta barra, para añadir bosques de una vez.

La ventana se divide en cuatro secciones:
1) Parte superior izquierda: Opciones de filtrado y ordenación.
2) Parte inferior izquierda: Una lista de selección con los árboles disponibles.
3) Parte superior derecha: Opciones de colocación.
4) Parte inferior derecha: Información e imagen del árbol seleccionado.

1 - Opciones de filtrado y ordenación

· Clima: Filtra por los climas permitidos.
· Ordenar por: Ordena la lista según alguno de los siguientes parámetros:
·· Traducción: Muestra y ordena por el nombre en el idioma dado tal como se define en el pakset. Si no hay traducción disponible, se utilizará el nombre del objeto.
·· Object: Muestra y ordena por el nombre del objeto interno utilizado por Simutrans.

2 - Lista de selección

En la lista de selección se muestran todos los árboles que están disponibles con las opciones especificadas. Pulsa en un árbol de la lista para ver más información sobre ese árbol en particular. Para plantar el árbol, pulsa en la ventana del mundo del juego en la ubicación deseada después de seleccionarlo en la lista.

3 - Opciones de colocación

· Ignorar climas: Esta opción desactiva las restricciones climáticas, permitiendo plantar el árbol en climas no permitidos.
· Edad aleatoria: Si está activo, la edad del árbol a plantar será aleatoria. Normalmente, se plantan a la edad más joven, crecerán hasta la madurez y luego morirán en el transcurso de muchos años.

4 - Información

La información sobre árboles contiene:
· Nombre: Nombre del árbol.
· Climas permitidos: Climas en los cuales se permite plantar el árbol (si la opción "Ignorar climas" no está activa).
· Estaciones: Número de estaciones.
· Autor: El nombre del autor que pintó el objeto (si está disponible).
· Imagen: Imagen del árbol.

simutrans-124.3/simutrans/text/es/bridges.txt000066400000000000000000000064031474050137200213560ustar00rootroot00000000000000Ayuda: construyendo puentes

Construyendo puentes

Se puede utilizar un puente para salvar un valle u otro obstáculo.

Cada puente tiene una longitud máxima posible especificada. Para salvar tramos más largos solo tendrás que buscar otro en el menú, o utilizar las islas y dividir la distancia total en varias partes. Se pueden construir puentes incluso a través de valles profundos con terreno irregular, la restricción solo se aplica en los campos iniciales y finales. El puente debe comenzar y terminar en una superficie horizontal, en una pendiente inclinada en la dirección del puente o en una cresta artificial. El inicio y el final del puente no tienen por qué estar a la misma altura, puede haber una diferencia de un nivel entre ellos. Los puentes sólo se pueden construir en la dirección de los límites de la casilla, es decir, (todavía) no se pueden construir en diagonal. Sin embargo, existe un tipo de vía férrea que se asemeja a un puente porque está sobre el suelo. Esta pista también se puede construir en diagonal.

Todos los puentes, ya sean de ferrocarril, de carretera, de transporte o de cables de alta tensión, se construyen de la misma manera. El puente de carretera tiene una excepción: también se le pueden añadir vías de tranvía.

Construyendo un puente

El siguiente procedimiento se puede aplicar a todo tipo de puentes, si aquí está escrito un camino, puedes sustituirlo por un ferrocarril u otro tipo de transporte que tenga puentes:
(i) Construya un camino hacia ambos extremos previstos del puente, siendo el camino y el primer y último espacio del futuro puente.
(ii) Haga clic en el símbolo del puente. Elige el que más te convenga según sus parámetros.
(iii) Haga clic en el campo con el origen del puente deseado y mantenga presionado el botón.
(iv) Mueva el cursor del mouse sobre el cuadrado donde debe terminar el puente y suelte el botón. El puente está terminado.

También existe un procedimiento alternativo. Sin embargo, debes tener ambos extremos del camino debidamente preparados con anticipación, de lo contrario puedes terminar gastando dinero en un puente largo que no deseas. En lugar de los pasos (iii) y (iv), haga clic en el comienzo del puente deseado y suelte el botón. El puente se extenderá hasta el tramo de carretera del otro lado.

Un error común al construir un puente es que no está conectado a la carretera (o al ferrocarril) en los extremos. Arrastra la carretera (ferrocarril) también a las casillas de inicio y fin del puente; de lo contrario, los coches (trenes) no pasarán por encima.

Consejo: A veces no vale la pena construir un puente. Los puentes generalmente tienen costes de mantenimiento más elevados que las carreteras normales (vías, líneas eléctricas, ..). Comprueba si merece la pena rellenar la depresión para detectar pequeñas irregularidades del terreno.

Eliminación del puente

Haga clic en el botón Eliminar y luego haga clic en el inicio o el final de la plataforma del puente.

->Ayuda para la construcción de carreteras
->Ayuda para la construcción de ferrocarriles

->Acerca de la traducción

simutrans-124.3/simutrans/text/es/citybuilding_build.txt000066400000000000000000000105621474050137200236050ustar00rootroot00000000000000Construir edificios urbanos

Construir edificios urbanos

La ventana de Construir edificios urbanos te permite colocar edificios urbanos. Es una opción de personalización del mapa, disponible si cambias al jugador del servicio público, y abres las Herramientas de Edición de Mapa.

La ventana se divide en cuatro secciones:
1) Parte superior izquierda: Opciones de filtrado y ordenación.
2) Parte inferior izquierda: Una lista de selección con los edificios disponibles.
3) Parte superior derecha: Opciones de colocación.
4) Parte inferior derecha: Información e imagen del edificio seleccionado.

1 - Opciones de filtrado y ordenación

· Usar cronología: La lista de selección solo contendrá los edificios que están disponibles en el año actual de Simutrans. Esto se excluye mutuamente con la opción "Disponible en fecha personalizada".
· Disponible en fecha personalizada: La lista de selección solo contendrá los edificios que estén disponibles en la fecha especificada. Esto se excluye mutuamente con la opción "Usar cronología".
· Mostrar obsoletos: Expande la lista de selección para incluir también edificios obsoletos en el año actual de Simutrans.
· Clima: Filtra por los climas permitidos.
· Ordenar por: Ordena la lista según alguno de los siguientes parámetros:
·· Traducción: Muestra y ordena por el nombre en el idioma dado tal como se define en el pakset. Si no hay traducción disponible, se utilizará el nombre del objeto.
·· Object: Muestra y ordena por el nombre del objeto interno utilizado por Simutrans.
·· Nivel de pasajeros: Ordenar por cantidad de pasajeros generados o demandados.
·· Nivel de correo: Ordenar por cantidad de correo generado o demandado.
·· Fecha intro.: Ordenar por fecha de introducción (cuando el edificio comienza a aparecer).
·· Fecha de retirada: Ordenar por fecha de retirada (cuando el edificio deja de aparecer).
·· Tamaño (área): Ordenar por tamaño de edificio en casillas (Nota: algunos paksets pueden tener sólo edificios de una casilla).
· Edificios residenciales: Muestra/oculta los edificios residenciales.
· Tiendas y oficinas: Muestra/oculta los edificios comerciales.
· Edificios industriales: Muestra/oculta los edificios industriales.

2 - Lista de selección

En la lista de selección se muestran todos los edificios que están disponibles con las opciones especificadas. Pulsa en un edificio de la lista para ver más información sobre ese edificio en particular. Para colocar el edificio, pulsa en la ventana del mundo del juego en la ubicación deseada después de seleccionarlo en la lista. El color del texto tiene el siguiente significado:
· Texto azul indica que es un edificio residencial.
· Texto verde indica que es un edificio comercial.
· Texto negro/em> indica que es un edificio industrial.

3 - Opciones de colocación

· Ignorar climas: Esta opción desactiva las restricciones climáticas, permitiendo colocar el edificio en climas no permitidos.
· Rotación: Si el edificio elegido se puede mostrar desde diferentes ángulos, entonces es posible elegir una vista específica del mismo aquí. La imagen cambiará para reflejar esto. Si esta opción se establece en Aleatorio, se utilizará una vista aleatoria del edificio.

4 - Información

La información sobre árboles contiene:
· Tipo: Tipo de edificio (Residencial, Industrial, o Tiendas y oficinas).
· Nombre y descripción: Mostrará solo la descripción si no tiene nombre. Mostrará el nombre del objeto solo si no tiene nombre ni descripción.
· Climas permitidos: Climas en los cuales se permite plantar el árbol (si la opción "Ignorar climas" no está activa). · Nivel de pasajeros: Métrica de cantidad de pasajeros generada o demandada.
· Nivel de correo: Métrica de cantidad de correo generado o demandado.
· Fecha de introducción: Fecha desde que aparece el edificio.
· Autor: El nombre del autor que pintó el objeto (si está disponible).
· Imagen: Imagen del edificio.

simutrans-124.3/simutrans/text/es/citygrowth.txt000066400000000000000000000010421474050137200221340ustar00rootroot00000000000000 Detalles sobre el crecimiento de la ciudad

Crecimiento de la ciudad

Este texto explica cómo se produce el crecimiento de la ciudad. Cómo se calcula, qué edificios se están construyendo y por qué. Y cómo influir en el desarrollo urbano a través de los distintos parámetros.

Una ciudad crece cuando las personas y el correo se transportan a su destino.
Y crece incluso cuando los mercados, las centrales eléctricas y las fábricas pertenecientes a la ciudad reciben suministros.

simutrans-124.3/simutrans/text/es/citylist_filter.txt000066400000000000000000000037731474050137200231570ustar00rootroot00000000000000Lista de Ciudades

Lista de Ciudades

Lista de Ciudades muestra los detalles acerca de las areas urbanas (villas, pueblos y ciudades) y poblaciones.

Para abrirla: pulsa en la herramienta Lista de Ciudades, en Administracion de Listas o pulsa [T].
Lista de Ciudades tiene dos botones de opcion, los cuales determinan el orden en que se muestran las areas urbanas y sus poblaciones.
{Consejos: Si los elementos listados solo son parcialmente visibles, entonces ajusta la ventana de la Lista de Ciudades o desplaza la lista usando la barra lateral.}

Total de habitantes: es el numero total de habitantes en el juego (la poblacion total de todas las areas urbanas). El reciente incremento de poblacion se muestra entre parentesis.

Ordenado por: tiene opciones para determinar el orden en que son mostradas las areas urbanas en la lista.
Pulsa en los botones de opcion para pasar a la siguiente opcion (cambia el nombre del boton de opcion):

- Nombre lista alfabeticamente (mayusculas antes que minusculas) los nombres.
- Ciudadanos ordena por poblacion.
- Crecimiento urbano ordena por tasa de crecimiento (depende del terreno cubierto por el area urbana y el numero de pasajeros transportado).

- ascendente / descendente invierte el orden de la lista.

Pulsa en un elemento listado en la Lista de Ciudadespara ver mas informacion sobre esa area urbana.
Los elementos listados para cada area urbana incluyen:

nombre asignado al area urbana (puede ser cambiado en el menu Informacion de la Ciudad)..

numero de habitantes de un area urbana, entre parentesis se muestra el incremento de poblacion.

simutrans-124.3/simutrans/text/es/citywindow.txt000066400000000000000000000103451474050137200221370ustar00rootroot00000000000000Ayuda de Estadisticas de Poblacion

Estadisticas de Poblacion

Estadisticas de Poblacion muestra estadistica sobre una area urbana seleccionada (villa, pueblo o ciudad) y se puede usar para cambiar el nombre del area urbana.

Cada arear urbana tiene su Ayuntamiento alrededor del cual crece. El transporte de pasajeros y correo ayuda al crecimiento, los cual supone: carreteras construidas y gestionadas por el jugador servicio publico; aparecen los nuevos edificios y las industrias; y el limite de la ciudad se extiende.

Pulsa en el Ayuntamiento con al herramienta de Exploracion o en una area urbana listada en la Lista de Ciudades para abrir las Estadisticas de Poblacion, las cuales contienen: caja de texto con el nombre; estadisticas; dos mini-mapas; y una grafico del area urbana.

nombre: el nombre asignado al area urbana aparece en una caja de texto en lo alto de la ventana Estadisticas de Poblacion.
Los nombres de las areas urbanas se usan en los nombres por defecto de las Paradas.
Para cambiar el nombre: pulsa en la caja de texto y escribe un nuevo nombre.
{Consejos: Usa [!] para activar la vista del nombre del area urbana, sobre el Ayuntamiento. Lee mas en el archivo readme_citylist.txt (en el directorio ...simutrans/text/) para ayuda en la generacion de nombres para areas urbanas}.

Bajo la caja de texto de nombre , se muestran estadisticas del area urbana:
Tam. ciudad: es el numero de habitantes (poblacion del area urbana). el incremento reciente en la poblacio se muestra entre parentesis.
edificios: numero de edificios en el area urbana.
coordenadas del mapa: indica los limites de la ciudad (cambia a medida que crece el area urbana).

Los contadores se incrementan con el crecimiento del area urbana y decrecen con la construccion de nuevos edificios
Desempleados: contador que determina que tipo de edificio (residencial/comercial/industrial) sera construido.
Sin hogar: contador que determina que tipo de de edificio (residencial/comercial/industrial) sera construido.

mini-mapas del mundo de juego en la ventana Estadisticas de la poblacion idica los destinos de los pasajeros y el correo.
Los destinos se muestran como puntos coloreados segun el mes actual de juego (mini-mapa de la derecha) y el ultimo mes de juego (mini-mapa de la izquierda).El color de los punto de destino da detalles acerca de los pasajeros y el correo:
- amarillo: encontro una ruta y una Parada no abarrotada para comenzar el viaje (se muestra una cara sonriente en la ventana Informacion de la Parada).
- naranja: no encontro ruta a su destino.
- rojo: encontro una ruta pero la parada inicial estaba abarrotada (se muestra una cara triste en la ventana Informacion de la Parada).

Grafico muestra las estadisticas del area urbana.
El eje y es la cantidad, el eje X es el tiempo.
Pulsa en la etiqueta para cambiar la escla de tiempo del eje X:
Años: muestra valores anuales para los ultimos diez años de juego.
Meses: muestra valores mensuales para los ultimos 12 meses de juego

Pulsa en los botones de opciones del grafico para ver informacion en el grafico (el boton se oscurece cuando seleccionas la opcion).
El color de las lineas del grafico corresponde con los colores de los botones de opcion:
Ciudadanos: poblacion.
Crecimiento urbano: cambios en la poblacion (depende la poblacion y los servicios de transporte proveidos para pasajeros y correo).
Recorrido: pasajeros y correo que gestionados a traves de la red de transporte (mostrado como una cara feliz en la ventana Informacion de la Parada)
Pasajeros: Numero total de pasajeros y correo generado en el area urbana.

{Consejos: Las opciones relacionadas con areas urbanas se pueden cambiar en los archivos simuconf.tab y cityrules.tab}.

simutrans-124.3/simutrans/text/es/climates.txt000066400000000000000000000027051474050137200215410ustar00rootroot00000000000000Ayuda de los Controles del Clima

Controles del Clima

Controles del Clima establece las opciones para los aspectos topograficos y meteorologicos del juego

Controles del Clima se abre con el botonCrear un Nuevo Mundo.

Ajusta los parametros con los botones:

Opciones:

Nivel del agua: establece la altura del nivel del mar en el mapa.

Altura: establece la altura maxima del terreno.

Terreno abrupto: establece la irregularidad del terreno; un valor alto crea un terreno mas escarpado.

Opciones de la cota de nieve:

Cota de nieve veraniega: establece la cota de nieve en verano

Cota de nieve invernal: establece la cota de nieve en invierno.

Opciones del clima:

clima desertico: muy poca lluvia y temperaturas extremas

clima tropical: tipico de lugares cercanos al ecuador, altas temperaturas constantes a nivel del mar y suaves mesetas).

clima mediterraneo: clima ligeramente humedo y cambiante

clima templado: se da en areas entre los tropicos y los polos, clima cambiante.

clima artico (tundra): bajas temperaturas, muy cerca de los polos

clima rocoso: cercano al desertico.

simutrans-124.3/simutrans/text/es/color.txt000066400000000000000000000016501474050137200210540ustar00rootroot00000000000000Ayuda sobre Color

Color del Jugador

Color establece el color del jugador.
Los vehiculos, edificios y otros elementos reflejan el color del jugador.

Color se abre desdeOpciones de juego.

Pulsa en uno de los colores para cambiar el color del jugador.
La ventana de Color cambia (no al nuevo color elegido) para indicar que un nuevo color ha sido seleccionado.

El color por defecto es azul claro para el jugador humano.
Algunos elementos no tienen la opcion de color del jugador, y puede que no muestren el color elegido.

{Consejo: Para cambiar el color de los jugadores controlados por la maquina usa laLista de Jugadores o P+ Cambiar de Jugador para seleccionar primero un jugador controlado por la maquina}.

simutrans-124.3/simutrans/text/es/convoi.txt000066400000000000000000000067741474050137200212470ustar00rootroot00000000000000Lista de Vehiculos

Lista de Vehiculos

Lista de Vehiculos muestra informacion y tiene controles para filtrar y listar los diferentes Convoys (un Convoy esta compuesto por un unico vehiculo o una combinacion de varias unidades).

Para abrirlo: pulsa en la herramienta de Lista de Vehiculos en Administracion de Listas o presiona [V]. Lista de Vehiculos tiene cuatro botones de opciones, dos se usan para ordenar los elementos de la lista y los otros dos se usan para aplicar opciones a los elementos seleccionados de la lista.
Los botones de debajo son una lista de Convoys que concuerdan con el criterio usado en las opciones de filtro.
{Consejos: Si no se listan Convoys cambia las opciones de Filtrado.Si los elementos de la lista son parcialmente visibles, entonces ajusta la ventana Lista de Vehiculos o desplaza ls lista usando la barra de desplazamiento.}

Pulsa en los botones de opcion para pasar a la siguiente opcion (cambia el nombre del boton) o abre el menu Opciones de Filtro:

Ordenar por: Dos botones de opcion determinan el orden de los Convoys mostrados en la lista.

- Tipo ordena por tipo de transporte (en orden ascendente de vehiculo de carretera, vehiculo de carretera, vehiculo de via ferrea, barcos y aviones)
- Nombre ordena por nombre asignado, alfanumericamente: mayusculas entes que minusculas (por defecto esto se hace para la primera unidad del un vehiculo comprado o unido para formar un Convoy).
- Ingresos ordena por beneficio (ingresos generados menos costes operativos). - ID interno ordena por un numero ID unico para cada convoy (asignado por defecto cuando un Convoy es comprado o ensamblado por primera vez en un deposito mostrado en la titulo de la ventana de Informacion del Convoy).

- ascendente / descendente invierte el orden de la lista.

Filtro: Dos botones de opcion, enciende/apaga el criterio de selecciona para la lista y los controles de acceso para cambiar los criterios.

- habilitar / deshabilitar pulsa para aplicar los criterios de flitrado para los Convoys en lista.

- Ajustes abre controles para cambiar los criterios de filtrado.

Pulsa en un elemento listado para ver mas informacion acerca de ese Convoy.

Los elementos listados por cada Convoy incluyen:

ID interno: un numero ID unico por convoy (asignado por defecto cuando el Convoy es comprado o ensamblado por primera vez en un deposito y se muestra en el titulo de la ventana deInformacion del Convoy).

nombre que has sido asignado (por defecto se hace cuando el primer vehiculo es comprado o ensamblado).

ingresos muestra los beneficios (ingresos generados menos costes operativos cuando esta en movimiento).

Linea: muestra la Linea asignadae indica si el Convoy esta en un deposito.

graficos muestra el tipo y nivel de carga.

simutrans-124.3/simutrans/text/es/convoi_filter.txt000066400000000000000000000045051474050137200226020ustar00rootroot00000000000000Filtro de la Lista de Vehiculos

Filtro de la Lista de Vehiculos

Filtro de la Lista de Vehiculos tiene opciones que determinan que Convoys, se muestran en la Lista de Vehiculos.

Pulsa en Opciones en la Lista de Vehiculos para abrir el Filtro de la Lista de Vehiculos.

Los botones de Opcion seleccionan los Convoys que apareceran en la Lista de Vehiculos cuando este activada la opcion de Filtro. Solo los Convoys que se ajusten al los criterios seran listados.

Pulsa en el boton cuadrado para establecer los criterios de flitrado (el boton de oscurece cuando es seleccionando):

Filtrar nombres: selecciona los Convoys por el nombre. Para usarlo: pulsa en el boton para seleccionar, despues pulsa en la caja de texto Nombre Filtro y teclea en nombre requerido con exactitud (distingue entre mayusculas y minusculas).

Filtros de tipo : listara los Convoys por tipo de transporte seleccionado. Para usarlo: pulse en el boton seleccionado, despues pulse en el tipo(s) de transporte: autobuses/camiones, trenes, barcos y aviones.

Filtros especiales: selecciona Convoys para listarlos segun los siguientes criterios (pulsa en el boton Filtro Especial, despues pulsa en la opcion eleguida ):
- sin camino - no puede encontrar el camino al proximo destino.
- sin horario - no tiene asignada una ruta.
- sin ingresos - no genera beneficios.
- en el deposito - aquellos que estan en un deposito.
- sin linea - no tiene asignada una Linea.

Filtro de Mercancias: selecciona los Convoys por la capacidad de transportar diferentes mercancias y pasajeros. Pulsa en el boton junto al nombre del elemento(s) seleccionado(s). Usa la barra de desplazamiento para desplazar los elementos en la lista. Entre las opciones se incluyen:
- todo selecciona todos los elementos.
- nada no selecciona ningun elemento.
- inv. invierte la seleccion actual de elementos.

simutrans-124.3/simutrans/text/es/convoidetail.txt000066400000000000000000000037111474050137200224160ustar00rootroot00000000000000Ayuda de Detalles del Convoy

Detalles del Convoy

Detalles del Convoy da mas informacion acerca de un Convoy (un vehiculo solo o una combinacion de unidades) y puede usar para vender rapidamente el Convoy.

Detalles del Convoy se abre desde el boton Detalles en la ventana Informacion del Convoy.
Si todos los elementos no son visibles ajusta la ventana de Detalles o usa la barra de desplazamiento para desplazar los elementos.

En lo alto de la ventana Detalles del Convoy se muestra la siguiente informacion:

Potencia: de Convoy (potencia combinada en el caso de un convoy de varias unidades).

Valor de Venta: el dinero recibido si se vende el Convoy (precio de compra menos un ligera depreciacion).

CUIDADO: Pulsa en el boton Modo Venta para vender el Convoy inmediatamente. No requiere confirmacion de la opracion de venta. El Convoy es eliminado del juego y se añade la cantidad de la venta al balance de jugador .

Detalles del Convoy lista todas la unidades del Convoy.
La informacion listada para todas las unidades de convoy incluyen:
- grafico del vehiculo: un dibujo de la unidad (tambien usado en depositos).
- Fabricado: mes y año de fabricacion, asi como fecha de introduccion si estas jugando con cronologia.
- Valor de Venta: cantidad recibida en caso de venta.
- Potencia: potencia generada (por vehiculos motorizados).
- Friccion: nivel actual de friccion.
- Ingresos maximos: ingresos del vehiculo por tipo de elemento transportado por el Convoy.
- Elementos cargados: cantidad y destino de los elementos actualmente cargados por el vehiculo.

simutrans-124.3/simutrans/text/es/convoiinfo.txt000066400000000000000000000156761474050137200221240ustar00rootroot00000000000000Informacion del Convoy

Informacion del Convoy

Informacion del Convoy muestra informacion sobre un Convoy (un vehiculo individual o una combinacion de varias unidades) usado para transportar pasajeros o mercancias.
Se lista los elementos cargados por un Convoy y tambien tiene controles para acceder a mas detalles y para la venta del Convoy; seguir la trayectoria del Convoy; y cambiar el nombre y la Ruta de un Convoy.

Un convoy esta compuesto por al menos una unidad motorizada (motorised) y un numero cualquiera de vagones/remolques.
Ejemplos de convoys: un grupo de caballos arrastrando un carruaje; una locomotora parte de un tender y vagones; un autobus; una camioneta; un camion con remolque; un tranvia de varios vagones; un barco; un remolcador empujando una barcaza; o un avion.
Los convoys son ensamblados y vendidos en el deposito segun el tipo de transporte.
{Consejos: Un convoy tiene un numero maximo de unidades segun su tipo: trenes, 24; vehiculos de carretera, 4 .}

Pulsa en un convoy con la Herramienta Explorar o pulsa en un convoy listado en la Lista de Vehiculos o en Administracion de Lineas para abrir la ventana Informacion del Convoy
El titulo de la ventana Informacion del Convoy muestra un numero ID y el nombre del (por defecto esto ocurre solo con el primer vehiculo del convoy ensamblado en el deposito).
Informacion del Convoy contiene una caja de texto para el nombre; una mini-vista e informacion acerca del convoy; botones de opcion; y una lista de los elementos cargados actualmente (si todos los elementos no son visibles ajusta la ventana Informacion del Convoy o usa la barra de desplazamiento).

La informacion mostrada en la parte superior de la ventana Informacion del Convoy:

ID interno: un numero ID unico por convoy (asignado por defecto cuando el convoy se compra o ensambla en el deposito).

- nombre: muestra el nombre asignado al convoy (asignado por defecto cuando el convoy se compra o ensambla en el deposito).
Pulsa en la caja de texto del nombre y escribe el nuevo nombre del Convoy para cambiarlo.

- velocidad: muestra la velocidad actual en km/h.
Entre parentesis, el limite maximo de velocidad del Convoy (determinado por la unidad mas lenta en un Convoy).
La barra verde indica la velocidad actual en relacion al limite maximo de velocidad.

- Ingresos: beneficios generados por el vehiculo (ingresos generados restando los costes de operacion) en el año actual de juego.
Entre parentesis, el coste operacional del Convoy en creditos Hajo por cuadricula.

- Peso: peso actual combinado del Convoy y la carga en toneladas.
Entre parentesis, el peso de la carga actual.
La barra verde indica la capacidad usada, para cargar mercancias y pasajeros.
La barra amarilla indica el nivel de Carga (cantidad minima de mercancias y pasajeros necesaria para continuar a la siguiente parada) establecida en los controles de Enrutar.
{Consejos: Para establecer o cambiar el nivel de carga en cada parada, para todos los convoys de una linea, usa la opcion Actualizar linea en la ventana Administracion de lineas o en los Controles del Deposito. Para establecer o cambiar el nivel de carga en cada parada, para un convoy solamente, en una linea, usa el boton Enrutar dentro de la ventana Informacion del Convoy o en los Controles del Deposito.}

- Destino: La proximo Parada o punto de paso en la Ruta del Convoy.
La barra verde indica el progreso hacia la siguiente parada.

- Sirve la linea: indica cualquier Linea asignada al Convoy.

- mini-vista muestra el Convoy.
Pulsa en la mini-vista para centrar la vista del juego en el Convoy.

Pulsa en los botones de la ventana Informacion del Convoy para abrir controles o seleccionar opciones:

Enrutar: abre los controles para cambiar la ruta y la cantidad minima de mercancias y pasajeros necesaria para continuar a la siguiente parada.

Ir a casa: manda el Convoy al deposito apropiado mas cercano. La carga se pierde, pero se recibe un ingreso por transporte al deposito.
En el deposito, el Convoy mantiene su Ruta y la Linea asignada.

sigueme: boton que permite seguir al Convoy (se oscurece si esta activada la opcion).
Para deseleccionar la opcion, pulsa el boton de nuevo o el boton izquierdo en la ventana del Mapa.

Grafica: pulsa el boton para mostrar el grafico (el boton se oscurece cuando el grafico esta visible) en la Informacion del Convoy.
El grafico muestra estadisticas de los ultimos 12 meses (eje x) cuando se selecciona la opcion.
Pulsa en los botones de opcion para ver informacion en el grafico (el boton se oscurece cuando la opcion esta seleccionada).
Las lineas de colores en el grafico corresponden a los colores de los botones:
- Capacidad libre indica el espacio no usado en el Convoy.
- Recorrido indica el numero de mercancias, pasajeros y correo transportado.
- Ingresos indica los ingresos generados por transporte.
- Operacion indica los costes generados por el Convoy en uso.
- Beneficio indica el beneficio recibido por transporte (Ingresos menos Costes de Operacion).

Detalles abre la ventanaDetalles del Convoy que contiene mas informacion y opciones para vender el Convoy.

Ordenar pasajeros/mercancia por: lista elementos actualmente cargados por el Convoy.
La informacion mostrada incluye la cantidad y capacidad del Convoy, tipo de carga, destino final y primera Parada.
El boton de opcion (cambia de nombre con cada seleccion) ordena la carga en grupos de pasajeros, correo y mercancias:
- destino: ordena la carga alfanumericamente, mayusculas antes que minusculas, por nombre del destino final.
- por (detalle): ordena la carga alfanumericamente, mayusculas antes que minusculas, por nombre del destino inicial.
- por (cantidad): ordena la carga por cantidad disponible en el destino intermedio.
- cantidad: ordena la carga por cantidad en orden descendente.

simutrans-124.3/simutrans/text/es/curiositylist_filter.txt000066400000000000000000000156761474050137200242460ustar00rootroot00000000000000Informacion del Convoy

Informacion del Convoy

Informacion del Convoy muestra informacion sobre un Convoy (un vehiculo individual o una combinacion de varias unidades) usado para transportar pasajeros o mercancias.
Se lista los elementos cargados por un Convoy y tambien tiene controles para acceder a mas detalles y para la venta del Convoy; seguir la trayectoria del Convoy; y cambiar el nombre y la Ruta de un Convoy.

Un convoy esta compuesto por al menos una unidad motorizada (motorised) y un numero cualquiera de vagones/remolques.
Ejemplos de convoys: un grupo de caballos arrastrando un carruaje; una locomotora parte de un tender y vagones; un autobus; una camioneta; un camion con remolque; un tranvia de varios vagones; un barco; un remolcador empujando una barcaza; o un avion.
Los convoys son ensamblados y vendidos en el deposito segun el tipo de transporte.
{Consejos: Un convoy tiene un numero maximo de unidades segun su tipo: trenes, 24; vehiculos de carretera, 4 .}

Pulsa en un convoy con la Herramienta Explorar o pulsa en un convoy listado en la Lista de Vehiculos o en Administracion de Lineas para abrir la ventana Informacion del Convoy
El titulo de la ventana Informacion del Convoy muestra un numero ID y el nombre del (por defecto esto ocurre solo con el primer vehiculo del convoy ensamblado en el deposito).
Informacion del Convoy contiene una caja de texto para el nombre; una mini-vista e informacion acerca del convoy; botones de opcion; y una lista de los elementos cargados actualmente (si todos los elementos no son visibles ajusta la ventana Informacion del Convoy o usa la barra de desplazamiento).

La informacion mostrada en la parte superior de la ventana Informacion del Convoy:

ID interno: un numero ID unico por convoy (asignado por defecto cuando el convoy se compra o ensambla en el deposito).

- nombre: muestra el nombre asignado al convoy (asignado por defecto cuando el convoy se compra o ensambla en el deposito).
Pulsa en la caja de texto del nombre y escribe el nuevo nombre del Convoy para cambiarlo.

- velocidad: muestra la velocidad actual en km/h.
Entre parentesis, el limite maximo de velocidad del Convoy (determinado por la unidad mas lenta en un Convoy).
La barra verde indica la velocidad actual en relacion al limite maximo de velocidad.

- Ingresos: beneficios generados por el vehiculo (ingresos generados restando los costes de operacion) en el año actual de juego.
Entre parentesis, el coste operacional del Convoy en creditos Hajo por cuadricula.

- Peso: peso actual combinado del Convoy y la carga en toneladas.
Entre parentesis, el peso de la carga actual.
La barra verde indica la capacidad usada, para cargar mercancias y pasajeros.
La barra amarilla indica el nivel de Carga (cantidad minima de mercancias y pasajeros necesaria para continuar a la siguiente parada) establecida en los controles de Enrutar.
{Consejos: Para establecer o cambiar el nivel de carga en cada parada, para todos los convoys de una linea, usa la opcion Actualizar linea en la ventana Administracion de lineas o en los Controles del Deposito. Para establecer o cambiar el nivel de carga en cada parada, para un convoy solamente, en una linea, usa el boton Enrutar dentro de la ventana Informacion del Convoy o en los Controles del Deposito.}

- Destino: La proximo Parada o punto de paso en la Ruta del Convoy.
La barra verde indica el progreso hacia la siguiente parada.

- Sirve la linea: indica cualquier Linea asignada al Convoy.

- mini-vista muestra el Convoy.
Pulsa en la mini-vista para centrar la vista del juego en el Convoy.

Pulsa en los botones de la ventana Informacion del Convoy para abrir controles o seleccionar opciones:

Enrutar: abre los controles para cambiar la ruta y la cantidad minima de mercancias y pasajeros necesaria para continuar a la siguiente parada.

Ir a casa: manda el Convoy al deposito apropiado mas cercano. La carga se pierde, pero se recibe un ingreso por transporte al deposito.
En el deposito, el Convoy mantiene su Ruta y la Linea asignada.

sigueme: boton que permite seguir al Convoy (se oscurece si esta activada la opcion).
Para deseleccionar la opcion, pulsa el boton de nuevo o el boton izquierdo en la ventana del Mapa.

Grafica: pulsa el boton para mostrar el grafico (el boton se oscurece cuando el grafico esta visible) en la Informacion del Convoy.
El grafico muestra estadisticas de los ultimos 12 meses (eje x) cuando se selecciona la opcion.
Pulsa en los botones de opcion para ver informacion en el grafico (el boton se oscurece cuando la opcion esta seleccionada).
Las lineas de colores en el grafico corresponden a los colores de los botones:
- Capacidad libre indica el espacio no usado en el Convoy.
- Recorrido indica el numero de mercancias, pasajeros y correo transportado.
- Ingresos indica los ingresos generados por transporte.
- Operacion indica los costes generados por el Convoy en uso.
- Beneficio indica el beneficio recibido por transporte (Ingresos menos Costes de Operacion).

Detalles abre la ventanaDetalles del Convoy que contiene mas informacion y opciones para vender el Convoy.

Ordenar pasajeros/mercancia por: lista elementos actualmente cargados por el Convoy.
La informacion mostrada incluye la cantidad y capacidad del Convoy, tipo de carga, destino final y primera Parada.
El boton de opcion (cambia de nombre con cada seleccion) ordena la carga en grupos de pasajeros, correo y mercancias:
- destino: ordena la carga alfanumericamente, mayusculas antes que minusculas, por nombre del destino final.
- por (detalle): ordena la carga alfanumericamente, mayusculas antes que minusculas, por nombre del destino inicial.
- por (cantidad): ordena la carga por cantidad disponible en el destino intermedio.
- cantidad: ordena la carga por cantidad en orden descendente.

simutrans-124.3/simutrans/text/es/depot.txt000066400000000000000000000177551474050137200210660ustar00rootroot00000000000000Cochera

Controles de Cochera

Las cochera se usan para comprar y gestionar vehiculos. Los diferentes tipos de transporte tienen su propia cochera. Las cocheras solo muestran los vehiculos electricos si estan sobre una via electrificada.
Si estan jugando con cronologia, a medida que el tiempo pase en Simutrans apareceran mas vehiculos.

Las herramientas para construir los distintos tipos de cochera estan disponibles en la barra de herramientas de construccion de cada tipo de transporte: Cochera ferroviaria; Cochera de Monorrail; Cochera de Tranvia; Deposito de carretera; Astillero ; y Hangar.

Pulsa en un deposito con la Herramienta de Exploracion para abrir Los controles de la Cochera que te dara informacion acerca de la compra y gestion de Convoys (un vehiculo operativo o una combinacion de varias unidades).
La barra de Titulo de la ventana Controles de Cochera indica el tipo de transportes que gestiona dicha cochera.

Controles de Cochera puede cambiar de tamaño (pulsa en la flecha hacia abajo en la barra de titulo de la ventana para volver al tamaño original).
Pulsa en las flechas hacia izquierda/derecha en la barra de titulo para pasar a la siguiente cochera que gestione el mismo tipo de vehiculo (centra la vista del juego en esa cochera).

En la parte superior de la ventana Controles de Cochera se muestra el numero de Convoys en la cochera, el nombre del Convoy y la Linea.

Nombre del Convoy: pulsa en los botones de flechas izquierda/derecha para pasar de un Convoy a otro en la cochera.
Para cambiar el nombre del Convoy: pulsa en la caja de texto e introduce un nuevo nombre (por defecto esto se hace para el primera unidad comprada o añadida para un nuevo Convoy).

Nombre de Linea: pulsa en los botones de flechas izquierda/derecha para seleccionar las lineas por tipo de transporte o pulsa en la caja de texto para abrir una lista de Lineas.
Para cambiar el nombre de la Linea: pulsa en la caja de texto e introduce un nuevo nombre. (por defecto se le asigna uno cuando se crea una Linea).

Grafico del convoy debajo de las cajas de texto de los nombres del Convoy y la Linea, se muestra el grafico del Convoy seleccionado.
Situa el raton sobre el grafico para ver los detalles acerca del vehiculo (se muestran en la parte inferior de la ventana Controles de Cochera).
Pulsa en el grafico del convoy o en alguna de las unidades para eliminarlo del mismo y almacenarlo en la cochera.

Debajo del grafico se muestra el numero de unidades de Convoy seleccionado, longitud de cuadriculas del Convoy (debe caber en una Parada del tamaño adecuado para carga y descargar pasajeros y mercancia), y la linea asignada.

Los botones de opcion (pulsa para usar) de Controles de Cochera incluyen:

Arrancar: envia el Convoy seleccionado fuera del deposito si este ultimo puede encontrar una ruta.

Enrutar: abre los controles para cambiar la ruta y la cantidad de elementos que un Convoy puede cargar en una Parada.

Desenganchar: almacena las unidades de Convoy seleccionado.

Vender: vende el Convoy actual, el balance aumente con la cantidad de Valor de Reventa.

Nueva Linea: abre los controles para definir una Ruta (una ruta y una minima cantidad de elementos que el Convoy puede cargar en una Parada), que pueda ser usado por varios Convoys.

Aplicar Linea: asigna la Linea mostrada en la caja de texto de linea en la parte superior de la ventana Controles de Cochera al Convoy seleccionado.

Actualizar Linea: abre los controles para cambiar la Ruta (una ruta y una minima cantidad de elementos que el Convoy puede cargar en una Parada) de la linea seleccionada.

Copiar Vehiculo: compra y añade otro convoy con la misma composicion, Ruta y Linea que el convoy seleccionado.

Debajo de los botones de opcion se muestran graficos de los vehiculos disponibles para comprar.
graficos de los vehiculos: los vehiculos se dividen en categorias, los cuales se pueden ver pulsando en las distintas pestañas. Las pestañas dividen los vehiculos en los siguientes grupos: vehiculos para pasajeros y correo, otros vehiculos (motorizados), y otros trailers y carruajes.
Un numero blanco sobre el grafico del vehiculo indica la cantidad de unidades almacenadas si algun Convoy ha sido desensamblado. Las unidades almacenadas se pueden vender o usarse en un nuevo Convoy.

Situa el cursor sobre el grafico del vehiculo para ver informacion acerca del vehiculo:
Nombre: y entre parentesis el tipo de motor usado.
Coste: precio de venta y entre parentesis el coste de operacion por kilometro
Potencia: potencia del motor y velocidad maxima para vehiculos motorizados.
Capacidad: cantidad y categoria de mercancia que puede llevar el vehiculo.
Peso: en toneladas.
Velocidad maxima: para vehiculos no motorizados.
Fecha intro: fecha en que estara disponible el vehiculo si esta activada la cronologia.
Fecha de retirada: fecha en que el vehiculo se vuelve obsoleto.
Construido por: creador del vehiculo para Simutrans.
Marcha: ratio de potencia.
Valor de Venta: cantidad de dinero recibida por la venta de un vehiculo previamente comprado.

Pulsa en los graficos de vehiculos debajo de las pestañas para comprar o vender un vehiculo dependiendo de la opcion del boton de opciones situado en la parte inferior derecha de la ventana de Controles de cochera. El boton de opcion tiene tres modos:

Añadir: compra un vehiculo y lo añade al Convoy seleccionado, o crea un nuevo Convoy.

Poner al frente: compra un vehiculo y lo añade el la parte frontal del convoy actual, o crea un nuevo Convoy.

Modo Venta: vende todos los vehiculos almacenados.

Barras de colores bajo los vehiculos indica que vehiculos y en que orden pueden ser añadidos a otros, para formar un Convoy operativo (las barras de color pueden cambiar con diferentes opciones de los vehiculos).
Los coloures indican:
- verde: el vehiculo puede ser usado.
- rojo: el vehiculo no puede ser usado
- amarillo: otro vehiculo debe ser puesto al frente o al final para crear un Convoy operativo.
- azul: el vehiculo se puede usar pero esta obsoleto.
{Consejos: un Convoy es operativo, si muestra barras verdes en todas las unidades de convoy; si existe alguna unidad con una barra amarilla necesitaras algun vehiculo que has olvidado.}

Mostrar obsoletos: si estas jugando con cronologia, el boton cuadrado mostrara (pulsa para usar) los vehiculos retirados.

simutrans-124.3/simutrans/text/es/display.txt000066400000000000000000000055561474050137200214140ustar00rootroot00000000000000Ayuda de Opciones de Pantalla

Opciones de Pantalla

Pantalla tiene controles acerca de la apariencia del juego; y da informaccion acerca del rendimiento del ordenador.

Pulsa en el boton Pantalla en el menu Opciones de Juego para abrir Opciones de Pantalla.

Pulsa en los botones para seleccionar las distintas opciones (el boton se oscurece cuando seleccionas la opcion), o usa los botones de flechas para ajustar las opciones:

Usar modo dia y noche: vista nocturna del juego.

Luminosidad:ajusta el brillo de la imagen; numeros negativos para oscurecer; valores muy altos o muy bajos pueden dar problemas; usa [+] para incrementar el valor sobre 0.

Invertir desplazamiento: invierte la direccion de desplazamiento en la Ventana de juego.

Velocidad de desplazamiento: establece la velocidad de desplazamiento de la Ventana de Juego.

Peatones en ciudades: muestra los peatones que aparecen en las areas urbanas.

Pedestrians en paradas: muestra los peatones que aparecen cuando un vehiculo llega a una Parada.

Densidad de trafico: establece el numero de vehiculos privador en las areas urbanas.
El numero de nuevos vehiculos priados que apareccen en las areas urbanas en crecimiento depende del tamaño y la densidad de trafico. Los valores altos crean mas trafico, el 0 no genera nada.

{Consejos: Se pueden cambiar mas opciones y valores en el archivo simuconf.tab}.


Informacion de Pantalla:

Debajo de estas opciones , se muestra informacion acerca del rendimiento del ordenador durante la ejecucion del juego Simutrans.
Si los numeros (normalmente en blanco) estan en rojo o amarillo, tendras que cambiar los parametros.
Cambios en el ritmo en el que pasa el tiempo en el juego, T, (usando el icono Acelerar >> en la parte superior de la pantalla, o [,]/ [.]) pueden cambiar el color de los numeros.

Frame Time: La primera cifra es el tiempo entre frames; la segunda es el tiempo exacto entre frames.

Inactivo: Cuando esta por debajo de 0, el ordendor tiene capacidad para ejecutar mas programas.

FPS: Valores altos significan animaciones mas suaves. Si los numeros estan en rojo, el ordenador es demasiado lento para los parametros actuales (intenta reducir la resolucion de la pantalla del juego).

Sim: Si esta en numeros rojos, el ordenador es demasiado lento para los parametros actuales - intentalo con un mapa de menor dimension con menos ciudades.

simutrans-124.3/simutrans/text/es/edittools.txt000066400000000000000000000143421474050137200217460ustar00rootroot00000000000000Ayuda de Herramientas de edicion de mapa

Herramientas de edicion de mapa

Herramientas de edicion de mapa permite personalizar el terreno de la partida actual.
Las herramientas pueden: cambiar poblaciones de las ciudades; crear carreteras urbanas, atracciones turisticas, centrales energeticas e industrias; la opcion Eliminar para jugar como otro jugador; y tambien para avanzar un año en la cronologia del juego.

La barra de herramientas se abre cuando juegas como el jugador servicio publico, que se puede seleccionar desde el menu Jugadores o el boton P+ en el menu Herramientas especiales de construccion(tambien pulsando la tecla [P]). La barra de herramientas continua abierta incluso cuando usas de nuevo la opcion cambiar de jugador.
Pasa el raton sobre la opcion (despues de abrir el menu o pulsando en la barra de herramienta) para ver el nombre y demas informacion de varias opciones-herramientas.

Las herramientas-opciones incluyen, de izquierda a derecha:

Ampliar ciudad: herramienta que incrementa la poblacion de una ciudad en 100 habitantes, construyendo nuevas carreteras y edificios si es necesario.
Para usarla: pulsa en la herramientas para seleccionar, el cursor cambiara a una flecha hacia arriba, y despues pulsa en una ciudad.

Reducir ciudad: herrramienta que reduce la poblacion de una ciudad en 100 habitantes. Las ciudades solo creceran si los niveles de Sin hogar y Desempleados aumentan.
Para usarla: pulsa en la herramientas para seleccionar, el cursor cambiara a una flecha hacia abajo, y despues pulsa en una ciudad.

Carretera urbana: herramienta que construye una carretera urbana entre dos puntos, y que como jugador servicio publico todo jugador deberia usar. Las carreteras urbanas no pueden ser construidas en areas ocupadas por otros edificios, y no encontraran un camino en terreno escarpado, agua y obstrucciones. La carretera urbana construida entre puntos, puede usar carreteras existentes en su camino.
Situa el cursor sobre la herramienta-opcion (despues de abrir o pulsando en la barra de herramientas) para ver el nombre, costes de construccion y mantenimiento para el jugador servicio publico y limite de velocidad maxima. Para construir una carretera urbana: pulsa en la herramienta parar seleccionar (el cursor cambiara de forma), despues pulsa en la vista del juego para marcar el punto de inicio (mostrara una bulldozer y las coordenadas en la parte derecha de la barra inferior de la pantalla), y finalmente pulsa en el terreno para el punto final.
{Consejos: Los diferentes tipos de carreteras se puede conectar. Usa los puentes y tuneles para conectar las carreteras a traves de terreno escarpado o para evitar obstaculos. Usa las Herramientas del Terreno para cambiar el terreno, para crear caminos para carreteras. Usa la herramienta Eliminar para eliminar carreteras urbanas y algunos obstaculos. Usa la tecla [Ctrl] al mismo tiempo para habilitar funciones extra.}

Construir atracciones turisticas aleatorias: herramienta para construir una atraccion turistica que los pasajeros querran visitar. Las diferentes atracciones generan tambien diferentes cantidades de pasajeros y correo. El tipo de atraccion construida es aleatorio y solo aparece si existe el suficiente espacio libre de obstaculos.
Para construir una atraccion: pulsa en la herramienta para seleccionar (el cursor cambiara de forma, punto rojo en circulo amarillo), despues pulsa en la posicion deseada del terreno.
{Consejos: Usa la herramienta Eliminar siendo jugador servicio publico para eliminar atracciones turisticas. Usa la herramienta Eliminar o las herramientas del Terreno para crear espacios adecuados para las atracciones.}

Construir nueva central electrica: herramienta que construye una central electrica (y sus posibles proveedores). El tipo de central electrica construida es aleatorio y solo aparece si existe el suficiente espacio libre de obstaculos..
Para construir una central electrica: pulsa en la herramienta o pulsa la tecla [I] para seleccionar (el cursor cambiara de forma, punto rojo en circulo amarillo), despues pulsa en la posicion deseada en el terreno.
{Consejos: Usa la herramienta Eliminar siendo jugador servicio publico para eliminar centrales electrica. Usa la herramienta Eliminar o las herramientas del Terreno para crear espacios adecuados para las centrales electricas.}

Construir un nuevo mercado en la ciudad mas cercana: herramienta que construye un consumidor final de mercancias en una ciudad (y los posibles proveedores, no necesariamente en la ciudad). El tipo de industria construida es aleatorio y solo aparece si existe suficiente espacio libre de obstaculos.
Para usarlo: pulsa en la herramienta para seleccionar (el cursor cambiara de forma, punto rojo en circulo amarillo), despues pulsa en una ciudad para construir un consumidor final.

{Consejos: Usa la herramienta Eliminar jugando como jugador servicio publico para eliminar consumidores. Usa la herramienta eliminar o las herramientas del terreno para crear espacios libres de obstaculos para las industrias.}

Impedir cambio de jugador: herramienta que elimina la opcion para jugar como otro jugador y abre el menu Herramientas de edicion de mapa.
Para usarlo: pulsa en la herramienta seleccionada (el cursor cambia a un candado), y despues pulsa en cualquier parte. No requiere confirmacion.

Avanzar cronologia un año: avanza el tiempo en un año. Si estas jugando con cronologia, a medida que pasa el tiempo apareceran mas transportes y opciones de construcion, y los vehiculos mas lentos que no sean rentables desapareceran (ya que los ingresos se calculan a partir de la velocidad media del vehiculo) .
Para usarlo: pulsa en la herramienta. No requiere confirmacion (la fecha cambia en la parte izquierda de la barra en la parte inferior de la pantalla).

simutrans-124.3/simutrans/text/es/factorylist_filter.txt000066400000000000000000000053041474050137200236460ustar00rootroot00000000000000Lista de Fabricas/Industrias

Lista de Fabricas/Industrias

Lista de Fabricas/Industrias muestra informacion acerca de todas las fabricas (suministradoras y consumidoras de mercancias) en la parida actual.

Para abrir la Lista de Fabricas/Industrias: pulsa en la herramienta de Lista de Fabricas en el icono Administracion de listas.
{Consejos: Si no todos los elementos son visibles, entonces ajusta la ventana de Lista de Fabricas o desplaza la lista mediante la lista de desplazamiento.}

Ordenado por: tiene opciones que determinan el orden de las Fabricas listadas.
Pulsa en los botones para para pasar a la siguiente opcion (cambia en nombre del boton de opcion):

- Nombre de fabrica ordena alfabeticamente por nombre.
- Suministro ordena por capacidad de almacenamiento del suministro.
- Produccion ordena por capacidad de almacenamiento de la produccion.
- Produccion ordena por produccion.
- Rating ordena por el color de la barra de estado (mira mas abajo).
- Potencia ordena por electricidad suministrada.

- ascendente / descendente invierte el orden de la lista.

Pulsa en un elemento listado en la Lista de Fabricas para ver mas informacion acerca de esa Fabrica.
Los elementos listado para cada Industria incluyen:

barra de estado en color: el color indica la operatibilidad de la Industria (tambien se usa en Informacion de la Industria):
- blanco: no requiere mercancias.
- amarillo: conectada por transporte, pero la cadena de suministros tiene un pobre suministro.
- verde: en estado optimo.
- naranja: operativa pero es necesita mejoras.
- rojo: operativa pero parte de la cadena de suministros tiene exceso de suministro.

El icono rojo de un rayo se muestra si la Fabrica requiere suministro electrico mediante una subestacion transformadora.

Nombre de la Fabrica: nombre de la industria.

Entre parentesis 3 valores que representan:
Consumo actual: cantidad de mercancias almacenadas y listas para ser procesadas.
Produccion actual: cantidad de mercancias preparadas para el transporte.
Produccion total: indice de produccion de la fabrica (cantidad maxima de mercancias producidas por mes/dia)

simutrans-124.3/simutrans/text/es/finances.txt000066400000000000000000000065611474050137200215320ustar00rootroot00000000000000Ayuda de Finanzas

Finanzas

Finanzas provee de un vista general del estado financiero del jugador.

Pulsa en el icono del dolar en la parte superior, o presiona [f], o pulsa en el nombre del jugador en Jugadores, para abrir Finanzas.

Los valores (en Creditos Hajo ) estan listados para el año actual y los siguientes.
Este año: año actual en juego.
Ultimos años: años previos de juego.

Los valores anuales pueden mostrarse en un grafico de los ultimos diez años, o de los ultimos doce meses del año actual en juego.
Pulsa en el boton con el nombre de valor para mostrar los detalles en el grafico: El eje Y es la cantidad, el eje X es el tiempo.
Pulsa en el pestaña del grafico para cambiar la escala del eje X:
Años: muestra los valores anuales de los ultimos 10 años de juego.
Meses: muestra los valores mensuales de los 12 ultimos meses de juego

Entre los valores (pulsa en los botones con los nombres para ver los detalles), se incluyen:

Ingresos - ingresos totales del transporte de pasajeros, mercancias, correo y eneriga electrica.

Operacion - coste total generado por todos los Convoys en movimiento.
{Consejos: El coste operacional por kilometro se puede ver en el deposito y en la venta Informacion del Convoy.}

Mantenimiento - coste total del mantenimiento de la red de transporte.
{Consejos: El coste mensual de mantenimiento de la red (Mantenimiento (mensual) se muestra a la derecha en la ventana Finanzas) es deducido el final del mes.}

Beneficio por Operaciones - beneficio por transporte de mercancias, pasajeros, correo y energia electrica (Ingresos menos Costes de Operacion y Mantenimiento).

Nuevos Vehiculos - creditos gastados e ingresados por la venta y compra de vehiculos.

Construccion - coste total generado por la construccion de redes de transporte, modificaciones del terreno, lineas de transporte de energia electrica, y por el uso de la herramienta Eliminar.

Beneficio bruto - ingresos totales menos los costes totales.

Efectivo - los creditos actualmente disponibles para construir y comprar vehiculos (se muestra en el centro de la parte inferior de la pantalla.
{Consejos: Si el jugador humano esta en numeros rojos (balance negativo) durante tres meses consecutivos, el jugador se declara en bancarrota y el juego termina}.

Activos - El valor de todos los vehiculos del jugador al final del ultimo mes.
{Consejos: cada mes el valor de los vehiculos en uso desciende ligeramente, el valor actual se puede ver en Detalles del Convoy o cuando el vehiculo esta en un deposito.}

Valor Neto - Balance mas Activos.

Margen - porcentaje entre el Beneficio por operacion y los Ingresos.

Recorrido - total de mercancias, pasajeros y correo transportados.

{Consejos: Algunos costes, tales como la cantidad inicial y las finazas se pueden cambiar a traves del archivo simuconf.tab}

simutrans-124.3/simutrans/text/es/general.txt000066400000000000000000000066521474050137200213620ustar00rootroot00000000000000Ayuda de Simutrans

Ayuda General

- Bienvenido
- Interfaz del Juego/Ventanas
- Ayuda de Raton (en construccion)
- Ayuda de Teclado

Opciones de Juego
- Idioma
- Color del Jugador
- Opciones de Pantalla
- Sonido y Musica
- Jugadores
- Cargar Juego
- Guardar Juego
- Nuevo Juego
- - Controles del Clima
- - Cargar Topografia

Menu Principal
- Opciones de Juego
- Mapa
- Herramienta de Exploracion
- Herramientas de Modelado del Terreno
- Herramientas de Ferrocarriles/Vias
- Herramientas de Monorail
- Herramientas de Tranvia
- Herramientas de Carreteras
- Herramientas de Puertos
- Herramientas de Aeropuertos
- Herramientas Especiales de Construction
- Herramientas de Edicion del Mapa
- Herramienta Eliminar

Menus de Administracion
- Administracion de Lineas
- Listas
- - Lista de Paradas/Estaciones
- - - Filtro para Paradas/Estaciones
- - Lista de Vehiculos
- - - Filtro de Vehiculos
- - Lista de Ciudades
- - Lista de Mercancias
- - Lista de Industrias
- - Lista de Atracciones
- Buzon
- Finanzas

Otras Opciones
- Guardar Captura de Pantalla
- Pausa
- Acelerar
- Ayuda

Otros Menus
-Controles de las Cocheras
-Controles de Enrutar
- Informacion de las Paradas
- - Detalles de las Paradas
- Informacion de los Convoys/Vehiculos
- - Detalles de los Convoys/Vehiculos
- Informacion de las Ciudades
- Informacion de las Industrias

Si nada de esto te ayuda, prueba en
http://docs.simutrans.com
http://wiki.simutrans.com
http://simutrans-tips.com
http://forum.simutrans.com

simutrans-124.3/simutrans/text/es/goods_filter.txt000066400000000000000000000073331474050137200224220ustar00rootroot00000000000000Lista de Mercancias

Lista de Mercancias

Lista de Mercancias contiene informacion de los diferentes elementos que pueden ser transportados en la partida, y tiene controles para cambiar los ingresos recibidos del transporte.

Para abrirlo: pulsa en la herramienta Lista de Mercancias en el icono de la Administracion de Listas o presiona la tecla [G].

La lista de elementos disponibles para transportar en la partida indica: remuneracion recibida, % bonus por velocidad, categoria de la mercancia y tonelaje.
{Consejos: Si no se puedes ver todos los elementos de la lista, entonces ajusta la ventana de la Lista de Mercancias o desplaza la lista usando la barra de desplazamiento.}

Bonus por velocidad: muestra la velocidad necesaria requerida para los distintos tipos de mercancias, a la que un Convoy es capaz de transportar cosas, para recibir un ingreso extra por transporte repido de mercancias y pasajeros (en algunos casos se puede penalizar por demasiada lentitud).
Si estas jugando con cronologia, a medida que pasa el tiempo en Simutrans, la velocidad necesaria requerida cambia con la introduccion de nuevos vehiculos.
Los botones de flechas ajustan los ingresos recibidos y la velocidad a la que debe ir un Convoy para recibir bonus por velocidad (o incurrir en una penalizacion por demasiada lentitud).

Ordenado por: tiene opciones que determinan el orden de los elementos mostrados en la lista.
Pulsa en los botones de opcion para pasar de una opcion a otra (el nombre del boton cambiara):

- sin ordenar ordenado aleatoriamente.
- por nombre ordenado alfabeticamente.
- por ingresos ordenado por los ingresos recibidos por transporte de una unidad por cuadricula del juego.
- por bonus ordena por % de bonus de velocidad (% de ingreso extra si el Convoy usado es capaz de ir a la velocidad necesaria requerida para tener derecho a dicho bonus).

- ascendente / descendente invierte el orden de la lista.

Los detalles listados para cada elemento incluyen:

cuadrado de color es el mismo color mostrado en la barra de estado de color de mercancias, en cada Parada para indicar la cantidad de elementos que esperan a ser transportados.
{Consejos: Usa [!] para mostrar la barra de colores de mercancias sobre una Parada.}

ingresos son los ingresos recibidos por transportar una unidad a una distancia de una cuadricula del juego.
{Consejos: Usa el Modo Principiante para incrementar los ingresos un 150% (puedes cambiarlo tambien en el archivo simuconf.tab)}

% bonus es el % de ingresos extra recibidos si el Convoy usado es capaz de ir a la velocidad necesaria requerida para tener derecho a bonus (en algunos casos se puede incurrir en una penalizacion si el vehiculo es demasiado lento).
La formula de calculo para los ingresos es compleja y considera la maxima velocidad del Convoy junto con la velocidad media de los vehiculos disponibles,y no la velocidad del vehiculo mostrada durante la partida.

tipo de mercancia indica el tipo de vehiculo necesario para el transporte. La carga especial requiere vehiculos especificos.
{Consejos: La capacidad de los vehiculos muestra que elementos puede transportar dicho vehiculo}.

peso se muestra el peso de una unidad en kilogramos.

simutrans-124.3/simutrans/text/es/haltlist.txt000066400000000000000000000102471474050137200215640ustar00rootroot00000000000000Lista de Estaciones

Lista de Estaciones

Lista de Estaciones muestra informacion y tiene controles para filtrar y listar las diferentes Paradas (pero no se incluyen las paradas de vehiculos maritimos), donde los vehiculos cargan y descargan pasajeros y mercancias.

Para abrirla: pulsa en la herramienta de Lista de Estaciones dentro de Administracion de Listas. Lista de Estaciones tiene cuatro botones de opcion, dos usados para ordenar elementos de la lista y otros dos para aplicar opciones a los elementos seleccionados para mostrar en la lista. Los botones de debajo hay una lista de Paradas que cumplen los criterios establecidos por las opciones de filtrado.
{Consejos: Si no se ha listado ninguna Parada cambia las opciones de Filtrado. Si no se ven todos los elementos de la lista, entonces ajusta la ventana de Lista de Estaciones o desplaza la lista con la barra de desplazamiento.}

Pulsa en los botones para pasar de una opcion a otra (cambiara el nombre del boton) o abre los controles de Opciones de Filtro:

Ordenado por: dos botones de opcion que determinan el orden de las Paradas mostradas en la lista:

- Tipo ordena por tipo de vehiculo.
- sin orden ordena en orden aleatorio.
- Nombre ordena alfanumericamente (mayusculas antes que minusculas) por el nombre asignado.
- esperando ordena por cantidad de mercancias y pasajeros presentes en relacion a la capacidad disponible y el servicio de transporte proveido.

- ascendente / descendente invierte el orden de la lista.

Filtrar: dos botones de opcion, activa/desactiva los criterios de seleccion para listar y controles de acceso para cambiar los criterios.

- activar / disactivar pulsa para aplicar los criterios de filtrado.

- Opciones pulsa para abrir los controles para cambiar los criterios de filtrado

Pulsa en un elemento listado en Lista de Estaciones para ver mas informacion acerca de esa Parada.
Los elementos listados para cada Parada incluyen:

barra de color de estado: los colores indican la operatibilidad de una Parada en relacion con como de atestada esta. La barra de color se usa tambien en Informacion de la Parada y Administracion de Listas y es el mismo color mostrado en la barra de color mostrada sobre la Parada:
- amarillo: sin servicio de transporte.
- verde: no se necesitan mejoras.
- naranja: es posible que necesite mejoras.
- rojo: es recomendable hacer mejoras.
{Consejos: Usa [!] para mostrar la barra de color sobre la Parada.}

nombre que le ha sido asignado {Consejos: Tienes la opcion de asignar numeros en el nombre de la Parada a traves del archivo simuconf.tab}.

icono de vehiculo indica que tipos de vehiculos se pueden usar en la Parada (tambien se usa en Informacion de la Parada y en Administracion de Listas).
Los iconos incluyen: bus (para vehiculos de pasajeros por carretera), camion (para vehiculos de mercancias por carretera), tren, barco y avion. Tranvias se indica mediante el icono de bus o tren en el tipo de Parada.

icono(s) de carga indica que elementos (pasajeros, mercancias y/o correo) puede gestionar la Parada (tambien se usa en Informacion de la Parada y en Administracion de Listas).
{Consejos: construyendo las extensiones apropiadas, cambiara la categoria de los elementos que puede gestionar la parada. Las Oficinas Postales pueden construirse junto a Paradas para permitir la gestion de correo}.

esperando detalles de las diferentes mercancias y pasajeros en la Parada.

simutrans-124.3/simutrans/text/es/haltlist_filter.txt000066400000000000000000000050071474050137200231270ustar00rootroot00000000000000Filtro de la Lista de Estaciones

Filtro de la Lista de Estaciones

Filtro de la Lista de Estaciones tiene opciones que determinan que Paradas (pero no se incluyen las paradas de barcos), donde los vehiculos cargan y descargan pasajeros, se muestran en la Lista de Estaciones .

Pulsa en Opciones en la Lista de Estaciones para abrir el Filtro de la Lista de Estaciones.

Los botones de opcion seleccionan Paradas de la Lista de Estaciones cuando la opcion del filtro esta activa. Solo se muestran las Paradas que cumplen dichos criterios.

Pulsa en un boton para seleccionar/deseleccionar criterios de filtrado (el boton se oscurece cuando lo seleccionas):

Filtrar nombres: selecciona las Paradas por nombre. Para usarlo: pulsa en el boton para seleccionar, pulsa en la caja de texto y escribe el nombre exacto requerido (distingue entre mayusculas y minusculas).

Filtrar tipos: listara las Paradas que tengan al menos uno de los elementos seleccionados. Para usarlo: pulsa en los botones. (Las paradas de barcos no aparecen en la Lista de Paradas)

Filtro Especial :
- desbordamiento no esta en uso.
- sin conexion selecciona las Paradas sin servicio de transporte.

Tipo de carga: hace referencia a las Paradas que son el destino final de los elementos seleccionados. Pulsa en el boton junto al nombre para seleccionar los elementos. Usa la barra de desplazamiento para desplazar los elementos de la lista. Entre la opciones se incluyen:
- todo selecciona todos los elementos.
- nada no selecciona ningun elemento.
- inv. invierte la seleccion actual de elementos.

Produccion: hace referencia a las Paradas que son el origen de los elementos seleccionados. Pulsa en el boton junto al nombre para seleccionar los elementos. Usa la barra de desplazamiento para desplazar los elementos de la lista. Entre la opciones se incluyen:
- todo selecciona todos los elementos.
- nada no selecciona ningun elemento.
- inv. invierte la seleccion actual de elementos.

simutrans-124.3/simutrans/text/es/industry_info.txt000066400000000000000000000131321474050137200226300ustar00rootroot00000000000000Informacion de Industrias

Informacion de Industrias

Informacion de Industrias muestra detalles acerca de la industria seleccionada (un proveedor o consumindor de mercancias) y permite que la vista del juego se posicione en determinados lugares.

Los proveedores y consumidores de mercancias estan conectados para crear una Cadena Industrial de Suministro que termina en un consumidor final. Alguna industria es a la vez consumidor y proveedor, situandose en la mitad de la Cadena Industrial de Suministro. Si no estas jugando en beginners mode, la industria dejara de suministrar si el consumidor esta saturada de mercancias.
Las industrias son un destino y origen para pasajeros y correo. Los vehiculos carga y descargan mercancias y pasajeros en una industria mediante las Paradas si el area de influencia de la parada cubre una porcion del edificio de la industria y si la Parada puede manejar la mercancia de la industria. {Consejos: Paradas maritimas/Plataformas petroliferas/Granja de peces/areas de influencia/petroleo/correo/pasajeros/ no son listados en la lista de estaciones}

El numero inicial de cadenas industriales de suministro se puede establecer en la ventana Crear un nuevo Mundo. A medida que las ciudades crecen, pueden aparecen nuevas industrias. Una nueva industria aparece cada vez que la poblacion de una ciudad dobla su poblacion en 2000 habitantes.
{Consejos: Añade industrias a una ciudad usando Construir un nuevo mercado en la ciudad mas cercan en en menu Herramientas especiales de cosntruccion. Cambia cuando las nuevas industrias son generadas en el archivo cityrules.tab (industry_increase_every = 0 no genera nuevas industrias )}.

Pulsa en una industria con la herramienta Explorar o en una industria listada en la Lista de Fabricas para abrir la ventana de Informacion de la Fabrica.
Usa la barra de desplazamiento para desplazar los elementos si no todos son visibles.

El nombre de la Industria seleccionada se muestra en el titulo de la ventana de Informacion de la Fabrica<.
Se muestra otra informacion y opciones, incluyendo:

Produccion: cantidad maxima de mercancias que suministrara la industria (si es un proveedor) o consumira (si es un consumidor final) en unidades por mes/dia.
{Consejos: Añadiendo subestaciones transformadoras y suministro electrico a una industria incrementa la cantidad de mercancias producidas/consumidas}.

Representacion de la Industria muestra una vista del edificio de la industria. Pulsa en el grafico para centrar la vista de juego en el edificio.

barra de color de estado bajo la representacion indica el estado operativo de la industria (tambien usado en la Lista de Fabricas):
- blanco: no requiere entrada de mercancias.
- amarillo: conectado por transporte, pero la cadena industrial de suministro tiene un suministro pobre.
- verda: en estado optimo.
- naranja: operativa pero es posible mejorar.
- rojo: operativo pero la cadena industrial de suministro tiene un exceso de suministro.

Consumidores: lista destinos en la Cadena Industrial de suministros para las mercancias producidas por la industria seleccionada.
Las industrias destino y sus coordenadas en el mapa son listadas junto a botones de flecha. Pulsa en el boton de la flecha para mover la vista del juego a ese destino.

Suministradores: muestra el origen de las mercancias en la Cadena Industrial de suministros, requerida por la industria seleccionada.
Las industrias suministradoras y sus coordenadas del mapa se listan junto a botones de flecha. Pulsa en el boton de la flecha para mover la vista al suministrador.

Trabajadores de : muestra en ciudades cercanas viven los empleados. Los pasajeros y correo de estas ciudades necesitaran ser llevados a la industria seleccionada.
Las ciudades y sus coordenadas del mapa se listan junto a botones de flecha. Pulsa en el boton de la flecha para mover la vista al suministrador.

Nivel de pasajeros: es la popularidad relativa como destino de pasajeros.
Correo: es la popularidad relativa como destino de correo.
{Consejos: unicamente una cuadricula de la industria necesita estar en el area de influencia de la parada, para dar un servicio optimo para pasajeros y correo}.

Produccion: da detalles de la produccion de la Industria.
La informacion mostrada incluye: nombre del elemento; cantidad actualmente almacenada en relacion a la maxima capacidad de almacenamiento por elemento; categoria de mercancia; y nivel de porcentaje de produccion comparada con el suministro.

Consumo: da detalles del consumo de la industria.
La informacion mostrada incluye: nombre del elemento; cantidad actualmente almacenada en relacion a la maxima capacidad de almacenamiento por elemento; categoria de mercancia; y nivel de porcentaje de produccion comparada con el consumo.

Paradas que sirven a la industria son listadas en la parte inferior de la ventana Informacion de la Fabrica.

simutrans-124.3/simutrans/text/es/inspection_tool.txt000066400000000000000000000144231474050137200231500ustar00rootroot00000000000000Herramienta de Exploracion

Herramienta de Exploracion

Exploracion se usa para abrir ventanas de dialogo que dan informacion u opciones de control para distintos elementos.

Pulsando en el icono de la lupa en la barra de herramientas, en la parte superior de la pantalla, o pulsando [a] para abrir Exploracion (cambia el cursor a una lupa).

Para usar la herramienta de Exploracion: posiciona el cursor de la lupa en el sitio deseado y pulsa para abrir la ventana de dialogo. Si hay mas de un elemento en ese sitio, vuelve a pulsar para abrir una segunda venta de dialogo. {Consejos: La opcion de abrir una o varias ventanas de dialogo se puede modificar en el archivo simuconf.tab}

Pulsando en los siguientes elementos,se abren distintas ventanas de dialogo:

Depositos - abre los controles para comprar y administrar vehiculos en el deposito.

Paradas - abre la ventana Informacion de la Parada para esa parada.

Vehiculos - abre la ventana Informacino del Convoy/Vehiculo para ese vehiculo.

Ayuntamiento - abre la ventana Estadisticas de Poblacion para esa area urbana. {Consejos: La opcion de abrir una o varias ventanas de dialogo para dar informacion acerca de un poblacion esta disponible en el fichero simuconf.tab}

Industrias - abre la ventana Informacion de la Industria para esa industria.

Edificios de Ciudad abre una ventana de dialogo que da informacion acerca del edificio (El titulo de la ventana es 'Edificio'). La informacion contenida en la ventana incluye:
- descripcion da informaccion acerca del edificio. Si no esta disponible la descripcion se muestra como 'casa residencial', 'edificio industrial', 'tiendas y almacenes' (para edificios comerciales).
- Ciudad de: indica a que area urbana pertence el edificio.
- Nivel de Pasajeros: es la popularidad relativa como destino de pasajeros.
- Nivel de Correo: es la popularidad relativa como destino para correo.
- Aparece desde: indica el año en que aparece el edificio si esta jugando concronologia.
- Valor:: indica los costes de eliminacion del edificio si se usa la herramienta Eliminar.
- Pintado por : nombre de la persona que diseño y pinto el edificio para Simutrans

Monumentos / Atracciones turisticas abre una ventana de dialogo que da informacion acerca de una atraccion (el titulo de la ventana indica si es un monumento o una atraccion turistica). La informacion contenida incluye:
- Propiedad Publica indica que el elemento no pertenece a ningun jugador.
- descripcion da informacion acerca de la atraccion.
- Nivel de Pasajeros: es la popularidad relativa como destino de pasajeros.
- Nivel de Correo:es la popularidad relativa como destino para correo.
- Aparece desde:indica el año en que aparece el edificio si esta jugando concronologia.
-Pintado por : nombre de la persona que diseño y pinto la atraccion para Simutrans

Carreteras y Vias abre una ventana de dialogo que da informacion acerca de una carretera o via (el titulo de la ventana indica el tipo de via que es - en el caso de vias de tranvia sobre carreteras, indica el tipo de carretera).
Information contained in dialogue:
- Vel. Max: velocidad maxima permitida en esa via o carretera.
- Ribi (unmasked):
es un contador interno que indica la direccion de la via.
- Ribi (masked): es un contador interno que indica la direccion de la via teniendo en cuenta las señales.
- with sign/signal is shown if there is a signal or sign present.
- electrificado/no electrificado indica si la via esta electrificada.
- vehiculos el mes pasado indica el numero de Vehiculos que han usado la via en el mes previo de juego.
- reservado por indica el tipo de vehiculo que ha reservado la via pasa su uso hasta que haya pasado por ella.
- inclinacion indica la direccion de inclinacion si existe
- coordenadas del mapa mostradas en la barra inferior de la pantalla
En el caso de la vias del tranviaconstruidas sobre carreteras: la informacion se muestra dos veces, la primera por la carretera y la segunda por la via del tranvia.

Señales/Signos abre la ventana de dialogo, el titulo de la ventana indica si es una señal normal o de carretera. La informacion mostrada incluye:
- direccion es un contador interno que indica la direccion impuesta por la señal.

Tendido electrico / Subestacion transformadora abre una ventana de dialogo que da informacion acerca del suministro de electricidad (el titulo de la ventana es 'Linea Electrica'). La informacion mostrada incluye :
- Potencia: valor que indica la cantidad de energia electrica suministrada.
- Disponible:: valor mostrado para subestacion Transformadora en Industria indicando la cantidad relativa de energia suministrada.
- Net: es un numero ID del red. Dos puntos con el mismo ID estaran conectados.

Arboles abre una ventana de dialogo, cuyo titulo es 'Arbol'. La informacion mostrada incluye:
- nombre : dado por la especie de arbol.
- edad : edad del arbol en meses.

Terreno abre una ventana de dialogo, cuyo titulo es 'Terreno'. La informacion mostrada incluye:
- pendiente : da las especies de arboles.
- coordenadas del mapa : son mostradas en la barra inferior de la pantalla.

{Consejos: La opcion de abrir ventanas de dialogo para carretera y peatones esta disponible en el archivo simunconf.tab}.

simutrans-124.3/simutrans/text/es/language.txt000066400000000000000000000013401474050137200215150ustar00rootroot00000000000000Ayuda de Idioma

Idioma

Idioma cambia el idioma usado en el juego

Idioma se abre desde Opciones del juego & con Crear un nuevo mundo.

Para jugar en otros idiomas: haga click en el buton correspondiente al idioma deseado, antes de empezar a jugar.

El nuevo idioma aparecera reflejado solamente en barras de herramientas nuevas o reabiertas,
en el menu opciones y en algunos de los textos del juego. Si la traduccion no esta disponible
en el idioma seleccionado, aparecera en Ingles.

Visite https://translator.simutrans.com para ayudar con la traduccion

simutrans-124.3/simutrans/text/es/linemanagement.txt000066400000000000000000000214531474050137200227250ustar00rootroot00000000000000Administracion de Lineas

Administracion de Lineas

Administracion de Lineas muestra informacion y controles para gestionar Lineas (rutas y cantidad minima de mercancias y pasajeros que cargara el Convoy en la parada) para uno o varios Convoys con la misma ruta.

Una Linea consta de una serie de Paradas donde los vehiculos cargan y descargan pasajeros y mercancias (los transportes maritimos usan una cuadricula cualquiera de agua en el area de influencia del puerto) y puntos de paso (usados para dirigir vehiculos si hay mas de una ruta posible o para proporcionar puntos intermedios de destino).

Pulsa en el icono de la red en la barra de la parte superior de la pantalla o pulsa [w] para abrir la ventana de Administracion de Lineas, de la cual puedes ajustar su tamaño (pulsa en la flecha hacia abajo de la barra de titulo para volver al tamaño original).

La parte izquierda de la ventana Administracion de Lineas lista las lineas existentes (para desplazar la lista: usa la barra de desplazamiento en la parte derecha de la lista), que puede filtrarse por tipo de transporte, pulsando en las distintas pestañas que hay sobre la lista para seleccionar:
Todo: lista Lineas de todos los vehiculos.
Tren: lista Lineas de todos los vehiculos ferroviarios.
Monorrail: lista Lineas de todos los vehiculos Monorrail/maglevs.
Tram: lista Lineas de todos tranvias.
Camion: lista Lineas de todos los vehiculos de carretera.
Barco: lista Lineas de todos los transportes maritimos.
Aire: lista Lineas de todos los aviones.

El color del nombre de la Linea indica los siguiente:
blanco - no hay vehiculos asignados a esta Linea
amarillo - no operativa, no genera beneficios o perdidas
negro - genera beneficios, sobra capacidad, necesita mejoras
azul - genera beneficios, sobra poca capacidad
rojo - linea con perdidas

Bajo la lista de lineas existentes estan los botones de opcion para gestionar las Lineas.
Pulsa en una Linea de la lista para seleccionarla (el nombre aparecera resaltado) y consulta informacion acerca de las Paradas, ingresos, y Convoys en la Linea seleccionada.
Si los detalles de las Paradas o Convoys son parcialmente visibles, ajusta el tamaño de la ventana Administracion de Lineas o usa las barras de desplazamiento para desplazar la informacion.

Los botones de opcion, en la parte izquierda, incluyen (pulsa para seleccionar):

Nueva linea:opcion que abre controles para definir la Ruta ( una ruta y la cantidad minima de mercancias y pasajeros que cargara el Convoy en cada Parada) de una nueva Linea.
Añade cuantas Paradas o puntos de paso como sea necesario, ajusta los niveles de carga para cada Parada, y por ultimo cierra la ventana de Enrutar para crear la nueva Linea (pulsa en la X de la parte superior izquierda de la ventana o usa el teclado). A la nueva Linea se le asignara un numero y se listara en la ventana Administracion de Lineas.
{Consejos: Selecciona el tipo de transporte usando las pestañas antes de crear una nueva Linea. Los vehiculos no cargan o descargan mercancias o pasajeros en los puntos de paso.}

Actualizar linea: abre los controles para alterar y gestionar una Ruta ya existente (una ruta y la cantidad minima de mercancias y pasajeros que cargara el Convoy en cada Parada) de una Linea. EL cambio afectara a todos los vehiculos de la Linea, una vez hayas cerrado la ventana de Enrutar (pulsa en la X de la esquina superior izquierda de la ventana).
Pulsa en el nombre de una Linea para seleccionarla (el nombre aparecera resaltado) y despues pulsa en el boton de opcion para abrir la ventana de Enrutar.

Borrar linea: borra la Linea seleccionada (una ruta y la cantidad minima de mercancias y pasajeros que cargara el Convoy en cada Parada).
Pulsa en el nombre de una Linea para seleccionarla (el nombre aparecera resaltado) y despues pulsa en el boton de opcion para eliminarla. No requiere confirmar la operacion.

Cuando se selecciona una Linea, las Paradas se muestran en la parte inferior izquierda de la ventana Administracion de Lineas. Pulsa en una Parada de la lista para abrir una ventana con informacion acerca de la misma.
Los elementos listado por cada Parada incluyen:
Barra de estado en color: los colores indican el estado operativo de una Parada en relacion a como de abarrotada esta. La barra de estado en color se usa tambien en la Lista de Estaciones y en Informacion de la Parada y el color es el mismo mostrado sobre cualquier Parada:
- amarillo: fuera de servicio.
- verde: no requiere mejoras.
- naranja: es posible que necesite mejoras.
- rojo: mejoras recomendadas.
{Consejos: Usa [!] para mostrar la barra de color sobre las Paradas.}
Nombre que ha sido asignado a la Parada.
Numero de Parada (Las Paradas son numeradas si esta activa esta opcion en el archivo simuconf.tab).
icono(s) de vehiculo indica que tipos de vehiculos pueden usar la Parada (se usa tambien en Lista de Estaciones y en Informacion de la Parada). os iconos incluyen: bus (para vehiculos de pasajeros por carretera), camion (para vehiculos de mercancias por carretera), tren, barco y avion. Los tranvias se indican mediante el icono del bus o tren dependiendo del tipo de estacion.
icono(s) de mercancias indica que elementos (pasajeros, mercancias y correo) puede manejar la Parada (tambien se usa en Informacion de la Parada y Lista de Estaciones).
{Consejos: añade las extensiones apropiadas para cambiar la categoria de las mercancias que puede manejar la Parada. Las oficinas de correos se pueden añadir a las Paradas para poder manejar correo}.
esperando detalles de las diferentes mercancias y pasajeros.

En la parte derecha de la ventana Administracion de Lineas se muestra informacion en un grafico, una caja de texto y una lista de Convoy para la Linea seleccionada.

Pulsa en un nombre de Linea de la lista (el nombre se resalta). Pulsa en los botones de opcion para mostrar informacion, acerca de la Linea seleccionada y los vehiculos asignados a esta, en el grafico (el eje x es el tiempo en meses):

- Capacidad libre - cantidad de espacio sobrante en los vehiculos para mercancias y pasajeros.

- Recorrido - cantidad de mercancias y pasajeros que han usado esa Linea.

- Ingresos - cantidad de ingresos generado por los vehiculos.

- Operacion - coste generado por los vehiculos en transito.

- Beneficio - ingresos generados menos los costes generados(Ganancias menos Costes Operativos).

- Convoyes - numero de Convoys asignados a la Linea.

Para renombrar una Linea: Pulsa en el nombre de una Linea de la lista (el nombre se resaltara), y despues pulsa en la caja de texto (debajo de las opciones del grafico, sobre la lista de Convoys) y escribe un nuevo nombre.

Cuando se selecciona una Linea (pulsa en el nombre de una Linea de la lista para resaltarlo), los Convoys asignados a la Linea se listan bajo el grafico.
En la parte superior de la lista de vehiculos se muestra: el numero total de Convoys asignados a la Linea; ingresos (ganancias menos costes operativos), capacidad, y cantidad actual de mercancias y pasajeros cargada(% de la maxima capacidad entre parentesis) the todos los Convoys de la linea.
Pulsa en un elemento de la lista para ver mas informacion acerca de dicho Convoy (usa la barra de desplazamiento para desplazar la lista).
los elementos listados por cada Convoy incluyen:
nombre: que ha sido asignado (por defecto esto se hace con el primer vehiculo comprado o añadido a un Convoy).
ingresos: muestra los beneficios (ingresos generados menos costes operaciones).
Linea: muestra el nombre de la Linea asignada al Convoy e indica si esta en una cochera.
graficos: muestra la composicion y el nivel actual de los elementos cargados.

simutrans-124.3/simutrans/text/es/list.txt000066400000000000000000000037351474050137200207170ustar00rootroot00000000000000Ayuda de Listas

Listas

Listas tiene opciones para abrir los controles con informacion acerca del estado actual de la partida (y tambien tiene controles para ajustar los ingresos relativos recividos del transporte de pasajeros, mercancias y correo).

La informacion esta disponible para el jugador en listas : Paradas; Convoys; ciudades; ingresos recibidos de las diferentes mercancias, pasajeros y correo; industrias; y atracciones turisticas.

Pulsa en un icono tipo lista en la barra de herramientas de la parte de arriba de la pantalla para abrir Listas.
Pasa el raton por encima de los iconos, para ver los nombres.

Pulsa en la herramienta seleccionada para abrir los controles con informacion,de izquierda a derecha, acerca de:

Lista de Estaciones: Paradas, donde los vehiculos cargan y descargan mercancias y pasajeros (no incluye las paradas de vehiculos maritimos).

Lista de Vehiculos: vehiculos sobre carretera y via del tren, aviones y barcos.

Lista de todas las ciudades: ciudades (villas, pueblos y ciudades).

Lista de todas las mercancias: ingresos recividos de las diferentes mercancias, pasajeros y correo (incluye controles para ajustar los ingresos relativos).

Lista de Fabricas: industrias (consumidores y suministradores de mercancias).

Lista de Atracciones : atracciones turisticas.

simutrans-124.3/simutrans/text/es/load.txt000066400000000000000000000033261474050137200206570ustar00rootroot00000000000000Ayuda de Cargar

Cargar

Cargar retoma un juego salvado (para continuar jugando) y puede ser usado para borrar esas partidas. Un juego que es retomado sustituye el mundo actual en juego, el cual se pierde.

Cargar se abre desde Crear un Nuevo Mundo y desde Opciones de Juego o presionando [L]; y lista el nombre, fecha y hora de las partidas salvadas disponibles.
Si no estan visibles todos las partidas: usa las barras de desplazamiento en la parte izquierda de la lista para desplazar los nombres.

Pulsa en un nombre de la lista para retomar una partida salvada; o teclea un nombre en la caja de texto en la parte de arriba de la ventana Cargar: pulsa en la caja de texto, escribe el nombre, y presiona [Enter] o [Return], o pulsa en OK.
Un nombre de partida incorrecto, se notificara mediante un mensaje de error : cierra el mensaje y prueba de nuevo.

CUIDADO: Pulsando en el boton X BORRARAS LA PARTIDA SALVADA de forma inmediata y permanente.
El nombre de la partida se eliminara de la lista y la ventana de Cargar se cerrara. USA ESTA FUNCION CON MUCHO CUIDADO.

IMPORTANTE: Nuevas versiones de Simutrans aparecen regularmente y las partidas salvadas de versiones previas podrian no funcionar con las ultimas versiones; por favor, lee las especificaciones de cada version para saber si las partidas antiguas son compatibles.

Pulsa en Cancelar para cerrar Cargar; o X en la parte superior derecha de la ventana; o usa el teclado.

simutrans-124.3/simutrans/text/es/load_relief.txt000066400000000000000000000032111474050137200221760ustar00rootroot00000000000000Ayuda de Cargar Topografia

Cargar Topografia

Cargar Topografia se usa para abrir un fichero de un mapa de altura del terreno (para usar en un juego nuevo) y puede ser usado para borrar este tipo de ficheros.

Cargar Topografia se abre desde Crear un Nuevo Mundo; y lista el nombre, fecha y hora (del juego salvado) del los distintos terrenos disponibles.
Si no puedes ver todos los elementos: usa la barra de desplazamiento en la parte derecha de la lista, para desplazar los nombres.

Pulsa en un nombre de la lista para usar una terreno; o introduce en nombre en la caja de texto en lo alto de la ventana: pulsa en la caja de texto, escribe el nombre, y pulsa [Enter], [Return] o pulsa en OK (un nombre incorrecto no tendra efecto, intentalo de nuevo).

CUIDADO: Pulsando en el boton X de la parte izquierda de un nombre de terreno, SE BORRARA EL FICHERO PERMANENTE E INMEDIATAMENTE, el nombre del fichero es eliminado de la lista y la ventana Cargar Topografia se cerrara. Usa esta funcion con cuidado.

Algunos terrenos estan disponibles en http://addons.simutrans.com.
El fichero nuevo debe tener formato ppm y estar en el directorio (o carpeta) llamada...simutrans/save/

La informacion acerca de como crear terrenos esta dsiponible en http://wiki.simutrans.com

Pulsa en Cancelar para cerrar la ventana de Cargar Topografia; o X en la parte superior izquierda de la ventana; o usa el teclado.

simutrans-124.3/simutrans/text/es/mailbox.txt000066400000000000000000000046021474050137200213710ustar00rootroot00000000000000Ayuda del Buzon

Buzon

Buzon lista mensajes de la partida y abre los controles para elegir como seran mostrados los mensajes.

Pulsa en el icono del buzon en la parte superior de la pantalla o presiona [B] para abrir el Buzon, el cual lista mensajes del juego.
Pulsa en un mensaje para mover la pantalla al lugar al que hace referencia el mensaje.

Opciones boton (pulsa para usar) que abre las Opciones del Buzon las cuales tienen controles que determinan como son mostrados los mensajes.


Opciones del Buzon

Opciones del Buzon tiene tres columnas de botones cuadrados que selecionan como son mostrados los mensajes.

De izquierda a derecha, las columnas seleccionan los criterios para mostrar los mensajes como: un texto en la parte inferior de la pantalla; como un aviso temporal; o como aviso permanente.
{Consejos: Pulsa la X en la esquina superior derecha del mensaje o usa el teclado para cerrar los avisos permanentes}

Pulsa en los botones cuadrados para seleccionar las opciones del mensaje para los siguientes mensajes:

Año nuevo: un nuevo periodo de 12 meses ha comenzado.

Noticias de la IA : un jugador controlado por la maquina ha abierto una nueva linea.

Noticias de las Ciudades: una ciudad esta contruyendo un ayuntamiento mas grande.

Sin Ruta: un vehiculo no puede encontrar la ruta al siguiente destino (una Parada o un punto de paso).

Nuevas Industrias: una nueva cadena industrial (un suministrador o un consumidor final) ha sido construido debido al crecimiento de una ciudad.

Turismo: una atraccion o monumento en la ciudad ha sido construido.

Nuevos Vehiculos: un nuevo vehiculos esta disponible, o es retirado (si la linea cronologica esta en uso).

Estacion llena: una Parada esta saturada.

Problemas: el jugador esta endeudado, y otros mensajes criticos.

simutrans-124.3/simutrans/text/es/map.txt000066400000000000000000000121251474050137200205120ustar00rootroot00000000000000Ayuda del Mapa

Mapa

Mapa muestra un mapa del mundo actual dando informacion del terreno, localizaciones importantes y redes de transporte. Tambien es una forma de mover la ventana del juego por el mundo creado.

Pulsa en el icono del mapa en la parte superior de la pantalla o pulsa [m] para abrir la ventana del Mapa, se puede ajustar o minimizar la ventana. Las flechas, en la parte superior del mapa, abren/cierran etapas : opciones del mapa, una escala de color min-max que muestra el nivel de actividad de algunas de las opciones, y una clave de colores de las industrias que se ven en el mapa.

El mapa tiene tres escalas diferentes: pulsa el boton derecho en el Mapa (o pon el cursor y usa la rueda del raton) para pasar de una escala a otra. Si no es visible el mapa entero entonces cambia la escala del mapa, o ajusta la ventana del Mapa, o mueve el mapa para ver la porcion deseada: pulsa el boton derecho para arrastrar (o usa las barras de desplazamiento en los laterales de la ventana).

En el mapa, el agua es azul y el terreno elevado es mas claro que el terreno bajo. La parte de mundo,que es mostrada, se representa con un cuadrado blanco en el Mapa: la parte superior de la pantalla corresponde con la parte superior izquierda del cuadrado blanco (El norte es la parte superior del mapa, el Noroeste es la parte superior de la pantalla). Si el cuadrado blanco cae fuera del mapa, esa parte se muestra como agua.

Para mover la vista del juego a grandes distancias, pulsa el boton izquierdo en el punto requerido o para arrastrar el cuadrado blanco.

Apunta con el cursor a una fabrica en el mapa, para ver el nombre y una linea blanca que enlaza con los consumidores que parpadean; manten pulsado [Shift] primero para mostrar una linea roja hasta los suministradores.

En el mapa (cuando no se estan usando las opciones): ciudades, atracciones, tuneles, canales aparecen en gris oscuro; carreteras en negro; vias de tren y tranvia en gris; puentes en gris claro; Paradas en rojo/amarillo; vias de monorail/maglev en naranja; areas de aeropuertos en blanco; y vehiculos en amarillo.

Pulsa en los botones de opcion para mostrar/ocultar detalles en el mapa acerca de:

Ciudades: nombres de las areas urbanas.

Pasajeros: areas de influencia para pasajeros de las Paradas.

Correo: areas de influencia para correo de las Paradas.

Mercancia: nivel de mercancias y pasajeros por las carreteras y vias (usa la escala min-max ).

Estado de la Parada: los colores indican la operatibilidad de la Parada en relacion con como de abarrotafa esta. El mismo color se muestra en las barras de color de estado en la Lista de Estaciones, en la ventana de Informacion de la Parada y en Administracion de Listas , y es el mismo color mostrado en la barra de color que hay sobre el nombre de la Parada).

Servicio: nivel de mercancias y pasajeros usando la Parada (usa la escala min-max).

Trafico: nivel de los vehiculos en carreteras y vias (usa la escala min-max).

Origen: nivel de las mercancias y pasajeros que comienzan el viaje en una Parada (usa la escala min-max).

Destino: nivel de las mercancias y pasajeros que terminan el viaje en una Parada (usa la escala min-max).

En espera: nivel de las mercancias y pasajeros esperando por transporte en una Parada (usa la escala min-max).

Vias: vias de tren, tranvia y señales; las vias, puentes y tuneles se muestran en blanco (en rojo si estan electrificadas) y las señales se muestran en amarillo.

Limite de velocidad: las carreteras y vias se muestran en relacion a la maxima velocidad permitida (usa la escala min-max).

Lineas electricas: el tendido electrico (usa la escala min-max para mostrar el nivel de suministro en el momento en que abriste el Mapa).

Atracciones turisticas: nivel de pasajeros que generan las atracciones turisticas (usa la escala min-max), la opcion tambien resalta las atracciones en el mapa.

Fabricas: resalta las industrias; ilumina los consumidores y suministradores en el mapa.

Depositos: resalta los depositos. Los colores indican el tipo de transporte: barco en amarillo; vehiculo de carretera en naranja; tren en rojo; avion en verde; tranvia en azul; y monorail en gris.

simutrans-124.3/simutrans/text/es/monorailtools.txt000066400000000000000000000176731474050137200226530ustar00rootroot00000000000000Ayuda de Herramientas de Monorail/Maglev

Herramientas de Monorail/Maglev

Herramientas de Monorail/Maglev construye un red de transporte mediante Monorail/Maglev. Las herramientas pueden crear o eliminar: vias de monorail y maglev; puentes; tuneles; señales; cocheras; estaciones; y extensiones. Si estas jugando concronologia, a medida que pase el tiempo apareceran nuevas herramientas.

Pulsa en el icono de Herramientas de monorail/maglev en la barra de la parte superior de la pantalla para abrir el menu de herramientas.
Situa el cursor del raton encima de los icones (tras abrir la barra de herramientas) para ver el nombre, los costes de construccion, costes de mantenimiento, limite maximo de velocidad y maxima longitud.

Herramientas de Monorail/Maglev incluye, de izquierda a derecha:

Via de Monorail/maglev : herramienta para construir vias para vehiculos monorail/maglev entre dos puntos. Las vias solo pueden ser construidas en cuestas en la direccion de dichas cuestas, y pueden no encontrar camino en terreno escarpado, agua u obstaculos. La nueva via puede usar parte de las vias ya existentes en su camino.
Para construir la via: pulsa en el icono de la herramienta Via (el cursor cambia a una via), despues pulsa en el terreno para establecer el punto inicial (se mostrara una excavadora y las coordenadas del punto en la parte izquierda de la barra inferior de la pantalla), por ultimo pulsa para el punto final de la via.
{Consejos: Los diferentes tipos de via se pueden conectar (excepto cuando intentas construir sobre vias de otros jugadores). Usa las Herramientas del terreno para modificar el terreno, para permitir la construccion de vias. Usa la herramienta Eliminar para eliminar partes individuales de la via y algunos obstaculos. Usa la tecla [Ctrl] al mismo tiempo para acceder a funciones extra. Deshaz la ultima ruta construida pulsando la tecla [z]. No se reembolsan los costes de construccion.}

Remove monorails: herramienta para eliminar vias de monorail/maglev, cuando no hay vehiculos presentes, entre dos puntos (las estaciones y señales tambien se eliminan).
El uso de esta herramienta implica un coste de construccion.
Para eliminar vias: pulsa en la herramienta (el cursor cambia a un cruz roja); despues pulsa en la via que quieres eliminar (en el punto seleccionado para borrar se muestra una cruz roja); por ultimo pulsa en otro punto de la via, para eliminar la parte entre ambos puntos.
{Consejos: Opera como otro jugador para eliminar sus vias.}

Rampas y Puentes: herramientas que construyen puentes rectos, para que pasen vehiculos monorail/maglev, entre dos puntos con via. Los puentes tienen una maximo de distancia entre pilares. Las herramientas construyen puentes partiendo desde el final de una via hasta otro punto adecuado (otro final de via o punto elevado).
Para construir una rampa o puente: pulsa en el icono de la herramienta (el cursor cambia a un puente), a continuacion pulsa en un tramo final de via (punto de comienzo del puente) para construirlo. Algunos obstaculos o la falta de espacio adecuado para emplazar el final del puente hara que el puente no se construye: construye via en ambos lados de futuro emplazamiento del puente, y prueba de nuevo.
{Consejos: Usa la herramienta Eliminar para destruir puente (pulsa en el final del puente) y algunos de los obstaculos para la construccion del puente. Usa las herramientas de Vias para conectar las partes finales del puente a las vias.}

Señales de Monorail: herramientas para construir señales para vehiculos monorrail y maglev en la via. Las señales dirigen y regulan el flujo de vehiculos en vias y puente, cruces y Paradas (donde los vehiculos cargan y descargan pasajeros).
Se pueden contruir señales de sentido unico o doble sentido. Para construir un señal de doble sentido en una via: pulsa en el icono de la herramienta (cambia el cursor a una señal); despues pulsa en la via. Para construir una señal de sentido unico: pulsa de nuevo en el mismo punto, con el cursor de señal, para pasar de un tipo de señal a otro.
IMPORTANTE: Ten cuidado en no poner señales de sentido unico, ya que pueden evitar que un vehiculo llegue a su destino, por defecto los vehiculos conducen por la derecha (se puede cambiar en el archivo simuconf.tab).
- Señales: los vehiculos continuan solo si el tramo de via hasta la siguiente señal o destino de la Ruta (a Parada o punto de paso) no esta ocupado por otro vehiculo. En el modo de sentido unico, los vehiculos se mueven en una unica direccion.
- PreSignals: los vehiculos continuan si el tramo de via (entre tres señales consecutivas o hasta el proximo destino en la Ruta) no esta ocupado por otro vehiculo. En el modo sentido unico, las preseñales dejan pasar a los vehiculos unicamente en un sentido.
- ChooseSignals: dirigen vehiculos hacia una estacion vacia, una Estacion multiple: un vehiculo pasando esta señal puede usar una estacion vacia en su proximo destino, y no justamente el que esta asignado en su Ruta. Si no hay estaciones vacias o una ruta clara hasta su proximo destino, los vehiculos esperaran en la señal.
{Consejo: Elimina las señales con la herramienta Eliminar. Manten pulsado [Ctrl] para poner señales en puentes sobre otras vias.}

Cochera de Monorail: herramienta que construye una cochera para comprar y gestionar vehiculos y vagones de monorrail/maglev.Las cocheras implican un coste de mantenimiento y se construyen al final de una via de monorrail/maglev.
Para construir una cochera de monorail: pulsa en la herramienta (el cursor cambia a una cochera), y a continuacion pulsa en un final de via.

Paradas de Tren: herramientas para construir estaciones, usadasd por vehiculos monorrailes/maglev para cargar o dejar pasajeros y correo.
Una estacion, cuando no se construye junto a otra Parada existente dara lugar a una nueva Parada.
Las Paradas tienen un coste de mantenimiento y se construyen sobre vias (pero no en curvas ni cruces).
Las paradas tiene un area de influencia para mercancias, pasajeros y correo. Las diferentes estaciones tienen distintas capacidades para mercancias, pasajeros y correo. . En la esquina superior de algunas de las herramientas un icono (usado en Lista de Estaciones y en Informacion de la Parada) muestra que elementos puede manejar la Parada.
Para construir una Parada: pulsa en el icono de la herramienta (el cursor cambia a una estacion), y despues pulsa en la via.
{Consejos: Elimina las Paradadas mediante la herramienta remove monorails. Las Paradas con extensiones y estaciones multiples (construyendo mas secciones de estacion en la via adyacente) pueden soportar vehiculos mas largos, incrementar su capacidad y area de influencia. Pulsa la tecla [v] para mostrar/ocultar el area de influencia para mercancias y pasajeros. Manten pulsado [Ctrl] para construir puentes o vias elevadas sobre otras vias.}

Monorail Foundation: herramienta que construye una extension de una Parada e incrementa la capacidad de dicha Parada. Las Monorail foundations se construyen en finales de vias de monorrail/maglev e implican un coste de mantenimiento.
Para construir una monorrail foundation: pulsa en la herramienta (el cursor cambia a foundation), y despues pulsa en el lugar deseado en el final de una via.
{Consejos: Elimina las monorail foundations mediante la herramienta Eliminar.}

simutrans-124.3/simutrans/text/es/new_world.txt000066400000000000000000000125531474050137200217420ustar00rootroot00000000000000Ayuda de Crear un Nuevo Mundo

Crear un Nuevo Mundo

Crear un Nuevo Mundo establece las opciones para una nueva partida, con un nuevo mapa y nuevas opciones.
Se incluyen muchas variables : tamaño del terreno, numero inicial de cuidades e industrias.
Se muestra una vista previa del terreno, segun las opciones elegidas.

Crear un Nuevo Mundo se abre junto con las ventanas de Idiomas y Control del Clima cuando arranca Simutrans (las otras opciones del juego estan deshabilitadas) y tambien se puede abrir desde el boton Opciones de Juego en la parte superior de la pantalla (las otras barras de herramientas, textos y opciones de la partida actual se cierran).
Los atajos del teclado para abrir la ventana Crear un Nuevo Mundo incluyen pulsar las teclas [Q] and [X].

Para volver a la partida actual, cierra la ventana Crear un Nuevo Mundo: pulsa en la X en la esquina superior izquierda de la ventana; o usa el teclado.

Los botones de las flechas ajustan las opciones y el resto activan/desactivan las opciones o abren nuevos controles:

Numero de Mapa: selecciona el terreno a usar en la partida.
Puls en la caja de texto y escribe el numero deseado o usa los botones de flechas para pasar de un terreno a otro.
La vista previa muestra el terreno seleccionado (el agua es azul, el terreno bajo es mas oscuro que el terreno elevado).

Tamaño: establece el tamaño del mapa (la cifra superior es el ancho, la inferior es el alto).
El numero entre parentesis es la cantidad de memoria requerida por el mapa
IMPORTANTE: Los mapas granges necesitan mas memoria y tardan mas tiempo en crearse. El juego y los graficos requieren aproximadamente 88MB en el pak64 y 144MB en el pak128. Como regla general,en un ordenador con 256MB RAM no intentes mapas mas grandes de 512 x 512.

Mapa al azar: selecciona un nuevo terreno de forma aleatoria , conservando el resto de las opciones.

Cargar topografia: abre los controles para cargar un mapa personalizado entre los disponibles.

Numero de ciudades: establece el numero inicial de ciudades en el juego.

Poblacion media por ciudad: establece la poblacion inicial de las ciudades.
Esta opcion es un valor medio, Simutrans tendera a generar mas ciudades pequeñas que grandes.

Longitud carretera interurbana: establece la longitud inicial de las carretera entre las ciudades.

Dens. de trafico: establece en numero de vehiculos privados en las ciudades.
Los valores alto dan lugar a mas vehiculos privados,el valor 0 no genera ninguno. A medida que crecen las ciudades, aparecen nuevos coches.

Fabricas fuera de las ciudades: establece el numero inicial de Cadenas industriales de suministro fuera de las ciudades.
Si el terreno tiene muchas cuestas, apareceran pocas industrias.

Mercados en las ciudades: establece el numero inicial de consumidores finales de mercancias en las ciudades.
Los nuevos consumidores (y los posibles suministradores, no necesariamente en ciudades) aparecen cada vez que se dobla la problacion a partir de los 2000 habitantes.

Atracciones turisticas: establece el numero inicial de lugares fuera de las ciudades que atraen pasajeros y correo.
Estas aparecen en las afueras de las ciudades, ademas de las atracciones generadas dentro de los pueblos y ciudades al inicion de la partida. Las atracciones tambien generan pasajeros y correo.

Usar cronologia desde el año: establece el año de inicio de la partida. Cuando la opcion esta seleccionada, a medida que pasa el tiempo en la partida, pueden aparecer mas vehiculos y edificios.
Cuando no esta seleccionada: la partida comienza en el ao elegido pero estan disponibles todos los vehiculos y edificios; las ciudades aparecen con edificios de todos los periodos; y los vehiculos mas lentos no son tan rentables (ya que en el calculo de los ingresos influye la velocidad media del vehiculo de transporte).

Permitir cambio de jugador: opcion que permite jugar como un jugador IA o como servicio publico (esta opcion no se puede cambiar un vez has iniciado una partida nueva).

Beginner mode: opcion que permite un nivel mas alto de ingresos que recibes por transportar mercancias y pasajeros(por defecto: el 150% del valor recibido en el modo normal). Ademas, las Industrias no pararan de suministrar cuando el consumidor tenga exceso de suministro.

Cargar juego: abre los controles para retomar una partida salvada, reemplazando el mundo actual que se pierde.

Empezar juego: crea un mundo nuevo, usando las opciones establecidas. Pulsa para comenzar a jugar - Buena suerte y divierte..

{Consejos: Los valores por defectos y otras propiedades cuando arranca Simutrans se pueden modificar en el archivo simuconf.tab}

simutrans-124.3/simutrans/text/es/options.txt000066400000000000000000000024721474050137200214340ustar00rootroot00000000000000Ayuda de Opciones de Juego

Opciones de Juego

Opciones de Juego abre controles para configurar eljuego; puedes salir del juego desde Opciones de Juego.

Pulsa en el icono del diskette en la parte superior izquierda de la pantalla para abrir Opciones de Juego.

Pulsa el boton para abrir el menu correspondiente:

Idioma: establece el idioma usado en el juego.

Color: establece el color de jugador

Pantalla: parametros para configurar la apariencia del juego.

Sonido: parametros para el sonido y la musica en el juego.

Jugadores: abre el menu para configurar los diferentes jugadores.

Cargar: abre el menu para cargar un juego salvado.

Guardar: abre el menu para guardar la partida.

Nuevo Mapa: abre el menu para empezar un nuevo juego (cierra el resto de menus y ventanas activas del juego).

Salir: sales de juego, la partida actual en juego no es salvada.

simutrans-124.3/simutrans/text/es/players.txt000066400000000000000000000042751474050137200214230ustar00rootroot00000000000000Ayuda de Lista de Jugadores

Lista de Jugadores

Lista de Jugadores da informacion y tiene controles para gestionar los distintos jugadores.

Pulsa en el boton Jugadores en Opciones de juego o pulsa [k] para abrir la Lista de Jugadores que muestra los nombres y balance economico de los jugadores.

Hay 8 jugadores : humano, servicio publico y 6 jugadores IA. Los controles permiten jugar como diferentes jugadores si se activo la opcion Permitir cambio de jugador al inicio de la partida.

Pulsa en las flechas para jugar como ese jugador en la partida actual. Aparecera un mensaje de confirmacion diciendo que has cambiado de jugador: pulsa en la X de la parte superior izquierda del mensaje o usa el teclado para cerrarlo.

Pulsa en el nombre del jugador para ver sus Finanzas.

Pulsa en el boton cuadrado junto al nombre del jugador IA para activar/desactivar dicho jugador (el boton se oscurece cuando esta activado el jugador).

Los jugadores IA no caen en bancarrota y gestionan vehiculos con maxima eficiencia.
Desactivar un jugador IA durante la partida no eliminara su red de transporte.
Algunos jugadores IA pueden usar solo vehiculos por carretera o via, o transportar solo mercancias o pasajeros.

{Consejos: Los vehiculos no usaran las vias o carreteras de otros jugadores, asi como tampoco Paradas (sin embargo, los vehiculos de todos los jugadores pueden usar elementos creados por el jugador servicio publico).
Los jugadores no pueden construir elementos o poner puntos de paso en las vias de otros jugadores, asi como tampoco en carreteras, o eliminar elementos creados por otros jugadores (sin embargo algunos elementos creados por el jugador servicio publico pueden ser eliminados usando la herramienta Eliminar).
Desactiva la opcion cambio de jugador y accede a herramientas extra como el jugador servicio publico.}

simutrans-124.3/simutrans/text/es/railtools.txt000066400000000000000000000234531474050137200217530ustar00rootroot00000000000000Herramientas de Ferrocarriles

Herramientas de Ferrocarriles

Herramientas de Ferrocarriles sirven para construir una red de transporte con ferrocarriles. Puedes construir: vias de tren (electrificarlas y eliminarlas); puentes; tuneles; señales; cocheras; estaciones; y extensiones. Si estas jugando con cronologia, a medida que pase el tiempo apareceran mas opciones.

Pulsa en el icono del tren en la barra de la parte superior de la pantalla para abrir la barra de herramientas. Situa el cursor sobre los iconos de la barra (tras abrirla) para ver el nombre, los costes de construccion, los costes de mantenimiento entre parentesis, limite de velocidad maxima y longitud maxima.

Herramientas de Ferrocarriles incluye, de izquierda a derecha:

Vias de Ferrocarril: herramientas para construir vias para ferrocarriles entre dos puntos. Las vias solo se pueden construir en cuestas, en la direccion de la cuesta y pueden no encontrar camino a traves de terreno escarpado, agua u obstaculos. Los nuevos tramos pueden usar algunos ya existentes en su camino.
Para construir vias: pulsa en la herramienta para seleccionarla (el cursor cambia a una via), despues pulsa en el terreno para establecer el punto de inicio (mostrara una excavadora y las coordenadas a la derecha, en la barra de la parte inferior de la pantalla), y pulsa de nuevo para establecer el punto de finalizacion.
{Consejos: Los diferentes tipos de vias se pueden conectar (siempre que no hayan sido construidas por algun otro jugador). Usa los puentes y tuneles para conectar vias a traves de terreno escarpado, o para evitar obstaculos. Usa las Herramientas del Terreno para cambiar el terreno, y habilitar caminos para las vias. Usa la herramienta Eliminar para eliminar partes individuales de la via o algunos obstaculos. Usa [Ctrl] al mismo tiempo para acceder a funciones extra. Pulsa la tecla [t] para seleccionar la ultima de las Herramientas de Ferrocarriles usada.}

Via electrificada: herramientas para electrificar vias, puentes y tuneles entre dos puntos, para vehiculos electricos.
Para electrificar un via: pulsa en la herramienta o pulsa la tecla [e] (el cursor cambia una via electrificada) para seleccionarla, despues pulsa en la via para establecer el punto inicial (situa un icono de electrificacion en dicho punto), y por ultimo pulsa en un segundo punto de la via, para electrificar el tramo entre ambos puntos.
{Consejos: Usa la herramienta Eliminar para volver a vias no electrificadas.}

Remove Track: herramienta que elimina vias normales y electrificadas, cuando no hay vehiculos presentes, entre dos puntos (ATENCION: estaciones, señales, puentes y tuneles entre ambos puntos tambien se eliminan). El uso de esta herramienta implica costes de construccion.
Para eliminar vias: pulsa en la herramienta (cambia el cursor a una cruz roja); despues pulsa en la via (situa una cruz roja en el punto seleccionado); por ultimo pulsa en un segundo punto de la via, para eliminar el tramo entre ambos puntos.
{Consejos: Cambia de jugador para poder borrar sus vias de ferrocarril.}

Puente ferroviario: herramientas para construir puentes rectos, para vehiculos ferroviarios, entre dos puntos de una via. Los puentes tiene una distancia maxima entre pilares.
Las herramientas construyen puentes desde un final de via hasta un lugar adecuado (otro final de via o un terreno elevado).
Para construir un puente: pulsa en la herramienta para seleccionarla (cambia el cursor a un puente), despues pulsa en un final de via (sera el inicio del puente) para construirlo.
Algunos obstaculos o la falta de un terreno adecuado pueden dar lugar a que el puente no se construya: construye via a ambos lados del emplazamiento del puente, y prueba de nuevo.
{Consejos: Usa la herramienta Eliminar para eliminar los puentes (pulsa en el inicio o final del puente) o alguno obstaculos que impiden la construccion del puente. Usa las distintas herramientas de ferrocarriles para conectar los lados del puente a tramos de via.}

Rail Tunnel: Herramientas para construir tuneles rectos, para vehiculos ferroviarios, entre dos puntos. Los tuneles no pueden estar en cuesta: los vehiculos entran y salen de ellos por accesos que estan a la misma altura.
La herramienta construye un tunel, en un final de via situado sobre una cuesta. Para construir un tunel: pulsa en la herramienta (el cursor cambia a un tunel),pulsa en un final de via situado sobre una cuesta para construir la entrada del tunel.
Si el tunel no puede encontrar una salida adecuada (una cuesta libre de obstaculos), el puente no se construira: construye via en ambos lados y prueba de nuevo.
{Consejos: Usa las Herramientas de Modelado del Terreno y la herramienta Eliminar para crear terreno adecuado para las entradas y salidas de tuneles. Usa las Herramientas de Ferrocarilles para conectar las salidas del tunel mediante vias.}

Señales: herramientas que construyen señales para ferrocarriles en una via. Las señales dirigen y regulan el flujo de los vehiculos en vias, puentes, cruces y Paradas (donde los vehiculos cargan y descargan pasajeros y mercancias).
Se pueden construir versiones de sentido unico y doble. Para construir una señal de doble sentido en una via: pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la via. Para construir una señal de sentido unico: pulsa de nuevo en el mismo punto, con el cursor de señal, para pasar de un tipo de señal a otro .
IMPORTANTE: Ten cuidado con no situar señales de sentido unico que impidan a los vehiculos llegar a su destino, por defecto los vehiculos conducen por la derecha (se puede cambiar en el archivo simuconf.tab).
- Señales: los vehiculos prosiguen solo si el tramo hasta la siguiente señal o destino en la Ruta (una Parada o punto de paso) no esta ocupado por otro vehiculo. En el modo de sentido unico los vehiculos solo van en una direccion.
- RailClose: los vehiculos no prosiguen mas alla de la señal (solo disponible en modo de sentido unico).
- PreSignals: los vehiculos prosiguen si el area (entre tres señales consecutivas o hasta el proximo destino en la Ruta) no esta ocupado por otro vehiculo. En el modo de sentido unico los vehiculos solo van en una direccion.
- ChooseSignals: dirigen los vehiculos a una estacion vacia, dentro de una Parada multiplataforma: un vehiculo que pasa por esta señal puede usar una estacion vacia como proximo destino, y no justamente el que se le ha asignado en su Ruta. Si no hay estaciones vacias o una ruta clara hasta el proximo destino, el vehiculo esperara en la señal.
{Consejos: elimina las señales con la herramienta Eliminar. Manten pulsado [Ctrl] para situar señales en puentes sobre vias.}

Cochera ferroviaria: herramienta para construir una cochera para comprar y gestionar trenes y vagones.
Las cocheras tiene un coste de mantenimiento y deben construirse sobre el final de una via.
Para construir una cochera ferroviaria: pulsa en la herramienta (el cursor cambia a una cochera), y pulsa sobre el final de una via.
{Consejos: Las cocheras solo muestran los vehiculos electricos si estan sobre una via electrificada. Elimina las cocheras con la herramienta Eliminar.}

Estaciones de tren:herramientas para construir estaciones, usadas por vehiculos sobre vias para cargar y descargar mercancias, pasajeros y correo.
Una estacion, cuando no se construye adyacente a una Parada existente creara una nueva Parada.
Las Paradas sobre vias tienen un coste de mantenimiento y se construyen sobre vias (pero no en curvas ni cruces).
Las Paradas sobre vias tienen un area de influencia para mercancias, pasajeros y correo. Las diferentes estaciones tienen distintas capacidades para pasajeros y correo. En la esquina de algunos iconos de herramientas hay un pequeño icono (usado en Lista de Estaciones e Informacion de la Parada) que muestra que elementos puede manejar la Parada.
Para construir una estacion: pulsa en la herramienta para seleccionarla (el cursor cambia a una estacion), y despues pulsa en la via.
{Consejos: Elimina las paradas en via mediante la herramienta Eliminar. Extiende las estaciones y construye estaciones multiples (construyendo varias secciones de estacion en vias adyacentes) para acomodar mas vehiculos y mas largos, incrementando la capacidad y el area de influencia para pasajeros y mercancias. Pulsa la tecla [v] para mostrar/ocultar el area de influencia de las paradas para pasajeros y mercancias. Manten pulsado [Ctrl] para construir puentes sobre vias.}.

Extensiones: herramientas para construir extensiones y edificios para Paradas, las cuales pueden incrementar su capacidad, area de influencia y coste de mantenimiento.
En la esquina de los botones de algunas herramientas hay un mini icono (usado en Lista de Estaciones e Informacion de la Parada) que muestra que elementos puede gestionar la Parada gracias a la extension.
Para construir una extension: pulsa en la herramienta para seleccionarla (cambia el cursor a una extension), y despues pulsa en el lugar deseado junto a una Parada ya existente. La nueva extension se considerara parte de la Parada.
{Consejos: Elimina las extensiones con la herramienta Eliminar.}

simutrans-124.3/simutrans/text/es/removal_tool.txt000066400000000000000000000045001474050137200224350ustar00rootroot00000000000000Herramienta Eliminar

Herramienta Eliminar

Herramienta Eliminar se usa para destruir y eliminar elementos no deseados y obstaculos que impiden construir durante la partida.

Uso: Pulsa el icono de la X roja (un icono de bulldozer en el pak128) en la barra de la parte superior de la pantalla o presiona [a] para abrir la herramienta Eliminar (cambia el cursor a una X sobre una nube de polvo blanca).
Posiciona el cursor, un cuadrado amarillo indica la posicion donde actuara la herramienta (las coordenadas del mapa estan indicadas en la barra de la parte inferior de la pantalla). Entoces, solo tienes que pulsar en el elemento para eliminarlo.

Se muestra el coste de la operacion y se suma a las cifras de Construccion. El coste de eliminacion es equivalente al coste de contruccion para los elementos del jugador.
El coste de destruir edificios de la ciudad se muestra como su valor en la ventana de dialogo que se abre son la herramienta de Exploracion. El coste de destruir arboles es 100 creditos Hajo.

Herramienta Eliminar puede ser usada para eliminar peatones y coches de ciudades.

El orden de eliminacion de los elementos de una cuadricula del juego es: peatones o coches privados, señaales, parada o estacion, tendido electrico, puente o tunel, via y finalmente carretera.

{Consejos: Para eliminar un vehiculo de un jugador, puedes venderlo desde Detalles del Convoy.
Para eliminar una Industria, Atracciones y Ayuntamiento primero cambia al jugador Servicio Publico. NOTA: el uso de la herramienta Eliminar sobre un Ayuntamiento elimina todos los edificios de la cuidad.
Usa [Ctrl] para usar la herramienta en un nivel superior.
Para eliminar elementos de otros jugadores , primero selecciona jugar como otro jugador first.
Para eliminar segmentos de carreteras o vias usa Eliminar vias (tambien la puedes encontrar en Herramientas de Tranvia) o Eliminar carreteras.}

simutrans-124.3/simutrans/text/es/roadtools.txt000066400000000000000000000246371474050137200217560ustar00rootroot00000000000000Ayuda de Herramientas de Carreteras

Herramientas de Carreteras

Herramientas de Carreteras sirven para construir una red transporte por carretera para mercancias y pasajeros. Puedes construir o eliminar: carreteras, puentes, tuneles, señalesm cocheras, extensiones y Paradas.Si estas jugando con cronologia, a medida que pase el tiempo apareceran mas opciones.

Pulsa en el icono del camion en la barra de la parte superior de la pantalla para abrir la barra de herramientas. Situa el cursor sobre los iconos de la barra (tras abrirla) para ver el nombre, los costes de construccion, los costes de mantenimiento entre parentesis, limite de velocidad maxima y longitud maxima.

Herramientas de Carreteras incluye, de izquierda a derecha:

Carreteras: herramientas para construir carreteras para vehiculos entre dos puntos. Las carreteras solo se pueden construir en cuestas, en la direccion de la cuesta y pueden no encontrar camino a traves de terreno escarpado, agua u obstaculos. Los nuevos tramos pueden usar algunos ya existentes en su camino.
Para construir carreteras: pulsa en la herramienta para seleccionarla (el cursor cambia a una carretera), despues pulsa en el terreno para establecer el punto de inicio (mostrara una excavadora y las coordenadas a la derecha, en la barra de la parte inferior de la pantalla), y pulsa de nuevo para establecer el punto de finalizacion.
{Consejos: Los diferentes tipos de carreteras se pueden conectar (siempre que no hayan sido construidas por algun otro jugador). Usa los puentes y tuneles para conectar carreteras a traves de terreno escarpado, o para evitar obstaculos. Usa las Herramientas del Terreno para cambiar el terreno, y habilitar caminos para las carreteras. Usa la herramienta Eliminar para eliminar partes individuales de la carretera o algunos obstaculos. Usa [Ctrl] al mismo tiempo para acceder a funciones extra. Pulsa la tecla [s] para seleccionar la ultima de las Herramientas de Carreteras usada.}

Remove roads: herramienta que elimina carreteras, cuando no hay vehiculos presentes, entre dos puntos (ATENCION: paradas, señales, puentes y tuneles entre ambos puntos tambien se eliminan). El uso de esta herramienta implica costes de construccion.
Para eliminar carreteras: pulsa en la herramienta (cambia el cursor a una cruz roja); despues pulsa en la carretera (situa una cruz roja en el punto seleccionado); por ultimo pulsa en un segundo punto de la carretera, para eliminar el tramo entre ambos puntos.
{Consejos: Cambia de jugador para poder borrar sus carreteras.}

Puente de carretera: herramientas para construir puentes rectos, para vehiculos de carretera, entre dos puntos de una carretera. Los puentes tiene una distancia maxima entre pilares.
Las herramientas construyen puentes desde un final de carretera hasta un lugar adecuado (otro Para construir un puente: pulsa en la herramienta para seleccionarla (cambia el cursor a un puente), despues pulsa en un final de carretera (sera el inicio del puente) para construirlo.
Algunos obstaculos o la falta de un terreno adecuado pueden dar lugar a que el puente no se construya: construye carretera a ambos lados del emplazamiento del puente, y prueba de nuevo.
{Consejos: Usa la herramienta Eliminar para eliminar los puentes (pulsa en el inicio o final del puente) o alguno obstaculos que impiden la construccion del puente. Usa las distintas herramientas de Carreteras para conectar los lados del puente a tramos de carretera.}

Tunel(carretera): Herramientas para construir tuneles rectos, para vehiculos de carretera, entre dos puntos. Los tuneles no pueden estar en cuesta: los vehiculos entran y salen de ellos por accesos que estan a la misma altura.
La herramienta construye un tunel, en un final de carretera situado sobre una cuesta. Para construir un tunel: pulsa en la herramienta (el cursor cambia a un tunel),pulsa en un final de carretera situado sobre una cuesta para construir la entrada del tunel.
Si el tunel no puede encontrar una salida adecuada (una cuesta libre de obstaculos), el puente no se construira: construye carretera en ambos lados y prueba de nuevo.
{Consejos: Usa las Herramientas de Modelado del Terreno y la herramienta Eliminar para crear terreno adecuado para las entradas y salidas de tuneles. Usa las Herramientas de Carretera para conectar las salidas del tunel mediante carreteras.}

Señales y barreras: herramientas para construir señales y barreras, para vehiculos de carretera. Las señales y barreras diriguen y regulan el flujo de vehiculos en carreteras y puentes , y en cruces y paradas (donde se cargan y descargan mercancias y pasajeros. Se pueden construir versiones de sentido unico o doble de algunas señales.
IMPORTANTE: Ten cuidado con no situar señales de sentido unico que impidan a los vehiculos llegar a su destino, por defecto los vehiculos conducen por la derecha (se puede cambiar en el archivo simuconf.tab).
- Traffic lights (semaforos): herramientas para construir semaforos para regular el rafico en los cruces, permitiendo el paso o haciendo esperar un rato. Para construir un semaforo: Pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la carretera. Pulsa de nuevo en el cruce para cambiar la orientacion de los semaforos.
- Barrera de sentido unico: herramienta que construye una barrera para forzar el uso de dicho tramo en un solo sentido. Para construir una barrera: Pulsa en la herramienta para seleccionarla (el cursor cambia a una barrera); y despues pulsa en la carretera. Pulsa de nuevo en el tramo para cambiar la orientacion de la barrera.
- road closed: herramienta que construye un señal que evita que continuen los vehiculos por ese tramo. Para construir una barrera: Pulsa en la herramienta para seleccionarla (el cursor cambia a una barrera), despues sobre un punto del tramo deseado.
- no entry: herramienta que construye una señal que permite la circulacion por un unico sentido de la carretera(similar a una barrera de sentido unico. Para construir una señal: Pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la carretera. Pulsa de nuevo en el tramo para cambiar la orientacion de la señal.
- minimum 80km/h herramienta que construye una señal que evita que continuen los vehiculos cuyo limite de velocidad maximo este por debajo de 80km/h. Para construir una señal: Pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la carretera. Pulsa de nuevo en el tramo para cambiar la orientacion de la señal.
- Choose Point: dirigen los vehiculos a una Parada vacia, dentro de una Parada multiplataforma: un vehiculo que pasa por esta señal puede usar una parada vacia como proximo destino, y no justamente el que se le ha asignado en su Ruta. Si no hay Paradas vacias o una ruta clara hasta el proximo destino, el vehiculo esperara en la señal. Para construir una señal: Pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la carretera. Pulsa de nuevo en el tramo para cambiar la orientacion de la señal.
- Autopistas: (solo disponible en el pak128) herramientas para construir una señal que solo permita el paso de vehiculos en una sola direccion, si su limite de maxima velocidad es mayor de 80km/h.
Para construir una señal: Pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la carretera. Pulsa de nuevo en el tramo para cambiar la orientacion de la señal.
{Consejos: Elimina las cocheras mediante la herramienta Eliminar. Usa [Ctrl] al mismo tiempo para situar señales en los puentes sobre carreteras.}

Deposito de carretera: herramienta para construir una cochera para comprar y gestionar vehiculos de carretera.
Las cocheras tiene un coste de mantenimiento y deben construirse sobre el final de una carretera.
Para construir un deposito de carretera: pulsa en la herramienta (el cursor cambia a una cochera), y pulsa sobre el final de una carretera.
{Consejos: Elimina las cocheras mediante la herramienta Eliminar.}

Car Parking: (solo disponible en el pak 128) herramientas para construir extensiones para Paradas las cuales incrementan su capacidad y area de influencia para pasajeros y mercancias, asi como el coste de mantenimiento.
Para construir una extension: pulsa en la herramienta para seleccionarla (el cursor cambia a extension), despues pulsa en el lugar deseado de la carretera, junto a una Parada existente. La nueva extension es considerada ahora parte de la Parada.
{Consejos: Elimina las extensiones con la herramienta Eliminar.}

Paradas de carretera: herramientas para construir lugares donde los tranvias y los vehiculos de carretera cargan y descargan pasajeros, mercancias y correo.
Una parada de carretera, cuando no se construye adyacente a una Parada existente creara una nueva Parada Las paradas de carretera se construyen sobre carreteras y tienen un coste de mantenimiento y una area de influencia para mercancias, correo y pasajeros. En la esquina de algunos iconos de herramientas hay un pequeño icono (usado en Lista de Estaciones e Informacion de la Parada) que muestra que elementos puede manejar la Parada. Las diferentes Paradas de carretera pueden tener distintas capacidades para pasajeros, mercancia y correo.
Para construir una Parada de carretera: pulsa en la herramienta para seleccionarla (el cursor cambia a una Parada de carretera), despues pulsa en el lugar deseado de la carretera,
{Consejos: Elimina las paradas de carretera mediante la herramienta Eliminar.Manten pulsado [Ctrl] para construir puentes sobre carreteras. Las paradas de carretera no se pueden construir sobre carreteras que pertenezcan a otros jugadores. Puedes crear Paradas multiples para incrementar el area de influencia y la capacidad de las mismas.}

simutrans-124.3/simutrans/text/es/save.txt000066400000000000000000000043331474050137200206750ustar00rootroot00000000000000Ayuda de Guardar

Guardar

Guardar almacena la partida actual en un fichero (para continuar jugando mas tarde) y puede ser usado para borrar partidas guardadas.

Guardar se abre desde Opciones de Juego o presionando [S]; y muestra una lista con nombre, fecha y hora de las partidas guardadas.
Si no son visibles todas las partidas: usa la barra de desplazamiento en la parte derecha de la lista para desplazar los nombres.

La partida actual puede ser salvada en un nuevo fichero o en un fichero ya existente.
Para salvar en un fichero nuevo, introduce el nombre en la caja de texto de la parte superior de la ventana Guardar: pulsa en la caja de texto, introduce el nombre y pulsa [Enter] o [Return] o pulsa en OK; el nuevo fichero se mostrara en la lista.
IMPORTANTE: Si se usa un fichero listado, la partida antigua en reemplazada, por la partida actual y se pierde.

Por defecto, la partida actual aparece en la caja de texto Archivo, para salvar esta ultima en ese fichero: pulsa en OK (los datos antiguos se pierden y son reemplazados por los datos de la partida actual).
Para salvar una partida en un fichero de una partida antigua: pulsa en el nombre dentro de la lista (la partida antigua es reemplazada por la partida actual).

Los nombres de fichero pueden ser una combinacion de letras, numeros y simbolos con una longitud maxima de 57 caracteres; despues de salvar, solo se muestran 20 caracteres en las ventanas Guardar y Cargar.

CUIDADO: Pulsando en el boton X BORRARA LA PARTIDA DE FORMA INMEDIATA Y PERMANENTE, el fichero se elimina de la lista y la ventana Guardar se cierra. Use esta funcion con cuidado.

{Consejos: Reinicia un juego salvado desde la ventana Cargar.
Puedes cambiar la opcion de auto-guardado (guardado automatico de la partida) en el fichero simuconf.tab}.

Pulsa en Cancelar para cerrar la ventana Guardar; o en el boton X en la esquina superior izquierda; o usa el teclado.

simutrans-124.3/simutrans/text/es/schedule.txt000066400000000000000000000116071474050137200215350ustar00rootroot00000000000000Controles de Enrutar

Controles de Enrutar

Controles de Enrutar establece el programa de ruta (la ruta y la cantidad minima de mercancias y pasajeros requerida por un Convoy para continuar ) de un Convoy o una Linea.
Lista las Paradas (donde los Convoys cargan y descargan mercancias y pasajeros) y puntos de paso (que pueden ser usados para dirigir Convoys por un camino si hay mas de uno disponible o dar puntos intermedios hasta el destino) con sus coordenadas del mapa.

Controles de Enrutar para un Convoy se abre desde el boton Enrutar en la ventana Informacion del Convoy y en los Controles del Deposito.
Los controles para un programa de ruta de una Linea se abren desde los botones Nueva linea o Actualizar linea en Administracion de Lineas y en los Controles del Deposito.

Cuando los Controles de Enrutar se han abierto desde la ventana Informacion de Convoy la linea asignada (si tiene alguna) se muestra en lo alto de los controles.
Nombre de la linea : Pulsa en los botones de flechas para pasar de una linea a otra o pulsa en la caja de texto para desplegar un lista de Lineas (pulsa en una Linea de la lista para seleccionar).
Pulsa en la caja de texto y escribe un nuevo nombre para cambiar el nombre de la Linea.

Cargar (Min): establece la cantidad minima de mercancias y pasajeros que requiere el Convoy para continuar. El porcentaje se refiere a la capacidad total del Convoy y no de un tipo de mercancia individual.
Un Convoy esperara en la Parada hasta que se carge el porcentaje requerido.
Para usarlo: pulsa en la Parada en la lista para seleccionar (> por nombre muestra que esa Parada ha sido seleccionada), entonces usa las flechas para cambiar el porcentaje.
{Consejos: para establecer o cambiar la Carga (Min) para todos los Convoys de una Linea, usa el boton Actualizar la linea en Administracion de Listas o en Controles del Deposito. Para cambiar ls Carga de un Convoy y no el resto de los de la Linea, usa la opcion Enrutar en Informacion del Convoy o en Controles de Deposito.}

Los botones de opcion (pulsa para usar, el boton se oscurece cuando se selecciona) incluyen:

Añadir Parada: esta opcion pone una Parada usada por vehiculos para cargar y descargar mercancias y pasajeros (los vehiculos de transporte maritimo pueden usar cualquier cuadricula de agua en el area de influencia del puerto) o un punto de paso en la ruta.
Para añadir una Parada o Punto de paso: pulsa en la opcion a seleccionar (cambia el cursor a un cartelito), entonces pulsa en el punto requerido para la Parada o Punto de paso (un punto en la carretera, via de tren o agua segun el tipo de vehiculo). La Parada o Punto de paso , es listada en Enrutar.
{Consejos: Los vehiculos no cargan ni descargan pasajeros ni mercancias en los Puntos de paso.}

Insertar: esta opcion pone una Parada o punto de paso en la ruta, antes que una Parada/Punto de paso ya existente.
Para insertar una Parada/Punto de paso: pulsa en una parada/punto de paso existente de la lista para seleccionar (se muestra > en el nombre de la parada/punto de paso seleccionado), despues pulsa en el boton Insertar (cambia el cursor a un cartelito), y finalmente pulsa en el punto requerido de un Parada/punto de paso (un punto de una carretera,via de tren o agua segun el tipo de vehiculo).
La nueva Parada/Punto de paso aparecera en la lista de Enrutar antes de la Parada/Punto de paso previamente seleccionado.
{Consejos: Los vehiculos no cargan ni descargan pasajeros ni mercancias en los Puntos de paso.}

Eliminar: esta opcion borra una Parada o Punto de paso de la ruta.
Pulsa en el boton Eliminar, y despues pulsa en un elemento de la lista para eliminarlo.

Viaje de vuelta: esta opcion añade las Paradas y Punto de paso existentes en orden inverso a la ruta. Los niveles de Carga (Min) tambien se copian. Pulsa en el boton de opcion para usar: Enrutar lista la nueva ruta.

Convertir en Linea: (solo disponible cuando se abre Enrutar desde la ventana Informacion de Convoy) creando una nueva Linea usando el programa actual de ruta. La nueva linea se le asigna un numero y se lista en Administracion de Lista.

simutrans-124.3/simutrans/text/es/shiptools.txt000066400000000000000000000146561474050137200217740ustar00rootroot00000000000000Ayuda de Herramientas de Barcos/Puertos

Herramientas de Barcos/Puertos

Herramientas de Barcos/Puertos construye una red de transporte maritima y fluvial. La herramientas pueden construir o eliminar: canales, esclusas, puertos varios, y astilleros . Si estas jugando con cronologia, a medida que pase el tiempo apareceran mas herramientas y opciones.

Pulsa en el boton de Barco en la parte superior de la pantalla para abrir la barra de herramientas.
Situa el cursor sobre los botones (despues de abrir o pulsar en la barra de herramientas) para ver el nombre y el coste: coste de construccion, entre parentesis el coste de mantenimiento maintenance cost in brackets, y el limite de velocidad.

Herramientas de Barcos/Puertos incluye, de izquierda a derecha:

Canal: construye canales, para barcos y barcazas, entre dos puntos.
Los canales solo se pueden construir en cuestas, en la direccion de la cuesta y puede no ser posible crear el camino si el terreno es escarpado. Los canales construidos entre puntos, pueden usar otros canales en su camino.
Para construir un canal: pulsa en la herramienta para seleccionar (el cursor cambia de forma, a un canal), despues pulsa en el terreno para el punto de inicio (muestra una bulldozer y las coordenadas del punto en la parte derecha de la barra inferior de la pantalla), y pulsa de nuevo para establecer el punto final.
{Consejos: Los canales construidos por diferentes jugadores no se conectan. Usa las Herramientas del Terreno para cambiar el terreno, para habilitar los caminos para canales. Usa la herramienta Eliminar para eliminar partes individuales del canal y algunos obstaculos. Deshacer la ultima ruta mediante la tecla [z] no reembolsa los costes de construccion.}

Remove channels: herramienta que elimina una parte del canal, cuando no hay vehiculos, entre dos puntos (ATENCION: Las paradas en el canal se eliminan tambien). La herramienta tiene asociados costes de construccion.
Para eliminar un canal: pulsa en la herramienta (el cursor cambia de forma, una cruz); despues pulsa en el canal a eliminar (en el punto seleccionado se muestra una cruz roja); y por ultimo pulsa en otro punto del canal, removiendo dicha parte del canal hasta el punto inicial.

Puente levadizo: herramienta que construy una esclusa y un puente levadizo para elevar/descender un barco o barcaza a otro nivel en un canal. El puente tiene un tamaño maximo y se construye al final del canal, en un lugar adecuado (otro canal en terreno elevado, sin limite).
Para construir un puente: pulsa en la herramienta para seleccionar puente levadizo (el cursor cambia de forma, un puente), pulsa en el final del canal. Algunos obstaculos o la falta de espacio adecuado para el final de puente puede hacer que no se construya: construye un canal a ambos lados para crear el puente levadizo, y prueba de nuevo.
{Tips: Use Destroy/Remove to remove bridges (click on hoist-end) & some obstructions to bridge building.
Use Canal tools to connect bridge-ends to water ways.}.

ChannelStop (Canal Quay en pak128) herramienta que construye un puerto en un canal para transporte fluvial, cargando y descargando mercancias y pasajeros.
La Parada del Canal, cuando no es contruida adyacente a una Parada existente, creara una nueva parada.
La Parada del Canal tiene un area de influencia para mercancias, pasajeros y correo. La esquina del icono de la herramienta es un mini icono que (usado en la Lista de Estaciones y en la ventana de Informacion de la Parada) muestra que elementos permite manejar la Parada del Canal, a una parada.
Para construir un Parada de Canal: pulsa en la herramienta (el cursor cambia de forma, una Parada del Canal); despues pulsa en un canal para cosntruir.
{Consejos: Elimina las Paradas de Canal con la herramienta Eliminar. Pulsa la tecla [v] para mostrar/ocultar el area de influencia para mercancias y pasajeros.
La paradas para vehiculos maritimos y fluviales no se listan en la Lista de Paradas/Estaciones}.

Ship-stops/Puertos: herramientas que construyen varios elementos de puertos para vehiculos maritimos y fluviales, para descargar y cargar mercancia y pasajeros.
Los puertos se construyen en los bordes de la costa.
Un puerto, cuando no es construido adyacente a una Parada existente, creara una nueva parada.
La Parada del Canal tiene un area de influencia para mercancias, pasajeros y correo. La esquina del icono de la herramienta es un mini icono que (usado en la Lista de Estaciones y en la ventana de Informacion de la Parada) muestra que elementos permite manejar el puerto, a una parada. Los diferentes puertos pueden tener diferente capacidad para mercancias, pasajeros y correo.
Para construir un puerto: pulsa en la herramienta seleccionada (el cursor cambia de forma, un puerto) y despues pulsa en una zona de la costa, cerca del agua
{Consejos: Elimina los puertos mediante la herramienta Eliminar.
El tamaño de los puertos se puede aumentar, construyendo en cuadriculas adyacentes. Los transportes maritimos pueden usar cualquier cuadricula del agua dentro del area influencia de un puerto.
Las Paradas maritimas no aparecen en la Lista de Estaciones/Paradas.
La Industria maritima tal como Plataformas Petroliferas no requieren un puerto, los vehiculos maritimos pueden usar cualquier cuadricula dentro del area de influencia de una Industria maritima.
Pulsa la tecla [v] para mostrar/ocultar el area de influencia para mercancias y pasajeros.}

Astillero: herramienta que construye un astillero para comprar y administrar barcos, barcas y barcazas. Los Astilleros tiene costes de mantenimiento y se construyen en el agua, cerca de la costa.
Para construir un Astillero: pulsa en la herramienta (el cursor cambia de forma, un astillero), y despues pulsa en el agua, en un lugar cercano a la costa.
{Consejos: Elimina los Astilleros mediante la herramienta Eliminar.}

simutrans-124.3/simutrans/text/es/simutrans.txt000066400000000000000000000045151474050137200217660ustar00rootroot00000000000000Simutrans

Bienvenido a Simutrans...

Eligue uno, entre los miles, de los terrenos de Simutrans. Despues ponte en la piel de un joven emprendedor con algo de dinero de la herencia de tus abuelos: se ambicioso para que se sientan orgullosos, con ansias de crear una exitosa empresa de transportes, tu desafio es crear una empresa prospera.

A medida que pasa el tiempo, deberas convertir tu empresa en un imperio del transporte, manteniendo la contabilidad sobre ruedas gracias a la entrega de la carga y a la satisfaccion de los deseos de viajar de millones de pasajeros cada mes.
Transporta pasajeros, correo y mercancias por tren, carretera, mar e incluso por aire.

Cada terreno tiene algo diferente que ofrecer. Echa un vistazo a los alrededores...su futuro esta en tus manos y las de tus competidores.

Como comienzo, puede ser mas facil empezar suministrando mercancias a la Central Energetica. Despues, conecta otras fabricas, tal vez usando paradas intermedias donde cargar las mercancias.
La desventaja de transportar solo mercancias es que los pueblos y ciudades no creceran y no se crearan nuevas industrias.

Alternativamente, puedes ir a por el transporte de pasajeros (y correo). Esto es un desafio mayor, ya que los habitantes de este mundo quieren viajar a las localizaciones que ellos han eleguido.
Algunos necesitan ir a las fabricas para trabajar, otros quieren ir a comprar a centros comerciales en la ciudad principal y otros quieren hacer turismo.

Si no les das una conexion a su destino, no viajaran contigo de ninguna forma. Necesitaras construir redes de transporte. Cuando hayas establecido dichas redes, necesitaras actualizarlas para ajustarlas a la demanda. Asi que planifica un poco antes.
Si a los pasajeros les gusta tu servicio, las cuidades creceran y se crearan nuevas industrias, y solo asi la economia ira sobre ruedas.

Puedes jugar tanto como quieras . Empieza en 1880 y termina en 2050, si lo deseas. En cada epoca tendras disponibles nuevos vehiculos y edificios.
Juega contra la IA o tu solo. Solo si estas en numeros rojos durante tres meses, llegaras a la bancarrota y el juego terminara.

El Equipo de Simutrans y la Comunidad de usuarios desean que pases un buen rato aqui en Simutrans...

simutrans-124.3/simutrans/text/es/slopetools.txt000066400000000000000000000040141474050137200221360ustar00rootroot00000000000000Ayuda de Herramientas del Terreno - elevar/bajar el terreno

Herramientas del Terreno

Herramientas del Terreno eleva y baja el terreno y puede ser usado para crear lugares adecuados para la construccion.

Pulsa en el icono del terreno en cuesta, en la parte superior de la pantalla para abrir la barra de herramientas.
Pon el cursor encima, despues de abrir o pulsar en la barra de herramientas, sobre una herramienta para ver el nombre y los costes de construccion.

Las herramientas se utilizan en areas vacias con obstrucciones (e.g. carretras, vias, edificios, paradas y estaciones).

Pulsa en la herramienta para seleccionar, el cursor cambiara, despues posiciona el cursor en el terreno y pulsa en el mismo para usar:

Elevar terreno/Rebajar terreno: eleva/rebaja el terreno
El cursor es una flecha hacia arriba o hacia abajo.
Las herramientas tambien se pueden abrir pulsando [u] y [d].

Pendientes: crea una pendiente, en la direccion indicada por la herramienta. Se puede crear una superficie vertical durante el proceso.
El cursor el un cubo amarillo solo con lineas que posiciona la pendiente.

Cuadrado elevado/rebajado: rebaja/eleve un cuadrado de terreno especifico. Se puede crear una superficie vertical durante el proceso.
El cursor el un cubo amarillo solo con lineas que selecciona la pendiente.

Restaurar pendiente natural: devuelve el terreno a su estado natural, eliminando las superficies artificiales verticales durante el proceso.
El cursor el un cubo amarillo solo con lineas que posiciona la pendiente.

{Consejo: Las herramientas del Terreno son faciles de usar con la cuadricula, presiona [#] y acerca el zoom.
Usa la herramienta Eliminar para eliminar algunos obstaculos.
Dependiendo del mapa, las herramientas puede elevar el terreno dentro o fuera del agua.}

simutrans-124.3/simutrans/text/es/sound.txt000066400000000000000000000016161474050137200210700ustar00rootroot00000000000000Ayuda sobre Ajustes de Sonido

Ajustes de Sonido

Ajustes de Sonido tiene controles para los efectos de sonido y la musica.

Ajustes de Sonido se abre desdeOpciones de Juego.

Use las flechas para ajustar los parametros o la barra de desplazamiento para subir/bajar el volumen:

Volumen de los efectos: establece el volumen de los efectos de sonido en el juego.

Volumen de la Musica: establece el volumen de la musica. Si no esta disponible, el control no funcionara.

Jugadores actuales: cambia la musica; las flechas saltan a la siguiente/anterior cancion entre las disponibles.

ATENCION: El juego no incluye archivos de musica.
Ayuda a crear musica para el juego en http://wiki.simutrans.com

simutrans-124.3/simutrans/text/es/special.txt000066400000000000000000000152531474050137200213620ustar00rootroot00000000000000Ayuda de Herramientas Especiales de Construccion

Herramientas Especiales de Construccion

Herramientas Especiales de Construccion construye elementos que no tienen relacion con el trafico y tambien permite jugar como otro jugador en el juego.

Pulsa en el icono de punto rojo dentro del circulo amarillo (el icono de la grua en el pak128) en la barra de la parte superior de la pantalla para abrir la barra de herramientas.
Situa el cursor sobre cada icono (despues de abrir o pulsar en la barra de herramientas) para ver el nombre y los costes de construccion.

Herramientas Especiales de Construccionincluye, de derecha a izquierda:

Post Office: herramientas para construir una oficina postal que permite a una Parada manejar correo. Las oficinas postales incrementan la capacidad y el area de influencia de una Parada y acarrean un coste de mantenimiento.
Para construir una oficina postal: pulsa en la herramienta seleccionada, despues pulsa en una para existente. La nueva oficina postal se considerara parte de la Parada.
{Consejos: Elimina las oficinas postales y los obstaculos mediante la herramienta Eliminar.}

Extensiones de Estacion: herramientas para construir edificios y extensiones para Paradas. Las extensiones pueden incrementar la capacidad y el area de influencia para pasajeros y mercancias, asi como el coste de mantenimiento. En la parte superior de algunos botones de herramienta aparece un mini icono (usado en la Lista de Estaciones y en la ventan de Informacion de la Parada) que muestra que elemento puede gestionar la parada, gracias a la extension.
Para construir una extension: pulsa en la herramienta seleccionada (el cursor cambia de forma, un extension), despues pulsa en la posicion deseada, junto a una parada existente. La nueva extension sera considerada parte de la Parada.
{Consejos: Elimina las extensiones con la herramienta Eliminar.}

P+ Cambiar de Jugador: permite jugar como otro jugador si la opcion Permitir cambio de jugador fue seleccionada en el comienzo de la partida. Las opciones extra estan disponibles jugando como jugador servicio publico.
Pulsa en la herramienta (o pulsa la tecla [P]) para cambiar de jugador. Aparecera un mensaje de confirmacion, notificando que el cambio de jugador: pulsa en la x de la parte superior de la ventana del mensaje o pulsa Esc para cerrar el mensaje.

Fundar nueva ciudad: herramienta que establece una nueva ciudad.
Para fundar una nueva ciudad: pulsa en la herramienta o pulsa la tecla [C] (el cursor cambia de forma, un ayuntamiento), y despues pulse en la posicion deseada. La nueva ciudad cuesta 5 milliones de credits y sera construida sin requerir confirmacion.
{Consejos: Pulsa en el ayuntamiento con la herramienta Eliminar para eliminar los edificios de la ciudad.}

Plantar un arbol: herramienta que planta un arbol.
Para plantar un arbol: pulsa en la herramienta seleccionada (el cursor cambia de forma, un arbol), y despues pulsa en la posicion deseada.
{Consejos: Elimina arboles con la herramienta Eliminar.}

Construir tendido electrico: herramienta que construye tendido electrico entre subestaciones transformadoras, centrales electricas e industrias (para aumentar la productividad). El suministro de energia electrica genera ingresos. Las lineas de tendido electrico no se pueden cruzar en diagonal con vias ni carreteras.
Para construir una linea de tendido electrico: pulsa en la herramienta o pulsa la tecla [l] (el cursor cambia de forma, un torre de tendido electrico), y despues pulsa en una subestacion transformadora situada junto a una central electrica. Por ultimo pulsa en la subestacion transformadora de una industria para suministrar energia electrica, para aumentar la produccion.
{Consejos: El tendido electrico se puede construir por etapas, pulsando en los lugares deseados del terreno. Elimina el tendido electrico mediante la herramienta Eliminar.}

Subestacion transformadora herramienta que construye una subestacion transformadora en centrales electricas o en industrias para conectar las lineas de tendido electrico.
Para construir una subestacion: pulsa el icono o la tecla [g] (el cursor cambia de forma, un circulo amarillo con un punto rojo), despues pulsa en el lugar deseado cerca de una central electrica o una industria.
Las subestaciones construidas junta a Centrales deben estar conectadas con otras subestaciones de industrias mediante tendido electrico para poder suministrar energia.
Si no se suminustra electricidad, la subestacion mostrara un rayo amarillo, cuando haya suministro aparecera un rayo rojo.
{Consejos: Las industrias y las Centrales electricas pueden tener varias subestaciones para incrementar la capacidad de suministro. Elimina las subestaciones mediante la herramienta Eliminar.}

Marcador: herramienta que abre los controles para situar un marcador con texto personalizado que puede usarse para mover la vista del juego a diferentes puntos.
Pulsa el icono o la tecla [M], el cursor cambiara a un marcador de texto, despues pulsa en el lugar deseado para abrir los controles del Marcador. En la parte superior de los controles estan las coordenadas de la posicion seleccionada en el mapa, ademas de una caja de texto vacia, introduce el texto deseado en la caja de texto (pulsa en la caja, escribe el texto y pulsa en OK ,[Enter] o [Return]) para situar el marcador. El nuevo marcador se mostrara en el juego y se listara en los controles de Marcador (junto con las coordenadas) cuando reabras los controles.
Para mover la vista del juego a un marcador: Abre los controles de Marcador y pulsa en la posicion deseada dentro de la lista.
Para eliminar un Marcador: pulsa en la herramienta Marcador o la tecla [M], el cursor cambiara a un marcador de texto; despues pulsa en las coordenadas del marcador a borrar; finalmente pulsa en Remove dentro de los controles de Marcador.
Para cerrar los controles de marcador: pulsa en la X de la parte superior izquierda de la ventana de los controles; o pulsa Cancel; o usa el teclado.
{Consejos: Las coordenadas del cursor se muestran en la parte izquierda de la barra inferior. Usa [!] para mostrar los textos de los marcadores en la vista del juego}

simutrans-124.3/simutrans/text/es/station.txt000066400000000000000000000200171474050137200214150ustar00rootroot00000000000000Informacion de la Parada

Informacion de la Parada

Informacion de la Parada da informacion acerca de una Parada (donde los vehiculos cargan y descargan mercancias y pasajeros). Tambien tiene controles para acceder a mas opciones y cambiar el nombre de la Parada.

Una Parada consiste en un lugar donde un Convoy puede cargar y descargar pasajeros y mercancias y una serie de edificios de extension.

Las herramientas para construir los lugares donde los Convoys pueden cargar o descargar estan disponibles en la respectiva barra de herramientas segun el tipo de transporte: estaciones/plataformas; paradas de monorail/maglev; Paradas de Tranvia; Paradas de carretera; Muelles ; y Aeropuertos.
{Consejos: los transportes maritimos pueden usar cualquier cuadricula en el agua dentro del area de influencia de un muelle, para cargar y descargar mercancias y pasajeros. Se pueden construir paradas mas grandes construyendo en cuadriculas adyacentes. Las paradas pueden construirse para uso de mas de un tipo de transporte}.

Pulsa en una Parada con la Herramienta Explorar o pulsa en una Parada listada en la Lista de Estaciones o en Administracion de Lineas para abrir la ventana Informacion de la Parada que muestra el nombre de la Parada como titulo de la ventana.
Informacion de la Parada contiene una caja de texto con el nombre; un mini vista de la Parada; informacion acerca de la Parada; botones de opcion; y una lista de todos los elementos preparados para transportar en la Parada (si no son visibles todos los elementos ajusta el tamaño de la ventana Informacion de la Parada o usa la barra de desplazamiento):

Nombre: nombre asignado a la Parada, que se muestra en una caja de texto en la parte superior de la ventana Informacion de la Parada.
Por defecto, el nombre se asigna automaticamente cuando se construye por primera vez y depende de la ciudad relacionada con la Parada y cualquier industria dentro del area de influencia de la Parada.
Para cambiar el nombre: pulsa en la caja de texto del nombre y teclea uno nuevo.
{Consejos: Usa la tecla [!] para mostrar la vista del nombre sobre la Parada. Usa la tecla [v] para mostrar el area de influencia de la Parada. La opcion de numerar las paradas esta disponible en el archivo simuconf.tab}

barra de estado de color: los colores indican el estado operativo de la Parada en relacion a como de abarrotada esta. La barra de estado de color se usa tambien en la Lista de Estaciones y en Administracion de Lista, y se muestra el mismo color en la barra sobre la Parada:
- amarillo: fuera de servicio.
- verde: no se necesitan mejoras.
- naranja: las mejoras son posibles.
- rojo: se recomiendan mejoras.
{Consejos: Usa la tecla [!] para mostrar la barra de estado de color(indica como de saturada esta la Parada) sobre la Parada.}

Iconos graficos tambien usado en la Lista de Estaciones y Administracion de Lista:
- icono(s) de carga indica que elementos (pasajeros, mercancias y correo) puede manejar una Parada.
{Consejos: añadiendo las extensiones apropiadas se puede cambiar la categoria de las mercancias que puede manejar una Parada. Las Oficinas de Correo se pueden añadir a las paradas para manejar correo}.
- icono(s) de vehiculos indica que tipos de vehiculos pueden usar la Parada. Los iconos incluidos: autobus (para pasajeros), camion (para mercancias), tren (por via ferrea), barco y avion. Los tranvias se indican mediante el icono del autobus o del tren dependiendo del tipo de Parada.

Capacidad de almacenamiento: cantidad de carga de cada tipo (mercancias, pasajeros y correo) que se puede almacenar en la Parada.

Dibujo de la Parada: es una mini vista de la Parada y cualquier convoy visible.
Pulsa en el dibujo para centrar la vista del juego en la Parada.

Pasajeros cifras que indican la cantidad de pasajeros que inician su viajes en dicha Parada:
- cara feliz indica el numero de pasajeros, que han llegado a una parada no saturada como resultado de su area de influencia, han encontrado una ruta a su destino y esperan transporte.
- cara triste indica el numero de pasajeros que han llegado a una Parada como resultado de su area de influencia, pero no esperan transporte porque la Parada esta Saturada.
- sin ruta indica el numero de pasajeros que han llegado a una Parada como resultado de su area de influencia, pero no encuentran una ruta a su destino.
{Consejos: Mantener a los pasajeros contentos ayuda al crecimiento de las ciudades. Se puede cambiar el numero maximo de intercambios permitidos para los pasajeros y las mercancias en el archivo simuconf.tab}.

Pasajeros/mercancia esperando: lista la carga que esta esperando por transporte en la Parada por grupos: pasajeros; correo; y tipo de mercancias.
La informacion de la carga que se muestra incluye cantidad, tipo, destino final y primera Parada intermedia.
Los botones de opcion (el nombre cambia cuando lo pulsas) ordena la carga en gtupossorts of items within groups:
- destino: ordena elementos, alfanumericamente (mayusculas antes que minusculas), por el nombre de la Parada destino final.
- via (detalle): ordena elementos, alfanumericamente (mayusculas antes que minusculas), por el nombre de la primera Parada intermedia.
- via (cantidad): ordena elementos por cantidad dirigida a la primera Parada intermedia.
- cantidad: ordena elementos por cantidad en orden descendente.
{Consejos: las barras de color de mercancias sobre la Parada (usa la tecla [!] para mostrar) indica la cantidad de elementos que esperan transporte y tienen el mismo color que los cuadrados de color en la Lista de Mercancias.}

Grafica: pulsa en el boton de opcion para mostrar el grafico (el boton se oscurece cuando el grafico esta visible) en la ventana Informacion de la Parada.
La grafica muestra las estadisticas de los ultimos 12 meses (eje x) cuando la opcion grafico esta seleccionada.
Pulsa en el boton grafico para ver la informacion en el grafico ((el boton se oscurece cuando el grafico esta visible).
El color de las lineas en el grafico se corresponde con el color de los botones de opcion:
- Felices indica el numero de pasajeros, que han llegado a una parada no saturada como resultado de su area de influencia, han encontrado una ruta hacia su destino y esperan transporte.
- Descontentos indica el numero de pasajeros, que han llegado a una parada como resultado de su area de influencia pero no esperan transporte porque estaba saturadad.
- Sin ruta indica el numero de pasajeros, que han llegado a una parada como resultado de su area de influencia pero no encuentran una ruta hacia su destino .
- En espera: cantidad de pasajeros y mercancias que esperan transporte en una Parada.
- Llego: cantidad de pasajeros y mercancias descargadas por un Convoy en una Parada que es destino final o intermedio.
- Partio: cantidad de pasajeros y mercancias cargadas por un Convoy en una Parada.
- Vehiculos: cantidad de vehiculos que han pasado por la Parada.

Detalles: boton de opcion que abre la ventana Detalles de la Parada y da mas informacion acerca de la Parada.

simutrans-124.3/simutrans/text/es/station_details.txt000066400000000000000000000032271474050137200231260ustar00rootroot00000000000000Detalles de la Parada

Detalles de la Parada

Detalles de la Parada da mas informacion acerca de una Parada (donde los vehiculos cargar y descargan pasajeros y mercancias).

Detalles de la Parada se abre desde el boton Detalles en la ventana de Informacion de la Parada.
Si no son visibles todos los elementos ajusta la ventana Detalles de la Parada o usa la barra de desplazamiento para desplazar los nombres)

La informacion listada incluye:
Industrias conectadas: nombres y coordenadas del mapa (entre parentesis) de industrias en el area de influencia de la Parada.
{Consejos: Usa [v] para mostrar el area de influencia de las paradas.}

Industrias cercanas demandan: tipos de mercancias requeridas por las industrias dentro del area de influencia de la Parada.

Lineas sirviendo a esta parada: Lineas que usan esta Parada.
Las lineas son listadas en orden alfanumerico (mayusculas antes que minusculas).

Paradas conectadas directamente :lista los nombres de Paradas que pueden se alcanzadas sin realizar un transbordo o cambio del tipo de mercancias o pasajeros.
Las paradas son listadas en orden alfanumerico (mayusculas antes que minusculas) en el caso de tipo de transporte, nombre de la Parada, y tipo de elemento que puede ser descargado (se muestra tambien para cada Parada).

simutrans-124.3/simutrans/text/es/tramtools.txt000066400000000000000000000217201474050137200217620ustar00rootroot00000000000000Ayuda de Herramientas de Tranvia/tren ligero

Herramientas de Tranvia/tren ligero

Herramientas de Tranvia/tren ligero contruye una red de transporte con tranvias. Las herramientas pueden construir: vias de trnvia (y electrificarlas o eliminarlas), señales, cocheras de tranvia, y paradas de tranvia. Si estas jugando con cronologia, a medidad que pase el tiempo iran apareciendo nuevas opciones.

Pulsa en el icono del tranvia en la barra de la parte superior de la pantalla para abrir la barra de herramientas.
Situa el cursor sobre los iconos (tras abrir la barra de herramientas) para ver el nombre y demas datos: costes de construccion, y limite de velocidad maxima .

Herramientas de Tranvias/tren ligero incluye, de izquierda a derecha :

Vias de tranvia: herramientas para construir vias, para vehiculos que van por railes entre dos puntos.
Las vias de tranvia se pueden construir sobre carreteras y en ciudades, pero no en areas ocupadas por otros edificios. Las vias solo se pueden construir en cuestas en la misma direccion de la cuesta y no sobre terreno escarpado, agua u obstaculos. Las nuevas vias pueden usar tramos de vias ya existentes en su camino.
Para construir una via: pulsa en la herramienta para seleccionarla (el cursor cambia a una via); despues pulsa en el terreno para establecer el punto de partida de la via (se muestra una excavador y las coordenadas del punto en la barra de la parte inferior de la pantalla); y por ultimo pulsa en el terreno para establecer el punto final del tramo de via.
{Consejos: Los diferentes tipos de via se pueden conectar (siempre que no pertenezcan a otros jugadores). Usa los puentes y tuneles para conectar vias a traves de terreno escarpado o para evitar obstaculos. Usa la herramienta Eliminar para eliminar partes individuales de un tramo de via asi como obstaculos. Manten pulsado [Ctrl] al mismo tiempo para obtener funciones extra. Deshacer [z] no reembolsa los costes de construccion.}

Via electrificada: herramientas para electrificar vias, puentes o tuneles entre dos puntos, para uso de vehiculos electricos.
Para electrificar una via: pulsa en la herramienta para seleccionarla o la tecla [e] (el cursor cambia a un icono de un rayo), despues pulsa en una via para establecer el punto de inicio de la electrificacion (situa un icono de via electrificada en dicho punto), y por ultimo pulsa en otro punto para establecer el punto final, electrificando el tramo entre ambos puntos.
{Consejos: Usa la herramienta Eliminar para quitar la electrificacion de la via.}

Remove Tracks: herramienta que elimina vias normales y electrificadas, cuando no hay vehiculos presentes, entre dos puntos (las estaciones, paradas, señales, tuneles y puentes en el camino tambien se eliminan). El uso de esta herramienta conlleva costes de construcion.
Para eliminar un via: pulsa en la herramienta para seleccionarla (el cursor cambia a una cruz roja); despues pulsa en la via que vas a borrar (en el punto seleccionado se muestra una cruz roja); y por ultimo pulsa en un segundo punto que este conectado con el primero, eliminando el tramo de via entre ambos.
{Consejos: Deberas cambiar de jugador para eliminar vias de otros jugadores.}

Señales: herramientas que construyen señales para vehiculos sobre railes en una via. Las señales dirigen y regulan el flujo de los vehiculos en vias, puentes, cruces y Paradas (donde los vehiculos cargan y descargan pasajeros y mercancias).
Se pueden construir versiones de sentido unico y doble. Para construir una señal de doble sentido en una via: pulsa en la herramienta para seleccionarla (el cursor cambia a una señal); y despues pulsa en la via. Para construir una señal de sentido unico: pulsa de nuevo en el mismo punto, con el cursor de señal, para pasar de un tipo de señal a otro .
IMPORTANTE: Ten cuidado con no situar señales de sentido unico que impidan a los vehiculos llegar a su destino, por defecto los vehiculos conducen por la derecha (se puede cambiar en el archivo simuconf.tab).
- Señales: los vehiculos prosiguen solo si el tramo hasta la siguiente señal o destino en la Ruta (una Parada o punto de paso) no esta ocupado por otro vehiculo. En el modo de sentido unico los vehiculos solo van en una direccion.
- RailClose: los vehiculos no prosiguen mas alla de la señal (solo disponible en modo de sentido unico).
- PreSignals: los vehiculos prosiguen si el area (entre tres señales consecutivas o hasta el proximo destino en la Ruta) no esta ocupado por otro vehiculo. En el modo de sentido unico los vehiculos solo van en una direccion.
- ChooseSignals: dirigen los vehiculos a una estacion vacia, dentro de una Parada multiplataforma: un vehiculo que pasa por esta señal puede usar una estacion vacia como proximo destino, y no justamente el que se le ha asignado en su Ruta. Si no hay estaciones vacias o una ruta clara hasta el proximo destino, el vehiculo esperara en la señal.
{Consejos: elimina las señales con la herramienta Eliminar. Manten pulsado [Ctrl] para situar señales en puentes sobre vias.}

Cochera de Tranvia: herramienta para construir una cochera para comprar y gestionar tranvias.
Las cocheras tiene un coste de mantenimiento y deben construirse sobre el final de una via.
Para construir una cochera de tranvia: pulsa en la herramienta (el cursor cambia a una cochera), y pulsa sobre el final de una via.
{Consejos: Las cocheras solo muestran los vehiculos electricos si estan sobre una via electrificada. Elimina las cocheras con la herramienta Eliminar.}

Paradas sobre vias: herramientas para construir estaciones, usadas por vehiculos sobre vias para cargar y descargar mercancias, pasajeros y correo.
Una estacion, cuando no se construye adyacente a una Parada existente creara una nueva Parada.
Las Paradas sobre vias tienen un coste de mantenimiento y se construyen sobre vias (pero no en curvas ni cruces).
Las Paradas sobre vias tienen un area de influencia para mercancias, pasajeros y correo. Las diferentes estaciones tienen distintas capacidades para pasajeros y correo. En la esquina de algunos iconos de herramientas hay un pequeño icono (usado en Lista de Estaciones e Informacion de la Parada) que muestra que elementos puede manejar la Parada.
Para construir una estacion: pulsa en la herramienta para seleccionarla (el cursor cambia a una estacion), y despues pulsa en la via.
{Consejos: Elimina las paradas en via mediante la herramienta Eliminar. Extiende las estaciones y construye estaciones multiples (construyendo varias secciones de estacion en vias adyacentes) para acomodar mas vehiculos y mas largos, incrementando la capacidad y el area de influencia para pasajeros y mercancias. Manten pulsado [Ctrl] para construir puentes sobre vias.}

Car Parking: (solo disponible en el pak 128) herramientas para construir extensiones para Paradas las cuales incrementan su capacidad y area de influencia para pasajeros y mercancias, asi como el coste de mantenimiento.
Para construir una extension: pulsa en la herramienta para seleccionarla (el cursor cambia a extension), despues pulsa en el lugar deseado de la carretera, junto a una Parada existente. La nueva extension es considerada ahora parte de la Parada.
{Consejos: Elimina las extensiones con la herramienta Eliminar.}

Paradas de carretera: herramientas para construir lugares donde los tranvias y los vehiculos de carretera cargan y descargan pasajeros, mercancias y correo.
Una parada de carretera, cuando no se construye adyacente a una Parada existente creara una nueva Parada Las paradas de carretera se construyen sobre carreteras y tienen un coste de mantenimiento y una area de influencia para mercancias, correo y pasajeros. En la esquina de algunos iconos de herramientas hay un pequeño icono (usado en Lista de Estaciones e Informacion de la Parada) que muestra que elementos puede manejar la Parada. Las diferentes Paradas de carretera pueden tener distintas capacidades para pasajeros, mercancia y correo.
Para construir una Parada de carretera: pulsa en la herramienta para seleccionarla (el cursor cambia a una Parada de carretera), despues pulsa en el lugar deseado de la carretera,
{Consejos: Elimina las paradas de carretera mediante la herramienta Eliminar.Manten pulsado [Ctrl] para construir puentes sobre carreteras.}

simutrans-124.3/simutrans/text/es/window.txt000066400000000000000000000127561474050137200212560ustar00rootroot00000000000000Ayuda de Interfaz/Ventana del juego

Interfaz/Ventana del juego

Simutrans se juega mediante una Interfaz/Ventana del juego que da informacion acerca de la partida actual; acceso a los controles y herramientas del juego; y una vista del mundo de la partida actual.

Barra de titulo: la parte izqierda de la barra de titulo de la Interfaz/Ventana del juego muestra la version y la fecha de creacion de la version de Simutrans que estas usando.
La parte derecha de la barra de titulo tambien tiene controles para minimizar, maximizar la Interfaz/Ventana del juego y tambien para salir de Simutrans. Esta barra se muestra solo cuando no estas jugando en modo pantalla completa

Iconos: una fila de iconos, usados para acceder a las herramientas y controles del juego mientras estas jugando a Simutrans, Esta justo debajo de la barra de titulo. Los iconos (pulsa para usarlos) estan agrupados en tres conjuntos:

- Los iconos del Menu principal, que incluyen:
- Disco floppy: abre las Ociones de juego
- Mapa: abre el Mapa
- Lupa selecciona la herramienta Explorar
- Icono de la cuesta: abre las herramientas del Terreno
- Tren: abre las herramientas de trenes y vias
- Monorail/maglev: abre la barra de herramientas de monorail
- Tranvia: abre la barra de herramientas de tranvia
- Camion: abre la barra de herramientas de transporte por carretera
- Barco: abre la barra de herramientas de transporte maritimo
- Avion: abre la barra de herramientas de transporte aereo
- Punto rojo en circulo amarillo (icono de grua en el pak128): abre la barra de herramientas especiales
- Cruz roja (icono de bulldozer en pak128): selecciona la herramienta Eliminar

- Los iconos de Administracion, que incluyen:
- Icono de lineas: abre el menu de Administracion de Lineas
- Icono de listas: abre el menu de Listas
- Icono del buzon: abre el menu del Centro de Mensajes
- Icono del dinero: abre el menu de Finanzas

- Los iconos de Otras opciones, que incluyen:
- Icono de la camara: captura la imagen actual de la Interfaz/Ventana del juego (sin la barra de titulo) y la salva en formato bmp en el directorio ...simutrans/screeshot/
{Consejo: Tambien se puede hacer un captura pulsando la tecla [c].}
- Icono de la taza de cafe: el juego entra/sale del modo pausa.
{Consejo: Pulsando tambien la tecla [p] puedes pausar el juego}.
- Icono >> : activa/desactiva el modo Acelerar. (cambia la escala en la que el tiempo , T, transcurre en el juego).
{Consejos: Acelerar se puede activar /desactivar pulsando la tecla [W]
IMPORTANTE: El juego puede no ejecutarse de forma fluida;el menu de Pantalla indica si tu ordenador puede soportar ese rendimiento.}
- ?: abre el menu de la Ayuda de Simutrans

Una parte de la vista del juego del mundo actual se muestra debajo de los Iconos.
Puede hacer zoom de la vista y tambien desplazarla para ver el resto de partes del mundo actual usando el raton o el teclado.

barra de mensajes temporales aparece y muestra mensajes en la parte inferior de la vista del juego.
{Consejo: Pulsa en el mensaje para centrar la vista del juego sobre el acontecimiento al que hace referencia.}

Una barra inferior muestra informacion acerca de la partida actual, y se situa en la parte inferior de la vista del juego.
La informacion mostrada, de izquierda a derecha en la barra inferior incluye:
fecha y hora: fecha y hora actual de la partida, seguida por el icono y nombre de la estacion del año.
balance economico: dinero actual disponible para construccion y otros costes (comprar vehiculos, mantenimiento de las infraestructuras de transporte y los costes operacionales de los vehiculos operativos).
coordenadas: indica la posicion del cursor en la vista de juego. Las tres cifras representan las coordenadas X, Y y la altura.
T: indica la escala de paso del tiempo en el juego.
{Consejos: Usa la tecla [.] / [,] para acelerar/decelerar el tiempo, T ; en el menu Pantalla indica si el ordenador puede soportar ese rendimiento.
El uso de Acelerar reemplaza el valor de T por ">>" en la barra inferior.}
cronologia: indica si se esta usando cronologia en la partida actual.

simutrans-124.3/simutrans/text/et.tab000066400000000000000000000166301474050137200176720ustar00rootroot00000000000000Eesti PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: et Eesti # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable blokeeritud cl_btn_filter_enable võimaldatud cl_btn_filter_settings Seaded cl_btn_sort_asc suurenev cl_btn_sort_desc vähenev cl_btn_sort_id Sisemine ID cl_btn_sort_income Sissetulek cl_btn_sort_name Nimi cl_btn_sort_type Tüüp clf_btn_alle kõik clf_btn_invers inv. clf_btn_keine ei ole #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktiline kliima #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Siia ei saa depood ehitada. Cannot create generic line!\nSelect line type by\nusing filter tabs. Ei saa luua üldist liini!\nVali liini tüüp\nkasutades sakke. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s nüüd\npakub bussiühendust\n %s\nja\n%svahel\(%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s nüüd\npakub bussiühendust\n %s\nja\n%svahel\(%i,%i).\n #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (in depot) (depoos) %d buildings\n %d ehitisi %d convois %d konvoid %d Einzelfahrzeuge im Depot %d sõidukit siin %i km/h (max. %ikm/h) %i km/h(maks. %ikm/h) %s building %s %s %s %s %s %s city %d %s %s linn %d %s %s has entered a depot. %s sisenes depoosse. %s land %d %s %s maa %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s\nehitas\nuue raekoja\nkui jõudis\n%i elanikuni. %s\nis crowded. %s\n on ülerahvastatud 1 convoi 1 konvoi 1 Einzelfahrzeug im Depot 1 sõiduk siin. 1LIGHT_CHOOSE Heledus: 1WORLD_CHOOSE Uue mängu seaded: 2LIGHT_CHOOSE Värvid: 2WORLD_CHOOSE Kaart number: 3LIGHT_CHOOSE Kerimiskiirus: 4LIGHT_CHOOSE Pöördkerimine 5LIGHT_CHOOSE Jalakäijad peatustes 5WORLD_CHOOSE Linnade arv 6LIGHT_CHOOSE Jalakäijad linnas 6WORLD_CHOOSE Liiklustihedus: 8WORLD_CHOOSE päeva ja öö vaheldumine A bridge must start on a way! Sild peab\nhakkama \nteel. Abfrage Ülevaatamise vahend Abnehmer Tarbija About Teave Abriss Hävita/Eemalda Absenken Madalda maad Add Stop Lisa peatus Add stops for backward travel Lisa peatused tagasiretkele. aircraft_tab Veolennukid Airport Lennujaam AIRTOOLS Lennujaama vahendid All Kõik Allow player change Luba mängija vahetamist Alters a schedule. Lisa/eemalda peatus sõiduplaani/sõiduplaanist Angenommene Waren Kaubad mida läheduses olevad tööstused vajavad anhaengen Lisama Anhaenger_tab Järelkärud Anheben Tõsta maad Apply Line Rakenda liin April aprill Arbeiter aus: Töötajad elavad: Arrived Kohale jõudnud Assets Väärtused Aufloesen Võta koost lahti August august Autohalt muss auf\nStrasse liegen!\n Auto- või bussipeatus \npeab olema \nasetatud teele. Available Kasutatav Bahndepot Rongidepoo Bankrott:\n\nDu bist bankrott.\n Pankrot: \n\nSa oled pankrotis!\n battery Aku Baum Puu Baustelle Ehitusala Beenden Välju Beginner mode Algaja re?iim Besonderes Gebaeude Vaatamisväärsus BF jaam bio bioloogiline Blockstrecke ist\nbelegt\n \nRaudtee on kasutuses\nteise rongi poolt!\n Boden Maa Bridge is too long for this type!\n Sild on liiga\npikk valitud\nsillatüübi jaoks. Bruecke Sild Bruecke muss an\neinfachem\nHang beginnen!\n Sillad peavad\nalgama sirgelt\nteelõigult! Brueckenboden sild build choosesignals Ehita signaale Build city market Ehita uus market lähimasse linna. Build drain Trafo build HQ Ehita peakorter Build land consumer Ehita uus elektrijaam. Build monorail depot Ehita monoraudtee depoo Build powerline Ehita elektriliin Build presignals Ehita topeltbloki signaalid Build road depot Ehita garaa? Build ship depot Ehita laevatehas Build signals Ehita signaale Build train depot Ehita rongidepoo Build tram depot Ehita trammidepoo Build truck depot Ehita garaa? Buildings Ei eksisteeri! Built artifical slopes Ehita kunstlikke kaldeid Built random attraction Ehita suvaline atraktsioon. Bus_tab Bussid Cancel Tühista Capacity: %s\nLoad: %d (%d%%) Mahutavus: %s\n» %d (%d%%) Cars are not available yet! Autod ei ole veel saadaval. Cash Kontobilanss Change player Vaheta mängijat Chart Diagramm Choose operation executed on clicking stored/new vehicles Vali tegevus vajutades uutele/olemasolevatele sõidukitele chooses a random map Valib juhusliku kaardi. citicens Linnaelanikud City industries Marketid linnas City list Linnade nimekiri City size Linna suurus city_road Linnatänav CityLimit Linna piirid cl_title Sõidukite nimekiri cl_txt_sort Sordi: clf_chk_aircrafts lennukid clf_chk_cars Bussid/veoautod clf_chk_indepot depoos clf_chk_name_filter Filtreeri nimed: clf_chk_noincome sissetulekut pole clf_chk_noline liini pole clf_chk_noroute marsruuti pole clf_chk_noschedule sõiduplaani pole clf_chk_ships Laevad clf_chk_spezial_filter Erifilter: clf_chk_stucked kinni clf_chk_trains Rongid clf_chk_type_filter Filtri tüübid: clf_chk_waren Filtreeri kaupu: clf_title Sõidukinimekirja filter Climate Control Sea kliimaolud COLOR_CHOOSE\n Palun vali \ncolour tabelist:\n Constructed by Värvis Constructed by %s Värvis %s Construction_Btn Ehitus maksab convoi %d of %d Konvoi number %d %d-st Convoi has been sent\nto the nearest depot\nof appropriate type.\n Sõiduk on saadetud lähimasse sobivasse depoosse. Convoi is sold when all wagons are empty. Sõiduk müüakse niipea kui see on täiesti tühi. Neue Karte Uus kaart player 2 Trikky Transport player 3 Meyer Moving Co. Size (%d MB): Suurus (%d MB): #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ %1_CITY_SYLL Harju %2_CITY_SYLL Järve %3_CITY_SYLL Põhja %4_CITY_SYLL Põlva %5_CITY_SYLL Kevade %6_CITY_SYLL Lehe %7_CITY_SYLL Puju 1center %s %s 1extern %s haru %s 2center %s kesk %s 2extern %s välis %s 3center %s põhi %s 3extern %s maa %s 4center %s sise %s 4extern %s välis %s 5center %s vahetus %s 6center %s kesk %s 7center %s linna %s simutrans-124.3/simutrans/text/fi.tab000066400000000000000000001057021474050137200176570ustar00rootroot00000000000000Suomi PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: fi Suomi # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable pois päältä cl_btn_filter_enable päällä cl_btn_filter_settings Asetukset cl_btn_sort_asc nouseva cl_btn_sort_desc laskeva cl_btn_sort_id sisäinen tunniste cl_btn_sort_income Tulot cl_btn_sort_name Nimi cl_btn_sort_type Tyyppi clf_btn_alle kaikki clf_btn_invers päinv. clf_btn_keine ei mitään gl_btn_sort_bonus bonus gl_btn_sort_name nimi gl_btn_sort_revenue tuotto gl_btn_unsort ei mikään hl_btn_filter_disable pois päältä hl_btn_filter_enable päällä hl_btn_filter_settings Asetukset hl_btn_sort_asc nouseva hl_btn_sort_desc laskeva hl_btn_sort_name Nimi hl_btn_sort_type Tyyppi hl_btn_sort_waiting Odottaa hlf_btn_alle kaikki hlf_btn_invers päinv. hlf_btn_keine ei mitään #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktinen ilmasto desert aavikkoilmasto mediterran välimerenilmasto rocky alppi-ilmasto temperate lämmin ilmasto tropic troopp. ilmasto tundra tundrailmasto #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Et voi rakentaa tallia tähän. Cannot built this station/building\nin underground mode here. Rakennusta ei voi rakentaa maan alle. Cannot create generic line!\nSelect line type by\nusing filter tabs. Et voi luoda yleisreittiä!\nValitse ensin reitin tyyppi\n Cannot create socket Yhteyden muodostaminen ei onnistu! Convoi handles exhausted! Saavutettiin kuljetusvälineiden\nenimmäismäärä. Das Feld gehoert\neinem anderen Spieler\n Maa on toisen\npelaajan omistuksessa.\n Der Besitzer erlaubt das Entfernen nicht Omistaja ei salli\ntehdä tätä.\n Diese Zusammenstellung kann nicht fahren!\n Tämä yhdistelmä\nei toimi.\n Flugzeughalt muss auf\nRunway liegen!\n Pysäkin pitää olla rullausalueella! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Tätä lentokenttärakennusta\n\nei voi rakentaa tähän! Hier kann kein\nSignal aufge-\nstellt werden!\n Rautatieopastinta\nei voi rakentaa\ntähän.\n Lost connection\nto server! Palvelin ei vastaa! Lost synchronisation\nwith server. Synkronisaatio palvelimen\nkanssa epäonnistui. Maglevhalt muss auf\nMaglevschiene liegen!\n Maglev-pysäkin voi rakentaa vain maglev-radalle! Monorailhalt muss auf\nMonorail liegen!\n Monorail-asema täytyy\nasettaa Monorail-radalle! Monorails are not available yet! Monorailit eivät ole vielä käytössä! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Kapearaidepysäkin oltava kapeariteisella raiteella. No through station here! Et voi rakentaa asemaa tähän! Not enough money! Sinulla ei ole tarpeeksi varoja tämän rakentamiseen! On narrowgauge track only!\n Tämä onnistuu vain kapearaideradalla!\n Post muss neben\nHaltestelle\nliegen!\n Postitoimisto pitää\nrakentaa aseman tai\npysäkin lähelle.\n Protocoll error (expecting game) Protokollavirhe (odotetaan peliä) Schiffhalt muss im\nWasser liegen!\n Laivan pysähdyspaikan\nvoi asettaa vain\nveteen lähelle\nlaituria.\n Terraforming not possible\nhere in underground view Maata ei voi muokata\nmaanalaisessa näkymässä. Upgrade must have\na higher level Päivityksen täytyy olla korkeampaa tasoa Zughalt muss auf\nSchiene liegen!\n Rautatieaseman\nvoi rakentaa\nvain rautatielle.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Pikanäppäinohje\n

Pikanäppäinohje

\n

\nPikanäppäinohje näyttää eri näppäimiä painamalla tapahtuvat toiminnot.\n

\n

\nPikanäppäinohje avautuu painamalla näppäintä, joka ei ole muussa käytössä, tai Yleisohjeen kautta.\n

\n

\nNäppäinkomennot huomioivat kirjainkoon (käytä [Shift]-näppäintä saadaksesi isot kirjaimet).\n

\n

\nSeuraavilla näppäimillä on omat toimintonsa:\n

\n

\n[Nuolinäppäimet]: vieritä pelinäkymää nuolen suunnassa.
\n[Backspace]: sulje kaikki ikkunat, työkalupalkit ja ohjetekstit.
\n[Delete], tai [Escape]: sulje ylin ikkuna, työkalupalkki tai ohjeteksti.
\n[Enter], tai [Return]: käytä vahvistaaksesi eri toimintoja.
\n[Page-Up], tai [>]: lähennä pelinäkymää.
\n[Page-Down], tai [ vähemmän kuin -merkki]: loitonna pelinäkymää.\n[F1]: avaa Simutrans-ohje.

\n

\n[1]: vieritä pelinäkymää etelään.
\n[2]: vieritä pelinäkymää kaakkoon.
\n[3]: vieritä pelinäkymää itään.
\n[4]: vieritä pelinäkymää lounaaseen.
\n[6]: vieritä pelinäkymää koilliseen.
\n[7]: vieritä pelinäkymää länteen.
\n[8]: vieritä pelinäkymää luoteeseen.
\n[9]: vieritä pelinäkymää pohjoiseen.\n

\n

\n[Shift] + hiiri: käytä Kartalla nähdäksesi Teollisuusketjujen yhteydet.
\n[CTRL] + työkalu: rakenna (osoittimia ja Pysäkkejä) ylemmälle tasolle; tai rakenna hitaita teitä tai ratoja nopeampien päälle; tai rakenna suorempia teitä tai ratoja.
\n[CTRL] + ([F2] - [F12]): asettaa valitun työkalun tietyllä näppäinkomennolla [F2] - [F12] käytettäväksi.\n

\n

#____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s liikennöi\nnyt bussilinjaa\nvälillä %s\n - %s (%i,%i).\n\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s liikennöi\nnyt bussilinjaa\nvälillä %s\n - %s (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). Yhtiön %s %i\nrekkaa huolehtivat\nnyt kuljetuksista välillä\n%s (%i,%i)\n - %s\n (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\navasi uuden rautatien\nvälille %s\n (%i,%i) - \n%s\n (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n %s\navasi uuden lentoreitin välille\n%s -\n%s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n %s\ntarjoaa nyt\nlauttayhteyden välillä\n%s -\n%s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Matkustajat käyttävät nyt\nyhtiön %s\nbusseja välillä\n%s - %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Maastonmuokkaus LISTTOOLS Listat MAGLEVTOOLS Maglev-työkalut MONORAILTOOLS Monorail NARROWGAUGETOOLS Kapearaidetyökalut RAILTOOLS Rautatie ROADTOOLS Tie SHIPTOOLS Laiva SLOPETOOLS Rinnetyökalut SPECIALTOOLS Erikoistyökalut TRAMTOOLS Raitiovaunu #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s on rakentanut uuden pääkonttorin. Factory chain extended\nfor %s near\n%s built with\n%i factories. Talouskasvu kiihtyy:\n%s laajentaa tuotantoa\nkaupungin %s alueella.\n%i uutta tehdasta perustettiin. New %s now available:\n%s\n Uusi %s saatavilla:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Uusi %s on\n alihankkijoineen avattu\nkaupungin %s\nlähellä, %i uutta tehdasta\n rakennettiin. New vehicle now available:\n%s\n \n Uusi kulkuneuvo on käytettävissä:\n\n\n » %s «\n\n Remove vehicle from map. Use with care! Poista kulj.väline. (Käytä varoen!) Screenshot\ngespeichert.\n Kuvankaappaus\ntallennettu.\n Sends the convoi to the last depot it departed from! Lähettää kulkuneuvon lähimpään talliin. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s rakensi uuden\nmuistomerkin. %i asukasta\nvietti kotiseudustaan ylpeänä\nansaittua vapaapäivää. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (tallissa) \nBauzeit bis \nvuoteen \nBauzeit von \nValmistettu vuodesta \nCan't open heightfield file.\n \nKorkokuvatiedostoa\nei voi avata.\n \ndirection: \nSuunnat: \nelektrified \nSähköistetty\n \nHeightfield has wrong image type.\n \nKorkokuva on\nvääräntyyppinen.\n \nis reserved by: \ntiellä on juna \nminimum speed: \nAlin sallittu nopeus: \nnot elektrified \nEi sähköistetty\n \nRibi (masked) \nSuunnat\m (maski): \nRibi (unmasked) \Suunnat\n (ei maskia): \nSet phases: \n säädä pituutta P-E/I-L: \nsingle way \nYksisuuntainen \nway1 reserved by Tien 1 varannut\nTien 1 varannut \nway2 reserved by Tien 2 varannut\nTien 2 varannut \nwith sign/signal\n \nmerkillä/opastimella\n %d buildings\n %d rakennusta %d convois %d kuljetusvälinettä %d Einzelfahrzeuge im Depot %d kulj.välinettä tallissa %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. %i vuotta %i kuukautta vanha. %s building %s %s %s %s %s %s city %d %s %s %d %s %s has entered a depot. %s on tallissa. %s land %d %s %s maa %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s rakensi\nuuden kaupungintalon\nsaavuttaessaan %i\nasukkaan rajan. %s\nis crowded. %s\on ruuhkainen. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nnopeus %i\nmax. nopeus %i\ndx:%i dy:%i %s\nwas liquidated. %s\non lakkautettu. 1 convoi 1 kuljetusväline 1 Einzelfahrzeug im Depot 1 kulj.väline tallissa. 1LIGHT_CHOOSE Kirkkaus: 1WORLD_CHOOSE Uuden kartan asetukset: 2LIGHT_CHOOSE Värit: 2WORLD_CHOOSE Kartan numero: 3LIGHT_CHOOSE Vieritysnopeus: 4LIGHT_CHOOSE Käänteinen vieritys 5LIGHT_CHOOSE Näytä jalankulkijat 5WORLD_CHOOSE Kaupunkien määrä: 6LIGHT_CHOOSE Jalankulkijat kaupungeissa 6WORLD_CHOOSE Liikennetiheys: 8WORLD_CHOOSE Käytä päivä/yö-tilaa A bridge must start on a way! Sillan täytyy alkaa tiestä. Abfrage Tutkimistyökalu Abnehmer Kuluttajat About Tietoja Abriss Tuhoa Absenken Laske maata Accelerate time Nopeuta aikaa Active player only Vain aktiivinen pelaaja Add forest Lisää metsää Add random citycar Lisää yksityisauto Add Stop Lisää pysäkki Add stops for backward travel Lisää pysäkkejä paluumatkalle air kiitorata/rullausalue aircraft_tab Rahtikoneet airplane Lentokone Airport Lentokenttä AIRTOOLS Lentokentät All Kaikki all convoi tooltips kaikki ajoneuvon tiedot Allow city growth Salli kasvu Allow player change Salli pelaajan vaihtaminen allowed climates:\n Sallitut ilmastot:\n Alters a schedule. Lisää/poista pysäkkejä reitille/ltä Angenommene Waren Lähiyritysten tarvitsemat tavarat anhaengen Liitä Anhaenger_tab Perävaunut Anheben Nosta maata Appends stops at the end of the schedule Lisää pysäkkejä reitin loppuun Apply Line Laita reitille April huhtikuu Arbeiter aus: Työntekijöiden asuinpaikat: Arrived Saapunut Assets Pääoma Aufloesen Pura August elokuu Autohalt muss auf\nStrasse liegen!\n Pysäkki täytyy asettaa tielle! Available Saatavilla Bahndepot Veturitalli Bankrott:\n\nDu bist bankrott.\n \n\nYhtiösi on tehnyt konkurssin.\n battery akku Baum Puu baum builder Kasvata puita Baustelle Rakennustyömaa Bauzeit Rakennusaika Beenden Lopeta Beginner mode Aloittelijatila Besonderes Gebaeude Turistikohteet BF asema Blockstrecke ist\nbelegt\n Rataosuus on toisen\njunan käytössä.\n Boden Maa bridge is too high for its type! Silta on liian korkea. Bridge is too long for this type!\n Silta on liian\npitkä! Bruecke Silta Bruecke muss an\neinfachem\nHang beginnen!\n Sillan täytyy\nalkaa mäestä.\n Brueckenboden silta Build air depot Rakenna hangaari build choosesignals Rakenne valintaosoittimia Build city market Rakenna uusi kauppa lähimpään kaupunkiin Build drain Rakenna muuntaja build HQ Rakenna pääkonttori Build land consumer Rakenna uusi voimala Build maglev depot Rakenna maglev-talli Build monorail depot Rakenna Monorail-talli Build narrowgauge depot Rakenna kapearaidetalli Build powerline Rakenna voimalinjoja Build presignals Rakenna esiosoittimia Build road depot Rakenna autotalli Build ship depot Rakenna telakka Build signals Rakenna osoittimia Build train depot Rakenna veturitalli Build tram depot Rakenna raitiovaunutalli Build truck depot Rakenna autotalli Building costs estimates Kustannusarvio Buildings Rakennuksia Built artifical slopes Rakenna keinotekoisia rinteitä Built random attraction Rakenna turistikohde Bus_tab Bussit Can only move from halt to halt or waypoint to waypoint. Voidaan siirtä vain\npysäkiltä toiselle\ntai reittipisteeltä toiselle. Cancel Peruuta Capacity Kapasiteetti Capacity: Kapasiteetti: Capacity: %.0f MW Kapasiteetti: %.0f MW\n Capacity: %d%s %s\n Kapasiteetti: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapasiteetti: %s\nLasti: %d (%d%%) Cars are not available yet! Autot eivät ole vielä käytettävissä. cars.\nstate autoa\n Cash Kate Change player Vaihda pelaajaa Chart Tiedot Choose direction Vaihda suunta Choose operation executed on clicking stored/new vehicles Valitse varastoitua/uutta kulkuvälinettä klikattaessa suoritettava toiminto chooses a random map Luo sattumanvarainen kartta citicens Asukkaita City attraction Kaupunkinähtävyys City industries Kaupat kaupungeissa City list Kaupunkilista City size Asukkaita city_road Katu citybuilding builder Talonrakentaja CityLimit Rajat cl_title Kuljetusvälinelista cl_txt_sort Järjestys: Clear block reservation Näytä/nollaa reittivaraukset clf_chk_aircrafts Lentokoneet clf_chk_cars Bussit/rekat clf_chk_indepot tallissa clf_chk_maglev Maglev-junat clf_chk_monorail Yksiraidejunat clf_chk_name_filter Suodata nimet: clf_chk_narrowgauge Kapearaidejunat clf_chk_noincome ei tuloja clf_chk_noline ei reittiä clf_chk_noroute ei reittiä clf_chk_noschedule ei reittiä clf_chk_ships Laivat clf_chk_spezial_filter Erik. suod.: clf_chk_stucked jumissa clf_chk_trains Junat clf_chk_trams Raitiovaunut clf_chk_type_filter Suod. tyyppi: clf_chk_waren Suod. tavarat: clf_title Kuljetusvälinelistan suodatus Climate Control Ilmaston asetukset closed suljettu COLOR_CHOOSE\n Valitse yhtiöllesi\nväriteema:\n Company bankrupt Yhtiö vararikossa Congratulation\nScenario was complete in\n%i months %i years. Onnittelut!\nSkenaario selvitetty\n%i kuukaudessa ja %i vuodessa. Connected stops Yhdist. pysäkit Constructed by Maalannut: Constructed by %s Maalannut: %s Construction_Btn Rakennuskulut convoi %d of %d Kuljetusväline %d / %d convoi error tooltips ajoneuvojen virhetiedot Convoi has been sent\nto the nearest depot\nof appropriate type.\n Ajoneuvo on lähetetty lähimpään sopivaan talliin. Convoi is sold when all wagons are empty. Kulkuneuvo myydään, kun kaikki vaunut ovat tyhjiä. convoi mouseover tooltips ajoneuvojen tiedot hiirellä convoi passed last\nmonth %i\n Ajoneuvoja viime\nkuussa %i\n Convois Ajoneuvot Convois: %d\nProfit: %s Ajoneuvot: %d\nTuotto: %s Convoys Ajoneuvot Copy Convoi Kopioi ajoneuvo Copy the selected convoi and its schedule or line Kopioi valittu ajoneuvo ja sen reitti. cost for removal poistaminen maksaa Costs Kulut Create a new line based on this schedule Luo uusi linja, joka perustuu tähän reittiin curiosity builder Nähtävyysrakentaja curlist_title Turistikohdelista Currently playing: Tällä hetkellä soi: Deccelerate time Hidasta aikaa December joulukuu decrease underground view level vähennä maanalaisen näkymän tasoa Del Stop Poista Delete Line Poista linja Delete the current stop Poista nykyinen pysäkki Delete this file. Poista tämä tiedosto. Demand: %.0f MW Tarve: %.0f MW\n Denkmal Muistomerkki Departed Lähtenyt Depots Tallit Der Tunnel ist nicht frei!\n Tunneli ei ole tyhjä.\n Destination Määränpää Details Lisätiedot Die Bruecke ist nicht frei!\n Silta ei ole vapaa. Direkt erreichbare Haltestellen Suorat yhteydet asemille disable midi Mykistä midi-musiikki Display settings Näytön asetukset Distance Matka Dock laituri Dock must be built on single slope! Laituri pitää rakentaa suoraan rinteeseen! Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Sinulla on %d kuukautta maksaa velkasi. Durchsatz Max. Economy Talous ja kaupungit Eigenbesitz\n Julkista omaisuutta\n Ein %s\npasst hier nicht.\n '%s'\nei sovi tähän.\n Einstellungen aendern Muuta asetuksia electric sähkö Electricity sähkö Electricity producer\n\n Sähköntuottaja\n\n Electrics_tab Sähkö Electrify track Sähköistä rata enlarge map Suurenna karttaa enter a value between %i and %i Syötä arvo %i:n ja %i:n väliltä Error Virhe Erzeuge neue Karte.\n Odota, uutta karttaa\nluodaan.\n\nTämä saattaa kestää\nmuutaman minuutin\nisoilla kartoilla.\n Es wird bereits\nein Fahrplan\neingegeben\n Aikataulua\ntehdään parhaillaan.\nSaata se päätökseen\nennen kuin uusit sen!\n Fabrikanschluss Yhdist. yritykset Fabrikname Tehtaan nimi Factories Tehtaat factory details Tehtaan yhteydet factorybuilder Tehdasrakentaja Fahrplan Reitti Fahrtziel Määränpää: Fahrzeuge koennen so nicht entfernt werden Kuljetusvälinettä ei\nvoi poistaa tällä\ntavalla.\n Fahrzeuge: Kulj.välineet: Farbe Väritys Fast forward Nopeuta aikaa February helmikuu Ferry_tab Matkustajalautat Fertig Valmis Filename Tiedosto: Filter: Suodatus: Finances of %s %s:n talous Finanzen Talous fl_title Tehdaslista Flug_tab Matkustajakoneet follow me Seuraa Follow the convoi on the map. Seuraa ajoneuvoa kartalla. Forest Metsät Found new city Perusta uusi kaupunki Fracht Rahti Frame time: Ruudunpäivitysaika: Free Capacity Tyhjää freeplay mode vapaapeli Friction: Kitkakerroin: fuel_cell polttokenno Full load Lasti: Fussgaenger Jalankulkija GAME PAUSED TAUOLLA Gear: Välitys: Gebaeude Rakennus General Yleinen Generation: %.0f MW Tuotanto: %.0f MW\n Gewicht Paino Gewinn Tulot: Give the selected vehicle(s) an individual schedule Anna valituille ajoneuvoille yksilöllinen reitti. gl_btn_sort_catg kategoria gl_title Lista kaikista tavaroista go home Lähetä talliin Goods Tavaraa Goods AI Rahti-AI Goods list Tavaralista Gross Profit Kokonaistuotto Groundobj Objekti Grow city Kasvata kaupunkia Growth Kasvu H pysäkki Hangar Hangaari Happy Tyytyväisiä Haus kaufen Osta talo Helligk. Näyttö Help Ohje Help text not found Ohjetekstiä ei löydy! hide all building Piilota kaikki rakennukset hide city building Piilota kaupunkien rakennukset hide station names Piilota pysäkkien nimet hide transparent Piilotetut läpinäkyviä hide trees Piilota puut Hier warten/lagern: Matkustajia/tavaroita asemalla: hl_title Pysäkkilista hl_txt_filter Suodatus: hl_txt_sort Järjestys: hlf_chk_airport lentokenttä hlf_chk_anleger laituri hlf_chk_bahnhof rautatieasema hlf_chk_bushalt bussipysäkki hlf_chk_frachthof lastausalue hlf_chk_keine_verb ei yhteyttä hlf_chk_maglevstop Maglev-pysäkki hlf_chk_monorailstop Yksiraidepysäkki hlf_chk_name_filter Suodata nimet: hlf_chk_narrowgaugestop Kapearaideasema hlf_chk_overflow Ylikapasiteetti hlf_chk_spezial_filter Erik. suod.: hlf_chk_tramstop Raitiovaunupysäkki hlf_chk_type_filter Suodata tyypit: hlf_chk_waren_abgabe Tuotanto: hlf_chk_waren_annahme Tavaran tarve: hlf_title Pysäkkilistan suodatus Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Sopivaa tallia ei löydy.\nSinun täytyy lähettää\najonevo talliin manuaalisesti. Homeless Kodittomia hydrogene vetyä Idle: Vapaana: ignore climates Älä huomioi ilmastoja Increase Industry density Lisää teollisuuden määrää increase underground view level lisää maanalaisen näkymän tasoa industrial building tuotantolaitos Init map ... Luodaan karttaa... Input Raaka-aineet Ins Stop Lisää eteen Insert stop before the current stop Lisää pysäkki ennen nykyistä pysäkkiä Intercity road len: Maanteiden pituus: Intro. date: Julkaisupäivä: invalid ei määritelty. Invalid coordinate Virheellinen komento isometric map isometrinen kartta January tammikuu July heinäkuu Jump to Siirry kohteeseen June kesäkuu Kann Spielstand\nnicht laden.\n Tallennetun pelin\nlataus epäonnistui.\n Kann Spielstand\nnicht speichern.\n Tallennus epäonnistui.\n Kein Besitzer\n Ei omistajaa\n keine ei mitään Keine Einzelfahrzeuge im Depot Ei kulj.välineitä tallissa. Keyboard_Help\n Pikanäppäimet\n koord koordinaatit Kreuzung Risteys labellist_title Merkkilista Lade Relief Lataa korkokuva Laden Lataa Land attraction Maaseutunähtävyys Land industries Tehtaita: LANG_CHOOSE\n Valitse kieli\nkäyttöliittymälle:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Year Viime vuosi: Leaving depot! Lähdössä tallista! leer tyhjä Legend Selite Leistung Teho Leistung: %d kW Teho: %d kW Leitung Voimalinja letzen Monat: diesen Monat: viime kuu: tämä kuu: Line linja Line Management Linjojen hallinta Lineless convoys serving this stop Linjattomat ajoneuvot tällä pysäkillä Lines serving this stop Linjat, jotka käyvät tällä pysäkillä LKW_tab Rekat Load game Lataa peli load height data from file Lataa korkeusdata tiedostosta. Load scenario Lataa skenaario loaded ladattu loaded passenger/freight Järjestä matkustajat/rahti: Loading (%i->%i%%)! Lastataan (%i->%i%%) Loading addon paks ... Ladataan lisäosia... Loading map ... Avataan karttaa... Loading paks ... Ladataan grafiikoita... Loading skins ... Ladataan käyttöliittymää... Lock game Estä pelaajan vaihto (edellyttää vahvistusta) Lokomotive_tab Veturit m3 m³ maglev vehicle Maglev-ajoneuvo maglev_track Maglev-rata Maglevdepot Maglev-asema Mailbox Postilaatikko Mailbox Options Postilaatikon asetukset Maintenance Ylläpito make stop public (or join with public stop next) costs %i per tile and level Tee pysäkistä julkinen (tai liitä se viereiseen julkiseen pysäkkiin). Maksaa %i$ jokaiselta ruudulta ja tasolta. Manual (Human) Pelaaja Manufactured: Valmistaja: Map roughness Maaston tasaisuus: map zoom suurennos March maaliskuu Margin (%%) Voitto (%%) Marker Merkkaustyökalu Max income: Maksimitulot: Max. speed: Huippunopeus: Maximum 254 stops\nin a schedule!\n Reitillä voi olla vain\n254 pysäkkiä!\n maximum length of rivers Jokien max.pituus Maximum tile height difference reached. Korkeusero \nkahden ruudun\nvälillä saa\nolla enintään 2. May toukokuu Median Citizen per town Asukkaita keskimäärin: Meldung Viesti Menge Määrä MessageOptionsText \nUusi vuosi\n\nPelaajauutiset\n\nKaupunkiuutiset\n\nEi reittiä\n\nUudet yritykset\n\nChat\n\nUudet ajoneuvot\n\nAsema täynnä\n\nOngelmat\n\nRuuhkat\n\nSkenaario minimum length of rivers Jokien min.pituus Modify the selected line Muokkaa valittua linjaa Monate alt kuukautta vanha. monorail vehicle yksiraidejuna monorail_track Monorail-rata Monorailboden Monorail-raiteen tuki Monoraildepot Monorail-talli month wait time Odotusaika (kk) Months Kuukaudet Monument Muistomerkki Monuments Monumentit Mountain height Mäkien korkeus: Movingobj liikkuva objekti Music playing disabled/not available Musiikin soitto pois päältä. Music volume: Musiikin voimakkuus: mute sound Mykistä Name Nimi Narrowgauge Kapearaiteinen Narrowgauge are not available yet! Kapearaide ei ole vielä saatavilla! narrowgauge vehicle kapearaidejuna narrowgauge_track Kapearaiderata Narrowgaugedepot Kapearaidetalli Net ID: %p Verkko: %p\n Net Wealth Nettovarallisuus Neue Karte Uusi kartta Neue Welt Luo uusi maailma new convoi Uusi kuljetusväline New Line Uusi linja New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Uusi linja on luotu.\nVoit liittää sen kulkuneuvoon\nvalitsemalla sen\nlinjavalikosta yläreunassa. New Vehicles Uudet kulj.välineet no buildings hidden Ei piilotettuja rakennuksia no convois Ei kuljetusvälineitä No goods are loaded onto this convoi. Kuljetusväline ei ota uutta lastia no goods waiting ei tavaroita odottamassa no load Ei lastia No Route ei reittiä No stop here! Työkalua voi käyttää\nvain pysäkkien kohdalla. No suitable ground! Alusta ei ole sopiva! No terminal station here! Ei päätepysäkkiä tässä! no timeline Ei aikalinjaa no tree Ei puita Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Aseta kuljetusvälineelle\nensin reitti.\n none ei mitään nord Pohjoinen nordost Koillinen nordwest Luode Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Ei sallittu!\nEt voi muuttaa \nkulkuneuvon reittiä \njuuri nyt. \nYritä myöhemmin uudestaan. Not enough fields would remain. Maatilan ympärille ei jäisi\ntarpeeksi peltoja. November marraskuu Now active as %s.\n Nyt aktiivisena pelaaja %s. Number of rivers Jokien määrä Object Objekti Odometer: %s km Matkamittari: %s km Oktober lokakuu On loan since %i month(s) Veloissa %i kuukauden ajan On this map, you are not\nallowed to change player!\n Peli lukittu!\nEt voi vaihtaa pelaajaa!\n Only city chains Vain kaupunkiketjut Only land chains Vain maaseutuketjut Only one transformer per factory! Vain yksi muuntaja tehdasta kohden! open auki. Operation Toiminta Ops Profit Tuotto toiminnasta Optionen Asetukset Origin Alkuperä ost Itä Output Tuotanto paletten laatikkoa Pas_tab Matkustajajunat Passagiere matkustajaa Passagierrate Matkustajia Passagierziele Matkustajien ja postin määränpäät Passenger AI Matkustaja-AI Passengers %d %c, %d %c, %d no route Matkustajia %d %c, %d %c, %d ei reittiä Passengers %d %s, %d %s, %d no route Matkustajia %d %s, %d %s, %d ei reittiä Pause Tauko PaxDest Määränpäät Percent Electricity Sähköntuotto (%% tarpeesta): Planes are not available yet! Lentokoneet eivät ole vielä käytettävissä! Plant tree Istuta puita player pelaaja player -1 Pelaaja player 0 Julkiset palvelut player 1 Tiger Trans oy player 10 Pelaaja 10 player 11 Pelaaja 11 player 12 Pelaaja 12 player 13 Pelaaja 13 player 2 Trikkyn Kuljetus player 3 Oy Simutransport Ab player 4 Meyerin Kuljetus oy player 5 Net shipping oy player 6 Katajamäen Kuljetus player 7 Pelaaja 7 player 8 Pelaaja 8 player 9 Pelaaja 9 Please choose vehicles first\n Valitse kulkuneuvot ensin!\n Post postia Postrate Postia Power Teho Power: Teho: Powerlines Voimalinjat Production of %s has been stopped:\n%s\n %s %s on poistunut tuotannosta.\n Produktion Tuotanto Profit Tuotto promote to line Aseta linjalle q1 Kevät q2 Kesä q3 Syksy q4 Talvi rail car juna random satunnainen Random age satunnainen vuosi Random map Arvo kartta Rathaus Kaupungintalo Rating Tila ratio_pax Matk. osuus Reliefkarte Kartta Remove Poista remove airstrips Poista kiitorata remove channels Poista kanava remove maglev tracks Poista maglev-rata remove monorails Poista Monorail-raiteet remove narrowgauge tracks Poista kapearaiderata remove powerlines Poista voimalinjoja remove roads Poista tie remove tracks Poista rautatie Remove wayobj %s Poista kohde %s replace stop Siirrä pysäkki request closing pyydä sulkemista residential house Asuinrakennus Restore natural slope Palauta luonnollinen muoto Restwert: Myyntiarvo: Retire. date: Eläköitym. päivä: return ticket Menopaluu Revenue Tulot road tie road vehicle ajoneuvo Roadsign Liikennemerkki Rotate map Käännä karttaa Rotation Kierto Routing Reitit sack säkkiä sail tuuli Saving map ... Tallennetaan karttaa... Scenario complete: %i%% Skenaarion edistyminen: %i%% Schedule changing! Vaihtaa reittiä! Schienentunnel Tunneli (rautatie) Schiff_tab Laivat Schiffdepot Telakka Schleppkahn_tab Proomut Screenshot Ota kuvankaappaus. Seasons Vuodenajat Sehenswuerdigkeit Turistikohde Sell the selected vehicle(s) Myy valitut kulkuneuvot. sended Läht. posti SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September syyskuu Server did not respond! Palvelin ei vastannut! Serves Line: Palvelee linjalla: Service Palvelu Setting Asetukset Ship Laiva shops and stores Kauppoja ja toimistoja Show all Näytä kaikki show all building Näytä rakennukset Show also vehicles no longer in production. Näytä myös tuotannosta poistuneet kulkuneuvot. Show also vehicles that do not match for current action. Näytä myös kulkuneuvot, jotka eivät sovellu kyseiseen toimintoon. show grid Näytä ruudukko Show industry Näytä tehtaat Show legend Selite Show map scale Mittakaava Show obsolete Näytä vanhenneet Show schedules Näytä reitit show station coverage Näytä asemien peittävyys show station names Näytä asemien nimet show waiting bars Näytä odottavat pylväinä Show/hide statistics Näytä/piilota tiedot Shows consumer/suppliers for factories Näytä tehtaiden saapuvat/lähtevät Shows the currently selected schedule Näytä valittu reitti Shrink city Pienennä kaupunkia shuffle midis sekoita kappaleet Sim: Silmukoita: Size (%d MB): Kartan koko: sliced underground mode Viipalenäkymä slot empty tyhjä Sort by Järjestä: Sort waiting list by Järjestä odottavien lista: Sound Äänet Sound settings Ääniasetukset Sound volume: Äänenvoimakkuus: special freight Erikoisrahti Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Nopeusbonus\ntie: %i km/h, rautatie: %i km/h\nlaivat: %i km/h, lentokoneet %i km/h Speedlimit Nopeusrajoitus Speichern Tallenna Spieler Pelaaja Spieler(mz) Pelaajat Spielerliste Pelaajalista Spielstand wurde\ngeladen!\n \nPeli ladattu.\n Spielstand wurde\ngespeichert!\n \nPeli tallennettu.\n Sprache Kieli Sprachen Kielet Stadtinformation Kaupungin tiedot Start Käynnistä Start the selected vehicle(s) Käynnistä kulkuneuvo(t). Starte Spiel Aloita peli Station tiles: Asemaruudut: Status Pysäkin tila steam höyry Step timeline one year Siirry vuosi eteenpäin. Storage capacity Varastokapasiteetti Strassendepot Autovarikko Strassentunnel Tunneli (tie) street car raitiovaunu sued etelä suedost kaakko suedwest lounas Summer snowline Lumiraja kesällä Suppliers Alihankkijat Tage alt päivää vanha. There are still vehicles\nstored in this depot!\n Tämän tallin sisällä on\nyhä kuljetusväline(itä)!\n This Month Tässä kuussa This Year Tämä vuosi: Tile not empty. Ruutu ei ole tyhjä. timeline Aikalinja tl_title Lista kaikista kaupungeista To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Houkutellakseen enemmän\nturisteja %s\nrakensi kohteen\n%s\n %i veronmaksajan avulla. To heavy traffic\nresults in traffic jam.\n Liikenneruuhka!\n Toggle day/night view Vaihda päivä/yö -tilaa Toggle vehicle tooltips Vaihda kulkuneuvovihjeitä tonnen tonnia Total inhabitants: Asukkaita: Tourist attractions Turistikohteita: Tourists Turistikohteita Town: %s\n Kaupunki:\n %s\n Towns Kaupungit track raide Tracks Raiteet Traffic Liikenne Train Juna Trains are not available yet! Junat eivät ole vielä käytettävissä. Tram Raitiovaunu tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. raitiovaunut %i km/h, monorail %i km/h\nmaglev %i km/h, kapearaide %i km/h. tram_track raitiovaunurata Tramdepot Raitiovaunutalli Trams are not available yet! Raitiovaunut eivät ole vielä käytettävissä! Transferring game ... Siirretään peliä... Transformer only next to factory! Muuntamon voi rakentaa vain\ntyhjääm, tasaiseen ruutuun\ntehtaan viereen. Translation Käännös transparent station coverage Läpinäkyvä asemien peittävyys Transported Kuljetettu TrolleyBus_tab Johdinautot Truck Rekka Tunnel muss an\neinfachem\nHang beginnen!\n Tunnelin täytyy\nalkaa mäestä.\n Tunnel must start on single way! Tunnelin täytyy alkaa\nyksittäisestä tiestä! Tunnelboden Tunneli underground mode Maanalainen näkymä UNDO failed! Et voi perua enää.\nReitin rakentamisen voi perua\nvain, jos reitille ei ole\nrakennettu osoittimia,\nasemia, pysäkkejä tai\nmitään muutakaan. Undo last ways construction Peruuta edellinen tien-/radanrakennustyö Unemployed Työttömiä Unhappy Pettyneitä units/day yksikköä/kk Update Line Päivitä linja upgrade HQ Päivitä pääkonttori Usage: %.0f %% Käyttöaste: %.0f %% Use timeline start year Käytä aikalinjaa vuodesta Vehicle %s can't find a route! Kulkuneuvo %s\nei löydä reittiä! Vehicle %s is stucked! Kulkuneuvo %s on jumissa! Vehicle details Kulkuneuvon tiedot Verbrauch Kulutus Vergroessere die Karte\n Suurenna kartta. verkaufen Myy Verkehrsteilnehmer Henkilöautoja Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Yhtiölläsi on velkoja!\n\nSinulla on %d kuukautta\naikaa maksaa velkasi.\n via Kautta via %s\n kautta %s\n via Menge Kautta (määrä) voranstellen Liitä eteen Waggon_tab Vaunut waiting odottamassa Waiting for clearance! Odottaa vuoroaan! Water Vesi Water level Veden taso: water vehicle Vesikulkuneuvo way %s cannot longer used:\n Tietyyppiä %s ei voida enää käyttää.\n way %s cannot longer used:\n%s\n Tietyyppiä %s ei voida enää käyttää:\n way %s now available:\n %s nyt saatavilla:\n Ways not connected Pisteitä ei ole yhdistetty. Wegpunkt Reittipiste Wert Arvo west Länsi Winter snowline Lumiraja talvella withdraw Lakkauta Withdraw All Lakkauta kaikki WRONGSAVE Tallennetun pelin versio\nei ole yhteensopiva.\nLataus ei onnistu.\n Year %i has started. Vuosi %i on alkanut. Years Vuodet Zielort Määränpää zooming in Lähennä zooming out Loitonna Zu nah am Kartenrand Et voi rakentaa tähän,\nsillä kartan reuna on\nliian lähellä.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Uusi nopeusennätys maglev-junille: %.1f km/h (%s). New world record for monorails: %.1f km/h by %s. Uusi nopeusennätys\nmonorail-junille: %.1f km/h\n(%s). New world record for motorcars: %.1f km/h by %s. Uusi nopeusennätys\nautoille: %.1f km/h\n(%s). New world record for narrowgauges: %.1f km/h by %s. Uusi nopeusennätys\nkapearaideradoilla: %.1f km/h\n(%s). New world record for planes: %.1f km/h by %s. Uusi nopeusennätys\nlentokoneille: %.1f km/h\n(%s). New world record for railways: %.1f km/h by %s. Uusi nopeusennätys\nrautateillä: %.1f km/h\n(%s). New world record for ship: %.1f km/h by %s. Uusi nopeusennätys\nmerellä: %.1f km/h\n(%s). #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL kaupunki &2_CITY_SYLL kylä &3_CITY_SYLL joki &4_CITY_SYLL linna &5_CITY_SYLL metsä &6_CITY_SYLL laakso &7_CITY_SYLL keto &8_CITY_SYLL kulma &9_CITY_SYLL niitty &A_CITY_SYLL pohja %1_CITY_SYLL Uusi %2_CITY_SYLL Vähä %3_CITY_SYLL Peruna %4_CITY_SYLL Viher %5_CITY_SYLL Armon %6_CITY_SYLL Omena %7_CITY_SYLL Oja %8_CITY_SYLL Lahti %9_CITY_SYLL Vanha %A_CITY_SYLL Kivi %B_CITY_SYLL Kauko 1center %s taajama %s 1extern %s haara %s 2center %s keskusta %s 2extern %s sivu %s 3center %s kylä %s 3extern %s maaseutu %s 4center %s sisus %s 4extern %s ulkoinen %s 5center %s risteys %s 6center %s keskus %s 7center %s kaupunki %s simutrans-124.3/simutrans/text/fi/000077500000000000000000000000001474050137200171625ustar00rootroot00000000000000simutrans-124.3/simutrans/text/fi/new_world.txt000066400000000000000000000105121474050137200217220ustar00rootroot00000000000000Uusi peli -ohje

Uusi peli

Uusi peli asettaa uuden pelin ominaisuudet.
Muokattavia asetuksia ovat mm. maaston koko ja kaupunki- ja teollisuusalueiden määrä pelin alussa. Asetusten mukaisesta uudesta kartasta näkee esikatseluversion.

Uusi peli avautuu yhdessä Kielet- ja Ilmaston asetukset -ikkunoiden kanssa, kun Simutrans käynnistyy. Sen saa esille myös Peliasetukset-kuvakkeesta (tällöin muut työkalut, ikkunat ja tekstit sulkeutuvat).
Pikanäppäimiä käytettäessä Uusi peli avautuu näppäimillä [Q] and [X].

Palataksesi nykyiseen peliin Uusi peli-ikkunasta klikkaa rastia vasemmassa yläkulmassa.

Nuolipainikkeet säätävät asetuksia ja painikkeet vaihtavat päälle/pois tai avaavat uusia asetuksia:

Kartan numero: valitsee pelissä käytettävän kartan numeron.
Klikkaa numerolaatikkoa ja kirjoita haluamasi numero tai käytä nuolipainikkeita siirtyäksesi eri maastovaihtoehtojen välillä.
Esikatselukuva näyttää valitun maaston (vesi on sinistä, maa on vaaleampaa korkeammilla kohdilla).

Kartan koko: asettaa kartan sivujen pituudet (ylempi arvo on leveys, alempi korkeus). Suuret kartat vaativat enemmän muistia ja niiden luominen kestää pidempään. Esim. tietokoneella, jossa on 256 Mt RAM-muistia, on kokoa 512 x 512 oleva kartta käytännössä maksimi sujuvaan peliin.

Arvo kartta: valitsee satunnaisen kartan l. kartan numeron. Muut asetukset säilyvät ennallaan.

Lataa korkokuva: avaa uuden ikkunan valmiiksi tehtyjen maastopohjien lataamiseksi.

Kaupunkien määrä: asettaa kaupunkien lukumäärän pelin alussa.

Asukkaita keskimäärin: asettaa kaupunkien väkiluvun pelin alussa.
Tämä on keskiarvo; Simutrans pyrkii luomaan enemmän pieniä kyliä kuin suuria kaupunkeja.

Maanteiden pituus: asettaa kaupunkienvälisten teiden pituuden.

Liikennetiheys: asettaa henkilöautojen määrän kaupungeissa.
Korkeat arvot luovat enemmän yksityisliikennettä, 0 ei yhtään. Väestön suuretessa ilmaantuu uusia autoja.

Tehtaita: asettaa tuotantoketjujen määrän pelin alussa.
Jos maasto on hyvin mäkistä, voi lopullinen määrä jäädä pienemmäksi.

Sähköntuotto: asettaa voimaloiden enimmillään tuottaman sähkön määrän prosentteina muiden tehtaiden enimmillään tarvitsemasta määrästä.
Useiden tehtaiden ja laitosten tuotantoa voidaan tehostaa kytkemällä ne sähköverkkoon.

Turistikohteita: asettaa turistaa ja postia puoleensavetävien nähtävyyksien määrän pelin alussa.
Nämä esiintyvät kaupunkialueiden ulkopuolella eivätkä ole riippuvaisia kaupunkeihin luotujen nähtävyyksien määrästä. Nähtävyyksien lähistöltä syntyy myös turistien ja postin paluuliikennettä.

Käytä aikalinjaa vuodesta: asettaa pelin aloitusvuoden. Kun neliöpainike on alhaalla, aikalinja on valittu ja pelin ajan kuluessa voi ilmaantua uusia ajoneuvo- ja rakennusvaihtoehtoja.
Kun neliöpainike on alhaalla ja aikalinja siis pois päältä, peli alkaa yhä valittuna vuonna, mutta kaikki ajoneuvot ja rakennukset ovat käytettävissä välittömästi. Kaupungeissa on tällöin rakennuksia usealta aikakaudelta ja hitaammat ajoneuvot eivät ole yhtä tuottoisia kuin muuten (kuljetuspalkkioihin vaikuttaa kulloinkin saatavilla olevien ajoneuvojen keskinopeus).

Salli pelaajan vaihtaminen: antaa mahdollisuuden ohjata tekoälyn(AI) tai julkiset palvelut -pelaajan yhtiötä (asetusta ei voi vaihtaa pelin alettua).

Lataa peli: avaa uuden ikkunan, jossa voi avata tallennetun pelin. Nykyinen (tallentamaton) peli menetetään.

Aloita peli: luo uuden pelimaailman valituilla asetuksilla. Klikkaa aloittaaksi - onnea matkaan ja nauti pelistä!

{Vinkki: Simutransin käynnistyessä näytettäviä oletusarvoja voi muokata tiedostossa simuconf.tab}

simutrans-124.3/simutrans/text/fp.tab000066400000000000000000000257411474050137200176720ustar00rootroot00000000000000§Arpitan PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: frp Arpitan # # Encoding: UTF-8 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable dèsactivâ cl_btn_filter_enable activâ cl_btn_filter_settings règllâjos cl_btn_sort_asc crèssant cl_btn_sort_desc dècrèssant cl_btn_sort_id Identificacion intèrna cl_btn_sort_income Bènèfiço cl_btn_sort_name Nom cl_btn_sort_type Tipo clf_btn_alle tôt clf_btn_invers envèrsar clf_btn_keine nyun gl_btn_sort_bonus pèr prima gl_btn_sort_name Pèr nom gl_btn_sort_revenue Pèr bènèfiço gl_btn_unsort Dèsordonâ hl_btn_filter_disable dèsactivâ hl_btn_filter_enable activâ hl_btn_filter_settings Règllâjos hl_btn_sort_asc crèssent hl_btn_sort_desc dècrèssent hl_btn_sort_name Nom hl_btn_sort_type Tipo hl_btn_sort_waiting Atenta hlf_btn_alle tôt hlf_btn_invers envèrsar hlf_btn_keine nyun Networks Têla de transpôrt Queueing Coa d'atenta Scenario Informacions de mission Transfers Travèrsant #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic climâ arctico desert Climâ dèsèrtico mediterran Climâ mèditèrranèen rocky climâ montanyârd temperate climâ tempèrâ tropic climâ tropicâl tundra climâ de tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Impossiblo de consture\nun dèpot iqui. Cannot built this station/building\nin underground mode here. Impossiblo de construre un\b\nbâtiment dessos la tèrra.\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Pas possiblo de\n\nconstrure d'aèropôrt iqui.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Pas possiblo de\nconstrure de sinyâl iqui.\n In order to lock the game, you have to protect the public player by password! Pèr vèrrolyér la partia, vos devéds protègér lo joyòr avoèc un contresìnyo! #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Highlight railroad tracks Têla fèrrovièra salyents Highlite depots Dèpôs salyents Highlite electrical transmission lines Linyes èlèctriques salyentes Highlite factories Favèrges salyentes Highlite forests Jors salyentes Increase water height Ôgmentar l'égua d'un nivél #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (u dèpot) [END] [FIN] [HOME] [POS1] \nBauzeit bis tant qu'a AIRTOOLS Otìlyâjo d'aèropôrt All Tôt Apply Line Aplicar la linye April Avrily Arbeiter aus: Travalyòrs de: Arrivals from\n Arrivâ de\n Arrived Arrivâ Assets Bens Aufloesen Dèsassemblar Aufspanntransformator Tansfòrmatòr August Ót Available Disponiblo Bahndepot Depot fèrrovièro Bankrott:\n\nDu bist bankrott.\n Bancarota:\n\n\nVos êtes en falyita!\n battery Bateria Baum Âbro baum builder Plantar un âbro Baustelle Sito de\n\nconstruccion Bauzeit Data de construccion Besonderes Gebaeude Atraccion toristica BF Gâra bio biologico Blockstrecke ist\nbelegt\n Plôt de ralys\nutilisâ pèr\nun âtro tren\n Boden Tèrra Bonusspeed: %i km/h Vèlocitâ maxima possibla: %i km/h Boost (%%) Ôgmentar la productivitâ bridge is too high for its type! Cèti pont est trop yôt por son tipo! Bridge is too long for this type!\n Cèti pont est trop long por son tipo. Bruecke Pont Brueckenboden Pont Build air depot Construre una remisa build choosesignals Construre un sinyâl de dicèrnement de plataforma Build city market Construre un novél marchérdiens la citâ la més prôche. Build drain Transfòrmatòr build HQ Construre la bâsa d'operacions Build land consumer Construre una centrâla èlèctrica. Build maglev depot Construre un dèpot de tren a èmant Build monorail depot Construre un dèpot de monoraly Build narrowgauge depot Construre un dèpot a vi èhtrêta Build powerline Construre una linye èlèctrica Build presignals Construre un sinyâl avanciê Build road depot Construre un garâjo Build ship depot Construre una câla Build signals Construre un sinyâl Build train depot Construre un dèpot de trens Build tram depot Construre un dèpot de tramevèts Build truck depot Construre un garâjo Building costs estimates Èstimacion de la construccion Buildings Construre un bâtiment Built artifical slopes Construre de bârmes Built random attraction Construre una novèla atraccion Cancel Anular Cannot connect to offline server! Conèxion impossibla u sèrvòr sur la têla! Capacity: Capacitâ Capacity: %.0f MW Capacitâ: %.0f MW\n Capacity: %d%s %s\n Capacitâ: %3d%s %s\n cars.\nstate vêtures\n Cash Balance Change player Changér de joyòr Chart Grafico Chat_msg Barjacâjo Choose direction Sèleccionar la dirèccion chooses a random map Sèlèccionar una mapa alèatoèra. citicens Citoyens City attraction Atraccion de la citâ City industries Favèrges diens les citâs City list Lista de citâs City size Talye de la citâ citybuilding builder Construccions diens la citâ CityLimit Limites de la citâ cl_title Lista de vèyicllos cl_txt_sort Dicèrnar pèr: clf_chk_aircrafts avions clf_chk_indepot diens un dèpot clf_chk_maglev Tren a èmant clf_chk_monorail Monoraly clf_chk_name_filter Filtro pèr nom: clf_chk_narrowgauge Trens a vi èhtrêta clf_chk_noline Sens linye clf_chk_noroute Sens chemin clf_chk_noschedule Sens itinèrèro clf_chk_obsolete Obsolèto clf_chk_ships batiôs clf_chk_spezial_filter Filtro spèciâl: clf_chk_stucked blocâ clf_chk_trains Trens clf_chk_trams Tramevèts clf_chk_type_filter Filtro pèr tipo: clf_chk_waren Filtro pèr charâ: clf_title Filtro vèyicllo Climate Control Règllâjos du climâ closed fèrmâ. Construction_Btn Côte de construccion December Dècembro Depots Dèpots Display settings Règllâjo d'afichâjo Dock Pôrt electric èlèctrico Electricity Èlècrticitâ Electricity producer\n\n Productòrs d'èlèctricitâ\n\n Electrify track Èlèctrifiar les vis enlarge map Ôgmentar la mapa February Fèvriér follow me Vens avoèc mè Forest Jor Found new city Fondar una novèla citâ FPS: Vindâjo d'ìmâges Fracht Frêt Frame time: Dèlê: Free Capacity Capacìtâ rèsta freeplay mode Sens bancarota Friction: Valyòr de friccion fuel_cell pila combustiblo Full load Charâ minima Fundament Fondacion Fussgaenger Pedon Game info Informacion de partia GAME PAUSED JUÈ EN ARRÉTA Game_msg G·ènèral Gear: Engrenâjo: Gebaeude Construccion General G·ènèral Generated G·ènèrâ Generation: %.0f MW G·ènèracion: %.0f MW\n Gewicht Pês Gewinn Renta: Give the selected vehicle(s) an individual schedule Balyér u(s) vèyiclo(s) sèlèccionât(s) un itinèrèro individuèl gl_btn_sort_catg Pèr catègori gl_title Lista de bens go home U dèpô Goods Bens Goods AI Charâ IA Goods list Lista de bens Gross Profit Bènèfiço lôrdo Groundobj Objèt Grow city Agrantir la citâ. Growth Crèssua citâ H avri Hangar Remisa Happy Content Haus kaufen Achetar la mêson Helligk. Afichâjo Help Èda Help text not found Lo tèxto d'èda fôte. hide all building cachér totes les construccions hide city building cachér les construccions de citâ hide objects under cursor cachér los èlèments sos lo cursòr hide station names cachiér los noms de stacion hide transparent transparents, pas chachiês hide trees cachér los âbros Hier warten/lagern: Passagérs e charâ en atenta: hl_title Lista de stacions hl_txt_filter Filtros: hl_txt_sort Ordonar pèr: hlf_chk_airport Aèropôrts hlf_chk_anleger Pôrt hlf_chk_bahnhof Gâra hlf_chk_frachthof Zona de charâ hlf_chk_keine_verb Sens conèxion hlf_chk_maglevstop Gâra de tren èman hlf_chk_monorailstop Gâra de monoraly hlf_chk_name_filter Filtro pèr nom: hlf_chk_narrowgaugestop Gâra de vi èhtrêta hlf_chk_overflow Saturâ hlf_chk_spezial_filter Filtro spèciâl: hlf_chk_tramstop Avri de tramevèt hlf_chk_type_filter Filtro pèr tipo: hlf_chk_waren_abgabe Produccion: hlf_chk_waren_annahme Matiére premiéra: hlf_title Filtro de nom de stacion Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Impossiblo de trovar lo dèpô.\nVos devéds i mandar\nlo vèyiclo manuèlment. Homeless Galapian hydrogene Hidrog·ènë Idle: Inactivo: ignore climates Inyorar lo climâ In the industry legend show only currently existing factories Ót In Transit en transito Increase Industry density Ôgmentar la densitâ de favèrges increase underground view level Sèrrar industrial building Construccion de favèrge Init map ... Après iniciar la mapa... Input Entrâ Ins Stop Apondre Intro. date: Data d'introduccion: invalid invalido. isometric map Mapa isomètrica January Janviér join game Partia sur la têla July Julyèt Jump to Alar a June Joen Kann Spielstand\nnicht laden.\n Impossiblo d'ovrir\nlo document enrègistrâ!\n Kann Spielstand\nnicht speichern.\n Impossiblo d'èhcrire\ndiens lo document enregistrâ!\n Kein Besitzer\n Sens propriètèro\n keine nyun Keine Einzelfahrzeuge im Depot Nyun vèyicllo u dèpot Keyboard_Help\n Èda de claviér\n koord Coordonâs Kreuzung Croesement labellist_title Lista de marcòrs Lade Relief Chargér una mapa d'altituda Laden Chargér un novél juè Land attraction Atraccion rurâla Land industries Chêna de favèrges Load game Chargér una partia load height data from file Chargiér un document de mapa d'altituda. Load scenario Chargér una mission loaded chargiê loaded passenger/freight Dicèrnar los passagérs e lo trèt pèr Loading (%i->%i%%)! Chargiment (%i->%i%%) March Mârs May Mê Narrowgauge Vi èhtrêta Narrowgauge are not available yet! La vi èhtrêta n'est p'oncor disponibla ora. nord Nôrd November Novembro Oktober Octobro Optionen Opcions September Sèptembro Sprache lengoua Sprachen Lengoues Start Dèpârt Starte Spiel Comencér simutrans-124.3/simutrans/text/fr.tab000066400000000000000000001334331474050137200176720ustar00rootroot00000000000000§Francais PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: fr Francais # # Encoding: UTF-8 # # Font: Prop-Latin1.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Affichage des heures sous forme de jour:hh:mm du mois AMBIENT_SOUND Sons d'ambiance cl_btn_filter_disable désactivé cl_btn_filter_enable activé cl_btn_filter_settings réglages cl_btn_sort_asc croissant cl_btn_sort_desc décroissant cl_btn_sort_id ID interne cl_btn_sort_income Revenu cl_btn_sort_name Nom cl_btn_sort_type Type clf_btn_alle tout clf_btn_invers inv. clf_btn_keine rien climate area percentage Taille d'une région climatique Find matching convois Trouver les convois correspondants gl_btn_sort_bonus par bonus gl_btn_sort_name par noms gl_btn_sort_revenue par recette gl_btn_unsort non trié hl_btn_filter_disable désactivé hl_btn_filter_enable activé hl_btn_filter_settings réglages hl_btn_sort_asc croissant hl_btn_sort_desc décroissant hl_btn_sort_name Nom hl_btn_sort_type Type hl_btn_sort_waiting Attente hlf_btn_alle tout hlf_btn_invers inv. hlf_btn_keine rien humidities Limites d'humidité Install Installer paks Lake lac Networks Réseau de transport Open Sea mer Queueing Tendance d'attente Reselect closes tools Re-sélection d'un outil le ferme Road toll Péages routiers Scenario Scénario Transfers Traversant #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic climat arctique desert climat désertique mediterran Climat méditerranéen rocky montagneux temperate Climat tempéré tropic climat tropical tundra Toundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Le chargement du scénario a échoué Can't buy obsolete vehicles! Impossible d'acheter des véhicules obsolètes Cannot alter water Le niveau d'eau du bassin ne peut pas être modifié Cannot built depot here! Un dépôt ne peut pas\nêtre construit ici. Cannot built this station/building\nin underground mode here. Ce bâtiment ne peut pas\nêtre construit sous terre.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Impossible de créer une ligne générique!\nSélectionnez un type de ligne\navec les onglets. Cannot create socket Impossible de créer un socket Convoi handles exhausted! Nombre maximum de convois atteint Convoy already deleted! Convoi déjà supprimé Das Feld gehoert\neinem anderen Spieler\n Ce terrain appartient\nà un autre joueur!\n Der Besitzer erlaubt das Entfernen nicht Le propriétaire\nne permet pas\nde retirer ceci.\n Diese Zusammenstellung kann nicht fahren!\n Cette combinaison\nne fonctionne pas!\n Flugzeughalt muss auf\nRunway liegen!\n Les aérogares doivent\nêtre sur une taxiway. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Vous ne pouvez pas\nconstruire d'aéroport\nici. Hier kann kein\nSignal aufge-\nstellt werden!\n Impossible de\nconstruire un\nsignal ici!\n In order to lock the game, you have to protect the public player by password! Pour verrouiller le jeu, vous devez protéger le service public par un mot de passe ! Lost connection\nto server! Connexion au\nserveur perdu!\n Lost synchronisation\nwith server. Perte de synchronization\navec le serveur. Maglevhalt muss auf\nMaglevschiene liegen!\n Un arrêt de maglev doit être placé sur des voies de maglev Monorailhalt muss auf\nMonorail liegen!\n Un arrêt de monorail doit être posé sur une voie de monorail. Monorails are not available yet! Les monorails ne sont pas encore disponibles. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Arrêt ou gare doit être sur une voie étroite! No bridges over runways! Ne peut pas construire de ponts au-dessus des pistes! No suitable way on the ground! Les arrêts ne peuvent être construits\nseulement sur le niveau droit correspondant aux voies No through station here! Impossible de placer\nun arrêt ici ! Not enough clearance. Une différence minimale de hauteur de 2 est requise pour construire des voies superposées Not enough money! Vous n'avez pas assez\nd'argent pour construire! On narrowgauge track only!\n Seulement pour les voies étroites!\n Only public player can lock games! Seul le service public peut verrouiller le jeu Out of funds Vous n'avez pas assez d'argent pour faire cela ! Post muss neben\nHaltestelle\nliegen!\n Une extension doit\nêtre placée près\nd'un arrêt ou gare!\n Protocoll error (expecting game) Erreur de protocole Schiffhalt muss im\nWasser liegen!\n Un arrêt de\nbateau peut\nseulement être\nplacé sur l'eau!\n Server busy Le serveur est occupé! Terraforming not possible\nhere in underground view Transformation du terrain impossible sous-terre. Upgrade must have\na higher level Mise à jour doit avoir un niveau plus élevé. Vehicle %s cannot choose because stop too short! %s ne peut pas choisir: tous les arrêts sont trop courts! Zughalt muss auf\nSchiene liegen!\n Un arrêt de train\npeut seulement\nêtre placé\nsur un rail !\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Aide

Contenu

*n'existe qu'en version anglaise

Simutrans en général

%1$s

Aide à la manipulation

%2$s

Engager un jeu

%4$s

Comment ça se passe ?

%5$s

Outils de gestion

%3$s

Dialogues supplémentaires

%6$s Keyboard Help\n

Keyboard Help

\n Commandes au clavier\n

Configuration :

\n9 - Déplacer la carte vers le nord-est
\n1 - Déplacer la carte vers le sud-ouest
\n7 - Déplacer la carte vers le nord-ouest
\n3 - Déplacer la carte vers le sud-est
\n6 - Déplacer la carte vers l'est
\n2 - Déplacer la carte vers le sud
\n8 - Déplacer la carte vers le nord
\n4 - Déplacer la carte vers l'ouest
\nDelete - Fermer l'écran actuel
\nBackspace - Fermer tous les écrans
\n

Decrease water height Baisser le niveau d'eau du bassin de 1 Highlight railroad tracks Surligner le réseau ferroviaire Highlite depots Montrer les dépôts. Highlite electrical transmission lines Surligner les lignes électriques Highlite factories Surligner les fabriques. Highlite forests Afficher les zones boisées Highlite tourist attraction Montrer les attractions touristiques Increase water height Augmenter le niveau d'eau du bassin de 1 Overlay city limits Afficher les frontières de la ville Overlay passenger destinations when a town window is open Afficher les trajets des passagers lorsque la ville est visible Overlay schedules/network Afficher les cadences et le réseau Overlay town names Afficher le nom des villes Please click on the map to add\nwaypoints or stops to this\nschedule. Cliquer sur la carte pour ajouter\ndes points de passage ou des arrêts pour cet\nitinéraire Set tile climate %s Transforme ce terrain en climat %s Show capacity and if halt is overcrowded Afficher la capacité et si l'arrêt est surchargé Show how many convoi reach a station Afficher combien de convois atteignent un arrêt Show how many people/much is waiting at halts Afficher combien de passagers attendent Show initial passenger departure Montrer les sources de départ de passagers Show level of city buildings Afficher la densité de passagers par bâtiment Show mail service coverage/mail network Afficher La couverture et le trafic des messages Show passenger coverage/passenger network Afficher l'état moyen du trafic des passagers Show speedlimit of ways Voir les limitations de vitesse des routes Show the change of waiting at halts Afficher les variations d'attentes aux arrêts Show the owenership of infrastructure Afficher les différents propriétaires des infrastructures Show transported freight/freight network Afficher le trafic du fret de marchandises Show usage of network Afficher la charge du trafic Shows a listing with all industries on the map. Afficher la liste de toutes les industries sur la carte Sum of departure/arrivals at halts Total des arrivées/départs des arrêts #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s Offre maintenant un service de bus\nentre %s\net l'attraction\n%s\nà (%i;%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s Offre maintenant un service de bus entre %s et l'usine %s à (%i,%i). %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s Maintenant %i camion(s) roule entre %s à (%i,%i) et %s à (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s a ouvert une nouvelle voie de chemin de fer entre %s à (%i,%i) et %s à (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n %s\nouverture d'une nouvelle ligne\naérienne entre \n%s \net %s.\n\n Ferry service by\n%s\nnow between\n%s \nand %s.\n %s\nouverture d'une nouvelle ligne\nde ferry entre\n%s et \n%s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Les voyageurs utilisent maintenant les bus de %s entre %s et %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Outils d'édition de carte LISTTOOLS Gestion des listes MAGLEVTOOLS Outils Maglev MONORAILTOOLS Outils monorails NARROWGAUGETOOLS Construire voies étroites RAILTOOLS Outils ferroviaires ROADTOOLS OUTILS ROUTIERS SHIPTOOLS Transport maritime et fluvial SLOPETOOLS Modification du terrain SPECIALTOOLS Outils Constructions spéciales TRAMTOOLS Outils trams #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s's a construit un nouveau quartier général. Factory chain extended\nfor %s near\n%s built with\n%i factories. L'économie est florissante :\n%s à côté de %s s'étend.\n%i nouvelles industries sont fondées. New %s now available:\n%s\n Nouveau %s disponible:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Croissance industrielle pour\n%s à côté de\n%s :\n%i nouvelles usines\nsont construites. New vehicle now available:\n%s\n \n Un nouveau véhicule\n est maintenant disponible:\n\n\n » %s «\n\n Now %u clients connected. %i clients branchés à cet instant.\n\n Remove vehicle from map. Use with care! Supprimer un véhicule. A utiliser avec précautions! Screenshot\ngespeichert.\n Capture d'écran\nsauvegardée.\n Sends the convoi to the last depot it departed from! Envoie le convoi au dernier dépôt qu'il a quitté. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s a construit un nouveau monument. %i citoyens ont été réjouis. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/mois) (%.2f$/km) (%.2f$/km) (%i)- (%i) (in depot) (au dépôt) \nBauzeit bis jusqu'en \nBauzeit von \nApparaît dès \nCan't open heightfield file.\n \nimpossible d'ouvrir le\nfichier de dénivelé.\n \ndirection: \ndirections: \nelektrified \nélectrifié\n \nHeightfield has wrong image type.\n \nLe dénivelé n'est pas\nau bon format d'image.\n \nis reserved by: \nréservé par le train \nminimum speed: \nvitesse minimale \nnot elektrified \nnon électrifié\n \nRibi (masked) \n (masqué): \nRibi (unmasked) \nRibi\n\n (non masqué): \nSet phases: \nAjuster temps ns/ew:\n\n \nsingle way \nVoie unique \nway1 reserved by voie 1 réservée par\nvoie 1 réservée par \nway2 reserved by voie 2 réservée par\nvoie 2 réservée par \nwith sign/signal\n \navec signe/signal\n %d buildings\n %d bâtiments\n %d Einzelfahrzeuge im Depot %d véhicules dans ce dépôt %i years %i months old. âgé de %i ans et %i mois. %s at (%i,%i) now public stop. %s at(%i,%i) est maintenant un arrêt public %s building %s %s %s %s %s %s city %d %s %s ville %d %s %s factory %s %s %s %s m %s has entered a depot. %s est entré au dépôt. %s land %d %s %s terrain %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \na construit un\nnouvel hôtel\nde ville quand\nelle a atteint\n%i habitants. %s\nis crowded. %s\nest pleine. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nvitesse actuelle %i\nvitesse maximale %i\ndx:%i dy:%i %s\nwas liquidated. %s\n a fait faillite. Toutes les activités ont été stoppées. %u Client(s)\n %i client(s)\n %u Player (%u locked)\n %u Joueurs (%u avec mot de passe)\n pas de ligne/itinéraire 1 Einzelfahrzeug im Depot 1 véhicule dans ce dépôt 1LIGHT_CHOOSE Luminosité: 1WORLD_CHOOSE Paramètres du nouveau jeu: 2LIGHT_CHOOSE Couleur: 2WORLD_CHOOSE Carte N°: 3LIGHT_CHOOSE Défilement: 4LIGHT_CHOOSE Défilement inversé 5LIGHT_CHOOSE Piétons aux arrêts 5WORLD_CHOOSE Nb villes: 6LIGHT_CHOOSE Flâneurs 6WORLD_CHOOSE Densité du trafic : 8WORLD_CHOOSE Mode jour/nuit A bridge must start on a way! Les ponts doivent commencer\nà une section existante. Abfrage Inspection Abnehmer Client About À propos About scenario Copyright Abriss Détruire Absenken Abaisser le sol Abspanntransformator Transformateur Accelerate time Accélérer le temps Act. load: %u MW\n Charge: %u MW\n Active player only seulement joueur actif Add forest Créer une forêt Add random citycar Générer une automobile add server Ajouter un serveur Add Stop Aj. Arrêt Add stops for backward travel Ajouter des arrêts pour le retour air Piste de décollage/Voie de circulation aircraft_tab Avions cargo airplane avion Airport Aéroport AIRTOOLS Outils Aviation All Tout all convoi tooltips Info-bulles convoi:toutes Allow city growth Permettre l'agrandissement des villes Allow player change Autoriser le changement de joueurs allowed climates:\n Climats autorisés: Alters a schedule. Modifier l'itinéraire Angenommene Waren Produits requis par les industries proches anhaengen Attacher Anhaenger_tab Remorques Anheben Elever le sol Appends stops at the end of the schedule Ajouter un arrêt à la fin de l'itinéraire Apply Line Assoc. ligne April Avril Arbeiter aus: Employés de : Arrivals from\n Arrivée depuis\n Arrived Arrivé Assets Biens Aufloesen Désassembler Aufspanntransformator Transformateur August Août Autohalt muss auf\nStrasse liegen!\n Un arrêt de bus doit être placé sur une route. Available Disponible Bahndepot Dépôt ferroviaire Bankrott:\n\nDu bist bankrott.\n Banqueroute:\n\nVous êtes en faillite.\n battery Batterie Baum Arbre baum builder Planter un arbre Baustelle Site de\nconstruction Bauzeit Época: Beenden Quitter Beginner mode Mode débutant Besonderes Gebaeude Attraction touristique BF gare Blockstrecke ist\nbelegt\n Bloc de rails\nutilisé par\nun autre train\n Boden Terrain Bonusspeed: %i km/h Vitesse maximale possible : %i km/h (pour le bonus de vitesse) Boost (%%) Augmentation de productivité (%%) bridge is too high for its type! Ce pont est trop haut pour ce type de pont ! Bridge is too long for this type!\n Ce pont est trop long pour ce type de pont! Bruecke Pont Bruecke muss an\neinfachem\nHang beginnen!\n Le pont doit\ncommencer sur\nune pente droite!\n Brueckenboden pont Build air depot Construire un hangar build choosesignals Construire un signal de choix de quai Build city market construire un nouveau marché dans la ville la plus proche Build drain Transfomateur build HQ Construire HQ Build land consumer construire une nouvelle centrale électrique Build maglev depot Construire un dépôt de Maglev Build monorail depot Construire un dépôt pour monorail Build narrowgauge depot Constructer un dépôt à voie étroite Build powerline Ligne à haute tension Build presignals Construire un signal avancé Build road depot Construire un dépôt routier Build ship depot Construire une gare maritime Build signals Signalisation Build train depot Dépôt de trains Build tram depot Construire un dépôt de tram Build truck depot Dépôt routier Building costs estimates Estimation des coûts de construction Buildings Bâtiments Built artifical slopes Construire des pentes artificielles Built random attraction Construire une attraction choisie au hasard. Bus_tab Bus Can only move from halt to halt or waypoint to waypoint. Peut seulement se déplacer \nd'arrêt en arrêt ou de \npoint de passage en point de passage. Cancel Annuler Cannot connect to offline server! Connection impossible, serveur hors ligne ! Capacity: Capacité Capacity: %.0f MW Capacité: %.0f MW\n\n\n Capacity: %d%s %s\n Capacité: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capacité: %s\n» %d (%d%%) Cars are not available yet! Les voitures ne sont pas encores disponibles! cars.\nstate voitures\n Change player Changer de joueur Chart Diagramme Chat_msg Chat Choose direction Choisisez la direction Choose operation executed on clicking stored/new vehicles Choisissez l'opération au clic sur les véhicules stockés/neufs chooses a random map Choisir une carte au hasard. citicens Citoyens City attraction Attraction urbaine City industries Marchés dans les villes City list Liste des villes City size Taille de la ville city_road Rue de la ville citybuilding builder Construction urbaines CityLimit limite ville cl_title Liste de véhicules cl_txt_sort trier par: Clear block reservation Afficher/cacher block reservations clf_chk_aircrafts avions clf_chk_cars Bus/camions clf_chk_indepot dans un dépôt clf_chk_maglev Maglevs clf_chk_monorail Monorails clf_chk_name_filter Filtre par nom: clf_chk_narrowgauge Trains à voies étroites clf_chk_noincome pas de revenu clf_chk_noline pas de ligne clf_chk_noroute pas de chemin clf_chk_noschedule pas d'itinéraire clf_chk_obsolete Obsolète clf_chk_ships bateaux clf_chk_spezial_filter Filtre spécial: clf_chk_stucked bloqué clf_chk_trains Trains clf_chk_trams Tramways clf_chk_type_filter Filtre par type: clf_chk_waren Filtre marchandises: clf_title Filtre véhicule Climate Control Contrôle Du Climat closed fermé. COLOR_CHOOSE\n Veuillez choisir\nune couleur\ndu tableau:\n Company bankrupt Companie en faillite! Company_msg Concurrents Comparing pak files ... Comparer les fichiers des paks... Configure AI Configurer l'IA Configure AI setttings Configurer les paramètres de l'IA Congratulation\nScenario was complete in\n%i months %i years. Félicitation!\nLe scénario a été \ncomplété en \n%i mois et %i années! Connected stops Arrêts connectés Connected with server Branché au serveur Constructed by Dessiné par Constructed by %s Dessiné par %s construction speed vitesse de construction Construction_Btn Construction Consumed Consommé convoi %d of %d convoi %d sur %d convoi error tooltips Info-bulles convoi:erreurs Convoi has been sent\nto the nearest depot\nof appropriate type.\n Le convoi a été envoyé\nau dépôt - du type\napproprié - le plus\nproche. Convoi is sold when all wagons are empty. Le véhicule sera vendu une fois qu'il sera complètement vide. convoi mouseover tooltips Info-bulles convoi:mouseover convoi passed last\nmonth %i\n Nombre de convois\npassés par ici le mois\ndernier : %i\n Convois Convoi Convois: %d\nProfit: %s Véhicule: %d\nProfit: %s Convoys Convois Copy Convoi Copier le convoi Copy the selected convoi and its schedule or line Copier le convoi sélectioné ainsi que son itinéraire ou sa ligne cost for removal cout de remplacement: Cost: %8s (%.2f$/km %.2f$/m)\n Coût: %8s (%.2f$/km, %.2f$/mois)\n Cost: %8s (%.2f$/km)\n Coût : %8s (%.2f$/km)\n Costs Coûts Create a new line based on this schedule Créer une nouvelle ligne basée sur cet itinéraire curiosity builder Construire une attraction curlist_title Liste des attractions Currently playing: Jouant: Customers live in: Clients de : deactivated in online mode désactivé en mode online Deccelerate time Ralentir le temps December Décembre decrease underground view level réduire le champ de la vue souterraine Del Stop Sup. Arrêt Delete Line Sup. Ligne Delete the current stop Supprimer l'arrêt actuel Delete the selected line (if without associated convois). Supprimer la ligne sélectionnée (si aucun convoi ne l'utilise) Delete this file. Détruire ce fichier. Delivered Délivrés Demand Demande Demand: %.0f MW Demande: %.0f MW\n Denkmal Monument Departed Parti Departure after %% chargement ou départ après (jj-hh-mm) Departure board Tableau des départs Departures to\n Départ pour\n Depots Dépôts Der Tunnel ist nicht frei!\n Le tunnel est occupé. Destroying map ... Destruction ancienne carte ... Details Détails Die Bruecke ist nicht frei!\n Le pont est occupé! Direkt erreichbare Haltestellen Gares/arrêt(s) connecté(s) disable midi Arrêter la musique MIDI Display settings Réglages d'affichage Distance distance Dock quai Dock must be built on single slope! Les quais doivent être construits sur une pente ! Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Vous avez %d mois pour recouvrir votre dette. Durchsatz Prod. max. Economy Économie et villes Eigenbesitz\n Prop. publique\n Ein %s\npasst hier nicht.\n Un(e) '%s'\nne tiend pas ici.\n Einstellungen aendern Modifier les options electric électrique Electricity Electricité Electricity producer\n\n Producteur d'électricité\n\n Electrics_tab Electrique Electrify track Électrifier les voies enlarge map Elargir la carte enter a value between %i and %i Entrez une valeur entre %i et %i Enter address Entrer l'adresse Enter Password Entrer un mot de passe Error Erreur Erzeuge neue Karte.\n Patientez S.V.P.,\ncréation d'une\nnouvelle carte?\n\n (Avec une grande\ncarte cela peut durer\nquelques minutes)\n Es wird bereits\nein Fahrplan\neingegeben\n Un trajet est\nen cours de\nprogrammation.\nTerminez-le d'abord\navantde le refaire!\n Fabrikanschluss Fabrique(s) liée(s) Fabrikname nom de fabrique Factories Fabriques factory details Détails fabriques factorybuilder Construction de fabriques Fahrplan Itinéraire Fahrtziel Destination: Fahrzeuge koennen so nicht entfernt werden Les véhicules ne\ndoivent pas être\nretirés de\ncette façon.\n Fahrzeuge: Véhicules: Farbe Couleur joueur Fast forward Avance rapide February Février Ferry_tab Ferrys Fertig Fin Filename Nom fichier: Filter: Filtre: Finances of %s Finances de %s Finanzen Finances find mismatch comparaison de paks fl_title liste des fabriques Flug_tab Avions de passagers follow me Suivez moi. Follow the convoi on the map. Suivre le convoi sur la carte. Forest forêts Found new city Créer une nouvelle ville Fracht Chargement Frame time: Image Time: Free Capacity Capac. restante freeplay mode Mode jeu libre Friction: facteur de friction actuel: fuel_cell pile à combustible Full load Attendre un chargement minimal Fundament Fondations Fussgaenger Piéton GAME PAUSED JEU EN PAUSE Game_msg Général Gear: Couple: Gebaeude Construction General Général Generated Généré Generation: %.0f MW Génération: %.0f MW\n Gewicht Masse Gewinn Revenu Give the selected vehicle(s) an individual schedule Donner au(x) véhicule(s) sélectionné(s) un itinéraire individuel gl_btn_sort_catg Catégorie gl_title Liste de tous les biens go home Au dépôt ! Goods Biens Goods AI Fracht-KI Goods list Liste des biens Gross Profit Profit Groundobj Objet du sol Grow city Agrandir ville Growth Croiss. ville H arrêt Happy Content Haus kaufen Acheter la maison Helligk. Affichage Help Aide Help text not found Le texte d'aide est manquant. hide all building cacher tout bâtiment hide city building cacher bâtiments urbains hide objects under cursor masquer les objets sous le curseur hide station names Cacher nom des arrêts hide transparent transparent au lieu de caché hide trees Cacher les arbres Hier warten/lagern: En attente de chargement: Higher transport fees, crossconnect all factories Pour plus de rentrée d'argent, désactiver le "just in time" (arrêt de production en cas de saturation) Highlite schedule Montrer les arrêts de la ligne hl_title Liste des arrêts hl_txt_filter Filtrer: hl_txt_sort Trier: hlf_chk_airport Aéroports hlf_chk_anleger Quai hlf_chk_bahnhof Gare hlf_chk_bushalt Arrêt de bus hlf_chk_frachthof Zone chargement hlf_chk_keine_verb pas de connection hlf_chk_maglevstop Gare Maglev hlf_chk_monorailstop Gare monorail hlf_chk_name_filter Filtre par nom: hlf_chk_narrowgaugestop Gare voie étroite hlf_chk_overflow Sur capacité hlf_chk_spezial_filter Filtre spécial: hlf_chk_tramstop Arrêt tramway hlf_chk_type_filter Filtre par type: hlf_chk_waren_abgabe Production: hlf_chk_waren_annahme Matières premières: hlf_title Filtre nom des gares Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Le dépôt ne peut pas\nêtre trouvé. Vous devez\nenvoyer le véhicule\nmanuellement. Homeless Sans domicile hydrogene hydrogène Idle: Arrêté: ignore climates Ignorer le climat In the industry legend show only currently existing factories Ne montrer que les industries existantes In Transit en transit Increase Industry density Augmenter la densité d'industries increase underground view level Augmenter le champ de la vue sous-terraine industrial building bâtiment industriel Init map ... Initialisation de la carte ... Input entrée Ins Stop Ins. Arrêt Insert stop before the current stop Insérer un arrêt avant celui-ci Intercity road len: Longueur routes intervilles: Intro. date: Date, dès: invalid invalide. Invalid coordinate ordre interdit isometric map carte isométrique January Janvier join game Partie réseau\n July Juillet Jump to Aller à June Juin Kann Spielstand\nnicht laden.\n Impossible de\nlire/ouvrir\nle fichier\nde sauvegarde!\n Kann Spielstand\nnicht speichern.\n Impossible d'ouvrir\nle fichier\nde sauvegarde\nen écriture!\n Kein Besitzer\n Sans propriétaire\n keine aucun Keine Einzelfahrzeuge im Depot Aucun véh au dépôt Keyboard_Help\n Aide clavier koord coordonnées Kreuzung Croisement labellist_title Liste des marqueurs Lade Relief Charger un relief Laden Charger Land attraction Attractions rurales Land industries Fabriques rurales LANG_CHOOSE\n Veuillez choisir votre langue:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Mois dernier Last Year Année passée Leaving depot! Sort du dépôt ! leer vide Legend Légende de la carte Leistung Energie Leistung: %d kW Puissance: %d kW Leitung Ligne à haute tension letzen Monat: diesen Monat: mois dernier: ce mois-ci: Line Ligne Line Management Gestion des lignes Lineless convoys serving this stop Convois sans ligne à cet arrêt Lines serving this stop Lignes desservant cet arrêt LKW_tab Camions Load game Charger partie load height data from file Charger les données d'altitude depuis un fichier. Load scenario Charger scénario loaded chargé loaded passenger/freight Trier passagers/marchandises par Loading (%i->%i%%)! Chargement (%i->%i%%) Loading (%i%%)! Chargement (%i%%) Loading addon paks ... Chargement des add-ons. Loading map ... Ouverture de la carte ... Loading paks ... Chargement des paks ... Loading skins ... Chargement des apparences ... Lock game Refuser d'avantage de changement de joueur (besoins de confirmation) Lokomotive_tab Locos m3 m³ Maglev LevMag maglev vehicle Véhicule à sustentation magnétique maglev_track Voie de Maglev Maglevdepot Dépôt des trains à sustentation magnétique Mail Demand %d\n Demande de courrier %d\n Mailbox Centre des messages Mailbox Options Options des messages make stop public (or join with public stop next) costs %i per tile and level faire un arrêt public (ou joindre un arrêt public voisin) coût %i$ par case et niveau Manual (Human) Manuel (humain) Manufactured: Construction: Map roughness Dénivelé carte: map zoom zoom March Mars Margin (%%) Marge Marker Marqueur Max Boost (%%) Augmentation max. (%%) Max income: Revenu max.: Max. speed: Vitesse max.: Max. waiting time Temps d'attente max Maximum 254 stops\nin a schedule!\n Au max 254 arrêts\ndans un ittinéraire ! maximum length of rivers Long. max. rivières Maximum tile height difference reached. La différence de\nhauteur maximum\nentre deux cases\na été atteinte. Maxspeed Vitesse maximale May Mai Median Citizen per town Moyenne d'habitants par ville: Meldung Message Menge Montant total MessageOptionsText \nNouvelle année\n\nInfos joueurs\n\nInfos villes\n\nPas de route\n\nIndustrie\n\nChat\n\nNouveaux véhicules\n\nGare pleine\n\nProblèmes\n\nBouchons\n\nScénario\n min min. minimum length of rivers Long. min. rivières Minimum load Charge minimale Missing pakfiles Objets manquants dans le pak ! Modify the selected line Modifier la ligne sélectionnée Monate alt mois. monorail vehicle Monorail monorail_track Voies de Monorail Monorailboden Support Monorail Monoraildepot Dépôt de monorail month wait time Attend max. (mois) Monthly departures Selon l'horaire Months Mois Mountain height Hauteur montagne: Movingobj Object mouvant Music playing disabled/not available Ambiance musicale autorisé/non autorisé Music volume: Volume musical: mute sound Mute Name Nom Narrowgauge Voie étroite Narrowgauge are not available yet! Il n'y a pas encore de voies étroites narrowgauge vehicle Véhicule voie étroite narrowgauge_track Voie étroite Narrowgaugedepot Dépôt de train à voi étroite Net ID: %p ID Réseau: %p\n Net Wealth Richesse Net wealth near zero Richesses proche de zéro Neue Karte Menu général Neue Welt Nouveau Monde new convoi Nouveau convoi New Line Nouvelle ligne New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nouvelle ligne crée!\nVous pouvez maintenant atribuer la ligne en la sélectionnant dans le sélectionneur de ligne ci-dessus. New Vehicles Nouveau Véhicule Nickname: Pseudo : no buildings hidden Pas de bâtiments masqués no convois Pas de convoi No goods are loaded onto this convoi. Aucune marchandise ne sera chargée dans ce convoi no goods waiting Pas de marchandises en attente no load Ne pas charger No Route Pas de chemin No stop here! L'outil doit être utilisé dans une case d'arrêt. No suitable ground! Terrain inadéquat! No terminal station here! Impossible de construire un \ndépôt ici! L'extrémité d'une \nroute/voie plane est nécéssaire. no timeline sans chronologie no tree Pas d'arbre No. of Factories Usines et magasins Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Aucun itinéraire\nprogrammé :\ndépart impossible !\n none aucun nord Nord nordost nord-est nordwest Nordouest Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Pas autorisé!\nL'itinéraire du convoi\nne peut pas être changé actuellement.\nEssayez plus tard! Not enough fields would remain. Manque de place pour\nles champs de cette ferme. November Novembre Now active as %s.\n Maintenant actif comme %s.\n Number of rivers Nombre de rivières Object Objet Odometer: %s km Odomètre: %s km\n\n Oktober Octobre On loan since %i month(s) Débiteur depuis %i mois on the départ par mois, à partir de (jj-hh-mm) On this map, you are not\nallowed to change player!\n Il n'est pas possible de\n changer les joueurs dans\ncette partie!\n Only city chains Seul chaine product urbaine Only first %d differing paks reported. There are probably more. Seulement %d des premiers paks ont été indiqués. Il y en a sûrement d'autres. Only land chains Seul chaine product rurale Only one transformer per factory! Seulement un transformateur par manufacture! Only show goods which are currently handled by factories Afficher seulement les biens qui sont actuellement utilisés par les fabriques open ouvert Operation Opération Ops Profit Profit opérationnel Optionen Options Or enter a server manually: Ou indiquer manuellement un server Origin Origine ost Est Output sortie Ownership Propriétés Pak which may cause severe errors: Les paks suivants sont absents et causent ainsi des erreurs dans les chaînes de transports: Pak which may cause visual errors: Les paks suivants ont été remplacés par des objets similaires: Pak(s) different: Paks différents: Pak(s) missing on client: Pak(s) absents du client: Pak(s) not on server: Pak(s) absents du serveur: Pakset differences Différence de paks paletten Pal. Pas_tab Trains voyageurs Passagiere Passagers Passagierrate Taux passagers Passagierziele Destination passagers/courrier Passenger AI Passagers AI Passenger Demand %d\n Demande pas. %d\n Passengers %d %c, %d %c, %d no route Passagers %d %c, %d %c, %d destination inaccessible Passengers %d %s, %d %s, %d no route Passagers %d %s, %d %s, %d destination inaccessible Password Mot de passe Pax <%i> Mail <%i> Passagers <%i> Courrier <%i> PaxDest Destinations Percent Electricity Pourcentage d'électricité Planes are not available yet! Les avions ne sont pas encore dispos! Plant tree Planter un arbre player joueur player -1 joueur humain player 0 service publique player 1 Napik Transport player 10 Joueur 10 player 11 Joueur 11 player 12 Joueur 12 player 13 Joueur 13 player 2 Trikky Express player 3 TransMeyer & Cie player 4 Transitaire Sàrl player 5 Freeline SA player 6 P.S.K. & Cie player 7 Joueur 7 player 8 Joueur 8 player 9 Joueur 9 Please choose vehicles first\n Veuillez d'abord choisir les véhicules\n Post Message Postrate Taux d'envois postaux Power Energie Power (MW) Puissance (MW) Power: Puissance: Power: %4d kW\n Puissance: %4d kW\n Powerlines Lignes HT Problems_msg Problèmes Produced Produit Produces: %.1f units/minute Produit %.1f unités/minute Production of %s has been stopped:\n%s\n La production de %s a été arrêtée:\n%s\n Production/Boost Production/Augmentation de production Produktion Production Profit Bénéfices promote to line En faire une ligne q1 Printemps q2 Eté q3 Automne q4 Hiver rail car véhicule ferroviaire random aléatoire Random age Époque aléatoire Random map carte quelconque Rathaus Mairie Rating Taux ratio_pax Rapport de passagers Relevant Utilisés sur la carte Reliefkarte Carte (relief) Remove Enlever remove airstrips Détruire des Taxiways remove channels Détruire des canaux remove interm. signals Retirer des signaux interm. remove maglev tracks Détruire des voies de Maglevs remove monorails Détruire des voies de monorail remove narrowgauge tracks Détruire des voies étroites remove powerlines enlever lignes à haute tension remove roads Détruire des routes remove tracks Détruire des voies Remove wayobj %s Enlever wayobj %s\n\n replace other signals Remplacer les autres signaux replace stop Changer l'arrêt request closing fermeture de la demande residential house maison résidentielle Restore natural slope Restaurer le relief naturel Restwert: Prix de vente: Retire. date: Date de retrait: return ticket Chemin retour Revenue Revenu Revision: Révision: road route road vehicle véhicule routier Roadsign Signal routier Rotate map Tourner la carte Routing Traversée sack sacs sail vent Save Enregistrer partie Saving map ... Sauvegarde de la carte ... Scenario complete: %i%% Scénario terminé: %i%% Schedule changing! Modification de l'itinéraire ! Schienentunnel Tunnel ferroviaire Schiff_tab Navires Schiffdepot Dépôt maritime Schleppkahn_tab Barges Screenshot Prendre une capture d'écran. Seasons saisons Sehenswuerdigkeit Attraction touristique Select a server to join: Choisir un serveur Select a theme for display Modifier le thème Sell the selected vehicle(s) Vendre le(s) véhicule(s) sélectionné(s). sended envoyé SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September Septembre Server did not respond! Le serveur ne répond plus Serves Line: Ligne desservie: set signal spacing Définir distance des signaux Setting Paramètres Ship Bateau shops and stores magasins et bureaux Show all Tout montrer show all building Montrer tous les bâtiments Show also vehicles no longer in production. Montrer aussi les véhicules plus en activité. Show also vehicles that do not match for current action. Montrer aussi les véhicules ne pouvant être utilisés pour cette action. Show even servers with wrong version or pakset Afficher même les serveurs de versions différentes ou hors paks show grid Afficher la grille Show industry Industries Show legend Légende Show map scale échelle carte Show mismatched Voir ce qui ne correspond pas Show obsolete Montrer Anc. Véhic. Show offline hors - ligne Show only used Afficher seulement ce qui est utilisé Show schedules Afficher l'itinéraire Show servers that are offline Afficher les serveurs hors-ligne Show servers where game version or pakset does not match your client Afficher les serveurs dont la version ou le pak ne correspond pas à votre client show station coverage Afficher la couverture des arrêts show station names Afficher le nom des arrêts show waiting bars Afficher la barre d'indice d'attente show/hide block reservations Afficher/masquer les blocs réservés Show/hide estimated arrival times Voir/Cacher les horaires d'arrivée potentielles show/hide object owner Afficher/masquer le propriétaire Show/hide statistics Aff./Masquer les statistiques Shows buttons on special topics. Affichage des boutons de visualisation et de contrôles Shows consumer/suppliers for factories Afficher les clients/fournisseurs des industries Shows the color code for several selections. affiche le code couleur de plusieurs sélections Shows the currently selected schedule Affiche l'itinéraire actuel Shrink city Réduire la ville shuffle midis Musique midi aléatoires signal spacing Espacement de signaux Sim: Simloops: Similar view as the main window Copie d'écran de la fenêtre principale Size (%d MB): Dimensions: (%d MB) sliced underground mode mode sous-terrain slot empty slot libre Sort by trier par Sort waiting list by Trier la liste d'attente par Sound Son Sound settings Réglages du son Sound volume: Volume sonore: special freight Marchandises spéciales Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus de vitesse\nroute %i km/h, rail %i km/h\nbateau %i km/h, avion %i km/h. Speedlimit vitesse limite Speichern Sauver Spieler Joueur Spieler(mz) Joueurs Spielerliste Liste des joueurs Spielstand wurde\ngeladen!\n Partie chargée !\n Spielstand wurde\ngespeichert!\n Partie sauvegardée !\n Sprache Langue Sprachen Langues Stadtinformation Statistiques de la ville Start Départ Start the selected vehicle(s) Expédier le(s) véhicule(s) sélectionné(s). Starte Spiel C'est parti ! Station tiles: Case de quai: Station_msg Station Status Etat de l'arrêt steam vapeur Step timeline one year Avancer le temps d'un an. Stops Arrêts Storage Stockage Storage capacity Capacité de stockage Strassendepot Dépôt routier Strassentunnel Tunnel routier street car voiture citadine sued Sud suedost Sud-Est suedwest Sud ouest Summer snowline Altitude neige d'été Supplied: %.0f %% Fournis: %.0f %% Suppliers Fournisseurs Tage alt jours (âge) There are still vehicles\nstored in this depot!\n Il y a encore des\nvéhicules dans le dépôt !\n This Month Ce mois This Year Cette année Tile not empty. Nettoyez la case avant\nd'utiliser l'outil de pente. timeline Contraintes historiques tl_title Liste des villes To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Pour attirer plus de touristes, %s construit un %s avec l'aide de %i contribuables. To heavy traffic\nresults in traffic jam.\n Un trafic dense génère un embouteillage. Toggle day/night view Alterner jour/nuit Toggle vehicle tooltips Afficher les infos des véhicules tonnen t Total inhabitants: Total d'habitants: Tourist attractions Attractions touristiques Tourists Attractions Town_msg Nouvelles destinations Town: %s\n Ville de %s.\n Towns Villes track voie Tracks Voies Traffic Trafic Trains are not available yet! Les chemins de fer ne sont pas encore disponibles. tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tram %i km/h, monorail %i km/h\nmaglev %i km/h, voie étroite %i km/h. tram_track voie de tramway Tramdepot Dépôt de Trams\n Trams are not available yet! Les trams ne sont pas encore disponibles. Transferring game ... Transfert de la partie... Transformer only next to factory! Les transformateurs doivent être\nplacés près\nd'une usine ! Translation Traduction transparent station coverage couverture stations transparente Transported Transporté(s) TrolleyBus_tab trolley bus Truck Camion tt_Other autres Tunnel muss an\neinfachem\nHang beginnen!\n Le tunnel doit\ncommencer sur une\npente droite!\n Tunnel must start on single way! Les tunnels doivent démarrer sur une voie unique. Tunnelboden Tunnel underground mode vue souterraine UNDO failed! Annuler n'est plus possible.\nVous pouvez annuler la\nconstruction d'une route tant\nqu'aucun signal/gare/arrêt ou\nquoique ce soit n'a été construit\nsur la route. Undo last ways construction Annuler la dernière voie construite Unemployed Chômeurs Unhappy Fâché units/day unités par mois Update Line MAJ. ligne upgrade HQ Améliorer HQ Usage: %.0f %% Utilisation: %.0f %% Usage/Output Electricité Use beginner mode Mode débutant Use timeline start year Jouer avec chronologie dès: Vehicle %s can't find a route! Le véhicule %s ne parvient pas à trouver son chemin! Vehicle %s is stucked! Le véhicule %s est bloqué! Vehicle details Détails du véhicule Verbrauch Consommation Vergroessere die Karte\n Agrandir la carte.\n Verkauf Éliminer! verkaufen Vendre Verkehrsteilnehmer Utilise la route Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Endettement:\n\nIl vous reste\n%d mois\npour rembourser.\n via %s\n via %s\n via Menge via (groupé) voranstellen Placer en tête Waggon_tab Wagons waiting en attente Waiting for clearance! J'attends une voie libre ! Walked à pieds walking à pied Warnings_msg Trafic Wasser Eau Water Canal Water level Niveau de la mer: water vehicle véhicules aquatiques way %s cannot longer used:\n Les voies de type %s ne peuvent plus être utilisées.\n way %s cannot longer used:\n%s\n Les voies de type %s ne peuvent plus être utilisées:\n%s\n way %s now available:\n Les voies de type %s sont maintenant disponibles.\n Way toll péage ferroviaire Ways not connected Voies non connectées Wegpunkt Point de passage Weight: Poids Wert Valeur west Ouest Wind direction Direction du vent Winter snowline Altitude neige hiver withdraw Retirer Withdraw All Retirer tout WRONGSAVE Chargement impossible:\nFormat de sauvegarde\nincompatible.\n Year %i has started. L'année %i a commencé! Years Années Your primary color: Votre couleur primaire : Your secondary color: Votre couleur secondaire : Zielort Destination zooming in Zoomer zooming out Dézoomer Zu nah am Kartenrand Trop près du\nbord de la carte\npour construire.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nouveau record du monde pour les maglevs: %.1f km/h por %s. New world record for monorails: %.1f km/h by %s. Nouveau record du monde pour les\nmonorails: %.1f km/h\nby %s. New world record for motorcars: %.1f km/h by %s. Nouveau record du monde pour les\nvéhicules à moteur:\n %.1f km/h\nby %s. New world record for narrowgauges: %.1f km/h by %s. Nouveau record du monde pour les trains à voie étroites: %.1f km/h por %s. New world record for planes: %.1f km/h by %s. Nouveau record du monde pour les\navions:\n %.1f km/h\nby %s. New world record for railways: %.1f km/h by %s. Nouveau record du monde pour les \ntrains:\n %.1f km/h \nby %s. New world record for ship: %.1f km/h by %s. Nouveau record du monde pour les\nbateaux:\n %.1f km/h\nby %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL village &1_CITY_SYLL -en-Gohelle &2_CITY_SYLL -en-Pévèle &3_CITY_SYLL -Ancoisne &4_CITY_SYLL -les-Marais &5_CITY_SYLL -en-Artois &6_CITY_SYLL -les-Près &7_CITY_SYLL -Noulette &8_CITY_SYLL -Fermont &9_CITY_SYLL -Capelle &A_CITY_SYLL -Thumesnil %1_CITY_SYLL Noyelle %2_CITY_SYLL Bruay %3_CITY_SYLL Calonne %4_CITY_SYLL Houplin %5_CITY_SYLL Billy %6_CITY_SYLL Hénin %7_CITY_SYLL Mons %8_CITY_SYLL Allennes %9_CITY_SYLL Vitry %A_CITY_SYLL Sailly %B_CITY_SYLL Camphin 1center %s %s 1extern %s-correspondance %s 1suburb %s %s %s 2center %s %s central 2extern %s %s extérieure 2suburb %s Champs %s %s 3center %s-place %s 3extern %s %s des champs 3suburb %s village %s %s 4center %s %s intérieur 4extern %s des marais %s 4suburb %s colonie %s %s 5center %s %s de transfert 5extern %s Wiesengrund %s 5suburb %s: %s Alfama 6center %s Hub %s 6extern %s: %s Évora 6suburb %s banlieue %s 7center %s ville %s 7extern %s: %s Gen. Carneiro 7suburb %s: %s Itaguaí 8center %s Knoten %s 8extern %s %s marge %s 8suburb %s satellite %s 9center %s Ring %s 9extern %s hameau %s 9suburb %s extension %s simutrans-124.3/simutrans/text/fr/000077500000000000000000000000001474050137200171735ustar00rootroot00000000000000simutrans-124.3/simutrans/text/fr/airtools.txt000066400000000000000000000110101474050137200215610ustar00rootroot00000000000000Aide sur les outils Aviation

Les outils Aviation

La barre d'outils "Aviation" contient les éléments nécessaires à la construction d'un réseau aérien. Ces outils permettent de construire (ou détruire) les pistes et voies de roulement (taxiways), les arrêts (lieux de chargement-déchargement pour les passagers, le courrier ou les biens), les dépôts (permettant d'acheter et gérer le matériel aérien - càd les avions la plupart du temps), ainsi que diverses extensions. Si vous jouez avec la timeline activée, certains bâtiments apparaîtront progressivement, vous donnant ainsi plus de choix.

Cliquez sur l?icône "avion" dans la barre supérieure pour ouvrir la barre d'outils aviation. Passez le curseur de la souris sur les icônes des différents outils pour connaître leur nom et certaines données : coût de construction, coût de la maintenance et vitesse maximum supportée.Sachez que les aéroports doivent être construits sur des surfaces planes, il n'y a pas de pentes possibles

La méthode à suivre pour construire simplement un aéroport :
1) construire une piste et un taxiway, les connecter
2) placer un arrêt sur une extrémité de taxiway
3) ajouter des bâtiments annexes si nécessaires

La barre d'outils Aviation contient, de gauche à droite :

Taxiway : permet le déplacement des avions entre la piste de décollage/atterrissage et l'arrêt. Ces taxiways sont construits au niveau du sol.
IMPORTANT : les taxiways ne doivent pas être connectés aux pistes par l'extrémité des ces dernières, mais sur le coté des pistes, sous peine d'empêcher le décollage ou l?atterrissage.
Pour construire un taxiway, cliquez sur l'outil "taxiway" désiré (le curseur se change en "taxiway"). Cliquez sur le point de départ du taxiway, puis sur le point d'arrivée (qui peut être une case vide ou une piste).

Piste : permet de construire une piste, utilisée par les avions pour décoller ou atterrir. Les pistes sont construites au niveau du sol, et peuvent éventuellement se croiser, mais ne peuvent être construites en diagonale.
Pour construire une piste, cliquez sur l'outil "piste" désiré (le curseur se change en "piste"). Cliquez sur le point de départ de la piste, puis sur le point d'arrivée, et ce en ligne droite stricte.
Les pistes doivent être connectées aux taxiways, sinon les avions ne pourront pas atterrir ou décoller.

Destruction de voies aériennes : permet de supprimer des segments de pistes ou de taxiways, si aucun avion n'est présent dessus. Cet outil de destruction est payant.
Pour détruire un segment, cliquer sur l'outil de destruction de voies aériennes (change le curseur en croix rouge). Cliquer sur la première extrémité du segment à supprimer, puis sur la deuxième.

Dépot Aérien : permet de construire un hangar pour acheter et gérer la flotte aérienne. Les hangars ont un cout de maintenance, et doivent être construits sur une extrémité de taxiway.
Pour construire un hangar, cliquez sur l'outil "hangar" désiré, puis sur une extrémité de taxiway.

Arrêts aériens et zones de chargement : permet la construction d'arrêts permettant aux avions de charger ou décharger des passagers, du courrier ou des biens. Si un tel arrêt n'est pas construit au contact d'un arrêt existant, cela va créer un nouvel arrêt.
Les arrêts ont un coût de maintenance et doivent être construits sur une extrémité de taxiway. ces arrêts possèdent une capacité de stockage de passagers ou biens. Un avion n'atterrira que si l'un de ces arrêts est libre et connecté à la piste via le taxiway.
Pour construire un arrêt, cliquez sur l'arrêt désiré, puis sur une extrémité de taxiway.
La touche "v" permet de montrer ou masquer la zone de couverture de l'arrêt.

Bâtiments aériens et extensions : permet de construire des extensions pour les stations. Ces extensions peuvent augmenter les coûts de maintenance, et permettre d'augmenter la capacité de stockage en passagers ou biens.
Une petite image dans le coin de l?icône permet de connaître le type d'extension (pour passagers, courrier ou biens)
Pour construire une extension, cliquez sur l'outil d'extension désirée puis placez là au contact d'un arrêt ou extension existant. Elle devient alors un élément de l'arrêt.

simutrans-124.3/simutrans/text/fr/baum_build.txt000066400000000000000000000022051474050137200220360ustar00rootroot00000000000000Aide sur la plantation des arbres Planter un arbre

la fenêtre de plantation des arbres est séparée en quatre parties :
- en haut à gauche : liste de sélection des différents arbres disponibles
- en bas à gauche : image de l'arbre sélectionné
- en haut à droite : réglages des options
- en dessous à droite : informations concernant l'arbre sélectionné

Liste de sélection


Dans cette liste, vous trouvez tous les arbres disponibles selon les options sélectionnées à droite. Ils sont classés de deux manières, accessibles via les onglets en haut de la liste :
translation : donne le nom de l'arbre dans une langue donnée (français par exemple). Si aucune traduction n'est disponible dans cette langue, c'est le nom interne de l'objet qui est affiché.
objet : donne le nom interne de l'objet dans simutrans

Options


Ignore climates : cette option désactive les restrictions de plantation dûes au climat.
Random year : avec cette option, l'arbre planté aura un âge aléatoire

simutrans-124.3/simutrans/text/fr/climates.txt000066400000000000000000000035301474050137200215360ustar00rootroot00000000000000Climate Control Help

Climate Control

Climate Control vous permet de modifier les options météorologiques et topographiques du monde à créer.

Climate Control s'ouvre automatiquement avecla création d'un nouveau jeu.

Niveau de la mer : Hauteur de l'eau (entre 0, terre exclusivement, et 5, avec alors des îlots).

Hauteur montagne : Hauteur des collines, entre 0 et 320.

Dénivelé carte : Entre 0 et 6. Une valeur élevée favorise l'existence sur terre d'une multitude de niveaux différents d'altitude.

Si hauteur et dénivelé sont simultanément élevés, il y aura beaucoup de montagnes, avec des pentes raides.

Si hauteur et dénivelé sont simultanément faibles, le monde généré sera très plat !

Si hauteur est élevée et que dénivelé est faible, il y aura peu de montagnes mais qui montent haut, les changements de niveaux étant éloignés (pente douce).

Si hauteur est faible et que dénivelé est élevé, alors le terrain est plat (les montagnes ont une pente raide... mais il n'y a pas de montagnes).

Summer snowline : Niveau à partir duquel il y a de la neige en été. Déterminé automatiquement à partie des choix suivants.

Winter snowline : Niveau à partir duquel il y a de la neige en été. Choisissez 0 si vous aimez le blanc. Le niveau maximal dépend des choix suivants.

Desert, tropic, mediteranean, temperate, tundra, rocky : Altitude à partie de laquelle vous pouvez commencer à trouver des terrains appropriés pour chaque climat. Ces options peuvent également être définie dans les fichiers de configuration pour Simutrans.


Actualisé pour Simutrans 100.0
05/07/2008. simutrans-124.3/simutrans/text/fr/color.txt000066400000000000000000000006721474050137200210570ustar00rootroot00000000000000Aide pour choix de couleur

Palette de couleur

Par ce menu, vous pouvez choisir la couleur de tous vos véhicules, gares etc... Pour sélectionner une couleur, cliquez simplement sur la couleur désirée. La couleur par défaut est le bleu clair. Tous les objets n'ont pas forcément votre couleur, ce sont les créateurs d'objets qui en décident.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/convoi.txt000066400000000000000000000017051474050137200212340ustar00rootroot00000000000000Liste des véhicules

Liste des véhicules

Cette liste vous affiche la liste de tous vos véhicules. (raccourci: Shift+V)

Si vous cliquez sur le nom ou l'image de la constitution de votre véhicule, une fenêtre de détail sur ce véhicule s'ouvre alors. Vous pourrez y voir toutes les informations comme le coût, revenu, chargement de votre véhicule.

Vous pouvez modifier les critère d'affichage des véhicules en appuyant sur le bouton à gauche : Nom, Revenu ou Type de véhicule. Le bouton juste à coté sert à afficher les véhicules selon l'ordre croissant ou décroissant.

Vous pouvez aussi filtrer la liste grâce aux boutons de droite. En cliquant sur le bouton de 'réglage' de filtrage, une fenêtre de sélection des critères de filtrage s'ouvrira. Puis vous pourrez activer le filtrage en appuyant sur le bouton 'activer'.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/convoi_filter.txt000066400000000000000000000025731474050137200226050ustar00rootroot00000000000000Filtres de véhicules

Filtrage de la liste des véhicules

Cet écran vous permet de définir des critères de filtrage pour afficher la liste de vos véhicules.

Les filtres sont organisés en groupe, indiqués en blanc. Vous pouvez activer un ou plusieurs groupe de filtre en appuyant sur les boutons associés à chaque groupe.

Filtre par Nom: Ecrivez tout ou partie du nom de véhicule, et appuyez sur le bouton associé pour valider le critère.

Filtre marchandises: Sélectionnez les marchandises transportées dans les véhicules que vous souhaitez voir affichés, et appuyez sur le bouton associé pour valider le critère.
Des boutons vous servent à sélectionner l'ensemble des critères marchandise ou aucun, ou encore d'inverser votre sélection.

Filtre par Type: Sélectionnez le(s) type(s) de véhicule que vous voulez afficher, et appuyez sur le bouton associé pour valider le critère.

Filtre spécial: Choissez ici les critères vous permettant de repérer les véhicules posant problème.

Important: Lorsque vous associez plusieurs critères, les véhicules affichés répondront à au moins un critère. ex: filtre par type : Train et bâteau, tous les trains et tous les bâteaux.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/depot.txt000066400000000000000000000060041474050137200210470ustar00rootroot00000000000000Les dépôts

Les dépôts

Dans un dépôt, vous pouvez acheter, vendre et définir les trajets de tous les véhicules d'un type particulier, par exemple : véhicules routiers si vous êtes dans un dépôt routier.

La fenêtre des dépôts contient les informations sur les véhicules que vous pouvez acheter, et ceux que vous avez déjà achetés. Dans les onglets à droite, sont affichés les véhicules que vous pouvez acheter. En haut à gauche, se trouve le convoi en cours d'assemblage (train). Au milieu à gauche, se sont les locomotives et camions que vous avez achetés. En bas à gauche, les wagons et remorques qui vous appartiennent.

Dans la partie basse, vous trouverez les informations concernant le véhicule actuellement sélectionné, et en dessous, il y a trois boutons.

Le plus à gauche est le bouton 'Départ', qui vous permet lancer le véhicule sur le trajet préalablement définit. Celui du milieu est le bouton 'Trajet', qui vous permet de définir un trajet pour le convoi en cours d'assemblage. Le bouton de droite est le bouton 'Vendre', qui vous permet de vendre des véhicules.

Pour voir les informations sur un véhicule particulier, survolez à la souris l'image correspondant. Vous les verrez alors dans la partie basse. Pour acheter un véhicule cliquez avec le bouton gauche de la souris sur le véhicule de votre choix dans l'onglet de droite. Il apparaîtra alors dans la partie gauche de la fenêtre. Le convoi que vous êtes en train de créer se trouve dans la partie supérieure de la fenêtre. Les autres véhicules (locomotives, camions, bateaux, chevaux) seront juste au dessous. Et les wagons, remorques et autres chariots apparaissent dans la partie du bas, juste au dessus de la partie 'informations'.

Pour créer un convoi, vous pouvez soit acheter tous les véhicules voulus les uns après les autres, en commençant par la locomotive ou le camion, puis par les wagons ou remorques. Ou alors, en sélectionnant les véhicules dans la partie gauche de la fenêtre. Vous ne pouvez agir que sur un seul véhicule à la fois. Pour vendre un de vos véhicules, sélectionnez le mode vente en appuyant sur le bouton 'Vendre', puis survolez à la souris le véhicule. Le prix de vente est alors affiché dans la partie 'informations', pour effectuer la vente, cliquez avec le bouton gauche de la souris sur le véhicule.

Pour définir le trajet d'un convoi cliquez sur le bouton 'Trajet' qui affichera la fenêtre de gestion de trajet. Une fois le trajet définit, vous ordonnez le départ du convoi en appuyant sur le bouton 'Départ'.

Pour renvoyer un convoi vers un dépôt, modifiez le trajet du convoi en lui indiquant le dépôt comme unique destination. Une fois arrivé dans le dépôt, le convoi sera désassemblé et chaque véhicule sera de nouveau disponible pour être réarrangé ou vendu.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/display.txt000066400000000000000000000024771474050137200214130ustar00rootroot00000000000000Aide sur les options d'affichage

Aide sur les options d'affichage

L'écran de gestion des options d'affichage permet de modifier de nombreuses paramètres qui vous permettrons de changer l'apparence visuelle de Simutrans.
Les options sont:

Luminosité - Eclairci et assombri l'affichage.
Couleurs - Sans effet
Défilement - La vitesse de défilement est proportionnelle au nombre défini.

Défilement inversé - inverse ou pas la droite / gauche, haut / bas et vice-versa quand vous faites défiler.
Afficher les piétons - Des piétons sont créés et affichés ou pas autour des villes. Si votre Configuration matérielle est juste, n'activez pas cette option.
Mode jour / nuit - Simule ou non les modes jour et nuit. Cette option activée, peut vous rendre une belle vue de nuit!

La moitié basse de l'écran vous informe sur la performance de votre ordinateur. Ces nombres n'ont pas d'intérêts pour le déroulement du jeu.
Important - On pourrait vous demander cette information lorsque vous êtes amené à remonter un dysfonctionnement.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/finances.txt000066400000000000000000000046461474050137200215340ustar00rootroot00000000000000Aide sur les finances

Finances [f]

Vous pouvez gérer vos finances par cet écran, accessible soit en pressant la touche 'f' ou en cliquant sur l'icône 'billet' dans la partie droite de la barre d'outils.
Vous y trouverez les informations financières de votre entreprise pour l'année passée et l'année en cours. Ainsi qu'un graphique permettant de voir rapidement l'état de vos finances. Un clic sur les entêtes de valeurs les affiche dans le graphique. Les onglets permettent de voir les valeurs des 10 dernières années et des 12 derniers mois

Revenu - Somme de tous les revenus dus au transport de marchandises et personnes.

Opération - Frais de fonctionnement des véhicules en circulation (Les frais de chaque véhicule sont indiqués dans les informations des dépôts et des convois

Maintenance - La somme des frais de maintenance des équipements qui vous appartiennent. Cette somme est déduite tous les mois et est indiquée à droite.

Péages routiers - Frais de péages pour l'utilisation des voies d'autres entreprises

Lignes électriques - Revenus des lignes électriques

Profit opérationnel - Profit sans les coûts de constructions et d'achats. Somme de revenu, opération, maintenance, péages et lignes électrique

Nouveaux véhicules - Somme de tous les véhicules achetés et vendus dans n'importe quel type de dépôt.

Construction - C'est la somme des dépenses concernant les constructions dans l'année en comprenant les signaux ferroviaires, les rails, les routes, les arrêts, les gares, les dépôts et les postes.

Profit - Profit de l'année en cours. Somme de profit opérationnel, nouveaux véhicules et construction.

Transporté(s) - Somme de quantité de biens transportés.

Cash - Argent disponible. Affiché au bas de l'écran.

Biens - Valeur des biens (véhicules, voies, ...) possédés.

Marge - Pourcentage entre profit opérationnel et revenu

Richesse - Somme cash et biens. Si cette valeur est négative, vous êtes en faillite.

Scénarios

Si vous jouez un scénario, l'objectif et le pourcentage de réussite est affiché.

simutrans-124.3/simutrans/text/fr/haltlist.txt000066400000000000000000000015011474050137200215550ustar00rootroot00000000000000Liste des arrêts

Liste des arrêts et gares

Cet écran vous montre tous les arrêts de bus, les gares et les quais de chargement du jeu.

Quand vous cliquez sur un arrêt, une fenêtre de détail de cet arrêt s'ouvre.

Il est possible de modifier l'ordre d'affichage des arrêt en appuyant sur le bouton à gauche. Les critères sont Nom, Attente, Type et numéro. Le bouton juste à coté permet de choisir l'ordre d'affichage croissant ou décroissant.

Vous pouvez aussi filtrer la liste grâce aux boutons de droite. En cliquant sur le bouton de 'réglage' de filtrage, une fenêtre de sélection des critères de filtrage s'ouvrira. Puis vous pourrez activer le filtrage en appuyant sur le bouton 'activer'.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/haltlist_filter.txt000066400000000000000000000032571474050137200231340ustar00rootroot00000000000000Filtrage des arrêts

Filtrage des arrêts, gares et quais de chargement

Cet écran vous permet de définir les critères de filtrage pour afficher la liste des arrêts.

Les filtres sont organisés en groupe, indiqués en blanc. Vous pouvez activer un ou plusieurs groupe de filtre en appuyant sur les boutons associés à chaque groupe.

Filtre par Nom: Ecrivez tout ou partie du nom de l'arrêt, et appuyez sur le bouton associé pour valider le critère.

Filtre par Matières premières: Sélectionnez les marchandises requises par les industries à proximité des arrêts que vous souhaitez voir s'afficher, et appuyez sur le bouton associé pour valider le critère.
Des boutons vous servent à sélectionner l'ensemble des critères marchandise ou aucun, ou encore d'inverser votre sélection.

Filtre par Production: Sélectionnez les marchandises produites par les industries à proximité des arrêts que vous souhaitez voir s'afficher, et appuyez sur le bouton associé pour valider le critère.
Des boutons vous servent à sélectionner l'ensemble des critères marchandise ou aucun, ou encore d'inverser votre sélection.

Filtre par Type: Sélectionnez le(s) type(s) d'arrêt que vous voulez afficher, et appuyez sur le bouton associé pour valider le critère.

Filtre spécial: Choissez ici les critères vous permettant de repérer les arrêts posant problème.

Important: Lorsque vous associez plusieurs critères, les arrêts affichés répondront à au moins un critère.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/language.txt000066400000000000000000000020561474050137200215220ustar00rootroot00000000000000Aide sur les langues

Ecran des langues

Simutrans est multilingue et vous permet de choisir la langue dans laquelle vous désirez afficher les textes. (Seulement si la traduction existe)
Quand vous changez la langue (en sélectionnt la langue voulue), le jeu va alors afficher tous les textes dans cette langue. Les écrans ne tiendront compte de la modification qu'à leur prochaine ré-ouverture.
Les villes existantes ne changeront pas de nom, et garderont les noms du jeu au démarrage. C'est pourquoi, lorsque vous souhaitez obtenir des noms de villes dans votre langue, choisissez la langue avant de créer un noveau jeu.

Si vous ne trouvez pas votre langue préférée, quelques traductions sont disponibles sur les sites http://www.simustation.de.vu et http://www.simutrans.de, mais elles ne sont pas toutes complètes, ni parfaitement à jour.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

Pour aider à traduire Simutrans dans votre langue,
visitez https://translator.simutrans.com

simutrans-124.3/simutrans/text/fr/load.txt000066400000000000000000000017331474050137200206570ustar00rootroot00000000000000Aide sur le chargement d'une partie

Charger un jeu

Le fait de charger une partie vous permet de continuer une partie que vous avez commencé auparavant. L'écran de chargement est très semblable à l'écran de sauvegarde.

Si vous tentez de charger un jeu inexistant, le jeu affichera un message d'erreur.

X - Pour supprimer un fichier de sauvegarde. Attention!, aucun message de confirmation n'apparaît.
Nom du fichier de sauvegarde - En cliquant dessus, Simutrans effectue le chargement de ce jeu.

Important Les sauvegardes effectuées avec d'anciennes versions de Simutrans ne sont pas toutes compatibles. Pour vous en assurer, veuillez vous reporter aux informations sur la version actuelle pour lire la mention de compatibilité. Entre les versions récentes et les plus anciennes, cela ne fonctionne pas.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/mailbox.txt000066400000000000000000000027551474050137200214000ustar00rootroot00000000000000Aide sur le centre des messages et leurs options

Centre des messages et options des messages

Dans le centre des messages arrivent tous les messages qui sont apparus depuis que le jeu a été créé ou chargé.

Avec le bouton Options, l'écran "Options des messages" va s'ouvrir. On y peut ajuster pour chaque message s'il apparaît dans une ligne en bas de l'écran principal de Simutrans (bouton de gauche), dans un écran temporaire (bouton du milieu) ou dans un écran permanent (bouton de droite).

De haut en bas, les messages suivants sont ajustables :
-Nouvelle année : un nouvel an a commencé.
-Nouveauté de l'AI : un joueur AI a ouvert une nouvelle ligne.
-Nouv dans villes : une ville construit une mairie plus grande.
-Pas de route : le véhicule nommé en ce message ne trouve pas de route pour le prochain arrêt.
-Industrie : par la croissance de la ville, une nouvelle chaîne industrielle avec un magasin a été construite.
-Touriste : une nouvelle attraction touristique ou un nouveau monument a été construit.
-Nouveau véhicule : un nouveau véhicule est disponible.
-Gare remplie : cet arrêt est surchargé.
-Problèmes : l'entreprise du joueur est débitrice ou autres messages critiques.

En cliquant sur un message avec le bouton gauche de la souris, on peut déplacer la vue du jeu sur l'événement.

simutrans-124.3/simutrans/text/fr/map.txt000066400000000000000000000050611474050137200205130ustar00rootroot00000000000000Aide sur la carte

Carte du jeu

On vient à la Carte du jeu en pressant 'm' ou par le symbol Carte dans la liste des symbols.

L'écran carte vous apporte une vue d'aigle sur le monde courrant avec des informations telles que les villes, les industries, les routes et les chemins de fer, vos véhicules etc. Vous allez atteindre chaque lieu en cliquant avec le bouton gauche.

En cliquant avec le bouton droit de votre souris, vous obtenez la carte en trois échelles differentes. La même fonction a la roue de la souris.

Chaque type d'industrie est référencé par une couleur différente, la légende est située au-dessous de la carte. Si le souris montre sur une industrie, les acheteurs sont soulignés; pressant simultanément la touche Shift, les fournisseurs sont mis en relief.

Les boutons colorés tout en bas de l'écran inscrivent certains informations dans la carte. S'il n'y a pas des indications de la couleur, l'échelle au droit de l'écran est utilisé.
Passagersmarque tous les territoires en blanc qui sont attachés à un arrêt.
Postemarque tous les territoires en bleu qui sont attachés à un bureau de poste.
Chargementmontre combien de chargement est transporté sur une pièce de la route ou du chemin de fer.
Statusmontre si les passagers à un arrêt sont transportes. La même vue est aussi utilisèe dans la liste des arrêts et à la ligne de status au nom de l'arrêt.
Servicemontre combien d'arrives et de départs se sont passés à un arrêt.
Circulationmontre la densité de la circulation sur une ligne.
Originemontre combien de passagers et de chargement ont cet arrêt comme point de départ.
Destinationmontre combien de passagers et de chargement ont cet arrêt comme déstination.
En attendantmontre combien de passagers et de chargement attendent à un arrêt pour être transportés.
Voiesouligne les lignes de chemin de fer en blanc; les lignes electrifiées sont soulignées en rouge. Les signaux sont marqués par un point jaune.
Limite de la vitessemontre rélativement les vitesses maximales sur les routes et les chemins de fer.
Lignesinscrit les lignes de transport dans la carte en rouge.
Attractionsenlarge les attractions touristiques inscrites dans la carte, et ils sont colorés selon leurs attractivités (Passagers).

Actualisé pour Simutrans 0.85.04.1
21.4.2005

simutrans-124.3/simutrans/text/fr/new_world.txt000066400000000000000000000107421474050137200217400ustar00rootroot00000000000000Aide sur un nouveau monde (nouveau jeu)

Créer un nouveau jeu

Les fenêtres qui permettent de créer un nouveau monde sont accessible au lancement du jeu et, en cours de partie, en cliquant sur la disquette (option) puis sur menu général.

Cet écran vous permet de créer une nouvelle carte (donc un nouveau jeu), en définissant les paramètres relatifs à l'époque, à la carte, à la météo, aux villes et aux industries.

Load game : Vous permet de charger l'un de vos jeux précédemment sauvegardé. Cliquez ici pour plus d'infos.

Charger un relief : si vous disposez d'un fichier avec un relief déterminé.

Numéro de carte : Sélectionnez l'une des nombreuses cartes à jouer, soit en entrant le n° souhaité, soit en utilisant les boutons qui permettent de passer à la carte précédente/suivante, soit en cliquant sur «carte quelconque» pour qu'un numéro de carte soit tiré au sort.

Dimensions : Nombre de carrés dont le monde généré sera composé. Valeur mini : 64, maxi : 4096. Attention à ne pas générer une carte trop grande pour la capacité de calcul de votre ordinateur. Une carte trop petite peut avoir pour conséquence un non respect de vos autres choix (s'il y a peu de terres, il ne pourra pas y avoir beaucoup de villes, par exemple).

Nb villes : Nombre initial de villes. D'autres villes peuvent être crées en cours de partie en payant une somme importante... ou en demandant au joueur service public de le faire.

Moyenne d'habitants par Ville : Nombre moyen de personnes vivant dans chaque ville (certaines villes seront bien évidemment plus grosses et d'autres plus petites, ce n'est qu'une moyenne).

Intercity road len : Longueur maximale de route reliant les villes entre elles. Une valeur élevée facilite les connexions routières entre les villes dès le début de la partie.

Densité Trafic : Densité Trafic : Trafic généré par l'ordinateur. Entre 0 et 16 (modifiable en cours de partie dans les options). Une valeur élevée représente un challenge pour gérer risques d'embouteillages et circulation de vos bus et camions. Une valeur nulle permet une circulation totalement privée.

Fabriques en dehors des villes : Nombre d'usines : bâtiments autonomes comme l'éolienne, sites d'extraction de matières premières, agriculture et élevage, industries de transformation.

Marchés dans les villes : Industries de vente dans les villes (supermarchés, etc.). Ces bâtiments consomment des biens (à y acheminer) pour les vendre à la population, il ne produisent aucun bien à transporter.

Tourist attractions : Nombre initial de sites touristiques, qui génèrent du trafic passagers et de courrier.

Use timeline start year : Si la case est cochée, les limitations applicables aux bâtiments et véhicules seront appliquées en fonction de l'année de départ choisie. Attention, il n'y a pas de construction de fabrique en cours de partie (sauf en jouant le joueur service public qui peut ajouter des attractions, des centrales électriques et des marchés dans les villes), et si l'année de départ est très ancienne il peut n'y avoir aucune fabrique sur la carte. Si la case n'est pas cochée, vous pouvez commencer en 1750 avec des usines électroniques et des éoliennes.

Autoriser le changement de joueur : Le titre est clair. Quand le changement est possible, il permet même d'incarner temporairement un joueur spécial qui bénéficie de quelques options spéciales et d'un découvert illimité : service public.

Beginner Mode : Les débutants et les mauvais gestionnaires peuvent cocher cette case pour bénéficier de revenu majorés de 50% et obliger les usines à toujours accepter les marchandises, même quand elles sont en surnombre vu la consommation du bâtiment.

C'est parti ! : Est-il nécessaire de préciser l'effet d'un click sur ce bouton une fois tous vos choix paramétrés ?

Pensez, en début de partie, à aller configurer, à partir du bouton en forme de disquette (option), les couleurs utilisées et les informations relatives aux joueurs (pour ajouter ou enlever des joueurs contrôlés par l'ordinateur, selon que vous préfériez jouer en solo ou avec des concurrents).

Actualisé pour Simutrans 100.0
05/07/2008.

simutrans-124.3/simutrans/text/fr/options.txt000066400000000000000000000021401474050137200214240ustar00rootroot00000000000000Aide sur les options de jeu

Options

L'écran des options de jeu est le carrefour vers les différents écrans de paramétrage de Simutrans allant du réglage fin au réglage de comportement. Ci-dessous, vous trouverez une liste des écrans disponibles et une brève description de chacun.

Langue - Définit la langue de jeu de Simutrans.
Couleur - Change la couleur de vos entreprises.
Affichage - Définit les paramètres d'affichage tels que les modes jour/nuit.
Son - Vos choix de musique d'ambiance.
Joueurs - Les différents joueurs adversaires.
Charger - Charger un jeu précédemment sauvegardé.
Sauvegarder - Sauvegarder la partie en cours.
Menu général - Démarrer un nouveau jeu (peut être annulé ensuite)
Quitter - Quitter, sans message de confirmation.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/players.txt000066400000000000000000000012431474050137200214130ustar00rootroot00000000000000Aide sur les joueurs adverses

Ecran des joueurs

Cet écran vous permet de choisir votre (vos) adversaire(s) dans le jeu. Ils sont gérés par le moteur d'Intelligence Artificielle du jeu.

Pour activer/désactiver un adversaire, cliquez simplement sur le bouton correspondant. Notez cependant que le fait de désactiver un adversaire ne va pas supprimer toutes ses routes, rails, véhicules, et il continuera aussi de percevoir ses revenus. Désactiver un adversaire le met tout simplement en veille.

L'écran vous indique aussi le solde de chacun de vos adversaires.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/railtools.txt000066400000000000000000000100501474050137200217400ustar00rootroot00000000000000Ferroviaire

L'écran de gestion ferroviaire

Cet écran comprend les outils de construction de rails, gare, dépôt, tunnel, passages à niveau, signalisation pour trains.

En haut à gauche, il y a l'outil de construction des rails. Cet outil permet de construire les rails entre les carrés. Cliquez et votre curseur prendra la forme d'un passage à niveau. Pour construire une voie ferrée, cliquez d'abord sur le point de départ, le curseur prendra alors la forme d'un bulldozer. Cliquez ensuite sur le point d'arrivée de votre voie ferrée. Simutrans construira alors le chemin de fer entre les deux carrés. Il n'utilisera uniquement que des carrés libres. Il ne franchira pas de route, n'utilsera pas de tunnels ou ponts. Si la construction n'est pas possible, il ne se passera rien.

A sa droite, l'outil de placement des signaux ferroviaires. Cliquez dessus pour changer le curseur en signal. Ces signaux sont utiles pour contraindre les mouvements des trains. Utilisez les pour autoriser deux trains à emprunter le même chemin, mais l'un après l'autre. Les signaux sens-unique forcent les trains dans un sens. Pour placer un signal sens-unique, placer un signal et cliquez le afin de le changer en 'sens-unique'. En cliquant plusieurs fois sur un signal, vous changerez son sens, et son type (Mono ou bi-directionnel). Soyez prudent dans l'utilisation des signaux 'sens-unique' car les trains ne sauront pas quel chemin prendre si vous vous êtes trompés. Pour placer un signal, cliquez ensuite sur la protion de rail où vous voulez le placer. Les signaux sont placés au bord des carrés, mais comptent pour un seul carré. Il ne peut y avoir qu'un seul signal par carré. Pour supprimer un signal, utilisez l'outil de destruction, et cliquez sur le carré où vous avez placé le signal. Ceci supprimera le signal en laissant intact le rail.

Le dernier symbole du haut est l'outil de construction de tunnels. Cliquez dessus et le curseur prendra l'image du tunnel. Les tunnels sont utilisés pour créer une seule de section de tunnel sous une montagne. Utilisez les pour éviter de contourner les montagnes. Pour placer un tunnel, vous devez d'abord avoir vos sections de rails. Placez le début et la fin des rails au bord de la montagne (de chaque côté), assurez-vous que les niveaux d'altitudes sont identiques. Pour construire le tunnel cliquez avec l'outil de placement sur l'une des deux extrémités.

Au dessous de ces symboles, il y a le passage à niveau. Cliquez dessus pour changer le curseur en passage à niveau. Ils sont utiles pour faire se croiser une route et une voie ferrée. Pour le placer, cliquez avec le bouton gauche sur une section de route.

A gauche, c'est le dépôt ferroviaire. Cliquez dessus pour changer le curseur en dépôt. Ils sont utilisés pour acheter, assembler, démonter et vendre des motrices et des wagons. pour placer le dépôt, cliquez sur un début/fin de rails.

Le dernier symbole est celui de la construction de gare. Cliquez dessus, le curseur prendra la forme d'un segment de gare. Les gares permettent aux trains de charger et décharger les passagers et marchandises. Les gares peuvent être composées de plusieurs segments alignés ou juxtaposés. Les gares peuvent contenir un nombre illimités de marchandises, mais les usines produisent lorsque moins de 1000 unités (tonnes, palettes, m3) attendent. Les gares sont construites à partir de segments individuels. Pour positionner un segment, cliquez sur le carré où vous souhaitez le placer. Les gares doivent être construites sur des rails existant, mais ne peuvent pas être placées dans des montées, descentes et intersections. Chaque segment adjacent avec une gare devient une partie de celle-ci, même si elle est située sur une autre section de rail. A chaque segment correspondent 2 wagons ou motrices. Assurez-vous de la longueur des gares pour vos trains les plus longs. Tout wagon se trouvant hors de la gare ne sera pas chergé ou déchargé.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/roadtools.txt000066400000000000000000000047571474050137200217570ustar00rootroot00000000000000Aide routière

L'écran de gestion routier

Cet écran vous donne accès a l'ensemble des outils de construction de routes, arrêts de bus, tunnels routiers, dépôts, passages à niveau, quai de chargement.

Dans le coin en haut à gauche se trouve l'outil de création de route. Cliquez dessus et le curseur prendra la forme du même symbole. Pour commencer la construction d'une route cliquez d'abord sur le point de départ, puis cliquez sur le point d'arrivée de la section. La route sera construite entre ces deux points.

A sa droite, le symbole indique la construction d'arrêts de bus. Cliquez dessus pour changer votre curseur en arrêts de bus. Les arrêts de bus permettent aux bus de prendre et déposer des passagers. Il peut contenir 2 bus, un dans chaque direction. Pour le placer, cliquez à l'endroit voulu. Il doit être positionné sur une portion de route, mais pas dans les intersections, ni les virages.

Le dernier symbole permet de construire les tunnels. Cliquez dessus et le curseur prendra l'image du tunnel. Les tunnels sont utilisés pour créer une seule de section de tunnel sous une montagne. Utilisez-les pour éviter de contourner les montagnes. Pour placer un tunnel, vous devez d'abord avoir vos sections de route. Placez le début et la fin de la route au bord de la montagne (de chaque côté), assurez-vous que les niveaux d'altitudes sont identiques. Pour construire le tunnel cliquez avec l'outil de placement sur l'une des deux extrémités.

Au dessous de ces symboles, il y a le passage à niveau. Cliquez dessus pour changer le curseur en passage à niveau. Ils sont utiles pour faire se croiser une route et une voie ferrée. Pour le placer, cliquez avec le bouton gauche sur une section de route.

A gauche, c'est le dépôt routier. Cliquez dessus pour changer le curseur en dépôt. Ils sont utilisés pour acheter, assembler, démonter et vendre des Camions, bus, fourgons postaux. Placer simplement le dépôt sur l'extrémité d'une portion de route à l'endroit voulu.

Le dernier symbole représente les quais de chargement/déchargement. Cliquez sur ce symbole et le curseur prendra sa forme. Les quais de chargement servent aux camions pour prendre et déposer des marchandises. Deux véhicules seulement peuvent emprunter un quai simultanément. Pour placer un quai de chargement, utilisez le même principe que pour les dépôts (ci-dessus).

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/save.txt000066400000000000000000000023361474050137200206760ustar00rootroot00000000000000Aide sur la sauvegarde

Sauvegarder un jeu

Si vous souhaitez jouer sur le même jeu pendant plusieurs jours, vous devrez sauvegarder le jeu à certains moments. Simutrans vous propose une solution vous permettant de sauvegarder l'ensemble de vos données dans un fichier.

L'écran de sauvegarde vous permet de sauvegarder vers un nouveau fichier ou d'écraser un fichier existant ou encore de supprimer un fichier. Pour sauvegarder un nouveau fichier, entrez le nom (sans extension) dans la zone de texte et cliquez sur le bouton 'sauver'. L'écran va alors se refermer et un message vous confirmera la bonne sauvegarde de votre jeu. Si vous souhaitez écraser un fichier existant, cliquez simplement sur son nom.

Pour la suppression de fichiers, soyez vigilants car une fois le fichier effacé, vous ne pourrez plus le retrouver. Même dans la poubelle (pour les versions Windows), vous ne le retrouverez plus. Pour supprimer un fichier cliquez sur le bouton 'X' en face du nom du fichier que vous voulez supprimer.
NB: Vous n'aurez pas d'autre information une fois le bouton pressé, l'écran va simplement se refermer.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/schedule.txt000066400000000000000000000074611474050137200215400ustar00rootroot00000000000000Itinéraires

Programmation des itinéraires

Il a deux manières de programmer ses véhicules :
1 - Dans les dépôts, à la création un nouveau véhicule ou convoi.
2 - Dans la fenêtre d'un véhicule en fonctionnement, par l'option "trajet".
Les procédures sont semblables : On peut Ajouter, Insérer ou Supprimer des arrêts, ainsi que modifier la limite de charge minimum ou la liste des arrêts vers lesquels le véhicule doit être dirigé.

A la fin, vous trouverez un exemple de l'utilisation des commandes qui sont décrites à suivre.

Aj. Arrêt : il sert à ajouter des arrêts à la fin d'une liste.
Ins. Arrêt : il insère un arrêt avant celui identifié par >>.
Sup. Arrêt : il sert à effacer un arrêt.
Fin : Quand vous avez terminé la définition de l'itinéraire de votre véhicule, l'appui sur ce bouton valide les modifications et ferme l'écran.
Charge mini (dans le haut de l'écran) : minimum de chargement que le véhicule doit atteindre pour continuer son chemin.
Il peut être 0, 20. 40. 60. 80 ou 100%. Zéro signifie que le véhicule va charger ce qu'il y aura dans la gare, et va partir immédiatement. Cent, le véhicule partira seulement quand il sera complet.

Attention donc, vous pouvez bloquer d'autres trains, tandis que celui-ci attendra pour atteindre sa capacité minimum.

Exemple : Un train doit porter le bois de la forêt 1 (F1) et de la forêt (F2) à Scierie 1 (S1) et à une papeterie (FP). Vous construisez vos voies et vos gares. Vous créez le dépôts ferroviaire et achetez le train. Cliquez sur 'Trajet''. Simutrans va vous ouvrir l'écran de gestion des trajets. On remarque tout de suite la charge mini: 0%. Et dans le bas, quatre boutons : 'Aj. Arrêt', 'Ins. Arrêt', 'Sup. Arrêt' et 'Fin'.

1. Pour créer l'itinéraire, cliquez sur 'Aj. Arrêt', commencez d'abord par le premier arrêt et ainsi de suite jusqu'au dernier du cycle. C'est très simple : le curseur va prendre l'aspect d'une pancarte où il est inscrit 'STOP', et il vous reste à cliquer sur les gares dans l'ordre désiré du passage.

2. Envisageons maintenant que le train ne doit pas quitter F1 avec moins de, disons, 20% de sa capacité, cliquez sur la gare de F1 dans le trajet, et après cela, dans la zone 'Charge mini' sur la flèche de droite pour augmenter la charge à 20% . L'autre flèche diminue la charge minimum.

3. Nous allons dire que vous voulez que le train passe par une autre scierie, la scierie 2 (S2), qui serait entre S1 et FP. Pour ceci, cliquez sur 'Ins. Arrêt' quand le trajet pointe sur la gare FP. Cliquez ensuite sur la gare S2. L'arrêt S2 sera entre S1 et FP. N'oubliez pas, qu'un raccordement doit exister entre la gare S2 et le circuit principal, et qu'il doit être électrifié, si votre train est électrique.

4. Disons que vous allez réaliser un changement de votre système et que vous êtes contraint de détruire une gare (S1 par exemple). Dans la définition du trajet, comme vous avez détruit la gare S1, vous voyez que l'itinéraire contient les coordonnées du segment de cette gare (x,y). Vous devrez lors supprimer cette ligne de l'itinéraire : sélectionnez la ligne en question et appuyez sur le bouton 'Sup. Arrêt'. Pour insérer la nouvelle gare, il suffit de suivre le procédé décrit dans le point 3.

5. Pour quelque raison, vous voulez que le train passe une certaine gare, ou simplement se rende immédiatement à une gare précise. Avec la programmation du train ouvert, cliquez sur l'arrêt souhaité.

6. Pour valider vos modifications, cliquez sur le bouton 'Fin'.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/shiptools.txt000066400000000000000000000026611474050137200217650ustar00rootroot00000000000000Aide maritime

L'écran de gestion maritime

Cet écran vous donne accès aux outils de construction de quais et gares maritime.

Dans le coin supérieur gauche se trouve le symbole du quai de chargement maritime. Cliquez dessus et votre curseur prendra la forme de ce symbole. Les quais permettent aux bateaux de charger et décharger leurs marchandises et passagers. Pour positionner un quai maritime cliquez sur la terre qui se trouve au bord de la mer, le quai est composé de deux parties : l'une sur la terre et l'autre en mer. Ils doivent être construits sur un littoral droit. Il est possible de construire de très grands quais, mais ils doivent toujours être adjacents les uns avec les autres. Pour diriger un bateau vers un quai, vous devrez l'envoyer vers un des carrés qui entoure le quai et pas le quai lui même. Attention, les quais ne peuvent pas encore être retirés proprement !

En bas, vous trouverez deux symboles pour construire une gare maritime, ils diffèrent seulement par le fait que l'un est orienté vers la gauche et l'autre vers la droite. Cliquez sur l'un des deux pour changer votre curseur à son effigie. Les gares maritimes servent à acheter les navires que vous désirez. Pour positionner une gare maritime cliquez dans l'eau à l'endroit où vous souhaitez construire votre gare maritime.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/sound.txt000066400000000000000000000017751474050137200210760ustar00rootroot00000000000000Aide sur les sons

Réglages sons et musiques

Dans cet écran vous pourrez ajuster les niveaux sonores de la musique et des sons joués dans Simutrans.

Les volume sont réglables via le curseur horizontal, pour augmenter déplacer le curseur vers la droite. Le volume sonore définit le niveau des effets sonores du jeu tels que les bruits des trains, etc. Le volume usical définit le niveau de la musique d'ambiance(fond sonore) du jeu.
Les derniers boutons au bas servent à définir le morceau de musique à jouer en tant que musique d'ambiance. Le bouton de gauche sert à faire défiler les morceaux de musique vers l'arrière et l'autre vers l'avant. S'il ne trouve aucun morceau de musique, c'est deux boutons n'auront aucun effet.
NB: La musique n'est pas fournie avec Simutrans, vous devrez l'ajouter manuellement. l'intérêt de cette aide ne concerne pas la procédure d'ajout de musique.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/fr/station.txt000066400000000000000000000027611474050137200214230ustar00rootroot00000000000000Les gares

L'écran de gestion des gares

Dans cet écran, vous pouvez trouver toute l'information sur la gare concernée. Vous pouvez voir les marchandises en attente de livraison, quelles marchandises sont attendues par les entreprises locales et quelles gares sont reliées à celle-ci.

Vous pouvez également modifier le nom d'une gare en changeant son nom dans la zone de texte en haut de l'écran. Cliquez simplement sur le nom et entrez le nouveau nom. Appuyez sur la touche 'Entrée' et votre modification est prise en compte.

Au bas de cet écran, sont affichées les marchandises en attente de livraison dans cette gare. Cette information est structurée pour afficher tous les mêmes types de marchandise ensemble. Par exemple:
402 voitures en attente
83 passagers en attente

Chacune de ces entêtes est éclatée en sous-entête, qui indiquent où les marchandises doivent aller, et leur nombre exact. Par exemple:

56 passagers en attente
- 25 passagers > Paris gare
- 29 passagers > Lyon gare via. Paris arrêt sud
- 2 passagers > Marseille gare

Dans le coin supérieur droit se trouve un bouton nommé 'Détails'. Cliquez dessus pour faire ouvrir une autre fenêtre indiquant les besoins en marchandises des industries locales, et les liaisons directes avec cette gare.

Les liaisons directes sont définies pour chaque type de marchandise.

Actualisé pour Simutrans 0.83.1.2
02/01/2003

simutrans-124.3/simutrans/text/gr.tab000066400000000000000000000521701474050137200176710ustar00rootroot00000000000000§Ellinika PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: gr Ellinika # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable απενεÏγοποιημένο cl_btn_filter_enable ενεÏγοποιημένο cl_btn_filter_settings Ρυθμίσεις cl_btn_sort_asc με αÏξουσα σειÏά cl_btn_sort_desc με φθίνουσα σειÏά cl_btn_sort_id εσωτεÏικό ID cl_btn_sort_income Εισόδημα cl_btn_sort_name Όνομα cl_btn_sort_type Είδος clf_btn_alle όλα clf_btn_keine κανένα gl_btn_sort_name ανά όνομα gl_btn_unsort αταξινόμητο hl_btn_filter_disable απενεÏγοποιημένο hl_btn_filter_enable ενεÏγοποιημένο hl_btn_filter_settings Ρυθμίσεις hl_btn_sort_asc ανιών hl_btn_sort_desc κατιών hl_btn_sort_name Όνομα hl_btn_sort_type Είδος hl_btn_sort_waiting Αναμονή hlf_btn_alle όλα hlf_btn_invers αντίστÏοφα hlf_btn_keine κανένα Scenario ΠληÏοφοÏίες για το σενάÏιο #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic αÏκτικό κλίμα desert κλίμα της εÏήμου #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Δεν μποÏείτε να χτίσετε έναν χώÏο στάθμευσης εδώ. Cannot create generic line!\nSelect line type by\nusing filter tabs. Δεν μποÏείτε να φτιάξετε μια γÏαμμή Î³ÎµÎ½Î¹ÎºÎ¿Ï Ï„Ïπου!\nΕπιλέξτε ένα είδος γÏαμμής\nχÏησιμοποιώντας φίλτÏα καÏτελών. Das Feld gehoert\neinem anderen Spieler\n Αυτό το τμήμα\nτου εδάφους ανήκει σε\nέναν άλλο παίκτη!\n Der Besitzer erlaubt das Entfernen nicht \nΟ ιδιοκτήτης δεν δίνει\nάδεια για να\nτο διαγÏάψετε!\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Δεν μποÏείτε να χτίσετε\n\nκτίÏιο αεÏοδÏομίου εδώ.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Δεν μποÏείτε να τοποθετήσετε\nσήματα σιδηÏοδÏόμων εδώ.\n Lost connection\nto server! Χαμένη σÏνδεση\nμε τον διακομιστή! Lost synchronisation\nwith server. Χάθηκε ο συγχÏονισμός\nμε τον διακομιστή Not enough money! Δεν έχεις αÏκετά\nχÏήματα για να το χτίσεις! Schiffhalt muss im\nWasser liegen!\n Το stop για τα πλοία μποÏει\nνα τοποθετηθεί μόνο\nκοντά σε λιμάνι!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Show the owenership of infrastructure Εμφάνιση κυÏιότητας των υποδομών #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s τώÏα\nÏ€ÏοσφέÏει υπηÏεσίες για λεωφοÏεία\nÎ¼ÎµÏ„Î±Î¾Ï %s\nκαι δελεαστικές Ï€Ïοτάσεις\n%s\nat (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s τώÏα\nÏ€ÏοσφέÏει υπηÏεσίες για λεωφοÏεία\nÎ¼ÎµÏ„Î±Î¾Ï %s\nκαι εÏγοστάσιο\n%s\nat (%i,%i).\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ LISTTOOLS Λίστες ROADTOOLS ΕÏγαλεία για δÏόμους SHIPTOOLS ναυτιλιακά εÏγαλεία #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s's έχει χτίσει ένα καινοÏÏιο διοικητήÏιο New %s now available:\n%s\n ΚαινοÏÏιο %s τώÏα διαθέσιμο:\n%s\n\n Now %u clients connected. ΤώÏα ακÏιβώς %u οι πελάτες είναι συνδεδεμένοι. Remove vehicle from map. Use with care! ΑφαίÏεσε το όχημα από τον χάÏτη #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (στον χώÏο στάθμευσης οχημάτων) \nBauzeit bis μέχÏι \nBauzeit von \nΕμφανίζεται από \nCan't open heightfield file.\n \nΑδυναμία φόÏτωσης Ïψους του χάÏτη.\n\n \ndirection: \nκατευθÏνσεις: \nelektrified \nμε ηλεκτÏισμό\n \nHeightfield has wrong image type.\n \nΤο πεδίο Ïψους έχει λανθασμένο\nÏ„Ïπο εικόνας.\n \nis reserved by: \nδεσμευμένο από Ï„Ïένο \nminimum speed: \nελάχιστη ταχÏτητα: \nnot elektrified \nχωÏίς ηλεκτÏισμό\n \nRibi (masked) \nκατευθÏνσεις\m (με απόκÏυψη): \nRibi (unmasked) \nκατευθÏνσεις\n (χωÏίς απόκÏυψη): \nsingle way \nΑπλή διαδÏομή \nway1 reserved by διαδÏομή 1 δεσμευμένη από\nδιαδÏομή 1 δεσμευμένη από \nway2 reserved by διαδÏομή 2 δεσμευμένη από\nδιαδÏομή 2 δεσμευμένη από \nwith sign/signal\n \nμε σήμα/σήμα\n %d buildings\n %d κτίÏια %d convois %d φάλαγγες οχημάτων %d Einzelfahrzeuge im Depot %d οχήματα σταθμευμένα εδώ. %i km/h (max. %ikm/h) %i χμ/ÏŽ (μέγ. %iχμ/ÏŽ) %s building %s %s %s %s %s %s city %d %s %s πόλη %d %s %s has entered a depot. %s έχει μπει στον χώÏο στάθμευσης οχημάτων. %s land %d %s %s γη %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \nέχτισε ένα\nκαινοÏÏιο δημαÏχείο\nόταν αυξήθηκαν\n%i οι κάτοικοι. %s\nis crowded. %s\σταθμός γεμάτος. %s\nwas liquidated. %s\nέχει εξοφληθεί. <δεν υπάÏχει γÏαμμή> 1 convoi 1 φάλαγγα οχημάτων 1 Einzelfahrzeug im Depot 1 όχημα πάÏκαÏε εδώ. 1LIGHT_CHOOSE Φωτεινότητα: 1WORLD_CHOOSE Ρυθμίσεις νέου παιχνιδιοÏ: Apply Line ΕφαÏμογή γÏαμμής April ΑπÏίλιος Arbeiter aus: Οι εÏγαζόμενοι ζουν σε: August ΑÏγουστος Autohalt muss auf\nStrasse liegen!\n Οι χώÏοι στάθμευσης αυτοκινήτων ή λεωφοÏείων\nÏ€Ïέπει να τοποθετηθοÏν\nκοντά στον δÏόμο. Available Διαθέσιμο Bahndepot ΧώÏος στάθμευσης Ï„Ïένων Bankrott:\n\nDu bist bankrott.\n ΧÏεοκοπημένος:\n\nΕίστε χÏεοκοπημένος!\n battery ΜπαταÏία bridge is too high for its type! Για τέτοιου Ï„Ïπου γέφυÏες, το Ïψος αυτό είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿! Bridge is too long for this type!\n Για τέτοιου Ï„Ïπου γέφυÏες,\nτο άνοιγμα είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿.\n Bruecke ΓέφυÏα Bruecke muss an\neinfachem\nHang beginnen!\n Οι γέφυÏες Ï€Ïέπει\nνα ξεκινοÏν από μια\nεπιφάνεια με κλίση!\n Brueckenboden γέφυÏα Build air depot Δεν υπάÏχει! build choosesignals ΔημιουÏγία πλατφόÏμας, επιλογή σημάτων Build city market Χτίστε μια νέα αγοÏά στην κοντινότεÏη πόλη. Build drain Σταθμός μετασχηματιστών build HQ Χτίστε HQ Build land consumer Χτίστε ένα νέο σταθμό ενέÏγειας. Build maglev depot Χτίστε έναν χώÏο στάθμευσης για αεÏοτÏένα. Build monorail depot Χτίστε χώÏο στάθμευσης αεÏοτÏένων μονής Ï„Ïοχιάς. Build narrowgauge depot Χτίστε χώÏο στάθμευσης για Ï„Ïένα με στενές γÏαμμές. Build powerline Χτίστε γÏαμμή μεταφοÏάς ενέÏγειας. Build presignals Τοποθετήστε σήματα Î´Î¹Ï€Î»Î¿Ï Î¼Ï€Î»Î¿Îº. Build road depot Χτίστε χώÏο στάθμευσης αυτοκινήτων. Build ship depot Χτίστε ναυπηγείο. Build signals Τοποθετήστε σήματα. Build train depot Χτίστε χώÏο στάθμευσης Ï„Ïένων. Build tram depot Χτίστε χώÏο στάθμευσης Ï„Ïαμ. Build truck depot Χτίστε χώÏο στάθμευσης αυτοκινήτων. Building costs estimates Δεν υπάÏχει! Buildings Δεν υπάÏχει! Built artifical slopes Κατασκευάστε τεχνητές επιφάνειες. Built random attraction Κατασκευάστε τυχαία κάτι ελκυστικό. Bus_tab ΛεωφοÏεία Can only move from halt to halt or waypoint to waypoint. Η κίνηση είναι δυνατή μόνο n\από στάση σε στάση ή \nαπό ένα ενδιάμεσο σημείο σε ένα άλλο. Cancel ΆκυÏο Capacity: %s\nLoad: %d (%d%%) ΧωÏητικότητα: %s\n? %d (%d%%) Cars are not available yet! Δεν υπάÏχουν διαθέσιμα αυτοκίνητα ακόμη. cars.\nstate αυτοκίνητα\n Cash Υπόλοιπο λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï Change player Αλλάξτε παίκτη Chart ΔιάγÏαμμα Choose direction Δεν υπάÏχει! Choose operation executed on clicking stored/new vehicles Επιλέξτε τη λειτουÏγία που θα εκτελεστεί με κλικ στα παλιά/καινοÏÏια αυτοκίνητα. chooses a random map Επιλέξτε έναν τυχαίο χάÏτη. citicens Πολίτες City attraction Δεν υπάÏχει! City industries ΑγοÏές στις πόλεις City list Κατάλογος πόλεων City size Μέγεθος πόλης city_road ΔÏόμος πόλης citybuilding builder Δεν υπάÏχει! CityLimit ÎŒÏια πόλης cl_title Κατάλογος οχημάτων cl_txt_sort Ταξινόμηση κατά: clf_chk_aircrafts αεÏοπλάνα clf_chk_cars ΛεωφοÏεία/ΦοÏτηγά clf_chk_indepot μέσα σε χώÏο στάθμευσης clf_chk_maglev ΑεÏοτÏένα clf_chk_monorail ΑεÏοτÏένα μονής Ï„Ïοχιάς clf_chk_name_filter Ονόματα φίλτÏων: Copy Convoi ΑντιγÏαφή φάλαγγας οχημάτων Copy the selected convoi and its schedule or line ΑντιγÏάψτε την επιλεγμένη φάλαγγα οχημάτων και το χÏονοδιάγÏαμμά της ή τη γÏαμμή Create a new line based on this schedule Κατασκευάστε μια νέα γÏαμμή βασισμένη σε αυτό το χÏονοδιάγÏαμμα Deccelerate time ΧÏόνος επιβÏάδυνσης December ΔεκέμβÏιος Del Stop ΑφαίÏεση Delete Line ΔιαγÏαφή γÏαμμής Delete this file. ΔιαγÏαφή Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… αÏχείου. Denkmal Μνημείο Depots ΧώÏοι στάθμευσης Der Tunnel ist nicht frei!\n Η σήÏαγγα δεν είναι άδεια.\n Destination ΠÏοοÏισμός Details ΛεπτομέÏειες Die Bruecke ist nicht frei!\n Η γέφυÏα δεν είναι ελεÏθεÏη!\n diesel πετÏελαιοκινητήÏας Display settings Ρυθμίσεις εμφάνισης Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Έχετε %d μήνες για να εξοφλήσετε τις οφειλές σας. Filter: ΦίλτÏο: follow me Ακολουθώ Follow the convoi on the map. ΑκολοÏθησε την αυτοκινητοπομπή στο χάÏτη Forest Δάσος Found new city Î’Ïες καινοÏÏια πόλη Frame time: ΧÏονικό πλαίσιο Free Capacity ΕλεÏθεÏος χώÏος freeplay mode ελεÏθεÏος Ï„Ïόπος Ï€Î±Î¹Ï‡Î½Î¹Î´Î¹Î¿Ï Full load Ελάχιστο φοÏτίο GAME PAUSED Το παιχνίδι έχει διακοπή Game_msg Γενικός Gebaeude ΚτίÏιο Gewicht ΒάÏος Gewinn Εισόδημα: Give the selected vehicle(s) an individual schedule Δώστε στο επιλεγμένο όχημα(τα) ένα ατομικό χÏονοδιάγÏαμμα. gl_btn_sort_catg ανά κατηγοÏία gl_title Κατάλογος όλων των αγαθών go home Μετάβαση στον χώÏο στάθμευσης Goods ΕμποÏεÏματα Goods list Κατάλογος εμποÏευμάτων Gross Profit Ρευστότητα επιχείÏησης Groundobj Αντικείμενο Grow city Μεγέθυνση πόλης. Growth Ανάπτυξη πόλης H στάση Hangar Υπόστεγο Happy Ευτιχισμένος Haus kaufen ΑγόÏασε σπίτι Helligk. Εμφάνιση Help Βοήθεια Help text not found Λείπει το κείμενο βοήθειας. hide all building απόκÏυψη όλων των κτιÏίων hide city building απόκÏυψη των κτιÏίων της πόλης hide station names απόκÏυψε τα ονόματα των σταθμών hide transparent διαφάνεια αντί απόκÏυψης hide trees ΑπόκÏυψη δέντÏων Hier warten/lagern: ΕμποÏεÏματα και επιβάτες σε αναμονή: hl_title Κατάλογος σταθμών hl_txt_filter ΦίλτÏο: hl_txt_sort Ταξινόμηση κατά: hlf_chk_airport ΑεÏοδÏόμια hlf_chk_anleger ΑποβάθÏα hlf_chk_bahnhof ΣιδηÏοδÏομικός σταθμός hlf_chk_bushalt Στάση λεωφοÏείου hlf_chk_frachthof ΕξέδÏα φόÏτωσης hlf_chk_keine_verb δεν υπάÏχει σÏνδεση hlf_chk_maglevstop Σταθμός αεÏοτÏένου hlf_chk_monorailstop Στάση αεÏοτÏένου μονής Ï„Ïοχιάς hlf_chk_name_filter Ονόματα φίλτÏων: hlf_chk_overflow ΥπεÏπλήÏης hlf_chk_spezial_filter Ειδικό φίλτÏο: hlf_chk_type_filter ΤÏποι φίλτÏων: Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Ο σταθμός δεν βÏέθηκε.\nΠÏέπει να στείλεις το \nόχημα εκεί χειÏοκίνητα Homeless Άστεγος industrial building Βιομηχανικά κτήÏια Init map ... ΑÏχικοποίηση του χάÏτη Input Είσοδος Ins Stop Εισάγω Intro. date: Εισαγωγή. ημεÏομηνία: January ΙανουάÏιος join game Παίξε στο ίντεÏνετ July ΙοÏλιος June ΙοÏνιος Kein Besitzer\n ΧωÏίς ιδιοκτήτη\n koord συντεταγμένες Laden ΦόÏτωσε καινοÏÏιο παιχνίδι LANG_CHOOSE\n ΠαÏακαλώ επέλεξε την \n γλώσσα που Ï€Ïοτιμάς:\n Last Month ΠÏοηγοÏμενος μήνας: Last Year ΠÏοηγοÏμενος χÏόνος: Leistung ΙσχÏÏ‚ letzen Monat: diesen Monat: Ï€ÏοηγοÏμενος μήνας: αυτός ο μήνας: LKW_tab ΦοÏτηγά Load scenario ΦόÏτωσε σενάÏιο loaded φοÏτωμένο Loading map ... ΦόÏτωση του χάÏτη ... Mailbox ΚέντÏο μηνυμάτων Manual (Human) ΕγχειÏίδιο (ΆνθÏωπος) Max income: Μέγιστο. Εισόδιμα: Max. speed: Μέγιστη. ταχÏτητα maximum length of rivers Μέγιστος. αÏιθμός ποταμών Maxspeed Μέγιστη ταχÏτητα May Μάιος Meldung Μήνυμα Menge ποσό MessageOptionsText \nΚαινοÏÏιος χÏόνος\n\nÎέα παιχτών\n\nÎέα της πόλης\n\nΚαμία διαδÏομή\n\nΚαινοÏÏιοι Ï€ÏοοÏισμοÏ\n\nChat\n\nΚαινοÏÏια οχήματα\n\nΟ σταθμός είναι πλήÏης\n\nΠÏοβλήματα\n\nΚυκλοφοÏιακή συμφόÏηση\n\nΣενάÏιο min Ελάχιστο minimum length of rivers Ελάχιστος αÏιθμός ποταμιών Missing pakfiles Τα αντικείμενα λείπουν Months Μήνες Mountain height Ύψος βουνοÏ: Music playing disabled/not available Η μουσική είναι απενεÏγοποιημένη/μη διαθέσιμη mute sound Σίγαση Name Όνομα Neue Karte ΚαινοÏÏιο παιχνίδι Neue Welt ΔημιοÏÏγησε καινοÏÏιο παιχνίδι New Vehicles ΚαινοÏÏια οχήματα No Route Καμία διαδÏομή No suitable ground! Όχι διαθέσιμο έδαφος! no tree Όχι δέντÏα No. of Factories ΕÏγοστάσια και μαγαζιά November ÎοέμβÏιος Number of rivers ΑÏιθμός των ποταμών Object Αντικείμενο Odometer: %s km ΟδόμετÏο. %s km Ok Εντάξει Oktober ΟκτώβÏιος On this map, you are not\nallowed to change player!\n Αυτό το παιχνίδι είναι κλειδωμένο.\nΔεν είναι δυνατές αλλαγές από τον παίκτη.\n Only one transformer per factory! Μόνο ένας μεταφοÏέας για κάθε εÏγοστάσιο Optionen Επιλογές Passagiere Επιβάτες Password Κωδικός: player Παίχτης player 11 Παίχτης 11 player 12 Παίχτης 12 player 13 Παίχτης 13 player 2 Trikky Transport player 3 Meyer Moving Co. Problems_msg ΠÏοβλήματα Produktion ΠαÏαγωγή: q1 Άνοιξη q2 ΚαλοκαίÏι q4 Χειμώνας Random age τυχαίος χÏόνος Random map Τυχαίος χάÏτης Reliefkarte ΧάÏτης Remove ΔιέγÏαψε την ετικέτα remove roads ΑφαίÏεσε τους δÏόμους replace stop Αντικατέστησε το stop road δÏόμος Rotate map ΠεÏιστÏοφή του χάÏτη Routing ΔιαδÏομή sack σάκοι Saving map ... Αποθήκευση χάÏτη ... Scenario information ΤÏέχουσες λεπτομέÏειες για το σενάÏιο Scenario Result Εξέλιξη Scenario Rules Κανόνες Schiff_tab ΚαÏάβια Seasons Εποχές Sehenswuerdigkeit Έλξη τουÏιστών Select a server to join: ΠαÏάθυÏο πληÏοφοÏιών του διακομιστή Sell the selected vehicle(s) ΠοÏλα το επιλεγμένο όχημα(οχήματα) sended Στείλε mail September ΣεπτέμβÏιος Service ΥπηÏεσία Setting Ρυθμίσεις Ship Πλοίο shops and stores Μαγαζιά και γÏαφεία Show all Εμφάνιση όλων show all building Εμφάνισε όλα τα κτήÏια Show legend Επιλογές Show schedules Εμφάνισε τα δÏομολόγια show station names Εμφάνισε τα ονόματα των σταθμών show waiting bars Εμφάνισε την μπάÏα αναμονής Show/hide statistics Εμφάνισε/ΑπόκÏιψε τα στατιστικά Sprache Γλώσσα Start ΈναÏξη Starte Spiel ΈναÏξη Ï€Î±Î¹Ï‡Î½Î¹Î´Î¹Î¿Ï #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL Δεν υπάÏχει! &1_CITY_SYLL πόλη &5_CITY_SYLL αστικό κέντÏο &7_CITY_SYLL χωÏάφι &8_CITY_SYLL στόμα &9_CITY_SYLL κλειδώνω &A_CITY_SYLL διασταÏÏωση &D_CITY_SYLL Δεν υπάÏχει! &E_CITY_SYLL Δεν υπάÏχει! %0_CITY_SYLL Δεν υπάÏχει! %2_CITY_SYLL πεζόδÏομος %4_CITY_SYLL άνοιξη %A_CITY_SYLL Παλιό %B_CITY_SYLL Λόφος %C_CITY_SYLL Δεν υπάÏχει! %D_CITY_SYLL Δεν υπάÏχει! %E_CITY_SYLL Δεν υπάÏχει! %F_CITY_SYLL Δεν υπάÏχει! 1center %s %s 1suburb %s %s %s simutrans-124.3/simutrans/text/hr.tab000066400000000000000000001065671474050137200177040ustar00rootroot00000000000000§Hrvatski PROP_FONT_FILE prop-latin2.fnt ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: hr Hrvatski # # Encoding: UTF-8 # # Font: prop-latin2.fnt # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable onemoguceno cl_btn_filter_enable omoguceno cl_btn_filter_settings Postavke cl_btn_sort_asc rastuce cl_btn_sort_desc padajuce cl_btn_sort_id unutarnji ID cl_btn_sort_income Prihod cl_btn_sort_name Ime cl_btn_sort_type Tip clf_btn_alle sve clf_btn_invers inv. clf_btn_keine nijedno gl_btn_sort_bonus bonusom gl_btn_sort_name ime gl_btn_sort_revenue prihod gl_btn_unsort nesortirano hl_btn_filter_disable onemoguceno hl_btn_filter_enable omoguceno hl_btn_filter_settings Opcije hl_btn_sort_asc uzlazno hl_btn_sort_desc silazno hl_btn_sort_name Ime hl_btn_sort_type Tip hl_btn_sort_waiting Cekaju hlf_btn_alle sve hlf_btn_invers obrnuti hlf_btn_keine nista #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Arkticka klima desert pustinjska klima mediterran Mediteranska klima rocky alpska klima temperate umjerena klima tropic tropska klima #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Depo se ne moze ovdje izgraditi. Cannot built this station/building\nin underground mode here. Zgrada se ne moze\n graditi podzemno.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Nije moguce napraviti genericku liniju!\nOdbrati tip linije\nkoristeci filtere. Cannot create socket Nije moguce otvoriti socket Convoi handles exhausted! Dostignut najveci broj konvoja. Das Feld gehoert\neinem anderen Spieler\n Ovaj dio \nzemlje posjeduje \ndrugi igrac! Der Besitzer erlaubt das Entfernen nicht \nVlasnik odbija\ndozvolu za\nuklnjanje ovoga!\n Diese Zusammenstellung kann nicht fahren!\n Ova kombinacija\se ne moze kretati!\n Flugzeughalt muss auf\nRunway liegen!\n Stajanje zrakoplova mora\nbiti na voznoj stazi. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Ne mozete sagraditi\n\naerodromsku zgradu ovdje.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Ne mozete staviti\nzeljeznicki signal ovdje.\n Lost connection\nto server! Izgubljena veza\nna server! Lost synchronisation\nwith server. Izgubljena sinhronizacija\nna server. Maglevhalt muss auf\nMaglevschiene liegen!\n Meglev stajaliste se mora nalaziti na maglev tracnici! Monorailhalt muss auf\nMonorail liegen!\n Monorail stajalista moraju\nbiti na monorail tracnici. Monorails are not available yet! Monorail jos nije dostupan. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n stajaliste uskog kolosijeka be trebalo biti na uskom kolosijeku No through station here! Stanica se mora postaviti na krajevima\n puteva ili ravnim dijelovima bez krizanja. Not enough money! Nemas dovoljno\nnovaca za gradnju ovoga! On narrowgauge track only!\n Samo na uskom kolosijeu!\n Post muss neben\nHaltestelle\nliegen!\n Zgrada prosirenja stanice\n(npr. posta, skladiste)\nmora biti postavljena na slobodnu plocicu\nodmah do postojeceg stajalista/stanice.\n Protocoll error (expecting game) Greska protokola (ocekivana igra) Schiffhalt muss im\nWasser liegen!\n Brodsko stajaliste moze samo\nbiti postavljeno na vodu\nblizu doka!\n Terraforming not possible\nhere in underground view Oblikovanje zemlje nemoguce pod zemljom. Upgrade must have\na higher level Nadogradnja mora imati\nveci nivo Zughalt muss auf\nSchiene liegen!\n Zeljeznicke stanice moraju\nbiti postavljene na\ntracnice.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Tipkovnicka\n

Tipkovnicka Pomoc

\n

\nTipkovncika Pomoc prikazuje funkcije za razne pritiske tipaka na tipkovnici.\n

\n

\nTipkovnicka pomoc otvara se kada se stisne nedodijeljena tipka ili od Opca Pomoc.\n

\n

\nPritisci tipke ovise o malim i velikim slovima (koristiti [Shift] za velika slova).\n

\n

\nTipke sa pridodijeljenim funkcijama ukljucuju:\n

\n

\n[Strelice]: pomicanje pogleda igre u smjeru strelice.
\n[Backspace]: zatvranje svih prozora, alatnih traka i tekstova pomoci u pogledu igre.
\n[Delete], ili [Escape]: zatvoriti vrsni prozor, alatnu traku ili tekst pomoci u pogledu igre.
\n[Enter], ili [Return]: koristenje za potvrdu akcija.
\n[Page-Up], ili [>]: zoom-in pogled u igri.
\n[Page-Down], ili [ less than symbol]: zoom-out pogled u igri.\n[F1]: otvoriti Simutrans Pomoc.

\n

\n[1]: pomicanje pogleda igre juzno.
\n[2]: pomicanje pogleda igre jugoistocno.
\n[3]: pomicanje pogleda igre istocno.
\n[4]: pomicanje pogleda igre jugozapadno.
\n[6]: pomicanje pogleda igre sjeveroistocno.
\n[7]: pomicanje pogleda igre zapadno.
\n[8]: pomicanje pogleda igre sjevernozapadno.
\n[9]: pomicanje pogleda igre sjeverno.\n

\n

\n[Shift] + mis: koristen na Map za pregled poveznica u Lancu Opskrbe Industrije.
\n[CTRL] + tool: konstrukcija (signala & Stajalista) na gornjem nivou; ili gradnja sporijih cesta i tracnica preko brzih; ili gradnja ravnijih (direktnijih) ulica i tracnica.
\n[CTRL] + ([F2] do [F12]): postavlja odabir trenutnog alata za pritisak tipaka [F2] do [F12].\n

\n

#____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s sada\nnudi uslugu prijevoza busom\nizmedju %s\ni atrakcije\n%s\nna (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s sada\nnudi uslugu prijevoza busom\nizmedju %s\ni tvornice\n%s\nna (%i, %i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\sada ima\n%i kaimona izmedju\n%s na (%i,%i)\ni %s\na (%i, %i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\notvara novu zeljeznicu\nizmedju %s\nna (%i,%i) i\n%s\nna (%i,%i).\n Airline service by\n%s\nnow between\n%s \nand %s.\n Avionska sluzba od\n%s\nizmedju\n%s \ni %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Trajektni promet od\n%s\nsada izmedju\n%s \n i %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\notvara novi prekoselski\nautobus servis izmedju\n%s and\n%s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Alati za uredjivanje mape LISTTOOLS Liste MAGLEVTOOLS Maglev alati MONORAILTOOLS Monorail/maglev alati NARROWGAUGETOOLS Alati uskog kolosijeka RAILTOOLS Tracnicki alati ROADTOOLS Cestovni alati SHIPTOOLS Alati luke SLOPETOOLS Vertikalno dici/spustiti teren SPECIALTOOLS Specijalni alati konstrukcije TRAMTOOLS Alati Tramvaja/lakosinske zeljeznice #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s s\nsredisnjica sada\nna (%i,%i). Factory chain extended\nfor %s near\n%s built with\n%i factories. Ekonomija jaca:\n%s bilzu %s povecava lanac.\n%i nova tvornica osnovana. New %s now available:\n%s\n Novo %s sada dostupno:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Rast industrije:Novi lanac industrije\m za %s blizu\n%s sagradjeno sa\n%i tvornica. New vehicle now available:\n%s\n \n Novo vozilo je\n sada dostupno:\n\n\n -- %s --\n\n Remove vehicle from map. Use with care! Ukloniti vozilo sa mape. (Koristi pazljivo!) Screenshot\ngespeichert.\n Snimak ekrana\nspremljen.\n Sends the convoi to the last depot it departed from! Salje konvoj u zadnji depo iz kojega je posao. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Sa velikim festivalom,\n %s sagradnjen\nnovi spomenik\n%i gradjana su se veselili. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (u depou) \nBauzeit bis do \nBauzeit von \nDostupno od \nCan't open heightfield file.\n \nNemoguce otvoriti mapu visina.\n \ndirection: \nsmjerovi: \nelektrified \nelektrificirano\n \nHeightfield has wrong image type.\n \nPolje visine ima krivi\tip slike.\n \nis reserved by: \nrezervirano od vlaka \nminimum speed: \nnajmanja brzina: \nnot elektrified \nnije elektrificirano\n \nRibi (masked) \nsmjerovi\m (maskirano): \nRibi (unmasked) \nsmjerovi\n (nemaskirano): \nSet phases: \nnamjestiti duzinu ns/ew: \nsingle way \nJednosmjeran put \nway1 reserved by \nput 1 rezerviran od \nway2 reserved by \nput 2 rezerviran od \nwith sign/signal\n \nsa znakom/signalom\n %d buildings\n %d objekata %d convois %d konvoja %d Einzelfahrzeuge im Depot %d vozila ovdje pohranjeno. %s building %s %s %s %s %s %s city %d %s %s grad %d %s %s factory %s %s %s %s dvorista %s has entered a depot. %s je usao u depo. %s land %d %s %s %d izvan %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s je trosio\ntvoj novac na\nnovu vijecnicu\nkada je dosegao\n%i stanovnika. %s\nis crowded. %s\nje pretrpana %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nbrzina %i\nmax brzina %i\ndx:%i dy:%i %s\nwas liquidated. %s\n je likvidiran. 1 convoi 1 konvoj 1 Einzelfahrzeug im Depot 1 vozilo ovdje spremljeno. 1LIGHT_CHOOSE Osvijetljenost: 1WORLD_CHOOSE Postavke za Novu Igru 2LIGHT_CHOOSE Boje: 2WORLD_CHOOSE Broj mape: 3LIGHT_CHOOSE Brzina pomicanja: 4LIGHT_CHOOSE Obrnuto pomicanje 5LIGHT_CHOOSE Pjesaci na stajalistima 5WORLD_CHOOSE Br. gradova: 6LIGHT_CHOOSE Pjesaci u gradovima 6WORLD_CHOOSE Gustoca prometa: 8WORLD_CHOOSE promjena dana i noci A bridge must start on a way! Ne posjedujete krajeve mosta,\n ili se nesto naslo na njegovom putu. Abfrage Istrazivacki alat Abnehmer Potrosac About O Abriss UniÅ¡ti/Ukloni Absenken Snizi zemljiÅ¡te Accelerate time Vrijeme ubrzanja Active player only Samo aktivan igraÄ Add forest Dodaj Å¡umu Add random citycar Dodaj slucajan gradski automobil Add Stop Dodaj postaju Add stops for backward travel Dodaj postaje za povratak air Pista aircraft_tab Teretni avioni airplane Avion Airport Aerodrom AIRTOOLS Alati za aerodrom All Sve all convoi tooltips Savjet za sve konvoje Allow city growth Dozvoli razvoj grada Allow player change Dopustiti promjenu igraca allowed climates:\n Dozvoljene klime Alters a schedule. Dodaj/ukloni postaje iz voznog reda Angenommene Waren Sirovine potrebne obliznjim industrijama anhaengen Dodaj Anhaenger_tab Prikolice Anheben Izdigni teren Appends stops at the end of the schedule Dodaj postaju na kraj linije Apply Line Primjeni liniju April Travanj Arbeiter aus: Radnici zive u: Arrived Opsrkba Assets Imovina Aufloesen Rastavi August Kolovoz Autohalt muss auf\nStrasse liegen!\n Autobusne postaje\nmoraju se\nnalazitina cesti. Available Dostupno Bahndepot Depo za vlakove. Bankrott:\n\nDu bist bankrott.\n Bankrot:\n\nBankrotirali ste!\n battery Akumulator Baum Drvo baum builder Posadi drvece Baustelle Gradiliste Bauzeit Vrijeme izgradnje Beenden Kraj Beginner mode Pocetnicki Mod Besonderes Gebaeude Turisticka atrakcija BF postaja bio bioloski Blockstrecke ist\nbelegt\n \nTracnicu koristi\ndrugi vlak\n Boden Zemljiste bridge is too high for its type! Most je previsok za svoj tip! Bridge is too long for this type!\n Raspon mosta\nje prevelik za\novaj tip mosta.\n Bruecke Most Bruecke muss an\neinfachem\nHang beginnen!\n Most mora\nnpoceti na\npravom nagibu!\n Brueckenboden most Build air depot Izgradi hangar build choosesignals Izgradi znak za odabir platforme Build city market Izgradi novu prodavaonicu u najblizem gradu. Build drain Trafostanica build HQ Izgradi sredisnjicu Build land consumer Izgradi novu elektricnu centralu Build maglev depot Izgradi depo za Maglev vlakove Build monorail depot Izgradi depo za Monorail vozove Build narrowgauge depot Izgradi depo uskotracne pruge Build powerline Izgradi dalekovod Build presignals Izgradi dvoblokni signal Build road depot Izgradi garazu Build ship depot Izgradi brodogradiliste Build signals Napravi semafor Build train depot Izgradi depo za vlakove Build tram depot Izgradi depo za tramvaje Build truck depot Izgradi depo za kamione Building costs estimates Procijenjena cijena izgradnje Buildings Broj gradjevina Built artifical slopes Izgradi umjetne nasipe Built random attraction Izgradi nasumicnu turisticku atrakciju Bus_tab Autobusi Can only move from halt to halt or waypoint to waypoint. Moze se kretati\nsamo od postaje do postaje\ili od tocke do tocke. Cancel Ponistiti Capacity: %d%s %s\n Kapacitet: %3d %s %s Capacity: %s\nLoad: %d (%d%%) Kapacitet: %s\n? %d (%d%%) Cars are not available yet! Automobili jos nisu dostupni. cars.\nstate automobili\n Cash Stanje racuna Change player Promjena igraca Chart Grafikon Choose direction Odabir smjera Choose operation executed on clicking stored/new vehicles Odabir operacije za izvrsenje pri kliku na spremljena/nova vozila chooses a random map Odabire nasumicnu mapu. citicens Gradjani City attraction Gradske atrakcije City industries Trznice u gradovima City list Lista gradova City size Velicina grada city_road Gradska ulica citybuilding builder Gradnja urbanih zgrada CityLimit Granice grada cl_title Lista vozila cl_txt_sort Sortirati: Clear block reservation Prikaz/reset reserviranih puteva clf_chk_aircrafts Zrakoplovi clf_chk_cars Autobusi/kamioni clf_chk_indepot u depou clf_chk_maglev Maglevi clf_chk_monorail Monorailovi clf_chk_name_filter Imena filtera: clf_chk_narrowgauge Vlakovi uskog kolosijeka clf_chk_noincome bez prihoda clf_chk_noline nema linije clf_chk_noroute nema rute clf_chk_noschedule nema rasporeda clf_chk_ships Brodovi clf_chk_spezial_filter Specijalni filter: clf_chk_stucked zaglavljeno clf_chk_trains Vlakovi clf_chk_trams Tramvaji clf_chk_type_filter Tipovi filtera: clf_chk_waren Filter tereta: clf_title Filter liste vozila Climate Control Postaviti klimu closed zatvoreno. COLOR_CHOOSE\n Molimo odabrati a\nboju iz tablice:\n Company bankrupt Kompanija bankrotirana Congratulation\nScenario was complete in\n%i months %i years. Cestitke!\nScenario je\nzavrsen unutar \n%i mjeseci i %i godina! Connected stops Spojena stajalista Constructed by Nacrtano od Constructed by %s Napravio %s Construction_Btn Troskovi gradnje convoi %d of %d Konvoj %d od %d convoi error tooltips Savjeti greske konvoja Convoi has been sent\nto the nearest depot\nof appropriate type.\n Konvoj je poslan\nu najblizi depo \nprikladne vrste.\n Convoi is sold when all wagons are empty. Konvoj je prodan kad su svi vagoni prazni. convoi mouseover tooltips Savjeti konvoja prelaska misem convoi passed last\nmonth %i\n \nkonvoja proslo zasnji\nmjesec: %i\n Convois Konvoj Convois: %d\nProfit: %s Vozila: %d\nPrihod: %s Convoys Konvoji Copy Convoi Kopiraj Konvoj Copy the selected convoi and its schedule or line Kopiraj odabrani konvoj i njegov vozni red ili liniju cost for removal Troskovi uklanjanja Costs Troskovi Create a new line based on this schedule Napravi novu liniju baziranu na ovom voznom redu curiosity builder Graditelj atrakcija curlist_title Lista atrakcija Currently playing: Svira: Deccelerate time Vrijeme decelaracije December Prosinac decrease underground view level spustiti podzemni nivo pogleda Del Stop Ukloni Delete Line Obrisati liniju Delete the current stop Obrisati trenutno stajaliste Delete this file. Obrisati ovu datoteku. Denkmal Spomenik Departed Odaslan Depots Depoi Der Tunnel ist nicht frei!\n Tunel nije prazan.\n Destination Dolasci Details Detalji Die Bruecke ist nicht frei!\n Most nije slobodan!\n diesel dizel Direkt erreichbare Haltestellen Direktne rute odavde disable midi Zanijemiti MIDI glazbu Display settings Opcije prikaza Distance Udaljenost Dock dok Dock must be built on single slope! Dok mora biti sagradjen na poziciji s kosinom. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Imate %d mjeseca da otplatite svoj dug. Durchsatz Max. Economy Ekonomija i gradovi Eigenbesitz\n Javni posjed\n Ein %s\npasst hier nicht.\n %s\nne pripada ovdje!\n Einstellungen aendern Promijeni opcije:\n electric elektricni pogon Electricity Elekticitet Electricity producer\n\n Proizvodjac elektriciteta\n\n Electrics_tab Elektricne Electrify track Elektrificiraj prugu enlarge map Povecati mapu enter a value between %i and %i Unijeti vrijednost izmedju %i i %i Error Greska Erzeuge neue Karte.\n Molimo Vas, pricekajte dok se nova\nmapa ne kreira.\n\n (Ovo bi moglo\n potrajati nekoliko minuta\n za velike mape.)\n Es wird bereits\nein Fahrplan\neingegeben\n Raspored se\nplanira.\nPrvo zavrsi\n prije nego se ponovno napravi!\n Fabrikanschluss Povezane tvornice Fabrikname ime tvornice Factories Tvornice factory details Tvornicke veze factorybuilder Graditelj tvornica Fahrplan Vozni red Fahrtziel Cilj: Fahrzeuge koennen so nicht entfernt werden Vozila ne mogu biti\nuklonjena na ovaj nacin Fahrzeuge: Vozila: Farbe Boja igraca Fast forward Ubrzati February Veljaca Ferry_tab Trajekti Fertig Gotovo Filename Datoteka: Finances of %s Financije %s Finanzen Financije fl_title lista tvornica Flug_tab Putnicki Avioni follow me Slijedi me. Follow the convoi on the map. Slijedi konvoj na mapi. Forest Suma Found new city sagraditi novi grad Fracht Teret Frame time: Okvirno vrijeme: Free Capacity Slobodan kapac. freeplay mode Slobodni modus Friction: trenutni faktor trenja: fuel_cell goriva celija Full load Min. napunjenost: Fussgaenger Pjesaci GAME PAUSED Igra je zaustavljena Gear: Vucna snaga: Gebaeude Gradjevina General Opcenito Gewicht Tezina Gewinn Dohodak: Give the selected vehicle(s) an individual schedule Dati odabranom(nim) vozilu(ima) poseban vozni red. gl_btn_sort_catg Kategorija gl_title Lista svih dobara go home Idi u depo. Goods Teret Goods AI AI tereta Goods list Lista dobara Gross Profit Tok novca Groundobj Objekt Grow city Povecati grad Growth Rast grada H postaja Happy Sretni Haus kaufen Kupiti kucu Helligk. Prikaz Help Pomoc Help text not found Tekst s pomoci nedostaje hide all building Sakrij sve gradjevine hide city building Sakrij gradjevine u gradovima hide station names sakriti imena stanica hide transparent transparentno umjesto sakriveno hide trees Sakrij stabla Hier warten/lagern: Roba i putnici koji cekaju: hl_title Lista stanica hl_txt_filter Filter: hl_txt_sort Sortirano: hlf_chk_airport Aerodromi hlf_chk_anleger Dok hlf_chk_bahnhof Zeljezincka stanica hlf_chk_bushalt Autobusna postaja hlf_chk_frachthof Zona za ukrcavanje hlf_chk_keine_verb nema veze hlf_chk_maglevstop Maglev stanica hlf_chk_monorailstop Monorail stajaliste hlf_chk_name_filter Imena filtera: hlf_chk_narrowgaugestop Stanica uskog kolosijeka hlf_chk_overflow Iznad kapaciteta hlf_chk_spezial_filter Poseban filter: hlf_chk_tramstop Stajaliste tramvaja hlf_chk_type_filter Tipovi filtera: hlf_chk_waren_abgabe Proizvodnja: hlf_chk_waren_annahme Potrebna roba: hlf_title Filter liste stanica Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depo nije nadjen.\nMorate poslati\nvozilo tamo rucno. Homeless Beskucnik hydrogene Vodik Idle: U mirovanju: ignore climates Ignoriranje klima Increase Industry density Povecavanje gustoce industrije increase underground view level povecati nivo podzemnog pogleda industrial building Industrijske zgrade Init map ... Postavljanje mape ... Input ulaz Ins Stop Umetnuti Insert stop before the current stop Umetnuti prije trentnog stajalista Intercity road len: Duzina medjugradske ceste: Intro. date: Datum uvodjenja: invalid nedefinirano. Invalid coordinate Neispravan redoslijed isometric map Izometricni pogled January Sijecanj July Srpanj Jump to Skociti na June Lipanj Kann Spielstand\nnicht laden.\n Nije moguce ucitati spremljenu igru! Kann Spielstand\nnicht speichern.\n Nije moguce otvoriti\nciljnu datoteku\nza pisanje! Kein Besitzer\n Bez vlasnika\n keine nema Keine Einzelfahrzeuge im Depot Nema ovdje spremljenih vozila. Keyboard_Help\n Pomoc tipkovnice\n koord koordinate Kreuzung Krizanje labellist_title Lista markera Lade Relief Ucitati Reljef Laden Ucitati Land attraction Zemaljske atrakcije Land industries Industrijski lanci: LANG_CHOOSE\n Molimo odaberite vas\n zeljeni jezik:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Year Zadnja godina: Leaving depot! Napustanje depoa! leer prazno Legend Legedna mape Leistung Snaga Leistung: %d kW Snaga: %d kW Leitung Dalekovod letzen Monat: diesen Monat: zadnji mjesec: ovaj mjesec: Line Linija Line Management Upravljanje linijom Lines serving this stop Linije ovoga stajalista LKW_tab Kamioni Load game Ucitati igru load height data from file Ucitati podatci visine iz datoteke. Load scenario Ucitati scenarij loaded ukrcano loaded passenger/freight Sortiranje putnika/tereta po Loading (%i->%i%%)! Utovarivanje (%i->%i%%) Loading addon paks ... Ucitavanje dodatnih paketa ... Loading map ... Ucitavanje mape ... Loading paks ... Ucitavanje paketa ... Loading skins ... Ucitanje koza ... Lock game Zabraniti promjene igraca (zahtijeva potvrdu). Lokomotive_tab Lokomotive maglev vehicle Maglev vozilo maglev_track Maglev tracnica Maglevdepot Maglev depo Mailbox Centar poruka Mailbox Options Opcije centra poruka Maintenance Odrzavanje make stop public (or join with public stop next) costs %i per tile and level Naciti stajalista javnima (ili spojiti sa susjednim javinim stajalistima) kosta %i$ po plocici i nivou Manual (Human) Uputsvo (ljudsko) Manufactured: Stvoreno: Map roughness hrapavost mape: map zoom zumiranje March Ozujak Margin (%%) Margina Marker Naciti znak Max income: Najveci prihod: Max. speed: Najveca brzina: Maximum 254 stops\nin a schedule!\n Najvise 254 stajalista\nu rasporedu!\n maximum length of rivers Max. duzina rijeke Maximum tile height difference reached. Najveca visina\nrazlika izmedju\ndvije plocice \nje dostignuta! May svibanj Median Citizen per town Srednji gradjani po gradu: Meldung Poruka Menge Iznos MessageOptionsText \nNova Godina\n\nAI novosti\n\nGradske novosti\n\nNema rute\n\nNove industrije\n\n"chat"\n\nNova vozila\n\nStanica puna\n\nProblemi\n\nUpozorenja min min. minimum length of rivers Min. duzina rijeka Modify the selected line Promjena odabrane linije Monate alt Mjeseca starosti. monorail vehicle monorail vozilo monorail_track Monorail tracnica Monorailboden Uzdignut put Monoraildepot Depo Monoraila month wait time mjeseci cekanja Months Mjeseci Monument Spomenik Monuments Spomenici Mountain height Velicina planine: Movingobj pokretni objekt Music playing disabled/not available Glazba onemogucena/nedostupna. Music volume: Jacina glazbe: mute sound Zanijemiti Name Ime Narrowgauge Uski kolosijek Narrowgauge are not available yet! Uski kolosijek jos nije dostupan! narrowgauge vehicle vozilo uskog kolosijeka narrowgauge_track Uska tracnica Narrowgaugedepot Depo uske tracnice Net Wealth Ukupna Imovina Neue Karte Nova mapa Neue Welt Stvoriti novu igru new convoi Novi konvoj New Line Nova linija New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nova linija stvorena!\nMozes pridruziti liniju sada\nodabiruci je sa\nodabiraca linija gore. New Vehicles Nova vozila no buildings hidden nijedna zgrada skrivena no convois nema konvoja No goods are loaded onto this convoi. Nikakav teret nije ukrcan u konvoj no goods waiting teret ne ceka no load Nema tereta No Route Nema rute No stop here! Alat se mora koristiti na plocicama stajalista. No suitable ground! Nije prigodna podloga! No terminal station here! Nije moguce graditi terminal\n ovdje! Krajnji komad \nod ravne ceste/pruge je potreban. no timeline sve epohe no tree Nema stabala Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "Gdje ja idem?"\nMorate ovome konvoju postaviti raspored ili dodijeliti mu liniju prije nego ode po nalog. none nema nord Sjever nordost Sjeveroistok nordwest Sjeverozapad Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Raspored vozila\nse ne smije mijenjati\n prilikom trazenja rute. Not enough fields would remain. Ne bi dovoljno polja\n ostalo oko farme. November Studeni Now active as %s.\n Sada aktivan kao %s.\n Number of rivers Broj rijeka Object Objekt Ok U redu Oktober Listopad On loan since %i month(s) U kreditu vec %i mjesec(i) On this map, you are not\nallowed to change player!\n Ova igra je zakljucana.\nPromjene od igraca nisu moguce.\n Only city chains Samo lanci gradova Only land chains Samo lanci sela open otvoreno. Operation Operativni Troskovi Ops Profit Operativni profit Optionen Opcije Origin Podrijetlo ost Istok Output Izlaz paletten sanduk Pas_tab Putnicki vlakovi Passagiere Putnici Passagierrate Nivo putnika Passagierziele ciljevi putnika/poste Passenger AI AI putnika Passengers %d %c, %d %c, %d no route Putnici %d %c, %d %c, %d nemaju rutu Passengers %d %s, %d %s, %d no route Putnici %d %s, %d %s, %d nemaju rutu Pause Pauza PaxDest Odredista Percent Electricity Elektricitet (%% potraznje): Planes are not available yet! Zrakoplovi jos nisu dostupni. Plant tree Posaditi stabla. player igrac player -1 Covjek player 0 Javni servis player 1 Napik 128 AS player 10 igrac 10 player 11 Igrac 11 player 12 Igrac 12 player 13 Igrac 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Freight Forwarder VM player 5 H-Trans Ltd player 6 PSK & Co KG player 7 Igrac 7 player 8 Igrac 8 player 9 Igrac 9 Please choose vehicles first\n Molimo prvo odaberi vozila!\n Post Posta Postrate Nivo poste Power Snaga Power: Snaga: Powerlines Dalekovodi Production of %s has been stopped:\n%s\n Proizvodnja od %s je ukinuta:\n%s\n Produktion Produkcija promote to line Promovirati u liniju q1 Proljece q2 Ljeto q3 Jesen q4 Zima rail car Tracnicko vozilo random slucajno Random age slucajna godina Random map Slucajna Mapa Rathaus Vijecnica Rating Procjena ratio_pax Omjer putnika Reliefkarte Mapa Remove Ukloniti remove airstrips ukloniti vozne staze remove channels Ukloniti kanale remove interm. signals Ukloniti signale izmedju remove maglev tracks ukloniti maglav tracnice remove monorails ukloniti monorailove remove narrowgauge tracks ukloniti uski kolosijek remove powerlines ukloniti dalekovode remove roads ukloniti ceste remove tracks ukloniti tracnice Remove wayobj %s Ukloniti wayobj %s replace other signals Zamjena postojecih signala replace stop Ukloniti stajaliste request closing traziti zatvaranje residential house Residentalne kuce Restore natural slope Vratiti prirodni nagib. Restwert: Prodajna vrijednost: Retire. date: Datum umirovljenja: return ticket ponovo unazad Revenue Prihodi road cesta road vehicle cestovni znak Roadsign Cestovni Znak Rotate map Okretanje mape Rotation Okretanje Routing Rutiranje sack vrece sail vjetar Saving map ... Spremanje mape... Scenario complete: %i%% Scenarij zavrsen:%i%% Schedule changing! Raspored u promijeni! Schienentunnel Gradnja zeljeznickog tunela Schiff_tab Brodovi Schiffdepot Brodogradiliste Schleppkahn_tab Sleperi Screenshot Uzeti snimak ekrana. Seasons Godisnja doba Sehenswuerdigkeit Turisticka atrakcija Sell the selected vehicle(s) Prodati odabrano vozilo/la. sended Poslana posta SEP_FRACTION , SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September Rujan Server did not respond! Server nije odgovorio! Serves Line: Posluzuje liniju: Service Servis set signal spacing Postavljanje razmaka signala Setting Postavke Ship Brod shops and stores Trgovine i biroi Show all Prikaz svih show all building Prikaz svih zgrada Show also vehicles no longer in production. Prikaz takodjer vozila koja se vise ne proizvode. Show also vehicles that do not match for current action. Prikaz i vozila koja se ne mogu koristiti odabranom akcijom. show grid Prikaz mreze Show industry Industrija Show legend Prikaz legende Show map scale Skala mape Show obsolete Prikaz zastarjelih Show schedules Prikaz rasporeda show station coverage Prikaz pokrivenosti stanice show station names Prikaz imena stanice show waiting bars prikaz motke cekanja Show/hide statistics Prikaz/Skrivanje Statistike Shows consumer/suppliers for factories Prikaz potrosaca/dobavljaca za tvornice Shows the currently selected schedule Prikaz trenutno prikazanog rasporeda Shrink city Smanjenje grada shuffle midis mijesanje mid-ova Sim: Simloop-ovi: Size (%d MB): Velicina (%d MB): sliced underground mode Prikaz Kriske Sloja slot empty isjecak prazan Sort by sortiranje prema Sort waiting list by Sortiranje liste cekanja prema Sound Zvuk Sound settings Postavke zvuka Sound volume: Jacina zvuka: special freight Specijalni teret Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Brzinski bonus\n cesta %i km/h, tracnice %i km/h\nbrodovi %i km/h, zrakoplovi %i km/h. Speedlimit Brzina Speichern Spremi Spieler Igrac Spieler(mz) Igraci Spielerliste Lista Igraca Spielstand wurde\ngeladen!\n \nIgra uspjesno ucitana.\n Spielstand wurde\ngespeichert!\n \n Igra uspjesno spremljena.\n Sprache Jezik Sprachen Jezici Stadtinformation Gradske statistike Start the selected vehicle(s) Poslati odabrano/na vozilo/la Starte Spiel Pokreni igru Station tiles: Plocice stanice: Status Status stajalista steam para Step timeline one year Pomaknuti za godinu dana unaprijed. Storage capacity Kapacitet spremanja Strassendepot Garaza Strassentunnel Gradnja cestovnog tunela street car ulicni auto sued Jug suedost Jugoistok suedwest Jugozapad Summer snowline Ljetna snjezna linija Suppliers Dobavljaci Tage alt dana staro. There are still vehicles\nstored in this depot!\n Jos ima vozila\nu ovom depou!\n This Month Ovaj mjesec This Year Ova Godina: Tile not empty. Obrisati plocicu prije\nkoristenja Alata za Nagibe. timeline slijediti epohu tl_title Lista svih Gradova To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Za privlacenje vise turista,\n%s je sagradio\n %s\s pomocu od\n%i placenih poreza. To heavy traffic\nresults in traffic jam.\n Preveliki promet\nprouzrocuje zastoj.\n Toggle day/night view Promjena dan/noc pogleda Toggle vehicle tooltips Promijena savjeta za vozila tonnen t Total inhabitants: Ukupno stanovnika: Tourist attractions Turisticke atrakcije: Tourists Znamenitosti Town: %s\n Grad od %s.\n Towns Gradovi track tracnica Tracks Tracnice Traffic Promet Train Vlak Trains are not available yet! Vlakovi jos nisu dostupni. Tram Tramvaj tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tramvaj %i km/h, monorail %i km/h\nmaglev %i km/h, uski kolosijek %i km/h. tram_track tramvajske tracnice Tramdepot Tramvajski depo Trams are not available yet! Tramvaji jos nisu dostupni. Transformer only next to factory! Transformatori moraju biti na\npraznom ravnom tlu\nblizu tvornici! Translation Prijevod transparent station coverage transparentan prikaz pokrivanja Transported Putovanja TrolleyBus_tab trolejbusi Truck Kamion Tunnel muss an\neinfachem\nHang beginnen!\n Tuneli moraju\npocinjati na ravnom\nnagibu!\n Tunnel must start on single way! Tuneli moraju pocinjati na pojedinacnom putu. Tunnelboden Tunel underground mode podzemni pogled UNDO failed! Ponistenje vise nije moguce.\nMozete ponistiti konstrukciju\nrute samo toliko dugo dok\nnijedan signal/stanica/stajaliste ili \nnista drugo nije izgradjeno \nna putu Undo last ways construction Ponistiti zadnju konstrukciju puteva Unemployed Nezaposlen Unhappy Nesretno units/day jedinice/mjesec Update Line Osvjeziti liniju upgrade HQ Nadogradnja HQ Use timeline start year Koristenje trake godina: Vehicle %s can't find a route! Vozilo %s\nne moze naci rutu! Vehicle %s is stucked! Vozilo %s je zaglavljeno! Vehicle details Detalji Vozila Verbrauch Potrosnja Vergroessere die Karte\n Povecanje mape.\n verkaufen Prodaje Verkehrsteilnehmer gradski auti Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Imas %d mjeseca\nza otplatu svojih dugova.\n via preko (detalj) via %s\n preko %s\n via Menge preko (kolicina) voranstellen Postaviti naprijed Waggon_tab vagoni waiting cekanje Waiting for clearance! Cekanje na odobrenje! Water Kanal Water level Nivo vode: water vehicle vodeno vozilo way %s cannot longer used:\n Putni tip %s se ne moze vise koristiti.\n way %s cannot longer used:\n%s\n tip puta %s se ne moze vise koristiti:\n way %s now available:\n Putni tip %s je sada dostupan.\n Ways not connected Putovi nisu spojeni Wegpunkt Putna tocka Wert Vrijednost west Zapad Winter snowline Zimska snjezna linija withdraw povuci Withdraw All Povuci Sve WRONGSAVE \nNekompatibilna spremljena igra.\nNemoguce ucitati datoteku.\n Year %i has started. Godina %i je zapocela. Years Godina Zielort Cilj zooming in uzumiravanje zooming out izumiravanje Zu nah am Kartenrand Ne mozes graditi\ntako blizu na\nrubu mape. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Novi svjetski record za maglevove: %.1f km/h by %s. New world record for monorails: %.1f km/h by %s. Novi svjetski rekord za\nmonorailove: %.1f km/h - %s. New world record for motorcars: %.1f km/h by %s. Novi svjetski rekord za\nmotorna vozila:\n %.1f km/h - %s. New world record for narrowgauges: %.1f km/h by %s. Novi svjetski rekord za uski kolosijek: %.1f km/h - %s. New world record for planes: %.1f km/h by %s. Novi svjetski rekord za\nzrakoplove:\n %.1f km/h\n - %s. New world record for railways: %.1f km/h by %s. Novi svjetski rekord za \nvlakove:\n %.1f km/h - %s. New world record for ship: %.1f km/h by %s. Novi svjetski rekod za \nbrodove:\n %.1f km/h\n - %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ %D_CITY_SYLL Vrata %E_CITY_SYLL Zid %F_CITY_SYLL Hrast 1center %s %s 1extern %s ekspoziturna %s 1suburb %s %s %s 2extern %s vanjska %s 3center %s glavna %s 3extern %s agrarna %s 3suburb %s selo %s %s 4extern %s vanjska %s 5center %S u centru grada %s 6center %s cvorisna %s 7center %s grad %s Asuburb Ne postoji! Bcenter Ne postoji! Bextern Ne postoji! Bsuburb Ne postoji! Ccenter Ne postoji! Cextern Ne postoji! Csuburb Ne postoji! Dcenter Ne postoji! Dextern Ne postoji! Dsuburb Ne postoji! Ecenter Ne postoji! Eextern Ne postoji! Esuburb Ne postoji! Fcenter Ne postoji! Fextern Ne postoji! Fsuburb Ne postoji! Gcenter Ne postoji! Gextern Ne postoji! simutrans-124.3/simutrans/text/hr/000077500000000000000000000000001474050137200171755ustar00rootroot00000000000000simutrans-124.3/simutrans/text/hr/baum_build.txt000066400000000000000000000017351474050137200220470ustar00rootroot00000000000000Sadnja drveca

Sadnja drveca

Dijalog je podijeljen u cetiri odijeljka.
- gore lijevo je lista odabira dostupnih vrsta drveca
- dolje lijevo je prikazana slika odabranog drveta
- gore desno su postavke
- dolje desno je prikazana informacija o odabranom drvetu

Lista odabira

U odabranoj listu su navedi svi tipovi drveca koji postoje s postavkama zadanim gore desno. Postoje dvije kartice koje ce dozvoliti promjenu identifikacije drveca.
- Prijevod: Prikazuje ime drveta u zadanom jeziku. Ako ne postoji prijevod u zadanom jeziku, ime objekta ce se korisiti.
- Objekt: Prikazuje Simutrans interno ime objekta za tip drveta.

Postavke

- igniranje klima: Ova postavka onemogucuje ogranicenja klima koje su pridjeljenje raznim tipovima drveta.
- slucajna godina: Starost drveta koje ce se posaditi ce biti slucajno odabrana.

simutrans-124.3/simutrans/text/hr/citybuilding_build.txt000066400000000000000000000040051474050137200236020ustar00rootroot00000000000000Gradnja gradskih zgrada

Gradnja gradskih zgrada

Dijalog je podijeljen u cetiri odjeljka.
- gore lijevo je lista odabira dostupnih gradskih zgrada
- dolje lijevo je prikazana slika odbrane gradske zgrade
- gore desno su neke postavke
- dolje desno je dana informacija o odabranoj gradskoj zgradi

Lista odabira

U listi odabira se nalaze sve urbane zgrade koje su dostupne postavkama danim gore desno (Stambene kuće, Trgovine i ured, Industrijske zgrade). Postoje dva jahaca koji dozvoljavaju promjenu nacina na koji se urbane gradjevine identificiraju.
- Prijevod: Prikazuje ime zgrade u zadanom jeziku. Ako ne postoji prijevod u zadanom jeziku, koristiti ce se ime objekta.
- Objekt: Prikazuje Simutrans unutarnje ime za tip zgrade.

Boja teksta ime slijedece znacenje:
- plavi tekst naznacava zgradu za stanovanje.
- zeleni tekst nazncÄava zgradu trgovine ili ureda.
- vrni tekst naznacava industrijsku zgradu.

Opcije

- ignoriranje klima: Ova postavka onemogucuje ogranicenje klime koje se odnosi na razne tipove zgrada.
- Koristiti vremensku traku: Lista odabira ce sadrzavati samo zgrade koje su dostupne u trenutnoj Simutrans godini.
- Takodjer prikaz zastarjelih: Prositiri listu odabira kako bi takodjer sadrzavala zgrade koje su zastarjele u trenutnoj Simutrans godini.
- Stambene kuce: Biti ce stambene kuce u listi odabira.
- Trgovine i uredi: Biti ce trgovine i uredi u listi odabira.
- Industrijske zgrade: Biti ce industrijske zgrade u listi odabira.
- Rotacija: Ako se odabrano zgrada moze prikazati iz drugacijih kutova, tada je moguce ovdje odabrati odredjeni pogled. Donja lijeva slika ce se promijeniti kako bi to odrazila. Ako je ova postavka na slucajno, koristi ce se slucajni pogled zgrade.

simutrans-124.3/simutrans/text/hr/citylist_filter.txt000066400000000000000000000035111474050137200231470ustar00rootroot00000000000000Pomoc Liste Gradova

Lista Gradova

Lista Gradova prikazuje detalje o urbanim podrucjima (selima, gradovima i velegradovima) i stanovnicima.

Za otvaranje: klik nba city-list-tool u Upravljanje Listom ili stisnuti [T].
Lista Gradova ima dva gumba postavki koji odredjuju redoslijed po kojemu se pokazuju urbana poruÄja (i njihovi stanovnici).
{Savjeti: Ako su stavke u listi djelomicno vidljive, tada promijeniti velicinu Lista Gradova ili pomicati se koristeci klizni pokazivac.}

Ukupno stanovnika: je potpun broj stanovnika u igri (potpuni stanovnici svih urbanih podrucja). Nedavni porast stanovnika se prikazuje u zagradama.

Sortiranje po: ima postavke za odredjivanje redoslijeda urbanih podrucja prikazanih u listi.
Kiliknuti na gumb postavki za kruzenje kroz postavke (mijenja ime gumba postavki):

- Ime prikazuje alfanumericki koristeci ASCC-code redoslijed (velika slova prije malih slova) dodijeljenih imena.
- Citizens slaze prema velicini stanovnika.
- Town growth slaze prema rastu (koji je ovisan o velicini urbanih podrucja i broju prevezenih putnika).

- rastuce / padajuce mijenja redoslijed liste.

Kilik na stavku prikazanu uLista Gradovaza pregled vise informacija o urvbanim podrucjima.
Stavke prikazane za svako urbano podrucje sadrze:

ime dodijeljenih urbanom podrucju (moze se promijeniti u Informaciji Gradova)..

broj stanovnika urbanog podrucja, u zagradama je nedavni porast stanovnika.

simutrans-124.3/simutrans/text/hr/citywindow.txt000066400000000000000000000110521474050137200221350ustar00rootroot00000000000000Pomoc Statistike Grada

Statistika Grada

Statistika Grada prikazuje statistike o oznacenom urbanom podrucju i moze se koristiti za promjenu imena. Urbano podrucje je grad, gradic ili selo; ispod se pojam grad koristi za bilo koje urbano podrucje.

Svaki grad ima vlastitu gradsku vijecnicu oko koje raste. Prijevoz putnika i poste poboljsava rast, što ukljucuje ulice koje se grade ili koje se preuzimaju od igraca javnog servisa; nove gradsje zgrade i industrije koje se pojavljuju; i granice grada se prosiruju.

Klik na vijecnicu u pogledu igre sa Alatom Inspekcije ili na grad koji je prikazan uListi Gradova za otvaranje Statistike Grada. Ovdje se moze vidjeti i promijeniti ime grada, neke statistike, dvije mini-map, i graf gdje je vidljiv razvoj tijekom vremena za razne faktore koji se odnose na grad.

Ime: pridruzeno ime grada, gradica ili sela se prikazuje u kucici na vrhu Statistike Grada.
Imena takvih urvanih podrucja se koriste za stvaranje imena za stajalista unutar granica grada. Za promjenu imena samo kliknuti na kucicu i upisati novo ime.
{Savjet: Koristiti [!] za promjenu prikaza imena grada iznad Vijecnice u pogledu igre. Pogledati readme_citylist.txt (u ...simutrans/text/) za vise informacija o tome kako se stvaraju imena grada}.

Pod kucicom imena su prikazane neke osnovne gradsje statistike:
Velicina Grada: je trenutan broj gradjana. Nedavni porast populacije je prikazan u zagradama.
Zgrade: boj gradskih zgrada (rezidencijalne/komercijalne/industrijske) u gradu.
Koordinate mape: prikazuje granicu grada (mijenjati ce se kako grad raste). Prvi par vrijednostiprikazuje gornji lijevi kut, a drugi donji desni kut. Kako gradovi rastu, granice gradova se mogu preklapati.

Trenutni broj nezaposlenih i beskucnih gradjana grada. Ovo ce rasti kako se grad siri u granicama, i smanjivati se kada niknu nove zgrade. Ravnoteza ovih brojaca odredjuje koji tip gradskih gradjevina (rezidencijalne/komercijalne/industrijske) ce se konstruirati.

Gumb Dozvoli rast grada omogucava promjenu rasta grada na ukljuceno i iskljuceno.

Mini-mape svijeta igre u Statistike Grada prikazuje odredista putnika i poste koji su stvoreni unutar grada kao obojene tocke.
Desna mini-mapa prikazuje vrijednosti trenutnog kalendarskjog mjeseca igre, a lijeva za zadnji kalendarski mjesec. Boja svake tocke oznacava moze li se odrediste dostici ili ne:
- zuta tocka: postoji ruta i nenatrpano stajaliste za pocetak putovanja (sretno lice prikazano u Informacijama Stajalista).
- narancasta tocka: nema rute na to odrediste.
- crvena tocka: postoji ruta na odrediste, ali stajaliste na pocetku putovanja je pretrpano (nesretno lice u Informacijama Stajalista).

Ispod mini-mapa postoji graf koji prikazuje statistike za grad.
Na y-osi se prikazuje kolicina a na x-osi vrijeme. Kilik na jahace indeksa grafa za promjenu skale x-osi:
Godine: prikazuje godisnje vrijednosti za zadnjih 12 kalendarskih godina igre.
Mjeseci: prikazuje mjesecne vrijednosti za zadnjih 12 mjeseci igre

Klikom na gumbe opcije grafa, aktivirate i deaktivirate funkciju za svaki zadani gumb. Kada je neki gumb odabran prikazan je utisnuto.
Funkcije odgovaraju boji odgovarajucih gumbi postavki:
Gradjani: Broj ljudi koji zive u gradu
Rast grada: Promjene u populaciji (ovise o velicini grada i prijevoznoj usluzi koja je pruzena za putnike i postu).
Br. zgrada: Koliko gradskih zgrada ima u gradu.
Gradskih automobila: Koliko gradskih automobila je stvoreno
Putovanja: Koliko putnika je uslo u prijevoznu mrezu (prikazano kao sretno lice u Informaciji Stajalista)
Putnici: Ukupni broj korisnika stvorenih u gradu.
Poslana posta: Posta koja je usla u mrezu
Posta: Potpuni broj poste stvorene od grada.
Dostava:Broj trenutaka kada je bilo robe u skladistima u gradskim tvornicama
Roba:Broj trenutaka kada je skladistenje gradskih tvrtki biko provjeravano.

{Savjet: Postavke koje se odnose na gradove mogu se promijeniti u simuconf.tab i cityrules.tab}.

simutrans-124.3/simutrans/text/hr/climates.txt000066400000000000000000000052641474050137200215460ustar00rootroot00000000000000Pomoc Postavljanja Klime

Postavljanje Klime

Prozor Postavljanje Klime omogućuje promjenu postavki za topografske i meteorološke aspekte svijeta igre. Otvara se skupa sa Stvaranje Nove Igre i Jezici prozori.

Za namjestanje svake postavke, klik tipke strelice sa strane svake postavke.

Opcije Mape

Razina Vode - Postavlja koliko je visoka voda na mapi. Više vrijednosti daju manje zemlje i više tijela vode.

Visina Planina - Postavlja najvecu visinu terena.

Grubost Mape - Postavlja grubost terena. Veći brojevi stvaraju viÅ¡e talasanja u obalnim podruÄjima. Za stvaranjwe realistiÄnijih linija obale, koristiti veću vrijednost.

Postavke Linije Snijega
Linija snjiega je visina na mapa na kojoj se pojavljuje snijeg.

ljetna linija snijega - Linija snijega tijekom ljeta. Ovo je najveća vrijednost terena odabrana u opcijama klime.

Zimska Linija Snijega - Postavlja visinu snježne linije u zimi. Kako bi se snijeg pojavljivao u većim podruÄjima na mapi, držati ovu vrijednost niskom.

Postavke Klime
Postavlja razne postavke klime za novu mapu.
Vrijednost pokraj svakog tipa klime postavlja visinu u mapi terena gdje se pojavljuje klima. Za iskljuÄivanje odreÄ‘ene klime, postaviti njegovu vrijednost na 0 (zero).

Klima Pustinje - Vrlo malo oborina, ekstremi u temperaturama. Ravan krajolik.

Tropska Klima - Tipicno za ne-bezvodna podruÄja oko ekvatora, stalno visoka temperatura na razini mora i mala uzviÄ‘enja.

Mediterabska klima - Umjereno promjenjivo vlažno vrijeme

Umjerena Klima - Može se naći u podruÄjima izmeÄ‘u tropske i polarnih kapa, promijenjivo vrijeme.

Tundra - Niske temperature, rubovi polarnih kapa

Alpska Klima - Suha klima, hladne zime.

Druge Postavke

Nema Drva - Klik za omogućenje. OmoguÄiti ovu postavku za spreÄavanje Simutrans-ovog iscrtavanja drva. Drva opterećuju CPU vrijeme za iscrtavanje. Koristiti ovu postavku na PCima sa sporijim CPU ili malo RAM-a.

Broj Rijeka - Postavlja najveci broj rijeka koji se mogu stvoriti na mapi terena. Rijeke se ne mogu ploviti camcima ili brodovima bilo kojeg tipa.

Najmanja duzina rijeke - Postavlja najmanju duzinu rijeke na mapi u u pogledu kvadratica.

Najveca duzina rijeke - Postavlja najvecu duzinu rijeke na mapi u pogledu kvadratica.

simutrans-124.3/simutrans/text/hr/color.txt000066400000000000000000000014141474050137200210540ustar00rootroot00000000000000Pomoc boje igraca

Boja igraca

Boja igraca postavlja boju kompananije.
Vozila, zgrade i druge stvari prikazuju boju kompanije.

Boja igraca se otvara iz Opcije Igre.

Kilinuti na obojane kvadratice za promjenu boje kompanije.
Naslov od Boja Igraca se mijenja (ne na novu boju kompanije) kako bi se prikazala nova odabrana boja.

Uobicajena boja ljudskog igraca je lagano plava.
Neki predmeti nisu kodirani bojom i ne moraju prikazivati odabranu boju.

{Savjeti: Za promjenu AI boje igraca koristiti Lista Igraca ili P+ Promjena Igraca za odabir AI igraca}.

simutrans-124.3/simutrans/text/hr/display.txt000066400000000000000000000052301474050137200214030ustar00rootroot00000000000000Pomoc Postavki Prikaza

Postavke Prikaza

Postavke Prikazaima kontrole za izgled igre; & nudi informacije o performansama racunala.

Klik na Prikaz-gumb u Postavkama Igre za otvaranje Postavke Prikaza.

Klik na kvadrate-gumbe za odabir postavki (gumb je oznacen kada je postavka odabrana), ili koristiti tipke strelica za prilagodbu postavki:

promjena dana i noci: pogled vremena noci u igri.

Svjetlina:prikazuje koliko svjetlo/tamno se igra pojavljuje; manji brojevi za zatamnjenje; premale ili prebelike vrijednosti stvaraju probleme; koristiti [+] za povecanje vrijednosti preko 0.

Inverzni pomak: mijenja smjer pomicanja za pogled igre u ?Prozoru Igre.

Brzina Pomicanja: postavlja brzinu pomicanja za pogled igre u Prozoru Igre.

Pjesaci u gradovima: pogled pjesaka koji se pojavljuju u urbanim podrucjima.

Pjesaci na stajalistima: Pogled pjesaka koji nastaju kada vozilo dolazi na Stajaliste.

Gustoca prometa: postavlja broj privatnih auta u urbanim podrucjima.
Broj novih privatnih automobila koji nastaju kako urbana podrucja rastu ovisi o velicini urbanih podrucja i gustoci prometa. Vece vrijednosti stvaraju vise privatnog prometa, 0 ne stvara nista.

{Savjeti: Vise postavki i podrazumijevane postavke za Simutrans pokretanje se mogu promijeniti u simuconf.tab}.


Informacija Prikaza:

Ispod ovih postavki, informacija se prikazuje o racunalnim performansama pri izvrsavanju Simutrans-a.
Ako su brojevi (obicno bijeli) crveni ili ?zuti mozda je potrebno promijeniti vase postavke.
Promjene u stopi kako vrijeme prolazi u igri, T, (koristeci Fast Forward >> ikonu iznad pogleda igre, ili [,]/ [.]) moze promijeniti broj boje.

Vrijeme Okvira: ?Prvi broj je zamisljeno vrijeme izmedju okvira; drugi broj je stvarno vrijeme izmedju okvira.

Besposlenost: Ako je iznad 0, racunalo ima kapaciteta za izvrsavanje drugog software-a.

FPS: Vece vrijednosti znace kako se vozila pojavljuju gladje. Ako broj ostaje crven, racunalo je presporo za trenutne postavke(?pokusajte smanjiti velicinu prozora pogleda igre).

Simloopovi: Ako broj ostane crven, racunalo je presporo za treutne postavke - pokusajte sa manjom kartom sa manje urbanih podrucja.

simutrans-124.3/simutrans/text/hr/finances.txt000066400000000000000000000064441474050137200215340ustar00rootroot00000000000000Financijska Pomoc

Financije

Finances prikazuje pregled financijskog stanja tvrtke igraca.

Klik na ikon jezika gore unutar pogleda igre, ili stisnuti [f], ili kliknuti na ime igraca u Igraci, za otvaranje Financije.

Vrijednosti (u Hajo Kreditima) su prikazane za trenutnu i prethodne kalendarske godine.
Ova godina: trenutna kalendarska godina igre.
Prethodna godina: prethodna kalendarska godina igre.

Godišnje vrijednosti se također mogu vidjeti u grafikonu za zadnjih deset godina, ili mjesecne vrijednosti za zadnju godinu.
Klik na vrijednost ime-gumb za promjenu detalja na grafu: y-os je kolicina, x-os je vrijeme.
Klik na indeksnu karticu na grafu index-kartici za promjenu skale x-osi:
Godine: prikaz godisnjih vrijednosti za zadnjih deset kalendarskih godina.
Mjeseci: prikaz mjesecnih vrijednosti za zadnjih 12 mjeseci igre

Vrijednosti (klik na ime-gumb za prikaz detalja na grafu), sadrze:

Proceeds - ukupni prihod prijevoza putnika, robe, poste i od viskonaponskih prijenosa.

Operativni Troskovi - ukupni troskovi koji su se pojavili od svih Convoja kada su bili u prijevozu.
{Savjeti: Operativni troskovi po kilometru za vozila se mogu vidjeti u depou i iz Informacija Konvoja.}

Odrzavanje - ukupni troskovi koji su se pojavili odrzavanje prijevozne mreze.
{Savjeti: Troskovi po mjesecu za odrzavanje mreze (Odrzavanje (mjesecno) prikazano na desnom Financije) se odbija na kraju kalendarskog mjeseca igre.}

Operacijski Prihod - Prihod prijevoza robe, putnika i poste i visokonaposki prijenos (Postupa manje Operacijske Troskove i Odrzavanje).

Nova Vozila - Rashodi i prihodi primljeni od kupnje ili prodaje vozila.

Gradiliste - ukupni troskovi koji su se pojavili izgradnjom mreza prijevoza, oblikovanjem zemljista, visokonaponskim vodovima, i koristenjem Unisti/Ukloni i drugih alata uklanjanja puteva (tracnice, cesta, kanali i poletno/sletnig staza).

Tok Gotovine - ukupni prihod minus ukupni rashod (troskovi).

Stanje Racuna - trenutno dostupna gotovina za izgradnju ili kupnju vozila (takodjer prikazanano u sredini donje trake ispod pogleda igre.
{Savjeri: Ako igrac covjek ode u crveno (negativno stanje na racunu) u slijedna tri mjeseca, igrac je bankrotirao i igra je gotova}.

Imovina - vrijednost svih vozila tvrtke na kraju poslijednjeg kalendarskog mjeseca.
{Savjeti: svaki mjesec se vrijednost operativnih vozila lagano smanjuje, trenutni prodajna vrijednost operativnih vozila se moze vidjeti u Detalji Konvoja ili kada je vozilo u depou.}

Neto bogatstvo - Stanje na racunu plus imovina.

Margina - je omjer operativnog profita naspram prihoda.

Puto?vali - ukupni broj robe, putnika i prevezene poste.

{Savjeti: Neki troskovi, pocetno stanje i financije u igri se mogu promijeniti u simuconf.tab}

simutrans-124.3/simutrans/text/hr/general.txt000066400000000000000000000063621474050137200213620ustar00rootroot00000000000000Simutrans Pomoc

Opcenita Pomoc

- Dobrodosli
- Sucelje Igre
- Pomoc Za Misa (za napisati)
- Podzemlje
- Pomoc Za Tipkovnicu
Opcije Igre
- Jezik
- Boja Igraca
- Postavke Prikaza
- Zvuk & Glazba
- Igraci
- Ucitavanje Igre
- Spremanje Igre
- Nova Igra
- - Kontrola Klime
- - Ucitavanje Visinske Mape

Glavni Meni
- Postavke Igre
- Mapa
- Alat Istrazivanja
- Alati Za Oblikovanje
- Zeljeznicki/Vlakovni Alati
- Monorail Alati
- Tramvajski Alati
- Cestovni Alati
- Lucni Alati
- Aerodromski Alati
- Alati Posebne Izgradnje
- Alati Uredjivanja Igre
- Unistiti/Ukloniti

?Meni Upravljanja
- Upravljanje Linijama
- Liste
- - Lista Stajalista/Stanica
- - - Filter Liste Stajalista/Stanica
- - Lista Vozila
- - - Filter Liste Vozila
- - Lista Gradova
- - Lista Robe
- - Lista Industrije
- - Lista Atrakcija
- Centar Poruka
- Financije

Druge Postavke
- Spremiti Sliku Ekrana
- Pauza
- Brzo Unaprijed
- Pomoc

Drugi Dijalozi
-Kontrole Depoa
-Kontrole Rasporeda
- Informacija Stajalista
- - Detali Stajalista
- Informacija Konvoja/Vozia
- - Detalji Konvoja/Vozila
- ?Informacija Grada
- Informacija Industrije

Ako pomoc nije nadjena ovdje, pokusati
http://guide.simutrans.com, ili
http://wiki.simutrans.com, ili
http://simutrans-tips.com, ili
http://forum.simutrans.com.

simutrans-124.3/simutrans/text/hr/language.txt000066400000000000000000000017061474050137200215250ustar00rootroot00000000000000Pomoc o jezicima

Jezici

Prozor Jezici mijenja jezik koji se koristi u igri.

Otvara se iz Opcije Igre prozora i sa Stvoriti Novu Igru prozorima.

Uobicajeni jezik za Simutransa je Engleski. Za igranje igre u drugom jeziku, odabrati gumb pokraj jezika u kojemu zelite igrati.

Jezik se moze promjeniti bilo kada tijekom igre. Za promjenu jezika, odabrati Opcije Igre -> Jezik.

Promjena jezika se dogadja odmah nakon stvaranja nove igre i nakon zatvaranja Jezici prozora ako se mijenja usred igre.

Ako prijevod nije dostupan u odabranom jeziku, moze se pojaviti na engleskom.

Za pomoc oko prijevoda Simutransa u Vas jezik, posjetite https://translator.simutrans.com

Da biste pomogli u prevođenju Simutrana na vaš jezik,
posjetite https://translator.simutrans.com

simutrans-124.3/simutrans/text/hr/linemanagement.txt000066400000000000000000000171171474050137200227310ustar00rootroot00000000000000Upravljanja linijama

Upravljanje linijom

Upravljanje Linijomnudi informacije i kontrole za upravljanje linijama (rute i najmanja kolicina robe & putnika zahtjevani za Konvoj to proceed) za konvoj ili visestruke konvoje na istoj ruti.

Linije se sastoje od Stajalista gdje vozila utovaruju i istovaruju robu i putnike (vozila vodenog prijevoza mogu koristiti bilo koji kvadrat u podrucju pokrivenisti doka) i putne tocke (koristene za usmjeravanje vozila ako postoji vise od jedne opcije ili nude privremene tocke cilja).

Klik na mreznu-ikonu s gornje strane igre ili pritisak [w] za otvaranje Upravljanje Linijama, sto moze mijenjati velicinu (klik na strelicu dolje u alatnoj traci za povrataka na originalnu velicinu).

Lijeva strana od Upravljanja Linijama prikazuje postojece Linije (za pomicanje u listi: koristiti klizac s desne strane liste), koje se mogu filtrirati prema tipu prijevoza, klikom na indeks-jahac iznad liste za odabir:
Sve: lista Linija za sva vozila.
Vlak: lista Linija za sva tracnicka vozila.
Monorail: lista Linija za sva Monorail/maglev vozila.
Tramvaj: lista Linija za sve tramvaje.
Kamion: lista Linija za sva cestovna vozila.
Brod: lista Linija za sva vodena prijevozna vozila.
Zrak: lista Linija za sve zrakoplove.

Boja imena linije koja se pojavljuje u listi za prikaz slijedeceg:
bijela - nema vozila pridruzenih liniji
zuta - ?nisu u funkciji, ne stvaraju dobit ili gubitak
crna - ?stvaraju profit, ?visak kapaciteta, ?poboljsanje moguce
plava - ?stvaraju profit, malo dodatnog kapaciteta
crvena - linija stvara gubitak

Pod listom postojecih linija su gumbi opcija za upravljanje Linijama.
Klik na liniju za odabir (istice ime) i pregled informacija o Stajalistima, dobiti, i konvojima na odabranoj Liniji.
Ako su detalji o Stajalistima ili Konvojima samo djelomicnop vidljivi potrebno je promijeniti velicinu Upravljanje Linijama ili koristiti klizac za pomicanje informacija.

Opcijski gumbi, slijeva, sadrze (klik za odabir):

Nova Linija:opcija otvara kontrole za definiranje Rasporeda (ruta i najmanja kolicina robe ili putnika zahtjevanih od Convoja to proceed) za novu Liniju .
Dodati koliko je potrebno Stajalista ili putnih tocaka, postavka nivoa Cekanja na koliko je potrebno, zatim zatvoriti Kontrole Rasporeda za stvaranje Nove Linije (klik x u gornjem lijevom kutu kotrola ili koristiti tipkovnicu). Novoj Liniji ce se pridjeliti broj i prikazati se u Upravkljanju Linijama.
{Savjeti: Odabrati tip prijevoza koristeci index-jahac prije stvaranja nove linije. Vozila ne utrpavaju ili istrpavaju robu i putnike na putnim tockama.}

Osvjezavanje Linije: otvara kontrole za promjenu i upravljanje postojecim Rasporedom (ruta i najmanja kolicina robe i putnika zahtjavana od Konvoja za nastavak) Linije. Promjene ce se odraziti na vozila na Liniji, kada se zatvore Kontrole Rasporeda (klikk x u gornjem lijevom kutu).
Klik na ime Linije u listi za odabir (oznacava ime) tada klik na gumb opcije za otvaranje Kontrola Rasporeda.

Brisanje Linije: brisanje odabrane linije (ruta i najmanja kolicina robe i putnika zahtjevane od Konvoja za nastavak).
Klik na ime Linije u listi za odabir (oznacava ime), tada klik na gumb opcije za uklanjanje. Daljnja potvrda nece biti potrebna.

Kada je Linija odabrana, Stajalistza su prikazana gore lijevo u Upravljanje Linijom. Klik na Stajaliste u listi za otvaranje Informacija o Stajalistu.
Stavke prikazane za svako stajaliste sadrze:
status-traku-boje: Boje prikazuju operaciju od Stajalista s obzirom na popunjenost. Status-traka-boje je također koristi u Listi Stajalista i Informacija o Stakjalistu je iste boje prikazane u traci-boje iznad Stajalista u prikazu igre:
- zuto: nije u sluzbi.
- zeleno: nisu potrebna poboljsanja.
- narancasto: moguca poboljsanja.
- crveno: preporucena poboljsanja.
{Savjeti: Koristiti [!] za promjenu stupca-boje iznad Stajalista u pogledu igre.}
ime koje je pridruzeno Stajalistu.
broj Stajalista (Stajalista se numeriraju ako je ukljucena postavka u simuconf.tab).
ikona/e vozila prikaz koji tipovi vozila mogu kosristiti stajaliste (takodjer koristeno u Informaciji Stajalista i Listi Stanica). Ikone sadrze: autobus (za cestovna putnicka vozila), kamion (za cestovna vozila prijevoza robe), vlak, brod ili zrakoplov. Tramvaji su prikazani autobus-ikonom ili vlak-ikonom sto ovisi o tipu stanice.
ikona/e tereta prikaz koji predmeti (putnici, roba i posta) koje Stajaliste moze obraditi (takodjer koristeno u Informaciji Stajalista i Listi Stanica).
{Savjeti: dodavanje ispravnih dodataka moze promijeniti kategorije predmeta koje stajaliste moze obraditi. Postanski ured moze biti dodan Stajalistima za obradu poste}.
cekanje detalja o raznim robama i putnicima.

Sdesna od Upravljanja Linijama informacije na grafu, ime-kvadratic i Konvoj lista su prikazani za odabranu Liniju.

Klik na ime Linije u listi za odabir (oznacava ime). Klik na opcija-dugme za promjenu informacije, o odabranoj Liniji i vozilima pridruzenim istoj, na grafu (x-os je vrijeme u mjesecima):

- Slobodan Kapacitet - kolicina viska prostora od vozila za robu i putnike.

- Putova?li - kolicina robe i putnika koji koriste Liniju.

- Prihod - kolicina dobiti stvorena od vozila.

- Operativni Troskovi - nastali troskovi od vozila u tranzitu.

- Profit - stvoreni profit minus troškovi koji su nastali (Prihod minus Operativni Troskovi).

- Konvoji - broj Konvoja pridruzenih Liniji.

Za preimenovanje Linije: Klik na imne Linije u listi za odabir (oznacava ime), tada klik na ime-kvacicu (pod opcijama grafa, ispod ispisanih Konvoja) i upis novoga imena.

Kada je Linija odabrana (klik na ime Linije u listi za oznacavanje), Konvoji pridruzeni Liniji su prikazani ispod grafa.
Na gornjem dijelu liste vozila: ukupni broj Konvoja pridruzenih Liniji; prihod (prinos minus operacijski troskovi), kapacitet, i trenutna kolicina robe i putnika prevezenih (% punog kapaciteta u zagradama) svih Konvoja od Linije je prikazano.
Klik na prikazani predmet za prikaz informacija o tome Konvoju (koristiti klizac za pomicanje liste).
Predmeti prikazani za svaki Konvoj sadrze:
ime koje je pridruzeno (podrazumijevano je to proizvodjac prve jedinice vozila kupjene ili sastavljene za Konvoj).
dohodak prikazuje dobit (stvoreni prihod minus opecarijski troskovi).
Linija: prikazuje ime Linije prikazane za Konvoj i prikazuje je li u depou.
grafike prikazuje kompoziciju i trenutni nivo predmeta na ploci.

simutrans-124.3/simutrans/text/hr/list.txt000066400000000000000000000034741474050137200207210ustar00rootroot00000000000000Pomoc Listi

Liste

Liste ima postavke za otvaranje kontola za informacije o trenutnom statusu igre (i takodjer kontrole za namjestanje relativnog dohotka koji je dobiven prijevozom raznih roba, putnika & poste).

Informacija je dostupna za igraca u listama o: Stajalistima; Convojima; urbanim podrucjima; dohotcima dobivenim iz raznih roba, putnika i poste; industrije; i turistickih znamenitosti.

Klik na ikonu liste s gornje strane pogleda igre za otvaranje Lista.
Pomicanje kurzora misa, nakon otvaranja ili klikom na alatnu traku, preko postavke alata liste za prikaz imena.

Klik na postavku alata za otvaranje kontrola za informacije, slijeva na desno, o:

Lista Stanica: Stajalista, gdje vozila utovaruju ili izbacuju robu & putnike (ali ne Stajalista samo za vozila prijevoza vodom).

Lista Vozila: cestovna i tracnicka vozila, zrakoploci i brodovi.

Lista svih gradova: urbana podrucja (sela, gradici i gradovi).

Lista svih roba: dohotci dobijevi od raznih roba, putnika i poste (ukljucuje kontrole za namjestanje relativnog dohotka).

Lista Tvrtki: industrija (potrosaci i dobavljaci robe).

Lista Znamenitosti: touristicke znamenitosti.

simutrans-124.3/simutrans/text/hr/load.txt000066400000000000000000000027641474050137200206660ustar00rootroot00000000000000Ucitavanje Pomoci

Ucitavanje

Ucitavanje pomnovno pokrece spremljenu igru (za nastavak igranja) & moze se koristiti za brisanje tih igara. Igra koja je ponovno startana mijenja trenutni svijet koji je izgubljen.

Ucitavanje otvara iz Stvaranje Novoga Svijeta & Postavke Igre ili pritiskom [L]; & lista imena, datuma & vremena (of spremanja) dostuopnih igara.
Ako nisu vidljive sve igre: koristiti kliznik sa desne strane liste za pomicanje imena.

Klik na ime liste za ponovno pokretanje igre; ili unos imena u kucicu s gornje strane Ucitavanja: klik na kvacicu, tip imena, & stisnuti [Enter] ili [Return] ili klik na OK.
Neispravno ime ce izazvati poruku o gresci: zatvoriti poruku, ponovno pokusati.

UPOZORENJE: Klik na x-button s imenom za BRISANJE igre odmah & za stalno.
Ime se uklanja iz liste i Ucitavanje se zatvara. Koristiti funkciju oprezno.

BITNO: Nove distribucije Simutrans-a se javljaju redovito & igre iz prethodnih distribucija Simutrans-a mozda ne rade sa kasnijim inacicama; molimo procitajte biljeske distribucije za kasnije inacice kako bi se provjerila kompatibilnost starijih igara.

Klik na Odustajanje za zatvaranje Ucitavanja; ili x u gornjem lijevom kutu; ili koristiti tipkovnicu.

simutrans-124.3/simutrans/text/hr/options.txt000066400000000000000000000024451474050137200214360ustar00rootroot00000000000000Pomoc Postavki Igre

Postavke Igre

Postavke Igre otvara kontrole za operaciju & prezentacijzu igre; izlaz iz Simutrans-a iz Postavke Igre.

Kliknuti na ikonu diskete na gornjem dijelu pogleda igre za otvaranje Postavke Igre.

Kilik na gumb za otvaranje novih kontrola:

Jezik: postavljanje jezika koristenom u igri.

Boja Igraca: postavljanje boje Igraceve kompanije.

Prikaz: postavke kako se igra pjavljuje u Simutrans-u.

Zvuk: postavke za zvuk & glazbu u igri.

Igraci: otvara kontrole za razlicite kompanije igraca.

Ucitavanje: otvara kontrole za restart snimljene igre.

Spremanje: otvara kontrole za spremanje trenutne igte, kako ni se nastavila kasnije.

Nova ?Igra/Mapa: otvara kontrole za pocetak nove igre (zatvara ostale trake izbornika, tekstove & postavke u trenutnoj igri).

Izlaz:napusta Simutrans, trenutna igra se ne sprema.

simutrans-124.3/simutrans/text/hr/players.txt000066400000000000000000000036241474050137200214220ustar00rootroot00000000000000Pomoc Liste Igraca

Lista Igraca

Lista Igraca daje informacije i ima kontrole za razne tvrtke igraca.

Klik na Igraci-gumb u Postavkama Igre ili pritisak [k] za otvaranje Liste Igraca koja prikazuje imena igraca & Stanja Racuna.

Postoji osam igraca: covjek, javni servis i sest AI igraca. Kontrole omogucuju igranje igre kao drugaciji igrac ako je odabrano Dozvoliti promjenu igraca na pocetku igre.

Klik na gumb strelice za rad kao drugacija tvrtka igraca u trenutnoj igri. Poruka potvrde se pojavljuje kako je promijenjen igrac: klik na x u gornjem lijevom kutu poruke ili koristiti tipkovnicu za zatvaranje.

Klik na ime igraca za predgled njegovih financija.

Klik na cetvrtasti-gumb pokraj AI imena igraca za promjenu ukljucen/iskljucen igrac (gumb je podebljan kakda je igrac odabran).

AI igraci ne bankrotiraju i koriste vozila sa najvecom efikasnoacu.
Iskljucivanje AI igraca tijekom igre nece ukloniti prijevoznu mrezu.
Neki AI igraci mogu koristiti samo cestovna ili zeljeznicka vozila, neki mogu prevoziti samo robu ili putnike.

{Savjeti: Vozila ne mogu koristiti tracnice drugog igraca ili Stajalista (svejedno vozila svih igraca mogu koristiti predmete sagradjene od igraca javnog servisa).
Igraci ne mogu graditi predmete ili postavljati putne tocke na tracnice drugih igraca ili ceste, ili uklanjati predmete sagradjene od drugih igraca (svejedni neki predmeti gradjeni od javnog servisa mogu se unistiti koristeci Unisti/Ukloni).
Onemoguciti postavku promjene igraca i pristup posebnih alata kao igrac javnog servisa.}

simutrans-124.3/simutrans/text/hr/simutrans.txt000066400000000000000000000044451474050137200217720ustar00rootroot00000000000000 Uvod

Dobrodosli u Simutrans ...

Odaberite jednu, od vise tisuca Simutrans karata ili stvorite novu pomocu mape visina. Zatim, stavite sebe u cipele od mladog poduzetnika s nesto novca od vasih djeda i bake: nestrpljiv da bi ih ucinio ponosnima, s ambicijama osnivanja uspjesnog transportnog poduzeca, vas izazov je sada izgradnja uspjesnog pothvata.

Kako vrijeme prolazi, razvijajajte svoju tvrtku u prijevozno carstvo, vodjenjem doboroustaljene ekonomije isporukom tereta i zadovoljavanjem zahtjeva putovanja milijuna putnika svaki mjesec.
Prevozite putnike, postu i robu zeljeznicom, cestom, brodom i cak jos i zrakom.

Svaka mapa ima nesto drugo za ponuditi. Pogledajte dobro na svoju okolinu ... njezina buducnost lezi u rukama vas i vasih konkurenata.

U pocetku, moglo bi biti lakse jednostavno dobavljati elektranu sa potrebnim sirovinama. Tada slijedi povezivanje drugih tvornica, mozda cak i upotrebe centralnih cvorista gdje se roba stalno prekracava.
Nedostatak prijevoza samo robe je kako gradovi nece rasti, a nove industrije se nece pojaviti.

Umjesto toga, vi odmah mozete krenuti na prijevoz putnika (i poste). To je veci izazov, jer stanovnici ovog svijeta zele putovati u odredjena mjesta.
Neki trebaju ici u tvornice na rad, neki zele ici u kupovinu u veliki trgovacki centar u glavnom gradu, a drugi zele otici u razgledavanje.

Ako ne nudite veze na njihovo odrediste, oni uopce nece putovati sa vama. Trebati ce izgraditi prometnu mrezu gdje je moguce otici na sto je vise moguce odredista - barem na sve one popularne. Kada se vase mreze uspostave, morati cete ih nadograditi kako bi ih zadrzali na istom nivou potražnje. Dakle planirajte unaprijed.
Ukoliko se putnicima svidja vasa usluga, gradovi će rasti i nove industrije će biti uspostavljene i samo tada će gospodarstvo pokrenuti glatko.

Mozete igrati koliko god zelite. Pocetak u 1880 i kraj u 2050. Postojati ce nova vozila i zgrade tijekom vremena.
Igrajte protiv AI ili sami. Samo ako je vase neto bogatstvo negativano tri mjeseca za redom, bankotirati cete i igra je gotova. Provjerite svoje neto bogatstvo u prozoru financija.

Simutrans-Team i zajednica Vam zele odlican provod ovdje u Simutrans-u!

simutrans-124.3/simutrans/text/hr/sound.txt000066400000000000000000000014421474050137200210670ustar00rootroot00000000000000Pomoc Postavki Zvuka

Postavke Zvuka

Postavke Zvuka ima kontrole za zvucne efekte i glazbu.

Postavke Zvuka se otvara iz Opcije Igre.

Koristiti tipke strelica za prilagodbu postavki ili pomicnih traka za smanjivanje/povecavanje glasnoce:

Glasnoca zvuka: postavlja glasnocu zvucnih efekata u igri.

Glasnoca glazbe: postavlja glasnocu glazbe. Ako glazba ne postoji tada kontrole nece raditi.

Trenutno svira: changes music; tipke strelica kruze kroz dostupnu glazbu.

Molimo primjetiti: glazba se ne isporucuje sa Simutrans-om.
Pomognite javno dodati glazbu na http://wiki.simutrans.com

simutrans-124.3/simutrans/text/hr/station_details.txt000066400000000000000000000016101474050137200231220ustar00rootroot00000000000000Detaljnih Informacija Stajalista

Pomoc Detaljnih Informacija Stajalista

Spojene Tvornice: Sve tvornice u podrucju pokrivanja stajalista se prikazuju alfabetski. Podrucja pokrivanja se mogu prikazati koristeci tipku v.

Roba potrebna od okolnih industrija: Svi tipovi robe, koje su potrebne od stajalista spojenih tvornica, se prikazuju alfabetski.

Linije koje opsluzuju ovo stajaliste: Sve linije, koje opsluzuju stajaliste, prikazuju se alfabetski. Klik na strelicu otvara Upravljanje Linijom.

Direktne rute: Sva stajalista se prikazuju, koja se direktno opsluzuju preko linija sa stajalista. Imenu stajalista slijedi u slijedecem retku nakon crtice tip prijevoza. Preko strelice ispred imena stajalista moguce je direktno skociti na to stajaliste.

simutrans-124.3/simutrans/text/hr/underground.txt000066400000000000000000000043641474050137200223010ustar00rootroot00000000000000gradnja u podzemlju

Postoje 2 moguca pogleda podzemlja.
potpuni pogled podzemlja
Sa U se ulazi u potpuni pogled podzemlja. U ovome pogledu se iskljucuje prikaz svih objekata na povrsini.
Podzemni pogled kao nivo
Sa Ctrl + U se ukjlucuje podzemni pogled sa nivoima. U ovom pogledu se iskljucuje prikaz svih objekata, koji se nalaze iznad odabranog nivoa. To su svi objekti povrsine i takodjer svi objekti u podzemlju, koji se nalaze iznad odabrane razine.

Promjena nivoa se dogadaja sa + (vise) i - (nize) ili preko Postavki prikaza.

Pokazivac misa (Cursor)
puni pogled podzemlja
Kod punog pogleda podzemlja se prikazuje resetka povrsine. Na nesagradjenim poljima se pokazivac namjesta prema toj resetci. Na sagradjenim poljima se pokazivac namjesta na izgradjena polja.
Jer je namjestanje pokazivaca misa preko resetke povrsine poprilicno mukotrpno, trebalo bi se pri gradnji u podzemlju koristiti pogled nivoa.

Pogled podzemlja kao nivo
Kod pogleda nivoa se resetka prikazuje na aktivnom nivou. Pokazivac nisa se namjesta na tu resetku. Jer se pokazivac misa nalazi uvijek na aktivnom nivou, gradnja je puno laksa.

Gradnja rute

opcenito


Opcenito se rute u podzemlju grade alatima za tunele. Kako bi se u pozemlju moglo graditi, mora se sagraditi tunel ili ulaz u tunel (tipka Ctrl + klik sa alatom za tunele na polju nagiba).

Promjena nivoa
Kako bi se promijenio nivo u podzemlju, koriste se alati iz Smanjiti/povecati nivo iz menija Alati okolisa. Za promjenu nivoa, potrebno je jednostavno sa odgovarajucim alatom kliknuti na kraj rute.

Posebni slucaj tramvaj


Tracnice za tramvaj se takodjer u podzemlju grade sa normalnim alatima za tracnice na cestu.

Stanice i pratece zgrade
Samo vlastite Stanice se mogu graditi jedna preko druge.

Pratece zgradee se ne mogu izgraditi u podzemlju.

Signali
Mogu se koristiti kao na povrsini.

simutrans-124.3/simutrans/text/hr/window.txt000066400000000000000000000114161474050137200212500ustar00rootroot00000000000000Pomoc Koristenja Sucelja Igre

Sucelje Igre

Simutrans se igra preko Sucelja Igre koje daje informacije o trenutnoj igri; pristup trakama izbornika & kotrolama igre; i pogled trenutnoga svijeta igre.

naslov: lijevo na naslovu Sucelja Igre se prikazuje inacica i datum release-a Simutransa koji je trenutno pokrenut.
Desna strana naslova takodjer sadrzi kontrole za smanjivanje, povecavanje Sucelja Igre i takoder izlaz iz Simutrans-a.

Ikone: red ikona, koje se koriste za pristup trakama izbornika igre i kontrolama igre kada se igra Simutrans, nalazi se pravo ispod naslova. Ikone (klik za koristenje) su grupirane u tri seta:

- Glavni Meni ikone sadrze:
- disketa: otvara Postavke Igre
- mapa: otvara Mapu
- lupa odabire Alat Inspekcije
- ikona nagnuca tla: otvara traku alata oblikovanja tla
- vlak: otvara ?traku alata zeljeznica vlak
- monorail/maglev: monorail transport traka alata
- tramvaj: otvara tram transport traku alata
- kamion: otvara cestovni transport traka alata
- brod: otvara vodeni transport traka alata
- zrakoplov: otvara zracni transport traka alata
- crvena kapljica u zuto krugu (ikona krana u pak128): otvara traka alata posebnih konstrukcija
- crveni kriz (ikona buldozera u pak128): odabire Alat Unisti/Ukoloni

- Meni Vodjenja ikone sadrze:
- ikona mreze: otvara Vodnjenje Linije
- ikona lista: otvara Liste
- ikona postanskog sanducica: otvara Centar Poruka
- ikona novca: otvara Financije

- Druge Postavke ikone sadrze:
- ikon kamere: hvata trenutnu sliku od Sucelja Igre (bez naslova) i sprema kao sliku u direktorij/mapu ...simutrans/screeshot/
{Savjeti: Slika takodjer moze biti uhvacena sa pritiskom tipke [c].}
- ikona salice za kavu: pauza /odpauziranje igre
{Savjeti: Pritisak tipke [p] se takodjer moze koristiti za pauzu/odpauziranje igre}.
- >> ikona: odbire/odznacava Brzo Naprijed. (mijenja stopu po kojoj Vrijeme, T, prolazi u igri).
{Savjeti: Brzo Naprijed se takodjer more odabrati/odznaciti sa pritiskom tipke [W]
VAZNO: Igra mozda nece ici glatko;>Informacija Prikazaprikazuje moze li se racunalo nositi sa promjenom.}
- ?: otvara Simutrans Pomoc

prikaz igre dio trenutnog pogleda igre se prikazuje ispod Ikona.
Mozete zumirati i odzumirati pogled igre i takodjer se pomicati okolo u drugim dijelovima svijeta igre koristeci misa ili tipkovnicu.

privremeni scroll-bar pomicanja pojavljuje se i prikazuje poruke na dnu pogleda igre.
{Savjeti: Klik na poruku u centru poruka za centriranje pogleda igre na povezanoj poziciji.}

Donja traka koja prikazuje informacije o trenutnom svijetu igre se prikazuej ispod pogleda igre.
Pruzena informacija, slijeva premna desno u donjoj traci sadrzi:
datum & vrijeme: trenutan datum i vrijeme u svijetu igre, slijedi grafiku i ime godisnjeg doba.
stanje na racunu: trenutna dostupna gotovina za konstrukciju i drugi troskovi (nabavljanje vozila, odrzavanje infrastrukture prijevoza i troskovi koristenja vozila u pogonu).
koordinate: pokazuje poziciju kursora u pogledu igre. Tri lika predstavljaju X koordinate, Y koordinate i visinu.
T: prikazuje stopu prolaska vremena u igri.
{Savjeti: Koristiti [.] / [,] za ubrzanje/usporavanje vremena, T ; Prikaz Informacijapokazuje moze li se racunalo nositi sa promjenom.
Koristenje Brzo Naprijed mijenja T sa ">>" na donjoj traci.}
vremenska traka: prikazuje je li vremenska traka odabrana u trenutnoj igri.

simutrans-124.3/simutrans/text/hu.tab000066400000000000000000001264441474050137200177030ustar00rootroot00000000000000§Magyar PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: hu Magyar # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ AMBIENT_SOUND Háttérzajok CASH_SOUND Pénzcsörgés cl_btn_filter_disable tiltva cl_btn_filter_enable engedélyezve cl_btn_filter_settings Beállítások cl_btn_sort_asc növekvÅ‘ cl_btn_sort_desc csökkenÅ‘ cl_btn_sort_id azonosító szám szerint cl_btn_sort_income Bevétel cl_btn_sort_name Név cl_btn_sort_type Típus clf_btn_alle mind clf_btn_invers fordít clf_btn_keine semmi CROSSING_SOUND Vasúti átjárók FACTORY_SOUND Gyárak zaja gl_btn_sort_bonus Bónusz gl_btn_sort_name Név gl_btn_sort_revenue Bevétel gl_btn_unsort Deszortíroz hl_btn_filter_disable Tiltva hl_btn_filter_enable Engedve hl_btn_filter_settings Beállítások hl_btn_sort_asc NövekvÅ‘ hl_btn_sort_desc CsökkenÅ‘ hl_btn_sort_name Név hl_btn_sort_type Típus hl_btn_sort_waiting Várakozók hlf_btn_alle mind hlf_btn_invers fordít hlf_btn_keine semmi Install Telepít Lake Tó Lake height tavak max. magassága Networks Hálózat Num pad keys always move map A numerikus billentyűkkel mindig mozdul a térkép Open Sea Nyílt Tenger Queueing Várakozók rainfall páratartalom Reselect closes tools Újbóli kiválasztás bezárja az eszközt Road toll Útdíjak Scenario Forgatókönyv sea tengeri éghajlat Sound range: Hangterjedelem Start this as a server Kiszolgáló indítása ezzel a játékkal TOOL_SOUND Eszközök hangja TRAFFIC_SOUND Forgalom zaja Transfers Ãtszállások #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Sarkvidéki éghajlat desert Sivatagi éghajlat mediterran Mediterrán éghajlat rocky Sziklás/köves temperate Mérsékelt éghajlat tropic Trópusi éghajlat tundra Tundra éghajlat #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Forgatókönyv betöltése sikertelen Bridge blocked by way below or above. Valami útban van a tervezett híd alatt vagy felett. Can't buy obsolete vehicles! Elavult járművet nem vásárolhatsz! Cannot alter water Ezt a medencét nem lehet jobban leereszteni vagy feltölteni. Cannot build on a double slope! Ez csak enyhe emelkedÅ‘n vagy sík terepen építhetÅ‘! Cannot built depot here! Ide nem építhetsz depót! Cannot built this station/building\nin underground mode here. Az épület metróépítÅ‘ módban nem építhetÅ‘. Cannot create generic line!\nSelect line type by\nusing filter tabs. Ãltalános menetrendet nem lehet kialakítani! Egyszer válasz menetrend típust. Cannot create socket Nem hozható létre socket Cannot rotate this building! Ez az épület nem forgatható el! Client closed connection during transfer A kliens az átvitel közben lezárta a kapcsolatot Convoi handles exhausted! A szerelvények száma elérte a maximumot. Convoy already deleted! A szerelvényt már törölték! Could not open file Nem sikerült megnyitni a fájlt Das Feld gehoert\neinem anderen Spieler\n Ezt a területet más játékos birtokolja! Der Besitzer erlaubt das Entfernen nicht Az eltávolítást a tulajdonos nem engedélyezte! Diese Zusammenstellung kann nicht fahren!\n Rossz kombináció! Flugzeughalt muss auf\nRunway liegen!\n LégikikötÅ‘ csakis kifutópályára építhetÅ‘! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Orsinak továbbítva!!! Hier kann kein\nSignal aufge-\nstellt werden!\n Vasúti forgalomjelzÅ‘ ide nem építhetÅ‘! In order to lock the game, you have to protect the public player by password! Ahhoz, hogy lezárhasd a játékot, le kell védened a publikus játékost jelszóval! Loading a new game will end the current server session! Új játék betöltése befejezi a jelenlegi kiszolgáló-munkamenetet! Lost connection\nto server! A szerverrel való kapcsolat megszűnt! Lost synchronisation\nwith server. Szerverrel való szinkronizáció nem működik! Maglevhalt muss auf\nMaglevschiene liegen!\n Nyeregvasúti megálló\ncsakis nyeregvasútra\népíthetÅ‘!\n Monorailhalt muss auf\nMonorail liegen!\n Megálló csakis nyeregvasútra építhetÅ‘! Monorails are not available yet! Még nem áll rendelkezésre nyeregvasúti szerelvény! More than one possibility to build this dock found. Ez a kikötÅ‘ egynél többféleképpen is megépíthetÅ‘. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n A keskeny nyomtávú sínen keskeny nyomtávú megállónak kell lennie No bridges over runways! Kifutópálya fölé nem lehet hidat építeni! No suitable way on the ground! Megállót csak útra lehet építeni! No through station here! Ide nem lehet építeni megállót! Not enough bytes transferred Túl kevés adat érkezett Not enough clearance. Két út között legalább két egység magasságkülönbség szükséges. Not enough money! Nincs elég pénz az építéshez! On narrowgauge track only!\n Csakis kisvasútpályán lehet! Only public player can lock games! Csak publikus játékos zárhatja le a játékot! Only up and down movement in the underground! Földalatti mezÅ‘ csak a talajemelÅ‘ és talajsüllyesztÅ‘ eszközzel formálható! Out of funds Nincs elég pénzed erre! Post muss neben\nHaltestelle\nliegen!\n A posta/vezérlÅ‘/tároló egy megállóhoz/állomáshoz kell közel legyen! Protocoll error (expecting game) Protokoll hiba Schiffhalt muss im\nWasser liegen!\n Hajómegálló csak vízre a dokkok mellé tehetÅ‘! Server busy Szerver elfoglalt Server version too new A kiszolgáló a program újabb verzióját használja. Terraforming not possible\nhere in underground view Terraformálás nem lehetséges metróépítÅ‘ módban. This tunnel branches. You can try Control+Click to remove. Ennek az alagútnak kettÅ‘nél több bejárata van. Próbáld Ctrl+klikkel eltávolítani az alagutat. Upgrade must have\na higher level Fejleszteni csak nagyobbra lehet! Vehicle %s cannot choose because stop too short! %s járműnek túl rövid a következÅ‘ megálló! Zughalt muss auf\nSchiene liegen!\n Vasúti megálló csak vasútra tehetÅ‘! #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Súgó

Tartalom

A Simutransról

%1$s

Hogyan használd

%2$s

Hogyan kezdj új játékot

%4$s

Hogyan játszd

%5$s

Eszközök

%3$s

További ablakok

%6$s Color-coded terrain according to altitude. A területek magasságtól függÅ‘ színezése Decrease water height Vízszint csökkentése Highlight railroad tracks Vasúti sínek jelölése a térképen Highlite depots Depók jelölése a térképen Highlite electrical transmission lines Elektromos hálózat jelölése Highlite factories Gyárak jelölése Highlite forests Fák jelölése a térképen Highlite tourist attraction Turistalátványosságok jelölése Increase water height Vízszint növelése Open station/stop details Ãllomás/megálló részleteinek megnyitása Overlay city limits Városhatárok mutatása a térképen Overlay passenger destinations when a town window is open Utasok célját jelöli, ha meg van nyitva a város infó ablak Overlay schedules/network Megjeleníti a vonalhálózatot Overlay town names Városok nevét mutatja Please click on the map to add\nwaypoints or stops to this\nschedule. Jelöld ki az érinteni kívánt\nmegállókat és pontokat\na térképre kattintással. Set tile climate %s A terület %s éghajlatúra alakítása Show capacity and if halt is overcrowded Megállók kapacitását és terheltségét mutatja Show how many convoi reach a station Megmutatja, mennyi jármű érinti a megállókat Show how many people/much is waiting at halts Megmutatja, mennyi utas/áru vár a megállóban Show initial passenger departure Utasok kiindulási helyét mutatja Show level of city buildings Épületek utasforgalmát jeleníti meg Show mail service coverage/mail network Postai lefedettség és postaszállító hálózat megjelenítése Show passenger coverage/passenger network Utas lefedettség és utasszállító hálózat megjelenítése Show speedlimit of ways Sebességhatárok megjelenítése Show the change of waiting at halts Várakozók számának változása a múlt hónaphoz képest. Show the owenership of infrastructure Infrastruktúra tulajdonosainak mutatása Show transported freight/freight network Ãruszállítás és áruszállító hálózat megjelenítése Show usage of network A havi forgalom nagyságát mutatja minden mezÅ‘n Shows a listing with all industries on the map. Az összes gyártípust listázza Sum of departure/arrivals at halts ÉrkezÅ‘k/távozók száma összesen #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s újabb buszjáratot indított %s és %s (%i,%i) között. %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s újabb buszjáratott indított %s és %s (%i,%i) között. %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). A(z) %s a(z) %i számú kamiont %s (%i,%i) és %s (%i,%i) között üzemelteti. %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s új vasutat avatott \n%s (%i,%i) és \n%s (%i,%i) között Airline service by\n%s\nnow between\n%s \nand %s.\n %s által\nüzemeltetett légikapcsolatt\njött létre\n%s és %s\nközött Ferry service by\n%s\nnow between\n%s \nand %s.\n A %s kompjárat\n%s és %s között közlekedik.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Az utasok mostmár\n%s\nbuszait használják\n%s és\n%s között. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS SzerkesztÅ‘ eszközök LISTTOOLS Listák MAGLEVTOOLS Mágnesvasúti kellékek MONORAILTOOLS Nyeregvasúti kellékek NARROWGAUGETOOLS Keskeny nyomközű vasút kellékei RAILTOOLS Vasúti kellékek ROADTOOLS Közúti kellékek SHIPTOOLS Hajózás SLOPETOOLS Földformázás SPECIALTOOLS Speciális eszközök TRAMTOOLS Villamos kellékei #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s-n\n felépítettek a (%i,%i) cégközpontot. Factory chain extended\nfor %s near\n%s built with\n%i factories. A gazdaság megerÅ‘sÅ‘dött:\nA %s mely %s van közel, fejlÅ‘dik.\n%i új gyár lett alapítva. Net wealth less than 10%% of starting capital! A tÅ‘ke a kezdÅ‘tÅ‘ke 10%%-a alatt van! New %s now available:\n%s\n Új %s érhetÅ‘ el:\n%s.\n New factory chain\nfor %s near\n%s built with\n%i factories. Új termelési lánc épült %s, közel %s városához, %i kiszolgáló gyárral (termelési egységgel). New vehicle now available:\n%s\n Új jármű áll rendelkezésre:\n\n\n -- %s -- \n\n Now %u clients connected. %u kliens csatlakozott Remove vehicle from map. Use with care! A jármű eltávolítása a térképrÅ‘l. (Gondold meg!) Screenshot\ngespeichert.\n KépernyÅ‘ kimentve. Sends the convoi to the last depot it departed from! Visszaküldi a szerelvényt az utolsó garázsba, ahonnan indult. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Egy nagy fesztivál kíséretében %s új emlékművet épített. %i lakós igencsak elégedett az eredménnyel. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Vonal szűrÅ‘ #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) depóban [CTRL] Ctrl [END] End [HOME] Home \nBauzeit bis \nEltűnik: \nBauzeit von \nMegjelenik: \nCan't open heightfield file.\n Domborzatfájlt nem lehet megnyitni. \ndirection: \nirány \nelektrified \nvillamosított\n \nHeightfield has wrong image type.\n A domborzatfájl inkompatibilis képeket tartalmaz. \nis reserved by: \nfoglalja: \nminimum speed: \nminimum sebesség: \nnot elektrified \nnincs villamosítva\n \nRibi (masked) \nberendezések (lefedett): \nRibi (unmasked) \nberendezések\n(összes): \nSet phases: \nFázisváltás ideje mp-ben\nÉszak-Dél Kelet-Nyugat: \nsingle way \negyirányú út \nwith sign/signal\n \njellel/táblával \n %d buildings\n %d épület\n %d convois %d szerelvény %d Einzelfahrzeuge im Depot %d van %i km/h (max. %ikm/h) %i km/ó (max. %i km/ó) %i years %i months old. Kora: %i év és %i hónap %s building %s %s %s épület %s %s %s city %d %s %s város %d %s %s factory %s %s %s%s épület %s has entered a depot. %s depóba/dokkba érkezett. %s land %d %s %s föld %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s többlet költséget jelent %i számú lakosnál. %s\nis crowded. %s\n túlterhelt. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nseb. %i\nmax_seb. %i\ndx:%i dy:%i %s\nwas liquidated. %s\nfelszámolásra került. %u Client(s)\n %u klient\n %u Player (%u locked)\n %u játékos (%u lezárva)\n <új vonal készítése> 1 convoi 1 szerelvény 1 Einzelfahrzeug im Depot 1 jármű van 1LIGHT_CHOOSE Fényesség: 1WORLD_CHOOSE Új térkép beállításai: 2LIGHT_CHOOSE Színek száma: 2WORLD_CHOOSE Térképszám: 3LIGHT_CHOOSE Görgetés sebessége: 4LIGHT_CHOOSE Fordított görgetés 5LIGHT_CHOOSE Gyalogost megállóban mutat 5WORLD_CHOOSE Városok száma: 6LIGHT_CHOOSE Gyalogost városban mutat 6WORLD_CHOOSE Forgalom sűrűsége: 8WORLD_CHOOSE Éjszaka/nappal mód A bridge must start on a way! Híd csakis úton kezdÅ‘dhet! Abfrage Infó eszköz Abnehmer Fogyasztók: About Infó About scenario Copyright Abriss Töröl/Eltávolít Absenken Talaj süllyesztése Abspanntransformator Transzformátorállomás Accelerate time IdÅ‘ felgyorsítása Act. load: %u MW\n Terhelés: %u MW\n Active player only Csak az aktív játékos Add forest ErdÅ‘ hozzáadása Add random citycar Véletlenszerű kocsi elhelyezése Add Stop Hozzáadás Add stops for backward travel Megállók hozzáadása a visszaúthoz Aircraft Légiközlekedés aircraft_tab Teherszállítók airplane repülÅ‘gép Airport RepülÅ‘tér AIRTOOLS Légi kellékek All Mind Allow city growth Város növekedés engedélyezve Allow player change Játékosváltás engedélyezése allowed climates:\n megengedett klímatípusok:\n Alters a schedule. Megváltoztatja a menetrendet. Angenommene Waren Közeli ipartelepek szükségletei anhaengen Vontatmány Anhaenger_tab Vontatmányok Anheben Talaj emelése Appends stops at the end of the schedule Megálló hozzáadása a menetrend végéhez Apply Line Útvonal alkalmaz April Ãprilis Arbeiter aus: Munkások: Arrivals from\n ÉrkezÅ‘ járatok\n Arrived Érkezett Assets Tárgyi eszközök Aufloesen Felbont August Augusztus Autohalt muss auf\nStrasse liegen!\n Megálló csakis útra építhetÅ‘! Available Rendelkezésre állás Bahndepot Vasúti kocsiszin Bankrott:\n\nDu bist bankrott.\n CsÅ‘dbe jutottál. battery akkumulátor Baum Fa baum builder Faültetés Baustelle Építési terület Bauzeit Építési idÅ‘ Beenden Kilépés Beginner mode KezdÅ‘ színtű játékmód Besonderes Gebaeude Turistalátványosság BF p.u. bio biológiai Blockstrecke ist\nbelegt\n A vonalat már más vonat használja Boden Föld Bonusspeed: %i km/h Legnagyobb elérhetÅ‘ sebesség: %i km/h Boost (%%) Növekedés (%%) bridge is too high for its type! A híd túl magas a típusához képest! Bridge is too long for this type!\n Ilyen típusú hídat ilyen hosszúra nem lehet építeni! Bruecke Híd Bruecke muss an\neinfachem\nHang beginnen!\n A híd csakis egyenes emelkedÅ‘rÅ‘l indulhat! Brueckenboden hídalap Build air depot Légi depó építése build choosesignals JelzÅ‘berendezés építése Build city market Fogyasztó/ipari egység építése Build drain Trafóállomás építése build HQ Székhely építése Build land consumer HÅ‘erÅ‘mű építése Build maglev depot Mágnesvasúti depó építése Build monorail depot Nyeregvasút depó építése Build powerline Elektromos hálózat építése Build presignals Vasúti elÅ‘jelzÅ‘ építése Build road depot Közúti depó építése Build ship depot Hajódepó építése Build signals ForgalomjelzÅ‘ építése Build train depot Vasúti depó építése Build tram depot Villamos depó építése Build truck depot Kocsiszín építése Building costs estimates Építkezés költségeinek becslése Buildings Épületek Built artifical slopes Mesterséges töltés építése Built random attraction Véletlenszerű turista attrakció építése Bus_tab Buszok Can only move from halt to halt or waypoint to waypoint. Eltávolítás csak megállótól megállóig vagy szakaszponttól szakaszpontig lehetséges. Cancel Mégsem Capacity: Kapacitás Capacity: %.0f MW Kapacitás: %.0f MW\n Capacity: %d%s %s\n Kapacitás: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapacitás: %s \nKihasználtság: %d (%d%%) Cars are not available yet! Még nem áll rendelkezésre gépkocsi! Cash Számlaegyenleg Change player Játékos váltása Chart Grafikon Choose operation executed on clicking stored/new vehicles A műveletet a járműre kattintással lép működésbe chooses a random map Véletlenszerű térkép választása citicens Lakók City attraction Városi látványosságok City industries Ipari egységek (városban) City list Városok listája City size Város mérete city_road Városi út citybuilding builder Városi épületek építése CityLimit Városhatár cl_title Járműlista cl_txt_sort Szortírozás: Clear block reservation Mutasd/rejtsd a lefoglalt utat clf_chk_aircrafts RepülÅ‘gépek clf_chk_cars Közúti járművek clf_chk_indepot Garázsban clf_chk_maglev Mágnesvasút clf_chk_monorail Nyeregvasút clf_chk_name_filter Szűrés névre: clf_chk_narrowgauge Keskeny nyomközű vasút clf_chk_noincome Veszteséges clf_chk_noline Nincs vonal clf_chk_noroute Eltévedt clf_chk_noschedule Nincs menetrend clf_chk_obsolete Elavult clf_chk_ships Hajók clf_chk_spezial_filter Speciális szűrÅ‘: clf_chk_stucked Elakadt clf_chk_trains Vonatok clf_chk_trams Villamosok clf_chk_type_filter Szűrés típusra: clf_chk_waren Szűrés árukra: clf_title Járműlista filter Climate Control Éghajlati beállítások COLOR_CHOOSE\n Válassz színt: Company bankrupt A cég csÅ‘dbement! Company_msg Versenytársak Comparing pak files ... Pak fájlok összehasonlítása... Congratulation\nScenario was complete in\n%i months %i years. Gratulálunk!\n A forgatókönyv %i hónap\nés %i év alatt lett végigjátszva. Connected stops Csatlakozó megállók: Connections Kapcsolatok Constructed by Rajzolta: Constructed by %s Rajzolta: %s Construction_Btn Építkezések Consumed Felhasznált convoi %d of %d %d./%d szerelvény Convoi following mode Járműkövetés módja Convoi has been sent\nto the nearest depot\nof appropriate type.\n A szerelvényt\na legközelebbi alkalmas\ngarázsba küldtük. Convoi is sold when all wagons are empty. A járművet eladjuk, amint teljesen kiürült. convoi passed last\nmonth %i\n \nmúlt hónapban áthaladt\njárművek száma: %i\n Convois Szerelvények Convois: %d\nProfit: %s Járművek: %d Profit: %s Convoys Szerelvények Copy Convoi Szerelvény másolása Copy the selected convoi and its schedule or line MegkettÅ‘zi a kiválasztott szerelvényt és menetrendjét/vonalát Copy to clipboard Másolás a vágólapra cost for removal Törlés díja Cost: %8s (%.2f$/km)\n Ãr: %8s (%.2f$/km)\n Costs Ãrak Create a new line based on this schedule Új vonal készítése a jelenlegi menetrend alapján curiosity builder Látványosság építése curlist_title Turistalátványosságok listája Currently playing: Most szól: Customers live in: Vásárlók itt élnek: Date format Dátumformátum Deccelerate time IdÅ‘ lelassítása Del Stop Törlés Delete Line Törlés Delete the current stop A kiválasztott megálló törlése Delete the selected line (if without associated convois). A vonal törölhetÅ‘ (ha nem használja jármű) Delete this file. Fájl törlése. Delivered Szállítva Demand Igény Demand: %.0f MW Igény: %.0f MW\n Denkmal Látványosság Departed Távozott Departure board Menetrendi kijelzÅ‘ Departures to\n Induló járatok Depots Garázsok Der Tunnel ist nicht frei!\n Az alagút nem szabad!\n Destination Célállomás Details Részletek Die Bruecke ist nicht frei!\n A híd nem üres! diesel dízel Direkt erreichbare Haltestellen Közvetlenül elérhetÅ‘ célok disable midi MIDI zene kikapcsolása Display settings KépernyÅ‘ beállítások Distance Távolság Dock Dokk Dock must be built on single slope! A dokk csak lejtÅ‘s (ferde)\npart mentén építhetÅ‘!\n dp_title Garázsok listája Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Még %d hónap maradt a tartozás viszafizetéséig! Durchsatz Max. Economy Gazdaság és városok Eigenbesitz\n Köztulajdon:\n Ein %s\npasst hier nicht.\n A '%s' nem fér ide! Einstellungen aendern Beállítások electric villamos Electricity Ãram Electricity producer\n\n VillanytermelÅ‘\n\n Electrics_tab Elektromos járművek Electrify track Vágányok villamosítása enlarge map Térkép nagyítása enter a value between %i and %i adj egy értéket %i és %i között Enter Password Játékosnév és jelszó módosítása Error Hiba Erzeuge neue Karte.\n Kis türelmet míg az új \ntérkép elkészül. (Nagy \ntérképek esetén ez \npercekbe is telhet.) Es wird bereits\nein Fahrplan\neingegeben\n Egy menetrend meghatározása már folyamatban van. Fejezd be elÅ‘bb azt! Fabrikanschluss Kapcsolódó ipar Fabrikname Gyárnév Factories Gyárak factory details Term./fogy. infó factorybuilder Gyárak építése Fahrplan Menetrend Fahrtziel Úticél: Fahrzeuge koennen so nicht entfernt werden A jármű nem távolítható el ilyen módon! Fahrzeuge: Járművek: Farbe Játékos színe Fast forward IdÅ‘gyorsítás February Február Ferry_tab Kompok Fertig Kész Filename Fájlnév: Files from: Fájlok itt: Filter: Szűrés: Finances of %s %s pénzügyei Finanzen Pénzügyek find mismatch Pakok összevetése fl_title TermelÅ‘egységek listája Flug_tab Utasszállítók follow me Követés Follow the convoi on the map. Kövesd a szerelvényt a térképen font size Betűméret Forest ErdÅ‘ Found new city Új város alapítása Fracht Rakomány Frame time: Képfrissítés: Free Capacity Szabad kapac. freeplay mode Szabad játékmód Friction: Pillanatnyi súrlódás: fuel_cell üzemanyagcella Full load Min. telítettség Fussgaenger gyalogos Game info Online játék GAME PAUSED Játék megállítva Game_msg Ãltalános Gear: Ãttétel: Gebaeude Épület General Ãltalános Generated Keletkezett Generation: %.0f MW Termelés: %.0f MW\n Gewicht Súly Gewinn Bevétel: Give the selected vehicle(s) an individual schedule A járműhöz rendelt vonal vagy egyedi menetrend megadása gl_btn_sort_catg Kategória gl_title Ãruk listája go home Garázsba Goods Ãruk Goods list Ãruk listája Gross Profit Végösszeg Grow city Város növelése Growth Növekedés GUI settings KezelÅ‘felület H megálló Hangar Hangár Happy Elégedett Haus kaufen Épület vásárlása Helligk. KépernyÅ‘ Help Súgó Help text not found Súgó fájl nem található hide all building Összes épület elrejtése hide city building Városi épületek elrejtése hide station names Megállók nevének elrejtése hide transparent Ãtlátszó terep hide trees Fák elrejtése Hier warten/lagern: Várakozó áruk és utasok: Higher transport fees, crossconnect all factories Magasabb fuvardíjak, raktárkorlát kikapcsolása Highlite schedule Megállók kiemelése hl_title Ãllomások/megállók listája hl_txt_filter Filter: hl_txt_sort Rendezési elv: hlf_chk_airport RepülÅ‘tér hlf_chk_anleger Dokk hlf_chk_bahnhof Vasútállomás hlf_chk_bushalt Buszmegálló hlf_chk_frachthof Rakodóudvar hlf_chk_keine_verb Nincs kapcsolat hlf_chk_maglevstop Mágnesvasúti megálló hlf_chk_monorailstop Nyeregvasúti megálló hlf_chk_name_filter Szűrés névre: hlf_chk_narrowgaugestop Keskenyvasúti megálló hlf_chk_overflow Túlzsúfolt hlf_chk_spezial_filter Speciális szűrÅ‘: hlf_chk_tramstop Villamosmegálló hlf_chk_type_filter Szűrés típusra: hlf_chk_waren_abgabe KimenÅ‘ áruk: hlf_chk_waren_annahme BemenÅ‘ áruk: hlf_title Ãllomás/megálló filter Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depó nem található! A depót manuálisan kell kijelölni. Homeless Hajléktalan hydrogene hidrogén Idle: Üresjárat: ignore climates Klimaövezetek ignorálása In Transit Érkezik Increase Industry density Iparsűrűség növelése industrial building Ipari épület Industry overlay Gyárak állapota Init map ... Térkép elÅ‘készítése ... Input Bemenet Ins Stop Beszúrás Insert stop before the current stop Megálló beszúrása a kiválasztott elé Intercity road len: Városközi utak hossza: Intro. date: Megjelenés: Invalid coordinate Nem valós útvonal! isometric map izometrikus térkép January Január join game Online játék July Július Jump to Ugrás June Június Kann Spielstand\nnicht laden.\n Nem tudom megnyitni a fájlt! Kann Spielstand\nnicht speichern.\n Nem lehet felülírni a fájlt! Kein Besitzer\n Köztulajdon\n keine nincs Keine Einzelfahrzeuge im Depot Nincs jármű Keyboard_Help\n Billentyűzet segítség koord Koordináták Kreuzung keresztezés/keresztezÅ‘dés labellist_title JelzÅ‘táblák listája Lade Relief Domborzat betöltése Laden Betöltés Land attraction Terep látványosságok Land industries Ipari egységek LANG_CHOOSE\n Válasz nyelvet: Last Month Múlt hónap: Last Year Múlt év: Leaving depot! Elhagyja a depót! leer üres Legend Jelmagyarázat Leistung Teljesítmény Leistung: %d kW Teljesítmény: %d kW Leitung vezeték letzen Monat: diesen Monat: múlt hónap: e hónap: Line Vonal Line Management Vonalak kezelése Lineless convoys serving this stop Vonal nélküli járművek Lines serving this stop Megállót kiszolgáló vonalak LKW_tab Teherautók Load game Játék betöltése load height data from file Terepadatok betöltése Load scenario Forg.könyv betölt loaded berakodva loaded passenger/freight Utas/áru rendezése eszerint: Loading (%i->%i%%)! Rakodás (%i->%i%%) Loading addon paks ... Pak fájl betöltése ... Loading map ... Térkép betöltése Loading paks ... Pakok betöltése... Loading skins ... Kinézetek betöltése... Lock game Játék zárolása Lokomotive_tab Mozdonyok Maglev Mágnesvasút maglev vehicle Mágnesvasúti jármű maglev_track Mágnesvasúti pálya Maglevdepot Mágnesvasúti depó Mailbox Postaláda Mailbox Options Üzenetek beállításai Maintenance Karbantartás Manufactured: Gyártási idÅ‘: Map roughness Terepdurvaság: map view Térkép map zoom méretarány March Március Margin (%%) Ãrrés (%%) Marker JelzÅ‘tábla Max Boost (%%) Max növekedés(%%) Max income: Maximális bevétel: Max. speed: Max. sebesség: Maximum 254 stops\nin a schedule!\n Maximum 254 megálló engedélyezett! maximum length of rivers Folyók maximális hossza Maximum tile height difference reached. A két szomszédos \nterület \nmagasságkülönbsége \nnagyobb mint \na megengedett! Maxspeed Max. sebesség May Május Median Citizen per town Ãtlagos népesség városonként: Meldung Üzenet Menge Mennyiség MessageOptionsText \nÚj év\n\nJátékoshírek\n\nVárosi hírek\n\nNincs út\n\nÚj úticélok\n\nChat\n\nÚj járművek\n\nÃllomás tele\n\nProblémák\n\nDugók\n\nForg.könyv minimum length of rivers Folyók minimális hossza Missing pakfiles Elemek hiányoznak! Modify the selected line Kiválasztott útvonal módosítása Monate alt hónapos Monorail Nyeregvasút monorail vehicle Nyeregvasúti jármű monorail_track Nyeregvasúti pálya Monorailboden Nyeregvasút alap Monoraildepot Nyeregvasút depó month wait time Max. hó várakozás Months Hónap Monument Emlékmű Monuments Emlékművek Mountain height Hegymagasság: Music playing disabled/not available Zenelejátszás kikapcsolva Music volume: Zene hangerÅ‘: mute sound Hang némítása Name Név Narrowgauge Keskeny nyomközű vasút Narrowgauge are not available yet! A keskeny nyomtávú vasút nem érhetÅ‘ még el! narrowgauge_track Metro/ HÈV vágányok Narrowgaugedepot Depot HÉVnek/ Metronak Net ID: %p Azonosító: %p\n Net Wealth TÅ‘ke Net wealth near zero A tÅ‘ke nullához közelít Neue Karte Új térkép Neue Welt Új térkép new convoi Új szerelvény New Line Új vonal New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Az új útvonal kész! Hozzárendelheted az útvonal szelektorral New Vehicles Új járművek Nickname: Becenév: no buildings hidden Épületek mutatása no convois Nincs szerelvény No goods are loaded onto this convoi. Nem rakodnak új árut a szerelvényre no goods waiting nincs várakozó áru/utas no load Csak kirakodás No Route Nincs útvonal No stop here! Csak megállókon használható! No suitable ground! Nem megfelelÅ‘ talaj! No terminal station here! Ide nem lehet építeni megállót! no timeline IdÅ‘vonal kikapcsolva no tree Fák elrejtése No. of Factories Gyárak és üzletek: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Egyszer definiálj menetrendet! none semmi nord Észak nordost Északkelet nordwest Északnyugat Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Tilos! A menetrendet ilyenkor nem lehet megváltoztatni Próbáld késÅ‘bb! Not enough fields would remain. A farm körül nem marad elég szabad terület! Now active as %s.\n Most "%s" játékosként folytatódik a játék. Number of rivers Folyók száma Object Objektum Odometer: %s km Megtett út: %s km Ok Rendben Oktober Október On loan since %i month(s) A kölcsön %i hónapja indult! On this map, you are not\nallowed to change player!\n Ezen a térképen a játékosváltás nem engedélyezett! Only city chains Csak városi láncolat! Only full Unicode fonts Csak teljes Unicode betűkészletek Only land chains Csak terep láncolat! Only one transformer per factory! Csak egy trafóállomást lehet építeni gyáranként! Operation Működési költségek Ops Profit Működési nyereség Optionen Beállítások Or enter a server manually: Vagy adj meg egyet kézzel: Origin Kiindulás ost Kelet Output Kimenet Ownership Tulajdonos paletten raklap Pas_tab Személyvonatok Passagiere Utas Passagierrate Utasforgalom Passagierziele Utas/levél célállomás Passengers %d %c, %d %c, %d no route Az utasoknak %d %c, %d %c, %d nincs útvonala Passengers %d %s, %d %s, %d no route Az utasoknak %d %s, %d %s, %d nincs útvonala Password Jelszó: Pause Megállítás/folytatás Pax <%i> Mail <%i> Utasok <%i> Levél <%i> PaxDest Célállomás Percent Electricity Százalék villamosság Planes are not available yet! Még nem áll rendelkezésre repülÅ‘gép! Plant tree Faültetés player Játékos player -1 Énmagam :-). player 0 Nullusz Kft. player 1 Amata Transz Kft. player 2 SündörgÅ‘ Speed Bt. player 3 Mávocska Rt. player 4 Pihe Transz Kft. player 5 Lubisz Speed Rt. player 6 Fakerék Transz Rt. Please choose vehicles first\n Egyszer válasz járművet! Post Küldemény Postrate Posta forgalom Power Teljesítmény Power (MW) Teljesítmény(MW) Power: Teljesítmény: Power: %4d kW\n Teljesítmény: %4d kW\n Powerlines Elektr. hálóz. Price Ãr Problems_msg Problémák Produced Termelve Production of %s has been stopped:\n%s\n A %s gyártása leállt:\n%s.\n Production/Boost Termelés/Növekedés Produktion Termelés promote to line Új útvonal q1 Tavasz q2 Nyár q3 Åsz q4 Tél Query server Lekérdezés rail car Vasúti kocsi random Véletlenszerű Random age Véletlenszerű kor Random map Véletlen térkép Rathaus Városháza Rating Terheltség ratio_pax Utas %% Relevant Érdemleges Reliefkarte Térkép Remove JelzÅ‘tábla törlése remove airstrips Kifutó-/gurulópálya elbontása remove channels Csatorna elbontása remove interm. signals Köztes jelzÅ‘k törlése remove maglev tracks Mágnesvasút elbontása remove monorails Nyeregvasút elbontása remove narrowgauge tracks Keskeny nyomközű vágány elbontása remove powerlines Elektromos vezeték elbontása remove roads Út elbontása remove tracks Sín elbontása Remove wayobj %s FelsÅ‘vezeték elbontása %sról replace other signals Többi jelzÅ‘ cseréje replace stop Megállócsere residential house Lakóház Restore natural slope Terepviszonyok visszaállítása Restwert: Eladási ár: Retire. date: Kifutás: return ticket Visszaút Revenue Ãrbevétel Revision: Revízió: road út road vehicle Közúti kocsi Roadsign közúti jelzÅ‘tábla Rotate map Térkép forgatása Rotation Forgatás sack zsák(ok) sail szél Saving map ... Térkép mentése... Scenario complete: %i%% Forgatóköny befejezve:%i%% Schedule changing! Menetrend megváltozik! Schienentunnel Vasúti alagút építése Schiff_tab Teherhajók Schiffdepot Hajó dokk Schleppkahn_tab Uszályok Screenshot KépernyÅ‘mentés Seasons Évszakok Sehenswuerdigkeit Látványosság Select a server to join: Válassz kiszolgálót, amihez csatlakoznál: Select a theme for display Megjelenési téma választása Select display font Betűtípus kiválasztása Sell the selected vehicle(s) A kiválasztott járművet/járműveket elad sended Küldemény SEP_FRACTION , September Szeptember Server did not respond! A kiszolgáló nem válaszolt! Serves Line: Kiszolg. vonal: Service Kiszolgálás set signal spacing JelzÅ‘távolság beállítása Setting Beállítások Ship Hajó shops and stores üzletek és irodák Show all Mindent mutat show all building Minden épületet mutat Show also vehicles no longer in production. A már nem gyártott járműveket is megjeleníti. Show also vehicles that do not match for current action. Mutassa azokat a járműveket is amelyek nem vesznek részt a műveletben. Show contour Domborzat mutatása Show finances for transport type Csak ezen járműtípus pénzügyei: show grid Tereprács mutatása Show industry Ipar mutatása Show legend Jelmagyarázat Show map scale Színkódok Show mismatched EltérÅ‘k mutatása Show networks Hálózatok mutatása Show obsolete Elavult járművek Show offline Offline lévÅ‘k mutatása Show schedules Menetrend mutat Show servers that are offline Az épp nem kapcsolódó kiszolgálókat is mutatja Show servers where game version or pakset does not match your client Az olyan kiszolgálókat is mutatja, ahol a játék verziója vagy a pakset eltér a te kliensedétÅ‘l show station coverage Ãllomás hatókör mutatása show station names Megállónevet mutat show waiting bars Terhelési csík mutatása Show/hide statistics Mutat/rejt statiszt. Shows consumer/suppliers for factories A fogyasztók / ellátók mutatása a termelÅ‘ egységeknél Shows the color code for several selections. Számos kiválasztásnál alkalmazott színkódok mutatása. Shows the currently selected schedule Jelenlegi menetrend mutatása Shrink city Város csökkentése shuffle midis Véletlenszerű lejátszás signal spacing JelzÅ‘távolság Sim: Szimuláció: Similar view as the main window A fÅ‘ablakéhoz hasonló nézet Size (%d MB): Méret (%d MB): sliced underground mode MetróépítÅ‘ mód rétegei slot empty üres hely Smart hide objects Épületek elrejtése Sort by Szortírozta Sort waiting list by Rendezés eszerint: Sound Hang Sound settings Hangbeállítások Sound volume: Effektus hangerÅ‘: special freight különleges áru Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Sebesség bónusz: \nközút %i km/ó, vasút %i km/ó \nhajó %i km/ó, repülÅ‘ %i km/ó. Speedlimit Sebességkorlát Speichern Mentés Spieler Játékos Spieler(mz) Játékosok Spielerliste Játékosok listája Spielstand wurde\ngeladen!\n Játék sikeresen betöltve! Spielstand wurde\ngespeichert!\n Játék sikeresen mentve! Sprache Nyelv Sprachen Nyelv kiválasztás: Stadtinformation Város statisztikák Start the selected vehicle(s) A kiválasztott jármű(vek) indítása Starte Spiel Játék indítása Station tiles: Ãllomáshosszúság: Station_msg Megállók Status Státusz steam gÅ‘z Step timeline one year Egy év ugrás Stops Megállók Storage Tárolva Storage capacity Tároló kapacitás Strassendepot Kocsiszin Strassentunnel Közúti alagút építése street car Utcai kocsi sued Dél suedost Délkelet suedwest Délnyugat Summer snowline Nyári hóhatár Supplied: %.0f %% Ellátás: %.0f %% Suppliers Beszállítók: Tage alt napos Theme selector Témaválasztó There are still vehicles\nstored in this depot!\n Még van jármű a depóba! This Month Folyó hónap: This Year Folyó év: Tile not empty. A terep nem üres! Terep megváltoztatása nem lehetséges. timeline IdÅ‘vonal bekapcsolva tl_title Városok listája To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Több turista kegyeinek\n elnyeréséért \n%s városa épített \negy %s nevű \nturista látványosságot \n%i lakosok segítségével. To heavy traffic\nresults in traffic jam.\n A nagy forgalom forgalmi dugót okoz. tonnen t Toolbar position: Eszköztár helye: Total inhabitants: Teljes népesség: Tourist attractions Turistalátványosságok: Tourists Turisták Town_msg Városok Town: %s\n Város: %s\n Towns Városok track vágány Tracks Vasutak Traffic Forgalom traffic settings Forgalom Train Vonat Trains are not available yet! Még nem áll rendelkezésre vonat! Tram Villamos tram_track villamos vágány Tramdepot Villamos kocsiszin Trams are not available yet! Még nem áll rendelkezésre villamos! Transformer only next to factory! Trafó csak termelÅ‘egység mellé telepíthetÅ‘! Translation Fordítás transparencies Ãtlátszóság transparent station coverage Ãtlátszó állomás hatókör Transported Szállítmányok TrolleyBus_tab Trolibuszok Truck Közúti jármű tt_Other Egyebek Tunnel muss an\neinfachem\nHang beginnen!\n Az alagút csakis egyenes emelkedÅ‘n építhetÅ‘! Tunnel must start on single way! Alagút csakis úton kezdÅ‘dhet Tunnelboden Alagút underground mode MetróépítÅ‘ mód UNDO failed! A visszavonás nem lehetséges! \nAz útépítés csak \naddig vonható vissza, \namíg nem építesz kapcsolódó \nlétesítményt (jelzÅ‘táblát, \n állomást, megállót).\n Undo last ways construction Utolsó útvonal visszaállítása Unemployed Munkanélküli Unhappy Elégedetlen units/day egység/nap Update Line Szerkesztés upgrade HQ Központ fejleszt. Usage: %.0f %% Felhasználva: %.0f %% Usage/Output Felhasz./kimenet Use beginner mode KezdÅ‘ mód használata Use timeline start year IdÅ‘vonal be KezdÅ‘ év: Vehicle %s can't find a route! %s nem találja az útat! Vehicle %s is stucked! A %s \njármű dugóba \nkerült (beragadt).\n Vehicle details A jármű adatai vehicles stored Tárolt járművek Verbrauch Felhasználás: Vergroessere die Karte\n Térkép nagyítása Verkauf Eltüntetés verkaufen Eladható Verkehrsteilnehmer Magánautó Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Eladósodtál! %d hónapod van a visszafizetésre! vh_title Minden jármű listája via keresztül (részletesen) via %s\n át %s\n via Menge keresztül (összesen) voranstellen Vontató Waggon_tab Vagonok waiting várakozik Waiting for clearance! Várakozás a szabad útra! Walked Gyalog Warnings_msg Forgalom Water level Tengervíz szintje: water vehicle Vizi jármű way %s cannot longer used:\n %s típúsú út többé már nem elérhatÅ‘\n way %s cannot longer used:\n%s\n %s típúsú út többé már nem elérhatÅ‘:\n%s\n way %s now available:\n %s típúsú út már elérhatÅ‘:\n Ways not connected Az útvonal nincs összekötve waytype Úttípus Wegpunkt Várakozópont Weight: Súly: Wert Érték west Nyugat Winter snowline Téli hóhatár withdraw Selejtezés Withdraw All Összes eladása WRONGSAVE Inkompatibilis verzió Fájl betöltése nem lehetséges. Year %i has started. Az %i év elkezdÅ‘dött Years Év Your primary color: ElsÅ‘dleges szín Your secondary color: Másodlagos szín Zielort Célállomás zooming in Nagyítás zooming out Kicsinyítés Zu nah am Kartenrand A térkép széle túl\közel van ahhoz, hogy építeni lehessen! #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Lebegés mágneseken \n%.1f km/h-val, %s által:\nÚj világrekord! New world record for monorails: %.1f km/h by %s. Nyeregvasútak új sebességi világrekordja: %.1f km/h - %s. New world record for motorcars: %.1f km/h by %s. Gépkocsik új sebeségi világrekordja: %.1f km/h - %s. New world record for narrowgauges: %.1f km/h by %s. Új villágrekord metronak/HÉVnek: %.1f km/h by %s. New world record for planes: %.1f km/h by %s. RepülÅ‘gépek új sebességi világrekordja: %.1f km/h - %s. New world record for railways: %.1f km/h by %s. Vonatok új sebességi világrekordja: %.1f km/h - %s. New world record for ship: %.1f km/h by %s. Vizijárművek új sebességi világrekordja: %.1f km/h - %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL hátság &2_CITY_SYLL falva &3_CITY_SYLL szeg &4_CITY_SYLL varsány &5_CITY_SYLL keszi &6_CITY_SYLL füred &7_CITY_SYLL mezÅ‘ &8_CITY_SYLL hegyi &9_CITY_SYLL keresztúr &A_CITY_SYLL határ %1_CITY_SYLL Duna %2_CITY_SYLL Tisza %3_CITY_SYLL Maros %4_CITY_SYLL Dráva %5_CITY_SYLL Száva %6_CITY_SYLL Olt %7_CITY_SYLL Ipoly %8_CITY_SYLL KÅ‘rös %9_CITY_SYLL Szamos %A_CITY_SYLL Ó %B_CITY_SYLL domb 1center %s %s 1extern %s elágazás %s 1suburb %s %s %s 2center %s központi %s 2extern %s felsÅ‘ %s 2suburb %s zöldmezÅ‘k %s %s 3center %s fÅ‘ %s 3extern %s határ %s 3suburb %s lakótelep %s %s 4center %s mellék %s 4extern %s külsÅ‘ %s 4suburb %s vidék % 5center %s átszálló %s 5suburb %s falu %s 6center %s központ %s 6extern %s alsó %s 6suburb %s külváros %s %s 7center %s város %s\n 7extern %s külterület %s 7suburb %s park %s 8center %s üzleti %s 8extern %s %s szélsÅ‘ %s 8suburb %s szatelit %s 9center %s tengely %s 9extern %s híd %s 9suburb %s közbülsÅ‘ %s Acenter %s sétány %s Bcenter %s belváros %s Ccenter %s centrum %s simutrans-124.3/simutrans/text/hu/000077500000000000000000000000001474050137200172005ustar00rootroot00000000000000simutrans-124.3/simutrans/text/hu/citylist_filter.txt000066400000000000000000000004121474050137200231470ustar00rootroot00000000000000Városok listája Sugó

Városok listája

Itt egy helyen jelennek meg a városok. Jelezve van a város mérete (lakosszámban) illetve, hogy épp mennyivel fejlõdõtt.

-> Város statisztikák

simutrans-124.3/simutrans/text/hu/citywindow.txt000066400000000000000000000010631474050137200221410ustar00rootroot00000000000000Város statisztikák Sugó

Város statisztikák

Itt lehet a városról infókat szerezni. Kijelzi a város méretét (lakosszámban kell érteni), munkanélkülieket, hajléktalanokat stb.

A két kis térképen nyomonkövetheted az e havi és múlt havi szállítmányozási célállomásokat.

A grafikon pedig segít követni a városlakok számának változását, a város növekedését stb. (értelemszerûen válaszd ki a grafikon alatt lávõ gombokat, aktiváld õket és voila meglesz a grafikon :) )

simutrans-124.3/simutrans/text/hu/color.txt000066400000000000000000000006151474050137200210610ustar00rootroot00000000000000Saját színed

Színválasztó

Itt tudod a saját színedet kiválasztani. Evvel lesznek az összes általad birtokolt javak, vonatok, kocsik, épületek stb. megjelenítve. De ne feledd nem minden épületnek és/vagy jármûnek változik meg a színe, ezt többnyire a tervezõ határozza meg (tudniillik ez egy több emberke álltal fejlesztett játék :-)).

simutrans-124.3/simutrans/text/hu/convoi.txt000066400000000000000000000013121474050137200212330ustar00rootroot00000000000000Jármûlista Sugó

Jármûlista

A következõ beállítások lehetségesek:

1.) Szortírozás:
Lehetõség van a kilistázott jármûvek szortírozására "Név", "Bevétel" vagy "Típus" szerint illetve az így kapott lista a jármûvek betétele függvényében növekvõ, vagy csökkenõ sorrendbe rakható.

2.) Filter:
A kilistázott jármûvekre filtereket is alkalmazhatsz. Vagyis a jármûvek egyedi kritériumok alapján is listázhatóak. A filtereket engedélyezni kell.

->Segédlet a filterek használatához

->Ãltlános információk

simutrans-124.3/simutrans/text/hu/convoi_filter.txt000066400000000000000000000027121474050137200226050ustar00rootroot00000000000000Jármûlista filter Sugó

Jármûlista filter

Beállítási lehetõségek:

1.) Filter neve:
A filtereket el lehet nevezni.

2.) Filter tipusa:
Jármûcsoportonként lehet választani. A jármûcsoportok melleti kis gombocskát megnyomva lehet aktiválni a kívánt filtert.

3.) Speciális filter:
Itt lehet a speciális igényeket kiválasztani. Az eltéved jármûveket (vagy a depóban lévõket) itt nagyon könnyen meg tudod találni. Eltévedt jármû az a jármû amelyik nem kapja az útvonalát. Ennek több oka lehet: vagy az történt, hogy építkezéseid során egy kapcsolódási pontot megszüntettél, vagy pont egy olyan állomást töröltél ahova a kérdéses jármû épp indulni készült. Utóbbi esetben ellenõrizd le a jármû menetrendjét vagy a hozzá rendelt vonalat.

4.) Javak filtere:
Itt lehet még jobban szûkíteni a kersett jármûvek listáját. A javak kiválasztásával csak azok a jármûvek jelennek meg amelyek az általad kiválasztott javakat szállítják. A "mind" gombbal a teljes javak listája kiválasztódik, a "semmi" mindent töröl, a "ford." az aktuális kiválasztást megfordítja.

->Kis segédlet a konvojokról

->Ãltalános információk

simutrans-124.3/simutrans/text/hu/depot.txt000066400000000000000000000066171474050137200210660ustar00rootroot00000000000000Közúti\vasúti\hajózási kocsiszin\dokk Sugó

Kocsiszin\dokk ablak

A kocsiszinben lehetõség van különbözõ típusú jármûvek vásárlására, eladására,menetrendek összeállítására.

A kocsiszin ablak megmutatja a vásárolt jármûveket, illetve, hogy miket lehet még vásárolni. A jármûvek különbözõ kategoriákban vannak osztva. Ezt a különbözõ füleken olvashatód le. Tulajdonképpen ez a depó lelke. Itt található az összes jármû. A felsõ részen ellenben a már kész összeállított konvojok között tudsz navigálni. Illetve ugyancsak a fenti legördülõ menük egyikében az útvonalak között barangolhatsz. A felsõ részen látható a már összeállított szerelvény. Több típus is összekapcsolható ha ez megengedett. Ha nem kapcsolható össze akkor azt egy vörös vonal jelzi a jármû alatt. A jobb alsó gomb segítségével állítható be a konvojok össszeállítási módja: "Hozzáad", "Elé rak", "Eladási mód"
Hozzáad - egymás után kapcsolódnak össze a jármûvek
Elé rak - az új jármû a régi elejébe kerül
Eladási mód - a depóban lévõ jármûveket így lehet eladni, tehát nem a konvojokat hanem a már szétbontott és depóban lévõ külön jármûveket. Az, hogy a depóban van-e jármû a bal alsó részen látható.

Az alsó részhez közel az aktuális jármûrõl találhatóak meg a legfontosabb paraméterek (ára, fentartási költsége, mit szállít, csúcssebesség, kapacitás stb.). A felsõ részen 8 menûgomb található.

A Start gombbal lehet a készen összeállított konvojt elindítani, de csak akkor ha a "Menetrend" vagy "Új vonal" menûgomb alatt már készítettél egy menetrendet vagy új vonalat. Az új vonalat "Útvonalat alkalmaz" gombal társítod a konvojhoz. A Menetrend és Vonal között az a különbség, hogy míg a Menetrend csak az adott jármûre érvényes, addig a Vonalat más jármû is használhatja párhuzamosan. Vagyis ugyanazt a vonalat nagyon sok jármû is használhatja és a Vonalon történõ változtatás minden az illetõ Vonalat használó jármûre kihat. A "Szétbont" gombbal az aktuális konvojt bontod fel, de a pénzedet nem kapod vissza. Ilyenkor ahhoz, hogy eladd a jármûveket, a jobb alsó gombot kell Eladási mód-ra változtatni majd a megfelelõ jármûre kattintva eladni. Az egész konvojt egyszerre eladni az "Elad" gombbal lehet.

Vásárláshoz elég ha a bal egérgombbal ráklikkelsz a megfelelõ jármûre. A konvoj tetszés szerintí összeállításához, a kiválasztott jármûveket sorba kell rakni. Nem akármelyék jármû rakható a másik után. Azt hogy elé/utána rakja-e a következõ jármûvet, a jobb alsó részhez közel lévõ kapcsológombbal határozod meg.Csakis egy konvojon dolgozhatsz egyszerre!

A már mûködõ konvoj újbóli kocsiszinbe küldéséhez, a jármû ablakában a "Depóba" gombra kell kattintani, vagy kézzel kell változtatni a menetrenden. Figyelem! A villanyal mûködõ jármûvek csakis a vágányok villamosítása után jelennek meg. Az Elavult jármûvek gombbal lehet szabályozni azt, hogy a depó mutassa-e vagy sem a régi jármûveket.

simutrans-124.3/simutrans/text/hu/display.txt000066400000000000000000000022401474050137200214040ustar00rootroot00000000000000Képernyõ beállítások Sugó

Képernyõ beállítások

Itt tudod a Simutrans megjelenítésével kapcsolatos beállításokat elvégezni.
A következõ dolgokat tudod állítani:

Fényesség - Sötétítí világosítja a képernyõt (- irányba sötétedik).
Színek száma - Nem mûködik
Görg. sebes. - A képernyõ görgetési sebességét lehet szabályozni (a nagyobb gyorsabb).

Fordított görgetés - A képernyõ görgetési irányának a megfordítása
Gyalogost megáll. mutat - Mutatja/elrejti a gyalogosokat a megállókban. Ha a géped egy kicsit lassú kapcsold ki.
Gyalogost városb. mutat - Mutatja/elrejti a gyalogosokat a városokban. Ha a géped egy kicsit lassú kapcsold ki.
Éjszaka/nappal mód - Mutatja a nappalt és az éjszakákat. Elég érdekes effektus, fõleg az éjszaka.

Az ablak alsó részén, a játék szempontjából lényegtelen információk találhatók. Ellenben ha valami hiba van és netán levelezni fogsz a fejlesztõkkel, akkor valoszínû errõl fognak egy pár dolgot kérdezni.

simutrans-124.3/simutrans/text/hu/edittools.txt000066400000000000000000000023401474050137200217460ustar00rootroot00000000000000Szerkesztõ eszközök Sugó

Szerkesztõ eszközök


Város növelése: egyszer kiválasztod a megfelelõ várost, megkeresed a Városházát majd ráklikkelsz. Egy klikkelés +100 lakost add hozzá a város aktuális lakósszámához.

Város csökkentése: egyszer kiválasztod a megfelelõ várost, megkeresed a Városházát majd ráklikkelsz. Egy klikkelés -100 lakost vesz el a város aktuális lakósszámából.

Városi út építése: 50 km/h sebességû utakat tudsz építeni.

Véletlenszerû turista attrakció építése: véletlenszerûen turista attrakciókat épít, így növelheted az utasforgalmat.

Hõerõmû építése: ha a meglévõ hõerõmûveid nem tudják kielégíteni az energia igényeidet akkor ezzel az eszközzel újabb hõerõmûveket építhetsz. A játék a hõerõmûhõz automatikusan szénbányákat is generál.

Fogyasztó/ipari egység építése: evvel az eszközzel tudsz új ipari egységeket építeni.

Játék zárolása: evvel az eszközzel megakadájozhatod azt, hogy a térképen módosítani lehessen.

simutrans-124.3/simutrans/text/hu/finances.txt000066400000000000000000000032731474050137200215340ustar00rootroot00000000000000Pénzügyek Sugó

Pénzügyek (f)

Itt tudod a gazdasági helyzetedet ellenõrizni. Leellenõrizhetõ a nyereség, veszteség a gazdasági hálózatod fentartási költsége és minden egyéb a játék szempotntjából hasznos információ.
Több kategoriában tudsz információkat kinyerni grafikus és számszerû adatok formájában. Fel vannak tüntetve az ez évi és múlt évi adatok is.

A következõ adatinformációk állank rendelkezésedre:

Ãrbevétel - Minden ami hasznot hoz.

Munkálatok - Minden költség amit építkezésre, hálozatfejlesztésre költöttél.

Karbantartás - Minden karbantartás igénylõ munkálat összegzése.

Üzleti eredmény - Bevételek összegzése.

Új jármû - Új jármûvekre költött pénzösszeg.

Építkezés - Építkezésre költött pénzösszegek összegzése.

Össz profit - Minden bevétel összegzése.

Készpénz - A pillanatnyi készpénz mennyiség (a képernyõ alján folyamatosan jelezve).

Vagyon - Az álltalad felépített vonalak, épületek, ipari egységek össz értéke.

Nettó jövedelem - A pillanatnyi pénzösszeg ami a kasszába befolyik.

Ãrrés - A pillanatnyi költség és árbevétel közötti különbség. Minnél nagyobb annál jobb.

Havi karbantartás - A közlekedési hálózatod fenttartási költsége.

Szállítmányok - A szállításra költött pénzmennyiség.

Az eredményeket évre, vagy hónapra lebontva lehet megjeleníteni.

simutrans-124.3/simutrans/text/hu/goods_filter.txt000066400000000000000000000017311474050137200224230ustar00rootroot00000000000000Javak listája

Javak listája

A különbözõ javaknak különbözõ színe van. Ez nagyon hasznos ha a kis térképet hasunálod. Minden egyes árú egységnek van egy értéke amely úgymond Simucentben van megadva. Ez azt jelenti, hogyha az árú a megfelelõ helyre ér, a jövedelmed ennyi centtel lesz több egységenként. Ugyanakkor a sebesség függvényében százalékban véve bónuszcenteket is kapsz. A bónusz az alap sebesség és az aktuális sebesség különbségébõl számolódik ki. Részleteket lásd a: http://128.simutrans.com/graphs.htm honlapon (angol nyelvû).

Rakomány Itt vannak felsorolva a különbözõ javak.

Ãr: Egyes javak ára Simucentben.

Bonusz: Plusz pénz amit az alapsebbességhez viszonytott aktuális sebességbõl számolodik ki.

Típus: Az árú típusa.

Súly: Egy egység kg-ban vett súlya.

simutrans-124.3/simutrans/text/hu/haltlist.txt000066400000000000000000000014011474050137200215610ustar00rootroot00000000000000Ãllomás/megálló lista Sugó

Ãllomás/megálló lista

Az Ãllomás/megálló listalehetõvé teszi a kis világodban fellelhetõ megállok és állomásák kilistázását, különbözõ opciók szerint. Az állomások/megállók név, a várakozó utas vagy termék, típus és számozás szerint sorba állíthatóak, illetve az azonos kategoriák növekvõ vagy csökkenõ sorrendbe jeleníthetõek meg.

A Filterek segítségével tovább szûkithetõ a megjelenített állomások/megállók listája. A filterek hatása csak engedélyezés után jelenik meg. A Filterek tulajdonságait a Beállítások gombbal lehet beállítani.

simutrans-124.3/simutrans/text/hu/haltlist_filter.txt000066400000000000000000000031231474050137200231310ustar00rootroot00000000000000Ãllomás/megálló filter Sugó

Ãllomás/megálló filter

Az Ãllomás/megálló filter teszi lehetõvé az állomások/megállok további szortírozását.

Beállítási lehetõségek:

1.) Filter neve:
A filtereket (szûrõket) el lehet nevezni.

2.) Filter tipusa:
Megálló típuskont lehet választani. A kívánt filtert a kis kockák "benyomásával" lehet aktiválni.

3.) Speciális filter:
Itt lehet azokat a megállókat/állomásokat kilistázni melyek túlzsúfoltal vagy amit egyetlen jármû sem érint. AZt, hogy az állomást milyen vonalak szolgálják ki, vagy van-e direkt útvonal valamilyen más megállóhoz azt az állomás "Részletek" gombjára kattintva tudod megnézni.

4.) Igényelt nyersany.:
Itt lehet az árú vagy utas függvényében jobban szûkíteni a keresett megállók listáját. A "mind" gombbal minden kijelõlõdik, a "semmi" mindent töröl, a "ford." az aktuális kiválasztást megfordítja.

5.) Termelés:
Itt lehet azokat a megállókat/dokkokat kiszûrni melyek az álltalad kiválasztott árúkat termelik. A "mind" gombbal minden kijelõlõdik, a "semmi" mindent töröl, a "ford." az aktuális kiválasztást megfordítja.

->Megálló részletek

->Ãltalános információk

simutrans-124.3/simutrans/text/hu/language.txt000066400000000000000000000023051474050137200215240ustar00rootroot00000000000000Nyelv választás Sugó

Nyelv ablak

A Simutrans sok nyelvre lett lefordítva. Többek között magyarra is. Az egyes nyelvek kiválasztásakor a játék összes szövege azonnal átvált.
A már létezõ városok neve nem fog megváltozni, hanem az új térkép generálása közben kapott néven marad. Ha azt akarod, hogy a városok egyértelmûen a kiválsztott nyelven jelenjenek meg, akkor az új térkép beindítása elõtt válaszd ki a nyelvet. A Simutrans alapvetõen két módszert használ a városneveknél, az elsõ egy szótagókból álló véletlenszerû névgenerálás a másik módszer pedig \text vagy \pak128\text vagy \pak könyvtárakban található városlistákból szedi ki véletlenszerûen a városok nevét.

Ha netán mégis hiányzik a kívánt fordítás akkor a
http://128.simutrans.com
http://forum.simutrans.com
http://www.simutrans.de

honlapokon kutakodhaszt tovább. Figyelem egyes fordítások nem biztos, hogy tartalmazzák a legutobbi fejlesztések leírását.

Hogy segítsen a Simutrans fordításában az Ön nyelvén,
látogasson el a https://translator.simutrans.com oldalra

simutrans-124.3/simutrans/text/hu/list.txt000066400000000000000000000007341474050137200207200ustar00rootroot00000000000000Szortírozás Sugó

Szortírozás

Különbözõ dolgok, infók filterek segítségével nagyon egyszerûen megtekinthetõek. Lásd a lenti link-eket.

Ãllomás/megálló lista
Jármûlista
Összes város listázása
Javak listázása
Termelõegységek listázása

simutrans-124.3/simutrans/text/hu/load.txt000066400000000000000000000013201474050137200206540ustar00rootroot00000000000000Betöltés Sugó

Lementett játékok betöltése

A "Betöltés" menûpont lehetõvé teszi a régebben lementett játékok folytatását. A felkínált gombok hasonlóak a "Mentés" menûpont alatti gombokkal.

Ha netán olyan játékot szertnél betölteni ami már nem létezik, akkor egyszerûen egy hibaüzenetet kapsz.

Fontos! Régebbi verzióban mentett játékok nem minden esetben kompatibilisek az új verziókkal. További információért kutakodj egy kicsit a neten. Például itt:http://forum.simutrans.com. Több mint valószínû a nagy verzióváltások lementett játékai nem kompatibilisek egymással.

simutrans-124.3/simutrans/text/hu/mailbox.txt000066400000000000000000000034131474050137200213750ustar00rootroot00000000000000Postaláda/Postaláda opciók Sugó

Postaláda/Postaláda opciók

A játék során felbukkanó összes üzenet itt mentõdik. Ugyanakkor itt tudod beállítani azt, hogy mirõl és hogyan kérsz figyelmeztetést.

Az Opciók gomb a "Postaláda opciók" nevû ablakot hozza fel. Itt lehet beállítani, hogy a különbözõ események üzenetei hogyan jelenjenek meg. Alapvetõen három módot lehet beállítani:
1. A kis bal oldali kocka aktiválása az jelenti, hogy az üzenetek futó szövegként a játék fõ ablakának alján jelennek meg (scroll text).
2. A közbelsõ kocka aktiválása azt jelenti, hogy az üzenetek egy felugró ablakban jelennek meg, amit csakis kézzel lehet lezárni.
3. A jobb kis kocka aktiválása azt jelenti, hogy az üzenetek egy felugró ablakban jelennek meg ami egy idõ után magától lezáródik.

From top to bottom, the following messages are adjustable:
-Új év: Üzenet küldése új év kezdetekor.
-AI (mesters. int.): Üzenet a számítógép álltal vezérelt játékos (AI) új vonaláról.
-Új város: Üzenet nagyobb városháza építésekor.
-Eltévedt jármû: Üzenet olyan jármûvekrõl, melyek nem találják az utat.
-Új ipari egység: Üzenet új ipari lánc kialakításáról.
-Turisták: Üzenet új turista atrakció vagy emlékmû építésérõl.
-Új jármû: Üzenet új jármû érkezésérõl.
-Tároló telítvel: Üzenet a túlterhelt megállókról.
-Egyéb problémák: Üzenet egyébb kritikus hibákról.

Minden egyes üzenetkor, az üzenetre vagy az üzenet melletti képre kattintva ráugrasz a problémás területre.

simutrans-124.3/simutrans/text/hu/map.txt000066400000000000000000000050021474050137200205130ustar00rootroot00000000000000Térkép ablak Sugó

Térkép ablak

Az egész "világról" mutat egy madártávlat típusú térképet. Alapállásban a térképen nincs feltüntetve semmi. Azt, hogy mi látszodjon a kis térképen azt a "Jelmagyarázat" ablakban tudod beállítani.

A "Jelmagyarázat" ablakban a következõ dolgokat lehet a kis térképre kihelyezni:
Városok - Megjeleníti a városok nevét illetve helyét.
Utas - Megjeleníti azokat a pontokat ahol utasok tartozkodnak. A terhelési színekbõl lehet következtetni (lásd az ablak felsõ részén a minimum és maximum színkódjait), hogy egy adott állomás vagy megálló mennyire zsúfolt.
Posta - Feltünteti a posták helyét.
Rakomány - Megjeleníti azokat a pontokat ahol rakomány van (legyen az árú, vagy nyersanyag, vagy posta).
Státusz - Megjeleníti azokat a helyeket, ahol túlterheltség vagy zsúfoltság van.
Szerviz - Jelzi azokat az útvonalakat és egységeket melyek szervizelést igényelnek.
Forgalom - A forgalom nagyságát jelzi utakon vasútakon.
Kiindulás - Kijelöli azokat az állomásokat vagy megállókat ahonnan az árúk, utasok kiindulnak illetve itt lehet követni azt, hogy honnan indul ki a legtöbb utas vagy árú.
Célállomás - Jelzi azokat a célállomásokat és megállókat ahova a legtöbb utas vagy árú tart.
Várakozik - Kijelöli azokat a megállókat vagy állomásokat ahol a legtöbb árú vagy utas várakozik.
Vonalak - Megjeleníti az összes vasúti és közúti vonalat.
Sebes.korlát. - Kijelzi azokat a szakaszokat ahol sebességkorlátozás van.
Elektr.hálóz. - Megjeleníti az egész elektromos hálózatot.
Turisták - Kijelzi azokat a helyeket ahol turisták illetve turistacélpontok vannak.
Gyárak - Megjeleníti az összes termelõ egységet (gyárakat, bányákat, iparegységeket).

Minden egyes termelési egység külön színnel van feltüntetve. A részletes színkódott a térkép alján találod.A minimum és maximum értéket is színkód jelzi (vagyis azt, hogy sok az utas vagy kevés, túlterhelt egy állomás vagy nem, nagy forgalom vagy kicsi stb.).

A madártávlat térképre kétfoklozatú nagyítás alkalmazható. Bármelyék részére az egér jobb gombjával, vagy a középsõ görgõvel ráklikkelve változtathatód a nagyítás mértékét.

simutrans-124.3/simutrans/text/hu/new_world.txt000066400000000000000000000057501474050137200217500ustar00rootroot00000000000000Új Térkép Sugó

Új térkép

Itt tudod az új létrehozandó térkép paramétereit beállítani. Mindegyik mellet egy rövid leírás található.

Térképszám - Itt határozod meg a térkép típusát. Egy kis elõnézeti térképet is láthatsz melyen a paraméterek változtatásának hatását lehet ellenõrizni.
Méret - A térkép MB vett méretét lehet meghatározni. Az alap a 20 MB. Fontos! Minnél nagyobb a MB vett térkép méret annál lassabban készül el az új térkép és több memoria szükségeltetik.

Városok száma - A városok számát tudod beállítani (min. 2 max. 64) Alapérték 16.

Forg. sûrûsége - A városban közlekedõ kocsik sûrûségét lehet meghatározni. Alapérték 9. Vízmennyiség - Az új térképen megjelenõ vízmennyiséget szabályozód. Minél kisebb az érték annál több föld lesz ill. annál kevesebb víz és fordítva. Alpérték 4.
Hegymagasság - A hegyek magasságát lehet beállítani. Minél kissebb annál lágyabb az átmenet a terepen. Alapérték 160.
Terepdurvaság - Mennyire legyen változatos a terep, mennyire legyen dimbes-dombos. Alapérték 2.

Ipari egys. (terepen) - Az ipari egységek sûrûségét szabályozod városon kívül. Nagyobb érték több ipari egységet jelent.
Ipari egys. (városban) - Az ipari egységek sûrûségét szabályozod a városokban vagy a városok közelében. Nagyobb érték több ipari egységet jelent.
Turista forgalom - Mennyi turista legyen a kis világodban. A nagyobb érték több turistaforgalmat jelent.

Ãtlag lakos per város - Itt lehet meghatározni az átlag lakósszámot városonként.

Véletlen térkép - Véletlen térkép generálása (nem befolyásol más beállítást).

Gyalogosokat mutat - Itt lehet beállítani, hogy mutassa-e vagy sem a városokban a gyalogosokat. A játék elindítása után a Képernyõ opciók dialogus ablakban módosítható.
Éjszaka/nappal mód - Itt állítható be, hogy legyen-e éjszaka és nappal mód. Ha ki van kapcsolva akkor "állandóan nappal van" :). A játék elindítása után a Képernyõ opciók dialogus ablakban módosítható.

Játék betöltés - Egy már lementett játék indítását teszi lehetõvé. (lásd az Opcióknál a Mentésmenüpontot.)
Játék indítása Az új a fenti paramétereket alkalmazó játék indítása.
Domborzat betölt. Itt lehet az álltalad készített térképfájlt, domborzatfájlt betölteni. Mikor nincs kedved a véletlenszerû térképekhez akkor készíts magadnak egy térképet. Azt, hogy hogyan kell ezt csinálni azt a neten lehet megtudni :)
Kilépés - Végleges kilépés a játékból.

simutrans-124.3/simutrans/text/hu/options.txt000066400000000000000000000016101474050137200214320ustar00rootroot00000000000000Játék beállítások Sugó

Játék beállítások

Itt lehet a mindenféle beállítási lehetõségeket kihasználni és alkalmazni

Nyelv - A játék nyelvének a megváltoztatása.
Játékos szín - Saját színed megváltoztatása.
Képernyõ - Képernyõvel kapcsolatos beállítások.
Hang - Hangokkal kapcsolatos beállítások.
Játékosok - Itt tudod a számítogépes ellenfeleidet (AI) kiválasztani.
Betöltés - Lementett játék betöltése
Mentés - Az aktuális játék lementése.
Új térkép - Új térkép létrehozása (figyelem a régi mentés nélkül lezárodik)
Kilépés - Kilépés a játékból (nincs figyelmeztetés és nem menti a játékot).

Részleteket az egyes opciók helyi sugójánál találsz.

simutrans-124.3/simutrans/text/hu/players.txt000066400000000000000000000010301474050137200214120ustar00rootroot00000000000000Játékosok Sugó Help

Játékosok

Itt tudod a számítógép állatl vezérelt ellenfeleidet (AI - Artificial intelligence) ki, illetve bekapcsolni.

A kikapcsolás a kis sima négyzet manipulálásával érhetõ el. Figyelem ha kikapcsolsz egy játékost lényegében csak annyit csinálsz, hogy "elaltatod" vagyis több fejlesztés nem lesz de a már felépített termelõegységek mûködni fognak.

Tájékoztatásképp az egyes játékosok pénzösszegét tudod egyelõre megnézni.

simutrans-124.3/simutrans/text/hu/railtools.txt000066400000000000000000000013701474050137200217520ustar00rootroot00000000000000Vasúti eszközök Sugó

Vasúti eszközök

Itt tudsz vasútat, mozdonyokat, jelzõlámpákat, alagútakat megállókat, depókat, felüljárókat építeni.

Többfajta vasúti sín létezik, válaszd ki a sebesség függvényében a neked megfelelõt.

A vasúti jelzõ építésekor mikor felépíted, akkor az mindkét irányba fog jelezni. Sorozatos klikkeléssel éred el azt, hogy a megfelelõ irányba mutasson.

Az alagút építésnél figyelembe kell vedd, hogy egyszer a hegyoldalra a síneket kell felépítsd és csak erre majd az alagútat. De erre a játék idejében figyelmeztet.

A Depóban tudod összeállítani a megfelelõ vasúti szerelvényt (mozdonyokat, vagonokat).

simutrans-124.3/simutrans/text/hu/roadtools.txt000066400000000000000000000005111474050137200217440ustar00rootroot00000000000000Közúti eszközök Sugó Help

Közúti eszközök

Itt található a közútak és kocsik építéséhez szükséges összes eszköz.

Többféle úttípus közül választhatsz. Válaszd ki a sebesség függvényében a neked épp megfelelõt, majd klikkeléssel helyezd a térképre.

simutrans-124.3/simutrans/text/hu/save.txt000066400000000000000000000026001474050137200206750ustar00rootroot00000000000000Mentés Sugó

Mentés

A megfelelõ fájlnév megadásával lehet kimenteni az aktuális játékmenetet, ami késõbb a "Betöltés" menûpontban bármikor visszatölthetõ.

Figyelem! Nagy verzióváltásoknál több mint valószínû a régebbi játékok nem tölthetõk be.

Menetrend Sugó

Menetrend ablak

Itt határozod meg. hogy konvojod milyen pontok között közlekedjen. Hat gombot találhatsz az ablak alsó részén:"Hozzáadás", "Beszúrás" "Törlés", "Kész","Új vonal", "Visszaút". A "Hozzáad" gombbal megállokat adsz hozzá a menetrendhez. A "Beszúrás" gombbal az aktuális megálló elé szúrsz be egy újabb megállót. Az aktuális megálló egy dupla ">>" jelezve van. A "Töröl" gombbal tudsz megállókat törölni, mégpedig úgy, hogy ha benyomod a "Töröl" gombot és utána a megfelelõ megállóra kattintasz a bal egérgombbal akkor az törlödik. Minden egyes megállóban meg tudod határozni, hogy a jármû kapacitásának, hány százaléka teljen fel mielõtt az elindulna. Tudni kell, hogy ha magasabb százalékra rakod és a termelõegység nem tudja egybõl megtölteni a jármûvet, akkor az addig marad a megállóban míg a megfelelõ százalékban fel nem telik. Az "Új vonal" új vonal tervezését teszi lehetõvé. A "Visszaút" pedig értelemszerû.

simutrans-124.3/simutrans/text/hu/schedule.txt000066400000000000000000000020521474050137200215340ustar00rootroot00000000000000Menetrend Sugó

Menetrend ablak

Itt határozod meg. hogy konvojod milyen pontok között közlekedjen. Hat gombot találhatsz az ablak alsó részén:"Hozzáadás", "Beszúrás" "Törlés", "Kész","Új vonal", "Visszaút". A "Hozzáad" gombbal megállokat adsz hozzá a menetrendhez. A "Beszúrás" gombbal az aktuális megálló elé szúrsz be egy újabb megállót. Az aktuális megálló egy dupla ">>" jelezve van. A "Töröl" gombbal tudsz megállókat törölni, mégpedig úgy, hogy ha benyomod a "Töröl" gombot és utána a megfelelõ megállóra kattintasz a bal egérgombbal akkor az törlödik. Minden egyes megállóban meg tudod határozni, hogy a jármû kapacitásának, hány százaléka teljen fel mielõtt az elindulna. Tudni kell, hogy ha magasabb százalékra rakod és a termelõegység nem tudja egybõl megtölteni a jármûvet, akkor az addig marad a megállóban míg a megfelelõ százalékban fel nem telik. Az "Új vonal" új vonal tervezését teszi lehetõvé. A "Visszaút" pedig értelemszerû.

simutrans-124.3/simutrans/text/hu/shiptools.txt000066400000000000000000000004671474050137200217740ustar00rootroot00000000000000Hajózási eszközõk Sugó

Hajózási eszközõk

Itt találhatód a hajók, dokkok építéséhez használatos eszközõket.

Megállókat a kiválasztott hely közvetlen közelébe kell elhelyezd, hogy azt a program a te álltalad igényelt állomásnak ismerje fel!

simutrans-124.3/simutrans/text/hu/sound.txt000066400000000000000000000010771474050137200210760ustar00rootroot00000000000000Hang beállítások Sugó

Hang beállítások

Itt tudod a játék hang- és zeneeffektusait beállítani.

Effektus hangerõ - A játék hangeffetusait szabályozod (pld. vonat fütyülése stb.)
Zene hangerõ: - A zene hangereját szabályozod. Figyelem a játékhoz nem minden esetben tartozik zene (attól függ honnan töltötted le). Ha nincsenek hangfájlok akkor ez a csuszka nem változtat semmin. Azt, hogy épp milyen hangfájl van használatban az két sorral lejjebb lehet látni.

simutrans-124.3/simutrans/text/hu/special.txt000066400000000000000000000031461474050137200213650ustar00rootroot00000000000000Speciális eszközök Sugó

Speciális eszközök

Itt találhatók azok az eszközök melyekkel a posta szállítási vonalakat felépítheted, illetve olyan eszközök melyekkel az egyes állomások, megállók/rakodóudvarok kapacitását megnövelheted.

Eszközök:

- Posta: több fajta postai épületet lehet építeni.

- Egy állomás kapacitását növelõ épületek: ezeket az épületeket egy már meglévõ megálló vagy állomás mellé kell építeni.

- Játékos váltás: nagy P betûvel válthatsz az AI vezérelte játékosok és magad álltal kontrolált játékos között. Azt, hogy épp melyék játékos aktív az a képernyõ alján látható. Illetve itt érhetõek el egyébb "Szerkesztõ" eszközök.

- Új város alapítása: ezt az eszközt kell alkalmazs, ha egy teljesen új várost akarsz építeni.

- Faültetés: minél több fát ültetsz annál nyereségesebb az egész rendszer.

- Elektromos hálózat építése: ezzel az eszközzel építheted ki az elektromos hálózatodat. A vezetékek a termelõegységekhez egy Trafóállomáson keresztül csatlakoznak.

- Trafóállomás építése: ez az eszköz szükséges a Trafóállomások felépítéséhez. A Trafóállomást közel kell építeni a termelõ egységekhez. A villamos vezetékek ide kell csatlakozzanak.

- Jelzõtábla: a térképen jelzõtáblákat helyezhetsz el a jobb tájékozódást elõsegítve.

simutrans-124.3/simutrans/text/hu/station.txt000066400000000000000000000003541474050137200214240ustar00rootroot00000000000000 Megálló/állomás infó Sugó

Megálló/állomás infó

Itt találhatod az aktuális állomás paramétereit. Pld. mennyi nyersanyag vagy utas várakozik, különbözõ statisztikai grafikonok stb.

simutrans-124.3/simutrans/text/hu/station_details.txt000066400000000000000000000003601474050137200231260ustar00rootroot00000000000000Részletek Sugó

Részletek

Itt megnézheted, hogy ehhez az egységhez milyen gyárak, termelõegységek kapcsolódnak.

Továbbá kijelzi a direkt útat, a tároló kapacitást és egyéb infót.

simutrans-124.3/simutrans/text/hu/tramtools.txt000066400000000000000000000013571474050137200217730ustar00rootroot00000000000000Villamos eszközök Sugó

Villamos eszközök

Itt tudsz villamos síneket, jelzõlámpákat, megállókat, depókat, felüljárókat építeni.

Többfajta villamos sín létezik, válaszd ki a sebesség függvényében a neked megfelelõt.

A villamos jelzõ építésekor mikor felépíted, akkor az mindkét irányba fog jelezni. Sorozatos klikkeléssel éred el azt, hogy a megfelelõ irányba mutasson.

Tudni kell, hogy villamos a rendes vasúti síneken is mûködik. Ezért ha hídra vagy alagútra van szükséget használd a "Vasúti eszközöknél" fellelhetõ kellékeket.

A Depóban tudod összeállítani a megfelelõ villamos szerelvényt.

simutrans-124.3/simutrans/text/id.tab000066400000000000000000001246271474050137200176640ustar00rootroot00000000000000Indonesia PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: id Indonesia # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Non-aktif cl_btn_filter_enable Aktif cl_btn_filter_settings Pengaturan cl_btn_sort_asc Kecil ke besar cl_btn_sort_desc Besar ke kecil cl_btn_sort_id ID internal cl_btn_sort_income Laba cl_btn_sort_name Nama cl_btn_sort_type Jenis clf_btn_alle Semua clf_btn_invers inv. clf_btn_keine tidak ada gl_btn_sort_bonus Bonus gl_btn_sort_name Nama gl_btn_sort_revenue Harga gl_btn_unsort Acak hl_btn_filter_disable Non-aktif hl_btn_filter_enable Aktif hl_btn_filter_settings Pengaturan hl_btn_sort_asc Kecil ke besar hl_btn_sort_desc Besar ke kecil hl_btn_sort_name Nama hl_btn_sort_type Jenis hl_btn_sort_waiting Menunggu hlf_btn_alle Semua hlf_btn_invers Balik hlf_btn_keine Tidak ada Networks Rute Queueing Tren menunggu Road toll Jalan Tol Scenario Info skenario Transfers Yang lewat #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Iklim Kutub desert Gurun mediterran Iklim Mediterrania rocky Iklim Alpen temperate iklim sedang tropic Iklim Tropis tundra Iklim Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Scenario script tidak dapat dibuka Can't buy obsolete vehicles! Kendaraan tua tidak dapat dibeli. Cannot alter water Air tidak dapat ditambah atau dikurangi lagi. Cannot built depot here! Depot tidak dapat dibangun di sini. Cannot built this station/building\nin underground mode here. Stasiun/bangunan ini tidak dapat\ndibangun di bawah tanah di sini. Cannot create generic line!\nSelect line type by\nusing filter tabs. Rute semua jenis tidak dapat dibuat.\nGunakan filter untuk\nmemilih jenis kendaraan. Cannot create socket Koneksi socket tidak dapat dilakukan Convoi handles exhausted! Konvoi sudah mencapai jumlah maksimum. Convoy already deleted! Konvoi sudah dihapus. Das Feld gehoert\neinem anderen Spieler\n Tanah ini\ndimiliki oleh\npemain lain.\n Der Besitzer erlaubt das Entfernen nicht Pemilik tidak\nmemberikan ijin\nuntuk menghapus.\n Diese Zusammenstellung kann nicht fahren!\n Salah Kombinasi\nKendaraan tdk dpt bergerak!\n Flugzeughalt muss auf\nRunway liegen!\n Tempat parkir pesawat\nharus di taxiway. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Bandara tidak dapat\n\ndibangun di sini.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Sinyal kereta tidak dapat\ndiletakkan di sini.\n In order to lock the game, you have to protect the public player by password! Untuk mengunci permainan, anda harus memberikan kata sandi untuk public player. Lost connection\nto server! Koneksi dengan\nserver terputus. Lost synchronisation\nwith server. Kehilangan sinkronisasi\ndengan server. Maglevhalt muss auf\nMaglevschiene liegen!\n Stasiun maglev harus dibuat di rel maglev Monorailhalt muss auf\nMonorail liegen!\n Stasiun Monorel\nharus dibuat di\njalur Monorel!\n Monorails are not available yet! Monorel belum dikembangkan! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Stasiun rel sempit hanya dapat diletakkan di rel sempit. No suitable way on the ground! Pemberhentian hanya dapat dibangun\ndi jalurnya dan harus datar. No through station here! Pemberhentian hanya dapat dibangun di jalur lurus tanpa persimpangan. Not enough money! Uang Anda tidak cukup\nuntuk membangun ini. On narrowgauge track only!\n Hanya untuk rel sempit.\n Only public player can lock games! Hanya public player yang dapat mengunci permainan. Out of funds Uang Anda tidak cukup untuk melakukan hal ini. Post muss neben\nHaltestelle\nliegen!\n Bangunan tambahan\n(kantor pos,gudang)\nhanya dapat dibangun di tanah kosong\ndi sebelah pemberhentian yang sudah ada.\n Protocoll error (expecting game) Protocol error (expecting game) Schiffhalt muss im\nWasser liegen!\n Pemberhentian kapal harus\ndibangun di air\ndi dekat dermaga.\n Server busy Server sibuk. Terraforming not possible\nhere in underground view Di bawah tanah, tanah tidak dapat dinaikturunkan. This tunnel branches. You can try Control+Click to remove. Terowongan ini memiliki cabang. Ctrl+klik untuk membongkar. Upgrade must have\na higher level Hanya dapat diperbaharui\nke tingkat yang lebih tinggi. Vehicle %s cannot choose because stop too short! Kendaraan %s tidak dapat memilih karena pemberhentian terlalu pendek. Zughalt muss auf\nSchiene liegen!\n Stasiun kereta\nhanya dapat dibangun\ndi atas rel kereta.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Help

Help Index

About Simutrans

%1$s

How to use

%2$s

How to start a game

%4$s

How to play

%5$s

Tools

%3$s

Others windows

%6$s Decrease water height Menurunkan air sebanyak satu tingkat Highlight railroad tracks Menampilkan rel kereta Highlite depots Menampilkan depot Highlite electrical transmission lines Menampilkan kabel transmisi listrik Highlite factories Menampilkan pabrik Highlite forests Menampilkan hutan Highlite tourist attraction Menampilkan tempat wisata Increase water height Meninggikan air sebanyak satu tingkat Overlay city limits Menampilkan batas kota Overlay passenger destinations when a town window is open Menampilkan tujuan penumpang saat jendela informasi kota dibuka Overlay schedules/network Menampilkan jadwal/jaringan Overlay town names Menampilkan nama kota Please click on the map to add\nwaypoints or stops to this\nschedule. Klik di peta untuk menambah\nwaypoint atau pemberhentian\nke jadwal ini. Set tile climate %s Mengubah tanah ini menjadi iklim %s. Show capacity and if halt is overcrowded Menampilkan kapasitas dan keramaian pemberhentian Show how many convoi reach a station Menampilkan jumlah konvoi yang mencapai stasiun Show how many people/much is waiting at halts Menampilkan jumlah yang menunggu di pemberhentian Show initial passenger departure Menampilkan keberangkatan awal penumpang Show level of city buildings Menampilkan tingkat bangunan kota Show mail service coverage/mail network Menampilkan jangkauan layanan pos Show passenger coverage/passenger network Menampilkan jangkauan layanan penumpang Show speedlimit of ways Menampilkan batas kecepatan jalan Show the change of waiting at halts Menampilkan perubahan jumlah yang menunggu dibandingkan bulan lalu Show the owenership of infrastructure Menampilkan kepemilikan bangunan/fasilitas Show transported freight/freight network Menampilkan jaringan kargo yang diantarkan Show usage of network Menampilkan kendaraan setiap kotak setiap bulan. Shows a listing with all industries on the map. Menampilkan daftar semua industri di peta. Sum of departure/arrivals at halts Jumlah kedatangan/keberangkatan di pemberhentian #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s\nmenyediakan bus\nantara %s\ndan tempat wisata\n%s\ndi (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s\nmenyediakan bus\nantara %s\ndan pabrik\n%s\ndi (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nmengoperasikan\n%i truk antara\n%s di (%i,%i)\ndan %s\ndi (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nmembuka jalur kereta\nantara %s\ndi (%i,%i)\ndan %s\ndi (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Layanan penerbangan oleh\n%s\nantara\n%s \ndan %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Layanan kapal feri oleh\n%s\nantara\n%s \ndan %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nmembuka layanan\nbus antara\n%s dan\n%s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Infrastruktur Publik LISTTOOLS Data-Data MAGLEVTOOLS Infrastruktur Maglev MONORAILTOOLS Infrastruktur Monorel NARROWGAUGETOOLS Peralatan kereta rel sempit RAILTOOLS Infrastruktur Kereta ROADTOOLS Infrastruktur Jalan SHIPTOOLS Infrastruktur Kapal SLOPETOOLS Perbaiki Lahan SPECIALTOOLS Infrastruktur Khusus TRAMTOOLS Infrastruktur Trem #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s membangun kantor pusat baru. Factory chain extended\nfor %s near\n%s built with\n%i factories. Ekonomi meningkat:\n%s di dekat %s menambah pabrik.\n%i pabrik baru dibangun. New %s now available:\n%s\n %s baru tersedia:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Pertumbuhan industri: Pabrik baru\nuntuk %s di dekat\n%s dibangun beserta\n%i pabrik. New vehicle now available:\n%s\n \n Kendaraan baru\n tersedia:\n\n\n -- %s --\n\n Now %u clients connected. Saat ini %u orang tersambung. Remove vehicle from map. Use with care! Menghapus kendaraan. (Gunakan secara hati-hati) Screenshot\ngespeichert.\n Screenshot\ntersimpan.\n Sends the convoi to the last depot it departed from! Mengirim konvoi ke depot tempat konvoi ini berangkat. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s membangun\nmonumen baru.\n%i penduduk bersuka cita. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Filter rute #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (di depot) \nBauzeit bis - \nBauzeit von \nAda sejak \nCan't open heightfield file.\n \nPeta ketinggian tidak dapat dibuka.\n \ndirection: \narah: \nelektrified \nberlistrik\n \nHeightfield has wrong image type.\n \nTanah memiliki jenis\ngambar yang salah.\n \nis reserved by: \nDigunakan Kereta: \nminimum speed: \nKecepatan Minimum: \nnot elektrified \nTidak Terelektrifikasi\n \nRibi (masked) \narah\m (disembunyikan): \nRibi (unmasked) \narah\m (ditampilkan): \nSet phases: \nTenggang waktu\nUtara-Selatan Timur-Barat: \nsingle way \nSatu Arah \nway1 reserved by \njalur 1 digunakan oleh \nway2 reserved by \njalur 2 digunakan oleh \nwith sign/signal\n \ndengan rambu/sinyal\n %d buildings\n %d bangunan\n %d convois %d konvoi %d Einzelfahrzeuge im Depot %d kendaraan disimpan di sini. %i km/h (max. %ikm/h) %i km/h (maks. %i km/h) %i years %i months old. Usia: %i tahun %i bulan %s at (%i,%i) now public stop. %s menjadi pemberhentian umum. %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s (pabrik) %s has entered a depot. %s telah kembali ke depot. %s land %d %s %s %d %s pinggir kota %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \nmembangun\nbalai kota baru\nsaat mencapai\n%i penduduk. %s\nis crowded. %s\n Penuh. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nkecepatan maksimum %3$i km/h\n\nkecepatan saat ini %2$i km/h.\n\n %s\nwas liquidated. %s bangkrut dan\nsudah dikeluarkan.\nSeluruh aktifitas dihentikan\ndan semua aset telah dijual. %u Client(s)\n %u orang\n %u Player (%u locked)\n %u pemain (%u terkunci)\n 1 convoi 1 konvoi 1 Einzelfahrzeug im Depot 1 kendaraan disimpan di sini. 1LIGHT_CHOOSE Brightness 1WORLD_CHOOSE Peta 2LIGHT_CHOOSE Warna 2WORLD_CHOOSE No. Peta 3LIGHT_CHOOSE Scroll Speed 4LIGHT_CHOOSE Scroll Inverse 5LIGHT_CHOOSE Pederstrians at stops 5WORLD_CHOOSE Jumlah Kota 6LIGHT_CHOOSE Pedestrians in town 6WORLD_CHOOSE Traffic Density 8WORLD_CHOOSE Tampilkan Malam Hari A bridge must start on a way! Ujung jembatan tidak tersedia atau terdapat penghalang di antaranya. Abfrage Lihat Abnehmer Konsumen About Tentang About scenario Copyright Abriss Hapus Absenken Turunkan Daratan Abspanntransformator Gardu Listrik Accelerate time Percepat Waktu Act. load: %u MW\n Yang digunakan: %u MW\n Active player only Hanya pemain yang aktif Add forest Membuat Hutan Add random citycar Tambah kendaraan penduduk add server Tambah server Add Stop Tambah pemberhentian Add stops for backward travel Tambah pemberhentian untuk perjalanan balik. aircraft_tab Pesawat kargo airplane pesawat Airport Bandara AIRTOOLS Infrastruktur Pesawat All Semua all convoi tooltips semua keterangan konvoi Allow city growth Ijinkan kota untuk berkembang Allow player change Ijinkan ganti pemain allowed climates:\n Iklim yang diijinkan:\n Alters a schedule. Tambah/hapus pemberhentian dari/ke jadwal Angenommene Waren Barang yang dibutuhkan oleh industri dekat sini anhaengen Tambah di akhir Anhaenger_tab Peti kemas Anheben Naikkan Daratan Appends stops at the end of the schedule Tambah pemberhentian di akhir jadwal Apply Line Terapkan Arbeiter aus: Tempat Tinggal Pekerja: Arrivals from\n Kedatangan dari\n Arrived Datang Assets Aktiva Tetap Aufloesen Batalkan Aufspanntransformator Gardu Listrik August Agustus Autohalt muss auf\nStrasse liegen!\n Halte Bus\nharus dibuat\ndi jalan. Available Tersedia Bahndepot Depot kereta Bankrott:\n\nDu bist bankrott.\n Bangkrut:\n\nAnda bangkrut.\n battery Baterai Baum Pohon baum builder Tanami Pohon Baustelle Tempat pembangunan Bauzeit waktu pembangunan Beenden Keluar Beginner mode Untuk pemula Besonderes Gebaeude Venue BF Stasiun bio Biologis Blockstrecke ist\nbelegt\n \nJalur sedang digunakan kereta lainnya,\ntunggu hingga kereta lewat!\n Boden Tanah Bonusspeed: %i km/h Kecepatan maks. yang mungkin dicapai: %i km/h Boost (%%) Peningkatan produksi(%%) bridge is too high for its type! Melebihi tinggi maksimum jenis jembatan ini. Bridge is too long for this type!\n Melebihi\npanjang maksimum\njenis jembatan ini.\n Bruecke Jembatan Bruecke muss an\neinfachem\nHang beginnen!\n Jembatan harus\ndibuat ditanah\nyang lurus!\n Brueckenboden Jembatan Build air depot Hangar Pesawat build choosesignals Membuat sinyal yang menentukan peron yang digunakan Build city market Bangun Rangkaian Industri di sekitar kota ini. Build drain Gardu Listrik build HQ Bangun kantor pusat Build land consumer Bangun Pembangkit listrik Build maglev depot Bangun depot maglev Build monorail depot Bangun depot monorel Build narrowgauge depot Membangun depot rel sempit Build powerline Bangun SUTET Build presignals Membuat sinyal dua blok Build road depot Garasi Build ship depot Bangun depot kapal Build signals Membuat sinyal Build train depot Bangun depot kereta Build tram depot Bangun depot trem Build truck depot Garasi Building costs estimates Perkiraan Biaya Buildings Jumlah Bangunan Built artifical slopes Perbaiki bentuk tanah Built random attraction Bangun Venue apapun Bus_tab Bus Can only move from halt to halt or waypoint to waypoint. Hanya dapat memindah\npemberhentian ke pemberhentian\natau waypoint ke waypoint Cancel Batalkan Cannot connect to offline server! Tidak dapat menghubungi server offline. Capacity: Kapasitas: Capacity: %.0f MW Kapasitas: %.0f MW\n Capacity: %d%s %s\n Kapasitas: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapasitas: %s\n? %d (%d%%) Cars are not available yet! Mobil belum tersedia. cars.\nstate mobil\n Cash Kas Change player Ganti Pemain Chart Grafik Chat_msg Bincang Choose direction Pilih arah Choose operation executed on clicking stored/new vehicles Pemilihan arah dilakukan saat klik pada kendaraan baru/tersimpan chooses a random map Peta Acak citicens Penduduk City attraction Venue dalam kota City industries Industri City list Daftar Kota City size Jumlah Penduduk city_road Jalan Perkotaan citybuilding builder Bangun Rumah penduduk CityLimit Batas Kota cl_title Daftar kendaraan cl_txt_sort Urutkan: Clear block reservation Menampilkan jalur/jalan yang digunakan clf_chk_aircrafts Pesawat clf_chk_cars Bus/truk clf_chk_indepot di depot clf_chk_maglev Maglev clf_chk_monorail Monorel clf_chk_name_filter Nama filter: clf_chk_narrowgauge Kereta rel sempit clf_chk_noincome Tidak membuat untung clf_chk_noline Tidak ada rute clf_chk_noroute Tidak ada jalur/jalan clf_chk_noschedule Tidak ada jadwal clf_chk_obsolete Kuno/tua clf_chk_ships Kapal clf_chk_spezial_filter Filter khusus: clf_chk_stucked Tersangkut clf_chk_trains Kereta clf_chk_trams Trem clf_chk_type_filter Jenis filter: clf_chk_waren Filter barang: clf_title Filter daftar kendaraan Climate Control Pengaturan kondisi alam closed ditutup. COLOR_CHOOSE\n Pilih dua warna\ndari gambar\ndi kanan: Company bankrupt Perusahaan bangkrut Company_msg Lawan Comparing pak files ... Membandingkan berkas pak... Configure AI Mengatur lawan komputer Configure AI setttings Melakukan pengaturan lawan komputer Congratulation\nScenario was complete in\n%i months %i years. Selamat!\nSkenario sudah\nselesai dalam\n%i bulan dan %i tahun. Connected stops Pemberhentian yang terhubung: Connected with server Terhubung ke server Constructed by Digambar oleh Constructed by %s Digambar oleh %s construction speed Kecepatan pembangunan Construction_Btn Biaya pembangunan Consumed Dihabiskan convoi %d of %d Konvoi %d dari %d convoi error tooltips keterangan kesalahan konvoi Convoi has been sent\nto the nearest depot\nof appropriate type.\n Konvoi telah dikirim\nke depot terdekat\nsesuai dengan jenisnya.\n Convoi is sold when all wagons are empty. Kendaraan akan dijual setelah isinya kosong. convoi mouseover tooltips keterangan konvoi dengan mouse convoi passed last\nmonth %i\n \nkonvoi yang lewat\nbulan lalu: %i\n Convois Konvoi Convois: %d\nProfit: %s Kendaraan: %d\nKeuntungan: %s Convoys Konvoi Copy Convoi Salin konvoi Copy the selected convoi and its schedule or line Salin konvoi yang dipilih beserta rute/jadwalnya cost for removal Biaya untuk menghapus Cost: %8s (%.2f$/km %.2f$/m)\n Harga: %s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Biaya: %8s (%.2f$/km)\n Costs Biaya Create a new line based on this schedule Buat rute baru berdasarkan jadwal ini curiosity builder Pembangun tempat wisata curlist_title Daftar tujuan turis Currently playing: Sedang bermain: Customers live in: Pelanggan tinggal di: deactivated in online mode Tidak aktif saat online Deccelerate time Perlambat waktu December Desember decrease underground view level kurangi tingkat tampilan bawah tanah Del Stop Hapus Delete Line Hapus rute Delete the current stop Hapus pemberhentian ini Delete the selected line (if without associated convois). Hapus rute yang dipilih (jika tidak ada konvoi di dalamnya) Delete this file. Hapus berkas ini. Delivered Terkirim Demand Dibutuhkan Demand: %.0f MW Dibutuhkan: %.0f MW\n Denkmal Monumen Departed Berangkat Departure board Waktu keberangkatan Departures to\n Keberangkatan ke\n Depots Depot Der Tunnel ist nicht frei!\n Terowongan tidak kosong.\n Destination Kedatangan Destroying map ... Menghapus peta yang lalu... Details Detil Die Bruecke ist nicht frei!\n Jembatan tidak kosong.\n Direkt erreichbare Haltestellen Rute langsung dari sini: disable midi Matikan Musik Display settings Pengaturan tampilan Distance Jarak Dock Galangan Kapal Dock must be built on single slope! Dermaga harus dibangun di tanah miring. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Anda memiliki %d bulan untuk membayar utang. Durchsatz Tingkat Produksi: Economy Ekonomi dan kota Eigenbesitz\n Fasilitas umum\n Ein %s\npasst hier nicht.\n '%s'\ntidak dapat diletakkan di sini.\n Einstellungen aendern Pilihan electric listrik Electricity Listrik Electricity producer\n\n Penyedia listrik\n\n Electrics_tab Listrik Electrify track Membuat rel listrik enlarge map Memperbesar peta enter a value between %i and %i masukkan nilai antara %i dan %i Enter address Masukkan alamat Enter Password Ganti nama pemain dan kata sandi Erzeuge neue Karte.\n Silakan tunggu.\nPeta sedang dibuat.\n\n(Proses dapat berlangsung beberapa\nmenit untuk peta yang besar)\n Es wird bereits\nein Fahrplan\neingegeben\n Jadwal sedang dibuat.\nSelesaikan terlebih\ndahulu sebelum\nmenjadwal ulang.\n Fabrikanschluss Pabrik yang terhubung Fabrikname nama pabrik Factories Pabrik factory details Detil pabrik factorybuilder Bangun pabrik Fahrplan Jadwal Fahrtziel Tujuan: Fahrzeuge koennen so nicht entfernt werden Kendaraan tidak dapat\ndihapus dengan cara ini.\n Fahrzeuge: Kendaraan: Farbe Pilihan Warna Fast forward Percepat waktu February Febuari Ferry_tab Feri Fertig Selesai Filename Nama berkas: Files from: Berkas dari: Finances of %s Keuangan %s Finanzen Kondisi Keuangan find mismatch Bandingkan pak fl_title Daftar pabrik Flug_tab Pesawat penumpang follow me Ikuti ini Follow the convoi on the map. Ikuti konvoi di peta Forest Hutan Found new city bangun kota yang baru Fracht Barang Frame time: Frame Time: Free Capacity Kapasitas kosong freeplay mode Permainan bebas Friction: Faktor gesekan: fuel_cell fuel cell Full load Muatan minimum: Fundament Pondasi Fussgaenger Pejalan kaki Game info Informasi permainan GAME PAUSED Permainan berhenti sementara Game_msg Umum Gear: Gigi: Gebaeude Bangunan General Umum Generated Dibuat Generation: %.0f MW Dihasilkan: %.0f MW\n Gewicht Berat Gewinn Pendapatan: Give the selected vehicle(s) an individual schedule Ubah rute/jadwal setiap kendaraan yang dipilih gl_btn_sort_catg Kategori gl_title Daftar barang go home Ke depot Goods Barang Goods AI Pemain komputer (barang) Goods list Daftar barang Gross Profit Cash Flow Groundobj Objek Grow city Perbesar kota Growth Pertumbuhan kota H halte Happy Senang Haus kaufen Beli rumah Helligk. Tampilan Help Bantuan Help text not found Teks bantuan tidak ada. hide all building Sembunyikan semua bangunan hide city building Sembunyikan bangunan kota hide objects under cursor Sembunyikan objek dekat pointer mouse hide station names Sembunyikan nama stasiun hide transparent Tembus pandang, bukan disembunyikan hide trees Sembunyikan pohon Hier warten/lagern: Barang/penumpang yang menunggu: Higher transport fees, crossconnect all factories Biaya angkut lebih tinggi, matikan just-in-time Highlite schedule Tampilan pemberhentian yang ada pada jadwal hl_title Daftar Stasiun hl_txt_filter Filter: hl_txt_sort Disusun menurut: hlf_chk_airport Bandara hlf_chk_anleger Pelabuhan hlf_chk_bahnhof Stasiun Kereta Api hlf_chk_bushalt Pemberhentian Bus hlf_chk_frachthof Tempat pengangkutan hlf_chk_keine_verb tidak ada jaringan hlf_chk_maglevstop Stasiun Maglev hlf_chk_monorailstop Stasiun monorel hlf_chk_name_filter Nama filter: hlf_chk_narrowgaugestop Stasiun rel sempit hlf_chk_overflow Terlalu ramai hlf_chk_spezial_filter Filter khusus: hlf_chk_tramstop Halte trem hlf_chk_type_filter Jenis filter: hlf_chk_waren_abgabe Barang keluar: hlf_chk_waren_annahme Barang masuk: hlf_title Filter daftar stasiun Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depot tidak ditemukan.\nKendaraan harus dikirim ke\ndepot secara manual. Homeless Tunawisma hydrogene Hidrogen Idle: Diam: ignore climates abaikan iklim In the industry legend show only currently existing factories Hanya menampilkan pabrik yang ada In Transit Sedang transit Increase Industry density Tambah kepadatan industri increase underground view level Tambah tingkat tampilan bawah tanah industrial building Bangunan industri Init map ... Menyiapkan peta... Input Kebutuhan Ins Stop Sisipkan Insert stop before the current stop Sisipkan pemberhentian sebelum pemberhentian yang dipilih Intercity road len: Panjang jalan antarkota: Intro. date: Tanggal kemunculan: invalid tidak benar. Invalid coordinate Urutan salah isometric map Tampilan isometrik January Januari join game Bermain online July Juli Jump to Pergi ke June Juni Kann Spielstand\nnicht laden.\n Data permainan tidak dapat dibuka. Kann Spielstand\nnicht speichern.\n Berkas yang dituju\ntidak dapat\ndiubah. Kein Besitzer\n Tanpa pemilik\n keine tidak ada Keine Einzelfahrzeuge im Depot Tidak ada kendaraan yang disimpan di sini Keyboard_Help\n Bantuan papan ketik\n koord kordinat Kreuzung Perlintasan labellist_title Daftar penanda Lade Relief Peta Buatan Laden Load Land attraction Tempat wisata luar kota Land industries Rantai industri: LANG_CHOOSE\n Pilih bahasa\nyang disukai:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Bulan lalu: Last Year Tahun lalu: Leaving depot! Meninggalkan depot leer kosong Legend Simbol peta Leistung Daya Leistung: %d kW Daya: %d kW Leitung Kabel listrik letzen Monat: diesen Monat: bulan lalu: bulan ini: Line Rute Line Management Pengelolaan rute Lineless convoys serving this stop Konvoi tanpa rute yang melayani pemberhentian ini Lines serving this stop Rute yang melayani pemberhentian ini LKW_tab Truk Load game Buka permainan load height data from file Memuat data ketinggian dari berkas. Load scenario Buka skenario loaded dimuat loaded passenger/freight Urutkan penumpang/kargo Loading (%i->%i%%)! Terisi (%i->%i%%) Loading addon paks ... Sedang Memuat Addons ... Loading map ... Sedang memuat peta Loading paks ... Sedang memuat file utama ... Loading skins ... Sedang memuat skin ... Lock game Mencegah ganti pemain (membutuhkan konfirmasi) Lokomotive_tab Lokomotif maglev vehicle Maglev maglev_track Rel Maglev Maglevdepot Depot maglev Mail Demand %d\n Kebutuhan pos %d\n Mailbox Pesan Mailbox Options Pilihan pesan Maintenance Perawatan make stop public (or join with public stop next) costs %i per tile and level menjadikan pemberhentian umum (atau bergabung dengan pemberhentian umum di sebelahnya) biaya %i$ setiap kotak dan tingkat Manual (Human) Manual (Manusia) Manufactured: Dibuat: Map roughness Kerumitan Peta: map zoom Perbesar Peta March Maret Margin (%%) Marjin Marker Meletakkan penanda max maks. Max Boost (%%) Peningkatan maks.(%%) Max income: Pendapatan Max: Max. speed: Kecepatan Max: Maximum 254 stops\nin a schedule!\n Paling banyak 254\npemberhentian dalam jadwal\n maximum length of rivers Panjang sungai maks. Maximum tile height difference reached. Perbedaan tinggi\nmaksimum antara\n2 kotak\ntelah tercapai. Maxspeed Kecepatan maksimum May Mei Median Citizen per town Penduduk kota rata-rata: Meldung Pesan Menge jumlah MessageOptionsText \nTahun baru\n\nBerita pemain\n\nBerita kota\n\nTidak ada jalan\n\nTujuan baru\n\nBincang\n\nKendaraan baru\n\nStasiun penuh\n\nMasalah\n\nKemacetan\n\nSkenario min min. minimum length of rivers Panjang sungai min. Missing pakfiles Objek tidak ditemukan. Modify the selected line Ubah rute yang dipilih Monate alt bulan (usia) Monorail Monorel monorail vehicle Kendaraan Monorel monorail_track Rel monorel Monorailboden Substruktur Monorel Monoraildepot Depot monorel month wait time waktu tunggu (bulan) Months Bulan Monument Monumen Monuments Monumen Mountain height Tinggi gunung: Movingobj objek bergerak Music playing disabled/not available Musik dimatikan/tidak tersedia Music volume: Tingkat suara musik: mute sound Matikan suara Name Nama Narrowgauge Rel sempit Narrowgauge are not available yet! Kereta rel sempit belum tersedia. narrowgauge vehicle Kereta rel sempit narrowgauge_track Rel untuk kereta rel sempit Narrowgaugedepot Depot rel sempit Net ID: %p ID jaringan: %p\n Net Wealth Ekuitas Net wealth near zero Kekayaan bersih mendekati nol Neue Karte Permainan baru Neue Welt Buat permainan baru new convoi Konvoi baru New Line Rute baru New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Rute baru telah dibuat.\nRute dapat digunakan dengan\nmemilihnya dari\npilihan rute di atas. New Vehicles Kendaraan baru Nickname: Nama panggilan: no buildings hidden tampilkan gedung no convois Tak ada iringan No goods are loaded onto this convoi. Kendaraan ini bukan untuk mengangkut barang jenis ini no goods waiting Tak ada penumpukan brg no load Tidak memuat No Route Tidak ada jalan ke tujuan No stop here! Harus ditempatkan di pemberhentian! No suitable ground! Tidak ada tanah yang sesuai. No terminal station here! Stasiun/terminal tidak dapat dibangun\ndi sini. Hanya dapat dibangun\ndi ujung rel/jalan. no timeline semua masa no tree Tanpa pohon No. of Factories Pabrik dan toko Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Konvoi ini harus memiliki jadwal atau rute perjalanan sebelum dapat dijalankan. nord Utara nordost Timur laut nordwest Barat laut Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Jadwal tidak dapat diubah\nsaat sedang mencari jalur.\nCoba sekali lagi. Not enough fields would remain. Lahan yang tersisa untuk\nladang ini tidak cukup. Now active as %s.\n Sekarang aktif sebagai %s.\n Number of rivers Jumlah sungai Object Objek Odometer: %s km Sudah ditempuh: %s km Ok OK On loan since %i month(s) Meminjam uang sejak %i bulan On this map, you are not\nallowed to change player!\n Permainan terkunci.\nSemua pemain tidak dapat mengubah apapun.\n Only city chains Bangun rantai industri dalam kota Only first %d differing paks reported. There are probably more. Hanya %d pak berbeda pertama yang dilaporkan. Mungkin masih ada lagi. Only land chains Bangun rantai industri luar kota Only one transformer per factory! Hanya satu transformer untuk setiap pabrik. Only show goods which are currently handled by factories Hanya menampilkan barang yang saat ini ditangani oleh pabrik open buka Operation Biaya operasional Ops Profit Keuntungan operasional Optionen Opsi Or enter a server manually: Atau masukkan server secara manual: Origin Asal ost Timur Output Hasil Ownership Kepemilikan Pak which may cause severe errors: Objek (pak) berikut tidak ditemukan, hal ini dapat menyebabkan masalah pada rantai transportasi: Pak which may cause visual errors: Objek (pak) berikut diganti dengan objek yang mirip/serupa: Pak(s) different: Pak yang berbeda: Pak(s) missing on client: Pak yang tidak Anda miliki: Pak(s) not on server: Pak yang tidak ada di server: Pakset differences Perbedaan pakset paletten peti/kotak Pas_tab Kereta penumpang Passagiere Penumpang Passagierrate Jumlah Pengunjung Passagierziele Tujuan penumpang/pos Passenger AI Pemain komputer (penumpang) Passenger Demand %d\n Permintaan penumpang %d\n Passengers %d %c, %d %c, %d no route Penumpang %d %c, %d %c, %d tidak bisa ke tujuan Passengers %d %s, %d %s, %d no route Penumpang %d %s, %d %s, %d tidak bisa ke tujuan Password Kata sandi: Pause Berhenti sementara Pax <%i> Mail <%i> Penumpang <%i> Pos <%i> PaxDest Tujuan Percent Electricity Listrik dihasilkan (%% dari permintaan): Planes are not available yet! Pesawat terbang belum tersedia. Plant tree Tanam pohon player Pemain player -1 Pemain manusia player 0 layanan umum player 1 pemain 1 player 10 pemain 10 player 11 pemain 11 player 12 pemain 12 player 13 pemain 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 pemain 4 player 5 pemain 5 player 6 pemain 6 player 7 pemain 7 player 8 pemain 8 player 9 pemain 9 Please choose vehicles first\n Pilih kendaraan terlebih dahulu\n Post Pos Postrate Jumlah Pos Power Daya Power (MW) Daya (MW) Power: Daya: Power: %4d kW\n Daya: %4d kW\n Powerlines Kabel listrik Problems_msg Masalah Produced Dibuat Production of %s has been stopped:\n%s\n Pembuatan %s telah dihentikan:\n%s\n Production/Boost Produksi/peningkatan Produktion Produksi Profit Keuntungan promote to line Masukkan ke rute q1 Musim semi q2 Musim panas q3 Musim gugur q4 Musim dingin Query server Panggil server rail car gerbong random acak Random age Tahun acak Random map Peta acak Rathaus Balai kota Rating Penilaian ratio_pax Perbandingan penumpang Relevant Yang diperlukan Reliefkarte Peta Remove Hapus remove airstrips Hapus landasan/jalan pesawat remove channels Hapus Kanal remove interm. signals Hapus sinyal di tengah remove maglev tracks Hapus rel maglev remove monorails Hapus monorel remove narrowgauge tracks Hapus rel sempit remove powerlines Hapus kabel listrik remove roads Hapus jalan remove tracks Hapus Rel Remove wayobj %s Hapus objek %s replace other signals Ganti sinyal lainnya replace stop Tukar pemberhentian request closing permintaan penutupan residential house Rumah penduduk Restore natural slope Kembalikan ke kemiringan alami Restwert: Nilai Jual: Retire. date: Tanggal tidak dibuat lagi: return ticket arah sebaliknya Revenue Laba Kendaraan Revision: Revisi road Jalanan road vehicle Kendaraan Roadsign Rambu-Rambu Rotate map Putar peta Rotation Perputaran Routing Pencarian arah sack bungkus/sak sail angin Saving map ... Menyimpan peta... Scenario complete: %i%% Skenario selesai: %i%% Scenario Debug Debug Scenario Error Log Kesalahan pada skrip Scenario Goal Tujuan skenario Scenario Info Keterangan singkat Scenario information Keterangan lengkap skenario Scenario Result Perkembangan Scenario Rules Peraturan Schedule changing! Perubahan jadwal Schienentunnel Bangun terowongan kereta Schiff_tab Kapal Schiffdepot Galangan kapal Schleppkahn_tab Kapal tongkang Screenshot Potret layar Seasons Musim Sehenswuerdigkeit Tempat wisata Select a server to join: Pilih server untuk bergabung: Select a theme for display Pilih tema untuk ditampilkan Sell the selected vehicle(s) Jual kendaraan yang dipilih. sended Pos terkirim SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Server did not respond! Server tidak dapat dihubungi. Serves Line: Melayani rute: Service Layanan set signal spacing Atur jarak antarsinyal Setting Pengaturan Ship Kapal shops and stores Toko dan kantor Show all Tampilkan semua show all building Tampilkan semua bangunan Show also vehicles no longer in production. Tampilkan juga kendaraan yang sudah tidak dibuat Show also vehicles that do not match for current action. Tampilkan juga kendaraan yang tidak sesuai digunakan saat ini. Show even servers with wrong version or pakset Tampilkan juga server yang menggunakan versi/pakset yang berbeda. show grid Tampilkan kotak-kotak Show industry Daftar industri Show legend Pilihan Show map scale Kode warna Show mismatched Tampilkan yang tidak cocok Show obsolete Tampilkan yang tua/kuno Show offline Tampilkan yang offline Show only used Tampilkan hanya yang digunakan Show schedules Tampilkan jadwal Show servers that are offline Tampilkan server yang mati Show servers where game version or pakset does not match your client Tampilkan server yang pakset/versinya tidak cocok dengan yang Anda gunakan show station coverage Tampilkan jangkauan stasiun show station names Tampilkan nama stasiun show waiting bars Tampilkan jumlah tunggu show/hide block reservations Tampilkan blok jalur yang digunakan Show/hide estimated arrival times Menampilkan perkiraan waktu kedatangan show/hide object owner Tampilkan pemilik benda Show/hide statistics Tampilkan statistik Shows buttons on special topics. Tampilkan tombol simbol peta Shows consumer/suppliers for factories Tampilkan pelanggan dan pemasok pabrik Shows the color code for several selections. Tampilkan kode warna untuk banyak pilihan Shows the currently selected schedule Tampilkan jadwal yang dipilih Shrink city Perkecil kota shuffle midis acak urutan MIDI Signal Sinyal signal spacing Jarak antarsinyal Sim: Simloops: Similar view as the main window Tampilan mirip dengan jendela utama Size (%d MB): Luas Peta sliced underground mode Tampilan atas+bawah tanah slot empty kosong Smart hide objects Sembunyikan objek secara otomatis Sort by urutkan Sort waiting list by Urutkan daftar tunggu Sound Suara Sound settings Pengaturan suara Sound volume: Tingkat keras suara: special freight Kargo khusus Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus kecepatan (persentase)\nkecepatan minimum yang dibutuhkan: jalan %i km/h,\nrel %i km/h, kapal %i km/h, pesawat %i km/h Speedlimit Batas kecepatan Speichern Save Spieler Pemain Spieler(mz) Pemain Spielerliste Daftar Pemain Spielstand wurde\ngeladen!\n \nPermainan berhasil dibuka.\n Spielstand wurde\ngespeichert!\n \nPermainan berhasil disimpan.\n Sprache Bahasa Sprachen Bahasa Stadtinformation Statistik kota Start Mulai Start the selected vehicle(s) Menjalankan kendaraan yang dipilih. Starte Spiel Mainkan! Station tiles: Kotak stasiun: Station_msg Stasiun Status Keadaan steam uap Step timeline one year Maju satu tahun Stops Pemberhentian Storage Penyimpanan Storage capacity Daya tampung penyimpanan Strassendepot Garasi Strassentunnel Bangun terowongan jalan street car mobil di jalan sued Selatan suedost Tenggara suedwest Barat daya Summer snowline Garis salju musim panas Supplied: %.0f %% Dipasok: %.0f %% Suppliers Pemasok Tage alt hari (usia). There are still vehicles\nstored in this depot!\n Masih ada kendaraan\ndi depot ini.\n This Month Bulan ini: This Year Tahun ini: Tile not empty. Kosongkan kotak sebelum\nmengubah kemiringan/ketinggian. timeline sesuai jaman tl_title Daftar semua kota To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Lalu lintas di %1$s meningkat.\n%3$i pembayar pajak membuat pembangunan\n%2$s menjadi kenyataan. To heavy traffic\nresults in traffic jam.\n Lalu lintas padat\nmenyebabkan kemacetan.\n Toggle day/night view Ubah tampilan siang/malam Toggle vehicle tooltips Tampilkan keterangan kendaraan saat disorot tonnen Ton Total inhabitants: Jumlah penghuni: Tourist attractions Tempat wisata: Tourists Tempat menarik Town_msg Tujuan baru Town: %s\n Kota %s.\n Towns Kota track rel Tracks Rel Traffic Lalu lintas Train Kereta Trains are not available yet! Kereta belum tersedia. Tram Trem tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. trem %i km/h, monorel %i km/h\nmaglev %i km/h, rel sempit %i km/h. tram_track rel trem Tramdepot Depot trem Trams are not available yet! Trem belum tersedia. Transferring game ... Memindahkan permainan... Transformer only next to factory! Transformer harus di\ntanah kosong dan rata\ndi sebelah pabrik. Translation Terjemahan transparent station coverage jangkauan stasiun tampil tembus pandang Transported Perjalanan TrolleyBus_tab Busway Truck Truk tt_Other Lain-lain Tunnel muss an\neinfachem\nHang beginnen!\n Terowongan harus\ndimulai di\nkemiringan lurus.\n Tunnel must start on single way! Terowongan harus dimulai di jalan tunggal. Tunnelboden Terowongan underground mode tampilan bawah tanah UNDO failed! Tidak dapat dibatalkan lagi.\nPembatalan hanya dapat\ndilakukan jika tidak ada\nsinyal/stasiun/pemberhentian\natau apapun yang dibangun\ndi jalan. Undo last ways construction Batalkan pembangunan jalan terakhir Unemployed Pengangguran Unhappy Tidak senang units/day satuan per bulan Update Line Ubah rute upgrade HQ Perbaharui kantor pusat Usage: %.0f %% Pemakaian: %.0f %% Usage/Output Pemakaian/hasil Use beginner mode Menggunakan cara pemula Use timeline start year Mulai pada tahun: Vehicle %s can't find a route! Kendaraan %s tidak\nmenemukan jalan/jalur. Vehicle %s is stucked! Kendaraan %s tersangkut. Vehicle details Rincian kendaraan Verbrauch Konsumsi Vergroessere die Karte\n Perbesar peta.\n Verkauf Hapus verkaufen Jual Verkehrsteilnehmer Mobil kota Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Anda memiliki %d bulan\nuntuk membayar utang.\n via melewati(rincian) via %s\n lewat %s\n via Menge melewati(jumlah) voranstellen Taruh di depan Waggon_tab Gerbong waiting menunggu Waiting for clearance! Menunggu jalan kosong. Walked Berjalan kaki Warnings_msg Lalu lintas Wasser Air Water Kanal Water level Tinggi air: water vehicle kendaraan air way %s cannot longer used:\n Jenis jalan %s tidak dapat digunakan lagi.\n way %s cannot longer used:\n%s\n jenis jalan %s tidak dapat digunakan lagi:\n way %s now available:\n Jenis jalan %s tersedia sekarang.\n Way toll Tarif tol Ways not connected Jalan tidak terhubung Wegpunkt Titik arah Weight: Berat: Wert Nilai west Barat Winter snowline Garis salju musim dingin withdraw Tarik kembali Withdraw All Tarik kembali semua WRONGSAVE \nData permainan tidak sesuai.\nBerkas tidak dapat dimuat.\n Year %i has started. Tahun %i telah dimulai. Years Tahun Your primary color: Warna utama Anda: Your secondary color: Warna kedua Anda: Zielort tujuan zooming in lihat lebih dekat zooming out lihat lebih jauh Zu nah am Kartenrand Anda tidak dapat\nmembangun di dekat\npinggiran peta. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Melayang di atas magnet dengan\n%.1f km/h oleh %s:\nRekor baru! New world record for monorails: %.1f km/h by %s. MHX NEWS: Rekor kecepatan di dunia Monorel terpecahkan dengan kecepatan: %.1f km/h oleh %s. Selamat kepada Human, silahkan hubungi forums.simutrans.com untuk berbagi kisah anda dalam bermain game ini. New world record for motorcars: %.1f km/h by %s. MHX NEWS: Rekor kecepatan di dunia Jalan Darat terpecahkan dengan kecepatan: %.1f km/h oleh %s. Selamat kepada Human, silahkan hubungi forums.simutrans.com untuk berbagi kisah anda dalam bermain game ini. New world record for narrowgauges: %.1f km/h by %s. Rekor baru untuk kereta rel sempit: %.1f km/h oleh %s. New world record for planes: %.1f km/h by %s. MHX NEWS: Rekor kecepatan di dunia Pesawat Terbang terpecahkan dengan kecepatan: %.1f km/h oleh %s. Selamat kepada Human, silahkan hubungi forums.simutrans.com untuk berbagi kisah anda dalam bermain game ini. New world record for railways: %.1f km/h by %s. MHX NEWS: Rekor kecepatan di dunia Kereta Api terpecahkan dengan kecepatan: %.1f km/h oleh %s. Selamat kepada Human, silahkan hubungi forums.simutrans.com untuk berbagi kisah anda dalam bermain game ini. New world record for ship: %.1f km/h by %s. MHX NEWS: Rekor kecepatan di dunia Kapal Laut terpecahkan dengan kecepatan: %.1f km/h oleh %s. Selamat kepada Human, silahkan hubungi forums.simutrans.com untuk berbagi kisah anda dalam bermain game ini. simutrans-124.3/simutrans/text/id/000077500000000000000000000000001474050137200171605ustar00rootroot00000000000000simutrans-124.3/simutrans/text/id/general.txt000066400000000000000000000061221474050137200213370ustar00rootroot00000000000000Simutrans Help

General Help

- Welcome
- Game Interface
- Mouse Help (to be written)
- Keyboard Help
Game Options
- Language
- Player Colour
- Display Settings
- Sound & Music
- Players
- Load Game
- Save Game
- New Game
- - Climate Control
- - Load Height Map

Main Menu
- Game Options
- Map
- Inspection Tool
- Landscaping Tools Tools
- Railroad/Train Tools
- Monorail Tools
- Tram Tools
- Road Tools
- Harbour Tools
- Airport Tools
- Special Construction Tools
- Game Edit Tools
- Destroy/Remove

?Management Menu
- Line Management
- Lists
- - Stops/Station List
- - - Stops/Station List Filter
- - Vehicle List
- - - Vehicle List Filter
- - City List
- - Goods List
- - Industry List
- - Attractions List
- Message Centre
- Finances

Other Options
- Save Screenshot
- Pause
- Fast Forward
- Help

Other Dialogs
-Depot Controls
-Schedule Controls
- Stop Information
- - Stop Details
- Convoy/Vehicle Information
- - Convoy/Vehicle Details
- City Information
- Industry Information

If no help is found here, try
http://guide.simutrans.com, or
http://wiki.simutrans.com, or
http://simutrans-tips.com, or
http://forum.simutrans.com.

simutrans-124.3/simutrans/text/id/simutrans.txt000066400000000000000000000047521474050137200217560ustar00rootroot00000000000000About Simutrans

Welcome to Simutrans!

First, select a map: either choose one of Simutrans' thousands of maps or create a new one from a height map. Then put yourself in the shoes of a young entrepreneur with some money from your grandparents: eager to make them proud, with ambitions of establishing a successful transport company, your challenge now is to build a prosperous transport empire.

As time passes, develop your company into a successful enterprise, whilst at the same time keeping the economy running smoothly by delivering freight & satisfying the travel requirements of millions of passengers. You can transport passengers, mail and goods by rail, road, ship and even air.

Every map has something different to offer. Take a good look at your surroundings: their future lies in the hands of you and your competitors.

You may find it easiest to begin by supplying a power station with the goods it needs. With the money you've made, gradually expand by supplying other factories - maybe even using central hubs where goods are reloaded. The disadvantage of only transporting goods is that towns and cities won't grow and new industries will not appear.

Alternatively, you may immediately go for passenger (and mail) transport. This is more challenging, as the inhabitants of the Simutrans world all wish to travel to specific destinations Some need to go to factories to work, some want to go shopping in the city centre, and others want to visit tourist attractions. But if you don't offer a connection to their desired destination, passengers will not travel with you at all.

You will need to build a transport network where as many popular destinations as possible are reachable. When your network is established, you will need to continuously upgrade it to keep abreast of demand, so plan ahead! If passengers like your service, towns will grow, new industries will be established, and only then will the economy run smoothly.

You can play as long as you like. Start in 1880 and finish in 2050, or set a start time anywhere between these dates. There will be new vehicles and buildings throughout this time. Play against the AI or on your own. But watch out: if your net wealth is negative for three months in a row, you will go bankrupt and the game is over. Check your net wealth in the Finances window.

The Simutrans Team and the community wish you an enjoyable time playing Simutrans!

simutrans-124.3/simutrans/text/it.tab000066400000000000000000001426741474050137200177060ustar00rootroot00000000000000Italiano PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: it Italiano # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Inattivo cl_btn_filter_enable Attivo cl_btn_filter_settings Proprietà cl_btn_sort_asc Ascend. cl_btn_sort_desc Discend. cl_btn_sort_id ID interno cl_btn_sort_income Incasso cl_btn_sort_name Nome cl_btn_sort_type Tipo clf_btn_alle tutti clf_btn_invers inv. clf_btn_keine ness. Find matching convois Trova convogli corrispondenti gl_btn_sort_bonus per bonus gl_btn_sort_name per nome gl_btn_sort_revenue per incassi gl_btn_unsort non ordinato hl_btn_filter_disable Inattivo hl_btn_filter_enable Attivo hl_btn_filter_settings Proprietà hl_btn_sort_asc Ascend. hl_btn_sort_desc Discend. hl_btn_sort_name Nome hl_btn_sort_type Tipo hl_btn_sort_waiting Attesa hlf_btn_alle tutti hlf_btn_invers inv. hlf_btn_keine ness. humidities umidità Lake Lago Maximize height levels Massimizza livelli altezza Networks Reti Open Sea Mare Aperto Queueing Accodamento rainfall pioggia Return to menu Torna al menù Road toll Casello stradale sea mare Start this as a server Avvia come server Transfers Trasferimenti #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic clima artico desert clima desertico mediterran clima mediterr. rocky roccioso temperate temperato tropic clima tropicale #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Caricamento dello scenario fallito Bridge blocked by way below or above. Ponte bloccato da strada sopra o sotto. Can't buy obsolete vehicles! Non puoi comprare veicoli obsoleti! Cannot alter water Non puoi modificare l'acqua Cannot build on a double slope! Non è possibile costruire su una doppia pendenza! Cannot built depot here! Impossibile costruire deposito qui. Cannot built this station/building\nin underground mode here. L'edificio non può\nessere costruito sotto terra.\n Cannot connect to the\ncenter of a double slope! Impossibile connettersi al\ncentro di una doppia pendenza! Cannot create generic line!\nSelect line type by\nusing filter tabs. Impossibile creare linea generia!\nSelezionare tipo linea\nusando i filtri. Cannot create socket Non si può creare il raccordo Cannot rotate this building! Impossibile ruotare questo edificio! Client closed connection during transfer Il client ha chiuso la connessione durante il caricamento Convoi handles exhausted! Massimo numero di convogli raggiunto Convoy already deleted! Convoglio già cancellato! Could not open file Impossibile aprire il file Das Feld gehoert\neinem anderen Spieler\n Questo terreno\nè di proprietà\ndi un altro giocatore!\n Der Besitzer erlaubt das Entfernen nicht Il proprietario non\nconcede il permesso\ndi rimozione.\n Diese Zusammenstellung kann nicht fahren!\n Questa combinazione\nnon può viaggiare!\n Flugzeughalt muss auf\nRunway liegen!\n I velivoli devono\nstare su taxiway. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Non puoi costruire\n\nun terminal qui.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Impossibile mettere QUI\ndei segnali ferroviari!\n In order to lock the game, you have to protect the public player by password! Per bloccare il cambio giocatore devi proteggere il giocatore pubblico con una password! Loading a new game will end the current server session! Caricare un nuovo gioco terminerà la sessione del server corrente! Lost connection\nto server! Connessione persa con il server! Lost synchronisation\nwith server. Persa la sincronizzazione con il\n\nserver! Maglevhalt muss auf\nMaglevschiene liegen!\n Una fermata per maglev deve essere su una linea maglev! Monorailhalt muss auf\nMonorail liegen!\n Le fermate devono\nstare su una rotaia. Monorails are not available yet! Morotaie non ancora disponibili. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n una fermata per scartamento ridotto deve stare su una linea a scartamento ridotto No bridges over runways! Impossibile costruire ponti sopra le piste di decollo! No curves on runways Curve non ammesse su piste di decollo No suitable crossing Nessun incrocio adatto No suitable way on the ground! Serve un percorso No through station here! Non c'è nessuna stazione passante qui! Not enough clearance. Spazio insufficiente. Not enough money! Non hai abbastanza soldi per costruirlo! On narrowgauge track only!\n Solo su linee a scartamento ridotto!\n Only public player can lock games! Solo il giocatore pubblico può bloccare i giochi! Out of funds Denaro esaurito Post muss neben\nHaltestelle\nliegen!\n Un ufficio postale\ndeve essere ubicato vicino\nad una fermata/stazione!\n Protocoll error (expecting game) Errore nel protocollo (aspettando il gioco) Schiffhalt muss im\nWasser liegen!\n Le fermate delle barche\npossono essere piazzate\nsolo sull'acqua\nvicino ad un attracco!\n Server busy Server sovraccarico Server version too new Aggiorna la versione del gioco, quella del server è avanzata. Terraforming not possible\nhere in underground view Il terraforming è impossibile sottoterra. This tunnel branches. You can try Control+Click to remove. Questo tunnel si ramifica. Puoi provare Control+click per rimuovere. Too far away to merge stations! Stazioni troppo lontane per unirle! Upgrade must have\na higher level L'aggiornamento deve essere a un livello superiore Vehicle %s cannot choose because stop too short! Il veicolo %s non può scegliere, fermata troppo corta! Zughalt muss auf\nSchiene liegen!\n Le fermate ferroviarie\npossono essere piazzate\nsolo sui binari!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Aiuto tastiera\n

Aiuto tastiera

\n

\nAiuto tastiera Mostra le funzioni per vari tasti premuti sulla tastiera\n

\n

\nAiuto tastiera si apre quando viene premuto un tasto non assegnato o da Aiuto generale.\n

\n

\nLe maiuscole sono diverse dalle minuscole (usare [Shift] per lettere maiuscole).\n

\n

\nTasti con le funzioni assegnate includono: \n

\n

\n[Tasti freccia]: muovi la vista nel senso della freccia.
\n[Backspace]: chiude tutte le finestre,barre e testi d'aiuto nella vista.
\n[Cancella], o [Esc]: chiude la finestra,barra o aiuto in primo piano sulla vista.
\n[Enter], or [Return]: usato per confermare azioni.
\n[Pagina su], o [>]: aumenta zoom.
\n[Pagina giù], o [simbolo "minore di"]: diminuisce zoom.\n[F1]: apre Aiuto Simutrans.

\n

\n[1]: muove la vista verso sud.
\n[2]: muove la vista verso sud-est.
\n[3]: muove la vista verso est.
\n[4]: muove la vista verso sud-ovest.
\n[6]: muove la vista verso nord-est.
\n[7]: muove la vista verso ovest.
\n[8]: muove la vista verso nord-ovest.
\n[9]: muove la vista verso nord.\n

\n

\n[Shift] + mouse: usato in Map per vedere collegamenti in Catena approvvigionamenti industrie.
\n[CTRL] + strumento: costruisce (segnali & fermate) al livello più alto; o costruisce strade più veloci sulle più lente; o più dritte (più dirette) strade e ferrovie.
\n[CTRL] + ([F2] fino a [F12]): seleziona lo strumento richiamato da [F2] a [F12].\n

\n

At least one stop is connected to the town. Almeno una fermata è collegata alla città. Decrease water height Diminuisci altezza acqua Highlight railroad tracks Evidenzia le ferrovie Highlite depots Evidenzia i depositi Highlite electrical transmission lines Evidenzia le linee elettriche Highlite factories Evidenzia le fabbriche Highlite forests Evidenzia le foreste Highlite tourist attraction Evidenzia le attrazioni turistiche Increase water height Aumenta altezza acqua Open station/stop details Apri dettagli stazioni/fermate Overlay city limits Sovrapponi i limiti delle città Overlay passenger destinations when a town window is open Sovrapponi le destinazioni dei passeggeri quando la finestra della città è aperta Overlay schedules/network Sovrapponi i percorsi/reti Overlay town names Sovrapponi i nomi delle città Please click on the map to add\nwaypoints or stops to this\nschedule. Click sulla mappa per aggiungere\npassaggi o fermate a questo\npercorso. Set tile climate %s Imposta il clima della casella %s Show capacity and if halt is overcrowded Mostra la capacità e se la fermata è sovraccarica Show how many convoi reach a station Mostra quanti convogli raggiungono una stazione Show how many people/much is waiting at halts Mostra quante persone e quanto tempo sono in attesa alle fermate Show initial passenger departure Mostra l'origine dei passeggeri Show level of city buildings Mostra il livello degli edifici cittadini Show mail service coverage/mail network Mostra la copertura del servizio postale / la rete postale Show passenger coverage/passenger network Mostra la copertura del servizio passeggeri / la rete passeggeri Show speedlimit of ways Mostra il limite di velocità delle strade Show the change of waiting at halts Mostra il cambio di attesa alle fermate Show the owenership of infrastructure Mostra il proprietario delle infrastrutture Show transported freight/freight network Mostra le merci trasportate / la rete merci Show usage of network Mostra l'utilizzo della rete Shows a listing with all industries on the map. Mostra la lista delle industrie sulla mappa Sum of departure/arrivals at halts Somma di partenze/arrivi alle fermate #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s ora\noffre servizio bus\ntra %s\ne l'attrazione\n%s\na (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s ora\noffre servizio bus\ntra %s\ne l'industria\n%s\na (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nora fa viaggiare\n%i camion tra\n%s a (%i,%i)\ne %s\na (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\ninaugura una nuova ferrovia\ntra %s\na (%i,%i) e\n%s\na (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Servizio aereo da\n%s\nadesso tra\n%s \ne %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Servizio navale tra\n%s\nadesso tra\n%s\ne%s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s apre un nuovo servizio bus tra %s e %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Strumenti per modifica mappa LISTTOOLS Liste MAGLEVTOOLS Strumenti maglev MONORAILTOOLS Strumenti monorotaia/maglev NARROWGAUGETOOLS Strumenti linea a scartamento ridotto RAILTOOLS Strumenti ferrovia ROADTOOLS Strumenti strade SHIPTOOLS Strumenti porto SLOPETOOLS Movimenti terra SPECIALTOOLS Strumenti costruzione speciali TRAMTOOLS Strumenti tram/ferrovia leggera #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s ha costruito una nuova sede. Factory chain extended\nfor %s near\n%s built with\n%i factories. L'economia si sta allargando:\n%s vicino %s allarga la catena.\n%i nuove fabbriche sono state fondate Net wealth less than 10%% of starting capital! Ricchezza netta inferiore al 10%% del capitale iniziale! New %s now available:\n%s\n Nuovo %s ora disponibile:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Nuova rete d'industrie\nper %s vicino a\n%s costruita con\n%i industrie. New vehicle now available:\n%s\n \n Un nuovo veicolo è\n ora disponibile:\n\n\n -- %s --\n\n Now %u clients connected. Adesso sono connessi %i giocatori. overtaking sorpasso Remove vehicle from map. Use with care! Rimuovi veicolo dalla mappa.(Attenzione!) Screenshot\ngespeichert.\n Schermata\nsalvata.\n Sends the convoi to the last depot it departed from! Manda convoglio all'ultimo deposito da cui è partito Trees Alberi With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Con una grande festa,\n%s ha costruito\nun nuovo monumento.\n%i cittadini festeggiano. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Filtro Linee #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (in deposito) /month /mese \nBauzeit bis \nfino al \nBauzeit von \nCompare dal \nCan't open heightfield file.\n \nFile dei rilievi non leggibile.\n \ndirection: \ndirezioni: \nelektrified \nelettrificata \nHeightfield has wrong image type.\n \nLa mappa dei rilievi è in un formato\ndi immagine errato.\n \nis reserved by: \nriservata da: \nminimum speed: \nvelocità minima: \nnot elektrified \nnon elettrificata\n \nRibi (masked) \ndirezioni\m (mascherate): \nRibi (unmasked) \ndirezioni\n(visibili): \nSet phases: \nregola lunghezza ns/ew: \nsingle way \nSingola Via \nway1 reserved by via 1 risevata da\nvia 1 riservata da \nway2 reserved by via 2 riservata da\nvia 2 riservata da \nwith sign/signal\n \ncon cartello/segnale\n %d buildings\n %d palazzi\n %d convois %d convogli %d Einzelfahrzeuge im Depot %d veicoli in deposito %i car(s), %i auto, %i km/h (max. %ikm/h) %i km/h (max %ikm/h) %i years %i months old. ha %i anni e %i mesi. %s at (%i,%i) now public stop. %s (coordinate %i,%i) è divenuta fermata pubblica. %s building %s %s %s %s %s %s city %d %s %s città %d %s %s factory %s %s %s fabbrica %s %s %s has entered a depot. %s è in deposito. %s land %d %s %s terreno %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s ha speso\nsoldi per costruire un\nnuovo municipio\nquando ha raggiunto\n%i abitanti. %s\nis crowded. %s è congestionata! %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nVelocità %i\nVelocità massima %i\ndx:%i dy:%i %s\nwas liquidated. %s\nè stato liquidato. %u Client(s)\n %i Connesso(i)\n %u Player (%u locked)\n %u Giocatore (%u bloccato)\n

Warning

addons for

Attenzione

addons per 1 convoi 1 convoglio 1 Einzelfahrzeug im Depot 1 veicolo in deposito 100 km/h = %i tiles/month 100 km/h = %i caselle/mese 1LIGHT_CHOOSE Luminosità: 1WORLD_CHOOSE Opzioni della nuova mappa: 2LIGHT_CHOOSE Colori: 2WORLD_CHOOSE Numero mappa: 3LIGHT_CHOOSE Vel. scrolling: 4LIGHT_CHOOSE Inverti scrolling 5LIGHT_CHOOSE Mostrare pedoni 5WORLD_CHOOSE Numero città: 6LIGHT_CHOOSE Pedoni in città 6WORLD_CHOOSE Densità traffico: 8WORLD_CHOOSE Modalità giorno e notte A bridge must end on a way! I ponti devono\nfinire su un\ntracciato esistente. A bridge must start on a way! I ponti devono\niniziare su un\ntracciato esistente. Abfrage Lente Abnehmer Clienti About Info About scenario Info scenario Abriss Distruggi/Rimuovi Absenken Abbassa terreno Abspanntransformator Trasformatore Accelerate time Accelera il tempo Act. load: %u MW\n Carico attuale:%u MW\n Active player only Solo giocatore attivo Add forest Aggiungi foresta Add random citycar Aggiungi auto casuale add server Aggiungi server Add Stop Aggiungi Add stops for backward travel Aggiungi fermate viaggio ritorno air pista di rullaggio Aircraft Aereo aircraft_tab Aerei merci airplane aeroplano Airport Aeroporto AIRTOOLS Strumenti aeroporto All Tutto all convoi tooltips Tutti i richiami dei convogli Allow city growth Permetti crescita città Allow player change Consenti cambio giocatore allowed climates:\n climi permessi Alters a schedule. Aggiungi/rimuovi fermate da percorso Angenommene Waren Prodotti necessari da impianti vicini anhaengen Aggiungi Anhaenger_tab Rimorchi Anheben Alza terreno Appends stops at the end of the schedule Aggiungi fermate alla fine del programma Apply Line Applica Linea April Aprile Arbeiter aus: Lavoratori da: Arrivals from\n Arrivi da\n Arrived Arrivati Aufloesen Disassembla Aufspanntransformator Trasformatore August Agosto Autohalt muss auf\nStrasse liegen!\n Le fermate dei veicoli\ndevono stare\nsu una strada. Available Disponibili Bahndepot Deposito treni Bankrott:\n\nDu bist bankrott.\n Bancarotta:\n\nSei fallito!\n battery Non esiste! Baum Albero baum builder Pianta alberi Baustelle Cantiere\nedile Bauzeit avanza nel tempo Beenden Esci Beginner mode Modalità principiante Besonderes Gebaeude Attrazione Turistica BF stazione bio biologico Blockstrecke ist\nbelegt\n Questo tratto di\nlinea è usato\nda un altro treno\n Boden Terreno Bonus Speed: %i km/h Bonus Velocità: %i km/h Bonusspeed: %i km/h Bonus velocità: %i km/h Boost (%%) Incremento (%%) bridge is too high for its type! Ponte troppo alto per il suo tipo Bridge is too long for this type!\n La campata è\ntroppo lunga per\nquesto tipo di ponte.\n Bruecke Ponte Bruecke muss an\neinfachem\nHang beginnen!\n Un ponte deve\niniziare su un\nterreno pianeggiante!\n Brueckenboden ponte Build air depot Costruisci deposito aerei build choosesignals Costruisci segnali di scelta Build city market Costruisci un mercato nella città più vicina. Build drain Trasformatore build HQ Costruisci sede Build land consumer Costruisci nuova stazione di potenza. Build maglev depot Costruisci deposito maglev Build monorail depot Costruisci deposito monorotaia Build narrowgauge depot Costruisci deposito per ferrovia scartamento ridotto Build powerline Costruisci linea elettrica Build presignals Costruisci presegnali Build road depot Costruisci deposito veicoli Build ship depot Costruisci deposito navale Build signals Costruisci segnale Build train depot Costruisci deposito treni Build tram depot Costruisci deposito tram Build truck depot Costruisci deposito veicoli Building costs estimates Stima costo costruzione Buildings Numero edifici Built artifical slopes Costruisci pendio artificiale Built random attraction Costruisci attrazione casuale Bus_tab Bus Can only move from halt to halt or waypoint to waypoint. Si può solo muovere\nda fermata a fermata o\n da punto a punto. Cancel Annulla Cannot connect to offline server! Impossibile connettersi, server offline! Capacity Capacità Capacity: Capacità: Capacity: %.0f MW Capacità: %.0f MW\n Capacity: %d%s %s\n Capacità: %3d %s %s\n Capacity: %s\nLoad: %d (%d%%) Capacità: %s\nCarico: %d (%d%%) Cars are not available yet! Automobili non ancora disponibili. cars.\nstate auto\n Cash Cassa Change player Cambia giocatore Chart Grafico Chat_msg Chat Choose direction Scegli direzione Choose operation executed on clicking stored/new vehicles Scegli operazione eseguita selezionando veicoli nuovi o in deposito chooses a random map Sceglie mappa casuale. citicens Cittadini City attraction Attrazione cittadina City industries Mercati in città City list Lista città City size Dimensioni city_road Strade urbane citybuilding builder Costruisci edifici urbani CityLimit Limiti città cl_title Lista veicoli cl_txt_sort Ordina per: Clear block reservation Mostra/nascondi vie riservate clf_chk_aircrafts Aereoplani clf_chk_cars Bus/Camion clf_chk_indepot in deposito clf_chk_maglev Maglev clf_chk_monorail Monorotaia clf_chk_name_filter Filtro per nome: clf_chk_narrowgauge Treni a scartamento ridotto clf_chk_noincome nessun incasso clf_chk_noline nessuna linea clf_chk_noroute nessuna rotta clf_chk_noschedule nessun percorso clf_chk_obsolete obsoleto clf_chk_ships Imbarcazioni clf_chk_spezial_filter Filtro speciale: clf_chk_stucked bloccato clf_chk_trains Treni clf_chk_trams Tram clf_chk_type_filter Filtro per tipo: clf_chk_waren Filtro per merci: clf_title Filtro Lista Veicoli Climate Clima Climate Control Controllo clima Climates Climi closed chiuso COLOR_CHOOSE\n Per favore scegli\nun colore dalla\ntabella:\n Company bankrupt Compagnia in bancarotta Company_msg Concorrenti Comparing pak files ... Comparazione pak files... Configure AI Configura AI Configure AI setttings Configura impostazioni AI Congratulation\nScenario was complete in\n%i months %i years. Congratulazioni!\nLo scenario è stato\ncompletato in\n%imesi e %i anni! Connected stops Fermate collegate Connected with server Connesso al server Connections Connessioni Constructed by Disegno di Constructed by %s Disegno di %s construction speed velocità di costruzione Construction_Btn Costi costruzione Consumed Consumato convoi %d of %d Convoglio %d di %d convoi error tooltips Richiami errori convogli Convoi following mode Modalità inseguimento convoglio Convoi has been sent\nto the nearest depot\nof appropriate type.\n Convoglio deviato al deposito più vicino Convoi is sold when all wagons are empty. Il convoglio viene venduto quando tutti i vagoni sono vuoti. convoi mouseover tooltips Richiami convogli con mouse sopra convoi passed last\nmonth %i\n \nconvogli nell'ultimo\nmese: %i\n Convois Convogli Convois: %d\nProfit: %s Veicoli: %d\nProfitto: %s Convoys Convogli Copy Convoi Copia Convoglio Copy the selected convoi and its schedule or line Copia convoglio selezionato con percorso o linea Cost Costo cost for removal Costi per rimozione Cost per unit Costo per unità Cost: %8s (%.2f$/km %.2f$/m)\n Costo: %8s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Costo: %8s (%.2f$/km)\n Costs Costi Create a new line based on this schedule Crea nuova linea da questo percorso curiosity builder Costruzione curiosità curlist_title Lista attrazioni Currently playing: Brano in esecuzione: Customers live in: Clienti abitano a: deactivated in online mode Non attivo online. Deccelerate time Rallenta tempo December Dicembre decrease underground view level Diminuisci livello visione sotterranea Del Stop Rimuovi Delete Line Cancella linea Delete the current stop Cancella la fermata corrente Delete the selected line (if without associated convois). Cancella la linea selezionata (se senza veicoli associati). Delete this file. Cancella questo file Delivered Consegnati Demand Richiesta Demand: %.0f MW Domanda %.0f MW\n Denkmal Monumento Departed Partiti Departs at Parte alle Departure after Partenza dopo Departure board Tabella partenze Departures per month Partenze al mese Departures to\n Partenze per\n Depot Deposito Depots Depositi Der Tunnel ist nicht frei!\n Galleria non vuota.\n Destination Destinazione Destroying map ... Distruzione della mappa... Details Dettagli Die Bruecke ist nicht frei!\n Il ponte non è libero!\n Direkt erreichbare Haltestellen Collegamenti diretti da qui disable midi Disabilita MIDI Display settings Modifica colori Distance Distanza distributing cities distribuzione città distributing factories distribuzione industrie Dock porto Dock must be built on single slope! I porti si costruiscono su unica livelletta. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Hai %d mesi per ripagare i debiti. Durchsatz Max. prod. Economy Economia e città Eigenbesitz\n Proprietà pubblica\n Ein %s\npasst hier nicht.\n Un '%s'\nnon va bene qui!\n Einstellungen Impostazioni Einstellungen aendern Cambia opzioni electric elettrico Electricity Elettricità Electricity producer\n\n Produttore elettricità\n\n Electrics_tab Veicoli elettrici Electrify track Elettrifica enlarge map Allarga mappa enter a value between %i and %i Inserisci un valore tra %i e %i Enter address Inserire l'indirizzo Enter Password Inserire Password Error Errore Erzeuge neue Karte.\n Attendere prego,\nsto creando una\nnuova mappa...\n\n(Per grandi mappe,\nquesta operazione\npuò richiedere anche\nalcuni minuti)\n Es wird bereits\nein Fahrplan\neingegeben\n Hai già iniziato\nad inserire un percorso!\n Fabrikanschluss Fabbriche connesse Fabrikname Nome fabbrica Factories Fabbriche factory details Dettagli fabbrica factorybuilder Costruisci fabbriche Fahrplan Percorso Fahrtziel Destinazione: Fahrzeuge koennen so nicht entfernt werden I veicoli non\npossono essere\nrimossi.\n Fahrzeuge: Veicoli: Farbe Colore giocat. Fast forward Tempo accelerato February Febbraio Ferry_tab Traghetti Fertig Fatto Filename Nome file: Files from: Files da: Filter: Filtro: Finances of %s Finanze di %s Finanzen Finanze find mismatch Compara il pak fl_title Lista fabbriche Flug_tab Aereo Passeggeri follow me Seguimi Follow the convoi on the map. Segui convoglio sulla mappa For questions and support please visit: Per domande e supporto visitare: Forest Foresta Found new city Fonda nuova città Fracht Merce Frame time: Tempo Frame: Free Capacity Capacità disp. freeplay mode Modalità gioco libero Friction: fattore frizione attuale: fuel_cell celle combustibile Full load Carico: Fundament Fondazione Fussgaenger Pedoni Game info Informazioni gioco GAME PAUSED GIOCO IN PAUSA Game_msg Generale Gear: Rapporti: Gebaeude Edificio General Generale Generated Generati Generation: %.0f MW Generazione: %.0f MW\n Gewicht Peso Gewinn Profitti: Give the selected vehicle(s) an individual schedule Dai al veicolo(i) selezionato un percorso individuale. gl_btn_sort_catg Categoria gl_title Lista di tutti i beni go home Al deposito Goods Merci Goods AI Merci IA Goods list Lista beni Gross Profit Utile lordo Groundobj Oggetto Grow city Ingrandisci Growth Crescita città H fermata Happy Felice Haus kaufen Compra casa Helligk. Grafica Help Aiuto Help text not found Testo della guida non trovato. hide all building Nascondi edifici hide city building Nascondi edifici città hide objects under cursor nascondi gli oggetti sotto il cursore hide station names nascondi nomi stazioni hide transparent Nascondi trasparenti hide trees Nascondi alberi Hier warten/lagern: Passeggeri/merci in attesa: Higher transport fees, crossconnect all factories Tasse di trasporto più alte, disabilita Just-in-time. Highlite schedule Evidenzia percorso hl_title Lista stazioni/fermate hl_txt_filter Filtro: hl_txt_sort Ordina per: hlf_chk_airport Aeroporti hlf_chk_anleger Porti hlf_chk_bahnhof Stazione ferrov. hlf_chk_bushalt Fermata bus hlf_chk_frachthof Piazz. di carico hlf_chk_keine_verb Senza conness. hlf_chk_maglevstop Stazione maglev hlf_chk_monorailstop Fermata monorail hlf_chk_name_filter Filtro per nome: hlf_chk_narrowgaugestop Stazione linea a scartamento ridotto hlf_chk_overflow Oltre Capacità hlf_chk_spezial_filter Filtro speciale: hlf_chk_tramstop Fermata tram hlf_chk_type_filter Filtro per tipo: hlf_chk_waren_abgabe Produzione: hlf_chk_waren_annahme Merci necessarie: hlf_title Filtro Lista Stazioni/Fermate Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Impossibile trovare deposito.\nManda il veicolo\nmanualmente. Homeless Senzatetto hydrogene Idrogeno Idle: Inattivi: ignore climates Ignora clima In the industry legend show only currently existing factories Nella legenda delle industrie mostra solo le fabbriche esistenti In Transit In Transito Increase Industry density Aumenta densità industrie increase underground view level Aumenta livello di visione sotterranea industrial building Edificio industriale Init map ... Costruzione mappa ... Ins Stop Inserisci Insert stop before the current stop Inserisci fermata prima della corrente Insufficient funds! Fondi insufficenti! Intercity road len: Lunghezza strade interurbane: Intro. date Data intro. Intro. date: Data intro.: invalid indefinito Invalid coordinate Ordine non valido Invert stops Inverti le fermate isometric map Mappa isometrica January Gennaio join game Gioca online! July Luglio Jump to Salta a June Giugno Kann Spielstand\nnicht laden.\n Impossibile leggere/aprire\nil file!\n Kann Spielstand\nnicht speichern.\n Impossibile aprire\nil file in\nscrittura!\n Kein Besitzer\n Nessun proprietario keine nessuno Keine Einzelfahrzeuge im Depot Nessun veicolo in deposito Keyboard_Help\n Aiuto tastiera\n koord Coordinate Kreuzung Attraversamento labellist_title Lista dei marcatori Lade Relief Carica Rilievo Laden Carica Land attraction Attrazioni della zona Land industries Industrie fuori città: LANG_CHOOSE\n Per favore scegli\nuna lingua:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Ultimo Mese Last used tools Ultimo strumento utilizzato Last Year Anno Scorso Leaving depot! Sto uscendo dal deposito! leer vuoto Legend Legenda Leistung Potenza Leistung: %d kW Potenza: %d kW Leitung Elettrodotto length: %d lunghezza: %d letzen Monat: diesen Monat: scorso mese: questo mese: Line Linea Line Management Gestione Linee Lineless convoys serving this stop Convogli senza linea che si fermano qui Lines serving this stop Linee passanti List of industries on the map Elenco industrie sulla mappa LKW_tab Camion Load game Apri file load height data from file Apri rilievo da file. Load scenario Carica scenario loaded caricato loaded passenger/freight Ordina passegeri/merci per Loading (%i->%i%%)! Caricamento (%i->%i%%) Loading (%i%%) departure %s! Caricando (%i%%) partenza %s! Loading (%i%%)! Caricando (%i%%)! Loading addon paks ... Caricamento pacchetti aggiuntivi... Loading map ... Caricamento mappa ... Loading paks ... Caricamento pacchetti... Loading skins ... Caricamento maschere... Loading time: Tempo di caricamento: Lock game Vieta cambio giocatore (richiede conferma). Lokomotive_tab Motrici m3 m³ maglev vehicle veicolo maglev maglev_track Linea maglev Maglevdepot Deposito maglev Mail Demand %d\n Richiesta di posta %d\n Mailbox Centro Messaggi Mailbox Options Opzioni Centro Messaggi Maintenance Manutenz. edifici make stop public (or join with public stop next) costs %i per tile and level far diventare la fermata pubblica (o collega a fermata pubblica vicina) costa %i$ per area e livello Make way or stop public (will join with neighbours), %i times maintainance Rendere pubblica fermata o strada (si unirà ai vicini), %i volte la manutenzione Manual (Human) Manuale (umano) Manufactured: Prodotti: Map roughness Asprezza terreno: map zoom Zoom March Marzo Margin (%%) Margine (%%) Marker Cartello Max Boost (%%) Incr. max. (%%) Max income: Guadagno max: Max. speed Velocità max. Max. speed: Velocità max.: Maximum 254 stops\nin a schedule!\n Al massimo 254 fermate\nin un percorso!\n maximum length of rivers Lunghezza max. fiumi Maximum tile height difference reached. Massimo dislivello\ntra due blocchi\ndi terreno\nraggiunto. Maxspeed Velocità massima May Maggio Median Citizen per town Media abitanti per città: Meldung Messaggio Menge ammontare merge stop unisci fermate MessageOptionsText \nNuovo Anno\n\nNotizie Avversari\n\nNotizie Città\n\nPercorsi Ostruiti\n\nNuove Fabbriche\n\nChat\n\nNuovi Veicoli\n\nStazioni Piene\n\nProblemi\n\nIngorghi Traffico min min. minimum length of rivers Lunghezza min. fiumi Missing pakfiles Nessun pak trovato Modify the selected line Modifica linea selezionata Monate alt mesi di età Monorail Monorotaia monorail vehicle Veicolo monorotaia monorail_track Linea monorail Monorailboden Suppporto Monorotaia Monoraildepot Deposito Monorotaia Month Mese month wait time Attesa mensile Monthly departures Partenze mensili Months Mesi Monument Monumento Monuments Monumenti Mountain height Altezza montagne: Movingobj Oggetto in movimento Music playing disabled/not available Musica disabilitata o non disponibile Music volume: Volume musica: mute sound Elimina suoni Name Nome Narrowgauge Linea a scartamento ridotto Narrowgauge are not available yet! Linea a scartamento ridotto non è ancora disponibile! narrowgauge vehicle Veicolo per linea a scartamento ridotto narrowgauge_track Linea a scartamento ridotto Narrowgaugedepot Deposito mezzi a scartamento ridotto Net ID: %p ID rete: %p\n Net Wealth Valore netto Net wealth near zero Valore netto prossimo a zero Neue Karte Nuova mappa Neue Welt Crea Nuovo Mondo new convoi Nuovo convoglio New Line Nuova linea New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nuova linea creata!\nPuoi assegnare la linea\nselezionandola dal\nmenu sopra. New Vehicles Nuovi veicoli no buildings hidden Nessun edificio nascosto no convois nessun convoglio No goods are loaded onto this convoi. Nessun bene sarà caricato sul convoglio no goods waiting nessuna merce in attesa no load No carico No Route Senza percorso No stop here! Lo strumento deve essere usato nelle aree di fermata No suitable ground! Terreno non disponibile No terminal station here! Non c'è nessuna stazione terminale! no timeline no linea del tempo no tree Nessun albero No vehicles are available for purchase. Nessun veicolo è disponibile per l'acquisto. No. of Factories Numero di fabbriche Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Assegna un percorso\nal veicolo prima\ndi dargli l'ordine\ndi partire!\n none nessuno nord Nord nordost Nord-Est nordwest Nord-Ovest Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Il percorso del veicolo\nnon può esser cambiato\ndurante la ricerca del percorso. Not enough fields would remain. Non rimarranno abbastanza\nterreni intorno a questa fattoria November Novembre now adesso Now active as %s.\n Ora attivo come %s.\n Number of rivers Numero di fiumi Object Oggetto Odometer: %s km Tachimetro: %skm Oktober Ottobre On loan since %i month(s) In debito da %i mese/i On this map, you are not\nallowed to change player!\n Le impostazioni della partita\nnon permettono il cambio di giocatore.\n Only city chains Solo catene di città Only first %d differing paks reported. There are probably more. Solo i primi %d paks differenti sono segnalati. Probabilmente le differenze sono di più. Only land chains Solo catene di campagna Only one transformer per factory! Solo un trasformatore per fabbrica! Only show goods which are currently handled by factories Mostra solo i beni che sono attualmente gestiti dalle fabbriche open apri Operation Costi Operativi Ops Profit Profitti Optionen Opzioni Or enter a server manually: O inserire manualmente il server: Origin Origine ost Est Ownership Proprietà Pak which may cause severe errors: Pak che può causare errori gravi: Pak which may cause visual errors: Pak che può causare errori di visualizzazione: Pak(s) different: Pak(s) differente: Pak(s) missing on client: Pak(s) mancanti sul client: Pak(s) not on server: Pak(s) non sul server: Pakset differences Differenze del Pakset paletten casse Pas_tab Treni Passeggeri Passagiere Passeggeri Passagierrate Livello Passeggeri Passagierziele Destinazioni passeggeri/posta Passenger AI Passeggeri IA Passenger Demand %d\n Richiesta di passeggeri %d\n Passengers %d %c, %d %c, %d no route Passeggeri %d %c, %d %c, %d non serviti Passengers %d %s, %d %s, %d no route Passeggeri %d %s, %d %s, %d non serviti Password Password: Pause Pausa Pax <%i> Mail <%i> Passeggeri <%i> Posta <%i> PaxDest Destinazioni Percent Electricity Produzione elettricità(%% domanda) Planes are not available yet! Aerei non ancora disponibili. Plant tree Pianta alberi player Giocatore player -1 umano player 0 servizio pubblico player 1 Napik 128 AS player 10 giocatore 10 player 11 giocatore 11 player 12 giocatore 12 player 13 giocatore 13 player 2 Tricchi Trasporti player 3 Fratelli Bianchi Trasporti player 4 Società Anonima Trasporti player 5 Trasporti Veloci Spa player 6 PSK & Co KG player 7 giocatore 7 player 8 giocatore 8 player 9 giocatore 9 Please choose vehicles first\n Scegli prima i veicoli!\n Post Posta Postrate Livello Posta Power Potenza Power (MW) Potenza (MW) Power: Potenza: Power: %4d kW\n Potenza: %4d kW\n Powerlines Elettrodotti Price Prezzo Problems_msg Problemi Produced Prodotti Produces: %.1f units/minute Produce: %.1f unità/minuto Production of %s has been stopped:\n%s\n Produzione di %s è stata interrotta:\n%s\n Production/Boost Produzione/Incremento Produktion Produzione Profit Profitti promote to line Promuovi a linea q1 Primav. q2 Estate q3 Autunno q4 Inverno Query server Interroga server rail car treno random casuale Random age Anno casuale Random map Mappa casuale Rathaus Municipio Rating Valutazione ratio_pax Percentuale passeggeri Relevant Rilevante Reliefkarte Mappa Remove Rimuovi remove airstrips Rimuovi aeroporto remove channels rimuovi canali remove interm. signals Rimuovi segnali intermedi remove maglev tracks rimuovi linee maglev remove monorails rimuovi rotaia remove narrowgauge tracks rimuovi linee a scartamento ridotto remove powerlines rimuovi linee elettriche remove roads rimuovi strada remove signal rimuovi segnale remove tracks rimuovi binari Remove wayobj %s Rimuovi oggetto %s replace other signals Sostituisci altri segnali replace stop ripristina fermata request closing richiedi chiusura residential house Abitazione Restore natural slope Ripristina pendio naturale. Restwert: Prezzo di vendita: Retire date Data ritiro Retire. date: Data ritiro: return ticket Replica ritorno Revenue Entrate Revenue/unit/100 tiles Entrate/unità/100 caselle Revision: Revisione: road strada road vehicle Veicolo da strada Roadsign Cartello Stradale Rotate Building Ruota Edificio Rotate map Ruota mappa Rotation Rotazione sack sacchi sail vela Saving map ... Salvataggio mappa ... Scenario complete: %i%% Scenario completo: %i%% Schedule changing! Cambio programma! Schienentunnel Costruisci tunnel ferroviario Schiff_tab Imbarcazioni Schiffdepot Deposito imbarcazioni Schleppkahn_tab Chiatte Screenshot Cattura schermata Search: Cerca: Seasons stagioni Sehenswuerdigkeit Attrazione turistica Select a server to join: Scegli un server al quale aderire: Select a theme for display Scegli un tema Sell the selected vehicle(s) Vendi veicolo(i) selezionato. Selling of the program is forbidden. È vietata la vendita di questo programma. sended Spedito SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September Settembre Served by Servito da Served by me Servito da me Server did not respond! Il server non risponde! Serves Line: Serve linee: Service Servizio set signal spacing Imposta distanza segnali Setting Opzioni Ship Imbarcazione shops and stores Negozi ed uffici Show all Mostra tutto show all building Visualizza tutti gli edifici Show also vehicles no longer in production. Mostra anche veicoli non più prodotti. Show also vehicles that do not match for current action. Mostra anche veicoli non adatti. Show even servers with wrong version or pakset Visualizza i server che forniscono una versione sbagliata del pakset. show grid Mostra griglia Show industry Mostra fabbriche Show legend Mostra legenda Show map scale Scala valori Show mismatched Mostra le mancate corrispondenze Show obsolete Mostra Veicoli Vecchi Show offline Mostra offline Show only used Mostra solo quelli utilizzati Show schedules Mostra programmi Show servers that are offline Mostra i server che sono offline Show servers where game version or pakset does not match your client Mostra i server dove il gioco o il pak non combaciano con la propria versione show station coverage Mostra copertura stazione show station names Mostra nomi stazioni show waiting bars Visualizza barre di attesa show/hide block reservations mostra/nascondi blocco prenotazioni Show/hide estimated arrival times mostra/nascondi tempi di arrivo stimati show/hide object owner mostra/nascondi possessore dell'oggetto Show/hide statistics Mostra/Nascondi Statistiche Shows buttons on special topics. Mostra i pulsanti relativi a particolari temi. Shows consumer/suppliers for factories Mostra clienti/fornitori per fabbrica Shows the color code for several selections. Mostra il codice colore per diverse selezioni. Shows the currently selected schedule Mostra la linea selezionata Shrink city Rimpicciolisci città shuffle midis MIDI casuali Signal Segnale signal spacing Distanza segnali Sim: CicliSim: Similar view as the main window Visualizza viste simili come finestra principale Size (%d MB): Dimens. (%d MB): sliced underground mode Vista per livelli slot empty Slot vuoto Smart hide objects Nascondi oggetti intelligente Sort by ordina per Sort by: Ordina per: Sort waiting list by Ordina lista di attesa per Sound Audio Sound settings Proprietà Audio Sound volume: Volume suono: special freight Carico Speciale Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus velocità\nstrada %i km/h, ferrovia %i km/h\nnavi %i km/h, aerei %i km/h. Speedlimit Limite velocità Speichern Salva Spieler Giocatore Spieler(mz) Giocatori Spielerliste Lista giocatori Spielstand wurde\ngeladen!\n \nGioco caricato con successo!\n Spielstand wurde\ngespeichert!\n \nGioco salvato con successo!\n Sprache Lingua Sprachen Lingue Stadtinformation Statistiche della città Start Parti Start the selected vehicle(s) Fai partire veicolo(i) selezionato. Starte Spiel Inizia Gioco Station tiles: Area stazioni: Station_msg Stazioni Status Stato fermata steam vapore Step timeline one year Salta un anno. Stops Fermate Storage Accoglienza Storage capacity Capacità di accoglienza Strassendepot Deposito camion/bus Strassentunnel Costruisci tunnel stradale street car Auto sued Sud suedost Sud-Est suedwest Sud-Ovest Summer snowline 0°C estate Supplied: %.0f %% Forniti: %.0f %% Suppliers Fornitori Tage alt giorni di età There are still vehicles\nstored in this depot!\n Ci sono ancora\ndei veicoli\nin questo deposito!\n This Month Questo mese This Year Anno Corrente Tile not empty. Rimuovi tutto prima\ndi spostare la terra. timeline Usa linea del tempo tl_title Lista di tutte le Città To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Per attrarre più turisti,\n%s ha costruito\nun %s\ncon l'aiuto di\n%i contribuenti. To heavy traffic\nresults in traffic jam.\n Il troppo traffico\nha causato code.\n Toggle day/night view Cambia visione giorno/notte Toggle vehicle tooltips Cambia richiami veicoli tonnen t Total inhabitants: Abitanti totali: Tourist attractions Attrazioni turistiche Tourists Attrazioni Town_msg Nuove Destinazioni Town: %s\n Città di %s.\n Towns Città track linea Tracks Binari Traffic Traffico Train Treno Trains are not available yet! Treni non ancora disponibili. tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. Tram %i km/h, Monorotaia %i km/h\nMaglev %i km/h, Scartamento ridotto %i km/h tram_track Linea tram Tramdepot Deposito tram Trams are not available yet! Tram non ancora disponibili. Transferring game ... Trasferimento gioco... Transformer only next to factory! I trasformatori devono essere in\nuno spazio piano vuoto\nvicino alla fabbrica! Translation Traduzione transparencies trasparenze transparent background sfondo trasparente transparent station coverage Copertura stazione trasparente Transported Trasportati Trees disabled! Alberi disabilitati! TrolleyBus_tab filobus Truck Camion Tunnel muss an\neinfachem\nHang beginnen!\n Un tunnel deve\niniziare su\nlivelletta uniforme!\n Tunnel must start on single way! Le gallerie devono iniziare su una singola via. Tunnelboden Galleria under the Artistic License secondo la Licenza Artistica underground mode Modalità sotterranea UNDO failed! Impossibile annullare. \nPuoi annullare la costruzione di \ntracciati solo prima di aver messo\nsegnali/stazioni/fermate ecc. Undo last ways construction Annulla costruzione delle ultime linee Unemployed Disoccupati Unhappy Infelici units/day unità/mese Unloading (%i%%)! Scaricando (%i%%)! Update Line Aggiorna linea upgrade HQ Migliora sede Usage: %.0f %% Utilizzo: %.0f %% Usage/Output Utilizzo/Produzione Use beginner mode Modalità principiante Use timeline start year Linea del tempo dall'anno: Vehicle %s can't find a route! Il veicolo %s\nnon trova il percorso! Vehicle %s is stucked! Il veicolo %s è bloccato! Vehicle count: Conteggio Veicoli: Vehicle details Dettagli Veicolo Vehicle Name Nome Veicolo Vehicle Power Potenza Veicolo vehicles stored veicoli in deposito Verbrauch Consumo Vergroessere die Karte\n Allarga mappa\n Verkauf Rimuovi convoglio verkaufen Vendi Verkehrsteilnehmer Utente stradale Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Sei in rosso!\n\nHai %d mese/i\nper rientrare.\n via via (dettaglio) via %s\n via %s\n via Menge via (ammontare) voranstellen Agg.in testa Waggon_tab Vagoni waiting in attesa Waiting for clearance! In attesa di permesso! Walked Camminato walking camminando Warnings_msg Traffico Wasser Acqua Water Acqua Water level Livello acqua: water vehicle Veicolo navale way %s cannot longer used:\n La via del tipo %s non può più esser usata.\n way %s cannot longer used:\n%s\n La via del tipo %s non può più essere usata:\n%s\n way %s now available:\n Via del tipo %s ora disponibile:\n Way toll Casello pedaggio Ways not connected Vie non connesse Wegpunkt Waypoint Weight Peso Weight: Peso: Weight/unit Peso/unità Welcome to Simutrans Benvenuti in Simutrans Wert Valore west Ovest Wind direction Direzione del vento Winter snowline 0°C inverno withdraw Ritira Withdraw All Ritira tutto WRONGSAVE Versione salvata\nnon compatibile.\n\nImpossibile leggere\nil file.\n Year Anno Year %i has started. L'anno %i è iniziato. Years Anni Your primary color: Il tuo colore primario: Your secondary color: Il tuo colore secondario: Zielort Destinazione zooming in Aumenta zoom zooming out Riduci zoom Zu nah am Kartenrand Troppo vicino al\nbordo della mappa\nper costruire qualcosa.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nuovo record mondiale per maglev: %.1f km/h da %s. New world record for monorails: %.1f km/h by %s. Nuovo record mondiale per \nmonorotaie: %.1f km/h\nda %s. New world record for motorcars: %.1f km/h by %s. Nuovo record del mondo per\nveicoli:\n %.1f km/h\nda %s. New world record for narrowgauges: %.1f km/h by %s. Nuovo record del mondo per ferrovie a scartamento ridotto: %.1f km/h da %s. New world record for planes: %.1f km/h by %s. Nuovo record del mondo per\naeroplani:\n %.1f km/h\nda %s. New world record for railways: %.1f km/h by %s. Nuovo record del mondo per\nferrovie:\n %.1f km/h\nda %s. New world record for ship: %.1f km/h by %s. Nuovo record del mondo per\nnavi:\n %.1f km/h\nda %s. #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s costruisce un convoglio aggiuntivo sulla linea: %s %s build rail line from %s (%s) to %s (%s) %s costruisce linea ferroviaria da %s (%s) a %s (%s) %s build road line from %s (%s) to %s (%s) %s costruisce linea stradale da %s (%s) a %s (%s) %s build ship line from %s (%s) to %s (%s) %s costruisce linea navale da %s (%s) a %s (%s) %s extends the route from %s (%s) to %s (%s) %s estende il percorso da %s (%s) a %s (%s) %s optimize way line from %s (%s) to %s (%s) %s ottimizza percorso da %s (%s) a %s (%s) %s removes convoys from line: %s %s rimuove i convogli dalla linea: %s vehicles of the line %s were retired i veicoli della linea %s sono stati ritirati #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. Aggiungi convogli con orari simili a questa linea. Enter intervall in days, hours, minutes Immettere l'intervallo in giorni, ore, minuti #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL villaggio &1_CITY_SYLL vecchio &2_CITY_SYLL nuovo &3_CITY_SYLL fiorito &4_CITY_SYLL bello &5_CITY_SYLL basso &6_CITY_SYLL bruno &7_CITY_SYLL verde &8_CITY_SYLL rosso &9_CITY_SYLL forte &A_CITY_SYLL corto &B_CITY_SYLL da &C_CITY_SYLL seppellire &D_CITY_SYLL vece &E_CITY_SYLL bene %0_CITY_SYLL pino %1_CITY_SYLL Borgo %2_CITY_SYLL Castel %3_CITY_SYLL Orto %4_CITY_SYLL Monte %5_CITY_SYLL Colle %6_CITY_SYLL Passo %7_CITY_SYLL Prato %8_CITY_SYLL Campo %9_CITY_SYLL Bosco %A_CITY_SYLL Sasso %B_CITY_SYLL Ponte %C_CITY_SYLL nuovo %D_CITY_SYLL Vuoto %F_CITY_SYLL Quercia 1center %s %s 1extern %s %s est. 1suburb %s %s %s 2center %s %s Centro 2extern %s %s P.ta Principe 2suburb %s Terre verdi %s %s 3center %s %s Via Dante 3extern %s %s P.ta Vecchia 3suburb %s villaggio %s %s 4center %s %s V.le Repubblica 4extern %s %s P.ta Nuova 4suburb %s rurale %s 5center %s %s C.so Roma 5extern % trasferimento %s 5suburb %s città %s 6center %s %s Hub 6extern %s scambio %s 6suburb %s periferia %s %s 7center %s %s Settimo 7extern %s pianure %s 7suburb %s parco %s 8center %s affari %s 8extern %s %s margine %s 8suburb %s satellite %s 9center %s asse %s 9extern %s bypass %s 9suburb %s mezzo %s simutrans-124.3/simutrans/text/it/000077500000000000000000000000001474050137200172005ustar00rootroot00000000000000simutrans-124.3/simutrans/text/it/airtools.txt000066400000000000000000000121671474050137200216040ustar00rootroot00000000000000Aiuto strumenti aeroporto

Strumenti aeroporto

Strumenti aeroporto contiene gli strumenti per costruire reti aeree. Gli strumenti possono costruire o rimuovere: piste di rullaggio o di atterraggio, spiazzi per carico/scarico (sia merci sia passeggeri), depositi per aerei (per comprare e gestire i mezzi) e vari edifici aeroportuali. Se giochi con la linea del tempo attivata, più il tempo passa e più strumenti ed edifici diventeranno disponibili.

Clicca sull'icona dell'aeroplano in cima alla vista di gioco per aprire la barra.
Posiziona il cursore sopra l'opzione o strumento voluto (dopo aver aperto o cliccato sulla barra) per vedere il nome e, dove previsto, il costo di costruzione, con quello di mantenimento tra parentesi, e la velocità massima consentita.

{Consigli: un semplice metodo per costruire un aeroporto è:
I) costruisci e collega piste di rullaggio e atterraggio;
II) piazza degli spiazzi alla fine delle piste di rullaggio;
III) aggiungi gli edifici richiesti.}

Gli strumenti possono includere, da sinistra a destra:

Pista di rullaggio: lo strumento costruisce delle aree di movimentazione per aerei per andare dal piazzale alle piste di atterraggio. Le piste di rullaggio sono costruite a livello del terreno.
IMPORTANTE: Se li piste di rullaggio sono connesse alla fine di una di atterraggio, gli aerei non atterreranno o decolleranno.
Come costruire una pista di rullaggio: clicca sullo strumento e seleziona (il cursore cambia su pista di atterraggio), poi clicca sul terreno per il punto di partenza (compare un bulldozer sul punto scelto) e sul punto finale.
{Consiglio: Usa Rimuovi per rimuovere parti individuali della pista di rullaggio. Annullare con [z] non rimborsa i costi di costruzione.}

Pista d'atterraggio: gli strumenti costruiscono una pista, usata dagli aerei per decollare e atterrare. Esse sono costruite a livello del terreno e si possono incrociare una all'altra.
Come costruire una pista d'atterraggio: clicca sullo strumento e seleziona (il cursore cambia su pista), poi clicca sul terreno per il punto iniziale (compare un bulldozer) e, infine, clicca sul punto finale.
{Consiglio: Lascia le estremità della pista non collegata, altrimenti gli aerei non partiranno o atterreranno. Usa Rimuovi per eliminare singoli pezzi di pista. Annullare con [z] non rimborsa i costi di costruzione.}

Rimuovere piste: lo strumento rimuove un segmento di pista di rullaggio o atterraggio, quando non ci sono aerei, tra due punti nella vista di gioco. L'uso dello strumento prevede un costo di costruzione.
Come rimuovere una pista: clicca sullo strumento (il cursore diventa una croce rossa), poi clicca sulla pista da rimuovere (seleziona il punto iniziale da rimuovere) e, infine, sul punto finale per rimuovere la porzione tra i due punti. {Consigli: Lascia gli estremi delle piste d'atterraggio non connessi, altrimenti gli aerei non atterreranno o decolleranno. Usa Rimuovi per eliminare singole parti di piste.}

Deposito aerei: lo strumento costruisce un hangar per comprare e gestire gli aerei. Gli hangar hanno un costo di mantenimento e devono essere costruiti alla fine di una pista di rullaggio.
Come costruire un hangar: clicca sullo strumento (il cursore cambia in un deposito) e poi alla fine di una pista di rullaggio.
{Consiglio: Rimuovi il deposito con Rimuovi.}

Piazzole di sosta e ponte di imbarco: gli strumenti costruiscono una fermata nella vista di gioco per caricare e scaricare merci e passeggeri.
Un piazzola non costruita a fianco un'altra Fermata ne creerà una nuova.
Le piazzole sono costruite alla fine di una pista di rullaggio, hanno costi di mantenimento e un bacino d'utenza per merci, passeggeri e posta. Un aereo atterrerà solo se c'è una piazzola libera.
Come costruire una fermata: clicca sullo strumento e poi su un'estremità di una pista di rullaggio.
{Consigli: elimina le piste con Rimuovi. Premi [v] per vedere/nascondere il bacino d'utenza per merci e passeggeri nella vista di gioco.}

Edifici aeroportuali: gli strumenti costruiscono estensioni per le Fermate e possono aumentare i costi di mantenimento, la capacità e il bacino d'utenza per merci e passeggeri. Nell'angolo di alcuni strumenti sono riportate le icone (usate in Lista Stazioni e Informazioni fermata) mostrano che tipo di bene l'estensione consente alla fermata di gestire.
Come costruire un'estensione: clicca sullo strumento per selezionare l'estensione (il cursore cambia nell'estensione), poi clicca sulla posizione richiesta, vicino a una fermata preesistente. La nuova estensione è ora considerata come parte della fermata.
{Consigli: rimuovere estensioni con Rimuovi. Premi [v] per visualizzare/nascondere i bacini di raccolta di merci e passeggeri nella vista di gioco.}

simutrans-124.3/simutrans/text/it/baum_build.txt000066400000000000000000000022431474050137200220450ustar00rootroot00000000000000Pianta alberi

Pianta alberi

La finestra di dialogo è divisa in quattro sezioni.
· Quella in alto a sinistra è una lista di selezione dei tipi di alberi a disposizione
· In fondo a sinistra a sinistra è presentata un'immagine dell'albero scelto
· In alto a destra possono essere selezionate alcune opzioni
· In fondo a destra ci sono le informazioni sull'albero selezionato

Lista di selezione

Nella lista di selezione sono elencati tutti i tipi di alberi che sono disponibili con le opzioni specificate in alto a destra. Ci sono due tab che ti permettono di cambiare come i tipi di albero sono identificati.
· Traduzioni: Presenta il nome dell'albero nella propria lingua. Se non è disponibile la traduzione, sarà utilizzato il nome dell'oggetto.
· Oggetto: Presenta il nome interno dell'oggetto in Simutrans per il tipo di albero.

Opzioni

· Ignora clima: Questa opzione disattiva le restrizioni climatiche associati i vari tipi di albero.
· Anno casuale: L'anno in cui l'albero sarà piantato è casuale.

simutrans-124.3/simutrans/text/it/citylist_filter.txt000066400000000000000000000035631474050137200231610ustar00rootroot00000000000000lista città

Lista città

Lista città visualizza i dettagli sulle aree urbane (villaggi, paesi e città) popolazioni.

Per aprire: clicca sullo strumento Lista città nella Gestione liste o premi [T].
Lista città ha due pulsanti opzione che determinano l'ordine in cui le aree urbane (e le loro popolazioni) sono presentate.
{Consiglio: Se le voci nella lista sono solo parzialmente visibili, modifica la dimensione di Lista città oppure muovi la lista con lo slider.}

Abitanti totali: è il numero totale di cittadini nel gioco (la popolazione di tutte le aree urbane). La variazione di popolazione è riportata tra parentesi.

Ordinati per: ha le opzioni per determinare l'ordine delle aree urbane elencate nella lista.
Clicca sul pulsante opzione per muoversi tra le opzioni (cambia il nome del bottone):

- Nome ordina alfanumericamente secondo il codice ASCII (le lettere maiuscole sono prima delle minuscole) inomi assegnati.
- Cittadini ordina secondo la popolazione.
- Crescita popolazione ordine secondo la crescita (che è dipendente dalle dimensioni dell'area urbana e dal numero numero di passeggeri trasportati).

- Ascendente / Discendente inverte l'ordine della lista.

Cliacca su un elemento dellaLista cittàper vedere più informazioni circa l'area urbana.
Per ogni area sono riportati:

nome assegnato all'area urbana (può essere cambiata nelle Informazioni città)..

numero di abitanti dell'area urbana, con l'aumento di popolazione tra parentesi.

simutrans-124.3/simutrans/text/it/citywindow.txt000066400000000000000000000117561474050137200221530ustar00rootroot00000000000000Aiuto statistiche città

Statistiche città

Statistiche città visualizza le statistiche dell'area urbana selezionata e può essere usata per cambiarne il nome. Un'area urbana è una città, un paese o un villaggio; tutte le aree urbane sono chiamate città.

Ogni città ha il suo Municipio e cresce attorno ad esso. Il trasporto di passeggeri e di posta aiuta la crescita, che provoca la costruzione di strade o l'assorbimento di quelle esistenti da parte del servizio pubblico; appaiono nuovi edifici cittadini e industrie e i limiti della città di espandono.

Clicca su un Municipio nella vista di gioco con lo Strumento ispezione o su una città elencata nella Lista città per aprire le Statistiche città. Qui puoi vedere e modificare il nome della città, alcune statistiche, due mini mappe e un grafico dove puoi vedere lo sviluppo nel tempo di certi fattori riguardanti la città.

Nome: il nome assegnato alla città appare in un riquadro nella parte alta di Statistiche città.
I nomi di queste aree urbane sono usati per creare quelli delle fermate nei limiti della città. Per cambiare il nomer cliccare semplicemente sul riquadro e inserirne uno nuovo.
{Suggerimento: Usa [!] per vedere il nome della città sopra il Municipio nella finestra di gioco. Guarda readme_citylist.txt (in ...simutrans/text/) per più informazioni su come sono generati i nomi delle città}.

Sotto il riquadro del nome sono presentate le statistiche base della città:
Dimensioni: numero di cittadini corrente. Il recente aumento di popolazione è riportato tra parentesi.
Edifici: numero di edifici (residenziali/commerciali e industriali) nella città.
Coordinate sulla mappa: indica i limiti della città (cambieranno con la crescita della città). Il primo paio di valori indica l'angolo in alto a sinistra e il secondo quello in basso a destra. Con la crescita delle città, i limiti si possono sovrapporre.

Numero corrente di disoccupati e senza tetto nella città. Essi aumenteranno quando la città espanderà i propri limiti e scenderanno quando saranno eretti nuovi edifici. L'equilibrio tra questi numeri determina che tipo di edifici (residenziale/commerciale/industriale) verrà costruito.

Il bottone Permetti crescita città ti permette di attivare o disattivare la crescita delle città.

Le Mini mappe del mondo nelle Statistiche città mostrano le destinazioni dei passeggeri e posta generati nella città come pallini colorati.
La mini mappa sulla destra riporta i dati dell'ultimo mese, e quella a sinistra del mese precedente. Il colore di ogni punto indica se la destinazione può essere raggiunta o meno:
- punto giallo: c'è un percorso e una fermata non troppo affollata per iniziare il viaggio (faccina felice nelle Informazioni sulla fermata).
- punto arancione: non c'è un tragitto per questa destinazione.
- punto rosso: c'è un tragitto fino alla destinazione, ma la fermata della partenza era troppo affollata (faccia triste nelle Informazioni sulla fermata).

Sotto le mini mappe c'è un grafico che mostra le statistiche per la città.
Sull'asse delle y c'è la quantità, mentre sulle x il tempo. Clicca su uno dei due tab sopra per cambiare la scala dell'asse delle x:
Anni: visualizza valori annuali per gli ultimi 12 anni.
Mesi: visualizza valori mensili per gli ultimi 12 mesi.

Cliccando sul bottone delle opzioni del grafico, attiverai e disattiverai le relative curve. Quando un bottone è selezionato, appare come premuto.
Le curve hanno lo stesso colore del loro bottone:
Popolazione: il numero di abitanti che vivono nella città.
Crescita città: aumento o calo di popolazione (dipendente dalle dimensioni della città e dal servizio di trasporto fornito a passeggeri e posta).
N° edifici: quanti edifici sono presenti nella città.
Auto da città: quante auto sono state generate.
Viaggi: quanti passeggeri sono entrati nella rete di trasporto (rappresentato da una faccina felice nelle informazioni sulla fermata)
Passeggeri: il numero totale di passeggeri generati dalla città.
Posta spedita: quantità di posta che è entrata nella rete di trasporti.
Posta: quantità totale di posta generata nella città.
Approvvigionamento: numero di volte che ci sono state merci nelle fabbriche della città.
Merci: numero di volte che il magazzino delle fabbriche in città è stato controllato.

{Suggerimento: le impostazioni relative alle città possono essere cambiate in simuconf.tab e cityrules.tab}.

simutrans-124.3/simutrans/text/it/climates.txt000066400000000000000000000052641474050137200215510ustar00rootroot00000000000000Aiuto imposta clima

Imposta clima

La finestra Imposta clima imposta le opzioni per gli aspetti topografici e meteorologici del mondo. Si può aprire dalle finestre Crea nuovo gioco e Lingue.

Per modificare ogni impostazione, cliccare sulle frecce a lato di ognuna di esse.

Opzioni mappa

Livello acqua - Imposta quant'è alto il livello dell'acqua nella mappa. Valori più alti riducono la terra ferma a favore dei mari.

Altezza montagne - Imposta l'altezza massima del terreno.

Asprezza mappa - Imposta l'asprezza del terreno. Un numero grande crea delle linee di costa più ondulate. Per creare una mappa realistica, impostare un valore alto.

Limite neve
È l'altezza oltre la quale appare la neve.

Limite neve estivo - È il limite della neve durante l'estate. È il valore più alto da impostare tra le opzioni del clima.

Limite neve invernale - Imposta il limite della neve per l'inverno. Per far apparire la neve in zone ampie della mappa, impostare un valore basso.

Opzioni clima
Impostare le differenti opzioni climatiche per la mappa.
Il valore dopo ogni opzione imposta le altezze del terreno dove appare quel dato clima. Per disattivarne uno in particolare, inserire 0 (zero).

Clima desertico - Pochissime precipitazioni e temperature estreme. Pochi alberi e paesaggio piatto

Clima tropicale - Tipico delle zone non aride intorno all'equatore, con temperature costantemente alte al livello del mare e a piccole elevazioni

Clima mediterraneo - Clima moderatamente variabile ed umido

Clima temperato - Presente nelle aree tra i topici e i poli. Tempo variabile

Tundra - Basse temperature, ai limiti dei poli

Clima alpino - Clima secco con inverni freddi

Altre opzioni

Nessun albero - Cliccare per abilitare. Attivare quest'opzione per evitare che Simutrans disegni alberi. Il loro disegno occupa la CPU. Usare quest'opzione su computer lenti o con poca RAM.

Numero di fiumi - Imposta il numero massimo di fiumi che possono essere generati e usati in una mappa. Essi non possono essere navigati da alcun tipo di barca o nave.

Lunghezza minima dei fiumi - Imposta la lunghezza minima dei fiumi in termini di numero di settori.

Lunghezza massima dei fiumi - Imposta la lunghezza massima dei fiumi in termini di numero di settori.

simutrans-124.3/simutrans/text/it/color.txt000066400000000000000000000003421474050137200210560ustar00rootroot00000000000000Aiuto - Scelta colori

Scelta colori

Con questo menù si può scegliere il colore che avranno tutti i propri veicoli, le proprie stazioni e le proprie fermate. Il colore di default è l'azzurro.

simutrans-124.3/simutrans/text/it/convoidetail.txt000066400000000000000000000036411474050137200224250ustar00rootroot00000000000000Aiuto dettagli del convoglio

Dettagli del convoglio

Dettagli del convoglio fornisce più informazioni riguardo un determinato convoglio (un veicolo o una combinazione di essi) e può essere usato per venderlo immediatamente.

Dettagli del convoglio si apre dal bottone Dettagli ne Informazioni sul convoglio.
Se tutti gli elementi non fossero visibili, ridimensiona Dettagli del convoglio o usa una barra di scorrimento per muoverli.

In cima a Dettagli del convoglio, le informazioni includono:

Potenza: del convoglio (combinazione della potenza di tutti gli elementi motorizzati in esso).

Valore di vendita: denaro ricevuto se il convoglio venisse venduto (prezzo d'acquisto meno tutte le perdite di valore).

ATTENZIONE: Clicca sull'opzione Modalità vendita per vendere il convoglio immediatamente. Nessuna conferma sarà richiesta. Esso sarà rimosso dal gioco e il bilancio del giocatore riceverà in credito il prezzo di vendita.

Dettagli convoglio elenca tutti gli elementi in esso.
Le informazioni presenti per tutti i veicoli includono:
- Immagine: una figura dell'unità (usata anche in Depositi).
- Costruito: mese e anno di costruzione e di introduzione se si sta giocando con la linea del tempo.
- Valore di rivendita: somma ricevuta se venduto.
- Potenza: potenza generata (dai veicoli motorizzati).
- Frizione: livello di frizione corrente.
- Guadagno massimo: guadagno dell'unità secondo il tipo di bene trasportato dal convoglio.
- Beni a bordo ammontare e destinazione dei beni trasportati dal veicolo.

simutrans-124.3/simutrans/text/it/convoiinfo.txt000066400000000000000000000153121474050137200221140ustar00rootroot00000000000000informazioni convoglio

Informazioni convoglio

Informazioni convoglio riporta le informazioni riguardanti un convoglio (un veicolo o una combinazione di essi) che è usato per trasportare merci o passeggeri.
Elenca quanto trasportato da un convoglio e ha la possibilità di accedere a maggiori informazioni e di venderlo, seguirlo nella vista di gioco, cambiargli nome e assegnargli una linea.

Un convoglio è composto da almento un veicolo motorizzato e da ogni rimorchio per merci o persone.
Esempi di convogli includono: un gruppo di cavalli che trainano un carro; una locomotiva attaccata a un tender e a dei vagoni; un bus o un camion attaccati a un rimorchio; tram collegati; una nave; un rimorchiatore che traina una chiatta; un aereo.
I convogli sono assemblati e comprati da un deposito a seconda del tipo di trasporto.
{Consigli: un convoglio ha un limite di unità a seconda del tipo: treni 24; veicoli stradali 4}

Clicca su un convoglio nella vista di gioco con lo strumento ispezione o clicca su un convoglio riportato nella Lista veicoli o Gestione linee per aprire le Informazioni convoglio
La barra del titolo delle Informazioni convoglio mostra un unico ID e nome del convoglio (per default è quello del primo veicolo acquistato o assemblato nel deposito).
Informazioni convoglio contiene una casella con il nome, una mini vista con informazioni sul convoglio, bottoni per le opzioni e una lisa di beni caricati al momento (se non sono visibili tutti ridimensiona Informazioni convoglio o usa gli slider per muoverli).

Le informazioni riportate in alto a Informazioni convoglio includono:

- ID interno: un unico ID per convoglio (assegnato al momento dell'acquisto o dell'assemblaggio in un deposito).

- nome: riporta il nome assegnato al convoglio (assegnato al momento dell'acquisto o dell'assemblaggio in un deposito).
Clicca sul nome e scrivine uno nuovo per cambiarlo.

- velocità: la velocità corrente è riportata in km/h.
Tra parentesi la velocità massima del convoglio (determinata dall'unità più lenta del convoglio).
Una barra verde indica la velocità corrente relativa alla massima consentita.

- guadagno: profitto generato dal veicolo (incasso meno costi operativi) nell'anno di gioco corrente.
Tra parentesi il costo operativo per quadrato di gioco.

- Peso: combinazione di peso del convoglio e delle merci in tonnellate.
Tra parentesi c'è il peso delle merci caricate.
Una barra del progresso verde indica la capacità utilizzata per caricare merci e passeggeri.
Una barra gialla indica In attesa del livello minimo (quantità minima di merci o persone richieste per partire) impostato nel Controllo linee.
{Consigli: per impostare o modificare i livelli minimi per tutti i convogli in una linea, utilizzare il bottone Aggiorna linea in Gestione linee o i Controlli nel deposito. Per impostarli solo per un certo convoglio, usare il bottone Imposta linea nelle Informazioni convoglio or Controlli deposito.}

- Destinazione: la prossima fermata o punto di passaggio nella linea.
Una barra del progresso verde indica la distanza alla prossima destinazione.

- Serve linea: indica ogni linea assegnata al convoglio.

- mini vista visualizza il convoglio.
Clicca sulla mini vista per vedere il convoglio sulla vista di gioco.

Clicca sui bottoni nelle Informazioni convoglio per aprire i controlli o selezionare le opzioni:

Linee: apre i controlli per cambiare percorso e la quantità minima di merci e passeggeri richiesta dal convoglio per procedere.

vai al deposito: manda il convoglio al deposito appropriato più vicino. Ogni elemento caricato è perduto e si riceve l'incasso per il trasporto al deposito.
Nel deposito il convoglio mantiene la propria Linea.

seguimi: bottone che muove la vista di gioco con il convoglio.
Per deselezionare l'opzione, cliccare ancora sul bottone o con il destro sulla Mappa.

grafico: clicca sul bottone per visualizzare il grafico (quando quest'ultimo è visibile, il bottone è evidenziato) nelle Informazioni convoglio.
Il grafico mostra le statistiche per gli ultimi 12 mesi (asse x) quando è selezionata un'opzione.
Clicca sui bottoni delle opzioni del grafico per avere delle informazioni su di esso (il bottone è evidenziato quando l'opzione è selezionata).
I colori e linee del grafico corrispondono a quelli dei bottoni:
- Capacità disponibile indica lo spazio inutilizzato del convoglio.
- Trasportati indica la quantità di merce, passeggeri e posta trasportati.
- Entrate indica i ricavi generati dal trasporto.
- Costi operativi indica i costi sostenuti durante il transito del convoglio.
- Profitto indica il profitto ricevuto dal trasporto (Entrate meno costi operativi).

Dettagli apre Dettagli convoglio che contiene più informazioni e opzioni per vendere un convoglio.

Ordina passeggeri/merci per: elenca quanto correntemente caricato su un convoglio.
Le informazioni riportate includono la quantità caricata e la capacità del convoglio, tipo di merce, destinazione finale e prossima fermata.
Il pulsante (cambia nome con la selezione) ordina gli elementi caricati in gruppi di passeggeri, posta e merci:
- destinazione: ordina gli elementi alfanumericamente secondo l'ordine ASCII (lettere maiuscole prima delle minuscole), secondo il nome della fermata di destinazione.
- via (dettaglio): ordina gli elementi alfanumericamente secondo l'ordine ASCII (lettere maiuscole prima delle minuscole), secondo il nome della prossima fermata.
- via (ammontare): ordina gli elementi trasportati alla prossima fermata secondo la quantità.
- ammontare: ordina gli elementi secondo la quantità in ordine decrescente.

simutrans-124.3/simutrans/text/it/depot.txt000066400000000000000000000057461474050137200210700ustar00rootroot00000000000000Deposito

Finestra di dialogo Deposito

Nel deposito si può comprare, vendere e definire il percorso di tutti i veicoli disponibili di un particolare tipo, ad es. autobus o camion se si è in un deposito di mezzi stradali.

Questa finestra di dialogo contiene informazioni sui veicoli che si possono comprare e su quelli già acquistati. Nelle tab sulla destra sono mostrati i veicoli acquistabili. Nella zona in alto a sinistra è mostrato il convoglio attualmente assemblato (ad es. un treno con i suoi vagoni). Nella zona di mezzo, sempre a sinistra, sono invece mostrati motrici e camion, mentre in basso a sinistra vengono mostrati vagoni e rimorchi.

Nella parte più in basso vengono visualizzate delle informazioni relative al veicolo selezionato. Al di sotto di questa zona, sono presenti tre bottoni.

Il più a sinistra è il pulsante "Parti", che serve per far partire un veicolo di cui si è già specificato il percorso. Il pulsante "Percorso" serve quindi proprio a definire una serie di punti in cui si vuole far passare il veicolo. Infine, il bottone "Vendi" svolge la ovvia funzione di vendere i veicoli in proprio possesso (questa funzione è attiva finchè non la si disattiva).

Per vedere le informazioni relative ad un particolare veicolo è sufficiente passare con il puntatore del mouse sopra uno di essi. Le informazioni compariranno nella parte bassa della finestra. Per comprare un veicolo basta selezionarlo con il tasto sinistro del mouse: comparirà nella parte sinistra della finestra. Il convoglio sul quale si sta lavorando apparirà nella zona superiore sinistra; ogni motrice/camion/nave addizionale viene visualizzata subito sotto, mentre ogni vagone/rimorchio addizionale ancora sotto, appena sopra le informazioni.

E' possibile formare un convoglio in due modi. Si possono comprare tutti i veicoli necessari uno dopo l'altro, iniziando dalla motrice/camion e quindi comprando ogni altro vagone/rimorchio; oppure si possono selezionare uno ad uno i veicoli già acquistati in precedenza e formare un convoglio con quelli.E' possibile lavorare su un solo convoglio alla volta. Per vendere un qualunque veicolo in proprio possesso, si seleziona il pulsante "Vendi" e quindi si clicca sul veicolo. Il prezzo di vendita appare nella zona delle informazioni.

Per definire il percorso di un veicolo, si preme il pulsante "Percorso" per far comparire la finestra di impostazione del percorso. Una volta definito il percorso, è possibile far partire il veicolo agendo sul bottone "Parti".

Per far tornare un convoglio al deposito, è necessario rimuovere tutte le fermate dal suo percorso e impostare come sua unica destinazione il deposito stesso. Una volta che il convoglio ha raggiunto il deposito, viene disassemblato e i veicoli di cui era composto diventano nuovamente disponibili nel deposito, pronti per ripartire, formare un altro convoglio o essere venduti.

simutrans-124.3/simutrans/text/it/display.txt000066400000000000000000000105471474050137200214150ustar00rootroot00000000000000Aiuto - Grafica

Grafica

Grafica permette di controllare l'aspetto grafico del gioco e fornisce informazioni sulle performance.

Click sul pulsante Grafica nel menù Opzioni di Gioco per aprire il menù Grafica.

Click sui bottoni quadrati permette di selezionare / deselezionare le opzioni, mentre si possono utilizzare i bottoni freccia per regolare i settaggi:

Mostra griglia: evidenzia i bordi dei quadrati in cui è suddivisa la mappa.

Modalità sotterranea: visualizza cosa si trova subito sotto al livello del suolo (utile per costruire tunnel, metropolitane, ferrovie sotterranee)

Sliced underground mode: seleziona il livello del terreno da visualizzare.
In questa modalità il terreno viene suddiviso "a fette" di pari livello, viene visualizzato il livello selezionato utilizzando i bottoni freccia.

Modalità giorno e notte: attiva / disattiva la variazione della luminosità in base all'ora del giorno.

Luminosità: permette di impostare la massima luminosità ad un determinato valore indicato utilizzando i bottoni freccia; 0 imposta la massimà luminosità, 9 la minima.

Inverti scrolling: inverte la direzione dello scroll nella finestra del gioco.
Tenendo premuto il tasto destro nella finestra di gioco è possibile trascinare o spostare il terreno.

Vel. scrolling: imposta la velocità dello scroll nella finestra del gioco.

Nascondi trasparenti: tutti gli oggetti nascosti (siano essi alberi od edifici) saranno resi trasparenti.

Nascondi alberi: selezionare questa opzione comporta che se "nascondi trasparenti" è selezionato gli alberi saranno resi trasparenti, altrimenti saranno miniaturizzati.

Copertura stazione trasparente: con questa opzione è possibile modificare l'aspetto grafico con cui viene indicata la copertura della stazione.

Mostra copertura stazione: visualizza un segnaposto, il cui aspetto è selezionabile da "copertura stazione trasparente", sulle caselle che possono usufruire dei servizi della stazione.

Mostra nomi stazioni: in prossimità di ogni stazione ne viene visualizzato il nome.

Visualizza barre di attesa: in prossimità di ogni stazione viene visualizzata una barra contenente informazioni su tutti i prodotti che vi sono in attesa.

Pedoni in città: abilita la visualizzazione dei pedoni che transitano sulle strade delle aree urbane.

Pedoni alle fermate: abilita la visualizzazione dei pedoni quando un veicolo arriva ad una fermata.

Densità di traffico: imposta il numero di auto private che circolano nelle aree urbane.
Il numero di auto private cresce al crescere della dimensione della città ed alla densità di traffico impostata. Impostando densità di traffico a 0 non verranno generate auto private.

{Consiglio: Maggiori opzioni e valori di default al caricamento di simutrans possono essere modificati in simuconf.tab}.


Display informativo:

Sotto alle impostazioni sono visualizzate delle informazioni sulle prestazioni di simutrans durante il suo funzionamento.
I numeri sono normalmente visualizzati in bianco, se sono gialli o rossi occorre modificare le impostazioni.
Modifiche alla velocità di scorrimento del gioco, T, (utilizzando l'icona Fast Forward >> in alto alla finestra di gioco, o [,]/ [.]) può modificare il colore dei numeri.

Tempo del frame: tempo tra tra un frame e il successivo.

Inattivi: quando è maggiore di 0 il computer può eseguire altri software.

FPS: valori elevati significano che i veicoli scorrono più fluidamenti. Se il numero rimane rosso significa che il computer è troppo lento per le attuali impostazioni, provate a ridurre la dimensione della finestra di gioco.

Sim: se il numero rimane rosso significa che il computer è troppo lento per la mappa attuale, provate con una mappa più piccola o con meno aree urbane.

simutrans-124.3/simutrans/text/it/finances.txt000066400000000000000000000025271474050137200215350ustar00rootroot00000000000000Aiuto - Finanze

Finanze

Attraverso questa finestra si può vedere lo stato delle proprie finanze, accessibile premendo "f" o cliccando sull'immagine sulla destra della toolbar.
Qui si trovano le informazioni relative alle finanze degli ultimi due anni, con entrate e uscite.

Le voci sono le seguenti:

Costruzioni - Qui c'è tutto ciò che è stato costruito durante l'anno, inclusi segnali, binari e uffici postali.

Nuovi veicoli - Qualunque veicolo comprato, di qualunque tipo.

Costi percorrenza veicoli - I costi di tutti i veicoli in movimento. I costi di ogni veicolo possono essere visti dalle finestre di dialogo dei depositi (fra parentesi, vicino al prezzo di acquisto).

Entrate - Entrate totali derivanti dai trasporti di merci e passeggeri.

Totale - Il totale delle entrate e delle uscite dell'anno. E' la somma di tutte le voci precedenti.

Saldo - Il bilancio totale della compagnia. E' il denaro disponibile per nuovi investimenti. Questa informazione si può trovare anche nella barra di stato sul bordo inferiore dello schermo.

simutrans-124.3/simutrans/text/it/haltlist.txt000066400000000000000000000112411474050137200215640ustar00rootroot00000000000000Elenco stazioni/fermate

Elenco delle stazioni/fermate

Elenco stazioni/fermate visualizza le informazioni relative alle stazioni/fermate dove è possibile caricare e scaricare passeggeri ed i beni, permette inoltre di filtrare i dati.

Per aprire: click sullo strumento Liste. Elenco stazioni/fermate ha quattro bottoni tra cui scegliere, due sono utilizzati per ordinare la lista di oggetti mentre gli altri due sono utilizzati per applicare dei filtri agli oggetti da visualizzare. Sotto ai bottoni si trova una lista di fermate selezionate secondo i criteri impostati nel filtro.
Click su uno degli elementi di Elenco stazioni/fermate per visualizzare maggiori informazioni riguardanti la fermata.
{Consiglio: se l'elenco di fermate è vuoto provate a modificare le opzioni del filtro. Se l'elenco è parziale, provate a ridimensionare Elenco stazioni/fermate o scorrete l'elenco con la barra di scorrimento.}

Premendo i tre bottoni a sinistra ci si muove all'interno delle possibili opzioni (il nome del bottone indica l'opzione attualmente selezionata), il bottone proprietà apre invece una maschera contenente ulteriori opzioni.

Ordina per: contiene due bottoni utilizzati per odrinare le fermate visualizzate nell'elenco:

Bottone di sinistra:
- Tipo: ordina in base al tipo di veicolo.
- Nome: ordina alfabeticamente utilizzando i codici ASCII (le lettere maiuscole si ordinano prima delle lettere minuscole ) dei nomi assegnati.
- Attesa: ordina in base alla quantità di passeggeri e beni presenti mostrando anche gli oggetti in attesa e il tipo di servizio offerto.
Bottone di destra:
- ascend. / discend.: inverte l'ordine dell'elenco.

Filtro: Due bottoni di opzioni, per abilitare / disabilitare i criteri di selezione e modificare i criteri di selezione degli oggetti.

Bottone di sinistra
- abilita / disabilita: abilita / disabilita l'utilizzo dei criteri del bottone proprietà.
Bottone di destra
- Proprietà: apre la finestra dei controlli per modificare i criteri si selezione.

Gli elementi elencati per ognuna delle fermate includono:

Barra con il colore di stato: i colori indicano quanto la fermata è sovraffollata. La stessa barra di colore è utilizzata nelle informazioni della fermata e Gestione linee e sono gli stessi colori visualizzati nella barra di colore in corrispondenza delle fermate nella finestra principale del gioco:
- giallo: fermata senza servizio, quindi non c'è nulla in attesa.
- verde: fermata non sovraffollata.
- arancio: fermata leggermente sovraffollata.
- rosso: fermata sovraffollata in cui si verifica una delle tre seguenti condizioni; sovraffollamento oltre 1.5 volte la capacità della fermata, fermata con più di 200 passeggeri malcontenti, fermata con fabbrica che ha bloccato la produzione a causa della congestione.
{Consiglio: Usa [!] per modificare l'aspetto delle barre di colore in corrispondenza delle fermate nella schermata principale del gioco.}

Nome: il nome assegnato alla fermata {Consiglio: In simuconf.tab si trovano delle opzioni per assegnare dei numeri alle fermate}.

Icone dei veicoli: indicano quali tipi di veicolo utilizzano la fermata (utilizzati anche nelle informazioni delle fermate e gestione linee).
Le icone icludono: bus (per veicoli passeggeri su strada), camion (per il trasporto di beni su strada), treni, navi ed aereoplani; i tram possono essere indicati dall'icona di un treno o di un bus a seconda del tipo di fermata.

Icone merci indicano quali elementi (passeggeri, posta, beni) la fermata può gestire (utilizzati anche nelle informazioni delle fermate e gestione linee).
{Consiglio: aggiungendo appositi edifici di estensione le categorie degli elementi gestiti dalla fermata possono aumentare; ad esempio gli Uffici postali possono essere aggiunti alla fermata per permetterle di gestire la posta}.

Attesa: dettaglio dei passeggeri e merci in attesa alla fermata.

simutrans-124.3/simutrans/text/it/language.txt000066400000000000000000000017211474050137200215250ustar00rootroot00000000000000Aiuto - Scelta lingua

Finestra di dialogo scelta lingua

Questa finestra di dialogo permette di scegliere la lingua di Simutrans. Se si seleziona la lingua prima di creare una nuova mappa, i nomi delle città saranno creati in base a quella lingua. Si può cambiare la lingua in ogni momento: i contenuti delle finestre aperte non verranno sempre aggiornati immediatamente, ma solo dopo la loro chiusura e riapertura. Molti testi sono invece aggiornati immediatamente.

Se si preferisce avere i nomi delle città nella propria lingua, è necessario selezionarla PRIMA di iniziare un nuovo gioco.

Se la propria lingua non è supportata, alcune ulteriori traduzioni sono disponibili al seguente indirizzo: http://www.simutrans.de/english/download/simu/download.html ma purtroppo potrebbero essere incomplete o non aggiornate.

Per aiutare a tradurre Simutrans nella tua lingua,
visita https://translator.simutrans.com

simutrans-124.3/simutrans/text/it/load.txt000066400000000000000000000004651474050137200206650ustar00rootroot00000000000000Aiuto - Caricamento

Caricare un gioco salvato

Quando si seleziona l'opzione di caricamento, appare una nuova finestra che mostra i nomi dei giochi salvati precedentemente. Facendo clic sul nome del file del gioco che si vuole caricare questo verrà caricato e fatto partire.

simutrans-124.3/simutrans/text/it/mailbox.txt000066400000000000000000000046311474050137200214000ustar00rootroot00000000000000Aiuto centro messaggi e sue opzioni

Centro messaggi

Il centro messaggi riporta i messaggi dal gioco e apre i controlli per selezionare quali sono visualizzati nel gioco.

Clicca sull'icona del centro messaggi in cima alla vista di gioco o premi [B] per aprire Message Centre, che elenca i messaggi dal gioco.
Clicca su un messaggio per muovere la vista di gioco sulla relativa posizione.

Il tasto Opzioni (clicca per usarlo) apre le Opzioni centro messaggi che controlla quali messaggi possono essere visualizzati.


Opzioni centro messaggi

Opzioni centro messaggi ha tre colonne di bottoni quadrati che stabiliscono come sono visualizzati i messaggi.

Da sinistra a destra, le colonne indicano come sono presentati i messaggi: come testo scorrevole in fondo alla vista di gioco, messaggio temporaneo o messaggio permanente.
{Consiglio: clicca sull'angolo in alto a sinistra del messaggio o usa la tastiera per chiudere i messaggi permanenti}

Clicca sui bottoni quadrati per selezionare le opzioni dei messaggi (i bottoni sono evidenziati quando selezionati) per i seguenti messaggi:

Anno nuovo: un nuovo anno è iniziato.

Notizie AI: un giocatore gestito dal computer ha aperto una nuova linea.

Notizie città: un'area urbana sta costruendo un municipio più grande.

Nessuna via: un veicolo non può trovare una via per la sua prossima destinazione (a Fermata o punto di transito).

Nuove industrie: una nuova catena industriale (un consumatore finale e ogni fornitore necessario) è stata costruita per la crescita della città.

Turismo: sono stati costruiti un'attrazione o un memorial.

Nuovi veicoli: un nuovo veicolo è disponibile o ritirato (se è utilizzata la linea temporale).

Stazione piena: una fermata è troppo piena.

Problemi: la società di un giocatore è in debito o altri messaggi di problemi.

simutrans-124.3/simutrans/text/it/map.txt000066400000000000000000000010441474050137200205150ustar00rootroot00000000000000Aiuto - Mappa

Finestra Mappa

La finestra mappa è visualizzabile sia premendo 'm' sia cliccando sul pulsante relativo nella toolbar.

La mappa permette di vedere il mondo in una vista ridotta e verificare la posizione di diversi elementi come ad es. fabbriche, ferrovie, strade e città.

E' possibile muoversi in ogni parte del mondo semplicemente cliccando nel punto della mappa corrispondente al luogo in cui si vuole andare; il gioco centrerà la vista generale ingrandita sul posto selezionato.

simutrans-124.3/simutrans/text/it/new_world.txt000066400000000000000000000052641474050137200217500ustar00rootroot00000000000000Aiuto - Nuovo Mondo

Finestra di dialogo Nuovo Mondo

Attraverso questa finestra di dialogo si possono cambiare i parametri che determinano le caratteristiche della mappa che si sta creando per iniziare un nuovo gioco. Inoltre, nell'angolo in alto a sinistra appare una finestra per la selezione della lingua di gioco.

Il primo parametro è il numero della mappa. Esso determina il 'layout' della mappa, ad es. quantità e dislocazione dell'acqua, delle colline, degli alberi, la posizione delle città e delle fabbriche. Viene mostrata un'anteprima per ogni mappa. Il numero di mappa di default è 33.

Le dimensioni della mappa determinano quanto grande essa sarà. E' possibile impostare un valore compreso fra 128x128 e 576x576 quadrati. Il default è 256x256.

La densità delle industrie determina quante fabbriche saranno inserite nella mappa. Più bassa è la densità e più difficile diveterà il gioco, poichè ci saranno meno possibilità di trasporto di beni. Il default è 125.

Il numero di città indica il numero di insediamenti urbani che verranno inseriti nella mappa e può variare da 2 a 64. Il default è 16.

La densità del traffico determina il numero di auto private che circoleranno nelle città. Il default è 8.

Il livello dell'acqua determina quanto acqua sarà presente nella mappa. Più basso è questo valore e più terreno sarà presente, e viceversa. Il default è 4.

L'altezza delle montagne indica l'altitudine della più alta montagna della mappa. Il default è 160. L'asprezza del terreno indica quanto pianeggiante sarà la mappa. Più questo valore è basso e meno colline e valli saranno presenti. il range di valori fra cui scegliere varia da 1 a 3. Il default è 2.

Il pulsante "Mappa casuale" selezionerà un numero di mappa a caso. Questa operazione non modifica qualsiasi altra opzione che si avesse selezionato precedentemente.

Il bottone "Mostra pedoni" determina se i pedoni verranno mostrati quando arrivano con un treno o un autobus. E' possibile cambiare questa impostazione in ogni momento anche durante il gioco attraverso la finestra di dialogoSchermo.

Il pulsante "Mod. giorno e notte" abilita o disabilita la funzione di simulazione dell'alternarsi di luce e buio. E' possibile cambiare questa impostazione in ogni momento anche durante il gioco attraverso la finestra di dialogoSchermo.

Il pulsante "Carica gioco" permette di scegliere un gioco da caricare. Il pulsante "Inizia gioco" fa iniziare un nuovo gioco creando una nuova mappa secondo i parametri indicati. Il pulsante "Esci" termina immediatamente l'esecuzione di Simutrans.

simutrans-124.3/simutrans/text/it/options.txt000066400000000000000000000016121474050137200214340ustar00rootroot00000000000000Aiuto - Opzioni di gioco

Opzioni di gioco

Questa finestra di dialogo è usata per modificare gran parte delle opzioni del gioco. Molte di queste sono raggruppate in sotto-finestre che possono essere aperte agendo sui pultanti relativi. Questa finestra è anche utilizzata per caricare, salvare e uscire dal gioco.

Lingue - Si sceglie la lingua di Simutrans
Colore giocatore - Si sceglie il colore della propria compagnia
Schermo - Si impostano le proprietà di visualizzazione
Audio - Si impostano le proprietà audio
Giocatori - Si imposta il numero di intelligenze artificiali (AI) nel gioco
Carica - Si carica un gioco salvato
Salva - Si salva il gioco in corso
Nuova mappa - Si crea una nuova mappa
Esci - Si esce dal gioco

Per ulteriori informazioni, si vedano le finestre di aiuto per ogni singola sotto-finestra.

simutrans-124.3/simutrans/text/it/players.txt000066400000000000000000000006431474050137200214230ustar00rootroot00000000000000Aiuto - Lista Giocatori

Lista Giocatori

Con questo menù si può vedere come stanno andando le AI concorrenti, con la possibilità di attivare o disattivare ognuna di esse.

Alla destra del colore di ogni concorrente è mostrato il relativo bilancio. Per attivare o disattivare i concorrenti, si selezioni il bottone relativo. Il concorrente attivo per default è quello turchese.

simutrans-124.3/simutrans/text/it/railtools.txt000066400000000000000000000072531474050137200217600ustar00rootroot00000000000000Ferrovie

Finestra Strumenti Ferrovie

Questa finestra contiene gli strumenti per costruire binari, segnali, tunnel, depositi, passaggi a livello e stazioni.

Nell'angolo in alto a sinistra c'è il tool per costruire i binari. Per costruire una ferrovia, prima si faccia clic sulla casella di partenza e quindi su quella di arrivo. Simutrans costruirà un binario fra le due caselle. Per costruire il binario verrano usate solo caselle libere: non verranno attraversate strade, costruiti ponti o tunnel. Se nessuna connessione è possibile, non accade nulla.

Il prossimo tool alla destra del precedente è quello per piazzare segnali ferroviari. I segnali sono usati per vincolare il movimento dei treni. E' possibile usarli per permettere a due treni di percorrere lo stesso tratto di binario, piazzandoli ogni poche caselle lungo la linea interessata. Per costruire un segnale si deve fare clic nel punto della linea in cui lo si vuole piazzare. I segnali appaiono ai lati delle caselle, ma in realtà viene messo un segnale su ogni bordo delle caselle adiacenti. Questo è importante in quanto una casella in cui è presente un segnale non può contenerne un altro. I segnali di senso unico possono essere usati per costringere un treno ad andare in una data direzione. Per costruire un segnale di senso unico basta piazzare un normale segnale ferroviario e fare clic su di esso. Con ulteriori click del mouse si cambierà la direzione e infine si ritornerà ad avere un normale segnale ferroviario. Attenzione: un segnale errato potrebbe impedire ai treni di muoversi come desiderato! Per rimuovere un segnale si deve usare il tool di rimozione sul segnale stesso o sui suoi bordi; questo rimuoverà il segnale lasciando intatti i binari.

L'ultimo simbolo della prima riga permette di costruire i tunnel. I tunnel sono utilizzati per creare una linea ferroviaria che attraversa una montagna, evitando quindi di doverla aggirare o costruire percorsi in salita. Per costruire un tunnel è necessario prima predisporre i binari ai lati della montagna, entrambi allo stesso livello. Quindi basta fare clic su una delle due estremità per connetterle con un tunnel.

Sotto il tool tunnel è presente quello per i passaggi a livello. Gli attraversamenti sono utilizzati per permettere intersezioni con eventuali strade. Per costruirne uno, è sufficiente fare clic nel punto della linea ferroviaria in cui si desidera crearlo.

Alla sinistra del precedente, c'è il simbolo per la costruzione di un deposito. I depositi sono usati per comprare e gestire i veicoli ferroviari, motrici e vagoni. Per costruire un deposito basta fare clic ad una estremità di una linea ferroviaria già esistente.

L'ultimo simbolo è quello delle stazioni. Le stazioni sono usate dai treni per caricare e scaricare merci e passeggeri e possono essere di qualsiasi forma e dimensione. Attualmente, le stazioni possono contenere un numero infinito di unità di merci, ma le fabbriche vi spediscono merci solo se sono già in attesa meno di 1000 unità. Le stazioni sono costituite da singoli segmenti. Per costruire un segmento si faccia clic sulla casella in cui lo si vuole mettere. Le stazioni possono essere costruite sopra binari già esistenti, ma non possono essere messe su colline, curve o intersezioni. Ogni segmento costruito adiacente ad una stazione già esistente diverrà parte integrante di quella stazione. Ogni segmento può ospitare un massimo di 2 veicoli ferroviari, quindi ci si assicuri che la lunghezza delle stazioni sia sufficiente a contenere il più lungo treno che vi passa: i vagoni che rimangono fuori da una stazione non vengono nè caricati nè scaricati!

simutrans-124.3/simutrans/text/it/removal_tool.txt000066400000000000000000000043241474050137200224460ustar00rootroot00000000000000Strumento rimozione

Strumento rimozione

Lo strumento rimozione è usato per distruggere e rimuovere gli elementi non voluti e gli ostacoli alle costruzioni sul singolo quadrato nella vista di gioco.

Utilizzo: clicca sull'icona con la croce rossa (bulldozer nel pak128) in cima alla vista di gioco o premi [a] per aprire lo strumento di rimozione (cambia il cursore in una croce rossa sopra una nuvola di polvere).
Posizionare il cursore sulla vista di gioco e un bordo giallo indicherà la posizione dove lo strumento farà effetto (le coordinate sulla mappa saranno riportate nella barra in fondo). Poi clicca sull'elemento nella vista di gioco per rimuovere.

Il costo dell'operazione è riportato nella vista di gioco sotto il sito di costruzione. Esso sarà uguale al costo di costruzione.
Il costo di distruzione degli edifici cittadini è riportato nella finestra di dialogo aperta con lo strumento ispezione. Per tagliare un albero sono necessari 100 crediti.

Strumento rimozione può essere usato per rimuovere pedoni e auto cittadine.

Gli elementi presenti nel singolo quadrato di gioco sono rimossi nell'ordine: pedoni o auto private, segnali, fermate o piattaforme, elettrificazioni, strade.

{Consigli: per rimuovere un veicolo di un giocare, venderlo da Dettagli convoglio.
Per rimuovere industrie, attrazioni o municipi passare prima al giocatore servizio pubblico. Nota: L'uso dello strumento rimozione su un municipio rimuove tutti gli edifici cittadini dall'area urbana.
Usa [Ctrl] per applicare lo strumento ad un livello superiore.
Per distruggere/rimuovere le cose di un altro giocatore, selezionarlo prima nella finestra giocatori.
Per rimuovere segmenti di binario o strada usare rimuovi binari (presente anche tra gli strumenti per tram) o rimuovi strade.}

simutrans-124.3/simutrans/text/it/roadtools.txt000066400000000000000000000044361474050137200217560ustar00rootroot00000000000000Aiuto - Strumenti Strade

Strumenti Strade

Con questa finestra di dialogo si può avere accesso a tutti gli strumenti necessari per costruire strade, fermate dell'autobus, tunnel, depositi, passaggi a livello e piazzali di carico.

Nell'angolo in alto a sinistra è presente il simbolo che identifica lo strumento per costruire le strade. Per iniziare a costruire una strada bisogna prima cliccare sul punto di inizio, quindi spostarsi sul punto in cui la si vuole far terminare e cliccare nuovamente con il tasto sinistro del mouse: verrà costruita una strada fra i due punti indicati.

Proseguendo a destra, troviamo il simbolo che contraddistingue lo strumento per la costruzione delle fermate dell'autobus. Queste fermate sono usate per permettere agli autobus di caricare i passeggeri in attesa. Ogni fermata ha la capacità di due autobus, una per ciascuna direzione. Per costruirne una basta cliccare nel punto in cui si desidera posizionarla. Possono essere costruite sulle strade ma non in curve o incroci.

L'ultimo simbolo della prima riga indica lo strumento per costruire tunnel. I tunnel vengono utilizzati per creare una strada diretta attraverso una montagna, evitando di doverla aggirare o scalare (le strade tortuose e/o in salita rallentano molto i veicoli). Per costruire un tunnel, per prima cosa occorre aver costruito le due strade ai lati della montagna (devono essere allo stesso livello). Cliccando su una delle due terminazioni il tunnel verrà automaticamente costruito.

Sotto questo simbolo c'è quello per il passaggio a livello. Viene usato per consentire ai treni di attraversare le strade. Per costruirne uno, è sufficiente cliccare nel punto di una strada già esistente in cui lo si desidera piazzare.

Alla sinistra di questo simbolo c'è quello per costruire i depositi. I depositi sono gli edifici in cui è possibile comprare tutti i veicoli stradali, come furgoni, bus, camion e rimorchi. Per posizionare un deposito basta cliccare sull'estremità di una strada già esistente.

L'ultimo simbolo presente è il piazzale di carico. Sono usati dai camion per caricare e scaricare le merci; sono in grado di ospitare un numero massimo di due veicoli. Per costruirne una il procedimento è lo stesso dei depositi (vedi sopra).

simutrans-124.3/simutrans/text/it/save.txt000066400000000000000000000010151474050137200206740ustar00rootroot00000000000000Aiuto - Salvataggio

Salvataggio di un gioco

Questa finestra elenca tutti i nomo di file dei giochi salvati precedentemente. Se si vuole sostituire un file esistente, si faccia clic sul bottone sul quale vi compare il nome: Simutrans salverà il gioco con quel nome.

Se si vuole invece salvare il gioco con un nuovo nome, si selezioni con il mouse la casella di inserimento e vi si scriva dentro il nuovo nome. Cliccando il bottone "Salva", il gioco verrà salvato con il nuovo nome.

simutrans-124.3/simutrans/text/it/scenario.txt000066400000000000000000000005751474050137200215530ustar00rootroot00000000000000Aiuto - Scenario

Scenari

Simutrans permette di giocare utilizzando scenari, la vincita negli scenari si ottiene raggiungendo determinati obbiettivi quali ad esempio: raggiungere una certa ricchezza entro un determinato lasso di tempo, erigere un quartier generale monumentale, connettere tra loro determinate fabbriche etc. etc.

simutrans-124.3/simutrans/text/it/shiptools.txt000066400000000000000000000026451474050137200217740ustar00rootroot00000000000000Aiuto - Strumenti Imbarcazioni

Finestra Strumenti Imbarcazioni

Questa finestra dà accesso a tutti i tool con i quali si possono costruire depositi di imbarcazioni e porti.

Il primo strumento a sinistra è quello per costruire un porto. Selezionandolo, il cursore si trasforma in un porto. I porti sono utilizzati per consentire alle imbarcazioni di caricare e scaricare merci e passeggeri provenienti da fabbriche e città vicine. Per costruire un porto, si faccia clic su un bordo (rettilineo) di costa: verrà creato un porto composto da due caselle. Si possono costruire porti anche molto grandi, tanto quanto la conformazione delle coste lo permette, ripetendo l'operazione precedente su porzioni di costa adiacenti. Per indirizzare una imbarcazione in un porto si deve mandarla in una casella adiacente al porto, non al porto stesso! Attenzione: in caso di errore, i porti non possono ancora essere rimossi del tutto!

Sull'ultima riga ci sono due simboli, entrambi usati per costruire depositi: la differenza fra i due sta nel fatto che quello a sinistra si affaccia sulla sinistra, l'altro sulla destra. Selezionando uno di essi, il cursore assume la forma di un deposito. I depositi sono usati per costruire tutti i possibili tipi di imbarcazioni che sono disponibili. Per posizionare un deposito è sufficiente fare clic sulla porzione d'acqua in cui lo si vuole mettere.

simutrans-124.3/simutrans/text/it/signal_spacing.txt000066400000000000000000000026631474050137200227310ustar00rootroot00000000000000Aiuto - Spaziatura automatica dei segnali

Spaziatura automatica dei segnali

Spaziatura automatica dei segnali permette di piazzare su di un percorso, in maniera automatica, una serie di segnali equispaziati tra loro.

Metodo di utilizzo:

-- Ctrl-click su un segnale fa apparire l'interfaccia.
-- Click-and-drag lungo il tracciato mostra la preview dei nuovi segnali, rilasciando il bottone i segnali diventeranno definitivi. I segnali saranno costruiti permettendo ai treni di muoversi lungo il percorso solo nella direzione che si è usata per trascinare i segnali.
-- Gioco in rete: per prima cosa ctrl-click sul tracciato e poi rilasciare il bottone del mouse. Premere il tasto e muovere il mouse per vedere l'anteprima. Rilasciare il bottone per costruire.

Parametri:

-- Spaziatura dei segnali: numero di piastrelle consecutive oltre le quali verrà piazzato il segnale (i percorsi in diagonale valgono 1/2 piastrella). Questo valore è visualizzato sull'icona selezionando il segnale.
-- Rimozione segnali intermedi: se selezionato tutti gli altri segnali sul percorso saranno cancellati.
-- Rimpiazza gli altri segnali: se selzionato i segnali in corrispondenza dei nuovi segnali saranno cancellati.

Questi parametri possono essere impostati per tutti i tipi di segnale in modo indipendente.

simutrans-124.3/simutrans/text/it/sound.txt000066400000000000000000000006571474050137200211010ustar00rootroot00000000000000Aiuto - Suono & Musica

Proprietà di Suono & Musica

Da questo menù è possibile impostare il volume dei suoni, della musica e quale colonna sonora ascoltare durante il gioco.

Per cambiare il volume dei suoni o della musica si può agire sul controllo a scorrimento (sinistra = volume più basso). Per cambiare la colonna sonora è invece sufficiente agire sulle frecce in fondo alla finestra.

simutrans-124.3/simutrans/text/it/station.txt000066400000000000000000000027771474050137200214370ustar00rootroot00000000000000Fermata/Stazione

Informazioni Fermata/Stazione

Attraverso questa finestra di dialogo si possono avere informazioni su una specifica fermata/stazione su cui si è cliccato. Si possono vedere le merci in attesa, quali merci sono necessarie alle fabbriche vicine e quali altre fermate e stazioni sono connesse direttamente a questa.

E' possibile anche cambiare il nome della fermata/stazione utilizzando il box vicino al top della finestra, dove il nome è visualizzato. Per farlo, si deve cliccare il box e editare il nome, premendo Invio quando si ha finito.

Al fondo della finestra di dialogo ci sono le informazioni relative ai beni in attesa alla fermata/stazione. Questi sono strutturati in modo che ci siano delle voci principali, una per ogni tipo di merce, per es.
402 auto in attesa
83 passeggeri in attesa

Quindi ognuna di queste voci è divisa in sotto-voci che indicano dove le merci sono dirette e l'esatto ammontare di ognuna, per es:

56 passeggeri in attesa
- 25 passeggeri > Stazione Collevecchio
- 29 passeggeri > Stazione Boscocorto via Pratofiorito ferm. est.
- 2 passeggeri > Castelforte ferm. C.so Roma

Nell'angolo in alto a destra della finestra c'è un bottone etichettato 'Dettagli'. Si clicchi su di esso per aprire una finestra separata che illustra le merci richieste da fabbriche vicine e tutte le rotte dirette a partire da questa stazione/fermata.

Le rotte dirette sono divise per tipo di merci.

simutrans-124.3/simutrans/text/it/station_details.txt000066400000000000000000000032431474050137200231310ustar00rootroot00000000000000Dettagli fermata

Dettagli fermata

Dettagli fermata fornisce più informazioni riguardo una fermata (dove i veicoli caricano e scaricano beni e passeggeri).

Dettagli fermata si apre dal bottone Dettagli nelle informazioni su di essa.
Se non sono visibili tutti gli elementi, ridimensiona Dettagli fermata o usa gli slider per muoverli.

Le informazioni riportate includono:
Fabbriche connesse: nomi e coordinate sulla mappa (tra parentesi) delle industrie nell'area circostante la fermata.
{Consigli: usa [v] per visualizzare le aree circostanti le fermate nel gioco.}

Merci necessarie alle fabbriche vicine: tipi di beni richiesti dalleindustrie nella zona circostante la stazione.

Linee che servono la fermata: Linee che usano la stazione.
Le linee sono elencate alfabeticamente nell'ordine dei caratteri ASCII (le maiuscole prima della minuscole).

Tragitti diretti da qui: elenca i nomi delle fermate che possono essere raggiunte senza cambiare linea e i tipi di beni (merci o passeggeri) che possono essere trasportati.
Le linee sono elencate alfabeticamente nell'ordine dei caratteri ASCII (le maiuscole prima della minuscole) secondo il tipo di trasporto, nome della fermata e tipo di bene che può essere trasportato (che è anche visualizzato per ogni stazione).

simutrans-124.3/simutrans/text/it/trafficlight_info.txt000066400000000000000000000004051474050137200234210ustar00rootroot00000000000000Aiuto - Semafori

Semafori

E' possibile controllare la durata del verde e del rosso dei semafori. I numeri che si possono impostare sono la durata del verde (in secondi) per le direzioni nord/sud ed est/ovest.

simutrans-124.3/simutrans/text/it/window.txt000066400000000000000000000114471474050137200212570ustar00rootroot00000000000000Aiuto uso interfaccia di gioco

Interfaccia di gioco

In Simutrans si gioca attraverso l'Interfaccia di gioco che contiene le informazioni sul gioco corrente, l'accesso alle barre degli strumenti e controlli di gioco e una vista della mappa.

Barra del titolo: nella parte sinistra della barra del titolo dell'Interfaccia di gioco è riportata la versione e la data di rilascio di Simutrans che sta girando.
La parte destra contiene i controlli per minimizzare e massimizzare l'Interfaccia di gioco e per uscire da Simutrans.

Icone: una riga di icone, usata per accedere alle barre degli strumenti e dei controlli mentre si gioca a Simutrans, è direttamente sotto la barra del titolo. Icone (cliccare per utilizzarle) sono raggruppate in tre set:

- Menù principale include:
- floppy-disc: apre Opzioni di gioco
- map: apre Mappa
- lente d'ingrandimento: seleziona Visualizza
- modifica terreno: apre la barra terreno
- treno: apre la barra ferrovie/treni
- monorotaia/maglev: apre la barra dei trasporti su monorotaia
- tram: apre la barra dei tram
- camion: apre la barra trasporti su strada
- nave: apre la barra trasporti su acqua
- aeroplano: apre la barra trasporti aerei
- pallino rosso dentro cerchio giallo (gru in pak128): apre la barra delle costruzioni speciali
- croce rossa (bulldozer in pak128): seleziona lo strumento di rimozione

- Menù gestione include:
- rete: apre la gestione linee
- lista: apre la lista
- cassetta delle lettere: apre il centro messaggi
- money-icon: opens Finances

- Altre opzioni include:
- macchina fotografica: cattura il contenuto dell'Interfaccia di gioco (senza la barra del titolo) e la salva come file bitmap nella cartella simutrans/screeshot/
{Consiglio: le immagini possono essere catturate premendo [c].}
- tazzina di caffè: mette o toglie dalla pausa il gioco.
{Consiglio: può essere usato anche il tasto [p]}.
- >>: seleziona e deseleziona l'accelerazione del tempo. (cambia la velocità con cui T passa nel gioco).
{Consiglio: può essere usato anche il tasto [W]
IMPORTANTE: il gioco non può essere rallentato;Display Informationindica se il computer può resistere al cambiamento.}
- ?: apre Aiuto Simutrans

La vista di gioco di una porzione della mappa corrente è rappresentata sotto le icone.
Puoi ingrandire o rimpicciolire la vista o muoverti per la mappa utilizzando il mouse o la tastiera.

Una barra di scorrimento temporanea appare in fondo e riporta i messaggi.
{Consigli: clicca sul messaggio per centrale la relativa posizione.}

Una barra in fondo riporta le informazioni riguardanti la mappa corrente.
Le informazioni riportate, da sinistra a destra, includono:
data e ora: data e ora correnti, a cui seguono un'icona e il nome della stagione.
bilancio: soldi disponibili per le costruzioni e altre spese (acquisto veicoli, mantenimento infrastrutture e costi operativi dei veicoli).
coordinate: indicano la posizione del cursore nella vista di gioco. Sono riportate le coordinate X e Y e l'altezza.
T: indica la velocità a cui passa il tempo nel gioco.
{Consigli: Usa [.] / [,] per accelerare/decelerare il tempo, T ; Visualizza informazioniindica se il computer può resistere al cambiamento.
L'uso di scorrimento veloce sostituisce T con ">>" on bottom-bar.}
linea del tempo: indica se la linea del tempo è stata selezionata nel gioco corrente.

simutrans-124.3/simutrans/text/ja.tab000066400000000000000000001737661474050137200176720ustar00rootroot00000000000000§Japanese PROP_FONT_FILE m+10r.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: ja Japanese # # Encoding: UTF-8 # # Font: m+10r.bdf # # Date Created: 10.01 2025 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times 時刻を月㮠日:時:分 ã¨ã—ã¦è¡¨ç¤º AMBIENT_SOUND 環境音ã®éŸ³é‡ CASH_SOUND 売買ã®éŸ³é‡ cl_btn_filter_disable 無効 cl_btn_filter_enable 有効 cl_btn_filter_settings 設定 cl_btn_sort_asc 昇順 cl_btn_sort_desc é™é † cl_btn_sort_id ç•ªå· cl_btn_sort_income åŽç›Š cl_btn_sort_name åå‰ cl_btn_sort_type タイプ clf_btn_alle å…¨é¸æŠž clf_btn_invers å転 clf_btn_keine 全解除 climate area percentage 気候区分ã®å‰²åˆ Continue Game å‰å›žã®ç¶šã CROSSING_SOUND è¸åˆ‡ã®éŸ³é‡ FACTORY_SOUND 産業施設ã®éŸ³é‡ Find matching convois åŒä¸€è»Šä¸¡ã®æ¤œç´¢ gl_btn_sort_bonus ボーナス順 gl_btn_sort_name åå‰é † gl_btn_sort_revenue åŽå…¥é † gl_btn_unsort ソート無㗠height based æ¨™é«˜ã®æ°—候 hl_btn_filter_disable 無効 hl_btn_filter_enable 有効 hl_btn_filter_settings 設定 hl_btn_sort_asc 昇順 hl_btn_sort_desc é™é † hl_btn_sort_name åå‰é † hl_btn_sort_type タイプ hl_btn_sort_waiting 待機 hlf_btn_alle å…¨é¸æŠž hlf_btn_invers å転 hlf_btn_keine 全解除 humidities 湿潤基準 Install インストール Lake æ¹– Lake height æ¹–é¢æ°´ä½ Maximize height levels 高ã•を最大化ã™ã‚‹ moisture land é™¸åœ°ã®æ¹¿æ½¤åº¦ moisture water å·ã€æ± å‘¨è¾ºã®æ¹¿æ½¤åº¦ Networks 路線図 Num pad keys always move map Numlockを無視ã™ã‚‹ Open Sea æµ· Queueing 待機ã®å¢—減 rainfall é™é›¨é‡ Reselect closes tools é¸æŠžæ¸ˆã®ãƒ„ールボタンを押ã™ã¨é¸æŠžã‚’解除ã™ã‚‹ Return to menu ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã«æˆ»ã‚‹ Road toll 通行料 Scenario シナリオ sea 海洋性気候 Single GUI シングルGUI Sound range: 効果音ã®å†ç”Ÿç¯„囲 Start this as a server ã“ã®ã‚²ãƒ¼ãƒ ã‚’サーãƒãƒ¼ã¨ã—ã¦é–‹å§‹ã—ã¾ã™ã€‚ temperature borders æ°—å€™åŒºåˆ†ã®æ°—温基準 temperature-humidity based 温湿度 TOOL_SOUND ツールã®éŸ³é‡ TRAFFIC_SOUND 乗り物ã®éŸ³é‡ Transfers 乗陿•° Tutorial ãƒãƒ¥ãƒ¼ãƒˆãƒªã‚¢ãƒ« #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic 極気候 desert 砂漠気候 mediterran 地中海性気候 rocky 氷雪気候 temperate 温暖気候 tropic 熱帯気候 tundra ツンドラ気候 #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed シナリオスクリプトã®ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—㟠Bridge blocked by way below or above. 建設予定地ã®ä¸Šã¾ãŸã¯ä¸‹ã«åˆ¥ã®è»Œé“ãŒã‚ã‚‹ãŸã‚æ©‹æ¢ã‚’建設ã§ãã¾ã›ã‚“ Can't buy obsolete vehicles! æ—§åž‹ã®ä¹—り物ã¯è³¼å…¥ã§ãã¾ã›ã‚“。 Cannot alter water ã“ã®çªªåœ°ã«ã¯ã“ã‚Œä»¥ä¸Šã€æ°´ã‚’満ãŸã™ã“ã¨ã‚‚排出ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã›ã‚“。 Cannot build on a double slope! ã“ã®åž‹ã®æ©‹æ¢ã¯ç·©ã‚„ã‹ãªå‚ã‹å¹³ã‚‰ãªåœ°é¢ã®ä¸Šã‹ã‚‰ã®ã¿å»ºè¨­ã§ãã¾ã™ Cannot built depot here! ã“ã“ã«è»Šåº«ã‚’\n建ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 Cannot built this station/building\nin underground mode here. 駅ビル/駅舎ã¯ã€\n地下ã«ã¯å»ºè¨­ã§ãã¾ã›ã‚“。 Cannot connect to the\ncenter of a double slope! ダブルスロープã®ä¸­é–“ã®é«˜ã•ã«ã¯æ©‹ã‚’建設ã§ãã¾ã›ã‚“。 Cannot create generic line!\nSelect line type by\nusing filter tabs. 汎用ã®è·¯ç·šã‚’作æˆã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\nタブã§è·¯ç·šã®ã‚¿ã‚¤ãƒ—ã‚’é¸ã‚“ã§ãã ã•ã„。 Cannot create socket ソケットエラー:\n接続を確立ã§ãã¾ã›ã‚“。\nCannot create socket Cannot rotate this building! ã“ã®å»ºç‰©ã®æ–¹å‘ã¯å¤‰ãˆã‚‰ã‚Œã¾ã›ã‚“。 Client closed connection during transfer ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®æŽ¥ç¶šãŒåˆ‡æ–­ã•れã¾ã—ãŸã€‚ Convoi handles exhausted! æœ€å¤§ç·¨æˆæ•°(65535)ã«é”ã—ã¾ã—ãŸã€‚\nã“れ以上追加ã§ãã¾ã›ã‚“。 Convoy already deleted! ç·¨æˆã¯æ—¢ã«å‰Šé™¤ã•れã¦ã„ã¾ã™ã€‚ Could not open file ファイルを開ã‘ã¾ã›ã‚“ Das Feld gehoert\neinem anderen Spieler\n ã“ã®å ´æ‰€ã¯\nä»–ã®ãƒ—レイヤーã«ã‚ˆã£ã¦\nã™ã§ã«å æ‹ ã•れã¦ã„ã¾ã™ã€‚\n Depots cannot be built on runways! 車庫を滑走路上ã«å»ºè¨­ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ï¼ Depots must be built on flat dead-end way tiles! 車庫ã¯å¹³å¦ãªé“è·¯ã®è¡Œãæ­¢ã¾ã‚Šã«è¨­ç½®ã§ãã¾ã™ Der Besitzer erlaubt das Entfernen nicht 撤去ã§ãã¾ã›ã‚“。\nã“ã“ã¯ä»–ç¤¾ã®æ‰€æœ‰åœ°ã§ã™ã€‚\n Diese Zusammenstellung kann nicht fahren!\n ã“ã®çµ„ã¿åˆã‚ã›ã§é‹è¡Œã™ã‚‹\nã“ã¨ã¯ã§ãã¾ã›ã‚“。\n Flugzeughalt muss auf\nRunway liegen!\n é§æ©Ÿå ´ã¯èª˜å°Žè·¯ä¸Šã«ã®ã¿è¨­ç½®ã§ãã¾ã™ï¼ Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n ã“ã“ã«æ ¼ç´åº«ã‚’\n建ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。 Hier kann kein\nSignal aufge-\nstellt werden!\n ã“ã“ã«ä¿¡å·æ©Ÿã‚’\n設置ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\n In order to lock the game, you have to protect the public player by password! ゲームをä¿è­·ã™ã‚‹ãŸã‚ã€\n公共事業ã«ãƒ‘スワードを\nã‹ã‘ã¦ä¸‹ã•ã„。 Loading a new game will end the current server session! æ–°ã—ã„ゲームを読ã¿è¾¼ã‚€ã¨ã€ç¾åœ¨æŽ¥ç¶šã•れã¦ã„るオンラインã®ã‚²ãƒ¼ãƒ ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‹ã‚‰åˆ‡æ–­ã•れã¾ã™ï¼ Lost connection\nto server! サーãƒãƒ¼ã¸ã®æŽ¥ç¶šãŒ\n切断ã•れã¾ã—㟠Lost synchronisation\nwith server. サーãƒãƒ¼ã¨ã®åŒæœŸãŒ\n失ã‚れã¾ã—㟠Maglevhalt muss auf\nMaglevschiene liegen!\n リニアã¯ãƒªãƒ‹ã‚¢è»Œé“上ã«ã®ã¿\nåœè»Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ Monorailhalt muss auf\nMonorail liegen!\n モノレールã¯ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«è»Œé“上ã«ã®ã¿\nåœè»Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ Monorails are not available yet! モノレールã¯ã¾ã é–‹ç™ºã•れã¦ã„ã¾ã›ã‚“ï¼ More than one possibility to build this dock found. ã“ã®æ¸¯ã‚’建設å¯èƒ½ãªå€™è£œãŒè¤‡æ•°ã‚りã¾ã™ã€‚ Narrowgaugehalt muss auf\nNarrowgauge liegen!\n ナローゲージ用ã®é§…ã¯\nナローゲージ上ã«ã®ã¿\n設置ã§ãã¾ã™ã€‚ No bridges over runways! 滑走路をã¾ãŸãæ©‹æ¢ã¯å»ºè¨­ã§ãã¾ã›ã‚“ No curves on runways 滑走路ã«ã‚«ãƒ¼ãƒ–ã¯ä½œã‚Œã¾ã›ã‚“! No suitable crossing é©åˆ‡ãªäº¤å·®ãŒã‚りã¾ã›ã‚“! (最高速度ãŒé€Ÿã™ãŽã‚‹ã®ã‹ã‚‚ã—れã¾ã›ã‚“) No suitable way on the ground! 設置ã«é©å½“ãªå ´æ‰€ã§ã¯ã‚りã¾ã›ã‚“。 No through station here! ã“ã“ã«é§…/åœè»Šå ´ã‚’建ã¦ã‚‹ã“ã¨ã¯\nã§ãã¾ã›ã‚“ï¼ Not enough bytes transferred データ転é€ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ Not enough clearance. 上下ã«é–“隔を空ã‘ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ Not enough money! 資金ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚ On narrowgauge track only!\n ナローゲージ上ã«ã®ã¿\nåœè»Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ Only public player can lock games! 公共事業ã ã‘ãŒã€Œãƒ—レイヤー変更ã®ç¦æ­¢ã€ã¨ãã®è§£é™¤ãŒã§ãã¾ã™ã€‚\nã¾ãŸãƒ­ãƒƒã‚¯è§£é™¤ã«ã¯å…¬å…±äº‹æ¥­ã®ãƒ‘スワードãŒå¿…è¦ã§ã™ã€‚ Only up and down movement in the underground! 地下ã®ã‚¿ã‚¤ãƒ«ã«ã¯æ–œé¢ã‚’作るスロープツールã¯åˆ©ç”¨ã§ãã¾ã›ã‚“\n地下鉄や地下é“ã®é«˜åº¦ã‚’変ãˆã‚‹ã«ã¯ä¸Šã’下ã’ã™ã‚‹ã‚¹ãƒ­ãƒ¼ãƒ—ツールを使用ã—ã¦ãã ã•ã„ Out of funds 資金ãŒã‚りã¾ã›ã‚“ Post muss neben\nHaltestelle\nliegen!\n 郵便局や駅舎ã¯ã€é§…ã‚„åœè»Šå ´ã®\n付近ã«å»ºè¨­ã—ã¦ãã ã•ã„。\n Protocoll error (expecting game) プロトコルエラー\nProtocoll error (expecting game) Schiffhalt muss im\nWasser liegen!\n èˆ¹èˆ¶ã¯æ¸¯ã®å‘¨è¾ºã«ã®ã¿\nåœæ³Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚\n Server busy サーãƒãƒ¼ä½¿ç”¨ä¸­\nServer busy Server version too new サーãƒãƒ¼ã§ä½¿ç”¨ã•れã¦ã„ã‚‹ã‚‚ã®ã‚ˆã‚Šå¤ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ—ログラムã§ã™ Ship depots must be built on water! é€ èˆ¹æ‰€ã¯æ°´ä¸Šã«å»ºè¨­ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ï¼ Show all revenue messages å…¨ã¦ã®ãƒ—レイヤーã®åŽç›Šã‚’表示 Show no revenue messages å…¨ã¦ã®ãƒ—レイヤーã®åŽç›Šã‚’éžè¡¨ç¤º Show only player's revenue ç¾åœ¨ã®ãƒ—レイヤーã®åŽç›Šã®ã¿è¡¨ç¤º Terraforming not possible\nhere in underground view スロープツールã¯ã€\n地下ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。 This tunnel branches. You can try Control+Click to remove. ã“ã®ãƒˆãƒ³ãƒãƒ«ã¯æžåˆ†ã‹ã‚Œã—ã¦ã„ã¾ã™ã€‚Control+クリックã§å‰Šé™¤ã§ãã¾ã™ã€‚ Too far away to merge stations! é§…ã‚’çµ±åˆã™ã‚‹ã«ã¯é›¢ã‚Œã™ãŽã¦ã„ã¾ã™! Upgrade must have\na higher level ã“ã®é§…ã«ã¯ã‚¢ãƒƒãƒ—グレードã§ãã¾ã›ã‚“\n\nよりレベルã®é«˜ã„é§…ã‚’é¸æŠžã™ã‚‹ã‹ã€\n一度撤去ã—ã¦ã‹ã‚‰ã€ç½®ãæ›ãˆã¦ãã ã•ã„ Vehicle %s cannot choose because stop too short! 車両 %sã®åœè»Šã§ãるホームãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。ホームãŒçŸ­ã™ãŽã¾ã™ã€‚ Zughalt muss auf\nSchiene liegen!\n 列車ã¯ç·šè·¯ä¸Šã«ã®ã¿\nåœè»Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s ヘルプ

ç·åˆãƒ˜ãƒ«ãƒ—

*:未訳(英文ã§è¡¨ç¤ºï¼‰

Simutransã«ã¤ã„ã¦

%1$s

ä½¿ã„æ–¹

%2$s

ゲームã®é–‹å§‹

%4$s

éŠã³æ–¹

%5$s

ツール

%3$s

ãã®ä»–ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°

%6$s Keyboard Help\n

Keyboard Help

\n キーボード ヘルプ

キーボード ヘルプ

キー割り当ã¦ã®ä¸€è¦§è¡¨ã§ã™ã€‚何もæ“作ãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ãªã„キーを押ã™ã¨ã€
ã“ã®ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ãƒ˜ãƒ«ãƒ—ウィンドウãŒé–‹ãã¾ã™ã€‚

アルファベットã®å¤§æ–‡å­—ã¨å°æ–‡å­—ã¯åŒºåˆ¥ã•れã¾ã™ã€‚大文字ã®å ´åˆã¯ã€
shiftキーを押ã—ãªãŒã‚‰ã‚­ãƒ¼ã‚’押ã—ã¾ã™ã€‚日本語入力ã¯è§£é™¤ã—ã¦ãã ã•ã„。

ウィンドウæ“作
Backspace - ã™ã¹ã¦ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦/ツールãƒãƒ¼ã‚’é–‰ã˜ã¾ã™
Delete, ESC - アクティブãªã‚¦ã‚£ãƒ³ãƒ‰ã‚¦/ツールãƒãƒ¼ã‚’é–‰ã˜ã¾ã™
F1 - ヘルプウィンドウを開ãã¾ã™

ゲーム画é¢ã®ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã€€ï¼ˆæ•°å­—キーã€çŸ¢å°ã‚­ãƒ¼ï¼‰
1,2,3,4,6,7,8,9 - ゲーム画é¢ã‚’スクロールã—ã¾ã™
↑,↓,→,↠- ゲーム画é¢ã‚’スクロールã—ã¾ã™

ゲーム画é¢ã®ã‚ºãƒ¼ãƒ 
>,PageUp - ゲーム画é¢ã‚’ズームインã—ã¾ã™
<,PageDown - ゲーム画é¢ã‚’ズームアウトã—ã¾ã™

[Ctrl]+é“è·¯/ç·šè·¯/トンãƒãƒ«ãƒ„ール
ç›´ç·šã®é“è·¯/線路を敷設ã§ãã¾ã™ã€‚
既存ã®é“è·¯/線路をã€ä½Žé€Ÿãªé“è·¯/ç·šè·¯ã§ç½®ãæ›ãˆã¾ã™ã€‚
トンãƒãƒ«ã®å…¥ã‚Šå£ã®ã¿ã‚’建設ã—ã¾ã™ã€‚

[Ctrl]+V
クリップボードã‹ã‚‰ãƒ†ã‚­ã‚¹ãƒˆã‚’貼り付ã‘ã¾ã™ã€‚(Windowsã®ã¿)

ä»¥ä¸‹ã®æ“作キーã¯ã€Œ(pakフォルダ)/config/menuconf.tabã€ãƒ•ァイル
ã§å®šç¾©ã•れã¦ã„ã¾ã™ã€‚ã“ã®ãƒ•ァイルを編集ã—ã¦ã€æ“作キーã®å‰²ã‚Šå½“ã¦ã‚’変更
ã—ãŸã‚Šã€åˆ¥ã®ãƒ„ールã«ã€æ–°ãŸã«æ“作キーを割り当ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

ç¾åœ¨ã®æ“作キー一覧

At least one stop is connected to the town. 1ã¤ä»¥ä¸Šã®è¼¸é€æ–½è¨­ãŒæŽ¥ç¶šã•れã¦ã„ã‚‹è¡—ã ã‘を表示ã™ã‚‹ At least one tile is connected to one stop. 1ã¤ä»¥ä¸Šã®è¼¸é€æ–½è¨­ãŒæŽ¥ç¶šã•れã¦ã„る産業施設ã ã‘を表示ã™ã‚‹ Color according to transport capacity left 色ã¯å—ã‘入れå¯èƒ½ãªè¼¸é€èƒ½åŠ›ã®æ®‹é‡ã‚’表ã—ã¾ã™ã€‚ Color-coded terrain according to altitude. 地形ã®ç­‰é«˜ç·šã‚·ã‚§ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã®è¡¨ç¤º/éžè¡¨ç¤ºã€‚ Decrease water height æ°´ä½ã‚’下ã’ã‚‹ Highlight railroad tracks 線路をãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Highlite depots 倉庫をãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Highlite electrical transmission lines é€é›»ç·šã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Highlite factories 産業をãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Highlite forests 森をãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Highlite tourist attraction 忉€ã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ Increase water height æµ·é¢æ°´ä½ã‚’1上ã’ã‚‹ Open station/stop details é§…ã®è©³ç´°ã‚’表示 Overlay city limits 市域を表示ã—ã¾ã™ Overlay passenger destinations when a town window is open 都市ウィンドウãŒé–‹ã„ã¦ã„ã‚‹å ´åˆã€æ—…客ã®ç›®çš„地を表示ã—ã¾ã™ Overlay schedules/network スケジュール/ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’表示ã—ã¾ã™ Overlay town names 都市åを表示ã—ã¾ã™ Please click on the map to add\nwaypoints or stops to this\nschedule. マップをクリックã—ã¦ã€ä¸­ç¶™ç‚¹ã¾ãŸã¯\n駅をスケジュールã«è¿½åŠ ã—ã¦ãã ã•ã„。 Remove double stops from schedule スケジュールã‹ã‚‰äºŒé‡åœè»Šã‚’削除ã—ã¾ã™ Set tile climate %s 地é¢ã‚¿ã‚¤ãƒ«ã®æ°—候を%sã«å¤‰æ›´ã—ã¾ã™ã€‚ Show capacity and if halt is overcrowded å„é§…/åœç•™æ‰€ã®å¾…åˆå®¤å®šå“¡ã®å¤§ãã•ã¨æ··é›‘度を表示 Show how many convoi reach a station é§…ã«åˆ°ç€ã—ãŸè»Šä¸¡ã®æ•°ã‚’表示 Show how many people/much is waiting at halts 待機é‡ã‚’表示 Show initial passenger departure 旅客ãŠã‚ˆã³éƒµä¾¿ã®ç™ºç”Ÿæºã‚’表示 Show level of city buildings å¸‚å†…å»ºç¯‰ç‰©ã®æ—…客度/郵便度を表示 Show mail service coverage/mail network 郵便事業ãŒè¡Œã‚れã¦ã„る範囲を表示 Show passenger coverage/passenger network 旅客事業ãŒè¡Œã‚れã¦ã„る範囲を表示 Show speedlimit of ways 軌é“/é“è·¯ã®åˆ¶é™é€Ÿåº¦ã‚’表示 Show the change of waiting at halts å…ˆæœˆã¨æ¯”ã¹ãŸå¾…機数ã®å¢—減を表示 Show the owenership of infrastructure 軌é“/é“è·¯ã®æ‰€æœ‰è€…を表示 Show transported freight/freight network 輸é€ã•れãŸè²¨ç‰©çµŒè·¯ã®è¡¨ç¤º Show usage of network ç·šè·¯/é“è·¯ã®äº¤é€šé‡ã‚’表示 Shows a listing with all industries on the map. マップ上ã«å­˜åœ¨ã™ã‚‹å…¨ã¦ã®ç”£æ¥­ã®ãƒªã‚¹ãƒˆ Sum of departure/arrivals at halts 到ç€ãƒ»å‡ºç™ºã—ãŸä¹—ã‚Šç‰©ã®æ•°ã‚’表示 #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s社ã¯\nç¾åœ¨ã€ãƒã‚¹ã®ä¾¿ã‚’\n%s町ã‹ã‚‰å所旧跡\n「%sã€(%i,%i)ã«\næä¾›ã—ã¦ã„ã¾ã™ã€‚\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s社ã¯\nç¾åœ¨ã€ãƒã‚¹ã®ä¾¿ã‚’\n%s町ã¨å·¥å ´\n「%sã€(%i,%i)\nã®é–“ã«æä¾›ã—ã¦ã„ã¾ã™ã€‚\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %sã¯\nç¾åœ¨ã€%iå°ã®ãƒˆãƒ©ãƒƒã‚¯ã§\n%s(%i,%i)ã¨\n%s(%i,%i)ã®é–“ã‚’\né‹è¡Œã—ã¦ã„ã¾ã™ã€‚ %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %sã¯\n%s(%i,%i)ã¨\n%s(%i,%i)ã®é–“ã§\næ–°ãŸãªé‰„é“を開通ã—ã¾ã—ãŸã€‚ Airline service by\n%s\nnow between\n%s \nand %s.\n %s社ã¯\nç¾åœ¨ã€èˆªç©ºä¾¿ã‚’\n%s町ã¨\n%s町\nã¨ã®é–“ã«æä¾›ã—ã¦ã„ã¾ã™ã€‚\n Ferry service by\n%s\nnow between\n%s \nand %s.\n %s社ã¯\nç¾åœ¨ã€èˆ¹ä¾¿ã‚’\n%s町ã¨\n%s町\nã¨ã®é–“ã«æä¾›ã—ã¦ã„ã¾ã™ã€‚\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n 旅行者ã¯ç¾åœ¨ã€\n%s社ãŒé‹è¡Œã—ã¦ã„ã‚‹\n%s町ã¨\n%s町をçµã¶\nãƒã‚¹ã‚’利用ã—ã¦ã„ã¾ã™ã€‚ #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS マップ編集ツール LISTTOOLS 一覧表 MAGLEVTOOLS リニアツール MONORAILTOOLS モノレール/リニアツール NARROWGAUGETOOLS ナローツール RAILTOOLS 鉄é“ツール ROADTOOLS é“路ツール SHIPTOOLS 船舶ツール SLOPETOOLS スロープツール SPECIALTOOLS 特別建築物 TRAMTOOLS 市電/軽便鉄é“ツール #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s社ã¯\n(%i, %i)ã«\n本社を建設ã—ã¾ã—ãŸã€‚ Factory chain extended\nfor %s near\n%s built with\n%i factories. 「%sã€ã¯\n事業を拡大ã—ã€æ–°ãŸã«\n%s近郊ã«\n%iã®ç”£æ¥­æ–½è¨­ã‚’建ã¦ã¾ã—ãŸã€‚ Net wealth less than 10%% of starting capital! ç·è³‡ç”£ãŒé–‹å§‹æ™‚ã®ç·è³‡ç”£ã®10%%未満ã«ãªã‚Šã¾ã—㟠New %s now available:\n%s\n æ–°åž‹%s\n「%sã€ãŒ\næ–°ãŸã«ä½¿ç”¨å¯èƒ½ã«ãªã‚Šã¾ã—ãŸã€‚ New factory chain\nfor %s near\n%s built with\n%i factories. æ–°ã—ã„産業ãƒã‚§ãƒ¼ãƒ³\n「%sã€ã¯\n%s近郊ã«\n%iã®ç”£æ¥­æ–½è¨­ã‚’建ã¦ã¾ã—ãŸã€‚ New vehicle now available:\n%s\n 「%sã€ãŒ\næ–°ãŸã«ä½¿ç”¨å¯èƒ½ã«ãªã‚Šã¾ã—ãŸã€‚ Now %u clients connected. ç¾åœ¨ã€ %u 人ãŒã‚ªãƒ³ãƒ©ã‚¤ãƒ³ä¸­ã§ã™ã€‚ overtaking 車線 Remove vehicle from map. Use with care! ! æ³¨æ„ ! ã“ã®ä¹—り物を撤去ã—ã¾ã™ ! æ³¨æ„ ! Screenshot\ngespeichert.\n スクリーンショットを\nä¿å­˜ã—ã¾ã—ãŸã€‚\n Sends the convoi to the last depot it departed from! ã“ã®ç·¨æˆã‚’一番近ã„車庫ã«å‘ã‹ã‚ã›ã¾ã™ã€‚ Server preparing game ... サーãƒãƒ¼ãŒã‚²ãƒ¼ãƒ ã®æº–備をã—ã¦ã„ã¾ã™... Trees 樹木 With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %sã«\næ–°ã—ã„記念碑ãŒå»ºç«‹ã•れã€\næ­“å–œã«æ²¸ã%i人ã®ä½æ°‘ãŒ\n見守る中ã€ç››å¤§ãªé™¤å¹•å¼ãŒ\n行ã‚れã¾ã—ãŸã€‚ #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter 路線フィルター #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ ... … (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/月) (%.2f$/km) (%.2f$/km) (%i)- (%i) (in depot) (入庫中) [0] south-facing [0] å—å‘ã [1] east-facing [1] æ±å‘ã [2] north-facing [2] 北å‘ã [3] west-facing [3] 西å‘ã [4] southeast corner [4] å—æ±ã®è§’ [5] northeast corner [5] 北æ±ã®è§’ [6] northwest corner [6] 北西ã®è§’ [7] southwest corner [7] å—西ã®è§’ [DELETE] [DEL] [SCROLLLOCK] [SCROLL LOCK] /month /月 \nBauzeit bis ~ \nBauzeit von \n登場ã™ã‚‹å¹´: \nCan't open heightfield file.\n \nマップファイルを\n読ã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥ã¾ã›ã‚“。\n \ndirection: \n接続方å‘: \nelektrified \n電化 \nHeightfield has wrong image type.\n \nマップファイルã®\nイメージ形å¼ãŒä¸æ­£ã§ã™ã€‚\n \nis reserved by: 優先列車: \nminimum speed: \n最低速度: \nnot elektrified \néžé›»åŒ– \nRibi (masked) \n制é™ä»˜ã接続方å‘: \nRibi (unmasked) \n接続方å‘    : \nSet phases: \nå—北(秒間) æ±è¥¿ï¼ˆç§’間) \nsingle way \n一方通行 \nway1 reserved by \n横断中車両: \nway2 reserved by \n通éŽä¸­è»Šä¸¡ï¼š \nwith sign/signal\n \nä¿¡å·/標識ã‚り\n %d buildings\n 市街地 %d ブロック %d convois %d ç·¨æˆ %d Einzelfahrzeuge im Depot %då°/両ãŒç•™ç½®ã•れã¦ã„ã¾ã™ã€‚ %i car(s), %i両〠%i km/h (max. %ikm/h) %i km/h (最高速度 %ikm/h) %i years %i months old. 樹齢 %i 年㨠%i ヶ月ã§ã™ã€‚ %s at (%i,%i) now public stop. %s ã¯å…¬å…±ã®åœè»Šå ´ã¨ãªã‚Šã¾ã—ãŸã€‚ %s building %s %s %s %så‰ %s %s city %d %s %s第%d%s %s factory %s %s %s %så‰ %s %s has entered a depot. %s\nã¯è»Šåº«ã«ç€ãã¾ã—ãŸã€‚\n %s has left. %s ãŒã‚ªãƒ•ラインã«ãªã‚Šã¾ã—ãŸã€‚ %s land %d %s %s郊外第%d%s %s now known as %s. %s ã¯ãƒ—レイヤーåã‚’ %s ã«å¤‰æ›´ã—ã¾ã—ãŸã€‚ %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s町ã¯\n使°‘ãŒ%i人ã«é”ã—ãŸã®ã§ã€\næ–°ã—ã„役場を建ã¦ã¾ã—ãŸã€‚ %s\nis crowded. %sãŒ\n混雑ã—ã¦ã„ã¾ã™ã€‚\n %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\n最高速度 %3$i km/h\n\n走行速度 %2$i km/h.\n\n %s\nwas liquidated. %s社ã¯\n破産ã—ã¾ã—ãŸã€‚\n資産ã¯ã™ã¹ã¦æ¸…ç®—ã•れã¾ã—ãŸã€‚ %u Client(s)\n %u åã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆ\n %u Player (%u locked)\n %u ã®ãƒ—レーヤー (%u ã¯ãƒ­ãƒƒã‚¯æ¸ˆã¿)\n スケジュールクリア <æ–°ã—ã„路線を作æˆ>

Error

注æ„: pakフォルダ内ã«ä»¥ä¸‹ã®ã‚ªãƒ–ジェクトã®é‡è¤‡ãŒã‚りã¾ã™ã€‚

Warning

addons for

注æ„: アドオンフォルダ内ã«ä»¥ä¸‹ã®ã‚ªãƒ–ジェクトã®é‡è¤‡ãŒã‚りã¾ã™ã€‚

<個別ã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«> <路線指定ãªã—> <スケジュールãªã—> <路線ã«ç™»éŒ²> 1 convoi 1ç·¨æˆ 1 Einzelfahrzeug im Depot 1å°/両ãŒç•™ç½®ã•れã¦ã„ã¾ã™ã€‚ 100 km/h = %i tiles/month 100 km/h = %i タイル/月 1LIGHT_CHOOSE 明るã•: 1WORLD_CHOOSE æ–°ã—ã„ゲームã®è¨­å®šï¼š 2LIGHT_CHOOSE カラー: 2WORLD_CHOOSE マップ番å·ï¼š 3LIGHT_CHOOSE スクロールã®é€Ÿã•: 4LIGHT_CHOOSE スクロールã®å転 5LIGHT_CHOOSE ä¹—é™å®¢ã‚’表示ã™ã‚‹ 5WORLD_CHOOSE ç”ºã®æ•°ï¼š 6LIGHT_CHOOSE 歩行者を表示ã™ã‚‹ 6WORLD_CHOOSE 交通é‡ï¼š 8WORLD_CHOOSE å¤œé–“ã¯æš—ãã™ã‚‹ A bridge must end on a way! æ©‹æ¢ã¯ã¾ã£ã™ããªé“è·¯/線路上ã«\n設置ã—ã¦ãã ã•ã„。 A bridge must start on a way! æ©‹æ¢ã¯ã¾ã£ã™ããªé“è·¯/線路上ã«\n設置ã—ã¦ãã ã•ã„。 Abfrage 調査ツール Abnehmer 需è¦å…ˆ About 解説 About scenario Copyright Abriss 撤去/å–り壊㗠Absenken 陸地を低ãã™ã‚‹ Abspanntransformator 変圧所 Accelerate time ゲームスピードを速ãã™ã‚‹ Act. load: %u MW\n é€é›»é‡:%u MW\n Active player only 自社ã®ã¿è¡¨ç¤º Add forest 森を作æˆã™ã‚‹ Add random citycar 自家用車をé“路上ã«é…ç½® add server サーãƒãƒ¼ã‚’追加 Add Stop 駅を追加 Add stops for backward travel 折り返ã—ã¦æˆ»ã‚‹ãŸã‚ã®åœè»Šé§…を追加ã—ã¾ã™ air 航空 Aircraft 航空機 aircraft_tab 貨物機 airplane 航空機 Airport 空港 AIRTOOLS 航空機ツール All 全㦠all convoi tooltips 常ã«è»Šä¸¡ã®çŠ¶æ…‹ã‚’è¡¨ç¤º Allow city growth 街を発展ã•ã›ã‚‹ Allow player change プレーヤーã®å¤‰æ›´ã‚’許å¯ã™ã‚‹ allowed climates:\n 気候æ¡ä»¶:\n Alters a schedule. é‹è¡Œã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã®ç·¨é›† Angenommene Waren 付近ã®ç”£æ¥­ã§éœ€è¦ã®ã‚る物資 anhaengen 追加 Anhaenger_tab トレーラー Anheben 陸地を高ãã™ã‚‹ Appends stops at the end of the schedule ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã®æœ€å¾Œã«é§…を追加 Apply Line 路線をé©ç”¨ Apr. 4月 April 4月 Arbeiter aus: 労åƒè€…å±…ä½åœ°: Arrivals from\n 到ç€äºˆæƒ³æ™‚é–“\n Arrived åˆ°ç€ Assets 資産 Aufloesen ç·¨æˆè§£é™¤ Aufspanntransformator 変圧所 Aug. 8月 August 8月 auto 自動 Autohalt muss auf\nStrasse liegen!\n 自動車ã¯é“路上ã«ã®ã¿\nåœè»Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚\n Available 利用å¯èƒ½ Available at custom date 以下ã®å¹´æœˆã§åˆ©ç”¨å¯èƒ½ Bahndepot 機関庫 Bankrott:\n\nDu bist bankrott.\n 破産:\n\n破産ã—ã¾ã—ãŸã€‚\n battery 蓄電池 Baum 木 baum builder æ¤æ¨¹ãƒ„ール Baustelle 建設場所 Bauzeit å»ºè¨­æ™‚æœŸã€€äººå£æ•° Beenden ゲーム終了 Beginner mode åˆå¿ƒè€…モード Besonderes Gebaeude 特殊建築物 BF é§… bio 生物 Blockstrecke ist\nbelegt\n 閉塞区間ã«ä»–ã®åˆ—車ãŒã‚りã¾ã™ã€‚\n Boden 地表 Bonus Multiplier: %i%% 速é”ボーナスå€çއ: %i%% Bonusspeed: %i km/h å¯èƒ½ãªæœ€å¤§é€Ÿåº¦: %i km/h Boost (%%) 増産率 (%%) Borderless (disabled on fullscreen) 全画é¢è¡¨ç¤º (ソフトウェアモード) bridge is too high for its type! ã“ã®åž‹ã®æ©‹æ¢ã§æž¶æ©‹ã§ãã‚‹\n橋脚ã®é«˜ã•制é™ã‚’è¶…ãˆã¦ã„ã¾ã™ã€‚ Bridge is too long for this type!\n ã“ã®åž‹ã®æ©‹æ¢ã§æž¶æ©‹ã§ãã‚‹é•·ã•ã‚’ã“ãˆã¦ã„ã¾ã™ Bruecke æ©‹ Bruecke muss an\neinfachem\nHang beginnen!\n æ©‹æ¢ã¯ç›´ç·šã®å‚ã«å»ºã¦ã¦ãã ã•ã„。\n Brueckenboden 橋上 Build air depot æ ¼ç´åº«ã®å»ºè¨­ build choosesignals 入線振分信å·ã®å»ºè¨­ Build city market 最寄りã®éƒ½å¸‚ã«ç”£æ¥­ç¶²ã‚’誘致 Build drain 変圧所を作る build HQ 本社を建設ã™ã‚‹ Build land consumer 発電所を作る Build maglev depot リニア車庫ã®å»ºè¨­ Build monorail depot モノレール基地ã®å»ºè¨­ Build narrowgauge depot ナローゲージ車庫ã®å»ºè¨­ Build powerline 高圧線を作る Build presignals プレシグナルã®å»ºè¨­ Build road depot 車庫ã®å»ºè¨­ Build ship depot 造船所ã®å»ºè¨­ Build signals ä¿¡å·ã®å»ºè¨­ Build train depot 機関庫ã®å»ºè¨­ Build tram depot 市電車庫ã®å»ºè¨­ Build truck depot 車庫ã®å»ºè¨­ Building costs estimates 建設費 Buildings 市街地 Built artifical slopes スロープ(人工斜é¢ï¼‰ã®å»ºè¨­ Built random attraction è¦³å…‰åœ°ã®æ•´å‚™ï¼ˆãƒ©ãƒ³ãƒ€ãƒ ï¼‰ Bus_tab ãƒã‚¹ Can be overgrown 生ã„茂るã“ã¨ãŒã‚りã¾ã™ Can only move from halt to halt or waypoint to waypoint. スケジュールã®ç§»å‹•ã¯ã€é§…ã¨é§…ã¾ãŸã¯\n中継点ã¨ä¸­ç¶™ç‚¹ã®é–“ã§ã®ã¿å¯èƒ½ã§ã™ã€‚\né§…ã‹ã‚‰é§…以外ã®å ´æ‰€ï¼ˆãã®é€†ã‚‚)\nã¸ã¯ç§»å‹•ã§ãã¾ã›ã‚“。 Cancel キャンセル Cannot connect to offline server! オフラインã®ã‚µãƒ¼ãƒãƒ¼ã«ã¯æŽ¥ç¶šå‡ºæ¥ã¾ã›ã‚“。 Capacity ç©è¼‰ Capacity: 定員/ç©è¼‰é‡: Capacity: %.0f MW é€é›»å®¹é‡:%.0f MW Capacity: %d%s %s\n 定員/ç©è¼‰é‡: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) 定員/ç©è¼‰: %s\nç©è¼‰: %d (%d%%) Cars are not available yet! 自動車ã¯ãƒ»ãƒ»ãƒ»\nã„ãˆã€é¦¬ã™ã‚‰è¦‹ã‚ãŸã‚Šã¾ã›ã‚“・・・ cars.\nstate 車\n Cash ç¾é‡‘ Change player プレイヤー変更 Chart グラフ Chat_msg ãƒãƒ£ãƒƒãƒˆ Choose direction å‘ãã‚’é¸æŠžã—ã¦ãã ã•ã„ Choose operation executed on clicking stored/new vehicles クリックã—ãŸä¹—り物ã«é©ç”¨ã•れるæ“作をé¸ã‚“ã§ãã ã•ã„ chooses a random map マップ番å·ã‚’無作為ã«é¸ã³ã¾ã™ citicens 使°‘ Cities can only be built on flat empty ground! 市役所ã¯å¹³å¦ãªç©ºã地ã«ã®ã¿å»ºè¨­ã§ãã¾ã™ã€‚ City attraction 都市内施設 City industries 産業ãƒã‚§ãƒ¼ãƒ³ã®æ•° City list 町一覧 City size è¡—ã®è¦æ¨¡ city_road å¸‚é“ citybuilding builder 市内建築物建設ツール CityLimit 市域 cl_title ç·¨æˆä¸€è¦§ cl_txt_sort ä¸¦ã³æ›¿ãˆ: clamp 値ã®ç¯„å›²ã‚’åˆ¶é™ Cleanup schedule 二é‡ã‚¨ãƒ³ãƒˆãƒªã‚’削除 Clear block reservation ç·šè·¯å æœ‰è§£é™¤ãƒ„ール clf_chk_aircrafts 航空機 clf_chk_cars 自動車 clf_chk_indepot 入庫中 clf_chk_maglev リニア clf_chk_monorail モノレール clf_chk_name_filter åå‰ãƒ•ィルター: clf_chk_narrowgauge ナローゲージ clf_chk_noincome åŽå…¥ãªã— clf_chk_noline 路線ãªã— clf_chk_noroute ルートãªã— clf_chk_noschedule スケジュールãªã— clf_chk_obsolete æ—§åž‹ clf_chk_ships 船舶 clf_chk_spezial_filter 特殊フィルター: clf_chk_stucked ç«‹ã¡å¾€ç”Ÿ clf_chk_trains 列車 clf_chk_trams 市電 clf_chk_type_filter タイプフィルター: clf_chk_waren 旅客/貨物フィルター: clf_title 乗り物ã®ä¸€è¦§ãƒ•ィルター Climate 気候 Climate Control 気候ã®è¨­å®š closed 鮿–­ Closes topmost line window when new line selected. è·¯ç·šã‚’é¸æŠžã—ãŸã¨ãã«æœ€å‰é¢ã®è·¯ç·šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‰ã˜ã¾ã™ COLOR_CHOOSE\n カラーをé¸ã‚“ã§ä¸‹ã•ã„。\n Company bankrupt 破産ã—ã¾ã—㟠Company_msg ライãƒãƒ«ä¼æ¥­ Comparing pak files ... pakを比較ã—ã¦ã„ã¾ã™ ... Configure AI AI指é‡è¨­å®š Configure AI setttings AI指é‡è¨­å®šã‚’編集ã—ã¾ã™ Congratulation\nScenario was complete in\n%i months %i years. ★☆★ Congratulation! ★☆★\nシナリオクリアãŠã‚ã§ã¨ã†ã”ã–ã„ã¾ã™\n\nã€€æ‰€è¦æ™‚é–“: %iヶ月 %iå¹´ Connected stops 接続駅: Connected with server サーãƒãƒ¼ã¨æŽ¥ç¶šã—ã¾ã—ãŸã€‚ Connections 接続産業・路線 Constructed by 作者: Constructed by %s 作者: %s construction speed 増線頻度 Construction_Btn 建設費 Consumed æ¶ˆè²»é‡ contains the following doubled objects:

以下ã®ã‚ªãƒ–ジェクトãŒé‡è¤‡ã—ã¦ã„ã¾ã™:

convoi %d of %d 入庫中ã®ç·¨æˆ %d / %d convoi error tooltips å•題ã®ã‚る車両ã®ã¿çŠ¶æ…‹ã‚’è¡¨ç¤º Convoi following mode 車両追跡モード Convoi has been sent\nto the nearest depot\nof appropriate type.\n ã“ã®ç·¨æˆã¯ä¸€ç•ªè¿‘ã„車庫ã«\nå‘ã‹ã„ã¾ã—ãŸã€‚\n Convoi is sold when all wagons are empty. ã“ã®ç·¨æˆã‚’回é€ã—ã€ç©ºè»Šæ™‚ã«å£²å´ã—ã¾ã™ã€‚ convoi mouseover tooltips マウスオーãƒãƒ¼ã§è»Šä¸¡ã®çŠ¶æ…‹ã‚’è¡¨ç¤º convoi passed last\nmonth %i\n \n剿œˆã®äº¤é€šé‡: %i\n――――――――――― Convois ç·¨æˆæ•° Convois: %d\nProfit: %s 就役編æˆ: %d\n利益: %s Convoys ç·¨æˆæ•° Copy Convoi ç·¨æˆã‚’コピー Copy the selected convoi and its schedule or line é¸æŠžã—ãŸç·¨æˆã¨ãã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«/路線を複製ã—ã¾ã™ Copy to clipboard クリップボードã«ã‚³ãƒ”ー Cost 輸é€è²» cost for removal 撤去費用: Cost per unit å˜ä½ã‚ãŸã‚Šã®è¼¸é€è²» Cost: %8s (%.2f$/km %.2f$/m)\n 費用: %s (%.2f$㎞ %.2f$月)\n Cost: %8s (%.2f$/km)\n 費用: %8s (%.2f$/km)\n Costs  費用  Create a new line based on this schedule ã“ã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’å…ƒã«æ–°ã—ã„路線を作りã¾ã™ curiosity builder ランドマーク建設ツール curlist_title 忉€æ—§è·¡ä¸€è¦§ Currently playing: æ¼”å¥ä¸­ã®æ›²ï¼š Customers live in: 顧客居ä½åœ°: Date format æ—¥ä»˜ã¨æ™‚刻ã®å½¢å¼ DAY_SYMBOL æ—¥ deactivated in online mode ãƒãƒƒãƒˆã‚²ãƒ¼ãƒ ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“ Dec. 12月 Deccelerate time ゲームスピードをé…ãã™ã‚‹ December 12月 decrease underground view level ãƒã‚¤ãƒˆã‚«ãƒƒãƒˆãƒ¬ãƒ™ãƒ«ã‚’下ã’ã‚‹ Del Stop 削除 Delete Line 路線削除 Delete the current stop 削除ã™ã‚‹é§…åをクリックã—ã¦å‰Šé™¤ Delete the selected line (if without associated convois). é¸æŠžä¸­ã®è·¯ç·šã‚’削除ã—ã¾ã™(æ‰€å±žç·¨æˆæ•°ãŒ0ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™) Delete this file. ファイルã®å‰Šé™¤ Delivered 出è·é‡ Demand 需è¦é‡ Demand: %.0f MW 需è¦é›»åŠ›: %.0f MW\n Denkmal モニュメント Departed 出発 Departs at 出発時間 (DD:HH:MM) Departure after %% ロードã¾ãŸã¯å¾…機時間(DD:SS:MM) Departure board ç™ºç€æ™‚刻 Departures per month 月間出発回数 Departures to\n 出発予想時間\n Depots 車庫 Der Tunnel ist nicht frei!\n トンãƒãƒ«å†…ãŒç©ºã§ã¯ãªã„ã‹ã€\nä»–ç¤¾ã®æ‰€æœ‰ç‰©ã§ã™ã€‚\n Destination 目的地 Destroying map ... ç¾åœ¨ã®ãƒžãƒƒãƒ—を終了ã—ã¦ã„ã¾ã™ ... Details 詳細 Die Bruecke ist nicht frei!\n æ©‹æ¢ä¸ŠãŒç©ºã§ã¯ãªã„ã‹ã€\nä»–ç¤¾ã®æ‰€æœ‰ç‰©ã§ã™ã€‚\n diesel ディーゼル directmail 広告郵便 Direkt erreichbare Haltestellen ã“ã“ã‹ã‚‰é‹è¡Œã•れã¦ã„る 駅・åœç•™æ‰€ãƒ»æ¸¯ disable midi BGMオフ Display bars above factory to show the status 産業建築物ã®ä¸Šéƒ¨ã«åœ¨åº«é‡ã‚’示ã™ãƒãƒ¼ã‚’表示ã—ã¾ã™ Display settings 表示設定 Distance 走行è·é›¢ distributing cities 都市をé…置中 distributing factories 産業をé…置中 Do not show éžè¡¨ç¤º Dock 港 Dock must be built on single slope! æ¸¯ã¯æ–œé¢æ²¿ã„ã«é€ ã£ã¦ãã ã•ã„ï¼ Downloading ダウンロード中 dp_title 車庫一覧 Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen ã‚㨠%d ヵ月以内ã«\n借金を返済ã—ã¦ãã ã•ã„。 Durchsatz 最高生産 Economy 経済 & 都市 Eigenbesitz\n 公共物\n Ein %s\npasst hier nicht.\n '%s' ã‚’\nã“ã“ã«å»ºã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\n Einstellungen 設定 Einstellungen aendern ゲームオプション electric 電気 Electricity 電力 Electricity producer\n\n 電力供給施設\n\n Electrics_tab 電車 Electrify track ç·šè·¯ã®é›»åŒ– enlarge map ãƒžãƒƒãƒ—ã®æ‹¡å¼µ enter a value between %i and %i %i~%i Enter address (IPアドレス/ホストåを入力) Enter Password プレーヤーåã¨ãƒ‘スワードを変更ã—ã¾ã™ã€‚ Error エラー Erzeuge neue Karte.\n æ–°ã—ã„マップを\n作æˆã—ã¦ã„ã¾ã™ã€‚\nãŠå¾…ã¡ãã ã•ã„。\n\n(大ãã„マップã§ã¯\n数分掛ã‹ã‚‹\nã“ã¨ãŒã‚りã¾ã™)\n Es wird bereits\nein Fahrplan\neingegeben\n ã™ã§ã«ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«\nダイアログãŒé–‹ã„ã¦ã„ã¾ã™ã€‚\nã¾ãšã€ã™ã§ã«ã‚るダイアログを\né–‰ã˜ã¦ãã ã•ã„。\n Extract files ファイルを展開中 Fabrikanschluss 接続ã•れã¦ã„る産業 Fabrikname 産業å Factories 産業 factory details 産業ã®éœ€è¦å…ˆ/供給元 factorybuilder 産業施設建設ツール Fahrplan スケジュール Fahrtziel 次ã®åœè»Šé§…: Fahrzeuge koennen so nicht entfernt werden 乗り物をブルドーザーツール\nã§æ’¤åŽ»ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\n Fahrzeuge: 乗り物: Farbe プレーヤーã®è‰² Fast forward æ—©é€ã‚Š Feb. 2月 February 2月 Ferry_tab フェリー Fertig 終了 Filename ファイルå: Files from: ファイルå: Filter: フィルター: Finances of %s %s ã®è²¡å‹™ Finanzen 財務 find mismatch パックファイルを比較 fl_title 産業一覧 Flug_tab 旅客機 follow me 追跡 Follow the convoi on the map. ã“ã®ç·¨æˆã‚’追ã£ã¦ãƒžãƒƒãƒ—を移動ã—ã¾ã™ font size フォントサイズ For questions and support please visit: 質å•・サãƒãƒ¼ãƒˆã¯ä»¥ä¸‹ã®ã‚µã‚¤ãƒˆã¸ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ãã ã•ã„: Forest 森 Found new city æ–°ã—ã„街を作る FPS: FPS: Fracht 貨物 Frame time: フレーム: Free Capacity 空席/ç©ºè· freeplay mode フリープレイ モード Friction: 摩擦 fuel_cell 燃料電池 Full load ç©ã‚€ã¾ã§å¾…機 Fullscreen (changed after restart) 全画é¢è¡¨ç¤º (ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ãƒ¢ãƒ¼ãƒ‰ã€å¤‰æ›´ã¯å†èµ·å‹•ãŒå¿…è¦) Fundament 土地 Fussgaenger 歩行者 Game info ã‚²ãƒ¼ãƒ ã®æƒ…å ± GAME PAUSED ä¸€æ™‚åœæ­¢ Game_msg ゲーム Gear: 有効出力比: Gebaeude 建築物 General 全般 Generated 発生 Generation: %.0f MW 発電é‡: %.0f MW\n Gewicht é‡é‡ Gewinn åŽç›Š Give the selected vehicle(s) an individual schedule é¸æŠžã—ã¦ã„ã‚‹ç·¨æˆã«å€‹åˆ¥ã®ç§»å‹•計画を設定ã—ã¾ã™ gl_btn_sort_catg カテゴリー順 gl_title 貨物一覧 go home 車庫㸠Goods è£½å“ Goods AI AI 貨物 Goods list 貨物一覧 Gross Profit 粗利益 Groundobj 景観物 groundobj builder 修景物設置ツール Grow city 都市ã®äººå£ã‚’増や㙠Growth 発展 GUI settings GUI設定 H åœ Hangar æ ¼ç´åº« Happy 旅行æˆåŠŸ Has slope graphics 傾斜地設置対応 Has Snow é™é›ªå¯¾å¿œ Haus kaufen 市内建築物を購入 Helligk. 表示設定 Help ヘルプ Help text not found 申ã—訳ã‚りã¾ã›ã‚“ãŒã€ã“ã®é …ç›®ã®ãƒ˜ãƒ«ãƒ—ã¯ã¾ã ã‚りã¾ã›ã‚“ hide all building å…¨ã¦ã®å»ºç‰©ã‚’éš ã™ hide city building 都市ã®å»ºç‰©ã‚’éš ã™ Hide labels é§…åプレートをéžè¡¨ç¤ºã«ã™ã‚‹ hide objects under cursor ã‚«ãƒ¼ã‚½ãƒ«å‘¨è¾ºã®æ¨¹æœ¨ã‚„建物を隠㙠hide station names é§…åã‚’éš ã™ hide transparent éš ã™æ™‚ã¯ã‚·ãƒ«ã‚¨ãƒƒãƒˆã§è¡¨ç¤ºã™ã‚‹ hide trees 樹木を隠㙠Hier warten/lagern: å¾…æ©Ÿä¸­ã®æ—…客/貨物 Higher transport fees, crossconnect all factories é‹è³ƒåŽå…¥ãŒ1.5å€ã«å¢—ãˆã€ã‚¸ãƒ£ã‚¹ãƒˆã‚¤ãƒ³ã‚¿ã‚¤ãƒ ç”Ÿç”£ãŒç„¡åйã«ãªã‚Šã¾ã™ Highlite schedule 路線ã®çµŒç”±åœ°ã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã™ã‚‹ hl_title 駅一覧 hl_txt_filter フィルター: hl_txt_sort ä¸¦ã³æ›¿ãˆ: hlf_chk_airport 空港 hlf_chk_anleger 港 hlf_chk_bahnhof 鉄é“é§… hlf_chk_bushalt ãƒã‚¹åœç•™æ‰€ hlf_chk_frachthof トラックターミナル hlf_chk_keine_verb 接続ãªã— hlf_chk_maglevstop リニア駅 hlf_chk_monorailstop モノレール駅 hlf_chk_name_filter åå‰ãƒ•ィルター: hlf_chk_narrowgaugestop ナローゲージ駅 hlf_chk_overflow 混雑中 hlf_chk_spezial_filter 特殊フィルター: hlf_chk_tramstop 市電駅 hlf_chk_type_filter タイプフィルター: hlf_chk_waren_abgabe 生産å“: hlf_chk_waren_annahme 製å“需è¦: hlf_title 駅一覧フィルター Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. 帰るã¹ã車庫ãŒç¢ºèªã§ãã¾ã›ã‚“。\n手動ã§å…¥åº«å…ˆã‚’指定ã—ã¦ãã ã•ã„。 Homeless 浮浪者 hydrogene æ°´ç´  Idle: 待機回数: ignore climates 気候æ¡ä»¶ã‚’無視ã™ã‚‹ In the industry legend show only currently existing factories ç¾åœ¨å­˜åœ¨ã™ã‚‹ç”£æ¥­ãŒå–り扱ã£ã¦ã„る貨物ã®ã¿ã‚’表示ã—ã¾ã™ã€‚ In Transit 待機/輸é€ä¸­ Increase Industry density 産業ãƒã‚§ãƒ¼ãƒ³/発電所を増や㙠increase underground view level ãƒã‚¤ãƒˆã‚«ãƒƒãƒˆãƒ¬ãƒ™ãƒ«ã‚’上ã’ã‚‹ industrial building 工場 Industry overlay 産業在庫é‡ãƒ„ールãƒãƒƒãƒ— Infinite mouse scrolling マップスクロール時ã«ãƒã‚¤ãƒ³ã‚¿ä½ç½®ã‚’固定(マウス使用時推奨) Infinite scrolling using mouse windowモードã§ã¯ã‚ªãƒ•ã«ã—ãŸå ´åˆã«ç”»é¢ã®å¤–ã«ãƒžã‚¦ã‚¹ãƒã‚¤ãƒ³ã‚¿ãŒç§»å‹•ã™ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚※タッãƒã‚¹ã‚¯ãƒªãƒ¼ãƒ³ã§ã¯å‹•作ã—ãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ï¼ Init map ... ãƒžãƒƒãƒ—ã‚’åˆæœŸåŒ–ã—ã¦ã„ã¾ã™ ... Input 原料 Ins Stop 駅を挿入 Insert stop before the current stop é¸æŠžã—ã¦ã„ã‚‹é§…ã®ç›´å‰ã«é§…を挿入 Install graphics グラフィックセットã®è¿½åŠ  Install paks Pakセットをダウンロードã—ã€ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã™ã€‚ Insufficient funds! 資金ãŒè¶³ã‚Šã¾ã›ã‚“ï¼ Intercity road len: 都市間é“è·¯ã®é•·ã•: Intro. date 開発年月 Intro. date: 開発年月: invalid æ•…éšœ Invalid coordinate ※無効ãªåº§æ¨™é«˜åº¦â€» isometric map 回転ã—ã¦è¡¨ç¤º Jan. 1月 January 1月 join game ゲームã«å‚加 July 7月 Jump to 指定座標ã¸ç§»å‹• June 6月 Kann Spielstand\nnicht laden.\n ゲームを読ã¿è¾¼ã‚€\nã“ã¨ãŒã§ãã¾ã›ã‚“。\n Kann Spielstand\nnicht speichern.\n ゲームをä¿å­˜ã§ãã¾ã›ã‚“。\n Kein Besitzer\n \n keine ç„¡ã— Keine Einzelfahrzeuge im Depot 車両ã¯ç•™ç½®ã•れã¦ã„ã¾ã›ã‚“ Keyboard_Help\n キーボードヘルプ\n koord ä½ç½®é † Kreuzung è¸åˆ‡ labellist_title マーカー一覧 Lade Relief 地形データを読ã¿è¾¼ã‚€ Laden ゲームã®ãƒ­ãƒ¼ãƒ‰ Land attraction 郊外型施設 Land industries 産業ãƒã‚§ãƒ¼ãƒ³ã®æ•°ï¼š LANG_CHOOSE\n 言語をé¸ã‚“ã§ãã ã•ã„。\n LARGE_NUMBER_STRING å„„ LARGE_NUMBER_VALUE 1e8 Last Month 先月 Last used tools 最後ã«ä½¿ç”¨ã—ãŸãƒ„ール Last Year å‰å¹´åº¦: Leaving depot! 出庫中 leer 空ã legacy (large heights) レガシー (高㕠2) legacy (small heights) レガシー (高㕠1) Legend 凡例 Leistung 出力 Leistung: %d kW ç·å‡ºåŠ›ï¼š%d kW Leitung é€é›»ç·š length: %d 建設è·é›¢: %d letzen Monat: diesen Monat: 先月:         今月: Line 路線 Line Management 路線編集 line name mouseover tooltips マウスオーãƒãƒ¼ã§è·¯ç·šåを表示 linear ç·šå½¢ Lineless convoys serving this stop è·¯ç·šã«æ‰€å±žã—ã¦ã„ãªã„車両 Lines serving this stop 乗り入れã¦ã„る路線 List of industries on the map マップ上ã®ç”£æ¥­æ–½è¨­ä¸€è¦§ LKW_tab トラック Load game ゲームã®å†é–‹ load height data from file 地形データをファイルã‹ã‚‰èª­ã¿è¾¼ã¿ã¾ã™ Load mode: ロードモード: Load scenario シナリオを読ã¿è¾¼ã‚€ loaded 乗車中 loaded passenger/freight ä¹—è»Šä¸­ã®æ—…客/貨物 Loading (%i->%i%%)! ç©è¼‰(%i->%i%%) Loading (%i%%)! æ­è¼‰(%i%%)! Loading addon paks ... アドオンを読ã¿è¾¼ã¿ä¸­ ... Loading map ... マップを読ã¿è¾¼ã¿ä¸­ Loading paks ... pakを読ã¿è¾¼ã¿ä¸­ ... Loading skins ... スキンを読ã¿è¾¼ã¿ä¸­ ... Lock game プレイヤー変更ã®ç¦æ­¢ã€è§£é™¤ä¸å¯ã€‘ Lokomotive_tab 機関車 m3 ç«‹æ–¹m Maglev リニア maglev vehicle リニア車両 maglev_track リニア Maglevdepot リニア車庫 Mail Demand %d\n éƒµä¾¿éœ€è¦ %d\n Mail level 郵便物ã®ãƒ¬ãƒ™ãƒ« Mailbox メッセージ表 Mailbox Options メッセージ設定 Maintenance ç¶­æŒè²» make stop public (or join with public stop next) costs %i per tile and level 公共駅ã«å¤‰æ›´ã€€é§…上をドラッグã§ã€å®Ÿéš›ã®è¦‹ç©ã‚Šè²»ç”¨ã‚’表示ã—ã¾ã™ (å˜ä¾¡%i) Make way or stop public (will join with neighbours), %i times maintainance é§…ã¾ãŸã¯é“路・軌é“等を公共化ã—ã¦éš£æŽ¥ã™ã‚‹å…¬å…±é§…ã¨çµ±åˆã—ã¾ã™ã€‚ç¶­æŒè²»%iヶ月分ãŒå¿…è¦ã§ã™ã€‚ Manual (Human) プレイヤー(人間) Manufactured: 製造年月: Map roughness èµ·ä¼ã®æ¿€ã—ã•: map view マップ表示設定 map zoom æ‹¡å¤§ï½¥ç¸®å° Mar. 3月 March 3月 Margin (%%) 利益率 (%%) Marker マーカー max 高 Max Boost (%%) 増産能力 (%%) Max income: 最大åŽç›Šï¼š Max. speed 最高速度 Max. speed: 最高速度: Max. waiting time æœ€å¤§å¾…ã¡æ™‚é–“ (DD:HH:MM) Maximum 254 stops\nin a schedule!\n スケジュールã«ã¯æœ€å¤§\n254ヶ所ã¾ã§ã—ã‹è¨­å®šã§ãã¾\nã›ã‚“\n maximum length of rivers æ²³å·ã®é•·ã• 最長: Maximum tile height difference reached. ã“れ以上高ã(低ã)\n造æˆã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\n\n隣接ã—ãŸåœŸåœ°ã®é«˜ä½Žå·®ã¯\n2段ã¾ã§ã§ã™ã€‚\n Maxspeed 最高速度 May 5月 Median Citizen per town 町ã®å¹³å‡äººå£ï¼š Meldung メッセージ Menge 待機数 merge stop é§…ã®çµåˆ MessageOptionsText \næ–°å¹´\n\n他社\n\n都市\n\nãƒ«ãƒ¼ãƒˆä¸æ˜Ž\n\n産業\n\nãƒãƒ£ãƒƒãƒˆ\n\n車両登場\n\né§…ã®æ··é›‘\n\nå•題\n\n渋滞\n\nシナリオ\n min 低 minimum length of rivers æ²³å·ã®é•·ã• 最短: Minimum load 最低ç©è¼‰çއ (%%) Missing pakfiles オブジェクトãŒä¸è¶³ã—ã¦ã„ã¾ã™! Modify the selected line é¸æŠžã•れã¦ã„る路線を編集ã—ã¾ã™ Monate alt 樹齢 (月) Monorail モノレール monorail vehicle モノレール/リニア車両 monorail_track モノレール Monorailboden 高架 Monoraildepot モノレール基地 Month 月 month wait time æœ€å¤§å¾…ã¡æ™‚é–“ (月): Monthly departures 時刻表 Months 月 Monument モニュメント Monuments モニュメント Mountain height èµ·ä¼ã®é«˜ã•: Move the map マップã®ç§»å‹• Movingobj 動物 Music playing disabled/not available BGMã¯æ¼”å¥ã§ãã¾ã›ã‚“。 Music volume: BGMã®éŸ³é‡: mute sound 効果音オフ Name åå‰ Narrowgauge ナローゲージ Narrowgauge are not available yet! ナローゲージã¯\nã¾ã åˆ©ç”¨ã§ãã¾ã›ã‚“。 narrowgauge vehicle ナローゲージ車両 narrowgauge_track ナローゲージ Narrowgaugedepot ナローゲージ車庫 Net ID: %p 電力網 ID: %p\n Net Wealth ç·è³‡ç”£ Net wealth near zero ç·è³‡ç”£ãŒå°½ãã‹ã‘ã¦ã„ã¾ã™ Neue Karte æ–°ã—ã„ゲーム Neue Welt æ–°ã—ã„ゲームを開始ã™ã‚‹ new convoi æ–°ã—ã„ç·¨æˆ New Line è·¯ç·šä½œæˆ New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. æ–°ã—ã„路線ãŒä½œã‚‰ã‚Œã¾ã—ãŸã€‚\né¸æŠžã™ã‚Œã°è·¯ç·šã‚’割り当ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ New Vehicles 購入費 Nickname: プレイヤーå: no buildings hidden ã™ã¹ã¦ã®å»ºç‰©ã‚’表示 no convois ç·¨æˆã¯ã‚りã¾ã›ã‚“ No goods are loaded onto this convoi. ã“ã®ç·¨æˆã‚’é™è»Šï¼ˆè·é™ã‚ã—)専用ã«ã—ã¾ã™ã€‚ no goods waiting 待機中ã®è²¨ç‰©ã¯ã‚りã¾ã›ã‚“ no load å›žé€ No player プレイヤーãŒå­˜åœ¨ã—ã¾ã›ã‚“ No Route 経路無㗠No stop here! ã“ã“ã«ã¯é§…ãŒã‚りã¾ã›ã‚“。\nキャンセルã—ã¾ã™ã€‚ No suitable ground! é©åˆ‡ãªå ´æ‰€ã§ã¯ã‚りã¾ã›ã‚“。\n\n気候æ¡ä»¶ãŒåˆã‚ãªã„/空地ã§ã¯ãªã„\nã¾ãŸã¯ç·šè·¯/é“路上ã§ã¯ã‚りã¾ã›ã‚“\nã¾ãŸåœ°ä¸‹ã§ã¯ç·šè·¯/é“路上を起点ã¨ã—ã¦ãã ã•ã„。 No suitable townhall available for this climate! 気候ã«é©åˆã™ã‚‹å½¹æ‰€å»ºç¯‰ç‰©ãŒã‚りã¾ã›ã‚“ï¼ No terminal station here! ã“ã®å½¢å¼ã®åœè»Šå ´ã¯èµ°è·¯ã®çµ‚端ã«\n建ã¦ã¦ãã ã•ã„ï¼ no timeline 年代設定:無効 no tree 木/森を作æˆã—ãªã„ No. of Factories 工場ã¨åº—舗数 Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n 乗り物をスタートã•ã›ã‚‹å‰ã«\nスケジュールを設定ã—ã¦ãã ã•ã„。\n none ç„¡ã— nord 北 nordost åŒ—æ± nordwest 北西 Not allowed to make publicly owned ways! 公共事業ã§è»Œé“を建設ã™ã‚‹ã“ã¨ã¯è¨±å¯ã•れã¦ã„ã¾ã›ã‚“。 Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! ç¾åœ¨ã€ã“ã®ç·¨æˆã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯\n変更ã§ãã¾ã›ã‚“。少ã—å¾…ã£ã¦ã‹ã‚‰\nå†åº¦è©¦ã—ã¦ãã ã•ã„。 Not enough fields would remain. ã“ã‚Œä»¥ä¸Šã¯æ’¤åŽ»ã§ãã¾ã›ã‚“ Nov. 11月 November 11月 now ç¾åœ¨æ™‚刻 Now active as %s.\n ç¾åœ¨ã€%sãŒ\næ“作ã§ãã¾ã™ nowhere ã©ã“ã«ã‚‚ãªã„ Number of rivers æ²³å·ã®æ•°ï¼š Object 原å Oct. 10月 Odometer: %s km ç©ç®—è·é›¢ï¼š %skm Ok OK Oktober 10月 On loan since %i month(s) ç¾åœ¨ã€è² å‚µãŒã‚りã¾ã™ã€‚(%iヶ月間) On mouseover マウスオーãƒãƒ¼ã§è¡¨ç¤º on the 出発(月)出発(月)最åˆ(æ—¥/時/分) On this map, you are not\nallowed to change player!\n ã“ã®ãƒžãƒƒãƒ—ã§ã¯ãƒ—レイヤーã®äº¤ä»£ã¯èªã‚られ\nã¦ã„ã¾ã›ã‚“。 Only city chains 都市ã«ãƒã‚§ãƒ¼ãƒ³ã‚’ä½œæˆ Only first %d differing paks reported. There are probably more. é•ã„ãŒå¤šã„ãŸã‚ã€%d個以上ã¯è¡¨ç¤ºã‚’çœç•¥ã—ã¦ã„ã¾ã™ã€‚ Only full Unicode fonts Unicodeを網羅ã—ãŸãƒ•ォントã«é™å®šã™ã‚‹ Only land chains 発電所/郊外ã®ãƒã‚§ãƒ¼ãƒ³ã‚’ä½œæˆ Only one transformer per factory! 工場ã”ã¨ã«å¤‰åœ§æ‰€ã¯ä¸€ã¤ã®ã¿å»ºè¨­ã§ãã¾ã™ã€‚ Only show goods which are currently handled by factories ç¾åœ¨å­˜åœ¨ã™ã‚‹ç”£æ¥­ãŒå–り扱ã£ã¦ã„る貨物ã®ã¿ã‚’表示ã—ã¾ã™ã€‚ open é€²å…¥å¯ Operation é‹è¡Œè²» Ops Profit é‹ç”¨åˆ©ç›Š Optionen 設定 Or enter a server manually: å‚加ã™ã‚‹ã‚µãƒ¼ãƒãƒ¼ã‚’入力: Origin 出発地 ost æ± Output è£½å“ Ownership 所有者 Pak which may cause severe errors: 以下ã®ã‚ªãƒ–ジェクト(pak)ãŒä¸è¶³ã—ã¦ã„ã‚‹ãŸã‚ã€è¼¸é€ã«éšœå®³ã‚’ã‚‚ãŸã‚‰ã™å¯èƒ½æ€§ãŒã‚りã¾ã™: Pak which may cause visual errors: 以下ã®ã‚ªãƒ–ジェクト(pak)ã¯åŒç­‰ã®ã‚ªãƒ–ジェクトã«ç½®æ›ã•れã¾ã—ãŸ: Pak(s) different: åå‰ãŒåŒã˜ã§å†…容ãŒç•°ãªã‚‹pak: Pak(s) missing on client: ä¸è¶³ã—ã¦ã„ã‚‹pak: Pak(s) not on server: サーãƒãƒ¼ã«ã¯ãªã„余分ãªpak: Pakset differences Pakセットã®å·®ç•° paletten パレット Pas_tab 旅客車 Passagiere 旅客 Passagierrate 旅客度 Passagierziele 旅客/郵便物ã®è¡Œãå…ˆ Passenger AI AI 旅客 Passenger Demand %d\n 労åƒè€…/顧客需è¦: %d\n Passengers %d %c, %d %c, %d no route 旅客ã®è©•価 %d %c, %d %c, %d 経路無㗠Passengers %d %s, %d %s, %d no route 旅客ã®è©•価 %d %s, %d %s, %d 経路無㗠Password パスワード: Pause ä¸€æ™‚åœæ­¢ Pax <%i> Mail <%i> 旅客 <%i> 郵便 <%i> Pax level 旅客レベル PaxDest 旅客/郵便目的地 Percent Electricity 電力供給率 (%%): Planes are not available yet! 飛行機ã¯ã¾ã é–‹ç™ºã•れã¦ã„ã¾ã›ã‚“ï¼ Plant tree 木をæ¤ãˆã‚‹ player プレイヤー順 player -1 プレイヤー会社 player 0 公共事業 player 1 Napik 128 AS player 10 プレイヤー 10 player 11 プレイヤー 11 player 12 プレイヤー 12 player 13 プレイヤー 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG player 7 プレイヤー 7 player 8 プレイヤー 8 player 9 プレイヤー 9 Please choose vehicles first\n 最åˆã«ä¹—り物をé¸ã‚“ã§ãã ã•ã„\n Post 郵便 Postrate 郵便度 Power 電力 Power (MW) 電力 (MW) Power: 出力: Power: %4d kW\n 出力: %4d kW\n Powerlines 高圧線 Price 車両価格 Problems_msg å•題 Produced ç”Ÿç”£é‡ Produces: %.1f units/minute 生産é‡: %.1f å˜ä½/分 Production of %s has been stopped:\n%s\n %s\n「%sã€ãŒ\n製造中止ã«ãªã‚Šã¾ã—ãŸã€‚ Production/Boost 生産能力/増産 Produktion 生産 Profit 利益 promote to line è·¯ç·šä½œæˆ q1 春 q2 å¤ q3 ç§‹ q4 冬 Query server ã‚µãƒ¼ãƒæƒ…å ±ã®è¡¨ç¤º rail car 鉄é“車両 random ランダム Random age ãƒ©ãƒ³ãƒ€ãƒ ãªæ¨¹é½¢ã‚’使用 Random map ランダムマップ Rathaus 役所 Rating 評価 ratio_pax 旅客輸é€çއ(%%) Relevant å–æ‰±ã„貨物ã®ã¿ Reliefkarte マップ Remove 撤去ã™ã‚‹ remove airstrips æ»‘èµ°è·¯ãƒ»èª˜å°Žè·¯ã®æ’¤åŽ» remove channels 鋿²³ã®æ’¤åŽ» remove interm. signals 途中ã®ä¿¡å·ã‚’削除 remove maglev tracks ãƒªãƒ‹ã‚¢ã®æ’¤åŽ» remove monorails ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ã®æ’¤åŽ» remove narrowgauge tracks ãƒŠãƒ­ãƒ¼ã‚²ãƒ¼ã‚¸ã®æ’¤åŽ» remove powerlines é€é›»ç·šã®æ’¤åŽ» remove roads é“è·¯ã®æ’¤åŽ» remove signal ä¿¡å·ã‚’削除ã—ã¾ã™ remove tracks 鉄é“ã®æ’¤åŽ» Remove wayobj %s %s æž¶ç·šã®æ’¤åŽ» replace other signals ä»–ã®ä¿¡å·ã‚’ç½®æ› replace stop スケジュール移動ツール request closing é€²å…¥ç¦æ­¢ residential house ä½å®… Restore natural slope スロープを戻㙠Restwert: 売å´ä¾¡æ ¼ï¼š Retire date 引退年月 Retire. date: 引退年月: return ticket 往復路線 Revenue åŽå…¥ Revision: リビジョン: road é“è·¯ road vehicle 自動車 Roadsign é“路標識 Rotate Building 建物ã®å‘ã回転 Rotate map 90°回転ã™ã‚‹ Rotation å‘ã Routing 経路 Running cost ç¶­æŒè²» sack 袋 sail 帆走 Save ゲームã®ä¿å­˜ Saving map ... マップをä¿å­˜ä¸­ Scenario complete: %i%% ã‚·ãƒŠãƒªã‚ªé”æˆçއ: %i%% Scenario Debug デãƒãƒƒã‚° Scenario Error Log エラーログ Scenario Goal 目標 Scenario Info 情報 Scenario information ã‚·ãƒŠãƒªã‚ªã®æ¦‚è¦ Scenario Result çµæžœ Scenario Rules ルール Scenario_ シナリオ Schedule changing! ルート変更中 Schienentunnel 鉄é“トンãƒãƒ«ã®å»ºè¨­ Schiff_tab 貨物船 Schiffdepot 造船所 Schleppkahn_tab ãƒãƒ¼ã‚¸ Screenshot スクリーンショット Scroll threshold スクロールã®ã—ãã„値 Search: 検索: Seasons 季節 Sehenswuerdigkeit 忉€æ—§è·¡ Select a server to join: å‚加ã™ã‚‹ã‚µãƒ¼ãƒãƒ¼ã‚’é¸æŠž: Select a theme for display 表示ã™ã‚‹ãƒ†ãƒ¼ãƒžã®é¸æŠž Select display font テキストã®ãƒ•ã‚©ãƒ³ãƒˆã‚’é¸æŠž Select one or more graphics to install (Ctrl+click): インストールã™ã‚‹ã‚°ãƒ©ãƒ•ィックスを1ã¤ã¾ãŸã¯è¤‡æ•°é¸æŠžã™ã‚‹ (Ctrl+クリック): Select soundfont サウンドフォントã®é¸æŠž Sell the selected vehicle(s) é¸æŠžã—ã¦ã„る乗り物を売å´ã—ã¾ã™ sended é…é”実績 SEP_FRACTION . SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 Sept. 9月 September 9月 Served by サービスæä¾› Served by me 自社輸é€ç¶²å†…ã®ã¿ Server did not respond! サーãƒãƒ¼ã®å¿œç­”ãŒã‚りã¾ã›ã‚“。 Serves Line: 指定路線: Service ç·¨æˆæ•° set signal spacing ä¿¡å·é–“éš”ã®è¨­å®š Setting 高度ãªè¨­å®š Ship 船舶 shops and stores 商店 Show all å…¨ã¦ã‚’表示 show all building ã™ã¹ã¦ã®å»ºç‰©ã‚’表示ã™ã‚‹ Show also vehicles no longer in production. 生産を終了ã—ã¦ã„る乗り物も表示ã—ã¾ã™ã€‚ Show also vehicles that do not match for current action. ã“ã®ãƒœã‚¿ãƒ³ã‚’オフã«ã™ã‚‹ã¨ã€é¸æŠž/連çµã§ããªã„乗り物を隠ã—ã¾ã™ Show always 常ã«è¡¨ç¤º Show climates 気候を表示 Show contour 等高線を表示 Show even servers with wrong version or pakset リビジョンや種類ãŒä¸æ˜Žã¾ãŸã¯ç•°ãªã‚‹ã‚µãƒ¼ãƒãƒ¼ã‚‚表示ã™ã‚‹ Show finances for transport type 輸é€å½¢æ…‹ Show future 登場予定ã®ä¹—り物 show grid グリッドを表示ã™ã‚‹ Show industry 産業凡例 Show legend è¡¨ç¤ºç¨®åˆ¥é¸æŠž Show map scale カラースケール Show mismatched ä¸é©åˆã®ã‚µãƒ¼ãƒãƒ¼ã‚’表示 Show networks ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’表示 Show obsolete 旧型を表示 Show offline オフラインを表示 Show only used マップã«å­˜åœ¨ã®ã¿è¡¨ç¤º Show outline インフラã®ã¿ Show schedules 路線経路ã®è¡¨ç¤º Show servers that are offline オフラインã®ã‚µãƒ¼ãƒãƒ¼ã‚’表示ã—ã¾ã™ Show servers where game version or pakset does not match your client ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚„pakセットãŒç•°ãªã‚‹ã‚µãƒ¼ãƒãƒ¼ã‚’表示 show station coverage é§…ã®æœ‰åŠ¹ç¯„å›²ã‚’è¡¨ç¤ºã™ã‚‹ show station names é§…åを表示ã™ã‚‹ show waiting bars 待機状態・待機数グラフを表示ã™ã‚‹ show/hide block reservations ルートã®äºˆç´„ã®è¡¨ç¤º/éžè¡¨ç¤º Show/hide estimated arrival times 到ç€äºˆå®šæ™‚刻ã®è¡¨ç¤º/éžè¡¨ç¤º show/hide object owner 所有者ã®è¡¨ç¤º/éžè¡¨ç¤º Show/hide statistics 統計グラフを見るï¼éš ã™ Shows buttons on network overlay. 接続ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’オーãƒãƒ¼ãƒ¬ã‚¤è¡¨ç¤ºã™ã‚‹ã‚ªãƒ—ションを表示ã—ã¾ã™ã€‚ Shows buttons on special topics. 詳細事項ã®ãƒœã‚¿ãƒ³ã‚’表示ã—ã¾ã™ Shows consumer/suppliers for factories 産業施設ã®ã‚¯ãƒªãƒƒã‚¯[shift+クリック]ã§ã€éœ€è¦å…ˆ[供給元]を表示ã—ã¾ã™ Shows the color code for several selections. カラースケールãƒãƒ¼ã‚’表示ã—ã¾ã™ã€‚ Shows the currently selected schedule 編集中ã®è·¯ç·šçµŒè·¯ã‚’表示ã—ã¾ã™ Shrink city 都市ã®äººå£ã‚’減ら㙠shuffle midis シャッフルå†ç”Ÿ Signal ä¿¡å· signal spacing ä¿¡å·/標識ã®é–“éš” Sim: 演算回数: Similar view as the main window メインウィンドウã¨åŒã˜è¦–点ã«ã—ã¾ã™ Size (%d MB): サイズ (%d MB): Size (area) サイズ (é¢ç©) sliced underground mode ãƒã‚¤ãƒˆã‚«ãƒƒãƒˆè¡¨ç¤ºãƒ¢ãƒ¼ãƒ‰ slot empty <空ã> Smart hide objects カーソル周辺を隠㙠Sort by ä¸¦ã³æ›¿ãˆè¦å‰‡ Sort by: ソート: Sort waiting list by 待機表ã®ä¸¦ã³å¤‰ãˆ Sound サウンド Sound settings サウンド設定 Sound volume: マスターボリューム Soundfonts are located in the music directory. サウンドフォントã¯ã€musicディレクトリã«ã‚りã¾ã™ã€‚ special freight 専用貨物 Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. 速é”ボーナス:\n é“è·¯ %i km/h, é‰„é“ %i km/h, \n æµ·è·¯ %i km/h, 空路 %i km/h\n Speedlimit 制é™é€Ÿåº¦ Speichern ゲームã®ä¿å­˜ Spieler プレイヤー Spieler(mz) プレイヤー Spielerliste プレイヤー一覧 Spielstand wurde\ngeladen!\n \nゲームをロードã—ã¾ã—ãŸã€‚\n Spielstand wurde\ngespeichert!\n \nゲームをä¿å­˜ã—ã¾ã—ãŸã€‚\n Sprache 言語 Sprachen 言語 Stadtinformation è¡—ã®è©³ç´° Start スタート Start the selected vehicle(s) é¸æŠžã—ã¦ã„ã‚‹ç·¨æˆã‚’発進ã•ã›ã¾ã™ Starte Spiel ã“ã®è¨­å®šã§å§‹ã‚ã‚‹ station labels 駅ラベル表示設定 Station tiles: ホームã®é•·ã•: Station_msg é§… Status å¾…åˆçŠ¶æ…‹ steam 蒸気 Step timeline one year 1年進ã‚ã‚‹ Stops é§… Storage åœ¨åº«é‡ Storage capacity å¾…åˆå®¤å®šå“¡ Strassendepot 車庫 Strassentunnel é“路トンãƒãƒ«ã®å»ºè¨­ street car è·¯é¢é›»è»Šè»Šä¸¡ sued å— suedost å—æ± suedwest å—西 Summer snowline 雪線 Supplied: %.0f %% 供給率: %.0f %% Suppliers 供給元 Tage alt 樹齢(月) The following graphics are unmaintained: 以下ã®ã‚°ãƒ©ãƒ•ィックã¯ãƒ¡ãƒ³ãƒ†ãƒŠãƒ³ã‚¹ã•れã¦ã„ã¾ã›ã‚“: The gradient does not fit a tunnel æ–œé¢ãŒãƒˆãƒ³ãƒãƒ«ã‚’建設ã™ã‚‹ã®ã«é©ã—ã¦ã„ã¾ã›ã‚“ Theme selector テーマã®é¸æŠž There are still vehicles\nstored in this depot!\n ã“ã®è»Šåº«ã«ã¯ã€ã¾ã ä¹—り物ãŒ\n留置ã•れã¦ã„ã¾ã™ã€‚\n This Month ç¶­æŒè²»(今月分) This Year 今年度: Tile not empty. ã“ã“ã¯ç©ºã地ã§ã¯ã‚りã¾ã›ã‚“。\n土地ã®é€ æˆã‚’ã™ã‚‹å‰ã«ã™ã¹ã¦ã®\n建造物をå–り除ã„ã¦ãã ã•ã„。 timeline 年代設定:有効 tl_title 町一覧 To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. より多ãã®ä¹—é™å®¢ã‚’\n%sã«å‘¼ã³è¾¼ã‚€ãŸã‚\n「%sã€ã‚’\n%i人ã®ä½æ°‘ã®æ´åŠ©ã«ã‚ˆã‚Š\n建設ã—ã¾ã—ãŸã€‚ To heavy traffic\nresults in traffic jam.\n 交通集中ã«ã‚ˆã‚Šæ¸‹æ»žç™ºç”Ÿä¸­\n Toggle day/night view 昼/夜を交互ã«åˆ‡ã‚Šæ›¿ãˆã¾ã™ Toggle vehicle tooltips 乗り物ã®çŠ¶æ…‹(ツールãƒãƒƒãƒ—)表示ã®åˆ‡ã‚Šæ›¿ãˆ tonnen t Toolbar position: ツールãƒãƒ¼ã®è¡¨ç¤ºä½ç½®: Total inhabitants: ç·äººå£: Tourist attractions 忉€æ—§è·¡ Tourists 忉€ Town_msg 都市 Town: %s\n 所在地: %s\n Towns 都市 track é‰„é“ Tracks 鉄é“ç·š Traffic äº¤é€šé‡ traffic settings 交通設定 Train 列車 Trains are not available yet! 鉄é“ã¯ã¾ã é–‹ç™ºã•れã¦ã„ã¾ã›ã‚“ï¼ Tram 市電 tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. 市電 %i km/h, モノレール %i km/h, \n リニア %i km/h ナローゲージ %i km/h tram_track 市電 Tramdepot 市電車庫 Trams are not available yet! è·¯é¢é›»è»Šã¯ã¾ã é–‹ç™ºã•れã¦ã„ã¾ã›ã‚“ï¼ Transferring game ... ゲームを転é€ã—ã¦ã„ã¾ã™ ... Transformer only next to factory! 変圧所ã¯ã€ç”£æ¥­æ–½è¨­ã«\n隣接ã—ã¦å»ºè¨­ã—ã¦ãã ã•ã„。 Translation 日本語å transparencies 逿˜Žåº¦è¨­å®š transparent station coverage é§…ã®æœ‰åŠ¹ç¯„å›²ã¯åŠé€æ˜Žè‰²ã§è¡¨ç¤ºã™ã‚‹ Transported 輸é€å®Ÿç¸¾ Trees disabled! 樹木ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“ï¼ TrolleyBus_tab トロリーãƒã‚¹ Truck 自動車 tt_Other ãã®ä»– Tunnel muss an\neinfachem\nHang beginnen!\n トンãƒãƒ«ã¯ç›´ç·šã®\nå‚ã«ä½œã£ã¦ãã ã•ã„。\n Tunnel must start on single way! トンãƒãƒ«ã¯ã¾ã£ã™ããªé“è·¯/線路上ã«\n設置ã—ã¦ãã ã•ã„。 Tunnelboden トンãƒãƒ«å†…部 underground mode 地下路線建設モード UNDO failed! å–り消ã—ã¯ã§ãã¾ã›ã‚“。\n建設ã®å–り消ã—ãŒã§ãã‚‹ã®\nã¯ãƒ«ãƒ¼ãƒˆä¸Šã«ä¿¡å·ã‚„駅を建\n設ã—ã¦ã„ãªã„å ´åˆã ã‘ã§ã™ã€‚ Undo last ways construction ç›´å‰ã«å»ºè¨­ã—ãŸé“è·¯/線路をå–り壊㙠Unemployed ç„¡è·è€… Unhappy 旅行失敗 units/day å˜ä½/月 Unloading (%i%%)! è·ä¸‹ã‚ã—(%i%%)! Update Line 路線編集 upgrade HQ 本社を拡張移転ã™ã‚‹ Usage: %.0f %% 稼動率: %.0f %% Usage/Output 使用é‡/ç™ºé›»é‡ Use beginner mode åˆå¿ƒè€…モード Use timeline start year 年代設定を使用   開始年: Vehicle %s can't find a route! 「%sã€ã®\né‹è¡Œã§ãる経路ãŒã‚りã¾ã›ã‚“ Vehicle %s is stucked! 「%sã€ãŒ\nç«‹ã¡å¾€ç”Ÿã—ã¦ã„ã¾ã™ï¼ Vehicle details 乗り物ã®è©³ç´° Vehicle Name 車両å Vehicle Power 出力 vehicles stored 留置中ã®è»Šä¸¡æ•° Verbrauch 消費 Vergroessere die Karte\n マップを拡ã’ã¦ã„ã¾ã™ã€‚\nã—ã°ã‚‰ããŠå¾…ã¡ãã ã•ã„。\n Verkauf å£²å´ verkaufen å£²å´ Verkehrsteilnehmer 自家用車 Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n ç¾åœ¨å€Ÿé‡‘ãŒã‚りã¾ã™ã€‚\n\nã‚㨠%d ヵ月以内ã«\n借金を返済ã—ã¦ãã ã•ã„。\n vh_title 乗り物一覧 via 経由地 via %s\n (%s経由)\n via Menge 待機数/経由地 voranstellen 先頭㸠Waggon_tab 貨車 waiting 待機中 Waiting for clearance! åœæ­¢ Walked å¾’æ­© walking 徒歩連絡 Warnings_msg 警告 Wasser 海上 Water 沿岸 Water level æµ·é¢æ°´ä½ï¼š water vehicle 船舶 way %s cannot longer used:\n ã“ã®å…ˆã€\n%sã¯\n建設ã§ãã¾ã›ã‚“。 way %s cannot longer used:\n%s\n ã“ã®å…ˆã€\n%sã¯\n建設ã§ãã¾ã›ã‚“。 way %s now available:\n %s ãŒ\næ–°ã—ã建設å¯èƒ½ã«ãªã‚Šã¾ã—ãŸã€‚\n\n Way toll 通行料 Ways not connected é“è·¯/ç·šè·¯ãŒ\n繋ãŒã£ã¦ã„ã¾ã›ã‚“。 waytype 経路ã®ç¨®é¡ž Wegpunkt 中継点 Weight é‡é‡ Weight: é‡é‡: Welcome to Simutrans よã†ã“ãã€Simutrans㸠Welcome, %s! %s ãŒã‚²ãƒ¼ãƒ ã«æŽ¥ç¶šã—ã¾ã—ãŸã€‚ Wert 価格 west 西 Wind direction 風å‘ã Winter snowline ç©é›ªé«˜åº¦ withdraw 引退 Withdraw All ã™ã¹ã¦å¼•退 WRONGSAVE äº’æ›æ€§ãŒç„¡ã„ãŸã‚ã€\nロードã§ãã¾ã›ã‚“。\n Year å¹´ Year %i has started. %iå¹´ã«ãªã‚Šã¾ã—ãŸã€‚ YEAR_SYMBOL å¹´ Years å¹´ Your primary color: 基調色 Your secondary color: 補助色 Zielort 目的地 zooming in ズームイン zooming out ズームアウト Zu nah am Kartenrand 地図ã®å‘¨è¾ºéƒ¨ã‹ã‚‰é›¢ã—ã¦\n設置ã—ã¦ãã ã•ã„\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. 最高速度記録(リニア)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for monorails: %.1f km/h by %s. 最高速度記録(モノレール)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for motorcars: %.1f km/h by %s. 最高速度記録(自動車)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for narrowgauges: %.1f km/h by %s. 最高速度記録(ナローゲージ)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for planes: %.1f km/h by %s. 最高速度記録(航空機)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for railways: %.1f km/h by %s. 最高速度記録(鉄é“)\n 時速 %.1f km\n「%sã€ãŒé”æˆ New world record for ship: %.1f km/h by %s. 最高速度記録(船舶)\n 時速 %.1f km\n「%sã€ãŒé”æˆ #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s 㯠路線: %s を増強ã—ã¾ã™ %s build rail line from %s (%s) to %s (%s) %s 㯠%s (%s) ã‹ã‚‰ %s (%s) ã¾ã§ã®é‰„é“路線を構築ã—ã¾ã™ %s build road line from %s (%s) to %s (%s) %s 㯠%s (%s) ã‹ã‚‰ %s (%s) ã¾ã§ã®è»Šä¸¡è·¯ç·šã‚’構築ã—ã¾ã™ %s build ship line from %s (%s) to %s (%s) %s 㯠%s (%s) ã‹ã‚‰ %s (%s) ã¾ã§ã®èˆªè·¯ã‚’構築ã—ã¾ã™ %s extends the route from %s (%s) to %s (%s) %s 㯠%s (%s) ã‹ã‚‰ %s (%s) ã¸ã¨ãƒ«ãƒ¼ãƒˆã‚’伸張ã—ã¾ã™ %s optimize way line from %s (%s) to %s (%s) %s 㯠%s (%s) ã‹ã‚‰ %s (%s) ã¾ã§ã®è·¯ç·šã‚’最é©åŒ–ã—ã¾ã™ %s removes convoys from line: %s %s 㯠路線: %s を縮å°ã—ã¾ã™ vehicles of the line %s were retired %s ã®è»Šä¸¡ã¯å¼•退ã—ã¾ã—㟠#_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. ã“ã®è·¯ç·šã¨åŒã˜ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã®è»Šä¸¡ã‚’追加ã—ã¾ã™ã€‚ Tutorial not available for this pakset. Please try loading Pak128. ã“ã®pakセットã«ã¯ãƒãƒ¥ãƒ¼ãƒˆãƒªã‚¢ãƒ«ãŒç”¨æ„ã•れã¦ã„ã¾ã›ã‚“。(最新版ã®pak128を確èªã—ã¦ã¿ã¦ãã ã•ã„) #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL å‚ &1_CITY_SYLL å´Ž &2_CITY_SYLL ç”° &3_CITY_SYLL 野 &4_CITY_SYLL æ©‹ &5_CITY_SYLL 塚 &6_CITY_SYLL å³¶ &7_CITY_SYLL æ²¼ &8_CITY_SYLL 原 &9_CITY_SYLL 岡 &A_CITY_SYLL è°· &B_CITY_SYLL 井 &C_CITY_SYLL 内 &D_CITY_SYLL å¹³ &E_CITY_SYLL æ²¢ %1_CITY_SYLL 森 %2_CITY_SYLL å±± %3_CITY_SYLL æ«» %4_CITY_SYLL 大 %5_CITY_SYLL æ¾ %6_CITY_SYLL å € %7_CITY_SYLL 倉 %8_CITY_SYLL 竹 %9_CITY_SYLL ç¦ %A_CITY_SYLL å· %B_CITY_SYLL 富士 %C_CITY_SYLL 白 %D_CITY_SYLL 石 %E_CITY_SYLL å¤ %F_CITY_SYLL 神 1center %s%s 1extern å‰%s%s 1suburb %s%s%s 2center %s中央%s 2extern 上%s%s 3center %s本町%s 3extern 下%s%s 4center 中%s%s 4extern %s外%s 5center æ–°%s%s 6center å…ƒ%s%s 7center %s大通り%s simutrans-124.3/simutrans/text/ja/000077500000000000000000000000001474050137200171565ustar00rootroot00000000000000simutrans-124.3/simutrans/text/ja/airtools.txt000066400000000000000000000161121474050137200215540ustar00rootroot00000000000000航空機ツール ヘルプ

航空機ツール

航空機ツールã«ã¯ã€èˆªç©ºè¼¸é€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’構築ã™ã‚‹ãŸã‚ã®ãƒ„ールãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚ツールã§ã¯ã€èˆªç©ºæ©Ÿç”¨ã®èª˜å°Žè·¯ã‚„滑走路ã€ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ï¼ˆè²¨ç‰©ã‚„ä¹—å®¢ã®æ­ä¹—ã‚„é™æ©Ÿã«ä½¿ç”¨ï¼‰ã€èˆªç©ºæ©Ÿã®æ ¼ç´åº«ï¼ˆèˆªç©ºè¼¸é€è»Šä¸¡ã®è³¼å…¥ã‚„管ç†ï¼‰ã€ã•ã¾ã–ã¾ãªç©ºæ¸¯ã®å»ºç‰©ãªã©ã‚’構築ã—ãŸã‚Šã€å‰Šé™¤ã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚年代設定ã§ãƒ—レイã—ã¦ã„ã‚‹å ´åˆã¯ã€Simutransã®æ™‚間経éŽã«ä¼´ã„ã€ãƒ„ールオプションãŒè¡¨ç¤ºã•れã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚る飛行機ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã—ã¦ã€ãƒ„ールãƒãƒ¼ã‚’é–‹ãã¾ã™ã€‚
ツールオプションã®ä¸Šã«ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ã‚’ç½®ãã¨ï¼ˆãƒ„ールãƒãƒ¼ã‚’é–‹ãã‹ã‚¯ãƒªãƒƒã‚¯ã—ãŸå¾Œï¼‰ã€åç§°ã¨å¿…è¦ã«å¿œã˜ã¦å»ºè¨­è²»ã€ç¶­æŒè²»ã®æ‹¬å¼§æ›¸ãã€æœ€é«˜é€Ÿåº¦ã®åˆ¶é™ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

{ヒント: 簡易ãªç©ºæ¸¯ã‚’作る方法ã®ä¸€ã¤ã¨ã—ã¦ã¯ã€
i) èª˜å°Žè·¯ã¨æ»‘走路を建設ã—ã€æŽ¥ç¶šã—ã¾ã™ã€‚
ii) 誘導路ã®ç«¯ã«ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—を設置ã—ã¾ã™ã€‚
iii) å¿…è¦ã«å¿œã˜ã¦ç©ºæ¸¯ã®å»ºç‰©ã‚’追加ã—ã¾ã™ã€‚}

ツールã¯ã€å·¦ã‹ã‚‰å³ã®é †ã«ä»¥ä¸‹ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒã‚りã¾ã™ã€‚

誘導路: 航空機ãŒã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ã‹ã‚‰æ»‘èµ°è·¯ã«å‘ã‹ã†ãŸã‚ã®åœ°ä¸Šç§»å‹•エリアを構築ã™ã‚‹ãƒ„ールã§ã™ã€‚誘導路ã¯ã‚²ãƒ¼ãƒ ãƒ“ュー上ã®å¹³åœ°ã«ä½œã‚‰ã‚Œã¾ã™ã€‚
é‡è¦: èª˜å°Žè·¯ãŒæ»‘èµ°è·¯ã®ç«¯ã«æŽ¥ç¶šã•れã¦ã„ã‚‹å ´åˆã€èˆªç©ºæ©Ÿã¯é›¢ç€é™¸ã§ãã¾ã›ã‚“。
誘導路を作るã«ã¯ï¼šãƒ„ールをクリックã—ã¦é¸æŠžã—(カーソルãŒèª˜å°Žè·¯ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«å§‹ç‚¹ã¨ãªã‚‹åœ°å½¢ã‚’クリックã—(ゲームビューã§ãƒ–ルドーザーãŒè¡¨ç¤ºã•れã€ãƒ‡ã‚£ã‚¹ãƒ—レイã®å³ä¸‹ã«åœ°å›³ã®åº§æ¨™ãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æœ€å¾Œã«çµ‚点ã¨ãªã‚‹åœ°å½¢ã¾ãŸã¯æ»‘走路をクリックã—ã¾ã™ã€‚
{ヒント:滑走路ï¼èª˜å°Žè·¯ã®æ’¤åŽ»ã‚’ä½¿ã£ã¦èª˜å°Žè·¯ã®å€‹ã€…ã®åŒºç”»ã‚’削除ã—ã¾ã™ã€‚å…ƒã«æˆ»ã™ [z] ã§ã¯å»ºè¨­ã‚³ã‚¹ãƒˆã¯æˆ»ã‚Šã¾ã›ã‚“。}

滑走路:航空機ãŒé›¢ç€é™¸ã™ã‚‹éš›ã«ä½¿ç”¨ã™ã‚‹æ»‘走路を作るツールã§ã™ã€‚滑走路ã¯ã‚²ãƒ¼ãƒ ãƒ“ュー上ã®å¹³åœ°ã«ä½œã‚‰ã‚Œã€äº’ã„ã«äº¤å·®ã™ã‚‹ã“ã¨ã‚‚ã‚りã¾ã™ã€‚
滑走路を作るã«ã¯ï¼šãƒ„ールをクリックã—ã¦é¸æŠžã—(カーソルãŒwayã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«é–‹å§‹ç‚¹ã¨ãªã‚‹åœ°å½¢ã‚’クリックã—(ゲームビューã§ã¯ãƒ–ルドーザーãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æœ€å¾Œã«çµ‚了点ã¨ãªã‚‹åœ°å½¢ã‚’クリックã—ã¾ã™ã€‚
{ヒント: 滑走路ãŒè¤‡æ•°ã‚ã‚‹å ´åˆã«ãã®ç«¯ã‚’接続ã—ãªã„ã§ãŠãã¨ã€èˆªç©ºæ©ŸãŒé›¢ç€é™¸ã§ããªã„ã“ã¨ãŒã‚りã¾ã™ã€‚滑走路ã®å€‹ã€…ã®éƒ¨åˆ†ã‚’削除ã™ã‚‹ã«ã¯ã€ [滑走路ï¼èª˜å°Žè·¯ã®æ’¤åŽ»] を使用ã—ã¦ãã ã•ã„ã€‚å…ƒã«æˆ»ã™ [z] ã§ã¯å»ºè¨­è²»ã¯æˆ»ã‚Šã¾ã›ã‚“。}

滑走路ï¼èª˜å°Žè·¯ã®æ’¤åŽ»: ゲームビュー上ã®2点間ã§ã€èˆªç©ºæ©ŸãŒå­˜åœ¨ã—ãªã„å ´åˆã«ã€èª˜å°Žè·¯ã‚„滑走路ã®éƒ¨åˆ†ã‚’削除ã™ã‚‹ãƒ„ールã§ã™ã€‚ツールã®ä½¿ç”¨ã«ã¯å»ºè¨­è²»ãŒã‹ã‹ã‚Šã¾ã™ã€‚
滑走路を削除ã™ã‚‹ã«ã¯ï¼šãƒ„ールをクリックã—(カーソルãŒèµ¤ã„åå­—ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«å‰Šé™¤ã—ãŸã„ストリップ(部分)をクリックã—(ゲームビューã§èµ¤ã„åå­—ã§è¡¨ç¤ºã•れる削除ãƒã‚¤ãƒ³ãƒˆãŒé¸æŠžã•れã¾ã™ï¼‰ã€æœ€å¾Œã«ã‚¹ãƒˆãƒªãƒƒãƒ—ã®åˆ¥ã®ãƒã‚¤ãƒ³ãƒˆã‚’クリックã™ã‚‹ã¨ã€æœ€åˆã®å‰Šé™¤ãƒã‚¤ãƒ³ãƒˆã¾ã§ã®éƒ¨åˆ†ãŒå‰Šé™¤ã•れã¾ã™ã€‚
{ãƒ’ãƒ³ãƒˆï¼šå„æ»‘èµ°è·¯ã®ç«¯ã‚’接続ã—ãªã„ã§ãŠãã¨ã€é£›è¡Œæ©ŸãŒé›¢ç€é™¸ã§ããªã„ã“ã¨ãŒã‚りã¾ã™ã€‚滑走路ã®å€‹ã€…ã®éƒ¨åˆ†ã‚’削除ã™ã‚‹ã«ã¯ [滑走路ï¼èª˜å°Žè·¯ã®æ’¤åŽ»] を使用ã—ã¦ãã ã•ã„。}

èˆªç©ºæ©Ÿã®æ ¼ç´åº«ï¼šèˆªç©ºæ©Ÿã‚’購入・管ç†ã™ã‚‹ãŸã‚ã®æ ¼ç´åº«ï¼ˆãƒãƒ³ã‚¬ãƒ¼ï¼‰ã‚’作るツールã§ã™ã€‚æ ¼ç´åº«ã«ã¯ç¶­æŒè²»ãŒã‹ã‹ã‚Šã€èª˜å°Žè·¯ã®ç«¯ã«å»ºè¨­ã•れã¾ã™ã€‚
æ ¼ç´åº«ã‚’作るã«ã¯ã€ãƒ„ールをクリックã—ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒæ ¼ç´åº«ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«èª˜å°Žè·¯ã®ç«¯ã‚’クリックã—ã¾ã™ã€‚
{ヒント: æ ¼ç´åº«ã¯ [削除ï¼å–り壊ã—] ã§å‰Šé™¤ã—ã¦ãã ã•ã„。}

é§æ©Ÿå ´ï¼†ãƒœãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ãƒ–リッジ(æ­ä¹—橋): 航空機ãŒä¹—客や貨物をé€è¿Žã™ã‚‹ãŸã‚ã®åœç•™æ‰€ã‚’ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ä¸Šã«æ§‹ç¯‰ã™ã‚‹ãƒ„ールã§ã™ã€‚
ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ï¼ˆé§æ©Ÿå ´ï¼‰ã¯ã€æ—¢å­˜ã®ã‚¹ãƒˆãƒƒãƒ—ã«éš£æŽ¥ã—ã¦å»ºè¨­ã•れãªã„å ´åˆã€æ–°ãŸãªã‚¹ãƒˆãƒƒãƒ—ã¨ã—ã¦å»ºè¨­ã™ã‚‹ã“ã¨ã«ãªã‚Šã¾ã™ã€‚ エアストップã¯èª˜å°Žè·¯ã®ç«¯ã«å»ºè¨­ã•れã€ç¶­æŒè²»ãŒã‹ã‹ã‚Šã€è²¨ç‰©ã€ä¹—客ã€éƒµä¾¿ç‰©ã®é›†æ•£åœ°ã¨ãªã‚Šã¾ã™ã€‚航空機ã¯ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ãŒç©ºã„ã¦ã„る空港ã«ã®ã¿ç€é™¸ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
エアストップを作るã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ã€èª˜å°Žè·¯ã®ç«¯ã‚’クリックã—ã¾ã™ã€‚
{ヒント:「撤去ï¼å–り壊ã—ã€ã§ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ã‚’å–り除ãã¾ã™ã€‚ [v] を押ã™ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューã§è²¨ç‰©ã‚„乗客ã®ãŸã‚ã®é›†å®¢ã‚¨ãƒªã‚¢ã®è¡¨ç¤ºï¼éžè¡¨ç¤ºã‚’切り替ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

空港施設等:å„ツールã¯ã‚¨ã‚¢ã‚¹ãƒˆãƒƒãƒ—ã®ä»˜å±žæ–½è¨­ã‚’建設ã—ã¾ã™ãŒã€ã“れã«ã‚ˆã£ã¦ç¶­æŒè²»ãŒå¢—加ã—ãŸã‚Šã€ç©è·ã‚„乗客ã®åŽå®¹èƒ½åŠ›ã‚„é›†å®¢ã‚¨ãƒªã‚¢ãŒå¢—加ã—ãŸã‚Šã—ã¾ã™ã€‚ã„ãã¤ã‹ã®ãƒ„ールã®ã‚ªãƒ—ションã®éš…ã«ã¯ã€ã‚¢ã‚¤ã‚³ãƒ³ãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆé§…一覧表ã¨ã‚¹ãƒˆãƒƒãƒ—情報ã§ä½¿ç”¨ï¼‰ã€‚
追加施設を作るã«ã¯ã€ãƒ„ールをクリックã—ã¦è¿½åŠ ã—ãŸã„æ–½è¨­ã‚’é¸æŠžã—(カーソルãŒè¿½åŠ æ–½è¨­ã«å¤‰ã‚りã¾ã™ï¼‰ã€ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ã§æ—¢å­˜ã®åœç•™æ‰€ã®éš£ã«ã‚ã‚‹å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚æ–°ã—ã„æ–½è¨­ã¯ã€ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€éƒ¨ã¨ã¿ãªã•れã¾ã™ã€‚
{ヒント: 追加ã—ãŸæ–½è¨­ã‚’削除ã™ã‚‹ã«ã¯ã€å‰Šé™¤/å–り壊㗠を使用ã—ã¾ã™ã€‚ [v] を押ã™ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューã®è²¨ç‰©ãƒ»ä¹—客用ã®é›†å®¢ã‚¨ãƒªã‚¢ã®è¡¨ç¤ºï¼éžè¡¨ç¤ºã‚’切り替ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/baum_build.txt000066400000000000000000000040521474050137200220230ustar00rootroot00000000000000木をæ¤ãˆã‚‹ã€€ãƒ˜ãƒ«ãƒ—

木をæ¤ãˆã‚‹

木をæ¤ãˆã‚‹ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§ã¯ã€å€‹ã€…ã®æœ¨ã‚’æ¤ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“れã¯ã€ãƒ—レーヤーを公共事業ã«åˆ‡ã‚Šæ›¿ãˆãŸã¨ãã«ã€ãƒžãƒƒãƒ—編集ツールãƒãƒ¼ã‹ã‚‰åˆ©ç”¨ã§ãるマップカスタマイズオプションã§ã™ã€‚
ヒント:ã“ã®ãƒãƒ¼ã«ã¯ã€ä¸€åº¦ã«æ£®ã‚’追加ã™ã‚‹ãŸã‚ã®æ£®ã‚’追加ã™ã‚‹ãƒœã‚¿ãƒ³ã‚‚ã‚りã¾ã™ã€‚

ダイアログã¯4ã¤ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã«åˆ†ã‹ã‚Œã¦ã„ã¾ã™ã€‚
· 左上ã«ã¯ã€æ¤æ¨¹å¯èƒ½ãªã™ã¹ã¦ã®æ¨¹ç¨®ã®ä¸€è¦§ï¼ˆãƒªã‚¹ãƒˆï¼‰ãŒè¡¨ç¤ºã•れã¦ã„ã¾ã™ã€‚リストã®ä¸­ã®é …目をクリックã™ã‚‹ã¨ã€ãã®æœ¨ã®è©³ç´°æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚木をé…ç½®ã™ã‚‹ã«ã¯ã€ãƒªã‚¹ãƒˆã‹ã‚‰é¸æŠžã—ãŸå¾Œã€ã‚²ãƒ¼ãƒ ãƒ¯ãƒ¼ãƒ«ãƒ‰ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å†…ã§å¸Œæœ›ã®å ´æ‰€ã‚’クリックã—ã¾ã™ã€‚
· 左下ã«ã¯ã€é¸ã‚“ã æœ¨ã®ç”»åƒãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· å³ä¸Šã«ã¯ã„ãã¤ã‹ã®ã‚ªãƒ—ションãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚
· é¸æŠžè‚¢ã®ä¸‹ã«ã¯ã€é¸æŠžã—ãŸæœ¨ã«ã¤ã„ã¦ã®æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

é¸æŠžãƒªã‚¹ãƒˆ

é¸æŠžãƒªã‚¹ãƒˆã«ã¯2ã¤ã®ã‚¿ãƒ–ãŒã‚ã‚Šã€æœ¨ã®ã‚¿ã‚¤ãƒ—ã®è­˜åˆ¥æ–¹æ³•を変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
· 日本語å: パックセットã§å®šç¾©ã•れã¦ã„るよã†ã«ã€æŒ‡å®šã•れãŸè¨€èªžã§ãã®æœ¨ã®åå‰ã‚’表示ã—ã¾ã™ã€‚利用å¯èƒ½ãªç¿»è¨³ãŒãªã„å ´åˆã¯ã€å…ƒã®ã‚ªãƒ–ジェクトå(原å)ãŒä½¿ç”¨ã•れã¾ã™ã€‚
· 原å: Simutransã®å†…部オブジェクトåを表示ã—ã¾ã™ã€‚

オプション

· 気候æ¡ä»¶ã‚’無視ã™ã‚‹: ã“ã®ã‚ªãƒ—ションã¯ã€æ§˜ã€…ãªæœ¨ã®ã‚¿ã‚¤ãƒ—ã«é–¢é€£ã™ã‚‹æ°—候制é™ã‚’無効ã«ã—ã¾ã™ã€‚
· 年代設定を使用: æ¤ãˆã‚‰ã‚Œã‚‹æœ¨ã®å¹´é½¢ã¯ãƒ©ãƒ³ãƒ€ãƒ ã«ãªã‚Šã¾ã™ã€‚é€šå¸¸ã€æœ€ã‚‚è‹¥ã„å¹´é½¢ã§æ¤ãˆã‚‰ã‚Œã€æˆç†Ÿã—ã¦ã‹ã‚‰ä½•å¹´ã‚‚ã‹ã‘ã¦æž¯ã‚Œã¦ã„ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/citybuilding_build.txt000066400000000000000000000050231474050137200235640ustar00rootroot00000000000000市内建築物建築ツール ヘルプ

市内建築物建築ツール

ダイアログã¯4ã¤ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã«åˆ†ã‹ã‚Œã¦ã„ã¾ã™ã€‚
· 左上ã¯ã€åˆ©ç”¨å¯èƒ½ãªéƒ½å¸‚ã®å»ºç‰©ã®é¸æŠžä¸€è¦§è¡¨ã§ã™ã€‚
· 左下ã«ã¯ã€é¸æŠžã—ãŸéƒ½å¸‚ã®å»ºç‰©ã®ç”»åƒãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· å³ä¸Šã«ã¯ã„ãã¤ã‹ã®ã‚ªãƒ—ションãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚
· å³ä¸‹ã¯ã€é¸æŠžã•れãŸéƒ½å¸‚ã®å»ºç‰©ã«é–¢ã™ã‚‹æƒ…å ±ã§ã™ã€‚

é¸æŠžãƒªã‚¹ãƒˆ

é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€å³ä¸Šã«æŒ‡å®šã•れãŸã‚ªãƒ—ション(ä½å®…ã€å•†åº—やオフィスã€å·¥å ´ã®å»ºç‰©ï¼‰ã§åˆ©ç”¨å¯èƒ½ãªã€ã™ã¹ã¦ã®éƒ½å¸‚部ã®å»ºç‰©ãŒè¡¨ç¤ºã•れã¾ã™ã€‚都市部ã®å»ºç‰©ã®è­˜åˆ¥æ–¹æ³•を変更ã™ã‚‹ãŸã‚ã«ã€2ã¤ã®ã‚¿ãƒ–ãŒã‚りã¾ã™ã€‚
· 日本語å: 指定ã•れãŸè¨€èªžï¼ˆæ—¥æœ¬èªžï¼‰ã§ã®å»ºç‰©ã®åå‰ã‚’表示ã—ã¾ã™ã€‚指定ã•れãŸè¨€èªžã§åˆ©ç”¨å¯èƒ½ãªç¿»è¨³ãŒãªã„å ´åˆã¯ã€åŽŸå(オブジェクトå)ãŒä½¿ç”¨ã•れã¾ã™ã€‚
。 - 原å: 建物ã®ç¨®é¡žã«å¯¾ã™ã‚‹Simutrans内部ã®ã‚ªãƒ–ジェクトåを表示ã—ã¾ã™ã€‚

文字ã®è‰²ã«ã¯æ¬¡ã®ã‚ˆã†ãªæ„味ãŒã‚りã¾ã™ã€‚
· é’ã®æ–‡å­—ã¯ä½å®…を表ã—ã¾ã™ã€‚
· ç·‘ã®æ–‡å­—ã¯ã€å•†åº—やオフィスビルを表ã—ã¾ã™ã€‚
· é»’ã®æ–‡å­—ã¯ã€å·¥å ´ã®å»ºç‰©ã‚’表ã—ã¾ã™ã€‚

オプション

· 気象æ¡ä»¶ã‚’無視ã™ã‚‹: ã“ã®ã‚ªãƒ—ションã¯ã€æ§˜ã€…ãªå»ºç‰©ã‚¿ã‚¤ãƒ—ã«é–¢é€£ä»˜ã‘られã¦ã‚‹æ°—候制é™ã‚’無効ã«ã—ã¾ã™ã€‚
· 年代設定を使用: é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€ç¾åœ¨ã®Simutrans年度ã«åˆ©ç”¨å¯èƒ½ãªå»ºç‰©ã®ã¿ãŒå«ã¾ã‚Œã¾ã™ã€‚
· 旧型を表示: é¸æŠžãƒªã‚¹ãƒˆã‚’æ‹¡å¼µã—ã¦ã€ç¾åœ¨ã®Simutransã®å¹´ã«å»ƒæ­¢ã•れãŸå»ºç‰©ã‚‚å«ã‚るよã†ã«ã—ã¾ã™ã€‚
· ä½å®…: é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€ä½å®…ãŒå«ã¾ã‚Œã¾ã™ã€‚
· 商店ã¨ã‚ªãƒ•ィスビル: é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€å•†åº—ã¨å·¥å ´ãŒå«ã¾ã‚Œã¾ã™ã€‚
· 工場: é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€å·¥å ´ãŒå«ã¾ã‚Œã¾ã™ã€‚
· å‘ã: é¸ã‚“ã å»ºç‰©ãŒã•ã¾ã–ã¾ãªè§’度ã‹ã‚‰è¦‹ã‚‰ã‚Œã‚‹å ´åˆã¯ã€ã“ã“ã§ç‰¹å®šã®å‘ãã‚’é¸ã¶ã“ã¨ãŒã§ãã¾ã™ã€‚é¸æŠžã—ãŸãƒ“ューã¯å·¦ä¸‹ã®ç”»åƒã«å映ã•れã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒãƒ©ãƒ³ãƒ€ãƒ ã«è¨­å®šã•れã¦ã„ã‚‹å ´åˆã€å»ºç‰©ã®å‘ãã¯ãƒ©ãƒ³ãƒ€ãƒ ã«ä½¿ç”¨ã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/citylist_filter.txt000066400000000000000000000050111474050137200231250ustar00rootroot00000000000000町一覧

町一覧

町一覧ã§ã¯éƒ½å¸‚部(æ‘ã€ç”ºã€å¸‚)ã«ã¤ã„ã¦äººå£ãªã©ã®è©³ç´°æƒ…報を得るã“ã¨ãŒ
ã§ãã¾ã™ã€‚ã¾ãŸã€ãƒžãƒƒãƒ—世界全体ã®çµ±è¨ˆæƒ…報をグラフã§è¦‹ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

é–‹ãæ–¹ï¼šä¸€è¦§è¡¨ãƒ„ールã®è¡—一覧ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã‹ã€[T]キーを
押ã—ã¾ã™ã€‚

æ“作: リストã®éƒ½å¸‚ã®åå‰ã‚’左クリックã™ã‚‹ã¨ã€è¡—ã®è©³ç´°ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹
ãã¾ã™ã€‚å³ã‚¯ãƒªãƒƒã‚¯ã¾ãŸã¯å·¦ç«¯ã®çŸ¢å°ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ç”»é¢
を都市ã«ç§»å‹•ã—ã¾ã™ã€‚

ç·äººå£ï¼šã¯ã‚²ãƒ¼ãƒ å†…ã®å…¨å¸‚æ°‘ã®åˆè¨ˆæ•°ï¼ˆå…¨ã¦ã®éƒ½å¸‚部ã®äººå£ã®åˆè¨ˆï¼‰
ã§ã™ã€‚最近ã®äººå£å¢—加ã¯ã‚«ãƒƒã‚³ä»˜ãã§è¡¨ç¤ºã•れã¦ã„ã¾ã™ã€‚

ä¸¦ã³æ›¿ãˆï¼š: ボタンã®ã‚¯ãƒªãƒƒã‚¯ã§ãƒªã‚¹ãƒˆã®ä¸¦ã³æ›¿ãˆåŸºæº–を切り替ãˆã¾ã™ã€‚

- 都市å åå‰ã®æ–‡å­—コードを基準ã«ä¸¦ã³æ›¿ãˆã¾ã™ã€‚
- 使°‘ 人å£è¦æ¨¡ã«ã‚ˆã£ã¦ä¸¦ã³æ›¿ãˆã¾ã™ã€‚
- 発展 発展度(ã«ã‚ˆã£ã¦ä¸¦ã³æ›¿ãˆã¾ã™ã€‚

- 昇順 / é™é † 並ã³é †ã‚’å転ã•ã›ã¾ã™ã€‚

都市å ãã®éƒ½å¸‚部ã®åå‰

äººå£ ãã®éƒ½å¸‚部ã®äººå£ã€‚ã‚«ãƒƒã‚³å†…ã¯æœ€è¿‘ã®ç™ºå±•度。

グラフ: グラフを開閉ã—ã¾ã™ã€‚

使°‘: 使°‘ã®æ•°

発展: 増加ã—ãŸä½æ°‘ã®æ•°

都市: éƒ½å¸‚ã®æ•°

産業: ç”£æ¥­æ–½è¨­ã®æ•°

ç·¨æˆæ•°: 全社ã®è»Šä¸¡ç·¨æˆã®ç·æ•°

自家用車: 自家用車ã®ç·æ•°

旅客輸é€çއ(%): 旅行希望者ã®ã†ã¡ã€ç›®çš„地ã¸ã¨å‡ºç™ºã§ããŸå‰²åˆ(%)

旅客: 旅行希望者ã®ç·æ•°

é…é”実績: é…é”希望郵便ã®ã†ã¡ã€ç›®çš„地ã¸ã¨å‡ºç™ºã§ããŸå‰²åˆ(%)

郵便: é…é”希望郵便ã®ç·æ•°

到ç€: 最終消費地ã«å¿…è¦ãªè£½å“ã®ç¨®é¡žã†ã¡ã€åœ¨åº«ãŒå……è¶³ã•れã¦ã„る種類ã®å‰²åˆ(%)

製å“: 最終消費地ã«å¿…è¦ãªè£½å“ã®ç¨®é¡žã®ç·æ•°

旅客輸é€çއ(%)ã€é…é”実績ã€åˆ°ç€ã®å‰²åˆã¯ã€å„都市ã®ç™ºå±•ã«å¤§ãã影響ã—ã¾ã™ã€‚
割åˆãŒé«˜ã„ã»ã©ã€ã‚ˆã‚Šé€Ÿã発展ã—ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/citywindow.txt000066400000000000000000000061741474050137200221270ustar00rootroot00000000000000è¡—ã®è©³ç´°ã®ãƒ˜ãƒ«ãƒ—

è¡—ã®è©³ç´°

é–‹ãæ–¹ï¼šè¡—ã®è©³ç´°ã‚’é–‹ãã«ã¯ã€ã‚²ãƒ¼ãƒ ç”»é¢ä¸Šã§èª¿æŸ»ãƒ„ールを使ã£ã¦
役所をクリックã™ã‚‹ã‹ã€ç”ºä¸€è¦§ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§ãƒªã‚¹ãƒˆã‚’左クリックã—ã¾ã™ã€‚

åå‰: 直接変更ã§ãã¾ã™ã€‚é•·ã„åå‰ã¯å…¥åŠ›ã§ãã¾ã›ã‚“。
è¡—ã®è¦æ¨¡: 都市ã®äººå£ã€‚ã‚«ãƒƒã‚³å†…ã¯æœ€è¿‘ã®ç™ºå±•度。
市街地: å»ºç‰©ã®æ•°ï¼ˆãƒ–ロック数)
市域: 都市ã®å¸‚域ã®å¢ƒç•Œåº§æ¨™
建物ãŒå»ºè¨­ã•れãŸã‚Šã€å¸‚é“ãŒæ•´å‚™ã•れるã®ã¯ã€ã“ã®å¸‚域ã®ç¯„囲内ã ã‘ã§ã™ã€‚
市域ã¯ãƒžãƒƒãƒ—ウィンドウã§ã‚‚確èªã§ãã¾ã™ã€‚

ç„¡è·è€…: 商店や工場ãŒå¢—ãˆã‚‹ã¨ã€ç„¡è·è€…ã®æ•°ã¯æ¸›å°‘ã—ã¾ã™ã€‚
浮浪者: ä½å±…ã®æ•°ãŒå¢—ãˆã‚‹ã¨ã€æµ®æµªè€…ã®æ•°ã¯æ¸›å°‘ã—ã¾ã™ã€‚

通常ã€ç„¡è·è€…ã¨æµ®æµªè€…ã¨ã®åˆè¨ˆãŒ100ã‚’è¶…ãˆã‚‹ã¨ã€æ–°ã—ã„建物ãŒå»ºè¨­ã•れ
ãŸã‚Šã€å¢—改築ãŒè¡Œã‚れã¾ã™ã€‚ç„¡è·è€…ã¨æµ®æµªè€…ã¨ã®æ•°ãŒã©ã‚“ã©ã‚“増ãˆç¶šã‘ã¦
ã„るよã†ãªå ´åˆã¯ã€æ–°ã—ã„建物を建設ã™ã‚‹é©åˆ‡ãªå ´æ‰€ãŒãªã‹ã£ãŸã‚Šã€å»ºç‰©
ãŒæœ€å¤§ãƒ¬ãƒ™ãƒ«ã«é”ã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚é©åˆ‡ãªæ•´åœ°ã‚„é“路整備ã§
改善ã•れるã‹ã‚‚ã—れã¾ã›ã‚“。

街を発展ã•ã›ã‚‹: ã“ã®ãƒœã‚¿ãƒ³ã‚’オフã«ã™ã‚‹ã¨ã€ã“ã®éƒ½å¸‚ã®ç™ºå±•を一時的ã«
æ­¢ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®ãƒœã‚¿ãƒ³ã®çŠ¶æ…‹ã¯ã‚»ãƒ¼ãƒ–ゲームã«ä¿å­˜ã•れã¾ã™ã€‚

åœ°å›³ï¼šå‰æœˆã¨ä»Šæœˆã®æ—…客ã¨éƒµä¾¿ã®ç›®çš„地を表示ã—ã¦ã—ã¾ã™ã€‚
地図上を左クリックã™ã‚‹ã¨ã€ã§ã‚²ãƒ¼ãƒ ç”»é¢ã‚’移動ã§ãã¾ã™ã€‚
マップウィンドウã«è¡¨ç¤ºã•ã›ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚
 橙: 目的地ã¸å‡ºç™ºã§ããŸ
 黄: 目的地ã¸å‡ºç™ºã§ããªã‹ã£ãŸ

グラフ

使°‘: 使°‘ã®æ•°

発展: 増加ã—ãŸä½æ°‘ã®æ•°

市街地: å»ºç‰©ã®æ•°ï¼ˆãƒ–ロック数)

自家用車: ã“ã®éƒ½å¸‚ã§å¢—ãˆãŸè‡ªå®¶ç”¨è»Šã®æ•°

輸é€å®Ÿç¸¾: ã“ã®éƒ½å¸‚ã®æ—…行希望者ã®ã†ã¡ã€ç›®çš„地ã¸ã¨å‡ºç™ºã§ããŸæ•°

旅客: ã“ã®éƒ½å¸‚ã®æ—…è¡Œå¸Œæœ›è€…ã®æ•°

é…é”実績: ã“ã®éƒ½å¸‚ã®é…é”希望郵便ã®ã†ã¡ã€ç›®çš„地ã¸ã¨å‡ºç™ºã§ããŸæ•°

郵便: ã“ã®éƒ½å¸‚ã®é…é”å¸Œæœ›éƒµä¾¿ã®æ•°

到ç€: ã“ã®éƒ½å¸‚ã‹ã‚‰åŠ´åƒè€…ãŒé€šã†æœ€çµ‚消費地ã«å¿…è¦ãªè£½å“ã®ç¨®é¡žã†ã¡ã€
在庫ãŒå……è¶³ã•れã¦ã„ã‚‹ç¨®é¡žã®æ•°

製å“: ã“ã®éƒ½å¸‚ã‹ã‚‰åŠ´åƒè€…ãŒé€šã†æœ€çµ‚消費地ã«å¿…è¦ãªè£½å“ã®ç¨®é¡žã®æ•°

輸é€å®Ÿç¸¾/旅客ã€é…é”実績/郵便ã€åˆ°ç€/製å“ã®å‰²åˆã¯ã€éƒ½å¸‚ã®ç™ºå±•ã«
大ãã影響ã—ã¾ã™ã€‚割åˆãŒé«˜ã„ã»ã©ã€ã‚ˆã‚Šé€Ÿã発展ã—ã¾ã™ã€‚
ã¾ãŸã€ã“ã®å‰²åˆãŒä½Žã„ã¨è‡ªå®¶ç”¨è»ŠãŒå¢—ãˆã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/climates.txt000066400000000000000000000103201474050137200215140ustar00rootroot00000000000000気候ã®è¨­å®šã€€ãƒ˜ãƒ«ãƒ—

気候ã®è¨­å®š

「気候ã®è¨­å®šã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§ã¯ã€ã‚²ãƒ¼ãƒ ãƒ¯ãƒ¼ãƒ«ãƒ‰ã®åœ°å½¢ã‚„気象ã«é–¢ã™ã‚‹ã‚ªãƒ—ションを設定ã—ã¾ã™ã€‚ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯ã€ã€Œæ–°ã—ã„マップã®ä½œæˆã€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®é …ç›®ã«ã‚るオプションã®1ã¤ã§ã™ã€‚

å„設定ã®èª¿æ•´ã¯ã€å„é …ç›®ã®æ¨ªã«ã‚る矢å°ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã‹ã€ãƒœãƒƒã‚¯ã‚¹ã«æ•°å­—を入力ã—ã¦è¡Œã„ã¾ã™ã€‚

マップã®ã‚ªãƒ—ション

æµ·é¢æ°´ä½ - ãƒžãƒƒãƒ—ä¸Šã®æ°´ä½ã®é«˜ã•を設定ã—ã¾ã™ï¼ˆæ¨™æº–値 -2)。 値ãŒé«˜ã„ã»ã©ã€ã‚ˆã‚Šå°‘ãªã„土地ã¨ã‚ˆã‚Šå¤šãã®æ°´åŸŸãŒæä¾›ã•れã¾ã™ã€‚

èµ·ä¼ã®é«˜ã• - åœ°å½¢ã®æœ€å¤§ã®é«˜ã•を設定ã—ã¾ã™ã€‚

èµ·ä¼ã®æ¿€ã—ã• - åœ°å½¢ã®æ¿€ã—ã•を設定ã—ã¾ã™ã€‚数値ãŒå¤§ãã„ã»ã©ã€æ²¿å²¸éƒ¨ã®èµ·ä¼ãŒå¤§ãããªã‚Šã¾ã™ï¼ˆã‚ˆã‚Šãƒªã‚¢ãƒ«ã«è¦‹ãˆã¾ã™ï¼‰ã€‚éžå¸¸ã«èµ·ä¼ã®ã‚るマップã§ã¯ã€æ„図ã—ãŸã»ã©å¤šãã®éƒ½å¸‚ã€ç”£æ¥­ã€é“路を生æˆã§ããªã„å ´åˆãŒã‚りã¾ã™ã€‚

警告: 33以上ã®é«˜ã•ã®ãƒ¬ãƒ™ãƒ«ã¯é¿ã‘ã‚‹ã¹ãã§ã™ï¼ˆãƒ—レイヤーã¯ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“)。必è¦ã«å¿œã˜ã¦ã€æ°´ä½ã‚’下ã’ã‚‹ã“ã¨ã§ã€ã‚ˆã‚Šå¤šãã®åœŸåœ°ã‚’生æˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

雪線オプション
雪線ã¨ã¯ã€é›ªãŒç¾ã‚Œã‚‹åœ°å›³ä¸Šã®é«˜ã•ã®ã“ã¨ã§ã™ã€‚年間を通ã˜ã¦ã€Simutransã®é›ªç·šã¯æ¬¡ã®è¨­å®šã«å¾“ã£ã¦å¤‰åŒ–ã—ã¾ã™ã€‚

å¤å­£ã®é›ªç·š - 極気候ã¯ã“ã“ã‹ã‚‰å§‹ã¾ã‚Šã¾ã™ã€‚å¤ã®é–“ã®é›ªç·šï¼ˆä¸‡å¹´é›ªï¼‰ã€‚ã“ã®å€¤ã¯ã€æ°—候オプションã§é¸æŠžã•ã‚ŒãŸæœ€ã‚‚高ã„地形ã®å€¤ã§ã™ã€‚

冬季ã®é›ªç·š - 冬季ã®é›ªç·šã®æœ€å°é«˜ã•を設定ã—ã¾ã™ã€‚マップ上ã®ã‚ˆã‚Šåºƒã„範囲ã«é›ªã‚’出ç¾ã•ã›ãŸã„å ´åˆã¯ã€ã“ã®å€¤ã‚’å°ã•ãã—ã¾ã™ã€‚

気候オプション
æ–°ã—ã„マップã«ç•°ãªã‚‹æ°—候タイプを設定ã—ã¾ã™ã€‚

ãれãžã‚Œã®æ°—候タイプã®éš£ã«ã‚る値ã¯ã€åœ°å½¢å›³ã®ä¸­ã§ãã®æ°—候ãŒç¾ã‚Œã‚‹å ´æ‰€ã¾ã§ã®é«˜ã•を設定ã—ã¾ã™ã€‚高ã„ä½ç½®ã«ã‚る気候帯ã¯ã€ä½Žã„ä½ç½®ã«ã‚る気候帯ã§ãŠãŠã‚れã¦ã„ã¾ã™ã€‚ç‰¹å®šã®æ°—候をオフã«ã™ã‚‹ã«ã¯ã€ãã®å€¤ã‚’リストã®ã•らã«ä¸Šã®æ°—候ã¨åŒã˜å€¤ã«è¨­å®šã—ã¾ã™ï¼ˆç ‚æ¼ ã®å ´åˆã¯æ°´ä½ã«è¨­å®šã—ã¾ã™ï¼‰ã€‚

注æ„:建物ã€ç”£æ¥­ã€æ¤ç‰©ã«ã¯ã€ãれãžã‚Œã®ä½œè€…ã«ã‚ˆã£ã¦ç‰¹å®šã®æ°—候ãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ã¾ã™ã€‚

砂漠気候 - 陿°´é‡ãŒéžå¸¸ã«å°‘ãªãã€æ°—æ¸©ãŒæ¥µç«¯ã«é«˜ã„。木ãŒã»ã¨ã‚“ã©ãªã„。平å¦ãªé¢¨æ™¯ã€‚

熱帯気候 - 赤é“周辺ã®éžä¹¾ç‡¥åœ°åŸŸã®å…¸åž‹çš„ãªä¾‹ã§ã€æµ·é¢ã‚„低地ã§ã¯å¸¸ã«é«˜æ¸©ã€‚

地中海性気候 - é©åº¦ã«å¤‰åŒ–ã®ã‚る湿気ãŒå¤šã„天候。

温暖気候 - ç†±å¸¯ã¨æ¥µåœ°ã®é–“ã«ä½ç½®ã—ã€å¤©å€™ã‚’変化ã«å¯Œã‚€å¤©å€™ã€‚

ツンドラ気候 - ä½Žæ¸©ã€æ¥µå† ã®å‘¨ç¸ã€‚

氷雪(高山)気候 - 乾燥ã—ãŸæ°—候ã€å†¬ã¯å¯’ã„。

ãã®ä»–ã®ã‚ªãƒ—ション

æœ¨ï¼æ£®ã‚’作æˆã—ãªã„ - ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€SimutransãŒæ¨¹æœ¨ã‚’æã‹ãªããªã‚Šã¾ã™ã€‚木ã¯ã€æç”»ã™ã‚‹ã®ã«CPUã§æ™‚é–“ã‚’è¦ã—ã¾ã™ã€‚性能ãŒä½Žã„CPUや容é‡ã®å°‘ãªã„RAMã®PCã§ã¯ã“ã®ã‚ªãƒ—ションを使用ã—ã¦ãã ã•ã„。

湖を作æˆã™ã‚‹ - ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€SimutransãŒåœ°é¢ã®ã„ãã¤ã‹ã®å‡¹ã¿ã‚’æ°´ã§æº€ãŸã—ã¦ãƒžãƒƒãƒ—å…¨ä½“ã«æ¹–を作るã“ã¨ãŒã§ãã¾ã™ã€‚

æ²³å·ã®æ•° - 地形図ã«ç”Ÿæˆãƒ»ä½¿ç”¨ã§ãã‚‹æ²³å·ã®æœ€å¤§æ•°ã‚’設定ã—ã¾ã™ã€‚ç‹­ã„å·ã¯ã€ãƒœãƒ¼ãƒˆã‚„船ãŒèˆªè¡Œã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。

æ²³å·ã®é•·ã• 最短 - ãƒžãƒƒãƒ—ä¸Šã®æ²³å·ã®æœ€å°ã®é•·ã•を設定ã—ã¾ã™ï¼ˆã‚¿ã‚¤ãƒ«å˜ä½ã§ï¼‰ã€‚

æ²³å·ã®é•·ã• 最長 - ãƒžãƒƒãƒ—ä¸Šã®æ²³å·ã®æœ€å¤§ã®é•·ã•を設定ã—ã¾ã™ï¼ˆã‚¿ã‚¤ãƒ«å˜ä½ã§ï¼‰ã€‚

simutrans-124.3/simutrans/text/ja/color.txt000066400000000000000000000020031474050137200210300ustar00rootroot00000000000000プレイヤーã®è‰²ã€€ãƒ˜ãƒ«ãƒ—

プレイヤーã®è‰²ãƒ€ã‚¤ã‚¢ãƒ­ã‚°

プレイヤーã®è‰²ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ã¯ã‚ãªãŸã®ä¼šç¤¾ã®è‰²ã‚’é¸æŠžã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
ã“ã“ã§é¸ã‚“ã è‰²ã¯ã€åˆ—車や建築物ãªã©ã®è‰²ã¨ãªã‚Šã¾ã™ã€‚

プレイヤーã®è‰²ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯ã‚²ãƒ¼ãƒ ã‚ªãƒ—ションã‹ã‚‰é–‹ãã¾ã™ã€‚

色ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ãã®è‰²ã‚’会社ã®è‰²ã«ã—ã¾ã™ã€‚
色ã®å¤‰æ›´ã¯ç›´ã¡ã«å映ã•れã¾ã™ã€‚

プレイヤー会社ã®åˆæœŸã®è‰²ã¯ãƒ©ã‚¤ãƒˆãƒ–ルーã§ã™ã€‚
å…¨ã¦ã®ç‰©ãŒã“ã“ã§é¸ã‚“ã è‰²ã«ãªã‚‹ã‚ã‘ã§ã¯ãªãã€è‰²ãŒå¤‰ã‚らãªã„物もã‚りã¾ã™ã€‚

{Tips: ライãƒãƒ«ä¼šç¤¾ã®è‰²ã‚’変更ã™ã‚‹å ´åˆã€æœ€åˆã« ライãƒãƒ«ä¼šç¤¾ä¸€è¦§ã¾ãŸã¯P+(プレイヤーã®å¤‰æ›´)ã‹ã‚‰ æ“作ã™ã‚‹ä¼šç¤¾ã‚’切り替ãˆã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚}

simutrans-124.3/simutrans/text/ja/convoi.txt000066400000000000000000000100611474050137200212120ustar00rootroot00000000000000乗り物一覧 ヘルプ

乗り物一覧

乗り物リストã«ã¯æƒ…å ±ãŒè¡¨ç¤ºã•れã€ç•°ãªã‚‹è»Šä¸¡ã‚’フィルタリングã—ã¦ãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã™ã‚‹ãŸã‚ã®æ“作機能ãŒã‚りã¾ã™ï¼ˆè»Šä¸¡ã¯ç¨¼åƒä¸­ã®è»Šä¸¡ã¾ãŸã¯è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®çµ„ã¿åˆã‚ã›ã§æ§‹æˆã•れã¦ã„ã¾ã™ï¼‰ã€‚

é–‹ãã«ã¯ã€ä¸€è¦§è¡¨ã®ä¹—り物一覧ツールをクリックã™ã‚‹ã‹ã€[V]を押ã—ã¾ã™ã€‚乗り物一覧ã«ã¯4ã¤ã®ã‚ªãƒ—ションボタンãŒã‚りã€2ã¤ã¯ä¸€è¦§è¡¨ã®ä¸­ã®ã‚¢ã‚¤ãƒ†ãƒ ã®é †ç•ªã‚’決ã‚ã‚‹ã®ã«ä½¿ç”¨ã—ã€2ã¤ã¯ä¸€è¦§ã«è¡¨ç¤ºã•れる内容ã®è¨­å®šã‚’変更ã™ã‚‹ã®ã«ä½¿ç”¨ã—ã¾ã™ã€‚
下ã®ãƒœã‚¿ãƒ³ã¯ã€ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æ¡ä»¶ã«åˆã†è»Šä¸¡ã®ãƒªã‚¹ãƒˆã§ã™ã€‚

{ヒント: 車両ãŒè¡¨ç¤ºã•れãªã„å ´åˆã¯ã€ãƒ•ィルターオプションを変更ã—ã¦ãã ã•ã„。一覧ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒä¸€éƒ¨ã—ã‹è¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€ä¹—り物一覧をre-size表示ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒãƒ¼ã‚’使ã£ã¦ä¸€è¦§ã‚’スクロールã—ã¦ãã ã•ã„。}

オプションボタンをクリックã™ã‚‹ã¨ã€ã‚ªãƒ—ションãŒåˆ‡ã‚Šæ›¿ã‚り(オプションボタンã®åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã€ãƒ•ィルタ設定コントロールãŒé–‹ãã¾ã™ã€‚

ä¸¦ã³æ›¿ãˆ: 2ã¤ã®ã‚ªãƒ—ションボタンã§ã€ä¸€è¦§ã«è¡¨ç¤ºã•れる車両ã®é †ç•ªã‚’決定ã—ã¾ã™ã€‚

- タイプ 輸é€å½¢æ…‹åˆ¥ã®é †ç•ªï¼ˆé“路車両ã€é‰„é“車両ã€èˆ¹èˆ¶ã€èˆªç©ºæ©Ÿã®æ˜‡é †ï¼‰
- åå‰ å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸåå‰ã§ã€è‹±æ•°å­—ã§ASCIIコードã®é †ç•ªï¼šå¤§æ–‡å­—ãŒå°æ–‡å­—ã®å‰ã«ä¸¦ã³ã¾ã™ï¼ˆæ¨™æº–ã§ã¯ã€è»Šä¸¡ç”¨ã«è³¼å…¥ã¾ãŸã¯çµ„ç«‹ã¦ãŸæœ€åˆã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®ãƒ¡ãƒ¼ã‚«ãƒ¼ã§ã™ï¼‰ã€‚
- åŽç›Š 利益(åŽå…¥ã‹ã‚‰å–¶æ¥­è²»ç”¨ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼‰ã®é †ç•ªã€‚
- è­˜åˆ¥ç•ªå· è»Šä¸¡å›ºæœ‰ã®ID番å·ï¼ˆæ¨™æº–ã§ã¯ã€è»Šä¸¡ãŒæœ€åˆã«è³¼å…¥ã•れãŸã¨ãã€ã¾ãŸã¯è»Šåº«ã§çµ„ç«‹ã¦ã‚‰ã‚ŒãŸã¨ãã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã€è»Šä¸¡æƒ…å ±ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«è¡¨ç¤ºã•れã¦ã„ã¾ã™ï¼‰ã®é †ç•ªã€‚

- 昇順 / é™é † 一覧ã®é †åºã‚’逆ã«ã—ã¾ã™ã€‚

フィルター: 2ã¤ã®ã‚ªãƒ—ションボタンã¯ã€ãƒªã‚¹ãƒˆã®é¸æŠžåŸºæº–ã®ã‚ªãƒ³/オフを切り替ãˆã€åŸºæº–を変更ã™ã‚‹ãŸã‚ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’行ã„ã¾ã™ã€‚

- 有効 / 無効 クリックã™ã‚‹ã¨ã€ä¸€è¦§è¡¨ã®è»Šä¸¡ã®ãƒ•ィルタæ¡ä»¶ãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ã€‚

- 設定 フィルタæ¡ä»¶ã‚’変更ã™ã‚‹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãŒé–‹ãã¾ã™ã€‚

記載ã•れã¦ã„る項目をクリックã™ã‚‹ã¨ã€ãã®è»Šä¸¡ã®è©³ç´°æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

å„車両ã«è¨˜è¼‰ã•れã¦ã„ã‚‹é …ç›®ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

識別番å·: コンボイã®å›ºæœ‰ã®ID番å·ï¼ˆãƒ‡ãƒ•ォルトã§ã¯ã€ã‚³ãƒ³ãƒœã‚¤ãŒæœ€åˆã«è³¼å…¥ã•れãŸã¨ãã€ã¾ãŸã¯è»Šåº«ã§çµ„ç«‹ã¦ã‚‰ã‚ŒãŸã¨ãã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã€è»Šä¸¡æƒ…å ±ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«è¡¨ç¤ºã•れã¾ã™ï¼‰ã€‚

åå‰ ãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ã¾ã™ï¼ˆæ¨™æº–ã§ã¯ã€ã‚³ãƒ³ãƒœã‚¤ãŒè³¼å…¥ã¾ãŸã¯çµ„ã¿ç«‹ã¦ã‚‰ã‚ŒãŸã¨ãã®æœ€åˆã®è»Šä¸¡ã®ãƒ¡ãƒ¼ã‚«ãƒ¼ã§ã™ï¼‰ã€‚

åŽç›Šã¯ã€åˆ©ç›Šï¼ˆç™ºç”Ÿã—ãŸåŽå…¥ã‹ã‚‰ç™ºç”Ÿã—ãŸé‹å–¶è²»ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚

路線: 割り当ã¦ã‚‰ã‚ŒãŸè·¯ç·šã‚’示ã—ã€è»Šä¸¡ãŒè»Šåº«ã«ã‚ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚

グラフィックスã¯ã€æ§‹æˆã¨ç¾åœ¨ã®è² è·ãƒ¬ãƒ™ãƒ«ã‚’示ã—ã¦ã„ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/convoi_filter.txt000066400000000000000000000055041474050137200225650ustar00rootroot00000000000000乗り物ã®ä¸€è¦§ãƒ•ィルター ヘルプ

乗り物ã®ä¸€è¦§ãƒ•ィルター

乗り物ã®ä¸€è¦§ãƒ•ィルターã«ã¯ã€ä¹—り物一覧ã«è¡¨ç¤ºã™ã‚‹è»Šä¸¡ã‚’決定ã™ã‚‹ã‚ªãƒ—ションãŒã‚りã¾ã™ã€‚

乗り物一覧ã®è¨­å®šã‚’クリックã™ã‚‹ã¨ã€ä¹—り物ã®ä¸€è¦§ãƒ•ィルターãŒè¡¨ç¤ºã•れã¾ã™ã€‚

オプションボタンã¯ã€ãƒ•ã‚£ãƒ«ã‚¿ã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒæœ‰åйãªã¨ãã«ä¹—り物一覧ã«è¡¨ç¤ºã™ã‚‹è»Šä¸¡ã‚’é¸æŠžã—ã¾ã™ã€‚設定ã•ã‚ŒãŸæ¡ä»¶ã«åˆè‡´ã—ãŸè»Šä¸¡ã®ã¿ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

四角ã„ボタンをクリックã—ã¦ãƒ•ã‚£ãƒ«ã‚¿ã®æ¡ä»¶ã‚’設定ã—ã¾ã™ï¼ˆãƒœã‚¿ãƒ³ã¯é¸æŠžã•ã‚Œã‚‹ã¨æŠ¼ã—è¾¼ã¾ã‚Œã¾ã™ï¼‰ã€‚

åå‰ãƒ•ィルター: 車両ã®åå‰ã§é¸æŠžã—ã¾ã™ã€‚ã“れを使ã†ã«ã¯ã€ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦é¸æŠžã—ã€åå‰ãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¦å¿…è¦ãªåå‰ã‚’正確ã«å…¥åŠ›ã—ã¾ã™ï¼ˆã‚ªãƒ—ションã¯å¤§æ–‡å­—ã¨å°æ–‡å­—を区別ã—ã¾ã™ï¼‰ã€‚

タイプフィルター: é¸æŠžã•れãŸå ´åˆã€è¼¸é€æ‰‹æ®µã®ç¨®é¡žåˆ¥ã«è»Šä¸¡ã‚’リストアップã—ã¾ã™ã€‚ã“れを使用ã™ã‚‹ã«ã¯ã€ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦é¸æŠžã—ã€è¼¸é€ã®ç¨®é¡žï¼ˆé“è·¯ã€é‰„é“ã€æ°´è·¯ã€ç©ºè·¯ï¼‰ã‚’クリックã—ã¾ã™ã€‚

特殊フィルター: selects Convoys to list by following criteria (click on button to select, then click on): 一覧ã«è¼‰ã›ã‚‹è»Šä¸¡ã‚’ä»¥ä¸‹ã®æ¡ä»¶ã§é¸æŠžã—ã¾ã™ï¼ˆãƒœã‚¿ãƒ³ã‚’クリックã—ã¦é¸æŠžã—ã€ä»¥ä¸‹ã®ä¸­ã‹ã‚‰ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„)。
- ルートãªã— - 次ã®ç›®çš„地ã¸ã®ãƒ‘スãŒè¦‹ã¤ã‹ã‚‰ãªã„。
- スケジュールãªã— - ルートãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ãªã„。
- åŽå…¥ãªã— - 利益ãŒå‡ºã¦ã„ãªã„。
- 入庫中 - 車庫ã«ä¿ç®¡ä¸­ã®ã‚‚ã®ã€‚
- 路線ãªã— - 路線ãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ãªã„。

旅客ï¼è²¨ç‰©ãƒ•ィルター: 旅客ï¼è²¨ç‰©ãƒ•ィルター: ã•ã¾ã–ã¾ãªå•†å“や乗客を輸é€ã™ã‚‹èƒ½åŠ›ã«ã‚ˆã£ã¦è»Šä¸¡ã‚’é¸æŠžã—ã¾ã™ã€‚åå‰ã®æ¨ªã«ã‚るボタンをクリックã—ã¦ã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã—ã¾ã™ã€‚スライダーãƒãƒ¼ã‚’使ã£ã¦ä¸€è¦§ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’スクロールã—ã¾ã™ã€‚オプションã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- å…¨é¸æŠž - ã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã—ã¾ã™ã€‚
- 全解除 - ã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã—ã¾ã›ã‚“。
- å転 - ç¾åœ¨é¸æŠžã•れã¦ã„る項目をå転ã•ã›ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/convoidetail.txt000066400000000000000000000043731474050137200224060ustar00rootroot00000000000000車両ã®è©³ç´°ã€€ãƒ˜ãƒ«ãƒ—

車両ã®è©³ç´°

車両ã®è©³ç´° 車両(é‹ç”¨ä¸­ã®è»Šä¸¡ã¾ãŸã¯è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®çµ„ã¿åˆã‚ã›ï¼‰ã®è©³ç´°æƒ…報をæä¾›ã—ã€è»Šä¸¡ã‚’ã™ãã«å£²å´ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

車両ã®è©³ç´°ã¯ã€è»Šä¸¡æƒ…å ±ã®è©³ç´°ã‚ªãƒ—ションã®ãƒœã‚¿ãƒ³ã‹ã‚‰é–‹ãã“ã¨ãŒã§ãã¾ã™ã€‚
å…¨ã¦ã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆãŒè¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€è»Šä¸¡ã®è©³ç´°ã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒãƒ¼ã‚’使ã£ã¦ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¾ã™ã€‚

車両ã®è©³ç´°ã®ä¸Šéƒ¨ã«ã¯ä»¥ä¸‹ã®æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

出力: 車両ã®é¦¬åŠ› (全車両ã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®åˆè¨ˆãƒ‘ワー)。

売å´ä¾¡æ ¼ï¼šè»Šä¸¡ãŒå£²å´ã•れãŸå ´åˆã«å—ã‘å–る金é¡ï¼ˆè»Šä¸¡ã®è³¼å…¥ä¾¡æ ¼ã‹ã‚‰æ¸›ä¾¡å„Ÿå´è²»ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼‰ã€‚

警告:車両を直ã¡ã«å£²å´ã™ã‚‹ã«ã¯ã€å£²å´ãƒ¢ãƒ¼ãƒ‰ã‚ªãƒ—ションボタンをクリックã—ã¦ãã ã•ã„。ãれ以上ã®ç¢ºèªã¯å¿…è¦ã‚りã¾ã›ã‚“。車両ã¯ã‚²ãƒ¼ãƒ ã‹ã‚‰å‰Šé™¤ã•れã€ãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ã®æ®‹é«˜ã«å£²å´ä¾¡æ ¼ãŒåŠ ç®—ã•れã¾ã™ã€‚

車両ã®è©³ç´°ã«ã¯ã€è»Šä¸¡ã«æ­è¼‰ã•れã¦ã„ã‚‹ã™ã¹ã¦ã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆãŒãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã•れã¦ã„ã¾ã™ã€‚
å„è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®æƒ…å ±ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- 車両ユニットã®ã‚°ãƒ©ãƒ•ィック: 車両ユニットã®ç”»åƒï¼ˆè»Šåº«ã§ã‚‚使用ã•れã¾ã™ï¼‰ã€‚
- 製造年月: 製造ã•ã‚ŒãŸæœˆã¨å¹´ã€ãã—ã¦å¹´ä»£è¨­å®šã§éŠã¶å ´åˆã¯å°Žå…¥æ—¥ã€‚
- 売å´ä¾¡æ ¼: 売å´ã—ãŸéš›ã«å—ã‘å–る金é¡
- 出力: 発電é‡ï¼ˆãƒ¢ãƒ¼ã‚¿ãƒ¼ä»˜ã車両ユニットã«ã‚ˆã‚‹ï¼‰
- 摩擦: ç¾åœ¨ã®æ‘©æ“¦ãƒ¬ãƒ™ãƒ«ï¼ˆæ¶ˆè€—度åˆï¼‰
- 最大åŽç›Š: ã“ã®è»Šä¸¡ãŒè¼¸é€ã™ã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã®ç¨®é¡žã«å¿œã˜ã¦ã€ã“ã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆãŒå¯èƒ½ãªæœ€å¤§åŽå…¥
- items on board: ã“ã®è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆãŒç¾åœ¨é‹ã‚“ã§ã„るアイテムã®é‡ã¨ç›®çš„地。

simutrans-124.3/simutrans/text/ja/convoiinfo.txt000066400000000000000000000214701474050137200220740ustar00rootroot00000000000000車両情報 ヘルプ

車両情報

車両情報ã¯ã€å•†å“や乗客を輸é€ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã•れる車両(é‹è¡Œä¸­ã®è»Šä¸¡ã¾ãŸã¯è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®çµ„ã¿åˆã‚ã›ï¼‰ã«é–¢ã™ã‚‹æƒ…報をæä¾›ã—ã¾ã™ã€‚
ã“ã®æƒ…å ±ã«ã¯è»Šä¸¡ãŒé‹ã¶ã‚¢ã‚¤ãƒ†ãƒ ãŒè¨˜è¼‰ã•れã¦ãŠã‚Šã€è»Šä¸¡ã®è©³ç´°æƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸã‚Šã€è»Šä¸¡ã‚’売å´ã—ãŸã‚Šã€ã‚²ãƒ¼ãƒ ãƒ“ューã§è»Šä¸¡ã‚’追跡ã—ãŸã‚Šã€è»Šä¸¡ã®åå‰ã‚„スケジュールを変更ã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

車両ã¯ã€å°‘ãªãã¨ã‚‚1ã¤ã®å‹•力付ã車両ユニットã¨ã€ãれã«ä»˜éšã™ã‚‹ãƒˆãƒ¬ãƒ¼ãƒ©ãƒ¼ã‚„è²¨è»Šã§æ§‹æˆã•れã¾ã™ã€‚
車両ã®ä¾‹ã¨ã—ã¦ã¯ã€é¦¬è»Šã‚’引ã馬ã®ç·¨æˆã€ãƒ†ãƒ³ãƒ€ãƒ¼ï¼ˆçµ¦æ°´è»Šï¼‰ã¨è²¨è»ŠãŒé€£çµã•れãŸå‹•力機関車ã€ãƒã‚¹ã€ãƒãƒ³ã€ãƒˆãƒ¬ãƒ¼ãƒ©ãƒ¼ã‚’連çµã—ãŸãƒˆãƒ©ãƒƒã‚¯ã€é€£çµã•れãŸè·¯é¢é›»è»Šã€èˆ¹èˆ¶ã€ãƒãƒ¼ã‚¸ã‚’引ãタグボートã€èˆªç©ºæ©Ÿãªã©ãŒã‚りã¾ã™ã€‚
車両ã¯ã€è¼¸é€ã®ç¨®é¡žã«å¿œã˜ã¦è»Šåº«ã‹ã‚‰çµ„ç«‹ã¦ã¦è³¼å…¥ã—ã¾ã™ã€‚
{ヒント: 車両ã«ã¯ã€ç·¨æˆã•ã‚Œã‚‹è»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®æ•°ã«ä¸Šé™ãŒã‚りã¾ã™ã€‚列車ã¯24å°ã€é“路車両ã¯4å°ã¾ã§ã§ã™ã€‚}

ゲームビュー上ã®è»Šä¸¡ã‚’調査ツールã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã‹ã€ä¹—り物一覧や路線編集ã«è¡¨ç¤ºã•れã¦ã„る車両をクリックã™ã‚‹ã¨ã€è»Šä¸¡æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
車両情報ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«ã¯ã€è»Šä¸¡ã®åå‰ã¨å›ºæœ‰ã®ID番å·ãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆã“れらã«ã¤ã„ã¦ã¯å¾Œè¿°ã—ã¾ã™ï¼‰ã€‚
車両情報ã«ã¯å剿¬„ã€ãƒŸãƒ‹ãƒ“ューã€è»Šä¸¡ã«é–¢ã™ã‚‹æƒ…å ±ã€ã‚ªãƒ—ションボタンã€ç¾åœ¨æ­è¼‰ã•れã¦ã„ã‚‹å…¨ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã®ä¸€è¦§ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ï¼ˆå…¨ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒè¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯è»Šä¸¡æƒ…å ±ã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã‚’使ã£ã¦ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¦ãã ã•ã„)。

車両情報ã®ä¸Šéƒ¨ã«è¡¨ç¤ºã•れる情報ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

内部ID(車体番å·ï¼‰: 車両を特定ã§ãã‚‹ID番å·ã‚’表示ã—ã¾ã™ï¼ˆæ¨™æº–ã§ã¯è»Šä¸¡ãŒæœ€åˆã«è³¼å…¥ã•れãŸã‹ã€è»Šåº«ã§çµ„ç«‹ã¦ã‚‰ã‚ŒãŸã¨ãã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã™ï¼‰ã€‚

- åå‰ï¼šè»Šä¸¡ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸåå‰ã‚’表示ã—ã¾ã™ï¼ˆæ¨™æº–ã§ã¯ã€è»Šä¸¡ã®ãŸã‚ã«æœ€åˆã«è³¼å…¥ã¾ãŸã¯è»Šåº«ã§çµ„ã¿ç«‹ã¦ã‚‰ã‚ŒãŸè»Šä¸¡ãƒ¦ãƒ‹ãƒƒãƒˆã®ãƒ¡ãƒ¼ã‚«ãƒ¼åã«ãªã£ã¦ã„ã¾ã™ï¼‰ã€‚
å剿¬„をクリックã—ã¦æ–°ã—ã„åå‰ã‚’入力ã™ã‚‹ã¨ã€è»Šä¸¡ã®åå‰ãŒå¤‰æ›´ã•れã¾ã™ã€‚

- 速度: ç¾åœ¨ã®é€Ÿåº¦ãŒkm/hã§è¡¨ç¤ºã•れã¾ã™ã€‚
括弧内ã«ã¯è»Šä¸¡ã®æœ€å¤§å¯èƒ½é€Ÿåº¦ãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆè»Šä¸¡ã®ä¸­ã§æœ€ã‚‚é…ã„車両ユニットã«ã‚ˆã£ã¦æ±ºå®šã•れã¾ã™ï¼‰ã€‚
緑色ã®é€²è¡Œçжæ³ãƒãƒ¼ã¯ã€æœ€é«˜é€Ÿåº¦ã«å¯¾ã™ã‚‹ç¾åœ¨ã®é€Ÿåº¦ã‚’示ã—ã¦ã„ã¾ã™ã€‚

- åŽå…¥: ç¾åœ¨ã®ã‚²ãƒ¼ãƒ æš¦å¹´ã«ãŠã‘る車両ã®åˆ©ç›Šï¼ˆç™ºç”Ÿã—ãŸåŽå…¥ã‹ã‚‰é‹è¡Œè²»ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼‰ã€‚
車両ã®é‹è¡Œè²»ã¯ã€1ゲームマスã‚ãŸã‚Šã® Hajoクレジットã§ï¼ˆï¼‰å†…ã«è¨˜è¼‰ã—ã¦ã„ã¾ã™ã€‚

- é‡é‡: 車両ã®ç¾åœ¨ã®ç·é‡é‡ã¨æ­è¼‰ã‚¢ã‚¤ãƒ†ãƒ ã®é‡é‡ï¼ˆå˜ä½ï¼šãƒˆãƒ³ï¼‰ã€‚
()内ã¯ç¾åœ¨ã®é‹æ¬ç‰©ã®é‡é‡ã§ã™ã€‚
緑色ã®é€²æ—ãƒãƒ¼ã¯ã€å•†å“や乗客をé‹ã¶ãŸã‚ã«ä½¿ç”¨ã•れã¦ã„る容é‡ã®å‰²åˆã‚’示ã—ã¾ã™ã€‚
黄色ã®ãƒãƒ¼ã¯ã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã§è¨­å®šã•れãŸå¾…機レベル(車両ãŒç™ºè»Šã™ã‚‹ãŸã‚ã«å¿…è¦ãªæœ€ä½Žé™ã®è·ç‰©ã¨ä¹—客ã®é‡ï¼‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚
{ヒント: 経路上ã®ã™ã¹ã¦ã®è»Šä¸¡ã®å¾…機レベルを設定ã¾ãŸã¯å¤‰æ›´ã™ã‚‹ã«ã¯ã€è·¯ç·šç·¨é›†ã¾ãŸã¯Depot Controlsã®Update Lineオプションボタンを使用ã—ã¾ã™ã€‚割り当ã¦ã‚‰ã‚ŒãŸçµŒè·¯ä¸Šã®ä»–ã®è»Šä¸¡ã§ã¯ãªãã€ã‚る特定ã®è»Šä¸¡ã®å¾…機レベルを設定ã¾ãŸã¯å¤‰æ›´ã™ã‚‹ã«ã¯ã€è»Šä¸¡æƒ…å ±ã¾ãŸã¯Depot Controlsã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã®ã‚ªãƒ—ションボタンを使用ã—ã¾ã™ã€‚}

- 目的地: コンボイã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ä¸Šã®æ¬¡ã®åœè»Šé§…ã¾ãŸã¯ä¸­ç¶™åœ°ç‚¹ã€‚
緑色ã®é€²è¡Œçжæ³ãƒãƒ¼ã¯ã€è»Šä¸¡ãŒæ¬¡ã®ç›®çš„地ã¾ã§é€²ã‚“ã§ã„ã‚‹ã“ã¨ã‚’示ã—ã¾ã™ã€‚

- 指定路線: ã“ã®è»Šä¸¡ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸè·¯ç·šã€‚三角å°ã¯ 路線作æˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§è·¯ç·šã‚’é–‹ãã¾ã™ã€‚(路線ãŒå‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ã‚‹å ´åˆã®ã¿è¡¨ç¤ºã•れã¾ã™ã€‚)

- ミニビュー ミニビューã«ã¯ã“ã®è»Šä¸¡ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ミニビューをクリックã™ã‚‹ã¨ã‚²ãƒ¼ãƒ ãƒ“ューãŒã“ã®è»Šä¸¡ã‚’ç”»é¢ä¸­å¤®ã«è¡¨ç¤ºã—ã¾ã™ã€‚

車両情報ã®ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’é–‹ã„ãŸã‚Šã€ä»¥ä¸‹ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’é¸æŠžã—ãŸã‚Šã—ã¾ã™ã€‚

スケジュール: コントロールを開ãã€è»Šä¸¡ãŒé€²è¡Œã™ã‚‹ãŸã‚ã«å¿…è¦ãªçµŒè·¯ã‚„最å°ã®è·ç‰©ã‚„乗客ã®é‡ã‚’変更ã—ã¾ã™ã€‚

車庫ã¸: 車両を最寄りã®é©åˆ‡ãªè»Šåº«ã¸é€ã‚Šã¾ã™ã€‚é‹ã‚“ã§ã„ãŸã‚¢ã‚¤ãƒ†ãƒ ã¯å¤±ã‚れã¾ã™ãŒã€è»Šåº«ã¾ã§ã®è¼¸é€ã®ãŸã‚ã®åŽå…¥ãŒå¾—られã¾ã™ã€‚
入庫中ã¯ã€è»Šä¸¡ã¯ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã¨å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸçµŒè·¯ã‚’ä¿æŒã—ã¾ã™ã€‚

追跡: ã“ã®ãƒœã‚¿ãƒ³ãŒæŠ¼ã—è¾¼ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€è»Šä¸¡ã¨ä¸€ç·’ã«ã‚²ãƒ¼ãƒ ãƒ“ューを移動ã—ã¾ã™ã€‚
ã“ã®ã‚ªãƒ—ションã®é¸æŠžã‚’解除ã™ã‚‹ã«ã¯ã€å†åº¦ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã‹ã€ãƒ¡ã‚¤ãƒ³ãƒžãƒƒãƒ—上ã§å·¦ã‚¯ãƒªãƒƒã‚¯ã—ã¾ã™ã€‚

グラフ: グラフ:ã“ã®ã‚ªãƒ—ションボタンをクリックã™ã‚‹ã¨ã€è»Šä¸¡æƒ…å ±ã®ã‚°ãƒ©ãƒ•(グラフãŒè¡¨ç¤ºã•れã¦ã„ã‚‹ã¨ãã¯ãƒœã‚¿ãƒ³ãŒæŠ¼ã—è¾¼ã¾ã‚Œã¦ã„ã¾ã™ï¼‰ãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ã€‚
グラフオプションãŒé¸æŠžã•れã¦ã„ã‚‹å ´åˆã€ã‚°ãƒ©ãƒ•ã¯éŽåŽ»12ヶ月間ã®çµ±è¨ˆï¼ˆx軸)を表示ã—ã¾ã™ã€‚
グラフオプションã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€é¸æŠžã•ã‚ŒãŸæƒ…å ±ãŒã‚°ãƒ©ãƒ•ã«è¡¨ç¤ºã•れã¾ã™ï¼ˆã‚ªãƒ—ションãŒé¸æŠžã•れるã¨ã€ãƒœã‚¿ãƒ³ãŒæŠ¼ã—è¾¼ã¾ã‚ŒãŸçŠ¶æ…‹ã«ãªã‚Šã¾ã™ï¼‰ã€‚
グラフ上ã®ç·šã®è‰²ã¯ã€ã‚°ãƒ©ãƒ•オプションã®ãƒœã‚¿ãƒ³ã®è‰²ã«å¯¾å¿œã—ã¦ã„ã¾ã™ã€‚ãã®è©³ç´°ã¯ä»¥ä¸‹ã®ã¨ãŠã‚Šã§ã™ã€‚
- 空席ï¼ç©ºè·ã¯ã€è»Šä¸¡å†…ã®æœªä½¿ç”¨ã‚¹ãƒšãƒ¼ã‚¹ã‚’示ã—ã¾ã™ã€‚
- 輸é€å®Ÿç¸¾ã¯ã€è¼¸é€ã—ãŸè²¨ç‰©ã€ä¹—客ã€éƒµä¾¿ç‰©ã®æ•°ã‚’表ã—ã¾ã™ã€‚
- åŽå…¥ã¯ã€è¼¸é€ã«ã‚ˆã£ã¦å¾—られãŸåŽå…¥ã‚’示ã—ã¾ã™ã€‚
- é‹è¡Œè²»ã¯ã€è¼¸é€ä¸­ã«è»Šä¸¡ãŒè² æ‹…ã—ãŸè²»ç”¨ï¼ˆçµŒè²»ï¼‰ã‚’示ã—ã¾ã™ã€‚
- 利益ã¨ã¯ã€è¼¸é€ã«ã‚ˆã£ã¦å¾—られãŸåˆ©ç›Šï¼ˆã€ŒåŽå…¥ã€ã‹ã‚‰ã€Œé‹å–¶è²»ã€ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼‰ã‚’示ã—ã¾ã™ã€‚

詳細をクリックã™ã‚‹ã¨ã€è»Šä¸¡ã®è©³ç´°ãŒè¡¨ç¤ºã•れã€è©³ç´°æƒ…å ±ã¨è»Šä¸¡ã‚’ã™ãã«å£²å´ã™ã‚‹ã‚ªãƒ—ションãŒè¡¨ç¤ºã•れã¾ã™ã€‚

ä¹—è»Šä¸­ã®æ—…客ï¼è²¨ç‰©ã®ä¸¦ã³æ›¿ãˆ: 車両ãŒç¾åœ¨é‹ã‚“ã§ã„るアイテムをリストアップã—ã¾ã™ã€‚
表示ã•れる情報ã¯ã€é‹ã°ã‚ŒãŸé‡ã€è»Šä¸¡ã®å®šå“¡ã€ã‚¢ã‚¤ãƒ†ãƒ ã®ç¨®é¡žã€æœ€çµ‚ç›®çš„åœ°ã€æ¬¡ã®ä¹—æ›ãˆé§…(経由地)ãªã©ã§ã™ã€‚
ã‚ªãƒ—ã‚·ãƒ§ãƒ³ãƒœã‚¿ãƒ³ï¼ˆé¸æŠžã™ã‚‹ã¨åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã¯ã€é‹ã°ã‚ŒãŸã‚¢ã‚¤ãƒ†ãƒ ï¼ˆä¹—客ã€éƒµä¾¿ã€è²¨ç‰©ï¼‰ã®ä¸€è¦§ã‚’以下ã®ã¨ãŠã‚Šä¸¦ã³æ›¿ãˆã¾ã™ã€‚
- 目的地 : 最終目的地ã®åœç•™æ‰€ã®åå‰ã§ã‚¢ã‚¤ãƒ†ãƒ ã‚’ä¸¦ã¹æ›¿ãˆã¾ã™ã€‚ASCIIコード順ã«è‹±æ•°å­—ã§ä¸¦ã¹ã¾ã™ï¼ˆå¤§æ–‡å­—ãŒå°æ–‡å­—よりå‰ã«æ¥ã¾ã™ï¼‰ã€‚
- 経由(詳細): 最åˆã®ä¹—りæ›ãˆé§…ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸåå‰ã§é‹ã°ã‚Œã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã‚’ã€ASCIIコード順ã«è‹±æ•°å­—ã§ä¸¦ã¹ã¾ã™ï¼ˆå¤§æ–‡å­—ãŒå°æ–‡å­—より先)。
- 経由(金é¡ï¼‰: 最åˆã®ä¹—りæ›ãˆé§…ã«å‘ã‹ã£ãŸæ•°é‡ã§é‹ã°ã‚Œã‚‹ã‚‚ã®ã®é †ã§ä¸¦ã¹ã¾ã™ã€‚
- æ•°é‡: é‹ã°ã‚Œã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã‚’æ•°é‡ã®é™é †ã§ä¸¦ã¹ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/curiosity_build.txt000066400000000000000000000052701474050137200231340ustar00rootroot00000000000000ランドマーク(歴å²çš„建築物)建設ツール ヘルプ

ランドマーク(歴å²çš„建築物)建設ツール

ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯4ã¤ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã«åˆ†ã‹ã‚Œã¦ã„ã¾ã™ã€‚
· 左上ã¯ã€åˆ©ç”¨å¯èƒ½ãªå»ºç‰©ã®é¸æŠžãƒªã‚¹ãƒˆã§ã™ã€‚
· 左下ã«ã¯ã€é¸æŠžã—ãŸå»ºç‰©ã®ç”»åƒãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· å³ä¸Šã«ã¯ã€ã„ãã¤ã‹ã®ã‚ªãƒ—ションãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚
· å³ä¸‹ã«ã¯ã€é¸æŠžã—ãŸå»ºç‰©ã‚„å²è·¡ãªã©ã«é–¢ã™ã‚‹æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

é¸æŠžãƒªã‚¹ãƒˆ

é¸æŠžãƒªã‚¹ãƒˆã«ã¯ã€å³ä¸Šã§æŒ‡å®šã—ãŸã‚ªãƒ—ション(都市型施設ã€éƒŠå¤–型施設ã€ãƒ¢ãƒ‹ãƒ¥ãƒ¡ãƒ³ãƒˆï¼‰ã§åˆ©ç”¨ã§ãã‚‹ã€ã™ã¹ã¦ã®ç‰¹åˆ¥ãªå»ºç‰©ã‚„ランドマークãŒè¡¨ç¤ºã•れã¾ã™ã€‚
2ã¤ã®ã‚¿ãƒ–ãŒã‚りã€å‘¼ã³ç‰©ã®å»ºç‰©ã®è­˜åˆ¥æ–¹æ³•を変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
· 日本語å: 指定ã•れãŸè¨€èªžã§å»ºç‰©ã®åå‰ã‚’表示ã—ã¾ã™ã€‚指定ã—ãŸè¨€èªžã®ç¿»è¨³ãŒãªã„å ´åˆã¯ã€ã‚ªãƒ–ジェクトåãŒä½¿ç”¨ã•れã¾ã™ã€‚
· オブジェクト: 建物タイプã®Simutrans内部オブジェクトåを表示ã—ã¾ã™ã€‚

文字ã®è‰²ã«ã¯æ¬¡ã®ã‚ˆã†ãªæ„味ãŒã‚りã¾ã™ã€‚
· é’ã„æ–‡å­— 都市型施設ã¯ã€éƒ½å¸‚部ã«ä½œã‚‰ãªã‘れã°ãªã‚‰ãªã„
· ç·‘ã®æ–‡å­— 郊外型施設ã¯ã€ç”°èˆŽã«ä½œã‚‰ãªã‘れã°ãªã‚‰ãªã„
· 黒文字 モニュメントã¯ã€ä¸€åº¦ã—ã‹å»ºè¨­ã§ããªã„

オプション

· 気候æ¡ä»¶ã‚’無視ã™ã‚‹: ã“ã®ã‚ªãƒ—ションã¯ã€æ§˜ã€…ãªå»ºç‰©ã‚¿ã‚¤ãƒ—ã«é–¢é€£ã™ã‚‹æ°—候ã®åˆ¶é™ã‚’無効ã«ã—ã¾ã™ã€‚
· 年代設定を使用: é¸æŠžä¸€è¦§ã«ã¯ã€ç¾åœ¨ã®Simutransã®æš¦å¹´ã«åˆ©ç”¨å¯èƒ½ãªå»ºç‰©ã®ã¿ãŒå«ã¾ã‚Œã¾ã™ã€‚
· 旧型を表示: é¸æŠžä¸€è¦§ã‚’æ‹¡å¼µã—ã¦ã€ç¾åœ¨ã®Simutransã®æš¦å¹´ã«å»ƒæ­¢ã•れãŸå»ºç‰©ã‚‚å«ã‚€ã‚ˆã†ã«ã—ã¾ã™ã€‚
· 都市型施設: é¸æŠžä¸€è¦§ã«éƒ½å¸‚ã®å所旧跡(観光地)ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· 郊外型施設: é¸æŠžä¸€è¦§ã«åœ°æ–¹ã®å所旧跡ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· モニュメント: é¸æŠžä¸€è¦§ã«ãƒ¢ãƒ‹ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆè¨˜å¿µç¢‘)ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· å‘ã: é¸æŠžã—ãŸå»ºç‰©ãŒæ§˜ã€…ãªè§’度ã‹ã‚‰è¦‹ã‚‹ã“ã¨ãŒã§ãã‚‹å ´åˆã€ã“ã“ã§ç‰¹å®šã®å‘ãï¼ˆãƒ“ãƒ¥ãƒ¼ï¼‰ã‚’é¸æŠžã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚左下ã®ç”»åƒã¯ã“ã‚Œã‚’åæ˜ ã—ã¦å¤‰åŒ–ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒãƒ©ãƒ³ãƒ€ãƒ ã«è¨­å®šã•れã¦ã„ã‚‹å ´åˆã¯ã€å»ºç‰©ã®å‘ãã¯ãƒ©ãƒ³ãƒ€ãƒ ã«ä½¿ç”¨ã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/curiositylist_filter.txt000066400000000000000000000051051474050137200242130ustar00rootroot00000000000000忉€æ—§è·¡ä¸€è¦§ã€€ãƒ˜ãƒ«ãƒ—

忉€æ—§è·¡ä¸€è¦§

忉€æ—§è·¡ä¸€è¦§ã«ã¯ã€ä¹—客や郵便物ã®ç›®çš„地ã¨å‡ºç™ºåœ°ã®ä¸¡æ–¹ã«ãªã£ã¦ã„ã‚‹ã™ã¹ã¦ã®è¦³å…‰åæ‰€ã®æƒ…å ±ãŒã‚りã¾ã™ã€‚

忉€æ—§è·¡ä¸€è¦§ã‚’é–‹ãã«ã¯ã€ä¸€è¦§è¡¨å所旧跡一覧をクリックã—ã¾ã™ã€‚
{ヒント: 一覧ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒéƒ¨åˆ†çš„ã«ã—ã‹è¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€å所旧跡一覧ã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã‚’使ã£ã¦ä¸€è¦§ã‚’スクロールã—ã¦ãã ã•ã„。ï½

ä¸¦ã³æ›¿ãˆ: 忉€æ—§è·¡ã®è¡¨ç¤ºé †ã‚’決ã‚るオプションãŒã‚りã¾ã™ã€‚
ボタンをクリックã™ã‚‹ã¨ã€ã‚ªãƒ—ションãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ï¼ˆã‚ªãƒ—ションボタンã®åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã€‚

- åå‰: åå‰ã®ã‚¢ãƒ«ãƒ•ァベット順ã«è¡¨ç¤ºã•れã¾ã™ã€‚
- 旅客度 乗客や郵便物ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—度ã§ä¸¦ã³ã¾ã™ã€‚

- 昇順 / é™é † 一覧ã®é †åºã‚’逆ã«ã—ã¾ã™ã€‚

忉€æ—§è·¡ä¸€è¦§ã«æŽ²è¼‰ã•れã¦ã„る項目をクリックã™ã‚‹ã¨ã€ãã®è¦³å…‰åœ°ã«ã¤ã„ã¦ã®è©³ç´°æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
{ヒント: 詳細情報ã®ä¸­ã®è¦³å…‰åœ°ã®å†™çœŸã‚’クリックã™ã‚‹ã¨ã€ãã®è¦³å…‰åœ°ã«ã‚²ãƒ¼ãƒ ãƒ“ューãŒç§»å‹•ã—ã¾ã™ã€‚ï½

ãれãžã‚Œã®åæ‰€æ—§è·¡ã«æŽ²è¼‰ã•れã¦ã„ã‚‹é …ç›®ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

ステータス・カラーãƒãƒ¼ ã®è‰²ã¯ã€å所旧跡ã®è©•価を示ã—ã¾ã™ã€‚
- 黄色: é§…ã®é›†å®¢ã‚¨ãƒªã‚¢ã«å…¥ã£ã¦ã„ãªã„。
- 緑色: 旅客用ã®é§…ãŒã‚りã¾ã™ã€‚
- é’色: 郵便用ã®é§…ãŒã‚りã¾ã™ã€‚
- é’ç·‘: 旅客ã¨éƒµä¾¿ç”¨ã®é§…ãŒã‚りã¾ã™ã€‚
- 橙色: 関連ã™ã‚‹é§…ãŒæ··é›‘ã—ã¦ã„ã¾ã™ã€‚
- 赤色: 関連ã™ã‚‹ã™ã¹ã¦ã®åœç•™æ‰€ãŒæ··é›‘ã—ã¦ã„ã¾ã™ã€‚

建物ã®ç”»åƒ ã¯ã€ãれãŒè¡—ã®å所旧跡ã§ã‚ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚

åå‰ åæ‰€æ—§è·¡ã®åå‰ã§ã™ã€‚

æ‹¬å¼§å†…ã®æ—…客度ã¯ã€ä¹—客や郵便ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—を示ã™å€¤ã§ã™ã€‚

{ヒント: 最é©ãªã‚µãƒ¼ãƒ“スをæä¾›ã™ã‚‹ãŸã‚ã«ã¯ã€å所旧跡全体ãŒ1ã¤ã¾ãŸã¯è¤‡æ•°ã®åœç•™æ‰€ã®é›†å®¢ã‚¨ãƒªã‚¢å†…ã«ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ï½

simutrans-124.3/simutrans/text/ja/depot.txt000066400000000000000000000063451474050137200210420ustar00rootroot00000000000000車庫

車庫ダイアログ

 車庫ダイアログã§ã¯ã€ãれãžã‚Œåˆ—車ã€è»Šä¸¡ã€èˆ¹èˆ¶ã®è³¼å…¥ã‚„スケジュール設定
を行ãˆã¾ã™ã€‚ã“ã“ã§ã¯åˆ—車ã®å ´åˆã§è§£èª¬ã—ã¾ã™ãŒã€è»Šä¸¡ã‚„船舶ã«ãŠã„ã¦ã‚‚æ“作
方法ã¯åŒã˜ã§ã™ã€‚

ã€€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®æœ€ä¸Šéƒ¨ã«ã¯ã€ç¾åœ¨ç·¨æˆä¸­ã®åˆ—è»Šã®æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚テキス
トフィールドã«ã¯åˆ—車åãŒè¡¨ç¤ºã•れã¾ã™ã€‚ã“ã“ã«æ–‡å­—を入力ã™ã‚‹ã“ã¨ã§ã€åˆ—車
åを変更ã§ãã¾ã™ã€‚ ォボタン㨠サボタンã§ã€ç·¨æˆå¯¾è±¡ã®åˆ—車を変更ã§ãã¾ã™ã€‚
ã“ã“ã§ã€Œæ–°ã—ã„ç·¨æˆã€ã‚’é¸æŠžã™ã‚‹ã¨ã€æ–°è¦ã®åˆ—車ã®ç·¨æˆã«ãªã‚Šã¾ã™ã€‚

 ãã®ä¸‹ã«ã¯ã€ç·¨æˆä¸­ã®åˆ—車をæ“作ã™ã‚‹ãŸã‚ã®æ¬¡ã®ãƒœã‚¿ãƒ³ãŒã‚りã¾ã™ã€‚

スタート - ç·¨æˆä¸­ã®åˆ—車ã®é‹è¡Œã‚’é–‹å§‹ã—ã¾ã™ã€‚é‹è¡Œã‚’é–‹å§‹ã™ã‚‹ãŸã‚ã«ã¯ã€
ã‚らã‹ã˜ã‚スケジュールãŒè¨­å®šã•れã¦ã„ãªã‘れã°ã„ã‘ã¾ã›ã‚“。
ç·¨æˆè§£é™¤ - ç¾åœ¨ã®ç·¨æˆã‚’解体ã—ã¾ã™ã€‚解体ã•れãŸç·¨æˆã®è»Šä¸¡ã¯ã‚¹ãƒˆãƒƒã‚¯ã•れã€
ä»–ã®ç·¨æˆã«çµ„ã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚
å£²å´ - ç¾åœ¨ã®ç·¨æˆã‚’æ§‹æˆã—ã¦ã„る車両を全ã¦å£²å´ã—ã¾ã™ã€‚ç¾åœ¨ã®å£²å´ä¾¡æ ¼ã¯
「売å´ä¾¡æ ¼ã€ã«ç¤ºã•れã¦ãŠã‚Šã€è³¼å…¥æ™‚ã‹ã‚‰ã®æ™‚é–“ã®çµŒéŽã«ä¼´ã£ã¦æ¸›å°‘ã—ã¦ã„ãã¾ã™ã€‚

 ダイアログã®ä¸­æ®µéƒ¨åˆ†ã«ã¯ã€è³¼å…¥ã§ãる車両ã®ä¸€è¦§ãŒè¡¨ç¤ºã•れã¦ã„ã¾ã™ã€‚è»Šä¸¡ã¯æ©Ÿé–¢
車ã¨å®¢è»Šãƒ»è²¨è»Šã«åˆ†ã‹ã‚Œã¦ãŠã‚Šã€ã€Œæ©Ÿé–¢è»Šã€ã‚¿ãƒ–ã€ã€Œè²¨è»Šãƒ»å®¢è»Šã€ã‚¿ãƒ–ã§è¡¨ç¤ºã‚’切り替
ãˆã‚‰ã‚Œã¾ã™ã€‚車両ã®ç”»åƒã«ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ã‚’é‡ã­ã‚‹ã¨ã€ãã®è»Šä¸¡ã®æƒ…å ±ãŒãƒ€ã‚¤ã‚¢ãƒ­ã‚°ä¸‹
部ã«è¡¨ç¤ºã•れã¾ã™ã€‚クリックã™ã‚‹ã¨ã€ãã®è»Šä¸¡ã‚’購入ã—ã€ç¾åœ¨ã®ç·¨æˆã«çµ„ã¿è¾¼ã¿ã¾ã™ã€‚

 å„車両ã®ä¸‹ã«ã‚る色付ãã®ãƒãƒ¼ã¯ã€ãã®è»Šä¸¡ã‚’ç¾åœ¨ã®ç·¨æˆã«çµ„ã¿è¾¼ã‚€ã“ã¨ãŒ
出æ¥ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¦ã„ã¾ã™ã€‚ç·‘ã®è»Šä¸¡ã¯ã€ç¾åœ¨ã®ç·¨æˆã«çµ„ã¿è¾¼ã‚€ã“ã¨ãŒå‡º
æ¥ã¾ã™ã€‚赤ã®è»Šä¸¡ã¯ã€ç¾åœ¨ã®ç·¨æˆã«ã¯çµ„ã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥ã¾ã›ã‚“。緑ã¨é»„色ã®
æ··ã˜ã£ãŸè»Šä¸¡ã¯ã€ç¾åœ¨ã®ç·¨æˆã«çµ„ã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥ã¾ã™ãŒã€ãã®ç·¨æˆã‚’完æˆã•
ã›ã‚‹ãŸã‚ã«ã¯ã€ã•らã«ä»–ã®è»Šä¸¡ã‚’購入ã—ãªã‘れã°ãªã‚‰ãªã„ã“ã¨ã‚’示ã—ã¦ã„ã¾ã™ã€‚
後部機関車ãŒå¿…è¦ãªåˆ—車ãªã©ãŒã€ã“ã®è¡¨ç¤ºã«ãªã‚Šã¾ã™ã€‚

 車両ã®å·¦ä¸Šã«ã‚ã‚‹æ•°å­—ã¯ã€ãã®è»Šä¸¡ã®ã‚¹ãƒˆãƒƒã‚¯ãŒã‚ã‚‹ã“ã¨ã‚’示ã—ã¦ã„ã¾ã™ã€‚
ストックã®ã‚る車両ã¯ã€ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã“ã¨ã§ç¾åœ¨ã®ç·¨æˆã«çµ„ã¿è¾¼ã‚€ã“ã¨ãŒå‡ºæ¥
ã¾ã™ã€‚

 å³å´ã«ã‚る「車両ã€ãƒœã‚¿ãƒ³ã§ã¯ã€è³¼å…¥ã—ãŸè»Šä¸¡ã‚’ç¾åœ¨ã®ç·¨æˆã®ã©ã®ä½ç½®ã«çµ„
ã¿è¾¼ã‚€ã‹ã‚’変更ã§ãã¾ã™ã€‚「追加ã€ã®çŠ¶æ…‹ã§ã¯ã€ç¾åœ¨ã®ç·¨æˆã®æœ€å¾Œéƒ¨ã«è¿½åŠ ã—
ã¾ã™ã€‚「先頭ã¸ã€ã§ã¯ã€ç¾åœ¨ã®ç·¨æˆã®å…ˆé ­ã«çµ„ã¿è¾¼ã¿ã¾ã™ã€‚「売å´ã€ã§ã¯ã€è»Š
両ã®è³¼å…¥ã§ã¯ãªãã€ã‚¹ãƒˆãƒƒã‚¯ã•れã¦ã„る車両ã®å£²å´ãƒ¢ãƒ¼ãƒ‰ã«ãªã‚Šã¾ã™

simutrans-124.3/simutrans/text/ja/display.txt000066400000000000000000000026141474050137200213670ustar00rootroot00000000000000表示オプションヘルプ

表示オプションヘルプ

 ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ã¯ã€è¡¨ç¤ºã«é–¢ã™ã‚‹æ§˜ã€…ãªè¨­å®šã‚’ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚
ã€€ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚

æ˜Žã‚‹ã• ï¼ ç”»é¢ã‚’明るãã—ãŸã‚Šã€æš—ãã—ãŸã‚Šã—ã¾ã™ã€‚
色åˆã„ ï¼ å‹•ä½œã—ã¾ã›ã‚“。
ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã®æ—©ã• ï¼ ã“ã®å€¤ãŒå¤§ãã„ã»ã©ã€ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ãŒæ—©ããªã‚Šã¾ã™ã€‚

スクロール方å‘ã®é€†è»¢ ï¼ ãƒžã‚¦ã‚¹ã‚’å‹•ã‹ã™æ–¹å‘ã¨ã€ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã®æ–¹å‘ã®å¯¾å¿œãŒ
逆ã«ãªã‚Šã¾ã™ã€‚例ãˆã°ã€å³ã«å‹•ã‹ã™ã¨å·¦ã«ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¾ã™ã€‚
歩行者を表示ã™ã‚‹ ï¼ ç”ºã«æ­©è¡Œè€…を生æˆã—ã¦è¡¨ç¤ºã™ã‚‹ã‹ã©ã†ã‹ã‚’設定ã—ã¾ã™ã€‚
コンピュータã®å‡¦ç†èƒ½åŠ›ãŒä¸è¶³ã—ã¦ã„ã‚‹å ´åˆã¯ã€ã“ã®ã‚ªãƒ—ションをオフã«ã—ã¦
ãã ã•ã„。
å¤œã¯æš—ãã™ã‚‹ ï¼ ï¼‘æ—¥ã®æ˜¼ã¨å¤œã®ã‚µã‚¤ã‚¯ãƒ«ã«ã‚ˆã£ã¦ç”»é¢ã®æ˜Žã‚‹ã•を変ãˆã¾ã™ã€‚
オンã«ã™ã‚‹ã¨ã€å¤œã«ã¯ç¶ºéº—ãªå¤œæ™¯ãŒç¾ã‚Œã¾ã™ã€‚

 ダイアログã®ä¸‹ã®éƒ¨åˆ†ã¯ã€ã‚³ãƒ³ãƒ”ュータã®ãƒ‘フォーマンスã«é–¢ã™ã‚‹æƒ…報を示
ã—ã¦ã„ã¾ã™ã€‚
æ³¨æ„ ï¼ ã“ã®æƒ…å ±ã¯ã€ãƒã‚°å ±å‘Šã®éš›ã‚„パフォーマンスå‘上ã®ç‚ºã«ã€ãŠèžãã™
ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/enlarge_map.txt000066400000000000000000000006501474050137200221720ustar00rootroot00000000000000マップ拡張ヘルプ

マップ拡張

マップã¯å³ã‹ä¸‹ã«å‘ã‘ã¦æ‹¡å¼µã§ãã¾ã™ã€‚ã‚‚ã—å·¦ã¾ãŸã¯ä¸Šã«æ‹¡å¼µã—ãŸã„å ´åˆã¯ã€ã¾ãšãƒžãƒƒãƒ—を回転ã•ã›ã¦ã‹ã‚‰ã€æ‹¡å¼µã‚’行ã„ã€å†ã³å›žè»¢ã•ã›ã¦å‘ãを戻ã—ã¾ã™ã€‚
æ‹¡å¼µã•れãŸãƒžãƒƒãƒ—ã®ãƒ—レビューãŒã€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®å³ä¸Šã«è¡¨ç¤ºã•れã¾ã™ã€‚dow.

simutrans-124.3/simutrans/text/ja/factorylist_filter.txt000066400000000000000000000054251474050137200236350ustar00rootroot00000000000000産業一覧 ヘルプ

産業一覧

産業一覧ã«ã¯ã€ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã«ç™»å ´ã™ã‚‹ã™ã¹ã¦ã®ç”£æ¥­ï¼ˆå•†å“ã®ä¾›çµ¦è€…ã¨æ¶ˆè²»è€…ï¼‰ã®æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

産業一覧を開ãã«ã¯ã€ä¸€è¦§è¡¨ã§ç”£æ¥­ä¸€è¦§ã‚’クリックã—ã¾ã™ã€‚
{ヒント: 一覧ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒä¸€éƒ¨ã—ã‹è¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€ç”£æ¥­/工場リストã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã‚’使ã£ã¦ä¸€è¦§ã‚’スクロールã—ã¦ãã ã•ã„。ï½

ä¸¦ã³æ›¿ãˆ: リストアップã•れãŸç”£æ¥­ã®é †åºã‚’決定ã™ã‚‹ã‚ªãƒ—ションãŒã‚りã¾ã™ã€‚
ボタンをクリックã™ã‚‹ã¨ã€ã‚ªãƒ—ションãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ï¼ˆã‚ªãƒ—ションボタンã®åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã€‚

- 産業åã¯ã€åå‰ã®ã‚¢ãƒ«ãƒ•ァベット順ã«ä¸¦ã³ã¾ã™ã€‚
- 供給 供給ä¿ç®¡èƒ½åŠ›ã®å®¹é‡é †ã€‚
- è£½å“ è£½å“ä¿ç®¡èƒ½åŠ›ã®å®¹é‡é †ã€‚
- 生産 生産能力ã«ã‚ˆã‚‹ç”£æ¥­é †ã€‚
- Rating orders Industry by status-colour-bar (see below). ステータスカラーãƒãƒ¼ã«ã‚ˆã‚‹ç”£æ¥­é †ï¼ˆä¸‹è¨˜å‚照)。
- 電力 供給電力ã«ã‚ˆã‚‹ç”£æ¥­é †ã€‚

- 昇順 / é™é †ã¯ä¸€è¦§ã®é †åºã‚’逆ã«ã—ã¾ã™ã€‚

ç”£æ¥­ä¸€è¦§ã«æŽ²è¼‰ã•れã¦ã„る項目をクリックã™ã‚‹ã¨ã€ãã®ç”£æ¥­ã®è©³ç´°ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
å„産業ã«ã¯ä»¥ä¸‹ã®é …ç›®ãŒã‚りã¾ã™ã€‚

ステータスカラーãƒãƒ¼ カラー(色)ã¯ãã®ç”£æ¥­ã®ç¨¼åƒçжæ³ã‚’示ã—ã¾ã™ï¼ˆç”£æ¥­æƒ…å ±ã§ã‚‚使ã‚れã¾ã™ï¼‰ã€‚
- 白色: 供給を必è¦ã¨ã—ãªã„。
- 黄色: è¼¸é€æ‰‹æ®µã§ã¤ãªãŒã£ã¦ã„ã‚‹ãŒã€ç”£æ¥­ã®ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã§ã¯ä¾›çµ¦ä¸è¶³ã€‚
- 緑色: 最é©ãªç¨¼åƒçŠ¶æ…‹ã€‚
- 橙色: 稼åƒä¸­ã ãŒã€æ”¹å–„ã®ä½™åœ°ã‚り。
- 赤色: 稼åƒä¸­ã ãŒã€ç”£æ¥­ã®ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã®ä¸€éƒ¨ãŒä¾›çµ¦éŽå‰°ã€‚

赤色ã®ç¨²å¦»ãƒžãƒ¼ã‚¯ã¯ã€å¤‰é›»æ‰€ã‚’使ã£ã¦é›»æ°—を供給ã—ã¦ã„る産業ã®å ´åˆã«è¡¨ç¤ºã•れã¾ã™ã€‚

産業å: ãã®ç”£æ¥­ã®åå‰ã€‚

括弧内ã¯3ã¤ã®å€¤ã‚’表ã—ã¦ã„ã¾ã™ã€‚
ç¾åœ¨ã®ä¾›çµ¦é‡: 処ç†å¯èƒ½ãªçŠ¶æ…‹ã§ä¿ç®¡ã•れã¦ã„る原料ã®åœ¨åº«é‡ã€‚
ç¾åœ¨ã®ç”Ÿç”£é‡: 出è·ã™ã‚‹æº–å‚™ãŒã§ãã¦ã„る生産é‡ã€‚
生産能力: ãã®ç”£æ¥­ã®ç”Ÿç”£èƒ½åŠ›ï¼ˆ1ヶ月ã«ç”Ÿç”£ã•れる製å“ã®æœ€å¤§é‡ï¼‰ã€‚

simutrans-124.3/simutrans/text/ja/finances.txt000066400000000000000000000113551474050137200215120ustar00rootroot00000000000000財務 ヘルプ

財務

財務ウィンドウã§ã¯ã€ãƒ—レーヤー会社ã®è²¡å‹™çжæ³ã‚’確èªã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

メインビューã®ä¸Šéƒ¨ã«ã‚ã‚‹ãŠé‡‘ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã‹ã€[f] を押ã™ã‹ã€ãƒ—レーヤーダイアログã§ãƒ—レーヤーã®åå‰ã‚’クリックã™ã‚‹ã¨è¡¨ç¤ºã•れã¾ã™ã€‚

貨幣å˜ä½ã¯Hajoクレジットã§ã€ç¾åœ¨ã¨éŽåŽ»ã®æœˆãƒ»å¹´ã”ã¨ã«è¡¨ç¤ºã•れã¾ã™ã€‚ã‚°ãƒ©ãƒ•ã®æ™‚間軸を変更ã™ã‚‹ã«ã¯ã€å¯¾å¿œã™ã‚‹ã‚¿ãƒ–をクリックã—ã¦ãã ã•ã„。
- 年:年間ã®å€¤ã‚’表示ã—ã¾ã™ã€‚
- 月:月å˜ä½ã®å€¤ã‚’表示ã—ã¾ã™ã€‚

グラフã¯ã€Y軸をé‡ã€X軸を時間ã¨ã—ã¦è¡¨ç¤ºã—ã¾ã™ã€‚è¤‡æ•°ã®æ›²ç·šã‚’åŒæ™‚ã«è¡¨ç¤ºã™ã‚‹ã“ã¨ãŒã§ãã€ã‚°ãƒ©ãƒ•上ã®ç‚¹ã«ã‚«ãƒ¼ã‚½ãƒ«ã‚’é‡ã­ã‚‹ã¨ãƒ„ールãƒãƒƒãƒ—ã«æ•°å€¤ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

å³ä¸Šã®æœ¬ç¤¾ã‚’建設ã™ã‚‹ãƒœã‚¿ãƒ³ã‚’押ã™ã¨ã€ä¼šç¤¾ã®æœ¬ç¤¾ã‚’建設ã—ãŸã‚Šã€ã‚¢ãƒƒãƒ—グレードã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼ˆã‚°ãƒ©ãƒ•ィックãŒãƒ‘ãƒƒã‚¯ã‚»ãƒƒãƒˆã§æä¾›ã•れã¦ã„ã‚‹å ´åˆï¼‰ã€‚本社ã¯é«˜ãƒ¬ãƒ™ãƒ«ã®ã‚¢ãƒˆãƒ©ã‚¯ã‚·ãƒ§ãƒ³ã¨ã—ã¦æ©Ÿèƒ½ã—ã€ã„ãã¤ã‹ã®ã‚·ãƒŠãƒªã‚ªã§ã¯å¿…è¦ã«ãªã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。


値(åå‰ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã‚°ãƒ©ãƒ•ã§è©³ç´°ã‚’表示)ã¯ã€ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

輸é€å®Ÿç¸¾ï¼ˆãƒˆãƒªãƒƒãƒ—) - 移動ã—ãŸã™ã¹ã¦ã®ã‚‚ã®ã®æ•°ï¼ˆä¹—客ã€éƒµä¾¿ã€å•†å“ã‚’æ•°ãˆã¾ã™ï¼‰ã€‚乗りæ›ãˆã¯1区間ã«ã¤ã1回カウントã•れã¾ã™ã€‚

åŽå…¥ï¼ˆè»Šä¸¡åŽå…¥ï¼‰ï¼šæ—…客ã€å•†å“ã€éƒµä¾¿ã®è¼¸é€ã«ã‚ˆã‚‹ç·åŽå…¥ã€‚

é‹è¡Œè²»ï¼ˆè¼¸é€ã‚³ã‚¹ãƒˆï¼‰ - 輸é€ä¸­ã«ã™ã¹ã¦ã®è¼¸é€æ©Ÿé–¢ãŒè¢«ã‚‹ç·ã‚³ã‚¹ãƒˆã€‚
{Tips: 車両ã®1kmã‚ãŸã‚Šã®é‹è¡Œã‚³ã‚¹ãƒˆã¯ã€è»Šåº«ã‚„車両情報ã§ç¢ºèªã§ãã¾ã™ã€‚}

ç¶­æŒè²» - 輸é€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ç¶­æŒã«ã‹ã‹ã‚‹ç·è²»ç”¨ã€‚
{Tips: ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’ç¶­æŒã™ã‚‹ãŸã‚ã®æœˆã”ã¨ã®ã‚³ã‚¹ãƒˆï¼ˆè²¡å‹™ã®å³ã«è¡¨ç¤ºã•れã¦ã„ã‚‹ç¶­æŒè²»ï¼ˆæœˆï¼‰ï¼‰ã¯ã€ã‚²ãƒ¼ãƒ ã®æš¦æœˆã®çµ‚ã‚りã«å·®ã—引ã‹ã‚Œã¾ã™ã€‚}

通行料(é“路通行料) - 外国ã®é“路を使ã£ã¦è¼¸é€è»Šä¸¡ã‚’走行ã•ã›ã‚‹å ´åˆã€ã‚³ã‚¹ãƒˆãŒç™ºç”Ÿã™ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚ä»–ã®ãƒ—レイヤーã®é“路を使用ã—ã¦ã„ã‚‹å ´åˆã¯ã€æ”¯æ‰•ã‚ãªã‘れã°ãªã‚Šã¾ã›ã‚“。ã—ã‹ã—ã€ã‚ãªãŸãŒéžå¸¸ã«è‰¯ã„é“路接続をæä¾›ã—ã¦ã„ã‚‹å ´åˆã€ã‚ãªãŸã¯ä»–ã®äººã‹ã‚‰ã‚‚åŽå…¥ã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

é€é›»ç·š - 高出力ã®é€é›»ã«ã‚ˆã‚‹é›»æ°—ã®è²©å£²ã‹ã‚‰å¾—られるåŽå…¥ã§ã™ã€‚

é‹å–¶åˆ©ç›Š - 輸é€ã€é“路通行料ã€é€é›»ã«ã‚ˆã‚‹åˆ©ç›Šã‹ã‚‰ã€ç¶­æŒè²»ã¨é‹å–¶è²»ã‚’å·®ã—引ã„ãŸã‚‚ã®ï¼ˆä¸Šè¨˜ã™ã¹ã¦ã®åˆè¨ˆï¼‰ã€‚

購入費(新è¦è»Šä¸¡ï¼‰ - 車両ã®è³¼å…¥ãŠã‚ˆã³è²©å£²ã«ã‹ã‹ã‚‹æ”¯å‡ºãŠã‚ˆã³åŽå…¥ã€‚

建設費(建設ç¾å ´ï¼‰-交通網ã€é€ æˆã€é«˜é›»åŠ›é€é›»ç·šã®å»ºè¨­ã€å‰Šé™¤ï¼å–り壊ã—ã‚„ãã®ä»–ã®é™¤åŽ»ãƒ„ãƒ¼ãƒ«ã‚’ä½¿ç”¨ã—ãŸçµŒè·¯ï¼ˆç·šè·¯ã€é“è·¯ã€é‹æ²³ã€æ»‘走路)ã®å»ºè¨­ã«ã‹ã‹ã‚‹ç·è²»ç”¨ã€‚

粗利益(キャッシュフロー) - ç·åŽå…¥ï¼ˆä¸Šè¨˜ã®ã™ã¹ã¦ã‚’åˆè¨ˆã—ãŸã‚‚ã®ï¼‰ã€‚


財務ウィンドウå³åŠåˆ†ã®ç¸¦åˆ—ã«ã¯ã€4ç¨®é¡žã®æ•°å€¤ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ã“れらã¯åˆè¨ˆé¡ï¼ˆç´¯ç©å€¤ï¼‰ã§ã™ã€‚

ç¾é‡‘ - 建設や車両購入ã«ä½¿ç”¨ã§ãã‚‹ç¾é‡‘å£åº§ã®æ®‹é«˜ã§ã™ï¼ˆã‚²ãƒ¼ãƒ ãƒ“ューã®ãƒœãƒˆãƒ ãƒãƒ¼ä¸­å¤®ã«ã‚‚表示ã•れã¾ã™ï¼‰:

資産 - カレンダーã®å‰æœˆæœ«æ™‚点ã§ã®ã€ãƒ—レーヤー会社所有ã®ã™ã¹ã¦ã®è»Šä¸¡ã®ç·ä¾¡é¡ã§ã™ã€‚
{ヒント: 車両ã®ç¾åœ¨ã®è²©å£²ä¾¡æ ¼ã¯è»Šä¸¡ã® 車両ã®è©³ç´° ã¾ãŸã¯è»Šä¸¡ãŒè»Šåº«ï¼ˆæ©Ÿé–¢åº«ï¼‰ã«ã‚ã‚‹ã¨ãã«è¦‹ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚}

利益率 (%) - 売上高ã«å¯¾ã™ã‚‹å–¶æ¥­åˆ©ç›Šã®å‰²åˆã§ã™ã€‚

純資産 - ç¾é‡‘残高ã«è³‡ç”£ã‚’加ãˆãŸã‚‚ã®ã€‚会社ã®ä¾¡é¡ã‚’表ã—ã¦ã„ã¾ã™ã€‚純資産ãŒãƒžã‚¤ãƒŠã‚¹ã«ãªã‚‹ã¨ã€ä¼šç¤¾ã¯å€’産ã—ã€ã‚²ãƒ¼ãƒ ã«è² ã‘ã¦ã—ã¾ã„ã¾ã™ã€‚

{ヒント: ゲーム内ã®ä¸€éƒ¨ã®è²»ç”¨ã€ã‚²ãƒ¼ãƒ é–‹å§‹æ™‚ã®åŽç›ŠçŽ‡ã‚„è²¡å‹™ã¯ã€simuconf.tab ã§å¤‰æ›´ã§ãã¾ã™}。

シナリオ情報

シナリオをプレイã™ã‚‹å ´åˆã«ã¯ã€ã‚·ãƒŠãƒªã‚ªã®ã‚´ãƒ¼ãƒ«ã¨é€²æ—率ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/general.txt000066400000000000000000000065011474050137200213360ustar00rootroot00000000000000Simutransç·åˆãƒ˜ãƒ«ãƒ—

ç·åˆãƒ˜ãƒ«ãƒ—

ã“れã¯ä¸»ãªãƒ˜ãƒ«ãƒ—ファイルã®ä¸€è¦§ã§ã™ï¼ˆã™ã¹ã¦ã§ã¯ã‚りã¾ã›ã‚“)。
※å°ã®ã‚‚ã®ã¯é•·ã„é–“ã€æ›´æ–°ã•れã¦ã„ã¾ã›ã‚“。ç¾åœ¨ã®å†…容ã¨å¤§ããç•°ãªã‚‹å ´åˆãŒã‚りã¾ã™ã€‚ 英語ã®ã‚‚ã®ã¯ã€æ—¥æœ¬èªžãƒ˜ãƒ«ãƒ—ãŒã¾ã ã‚りã¾ã›ã‚“。

キーボード

ゲームオプション
※ゲームオプション
※言語
※プレイヤーã®è‰²
※表示設定
※サウンド
※ライãƒãƒ«ä¼šç¤¾
※ゲームã®å†é–‹
※ゲームã®ä¿å­˜
※新ã—ã„マップã®ä½œæˆ
気候ã®è¨­å®š
地形データ読ã¿è¾¼ã¿
高度ãªè¨­å®š

メインメニュー
※設定をé¸ã¶
※マップ
調査ツール
※スロープツール
※鉄é“ツール
・※信å·ï¼æ¨™è­˜ã®é–“隔設定
モノレールï¼ãƒªãƒ‹ã‚¢ãƒ„ール
市電ï¼è»½ä¾¿é‰„é“ツール
※é“路ツール
※船舶ツール
航空機ツール
特別建築物建設ツール
撤去ï¼å–り壊ã—
Game Edit Tools

一覧表
ライãƒãƒ«ä¼šç¤¾ä¸€è¦§
路線編集
一覧表
・駅一覧
・・駅一覧フィルター
・乗り物一覧
・・乗り物一覧フィルター
・※町一覧
・貨物一覧
・産業一覧
ãƒ»åæ‰€æ—§è·¡ä¸€è¦§
※メッセージ表
財務(財務一覧)

ãã®ä»–ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°
â€»ã‚²ãƒ¼ãƒ ã®æƒ…報ウィンドウ
※パスワード設定ウィンドウ
è»Šä¸¡ã®æƒ…å ±
・車両ã®è©³ç´°
※車庫ダイアログ
※スケジュールダイアログ
※駅情報ダイアログ
・※駅情報詳細ダイアログ
※街ã®è©³ç´°
ç”£æ¥­ã®æƒ…å ±
äº¤é€šä¿¡å·æ©Ÿã®æƒ…å ±
指定座標ã¸ç§»å‹•

simutrans-124.3/simutrans/text/ja/goods_filter.txt000066400000000000000000000076031474050137200224050ustar00rootroot00000000000000貨物一覧 ヘルプ

貨物一覧

貨物一覧ã«ã¯ã€ã‚²ãƒ¼ãƒ å†…ã§è¼¸é€å¯èƒ½ãªã•ã¾ã–ã¾ãªã‚¢ã‚¤ãƒ†ãƒ ã¨ã€ãれらを輸é€ã™ã‚‹ã“ã¨ã§å¾—られるåŽå…¥ã®æƒ…å ±ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚

é–‹ãã«ã¯ã€ä¸€è¦§è¡¨ã§è²¨ç‰©ä¸€è¦§ãƒ„ールをクリックã™ã‚‹ã‹ã€[G] を押ã—ã¾ã™ã€‚

ゲーム内ã§è¼¸é€å¯èƒ½ãªã‚¢ã‚¤ãƒ†ãƒ ã®ãƒªã‚¹ãƒˆã«ã¯ã€å—ã‘å–ã£ãŸåŽå…¥ã€é€Ÿåº¦ãƒœãƒ¼ãƒŠã‚¹ï¼ˆ%)ã€è²¨ç‰©ã®ã‚«ãƒ†ã‚´ãƒªãƒ¼ã€é‡é‡ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
{ヒント: 一覧ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒä¸€éƒ¨ã—ã‹è¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€è²¨ç‰©ä¸€è¦§ã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã§ä¸€è¦§ã‚’スクロールã—ã¦ãã ã•ã„。ï½

速度ボーナス: 一覧ã«è¨˜è¼‰ã•れã¦ã„ã‚‹åŽç›Šã‚’å¾—ã‚‹ãŸã‚ã«å¿…è¦ãªã€ã•ã¾ã–ã¾ãªè¼¸é€ã‚¿ã‚¤ãƒ—ã®è»Šä¸¡ã®å¹³å‡æœ€å¤§é€Ÿåº¦ãŒè¡¨ç¤ºã•れã¾ã™ã€‚平凿œ€é«˜é€Ÿåº¦ãŒè¡¨ç¤ºã•れã¦ã„る速度よりも速ã„å ´åˆã€ã„ãã¤ã‹ã®ã‚¢ã‚¤ãƒ†ãƒ ã¯ã‚ˆã‚Šå¤šãã®åŽç›Šã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã™ãŒã€é…ã„å ´åˆã¯åŽç›ŠãŒå°‘ãªããªã‚Šã¾ã™ã€‚
年代設定を有効ã«ã™ã‚‹ã¨ã€æ™‚é–“ã®çµŒéŽã¨ã¨ã‚‚ã«é€Ÿåº¦ã®å€¤ãŒå¤‰åŒ–ã™ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚ã“ã®å¤‰æ›´ã¯é€šå¸¸ã€ã‚ˆã‚Šé«˜é€Ÿã¾ãŸã¯çµŒæ¸ˆçš„ãªè»Šä¸¡ã®å°Žå…¥ã«ä¼´ã£ã¦è¡Œã‚れã¾ã™ã€‚
矢å°ãƒœã‚¿ãƒ³ã‚’使ã£ã¦é€Ÿåº¦ã‚’一定ã®å‰²åˆã§èª¿æ•´ã—ã€è¡¨ç¤ºã•れã¦ã„ã‚‹ã™ã¹ã¦ã®åŽç›Šã‚’æ›´æ–°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚車両ã®å¹³å‡æœ€é«˜é€Ÿåº¦ãŒãƒœãƒ¼ãƒŠã‚¹é€Ÿåº¦ã«é”ã—ã¦ã„ãªã„å ´åˆã®åŽç›Šã‚’ã€æ‰‹å‹•ã§è¨ˆç®—ã™ã‚‹ã“ã¨ãªã確èªã—ãŸã„å ´åˆã«ä¾¿åˆ©ã§ã™ã€‚

ä¸¦ã³æ›¿ãˆ: アイテム一覧ã®è¡¨ç¤ºé †ã‚’示ã—ã¾ã™ã€‚
オプションボタンをクリックã™ã‚‹ã¨ã€ã•ã¾ã–ã¾ãªä¸¦ã¹æ›¿ãˆã‚ªãƒ—ションãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆã‚ªãƒ—ションボタンã®åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã€‚

- åå‰é †ã¯ã€åå‰ã®ã‚¢ãƒ«ãƒ•ァベット順ã«è¡¨ç¤ºã—ã¾ã™ã€‚
- åŽå…¥é †ã¯ã€åŽå…¥ã‚’å¾—ãŸé †ã«è¡¨ç¤ºã—ã¾ã™ã€‚
- ボーナス別ã¯ã€é€Ÿåº¦ãƒœãƒ¼ãƒŠã‚¹ã® % 別ã«ä¸¦ã³æ›¿ãˆã¾ã™ã€‚

- 昇順 / é™é †ã¯ã€ä¸€è¦§ã®é †åºã‚’逆ã«ã—ã¾ã™ã€‚

å„é …ç›®ã®è©³ç´°ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

色ã¤ã四角ã¯ã€ã‚²ãƒ¼ãƒ ãƒ“ューã§ã‚¹ãƒˆãƒƒãƒ—ã®ä¸Šã«ã‚る貨物ã®è‰²ãƒãƒ¼ã«è¡¨ç¤ºã•れã¦ã„る色ã¨åŒã˜è‰²ã§ã€è¼¸é€å¾…ã¡ã®ã‚¢ã‚¤ãƒ†ãƒ ã®é‡ã‚’示ã—ã¾ã™ã€‚
{ヒント: [ ! ] を使ã†ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューã®ã‚¹ãƒˆãƒƒãƒ—上ã®è²¨ç‰©ã®è‰²ãƒãƒ¼ãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ã€‚ï½

åŽå…¥ã¨ã¯ã€ç¾åœ¨ã®æ”¯æ‰•ã„モデルã«ãŠã„ã¦ã€1ユニットを1タイル分ã®è·é›¢ã ã‘輸é€ã™ã‚‹ã®ã«å—ã‘å–ã‚‹åŽå…¥ã®ã“ã¨ã§ã™ã€‚
ã“れ㯠{(基本åŽå…¥) x (1 + ((平凿œ€å¤§é€Ÿåº¦) / (速度ボーナス) - 1) x (ボーナス%))} ã§è¨ˆç®—ã•れã¾ã™ã€‚

ボーナス %ã¯ã€è»Šä¸¡ã®æœ€å¤§é€Ÿåº¦ã«æ¯”例ã—ã¦å¤‰åŒ–ã™ã‚‹åŽå…¥ã®å‰²åˆã§ã‚り〠速度ボーナスã®é€Ÿåº¦ã«å¿œã˜ã¦å比例ã—ã¾ã™ã€‚

貨物カテゴリã¯ã€è¼¸é€ã«å¿…è¦ãªè»Šä¸¡ã®ç¨®é¡žã‚’示ã—ã¾ã™ã€‚特殊ãªè²¨ç‰©ã¯ç‰¹å®šã®è»Šä¸¡ã‚’å¿…è¦ã¨ã—ã¾ã™ã€‚
{ヒント: 車両ã®ç©è¼‰ç‰©ã¯ã€è»Šä¸¡ãŒã©ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’輸é€ã§ãã‚‹ã‹ã‚’示ã—ã¦ã„ã¾ã™}。

é‡é‡ã¯ã€è²¨ç‰© 1ユニット当ãŸã‚Šã®é‡ã•をキログラムå˜ä½ã§ç¤ºã—ã¾ã™ã€‚
ã“ã®é‡é‡ã¯è¼¸é€ä¸­ã®è»Šä¸¡é‡é‡ã«åŠ ç®—ã•れるã®ã§ã€ç©ºã®æ™‚より車両を動ã‹ã™ã®ã«å¤šãã®é¦¬åŠ›ãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/haltlist.txt000066400000000000000000000120011474050137200215350ustar00rootroot00000000000000駅一覧 ヘルプ

駅一覧

駅一覧ã«ã¯æƒ…å ±ãŒè¡¨ç¤ºã•れã€è»Šä¸¡ãŒè·ç‰©ã‚„乗客をç©ã‚“ã ã‚Šé™ã‚ã—ãŸã‚Šã™ã‚‹ã•ã¾ã–ã¾ãªã‚¹ãƒˆãƒƒãƒ—(水上輸é€å°‚用ã®åŸ é ­ä»¥å¤–ã‚‚å«ã‚€ï¼‰ã‚’フィルタリングã—ã¦ãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã™ã‚‹æ©Ÿèƒ½ãŒã‚りã¾ã™ã€‚

ã“れを開ãã«ã¯ã€ä¸€è¦§è¡¨ã®é§…一覧ツールをクリックã—ã¾ã™ã€‚駅一覧ã«ã¯4ã¤ã®ã‚ªãƒ—ションボタンãŒã‚りã€2ã¤ã¯ä¸€è¦§å†…ã®ã‚¢ã‚¤ãƒ†ãƒ ã®é †ç•ªã‚’決ã‚ã‚‹ãŸã‚ã€2ã¤ã¯ä¸€è¦§ã«è¡¨ç¤ºã™ã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã®é¸æŠžã«ã‚ªãƒ—ションをé©ç”¨ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã—ã¾ã™ã€‚ボタンã®ä¸‹ã«ã¯ã€ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã®æ¡ä»¶ã«åˆã†ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€è¦§ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
{ヒント: ストップã®ä¸€è¦§ãŒãªã„å ´åˆã¯ã€ãƒ•ィルターオプションを変更ã—ã¦ãã ã•ã„。一覧ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒä¸€éƒ¨ã—ã‹è¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€é§…一覧ã®ã‚µã‚¤ã‚ºã‚’変更ã™ã‚‹ã‹ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã§ä¸€è¦§ã‚’スクロールã—ã¦ãã ã•ã„。ï½

ボタンをクリックã™ã‚‹ã¨ã€ã‚ªãƒ—ションãŒåˆ‡ã‚Šæ›¿ã‚り(オプションボタンã®åå‰ãŒå¤‰ã‚りã¾ã™ï¼‰ã€ãƒ•ィルタ設定コントロールãŒé–‹ãã¾ã™ã€‚

ä¸¦ã¹æ›¿ãˆ: 2ã¤ã®ã‚ªãƒ—ションボタンã§ã€ä¸€è¦§ã«è¡¨ç¤ºã•れるストップã®é †ç•ªã‚’決定ã—ã¾ã™ã€‚

- タイプ: å—ã‘入れå¯èƒ½ãªè»Šä¸¡ã®ã‚¿ã‚¤ãƒ—別ã«è¡¨ç¤ºã—ã¾ã™ã€‚
- ランダム: ランダムãªé †åºã§è¡¨ç¤ºã—ã¾ã™ã€‚
- åå‰é †ï¼š 割り当ã¦ã‚‰ã‚ŒãŸåå‰ã®ASCIIコード順ã®è‹±æ•°å­—ã§è¡¨ç¤ºã—ã¾ã™ï¼ˆå¤§æ–‡å­—ãŒå°æ–‡å­—ã®å‰ã«ãã¾ã™ï¼‰ã€‚
- 待機数: æä¾›ã•れる輸é€ã‚µãƒ¼ãƒ“スã«é–¢é€£ã™ã‚‹ã€ç¾ã«å­˜åœ¨ã™ã‚‹å•†å“ã¨ä¹—å®¢ã®æ•°é‡ã«ã‚ˆã‚‹é †åºã€‚
- 昇順 / é™é †ï¼š 一覧ã®é †åºã‚’逆ã«ã—ã¾ã™ã€‚

フィルター: 2ã¤ã®ã‚ªãƒ—ションボタンã¯ã€ä¸€è¦§ã®é¸æŠžåŸºæº–をオン/オフã—ã€åŸºæº–を変更ã™ã‚‹ãŸã‚ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’行ã„ã¾ã™ã€‚

- 有効 / 無効: クリックã™ã‚‹ã¨ã€ãƒ•ィルタ基準ãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ã€‚

- 設定: クリックã™ã‚‹ã¨ã€ãƒ•ィルター基準を変更ã™ã‚‹ãŸã‚ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

ステーションリストã«è¡¨ç¤ºã•れã¦ã„る項目をクリックã™ã‚‹ã¨ã€ãã®ã‚¹ãƒˆãƒƒãƒ—ã«é–¢ã™ã‚‹è©³ç´°æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
å„ストップã«è¡¨ç¤ºã•れる項目ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

ステータスカラーãƒãƒ¼: å„色ã¯ã‚¹ãƒˆãƒƒãƒ—ã®æ··é›‘度ãªã©ã€ãã®ã‚¹ãƒˆãƒƒãƒ—ã®é‹å–¶çжæ³ã‚’示ã—ã¾ã™ã€‚ã“ã®ã‚«ãƒ©ãƒ¼ãƒãƒ¼ã¯ã€ã‚¹ãƒˆãƒƒãƒ—情報ã¨è·¯ç·šç·¨é›†ã§ã‚‚使用ã•れã€ã‚²ãƒ¼ãƒ ãƒ‡ã‚£ã‚¹ãƒ—レイã®ã‚¹ãƒˆãƒƒãƒ—ã®ä¸Šã«ã‚るカラーãƒãƒ¼ã«è¡¨ç¤ºã•れる色ã¨åŒã˜ã§ã™ã€‚
- 黄色: 経路ã€ä½•ã‚‚å¾…ã£ã¦ã„ãªã„状態。
- 緑色: 改善ã®å¿…è¦ãªã—。
- 橙色: ストップãŒã‚„や混雑ã—ã¦ã„る(主ã«è²¨ç‰©ãŒå¤šã„)。
- 赤色: 定員ã®1.5å€ä»¥ä¸Šã€ã¾ãŸã¯200人以上ã®ä¸å¹¸ãªå¾…機客ãŒã„ã‚‹ã€ã¾ãŸã¯ã‚¹ãƒˆãƒƒãƒ—ãŒæ··é›‘ã—ã¦ã„ã‚‹ã®ã§å·¥å ´ã¯ç”Ÿç”£ã‚’åœæ­¢ã—ãªã‘れã°ãªã‚‰ãªã„。
{ヒント: [ ! ] を使ã†ã¨ã€ã‚²ãƒ¼ãƒ è¡¨ç¤ºã§ã‚¹ãƒˆãƒƒãƒ—ã®ä¸Šã®ã‚«ãƒ©ãƒ¼ãƒãƒ¼ãŒåˆ‡ã‚Šæ›¿ã‚りã¾ã™ã€‚ï½

åå‰ å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸåå‰ã€‚
割り当ã¦ã‚‰ã‚ŒãŸåå‰{ヒント: simuconf.tabã§ã‚¹ãƒˆãƒƒãƒ—åã«æ•°å­—を割り当ã¦ã‚‹ã‚ªãƒ—ションãŒã‚りã¾ã™ã€‚ï½

車両アイコンã¯ã€ã©ã®ã‚¿ã‚¤ãƒ—ã®è»Šä¸¡ãŒã‚¹ãƒˆãƒƒãƒ—を使用ã§ãã‚‹ã‹ã‚’示ã—ã¾ã™ï¼ˆåœç•™æ‰€æƒ…å ±ã¨ãƒ©ã‚¤ãƒ³ç®¡ç†ã§ã‚‚使用ã•れã¾ã™ï¼‰ã€‚
アイコンã«ã¯ã€ãƒã‚¹ï¼ˆé“路用ã®ä¹—用車)ã€ãƒˆãƒ©ãƒƒã‚¯ï¼ˆé“路用ã®è²¨ç‰©è»Šï¼‰ã€åˆ—車ã€èˆ¹èˆ¶ã€èˆªç©ºæ©ŸãŒã‚りã¾ã™ã€‚市電(路é¢é›»è»Šï¼‰ã¯ã€åœç•™æ‰€ã®ç¨®é¡žã«å¿œã˜ã¦ã€ãƒã‚¹ã‚¢ã‚¤ã‚³ãƒ³ã¾ãŸã¯åˆ—車アイコンã§è¡¨ç¤ºã•れã¾ã™ã€‚

貨物アイコンã¯ã€ãã®ã‚¹ãƒˆãƒƒãƒ—ãŒã©ã®ã‚ˆã†ãªã‚¢ã‚¤ãƒ†ãƒ ï¼ˆæ—…客ã€è²¨ç‰©ã€éƒµä¾¿ç‰©ï¼‰ã‚’扱ã†ã“ã¨ãŒã§ãã‚‹ã‹ã‚’示ã—ã¾ã™ï¼ˆé§…情報や路線編集ã§ã‚‚使用ã•れã¾ã™ï¼‰ã€‚
{ヒント: é©åˆ‡ãªæ‹¡å¼µæ–½è¨­ã‚’追加ã™ã‚‹ã“ã¨ã§ã€ã‚¹ãƒˆãƒƒãƒ—ãŒæ‰±ãˆã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã®ã‚«ãƒ†ã‚´ãƒªãƒ¼ãŒå¤‰ã‚りã¾ã™ã€‚郵便物ã®å–り扱ã„ã‚’å¯èƒ½ã«ã™ã‚‹ãŸã‚ã«ã€éƒµä¾¿å±€ã‚’ストップã«è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ï½ã€‚

待機中ã¯ã€ã‚¹ãƒˆãƒƒãƒ—ã§å¾…機ã—ã¦ã„る色々ãªè²¨ç‰©ã‚„乗客ã®è©³ç´°ã§ã™ã€‚

simutrans-124.3/simutrans/text/ja/haltlist_filter.txt000066400000000000000000000057201474050137200231140ustar00rootroot00000000000000駅一覧フィルター ヘルプ

駅一覧フィルター

駅一覧フィルターã§ã¯ã€ä¹—客ã®ä¹—りé™ã‚Šã‚’行ã†ã‚¹ãƒˆãƒƒãƒ—(駅・åœç•™æ‰€ï¼‰ï¼ˆæ°´ä¸Šè¼¸é€ã®ãŸã‚ã®æ¸¯ã‚‚å«ã‚€ï¼‰ã‚’駅一覧ã«è¡¨ç¤ºã™ã‚‹ã‹ã©ã†ã‹ã‚’設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

駅一覧ã®è¨­å®šã‚’クリックã™ã‚‹ã¨ã€é§…一覧フィルターãŒè¡¨ç¤ºã•れã¾ã™ã€‚

オプションボタンã¯ã€ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚ªãƒ—ã‚·ãƒ§ãƒ³ãŒæœ‰åйãªå ´åˆã«ã€é§…一覧ã«è¡¨ç¤ºã™ã‚‹ã‚¹ãƒˆãƒƒãƒ—ã‚’é¸æŠžã—ã¾ã™ã€‚設定ã•ã‚ŒãŸæ¡ä»¶ã«åˆè‡´ã™ã‚‹ã‚¹ãƒˆãƒƒãƒ—ã®ã¿ãŒä¸€è¦§ã«è¡¨ç¤ºã•れã¾ã™ã€‚

ボタンをクリックã™ã‚‹ã¨ã€ãƒ•ã‚£ãƒ«ã‚¿ã®æ¡ä»¶ã‚’é¸æŠžï¼è§£é™¤ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼ˆãƒœã‚¿ãƒ³ã‚’é¸æŠžã™ã‚‹ã¨ã€æŠ¼ã—è¾¼ã¾ã‚ŒãŸçŠ¶æ…‹ã«ãªã‚Šã¾ã™ï¼‰ã€‚

åå‰ãƒ•ィルター: ストップをåå‰ã§é¸æŠžã—ã¾ã™ã€‚使用方法:ボタンをクリックã—ã¦é¸æŠžã—ã€åå‰ãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¦å¿…è¦ãªåå‰ã‚’正確ã«å…¥åŠ›ã—ã¾ã™ï¼ˆã‚ªãƒ—ションã¯å¤§æ–‡å­—ã¨å°æ–‡å­—を区別ã—ã¾ã™ï¼‰ã€‚

タイプフィルター: 以下ã®é …ç›®ã®ã†ã¡ã€å°‘ãªãã¨ã‚‚1ã¤ä»¥ä¸Šã®é …目をæŒã¤ã‚¹ãƒˆãƒƒãƒ—ã‚’é¸æŠžã—ã¾ã™ã€‚使用ã™ã‚‹ã«ã¯ã€ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦ãã ã•ã„。(水上輸é€å°‚用ã®åŸ é ­ã¯ã€é§…一覧ã«ã¯è¡¨ç¤ºã•れã¾ã›ã‚“。)

特殊フィルター:
- 混雑中ã¯ã€ä½¿ç”¨ã§ãã¾ã›ã‚“。
- 接続ãªã—ã¯ã€è¼¸é€çµŒè·¯ã®ãªã„ã‚¹ãƒˆãƒƒãƒ—ã‚’é¸æŠžã—ã¾ã™ã€‚

製å“需è¦: é¸æŠžã•れãŸã‚¢ã‚¤ãƒ†ãƒ ã®æœ€çµ‚目的地ã¨ãªã‚‹ã‚¹ãƒˆãƒƒãƒ—ã®ã“ã¨ã§ã™ã€‚åå‰ã®æ¨ªã«ã‚るボタンをクリックã™ã‚‹ã¨ã€ã‚¢ã‚¤ãƒ†ãƒ ãŒé¸æŠžã•れã¾ã™ã€‚スライダーãƒãƒ¼ã§ã‚¢ã‚¤ãƒ†ãƒ ã®ãƒªã‚¹ãƒˆã‚’スクロールã—ã¾ã™ã€‚é¸æŠžè‚¢ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- å…¨é¸æŠžï¼šã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã™ã‚‹ã€‚
- 全解除:アイテムを1ã¤ã‚‚é¸æŠžã—ãªã„。
- å転:ç¾åœ¨é¸æŠžã•れã¦ã„るアイテムをå転ã™ã‚‹ã€‚

生産å“: é¸æŠžã•れãŸã‚¢ã‚¤ãƒ†ãƒ ã®è¼¸é€ã‚’é–‹å§‹ã™ã‚‹ã‚¹ãƒˆãƒƒãƒ—ã‚’å‚ç…§ã—ã¾ã™ã€‚åå‰ã®æ¨ªã«ã‚るボタンをクリックã™ã‚‹ã¨ã€ã‚¢ã‚¤ãƒ†ãƒ ãŒé¸æŠžã•れã¾ã™ã€‚スライダーãƒãƒ¼ã‚’使ã£ã¦ã‚¢ã‚¤ãƒ†ãƒ ä¸€è¦§ã‚’スクロールã—ã¾ã™ã€‚オプションã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- å…¨é¸æŠžï¼šã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã™ã‚‹ã€‚
- å…¨è§£é™¤ï¼šã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã—ãªã„。
- å転:ç¾åœ¨é¸æŠžã•れã¦ã„る項目をå転ã™ã‚‹ã€‚

simutrans-124.3/simutrans/text/ja/industry_info.txt000066400000000000000000000137441474050137200226240ustar00rootroot00000000000000産業情報 ヘルプ

産業情報

産業情報 ã§ã¯ã€é¸æŠžã—ãŸç”£æ¥­ï¼ˆå•†å“ã®ä¾›çµ¦ä¼šç¤¾ã¾ãŸã¯æ¶ˆè²»è€…)ã®è©³ç´°ãŒè¡¨ç¤ºã•れã€ã‚²ãƒ¼ãƒ ãƒ“ューをゲームワールドã®é–¢é€£ã™ã‚‹ä½ç½®ã«ç§»å‹•ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

商å“ã®ä¾›çµ¦è€…ã¨æ¶ˆè²»è€…ã¯ã€æœ€çµ‚消費者ã«åˆ°é”ã™ã‚‹ç”£æ¥­ç•Œã®ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ï¼ˆæµé€šãƒ—ロセス)をæä¾›ã—ã¾ã™ã€‚ã‚る産業ã¯ã€æ¶ˆè²»è€…ã§ã‚ã‚‹ã¨åŒæ™‚ã«ä¾›çµ¦è€…ã§ã‚‚ã‚りã€ç”£æ¥­ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã®ä¸­é–“ã«ä½ç½®ã—ã¦ã„ã¾ã™ã€‚åˆå¿ƒè€…モードã§ãªã‘れã°ã€æ¶ˆè²»è€…ãŒä¾›çµ¦éŽå‰°ã«ãªã£ãŸå ´åˆã€ç”£æ¥­ã¯ä¾›çµ¦ã‚’åœæ­¢ã—ã¾ã™ã€‚
産業ã¯ã€ä¹—客や郵便ã®ç›®çš„地や発信地ã«ãªã‚‹ã“ã¨ã‚‚ã‚りã¾ã™ã€‚車両ã¯ã€åœè»Šå ´ã®é›†å®¢ã‚¨ãƒªã‚¢ãŒç”£æ¥­ã®å»ºç‰©ã®ä¸€éƒ¨ã‚’ã‚«ãƒãƒ¼ã—ã¦ã„ã¦ã€åœè»Šå ´ãŒãã†ã—ãŸå¯¾è±¡ã‚’扱ãˆã‚‹å ´åˆã€åœè»Šå ´ã‚’経由ã—ã¦ç”£æ¥­ã«å•†å“や乗客を集ã‚ãŸã‚Šå±Šã‘ãŸã‚Šã—ã¾ã™ã€‚{ヒント: æ²–åˆã®åŸ é ­ï¼çŸ³æ²¹æŽ˜å‰Šæ‰€ï¼é¤Šé­šå ´ï¼é›†æ•£åœ°ï¼çŸ³æ²¹ï¼éƒµä¾¿ï¼æ—…客ï¼åœç•™æ‰€ä¸€è¦§ã«è¨˜è¼‰ã•れã¦ã„ãªã„ã‚‚ã®ï½

æ–°ã—ã„ゲームã§ã¯ã€åˆæœŸã®ç”£æ¥­ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã®æ•°ã‚’設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚éƒ½å¸‚éƒ¨ã®æˆé•·ã«ä¼´ã„ã€ã‚ˆã‚Šå¤šãã®ç”£æ¥­ãŒå‡ºç¾ã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚2000å¹´é ƒã‹ã‚‰éƒ½å¸‚部ã®äººå£ãŒå€å¢—ã™ã‚‹ãŸã³ã«ã€æ–°ã—ã„産業ãŒå‡ºç¾ã—ã¾ã™ã€‚
{ãƒ’ãƒ³ãƒˆã€‚ã‚²ãƒ¼ãƒ ç·¨é›†ãƒ„ãƒ¼ãƒ«ã®æœ€å¯„りã®éƒ½å¸‚ã«æ–°ã—ã„市場を作るツールを使ã£ã¦ã€éƒ½å¸‚部ã«ç”£æ¥­ã‚’追加ã—ã¾ã™ã€‚cityrules.tab ã§æ–°ã—ã„産業ãŒç™ºç”Ÿã™ã‚‹ã‚¿ã‚¤ãƒŸãƒ³ã‚°ã‚’変更ã—ã¾ã™ï¼ˆindustry_increase_every = 0 ã§ã¯æ–°ã—ã„産業ãŒç™ºç”Ÿã—ã¾ã›ã‚“)ï½ã€‚

調査ツールã§ã‚²ãƒ¼ãƒ ãƒ“ューã«è¡¨ç¤ºã•れã¦ã„る産業ã€ã¾ãŸã¯ç”£æ¥­ä¸€è¦§ã«è¡¨ç¤ºã•れã¦ã„る産業をクリックã™ã‚‹ã¨ã€ç”£æ¥­æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
ã™ã¹ã¦ã®é …ç›®ãŒè¡¨ç¤ºã•れã¦ã„ãªã„å ´åˆã¯ã€ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ãƒãƒ¼ã‚’使ã£ã¦é …目をスクロールã—ã¾ã™ã€‚

é¸æŠžã•れãŸç”£æ¥­ã®åå‰ã¯ã€ç”£æ¥­æƒ…å ±ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«è¡¨ç¤ºã•れã¾ã™ã€‚
。 ãã®ä»–ã€é¸æŠžã•れãŸç”£æ¥­ã«é–¢ã™ã‚‹æƒ…報やオプションã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚

生産:産業ãŒä¾›çµ¦ã™ã‚‹ï¼ˆä¾›çµ¦å´ã®å ´åˆï¼‰ã€ã¾ãŸã¯æ¶ˆè²»ã™ã‚‹ï¼ˆæœ€çµ‚消費者ã®å ´åˆï¼‰å•†å“ã®æœ€å¤§ãƒ¬ãƒ¼ãƒˆï¼ˆå˜ä½ï¼šæœˆï¼æ—¥ï¼‰ã€‚
{ヒント: 変電所を追加ã—ã¦ã€ç”£æ¥­ã¸é›»æ°—を供給ã§ãるよã†è¿½åŠ ã™ã‚‹ã¨ã€å•†å“ã®ç”Ÿç”£ï¼æ¶ˆè²»çއãŒå¢—加ã—ã¾ã™}。

産業ã®ç”»åƒã¯ã€ç”£æ¥­ã®å»ºç‰©ã®å¤–観を表ã—ã¦ã„ã¾ã™ã€‚ç”»åƒã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューãŒç”£æ¥­ã®å»ºç‰©ã«ç§»å‹•ã—ã¾ã™ã€‚

ç”»åƒã®ä¸‹ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒãƒ¼ã®è‰²ã¯ã€ç”£æ¥­ã®ç¨¼åƒçжæ³ã‚’示ã—ã¦ã„ã¾ã™ï¼ˆç”£æ¥­ä¸€è¦§è¡¨ã§ã‚‚使用ã•れã¦ã„ã¾ã™ï¼‰ã€‚
- 白色: 供給ã¯å¿…è¦ã‚りã¾ã›ã‚“。
- 黄色: 輸é€ã§ã¤ãªãŒã£ã¦ã„ã¾ã™ãŒã€ç”£æ¥­ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã¯ä¾›çµ¦åŠ›ãŒå¼±ã„。
- 緑色: 最é©ãªçŠ¶æ…‹ã§ã™ã€‚
- 橙色: 稼åƒã—ã¦ã„ã¾ã™ãŒã€æ”¹å–„ã®ä½™åœ°ãŒã‚りã¾ã™ã€‚
- 赤色: 稼動ã—ã¦ã„ã¾ã™ãŒã€ç”£æ¥­ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã®ä¸€éƒ¨ãŒä¾›çµ¦éŽå‰°ã§ã™ã€‚

需è¦å…ˆ: é¸æŠžã•れãŸç”£æ¥­ã§ç”Ÿç”£ã•れãŸå•†å“ã®ã€ç”£æ¥­ã®ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ä¸Šã®ç›®çš„地ãŒè¨˜è¼‰ã•れã¦ã„ã¾ã™ã€‚
目的地ã¨ãªã‚‹ç”£æ¥­ã¨ãã®åœ°å›³ä¸Šã®åº§æ¨™ãŒçŸ¢å°ãƒœã‚¿ãƒ³ã§è¡¨ç¤ºã•れã¾ã™ã€‚矢å°ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューãŒç›®çš„地ã«ç§»å‹•ã—ã¾ã™ã€‚

供給元(仕入先): é¸æŠžã•れãŸç”£æ¥­ãŒå¿…è¦ã¨ã™ã‚‹ã€ç”£æ¥­ã‚µãƒ—ライãƒã‚§ãƒ¼ãƒ³ã«ãŠã‘る商å“ã®èµ·æºã‚’示ã—ã¾ã™ã€‚
供給元ã®ç”£æ¥­ã¨ãã®åœ°å›³åº§æ¨™ã¯ã€çŸ¢å°ãƒœã‚¿ãƒ³ã§è¡¨ç¤ºã•れã¾ã™ã€‚矢å°ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューãŒä¾›çµ¦å…ƒã¸ç§»å‹•ã—ã¾ã™ã€‚

労åƒè€…å±…ä½åœ°: 従業員ãŒè¿‘ãã®ã©ã®éƒ½å¸‚部ã«ä½ã‚“ã§ã„ã‚‹ã®ã‹ãŒåˆ†ã‹ã‚Šã¾ã™ã€‚ ã“れらã®éƒ½å¸‚部ã‹ã‚‰ã®ä¹—客や郵便物ã¯ã€é¸æŠžã•れãŸç”£æ¥­ã«åˆ°é”ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
。 都市部ã¨ãã®åœ°å›³ã®åº§æ¨™ã¯çŸ¢å°ãƒœã‚¿ãƒ³ã§è¡¨ç¤ºã•れã¾ã™ã€‚矢å°ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューãŒä¾›çµ¦å…ƒã¸ç§»å‹•ã—ã¾ã™ã€‚

旅客度: 乗客ã«ã¨ã£ã¦ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—ã§ã™ã€‚
郵便度: 郵便ã®å®›å…ˆã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—ã§ã™ã€‚
{ヒント: 乗客ã¨éƒµä¾¿ã®ãŸã‚ã®æœ€é©ãªã‚µãƒ¼ãƒ“スをæä¾›ã™ã‚‹ãŸã‚ã«ã¯ã€ç”£æ¥­ã®å»ºç‰©ã®1マスã ã‘ãŒåœè»Šå ´ã®é›†å®¹ã‚¨ãƒªã‚¢ã«å…¥ã‚‹å¿…è¦ãŒã‚りã¾ã™ï½ã€‚}

生産: 産業ã®ç”Ÿç”£å“ã®è©³ç´°ãŒåˆ†ã‹ã‚Šã¾ã™ã€‚
表示ã•れる情報ã¯ã€ã‚¢ã‚¤ãƒ†ãƒ ï¼ˆè²¨ç‰©ï¼‰ã®åå‰ã€è£½å“ã®æœ€å¤§ä¿å­˜å®¹é‡ãŠã‚ˆã³ç¾åœ¨ã®ä¿å­˜é‡ã€ã‚¢ã‚¤ãƒ†ãƒ ã®ã‚«ãƒ†ã‚´ãƒªãƒ¼ã€ä¾›çµ¦ã«å¯¾ã™ã‚‹æ¶ˆè²»ã®ãƒ¬ãƒ™ãƒ«ã®å‰²åˆãªã©ã§ã™ã€‚

消費: 産業ã®ä¾›çµ¦ã«é–¢ã™ã‚‹è©³ç´°ã‚’æä¾›ã—ã¾ã™ã€‚
表示ã•れる情報ã¯ã€ã‚¢ã‚¤ãƒ†ãƒ ã®åå‰ã€ã‚¢ã‚¤ãƒ†ãƒ ã®æœ€å¤§ä¿å­˜å®¹é‡ã¨æ¯”較ã—ãŸç¾åœ¨ã®ä¿å­˜é‡ã€ã‚¢ã‚¤ãƒ†ãƒ ã®ã‚«ãƒ†ã‚´ãƒªãƒ¼ã€ä¾›çµ¦ã«å¯¾ã™ã‚‹æ¶ˆè²»ã®å‰²åˆãƒ¬ãƒ™ãƒ«ãªã©ã§ã™ã€‚

ç”£æ¥­ã«æŽ¥ç¶šã—ã¦ã„ã‚‹é§…ã‚„åœç•™æ‰€ã¯ã€ç”£æ¥­æƒ…報ウィンドウã®ãƒœãƒˆãƒ ï¼ˆä¸‹éƒ¨ï¼‰ã«æŽ²è¼‰ã•れã¦ã„ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/inspection_tool.txt000066400000000000000000000155421474050137200231360ustar00rootroot00000000000000調査ツール ヘルプ

調査ツール

調査ツールã¯ã€ã•ã¾ã–ã¾ãªã‚¢ã‚¤ãƒ†ãƒ ã®æƒ…報やオプションコントロールをæä¾›ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ããŸã‚ã«ä½¿ç”¨ã—ã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚る虫眼é¡ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã‹ã€[a] を押ã™ã¨ã€èª¿æŸ»ãƒ„ールãŒé–‹ãã¾ã™ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒè™«çœ¼é¡ã«å¤‰ã‚りã¾ã™ï¼‰ã€‚

調査ツールを使ã†ã«ã¯ã€ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ã®æ‹¡å¤§é¡ã‚«ãƒ¼ã‚½ãƒ«ã‚’å¿…è¦ãªä½ç½®ã«ç½®ãã€ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ã€‚å¿…è¦ãªä½ç½®ã«è¤‡æ•°ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒã‚ã‚‹å ´åˆã¯ã€ã•らã«ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨2ã¤ç›®ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã¾ã™ã€‚
{ヒント:simuconf.tabã«ã¯ã€æŒ‡å®šã•れãŸã‚«ãƒ¼ã‚½ãƒ«ã®ä½ç½®ã§1ã¤ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¾ãŸã¯ã™ã¹ã¦ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãオプションãŒã‚りã¾ã™ã€‚ï½

ゲームビュー上ã®ä»¥ä¸‹ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’ツールã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€æ§˜ã€…ãªãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

機関庫(車庫) - ãã®æ©Ÿé–¢åº«ã§è»Šä¸¡ã®è³¼å…¥ã¨ç®¡ç†ã‚’行ã†ãŸã‚ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’é–‹ãã¾ã™ã€‚

ストップ(駅やåœç•™æ‰€ï¼‰ - ストップ - ãã®ã‚¹ãƒˆãƒƒãƒ—ã«ã¤ã„ã¦ã®ã‚¹ãƒˆãƒƒãƒ—情報を開ãã¾ã™ã€‚

車両 - ãã®è»Šä¸¡ã®è»Šä¸¡ï¼è»Šä¸¡æƒ…報を開ãã¾ã™ã€‚

タウンホール(自治体ã®åºèˆŽï¼‰ - ãã®å¸‚町æ‘ã®è¡—ã®æƒ…å ±ãŒé–‹ãã¾ã™ã€‚
{ヒント:タウンホールã«é–¢ã™ã‚‹æƒ…報をæä¾›ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãオプションã¯ã€simuconf.tabã§åˆ©ç”¨ã§ãã¾ã™}

産業 - 産業 - ãã®ç”£æ¥­ã«ã¤ã„ã¦ã®ç”£æ¥­æƒ…報を開ãã¾ã™ã€‚

建築物 ãã®å»ºç‰©ã«é–¢ã™ã‚‹æƒ…報をæä¾›ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã¾ã™ï¼ˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã¯ã€Œå»ºç‰©ã€ã§ã™ï¼‰ã€‚ダイアログã«å«ã¾ã‚Œã‚‹æƒ…å ±ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- 説明 建物ã«é–¢ã™ã‚‹æƒ…報をæä¾›ã—ã¾ã™ã€‚ã‚‚ã—説明ãŒãªã„å ´åˆã¯ã€ã€Œä½å®…ã€ã€ã€Œç”£æ¥­ç”¨å»ºç‰©ã€ã€ã€Œã‚·ãƒ§ãƒƒãƒ—ã¨å•†åº—ã€ï¼ˆå•†æ¥­æ–½è¨­ã®å ´åˆï¼‰ã®ã„ãšã‚Œã‹ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
- City of : ãã®å¸‚街ビルãŒã©ã®éƒ½å¸‚åœã«å±žã—ã¦ã„ã‚‹ã‹ã‚’示ã—ã¾ã™ã€‚
- 旅客度: 乗客ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—度ã§ã™ã€‚
- 郵便度: 郵便物ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—を表ã—ã¾ã™ã€‚
- 登場ã™ã‚‹å¹´: 時系列ã§è¦‹ãŸå ´åˆã€å»ºç‰©ãŒç¾ã‚Œã‚‹å¹´ã‚’示ã—ã¾ã™ã€‚
- 価格: 撤去ï¼å–り除ãツールã§å»ºç‰©ã‚’除去ã—ãŸå ´åˆã«ç™ºç”Ÿã™ã‚‹è²»ç”¨ã‚’示ã—ã¾ã™ã€‚
- 作者: Simutransã®ãŸã‚ã«å»ºç‰©ã‚’æã„ãŸäººã®åå‰ã§ã™ã€‚

モニュメント ï¼ åæ‰€æ—§è·¡ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ã¯ã€ãã®å所ã«é–¢ã™ã‚‹æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«ã¯ã€ãれãŒãƒ¢ãƒ‹ãƒ¥ãƒ¡ãƒ³ãƒˆã‹å所旧跡ã‹ãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€‚ダイアログã«å«ã¾ã‚Œã‚‹æƒ…å ±ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- 公共物 ã“れã¯ã€ãƒ—レイヤーã®ä¼šç¤¾ãŒæ‰€æœ‰ã—ã¦ã„ãªã„ã“ã¨ã‚’示ã—ã¾ã™ã€‚
- 説明 忉€æ—§è·¡ã«é–¢ã™ã‚‹æƒ…報をæä¾›ã—ã¾ã™ã€‚
- 旅客度: 乗客ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—度ã§ã™ã€‚
- 郵便度: 郵便物ã®ç›®çš„地ã¨ã—ã¦ã®ç›¸å¯¾çš„ãªäººæ°—を表ã—ã¾ã™ã€‚
- 登場ã™ã‚‹å¹´: 年代設定ã§ãƒ—レイã—ã¦ã„ã‚‹å ´åˆã€å»ºç‰©ã®ç™»å ´å¹´ã‚’示ã—ã¾ã™ã€‚
- 作者: Simutransã®ãŸã‚ã«å所旧跡をæã„ãŸäººã®åå‰ã§ã™ã€‚

é“è·¯ã¨ç·šè·¯ é“路やトラックã«ã¤ã„ã¦ã®æƒ…報をæä¾›ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã¾ã™ï¼ˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«ã¯ã€ãã®é“è·¯ã®ç¨®é¡žãŒè¡¨ç¤ºã•れã¾ã™ - é“路上ã«ä½œã‚‰ã‚ŒãŸè·¯é¢é›»è»Šã®å ´åˆã€ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«ã¯é“è·¯ã®ç¨®é¡žãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€‚
ダイアログã«ã¯ã€ä»¥ä¸‹ã®æƒ…å ±ãŒå«ã¾ã‚Œã¾ã™ã€‚
- 最大速度: é“路や線路ã§è¨±å®¹ã•れる最大速度。
- Ribi (unmasked): ã“れã¯wayã®æ–¹å‘を示ã™å†…部カウンターã§ã™ã€‚
- Ribi (masked): ä¿¡å·ã‚„標識を考慮ã—ãŸä¸Šã§ã€é€²è¡Œæ–¹å‘を示ã™å†…部カウンターã§ã™ã€‚
- with sign/signal ä¿¡å·ã‚„標識ãŒã‚ã‚‹å ´åˆã«è¡¨ç¤ºã•れã¾ã™ã€‚
- 電化ã•れã¦ã„ã‚‹ï¼ã•れã¦ã„ãªã„ ã¯ã€è»Œé“ãŒé›»åŒ–ã•れã¦ã„ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚
- 先月通éŽã—ãŸè»Šä¸¡ 先月通éŽã—ãŸè»Šä¸¡ã¯ã€å‰ã®ã‚²ãƒ¼ãƒ ã®ã‚«ãƒ¬ãƒ³ãƒ€ãƒ¼æœˆã«ã‚¦ã‚§ã‚¤ã‚’使用ã—ãŸè»Šä¸¡ã®æ•°ã‚’示ã—ã¾ã™ã€‚
- reserved by ã¯ã€ã©ã®è»Šä¸¡ãŒé€šéŽã™ã‚‹ã¾ã§ãƒˆãƒ©ãƒƒã‚¯ã‚’使用ã™ã‚‹ãŸã‚ã«äºˆç´„ã—ãŸã‹ã‚’示ã—ã¾ã™ã€‚
- wayslope ã‚‚ã—ã‚れã°ã€å‚¾æ–œã®æ–¹å‘を示ã—ã¾ã™ã€‚
- 座標 ボトムãƒãƒ¼ã«è¡¨ç¤ºã•れã¦ã„る地図ã®åº§æ¨™ã§ã™ã€‚
é“路上ã«å»ºè¨­ã•れãŸå¸‚電(路é¢é›»è»Šï¼‰ã®å ´åˆã€æƒ…å ±ã¯2回表示ã•ã‚Œã€æœ€åˆã¯é“è·¯ã€æ¬¡ã«å¸‚é›»ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

シグナル/Signs ダイアログを開ãã€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã«ã¯ä¿¡å·ã‹é“路標識ã‹ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ダイアログã«ã¯ä»¥ä¸‹ã®ã‚ˆã†ãªæƒ…å ±ãŒå«ã¾ã‚Œã¾ã™ã€‚
- direction ã¯ã€ä¿¡å·ãŒé©ç”¨ã•れる方å‘を示ã™å†…部カウンターã§ã™ã€‚

é€é›»ç·š / 変電所 ã§ã¯ã€é›»åŠ›ä¾›çµ¦ç¶²ã«é–¢ã™ã‚‹æƒ…報をæä¾›ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã¾ã™ï¼ˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã¯ã€Œé€é›»ç·šã€ï¼‰ã€‚表示ã•れる情報ã¯ç¾åœ¨ã®éœ€è¦ã¨ä¾›çµ¦ã§ã™ã€‚

木 ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã¾ã™ï¼ˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã¯ã€Œæœ¨ã€ï¼‰ã€‚表示ã•れる情報ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- åå‰ æ¨¹æœ¨ã®ç¨®é¡žã‚’示ã—ã¾ã™ã€‚
- 樹齢 樹齢を月å˜ä½ã§è¡¨ç¤ºã—ã¦ã„ã¾ã™ã€‚

土地ダイアログボックスãŒè¡¨ç¤ºã•れã¾ã™ï¼ˆã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã¯ã€ŒåœŸåœ°ã€ï¼‰ã€‚表示ã•れる情報ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
- スロープ 樹木ã®ç¨®ã‚’æä¾›ã—ã¾ã™ã€‚
- マップ座標 ボトムãƒãƒ¼ã«è¡¨ç¤ºã•れる地図上ã®åº§æ¨™ã€‚

{ヒント: ç§é“ã®åˆ©ç”¨è€…や歩行者ã«é–¢ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãオプションã¯ã€simunconf.tab ã§åˆ©ç”¨ã§ãã¾ã™ã€‚}

simutrans-124.3/simutrans/text/ja/jump_frame.txt000066400000000000000000000013661474050137200220520ustar00rootroot00000000000000指定座標ã¸ç§»å‹• ヘルプ

指定座標ã¸ç§»å‹•

SHIFT + [ J ] キーã§ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒé–‹ãã€æŒ‡å®šã—ãŸåº§æ¨™ã¸ã®ã‚¸ãƒ£ãƒ³ãƒ—ãŒå¯èƒ½ã«ãªã‚Šã¾ã™ã€‚ã“れã¯ã€ã‚²ãƒ¼ãƒ ãƒ¯ãƒ¼ãƒ«ãƒ‰ä¸Šã®ç‰¹å®šã®ä½ç½®ã«ç´ æ—©ã移動ã™ã‚‹ã®ã«ä¾¿åˆ©ã§ã™ã€‚

ゲームワールド上ã®ã™ã¹ã¦ã®ã‚¿ã‚¤ãƒ«ã«ã¯2ã¤ã®åº§æ¨™ï¼ˆx,y)ãŒã‚りã€ï¼ˆ0,0)ã¯ãƒžãƒƒãƒ—ã®å·¦ä¸Šã®éš…ã«ä½ç½®ã—ã¦ã„ã¾ã™ã€‚カーソルã®åº§æ¨™ã¯ã€ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒãƒ¼ã«å¸¸ã«è¡¨ç¤ºã•れã¾ã™ã€‚
注æ„: マップã®å›žè»¢ï¼ˆ SHIFT + [ R ] キーã§å®Ÿè¡Œï¼‰ã¯ã€ã™ã¹ã¦ã®ã‚¿ã‚¤ãƒ«ã®åº§æ¨™ã‚’回転ã•ã›ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/language.txt000066400000000000000000000020111474050137200214740ustar00rootroot00000000000000言語ダイアログヘルプ

言語ダイアログ

 Simutrans ã¯è¤‡æ•°ã®è¨€èªžã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ä½¿ç”¨ã—ãŸ
ã„è¨€èªžã‚’é¸æŠžã™ã‚‹ã“ã¨ã§ã€ã‚²ãƒ¼ãƒ ä¸­ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®è¨€èªžã‚’切り替ãˆã‚‹ã“ã¨ãŒå‡º
æ¥ã¾ã™ã€‚ç¾åœ¨é–‹ã„ã¦ã„るウィンドウã®è¡¨ç¤ºå†…容ã¯å¤‰æ›´ã•れã¾ã›ã‚“。ã¾ãŸã€ã™ã§
ã«å­˜åœ¨ã™ã‚‹ç”ºã®åç§°ã¯å¤‰æ›´ã•れã¾ã›ã‚“ã®ã§ã€ãã®è¨€èªžã‚‰ã—ã„町åã§ãƒ—レイã—ãŸ
ã„å ´åˆã«ã¯ã€ã‚²ãƒ¼ãƒ ã‚’é–‹å§‹ã™ã‚‹å‰ã«ã‚らã‹ã˜ã‚è¨€èªžã‚’é¸æŠžã—ã¦ãŠãã¨è‰¯ã„ã§ã—ょ
ã†ã€‚

 ã“ã®ä¸€è¦§ã§é¸æŠžã§ãる言語ã®ä»–ã«ã‚‚ã€http://www.simustation.de.vu ã‚„
http://www.simutrans.de ã§ã„ãã¤ã‹å…¬é–‹ã•れã¦ã„ã¾ã™ï¼ˆãŸã ã—ä¸å®Œå…¨ã§ã‚ã£
ãŸã‚Šæœ€æ–°ç‰ˆã«å¯¾å¿œã—ã¦ã„ãªã„å¯èƒ½æ€§ãŒã‚りã¾ã™ï¼‰ï½¡

Simutransã‚’ã‚ãªãŸã®è¨€èªžã«ç¿»è¨³ã™ã‚‹ãŸã‚ã«ã€
https://translator.simutrans.comã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™

simutrans-124.3/simutrans/text/ja/linemanagement.txt000066400000000000000000000066651474050137200227200ustar00rootroot00000000000000路線編集 ヘルプ

路線編集

路線一覧 路線を管ç†ã—ã¾ã™ï¼ˆåŒã˜ãƒ«ãƒ¼ãƒˆã‚’共有ã™ã‚‹è»Šä¸¡ã®ã‚°ãƒ«ãƒ¼ãƒ—)

路線ã«ã¯ã€è·ç‰©ã‚„乗客を乗ã›ãŸã‚Šé™ã‚ã—ãŸã‚Šã™ã‚‹ã‚¹ãƒˆãƒƒãƒ—(係留場)(水上輸é€ã§ã¯åŸ é ­ã®é›†è·åŸŸå†…ã®æ°´è¾ºã‚’利用ã§ãã¾ã™ï¼‰ã¨ã€ã‚¦ã‚§ã‚¤ãƒã‚¤ãƒ³ãƒˆï¼ˆè¤‡æ•°ã®é¸æŠžè‚¢ãŒã‚ã‚‹å ´åˆã«è»Šä¸¡ã‚’誘導ã—ãŸã‚Šã€æš«å®šçš„ãªç›®çš„地をæä¾›ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã•れã¾ã™ï¼‰ãŒã‚りã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚ã‚‹ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã‹ã€ [w] を押ã™ã¨è·¯ç·šç·¨é›†ãŒè¡¨ç¤ºã•れã€ã“ã®ã‚µã‚¤ã‚ºã¯å¤‰æ›´ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ï¼ˆã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã®ä¸‹å‘ã矢å°ã‚’クリックã™ã‚‹ã¨æœ¬æ¥ã®ã‚µã‚¤ã‚ºã«æˆ»ã‚Šã¾ã™ï¼‰ã€‚

The 路線一覧 lists existing Lines (to scroll list: use slider-bar on right of list), which can be filtered by name or by transport type (click on a index-tab above list to select): ラインリストã«ã¯ã€æ—¢å­˜ã®è·¯ç·šãŒãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã•れã¦ã„ã¾ã™ï¼ˆä¸€è¦§ã‚’スクロールã™ã‚‹ã«ã¯ã€ä¸€è¦§ã®å³ã«ã‚るスライダーãƒãƒ¼ã‚’使用)。ã“ã®ä¸€è¦§ã¯ã€åå‰ã‚„輸é€ã‚¿ã‚¤ãƒ—ã§ãƒ•ィルタリングã§ãã¾ã™ï¼ˆãƒªã‚¹ãƒˆä¸Šã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚¿ãƒ–をクリックã—ã¦é¸æŠžã—ã¾ã™ï¼‰ã€‚
å…¨ã¦All: ã™ã¹ã¦ã®è»Šä¸¡ã®çµŒè·¯ãŒãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã•れã¾ã™ã€‚
列車: ã™ã¹ã¦ã®é‰„é“車両ã®è·¯ç·šãŒãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã•れã¾ã™ã€‚
モノレール: ã™ã¹ã¦ã®ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ï¼ãƒªãƒ‹ã‚¢ãƒ¢ãƒ¼ã‚¿ãƒ¼ã‚«ãƒ¼è»Šä¸¡ã®è·¯ç·šã‚’リストアップã—ã¾ã™ã€‚
市電: ã™ã¹ã¦ã®è·¯é¢é›»è»Šã®è·¯ç·šã‚’リストアップã—ã¾ã™ã€‚
自動車: ã™ã¹ã¦ã®é“路交通車両ã®è·¯ç·šã‚’リストアップã—ã¾ã™ã€‚
船舶: ã™ã¹ã¦ã®æ°´ä¸Šäº¤é€šæ©Ÿé–¢ã®è·¯ç·šã‚’リストアップã—ã¾ã™ã€‚
航空機: ã™ã¹ã¦ã®èˆªç©ºæ©Ÿã®è·¯ç·šã‚’リストアップã—ã¾ã™ã€‚

一覧ã«è¡¨ç¤ºã•れる路線åã®è‰²ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
白色 - 路線ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸè»Šä¸¡ãŒãªã„。
黄色 - 稼動ã—ã¦ãŠã‚‰ãšã€æç›ŠãŒå‡ºã¦ã„ãªã„。
黒色 - 利益を出ã—ã¦ã„る。
é’色 - æ—§å¼ã®è»Šä¸¡ãŒã‚る。
赤色 - æå¤±ã‚’出ã—ã¦ã„るライン。

路線ã®ä¸Šã«ã‚«ãƒ¼ã‚½ãƒ«ã‚’ç½®ãã¨ã€ã•らã«è©³ã—ã„æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚一覧ã®è·¯ç·šã‚’クリックã™ã‚‹ã¨ã€ãã®è·¯ç·šãŒè¡¨ç¤ºã•れã€ãã®è·¯ç·šã®åœè»Šæ‰€ã€åŽå…¥ã€è»Šä¸¡æƒ…報を確èªã—ãŸã‚Šã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

路線編集ã«ã¯ã€æ¬¡ã®2ã¤ã®ã‚ªãƒ—ションãŒã‚りã¾ã™ã€‚

路線作æˆ: æ–°ã—ã„路線ウィンドウを作æˆã—ã¾ã™ã€‚ã“れã«ã¯è¼¸é€ã‚¿ã‚¤ãƒ—ãŒé¸æŠžã•れã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
路線削除: ç¾åœ¨ã®è·¯ç·šã‚’ゲームã‹ã‚‰å‰Šé™¤ã—ã¾ã™ã€‚ãã®è·¯ç·šã«å±žã™ã‚‹ã™ã¹ã¦ã®è»Šä¸¡ã¯ã€ãã®è·¯ç·šã¨åŒæ§˜ã®å€‹åˆ¥ã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§é‹è»¢ã—ã¾ã™ã€‚
Single GUI: 路線をクリックã™ã‚‹ã¨ã€ä¸€ç•ªä¸Šã®è·¯ç·šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒé¸æŠžã•れãŸè·¯ç·šã§ç½®ãæ›ãˆã‚‰ã‚Œã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/list.txt000066400000000000000000000042441474050137200206760ustar00rootroot00000000000000一覧表 ヘルプ

一覧表

一覧表ã«ã¯ã€ã‚²ãƒ¼ãƒ ã®ç¾åœ¨ã®çжæ³ã«é–¢ã™ã‚‹æƒ…報を得るãŸã‚ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’é–‹ãオプションãŒã‚りã¾ã™ï¼ˆã¾ãŸã€ã•ã¾ã–ã¾ãªå•†å“ã€ä¹—客ã€éƒµä¾¿ç‰©ã®è¼¸é€ã‹ã‚‰å¾—られる相対的ãªåŽå…¥ã‚’調整ã™ã‚‹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚‚ã‚りã¾ã™ï¼‰ã€‚

ãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ã¯æƒ…報を一覧表ã§è¦‹ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚åœç•™æ‰€ã€è»Šä¸¡ã€éƒ½å¸‚部ã€ã•ã¾ã–ã¾ãªå•†å“や乗客ã€éƒµä¾¿ã‹ã‚‰å¾—られるåŽå…¥ã€ç”£æ¥­ã€è¦³å…‰åœ°ãªã©ã®æƒ…å ±ãŒä¸€è¦§è¡¨ã«ãªã£ã¦ã„ã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚る一覧表アイコンをクリックã—ã¦ã€ä¸€è¦§è¡¨ãƒªã‚¹ãƒˆã‚’é–‹ãã¾ã™ã€‚
ツールãƒãƒ¼ã‚’é–‹ãã‹ã€ãƒ„ールãƒãƒ¼ã‚’クリックã—ãŸå¾Œã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ã‚’一覧表ツールã®ã‚ªãƒ—ションã«åˆã‚ã›ã‚‹ã¨åå‰ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

ツールオプションをクリックã™ã‚‹ã¨ã€å·¦ã‹ã‚‰å³ã®é †ã«æƒ…報を表示ã™ã‚‹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãŒé–‹ãã¾ã™ã€‚

駅一覧: é§…ã€è»Šä¸¡ãŒè·ç‰©ã‚„乗客を乗ã›ãŸã‚Šé™ã‚ã—ãŸã‚Šã™ã‚‹å ´æ‰€ï¼ˆã—ã‹ã—ã€æ°´ä¸Šè¼¸é€ã®åŸ é ­ã ã‘ã§ã¯ã‚りã¾ã›ã‚“)。

乗り物一覧: é“路・鉄é“車両ã€èˆªç©ºæ©Ÿã€èˆ¹èˆ¶ã€‚

町一覧: å„都市 (æ‘ã€ç”ºã€å¸‚)。

貨物一覧: ç•°ãªã‚‹å•†å“ã€ä¹—客ã€éƒµä¾¿ã‹ã‚‰å—ã‘å–ã‚‹åŽå…¥ï¼ˆç›¸å¯¾çš„ãªåŽå…¥ã‚’調整ã™ã‚‹ãŸã‚ã®ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’å«ã‚€ï¼‰ã€‚

産業一覧: 産業 (商å“ã®æ¶ˆè²»è€…ã¨ä¾›çµ¦ä¼šç¤¾ï¼‰

忉€æ—§è·¡ä¸€è¦§: è¦³å…‰åæ‰€ã€‚

simutrans-124.3/simutrans/text/ja/load.txt000066400000000000000000000007711474050137200206430ustar00rootroot00000000000000ロードダイアログヘルプ

ä¿å­˜ã•れã¦ã„るゲームをロードã™ã‚‹

 ロードダイアログã§ã¯ä»¥å‰ä¿å­˜ã—ãŸã‚²ãƒ¼ãƒ ã‚’ロードã—ã¦ç¶šè¡Œã™ã‚‹ã“ã¨ãŒå‡ºæ¥
ã¾ã™ã€‚æ“作方法ã¯ã‚»ãƒ¼ãƒ–ダイアログã¨åŒæ§˜ã§ã™ã€‚

注æ„ ゲームをä¿å­˜ã—ãŸSimutransã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«ã‚ˆã£ã¦ã¯ãƒ•ァイルã®äº’æ›æ€§
ã®å•題ã«ã‚ˆã‚Šã€ãƒ­ãƒ¼ãƒ‰ã§ããªã„å ´åˆãŒã‚りã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/load_relief.txt000066400000000000000000000037221474050137200221700ustar00rootroot00000000000000地形データ読ã¿è¾¼ã¿ãƒ˜ãƒ«ãƒ—

地形データã®èª­ã¿è¾¼ã¿

地形データを読ã¿è¾¼ã‚€ ã¯æ–°ã—ã„マップã§å§‹ã‚ã‚‹éš›ã«è‡ªä½œã®åœ°å½¢ãƒ•ァイルを使用ã™ã‚‹ã¨ãã‚„ã€ã“れらã®åœ°å½¢ãƒ•ァイルを削除ã™ã‚‹éš›ã«ä½¿ã„ã¾ã™ã€‚

地形データを読ã¿è¾¼ã‚€ 㯠新ã—ã„マップã®ä½œæˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‹ã‚‰é–‹ãã“ã¨ãŒã§ãã€ä½¿ç”¨å¯èƒ½ãªåœ°å½¢ãƒ‡ãƒ¼ã‚¿ãƒ•ァイルã®åç§°ã¨ä¿å­˜æ—¥æ™‚ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

使用ã—ãŸã„地形データファイルã®åå‰ã‚’クリックã™ã‚‹ã‹ã€ä¸Šæ®µã®å…¥åŠ›ã‚¹ãƒšãƒ¼ã‚¹ã«ãƒ•ァイルåを打ã¡è¾¼ã‚“ã§[Enter]キーã‹[Return]キーを押ã—ã¦ä¸‹ã•ã„(ã‚‚ã—存在ã—ãªã„ファイルåを打ã¡è¾¼ã‚“ã å ´åˆã¯ä½•ã‚‚èµ·ã“らãªã„ã®ã§ã€æ­£ã—ã„ファイルåを入力ã—ç›´ã—ã¦ä¸‹ã•ã„)。

ãªãŠã€ãƒ•ァイルåã®å·¦ã«ã‚る×ボタンをクリックã™ã‚‹ã¨ã€ãã®åœ°å½¢ãƒ•ァイルを削除ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚警告:ã“ã®éš›ã€å‰Šé™¤ã®ç¢ºèªç­‰ã¯è¡¨ç¤ºã•れãšå³åº§ã«å‰Šé™¤ã•れã¾ã™ã®ã§ã€èª¤ã£ã¦æŠ¼ã—ãŸã‚Šã—ãªã„よã†ã«æ°—ã‚’ã¤ã‘ã¦ä¸‹ã•ã„。

http://maps.simutrans.com ã«åˆ©ç”¨å¯èƒ½ãªåœ°å½¢ãƒ‡ãƒ¼ã‚¿ãƒ•ァイルãŒã‚りã¾ã™ã€‚
ã¾ï½”地形データファイルã¯.ppmã‹.bmpå½¢å¼(RLE圧縮ã•れãŸ256色ã®ã‚‚ã®ãŒæœ€è‰¯)ã§ãªã‘れã°ãªã‚‰ãšã€simutrans/maps/ã¨åå‰ã®ã¤ã„ãŸãƒ‘ーソナルディレクトリ(ã¾ãŸã¯ãƒ•ォルダ)ã«ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚

地形データファイルã®è£½ä½œæ–¹æ³•ã«ã¤ã„ã¦ã¯ã€ http://wiki.simutrans.com ã‚„ http://japanese.simutrans.com/index.php?FrontPage ã§è¦‹ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

キャンセルをクリックã™ã‚‹ã‹ã€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°å³ä¸Šã®Ã—をクリックã™ã‚Œã°åœ°å½¢ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã‚€ã‚’終了出æ¥ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/mailbox.txt000066400000000000000000000047701474050137200213620ustar00rootroot00000000000000メッセージ表 メッセージ設定ヘルプ

メッセージ表 メッセージ設定

メッセージ表
ゲーム中ã®ã™ã¹ã¦ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¯ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸è¡¨ã«è¡¨ç¤ºã•れã¾ã™ã€‚
左クリック: メッセージウィンドウをå†è¡¨ç¤ºã—ã¾ã™ã€‚
å³ã‚¯ãƒªãƒƒã‚¯: メッセージã®ç™ºç”Ÿå ´æ‰€ã«ç§»å‹•ã—ã¾ã™ã€‚
設定: メッセージ設定ウィンドウを開ãã¾ã™ã€‚

メッセージ設定
メッセージã¯ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸è¡¨ã®ã»ã‹ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚„ç”»é¢æœ€ä¸‹éƒ¨ã®
スクロールテキストã«ã‚‚表示ã§ãã¾ã™ã€‚
メッセージ設定ã§ã¯ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®ç¨®é¡žã”ã¨ã«ã€è¡¨ç¤ºæ–¹æ³•を設定ã§ãã¾ã™ã€‚
ã“ã®è¨­å®šã¯ã€simutransã®æ­£å¸¸çµ‚了時ã«ã€settings.xmlã«ä¿å­˜ã•れã¾ã™ã€‚

左端列ã®ãƒœã‚¿ãƒ³ã‚’オフã«ã™ã‚‹ã¨ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’完全ã«éžè¡¨ç¤ºã«ã§ãã¾ã™ã€‚
メッセージ表ã«ã‚‚表示ã•れã¾ã›ã‚“。

å³å´ã®ï¼“列ã¯ã€å·¦ã‹ã‚‰ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ãƒ†ã‚­ã‚¹ãƒˆã€æ™‚é™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã€
固定メッセージウィンドウã®è¡¨ç¤º/éžè¡¨ç¤ºã®è¨­å®šã§ã™ã€‚

スクロールテキスト: 左クリックã§ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®ç™ºç”Ÿå ´æ‰€ã«ç§»å‹• ã—ã¾ã™ã€‚
時é™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦: ä¸€å®šæ™‚é–“å¾Œã«æ¶ˆãˆã¾ã™ã€‚
固定メッセージウィンドウ: クリックã§é–‰ã˜ã‚‹ã¾ã§æ¶ˆãˆã¾ã›ã‚“。

・新年    新年ãŒå§‹ã¾ã£ãŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
ãƒ»ä»–ç¤¾ã€€ã€€ã€€ã€€ä»–ç¤¾ãŒæ–°ã—ã„路線を作ã£ãŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
・都市    都市ã«å¤§ããªå»ºç¯‰ç‰©ãŒã§ããŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
ãƒ»ãƒ«ãƒ¼ãƒˆä¸æ˜Žã€€åˆ—è»ŠãŒæ¬¡ã®é§…ã«è¡Œãã“ã¨ãŒã§ããªã„ã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
・産業    新ã—ã„産業ãŒã§ããŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
ãƒ»åæ‰€æ—§è·¡ã€€ã€€ã€€æ–°ã—ã„観光地ãŒã§ããŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
・車両登場  新ã—ã„車両ãŒç™»å ´ã—ãŸã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
ãƒ»é§…ã®æ··é›‘  駅ãŒã¨ã¦ã‚‚混雑ã—ã¦ã„ã‚‹ã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
・å•題    借金ãŒå¤§ãã„ã“ã¨ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚
・警告    交通渋滞やプレイヤーã®å¤‰æ›´ã‚’ãŠçŸ¥ã‚‰ã›ã—ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/map.txt000066400000000000000000000112031474050137200204710ustar00rootroot00000000000000マップ ヘルプ

マップ・ウィンドウ

マップ(地図)ウィンドウを開ãã«ã¯ã€ãƒ„ールãƒãƒ¼ã®å·¦ã‹ã‚‰2番目ã«ã‚るマップã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã‹ã€
キーボードã®[m]キーを押ã—ã¾ã™ã€‚

基本マウスæ“作: マップ上ã§ã¯ã€ä»¥ä¸‹ã®æ“作ãŒä½¿ç”¨ã§ãã¾ã™ã€‚

左クリック: クリックã—ãŸå ´æ‰€ã«ã‚²ãƒ¼ãƒ ç”»é¢ã‚’移動ã—ã¾ã™ã€‚ãã®ã¾ã¾ãƒ‰ãƒ©ãƒƒã‚°
ã™ã‚‹ã¨ã€é€£ç¶šã—ã¦ç§»å‹•ã—ã¾ã™ã€‚
å³ãƒ‰ãƒ©ãƒƒã‚°: マップ画é¢ã‚’スクロールã—ã¾ã™ã€‚
å³ãƒ€ãƒ–ルクリック: マップ画é¢ã‚’スクロールå‰ã®ä½ç½®ã«æˆ»ã‚Šã¾ã™ã€‚
マウスホイール: マップ画é¢ã‚’拡大/縮å°ã—ã¾ã™ã€‚

基本ボタンæ“作

拡大・縮å°: マップ画é¢ã‚’拡大/縮å°ã—ã¾ã™ã€‚
回転ã—ã¦è¡¨ç¤ºãƒžãƒƒãƒ—ã®è¡¨ç¤ºã‚’å³ã«45度傾ã‘ã¾ã™ã€‚ゲーム画é¢ã¨ä¸Šä¸‹å·¦å³ãŒä¸€è‡´
ã—ã¾ã™ã€‚
産業ã®éœ€è¦å´Ž/供給元
ã“ã®ãƒœã‚¿ãƒ³ãŒã‚ªãƒ³ã®æ™‚ã¯ã€ç”£æ¥­æ–½è¨­ã«ãƒžã‚¦ã‚¹ãƒã‚¤ãƒ³ã‚¿ã‚’åˆã‚ã›ã‚‹ã¨ã€ç”Ÿç”£å“ã®
需è¦å…ˆã¨ç™½ã®ãƒ©ã‚¤ãƒ³ã§çµã°ã‚Œã¾ã™ã€‚[Shift]キーを押ã—ãªãŒã‚‰ç”£æ¥­æ–½è¨­ã«ãƒžã‚¦ã‚¹
ãƒã‚¤ãƒ³ã‚¿ã‚’åˆã‚ã›ã‚‹ã¨ã€åŽŸæ–™ã®ä¾›çµ¦å…ƒã¨èµ¤ã®ãƒ©ã‚¤ãƒ³ã§çµã°ã‚Œã¾ã™ã€‚

路線経路ã®è¡¨ç¤º
ã“ã®ãƒœã‚¿ãƒ³ãŒã‚ªãƒ³ã®æ™‚ã¯ã€è·¯ç·šç·¨é›†ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§è·¯ç·šãŒé¸æŠžã•れã¦ã„る時やã€
スケジュールウィンドウãŒé–‹ã‹ã‚Œã¦ã„る時ã«ã€ãã®çµŒè·¯ã®é§…ãŒç›´ç·šã§çµã°ã‚Œã¦
表示ã•れã¾ã™ã€‚
é§…ã®ä¸Šã«ãƒžã‚¦ã‚¹ãƒã‚¤ãƒ³ã‚¿ã‚’åˆã‚ã›ã‚‹ã¨ã€é§…åを表示ã—ã¾ã™ã€‚

カラースケール

産業凡例

è¡¨ç¤ºç¨®åˆ¥é¸æŠž: マップã®è¡¨ç¤ºå†…容を切り替ãˆã¾ã™ã€‚
[Ctrl]ã‚­ãƒ¼ãŒæŠ¼ã•れã¦ã„ã‚‹é–“ã¯ã€ç”ºã®åå‰ãŒä¸€æ™‚çš„ã«è¡¨ç¤ºã•れã¾ã™ã€‚

都市: 都市ã®åå‰ã‚’表示ã—ã¾ã™ã€‚デフォルトã§é¸æŠžã•れã¦ã„ã¾ã™ã€‚

旅客: æ—…å®¢å–æ‰±ã„é§…ã®é§…å‹¢åœã‚’プレイヤーカラーã§è¡¨ç¤ºã—ã¾ã™ã€‚

郵便: éƒµä¾¿å–æ‰±ã„é§…ã®é§…å‹¢åœã‚’プレイヤーカラーã§è¡¨ç¤ºã—ã¾ã™ã€‚

貨物: é“è·¯/ç·šè·¯ã®è²¨ç‰©é‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™ã€‚

å¾…åˆçŠ¶æ…‹: é§…ã®æ··é›‘ã®çŠ¶æ…‹ã‚’è¡¨ç¤ºã—ã¾ã™ã€‚
é§…ä¸€è¦§ã‚„é§…ã®æƒ…å ±ã§è¡¨ç¤ºã•れる色ã¨åŒã˜ã§ã™ã€‚

ç·¨æˆæ•°: ãã®é§…ã«åˆ°ç€ã—ãŸä¹—り物ã®ç·¨æˆæ•°ã®é‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™ã€‚

交通é‡: é“è·¯/ç·šè·¯ã®äº¤é€šé‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™

出発地: ãã®é§…を出発ã—ãŸæ—…客/貨物ã®é‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™

目的地: ãã®é§…ã«åˆ°ç€ã—ãŸæ—…客/貨物ã®é‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™

待機: 待機ã—ã¦ã„る旅客/貨物ã®é‡ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™

鉄é“ç·š: 鉄é“線を表示ã—ã¾ã™ã€‚
 白: éžé›»åŒ–
 茶: 電化
 黄: ä¿¡å·

制é™é€Ÿåº¦: é“è·¯/ç·šè·¯ã®åˆ¶é™é€Ÿåº¦ã‚’カラースケールã§è¡¨ç¤ºã—ã¾ã™

高圧線: 高圧線ã®é›»åŠ›ä¾›çµ¦çŽ‡ã‚’ã‚«ãƒ©ãƒ¼ã‚¹ã‚±ãƒ¼ãƒ«ã§è¡¨ç¤ºã—ã¾ã™ã€‚
自動更新ã•れã¾ã›ã‚“

忉€: 忉€æ—§è·¡ã‚’旅客度ã«åŸºã¥ã„ã¦ã‚«ãƒ©ãƒ¼ã‚¹ã‚±ãƒ¼ãƒ«ã§è¡¨ç¤ºã—ã¾ã™

産業: 産業施設を凡例ã®è‰²ã§è¡¨ç¤ºã—ã¾ã™

車庫: 自社ã®è»Šåº«ãƒ»æ©Ÿé–¢åº«ãƒ»é€ èˆ¹æ‰€ã‚’ãƒã‚¤ãƒ©ã‚¤ãƒˆã—ã¾ã™ã€‚
交通機関ã®ç¨®é¡žã”ã¨ã«ã€ç•°ãªã‚‹è‰²ã§è¡¨ç¤ºã•れã¾ã™ã€‚
 赤:  造船所
 黄:  自動車車庫
 橙:  機関庫
 臙脂: モノレール車庫
 桃:  航空機格ç´åº«

森: 樹木ã®å¤šã„場所を緑色ã®ç‚¹ã§è¡¨ç¤ºã—ã¾ã™ã€‚
市域: 都市ã®å¸‚域ã®å¢ƒç•Œç·šã‚’ã€æ°´è‰²ã§è¡¨ç¤ºã—ã¾ã™ã€‚
旅客/郵便目的地: è¡—ã®è©³ç´°ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒé–‹ã‹ã‚Œã¦ã„る時ã€
ãã®éƒ½å¸‚ã®æ—…客/郵便目的地をリアルタイムã«è¡¨ç¤ºã—ã¾ã™ã€‚
è¡—ã®è©³ç´°ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®å³ä¸Šã«è¡¨ç¤ºã•れã¦ã„ã‚‹ã‚‚ã®ã¨åŒã˜ã§ã™ã€‚
 オレンジ: 目的地ã¸å‡ºç™ºã§ããŸ
 黄色:   目的地ã¸å‡ºç™ºã§ããªã‹ã£ãŸ

simutrans-124.3/simutrans/text/ja/monorailtools.txt000066400000000000000000000216421474050137200226250ustar00rootroot00000000000000モノレール/リニアツールã®ãƒ˜ãƒ«ãƒ—

モノレール/リニアツール

モノレール/リニアツールã§ã¯ã€ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®äº¤é€šç¶²ã‚’作æˆã—ã¾ã™ã€‚ã“ã“ã§ã¯ã€ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ã‚„リニアã®è»Œé“ã‚„æ©‹æ¢ã€ãƒˆãƒ³ãƒãƒ«ã€ä¿¡å·ã€è»Šåº«ã€é§…ã®ãƒ›ãƒ¼ãƒ ãªã©ã®å»ºè¨­ã‚„å–り壊ã—ãŒå¯èƒ½ã§ã™ã€‚年代設定を有効ã«ã—ã¦ã„ã‚‹å ´åˆã€Simutransã§ã®æ™‚é–“ãŒçµŒéŽã™ã‚‹ã«ã¤ã‚Œã¦æ–°ãŸãªãƒ„ールオプションãŒå‡ºç¾ã—ã¾ã™ã€‚

ゲーム画é¢ã®ä¸€ç•ªä¸Šã«ã‚るモノレール/リニアツールã¨ã„ã†ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã—ã¦ã€ãƒ„ールãƒãƒ¼ã‚’é–‹ãã¾ã™ã€‚
ãã†ã—ãŸã‚‰ã€ãƒ„ールオプションã«ãƒžã‚¦ã‚¹ã®ã‚«ãƒ¼ã‚½ãƒ«ã‚’ä¹—ã›ã¦åå‰ã‚„建設費ã€ç¶­æŒè²»ã€æœ€é«˜é€Ÿåº¦ã‚„最大長ãŒé©åˆ‡ã§ã‚ã‚‹ã‹ã‚’確èªã—ã¾ã™ã€‚

モノレール/リニアツールã¯2ã¤ã®ã©ã¡ã‚‰ã‚‚å«ã¿ã¾ã™ã€‚

モノレール/リニアã®è»Œé“ ã“ã®ãƒ„ールã¯ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ã¨ãƒªãƒ‹ã‚¢ã®ä¸¡æ–¹ã®ä¹—り物ã«ã¤ã„ã¦è»Œé“を建設ã—ã¾ã™ã€‚軌é“ã¯ã‚¹ãƒ­ãƒ¼ãƒ—ã®æ–¹å‘ã«å¯¾ã—ã¦ã‚¹ãƒ­ãƒ¼ãƒ—上ã‚ã‚‹ã„ã¯å¹³é¢ä¸Šã«ã—ã‹å»ºè¨­ã§ããšã€ãã—ã¦è’ã„地形や水ã€éšœå®³ç‰©ã‚’横切ã£ãŸçµŒè·¯ã‚’使用ã§ãã¾ã›ã‚“。新ãŸã«å»ºè¨­ã•れる軌é“ã¯ã€çµŒè·¯ä¸Šã®æ—¢å­˜ã®è»Œé“を使用ã—ã¾ã™ã€‚
軌é“を建設ã™ã‚‹ã«ã¯ãƒ„ールをクリックã—ã¦è»Œé“ã‚’é¸æŠžã—ã€ã‚²ãƒ¼ãƒ ç”»é¢ã«ã‚る軌é“ã®å§‹ã¾ã‚Šã‚’クリックã—ã¾ã™ã€‚(ãã®ã¨ãã€ç”»é¢ã«ãƒ–ルドーザーãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ãã—ã¦ã€ã‚²ãƒ¼ãƒ ç”»é¢ã«ã‚る軌é“ã®çµ‚ã‚りをクリックã—ã¾ã™ã€‚
{ヒント 様々ãªã‚¿ã‚¤ãƒ—ã®è»Œé“を繋ã’ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚(他ã®ãƒ—レーヤーã«ã‚ˆã£ã¦å»ºè¨­ã•れãªã„é™ã‚Šï¼‰
軌é“ã®å»ºè¨­ã§ãる通りé“ã«ã™ã‚‹ã«ã¯ã€ã‚¹ãƒ­ãƒ¼ãƒ—ツールを使ã£ã¦åœ°å½¢ã‚’変ãˆã¾ã™ã€‚
個々ã®ã€ã²ã¨ã¤ã®è»Œé“や障害物を撤去ã™ã‚‹ã«ã¯ã€æ’¤åŽ»/å–り壊ã—を使ã„ã¾ã™ã€‚
ç‰¹åˆ¥ãªæ©Ÿèƒ½ã‚’使ã†ãŸã‚ã«ã¯ã€åŒæ™‚ã«[Ctrl]を押ã—ã¾ã™ã€‚[z]を押ã™ã¨æœ€æ–°ã®å»ºè¨­ãƒ«ãƒ¼ãƒˆã‚’å–り消ã›ã¾ã™ãŒã€å»ºè¨­è²»ã¯æ‰•ã„æˆ»ã•れã¾ã›ã‚“。}

ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ã®æ’¤åŽ»ã€€ã“ã®ãƒ„ールã¯ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®è»Œé“ã‚’ã€ä¹—り物ãŒå­˜åœ¨ã›ãšã€äºŒã¤ã®åœ°ç‚¹ãŒã‚²ãƒ¼ãƒ ç”»é¢ã«ã‚ã‚‹æ™‚ã«æ’¤åŽ»ã—ã¾ã™ã€‚(経路上ã®ãƒ—ラットホームや信å·ã‚‚撤去ã•れã¾ã™ï¼‰
ツールを使ã†ã“ã¨ã§ã€å»ºè¨­è²»ãŒã‹ã‹ã‚Šã¾ã™ã€‚
軌é“を撤去ã™ã‚‹ã«ã¯ãƒ„ールをクリックã—ã¾ã™ã€‚(カーソルãŒèµ¤ã„ãƒãƒ„å°ã«å¤‰ã‚りã¾ã™ï¼‰æ¶ˆåŽ»ã™ã‚‹è»Œé“をクリックã—ã¾ã™ã€‚(赤ã„ãƒãƒ„å°ã§ç¤ºã•れãŸå‰Šé™¤åœ°ç‚¹ã‚’é¸æŠžã—ã¾ã™ï¼‰ãã—ã¦ã€è»Œé“上ã®åœ°ç‚¹ã®ã‚‚ã†ä¸€æ–¹ã‚’クリックã—ã¦ã€æœ€åˆã®å‰Šé™¤åœ°ç‚¹ã¾ã§æ’¤åŽ»ã—ã¾ã™ã€‚
{ヒント 他ã®ãƒ—レーヤーã¨ã—ã¦ã€ãれらã®è»Œé“を撤去ã™ã‚‹ãŸã‚ã«æ“作ã—ã¾ã™ã€‚ï½

ãƒ©ãƒ³ãƒ—ã¨æ©‹æ¢ã€€ã“ã®ãƒ„ールã¯ã€ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®ä¹—り物ãŒãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã¨ã„ã†2ã¤ã®ã€è»Œé“を通るãŸã‚ã«ç›´ç·šã®æ©‹æ¢ã‚’建設ã—ã¾ã™ã€‚æ©‹æ¢ã«ã¯æœ€å¤§é•·ãŒã‚りã¾ã™ã€‚軌é“ã®ç«¯ã‹ã‚‰é©åˆ‡ãªå ´æ‰€ï¼ˆæœ€å¤§é•·ã®ç¯„囲内ã§ã€è»Œé“ã®ã‚‚ã†ä¸€æ–¹ã®ç«¯ã‚ã‚‹ã„ã¯å°‘ã—高ã„åœŸåœ°ï¼‰ã«æ©‹æ¢ã‚’建設ã—ã¾ã™ã€‚
ランプや橋æ¢ã‚’建設ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ã¾ã™ã€‚ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒæ©‹æ¢ã«å¤‰ã‚りã¾ã™ã€‚)ãã—ã¦ã€è»Œé“ã®ç«¯ï¼ˆæ©‹æ¢ã®å§‹ã¾ã‚Šï¼‰ã‚’クリックã—ã¦å»ºè¨­ã—ã¾ã™ã€‚障害物ãŒã‚ã£ãŸã‚Šã€ã‚ã‚‹ã„ã¯æ©‹æ¢ã®ç«¯ã«å¯¾ã™ã‚‹é©åˆ‡ãªå ´æ‰€ãŒãªã‹ã£ãŸã‚Šã™ã‚‹ã¨æž¶æ©‹ã•れã¾ã›ã‚“。架橋ã•れる両å´ã«è»Œé“ã‚’ç½®ãã€ã‚‚ã†ä¸€åº¦è©¦ã—ã¾ã—ょã†ã€‚
{ヒント 橋æ¢ã‚„ã€æž¶æ©‹ã™ã‚‹ã“ã¨ã«å¯¾ã™ã‚‹éšœå®³ç‰©ã‚’撤去ã™ã‚‹ãŸã‚ã«ã¯æ’¤åŽ»/å–り壊ã—を使ã„ã¾ã™ã€‚(橋æ¢ã‚’撤去ã™ã‚‹ã«ã¯æ©‹æ¢ã®ç«¯ã‚’をクリックã—ã¾ã™ã€‚)
æ©‹æ¢ã®ç«¯ã‚’軌é“ã«æŽ¥ç¶šã™ã‚‹ãŸã‚ã«ã¯è»Œé“ã®ãƒ„ールを使用ã—ã¾ã™ã€‚}

モノレールã®ä¿¡å·ã€€ã“ã®ãƒ„ールã¯ã€ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«ã¨ãƒªãƒ‹ã‚¢ã®ä¹—り物ã«å¯¾ã™ã‚‹ä¿¡å·ã‚’建設ã—ã¾ã™ã€‚ä¿¡å·ã¯è»Œé“ã‚„æ©‹æ¢ã€åˆ†å²ç‚¹ã€ï¼ˆä¹—り物ãŒä¹—客を乗ã›ãŸã‚Šä¸‹ã‚ã—ãŸã‚Šã™ã‚‹ï¼‰åœè»Šå ´ä¸Šã®ä¹—ã‚Šç‰©ã®æµã‚Œã‚’振り分ã‘ã€è¦åˆ¶ã—ã¾ã™ã€‚
ä¿¡å·ã®äºŒæ–¹å‘ã¨ä¸€æ–¹å‘ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’建設ã§ãã¾ã™ã€‚軌é“上ã«äºŒæ–¹å‘ã®ä¿¡å·ã‚’建設ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã—ã¦ä¿¡å·ã‚’é¸æŠžã—ã¾ã™ã€‚(カーソルãŒä¿¡å·ã«å¤‰ã‚りã¾ã™ã€‚)ãã—ã¦ã€è»Œé“をクリックã—ã¾ã™ã€‚一方å‘ã®ä¿¡å·ã‚’建設ã™ã‚‹ã«ã¯ã€åŒã˜å ´æ‰€ã‚’ä¿¡å·ã®ã‚«ãƒ¼ã‚½ãƒ«ã§ã‚‚ã†ä¸€åº¦ã‚¯ãƒªãƒƒã‚¯ã—ã¦ã€ä¸€æ–¹å‘ã®ä¿¡å·ã‹ã‚‰å¾ªç’°ã—ã€äºŒæ–¹å‘ã®ä¿¡å·ã¸æˆ»ã£ã¦ãã¾ã™ã€‚
é‡è¦ã€€è»Šä¸¡ãŒæ­£ã—ãé‹è¡Œã•れãªã„ã“ã¨ã«ã‚ˆã£ã¦ã€è»Šä¸¡ãŒè¡Œãå…ˆã«åˆ°ç€ã™ã‚‹ã®ã‚’妨ã’るよã†ãªä¸€æ–¹å‘ã®ä¿¡å·ã‚’ç½®ã‹ãªã„よã†ã«æ³¨æ„ã—ã¾ã—ょã†ã€‚(simuconf.tabã§å¤‰æ›´ã§ãã¾ã™ã€‚)
- ä¿¡å·ã€€æ¬¡ã®ä¿¡å·ã®ã€å‰æ–¹ã®è»Œé“ã€ã‚ã‚‹ã„ã¯ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ï¼ˆåœè»Šå ´ã‚„中継地点)ãŒä»–ã®è»Šä¸¡ã«ã‚ˆã£ã¦äºˆç´„ã•れã¦ã„ãªã„å ´åˆã«é™ã‚Šè»Šä¸¡ã¯é€²ã¿ã¾ã™ã€‚一方å‘モードã«ãŠã„ã¦ã¯ã€è»Šä¸¡ã¯ã²ã¨ã¤ã®æ–¹å‘ã«å¯¾ã—ã¦ã®ã¿é€šã‚Šã¾ã™ã€‚
- 入線振分信å·ã€€ç©ºãã®ã‚ã‚‹é§…ã®ãƒ›ãƒ¼ãƒ ã‚„ã€ãƒ›ãƒ¼ãƒ ãŒè¤‡æ•°ã‚ã‚‹åœè»Šå ´ã§è»Šä¸¡ã‚’振り分ã‘ã¾ã™ã€‚ã“ã®ä¿¡å·ã‚’通éŽã™ã‚‹è»Šä¸¡ã¯ã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸãŸã£ãŸä¸€ã¤ã ã‘ã§ãªãã€æ¬¡ã®è¡Œãå…ˆã®ã€ç©ºãã®ã‚ã‚‹ã‚らゆるホームを使ãˆã¾ã™ã€‚ã‚‚ã—ホームã«ç©ºãã‚„ã€æ¬¡ã®è¡Œãå…ˆã¸ã®æ˜Žã‚‰ã‹ãªãƒ«ãƒ¼ãƒˆãŒç„¡ã„ã“ã¨ãŒã‚ã‹ã‚‹å ´åˆã€è»Šä¸¡ã¯ä¿¡å·ã§å¾…機ã—ã¾ã™ã€‚
{ヒント 撤去/å–り壊ã—ã§ä¿¡å·ã‚’撤去ã—ã¾ã™ã€‚軌é“上ã«ä¿¡å·ã‚’連続ã§è¨­ç½®ã™ã‚‹ãŸã‚ã«ã¯[Ctrl]を押下ã—ã¾ã™ã€‚}

モノレール 車庫 ã“ã®ãƒ„ールã¯ã€ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®è»Šä¸¡ã‚’購入ã—ãŸã‚Šç®¡ç†ã—ãŸã‚Šã™ã‚‹ãŸã‚ã®è»Šåº«ã‚’建設ã—ã¾ã™ã€‚車庫ã¯ç¶­æŒè²»ãŒã‚りã€ãã—ã¦ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®è»Œé“ã®ç«¯ã«å»ºè¨­ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚
モノレールã®è»Šåº«ã‚’建設ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã—ã€ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒè»Šåº«ã«å¤‰ã‚りã¾ã™ã€‚)軌é“ã®ç«¯ã‚’クリックã—ã¾ã™ã€‚

列車ã®åœè»Šå ´ã€€ã“ã®ãƒ„ールã¯ã€ä¹—客や郵便物を乗ã›ãŸã‚Šä¸‹ã‚ã—ãŸã‚Šã™ã‚‹ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニアã®è»Šä¸¡ã«ã‚ˆã£ã¦ä½¿ã‚れるã€é§…ã®ãƒ›ãƒ¼ãƒ ã‚’建設ã—ã¾ã™ã€‚
既存ã®åœè»Šå ´ã«è¿‘接ã—ã¦å»ºè¨­ã•れる場åˆã‚’除ãã€é§…ã®ãƒ›ãƒ¼ãƒ ã¯æ–°ãŸãªåœè»Šå ´ã‚’生æˆã—ã¾ã™ã€‚
列車ã®åœè»Šå ´ã«ã¯ç¶­æŒè²»ãŒã‚りã€ãã—ã¦è»Œé“上ã«å»ºè¨­ã•れる必è¦ãŒã‚りã¾ã™ã€‚(ãŸã ã—ã€è»Œé“ã®æ›²ãŒã£ãŸã¨ã“ã‚や分å²ç‚¹ã§ã¯å»ºè¨­ã•れã¾ã›ã‚“。)
列車ã®åœè»Šå ´ã¯è²¨ç‰©ã‚„乗客ã€éƒµä¾¿ç‰©ã®ç®¡è½„区域ã§ã™ã€‚ 様々ãªé§…ã®ãƒ›ãƒ¼ãƒ ã«ã¯è²¨ç‰©ã‚„乗客ã€éƒµä¾¿ç‰©ã®ã•ã¾ã–ã¾ãªå®¹é‡ãŒã‚りã¾ã™ã€‚ツールオプションã®é¢ã§ã¯ã€ï¼ˆåœè»Šå ´ãƒªã‚¹ãƒˆã‚„åœè»Šå ´ã®æƒ…å ±ã§ä½¿ã‚れる)アイコンã¯ã€åœè»Šå ´ã§æ‰±ã†ã‚ˆã†ã«é§…ã®ãƒ›ãƒ¼ãƒ ãŒæŒ‡å®šã™ã‚‹ã‚¢ã‚¤ãƒ†ãƒ ãŒã©ã‚Œã‹ã‚’示ã—ã¾ã™ã€‚
{ヒント 撤去/å–り壊ã—ã§åˆ—車ã®åœè»Šå ´ã‚’撤去ã—ã¾ã™ã€‚
より長ãã€ã‚ˆã‚ŠãŸãã•ã‚“ã®è»Šä¸¡ã«å¯¾å¿œã—ã€å®¹é‡ã‚„å—ã‘æŒã¡åŒºåŸŸã‚’増やã™ãŸã‚ã«ã¯ã€ï¼ˆè¿‘接ã™ã‚‹è»Œé“上ã®åŒºåŸŸã«ã‚ˆã‚Šå¤šãホームを建設ã™ã‚‹ã“ã¨ã§ã€ï¼‰é§…ã®ãƒ›ãƒ¼ãƒ ã‚’広ã’ãŸã‚Šã€è¤‡æ•°ã®ãƒ›ãƒ¼ãƒ ã®åœè»Šå ´ã‚’建設ã—ã¾ã™ã€‚
貨物や乗客ã®å—ã‘æŒã¡åŒºåŸŸã‚’ゲーム画é¢ä¸Šã«è¡¨ç¤º/éš ã™ãŸã‚ã«ã¯[v]を押ã—ã¾ã™ã€‚}

モノレール基部 ã“ã®ãƒ„ールã¯ã€åœè»Šå ´ã®å»¶é•·ã‚’ã—ãŸã‚Šã€åœè»Šå ´ã®å®¹é‡ã‚’増やã—ã¾ã™ã€‚モノレール基部ã¯ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«/リニア軌é“ã®ç«¯ã«å»ºè¨­ã•れる必è¦ãŒã‚りã€ç¶­æŒè²»ãŒã‹ã‹ã‚Šã¾ã™ã€‚
モノレール基部を建設ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ã€ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒåŸºéƒ¨ã«å¤‰ã‚りã¾ã™ã€‚)軌é“ã®ç«¯ã®å¿…è¦ãªå ´æ‰€ã‚’クリックã—ã¾ã™
{ヒント 撤去/å–り壊ã—ã§ãƒ¢ãƒŽãƒ¬ãƒ¼ãƒ«åŸºéƒ¨ã‚’撤去ã—ã¾ã™ã€‚}

simutrans-124.3/simutrans/text/ja/new_world.txt000066400000000000000000000063441474050137200217260ustar00rootroot00000000000000æ–°ã—ã„マップã®ä½œæˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãƒ˜ãƒ«ãƒ—

æ–°ã—ã„マップã®ä½œæˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°

 新ã—ã„マップã®ä½œæˆãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ã¯ã€æ–°ã—ã„マップ(ゲーム)を作æˆã™ã‚‹ã«
ã‚ãŸã£ã¦ã®è¨­å®šã‚’ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚マップã®ã‚µã‚¤ã‚ºã‚„ã€ç”£æ¥­ã®å映度ãªã©
ãŒè¨­å®šå‡ºæ¥ã¾ã™ã€‚

ã€€ä»¥ä¸‹ã¯æ–°ã—ã„マップã«é–¢ã™ã‚‹å„オプションã«ã¤ã„ã¦ã®èª¬æ˜Žã§ã™ã€‚

ãƒžãƒƒãƒ—ç•ªå· ï¼ åœ°å½¢ã‚„ã€éƒ½å¸‚ã®ä½ç½®ã‚’決定ã—ã¾ã™ã€‚番å·ã‚’変更ã™ã‚‹ãŸã³ã«ãƒ—
レビューも更新ã•れã¾ã™ï¼ˆä»–ã®ã‚ªãƒ—ションを変更ã—ã¦ã‚‚æ›´æ–°ã•れã¾ã™ï¼‰ã€‚デフォ
ルトã®ãƒžãƒƒãƒ—番å·ã¯33ã§ã™ã€‚
マップサイズ ï¼ ãƒžãƒƒãƒ—ãŒä½•ã‚¿ã‚¤ãƒ«ã§æ§‹æˆã•れるã‹ã‚’128×128ã‹ã‚‰640×640
タイルã®ç¯„囲ã§è¨­å®šã—ã¾ã™ã€‚デフォルトã¯256ã§ã™ã€‚
注æ„マップãŒå¤§ãã‘れã°å¤§ãã„ã»ã©ç©ºãメモリãŒå¿…è¦ã¨ãªã‚Šã¾ã™ã€‚プレイã™
ã‚‹ã«ã‚ãŸã£ã¦ã¯å……分ãªç©ºãメモリãŒç¢ºä¿ã•れã¦ã„ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„。

産業ã®å映度 ï¼ æ²¹ç”°ã‚„è‡ªå‹•è»Šå·¥å ´ãªã©ã€ã©ã‚Œãらã„ã®ç”£æ¥­ã‚’é…ç½®ã™ã‚‹ã‹è¨­
定ã—ã¾ã™ã€‚ã“ã®æ•°å€¤ã‚’低ãã™ã‚‹ã¨ã€å·¥å ´ã‚„生産地ã®é–“ã§ã®è¼¸é€ãŒã—ã«ãããªã‚‹
ã®ã§ã€ã‚²ãƒ¼ãƒ ãŒé›£ã—ããªã‚Šã¾ã™ã€‚
ç”ºã®æ•° ï¼ ãƒžãƒƒãƒ—ä¸Šã«ç”ºã‚’ã„ãã¤é…ç½®ã™ã‚‹ã‹ã‚’設定ã—ã¾ã™ã€‚2ã‹ã‚‰64ã®é–“ã§
設定ãŒå‡ºæ¥ã¾ã™ã€‚デフォルトã¯16ã§ã™ã€‚
äº¤é€šé‡ ï¼ è‡ªå®¶ç”¨è»Šã®äº¤é€šé‡ã‚’設定ã—ã¾ã™ã€‚デフォルトã¯8ã§ã™ã€‚

æµ·é¢ã®æ°´ä½ ï¼ æµ·é¢ã®é«˜ã•を設定ã—ã¾ã™ã€‚æ°´ä½ãŒä½Žã„ã»ã©é™¸åœ°ã¯åºƒããªã‚Šã€
高ã„ã»ã©ç‹­ããªã‚Šã¾ã™ã€‚デフォルトã¯4ã§ã™ã€‚
èµ·ä¼ã®é«˜ã• ï¼ èµ·ä¼ã®æœ€é«˜å€¤ã‚’設定ã—ã¾ã™ã€‚ã“ã®æ•°å€¤ãŒä½Žã„ã»ã©ä¸˜ã‚„è°·ã®æ•°
ãŒå°‘ãªããªã‚Šã¾ã™ã€‚0ã‹ã‚‰160ã®ç¯„囲ã§è¨­å®šã§ãã¾ã™ã€‚デフォルトã¯160ã§ã™ã€‚
èµ·ä¼ã®æ¿€ã—ã• ï¼ èµ·ä¼ã®æ¿€ã—ã•を設定ã—ã¾ã™ã€‚ã“ã®æ•°å€¤ãŒå°‘ãªã„ã»ã©è‡ªå‹•車
や列車ã§ã®è¼¸é€ãŒæ¥½ã«ãªã‚Šã¾ã™ã€‚

ランダムマップ ï¼ ãƒžãƒƒãƒ—ç•ªå·ã‚’ランダムã«é¸æŠžã—ã¾ã™ï¼ˆä»–ã®è¨­å®šã«ã¯å½±éŸ¿
ã—ã¾ã›ã‚“)。

歩行者を表示ã™ã‚‹ ï¼ ç”ºä¸­ã‚’é€šè¡Œã—ã¦ã„る歩行者を表示ã™ã‚‹ã‹ã©ã†ã‹ã‚’設定
ã—ã¾ã™ã€‚ã“ã®è¨­å®šã¯ã‚²ãƒ¼ãƒ ä¸­ã§ã‚‚表示オプション
ダイアログã«ã¦å¤‰æ›´å¯èƒ½ã§ã™ï½¡
å¤œã¯æš—ãã™ã‚‹ï¼1æ—¥ã®æ˜¼ã¨å¤œã®ã‚µã‚¤ã‚¯ãƒ«ã«ã‚ˆã£ã¦ç”»é¢ã®æ˜Žã‚‹ã•を変ãˆã¾ã™ã€‚ã“
ã®è¨­å®šã¯ã‚²ãƒ¼ãƒ ä¸­ã§ã‚‚表示オプションダイアログã«ã¦å¤‰æ›´å¯èƒ½ã§ã™ã€‚

ロード ï¼ ä¿å­˜ã•れã¦ã„るゲームをロードã—ã¾ã™ï¼ˆè©³ã—ãã¯ãƒ­ãƒ¼ãƒ‰ãƒ€ã‚¤ã‚¢ãƒ­
ã‚°ã‚’ã”覧下ã•ã„)。
ゲームスタート ï¼ å„設定を用ã„ã¦ãƒžãƒƒãƒ—を作æˆã—ã¾ã™ã€‚大ãã„マップã»ã©
æ™‚é–“ãŒæŽ›ã‹ã‚Šã¾ã™ã€‚
終了ï¼ç›´ã¡ã«Simutrans を終了ã—ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/options.txt000066400000000000000000000037401474050137200214160ustar00rootroot00000000000000ゲームオプションヘルプ

ゲームオプション

ゲームオプションã§ã¯Simutransã®ã‚ªãƒ—ションã®ç¢ºèªã¨å¤‰æ›´ãŒã§ãã¾ã™ã€‚ゲームã®çµ‚了もã“ã“ã‹ã‚‰è¡Œã„ã¾ã™ã€‚

ゲームオプションã¯ãƒ„ールãƒãƒ¼ã®å·¥å…·ã®ã‚¢ã‚¤ã‚³ãƒ³ã‹ã‚‰é–‹ãã“ã¨ãŒã§ãã¾ã™ã€‚

ゲームオプションã§è¨­å®šã§ãã‚‹é …ç›®:

言語: 使用ã™ã‚‹è¨€èªžã‚’設定ã—ã¾ã™ã€‚

ライãƒãƒ«ä¼šç¤¾: ゲームã«å‚加ã™ã‚‹(AIã‚’å«ã‚€)プレイヤーã®è¨­å®šãŒãã¾ã™ã€‚公共事業もã“ã“ã«å«ã¾ã‚Œã¾ã™ã€‚

プレイヤーã®è‰²: プレイヤーã®ä¼šç¤¾ã®è‰²ã‚’設定ã—ã¾ã™ã€‚

表示設定: 表示ã«é–¢ã™ã‚‹è¨­å®šã‚’行ã„ã¾ã™ã€‚

サウンド: 効果音ã¨BGMã®è¨­å®šã‚’行ã„ã¾ã™ã€‚

æ–°ã—ã„ゲーム: æ–°è¦ã«ã‚²ãƒ¼ãƒ ã‚’å§‹ã‚るダイアログを表示ã—ã¾ã™ã€‚

ゲームã®å†é–‹: ä¿å­˜ï¼ˆã‚»ãƒ¼ãƒ–)ã—ãŸã‚²ãƒ¼ãƒ ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ã¾ã™ã€‚

ゲームã®ä¿å­˜: ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã®çŠ¶æ…‹ã‚’ä¿å­˜ï¼ˆã‚»ãƒ¼ãƒ–)ã—ã¾ã™ã€‚

シナリオを読ã¿è¾¼ã‚€: ゲームシナリオを読ã¿è¾¼ã‚€ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ã€‚シナリオã¯å®šã‚られãŸã‚´ãƒ¼ãƒ«(æ¡ä»¶)ã®é”æˆã‚’目指ã™ãƒ—レーモードã§ã™ã€‚

シナリオ情報: 通常ã®ãƒ—レーã§ã¯ã“ã®ãƒœã‚¿ãƒ³ã¯ç„¡åйã«ãªã£ã¦ã„ã¾ã™ã€‚シナリオプレー中ã®ã¿ã“ã®ãƒœã‚¿ãƒ³ã§ã‚·ãƒŠãƒªã‚ªã®è©³ç´°ã‚’表示ã§ãã¾ã™ã€‚

ゲーム終了: Simutransを終了ã—ã¾ã™ã€‚ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã¯ä¸€æ™‚データã¨ã—ã¦ä¿å­˜ã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/password.txt000066400000000000000000000031401474050137200215570ustar00rootroot00000000000000パスワード設定ウィンドウヘルプ

パスワード設定ウィンドウ

 ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§ã¯ã€ä¼šç¤¾åã®å¤‰æ›´ã¨ãƒ‘スワードã®å…¥åŠ›ã€å¤‰æ›´ã€è§£é™¤ãŒã§ã
ã¾ã™ã€‚入力内容ã¯[Enter]キーã§ç¢ºå®šã—ã¾ã™ã€‚
パスワードã¯ä¸»ã«ã€ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‚²ãƒ¼ãƒ ã§ä½¿ç”¨ã•れã¾ã™ãŒã€ãƒ—レイヤーã®å¤‰æ›´ã‚’
ç¦æ­¢ã—ãŸã„å ´åˆã«ã‚‚ã€å…¬å…±äº‹æ¥­ã«ãƒ‘スワードを設定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚

ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯ã€ãƒ©ã‚¤ãƒãƒ«ä¼šç¤¾ä¸€è¦§ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰é–‹ãã“ã¨ãŒã§ãã¾ã™ã€‚
ã¾ãŸã€ãƒ­ãƒƒã‚¯ã•れã¦ã„るプレイヤーをæ“作ã—よã†ã¨ã—ãŸæ™‚ã«ã‚‚é–‹ã‹ã‚Œã¾ã™ã€‚

会社åã®å¤‰æ›´
プレイヤーãŒãƒ­ãƒƒã‚¯ã•れã¦ã„ãªã„å ´åˆã€ä¼šç¤¾åを変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
ã“ã®ä¼šç¤¾åã¯ã‚»ãƒ¼ãƒ–ゲームã”ã¨ã«ä¿å­˜ã•れã€å¾Œã‹ã‚‰å¤‰æ›´ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚

パスワードã®å…¥åŠ›
ロックã•れã¦ã„ã‚‹å ´åˆ
プレイヤーãŒãƒ­ãƒƒã‚¯ã•れã¦ã„ã‚‹å ´åˆã€ãƒ‘スワードを入力ã—ã¦ãƒ­ãƒƒã‚¯ã‚’解除ã—
ã¾ã™ã€‚
ロックã•れã¦ã„ãªã„å ´åˆ
入力ã—ãŸãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ãŒæ–°è¦ã«è¨­å®šã•れã€ã¾ãŸã¯ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ãŒæ›´æ–°ã•れã¾ã™ã€‚
パスワードã«ä½•も指定ã›ãšã«[Enter]キーを押ã™ã¨ã€ãƒ‘スワードä¿è­·ãŒè§£é™¤ã•れã¾ã™ã€‚

注æ„:公共事業プレイヤーã¯ã€ãƒ­ãƒƒã‚¯ã•れã¦ã„る他社ã®ãƒ‘スワードを強制的ã«å¤‰æ›´
ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/players.txt000066400000000000000000000107341474050137200214030ustar00rootroot00000000000000ライãƒãƒ«ä¼šç¤¾ä¸€è¦§ã€€ãƒ˜ãƒ«ãƒ—

ライãƒãƒ«ä¼šç¤¾ä¸€è¦§

プレイヤーå
クリックã™ã‚‹ã¨ã€ãれãžã‚Œã®ãƒ—レイヤーã®è²¡å‹™ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒé–‹ã‹ã‚Œã¾ã™ã€‚
プレイヤーåã®å³å´ã«ã¯ã€å„プレイヤーã®ç¾åœ¨ã®ç¾é‡‘ãŒç¤ºã•れã¦ã„ã¾ã™ï½¡

プレイヤーã®è‰²ã‚’変更ã—ãŸã„å ´åˆã¯ã€å³å‘ã三角ボタンã§å¤‰æ›´ã—ãŸã„
プレイヤーã«åˆ‡ã‚Šæ›¿ãˆã¦ã‹ã‚‰ã€ã‚«ãƒ©ãƒ¼ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§å¤‰æ›´ã—ã¾ã™ã€‚

プレイヤーã®è¿½åŠ 
■ボタンã§ã€æ–°ã—ã„プレイヤー会社を追加ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
一度追加ã—ãŸãƒ—レイヤーをã€ã‚ã¨ã‹ã‚‰å–り除ã„ãŸã‚Šã€ã‚¹ãƒ­ãƒƒãƒˆã‚’開放ã™ã‚‹
ã“ã¨ã¯ã§ãã¾ã›ã‚“。

プレイヤーã®ç¨®é¡žã‚’ã€ãƒ—レイヤー(人間)ã€AI 貨物ã€AI 旅客ã‹ã‚‰é¸ã³ã€
左端ã®â– ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦æœ‰åйã«ã—ã¾ã™ã€‚

AIã®æœ‰åй/無効
AIãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ãŒæœ‰åйãªå ´åˆã€â– ãƒœã‚¿ãƒ³ã§AIã®æœ‰åй/無効を切り替ãˆã‚‹ã“ã¨
ãŒã§ãã¾ã™ã€‚
オフã«ã™ã‚‹ã¨ã€æ–°è¦è·¯ç·šã®é–‹æ‹“や資産ã®å£²å´ãªã©ã®æ´»å‹•ã‚’åœæ­¢ã—ã¾ã™ã€‚
ç¾åœ¨é‹è¡Œã•れã¦ã„ã‚‹ã‚‚ã®ã¯ã€ãã®ã¾ã¾é‹è¡Œã‚’継続ã—ã¾ã™ã€‚
経路ãŒè¦‹ã¤ã‹ã‚‰ãªã„ç·¨æˆãªã©ã®å•題ã«ã‚‚対処ã§ããªããªã‚Šã¾ã™ã€‚

プレイヤーã®åˆ‡ã‚Šæ›¿ãˆ
å³å‘ãä¸‰è§’ãƒœã‚¿ãƒ³ã§æ“作ã§ãるプレイヤーを切り替ãˆã¾ã™ã€‚
プレイヤーã®åˆ‡ã‚Šæ›¿ãˆã¯ã€ç‰¹æ®Šå»ºç¯‰ç‰©ãƒ„ールã®[プレイヤーã®å¤‰æ›´]ã§æ˜‡é †
ã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚([Shift+P])
ç¾åœ¨ã®ãƒ—レイヤーåã¯ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒãƒ¼ã«è¡¨ç¤ºã•れã¾ã™ã€‚

ゲームã®ãƒ«ãƒ¼ãƒ«ã§ãƒ—レイヤーã®å¤‰æ›´ãŒç¦æ­¢ã•れã¦ã„ã‚‹å ´åˆã«ã¯ã€ãƒ—レイヤー
を変更ã™ã‚‹ã“ã¨ã¯ä¸€åˆ‡ã§ãã¾ã›ã‚“。
プレイヤーã®å¤‰æ›´ã®ç¦æ­¢ã¯ã€æ–°è¦ãƒžãƒƒãƒ—ä½œæˆæ™‚ã«è¨­å®šã§ãã‚‹ã»ã‹ã€
マップ編集ツールã‹ã‚‰ã‚‚ã§ãã¾ã™ã€‚
プレイヤーã®å¤‰æ›´ã®ç¦æ­¢ã‚’ã€å¾Œã‹ã‚‰å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。

プレイヤーã®ç¨®é¡ž
æ–°ã—ã„マップã®é–‹å§‹æ™‚ã«ã¯ã€ãƒ—レイヤー会社ã¨å…¬å…±äº‹æ¥­ã®ã¿ãŒæœ‰åйã§ã™ã€‚

プレイヤー会社: ã‚ãªãŸã®ä¼šç¤¾ã§ã™

公共事業: 公共事業ã¯ã€å½¹æ‰€ã€ç”£æ¥­æ–½è¨­ã€å所旧跡ãªã©ã‚’所有ã—ã¦ã„ã¾ã™ã€‚
ã¾ãŸã€ãƒžãƒƒãƒ—編集ツールを使用ã—ã¦ã€ãれらを任æ„ã«å»ºè¨­ã™ã‚‹ã“ã¨ãŒã§
ãã¾ã™ã€‚
公共事業ã¯ã€ã™ã¹ã¦ã®ãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ã®æ‰€æœ‰ç‰©ã‚’å–り除ãã“ã¨ãŒã§ãã¾ã™ã€‚
å…¬å…±äº‹æ¥­ãŒæ‰€æœ‰ã™ã‚‹é“è·¯/線路や駅ãªã©ã¯ã€ã™ã¹ã¦ã®ãƒ—レイヤーãŒåˆ©ç”¨
ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚公共駅ã§ã®ã¿ä¼šç¤¾é–“ã§ã®ä¹—æ›ãŒã§ãã¾ã™ã€‚

公共事業ã¯è»Šåº«ã‚’建設ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã®ã§ã€é‹é€ã«ã‚ˆã£ã¦ç›´æŽ¥åŽå…¥ã‚’
å¾—ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。赤字ã§ã‚‚å•題ã‚りã¾ã›ã‚“ã®ã§æ°—ã«ã—ãªã„ã§ãã ã•ã„。

プレイヤー(人間): ãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ãŒæ“作ã—ã¾ã™ã€‚破産ã—ã¦ã‚‚勿‰‹ã«æ¸…ç®—ã•れãŸã‚Š
ã¯ã—ã¾ã›ã‚“。

AI 貨物: 鉄é“/é“è·¯/船舶を使用ã—ã¦ã€è²¨ç‰©è¼¸é€ã‚’行ã„ã¾ã™ã€‚

AI 旅客: ãƒã‚¹/船舶を使用ã—ã¦ã€æ—…客輸é€ã‚’行ã„ã¾ã™ã€‚資金ãŒå分ã‚ã‚‹ã¨ã
ã«ã¯æ—…客機を使用ã™ã‚‹ã“ã¨ã‚‚ã‚りã¾ã™ã€‚

フリープレイモード
通常ã€ç·è³‡ç”£ãŒãƒžã‚¤ãƒŠã‚¹ã«ãªã£ãŸä¼šç¤¾ã¯ç ´ç”£ã¨ãªã‚Šã¾ã™ã€‚
ã‚ãªãŸãŒç ´ç”£ã—ãŸå ´åˆã€ã‚²ãƒ¼ãƒ ã¯çµ‚了ã—ã€æ–°ã—ã„マップã®ä½œæˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãŒ
é–‹ã‹ã‚Œã¾ã™ã€‚
AIプレイヤーã®å ´åˆã¯ã€ã™ã¹ã¦ã®è³‡ç”£ãŒå£²å´ã•ã‚Œã€æ´»å‹•ã‚’åœæ­¢ã—ã¾ã™ã€‚
破産ã—ãŸä¼šç¤¾ã®ã‚¹ãƒ­ãƒƒãƒˆã¯ä½¿ç”¨ã§ããªããªã‚Šã¾ã™ã€‚

フリープレイモードをオンã«ã™ã‚‹ã¨ã€ç ´ç”£ã™ã‚‹ã“ã¨ãªãã€ã‚²ãƒ¼ãƒ ã‚’ç¶šã‘ã‚‹ã“ã¨
ãŒã§ãã¾ã™ã€‚ã“ã®è¨­å®šã¯ã‚»ãƒ¼ãƒ–ゲームã«ä¿å­˜ã•れã€ã„ã¤ã§ã‚‚変更ã™ã‚‹ã“ã¨ãŒ
ã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/privatesign_info.txt000066400000000000000000000011201474050137200232570ustar00rootroot00000000000000ゲート

ゲート

ダイアログã§ã©ã®ãƒ—レイヤーã®è»Šä¸¡ã‚’通éŽã•ã›ã‚‹ã‹ã‚’設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚(公共事業ã®å ´åˆã¯city carã«ã‚‚é©ç”¨ã•れã¾ã™ã€‚)通éŽã‚’許å¯ã•れã¦ã„るプレイヤーã¯ã‚²ãƒ¼ãƒˆãŒé–‹ã„ãŸçŠ¶æ…‹ã«ã€è¨±å¯ã•れã¦ã„ãªã„å ´åˆã¯ã‚²ãƒ¼ãƒˆãŒé–‰ã˜ãŸçŠ¶æ…‹ã«ãªã‚Šã¾ã™ã€‚

ゲートã¯å„交通機関ã®ãƒ„ールãƒãƒ¼ã‹ã‚‰é¸æŠžã—ã¦è¨­ç½®ã—ã¾ã™ã€‚(鉄é“:鉄é“ツール 自動車:é“路ツール)

simutrans-124.3/simutrans/text/ja/railtools.txt000066400000000000000000000111411474050137200217250ustar00rootroot00000000000000鉄é“ツール

鉄é“ツール

 鉄é“ツールã‹ã‚‰ã¯ã€ç·šè·¯ã€ä¿¡å·ã€ãƒˆãƒ³ãƒãƒ«ã€é§…ã€æ“車場ã€è¸åˆ‡ã‚’作るã“ã¨ãŒ
出æ¥ã¾ã™ã€‚

 上段ã®ä¸€ç•ªå·¦ã¯ã€ç·šè·¯ãƒ„ールã§ã™ã€‚マップã®äºŒç‚¹é–“ã«ç·šè·¯ã‚’æ•·ãã“ã¨ãŒå‡ºæ¥
ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒç·šè·¯ã®äº¤å·®ã—ãŸã‚ˆã†ãªå½¢
状ã«å¤‰åŒ–ã—ã¾ã™ã€‚ã¾ãšç·šè·¯ã®èµ·ç‚¹ã§ã‚¯ãƒªãƒƒã‚¯ã—(ãã®å ´æ‰€ã«ãƒ–ルドーザーã®ãƒžãƒ¼
クãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æ¬¡ã«ç·šè·¯ã®çµ‚点ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€é¸æŠžã—ãŸäºŒç‚¹ã‚’çµã¶
よã†ã«ç·šè·¯ãŒæ•·ã‹ã‚Œã¾ã™ã€‚ã“ã®ã¨ãã€äºŒç‚¹é–“ã¯æ™®é€šã®ç·šè·¯ã ã‘ã§çµã°ã‚Œã¾ã™ã€‚
è¸ã¿åˆ‡ã‚Šã‚„æ©‹ã€ãƒˆãƒ³ãƒãƒ«ã‚’自動的ã«ä½œã‚‹ã“ã¨ã¯ã‚りã¾ã›ã‚“ã€‚é¸æŠžã—ãŸäºŒç‚¹ã‚’çµ
ã¶çµŒè·¯ãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã¯ã€ä½•ã‚‚èµ·ã“りã¾ã›ã‚“。

 上段ã®å·¦ã‹ã‚‰ï¼’番目ã¯ã€ä¿¡å·ãƒ„ールã§ã™ã€‚ä¿¡å·ã‚’設置ã—ã¦é–‰å¡žåŒºé–“を作るã“
ã¨ã§ã€ä¸€æœ¬ã®ç·šè·¯ã«è¤‡æ•°ã®åˆ—車を走らã›ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚アイコンをクリッ
クã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒä¿¡å·æ©Ÿã«å¤‰åŒ–ã—ã¾ã™ã€‚ä¿¡å·ã‚’設置ã—ãŸã„場所ã§ã‚¯
リックã—ã¦ãã ã•ã„。信å·ã«ã¯ã€ä¸¡æ–¹å‘ä¿¡å·ã¨ä¸€æ–¹å‘ä¿¡å·ãŒã‚りã¾ã™ã€‚一方å‘
ä¿¡å·ã¯ã€é–‰å¡žåŒºé–“を作る効果ã«åŠ ãˆã¦ã€å対å´ã‹ã‚‰ã®åˆ—車ã®é€²å…¥ã‚’ç¦æ­¢ã™ã‚‹åй
æžœãŒã‚りã¾ã™ã€‚一方å‘ä¿¡å·ã‚’設置ã™ã‚‹ã«ã¯ã€ã¾ãšä¸¡æ–¹å‘ä¿¡å·ã‚’設置ã—ã¦ã‹ã‚‰ã€
ãã“ã§ã‚‚ã†ä¸€åº¦ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。クリックã™ã‚‹ãŸã³ã«ã€ä¸¡æ–¹å‘ä¿¡å· ï¼
一方å‘ä¿¡å· ï¼ å対方å‘ã®ä¸€æ–¹å‘ä¿¡å· ï¼ ä¸¡æ–¹å‘ä¿¡å·ã¨ã€å¾ªç’°çš„ã«åˆ‡ã‚Šæ›¿ã‚り
ã¾ã™ã€‚ä¿¡å·ã‚’撤去ã™ã‚‹æ™‚ã¯ã€æ’¤åŽ»ãƒ„ãƒ¼ãƒ«ã‚’é¸æŠžã—ã¦ä¿¡å·ã®ã‚る場所をクリック
ã—ã¦ãã ã•ã„。ã“ã®ã¨ãã€ä¿¡å·æ©Ÿã ã‘ãŒæ’¤åŽ»ã•れã€ç·šè·¯ã¯æ®‹ã‚Šã¾ã™ã€‚

 上段ã®å·¦ã‹ã‚‰ï¼“番目ã¯ã€ãƒˆãƒ³ãƒãƒ«ãƒ„ールã§ã™ã€‚トンãƒãƒ«ã¯ã€åŒã˜é«˜ã•ã®ç›´ç·š
ã®ç·šè·¯ã‚’çµã³ã¾ã™ã€‚トンãƒãƒ«ã‚’設置ã™ã‚‹å‰ã«ã€ãƒˆãƒ³ãƒãƒ«ã§çµã¶ç·šè·¯ã®ä¸¡ç«¯ãŒã€
ãれãžã‚Œå±±ã®æ–œé¢ã«æŽ›ã‹ã£ã¦ã„るよã†ã«ã—ã¦ãã ã•ã„。アイコンをクリックã™
ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒãƒˆãƒ³ãƒãƒ«ã«å¤‰åŒ–ã—ã¾ã™ã€‚トンãƒãƒ«ã®å…¥ã‚Šå£ã§ã‚¯ãƒªãƒƒã‚¯
ã™ã‚‹ã¨ã€å‘ã‹ã„åˆã£ãŸç·šè·¯ãŒãƒˆãƒ³ãƒãƒ«ã§çµã°ã‚Œã¾ã™ã€‚

 上段ã®ä¸€ç•ªå³ã¯ã€æž¶ç·šãƒ„ールã§ã™ã€‚電車を走らã›ã‚‹ç‚ºã«ã¯ã€ç·šè·¯ã‚’敷設ã—ãŸ
ã‚ã¨ã«æž¶ç·šã‚’張らãªã‘れã°ã„ã‘ã¾ã›ã‚“。アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼
ã‚½ãƒ«ãŒæž¶ç·šã®ã‚°ãƒ©ãƒ•ィックã«å¤‰åŒ–ã—ã¾ã™ã€‚架線を張りãŸã„ç·šè·¯ã®ä¸Šã§ã‚¯ãƒªãƒƒã‚¯
ã™ã‚‹ã¨ã€ãã®å ´æ‰€ã‚’å«ã‚€é–‰å¡žåŒºé–“å…¨ä½“ã«æž¶ç·šãŒå¼µã‚‰ã‚Œã¾ã™ã€‚

 下段ã®ä¸€ç•ªå·¦ã¯ã€é§…建設ツールã§ã™ã€‚列車ã¯ã€é§…ã§ç‰©è³‡ã‚„旅客ã®ç©ã¿ä¸‹ã‚ã—
を行ã„ã€åŽç›Šã‚’å¾—ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒé§…ã«å¤‰
化ã—ã¾ã™ã€‚建設ã—ãŸã„線路上ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€ãã“ã«é§…ãŒå»ºè¨­ã•れã¾ã™ã€‚é§…
ã¯ã€å¹³å¦ãªç›´ç·šç·šè·¯ã®ä¸Šã«ã—ã‹ä½œã‚Œã¾ã›ã‚“。ã¾ãŸã€ï¼‘マスã®é§…ã«ã¯ï¼’両ã¾ã§ã®
列車ã—ã‹å…¥ã‚Šã¾ã›ã‚“。駅ã«å…¥ã‚‰ãªã„部分ã®è»Šä¸¡ã¯ã€è·ç‰©ã®ç©ã¿ä¸‹ã‚ã—を行ãˆã¾
ã›ã‚“。より長ã„列車をåœè»Šã•ã›ã‚‹ç‚ºã«ã¯ã€å¤§ããªé§…を作る必è¦ãŒã‚りã¾ã™ã€‚ã™
ã§ã«å­˜åœ¨ã™ã‚‹é§…ã«éš£æŽ¥ã™ã‚‹ãƒžã‚¹ã«é§…を建設ã™ã‚‹ã¨ã€ãれã¯åŒä¸€ã®é§…ã¨ã¿ãªã•れ
ã¾ã™ã€‚é§…ã®å¤§ãã•や形状ã«åˆ¶é™ã¯ãªãã€ç¹‹ãŒã£ã¦ã„ã‚‹é™ã‚Šã¯å…¨ã¦ä¸€ã¤ã®é§…ã«ãª
りã¾ã™ã€‚Simutrans ã®ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã¯ã€é§…ã«ã¯ã„ãらã§ã‚‚物資を貯ã‚ã‚‹
ã“ã¨ãŒå‡ºæ¥ã¾ã™ï¼ˆç”£æ¥­æ–½è¨­ã«ã¯1000tã¾ã§ã—ã‹è²¯ã‚ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã›ã‚“)。

 下段ã®å·¦ã‹ã‚‰ï¼’番目ã¯ã€æ“車場建設ツールã§ã™ã€‚列車ã®è³¼å…¥ã‚„スケジュール
設定を行ã†ãŸã‚ã«ã¯ã€æ“車場ãŒå¿…è¦ã§ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹
ã‚«ãƒ¼ã‚½ãƒ«ãŒæ“車場ã«å¤‰åŒ–ã—ã¾ã™ã€‚æ“車場ã¯ç·šè·¯ã®çµ‚端ã«ã—ã‹å»ºè¨­ã§ãã¾ã›ã‚“ã®
ã§ã€ãã®ã‚ˆã†ãªå ´æ‰€ã‚’é¸ã‚“ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。

 下段ã®å·¦ã‹ã‚‰ï¼“番目ã¯ã€è¸ã¿åˆ‡ã‚Šãƒ„ールã§ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€
マウスカーソルãŒè¸ã¿åˆ‡ã‚Šã®å½¢çжã«å¤‰åŒ–ã—ã¾ã™ã€‚è¸åˆ‡ã‚’設置ã—ãŸã„é“路上ã§ã‚¯
リックã—ã¦ãã ã•ã„。

simutrans-124.3/simutrans/text/ja/removal_tool.txt000066400000000000000000000052331474050137200224240ustar00rootroot00000000000000撤去ツール

撤去ツール

撤去ツール ã¯ã€ä¸è¦ãªå»ºç¯‰ç‰©ã‚„アイテムをã€å–り壊ã—ã¦æ’¤åŽ»ã™ã‚‹ã¨ãã«ä½¿ã„ã¾ã™ã€‚

ä½¿ã„æ–¹: ゲーム画é¢ã®ä¸Šã«ã‚るツールãƒãƒ¼ã®èµ¤ã„×å°ã®ã‚¢ã‚¤ã‚³ãƒ³(pak128ã§ã¯ãƒ–ルドーザーã®ã‚¢ã‚¤ã‚³ãƒ³)をクリックã™ã‚‹ã‹ã€[r]ã®ã‚­ãƒ¼ã‚’押ã™ã¨æ’¤åŽ»ãƒ„ãƒ¼ãƒ«ãŒèµ·å‹•ã—ã€ã‚«ãƒ¼ã‚½ãƒ«ãŒèµ¤ã„×å°ã«å¤‰ã‚りã¾ã™ã€‚
ゲーム画é¢ã«è¡¨ç¤ºã•ã‚Œã‚‹é»„è‰²ã®æž ãŒã€æ’¤åŽ»ãƒ„ãƒ¼ãƒ«ã®ä½œç”¨ã™ã‚‹ç¯„囲を示ã—ã¾ã™(座標ã¯ç”»é¢ä¸‹ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒãƒ¼ã®å³æ–¹ã«è¡¨ç¤ºã•れã¾ã™)。カーソルã®ä½ç½®ã‚’目的ã®å ´æ‰€ã«åˆã‚ã›ã¦å·¦ã‚¯ãƒªãƒƒã‚¯ã™ã‚Œã°ã€æ’¤åŽ»ã§ãã¾ã™ã€‚

撤去費用ã¯ã€æ’¤åŽ»å¾Œã«ã‚²ãƒ¼ãƒ ç”»é¢ã«è¡¨ç¤ºã•れるã¨ã¨ã‚‚ã«ã€å»ºè¨­è²»ã«åŠ ç®—ã•れã¾ã™ã€‚ãªãŠæ’¤åŽ»è²»ç”¨ã¯ã€æ’¤åŽ»ã—ãŸã‚¢ã‚¤ãƒ†ãƒ ã‚’プレイヤーãŒè¨­ç½®ã™ã‚‹éš›ã«ã‹ã‹ã‚‹è²»ç”¨ã¨åŒã˜ã§ã™ã€‚
ã¾ãŸå¸‚å†…å»ºç¯‰ç‰©ã®æ’¤åŽ»ã«ã‹ã‹ã‚‹è²»ç”¨ã¯ã€èª¿æŸ»ãƒ„ール使用時ã«ãã®æ’¤åŽ»ã—ãŸã„市内建築物をクリックã—ã¦è¡¨ç¤ºã•れるダイアログ中ã®ä¾¡æ ¼ã¨åŒã˜ã§ã™ã€‚

ãªãŠã€æ’¤åŽ»ãƒ„ãƒ¼ãƒ«ã¯æ­©è¡Œè€…や自家用車をå–り除ããŸã„ã¨ãã«ã‚‚åŒã˜ã‚ˆã†ã«ä½¿ç”¨å‡ºæ¥ã¾ã™ã€‚

åŒä¸€ã®ãƒžã‚¹ã«è¤‡æ•°ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒå­˜åœ¨ã™ã‚‹å ´åˆã€1,歩行者ã¾ãŸã¯è‡ªå®¶ç”¨è»Šã€2,標識ã¾ãŸã¯ä¿¡å·ã€3,åœç•™æ‰€ã¾ãŸã¯é§…ã®ãƒ›ãƒ¼ãƒ ã€4,æž¶ç·šã€5,æ©‹ã¾ãŸã¯ãƒˆãƒ³ãƒãƒ«ã€6,é“è·¯ã¾ãŸã¯ç·šè·¯(è¸åˆ‡ãŒã‚れã°ç·šè·¯ãŒå…ˆ)ã®é †ã«å„ªå…ˆã—ã¦æ’¤åŽ»ã•れã¾ã™ã€‚

{Tips: プレイヤー会社ã®ä¹—り物を撤去ã—ãŸã„ã¨ãã¯ã€ä¹—り物詳細ã‹ã‚‰ä¹—り物をå³åº§ã«å£²å´ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
ç”£æ¥­æ–½è¨­ã‚„åæ‰€æ—§è·¡ã€ç”ºå½¹å ´ã‚’撤去ã—ãŸã„ã¨ãã¯ã€ã¾ãšã¯æ“作ã™ã‚‹ä¼šç¤¾ã‚’公共事業ã«åˆ‡ã‚Šæ›¿ãˆã¦ä¸‹ã•ã„ã€‚è¦æ³¨æ„:町役場を撤去ã™ã‚‹ã¨ã€ãã®å¸‚域ã®å…¨ã¦ã®å¸‚å†…å»ºç¯‰ç‰©ãŒæ’¤åŽ»ã•れã¦ã—ã¾ã„ã¾ã™ã€‚
ライãƒãƒ«ä¼šç¤¾ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’撤去ã—ãŸã„ã¨ãã¯ã€ã¾ãšæ“作ã™ã‚‹ä¼šç¤¾ã‚’ãã®ãƒ©ã‚¤ãƒãƒ«ä¼šç¤¾ã«åˆ‡ã‚Šæ›¿ãˆã¦ãã ã•ã„。
線路やé“路を標識や信å·ã¨ã¾ã¨ã‚ã¦æ’¤åŽ»ã—ãŸã„ã¨ãã¯ã€é‰„é“ã®æ’¤åŽ»(åŒæ§˜ã®ãƒ„ールã¯å¸‚é›»/軽便鉄é“ツール内ã«ã‚‚ã‚りã¾ã™)ã‚„é“è·¯ã®æ’¤åŽ»ã‚’ä½¿ç”¨ã—ã¦ä¸‹ã•ã„。}

simutrans-124.3/simutrans/text/ja/roadtools.txt000066400000000000000000000063051474050137200217310ustar00rootroot00000000000000é“路ツールダイアログヘルプ

é“路ツールダイアログ

 é“路ツールダイアログã‹ã‚‰ã¯ã€é“è·¯ã€ãƒã‚¹åœã€ãƒˆãƒ³ãƒãƒ«ã€ãƒˆãƒ©ãƒƒã‚¯åœè»Šå ´ã€
車庫ã€è¸åˆ‡ã‚’作るã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚

 上段ã®ä¸€ç•ªå·¦ã¯ã€é“路敷設ツールã§ã™ã€‚マップã®äºŒç‚¹é–“ã«é“路を敷ãã“ã¨ãŒ
出æ¥ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒäº¤å·®ç‚¹ã®ã‚ˆã†ãªå½¢çж
ã«å¤‰åŒ–ã—ã¾ã™ã€‚ã¾ãšé“è·¯ã®èµ·ç‚¹ã§ã‚¯ãƒªãƒƒã‚¯ã—(ãã®å ´æ‰€ã«ãƒ–ルドーザーã®ãƒžãƒ¼
クãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æ¬¡ã«é“è·¯ã®çµ‚点ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€é¸æŠžã—ãŸäºŒç‚¹ã‚’çµã¶
よã†ã«é“è·¯ãŒæ•·ã‹ã‚Œã¾ã™ã€‚ã“ã®ã¨ãã€äºŒç‚¹é–“ã¯æ™®é€šã®é“è·¯ã ã‘ã§çµã°ã‚Œã¾ã™ã€‚
è¸åˆ‡ã‚„æ©‹ã€ãƒˆãƒ³ãƒãƒ«ã‚’自動的ã«ä½œã‚‹ã“ã¨ã¯ã‚りã¾ã›ã‚“ã€‚é¸æŠžã—ãŸäºŒç‚¹ã‚’çµã¶çµŒ
è·¯ãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã¯ã€ä½•ã‚‚èµ·ã“りã¾ã›ã‚“。

 上段ã®å·¦ã‹ã‚‰ï¼’番目ã¯ã€ãƒã‚¹åœå»ºè¨­ãƒ„ールã§ã™ã€‚ãƒã‚¹åœã§ã¯ã€ãã®ä»˜è¿‘ã®å»º
物を利用ã™ã‚‹äººãŒä¹—りé™ã‚Šã—ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½
ルãŒãƒã‚¹åœã«å¤‰åŒ–ã—ã¾ã™ã€‚ãƒã‚¹åœã‚’建設ã—ãŸã„é“路上ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。
ãƒã‚¹åœã¯ã€å¹³å¦ãªç›´ç·šé“è·¯ã®ä¸Šã«ã—ã‹ä½œã‚Œã¾ã›ã‚“。1マスã®ãƒã‚¹åœã«ã¯ã€é“è·¯
ã®ãれãžã‚Œã®è»Šç·šã«ï¼‘å°ãšã¤ã®ãƒã‚¹ãŒåœè»Šã§ãã¾ã™ã€‚

 上段ã®å·¦ã‹ã‚‰ï¼“番目ã¯ã€ãƒˆãƒ³ãƒãƒ«ãƒ„ールã§ã™ã€‚トンãƒãƒ«ã¯ã€åŒã˜é«˜ã•ã®ç›´ç·š
ã®é“路をçµã³ã¾ã™ã€‚トンãƒãƒ«ã‚’設置ã™ã‚‹å‰ã«ã€ãƒˆãƒ³ãƒãƒ«ã§çµã¶é“è·¯ã®ä¸¡ç«¯ãŒã€
ãれãžã‚Œå±±ã®æ–œé¢ã«æŽ›ã‹ã£ã¦ã„るよã†ã«ã—ã¦ãã ã•ã„。アイコンをクリックã™
ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒãƒˆãƒ³ãƒãƒ«ã«å¤‰åŒ–ã—ã¾ã™ã€‚トンãƒãƒ«ã®å…¥ã‚Šå£ã«ã—ãŸã„ã¨
ã“ã‚ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€å‘ã‹ã„åˆã£ãŸé“è·¯ãŒãƒˆãƒ³ãƒãƒ«ã§çµã°ã‚Œã¾ã™ã€‚

 下段ã®ä¸€ç•ªå·¦ã¯ã€ãƒˆãƒ©ãƒƒã‚¯åœè»Šå ´å»ºè¨­ãƒ„ールã§ã™ã€‚トラックåœè»Šå ´ã§ã¯ã€ãƒˆ
ラックãŒç‰©è³‡ã®ç©ã¿ä¸‹ã‚ã—を行ã„ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼
ソルãŒãƒˆãƒ©ãƒƒã‚¯åœè»Šå ´ã«å¤‰åŒ–ã—ã¾ã™ã€‚トラックåœè»Šå ´ã¯é“è·¯ã®çµ‚端ã«ã—ã‹å»ºè¨­
ã§ãã¾ã›ã‚“ã®ã§ã€ãã®ã‚ˆã†ãªå ´æ‰€ã‚’é¸ã‚“ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ä¸‹ã•ã„。1マスã®ãƒˆãƒ©ãƒƒ
クåœè»Šå ´ã«ã¯ã€ï¼’å°ã¾ã§ã®ãƒˆãƒ©ãƒƒã‚¯ãŒåœè»Šã§ãã¾ã™ã€‚

 下段ã®å·¦ã‹ã‚‰ï¼’番目ã¯ã€è»Šåº«å»ºè¨­ãƒ„ールã§ã™ã€‚ãƒã‚¹ã‚„トラックã€éƒµä¾¿é…é”車
ãªã©ã€è»Šä¸¡ã®è³¼å…¥ã‚„スケジュール設定を行ã†ãŸã‚ã«ã¯ã€è»Šåº«ãŒå¿…è¦ã§ã™ã€‚アイ
コンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒè»Šåº«ã«å¤‰åŒ–ã—ã¾ã™ã€‚車庫ã¯é“è·¯ã®çµ‚
端ã«ã—ã‹å»ºè¨­ã§ãã¾ã›ã‚“ã®ã§ã€ãã®ã‚ˆã†ãªå ´æ‰€ã‚’é¸ã‚“ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。

 下段ã®å·¦ã‹ã‚‰ï¼“番目ã¯ã€è¸åˆ‡ãƒ„ールã§ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦
スカーソルãŒè¸åˆ‡ã®å½¢çжã«å¤‰åŒ–ã—ã¾ã™ã€‚è¸åˆ‡ã‚’設置ã—ãŸã„線路上ã§ã‚¯ãƒªãƒƒã‚¯ã—
ã¦ä¸‹ã•ã„。

simutrans-124.3/simutrans/text/ja/save.txt000066400000000000000000000014441474050137200206600ustar00rootroot00000000000000セーブダイアログヘルプ

セーブダイアログ

 ç¾åœ¨ã®çŠ¶æ…‹ã‚’ä¿å­˜ã§ãã¾ã™ã€‚

 新ã—ã„ファイルã«ä¿å­˜ã™ã‚‹å ´åˆã¯ã€ãƒ†ã‚­ã‚¹ãƒˆãƒ•ィールドã«ãƒ•ァイルåを入力
ã—ã¦OKボタンを押ã—ã¦ãã ã•ã„。ファイルåã«ã¯æ‹¡å¼µå­ã‚’å«ã‚ã‚‹å¿…è¦ã¯ã‚りã¾ã›ã‚“。

 既存ã®ãƒ•ァイルã«ä¸Šæ›¸ãä¿å­˜ã™ã‚‹å ´åˆã¯ã€è¡¨ç¤ºã•れã¦ã„るファイルåをクリッ
クã—ã¦ãã ã•ã„。上書ãã®ç¢ºèªã¯ã‚りã¾ã›ã‚“ã®ã§ã€æ³¨æ„ã—ã¦ãã ã•ã„。

 ファイルを削除ã—ãŸã„å ´åˆã¯ã€ãã®ãƒ•ァイルåã®å·¦å´ã«ã‚る×ボタンをクリッ
クã—ã¦ãã ã•ã„。削除ã®ç¢ºèªã¯ã‚りã¾ã›ã‚“ã®ã§ã€æ³¨æ„ã—ã¦ãã ã•ã„。

simutrans-124.3/simutrans/text/ja/scenario.txt000066400000000000000000000004731474050137200215260ustar00rootroot00000000000000シナリオ ヘルプ

シナリオ

simutransã§ã¯ã‚·ãƒŠãƒªã‚ªã‚’使ã£ã¦éŠã¶ã“ã¨ãŒã§ãã¾ã™ã€‚工場をã¤ãªãã€ã§ãã‚‹ã ã‘æ—©ãåŽå…¥ã‚’å¾—ã‚‹ã€æœ¬ç¤¾ã‚’ç«‹ã¦ã‚‹ã¨ã„ã£ãŸç›®æ¨™ã‚’锿ˆã™ã‚‹ã“ã¨ã§ã‚·ãƒŠãƒªã‚ªã‚’完çµã•ã›ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/schedule.txt000066400000000000000000000033601474050137200215150ustar00rootroot00000000000000時刻表

時刻表ダイアログ

 時刻表ダイアログã§ã¯ã€è»Šä¸¡ãƒ»èˆ¹èˆ¶ã®é‹è¡ŒçµŒè·¯ã‚’設定ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚ã¡ãªã¿ã«æ™‚刻を設定ã—ã¦ã®é‹è¡Œã¯å‡ºæ¥ã¾ã›ã‚“。

 é‹è¡ŒçµŒè·¯ã‚’設定ã™ã‚‹ã«ã¯ã€ã¾ãšè¿½åŠ ãƒœã‚¿ãƒ³ã‚’ã‚¯ãƒªãƒƒã‚¯ã—ã¾ã™ã€‚次ã«ã€åœè»Šã™ã‚‹é§…ãªã©ã®ä¸Šã‚’クリックã—ã¦ãã ã•ã„。港を指定ã™ã‚‹å ´åˆã¯ã€æ¸¯ã®å‘¨è¾ºã®ãƒžã‚¹ã‚’クリックã—ã¦ãã ã•ã„。リストã«é§…å・港åãŒè¿½åŠ ã•れã¾ã™ã€‚ãªãŠã€ç·šè·¯ä¸Šãƒ»é“路上・海上ã§é§…ãªã©å‡ºãªã„場所も中継点ã¨ã—ã¦è¨­å®šã§ãã¾ã™ã€‚ã“ã®ã‚ˆã†ã«ã—ã¦ã€é‹è¡ŒçµŒè·¯ã®é§…・港ãªã©ã‚’次々ã¨ã‚¯ãƒªãƒƒã‚¯ã—ã¦ã„ã£ã¦ä¸‹ã•ã„。最大16ヵ所ã¾ã§æŒ‡å®šã§ãã¾ã™ã€‚

 車両・船舶ã¯ã€ãƒªã‚¹ãƒˆã®ä¸Šã‹ã‚‰é †ç•ªã«è¨­å®šã•れãŸç®‡æ‰€ã‚’回りã¾ã™ã€‚リストã®ä¸€ç•ªä¸‹ã¾ã§æ¥ãŸã‚‰ã€ã¾ãŸä¸Šã¾ã§æˆ»ã£ã¦é‹è¡Œã‚’ç¶šã‘ã¾ã™ã€‚番å·ã®å·¦ã®ãƒžãƒ¼ã‚¯ã¯ç¾åœ¨å‘ã‹ã£ã¦ã„る箇所を示ã—ã¾ã™ã€‚

 追加ボタンã§ã¯ã€æ–°ãŸã«ç®‡æ‰€ã‚’リストã®ä¸€ç•ªä¸‹ã«è¿½åŠ ã—ã¾ã™ã€‚挿入ボタンã§ã¯ã€ãƒªã‚¹ãƒˆä¸Šã®ç¾åœ¨ãƒžãƒ¼ã‚¯ãŒã‚ã‚‹é …ç›®ã«ã€æ–°ãŸãªç®‡æ‰€ãŒæŒ¿å…¥ã•れã¾ã™ã€‚リストã®é …目を削除ã™ã‚‹ã«ã¯ã€å‰Šé™¤ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦ã€å‰Šé™¤ã—ãŸã„項目をクリックã—ã¦ãã ã•ã„。全ã¦ã®è¨­å®šãŒçµ‚ã‚ã£ãŸã‚‰çµ‚了ボタンをクリックã—ã¦ãã ã•ã„。

 「ç©ã‚€ã¾ã§å¾…機ã€ã®æ•°å­—ã¯ã€ãã®é§…・港ã§ã€è»Šä¸¡ãƒ»èˆ¹èˆ¶ã«è²¨ç‰©ãƒ»æ—…客をã“ã®å‰²åˆç©ã‚“ã çŠ¶æ…‹ã«ãªã‚‹ã¾ã§ã€å‡ºç™ºã‚’å¾…ã¤ã¨è¨€ã†æ„味ã§ã™ã€‚ã“ã®æ•°å­—を大ããã™ã‚‹ã“ã¨ã§ã€ç„¡é§„ã®ãªã„é‹è¡ŒãŒå‡ºæ¥ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/server.txt000066400000000000000000000034621474050137200212320ustar00rootroot00000000000000ゲーム情報 ï¼ ã‚µãƒ¼ãƒãƒ¼ã€€ãƒ˜ãƒ«ãƒ—

ゲーム情報 ï¼ ã‚µãƒ¼ãƒãƒ¼

Game information / Server will show you the current state of the game running, including the date, map size, number of companies, towns, citizens, factories, vehicles running, and so on. ゲーム情報 ï¼ ã‚µãƒ¼ãƒãƒ¼ã§ã¯ã€æ—¥ä»˜ã€ãƒžãƒƒãƒ—サイズã€ä¼šç¤¾æ•°ã€è¡—ã®æ•°ã€äººå£ã€å·¥å ´æ•°ã€ç¨¼åƒä¸­ã®è»Šä¸¡æ•°ãªã©ã€ç¾åœ¨ç¨¼åƒä¸­ã®ã‚²ãƒ¼ãƒ ã®çŠ¶æ…‹ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ãŒã¾ã ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‚²ãƒ¼ãƒ ã§ãªã„å ´åˆã¯ã€æŽ¥ç¶šå¯èƒ½ãªä»–ã®ã‚µãƒ¼ãƒãƒ¼ãŒãƒ‰ãƒ­ãƒƒãƒ—ダウンリストã«è¡¨ç¤ºã•れã¾ã™ã€‚ã“ã®ãƒªã‚¹ãƒˆãŒç©ºã®å ´åˆã€ãŠä½¿ã„ã®ãƒ‘ックãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚„プログラムãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚µãƒ¼ãƒãƒ¼ãŒã‚りã¾ã›ã‚“。ã™ã¹ã¦è¡¨ç¤ºãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€æ—¢å­˜ã®ã™ã¹ã¦ã®ã‚µãƒ¼ãƒãƒ¼ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

サーãƒãƒ¼ã‚’é¸æŠžã™ã‚‹ã¨ã€ãã®ã‚µãƒ¼ãƒãƒ¼ã®çŠ¶æ…‹ã‚’ç¤ºã™ã‚²ãƒ¼ãƒ æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚(サーãƒãƒ¼ãŒãƒ€ã‚¦ãƒ³ã—ã¦ã„ã‚‹å ´åˆã€ç¢ºèªã«æ™‚é–“ãŒã‹ã‹ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚) ã¾ãŸã€ã‚µãƒ¼ãƒãƒ¼ã®ãƒ‘ックセットã¨ãƒ—ログラムãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒè¡¨ç¤ºã•れã¾ã™ã€‚両方ã¨ã‚‚é»’ã§ã‚れã°ã€ã‚ãªãŸã®ãƒ‘ックセットã¨ãƒ—ログラムã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒã‚µãƒ¼ãƒãƒ¼ã¨ä¸€è‡´ã—ã¦ã„ã‚‹ã®ã§ã€Play online を押ã—ã¦å‚加ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

pakセットã®ä¸ä¸€è‡´ãŒã‚ã‚‹å ´åˆã¯ã€ã‚¨ãƒ³ãƒˆãƒªãƒ¼ãŒèµ¤ã«ãªã‚Šã¾ã™ã€‚ãã®ã¨ãã¯ã€ãƒ‘ックを比較ã™ã‚‹ãƒœã‚¿ãƒ³ã‚’使ã£ã¦ã€è¶³ã‚Šãªã„パックã€é•ã†ãƒ‘ックã€ä½™åˆ†ãªãƒ‘ックã®ãƒ¬ãƒãƒ¼ãƒˆã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚(ã“れã«ã¯æ™‚é–“ãŒã‹ã‹ã‚‹å ´åˆãŒã‚りã¾ã™ã€‚)

simutrans-124.3/simutrans/text/ja/settings.txt000066400000000000000000000025331474050137200215620ustar00rootroot00000000000000高度ãªè¨­å®šãƒ˜ãƒ«ãƒ—

高度ãªè¨­å®š

高度ãªè¨­å®šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯æ–°ã—ã„マップã®ä½œæˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰é–‹ãã¾ã™ã€‚
ã“ã“ã§ã¯ã€ä¸»ã«ä½œæˆã™ã‚‹æ–°ã—ã„マップã®ãƒ«ãƒ¼ãƒ«ã‚’設定ã—ã¾ã™ã€‚

 最上部ã®ãƒœã‚¿ãƒ³ã¯ãƒªã‚»ãƒƒãƒˆãƒœã‚¿ãƒ³ã§ã™ã€‚設定をリセットã—ã¾ã™ã€‚注æ„ã—ã¦ã
ã ã•ã„。(一部リセットã•れãªã„項目もã‚りã¾ã™ï¼‰
Simuconf.tab simuconf.tabã®è¨­å®šã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ã€‚
Default.sveã€€æœ€å¾Œã«æ–°è¦ãƒžãƒƒãƒ—を作æˆã—ãŸæ™‚ã®è¨­å®šã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ã€‚

設定項目ã«ã¯ã€ã‚»ãƒ¼ãƒ–ゲームã«ä¿å­˜ã•れるもã®ã¨ã€ä¿å­˜ã•れãªã„ã‚‚ã®ã¨ãŒã‚り
ã¾ã™ã€‚
セーブゲームã«ä¿å­˜ã•れるもã®ã¯ã€æ–°è¦ã«ä½œæˆã•れるゲームã«ã®ã¿å映ã•れã¾ã™ã€‚
ゲーム開始後ã«å¤‰æ›´ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。

ä¿å­˜ã•れãªã„設定項目ã¯ã€å¤‰æ›´ãŒå³æ™‚ã«å映ã•れã¾ã™ã€‚ãŸã ã—å†èµ·å‹•後ã¯å…ƒã®
è¨­å®šã«æˆ»ã£ã¦ã—ã¾ã„ã¾ã™ã®ã§ã€å¤‰æ›´ã‚’固定ã—ãŸã„å ´åˆã¯ã€simuconf.tabã‚„
cityrules.tabをテキストエディタã§ç›´æŽ¥å¤‰æ›´ã—ã¦ãã ã•ã„。

å„設定項目ã®è©³ç´°ã¯ã€Œæ—¥æœ¬èªžåŒ–wikiã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。

simutrans-124.3/simutrans/text/ja/shiptools.txt000066400000000000000000000027401474050137200217460ustar00rootroot00000000000000船舶ツールダイアログヘルプ

船舶ツールダイアログ

 船舶ツールã§ã¯ã€æ¸¯ã¨ãƒ‰ãƒƒã‚¯ã®å»ºé€ ãŒè¡Œãˆã¾ã™ã€‚

 上段ã®ä¸€ç•ªå·¦ã®ãƒœã‚¿ãƒ³ã¯ã€æ¸¯å»ºé€ ãƒ„ールã§ã™ã€‚港ã§ã¯ã€èˆ¹èˆ¶ãŒè²¨ç‰©ã‚„旅客ã®
ç©ã¿ä¸‹ã‚ã—を行ã„ã¾ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ãŒæ¸¯ã®å½¢
状ã«å¤‰åŒ–ã—ã¾ã™ã€‚æµ·ã«
接ã—ãŸæ–œé¢ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€ãã®æ–œé¢ã¨éš£æŽ¥ã™ã‚‹
æµ·ã¨ã®ï¼’マスを利用ã—ã¦ã€æ¸¯ãŒå»ºé€ ã•
れã¾ã™ã€‚港を建造ã™ã‚‹æ–œé¢ã¯ã€çœŸã£
ç›´ããªæ–œé¢ï¼ˆç·šè·¯ã‚„é“路を敷設ã§ãるよã†ãªæ–œé¢ï¼‰å‡ºãªã‘れã°ã„ã‘ã¾ã›ã‚“。船
èˆ¶ã‚’åœæ³Šã•ã›ã‚‹ã‚ˆã†ã«ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’組むã«ã¯ã€æ¸¯ã®ã‚るマスã§ã¯ãªãã€æ¸¯ã«
隣接ã™ã‚‹ãƒžã‚¹ã«åœæ³Šã™ã‚‹ã‚ˆã†ã«æŒ‡å®šã—ã¦ä¸‹ã•ã„。Simutrans ã®ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§
ンã§ã¯ã€æ¸¯ã®æ’¤åŽ»ã¯æ­£ã—ã動作ã—ã¾ã›ã‚“。

 下段ã®å·¦ã®ï¼’ã¤ã®ãƒœã‚¿ãƒ³ã¯ã€ãƒ‰ãƒƒã‚¯å»ºé€ ãƒ„ールã§ã™ã€‚ã“れら2ã¤ã¯ç”»é¢ä¸Šã§
ã®å‘ããŒé•ã†ã ã‘ã§ã€å®Ÿè³ªçš„ã«ã¯é•ã„ã¯ã‚りã¾ã›ã‚“。ドックã¯ã€èˆ¹èˆ¶ã®è³¼å…¥ã‚„
スケジュール設定を行ã†ãŸã‚ã«å¿…è¦ã§ã™ã€‚アイコンをクリックã™ã‚‹ã¨ã€ãƒžã‚¦ã‚¹
カーソルãŒãƒ‰ãƒƒã‚¯ã«å¤‰åŒ–ã—ã¾ã™ã€‚ãƒ‰ãƒƒã‚¯ã¯æµ·ä¸Šã«å»ºé€ ã—ã¾ã™ã€‚ドックを建造ã—
ãŸã„場所ã§ã‚¯ãƒªãƒƒã‚¯ã—ã¦ä¸‹ã•ã„。

simutrans-124.3/simutrans/text/ja/signal_spacing.txt000066400000000000000000000016571474050137200227110ustar00rootroot00000000000000ä¿¡å·ï¼æ¨™è­˜ã®é–“隔設定ヘルプ

ä¿¡å·ï¼æ¨™è­˜ã®é–“隔設定

 信å·ã€æ¨™è­˜ã‚¢ã‚¤ã‚³ãƒ³ã‚’[Ctrl]キーを押ã—ãªãŒã‚‰ã‚¯ãƒªãƒƒã‚¯ã—ã¾ã™ã€‚
ã€€ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚

ä¿¡å·ï¼æ¨™è­˜ã®é–“éš”
設置間隔。間隔ã¯ãƒ„ールアイコンã«ã‚‚表示ã•れã¾ã™ã€‚

中間ã®ä¿¡å·ï¼æ¨™è­˜ã‚’撤去ã™ã‚‹
 オン...設置間隔ã®ä¸­é–“ã«ã‚ã‚‹ä¿¡å·ãƒ»æ¨™è­˜ã¯æ’¤åŽ»ã—ã¾ã™ã€‚
 オフ...設置間隔ã®ä¸­é–“ã«ã‚ã‚‹ä¿¡å·ãƒ»æ¨™è­˜ã¯æ®‹ã—ã¾ã™ã€‚

ä»–ã®ä¿¡å·ï¼æ¨™è­˜ã‚’ç½®ãæ›ãˆã‚‹
 オン...設置予定場所ã«åˆ¥ã®ä¿¡å·ãƒ»æ¨™è­˜ãŒã‚ã£ãŸå ´åˆã€æ’¤åŽ»ã—æ–°ã—ã設置ã—
ã¾ã™ã€‚
 オフ...設置予定場所ã«åˆ¥ã®ä¿¡å·ãƒ»æ¨™è­˜ãŒã‚ã£ãŸå ´åˆãã®ã¾ã¾æ®‹ã—ã€ãれよ
り先ã«è¨­ç½®å¯èƒ½ãªå ´æ‰€ã‚’探ã—ã€ãã“ã«è¨­ç½®ã—ã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/simutrans.txt000066400000000000000000000024041474050137200217440ustar00rootroot00000000000000Simutrans

Simutrans

Simutransã¯ã€é‰„é“ï½¥è‡ªå‹•è»Šï½¥èˆ¹èˆ¶ï½¥é£›è¡Œæ©Ÿç­‰ã§æ—…客ã®è¼¸é€ãƒ«ãƒ¼ãƒˆã‚„産業物資を開拓ã—利益を上ã’ã‚‹ã€ãƒ•リーã®çµŒå–¶ã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã‚²ãƒ¼ãƒ ã§ã™ã€‚ åˆå¿ƒè€…ã§ã‚‚ã¨ã£ã¤ãã‚„ã™ãã€åŠ¹çŽ‡ã®ã‚ˆã„äº¤é€šã‚·ã‚¹ãƒ†ãƒ ã®æ§‹ç¯‰ã€éƒ½å¸‚ã®ç™ºå±•ã€æ··é›‘ã®è§£æ¶ˆã€æµé€šãƒ«ãƒ¼ãƒˆé–‹æ‹“ã«ã‚ˆã‚‹ç”£æ¥­ã®é–‹ç™ºãªã©ã€é†é†å‘³ã¯å°½ãã¾ã›ã‚“。 海外ã§é–‹ç™ºãŒç¶šã‘られã¦ã„るフリーウェア(無料)ã§ã™ãŒã€è£½å“ã¨ã—ã¦ã‚‚å分通用ã™ã‚‹ã»ã©ã®å®Œæˆåº¦ã®é«˜ã•ã¯ã€ç€å®Ÿã«å›½å†…ã®ãƒ—レイヤーを増やã—ã¦ã„ã¾ã™ã€‚ 大変楽ã—ã‚る作å“ã§ã™ã®ã§ã€ãœã²ä¸€åº¦ãƒ—レイã•れるã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚Windows・MacOS X・Linux・FreeBSD・BeOS(Haiku OS)・AmigaOS・iPhone(iPod touch)ã«å¯¾å¿œã—ã¦ã„ã¾ã™ã€‚  ※iPhone(iPod touch)対応ã¯å…¬å¼ãƒ“ルドã§ã¯ã‚りã¾ã›ã‚“。

Simutransã«ã¤ã„ã¦ã‚ˆã‚Šã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã§è¦‹ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼š
http://japanese.simutrans.com/
http://forum.japanese.simutrans.com/
http://forum.simutrans.com.

 日本語訳「フリーã®çµŒå–¶ã‚·ãƒ "Simutrans"を語るスレ」ã®313ã•ん+囲ç¢25ç´š

simutrans-124.3/simutrans/text/ja/slopetools.txt000066400000000000000000000045071474050137200221300ustar00rootroot00000000000000スロープツール ヘルプ

スロープツール

スロープツールを使ã£ã¦ã€é™¸åœ°ã‚’造æˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚造æˆã§ãる場所ã¯ä½•ã‚‚ãªã„空地や海上ã«é™ã‚‰ã‚Œã¾ã™ã€‚
[#]キー([shift+3])ã§ã€ã‚°ãƒªãƒƒãƒ‰ã‚’表示ã•ã›ã¦ãŠãã¨ä¾¿åˆ©ã§ã™ã€‚

陸地を高ãã™ã‚‹
 陸地をç¾åœ¨ã‚ˆã‚Šï¼‘レベル上ã®é«˜ã•ã«ç››ã‚Šä¸Šã’ã¾ã™ã€‚
陸地を低ãã™ã‚‹
 陸地をç¾åœ¨ã‚ˆã‚Šï¼‘レベル下ã®é«˜ã•ã«çªªã¾ã›ã¾ã™ã€‚

以上ã®ï¼’ã¤ã®ãƒ„ールã¯ã€å·¦ã‚¯ãƒªãƒƒã‚¯ã¾ãŸã¯å·¦ãƒœã‚¿ãƒ³ã‚’押ã—ãŸã¾ã¾ãƒ‰ãƒ©ãƒƒã‚°ã—ã¦ä½¿ç”¨ã—ã¾ã™ã€‚ドラッグã®å ´åˆã¯ã€ã™ã¹ã¦åŒã˜é«˜ã•ã«ãªã‚Šã¾ã™ã€‚
造æˆã™ã‚‹ä½“ç©ã«æ¯”例ã—ã¦ã€è²»ç”¨ãŒé«˜ããªã‚Šã¾ã™ã€‚
樹木ãªã©ã®è‡ªç„¶ç‰©ã¯å–り除ã‹ã‚Œã¦ã—ã¾ã„ã¾ã™ã€‚

スロープã®å»ºè¨­: 人工的ãªé€ æˆã‚’ã—ã¾ã™ã€‚

å·¦ã®ï¼”ã¤ã¯å‚¾æ–œåœ°ã‚’ã€å³ã®ï¼’ã¤ã¯åž‚ç›´ã«é™¸åœ°ã‚’盛り上ã’/切り下ã’ã—ã¾ã™ã€‚
人工的ãªé€ æˆã§ã¯ã€å‘¨å›²ã¨ã®æ®µå·®ã‚’2段以上ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
後者ã®ãƒ„ールã¯ç©ºåœ°ã‚„海上以外ã«ã€ç·šè·¯/é“è·¯/鋿²³(高架å«ã‚€)ã‚„é€é›»ç·šã®çµ‚端上ã§ã‚‚使用ã§ãã¾ã™ã€‚
ã¾ãŸã€é£›è¡Œæ©Ÿã®èª˜å°Žè·¯ã‚„滑走路ã«é©ç”¨ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。

ç·šè·¯/é“è·¯ã®çµ‚端上ã§ã®ä½¿ç”¨
ã“ã®å ´åˆã€ä¸»ã«å³ã®ï¼’ã¤ã®ãƒ„ールを使ã£ã¦ã€ç·šè·¯/é“è·¯/鋿²³ã”ã¨å‚¾æ–œã•ã›ã¾ã™ã€‚
å‘ããŒåˆãˆã°å·¦ã®ï¼”ã¤ã®ã‚¹ãƒ­ãƒ¼ãƒ—も使ãˆã¾ã™ãŒã€ã‚ã¾ã‚Šä¾¿åˆ©ã§ã¯ã‚りã¾ã›ã‚“。
å‚¾æ–œã‚’å…ƒã«æˆ»ã™å ´åˆã«ã‚‚ã€ã“れら2ã¤ã®ãƒ„ールを使用ã—ã¾ã™ã€‚
下りã®å‚¾æ–œã‚’å…ƒã«æˆ»ã™ã«ã¯ã€ç››ã‚Šä¸Šã’ツールãŒã€ä¸Šã‚Šã®å‚¾æ–œã‚’å…ƒã«æˆ»ã™ã«ã¯ã€åˆ‡ã‚Šä¸‹ã’ツールãŒä½¿ç”¨ã§ãã¾ã™ã€‚
地下ã§ç·šè·¯/é“路を傾斜ã•ã›ãŸã„å ´åˆã«ã¯ã€å¿…è¦ã§ã™ã€‚
地下ã§åˆ‡ã‚Šä¸Šã’を行ã£ãŸå¾Œã€ç·šè·¯/é“路を延伸ã™ã‚‹ã«ã¯ã€è¡¨ç¤ºè¨­å®šã‚ˆã‚Šåœ°ä¸‹è·¯ç·šå»ºè¨­ãƒ¢ãƒ¼ãƒ‰ã‚’使用ã—ã¦ãã ã•ã„。

スロープを戻ã™
人工的ãªé€ æˆåœ°ã‚„ãã®å‘¨å›²ã‚’ã€ã§ãã‚‹é™ã‚Šè‡ªç„¶ãªçŠ¶æ…‹ã«æˆ»ã—ã¾ã™ã€‚
ç·šè·¯/é“è·¯ã®çµ‚端上ã§ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。

simutrans-124.3/simutrans/text/ja/sound.txt000066400000000000000000000043451474050137200210550ustar00rootroot00000000000000サウンド設定ã®ãƒ˜ãƒ«ãƒ—

サウンド設定

サウンド設定 ダイアログã§ã¯åŠ¹æžœéŸ³ã¨BGMã®è¨­å®šãŒã§ãã¾ã™ã€‚サウンド設定ã¯ã‚²ãƒ¼ãƒ ã‚ªãƒ—ションメニューã‹ã‚‰é–‹ãã¾ã™.
メモ: Windowsã§ã¯SDLãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒéŸ³è³ªã«å„ªã‚Œã‚‹

矢å°ãƒœã‚¿ãƒ³ã‹ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ã‚’使用ã—ã¦éŸ³é‡ã®èª¿æ•´ãŒã§ãã¾ã™ã€‚

効果音ã®è¨­å®š(上段)

ミュート: å…¨ã¦ã®åŠ¹æžœéŸ³ã‚’æ­¢ã‚ã¾ã™ã€‚

効果音ã®éŸ³é‡: 効果音全体ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

効果音ã®å†ç”Ÿç¯„囲: 効果音ãŒå†ç”Ÿã•れる範囲を設定ã—ã¾ã™ã€‚設定値を大ããã™ã‚‹ã»ã©ãƒžã‚¦ã‚¹ã®ã‚«ãƒ¼ã‚½ãƒ«ã‹ã‚‰é›¢ã‚ŒãŸæ‰€ã®éŸ³ãŒèžã“ãˆã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚

ツールã®éŸ³é‡: ツールを使ã£ã¦æ“作ã—ãŸæ™‚ã®éŸ³é‡(調査ã€å»ºè¨­ã€æ’¤åŽ»ç­‰)を設定ã—ã¾ã™ã€‚

乗り物ã®éŸ³é‡: 車ã€åˆ—車ã€èˆ¹èˆ¶ã€èˆªç©ºæ©Ÿã®åŠ¹æžœéŸ³ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

環境音ã®éŸ³é‡: 環境音(é³¥ã®é³´ã声等)ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

産業施設ã®éŸ³é‡: 産業施設ã®åŠ¹æžœéŸ³ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

è¸åˆ‡ã®éŸ³é‡: è¸åˆ‡ã‚’列車ãŒé€šéŽã™ã‚‹æ™‚ã®åŠ¹æžœéŸ³ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

売買ã®éŸ³é‡: å–引ã®éš›ã«ç™ºç”Ÿã™ã‚‹åŠ¹æžœéŸ³ã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚

BGMã®è¨­å®š(下段)

ミュート: å…¨ã¦ã®BGMã‚’æ­¢ã‚ã¾ã™ã€‚

BGMã®éŸ³é‡: BGMã®éŸ³é‡ã‚’設定ã—ã¾ã™ã€‚(Windowsã§ã¯ãƒœãƒªãƒ¥ãƒ¼ãƒ ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã®ãƒŸã‚­ã‚µãƒ¼ã¨é€£å‹•ã—ã¦ã„ã¾ã™ï¼‰

æ¼”å¥ä¸­ã®æ›²: ç¾åœ¨å†ç”Ÿã•れã¦ã„ã‚‹BGMãŒè¡¨ç¤ºã•れã¾ã™ã€‚矢å°ãƒœã‚¿ãƒ³ã§å¤‰æ›´ã§ãã¾ã™ã€‚

シャッフルå†ç”Ÿ: ONã«ã™ã‚‹ã¨BGMをランダムãªé †ç•ªã§å†ç”Ÿã—ã¾ã™ã€‚OFFã«ã™ã‚‹ã¨é †ç•ªã«å†ç”Ÿã•れã¾ã™ã€‚

メモ: Simutransã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³èµ·å‹•オプションã«ã€Œ-nomidiã€ã€Œ-nosoundã€ã‚’指定ã—ã¦èµ·å‹•ã™ã‚‹ã¨BGMã¨åŠ¹æžœéŸ³ã‚’åœæ­¢ã—ã¦èµ·å‹•ã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/special.txt000066400000000000000000000211251474050137200213400ustar00rootroot00000000000000特別建築物ツール ヘルプ

特別建築物ツール

特別建築物ツール 特別建築物ツールã¯ã€äº¤é€šã«é–¢ä¿‚ã®ãªã„アイテムを建設ã™ã‚‹ã»ã‹ã€ã‚²ãƒ¼ãƒ å†…ã§ã‚ãªãŸãŒåˆ¥ã®ãƒ—レイヤーã¨ã—ã¦æ“作ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚ã‚‹ã€é»„色ã„丸ã®ä¸­ã«èµ¤ã„点ã®ã‚¢ã‚¤ã‚³ãƒ³ï¼ˆpak128ã§ã¯ã‚¯ãƒ¬ãƒ¼ãƒ³ã®ã‚¢ã‚¤ã‚³ãƒ³ï¼‰ã‚’クリックã™ã‚‹ã¨ã€ãƒ„ールãƒãƒ¼ãŒé–‹ãã¾ã™ã€‚
ツールãƒãƒ¼ã‚’é–‹ãã‹ã‚¯ãƒªãƒƒã‚¯ã—ãŸå¾Œã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ã‚’ツールオプションã«åˆã‚ã›ã‚‹ã¨ã€åå‰ã¨å¿…è¦ã«å¿œã˜ã¦å»ºè¨­è²»ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

特別建築物ツールã«ã¯ã€å·¦ã‹ã‚‰å³ã®é †ã«ä»¥ä¸‹ã®ã‚¢ã‚¤ãƒ†ãƒ ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚

郵便局: ストップ(駅やåœç•™æ‰€ãªã©ï¼‰ãŒéƒµä¾¿ã‚’扱ãˆã‚‹ã‚ˆã†ã«ã™ã‚‹ãŸã‚ã«ã€éƒµä¾¿å±€ã‚’建設ã™ã‚‹ãƒ„ールã§ã™ã€‚郵便局ã¯ã€ã‚¹ãƒˆãƒƒãƒ—ã®åŽå®¹é‡ã¨é›†å®¢ã‚¨ãƒªã‚¢ã‚’増やã—ã¾ã™ãŒã€ç¶­æŒè²»ãŒã‹ã‹ã‚Šã¾ã™ã€‚
郵便局を作るã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ã€ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ã§æ—¢å­˜ã®ã‚¹ãƒˆãƒƒãƒ—ã®ãã°ã‚’クリックã—ã¾ã™ã€‚æ–°ã—ã„郵便局ã¯ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€éƒ¨ã¨ã¿ãªã•れã¾ã™ã€‚
{ヒント 郵便局や一部ã®éšœå®³ç‰©ã¯ã€Œæ’¤åŽ»ï¼å–り壊ã—ã€ã§å–り除ãã¾ã™ã€‚}

é§…ã®æ‹¡å¼µ: ã‚¹ãƒˆãƒƒãƒ—ã®æ‹¡å¼µã‚„増築を行ã†ãŸã‚ã®ãƒ„ールã§ã™ã€‚増築ã™ã‚‹ã“ã¨ã§ã€è²¨ç‰©ã‚„乗客ã®åŽå®¹åŠ›ã‚„é›†å®¢ã‚¨ãƒªã‚¢ãŒå¢—加ã—ã€ç¶­æŒè²»ã‚‚増加ã—ã¾ã™ã€‚ã„ãã¤ã‹ã®ãƒ„ールオプションã®éš…ã«ã¯ã€ã‚¢ã‚¤ã‚³ãƒ³ï¼ˆã“れã¯é§…一覧ã¨ã‚¹ãƒˆãƒƒãƒ—情報ã§ä½¿ç”¨ã•れる)ãŒè¡¨ç¤ºã•れã€ãã®æ‹¡å¼µæ©Ÿèƒ½ã§ã‚¹ãƒˆãƒƒãƒ—ãŒæ‰±ãˆã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã‚’示ã—ã¦ã„ã¾ã™ã€‚
拡張部分を作るã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒæ‹¡å¼µéƒ¨åˆ†ã«å¤‰ã‚る)ã€ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ã§æ—¢å­˜ã®ã‚¹ãƒˆãƒƒãƒ—ã®æ¨ªã®å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚æ–°ã—ã„æ‹¡å¼µéƒ¨åˆ†ã¯ã€ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€éƒ¨ã¨ã¿ãªã•れã¾ã™ã€‚
{ヒント: 拡張部分ã®å‰Šé™¤ã«ã¯ã€ã€Œæ’¤åŽ»ï¼å–り壊ã—ã€ã‚’使用ã—ã¾ã™ã€‚}

P+ プレイヤー変更: P+ プレイヤー変更:ゲーム開始時ã«ãƒ—レイヤー変更を許å¯ãŒé¸æŠžã•れã¦ã„ãŸå ´åˆã€åˆ¥ã®ãƒ—レイヤーã¨ã—ã¦ã‚²ãƒ¼ãƒ ã‚’プレイã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚公共事業ã¨ã—ã¦è¿½åŠ ã®ã‚ªãƒ—ションãŒåˆ©ç”¨ã§ãã¾ã™ã€‚
ツールをクリックã—ã¦ï¼ˆã¾ãŸã¯ [P] を押ã—ã¦ï¼‰ãƒ—レーヤーを切り替ãˆã¦ãã ã•ã„。プレイヤーãŒå¤‰æ›´ã•れãŸã“ã¨ã‚’確èªã™ã‚‹ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•れã¾ã™ã€‚メッセージã®å·¦ä¸Šã«ã‚ã‚‹ x をクリックã™ã‚‹ã‹ã€ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ã§é–‰ã˜ã¦ãã ã•ã„。

æ–°ã—ã„街を作る: æ–°ã—ã„éƒ½å¸‚ã‚’ä½œã‚‹ï¼šãƒ„ãƒ¼ãƒ«ã¯æ–°ã—ã„街を作りã¾ã™ã€‚
æ–°ã—ã„都市を建設ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã™ã‚‹ã‹ã€ [C] キーを押ã—ã¦é¸æŠžã—(カーソルãŒå¸‚町æ‘役場ã«å¤‰ã‚りã¾ã™ï¼‰ã€ã‚²ãƒ¼ãƒ ãƒ“ュー内ã®å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚æ–°ã—ã„è¡—ã®å»ºè¨­ã«ã¯500万クレジットãŒå¿…è¦ã§ã€è¿½åŠ ã®ç¢ºèªãªã—ã«å»ºè¨­ã•れã¾ã™ã€‚
{ヒント: ゲームビュー上ã®å½¹å ´ã‚’「撤去ï¼å–り壊ã—ã€ã§ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€æ–°ã—ã„è¡—ã®ã™ã¹ã¦ã®å»ºç‰©ãŒå‰Šé™¤ã•れã¾ã™ã€‚}

木をæ¤ãˆã‚‹: ツールã¯ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ã«æœ¨ã‚’é…ç½®ã—ã¾ã™ã€‚
木をæ¤ãˆã‚‹ã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒæœ¨ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚
{ヒント: 撤去ï¼å–り除ãã€ã§æœ¨ã€…ã‚’å–り除ãã¾ã™ã€‚}

é€é›»ç·šã®å»ºè¨­: é€é›»ç·šã®å»ºè¨­ï¼šãƒ„ールã¯ç™ºé›»æ‰€ã®å¤‰é›»æ‰€ã¨ç”£æ¥­ã¨ã®é–“ã«é›»åŠ›ã‚’ä¾›çµ¦ã™ã‚‹é€é›»ç·šã‚’建設ã—ã¾ã™ï¼ˆç”Ÿç”£æ€§å‘上ã®ãŸã‚)。電力を供給ã™ã‚‹ã“ã¨ã§åŽå…¥ãŒå¾—られã¾ã™ã€‚ã“ã®é€é›»ç·šã¯ã€æ–œã‚ã®ç·šè·¯ã‚„é“路を越ãˆã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。
高圧線を作るã«ã¯ã€ãƒ„ールをクリックã™ã‚‹ã‹ã€[l] キーを押ã—ã¦é¸æŠžã—(カーソルãŒé€é›»ç·šã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«ç™ºé›»æ‰€ã®éš£ã«ç½®ã‹ã‚ŒãŸå¤‰é›»æ‰€ã‚’クリックã—ã€æœ€å¾Œã«ç”£æ¥­ã®å¤‰é›»æ‰€ã‚’クリックã—ã¦ã€é›»åŠ›ã‚’ä¾›çµ¦ã—ã¦ç”Ÿç”£é‡ã‚’増やã—ã¾ã™ã€‚

変電所 変電所ツールã¯ã€ç™ºé›»æ‰€ã‚„産業ã«å¤‰é›»æ‰€ã‚’建設ã—ã€é«˜å‡ºåŠ›ã®é€é›»ç·šã«æŽ¥ç¶šã™ã‚‹ãŸã‚ã®ãƒ„ールã§ã™ã€‚
変電所を作るã«ã¯ã€ãƒ„ールをクリックã™ã‚‹ã‹ã€ [g] を押ã—ã¦é¸æŠžã—(カーソルãŒé»„色ã®ä¸­ã«èµ¤è‰²ã®ç‚¹ã«å¤‰ã‚りã¾ã™ï¼‰ã€ã‚²ãƒ¼ãƒ ãƒ“ューã§ç”£æ¥­ã‚„ç™ºé›»æ‰€ã®æ¨ªã«ã‚ã‚‹å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚
発電所ã«ä½œã‚‰ã‚ŒãŸå¤‰é›»æ‰€ã¯ã€ç”£æ¥­ã«ä½œã‚‰ã‚ŒãŸå¤‰é›»æ‰€ã¨é€é›»ç·šã§çµã°ã‚Œã¦ã„ãªã„ã¨é›»æ°—ãŒä¾›çµ¦ã•れã¾ã›ã‚“。
電気ãŒä¾›çµ¦ã•れã¦ã„ãªã„å ´åˆã€ã‚²ãƒ¼ãƒ ãƒ“ュー上ã®å¤‰é›»æ‰€ã«ã¯é»„色ã®ç¨²å¦»ãƒžãƒ¼ã‚¯ãŒè¡¨ç¤ºã•れã€é›»æ°—ãŒä¾›çµ¦ã•れã¦ã„ã‚‹å ´åˆã¯èµ¤è‰²ã®ç¨²å¦»ãƒžãƒ¼ã‚¯ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
{ヒント: 産業や発電所ã¯ã€é›»æ°—ã®ä¾›çµ¦é‡ã‚’増やã™ãŸã‚ã«è¤‡æ•°ã®å¤‰é›»æ‰€ã‚’所有ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚å¤‰é›»æ‰€ã¯æ’¤åŽ»ï¼å–り壊ã—ã§å‰Šé™¤ã—ã¦ãã ã•ã„。ï½

マーカー(サインを作る): ツールを起動ã™ã‚‹ã¨ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãŒé–‹ãã€ã‚²ãƒ¼ãƒ ãƒ“ューã«ãƒ—レイヤーãŒè‡ªåˆ†ã§ä½œã£ãŸæ–‡å­—(テキスト)をå«ã‚€ã‚µã‚¤ãƒ³ï¼ˆçœ‹æ¿ï¼‰ã‚’é…ç½®ã™ã‚‹ã“ã¨ãŒã§ãã€ã‚²ãƒ¼ãƒ ãƒ“ューを別ã®åœ°ç‚¹ã«ç§»å‹•ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚
ツールをクリックã—ã¦é¸æŠžã™ã‚‹ã‹ã€[M] を押ã™ã¨ã‚«ãƒ¼ã‚½ãƒ«ãŒãƒ†ã‚­ã‚¹ãƒˆãƒžãƒ¼ã‚«ãƒ¼ã«å¤‰ã‚ã‚‹ã®ã§ã€ã‚²ãƒ¼ãƒ ãƒ“ュー内ã®å¿…è¦ãªä½ç½®ã‚’クリックã—ã¦ã€Œãƒžãƒ¼ã‚«ãƒ¼ã€ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’é–‹ãã¾ã™ã€‚マーカーコントロールã®ä¸Šéƒ¨ã«ã¯ã€é¸æŠžã—ãŸä½ç½®ã®åœ°å›³ä¸Šã®åº§æ¨™ã¨ç©ºã®ãƒœãƒƒã‚¯ã‚¹ãŒè¡¨ç¤ºã•れるã®ã§ã€ãƒœãƒƒã‚¯ã‚¹ã«å¿…è¦ãªãƒ†ã‚­ã‚¹ãƒˆã‚’入力ã—ã¦ï¼ˆãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¦ãƒ†ã‚­ã‚¹ãƒˆã‚’入力ã—ã€OK をクリックã™ã‚‹ã‹[Enter]ã‚ã‚‹ã„ã¯[Return]を押ã—ã¦ï¼‰ã‚µã‚¤ãƒ³ã‚’設置ã—ã¾ã™ã€‚æ–°ã—ã„サインã¯ã‚²ãƒ¼ãƒ ãƒ“ューã«è¡¨ç¤ºã•れã€å†åº¦é–‹ãã¨ãƒžãƒ¼ã‚«ãƒ¼ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã«ãƒªã‚¹ãƒˆã‚¢ãƒƒãƒ—ã•れã¾ã™ï¼ˆåœ°å›³ä¸Šã®åº§æ¨™ã‚‚表示)。
ゲームビューをサインã®ã‚ã‚‹ä½ç½®ã¸ç§»å‹•ã™ã‚‹ã«ã¯ã€ãƒžãƒ¼ã‚«ãƒ¼ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’é–‹ãã€ä¸€è¦§ã®ä¸­ã‹ã‚‰å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚
マーカーを削除ã™ã‚‹ã«ã¯ãƒžãƒ¼ã‚«ãƒ¼ãƒ„ールをクリックã™ã‚‹ã‹ã€[M] を押ã—ã¦é¸æŠžã™ã‚‹ã¨ã€ã‚«ãƒ¼ã‚½ãƒ«ãŒãƒ†ã‚­ã‚¹ãƒˆãƒžãƒ¼ã‚«ãƒ¼ã«å¤‰ã‚ã‚‹ã®ã§ã€ã‚²ãƒ¼ãƒ ãƒ“ューã§ã‚µã‚¤ãƒ³ã®åº§æ¨™ã‚’クリックã—ã€ãƒžãƒ¼ã‚«ãƒ¼ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã§å‰Šé™¤ã‚’クリックã—ã¾ã™ã€‚
マーカーコントロールを閉ã˜ã‚‹ã«ã¯ã€ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã®å·¦ä¸Šã«ã‚ã‚‹ x をクリックã™ã‚‹ã‹ã€ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã‚’クリックã™ã‚‹ã‹ã€ã¾ãŸã¯ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ã‚’使用ã—ã¾ã™ã€‚
{ヒント: ゲームビュー下部ã®ãƒãƒ¼ã®å³å´ã«ã¯ã€ã‚«ãƒ¼ã‚½ãƒ«ã®åœ°å›³åº§æ¨™ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ゲームビューã§ã‚µã‚¤ãƒ³ã®ãƒ†ã‚­ã‚¹ãƒˆã‚’切り替ãˆã‚‹ã«ã¯ [!] を使ã„ã¾ã™ã€‚ï½

スケジュール移動ツール: ã“ã®ãƒ„ールを使ã†ã¨ã€ãã®ã‚¹ãƒˆãƒƒãƒ—(駅やåœç•™æ‰€ãªã©ï¼‰ã‚’使用ã—ã¦ã„ã‚‹ã™ã¹ã¦ã®è»Šä¸¡ã¨è·¯ç·šã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã€ã‚¹ãƒˆãƒƒãƒ—ã‚’ç½®ãæ›ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã¾ãŸã€ã‚¹ãƒˆãƒƒãƒ—内ã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚¿ã‚¤ãƒ«ã‚’変更ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ï¼ˆä¾‹ãˆã°ã€ã™ã¹ã¦ã®è·¯ç·šã‚’鉄é“é§…ã®åˆ¥ã®ãƒ—ラットフォームã«ç§»å‹•ã•ã›ã‚‹å ´åˆãªã©ï¼‰ã€‚ãƒ„ãƒ¼ãƒ«ã‚’é¸æŠžã—ãŸå¾Œã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‹ã‚‰å‰Šé™¤ã—ãŸã„ストップ(ã¾ãŸã¯ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€éƒ¨ï¼‰ã‚’クリックã—ã€æ¬¡ã«ä»Šå¾Œä½¿ç”¨ã—ãŸã„ストップ(ã¾ãŸã¯ã‚¹ãƒˆãƒƒãƒ—ã®ä¸€éƒ¨ï¼‰ã‚’クリックã—ã¾ã™ã€‚最åˆã®ã‚¹ãƒˆãƒƒãƒ—を使用ã—ã¦ã„ãŸä»¥å‰ã®å…¨è»Šä¸¡ã¯ã€2番目ã®ã‚¹ãƒˆãƒƒãƒ—を使用ã™ã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚スケジュールã®è¨­å®šã«ã‚ˆã£ã¦ã¯ã€å¤‰æ›´æ™‚ã«1ã¤ç›®ã®ã‚¹ãƒˆãƒƒãƒ—ã«å‘ã‹ã†è»Šä¸¡ã«æ··ä¹±ãŒç”Ÿã˜ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/station.txt000066400000000000000000000022401474050137200213760ustar00rootroot00000000000000駅情報

駅情報ダイアログ

 駅情報ダイアログã«ã¯ã€ãã®é§…ã«é–¢ã™ã‚‹æƒ…å ±ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ã¾ãŸã€ã“ã“ã§
é§…åを変更ã™ã‚‹äº‹ã‚‚ã§ãã¾ã™ã€‚ãªãŠã€ã“ã“ã§ã„ã†ã€Œé§…ã€ã¯ã€é‰„é“é§…ã ã‘ã§ãªããƒã‚¹åœã‚„港ã€ç©ºæ¸¯ã‚‚å«ã¿ã¾ã™ã€‚

 ダイアログ上部ã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ィールドã«ã¯ã€é§…åãŒè¡¨ç¤ºã•れã¦ã„ã¾ã™ã€‚ã“ã“ã«
文字を入力ã™ã‚‹äº‹ã§ã€é§…åを変更ã§ãã¾ã™ã€‚

 å³å´ã«ã‚る詳細ボタンをクリックã™ã‚‹ã¨ã€ãã®é§…ã«é–¢ã™ã‚‹ã‚ˆã‚Šè©³ç´°ãªæƒ…報を
調ã¹ã‚‹äº‹ãŒå‡ºæ¥ã¾ã™ã€‚

 駅情報ダイアログã®ä¸»è¦ãªéƒ¨åˆ†ã¯ã€ä¸‹éƒ¨ã«ã‚る貨物・乗客リストã§ã™ã€‚ã“ã“
ã«ã¯ã€ãã®é§…ã§è¼¸é€ã‚’å¾…ã£ã¦ã„る貨物や乗客ã®ä¸€è¦§ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ã“ã®ä¸€è¦§
情報ã¯ã€è²¨ç‰©ã®ç¨®é¡žã”ã¨ã€ç›®çš„地ã”ã¨ã«è¡¨ç¤ºã•れã¾ã™ã€‚ã¾ãŸã€ã“ã“ã«è¡¨ç¤ºã•れ
る情報ã¯ã‚²ãƒ¼ãƒ ã®é€²è¡Œã«ä¼´ã£ã¦è‡ªå‹•çš„ã«æ›´æ–°ã•れã¾ã™ã®ã§ã€æœ€æ–°ã®æƒ…報を得る
ãŸã‚ã«ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‰ã˜ã¦é–‹ããªãŠã™å¿…è¦ã¯ã‚りã¾ã›ã‚“。

simutrans-124.3/simutrans/text/ja/station_details.txt000066400000000000000000000013431474050137200231060ustar00rootroot00000000000000駅情報詳細ダイアログ

駅情報詳細ダイアログヘルプ

 駅詳細ダイアログã§ã¯ã€ã“ã®é§…ã«æŽ¥ç¶šã•れã¦ã„る工場を示ã—ã¦ã„ã¾ã™ã€‚ã¾ãŸã€
ã“れらã®å·¥å ´ãŒã©ã®è£½å“ã‚’å¿…è¦ã¨ã—ã¦ã„ã‚‹ã‹ã‚‚示ã—ã¦ã„ã¾ã™ã€‚

 ã“ã®æŽ¥ç¶šæƒ…å ±ã¯ã€ä¹—りæ›ãˆã‚’ã—ãªã„ã§ç›´æŽ¥å±Šã‘ã‚‹ã“ã¨ãŒã§ãる目的地ã ã‘ã‚’
示ã—ã¦ã„ã¾ã™ã€‚乗客ã¨è²¨ç‰©ã¯ã€æœ€çµ‚çš„ãªç›®çš„地ã«è¾¿ã‚Šç€ãã®ã«å¿…è¦ãªã‚‰ä½•度ã‹
ã®ä¹—りæ›ãˆã‚’試ã¿ã¾ã™ã€‚

 駅ã®è©³ç´°ã¯ã€é§…情報ダイアログã«ã‚る詳細ボタンを押ã™ã“ã¨ã«ã‚ˆã£ã¦é–‹ã
ã“ã¨ãŒã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/trafficlight_info.txt000066400000000000000000000025231474050137200234020ustar00rootroot00000000000000äº¤é€šä¿¡å·æ©Ÿã®åˆ¶å¾¡

äº¤é€šä¿¡å·æ©Ÿã®åˆ¶å¾¡

接続方å‘
ç¾åœ¨é€šè¡Œå¯èƒ½ãªæ–¹å‘ã§ã™ã€‚

é€šè¡Œè¨±å¯æ™‚é–“ã®è¨­å®š
ä¸‹éƒ¨ã®æ•°å€¤å…¥åŠ›ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã§ã€é€šè¡Œè¨±å¯æ™‚間を設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

å—北: å·¦å´ã®æ•°å€¤å…¥åŠ›ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã§ã¯å—北方å‘ã®é€šè¡Œè¨±å¯æ™‚間を設定ã—ã¾ã™ã€‚設定å˜ä½ã¯ç§’ã§ã™ã€‚
ã“ã®å—北ã¨ã¯ã€ãƒžãƒƒãƒ—ä½œæˆæ™‚ã®å—北方å‘を指ã—ã¾ã™ã€‚
マップを回転ã—ãŸå ´åˆã€ç¾åœ¨ã®å—北方å‘ã¨ã¯ç•°ãªã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚

æ±è¥¿: ä¸­å¤®ã®æ•°å€¤å…¥åŠ›ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã§ã¯æ±è¥¿æ–¹å‘ã®é€šè¡Œè¨±å¯æ™‚間を設定ã—ã¾ã™ã€‚設定å˜ä½ã¯ç§’ã§ã™ã€‚
ã“ã®æ±è¥¿ã¨ã¯ã€ãƒžãƒƒãƒ—ä½œæˆæ™‚ã®æ±è¥¿æ–¹å‘を指ã—ã¾ã™ã€‚
マップを回転ã—ãŸå ´åˆã€ç¾åœ¨ã®æ±è¥¿æ–¹å‘ã¨ã¯ç•°ãªã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚

3番目ã®ãƒ•ィールド: å³å´ã®æ•°å€¤å…¥åŠ›ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã§ã¯ã‚ªãƒ•セットを設定ã—ã¾ã™ã€‚設定å˜ä½ã¯ç§’ã§ã™ã€‚
ã™ã¹ã¦ã®ä¿¡å·æ©Ÿã¯åŒæ–¹å‘ã§åˆ‡ã‚Šæ›¿ã‚ã‚‹ã®ã§ã€å¾Œç¶šã®ä¿¡å·æ©Ÿã§ç‰¹å®šã®æ–¹å‘ã®äº¤é€šæµã‚’妨ã’ãªã„よã†ã«ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

ä¿¡å·æ©Ÿã¯ã€é“路ツールã‹ã‚‰æ§‹ç¯‰ã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/tramtools.txt000066400000000000000000000252741474050137200217550ustar00rootroot00000000000000市電ï¼è»½ä¾¿é‰„é“ツール ヘルプ

市電ï¼è»½ä¾¿é‰„é“ツール

市電ï¼è»½ä¾¿é‰„é“ツール è·¯é¢é›»è»Šã®è¼¸é€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’構築ã—ã¾ã™ã€‚ã“ã®ãƒ„ールã§ã¯ã€å¸‚é›»ã®è»Œé“(ãŠã‚ˆã³ãã®é›»åŒ–・撤去)ã€ä¿¡å·ã€å¸‚é›»ã®è»Šåº«ã€å¸‚é›»ã®é§…ãªã©ã‚’設置ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚年代設定ã§ãƒ—レイã—ã¦ã„ã‚‹å ´åˆã€Simutransã§æ™‚é–“ãŒçµŒéŽã™ã‚‹ã¨ã€ã‚ˆã‚Šå¤šãã®ãƒ„ールオプションãŒè¡¨ç¤ºã•れるã“ã¨ãŒã‚りã¾ã™ã€‚

ゲームビューã®ä¸Šéƒ¨ã«ã‚る市電ï¼è»½ä¾¿é‰„é“ツールã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã—ã¦ã€ãƒ„ールãƒãƒ¼ã‚’é–‹ãã¾ã™ã€‚
ツールãƒãƒ¼ã‚’é–‹ãã‹ã‚¯ãƒªãƒƒã‚¯ã—ãŸå¾Œã€ãƒžã‚¦ã‚¹ã‚«ãƒ¼ã‚½ãƒ«ã‚’ツールオプションã®ä¸Šã«ç½®ãã¨ã€åå‰ã¨å¿…è¦ã«å¿œã˜ã¦å»ºè¨­è²»ã€æœ€é«˜é€Ÿåº¦ãŒè¡¨ç¤ºã•れã¾ã™ã€‚

市電ï¼è»½ä¾¿é‰„é“ツールã®ãƒ„ールã«ã¯ã€å·¦ã‹ã‚‰é †ã«æ¬¡ã®ã‚ˆã†ãªã‚‚ã®ãŒã‚りã¾ã™ã€‚

軌é“: 2点間ã®é§…ã‚’çµã¶åˆ—車ã®è»Œé“(線路)を建設ã™ã‚‹ãƒ„ールã§ã™ã€‚
市電(路é¢é›»è»Šï¼‰ã®è»Œé“ã¯ã€é“路沿ã„や市街地ã«å»ºè¨­ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ãŒã€ä»–ã®å»ºç‰©ãŒå»ºã£ã¦ã„る場所ã«ã¯å»ºè¨­ã§ãã¾ã›ã‚“。市電ã®è»Œé“ã¯ã€æ–œé¢ä¸Šã«ä½œã‚‹å ´åˆã¯æ–œé¢ã®ã‚ã‚‹æ–¹å‘ã«ã®ã¿å»ºè¨­ã™ã‚‹ã“ã¨ãŒã§ãã€ä¸æ•´åœ°ã€æ°´ä¸Šã€éšœå®³ç‰©ã®ä¸Šã«ã¯å»ºè¨­ã§ãã¾ã›ã‚“。新ã—ã„軌é“ã¯ã€æ—¢å­˜ã®è»Œé“を使用ã—ã¦è¨­ç½®ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
軌é“を作るã«ã¯ï¼šãƒ„ールをクリックã—ã¦è»Œé“ã‚’é¸æŠžã—(カーソルãŒè»Œé“ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«ã‚²ãƒ¼ãƒ ãƒ“ューをクリックã—ã¦è»Œé“ã®å§‹ç‚¹ã‚’決ã‚(ゲームビューã«ãƒ–ルドーザーãŒè¡¨ç¤ºã•れã€ã‚²ãƒ¼ãƒ ãƒ“ュー下部ã®ãƒãƒ¼ã®å³ã«åœ°å›³ã®åº§æ¨™ãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æœ€å¾Œã«ã‚²ãƒ¼ãƒ ãƒ“ューをクリックã—ã¦è»Œé“ã®çµ‚点を決ã‚ã¾ã™ã€‚
{ヒント: ç•°ãªã‚‹ç¨®é¡žã®ç·šè·¯ã‚’接続ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼ˆãŸã ã—ã€ä»–ã®ãƒ—レイヤーãŒä½œã£ãŸè»Œé“ã¯æŽ¥ç¶šã§ãã¾ã›ã‚“)。橋やトンãƒãƒ«ã‚’使ã£ã¦ä¸æ•´åœ°ã®è»Œé“ã‚’ã¤ãªã’ãŸã‚Šã€éšœå®³ç‰©ã‚’é¿ã‘ãŸã‚Šã—ã¾ã™ã€‚撤去ï¼å–り除ãを使ã†ã¨ã€è»Œé“ã®å€‹ã€…ã®éƒ¨å“や一部ã®éšœå®³ç‰©ã‚’å–り除ãã“ã¨ãŒã§ãã¾ã™ã€‚[Ctrl] ã‚’åŒæ™‚ã«æŠ¼ã™ã¨ã€ã•ã‚‰ã«æ©Ÿèƒ½ãŒå¢—ãˆã¾ã™ã€‚å…ƒã«æˆ»ã™ [z] ã§ã¯ã€å»ºè¨­è²»ã®æ‰•ã„æˆ»ã—ã¯ã§ãã¾ã›ã‚“。ï½

軌é“ã®é›»åŒ–: ゲームビュー上ã®2ç‚¹é–“ã®æ©‹ã‚„トンãƒãƒ«ã€è»Œé“ã‚’ã€é›»è»ŠãŒåˆ©ç”¨ã§ãるよã†ã«é›»åŒ–ã™ã‚‹ãƒ„ールã§ã™ã€‚
軌é“を電化ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã™ã‚‹ã‹ã€[e]を押ã—ã¦ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒé›»æ°—トラックã®ã‚¢ã‚¤ã‚³ãƒ³ã«å¤‰ã‚りã¾ã™ï¼‰é¸æŠžã—ã€ã‚²ãƒ¼ãƒ ãƒ“ューã®è»Œé“上ã§é›»åŒ–ã®é–‹å§‹ç‚¹ã‚’クリックã—(ゲームビューã«é›»æ°—トラックã®ã‚¢ã‚¤ã‚³ãƒ³ãŒè¡¨ç¤ºã•れã¾ã™ï¼‰ã€æœ€å¾Œã«è»Œé“上ã®2ã¤ç›®ã®ç‚¹ã‚’クリックã™ã‚‹ã¨ã€é–‹å§‹ç‚¹ã¾ã§ã®è»Œé“ã®ä¸€éƒ¨ãŒé›»åŒ–ã•れã¾ã™ã€‚
{ヒント: 電化ã•れã¦ã„ãªã„å…ƒã®è»Œé“ã«æˆ»ã™ã«ã¯ã€æ’¤åŽ»ï¼å–り壊㗠を使ã„ã¾ã™ã€‚ï½

鉄é“ã®æ’¤åŽ»: ゲームビュー上ã®2点間ã®ã€è»Šä¸¡ãŒå­˜åœ¨ã—ãªã„軌é“ã¨é›»æ°—軌é“を削除ã™ã‚‹ãƒ„ールã§ã™ï¼ˆçµŒè·¯ä¸Šã®é§…ã®ãƒ›ãƒ¼ãƒ ã€åœè»Šå ´ã€ä¿¡å·ã€ãƒˆãƒ³ãƒãƒ«ã€æ©‹ã‚‚削除ã•れã¾ã™ï¼‰ã€‚ツールã®ä½¿ç”¨ã«ã¯å»ºè¨­è²»ãŒã‹ã‹ã‚Šã¾ã™ã€‚
軌é“を削除ã™ã‚‹ã«ã¯ã€ãƒ„ールをクリックã—(カーソルãŒèµ¤ã„åå­—ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«å‰Šé™¤ã—ãŸã„軌é“をクリックã—(ゲームビューã§èµ¤ã®åå­—ã§ç¤ºã•れる削除ãƒã‚¤ãƒ³ãƒˆãŒé¸æŠžã•れã¾ã™ï¼‰ã€æœ€å¾Œã«æŽ¥ç¶šã•れãŸè»Œé“ã®äºŒã¤ç›®ï¼ˆçµ‚端)ã®ãƒã‚¤ãƒ³ãƒˆã‚’クリックã™ã‚‹ã¨ã€æœ€åˆã®å‰Šé™¤ãƒã‚¤ãƒ³ãƒˆã¾ã§ã®éƒ¨åˆ†ãŒå‰Šé™¤ã•れã¾ã™ã€‚
{ヒント: ä»–ã®ãƒ—レイヤーã«äº¤ä»£ã—ã¦ã€å…ƒã®ãƒ—レイヤーã®è»Œé“ãŒå‰Šé™¤ã§ãã¾ã™ã€‚ï½

ä¿¡å·: ゲームビューã®è»Œé“上ã§ã€é‰„é“車両ã®ä¿¡å·ã‚’設置ã™ã‚‹ãƒ„ールã§ã™ã€‚ä¿¡å·ã¯ã€ç·šè·¯ã‚„æ©‹ã€åˆ†å²ç‚¹ã‚„ストップ(åœè»Šå ´ï¼‰ï¼ˆè·ç‰©ã‚„乗客を乗ã›ãŸã‚Šé™ã‚ã—ãŸã‚Šã™ã‚‹å ´æ‰€ï¼‰ã§è»Šä¸¡ã®æµã‚Œã‚’指示・è¦åˆ¶ã—ã¾ã™ã€‚
ä¿¡å·ã«ã¯ã€åŒæ–¹å‘ã¨ä¸€æ–¹é€šè¡Œã®ã‚‚ã®ãŒã‚りã¾ã™ã€‚線路上ã«åŒæ–¹å‘ä¿¡å·ã‚’作るã«ã¯ã€ãƒ„ールをクリックã—ã¦ä¿¡å·ã‚’é¸æŠžï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒä¿¡å·ã«å¤‰ã‚る)ã—ã€è»Œé“をクリックã—ã¾ã™ã€‚一方通行ã®ä¿¡å·ã‚’作るã«ã¯ã€åŒã˜å ´æ‰€ã§ä¿¡å·ã‚«ãƒ¼ã‚½ãƒ«ã‚’使ã£ã¦ã‚‚ã†ä¸€åº¦ã‚¯ãƒªãƒƒã‚¯ã™ã‚‹ã¨ã€ä¸€æ–¹é€šè¡Œã®ä¿¡å·ã‚’経ã¦ã€å†ã³åŒæ–¹å‘ã®ä¿¡å·ã«æˆ»ã‚Šã¾ã™ã€‚
é‡è¦ï¼šè»Šä¸¡ãŒç›®çš„地ã«åˆ°é”ã§ããªã„よã†ãªä¸€æ–¹é€šè¡Œã®ä¿¡å·ã‚’設置ã—ãªã„よã†ã«æ³¨æ„ã—ã¦ãã ã•ã„。標準ã§ã¯ã€è»Šä¸¡ã¯å³å´é€šè¡Œã‚’ã—ã¾ã™ï¼ˆsimuconf.tabã§å¤‰æ›´å¯èƒ½ï¼‰ã€‚
- ä¿¡å·æ©Ÿ: 次ã®ä¿¡å·ã‚„スケジュールã®ç›®çš„地(ストップや信å·ãƒ»æ¨™è­˜ï¼‰ã¾ã§ã®è»Œé“ãŒä»–ã®è»Šä¸¡ã«å æœ‰ã•れã¦ã„ãªã„å ´åˆã®ã¿ã€è»Šä¸¡ã¯é€²ã¿ã¾ã™ã€‚一方通行モードã§ã¯ã€è»Šä¸¡ã¯ä¸€æ–¹å‘ã«ã—ã‹é€²ã¿ã¾ã›ã‚“。
- RailClose: 車両ã¯ä¿¡å·ã‚’è¶Šãˆã¦é€²ã¿ã¾ã›ã‚“(一方通行モードã§ã®ã¿ä½¿ç”¨å¯èƒ½ï¼‰ã€‚
- プレシグナル: 先行ã™ã‚‹è»Œé“ã®ç¯„囲(連続ã™ã‚‹3ã¤ã®ä¿¡å·ã®é–“ã‹ã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ä¸Šã®æ¬¡ã®ç›®çš„地ã¾ã§ï¼‰ãŒä»–ã®è»Šä¸¡ã«ã‚ˆã£ã¦å æœ‰ã•れã¦ã„ãªã„å ´åˆã€è»Šä¸¡ã¯é€²ã¿ã¾ã™ã€‚一方通行モードã§ã¯ã€ä¸€æ–¹å‘ã«ã®ã¿è»Šä¸¡ã‚’通éŽã•ã›ã¾ã™ã€‚
- ãƒãƒ¥ãƒ¼ã‚ºã‚·ã‚°ãƒŠãƒ«: 複数ã®ãƒ—ラットフォームãŒã‚ã‚‹é§…ã§ã€ç©ºã„ã¦ã„るプラットフォームã«è»Šä¸¡ã‚’誘導ã—ã¾ã™ã€‚ã“ã®ä¿¡å·ã‚’通éŽã—ãŸè»Šä¸¡ã¯ã€ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸã‚‚ã®ã ã‘ã§ãªãã€æ¬¡ã®ç›®çš„地ã®ç©ºã„ã¦ã„るプラットフォームを利用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚空ãプラットフォームや次ã®ç›®çš„地ã¸ã®æ˜Žç¢ºãªãƒ«ãƒ¼ãƒˆãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã€è»Šä¸¡ã¯ä¿¡å·ã§å¾…機ã—ã¾ã™ã€‚
{ヒント: 撤去ï¼å–り壊ã—ã§ä¿¡å·ã‚’削除ã—ã¾ã™ã€‚[Ctrl] を押ã—ãªãŒã‚‰ã ã¨ã€ä¸‹ã®ç·šè·¯ã«æž¶ã‹ã‚‹æ©‹ã«ä¿¡å·ã‚’設置ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚}

市電車庫: 市電を購入・管ç†ã™ã‚‹ãŸã‚ã®è»Šä¸¡åº«ã‚’建設ã™ã‚‹ãƒ„ールã§ã™ã€‚
市電車庫ã«ã¯ç¶­æŒè²»ãŒã‹ã‹ã‚Šã€ã‚²ãƒ¼ãƒ ãƒ“ューã®è»Œé“ã®ç«¯ã«å»ºã¦ã‚‰ã‚Œã¾ã™ã€‚
市電車庫を作るã«ã¯ã€ãƒ„ールをクリックã—(カーソルãŒè»Šåº«ã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«è»Œé“ã®ç«¯ã‚’クリックã—ã¾ã™ã€‚
{ヒント: 車庫ãŒé›»æ°—軌é“上ã«ã‚ã‚‹å ´åˆã¯ã€é›»è»Šã®ã¿è¡¨ç¤ºã•れã¾ã™ã€‚è»Šåº«ã¯æ’¤åŽ»ï¼å–り壊ã—ã§å‰Šé™¤ã—ã¦ãã ã•ã„。ï½

レールストップ: ã“ã®ãƒ„ールã¯ã€åˆ—車ãŒè·ç‰©ã‚„乗客ã€éƒµä¾¿ç‰©ã‚’ç©ã¿é™ã‚ã—ã™ã‚‹ãŸã‚ã®é§…ã®ãƒ—ラットフォームを建設ã—ã¾ã™ã€‚
既存ã®é§…ã«éš£æŽ¥ã—ã¦é§…ã®ãƒ—ラットフォームãŒå»ºè¨­ã•れã¦ã„ãªã„å ´åˆã€æ–°ã—ã„é§…ãŒä½œã‚‰ã‚Œã¾ã™ã€‚
レールストップã«ã¯ç¶­æŒè²»ãŒã‹ã‹ã‚Šã€è»Œé“上ã«å»ºè¨­ã•れã¾ã™ï¼ˆãŸã ã—ã€è»Œé“ã®æ›²ãŒã‚Šè§’や分å²ç‚¹ã«ã¯å»ºè¨­ã•れã¾ã›ã‚“)。
レールストップã«ã¯ã€å•†å“ã€ä¹—客ã€éƒµä¾¿ç‰©ãªã©ã®é›†å®¢ã‚¨ãƒªã‚¢ãŒã‚りã¾ã™ã€‚é§…ã®ãƒ—ラットフォームã«ã‚ˆã£ã¦ã€ä¹—客や郵便物ã®åŽå®¹èƒ½åŠ›ãŒç•°ãªã‚‹å ´åˆãŒã‚りã¾ã™ã€‚ã„ãã¤ã‹ã®ãƒ„ールオプションã®éš…ã«ã‚るアイコン(駅一覧ã¨ã‚¹ãƒˆãƒƒãƒ—情報ã§ä½¿ç”¨ï¼‰ã¯ã€é§…ã®ãƒ—ラットフォームãŒã‚¹ãƒˆãƒƒãƒ—ã«ã©ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’å–り扱ã‚ã›ã‚‹ã“ã¨ãŒã§ãã‚‹ã‹ã‚’示ã—ã¦ã„ã¾ã™ã€‚
é§…ã®ãƒ—ラットフォームを作るã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—(カーソルãŒãƒ—ラットフォームã«å¤‰ã‚りã¾ã™ï¼‰ã€æ¬¡ã«è»Œé“をクリックã—ã¾ã™ã€‚
{ヒント: 撤去ï¼å–り壊ã—ã§ãƒ¬ãƒ¼ãƒ«ã‚¹ãƒˆãƒƒãƒ—を削除ã—ã¾ã™ã€‚é§…ã®ãƒ—ラットフォームを延長ã—ãŸã‚Šã€è¤‡æ•°ã®ãƒ—ラットフォームをæŒã¤ã‚¹ãƒˆãƒƒãƒ—を建設ã™ã‚‹ã“ã¨ã§ï¼ˆéš£æŽ¥ã™ã‚‹ãƒˆãƒ©ãƒƒã‚¯ã«ãƒ›ãƒ¼ãƒ ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚’増設ã™ã‚‹ã“ã¨ã«ã‚ˆã£ã¦ï¼‰ã€ã‚ˆã‚Šé•·ã„車両やより多ãã®è»Šä¸¡ã«å¯¾å¿œã—ã€åŽå®¹äººæ•°ã‚„集客エリアを増やã™ã“ã¨ãŒã§ãã¾ã™ã€‚[v] を押ã™ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ュー上ã§è²¨ç‰©ã¨ä¹—客ã®é›†å®¢ã‚¨ãƒªã‚¢ã®è¡¨ç¤º/éžè¡¨ç¤ºã‚’切り替ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚[Ctrl] を押ã—ãªãŒã‚‰å»ºè¨­ã™ã‚‹ã¨ã€ä¸‹ã«ã‚る軌é“ä¸Šã«æ©‹ã«å»ºè¨­ã§ãã¾ã™ã€‚

é§è»Šå ´: (PAK 128 ã®ã¿ï¼‰ã“ã®ãƒ„ールã¯ã€å•†å“や乗客ã®åŽå®¹åŠ›ã‚’é«˜ã‚ã€ãƒ¡ãƒ³ãƒ†ãƒŠãƒ³ã‚¹ã‚³ã‚¹ãƒˆã‚’削減ã™ã‚‹ãŸã‚ã«ã€åœç•™æ‰€ã®æ‹¡å¼µã‚’行ã„ã¾ã™ã€‚
拡張部分を作るã«ã¯ã€ãƒ„ールをクリックã—ã¦ãã®æ‹¡å¼µã‚¢ã‚¤ãƒ†ãƒ ã‚’é¸æŠžã—ï¼ˆã‚«ãƒ¼ã‚½ãƒ«ãŒæ‹¡å¼µéƒ¨åˆ†ã«å¤‰ã‚りã¾ã™ï¼‰ã€ã‚²ãƒ¼ãƒ ãƒ“ãƒ¥ãƒ¼ä¸Šã®æ—¢å­˜ã®åœç•™æ‰€ã®æ¨ªã«ã‚ã‚‹é“路上ã®å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚æ–°ã—ã„æ‹¡å¼µéƒ¨åˆ†ã¯åœç•™æ‰€ã®ä¸€éƒ¨ã¨ã¿ãªã•れã¾ã™ã€‚
{ヒント: 撤去ï¼å–り壊ã—ã§æ‹¡å¼µéƒ¨åˆ†ã‚’削除ã—ã¦ãã ã•ã„。ï½

åœç•™æ‰€: 市電やé“路車両ãŒè·ç‰©ã‚„郵便物ã€ä¹—客をé€è¿Žã™ã‚‹ãŸã‚ã®å ´æ‰€ã‚’作るツールã§ã™ã€‚
åœç•™æ‰€ã¯ã€æ—¢å­˜ã®ã‚¹ãƒˆãƒƒãƒ—ã«éš£æŽ¥ã—ã¦å»ºè¨­ã•れã¦ã„ãªã„å ´åˆã€æ–°ã—ã„ストップãŒä½œæˆã•れã¾ã™ã€‚åœç•™æ‰€ã¯é“路上ã«å»ºè¨­ã•れã€ç¶­æŒè²»ãŒã‹ã‹ã‚Šã€å•†å“や乗客ã€éƒµä¾¿ç‰©ã®å—ã‘çš¿ã«ãªã‚Šã¾ã™ã€‚ã„ãã¤ã‹ã®ãƒ„ールオプションã®éš…ã«ã‚るアイコン(駅一覧ã¨ã‚¹ãƒˆãƒƒãƒ—情報ã§ä½¿ç”¨ã•れã¾ã™ï¼‰ã¯ã€ãã®åœç•™æ‰€ã§æ‰±ãˆã‚‹ã‚¢ã‚¤ãƒ†ãƒ ã‚’示ã—ã¦ã„ã¾ã™ã€‚åœç•™æ‰€ã®ç¨®é¡žã«ã‚ˆã£ã¦ã€å•†å“ã€ä¹—客ã€éƒµä¾¿ç‰©ã®å–り扱ã„容é‡ãŒç•°ãªã‚Šã¾ã™ã€‚
åœç•™æ‰€ã‚’作るã«ã¯ã€ãƒ„ールをクリックã—ã¦é¸æŠžã—(カーソルãŒåœç•™æ‰€ã«å¤‰ã‚りã¾ã™ï¼‰ã€ã‚²ãƒ¼ãƒ ãƒ“ューã®é“路上ã®å¿…è¦ãªä½ç½®ã‚’クリックã—ã¾ã™ã€‚
{ヒント: 撤去ï¼å–り壊ã—ã§åœç•™æ‰€ã‚’削除ã—ã¾ã™ã€‚[Ctrl] を押ã—ãŸã¾ã¾ã«ã™ã‚‹ã¨ã€ä½Žã„é“è·¯ã®ä¸Šã«ã‚ã‚‹æ©‹ã®ä¸Šã«å»ºã¦ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

simutrans-124.3/simutrans/text/ja/window.txt000066400000000000000000000277021474050137200212360ustar00rootroot00000000000000ゲーム・インターフェースã®ä½¿ã„æ–¹

ゲーム・インターフェース

Simutransã¯ã€ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã«é–¢ã™ã‚‹æƒ…å ±ã€ãƒ„ールãƒãƒ¼ã‚„ゲームコントロールã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã€ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ãƒ¯ãƒ¼ãƒ«ãƒ‰ã®ãƒ“ューをæä¾›ã™ã‚‹ã‚²ãƒ¼ãƒ ãƒ»ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェースを通ã—ã¦ãƒ—レイã—ã¾ã™ã€‚Simutransã¯ã€ãƒžã‚¦ã‚¹ã¨ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ã§æ“作ã§ãã¾ã™ã€‚キーボードレイアウトã¯ã€ãƒ˜ãƒ«ãƒ—メニューã®ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ãƒã‚¤ãƒ³ãƒ‡ã‚£ãƒ³ã‚°ã§ç¢ºèªã™ã‚‹ã‹ã€ [F1]キーを押ã—ã¦ç¢ºèªã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã¾ãŸã€æ©Ÿèƒ½ã®ãªã„キーを押ã™ãŸã³ã«è¡¨ç¤ºã•れã¾ã™ã€‚
é‡è¦: キーã¯å¤§æ–‡å­—ã¨å°æ–‡å­—を区別ã—ã¾ã™ã€‚

ゲームウインドウ

ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ãƒ¯ãƒ¼ãƒ«ãƒ‰ã®ä¸€éƒ¨ã‚’表示ã—ã¾ã™ã€‚マウスホイールã€[PGUP]/[PGDN]キーã€ã¾ãŸã¯ãƒ¡ã‚¤ãƒ³ã®ãƒ„ールãƒãƒ¼ã«ã‚ã‚‹2ã¤ã®å°‚用アイコンを使ã£ã¦ã€æ‹¡å¤§ï¼ç¸®å°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚マップã®ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã«ã¯ã„ãã¤ã‹ã®æ–¹æ³•ãŒã‚りã¾ã™ã€‚

· マウスã®å³ãƒœã‚¿ãƒ³ã‚’押ã—ãŸã¾ã¾ã€åœ°å›³ã‚’ä»»æ„ã®æ–¹å‘ã«ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¦ã€ç›®çš„ã®ä½ç½®ã«ç§»å‹•ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚åˆæœŸè¨­å®šã§ã¯ã€ãƒžã‚¦ã‚¹ã®å‹•ãã«åˆã‚ã›ã¦ãƒžãƒƒãƒ—ãŒã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«ã—ã¾ã™ã€‚ã“ã®å‹•作ã¯ã€è¡¨ç¤ºè¨­å®šã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§å¤‰æ›´ã§ãã¾ã™ã€‚
· テンキーを使ã„ã¾ã™ã€‚
· マップウィンドウ上ã®é©åˆ‡ãªãƒã‚¤ãƒ³ãƒˆã‚’é¸æŠžã—ã¦ã€ç›®çš„ã®ãƒžãƒƒãƒ—セクションã¸ç›´æŽ¥ã‚¸ãƒ£ãƒ³ãƒ—(移動)ã—ã¾ã™ã€‚
· Jump to ダイアログ([J]キーを押ã™ï¼‰ã‚’使ã£ã¦ç‰¹å®šã®åº§æ¨™ã¸ç§»å‹•ã—ã¾ã™ã€‚

町ã€å·¥å ´ã€é§…ã€è»Šä¸¡ã€è¼¸é€ãƒ©ã‚¤ãƒ³ãªã©ã€ã„ãã¤ã‹ã®ã‚ªãƒ–ジェクトã®åå‰ã¯ç·¨é›†å¯èƒ½ã§ã™ã€‚編集ã™ã‚‹ã«ã¯ã€è™«çœ¼é¡ï¼ˆèª¿æŸ»ãƒ„ール)ã§é–‹ã„ãŸãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã®å剿¬„をマウスã§ã‚¯ãƒªãƒƒã‚¯ã—ã¾ã™ï¼ˆä¸‹å›³ï¼‰ã€‚編集ã—ãŸå†…容ã¯ã™ãã«æœ‰åйã«ãªã‚Šã¾ã™ã€‚Returnキーを押ã—ã¦ãƒ•ィールドを終了ã—ã¾ã™ã€‚

タイトルãƒãƒ¼

タイトルãƒãƒ¼ï¼ˆãƒšãƒ¼ã‚¸ä¸Šç«¯ã®è¦‹å‡ºã—)ã®å·¦å´ã«ã¯ã€ç¾åœ¨ãƒ—レイ中ã®Simutransã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¨ãƒªãƒªãƒ¼ã‚¹æ—¥ãŒè¡¨ç¤ºã•れã¾ã™ã€‚タイトルãƒãƒ¼ã®å³å´ã«ã¯ã€ã‚²ãƒ¼ãƒ ãƒ»ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェイスを最å°åŒ–ã€æœ€å¤§åŒ–ã—ãŸã‚Šã€Simutransを終了ã—ãŸã‚Šã™ã‚‹ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ãŒã‚りã¾ã™ã€‚

ゲームウィンドウã®ä¸Šéƒ¨ã«ã¯ã€Simutransをプレイã™ã‚‹éš›ã«ã€ã‚²ãƒ¼ãƒ ãƒ„ールãƒãƒ¼ã‚„ゲームコントロールã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®ã‚¢ã‚¤ã‚³ãƒ³ï¼ˆãƒ¡ã‚¤ãƒ³ãƒ„ールãƒãƒ¼ï¼‰ãŒä¸¦ã‚“ã§ã„ã¾ã™ã€‚アイコン(ã“れを利用ã™ã‚‹ã«ã¯ã‚¯ãƒªãƒƒã‚¯ï¼‰ã¯ã€ã„ãã¤ã‹ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã«åˆ†é¡žã•れã¾ã™:

メインメニュー

オプション: フロッピーディスクã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã¨ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãŒè¡¨ç¤ºã•れã€ãã“ã‹ã‚‰ã‚²ãƒ¼ãƒ ã®ãƒ­ãƒ¼ãƒ‰ã€ã‚»ãƒ¼ãƒ–ã€æ–°è¦ã‚²ãƒ¼ãƒ ã®é–‹å§‹ãŒã§ãã¾ã™ã€‚

マップ: オブジェクトをå«ã‚€ä¸–界ã®ã‚ªãƒ¼ãƒãƒ¼ãƒ“ュー・マップã¯ã€ãƒ—レイヤーã®è¼¸é€æ©Ÿé–¢ã®å‹•ãを示ã—ã€ã„ãã¤ã‹ã®çµ±è¨ˆæƒ…報を見るã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®ãƒžãƒƒãƒ—上ã®ä»»æ„ã®ãƒã‚¤ãƒ³ãƒˆã‚’é¸æŠžã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯ãれã«è©²å½“ã™ã‚‹ç”»åƒãŒã‚る地点ã¸ç§»å‹•ã—ã¾ã™ã€‚

調査ツール: 虫眼é¡ã‚¢ã‚¤ã‚³ãƒ³ã¯ã€èª¿æŸ»ãƒ„ールを象徴ã—ã¦ã„ã¾ã™ã€‚ã“れãŒã‚¢ã‚¯ãƒ†ã‚£ãƒ–ãªå ´åˆã€ã‚«ãƒ¼ã‚½ãƒ«ã‚‚虫眼é¡ã«ãªã‚Šã¾ã™ã€‚ã“ã®ã‚¢ã‚¤ã‚³ãƒ³ã§ã‚ªãƒ–ジェクト(建物ã€è»Šä¸¡ãªã©ï¼‰ã‚’é¸æŠžã™ã‚‹ã¨ã€ãã®ä¸Šã«æƒ…報ウィンドウãŒè¡¨ç¤ºã•れã¾ã™ã€‚特ã«å‰Šé™¤ãƒ„ールã§ä½œæ¥­ã—ãŸã°ã‹ã‚Šã®å ´åˆã¯ã€å¸¸ã«è™«çœ¼é¡ã«æˆ»ã‚‹ã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚ãã†ã™ã‚Œã°ã€ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã®æƒ…報を呼ã³å‡ºã™ä»£ã‚りã«ã€èª¤ã£ã¦ã‚ªãƒ–ジェクトを破壊ã—ã¦ã—ã¾ã†ã“ã¨ã‚’é¿ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

スロープツール: スロープツールã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ãƒ„ールãƒãƒ¼ãŒè¡¨ç¤ºã•れã€å„タイルã®å‚¾æ–œã‚’変更ã—ã¦åœ°å½¢ã‚’変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

å„種ã®å»ºè¨­ç”¨ãƒ„ールãƒãƒ¼: 交通機関ã®ç¨®é¡žã”ã¨ã«ç”¨æ„ã•れãŸãƒ„ールãƒãƒ¼ã®ã‚»ãƒƒãƒˆã‚’é–‹ãã¾ã™ã€‚
· 鉄é“ツール
· モノレールï¼ãƒªãƒ‹ã‚¢ãƒ„ール
· 市電ï¼è»½ä¾¿é‰„é“ツール
· é“路ツール
· 船舶ツール
· 飛行機ツール

注æ„:一部ã®ãƒ‘ックセットã«ã¯ã€ãƒŠãƒ­ãƒ¼ã‚²ãƒ¼ã‚¸ãƒ„ールãªã©ã€è¿½åŠ çš„ãªå»ºè¨­ç”¨ãƒ„ールãƒãƒ¼ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆãŒã‚りã¾ã™ã€‚
å„ツールãƒãƒ¼ã«ã¯è»Šä¸¡åŸºåœ°ï¼ˆè»Šåº«ï¼‰ã®ã‚¢ã‚¤ã‚³ãƒ³ãŒã‚りã¾ã™ã€‚車庫を建設ã™ã‚‹ã¨ã€è»Šåº«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã«å…¥ã£ã¦è»Šä¸¡ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚

特別建築物: 黄色ã„丸å°ã®ä¸­å¿ƒã«èµ¤ã„点ãŒã‚るアイコン(pak128ã§ã¯ã‚¯ãƒ¬ãƒ¼ãƒ³ã®ã‚¢ã‚¤ã‚³ãƒ³ï¼‰ã‚’クリックã—ã¦é–‹ãツールãƒãƒ¼ã«ã¯ã€äº¤é€šãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®æ§‹ç¯‰ã‚’補完ã™ã‚‹ã•ã¾ã–ã¾ãªå»ºè¨­ãƒ„ールãŒç”¨æ„ã•れã¦ã„ã¾ã™ã€‚

撤去ï¼å–り壊ã—: 赤ã„Xã®ã‚¢ã‚¤ã‚³ãƒ³ï¼ˆpak128ã§ã¯ãƒ–ルドーザーã®ã‚¢ã‚¤ã‚³ãƒ³ï¼‰ã¯ã€åœ°å›³ä¸Šã®æ§˜ã€…ãªã‚ªãƒ–ジェクトを削除ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã•れã¾ã™ã€‚

管ç†ãƒ¡ãƒ‹ãƒ¥ãƒ¼

路線編集: ã“ã“ã§ã¯è¼¸é€çµŒè·¯ï¼ˆãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¢ã‚¤ã‚³ãƒ³ï¼‰ã‚’作æˆã—ã€å¤‰æ›´ãƒ»å‰Šé™¤ã™ã‚‹ã“ã¨ãŒã§ãã€ã¾ãŸãã®æƒ…報も閲覧ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚

一覧表: 一覧表ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã¨ã€æ¬¡ã®7種類ã®ä¸€è¦§è¡¨ãŒè¡¨ç¤ºã•れるサブメニューã«ã¤ãªãŒã‚Šã¾ã™:
· 駅一覧
· 乗り物一覧
· 町一覧
· 貨物一覧
· 産業一覧
· 忉€æ—§è·¡ä¸€è¦§
· マーカー一覧

メッセージ表: ã“ã®éƒµä¾¿å—ã‘ã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ é–‹å§‹æ™‚ã¾ãŸã¯å‰å›žã®ã‚²ãƒ¼ãƒ èª­ã¿è¾¼ã¿æ™‚以é™ã«ç™ºç”Ÿã—ãŸã™ã¹ã¦ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒä¸€è¦§è¡¨ç¤ºã•れã¾ã™ã€‚

財務: ã“ã®ãŠé‡‘ã®ã‚¢ã‚¤ã‚³ãƒ³ã¯ã€ã‚ãªãŸã®ç¾åœ¨ã®è²¡å‹™çжæ³ã«ã¤ã„ã¦ã€çŸ¥ã‚‹ä¾¡å€¤ã®ã‚ã‚‹ã‚‚ã®ã™ã¹ã¦ã‚’表示ã™ã‚‹ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹ãã¾ã™ã€‚

ãã®ä»–ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼

スクリーンショット: カメラアイコンをクリックã™ã‚‹ã¨ã€ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®ã‚¹ãƒŠãƒƒãƒ—ショット(ツールãƒãƒ¼ã‚’å«ã¿ã€ã‚¿ã‚¤ãƒˆãƒ«ãƒãƒ¼ã¯å«ã¿ã¾ã›ã‚“)㌠.png イメージã¨ã—㦠simutrans/screenshot/ フォルダã«ä¿å­˜ã•れã¾ã™ã€‚ç”»åƒã¯ã€[c] キーã§ã‚‚キャプãƒãƒ£ã§ãã¾ã™ã€‚

ä¸€æ™‚åœæ­¢: 輸é€ä¼šç¤¾ã®å¿™ã—ã„経営ã‹ã‚‰é›¢ã‚Œã¦ä¸€æ¯ã¤ããŸã„ã¨ãã¯ã€ã‚³ãƒ¼ãƒ’ーカップã®ã‚¢ã‚¤ã‚³ãƒ³ã‚’クリックã—ã¦æ¸©ã‹ã„ãŠèŒ¶ã‚„コーヒーを注文ã—ã¦ãã ã•ã„。シムトランã§ã¯ã€ã‚‚ã¡ã‚ã‚“ç„¡æ–™ã§ã‚µãƒ¼ãƒ“スをå—ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼
[p] キーã§ã‚‚ゲームã®ä¸€æ™‚åœæ­¢ï¼ä¸€æ™‚åœæ­¢è§£é™¤ãŒã§ãã¾ã™ã€‚

æ—©é€ã‚Š: ã‚·ãƒ ãƒˆãƒ©ãƒ³ã®æ™‚間経éŽãŒé…ã™ãŽã‚‹å ´åˆã€ã“ã® >> アイコンを押ã™ã“ã¨ã§ã€æ™‚é–“ã‚’æ—©ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚æ—©é€ã‚Šã¯ã€[W] キーã§ã‚‚é¸æŠž/解除ã§ãã¾ã™ã€‚
警告: æ—©é€ã‚Šãƒ¢ãƒ¼ãƒ‰ã§ã¯ã€ã‚²ãƒ¼ãƒ ãŒã‚¹ãƒ ãƒ¼ã‚ºã«é€²è¡Œã—ãªã„å ´åˆãŒã‚りã¾ã™ã€‚表示設定ウィンドウã®ä¸‹éƒ¨ã«ã‚るディスプレイã®ãƒ‘フォーマンス情報セクションã¯ã€ã‚³ãƒ³ãƒ”ュータãŒã“ã®å¤‰åŒ–ã«å¯¾å¿œã§ãã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚

ヘルプ: ?アイコンをクリックã™ã‚‹ã¨ã€ãƒ˜ãƒ«ãƒ—ã®ç´¢å¼•を表示ã—ã¾ã™ã€‚[F1] キーã§ã‚‚表示ã§ãã¾ã™ã€‚

注æ„: プレイã™ã‚‹ãƒ‘ックセットã«ã‚ˆã£ã¦ã¯ã€ãƒ¡ã‚¤ãƒ³ãƒ„ールãƒãƒ¼ã«è¡¨ç¤ºã•れるアイコンãŒå¢—ãˆã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚例ãˆã°æ¬¡ã®ã‚¢ã‚¤ã‚³ãƒ³ã§ã™: ズームイン / ズームアウトã€ã‚°ãƒªãƒƒãƒ‰ã‚’表示ã™ã‚‹ã€90°回転ã™ã‚‹ ãªã©ã€‚

ステータスãƒãƒ¼

ゲームワールドã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä¸‹éƒ¨ã«ã‚るステータスãƒãƒ¼ã«ã¯ã€ã‚²ãƒ¼ãƒ ã®é€²è¡Œã«åˆã‚ã›ã¦å¸¸ã«æ›´æ–°ã•れる情報ãŒã‚りã¾ã™ã€‚ステータスãƒãƒ¼ã«è¡¨ç¤ºã•れる情報ã¯ã€å·¦ã‹ã‚‰å³ã®é †ã«ä»¥ä¸‹ã®é€šã‚Šã§ã™:
· æ—¥ä»˜ã¨æ™‚é–“: シムトランã§ã¯ã€1å¹´ã‚’æœˆã€æ—¥ã€æ™‚é–“ã«åˆ†ã‘ã¦ã„ã¾ã™ã€‚日付ã¯ã€ã€Œå¹´ä»£è¨­å®šã€ï¼ˆä¸‹è¨˜å‚照)を有効ã«ã—ãŸã¨ãã®è»Šä¸¡ã‚„建物ã®åˆ©ç”¨å¯èƒ½æ€§ã‚’制御ã—ã¾ã™ã€‚日付ã®å‰ã«ã¯ã€æ°—象ã®å­£ç¯€ã‚’示ã™ã‚¢ã‚¤ã‚³ãƒ³ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ä¸€éƒ¨ã®æ°—候設定ã§ã¯ã€å­£ç¯€ã«ã‚ˆã£ã¦åœ°é¢ãŒå¤‰åŒ–ã™ã‚‹ã“ã¨ãŒã‚りã¾ã™ã€‚
· プレーヤー: ç¾åœ¨ã®ãƒ—レイヤーã®åå‰ãŒãƒ—レイヤーã®è‰²ã§è¡¨ç¤ºã•れã¾ã™ã€‚
· ç¾é‡‘: ç¾åœ¨ã®ãƒ—レイヤーã®ç¾é‡‘å£åº§æ®‹é«˜ãŒè¡¨ç¤ºã•れã€å¸¸ã«æ›´æ–°ã•れã¾ã™ã€‚建設費やãã®ä»–ã®ã‚³ã‚¹ãƒˆï¼ˆè»Šä¸¡ã®è³¼å…¥è²»ã€è¼¸é€ã‚¤ãƒ³ãƒ•ラã®ç¶­æŒè²»ã€è»Šä¸¡ã®é‹è¡Œã‚³ã‚¹ãƒˆï¼‰ãŒè€ƒæ…®ã•れã¦ã„ã¾ã™ã€‚
· ä½ç½®åº§æ¨™: 括弧内ã«ã¯ã€ã‚«ãƒ¼ã‚½ãƒ«ã® x 座標㨠y 座標ã€ç¾åœ¨ä½ç½®ã™ã‚‹ã‚¿ã‚¤ãƒ«ã®é«˜ã•ãŒè¡¨ç¤ºã•れã¾ã™ã€‚座標(0,0)ã¯ãƒžãƒƒãƒ—ã®å·¦ä¸Šã«ä½ç½®ã—ã€é«˜ã•0ã¯æ°´ä½ã¾ãŸã¯ãれより上ã«ä½ç½®ã—ã¾ã™ï¼ˆãƒžãƒƒãƒ—ä½œæˆæ™‚ã®æ°´ä½è¨­å®šã«ã‚ˆã‚Šã¾ã™ï¼‰ã€‚
· ゲーム速度: 値(T=1.00)ã¯ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã®é€²è¡Œé€Ÿåº¦ã‚’示ã—ã¾ã™ã€‚[,] / [.] ã‚­ãƒ¼ã§æ™‚é–“ã‚’å°‘ã—ãšã¤åŠ é€Ÿï¼æ¸›é€Ÿã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ディスプレイ設定画é¢ã®ä¸‹éƒ¨ã«ã‚るディスプレイパフォーマンス情報ã«ã¯ã€ã‚³ãƒ³ãƒ”ュータãŒãã®å¤‰åŒ–ã«å¯¾å¿œã§ãã‚‹ã‹ã©ã†ã‹ãŒè¡¨ç¤ºã•れã¾ã™ã€‚æ—©é€ã‚Šãƒ¢ãƒ¼ãƒ‰ã§ã¯ã€è¿½åŠ ã®ã‚¢ã‚¤ã‚³ãƒ³ >> ãŒè¡¨ç¤ºã•れã¾ã™ã€‚
· 時代ã«å¾“ã†: ç¾åœ¨ã®ã‚²ãƒ¼ãƒ ã§ã€å¹´ä»£è¨­å®šãŒé¸æŠžã•れã¦ã„ã‚‹ã‹ã©ã†ã‹ã‚’カレンダーアイコンã§è¡¨ç¤ºã—ã¾ã™ã€‚

スクロールãƒãƒ¼

ゲームワールドã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä¸‹éƒ¨ã«ã‚るステータスãƒãƒ¼ã«ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•れるã“ã¨ãŒã‚りã¾ã™ã€‚表示ã•れるメッセージã¯ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚»ãƒ³ã‚¿ãƒ¼ã‚ªãƒ—ションã§å®šç¾©ã§ãã¾ã™ã€‚
ヒント: メッセージをクリックã™ã‚‹ã¨ã€ã‚²ãƒ¼ãƒ ãƒ“ューãŒé–¢é€£ã™ã‚‹ä½ç½®ã«ã‚»ãƒ³ã‚¿ãƒªãƒ³ã‚°ï¼ˆä¸­å¤®å¯„ã›ï¼‰ã•れã¾ã™ã€‚

simutrans-124.3/simutrans/text/ko.tab000066400000000000000000001334261474050137200176760ustar00rootroot00000000000000§Korean PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: ko Korean # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable 불가능 cl_btn_filter_enable 가능 cl_btn_filter_settings 설정 cl_btn_sort_asc 오름차순 cl_btn_sort_desc 내림차순 cl_btn_sort_id 번호(ID) cl_btn_sort_income 수입 cl_btn_sort_name ì´ë¦„ cl_btn_sort_type 종류 clf_btn_alle ëª¨ë‘ ì„ íƒ clf_btn_invers 반전 clf_btn_keine ëª¨ë‘ í•´ì œ gl_btn_sort_bonus 보너스 gl_btn_sort_name ì´ë¦„ gl_btn_sort_revenue 수입 gl_btn_unsort ì •ë ¬ë˜ì§€ì•ŠìŒ hl_btn_filter_disable 불가능 hl_btn_filter_enable 가능 hl_btn_filter_settings 설정 hl_btn_sort_asc 오름차순 hl_btn_sort_desc 내림차순 hl_btn_sort_name ì´ë¦„ hl_btn_sort_type 종류 hl_btn_sort_waiting 대기량 hlf_btn_alle ëª¨ë‘ ì„ íƒ hlf_btn_invers 반전 hlf_btn_keine ëª¨ë‘ í•´ì œ Networks ë„¤íŠ¸ì›Œí¬ Queueing 대기시간 Road toll 통행료 Scenario 시나리오 ì •ë³´ Transfers 환승 #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic ë¶ê·¹ê¶Œ 기후 desert 사막 기후 mediterran 지중해성 기후 rocky ê³ ì‚° 기후 temperate 온대 기후 tropic 열대 기후 tundra íˆ°ë“œë¼ ê¸°í›„ #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed 시나리오를 불러오는ë°ì— 실패했습니다. Can't buy obsolete vehicles! ìƒì‚° ì¤‘ë‹¨ëœ ì°¨ëŸ‰ì„ ì‚´ 수 없습니다! Cannot alter water ë”ì´ìƒ ë¬¼ì„ ì±„ìš°ê±°ë‚˜ 뺄 수 없습니다. Cannot built depot here! ì—¬ê¸°ì— ì°¨ê³ ì§€ë¥¼ 건설할 수 없습니다. Cannot built this station/building\nin underground mode here. ì´ ê±´ë¬¼/ì—­ì€ ì§€í•˜ì— ê±´ì„¤í•  수 없습니다.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. ì¼ë°˜ ë…¸ì„ ì„ ë§Œë“¤ 수 없습니다!\ní•„í„°íƒ­ì„ ì‚¬ìš©í•´ì„œ\n노선 íƒ€ìž…ì„ ì„ íƒí•˜ì„¸ìš”.\n Cannot create socket ì†Œì¼“ì„ ë§Œë“¤ 수 없습니다 Convoi handles exhausted! 최대 차량 ìˆ˜ì— ë„달했습니다.\nì´ ì´ìƒ ì°¨ëŸ‰ì„ ìƒì„±í•  수 없습니다. Convoy already deleted! ì´ë¯¸ ì°¨ëŸ‰ì´ ì œê±°ë˜ì—ˆìŠµë‹ˆë‹¤! Das Feld gehoert\neinem anderen Spieler\n ì´ í† ì§€ëŠ”\n다른 플레ì´ì–´ê°€\n소유하고 있습니다!\n Der Besitzer erlaubt das Entfernen nicht 주ì¸ì´ \n없애는 것ì„\ní—ˆë½í•˜ì§€ 않습니다!\n Diese Zusammenstellung kann nicht fahren!\n ì´ ì¡°í•©ìœ¼ë¡œ\n운행할 수 없습니다!\n Flugzeughalt muss auf\nRunway liegen!\n 비행기는 활주로ì—서만 착륙할 수 있습니다. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n 여기ì—\nê³µí•­ì„ ê±´ì„¤í•  수 없습니다.\n Hier kann kein\nSignal aufge-\nstellt werden!\n ì—¬ê¸°ì— ì—´ì°¨ 신호등ì„\n만들 수 없습니다.\n In order to lock the game, you have to protect the public player by password! ê²Œìž„ì„ ìž ê·¸ê¸°ìœ„í•´ 공공 ì„œë¹„ìŠ¤ì— ë¹„ë°€ë²ˆí˜¸ë¥¼ 거세요! Lost connection\nto server! ì„œë²„ì™€ì˜ ì—°ê²°ì´ ëŠì–´ì¡ŒìŠµë‹ˆë‹¤! Lost synchronisation\nwith server. ì„œë²„ì™€ì˜ ë™ê¸°í™”ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤! Maglevhalt muss auf\nMaglevschiene liegen!\n ìžê¸°ë¶€ìƒì—´ì°¨ëŠ” ìžê¸°ë¶€ìƒì—´ì°¨ ì² ë„ ìœ„ì—서만 운행할 수 있습니다. Monorailhalt muss auf\nMonorail liegen!\n ëª¨ë…¸ë ˆì¼ ì—´ì°¨ëŠ” ëª¨ë…¸ë ˆì¼ ìœ„ì—서만 운행할 수 있습니다.\n Monorails are not available yet! 모노레ì¼ì€ ì•„ì§ ì‚¬ìš©í•  수 없습니다! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n 협궤열차는 í˜‘ê¶¤ì² ë„ ìœ„ì—서만 운행할 수 있습니다. No through station here! ì—­ì€ ì„ ë¡œì˜ ë부분ì´ë‚˜ êµì°¨ì§€ì ì´ 없는\nì§ì„  선로 위ì—서만 건설할 수 있습니다. Not enough money! ëˆì´ 부족합니다. On narrowgauge track only!\n 협궤철ë„ì—서만 ì´ìš©í•  수 있습니다!\n Only public player can lock games! 주ì¸ìž¥ë§Œ ê²Œìž„ì„ ìž ê¸€ 수 있습니다! Out of funds ëˆì´ 부족합니다! Post muss neben\nHaltestelle\nliegen!\n ì—­ 확장 건물(예: ìš°ì²´êµ­, 창고)ì€\n정류장/ì—­ ì˜†ì˜ ë¹ˆ 타ì¼ì— 건설해야 합니다.\n\n Protocoll error (expecting game) 프로토콜 오류 (ëŒ€ê¸°ì¤‘ì¸ ê²Œìž„ì—서) Schiffhalt muss im\nWasser liegen!\n 배는 항구 주변ì—서만 ì •ë°• í•  수 있습니다!\n Server busy 서버가 복잡합니다. Terraforming not possible\nhere in underground view ì§€í˜•ë³€ê²½ì€ ì§€í•˜ì—서 사용할 수 없습니다. This tunnel branches. You can try Control+Click to remove. ì´ í„°ë„ì€ 2ê°œ ì´ìƒì˜ 출구가 있습니다. Crtl+í´ë¦­ìœ¼ë¡œ 철거하세요. Upgrade must have\na higher level ë” ë†’ì€ ë ˆë²¨ì—서 업그레ì´ë“œë¥¼ 해야합니다. Vehicle %s cannot choose because stop too short! 차량 %sê°€ 정차하기ì—는 ìŠ¹ê°•ìž¥ì´ ë„ˆë¬´ 짧습니다. Zughalt muss auf\nSchiene liegen!\n 기차는 ì² ë„ ìœ„ì—서만 운행할 수 있습니다.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s ë„움ë§

ë„ì›€ë§ ëª©ë¡

Simutransì— ëŒ€í•´

%1$s

사용법

%2$s

게임 시작

%4$s

게임하는 법

%5$s

ë„구

%3$s

기타

%6$s Keyboard Help\n

Keyboard Help

\n 단축키 ë„움ë§\n

단축키 ë„움ë§

\n

\n단축키 ë„움ë§ì€ ë‹¨ì¶•í‚¤ì˜ ë‹¤ì–‘í•œ ê¸°ëŠ¥ë“¤ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.\n

\n

\n단축키 ë„움ë§ì€ 할당ë˜ì§€ ì•Šì€ ë‹¨ì¶•í‚¤ë¥¼ 누를때나 ì¼ë°˜ ë„움ë§ì„ ì—´ 때 나타납니다.\n

\n

\n키 ìž…ë ¥ì€ ëŒ€ì†Œë¬¸ìžë¥¼ 구별합니다.\n (ëŒ€ë¬¸ìž ìž…ë ¥ì€ [Shift]를 사용)\n

\n

\ní• ë‹¹ëœ íƒ„ì¶•í‚¤ëŠ” 다ìŒê³¼ 같습니다:\n

\n

\n[화살표키]: 게임 í™”ë©´ì„ í™”ì‚´í‘œ 방향으로 ì´ë™í•©ë‹ˆë‹¤.
\n[Backspace]: ê²Œìž„í™”ë©´ì˜ ëª¨ë“  ì°½, 툴바, ë„움ë§ì„ 닫습니다.
\n[Delete], ë˜ëŠ” [Esc]: ê²Œìž„í™”ë©´ì˜ ë§¨ìœ„ì˜ ì°½, 툴바 ë˜ëŠ” ë„움ë§ì„ 닫습니다.
\n[Enter], or [Return]: í–‰ë™ì„ 확정할때 사용합니다.
\n[Page-Up], ë˜ëŠ” [>]: ê²Œìž„í™”ë©´ì„ í™•ëŒ€í•©ë‹ˆë‹¤.
\n[Page-Down], ë˜ëŠ” [<]: ê²Œìž„í™”ë©´ì„ ì¶•ì†Œí•©ë‹ˆë‹¤.\n[F1]: Simutrans ë„움ë§ì„ 엽니다.

\n

\n[1]: 왼쪽아래(남쪽) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[2]: 아래(ë™ë‚¨ìª½) 방향으로 화면ì´\n ì´ë™í•©ë‹ˆë‹¤.
\n[3]: 오른쪽아래(ë™ìª½) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[4]: 왼쪽(남서쪽) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[6]: 오른쪽(ë¶ë™ìª½) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[7]: 왼쪽위(서쪽) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[8]: 위(ë¶ì„œìª½) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.
\n[9]: 오른쪽위(ë¶ìª½) 방향으로 í™”ë©´ì´ ì´ë™í•©ë‹ˆë‹¤.\n

\n

\n[Shift] + 마우스: ì§€ë„ìƒì—서 사용하면 ì‚°ì—… 공급 ì²´ì¸ì˜ ì—°ê²°ë“¤ì„ ë³¼\n 수 있습니다.
\n[CTRL] + ë„구버튼: ì†ë„ì œí•œì´ ë†’ì€ ë„로나 선로 ìœ„ì— ì†ë„ì œí•œì´ ë‚®ì€ ë„로나 선로를 ë®ì–´ 씌울 때, ë˜ëŠ” 똑바른 ì§ì„  ë„로나 선로를 건설할 때 사용합니다.\n

\n

\n\n Decrease water height ìˆ˜ë©´ì„ í•œ 단계 내리기 Highlight railroad tracks ì² ë„ ì„ ë¡œ ê°•ì¡° Highlite depots 차고지 ê°•ì¡° Highlite electrical transmission lines 송전선 ê°•ì¡° Highlite factories 공장 ê°•ì¡° Highlite forests 숲 ê°•ì¡° Highlite tourist attraction 관광명소 ê°•ì¡° Increase water height ìˆ˜ë©´ì„ í•œ 단계 올리기 Open station/stop details ì—­ 세부정보 보기 Overlay city limits ë„시 경계 ë³´ì´ê¸° Overlay passenger destinations when a town window is open ë„시 ì°½ì´ ì—´ë ¤ìžˆëŠ” 경우 승ê°ì˜ 목ì ì§€ë¥¼ 표시합니다. Overlay schedules/network 스케줄/ë„¤íŠ¸ì›Œí¬ ë³´ê¸° Overlay town names ë„시 ì´ë¦„ 표시 Please click on the map to add\nwaypoints or stops to this\nschedule. ì§€ë„를 í´ë¦­í•˜ì—¬ 웨ì´í¬ì¸íЏ ë˜ëŠ” ì—­ì„ ìŠ¤ì¼€ì¤„ì— ì¶”ê°€í•˜ì„¸ìš”. Set tile climate %s ì´ ë•…ì„ %s 기후로 바꿉니다. Show speedlimit of ways 선로/ë„ë¡œì˜ ì œí•œì†ë„ 표시 Show the owenership of infrastructure 기반시설(선로/ë„로 등)ì˜ ì†Œìœ ìž í‘œì‹œ Show transported freight/freight network ìš´ì†¡ëœ í™”ë¬¼ì˜ ê²½ë¡œ 표시 Shows a listing with all industries on the map. ì§€ë„ì— ì¡´ìž¬í•˜ëŠ” 모든 ì‚°ì—…ì˜ ëª©ë¡ #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s는 ì´ì œ\n %s와 관광지 %s 사ì´ì— 버스 서비스를 제공합니다.\n(%i,%i)부터.\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s는 ì´ì œ\n %s와 공장 %s 사ì´ì— 버스 서비스를 제공합니다.\n(%i,%i)부터.\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s는\n%i íŠ¸ëŸ­ì„ %sê³¼ (%i,%i)부터\n %s\n사ì´ì— (%i,%i)부터\n 개통했습니다.\n\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s는\n %s와 (%i,%i)부터\n%s사ì´ì—\n(%i,%i)부터\n새로운 ì² ë„를 개통했습니다. Airline service by\n%s\nnow between\n%s \nand %s.\n 항공서비스가 %sì— ì˜í•´\n%s와 \n%s사ì´ì— 제공ë©ë‹ˆë‹¤.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n 페리서비스가 %sì— ì˜í•´\n%s와 \n%s사ì´ì— 제공ë©ë‹ˆë‹¤.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s는 \n%s와\n%s 사ì´ì—\n새로운 버스서비스를 개통했습니다.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS ì§€ë„ íŽ¸ì§‘ ë„구 LISTTOOLS ëª©ë¡ MAGLEVTOOLS ìžê¸°ë¶€ìƒì—´ì°¨ ë„구 MONORAILTOOLS ëª¨ë…¸ë ˆì¼ ë„구 NARROWGAUGETOOLS í˜‘ê¶¤ì² ë„ ë„구 RAILTOOLS ì² ë„ ë„구 ROADTOOLS ë„로 ë„구 SHIPTOOLS ì„ ë°• ë„구 SLOPETOOLS 지형/슬로프 ë„구 SPECIALTOOLS 특수 건설 ë„구 TRAMTOOLS 노면전차 ë„구 #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s는 새로운 본사를 건설했습니다. Factory chain extended\nfor %s near\n%s built with\n%i factories. 경제 성장:\n%s ê·¼ì²˜ì˜ %s는 ì²´ì¸ì„ 확장합니다.\n%iì— ìƒˆë¡œìš´ ê³µìž¥ì´ ê±´ì„¤ë©ë‹ˆë‹¤.\n New %s now available:\n%s\n 새로운 %s를 사용할 수 있습니다.:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. ì‚°ì—… 성장:%s를 위한 %s근처ì—\n 새로운 공장 ì²´ì¸ì´\n %i 공장과 함께 건설ë©ë‹ˆë‹¤. New vehicle now available:\n%s\n \n 새로운 차량ì„\n 사용할 수 있습니다:\n\n\n -- %s --\n\n Now %u clients connected. 플레ì´ì–´ %uê°€ ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤. Remove vehicle from map. Use with care! ì°¨ëŸ‰ì„ ì œê±°í•©ë‹ˆë‹¤. 조심하세요! Screenshot\ngespeichert.\n 스í¬ë¦°ìƒ·ì´\n저장ë˜ì—ˆìŠµë‹ˆë‹¤.\n Sends the convoi to the last depot it departed from! 가장 마지막으로 방문한 차고지로 보냅니다. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. 대형 축제와 함께,\n%sì— ìƒˆë¡œìš´\n기ë…ë¬¼ì´ ê±´ì„¤ë˜ì—ˆìŠµë‹ˆë‹¤.\n%i ì‹œë¯¼ë“¤ì´ ê¸°ë»í•˜ê³  있습니다. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter 노선 í•„í„° #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (차고지 ì•ˆì— ìžˆìŒ) \nBauzeit bis 까지 \nBauzeit von \nì—서 나타남 \nCan't open heightfield file.\n \nheightmapì„ ì—´ 수 없습니다.\n \ndirection: \në°©í–¥: \nelektrified \nì „ì² í™” ëœ\n \nHeightfield has wrong image type.\n \nHeightfieldê°€ 잘못ëœ\nì´ë¯¸ì§€ 타입입니다.\n \nis reserved by: \nì—´ì°¨ì— ì˜í•´ ì˜ˆì•½ë¨ \nminimum speed: \n최저ì†ë ¥ï¼š \nnot elektrified \nì „ì² í™” ë˜ì§€ 않ì€\n \nRibi (masked) \në°©í–¥\m (가려ì§): \nRibi (unmasked) \në°©í–¥\n (드러남): \nSet phases: \n남ë¶/ë™ì„œ êµí†µì‹ í˜¸ ê¸¸ì´ ì¡°ì ˆ: \nsingle way \n단선 \nway1 reserved by \nway 1 ì˜ˆì•½ë¨ \nway2 reserved by \nway 2 ì˜ˆì•½ë¨ \nwith sign/signal\n \n표지íŒ/신호등 í¬í•¨\n %d buildings\n %d 건물 %d convois 차량 %d대 %d Einzelfahrzeuge im Depot %d ì°¨ëŸ‰ì€ ì—¬ê¸°ì— ìž…ê³ ë˜ì–´ 있습니다. %i km/h (max. %ikm/h) %i km/h (최고ì†ë ¥ %ikm/h) %i years %i months old. 수령: %i ë…„ %i 개월 %s at (%i,%i) now public stop. %s는 공공 정류장ì´ë˜ì—ˆìŠµë‹ˆë‹¤. %s building %s %s %s %s %s %s city %d %s %s %d %s %s has entered a depot. %sê°€ 차고로 들어왔습니다. %s land %d %s %s %d ì™¸ë¶€ì˜ %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s 주민수가 %iì— ë„달해, 새 ì‹œì²­ì„ ì§€ì—ˆìŠµë‹ˆë‹¤. %s\nis crowded. %s\n는 혼잡합니다.\n\n %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\n최고ì†ë ¥ %3$i km/h\n\n현재ì†ë ¥ %2$i km/h.\n\n %s\nwas liquidated. %s ê°€ 파산했습니다.\n모든 ì‚¬ì—…ì€ ì¤‘ì§€ë˜ì—ˆê³ , ìž¬ì‚°ì€ ë§¤ê°ë˜ì—ˆìŠµë‹ˆë‹¤. %u Client(s)\n %u í´ë¼ì´ì–¸íЏ\n %u Player (%u locked)\n %u 플레ì´ì–´ (%u ìž ê¹€)\n <스케줄 취소> <새 노선 만들기> <개별 스케줄> <노선 ì—†ìŒ> <스케줄 ì—†ìŒ> <노선 만들기> 1 convoi 차량 1대 1 Einzelfahrzeug im Depot ì—¬ê¸°ì— ì°¨ëŸ‰ 1대가 있습니다. 1LIGHT_CHOOSE ë°ê¸°: 1WORLD_CHOOSE 새 게임 설정: 2LIGHT_CHOOSE 색ìƒ: 2WORLD_CHOOSE ì§€ë„ ë²ˆí˜¸: 3LIGHT_CHOOSE 스í¬ë¡¤ ì†ë„: 4LIGHT_CHOOSE ì—­ë°©í–¥ 스í¬ë¡¤ 5LIGHT_CHOOSE ì •ë¥˜ìž¥ì˜ ë³´í–‰ìž 5WORLD_CHOOSE ë„ì‹œì˜ ìˆ˜: 6LIGHT_CHOOSE ë„ì‹œì˜ ë³´í–‰ìž 6WORLD_CHOOSE êµí†µëŸ‰: 8WORLD_CHOOSE ë‚®/ë°¤ 변화 A bridge must start on a way! 다리 ê²½ë¡œì˜ ëë¶€ë¶„ì„ ì†Œìœ í•˜ê³  있지 않거나, 다리 경로가 막혀있습니다. Abfrage 조사ë„구 Abnehmer ì†Œë¹„ìž About ì— ëŒ€í•´ About scenario Copyright Abriss 파괴/제거 Absenken ë•… 낮추기 Abspanntransformator 변전소 Accelerate time ê°€ì†ì‹œê°„ Act. load: %u MW\n 송전량: %u MW\n Active player only 활ë™ì ì¸ 플레ì´ì–´ë§Œ Add forest 숲 추가 Add random citycar ëžœë¤ ìžê°€ìš© 추가 add server 서버 추가 Add Stop 정류장 추가 Add stops for backward travel 여정 ë’¤ì— ì •ë¥˜ìž¥ì„ ì¶”ê°€í•©ë‹ˆë‹¤. air 활주로/유ë„로 aircraft_tab 화물 수송기 airplane 항공기 Airport 공항 AIRTOOLS 비행기 ë„구 All ëª¨ë‘ all convoi tooltips 모든 차량 ë„êµ¬íŒ Allow city growth ë„시성장 허용 Allow player change 플레ì´ì–´ êµì²´ 허용 allowed climates:\n 가능한 기후:\n Alters a schedule. 스케줄ì—서 ì •ë¥˜ìž¥ì„ ì¶”ê°€/제거 Angenommene Waren 근처 ê³µìž¥ì— í•„ìš”í•œ 물품 anhaengen 추가 Anhaenger_tab 트레ì¼ëŸ¬ Anheben ë•… 올리기 Appends stops at the end of the schedule 스케줄 ëì— ì •ë¥˜ìž¥ 추가 Apply Line 노선 ì ìš© April 4ì›” Arbeiter aus: ë…¸ë™ìž 거주지: Arrived ë„ì°© Assets ìžì‚° Aufloesen 해체하다 Aufspanntransformator 변전소 August 8ì›” Autohalt muss auf\nStrasse liegen!\n 버스/ìžë™ì°¨ëŠ” ë„로 위ì—서만 운행할 수 있습니다. Available 사용가능 Bahndepot ì² ë„ ì°¨ëŸ‰ê¸°ì§€ Bankrott:\n\nDu bist bankrott.\n 파산:\n\në‹¹ì‹ ì€ íŒŒì‚°í–ˆìŠµë‹ˆë‹¤!\n battery 배터리 Baum 나무 baum builder 나무 심기 Baustelle 공사 현장 Bauzeit 공사소요시간 Beenden 종료 Beginner mode ì´ˆë³´ìž ëª¨ë“œ Besonderes Gebaeude 관광 명소 BF ì—­ bio ìƒë¬¼í•™ì ì¸ Blockstrecke ist\nbelegt\n \n선로가 ë˜ë‹¤ë¥¸ 기차ì—\nì˜í•´ 막혀있습니다!\n Boden ë•… Bonusspeed: %i km/h 가능한 최고ì†ë ¥: %i km/h Boost (%%) ì¦ì‚°ë¥  (%%) bridge is too high for its type! ì´ íƒ€ìž…ì˜ ë‹¤ë¦¬ë¥¼ 건설하기ì—는 너무 높습니다! Bridge is too long for this type!\n ì´ íƒ€ìž…ì˜ ë‹¤ë¦¬ë¥¼ 건설하기ì—는 너무 ê¹ë‹ˆë‹¤!\n Bruecke 다리 Bruecke muss an\neinfachem\nHang beginnen!\n 다리는 ê³§ì€ ê²½ì‚¬ 위ì—서 건설해야 합니다!\n Brueckenboden 다리 Build air depot 격납고 건설 build choosesignals ìž…ì„  ë°°ë¶„ 신호기 건설 Build city market 가장 가까운 ë„ì‹œì— ìƒˆë¡œìš´ 시장 건설 Build drain 변전소 build HQ 본사 건설 Build land consumer 새 발전소 건설 Build maglev depot ìžê¸°ë¶€ìƒì—´ì°¨ 차량기지 건설 Build monorail depot ëª¨ë…¸ë ˆì¼ ì°¨ëŸ‰ê¸°ì§€ 건설 Build narrowgauge depot í˜‘ê¶¤ì² ë„ ì°¨ëŸ‰ê¸°ì§€ 건설 Build powerline 송전선 건설 Build presignals 2í색 신호기 건설 Build road depot 차고지 건설 Build ship depot 조선소 건설 Build signals 신호등 건설 Build train depot ì² ë„ ì°¨ëŸ‰ê¸°ì§€ 건설 Build tram depot 노면전차 차량기지 건설 Build truck depot 차고지 건설 Building costs estimates ì˜ˆìƒ ê±´ì„¤ 비용 Buildings ë„시 건물 Built artifical slopes ì¸ê³µ 경사면 건설 Built random attraction 관광지를 무작위로 건설 Bus_tab 버스 Can only move from halt to halt or waypoint to waypoint. 정류장부터 정류장 사ì´\në˜ëŠ” 웨ì´í¬ì¸íŠ¸ë¶€í„° 웨ì´í¬ì¸íЏ 사ì´ì—ë§Œ\nì´ë™í•  수 있습니다. Cancel 취소 Cannot connect to offline server! 오프ë¼ì¸ ì„œë²„ì— ì—°ê²°í•  수 없습니다. Capacity: 수송량: Capacity: %.0f MW 송전 용량: %.0f MW\n Capacity: %d%s %s\n 수송량: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) 수송량: %s\nì ìž¬ëŸ‰: %d (%d%%) Cars are not available yet! ìžë™ì°¨ëŠ” ì•„ì§ ì‚¬ìš©í•  수 없습니다. cars.\nstate ìžë™ì°¨\n Cash 잔액 Change player 플레ì´ì–´ êµì²´ Chart 차트 Chat_msg 채팅 Choose direction ë°©í–¥ ì„ íƒ Choose operation executed on clicking stored/new vehicles ìž…ê³ ëœ/새로운 ì°¨ëŸ‰ì„ í´ë¦­í•´ì„œ ìž‘ë™ì—¬ë¶€ë¥¼ ì„ íƒ chooses a random map ëžœë¤ ë§µì„ ì„ íƒí•©ë‹ˆë‹¤. citicens 시민 City attraction 시내 관광명소 City industries 시내 시장 City list ë„시 ëª©ë¡ City size ë„시 í¬ê¸° city_road 시내ë„로 citybuilding builder ë„시 건물 건설 CityLimit ë„시 규모 한계 cl_title 차량 ëª©ë¡ cl_txt_sort 분류: Clear block reservation ì˜ˆì•½ëœ ì„ ë¡œë¥¼ ë³´ìž„/리셋함 clf_chk_aircrafts 항공기 clf_chk_cars 버스/트럭 clf_chk_indepot 차고 ì•ˆì— clf_chk_maglev ìžê¸°ë¶€ìƒì—´ì°¨ clf_chk_monorail ëª¨ë…¸ë ˆì¼ clf_chk_name_filter í•„í„° ì´ë¦„: clf_chk_narrowgauge í˜‘ê¶¤ì² ë„ ì—´ì°¨ clf_chk_noincome 수입 ì—†ìŒ clf_chk_noline 노선 ì—†ìŒ clf_chk_noroute 경로 ì—†ìŒ clf_chk_noschedule 스케줄 ì—†ìŒ clf_chk_ships ì„ ë°• clf_chk_spezial_filter 특수 í•„í„°: clf_chk_stucked 갇힘 clf_chk_trains 기차 clf_chk_trams 노면전차 clf_chk_type_filter í•„í„° 타입: clf_chk_waren í•„í„° ìƒí’ˆ: clf_title ì°¨ëŸ‰ëª©ë¡ í•„í„° Climate Control 기후 설정 closed ë‹«ìŒ. COLOR_CHOOSE\n 색ìƒì„ ì„ íƒí•˜ì„¸ìš”.:\n Company bankrupt 회사 파산 Company_msg ê²½ìŸìž Comparing pak files ... 팩 ë¹„êµ ì¤‘... Congratulation\nScenario was complete in\n%i months %i years. 축하합니다!\nì´ ì‹œë‚˜ë¦¬ì˜¤ê°€ \n%i개월, %ië…„ ë§Œì—\n완료ë˜ì—ˆìŠµë‹ˆë‹¤! Connected stops ì—°ê²°ëœ ì •ë¥˜ìž¥ Connected with server ì„œë²„ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤. Constructed by ì œìž‘ìž Constructed by %s 제작 : %s construction speed 건설 ì†ë„ Construction_Btn 건설비용 Consumed 소비 convoi %d of %d %d번째 차량 %d대중 convoi error tooltips 차량 오류 ë„êµ¬íŒ Convoi has been sent\nto the nearest depot\nof appropriate type.\n ì°¨ëŸ‰ì„ ì ë‹¹í•œ 타입ì˜\n가까운 차고로 보냅니다.\n Convoi is sold when all wagons are empty. ì°¨ëŸ‰ì´ ë¹„ë©´ 팔릴 것입니다. convoi mouseover tooltips 차량 마우스오버 ë„êµ¬íŒ convoi passed last\nmonth %i\n \nì§€ë‚œë‹¬ì— í†µê³¼í•œ\n차량: %i\n Convois 차량 Convois: %d\nProfit: %s 차량: %d\nì´ìµ: %s Convoys 차량 Copy Convoi 차량 복사 Copy the selected convoi and its schedule or line ì„ íƒëœ 차량과 스케줄 ë˜ëŠ” ë…¸ì„ ì„ ë³µì‚¬ cost for removal 제거비용: Cost: %8s (%.2f$/km %.2f$/m)\n 비용: %s (%.2f$/km %.2f$달)\n Cost: %8s (%.2f$/km)\n 비용: %8s (%.2f$/km)\n Costs 비용 Create a new line based on this schedule ì´ ìŠ¤ì¼€ì¤„ë¡œ 새 노선 만들기 curiosity builder 호기심있는 ê±´ì„¤ì—…ìž curlist_title 관광명소 ëª©ë¡ Currently playing: 게임중: Customers live in: ì†Œë¹„ìž ê±°ì£¼ì§€: deactivated in online mode 온ë¼ì¸ì—서는 사용할 수 없습니다. Deccelerate time ê°ì† 시간 December 12ì›” decrease underground view level ì§€í•˜ì‹œì  ë ˆë²¨ 낮추기 Del Stop 제거 Delete Line 노선 ì‚­ì œ Delete the current stop í˜„ìž¬ì˜ ì •ë¥˜ìž¥ ì‚­ì œ Delete the selected line (if without associated convois). ì„ íƒí•œ 노선 ì‚­ì œ (ë…¸ì„ ì— ì°¨ëŸ‰ì´ ì—†ë‹¤ë©´) Delete this file. ì´ íŒŒì¼ì„ 삭제합니다. Delivered 출하량 Demand 수요량 Demand: %.0f MW 수요량: %.0f MW\n Denkmal 기ë…물 Departed 출발 Departure board 출발 시간 Depots 차고지 Der Tunnel ist nicht frei!\n í„°ë„ì´ ë¹„ì–´ìžˆì§€ 않습니다.\n Destination ë„ì°© Details 세부사항 Die Bruecke ist nicht frei!\n 다리가 비어있지 않습니다!\n diesel 디젤 Direkt erreichbare Haltestellen 여기ì—서 바로가는 경로 disable midi 미디 ìŒì•… ìŒì†Œê±° Display settings ë””ìŠ¤í”Œë ˆì´ ì„¤ì • Distance 주행거리 Dock 항구 Dock must be built on single slope! 항구는 반드시 1ê°œì˜ ê²½ì‚¬ë©´ 타ì¼ì— 건설ë˜ì–´ì•¼ 합니다. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen 부채 ìƒí™˜ ê¸°í•œì´ %d개월 남았습니다. Durchsatz 최대 Economy 경제 Eigenbesitz\n 공공 재산\n Ein %s\npasst hier nicht.\n '%s'는 여기ì—서\n ë§žì§€ 않습니다!\n Einstellungen aendern 옵션 바꾸기 electric 전기 Electricity 전기 Electricity producer\n\n 전기 ìƒì‚°ìž\n\n Electrics_tab 전기 Electrify track ì „ê¸°ì² ë„ ì„ ë¡œ enlarge map ì§€ë„ ë„“ížˆê¸° enter a value between %i and %i %i와 %i사ì´ì˜ ê°’ì„ ìž…ë ¥ Enter address 서버 주소 ìž…ë ¥ Enter Password 플레ì´ì–´ ì´ë¦„ê³¼ 비밀번호를 변경 Error 오류 Erzeuge neue Karte.\n 새 ì§€ë„ê°€ ìƒì„±ë  때까지\n기다리세요.\n\n(대형 ì§€ë„는 시간ì´\n오래 걸립니다.)\n\n Es wird bereits\nein Fahrplan\neingegeben\n ì´ ìŠ¤ì¼€ì¤„ì€\n진행중입니다.\nìŠ¤ì¼€ì¤„ì„ ìƒˆë¡œ 짜기 ì „ì—\n먼저 기존 ìŠ¤ì¼€ì¤„ì„ ë내세요!\n Fabrikanschluss ì—°ê²°ëœ ê³µìž¥ Fabrikname 공장 ì´ë¦„ Factories 공장 factory details 공장 ì—°ê²° factorybuilder 공장 ê±´ì„¤ìž Fahrplan 스케줄 Fahrtziel 행선지: Fahrzeuge koennen so nicht entfernt werden ì´ ë°©ë²•ìœ¼ë¡œ 차량ì„\n제거할 수 없습니다!\n Fahrzeuge: 차량: Farbe 플레ì´ì–´ ìƒ‰ìƒ Fast forward 빨리ê°ê¸° February 2ì›” Ferry_tab ì„ ë°• Fertig 완료 Filename 파ì¼ëª…: Filter: í•„í„°: Finances of %s %sì˜ ìž¬ì • Finanzen 재정 find mismatch íŒ©ì„ ë¹„êµí•˜ì„¸ìš” fl_title 공장 ëª©ë¡ Flug_tab ì—¬ê°ê¸° follow me ë”°ë¼ê°€ê¸° Follow the convoi on the map. ì§€ë„ìƒì˜ ì°¨ëŸ‰ì„ ë”°ë¼ê° Forest 숲 Found new city ì‹ ë„시 건설 FPS: FPS: Fracht 화물 Frame time: 프레임 시간: Free Capacity ë¹„ì–´ìžˆìŒ freeplay mode 프리게임 모드 Friction: 현재 마찰 요소: fuel_cell 연료전지 Full load 최소 ì í•˜ëŸ‰: Fundament 기초 Fussgaenger ë³´í–‰ìž Game info 온ë¼ì¸ 게임 ì •ë³´ GAME PAUSED 게임 ì¼ì‹œì •ì§€ Game_msg ì¼ë°˜ Gear: 기어비: Gebaeude 건물 General ì¼ë°˜ Generated ìƒì‚° Generation: %.0f MW 발전량: %.0f MW\n Gewicht 무게 Gewinn 수입: Give the selected vehicle(s) an individual schedule ì„ íƒí•œ ì°¨ëŸ‰ì˜ ìŠ¤ì¼€ì¤„ ë˜ëŠ” ë…¸ì„ ì„ ìˆ˜ì • gl_btn_sort_catg 카테고리 gl_title ìƒí’ˆ ëª©ë¡ go home 차고지로 보내기 Goods ìƒí’ˆ Goods AI ìƒí’ˆ AI Goods list ìƒí’ˆ ëª©ë¡ Gross Profit 현금 í름 Groundobj 오브ì íЏ Grow city ë„시 키우기 Growth ë„시 성장 H ì •ì§€ Hangar 격납고 Happy 행복 Haus kaufen ì§‘ 구매 Helligk. ë””ìŠ¤í”Œë ˆì´ Help ë„ì›€ë§ Help text not found ë„움ë§ì´ ì•„ì§ ìž‘ì„±ë˜ì§€ 않았습니다. hide all building 모든 건물 숨기기 hide city building ë„시 건물 숨기기 hide objects under cursor 커서 ë°‘ì˜ ì˜¤ë¸Œì íЏ 숨기기 hide station names ì—­ ì´ë¦„ 숨기기 hide transparent 반투명하게 숨기기 hide trees 나무 숨기기 Hier warten/lagern: ëŒ€ê¸°ì¤‘ì¸ ìƒí’ˆê³¼ 승ê°: Highlite schedule ìŠ¤ì¼€ì¤„ì˜ ì •ë¥˜ìž¥ ê°•ì¡° hl_title ì—­ ëª©ë¡ hl_txt_filter í•„í„°: hl_txt_sort 분류: hlf_chk_airport 공항 hlf_chk_anleger 항구 hlf_chk_bahnhof ì² ë„ì—­ hlf_chk_bushalt 버스정류장 hlf_chk_frachthof ì ìž¬ êµ¬íš hlf_chk_keine_verb ì—°ê²°ì•ˆë¨ hlf_chk_maglevstop ìžê¸°ë¶€ìƒì—´ì°¨ì—­ hlf_chk_monorailstop 모노레ì¼ì—­ hlf_chk_name_filter í•„í„° ì´ë¦„: hlf_chk_narrowgaugestop 협궤철ë„ì—­ hlf_chk_overflow 수용량 초과 hlf_chk_spezial_filter 특수 í•„í„°: hlf_chk_tramstop 노면전차 정류장 hlf_chk_type_filter í•„í„° 타입: hlf_chk_waren_abgabe ìƒí’ˆ 출고: hlf_chk_waren_annahme ìƒí’ˆ ìž…ê³ : hlf_title ì—­ ëª©ë¡ í•„í„° Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. 차고지를 ì°¾ì„ ìˆ˜ 없습니다.\n수ë™ìœ¼ë¡œ 차량ì„\n차고지로 보내세요. Homeless ë…¸ìˆ™ìž hydrogene 수소 Idle: ì¼ì´ì—†ëŠ”: ignore climates 기후를 무시 In the industry legend show only currently existing factories 현존하는 ê³µìž¥ì— ëŒ€í•œ 범례만 ë³´ì—¬ì¤ë‹ˆë‹¤. In Transit 운송 ì¤‘ì¸ Increase Industry density ì‚°ì—… ë°€ë„ ì¦ê°€ increase underground view level ì§€í•˜ì‹œì  ë ˆë²¨ ì¦ê°€ industrial building 공장 건물 Init map ... ì§€ë„ ì´ˆê¸°í™”ì¤‘... Input 공급 Ins Stop 삽입 Insert stop before the current stop í˜„ìž¬ì˜ ì •ë¥˜ìž¥ ì „ë‹¨ê³„ì— ì •ë¥˜ìž¥ì„ ì‚½ìž… Intercity road len: ë„시간 ë„로 길ì´: Intro. date: ë„ìž… ë‚ ì§œ: invalid ì •ì˜ë˜ì§€ 않ìŒ. Invalid coordinate ìž˜ëª»ëœ ëª…ë ¹ isometric map 게임화면 ì‹œì  January 1ì›” join game 온ë¼ì¸ì—서 í”Œë ˆì´ July 7ì›” Jump to 건너뛰기 June 6ì›” Kann Spielstand\nnicht laden.\n ê²Œìž„ì„ ë¶ˆëŸ¬ì˜¬ 수 없습니다! Kann Spielstand\nnicht speichern.\n ê²Œìž„ì„ ì €ìž¥ì„ í•  수 없습니다! Kein Besitzer\n ì£¼ì¸ ì—†ìŒ\n keine ì—†ìŒ Keine Einzelfahrzeuge im Depot ì°¨ëŸ‰ì´ ì—†ìŠµë‹ˆë‹¤. Keyboard_Help\n 단축키 ë„움ë§\n koord 좌표 Kreuzung êµì°¨ labellist_title í‘œì‹œíŒ ëª©ë¡ Lade Relief Height Map 불러오기 Laden 새 게임 불러오기 Land attraction 지역 관광명소 Land industries ì‚°ì—… ì²´ì¸: LANG_CHOOSE\n ì›í•˜ëŠ” 언어를 ì„ íƒí•´ì£¼ì„¸ìš”:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month 지난달: Last used tools 마지막으로 사용한 ë„구 Last Year 지난 í•´: Leaving depot! 차고지를 떠남! leer 비어있는 Legend ì§€ë„ ë²”ë¡€ Leistung 힘 Leistung: %d kW ì „ë ¥: %d kW Leitung 송전선 letzen Monat: diesen Monat: 지난달: ì´ë²ˆë‹¬: Line 노선 Line Management 노선 관리 Lineless convoys serving this stop ë…¸ì„ ì´ í• ë‹¹ë˜ì§€ ì•Šì€ ì°¨ëŸ‰ Lines serving this stop ì´ ì •ë¥˜ìž¥ì—서 운행하는 노선 LKW_tab 트럭 Load game 게임 불러오기 load height data from file 파ì¼ë¡œë¶€í„° height ë°ì´í„° 불러오기 Load scenario 시나리오 불러오기 loaded ì ìž¬ëœ loaded passenger/freight 승ê°/화물 분류 Loading (%i->%i%%)! ì ìž¬ì¤‘ (%i->%i%%) Loading addon paks ... 추가 íŒ©ì„ ë¶ˆëŸ¬ì˜¤ëŠ” 중... Loading map ... ì§€ë„를 불러오는중.... Loading paks ... íŒ©ì„ ë¶ˆëŸ¬ì˜¤ëŠ” 중... Loading skins ... ìŠ¤í‚¨ì„ ë¶ˆëŸ¬ì˜¤ëŠ” 중... Lock game 플레ì´ì–´ êµì²´ë¥¼ í•  수 없습니다. (ì¸ì¦ í•„ìš”) Lokomotive_tab 기관차 m3 m³ Maglev ìžê¸°ë¶€ìƒì—´ì°¨ maglev vehicle ìžê¸°ë¶€ìƒì—´ì°¨ 차량 maglev_track ìžê¸°ë¶€ìƒì—´ì°¨ 선로 Maglevdepot ìžê¸°ë¶€ìƒì—´ì°¨ 차량기지 Mail Demand %d\n 편지 수요 %d\n Mailbox 메시지 센터 Mailbox Options 메시지 센터 옵션 Maintenance 유지 관리 make stop public (or join with public stop next) costs %i per tile and level 공용 정류장(ë˜ëŠ” ì´ì›ƒí•˜ëŠ” 공용정류장과 통합)ì„ ë§Œë“œëŠ”ë° íƒ€ì¼ê³¼ 높ì´ë‹¹ %i$ì˜ ë¹„ìš©ì´ ë“­ë‹ˆë‹¤. Manual (Human) ìˆ˜ë™ (사람) Manufactured: 제조: Map roughness ì§€ë„ì˜ ê±°ì¹ ìŒ: map zoom ì§€ë„ ì¤Œ March 3ì›” Margin (%%) ì´ì´ìµ Marker í‘œì§€íŒ ë§Œë“¤ê¸° max 최대 Max Boost (%%) 최대촉진률 (%%) Max income: 최대수입: Max. speed: 최고ì†ë ¥: Maximum 254 stops\nin a schedule!\n 스케줄ì—는 최대 254ê°œì˜ ì •ë¥˜ìž¥ì„\n할당할 수 있습니다.\n maximum length of rivers ê°•ì˜ ìµœëŒ€ ê¸¸ì´ Maximum tile height difference reached. ë‘ íƒ€ì¼ ì‚¬ì´ì˜ 높ì´ì°¨ê°€\nìµœëŒ€ì¹˜ì— ë„달했습니다.\n Maxspeed 최대ì†ë ¥ May 5ì›” Median Citizen per town ë„시당 ì¸êµ¬ í‰ê·  Meldung 메시지 Menge 수량 MessageOptionsText \n새해\n\nAI\n\në„시\n\n새 행선지\n\n채팅\n\n신규차량\n\nì—­ í¬í™”\n\n문제\n\nêµí†µì •ì²´\n\n시나리오 min 최소 minimum length of rivers ê°•ì˜ ìµœì†Œ ê¸¸ì´ Missing pakfiles 오브ì íŠ¸ê°€ 없습니다! Modify the selected line ì„ íƒí•œ 노선 수정 Monate alt 개월 ì „ Monorail ëª¨ë…¸ë ˆì¼ monorail vehicle ëª¨ë…¸ë ˆì¼ ì°¨ëŸ‰ monorail_track ëª¨ë…¸ë ˆì¼ ì„ ë¡œ Monorailboden 올ë¼ê°€ëŠ” 길 Monoraildepot ëª¨ë…¸ë ˆì¼ ì°¨ëŸ‰ê¸°ì§€ month wait time 개월 대기시간 Months 개월 Monument 기ë…물 Monuments 기ë…물 Mountain height ì‚°ì˜ ë†’ì´: Movingobj 오브ì íЏ ì´ë™ Music playing disabled/not available ìŒì•… 사용 불가능. Music volume: ìŒì•… 볼륨: mute sound ìŒì†Œê±° Name ì´ë¦„ Narrowgauge í˜‘ê¶¤ì² ë„ Narrowgauge are not available yet! 협궤철ë„는 ì•„ì§ ì‚¬ìš©í•  수 없습니다! narrowgauge vehicle í˜‘ê¶¤ì² ë„ ì°¨ëŸ‰ narrowgauge_track í˜‘ê¶¤ì² ë„ ì„ ë¡œ Narrowgaugedepot í˜‘ê¶¤ì² ë„ ì°¨ëŸ‰ê¸°ì§€ Net ID: %p ì „ë ¥ë§ ID: %p\n Net Wealth ì „ ìžì‚° Neue Karte 새 ì§€ë„ Neue Welt 새 게임 만들기 new convoi 새 차량 New Line 새로운 노선 New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. 새로운 ë…¸ì„ ì´ ë§Œë“¤ì–´ì¡ŒìŠµë‹ˆë‹¤!\nìœ„ì˜ ë…¸ì„ ì„ ì„ íƒí•˜ë©´\në…¸ì„ ì„ í• ë‹¹í•  수 있습니다.\n\n New Vehicles 새로운 차량 Nickname: ì´ë¦„: no buildings hidden 모든 건물 표시 no convois 차량 ì—†ìŒ No goods are loaded onto this convoi. ì´ ì°¨ëŸ‰ì€ ì ìž¬í•˜ê³  있는 ìƒí’ˆì´ 없습니다. no goods waiting ëŒ€ê¸°ì¤‘ì¸ ìƒí’ˆ ì—†ìŒ no load ì ìž¬ëŸ‰ ì—†ìŒ No Route 경로 ì—†ìŒ No stop here! ì´ ë„구는 정거장 타ì¼ì—ë§Œ 사용ë˜ì–´ì•¼ 합니다. No suitable ground! ì í•©í•œ ì§€í˜•ì˜ ë•…ì´ ì—†ìŠµë‹ˆë‹¤. No terminal station here! ì—¬ê¸°ì— í„°ë¯¸ë„ì„ \nì§€ì„ ìˆ˜ 없습니다! í‰ì§€ì— 위치한 \në„로/선로 ëë¶€ë¶„ì— ì§€ì–´ì•¼ 합니다. no timeline 모든 시대 no tree 나무 ì—†ìŒ No. of Factories 공장과 ìƒì  수 Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n ì°¨ëŸ‰ì„ ì¶œë°œì‹œí‚¤ ì „ì— ìŠ¤ì¼€ì¤„ì„ ì„¤ì •í•´ì£¼ì„¸ìš”!\n none ì•„ë¬´ê²ƒë„ ì—†ìŒ nord ë¶ìª½ nordost ë¶ë™ìª½ nordwest ë¶ì„œìª½ Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! 경로를 íƒìƒ‰í•˜ëŠ” ë™ì•ˆ\nì°¨ëŸ‰ì˜ ìŠ¤ì¼€ì¤„ì„\n바꿀 수 없습니다. Not enough fields would remain. ì´ ë†ìž¥ 주변ì—는\n충분한 í‰ì§€ê°€ 없습니다. November 11ì›” Now active as %s.\n %sê°€ 활성화ë¨.\n Number of rivers ê°•ì˜ ê°œìˆ˜ Object 오브ì íЏ Odometer: %s km 주행기ë¡: %s km Ok í™•ì¸ Oktober 10ì›” On loan since %i month(s) %i달 ë™ì•ˆ 대출 On this map, you are not\nallowed to change player!\n ì´ ê²Œìž„ì—서는 플레ì´ì–´ë¥¼ êµì²´í•  수 없습니다.\n\n Only city chains ë„ì‹œì— ì²´ì¸ ë§Œë“¤ê¸° Only land chains ì§€ìƒ ì‚°ì—… ì²´ì¸ ë§Œë“¤ê¸° Only one transformer per factory! 한 공장ì—는 í•˜ë‚˜ì˜ ë³€ì „ì†Œë§Œ 건설할 수 있습니다! Only show goods which are currently handled by factories 현존하는 ì‚°ì—…ì´ ì·¨ê¸‰í•˜ëŠ” 화물만 표시합니다. open 열기. Operation ìš´ìš© 비용. Ops Profit ìš´ì˜ ì´ìµ Optionen 설정 Or enter a server manually: ë˜ëŠ” 참여할 서버 ì§ì ‘ ìž…ë ¥: Origin 출처 ost ë™ìª½ Output ìƒì‚° Ownership ì†Œìœ ìž Pak which may cause severe errors: ë‹¤ìŒ ì˜¤ë¸Œì íЏ (팩)ì´ ì—†ê¸° 때문ì—, 운송 ì²´ì¸ì— 문제가 ë°œìƒí•  수 있습니다: Pak which may cause visual errors: ë‹¤ìŒ ì˜¤ë¸Œì íЏ (팩)ì€ ë¹„ìŠ·í•œ 오브ì íŠ¸ë¡œ 대체ë˜ì—ˆìŠµë‹ˆë‹¤: Pak(s) different: 다른 오브ì íЏ: Pak(s) missing on client: ë‹¤ìŒ ì˜¤ë¸Œì íЏ (팩)ì´ ì—†ìŠµë‹ˆë‹¤: Pak(s) not on server: ì„œë²„ì— ì—†ëŠ” 오브ì íЏ (팩): Pakset differences 팩 ì°¨ì´ paletten í‹€ Pas_tab ì—¬ê°ì—´ì°¨ Passagiere ìŠ¹ê° Passagierrate ìŠ¹ê° ë“±ê¸‰ Passagierziele 승ê°/편지 목ì ì§€ Passenger AI ìŠ¹ê° AI Passenger Demand %d\n ìŠ¹ê° ìˆ˜ìš” %d\n Passengers %d %c, %d %c, %d no route ìŠ¹ê° %d %c, %d %c, %d ê²½ë¡œì—†ìŒ Passengers %d %s, %d %s, %d no route ìŠ¹ê° %d %s, %d %s, %d ê²½ë¡œì—†ìŒ Password 비밀번호 Pause ì¼ì‹œì •ì§€ Pax <%i> Mail <%i> ì—¬ê° <%i> 편지 <%i> PaxDest 목ì ì§€ Percent Electricity 전기 ìƒì‚°ëŸ‰ (%%): Planes are not available yet! 비행기는 ì•„ì§ ì‚¬ìš©í•  수 없습니다! Plant tree 나무 심기 player 플레ì´ì–´ player -1 ì¸ê°„ 플레ì´ì–´ player 0 공공 서비스 player 1 Napik 128 AS player 10 플레ì´ì–´ 10 player 11 플레ì´ì–´ 11 player 12 플레ì´ì–´ 12 player 13 플레ì´ì–´ 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Freight Forwarder VM player 5 H-Trans Ltd player 6 PSK & Co KG player 7 플레ì´ì–´ 7 player 8 플레ì´ì–´ 8 player 9 플레ì´ì–´ 9 Please choose vehicles first\n 먼저 ì°¨ëŸ‰ì„ ì„ íƒí•˜ì„¸ìš”!\n Post 편지 Postrate 편지 등급 Power 힘 Power (MW) ì „ë ¥ (MW) Power: 힘: Power: %4d kW\n ì „ë ¥: %4d kW\n Powerlines 송전선 Problems_msg 문제 Produced ìƒì‚° Production of %s has been stopped:\n%s\n %sì˜ ìƒì‚°ì´ 중지ë˜ì—ˆìŠµë‹ˆë‹¤:\n%s\n Production/Boost ìƒì‚°/ì¦ì‚° Produktion ìƒì‚° Profit ì´ìµ promote to line 노선 ìƒì„± q1 ë´„ q2 여름 q3 ê°€ì„ q4 겨울 Query server 쿼리 서버 rail car ì² ë„ ì°¨ëŸ‰ random 무작위 Random age 무작위 ì—°ë„ Random map 무작위 ì§€ë„ Rathaus 시청 Rating 비율 ratio_pax ìŠ¹ê° ë¹„ìœ¨ Reliefkarte ì§€ë„ Remove 제거 remove airstrips 활주로/유ë„로 ì² ê±° remove channels 수로 ì² ê±° remove interm. signals 중간 신호기 제거 remove maglev tracks ìžê¸°ë¶€ìƒì—´ì°¨ 선로 ì² ê±° remove monorails ëª¨ë…¸ë ˆì¼ ì„ ë¡œ ì² ê±° remove narrowgauge tracks 협궤선로 ì² ê±° remove powerlines 송전선 ì² ê±° remove roads ë„로 ì² ê±° remove tracks 선로 ì² ê±° Remove wayobj %s ë„로 오브ì íЏ %s를 제거 replace other signals 다른 신호기로 êµì²´ replace stop 정류장 êµì²´ request closing 리퀘스트 종료 residential house ì£¼íƒ Restore natural slope ìžì—° 경사면 복구 Restwert: 재íŒë§¤ 가격: Retire. date: 퇴역 ë‚ ì§œ: return ticket 왕복운행 노선 Revenue 수입 Revision: 수정: road ë„로 road vehicle ìžë™ì°¨ Roadsign ë„로 í‘œì§€íŒ Rotate map ì§€ë„ íšŒì „ Rotation 회전 Routing 여정 sack 가방 sail 바람 Saving map ... ì§€ë„를 저장 중... Scenario complete: %i%% 시나리오 완료: %i%% Scenario Debug 디버그 Scenario Error Log 스í¬ë¦½íЏ 오류 Scenario Goal 목표 Scenario Info 설명 Scenario information 시나리오 세부정보 Scenario Result 성과 Scenario Rules 규칙 Schedule changing! 스케줄 êµì²´! Schienentunnel ì² ë„í„°ë„ ê±´ì„¤ Schiff_tab ì„ ë°• Schiffdepot 조선소 Schleppkahn_tab 바지선 Screenshot 스í¬ë¦°ìƒ· Seasons 계절 Sehenswuerdigkeit 관광명소 Select a server to join: 참여할 서버 고르기: Select a theme for display ë””ìŠ¤í”Œë ˆì´ í…Œë§ˆ ì„ íƒí•˜ê¸° Sell the selected vehicle(s) ì„ íƒí•œ ì°¨ëŸ‰ì„ íŒë‹ˆë‹¤. sended 보낸 편지 SEP_FRACTION . SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September 9ì›” Server did not respond! 서버가 ì‘답하지 않습니다. Serves Line: 노선 ìš´ì˜: Service 서비스 set signal spacing 신호간격 설정 Setting 설정 Ship ì„ ë°• shops and stores ìƒì ê³¼ 사무실 Show all ëª¨ë‘ ë³´ê¸° show all building 모든 빌딩 보기 Show also vehicles no longer in production. ë” ì´ìƒ ìƒì‚°ë˜ì§€ 않는 ì°¨ëŸ‰ë„ ë³´ê¸° Show also vehicles that do not match for current action. ì„ íƒí•œ í–‰ë™ì— 사용할 수 없는 ì°¨ëŸ‰ë„ ë³´ê¸° Show even servers with wrong version or pakset 종류를 알 수 없는 버전ì´ë‚˜ 팩 ì„œë²„ë„ í‘œì‹œ show grid ê²©ìž ë³´ê¸° Show industry ì‚°ì—… ëª©ë¡ Show legend 범례 보기 Show map scale ìƒ‰ìƒ ì½”ë“œ Show obsolete íê¸°ëœ ê²ƒë„ í‘œì‹œ Show offline 오프ë¼ì¸ 서버 보기 Show schedules 스케줄 보기 Show servers that are offline 오프ë¼ì¸ 서버 보기 Show servers where game version or pakset does not match your client 게임 버전ì´ë‚˜ íŒ©ì´ í˜¸í™˜ë˜ì§€ 않는 서버 보기 show station coverage ì—­ 범위 보기 show station names ì—­ ì´ë¦„ 보기 show waiting bars 대기 막대그래프 보기 show/hide block reservations 경로 예약 보기/숨기기 Show/hide estimated arrival times 추정 ë„ì°© 시간 보기/숨기기 show/hide object owner 오브ì íЏ ì£¼ì¸ ë³´ê¸°/숨기기 Show/hide statistics 통계 보기/숨기 Shows buttons on special topics. 특정한 ì£¼ì œë“¤ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. Shows consumer/suppliers for factories ê³µìž¥ì˜ ê³µê¸‰ìž/ì†Œë¹„ìž ë³´ê¸° Shows the currently selected schedule 현재 ì„ íƒëœ 스케줄 보기 Shrink city ë„시 축소 shuffle midis 셔플 ìž¬ìƒ Signal 신호기 signal spacing 신호 간격 Sim: 심루프: Similar view as the main window 주 게임창처럼 ë³´ì´ê²Œ 합니다. Size (%d MB): 파ì¼í¬ê¸° (%d MB): sliced underground mode 층 ì‹œì  slot empty 빈 슬롯 Smart hide objects 커서 주변 숨기기 Sort by 승ê°/화물 분류 Sort waiting list by ëŒ€ê¸°ëª©ë¡ ë¶„ë¥˜ Sound 소리 Sound settings 소리 설정 Sound volume: 소리 볼륨: special freight 특별화물 Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. ì†ë„ 보너스: ë„로 %i km/h, ì² ë„ %i km/h\nì„ ë°• %i km/h, 항공기 %i km/h. Speedlimit 제한ì†ë„ Speichern 저장 Spieler 플레ì´ì–´ Spieler(mz) 플레ì´ì–´ Spielerliste 플레ì´ì–´ ëª©ë¡ Spielstand wurde\ngeladen!\n \n게임 불러왔습니다.\n Spielstand wurde\ngespeichert!\n \n게임 저장했습니다.\n Sprache 언어 Sprachen 언어 Stadtinformation ë„시 통계 Start 시작 Start the selected vehicle(s) ì„ íƒí•œ ì°¨ëŸ‰ì„ ë‚´ë³´ëƒ…ë‹ˆë‹¤. Starte Spiel 게임 시작 Station tiles: ì—­ 타ì¼: Station_msg ì—­ Status ì •ì§€ ìƒíƒœ steam ì¦ê¸° Step timeline one year ì—°ë„별 타임ë¼ì¸ Stops 정류장 Storage 재고량 Storage capacity 창고 용량 Strassendepot 차고지 Strassentunnel ë„ë¡œí„°ë„ ê±´ì„¤ street car 노면전차 sued 남쪽 suedost 남ë™ìª½ suedwest 남서쪽 Summer snowline 여름 만년설 ë†’ì´ Supplied: %.0f %% 공급량: %.0f %% Suppliers 공급ìž: Tage alt ì¼ ì „. There are still vehicles\nstored in this depot!\n ì°¨ëŸ‰ì´ ì°¨ê³ ì§€ì—서\n대기중입니다!\n This Month ì´ë²ˆ 달 This Year ì´ë²ˆ í•´: Tile not empty. 타ì¼ì„ 비운 ë’¤ 경사면 ë„구를 사용하세요. timeline ì‹œëŒ€ì— ë”°ë¦„ tl_title 모든 ë„시 ëª©ë¡ To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %1$sì—ì„œì˜ êµí†µëŸ‰ ì¦ê°€: %3$i ì£¼ë¯¼ë“¤ì´ %2$s 건설 To heavy traffic\nresults in traffic jam.\n ë§Žì€ êµí†µëŸ‰ì´\n êµí†µí˜¼ìž¡ì„ 유발합니다.\n Toggle day/night view ë‚®/ë°¤ ì‹œì  í† ê¸€ Toggle vehicle tooltips 차량 ë„êµ¬íŒ í† ê¸€ tonnen 톤 Total inhabitants: ì´ ì£¼ë¯¼ìˆ˜: Tourist attractions 관광명소: Tourists 관광지 Town_msg 새 행선지 Town: %s\n %s 시.\n Towns ë„시 track 선로 Tracks 선로 Traffic êµí†µëŸ‰ Train 기차 Trains are not available yet! 기차는 ì•„ì§ ì‚¬ìš©í•  수 없습니다. Tram 노면전차 tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. 노면전차 %i km/h, ëª¨ë…¸ë ˆì¼ %i km/h\nìžê¸°ë¶€ìƒì—´ì°¨ %i km/h, 협궤열차 %i km/h. tram_track 노면전차 선로 Tramdepot 노면전차 차량기지 Trams are not available yet! 노면전차는 ì•„ì§ ì‚¬ìš©í•  수 없습니다. Transferring game ... 게임 전송중... Transformer only next to factory! 변전소는 공장 ì˜†ì˜ ë¹ˆ í‰ì§€ì— 건설해주세요! Translation 번역 transparent station coverage ì—­ 범위 반투명으로 보기 Transported ìˆ˜ì†¡ì‹¤ì  TrolleyBus_tab 트롤리 버스 Truck 트럭 tt_Other 기타 Tunnel muss an\neinfachem\nHang beginnen!\n í„°ë„ì€ ê³§ì€ ê²½ì‚¬ë©´ì—서\n 시작해야 합니다!\n Tunnel must start on single way! í„°ë„ì€ ì§ì„  ë„로ì—서 시작해야 합니다. Tunnelboden í„°ë„ underground mode 지하 ì‹œì  UNDO failed! ë˜ëŒë¦¬ê¸°ë¥¼ ë”ì´ìƒ 사용할 수 없습니다.\n신호등/ì—­/정류장 ë“±ì˜ \n선로 ìœ„ì— ì„¸ì›Œì§„ \nêµ¬ì¡°ë¬¼ì´ ì—†ì„ ë•Œì—ë§Œ\në˜ëŒë¦¬ê¸°ë¥¼ 사용할 수 있습니다. Undo last ways construction 마지막으로 건설한 ë„로를 ë˜ëŒë¦¬ê¸° Unemployed 실업 Unhappy 불행 units/day 단위/개월 Update Line 노선 수정 upgrade HQ 본사 업그레ì´ë“œ Usage: %.0f %% 사용량: %.0f %% Usage/Output 사용량/발전량 Use beginner mode ì´ˆë³´ìž Use timeline start year 타임ë¼ì¸ ì‹œìž‘ë…„ë„ ì‚¬ìš©: Vehicle %s can't find a route! 차량 %sì´\n경로를 ì°¾ì„ ìˆ˜ ì—†ìŒ! Vehicle %s is stucked! 차량 %sì´ ê°‡íž˜! Vehicle details 차량 ìƒì„¸ Verbrauch 소비 Vergroessere die Karte\n ì§€ë„ í‚¤ìš°ê¸°.\n Verkauf 지금 제거! verkaufen íŒë§¤ Verkehrsteilnehmer ìžê°€ìš© Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n 부채 ìƒí™˜ 기한ì´\n %d개월 남았습니다.\n via 경유(세부사항) via %s\n %s를 경유\n via Menge 경유 (수량) voranstellen ë§¨ì•žì— ë„£ê¸° Waggon_tab ìžë™ì°¨ waiting 대기수량 Waiting for clearance! 정리를 위한 대기! Walked ë„ë³´ walking ë„ë³´ Warnings_msg êµí†µëŸ‰ Wasser 물 Water 운하 Water level 수면 높ì´: water vehicle ì„ ë°• way %s cannot longer used:\n %s 길 íƒ€ìž…ì€ ë” ì´ìƒ 사용할 수 없습니다.\n way %s cannot longer used:\n%s\n %s 길 íƒ€ìž…ì€ ë” ì´ìƒ 사용할 수 없습니다:\n%s\n\n way %s now available:\n %s 길 íƒ€ìž…ì„ ì‚¬ìš©í•  수 있습니다.\n Way toll 통행료 Ways not connected ê¸¸ì´ ì—°ê²°ë˜ì§€ 않았습니다. Wegpunkt 웨ì´í¬ì¸íЏ Weight: 무게: Wert 가격 west 서쪽 Winter snowline 겨울 만년설 ë†’ì´ withdraw 퇴역 Withdraw All ëª¨ë‘ í‡´ì—­ WRONGSAVE \n호환ë˜ì§€ 않는 세ì´ë¸Œìž…니다.\n불러올 수 없습니다.\n Year %i has started. %ië…„ì— ì‹œìž‘. Years ë…„ Your primary color: 주 색깔: Your secondary color: ë¶€ 색깔: Zielort 행선지 zooming in 화면 확대 zooming out 화면 축소 Zu nah am Kartenrand ì§€ë„ì˜ ê°€ìž¥ìžë¦¬ì™€\n가까운 지역ì—\n건설할 수 없습니다. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. ìžê¸°ë¶€ìƒì—´ì°¨ %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for monorails: %.1f km/h by %s. ëª¨ë…¸ë ˆì¼ %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for motorcars: %.1f km/h by %s. ìžë™ì°¨ %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for narrowgauges: %.1f km/h by %s. 협궤기차 %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for planes: %.1f km/h by %s. 비행기 %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for railways: %.1f km/h by %s. 기차 %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! New world record for ship: %.1f km/h by %s. ì„ ë°• %2$sê°€ %1$.1f km/h로 세계 ì‹ ê¸°ë¡ ë‹¬ì„±! #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL ì¸ &1_CITY_SYLL 성 &2_CITY_SYLL ë™ &3_CITY_SYLL 주 &4_CITY_SYLL ì´Œ &5_CITY_SYLL ì &6_CITY_SYLL ì–‘ &7_CITY_SYLL ì „ &8_CITY_SYLL 구 &9_CITY_SYLL ë ¹ &A_CITY_SYLL êµ &B_CITY_SYLL 림 &C_CITY_SYLL ì‚° &D_CITY_SYLL ì› &E_CITY_SYLL ì • %0_CITY_SYLL 송 %1_CITY_SYLL ì˜ %2_CITY_SYLL ì‚° %3_CITY_SYLL 안 %4_CITY_SYLL ì–‘ %5_CITY_SYLL í‰ %6_CITY_SYLL ë…¸ %7_CITY_SYLL í•© %8_CITY_SYLL 병 %9_CITY_SYLL ì› %A_CITY_SYLL 구 %B_CITY_SYLL ì‚° %C_CITY_SYLL ì‹  %D_CITY_SYLL ì  %E_CITY_SYLL 천 %F_CITY_SYLL ë™ 1center %s %s 1extern %s 지선 %s 1suburb %s %s %s 2center %s 중앙 %s 2extern %s 외곽 %s 2suburb %s ì „ì›êµ¬ì—­ %s %s 3center %s ë©”ì¸ %s 3extern %s 토지 %s 3suburb %s ë§ˆì„ %s %s 4center %s ë‚´ë¶€ %s 4extern %s 외부 %s 4suburb %s ì´Œë½ %s 5center %s 시내 %s 5extern %s 환승센터 %s 5suburb %s ë§ˆì„ %s 6center %s 허브 %s 6extern %s êµí™˜ %s 6suburb %s ë³€ë‘리 %s %s 7center %s ë„시 %s 7extern %s í‰ì› %s 7suburb %s ê³µì› %s 8center %s 사업 %s 8extern %s %s 마진 %s 8suburb %s 위성 %s 9center %s 중심축 %s 9extern %s 우회 %s 9suburb %s 중간 %s simutrans-124.3/simutrans/text/ko/000077500000000000000000000000001474050137200171755ustar00rootroot00000000000000simutrans-124.3/simutrans/text/ko/airtools.txt000066400000000000000000000141361474050137200215770ustar00rootroot00000000000000í•­ê³µ 관련 ë„구

í•­ê³µ 관련 ë„구

í•­ê³µ 관련 ë„구 í•­ê³µë§ì„ 형성하기 위한 ë„구를 í¬í•¨í•©ë‹ˆë‹¤.

ë„êµ¬ë“¤ì€ ìƒì„± ë° ì œê±° ìž‘ì—…ì„ ì‹œí–‰í•©ë‹ˆë‹¤: 유ë„로나 í•­ê³µ 활주로, ì—어스탑 (비행기와 ê³µí•­ì„ ì˜¤ê°€ë©° 화물ì´ë‚˜ 승ê°ì„ 실고 내리는 ë°ì— 사용ë˜ì–´ 진다), 격납고(í•­ê³µê¸°ì²´ë“¤ì„ ë³´ê´€í•˜ê³  관리하기 위한 것입니다.) 그리고 그리고 ë‹¤ìˆ˜ì˜ í•­ê³µ 관련 ê±´ì¶•ë¬¼ì„ í¬í•¨í•©ë‹ˆë‹¤.

플레ì´ë¥¼ 하며 타임ë¼ì¸ì´ ìƒì„±ëœë‹¤ë©´, ì‹œê°„ì´ ì§€ë‚˜ë©´ Simutransì—서 ë” ë§Žì€ ë„구-ì˜µì…˜ì´ ë‚˜íƒ€ë‚  수 있습니다

게임 ë·° 맨 ìœ„ì— ìžˆëŠ” 비행기 ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ ë„구 모ìŒì„ 엽니다.

ë„구 모ìŒì„ 열거나 í´ë¦­í•œ 후 마우스 커서를 ë„구 ì˜µì…˜ì— ê°€ì ¸ê°€ì„œ ì´ë¦„ê³¼ ì ì ˆí•œ 위치를 확ì¸í•©ë‹ˆë‹¤: 건설 비용, 유지보수 비용과 최대 ì†ë„ 제한.

{íŒ: 간단한 ê³µí•­ì„ ë§Œë“œëŠ” 방법:

i) 유ë„로(들)와 활주로(들)ì„ êµ¬ì¶• ë° ì—°ê²°í•©ë‹ˆë‹¤.;

ii) 유ë„로(들)ì˜ ëì— ì—ì–´ìŠ¤íƒ‘ì„ ì„¤ì¹˜í•©ë‹ˆë‹¤.;

iii) í•„ìš”ì— ë”°ë¼ ê³µí•­ ê±´ë¬¼ì„ ì¶”ê°€í•©ë‹ˆë‹¤.}

ë„구ì—는 ë‹¤ìŒ í•­ëª©ì´ í¬í•¨ë  수 있습니다:

유ë„로: ì´ ë„구는 항공기가 활주로ì—서 활주로로 ì´ë™í•  수 있는 ì§€ìƒ ì´ë™ ì˜ì—­ì„ 구축합니다. 유ë„로는 게임 ë·° 기준 í‰ì§€ì— 건설ë©ë‹ˆë‹¤.

주ì˜: 활주로가 활주로 ëì— ì—°ê²°ë˜ì–´ 있는 경우 항공기는 ì´ë¥™ ë° ì°©ë¥™ì„ í•  수 없습니다.

유ë„로 건설법: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒ (커서를 유ë„로 변경합니다.), 그런 ë‹¤ìŒ ì§€í˜•ì„ í´ë¦­í•˜ì—¬ 시작ì ì„ 찾습니다. (게임 ë·°ì— ë¶ˆë„저를 표시하고 ë””ìŠ¤í”Œë ˆì´ ì˜¤ë¥¸ìª½ í•˜ë‹¨ì— ì¢Œí‘œë¥¼ 표시합니다.), 그리고 ì—°ê²°í•  지형 ë˜ëŠ” 활주로를 í´ë¦­í•©ë‹ˆë‹¤.

{íŒ: 파괴/제거를 사용하여 유ë„ë¡œì˜ ê°œë³„ì ìœ¼ë¡œ 제거합니다. ë˜ëŒë¦¬ê³ ë‚˜ë©´ [z] ê±´ì¶• ë¹„ìš©ì„ í™˜ë¶ˆí•˜ì§€ 않습니다.}

활주로: ì´ ë„구는 항공기가 ì´ë¥™ê³¼ ì°©ë¥™ì„ ìœ„í•´ 사용하는 활주로를 만듭니다. 활주로는 게임 ë·°ì˜ í‰í‰í•œ ì§€ë©´ì— ì„¸ì›Œì§€ë©° 서로 êµì°¨í•  수 있습니다.
{íŒ: 활주로 ëì„ ì—°ê²°í•˜ì§€ ì•Šì€ ì±„ë¡œ 남겨둡니다. 그렇지 않으면 항공기가 ì´ë¥™í•˜ê±°ë‚˜ 착륙할 수 없습니다. 파괴/제거를 사용하여 유ë„ë¡œì˜ ê°œë³„ì ìœ¼ë¡œ 제거합니다. ë˜ëŒë¦¬ê³ ë‚˜ë©´ [z] 건설 ë¹„ìš©ì„ í™˜ë¶ˆí•˜ì§€ 않습니다.}

활주로 제거: ì´ ë„구는 게임 ë·°ì˜ ë‘ ì  ì‚¬ì´ì—,비행기가 ì—†ì„ ë•Œ, 유ë„로 ë˜ëŠ” 활주로 ë¶€ë¶„ì„ ì œê±°í•©ë‹ˆë‹¤. ì´ ë„구는 사용시 ë¹„ìš©ì´ ë°œìƒí•©ë‹ˆë‹¤.
활주로 제거법: ë„구를 í´ë¦­í•©ë‹ˆë‹¤. (커서를 빨간색 Xìžë¡œ 변경합니다.); 삭제할 활주로를 í´ë¦­í•©ë‹ˆë‹¤. (게임 ë·°ì—서 빨간색 X표로 í‘œì‹œëœ ì‚­ì œ ì§€ì  ì„ íƒ); 그리고 마지막으로 ìŠ¤íŠ¸ë¦½ì˜ ë‹¤ë¥¸ ì§€ì ì—서 í´ë¦­í•˜ì—¬ 첫 번째 ì‚­ì œ ì§€ì ê¹Œì§€ ë¶€ë¶„ì„ ì œê±°í•©ë‹ˆë‹¤. {íŒ: 활주로 ëì„ ì—°ê²°í•˜ì§€ ì•Šì€ ìƒíƒœë¡œ 유지하지 않으면 비행기가 ì´ë¥™í•˜ì§€ 않거나 착륙할 수 없습니다. 활주로를 개별ì ìœ¼ë¡œ 제거하려면 파괴/제거 사용하시면ë©ë‹ˆë‹¤.}

항공기 격납고(차고, 차고지, 차량기지): 항공기 구매 ë° ê´€ë¦¬ë¥¼ 위한 격납고 구축 ë„구입니다. 격납고는 유지 관리 ë¹„ìš©ì´ ë°œìƒí•˜ë©°, 유ë„ë¡œì˜ ëì— ì œìž‘ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤.
격납고 제작법: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒ (커서를 창고 모양으로 변경), 그리고 나서 유ë„ë¡œì˜ ë ë¶€ë¶„ì„ í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/제거로 격납고 제거}

ì—어스탑&탑승êµ: ì´ ë„구는 게임 ë·° ë‚´ì— í•­ê³µê¸°ê°€ 승ê°ì´ë‚˜ í™”ë¬¼ì„ í”½ì—… ë° ë‚´ë¦´ 수 있ë„ë¡ í•˜ëŠ” ì—어스탑(들)ì„ ë§Œë“­ë‹ˆë‹¤.
만약 새롭게 만들어진 ì—ì–´ìŠ¤íƒ‘ì´ ê¸°ì¡´ì— ì¡´ìž¬í•˜ëŠ” ì—어스탑과 ì—°ê²°ë˜ì§€ 않는다면, ì—어스탑 ì´ë¼ëŠ” 새로운 ì—ì–´ìŠ¤íƒ‘ì´ ë§Œë“¤ì–´ 집니다.
ì—ì–´ìŠ¤í†±ì€ ìœ ë„로 타ì¼ì˜ ëì— ê±´ì„¤ë©ë‹ˆë‹¤.; 그리고 ì—ì–´ìŠ¤íƒ‘ì€ ë¬¼í’ˆ, 승ê°, ìš°íŽ¸ë¬¼ì˜ ìœ ì§€ë³´ìˆ˜ 비용과 유역 구역(모ì´ëŠ” ê³³)ì„ ê°€ì§€ê³  있습니다. 항공기는 무료로 ì´ìš©ê°€ëŠ¥í•œ ì—ì–´ìŠ¤íƒ‘ì´ ìžˆëŠ” 공항ì—ë§Œ 착륙할 수 있습니다.
ì—어스탑 제작법: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ ìœ ë„ë¡œì˜ ëì„ í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/제거로 ì—ì–´ìŠ¤íƒ‘ì„ ì œê±°í•©ë‹ˆë‹¤. [v] 키를 눌러 게임 ë·° ë‚´ì˜ í™”ë¬¼ê³¼ 승ê°ë“¤ì„ 위한 유역 êµ¬ì—­ì„ ë³´ì´ê±°ë‚˜ 숨길 수 있습니다.}

공항건물: ì´ ë„구는 공항(ì—­, 정류장)ì„ ìœ„í•´ ì¦ì¶•공사를 합니다. ì´ëŠ” 유지보수 비용과 화물과 승ê°ì„ 위한 유역 구역과 ìˆ˜ìš©ëŸ‰ì„ ì¦ê°€ì‹œí‚µë‹ˆë‹¤. ì¼ë¶€ ë„구 옵션ì—서 ì•„ì´ì½˜(공항(ì—­) 목ë¡ê³¼ 공항 ì •ë³´ì—서 사용ëœë‹¤.) ì€ í™•ìž¥ì„ í†µí•´ 중지 ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있는 í•­ëª©ì„ í‘œì‹œí•©ë‹ˆë‹¤.
확장 하는 법: 확장 ì„ íƒì„ 위한 ë„구를 í´ë¦­í•©ë‹ˆë‹¤. (커서를 '확장'으로 변경), 그런 ë‹¤ìŒ ê²Œìž„ ë·° ë‚´ì—서 기존 공항 ì£¼ë³€ì— ìžˆëŠ” í™•ìž¥ì´ í•„ìš”í•œ 위치를 í´ë¦­í•©ë‹ˆë‹¤. 새로 í™•ìž¥ëœ ë¶€ë¶„ì€ ì´ì œ ê³µí•­ì˜ ì¼ë¶€ë¶„으로 간주ë©ë‹ˆë‹¤.
{íŒ: í™•ìž¥ëœ ë¶€ë¶„ì€ íŒŒê´´/제거로 제거합니다. [v]키를 눌러 게임 ë·° ë‚´ì˜ í™”ë¬¼ê³¼ 승ê°ë“¤ì„ 위한 유역 êµ¬ì—­ì„ ë³´ì´ê±°ë‚˜ 숨길 수 있습니다.}

simutrans-124.3/simutrans/text/ko/baum_build.txt000066400000000000000000000035661474050137200220530ustar00rootroot00000000000000나무 심기 ë„움ë§

나무 심기

ì´ ë‚˜ë¬´ 심기 ì°½ì€ ë‚˜ë¬´ë¥¼ 개별ì ìœ¼ë¡œ 심는 ê²ƒì„ ê°€ëŠ¥í•˜ê²Œ 합니다. ì´ ê¸°ëŠ¥ì€ ë§µ 커스터마ì´ì¦ˆ 기능으로, ë‹¹ì‹ ì´ ê³µìš©ì„œë²„ 유저로 전환하는 경우 ì§€ë„ íŽ¸ì§‘ ë„구모ìŒì„ ì´ìš©í•´ ì‚¬ìš©ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤.
íŒ: ì´ ë„구 모ìŒì—는 í•œë²ˆì— ìˆ²ì„ ì¶”ê°€í•  수 있는 '숲 추가' ë¼ëŠ” ë²„íŠ¼ë„ ìžˆìŠµë‹ˆë‹¤.

정보를 네 부분으로 나누어 설명 드리겠습니다.
· 왼쪽 ìƒë‹¹ì—는 ì‹¬ì„ ìˆ˜ 있는 모든 ì¢…ì˜ ëª©ë¡ì´ 있습니다. 특정 ë‚˜ë¬´ì— ëŒ€í•œ ìžì„¸í•œ 정보를 보려면 목ë¡ì—서 í•­ëª©ì„ í´ë¦­í•˜ì‹­ë©´ë©ë‹ˆë‹¤. 나무를 배치하려면 목ë¡ì—서 ì„ íƒí•œ 다ìŒ, ì›í•˜ëŠ” 게임 월드 ì°½ì—서 ì›í•˜ëŠ” 위치를 í´ë¦­í•˜ì‹œë©´ë©ë‹ˆë‹¤.
· 왼쪽 ì•„ëž˜ì— ì„ íƒí•œ ë‚˜ë¬´ì˜ ê·¸ë¦¼ì´ í‘œì‹œë©ë‹ˆë‹¤.
· 오른쪽 ìƒë‹¨ì—서 ì¼ë¶€ ì˜µì…˜ì´ ì„¤ì •í•  수 있습니다.
· ì˜µì…˜ì˜ ì•„ëž˜ë¶€ë¶„ì€ ì„ íƒí•œ ë‚˜ë¬´ì— ëŒ€í•œ 정보입니다.

ì„ íƒ ëª©ë¡

ì„ íƒ ëª©ë¡ì—는 나무 ìœ í˜•ì´ ì‹ë³„ë˜ëŠ” ë°©ë²•ì„ ë³€ê²½í•  수 있는 ë‘ ê°œì˜ íƒ­ì´ ìžˆìŠµë‹ˆë‹¤.
· 대체명: Paksetsì— ì •ì˜ëœ 대로 ì§€ì •ëœ ì–¸ì–´ë¡œ 트리 ì´ë¦„ì„ í‘œì‹œí•©ë‹ˆë‹¤. ë³€ê²½ëœ ì´ë¦„ì´ ì—†ìœ¼ë©´, ì¼ë°˜ì ì¸ 개체 ì´ë¦„ì´ ì‚¬ìš©ë©ë‹ˆë‹¤.
· ê°ì²´ 고유명: Simutrans ë‚´ë¶€ 개체 ì´ë¦„ì„ í‘œì‹œí•©ë‹ˆë‹¤.

옵션들

· 기후 무시: ì´ ì˜µì…˜ì€ ë‹¤ì–‘í•œ 나무 유형들과 ê´€ë ¨ëœ ê¸°í›„ 제약 ê¸°ëŠ¥ì„ ë¹„í™œì„±í™”í•©ë‹ˆë‹¤..
· ë‚˜ì´ ëžœë¤: ì‹¬ì„ ë‚˜ë¬´ì˜ ë‚˜ì´ê°€ ëžœë¤í™”ë©ë‹ˆë‹¤. ë³´í†µì€ ê°€ìž¥ 어린 나ì´ëŒ€ë¡œ 심어져 ìžë¼ë©°, ê¾€ 오랜 세월 ë™ì•ˆ 살아있습니다.

simutrans-124.3/simutrans/text/ko/citybuilding_build.txt000066400000000000000000000046051474050137200236100ustar00rootroot00000000000000ë„시 건물 건설

ë„시 건물 건설

네 부분으로 나눠서 설명합니다.
· 왼쪽 ìƒë‹¨ì€ 건설 가능한 ë„시 ê±´ë¬¼ë“¤ì˜ ì„ íƒ ëª©ë¡ìž…니다.
· 왼쪽 í•˜ë‹¨ì— ì„ íƒí•œ ë„시 ê±´ë¬¼ì˜ ì‚¬ì§„ì´ í‘œì‹œë©ë‹ˆë‹¤.
· 오른쪽 ìƒë‹¨ì—서 ì¼ë¶€ ì˜µì…˜ì„ ì„¤ì •í•  수 있습니다.
· 오른쪽 í•˜ë‹¨ì€ ì„ íƒí•œ ë„시 ê±´ë¬¼ì— ëŒ€í•œ 정보입니다.

ì„ íƒ ëª©ë¡

ì„ íƒ ëª©ë¡ì€ 사용 가능한 모든 ë„시 ê±´ë¬¼ì„ ë³´ì´ë©°, 오른쪽 ìƒë‹¨ì— 사용 가능한 ì˜µì…˜ë„ í‘œì‹œí•©ë‹ˆë‹¤. (주íƒ, ìƒì ê³¼ 사무실, 공업용 건물). ë„시 ê±´ë¬¼ì˜ ì‹ë³„ ë°©ë²•ì„ ë³€ê²½í•  수 있는 íƒ­ì´ ë‘ ê°€ì§€ê°€ 있습니다.
· 대체명: ì„¤ì •ëœ ì–¸ì–´ë¡œ 건물 ì´ë¦„ì„ í‘œì‹œí•©ë‹ˆë‹¤. ì„¤ì •ëœ ì–¸ì–´ì— ëŒ€ì²´í• ë§Œí•œ ê²ƒì´ ì—†ëŠ” 경우, 개체 ë³¸ì—°ì˜ ì´ë¦„ì´ ì‚¬ìš©ë©ë‹ˆë‹¤.
· 고유 개체명: Simutransì—서 ê¸°ì¡´ì— ì„¤ì •í•œ 건물 ìœ í˜•ì— ë”°ë¥¸ 고유 ê°œì²´ëª…ì„ í‘œì‹œí•©ë‹ˆë‹¤.

색ìƒì´ 들어간 ê¸€ì€ ê°ìž 특별한 ì˜ë¯¸ë¥¼ 가집니다:
· 파란글 주íƒì„ 나타냅니다.
· ì´ˆë¡ê¸€ ìƒì ê³¼ ì‚¬ë¬´ì‹¤ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
· ê²€ì€ìƒ‰ 글 공업용 ê±´ë¬¼ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.

옵션들

· 기후 무시: ì´ ì˜µì…˜ì€ ë‹¤ì–‘í•œ 건물 유형과 ê´€ë ¨ëœ ê¸°í›„ 제약 ê¸°ëŠ¥ì„ ë¹„í™œì„±í™”í•©ë‹ˆë‹¤.
· 사용 ì—°ì‹: ì„ íƒ ëª©ë¡ì—는 현재 Simutransì˜ ì—°ë„를 사용할 수 있는 건물만 í¬í•¨ë©ë‹ˆë‹¤.
· 구형 항목 표시: ì„ íƒ ëª©ë¡ì„ 확장하여 현재 Simutransì˜ ì—°ë„ê°€ ë” ì´ìƒ 사용ë˜ì§€ 않는 ê±´ë¬¼ë„ í¬í•¨í•©ë‹ˆë‹¤..
· 주íƒ: ì„ íƒ ëª©ë¡ì— 거주지가 ìžˆì„ ê²ƒìž…ë‹ˆë‹¤.
· ìƒì ê³¼ 사무실: ì„ íƒ ëª©ë¡ì— ìƒì ê³¼ ì‚¬ë¬´ì‹¤ì´ ìžˆì„ ê²ƒìž…ë‹ˆë‹¤.
· 공업용 건물: ì„ íƒ ëª©ë¡ì— 공업용 ê±´ë¬¼ì´ ìžˆì„ ê²ƒìž…ë‹ˆë‹¤.
· 회전: ì„ íƒí•œ ê±´ë¬¼ì„ ê°ê¸° 다른 ê°ë„ì—서 ë³¼ 수 있습니다. 그로ì¸í•´ 해당 위치ì—서 특정ê°ë„를 ì„ íƒ ê°€ëŠ¥í•©ë‹ˆë‹¤. 왼쪽 í•˜ë‹¨ì— ìžˆëŠ” ì´ë¯¸ì§€ê°€ ì´ë¥¼ ë°˜ì˜í•˜ë„ë¡ ë³€ê²½ë©ë‹ˆë‹¤. ì´ ì˜µì…˜ì„ ëžœë¤ìœ¼ë¡œ 설정하면 ê±´ë¬¼ì˜ ëžœë¤ ë³´ê¸°ê°€ 사용ë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/citylist_filter.txt000066400000000000000000000036241474050137200231540ustar00rootroot00000000000000ë„시 목ë¡

ë„시 목ë¡

ë„시 목ë¡ì—서는 ë„시지역(시골, 마ì„, ë„시)ê³¼ ì¸êµ¬ ë“±ì— ëŒ€í•œ 정보를 ë³¼ 수 있습니다.

여는 방법: ëª©ë¡ ê´€ë¦¬ ì•ˆì˜ ë„시 ëª©ë¡ ì•„ì´ì½˜ì´ë‚˜ [Shift+T]키를 누르면 ë©ë‹ˆë‹¤.
ë„시 목ë¡ì€ ë„ì‹œì˜ ìˆœì„œë¥¼ 바꾸는 2ê°œì˜ ì˜µì…˜ ë²„íŠ¼ì´ ìžˆìŠµë‹ˆë‹¤.
{íŒ: 목ë¡ì´ ì¼ë¶€ë¶„ë§Œ ë³´ì¸ë‹¤ë©´, 슬ë¼ì´ë“œ 바를 ì´ìš©í•˜ì—¬ ë„시 목ë¡ì˜ í¬ê¸°ë¥¼ìž¬ì¡°ì •하거나 바꾸세요. }

ì´ì¸êµ¬: 는 게임 ë‚´ì˜ ì „ì²´ ì¸êµ¬(모든 ë„ì‹œì§€ì—­ì˜ ì´ì¸êµ¬ 수)입니다. ìµœê·¼ì˜ ì¸êµ¬ ì¦ê°€ëŠ” 괄호 ì•ˆì— í‘œì‹œë©ë‹ˆë‹¤.

분류: ì—는 ë„ì‹œì§€ì—­ì˜ ìˆœì„œë¥¼ 결정하는 ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤.
옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ë©´ 다른 ì˜µì…˜ì´ ë‚˜ì˜µë‹ˆë‹¤.

- ì´ë¦„ì€ ë„시ì´ë¦„ì„ ì•„ìŠ¤í‚¤ 코드(ASCII-code) 순서대로 배열합니다. (대문ìžê°€ 소문ìžë³´ë‹¤ 먼저 나옴)
- ì£¼ë¯¼ì€ ì¸êµ¬ìˆ˜ 순서대로 배열합니다.
- ë„시 ì„±ìž¥ì€ ë°œì „ì†ë„ 순서대로 배열합니다.(발전ì†ë„는 ë„ì‹œì§€ì—­ì˜ í¬ê¸°ì™€ 수송ë˜ëŠ” 승ê°ìˆ˜ì— ë”°ë¼ ê²°ì •ë©ë‹ˆë‹¤.)
- 오름차순 / 내림차순 순서를 반전시킵니다.

ë„시 목ë¡ì˜ ë„시 ì´ë¦„ì„ í´ë¦­í•˜ë©´, ê·¸ ë„ì‹œì§€ì—­ì— ëŒ€í•œ ë” ë§Žì€ ì •ë³´ë¥¼ ë³¼ 수 있습니다.
목ë¡ì—는 다ìŒê³¼ ê°™ì€ ì •ë³´ê°€ 표시ë©ë‹ˆë‹¤:

ë„시명 ê·¸ ë„ì‹œì§€ì—­ì˜ ì´ë¦„ (ë„시 ì •ë³´ì—서 바꿀 수 잇습니다)..

ì¸êµ¬ ê·¸ ë„ì‹œì§€ì—­ì˜ ì¸êµ¬. 괄호 ì•ˆì˜ ê²ƒì€ ìµœê·¼ì˜ ë°œì „ì†ë„.

simutrans-124.3/simutrans/text/ko/citywindow.txt000066400000000000000000000115521474050137200221420ustar00rootroot00000000000000ë„시 통계 ë„움ë§

ë„시 통계

ë„시 통계는 ì„ íƒí•œ ë„ì‹œì§€ì—­ì˜ í†µê³„ë¥¼ 보여주며, ë„시 통계를 ì´ìš©í•˜ì—¬ ê·¸ ë„ì‹œì˜ ì´ë¦„ì„ ë°”ê¿€ 수 있습니다. ë„ì‹œì§€ì—­ì€ ë„시, ë§ˆì„ ë˜ëŠ” 시골입니다. ì•„ëž˜ì— ì“°ì¸ ë„시ë¼ëŠ” 단어는 ë„시지역 3ê°œ ëª¨ë‘ í•´ë‹¹í•©ë‹ˆë‹¤.

ê° ë„시는 ì‹œì²­ì´ ìžˆìœ¼ë©°, ê·¸ 주변ì—서 성장합니다. 승ê°ê³¼ ìš°íŽ¸ì˜ ì´ë™ìœ¼ë¡œ 성장합니다. ë„ì‹œì˜ ì„±ìž¥ì€ ë„ë¡œì˜ ê±´ì„¤, 공공 서비스 플레ì´ì–´ì˜ ë„로 ì¸ìˆ˜, 새 ë„시 건물과 새 ì‚°ì—…ì˜ ë“±ìž¥ê³¼ ë„시 경계 확장으로 나타납니다.

ë„시 통계는 ì‹œì²­ì„ ì ê²€ ë„구로 í´ë¦­í•˜ê±°ë‚˜ ë„시 목ë¡ì—서 ë„시를 í´ë¦­í•˜ë©´ 나옵니다. 여기서 ë„ì‹œì˜ ì´ë¦„ì„ ë°”ê¿€ 수 있으며, 몇몇 통계, ë‘ ê°œì˜ ë¯¸ë‹ˆë§µê³¼ ë„ì‹œì˜ ë°œì „ì„ ì‹œê°„ ê²½ê³¼ì— ë”°ë¼ ë³´ì—¬ì£¼ëŠ” 그래프를 ë³¼ 수 있습니다.

ì´ë¦„: ì€ ë„ì‹œì— ë¶€ì—¬ëœ ì´ë¦„ì´ë©°, ë„시 통계 ì œì¼ ìœ„ ìƒìžì— 나타납니다.
ë„ì‹œì§€ì—­ì˜ ì´ë¦„ì€ ë„시 경계 ë‚´ì˜ ì—­ ì´ë¦„ì— ì“°ìž…ë‹ˆë‹¤. ë„시 ì´ë¦„ì„ ë³´ì—¬ì£¼ëŠ” ìƒìžë¥¼ í´ë¦­í•˜ì—¬ ì´ë¦„ì„ ë°”ê¿€ 수 있습니다.
{íŒ: [!] 버튼으로 시청 ìœ„ì— ë‚˜íƒ€ë‚˜ëŠ” 고시 ì´ë¦„ì˜ í‘œí˜„ ë°©ì‹ì„ 바꿀 수 있습니다. ë„시 ì´ë¦„ì˜ ìƒì„± ë°©ì‹ì— 대해 ë” ìžì„¸ížˆ 알고 싶으시다면 ...simutrans/text/ ì•ˆì˜ readme_citylist.txt를 참고하세요.}

ì´ë¦„ ìƒìž ë°‘ì—는 다ìŒê³¼ ê°™ì€ ê¸°ë³¸ì ì¸ ë„시 통계가 있습니다.:
ë„시 í¬ê¸°: ë„ì‹œì˜ ì¸êµ¬ìž…니다. 괄호 ì•ˆì˜ ìˆ«ìžëŠ” ìµœê·¼ì˜ ì¸êµ¬ ì¦ê°€ë¥¼ ì˜ë¯¸í•©ë‹ˆë‹¤.
시가지: ë„시 건물(주거/ìƒì—…/공업)ì˜ ìˆ˜
ë„시 좌표: ë„ì‹œì˜ ê²½ê³„ë¥¼ ì˜ë¯¸í•©ë‹ˆë‹¤. ì´ëŠ” ë„시가 성장하면서 ë°”ë€ë‹ˆë‹¤. ì•žìª½ì˜ ì¢Œí‘œëŠ” ê²½ê³„ì˜ ìžìƒê·€ 좌표ì´ë©°, ë’¤ìª½ì€ ìš°í•˜ê·€ìž…ë‹ˆë‹¤. 여러 ë„시가 성장하면서 ë„시경계가 ê³‚ì¹ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.
실업ìž: 와 노숙ìž: 는 현재 ë„ì‹œì— ì‚´ê³  있는 실업ìžì™€ 노숙ìžì˜ 수입니다. ì´ë“¤ì€ ë„시 경계가 커지면서 ì¦ê°€í•˜ë©°, ë„ì‹œì— ìƒˆ ê±´ë¬¼ì´ ë“¤ì–´ì„œë©´ ê°ì†Œí•©ë‹ˆë‹¤. ì´ë“¤ì˜ ê· í˜•ì— ë”°ë¼ ì–´ë–¤ ìœ í˜•ì˜ ë„시 건물(주거/ìƒì—…/공업)ì´ ë“¤ì–´ì„¤ì§€ ê²°ì •ë©ë‹ˆë‹¤.

ë„시성장 허용 ë²„íŠ¼ì€ ë„시 ì„±ìž¥ì„ ê°€ëŠ¥í•˜ê²Œ 하거나 막게 í•  수 있습니다.

ë„시 통계ì—ì„œì˜ ë¯¸ë‹ˆë§µì€ ìŠ¹ê°ê³¼ 우편(ìƒ‰ì¹ ëœ ì ìœ¼ë¡œ ë³´ì—¬ì§)ì˜ ëª©ì ì§€ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤.
오른쪽 ë¯¸ë‹ˆë§µì€ ê²Œìž„ìƒ í˜„ìž¬ ë‹¬ì˜ ê°’ì„, ì™¼ìª½ì€ ì €ë²ˆ ë‹¬ì˜ ê°’ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ê° ì ë“¤ì˜ ìƒ‰ê¹”ì€ ê·¸ ìŠ¹ê° ë˜ëŠ” ìš°íŽ¸ì´ ëª©ì ì§€ì— ë„달했는지, 안했는지를 나타냅니다.
- 노란색 ì : 경로가 있으며, ë¶ë¹„ì§€ 않는 ì—­(ì—­ ì •ë³´ì—서 행복한 얼굴로 표시ë¨)ì—서 ì—¬ì •ì„ ì‹œìž‘í•¨
- 오랜지색 ì : 목ì ì§€ë¡œ 가는 경로가 ì—†ìŒ - 빨간색 ì : 목ì ì§€ë¡œ 가는 경로가 있지만, ë¶ë¹„는 ì—­(ì—­ ì •ë³´ì—서 불행한 얼굴로 표시ë¨)ì—서 ì—¬ì •ì„ ì‹œìž‘í•¨

미니맵 아래ì—서는 ë„ì‹œì˜ í†µê³„ë¥¼ 보여주는 그래프가 있습니다.
yì¶•(세로축)ì€ ì–‘ì„ xì¶•(가로축)ì€ ì‹œê°„ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 그래프 ìœ„ìª½ì˜ ë²„íŠ¼ìœ¼ë¡œ xì¶•ì˜ ë‹¨ìœ„ë¥¼ 바꿀 수 있습니다.:
ë…„: ê° ë…„ë„로 보여줌
달: 12개월 단위로 보여줌

그래프 옵션 ë²„íŠ¼ì„ ë¶€ë¥´ë©´, ê° ë²„íŠ¼ì— í•´ë‹¹í•˜ëŠ” 통계가 그래프로 나타나며, 눌린 것으로 표시ë©ë‹ˆë‹¤.
ë²„íŠ¼ì˜ ìƒ‰ê¹”ê³¼ ê·¸ì— í•´ë‹¹í•˜ëŠ” ê·¸ëž˜í”„ì˜ ìƒ‰ê¹”ì€ ê°™ìŠµë‹ˆë‹¤.:
주민: ë„ì‹œì— ì‚´ê³  있는 ì£¼ë¯¼ì˜ ìˆ˜
성장: ì¸êµ¬ 변화 (ë„시 í¬ê¸°ì™€ 승ê°/ìš°íŽ¸ì— ì œê³µë˜ëŠ” êµí†µ ì„œë¹„ìŠ¤ì— ë”°ë¼ ë³€í™”í•¨)
건물 수: ë„ì‹œì— ìžˆëŠ” ê±´ë¬¼ì˜ ìˆ˜
ìžê°€ìš©: ë„시ì—서 ìƒì„±ëœ ìžê°€ìš©ì˜ 수
통근: êµí†µ 네트워í¬ë¥¼ ì´ìš©í•˜ëŠ” 승ê°ì˜ 수 (ì—­ ì •ë³´ì—서 행복한 얼굴로 표시ë¨)
승ê°: ë„시ì—서 ìƒì„±ë˜ëŠ” 승ê°ì˜ 수
ë³´ë‚´ì§„ 우편물: êµí†µ 네트워í¬ë¥¼ ì´ìš©í•œ ìš°íŽ¸ë¬¼ì˜ ìˆ˜
우편물: ë„시ì—서 ìƒì„±ë˜ëŠ” ìš°íŽ¸ë¬¼ì˜ ìˆ˜
공급: ê³µìž¥ì— ë³´ê´€ëœ ë¬¼í’ˆì´ ìžˆì—ˆë˜ íšŸìˆ˜
물품: 공장ì—서 ìƒì‚°í•œ 물품 수

{íŒ: simuconf.tab와 cityrules.tabì—서 ë„시와 ê´€ë ¨ëœ ì„¤ì •ì„ ë°”ê¿€ 수 있습니다.}

simutrans-124.3/simutrans/text/ko/climates.txt000066400000000000000000000074031474050137200215430ustar00rootroot00000000000000í’ê²½ 설정 ë„움ë§

í’ê²½ 설정

í’ê²½ 설정 ì°½ì€ ê²Œìž„ ì„¸ê³„ì˜ ì§€í˜• ë° ê¸°ìƒ ì¸¡ë©´ì— ëŒ€í•œ ì˜µì…˜ì„ ì„¤ì •í•©ë‹ˆë‹¤. 새 게임 만들기 창과 함께 열립니다.

ê° ì„¤ì •ì„ ì¡°ì •í•˜ë ¤ë©´ ê° ì˜µì…˜ì˜ ì˜†ì— ìžˆëŠ” 화살표 ë²„íŠ¼ì„ í´ë¦­í•˜ê±°ë‚˜ ìƒìžì— 숫ìžë¥¼ 입력하십시오.

ì§€ë„ ì˜µì…˜

수위 - ì§€ë„ì—서 ë¬¼ì˜ ë†’ì´ë¥¼ 설정하십시오 (기본값 -2). ê°’ì´ ë†’ì„ìˆ˜ë¡ ìœ¡ì§€ê°€ ì ê³  ìˆ˜ì—­ì´ ë§Žì•„ì§‘ë‹ˆë‹¤.

ì‚°ì˜ ë†’ì´ - ì§€í˜•ì˜ ìµœëŒ€ 높ì´ë¥¼ 설정하십시오.

ì§€ë„ì˜ ì¡°ë„ - ì§€í˜•ì˜ ì¡°ë„를 설정하십시오. 숫ìžê°€ í´ìˆ˜ë¡ 해안 지역ì—서 ë” ë§Žì€ ê¸°ë³µì„ ë§Œë“­ë‹ˆë‹¤ (ë” ì‚¬ì‹¤ì ìœ¼ë¡œ 보입니다). 매우 거친지ë„는 ì˜ë„í–ˆë˜ë§Œí¼ ë§Žì€ ë„시, ì‚°ì—… ë˜ëŠ” ë„로를 ìƒì„±í•˜ì§€ 못할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.

경고: ë†’ì´ ë ˆë²¨ì´ 33보다 커야합니다.(플레ì´ì–´ê°€ 접근할 수 없습니다). 필요한 경우수위를 낮추면 ë” ë§Žì€ ì§€ë©´ ë ˆë²¨ì„ ìƒì„±í•  수 있습니다.

스노우 ë¼ì¸ 옵션
스노우 ë¼ì¸ì€ ëˆˆì´ ë‚˜íƒ€ë‚˜ëŠ” ì§€ë„ ìƒì˜ 높ì´ìž…니다. 1ë…„ ë™ì•ˆ Simutransì˜ ìŠ¤ë…¸ìš° ë¼ì¸ì€ ë‹¤ìŒ ì„¤ì •ì— ë”°ë¼ ë‹¤ë¦…ë‹ˆë‹¤.

여름 스노우 ë¼ì¸ - ì—¬ë¦„ì² ì˜ ìŠ¤ë…¸ìš° ë¼ì¸(ì˜ì›í•œ 눈). ì´ ê°’ì€ ê¸°í›„ 옵션ì—서 ì„ íƒëœ 가장 ë†’ì€ ì§€í˜• 값입니다. ë¶ê·¹ 기후는 여기ì—서 시작ë©ë‹ˆë‹¤.

겨울 스노우 ë¼ì¸ - 겨울철 스노우 ë¼ì¸ì˜ 최소 높ì´ë¥¼ 설정하십시오. ì§€ë„ ìƒì˜ ë„“ì€ ì§€ì—­ì— ëˆˆì´ ë‚˜íƒ€ë‚˜ê²Œ 하려면 ì´ ê°’ì„ ë‚®ê²Œ 유지하십시오.

기후 옵션
새 ì§€ë„ì˜ ë‹¤ë¥¸ 기후 ìœ í˜•ì„ ì„¤ì •í•˜ì‹­ì‹œì˜¤.

ê° ê¸°í›„ 유형 ì˜†ì˜ ê°’ì€ ì§€í˜•ì§€ë„ì˜ ë†’ì´ë¥¼ 기후가 나타나는 곳까지 설정합니다. ë” ë†’ì€ ê¸°í›„ëŒ€ëŠ” ë‚®ì€ ì§€ì—­ì˜ ë” ë‚®ì€ ê¸°í›„ëŒ€ë¡œ ë®ì—¬ìžˆìŠµë‹ˆë‹¤. 특정 기후를 ë„려면 목ë¡ì—서 ë” ë†’ì€ ê¸°í›„ (ì‚¬ë§‰ì˜ ê²½ìš° 수위)와 ë™ì¼í•œ ê°’ì„ ì„¤ì •í•˜ì‹­ì‹œì˜¤.

참고: 건물, ì‚°ì—… 그리고 ì‹ë¬¼ì€ 제작ìžì— ì˜í•´ 특정 기후를 할당받았습니다.

사막 기후 - 매우 ì ì€ 강수량, 극심한 기온. 매우 ì ì€ 나무. í‰í‰í•œ í’ê²½.

열대 기후 - ì ë„ ë¶€ê·¼ì˜ ê±´ì¡°í•˜ì§€ ì•Šì€ ì§€ì—­ì˜ ì „í˜•ì ì¸ í•´ìˆ˜ë©´ì˜ ì¼ì •한 고온 ë° ë‚®ì€ ê³ ë„.

지중해성 기후 - ì ë‹¹ížˆ 변하는 습한 날씨.

온화한 기후 - 열대와 극관 사ì´ì˜ 지역ì—서 발견ë˜ì–´ 날씨가 변합니다.

íˆ°ë“œë¼ ê¸°í›„ - ë‚®ì€ ê¸°ì˜¨, ê·¹ê´€ì˜ ê°€ìž¥ìžë¦¬.

ê³ ì‚°(바위 투성ì´ì˜) 기후 - 건조한 기후, 추운 겨울.

다른 옵션

나무가 ì—†ìŒ - simutransê°€ 나무를 그릴 수 ì—†ë„ë¡ í•˜ë ¤ë©´ ì´ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. 나무는 ë Œë”ë§ì— CPU ì‹œê°„ì„ ì†Œë¹„í•©ë‹ˆë‹¤. CPU ì†ë„ê°€ ëŠë¦¬ê±°ë‚˜ RAMì´ ì ì€ PCì—서는 ì´ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤.

호수 - simutransê°€ ì§€í‘œë©´ì˜ ì¼ë¶€ 피트를 물로 채워 ì§€ë„ ì „ì²´ì—서 호수를 만드려면 ì´ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤.

í•˜ì²œì˜ ìˆ˜ - 지형지ë„ì—서 ìƒì„±ë˜ê³  ì‚¬ìš©ë  ìˆ˜ 있는 í•˜ì²œì˜ ìµœëŒ€ 수를 설정하십시오.

최소. í•˜ì²œì˜ ê¸¸ì´ - ì§€ë„ ìƒì˜ í•˜ì²œì˜ ìµœì†Œ 길ì´ë¥¼ 설정하십시오.(타ì¼ì„ 통해서)

최대. í•˜ì²œì˜ ê¸¸ì´ - ì§€ë„ ìƒì˜ í•˜ì²œì˜ ìµœëŒ€ 길ì´ë¥¼ 설정하십시오.(타ì¼ì„ 통해서)

simutrans-124.3/simutrans/text/ko/color.txt000066400000000000000000000017261474050137200210620ustar00rootroot00000000000000플레ì´ì–´ ìƒ‰ìƒ ë„움ë§

플레ì´ì–´ 색ìƒ

플레ì´ì–´ 색ìƒì—서는 ì—¬ëŸ¬ë¶„ì˜ íšŒì‚¬ ìƒ‰ê¹”ì„ ê³ ë¥¼ 수 있습니다.
차량, 건물 ë“±ì— íšŒì‚¬ 색깔로 색칠ë©ë‹ˆë‹¤.

플레ì´ì–´ 색ìƒì€ 게임 옵션ì—서 ì—´ 수 있습니다.

ìƒ‰ìƒ ë²„íŠ¼ì„ ëˆ„ë¥´ë©´, 회사 ìƒ‰ê¹”ì´ ë°”ë€ë‹ˆë‹¤.
새 색ìƒì„ 골ëžë‹¤ëŠ” ê²ƒì„ ë³´ì—¬ì£¼ê¸° 위해, 제목 í‘œì‹œì¤„ì˜ ìƒ‰ê¹”ë„ ë°”ë€ë‹ˆë‹¤.

기본 ì¸ê°„ 플레ì´ì–´ì˜ 색ìƒì€ ë°ì€ 파란색입니다.
몇몇 ê²ƒë“¤ì€ ìƒ‰ìƒ ì½”ë“œê°€ 없거나 ì„ íƒí•œ 색깔로 보여지지 ì•Šì„ ìˆ˜ 있습니다.

{íŒ: AI 플레ì´ì–´ì˜ 색ìƒì„ 바꾸려면, 플레ì´ì–´ 목ë¡ì´ë‚˜ [Shift+P]를 눌러 플레ì´ì–´ë¥¼ 바꾼 ë’¤ 플레ì´ì–´ 색ìƒì—서 바꾸시면 ë©ë‹ˆë‹¤.}

simutrans-124.3/simutrans/text/ko/convoi.txt000066400000000000000000000071501474050137200212360ustar00rootroot00000000000000차량 목ë¡

차량 목ë¡

차량 목ë¡ì€ 정보를 보여주며 다른 차량 (ìˆ˜ì†¡ìˆ˜ë‹¨ì€ ìš´ìš©ê°€ëŠ¥í•œ 차량 ë˜ëŠ” 차량 ë‹¨ìœ„ì˜ ì¡°í•©ìœ¼ë¡œ 구성ë©ë‹ˆë‹¤)ì„ í•„í„°ë¥¼ 관리하고 나열합니다.

열려면: ëª©ë¡ ê´€ë¦¬ì—서 차량 ëª©ë¡ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [V]를 누릅니다. 차량 목ë¡ì—는 4ê°œì˜ ì˜µì…˜ ë²„íŠ¼ì´ ìžˆìŠµë‹ˆë‹¤: ë‘ ê°œëŠ” 목ë¡ì˜ í•­ëª©ì„ ì£¼ë¬¸í•˜ëŠ” ë° ì‚¬ìš©ë˜ë©° ë‘ ê°œëŠ” 목ë¡ì— í‘œì‹œëœ í•­ëª©ì˜ ì„¤ì •ì„ ë³€ê²½í•˜ëŠ” ë° ì‚¬ìš©ë©ë‹ˆë‹¤.
아래 ë²„íŠ¼ì€ í•„í„° ì˜µì…˜ì˜ ê¸°ì¤€ì— ë§žëŠ” 수송수단 목ë¡ìž…니다.
{íŒ: 만약 ìˆ˜ì†¡ìˆ˜ë‹¨ì´ ë‚˜ì—´ë˜ì§€ 않는다면 í•„í„° ì˜µì…˜ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤. 만약 목ë¡ì— 있는 í•­ëª©ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ ë³´ì¸ë‹¤ë©´ 슬ë¼ì´ë” 바를 사용하여 차량 ëª©ë¡ ë˜ëŠ” 스í¬ë¡¤ 목ë¡ì˜ í¬ê¸°ë¥¼ 조정하십시오.}

ì˜µì…˜ì„ ìˆœí™˜í•˜ê±°ë‚˜(옵션 ë²„íŠ¼ì˜ ì´ë¦„ 변경) í•„í„° 설정 관리를 열려면 옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤:

ì •ë ¬ 기준: ë‘ ê°œì˜ ì˜µì…˜ ë²„íŠ¼ì€ ëª©ë¡ì— í‘œì‹œëœ ì°¨ëŸ‰ì˜ ìˆœì„œë¥¼ 결정합니다.

- 유형 ìˆ˜ì†¡ì˜ ìœ í˜•ì— ë”°ë¥¸ 순서(ë„로 차량, ì² ë„ ì°¨ëŸ‰, 보트 ë° í•­ê³µê¸°ì˜ ì˜¤ë¦„ì°¨ìˆœ)
- ì´ë¦„ ASCII 코드 순서 ë‚´ì—서 알파벳 순으로 í• ë‹¹ëœ ì´ë¦„ì— ë”°ë¥¸ 순서: ì†Œë¬¸ìž ì•žì˜ ëŒ€ë¬¸ìž(기본ì ìœ¼ë¡œ ì´ê²ƒì€ 수송수단으로 매입 ë˜ëŠ” ì¡°ë¦½ëœ ìµœì´ˆì˜ ì°¨ëŸ‰ 단위입니다).
- 수입 수ìµì— ì˜í•œ 순서(ìƒì„±ëœ 수입 - ìš´ì˜ ë¹„ìš©).
- ë‚´ë¶€ ì•„ì´ë”” ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ê³ ìœ  ì•„ì´ë”” ë²ˆí˜¸ì— ì˜í•œ 순서(ìˆ˜ì†¡ìˆ˜ë‹¨ì´ ì²˜ìŒ ë§¤ìž…ë거나 차고ì—서 조립ëì„ ë•Œ 기본ì ìœ¼ë¡œ 할당ë˜ê³  수송수단 ì •ë³´ì˜ ì œëª© ë°”ì— í‘œì‹œë©ë‹ˆë‹¤).

- 오름차순 / ë‚´ë¦¼ì°¨ìˆœì€ ëª©ë¡ì˜ 순서를 바꿉니다.

í•„í„°: ë‘ ê°œì˜ ì˜µì…˜ 버튼, ê¸°ì¤€ì„ ë³€ê²½í•˜ê¸°ìœ„í•œ ëª©ë¡ ë° ì ‘ê·¼ ê´€ë¦¬ì— ëŒ€í•œ ì„ íƒ ê¸°ì¤€ì„ ì¼œê³  ë•니다.

- 활성화 / 비활성화 í´ë¦­í•´ì„œ 목ë¡ì—서 ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ í•„í„° ê¸°ì¤€ì„ ì „í™˜í•©ë‹ˆë‹¤.

- 설정ì—서 관리 ì°½ì„ ì—´ì–´ í•„í„° ê¸°ì¤€ì„ ë³€ê²½í•©ë‹ˆë‹¤.

해당 ì°¨ëŸ‰ì— ëŒ€í•œ ë” ë§Žì€ ì •ë³´ë¥¼ 보려면 ë‚˜ì—´ëœ í•­ëª©ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

ê° ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•´ ë‚˜ì—´ëœ í•­ëª©ì€ í¬í•¨í•©ë‹ˆë‹¤:

ë‚´ë¶€ ì•„ì´ë””: ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ê³ ìœ  ì•„ì´ë”” 번호(ìˆ˜ì†¡ìˆ˜ë‹¨ì´ ì²˜ìŒìœ¼ë¡œ 매입ë거나 차고ì—서 조립ëì„ ë•Œ 기본ì ìœ¼ë¡œ 할당ë˜ê³  차량 ì •ë³´ì˜ ì œëª© ë°”ì— í‘œì‹œë©ë‹ˆë‹¤).

í• ë‹¹ëœ ì´ë¦„(기본ì ìœ¼ë¡œ ì´ê²ƒì€ ìˆ˜ì†¡ìˆ˜ë‹¨ì´ êµ¬ë§¤ë거나 조립ëì„ ë•Œ 첫번째 ì°¨ëŸ‰ì´ ë©ë‹ˆë‹¤).

ìˆ˜ìž…ì€ ìˆ˜ìµì„ ë³´ì—¬ì¤ë‹ˆë‹¤.(ìƒì„±ëœ 수입 - ë°œìƒí•œ ìš´ì˜ ë¹„ìš©).

ë¼ì¸: í• ë‹¹ëœ ë¼ì¸ì„ 표시하고 ìˆ˜ì†¡ìˆ˜ë‹¨ì´ ì°¨ê³ ì— ìžˆëŠ”ì§€ë¥¼ 나타냅니다.

ê·¸ëž˜í”½ì€ êµ¬ì„±ê³¼ 현재 부하 ë ˆë²¨ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/convoi_filter.txt000066400000000000000000000045451474050137200226100ustar00rootroot00000000000000차량 ëª©ë¡ í•„í„°

차량 ëª©ë¡ í•„í„°

차량 ëª©ë¡ í•„í„°ì—는 차량 목ë¡ì— í‘œì‹œëœ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ê²°ì •í•˜ëŠ” ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤.

차량 ëª©ë¡ í•„í„°ë¥¼ 열려면 차량 목ë¡ì˜ ì„¤ì •ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

옵션 ë²„íŠ¼ì€ í•„í„° ì˜µì…˜ì´ í™œì„±í™”ëì„ ë•Œ 차량 목ë¡ì— ë‚˜ì—´ë  ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ì„ íƒí•©ë‹ˆë‹¤. 모든 기준 ì„¸íŠ¸ì— ë§žëŠ” 수송수단만 나열ë©ë‹ˆë‹¤.

í•„í„° ê¸°ì¤€ì„ ì„¤ì •í•˜ë ¤ë©´ 정사ê°í˜• ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (ì„ íƒëì„ ë•Œ ë²„íŠ¼ì´ ë“¤ì—¬ì“°ê¸°ë©ë‹ˆë‹¤):

í•„í„° ì´ë¦„: ì´ë¦„으로 ì°¨ëŸ‰ì„ ì„ íƒí•©ë‹ˆë‹¤. 사용하려면: ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  ì´ë¦„ ìƒìžë¥¼ í´ë¦­í•œ ë‹¤ìŒ í•„ìš”í•œ ì´ë¦„ì„ ì •í™•í•˜ê²Œ 입력하십시오(ì˜µì…˜ì€ ëŒ€ì†Œë¬¸ìžë¥¼ 구분합니다).

í•„í„° 유형: ì„ íƒëœë‹¤ë©´ 수송 ìœ í˜•ì— ë”°ë¼ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ë‚˜ì—´í•©ë‹ˆë‹¤. 사용하려면: ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³ , 운송 유형: (ë„로, ì² ë„, 물 ë° ê³µê¸°)ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

특수 í•„í„°: ì°¨ëŸ‰ì„ ì„ íƒí•˜ì—¬ ë‹¤ìŒ ê¸°ì¤€ì— ë”°ë¼ ë‚˜ì—´í•©ë‹ˆë‹¤(ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  í´ë¦­í•©ë‹ˆë‹¤):
- 경로 ì—†ìŒ - ë‹¤ìŒ ëª©ì ì§€ì— 대한 경로를 ì°¾ì„ ìˆ˜ 없습니다.
- ì¼ì • ì—†ìŒ - 경로가 할당ë˜ì§€ 않았습니다.
- 수입 ì—†ìŒ - 수ìµì„ ìƒì„±í•˜ì§€ 못합니다.
- ì°¨ê³ ì— - ì°¨ê³ ì— ìžˆëŠ” 것들
- 노선 ì—†ìŒ - ë…¸ì„ ì´ í• ë‹¹ë˜ì§€ 않았습니다.

화물 í•„í„°: 다른 화물 ë° ìŠ¹ê°ì„ 수송할 수 있는 ëŠ¥ë ¥ì— ë”°ë¼ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ì„ íƒí•©ë‹ˆë‹¤. í•­ëª©ì„ ì„ íƒí•˜ë ¤ë©´ ì´ë¦„ ì˜†ì— ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. 목ë¡ì—서 í•­ëª©ì„ ìŠ¤í¬ë¡¤í•˜ë ¤ë©´ 슬ë¼ì´ë” 바를 사용하십시오. 옵션ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤:
- allì€ ëª¨ë“  í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤.
- noneì€ ì–´ë– í•œ í•­ëª©ë„ ì„ íƒë˜ì§€ 않습니다.
- inv.ì€ í˜„ìž¬ í•­ëª©ì˜ ì„ íƒì„ 반대로 합니다.

simutrans-124.3/simutrans/text/ko/convoidetail.txt000066400000000000000000000042741474050137200224250ustar00rootroot00000000000000수송수단 세부 사항

차량 세부 사항

수송수단 세부 사항 수송수단 세부 정보는 수송수단(운용가능한 차량 ë˜ëŠ” 차량 ë‹¨ìœ„ì˜ ì¡°í•©)ì— ëŒ€í•œ ë” ë§Žì€ ì •ë³´ë¥¼ 제공하고 즉시 ìˆ˜ì†¡ìˆ˜ë‹¨ì„ íŒë§¤í•˜ëŠ” ë° ì‚¬ìš©ë  ìˆ˜ 있습니다.

수송수단 세부 ì‚¬í•­ì€ ìˆ˜ì†¡ìˆ˜ë‹¨ ì •ë³´ì˜ ì„¸ë¶€ 사항 옵션 버튼ì—서 ì—´ 수 있습니다.
만약 모든 차량 단위가 ë³´ì´ì§€ 않으면 수송수단 세부 ì‚¬í•­ì„ ì¡°ì •í•˜ê±°ë‚˜ 스í¬ë¡¤í•  수 있ë„ë¡ ìŠ¬ë¼ì´ë” 바를 사용하십시오.

수송수단 세부 ì‚¬í•­ì˜ ë§¨ 위ì—는 다ìŒê³¼ ê°™ì€ ì •ë³´ê°€ í¬í•¨ë©ë‹ˆë‹¤:

ë™ë ¥: 수송수단ì˜(ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ëª¨ë“  차량 ë‹¨ìœ„ì˜ ê²°í•©ëœ ë™ë ¥)

재íŒë§¤ 가치: ìˆ˜ì†¡ìˆ˜ë‹¨ì´ íŒë§¤ë  경우 ë°›ì„ ê¸ˆì•¡(ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ë§¤ìž… 가격ì—서 ê°ê°€ 견ì ì„ 제외한 금액)

경고: ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ì¦‰ì‹œ íŒë§¤í•˜ë ¤ë©´ íŒë§¤ëª¨ë“œ 옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. ë”ì´ìƒì˜ 확ì¸ì€ 필요하지 않습니다. ìˆ˜ì†¡ìˆ˜ë‹¨ì€ ê²Œìž„ì—서 제거ë˜ê³  플레ì´ì–´ ìž”ì•¡ì€ íŒë§¤ ê°€ê²©ì— ë§žê²Œ ì ë¦½ë©ë‹ˆë‹¤.

수송수단 세부 ì‚¬í•­ì€ ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ëª¨ë“  차량 단위를 나열합니다.
ê° ì°¨ëŸ‰ ë‹¨ìœ„ì— ëŒ€í•´ ë‚˜ì—´ëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤:
- 차량 단위 그래픽: 차량 ë‹¨ìœ„ì˜ ì‚¬ì§„(차고ì—ì„œë„ ì‚¬ìš©ë©ë‹ˆë‹¤.)
- 제조: 제조 ë…„ì›”, 타임ë¼ì¸ì„ 사용하는 경우 소개 ë‚ ì§œ
- 재íŒë§¤ 가치: íŒë§¤í•  경우 받는 금액
- ë™ë ¥: ìƒì„±ëœ 힘(ì „ë™ì‹ì˜ 차량 ë‹¨ìœ„ì— ì˜í•´)
- 마찰: 현재 마찰 레벨
- 최대 수입: ì´ ìˆ˜ì†¡ìˆ˜ë‹¨ìœ¼ë¡œ 수송ë˜ëŠ” í•­ëª©ì˜ ìœ í˜•ì— ê¸°ë°˜ì„ ë‘” 차량 ë‹¨ìœ„ì˜ ìµœëŒ€ 가능 수입
- íƒ‘ìž¬ëœ í•­ëª© ì´ ì°¨ëŸ‰ ë‹¨ìœ„ì— ì˜í•´ 현재 ìš´ë°˜ë˜ëŠ” í•­ëª©ì˜ ìˆ˜ëŸ‰ê³¼ 목ì ì§€

simutrans-124.3/simutrans/text/ko/convoiinfo.txt000066400000000000000000000202521474050137200221100ustar00rootroot00000000000000수송수단 정보

수송수단 정보

수송수단 정보는 화물과 승ê°ì„ ìˆ˜ì†¡í•˜ëŠ”ë° ì‚¬ìš©ë˜ëŠ” 수송수단(운용가능한 차량 ë˜ëŠ” 차량 ë‹¨ìœ„ì˜ ì¡°í•©)ì— ëŒ€í•œ 정보를 제공합니다.
여기ì—는 ìˆ˜ì†¡ìˆ˜ë‹¨ì— ì˜í•´ ìš´ë°˜ëœ í•­ëª©ë“¤ì„ ë‚˜ì—´í•˜ë©° 추가 세부 ì‚¬í•­ì— ì ‘ê·¼í•´ì„œ 관리하고 ìˆ˜ì†¡ìˆ˜ë‹¨ì„ íŒë§¤í•  수 있습니다; 게임 ë·°ì—서 ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ë”°ë¼ê°€ì‹­ì‹œì˜¤; 그리고 ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì´ë¦„ê³¼ ìŠ¤ì¼€ì¥´ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤.

ìˆ˜ì†¡ìˆ˜ë‹¨ì€ ì ì–´ë„ í•˜ë‚˜ì˜ ë™ë ¥(ì „ë™ì‹ì˜)ì„ ì´ìš©í•œ 차량 단위와 ì—°ê²°ëœ íŠ¸ë ˆì¼ëŸ¬/ê°ì°¨ë¡œ 구성ë˜ì—ˆìŠµë‹ˆë‹¤.
ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì˜ˆì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤: 마차를 ë„는 ë§ì˜ 무리; ë˜ëŠ” 탄수차가 ì—°ê²°ëœ ê¸°ê´€ì°¨ì™€ ê°ì°¨; ë˜ëŠ” 버스; ë˜ëŠ” ë°´; ë˜ëŠ” 트레ì¼ëŸ¬ê°€ ì—°ê²°ëœ íŠ¸ëŸ­; ë˜ëŠ” ì—°ê²°ëœ ë…¸ë©´ì „ì°¨; ë˜ëŠ” ë°°; ë˜ëŠ” ë°”ì§€ì„ ì„ ë„는 예ì¸ì„ ; ë˜ëŠ” 항공기.
ìˆ˜ì†¡ìˆ˜ë‹¨ì€ ìˆ˜ì†¡ ìœ í˜•ì— ë”°ë¼ ì°¨ê³ ì—서 조립 ë° êµ¬ë§¤ë©ë‹ˆë‹¤.
{íŒ: ìˆ˜ì†¡ìˆ˜ë‹¨ì€ êµ¬ì„±ì— ìžˆì–´ì„œ 차량 ë‹¨ìœ„ì˜ ìˆ˜ì— ìµœëŒ€ 한ë„ê°€ 있습니다: 기차, 24대; ë„로 차량, 4대.}

ì ê²€ ë„구로 게임 보기ì—서 ìˆ˜ì†¡ìˆ˜ë‹¨ì„ í´ë¦­í•˜ê±°ë‚˜ 수송수단 정보를 열려면 차량 ëª©ë¡ ë˜ëŠ” ë¼ì¸ ê´€ë¦¬ì— ë‚˜ì—´ëœ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
수송수단 ì •ë³´ì˜ ì œëª© 바는 ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì´ë¦„ê³¼ 고유 ì•„ì´ë”” 번호를 ë³´ì—¬ì¤ë‹ˆë‹¤(ìžì„¸í•œ ë‚´ìš©ì€ ì•„ëž˜ë¥¼ 참고하십시오).
수송수단 ì •ë³´ì—는 ì´ë¦„ ìƒìžê°€ 있습니다; ìž‘ì€ ë³´ê¸°; ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ ì •ë³´; 옵션 버튼; 현재 ìš´ë°˜ëœ ëª¨ë“  í•­ëª©ì˜ ëª©ë¡(만약 모든 í•­ëª©ì´ ë³´ì´ì§€ 않는다면 수송수단 정보를 재조정하거나 스í¬ë¡¤í•  수 있ë„ë¡ ìŠ¬ë¼ì´ë” 바를 사용하십시오).

수송수단 ì •ë³´ì˜ ë§¨ ìœ„ì— í‘œì‹œëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤:

ë‚´ë¶€ ì•„ì´ë””: ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ 고유 ì•„ì´ë”” 번호(ìˆ˜ì†¡ìˆ˜ë‹¨ì´ ì°¨ê³ ì—서 ì²˜ìŒ ë§¤ìž…ë˜ê±°ë‚˜ 조립ë˜ì—ˆì„ 때 기본ì ìœ¼ë¡œ 할당ë©ë‹ˆë‹¤).

- ì´ë¦„: ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ í• ë‹¹ëœ ì´ë¦„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤(기본ì ìœ¼ë¡œ ì´ê²ƒì€ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ìœ„í•œ 차고ì—서 매입 ë˜ëŠ” ì¡°ë¦½ëœ ìµœì´ˆì˜ ì°¨ëŸ‰ 단위입니다).
ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì´ë¦„ì„ ë³€ê²½í•˜ë ¤ë©´ ì´ë¦„ ìƒìžë¥¼ í´ë¦­í•˜ê³  새로운 ì´ë¦„ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤.

- ì†ë„: 현재 ì†ë„는 km/h로 표시ë©ë‹ˆë‹¤.
ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ìµœëŒ€ 가능 ì†ë„는 괄호 ì•ˆì— í‘œì‹œë©ë‹ˆë‹¤(수송수단ì—서 가장 ëŠë¦° 차량 ë‹¨ìœ„ì— ì˜í•´ ê²°ì •ë©ë‹ˆë‹¤).
ì´ˆë¡ìƒ‰ ì§„í–‰ 바는 최대 ì†ë„와 관련하여 현재 ì†ë„를 나타냅니다.

- 수입: 현재 ê²Œìž„ì˜ ì¼ì •ì˜ ì—°ë„ì—서 차량(수입으로 ì¸í•´ ìš´ì˜ ë¹„ìš©ì´ ê°ì†Œ)ì— ì˜í•´ 만들어진 수ìµ.
게임 당 Hajo Creditì— í¬í•¨ëœ ìš´ì†¡ìˆ˜ë‹¨ì˜ ìš´ì˜ ë¹„ìš©ì€ ê´„í˜¸ ì•ˆì— í‘œì‹œë©ë‹ˆë‹¤.

- 중량: ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ í˜„ìž¬ í•©ì‚°ëœ ì¤‘ëŸ‰ê³¼ ìˆ˜ì†¡ìˆ˜ë‹¨ì— ì˜í•´ ìš´ë°˜ëœ í•­ëª©(톤).
ìš´ë°˜ëœ í•­ëª©ì˜ í˜„ìž¬ ì¤‘ëŸ‰ì€ ê´„í˜¸ ì•ˆì— í‘œì‹œë©ë‹ˆë‹¤.
ì´ˆë¡ìƒ‰ ì§„í–‰ 바는 화물 ë° ìŠ¹ê°ì„ 운반하는 ë° ì‚¬ìš©ëœ ìš©ëŸ‰ì˜ ë¹„ìœ¨ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
노란색 바는 ì¼ì • ê´€ë¦¬ì— ì„¤ì •ëœ ëŒ€ê¸° 레벨(ìš´ì†¡ìˆ˜ë‹¨ì´ ì§„í–‰í•˜ëŠ”ë° í•„ìš”í•œ 화물 ë° ìŠ¹ê°ì˜ 최소량)ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
{íŒ: ë¼ì¸ì˜ 모든 ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ 대기 ë ˆë²¨ì„ ì„¤ì •í•˜ê±°ë‚˜ 변경하려면 ë¼ì¸ 관리 ë˜ëŠ” 차고 관리ì—서 ë¼ì¸ ì—…ë°ì´íЏ 옵션 ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. ìˆ˜ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ 대기 레벨 ë° í• ë‹¹ëœ ë¼ì¸ì— 다른 ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ì„¤ì •í•˜ê±°ë‚˜ 변경하려면 수송수단 ì •ë³´ ë˜ëŠ” 차고 관리ì—서 ì¼ì • 옵션 ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤.}

- 목ì ì§€: ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì¼ì •ì— ìžˆëŠ” ë‹¤ìŒ ì •ê±°ìž¥ ë˜ëŠ” 경유지.
ì´ˆë¡ìƒ‰ ì§„í–‰ 바는 ë‹¤ìŒ ëª©ì ì§€ê¹Œì§€ì— 대한 ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì§„í–‰ ìƒí™©ì„ 나타냅니다.

- 서브 ë¼ì¸: ì´ ìˆ˜ì†¡ìˆ˜ë‹¨ì— í• ë‹¹ëœ ë…¸ì„ . 삼ê°í˜•ì€ ë…¸ì„  관리창ì—서 ë¼ì¸ì„ 엽니다. (ë…¸ì„ ì´ í• ë‹¹ëœ ê²½ìš°ì—ë§Œ ë³¼ 수 있습니다.)

- ìž‘ì€ ë³´ê¸°ëŠ” ì´ëŸ¬í•œ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ì´ ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ê²Œìž„ 보기를 ì¤‘ì•™ì— ë°°ì¹˜í•˜ë ¤ë©´ ìž‘ì€ ë³´ê¸°ë¥¼ í´ë¦­í•˜ì‹­ì‹œì˜¤.

관리 ì°½ì„ ì—´ê±°ë‚˜ ì˜µì…˜ì„ ì„ íƒí•˜ë ¤ë©´ 수송수단 ì •ë³´ì˜ ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤:

ì¼ì •: 경로와 ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ ì§„í–‰ì— í•„ìš”í•œ 화물 ë° ìŠ¹ê°ì˜ ìµœì†ŒëŸ‰ì„ ë³€ê²½í•˜ë ¤ë©´ 관리 ì°½ì„ ì—½ë‹ˆë‹¤.

차고로 수송: ìˆ˜ì†¡ìˆ˜ë‹¨ì„ ê°€ìž¥ 가까우면서 ì ì ˆí•œ ì°¨ê³ ì— ë³´ëƒ…ë‹ˆë‹¤. 차고로 수송하는 ë°ì— 대한 ìˆ˜ìž…ì€ ì–»ê²Œë˜ì§€ë§Œ ìš´ë°˜ë˜ëŠ” 모든 í•­ëª©ì€ ë¶„ì‹¤ë©ë‹ˆë‹¤.
차고ì—서 ìˆ˜ì†¡ìˆ˜ë‹¨ì€ ì¼ì •ê³¼ í• ë‹¹ëœ ë¼ì¸ì„ 유지합니다.

다ìŒì„ ë”°ë¼í•˜ì‹­ì‹œì˜¤: 들여쓰기ëì„ ë•Œ ë²„íŠ¼ì€ ìˆ˜ì†¡ìˆ˜ë‹¨ê³¼ 함께 게임 보기로 ì´ë™í•©ë‹ˆë‹¤.
ì´ ì˜µì…˜ì˜ ì„ íƒì„ 취소하려면, ë²„íŠ¼ì„ ë‹¤ì‹œ í´ë¦­í•˜ê±°ë‚˜ ë©”ì¸ ì§€ë„ ìƒì—서 왼쪽 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

차트: 수송수단 ì •ë³´ì—서 그래프(ë²„íŠ¼ì€ ê·¸ëž˜í”„ê°€ ë³´ì´ë©´ 들여쓰기ë©ë‹ˆë‹¤)를 전환하려면 옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
그래프는 그래프 ì˜µì…˜ì´ ì„ íƒë˜ì—ˆì„ 때 지난 12개월(xì¶•)ì— ëŒ€í•œ 통계를 ë³´ì—¬ì¤ë‹ˆë‹¤.
그래프ì—서 ì„ íƒëœ 정보를 보려면 그래프 옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤(ë²„íŠ¼ì€ ì˜µì…˜ì´ ì„ íƒë˜ë©´ 들여쓰기ë©ë‹ˆë‹¤).
그래프ì—서 ë¼ì¸ì˜ 색ìƒì€ 그래프 옵션 ë²„íŠ¼ì˜ ìƒ‰ìƒê³¼ ì¼ì¹˜í•©ë‹ˆë‹¤:
- 여유 ìš©ëŸ‰ì€ ìˆ˜ì†¡ìˆ˜ë‹¨ì—서 미사용 ê³µê°„ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
- ìš´ì†¡ëŸ‰ì€ í™”ë¬¼, ìŠ¹ê° ë° ìš´ë°˜ëœ ìš°íŽ¸ì˜ ìˆ˜ë¥¼ 나타냅니다.
- ì´ìµì€ ìˆ˜ì†¡ì— ì˜í•´ ìƒì„±ëœ ìˆ˜ìž…ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
- ìš´ì˜ ë¹„ìš©ì€ ìˆ˜ì†¡ ì¤‘ì— ìˆ˜ì†¡ìˆ˜ë‹¨ì— ì˜í•´ ë°œìƒí•˜ëŠ” ë¹„ìš©ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
- 수ìµì€ 수송으로 ì–»ì€ ìˆ˜ìµì„ 나타냅니다 (ìš´ì˜ ë¹„ìš© ê°ì†Œ).

세부 ì‚¬í•­ì€ ì¦‰ì‹œ ìˆ˜ì†¡ìˆ˜ë‹¨ì„ íŒë§¤í•˜ëŠ” 옵션과 추가 ì •ë³´ê°€ í¬í•¨ëœ 수송수단 ì„¸ë¶€ì‚¬í•­ì„ ì—½ë‹ˆë‹¤.

승ê°/ 화물 ì •ë ¬ 기준: ìˆ˜ì†¡ìˆ˜ë‹¨ì— ì˜í•´ 현재 ìš´ë°˜ëœ í•­ëª©ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
í‘œì‹œëœ ì •ë³´ì—는 ìš´ë°˜ëœ ì–‘, ìˆ˜ì†¡ìˆ˜ë‹¨ì˜ í•œë„, í•­ëª©ì˜ ìœ í˜•, 최종 목ì ì§€ ë° ë‹¤ìŒ í™˜ìŠ¹ ì •ê±°ìž¥ì´ í¬í•¨ë©ë‹ˆë‹¤.
옵션 버튼(ì„ íƒì— ë”°ë¼ ì´ë¦„ì´ ë³€ê²½ë©ë‹ˆë‹¤)ì€ ìš´ë°˜ëœ í•­ëª©(승ê°, 우편 ë° í™”ë¬¼)ì˜ ëª©ë¡ì„ 정렬합니다:
- 목ì ì§€: ASCII 코드 ìˆœì„œì— ë”°ë¼ ì•ŒíŒŒë²³ 순으로, 최종 목ì ì§€ ì •ê±°ìž¥ì˜ í• ë‹¹ëœ ì´ë¦„ì— ë”°ë¼ í•­ëª©ì„ ì •ë ¬í•©ë‹ˆë‹¤ (ì†Œë¬¸ìž ì•žì˜ ëŒ€ë¬¸ìž).
- 경유 (세부 사항): ASCII 코드 ìˆœì„œì— ë”°ë¼ ì•ŒíŒŒë²³ 순으로, 첫번째 환승 ì •ê±°ìž¥ì˜ í• ë‹¹ëœ ì´ë¦„ì— ë”°ë¼ ìš´ë°˜ëœ í•­ëª©ì„ ì •ë ¬í•©ë‹ˆë‹¤ (ì†Œë¬¸ìž ì•žì˜ ëŒ€ë¬¸ìž).
- 경유 (수량): 첫번째 환승 정거장으로 향하는 ìˆ˜ëŸ‰ì— ë”°ë¼ ìš´ë°˜ëœ í•­ëª©ì„ ì •ë ¬í•©ë‹ˆë‹¤.
- 수량: 내림차순으로 ìˆ˜ëŸ‰ì— ë”°ë¼ ìš´ë°˜ëœ í•­ëª©ì„ ì •ë ¬í•©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/curiosity_build.txt000066400000000000000000000045021474050137200231500ustar00rootroot00000000000000매력ì ì¸ 건물 건설

매력ì ì¸ 건물 건설

다ì´ì–¼ë¡œê·¸ëŠ” 4ê°œì˜ ë¶€ë¶„ìœ¼ë¡œ 나뉩니다.
- 왼쪽 ìƒë‹¨ì€ 사용 가능한 ê±´ë¬¼ì˜ ì„ íƒ ëª©ë¡ìž…니다
- 왼쪽 í•˜ë‹¨ì€ ì„ íƒëœ ê±´ë¬¼ì˜ ì‚¬ì§„ì´ í‘œì‹œë©ë‹ˆë‹¤
- 오른쪽 ìƒë‹¨ì€ 몇 가지 ì˜µì…˜ì„ ì„¤ì •í•  수 있습니다
- 오른쪽 í•˜ë‹¨ì€ ì„ íƒëœ ë„시 ê±´ë¬¼ì— ëŒ€í•œ 정보입니다

ì„ íƒ ëª©ë¡

ì„ íƒ ëª©ë¡ì—는 오른쪽 ìƒë‹¨ì— ëª…ì‹œëœ ì˜µì…˜ìœ¼ë¡œ 사용 가능한 모든 특수 건물과 랜드마í¬ê°€ 제공ë©ë‹ˆë‹¤. (ë„시 명소, 육지 명소, 기ë…물). 매력ì ì¸ ê±´ë¬¼ì„ ì‹ë³„하는 ë°©ë²•ì„ ë³€ê²½í•  수 있는 2ê°œì˜ íƒ­ì´ ìžˆìŠµë‹ˆë‹¤.
- 번역: 주어진 언어로 ê±´ë¬¼ì˜ ì´ë¦„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 만약 주어진 언어ì—서 번역할 수 없으면, ê°ì²´ ì´ë¦„ì´ ì‚¬ìš©ë©ë‹ˆë‹¤.
- ê°ì²´: 건물 ìœ í˜•ì— ëŒ€í•œ Simutrans ë‚´ë¶€ ê°ì²´ ì´ë¦„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.

í…ìŠ¤íŠ¸ì˜ ìƒ‰ìƒì€ 다ìŒê³¼ ê°™ì€ ì˜ë¯¸ë¥¼ 가집니다:
- 파란색 í…스트 명소는 ë„ì‹œì— ê±´ì„¤ë˜ì–´ì•¼ 합니다
- ì´ˆë¡ìƒ‰ í…스트 명소는 ì‹œê³¨ì— ê±´ì„¤ë˜ì–´ì•¼ 합니다
- 검정색 í…스트 기ë…물: 한 번만 건설할 수 있습니다

옵션

- 기후를 무시: ì´ ì˜µì…˜ì€ ë‹¤ì–‘í•œ 건물 유형과 ê´€ë ¨ëœ ê¸°í›„ ì œí•œì„ ë¹„í™œì„±í™”í•©ë‹ˆë‹¤.
- 타임ë¼ì¸ ì—°ë„ ì‚¬ìš©: ì„ íƒ ëª©ë¡ì—는 현재 Simutrans ì—°ë„ì—서 사용할 수 있는 건물만 í¬í•¨ë©ë‹ˆë‹¤.
- 쓸모없는 ë¶€ë¶„ë„ í‘œì‹œ: 현재 simutrans ì—°ë„ì—서 쓸모없는 ê±´ë¬¼ë„ í¬í•¨í•˜ë ¤ë©´ ì„ íƒ ëª©ë¡ì„ 확장하십시오.
- ë„시 명소: ì„ íƒ ëª©ë¡ì— ë„시 명소가 있습니다.
- 육지 명소: ì„ íƒ ëª©ë¡ì— 육지 명소가 있습니다.
- 기ë…물: ì„ íƒ ëª©ë¡ì— 기ë…ë¬¼ì´ ìžˆìŠµë‹ˆë‹¤.
- 회전: ì„ íƒí•œ ê±´ë¬¼ì„ ë‹¤ë¥¸ ê°ë„ì—서 ë³¼ 수 있다면, 여기ì—서 특정한 보기를 ì„ íƒí•  수 있습니다. ì´ê²ƒì„ ë°˜ì˜í•˜ê¸° 위해 왼쪽 í•˜ë‹¨ì˜ ì´ë¯¸ì§€ê°€ 변경ë©ë‹ˆë‹¤. 만약 ì´ ì˜µì…˜ì„ ìž„ì˜ë¡œ 설정한다면 ê±´ë¬¼ì˜ ìž„ì˜ ë³´ê¸°ê°€ 사용ë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/curiositylist_filter.txt000066400000000000000000000046661474050137200242450ustar00rootroot00000000000000명소 목ë¡

명소 목ë¡

명소 목ë¡ì—는 승ê°ê³¼ ìš°íŽ¸ì˜ ëª©ì ì§€ ë° ì¶œë°œì§€ì¸ ëª¨ë“  관광 ëª…ì†Œì— ëŒ€í•œ ì •ë³´ê°€ 있습니다.

명소 목ë¡ì„ 열려면: ëª©ë¡ ê´€ë¦¬ì—서 명소 ëª©ë¡ ë„구를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 만약 목ë¡ì— 있는 í•­ëª©ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ 표시ëœë‹¤ë©´ 슬ë¼ì´ë” 바를 사용해서 명소 ëª©ë¡ ë˜ëŠ” 스í¬ë¡¤ 목ë¡ì„ 재조정하십시오.}

ì •ë ¬ 기준: í‘œì‹œëœ ê´€ê´‘ ëª…ì†Œì˜ ìˆœì„œë¥¼ ê²°ì •í•  수 있는 ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤.
ì˜µì…˜ì„ í†µí•´ 순환하려면 ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (옵션 ë²„íŠ¼ì˜ ì´ë¦„ì„ ë³€ê²½í•©ë‹ˆë‹¤):

- ì´ë¦„ 알파벳 ìˆœì„œì— ì˜í•œ ì´ë¦„ 순서.
- ìŠ¹ê° ìˆ˜ì¤€ 승ê°ê³¼ ìš°íŽ¸ì— ëŒ€í•œ 목ì ì§€ë¡œì„œ ìƒëŒ€ì  ì¸ê¸° 순서.

- 오름차순 / 내림차순 목ë¡ì˜ 순서를 뒤집습니다.

해당 관광 ëª…ì†Œì— ëŒ€í•œ ìžì„¸í•œ 정보를 보려면 명소 목ë¡ì— ë‚˜ì—´ëœ í•­ëª©ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 해당 명소로 게임 보기를 ì´ë™í•˜ë ¤ë©´ ìžì„¸í•œ ì •ë³´ì—서 관광 ëª…ì†Œì˜ ì‚¬ì§„ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.}

ê° ê´€ê´‘ ëª…ì†Œì— ëŒ€í•´ ë‚˜ì—´ëœ í•­ëª©ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤:

색ìƒ-ìƒíƒœ ë°” 색ìƒì€ ëª…ì†Œì˜ ìƒíƒœë¥¼ 나타냅니다:
- 노란색: 정거장(ì—­)ì˜ í†µí–‰ 가능 지역ì—서 내릴 수 없습니다.
- ì´ˆë¡ìƒ‰: 승ê°ì— 대한 정거장과 ì—°ê´€ë습니다.
- 파란색: ìš°íŽ¸ì— ëŒ€í•œ 정거장과 ì—°ê´€ë습니다.
- ì²­ë¡ìƒ‰: 승ê°ê³¼ ìš°íŽ¸ì— ëŒ€í•œ 정거장과 ì—°ê´€ë습니다.
- 주황색: ì—°ê´€ëœ ì •ê±°ìž¥ì€ í˜¼ìž¡í•©ë‹ˆë‹¤.
- 빨간색: 모든 ì—°ê´€ëœ ì •ê±°ìž¥ì€ í˜¼ìž¡í•©ë‹ˆë‹¤.

건물 ê·¸ëž˜í”½ì€ ê·¸ ê³³ì´ ë„시 명소ì¸ì§€ë¥¼ 나타냅니다.

관광 ëª…ì†Œì˜ ì´ë¦„

대괄호 ì•ˆì— ìŠ¹ê° ë ˆë²¨ì€ ìŠ¹ê°ê³¼ ìš°íŽ¸ì— ëŒ€í•œ 목ì ì§€ë¡œì„œì˜ ìƒëŒ€ì  ì¸ê¸°ë¥¼ 나타내는 값입니다.

{íŒ: 최ì ì˜ 서비스를 제공하기 위해서 ì „ì²´ 관광 명소는 하나 ë˜ëŠ” 여러 ê°œì˜ ì •ê±°ìž¥ì˜ í†µí–‰ 가능 ì§€ì—­ì— ìžˆì–´ì•¼ 합니다.}

simutrans-124.3/simutrans/text/ko/depot.txt000066400000000000000000000115231474050137200210530ustar00rootroot00000000000000차고지, 차량기지, 조선소, 격납고 ë„움ë§

차고지

* ì´í•˜ 차고지로 통ì¼í•˜ì—¬ 서술합니다.

차고지ì—서는 ì°¨ëŸ‰ì„ êµ¬ìž…í•˜ê±°ë‚˜ 관리할 수 있습니다. 서로다른 운송수단마다 ê°ìž 차고지가 있습니다. 전기 ì² ë„ ì°¨ëŸ‰ì˜ ê²½ìš°ì—는 ì „ê¸°ì² ë„ ì°¨ê³ ì§€ì—서만 나타납니다. 차고지는 ê° ìš´ì†¡ìˆ˜ë‹¨ 툴바ì—서 ì°¾ì„ ìˆ˜ 있으며, 순서대로 ì² ë„ ì°¨ëŸ‰ê¸°ì§€, ëª¨ë…¸ë ˆì¼ ì°¨ëŸ‰ê¸°ì§€, 트램 차량기지, ë„로 차고지, ì„ ë°• 정박소, 비행기 격납고입니다. ë˜í•œ, 타임ë¼ì¸ ì‹œìž‘ë…„ë„ ì„¤ì •ì„ í™œì„±í™”í•œ 경우, ì°¨ëŸ‰ì˜ ë“±ìž¥ë…„ë„ê°€ ë˜ê¸° ì „ì—는 ì°¨ëŸ‰ì´ ë‚˜íƒ€ë‚˜ì§€ 않습니다.

게임 ì°½ì—서 조사 ë„구로 차고지를 í´ë¦­í•˜ë©´, 차고지 관리 ì°½ì´ ëœ¨ë©°, 여기서 ì°¨ëŸ‰ë“¤ì˜ ì •ë³´ë¥¼ 얻거나, 구입, 관리할 수 있습니다.
타ì´í‹€ 바는 ì´ ì°¨ê³ ì§€ê°€ ì–´ëŠ ì¢…ë¥˜ì˜ ìš´ì†¡ìˆ˜ë‹¨ 것ì¸ì§€ë¥¼ 알려ì¤ë‹ˆë‹¤.
차고지 관리 ì°½ì€ í¬ê¸°ë¥¼ 조절할 수 있으며, 타ì´í‹€ë°”ì˜ ì•„ëž˜ìª½ ë°©í–¥ 화살표를 누르면 ì›ëž˜ í¬ê¸°ë¡œ ëŒì•„갑니다.
타ì´í‹€ë°”ì˜ ì™¼ìª½/오른쪽 화살표를 누르면, ê°™ì€ ì¢…ë¥˜ì˜, 다른 차고지로 ê°ˆ 수 있습니다.

차고지 관리 ì°½ 윗 부분ì—는 다ìŒê³¼ ê°™ì€ ì •ë³´ê°€ 나타납니디.

차량 X 중 Y : ì°¨ê³ ì§€ì— ìœ ì¹˜ëœ ì°¨ëŸ‰ 중 현재 차량(편성)ì˜ ìˆœë²ˆì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
차량 ì´ë¦„: ì˜†ì˜ ì™¼ìª½/오른쪽 화살표를 누르면, ì´ ì°¨ëŸ‰ì˜ ì•ž/ë’¤ 차량으로 ì´ë™í•©ë‹ˆë‹¤. ì´ë¦„ ìƒìžë¥¼ 눌러 ì°¨ëŸ‰ì˜ ì´ë¦„ì„ ë°”ê¿€ 수 있습니다.
노선 ì´ë¦„: ì˜†ì˜ ì™¼ìª½/오른쪽 화살표를 눌러, ì°¨ëŸ‰ì˜ ë…¸ì„ ì„ ë°”ê¿€ 수 있습니다. ë˜í•œ ìƒìžë¥¼ 누르면, 노선들 목ë¡ì´ 뜹니다. 노선 ì´ë¦„ì„ ë°”ê¾¸ëŠ” ë°©ë²•ì€ ì°¨ëŸ‰ ì´ë¦„ì„ ë°”ê¾¸ëŠ” 것과 같습니다.
차량 그림: 차량 그림 ìœ„ì— ë§ˆìš°ìŠ¤ë¥¼ 갖다대면, 해당 차량(1량)ì˜ ì •ë³´ê°€ 뜹니다. ê·¸ë¦¼ì„ ëˆ„ë¥´ë©´, ê·¸ 차량(1량)ì´ ì°¨ëŸ‰ 묶ìŒì—서 빠집니다.

(번역중) ê·¸ 아래ì—는, íŽ¸ì„±ì¤‘ì˜ ì—´ì°¨ë¥¼ 조작하기 위한 다ìŒì˜ ë²„íŠ¼ì´ ìžˆìŠµë‹ˆë‹¤.

스타트 - íŽ¸ì„±ì¤‘ì˜ ì—´ì°¨ì˜ ìš´í–‰ì„ ê°œì‹œí•©ë‹ˆë‹¤.ìš´í–‰ì„ ê°œì‹œí•˜ê¸° 위해서는,
ë¯¸ë¦¬ìŠ¤ì¼€ì¤„ì´ ì„¤ì •ë˜ì–´ 있지 않으면 안ë©ë‹ˆë‹¤.
편성 í•´ì œ - í˜„ìž¬ì˜ íŽ¸ì„±ì„ í•´ì²´í•©ë‹ˆë‹¤.í•´ì²´ëœ íŽ¸ì„±ì˜ ì°¨ëŸ‰ì€ ìŠ¤í†¡ ë˜ì–´
다른 íŽ¸ì„±ì— ì§œë„£ì„ ìˆ˜ 있습니다.
ë§¤ê° - í˜„ìž¬ì˜ íŽ¸ì„±ì„ êµ¬ì„±í•´ 있는 ì°¨ëŸ‰ì„ ëª¨ë‘ ë§¤ê°í•©ë‹ˆë‹¤.í˜„ìž¬ì˜ ë§¤ê° ê°€ê²©ì€
ã€Œë§¤ê° ê°€ê²©ã€ì— 나타나고 있어 êµ¬ìž…ì‹œë¶€í„°ì˜ ì‹œê°„ì˜ ê²½ê³¼ì— ìˆ˜ë°˜í•´ ê°ì†Œí•´ ê°ˆ 것입니다.

 다ì´ì–¼ë¡œê·¸ì˜ 중단 부분ì—는, 구입할 수 있는 ì°¨ëŸ‰ì˜ ì¼ëžŒì´ 표시ë˜ê³  있습니다.ì°¨ëŸ‰ì€ ê¸°ê´€
차와 ê°ì°¨Â·í™”차로 나누어져 있어 「기관차ã€íƒ­, 「화차·ê°ì°¨ã€íƒ­ìœ¼ë¡œ 표시를 완전히 êµì²´ë˜ì–´
ì–»ì„ ìˆ˜ 있습니다.ì°¨ëŸ‰ì˜ í™”ìƒì— 마우스 커서를 거듭하면, ê·¸ ì°¨ëŸ‰ì˜ ì •ë³´ê°€ 다ì´ì–¼ë¡œê·¸í•˜
ë¶€ì— í‘œì‹œë©ë‹ˆë‹¤.í´ë¦­í•˜ë©´, ê·¸ ì°¨ëŸ‰ì„ êµ¬ìž…í•´, í˜„ìž¬ì˜ íŽ¸ì„±ì— ì§œë„£ìŠµë‹ˆë‹¤.

ã€€ê° ì°¨ëŸ‰ì•„ëž˜ì— ìžˆëŠ” ìƒ‰ì²¨ë¶€ì˜ ë°”ëŠ”, ê·¸ ì°¨ëŸ‰ì„ í˜„ìž¬ì˜ íŽ¸ì„±ì— ì§œë„£ëŠ” 것ì´
í•  수 있ì„지를 나타내고 있습니다.ì´ˆë¡ì˜ 차량ì€, í˜„ìž¬ì˜ íŽ¸ì„±ì— ì§œë„£ëŠ” ê²ƒì´ ì¶œ
옵니다.ë¹¨ê°•ì˜ ì°¨ëŸ‰ì€, í˜„ìž¬ì˜ íŽ¸ì„±ì—는 ì§œë„£ì„ ìˆ˜ 없습니다.ì´ˆë¡ê³¼ 황색ì˜
ì„žì¸ ì°¨ëŸ‰ì€, í˜„ìž¬ì˜ íŽ¸ì„±ì— ì§œë„£ì„ ìˆ˜ 있습니다만, ê·¸ íŽ¸ì„±ì„ ì™„ì„±í•¨
다투기 위해서는, 한층 ë” ë‹¤ë¥¸ ì°¨ëŸ‰ì„ êµ¬ìž…í•˜ì§€ 않으면 안 ë˜ëŠ” ê²ƒì„ ë‚˜íƒ€ë‚´ ë³´ì´ê³  있습니다.
후부 기관차가 필요한 열차등ì´, ì´ í‘œì‹œê°€ ë©ë‹ˆë‹¤.

ã€€ì°¨ëŸ‰ì˜ ì¢Œìƒì— 있는 숫ìžëŠ”, ê·¸ ì°¨ëŸ‰ì˜ ìŠ¤í†¡ì´ ìžˆëŠ” ê²ƒì„ ë‚˜íƒ€ë‚´ê³  있습니다.
ìŠ¤í†¡ì´ ìžˆëŠ” 차량ì€, í´ë¦­í•˜ëŠ” 것으로 í˜„ìž¬ì˜ íŽ¸ì„±ì— ì§œë„£ëŠ” ê²ƒì´ ì„±ê³¼
.

ã€€ìš°ì¸¡ì— ìžˆëŠ” 「차량ã€ë²„튼ì—서는, 구입한 ì°¨ëŸ‰ì„ í˜„ìž¬ì˜ íŽ¸ì„±ì˜ ì–´ëŠ ìœ„ì¹˜ì— ì¡°
보는지 를 변경할 수 있습니다.「추가〠ìƒíƒœì—서는, í˜„ìž¬ì˜ íŽ¸ì„±ì˜ ìµœí›„ë¶€ì— ì¶”ê°€í•´
.「선ë‘ì—ã€ì—서는, í˜„ìž¬ì˜ íŽ¸ì„±ì˜ ì„ ë‘ì— ì§œë„£ìŠµë‹ˆë‹¤.「매ê°ã€ì—서는, ì°¨
ì–‘ì˜ êµ¬ìž…ì´ ì•„ë‹ˆê³ , 스톡 ë˜ê³  있는 ì°¨ëŸ‰ì˜ ë§¤ê° ëª¨ë“œê°€ ë©ë‹ˆë‹¤

simutrans-124.3/simutrans/text/ko/display.txt000066400000000000000000000123001474050137200213770ustar00rootroot00000000000000ë””ìŠ¤í”Œë ˆì´ ì„¤ì • ë„움ë§

ë””ìŠ¤í”Œë ˆì´ ì„¤ì •

ë””ìŠ¤í”Œë ˆì´ ì„¤ì •ì—서는 ê²Œìž„ì´ ë³´ì—¬ì§€ëŠ” ë°©ì‹ê³¼ 정보를 제공하는 ë°©ì‹ì„ ì¡°ì •í•  수 있습니다.

ë””ìŠ¤í”Œë ˆì´ ì„¤ì •ì€ ê²Œìž„ ì˜µì…˜ì˜ ë””ìŠ¤í”Œë ˆì´ ë²„íŠ¼ì„ ëˆ„ë¥´ë©´ 들어갈 수 있습니다. 옵션 버튼 ì™¼ìª½ì˜ ë„¤ëª¨ 버튼ì´ë‚˜ 화살표 버튼으로 조절할 수 있습니다.:

ê²©ìž ë³´ì´ê¸°: 게임 화면ì—서 격ìžê°€ 나타납니다. ([#]ìœ¼ë¡œë„ ê°€ëŠ¥í•©ë‹ˆë‹¤.)
지하 시ì : 지하를 ë³¼ 수 있습니다. ì´ë¥¼ ì´ìš©í•˜ì—¬ í„°ë„ì´ë‚˜ 지하철ë„를 건설할 수 있습니다. ([Shift+U]ë¡œë„ ê°€ëŠ¥í•©ë‹ˆë‹¤.)
층 시ì : 오른쪽 숫ìžë§Œí¼ì— 해당하는 높ì´ë¡œ ì§€ë„를 잘ë¼ì„œ ë³´ì—¬ì¤ë‹ˆë‹¤. ([Crtl] + [u]ë¡œë„ ê°€ëŠ¥í•©ë‹ˆë‹¤. ì´ ë•Œ [-]나 [+]를 누르면 층 높ì´ê°€ 변합니다.)
ë‚®/ë°¤ 변화: 활성화하면 ì‹œê°„ì— ë”°ë¼ ë‚®/ë°¤ì´ ë³€í•©ë‹ˆë‹¤.
ë°ê¸°: 게임 í™”ë©´ì˜ ë°ê¸°ë¥¼ 설정합니다. ê°’ì´ ë‚®ì•„ì§€ë©´ ì–´ë‘워지며, 너무 낮거나 ë†’ì€ ê°’ì€ ë¬¸ì œë¥¼ ì¼ìœ¼í‚¬ 수 있습니다.
ì—­ë°©í–¥ 스í¬ë¡¤: 활성화하면 게임 화면ì—서 스í¬ë¡¤ ë°©í–¥ì´ ë°˜ëŒ€ê°€ ë©ë‹ˆë‹¤. 예를 들면, 오른쪽으로 마우스를 드래그하면, 게임 í™”ë©´ì´ ì™¼ìª½ìœ¼ë¡œ 움ì§ìž…니다.
스í¬ë¡¤ ì†ë„: 게임 화면ì—ì„œì˜ ìŠ¤í¬ë¡¤ ì†ë„를 정합니다. ê°’ì´ í´ìˆ˜ë¡, 스í¬ë¡¤ì´ 빨리 ë©ë‹ˆë‹¤.

반투명 모드: 활성화 하면 나무나 ê±´ë¬¼ì´ ìž‘ì•„ì§€ì§€ 않고 반투명하게 보입니다. 아래 ë‘ ì„¤ì •ì— ì˜í–¥ì„ 미칩니다.
- 나무 최소화: 나무를 작게 ë³´ì´ê²Œ 합니다. 반투명 모드가 활성화ë˜ë©´ 반투명하게 보입니다.
- 건물 디스플레ì´: ì–´ë–¤ ê±´ë¬¼ì„ ìž‘ê²Œ ë³´ì´ê²Œí• ì§€ë¥¼ 고를 수 있습니다.
- - ê±´ë¬¼ì„ ìˆ¨ê¸°ì§€ 않ìŒ: 모든 ê±´ë¬¼ì´ ë³´ìž…ë‹ˆë‹¤.
- - ë„시건물 숨기기: ë„시 ê±´ë¬¼ë§Œì„ ìž‘ê²Œ ë³´ì´ê²Œ 합니다. 반투명 모드가 활성화ë˜ë©´ 반투명하게 보입니다.
- - 모든 건물 숨기기: 모든 ê±´ë¬¼ì„ ìµœìž‘ê²Œ ë³´ì´ê²Œ 합니다. 반투명 모드가 활성화ë˜ë©´ 반투명하게 보입니다.
- í¬ì¸í„° 주변 숨기기: 활성화 하면 오른쪽 숫ìžë§Œí¼ì˜ ì˜ì—­ ì•ˆì˜ ë‚˜ë¬´ì™€ ê±´ë¬¼ì„ ìž‘ê²Œ ë³´ì´ê²Œ 합니다. 반투명 모드가 활성화ë˜ë©´ 반투명하게 보입니다.

ì—­ì˜ ìŠ¹ê° ìœ ì¹˜ 범위: 잘 모르겠습니다;;
역세권: 역세권 ì•ˆì— ìžˆëŠ” 건물ì—서만 승ê°ì´ë‚˜ í™”ë¬¼ì„ ìˆ˜ì†¡í•  수 있으며, ì´ ì—­ì„¸ê¶Œì„ ê²Œìž„ í™”ë©´ì— ê° í”Œë ˆì´ì–´ 색ìƒìœ¼ë¡œ 나타나게 합니다.
ì—­ ì´ë¦„ 보기: 게임 í™”ë©´ì— ë‚˜íƒ€ë‚˜ëŠ” ì—­ ì´ë¦„ 표시 ë°©ì‹ì„ 바꾸는 것입니다.
대기 막대 보기: 활성화하면 ì—­ì—서 수송하지 못한 승ê°ì´ë‚˜ í™”ë¬¼ì˜ ì–‘ì„ ì—­ëª… ìœ„ì— ë§‰ëŒ€ê·¸ëž˜í”„ë¡œ 표시하게 합니다. ë§‰ëŒ€ê·¸ëž˜í”„ì˜ ìƒ‰ê¹”ì€ í™”ë¬¼(ë˜ëŠ” 승ê°)ì˜ ìƒ‰ê¹”ì„ ë”°ë¦…ë‹ˆë‹¤.

ë„ì‹œì˜ ë³´í–‰ìž: ë„ì‹œì§€ì—­ì— ë³´í–‰ìžê°€ 나타납니다.
ì—­ì˜ ë³´í–‰ìž: ì°¨ëŸ‰ì´ ì •ì°¨í•˜ëŠ” ì—­(정류장)ì— ë³´í–‰ìžê°€ 나타납니다.
êµí†µëŸ‰: ë„ì‹œì§€ì—­ì˜ ìžê°€ìš©ì˜ 수를 정합니다. ë„ì‹œì§€ì—­ì´ ì„±ìž¥í•˜ë©´ì„œ 새로 ìƒê¸°ëŠ” ìžê°€ìš©ì˜ 수는 ë„ì‹œì§€ì—­ì˜ í¬ê¸°ì™€ êµí†µëŸ‰ì— ì˜í•´ ê²°ì •ë©ë‹ˆë‹¤. êµí†µëŸ‰ ê°’ì´ ë†’ì„ìˆ˜ë¡ ìžê°€ìš©ì´ 많아지며, 0ì´ë¼ë©´ ìƒì„±ë˜ì§€ 않습니다.
{íŒ: simuconf.tabì—서 ë” ë§Žì€ ì˜µì…˜ê³¼ ê°’ì„ ë°”ê¿€ 수 있습니다.}
차량 툴íŒ: 설명 추가 예정
스케줄 강조: 설명 추가 예정

ë””ìŠ¤í”Œë ˆì´ ì •ë³´:

위 설정 아래ì—는 Simutrans를 실행할 ë•Œì˜ ì»´í“¨í„° ì„±ëŠ¥ì— ëŒ€í•œ ì •ë³´ê°€ 표시ë©ë‹ˆë‹¤.
숫ìžê°€ 하얀색ì´ë©´ 모든 ê²ƒì´ ì œëŒ€ë¡œ ëŒì•„가는 중입니다. 하지만 빨간색ì´ë‚˜ 노란색 숫ìžê°€ 있다면, ì„¤ì •ì„ ë³€ê²½í•  필요가 있습니다.
게임 ìƒì—서 ì‹œê°„ì´ í르거나 빨리ê°ê¸° ì¤‘ì¼ ë•Œì—는 ìˆ«ìž (ë˜ëŠ” 색깔)ì´ ë³€í•  수 있습니다.

프레임 시간: ì€ ë‘ í”„ë ˆìž„ 사ì´ì˜ 실제 ì‹œê°„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
대기: ë‘ í™”ë©´ ì—…ë°ì´íЏ 사ì´ì˜ 컴퓨터가 ì¼ì‹œì •ì§€ ëœ ì‹œê°„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
FPS: ê°’ì´ ë†’ì„ìˆ˜ë¡ ì°¨ëŸ‰ì´ ì¢€ ë” ë¶€ë“œëŸ½ê²Œ 움ì§ìž…니다. ìˆ«ìž ìƒ‰ê¹”ì´ ë¹¨ê°„ìƒ‰ì´ë¼ë©´, 컴퓨터가 매우 ëŠë¦¬ë‹¤ëŠ” ê²ƒì„ ì˜ë¯¸í•˜ë¯€ë¡œ, ì„¤ì •ì„ ë°”ê¾¸ì„¸ìš”. (게임 화면 í¬ê¸°ë¥¼ 한번 줄여보세요.)
Simloop: 초당 시뮬레ì´ì…˜ ë£¨í”„ì˜ ìˆ˜ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤. ìˆ«ìž ìƒ‰ê¹”ì´ ë¹¨ê°„ìƒ‰ì´ë¼ë©´, ë„ì‹œì§€ì—­ì´ ì ì€ 좀 ë” ìž‘ì€ ì§€ë„로 플레ì´í•˜ì„¸ìš”.

simutrans-124.3/simutrans/text/ko/edittools.txt000066400000000000000000000152601474050137200217500ustar00rootroot00000000000000게임 ë° ì§€ë„ íŽ¸ì§‘ ë„구 ë„움ë§

게임 ë° ì§€ë„ íŽ¸ì§‘ ë„구

게임 편집 ë„구는 현재 게임 세계를 추가로 ì‚¬ìš©ìž ì§€ì •í•  수 있ë„ë¡ í—ˆìš©í•©ë‹ˆë‹¤.
ë„구를 통해 다ìŒê³¼ ê°™ì´ í•  수 있습니다: ë„시 ì§€ì—­ì˜ ì¸êµ¬ë¥¼ 변화시킵니다; ë„ì‹œì˜ ë„로, 명소, 발전소 ë° ì‚°ì—…ë‹¨ì§€ë¥¼ 건설합니다; 다른 플레ì´ì–´ 회사로서 ìš´ì˜í•˜ê¸° 위한 ì˜µì…˜ì„ ì œê±°í•©ë‹ˆë‹¤; ê²Œìž„ì„ 1ë…„ì„ ì•žë‹¹ê¹ë‹ˆë‹¤.

공용 서비스 플레ì´ì–´ë¡œ ìž‘ë™í•˜ëŠ” ì˜µì…˜ì´ íŠ¹ìˆ˜ 건설 ë„구(ë˜ëŠ” 키 누르기 [P])ì˜ í”Œë ˆì´ì–´ ë˜ëŠ” P+ì—서 ì„ íƒë˜ë©´ ë„구 바가 열립니다. 플레ì´ì–´ë¥¼ 변경하는 ì˜µì…˜ì´ ë‹¤ì‹œ 사용ë˜ëŠ” 경우ì—ë„ ë„구 바는 열린 ìƒíƒœë¡œ 유지ë©ë‹ˆë‹¤.
ì¼ë¶€ ë„구 ì˜µì…˜ì— ëŒ€í•œ ì´ë¦„ ë° ìžì„¸í•œ 정보를 보려면 ë„구 옵션 (ë„구 바를 열거나 í´ë¦­í•œ 후) 위로 마우스 커서를 올리십시오.

ë„구 ì˜µì…˜ì€ ì™¼ìª½ì—서 오른쪽으로 다ìŒì„ í¬í•¨í•©ë‹ˆë‹¤:

ë„시 성장: ë„구는 ë„시 ì§€ì—­ì˜ ì¸êµ¬ë¥¼ 100명으로 늘리고 필요한 경우 새로운 ë„로와 ê±´ë¬¼ì„ ê±´ì„¤í•©ë‹ˆë‹¤.
사용하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  커서를 빨간색 위 화살표로 변경한 ë‹¤ìŒ ë„시 ì§€ì—­ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

ë„시 축소: ë„구는 ë„시 ì§€ì—­ì˜ ì¸êµ¬ë¥¼ 100으로 줄입니다. ë„시 ì§€ì—­ì€ ë…¸ìˆ™ìžì™€ ì‹¤ì—…ìž ìˆ˜ì˜ ë ˆë²¨ì´ ì¦ê°€í•˜ë©´ ê³„ì† ì„±ìž¥í•  것입니다.
사용하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  커서를 빨간색 아래 화살표로 변경한 ë‹¤ìŒ ë„시 ì§€ì—­ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

ë„시 ë„로: ë„구는 모든 플레ì´ì–´ê°€ 사용할 수 있는 공용 서비스 플레ì´ì–´ë¡œì„œ ë‘ ì§€ì  ì‚¬ì´ì— ë„시 ë„로를 건설합니다. ë„시 ë„로는 다른 ê±´ë¬¼ì´ ì°¨ì§€í•˜ëŠ” 지역ì—는 건설ë˜ì§€ ì•Šì„ ìˆ˜ 있으며 거친 지형, 물 ë° ìž¥ì• ë¬¼ì„ ê°€ë¡œ 지르는 경로를 찾지 못할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. ì§€ì  ì‚¬ì´ì— ê±´ì„¤ëœ ë„시 ë„로는 기존 ë„로를 경로로 사용할 수 있습니다.
공용 서비스 플레ì´ì–´ ì˜í•´ ë°œìƒëœ ì´ë¦„, 건설 ë° ìœ ì§€ 비용 그리고 최대 ì†ë„ 한ë„를 보려면 ë„구 옵션 (ë„구 바를 열거나 í´ë¦­í•œ 후) 위로 마우스 커서를 올리십시오. ë„시 ë„로를 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ (ë„시 ë„로로 커서를 변경합니다) 다ìŒ, ë„로 (게임 보기ì—서 불ë„저를 표시하고 게임 보기 아래 하단 ë°”ì˜ ì˜¤ë¥¸ìª½ì— ì§€ë„ ì¢Œí‘œë¥¼ 표시합니다)ì˜ ì‹œìž‘ ì§€ì ì˜ 게임 보기를 í´ë¦­í•˜ê³ , 마지막으로 ë„ë¡œì˜ ë ì§€ì ì— 대한 ì§€í˜•ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 다른 ìœ í˜•ì˜ ë„로가 ì—°ê²°ë  ìˆ˜ 있습니다. 거친 ì§€í˜•ì„ ê°€ë¡œ 지르는 ë„로를 연결하거나 ìž¥ì• ë¬¼ì„ í”¼í•˜ë ¤ë©´ 다리와 í„°ë„ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. ë„로를 위한 경로를 사용할 수 있ë„ë¡ ì§€í˜•ì„ ë³€ê²½í•˜ë ¤ë©´ 지형변경 ë„구를 사용하십시오. ë„시 ë„로 ë° ì¼ë¶€ ìž¥ì• ë¬¼ì„ ì œê±°í•˜ë ¤ë©´ 파괴/제거를 사용하십시오. 추가ì ì¸ ê¸°ëŠ¥ì„ ìœ„í•´ì„œ ë™ì‹œì— [Ctrl]키를 사용하십시오.}

무작위로 명소를 건설하십시오: ë„구는 승ê°ë“¤ì´ 방문하고 싶어하는 명소를 건설합니다. 서로 다른 명소ì—서는 ê°ê° 다른 ì–‘ì˜ ìŠ¹ê°ê³¼ ìš°íŽ¸ì´ ë°œìƒí•©ë‹ˆë‹¤. ê±´ì„¤ëœ ëª…ì†Œì˜ ìœ í˜•ì€ ë¬´ìž‘ìœ„ì´ë©° ìž¥ì• ë¬¼ì´ ì—†ëŠ” ì ì ˆí•œ ê³µê°„ì˜ ê²½ìš°ì—ë§Œ 나타납니다.
명소를 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ (커서를 red-drop-in-yellow-circle ì•„ì´ì½˜ìœ¼ë¡œ 변경합니다) 다ìŒ, 게임 보기ì—서 지형 ìƒì˜ 필수 위치를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 공용 서비스 플레ì´ì–´ë¡œ 명소를 제거하려면 파괴/제거를 사용하십시오. ëª…ì†Œì— ê´€í•œ ì ì ˆí•œ 장소를 ìƒì„±í•˜ë ¤ë©´ 파괴/제거 ë˜ëŠ” í’ê²½ ë„구를 사용하십시오.}

새 발전소를 건설하십시오: ë„구는 발전소 (ë° ê°€ëŠ¥í•œ 공급소)를 건설합니다. ê±´ì„¤ëœ ë°œì „ì†Œì˜ ìœ í˜•ì€ ë¬´ìž‘ìœ„ì´ë©° ìž¥ì• ë¬¼ì´ ì—†ëŠ” ì ì ˆí•œ ê³µê°„ì˜ ê²½ìš°ì—ë§Œ 나타납니다.
발전소를 건설하려면: ë„구를 í´ë¦­í•˜ê±°ë‚˜ [I]를 눌러서 ì„ íƒí•œ (커서를 red-drop-in-yellow-circle ì•„ì´ì½˜ìœ¼ë¡œ 변경합니다) 다ìŒ, 게임 보기ì—서 지형 ìƒì˜ 필수 위치를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 공용 서비스 플레ì´ì–´ë¡œ 발전소를 제거하려면 파괴/제거를 사용하십시오. ë°œì „ì†Œì— ê´€í•œ ì ì ˆí•œ 장소를 ìƒì„±í•˜ë ¤ë©´ 파괴/제거 ë˜ëŠ” í’ê²½ ë„구를 사용하십시오.}

가장 가까운 ë„ì‹œì— ìƒˆë¡œìš´ ì‹œìž¥ì„ ê±´ì„¤í•˜ì‹­ì‹œì˜¤: ë„구는 ë„시 지역 (그리고 ë„시 ì§€ì—­ì— ê³µê¸‰ìžê°€ 반드시 필요한 ê²ƒì€ ì•„ë‹™ë‹ˆë‹¤)ì—서 최종 소비ìžë¥¼ 구성합니다. ê±´ì„¤ëœ ì‚°ì—… ì‹œì„¤ì˜ ìœ í˜•ì€ ë¬´ìž‘ìœ„ì´ë©° ìž¥ì• ë¬¼ì´ ì—†ëŠ” ì ì ˆí•œ ê³µê°„ì˜ ê²½ìš°ì—ë§Œ 나타납니다.
사용하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ (커서를 red-drop-in-yellow-circle ì•„ì´ì½˜ìœ¼ë¡œ 변경합니다) 다ìŒ, 가장 가까운 ë„시 지역ì—서 소비ìžë¥¼ 구축할 수 있ë„ë¡ ê²Œìž„ 보기를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 공용 서비스 플레ì´ì–´ë¡œ 발전소를 제거하려면 파괴/제거를 사용하십시오. ì‚°ì—… ì‹œì„¤ì— ê´€í•œ ì ì ˆí•œ 장소를 ìƒì„±í•˜ë ¤ë©´ 파괴/제거 ë˜ëŠ” í…Œë¼í¬ë° ë„구를 사용하십시오.}

추가 플레ì´ì–´ ë³€ê²½ì„ í—ˆìš©í•˜ì§€ 마십시오: ë„구는 다른 플레ì´ì–´ 회사로 ìž‘ë™í•˜ê³  게임 (ì§€ë„) 편집 ë„구를 ì—´ 수 있는 ì˜µì…˜ì„ ì œê±°í•©ë‹ˆë‹¤.
사용하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ (커서를 ìžë¬¼ì‡  형ìƒìœ¼ë¡œ 변경합니다) 다ìŒ, 게임 ë³´ê¸°ì˜ ì•„ë¬´ ê³³ì´ë‚˜ í´ë¦­í•˜ë©´, 확ì¸ì´ 필요하지 않습니다.

1ë…„ ë‹¨ìœ„ì˜ íƒ€ìž„ë¼ì¸ 단계: ê²Œìž„ì˜ ì¼ì •ì„ 1ë…„ 앞당ê¹ë‹ˆë‹¤. 만약 타임ë¼ì¸ì„ 사용한다면, ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ë” ë§Žì€ ìˆ˜ì†¡ ë° ê±´ì„¤ ì˜µì…˜ì„ ì‚¬ìš©í•  수 있게ë˜ê³  ëŠë¦° ì°¨ëŸ‰ì€ ìˆ˜ìµì„±(ìˆ˜ìž…ì€ ì´ìš© 가능한 ìˆ˜ì†¡ì°¨ëŸ‰ì˜ í‰ê·  ì†ë„ì— ì˜í•´ 계산ë©ë‹ˆë‹¤)ì´ ì—†ì–´ì§€ê²Œ ë©ë‹ˆë‹¤.
사용하려면: ë„구를 í´ë¦­í•˜ë©´, ë”ì´ìƒ 확ì¸í•  필요가 없습니다 (게임 보기 아래 하단 ë°”ì˜ ì™¼ìª½ì— ë‚ ì§œê°€ 변경ë©ë‹ˆë‹¤).

simutrans-124.3/simutrans/text/ko/enlarge_map.txt000066400000000000000000000006101474050137200222050ustar00rootroot00000000000000ì§€ë„ í™•ëŒ€ ë„움ë§

확대 ì§€ë„

여기서, ì§€ë„를 오른쪽과 아래쪽으로 확장할 수 있습니다. 만약 왼쪽 / 위쪽으로 확장하려면, 먼저 ì§€ë„를 회전하고 확대한 ë‹¤ìŒ ë’¤ë¡œ 회전해야 합니다.
í™•ëŒ€ëœ ì§€ë„ì˜ ë¯¸ë¦¬ë³´ê¸°ëŠ” 다ì´ì–¼ë¡œê·¸ ì°½ì˜ ì˜¤ë¥¸ìª½ ìƒë‹¨ì— 표시ë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/factorylist_filter.txt000066400000000000000000000047601474050137200236550ustar00rootroot00000000000000 팩토리 목ë¡

팩토리 목ë¡

Factory List ì€ í˜„ìž¬ ê²Œìž„ì˜ ëª¨ë“  factories(ìƒí’ˆ 공급업체 ë° ì†Œë¹„ìž)ì— ëŒ€í•œ 정보를 ë³´ì—¬ì¤ë‹ˆë‹¤.

공장 ëª©ë¡ ì—´ê¸°: ëª©ë¡ ê´€ë¦¬.
ì—서 공장 ëª©ë¡ í´ë¦­ {íŒ: 목ë¡ì˜ í•­ëª©ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ 표시ë˜ëŠ” 경우 재조정 ì‚°ì—…/공장 ëª©ë¡ ë˜ëŠ” 스í¬ë¡¤ì€ 슬ë¼ì´ë” 막대를 사용하여 수행합니다.}

순서 지정: ì—는 ë‚˜ì—´ëœ ì‚°ì—…ì²´ì˜ ìˆœì„œë¥¼ 결정하는 ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤.
ì˜µì…˜ì„ ìˆœí™˜í•˜ë ¤ë©´ ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤(옵션 ë²„íŠ¼ì˜ ì´ë¦„ 변경).

- 공장ì´ë¦„ì€ ì´ë¦„으로 알파벳순으로 주문ë©ë‹ˆë‹¤.
- 입력 용량별 주문 건수입니다.
- 출력 출력 스토리지 용량별 주문입니다.
- ìƒì‚°ì€ ìƒì‚° 능력별로 업계를 주문합니다.
- ë ˆì´íŒ…ì€ ìƒíƒœë³„ ìƒ‰ìƒ í‘œì‹œì¤„ë¡œ 업계를 주문합니다(아래 참조).
- íŒŒì›Œì€ ì „ê¸° 공급으로 업계를 주문합니다.

- 스캔딩 / descendingì€ ëª©ë¡ ìˆœì„œë¥¼ 반대로 합니다.

해당 ì—…ê³„ì— ëŒ€í•œ ìžì„¸í•œ ë‚´ìš©ì„ ë³´ë ¤ë©´ Factory List ì— ë‚˜ì—´ëœ í•­ëª©ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. ê° ì—…ì¢…ì— ëŒ€í•œ 목ë¡ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤:

ìƒíƒœ-색ìƒ-ë°” 색ìƒì€ 업계 ìš´ì˜ì„ 나타냅니다(Aì—ì„œë„ ì‚¬ìš©ë¨):
- í°ìƒ‰: ì€ ë³´ì¶©ì œê°€ 필요하지 않습니다.
- 노란색:운송으로 ì—°ê²°ë˜ì—ˆì§€ë§Œ, ì‚°ì—… 공급 ì²´ì¸ì˜ ê³µê¸‰ì€ ë¶€ì¡±í•©ë‹ˆë‹¤.
- 녹색: 최ì ìƒíƒœì—서 녹색입니다.
- 오렌지: ìž‘ë™ ê°€ëŠ¥í•˜ì§€ë§Œ ê°œì„ ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤.
- 빨간색: ìž‘ë™ ì¤‘ì´ì§€ë§Œ ì‚°ì—… 공급ë§ì˜ ì¼ë¶€ê°€ 공급 과잉입니다.

업계가 변전소 를 통해 ì „ë ¥ì„ ê³µê¸‰ë°›ëŠ”ë‹¤ë©´ 빨간불-í•­ëª©ì´ í‘œì‹œë©ë‹ˆë‹¤.

ê³µìž¥ì˜ ì´ë¦„ 공장 ì´ë¦„:

괄호 ì•ˆì˜ 3 ê°’ì€ ë‹¤ìŒê³¼ 같습니다. 전류 ìž…ë ¥: 처리 준비가 ëœ ìƒí’ˆì˜ 양입니다.
전류 출력: 운송 준비가 ëœ ìƒí’ˆì˜ 양입니다.
ì´ìƒì‚°: ê³µìž¥ì˜ ìƒì‚°ìœ¨(월당 최대 ìƒì‚°ëŸ‰)

simutrans-124.3/simutrans/text/ko/finances.txt000066400000000000000000000023171474050137200215270ustar00rootroot00000000000000재정 ë„움ë§

재정

 재정 다ì´ì–¼ë¡œê·¸ì—서는, 작년ë„ì˜ ê²°ì‚°, ë° ê¸ˆë…„ë„ì˜ í˜„ì‹œì ì—ì„œì˜ ìˆ˜ì§€ë¥¼ 보는 와
(ì´)ê°€ í•  수 있습니다.ê° í•­ëª©ì€ ì´í•˜ì˜ ë‚´ìš©ì„ ë‚˜íƒ€ë‚´ê³  있습니다.

건설비 선로나 ë„로, ì—­ 등, ê±´ì¶•ë¬¼ì— ì‚¬ìš©ëœ ë¹„ìš©ì˜ í•©ê³„ìž…ë‹ˆë‹¤.

차량/ì„ ë°• 구입비 ì—´ì°¨, 트럭ì´ë‚˜ 버스, ì„ ë°• 등, 탈 ê²ƒì˜ êµ¬ìž…ì— ì‚¬ì›
ë¹„ìš©ì˜ í•©ê³„ìž…ë‹ˆë‹¤.

차량/ì„ ë°• ìš´í•­ 비용 탈 ê²ƒì˜ ìš´í–‰ ë¹„ìš©ì˜ í•©ê³„ìž…ë‹ˆë‹¤(ì°¨ëŸ‰ë§ˆë‹¤ì˜ ìš´í–‰ 비용ì€,차고 위
드우로 조사할 수 있습니다).

수입 ì—¬ê° ìˆ˜ì†¡, 화물 ìˆ˜ì†¡ì— ì˜í•´ì„œ ì–»ì„ ìˆ˜ ìžˆë˜ ëª¨ë“  ìˆ˜ìž…ì˜ í•©ê³„ìž…ë‹ˆë‹¤.

유지비 선로나 ë„로, ì—­ë“±ì˜ ê±´ì¶•ë¬¼ì„ ìœ ì§€í•˜ê¸° 위해 걸린 ë¹„ìš©ì˜ í•©ê³„ 입니다.
(íŒ:ì´ í•­ëª©ì€ ë‹¤ì´ì–¼ë¡œê·¸ì•„ëž˜ì˜ ë¶€ë¶„ì— ìžˆìŠµë‹ˆë‹¤)

수지 ì´ìƒì˜ ê° í•­ëª©ì˜ ì§€ì¶œê³¼ ìˆ˜ìž…ì„ ê³„ì‚°í•œ ê²°ê³¼ì˜ ìˆ˜ì§€ìž…ë‹ˆë‹¤.

잔금 í˜„ìž¬ì˜ ìžê¸ˆ ì´ì•¡ìž…니다.

simutrans-124.3/simutrans/text/ko/general.txt000066400000000000000000000063231474050137200213570ustar00rootroot00000000000000Simutrans ë„움ë§

ì¼ë°˜ ë„움ë§

- 환ì˜í•©ë‹ˆë‹¤!
- ì¸í„°íŽ˜ì´ìФ
- 마우스 ë„움ë§
- 키보드 ë„움ë§

게임 옵션

- 언어
- 플레ì´ì–´ 색ìƒ
- ë””ìŠ¤í”Œë ˆì´ ì„¤ì •
- 소리와 ìŒì•…
- 플레ì´ì–´
- 게임 불러오기
- 게임 저장하기
- 새 게임
- - 기후 설절
- - Height Map 불러오기

주 메뉴

- 게임 옵션
- ì§€ë„
- 조사 ë„구
- ì¡°ê²½ ë„구
- ì² ë„ ë„구
- ëª¨ë…¸ë ˆì¼ ë„구
- 트램 ë„구
- ë„로 ë„구
- ì„ ë°• ë„구
- 비행기 ë„구
- 특수 건설 ë„구
- 게임 편집 ë„구
- 파괴/제거

ê²½ì˜ ë©”ë‰´

- 노선 관리
- 목ë¡
- - 정류장/ì—­ 목ë¡
- - - 정류장/ì—­ ëª©ë¡ í•„í„°
- - 차량 목ë¡
- - - 차량 ëª©ë¡ í•„í„°
- - ë„시 목ë¡
- - ìƒí’ˆ 목ë¡
- - ì‚°ì—… 목ë¡
- - 관광명소 목ë¡
- 메시지 센터
- 재정

기타 옵션

- 스í¬ë¦°ìƒ·
- 멈춤
- 빨리ê°ê¸°
- ë„움ë§

기타 ì´ì•¼ê¸°

- 차고지 관리
- 스케줄 관리
- 정류장/역 정보

- - 정류장/ì—­ ìƒì„¸ ì •ë³´
- 차량 정보
- - 차량 ìƒì„¸ ì •ë³´
- ë„시 ì •ë³´
- ì‚°ì—… ì •ë³´

찾으시는 ë„움ë§ì´ 없다면 ë°‘ì˜ ì‚¬ì´íŠ¸ë“¤ì„ ì°¸ê³ í•˜ì„¸ìš”.
- http://guide.simutrans.com
- http://wiki.simutrans.com
- http://simutrans-tips.com
- http://forum.simutrans.com

simutrans-124.3/simutrans/text/ko/goods_filter.txt000066400000000000000000000067211474050137200224240ustar00rootroot00000000000000 ìƒí’ˆ 목ë¡

ìƒí’ˆ 목ë¡

ìƒí’ˆ ëª©ë¡ ì—는 게임 ë‚´ì—서 수송할 수 있는 여러 가지 항목과 ì´ë¥¼ 운반하는 ë° í•„ìš”í•œ ìˆ˜ìž…ì˜ ì–‘ì— ëŒ€í•œ ì •ë³´ê°€ í¬í•¨ë˜ì–´ 있습니다.

열려면: ëª©ë¡ ê´€ë¦¬ì—서 ìƒí’ˆ ëª©ë¡ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [G].를 누릅니다.

게임ì—서 ìš´ì†¡ì´ ê°€ëŠ¥í•œ í’ˆëª©ì˜ ëª©ë¡ì€ 수령한 수ìµ, ì†ë„ 보너스 %, ìƒí’ˆ 카테고리, 중량ì´ë‹¤.
{íŒ: 목ë¡ì˜ í•­ëª©ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ 표시ë˜ëŠ” 경우 re-size ìƒí’ˆ ëª©ë¡ ë˜ëŠ” 스í¬ë¡¤ì€ 슬ë¼ì´ë” 막대를 사용하여 수행합니다.}

ì†ë„보너스 : ì—´ê±°ëœ ìˆ˜ìµì„ 얻는 ë° í•„ìš”í•œ 다양한 전송 ìœ í˜•ì˜ ì°¨ëŸ‰í‰ê·  최대 ì†ë„를 ë³´ì—¬ì¤ë‹ˆë‹¤. í‰ê·  최대 ì†ë„ê°€ ë‚˜ì—´ëœ ì†ë„보다 빠를 경우 ì¼ë¶€ í•­ëª©ì€ ë” ë§Žì´ ë²Œ 수 있지만 ì†ë„ê°€ ë” ëŠë¦´ 경우 ë” ì ê²Œ 벌 수 있습니다.
타임ë¼ì¸ ì„¤ì •ì´ í™œì„±í™”ë˜ë©´ ì‹œê°„ì´ ê²½ê³¼í•¨ì— ë”°ë¼ ì†ë„ ê°’ì´ ë³€ê²½ë  ìˆ˜ 있습니다. 변화는 대개 ë” ë¹ ë¥´ê±°ë‚˜ ë” ê²½ì œì ì¸ 차량
ì˜ ë„ìž…ì— ë”°ë¦…ë‹ˆë‹¤. 화살표 ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ ì†ë„를 백분율로 조정하고 í‘œì‹œëœ ëª¨ë“  수ìµì„ ì—…ë°ì´íŠ¸í•  수 있습니다. ì´ê²ƒì€ ì°¨ëŸ‰ì˜ í‰ê·  최대 ì†ë„ê°€ 수ë™ìœ¼ë¡œ 계산할 í•„ìš” ì—†ì´ ì†ë„보너스 ì†ë„ì— ì •í™•ížˆ ë§žì§€ ì•Šì„ ë•Œ ì°¨ëŸ‰ì´ ì–»ëŠ” 수ìµì„ 알고 ì‹¶ì„ ë•Œ 유용합니다.

순서 지정: ì€ í•­ëª© 목ë¡ì´ 표시ë˜ëŠ” 순서를 ë³´ì—¬ì¤ë‹ˆë‹¤.
다양한 ì •ë ¬ 옵션(옵션 ë²„íŠ¼ì˜ ì´ë¦„ 변경):

- ì´ë¦„ì— ì˜í•œ, 알파벳순으로 주문ë©ë‹ˆë‹¤.
- 수ìµì— ì˜í•œ 소ë“별로 주문ë©ë‹ˆë‹¤.
- ë³´ë„ˆìŠ¤ì— ì˜í•œ 스피드보너스 비율(%)ì— ì˜í•´ 주문ë©ë‹ˆë‹¤.

- 오름차순 / ë‚´ë¦¼ì°¨ìˆœì€ ëª©ë¡ ìˆœì„œë¥¼ 반대로 합니다.

ê° í•­ëª©ì— ëŒ€í•œ 세부 정보는 다ìŒê³¼ 같습니다.

색ìƒí‘œëŠ” A 위 게임 ë·°ì— ìƒí’ˆ-ìƒ‰ìƒ ë°”ì—서 운송 대기 ì¤‘ì¸ í’ˆëª©ì˜ ì–‘ì„ ë‚˜íƒ€ë‚´ëŠ” 색ìƒê³¼ ë™ì¼í•©ë‹ˆë‹¤.
{íŒ: [!]ì„(를) 사용하여 게임 ë·°ì˜ ì¤‘ì§€ ìœ„ì— ìžˆëŠ” ìƒí’ˆ-색ìƒ-바를 전환합니다.}

수ìµì€ 한 단위를 현재 지급 모ë¸ì—서 한 ê°œì˜ íƒ€ì¼ ê±°ë¦¬ë¡œ 운반하여 ë°›ì€ ì†Œë“ì´ë‹¤.
{(기본 수ìµ) * (1 + (í‰ê·  최대 ì†ë„) / (ì†ë„보너스) - 1) * (% 보너스)}ì— ì˜í•´ 계산ë©ë‹ˆë‹¤.

% ë³´ë„ˆìŠ¤ì€ ì†ë„보너스 ì†ë„를 중심으로 한 ì†ë„보너스와 반대로 최대 ì†ë„ Convoy와 선형ì ìœ¼ë¡œ 매출 변화율 %입니다.

화물 ì¹´í…Œê³ ë¦¬ì€ ìš´ì†¡ì— í•„ìš”í•œ ì°¨ëŸ‰ì˜ ì¢…ë¥˜ë¥¼ 나타냅니다. 특수 í™”ë¬¼ì€ íŠ¹ì • ì°¨ëŸ‰ì„ í•„ìš”ë¡œ 합니다.
{íŒ: 차량capacity ì— ìš´ì†¡í•  수 있는 í•­ëª©ì´ í‘œì‹œë©ë‹ˆë‹¤.

ë¬´ê²Œì€ í™”ë¬¼ 한 ë‹¨ìœ„ì˜ ë¬´ê²Œê°€ 얼마나 ë˜ëŠ”ì§€ ë³´ì—¬ì¤ë‹ˆë‹¤.
ì´ëŠ” 운송 중 차량 ë¬´ê²Œì— ì¶”ê°€ë˜ì–´ ì°¨ëŸ‰ì´ ë¹„ì–´ 있는 경우보다 ë” ë§Žì€ ë™ë ¥ì„ 필요로 합니다.

simutrans-124.3/simutrans/text/ko/haltlist.txt000066400000000000000000000104221474050137200215610ustar00rootroot00000000000000ì—­ 목ë¡

ì—­ 목ë¡

ì—­ ëª©ë¡ ì€ ì •ë³´ë¥¼ 보여주며 다양한 정거장(물 운송 차량만 해당)ì„ í•„í„°ë§ ë° ë‚˜ì—´í•  수 있는 제어 장치를 갖추고 있으며, ì°¨ëŸ‰ì´ í”½ì—… ë° ë“œë¡­ë©ë‹ˆë‹¤.

열기:ëª©ë¡ ê´€ë¦¬ë¥¼ í´ë¦­í•˜ì‹­ì‹œì˜¤. ì—­ ëª©ë¡ ì€ ë„¤ ê°œì˜ ì˜µì…˜ ë²„íŠ¼ì´ ìžˆìœ¼ë©°, ë‘ ê°œëŠ” 목ë¡ì˜ í•­ëª©ì„ ì£¼ë¬¸í•˜ëŠ” ë° ì‚¬ìš©ë˜ê³  ë‘ ê°œëŠ” 목ë¡ì— 표시할 í•­ëª©ì„ ì„ íƒí•˜ëŠ” ë° ì‚¬ìš©ë©ë‹ˆë‹¤. 아래 ë²„íŠ¼ì€ í•„í„° ì˜µì…˜ì˜ ê¸°ì¤€ì— ë§žëŠ” 정류장 ì˜ ëª©ë¡ìž…니다.
{íŒ: 목ë¡ì— 있는 ì •ë¥˜ìž¥ì´ ì—†ìœ¼ë©´ í•„í„° ì˜µì…˜ì„ ë³€ê²½í•©ë‹ˆë‹¤. 목ë¡ì˜ í•­ëª©ì´ ë¶€ë¶„ì ìœ¼ë¡œë§Œ 표시ë˜ëŠ” 경우 재조정 ì—­ ëª©ë¡ ë˜ëŠ” 스í¬ë¡¤ 목ë¡(슬ë¼ì´ë” 막대가 있는 경우)}

ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì˜µì…˜ì„ ìˆœí™˜í•˜ê±°ë‚˜(옵션 ë²„íŠ¼ì˜ ì´ë¦„ 변경) í•„í„° 설정 ì»¨íŠ¸ë¡¤ì„ ì—½ë‹ˆë‹¤.

ì •ë ¬: ë‘ ì˜µì…˜ ë²„íŠ¼ë“¤ì€ ë³´ì—¬ì§€ëŠ” 리스트들ì—서 ì •ë¥˜ìž¥ì˜ ìˆœì„œ 결정한다.

- íƒ€ìž…ì€ í—ˆê°€ëœ ì°¨ëŸ‰ì˜ íƒ€ìž…ì„ ì£¼ë¬¸í•œë‹¤.
- 비정렬는 무작위로 순서를 정한다.
- ì´ë¦„ì€ ì´ë¦„ì— í• ë‹¹ëœ ì„œë¹„ìŠ¤ ì£¼ë¬¸ì˜ ASCII 코드(하위 사례 문ìžì˜ 대문ìž) ë‚´ì—서 ì˜ìˆ«ìž 순서로 주문한다.
- 대기순서는 대기 ì¤‘ì¸ ìŠ¹ê°ê³¼ ìƒí’ˆì˜ ì–‘ë§Œí¼ ì œê³µë©ë‹ˆë‹¤.

- 오름차순 / ë‚´ë¦½ì°¨ìˆœì€ ëª©ë¡ ìˆœì„œë¥¼ 반대로 합니다.

í•„í„°: 옵션 버튼 ë‘ ê°œ, ëª©ë¡ ì„¤ì •/í•´ì œ ì„ íƒ ê¸°ì¤€ì„ ì„¤ì •í•˜ì—¬ ê¸°ì¤€ì„ ë³€ê²½í•©ë‹ˆë‹¤.

- 가능 / 불가능 í´ë¦­í•´ì„œ í•„í„° ê¸°ì¤€ì„ ì „í™˜í•©ë‹ˆë‹¤.

-설정 ì„ í´ë¦­í•˜ì—¬ ì»¨íŠ¸ë¡¤ì„ ì—´ê³  í•„í„° ê¸°ì¤€ì„ ë³€ê²½í•©ë‹ˆë‹¤.

ì—­ 목ë¡ì— ë‚˜ì—´ëœ í•­ëª©ì„ í´ë¦­í•˜ë©´ 해당 ì •ë¥˜ìž¥ì— ëŒ€í•œ ìžì„¸í•œ ì •ë³´ 를 ë³¼ 수 있습니다.
ê° ì •ì§€ì— ëŒ€í•´ ë‚˜ì—´ëœ í•­ëª©ì€ ë‹¤ìŒê³¼ 같습니다.

ìƒ‰ìƒ ìƒíƒœ ë°”: 색ìƒì€ 과밀ë„와 관련하여 Stopì˜ ìž‘ë™ì„ 나타냅니다. ìƒ‰ìƒ ë°”ëŠ” ì •ì§€ ì •ë³´ ë° ë…¸ì„  관리ì—ì„œë„ ì‚¬ìš©ë˜ë©°, 게임 디스플레ì´ì—서 ì •ì§€ ìœ„ì˜ ìƒ‰ìƒ ë§‰ëŒ€ì— í‘œì‹œëœ ìƒ‰ìƒê³¼ ë™ì¼í•©ë‹ˆë‹¤. - 노란:ì€ ì•„ë¬´ ì„œë¹„ìŠ¤ë„ ë°›ì§€ 않고 기다리는 ê²ƒë„ ì—†ìŠµë‹ˆë‹¤.
- 녹색:ì€ ê°œì„ í•  필요가 없습니다.br - 주황:ì€ ì •ë¥˜ìž¥ 꽉찬 ìƒíƒœì´ë‹¤(대부분 환승 ë¬¼í’ˆì´ ìžˆëŠ”).
- 빨강: ì •ë¥˜ìž¥ì€ ìš©ëŸ‰ì˜ 1.5ë°° ì´ìƒ, ë˜ëŠ” 200명 ì´ìƒì˜ 불행한 승ê°ì„ 수용하거나, ì—­ì´ ê³¼ë°€í•˜ê¸° ë•Œë¬¸ì— ê³µìž¥ì—서 ìƒì‚°ì„ 중단해야 합니다.
{íŒ: [!]를 사용하여 게임 디스플레ì´ì—서 중지 ìœ„ì˜ ìƒ‰ìƒ ë§‰ëŒ€ë¥¼ 전환합니다.}

í• ë‹¹ëœ ì´ë¦„ {íŒ: simuconf.tab}ì—서 사용할 수 있는 중지 ì´ë¦„ì˜ ë²ˆí˜¸ë¥¼ 할당하는 옵션입니다.

차량 ì•„ì´ì½˜ ì€ ì •ë¥˜ìž¥ë¥¼ 사용할 수 있는 차량 ìœ í˜•ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤(정류장 정보와 노선 관리ì—ì„œë„ ì‚¬ìš©ë¨).
ì•„ì´ì½˜ì—는 버스(ë„로 승ê°ìš©), 트럭(ë„로 화물용), 기차, 보트 ë° ë¹„í–‰ê¸°ê°€ í¬í•¨ë©ë‹ˆë‹¤. 열차는 ì •ì§€ ìœ í˜•ì— ë”°ë¼ ë²„ìŠ¤-ì•„ì´ì½˜ ë˜ëŠ” ì—´ì°¨-ì•„ì´ì½˜ìœ¼ë¡œ í‘œì‹œë  ìˆ˜ 있습니다.

화물 ì•„ì´ì½˜ ì€ ì •ë¥˜ìž¥ ì´ ì²˜ë¦¬í•  수 있는 항목(승ê°, ìƒí’ˆ ë°/ë˜ëŠ” ë©”ì¼)ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤(정류장 정보와 노선 관리ì—ì„œë„ ì‚¬ìš©ë¨).
{íŒ: ì ì ˆí•œ í™•ìž¥ì„ ì¶”ê°€í•˜ë©´ 중지 시 처리할 수 있는 í•­ëª©ì˜ ë²”ì£¼ê°€ 변경ë©ë‹ˆë‹¤. ìš°ì²´êµ­ì„ ì •ë¥˜ìž¥ì— ì¶”ê°€í•˜ì—¬ ë©”ì¼ì„(를) 처리할 수 있습니다.}

ì •ë¥˜ìž¥ì— ê´€ë ¨ëœ ë³´ë„ê°ë“¤ ìƒí’ˆë“¤ì˜ ì°¨ì´ì ì˜ 대기 세부사항.

simutrans-124.3/simutrans/text/ko/haltlist_filter.txt000066400000000000000000000050311474050137200231260ustar00rootroot00000000000000ì—­ ëª©ë¡ í•„í„°

ì—­ ëª©ë¡ í•„í„°

ì—­ ëª©ë¡ í•„í„°ì—는 ì°¨ëŸ‰ì´ ìŠ¹ê°ì„ 태워가는 정류장 ì„ ê²°ì •í•˜ëŠ” ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤(물 운송 ì°¨ëŸ‰ì€ í•´ë‹¹ 안ë¨). ë˜í•œ ì—­ 목ë¡ì— 표시ë©ë‹ˆë‹¤.

스테ì´ì…˜ 목ë¡ì—서 설정를 í´ë¦­í•˜ì—¬ ì—­ ëª©ë¡ í•„í„°ë¥¼ 엽니다.

옵션 ë²„íŠ¼ì€ ì •ë¥˜ìž¥ì„ ì„ íƒí•©ë‹ˆë‹¤. í•„í„° ì˜µì…˜ì´ ê°€ëŠ¥ ìƒíƒœì¼ 때 ì—­ 목ë¡ì— 나열ë¨. 모든 기준 ì§‘í•©ì— ì í•©í•œ 정류장만 나열ë©ë‹ˆë‹¤.

ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ í•„í„° ê¸°ì¤€ì„ ì„ íƒí•˜ê±°ë‚˜ ì„ íƒ ì·¨ì†Œí•©ë‹ˆë‹¤(ì„ íƒí•˜ë©´ ë²„íŠ¼ì´ ë“¤ì—¬ì“°ê¸°ë¨).

í•„í„° ì´ë¦„:ì€ ì •ë¥˜ìž¥ì„ ì„ íƒí•©ë‹ˆë‹¤. 사용하려면 단추를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ ì´ë¦„ ìƒìžë¥¼ í´ë¦­í•˜ê³  필요한 ì´ë¦„ì„ ì •í™•í•˜ê²Œ 입력합니다(ì˜µì…˜ì€ ëŒ€ì†Œë¬¸ìžë¥¼ 구분함).

í•„í„° 유형:ì—는 ì„ íƒí•œ 경우 ë‹¤ìŒ í•­ëª© 중 하나 ì´ìƒì„ í¬í•¨í•˜ëŠ” 정류장 ì´ ë‚˜ì—´ë©ë‹ˆë‹¤. 사용하려면: ë²„íŠ¼ì„ í´ë¦­í•©ë‹ˆë‹¤. (수송 차량만 정지하면 ì—­ 목ë¡ì— ì—†ìŒ)

특수 필터:
- 오버플로? 사용 ì¤‘ì´ ì•„ë‹™ë‹ˆë‹¤.
- 비 ì—°ê²°ì€ ìš´ì†¡ 서비스가 없는 ì •ë¥˜ìž¥ì„ ì„ íƒí•©ë‹ˆë‹¤.

필요한 ìƒí’ˆ: ì€ ì •ë¥˜ìž¥ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 여기서 ì„ íƒí•œ í•­ëª©ì€ ì´ë™ì„ 종료합니다. ì´ë¦„ ì˜†ì— ìžˆëŠ” ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤. 항목 목ë¡ì„ 스í¬ë¡¤í•˜ë ¤ë©´ 슬ë¼ì´ë“œ ë°” 를 사용하십시오. ì˜µì…˜ì€ ë‹¤ìŒê³¼ 같습니다:
- allì€ ëª¨ë“  í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤.
- none í•­ëª©ì´ ì„ íƒë˜ì§€ 않았습니다.
- inv.ì€ í˜„ìž¬ ì„ íƒí•œ 항목보다 우선합니다.

ìƒì‚°:ì€ ì´ë™ 경로를 ë°˜ì˜í•œ 정류장 ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤. ì´ë¦„ ì˜†ì— ìžˆëŠ” ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤. 슬ë¼ì´ë” 바를 사용하여 항목 목ë¡ì„ 스í¬ë¡¤í•©ë‹ˆë‹¤. ì˜µì…˜ì€ ë‹¤ìŒê³¼ 같습니다.
- allì€ ëª¨ë“  í•­ëª©ì„ ì„ íƒí•©ë‹ˆë‹¤.
- none í•­ëª©ì´ ì„ íƒë˜ì§€ 않았습니다.
- inv.ì€ í˜„ìž¬ ì„ íƒí•œ 항목보다 우선합니다.

simutrans-124.3/simutrans/text/ko/industry_info.txt000066400000000000000000000124261474050137200226370ustar00rootroot00000000000000ì‚°ì—… ì •ë³´

ì‚°ì—… ì •ë³´

ì‚°ì—… 정보는 ì„ íƒëœ ì‚°ì—…(ìƒí’ˆ 공급업체 ë˜ëŠ” 소비ìž)ì— ëŒ€í•œ 세부 정보를 표시하고 게임 ì„¸ê³„ì˜ ê´€ë ¨ 위치로 게임 보기를 ì´ë™í•  수 있ë„ë¡ í•©ë‹ˆë‹¤.

ìƒí’ˆì˜ 공급ìžì™€ 소비ìžëŠ” 최종 소비ìžë¡œ 종료ë˜ëŠ” ì‚°ì—… 공급ë§ì„ 제공하기 위해 ì—°ê²° ë©ë‹ˆë‹¤. ì–´ë–¤ ì‚°ì—…ì€ ì†Œë¹„ìžì™€ ê³µê¸‰ìž ë‘˜ 다ì´ë©° ì‚°ì—… 공급ë§ì˜ ì¤‘ê°„ì— ìžˆë‹¤. 만약 ì´ˆë³´ìž ëª¨ë“œì—서 ë›°ì§€ 않으면, 소비ìžëŠ” 공급 ê³¼ìž‰ì„ ì¤‘ë‹¨í•˜ê²Œ ë©ë‹ˆë‹¤.
ì‚°ì—…ì€ ë˜í•œ 승ê°ê³¼ ìš°íŽ¸ë¬¼ì˜ ëª©ì ì§€ì¼ ìˆ˜ë„ ìžˆë‹¤. ì •ì°¨ìž¥ì˜ ìœ ì—­ êµ¬ì—­ì´ ì‚°ì—… ê±´ë¬¼ì˜ ì–´ëŠ ë¶€ë¶„ì„ ì»¤ë²„í•˜ê³  ì •ì°¨ìž¥ì´ í•´ë‹¹ í’ˆëª©ì„ ì²˜ë¦¬í•  수 있는 경우 ì°¨ëŸ‰ì€ ì •ë¥˜ìž¥ ì„ í†µí•´ ìƒí’ˆê³¼ 승ê°ì„ 수집하여 산업으로 운송한다. {íŒ: í•´ìƒìš´ë°˜/오ì¼ì„ /어류 ì–‘ì‹ìž¥/배치구역/오ì¼/우편/승ê°/ì—­ 목ë¡ì— ì—†ìŒ}

초기 ì‚°ì—… 공급 ì²´ì¸ ìˆ˜ëŠ”ìƒˆ 게임 ë§Œë“¤ê¸°ì„ ì„¤ì •ê°€ëŠ¥í•œ ì²´ì¸ë“¤ì„ 공급합니다. ë„시 지역가 ì„±ìž¥í• ìˆ˜ë¡ ë” ë§Žì€ ì‚°ì—…ì´ ë‚˜íƒ€ë‚  것입니다. 새로운 ì‚°ì—…ì€ ë„시 ì§€ì—­ì˜ ì¸êµ¬ê°€ 2000ë…„ ì´í›„ ë‘ ë°°ê°€ ë  ë•Œë§ˆë‹¤ 나타난다.
{íŒ: 가까운 ë„ì‹œì— ìƒˆë¡œìš´ 시장 ê±´ì„¤ì„ ì‚¬ìš©í•˜ì—¬ 산업체를 ë„시 ì§€ì—­ì— ì¶”ê°€í•œë‹¤?게임 편집 ë„구. cityrules.tabì—서 새 ì‚°ì—…ì´ ìƒì„±ë  때 변경(ì‚°ì—…ì²´ 성장률 = 0ì€ ìƒˆë¡œìš´ ì‚°ì—…ì„ ìƒì„±í•˜ì§€ 않ìŒ)}.

검사 ë„구를 ì´ìš©í•˜ê±°ë‚˜ 게임 ë·°ì— ìžˆëŠ” 업체를 í´ë¦­í•˜ê±°ë‚˜ ì‚°ì—… 목ë¡ì— ë‚˜ì—´ëœ ì‚°ì—…ì²´ë¥¼ í´ë¦­í•˜ì—¬ ì‚°ì—… 정보를 엽니다. 슬ë¼ì´ë” ë°” 를 사용하여 ë³´ì´ì§€ 않는 모든 í•­ëª©ì„ ìŠ¤í¬ë¡¤ í•  수 있습니다.

ì„ íƒí•œ ì‚°ì—…ì˜ ì´ë¦„ì€ ì‚°ì—… ì •ë³´ì˜ ì œëª© í‘œì‹œì¤„ì— í‘œì‹œë©ë‹ˆë‹¤.
ì„ íƒí•œ ì‚°ì—… ë° ì˜µì…˜ì— ëŒ€í•œ 기타 정보는 다ìŒê³¼ 같습니다.

ìƒì‚°: 업계가 공급(ê³µê¸‰ì—…ì²´ì¸ ê²½ìš°) ë˜ëŠ” 소비(최종 소비ìžì¸ 경우)ì˜ ìµœëŒ€ 비율(ì›”/ì¼ ë‹¨ìœ„).
{íŒ: 변압소 와 ì‚°ì—…ì— ì „ê¸°ë¥¼ 공급하는 ê²ƒì„ ì¶”ê°€í•˜ë©´ ìƒì‚°/소비ë˜ëŠ” ìƒí’ˆì˜ ë¹„ìœ¨ì´ ì¦ê°€í•œë‹¤.

ì‚°ì—…ì€ ì‚°ì—…ê±´ë¬¼ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 게임 뷰를 ì‚°ì—… 건물로 ì´ë™í•˜ë ¤ë©´ ê·¸ë¦¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

그림 ì•„ëž˜ì˜ ìƒ‰ìƒ ìƒíƒœ ë°” 는 ì‚°ì—…ì˜ ìš´ì˜ì„ 나타냅니다(ë˜í•œ ì‚°ì—… 목ë¡)ì—ì„œë„ ì‚¬ìš©ë¨). - í°ìƒ‰:ì€ ìž…ë ¥í•˜ì§€ ì•Šì•„ë„ ë©ë‹ˆë‹¤.
- 노란색:운송으로 ì—°ê²°ë˜ì—ˆì§€ë§Œ, ì‚°ì—… 공급 ì²´ì¸ì˜ ê³µê¸‰ì€ ë¶€ì¡±í•©ë‹ˆë‹¤.
- 녹색: 최ì ì˜ ìƒíƒœ.br - 주황색: ìž‘ë™ ê°€ëŠ¥í•˜ì§€ë§Œ ê°œì„ ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤.
- 빨간색: ìž‘ë™ ì¤‘ì´ì§€ë§Œ ì‚°ì—… 공급ë§ì˜ ì¼ë¶€ê°€ 공급 과잉입니다.

소비ìž:ì€ ì„ íƒëœ 산업계ì—서 ìƒì‚°ëœ ì œí’ˆì— ëŒ€í•œ ì‚°ì—… 공급ë§ì˜ ëŒ€ìƒ ëª©ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
목ì ì§€ ì‚°ì—…ê³¼ ê·¸ ì§€ë„ ì¢Œí‘œëŠ” 화살표 ë²„íŠ¼ì— ì˜í•´ 나열ë˜ì–´ 있다. 화살표 ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ 게임 보기를 대ìƒìœ¼ë¡œ ì´ë™í•©ë‹ˆë‹¤.

공급ìž:ì€ íŠ¹ì • ì‚°ì—…ì´ ìš”êµ¬í•˜ëŠ” ì‚°ì—… 공급ë§ì—서 ìƒí’ˆì˜ 출처를 ë³´ì—¬ì¤ë‹ˆë‹¤.br 공급 ì—…ì²´ ì‚°ì—…ê³¼ ì´ë“¤ì˜ ì§€ë„ ì¢Œí‘œëŠ” 화살표 버튼별로 나열ë˜ì–´ 있다. 화살표 단추를 í´ë¦­í•˜ì—¬ 게임 보기를 공급업체로 ì´ë™í•©ë‹ˆë‹¤.

ë…¸ë™ìž:ì€ ì§ì›ë“¤ì´ ì‚´ê³  있는 ë„시 지역 ê·¼ì²˜ì— ì‚´ê³  있습니다. ì´ëŸ¬í•œ ë„시 ì§€ì—­ì˜ ìŠ¹ê°ê³¼ ìš°íŽ¸ë¬¼ì€ ì„ íƒëœ ì‚°ì—…ì— ë„달해야 í•  것ì´ë‹¤.
ë„시 지역과 ì§€ë„ ì¢Œí‘œëŠ” 화살표 ë²„íŠ¼ì— ì˜í•´ 나열ë˜ì–´ 있다. 화살표 단추를 í´ë¦­í•˜ì—¬ 게임 보기를 공급업체로 ì´ë™í•©ë‹ˆë‹¤.

ìŠ¹ê° ë ˆë²¨:ì€ ìŠ¹ê°ì˜ 목ì ì§€ë¡œ ìƒëŒ€ì ì¸ ì¸ê¸°ë¥¼ 얻고 있습니다. ë©”ì¼ ë ˆë²¨:ì€ ë©”ì¼ì˜ 목ì ì§€ë¡œ ìƒëŒ€ì ì¸ ì¸ê¸°ìž…니다.
{íŒ: 승ê°ê³¼ ë©”ì¼ì— 최ì ì˜ 서비스를 제공하기 위해 ì‚°ì—… 건물 중 1í‰ë°©ë¯¸í„°ë§Œ ì •ë¥˜ìž¥ì˜ ë³´ê´€ êµ¬ì—­ì— ë–¨ì–´ì§€ë©´ ë©ë‹ˆë‹¤.

프로ë•ì…˜:ì€ ì‚°ì—… ìƒì‚°ëŸ‰ì— 대한 세부 정보를 제공합니다.
í‘œì‹œëœ ì •ë³´ì—는 품목 ì´ë¦„, í’ˆëª©ì˜ ìµœëŒ€ 저장 용량으로 현재 ì €ìž¥ëœ ìˆ˜ëŸ‰, ìƒí’ˆ 카테고리, ìž…ë ¥ 대비 출력 수준 ë“±ì´ í¬í•¨ë©ë‹ˆë‹¤.

ì†Œë¹„ì€ ì‚°ì—… ìž…ë ¥ì— ëŒ€í•œ 세부 정보를 제공합니다.br í‘œì‹œëœ ì •ë³´ì—는 품목 ì´ë¦„, í’ˆëª©ì˜ ìµœëŒ€ 저장 용량으로 현재 ì €ìž¥ëœ ìˆ˜ëŸ‰, ìƒí’ˆ 카테고리, 출력 대비 ìž…ë ¥ 비율 ìˆ˜ì¤€ì´ í¬í•¨ë©ë‹ˆë‹¤.

ì—…ê³„ì— ì„œë¹„ìŠ¤ë¥¼ 제공하는 ì •ë¥˜ìž¥ì€ ì‚°ì—… ì •ë³´ í•˜ë‹¨ì— ë‚˜ì—´ë˜ì–´ 있습니다.

simutrans-124.3/simutrans/text/ko/inspection_tool.txt000066400000000000000000000137351474050137200231570ustar00rootroot00000000000000 검사 ë„구

검사 ë„구

검사 ë„구는 다양한 í•­ëª©ì— ëŒ€í•œ ì •ë³´ ë˜ëŠ” 옵션 제어를 제공하는 대화를 여는 ë° ì‚¬ìš©ë©ë‹ˆë‹¤.

게임 ë·° 맨 ìœ„ì— ìžˆëŠ” ë‹ë³´ê¸°-유리-ì•„ì´ì½˜ì„ í´ë¦­í•˜ê±°ë‚˜ [a]를 눌러 검사 ë„구를 엽니다(커서가 ë‹ë³´ê¸° 모양으로 변경).

검사 ë„구를 사용하려면: 필요한 위치ì—서 게임 ë·°ì— ë‹ë³´ê¸°-유리-커서를 배치하고 대화 ìƒìžë¥¼ í´ë¦­í•˜ì—¬ 엽니다. 둘 ì´ìƒì˜ í•­ëª©ì´ í•„ìš”í•œ ìœ„ì¹˜ì— ìžˆëŠ” 경우, 다시 í´ë¦­í•˜ë©´ ë‘ ë²ˆì§¸ 대화 ìƒìžê°€ 열립니다. {íŒ: simuconf.tab}ì—서 사용할 수 있는 ì§€ì •ëœ ì»¤ì„œ ìœ„ì¹˜ì— ëŒ€í•´ í•˜ë‚˜ì˜ ëŒ€í™” ë˜ëŠ” 모든 대화 ìƒìžë¥¼ 여는 옵션

다양한 대화를 열려면 툴과 함께 ë‹¤ìŒ í•­ëª©ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

차고지 - 제어 ì°½ì„ ì—´ì–´ 해당 차고ì—서 ì°¨ëŸ‰ì„ êµ¬ë§¤í•˜ê³  관리합니다.

정류장 - 해당 Stopì— ëŒ€í•œ 정류장 정보를 엽니다.

차량 - 해당 ì°¨ëŸ‰ì— ëŒ€í•œ 수송수단/차량 정보를 엽니다.

시청 ì€ ê·¸ ë„시 ì§€ì—­ì„ ìœ„í•œ ë„시 ì •ë³´ 를 엽니다. {íŒ: simuconf.tabì—서 사용 가능한 시청 정보를 제공하는 다ì´ì•Œë¡œê·¸ë¥¼ 여는 옵션입니다}

ì‚°ì—… - 해당 ì‚°ì—…ì˜ ì‚°ì—… 정보를 엽니다.

ë„시 ê±´ë¬¼ì€ ê±´ë¬¼ì— ëŒ€í•œ 정보를 제공하는 대화ìƒìžë¥¼ 엽니다(대화 제목 í‘œì‹œì¤„ì€ '건물'). 대화 ìƒìžì— í¬í•¨ëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤. - ì„¤ëª…ì€ ê±´ë¬¼ì— ëŒ€í•œ 정보를 제공합니다. ì„¤ëª…ì„ ì‚¬ìš©í•  수 없는 경우 '주íƒ', 'ì‚°ì—… 건물', '작업장 ë° ìƒì '(ìƒì—… ê±´ë¬¼ì˜ ê²½ìš°) 중 하나가 표시ë©ë‹ˆë‹¤.
- ë„시: ë„시 ê±´ë¬¼ì´ ì†í•œ ë„시 ì§€ì—­ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
- ìŠ¹ê° ë ˆë²¨: ì€ ìŠ¹ê°ì˜ 목ì ì§€ë¡œ ìƒëŒ€ì ì¸ 선호ë„입니다.
- ë©”ì¼ ë ˆë²¨: ì€ ë©”ì¼ì˜ 수신지로서 ìƒëŒ€ì ì¸ 선호ë„입니다.
-
시작 시기:
타임ë¼ì¸ìœ¼ë¡œ 플레ì´í•  경우 ê±´ë¬¼ì´ ë‚˜íƒ€ë‚˜ëŠ” ì—°ë„를 나타냅니다.
- ê°’: 파괴/제거 ë„구로 ê±´ë¬¼ì„ ì² ê±°í•  경우 ë°œìƒí•˜ëŠ” ë¹„ìš©ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
- 그린 ì´: ì‹œë®¤íŠ¸ë ŒìŠ¤ì˜ ê±´ë¬¼ì„ ê·¸ë¦° ì‚¬ëžŒì˜ ì´ë¦„

기ë…비 / 관광 명소는 관광 ëª…ì†Œì— ëŒ€í•œ 정보를 제공하는 대화를 엽니다(대화 모ìŒì€ ê·¸ê²ƒì´ ê¸°ë…물ì¸ì§€ 관광 명소ì¸ì§€ë¥¼ 나타냅니다). 다ì´ì•Œë¡œê·¸ì— í¬í•¨ëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤. - 공개 ìžì‚°ì€ 해당 í•­ëª©ì´ í”Œë ˆì´ì–´ íšŒì‚¬ì— ì˜í•´ 소유ë˜ì§€ 않ìŒì„ 나타냅니다.
- ì„¤ëª…ì€ ë§¤ë ¥ì— ëŒ€í•œ 정보를 제공합니다.
- ìŠ¹ê° ë ˆë²¨:ì€ ìŠ¹ê°ì˜ 목ì ì§€ë¡œ ìƒëŒ€ì ì¸ 선호ë„입니다.
- ë©”ì¼ ë ˆë²¨:ì€ ë©”ì¼ì˜ 수신지로서 ìƒëŒ€ì ì¸ 선호ë„입니다.
- 시작 시기:타임ë¼ì¸ìœ¼ë¡œ 플레ì´í•  경우 나타나는 ì—°ë„를 나타냅니다.
- 그린 ì´: ì‹œë®¤íŠ¸ëžœìŠ¤ì˜ ê´€ê´‘ì§€ë¥¼ 그린 ì‚¬ëžŒì˜ ì´ë¦„

ë„로와 ì„ ë¡œì€ ë„로 ë˜ëŠ” ì„ ë¡œì— ëŒ€í•œ 정보를 제공하는 다ì´ì•Œë¡œê·¸ë¥¼ 엽니다(대화 제목 í‘œì‹œì¤„ì€ ë„로 표제 íŠ¸ëž™ì˜ ìœ í˜•ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤).
ëŒ€í™”ì— í¬í•¨ëœ ì •ë³´: - 최대 ì†ë„: ë„로 ë˜ëŠ” 트랙ì—서 허용ë˜ëŠ” 최대 ì†ë„ 제한.
- Ribi(ë§ˆìŠ¤í¬ ì—†ìŒ) :
ì€ ì´ë™ ë°©í–¥ì„ ë‚˜íƒ€ë‚´ëŠ” ë‚´ë¶€ 카운터입니다.
- Ribi(ë§ˆìŠ¤í¬ ì ìš©): 신호나 신호를 고려하는 경로 ë°©í–¥ì„ ë‚˜íƒ€ë‚´ëŠ” ë‚´ë¶€ 카운터입니다.
- 신호 ë˜ëŠ” 기호가 있는 경우 - 기호/신호 ì´ í‘œì‹œë©ë‹ˆë‹¤.
- 전기화/ 비 전기화는 ê¸¸ì´ ì „ê¸°í™”ë˜ì—ˆëŠ”ì§€ 여부를 나타냅니다.
- 지난 달 수송량는 ì´ì „ 게임 ì¼ì • ê¸°ê°„ì— ì‚¬ìš©ëœ ì°¨ëŸ‰ì˜ ìˆ˜ë¥¼ 나타냅니다.
- ì˜ˆì•½ì€ ì–´ëŠ ì°¨ëŸ‰ì´ í†µê³¼ë  ë•Œê¹Œì§€ ì„ ë¡œì„ ì˜ˆì•½í–ˆëŠ”ì§€ 나타냅니다.
- 경사 ë¡œí”„ì€ ìŠ¬ë¡œí”„ ë°©í–¥ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤. - ë§µ ì¢Œí‘œì€ ì•„ëž˜ìª½ 막대 ì— ë‚˜ì˜¨ 것과 ê°™ì´
- ë„ë¡œì— ì„¤ì¹˜ëœ íŠ¸ëž¨ ì„ ë¡œì˜ ê²½ìš°: ì •ë³´ê°€ ë‘ ë²ˆ 표시ë©ë‹ˆë‹¤(처ìŒì—는 ë„로, ê·¸ 다ìŒì—는 트램 선로).

신호등/ì‹ í˜¸ì€ íƒ€ì´í‹€ ë°”ì˜ ë‹¤ì´ì•Œë¡œê·¸ê°€ 신호ì¸ì§€ ë„로 표지íŒì¸ì§€ë¥¼ 분별하는 다ì´ì•Œë¡œê·¸ë¥¼ 엽니다. ëŒ€í™”ì— í¬í•¨ëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤. - ë°©í–¥ì€ ì‹ í˜¸ê°€ ì ìš©ë˜ëŠ” ë°©í–¥ì„ ë‚˜íƒ€ë‚´ëŠ” ë‚´ë¶€ 카운터입니다.

ì „ì••ì„  / ë³€ì••ì†Œì€ ì „ê¸° 공급 ê·¸ë¦¬ë“œì— ëŒ€í•œ 정보를 제공하는 대화를 엽니다. í‘œì‹œëœ ì •ë³´ì—는 현재 수요와 ê³µê¸‰ì´ í¬í•¨ë©ë‹ˆë‹¤.

나무를 누르면 다ì´ì•Œë¡œê·¸ê°€ 열립니다(타ì´í‹€ 바는 '나무'ìž„). í‘œì‹œëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤. - ì´ë¦„ì€ ë‚˜ë¬´ì˜ ì¢…ë¥˜ë¥¼ 제공.
- 나ì´ì€ 월별 나무 나ì´.

ë•…ì€ ëŒ€í™”ë¥¼ 엽니다(제목표는 'ë•…'ìž„). í‘œì‹œëœ ì •ë³´ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤.
- 경사로는 ë‚˜ë¬´ì˜ ì¢…ë¥˜ë¥¼ 제공합니다.
- 하단 ë°”ì— ë‚˜ì˜¨ 것처럼 ì§€ë„ ì¢Œí‘œì— ë³´ì—¬ì§„ë‹¤.

{íŒ: simunconf.tabì—서 사용할 수 있는 ê°œì¸ ë„로 ì‚¬ìš©ìž ë° ë³´í–‰ìžì— 대한 대화를 여는 옵션입니다.}

simutrans-124.3/simutrans/text/ko/jump_frame.txt000066400000000000000000000012071474050137200220630ustar00rootroot00000000000000건너뛰기 ë„움ë§

건너뛰기

다ì´ì•Œë¡œê·¸ëŠ” [J]키와 건너뛰기 가능한 특정한 좌표와 함께 열립니다. ì´ê²ƒì€ ê²Œìž„ì„¸ê³„ì˜ íŠ¹ì •í•œ 위치로 빠르게 움ì§ì´ëŠ”ë° ìœ ìš©í•©ë‹ˆë‹¤.

ê²Œìž„ì•ˆì˜ ëª¨ë“ íƒ€ì¼ì€ (x,y)ë‘가지 좌표를 가지며,(0,0)ì€ ì§€ë„ì˜ ë§¨ì™¼ìª½êµ¬ì„ì— ìœ„ì¹˜í•©ë‹ˆë‹¤. 커서 ì¢Œí‘œë“¤ì€ ì˜êµ¬ì ìœ¼ë¡œ ìƒíƒœ ë°”ì— ë³´ì—¬ì§‘ë‹ˆë‹¤.
주ì˜: ì§€ë„회전([R]키와 ê°™ì´ ìˆ˜í–‰ ë˜ì–´ì§€ëŠ”)ì€ ëª¨ë“  좌표타ì¼ë“¤ì„ 회전시킵니다.

simutrans-124.3/simutrans/text/ko/labellist_filter.txt000066400000000000000000000005101474050137200232520ustar00rootroot00000000000000신호 목ë¡

플레ì´ì–´ 신호 목ë¡

여기는 ì§€ë„ì˜ ëª¨ë“  ì‹ í˜¸ë“¤ì˜ ëª©ë¡ì´ 있다.
í™œë™ ì‚¬ìš©ìž ì „ìš© ì˜µì…˜ì€ í™œë™í•˜ëŠ” 사용ìžì˜ 신호들만 ë³´ì—¬ì¤ë‹ˆë‹¤.

í•­ëª©ì„ í´ë¦­í•˜ë©´ 해당 í…스트를 편집할 수 있습니다. simutrans-124.3/simutrans/text/ko/language.txt000066400000000000000000000020641474050137200215230ustar00rootroot00000000000000언어 ë„움ë§

언어

언어 ì°½ì—서는 ê²Œìž„ì— ì‚¬ìš©ë˜ëŠ” 언어를 바꿀 수 있습니다.

게임 옵션ì—서 ì—´ 수 있으며, 새 게임 만들기 창과 함께 뜹니다.

Simutransì˜ ê¸°ë³¸ 언어는 ì˜ì–´ìž…니다. 다른 언어로 설정하려면, ì—¬ëŸ¬ë¶„ì´ í•˜ê³  ì‹¶ì€ ì–¸ì–´ 옆 ë²„íŠ¼ì„ ëˆ„ë¥´ì„¸ìš”.

언어는 게임하는 ë„중ì—ë„ ë°”ê¿€ 수 있습니다. ê·¸ 때ì—는 게임 ì˜µì…˜ì˜ ì–¸ì–´ 창으로 들어가세요.

언어는 새 ê²Œìž„ì„ ë§Œë“¤ 때 즉시 바뀌며, 게임 ë„중ì—는 언어 ì°½ì„ ë„ìžë§ˆìž ë°”ë€ë‹ˆë‹¤.

ì„ íƒí•œ 언어ì—서 번역ë˜ì§€ ì•Šì€ ë§ì´ 있다면, ê·¸ ë§ë“¤ì€ ì˜ì–´ë¡œ 나타납니다.

Simutrans ë²ˆì—­ì„ ë•ê³  싶으시다면, https://translator.simutrans.com를 방문해주세요.

ê·€í•˜ì˜ ì–¸ì–´ë¡œ Simutrans를 번역 í•  수 있ë„ë¡
https://translator.simutrans.comì„ ë°©ë¬¸í•˜ì‹­ì‹œì˜¤.

simutrans-124.3/simutrans/text/ko/linemanagement.txt000066400000000000000000000215051474050137200227250ustar00rootroot00000000000000노선 관리

노선 관리t

ë™ì¼í•œ 경로를 가진 운송수단ì´ë‚˜ 복수 ìš´ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ 노선 관리 는(ìš´ì†¡ìˆ˜ë‹¨ì´ ì§„í–‰í•˜ê¸° 위해 필요한 재화 ë° ìŠ¹ê°ì˜ 경로 ë° ìµœì†Œ 수량 )ë“¤ì„ ê´€ë¦¬í•˜ê¸° 위한 정보와 제어를 제공한다.

ì„ ì€ ì°¨ëŸ‰ 픽업 ë° ë“œë¡­ 오프 ìƒí’ˆë“¤ ë° ìŠ¹ê°ë“¤(물 운송 ì°¨ëŸ‰ì´ ë¶€ë‘ì˜ ìœ ì—­ êµ¬ì—­ì— ìžˆëŠ” 모든 정사ê°í˜• ë¬¼ì„ ì‚¬ìš©í•˜ëŠ”) ê³¼ 경유지(ë‘ ê°œ ì´ìƒì˜ ì˜µì…˜ì´ ê°€ëŠ¥í•œ 경우 ì°¨ëŸ‰ì„ ì§ì ‘ 연결하거나 중간 목ì ì§€ ì§€ì ì„ 제공하는 ë° ì‚¬ìš©)로 구성ë©ë‹ˆë‹¤.

게임 보기 맨 ìœ„ì— ìžˆëŠ” ë„¤íŠ¸ì›Œí¬ ì•„ì´ì½˜ì„ í´ë¦­í•˜ê±°ë‚˜ [w]를 눌러 노선 ê´€ë¦¬ì„ ì—½ë‹ˆë‹¤. ì´ ìž‘ì—…ì€ ìž¬ì¡°ì • í¬ê¸°ë¥¼ 다시 ì¡°ì •í•  수 있습니다(ì›ëž˜ í¬ê¸°ì—서 아래쪽 화살표 í´ë¦­).

노선 ê´€ë¦¬ì˜ ì™¼ìª½ì—는 전송 유형으로 í•„í„°ë§í•  수 있는 기존 ë¼ì¸ì´ 나열ë˜ì–´ 있습니다(ëª©ë¡ ì˜¤ë¥¸ìª½ì— ìžˆëŠ” 슬ë¼ì´ë” ë°” 사용). 위 목ë¡ì—서 index-tab를 í´ë¦­í•˜ì—¬ ë‹¤ìŒ í•­ëª©
ì„ ì„ íƒí•©ë‹ˆë‹¤. ì „ë¶€: 모든 ì°¨ëŸ‰ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
기차:모든 ì² ë„ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
모노레ì¼:모든 모노레ì¼/í™”ê±°ë¦¬ì°¨ëŸ‰ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
기차: 모든 ì „ì°¨ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
트럭: 모든 ë„ë¡œì°¨ëŸ‰ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
ë°°: 모든 ìˆ˜ì†¡ì°¨ëŸ‰ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
í•­ê³µ: 모든 í•­ê³µê¸°ì— ê´€í•œ ì„ ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.

목ë¡ì— 나타나는 ì„ ì˜ ìƒ‰ìƒì€ 다ìŒì„ 나타냅니다.:
하양 - ë¼ì¸ì— í• ë‹¹ëœ ì°¨ëŸ‰ì´ì—†ìŠµë‹ˆë‹¤.
노랑 - ìš´ì˜ë˜ì§€ 않고 ì´ë“ê³¼ ì†ì‹¤ì„ ë°œìƒì‹œí‚¤ì§€ 않습니다.
ê²€ì€ - ì´ë“ì„ ë§Œë“­ë‹ˆë‹¤.
파랑 - 쓸모없는 ì°¨ëŸ‰ì„ ê°€ì§€ê³  있습니다.
빨간 - ì„ ì´ ì†ì‹¤ì„ 만듭니다.

ì•„ëž˜ì— ì¡´ìž¬í•˜ëŠ” ì„ ë“¤ì˜ ë‚˜ì—´ì€ ì„ ë“¤ì„ ê´€ë¦¬í•˜ê¸°ìœ„í•œ ì„ íƒ-버튼들ì´ë‹¤.
ë¼ì¸ ìž…ë ¥ 목ë¡ì„ í´ë¦­í•˜ì—¬ ì„ íƒ(ì´ë¦„ ê°•ì¡°)하고 ì •ë¥˜ìž¥ì— ê´€í•œ ì •ë³´,수입,그리고 ì„ íƒëœ ì„ ì˜ ìš´ì†¡ìˆ˜ë‹¨ë“¤ì„ ë³¼ìˆ˜ 있습니다.
정류장들 ë˜ëŠ” ìš´ì†¡ìˆ˜ë‹¨ë“¤ì— ëŒ€í•œ 세부 ì •ë³´ê°€ 부분ì ìœ¼ë¡œë§Œ ë³´ì´ëŠ” 경우, 노선 관리 í¬ê¸°ë¥¼ 조정하거나 슬ë¼ì´ë” 막대를 사용하여 정보를 스í¬ë¡¤í•©ë‹ˆë‹¤.

ì™¼ìª½ì˜ ì„ íƒ-ë²„íŠ¼ë“¤ì€ (ì„ íƒì„ í´ë¦­)í¬í•¨í•œë‹¤:

새 노선:ì˜µì…˜ì€ ìŠ¤ì¼€ì¥´(수송 수단 ì—서 진행하기 위해 요구하는 재화와 승ê°ì˜ 경로 ë° ìµœì†Œ 수량)ì„ ì •ì˜í•˜ëŠ” ì»¨íŠ¸ë¡¤ì´ ì—´ë¦½ë‹ˆë‹¤.
필요한 ìˆ˜ì˜ ì •ë¥˜ìž¥ ë˜ëŠ” 경유지를 추가하고 í•„ìš”ì— ë”°ë¼ ëŒ€ê¸° ë ˆë²¨ì„ ì„¤ì •í•œ ë‹¤ìŒ ìŠ¤ì¼€ì¤„ ì»¨íŠ¸ë¡¤ì„ ë‹«ì•„ 새 ë¼ì¸ì„ 만듭니다(제어íŒì˜ 왼쪽 ìƒë‹¨ 모서리ì—서 x í´ë¦­ ë˜ëŠ” 키보드 사용). 새 íšŒì„ ì€ ë²ˆí˜¸ê°€ 할당ë˜ê³  노선 ê´€ë¦¬ì— ë‚˜ì—´ë©ë‹ˆë‹¤.
{íŒ: 새 ë¼ì¸ì„ ìƒì„±í•˜ê¸° ì „ì— ìƒ‰ì¸ íƒ­ì„ ì‚¬ìš©í•˜ì—¬ 전송 ìœ í˜•ì„ ì„ íƒí•©ë‹ˆë‹¤. ì°¨ëŸ‰ë“¤ì€ ê²½ìœ ì§€ì— ìžˆëŠ” 물품과 승ê°ë“¤ì„ 픽업하거나 내려놓지 않는다.}

노선 갱신:ì€ ê¸°ì¡´ 스케쥴(수송 수단가 진행하는 ë° í•„ìš”í•œ 재화와 승ê°ì˜ 경로 ë° ìµœì†Œ 수량)ì„ ë³€ê²½í•˜ê³  관리하기 위한 ì»¨íŠ¸ë¡¤ì„ ì—½ë‹ˆë‹¤. 변경 ì‚¬í•­ì€ ìŠ¤ì¼€ì¤„ 제어를 ë‹«ì€ í›„ 온ë¼ì¸ ì°¨ëŸ‰ì— ì˜í–¥ì„ 미칩니다(왼쪽 ìƒë‹¨ 모서리ì—서 x í´ë¦­).
목ë¡ì—서 노선 ì´ë¦„ì„ í´ë¦­í•˜ì—¬ ì„ íƒ(ì´ë¦„ ê°•ì¡°)한 ë‹¤ìŒ ì˜µì…˜ ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì¼ëžŒí‘œ ì»¨íŠ¸ë¡¤ì„ ì—½ë‹ˆë‹¤.

노선 제거:ì€ ì„ íƒí•œ ë¼ì¸(수송 수단가 ì§„í–‰í•˜ëŠ”ë° í•„ìš”í•œ 재화와 승ê°ì˜ 경로 ë° ìµœì†Œ 수량)ì„ ì‚­ì œí•©ë‹ˆë‹¤.
목ë¡ì—서 노선 ì´ë¦„ì„ í´ë¦­í•˜ì—¬ ì„ íƒ(ì´ë¦„ ê°•ì¡°)한 ë‹¤ìŒ ì˜µì…˜ ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ 제거합니다. 추가 확ì¸ì€ 필요하지 않습니다.

ë…¸ì„ ì„ ì„ íƒí•˜ë©´ 정류장가 ë¼ì¸ 관리"ì˜ ì™¼ìª½ í•˜ë‹¨ì— í‘œì‹œë©ë‹ˆë‹¤. ëª©ë¡ ì •ë¥˜ìž¥ë¥¼ í´ë¦­í•˜ì—¬ 정류장 정보를 엽니다.
ê° ì •ë¥˜ìž¥ì— ëŒ€í•´ ë‚˜ì—´ëœ í•­ëª©ì—는 다ìŒì´ í¬í•¨ë©ë‹ˆë‹¤. ìƒ‰ìƒ ìƒíƒœ ë°”: 색ìƒì€ 과밀ë„와 관련하여 정류장 ì˜ ìž‘ë™ì„ 나타냅니다. ìƒíƒœ-색ìƒì€ ë˜í•œ ì—­ ëª©ë¡ ë° ì •ë¥˜ìž¥ ì •ë³´ì—ë„ ì‚¬ìš©ë˜ë©°, 게임 디스플레ì´ì—서 정류장 ìœ„ì˜ ìƒ‰ìƒ í‘œì‹œì¤„ì— í‘œì‹œë˜ëŠ” 색ìƒê³¼ ë™ì¼í•©ë‹ˆë‹¤:
- ë…¸ë½ìƒ‰: ì€ ìž‘ë™í•˜ì§€ 않습니다.
- ì´ˆë¡ìƒ‰: 개선 불필요합니다.
- 주황색: 개선 가능.
- 빨간색: 개선 ì‚¬í•­ì´ ê¶Œìž¥ë©ë‹ˆë‹¤.
{íŒ: [!]ì„(를) 사용하여 게임 보기ì—서 정류장 ìœ„ì˜ ìƒ‰ìƒ ë§‰ëŒ€ë¥¼ 전환합니다.}
ì •ë¥˜ìž¥ì˜ ìˆ«ìž(simuconf.tabì—서 ì˜µì…˜ì„ ì„ íƒí•œ 경우 정류장 번호가 부여ë©ë‹ˆë‹¤)입니다
차량 ì•„ì´ì½˜ì€ 정류장를 사용할 수 있는 차량 ìœ í˜•ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤(정류장 ì •ë³´ ë° ì—­ 목ë¡ì—ì„œë„ ì‚¬ìš©ë¨). ì•„ì´ì½˜ì—는 버스(ë„로 승ê°ìš©), 트럭(ë„로 화물용), 기차, 보트 ë° ë¹„í–‰ê¸°ê°€ í¬í•¨ë©ë‹ˆë‹¤. 열차는 ì—­ ì¢…ë¥˜ì— ë”°ë¼ ë²„ìŠ¤-ì•„ì´ì½˜ì´ë‚˜ 기차-ì•„ì´ì½˜ìœ¼ë¡œ 표시할 수 있다.
화물 ì•„ì´ì½˜ì€ ì •ë¥˜ìž¥ì´ ì²˜ë¦¬í•  수 있는 항목(승ê°, ìƒí’ˆ ë° ë©”ì¼)ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤(정류장 ì •ë³´ ë° ì—­ 목ë¡ì—ì„œë„ ì‚¬ìš©ë¨).
{íŒ: ì ì ˆí•œ í™•ìž¥ì„ ì¶”ê°€í•˜ë©´ 정류장ì—서 처리할 수 있는 í•­ëª©ì˜ ë²”ì£¼ë¥¼ 변경할 수 있습니다. 우편물 ì·¨ê¸‰ì„ ìœ„í•´ ìš°ì²´êµ­ì„ ì¶”ê°€í•  수 있습니다.br 대기다양한 ìƒí’ˆê³¼ 승ê°ì— 대한 세부 ì •ë³´

ê·¸ëž˜í”„ì˜ ë…¸ì„  관리 ì •ë³´ ì˜¤ë¥¸ìª½ì— ì„ íƒí•œ ë¼ì¸ì— 대한 ì´ë¦„ ìƒìžì™€ 수송 수단 목ë¡ì´ 표시ë©ë‹ˆë‹¤.

목ë¡ì—서 ë…¸ì„ ëª…ì„ í´ë¦­í•˜ì—¬ ì„ íƒí•©ë‹ˆë‹¤(ì´ë¦„ ê°•ì¡°). 옵션 ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ ì„ íƒí•œ 노선과 ì—¬ê¸°ì— í• ë‹¹ëœ ì°¨ëŸ‰ì— ëŒ€í•œ 정보를 그래프ì—서 전환합니다(xì¶•ì€ ì›” 단위 시간).

- ë‚¨ì€ ìˆ˜ìš©ëŸ‰ - ìƒí’ˆê³¼ 승ê°ì„ 위한 차량 ë‚´ 여유 ê³µê°„ì˜ ì–‘

-ì´ìš©ëŸ‰ - ë…¸ì„ ì„ ì‚¬ìš©í•œ ìƒí’ˆê³¼ 승ê°ì˜ ì–‘.

-수입 - 차량ì—서 ë°œìƒí•œ 소ë“ì˜ ì–‘

- ìš´ì˜ ë¹„ìš© - 운송 중 ì°¨ëŸ‰ì— ì˜í•´ ë°œìƒí•˜ëŠ” 비용.

노선: 수송 ìˆ˜ë‹¨ì´ ì´ìš©í•˜ê³  있는 노선명과 ê·¸ê²ƒì´ ì°¨ê³  있는지 보여준다.
그래프 보드 위 í•­ëª©ì˜ í˜„ìž¬ 레벨과 êµ¬ì„±ì„ ë³´ì—¬ì¤€ë‹¤.

-ì´ìµ- 소ë“으로 ë°œìƒëœ ë¹„ìš©ì´ ê°ì†Œí•¨(ìš´ì˜ ë¹„ìš© ê°ì†Œ).

- 수송 수단- ë¼ì¸ì— í• ë‹¹ëœ ìš´ì†¡ ìˆ˜ë‹¨ì˜ ìˆ˜ìž…ë‹ˆë‹¤.

노선명 바꾸기: 목ë¡ì—서 ë…¸ì„ ëª…ì„ í´ë¦­í•˜ì—¬ ì„ íƒ(ì´ë¦„ ê°•ì¡°)한 ë‹¤ìŒ ì´ë¦„ ìƒìžë¥¼ í´ë¦­í•˜ê³ (그래프 옵션ì—서 ìœ„ì— í‘œì‹œëœ ìˆ˜ì†¡ 수단) 새 ì´ë¦„ì„ ìž…ë ¥í•©ë‹ˆë‹¤.

ë…¸ì„ ì„ ì„ íƒí•˜ë©´(목ë¡ì—서 ë…¸ì„ ëª…ì„ í´ë¦­í•˜ì—¬ ê°•ì¡° 표시) ë¼ì¸ì— í• ë‹¹ëœ ìˆ˜ì†¡ 수단 ê°€ 그래프 ì•„ëž˜ì— ë‚˜ì—´ë©ë‹ˆë‹¤.
차량 ëª©ë¡ ìƒë‹¨ì—는 ë¼ì¸ìœ¼ë¡œ ë°°ì •ëœ ì´ ìˆ˜ì†¡ 수단 수, 소ë“(ìš´ì˜ ë¹„ìš© ê°ì†Œ), 수용량 ë° ìš´ë°˜í•œ 재화와 승ê°ì˜ 현재 수량(ì´ ìˆ˜ìš©ëŸ‰ 중 괄호 ì•ˆì— í‘œì‹œ)ì´ ìžˆë‹¤.
ë‚˜ì—´ëœ í•­ëª©ì„ í´ë¦­í•˜ë©´ 해당 ìš´ì†¡ìˆ˜ë‹¨ì— ëŒ€í•œ ìžì„¸í•œ 정보를 ë³¼ 수 있습니다(슬ë¼ì´ë” 바를 사용하여 목ë¡ì„스í¬ë¡¤).
ê° ìš´ì†¡ìˆ˜ë‹¨ì— ëŒ€í•´ ë‚˜ì—´ëœ í’ˆëª©ì€ ë‹¤ìŒê³¼ 같습니다. ì´ë¦„(기본ì ìœ¼ë¡œ ì´ê²ƒì€ 첫 번째 차량 장치를 구매 하거나 수송 수단를 위해 조립ë¨)ì˜í•´ 할당 ë˜ì–´ì§„다.
ìˆ˜ìž…ì€ ìˆ˜ìµì„ 나타냅니다(소ë“으로 ì¸í•´ ìš´ì˜ ë¹„ìš©ì´ ì ˆê°ë¨).
노선: 수송 ìˆ˜ë‹¨ì´ ì´ìš©í•˜ê³  있는 노선명과 ê·¸ê²ƒì´ ì°¨ê³  있는지 보여준다.
그래픽 보드 위 í•­ëª©ì˜ í˜„ìž¬ 레벨과 êµ¬ì„±ì„ ë³´ì—¬ì¤€ë‹¤.

simutrans-124.3/simutrans/text/ko/list.txt000066400000000000000000000035731474050137200207210ustar00rootroot00000000000000ëª©ë¡ ë„움ë§

목ë¡

목ë¡ì—는 ê²Œìž„ì˜ í˜„ìž¬ ìƒíƒœì— 대한 정보를 위한 ì»¨íŠ¸ë¡¤ì„ ì—¬ëŠ” ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤. (ë˜í•œ 다른 물품, 승ê°, ìš°íŽ¸ë¬¼ì˜ ìš´ì†¡ì—서 받는 ìƒëŒ€ì  소ë“ì„ ì¡°ì •í•˜ëŠ” 통제).

플레ì´ì–´ì˜ ì •ë³´ 목ë¡: 정류장; 수송 수단; ë„시 지역; 다른ìƒí’ˆ, 승ê°, 우편ì—서 받는 수입; ì‚°ì—…; 그리고 관광명소.

게임 ë·° ìƒë‹¨ì— 있는 ì•„ì´ì½˜ 목ë¡ì„ í´ë¦­í•˜ì—¬ 엽니다. 목ë¡.
ë„구 모ìŒì„ 열거나 í´ë¦­í•œ 후 목ë¡-툴-ì˜µì…˜ì„ ë§ˆìš°ìŠ¤ë¡œ 가리키면 ì´ë¦„ì´ í‘œì‹œë©ë‹ˆë‹¤.

ë„구 ì˜µì…˜ì„ í´ë¦­í•˜ì—¬ 정보를 위한 ì»¨íŠ¸ë¡¤ì„ ì—½ë‹ˆë‹¤.:

ì—­ 목ë¡: 정류장, ìš´ì†¡ìˆ˜ë‹¨ì´ í™”ë¬¼ê³¼ 승ê°ë“¤ì„ 픽업하거나 하차하는 장소입니다. (í•´ì–‘ 운송 ìˆ˜ë‹¨ì„ ìœ„í•œ 경유지는 없습니다).

운송 수단 목ë¡: 길과 ì² ë„ ìˆ˜ì†¡ 수단, 항공기와 해양선박들.

모든 ë„시 목ë¡: ë„시 지역 (마ì„, (소)ë„시 그리고 (대)ë„시).

모든 ìƒí’ˆ 목ë¡: ê°ê°ì˜ ìƒí’ˆ, ìŠ¹ê° ë° ìš°íŽ¸ì—서 ë°›ì€ ì†Œë“(ìƒëŒ€ì†Œë“ì„ ì¡°ì •í•˜ëŠ” 통제 í¬í•¨).

공장 목ë¡: 공업 (ìƒí’ˆì˜ 소비ìžì™€ 공급ìž).

관광지 목ë¡: 관광 명소.

simutrans-124.3/simutrans/text/ko/load.txt000066400000000000000000000031431474050137200206560ustar00rootroot00000000000000ë„ì›€ë§ ë¶ˆëŸ¬ì˜¤ê¸°

불러오기

불러오기는 ì €ìž¥ëœ ê²Œìž„ì„ ë‹¤ì‹œ 시작하고 (계ì†í•˜ë ¤ë©´) ê²Œìž„ì„ ì‚­ì œí•˜ëŠ” ë° ì‚¬ìš©í•  수 있습니다. 다시 ì‹œìž‘ëœ ê²Œìž„ì€ ìžƒì–´ë²„ë¦° 현재 세계를 대체합니다.

불러오기는 새로운 세계 ë° ê²Œìž„ 옵션 만들기ì—서 ë˜ëŠ” [L]ì„ ëˆŒëŸ¬ 열립니다. 그리고 사용 가능한 ê²Œìž„ì˜ ì´ë¦„ê³¼ ë‚ ì§œ ë° ì‹œê°„ì„ ì €ìž¥í•©ë‹ˆë‹¤.

ê²Œìž„ì„ ë‹¤ì‹œ 시작하려면 목ë¡ì— 있는 ì´ë¦„ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤; ë˜ëŠ” ë¶ˆëŸ¬ì˜¤ê¸°ì˜ ìƒë‹¨ ìƒìž ì•ˆì— ì´ë¦„ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤: ìƒìžë¥¼ í´ë¦­í•˜ê³  ì´ë¦„ì„ ìž…ë ¥í•œ ë‹¤ìŒ [Enter] ë˜ëŠ” [Return]ì„ ëˆ„ë¥´ê±°ë‚˜ 확ì¸ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. ìž˜ëª»ëœ ì´ë¦„ì€ ì˜¤ë¥˜ 메시지를 수신합니다: 메시지를 ë‹«ê³  다시 시ë„하십시오.

경고: ê²Œìž„ì„ ì¦‰ì‹œ & ì˜êµ¬ì ìœ¼ë¡œ 삭제하려면 ì´ë¦„ì— ë”°ë¼ x ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
ì´ ê¸°ëŠ¥ì„ ì£¼ì˜í•˜ì—¬ 사용하십시오.

중요사항: Simutransì˜ ìƒˆë¡œìš´ 릴리스는 정기ì ìœ¼ë¡œ 출시ë˜ë©° ì´ì „ ë²„ì „ì˜ Simutrans는 ì´í›„ 버전ì—서 ìž‘ë™í•˜ì§€ ì•Šì„ ìˆ˜ 있습니다; ì´ì „ ê²Œìž„ì´ í˜¸í™˜ë˜ëŠ”ì§€ 확ì¸í•˜ë ¤ë©´ 최신 ë²„ì „ì˜ ì¶œì‹œ 노트를 ì½ì–´ë³´ì‹­ì‹œì˜¤.

불러오기를 닫으려면 취소를 í´ë¦­í•˜ì‹­ì‹œì˜¤; ë˜ëŠ” 왼쪽 ìƒë‹¨ì˜ x를 í´ë¦­í•˜ì‹­ì‹œì˜¤; ë˜ëŠ” 키보드를 사용하십시오.

simutrans-124.3/simutrans/text/ko/load_relief.txt000066400000000000000000000035421474050137200222070ustar00rootroot00000000000000Height Map ë„ì›€ë§ ë¶ˆëŸ¬ì˜¤ê¸°

Height Map 불러오기

Height Map 불러오기 윈ë„우를 사용하여 ì‚¬ìš©ìž ì§€ì • ì§€í˜•ì˜ íŒŒì¼ì„ ì—´ê³ (새 ê²Œìž„ì„ ë§Œë“¤ 때 사용) ì´ëŸ¬í•œ 파ì¼ì„ 삭제할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. 새 게임 ìƒì„± ì°½ì—서 열리며 사용 가능한 ì‚¬ìš©ìž ì •ì˜ ì§€ì—­ 파ì¼ì˜ ì´ë¦„, ë‚ ì§œ ë° ì‹œê°„(저장)ì´ ë‚˜ì—´ë©ë‹ˆë‹¤. ì¼ë¶€ íŒŒì¼ ì´ë¦„ì´ ë³´ì´ì§€ 않으면 ëª©ë¡ ì˜¤ë¥¸ìª½ì— ìžˆëŠ” 슬ë¼ì´ë” 바를 사용하여 ì´ë¦„ì„ ìŠ¤í¬ë¡¤í•©ë‹ˆë‹¤.

목ë¡ì—서 ì´ë¦„ì„ í´ë¦­í•˜ì—¬ ì‚¬ìš©ìž ì§€ì • ì˜ì—­ ì§€ë„를 불러오거나 ì°½ ìœ„ìª½ì˜ í…스트 ìƒìžì— ì´ë¦„ì„ ìž…ë ¥í•©ë‹ˆë‹¤: ìƒìžë¥¼ í´ë¦­í•˜ê³  ì´ë¦„ì„ ìž…ë ¥í•˜ê³  [Enter] ë˜ëŠ” [Return]를 누르거나 확ì¸ì„ í´ë¦­í•©ë‹ˆë‹¤ (ìž˜ëª»ëœ ì´ë¦„ì€ ì˜í–¥ì„ 미치지 않습니다. 다시 시ë„해야합니다).

경고: ì´ë¦„ ì™¼ìª½ì— ìžˆëŠ” x-버튼(simuconf.tab으로 ì„¤ì •ëœ ê²½ìš°)ì„ í´ë¦­í•˜ì—¬ 파ì¼ì„ 즉시 ì˜êµ¬ì ìœ¼ë¡œ 삭제합니다; 목ë¡ì—서 íŒŒì¼ ì´ë¦„ì´ ì œê±°ë˜ê³  Height Map ë¶ˆëŸ¬ì˜¤ê¸°ì°½ì´ ë‹«íž™ë‹ˆë‹¤. ì´ ê¸°ëŠ¥ì€ ì£¼ì˜í•´ì„œ 사용하셔야 합니다!

ì¼ë¶€ 커스텀-ì§€í˜•ë“¤ì€ http://maps.simutrans.com ì—서 다운받아야 ì´ìš©í•  수 있습니다. 새 파ì¼ì€ .ppm ë˜ëŠ” .bmp 형ì‹(최ìƒì˜ 256색 RLE ì••ì¶•)ì´ì–´ì•¼ 하며 simutrans/maps/ ë””ë ‰í† ë¦¬ì— ë°°ì¹˜ë˜ì–´ì•¼ 합니다.

íŒ: 커스텀 ì§€í˜•ì„ ë§Œë“œëŠ” ë°©ë²•ì€ http://wiki.simutrans.comì—서 ë³¼ 수 있습니다.

취소를 í´ë¦­í•˜ì—¬ Height Map ë¶ˆëŸ¬ì˜¤ê¸°ì°½ì„ ë‹«ê±°ë‚˜ 좌측 ìƒë‹¨ì˜ x-버튼 ë˜ëŠ” 키보드를 ì´ìš©í•˜ì—¬ ë‹«ì„ ìˆ˜ 있다.

simutrans-124.3/simutrans/text/ko/mailbox.txt000066400000000000000000000050641474050137200213760ustar00rootroot00000000000000메시지 센터 & 메시지 센터 옵션 ë„움ë§

메시지 센터

메시지 센터는 ê²Œìž„ì˜ ë©”ì‹œì§€ë¥¼ 나열하고 게임ì—서 메시지가 표시ë˜ëŠ” ë°©ì‹ì„ ì„ íƒí•˜ëŠ” 관리 ì„¤ì •ì„ ì—½ë‹ˆë‹¤.

게임 ì‹œì  ìƒë‹¨ì˜ 사서함 ì•„ì´ì½˜ì„ í´ë¦­í•˜ê±°ë‚˜ [B]를 눌러 메시지 센터를 ì—´ë©´ ê²Œìž„ì˜ ë©”ì‹œì§€ê°€ 나열ë©ë‹ˆë‹¤.
게임 시ì ì„ 관련 위치로 ì´ë™í•˜ë ¤ë©´ 메시지를 í´ë¦­í•˜ì‹­ì‹œì˜¤.

옵션 버튼 (사용하려면 í´ë¦­í•˜ì‹­ì‹œì˜¤)ì€ ë©”ì‹œì§€ 표시 ë°©ë²•ì„ ê²°ì •í•˜ëŠ” ì»¨íŠ¸ë¡¤ì´ ìžˆëŠ” 메시지 센터 ì˜µì…˜ì„ ì—½ë‹ˆë‹¤.


메시지 센터 옵션

메시지 센터 옵션ì—는 메시지 표시 ë°©ë²•ì„ ì„ íƒí•˜ëŠ” 세 ê°œì˜ ì—´ì´ ìžˆìŠµë‹ˆë‹¤.

왼쪽ì—서 오른쪽으로, ì—´ì€ ë©”ì‹œì§€ê°€ 다ìŒê³¼ ê°™ì´ í‘œì‹œë ì§€ 여부를 ì„ íƒí•©ë‹ˆë‹¤: 게임 ì‹œì  í•˜ë‹¨ì˜ ìŠ¤í¬ë¡¤ í…스트; 임시 메시지; ë˜ëŠ” ì˜êµ¬ 메시지.
{íŒ: ë©”ì‹œì§€ì˜ ì™¼ìª½ ìƒë‹¨ 모서리ì—있는 x를 í´ë¦­í•˜ê±°ë‚˜ 키보드를 사용하여 ì˜êµ¬ 메시지를 닫습니다.}

ë‹¤ìŒ ë©”ì‹œì§€ì— ëŒ€í•œ 메시지 옵션 (단추를 들여쓰기할 때 ì„ íƒ)ì„ ì„ íƒí•˜ë ¤ë©´ 사ê°í˜• 단추를 í´ë¦­í•˜ì‹­ì‹œì˜¤:

ì‹ ë…„: ì‹ ë…„ì´ ì‹œìž‘ë˜ì—ˆìŠµë‹ˆë‹¤.

AI 뉴스: AI 플레ì´ì–´ê°€ 새로운 ë…¸ì„ ì„ ì—´ì—ˆìŠµë‹ˆë‹¤.

ë„시 뉴스: ë„시 ì§€ì—­ì€ ë” í° íƒ€ìš´í™€ì„ ë§Œë“¤ê³  있습니다.

경로 ì—†ìŒ: ì°¨ëŸ‰ì€ ë‹¤ìŒ ëª©ì ì§€ (정류장 ë˜ëŠ” 경유지)ê¹Œì§€ì˜ ê²½ë¡œë¥¼ ì°¾ì„ ìˆ˜ 없습니다.

새로운 ì‚°ì—…: ë„시 성장으로 ì¸í•´ 새로운 ì‚°ì—… ì²´ì¸ (최종 ì†Œë¹„ìž ë° í•„ìš”í•œ 공급ìž)ì´ ê±´ì„¤ë˜ì—ˆìŠµë‹ˆë‹¤.

관광: ë„시 관광지나 기ë…íƒ‘ì´ ì„¸ì›Œì¡ŒìŠµë‹ˆë‹¤.

새로운 차량: 새 ì°¨ëŸ‰ì„ ì‚¬ìš©í•  수 있게 ë˜ê±°ë‚˜ ì°¨ëŸ‰ì´ í기ë©ë‹ˆë‹¤ (타임ë¼ì¸ì´ 사용ë˜ëŠ” 경우).

ì—­ 혼잡: ì—­ì€ ë§¤ìš° ë¶ë¹•니다.

문제: 플레ì´ì–´ 회사ì—는 부채 ë° ê¸°íƒ€ 비íŒì ì¸ 메시지가 있습니다.

simutrans-124.3/simutrans/text/ko/map.txt000066400000000000000000000172011474050137200205140ustar00rootroot00000000000000ì§€ë„ ì°½ ë„움ë§

ì§€ë„ ì°½

ì§€ë„는 지형, 중요한 위치 ë° êµí†µë§ì— 대한 정보를 제공하는 현재 ì„¸ê³„ì˜ ì§€ë„를 제공합니다. ë˜í•œ ì „ 세계로 ì´ë™í•˜ëŠ” ë°©ë²•ì„ ì œê³µí•©ë‹ˆë‹¤.

ìƒë‹¨ 메뉴ì—서 ì§€ë„ ì•„ì´ì½˜ì„ í´ë¦­í•˜ê±°ë‚˜ [m]ì„ ëˆŒëŸ¬ ì§€ë„를 ì—´ë©´ í¬ê¸°ê°€ 재조정ë˜ê±°ë‚˜ ìµœì†Œí™”ë  ìˆ˜ 있습니다. 가장 ìœ„ì— ìžˆëŠ” 3ê°œì˜ ë²„íŠ¼ìœ¼ë¡œ 추가 ì˜µì…˜ì„ ì‚¬ìš©í•  수 있습니다.
 ì„ íƒ 항목ì—는 ì§€ë„ì˜ ì¶”ê°€ 정보를 ë®ì–´ì”Œìš°ëŠ” 다양한 ë²„íŠ¼ì´ í‘œì‹œë©ë‹ˆë‹¤.
 ìƒ‰ìƒ 코드는 ì¼ë¶€ ì˜µì…˜ì— ëŒ€í•œ í™œë™ ìˆ˜ì¤€ì„ ë³´ì—¬ì£¼ëŠ” 최소-최대 ìƒ‰ìƒ í¬ê¸°ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤.
 ì‚°ì—… 목ë¡ì€ ì§€ë„ì— í‘œì‹œëœ ì‚°ì—…ì˜ ìƒ‰ìƒì„ 가진 í…Œì´ë¸”ì„ ì—½ë‹ˆë‹¤.

ì§€ë„ì—는 다른 확대 / 축소 ìˆ˜ì¤€ì´ ìžˆìŠµë‹ˆë‹¤: 마우스 휠, 페ì´ì§€ 위/ 아래 ë˜ëŠ” ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ 변경하십시오. ë“±ê° íˆ¬ì˜ì§€ë„ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ ì§€ë„를 기울여 디스플레ì´ì™€ ì¼ì¹˜ì‹œí‚¬ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.

ì§€ë„ì—서 ë¬¼ì€ íŒŒëž€ìƒ‰ì´ê³  ë‚®ì€ ë•…ì€ ë†’ì€ ë•…ë³´ë‹¤ ë” ì–´ë‘¡ìŠµë‹ˆë‹¤. 현재 í™”ë©´ì— ë³´ì´ëŠ” ì„¸ê³„ì˜ ì¼ë¶€ëŠ” 노란색 사ê°í˜• 윤곽으로 표시ë©ë‹ˆë‹¤. ì´ ì‹œì•¼ë¥¼ 전세계로 ì´ë™í•˜ë ¤ë©´ ì›í•˜ëŠ” 위치ì—서 ì§€ë„를 마우스 왼쪽 버튼으로 í´ë¦­í•˜ê±°ë‚˜ 노란색 사ê°í˜•ì„ ë§ˆìš°ìŠ¤ 왼쪽 버튼으로 드래그합니다. 마우스 오른쪽 ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ 스í¬ë¡¤ 바를 사용하지 않고 ì§€ë„ ì°½ì—서 ì˜ì—­ì„ ì´ë™í•  수 있습니다.

기본 ì§€ë„ì—서 (ì˜µì…˜ì„ ì‚¬ìš©í•˜ì§€ ì•Šì„ ë•Œ) ë„시 지역과 관광지는 회색, ì „ë ¥ì„ ì€ ì²­ë¡ìƒ‰, í„°ë„ì€ ê°ˆìƒ‰, ê³ ê°€ ë„로는 ë°ì€ 갈색, 다리는 ë°ì€ 회색입니다. ì§€ìƒì˜ 길ì—는 ê³ ìœ ì˜ ìƒ‰ìƒì´ 있습니다: ë„로는 ê±°ì˜ ê²€ì€ìƒ‰ìœ¼ë¡œ 보입니다; ë ˆì¼ê³¼ 노면 ì „ì°¨ íŠ¸ëž™ì€ ì–´ë‘ìš´ 갈색; 수로는 파란색; 활주로는 진한 노란색입니다. 다른 모든 방법 (ì¢ì€ 게ì´ì§€, ìžê¸° ë¶€ìƒ ì² ë„ ë˜ëŠ” ëª¨ë…¸ë ˆì¼ íŠ¸ëž™ê³¼ ê°™ì€)ì€ ë°ì€ 빨간색입니다. ì •ë¥˜ìž¥ì€ ë¹¨ê°„ìƒ‰ìž…ë‹ˆë‹¤. ê¸¸ì— ìžˆëŠ” ì°¨ëŸ‰ì€ ë…¸ëž€ìƒ‰ìž…ë‹ˆë‹¤.

버튼 네트워í¬ëŠ” ì§€ë„ ìƒì˜ 지하철 노선ë„와 ê°™ì€ ì¶”ìƒì ì¸ 노선 네트워í¬ë¥¼ ë®ì–´ì”Œì›ë‹ˆë‹¤. 노란색 ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ 승ê°, 우편물 ë˜ëŠ” 화물 ì—°ê²°ë§Œ 표시하ë„ë¡ ì œí•œí•  수 있습니다.

ì„ íƒ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ ë§Žì€ ì¶”ê°€ 정보를 중첩할 수 있습니다. ì´ë“¤ì€ 세 그룹으로 나뉩니다. í°ìƒ‰ê³¼ 노란색 ë²„íŠ¼ì€ ë…ì ì ì´ë©° 다른 모든 í°ìƒ‰ ì˜µì…˜ì„ ë¹„í™œì„±í™”í•©ë‹ˆë‹¤. 녹색 ë²„íŠ¼ì€ ë‹¤ë¥¸ 버튼과 ê²°í•©í•  수 있는 중첩용 버튼입니다. 세 번째 ê·¸ë£¹ì€ ì •ë¥˜ìž¥ì„ ìœ„í•œ 빨간 버튼입니다.

다ìŒì˜ ì˜µì…˜ì´ ì¡´ìž¬í•©ë‹ˆë‹¤:

ë„시 ì§€ì—­ì˜ ë„시 ì´ë¦„.
ë„시 í•œê³„ì€ ë„ì‹œì˜ í•œê³„ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤; 새로운 주íƒê³¼ ë„로는 ë„ì‹œì˜ í•œë„ ë‚´ì—서만 지어집니다.
ê±´ë¬¼ì€ ê° ë„ì‹œì˜ ê±´ë¬¼ ë ˆë²¨ì— ë”°ë¼ ìƒ‰ìƒì´ 지정ë©ë‹ˆë‹¤. ë ˆë²¨ì— ë”°ë¼ ìŠ¹ê° ë˜ëŠ” ìš°íŽ¸ë¬¼ì„ ìƒì„±í•  í™•ë¥ ì´ ê²°ì •ë©ë‹ˆë‹¤.
목ì ì§€ë¡œ ë„시가 ì„ íƒëœ 경우, ì´ ì˜µì…˜ì€ í˜„ìž¬ 승ê°ì˜ 목ì ì§€ë¥¼ ë®ì–´ì”Œì›ë‹ˆë‹¤ (ë„시 ì •ë³´ì˜ ìž‘ì€ ì§€ë„와 유사.)
관광지는 관광 ëª…ì†Œì˜ ìœ„ì¹˜ì— ì›ì„ 그립니다. 색ìƒê³¼ í¬ê¸°ëŠ” ì´ ê´€ê´‘ 명소가 ìƒì„±í•˜ëŠ” êµí†µëŸ‰ì„ 나타냅니다 (최소-최대 규모 사용).
공장: ì‚°ì—… (ì†Œë¹„ìž ë° ê³µê¸‰ìž)ì„ ê°•ì¡° 표시합니다. ì´ëŸ¬í•œ ì¤‘ì²©ì´ í™œì„±í™”ë˜ì–´ 있고 마우스 í¬ì¸í„°ê°€ ì§€ë„ ìƒì˜ ì‚°ì—…ì„ ê°€ë¦¬í‚¤ëŠ” 경우, ê³ ê°ì„ 연결하는 ì´ë¦„ê³¼ í°ìƒ‰ ì„ ì´ í‘œì‹œë©ë‹ˆë‹¤. 공급ìžì—게 빨간 ì„ ì„ í‘œì‹œí•˜ë ¤ë©´ [Shift]를 누르십시오. 색ìƒì€ ì‚°ì—… 목ë¡ì—서 ë³¼ 수 있는 ì‚°ì—…ì˜ ìƒ‰ìƒìž…니다.
승ê°ì€ ê° ì†Œìœ ìžì˜ 색ìƒìœ¼ë¡œ 승ê°ì„ 위한 ìš´í–‰ ê¶Œì—­ì„ ì •ë¥˜ìž¥ë³„ 색ìƒìœ¼ë¡œ 표시합니다. ë„¤íŠ¸ì›Œí¬ ì¤‘ì²©ì´ í™œì„±í™”ë˜ì–´ 있는 경우, ìŠ¹ê° ì—°ê²°ë§Œ 표시ë©ë‹ˆë‹¤.
ìš°íŽ¸ë¬¼ì€ ê° ì†Œìœ ìžì˜ 색ìƒìœ¼ë¡œ 우편물 배송 ê¶Œì—­ì„ ì •ë¥˜ìž¥ë³„ 색ìƒìœ¼ë¡œ 표시합니다. ë„¤íŠ¸ì›Œí¬ ì¤‘ì²©ì´ í™œì„±í™”ë˜ì–´ 있는 경우, ìŠ¹ê° ì—°ê²°ë§Œ 표시ë©ë‹ˆë‹¤.
모든 방법으로 운송ë˜ëŠ” 화물 ë° ìŠ¹ê°ì˜ 화물 레벨 (최소-최대 규모 사용). ë„¤íŠ¸ì›Œí¬ ì¤‘ì²©ì´ í™œì„±í™”ë˜ì–´ 있는 경우, 화물 ì—°ê²°ë§Œ 표시ë©ë‹ˆë‹¤.
정류장 ìƒíƒœëŠ” (ë° ì´í›„ì˜ ëª¨ë“  빨간색 옵션) ì›ì„ 기준으로한 ì •ë¥˜ìž¥ì„ ê°•ì¡° 표시합니다. 정류장 ìƒíƒœ 색ìƒì€ ì •ë¥˜ìž¥ì˜ í˜¼ìž¡ ìƒíƒœë¥¼ 나타냅니다. ì—­ 목ë¡ì˜ ìƒíƒœ-색ìƒ-ë°”, 정류장 ì •ë³´, 노선 관리, 마지막으로 ì •ë¥˜ìž¥ì˜ ì´ë¦„ ìœ„ì— ìžˆëŠ” 색ìƒ-ë°”ì— ë™ì¼í•œ 색ìƒì´ 표시ë©ë‹ˆë‹¤. í¬ê¸°ëŠ” 승ê°ì— 대한 ì •ë¥˜ìž¥ì˜ ìˆ˜ìš©ëŸ‰ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤.
대기는 ì •ë¥˜ìž¥ì— ìš´ì†¡ 대기 ì¤‘ì¸ ìŠ¹ê°, 우편물 ë° í™”ë¬¼ì˜ ì–‘ì„ í‘œì‹œí•©ë‹ˆë‹¤. ìƒ‰ìƒ ë° í¬ê¸°ëŠ” 대기 ì¤‘ì¸ ì–‘ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤ (최소-최대 ìŠ¤ì¼€ì¼ ì‚¬ìš©).
íìž‰ì€ ì´ë²ˆ 달 ì•ˆì— ìŠ¹ê°, 우편물 ë° ê¸°ë‹¤ë¦¬ëŠ” í™”ë¬¼ì˜ ì–‘ì´ ì–¼ë§ˆë‚˜ ë§Žì´ ë³€ê²½ë˜ì—ˆëŠ”ì§€ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤. í¬ê¸°ëŠ” ì „ì²´ ë³€ê²½ì„ ë‚˜íƒ€ë‚´ë©° 색ìƒì€ ê°ì†Œ 시 녹색ì´ê³  ì¦ê°€ì‹œ 빨간색입니다 (최소-최대 배율 사용).
서비스 색ìƒê³¼ í¬ê¸°ëŠ” ì´ë²ˆ ë‹¬ì— ì—­ì„ ìš´ì˜í•œ 차량 수를 나타냅니다 (최소-최대 규모 사용).
전송 í¬ê¸° ë° ìƒ‰ìƒì€ ì—­ì—서 얼마나 ë§Žì€ ì‚¬ëžŒë“¤ì´ ë„ì°©/ 출발했는지 나타냅니다 (최소-최대 규모 사용).
출발지 색ìƒê³¼ í¬ê¸°ëŠ” 정류장ì—서 ì—¬í–‰ì„ ì‹œìž‘í•˜ë ¤ëŠ” 승ê°ê³¼ ìš°íŽ¸ë¬¼ì˜ ìˆ˜, 즉 행복하고 불행한 승ê°ì´ì—†ëŠ” 경우를 ë³´ì—¬ì¤ë‹ˆë‹¤ (최소-최대 규모 사용).
êµí†µëŸ‰ì€ 한 달 ì•ˆì— ì§€ë‚˜ê°€ëŠ” 차량 ìˆ˜ì— ë”°ë¼ ìƒ‰ìƒì„ 바꿉니다 (최소-최대 ìŠ¤ì¼€ì¼ ì‚¬ìš©).
ì„ ë¡œë ˆì¼ ë° ë…¸ë©´ì „ì°¨ 트랙, êµëŸ‰ ë° í„°ë„ì€ í°ìƒ‰ (전기ë¼ë©´ 빨간색)으로 표시ë©ë‹ˆë‹¤. 신호는 노란색으로 표시ë©ë‹ˆë‹¤.
ì†ë„ ì œí•œì€ í—ˆìš©ë˜ëŠ” 최대 ì†ë„와 관련하여 모든 ë©´ì—서 색ìƒì„ 지정합니다 (최소-최대 ìŠ¤ì¼€ì¼ ì‚¬ìš©).
차고는 차고를 ê°•ì¡° 표시합니다. 색ìƒì€ 운송 ìœ í˜•ì„ ë‚˜íƒ€ëƒ…ë‹ˆë‹¤: ì„ ë°•, 노란색; ë„로, 주황색; 선로, 빨간색; 항공기, 녹색; 노면전차, 파란색; 그리고 모노레ì¼, 회색.
ì „ë ¥ì„ ì€ ì†¡ì „ ì„ ë¡œì— ë¶€í•˜ë¥¼ 나타냅니다.
ìˆ²ì€ ë°ì€ 녹색 숲으로 표시ë©ë‹ˆë‹¤.
ì†Œìœ ê¶Œì€ ì§€ë„ì— ìžˆëŠ” 모든 ê²ƒì„ ì†Œìœ ìžì˜ 색ìƒìœ¼ë¡œ 표시합니다 (소유ìžê°€ 없는 경우 주황색).

simutrans-124.3/simutrans/text/ko/monorailtools.txt000066400000000000000000000207571474050137200226520ustar00rootroot00000000000000모노레ì¼/ ìžê¸°ë¶€ìƒ ì—´ì°¨ ë„구 ë„움ë§

모노레ì¼/ ìžê¸°ë¶€ìƒ ì—´ì°¨ ë„구

모노레ì¼/ ìžê¸°ë¶€ìƒ ì—´ì°¨ ë„구는 모노레ì¼/ìžê¸°ë¶€ìƒì—´ì°¨ 수송ë§ì„ 구축합니다. ì´ ë„구는 건설 ë° ì œê±° ìž‘ì—…ì„ ìˆ˜í–‰í•©ë‹ˆë‹¤: 모노레ì¼ê³¼ ìžê¸°ë¶€ìƒ ì—´ì°¨ì˜ íŠ¸ëž™; 다리; í„°ë„; 신호등; ì—­; ì—­ 플랫í¼; 그리고 확장합니다. 플레ì´í•˜ë©° 타임ë¼ì¸ì´ 추가ëœë‹¤ë©´, ì‹œê°„ì´ ì§€ë‚˜ë©´ì„œ Simutransì—서 ë” ë§Žì€ ë„구 ì˜µì…˜ì´ ë‚˜íƒ€ë‚  수 있습니다.

게임 ì‹œì  ë§¨ ìœ„ì— ìžˆëŠ” 모노레ì¼/ìžê¸°ë¶€ìƒ ì—´ì°¨ - ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ ë„구 모ìŒì„ 엽니다.
ë„구 모ìŒì„ 열거나 í´ë¦­í•œ 후 마우스 커서를 ë„구 ì˜µì…˜ì— ê°€ì ¸ê°€ì„œ ì´ë¦„ ë° í•´ë‹¹ë˜ëŠ” 경우 확ì¸: 건설 비용 유지비, 최대 ì†ë„ 제한 ë° ìµœëŒ€ 길ì´.

모노레ì¼/ìžê¸°ë¶€ìƒ ì—´ì°¨ ë„구 ì˜µì…˜ì€ ì™¼ìª½ì—서 오른쪽으로 í¬í•¨í•©ë‹ˆë‹¤:

모노레ì¼ê³¼ ìžê¸°ë¶€ìƒ ì—´ì°¨ì˜ íŠ¸ëž™: ì´ ë„구는 ì„ íƒëœ ë‘ ì§€ì ì— 모노레ì¼ê³¼ ìžê¸°ë¶€ìƒ ì—´ì°¨ì˜ íŠ¸ëž™ì„ ê±´ì„¤í•©ë‹ˆë‹¤, íŠ¸ëž™ì€ ê²½ì‚¬ë©´ 방향으로만 ê²½ì‚¬ë¡œì— ê±´ì„¤ë  ìˆ˜ 있으며, 거친 지형, 물 ë° ìž¥ì• ë¬¼ì„ ê°€ë¡œ 지르는 경로는 ì°¾ì„ ìˆ˜ 없습니다.
새 íŠ¸ëž™ì€ ê²½ë¡œì— ê¸°ì¡´ íŠ¸ëž™ì„ ì‚¬ìš©í•  수 있습니다.
íŠ¸ëž™ì„ ê±´ì„¤í•˜ë ¤ë©´: ë„구를 í´ë¦­í•˜ì—¬ 트랙(커서를 트랙으로 변경)ì„ ì„ íƒí•œ 다ìŒ, 게임 시ì ì˜ 시작ì (마지막 í´ë¦­ 게임 시ì ì— 불ë„ì € 표시), 하단 ë°”ì˜ ê²Œìž„ ì˜¤ë¥¸ìª½ì— ì¢Œí‘œë¥¼ 표시합니다.
{íŒ: 서로 다른 ìœ í˜•ì˜ íŠ¸ëž™ì´ ì—°ê²°ë  ìˆ˜ 있습니다(그러나 ì¼ë¶€ 다른 플레ì´ì–´ë“¤ì— ì˜í•´ 구축ë˜ì§€ ì•Šì€ ê²½ìš°).
지형 ë„구를 ì´ìš©í•˜ì—¬ ì§€í˜•ì„ íŠ¸ëž™ì´ ì§€ë‚˜ê°ˆ 수 있게 변경합니다.
개별ì ì¸ íŠ¸ëž™ì˜ ì¼ë¶€ë¶„ê³¼ ìž¥ì• ë¬¼ì„ ì œê±°í•˜ë ¤ë©´ 파괴/ 제거를 사용하면ë©ë‹ˆë‹¤.
[Ctrl] ì„ ì‚¬ìš©í•˜ì—¬ ë™ì‹œì— 추가 ê¸°ëŠ¥ì„ ìˆ˜í–‰í•  수 있습니다.
마지막 경로 공사를 [z]키로 ì·¨ì†Œí•´ë„ ê³µì‚¬ ë¹„ìš©ì„ í™˜ë¶ˆí•˜ì§€ 않습니다.}

ëª¨ë…¸ë ˆì¼ ì œê±°: ì´ ë„구는 ì°¨ëŸ‰ì´ ì—†ì„ ë•Œ 게임 시ì ì˜ ë‘ ì§€ì  ì‚¬ì´ì— 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ íŠ¸ëž™ì„ ì œê±°í•©ë‹ˆë‹¤(í”Œëž«í¼ ë° ê²½ë¡œ ì‹ í˜¸ë„ ì œê±°ë©ë‹ˆë‹¤).
ë„구를 사용하면 건설 ë¹„ìš©ì´ ë°œìƒí•©ë‹ˆë‹¤.
íŠ¸ëž™ì„ ì œê±°í•˜ë ¤ë©´: ë„구 í´ë¦­(커서를 빨간색 X로 변경);
삭제할 트랙ì—서 ì•” í´ë¦­(게임 ë·°ì—서 빨간색 X 표시 ì‚­ì œ ì§€ì  ì„ íƒ);
그리고 마지막으로 íŠ¸ëž™ì˜ ë‹¤ë¥¸ ì§€ì ì„ í´ë¦­í•˜ì—¬ 첫 번째 ì‚­ì œ ì§€ì ë¶€í„° 마지막 í´ë¦­ ì§€ì ê¹Œì§€ì˜ ë¶€ë¶„ë“¤ì„ ì œê±°í•©ë‹ˆë‹¤.
{íŒ: 트랙 제거를 위한 다른 플레ì´ì–´ì²˜ëŸ¼ í–‰ë™í•©ë‹ˆë‹¤.}

경사로 그리고 êµëŸ‰: ì´ ë„구는 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ê°€ 통과할 수 있ë„ë¡ ê²Œìž„ 시ì ì˜ 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ 트랙 ë‘ ê°œ 사ì´ì— ì§ì„  êµëŸ‰ì„ 구축한다.
êµëŸ‰ì˜ 최대경간.
ì´ ë„구는 선로 ëì—서 ì ì ˆí•œ 장소까지 제작합니다(다른 선로 ë ë˜ëŠ” 약간 ë†’ì€ ì§€ë©´, 범위 ì´ë‚´).
경사로와 êµëŸ‰ì„ 제작하려면: ë„구를 í´ë¦­í•œ(êµëŸ‰ìœ¼ë¡œ 커서 변경) 다ìŒ, 구축할 íŠ¸ëž™ì˜ ë(êµëŸ‰ì˜ 시작ì )ì„ í´ë¦­í•©ë‹ˆë‹¤.
êµëŸ‰ ëì— ì í•©í•œ 장소가 부족하거나 ì¼ë¶€ ë°©í•´ë¬¼ì´ ìžˆë‹¤ë©´ êµëŸ‰ ì‹œê³µì´ ë§‰íž™ë‹ˆë‹¤: êµëŸ‰ì— ì—°ê²°í•  ì–‘ìª½ì˜ íŠ¸ëž™ì„ ë°°ì¹˜í•˜ê³  다시 시ë„하십시오.
{íŒ: 파괴/ 제거로 êµëŸ‰(êµëŸ‰ ë í´ë¦­) ë° êµëŸ‰ ê±´ë¬¼ì— ëŒ€í•œ 몇 가지 ìž¥ì• ë¬¼ì„ ì œê±°í•˜ì‹­ì‹œì˜¤. 트랙 ë„구를 사용하여 êµëŸ‰ ëìžë½ì„ íŠ¸ëž™ì— ì—°ê²°í•©ë‹ˆë‹¤.}

ëª¨ë…¸ë ˆì¼ ì‹ í˜¸ë“±: 게임 ì‹œì  íŠ¸ëž™ì—서 모노레ì¼ê³¼ ìžê¸° ë¶€ìƒ ì—´ì°¨ë¥¼ 위한 신호등 제작 ë„구.
신호는 트랙 & êµëŸ‰, êµì°¨ë¡œ & 정류장 차량 픽업 ë° í•˜ì°¨)ì—서 ì°¨ëŸ‰ì˜ íë¦„ì„ ì§ì ‘ 조정하고 조절합니다.)
ì–‘ë°©í–¥ ë° ë‹¨ë°©í–¥ ë²„ì „ì˜ ì‹ í˜¸ë“±ì„ ìž‘ì„±í•  수 있습니다.
트랙 위 ì–‘ë°©í–¥ 신호등 제작하려면: ë„구를 í´ë¦­í•˜ì—¬ 신호 ì„ íƒ(커서를 신호등으로 변경); 그리고 íŠ¸ëž™ì„ í´ë¦­í•©ë‹ˆë‹¤.
단방향 신호등 제작하려면: 신호등 커서로 ê°™ì€ ì§€ì ì—서 다시 í´ë¦­ 하면 단방향 신호와 ì–‘ë°©í–¥ 신호를 번갈아 표시합니다..
중요사항: ì°¨ëŸ‰ì˜ ê¸°ë³¸ì ì¸ ì£¼í–‰ì€ ìš°ì¸¡ 주행ì´ë©°, ì´ë¥¼ 무시한 체로 ì‹ í˜¸ë“±ì„ ì„¤ì¹˜í•˜ì§€ 마십시오.(simuconf.tabì—서 변경할 수 있ìŒ).
- 신호등: ì°¨ëŸ‰ì€ ìš´í–‰ì‹œê°„í‘œ (정류장 í˜¹ì€ ê²½ìœ ì§€)ì— ë§žì¶”ì–´ 다른 ì°¨ëŸ‰ì´ ì—†ëŠ” 경우, ë‹¤ìŒ ì‹ í˜¸ë“±ê¹Œì§€ë‚˜ 목ì ì§€ê¹Œì§€ ì´ë™í•©ë‹ˆë‹¤.
단방향 모드ì—서는 ì°¨ëŸ‰ì´ í•œ 방향으로만 ì´ë™í•©ë‹ˆë‹¤.
- ì„ í–‰ 신호등: ì „ë°©ì˜ íŠ¸ëž™ ì˜ì—­ì´ 다른 ì°¨ëŸ‰ì— ì˜í•´ ì ìœ ë˜ì§€ ì•Šì„ ê²½ìš° ì°¨ëŸ‰ì´ ì§„í–‰ë©ë‹ˆë‹¤. (3ê°œì˜ ì—°ì† ì‹ í˜¸ë“± ë˜ëŠ” ì¼ì •ì˜ ë‹¤ìŒ ëª©ì ì§€ 사ì´ì—서)
단방향 모드ì—서는 ì°¨ëŸ‰ì´ í•œ 방향으로만 통과할 수 있습니다.
- 신호등 ì„ íƒ: ì°¨ëŸ‰ì„ ì—¬ëŸ¬ í”Œëž«í¼ ì •ë¥˜ìž¥ì—서 빈 ì—­ 플랫í¼ìœ¼ë¡œ 유ë„: ì´ ì‹ í˜¸ë“±ì„ í†µê³¼í•˜ëŠ” ì°¨ëŸ‰ì€ ì¼ì •ì— í• ë‹¹ëœ í”Œëž«í¼ë¿ë§Œ ì•„ë‹ˆë¼ ë‹¤ìŒ ëª©ì ì§€ì—서 빈 플랫í¼ì„ 사용할 수 있습니다.
빈 플랫í¼ì´ë‚˜ ë‹¤ìŒ ëª©ì ì§€ë¡œ 가는 명확한 경로가 발견ë˜ì§€ 않으면 ì°¨ëŸ‰ì€ ì‹ í˜¸ë“±ì—서 대기합니다.
{íŒ: 파괴/ 제거로 ì‹ í˜¸ë“±ì„ ì œê±°í•˜ì‹­ì‹œì˜¤.
[Ctrl]ì„ ëˆŒëŸ¬ 하단 트랙 ìœ„ì— ìžˆëŠ” ë‹¤ë¦¬ì— ì‹ í˜¸ë“±ì„ ë°°ì¹˜í•©ë‹ˆë‹¤.}

ëª¨ë…¸ë ˆì¼ ì°¨ê³ ì§€: ì´ ë„구는 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ì˜ ì°¨ê³ ë¥¼ 매입 ë° ê´€ë¦¬í•˜ê¸° 위해 사용ë©ë‹ˆë‹¤. 차고지는 유지관리 ë¹„ìš©ì´ ë°œìƒí•˜ë©° 게임 시ì ì˜ 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ íŠ¸ëž™ì˜ ëì— ê±´ì„¤ 가능합니다.
ëª¨ë…¸ë ˆì¼ ì°¨ê³ ì§€ë¥¼ 제작하려면: ë„구를 í´ë¦­í•œ 다ìŒ(커서를 차고지로 변경), íŠ¸ëž™ì˜ ëì„ í´ë¦­í•©ë‹ˆë‹¤.

ì—´ì°¨-정류장: ì´ ë„구는 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ê°€ 화물, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì„ ì‹£ê³  내리기 위한 ì—­-플렛í¼ì„ 건설합니다.
기존 정류장 ì— ì¸ì ‘í•´ 구축ë˜ì§€ ì•Šì€ ì—­-플랫í¼ì€ 새로운 ì •ë¥˜ìž¥ì„ ë§Œë“­ë‹ˆë‹¤.
ì—´ì°¨-정류장ì—는 유지 관리 ë¹„ìš©ì´ ë“¤ê³ , 선로 ìœ„ì— ê±´ì„¤ë©ë‹ˆë‹¤ (커브 구간과 êµì°¨ë¡œëŠ” 제외).
ì—´ì°¨-정류장ì—는 화물, 승ê°, 우편물 ìš´í–‰ ê¶Œì—­ì´ ìžˆìŠµë‹ˆë‹¤.
ê°ê°ì˜ ì—­ 플랫í¼ì€ 화물, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì— ëŒ€í•´ 서로 다른 ìˆ˜ìš©ëŸ‰ì„ ê°€ì§ˆ 수 있습니다.
ì¼ë¶€ ë„구 ì˜µì…˜ì˜ ì½”ë„ˆì—서 ì•„ì´ì½˜ (ì—­ ëª©ë¡ ë° ì •ë¥˜ìž¥ ì •ë³´ì—서 사용) ì€ ì—­ 플랫í¼ì´ 처리할 수 있는 í•­ëª©ì„ í‘œì‹œí•©ë‹ˆë‹¤.
ì—­-í”Œë ›í¼ ì œìž‘í•˜ë ¤ë©°: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒ(커서를 플랫í¼ìœ¼ë¡œ 변경)한 ë‹¤ìŒ íŠ¸ëž™ì„ í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/ 제거로 ì—´ì°¨-ì •ë¥˜ìž¥ì„ ì œê±°í•˜ì‹­ì‹œì˜¤.
ë” ë§Žì€ ì—´ì°¨ë“¤ì„ ìˆ˜ìš©í• ìˆ˜ 있ë„ë¡ ì—­-플랫í¼ì„ 확장 하거나 여러 í”Œëž«í¼ ì •ë¥˜ìž¥ì„ ê±´ì„¤í•©ë‹ˆë‹¤(ì¸ì ‘ íŠ¸ëž™ì— ë” ë§Žì€ í”Œëž«í¼ ì„¹ì…˜ 건설)
[v]를 눌러 게임 시ì ì— 화물 ë° ìŠ¹ê°ì˜ ìš´í–‰ ê¶Œì—­ì„ í‘œì‹œí•˜ê±°ë‚˜ 숨ê¹ë‹ˆë‹¤.
[Ctrl]ì„ ëˆŒëŸ¬ êµëŸ‰ ë˜ëŠ” 하부 트랙 ìœ„ì— ê³ ê°€ íŠ¸ëž™ì„ êµ¬ì¶•í•©ë‹ˆë‹¤.}

ëª¨ë…¸ë ˆì¼ í† ëŒ€: ì´ ë„구는 ì •ë¥˜ìž¥ì— ëŒ€í•œ í™•ìž¥ì„ êµ¬ì„±í•˜ë©° ì •ë¥˜ìž¥ì˜ ìˆ˜ìš©ëŸ‰ì„ ì¦ê°€ì‹œí‚¨ë‹¤.
ëª¨ë…¸ë ˆì¼ í† ëŒ€ëŠ” 모노레ì¼/ ìžê¸° ë¶€ìƒ ì—´ì°¨ì˜ íŠ¸ëž™ ëì— ê±´ì„¤ë˜ë©°, 유지 ë¹„ìš©ì´ ë°œìƒí•©ë‹ˆë‹¤.
ëª¨ë…¸ë ˆì¼ í† ëŒ€ë¥¼ 제작하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 토대로 변경), 트랙 ëì—서 필요한 ë 위치를 í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/ 제거로 ëª¨ë…¸ë ˆì¼ í† ëŒ€ë¥¼ 제거하십시오.}

simutrans-124.3/simutrans/text/ko/new_world.txt000066400000000000000000000137401474050137200217430ustar00rootroot00000000000000새 게임 ìƒì„± ë„움ë§

새 게임 ìƒì„±

새 게임 만들기 ì°½ì€ ìƒˆ ê²Œìž„ì— ëŒ€í•œ ì˜µì…˜ì„ ì„¤ì •í•©ë‹ˆë‹¤. ì´ë ‡ê²Œ 하면 ì„ íƒí•œ 설정으로 새 ì§€ë„ê°€ 만들어집니다. ì§€í˜•ì˜ í¬ê¸°, ë„시 ì§€ì—­ì˜ ì´ˆê¸° 수 ë° ì‚°ì—…ì˜ ìˆ˜ë¥¼ í¬í•¨í•˜ì—¬ ë§Žì€ ê²Œìž„ 변수를 구성할 수 있습니다. ì„ íƒí•œ ì§€í˜•ì˜ ë¯¸ë¦¬ë³´ê¸°ê°€ 새 게임 만들기 ì°½ì—ë„ í‘œì‹œë©ë‹ˆë‹¤.

ì´ ì°½ì„ ì—´ë©´ 다른 모든 게임 ì˜µì…˜ì´ ë¹„í™œì„±í™”ë©ë‹ˆë‹¤. 새 게임 만들기 ì°½ì„ ë‹«ì•„ 현재 게임으로 ëŒì•„가려면 제목 ë°”ì—있는 x ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

화살표 ë²„íŠ¼ì€ ì„¤ì •ì„ ì¡°ì •í•˜ê³  ë²„íŠ¼ì€ ì˜µì…˜ì„ ì¼œê±°ë‚˜ ë„거나 새 ì»¨íŠ¸ë¡¤ì„ ì—½ë‹ˆë‹¤.

ì§€ë„ ë²ˆí˜¸ - ê²Œìž„ì— ì‚¬ìš©í•  ì§€í˜•ì„ ì„ íƒí•©ë‹ˆë‹¤.
ì§€í˜•ì„ ìˆœí™˜í•˜ë ¤ë©´ ìˆ«ìž ìƒìžë¥¼ í´ë¦­í•˜ê³  필요한 ì§€ë„ ë²ˆí˜¸ë¥¼ 입력하거나 화살 ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. 미리보기 ì˜ì—­ì—는 ê²Œìž„ì— í‘œì‹œë˜ëŠ”ëŒ€ë¡œ ì„ íƒëœ ì§€í˜•ì´ í‘œì‹œë©ë‹ˆë‹¤ (ë¬¼ì€ íŒŒëž€ìƒ‰, ë‚®ì€ ë•…ì€ ë†’ì€ ë•…ë³´ë‹¤ 어둡습니다).

í¬ê¸° - ì§€ë„ í¬ê¸°ë¥¼ W x H로 설정합니다. ìƒë‹¨ì— 있는 ìˆ«ìž ìƒìžëŠ” 너비ì´ê³  ê·¸ 아래ì—는 높ì´ê°€ 있습니다. ì§€ë„ì— í•„ìš”í•œ 메모리는 대괄호 ì•ˆì— í‘œì‹œë©ë‹ˆë‹¤.
참고: í° ì§€ë„는 ë” ë§Žì€ ë©”ëª¨ë¦¬ê°€ 필요하며 ìƒì„±ì— ë” ë§Žì€ ì‹œê°„ì´ í•„ìš”í•©ë‹ˆë‹¤. 게임 ë° ê¸°íƒ€ ê·¸ëž˜í”½ì€ pak64ì—서 추가 88MB, pak128ì—서 144MBê°€ 필요합니다. ì¼ë°˜ì ìœ¼ë¡œ 256MB RAMì´ ìž¥ì°©ëœ ì»´í“¨í„°ì—서는 512 x 512보다 훨씬 í° ì§€ë„를 사용하지 마십시오.

ëžœë¤ ì§€ë„ - ëžœë¤ìœ¼ë¡œ 새로운 ì§€í˜•ì„ ì„ íƒí•©ë‹ˆë‹¤. 다른 ì„¤ì •ì€ ë³€ê²½ë˜ì§€ 않습니다.

Height Map 불러오기 - 커스텀 ì§€í˜•ì„ ë¶ˆëŸ¬ì˜µë‹ˆë‹¤. Height Map 불러오기 ì°½ì„ ì—½ë‹ˆë‹¤.

ë„ì‹œì˜ ìˆ˜ - ê²Œìž„ì˜ ì´ˆê¸° ë„시 지역 수를 설정합니다. ì§€ë„ê°€ 너무 작거나 거친 경우, ë„시가 ì ê²Œ 만들어집니다. 공용 플레ì´ì–´ë¡œ 전환하여 새로운 ë„시를 수ë™ìœ¼ë¡œ 추가할 수 있습니다.

ë„시 당 í‰ê·  시민 - 모든 ë„시 ì§€ì—­ì˜ í‰ê·  초기 ì¸êµ¬ë¥¼ 설정합니다. Simutrans는 대ë„시보다 ìž‘ì€ ë§ˆì„ì„ ì°½ì¶œí•˜ë ¤ê³  노력할 것입니다.

ë„시 ê°„ì˜ ë„로 ê¸¸ì´ - 게임 시작 시 ë„시 지역 사ì´ì˜ 공용 ë„ë¡œì˜ â€‹â€‹ìµœëŒ€ 길ì´ë¥¼ 설정합니다. ì´ ê°’ì„ ë” ë†’ê²Œ 설정하면 ë„시 ì§€ì—­ì„ ë” ì‰½ê²Œ ì—°ê²°í•  수 있습니다.

공장과 가게 - ë„시 지역 ë°–ì˜ ì‚°ì—… 공급ë§ì˜ 초기 수를 설정합니다. ë„시 지역 ì¸êµ¬ê°€ ì¦ê°€í•¨ì— ë”°ë¼ ë” ë§Žì€ ì‚°ì—… ì²´ì¸ì´ ìžë™ìœ¼ë¡œ 나타납니다.
참고: ì§€í˜•ì— ì–¸ë•ì´ ë§¤ìš° ë§Žì€ ê²½ìš°, ì‚°ì—… ì²´ì¸ì„ 만드는 ë° ì í•©í•œ í‰ì§€ì˜ ê³µê°„ì´ ì—†ê¸° ë•Œë¬¸ì— ë” ì ì€ ìˆ˜ì˜ ì‚°ì—…ì´ ë‚˜íƒ€ë‚©ë‹ˆë‹¤.

관광 명소 - 승ê°ê³¼ ìš°íŽ¸ë¬¼ì„ ìœ ì¹˜í•˜ëŠ” ë„시 외 ìž¥ì†Œì˜ ì´ˆê¸° 개수를 설정합니다. 관광 명소는 게임 시작 시 새로운 ë„시나 ë„시ì—서 ìƒì„± ëœ ê´€ê´‘ 명소 ì™¸ì— ë„시 외곽 지역ì—ë„ ë‚˜íƒ€ë‚©ë‹ˆë‹¤.

ì—°ë„별 타임 ë¼ì¸ 사용 - ê²Œìž„ì˜ ì‹œìž‘ ì—°ë„를 설정합니다. 시간 기반 제약 ì¡°ê±´ì„ ì ìš©í•˜ì—¬ ê²Œìž„ì„ ì¦ê¸°ë ¤ë©´ 사ê°í˜• ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. 게임ì—서 ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ë” ë§Žì€ ì°¨ëŸ‰, 건물 ë° ì‚°ì—…ì´ ë‚˜íƒ€ë‚©ë‹ˆë‹¤.

ì´ ì˜µì…˜ì„ ì„ íƒí•˜ì§€ 않으면 게임ì—서 모든 차량, 건물 ë° ì‚°ì—…ì„ ì‚¬ìš©í•  수 있습니다. ë„시 ì§€ì—­ì€ ëª¨ë“  ì‹œëŒ€ì˜ ê±´ë¬¼ì— ë‚˜íƒ€ë‚˜ê³  ëŠë¦° ì°¨ëŸ‰ì€ ë¹ ë¥¸ ì°¨ëŸ‰ë§Œí¼ ìˆ˜ìµì´ 높지 않으며 ìˆ˜ìž…ì€ ìš´ì†¡ ì°¨ëŸ‰ì˜ í‰ê·  ì†ë„로 계산ë©ë‹ˆë‹¤.

ìž…ë¬¸ìž ëª¨ë“œ 사용 - 게임 플레ì´ì—서 화물 ë° ìŠ¹ê°ì„ 운송하는 ë° ë” ë†’ì€ ìˆ˜ì¤€ì˜ ìˆ˜ìž…ì„ ë°›ì„ ìˆ˜ìžˆëŠ” ì˜µì…˜ì„ ì„¤ì •í•©ë‹ˆë‹¤. 기본ì ìœ¼ë¡œ 'ìž…ë¬¸ìž ëª¨ë“œ'로 재ìƒí•˜ë©´ ì •ìƒ ëª¨ë“œì—서 재ìƒí•  때 ë°›ì€ ê°’ì˜ 150%를 받게ë©ë‹ˆë‹¤. ë˜í•œ, 소비ìž(s)ê°€ 초과 ê³µê¸‰ì„ í•  경우 산업계는 ê³µê¸‰ì„ ì¤‘ë‹¨í•˜ì§€ ì•Šì„ ê²ƒìž…ë‹ˆë‹¤.

설정 - 확장 설정 ì°½ì´ ì—´ë¦½ë‹ˆë‹¤. simuconf.tab 파ì¼ì—ì„œë„ ì‚¬ìš©í•  수 있는 모든 매개 ë³€ìˆ˜ì— ì ‘ê·¼í•  수 있습니다.

í’ê²½ 설정 - 다양한 ì§€ë„ ì„¤ì •ì„ ì œì–´í•˜ëŠ” ​​í’ê²½ 설정 ì°½ì„ ì—½ë‹ˆë‹¤: ì¡°ë„, 수위, 기후, 숲, 하천.

게임 불러오기 - ì €ìž¥ëœ ê²Œìž„ì„ ë¶ˆëŸ¬ì˜µë‹ˆë‹¤. ì´ì „ì— ì €ìž¥ëœ ê²Œìž„ì„ ë‹¤ì‹œ 시작할 수 있게 제어를 통해 게임 불러오기 ì°½ì´ í‘œì‹œë©ë‹ˆë‹¤. ì €ìž¥ëœ ê²Œìž„ì´ ë¶ˆëŸ¬ì˜¤ê¸°ë˜ë©´ í™•ì¸ ì—†ì´ í˜„ìž¬ ê²Œìž„ì„ ëŒ€ì²´í•©ë‹ˆë‹¤.

시나리오 불러오기 - 시나리오를 불러옵니다. 즉, 특정 목표를 달성해야 하는 게임입니다. ì´ê²ƒì€ ì¼ë°˜ì ì¸ 개방형 Simutrans í”Œë ˆì´ ìŠ¤íƒ€ì¼ì˜ 대안입니다.
참고: ì¼ë¶€ 팩셋ì—는 시나리오가 ì—†ì„ ìˆ˜ 있습니다.

게임 시작 - ì„ íƒí•œ ì„¤ì •ì„ ì‚¬ìš©í•˜ì—¬ 새로운 세계를 만들어 ê²Œìž„ì„ ì‹œìž‘í•©ë‹ˆë‹¤. Simutrans 플레ì´ë¥¼ 시작하려면 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. í–‰ìš´ì„ ë¹•ë‹ˆë‹¤. ê²Œìž„ì„ ì¦ê¸°ì‹­ì‹œì˜¤!

나가기 - ê²Œìž„ì„ ì¢…ë£Œí•˜ë ¤ë©´ ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.

íŒ: Simutrans를 시작할 때 기본 ê°’ì„ ë³€ê²½í•˜ê±°ë‚˜ 다른 ì „ì—­ ì†ì„±ì„ 변경하려면 simuconf.tab 파ì¼ì—서 ê°’ì„ ìˆ˜ì •í•˜ì‹­ì‹œì˜¤.

simutrans-124.3/simutrans/text/ko/options.txt000066400000000000000000000030331474050137200214300ustar00rootroot00000000000000게임 옵션 ë„움ë§

게임 옵션

게임 옵션ì—서는 ê²Œìž„ì˜ ìž‘ë™ê³¼ 표시 ë°©ì‹ì„ 조절할 수 있습니다; ë˜í•œ 게임 옵션ì—서 저장, 불러오기, 게임 종료, 새 게임 시작 ë“±ì„ í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.

게임 ì‹œì  ìƒë‹¨ì— 있는 í”Œë¡œí”¼ë””ìŠ¤í¬ ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ 게임 ì˜µì…˜ì„ ì—½ë‹ˆë‹¤.

새로운 ì»¨íŠ¸ë¡¤ì„ ì—´ë ¤ë©´ ë²„íŠ¼ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤:

언어: 사용하는 언어를 설정합니다.

플레ì´ì–´: 플레ì´ì–´ë“¤ì„ 관리합니다.

플레ì´ì–´ 색ìƒ: 플레ì´ì–´ íšŒì‚¬ì˜ ìƒ‰ìƒì„ 설정합니다.

디스플레ì´:ê²Œìž„ì´ í‘œì‹œë˜ëŠ” ë°©ì‹ì„ 설정합니다.

소리:효과ìŒê³¼ BGMì„ ì„¤ì •í•©ë‹ˆë‹¤.

새 ì§€ë„:í˜„ìž¬ì˜ ê²Œìž„ì—ì„œì˜ ë„구 바를 ëª¨ë‘ ë‹«ê³ , 게임 시작 ì°½ì´ ëœ¹ë‹ˆë‹¤.

불러오기:ì´ì „ì— ì €ìž¥í•œ ê²Œìž„ì„ ë¶ˆëŸ¬ì˜µë‹ˆë‹¤.

저장:현재 ê²Œìž„ì„ ì €ìž¥í•©ë‹ˆë‹¤.

시나리오 불러오기:ì €ìž¥ëœ ì‹œë‚˜ë¦¬ì˜¤ë¥¼ 불러옵니다.

나가기:Simutrans를 종료합니다. ê²Œìž„ì´ ì €ìž¥ë˜ì§€ 않습니다.

simutrans-124.3/simutrans/text/ko/password.txt000066400000000000000000000024231474050137200216010ustar00rootroot00000000000000 플레ì´ì–´ ì´ë¦„ ë° ì•”í˜¸ 변경 ë„움ë§

플레ì´ì–´ ì´ë¦„ ë° ì•”í˜¸ 변경

플레ì´ì–´ ì´ë¦„ ë° ì•”í˜¸ 변경ì—는 ë‘가지 ë°©ë²•ì´ ìžˆìŠµë‹ˆë‹¤:

플레ì´ì–´ 목ë¡ì—서
플레ì´ì–´ ì´ë¦„ ì˜¤ë¥¸ìª½ì— ìžˆëŠ” ìƒìžë¥¼ í´ë¦­í•˜ê±°ë‚˜ 암호로 ë³´í˜¸ëœ í”Œë ˆì´ì–´ë¥¼ 변경하여 ëª…ë ¹ì„ ì‹¤í–‰í•©ë‹ˆë‹¤.

플레ì´ì–´ ì´ë¦„ ì˜¤ë¥¸ìª½ì— ë…¹ìƒ‰ ìƒìžê°€ 있으면 암호가 보호ë˜ì§€ 않으며, 녹색 ìƒìžë¥¼ 누르고 암호를 입력하여 권한 ë° ì•”í˜¸ë¥¼ 보호할 수 있습니다. ì´ë¦„ì„ ì„ íƒí•  수 없는 경우 올바른 암호를 지정해야 합니다.

암호가 없거나 잠금 í•´ì œëœ í”Œë ˆì´ì–´ì˜ ì´ë¦„ì€ ë§¨ ìœ„ì— ìžˆëŠ” í…스트를 편집하여 변경할 수 있습니다.

암호로 ë³´í˜¸ëœ í”Œë ˆì´ì–´ì— 플레ì´ì–´ 목ë¡ì˜ ì´ë¦„ ì˜¤ë¥¸ìª½ì— ë¹¨ê°„ìƒ‰ ìƒìžê°€ 표시ë©ë‹ˆë‹¤. 올바른 암호를 입력하면 ìƒìžê°€ 녹색으로 바뀌고 해당 플레ì´ì–´ë¡œ 플레ì´í•  수 있습니다. 입력한 잠금 í•´ì œ 암호가 ë¡œì»¬ì— ìœ ì§€ë˜ë¯€ë¡œ í”„ë¡œê·¸ëž¨ì„ ë‹¤ì‹œ 시작하지 않는 한 암호를 한 번만 입력하면 ë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/players.txt000066400000000000000000000064411474050137200214220ustar00rootroot00000000000000플레ì´ì–´ ëª©ë¡ ë„움ë§

플레ì´ì–´ 목ë¡

플레ì´ì–´ 목ë¡ì—서는 플레ì´ì–´ë“¤ì˜ 정보와 다른 플레ì´ì–´ì˜ 회사를 관리할 수 있습니다.

플레ì´ì–´ 목ë¡ì€ 게임 ì˜µì…˜ì˜ í”Œë ˆì´ì–´ 버튼ì´ë‚˜ [k]ë²„íŠ¼ì„ ëˆ„ë¥´ë©´ 나타나고, 거기서 플레ì´ì–´ì˜ ì´ë¦„ê³¼ 재정 ìƒíƒœê°€ 표시ë©ë‹ˆë‹¤.

ì´ 14ëª…ì˜ í”Œë ˆì´ì–´ê°€ 있습니다: ì¸ê°„, 공용 서비스와 12ê°œì˜ ë¹ˆ 슬롯으로 구성ë˜ì–´ 있습니다. 빈 슬롯ì—는 다른 ì¸ê°„ 플레ì´ì–´ë‚˜ 2ì¢…ë¥˜ì˜ AI로 채울 수 있습니다.

ì™¼ìª½ì˜ ë„¤ëª¨ ë²„íŠ¼ì„ ëˆ„ë¥´ë©´, 플레ì´ì–´ê°€ 활성화ë©ë‹ˆë‹¤. ê·¸ 플레ì´ì–´ê°€ AIë¼ë©´, ê·¸ 버튼으로 멈추거나 ê³„ì† í™•ìž¥í•˜ê²Œ í•  수 있습니다. 게임 ë„중 AI를 ë„ë”ë¼ë„ AIì˜ êµí†µ 네트워í¬ëŠ” 없어지지 않습니다.

화살표 ë²„íŠ¼ì„ ëˆ„ë¥´ë©´ ê·¸ 플레ì´ì–´ì˜ 회사를 ìš´ì˜í•  수 있습니다. 플레ì´ì–´ë¥¼ 바꾸면 í™•ì¸ ë©”ì‹œì§€ê°€ 뜹니다: ë©”ì‹œì§€ì˜ ì™¼ìª½ ìƒë‹¨ ëª¨ì„œë¦¬ì— ìžˆëŠ” x를 í´ë¦­í•˜ê±°ë‚˜ 키보드를 사용하여 ë‹«ì„ ìˆ˜ 있습니다.

ìžì‹ ì˜ 재정 ìƒíƒœë¥¼ 보려면 플레ì´ì–´ ì´ë¦„ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. 플레ì´ì–´ ìŠ¬ë¡¯ì´ ì§€ì •ë˜ì§€ ì•Šì€ ê²½ìš° ì´ ìŠ¬ë¡¯ì„ ì°¨ì§€í•  플레ì´ì–´ 종류를 ì„ íƒí•  수 있습니다. ê·¸ê²ƒì„ í™œì„±í™”í•˜ë ¤ë©´ 가장 왼쪽 ìƒìžë¥¼ 사용하십시오.

암호로 플레ì´ì–´ë¥¼ 보호 í•  수 있습니다. 보호 ëœ í”Œë ˆì´ì–´ë¡œ ê²Œìž„ì„ í•˜ëŠ” 경우 ë§Žì€ í†µê³„ì— ì ‘ê·¼í•  수 있지만 ì´ í”Œë ˆì´ì–´ì™€ ê´€ë ¨ëœ ê²Œìž„ì€ ë³€ê²½í•  수 없습니다.
ë³´í˜¸ëœ í”Œë ˆì´ì–´ëŠ” ê·¸ì˜ ì´ë¦„ ì˜¤ë¥¸ìª½ì— ë¹¨ê°„ìƒ‰ ìƒìžë¡œ 표시ë©ë‹ˆë‹¤. 암호가 설정ë˜ì–´ 있지 않거나 플레ì´ì–´ì˜ ìž ê¸ˆì´ í•´ì œëœ ê²½ìš°ì´ ìƒìžëŠ” 녹색으로 표시ë©ë‹ˆë‹¤. 암호를 입력하거나 설정할 수있는 암호 대화 ìƒìžë¥¼ 열려면 ìƒìžë¥¼ í´ë¦­í•˜ì‹­ì‹œì˜¤.

ë„¤íŠ¸ì›Œí¬ ê²Œìž„ì˜ ê²½ìš° 플레ì´ì–´ ê°„ì˜ í˜‘ë ¥ì´ ë°”ëžŒì§í•  수 있습니다. ë‹¹ì‹ ì€ ëŒ€ì¤‘ë“¤ì—게 공개할 수 있습니다. 모든 플레ì´ì–´ëŠ” 연결하거나 ì§ì ‘ 운전하여 공용 정류장으로 ì´ë™í•  수 있습니다. ë˜í•œ ì—°ê²° 타ì¼ì„ ê³µê°œí•¨ìœ¼ë¡œì¨ íŠ¸ëž™ì„ ê³µìœ í•  수 있습니다. ì´ëŸ¬í•œ 트랙ì—서 ì–´ë–¤ 회사를 ìš´ì˜ë  수 ìžˆëŠ”ì§€ì— ëŒ€í•œ 통제는 게ì´íŠ¸ë¥¼ 통해 ìˆ˜í–‰ë  ìˆ˜ 있습니다.

플레ì´ì–´ëŠ” ì•„ì´í…œì„ 만들거나 다른 플레ì´ì–´ì˜ 트랙ì´ë‚˜ ë„ë¡œì— ê²½ìœ ì§€ë¥¼ 배치하거나 다른 플레ì´ì–´ê°€ 만든 ì•„ì´í…œì„ 제거할 수 없습니다 (단, 공공 서비스 플레ì´ì–´ê°€ 만든 ì¼ë¶€ ì•„ì´í…œì€ 파괴/ 제거를 사용하여 제거할 수 있습니다).

하단ì—는 ìžìœ í”Œë ˆì´ 모드를 활성화하는 ì˜µì…˜ì´ ìžˆìŠµë‹ˆë‹¤ (공개 플레ì´ì–´ê°€ 잠겨 있지 ì•Šì€ ê²½ìš°). ì´ ëª¨ë“œì—서는 파산하지 않습니다. 그렇지 않으면 부정ì ì¸ 회사 가치를 ì–»ì€ í›„ 플레ì´ì–´ëŠ” 제거ë˜ê³  1ë…„ í›„ì— ìŠ¬ë¡¯ì´ í•´ì œë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/privatesign_info.txt000066400000000000000000000012351474050137200233050ustar00rootroot00000000000000ê°œì¸ìš© 입장 게ì´íЏ

ê°œì¸ìš© 입장 게ì´íЏ

ì´ ì„¤ëª…ê¸€ ì½ê³  ì„ íƒ ì·¨ì†Œëœ ëª¨ë“  플레ì´ì–´ê°€ ìžì‹ ì˜ 차량으로 ì´ ë¬¸ì„ í†µê³¼í•´ 진입하는 ê²ƒì„ ê±°ë¶€í•  수 있습니다. (ì´ ì„¤ì •ì€ ë„ì‹œì˜ ëª¨ë“  ì°¨ì—게 ì˜í–¥ì„ 준다.) 통과가 í—ˆìš©ëœ í”Œë ˆì´ì–´ëŠ” 열린 게ì´íŠ¸ë‚˜ ìž¥ë²½ì„ ë³¼ 수 있으며, ì œì™¸ëœ í”Œë ˆì´ì–´ëŠ” 닫힌 게ì´íŠ¸ë‚˜ ìž¥ë²½ì„ ë³¼ 수 있습니다.

ì´ ê¸°í˜¸ëŠ” 건물 ë„구 ëª¨ìŒ ì¤‘ 하나를 통해 제작ë˜ì—ˆìŠµë‹ˆë‹¤. (ì² ë„ ë„구 or ë„로 ë„구같ì€).

simutrans-124.3/simutrans/text/ko/railtools.txt000066400000000000000000000247571474050137200217650ustar00rootroot00000000000000ì² ë„ ë„구 ë„움ë§

ì² ë„/ì—´ì°¨/선로 ë„구

ì² ë„ ë„구는 기차 운송 네트워í¬ë¥¼ 구성합니다. ë„구가 ìƒì„±ë  수 있습니다: 선로 트랙 (그리고 ê·¸ê²ƒì„ ì „í™” ë˜ëŠ” 제거); í„°ë„; 신호; 차고지; ì—­ 플랫í¼; & ì¦ì¶•. 타임 ë¼ì¸ì„ 가지고 플레ì´í•˜ëŠ” 경우, Simutransì—서 ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ë” ë§Žì€ ë„구 ì˜µì…˜ì´ ë‚˜íƒ€ë‚  수 있습니다.

게임 시ì ì˜ ìƒë‹¨ì— 있는 ì—´ì°¨ ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ ë„구 바를 엽니다. 마우스 커서를 ë„구 옵션 ìœ„ì— ì˜¬ë¦¬ê±°ë‚˜ (ë„구 바를 열거나 í´ë¦­ 한 후) ì´ë¦„ì„ ë³´ê³  ì ì ˆí•œ ìœ„ì¹˜ì— í‘œì‹œí•˜ì‹­ì‹œì˜¤: 건설 비용, 괄호 ì•ˆì˜ ìœ ì§€ 보수 비용, 최대 ì†ë„ 제한 ë° ìµœëŒ€ 길ì´.

ì² ë„ ë„구는 왼쪽ì—서 오른쪽으로 í¬í•¨í•©ë‹ˆë‹¤:

선로 트랙: ë„구는 ë‘ ì§€ì  ì‚¬ì´ì—서 ì² ë„ ì°¨ëŸ‰ì„ ìœ„í•œ íŠ¸ëž™ì„ ë§Œë“­ë‹ˆë‹¤. íŠ¸ëž™ì€ ê²½ì‚¬ë©´ 방향으로 경사면ì—ë§Œ 건설할 수 있으며 거친 지형, 물 ë° ìž¥ì• ë¬¼ì„ ê°€ë¡œ 지르는 경로를 ì°¾ì„ ìˆ˜ 없습니다. 새 íŠ¸ëž™ì´ ë§Œë“¤ì–´ì§€ë©´ ê²½ë¡œì˜ ê¸°ì¡´ íŠ¸ëž™ì„ ì‚¬ìš©í•  수 있습니다.
íŠ¸ëž™ì„ ê±´ì„¤í•˜ë ¤ë©´: ë„구를 í´ë¦­í•˜ì—¬ íŠ¸ëž™ì„ ì„ íƒí•œ ë‹¤ìŒ (트랙으로 커서 변경), íŠ¸ëž™ì˜ ì‹œìž‘ì ì— 대한 게임 ì‹œì  (게임 시ì ì˜ 불ë„ì € 표시 ë° ê²Œìž„ 시ì ì˜ 하단 막대 ì˜¤ë¥¸ìª½ì— ìžˆëŠ” ì§€ë„ ì¢Œí‘œ 표시)를 í´ë¦­í•©ë‹ˆë‹¤. 마지막으로 íŠ¸ëž™ì˜ ì¢…ì ì— 대한 게임 시ì ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 다른 ìœ í˜•ì˜ íŠ¸ëž™ì´ ì—°ê²°ë  ìˆ˜ 있습니다 (그러나 다른 플레ì´ì–´ê°€ 제작한 íŠ¸ëž™ì€ ì—°ê²°í•  수 없습니다). 거친 ì§€í˜•ì„ ê°€ë¡œ 질러 íŠ¸ëž™ì„ ì—°ê²°í•˜ê±°ë‚˜ ìž¥ì• ë¬¼ì„ í”¼í•˜ë ¤ë©´ 다리 ë° í„°ë„ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. íŠ¸ëž™ì˜ ê²½ë¡œë¥¼ 사용하려면 í’ê²½ ë„구를 사용하여 ì§€í˜•ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤. 파괴/ 제거를 사용하여 개별 트랙 ì¡°ê° ë° ì¼ë¶€ ìž¥ì• ë¬¼ì„ ì œê±°í•˜ì‹­ì‹œì˜¤. 추가 ê¸°ëŠ¥ì„ ìœ„í•´ [Ctrl]ì„ ë™ì‹œì— 사용하십시오. 마지막으로 사용 ëœ íŠ¸ëž™ ë„구를 ì„ íƒí•˜ë ¤ë©´ [t]를 누르십시오.}

ì „í™” 트랙: ë„구는 전기 ìžë™ì°¨ìš© 게임 시ì ì—서 ë‘ ì§€ì  ê°„ 트랙, êµëŸ‰ ë° í„°ë„ì— ì „ê¸°ë¥¼ 공급합니다.
íŠ¸ëž™ì— ì „ê¸°ë¥¼ 통하게 하려면: ë„구를 í´ë¦­í•˜ê±°ë‚˜ [e] (전기 트랙 ì•„ì´ì½˜ìœ¼ë¡œ 커서 ì´ë™)를 눌러 ì„ íƒí•œ ë‹¤ìŒ ì „í™”ì˜ ì‹œìž‘ì ì— 대한 게임 시ì ì—서 íŠ¸ëž™ì„ í´ë¦­í•˜ê³  (게임 시ì ì—서 전기 트랙 ì•„ì´ì½˜ 배치) 마지막으로 íŠ¸ëž™ì˜ ë‘ ë²ˆì§¸ ì ì„ í´ë¦­í•˜ì—¬ 시작ì ê¹Œì§€ íŠ¸ëž™ì˜ ì¼ë¶€ë¶„ì„ í‘œì‹œí•©ë‹ˆë‹¤.
{íŒ: 파괴/ 제거를 사용하여 비 전기 트랙으로 다시 변경하십시오.}

트랙 제거: ë„구는 게임 ë³´ê¸°ì˜ ë‘ ì§€ì  ì‚¬ì´ì— ì°¨ëŸ‰ì´ ì—†ì„ ë•Œ 트랙 ë° ì „ê¸° íŠ¸ëž™ì„ ì œê±°í•©ë‹ˆë‹¤ (참고하십시오: ê²½ë¡œì— ìžˆëŠ” 플랫í¼, 신호, í„°ë„ ë° êµëŸ‰ë„ 제거ë©ë‹ˆë‹¤). ë„구를 사용하면 건설 ë¹„ìš©ì´ ë°œìƒí•©ë‹ˆë‹¤.
íŠ¸ëž™ì„ ì œê±°í•˜ë ¤ë©´: ë„구를 í´ë¦­í•˜ì‹­ì‹œì˜¤ (커서가 빨간색 ì‹­ìž ê¸°í˜¸ë¡œ ë°”ë€ë‹ˆë‹¤); íŠ¸ëž™ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (게임 시ì ì—서 빨간색 ì‹­ìžê°€ë¡œ í‘œì‹œëœ ì‚­ì œ ì ì„ ì„ íƒí•˜ì‹­ì‹œì˜¤); 마지막으로 íŠ¸ëž™ì˜ ë‘ ë²ˆì§¸ ì ì„ í´ë¦­í•˜ì—¬ 첫 번째 ì‚­ì œ ì ê¹Œì§€ ë¶€ë¶„ì„ ì œê±°í•©ë‹ˆë‹¤.
{íŒ: 다른 플레ì´ì–´ë¡œ ìž‘ë™í•˜ì—¬ íŠ¸ëž™ì„ ì œê±°í•˜ì‹­ì‹œì˜¤.}

선로 êµëŸ‰: ë„구는 ì² ë„ ì°¨ëŸ‰ì´ ì§€ë‚˜ê°ˆ 수 있ë„ë¡ ê²Œìž„ 시ì ì—서 ë‘ ê°œì˜ íŠ¸ëž™ 사ì´ë¥¼ ì§ì„ ìœ¼ë¡œ 연결합니다. êµëŸ‰ì—는 최대 ê²½ê°„ì´ ìžˆìŠµë‹ˆë‹¤.
ë„구는 트랙 ëì—서 ì ì ˆí•œ 위치 (경간 ë‚´ 다른 트랙 ë ë˜ëŠ” 약간 ë†’ì€ ìª½)ì— ë‹¤ë¦¬ë¥¼ 만듭니다.
êµëŸ‰ì„ 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 êµëŸ‰ìœ¼ë¡œ 변경), 트랙 ë (êµëŸ‰ì˜ì˜ 시작ì )ì„ í´ë¦­í•˜ì—¬ 건설하십시오.
êµëŸ‰ ë ë¶€ë¶„ì— ìž¥ì• ë¬¼ì´ ìžˆê±°ë‚˜ ì ì ˆí•œ 장소가 없는 경우, êµëŸ‰ì´ 막히는 ê²ƒì„ ë°©ì§€í•©ë‹ˆë‹¤: êµëŸ‰ì˜ ì–‘ë©´ì— íŠ¸ëž™ì„ ë†“ê³  다시 시ë„하십시오.
{íŒ: 다리를 제거하려면 파괴/ 제거를 사용하십시오 (êµëŸ‰ì˜ ëì„ í´ë¦­í•˜ì‹­ì‹œì˜¤). ê±´ë¬¼ì„ ì—°ê²°í•˜ê¸°ìœ„í•œ ìž¥ì• ë¬¼ì´ ìžˆìŠµë‹ˆë‹¤. 트랙 ë„구를 사용하여 êµëŸ‰ì˜ ëì„ íŠ¸ëž™ì— ì—°ê²°í•©ë‹ˆë‹¤.}

선로 í„°ë„: ì´ ë„구는 ì² ë„ ì°¨ëŸ‰ì´ ì§€ìƒì„ 통과할 수 있ë„ë¡ ì§ì„  í„°ë„ì„ êµ¬ì¶•í•˜ì—¬ 게임 시ì ì˜ ë‘ íŠ¸ëž™ 사ì´ì— 놓습니다. í„°ë„ì€ ê¸°ìš¸ì–´ì§ˆ 수 없습니다: ì°¨ëŸ‰ì€ ë™ì¼í•œ 높ì´ë¡œ 출입합니다.
ì´ ë„구는 ê²½ì‚¬ë©´ì— ìœ„ì¹˜í•œ 트랙 ëì— í„°ë„ì„ ë§Œë“­ë‹ˆë‹¤. í„°ë„ì„ ê±´ì„¤í•˜ë ¤ë©´: ë„구를 í´ë¦­í•œ ë‹¤ìŒ (커서를 í„°ë„로 변경), ê²½ì‚¬ë©´ì˜ íŠ¸ëž™ ëì„ í´ë¦­í•˜ì—¬ í„°ë„ ìž…êµ¬ë¥¼ 찾습니다.
í„°ë„ì´ ì ë‹¹í•œ 출구 (ìž¥ì• ë¬¼ì´ ì—†ëŠ” 경사면)를 찾지 못하면, ê·¸ê²ƒì€ ê±´ì„¤ë˜ì§€ ì•Šì„ ê²ƒìž…ë‹ˆë‹¤. ì—°ê²°ë  ì–‘ë©´ì— íŠ¸ëž™ì„ ë†“ê³  다시 시ë„하십시오.
{íŒ: í„°ë„ ì¶œìž…êµ¬ì— ëŒ€í•´ ì ì ˆí•œ 장소를 ìƒì„±í•˜ë ¤ë©´ í’ê²½ ë„구 ë° íŒŒê´´/ 제거를 사용하십시오. 트랙 ë„구를 사용하여 í„°ë„ ì¶œêµ¬ë¥¼ íŠ¸ëž™ì— ì—°ê²°í•˜ì‹­ì‹œì˜¤.}

선로 신호: ë„구는 게임 시ì ì˜ 트랙ì—서 ì² ë„ ì°¨ëŸ‰ 신호를 만듭니다. 신호는 트랙 ë° êµëŸ‰, êµì°¨ì  ë° ì •ë¥˜ìž¥ì—서 ì°¨ëŸ‰ì˜ íë¦„ì„ ì§ì ‘ 제어합니다.
ì‹ í˜¸ì˜ ì–‘ë°©í–¥ ë° ë‹¨ë°©í–¥ ë²„ì „ì„ êµ¬ì¶•í•  수 있습니다. 트랙ì—서 ì–‘ë°©í–¥ 신호를 구축하려면: ë„구를 í´ë¦­í•˜ì—¬ 신호를 ì„ íƒí•˜ì‹­ì‹œì˜¤ (커서를 신호로 변경); íŠ¸ëž™ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. 단방향 신호를 구축하려면: 단방향 신호를 순환하고 ì–‘ë°©í–¥ 신호로 ëŒì•„가려면 신호-커서를 사용하여 ê°™ì€ ì§€ì ì—서 다시 í´ë¦­í•˜ì‹­ì‹œì˜¤.
중요사항: ì°¨ëŸ‰ì´ ëª©ì ì§€ì— ë„달하지 못하ë„ë¡ ë‹¨ë°©í–¥ 신호를 ë³´ë‚´ì§€ 않ë„ë¡ ì£¼ì˜í•˜ì‹­ì‹œì˜¤. 기본ì ìœ¼ë¡œ ì°¨ëŸ‰ì€ ì˜¤ë¥¸ìª½ìœ¼ë¡œ 주행합니다 (simuconf.tabì—서 변경할 수 있습니다).
신호를 í´ë¦­í•  때 제어 키를 누르고 있는 경우, 다중 신호 구축기가 활성화ë©ë‹ˆë‹¤.
- 신호: ì°¨ëŸ‰ì´ ë‹¤ìŒ ì‹ í˜¸ ë˜ëŠ” 목ì ì§€ì˜ ì¼ì • (정류장 ë˜ëŠ” 중간 ì§€ì )까지 다른 ì°¨ëŸ‰ì— ì˜í•´ ì ìœ ë˜ì§€ ì•Šì€ ê²½ìš°ì—ë§Œ ì§„í–‰ë©ë‹ˆë‹¤. 단방향 모드ì—서 ì°¨ëŸ‰ì€ í•œ 방향으로만 지나갑니다.
- 선로 닫힘: ì°¨ëŸ‰ì´ ì‹ í˜¸ ì´ìƒìœ¼ë¡œ 진행하지 않습니다 (단방향 모드ì—서만 사용 가능).
- ì„ í–‰ 신호: ì„ í–‰ 신호 ì°¨ëŸ‰ì€ íŠ¸ëž™ ì „ë°© (3ê°œì˜ ì—°ì† ì‹ í˜¸ ì‚¬ì´ ë˜ëŠ” ì¼ì •ì˜ ë‹¤ìŒ ëª©ì ì§€ê¹Œì§€) ì˜ì—­ì´ 다른 ì°¨ëŸ‰ì— ì˜í•´ ì ìœ ë˜ì§€ 않는 경우, ê³„ì† ì§„í–‰ë©ë‹ˆë‹¤. 단방향 모드ì—서는 ì°¨ëŸ‰ì´ í•œ 방향으로만 지나가게 합니다.
- ì„ íƒ ì‹ í˜¸: 다중 í”Œëž«í¼ ì •ë¥˜ìž¥ì—서 빈 ì—­ 플랫í¼ìœ¼ë¡œ ì°¨ëŸ‰ì„ ì•ˆë‚´í•©ë‹ˆë‹¤: ì´ ì‹ í˜¸ë¥¼ 통과하는 ì°¨ëŸ‰ì€ ì¼ì •ì— ì§€ì •ëœ ê²ƒë¿ë§Œ ì•„ë‹ˆë¼ ë‹¤ìŒ ëª©ì ì§€ì—서 빈 플랫í¼ì„ 사용할 수 있습니다. 빈 플랫í¼ì´ë‚˜ ë‹¤ìŒ ëª©ì ì§€ê¹Œì§€ 가는 명확한 경로가 없는 경우, ì°¨ëŸ‰ì€ ì‹ í˜¸ë¥¼ 기다립니다.
{íŒ: 파괴/ 제거로 신호를 제거하십시오. 다리 ìœ„ì˜ ì‹ í˜¸ë¥¼ ë” ë‚®ì€ íŠ¸ëž™ ìœ„ì— ë†“ìœ¼ë ¤ë©´ [Ctrl] 키를 길게 누르십시오.}

ì—´ì°¨ 차고지: ë„구는 ì—´ì°¨ ë° ê°ì°¨ 매입 ë° ê´€ë¦¬ë¥¼ 위한 차고지를 건설합니다. 차고지는 유지 보수 ë¹„ìš©ì´ í•„ìš”í•˜ë©° 게임 시ì ì—서 íŠ¸ëž™ì˜ ë ë¶€ë¶„ì— ê±´ì„¤ë©ë‹ˆë‹¤.
ì—´ì°¨ 차고지를 건설하려면: ë„구를 í´ë¦­í•œ ë‹¤ìŒ (커서를 저장소로 변경), íŠ¸ëž™ì˜ ëì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/ 제거로 차고지를 제거하십시오. 차고지 전기 트랙ì—서만 전기 ì°¨ëŸ‰ì„ í‘œì‹œí•©ë‹ˆë‹¤.}

선로-정류장: ë„구는 ì² ë„ ì°¨ëŸ‰ì´ í™”ë¬¼, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì„ ì‹£ê³  내리는 ë° ì‚¬ìš©í•˜ëŠ” ì—­ 플랫í¼ì„ 건설합니다.
ì—­ 플랫í¼ì€ ê¸°ì¡´ì˜ ì •ë¥˜ìž¥ì— ì¸ì ‘하지 않으면, 새로운 ì •ë¥˜ìž¥ì„ ë§Œë“¤ 수 있습니다.
선로-ì •ë¥˜ìž¥ì€ ìœ ì§€ 보수 ë¹„ìš©ì´ ìžˆìœ¼ë©° íŠ¸ëž™ì— ê±´ì„¤ë˜ì–´ 있습니다 (그러나 íŠ¸ëž™ì˜ êµ´ê³¡ ë° êµì°¨ì ì—는 해당ë˜ì§€ 않습니다).
선로-정류장ì—는 화물, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì„ ìœ„í•œ ìš´í–‰ ê¶Œì—­ì´ ìžˆìŠµë‹ˆë‹¤. 다른 ì—­ 플랫í¼ì€ 화물, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì— ëŒ€í•´ 서로 다른 ìˆ˜ìš©ëŸ‰ì„ ê°€ì§ˆ 수 있습니다. ì¼ë¶€ ë„구 ì˜µì…˜ì˜ ëª¨ì„œë¦¬ì— ì•„ì´ì½˜ (ì—­ ëª©ë¡ ë° ì •ë¥˜ìž¥ ì •ë³´ì— ì‚¬ìš©)ì€ ì—­ 플랫í¼ì´ 정류장를 처리할 수 있는 í•­ëª©ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
ì—­ 플랫í¼ì„ 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 플랫í¼ìœ¼ë¡œ 변경), íŠ¸ëž™ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/ 제거로 선로-ì •ë¥˜ìž¥ì„ ì œê±°í•˜ì‹­ì‹œì˜¤. ë” ê¸¸ê³  ë” ë§Žì€ ì°¨ëŸ‰ì„ ìˆ˜ìš©í•˜ê³  용량 ë° ìš´í–‰ ê¶Œì—­ì„ ëŠ˜ë¦¬ë ¤ë©´ ì—­ 플랫í¼ì„ ì¦ì¶•하고 (ì¸ì ‘ íŠ¸ëž™ì— ë” ë§Žì€ í”Œëž«í¼ ì„¹ì…˜ì„ ê±´ì„¤í•˜ì—¬) 다중 í”Œëž«í¼ ì •ë¥˜ìž¥ì„ ê±´ì„¤í•˜ì‹­ì‹œì˜¤. 게임 시ì ì—서 화물 ë° ìŠ¹ê°ì„ 위한 ìš´í–‰ ê¶Œì—­ì„ í‘œì‹œí•˜ê±°ë‚˜ 숨기려면 [v]를 누르십시오. ë” ë‚®ì€ íŠ¸ëž™ ìœ„ì— êµëŸ‰ì„ 건설하려면 [Ctrl]ì„ ê¸¸ê²Œ 누르십시오.}

ì¦ì¶•: ë„구는 용량, ìš´í–‰ 권역 ë° ìœ ì§€ 보수 ë¹„ìš©ì„ ì¦ê°€ì‹œí‚¬ 수 있는 ì •ë¥˜ìž¥ì„ ìœ„í•œ ì¦ì¶• ë° ê±´ë¬¼ì„ ê±´ì„¤í•©ë‹ˆë‹¤.
ì¼ë¶€ ë„구 ì˜µì…˜ì˜ ëª¨ì„œë¦¬ì— ìžˆëŠ” ì•„ì´ì½˜ (ì—­ ëª©ë¡ ë° ì •ë¥˜ìž¥ ì •ë³´ì—ì„œë„ ì‚¬ìš©)ì€ ì •ë¥˜ìž¥ì„ ì²˜ë¦¬ ​​할 수 있는 ì¦ì¶• í•­ëª©ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
ì¦ì¶•하려면: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 ë‚´ì„  번호로 변경), 게임 시ì ì—서 기존 정류장 ì˜†ì˜ í•„ìš”í•œ 위치를 í´ë¦­í•˜ì‹­ì‹œì˜¤. 새로 ì¦ì¶•ëœ ë¶€ë¶„ì€ ì •ë¥˜ìž¥ì˜ ì¼ë¶€ë¡œ 간주ë©ë‹ˆë‹¤.
{íŒ: 파괴/ 제거로 ì¦ì¶•ëœ ë¶€ë¶„ì„ ì œê±°í•˜ì‹­ì‹œì˜¤.}

simutrans-124.3/simutrans/text/ko/removal_tool.txt000066400000000000000000000047661474050137200224550ustar00rootroot00000000000000제거 ë„구 ë„움ë§

파괴/ 제거 ë„구

제거 ë„구는 게임 시ì ë‹¨ì¼ 게임-타ì¼ì—서 ì›ì¹˜ 않는 ì•„ì´í…œê³¼ 구성 요소를 파괴하고 제거하기 위해 사용ë©ë‹ˆë‹¤.

사용법: 게임 시ì ì˜ 맨 ìœ„ì— ìžˆëŠ” 빨간색 ì‹­ìžì„ (pak128ì˜ bulldozer-icon)ì„ í´ë¦­í•˜ê±°ë‚˜ [r] 키를 눌러 제거 ë„구를 엽니다(커서가 빨간색 ì‹­ìž-ë¶„ì§„ 구름 모양으로 변경ë¨). 게임 시ì ì—서 커서 ìœ„ì¹˜ì— í‘œì‹œë˜ëŠ” 노란색 ìœ¤ê³½ì€ ë„구가 ìž‘ë™í•  위치를 나타냅니다(ì§€ë„ ì¢Œí‘œëŠ” 아래쪽 ë°”ì— í‘œì‹œë¨). 그런 ë‹¤ìŒ ê²Œìž„ 시ì ì—서 개체를 í´ë¦­í•˜ì—¬ 제거합니다. 제거할 수 있는 ê¶Œí•œì´ ìžˆìœ¼ë©´ 경고 ì—†ì´ í•´ë‹¹ 개체가 ì§€ë„ì—서 제거ë©ë‹ˆë‹¤.

ë°œìƒëœ ë¹„ìš©ì€ ê²Œìž„ 시ì ì— 즉시 표시ë˜ë©° ê±´ì¶• 비용 í•­ëª©ì— í‘œì‹œë˜ë©°, ì´ëŠ” 재정 ìƒíƒœ ì°½ì— ì†í•´ìžˆìŠµë‹ˆë‹¤. 제거 ë¹„ìš©ì€ (선수 í’ˆëª©ì˜ ê²½ìš°) 건설 비용과 ë™ì¼í•©ë‹ˆë‹¤. ë„시 건물 파괴 ë¹„ìš©ì€ ì ê²€ë„구로 열린 설명창ì—서 ë³´ë“¯ì´ ê·¸ 가치와 같습니다. ë˜í•œ 나무를 파괴하는 ë¹„ìš©ë„ ë“­ë‹ˆë‹¤.

제거 ë„구는 ê°œì¸ ë³´í–‰ìžì™€ ê°œì¸ ì°¨ë¥¼ 제거하는 ë°ë„ 사용할 수 있습니다.

ë‹¨ì¼ ë„로/트랙 타ì¼ë¡œë¶€í„° í•­ëª©ì„ ì œê±°í•˜ëŠ” 순서: ë³´í–‰ìž ë˜ëŠ” ê°œì¸ ë„시 차량, 신호, ì •ì§€/ì •ì§€ 플랫í¼, 경로 전기화, êµëŸ‰ ë˜ëŠ” í„°ë„, 경로 ìžì²´(ë„ë¡œì— ìžˆëŠ” 경우 먼저 ì¶”ì ).

íŒ:
플레ì´ì–´ ì°¨ëŸ‰ì„ ì œê±°í•˜ë ¤ë©´ Convoy Detailsì°½ì—서 íŒë§¤/소지를 해야합니다.
ì‚°ì—…, 관광지 ë˜ëŠ” ì‹œì²­ì„ ì œê±°í•˜ë ¤ë©´ 먼저 공용 서비스 플레ì´ì–´ë¡œ 전환해야합니다.
경고: 시청 ë˜ëŠ” 마ì„íšŒê´€ì„ ì² ê±°í•  때 ê·¸ ë„시 ì§€ì—­ì˜ ëª¨ë“  ë„시 ê±´ë¬¼ë„ ì² ê±°ë©ë‹ˆë‹¤.
다른 플레ì´ì–´ í•­ëª©ì„ ì‚­ì œ/ 제거하려면 먼저 다른 플레ì´ì–´ë¡œ 재ìƒí•˜ë„ë¡ ì„ íƒí•©ë‹ˆë‹¤.
트랙 ë˜ëŠ” ë„ë¡œì˜ ì„¸ê·¸ë¨¼íŠ¸ë¥¼ 제거하려면 트랙 제거 ë„구 (트램 ë„구ì—ë„ ìžˆìŒ) ë˜ëŠ” ë„로 제거 ë„구를 사용합니다.

simutrans-124.3/simutrans/text/ko/roadtools.txt000066400000000000000000000260311474050137200217460ustar00rootroot00000000000000ë„로 ë„구 ë„움ë§

ë„로 ë„구

ë„로 ë„구는 화물과 승ê°ì„ 위한 ë„로 êµí†µë§ì„ 구축합니다. ë„구는 작성 ë˜ëŠ” 제거 ë  ìˆ˜ 있습니다: ë„로, êµëŸ‰, í„°ë„, 신호, 차고지, ì¦ì¶•, 그리고 정류장. 타임 ë¼ì¸ì„ 가지고 플레ì´í•˜ëŠ” 경우, Simutransì—서 ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ë” ë§Žì€ ë„구 ì˜µì…˜ì´ ë‚˜íƒ€ë‚  수 있습니다.

ë„구 바를 열려면 게임 시ì ì˜ ìƒë‹¨ì— 있는 트럭 ì•„ì´ì½˜ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
마우스 커서를 ë„구 옵션 ìœ„ì— ì˜¬ë¦¬ê±°ë‚˜ (ë„구 바를 열거나 í´ë¦­ 한 후) ì´ë¦„ì„ ë³´ê³  ì ì ˆí•œ ìœ„ì¹˜ì— í‘œì‹œí•˜ì‹­ì‹œì˜¤: 건설 비용, 괄호 ì•ˆì˜ ìœ ì§€ 보수 비용, 최대 ì†ë„ 제한 ë° ìµœëŒ€ 길ì´.

선로 ë„구는 왼쪽ì—서 오른쪽으로 í¬í•¨í•©ë‹ˆë‹¤:

ë„로: ë„구는 ë„로 ì°¨ëŸ‰ì„ ìœ„í•´ ë‘ ì§€ì  ì‚¬ì´ì— ë„로를 건설합니다. ë„로는 다른 ê±´ë¬¼ì´ ì°¨ì§€í•˜ëŠ” 구역ì—는 ê±´ì„¤ë  ìˆ˜ 없습니다. ë„로는 경사면 방향으로 경사면ì—ë§Œ ê±´ì„¤ë  ìˆ˜ 있으며 거친 지형ì´ë‚˜ ë¬¼ì„ ê°€ë¡œ 질러 ê±´ì„¤ë  ìˆ˜ëŠ” 없습니다. 새로 ê±´ì„¤ëœ ë„로는 기존 ê²½ë¡œì˜ ë„로를 사용할 수 있습니다.
ë„로를 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ ë„로 ìœ í˜•ì„ ì„ íƒí•˜ê³  (커서를 ë„로로 변경), ë„ë¡œì˜ ì‹œìž‘ì ì— 대한 게임 시ì ì—서 í´ë¦­í•˜ì‹­ì‹œì˜¤ (ê²Œìž„ë³´ê¸°ì˜ ë¶ˆë„ì € 표시 ë° ê²Œìž„ë³´ê¸°ì˜ í•˜ë‹¨ 막대 오른쪽ì—ì§€ë„ ì¢Œí‘œ 표시 ), 마지막으로 ë„로 종ì ì— 대한 게임 시ì ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 다른 ìœ í˜•ì˜ ë„로는 다른 플레ì´ì–´ê°€ 만든 경우ì—ë„ ì—°ê²°í•  수 있습니다. 거친 ì§€í˜•ì„ ê°€ë¡œ 질러 ë„로를 연결하거나 ìž¥ì• ë¬¼ì„ í”¼í•˜ë ¤ë©´ êµëŸ‰ê³¼ í„°ë„ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. ì§€í˜•ì„ ë³€ê²½í•˜ê³  ë„로 경로를 사용하려면 í…Œë¼í¬ë° ë„구를 사용하십시오. 개별 ë„로 ë° ìž¥ì• ë¬¼ì„ ì œê±°í•˜ë ¤ë©´ 파괴/ 제거를 사용하십시오. 추가 ê¸°ëŠ¥ì„ ìœ„í•´ [Ctrl]ì„ ë™ì‹œì— 사용하십시오. 실행 취소 [z]는 ê±´ì¶• ë¹„ìš©ì„ í™˜ë¶ˆí•˜ì§€ 않습니다. 마지막 ë„로 ë„구를 ì„ íƒí•˜ë ¤ë©´ [s]를 누르십시오.}

ë„로 제거: ì´ ë„구는 ì°¨ëŸ‰ì´ ì—†ì„ ë•Œ ë„로를 제거하여 게임 시ì ì˜ ë‘ ì§€ì  (ê²½ë¡œì— ìžˆëŠ” ë„로-정류장, 신호, êµëŸ‰ì˜ í„°ë„ ë˜í•œ 제거ë©ë‹ˆë‹¤) 사ì´ì— 있습니다. ë„구를 사용하면 건설 ë¹„ìš©ì´ ë°œìƒí•©ë‹ˆë‹¤.
ë„로를 제거하려면: ë„구를 í´ë¦­í•˜ì‹­ì‹œì˜¤ (커서가 빨간색 ì‹­ìž ê¸°í˜¸ë¡œ ë°”ë€ë‹ˆë‹¤); 삭제할 íŠ¸ëž™ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (게임 시ì ì—서 ì ì‹­ìžë¡œ í‘œì‹œëœ ì‚­ì œì ì„ ì„ íƒí•˜ì‹­ì‹œì˜¤); 마지막으로 íŠ¸ëž™ì˜ ë‹¤ë¥¸ ì§€ì ì„ í´ë¦­í•˜ì—¬ 첫 번째 ì‚­ì œì ê¹Œì§€ 트랙 ë¶€ë¶„ì„ ì œê±°í•©ë‹ˆë‹¤.
{íŒ: ë„로를 제거하려면 다른 플레ì´ì–´ë¡œ ìž‘ë™í•˜ì‹­ì‹œì˜¤.}

ë„로 êµëŸ‰: ë„구는 게임 시ì ì—서 ë„ë¡œì˜ ë‘ ë¶€ë¶„ 사ì´ë¥¼ 통과하는 ì§ì„  êµëŸ‰ì„ 만듭니다. êµëŸ‰ì—는 최대 ê²½ê°„ì´ ìžˆìŠµë‹ˆë‹¤. ë„구는 ë„로 ëì—서부터 ì ë‹¹í•œ 장소 (경간 ë‚´ 다른 ë„로 ë ë˜ëŠ” 약간 ë†’ì€ ë•…)까지 êµëŸ‰ì„ 만듭니다.
êµëŸ‰ì„ 건설하려면: ë„구를 í´ë¦­í•˜ì—¬ êµëŸ‰ì„ ì„ íƒí•˜ê³  (커서를 êµëŸ‰ìœ¼ë¡œ 변경) ë„ë¡œì˜ ë (êµëŸ‰ì˜ 시작ì )ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. êµëŸ‰ 쪽 ë ë¶€ë¶„ì— ìž¥ì• ë¬¼ì´ë‚˜ ì ë‹¹í•œ 장소가 없는 경우 êµëŸ‰ì´ 막히는 ê²ƒì„ ë§‰ì„ ìˆ˜ 있습니다: êµëŸ‰ì´ ë  ì–‘ì¸¡ ë„로를 만들고 다시 시ë„하십시오.
{íŒ: 다리를 제거하려면 (다리 ëì„ í´ë¦­í•˜ì‹­ì‹œì˜¤) 파괴/ 제거를 사용하십시오. ê±´ë¬¼ì„ ì—°ê²°í•˜ê¸° 위한 ìž¥ì• ë¬¼ì´ ìžˆìŠµë‹ˆë‹¤. ë„ë¡œì— êµëŸ‰ì˜ ëì„ ì—°ê²°í•˜ë ¤ë©´ ë„로 ë„구를 사용하십시오.}

ë„로 í„°ë„: ì´ ë„구는 ì°¨ëŸ‰ì´ ìœ¡ì§€ë¥¼ 통과할 수 있ë„ë¡ ì§ì„  í„°ë„ì„ ê±´ì„¤í•˜ì—¬ 게임 시ì ì—서 ë‘ ê°œì˜ ë„로 사ì´ì— 둡니다. í„°ë„ì€ ê¸°ìš¸ì–´ 질 수 없습니다: ì°¨ëŸ‰ì€ ë™ì¼í•œ 높ì´ë¡œ 출입합니다.
ë„구는 ê²½ì‚¬ë©´ì— ìœ„ì¹˜í•œ ë„로 ë ë¶€ë¶„ì— í„°ë„ì„ ë§Œë“­ë‹ˆë‹¤. í„°ë„ì„ ê±´ì„¤í•˜ë ¤ë©´: ë„구를 í´ë¦­í•œ ë‹¤ìŒ (커서를 í„°ë„로 변경), ê²½ì‚¬ë©´ì˜ ë„로 ëì„ í´ë¦­í•˜ì—¬ í„°ë„ ìž…êµ¬ë¥¼ 찾습니다. í„°ë„ì´ ì ë‹¹í•œ 출구 (ìž¥ì• ë¬¼ì´ ì—†ëŠ” 경사면)를 찾지 못하는 경우, ê·¸ê²ƒì€ ê±´ì„¤ë˜ì§€ ì•Šì„ ê²ƒìž…ë‹ˆë‹¤: ì—°ê²°ë  ì–‘ìª½ì— ë„로를 놓고 다시 시ë„하십시오.
{íŒ: í„°ë„ ì¶œìž…êµ¬ì— ëŒ€í•´ ì í•©í•œ 장소를 ìƒì„±í•˜ë ¤ë©´ í’ê²½ ë„구 ë° íŒŒê´´/ 제거를 사용하십시오. ë„로 ë„구를 사용하여 í„°ë„ ì¶œêµ¬ë¥¼ ë„ë¡œì— ì—°ê²°í•˜ì‹­ì‹œì˜¤.}

ë„로 신호 ë° ìž¥ë²½: ë„구는 ë„로 ì°¨ëŸ‰ì˜ ì‹ í˜¸ ë° ìž¥ë²½ì„ ê²Œìž„ 시ì ì—서 건설합니다. 신호 ë° ìž¥ì• ë¬¼ì€ ë„로 ë° êµëŸ‰, êµì°¨ì  ë° ì •ë¥˜ìž¥ (화물 ë° ìŠ¹ê°ì„ 싣고 내린 ê³³)ì—서 ì°¨ëŸ‰ì˜ íë¦„ì„ ì§ì ‘ 통제합니다. ì¼ë¶€ ì‹ í˜¸ì˜ ì–‘ë°©í–¥ ë° ë‹¨ë°©í–¥ ë²„ì „ì„ êµ¬ì¶•í•  수 있습니다.
중요사항: ì£¼ì˜ ì‹ í˜¸ëŠ” ì°¨ëŸ‰ì´ ëª©ì ì§€ì— ë„달하지 못하ë„ë¡ ë§‰ëŠ” 신호를 구축하지 않으며, 기본ì ìœ¼ë¡œ ì°¨ëŸ‰ì€ ì˜¤ë¥¸ìª½ìœ¼ë¡œ 주행합니다 (simuconf.tabì—서 변경할 수 있습니다).
- êµí†µ 신호등: ë„구는 게임 시ì ì—서 신호를 구축하여 êµì°¨ì ì—서 ë„로 ì°¨ëŸ‰ì˜ íë¦„ì„ ì¡°ì ˆí•˜ê³  진행시키거나 잠시 기다릴 수 있ë„ë¡ í•©ë‹ˆë‹¤. ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 신호로 변경), 구축할 ë„로를 í´ë¦­í•˜ì‹­ì‹œì˜¤. 신호 ë°©í–¥ì„ ë³€ê²½í•˜ë ¤ë©´ êµì°¨ì ì—서 다시 í´ë¦­í•˜ì‹­ì‹œì˜¤.
- ë‹¨ì¼ ìž¥ë²½: ë„구는 ë„로 í•œìª½ì„ ì‚¬ìš©í•˜ì—¬ ë„로 ì°¨ëŸ‰ì„ ë§‰ëŠ” ìž¥ë²½ì„ ë§Œë“­ë‹ˆë‹¤. ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  (커서를 장벽으로 변경), 건설할 ë„로를 í´ë¦­í•œ 다ìŒ, ë™ì¼í•œ 위치ì—서 다시 í´ë¦­í•˜ì—¬ ìž¥ë²½ì´ ì ìš©ë˜ëŠ” ë„ë¡œì˜ ì¸¡ë©´ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤.
- ë„로 닫힘: ë„구는 ë„로 ì°¨ëŸ‰ì˜ ì§„í–‰ì„ ë°©í•´í•˜ëŠ” ìž¥ë²½ì„ ë§Œë“­ë‹ˆë‹¤. ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 장벽으로 변경), 건설할 ë„로를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
- 출입 금지: ë„구는 ë„로 ì°¨ëŸ‰ì´ ë„ë¡œì˜ í•œìª½ì—서 ì§„í–‰ë˜ëŠ” ê²ƒì„ ë°©ì§€í•˜ê¸° 위한 신호를 구축합니다 (ë‹¨ì¼ ìž¥ë²½ê³¼ 유사). ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 신호로 변경), 건설할 ë„로를 í´ë¦­í•˜ê³  ë™ì¼í•œ 위치ì—서 다시 í´ë¦­í•˜ì—¬ 신호가 있는 ë„ë¡œì˜ ì¸¡ë©´ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤. ë˜í•œ 특정 플레ì´ì–´ì˜ í†µí–‰ë§Œì„ í—ˆìš©í•˜ëŠ” ê°œì¸ìš© 입구 게ì´íЏë¼ëŠ” ë³€í˜•ì´ ìžˆìŠµë‹ˆë‹¤.
- 최소 80km/h 최대 ì†ë„ê°€ 80km/h ë¯¸ë§Œì¸ ê²½ìš°, ë„로 ì°¨ëŸ‰ì´ ì§„í–‰í•˜ì§€ 못하ë„ë¡ ì‹ í˜¸ë¥¼ 구축합니다. ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  커서를 신호로 변경한 다ìŒ, 건설할 ë„로를 í´ë¦­í•˜ê³  ë™ì¼í•œ 위치ì—서 다시 í´ë¦­í•˜ì—¬ 신호가 ì ìš©ë˜ëŠ” ë„ë¡œì˜ ì¸¡ë©´ì„ ë³€ê²½í•©ë‹ˆë‹¤.
- ì§€ì  ì„ íƒ: ë„구는 ë„로 ì°¨ëŸ‰ì„ ë¹ˆ ë„로-정류장으로 안내하여 여러 ë„로-정류장ì´ìžˆëŠ” 정류장ì—서 화물 ë° ìŠ¹ê°ì„ 싣고 내리는 신호를 구축합니다: ì´ ì‹ í˜¸ë¥¼ 통과하는 ì°¨ëŸ‰ì€ ì¼ì •ì— í• ë‹¹ëœ ì°¨ëŸ‰ë¿ë§Œ ì•„ë‹ˆë¼ ë‹¤ìŒ ëª©ì ì§€ì—서 무료 ë„로-ì •ë¥˜ìž¥ì„ ì‚¬ìš©í•  수 있습니다. 빈 ë„로-정류장 ë˜ëŠ” ë‹¤ìŒ ëª©ì ì§€ê¹Œì§€ 가는 명확한 경로가 없으면 ì°¨ëŸ‰ì€ ì‹ í˜¸ë¥¼ 기다립니다. ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  커서를 신호로 변경한 ë‹¤ìŒ ê±´ì„¤í•  ë„로를 í´ë¦­í•˜ê³  ë™ì¼í•œ 위치ì—서 다시 í´ë¦­í•˜ì—¬ 신호가 ì ìš©ë˜ëŠ” ë„ë¡œì˜ ì¸¡ë©´ì„ ë³€ê²½í•©ë‹ˆë‹¤.
- ê³ ì†ë„로: (pak128ì—서만 사용 가능) ë„구는 최대 ì†ë„ ì œí•œì´ 80km/h를 초과하는 경우, ì°¨ëŸ‰ì´ í•œ 방향으로 진행하는 ê²ƒì„ í—ˆìš©í•˜ëŠ” 신호를 구축합니다.
ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•˜ê³  (커서를 신호로 변경), 건설할 ë„로를 í´ë¦­í•˜ê³  ë™ì¼í•œ 위치ì—서 다시 í´ë¦­í•˜ì—¬ 신호가 ì ìš©ë˜ëŠ” ë„ë¡œì˜ ë°©í–¥ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/ 제거로 신호를 제거하십시오. ë” ë‚®ì€ ë„로 ìœ„ì˜ êµëŸ‰ì— 신호를 배치하려면 [Ctrl]ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤.}

ë„로 차고지: ë„구는 ë„로 차량 ë° íŠ¸ë ˆì¼ëŸ¬ 매입 ë° ê´€ë¦¬ë¥¼ 위한 차고지를 건설합니다. 차고지는 유지 보수 ë¹„ìš©ì´ ìžˆìœ¼ë©° 게임 시ì ì—서 ë„로 ë ë¶€ë¶„ì— ê±´ì„¤ë©ë‹ˆë‹¤.
ë„로 차고지를 건설하려면: ë„구를 í´ë¦­í•œ ë‹¤ìŒ (커서를 저장소로 변경), ë„ë¡œì˜ ëì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/ 제거로 차고지를 제거하십시오.}

주차: (pak 128ì—서만 ì´ìš© 가능) ë„구는 화물 ë° ìŠ¹ê°ì˜ 수용량 ë° ìš´í–‰ ê¶Œì—­ì„ ëŠ˜ë¦¬ê³  유지 ë¹„ìš©ì„ ì¦ê°€ì‹œí‚¤ëŠ” ì •ë¥˜ìž¥ì˜ í™•ìž¥ì„ êµ¬ì„±í•©ë‹ˆë‹¤.
ì¦ì¶•하려면: ë„구를 í´ë¦­í•˜ì—¬ ì¦ì¶•í•  ë¶€ë¶„ì„ ì„ íƒí•˜ê³  (커서를 확장 프로그램으로 변경), 게임 시ì ì˜ 기존 정류장 ì˜†ì— ìžˆëŠ” ë„로ì—서 필요한 위치를 í´ë¦­í•˜ì‹­ì‹œì˜¤. 새로 ì¦ì¶•한 ë¶€ë¶„ì€ ì´ ì •ë¥˜ìž¥ì˜ ì¼ë¶€ë¡œ 간주ë©ë‹ˆë‹¤.
{íŒ: 파괴/ 제거로 ì¦ì¶•ëœ ë¶€ë¶„ì„ ì œê±°í•˜ì‹­ì‹œì˜¤.}

ë„로-정류장: ë„구는 ë„로 ì°¨ëŸ‰ì´ í™”ë¬¼ ë° ìŠ¹ê°ì„ 싣고 내릴 수 있는 장소를 건설합니다.
ë„로-ì •ë¥˜ìž¥ì´ ê¸°ì¡´ ì •ë¥˜ìž¥ì— ì¸ì ‘해서 건설ë˜ì§€ 않으면 새로운 ì •ë¥˜ìž¥ì„ ë§Œë“¤ 수 있습니다.
ë„로-ì •ë¥˜ìž¥ì€ ë„ë¡œì— ê±´ì„¤ë˜ê³  화물, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì— ëŒ€í•œ 유지 비용 ë° ìš´í–‰ ê¶Œì—­ì´ ìžˆìŠµë‹ˆë‹¤. ì¼ë¶€ ë„구 ì˜µì…˜ì˜ ëª¨ì„œë¦¬ì— ì•„ì´ì½˜ (ì—­ ëª©ë¡ ë° ì •ë¥˜ìž¥ ì •ë³´ì— ì‚¬ìš©)ì€ ì •ë¥˜ìž¥ë¥¼ 처리​​할 수 있는 ë„로-ì •ë¥˜ìž¥ì˜ í•­ëª©ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 다른 ë„로-ì •ë¥˜ìž¥ì€ í™”ë¬¼, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì— ëŒ€í•´ 서로 다른 ìˆ˜ìš©ëŸ‰ì„ ê°€ì§ˆ 수 있습니다.
ë„로-ì •ë¥˜ìž¥ì„ ê±´ì„¤í•˜ë ¤ë©´: ë„구를 í´ë¦­í•˜ì—¬ ì„ íƒí•œ ë‹¤ìŒ (커서를 ë„로 정지까지 변경), 게임 시ì ì—서 ë„로 ìƒì˜ 필요한 위치를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/ 제거로 ë„로-ì •ë¥˜ìž¥ì„ ì œê±°í•˜ì‹­ì‹œì˜¤. 게임 시ì ì—서 화물 ë° ìŠ¹ê°ì˜ ìš´í–‰ ê¶Œì—­ì„ í† ê¸€í•˜ë ¤ë©´ [v]를 누르십시오. ë„로-ì •ë¥˜ìž¥ì€ ë‹¤ë¥¸ 플레ì´ì–´ê°€ 만든 ë„로ì—는 설치할 수 없습니다. ë” ë‚®ì€ ë„로 ìœ„ì— êµëŸ‰ì„ 건설하려면 [Ctrl]ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. 수용량 ë° ìš´í–‰ ê¶Œì—­ì„ ì¦ê°€ì‹œí‚¤ë ¤ë©´ ì°¨ëŸ‰ì— ëŒ€í•´ 여러 ìž¥ì†Œì— ì •ë¥˜ìž¥ì„ ë§Œë“œì‹­ì‹œì˜¤.}

simutrans-124.3/simutrans/text/ko/save.txt000066400000000000000000000043531474050137200207010ustar00rootroot00000000000000저장 ë„움ë§

저장

ì €ìž¥ì€ í˜„ìž¬ ê²Œìž„ì„ íŒŒì¼ì— 저장하고 (ë‚˜ì¤‘ì— ìž¬ìƒí•˜ê¸° 위해)ì´ íŒŒì¼ì„ 삭제하는 ë° ì‚¬ìš©í•  수 있습니다.

ì €ìž¥ì€ ê²Œìž„ 옵션 ë˜ëŠ” [S]를 눌러 ì—´ 수 있습니다; ì´ì „ ê²Œìž„ì˜ ì´ë¦„ê³¼ ë‚ ì§œ ë° ì‹œê°„ì„ ë‚˜ì—´í•©ë‹ˆë‹¤.
모든 ê²Œìž„ì´ ë³´ì´ì§€ 않는 경우: 목ë¡ì˜ ì˜¤ë¥¸ìª½ì— ìžˆëŠ” 슬ë¼ì´ë” 바를 사용하여 ì´ë¦„ì„ ìŠ¤í¬ë¡¤í•˜ì‹­ì‹œì˜¤.

현재 ê²Œìž„ì„ ìƒˆ 파ì¼ì´ë‚˜ 기존 ê²Œìž„ì— ì €ìž¥í•  수 있습니다.
ê²Œìž„ì„ ìƒˆ 파ì¼ë¡œ 저장하려면 저장 ìƒë‹¨ì˜ ìƒìžì— 새 ì´ë¦„ì„ ìž…ë ¥í•˜ì‹­ì‹œì˜¤. ìƒìžë¥¼ í´ë¦­í•˜ê³  ì´ë¦„ì„ ìž…ë ¥í•œ ë‹¤ìŒ [Enter] ë˜ëŠ” [Return] 키를 누르거나 확ì¸ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤; 새 íŒŒì¼ ì´ë¦„ì´ ë‚˜ì—´ë©ë‹ˆë‹¤.
중요사항: ë‚˜ì—´ëœ íŒŒì¼ ì´ë¦„ì´ ì‚¬ìš©ëœ ê²½ìš°: ì˜¤ëž˜ëœ ê²Œìž„ì€ í˜„ìž¬ ê²Œìž„ì— ë”°ë¼ ëŒ€ì²´ë˜ê³  ì†ì‹¤ë©ë‹ˆë‹¤.

기본ì ìœ¼ë¡œ 현재 ê²Œìž„ì´ ì´ íŒŒì¼ì— 저장하기 위해 íŒŒì¼ ì´ë¦„ ìƒìžì— 나타납니다: 확ì¸ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (ì´ì „ ë°ì´í„°ê°€ ì†ì‹¤ë˜ì–´ 현재 ë°ì´í„°ë¡œ 대체ë©ë‹ˆë‹¤).
ì´ì „ ê²Œìž„ì„ í†µí•´ 파ì¼ë¡œ ê²Œìž„ì„ ì €ìž¥í•˜ë ¤ë©´: 목ë¡ì—서 ì´ë¦„ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤ (예전 ê²Œìž„ì€ í˜„ìž¬ 게임으로 대체ë©ë‹ˆë‹¤).

íŒŒì¼ ì´ë¦„ì€ ê¸€ìž, ìˆ«ìž ë° ê¸°í˜¸ë¥¼ 최대 57ìžê¹Œì§€ ì¡°í•©í•  수 있습니다; 저장 후ì—는 저장 ë° ë¶ˆëŸ¬ì˜¤ê¸°ì— 20ìž ì •ë„ë§Œ 표시ë©ë‹ˆë‹¤.

경고: ê²Œìž„ì„ ì¦‰ì‹œ & ì˜êµ¬ì ìœ¼ë¡œ 삭제하기 위하여 íŒŒì¼ ì´ë¦„ì— ì˜í•˜ì—¬ x ë²„íŠ¼ì„ ëˆ„ë¥´ì‹­ì‹œì˜¤, íŒŒì¼ ì´ë¦„ì€ ëª©ë¡ì—서 제거ëœë‹¤. ì´ ê¸°ëŠ¥ì„ ì£¼ì˜í•˜ì—¬ 사용하십시오.

{íŒ: 불러오기ì—서 ì €ìž¥ëœ ê²Œìž„ì„ ë‹¤ì‹œ 시작하십시오.
simuconf.tabì—서 ìžë™ 저장 (ìžë™ 게임 저장)ì„ ë³€ê²½í•˜ì‹­ì‹œì˜¤}.

ì €ìž¥ì„ ë‹«ìœ¼ë ¤ë©´ 취소를 í´ë¦­í•˜ì‹­ì‹œì˜¤. ë˜ëŠ” 좌ìƒë‹¨ ë¶€ë¶„ì˜ x; ë˜ëŠ” 키보드를 사용하십시오.

simutrans-124.3/simutrans/text/ko/scenario.txt000066400000000000000000000004431474050137200215420ustar00rootroot00000000000000시나리오 ë„움ë§

시나리오

ë‹¹ì‹ ì€ simutransì—서 시나리오를 í”Œë ˆì´ í•  수 있습니다. 완수해야할 몇 가지 목표: 공장 연결시키기, 최단 시간으로 ë¶€ìžë˜ê¸°, 기ë…비ì ì¸ 본부 세우기.

simutrans-124.3/simutrans/text/ko/schedule.txt000066400000000000000000000034531474050137200215370ustar00rootroot00000000000000스케줄 다ì´ì–¼ë¡œê·¸ ë„움ë§

스케줄 다ì´ì–¼ë¡œê·¸

 스케줄 다ì´ì–¼ë¡œê·¸ì—서는, ì°¨ëŸ‰Â·ì„ ë°•ì˜ ìš´í–‰ 경로를 설정하는 ê²ƒì´ ì„±ê³¼
.ë§ë¶™ì—¬ì„œ 시ê°ì„ 설정한 ìš´í–‰ì€ í•  수 없습니다.

 운행 경로를 설정하려면 , ìš°ì„  추가 ë²„íŠ¼ì„ í´ë¦­í•©ë‹ˆë‹¤.다ìŒì—, ì •ì°¨
ì—­ë“±ì˜ ìœ„ë¥¼ í´ë¦­í•´ 주세요.항구를 지정하는 경우는, í•­êµ¬ì˜ ì£¼ë³€ì˜ ë§¤ìŠ¤
(ì„)를 í´ë¦­í•´ 주세요.ë¦¬ìŠ¤íŠ¸ì— ì—­ëª…Â·í•­ëª…ì´ ì¶”ê°€ë©ë‹ˆë‹¤.ë§ë¶™ì—¬ 선로ìƒÂ·
ë„로ìƒÂ·í•´ìƒì—서 ì—­ 등 나오지 않는 ìž¥ì†Œë„ ì¤‘ê³„ì ìœ¼ë¡œì„œ 설정할 수 있습니다.ì´ì™€ ê°™ì´ í•´
(ì´)ë¼ê³ , ìš´í–‰ ê²½ë¡œì˜ ì—­Â·í•­ë“±ì„ ì°¨ë¡€ì°¨ë¡€ë¡œ í´ë¦­í•˜ë©° ê°€ 주세요.최대 16개소
그리고 지정할 수 있습니다.

 차량·선박ì€, 리스트 위로부터 차례로 ì„¤ì •ëœ ê°œì†Œë¥¼ ë•니다.리스트ì˜
맨 밑까지 오면, ë˜ ìœ„ê¹Œì§€ ëŒì•„오고 ìš´í–‰ì„ ê³„ì†í•©ë‹ˆë‹¤.ë²ˆí˜¸ì˜ ì™¼ìª½ì˜ ë§ˆí¬ëŠ” 현
재 향하고 있는 개소를 나타냅니다.

 추가 버튼ì—서는, 새롭게 개소를 ë¦¬ìŠ¤íŠ¸ì˜ ë§¨ ë°‘ì— ì¶”ê°€í•©ë‹ˆë‹¤.삽입 버튼으로
(ì€)는, 리스트ìƒì˜ 현재 마í¬ê°€ 있는 항목ì—, 새로운 개소가 삽입ë©ë‹ˆë‹¤.리스트
ì˜ í•­ëª©ì„ ì‚­ì œí•˜ë ¤ë©´ , ì‚­ì œ ë²„íŠ¼ì„ í´ë¦­í•˜ê³ , 삭제하고 ì‹¶ì€ í•­ëª©ì„ í¬ë¦¬
ì¿  í•´ 주세요.모든 ì„¤ì •ì´ ë나면 종료 ë²„íŠ¼ì„ í´ë¦­í•´ 주세요.

ã€€ã€ŒìŒ“ì„ ë•Œê¹Œì§€ 대기ã€ì˜ 숫ìžëŠ”, ê·¸ 역·항으로, ì°¨ëŸ‰Â·ì„ ë°•ì— í™”ë¬¼Â·ì—¬ê°ì„ ì´
비율 ìŒ“ì€ ìƒíƒœê°€ ë  ë•Œê¹Œì§€, ì¶œë°œì„ ê¸°ë‹¤ë¦°ë‹¤ê³  하는 ì˜ë¯¸ìž…니다.ì´ ìˆ«ìžë¥¼ 대나무 쿠스
ì¼ë¡œ, í—›ë¨ì´ 없는 ìš´í–‰ì„ í•  수 있습니다.

simutrans-124.3/simutrans/text/ko/server.txt000066400000000000000000000025041474050137200212450ustar00rootroot00000000000000게임 ì •ë³´ / 서버 ë„움ë§

게임 정보 / 서버

게임 ì •ë³´ / 서버 는 시간대, ì§€ë„ í¬ê¸°, 회사 수, 마ì„, 시민, 공장, ìš´ì˜ì¤‘ì¸ ì°¨ëŸ‰ ë“±ë“±ì˜ ì‹¤í–‰ì¤‘ì¸ ê²Œìž„ì˜ í˜„ìž¬ ìƒíƒœë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤.

현재 ê²Œìž„ì´ ì˜¨ë¼ì¸ì´ 아닌 경우, 연결가능한 서버 목ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 만약 목ë¡ì´ 비어있다면, ë‹¹ì‹ ì˜ pak 버전ì´ë‚˜ 프로그램 ë²„ì „ì— ë§žëŠ” 서버가 없는 것입니다. ëª¨ë‘ ë³´ì´ê¸° ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ 존재하는 모든 서버를 확ì¸í•  수 있습니다.

서버를 ì„ íƒí•˜ë©´ 서버 ìƒíƒœì— 대한 게임 ì •ë³´ 개요가 표시ë©ë‹ˆë‹¤. (만약 서버가 다운ë˜ë©´, ì´ë¥¼ 확ì¸í•˜ëŠ” ë° ì•½ê°„ì˜ ì‹œê°„ì´ ì†Œìš”ë©ë‹ˆë‹¤.) ë˜í•œ ì„œë²„ì˜ pak setê³¼ 프로그램 ë²„ì „ì´ í‘œì‹œë©ë‹ˆë‹¤. 둘 다 ê²€ì€ ìƒ‰ì´ë¼ë©´, ë‹¹ì‹ ì˜ pak setê³¼ 프로그램 ë²„ì „ì´ ì„œë²„ì™€ ì¼ì¹˜í•˜ë©° 온ë¼ì¸ í”Œë ˆì´ ì„ ëˆŒëŸ¬ 참가할 수 있습니다.

pak setì´ ì¼ì¹˜í•˜ì§€ 않으면, í•­ëª©ì´ ë¹¨ê°„ìƒ‰ìœ¼ë¡œ 표시ë©ë‹ˆë‹¤. ë‹¹ì‹ ì˜ pak ë¹„êµ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ 누ë½ë˜ì—ˆê±°ë‚˜, 다르거나, í˜¹ì€ ì¶”ê°€ paksë“¤ì— ëŒ€í•œ 보고서를 받아 ë³¼ 수 있습니다. (다소 ì‹œê°„ì´ ê±¸ë¦´ 수 있습니다.)

simutrans-124.3/simutrans/text/ko/settings.txt000066400000000000000000000024311474050137200215760ustar00rootroot00000000000000ê³ ë„ì˜ ì„¤ì • ë„움ë§

ê³ ë„ì˜ ì„¤ì •

ê³ ë„ì˜ ì„¤ì •ìœˆë„우는새로운 ë§µì˜ ìž‘ì„± 윈ë„우로부터 엽니다.
여기ì—서는, 주로 작성하는 새로운 ë§µì˜ ë£°ì„ ì„¤ì •í•©ë‹ˆë‹¤.

 최ìƒë¶€ì˜ ë²„íŠ¼ì€ ë¦¬ì…‹ 버튼입니다.ì„¤ì •ì„ ë¦¬ì…‹íŠ¸ 합니다.주ì˜í•´ 간다
(ì´)다 ì°¨ì´.(ì¼ë¶€ 리셋트 ë˜ì§€ 않는 í•­ëª©ë„ ìžˆìŠµë‹ˆë‹¤)
Simuconf.tab simuconf.tabì˜ ì„¤ì •ì— ë¦¬ì…‹íŠ¸ 합니다.
Default.sveã€€ë§ˆì§€ë§‰ì— ì‹ ê·œ ë§µì„ ìž‘ì„±í–ˆì„ ë•Œì˜ ì„¤ì •ì— ë¦¬ì…‹íŠ¸ 합니다.

설정 항목ì—는, 세ì´ë¸Œ ê²Œìž„ì— ë³´ì¡´ë˜ëŠ” 것과 ë³´ì¡´ë˜ì§€ 않는 ê²ƒì´ ìžˆì–´
.
세ì´ë¸Œ ê²Œìž„ì— ë³´ì¡´ë˜ëŠ” 것ì€, ì‹ ê·œì— ìž‘ì„±ë˜ëŠ” 게임ì—게만 ë°˜ì˜ë©ë‹ˆë‹¤.
게임 개시 후로 변경할 수 없습니다.

ë³´ì¡´ë˜ì§€ 않는 설정 항목ì€, ë³€ê²½ì´ ì¦‰ì‹œì— ë°˜ì˜ë©ë‹ˆë‹¤.다만 ìž¬ê¸°ë™ í›„ëŠ” ì›ì˜
설정으로 ëŒì•„와 버리기 때문ì—, ë³€ê²½ì„ ê³ ì •í•˜ê³  ì‹¶ì€ ê²½ìš°ëŠ”, simuconf.tab나
cityrules.tab를 í…스트 ë¬¸ìž íŽ¸ì§‘ê¸°ë¡œ ì§ì ‘ 변경해 주세요.

ê° ì„¤ì • í•­ëª©ì˜ ìžì„¸í•œ ê²ƒì€ ã€Œì¼ë³¸ì–´í™” wikiã€ë¥¼ 참조해 주세요.

simutrans-124.3/simutrans/text/ko/shiptools.txt000066400000000000000000000027341474050137200217700ustar00rootroot00000000000000ì„ ë°• 툴 다ì´ì–¼ë¡œê·¸ ë„움ë§

ì„ ë°• ë„구 다ì´ì–¼ë¡œê·¸

 선박 툴ì—서는, 항구와 ë„í¬ì˜ ê±´ì¡° ì„ í•  수가 있습니다.

 ìƒë‹¨ì˜ ì œì¼ ì™¼ìª½ì˜ ë²„íŠ¼ì€, 항구 ê±´ì¡° ë„구입니다.항구ì—서는, ì„ ë°•ì´ í™”ë¬¼ì´ë‚˜ ì—¬ê°ì˜
실ìŒê³¼ ë‚´ë¦¼ì„ ì‹¤ì‹œí•©ë‹ˆë‹¤.ì•„ì´ì½˜ì„ í´ë¦­í•˜ë©´, 마우스 커서가 í•­êµ¬ì˜ í˜•íƒœ
ìƒíƒœì— 변화합니다.바다ì—
접한 경사면ì—서 í´ë¦­í•˜ë©´, ê·¸ 경사면과 ì¸ì ‘한다
ë°”ë‹¤ì™€ì˜ 2 매스를 ì´ìš©í•˜ê³ , 항구가 건조함
.항구를 건조하는 경사면ì€, ì§„
곧경사면(선로나 ë„로를 부설할 수 있는 경사면) 나오지 않으면 안ë©ë‹ˆë‹¤.ì„ 
ë°•ì„ ì •ë°•ì‹œí‚¤ë„ë¡(듯ì´) ìŠ¤ì¼€ì¤„ì„ ì§œë ¤ë©´ , 항구가 있는 매스가 아니고, 항구ì—
ì¸ì ‘하는 ë§¤ìŠ¤ì— ì •ë°•í•˜ë„ë¡(듯ì´) 지정해 주세요.Simutrans ì˜ í˜„ìž¬ì˜ ë°”ì£ 
ì—서는,í•­êµ¬ì˜ ì² ê±°ëŠ” 올바르게 ë™ìž‘하지 않습니다.

ã€€í•˜ë‹¨ì˜ ì™¼ìª½ì˜ 2ê°œì˜ ë²„íŠ¼ì€, ë„í¬ ê±´ì¡° ë„구입니다.ì´ê²ƒë“¤ 2는 화면ìƒì—서
ì˜ ë°©í–¥ì´ ë‹¤ë¥¸ 것만으로, 실질ì ìœ¼ë¡œëŠ” ì°¨ì´ëŠ” 없습니다.ë„í¬ëŠ”, ì„ ë°•ì˜ êµ¬ìž…ì´ë‚˜
스케줄 ì„¤ì •ì„ ì‹¤ì‹œí•˜ê¸° 위해서 필요합니다.ì•„ì´ì½˜ì„ í´ë¦­í•˜ë©´, 마우스
커서가 ë„í¬ì— 변화합니다.ë„í¬ëŠ” í•´ìƒì— 건조합니다.ë„í¬ë¥¼ ê±´ì¡°í•´
ì‹¶ì€ ìž¥ì†Œì—서 í´ë¦­í•´ 주세요.

simutrans-124.3/simutrans/text/ko/signal_spacing.txt000066400000000000000000000023741474050137200227250ustar00rootroot00000000000000신호등 배치 간격 ë„움ë§

ì¼ë°˜ì ì¸ 사용법:


-- 신호등 ì•„ì´ì½˜ì„ Ctrl-í´ë¦­í•˜ì—¬ gui를 불러옵니다.
-- íŠ¸ëž™ì„ í´ë¦­í•˜ê³  드래그 하면 만들어질 ì‹ í˜¸ë“±ì˜ ë¯¸ë¦¬ë³´ê¸°ê°€ 나타나고 마우스 ë²„íŠ¼ì„ ë†“ìœ¼ë©´ ê±´ì„¤ì´ ì§„í–‰ë©ë‹ˆë‹¤. 열차가 마우스로 드래그한 ë°©í–¥ì„ í†µê³¼í•  수 있어야만 ì‹ í˜¸ë“±ì´ ë§Œë“¤ì–´ì§‘ë‹ˆë‹¤.
-- 온ë¼ì¸ 게임ì—ì„ : 먼저 íŠ¸ëž™ì„ Ctrl-í´ë¦­í•˜ê³  마우스 ë²„íŠ¼ì„ ë†“ìŠµë‹ˆë‹¤. 마우스를 누르고 있는ë™ì•ˆ 마우스를 움ì§ì´ë©´ 미리보기가 나타납니다. ë²„íŠ¼ì„ ë†“ìœ¼ë©´ 만들어 집니다.

신호등 ì°½ì˜ ì¸ìžë“¤:

-- 신호등 배치 간격: 타ì¼ì— 얼마나 ë§Žì€ ì—°ì†ëœ ì‹ í˜¸ë“±ì„ ë°°ì¹˜í•  수 있는지 나타냅니다 (대ê°ì„ ì€ 1/2 타ì¼ë¡œ 계산한다). ì´ ê°’ì€ ì‹ í˜¸ë“±ì´ ì„ íƒë˜ë©´ 표시ë©ë‹ˆë‹¤.
-- 다른 신호등 제거: ì„ íƒë˜ë©´ ê¸¸ì˜ ë‹¤ë¥¸ ì‹ í˜¸ë“±ì€ ì‚­ì œë©ë‹ˆë‹¤.
-- 다른 신호등 재배치: ì„ íƒë˜ë©´, 만들려는 신호등 íƒ€ì¼ ìœ„ì— ìžˆëŠ” ê¸°ì¡´ì˜ ì‹ í˜¸ë“±ì€ ì‚­ì œë©ë‹ˆë‹¤.

ì´ ì¸ìžë“¤ì€ 다른 ì¢…ë¥˜ì˜ ì‹ í˜¸ë“±ê³¼ëŠ” ë…립ì ìœ¼ë¡œ 설정ë©ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/simutrans.txt000066400000000000000000000060761474050137200217740ustar00rootroot00000000000000Simutransì— ëŒ€í•˜ì—¬

Welcome to Simutrans!

첫째로, ì§€ë„ ê³ ë¥´ê¸°: ì¼ë‹¨ Simutransì˜ ìˆ˜ì²œ ê°œì˜ ì§€ë„ ì¤‘ 하나를 ì„ íƒí•˜ê±°ë‚˜ ë†’ì´ ì§€ë„ì—서 새 ì§€ë„를 만드십시오. 그런 ë’¤ ì¡°ë¶€ëª¨ì˜ ëˆì„ 물려 ë°›ì€ ì Šì€ ì‚¬ì—…ê°€ê°€ ë˜ì–´ë³´ì„¸ìš”. ê·¸ë“¤ì˜ ìžë¶€ì‹¬ì´ ë˜ê³ . 성공ì ì¸ 운송 회사를 세우려는 야ë§ê³¼ 함께 번창하는 운송 ì œêµ­ì„ ë§Œë“œëŠ” ì¼ ëª¨ë‘ ë‹¹ì‹ ì—게 달려있습니다.

ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼, 수백만 승ê°ì˜ 여행 요구 ì‚¬í•­ì„ ë§Œì¡±ì‹œí‚¤ê³  í™”ë¬¼ì„ ìš´ì†¡í•˜ì—¬ 경제를 ì›í™œížˆ ê°€ì†í™” 시키는 ë™ì•ˆ ë‹¹ì‹ ì˜ íšŒì‚¬ë¥¼ 성공ì ì¸ 기업으로 발전십시오. ë‹¹ì‹ ì€ ìŠ¹ê°, 우편 ë° í™”ë¬¼ì„ ì² ë„, ë„로, ì„ ë°•, 심지어 í•­ê³µìœ¼ë¡œë„ ìš´ì†¡ í•  수 있습니다.

모든 ì§€ë„는 ê°ìž 다른 요소를 제공합니다. 주변 í™˜ê²½ì„ ìž˜ 살펴보십시오: ê·¸ê²ƒë“¤ì€ ëª¨ë‘ ë‹¹ì‹ ê³¼ ê²½ìŸìž ì† ìœ„ì— ë†“ì—¬ìžˆìŠµë‹ˆë‹¤.

ë°œì „ì†Œì— í•„ìš”í•œ ë¬¼í’ˆì„ ê³µê¸‰í•˜ëŠ” ê²ƒì´ ê°€ìž¥ 쉽다는 ê²ƒì„ ì•Œ 수 ìžˆì„ ê²ë‹ˆë‹¤. ë‹¹ì‹ ì´ ë²ˆ ëˆì„ ì ì°¨ì ìœ¼ë¡œ ê³µìž¥ì— íˆ¬ìží•´ 확장시키십시오 - 어쩌면 í™”ë¬¼ì„ ë‹¤ì‹œ ì‹¤ì„ ìˆ˜ 있는 중앙 허브를 사용할 ìˆ˜ë„ ìžˆì„ ê²ƒìž…ë‹ˆë‹¤. í™”ë¬¼ì„ ìš´ì†¡ë§Œ 한다면 마ì„ê³¼ ë„시가 성장하지 않고 새로운 ì‚°ì—…ì´ ì¶œí˜„í•˜ì§€ ì•Šì„ ê²ƒìž…ë‹ˆë‹¤.

ë˜ëŠ”, 즉시 승ê°(ë° ìš°íŽ¸) ìˆ˜ì†¡ì„ í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. Simutrans ì›”ë“œì˜ ì£¼ë¯¼ë“¤ì€ ëª¨ë‘ íŠ¹ì • 목ì ì§€ë¡œ 여행하기를 ì›í•˜ê¸° ë•Œë¬¸ì— ì´ ë°©ë²•ì€ ë”ìš± 어려울 수 있습니다. ëª‡ëª‡ì€ ê³µìž¥ì— ì¼í•˜ë¡œ 가길 ì›í•˜ê³ , ëª‡ëª‡ì€ ì‹œë‚´ì— ì‡¼í•‘í•˜ê¸¸ ì›í•˜ë©° ë˜ ë‹¤ë¥¸ì´ë“¤ì€ 관광 ëª…ì†Œì— ë°©ë¬¸í•˜ê¸¸ ì›í•©ë‹ˆë‹¤. 만약 ê·¸ë“¤ì´ ì›í•˜ëŠ” 목ì ì§€ì™€ ì—°ê²°ë˜ì–´ 있지 않다면, ê·¸ë“¤ì€ ë‹¹ì‹ ì„ ìœ„í•´ 여행하지 ì•Šì„ ê²ƒìž…ë‹ˆë‹¤.

ë‹¹ì‹ ì€ ê°€ëŠ¥í•œ ë§Žì´ ëŒ€ì¤‘ì ì¸ 목ì ì§€ì— ë„달할 수 있는 운송 네트워í¬ë¥¼ 구축해야 합니다. 네트워í¬ê°€ 형성ë˜ë©´, ì§€ì†ì ì¸ 수요를 유지하기 위해 ì§€ì†ì ìœ¼ë¡œ 업그레ì´ë“œí•´ì•¼ í•  것입니다, 그러니 미리 계íší•˜ì‹­ì‹œì˜¤! 만약 승ê°ë“¤ì´ ë‹¹ì‹ ì˜ ì„œë¹„ìŠ¤ì— ë§Œì¡±í•œë‹¤ë©´, 마ì„ì€ ì„±ìž¥í•˜ê³  새로운 ì‚°ì—…ì²´ë“¤ì´ ì„¤ë¦½ë  ê²ƒì´ë©°, 그럴 경우ì—ë§Œ 경제가 ì›í™œížˆ ìš´ì˜ë  것입니다.

ë‹¹ì‹ ì€ ìµœëŒ€í•œ 오래 플레ì´í•˜ëŠ” ê²ƒì„ ì¢‹ì•„í•  수 있습니다. 그렇다면 1880ë…„ì— ì‹œìž‘í•´ì„œ 2050ë…„ì— ë내십시오, í˜¹ì€ ì´ ì‚¬ì´ ì–´ë–¤ 시대로든 시작 ì‹œê°„ì„ ì„¤ì •í•˜ì‹­ì‹œì˜¤. ì‹œê°„ëŒ€ì— ë§žëŠ” 차량과 ë¹Œë”©ì´ ì¡´ìž¬í•©ë‹ˆë‹¤. AI를 ìƒëŒ€í•˜ê±°ë‚˜ ë‹¹ì‹ ì„ ìœ„í•´ í”Œë ˆì´ í•˜ì‹­ì‹œì˜¤. 하지만 주ì˜í•  ì ì€: 3개월 ë™ì•ˆ 마ì´ë„ˆìФ ìž¬ì‚°ì„ ìœ ì§€í•œë‹¤ë©´, ë‹¹ì‹ ì€ íŒŒì‚°í•  것ì´ê³  ê²Œìž„ì€ ë나게 ë©ë‹ˆë‹¤. 재정 ì°½ì„ í†µí•´ ìžì‚°ì„ 확ì¸í•˜ì‹­ì‹œì˜¤.

Simutrans 팀 ê³¼ 커뮤니티는 ë‹¹ì‹ ì´ Simutrans 플레ì´í•˜ë©° ì¦ê±°ìš´ ì‹œê°„ì„ ë³´ë‚´ì‹œê¸¸ ë°”ëžë‹ˆë‹¤!

simutrans-124.3/simutrans/text/ko/slopetools.txt000066400000000000000000000041421474050137200221420ustar00rootroot00000000000000슬로프 툴 ë„움ë§

슬로프 ë„구

슬로프 ë„구를 사용하고, 육지를 조성할 수 있습니다.조성할 수 있다
장소는 ì•„ë¬´ê²ƒë„ ì—†ëŠ” 빈터나 í•´ìƒì— 한정ë©ë‹ˆë‹¤.
[#]키([shift+3])로, 구ë¼ë‘를 표시 하게 하면 편리합니다.

육지를 비싸게 한다
 육지를 현재보다 1 레벨ìƒì˜ 높ì´ì— ë¶ë‹ì›ë‹ˆë‹¤.
육지를 낮게 한다
 육지를 현재보다 1 ë ˆë²¨í•˜ì˜ ë†’ì´ì— 움푹 팬 ê³³.

ì´ìƒì˜ 2ê°œì˜ ë„구는, 왼쪽 í´ë¦­ ë˜ëŠ” 왼쪽 ë²„íŠ¼ì„ ëˆ„ë¥¸ 채로 드러그 í•´
사용합니다.ë“œëŸ¬ê·¸ì˜ ê²½ìš°ëŠ”, ëª¨ë‘ ê°™ì€ ë†’ì´ê°€ ë©ë‹ˆë‹¤.
조성하는 ì²´ì ì— 비례하고, ë¹„ìš©ì´ ë¹„ì‹¸ì§‘ë‹ˆë‹¤.
ìˆ˜ëª©ë“±ì˜ ìžì—°ë¬¼ì€ 제거ë˜ì–´ 버립니다.

ìŠ¬ë¡œí”„ì˜ ê±´ì„¤: ì¸ê³µì ì¸ ì¡°ì„±ì„ í•©ë‹ˆë‹¤.

ì™¼ìª½ì˜ 4개는 경사지를, ì˜¤ë¥¸ìª½ì˜ 2개는 수ì§ì— 육지를 분위기 ê³ ì·¨/ì¸í•˜í•©ë‹ˆë‹¤.
ì¸ê³µì ì¸ 조성ì—서는, ì£¼ìœ„ì™€ì˜ ë‹¨ì°¨ë¥¼ 2단 ì´ìƒìœ¼ë¡œ í•  수 없습니다.
ì´ëŸ¬í•œ ë„구는 빈터나 í•´ìƒ ì´ì™¸ì—, 선로/ë„ë¡œì˜ ì¢…ë‹¨ìƒì—ì„œë„ ì‚¬ìš©í•  수 있습니다.

선로/ë„ë¡œì˜ ì¢…ë‹¨ìƒì—ì„œì˜ ì‚¬ìš©
ì´ ê²½ìš°, 주로 ì˜¤ë¥¸ìª½ì˜ 2ê°œì˜ ë„구를 사용하고, 선로/ë„로마다 경사시킵니다.
ë°©í–¥ì´ ë§žìœ¼ë©´ ì™¼ìª½ì˜ 4ê°œì˜ ìŠ¬ë¡œí”„ë„ ì‚¬ìš©í•  수 있습니다만, 별로 편리하지는 않습니다.
경사를 바탕으로 ë˜ëŒë¦¬ëŠ” 경우ì—ë„, ì´ê²ƒë“¤ 2ê°œì˜ ë„구를 사용합니다.
ë‚´ë¦¬ë§‰ì˜ ê²½ì‚¬ë¥¼ 바탕으로 ë˜ëŒë¦¬ë ¤ë©´ , 분위기 ê³ ì·¨ ë„구가, ì˜¤ë¦„ì˜ ê²½ì‚¬ë¥¼ 바탕으로 ë˜ëŒë¦¬ë ¤ë©´ ,
ì¸í•˜ ë„구를 사용할 수 있습니다.
지하ì—서 선로/ë„로를 경사시키고 ì‹¶ì€ ê²½ìš°ì—는, 필요합니다.

슬로프를 ë˜ëŒë¦°ë‹¤
ì¸ê³µì ì¸ 조성지나 ê·¸ 주위를, 가능한 한 ìžì—°ìŠ¤ëŸ¬ìš´ ìƒíƒœì— ë˜ëŒë¦½ë‹ˆë‹¤.
선로/ë„ë¡œì˜ ì¢…ë‹¨ìƒì—서는 사용할 수 없습니다.

simutrans-124.3/simutrans/text/ko/sound.txt000066400000000000000000000015771474050137200211000ustar00rootroot00000000000000소리 설정 ë„움ë§

소리 설정

소리 설정ì—서는 효과ìŒê³¼ BGMì„ ì¡°ì ˆí•  수 있습니다.

소리 ì„¤ì •ì€ ê²Œìž„ 옵션ì—서 ì—´ 수 있습니다.

화살표 버튼ì´ë‚˜ 슬ë¼ì´ë“œ 바를 ì´ìš©í•˜ì—¬ ì„¤ì •ì„ ì¡°ì ˆí•  수 있습니다.

소리 í¬ê¸°: 효과ìŒì˜ í¬ê¸°ë¥¼ 조절합니다.

ìŒì•… í¬ê¸°: BGMì˜ í¬ê¸°ë¥¼ 조절합니다. ìŒì•…ì´ ì—†ìœ¼ë©´ ìž‘ë™í•˜ì§€ 않습니다.

ìž¬ìƒ ì¤‘ì¸ ìŒì•…: BGMì„ ë°”ê¿‰ë‹ˆë‹¤. 화살표 버튼으로 바꿀 수 있습니다.
ìž„ì˜ ìž¬ìƒì„ 누르면, 노래가 ìž„ì˜ì˜ 순서로 재ìƒë©ë‹ˆë‹¤.

온ë¼ì¸ ìŒì›ì„ 추가하고 싶으시다면, http://wiki.simutrans.com를 참조하세요.

simutrans-124.3/simutrans/text/ko/special.txt000066400000000000000000000145421474050137200213640ustar00rootroot00000000000000특수 건설 ë„구 ë„움ë§

특수 건설 ë„구

특수 건설 ë„구 는 êµí†µê³¼ 관련 없는 항목들로 구성ë˜ë©° 다른 플레ì´ì–´ë„ ìž‘ë™ì‹œí‚¬ 수 있ë„ë¡ í—ˆìš©ë©ë‹ˆë‹¤.

ë„구 모ìŒ(toolbar)ì„ ì—´ê¸° 위해 게임 ë·° ìƒë‹¨ì— 위치한 red-drop-in-yellow-circle ì•„ì´ì½˜ (pak128ì˜ í¬ë ˆì¸ ì•„ì´ì½˜) ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤. 마우스 커서를 ë„구 옵션 ìœ„ì— ì˜¬ë ¤ (ë„구 모ìŒì„ 열거나 í´ë¦­í•œ 후) ì´ë¦„ê³¼ ë‹¤ìŒ í•­ëª©ì„ í™•ì¸: 건설비용.

특수 건설 ë„구 ê°€ í¬í•¨í•˜ëŠ” ë„구들(좌측 부터):

ìš°ì²´êµ­: 정거장 ì´ ìš°íŽ¸ë¬¼ì„ ì²˜ë¦¬ í•  수 있게 해주는 ìš°ì²´êµ­ì„ ë§Œë“œëŠ” ë„구입니다. ìš°ì²´êµ­ì€ ì •ê±°ìž¥ì˜ ìˆ˜ìš© ë° ì§‘ìˆ˜ ìš©ëŸ‰ì„ ëŠ˜ë¦¬ê³  유지 보수 ë¹„ìš©ì´ ìžˆìŠµë‹ˆë‹¤.
ìš°ì²´êµ­ 만들기: ì„ íƒí•œ ë„구를 í´ë¦­í•œ ë’¤, 게임 ë·°ì˜ ê¸°ì¡´ ì •ê±°ìž¥ì„ í´ë¦­í•©ë‹ˆë‹¤. 새로운 만든 ìš°ì²´êµ­ì€ ì´ì œ ì •ê±°ìž¥ì˜ ì¼ë¶€ê°€ ë©ë‹ˆë‹¤.
{íŒ: 파괴/제거 ë„구로 ìš°ì²´êµ­ì„ ì œê±°í•  수 있습니다.}

ì—­ 확장: 정거장 ì˜ ê±´ë¬¼ë“¤ì„ ì¶”ê°€í•˜ê±°ë‚˜ 확장하기 위한 ë„구 입니다. 확장 ë„구는 물품과 승ê°ë“¤ì„ 위한 집수 êµ¬ì—­ì˜ ìš©ëŸ‰ê³¼ 유지 ë¹„ìš©ì„ ì¦ê°€ 시킬 수 있습니다. ì¼ë¶€ ë„구 옵션 구ì„ì— ìžˆëŠ” ì•„ì´ì½˜ (ì—­ ëª©ë¡ ê³¼ ì—­ ì •ë³´ì—서 사용ë˜ëŠ”) ì€ í™•ìž¥ë„구로 ì •ê±°ìž¥ì„ ë‹¤ë£° 수 있는 í•­ëª©ë“¤ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
확장 시키기: ì„ íƒí•œ ë„구를 í´ë¦­í•œ ë’¤ (커서가 확장 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), 게임 ë·° ë‚´, 기존 정거장 옆ì—, ì›í•˜ëŠ” ê³µê°„ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/제거 ë„구로 í™•ìž¥ì‹œì„¤ì„ ì œê±°í•  수 있습니다.}

P+ 플레ì´ì–´ êµì²´: 만약 게임 시작 ì „ 플레ì´ì–´ êµì²´ 허용 ì´ ì²´í¬ë˜ì–´ 있다면 다른 플레ì´ì–´ 로 게임 í”Œë ˆì´ í•˜ëŠ” ê²ƒì„ í—ˆìš©í•©ë‹ˆë‹¤. 추가 옵션 으로 플레ì´ì–´ ê³µë™ ì´ìš©ì„ 가능하게 í•  수 있습니다.
플레ì´ì–´ë¥¼ 바꾸기 위해 ë„구를 í´ë¦­í•˜ì‹­ì‹œì˜¤ (í˜¹ì€ [P] 를 누르거나). 플레ì´ì–´ 변경 ì‚¬ì‹¤ì„ ì•Œë ¤ì£¼ëŠ” í™•ì¸ ë©”ì„¸ì§€: 좌측 ìƒë‹¨ x를 í´ë¦­í•˜ê±°ë‚˜ 키보드를 사용하여 ëŒ ìˆ˜ 있습니다.

ë„시 건설: 새로운 ë„시 구역.
ì„ ì„¤ë¦½í•˜ëŠ” ë„구입니다. 새 ë„시 만들기: ì„ íƒí•œ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [C] 키를 누른 ë’¤ (커서가 시청 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), 게임 ë·°ì—서 ì›í•˜ëŠ” ì§€ì—­ì„ í´ë¦­í•©ë‹ˆë‹¤. 새 ë„시는 추가 í™•ì¸ ì—†ì´ 500ë§Œ credits 으로 건설ë˜ì–´ì§‘니다.
{íŒ: 파괴/제거 ë„구로 게임 ë·° ë‚´ ì‹œì²­ì„ í´ë¦­í•˜ì—¬ 새 ë„시를 제거할 수 있습니다.}

나무 심기: 게임 ë·° ë‚´ì—서 나무를 심는 ë„구입니다.
나무 심기: ì„ íƒí•œ ë„구를 í´ë¦­í•œ ë’¤ (커서가 나무 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), ì›í•˜ëŠ” ê³µê°„ì„ í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/제거 ë„구로 나무를 제거할 수 있습니다.}

ê³ ì•• ì „ì„  만들기: ë°œì „ì†Œì˜ ë³€ì „ì†Œì™€ ì‚°ì—…ì²´ ê°„ì— ì „ë ¥ì„ ê³µê¸‰í•˜ê¸° 위해 ì „ì••ì„ ì„ êµ¬ì¶• (ìƒì‚°ì„±ì„ 높ì´ê¸° 위해) 하는 ë„구입니다. ì „ë ¥ì˜ ê³µê¸‰ì€ ìˆ˜ìž…ì„ ì°½ì¶œí•´ëƒ…ë‹ˆë‹¤. ì´ ì „ë ¥ì„ ì€ ëŒ€ê°ì„  트랙과 ë„ë¡œì— êµì°¨ì‹œí‚¬ 수 없습니다.
ê³ ì•• ì „ì„  만들기: ì„ íƒí•œ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [l]키를 누른 ë’¤ (커서가 ì „ì••ì„  ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), 발전소 ì˜†ì— ìžˆëŠ” 변전소를 í´ë¦­í•˜ê³ , 마지막으로 ì‚°ì—…ì²´ì—서 변전소를 í´ë¦­í•˜ì—¬ ìƒì‚°ëŸ‰ì„ ì¦ê°€ì‹œí‚¤ëŠ” ì „ë ¥ì„ ê³µìŠµí•˜ì‹­ì‹œì˜¤.

변전소 ê³ ì•• ì „ì„ ì„ ì—°ê²°í•˜ê¸° 위해 발전소나 ì‚°ì—…ì²´ ì— í•„ìš”í•œ 변전소를 건설하기 위한 ë„구입니다.
변전소 만들기: ì„ íƒí•œ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [g] 키를 누른 ë’¤ (커서가 red-drop-in-yellow-circle ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), 게임 시ì ì—서, 산업체나 발전소 옆 ì›í•˜ëŠ” ê³µê°„ì„ í´ë¦­í•©ë‹ˆë‹¤.
ë°œì „ì†Œì— ì„¤ì¹˜ëœ ë³€ì „ì†ŒëŠ” 반드시 ì‚°ì—…ì²´ì˜ ë³€ì „ì†Œì™€ 연결하여 ê³ ì•• ì „ì„ ì„ í†µí•´ 전기를 공급 ë°›ë„ë¡ í•˜ì—¬ì•¼ 합니다.
전기가 공급ë˜ì§€ 않는다면, 게임 시ì ì—서 변전소는 노란 번개 모양으로 표시ë˜ê³  전류가 공급 ëœë‹¤ë©´ ë¶‰ì€ ë²ˆê°œ 모양으로 표시ë©ë‹ˆë‹¤.
{íŒ: 산업체와 발전소는 ì „ë ¥ ê³µê¸‰ì„ ë†’ì´ê¸° 위해 여러 변전소를 가질 수 있습니다. 파괴/제거 ë„구로 변전소를 제거할 수 있습니다.}

í‘œì§€íŒ ë§Œë“¤ê¸°: 게임 시ì ì—서 ì›í•˜ëŠ” í…스트를 ì ì„ 수 있는 표지íŒì„ 배치하고 게임 뷰를 다른 ì§€ì ìœ¼ë¡œ ì´ë™ì‹œí‚¤ëŠ” ë° ì‚¬ìš©í•  수 있는 ë„구입니다.
ì„ íƒí•œ ë„구를 í´ë¦­í•˜ê±°ë‚˜ [M] 키를 누른 ë’¤, 커서가 í‘œì§€íŒ ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨, 게임 ë·°ì—서 ì›í•˜ëŠ” ì§€ì ì„ í´ë¦­í•˜ì—¬ í‘œì§€íŒ ì¡°ìž‘ì„ ì—½ë‹ˆë‹¤. í‘œì§€íŒ ì¡°ìž‘ ìƒë‹¨ì— ì„ íƒí•œ ìœ„ì¹˜ì˜ ì¢Œí‘œê°€ 기입ë˜ê³ , 빈ìƒìžì— ì›í•˜ëŠ” í…스트를 ìž…ë ¥ (박스를 í´ë¦­í•˜ê³  í…스트를 입력한 ë’¤ í™•ì¸ ì„ í´ë¦­í•˜ê±°ë‚˜ [Enter] í˜¹ì€ [Return]ì„ ëˆ„ë¥´ì‹­ì‹œì˜¤) 한 후 표지íŒì„ 배치합니다. 게임 시ì ì—서 새 표지íŒì´ 보여지고 다시 연다면 í‘œì§€íŒ ì¡°ìž‘ (ì§€ë„ ì¢Œí‘œì™€ 함께) ì´ ë‚˜ì—´ë©ë‹ˆë‹¤.
표지íŒìœ¼ë¡œ 게임 ì‹œì  ì´ë™í•˜ê¸°: í‘œì§€íŒ ì¡°ìž‘ì„ ì—´ê³  목ë¡ì—서 ì›í•˜ëŠ” ì§€ì ì„ í´ë¦­í•©ë‹ˆë‹¤.
í‘œì§€íŒ ì œê±°í•˜ê¸°: í‘œì§€íŒ ë§Œë“¤ê¸° ë„구를 í´ë¦­í•˜ê±°ë‚˜ [M] ì„ ëˆ„ë¥¸ ë’¤, 커서가 í‘œì§€íŒ ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨; 게임-시ì ì—서 표지íŒì˜ 좌표를 í´ë¦­í•œê³ ; í‘œì§€íŒ ì¡°ìž‘ì—서 제거 를 í´ë¦­í•©ë‹ˆë‹¤.
í‘œì§€íŒ ì¡°ìž‘ 닫기: 좌측 ìƒë‹¨ì˜ x 를 í´ë¦­í•˜ê±°ë‚˜; 취소 를 í´ë¦­; í˜¹ì€ í‚¤ë³´ë“œë¥¼ 사용하십시오.
{íŒ: ì»¤ì„œì˜ ì¢Œí‘œëŠ” 게임-ì‹œì  ìš°ì¸¡ í•˜ë‹¨ì— í‘œì‹œë©ë‹ˆë‹¤. [!] 키를 사용하여 게임-시ì ì—서 표지íŒì˜ í…스트 ëª¨ì–‘ì„ ë³€ê²½ì‹œí‚¬ 수 있습니다.}

simutrans-124.3/simutrans/text/ko/station.txt000066400000000000000000000021171474050137200214200ustar00rootroot00000000000000ì—­ ì •ë³´ 다ì´ì–¼ë¡œê·¸ ë„움ë§

ì—­ ì •ë³´ 다ì´ì–¼ë¡œê·¸

 역 ì •ë³´ 다ì´ì–¼ë¡œê·¸ì—는, ê·¸ ì—­ì— ê´€í•œ ì •ë³´ê°€ 표시ë©ë‹ˆë‹¤.ë˜, 여기서
ì—­ëª…ì„ ë³€ê²½í•˜ëŠ” ì¼ë„ í•  수 있습니다.

 다ì´ì–¼ë¡œê·¸ ìƒë¶€ì˜ í…스트 필드ì—는, ì—­ëª…ì´ í‘œì‹œë˜ê³  있습니다.여기ì—
문ìžë¥¼ 입력하는 ì¼ë¡œ, ì—­ëª…ì„ ë³€ê²½í•  수 있습니다.

ã€€ìš°ì¸¡ì— ìžˆëŠ” ìƒì„¸ ë²„íŠ¼ì„ í´ë¦­í•˜ë©´, ê·¸ ì—­ì— ê´€í•œë³´ë‹¤ ìƒì„¸í•œ 정보를
조사할 수가 있습니다.

 역 ì •ë³´ 다ì´ì–¼ë¡œê·¸ì˜ 주요한 부분ì€, í•˜ë¶€ì— ìžˆëŠ” í™”ë¬¼Â·ìŠ¹ê° ë¦¬ìŠ¤íŠ¸ìž…ë‹ˆë‹¤.여기
ì—는, ê·¸ ì—­ì—서 ìˆ˜ì†¡ì„ ê¸°ë‹¤ë¦¬ê³  있는 화물ì´ë‚˜ 승ê°ì˜ ì¼ëžŒì´ 표시ë©ë‹ˆë‹¤.ì´ ì¼ëžŒ
정보는, í™”ë¬¼ì˜ ì¢…ë¥˜ë§ˆë‹¤, 목ì ì§€ 마다 표시ë©ë‹ˆë‹¤.ë˜, ì—¬ê¸°ì— í‘œì‹œë˜ì–´
정보는 ê²Œìž„ì˜ ì§„í–‰ì— ìˆ˜ë°˜í•´ ìžë™ì ìœ¼ë¡œ 갱신ë˜ê¸° 때문ì—, ìµœì‹ ì˜ ì •ë³´ë¥¼ 얻는다
위해(때문ì—) 다ì´ì–¼ë¡œê·¸ë¥¼ 다물어 다시 ì—´ 필요는 없습니다.

simutrans-124.3/simutrans/text/ko/station_details.txt000066400000000000000000000014171474050137200231270ustar00rootroot00000000000000ì—­ ì •ë³´ ìƒì„¸ 다ì´ì–¼ë¡œê·¸ 헬프

ì—­ ì •ë³´ ìƒì„¸ 다ì´ì–¼ë¡œê·¸ ë„움ë§

 역 ìƒì„¸ 다ì´ì–¼ë¡œê·¸ì—서는, ì´ ì—­ì— ì ‘ì†ë˜ê³  있는 ê³µìž¥ì„ ë‚˜íƒ€ë‚´ê³  있습니다.ë˜,
ì´ëŸ¬í•œ ê³µìž¥ì´ ì–´ëŠ ì œí’ˆì„ í•„ìš”ë¡œ 하고 있ì„ì§€ë„ ë‚˜íƒ€ë‚´ ë³´ì´ê³  있습니다.

ã€€ì´ ì ‘ì† ì •ë³´ëŠ”, í™˜ìŠ¹ì„ í•˜ì§€ 않고 ì§ì ‘ 보낼 수 있는 목ì ì§€ë§Œì„
나타내 ë³´ì´ê³  있습니다.승ê°ê³¼ 화물ì€, 최종ì ì¸ 목ì ì§€ì— 겨우 ë„ì°©í•˜ëŠ”ë° í•„ìš”í•˜ë©´ 몇 번ì¸ê°€
ì˜ í™˜ìŠ¹ì„ ì‹œë„합니다.

ã€€ì—­ì˜ ìžì„¸í•œ 것ì€,ì—­ ì •ë³´ 다ì´ì–¼ë¡œê·¸ì— 있는ìƒì„¸ë²„íŠ¼ì„ ëˆ„ë¥´ëŠ” ê²ƒì— ì˜í•´ì„œ 연다
ì¼ì´ ìƒê¹ë‹ˆë‹¤.

simutrans-124.3/simutrans/text/ko/trafficlight_info.txt000066400000000000000000000012131474050137200234140ustar00rootroot00000000000000êµí†µ 신호등 제어

êµí†µ 신호등 제어

êµí†µ ì‹ í˜¸ë“±ì˜ ë¹¨ê°„ë¶ˆê³¼ ì´ˆë¡ë¶ˆì˜ 빈ë„를 제어할 수 있습니다. ì„ íƒí•  수 있는 ê²ƒì€ ë¶/남 ê³¼ ë™/서 ë°©í–¥ì˜ ì´ˆë¡ë¶ˆ ì§€ì†ì‹œê°„입니다 (ì´ˆ 단위).

모든 êµí†µ ì‹ í˜¸ë“±ì´ ë‹¨ê³„ì ìœ¼ë¡œ 전환ë˜ë¯€ë¡œ, 세 번째 í•„ë“œì— ì¶”ê°€ ì˜¤í”„ì…‹ì„ ìž‘ì„±í•˜ì—¬, í›„ì† êµí†µ ì‹ í˜¸ë“±ì„ í†µí•´ 특정 방향으로 장애물 없는 êµí†µ íë¦„ì„ ì‹¤í˜„ì‹œí‚¬ 수 있습니다.

êµí†µ ì‹ í˜¸ë“±ì€ ë„로 건설 ë„구 ëª¨ìŒ ì—서 만들 수 있습니다.

simutrans-124.3/simutrans/text/ko/tramtools.txt000066400000000000000000000231551474050137200217700ustar00rootroot00000000000000노면전차 ë„구 ë„움ë§

노면전차 ë„구

노면전차 ë„구 는 ì „ì°¨ 수송ë§ì„ 건설합니다. ì´ ë„구로 만들 수 있는 것: ì „ì°¨ 트랙 (전기를 통하게 하거나 ê·¸ê²ƒì„ ì œê±°í•˜ê±°ë‚˜), 신호들, 노면전차 차량기지, 노면전차 정류장. 타임 ë¼ì¸ 으로 í”Œë ˆì´ í•˜ëŠ” 경우 Simutransì—서 ì‹œê°„ì´ ì§€ë‚¨ì— ë”°ë¼ ë” ë§Žì€ ë„구 ì˜µì…˜ì´ ë‚˜íƒ€ë‚  수 있습니다.

게임 ë·° ìƒë‹¨ì˜ ì „ì°¨ ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ ë„구 모ìŒ(toolbar)를 엽니다.
ë„구 옵션 ìœ„ì— ë§ˆìš°ìŠ¤ 커서를 가져 가면 (ë„구 모ìŒ(toolbar)를 열거나 í´ë¦­í•œ ë’¤) ì´ë¦„ê³¼ ë‹¤ìŒ íŠ¹ì§•ë“¤ì„ ë³¼ 수 있습니다: 건설 비용, & ì†ë„ 제한.

노면전차 ë„구 ê°€ 만들 수 있는 것들 , 좌측부터:

ì „ì°¨ 트랙: ë‘ ì§€ì  ì‚¬ì´ì˜ ì² ë„ ì°¨ëŸ‰ì´ ì´ìš©í•˜ëŠ” íŠ¸ëž™ì„ ë§Œë“œëŠ” ë„구ì´ë‹¤.
ì „ì°¨ íŠ¸ëž™ì€ ë„로와 ë„시 ì§€ì—­ì— ë”°ë¼ ì§€ì–´ì§ˆ 수 있지만 ê±´ë¬¼ì„ ê°€ë¡œì§ˆëŸ¬ì„œëŠ” 불가능 합니다. íŠ¸ëž™ì€ ê²½ì‚¬ë¡œì—ë„ ê±´ì„¤í•  수 있는ë°, 거친 지형, ë¬¼ì´ ìžˆëŠ” 지형, ìž¥ì• ë¬¼ì´ ì—†ëŠ” 지형ì—ë§Œ 건설 가능합니다. 새로 만든 íŠ¸ëž™ì€ ê¸°ì¡´ 트랙과 한 경로로 ì´ì„ 수 있습니다.
트랙 만들기: ë„구를 í´ë¦­í•˜ì—¬ íŠ¸ëž™ì„ ì„ íƒí•˜ì‹­ì‹œì˜¤ (커서가 트랙 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨); ê·¸ 후 íŠ¸ëž™ì˜ ì‹œìž‘ì ì— 대한 게임 뷰를 í´ë¦­í•˜ì‹­ì‹œì˜¤ (게임 ë·°ì— ë¶ˆë„저가 나타나고 우측 하단 ë°”ì— ì¢Œí‘œê°€ 표시ë¨); 마지막으로 íŠ¸ëž™ì˜ ì¢…ì ì— 대한 게임 뷰를 í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 다른 ìœ í˜•ì˜ íŠ¸ëž™ì´ ì—°ê²°ë  ìˆ˜ 있습니다 (단, 다른 플레ì´ì–´ê°€ 만든 경우는 제외). 거친 지형ì—서 íŠ¸ëž™ì„ ì—°ê²°í•˜ê±°ë‚˜ ìž¥ì• ë¬¼ì„ í”¼í•˜ë ¤ë©´ 다리 ë° í„°ë„ì„ ì‚¬ìš©í•˜ì‹­ì‹œì˜¤. 파괴/제거 ë„구를 ì´ìš©í•˜ì—¬ 개별 트랙 ë° ìž¥ì• ë¬¼ì„ ì œê±°í•©ë‹ˆë‹¤. [Ctrl] 키와 ë™ì‹œì— 사용한다면 추가 ê¸°ëŠ¥ì„ ì‚¬ìš©í•  수 있습니다. 실행 취소 [z]는 건설 ë¹„ìš©ì„ í™˜ë¶ˆí•˜ì§€ 않습니다.}

전기 선로: 게임 ë·°ì—서 ë‘ ìž¥ì†Œë¥¼ 있는 전기 선로, 다리 í„°ë„ì— ì „ê¸°ë¥¼ 통하게 하여 전기로 ìš´ì˜ë˜ëŠ” ì°¨ëŸ‰ë“¤ì„ ì´ìš©í•  수 있게 í•´ì¤ë‹ˆë‹¤.
íŠ¸ëž™ì— ì „ê¸° 통하게 하기: ë„구를 í´ë¦­í•˜ê±°ë‚˜ [e] (커서가 전기 선로 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨) 키를 눌러 ì„ íƒí•œ 다ìŒ. 게임 ë·°ì—서 ì „ë ¥ì´ ì‹œìž‘ ë  ë¶€ë¶„ì„ í´ë¦­í•˜ê³  (게임 ë·°ì— ì „ê¸° 선로 ì•„ì´ì½˜ì„ 위치시킴), 마지막으로 ì„ ë¡œì˜ ë‘ ë²ˆì§¸ ì ì„ í´ë¦­í•˜ì—¬ 시작 ì ê¹Œì§€ 전기를 공급합니다.
{íŒ: 파괴/제거 ë„구를 ì´ìš©í•˜ì—¬ ì „ë ¥ì´ í르지 않는 트랙으로 ë˜ëŒë¦½ë‹ˆë‹¤.}

트랙 제거: ì°¨ëŸ‰ì´ ì—†ëŠ” 경우 게임 ë·°ì˜ ë‘ ì§€ì  ì‚¬ì´ì˜ 트랙과 전기 선로를 제거하는 ë„구 (정거장, 정류장, 신호등, í„°ë„ ë° ë‹¤ë¦¬ë„ í•¨ê»˜ 제거ë¨). ì´ ë„구를 ì‚¬ìš©í•˜ì—¬ë„ ê±´ì„¤ 비용 ì´ ì§€ì¶œë©ë‹ˆë‹¤.
트랙 제거하기: ë„구를 누른 ë’¤ (커서가 ì ìƒ‰ Xìž ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨); 제거ë˜ê¸¸ ì›í•˜ëŠ” íŠ¸ëž™ì„ í´ë¦­í•˜ê³  (게임 ë·°ì—서 ì ìƒ‰ Xìžë¡œ í‘œì‹œëœ ì‚­ì œ í¬ì¸íŠ¸ë¥¼ ì„ íƒí•©ë‹ˆë‹¤.); 마지막으로 ì—°ê²°ëœ íŠ¸ëž™ì˜ ë‘ ë²ˆì§¸ ì§€ì ì„ í´ë¦­í•˜ì—¬ 첫 ì§€ì ê¹Œì§€ì˜ íŠ¸ëž™ì„ ì‚­ì œí•©ë‹ˆë‹¤.
{íŒ: 플레ì´ì–´ë“¤ì€ ìžì‹ ì˜ 트랙만 삭제할 수 있ë„ë¡ ìž‘ë™í•©ë‹ˆë‹¤.}

ì² ë„ ì‹ í˜¸ë“±: 게임 ë·°ì•ˆì˜ íŠ¸ëž™ì—서 ì² ë„ ì°¨ëŸ‰ ì‹ í˜¸ë“±ì„ ìƒì„±í•˜ëŠ” ë„구입니다. ì‹ í˜¸ë“±ì€ íŠ¸ëž™ ë° ë‹¤ë¦¬, êµì°¨ì  ê³¼ 정거장 (물품ì´ë‚˜ 승ê°ë“¤ì„ 승,하차 시키는 ê³³)ì—서 ì°¨ëŸ‰ì˜ íë¦„ì„ ì§ì ‘ 통제합니다.
ì¼ë°© 통행 신호등, ì–‘ë°©í–¥ 신호등 ëª¨ë‘ ì„¤ì¹˜ 가능합니다. 트랙ì—서 ì–‘ë°©í–¥ 신호등 만들기: 신호등 ë„구를 í´ë¦­í•œ ë’¤(커서가 신호등 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨); íŠ¸ëž™ì„ í´ë¦­í•©ë‹ˆë‹¤. ì¼ë°© 통행 신호등 만들기: 신호등 커서로 ê°™ì€ ì§€ì ì„ 다시 í´ë¦­í•˜ë©´ ì¼ë°© 통행 ì‹ í˜¸ë“±ì´ ë˜ì—ˆë‹¤ê°€ ë˜ í´ë¦­í•˜ë©´ ì–‘ë°©í–¥ 신호등으로 ëŒì•„오는 순환구조 입니다.
중요사항: ì°¨ëŸ‰ì´ ëª©ì ì§€ì— ë„달하지 못하게 단방향 신호를 ë³´ë‚´ì§€ 않ë„ë¡ ì£¼ì˜ í•˜ì‹­ì‹œì˜¤. 기본ì ìœ¼ë¡œ ì°¨ëŸ‰ì€ ì˜¤ë¥¸ìª½ìœ¼ë¡œ 주행합니다 (simuconf.tabì—서 변경 가능).
- 신호등: ì°¨ëŸ‰ì€ ë‹¤ë¥¸ ì°¨ëŸ‰ì˜ ì¼ì • ì— í¬í•¨ë˜ì§€ ì•Šì€ ëª©ì ì§€ (정거장 ì´ë‚˜ 중간지ì ) 나 다른 ì‹ í˜¸ë“±ì´ ìžˆëŠ” 트랙까지 향하게 ë©ë‹ˆë‹¤. ì¼ë°© 통행 ëª¨ë“œì¸ ê²½ìš° ì°¨ëŸ‰ì€ ì˜¤ì§ í•œ 방향으로만 주행 가능합니다.
- ì² ë„ í쇄 표시: ì°¨ëŸ‰ì´ ì‹ í˜¸ë¥¼ 무시하지 못하게 합니다 (ì¼ë°© 통행 모드ì—서만 가능합니다).
- ì „ 신호등: íŠ¸ëž™ì´ í–¥í•˜ëŠ” 공간 (ì¼ì • ì—ì„œì˜ ë‹¤ìŒ ëª©ì ì§€ë‚˜ ì—°ì†ëœ 세 신호 사ì´ê¹Œì§€ í¬í•¨)ì— ë‹¤ë¥¸ ì°¨ëŸ‰ì´ ìžˆì§€ì•Šë‹¤ë©´ ì°¨ëŸ‰ì€ ê³„ì†í•´ì„œ 움ì§ì¼ 수 있습니다. ì¼ë°© 통행 모드ì—서는 ì°¨ëŸ‰ì´ í•œ 방향으로만 지나가게 합니다.
- ì„ íƒ ì‹ í˜¸ë“±: 다중 í”Œëž«í¼ ì •ê±°ìž¥ ì—서 빈 플랫í¼ìœ¼ë¡œ 향하ë„ë¡ ì°¨ëŸ‰ì„ ì§€ì‹œ: ì°¨ëŸ‰ì´ ì´ ì‹ í˜¸ë“±ì„ í†µê³¼í•œë‹¤ë©´ ë‹¤ìŒ ëª©ì ì§€ëŠ” 빈 플랫í¼ì´ ëœë‹¤. ì´ê³³ì€ ì¼ì • ì— ì§€ì •ë˜ì–´ 있지 않다. 빈 플랫í¼ì´ 없거나 ë‹¤ìŒ ëª©ì ì§€ì— 대한 명확한 경로가 없다면 ì°¨ëŸ‰ì€ ì‹ í˜¸ë¥¼ 기다린다.
{íŒ: 파괴/제거 ë„구로 ì‹ í˜¸ë“±ì„ ì œê±°í•˜ì‹­ì‹œì˜¤. [Ctrl] 키를 길게 누르면 다리 ìœ„ì˜ ì‹ í˜¸ë“±ì„ ë” ë‚®ì€ íŠ¸ëž™ ì— ë°°ì¹˜í•  수 있습니다.}

노면 ì „ì°¨ 차고: 노면 전차를 구입하거나 관리하기 위해 차고를 짓는 ë„구.
ì°¨ê³ ë“¤ì€ ìœ ì§€ 보수 ë¹„ìš©ì´ ìžˆìœ¼ë©° 게임 ë·°ì—서 트랙 ë ë¶€ë¶„ì— ê±´ì„¤ë©ë‹ˆë‹¤.
노면 ì „ì°¨ 차고 만들기: ë„구를 í´ë¦­í•˜ê³  (커서가 차고 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), íŠ¸ëž™ì˜ ëì„ í´ë¦­í•œë‹¤.
{íŒ: 전기가 í르는 트랙ì´ë¼ë©´ ì°¨ê³ ë“¤ì€ ì „ê¸°ë¡œ 운용가능한 차량들만 ë³´ì—¬ì¤ë‹ˆë‹¤. 파괴/제거 ë„구로 차고를 제거할 수 있습니다.}

ì² ë„ ì •ë¥˜ìž¥: ì² ë„ ì°¨ëŸ‰ì´ ë¬¼í’ˆ, ìŠ¹ê° ê·¸ë¦¬ê³  ìš°íŽ¸ë¬¼ì„ ìŠ¹, 하차 시키는 ë° ì‚¬ìš©í•˜ëŠ” ì—­ 플랫í¼ì„ 건설하는 ë„구.
ì—­ 플랫í¼ì´ 정류장 ì— ì¸ì ‘하지 않다면 새로운 ì •ë¥˜ìž¥ì„ ë§Œë“­ë‹ˆë‹¤.
ì² ë„ ì •ë¥˜ìž¥ì€ ìœ ì§€ 보수 ë¹„ìš©ì´ ì†Œìš”ë˜ë©° íŠ¸ëž™ì— ê±´ì„¤ë©ë‹ˆë‹¤ (하지만 굴곡지거나 êµì°¨ë˜ëŠ” 트랙ì—는 건설ë˜ì§€ 않습니다).
ì² ë„ ì •ë¥˜ìž¥ì—는 물품, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì„ ìˆ˜ìš©í•  수 있는 êµ¬ì—­ì´ ìžˆìŠµë‹ˆë‹¤. ì—­ 플랫í¼ë§ˆë‹¤ 승ê°ê³¼ ìš°íŽ¸ì„ ìˆ˜ìš©í•  수 있는 ìš©ëŸ‰ì´ ë‹¤ë¦…ë‹ˆë‹¤. ì¼ë¶€ ë„구 ì˜µì…˜ì˜ ëª¨ì„œë¦¬ì—있는 ì•„ì´ì½˜ (ì—­ ëª©ë¡ ê³¼ 정류장 ì •ë³´ì— ì‚¬ìš©ë¨) ì€ ì—­ 플랫í¼ì´ ì •ë¥˜ìž¥ì„ ë‹¤ë£° 수 있는 í•­ëª©ì„ ë³´ì—¬ì¤ë‹ˆë‹¤.
ì—­ í”Œëž«í¼ ë§Œë“¤ê¸°: ì„ íƒí•œ ë„구를 í´ë¦­í•œ ë’¤ (커서가 í”Œëž«í¼ ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨) íŠ¸ëž™ì„ í´ë¦­í•©ë‹ˆë‹¤.
{íŒ: 파괴/제거 ë„구로 ì² ë„ ì •ë¥˜ìž¥ì„ ì œê±° í•  수 있습니다. ë” ê¸¸ê³  ë” ë§Žì€ ì°¨ëŸ‰ì„ ìˆ˜ìš©í•˜ê³  ì ìž¬ êµ¬ì—­ì˜ ìš©ëŸ‰ì„ ëŠ˜ë¦¬ê¸° 위해서 ì—­ 플랫í¼ì„ 확장하거나 다중 í”Œëž«í¼ ì •ë¥˜ìž¥ì„ ê±´ì„¤í•˜ì‹­ì‹œì˜¤ (ì¸ì ‘ íŠ¸ëž™ì— ë”ë§Žì€ í”Œëž«í¼ì„ 건설함으로ì¨). [v]를 눌러 물품과 승ê°ì„ 수용하는 êµ¬ì—­ì„ ê²Œìž„ ë·°ì—서 ë³´ì´ê±°ë‚˜/ 숨길 수 있습니다. [Ctrl] 키를 누른 채로 아래 트랙 위로 다리를 ì§€ì„ ìˆ˜ 있습니다.}

주차장: (pak128 버전ì—서만 가능) 정류장 ì„ í™•ìž¥í•˜ì—¬ 물품 ë° ìŠ¹ê°ì˜ 수용 ë° ì ìž¬ 구역, 유지 보수 ë¹„ìš©ì„ ë†’ì´ëŠ” ë° ì‚¬ìš©í•˜ëŠ” ë„구입니다.
확장시키기: 확장 ë„구를 í´ë¦­í•œ ë’¤ (커서가 확장 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨), 게임뷰ì—서 정류장 ì˜†ì— ì›í•˜ëŠ” ë„로를 í´ë¦­ 하십시오. ì´ í™•ìž¥êµ¬ì—­ì€ ì´ì œ ì •ë¥˜ìž¥ì˜ ì¼ë¶€ë¶„ì´ ë©ë‹ˆë‹¤.
{íŒ: 파괴/제거 ë„구로 í™•ìž¥êµ¬ì—­ì„ ì œê±°í•  수 있습니다.}

?ë„로 정거장: 노면 전차나 ë„로 ì°¨ëŸ‰ì´ ë¬¼í’ˆ, 우편, 승ê°ë“¤ì„ 승,하차 시킬 수 있는 ê³µê°„ì„ ë§Œë“œëŠ” ë„구.
기존 정거장 ì— ì¸ì ‘하여 건설하지 ì•Šì„ ê²½ìš° ë„로 ì •ê±°ìž¥ì€ ìƒˆë¡œìš´ ì •ê±°ìž¥ì„ ë§Œë“­ë‹ˆë‹¤. ë„로 정거장 ë„로 를 기반으로 지어야 하며 물품, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì— ëŒ€í•œ 집수 공간과 유지 관리 ë¹„ìš©ì´ ìžˆìŠµë‹ˆë‹¤. ì¼ë¶€ ë„구 옵션 ëª¨ì„œë¦¬ì— ìœ„ì¹˜í•œ ì•„ì´ì½˜ (정거장 목ë¡ê³¼ ì •ë³´ì— ì‚¬ìš©ë¨) ì€ ë„로 정거장ì—서 다룰 수 있는 í•­ëª©ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ê° ë„로 정거장마다 물품, ìŠ¹ê° ë° ìš°íŽ¸ë¬¼ì„ ìˆ˜ìš©í•  수 있는 ìš©ëŸ‰ì´ ë‹¤ë¦…ë‹ˆë‹¤.
ë„로 정거장 건설하기: ì„ íƒí•œ ë„구를 í´ë¦­í•œ ë’¤ (커서가 ë„로 정거장 ì•„ì´ì½˜ìœ¼ë¡œ 변경ë¨) 게임 ë·° ì† ë„로 중 ì›í•˜ëŠ” ì§€ì—­ì„ í´ë¦­í•˜ì‹­ì‹œì˜¤.
{íŒ: 파괴/제거 ë„구로 ë„로 ì •ê±°ìž¥ì„ ì œê±°í•  수 있습니다. [Ctrl] 키를 눌러 아래 ë„로 위로 다리를 ì§€ì„ ìˆ˜ 있습니다.}

simutrans-124.3/simutrans/text/ko/underground.txt000066400000000000000000000041041474050137200222710ustar00rootroot00000000000000지하 건설 ë„ì›€ë§ Help

지하 건설

Simutransì—는 ë‘ ê°€ì§€ 지하시ì ì´ 있습니다, ë‘ ê°€ì§€ ëª¨ë‘ ë””ìŠ¤í”Œë ˆì´ ì„¤ì • ì°½ì—서 접근하거나 단축키를 사용하여 접근할 수 있습니다.

지하 시ì : [U] 키를 눌러, 모든 지하 ë ˆë²¨ì´ ê³µê°œë˜ê³  모든 ì§€ìƒ ìœ„ì˜ ë¬¼ì²´ê°€ 숨겨집니다. 지표 그리드는 기본ì ìœ¼ë¡œ 표시ë©ë‹ˆë‹¤, 하지만 ì´ ê·¸ë¦¬ë“œ íŒ¨í„´ì„ ì‚¬ìš©í•˜ì—¬ ì›í•˜ëŠ” ìœ„ì¹˜ì— ê°ì²´ë¥¼ 배치하는 ê²ƒì€ ë§¤ìš° 어렵기 ë•Œë¬¸ì— ë‹¤ìŒ ì§€ë„ ì‹œì ì´ 지하 ê±´ì„¤ì— ê¶Œìž¥ë©ë‹ˆë‹¤.

층 시ì : [Ctrl+U] 를 통해 Simutransì—서 ë‹¨ì¼ ë†’ì´ ë ˆë²¨ë¡œ 지하가 표시ë©ë‹ˆë‹¤. ì´ ì‹œì ì€ ì„ íƒí•œ 층 ìœ„ì— ìžˆëŠ” 지하, í‘œë©´ì˜ ëª¨ë“  ê°ì²´ë¥¼ 숨ê¹ë‹ˆë‹¤. 현재 ì‹œì  ë ˆë²¨ì€ ë””ìŠ¤í”Œë ˆì´ ì„¤ì •ì—서 조정하거나 paksetì˜ íŠ¹ì • 키 를 통해조정할 수 있습니다. í™œì„±í™”ëœ ì¸µì˜ ê·¸ë¦¬ë“œ íŒ¨í„´ì´ ë³´ì—¬ì§‘ë‹ˆë‹¤. 마우스 í¬ì¸í„°ëŠ” 현재 레벨ì—서만 움ì§ì´ë¯€ë¡œ 건설 ìž‘ì—…ì— ë” ìš©ì´í•©ë‹ˆë‹¤.

ì¼ë°˜ì ìœ¼ë¡œ, 지하 ë…¸ì„ ì€ í„°ë„ ê±´ì¶• ë„구를 사용하여 건설ë©ë‹ˆë‹¤. ì§€í•˜ì— ì§“ê¸° 위해서는 í„°ë„ì´ë‚˜ í„°ë„ ìž…êµ¬ (ê²½ì‚¬ë©´ì„ í„°ë„ ë„구로 Ctrl + í´ë¦­) ê°€ 먼저 만들어져야 합니다.

ì§€í•˜ì— ë˜ ë‹¤ë¥¸ ì¸µì„ ë§Œë“¤ë ¤ë©´, í’ê²½ ë„구 ë©”ë‰´ì˜ ì¸ê³µ 경사 만들기 ë„구를 사용합니다. ì´ ë„구로 ë„로/íŠ¸ëž™ì˜ ëë§Œ í´ë¦­í•˜ë©´ ë©ë‹ˆë‹¤.

노면전차 íŠ¸ëž™ì€ ì¼ë°˜ 노면전차 ë„구 를 사용하여 ì§€í•˜ì— ì„¤ì¹˜í•  수 있습니다.

ì˜¤ì§ ì •ê±°ìž¥/ì—­ ë§Œì´ ì„œë¡œì˜ ìœ„ì— ë§Œë“¤ 수 있습니다. ì—­ì€ ì§€í•˜ì— ì§€ì„ ìˆ˜ 없습니다.

참고: ë” ì§€í•˜ë¥¼ 만들 수 없다면 ì§€ìƒì˜ ìž¥ì• ë¬¼ì„ í™•ì¸í•˜ì‹­ì‹œì˜¤.

simutrans-124.3/simutrans/text/ko/window.txt000066400000000000000000000234621474050137200212540ustar00rootroot00000000000000게임 ì¸í„°íŽ˜ì´ìФ 사용법

게임 ì¸í„°íŽ˜ì´ìФ

Simutrans는 현재 ê²Œìž„ì— ëŒ€í•œ ì •ë³´, ë„구 모ìŒ(toolbars) ë° ê²Œìž„ ì»¨íŠ¸ë¡¤ì— ëŒ€í•œ 접근과 게임 월드 ë‚´ 시야를 제공하는 게임 ì¸í„°íŽ˜ì´ìŠ¤ë¥¼ 통해 í”Œë ˆì´ ë©ë‹ˆë‹¤. Simutrans는 마우스 와 키보드 를 통해 컨트롤 í•  수 있습니다. 키보드 êµ¬ì„±ì€ ë‹¨ì¶•í‚¤ ì„¹ì…˜ì˜ ë„ì›€ë§ ë©”ë‰´ì—서 í™•ì¸ ê°€ëŠ¥í•˜ë©°, [F1] 키를 누르거나 할당ë˜ì§€ ì•Šì€ í‚¤ë¥¼ 누를 때마다 í™•ì¸ ê°€ëŠ¥í•©ë‹ˆë‹¤.
중요사항: í‚¤ë“¤ì€ ëŒ€ì†Œë¬¸ìžë¥¼ 구분합니다.

게임 창

게임 ì›”ë“œì˜ ì¼ë¶€ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤. 마우스 휠ì´ë‚˜ [PgUp]/[PgDown] 키, 주 ë„구 모ìŒ(toolbar)ì— ìžˆëŠ” ë‘ ê°€ì§€ ì „ìš© ì•„ì´ì½˜ì„ 통해 확대와 축소를 í•  수 있습니다. ì§€ë„를 스í¬ë¡¤í•˜ëŠ” 방법:
? 마우스 오른쪽 ë²„íŠ¼ì„ ëˆ„ë¥¸ ìƒíƒœì—서 ì›í•˜ëŠ” 위치를 향해 ì§€ë„를 스í¬ë¡¤í•œë‹¤. ì§€ë„ê°€ ë§ˆìš°ìŠ¤ì˜ ì›€ì§ìž„ì— ë”°ë¼ ìŠ¤í¬ë¡¤ë˜ëŠ” ê²ƒì´ ê¸°ë³¸ 설정입니다. ë””ìŠ¤í”Œë ˆì´ ì„¤ì • ì°½ì—서 변경할 수 있습니다.
? ìˆ«ìž í‚¤íŒ¨ë“œë¥¼ 사용한다.
? ì§€ë„ ì°½ì—서 ì ì ˆí•œ ì§€ì ì„ ì„ íƒí•˜ì—¬ ì›í•˜ëŠ” ì§€ì ìœ¼ë¡œ ì´ë™í•œë‹¤.
? ì í”„ 다ì´ì•Œë¡œê·¸ ([J] 키)를 사용하여 특정 좌표로 ì´ë™í•œë‹¤.

마ì„, 공장, ì—­, 차량 ë° ìˆ˜ì†¡ì„ ê³¼ ê°™ì€ ì—¬ëŸ¬ ê°ì²´ì˜ ì´ë¦„ì„ íŽ¸ì§‘ í•  수 있습니다. 편집하려면 조사 ë„구 (아래 참조)로 ì—° 다ì´ì•Œë¡œê·¸ì˜ ì´ë¦„ 필드ì—서 마우스로 í´ë¦­í•˜ì‹­ì‹œì˜¤. 수정 ì‚¬í•­ì€ ì¦‰ì‹œ ì ìš©ë©ë‹ˆë‹¤. [Return]ì„ ëˆ„ë¥´ë©´ 필드ì—서 나갑니다.

타ì´í‹€ ë°”

타ì´í‹€ ë°”ì˜ ì™¼ìª½ ë¶€ë¶„ì€ ì‹œë®¤íŠ¸ëžœìŠ¤ì˜ ë²„ì „ ë° ì—…ë°ì´íЏ 날짜를 표시합니다. 오른쪽 부분ì—서는 게임 ì¸í„°íŽ˜ì´ìŠ¤ë¥¼ 최소화, 최대화하거나 Simutrans를 종료할 수 있습니다.

게임 ì°½ ìƒë‹¨ì—는 Simutrans ê²Œìž„ì„ í•  때 게임 툴바 ë° ê²Œìž„ ì»¨íŠ¸ë¡¤ì— ì ‘ê·¼í•˜ëŠ” ë° ì‚¬ìš©ë˜ëŠ” ì•„ì´ì½˜ë“¤ (주 ë„구 모ìŒ(toolbar))ì´ ìžˆìŠµë‹ˆë‹¤. 여러 메뉴들로 그룹화 ë˜ì–´ìžˆëŠ” ì•„ì´ì½˜ë“¤ (í´ë¦­í•´ì„œ 사용):

주 메뉴

옵션: 플로피 ë””ìŠ¤í¬ ì•„ì´ì½˜ì€ 새로운 ê²Œìž„ì„ ë¡œë“œ, 저장 ë˜ëŠ” 시작할 수있는 다ì´ì•Œë¡œê·¸ë¥¼ 엽니다.

ì§€ë„: ê·¸ ìžì²´ê°€ 목ì ì¸ 오버뷰 월드 ì§€ë„는 플레ì´ì–´ì˜ 차량 움ì§ìž„ì„ ë³´ì—¬ì£¼ê³  몇몇 통계 치를 ë³¼ 수 있게 í•´ì¤ë‹ˆë‹¤. ì§€ë„ì—서 한 ì§€ì ì„ ì„ íƒí•˜ë©´ 게임 ì°½ì—서 해당 ì´ë¯¸ì§€ 섹션으로 ì´ë™í•©ë‹ˆë‹¤.

조사 ë„구: ë‹ë³´ê¸° ì•„ì´ì½˜ì€ 검색 ê¸°ëŠ¥ì„ ìƒì§•합니다. 활성화 ëœë‹¤ë©´, 커서가 ë‹ë³´ê¸° ëª¨ì–‘ì´ ë©ë‹ˆë‹¤. 건물, 차량 ë“±ì˜ ê°ì²´ë¥¼ ì„ íƒí•˜ë©´ ê·¸ ìœ„ì— ì •ë³´ ì°½ì´ ë‚˜íƒ€ë‚©ë‹ˆë‹¤. 특히 제거 ë„구 로 작업 한 경우, í•­ìƒ ë‹ë³´ê¸°ë¡œ ëŒì•„가는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤. ê°ì²´ì˜ 정보를 조사하는 대신 실수로 ê°ì²´ë¥¼ 제거하지 마십시오.

ì¡°ê²½ ë„구: 경사로 ì•„ì´ì½˜ì€ ê° íƒ€ì¼ì˜ 기울기를 변경하여 ì§€í˜•ì„ ë³€ê²½í•  수 있는 ë„구 모ìŒ(toolbar)ì„ ì—½ë‹ˆë‹¤.

건설 ë„구: ê° ìš´ì†¡ ìœ í˜•ì˜ ë„구 모ìŒ(toolbars)를 엽니다.
?ì² ë„ ë„구
?ëª¨ë…¸ë ˆì¼ ë„구
?노면전차 ë„구
?ë„로 ë„구
?ì„ ë°• ë„구
?비행기 ë„구

참고: ì¼ë¶€ 펙셋ì—는 협괘(광궤) ì² ë„ ë„구 와 ê°™ì€ ì¶”ê°€ 건설 ë„구가 í¬í•¨ë  수 있습니다.
ê° ë„구 모ìŒ(toolbars)ì—는 차고 ì•„ì´ì½˜ì´ 있습니다. 차고가 지어진다면, ì°¨ëŸ‰ì— ì ‘ê·¼í•˜ê¸° 위해 차고 ì°½ 으로 들어갈 수 있습니다.

특수 건설 ë„구: red-drop-in-yellow-circle ì•„ì´ì½˜ (pak128ì˜ í¬ë ˆì¸ ì•„ì´ì½˜)ì„ í´ë¦­í•˜ë©´ 열리는 ë„구 ëª¨ìŒ (toolbar)ì—는 êµí†µ ë„¤íŠ¸ì›Œí¬ êµ¬ì¶•ì„ ë³´ì™„í•˜ëŠ” 다양한 구성 ë„구가 í¬í•¨ë˜ì–´ 있습니다.

파괴/제거 ë„구: ì ìƒ‰ X ì•„ì´ì½˜ (pak128ì˜ ë¶ˆë„ì € ì•„ì´ì½˜)ì€ ì§€ë„ì—서 다양한 ê°ì²´ë¥¼ 제거하는 ë° ì‚¬ìš©ë©ë‹ˆë‹¤.

관리 메뉴

노선 관리: 수송 ë…¸ì„ ì„ ì—¬ê¸° (ë„¤íŠ¸ì›Œí¬ ì•„ì´ì½˜)ì—서 설정하거나, 변경하거나 삭제할 수 ìžˆì„ ë¿ë§Œ ì•„ë‹ˆë¼ ê·¸ 정보를 ë³¼ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.

목ë¡: ëª©ë¡ ì•„ì´ì½˜ì—서 ì´ì–´ì§€ëŠ” 7ê°œì˜ í•˜ìœ„ 목ë¡:
?ì—­ 목ë¡
?차량 목ë¡
?ë„시 목ë¡
?ìƒí’ˆ 목ë¡
?공장 목ë¡
?관광 명소 목ë¡
?í‘œì‹œíŒ ëª©ë¡

통신 센터: 사서함 ì•„ì´ì½˜ì„ í´ë¦­í•˜ë©´ ê²Œìž„ì„ ì‹œìž‘í•œ ì´í›„, í˜¹ì€ ë§ˆì§€ë§‰ìœ¼ë¡œ 로드한 ì´í›„ ìƒì„±ëœ 모든 메세지가 나열ë©ë‹ˆë‹¤.

재정: ì´ ëˆ ì•„ì´ì½˜ì€ 현재 재무 ìƒí™©ì— 대해 알만한 가치가 있는 모든 ê²ƒì„ ë³´ì—¬ì£¼ëŠ” ì°½ì„ ì—´ì–´ì¤ë‹ˆë‹¤.

다른 메뉴들

스í¬ë¦°ìƒ·: ì¹´ë©”ë¼ ì•„ì´ì½˜ ë²„íŠ¼ì„ ëˆ„ë¥¸ë‹¤ë©´, 현재 게임 ì°½ì˜ ìŠ¤ëƒ… 샷 (ë„구 모ìŒ(toolbars) í¬í•¨, 타ì´í‹€ ë°” 제외)ì€ simutrans/screenshot/ í´ë”ì— .png ì´ë¯¸ì§€ë¡œ 저장ë©ë‹ˆë‹¤. [c] 키를 사용하여 ì´ë¯¸ì§€ë¥¼ 캡처할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.

ì¼ì‹œì •ì§€: ë‹¹ì‹ ì´ ìš´ì†¡ íšŒì‚¬ì˜ í˜¼ìž¡ê³¼ 번잡ì—서 벗어나고 ì‹¶ë‹¤ë©´ì´ ì»¤í”¼ 머그 ì•„ì´ì½˜ìœ¼ë¡œ ì°¨ ë˜ëŠ” 커피 í•œìž”ì„ ì£¼ë¬¸í•˜ì‹­ì‹œì˜¤. ì´ ì„œë¹„ìŠ¤ëŠ” 물론 Simutransì—서 무료입니다!
ì´ í‚¤ [p] 는 게임 ì¼ì‹œ 중지 / í•´ì œì—ë„ ì‚¬ìš©í•  수 있습니다.

빨리ê°ê¸°: Simutransì˜ ì‹œê°„ì´ ëŠë¦¬ê²Œ ëŠê»´ì§„다면 ì´ >> ì•„ì´ì½˜ì„ 눌러 ê°€ì†ì‹œí‚¬ 수 있습니다. 빨리ê°ê¸°ëŠ” [W] 키를 사용하여 ì„ íƒ / 취소 í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.
경고: 빨리ê°ê¸° 모드ì—ì„  ê²Œìž„ì´ ì›í™œí•˜ê²Œ 실행ë˜ì§€ ì•Šì„ ìˆ˜ 있습니다. ë””ìŠ¤í”Œë ˆì´ ì„¤ì • ì°½ì˜ í•˜ë‹¨ì— ìžˆëŠ” ë””ìŠ¤í”Œë ˆì´ ì„±ëŠ¥ ì •ë³´ ì„¹ì…˜ì€ ì»´í“¨í„°ê°€ 변경 ì‚¬í•­ì„ ì²˜ë¦¬ í•  수 ??있는지 여부를 나타냅니다.

ë„움ë§: ? ì•„ì´ì½˜ì€ [F1] 키와 함께 ë„ì›€ë§ ìƒ‰ì¸ì„ 엽니다.

참고: í”Œë ˆì´ í•˜ëŠ” paksetì— ë”°ë¼ ì£¼ ë„구 모ìŒ(toolbar)ì— ì•„ì´ì½˜ì´ ë” ìžˆì„ ìˆ˜ 있습니다: 확대/축소, ê²©ìž ë³´ì´ê¸°, ì§€ë„ íšŒì „, 등등

ìƒíƒœ ë°”

게임 월드 ì°½ í•˜ë‹¨ì— ìžˆëŠ” ìƒíƒœ ë°”ì—는 ê²Œìž„ì´ ì§„í–‰í•¨ì— ë”°ë¼ ì§€ì†ì ìœ¼ë¡œ ì—…ë°ì´íЏ ë˜ëŠ” ì •ë³´ê°€ í¬í•¨ë˜ì–´ 있습니다. 좌측ì—서 우측으로 ì •ë³´ê°€ 제공ë˜ëŠ” ìƒíƒœ ë°”:
?날짜와 시간: Simutransì—서 1 ë…„ì€ ì›”, ì¼ ë° ì‹œê°„ìœ¼ë¡œ 나뉩니다. 날짜는 '타임 ë¼ì¸'ì´ í™œì„±í™” ë  ë•Œ 차량 ë° ê±´ë¬¼ì´ ì‚¬ìš© 가능한지 제어합니다 (아래 참조). ë‚ ì§œ ì•žì— ê¸°ìƒ ê³„ì ˆ ì•„ì´ì½˜ì´ 표시ë©ë‹ˆë‹¤. ì¼ë¶€ 기후 설정 ì˜ ê²½ìš° ì‹œì¦Œì€ ê³„ì ˆì— ë”°ë¼ ë³€ê²½ë  ìˆ˜ 있습니다.
?플레ì´ì–´: 현재 플레ì´ì–´ì˜ ì´ë¦„ì´ í”Œë ˆì´ì–´ì˜ 색ìƒìœ¼ë¡œ 표시ë©ë‹ˆë‹¤.
?잔액: 현재 플레ì´ì–´ì˜ ìž”ì•¡ì´ í‘œì‹œë˜ê³  ì§€ì†ì ìœ¼ë¡œ ì—…ë°ì´íЏë©ë‹ˆë‹¤. 건설 ë° ê¸°íƒ€ 비용 (차량 구매, 운송 ì¸í”„ë¼ ìœ ì§€ ë° ì°¨ëŸ‰ ìš´ì˜ ë¹„ìš©)ì„ ê³ ë ¤í•©ë‹ˆë‹¤.
?위치 좌표: 괄호 ì•ˆì€ ì»¤ì„œê°€ 현재 위치한 타ì¼ì˜ x ë° y 좌표와 ë†’ì´ ë¡œ 표시ë©ë‹ˆë‹¤. 좌표 (0,0) ì€ ì§€ë„ì˜ ì™¼ìª½ ìƒë‹¨ ëª¨ì„œë¦¬ì— ìžˆê³  ë†’ì´ 0ì€ í•´ìˆ˜ë©´ìž…ë‹ˆë‹¤. (ë§µì˜ ìˆ˜ìœ„ ì„¤ì •ì— ë”°ë¼ ë‹¤ë¦„)
?게임 ì†ë„: (T = 1.00)ì€ í˜„ìž¬ 게임 ì†ë„를 나타냅니다. [,]/[.] 키를 사용하여 ì•½ê°„ì˜ ì‹œê°„ 단위로 ê°€ì† / ê°ì†ì‹œí‚¬ 수 있습니다. ë””ìŠ¤í”Œë ˆì´ ì„¤ì • ì°½ì˜ í•˜ë‹¨ì— ìžˆëŠ” ë””ìŠ¤í”Œë ˆì´ ì„±ëŠ¥ ì •ë³´ ì„¹ì…˜ì€ ì»´í“¨í„°ê°€ 변경 ì‚¬í•­ì„ ì²˜ë¦¬ í•  수 ??있는지 여부를 나타냅니다. 빨리ê°ê¸° 모드ì—ì„  추가 ì•„ì´ì½˜ >>ì´ í‘œì‹œë©ë‹ˆë‹¤.
?연대 설정: 현재 게임ì—서 타임 ë¼ì¸ ì´ ì„ íƒë˜ì—ˆëŠ”ì§€ 달력 ì•„ì´ì½˜ìœ¼ë¡œ 나타냅니다.

스í¬ë¡¤ ë°”

ê²½ìš°ì— ë”°ë¼, 메시지가 게임 월드 ì°½ 하단, ìƒíƒœ ë°” ìœ„ì— í‘œì‹œë©ë‹ˆë‹¤. 표시 í•  메시지는 통신 센터 옵션 ì—서 ì •ì˜ í•  수 있습니다.
íŒ: 메시지를 í´ë¦­í•˜ë©´ 게임 시ì ì„ 관련 위치로 ì´ë™ 시킵니다.

simutrans-124.3/simutrans/text/lt.tab000066400000000000000000001302231474050137200176740ustar00rootroot00000000000000§Lithuanian PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: lt Lithuanian # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable iÅ¡jungtas cl_btn_filter_enable įjungtas cl_btn_filter_settings Nustatymai cl_btn_sort_asc didÄ—janÄiai cl_btn_sort_desc mažėjanÄiai cl_btn_sort_id numerį (ID) cl_btn_sort_income Pajamas cl_btn_sort_name VardÄ… cl_btn_sort_type Rūšį clf_btn_alle visi clf_btn_invers atv. clf_btn_keine joks gl_btn_sort_bonus pagal bonusÄ… gl_btn_sort_name pagal vardÄ… gl_btn_sort_revenue pagal pajamas gl_btn_unsort nesurikiuota hl_btn_filter_disable iÅ¡jungti hl_btn_filter_enable įjungti hl_btn_filter_settings Nustatymai hl_btn_sort_asc didÄ—janÄiai hl_btn_sort_desc mažėjanÄiai hl_btn_sort_name PavadinimÄ… hl_btn_sort_type Rūšį hl_btn_sort_waiting Laukia hlf_btn_alle visi hlf_btn_invers atvirkÅ¡Äiai hlf_btn_keine joks Networks Tinklai Queueing Laukimo eilÄ— Road toll Kelio mokestis Transfers Juda per #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktinis klimatas desert dykumų klimatas mediterran viduržemio j. klimatas rocky kalnų klimatas temperate vidutinis klimatas tropic tropikai #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Negalima Äia statyti depo. Cannot built this station/building\nin underground mode here. Pastatas negali bÅ«ti\npastatytas po žeme.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Negalima sukurtu bet kam linijos!\nPasirinkite tr. priemonÄ—s tipÄ…\nvirÅ¡utinÄ—se lango auselÄ—se. Cannot create socket Negalima sukurti lizdo Convoi handles exhausted! Pasiektas maksimalus transporto priemonių skaiÄius. Convoy already deleted! Konvojus jau iÅ¡trintas! Das Feld gehoert\neinem anderen Spieler\n Å itas žemÄ—s lopinÄ—lis\nvaldomas\nkito žaidÄ—jo!\n Der Besitzer erlaubt das Entfernen nicht Laukelio savininkas atsisako\nduoti leidimÄ…\nsunaikinti Å¡itÄ… objektÄ…!\n Diese Zusammenstellung kann nicht fahren!\n Å ita kombinacija\nnevažiuoja!\n Flugzeughalt muss auf\nRunway liegen!\n LÄ—ktuvo sustojimas\nturi bÅ«ti ant orouosto dangos. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n JÅ«s negalite Äia statyti\n\naerousto pastatų.\n Hier kann kein\nSignal aufge-\nstellt werden!\n JÅ«s Äia negalite\nstatyti signalo.\n In order to lock the game, you have to protect the public player by password! NorÄ—dami apriboti kitų žaidÄ—jų prieigÄ… prie žaidimo, uždÄ—kite vieÅ¡am (valstybÄ—s, public) žaidÄ—jui slaptažodį. Lost connection\nto server! Prarastas ryÅ¡ys\nsu serveriu! Lost synchronisation\nwith server. Prarasta sinchronizacija\nsu serveriu! Maglevhalt muss auf\nMaglevschiene liegen!\n M. levitacijos traukinio stotelÄ— privalo bÅ«ti ant atitinkamų bÄ—gių! Monorailhalt muss auf\nMonorail liegen!\n VienbÄ—gio stotelÄ—s privalo\nbÅ«ti ant atitinkamų bÄ—gių. Monorails are not available yet! VienbÄ—giai dar neatsirado. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Siauruko sustojimas tik ant atitinkamų bÄ—gių No through station here! Neįmanoma Äia pastatyti stoties ji turi bÅ«ti ant kelio galo arba sekcijose be sankryžos. Not enough money! TrÅ«ksta pinigų statyboms! On narrowgauge track only!\n Tik ant siauruko bÄ—gių! Only public player can lock games! Tik vieÅ¡as (valstybÄ—s, public) žaidÄ—jas gali užrakinti žaidimÄ…! Out of funds TrÅ«ksta pinigų! Post muss neben\nHaltestelle\nliegen!\n StotelÄ—s iÅ¡plÄ—timas\n(sandÄ—lis, paÅ¡tas)\nprivalo bÅ«ti Å¡alia\negzistuojanÄios stotelÄ—s.\n Protocoll error (expecting game) Protokolo klaida (tikimasi žaidimo) Schiffhalt muss im\nWasser liegen!\n Laivų sustojimas\n gali bÅ«ti tik ant vandens\nÅ¡alia prieplaukos!\n Server busy Serveris užsiÄ—mÄ™s Terraforming not possible\nhere in underground view Neįmanoma po žeme tvarkyti aplinkos. Upgrade must have\na higher level Atnaujinimas turi bÅ«ti\naukÅ¡tesnio lygio Vehicle %s cannot choose because stop too short! Transportas %s negali sustoti stotyje, kadangi stoties platforma per trumpa! Zughalt muss auf\nSchiene liegen!\n Geležinkelio stotys\n turi bÅ«ti padÄ—tos ant bÄ—gių.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Klaviat?ros pagalba\n

Klaviat?ros pagalba

\n

\nKlaviat?ros pagalba rodo ?vairi? mygtuk? funkcijas.\n

\n

\nKlaviat?ros pagalba atsirado tada kai paspaudžiana neegzistuojanti klaviš? kombinacija General Help.\n

\n

\nmygtukai skiria didžiasias ir mažąsias raides (naudoti [Shift] pakeisti raides(ne caps lock)).\n

\n

\nFunkcionuojantys mygtukai:\n

\n

\n[Rodykl?s]: Slenka žaidimo vaizdą.
\n[Backspace]: uždaro visus langus, ?rankines ir pagalbos tekstus.
\n[Delete], arba [Escape]: uždaro aktyv? langą, ?rankinę ar pagalbos tekstus žaidime.
\n[Enter], arba [Return]: patvirtina veiksmus.
\n[Page-Up], arba [>]: artina vaizdÄ….
\n[Page-Down], or [ less than symbol]: tolina vaizdÄ….\n[F1]: atveria Simutrans pagalbÄ….

\n

\n[1]: slenka vaizdÄ….
\n[2]: slenka vaizdÄ….
\n[3]: slenka vaizdÄ….
\n[4]: slenka vaizdÄ….
\n[6]: slenka vaizdÄ….
\n[7]: slenka vaizdÄ….
\n[8]: slenka vaizdÄ….
\n[9]: slenka vaizdÄ….\n

\n

\n[Shift] + pel?: naudojama Žem?lapyje rodyti jungtis tarp gamykl?tiekimo linij?.
\n[CTRL] + tool: construct (signals & Stops) on upper level; or build slower roads and tracks over faster ones; or build straighter (more direct) roads and tracks.
\n[CTRL] + ([F2] to [F12]): sets select current tool to keypresses [F2] to [F12].\n

\n

Highlight railroad tracks ParyÅ¡kinti bÄ—gius Highlite depots ParyÅ¡kinti depus Highlite electrical transmission lines ParyÅ¡kinti elektros linijas Highlite factories ParyÅ¡kinti gamyklas Highlite forests ParyÅ¡kinti miÅ¡kus Highlite tourist attraction ParyÅ¡kinti lankytinas vietas Overlay city limits Miesto ribų vaizdas Overlay passenger destinations when a town window is open Keleivių tikslų vaizdas Overlay schedules/network Tinklų/grafikų vaizdas Overlay town names Miestų pavadinimų vaizdas Please click on the map to add\nwaypoints or stops to this\nschedule. Spauskite ant žemelapio, norÄ—dami \npridÄ—ti naujų stotelių ir krypÄių\n į grafikÄ…. Show capacity and if halt is overcrowded Rodyti stoÄių talpÄ… ir perkrovimo bÅ«klÄ™. Show how many convoi reach a station Rodyti kiek konvojų sugebÄ—s pasiekti stotį Show how many people/much is waiting at halts Rodyti kiek laukia Show initial passenger departure Rodyti pradinius kelionÄ—s tikslus Show level of city buildings Miesto pastatų lygių vaizdas Show mail service coverage/mail network PaÅ¡to paslaugų/pasiekiamumo vaizdas Show passenger coverage/passenger network Keleivių tinklo vaizdas Show speedlimit of ways GreiÄio apribojimų vaizdas Show the change of waiting at halts Keleivių ir prekių laukianÄių stotyse pokyÄio per mÄ—nesį vaizdas Show the owenership of infrastructure Rodyti infrastruktÅ«ros savininkÄ… Show transported freight/freight network Pervežti kroviniai tinkle Show usage of network Transporto priemonÄ—s per mÄ—nesį pravažiavusios laukelyje Shows a listing with all industries on the map. Rodo visų įmonių sarašą. Sum of departure/arrivals at halts Visi atvykimai/iÅ¡vykimai stotyje #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s dabar\nsi?lo autobuso paslaugas\ntarp %s\nir lankytinos vietos\n%s\nat (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s dabar\nsi?lo autobuso paslaugas\ntarp %s\nir gamyklos\n%s\n (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\ndabar valdo\n%i sunkvežimius tarp\n%s esanÄios (%i,%i)\nir %s\n (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\natidar? naujÄ… geležinkel?\ntarp %s\n (%i,%i) ir\n%s\n (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Naujos oro linijos\n%s\ndabar tarp\n%s \nir %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Kompanijos\n%s\keltas veikia tarp\n%s \nir %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\natidarÄ— naujÄ…\nautobusų linijÄ… tarp\n%s ir\n%s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS ŽemÄ—lapio redagavimo įrankiai LISTTOOLS SÄ…raÅ¡ai MAGLEVTOOLS Maglev įrankiai MONORAILTOOLS VienbÄ—giÅ« traukinių statybos įrankiai NARROWGAUGETOOLS Siauruko stat. įrankiai RAILTOOLS Geležinkeliai ROADTOOLS Keliai SHIPTOOLS Uostų statybos įrankiai SLOPETOOLS Reljefo įrankiai SPECIALTOOLS Spec. statybos įrankiai TRAMTOOLS Tramvajų/lengvojo traukinio įrankiai #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s'as pastat? naujÄ… vadavietÄ™. Factory chain extended\nfor %s near\n%s built with\n%i factories. Ekonomika pakilo: \n%s Å¡alia %s praplÄ—tÄ— gamybÄ…. \n%i pastatyta nauja gamykla. New %s now available:\n%s\n Naujas %s :\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Ekonomikos pakilimas: Nauja gamyklų linija\nskirta %s Å¡alia\n%s sudaryta iÅ¡\n%i gamyklų. New vehicle now available:\n%s\n \n Atsirado nauja\n tr. priemonÄ—:\n\n\n -- %s --\n\n Now %u clients connected. Dabar %i žaidÄ—jų prisijungÄ™. Remove vehicle from map. Use with care! Naikinti transportÄ…. (Naudoti atsargiai!) Screenshot\ngespeichert.\n Ekrano fonas\niÅ¡saugotas.\n Sends the convoi to the last depot it departed from! SiunÄia konvojų į praeitÄ… depÄ… iÅ¡ kurio iÅ¡vyko With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Å vesdami,\n%s pastatÄ—\nnaujÄ… paminklÄ….\n%i miestieÄių dalyvavo ceremonijoje. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Linijos filtras #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (garaže) \nBauzeit bis iki \nBauzeit von \nAtsiranda nuo \nCan't open heightfield file.\n \nNe?manoma atverti aukÅ¡Äio žem?lapio.\n \ndirection: \nkryptys: \nelektrified \nelektrifikuotas\n \nHeightfield has wrong image type.\n \nNetinkamas failas ukÅ¡Äio žem?lapiui\n \nis reserved by: \nparuoÅ¡ta kitam traukiniui: \nminimum speed: \nmažiausias greitis: \nnot elektrified \nneelektrifikuota\n \nRibi (masked) \nkryptys (masked) \nRibi (unmasked) \nkryptys\n (unmasked): \nSet phases: \nustatyti ilgį ns/ew: \nsingle way \nViena kryptis \nway1 reserved by kelias 1 reservuotas \nkelias 1 reservuotas \nway2 reserved by kelias 2 užimtas: \nkelias 2 paruoÅ¡tas \nwith sign/signal\n \nsu ženklu/signalu\n %d buildings\n %d pastatai\n %d convois %d konvojai %d Einzelfahrzeuge im Depot %d transporto priemon?s laikomos Äia. %i years %i months old. %i metų %i mÄ—nesių amžiaus. %s at (%i,%i) now public stop. %s tapo vieÅ¡ai prieinama. %s building %s %s %s %s %s %s city %d %s %s miestas %d %s %s factory %s %s %s %s aikÅ¡telÄ— %s has entered a depot. %s pasiekÄ— depÄ…. %s land %d %s %s žem? %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \npastatÄ—\nnaujÄ… rotušę\nkada pasiekÄ—\n%i gyventojus. %s\nis crowded. %s\n užimta. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nmaksimalus greitis %3$i km/h\n\nesamas greitis %2$i km/h.\n\n %s\nwas liquidated. %s įmonÄ— bankrutavo\nir buvo likviduota.\nVisa veikla sustabdyta,\no turtas iÅ¡parduotas. %u Client(s)\n %i klientas -ų\n %u Player (%u locked)\n %u žaidÄ—jų (%u užrakinta)\n 1 convoi 1 konvojus 1 Einzelfahrzeug im Depot 1 transporto priemon? laikoma Äia. 1LIGHT_CHOOSE RyÅ¡kumas: 1WORLD_CHOOSE Nustatymai naujam žaidimui: 2LIGHT_CHOOSE Spalvos: 2WORLD_CHOOSE ŽemÄ—lapio numeris: 3LIGHT_CHOOSE Lango slinkties greitis: 4LIGHT_CHOOSE AtvirkÅ¡tine slinktis 5LIGHT_CHOOSE P?stieji stotel?se 5WORLD_CHOOSE GyvenvieÄių skaiÄius: 6LIGHT_CHOOSE P?stieji gatv?se 6WORLD_CHOOSE Eismo intensyvumas: 8WORLD_CHOOSE dienos ir nakties kaita A bridge must start on a way! Tiltai privalo\nprasid?ti ant\negistuojanÄio kelio. Abfrage Tikrinimo ?rankis Abnehmer Vartotojas About Apie Abriss Sunaikinti/paÅ¡alinti Absenken Nuleisti žemÄ™ Abspanntransformator Transformatorius Accelerate time ?sib?g?jimo laikas Act. load: %u MW\n \nApkrova: Active player only Tik aktyvus žaidÄ—jas Add forest Prid?ti miÅ¡kÄ… Add random citycar PridÄ—ti bet kokį automobilį add server PridÄ—ti serverį Add Stop Pastatyti stotelÄ™ Add stops for backward travel Prid?ti stot? atgaliniam keliavimui. air takas aircraft_tab Krovininiai l?ktuvai airplane L?ktuvas Airport Aerouostas AIRTOOLS Orousto statybos ?rankiai All Visi all convoi tooltips visi konvojų praneÅ¡imai Allow city growth Leisti miestui augti Allow player change Leisti žaid?jo apsikeitimÄ… allowed climates:\n Leidžiami klimatai:\n Alters a schedule. Prideda/naikina stoteles iÅ¡ grafiko Angenommene Waren Prek?s reikalingos kitoms gamykloms anhaengen IÅ¡ardyti Anhaenger_tab Priekabos Anheben Kelti žemÄ™ Appends stops at the end of the schedule Prid?ti stotelÄ™ grafiko gale Apply Line Priskirti linijÄ… April Balandis Arbeiter aus: Darbininkai gyvena: Arrived AtvykÄ™ Assets Turtas Aufloesen Keisti Aufspanntransformator Transformatorius August RugpjÅ«tis Autohalt muss auf\nStrasse liegen!\n Autobuso ar automobilio stotelÄ—s\nturi bÅ«ti\nant kelio. Available Galimi Bahndepot Traukinių depas Bankrott:\n\nDu bist bankrott.\n Bankrotas:\n\nTU BANKRUTAVAI!\n battery Baterija Baum Medis baum builder Sodinti medžius Baustelle StatybvietÄ— Bauzeit statymo laikas Beenden IÅ¡eiti Beginner mode Naujoko rėžimas Besonderes Gebaeude Lankoma vieta BF stotis bio biologinis Blockstrecke ist\nbelegt\n \nBÄ—gių blokas naudojamas\nkito traukinio!\n Boden ŽemÄ— Bonusspeed: %i km/h Maks. greitis: %i km/h Boost (%%) Produktyvumas (%%) bridge is too high for its type! Tiltas per aukÅ¡tas savo tipui! Bridge is too long for this type!\n Tiltas per ilgas\nnaudokite kitÄ…\ntipÄ….\n Bruecke Tiltas Bruecke muss an\neinfachem\nHang beginnen!\n Tiltas privalo\nprasidÄ—ti ant\ntiesios nuokalnÄ—s!\n Brueckenboden tiltas Build air depot Statyti angarÄ… build choosesignals Pastatyti "Rinkis platformÄ…" signalus. Build city market Pastatyti naujÄ… prekybos centrÄ… artimiausiame mieste. Build drain TransformatorinÄ— build HQ Statyti bÅ«stinÄ™ Build land consumer Pastatyti elektrinÄ™. Build maglev depot Statyti maglev depÄ… Build monorail depot Pastatyti vienbÄ—gio depÄ… Build narrowgauge depot Statyti siauruko depÄ… Build powerline Pastatyti elektros trasÄ… Build presignals Pastatyti presignalus Build road depot Pastatyti garažą Build ship depot Pastatyti laivų statyklÄ… Build signals Ä®rengti signalus Build train depot Pastatyti traukinių depÄ… Build tram depot Pastatyti tramvajų depÄ… Build truck depot Statyti garažą Building costs estimates Numatoma statybų kaina Buildings Pastatai Built artifical slopes Sukasti Å¡laitus Built random attraction Pastatyti atsitiktinÄ™ lankomÄ… vietÄ… Bus_tab Autobusai Can only move from halt to halt or waypoint to waypoint. Galima judÄ—ti\ntik nuo gairÄ—s iki gairÄ—s\nar nuo sustojimo iki sustojimo. Cancel AtÅ¡aukti Cannot connect to offline server! Negalima prisijungti prie serverio: serveris atsijungÄ™s. Capacity: %.0f MW Pralaidumas:%.0f MW\n Capacity: %d%s %s\n Talpa: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Talpa: %s\n? %d (%d%%) Cars are not available yet! MaÅ¡inos dar neprieinamos. cars.\nstate automobiliai\n Cash SÄ…skaitos balansas Change player Pakeisti žaidÄ—jÄ… Chart Diagrama Chat_msg ÄŒatas Choose direction RinkitÄ—s kryptį Choose operation executed on clicking stored/new vehicles Pasirenkamas veiksmas vykdomas paspaudus ant saugomų/naujų transporto priemonių chooses a random map Pasirenkamas atsitiktinis žemÄ—lapis. citicens Gyventojai City attraction Lankoma vieta City industries Prekybos centrai miestuose City list Miestų sÄ…raÅ¡as City size Miesto dydis city_road Miesto kelias citybuilding builder Miesto pastatų įrankis CityLimit Miesto ribos cl_title Tr. priemonių sÄ…raÅ¡as cl_txt_sort SuruÅ¡iuoti pagal: Clear block reservation Naikinti bloko rezervacijÄ… clf_chk_aircrafts LÄ—ktuvai clf_chk_cars Autobusai/sunkvežimiai clf_chk_indepot depe clf_chk_maglev Magnetiniai tr. clf_chk_monorail VienbÄ—giai clf_chk_name_filter Filtrų pavadinimai: clf_chk_narrowgauge Siauruko traukiniai clf_chk_noincome nÄ—ra pajamų clf_chk_noline be linijos clf_chk_noroute nÄ—ra kelio clf_chk_noschedule nÄ—ra grafiko clf_chk_obsolete PasenÄ™ clf_chk_ships Laivai clf_chk_spezial_filter Specialus filtras: clf_chk_stucked užstrigo clf_chk_trains Traukiniai clf_chk_trams Tramvajai clf_chk_type_filter Filtruoti tipus: clf_chk_waren Filtruoti pagal krovinius: clf_title Tr. priemonių sÄ…raÅ¡o filtras Climate Control Nustatyti klimatÄ… closed uždaryta COLOR_CHOOSE\n PraÅ¡ome pasirinkti\nspalvÄ… iÅ¡ lentelÄ—s:\n Company bankrupt Kompanijos bankrotas Company_msg Konkurentai Comparing pak files ... Lyginami pak paketai... Configure AI KonfigÅ«ruoti DI Configure AI setttings Nustatyti Dirbtinio Intelekto nustatymus Congratulation\nScenario was complete in\n%i months %i years. Sveikiname!\njÅ«s pabaigÄ—te \nscenarijų per \n%i mÄ—nesių ir %i metų! Connected stops Aptarnaujamas stotelių: Connected with server Prisijungta prie serverio Constructed by Nupiešė : Constructed by %s Nupiešė %s construction speed statymo greitis Construction_Btn Statybos/pirkimo kaina Consumed Suvartota convoi %d of %d Konvojus %d iÅ¡ %d convoi error tooltips konvojaus praneÅ¡imai Convoi has been sent\nto the nearest depot\nof appropriate type.\n Konvojus buvo iÅ¡siųstas\nį artimiausia depÄ…. \n Convoi is sold when all wagons are empty. Transporto priemonÄ— bus perduota iÅ¡kart kai bus tuÅ¡Äia. convoi mouseover tooltips konvojų praneÅ¡imai užvedus rodyklÄ™ convoi passed last\nmonth %i\n \nkonvojai pravažiavÄ™ praeitÄ…\nmÄ—nesį: %i\n Convois Konvojai Convois: %d\nProfit: %s Tr. priemonÄ—s: %d\nPelnas: %s Convoys Konvojai Copy Convoi Nukopijuoti maÅ¡inÄ… Copy the selected convoi and its schedule or line Kopijuoti pasirinkta konvojų ir jo grafikÄ… ar visÄ… linijÄ… cost for removal PaÅ¡alinimo iÅ¡laidos Costs Kainuoja Create a new line based on this schedule Sukurti linija paremta Å¡iuo grafiku curiosity builder Ä®vairÅ«s pastatai curlist_title Lankomų vietų sÄ…raÅ¡as Currently playing: Grojama: Customers live in: Klientai gyvena: deactivated in online mode Neveikia "online" rėžime Deccelerate time SulÄ—tinti laikÄ… December Gruodis decrease underground view level nuleisti požeminį vaizdÄ… Del Stop PaÅ¡alinti Delete Line PaÅ¡alinti linijÄ… Delete the current stop Sugriauti stotelÄ™ Delete the selected line (if without associated convois). IÅ¡trinti pasirinktÄ… linijÄ… (jei linija tusÄia) Delete this file. IÅ¡trinti šį failÄ… Delivered Nusiųsta Demand Paklausa Demand: %.0f MW Paklausa: %.0f MW \n Denkmal Monumentas Departed IÅ¡vykÄ™ Depots Depai Der Tunnel ist nicht frei!\n Tunelis nÄ—ra tuÅ¡Äias.\n Destination Tikslas Destroying map ... Naikinamas žemÄ—lapis ... Details Informacija Die Bruecke ist nicht frei!\n Tiltas užimtas \n diesel dyzelis Direkt erreichbare Haltestellen Tiesioginiai marÅ¡rutai iÅ¡ Å¡ios vietos disable midi IÅ¡jungti MIDI muzikÄ… Display settings Vaizdo nustatymai Distance Atstumas Dock prieplauka Dock must be built on single slope! Dokai turi bÅ«ti pastatyti ant lygios pakrantÄ—s. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Tu turi %d mÄ—nesių gražinti skolÄ…. Durchsatz Max. Economy Miestai ir ekonomika Eigenbesitz\n VieÅ¡a nuosavybÄ—\n Ein %s\npasst hier nicht.\n '%s'\nÄia netinka!\n Einstellungen aendern Pakeisti nustatymus electric elektrinis Electricity Elektra Electricity producer\n\n Elektros gamintojas\n\n Electrics_tab Elektriniai Electrify track Elektrifikuoti bÄ—gius enlarge map Padidinti žemÄ—lapį enter a value between %i and %i Ä®veskite reikÅ¡mÄ™ tarp %i ir %i Enter address Ä®vesti adresÄ… Enter Password Keisti žaidÄ—jo vardÄ… ir slaptažodį Error Klaida Erzeuge neue Karte.\n PraÅ¡om palaukti kol naujas\nžemÄ—lapis kuriamas.\n\n(Tai gali užtrukti kelias\nminutes dideliems žemÄ—lapiams.) Es wird bereits\nein Fahrplan\neingegeben\n Grafikas\nsuplanuotas.\nPirmÄ… jį pabaikite\nprieÅ¡ pakeisdami jį iÅ¡ naujo!\n Fabrikanschluss Sujungtos gamyklos Fabrikname gamyklos pavadinimas Factories Gamyklos factory details Gamyklos informacija factorybuilder Statyti gamyklÄ… Fahrplan Grafikas Fahrtziel Tikslas: Fahrzeuge koennen so nicht entfernt werden maÅ¡inos negali bÅ«ti\npaÅ¡alintos tokiu bÅ«du!\n Fahrzeuge: Transportas: Farbe ŽaidÄ—jo spalvos Fast forward Prasukti laikÄ… February Vasaris Ferry_tab Keltai Fertig Atlikta Filename Failas: Filter: Filtras: Finances of %s Financai %s Finanzen Financai find mismatch Palyginti pak fl_title Gamyklų sÄ…raÅ¡as Flug_tab Keleivinis lÄ—ktuvas follow me Sek mane! Follow the convoi on the map. Sekti konvojų žemÄ—lapyje. Forest MiÅ¡kas Found new city Ä®kurti naujÄ… miestÄ… FPS: Kadrai/s: Fracht Krovinys Frame time: Kadro laikas: Free Capacity Laisva Talpa freeplay mode laisvas žaidimas Friction: Trinties faktorius: fuel_cell kuro elementas Full load Minimali apkrova: Fundament Pamatas Fussgaenger PÄ—stysis Game info Žaidimo info GAME PAUSED Žaidimas sustabdytas Game_msg Bendri Gear: Pavara: Gebaeude Pastatas General Pagrindiniai Generated Sugeneruotas Generation: %.0f MW Gamyba: %.0f MW\n Gewicht Svoris Gewinn Pelnas: Give the selected vehicle(s) an individual schedule Duoti transporto priemonei nuosavÄ… grafikÄ…. gl_btn_sort_catg pagal kategorijÄ… gl_title Visas prekių sÄ…raÅ¡as go home Ä® depÄ…. Goods PrekÄ—s Goods AI Prekių DI Goods list Prekių sÄ…raÅ¡as Gross Profit Pinigų prieaugis Groundobj Objektas Grow city PlÄ—sti miestÄ…. Growth Miesto augimas H stotelÄ— Hangar Angaras Happy Laimingi Haus kaufen Nupirkti namÄ… Helligk. Rodyti Help Pagalba Help text not found TrÅ«ksta pagalbinio teksto. hide all building slÄ—pti pastatus hide city building slÄ—pti miesto pastatus hide objects under cursor paslÄ—pti objektus po kursoriu hide station names slÄ—pti stotelių pavadinimus hide transparent permatomi užuot paslÄ—pti hide trees SlÄ—pti medžius Hier warten/lagern: Laukiantys keleiviai ir prekÄ—s: Higher transport fees, crossconnect all factories Didesni transporto mokesÄiai, iÅ¡jungti "Just-In-Time". Highlite schedule rodyti grafiko stoteles hl_title StoÄių sÄ…raÅ¡as hl_txt_filter Filtras: hl_txt_sort Sutrumpinta pagal: hlf_chk_airport Aerouostai hlf_chk_anleger Dokai hlf_chk_bahnhof Geležinkelio stotis hlf_chk_bushalt Autobuso stotelÄ— hlf_chk_frachthof Krovos punktas hlf_chk_keine_verb Nesujungta hlf_chk_maglevstop Magnetinio tr. stotelÄ— hlf_chk_monorailstop VienbÄ—gio stotelÄ— hlf_chk_name_filter Filtro pavadinimas: hlf_chk_narrowgaugestop Siauruko stotelÄ— hlf_chk_overflow VirÅ¡ talpos hlf_chk_spezial_filter Specialus filtras: hlf_chk_tramstop Tramvajaus stotelÄ— hlf_chk_type_filter Filtro tipai: hlf_chk_waren_abgabe Produkcija: hlf_chk_waren_annahme Reikalingos prekÄ—s: hlf_title StoÄių sÄ…raÅ¡o filtras Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depas nerastas.\nSiųskite transporto priemonÄ™\nrankiniu bÅ«du. Homeless "Benamių" hydrogene Vandenilis Idle: Laisvi: ignore climates nekreipti dÄ—mesio į klimatÄ… In the industry legend show only currently existing factories Rodyti tik egzistuojanÄias gamyklas Increase Industry density Padidinti gamyklų tinklo tankį increase underground view level pakelti požeminį vaizdÄ… industrial building Pramoninis pastatas Init map ... Paledžiamas žemÄ—lapis ... Input įvestis Ins Stop Ä®terpti Insert stop before the current stop Ä®terpia stotelÄ™ prieÅ¡ pasirinktÄ… Intercity road len: Tarpmiestinio kelio ilgis: Intro. date: Atsiradimo data: invalid nenustatyta. Invalid coordinate Netinkamas nurodymas isometric map Izometrinis žemÄ—lapis January Sausis join game Prisijunk ! July Liepa Jump to PerÅ¡okti į June Birželis Kann Spielstand\nnicht laden.\n Neįmanoma užkrauti iÅ¡saugoto žaidimo! Kann Spielstand\nnicht speichern.\n Neįmanoma atverti\npasirinktos bylos\nįraÅ¡imui! Kein Besitzer\n Neturi savininko\n keine n?ra Keine Einzelfahrzeuge im Depot ÄŒia nÄ—ra transporto priemonių. Keyboard_Help\n KlaviatÅ«ros pagalba\n koord koordinatÄ—s Kreuzung Pervaža labellist_title Žymeklių sÄ…raÅ¡as Lade Relief AukÅ¡Äių žem. Laden Užkrauti Land attraction Traukos vieta Land industries Ä®monių grandinÄ—s LANG_CHOOSE\n PraÅ¡ome pasirinkti kalbÄ…:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Pask. mÄ—nuo: Last Year Praeiti metai: Leaving depot! PaliekÄ… depÄ…! leer tuÅ¡Äia Legend Sutartiniai ženklai Leistung Galia Leistung: %d kW Galia: %d kW Leitung Elektros linija letzen Monat: diesen Monat: PraeitÄ… mÄ—nesį: Šį mÄ—nesį: Line Linija Line Management Linijos valdymas Lineless convoys serving this stop Konvojai be linijos aptarnauja Å¡iÄ… stotelÄ™ Lines serving this stop Linijos aptarnaujanÄios Å¡iÄ… stotelÄ™ LKW_tab Sunkvežimiai Load game Užkrauti žaidimÄ… load height data from file Užkrauti aukÅ¡Äių duomenis iÅ¡ failo. Load scenario Užkrauti scenarijų loaded užkrauta loaded passenger/freight Rikiuoti prekes/krovinius pagal Loading (%i->%i%%)! Krauna (%i->%i%%) Loading addon paks ... Krauna papildinius ... Loading map ... Kraunamas pasaulis... Loading paks ... Kraunami pak'ai... Loading skins ... Kraunamos temos ... Lock game Uždrausti žaidÄ—jų apsikeitimÄ… (reikia patvirtinimo). Lokomotive_tab Lokomotyvai m3 m³ Maglev Magnetinis tr. maglev vehicle magnetinis traukinys maglev_track MagnetinÄ—s levitacijos bÄ—giai Maglevdepot Magnetinio traukinio depas Mail Demand %d\n PaÅ¡to paklausa %d\n Mailbox ŽinutÄ—s Mailbox Options ŽinuÄių nustatymai Maintenance IÅ¡laikymas make stop public (or join with public stop next) costs %i per tile and level Paversti stotelÄ™ vieÅ¡a (ar sujungti su gretimomis vieÅ¡omis stotelÄ—mis) kainuoja %i$ per aukÅ¡tį ir langelį Manual (Human) Rankinis (žmogus) Manufactured: Pagaminta: Map roughness ŽemÄ—lapio Å¡iurkÅ¡tumas: map zoom Priartinimas March Kovas Margin (%%) Margin'as Marker Pastatyti ženklÄ… Max Boost (%%) Maks. bonusas (%%) Max income: Max pajamos: Max. speed: Max greitis: Maximum 254 stops\nin a schedule!\n Daugiausia 254 stotelÄ—s\ngrafike!\n maximum length of rivers Max. upių ilgis Maximum tile height difference reached. Didžiausias aukÅ¡Äių\nskirtumas tarp\ndviejų langelių\nbuvo pasiektas. Maxspeed Maks. greitis May Gegužė Median Citizen per town Vidutinis miesto gyventojų sk.: Meldung ŽinutÄ— Menge kiekis MessageOptionsText \nNauji metai\n\nDI Naujienos\n\nMiesto naujienos\n\nnÄ—ra kelio\n\nNaujos įmonÄ—s\n\n"chat"\n\nNaujos tr. priemonÄ—s\n\nStotelÄ— pilna\n\nProblemos\n\nTraffic jam\n\nScenario min min. minimum length of rivers Min. upių ilgis Missing pakfiles TrÅ«ksta objektų Modify the selected line Modifikuoti pasirinktÄ… linijÄ… Monate alt mÄ—nesių amžiaus. Monorail VienbÄ—gis monorail vehicle VienbÄ—gis traukinys monorail_track VienbÄ—gio bÄ—giai Monorailboden VienbÄ—gio kelio atrama Monoraildepot VienbÄ—gio depas month wait time laukimo laikas mÄ—nesiais Months MÄ—nesiai Monument Statula Monuments Statulos Mountain height Kalnų aukÅ¡tis: Movingobj judantis objektas Music playing disabled/not available Muzikos groti neįmanoma arba ji iÅ¡jungta. Music volume: Muzikos garsas: mute sound Be garso Name Pavadinimas Narrowgauge Siaurukas Narrowgauge are not available yet! Siauruko dar negalima statyti. narrowgauge vehicle Siauruko traukinys narrowgauge_track Siauruko bÄ—giai Narrowgaugedepot Siauruko depas Net ID: %p Tinklo Nr: %p\n Net Wealth Turto vertÄ— Net wealth near zero Bendra turto vertÄ— beveik 0 Neue Karte Naujas žaidimas Neue Welt Paleisti naujÄ… žaidimÄ… new convoi Naujas sÄ…statas New Line Nauja linija New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nauja linija įkurta!\nJÅ«s galite pridÄ—ti naujas \n tr. priemones į linijÄ…. New Vehicles Naujas tr. Nickname: Vardas: no buildings hidden pastatai nepaslÄ—pti no convois NÄ—ra konvojų No goods are loaded onto this convoi. Å iame konvojuje nebus pakrauta krovinių. no goods waiting nÄ—ra krovinių no load Nepakrauti No Route NÄ—ra kelio No stop here! Ä®rankį naudoti tik ant stotelių lagelių. No suitable ground! Netinkama žemÄ—! No terminal station here! Neįmanoma pastatyti \nstoties Äia! Reikia statytiti ant jau egzistuojanÄių \n kelių ar bÄ—gių. no timeline visos eros no tree NÄ—ra medžių Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Duokite tvarkaraÅ¡tį!\nPrieÅ¡ paleisdami konvojų! none joks nord Å iaurÄ— nordost Å iaurÄ—s rytai nordwest Å iaurÄ—s vakarai Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Transporto priemonÄ—s\ngrafiko nekeisti\nper kelio paieÅ¡kÄ…. Not enough fields would remain. Per mažai laukų\nliks aplink Å¡iÄ… fermÄ…. November Lapkritis Now active as %s.\n Dabar žaidžiate kaip %s.\n Number of rivers Upių kiekis Object Objektas Odometer: %s km Kilometražas: %s km Ok Gerai Oktober Spalis On loan since %i month(s) Skoloje %i mÄ—nesius On this map, you are not\nallowed to change player!\n Žaidimas užrakintas.\nŽaidÄ—jo keitimas uždraustas.\n Only city chains Tik miesto įmonÄ—s Only first %d differing paks reported. There are probably more. Tik pirmi %d pak'ai rodomi. Galimai jų skaiÄius didesnis. Only land chains Tik sausumos įmonÄ—s. Only one transformer per factory! Leidžiamas tik vienas transformatorius gamyklai! Only show goods which are currently handled by factories Rodyti tik prekes, kurias gali apdirbti gamykla open atvertas. Operation Veikimo kaina Ops Profit AtneÅ¡tas pelnas Optionen Parametrai Or enter a server manually: Arba įveskite serverį rankiniu bÅ«du: Origin KilmÄ— ost Rytai Output IÅ¡eiga Ownership Savininkai Pak which may cause severe errors: TrÅ«ksta Å¡ių paketų objektų, kas gali sukelti problemų ir sugadinti gamybos grandines: Pak which may cause visual errors: Paketų objektai pakeisti analogais: Pak(s) different: Pak skirtumai: Pak(s) missing on client: Paketai trÅ«kstami kliento pusÄ—je: Pak(s) not on server: Paketai nesantys serveryje: Pakset differences Paketų skirtumai paletten dėžės Pas_tab Keleiviniai traukiniai Passagiere Keleiviai Passagierrate Keleivių kiekis Passagierziele Keleivių/ paÅ¡to tikslai Passenger AI Keleivių DI Passenger Demand %d\n Keleivių paklausa %d\n Passengers %d %c, %d %c, %d no route Keleiviai %d %c, %d %c, %d neturi kelio Passengers %d %s, %d %s, %d no route Keleiviai %d %s, %d %s, %d neturi kelio Password Slaptažodis: Pause PauzÄ— Pax <%i> Mail <%i> Keleiviai <%i> PaÅ¡tas <%i> PaxDest Tikslai Percent Electricity Elektros gamyba (%%paklausos): Planes are not available yet! LÄ—ktuvai dar neasirado. Plant tree Sodinti medžius player ŽaidÄ—jas player -1 žmogus player 0 valstybÄ— player 1 Napik 128 AS player 10 UAB "Busturas" player 11 žaidÄ—jas nr. 11 player 12 žaidÄ—jas nr. 12 player 13 žaidÄ—jas nr. 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Eksppedicija VM player 5 Hayo, the conqueror UAB player 6 PSK & Co KG player 7 LG, valstybinÄ— įmonÄ— player 8 Kauno Å¡iukÅ¡lių ir keleivių pervežimo kompanija player 9 UAB "K-Busas" Please choose vehicles first\n Pirma pasirinkite automobilį!\n Post PaÅ¡tas Postrate PaÅ¡to lygis Power Galia Power (MW) Galia (MW) Power: Galia: Powerlines Elektros linijos Problems_msg BÄ—dos Produced Pagaminta Production of %s has been stopped:\n%s\n Gamyba %s sustabdyta:\n%s\n Production/Boost Produktyvumas/Bonusas Produktion Gamyba Profit Pelnas promote to line Paversti į linijÄ… q1 Pavasaris q2 Vasara q3 Ruduo q4 Žiema Query server IeÅ¡koti serverių rail car vagonas random atsitiktinis Random age bet kokie metai Random map Bet koks žemÄ—lapis Rathaus Rotušė Rating Reitingas ratio_pax Keleiv. koef. Relevant Atitinkami Reliefkarte ŽemÄ—lapis Remove PaÅ¡alinti užrašą remove airstrips Naikinti pakilimo takus remove channels Sunaikinti kanalus remove interm. signals PaÅ¡alinti tarpinius signalus remove maglev tracks Å alinti magnetinius bÄ—gius remove monorails Å alinti vienbÄ—gį remove narrowgauge tracks Naikinti siaurukÄ… remove powerlines PaÅ¡alinti el. linijas remove roads Griauti keliÄ… remove tracks Ardyti bÄ—gius Remove wayobj %s PaÅ¡alinti kelio objektus %s replace other signals Pakeisti kitais signals replace stop Keisti stotelÄ™ request closing praÅ¡yti uždarymo residential house Gyvenamasis namas Restore natural slope Sugražinti kalvos Å¡laitÄ… Restwert: Perpardavimo vertÄ—: Retire. date: Pasens: return ticket kopijuoti atv. Revenue Pajamos Revision: Versija: road kelias road vehicle automobilis Roadsign Ženklas Rotate map Sukti vaizdÄ… Rotation Sukimas Routing Kelio paieÅ¡ka sack maiÅ¡ai sail vÄ—jas Saving map ... IÅ¡saugomas žemÄ—lapis ... Scenario complete: %i%% Scenarijus baigtas: %i%% Schedule changing! Grafikas keiÄiasi! Schienentunnel Statyti geležinkelio tunelį Schiff_tab Laivai Schiffdepot Laivų statykla Schleppkahn_tab Baržos Screenshot Nufotograpuoti ekrano fonÄ…. Seasons Metų laikai Sehenswuerdigkeit Lankytina vieta Select a server to join: Pasirinkite serverį prisijungimui: Sell the selected vehicle(s) Parduoti transporto priemones sended IÅ¡siųsta paÅ¡to SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September RugsÄ—jis Server did not respond! Serveris neatsako! Serves Line: Aptarnaujama linija: Service Aptarnavimas set signal spacing Nustatyti atstumÄ… tarp signalų Setting Nustatymai Ship Laivai shops and stores ParduotuvÄ—s ir biurai Show all Rodyti viskÄ… show all building Rodyti visus pastatus Show also vehicles no longer in production. Rodyti ir automobilius kurie daugiau nebegaminami Show also vehicles that do not match for current action. Taip pat parodyti tr. priemones, kurios negali bÅ«ti panaudotos. Show even servers with wrong version or pakset Rodyti ir serverius skirtus kitam pak'ui ar versijai. show grid Rodyti tinklelį Show industry Rodyti įmones Show legend Rodyti legendÄ… Show map scale Spalvų kodai Show mismatched Rodyti nesutapimus Show obsolete Rodyti pasenusius Show offline Rodyti atjungtus Show only used Rodyti naudojamus Show schedules Rodyti marÅ¡rutus Show servers that are offline Rodo atjungtus serverius Show servers where game version or pakset does not match your client Rodyti serverius su nesutampanÄia žaidimo ar paketo versijomis esanÄiomis kliento pusÄ—je show station coverage Rodyti stotelių aprÄ—ptį show station names Rodyti stotelių pavadinimus show waiting bars rodyti laukimo juostas show/hide block reservations rodyti/slÄ—pti blokų rezervacijas show/hide object owner rodyti objektų savininkus Show/hide statistics Rodyti/slÄ—pti statistikÄ… Shows buttons on special topics. Rodyti mygtukus spec. straipsniams Shows consumer/suppliers for factories Rodyti tiekÄ—jus ir vartotojus gamyklose Shows the color code for several selections. Rodyti spalvas keliems pažymÄ—jimams. Shows the currently selected schedule Rodyti esamÄ… grafikÄ… Shrink city Mažinti miestÄ… shuffle midis iÅ¡maiÅ¡yti muzikÄ… Signal Signalas signal spacing Tarpai tarp signalų Sim: Simuliacijos/min: Similar view as the main window Vienodas vaizdas kaip pagrindiniame lange Size (%d MB): Dydis (%d MB): sliced underground mode Sluoksniuotas vaizdas slot empty tuÅ¡Äia Smart hide objects SlÄ—pti objektus automatiÅ¡kai Sort by rikiuoti krovinius pagal Sort waiting list by Rikiuoti laukianÄiuosius pagal Sound Garsas Sound settings Garso nustatymai Sound volume: Garso lygis: special freight Specialus krovinys Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. GreiÄio bonusas\nkelias %i km/h, geležinkelis %i km/h\nlaivai %i km/h, lÄ—ktuvai %i km/h. Speedlimit GreiÄio apribojimas Speichern IÅ¡saugoti Spieler ŽaidÄ—jas Spieler(mz) ŽaidÄ—jai Spielerliste ŽaidÄ—jų sÄ…raÅ¡as Spielstand wurde\ngeladen!\n \nŽaidimas užkrautas.\n Spielstand wurde\ngespeichert!\n \nŽaidimas iÅ¡saugotas.\n Sprache Kalba Sprachen Kalbos Stadtinformation Miesto statistika Start PradÄ—ti Start the selected vehicle(s) Paleidžia transporto priemones. Starte Spiel Paleisti žaidimÄ… Station tiles: StotelÄ—s laukeliai: Station_msg Stotys Status StotelÄ—s statusas steam garinis Step timeline one year Praleisti 1 metus. Stops Sustojimai Storage Talpykla Storage capacity Saugyklos talpa Strassendepot Garažas Strassentunnel Statyti geležinkelio tunelį street car lengvasis automobilis sued PietÅ«s suedost PietryÄiai suedwest Pietvakariai Summer snowline Vasaros sniego juosta: Supplied: %.0f %% Tiekta: %.0f %% Suppliers TiekÄ—jai Tage alt dienų senumo. There are still vehicles\nstored in this depot!\n Å itame depe\nyra automobilių!\n This Month Šį mÄ—nesį This Year Å iais metais: Tile not empty. Apvalykite laukelį\nprieÅ¡ kasdami Å¡laitÄ…. timeline su laiko tÄ—kme tl_title Vaizduoti visus miestus To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Pritraukti turistams,\n%s pastatÄ— %s\nsu pagalba n%i mokeÅ¡Äių mokÄ—tojų. To heavy traffic\nresults in traffic jam.\n Didelis eismas\nsukÄ—lÄ— kamÅ¡tį.\n Toggle day/night view Dienos/ nakties rėžimas Toggle vehicle tooltips Keisti transporto praneÅ¡imus tonnen t Total inhabitants: Gyventojai: Tourist attractions Turistų traukos centrai: Tourists Lankytinos vietos Town_msg Nauji tikslai Town: %s\n Miestas %s.\n Towns Miestai track bÄ—giai Tracks BÄ—giai Traffic Eismas Train Traukinys Trains are not available yet! Traukinių dar negalima statyti. Tram Tramvajus tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tramvajus %i km/h, vienbÄ—gis %i km/h\nmaglev %i km/h, siaurukas %i km/h tram_track Tramvajaus bÄ—giai Tramdepot Tramvajus depas Trams are not available yet! Tramvajų dar negalima gaminti. Transferring game ... Perkeliamas žaidimas ... Transformer only next to factory! Transformatoriai privalo bÅ«ti\nant laisvo žęmÄ—s ploto\nprie gamyklos! Translation Vertimas transparent station coverage permatomas stoties vaizdas Transported Nukeliavo TrolleyBus_tab troleibusai Truck Sunkvežimiai Tunnel muss an\neinfachem\nHang beginnen!\n Tuneliai\nprasideda ant\ntiesaus Å¡laito!\n Tunnel must start on single way! Tuneliai privalo prasidÄ—ti viename kelyje Tunnelboden Tunelis underground mode požeminis vaizdas UNDO failed! Undo nebeįmanomas.\n Undo veikia tik \n kai nÄ—ra ant kelio\n signalų, stotelių\n ir kitų daiktų. Undo last ways construction AtÅ¡aukti paskutinÄ™ konstrukcijÄ… Unemployed Bedarbiai Unhappy Nepatenkinti units/day vienetai/mÄ—nesį Update Line Atnaujinti linijÄ… upgrade HQ Patobulinti bÅ«stinÄ™ Usage: %.0f %% Gener. naudojimas: %.0f %% Usage/Output Sunaudojimas/IÅ¡eiga Use beginner mode Naujoko rėžimas Use timeline start year Laikas teka, nuo: Vehicle %s can't find a route! Automobilis %s\nneranda kelio! Vehicle %s is stucked! Automobilis %s užstrigo! Vehicle details Transporto priemonÄ—s info Verbrauch Vartojimas Vergroessere die Karte\n Padidinti žemÄ—lapį \n verkaufen Pardavimas Verkehrsteilnehmer miesto maÅ¡inos Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Tu turi %d mÄ—nesių\niÅ¡mokÄ—ti skolÄ….\n via per (info) via %s\n per %s\n via Menge per (kiekis) voranstellen Perkelti priekin Waggon_tab Vagonai waiting laukia Waiting for clearance! Laukia laisvo kelio! Walked Išėjo Warnings_msg Eismas Wasser Vanduo Water Kanalas Water level Vandens lygis: water vehicle laivas way %s cannot longer used:\n Kelio %s daugiau nebegalima naudoti.\n way %s cannot longer used:\n%s\n Kelio rūšis %s negali bÅ«ti naudijama:\n way %s now available:\n Nauja kelio rūšis : %s .\n Ways not connected Keliai nesujungti Wegpunkt GairÄ— Wert VertÄ— west Vakarai Winter snowline Sniego aukÅ¡tis žiemÄ… withdraw atstatydinti Withdraw All Atstatydinti visus WRONGSAVE \nIÅ¡saugotas žaidimas ne tai versijai.\nNeįmanoma įkrauti failo.\n Year %i has started. Metai %i prasidÄ—jo. Years Metai Your primary color: PagrindinÄ— spalva: Your secondary color: Papildoma spalva: Zielort tikslas zooming in pritraukiama zooming out atitraukiama Zu nah am Kartenrand Negalite statyti\nper arti \nžemÄ—lapio kraÅ¡to. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Magnetinis traukinys pasiekÄ—: %.1f km/h.\n Traukinys pasiekÄ—s rekordÄ… buvo pavadintas %s. New world record for monorails: %.1f km/h by %s. Naujas vienbÄ—gio pasaulio\n rekordas: %.1f km/h\npasiektas %s. New world record for motorcars: %.1f km/h by %s. Naujas pasaulio motoristų\nrekordas:\n %.1f km/h\n kurį pademonstravo %s. New world record for narrowgauges: %.1f km/h by %s. Naujas siauruko pasaulio rekordas:/n %.1f km/h pasiektas %s. New world record for planes: %.1f km/h by %s. Naujas lÄ—ktuvo pasaulio \nrekordas:\n %.1f km/h\npasiektas %s. New world record for railways: %.1f km/h by %s. Naujas traukinio pasaulio \nrekordas:\n %.1f km/h \npasiektas %s. New world record for ship: %.1f km/h by %s. Naujas laivų pasaulio rekordas:\n %.1f km/h\npasiektas %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL inÄ— &1_CITY_SYLL as &2_CITY_SYLL miestis &3_CITY_SYLL vilis &4_CITY_SYLL iai &5_CITY_SYLL iÅ«nai &6_CITY_SYLL ys &7_CITY_SYLL arÄ— &8_CITY_SYLL onas &9_CITY_SYLL uojis &A_CITY_SYLL akiai &B_CITY_SYLL iuolÄ— &C_CITY_SYLL Å«kis &D_CITY_SYLL Ä—nai &E_CITY_SYLL ius %0_CITY_SYLL PuÅ¡ %1_CITY_SYLL Appingas %2_CITY_SYLL Medž %3_CITY_SYLL Kaun %4_CITY_SYLL KalabybiÅ¡k %5_CITY_SYLL MÄ—smal %6_CITY_SYLL Montvil %7_CITY_SYLL Narkon %8_CITY_SYLL Mork %9_CITY_SYLL Bil %A_CITY_SYLL Sen %B_CITY_SYLL Kaln %C_CITY_SYLL Panevėž %D_CITY_SYLL Mek %E_CITY_SYLL Tilž %F_CITY_SYLL Ties 0center %s Centras %s 0extern %s PriemiesÄio %s 1center %s %s 1extern %s atÅ¡akos %s 1suburb %s %s %s 2center %s centrin? %s 2extern %s IÅ¡orin? %s 2suburb %s Greenfieldas %s %s 3center %s pagrindinis %s 3extern %s žem? %s 3suburb %s kaimas %s %s 4center %s vidin? %s 4extern %s iÅ¡orin? %s 4suburb %s kaimo % 5center %s perk?la %s 5extern %s krova %s 5suburb % miestelio % 6center %s sankirta %s 6extern %s pamiÅ¡k? %s 6suburb %s pakampių %s 7center %s miestas %s 7extern %s lygumų %s 7suburb %s parkas %s 8center %s transporto mazgo %s 8extern %s %s pamiÅ¡kÄ—s %s 8suburb %s ateities %s 9center %s aÅ¡ies %s 9extern %s apylankos %s 9suburb %s sodų %s simutrans-124.3/simutrans/text/nl.tab000066400000000000000000001244211474050137200176710ustar00rootroot00000000000000Nederlands PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: nl Nederlands # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable uit cl_btn_filter_enable aan cl_btn_filter_settings Instellingen cl_btn_sort_asc oplopend cl_btn_sort_desc aflopend cl_btn_sort_id id-nummer cl_btn_sort_income Inkomsten cl_btn_sort_name Naam cl_btn_sort_type Type clf_btn_alle alles clf_btn_invers wissel clf_btn_keine geen Continue Game Speel verder gl_btn_sort_bonus naar bonus gl_btn_sort_name op naam gl_btn_sort_revenue op inkomsten gl_btn_unsort niet gesorteerd hl_btn_filter_disable uit hl_btn_filter_enable aan hl_btn_filter_settings Instellingen hl_btn_sort_asc oplopend hl_btn_sort_desc aflopend hl_btn_sort_name Naam hl_btn_sort_type Soort hl_btn_sort_waiting Wachtend hlf_btn_alle alles hlf_btn_invers wissel hlf_btn_keine geen Maximize height levels Meer hoogteverschillen Networks Transportnetwerk Queueing Wachtend Road toll Tol Scenario Scenario info Transfers Verwerkt #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic poolklimaat desert Woestijn mediterran mediterraans rocky Rotsachtig temperate Gematigd tropic Tropisch tundra Toendra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Scenario kan niet geladen worden! Can't buy obsolete vehicles! Verouderde voertuigen kunnen niet gekocht worden! Cannot alter water Je kan de waterstand van dit waterbekken niet aanpassen. Cannot built depot here! Hier kan geen depot gebouwd worden! Cannot built this station/building\nin underground mode here. Dit gebouw kan niet\nondergronds gebouwd worden.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Kies eerst een voertuig voor\nde nieuwe lijn! Cannot create socket Kan netwerk niet initialiseren! Convoi handles exhausted! Maximum aantal lijnen bereikt! Convoy already deleted! Convooi reeds verwijderd Das Feld gehoert\neinem anderen Spieler\n Deze grond \nis van een \nandere Speler!\n\n Der Besitzer erlaubt das Entfernen nicht De eigenaar laat\nverwijderen\nniet toe\n Diese Zusammenstellung kann nicht fahren!\n Deze voertuigsamenstelling \nkan niet rijden! Flugzeughalt muss auf\nRunway liegen!\n Vliegtuigen kunnen alleen\nop een luchthaven landen. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Dit luchthavengebouw \nkan hier niet gebouwd \nworden! Hier kann kein\nSignal aufge-\nstellt werden!\n Hier kan geen\nsein staan!\n In order to lock the game, you have to protect the public player by password! Om het spel te blokkeren moet de overheid beschermd worden met een wachtwoord Lost connection\nto server! Verbinding met server\nverbroken! Lost synchronisation\nwith server. Verbinding verbroken\nLaad het spel opnieuw!\n Maglevhalt muss auf\nMaglevschiene liegen!\n Maglev-halte moet op magneetbaan liggen. Monorailhalt muss auf\nMonorail liegen!\n Een monorail station moet \nop een monorailbaan\ngeplaatst worden! Monorails are not available yet! Monorails zijn nog niet beschikbaar! Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Smalspoorhalte moet op smalspoor liggen No suitable way on the ground! Haltes kunnen alleen op rechte\nvlakke wegen gebouwd worden No through station here! Hier is geen (doorrij) station mogelijk! Not enough clearance. Tussen twee wegen moeten minstens 2 hoogtes zijn. Not enough money! Onvoldoende saldo! On narrowgauge track only!\n Alleen op smalspoor!\n Only public player can lock games! Alleen de overheid kan spellen blokkeren Out of funds Je hebt daar niet genoeg geld voor! Post muss neben\nHaltestelle\nliegen!\n Een postkantoor of ander \ngebouw moet geplaatst worden\nop een vrij veld naast een \nstopplaats/station! Protocoll error (expecting game) Protocolfout Schiffhalt muss im\nWasser liegen!\n Een scheepsstop\nmoet op het water\nworden geplaatst\n Server busy Server bezet. Terraforming not possible\nhere in underground view Actie niet mogelijk ondergronds This tunnel branches. You can try Control+Click to remove. Deze tunnel heeft meer dan 2 ingangen. Je kan deze tunnel verwijderen met ctrl+klik. Upgrade must have\na higher level Upgraden alleen naar hoger niveau Vehicle %s cannot choose because stop too short! Voertuig %s heeft een te kort station in zijn dienstregeling! Zughalt muss auf\nSchiene liegen!\n Een treinstop\nmoet op rails\ngeplaatst worden\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Hulp

Hulp Index

Over Simutrans

%1$s

Hoe te bedienen

%2$s

Hoe een spel te starten

%4$s

Hoe te spelen

%5$s

Gereedschappen

%3$s

Andere vensters

%6$s Decrease water height Waterstand 1 verlagen Highlight railroad tracks Benadruk spoorwegen Highlite depots Benadruk depots Highlite electrical transmission lines Benadruk elektriciteitsnet Highlite factories Benadruk fabrieken Highlite forests Benadruk bossen Highlite tourist attraction Benadruk toeristenattracties Increase water height Waterstand 1 verhogen Open station/stop details Toon stationdetails Overlay city limits Benadruk stadsgrenzen Overlay passenger destinations when a town window is open Benadruk passagiers- en post-bestemmingen van de stad als deze in een open venster staat Overlay schedules/network Laat alle verbindingen zien op de kaart Overlay town names Toon stadsnamen Please click on the map to add\nwaypoints or stops to this\nschedule. Klik op de kaart om haltes en routepunten toe te voegen Set tile climate %s Verander het klimaat van deze tegel naar %s Show capacity and if halt is overcrowded Toon capaciteit en status van halte Show how many convoi reach a station Toon hoeveel voertuigen aangekomen zijn Show how many people/much is waiting at halts Toon aantal wachtende mensen en goederen Show initial passenger departure Toon de oorsprong van de passagiers en post. Show level of city buildings Toon niveaus van stadsgebouwen Show mail service coverage/mail network Toon het bereik van de post Show passenger coverage/passenger network Toon bereik van het passagiersnetwerk Show speedlimit of ways Toont de maximale snelheid van wegen Show the change of waiting at halts Toon de geschiedenis van de wachttijd Show the owenership of infrastructure Toon de eigenaar van de infrastructuur Show transported freight/freight network Toon goederentransport en verbindingen Show usage of network Toon de drukte van de wegen Shows a listing with all industries on the map. Geeft een lijst van alle fabrieken Sum of departure/arrivals at halts Toon het aantal aangekomen en vertrokken voertuigen #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n Toeristen kunnen nu\nde buslijn van %s\ntussen %s en\nbezienswaardigheid %s\nbij (%i,%i) gebruiken. %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n Arbeiders kunnen nu\nde buslijn van %s\ntussen %s en\nfabriek %s\nbij (%i,%i) gebruiken. %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s heeft nu %i vrachtwagens,\ndie tussen %s (%i,%i)\nen %s (%i,%i)\nrijden. %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s voltooit\nnieuwe spoorwegen tussen\n%s (%i,%i) en\n%s (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n %s heeft\neen Luchtverbinding tussen\n%s en\n%s geopend. Ferry service by\n%s\nnow between\n%s \nand %s.\n %s\nopening van een nieuwe bootlijn\ntussen\n%s en \n%s.\n\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nopent een nieuwe\nbusverbinding tussen\n%s en\n%s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Kaarteneditor LISTTOOLS Lijstenbeheer MAGLEVTOOLS Maglev MONORAILTOOLS Monorail/maglev werktuigen NARROWGAUGETOOLS Smalspoor RAILTOOLS Spoorwegen ROADTOOLS Autowegen SHIPTOOLS Scheepvaart SLOPETOOLS Land ophogen/verlagen SPECIALTOOLS Bijzondere werktuigen TRAMTOOLS Trams #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s's heeft een nieuw hoofdkantoor gebouwd. Factory chain extended\nfor %s near\n%s built with\n%i factories. Economie gaat goed\n voor %s bij %s zijn\n%i nieuwe fabrieken gebouwd. Net wealth less than 10%% of starting capital! Het nettovermogen bedraagt minder dan 10%% van het startkapitaal! New %s now available:\n%s\n %s '%s'\nis nu beschikbaar. New factory chain\nfor %s near\n%s built with\n%i factories. Er is een nieuwe productieketen\nvoor %s bij\n%s gebouwd,\nbestaande uit %i fabrieken. New vehicle now available:\n%s\n Nieuw voertuig is \nnu beschikbaar:\n\n» %s «\n Now %u clients connected. %i spelers verbonden. Remove vehicle from map. Use with care! Verwijder het voertuig direct. Screenshot\ngespeichert.\n Schermafdruk\nopgeslagen\n Sends the convoi to the last depot it departed from! Stuur het voertuig naar een nabijgelegen depot. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s heeft\neen nieuw monument\nopgericht. Dit wordt\ngevierd met festiviteiten.\n #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter lijn filter #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (in remise) \nBauzeit bis tot \nBauzeit von \ngebouwd vanaf \nCan't open heightfield file.\n \nKan hoogteveld niet openen.\n \ndirection: \nrichtingen: \nelektrified geëlektrificeerd \nHeightfield has wrong image type.\n \nHoogteveld heeft een onjuiste\nbestands opmaak.\n \nis reserved by: \nin gebruik door trein: \nminimum speed: \nminimumsnelheid: \nnot elektrified niet geëlektrificeerd \nRibi (masked) \nRichtingen (gemaskeerd) \nRibi (unmasked) \n\nrichtingen (alle): \nSet phases: \npas stoplicht aan NZ/OW: \nsingle way \neenrichtingsweg \nway1 reserved by Weg 1 gebruikt door\nWeg 1 gebruikt door \nway2 reserved by Weg 2 gebruikt door\nWeg 2 gebruikt door \nwith sign/signal\n \nmet bord/sein\n %d buildings\n %d Gebouwen\n %d convois %d voertuigen %d Einzelfahrzeuge im Depot %d voertuigen in het depot %i years %i months old. %i jaar en %i maanden oud. %s at (%i,%i) now public stop. %s is een publieke halte geworden. %s building %s %s %s %s %s %s city %d %s %s centrum %d %s %s factory %s %s %s %s fabriek %s has entered a depot. %s heeft een depot bereikt. %s land %d %s %s %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s heeft \neen nieuw stadhuis \ngebouwd toen de stad\n%i inwoners bereikte. %s\nis crowded. %s is overbelast. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nmaximale snelheid %3$i km/u\n\n\nhuidige snelheid %2$i km/u.\n\n %s\nwas liquidated. %s is bankroet gegaan\n. Het bedrijf is stilgelegd en alle bezittingen zijn verkocht. %u Client(s)\n %i spelers\n %u Player (%u locked)\n %u spelers (%u beveiligd)\n 1 convoi 1 voertuigsamenstelling 1 Einzelfahrzeug im Depot 1 voertuig in dit depot 1LIGHT_CHOOSE Helderheid: 1WORLD_CHOOSE Instellingen voor een nieuw spel: 2LIGHT_CHOOSE Contrast: 2WORLD_CHOOSE Kaartnummer: 3LIGHT_CHOOSE Scrollsnelheid: 4LIGHT_CHOOSE Scroll omdraaien 5LIGHT_CHOOSE voetgangers (halte) 5WORLD_CHOOSE Steden: 6LIGHT_CHOOSE voetgangers (stad) 6WORLD_CHOOSE Stadsverkeer: 8WORLD_CHOOSE Dag en Nacht Modus A bridge must start on a way! Een brug \nmoet op een weg beginnen! Abfrage Info Abnehmer Afnemer About Info About scenario Copyright Abriss Verwijder Absenken Verlagen Abspanntransformator Transformator Accelerate time Tijd versnellen Act. load: %u MW\n Verbruik: %u MW\n Active player only alleen actieve speler Add forest Bos aanplanten Add random citycar voeg willekeurige stadsauto toe add server Voeg server toe Add Stop Toevoegen Add stops for backward travel Toevoegen van de stops voor de terugweg air start/taxibaan aircraft_tab Vrachtvliegtuigen airplane vliegtuig Airport Luchthaven AIRTOOLS Luchtvaart \n All Alle all convoi tooltips alle tooltips voor voertuigen Allow city growth Stadsuitbreiding toestaan Allow player change Speleromschakeling toelaten allowed climates:\n Klimaatzones Alters a schedule. Dienstregeling wijzigen Angenommene Waren Vlakbij benodigde goederen anhaengen Toevoegen Anhaenger_tab Opleggers Anheben Ophogen Appends stops at the end of the schedule Stop toevoegen aan einde dienstregeling Apply Line Lijn toewijzen Arbeiter aus: Arbeiders uit: Arrivals from\n Aankomst van Arrived Aangekomen Assets Overige activa Aufloesen Opheffen Aufspanntransformator Transformator August Augustus Autohalt muss auf\nStrasse liegen!\n Een halte voor bussen of \nvrachtwagens moet op een \nweg geplaatst worden! Available Beschikbaar Bahndepot Depot Bankrott:\n\nDu bist bankrott.\n Bankroet:\n\nU bent falliet.\n battery batterij Baum Boom baum builder Plant bomen Baustelle Bouwplaats Bauzeit Bouwtijd Beenden Afsluiten Besonderes Gebaeude Bezienswaardigheid BF station bio biologisch Blockstrecke ist\nbelegt\n Andere trein op\ndit railblok\n Boden Land Bonusspeed: %i km/h Max. haalbare snelheid: %i km/h Boost (%%) verhoging met (%%) bridge is too high for its type! De brug is te hoog voor dit type! Bridge is too long for this type!\n Dit brugtype kan \nde overspanning niet halen!\n Bruecke Brug Bruecke muss an\neinfachem\nHang beginnen!\n Een brug moet op\neen rechte\nhelling beginnen!\n Brueckenboden brugdek Build air depot Bouw hangar build choosesignals Plaats keuzeseinen Build city market Bouw een nieuwe winkel in de dichtstbijzijnde stad Build drain Transformator build HQ Bouw Hoofdkantoor Build land consumer Bouw een nieuwe energiecentrale. Build maglev depot Bouw een Maglev depot Build monorail depot Bouw een monorail depot Build narrowgauge depot Bouw een smalspoor depot Build powerline Hoogspanningslijn Build presignals Plaats voorseinen Build road depot Bouw een garage Build ship depot Bouw een scheepswerf Build signals Plaats seinen Build train depot Bouw een trein depot Build tram depot Bouw een tram depot Build truck depot Bouw een garage Building costs estimates Geschatte bouwkosten Buildings gebouwen Built artifical slopes Kunstmatige glooiingen Built random attraction Nieuwe bezienswaardigheid Bus_tab Bussen Can only move from halt to halt or waypoint to waypoint. Kan alleen verplaatst worden \nvan halte naar halte of \nvan routepunt naar routepunt. Cancel Annuleren Cannot connect to offline server! Server is offline en niet bereikbaar. Capacity: Capaciteit Capacity: %.0f MW Capaciteit: %.0f MW\n Capacity: %d%s %s\n Capaciteit: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capaciteit: %s\n» %d (%d%%) Cars are not available yet! Voertuigen zijn nog niet beschikbaar! cars.\nstate Voertuigen\n Cash Kas Change player Van speler wisselen Chart Grafiek Chat_msg Chat Choose direction Richting kiezen Choose operation executed on clicking stored/new vehicles Kies een actie voor de opgeslagen/nieuwe voertuigen. chooses a random map Kiest een willekeurige kaart citicens Inwoners City attraction Toeristische attractie City industries Aantal industrieën (stad) City list Stedenlijst City size Aantal inwoners city_road stadsweg citybuilding builder Stadsgebouwen bouwen CityLimit Gemeentegrens cl_title Voertuigen lijst cl_txt_sort Sorteren op: Clear block reservation Blokreservering tonen/wissen clf_chk_aircrafts Vliegtuigen clf_chk_cars Wegverkeer clf_chk_indepot in een depot clf_chk_maglev Maglev banen clf_chk_monorail Monorail banen clf_chk_name_filter Filter namen: clf_chk_narrowgauge Smalspoorbanen clf_chk_noincome geen inkomen clf_chk_noline geen lijn clf_chk_noroute geen route clf_chk_noschedule geen dienstregeling clf_chk_obsolete Verouderd clf_chk_ships Schepen clf_chk_spezial_filter Speciaal filter: clf_chk_stucked geblokkeerd clf_chk_trains Treinen clf_chk_trams Trams clf_chk_type_filter Filter type: clf_chk_waren Filter goederen: clf_title Voertuigen Filter Climate Control Klimaatinstellingen closed gesloten COLOR_CHOOSE\n Kies een kleur\nuit de tabel:\n Company bankrupt Onderneming is failliet! Company_msg Concurrenten Comparing pak files ... Bezig met het vergelijken van pak-bestanden ... Configure AI AI-instellingen Configure AI setttings AI (computer tegenstander) instellingen aanpassen Congratulation\nScenario was complete in\n%i months %i years. Gefeliciteerd!\nHet scenario is gerealiseerd\nin \n%i maanden en %i jaren! Connected stops Aangesloten haltes Connected with server Verbonden met server Constructed by Gemaakt door Constructed by %s Gemaakt door %s construction speed Bouwsnelheid Construction_Btn Bouwkosten Consumed verbruikt convoi %d of %d Voertuig %d van %d convoi error tooltips tooltips voor voertuig fouten Convoi has been sent\nto the nearest depot\nof appropriate type.\n Dit voertuig is naar een\nnabijgelegen depot gestuurd.\n Convoi is sold when all wagons are empty. Het voertuig of de samenstelling wordt verkocht zodra het helemaal leeg is. convoi mouseover tooltips convooi mouseover tooltips convoi passed last\nmonth %i\n Verkeer in de \nvoorafgegane maand: %i\n Convois Voertuigen Convois: %d\nProfit: %s Voertuigen: %d\nWinst: %s Convoys Voertuigen Copy Convoi Kopiëren Copy the selected convoi and its schedule or line Kopieer dit voertuig inclusief dienstregeling of lijn cost for removal Kosten voor verwijdering Cost: %8s (%.2f$/km %.2f$/m)\n Kosten: %s (%.2f$/km, %.2f$/m)\n Cost: %8s (%.2f$/km)\n Kosten: %8s (%.2f$/km)\n Costs Kosten Create a new line based on this schedule Maak van deze dienstregeling een nieuwe lijn curiosity builder Attractie bouwen curlist_title Bezienswaardigheden Currently playing: Momenteel spelend: Customers live in: Klanten wonen in: deactivated in online mode Niet actief in online modus Deccelerate time Tijd vertragen decrease underground view level lager ondergronds niveau Del Stop Verwijderen Delete Line Lijn opheffen Delete the current stop Verwijder halte Delete the selected line (if without associated convois). Verwijder de geselecteerde lijn (mits zonder konvooien) Delete this file. Dit bestand verwijderen Delivered Geleverd Demand Vraag: Demand: %.0f MW Vraag: %.0f MW\n Denkmal Monument Departed Vertrokken Departure board Vertrektijden Departures to\n Gaat naar\n Der Tunnel ist nicht frei!\n De tunnel is niet vrij!\n Destination Bestemming Destroying map ... Oude kaart wordt ontruimd ... Die Bruecke ist nicht frei!\n De brug is niet leeg!\n directmail Direct Mail Direkt erreichbare Haltestellen Direct bereikbare stopplaatsen disable midi Midi-muziek uitschakelen Display settings Beeldscherm instellingen Distance Afstand Dock haven Dock must be built on single slope! Een haven moet op een enkelvoudige helling gebouwd worden! Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Je hebt %d maanden om je schulden af te lossen! Durchsatz Capaciteit Economy Economie en steden Eigenbesitz\n Openbaar bezit\n Ein %s\npasst hier nicht.\n Hier past geen\n%s.\n Einstellungen aendern Instellingen aanpassen electric elektrisch Electricity Stroom Electricity producer\n\n Energiecentrale \n\n Electrics_tab Elektrisch Electrify track Bovenleidingen enlarge map Vergroot kaartafmetingen enter a value between %i and %i Geef een waarde tussen %i en %i Enter address Serveradres Enter Password Naam en wachtwoord van speler wijzigen Error Fout Erzeuge neue Karte.\n Een ogenblik geduld,\neen nieuwe kaart\nwordt gemaakt ...\n\n(Bij een grote\nkaart kan dit even\nduren)\n Es wird bereits\nein Fahrplan\neingegeben\n Er wordt al\neen dienstregeling\ngemaakt.\nMaak deze eerst af!\n Fabrikanschluss Aangesloten industrie Fabrikname Fabrieksnaam Factories Fabrieken factory details Fabrieks details factorybuilder Fabrieken bouwen Fahrplan Dienstregeling Fahrtziel Bestemming: Fahrzeuge koennen so nicht entfernt werden Voertuigen kunnen\nzo niet verwijderd\nworden\n Fahrzeuge: Voertuigen: Farbe Kleur Fast forward Snel voorwaarts in tijd February Februari Ferry_tab Veerboten Fertig Klaar Filename Bestand: Files from: Bestanden uit: Finances of %s Financiën van %s Finanzen Financiën find mismatch Vergelijk je pak fl_title Lijst met fabrieken Flug_tab Passagier-vliegtuigen follow me volgen Follow the convoi on the map. Volg het voertuig op de kaart. Forest Bos Found new city Nieuwe Stad Fracht Vracht Frame time: Beeldfrequentie: Free Capacity Vrije capaciteit freeplay mode Freeplay, nooit bankroet Friction: Frictie: fuel_cell brandstofcel Full load Laden t/m Fundament Fundering Fussgaenger Voetgangers Game info Online multiplayer GAME PAUSED SPEL GEPAUZEERD Game_msg Algemeen Gear: Overbrenging: Gebaeude Gebouw General Algemeen Generated Gegenereerd Generation: %.0f MW Generatie: %.0f MW\n Gewinn Inkomsten Give the selected vehicle(s) an individual schedule Ken het geselecteerde voertuig een eigen dienstregeling toe gl_btn_sort_catg op categorie gl_title Goederenlijst go home naar depot Goods Goederen Goods AI Vracht-AI Goods list Goederenlijst Gross Profit Cash flow Groundobj Object Grow city Stad vergroten Growth Groei H bushalte Happy Tevreden Haus kaufen koop huis Helligk. Scherm Help Hulp Help text not found Hulp tekst niet gevonden. hide all building verberg alle gebouwen hide city building Verberg stadsgebouwen hide objects under cursor Verberg objecten onder de cursor. hide station names Verberg stationsnamen hide transparent Verberg objecten transparant hide trees Verberg bomen Hier warten/lagern: Wachtende passagiers/goederen: Higher transport fees, crossconnect all factories Voor meer winsten op transport, deactiveer Just-in-time. Highlite schedule Benadruk haltes dienstregeling hl_title Stations lijst hl_txt_filter Filter: hl_txt_sort Gesorteerd op: hlf_chk_airport Luchthaven hlf_chk_anleger Haven hlf_chk_bahnhof Station hlf_chk_bushalt Bushalte hlf_chk_frachthof Laadperron hlf_chk_keine_verb Geen verbinding hlf_chk_maglevstop Maglev station hlf_chk_monorailstop monorail halte hlf_chk_name_filter Filter namen: hlf_chk_narrowgaugestop Smalspoorstation hlf_chk_overflow overbeladen hlf_chk_spezial_filter Speciaal filter: hlf_chk_tramstop Tramhalte hlf_chk_type_filter Filter soort: hlf_chk_waren_abgabe Capaciteit: hlf_chk_waren_annahme Verbruik: hlf_title Station Filter Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depot niet gevonden!\nKies zelf een depot \n(met de dienstregeling). Homeless Dakloos hydrogene Waterstof Idle: Werkloos: ignore climates Negeer klimaatzones In the industry legend show only currently existing factories Toon enkel de gebruikte fabrieken In Transit Onderweg Increase Industry density Verhoog industriedichtheid increase underground view level hoger ondergronds niveau industrial building Fabrieksgebouw Init map ... Kaart inrichten... Input input Ins Stop Invoegen Insert stop before the current stop Stop invoegen voor de huidige Intercity road len: Lengte provinciale wegen Intro. date: Geïntroduceerd: invalid ongeldig Invalid coordinate Ongeldige coördinaat isometric map isometrische kaart January Januari join game Online spelen July Juli Jump to Ga naar June Juni Kann Spielstand\nnicht laden.\n Kan opgeslagen spelstand\nniet vinden/laden\n Kann Spielstand\nnicht speichern.\n Kan spelstand\nniet opslaan\n Kein Besitzer\n Geen eigenaar keine geen Keine Einzelfahrzeuge im Depot Het depot is leeg Keyboard_Help\n Toetsenbord help\n koord coördinaten Kreuzung Kruising labellist_title Label lijst Lade Relief Laad Hoogtekaart Land attraction Bezienswaardigheid Land industries Aantal industrieën (land) LANG_CHOOSE\n Maak de keuze uit\nde volgende talen:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Vorige maand: Last used tools Laatst gebruikte werktuigen Last Year Afgelopen Jaar Leaving depot! Verlaat depot! leer leeg Legend Legenda Leistung Vermogen Leistung: %d kW Vermogen: %d kW Leitung Hoogspanningsleiding letzen Monat: diesen Monat: Afgelopen maand: Deze maand: Line Lijn Line Management Lijnenbeheer Lineless convoys serving this stop Niet aan lijn gebonden voertuigen die hier stoppen: Lines serving this stop Aangesloten lijnen LKW_tab Vrachtverkeer Load game Spel laden load height data from file Bestand met reliëfinformatie laden Load scenario Laad scenario loaded geladen. loaded passenger/freight Sorteer passagiers/vracht op Loading (%i->%i%%)! Laden van (%i->%i%%) Loading addon paks ... Addon paks laden ... Loading map ... Bezig met het laden van de kaart... Loading paks ... Paks laden ... Loading skins ... Skins laden ... Lock game Blokkeer speleromschakeling. Lokomotive_tab Locomotieven m3 m³ Maglev Magneetbaan maglev vehicle Magneetbaanvoertuig maglev_track Maglev baan Maglevdepot Maglev depot Mail Demand %d\n Vraag naar post %d\n Mailbox Berichten Mailbox Options Berichtencentrum en opties Maintenance Onderhoud make stop public (or join with public stop next) costs %i per tile and level maak halte openbaar of verbind met openbare halte (%i$ per veld en niveau) Manual (Human) Mens Manufactured: Geproduceerd: Map roughness Ruigheid: map zoom Inzoomen March Maart Margin (%%) Marge (%%) Marker InfoBordje max max. Max Boost (%%) Maximale verhoging Max income: Max. inkomsten: Max. speed: Max. snelheid: Maximum 254 stops\nin a schedule!\n Niet meer dan 254 haltes\nin één dienstregeling!\n maximum length of rivers Maximale rivierlengte Maximum tile height difference reached. Het maximale hoogteverschil\ntussen twee grondvlakken \nis bereikt. Maxspeed Maximum snelheid May Mei Median Citizen per town Gem. aantal inwoners Meldung Melding Menge Hoeveelheid MessageOptionsText \nNieuw Jaar\n\nAI Nieuws\n\nStadnieuws\n\nGeen Route\n\nNieuwe industrie\n\nChat\n\nNieuwe Voertuigen\n\nStation overbeladen\n\nProblemen\n\nFiles\n\nScenario min min. minimum length of rivers Minimum rivierlengte Missing pakfiles Er ontbreken objecten! Modify the selected line Gekozen lijn veranderen Monate alt maanden oud Monorail monorail monorail vehicle Monorail voertuig monorail_track Monorail baan Monorailboden monorailfundering Monoraildepot monoraildepot month wait time wachttijd in maanden Months Maanden Monuments Monumenten Mountain height Berghoogte Movingobj Verschuiven Music playing disabled/not available Muziek uitgeschakeld/niet beschikbaar Music volume: Muziek volume: mute sound geluid uitschakelen Name Naam Narrowgauge Smalspoor Narrowgauge are not available yet! Smalspoor nog niet beschikbaar! narrowgauge vehicle Smalspoor voertuig narrowgauge_track Smalspoor Narrowgaugedepot Smalspoor depot Net ID: %p Net ID: %p\n Net Wealth Totale activa Net wealth near zero Er dreigt een negatief vermogen Neue Karte Nieuwe kaart Neue Welt Nieuwe wereld new convoi Nieuw voertuig New Line Nieuwe lijn New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nieuwe lijn gecreëerd!\nJe kunt de lijn nu toewijzen\ndoor deze te kiezen uit\nde lijnen hierboven. New Vehicles Nieuwe voertuigen no buildings hidden geen verborgen gebouwen no convois geen voertuigsamenstellingen No goods are loaded onto this convoi. Het voertuig accepteert geen nieuwe lading. no goods waiting geen wachtende goederen no load Alleen lossen No Route Geen route No stop here! Dit kan alleen voor haltes! No suitable ground! Geen geschikt terrein! No terminal station here! Hier is geen eindstation mogelijk! no timeline Geen tijdlijn no tree zonder bomen No. of Factories Fabrieken en winkels Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Voertuig heeft\n een dienstregeling\nnodig voordat het\nkan vertrekken!\n none Geen nord Noord nordost Noord-Oost nordwest Noord-West Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Niet mogelijk!\nDe dienstregeling kan \nnu niet veranderd \nworden.\nProbeer later. Not enough fields would remain. Onvoldoende vrije velden. Now active as %s.\n Je bent nu actief \nals speler %s. Number of rivers Aantal rivieren Odometer: %s km Kilometerstand: %s Ok OK On loan since %i month(s) U heeft schulden sinds %i maand(en) On this map, you are not\nallowed to change player!\n Spelerswissel is niet mogelijk in dit spel.\nSpelerswissel is uitgeschakeld!\n Only city chains Alleen stadsfabrieken Only first %d differing paks reported. There are probably more. Enkel de eerste paks die verschillen zijn aangegeven. Waarschijnlijk zijn er nog meer. Only land chains Alleen plattelandsfabrieken Only one transformer per factory! Slecht één transformator per fabriek Only show goods which are currently handled by factories Toon enkel de goederen die momenteel verwerkt kunnen worden Operation Exploitatiekosten Ops Profit Resultaat Optionen Instellingen Or enter a server manually: Of voer manueel het serveradres in: Origin Herkomst ost Oost Output Productie Ownership Eigenaar Pak which may cause severe errors: De volgende ontbrekende objecten kunnen problemen veroorzaken in transportnetwerken: Pak which may cause visual errors: De volgende objecten werden vervangen door gelijkaardige objecten: Pak(s) different: Afwijkende objecten: Pak(s) missing on client: ontbrekende objecten: Pak(s) not on server: Deze paks doen niet mee: Pakset differences Verschillen in paksets: paletten Kisten Pas_tab Passagiertreinen Passagiere Passagiers Passagierrate Passagiersaanbod Passagierziele Passagiers/postbestemmingen Passenger AI Passagiers AI Passenger Demand %d\n Vraag naar passagiers: %d\n Passengers %d %c, %d %c, %d no route Passagiers %d %c, %d %c, %d zonder route Passengers %d %s, %d %s, %d no route Passagiers %d %s, %d %s, %d zonder route Password Wachtwoord: Pause Pauze Pax <%i> Mail <%i> Passagiers <%i> Post <%i> PaxDest Bestemmingen Percent Electricity Stroomproductie (%% vraag) Planes are not available yet! Vliegtuigen zijn nog niet\nbeschikbaar! Plant tree Plant een boom player speler player -1 Mens player 0 Overheid player 1 Napik 128 AS player 10 speler 10 player 11 speler 11 player 12 speler 12 player 13 speler 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans b.v. player 6 PSK & Co KG player 7 speler 7 player 8 speler 8 player 9 speler 9 Please choose vehicles first\n Selecteer eerst een voertuig!\n Post post Postrate Postaanbod Power Stroom Power (MW) Vermogen (MW) Power: Vermogen: Power: %4d kW\n Vermogen: %4d kW\n Powerlines HSP-leidingen Problems_msg Waarschuwingen Produced Geproduceerd Production of %s has been stopped:\n%s\n %s '%s'\nword niet meer geproduceerd. Production/Boost Productie/boost Produktion Produktie Profit Winst promote to line Maak nieuwe lijn q1 Lente q2 Zomer q3 Herfst q4 Winter Query server Server opvragen rail car spoorwagen random willekeurig Random age willekeurig jaar Random map Willekeurige kaart Rathaus Stadhuis Rating Beoordeling ratio_pax Verhouding Relevant Alleen benodigde Reliefkarte Kaart Remove Verwijder remove airstrips landingsbaan verwijderen remove channels kanaal verwijderen remove interm. signals verwijder tussenliggende signalen remove maglev tracks verwijder maglevbaan remove monorails monorail verwijderen remove narrowgauge tracks smalspoor verwijderen remove powerlines Verwijder HSP-leidingen remove roads weg verwijderen remove tracks spoorbaan verwijderen Remove wayobj %s Verwijder wayobj %s replace other signals Vervang andere signalen replace stop vervang halte request closing verzoek sluiten residential house woonhuis Restore natural slope Herstel natuurlijke glooiing Restwert: Verkoop waarde: Retire. date: Gebouwd tot: return ticket Retourtraject Revenue Inkomsten Revision: Revisie: road weg road vehicle Wegvoertuig Roadsign verkeersbord Rotate map Kaart draaien Rotation Draaiing Routing Verbindingen sack zakken sail Wind Saving map ... Bezig met het opslaan van de kaart... Scenario complete: %i%% doel voor %i%% bereikt Scenario Debug Debug Scenario Goal Doel Scenario information Details Scenario Result Voortgang Scenario Rules Regels Schedule changing! Wijziging in dienstregeling! Schienentunnel Spoorwegtunnel bouwen Schiff_tab Schepen Schiffdepot Scheepswerf Schleppkahn_tab Sleepboot Screenshot Schermafdruk Seasons Seizoenen Sehenswuerdigkeit Bezienswaardigheid Select a server to join: Kies een server Select a theme for display Verander het thema Sell the selected vehicle(s) Verkoop de gekozen voertuigen. sended verstuurd SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Server did not respond! Server reageert niet Serves Line: Bedient lijn: set signal spacing Set afstand tussen signalen Setting Instellingen Ship Schip shops and stores Winkels en magazijnen Show all Toon alles show all building Toon alle gebouwen Show also vehicles no longer in production. Toon ook voertuigen die niet meer vervaardigd worden. Show also vehicles that do not match for current action. Toon ook voertuigen die niet passen bij de reeds geselecteerde voertuigen. Show even servers with wrong version or pakset Toon ook servers met verkeerde programmaversie of verkeerde pakset show grid Toon raster Show industry Toon industrie Show legend Toon legenda Show map scale Toon schaal Show mismatched Toon foute combinaties Show obsolete Verouderde tonen Show offline Toon offline servers Show only used Toon enkel gebruikte Show schedules toon dienstregelingen Show servers that are offline Toon offline servers Show servers where game version or pakset does not match your client Toon servers die niet overeenkomen met jouw versie of pakset show station coverage toon stations dekking show station names toon stationsnamen show waiting bars toon waiting bars show/hide block reservations Toon/verberg blokreservering Show/hide estimated arrival times Toon/verberg de geschatte aankomsttijden show/hide object owner Toon/verberg eigenaar Show/hide statistics Toon/verberg statistieken Shows buttons on special topics. Toon interactieve kaart Shows consumer/suppliers for factories Toon afnemers/leveranciers voor fabrieken Shows the color code for several selections. Toon de kleurcode bij de selecties Shows the currently selected schedule Toon de gekozen dienstregeling Shrink city Stad verkleinen shuffle midis shufflemode voor achtergrondmuziek Signal Sein signal spacing Signaal afstand Sim: Simloops: Similar view as the main window Zelfde oriëntatie als het hoofdscherm Size (%d MB): Omvang (%d MB): sliced underground mode "sliced" ondergrondse modus slot empty vrij Smart hide objects Verberg objecten rond de cursor Sort by Gesorteerd op Sort waiting list by Sorteer wachtenden op Sound Geluid Sound settings Geluidsinstellingen Sound volume: Geluidssterkte special freight Speciale vracht Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Snelheidsbonus\nstraat %i km/h, treinen %i km/h\nschepen %i km/h, vliegtuigen %i km/h.\n Speedlimit Max. snelheid Speichern Opslaan Spieler Speler Spieler(mz) Spelers Spielerliste Lijst met spelers Spielstand wurde\ngeladen!\n \nSpelstand is\ngeladen\n Spielstand wurde\ngespeichert!\n \nSpelstand is\nopgeslagen\n Sprache Taal Sprachen Talen Stadtinformation Stadsinformatie Start Starten Start the selected vehicle(s) Start het gekozen voertuig. Starte Spiel Start Spel Station tiles: min. stationslengte: Station_msg Overbezettingen Status Haltestatus steam Stoom Step timeline one year Een jaar naar voren springen Stops Haltes Storage voorraad Storage capacity Opslagcapaciteit Strassendepot Garage Strassentunnel Tunnel bouwen street car Wagen sued Zuid suedost Zuid-Oost suedwest Zuid-West Summer snowline Sneeuwgrens(z): Supplied: %.0f %% Geleverd: %.0f %% Suppliers Leveranciers Tage alt dagen oud Theme selector Thema selectie There are still vehicles\nstored in this depot!\n Er zijn nog\nvoertuigen in\ndit depot!\n This Month Deze maand This Year Dit jaar Tile not empty. Het veld is niet leeg! timeline Tijdlijn tl_title Lijst met steden To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %s bouwt\neen %s,\nom meer toeristen aan te trekken. To heavy traffic\nresults in traffic jam.\n Te druk verkeer veroorzaakt\nopstoppingen. Toggle day/night view dag/nacht schakelen Toggle vehicle tooltips Voertuig info omschakelen tonnen t Total inhabitants: Aantal inwoners Tourist attractions Bezienswaardigheden Tourists Toerisme Town_msg Nieuwe bestemmingen Town: %s\n Stad: %s\n Towns Stadsnamen track spoor Tracks Spoorwegen Traffic Verkeer Train Trein Trains are not available yet! Treinen zijn nog niet beschikbaar! tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tram %i km/h, monorail %i km/h\nmagneetbaan %i km/h, smalspoor %i km/h. tram_track tramrails Tramdepot Tramremise Trams are not available yet! Trams zijn nog niet beschikbaar! Transferring game ... Spel wordt overgehaald ... Transformer only next to factory! Een transformatorstation moet direct naast de fabriek geplaatst worden! Translation Vertaling transparent station coverage transparante stations dekking Transported Vervoerd TrolleyBus_tab Trolleybussen Truck Vrachtwagen tt_Other Andere Tunnel muss an\neinfachem\nHang beginnen!\n Een tunnel moet op\neen rechte\nhelling beginnen\n Tunnel must start on single way! Een tunnel moet op het einde van een straat beginnen! Tunnelboden Tunnelbodem underground mode ondergrondse mode UNDO failed! Ongedaan maken is niet meer mogelijk.\nJe kunt alleen de bouw van een weg\nongedaan maken zo lang je geen\nstations/haltes/seinen/borden/... \nhebt geplaatst op de weg. Undo last ways construction Maak laatste wegconstructie ongedaan Unemployed Werkeloos Unhappy Ontevreden units/day eenh./dag Update Line Lijn veranderen upgrade HQ Hoofdkwartier uitbreiden Usage: %.0f %% Gebruik: %.0f %% Usage/Output Verbruik/productie Use beginner mode Activeer beginnermode Use timeline start year Tijdlijn/Aanvangsjaar Vehicle %s can't find a route! Voertuig %s \nkan geen route vinden! Vehicle %s is stucked! Voertuig %s\nis geblokkeerd. Vehicle details Voertuigdetails Verbrauch Verbruik Vergroessere die Karte\n Vergroot kaart Verkauf Verkopen! verkaufen Verkopen Verkehrsteilnehmer Weggebruiker Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n U heeft schulden!\n\nU heeft %d maanden\nom uw schulden af\n te lossen!\n via %s\n via %s\n via Menge Aantal-via voranstellen Invoegen Waggon_tab Wagons waiting wachtend Waiting for clearance! Wacht op voorligger Walked Te voet walking Te voet Warnings_msg Verkeersmededelingen Wasser Water Water Kanaal Water level Waterpeil: water vehicle Watervoertuig way %s cannot longer used:\n %s kan niet langer worden gebruikt:\n way %s cannot longer used:\n%s\n %s kan niet langer worden gebruikt:\n%s\n way %s now available:\n %s is nu beschikbaar.\n Way toll Tol Ways not connected Wegen niet aangesloten Wegpunkt Routepunt Weight: Gewicht: Wert Waarde west West Winter snowline Sneeuwgrens(w): withdraw Terugtrekken Withdraw All Alles terugtrekken WRONGSAVE Opgeslagen spelversie\nniet compatibel. Bestand kan\nniet geladen worden.\n Year %i has started. Het jaar %i is begonnen. Years Jaren Your primary color: Eerste kleur Your secondary color: Tweede kleur Zielort Bestemming zooming in inzoomen zooming out uitzoomen Zu nah am Kartenrand Er kan hier niet\ngebouwd worden!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nieuw wereldrecord voor\nmaglevs: %.1f km/h\nby %s. New world record for monorails: %.1f km/h by %s. Nieuw wereldrecord voor\nmonorails: %.1f km/h\nby %s. New world record for motorcars: %.1f km/h by %s. Nieuw wereldrecord voor\nmotorvoertuigen:\n %.1f km/h\nby %s. New world record for narrowgauges: %.1f km/h by %s. Nieuw wereldrecord voor\nsmalspoor: %.1f km/h\nby %s. New world record for planes: %.1f km/h by %s. Nieuw wereldrecord voor\nvliegtuigen: %.1f km/h\nby %s. New world record for railways: %.1f km/h by %s. Nieuw wereldrecord voor\nspoorwegen: %.1f km/\nby %s. New world record for ship: %.1f km/h by %s. Nieuw wereldrecord voor\nschepen: %.1f km/h\nby %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL dam &2_CITY_SYLL sum &3_CITY_SYLL hoven &4_CITY_SYLL tricht &5_CITY_SYLL drecht &6_CITY_SYLL hage &7_CITY_SYLL ham &8_CITY_SYLL mare &9_CITY_SYLL dijk &A_CITY_SYLL huizen &B_CITY_SYLL sel &C_CITY_SYLL burg &D_CITY_SYLL stad &E_CITY_SYLL bron %0_CITY_SYLL woud %1_CITY_SYLL Amster %2_CITY_SYLL Rotter %3_CITY_SYLL Hilver %4_CITY_SYLL Veen %5_CITY_SYLL Eind %6_CITY_SYLL Maas %7_CITY_SYLL Rijn %8_CITY_SYLL Nieuw %9_CITY_SYLL Delf %A_CITY_SYLL Oud %B_CITY_SYLL Volen %C_CITY_SYLL nieuw %D_CITY_SYLL top %F_CITY_SYLL park 1center %s %s 1extern %s buiten %s 1suburb %s %s %s 2center %s centraal %s 2extern %s extern %s 2suburb %s Velden %s %s 3center %s centrum %s 3extern %s land %s 3suburb %s dorp %s %s 4center %s binnen %s 4extern %s veld %s 4suburb %s Kolonie %s %s 5center %s brink %s 5extern %s Weidegrond %s 5suburb Ontwikkelingsgebied %s %s %s 6center %s Centraal %s 6extern %s Industrieterrein %s 7center %s Stad %s simutrans-124.3/simutrans/text/nl/000077500000000000000000000000001474050137200171755ustar00rootroot00000000000000simutrans-124.3/simutrans/text/nl/airtools.txt000066400000000000000000000142301474050137200215720ustar00rootroot00000000000000Luchtvaart Tools Help (Nederlands)

Luchtvaart Tools

Luchtvaart Tools bevatten tools om een luchtvaart infrastructuur te bouwen . Deze tools kunnen de volgende onderdelen bouwen of slopen: taxibanen en start- en landingsbanen voor vliegtuigen, pieren (gebruikt om passagiers en vracht te laden en te lossen), hangars (voor het beheren en kopen van vliegtuigen) en nog andere luchtvaart gebouwen. Indien de tijdlijn is geactiveerd in het spel, zal naar mate de tijd vordert in Simutrans het aantal beschikbare keuzes aan verandering onderhevig zijn.

Klik op het vliegtuig icoon bovenin het scherm om het menu te openen
Beweeg de muis aanwijzer over de beschikbare keuzes in het menu (het menu dient wel geactiveerd te zijn, anders even ergens in het menu klikken) om de naam en waar van toepassing: constructiekosten, onderhoudskosten tussen haken, en de snelheidslimiet.

{TIP: Een manier om een eenvoudige luchthaven te bouwen is:
i) leg taxiba(a)n(en) en start/landingsbanen aan en verbindt deze met elkaar;
ii) plaats een of meer pieren aan het einde van de taxiba(a)n(en);
iii) voeg overige luchthaven gebouwen toe indien nodig.}

In het menu kunnen de volgende tools voorkomen, van links naar rechts:

Taxibaan: cre-eert een taxibaan voor het verbinden van de pier met de start- en/of landingsbaan. Taxibanen dienen op een horizontale ondergrond te worden geplaatst.
LET OP: Als taxibanen aangesloten zijn op het begin of het einde van een start- en landingsbaan kan het voorkomen dat vliegtuigen niet kunnen stijgen of landen.

Hoe een taxibaan te bouwen: klik op de toolbar (het menu met iconen voor Luchtvaart) op het taxibaan icoon (verandert de cursor in een afbeelding van een taxibaan), klik op het terrein voor de beginpositie (cursor verandert in een bulldozer en laat de co-ordinaten zien rechtsonder op het scherm), en klik tot slot op het terrein voor het eindpunt van de taxibaan.

{TIP: Gebruik de verwijder functie om individuele stukken taxibaan te verwijderen. De undo functie [z] geeft het ge-investeerde bedrag niet terug.}

Start- en landingsbaan: cre-eert een start- (en landingsbaan) welke door vliegtuigen worden gebruikt om te stijgen en te landen. Startbanen worden gebouwd op horizontaal terrein en mogen elkaar kruisen.
Hoe een startbaan te bouwen: klik op de toolbar (het menu met iconen voor Luchtvaart) op het start- en landingsbaan icoon (verandert de cursor in een afbeelding van een start- en landingsbaan), klik op het terrein voor de beginpositie (cursor verandert in een bulldozer en laat de co-ordinaten zien rechtsonder op het scherm), en klik tot slot op het terrein voor het eindpunt van de start- en landingsbaan.

{TIP: Houdt het begin en einde van start- en landingsbanen vrij van connecties omdat het anders kan voorkomen dat vliegtuigen niet willen stijgen of landen. Gebruik de verwijder functie om individuele stukken start- en landingsbaan te verwijderen. De undo functie [z] geeft het ge-investeerde bedrag niet terug.}

Verwijder (start/landings/taxi)banen: verwijdert aaneengesloten delen van een taxibaan of start- en landingsbaan, als er zich geen vliegtuigen bevinden tussen het begin en het einde van de te verwijderen baan. Het gebruik van deze tool brengt constructiekostenmet zich mee.

Hoe een baan te verwijderen: klik op de toolbar (het menu met iconen voor Luchtvaart) op het rode kruis icoon (verandert de cursor in een afbeelding van een rood kruis), klik op het terrein voor de beginpositie (laat de co-ordinaten zien rechtsonder op het scherm), en klik tot slot op het terrein voor het eindpunt van de start- en landingsbaan.

{TIP: Houdt het begin en einde van start- en landingsbanen vrij van connecties omdat het anders kan voorkomen dat vliegtuigen niet willen stijgen of landen. Gebruik de verwijder functie om individuele stukken start- en landingsbaan te verwijderen.}

Hangar (Depot): bouwt een hangar om vliegtuigen te kopen en te beheren. Hangars hebben onderhoudskosten en worden gebouwd op een uiteinde van een taxibaan.
Om een hangar te bouwen (verandert de cursor in een hangar) en klik op een uiteinde van een taxibaan.

{TIP: Verwijder hangars met de verwijder tool.}

Pier: noodzakelijk om het in- en uitladen van passagiers en vracht mogelijk te maken.
Wanneer een pier niet in de buurt van een bestaand station of halte wordt gebouwd zal er een nieuw station worden gebouwd.
Een pier wordt op het einde van een stuk taxibaan geplaatst; een pier heeft onderhoudskosten en kan passagiers, post en vracht herbergen. Een vliegtuig zal alleen landen wanneer er een pier beschikbaar is voor laden en lossen.
Hoe een pier te plaatsen: klik op de toolbar (het menu met iconen voor Luchtvaart) op het pier icoon en klik vervolgens op een uiteinde van de taxibaan op het terrein.

{TIP: Verwijder pieren met de verwijder tool. Druk op [v] om het dekkingsgebied van een pier te tonen of te verbergen.}

Luchthaven gebouwen: bouwt uitbreidingen voor de luchthaven (station of halte)> die de capaciteit voor passagiers, post en vracht kunnen vergroten, het dekkingsgebied van het vliegveld kunnen vergroten maar ook onderhoudskosten kunnen verhogen. Indien er in de bovenhoek van de te kiezen uitbreiding een icoontje staat (ook gebruikt in stationslijst en stations en halte details) geeft dat aan welke capaciteit wordt uitgebreid.
Hoe een uitbreiding te plaatsen: klik op de toolbar (het menu met iconen voor Luchtvaart) op het rode kruis icoon (verandert de cursor in een afbeelding van de gekozen uitbreiding), en plaats deze naast een pier/station/halte. De nieuwe uitbreiding wordt nu geacht bij de pier/station/halte te horen.

{TIP: Verwijder uitbreidingen met de verwijder tool. Druk op [v] om het dekkingsgebied van een pier/station/halte te tonen of te verbergen.}

simutrans-124.3/simutrans/text/nl/citylist_filter.txt000066400000000000000000000036611474050137200231550ustar00rootroot00000000000000Lijst met steden

Lijst met steden

Lijst met steden toont details over dorpen en steden en inwoners.

Hoe te openen: klik op het Lijst met steden icoon in Lijstenbeheer of druk op toets [T].
Lijst met steden heeft twee knoppen die de volgorde bepalen waarop de dorpen en steden (en de inwoners) worden getoond.
{TIP: Als de items in de lijst slechts gedeeltelijk zichtbaar zijn, dan kun je het scherm vergroten Lijst met steden of door de lijst "scrollen" door middel van de scroll-bar.}

Totaal inwoners: is het totaal aantal bewoners in het spel (het totaal van de inwoners van alle dorpen en steden). De recente groei van de bevolking wordt getoond tussen haakjes.

Gesorteerd op: bepaalt de sortering van de lijst.
Klik meerdere malen op de knop om door de beschikbare sorteringen te bladeren (naam van de knop wijzigt ook):

- Naam toont de alfanumerieke lijst op de ASCII-code volgorde (hoofdletters gaan voor kleine letters) op de toegekende namen.
- Inwoners sorteert op het aantal inwoners.
- Groei sorteert op de mate van groei van een dorp of stad (welke afhankelijk is van de grootte van het dorp of stad het aantal reizigers).

- oplopend / aflopend draait de volgorde van de lijst om.

Klik op een dorp of stad in de Lijst met stedenom meer stadsinformatie over de beteffende plaats te zien.
Voor elke plaats wordt het volgende getoond:

Toegewezen naam van het gebied (kan worden gewijzigd in stadsinformatie scherm)..

aantal inwoners van het gebied, tussen haakjes staat de recente groei van de bevolking.

simutrans-124.3/simutrans/text/nl/citywindow.txt000066400000000000000000000105101474050137200221330ustar00rootroot00000000000000Stadsinformatie Help (Nederlands)

Stadsinformatie

Stadsinformatie toont statistieken over het geselecteerde dorp of stad en biedt de mogelijkheid de naam van de betreffende plaats te wijzigen.

Elk dorp of stad heeft een eigen stadhuis en zal groeien in de buurt van dat stadhuis. Transport van passagiers en post helpt om het dorp of de stad te laten groeien en dat heeft de volgende kenmerken: door de speler aangelegde wegen worden overgenomen door de overheidr; nieuwe gebouwen en industrie verschijnen op de kaart; en de grenzen van de stad worden uitgebreid.

Klik op het stadhuis met de info tool of op de naam van het dorp of de stad in lijst met steden om het scherm met stadsinformatiete bekijken, waarop het volgende is te zien: een vak met een naam; statistieken; twee kleine kaarten; en een grafiek voor de geselecteerde plaats.

naam: toegekende naam van de plaats verschijnt in het naam vak bovenin het scherm met stadsinformatie.
Namen van dorpen en steden worden gebruikt in de standaard namen voor haltes en stations.
Hoe een naam te wijzigen: klik op het naam vak en voer een nieuwe naam in.
{TIP: Gebruik [!] om de naam van een plaats boven het stadhuis zichtbaar en onzichtbaar te maken in het spel. Zie ook readme_citylist.txt (in ...simutrans/text/) voor hulp bij het genereren van namen van dorpen en steden}.

Onder het naam vak zijn statistieken te zien voor de geselecteerde plaats:
inwoners: het aantal inwoners van de plaats. Tussen haakjes is de recente groei in inwoneraantal te lezen.
gebouwen: het aantal gebouwen dat zich in de plaats bevindt.
co-ordinaten: geeft de grenzen aan van de plaats (verandert wanneer het dorp of de stad groeit).

Kengetallen zullen toenemen wanneer de plaats groeit en afnemen wanneer er nieuwe gebouwen worden gebouwd in het dorp of de stad:
werkloosheid: geeft aan hoeveel inwoners zonder werk zitten en welk type gebouw zou kunnen worden gebouwd (huizen, winkels, industrie).
dakloos: geeft aan hoeveel inwoners geen huis hebben en welk type gebouw zou kunnen worden gebouwd (huizen, winkels, industrie)..

kleine kaarten van de virtuele wereld in het stadsinformatie scherm toont bestemmingen voor passagiers en post.
Bestemmingen worden getoond door gekleurde punten en zijn geldig voor de maand waarin het spel zich bevindt (rechter kaart) en voor de afgelopen maand (linker kaart). De kleur van de punten geeft de details van de passagiers- en postbestemmingen aan:
- geel: er is een route gevonden met een rustige halte of station om de reis te beginnen (lachende smiley wordt getoond in de stationsinformatie).
- oranje: er is geen route gevonden naar de bestemming.
- rood: er is een route gevonden naar de bestemming maar de halte of station aan het begin van de route is overbezet (triest kijkende smiley in de stationsinformatie).

Grafiek toont statistieken voor de plaats.
De y-as (verticaal) is hoeveelheid, de x-as (horizontaal) is tijd.
Klik op de tabbladen om de schaal van de x-as te wijzigen:
Jaren: laat de jaarlijkse waardes zien voor de afgelopen tien jaren.
Maanden: toont de maandelijkse waardes voor de afgelopen twaalf maanden.

Klik op de knoppen onderin de grafiek om informatie in de grafiek aan of uit te zetten.
De kleuren van de lijn in de grafiek corresponderen met de kleuren van de knoppen:
Inwoners: bevolking.
Groei: wijziging in het aantal inwoners (afhankelijk van de grootte van de plaats en van het transport van passagiers en post).
Vervoerd: passagiers en post die zijn begonnen met een reis naar een bestemming (getoond als een lachende smiley in stations- en halte-informatie)
Passagiers: Totaal aantal passagiers en post dat beschikbaar is voor tansport in de geselecteerde plaats.

{TIP: Instellingen van dorpen en steden zijn te veranderen in de configuratiebestanden simuconf.tab en cityrules.tab}.

simutrans-124.3/simutrans/text/nl/climates.txt000066400000000000000000000027571474050137200215520ustar00rootroot00000000000000Klimaatinstellingen Help (Nederlands)

Klimaatinstellingen

Klimaatinstellingen biedt opties om topografische en meteorologische variabelen te veranderen in de virtuele spel wereld

Klimaatinstellingen wordt geactiveerd wanneer je Simutrans start of door te kiezen voor Hoofdmenu en vervolgens voor de optie Nieuwe kaart.

Pijltjes knoppen veranderen de instellingen:

opties:

Waterpeil: bepaalt op welk niveau het water zich bevindt in het nieuwe spel.

Berghoogte: bepaalt de maximum hoogte van het terrein.

Ruigheid: bepaalt de ruigheid van het terrein; een hoger getal zorgt voor extra glooingen.

Sneeuwgrens opties:

Sneeuwgrens(z): bepaalt de hoogte van de sneeuwgrens in de zomer

Sneeuwgrens(w): bepaalt de hoogte van de sneeuwgrens in de winter.

Klimaat opties:

Woestijn: weinig begroeing, extreme temperaturen

Tropisch: tropisch, erg hoge en constante temperatuur, regenwouden.

Subtropisch: gematigd wisselvallig vochtig weer.

Gematigd: wisselvallig weer, komt voor tussen de polen en de subtropische gebieden.

Toendra: lage temperatuur, grenst aan de polen

rotsachtig: maakt de kaart meer of minder rotsachtig.

simutrans-124.3/simutrans/text/nl/color.txt000066400000000000000000000020511474050137200210520ustar00rootroot00000000000000Kleur van de speler Help (Nederlands)

Kleur van de speler

Kleur van de spelers bepaalt de kleur van de speler.
Voertuigen, gebouwen en andere zaken krijgen de kleur van de speler.

Kleur van de speler wordt geactiveerd door de optie kleuren te kiezen vanuit het Hoofdmenu.

Klik op de knop met de kleur van je keuze om de kleur voor de speler te wijzigen.
De titelbalk van Kleur van de speler scherm zal van kleur veranderen (niet in de nieuw gekozen kleur) om aan te geven dat de instelling is gewijzigd.

Standaard kleur voor de mens is licht blauw.
Niet alle objecten zijn geschikt om in de kleur van de speler te worden getoond.

{TIP: Om de kleur van een AI (= kunstmatige intelligentie = computer) speler te wijzigen kies eerst de Lijst met spelers of P (net zo vaak totdat je de speler van je keuze bent) om van speler te wisselen}.

simutrans-124.3/simutrans/text/nl/convoi.txt000066400000000000000000000073471474050137200212460ustar00rootroot00000000000000Voertuigen Lijst

Voertuigen Lijst

Voertuigen Lijst toont informatie over voertuigen en kan een filter toepassen op de lijst met voertuigen (een voertuig is een enkel voertuig of een samenstelling van voertuigen).

Hoe te benaderen: klik op het voertuigen lijst icoontje in Lijstenbeheer of toets [V]. De voertuigen lijst heeft vier knoppen, de eerste twee knoppen bepalen de sortering van de lijst en de andere twee zijn voor het filter.
Onder de knoppen wordt een lijst met voertuigen getoond die (indien geactiveerd) voldoen aan de filter voorwaarden.
{TIP: indien er geen voertuigen te zien zijn kun je de filter instellingen aanpassen. Indien de lijst slechts voor een deel zichtbaar is, kun je de grootte van het scherm voertuigen lijst of scrollen door middel van de schuifbalk.}

Klik op de knoppen om door de opties te bladeren (verandert de naam van de betreffende knop in het op dat moment gekozen instelling) of opent een scherm voor de instellingen van het filter :

Gesorteerd op: Twee knoppen regelen de instelling van de volgorde waarop de voertuigen worden getoond in de lijst.

- Naam sorteert op de naam van het voertuig, alfanumeriek op de volgorde van ASCII-code order (hoofdletters voor kleine letters (de naam is standaard het merk en naam van het eerst gekozen voertuig van de samenstelling in een remise of hangar (depot)).
- Inkomsten sorteert de lijst op inkomsten (netto). - Type sorteert de lijst op het type transport (in oplopende volgorde wegverkeer, treinen, schepen en vliegtuigen)
- id nummer sorteert de lijst op het unieke id-nummer van het voertuig (wordt automatisch toegekend op het moment dat het voertuig in een remise of hangar (depot) wordt gekocht en wordt getoond in de titelbalk van het scherm voertuig informatie).

- oplopend / aflopend keert de volgorde van de lijst om.

Filter: Twee knoppen waarvan de eerste het filter in- en uitschakelt en de tweede een scherm opent met instellingen van het filter.

- aan / uit klik op de knop om het filter voor voertuig informatie aan of uit te zetten.

- Instellingen opent het scherm om de selectiecriteria voor het filter aan te passen.

Klik op een voertuig in de lijst om meer informatie te zien van het voertuig.

De volgende informatie wordt getoond voor elk voertuig:

id-nummer: een uniek nummer dat automatisch wordt toegekend op het moment dat het voertuig in een remise of hangar (depot) wordt gekocht en wordt getoond in de titelbalk van het scherm voertuig informatie).

naam naam van het voertuig (dit is standaard het merk en naam van het eerst gekozen voertuig van de samenstelling in een remise of hangar (depot)).

Inkomsten toont inkomsten (netto).

Lijn: toont de toegekende lijn en toont of een voertuig zich in een remise of hangar (depot).

plaatje toont een plaatje van het voertuig en een groene balk die weergeeft hoeveel lading het voertuig op dit moment vervoert ten opzichte van het maximum laadvermogen.

simutrans-124.3/simutrans/text/nl/convoi_filter.txt000066400000000000000000000047001474050137200226010ustar00rootroot00000000000000Voertuigen Lijst Filter

Voertuigen Lijst Filter

Voertuigen Lijst Filter biedt mogelijkheden om te bepalen welke Voertuigen worden getoond in de Voertuigen lijst.

Klik op de Instellingen knop in de voertuigen lijst om het Voertuigen Lijst Filter te benaderen.

De knoppen selecteren voertuigen die worden getoond in de voertuigen lijst als het filter aan is. Alleen voertuigen die aan alle selectie criteria voldoen worden getoond.

Klik op een knop om de selectie criteria te activeren of te deactiveren voor het filter:

Filter namen: selecteert voertuigen door middel van de naam van het voertuig. Hoe te gebruiken: klik op de knop om het filter te activeren, en klik vervolgens in het vak onder Filter namen en toets de naam precies in (hoofdlettergevoelig).

Filter type: selecteert voertuigen van het geselecteerde type indien geactiveerd. Hoe te gebruiken: klik op de knop naast Filter type om het filter te selecteren, klik vervolgens op het type transport dat je wilt selecteren: Wegverkeer, Treinen, Schepen en Vliegtuigen.

Speciaal filter: selecteert voertuigen indien deze voldoen aan de volgende criteria (klik op de knop naast Speciaal filter om te selecteren, klik vervolgens op):
- geen route - voertuig kan geen route vinden naar de volgende bestemming.
- geen planning - voertuigen die geen route toegewezen hebben gekregen.
- geen inkomen - voertuigen die geen winst maken.
- in een depot - voertuigen die in een hangar of remise (depot) staan.
- geen lijn - voertuigen die geen lijn toegewezen hebben gekregen .

Filter goederen: selecteert voertuigen die in staat zijn om de geselecteerde goederen en passagiers te vervoeren. Klik op de knop naast Filter goederen om het filter te selecteren een klik vervolgens op de knop naast de optie van je keuze om te selecteren. Gebruik de schuifbalk om te scrollen door de beschikbare goederen in de lijst. Opties bevatten:
- alles selecteert alles.
- geen zet alles uit.
- wissel draait de selectie om.

simutrans-124.3/simutrans/text/nl/convoidetail.txt000066400000000000000000000044161474050137200224230ustar00rootroot00000000000000Voertuig Details Help (Nederlands)

Voertuig details

Voertuig details geeft meer informatie over een voertuig (een in gebruik zijnd voertuig of samenstelling) en kan gebruikt worden om een voertuig onmiddelijk te kunnen verkopen.

Voertuig details worden zichtbaar door op de knop Details te klikken in het voertuig informatie scherm.
Indien niet alle items zichtbaar zijn kun je de grootte van het scherm wijzigen of de schuifbalken om door de items te scrollen.

Bovenin het scherm Voertuig details getoonde informatie bevat:

Vermogen: in kW van het voertuig (optelsom van het vermogen van alle gemotoriseerde voertuigen in de samenstelling).

Verkoop waarde: bedrag dat het voertuig nog oplevert indien het verkocht wordt op dat moment (is aanschafwaarde minus afschrijving).

LET OP: Klik op verkopen knop om het voertuig onmiddelijk te verkopen. Er wordt niet om bevestiging gevraagd. Het voertuig wordt uit het spel verwijderd en de speler krijgt de verkoop waarde bijgestort in de kas. Terugtrekken doet hetzelfde dan verkopen maar zal eerst de volledige lading afleveren alvorens verkocht te worden.

Voertuig details toont alle voertuigen uit de samenstelling.
Per voertuig wordt de volgende informatie getoond:
- afbeelding van het voertuig een afbeelding van het voertuig (wordt ook gebruikt in de hangar of remise (depots)).
- Geproduceerd: jaar en maand van productie van het voertuig en indien met de tijdlijn ingeschakeld wordt gespeeld wordt ook de datum van introductie van het voertuig vermeld.
- Verkoop waarde: bedrag dat wordt ontvangen indien het voertuig nu verkocht zou worden.
- Vermogen: vermogen in kW (in geval van gemotoriseerd voertuig).
- Frictie: huidig frictie niveau.
- Max inkomsten: het maximale bedrag dat het voertuig aan inkomsten heeft gegenereerd.
- Lading hoeveelheid en bestemming van de op dit moment aanwezige lading.

simutrans-124.3/simutrans/text/nl/convoiinfo.txt000066400000000000000000000174751474050137200221250ustar00rootroot00000000000000Voertuig Informatie

Voertuig Informatie

Voertuig informatie toont informatie over een voertuig (een enkel voertuig of een voertuig samenstelling) dat wordt gebruikt voor het vervoeren van vracht of passagiers.
In het scherm worden details getoond over de lading van het voertuig en tevens zijn er knoppen voor meer details, er wordt een mogelijkheid geboden het voertuig direct te verkopen, je kunt het voertuig volgen op de kaart, de naam van het voertuig wijzigen en een dienstregeling toewijzen of wijzigen van een voertuig.

Een voertuig is een samenstelling van minimaal een (1) aangedreven (gemotoriseerd) voertuig en een hoeveelheid aanhangers of wagons.
Voorbeelden van voertuigen zijn: een span paarden dat een kar trekt; een locomotief met tender en wagons; een bus; een bestelauto; een tram met wagons; een schip of een vliegtuig.
Voertuigen worden samengesteld en gekocht in een remise of hangar (depot) van toepassing voor het type voertuig.
{TIP: Een voertuig samenstelling heeft een maximum aantal voertuigen in een samenstelling: treinen, 24; wegverkeer, 4 .}

Klik op een voertuig in het spel met de info tool of klik op een voertuig in de lijst met voertuigen of lijnen beheer om het scherm met voertuig informatie te activeren.
De titelbalk van het scherm met voertuig informatie toont een uniek ID nummer en een naam van het voertuig (dit is standaard het merk en naam van het eerst gekozen voertuig van de samenstelling in een remise of hangar (depot)).
Voertuig informatie bestaat uit een vak met een naam; een mini kaart en informatie over het voertuig; knoppen met opties; en een opsomming van de op dat moment door het voertuig getransporteerde goederen of passagiers (indien niet alles zichtbaar is kun je de grootte van het scherm wijzigen of de schuifbalken gebruiken om te scrollen).

De volgende informatie wordt getoond in de titelbalk en bovenin van het scherm voertuig informatie :

Intern ID: een uniek ID nummer voor dat voertuig (toegekend wanneer het voertuig wordt gekocht in een remise of hangar (depot)).

- naam: dit is standaard het merk en naam van het eerst gekozen voertuig van de samenstelling in een remise of hangar (depot)).
Klik in het naam vak en toets een nieuwe naam om de toegewezen naam te wijzigen.

- snelheid: de huidige snelheid in km/u.
De maximum snelheid van het voertuig staat tussen haakjes vermeld (dit is de maximum snelheid van het langzaamste voertuig uit de samenstelling).
De snelheid ten opzichte van de maximum snelheid wordt weergegeven door een groene balk.

- Inkomsten: de netto inkomsten die de exploitatie van het voertuig dit kalenderjaar heeft opgeleverd. Verlies wordt voorafgegaan door een - en in het rood weergegeven.
De kostprijs per kilometer is vermeld tussen haakjes in Hajo valuta per kilometer.

- Gewicht: totaal gewicht van het voertuig inclusief lading op dit moment in ton.
Het gewicht van de lading staat tussen haakjes vermeld.
Een groene balk geeft aan hoe de werkelijke lading zich verhoudt tot de maximale lading voor het voertuig of samenstelling.
Een gele balk geeft aan dat het voertuig wacht op lading (zie laden t/m). Dit is in te stellen bij de dienstregeling van het voertuig en is een percentage van de maximale laadcapaciteit van het voertuig. Het voertuig zal niet eerder vertrekken totdat minstens de minimale lading is geladen.
{TIP: Om laden t/m in te stellen of te wijzigen voor alle voertuigen die dezelfde lijn bedienen, kun je de Lijn veranderen knop in Lijnenbeheer gebruiken of dezelfde knop in de remise of hangar (depot). Om alleen voor een (1) voertuig de laden t/m instelling te wijzigen kun je de knop dienstregeling in het scherm voertuig informatie of in de remise of hangar (depot).}

- Bestemming: De volgende halte of stopplaats volgens de dienstregeling van het voertuig.
De groene balk geeft de relatieve afstand aan die is afgelegd op weg naar de aangegeven bestemming.

- Bedient lijn: toont de lijn die het voertuig bedient indien er een lijn is toegewezen aan het voertuig. Een voertuig kan ook een aparte dienstregeling hebben.

- mini kaart toont het voertuig in aktie.
Klik op de mini kaart om het scherm te centreren rond het voertuig.

Klik op de knoppen in het scherm voertuig informatie om opties te activeren of een scherm te openen:

Dienstregeling: opent een scherm om de dienstregeling aan te passen of om laden t/m te wijzigen.

naar depot: stuurt het voertuig naar een dichtbij gelegen remise of hangar (depot). De aanwezige lading zal verloren gaan maar wel geld opbrengen voor het transport naar de remise of hangar.
Eenmaal in de remise of hangar zal het voertuig de dienstregeling en de toegewezen lijn behouden.

alleen lossen: zorgt ervoor dat er alleen lading wordt gelost en niet geladen.

volgen: als deze knop is geactiveerd zal het voertuig gevolgd worden op de kaart.
Nogmaals klikken of ergens op de overzichtskaart zal het volgen van het voertuig eindigen

Gesorteerd op: sorteert het overzicht van de aanwezige lading.
Het overziccht toont informatie over de hoeveelheid lading, de capaciteit van het voertuig, soort lading, de bestemming van de lading en het eerste overlaadstation.
De knop krijgt de naam van de actieve sortering. De mogelijkheden zijn:
- bestemming: sorteert de lading alfanumeriek op de volgorde van ASCII-code order (hoofdletters voor kleine letters), op de naam van de uiteindelijke bestemming van de lading.
- via: sorteert de lading alfanumeriek op de volgorde van ASCII-code order (hoofdletters voor kleine letters), op de naam van het eerste overlaadstation.
- aantal-via: sorteert de lading op hoeveelheid en op het eerste overlaadstation.
- aantal: sorteert de lading op hoeveelheid in aflopende volgorde.

Grafiek: klik op de knop om de grafiek aan of uit te zetten (knop is ingedrukt wanneer de grafiek zichtbaar is) in het voertuig informatie scherm.
De grafiek toont statistieken over de laatste 12 maanden (x-as) wanneer er een grafiek is geactiveerd door middel van de knoppen onder de grafiek.
Klik op de knoppen om grafieken aan of uit te zetten. De knop zal zijn ingedrukt wanneer een optie wordt getoond.
De kleur van de lijn in de grafiek correspondeert met de kleur van de knop voor de grafiek:
- Vrije capaciteit geeft informatie over onbenutte laadcapaciteit van het voertuig.
- Vervoerd geeft informatie over de hoeveelheid lading die is vervoerd.
- Inkomsten de inkomsten die het voertuig heeft gegenereerd.
- Exploitatiekosten geeft aan hoeveel kosten het voertuig heeft gemaakt.
- Winst het saldo van de twee bovenstaande waardes.

Details opent het voertuig details scherm met meer informatie en de opties om een voertuig terug te trekken of te verkopen.

simutrans-124.3/simutrans/text/nl/curiositylist_filter.txt000066400000000000000000000051651474050137200242400ustar00rootroot00000000000000Lijst met bezienswaardigheden

Lijst met bezienswaardigheden

Lijst met bezienswaardigheden toont informatie over alle bezienswaardigheden (dit zijn zowel vertrekpunten als bestemmingen voor passagiers en post).

Hoe het scherm lijst met bezienswaardigheden te openen: klik op het icoon voor lijst met bezienswaardigheden in het submenu met opties voor het lijstenbeheer.
{TIP: indien de bezienswaardigheden in de lijst ten dele zichtbaar zijn, kun je de lijst met bezienswaardighedenin grootte wijzigen of door de lijst scrollen door middel van de schuifbalk.}

Gesorteerd op bepaalt de volgorde waarop de bezienswaardigheden worden getoond.
Klik op de knoppen om door de verschillende mogelijkheden te bladeren (dit zal de naam van de knop wijzigen in de op dat moment actieve sortering):

- Naam sorteert alfabetisch op naam.
- Passagiersaanbod sorteert op het passagiers- en postaanbod dat een attractie genereert.

- oplopend / aflopend keert de volgorde van de lijst om.

Klik op een bezienswaardigheid in de lijst met bezienswaardigheden om meer informatie over de gekozen bezienswaardigheid te zien.
{TIP: klik op het plaatje in het detail scherm om naar de betreffende bezienswaardigheid op de kaart te gaan.}

Informatie welke wordt getoond van iedere bezienswaardigheid bestaat uit:

statusbalk kleuren geven een indicatie voor de status van de bezienswaardigheid:
- geel: heeft geen halte of station waar het passagiers en post verbonden.
- groen: heeft een station of halte verbonden voor passagiers.
- blauw: heeft een halte of station verbonden voor post.
- turquoise: heeft zowel een halte of station voor passagiers als voor post.
- oranje: een (1) verbonden station of halte is overbezet.
- rood: alle verbonden stations of haltes zijn overbezet.

gebouw icoon geeft aan dat de bezienswaardigheid zich in een stad of dorp bevindt.

naam van de bezienswaardigheid.

passagiersaanbod geeft tussen haakjes aan hoeveel passagiers en post de bezienswaardigheid genereert (in andere woorden: hoe populair het is).

{TIP: Om een optimale service voor passagiers en post te bieden kan het nodig zijn dat er meerdere haltes of stations zijn verbonden met een bezienswaardigheid.}

simutrans-124.3/simutrans/text/nl/depot.txt000066400000000000000000000254631474050137200210630ustar00rootroot00000000000000Depot (garage, hangar, remise)

Depot (garage, hangar, remise) Opties

In dit spel wordt de term depot gebruikt om een garage, remise, hangar of werf aan te duiden. Dit is afhankelijk van het type voertuig dat in het depot wordt geproduceerd. Zo zijn er depots voor wegtransport, railvervoer (treinen, monorails/maglevs en trams), luchtvaart (vliegtuigen en dergelijke) en scheepvaart (schepen en dergelijke). Al deze depots hebben een groot aantal overeenkomsten welke in deze helptekst worden behandeld.
Een depot wordt gebruikt om voertuigen aan te schaffen en te beheren. Een depot toont alleen voertuigen die ook kunnen bewegen op het type infrastructuur dat is verbonden met het depot: een depot voor treinen dat niet is verbonden met rails met bovenleiding zal geen elektrische treinen tonen.
Indien de optie tijdlijn is ingeschakeld, zal het depot alleen die nieuwe voertuigen tonen die op dat moment in productie zijn. Naar mate de tijd vordert zullen voertuigen worden toegevoegd dan wel worden verwijderd.

Gereedschappen om de verschillende types depots te maken zijn beschikbaar in de iconenbalk voor het betreffende type transport: Trein remise; Monorail remise; Tram remise; Garage; Scheepswerf ; en een Hangar.

Klik op een depot met de Info tool om het scherm met de Depot opties te openen. Het scherm geeft informatie over Voertuigen en voertuig samenstellingen en de mogelijkheid deze samen te stellen, te beheren en te verkopen.
De titelbalk van de Depot opties geeft aan welk type voertuigen er mee kunnen worden beheerd.

Het scherm Depot opties kan in grootte worden gewijzigd en door in de titelbalk op het pijltje naar beneden te klikken (nogmaals op het pijltje naar beneden klikken zal het scherm weer herstellen in de oorspronkelijke grootte).
De pijltjes naar links en naar rechts zullen naar een vorig of volgend depot van hetzelfde type navigeren en het spelscherm centreren op het geselecteerde depot.

Bovenin het Depot opties scherm wordt het aantal voertuigen getoond dat aanwezig is in het geselecteerde depot, en wanneer een (1) van deze voertuigen is geselecteerd zal ook de naam en de lijn worden getoond.

Voertuig naam: Klik op de pijltjes links of rechts van de naam om door de aanwezige voertuigen te bladeren.
Hoe de naam van een voertuig te wijzigen: klik in het veld waar de naam wordt getoond en pas de naam aan. De standaard naamgeving die het spel toepast is de naam van het eerst gekochte voertuig in de samenstelling van het voertuig.

Hoe een lijn toe te kennen: gebruik de pijltjes links en rechts om te bladeren in de beschikbare lijnen voor dit type voertuig of klik in het vak met daarin de aanduiding van de lijn (onder de naam van het voertuig) om een scherm met beschikbare lijnen te tonen. Selecteer vervolgens de lijn die je wilt en klik op de knop lijn toewijzen.
Hoe de naam van een lijn te wijzigen: klik in het vak waar de lijn wordt getoond en toets een nieuwe naam. Standaard wordt de naam Lijn + (nummer van de lijn) toegewezen.

Afbeelding van het voertuig: onder de velden voor naam en lijn van het voertuig vind je een afbeelding van het geselecteerde voertuig of samenstelling.
Beweeg de muis over de afbeelding van het voertuig of de samenstelling om details te zien over het deel van het voertuig waarnaar je wijst. (De details worden getoond onderin het scherm van de depot opties).
Klikken op het deel van het voertuig in de afbeelding zal dat betreffende deel verwijderen uit de samenstelling en deze weer plaatsen in de voorraad van het depot.

Onder de afbeelding van het voertuig of de samenstelling staat het aantal delen van het voertuig of de samenstelling vermeld en tevens de benodigde grootte van het station of de halte om het hele voertuig of de samenstelling volledig te kunnen laden en lossen, alsmede de lijn die het voertuig bedient.

De knoppen in het depot opties hebben de volgende functies (klik om de betreffende optie te selecteren):

Starten: het geselecteerde voertuig wordt gestart en zal het depot verlaten indien de toegewezen route of dienstregeling kan worden gestart (met andere woorden: indien er een route kan worden gevonden).

Dienstregeling: opent een scherm met de mogelijkheid om een dienstregeling toe te kennen of te wijzigen; tevens is per station of halte aan te geven hoeveel de minimaal aanwezige lading moet zijn om verder te gaan met de volgende halte of station in de dienstregeling.

Opheffen: plaatst het geselecteerde voertuig in de voorraad van het depot. Het betreffende voertuig zal niet langer een dienstregeling onderhouden.

Verkopen: verkoopt het geselecteerde voertuig, het kassaldo zal met de restwaarde van het voertuig worden verhoogd.

Nieuwe lijn: opent een scherm met de mogelijkheid om een lijn te defini-eren en eventueel te bepalen hoeveel lading het voertuig dient te hebben voordat het naar het volgende punt in de lijn vertrekt. Een lijn kan voor meerdere voertuigen worden gebruikt.

Lijn toewijzen: wijst de geselecteerde lijn toe aan het geselecteerde voertuig.

Lijn veranderen: opent een scherm waarin je de geselecteerde lijn kunt wijzigen (zowel de route als de minimale lading bij een halte of station). Dit heeft gevolgen voor alle voertuigen die de lijn bedienen.

Kopieren: maakt een kopie van het geselecteerde voertuig met dezelfde samenstelling en dienstregeling of lijn. Dit zal automatisch het benodigde aankoopbedrag in mindering brengen op het kassaldo.

Onder de knoppen is een overzicht van de beschikbare voertuigen met afbeeldingen te zien. Wat er zichtbaar is is afhankelijk van de staat waarin een samen te stellen voertuig zich bevindt en de geselecteerde opties onder de plaatjes. Dit kunnen alle voertuigen zijn, alleen de op dit moment nog in productie zijnde voertuigen of alleen die voertuigen welke relevant zijn voor de reeds geselecteerde voertuigen. Ook wordt er een aantal tabbladen getoond waarop verschillende soorten voertuigen zijn te selecteren. Dit is afhankelijk van het type depot wat wordt getoond.
afbeeldingen van voertuigen: Voertuigen worden verdeeld in categori-en die kunnen worden benaderd door op de betreffende tabblad te klikken. Tabbladen verdelen de voertuigen in soorten: voertuigen voor de transport van passagiers en post, overige aangedreven voertuigen en aanhangers en opleggers.
Een getal dat boven het voertuig staat (wit) geeft het aantal eenheden aan dat in voorraad is. Deze kan (kunnen) zonder kosten weer gebruikt worden in een nieuwe samenstelling.

Beweeg de muis over de afbeelding om meer informatie over het betreffende voertuig te krijgen (de volgorde is afhankelijk van het type voertuig):
Naam: en tussen haakjes het type motor dat wordt gebruikt in geval van aangedreven voertuigen.
Prijs: aanschafprijs en tussen haakjes de kostprijs per kilometer.
Vermogen: motorvermogen en maximum snelheid voor aangedreven voertuigen.
Gewicht: in ton.
Maximum snelheid: van niet aangedreven voertuigen.
Capaciteit: hoeveelheid en soort goederen dat het voertuig maximaal kan vervoeren.
Geintroduceerd: datum waarop een voertuig beschikbaar kwam indien de tijdlijn is geactiveerd.
Gebouwd tot: datum waarop het voertuig uit productie wordt genomen. (tijdlijn)
Gemaakt door: de ontwerper van het voertuig in Simutrans.
Overbrenging: versnelling.
Verkoopwaarde: het bedrag dat het voertuig op dit moment nog waard is wanneer het wordt verkocht.

Klik op het voertuig in het tabblad om deze (afhankelijk van de instelling van de knop rechts onderin het scherm) te kopen of te verkopen. Deze knop schakelt tussen drie opties:

Toevoegen: koopt het geselecteerde voertuig en plaatst deze achteraan in de geselecteerde voertuig of samenstelling of indien dit het eerste voertuig is zal dit een nieuw voertuig cre-eren.

Invoegen: koopt het geselecteerde voertuig en plaatst deze vooraan in het geselecteerde voertuig of samenstelling.

Verkopen: verkoopt het in voorraad zijnde voertuig (deze dient dan wel in voorraad te zijn).

gekleurde balken onder de afbeelding van het voertuig geeft aanwijzingen voor volgorde waarin een voertuig moet worden gebruikt en welke voertuigen aan een bestaande samenstelling kunnen worden toegevoegd om een werkende voertuig samenstelling te vormen (kleurenbalken kunnen veranderen door een andere instelling van de hiervoor beschreven knop).
De kleuren betekenen het volgende:
- groen: voertuig kan worden gebruikt.
- rood: voertuig kan niet worden gebruikt.
- geel: voertuig is pas beschikbaar indien er een ander voertuig voor wordt geplaatst.
- blauw: voertuig kan worden gebruikt maar is inmiddels uit productie genomen.
{TIP: een voertuig of samenstelling is bruikbaar wanneer er groene balken voor alle eenheden worden getoond. Indien er nog deels een gele balk wordt getoond zal er nog een aanvullend onderdeel moeten worden toegevoegd.}

Toon alles: deze optie zorgt ervoor dat alle beschikbare voertuigen worden getoond en niet alleen de relevante voor de reeds geselecteerde samenstelling. De optie is ingeschakeld wanneer de knop is ingedrukt. Nogmaals klikken zal de optie uitzetten.
Verouderde tonen: indien er wordt gespeeld met de tijdlijn ingeschakeld, zullen indien deze optie is gekozen ook de verouderde voertuigen worden getoond welke al uit productie zijn genomen.

simutrans-124.3/simutrans/text/nl/display.txt000066400000000000000000000107511474050137200214070ustar00rootroot00000000000000Beeldscherm instellingen help (Nederlands)

Beeldscherm instellingen

Beeldscherm instellingen bevat instellingen waarmee de wijze waarop het spel wordt getoond kunnen worden be-invloed; & geeft informatie over de prestaties van de computer.

Om het scherm beeldscherm instellingen te openen dien je op de Scherm knop klikken in het Spel instellingen scherm.

Klik op de kleine vierkante knoppen om een instelling te activeren of te deactiveren, of gebruik de horizontale pijltjes om de instelling aan te passen:

underground mode: zet het spel in ondergrondse modus (in 99.08.1 nog erg experimenteel)

Dag en Nacht Modules: zet het spel in dag en nacht modus (licht en donker).

Helderheid:bepaalt de helderheid van het scherm tijdens het spel; bij een lagere waarde neemt de helderheid af; te lage of hoge waardes kunnen problemen veroorzaken (dus wees voorzichtig met wijzigen van deze instelling); om de helderheid boven 0 te laten stijgen dien je de [+] toets te gebruiken. Met de muis is een waarde tot maximaal 0 in te stellen.

Scroll omdraaien: draait de richting om bij het scrollen in het spel in het spel scherm (wereld/kaart).

Scroll snelheid: bepaalt de snelheid van het scrollen tijden het spelen in het spel scherm (wereld/kaart).

Verberg objecten transparant: toont doorzichtige objecten met een kleurmarkering in het spel scherm wanneer betreffende objecten verborgen zijn (zie de instellingen hierna, verbergen kan ook met de ["] toets).

Verberg bomen: verbergt bomen in het spel, bomen worden nu of transparant (zie hierboven) of geminimaliseerd getoond wanneer deze instelling is gekozen.

Verberg stadsgebouwen: verbergt alle huizen, kantoren, industrie en winkels in een stad behalve speciale gebouwen.

Verberg alle gebouwen: verbergt alle gebouwen. Deze optie zet tevens de bovenliggende optie aan.

Transparante stations dekking: toont het gebied dat wordt verzorgd door een station als een doorzichtig gekleurd vlak in plaats van de markering met vierkante blokjes.

Toon stations dekking: om tijdens het spel de zichtbaarheid van de dekking van een station aan of uit te zetten kun je ook de [v] toets gebruiken

Voetgangers (stad): toont voetgangers in een dorp of stad.

Voetgangers (halte): toont voetgangers bij een halte of station.

Stadsverkeer: bepaalt de hoeveelheid particuliere voertuigen in steden en dorpen.
De hoeveelheid particuliere voertuigen is afhankelijk van de grootte van het dorp of de stad en deze instelling. Hoge waardes zorgen voor veel verkeer, 0 zet het genereren van stadsverkeer uit.

{TIP: Meer instellingen en de standaard waardes kunnen worden gezet in simuconf.tab}.


Prestaties van de computer:

Onder bovenstaande instellingen wordt informatie getoond over de prestaties van de computer tijdens het spelen van .
Indien de getallen (normaal gesproken wit gekleurd) in het rood of geel worden getoond kan het noodzakelijk zijn om de instellingen van de computer te wijzigen.
Wijzigingen in de snelheid van het spel, W, (of de Snel voorwaarts in tijd >> icoon, of [,]/ [.]) kunnen deze kleur be-invloeden.

Beeldfrequentie: geeft de snelheid van een enkel beeld aan.

Werkloos: Indien deze waarde groter is dan 0, heeft de computer tijd over voor andere taken.

FPS: Hogere waardes geven aan dat het systeem in staat om bijvoorbeeld de voertuigen in het spel vloeiend voort te bewegen. Indien deze waarde rood blijft is dat een indicatie voor het feit dat de computer te traag is om Simutrans goed te kunnen draaien met de huidige instellingen ( probeer eens een kleiner formaat voor het Simutrans scherm).

Simloops:Indien deze waarde rood blijft is dat een indicatie voor het feit dat de computer te traag is om Simutrans goed te kunnen draaien met de huidige instellingen ( probeer eens een kleiner formaat voor het Simutrans scherm).

simutrans-124.3/simutrans/text/nl/general.txt000066400000000000000000000062401474050137200213550ustar00rootroot00000000000000Simutrans Help (Nederlands)

Simutrans Help


Algemeen
- Welkom
- Speel scherm/interface
- Toetsenbord configuratie
- Muis bediening

Spel instellingen
- Taal
- Kleur
- Scherm
- Geluid
- Spelers
- Laden
- Opslaan
- Nieuwe wereld
-- Klimaat instellingen
-- Laad hoogtekaart

Menu - algemeen
- Spel instellingen
- Mini kaart
- Info Tool
- Landschap
- Spoorwegen
- Monorail/Maglev
- Trams
- Autowegen
- Scheepvaart
- Luchtvaart
- Bijzondere werktuigen
-- Kaarteditor
- Verwijder

Menu - management
- Lijnen administratie
- Lijsten administratie
-- Stations lijst
--- Station filter
-- Voertuigen lijst
--- Voertuigen filter
-- Lijst met steden
-- Goederen lijst
-- Industrie lijst
-- Bezienswaardigheden
- Berichtencentrum
- Financiën

Menu - overig
- Schermafdruk
- Pause
- Snel vooruit in tijd
- Hulp

Overige dialogen
-Depot/Garage/Werf informatie
-Dienstregeling informatie
- Station/Halte informatie
-- Station/Halte details
- Voertuigen informatie
-- Voertuigen details
- Stad informatie
- Industrie informatie

Aanvullende hulp is te vinden op de diverse Simutrans websites (in het Engels):
http://guide.simutrans.com
http://wiki.simutrans.com
http://simutrans-tips.com
http://forum.simutrans.com

simutrans-124.3/simutrans/text/nl/mailbox.txt000066400000000000000000000045561474050137200214030ustar00rootroot00000000000000Berichtencentrum & Opties

Berichtencentrum

Het Berichtencentrum toont berichten uit het spel en geeft toegang tot de opties die betrekking hebben op de wijze waarop de berichten getoont worden.

Klik op het mailbox icoon in het menu of druk op de [B] toets om het berichtencentrum te openen.

Het berichtencentrum toont de berichten uit het spel. Door op een bericht te klikken wordt de spel-scherm naar de gerelateerde positie verplaatst.

De knop [Opties] geeft toegang tot de opties voor het berichtencentrum. De opties bepalen hoe de diverse berichten worden getoond.



Berichtencentrum Opties

Het scherm Berichtencentrum Opties bevat drie kolommen met check-boxes die bepalen hoe de diverse berichten worden getoond.

Van links naar rechts bepalen de kolommenof berichten als:
a) scrollende tekst in de statusbalk; b) een tijdelijke popup; of c) een permanente popup
getoond worden. De tijdelijke popup verdwijnt weer na een aantal seconden van het scherm, de permanente popup moet door de speler (m.b.v. [x]) gesloten worden.

De volgende bericht-categorien zijn afzonderlijk in te stellen:

Nieuw Jaar: Een nieuw jaar is begonnen.

AI Nieuws: Berichten betreffende de simutrans spelers.

Stadnieuws: Berichten betreffende de steden en de stedelijke ontwikkelingen.

Geen Route: Een voertuig kan geen route vinden naar de volgende bestemming, station of routepunt.

Nieuwe Industrie: Berichten betreffende de industrie ketens van grondstof producerende industrieen tot de eind-gebruikers.

Tourisme: Berichten betreffende attracties en monumenten.

Nieuwe Voertuigen: een nieuw voertuig komt beschikbaar of is niet langer meer beschikbaar (als timeline wordt gebruikt).

Station vol: Een Station is overvol.

Problemen: Roodstaan en andere kritieke berichten.

simutrans-124.3/simutrans/text/nl/map.txt000066400000000000000000000112621474050137200205150ustar00rootroot00000000000000MiniKaart Help (Nederlands)

MiniKaart

De MiniKaart toont een overzicht van de simutrans wereld. Het geeft informatie over het terrein, belangrijke locaties en de transportinfrastructuur. Daarnaast geeft het de mogelijkheid het speel-scherm naar een andere positie van de simutrans wereld te verplaatsen.

Klik op het MiniKaart icoon in het menu of druk op de [m] toets om het MiniKaart scherm te openen. Met behulp van de rechts/links pijltjes kan de minikaart in 7 stappen in- en uitgezoomd worden. De knop [# ] isometric view toont de minikaart gelijk aan het het speel-scherm.

Het minikaartscherm heeft drie optieknoppen: toon legenda; toon schaal en toon industriën

Water is blauw op de kaart en het land groen. Het hoogte- (land) en diepte- (water) niveau wordt weergegeven in lichtere en donkere tinten. Het gedeelte van de simutranswereld dat zichtbaar is wordt op de minikaart aangegeven door een geel kader.

Links-klik, of links-klik en sleep het kader op de minikaart om het speel-scherm snel door de simutrans wereld te verplaatsen.

Als de muis-cursor op een industrie op de minikaart wordt geplaatst, wordt de naam getoond en worden witte lijntjes getoond naar afnemende industriën. Als eerst de [Shift] wordt ingedrukt wordt m.b.v. rode lijntjes de aanleverende industriën aangegeven.

Steden en dorpen, attracties, tunnels en kanalen worden donker grijs weergegeven; wegen zwart; spoor- en tramlijnen grijs; bruggen licht grijs; stations/haltes rood/geel; monorail- en maglevlijnen oranje; luchthavens wit en voertuigen geel.

Op de minikaart kan extra detailinformatie gegeven worden. Klik hiervoor op [toon legenda]. Er verschijnt nu een hele serie extra optie-knoppen waarmee de informatie die op de minikaart getoond wordt in- en uitgeschakeld kan worden. Een aantal opties maakt gebruik van een min-max schaal. De min-max schaal kan met behulp van de knop [toon schaal] zichtbaar/verborgen worden.

De volgende opties zijn beschikbaar:

Plaatsnamen: namen van steden en dorpen.
Passagiers: gebieden die voorzien zijn van stations en haltes voor passagiersvervoer.
Post: gebieden die voorzien zijn van stations en haltes voor postvervoer.
Vracht:aantallen passagiers en/of goederen op het spoor of de weg (min-max schaal).
Halte status: operationele status van de stations/haltes. De status wordt als volgt weergegeven:
geel: halte/station niet opgenomen in een route; groen: status OK; oranje: station/halte druk. Actie nemen wordt aangeraden; rood: station/halte overvol. Actie nemen noodzakelijk.
Service: aantallen passagiers en/of goederen dat gebruik maakt van een station of halte(min-max schaal).
Verkeer: aantallen voertuigen op het spoor of de weg (min-max schaal).
Herkomst: aantallen passagiers en/of goederen dat het station/halte als beginpunt heeft (min-max schaal).
Bestemming: aantallen passagiers en/of goederen dat het station/halte als eindpunt heeft (min-max schaal).
Wachtend: aantallen passagiers en/of goederen dat bij het station/halte wacht op vervoer (min-max schaal).
Spoorwegen: trein- en tramrails; -bruggen; -tunnels en -seinen (kleur: wit of rood indien geëlectrificeerd; seinen: geel).
Max snelheid: maximaal toegestane snelheid op spoorwegen en wegen (min-max schaal).
HSP leidingen: hoogspanningsleidingen in de simutranswereld. De kleur is een indicatie voor het vermogen dat getransporteerd wordt (min-max schaal).
Attracties: positie van toeristische attracties in de simutranswereld. Tevens toont het de aantallen passagiers dat gegenereerd wordt door attracties (min-max schaal).
Fabrieken: positie van industriën in de simutranswereld. De verschillende soorten industriën hebben verschillende kleuren. Klik voor de gedefinieerde kleuren op [toon industriën].
Depots: positie van depots in de simutranswereld. De kleuren duiden op verschillende typen. Schepen:geel; bus/truck:oranje; trein:rood; vliegtuigen:groen; trams:blauw; en monorail/maglev:grijs.

simutrans-124.3/simutrans/text/nl/monorailtools.txt000066400000000000000000000120761474050137200226450ustar00rootroot00000000000000Monorail/Maglev Tools Help (Nederlands)

Monorail/Maglev Tools

Het Monorail/Maglev Tools menu bevat tools om een monorail/maglev infrastructuur te bouwen. Deze tools kunnen de volgende onderdelen bouwen of slopen: monorail- en maglevbanen, seinen, bruggen, tunnels en stations. Indien de tijdlijn is geactiveerd in het spel, zal met de tijd het aantal beschikbare opties aan verandering onderhevig zijn.

Klik op het Monorail/Maglev icoon in het menu om het Monorail/Maglev Tools Menu te openen.

In het Monorail/Maglev Werktuigen Tools Menu kunnen, van links naar rechts, de volgende tools voorkomen:

Monorail/Maglev baan: bouwt de verschillende monorail-/maglevbaangedeeltes tussen twee punten. Een monorail- en maglevbaan kan alleen in in de richting van een helling gebouwd worden en kan niet door ruig terrein, door water en door andere obstakels gebouwd worden. Een nieuwe baan kan/mag gebruik maken van een al bestaand stuk baan dat eigendom is van dezelfde speler.
Klik om een baan te bouwen op een van de baanopties in het menu (de cursor verandert nu), klik dan in het spel-scherm op de plaats waar de baan moet beginnen en klik tenslotte in het spel-scherm op het eindpunt van de baan.
{TIPS: - verschillende baantypen kunnen gekoppeld worden door gebruik te maken van de koppelstukken uit het menu. - gebruik de Land ophogen/verlagen tool om het terrein aan te passen zodat het bouwen van een baan mogelijk wordt. - gebruik de Verwijder tool om obstakels te verwijderen.}

Verwijder monorails: verwijdert een, gedeelte van een, monorail-/maglevbaan. Er mogen geen voertuigen aanwezig zijn op het te verwijderen baangedeelte (stations en seinen op het baangedeelte worden wel verwijderd). Het gebruik van de tool kost geld.
Klik om een stuk baan te verwijderen op de Verwijder monorails tool; klik dan in het spel-scherm op de het eerste stuk baan dat verwijdert moet worden en tenslotte op het laatste stuk baan dat verwijderd moet worden. Het tussenliggende stuk baan (incl stations en seinen) wordt nu verwijderd.

Bruggen en koppelstukken: worden gebruit om bruggen/koppelingen te bouwen tussen twee monorail/maglevbanen. Bruggen hebben een maximum lengte, als de te overbruggen afstand te groot is zal geen brug gebouwd worden. Koppelingen worden gebruikt een standaard monorailbaan en een verhoogde monorailbaan met elkaar te verbinden.
Klik om een brug of koppelstuk te bouwen op de betreffende optie in het menu (de cursor verandert nu) en klik op een uiteinde van een monorail-/maglevbaan. Op dit punt wordt gestart met het bouwen van de brug/koppelstuk.
{TIPS: - gebruik de Verwijder tool om obstakels te verwijderen. - gebruik de monorail/maglevbaan opties om een los einde van een brug te verbinden met de monorail-/maglevbaan.}

Seinen worden gebruikt om de loop van monorail/maglevtreinen te controleren. Het werken met seinen wordt in uitgelegd in het hoofdstuk Seinen.

Remise (depot): bouwt een remise om monorail/maglev treinen te kopen en te beheren. Een remise heeft onderhoudskosten en wordt gebouwd op een uiteinde van een monorail-/maglevbaan.
Klik om een remise te bouwen op de remise optie in het menu (de cursor verandert in een remise) en klik op een uiteinde van een monorail-/maglevbaan.

Haltes: noodzakelijk om het in- en uitladen van passagiers, post en vracht mogelijk te maken. Er zijn verschillende haltes voor passagiers, post en vracht. Meestal wordt dit met behulp van kleine icoontjes aangegeven. De capaciteit voor passagiers, post en vracht is per halte verschillend. Een halte heeft onderhoudskosten en kan overal op de monorail-/maglevbaan gebouwd worden (behalve in bochten en kruisingen). Wanneer een halte niet direct naast een andere halte gebouwd wordt zal er een nieuwe halte gebouwd worden.
Klik om een halte te bouwen op de betreffende halte optie in het menu (de cursor verandert in een halte) en klik op de gewenste plaats op de monorail-/maglevbaan. Door meerdere haltes direct naast elkaar te plaatsen kan de capaciteit van de halte uitgebreid worden of kan de halte geschikt gemaakt worden voor meerdere soorten vervoer. Bijvoorbeeld passagiers en vracht.
{TIPS: - verwijder uitbreidingen met de verwijder tool. - druk op [v] om het dekkingsgebied van het station te tonen of te verbergen. - gebruik [Ctrl] om monorail-/maglevbanen te bouwen op bruggen of om verhoogde banen te bouwen boven een lage baan.}

Monorail fundament: cre-eert ?een uitbreiding voor een halte en vergroot de capaciteit van de halte. Monorail fundamenten worden gebouwd op het uiteinde van een monorail-/maglevbaan.
Klik om een fundament te bouwen op de fundament optie in het menu (de cursor verandert nu) en klik op een uiteinde van een monorail-/maglevbaan waar je het fundament wilt bouwen.

simutrans-124.3/simutrans/text/nl/mouse.txt000066400000000000000000000023741474050137200210740ustar00rootroot00000000000000Muisbediening Help (Nederlands)

Muisbediening Help

Muisbediening geeft informatie hoe met de muis om te gaan met schermen en het wijzigen van de grootte om lijsten beter in beeld te krijgen.

Hoe een schermgrootte te wijzigen in Simutrans: klik op rechteronderhoek van een scherm (gemarkeerd met horizontale strepen) waarvan je de grootte wilt wijzen en klik met de linkermuisknop en houdt deze ingedrukt. Sleep de muis over het scherm om de grootte aan te passen.

Richtingen:
Naar links: het scherm wordt smaller
Naar rechts: het scherm wordt breder
Naar boven: het scherm wordt kleiner, er worden minder regels getoond
Naar beneden: het scherm wordt groter, er worden meer regels getoond
Diagonaal: combineert de bovenstaande mogelijkheden, bijvoorbeeld diagonaal rechts naar beneden zal het scherm groter en breder maken.

Een aantal schermen heeft links en rechts van een bepaalde optie een horizontale pijl staan. Hiermee is het mogelijk om te bladeren in een lijst met waardes.
De linkerpijl zal naar de vorige of lagere waarde gaan
De rechterpijl zal naar de volgende of hogere waarde gaan

simutrans-124.3/simutrans/text/nl/signals.txt000066400000000000000000000054641474050137200214070ustar00rootroot00000000000000Seinen Help (Nederlands)

Seinen

Seinen worden gebruikt om de loop van treinen, trams en monorail/maglevs te controleren bij stations, kruisingen, bruggen etc. Ze verdelen het spoor in baanvakken. In een baanvak kan zich maar een trein tegelijk bevinden.

Er zijn verschillende soorten seinen:
- (normale) Seinen
- Voorseinen
- Keuzeseinen
Seinen kunnen in eenrichting- en tweerichtingmode gebouwd worden. In eenrichtingmode kan een sein maar in een richting gepasseerd worden. Let er bij het gebruik van eenrichtingseinen op dat de treinen hun bestemming wel kunnen bereiken. Houd in het begin een eenrichtingsbaanvak extra in de gaten.

Seinen: treinen passeren een normaal sein alleen als het baanvak tot het volgende sein of tot de bestemming (station/halte) niet bezet is door een andere trein.

Voorseinen: treinen passeren een voorsein alleen als de volgende twee baanvakken niet bezet zijn door een andere trein of als de volgende baanvakken tot de bestemming (station/halte) niet door een andere trein bezet zijn.

Keuzeseinen: sturen een trein naar een beschikbaar (leeg) perron. Bij een station met meerdere perrons mag een trein een willekeurig beschikbaar perron gebruiken. Als er geen beschikbaar perron is zal de trein bij het sein blijven wachten.

Bouw en positie: Seinen kunnen alleen op trein, tram of monorail/maglev banen gebouwd worden. Er kan maar een sein per veld zijn; het kortst mogelijke baanvak is dus twee velden lang. Neem voor het bepalen van de baanvakgrootte de lengte van de langste trein in velden en tel daar nog een veld bij op. Dit bevordert een soepele dienstregeling.

Klik om een sein te bouwen op de betreffende sein optie in het menu (de cursor verandert in een sein) en klik op de gewenste plaats op de baan. Er wordt nu aan beide zijden van de baan een sein geplaatst. Het sein kan nu in twee richtingen gepasseerd worden (tweerichtingenmode). Klik nogmaals op hetzelfde veld waar het sein geplaatst is en er zal een sein verdwijnen, en het sein kan alleen nog in de richting van het sein gepasseerd worden (eenrichtingmode). In het algemeen staan seinen in Simutrans aan rechter zijde van het spoor/baan. Bij de volgende klik wordt de toegestane richting omgedraaid; het sein staat aan de andere kant van het spoor/baan. Door hierna nog een keer te klikken kom je weer in de beginsituatie (tweerichtingenmode).

Werkzaamheden aan het spoor kun je door twee blokkerende seinen ongestoord uitvoeren. Na het aanpassen van een baanvak herstel je de seinen weer naar "normaal" bedrijf. Open dan de getroffen lijnen (via lijnManagement, Klik op "Klaar" waarna de route opnieuw wordt ingelezen en de treinen weer gaan rijden.

simutrans-124.3/simutrans/text/no.tab000066400000000000000000000321221474050137200176700ustar00rootroot00000000000000Norsk PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: no Norsk # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable av cl_btn_filter_enable på cl_btn_filter_settings Innstillinger cl_btn_sort_asc Stigende cl_btn_sort_desc Synkende cl_btn_sort_id ID-nummer cl_btn_sort_income Inntekt cl_btn_sort_name Navn cl_btn_sort_type Type clf_btn_alle alle clf_btn_invers bytt clf_btn_keine ingen gl_btn_sort_bonus bonus hlf_btn_invers bytt hlf_btn_keine ingen Networks Nettverk #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktisk klima desert ørkenklima mediterran middelhavsklima rocky alpint klima temperate temperert klima tropic tropisk klima tundra tundraklima #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Monorails are not available yet! Monorailer er ikke tilgjengelig enda! Not enough money! Ikke nok penger! Zughalt muss auf\nSchiene liegen!\n Togstasjoner maa\nplasseres paa togskinner.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Tastatur hjelp\n

Tastatur hjelp

\n

\nTastatur hjelp viser funksjonene til de forskjellige tastene på tastaturet.\n

\n

\nTastatur hjelp aapnes ved aa taste en ugyldig hurtigtast eller via Generell hjelp.\n

\n

\nStore og smaa bokstaver er forskjellige hurtigtaster (bruk [Shift] for store bokstaver).\n

\n

\nHurtigtaster inkluderer:\n

\n

\n[Piltaster]: flytter spillervindu i pilens retning.
\n[Backspace]: lukker alle vinduer, verktøylinjer og hjelpetekster.
\n[Del], eller [Esc]: lukker oeverste windu, verktøylinje eller hjelpetekst.
\n[Enter], eller [Return]: brukes for å bekrefte handlinger.
\n[Pg-Up], eller [>]: zoom-inn spillervindu.
\n[Pg-Dn], eller [<]: zoom-ut spillervindu.\n[F1]: aapner Simutrans hjelp.

\n

\n[1]: flytter spillervindu mot soer.
\n[2]: flytter spillervindu mot soeroest.
\n[3]: flytter spillervindu mot oest.
\n[4]: flytter spillervindu mot soervest.
\n[6]: flytter spillervindu mot nordoest.
\n[7]: flytter spillervindu mot vest.
\n[8]: flytter spillervindu mot nordvest.
\n[9]: flytter spillervindu mot nord.\n

\n

\n[Shift] + mus: brukt paa Kart for aa se informasjon om Industriers leveranse-kjeder.
\n[CTRL] + verktoey: lager (signaler og Stasjoner) paa et hoere nivaa; eller bygger veier eller spor med lav hastighet over veier og spor med høy hastinghet; eller bygger rettere (mer direkte) veier og spor.
\n[CTRL] + ([F2] til [F12]): for aa legge til markert verktoey som hurtigtast på tastene [F2] til [F12].\n

\n

#____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s har naa\nbussforbindelse mellom\n%s og\nattraksjon\n%s\n(%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s har naa\nbussforbindelse mellom\n%s og\nfabrikk\n%s\n(%i,%i).\n Airline service by\n%s\nnow between\n%s \nand %s.\n Nå flyr %s mellom\n%s og %s!\n #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %ss har bygget nytt hovedkontor. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (i depot) \nBauzeit bis til \nBauzeit von \nProduseres fra \nCan't open heightfield file.\n \nKan ikke aapne hoeydekart.\n \ndirection: \nretning: \nelektrified \nelektrifisert\n \nHeightfield has wrong image type.\n \nFeil filtype.\n \nis reserved by: \nreservert av tog: \nminimum speed: \nminimum hastighet: \nnot elektrified \nikke elektrifisert\n \nRibi (masked) \nretninger (tillatte) \nRibi (unmasked) \nretninger (alle): \nSet phases: \angi tidsintervall NS/ØV retning: \nsingle way \nenveisstrekning \nway1 reserved by \nvei 1 er reservert av \nway2 reserved by \nvei 2 er reservert av \nwith sign/signal\n \n med skilt/signal\n %d convois %d kjøretøy %d Einzelfahrzeuge im Depot %d kjoeretoey parkert her. %i km/h (max. %ikm/h) %i km/t (maks. %ikm/t) %i years %i months old. %i år %i måned(er) gammel. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s\noppfoerte et nytt\nraadhus naar\ninnbyggertallet steg\n til over %i. %s\nis crowded. er overfyldt. 1WORLD_CHOOSE Innstillinger for Nytt spill: 2LIGHT_CHOOSE Farger: 2WORLD_CHOOSE Kart nummer: 5LIGHT_CHOOSE Fotgjengere på holdeplasser 5WORLD_CHOOSE Ant. byer: 6LIGHT_CHOOSE Fotgjengere i byer Abfrage Inspeksjonsverktøy Abnehmer Forbruker About scenario Opphavsrett Abriss Rivningsverktøy Absenken Senk jordnivå Abspanntransformator Transformatorstasjon Accelerate time Øk spillhastighet Add forest Legg til skog add server Legg til server Add Stop Legg til Add stops for backward travel Legg til stopp på veien tilbake. aircraft_tab Frakt airplane fly Airport Flyplass AIRTOOLS Flyplassverktøy All Alle Allow city growth Tillat ekspansjon av byer Allow player change Tillat spillerbytte allowed climates:\n Klimasoner: Alters a schedule. Endrer rute Angenommene Waren -- Varer som kan leveres anhaengen Heng på Anhaenger_tab Tilhengere Anheben Hev land Appends stops at the end of the schedule Legg til stopp på enden av ruta Apply Line Bruk rute Arbeiter aus: Arbeidere bor i: Arrivals from\n Ankommende fra\n Arrived Ankommet Assets Øvrige aktiva Aufspanntransformator Transformatorstasjon Autohalt muss auf\nStrasse liegen!\n Buss- og lastebilholdeplasser må ligge på en vei.\n Available Tilgjengelig Bahndepot Lokstall/Vognhall Bankrott:\n\nDu bist bankrott.\n Konkurs:\n\nDu er konkurs!\n battery Batteri Baum Tre baum builder Plant trær Baustelle Byggeplass Beenden Avslutte Beginner mode Begynnermodus Besonderes Gebaeude Turistattraksjon BF stasjon bio biologisk Blockstrecke ist\nbelegt\n Linjeblokk er\nopptatt\nav et annet tog\n Boden Land Bonusspeed: %i km/h Maks. mulige hastighet: %i km/t bridge is too high for its type! Dalen er for dyp for \ndenne type bro!\n Bridge is too long for this type!\n Spennet blir for\nlangt for denne brotypen!\n Bruecke Bro Bruecke muss an\neinfachem\nHang beginnen!\n Broer må\nbegynne på\nrette bakker!\n Brueckenboden bro Build air depot Bygg flyhangar build choosesignals Innfartssignaler Build city market Bygg ny butikk Build drain Bygg drenering build HQ Bygg hovedkontor Build land consumer Bygg kraftverk Build maglev depot Vognhall for Maglev Build monorail depot Monorailvognhall Build narrowgauge depot Vognhall for smalsporet jernbane Build powerline Bygg Kraftlinje Build road depot Verkstedhall Build ship depot Skipsverft Build signals Bygg signaler Build train depot Bygg lokstall/vognhall Build tram depot Bygg trikkestall/bybanevognhall Build truck depot Bygg verkstedhall Building costs estimates Estimert byggekostnad Buildings Ant. bygninger Built artifical slopes Lag bakker Built random attraction Bygg en vilkårlig turistattraksjon Bus_tab Busser Can only move from halt to halt or waypoint to waypoint. Kan bare flytte \nfra holdeplass til holdeplass eller \nfra veipunkt til veipunkt. Cancel Avbryt Capacity: Kapasitet: Capacity: %s\nLoad: %d (%d%%) Kapasitet: %s\n? %d (%d%%) Cash Penger Change player Bytt spiller chooses a random map Velg et tilfeldig kart. cl_txt_sort Sorter etter: clf_chk_aircrafts Fly clf_chk_noincome mangler inntekt clf_chk_ships Skip clf_chk_trains Tog closed Stengt Configure AI Konfigurer KI Constructed by Tegnet av Constructed by %s Tegnet av %s Construction_Btn Byggekostnader Costs Koster December Desember Destroying map ... Ødelegger kart... Details Detaljer Dock Havn Dock must be built on single slope! Havnen må bli bygget på skrå-bakke Electricity Elektrisitet Enter Password Skriv inn passord Error Feil Fabrikname Fabrikknavn follow me Følg meg. Found new city Lag en ny by go home Kjør til depot Help Hjelp January Januar join game Bli med i spill July Juli June Juni Kann Spielstand\nnicht laden.\n Kan ikke laste lagret spill! Kein Besitzer\n Eksisterer ikke! keine ingen Keyboard_Help\n Tastaturhjelp\n koord koordinater Lade Relief Last høydekart Last Year Siste år Legend Legende Line Linje Load game Last inn lagret spill Load scenario Last inn Scenario loaded lastet inn loaded passenger/freight Sorter pass./gods etter: Loading addon paks ... Laster tilleggspakke (add-on)... Loading map ... Kartet lastes... Loading paks ... Leser inn pak... Mailbox Mailboks max Max Months Måneder Mountain height Høyde på fjell: Name Navn Neue Karte Nytt kart Neue Welt Generer Nytt spill New Vehicles Nytt kjøretøy no load ingen last Number of rivers Antall elver Object Objekt open Åpen Optionen Innstillinger Ownership Eierskap Password Passord player spiller player 0 Spiller 0 player 1 Spiller 1 player 10 Spiller 10 player 11 Spiller 11 player 12 Spiller 12 player 13 Spiller 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 7 Spiller 7 player 8 Spiller 8 player 9 Spiller 9 Power Kraft random tilfeldig Random age tilfeldig aar Random map Tilfeldig kart Rathaus Raadhus Reliefkarte Kart Remove Fjern remove powerlines Fjerne kraftlinje remove roads fjerne veier road vei Rotate map Roter kart sail Seil Saving map ... Lagrer kart ... Schienentunnel Bygg togtunnel Schiff_tab Skip Schiffdepot Skipsverft Sehenswuerdigkeit Turistattraksjon SEP_FRACTION . SEP_THOUSAND Setting Innstillinger Ship Skip Show all Vis alle show all building Vis alle bygninger Show industry Vis industri show station coverage Vis dekningsomraade for stasjon show station names vis navn paa stasjoner Show/hide statistics Vis/skjul statistikk Size (%d MB): Stoerrelse (%d MB): Sound Lyd Sound settings Innstillinger for lyd Speichern Lagre Spieler Spiller Spieler(mz) Spillere Spielerliste Spillerliste Spielstand wurde\ngeladen!\n \nInnlasting av spill vellykket.\n Spielstand wurde\ngespeichert!\n \nLagring av spill vellykket.\n Sprache Språk Sprachen Språk Starte Spiel Start spill steam damp Storage capacity Lagringskapasitet sued Soer suedost Soeroest suedwest Soervest Suppliers Leverandører Tage alt dager gammel. This Month Denne mnd This Year I år: tl_title Byoversikt Towns Byer Traffic Trafikk Train Tog Translation Oversettelse transparent station coverage gjennomsiktig dekningsomraade Unemployed Arbeidsloes units/day enheter/mnd upgrade HQ Oppgradere HK Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Gjeld maa tilbakebetales\n innen %d mnd.\n Waggon_tab Biler waiting venter Wert Verdi west Vest Year %i has started. Aar %i har startet. Years Aar #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL by &1_CITY_SYLL stad &4_CITY_SYLL berg &5_CITY_SYLL berg &6_CITY_SYLL dal &7_CITY_SYLL fjell &8_CITY_SYLL foss &9_CITY_SYLL sjø &A_CITY_SYLL vann &B_CITY_SYLL sand &C_CITY_SYLL hei &D_CITY_SYLL vik &E_CITY_SYLL ås %1_CITY_SYLL Lunde %2_CITY_SYLL Mos %3_CITY_SYLL Nord %4_CITY_SYLL Vest %5_CITY_SYLL Sør %6_CITY_SYLL Øst %7_CITY_SYLL Skog %8_CITY_SYLL Kristian %9_CITY_SYLL Haug %A_CITY_SYLL Viks %B_CITY_SYLL Ask %D_CITY_SYLL Fjell %E_CITY_SYLL Tran %F_CITY_SYLL Gran simutrans-124.3/simutrans/text/ol.tab000066400000000000000000001554571474050137200177070ustar00rootroot00000000000000§Livvinkarjal PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: olo Livvinkarjal # # Encoding: UTF-8 # # Font: Prop-Latin1.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Näytä kuun aijat dd:hh:mm-muvvos AMBIENT_SOUND Ymbaristön iänet: CASH_SOUND Rahan kilahtus: cl_btn_filter_disable Iäre piäl cl_btn_filter_enable Piäl cl_btn_filter_settings Laitokset cl_btn_sort_asc Nouzeva cl_btn_sort_desc Laskeva cl_btn_sort_id Syvainp. ID cl_btn_sort_income Tulot cl_btn_sort_name Nimi cl_btn_sort_type Tiippu clf_btn_alle kaikin clf_btn_invers inv. clf_btn_keine ei nimidä climate area percentage Ilmastopalstoin suurus: CROSSING_SOUND Tazorist. varoitusiänet: FACTORY_SOUND Zavodoin iänet: Find matching convois EÄi luajivie kulgunevvoloi gl_btn_sort_bonus Bonus gl_btn_sort_name Nimi gl_btn_sort_revenue Bizn. oborottu gl_btn_unsort Ei nimidä height based Ilmaston mugaine hl_btn_filter_disable Iäre piäl hl_btn_filter_enable Piäl hl_btn_filter_settings Laitokset hl_btn_sort_asc Nouzeva hl_btn_sort_desc Laskeva hl_btn_sort_name Nimi hl_btn_sort_type Tiippu hl_btn_sort_waiting Vuottau hlf_btn_alle kaikin hlf_btn_invers inv. hlf_btn_keine ei nimidä humidities Kostevusrajat: Install Azeta pakiettusarjoi Lake Järvi Lake height Järven enimäiskorgevus: Maximize height levels Laita korgevustazot maksimumih moisture land Nosta muan yl: moisture water Nosta vien yl: Networks Liiniiverko Num pad keys always move map Älä käytä numpad-kluaviššoi kartan liikuttamizeh Open Sea Meri Queueing Vuottajien muutos rainfall Kostevuon mugah Reselect closes tools Ruadoinstr:n valliÄuksen iäreottuamine uuvessahvalliÄuksel Road toll Tiemaksut Scenario Tieduo skenuariospäi sea meri Single GUI Yksil. käyttöl. Sound range: Iänen aloveh: Start this as a server Pane serveru käymäh temperature borders Lämbörajat: temperature-humidity based Temperatuuran/kostevuon mugaine TOOL_SOUND Ruadoinstr. iänet: TRAFFIC_SOUND Likendehen iänet: Transfers Vaihtoi #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktilline desert kuivikko mediterran välimerelline rocky alppi-ilmasto temperate lauhkei tropic tropiiÄeskoi tundra tundru #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed SkenuarioÅ¡riftan täyttiämine ei mennyh hyvin. Bridge blocked by way below or above. Sildu on typitty ylähän- libo alahanpäi. Can't buy obsolete vehicles! Et voi ostua tuotandospäi otettuloi kulgunevvomalliloi. Cannot alter water Tädä basseinua ei voi tyhjendäy libo täyttäy enämbäh. Cannot build on a double slope! Objektan voi srojie vaiku yksittäismägeh libo tazazeh muah. Cannot built depot here! Depoa ei voi srojie täh. Cannot built this station/building\nin underground mode here. Tädä azemua/srojua ei voi srojie muan alle. Cannot create generic line!\nSelect line type by\nusing filter tabs. Ei voitu luadie ylehispäi liiniedy! ValliÄÄe liinin tiippu enzin. Cannot create socket Yhtevyön luadimine ei mennyh hyvin. (ei voitu luadie socketoa) Cannot rotate this building! Tädä srojua ei voi kiändäy. Client closed connection during transfer Klijentu katkai yhtevyön tiijonsiirron aiguna. Convoi handles exhausted! Kulgunevvoloin enimäismiäry tavattih. Convoy already deleted! Kulgunevvo on jo otettu iäre. Could not open file Tiijostuo ei voitu avata. Das Feld gehoert\neinem anderen Spieler\n Plitku on toizen kižuajan omistukses. Der Besitzer erlaubt das Entfernen nicht Omistai ei ole andanuh lubua objektan ottamizeh iäre. Diese Zusammenstellung kann nicht fahren!\n Tädä yhtistelmiä ei voi käyttäy. Flugzeughalt muss auf\nRunway liegen!\n Seizondupaikan tulou olla ruloamisdorogal. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Lendokentysrojua ei voi srojie täh. Hier kann kein\nSignal aufge-\nstellt werden!\n Likendehenohjavuslaitetta ei voi panna täh. In order to lock the game, you have to protect the public player by password! Sinun pidäy suojata julgine kižuaju peittosanal, ga voit lukita kižan. Loading a new game will end the current server session! Uvven kižan täyttiämine loppie nygözen serveruistundon, oletgo varmu? Lost connection\nto server! Yhtevys serverale menetettih. Lost synchronisation\nwith server. Sinhronizatsii serverale menetettih. Maglevhalt muss auf\nMaglevschiene liegen!\n Maglev-azetus tulou panna maglev-raudutiele. Monorailhalt muss auf\nMonorail liegen!\n Yksiraizivoazetus tulou panna yksiraizivotiele. Monorails are not available yet! Yksiraizivotiet ei ole vie suadavannu. More than one possibility to build this dock found. Portan srojimizeh löydittih muidagih taboi. ValliÄÄe taba valliÄemal portu uuvessah Ctrl+klikil. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Kaiduraizivoazetus tulou panna kaiduraizivotiele. No bridges over runways! Sildoi ei voi srojie lennätysdorogoin yli. No curves on runways Lennätysdorogat ei voi ruadua kiännälmyksii. No suitable crossing Sobijua ristavustu ei löytynyh. (enimäisvauhti liijan suuri?) No suitable way on the ground! Azetukset voi panna vaiku tazazele muale, oigien luaduzele da suorale tiele. No through station here! Azemat tulou panna tien piäteheh libo suorale vuitile, mis ei ole ristavuksii. Not enough bytes transferred Tavuloi ei siirretty tävveliste. Not enough clearance. Kahten tien välil pidäy olla vähimytteh kahten yksikön korgevusero. Not enough money! Sinul ei ole tävveliste rahua tämän ostamizeh. On narrowgauge track only!\n Tämä meneh hyvin vaiku kaiduraizivotiel. Only public player can lock games! Vaiku julgine kižuaju voi lukita kižoi. Only up and down movement in the underground! Muanalaistu plitkua voi vaiku heittäy ylembäkse libo alembakse tarvittavien ruadoinstrumentoin kel. Out of funds Sinul ei ole tävveliste rahua jällel täh. Post muss neben\nHaltestelle\nliegen!\n Levendämissroju (ezim. poÅ¡tutoimisto, varasto) tulou srojie azetuksien/azemien rinnale. Protocoll error (expecting game) ProtokoloÅ¡ipku (vuotettih kižua) Schiffhalt muss im\nWasser liegen!\n Laivuazetuksen voi panna vaiku veteh, portan viereh. Server busy Serveru on tungokselline. Server version too new Serveru käyttäy uvvembua versieda kižas. Show all revenue messages Näytä kaikin oborottuviestit Show no revenue messages Älä näytä oborottuviestilöi Show only player's revenue Näytä vaiku kižuajan oborottu Terraforming not possible\nhere in underground view Muata ei voi ruadua muan al. This tunnel branches. You can try Control+Click to remove. Tunnelil on enämbän kui kaksi sydämehpiäzyä. Ottuakses tunnelin iäre, käytä Ctrl+klikkuaustu. Too far away to merge stations! Azemat on liijan loitton toizispäih. Upgrade must have\na higher level Päivityksen tulou olla korgiemboa tazoa. Vehicle %s cannot choose because stop too short! Kulgunevvo %s ei voi vallita pristania gu azetus on liijan lyhyt. Zughalt muss auf\nSchiene liegen!\n Raudutieazemat voi srojie vaiku raudutiele. #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Ohjavo

Opasluvettelo

Tieduo Simutransispäi

%1$s

Käyttö

%2$s

Kižan alguamine

%4$s

Kižuamine

%5$s

Ruadoinstrumentat

%3$s

Muut dialougat

%6$s Keyboard Help\n

Keyboard Help

\n Klaviatuuran käyttö

Klaviatuuran käyttö

Klaviatuuran käyttöohjavo avavuu painamal kluaviššua, mi ei ole muus käytös, libo ylehizen ohjavon kauti.

Kluaviššukomandat huomavoi kirjainsuuruon (käytä [Shift]-kluaviššua suajakses suuret kirjaimet).

Tulieloil kluaviššukomandil on miäritelty tietyt funksiet:

[nuolikluaviššut]: vieretä kižanägymiä nuolen suundah.
[askeltyöndin]: salbua kaikin ikkunat da ruadoinstrumentupalkat.
[Delete], libo [Escape]: salbua ylin ikkun/ruadoinstrumentupalkku.
[Page Up], libo [>]: lähendä kižanägymiä.
[Page Down], libo [<]: loitonda kižanägymiä.
[Ctrl] + ruadoinstumentu: sroji suorembii tielöi (daže boikoimbien tielöin yli) libo muuta valliÄuskundo inversiellizekse kyzelyn libo iäreottuamizen aiguna.

At least one stop is connected to the town. Yhtelläh yksi azetus on liitätty linnah. At least one tile is connected to one stop. Yhtelläh yksi plitku on liitätty yhteh azetukseh. Color according to transport capacity left Näytä värit jällel olijale kulletussijan miäräle Color-coded terrain according to altitude. Näytä alovehen muvvot Decrease water height Alenda vientazuo Highlight railroad tracks Näytä raudutiet Highlite depots Näytä depot Highlite electrical transmission lines Näytä sähkönsiirdoliiniit Highlite factories Näytä zavodat Highlite forests Näytä meÄÄät Highlite tourist attraction Näytä turistunähtävykset Increase water height Nosta vientazuo Open station/stop details Näytä azeman/azetuksen tiijot Overlay city limits Näytä linnoin rajat Overlay passenger destinations when a town window is open Näytä passažiiroin piämiärät linnan tiedoikkunan olles avvoi Overlay schedules/network Näytä reitit da liinit Overlay town names Näytä linnoin nimet Please click on the map to add\nwaypoints or stops to this\nschedule. Klikkua kartua lizätäkses välietuappoi libo azetuksii reitile. Set tile climate %s Laita muan ilmastokse %s Show capacity and if halt is overcrowded Näytä azetuksen sijan miäry da tila Show how many convoi reach a station Näytä azetuksele piäzejjen kulgunevvoloin miäry Show how many people/much is waiting at halts Näytä vuottavien passažiiroin miäry Show initial passenger departure Näytä passažiiroin da poÅ¡tan lähtöÄökehet Show level of city buildings Näytä linnusrojuloin tazo Show mail service coverage/mail network Näytä poÅ¡tupalvelan kattavus/verko Show passenger coverage/passenger network Näytä hengilölikendehen kattavus/verko Show speedlimit of ways Näytä tielöin enimäisvauhtit Show the change of waiting at halts Näytä vuottajien miärän muutos viime kuuh verduttuna Show the owenership of infrastructure Näytä infrastruktuuran omistavus Show transported freight/freight network Näytä vedolikendehverko Show usage of network Näytä kulgunevvoloin miäry per plitku da kuu Shows a listing with all industries on the map. Näytä luvettelo kaikispäi tevollizusaloispäi kartal Sum of departure/arrivals at halts Näytä tullejjen da lähtenejjen kulgunevvoloin miäry #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s ajeleh nygöi avtobussuliiniedy välil %s - %s (%i,%i). %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s ajeleh nygöi avtobussuliiniedy välil %s - %s (%i,%i). %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). Yhtivön %s %i rekkua huolehtii kulletuksispäi välil %s (%i,%i) - %s (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s avas uvven raudutien välile %s (%i,%i) - %s (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n %s lendäy nygöi välil %s - %s. Ferry service by\n%s\nnow between\n%s \nand %s.\n %s ajeleh nygöi lauttua välil %s - %s. Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s ajeleh nygöi loittolikendehen avtobussuliiniedy välil %s - %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Kartan kohendelemine LISTTOOLS Luvettelot MAGLEVTOOLS Maglev-raudutiet MONORAILTOOLS Yksiraizivotiet NARROWGAUGETOOLS Kaiduraizivotiet RAILTOOLS Raudutiet ROADTOOLS Dorogat SHIPTOOLS Laivat SLOPETOOLS Muan kohendelemine SPECIALTOOLS Spetsial'noit ruadoinstrumentat TRAMTOOLS Tramvait #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s on srojinuh uvven piäkantoran. Factory chain extended\nfor %s near\n%s built with\n%i factories. Talovuskazvo raveneh: %s levendäy omua tuotanduo linnan %s alovehel. %i uuttu zavodua perustettih. Net wealth less than 10%% of starting capital! Nettovarakkahus on alle 10%% algupiäomazuospäi! New %s now available:\n%s\n Uuzi %s nygöi suadavannu:\n%s New factory chain\nfor %s near\n%s built with\n%i factories. Uuzi %s on välifirmoineh avuattu linnan %s lähäl. %i uuttu zavodua srojittih. New vehicle now available:\n%s\n Uuzi kulgunevvo nygöi suadavannu:\n%s Now %u clients connected. Täl kodvazel %u klijentua on yhtistetty. overtaking menöy siiriÄi Remove vehicle from map. Use with care! Ota kulgunevvo iäre kartalpäi. (Käytä vardoiÄen!) Screenshot\ngespeichert.\n Kuvakuabavus tallendettu. Sends the convoi to the last depot it departed from! Työnnä kulgunevvo viimezimbäh depoh mispäi se on lähtenyh. Server preparing game ... Serveru valmisteleh kižua... Trees Puut: With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s sroji uvven mustomerkin. %i eläjiä vietti vällypäiviä sen kunnivokse. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Liiniifiltru #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/kuu) (%.2f$/km) (%.2f$/km) (%i)- (%i) (in depot) (depos) [0] south-facing [0] suven suundaine [1] east-facing [1] päivännouzun suundaine [2] north-facing [2] pohjaizen suundaine [3] west-facing [3] päivänlaskun suundaine [4] southeast corner [4] liidehine kulmu [5] northeast corner [5] koilline kulmu [6] northwest corner [6] luodehine kulmu [7] southwest corner [7] lounaine kulmu \nBauzeit bis vuoteh \nBauzeit von \nValmistettu vuodespäi \nCan't open heightfield file.\n Korgevuskuvua ei voitu avata. \ndirection: \nSuunnat: \nelektrified \nSähköstetty\n \nHeightfield has wrong image type.\n Korgevuskuva on viäränluaduine. \nis reserved by: \nVuitil on juna \nminimum speed: \nVähimäisvauhti: \nnot elektrified \nEi sähköstetty\n \nRibi (masked) \nSuunnat\m (masku): \nRibi (unmasked) \nSuunnat\n (ei maskia): \nSet phases: \nReguliirui aiguvälilöi:\n p.-s. -> pl.-pn. -> siirros \nsingle way \nYksisuundaine \nway1 reserved by \nTiedy 1 käyttäy \nway2 reserved by \nTiedy 2 käyttäy \nwith sign/signal\n \nMerki-/valo-ozuttimel\n %d buildings\n %d srojua\n %d convois %d kulgunevvuo %d Einzelfahrzeuge im Depot %d kulgunevvuo depos %i car(s), %i vagonua, %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. Igä: %i vuottu da %i kuudu %s at (%i,%i) now public stop. Azetus %s on muuttunuh julgizekse vaihtopaikakse. %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s kenty %s has entered a depot. Kulgunevvo %s on tulluh depoh. %s land %d %s %s %d kyläaloveh %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s sroji uvven linnantaloin, ku se tavatti %i eläjän rajan. %s\nis crowded. Azetus %s on tungokselline. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nYlen suuri vauhti %3$i km/h\n\nNygöine vauhti %2$i km/h.\n\n %s\nwas liquidated. %s on mennyh maksukyvyttomäkse. Kaikin ruado loppiettih, da yhtivön omazus myötih. %u Client(s)\n %u klijentu(a)\n %u Player (%u locked)\n %u kižuaj(u)a (%u lukittu(u))\n

Error

OÅ¡ipku: Monda yhtenluaduistu objektua pakiettusarjan piäeÄÄomistos

Koht(i/a)s

Warning

addons for

OÅ¡ipku: Monda yhtenluaduistu objektua lizäozan eÄÄomistos

Lizäozis koht(a/i)le 1 convoi 1 kulgunevvo 1 Einzelfahrzeug im Depot 1 kulgunevvo depos 100 km/h = %i tiles/month 100 km/h = %i plitkua/kuu 1LIGHT_CHOOSE Kirkavus: 1WORLD_CHOOSE Uvven kižan laitokset: 2LIGHT_CHOOSE Värit: 2WORLD_CHOOSE Kartan noumer: 3LIGHT_CHOOSE Vieretysvauhti: 4LIGHT_CHOOSE Inversiellizet vieretyssuunnat 5LIGHT_CHOOSE Kävelijöi azetuksil 5WORLD_CHOOSE Linnoin lugumiäry: 6LIGHT_CHOOSE Kävelijöi linnois 6WORLD_CHOOSE Likendehen tihevys: 8WORLD_CHOOSE Päivy/yö-kierdo A bridge must end on a way! Sillan tulou loppie tiele. A bridge must start on a way! Libo et omista sillan mollembii piälöi, libo reiti on typitty. Abfrage Tutki Abnehmer Kuluttai: About Tieduo About scenario Avtoranvallat Abriss Hävitä/ota iäre Absenken Heitä muata alembakse Abspanntransformator Transformuator Accelerate time Boikonda aigua Act. load: %u MW\n Akt. takku: %u MW\n Active player only Vaiku aktiivine kižuaju Add forest Liziä meÄÄiä Add random citycar Liziä piävyndähine hengilöavto add server Liziä serveru Add Stop Liziä azetus Add stops for backward travel Liziä azetuksii tulomatkale. air Lennätys-/ruloamisdorogu Aircraft Lendoliinii aircraft_tab Gruuzulendokonehet airplane lendokoneh Airport lendokenty AIRTOOLS Lendokentät All Kaikin all convoi tooltips Kaikin kulgunevvon tiijot Allow city growth Anna luba linnan kazvole Allow player change Anna luba kižuajan vaihtamizele allowed climates:\n Luvallizet ilmastot:\n Alters a schedule. Muuta reitii Angenommene Waren Lähäl olijoin yrityksien tarviÄemat tavarat anhaengen Liziä Anhaenger_tab Pritsepat Anheben Heitä muata ylembäkse Appends stops at the end of the schedule Liziä azetus reitin loppuh Apply Line Laita reitile Apr. sulakuu April sulakuu Arbeiter aus: Ruadajat eläh linnois: Arrivals from\n Tuliet:\n Arrived Tulluh Assets Kulgunevvoloin arvo Aufloesen RiiÄi Aufspanntransformator Transformuator Aug. elokuu August elokuu auto avtomuatilline Autohalt muss auf\nStrasse liegen!\n Avtobussu-/gruzoviekkuazetukset tulou panna dorogan piäle. Available Suadavannu Available at custom date Suadav. tietys pvm:s algajen Bahndepot Veduridepo Bankrott:\n\nDu bist bankrott.\n Yhtivösi on mennyh maksukyvyttömäkse. battery Akkumul'uatoru Baum Puu baum builder Istuta puuloi Baustelle Srojuruadopaikku Bauzeit Srojuamisaigu Beenden Lope Beginner mode Algaitila Besonderes Gebaeude Turistunähtävys BF azemu bio Biolougine Blockstrecke ist\nbelegt\n Raudutieoza on toizen junan käytös. Boden Mua Bonus Multiplier: %i%% Bonuskerduaju: %i%% Bonusspeed: %i km/h Korgein mahtolline vauhti: %i km/h Boost (%%) Lizävys (%%) Borderless (disabled on fullscreen) Reunatoi kogo näyttö (ei käytettävänny oigies tilas) bridge is too high for its type! Sildu on liijan korgei sen tiipule. Bridge is too long for this type!\n Tugiväli on liijan pitky sillan tiipule. Bruecke Sildu Bruecke muss an\neinfachem\nHang beginnen!\n Sillat tulou algua suoraspäi mäespäi. Brueckenboden sildu Build air depot Sroji hanguaru build choosesignals Sroji pristaninvalliÄusozutin Build city market Sroji uuzi kauppu lähimbäh linnah Build drain Transformuatorazemu build HQ Sroji piäkantor Build land consumer Sroji uuzi sähkölaitos Build maglev depot Sroji maglev-depo Build monorail depot Sroji yksiraizivodepo Build narrowgauge depot Sroji kaiduraizivodepo Build powerline Sroji sähkönsiirdoliinielöi Build presignals Sroji kahtenaine suojastusozutin Build road depot Sroji garažu Build ship depot Sroji dokku Build signals Sroji ozuttimii Build train depot Sroji veduridepo Build tram depot Sroji tramvaidepo Build truck depot Sroji garažu Building costs estimates hinnoitus Buildings Srojuloi Built artifical slopes Sroji keinotegozii rindehii Built random attraction Sroji piävyndähine turistunähtävys Bus_tab Avtobusat Can be overgrown Sua olla ylikazvanuh Can only move from halt to halt or waypoint to waypoint. Kohtu voijah siirdäy vaiku azetukselpäi libo välietuapalpäi toizele. Cancel Peruuta Cannot connect to offline server! Serveru on iäre piäl, eigä se ole muga tavattavannu. Capacity Tilavus Capacity: Tilavus: Capacity: %.0f MW Tilavus: %.0f MW\n Capacity: %d%s %s\n Tilavus: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Tilavus: %s\n\nGruuzu: %d (%d%%) Cars are not available yet! Avtot ei ole vie suadavannu. cars.\nstate kulgunevvuo\n Cash ÄŒotan sal'do Change player Vaihta kižuajua Chart Statistiekat Chat_msg Čätty Choose direction ValliÄÄe suundu Choose operation executed on clicking stored/new vehicles ValliÄÄe funksii mi ajetah ku säilytettyy/uuttu kulgunevvuo klikatah. chooses a random map Luaji piävyndähine kartu citicens Eläilugu City attraction Linnunähtävys City industries Kaupat linnois City list Linnuluvettelo City size Eläjii city_road Piha citybuilding builder Sroji linnusrojuloi CityLimit Linnoin rajat cl_title Kulgunevvoluvettelo cl_txt_sort Lajitteluperusteh: clamp Rajoita arvoalovehta Cleanup schedule Ota toistuvat kohtat iäre Clear block reservation Näytä/nol'ua tielöin tilavuksii clf_chk_aircrafts Lendokonehet clf_chk_cars Avtobusat/gruzoviekat clf_chk_indepot Depos clf_chk_maglev Maglev-junat clf_chk_monorail Yksiraizivojunat clf_chk_name_filter Filtrui nimet: clf_chk_narrowgauge Kaiduraizivojunat clf_chk_noincome Luadiu hävivyö clf_chk_noline Ei liiniedy clf_chk_noroute Ei reitii clf_chk_noschedule Ei azetuksii clf_chk_obsolete Ei tuotandos clf_chk_ships Laivat clf_chk_spezial_filter Spetsial'noi filtru clf_chk_stucked Juuttunuh clf_chk_trains Junat clf_chk_trams Tramvait clf_chk_type_filter Filtrui tiiput: clf_chk_waren Filtrui tavarat clf_title Kulgunevvoluvettelon filtruiÄus Climate Ilmasto Climate Control LandÅ¡aftan laitokset closed salvattu. Closes topmost line window when new line selected. Salbuau ylimän ikkunan uuttu liiniedy vallites COLOR_CHOOSE\n ValliÄÄe väriteemu al\nolijois paletoispäi: Company bankrupt Yhtivö on häviendäs Company_msg Kilbailijat Comparing pak files ... Verdaillah pak-tiijostoloi... Configure AI Muuta luadivoälyy Configure AI setttings Muuta luadivoälyn laitoksii Congratulation\nScenario was complete in\n%i months %i years. Hyvittelyt! Piäzit läbi skenuariospäi %i kuus da %i vuvves! Connected stops Yhtistetyt azetukset: Connected with server Yhtistetty serverale Connections Yhtevykset Constructed by Mualuaju: Constructed by %s Mualuaju: %s construction speed Srojuamisvauhti Construction_Btn Srojuamismaksut Consumed Kulutettu contains the following doubled objects:

tuliet objektat toistuu vähimiten kerran:

convoi %d of %d Kulgunevvo %d/%d convoi error tooltips Kulgunevvoloin oÅ¡ipkutiijot Convoi following mode Kulgunevvoloin tarkailutila: Convoi has been sent\nto the nearest depot\nof appropriate type.\n Kulgunevvo on työnnetty lähimbäh sobijah depoh. Convoi is sold when all wagons are empty. Kulgunevvo myvväh hedi, ku se on kogonah tyhjy. convoi mouseover tooltips Kulgunevvon tiijot hiirel convoi passed last\nmonth %i\n \nKulgunevvoloi viime kuus: %i\n Convois Kulgunevvot Convois: %d\nProfit: %s Kulgunevvoloi: %d\nTulos: %s Convoys Kulgunevvoloi Copy Convoi Kopiirui kulgunevvo Copy the selected convoi and its schedule or line Kopiirui vallittu kulgunevvo da sen reiti Copy to clipboard Kopiirui leikehstolale Cost Maksut cost for removal Iäreottuamismaksut Cost per unit Maksut per yksikkö Cost: %8s (%.2f$/km %.2f$/m)\n Maksut: %s (%.2f$/km %.2f$/kuu)\n Cost: %8s (%.2f$/km)\n Maksut: %8s (%.2f$/km)\n Costs Maksut Create a new line based on this schedule Luaji uuzi liinii, mi pohjavuu täh reitih curiosity builder Nähtävyssrojii curlist_title Nähtävysluvettelo Currently playing: Nygöi soi: Customers live in: Aziiniekat eläh linnois: Date format Päivymiärymuodo: deactivated in online mode Ei aktiivine nettukižas Dec. talvikuu Deccelerate time Hillendä aigua December talvikuu decrease underground view level Alenda muanalazen nägymän tazoa Del Stop Ota iäre Delete Line Ota liinii iäre Delete the current stop Ota nygöine azetus iäre Delete the selected line (if without associated convois). Ota vallittu liinii iäre (ku kulgunevvoloi ei ole liitätty) Delete this file. Ota tämä tiijosto iäre Delivered Työnnetty Demand Tarveh Demand: %.0f MW Tarveh: %.0f MW\n Denkmal Monumentu Departed Lähtenyh Departs at Lähtöy (dd:hh:mm): Departure after %-gruuzu libo vuottamisaigu (dd-hh-mm) Departure board Lähtöaijat Departures per month Lähtöt/kuu: Departures to\n Lähtevät:\n Depots Depot Der Tunnel ist nicht frei!\n Tunneli ei ole vie tyhjy. Destination Tuliet Destroying map ... Hävitetäh vahnua kartua... Details Lizätiijot Die Bruecke ist nicht frei!\n Sildu ei ole vie välly. diesel Diizeli directmail Lehtizet Direkt erreichbare Haltestellen Suorat yhtevykset tiä azemalpäi disable midi Nemoita muuzikku Display bars above factory to show the status Näytä zavodan piäl palkkoi, mit näyttäy sen tilan Display settings Näytön laitokset Distance Matku distributing cities Sijoitetah linnoi... distributing factories Sijoitetah zavodoi... Do not show Älä näytä Dock portu Dock must be built on single slope! Portat tulou srojie yhten yksikön korgevuoh mägeh. Downloading Täytetäh dp_title Depoluvettelo Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Sinul on %d kuudu aigua maksua velgas iäre. Durchsatz Max. Economy Talovus da linnat Eigenbesitz\n Julgine omazus\n Ein %s\npasst hier nicht.\n '%s' ei sovi täh. Einstellungen Laitokset Einstellungen aendern Laitokset electric Sähkö Electricity Sähkö Electricity producer\n\n Sähkönluoju\n\n Electrics_tab Sähkö Electrify track Sähköstä raudutie enlarge map Suurenda kartua enter a value between %i and %i Syötä arvo %i:n da %i:n välilpäi Enter address Syötä adressi Enter Password Muuta kižuajan nimie da peittosanua Error OÅ¡ipku Erzeuge neue Karte.\n Uuttu kartua luajitah, vuota kodvaine.\n\n(Tämä voi kestäy erähän minuutin suuril kartoil.) Es wird bereits\nein Fahrplan\neingegeben\n Reitii planiiruijah parahite. Suata se enzin loppuh enne kui luajit sen uvvessah. Extract files Purretah tiijostoloi... Fabrikanschluss Yhtistetyt zavodat Fabrikname Zavodan nimi Factories Zavodoi factory details Zavodan yhtevykset factorybuilder Zavodusrojii Fahrplan Reiti Fahrtziel Miäränpiä: Fahrzeuge koennen so nicht entfernt werden Kulgunevvuo ei voi ottua iäre nenga. Fahrzeuge: Kulgunevvot: Farbe Kižuajan värit Fast forward Boikonda aigua Feb. tuhukuu February tuhukuu Ferry_tab Lautat Fertig Valmis Filename Tiijosto: Files from: Tiijostot kohtas: Filter: FiltruiÄus: Finances of %s Yhtivön %s talovus Finanzen Talovus find mismatch Verdua pakiettusarjoi fl_title Zavoduluvettelo Flug_tab Passažiirulendokonehet follow me Tule jälles Follow the convoi on the map. Tule kulgunevvon jälles kartal font size Å riftusuurus (vaiku TTF- da OTF-Å¡riftat): Forest MeÄÄät Found new city Perusta uuzi linnu Fracht gruuzua Frame time: Klietkumyöh.: Free Capacity Välly sija freeplay mode Vällykiža Friction: Nygöine treeniikoefitsijentu: fuel_cell Poltokenno Full load Vuota vähimäisgruuzuu Fullscreen (changed after restart) Kogo näyttö (vuadiu uvvestahtyönnändän) Fundament Perustu Fussgaenger Kävelii Game info Nettukiža GAME PAUSED Pauzal Game_msg Ylehine Gear: Välitys: Gebaeude Sroju General Ylehine Generated Luajittu Generation: %.0f MW Tuotando: %.0f MW\n Gewicht Paino Gewinn Tulos: Give the selected vehicle(s) an individual schedule Muuta vallittuloin kulgunevvoloin reitii gl_btn_sort_catg Kategourii gl_title Tavarluvettelo go home Työnnä depoh Goods Tavarua Goods AI Tavarluadivoäly Goods list Tavaraluvettelo Gross Profit Bruttotulos Groundobj Objektu groundobj builder LandÅ¡aftuobjektoin srojii Grow city Kazvata linnua Growth Kazvo GUI settings Käyttöliittymy H azetus Hangar Hanguaru Happy Tyydyväzii Has slope graphics Pidäy sydämessäh rinnehgruafiekat Has Snow Pidäy sydämessäh lumigruafiekat Haus kaufen Osta taloi Helligk. Näyttö Help Ohjavo Help text not found Ohjavotekstua ei löytynyh. hide all building Peitä kaikin srojut hide city building Peitä linnusrojut hide objects under cursor Peitä kursoran al olijat objektat hide station names Peitä azetuksien nimet hide transparent Näytä peitetyt objektat läbinägyjinä hide trees Peitä puut Hier warten/lagern: Passažiiroi/tavaroi vuottamas Higher transport fees, crossconnect all factories Korgeambii kulletustuloloi, zavodan tuotando ei azetu varaston mennes tävvelleh Highlite schedule Näytä reitin azetukset hl_title Azetusluvettelo hl_txt_filter FiltruiÄus: hl_txt_sort Lajitteluperusteh: hlf_chk_airport Lendokenty hlf_chk_anleger Portu hlf_chk_bahnhof Raudutieazemu hlf_chk_bushalt Avtobussuazetus hlf_chk_frachthof Nakkavusaloveh hlf_chk_keine_verb Ei yhtevysty hlf_chk_maglevstop Maglev-azemu hlf_chk_monorailstop Yksiraizivoazetus hlf_chk_name_filter Filtrui nimet: hlf_chk_narrowgaugestop Kaiduraizivoazemu hlf_chk_overflow Ylipainunuh hlf_chk_spezial_filter Spetsial'noi filtru hlf_chk_tramstop Tramvaiazetus hlf_chk_type_filter Filtrui tiiput: hlf_chk_waren_abgabe Tavarat sydämeh hlf_chk_waren_annahme Tavarat ullos hlf_title Azetusluvettelon filtruiÄus Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depuo ei löyditty; sinun pidäy tuöndäy kulgunevvo depoh manuaalizesti. Homeless Kodittomii hydrogene Vodorodu Idle: Vällyna: ignore climates Älä huomavoi ilmastoloi In the industry legend show only currently existing factories Näytä vaiku olemas olijat zavodat tevollizuskohtien sellittehes In Transit Matkal Increase Industry density Kazvata tevollizuon miäryä increase underground view level Nosta muanalazen nägymän tazoa industrial building Tevollizussrojut Industry overlay Tevollizustiijot: Infinite mouse scrolling Rajatoi kartan vieretysaloveh Infinite scrolling using mouse Kursoru pyzyy paikallah kartua vierettäes. Tämä ei vältämättäh rua kosketusnäyttölöil. Init map ... Luajitah kartua... Input Sydämeh Ins Stop Sijoita Insert stop before the current stop Liziä azetus enne nygöisty azetustu Install graphics Azeta gruafiekkoi Install paks Täytetäh da azetetah pakiettusarjoi... Insufficient funds! Sinul ei ole tävvellizesti varoi käyttäy tädä. Intercity road len: Muantielöin piduhus: Intro. date Käyttöhottopvm. Intro. date: Käyttöhottopvm.: invalid ei miäritelty. Invalid coordinate Viäry jälletys Invert stops Inversielline jälletys isometric map Izometrine nägymy Jan. pakkaskuu January pakkaskuu join game Kižua netas July heinykuu Jump to Mene siiriÄi kohtah June kezäkuu Kann Spielstand\nnicht laden.\n Tallendustu ei voitu täyttäy. Kann Spielstand\nnicht speichern.\n Kižua ei voitu tallendau. Kein Besitzer\n Ei omistajua\n keine ei nimidä Keine Einzelfahrzeuge im Depot Ei kulgunevvoloi depos Keyboard_Help\n Pikakluaviššuohjavo\n koord Kordinuatat Kreuzung Ristavus labellist_title Merkiluvettelo Lade Relief Täytä korgevuskuva Laden Täytä uuzi kiža Land attraction Kyläalovehnähtävys Land industries ZavoduÄiepit: LANG_CHOOSE\n ValliÄÄe tahtomas\nkieli:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Viime kuus: Last used tools Viimekse käytetyt ruadoinstrumentat Last Year Viime vuvvel: Leaving depot! Lähtös depospäi leer tyhjy legacy (large heights) Vahnu tila (kaksinkerdazet korgevuot) legacy (small heights) Vahnu tila (puolitetut korgevuot) Legend Kartan selliteh Leistung Voimu Leistung: %d kW Voimu: %d kW Leitung Sähköliinii length: %d Piduhus: %d letzen Monat: diesen Monat: viime kuu: tämä kuu: Line Liinii Line Management Liinielöin haldivo line name mouseover tooltips Liinin nimi hiirel linear Linearine Lineless convoys serving this stop Azetuksel kävvät liinitömät kulgunevvot Lines serving this stop Azetuksel kävvät liinit List of industries on the map Luvettelo kaikispäi kartal olijoispäi zavodoispäi LKW_tab Gruzoviekat Load game Täytä kiža load height data from file Täytä korgevusdatua tiijostospäi Load mode: Täyttötaba: Load scenario Täytä skenuario loaded nakattu loaded passenger/freight Passažiiroin/gruuzun lajitteluperusteh: Loading (%i->%i%%)! Nakatah (%i->%i%%) Loading (%i%%)! Nakatah (%i%%) Loading addon paks ... Täytetäh lizäozii... Loading map ... Täytetäh kartua... Loading paks ... Täytetäh pakiettoi... Loading skins ... Täytetäh käyttöliittymän gruafiekkoi... Loading time: Täyttöaigu: Lock game Estä kižuajan vaihto (vuadiu varmendustu) Lokomotive_tab Vedurit maglev vehicle maglev-juna maglev_track Maglev-raudutie Maglevdepot Maglev-depo Mail Demand %d\n PoÅ¡tan tarveh: %d\n Mail level PoÅ¡tua Mailbox Viestit Mailbox Options Viestilöin laitokset Maintenance Hoidamine make stop public (or join with public stop next) costs %i per tile and level Muuta azetus julgizekse (libo yhtistä rinnal olijah julgizeh azetukseh), maksau %i$ per plitku da tazo Make way or stop public (will join with neighbours), %i times maintainance Muuta tie libo azetus julgizekse (yhtistetäh rinnal olijoih azetuksih), %i-kerdazil hoidomenoloil Manual (Human) Manualine (kižuaju) Manufactured: Valmistettu: Map roughness Kartan Å¡armakkoizus: map view Kartu map zoom zoom: Mar. kevätkuu March kevätkuu Margin (%%) Voitto (%%) Marker Sijoita merki max max. Max Boost (%%) Enimäislizävys (%) Max income: Enimäistulot: Max. speed Enimäisvauhti Max. speed: Enimäisvauhti: Max. waiting time Enimäine vuottamisaigu (dd:hh:mm): Maximum 254 stops\nin a schedule!\n Aiguluvettelos voi olla enimilläh vaiku 254 azetustu. maximum length of rivers Jogiloin enimäispiduhus: Maximum tile height difference reached. Suurin korgevusero kahten plitkan välil tavattih. Maxspeed Enimäisvauhti May oraskuu Median Citizen per town Eläjii keskimiärin per linnu: Meldung Viesti Menge miäry merge stop Yhtistä azetus MessageOptionsText \nUuzi vuozi\n\nKižuaju-uudizet\n\nLinnu-uudizet\n\nEi reitii\n\nUvvet miäränpiät\n\nČätty\n\nUvvet kulgunevvot\n\nAzemu täyzi\n\nOngelmat\n\nTungokset\n\nSkenuario min min. minimum length of rivers Jogiloin vähimäispiduhus: Minimum load Vähimäisgruuzu (%): Missing pakfiles Ei-olijoi objektoi Modify the selected line Muuta vallittuu liiniedy Monate alt kuudu vahnu. monorail vehicle yksiraizivojuna monorail_track Yksiraizivotie Monorailboden Nostettu raudutie Monoraildepot Yksiraizivodepo Month Kuu month wait time Vuotanduaigu (kuus) Monthly departures Plotnoit lähtöaijat Months Kuut Monument Monumentu Monuments Monumentat Mountain height Gorien korgevus: Move the map Liikuta kartua Movingobj Liikkui objektu Music playing disabled/not available Muuzikku on iäre piäl/ei suadavannu. Music volume: Muuzikan iänenkovus: mute sound Nemoita iänet Name Nimi Narrowgauge Kaiduraizivo Narrowgauge are not available yet! Kaiduraizivotiet ei ole vie suadavannu. narrowgauge vehicle kaiduraizivojuna narrowgauge_track Kaiduraizivotie Narrowgaugedepot Kaiduraizivodepo Net ID: %p Verkon tunnus: %p\n Net Wealth Nettovarakkahus Net wealth near zero Nettovarakkahus on käytetty läs kogonah. Neue Karte Uuzi kiža Neue Welt Luaji uuzi kiža new convoi Uuzi kulgunevvo New Line Uuzi liinii New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Uuzi liinii on luajittu. Voit nygöi liittäy liinin kulgunevvoh valliÄemal sen liiniivalikospäi ylähäl. New Vehicles Uvvet kulgunevvot Nickname: KuÄÄumanimi: no buildings hidden Ei peitettylöi srojii no convois Ei kulgunevvoloi No goods are loaded onto this convoi. Gruuzuu ei nakata täh kulgunevvoh no goods waiting Ei vuottavii tavaroi no load Vaiku purgavo No player Ei kižuajua No Route Ei reitii No stop here! Ruadoinstrumentua tulou käyttäy azetuksien kohtal. No suitable ground! Mua on ebäsobii. No terminal station here! Agjuazemua ei voi srojie täh. Tazazel mual olii tienpiäte tarvitah. no timeline Kaikin aiguvälit no tree Ei puuloi No. of Factories Zavodoi da kauppoi: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "Kunnepäi lähten?"\nSinun pidäy andua kulgunevvole azetuksii libo liinii enne kui voit työndäy sen. none Ei nimidä nord pohjaine nordost koilline nordwest luodeh Not allowed to make publicly owned ways! Julgizien tielöin srojuamine ei ole luvallistu. Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Kulgunevvon aiguluvetteluo ei sua muuttua tien eÄon aiguna. Not enough fields would remain. Ferman ymbarile ei jiäs tarbehekse peldoloi. Nov. kylmykuu November kylmykuu now nygöi Now active as %s.\n Nygöi aktiivine kižuajana %s. nowhere ei nimis Number of rivers Jogiloin lugumiäry: Object Objektu Oct. ligakuu Odometer: %s km Matkumittari: %s km Ok OK Oktober ligakuu On loan since %i month(s) Velgois %i kuun aijan On mouseover Ku kursoru on piäl on the lähtö(y)/kuu, enzimäine lähtö (dd-hh-mm) On this map, you are not\nallowed to change player!\n Kiža on lukittu; kižuajua ei voi vaihtau. Only city chains Sroji linnutevollizusÄieppi Only first %d differing paks reported. There are probably more. Vaiku enzimäzet %d eriluadustu pakiettua näytetäh. Tovenägözes nennii on enämbängi. Only full Unicode fonts Käytä vaiku tävvellizii Unicode-Å¡riftoi Only land chains Sroji kyläalovehen tevollizusÄieppi Only one transformer per factory! Zavodan viereh voi srojie vaiku yhten transformuatoran. Only show goods which are currently handled by factories Näytä vaiku tavarat, mit on täl kodvazel käzittelys zavodal open Avvoi Operation Ruadomenot Ops Profit Laukkuvoitto Optionen Laitokset Or enter a server manually: Libo syötä adressi manualizesti: Origin Alguperä ost päivännouzu Output Ullostulo Ownership Omistavus Pak which may cause severe errors: Tulieloi objektoi (*.pak) ei ole, mi voi nostattau likendehÄieppilöin kuadumizen: Pak which may cause visual errors: Tuliet objektat (*.pak) korvattih samankaldazil objektoil: Pak(s) different: Eriluaduzet pakietat: Pak(s) missing on client: Pakietat, mit ei ole klijental: Pak(s) not on server: Pakietat, mit ei ole serveral: Pakset differences Objektusarjoin erot paletten juaššiekkua Pas_tab Passažiirujunat Passagiere passažiirua Passagierrate Passažiiroi Passagierziele Passažiiroin/poÅ¡tan miäränpiät Passenger AI Passažiiruluadivoäly Passenger Demand %d\n Passažiiroin tarveh: %d\n Passengers %d %c, %d %c, %d no route Passažiiroi %d %c, %d %c, %d ilmai reitii Passengers %d %s, %d %s, %d no route Passažiiroi %d %s, %d %s, %d ilmai reitii Password Peittosana: Pause Pauzu Pax <%i> Mail <%i> Passažiiroi <%i> poÅ¡tua <%i> Pax level Passažiiroi PaxDest Miäränpiät Percent Electricity Sähkön tuotando (% tarpehespäi): Planes are not available yet! Lendokonehet ei ole vie suadavannu. Plant tree Istuta puuloi player Kižuaju player -1 Ristikanzankižuaju player 0 Julgizet palvelut player 1 Tiger Trans Oy player 10 Kižuaju 10 player 11 Kižuaju 11 player 12 Kižuaju 12 player 13 Kižuaju 13 player 2 Kulletus Trikky player 3 Oy Simutransport Ab player 4 Kulletus Meyer Oy player 5 Net Shipping Oy player 6 Kulletus Kataimägi player 7 Kižuaju 7 player 8 Kižuaju 8 player 9 Kižuaju 9 Please choose vehicles first\n ValliÄÄe kulgunevvot enzin.\n Post poÅ¡tua Postrate PoÅ¡tua Power Voimu Power (MW) Voimu (MW) Power: Voimu: Power: %4d kW\n Voimu: %4d kW\n Powerlines Sähköliinit Price Hindu Problems_msg Ongelmat Produced Luajittu Produces: %.1f units/minute Luadiu %.1f yksikkyö/min Production of %s has been stopped:\n%s\n Tiipun %s kulgunevvon tuotando on loppiettu:\n%s Production/Boost Tuotando/lizävys Produktion Tuotando: Profit Tulos promote to line Muuta liinikse q1 Kevät q2 Kezä q3 Sygyzy q4 Talvi Query server Työnnä kyzely rail car junanvagon random Piävyndähine Random age Piävyndähine igä Random map Piävyndähine kartu Rathaus Linnutaloi Rating Luokittelu ratio_pax Matkoin vuitti Relevant Relevantnoi Reliefkarte Kartu Remove Ota merki iäre remove airstrips Ota lennätys-/ruloamisdorogoi iäre remove channels Ota kanualoi iäre remove interm. signals Ota välis olijoi ozuttimii iäre remove maglev tracks Ota maglev-raudutielöi iäre remove monorails Ota yksiraizivotielöi iäre remove narrowgauge tracks Ota kaiduraizivotielöi iäre remove powerlines Ota sähköliinielöi iäre remove roads Ota dorogoi iäre remove signal Ota ozuttimii iäre remove tracks Ota raudutielöi iäre Remove wayobj %s Ota tieobjektua %s iäre replace other signals Korvua muut ozutimet replace stop Korvua azetus request closing PakiÄe salbavuo residential house Eländyhuonukset Restore natural slope Työnnä luonnolline rinneh järilleh Restwert: Myöndyarvo: Retire date Vahnavumispvm. Retire. date: Vahnavumispvm.: return ticket Kopiirui tulole Revenue Ruadotulot Revert schedule Kumua muutokset Revision: Kerävöversii: road dorogu road vehicle ajonevvo Roadsign Likendehmerki Rotate Building Kiännä srojua Rotate map Kiännä kartua Rotation Pyörindy Routing Reititys Running cost Käyttömenot sack säkkii sail tuuli Saving map ... Tallendetah kartua... Scenario complete: %i%% Skenuarion progressu: %i%% Scenario Debug OÅ¡ipkanhaldivo Scenario Error Log Å riftan oÅ¡ipkat Scenario Goal Tavoiteh Scenario Info Tieduo lyhyes Scenario information Tieduo nygözespäi skenuariospäi Scenario Result Progressu Scenario Rules Siännöt Schedule changing! Reitii muutetah! Schienentunnel Sroji raudutietunneli Schiff_tab Laivat Schiffdepot Dokku Schleppkahn_tab Baržat Screenshot Ota kuvakuabavus Scroll threshold Vieretyskynnys Search: EÄi: Seasons Vuvvenaijat Sehenswuerdigkeit Turistunähtävys Select a server to join: ValliÄÄe serveru mih tahtot yhtistäy: Select a theme for display ValliÄÄe näytettävä teemu Select display font ValliÄÄe näytettävä Å¡riftu Select one or more graphics to install (Ctrl+click): ValliÄÄe vähimiten yksi gruafiekkupakiettu azetettavakse (Ctrl+klikkuaus): Select soundfont ValliÄÄe soundfont-tiijosto Sell the selected vehicle(s) Myö vallitut kulgunevvot sended Työn. poÅ¡tu SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Sept. syvyskuu September syvyskuu Served by Ajelii: Served by me Minun ajelema Server did not respond! Serveru ei vastannuh! Serves Line: Palveleh liinil: Service Kursiiruindu set signal spacing Laita ozutinväli Setting Laitokset Ship Laivu shops and stores Kaupat da laitokset Show all Näytä kaikin show all building Näytä kaikin srojut Show also vehicles no longer in production. Näytä myös tuotandospäi iäreotetut kulgunevvot. Show also vehicles that do not match for current action. Näytä myös kulgunevvot, midä ei voi käyttäy vallitul funksiel. Show always Näytä ainos Show climates Ilmastot Show contour Muanmuvvot Show even servers with wrong version or pakset Näytä myös serverat, mit taritah viäryä versieda libo objektusarjua. Show finances for transport type Näytä tiedoloi likendehmuvvole Show future Näytä tulevazus show grid Näytä kodazilokku Show industry Zavoduluvettelo Show legend ValliÄukset Show map scale Värikoodat Show mismatched Näytä ebäluadeivat Show networks Näytä verkot Show obsolete Näytä vahnavunnuot Show offline Näytä offline-serverat Show only used Näytä vaiku käytetyt Show outline Infrastruktuuru Show schedules Näytä reitit Show servers that are offline Näytä offline-tilas olijat serverat Show servers where game version or pakset does not match your client Näytä serverat kudamin kižan versii libo objektusarju ei luadihes klijentas kel. show station coverage Näytä azemien kattavus show station names Näytä azemien nimet show waiting bars Näytä paÄÄahii vuottavispäi show/hide block reservations Näytä/peitä tielöin tilavukset Show/hide estimated arrival times Näytä/peitä laskietut tuloaijat show/hide object owner Näytä/peitä objektan omistai Show/hide statistics Näytä/peitä statistiekat Shows buttons about networks overlay. Näytä liiniiverkon kattokuvan luajindah liittyjät painoknopkat Shows buttons on network overlay. Näytä painoknopkat, mil luajitah kattokuva liiniiverkospäi Shows buttons on special topics. Näytä painoknopkii omaluaduzispäi peruksispäi Shows consumer/suppliers for factories Näytä zavodoin kuluttajat/tavaranruadajat Shows the color code for several selections. Näytä värilöin selliteh muudamile valliÄuksile Shows the currently selected schedule Näytä täl kodvazel vallittu reiti Shrink city KuÄista linnua shuffle midis Sevoita ozutelmat Signal Ozutin signal spacing Ozutinväli Sim: Petlat: Similar view as the main window Samankaldaine nägymy kui piäikkunas Size (%d MB): Suurus (%d Mt): Size (area) Suurus (aloveh) sliced underground mode Viibalehnägymy slot empty Tyhjy Smart hide objects Peitä objektoi kursoran ymbärilpäi Sort by Lajitteluperusteh Sort by: Lajitteluperusteh: Sort waiting list by Vuottavien luvettelon lajitteluperusteh: Sound Iänet Sound settings Iänilaitokset Sound volume: Iänien kovus: Soundfonts are located in the music directory. Soundfontat on 'music'-eÄÄomistas. special freight Spetsgruuzu Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Vuajittai vähimäisvauhti vauhtibonuksele (%%):\ndorogat %i km/h, raudutiet %i km/h,\nlaivat %i km/h, lendokonehet %i km/h Speedlimit Vauhtirajoitus Speichern Tallenda Spieler Kižuaju Spieler(mz) Kižuajat Spielerliste Kižuajuluvettelo Spielstand wurde\ngeladen!\n Kiža täytettih hyvin. Spielstand wurde\ngespeichert!\n Kiža tallendettih hyvin. Sprache Kieli Sprachen Kielet Stadtinformation Linnan statistiekat Start Pane käymäh Start the selected vehicle(s) Työnnä vallitut kulgunevvot likendeheh Starte Spiel Alla kiža station labels Azemat Station tiles: Azemuplitkat: Station_msg Azemat Status Azetuksen tila steam höyry Step timeline one year Siirry vuvvel edehpäi Stops Azetukset Storage Varasto Storage capacity Varastotilavus Strassendepot Garažu Strassentunnel Sroji dorogutunneli street car tramvai sued suvi suedost liideh suedwest lounas Summer snowline Lumiraja kezäl: Supplied: %.0f %% Ruattu: %.0f %% Suppliers Tavaranruadajat: Tage alt päiviä vahnu. The following graphics are unmaintained: Tulieloi gruafiekkupakiettoi ei hoijeta: The gradient does not fit a tunnel Täh mägeh ei synny tunneli. Theme selector Teeman valliÄus There are still vehicles\nstored in this depot!\n Depos on vie kulgunevvoloi. This Month Täs kuus: This Year Täl vuvvel: Tile not empty. Tyhjendä plitku enzin enne muankohendeluu. timeline Mene aiguvälii myöte tl_title Linnuluvettelo To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Linnan %1$s likendehmiärät kazvos: %3$i veronmaksajua luaji srojun %2$s srojimizespäi mahtollistu. To heavy traffic\nresults in traffic jam.\n Bohattu likendeh nostattau tungoksen. Toggle day/night view Vaihta päivy/yö-tilua Toggle vehicle tooltips ValliÄÄe, mibo kulgunevvovihjavukset näytetäh tonnen t Toolbar position: Ruadoinstrupalkan paikku: Total inhabitants: Eläjii: Tourist attractions Turistunähtävyksii: Tourists Nähtävyksii Town_msg Uvvet miäränpiät Town: %s\n Linnu (%s)\n Towns Linnat track raizivo Tracks Raudutiet Traffic Likendeh traffic settings Likendeh Train Juna Trains are not available yet! Junat ei ole vie suadavannu. Tram Tramvai tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. tramvaitiet %i km/h, yksiraizivo %i km/h, maglev %i km/h, kaiduraizivo %i km/h. tram_track Tramvaitie Tramdepot Tramvaidepo Trams are not available yet! Tramvait ei ole vie suadavannu. Transferring game ... Siirretäh kižua... Transformer only next to factory! Transformuatorat tulou olla tyhjäl, tazazel mual zavodan vieres. Translation Kiännös transparencies Läbinägyvys transparent station coverage Läbinägyi azemien kattavus Transported Matkoi Trees disabled! Puut on otettu iäre piäl. TrolleyBus_tab Troleibusat Truck Gruzoviekku tt_Other Muut Tunnel muss an\neinfachem\nHang beginnen!\n Tunnelit tulou algua suoraspäi mäespäi. Tunnel must start on single way! Tunnelit tulou algua tielpäi. Tunnelboden Tunneli underground mode Muanalaine nägymy UNDO failed! Kumuamine enämbiä ei ole mahtollistu. Reitin srojimizen voi kumata vain, ku reitile ei ole srojittu ozutimii/azemii/azetuksii libo nimidä muuta. Undo last ways construction Kumua viimezin tiensrojuamisruado Unemployed Ruavottomii Unhappy Tyydymättömii units/day yksikkyö/kuu Unloading (%i%%)! Purretah (%i%%) Update Line Muuta liiniedy upgrade HQ Päivitä piäkantor Usage: %.0f %% Käyttö: %.0f %% Usage/Output Käyttö/luajindu Use beginner mode Algaitila Use timeline start year Käytä aiguvälii vuvvespäi: Vehicle %s can't find a route! Kulgunevvo %s ei lövvä reitii. Vehicle %s is stucked! Kulgunevvo %s on juuttunuh. Vehicle details Kulgunevvon tiijot Vehicle Name Nimi Vehicle Power Voimu vehicles stored Säilytetut kulgunevvot Verbrauch Kulutus: Vergroessere die Karte\n Suurenda kartua. Verkauf Ota iäre hedi verkaufen Myö Verkehrsteilnehmer Hengilöavtot Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Sinul on %d kuudu aigua maksau velgas iäre. vh_title Luvettelo kaikispäi kulgunevvoloispäi via kauti (podr.) via %s\n kauti %s\n via Menge kauti (miäry) voranstellen Laita edeh Waggon_tab Vagonat waiting vuottamas Waiting for clearance! Vuottau vuoroah Walked Kävelty walking Kävelöy Warnings_msg Likendeh Wasser Vezi Water Kanualu Water level Vientazo: water vehicle vezikulgunevvo way %s cannot longer used:\n Tietiippu %s enämbi ei ole käytettävänny.\n way %s cannot longer used:\n%s\n Tietiippu %s enämbi ei ole käytettävänny:\n way %s now available:\n Tietiippu %s on nygöi suadavannu.\n Way toll Tiemaksut Ways not connected Tielöi ei ole yhtistetty. waytype tietiippu Wegpunkt Välietuappu Weight Paino Weight: Paino: Wert Arvo west päivänlasku Wind direction Tuulensuundu: Winter snowline Lumiraja talvel: withdraw Lope Withdraw All Lope kaikin WRONGSAVE Tallendettu kiža ei ole yhtehsobii. Tiijostuo ei voitu täyttäy. Year Vuozi Year %i has started. Vuozi %i on alganuh. Years Vuvvet Your primary color: Enzisijahine väri: Your secondary color: Toizensijahine väri: Zielort miäränpiä zooming in Lähendä zooming out Loitonda Zu nah am Kartenrand Et voi srojie nenga lähäle kartan reunua. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Levitoindii magniettoin piäl %.1f km/h:n vauhtil: kulgunevvolpäi %s uuzi muailmanrekordu! New world record for monorails: %.1f km/h by %s. Yksi raizivo luajittu vauhtile: tarkah %.1f km/h kulgunevvolpäi %s luadiu täs uvven muailmanrekordan! New world record for motorcars: %.1f km/h by %s. Vaiku junot jäi jällele kulgunevvon %2$s kahaittua-ajuamizespäi %1$.1f km/h:s piästäkseh uuteh muailmanrekordah! New world record for narrowgauges: %.1f km/h by %s. Jyristämisty kaidoin raizivoloin yli %.1f km/h:n vauhtil: %s luaji uvven kaiduraizivojunien muailmanrekordan. New world record for planes: %.1f km/h by %s. Piduhuksien kuÄistamistu myös: %2$s lendi %1$.1f km/h - uuzi muailmanrekordu! New world record for railways: %.1f km/h by %s. Jyristämisty raizivoloin yli %.1f km/h:n vauhtil: %s laittau uvven muailmanrekordan junile.\m New world record for ship: %.1f km/h by %s. Sinizen nuorazen kulleskeluspäi %.1f km/h:n vauhtil on voittanuh %s. #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s osti kulgunevvon liinile %s. %s build rail line from %s (%s) to %s (%s) %s sroji raudutieliinin välile %s (%s) - %s (%s). %s build road line from %s (%s) to %s (%s) %s sroji gruzoviekkuliinin välile %s (%s) - %s (%s). %s build ship line from %s (%s) to %s (%s) %s sroji laivuliinin välile %s (%s) - %s (%s). %s extends the route from %s (%s) to %s (%s) %s levendi reitii välil %s (%s) - %s (%s). %s optimize way line from %s (%s) to %s (%s) %s muutti liiniedy välil %s (%s) - %s (%s). %s removes convoys from line: %s %s otti kulgunevvoloi iäre liinilpäi %s. vehicles of the line %s were retired Kulgunevvoloi loppiettih liinilpäi %s. #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. Liziä liinile muut samankaldaistu reitii ajajat kulgunevvot Enter intervall in days, hours, minutes Syötä aiguväli päivis, Äuassulois da minuutilois Mirrors order of stops Muuta azetuksien kundo inversiellizekse Revert to original schedule Kumua kaikin muutokset aiguluvetteloh #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL järvi &1_CITY_SYLL linnu &2_CITY_SYLL kylä &3_CITY_SYLL jogi &5_CITY_SYLL meÄÄä &6_CITY_SYLL levei &7_CITY_SYLL niittu &8_CITY_SYLL kulmu &9_CITY_SYLL koski &A_CITY_SYLL pohju &B_CITY_SYLL korbi &C_CITY_SYLL kallivo &D_CITY_SYLL rinneh &E_CITY_SYLL lambi %0_CITY_SYLL Raja %1_CITY_SYLL Uuzi %2_CITY_SYLL Vähä %3_CITY_SYLL Koivu %4_CITY_SYLL Leppä %5_CITY_SYLL Armon %6_CITY_SYLL Laaja %7_CITY_SYLL Oja %8_CITY_SYLL Lahti %9_CITY_SYLL Vahnu %A_CITY_SYLL Kivi %B_CITY_SYLL Loitto %C_CITY_SYLL Lapin %D_CITY_SYLL Kirikön %E_CITY_SYLL Riihi 1center %s %s 1extern %s Å¡uaru %s 1suburb %s %s %s 2center %s keskus %s 2extern %s sivu %s 2suburb %s kylä %s %s 3center %s piäaloveh %s 3extern %s mua %s 3suburb %s niittu %s %s 4center %s syväinpuoline %s 4extern %s ulgoine %s 4suburb %s kyläläine %s 5center %s keskilinnu %s 5extern %s vaihto %s 5suburb %s pieni linnu %s 6center %s ristavus %s 6extern %s tazango %s 6suburb %s laidu %s %s 7center %s linnu %s 7suburb %s puusto %s 8center %s laukkukeskus %s 8extern %s %s reunu %s 9center %s akseli %s 9extern %s dorogu siiriÄi %s simutrans-124.3/simutrans/text/ol/000077500000000000000000000000001474050137200171765ustar00rootroot00000000000000simutrans-124.3/simutrans/text/ol/climates.txt000066400000000000000000000022731474050137200215440ustar00rootroot00000000000000LandÅ¡aftan laitokset

Landšaftan laitokset (ruan al)

Landšaftan laitokset -ikkun laittau kižamuailman topogruafellizii da meteorolougizii ominazuksii. Ikkun avavuu ühtes luaji uuzi kiža -ikkunan kel.

Muuttuakses jogahistu laitostu, n'apsahuta jogahizen valliÄuksen sivus olevii nuolipainoknopkii, libo süötä noumer juaššiekkah.

Kartan valliÄukset

Vientazo - Laittau vien korgevuon kartal (gipoutezu on -2). Korgeambat arvot tariÄÄou vähembän muata da enämbi vezistölöi.

Gorien korgevus - Laittau alovehen enimäiskorgevuon.

Kartan šarmakkoizus - Laittau alovehen šarmakkoizuon. Suurembi noumer luadiu enämbi aldoiluu rannikkoalovehil (nenne on real'noimbii). Ülen šarmakkoizile kartoile ei vältämättäh voi luadie muga äijü linnoi, zavodoi libo dorogoi kui midä oli tarkoitus luadie.

Varoitus: korgevustazoloi, mit on suurembii kui 33, tulis vältüö (nenne ei ole kižuajan käütettävännü). Liziä muatazoloi voi luadie tarbehen mugah alendamal vientazoa.

simutrans-124.3/simutrans/text/ol/general.txt000066400000000000000000000075141474050137200213630ustar00rootroot00000000000000Simutransin ohjavo

Ülehine ohjavo

- Tulgua terveh
- Käüttöliittümü
- Hiiren käüttö
- Klaviatuuran käüttö

Kižan laitokset
- Kieli
- Kižuajan värit
- Näütön laitokset
- Iäni ja muuzikku
- Kižuajat
- Kižan täüttiämine
- Tallendamine
- Uuzi kiža
- - Landšaftan laitokset
- - Korgevuskuvan käüttö

Piävalikko
- Kižan laitokset
- Kartuikkuna
- Tutkimisruadoinstr.
- Muankohendeluruadoinstr.
- Raudutieruadoinstr.
- Üksiraizivoruadoinstr.
- Tramvairuadoinstr.
- Doroguruadoinstr.
- Porturuadoinstr.
- Lendokentüruadoinstr.
- Spetsial'noit srojimisruadoinstrumentat
- Kižankohendeluruadoinstr.
- Hävitä/ota iäre

- HaldivoiÄÄemisvalikko
- Liinielöin haldivo
- Luvettelot
- - Azetusluvettelo
- - - Azetus-/azemuluvettelon filtruiÄus
- - Kulgunevvoluvettelo
- - - Kulgunevvoluvettelon filtruiÄus
- - Linnuluvettelo
- - Tavarluvettelo
- - Zavoduluvettelo
- - Nähtävüsluvettelo
- Viestit
- Talovus

Muut valliÄukset
- Kuvakuabavuksen otto
- Pauzu
- Boikonda aigua
- Ohjavo

Muut dialougat
- Depon haldivo
- Aiguluvettelon haldivo
- Azetuksen tiijot
- - Azetuksen lizätiijot
- Kulgunevvon tiijot
- - Kulgunevvon lizätiijot
- Linnan tiijot
- Zavodan tiijot

Abuu voi löudüö muuloil kielil
müös tulieloil sivustoloil:
https://simutrans-germany.com/wiki/wiki/Home/
https://forum.simutrans.com/
https://www.tips.simutrans.com/
libo tulielois ohjavokirjoispäi:
Simutrans Starter Guide
(ezim. http://simutrans.igoreliezer.com/docs/
Simutrans%20Starter%20Guide.pdf
)
Simutrans Reference Manual
(ezim. http://simutrans.igoreliezer.com/docs
/Simutrans%20Reference%20Manual.pdf
)

simutrans-124.3/simutrans/text/ol/load_relief.txt000066400000000000000000000034461474050137200222130ustar00rootroot00000000000000Täütä korgevuskuva

Täütä korgevuskuva

Täütä korgevuskuva -ikkunua käütetäh avuamah tiijostuo, mis on mugavutettu aloveh (käütettäväkse uvven kižan luajindas), da sidä voi müös käüttäü nämien iäreottuamizeh. Se avavuu luaji uuzi kiža -ikkunaspäi, da se näüttäü tiijostoloin nimet, päivümiärät da tallendusaijat luvettelos. Ku kaikin tiijostonimet ei nävü, käütä luvettelon oigienpuolistu vieretüspalkkuo vierettäkses nimien läbi.

N'apsahuta nimie luvettelospäi täüttiäkses mugavutetun kartan, libo süötä nimi ikkunan üläreunas olevah tekstujuaššiekkah: n'apsahuta juaššiekkua, kirjuta nimi da paina [Enter]- libo [Return]-kluaviššua libo n'apsahuta OK-painoknopkua (viärü nimi ei rua nimidä, üritä uvvessah).

N'apsahuta nimen hural puolel olevua x-painoknopkua (ku on laitettu piäle simuconf.tab:s) ottuakses mainitun tiijoston iäre tiijostosistiemaspäi. Tiijostonimi lähtöü iäre luvettelospäi da ikkun salbavuu.
Varoitus: tiijosto otetah iäre välittömästi da lujasti. Käütä funksiedu hüvin ruatusti!

Alovehii on suadavannu netispäi, ezim. sivustol https://maps.simutrans.com libo Steam Workshopispäi. Uvven tiijoston tuleh olla PPM- libo BMP-muvvos, mis jälgimäistü pidetäh tugie rajoitetusti. Tiijostot tuleh laittau kižan käüttäieÄÄomistoh "simutrans/maps/".

Vihjavus: Tieduo omien alovehien luadimizespäi on suadavannu Simutransin wikis.

N'apsahuta Peruuta-painoknopkua libo üläoigies reunas olevua x-painoknopkua libo käütä kluaviššua salbuakses ikkunan.

simutrans-124.3/simutrans/text/ol/new_world.txt000066400000000000000000000127421474050137200217450ustar00rootroot00000000000000Luaji uuzi kiža

Luaji uuzi kiža

Luaji uuzi kiža -ikkunas laitetah uvven kižan ominazuksii. Täl luajitah uuzi kartu vallittuloil laitoksil. Voit muuttau monii eri kižan muuttujii, ezim. kartan suuruttu, eloikeskuksien miäryä kižan allus da zavodoin miäryä. Vallituspäi alovehespäi näytetäh myös ezikaÄeluversii.

Muut laitosikkunat ei ole käytettävis, ku tämä ikkun on avvoi. Tullakses järilleh nygözeh kižah, salbua ikkun n'apsahuttamal nimipalkis olevua x-painoknopkua.

Nuolipainoknopkat muuttau laitoksii, da valliÄusklietkat panou valliÄuksii piäle/pois piälpäi libo avuau uuzii ohjavusikkunoi.

Kartan noumer - ValliÄeh kižas käytettävän alovehen.
Klikkua noumerjuaššiekkua da syötä kartan noumer, libo käytä nuolipainoknopkii siirdyäkses eri alovehvaihtoehtoloin välil. EzikaÄelunägymy näyttäy vallitun alovehen moizena kui se nägys kižas (vezistöt on sinizii, madalembi mua on mustembi kui korgeambi mua).

Suurus - Laittau kartan suuruon L x K (levevys x korgevus) -muvvos. Ylembi arvo on levevys, da alembi on korgevus. Vuajittava keskusmuston miäry näytetäh salbavomerkien sydämes.
Huom.: Suuremmat kartat vuadiu enämbän mustuo, da nennien generoindas meneh enämbän aigua. Kiža da muut gruafiekat vuadiu lizäkse 88 Mt mustuo pak64:s da 144 Mt pak128:s. Ylehizenä piäsiändönä älä yritä luadiu kartua mi on suurembi kui 512 x 512 plitkua tiedokonehel, mis on 256 Mt mustuo.

Piävyndähine kartu - ValliÄeh alovehen piävyndähizesti. Muut laitokset ei muutu.

Täytä korgevuskuva - Täyttäy mugavutetun alovehen. Avuau mainitun ikkunan.

Linnoin lugumiäry - Laittau eloikeskuksien miärän kižan allus. Ku kartu on liijan pieni libo liijan karhei, linnoi luajitah vähembän. Liziä uuzii linnoi voi panna manualizesti vaihtamal julgizeh kižuajah.

Eläjii keskimiärin per linnu - Laittau kaikkien eloikeskuksien keskimiaräzen eläiluvun. Simutrans yrittäy luadie enämbän pienii kylii kui suurii linnoi.

Muantielöin piduhus - Laittau eloikeskuksien keskeizien julgizien dorogoin enimäispiduhuon kižan allus. Laita täh suurembi arvo yhtistiäkses eloikeskuksii, mit on loitombana toizispäih.

Zavodoi da kauppoi - Laittau eloikeskuksien ulgopuolizien tevollizusruanduÄieppilöin miärän kižan allus. Liziä tevollizusÄieppilöi ilmestyy avtomuatillizesti eloikeskuksen eläiluvun kazvaes.
Huom.: Ku aloveh on ylen mägine, sobijua tazamuata ei vältämättäh löydy tevollizusÄieppilöin luadimizeh, sikse vähembän tevollizuttu ilmestyy.

Turistunähtävyksii - Laittau eloikeskuksien ulgopuolizien passažiiroi da poštua muanittelijoin mua-aloin miärän kižan allus. Turistunähtävykset ilmestyy eloikeskuksien ulgopuolele uuzien kylien libo linnoin kel luajittuloin nähtävyksien lizäkse kartan luajindan jälgeh.

Käytä aiguvälii algajen vuvves - Laittau kižan allatusvuvven. N'apsahuta valliÄusklietkua kižatakses aiguperustehizil rajoituksil. Ku aigu kižas kuluu, liziä kulgunevvoi, srojii da zavodoi ilmestyy.

Ku funksiedu ei ole vallittu, kaikin kulgunevvot, srojut da zavodat on suadavannu da käytös kižas. Eloikeskukset ilmestyy eri aiguvälielpäi tulieloin srojien kel, da hil'l'ambat kulgunevvot ei ole muga tuloksekkahii kui boikoimbat, ku tulos laskietah käytetyn kulgunevvon keskivauhtin mugah.

Algaitila - Laittau valliÄuksen, mi andau luvan korgeambien tuloloin suandah kižas tavaroin da passažiiroin kullettamizespäi. Gipoutezuarvozesti, ku kižatah algaitilas, suat 150% arvospäi kui ku sais 100% tavallizes tilas. Lizäkse zavodat ei lope tuotanduo ku kuluttajil on ylitariÄustu.

Laitokset - Avuau levendetyt laitokset -ikkunan. Tiäpäi piäzeh käzikse kaikkih parametroih mit on käytettävänny myös simuconf.tab -tiijostos.

LandÅ¡aftan laitokset - Avuau landÅ¡aftan laitokset -ikkunan, mi ohjuau erilazii kartan laitoksii: Å¡armakkoizuttu, vientazoa, ilmastoloi, meÄÄäy da jogiloi.

Täytä kiža - Täyttäy tallendetun kižan. Näyttäy Täytä kiža -ikkunan, mispäi voi jatkau aijembah tallendettuu kižua. Ku tallendettu kiža on täytetty, se korvuau nygözen kižan ilmai varmendustu.

Täytä skenuario - Täyttäy skenuarion, toizin sanoen kižan, mis tietty tavoiteh pidäy tavoittau. Tämä on vaihtoehto tavallizele, välläle Simutransin kižaluavule.
Huom.: Mistah pakiettusarjois ei ole ni yhty skenuarioloi.

Alla kiža - Algau kižan luajimal uvven muailman vallituloil laitoksil. N'apsahuta painoknopkua kižatakses Simutransii. Ozua da hyvii kižakodvazii!

Lope - N'apsahuta painoknopkua lähtiekses iäre kižas.

Vihjavus: muuttuakses Simutransii käymäh laittaes täytettävii gipoutezuarvoloi libo muuloi globualoi muuttujii, muuta arvoloi simuconf.tab -tiijostos.

simutrans-124.3/simutrans/text/pl.tab000066400000000000000000001537271474050137200177060ustar00rootroot00000000000000§Polski PROP_FONT_FILE prop-latin2.fnt ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: pl Polski # # Encoding: UTF-8 # # Font: prop-latin2.fnt # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Czas bezwzględny AMBIENT_SOUND Dźwięk otoczenia CASH_SOUND Dźwięk pieniędzy cl_btn_filter_disable Wyłącz cl_btn_filter_enable Włącz cl_btn_filter_settings Ustaw cl_btn_sort_asc Rosnąco cl_btn_sort_desc Malejąco cl_btn_sort_id Wewnętrzne ID cl_btn_sort_income Przychód cl_btn_sort_name Nazwa cl_btn_sort_type Typ clf_btn_alle Wszystkie clf_btn_invers Odwróć clf_btn_keine Brak climate area percentage Procent obszaru klimatu CROSSING_SOUND Dźwięk przejścia FACTORY_SOUND Dźwięk fabryk Find matching convois Znajdź pasujące konwoje gl_btn_sort_bonus w/g premii gl_btn_sort_name w/g nazwy gl_btn_sort_revenue w/g dochodu gl_btn_unsort nieposortowane height based Na podstawie wysokości hl_btn_filter_disable Wyłącz hl_btn_filter_enable Włącz hl_btn_filter_settings Ustaw hl_btn_sort_asc Rosnąco hl_btn_sort_desc Malejąco hl_btn_sort_name Nazwa hl_btn_sort_type Typ hl_btn_sort_waiting Oczekiwanie hlf_btn_alle Wszystkie hlf_btn_invers Odwróć hlf_btn_keine Brak humidities Wilgotność Install Instalacja paczek Lake Jezioro Lake height Wysokość jezior Maximize height levels Maksymalizuj poziomy wysokości moisture land Wilgotność nad lądem moisture water Wilgotność nad wodą Networks Sieci transportowe Num pad keys always move map Klawisze numeryczne zawsze przesuwają mapę Open Sea Otwarte morze Queueing Czas oczekiwania rainfall Opady deszczu Reselect closes tools Ponowny wybór narzędzia powoduje jego zamknięcie Road toll Opłata drogowa Scenario Sceneria sea Morze Single GUI Pojedynczy interf. graf. Sound range: Zakres dźwięku: Start this as a server Uruchom jako serwer temperature borders Granice temperatur temperature-humidity based Na podstawie temperatury i wilgotności TOOL_SOUND Dźwięk narzędzi TRAFFIC_SOUND Dźwięk ruchu Transfers Przepustowość #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Klim. arktyczny desert Klim. pustynny mediterran Klim. śródziemny rocky Ter. skaliste temperate Klim. umiarkowany tropic Klim. tropikalny tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Wczytanie scenariusza nie powiodło się! Bridge blocked by way below or above. Most zablokowany poniżej lub powyżej. Can't buy obsolete vehicles! Nie można zakupić przestarzałych pojazdów! Cannot alter water Zbiornika tego nie można dalej opróżniać ani napełniać. Cannot build on a double slope! Można budować tylko na jednym zboczu lub terenie płaskim. Cannot built depot here! Nie można zbudować tu zajezdni. Cannot built this station/building\nin underground mode here. Budynek można wybudować tylko na powierzchni.\n Cannot connect to the\ncenter of a double slope! Nie można połączyć się ze środkiem podwójnego zbocza! Cannot create generic line!\nSelect line type by\nusing filter tabs. Nie mogę utworzyć linii \nnie znając jej typu! \n\n\nWybierz typ linii za pomocą zakładek. Cannot create socket Nie można zainicjować połączenia! Cannot rotate this building! Nie można obrócić tego budynku. Client closed connection during transfer Klient zamknął połączenie podczas transferu. Convoi handles exhausted! Maksymalna ilość pojazdów (konwojów) osiągnięta. Convoy already deleted! Skład już usunięto! Could not open file Nie można otworzyć pliku. Das Feld gehoert\neinem anderen Spieler\n Te tereny\nsą własnoscią\ninnego gracza!\n Der Besitzer erlaubt das Entfernen nicht \nWłaściciel nie wyraża\nzgody na likwidację\nobiektu!\n Diese Zusammenstellung kann nicht fahren!\n Taki zestaw\nnie pojedzie! Flugzeughalt muss auf\nRunway liegen!\n Przystanek musi\nleżeć na pasie\nstartowym! Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Tego budynku lotniska nie można tutaj zbudować. Hier kann kein\nSignal aufge-\nstellt werden!\n Nie możesz\nzbudować tu\nsemaforu!\n In order to lock the game, you have to protect the public player by password! W celu zapisania gry trzeba ustawić hasło! Loading a new game will end the current server session! Uruchomienie nowej gry zakończy bieżącą sesję serwera Lost connection\nto server! Serwer \nnieodpowiada!\nGrasz offline! Lost synchronisation\nwith server. Utracono synchronizację\nz serwerem. Maglevhalt muss auf\nMaglevschiene liegen!\n Przystanek kolei magnetycznej może znajdować się tylko na szynach magnetycznych! Monorailhalt muss auf\nMonorail liegen!\n Przystanek jednoszynowy\nmusi być na szynie. Monorails are not available yet! Kolej jednoszynowa nie jest jeszcze dostępna. More than one possibility to build this dock found. Znaleziono więcej niż jedną możliwość zbudowania tego doku. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Przystanek kolei wąskotorowej może zostać zbudowany tylko na szynach wąskotorowych! No bridges over runways! Nie można zbudować mostu nad pasem startowym. No curves on runways Nie można budować zakrętu pasa startowego. No suitable crossing Brak odpowiedniej trasy. No suitable way on the ground! Peron można wybudować tylko na płaskiej powierzchni! No through station here! Nie możesz tu wybudować \nprzystanku! Not enough bytes transferred Serwer nie wysłał wystarczającej liczby bajtów podczas transmisji gry. Not enough clearance. Za mało miejsca nad lub pod. Not enough money! Masz za mało pieniędzy aby to zbudować! On narrowgauge track only!\n Tylko na torach! Only public player can lock games! Tylko zarejestrowany gracz może zamknąć grę! Only up and down movement in the underground! W podziemiach możesz poruszać się w górę i w dół wyłącznie za pomocą narzędzi góra/dół! Out of funds Brak funduszy. Post muss neben\nHaltestelle\nliegen!\n Poczta musi\nznajdować się\nprzy stacji/przystanku!\n Protocoll error (expecting game) Błąd protokołu Schiffhalt muss im\nWasser liegen!\n Porty można budować\ntylko na wodzie!\n Server busy Serwer zajęty! Server version too new Wersja serwera jest nowsza od twojej. Show all revenue messages Pokaż zarobki wszystkich graczy Show no revenue messages Ukryj zarobki wszystkich graczy Show only player's revenue Pokaż tylko przychody graczy Terraforming not possible\nhere in underground view Terraformowanie jest pod ziemią niemożliwe. This tunnel branches. You can try Control+Click to remove. Ten tunel rozgałęzia się. Możesz spróbować ctrl+klik, aby usunąć. Too far away to merge stations! Zbyt daleko, aby połączyć stacje! Upgrade must have\na higher level Unowocześnić można tylko\nna wyższy poziom! Vehicle %s cannot choose because stop too short! Pojazd %s nie mógł wybrać drogi. Przystanek za krótki! Zughalt muss auf\nSchiene liegen!\n Stacje kolejowe\nmożna budować\ntylko na\ntorach kolejowych!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Pomoc

Spis pomocy

O Simutrans

%1$s

Jak używać

%2$s

Jak zacząć grę

%4$s

Jak grać

%5$s

Narzędzia

%3$s

Inne okna

%6$s Keyboard Help\n

Keyboard Help

\n Polecenia klawiaturowe\n

Polecenia klawiaturowe

\nSimutrans zna następujące polecenia klawiaturowe:

\nCtrl(< em>Ctrl) + kliknięcie - ukrywanie okna informacyjnego (tylko w niektórych miejscach)
\nCtrl(Ctrl) + narzędzie - działanie na wyższym poziomie lub .buduj tylko proste ścieżki.
\n\nEsc, Usuń: zamknij górne okno
\nBackspace >: Zamknięcie wszystkich okien
\nStrona w górę/Strona w dół, </>: Powiększ mniejszy/większy< br>\nKlawisze kursora i klawiatura numeryczna przesuwają mapę\n

\nDowolnie można przypisywać następujące polecenia:
\n At least one stop is connected to the town. Przynajmniej jeden przystanek jest połączony z miastem. At least one tile is connected to one stop. Co najmniej jeden budynek jest połączony z przystankiem. Color according to transport capacity left Kolor w zależności od pozostałej pojemności transportowej Color-coded terrain according to altitude. Pokaż/ukryj cieniowanie konturu terenu. Decrease water height Zmniejsz poziom wody Highlight railroad tracks Podświetl tory Highlite depots Podświetl magazyny Highlite electrical transmission lines Podświetl linie wysokiego napięcia Highlite factories Podświetl fabryki Highlite forests Podświetl lasy Highlite tourist attraction Podświetl atrakcje turystyczne Increase water height Zwiększ poziom wody Open station/stop details Pokaż szczegóły przystanku Overlay city limits Pokaż granice miast Overlay passenger destinations when a town window is open Przy otwartym oknie miasta: Pokaż cele pasażerów/poczty Overlay schedules/network Pokaż na mapie wszystkie istniejące połączenia Overlay town names Pokaż nazwy miast Please click on the map to add\nwaypoints or stops to this\nschedule. Kliknij na mapie aby dodać do tego rozkładu punkty przejazdowe albo przystanki. Remove double stops from schedule Usuń powtarzające się przystanki z rozkładu Set tile climate %s Zmień klimat na %s Show capacity and if halt is overcrowded Pokaż pojemność przystanku oraz stan przeciążenia. Show how many convoi reach a station Pokaż, ile pojazdów zatrzymuje się na tej stacji. Show how many people/much is waiting at halts Pokaż liczbę oczekujących Show initial passenger departure Pokaż, skąd przjeżdżają pasażerowie. Show level of city buildings Pokaż poziom budynków miejskich. Show mail service coverage/mail network Pokaż zasięg usług poczty Show passenger coverage/passenger network Pokaż zasięg/sieć pasażerów Show speedlimit of ways Pokaż maksymalne prędkości na drogach. Show the change of waiting at halts Pokaż historię czasu oczekiwania Show the owenership of infrastructure Pokaż właściciela infrastruktury. Show transported freight/freight network Pokaż transport towarowy i połączenia Show usage of network Pokaż wykorzystanie sieci. Shows a listing with all industries on the map. Pokaż listę wszystkich fabryk na mapie. Sum of departure/arrivals at halts Liczba przybyłych i odprawionych towarów (pasażerów, poczty) na tej stacji. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s prowadzi linię\nautobusową pomiędzy %s\na atrakcją %s\nna (%i,%i) %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s otworzył linię autobusową\npomiędzy %s\na fabryką %s\nna (%i,%i) %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nteraz korzysta z\n%i pojazdów pomiędzy\n%s w (%i,%i)\ni %s w (%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s \notworzył nowe połączenie \nkolejowe między \n%s w (%i,%i) a %s \nw (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Firma %s utworzyła połączenie\nlotnicze pomiędzy %s a %s. Ferry service by\n%s\nnow between\n%s \nand %s.\n Firma %s uruchomiła połączenie promowe\npomiędzy %s a %s. Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Podróżni mogą teraz korzystać z połączenia\nautobusowego firmy %s pomiędzy\n%s a %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Narzędzia edycji mapy LISTTOOLS Listy MAGLEVTOOLS Buduj kolej magnetyczną MONORAILTOOLS Buduj kolej jednoszynową NARROWGAUGETOOLS Buduj kolejkę wąskotorową RAILTOOLS Buduj koleje ROADTOOLS Buduj drogi SHIPTOOLS Buduj porty SLOPETOOLS Narzędzia zbocza SPECIALTOOLS Buduj budynki specjalne TRAMTOOLS Buduj tramwaje #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s ma teraz siedzibę w (%i,%i). Factory chain extended\nfor %s near\n%s built with\n%i factories. Gospodarka rośnie:\n%s blisko %s rozszerza łańcuch.\n%i założono nową fabrykę. Net wealth less than 10%% of starting capital! Majątek netto poniżej 10%% kapitału początkowego! New %s now available:\n%s\n Nowy %s jest dostępny:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Nowy łańcuch fabryk\ndla %s powstał\nniedaleko %s z %i fabrykami. New vehicle now available:\n%s\n Dostepny nowy pojazd:\n%s\n Now %u clients connected. Obecnie na serwerze jest %u graczy. overtaking wyprzedzanie Remove vehicle from map. Use with care! Usuń pojazd z gry. Używać ostrożnie! Screenshot\ngespeichert.\n Zapisano\nzrzut ekranu.\n Sends the convoi to the last depot it departed from! Wyślij pojazd do najbliższej bazy. Server preparing game ... Serwer przygotowuje grę... Trees Drzewa With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Dzięki dużemu festiwalowi,\n\nw %s zbudowano\n\nnowy monument powodując\n\nradość obywateli.\n #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Filtr liniowy #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/km %.2f$/mies.) (%i)- (%i) (in depot) (w zajezdni) [0] south-facing [0] zwrócone na południe [1] east-facing [1] zwrócone na wschód [2] north-facing [2] zwrócone na północ [3] west-facing [3] zwrócone na zachód [4] southeast corner [4] narożnik południowo-wschodni [5] northeast corner [5] narożnik północno-wschodni [6] northwest corner [6] narożnik północno-zachodni [7] southwest corner [4] narożnik południowo-zachodni [END] End [HOME] Home \nBauzeit bis do \nBauzeit von \nPojawia się od \nCan't open heightfield file.\n \nNie mogę odczytać pliku mapy.\n \ndirection: \nkierunek: \nelektrified \nzelektryfikowane \nHeightfield has wrong image type.\n \nZły typ obrazu\ndla mapy!\n(.ppm)\n \nis reserved by: \nzarezerwowany przez: \nminimum speed: \nprędkość minimalna: \nnot elektrified \nnie zelektryfikowane \nRibi (masked) \n\nKierunki\n\n(maskowane): \nRibi (unmasked) \nKierunki\n(niezamaskowane): \nSet phases: \nCzas zielonego światła: \nsingle way \npojedyncza droga \nway1 reserved by \nTrasa 1 zarezerwowana przez \nway2 reserved by \nTrasa 2 zarezerwowana przez \nwith sign/signal\n \n\nZe znakiem/semaforem\n %d buildings\n Budynków: %d %d convois Składów: %d %d Einzelfahrzeuge im Depot Pojazdów w zajezdni: %d %i car(s), %i pojazd(ów), %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. Wiek: %i lat i %i miesięcy %s at (%i,%i) now public stop. %s stał się węzłem publicznym. %s building %s %s %s - %s %s %s city %d %s %s miasto %d %s %s factory %s %s %s fabryka %s %s %s has entered a depot. %s\nPojazd czeka w bazie %s land %d %s %s teren %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s zbudowało nowy ratusz gdy ilość\n\nmieszkańców wyniosła\n\n%i. %s\nis crowded. %s\njest przepełniony/a. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nPrędkość maksymalna: %3$i km/h\n\nAktualna prędkość: %2$i km/h.\n %s\nwas liquidated. %s zbankrutował\n. Firma została zamknięta, a wszystkie aktywa sprzedane. %u Client(s)\n %u Klient(ci)\n %u Player (%u locked)\n %u Gracz (%u zablokowany)\n %s - %s
\n [%s]: %s
\n

Error

Błąd: Podwójne obiekty w głównym katalogu pak

W

Warning

addons for

Ostrzeżenie: zdublowane obiekty w katalogu dodatków

Dodatki dla 1 convoi 1 skÅ‚ad 1 Einzelfahrzeug im Depot 1 pojazd w zajezdni 100 km/h = %i tiles/month 100 km/h = %i pól/miesiÄ…c 1LIGHT_CHOOSE Jasność: 1WORLD_CHOOSE Opcje nowej mapy: 2LIGHT_CHOOSE Kolor: 2WORLD_CHOOSE Numer mapy: 3LIGHT_CHOOSE PrÄ™dk. przewijania: 4LIGHT_CHOOSE Odwróć przewijanie 5LIGHT_CHOOSE Pokaż przechodniów 5WORLD_CHOOSE Ilość miast: 6LIGHT_CHOOSE Piesi w miastach 6WORLD_CHOOSE Ruch drogowy: 8WORLD_CHOOSE Tryb dzieÅ„/noc A bridge must end on a way! Most musi koÅ„czyć siÄ™ na drodze! A bridge must start on a way! Most musi zaczynać\nsiÄ™ na drodze! Abfrage Zobacz... Abnehmer Odbiorcy About Informacje About scenario O scenariuszu Abriss Zniszcz/UsuÅ„ Absenken Obniż poziom Abspanntransformator Stacja transformatorowa Accelerate time PrzyÅ›piesz Act. load: %u MW\n Aktualne zużycie: %u MW\n Active player only Tylko Aktywny Gracz Add forest Zasadź las Add random citycar Dodaj losowy samochód add server Dodaj serwer Add Stop Dodaj Add stops for backward travel Dodaj stacje drogi powrotnej air Pas startowy Aircraft Samolot aircraft_tab Transportowe airplane samolot Airport Lotnisko AIRTOOLS Buduj lotniska All Wszystkie all convoi tooltips wszystkie podpowiedzi dotyczÄ…ce pojazdów Allow city growth Pozwól miastu siÄ™ rozrastać Allow player change Zezwól na zmianÄ™ gracza allowed climates:\n Dozwolone klimaty:\n Alters a schedule. Dodaje/usuwa przystanki z rozkÅ‚adu and arranged by aranżacja przez Angenommene Waren Tutejszy przemysÅ‚ potrzebuje: anhaengen Dodaj Anhaenger_tab Przyczepy Anheben PodnieÅ› poziom Appends stops at the end of the schedule Dodaj przystanki na koÅ„cu rozkÅ‚adu Apply Line Przypisz liniÄ™ Apr. KwiecieÅ„ April KwiecieÅ„ Arbeiter aus: Robotnicy mieszkajÄ… w: Arrivals from\n Przybycie z\n Arrived PrzybyÅ‚ych Assets Aktywa Aufloesen Rozłóż Aufspanntransformator Stacja transformatorowa Aug. SierpieÅ„ August SierpieÅ„ auto Automatyczny Autohalt muss auf\nStrasse liegen!\n Przystanek musi\nbyć postawiony\nna drodze. Available DostÄ™pny Available at custom date DostÄ™pne w niestandardowym terminie Bahndepot Lokomotywownia Bankrott:\n\nDu bist bankrott.\n Bankructwo:\n\nStraciÅ‚eÅ› caÅ‚y majÄ…tek.\n battery akumulatorowy Baum Drzewo baum builder Posadź drzewa Baustelle Konstrukcja Bauzeit Czas budowy Beenden Koniec gry Beginner mode Tryb PoczÄ…tkujÄ…cy Besonderes Gebaeude Atrakcja turystyczna BF Stacja bio Biologiczny Blockstrecke ist\nbelegt\n Tor używany\nprzez inny pociÄ…g\n Boden LÄ…d Bonus Multiplier: %i%% Mnożnik premii: %i%% Bonus Speed: %i km/h Premia prÄ™dkoÅ›ci: %i km/h Bonusspeed: %i km/h Maks. możliwa prÄ™dkość: %i km/h Boost (%%) Wzrost (%%) Borderless (disabled on fullscreen) Bez obramowania (wyłączone na peÅ‚nym ekranie) bridge is too high for its type! Ten typ mostu nie może być tak wysoki! Bridge is too long for this type!\n PrzÄ™sÅ‚o zbyt dÅ‚ugie\ndla tego typu mostu!\n Bruecke Most Bruecke muss an\neinfachem\nHang beginnen!\n Most musi\nzaczynać siÄ™ na\nrównym zboczu!\n Brueckenboden most Build air depot Zbuduj hangar lotniczy build choosesignals Semafory wyboru peronu Build city market Zbuduj market w najbliższym mieÅ›cie Build drain Stacja transformatorowa build HQ Zbuduj siedzibÄ™ Build land consumer Stacja zasilania Build maglev depot Baza kolei magnetycznej Build monorail depot Lokomotywownia Build narrowgauge depot Baza kolejowa Build powerline Linia wysokiego napiÄ™cia Build presignals Semafor wyprzedzajÄ…cy Build road depot Zbuduj garaż Build ship depot Stocznia Build signals Semafor Build train depot Lokomotywownia Build tram depot Zajezdnia tramwajowa Build truck depot Baza Building costs estimates Koszt budowy wyniesie Buildings Ilość budynków Built artifical slopes Zbuduj sztuczne zbocza Built random attraction Buduj losowÄ… atrakcjÄ™ Bus_tab Autobusy Can be overgrown Może być obroÅ›niÄ™ty Can only move from halt to halt or waypoint to waypoint. Może siÄ™ przemieszczać jedynie\nod przystanku do przystanku lub\nod punktu do punktu. Cancel Anuluj Cannot connect to offline server! Nie można połączyć siÄ™ z serwerem offline! Capacity Pojemność Capacity: Pojemność: Capacity: %.0f MW Pojemność: %.0f MW Capacity: %d%s %s\n Pojemność: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Pojemność: %s\nÅadunek: %d (%d%%) Cars are not available yet! Samochody nie sÄ… jeszcze dostÄ™pne. cars.\nstate pojazdów\n Cash Gotówka Change player ZmieÅ„ gracza Chart Wykres Chat_msg Czat Choose direction Wybierz kierunek Choose operation executed on clicking stored/new vehicles Wybierz operacjÄ™ wykonywanÄ… podczas klikniÄ™cia na pojazdy chooses a random map Wybiera losowÄ… mapÄ™ citicens Obywateli City attraction Atrakcja turystyczna City industries Marketów w miastach: City list Lista miast City size Ludność city_road Droga miejska citybuilding builder Rozbudowa urbanizacji CityLimit ZasiÄ™g miast cl_title Lista pojazdów cl_txt_sort Sortuj po: clamp Ogranicz zakres Cleanup schedule Wyczyść podwójne rozkÅ‚ady Clear block reservation Pokaż/usuÅ„ rezerwacje tras clf_chk_aircrafts Samoloty clf_chk_cars Pojazdy drogowe clf_chk_indepot W bazie clf_chk_maglev Kolej magnetyczna clf_chk_monorail Jednotorówka clf_chk_name_filter Nazwa filtru: clf_chk_narrowgauge Kolej wÄ…skotorowa clf_chk_noincome Bez dochodu clf_chk_noline Bez linii clf_chk_noroute Bez połączenia clf_chk_noschedule Bez rozkÅ‚adu clf_chk_obsolete przestarzaÅ‚e clf_chk_ships Statki clf_chk_spezial_filter Filtr specjalny: clf_chk_stucked Zablokowane clf_chk_trains PociÄ…gi clf_chk_trams Tramwaje clf_chk_type_filter Typ filtru: clf_chk_waren Filtruj towary: clf_title Filtruj listÄ™ pojazdów Climate Klimat Climate Control Kontrola klimatu Climates Klimaty closed ZamkniÄ™te Closes topmost line window when new line selected. Zamyka najwyższe okno linii po wybraniu nowej linii. COLOR_CHOOSE\n Wybierz kolor\n z tabeli:\n Company bankrupt Firma zbankrutowaÅ‚a! Company_msg Konkurencja Comparing pak files ... Porównywanie plików... Composed by Skomponowany przez Configure AI Skonfiguruj AI Configure AI setttings Skonfiguruj ustawienia AI Congratulation\nScenario was complete in\n%i months %i years. Gratulacje!\nScenariusz zostaÅ‚ ukoÅ„czony \nw %i miÄ™siecy i %i lat! Connected stops Połączony z: Connected with server Połącz z serwerem Connections Połączenia Constructed by Autor Constructed by %s Autor: %s construction speed Szybkość budowy Construction_Btn Koszty konstrukcji Consumed zużyto contains the following doubled objects:

zawiera następujące podwójne obiekty:

convoi %d of %d SkÅ‚ad %d z %d convoi error tooltips podpowiedzi dotyczÄ…ce błędów pojazdów Convoi following mode Tryb Å›ledzenia skÅ‚adu Convoi has been sent\nto the nearest depot\nof appropriate type.\n Pojazd zostaÅ‚\nwysÅ‚any do najbliższej\nbazy. Convoi is sold when all wagons are empty. Pojazdy zostanÄ… sprzedane gdy wszystkie wagony bÄ™dÄ… puste. convoi mouseover tooltips podpowiedzi po najechaniu myszÄ… na pojazd convoi passed last\nmonth %i\n \nskÅ‚ady przej. przez\nostatni miesiÄ…c: %i\n Convois Konwoje Convois: %d\nProfit: %s Pojazdów: %d\nZysk: %s Convoys Pojazdy Copy Convoi Kopiuj Copy the selected convoi and its schedule or line Skopiuj zaznaczone skÅ‚ady i ich rozkÅ‚ad jazdy Copy to clipboard Skopiuj do schowka Cost Koszt cost for removal Koszty usuniÄ™cia Cost per unit Koszt jednostkowy Cost: %8s (%.2f$/km %.2f$/m)\n Koszt: %8s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Koszt: %8s (%.2f$/km)\n Costs Koszty Create a new line based on this schedule Utwórz nowÄ… liniÄ™ na bazie tego rozkÅ‚adu curiosity builder Budowanie atrakcji curlist_title Lista atrakcji Currently playing: Teraz odtwarzane: Customers live in: Klienci mieszkajÄ… w: Date format Format daty deactivated in online mode Dezaktywowany w trybie online Dec. GrudzieÅ„ Deccelerate time Zwolnij czas December GrudzieÅ„ decrease underground view level zmniejsz poziom widoku pod ziemiÄ… Del Stop UsuÅ„ Delete Line UsuÅ„ liniÄ™ Delete the current stop UsuÅ„ bieżący przystanek Delete the selected line (if without associated convois). UsuÅ„ wybranÄ… liniÄ™ (jeÅ›li nie ma powiÄ…zanych skÅ‚adów). Delete this file. Skasuj ten plik Delivered Dostarczono Demand Popyt Demand: %.0f MW Popyt: %.0f MW\n Denkmal Pomnik Departed WysÅ‚anych Departs at Odjazd o Departure after Wyjazd po Departure board Tablica odlotów Departures per month Odjazdów na miesiÄ…c Departures to\n Odjazdy do\n Depot Baza Depots Bazy Der Tunnel ist nicht frei!\n Tunel nie jest pusty.\n Destination Przeznaczenie Destroying map ... Niszczenie mapy Details Szczegóły Die Bruecke ist nicht frei!\n Most nie jest pusty.\n diesel spalinowy directmail Poczta bezpoÅ›rednia Direkt erreichbare Haltestellen BezpoÅ›rednie połączenie z disable midi Wyłącz muzykÄ™ Midi Display bars above factory to show the status WyÅ›wietl paski nad fabrykÄ…, aby pokazać status Display settings Ustawienie wyÅ›wietlania Distance OdlegÅ‚ość distributing cities Dystrybucja miast distributing factories Dystrybucja fabryk Do not show Nie pokazuj Dock Port Dock must be built on single slope! Port musi być budowany na prostym zboczu. Downloading Pobieranie dp_title Lista baz Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Masz %d miesiÄ™cy na spÅ‚atÄ™ zadÅ‚użenia. Durchsatz Max. prod. Economy Ekonomia Eigenbesitz\n Obiekt publiczny\n Ein %s\npasst hier nicht.\n '%s'\nie pasuje\nw tym miejscu!\n Einstellungen Ustawienia Einstellungen aendern ZmieÅ„ opcje electric elektryczny Electricity Elektryczność Electricity producer\n\n Producent energii elektrycznej\n\n Electrics_tab Trakcja elektryczna Electrify track Elektryfikuj trasÄ™ enlarge map PowiÄ™ksz mapÄ™ enter a value between %i and %i wprowadź wartość pomiÄ™dzy %i - %i Enter address Wpisz adres IP Enter Password ZmieÅ„ nazwÄ™ gracza i hasÅ‚o Error Błąd Erzeuge neue Karte.\n ProszÄ™ czekać.\nTworzÄ™ mapÄ™.\n\n (Może to potrwać\n kilka minut)\n\n\n Es wird bereits\nein Fahrplan\neingegeben\n RozkÅ‚ad już\nzaplanowano.\nMusisz najpierw\nusunąć stary rozkÅ‚ad!\n Extract files Rozpakuj pliki Fabrikanschluss Pobliskie zakÅ‚ady Fabrikname nazwa fabryki Factories Fabryki factory details Szczegóły fabryk factorybuilder Buduj fabryki Fahrplan RozkÅ‚ad jazdy Fahrtziel Przeznaczenie: Fahrzeuge koennen so nicht entfernt werden Pojazdy nie mogÄ…\nbyć cofniÄ™te\ntÄ… drogÄ…!\n Fahrzeuge: Pojazdy: Farbe Kolor gracza Fast forward Przyspiesz Feb. Luty February Luty Ferry_tab Pasażerskie Fertig Gotowe Filename Nazwa pliku: Files from: Pliki z: Filter: Filtr: Finances of %s Finanse %s Finanzen Finanse find mismatch Sprawdź pliki fl_title Lista fabryk Flug_tab Pasażerskie follow me Åšledź Follow the convoi on the map. Podążaj za pojazdem na mapie font size Rozmiar czcionki Forest Lasy Found new city Załóż nowe miasto Fracht PojemnoÅ›ci magazynowej Frame time: Czas klatki: Free Capacity Pusta Å‚ad. freeplay mode Bez bankructwa Freight Transport Friction: Tarcie: fuel_cell Ogniwa paliwowe Full load Åaduj do: Fullscreen (changed after restart) PeÅ‚ny ekran (wymagany restart) Fussgaenger Pieszy Game info Multiplayer GAME PAUSED GRA WSTRZYMANA Game_msg Ogólne Gear: PrzeÅ‚ożenie: Gebaeude Budynek General Ogólne Generated Wytworzono Generation: %.0f MW Wytwarzanie: %.0f MW Gewicht Masa Gewinn Dochód: Give the selected vehicle(s) an individual schedule Nadaj wybranemu pojazdowi indywidulany rozkÅ‚ad. gl_btn_sort_catg Kategoria gl_title Lista towarów go home Do bazy Goods Towary Goods AI Towary AI Goods list Lista towarów Gross Profit Przychód caÅ‚kowity Groundobj Objekt groundobj builder Budowa obiektów naziemnych Grow city Rozwój miasta. Growth Rozwój miasta GUI settings Ustawienia graficznego interfejsu użytkownika H Przystanek Happy Zadowoleni Has slope graphics Posiada grafikÄ™ nachylenia Has Snow Ma Å›nieg Haus kaufen Kup dom Helligk. Grafika Help Pomoc Help text not found Nie znaleziono pomocy hide all building Schowaj wszystkie budynki hide city building Schowaj budynki miejskie hide objects under cursor Ukryj obiekty pod kursorem hide station names Ukryj nazwy przystanków hide transparent Schowaj przezroczyste hide trees Schowaj drzewa Hier warten/lagern: Lista czekajacych ludzi/towarów: Higher transport fees, crossconnect all factories Aby uzyskać wiÄ™cej zysków z transportu, dezaktywuj Just-in-time. Highlite schedule Harmonogram najważniejszych wydarzeÅ„ hl_title Lista stacji hl_txt_filter Filtr: hl_txt_sort Sortuj wg: hlf_chk_airport Lotniska hlf_chk_anleger Porty hlf_chk_bahnhof Dworce kolejowe hlf_chk_bushalt Przystanki hlf_chk_frachthof SkÅ‚ady towarów hlf_chk_keine_verb Bez połączenia hlf_chk_maglevstop Przystanek kolei magnetycznej hlf_chk_monorailstop Przystanek jednotorówki hlf_chk_name_filter Nazwa filtru: hlf_chk_narrowgaugestop Przystanek wÄ…skotorówki hlf_chk_overflow Ponad rozmiar hlf_chk_spezial_filter Filtr specialny: hlf_chk_tramstop Przystanek tramwajowy hlf_chk_type_filter Typ filtru: hlf_chk_waren_abgabe Produkcja: hlf_chk_waren_annahme Zapotrzebowanie: hlf_title Filtruj listÄ™ stacji Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Baza nie może zostać\nodnaleziona. Musisz\nwysÅ‚ać rÄ™cznie. Homeless Bezdomni hydrogene Wodór Idle: Bezczynni: ignore climates Ignoruj klimat In the industry legend show only currently existing factories W legendzie branżowej pokazuj tylko aktualnie istniejÄ…ce fabryki In Transit W drodze Increase Industry density ZwiÄ™ksz gÄ™stość przemysÅ‚u increase underground view level zwiÄ™ksz poziom widoku pod ziemiÄ… industrial building Budynek przemysÅ‚owy Industry overlay Interfejs fabryki Infinite mouse scrolling NieskoÅ„czone przewijanie mapy Infinite scrolling using mouse NieskoÅ„czone przewijanie za pomocÄ… myszy Init map ... Inicjalizacja mapy...\n\n Input WejÅ›cie Ins Stop Wstaw Insert stop before the current stop Wstaw przystanek przed bieżącym przystankiem Install graphics Zainstaluj grafikÄ™ Install paks Zainstaluj paczki Insufficient funds! Brak wystarczajÄ…cych funduszy! Intercity road len: DÅ‚ugość tras miÄ™dzymiast.: Intro. date Data wprowadzenia Intro. date: Wprowadzony: invalid nieważny Invalid coordinate Błędne współrzÄ™dne Invert stops Odwróć przystanki isometric map Mapa izometryczna Jan. StyczeÅ„ January StyczeÅ„ join game Graj online July Lipiec Jump to Skocz do June Czerwiec Kann Spielstand\nnicht laden.\n Nie mogÄ™ odczytać\nzapisanej gry!\n Kann Spielstand\nnicht speichern.\n Nie mogÄ™ otworzyć\n gry do zapisu!\n Kein Besitzer\n Brak wÅ‚aÅ›ciciela keine brak Keine Einzelfahrzeuge im Depot Å»adnych pojazdów w zajezdni Keyboard_Help\n Pomoc dotyczÄ…ca klawiatury\n koord koordynaty Kreuzung Skrzyżowanie labellist_title Lista etykiet Lade Relief Wczytaj mapÄ™ Laden Wczytaj Land attraction Atrakcja turystyczna Land industries Fabryk poza miastem: LANG_CHOOSE\n Wybierz\njÄ™zyk:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month ZeszÅ‚y miesiÄ…c: Last used tools Ostatnio użyte narzÄ™dzie Last Year ZeszÅ‚y rok: Leaving depot! Opuszczam zajezdniÄ™! leer pusty legacy (large heights) Dziedzictwo (duży wzrost) legacy (small heights) Dziedzictwo (maÅ‚y wzrost) Legend Legenda Leistung Moc Leistung: %d kW Moc: %d kW Leitung Linie elektryczne length: %d DÅ‚ugość: %d letzen Monat: diesen Monat: zeszÅ‚y miesiÄ…c: ten miesiac: Line Linia Line Management ZarzÄ…dzanie liniami line name mouseover tooltips Informacje o nazwie linii po najechaniu kursorem linear Liniowy Lineless convoys serving this stop Pojazdy obsÅ‚ugujÄ…ce ten przystanek bez przypisanej linii Lines serving this stop Line obsÅ‚ugujÄ…ce ten przystanek List of industries on the map Lista fabryk na mapie LKW_tab Ciężarówki Load game ZaÅ‚aduj grÄ™ load height data from file Wczytuje plik z mapÄ…. Load mode: Tryb Å‚adowania: Load scenario Scenariusz Load script tool ZaÅ‚aduj narzÄ™dzie skryptu Load Scripted AI ZaÅ‚aduj AI ze skryptu loaded zaÅ‚adowane loaded passenger/freight Sortuj pas./tow. wg: Loading (%i->%i%%)! Åadowanie (%i->%i%%) Loading (%i%%) departure %s! Åadowanie (%i%%) odjazd %s! Loading (%i%%)! Åadowanie (%i%%)! Loading addon paks ... Åadowanie paczek addon ... Loading map ... WczytujÄ™ mapÄ™... Loading paks ... Åadowanie paczek Loading skins ... Åadowanie skórek ... Loading time: Czas Å‚adowania: Lock game Zablokuj zmianÄ™ gracza (wymaga potwierdzenia) Lokomotive_tab Lokomotywy maglev vehicle Pojazd kolei magnetycznej maglev_track Tory Maglev Maglevdepot Lokomotywownia (Maglev) Mail Demand %d\n Popyt poczty %d\n Mail level Poziom poczty Mailbox Skrzynka pocztowa Mailbox Options Opcje skrzynki pocztowej Maintenance ObsÅ‚uga make stop public (or join with public stop next) costs %i per tile and level Utwórz/połącz z sÄ…siednim publicznym przystankiem (kosztuje %i$ za pole i stopieÅ„) Make way or stop public (will join with neighbours), %i times maintainance UstÄ…p drogi lub przestaÅ„ być publiczny (dołączy do sÄ…siadów), %i-krotność utrzymania Manual (Human) Nowy gracz Manufactured: Wyprodukowane: Map roughness Nierówn. mapy: map view Widok mapy map zoom Skala mapy Mar. Marzec March Marzec Margin (%%) Margines zysku Marker Etykietka max Max Max Boost (%%) Maksymalny wzrost (%%) Max income: Maks. dochód: Max. speed Maks. prÄ™dkość Max. speed: PrÄ™dkość max: Max. waiting time Maksymalny czas oczekiwania Maximum 254 stops\nin a schedule!\n Maksymalnie 254\nprzystanki na trasie!\n maximum length of rivers Max dÅ‚ugość rzek Maximum tile height difference reached. Maksymalna różnica\nwysokoÅ›ci pomiÄ™dzy\ndwoma polami\nzostaÅ‚a osiÄ…gniÄ™ta. Maxspeed PrÄ™dkość maksymalna May Maj Median Citizen per town Åšrednia mieszkaÅ„ców/miasto: Meldung Komunikat Menge Ilość merge stop Przystanek transferowy MessageOptionsText \nNowy rok\n\niadomoÅ›ci AI\n\nWiadomoÅ›ci miasta\n\nBrak trasy\n\nNowe Fabryki\n\nChat\n\nNowe pojazdy\n\nStacja peÅ‚na\n\nProblemy\n\nKorki\n\nScenario min Min. minimum length of rivers Min dÅ‚ugość rzek Minimum load Minimalny zaÅ‚adunek (%%) Missing pakfiles BrakujÄ…ce pliki! Modify the selected line Edytuj wybranÄ… liniÄ™ Monate alt miesiÄ™cy. Monorail Jednoszyn. monorail vehicle Pojazd jednoszyn. monorail_track Tor kolei jednoszynowej Monorailboden Kolej jednoszynowa (wspornik) Monoraildepot Zajezdnia jednoszynowa Month MiesiÄ…c month wait time miesiÄ™czny czas oczekiwania Monthly departures StaÅ‚e godziny odjazdów Months MiesiÄ…ce Monuments Monumenty Mountain height Wysokość gór: Move the map PrzesuÅ„ mapÄ™ Movingobj PrzesuÅ„ objekt Music playing disabled/not available Muzyka wyÅ‚/niedostÄ™pna. Music volume: GÅ‚oÅ›ność muzyki: mute sound wycisz Name Nazwa Narrowgauge Kolej wÄ…skotorowa Narrowgauge are not available yet! Kolej wÄ…skotorowa nie jest jeszcze dostÄ™pna! narrowgauge vehicle Pojazd kolei wÄ…skotorowej narrowgauge_track Tory o wÄ…skim przeÅ›wicie Narrowgaugedepot Lokomotywownia kolei wÄ…skotorowej Net ID: %p Identyfikator sieciowy: %p\n Net Wealth Wartość caÅ‚kowita Net wealth near zero MajÄ…tek netto bliski zeru Neue Karte Nowa mapa Neue Welt Utworz nowy Å›wiat new convoi Nowy skÅ‚ad New Line Nowa linia New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Utworzono nowÄ… liniÄ™!\nMożesz przypisac liniÄ™\npoprzez wybranie jej z\n listy wyboru powyżej. New Vehicles Nowe pojazdy Nickname: Nazwa gracza: no buildings hidden Bez ukrytych budynków no convois Brak pojazdów No goods are loaded onto this convoi. Pojazdy nie podlegajÄ… zaÅ‚adunkowi. no goods waiting Pusty no load bez Å‚adowania No player Brak gracza No Route Bez połączenia No stop here! Tu nie ma przystanku No suitable ground! ZÅ‚e podÅ‚oże! No terminal station here! Nie ma tutaj stacji! no timeline Bez osi czasu no tree bez drzew No vehicles are available for purchase. Brak możliwoÅ›ci zakupu pojazdów No. of Factories Liczba fabryk Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Najpierw ustal\nrozkÅ‚ad jazdy!\n none Nic nord Północ nordost Północny wschód nordwest Północny zachód Not allowed to make publicly owned ways! Niedozwolone jest tworzenie dróg publicznych! Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! RozkÅ‚ad jazdy tego\npojazdu nie może być zmieniany\n w czasie znajdywania trasy. Not enough fields would remain. To pole obsiane zbożem jest\nwÅ‚asnoÅ›ciÄ… prywatnÄ…, \na wÅ‚aÅ›ciciel nie wyraża zgody \nna jego sprzedaż. Nie możesz \nwiÄ™c zrównać go z ziemiÄ…. Nov. Listopad November Listopad now Teraz Now active as %s.\n Aktywny teraz jako %s.\n nowhere Nigdzie Number of rivers Ilość rzek Object Objekt Oct. Październik Odometer: %s km Przebieg Ok OK Oktober Październik On loan since %i month(s) Na debecie od %i miesiÄ…c/miesiÄ™cy. On mouseover Po najechaniu kursorem myszy on the wyjazd/miesiÄ…c pierwszy o (dd-gg-mm) On this map, you are not\nallowed to change player!\n Ta gra jest zablokowana.\nNie można zmieniać gracza.\n Only city chains Tylko sieci miejskie Only first %d differing paks reported. There are probably more. ZgÅ‚oszono tylko pierwsze %d różnych pakietów. Prawdopodobnie jest ich wiÄ™cej. Only full Unicode fonts Tylko peÅ‚ne czcionki Unicode Only land chains Tylko sieci lÄ…dowe Only one transformer per factory! Tylko jeden transformator na jednÄ… fabrykÄ™! Only show goods which are currently handled by factories Pokazuj tylko towary, które sÄ… obecnie obsÅ‚ugiwane przez fabryki open otwarty Operation Koszty ruchu Ops Profit Przychody Optionen Opcje Or enter a server manually: Lub połącz siÄ™ rÄ™cznie z serwerem: Origin Pochodzenie ost wschód Output WyjÅ›cie Ownership Posiadacz Pak which may cause severe errors: Pak może powodować poważne błędy: Pak which may cause visual errors: Pak może powodować błędy wizualne: Pak(s) different: Różnice w plikach Pak(s) missing on client: BrakujÄ…ce pliki: Pak(s) not on server: ZbÄ™dne pliki: Pakset differences Różnice w pakietach paletten Palet Pas_tab PociÄ…gi pasażerskie Passagiere Pasażerowie Passagierrate Poziom pasażerów Passagierziele Cele pas./pocz. Passenger AI SI przewozów pasażerskich Passenger Demand %d\n Popyt pas. %d\n Passengers %d %c, %d %c, %d no route Pasażerowie %d %c, %d %c, %d brak trasy Passengers %d %s, %d %s, %d no route Pasażerowie %d %s, %d %s, %d brak trasy Password HasÅ‚o Pause Pauza/Wznów Pax <%i> Mail <%i> Pasażerowie <%i> Poczta <%i> Pax level Liczba pasażerów PaxDest Cel podróży Percent Electricity Procent zelektryfikowania Planes are not available yet! Samoloty jeszcze nie sÄ… dostÄ™pne. Plant tree Zasadź drzewa. player Gracz player -1 CzÅ‚owiek player 0 Transport Publiczny player 1 Napik 128 AS player 10 Gracz 10 player 11 Gracz 11 player 12 Gracz 12 player 13 Gracz 13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans Ltd player 6 PSK & Co KG player 7 Gracz 7 player 8 Gracz 8 player 9 Gracz 9 Please choose vehicles first\n Najpierw wybierz pojazd.\n Post Poczta Postrate Poziom poczty Power Moc Power (MW) Moc (MW) Power: Moc: Power: %4d kW\n Moc: %4d kW\n Powerlines Linie elektr. Price Cena Problems_msg Problemy Produced Wyprodukowano Produces: %.1f units/minute Produkuje: %1f jednostek na minutÄ™ Production of %s has been stopped:\n%s\n Produkcja %s zostaÅ‚a zatrzymana:\n%s\n Production/Boost Produkcja/wzrost Produktion Wydobycie/Produkcja Profit Zysk promote to line Utwórz liniÄ™ q1 Wiosna q2 Lato q3 JesieÅ„ q4 Zima Query server Pokaż informacje o serwerze rail car wagon kolejowy random losowy Random age losowy rok Random map Losuj mapÄ™ Rathaus Ratusz Rating Ocena ratio_pax Proporcja Relevant NiezbÄ™dne Reliefkarte Mapa Remove UsuÅ„ remove airstrips UsuÅ„ pas startowy remove channels UsuÅ„ kanaÅ‚y remove interm. signals UsuÅ„ sygnaÅ‚y poÅ›rednie remove maglev tracks UsuÅ„ tory remove monorails UsuÅ„ szynÄ™ remove narrowgauge tracks UsuÅ„ tory remove powerlines UsuÅ„ liniÄ™ wysokiego napiÄ™cia remove roads UsuÅ„ drogÄ™ remove signal UsuÅ„ sygnaÅ‚ remove tracks UsuÅ„ tory Remove wayobj %s UsuÅ„ %s replace other signals ZamieÅ„ inne sygnaÅ‚y replace stop PrzenieÅ› przystanek request closing żądanie zamkniÄ™cia residential house Dom Restore natural slope Przywróć naturalne zbocze. Restwert: Cena sprzedaży: Retire date Data wycofania Retire. date: Data wycofania: return ticket Trasa powrotna Revenue Przychody Revert schedule Przywróć rozkÅ‚ad jazdy Revision: Rewizja: road droga road vehicle pojazd drogowy Roadsign Znak drogowy Rotate Building Obróć budynek Rotate map Obróć mapÄ™ o 90° Rotation Obrót Routing Obliczanie trasy Running cost Koszty ekploatacji sack Paczek sail SiÅ‚a wiatru Save Zapisz Saving map ... ZapisujÄ™ mapÄ™... Scenario complete: %i%% Scenariusz kompletny w %i%%. Scenario Debug Debugowanie scenariusza Scenario Error Log Log błędów scenariusza Scenario Goal Cel scenariusza Scenario Info Informacje o scenariuszu Scenario information Informacje o scenariuszu Scenario Result Rezultaty scenariusza Scenario Rules ReguÅ‚y scenariusza Scenario_ Scenariusz Schedule changing! Zmieniono rozkÅ‚ad jazdy! Schienentunnel Zbuduj tunel kolejowy Schiff_tab Statki Schiffdepot Stocznia Schleppkahn_tab Barki Screen scale: Skala ekranu Screenshot Zrzut ekranu. Scroll threshold Próg przemieszczenia Search: Szukaj: Seasons Pory roku Sehenswuerdigkeit Atrakcja turystyczna Select a server to join: Wybierz serwer żeby dołączyć: Select a theme for display Wybierz motyw do wyÅ›wietlenia Select display font Wybierz czcionkÄ™ do wyÅ›wietlenia Select one or more graphics to install (Ctrl+click): Wybierz jednÄ… lub wiÄ™cej grafik do zainstalowania (Ctrl+klik): Select soundfont Wybierz Å›cieżkÄ™ dźwiÄ™kowÄ… Sell the selected vehicle(s) Sprzedaj wybrany pojazd sended WysÅ‚anych SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 Sept. WrzesieÅ„ September WrzesieÅ„ Served by ObsÅ‚ugiwany przez Served by me ObsÅ‚ugiwane przeze mnie Server did not respond! Serwer nie odpowiada! Serves Line: ObsÅ‚uguje liniÄ™: Service ObsÅ‚uga set signal spacing Ustal odlegÅ‚ość sygnałów Setting Ustawienia Ship Wodne shops and stores Sklepy i biura Show all Pokaż wszystko show all building Pokaż wszystkie budynki Show also vehicles no longer in production. Pokaż również pojazdy wycofane z produkcji. Show also vehicles that do not match for current action. Pokaż również pojazdy nie pasujÄ…ce. Show always Zawsze pokazuj Show climates Pokaż klimaty Show contour Pokaż kontury Show even servers with wrong version or pakset Pokaż nawet serwery z niewÅ‚aÅ›ciwÄ… wersjÄ… lub zestawem pakietów Show finances for transport type Pokaż finanse dla rodzaju transportu Show future Pokaż przyszÅ‚e pojazdy show grid Pokaż siatkÄ™ Show industry Pokaż fabryki Show legend Pokaż legendÄ™ Show map scale Pokaż skalÄ™ Show mismatched Pokaż niedopasowane Show networks Sieci Show obsolete Pokaż zużyte pojazdy Show offline Pokaż offline Show only used pokaż tylko używane Show outline Pokaż zarys Show schedules Pokaż linie Show servers that are offline Pokaż serwery offline Show servers where game version or pakset does not match your client Pokaż serwery, na których wersja gry lub zestaw pakietów nie pasuje do Twojego klienta show station coverage Pokaż zasiÄ™g stacji show station names Pokaż nazwy stacji show waiting bars Pokaż wykresy czasu czekania show/hide block reservations Pokaż/ukryj rezerwacjÄ™ bloku Show/hide estimated arrival times Pokaż/ukryj szacowany czas przybycia show/hide object owner Pokaż/ukryj wÅ‚aÅ›ciciela obiektu Show/hide statistics Pokaż/ukryj statystyki Shows buttons about networks overlay. Pokaż przyciski nakÅ‚adki sieci Shows buttons on network overlay. Pokaż opcje naÅ‚ożenia sieci połączeÅ„. Shows buttons on special topics. Pokaż interaktywnÄ… mapÄ™ Shows consumer/suppliers for factories Pokazuje połączenia dostawcy-odbiorcy dla fabryk Shows the color code for several selections. Pokazuje kod koloru dla kilku opcji. Shows the currently selected schedule Pokazuje aktualnie wybranÄ… liniÄ™ Shrink city Zmniejsz miasto shuffle midis Odtwarzaj losowo Signal Semafor signal spacing OdstÄ™p sygnaÅ‚u Sim: SimpÄ™tle: Similar view as the main window Widok podobny jak w oknie głównym Single toolbar only Tylko pojedynczy pasek narzÄ™dzi Size (%d MB): Wielkość (%d MB): Size (area) Rozmiar (terenu) sliced underground mode PÅ‚aszczyzna mapy slot empty pusty Smart hide objects Inteligentne ukrywanie obiektów Sort by Sortuj wg Sort by: Sortuj wedÅ‚ug: Sort waiting list by Posortuj listÄ™ wedÅ‚ug Sound DźwiÄ™k Sound settings Ustawienia dźwiÄ™ku Sound volume: Poziom dźwiÄ™ku: Soundfonts are located in the music directory. Åšcieżki dźwiÄ™kowe znajdujÄ… siÄ™ w katalogu muzycznym. special freight Towar specjalny Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bonus za szybkość\ndroga %i km/h, kolej %i km/h\nstatki %i km/h, samoloty %i km/h Speedlimit PrÄ™dkość maks. Speichern Zapisz Spieler Gracz Spieler(mz) Gracze Spielerliste Lista graczy Spielstand wurde\ngeladen!\n \nGrÄ™ zaÅ‚adowano!\n Spielstand wurde\ngespeichert!\n \nGra zostaÅ‚a zapisana!\n Sprache JÄ™zyk Sprachen JÄ™zyki Stadtinformation Statystyka miasta Start the selected vehicle(s) Uruchom wybrany pojazd Starte Spiel Rozpocznij grÄ™ station labels Etykiety przystanków Station tiles: Wielkość stacji: Station_msg PrzepeÅ‚nienia Status Stan steam parowy Step timeline one year PrzesuÅ„ czas o rok do przodu Stops Stacje Storage Magazyn Storage capacity Pojemność magazynowa Strassendepot Zajezdnia Strassentunnel Zbuduj tunel drogowy street car Samochód sued PoÅ‚udnie suedost PoÅ‚udniowy wschód suedwest PoÅ‚udniowy zachód Summer snowline Åšnieg w lecie (linia) Supplied: %.0f %% Dostarczone: %.0f %% Suppliers Dostawcy Tage alt dniowe The following graphics are unmaintained: Poniższe grafiki sÄ… nie obsÅ‚ugiwane: The gradient does not fit a tunnel Nachylenie nie pasuje do tunelu Theme selector Wybór motywu There are still vehicles\nstored in this depot!\n W zajezdni/lokomotywowni\nnadal znajduje siÄ™\npojazd!\n This Month W tym miesiÄ…cu: This Year Bieżący rok: Tile not empty. Wyczyść pole zanim\nużyjesz NarzÄ™dzi zbocza. timeline Użyj osi czasu tl_title Lista miast To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Aby zachÄ™cić turystów\n\nw %s wybudowano\n\n%s\n\nz pomocÄ… %i\n\npodatników. To heavy traffic\nresults in traffic jam.\n Duży ruch\n\nspowodowaÅ‚ korki. Toggle day/night view Przełącz widok dzieÅ„/noc Toggle vehicle tooltips Przełącz podpowiedzi dotyczÄ…ce pojazdów tonnen t Toolbar position: Pozycja paska narzÄ™dzi Total inhabitants: MieszkaÅ„ców: Tourist attractions Atrakcji turystycznych: Tourists Atrakcje Town_msg Rozwój miasta Town: %s\n Miasto %s.\n Towns Miasta track trasa Tracks Tory Traffic Ruch traffic settings Ustawienia ruchu Train Kol. Trains are not available yet! PociÄ…gi jeszcze nie dostÄ™pne. Tram Tramwaj tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. Trolejbus %i km/h, jednotorówka %i km/h\nkolej magnetyczna %i km/h, wÄ…skotorówka %i hm/h. tram_track Trasa trolejbusa Tramdepot Zajezdnia tramwajowa Trams are not available yet! Tramwaje jeszcze nie dostÄ™pne. Transferring game ... PrzesyÅ‚anie gry ... Transformer only next to factory! Stacja transformatorowa musi być postawiona przy fabryce! Translation TÅ‚umaczenie transparencies Przezroczystość transparent background Przezroczyste tÅ‚o transparent station coverage Przezr. zasiÄ™g stacji Transported Przewiezione Trees disabled! Drzewa nieaktywne! TrolleyBus_tab Trolejbusy Truck Drogowe tt_Other Inny Tunnel muss an\neinfachem\nHang beginnen!\n Tunel musi\nzaczynać siÄ™ na \nrównym zboczu!\n Tunnel must start on single way! Tunel musi zaczynać siÄ™ na pojedynczej drodze. Tunnelboden Tunel underground mode Tryb podziemi UNDO failed! Nie można cofnąć.\n\nCofać trasÄ™ można do czasu\n\npostawienia semaforów\n\nstacji/przystanków. Undo last ways construction Cofnij ostatniÄ… budowÄ™ trasy. Unemployed Bezrobotni Unhappy Niezadowoleni units/day jedn./dzieÅ„ Unloading (%i%%)! RozÅ‚adowywanie (%i%%)! Update Line ZmieÅ„ liniÄ™ upgrade HQ Rozbuduj siedzibÄ™ Usage: %.0f %% Użycie: %.0f %% Usage/Output Zużycie/produkcja prÄ…du Use beginner mode Tryb poczÄ…tkujÄ…cego Use timeline start year Rozpocznij od roku: Vehicle %s can't find a route! Pojazd %s\nnie może znaleźć drogi! Vehicle %s is stucked! Pojazd %s utknÄ…Å‚! Vehicle count: Liczba pojazdów: Vehicle details Szczegóły pojazdu Vehicle Name Nazwa pojazdu Vehicle Power Moz pojazdu vehicles stored Przechowywane pojazdy Verbrauch Zużycie Vergroessere die Karte\n PowiÄ™ksz mapÄ™.\n Verkauf Sprzedano! verkaufen Sprzedaj Verkehrsteilnehmer Użytkownik drogi Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Masz dlugi!\n\nDostaÅ‚eÅ› %d miesiÄ™cy\nna spÅ‚atÄ™ dÅ‚ugu!\n vh_title Lista wszystkich pojazdów via Przez via %s\n przez %s\n via Menge przez (ilość) voranstellen Dostaw z przodu Waggon_tab Wagony waiting CzekajÄ…cych Waiting for clearance! Czekam na wolnÄ… drogÄ™! Walked pieszo walking Pieszo Warnings_msg Wiadomość o korkach Wasser Woda Water KanaÅ‚ Water level Poziom wody: water vehicle Pojazd wodny way %s cannot longer used:\n Droga typu %s nie może być dalej używana:\n way %s cannot longer used:\n%s\n Droga typu %s nie może być dalej używana:\n\n%s\n way %s now available:\n Droga %s jest dostÄ™pna:\n Way toll CÅ‚o Ways not connected Trasa nie jest połączona!\n waytype Rodzaj drogi Wegpunkt Punkt Weight Waga Weight: Waga: Wert Wartość west Zachód Wind direction Kierunek wiatru Winter snowline Åšnieg w zimie (linia) withdraw Wycofaj Withdraw All Wycofaj wszystko WRONGSAVE Nie można odczytać\npliku z poprzedniej\nwersji gry.\n Year Rok Year %i has started. RozpoczÄ…Å‚ siÄ™ rok %i. YEAR_SYMBOL r. Years Lata Your primary color: Główny kolor Your secondary color: PodrzÄ™dny kolor Zielort Przeznaczenie zooming in PowiÄ™ksz zooming out Oddal Zu nah am Kartenrand Za blisko brzegu mapy\naby cokolwiek\nzbudować!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci kolei magnetycznej: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for monorails: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci kolei jednoszynowej: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for motorcars: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci samochodów: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for narrowgauges: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci kolejki wÄ…skotorowej: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for planes: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci samolotów: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for railways: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci kolei: %.1f km/h osiÄ…gniÄ™ty przez %s. New world record for ship: %.1f km/h by %s. Nowy rekord prÄ™dkoÅ›ci statków: %.1f km/h osiÄ…gniÄ™ty przez %s. #________________________________script_ai_text_________________________________ #________________________________script_ai_text_________________________________ %s build additional convoy to line: %s %s Stwórz dodatkowy pojazd do linii: %s %s build rail line from %s (%s) to %s (%s) %s Stwórz liniÄ™ kolejowÄ… z %s (%s) do %s (%s) %s build road line from %s (%s) to %s (%s) %s Stwórz liniÄ™ drogowÄ… z %s (%s) do %s (%s) %s build ship line from %s (%s) to %s (%s) %s Stwórz liniÄ™ wodnÄ… z %s (%s) do %s (%s) %s extends the route from %s (%s) to %s (%s) %s wydÅ‚uża trasÄ™ z %s (%s) do %s (%s) %s optimize way line from %s (%s) to %s (%s) %s optymalizuje trasÄ™ z %s (%s) do %s (%s) %s removes convoys from line: %s %s usuwa pojazdy z linii: %s vehicles of the line %s were retired Pojazdy linii %s zostaÅ‚y wycofane #_________________________________tooltip_text__________________________________ #_________________________________tooltip_text__________________________________ Add convois with similar schedule to this line. Dodaj do tej linii pojazdy o podobnym harmonogramie. Enter intervall in days, hours, minutes Wprowadź odstÄ™p w dniach, godzinach, minutach Mirrors order of stops Odzwierciedla kolejność przystanków Revert to original schedule Przywróć oryginalny harmonogram #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL bryg &1_CITY_SYLL in &2_CITY_SYLL ów &3_CITY_SYLL inów &4_CITY_SYLL iny &5_CITY_SYLL in &6_CITY_SYLL owo &7_CITY_SYLL owice &8_CITY_SYLL ice &9_CITY_SYLL iska &A_CITY_SYLL ica %1_CITY_SYLL Grab %2_CITY_SYLL Ryp %3_CITY_SYLL Koz %4_CITY_SYLL Biel %5_CITY_SYLL Os %6_CITY_SYLL Wierzb %7_CITY_SYLL Kon %8_CITY_SYLL DÄ™b %9_CITY_SYLL Lip %A_CITY_SYLL Wol %B_CITY_SYLL Rudź %Z_CITY_SYLL Zim 1center %s %s 1extern %s %s ZamieÅ›cie 2center %s %s Centralny 2extern %s %s Kopalnia 3center %s %s Główny 3extern %s %s Fabryczny 4center %s ÅšródmieÅ›cie 4extern %s %s ZewnÄ™trzny 5center %s %s Robotniczy 6center %s Centrum %s 7center %s miasto %s simutrans-124.3/simutrans/text/pl/000077500000000000000000000000001474050137200171775ustar00rootroot00000000000000simutrans-124.3/simutrans/text/pl/color.txt000066400000000000000000000004571474050137200210640ustar00rootroot00000000000000POMOC: wybór koloru

Wybór koloru

Mozesz wybrac dla siebie odpowiedni kolor. Tym kolorem beda zaznaczone Twoje posiadlosci (budynki, tory itp.) Zwróc uwage, ze nie wszystkie nalezace do Ciebie budynki/pojazdy beda w tym kolorze (tak zadecydowali autorzy rysunków).

simutrans-124.3/simutrans/text/pl/depot.txt000066400000000000000000000050431474050137200210550ustar00rootroot00000000000000Zajezdnia i Lokomotywownia

Zajezdnia samochodowa & Lokomotywownia

W zajezdni mozesz kupic, sprzedac i ustalic rozklad jazdy dla wszystkich pojazdów kolowych, do niej nalezacych.

Menu zajezdni zawiera informacje o pojazdach które mozesz kupic i tych które wlasnie kupiles. W górnej czesci okna, po prawej, wyswietlone sa wszystkie pojazdy które mozesz kupic. Na glównej zakladce znajduja sie samochody, autobusy i lokomotywy a na drugiej zakladce przyczepy i wagony. (W zaleznosci w zaleznosci od tego czy jest to Zajezdnia czy Lokomotywownia) U góry z lewej znajduje sie wizerunek wlasnie zestawionych pojazdów (samochód+przyczepa lub lokomotywa+wagony).

Nizej znajduja sie wszystkie informacje o danym pojezdzie a na samym dole przyciski:

'Start' wlacza dany pojazd do ruchu. Wczesniej jednak pojazd musi miec ustalony 'Rozklad jazdy'. Dzieki opcji 'Sprzedaj' mozesz sprzedac dowolny pojazd, przyczepy czy wagony.

Po najechaniu kursorem na wizerunek dowolnego pojazdu bedziesz mógl odczytac wszystkie wazne informacje o tym pojezdzie. Aby kupić wybrany pojazd wystarczy na nim kliknac. Pojawi sie on wtedy w lewej czesci okna na górze. Po kupieniu nastepnego pojazdu pojawi sie on na górze, a wczesniej kupiony nieco nizej. Jesli pojazd posiada wagony/przyczepy to pojawia sie one pod wszystkimi pojazdami.

Aby zestawic pojazd z wagonami/przyczepami najpierw nalezy kupic pojazd, a nastepnie przejsc na zakladke 'Przyczepy' lub 'Wagony' i wybrac odpowiednie wagony/przyczepy. Mozna tez dokupic wagony/przyczepy do pojazdu ktory ich nie posiadal. W jednym czasie mozesz pracowac tylko nad jednym pojazdem. Aby sprzedac pojazd wybierz 'Sprzedaj' w menu zajezdni/lokomotywowni a nastepnie kliknij na pojazd który zamierzasz sprzedac. Na ekranie podana jest cena jaka mozesz uzyskac ze sprzedarzy. Cena ta wraz z uplywem czasu jest coraz nizsza. Uwaga! pojazd który chcesz sprzedac musi znajdowac sie w zajezdni/lokomotywowni.

W celu ustalenia rozkladu jazdy wybierz przycisk'Rozklad jazdy'. Pojawi sie okno rozkladu jazdy. Kiedy juz ustalisz przebieg trasy wystarczy kliknac na przycisk 'Start' - pojazd wyruszy w droge.

Aby pojazd skierowac do zajezdni/lokomotywoni musisz usunac z rozkladu jazdy wszystkie przystanki a nastepnie wstawic jako miejsce przystanku odpowiednia zajezdnie/lokomotywownie. Po dotarciu danego pojazdu do zajezdni/lokomotywowni bedzisz mógl go sprzedac lub zmienic ilosc wagonów/przyczep.

simutrans-124.3/simutrans/text/pl/display.txt000066400000000000000000000020141474050137200214020ustar00rootroot00000000000000POMOC: Opcje wyswietlania

Opcje wyswietlanie

Opcje te pozwalaja zmieniac wyglad i dzialanie gry Simutrans.
Opis opcji:

Jasnosc - rozjasnienie/przyciemnienie ekranu gry.
Kolory - bez efektu
Predkosc przewijania - im wyzsza liczba tym szybciej bedzie przewijany ekran.

Odwróc przewijanie - Zmiana kieruku przewijania na przeciwny (Ekran przewija sie trzymajac wcisniety prawy przycisk myszki)
Pokaz pasazerów - Mozna wlaczyc lub wylaczyc przedstawianie przechodniów w grze (Jesli masz slaby komputer wylacz pokazywanie pasazerów
Tryb dzien/noc - Kiedy usawisz ten tryb cyklicznie bedzie nastepowala noc (Ciemny ekran z bardzo ciekawymi efektami!).

Dolna czesc okna zawiera niektóre informacje zwiazane z praca komputera. Opcje te sa wazne jedynie dla prawdziwych 'komputerowców'.
Wazne: - Jesli bedziesz zglaszal problemy lub bledy mozesz byc poproszony o podanie tych informacji.

simutrans-124.3/simutrans/text/pl/finances.txt000066400000000000000000000017161474050137200215330ustar00rootroot00000000000000POMOC: Finanse

Finanse (f)

W tym oknie mozesz obserwowac stan swoich finansów w danym roku i w roku poprzednim.

W oknie znajduja sie ponizsze inforamcje:

Infrastruktura - wszystko co zbudowales: koleje, drogi, budynki, sygnalizacje itp.

Nowe pojazdy - Wszystkie zakupione w danym roku pojazdy/pociagi/statki.

Koszty przejazdów - Koszty zwiazane z utrzymaniem wszystkich pojazdów. (Koszty te dostepne sa w oknie 'Zajezdnia')

Dochód - Twoje dochody zwiazane z dzialalnoscia transportowa.

Utrzymanie - Koszty zwiazane z utrzymaniem budynków, dróg, mostów itp. (Na dole okna znajduja sie miesieczne koszty utrzymania)

Razem - Suma powyzszych kwot, zyski/straty w danym roku.

Balans - Pieniadze które posiadasz. Jest to kwota która mozesz inwestowac i wydawac.

simutrans-124.3/simutrans/text/pl/language.txt000066400000000000000000000020211474050137200215160ustar00rootroot00000000000000POMOC: Języki

Języki

Okno języków pozwala zmienić język używany w grze.

Można je otworzyć za pomocą opcji gry, wyświetla się również przy tworzeniu nowego świata.

Domyślnym językiem gry jest język angielski. Jeśli chcesz grać w innym języku, zaznacz odpowiednie pole przy nazwie języka.

Język może być dowolnie zmieniany podczas gry. Aby go zmienić, wejdź w Opcje gry i kliknij Język.

Zmiana następuje natychmiastowo gdy tworzysz nowy świat lub przy zamykaniu okienka Języki jeśli grasz na wcześniej stworzonej mapie.

Jeżeli tłumaczenie zawiera błędy, niektóre teksty mogą wyświetlać się w języku angielskim. Jeśli tak jest, zgłoś to!

Jeżeli chcesz pomóc w tłumaczeniu gry, odwiedź stronę SimuTranslator - https://translator.simutrans.com
Pamiętaj, każda pomoc się przyda!

simutrans-124.3/simutrans/text/pl/load.txt000066400000000000000000000010471474050137200206610ustar00rootroot00000000000000POMOC: Wczytaj gre

Wczytywanie zapisanej gry

Dzieki tej opcji mozesz kontynuowac rozgrywania wczesniej i zapisana gre. To menu podobne jest do menu 'Zapisz gre'.

Jesli bedziesz chcial wczytac gre której nie ma na dysku otrzymasz inforamacje o bledzie.

WAZNE Gry zapisane w starszych wersjach SimuTrans moga byc niekompatybilne z nowszymi wersjami!!! Szczególowe informacje o mozliwosci uruchomienia starszych gier znajdziesz w dodatkowej dokumentacji na stronie gry.

simutrans-124.3/simutrans/text/pl/map.txt000066400000000000000000000006431474050137200205200ustar00rootroot00000000000000POMOC: Mapa

Okno mapy

Mapa pokazuje wyglad utworzonego swiata z zaznaczeniem miast, rozmieszczenia przemyslu, kolei itp.

Kazdy rodzaj przemyslu oznaczony jest innym kolorem (Legenda kolorów znajduje sie u dolu mapy)

Jesli chcesz powiekszyc poglad mapy kliknij na niej prawym przyciskiem myszy. W ten sposób mozesz wybierac korzystac z dwuch stopni powiekszenia.

simutrans-124.3/simutrans/text/pl/new_world.txt000066400000000000000000000046501474050137200217450ustar00rootroot00000000000000POMOC: Tworzenie nowego swiata

Tworzenie nowego swiata

W tym oknie masz mozliwosc utworzenia nowej mapy. Mozesz przy tym korzystac z wielu opcji (wielkosc, gestosc przemyslu itp.)

Ponizej znajduje sie lista opcji dostepnych przy tworzeniu swiata wraz z ich krotkim objasnienim .

Numer mapy - Określa wygląd świata wraz z iloscia miast, obszarem i polozeniem wody, wzniesien itp. Dla kazdej mapy dostepny jest podglad (Podglad zmienia sie jesli ustawisz opcje dodatkowe). Domyslnie ustawiona jest mapa nr 33.
Wielkosc mapy - okresla wielkosc mapy w kwadratach w zakresi od 128*128 do 640*640. Domyslna wielkoscia jest 256.
Uwaga: Duze mapy wymagaja wiecej pamieci od komputera!

Osrodki przemyslowe - Wielkosc ta oznacza ilosc zakladów przemyslowych/kopaln na mapie. Mala gestosc oznacza trudniejsza gre (trudniej jest ustalic trasy przejazdu, trasy te sa czesto bardzo dlugi) Domyslna gestosc osrodków przemyslowych wynosi 125.
Ilosc miast - Pozwala ustalic ilosc miast na naszej mapie (od 2 do 64 miast). Domyslnie ustawiono 16 miast.
Transport osobowy - Okresla ilosc poruszajacych sie pojazdów prywatnych. Domyslna wielkoscia jest 8.

Poziomo wody - Okresla wysokosc (w kwadratach) poziomu wody. Mniejsza liczba oznacza odsloniecie wiekszej ilosci ladów. Domyslny poziom wody to 4.
Wysokosc gór - Okresla wysokosc najwiekszych gór na mapie. Mniejsza liczba oznacza mniej malych gór i wawozów. Dostepny zakres ustawien 0-160. Domyslna wilkoscia jest 160.
Wygladzanie mapy - Dzieki tej opcji wzniesienia moga byc lagodniejsze (zakres ustawien: 1-3).

Mapa losowa - Losowy wybór mapy (Bez mozliwosci zmian innych efektów).

Pokaz pasazerów - Wlacza/wylacza pokazywanie ludzi poruszajacych sie w miastach. Opcje ta mozna zmienic w czasie gry wybierajac 'Opcje wyswietlania'.
Tryb dzien/noc - Pozwala wybrac cykl dnia/nocy. Opcje te mozna zmienic podczas gry w menu 'Opcje wyswietlania'.

Wczytaj gre - Wczytanie zapisanej wczesniej gry (zobacz tez 'Wczytaj gre')
Rozpocznij gre Tworzy nowa mape na podstawie ustawien tego okna. Wygenerowanie duzej mapy moze zajac troche czasu.
Wyjscie - Wyjscie z gry.

simutrans-124.3/simutrans/text/pl/options.txt000066400000000000000000000014771474050137200214440ustar00rootroot00000000000000POMOC: opcje gry

Opcje gry

W tym oknie mozesz dokonac szczególowych ustawien gry. Ponizej znajduje sie lista ustawien z krótkim opisem.

Jezyk - Umozliwia wybór wersji jezykowych gry.
Kolory graczy - Pozwala wyrac/zmienic kolor twojej firmy.
Wyswietlanie - Opcje wyswietlania, np. tryb dzien/noc
Dzwiek - Ustawienia dzwieku i muzyki.
Gracze - Ustawienia dla graczy CPU.
Wczytaj - Wczytanie zapisanej gry
Zapisz - Zapisuje gre na dysk.
Nowa mapa - Rozpoczecie gry na nowej mapie
Koniec gry - Zakonczenie gry bez jej zapisania.

simutrans-124.3/simutrans/text/pl/players.txt000066400000000000000000000006601474050137200214210ustar00rootroot00000000000000POMOC: gracze

Gracze CPU

W tym oknie masz mozliwosc manipulacji AI graczy oraz ich wlaczania i wylaczania.

Aby wl/wyl gracza CPU wystarczy kliknac na kwadracik obok kolorów graczy. Prosze zauwazyc, ze raz wlaczony gracz CPU bedzie obecny nawet jesli zostanie wylaczony (zostanie tylko 'uspiony').

W oknie tym mozna tez sprawdzic stan funduszy graczy CPU (w tej wersji tylko balans).

simutrans-124.3/simutrans/text/pl/railtools.txt000066400000000000000000000057661474050137200217660ustar00rootroot00000000000000Budowa kolei

Budowa kolei

To okno zawiera narzedzia do budowy torów, sygnalów, tuneli, lokomotywowni, skrzyzowan i stacji. Po wybraniu danego narzedzia, obok kursora pojawi sie jego wizerunek.

W lewym górnym rogu znajduje sie narzedzie do budowy torów. Z jego pomoca mozna budowac tory miedzy dwoma kwadratami. Chcac zbudowac tory kliknij na kwadrat poczatkowy - kursor zamieni sie w buldozer - a nastepnie na kwadrat docelowy. Miedzy tymi kwadratami powstana tory (pola miedzy kwadratami powinny byc wolne). Jesli bedziesz chcial przeciac ulice zastosuj skrzyzowanie, most, lub tunel. Jesli nie bedzi polaczenia miedzy kwadratem poczatkowym i koncowym tory nie zostana wybudowane.

Nastepna ikona pozwala budowac sygnalizacje kolejowe. Sygnaly pozwalaja ustalic ruch pociagów. Dzieki nim dwa pociagi moga poruszac sie po jednym torze. Syganal jednokierunkowy nakazuje pociagowi jazde wyznaczonym torem. Sygnaly jednokierunkowe budujemy w ten sposób, ze stawiamy normalny sygnal i klikamy na niego - wtedy zamieni sie w syganl jednokierunkowy. Kolejne kliknieci spowoduje ze zmieni sie kierunek syganalu, a nastepne zamieni sygnal jednokierunkowy w dwukierunkowy (Sygnaly mozna zmieniac przy pomocy ikony 'sygnaly'). Nalezy uwazac aby zle ustawione sygnaly nie zablokowaly ruchu pociagów. Aby zbudowac sygnal kliknij lewym przyciskiem myszy na torach w miejscu gdzie ma stanac syganl. Sygnaly umieszczane sa na kwadratowym polu. Na jednym polu moze stac tylko jeden sygnal. Aby usunac sygnal uzyj narzedzia 'zniszcz'. Po kliknieciu na niepotrzebny sygnal zostanie on zlikwidowany (tory pozostana nienaruszone).

Ostatnia ikona zawiera narzedzia do budowy tuneli. Tunele sa uzywane do budowy krótkich polaczen przez wysokie góry. Przed skonstruowaniem tunelu najpierw musisz wybudowac tory. Po obu stronach góry w wybranym przez Ciebie miejscu musisz wybudowac zakonczenie torów (koniecznie na tej samej wysokosci po obu stronach!). Nastepnie wybuduj tunel klikjac na narzedzie 'Tunel' i przeciagajac linie pomiedzy utworzonymi zakonczeniami torów.

Kolejna ikona sa 'Skrzyzowania'. Dzieki 'Skrzyzowaniom' tory moga sie nawzajem przecinac. Skrzyzowania budujemy przez klikniecie na torach w miejscu gdzie chcemy je utworzyc.

Nastepnym narzedziem jest 'Lokomotywownia'. W lokomotywowni kupujemy, naprawiamy i sprzedajemy lokomotywy i wagony. Lokomotywnie mozna zbudowac tylko na koncu torów.

Ostatnia ikona to 'Stacja'. Stacje uzywane sa do zaladunku/wyladunku towarów i przewozu ludzi. Stacje moaga miec dowolny ksztalt i rozmiar. Na stacjach mozna przechowywac niograniczona liczbe towarów, ale fabryki przyjmuja towary jesli oczekuje mniej niz 1000 jednostek towaru. Stacje budujemy na skraju torów, ale nie moga powstac na pochylosciach skrzyzowaniach i zakretach. Kazdy segment stacji moze przyjac do 2 wagonów, dlatego upewnij sie czy dany pociag zmiesci sie w calosci na stacji. Wagony nie mieszczace sie na stacji nie moga transportowac towarów/ludzi.

simutrans-124.3/simutrans/text/pl/roadtools.txt000066400000000000000000000033361474050137200217530ustar00rootroot00000000000000POMOC: Budowa dróg

Budowa dróg

W tym oknie znajduja sie narzedzia do budowy dróg, przystanków, tuneli, punktów załadunku, zajezdni itp. Po kliknieciu na dane narzedzie kursor zmieni sie w ikonke obrazujaca to narzedzie.

W lewym górnym rogu znajduje sie ikona budowy dróg. Klikamy w miejscu gdzie droga ma sie rozpoczac (ikona zmieni sie w buldozer) a nastepnie zaznaczmy punkt, gdzie droga ma sie zakonczyc - droga zostanie zbudowana automatycznie.

Nastepna ikona to 'Przystanek'. Na przystankach gromadza sie ludzie z najblizszej strefy i mozemy ich przewozic do innych przystanków. Na przystanku moga sie zmiescic dwa autobusy. Przystanki mozna budowac na drogach z wylaczeniem skrzyzowan i zakretów.

Kolejne narzedzie sluzy do budowy tuneli. Dzieki nim mozemy skrócic czas podrózy poprzez duze góry. Przed wybudowaniem tunelu najpierw z obu stron góry musisz zbudowac drogi. Zakonczenie tych dróg musi znajdowac sie na tej samej wysokosci. Nastepnie wybieramy ikonke 'Tunel' i przeciagamy linie poprzez góry laczac konce dróg.

Ponizej znajduje sie narzedzie 'Skrzyzowanie'. Jest ono uzywane w celu przeprowadzenia przez droge linii kolejowych. Skrzyzowanie tworzymy klikajac w miejscu gdzie ma ono powstac.

Na lewo widnieje symbol 'Zajezdnia'. W zajezdni kupujemy i sprzedajemy wszystkie dostepne pojazdy i przyczepy. Zajezdnie budujemy na segmentach konczacych droge.

Ostatnie narzedzie to sluzy do budowy punktów przeladunku towarów. Punkty takie budujemy w poblizu kopaln i fabryk aby móc transportowac towary. W jednym punkcie moze stacjonowac równoczensnie do dwóch pojazdów. Punkty przeladunków budujemy na segmentach konczacych drogi.

simutrans-124.3/simutrans/text/pl/save.txt000066400000000000000000000014211474050137200206740ustar00rootroot00000000000000POMOC: zapis gry

Zapisywanie stanu gry

Jesli zamierzasz kontynuowac gre po wyjsciu z Simutrans bedziesz musial zapisac stan gry. Mozesz zapisac wszystkie gre w dowolnym momencie aby pózniej do niej powrócic.

W tym menu mozesz zapisac gre w nowym pliku, nadpisac istniejacy plik, lub usunac zapisana gre. Aby zapisac gre w nowym pliku musisz podac nazwe pliku i wcisnac przycisk 'zapisz' - za chwile pojawi sie komunikta potwierdzajacy zapis gry. Jesli chcesz nadpisac istniejacy plik kliknij na nazwie tego pliku.

Jesli chcesz usunac plik musisz sie dobrze zastanowic, poniewaz usunietego pliku nie da sie juz odzyskc (nawet z kosza w systemie Windows). W celu usuniecia pliku kliknij na przycisk 'X' obok nazwy danego pliku.

simutrans-124.3/simutrans/text/pl/schedule.txt000066400000000000000000000017121474050137200215350ustar00rootroot00000000000000Rozklad jazdy

Rozklad jazdy

Po zakupie pojazdu w oknie zajezdni/lokomotywowni wybierz przycisk 'Rozklad jazdy'. Przy kursorze pojawi sie zólta tabliczka. Teraz mozesz zaznaczyc gdzie bedzie sie zatrzymywal pojazd. Zwykle beda to przystanki i stacje. Dodatkowo masz mozliwosc ustawienia czy pojazd ma od razu odjezdzac z przystanku czy czekac az zostanie zaladowany okreslaona liczbe procent (zaznaczamy to u góry okna). Po ustaleniu trasy kliknij na 'wlacz' zniknie wtedy okno 'Rozklad jazdy' i ponownie pojawie sie okno zajezdni/lokomotywowni. Teraz wystarczy ze klikniesz na start i pojazd wyruszy w droge!

W oknie 'Rozklad jazdy' mozesz równiez dodawac lub zmieniac wczesnie zaplanowana trase. Po wcisnieciu 'Dodaj' wybierz dodatkowy przystanek na trasie. Jesli chcesz dany przystanek usuna kliknij 'Usun' a nastepnie zaznacz nazwe przystanku w oknie. Zaistniale zmiany zatwierdzamy wciskajac przycisk 'Gotowe'. C.D.N.

simutrans-124.3/simutrans/text/pl/shiptools.txt000066400000000000000000000015461474050137200217720ustar00rootroot00000000000000POMOC: transport morski

Transport morski

W tym oknie dostepne sa narzedzia do budowy stoczni, statków i portów.

W górnym lewym rogu znajduje sie ikona budowy portów. Po kliknieciu kursor zamieni sie w rysunek portu. Dzieki portom mozliwy jest transport ludzi i towarów pomiedzy obszarami przedzielonymi woda lub na wyspy. Po kliknieciu na brzegu morza zostanie zbudowany port. Mozna zbudowac port nawet duzych rozmiarów. Aby przydzielic statek do portu podczas ustalania rozkladu musisz wybrac pole sasiadujace z portem.Uwaga! Podczas usuwania portu moga wystapic bledy!

W menu znajduja sie dwie ikony budowy stoczni. Jedyna róznica jest kierunek wyplywania gotowych statków. Stocznie uzywane sa do produkcji statków. Stocznie budujemy klikajac w wybranym miejscu na wodzie w poblizu brzegu.

simutrans-124.3/simutrans/text/pl/sound.txt000066400000000000000000000012631474050137200210720ustar00rootroot00000000000000POMOC: Ustawienia dzwieku i muzyki

Ustawienia dzwieku i muzyki

W tym oknie masz mozliwosc ustawienia dzwieku i muzyki dla gry SimuTrans.

Poziom dzwieku utawiamy suwakiem. Suwak efektów ustala glosnosc dla pociagów, samochodów itp., natomiast suwak 'Muzyka' ustala glosnosc melodii odgrywanych w tle.
Istnieje mozliwosc odgrywania muzyki w petli do przodu i do tylu (dwa odrebne przyciski). Jesli muzyka jest nie dostepna przyciski te sa nieaktywne.
Uwaga: Gra nie zawiera zadnych melodii. Nalezy je dolaczyc samodzielnie i ustalic kolejnosc odgrywania. Jak tego dokonac? Odpowiedz znajdziesz w pliku readme w katalogu 'Music'.

simutrans-124.3/simutrans/text/pl/station.txt000066400000000000000000000012361474050137200214230ustar00rootroot00000000000000Infomacje o stacjach i przystankach

Informacje o stacjach i przystankach

Informacje te zawieraja niezbedne dane o wszystkich stacjach na mapie. Mozliwa jest zmiana nazw stacji.

U góry okna znajduje sie nazwa stacji, która mozna zmienic klikajac na niej i wpisujac nowa.

W tym oknie znajdziesz liste towarów i pasazerów danej stacji (ilosc i miejsce docelowe).

W szczególowych informacjach znajdziesz takie dane jak: - dokad nalezy przewozic towary/ludzi ze stacji - jakich towarów potrzebuje miejscowy przemysl (co nalezy tu przywozic)
Uwaga: Lista uaktualniana w czasie rzeczywistym.

simutrans-124.3/simutrans/text/pt.tab000066400000000000000000001353121474050137200177040ustar00rootroot00000000000000Portugues PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: pt Portugues # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Desligado cl_btn_filter_enable Ligado cl_btn_filter_settings Opções filtro cl_btn_sort_asc Crescente cl_btn_sort_desc Decrescente cl_btn_sort_id Nº criação cl_btn_sort_income Renda cl_btn_sort_name Nome cl_btn_sort_type Tipo clf_btn_alle Tudo clf_btn_invers Inv. clf_btn_keine Nada gl_btn_sort_bonus Bônus gl_btn_sort_name Nome gl_btn_sort_revenue Valor gl_btn_unsort Sem ordem hl_btn_filter_disable Desligado hl_btn_filter_enable Ligado hl_btn_filter_settings Opções filtro hl_btn_sort_asc Crescente hl_btn_sort_desc Decrescente hl_btn_sort_name Nome hl_btn_sort_type Tipo de carga hl_btn_sort_waiting Esperando hlf_btn_alle Tudo hlf_btn_invers Inv. hlf_btn_keine Nada Networks Esquemático Queueing Em fila Road toll Pedágio rodoviário Scenario Cenário Transfers Transferências #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Ártico desert Deserto mediterran Mediterrâneo rocky Alpino temperate Temperado tropic Tropical tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Não foi possível carregar o script do cenário! Can't buy obsolete vehicles! Não se pode comprar veículos obsoletos! Cannot alter water Não é possível alterar a água Cannot built depot here! Não é possível construir um depósito neste local! Cannot built this station/building\nin underground mode here. O edifício não pode\nser construído no subterrâneo.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Não é possível criar uma linha\nna aba Geral. Selecione\no tipo de linha pelas\noutras abas. Cannot create socket Não pôde criar conexão Convoi handles exhausted! Número máximo de comboios atingido. Convoy already deleted! Veículo já deletado! Das Feld gehoert\neinem anderen Spieler\n Você não tem permissão para usar ou modificar!\n\nIsto não lhe pertence! Der Besitzer erlaubt das Entfernen nicht Você não tem permissão para usar ou modificar!\n\nIsto não lhe pertence! Diese Zusammenstellung kann nicht fahren!\n Esta combinação de veículos não funciona! Flugzeughalt muss auf\nRunway liegen!\n Paradas aeroviárias só\npodem ser colocadas\nem pistas de\ntaxeamento.\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Não se pode construir\nessa dependência do\naeroporto aí!\n Hier kann kein\nSignal aufge-\nstellt werden!\n O sinal não pode ser instalado neste local! In order to lock the game, you have to protect the public player by password! Para proibir a mudança de jogador o Poder público deve ter uma senha! Lost connection\nto server! Conexão ao servidor foi perdida! Lost synchronisation\nwith server. A sincronização com o servidor foi perdida. Maglevhalt muss auf\nMaglevschiene liegen!\n Paradas de maglev devem\nficar em vias magnéticas! Monorailhalt muss auf\nMonorail liegen!\n A programação para os veículos de monotrilho deve ser sobre monotrilhos! Monorails are not available yet! Monotrilhos ainda não\nestão disponíveis!\n Narrowgaugehalt muss auf\nNarrowgauge liegen!\n A estação deve estar num trilho de bitola estreita! No suitable way on the ground! As estações devem ser construídas sobre uma superfície plana! No through station here! Não é possível colocar uma parada neste local! Not enough clearance. Deve existir uma altura mínima de dois entre duas vias! Not enough money! Você não tem bastante dinheiro para construir isto! On narrowgauge track only!\n Somente sobre trilhos de bitola estreita!\n Only public player can lock games! Somente o Poder público pode bloquear jogos! Out of funds Você não tem dinheiro suficiente para isto! Post muss neben\nHaltestelle\nliegen!\n Extensões de estação e\nagências postais devem\nser colocadas numa área\nlivre e ao lado de uma\nparada/estação.\n\n Protocoll error (expecting game) Erro de protocolo (esperando jogo) Schiffhalt muss im\nWasser liegen!\n A programação para embarcações deve ser sobre rios e mares! Server busy Servidor cheio Terraforming not possible\nhere in underground view Não é possível modificar\no terreno na visão subterrânea! This tunnel branches. You can try Control+Click to remove. Este túnel se ramifica. Tente utilizar CTRL+Clique para remover esta entrada. Upgrade must have\na higher level Atualização tem que ter um nível mais alto! Vehicle %s cannot choose because stop too short! Veículo %s não pôde se dirigir porque a parada é curta demais. Zughalt muss auf\nSchiene liegen!\n A programação para este tipo de veículo deve ser sobre trilhos! #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Ajuda

Índice

Sobre Simutrans

%1$s

Como usar

%2$s

Como iniciar um jogo

%4$s

Como jogar

%5$s

Ferramentas

%3$s

Outras janelas

%6$s Keyboard Help\n

Keyboard Help

\n Teclas de Atalho\n

Teclas de Atalho

\n

\nAs teclas de atalho apresentam teclas do teclado que acionam diversas funções.\n

\n

\nEsta ajuda aparece quando uma tecla sem função é pressionada ou pela Ajuda do Simutrans.\n

\n

\nO Simutrans faz diferenciação entre letras maiúsculas e minúsculas, então use [Shift] para usar letras maiúsculas.\n

\n

\nAs teclas com funções atribuídas são:\n

\n

\n[Setas do teclado]: Move a tela para a direção da seta.
\n[Backspace]: Fecha todas as janelas abertas.
\n[Delete] ou [Esc]: Fecha apenas a janela em uso.
\n[Enter] ou [Return]: Confirma ações.
\n[Page-Up] ou [>]: Aumenta zoom do jogo.
\n[Page-Down] ou [<]: Diminui zoom do jogo.
\n[F1]: Abre a Ajuda do Simutrans.\n

\n

\nUse com a parte numérica do teclado:

\n

\n[1]: Move a tela para a direção sul.
\n[2]: Move a tela para a direção sudeste.
\n[3]: Move a tela para a direção leste.
\n[4]: Move a tela para a direção sudoeste.
\n[6]: Move a tela para a direção nordeste.
\n[7]: Move a tela para a direção oeste.
\n[8]: Move a tela para a direção noroeste.
\n[9]: Move a tela para a direção norte.\n

\n

\n[Ctrl] pode ser utilizado para trocar as vias por uma mais lenta.\n

\n

\nAtalhos para ferramentas e opções:\n

\n Decrease water height Reduzir nível da água Highlight railroad tracks Realçar ferrovias Highlite depots Realçar depósitos Highlite electrical transmission lines Realçar linhas de transmissão Highlite factories Realçar fábricas Highlite forests Realçar florestas Highlite tourist attraction Realçar atrações turísticas Increase water height Elevar nível da água Overlay city limits Sobrepor limites das cidades Overlay passenger destinations when a town window is open Sobrepor destinações de passageiros quando a janela Estatísticas da Cidade estiver aberta Overlay schedules/network Sobrepõe esquema de rede de transportes no mapa Overlay town names Sobrepor nomes de cidades Please click on the map to add\nwaypoints or stops to this\nschedule. Por favor clique no mapa para adicionar\npontos de passagem ou paradas a esta\nprogramação. Set tile climate %s Clima do quadro %s Show capacity and if halt is overcrowded Mostrar capacidade e se a parada está lotada Show how many convoi reach a station Mostrar quantos veículos atendem a estação Show how many people/much is waiting at halts Mostrar quantos passageiros há e quanto tempo ficam esperando nas paradas Show initial passenger departure Mostrar origem dos passageiros Show level of city buildings Mostrar o nível dos edifícios urbanos Show mail service coverage/mail network Mostrar a cobertura da rede de transporte de correios Show passenger coverage/passenger network Mostrar a cobertura da rede de transporte de passageiros Show speedlimit of ways Mostrar o limite de velocidade das vias Show the change of waiting at halts Mostrar evolução da espera nas paradas desde o mês anterior Show the owenership of infrastructure Mostrar propriedade sobre a infra-estrutura Show transported freight/freight network Mostrar a rede de transporte de cargas/bens Show usage of network Mostrar uso da rede de transportes Shows a listing with all industries on the map. Lista de indústrias no mapa Sum of departure/arrivals at halts Soma de partidas e chegadas nas paradas #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s começou uma linha\nde ônibus entre %s e a\natração %s em (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s começou uma linha\nde ônibus entre %s e a\nfábrica %s em (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s começou a operar\n%i caminhões entre %s\nem (%i,%i) e %s em\n(%i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s abriu novos\ntrilhos entre %s em\n(%i,%i) e %s em\n(%i,%i).\n Airline service by\n%s\nnow between\n%s \nand %s.\n %s\niniciou nova linha\naérea entre \n%s \ne %s.\n\n Ferry service by\n%s\nnow between\n%s \nand %s.\n %s\n iniciou nova linha\nde barcas entre\n%s e \n%s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s abriu uma nova linha de ônibus entre %s e %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Editor do mapa LISTTOOLS Listas MAGLEVTOOLS Ferramentas de MagLev MONORAILTOOLS Monotrilhos NARROWGAUGETOOLS Bitola Estreita RAILTOOLS Ferrovias ROADTOOLS Estradas SHIPTOOLS Navegação SLOPETOOLS Editor de terrenos SPECIALTOOLS Ferramentas especiais TRAMTOOLS Bondes #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). A empresa %s construiu seu centro administrativo. Factory chain extended\nfor %s near\n%s built with\n%i factories. Economia em crescimento!\nA %s, perto de %s, ampliou sua cadeia de produção.\n%i nova(s) fábrica(s) fundada(s). Net wealth less than 10%% of starting capital! Riqueza líquida inferior a 10%% do capital inicial! New %s now available:\n%s\n Novo %s disponível:\n%s New factory chain\nfor %s near\n%s built with\n%i factories. Nova cadeia de\nprodução de %s\npróximo a %s\nfoi construída com\n%i fábricas. New vehicle now available:\n%s\n Novo veículo disponível:\n%s\n Now %u clients connected. Agora %u clientes conectados. Remove vehicle from map. Use with care! Vende o veículo e toda sua carga é perdida Screenshot\ngespeichert.\n \nImagem salva!\n Sends the convoi to the last depot it departed from! Envia o veículo para o depósito mais próximo With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s inaugurou um monumento.\n%i pessoas participaram. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Busca rápida #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (no depósito) \nBauzeit bis até \nBauzeit von \nAno de Disponibilidade: \nCan't open heightfield file.\n Não foi possível abrir o arquivo de relevo. \ndirection: \nBits de direção: \nelektrified \nEletrificado\n \nHeightfield has wrong image type.\n O arquivo de relevo está\nem um formato incorreto.\n \nis reserved by: Sendo usada por:\n \nminimum speed: \nVelocidade Mínima: \nnot elektrified \nNão eletrificado\n \nRibi (masked) \nBits direção (oculto): \nRibi (unmasked) \nBits direção (visível): \nSet phases: \nTempo do Semáforo\nNorte-Sul: Leste-Oeste: \nsingle way Mão única \nway1 reserved by \nVia 1 sendo usada por \nway2 reserved by veículos.\nVia 2 sendo usada por \nwith sign/signal\n \ncom sinal\n %d buildings\n %d edifícios\n %d convois %d veículos %d Einzelfahrzeuge im Depot Armazenados: %d %i km/h (max. %ikm/h) %i km/h (máx. %ikm/h) %i years %i months old. Idade: %i anos e %i meses %s at (%i,%i) now public stop. %s se tornou em parada pública. %s building %s %s %s - Parada %s %s city %d %s %s - %d.a %s urbana %s factory %s %s %s - Parada %s %s has entered a depot. O veículo\n%s\ninforma que\nchegou ao\ndepósito %s land %d %s %s - %d.a %s rural %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s construiu uma nova prefeitura quando atingiu %i habitantes. %s\nis crowded. %s está lotada. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nVelocidade máx. %3$i km/h\n\nVelocidade atual %2$i km/h.\n %s\nwas liquidated. %s faliu e foi liquidado. Todas as operações foram paralizadas, e todos os ativos foram vendidos. %u Client(s)\n %u cliente(s)\n %u Player (%u locked)\n %u jogadores (%u com senha)\n 1 convoi 1 veículo 1 Einzelfahrzeug im Depot Armazenados: 1 1LIGHT_CHOOSE Luminosidade 1WORLD_CHOOSE Criando novo jogo: 2LIGHT_CHOOSE Cores: 2WORLD_CHOOSE Número do mapa 3LIGHT_CHOOSE Velocidade botão direito 4LIGHT_CHOOSE Inverter direção botão direito 5LIGHT_CHOOSE Pedestres descem nas paradas 5WORLD_CHOOSE Número de cidades 6LIGHT_CHOOSE Pedestres nas cidades 6WORLD_CHOOSE Densidade do tráfego 8WORLD_CHOOSE Alternar dia e noite A bridge must start on a way! Uma ponte deve começar onde termina uma via e ter seu final livre! Abfrage Consultar Abnehmer Consumidores About Sobre About scenario Autoria Abriss Remover Absenken Rebaixar terreno Abspanntransformator Transformador industrial Accelerate time Acelerar tempo Act. load: %u MW\n Carga ativa: %u MW\n Active player only Apenas deste jogador Add forest Adicionar floresta Add random citycar Adicionar veículos urbanos add server Criar servidor Add Stop Adicionar Add stops for backward travel Adiciona as mesmas paradas no sentido contrário air Aviões aircraft_tab Cargueiros airplane veículo aéreo Airport Aeroporto AIRTOOLS Aeroportos All Todos all convoi tooltips Status sobre os veículos Allow city growth Permitir crescimento Allow player change Permitir mudança de jogador allowed climates:\n Climas permitidos:\n Alters a schedule. Modifica a programação do veículo Angenommene Waren Indústrias próximas precisam de: anhaengen A reboque Anhaenger_tab Reboques Anheben Elevar terreno Appends stops at the end of the schedule Adiciona paradas ao fim da programação Apply Line Associar April Abril Arbeiter aus: Trabalhadores e correio de: Arrivals from\n Chegadas de\n Arrived Chegaram Assets Valor dos veículos Aufloesen Desmontar Aufspanntransformator Transformador de usina August Agosto Autohalt muss auf\nStrasse liegen!\n A programação para veículos rodoviários\ndeve ser sobre estradas! Available Disponível Bahndepot Depósito ferroviário Bankrott:\n\nDu bist bankrott.\n Fim de Jogo\n\nVocê ficou muito tempo com a conta negativa e faliu!\n\nSe prefere não usar dinheiro, na lista de jogadores há a opção\nModo Jogo-livre. battery bateria Baum Árvore baum builder Plantar árvore Baustelle Canteiro de obras Bauzeit Época: Beenden Sair Beginner mode Modo iniciante Besonderes Gebaeude Atração turística BF Estação bio Animal Blockstrecke ist\nbelegt\n Esta seção está em uso por outro veículo. Boden Terra Bonusspeed: %i km/h Vel. máxima possível: %i km/h Boost (%%) Reforço (%%) bridge is too high for its type! O local é muito alto para este modelo de ponte! Bridge is too long for this type!\n A distância da ponte é muito extensa para este modelo! Bruecke Ponte Bruecke muss an\neinfachem\nHang beginnen!\n A ponte deve\ncomeçar em um\ntalude reto!\n Brueckenboden Ponte Build air depot Hangar build choosesignals Colocar sinais de opção de parada Build city market Construir mercado Build drain Construir transformador build HQ Construir empresa Build land consumer Construir usina de energia Build maglev depot Depósito de Maglev Build monorail depot Depósito de monotrilho Build narrowgauge depot Depósito de bitola estreita Build powerline Construir linha elétrica Build presignals Colocar sinal intermediário\n Build road depot Garagem Build ship depot Estaleiro Build signals Colocar sinais Build train depot Depósito ferroviário Build tram depot Depósito de bonde Build truck depot Garagem Building costs estimates Estimativa de custo Buildings Edifícios Built artifical slopes Construir muro de arrimo Built random attraction Construir atração aleatória Bus_tab Ônibus Can only move from halt to halt or waypoint to waypoint. Só pode mover de parada\npara parada ou de ponto\ndepassagem para ponto\nde passagem. Cancel Cancelar Cannot connect to offline server! Não é possível se conectar a um servidor desligado! Capacity: Capacidade: Capacity: %.0f MW Capacidade: %.0f MW\n Capacity: %d%s %s\n Capacidade: %3d%s %s Capacity: %s\nLoad: %d (%d%%) Capacidade: %s\n? %d (%d%%) Cars are not available yet! Carros ainda não estão\ndisponíveis!\n cars.\nstate veículos.\nCancela: Cash Balanço Change player Mudar jogador Chart Gráfico Chat_msg Chat Choose direction Escolher direção Choose operation executed on clicking stored/new vehicles Opções para vender ou adicionar veículos por uma ordem chooses a random map Escolher um mapa aleatório citicens Habitantes City attraction Atrações urbanas City industries Indústrias urbanas City list Lista de cidades City size Habitantes city_road Via urbana citybuilding builder Construtor de edifícios urbanos CityLimit Limites cidade cl_title Lista de veículos cl_txt_sort Classificação por: Clear block reservation Mostrar/limpar vias reservadas clf_chk_aircrafts Aviões clf_chk_cars Automóveis clf_chk_indepot No depósito clf_chk_maglev Maglev clf_chk_monorail Monotrilhos clf_chk_name_filter Filtro por nome: clf_chk_narrowgauge Bitola estreita clf_chk_noincome sem renda clf_chk_noline Sem linha clf_chk_noroute Sem rota clf_chk_noschedule Sem programação clf_chk_obsolete obsoleto clf_chk_ships Barcos clf_chk_spezial_filter Filtro especial: clf_chk_stucked Preso clf_chk_trains Trens clf_chk_trams Bondes clf_chk_type_filter Filtro por veículo: clf_chk_waren Filtro por carga: clf_title Filtro da lista de veículos Climate Control Controle do clima closed Fechada COLOR_CHOOSE\n Escolha duas cores\npara sua companhia: Company bankrupt Falido! Company_msg Concorrência Comparing pak files ... Comparando arquivos... Configure AI Configurar IA Configure AI setttings Defina configurações IA Congratulation\nScenario was complete in\n%i months %i years. Parabéns! \nO cenário foi \ncompletado em \n%i meses e%i anos! Connected stops Paradas conectadas: Connected with server Conectado com servidor Constructed by Pintado por Constructed by %s Desenhado por %s construction speed velocidade de construção Construction_Btn Gasto em obras Consumed Consumido convoi %d of %d Veículo %d de %d convoi error tooltips Apenas status de erro Convoi has been sent\nto the nearest depot\nof appropriate type.\n O veículo foi enviado ao depósito do seu tipo mais próximo. Convoi is sold when all wagons are empty. Os veículos serão vendidos assim que estiverem descarregados convoi mouseover tooltips Status veículos com mouse convoi passed last\nmonth %i\n Tráfego no último mês: %i veículos\n Convois Comboios Convois: %d\nProfit: %s Comboios: %d\nLucro: %s Convoys Veíc. jogador Copy Convoi Copiar Copy the selected convoi and its schedule or line Compra um veículo igual e com programação igual cost for removal \nCusto de remoção: Cost: %8s (%.2f$/km %.2f$/m)\n Custo: %8s (%.2f$/km %.2f$/m)\n Cost: %8s (%.2f$/km)\n Custo: %8s (%.2f$/km)\n Costs Custos Create a new line based on this schedule Cria uma nova linha baseada na programação deste veículo curiosity builder Construtor de atrações turísticas curlist_title Lista de atrações turísticas Currently playing: Tocando: Customers live in: Consumidores vivem em: deactivated in online mode Não ativo enquanto online Deccelerate time Desacelerar tempo December Dezembro decrease underground view level Baixar nível de visão subterrânea Del Stop Apagar Delete Line Apagar Delete the current stop Selecione e depois clique sobre a parada que deseja apagar Delete the selected line (if without associated convois). Apagar linha selecionada (se não houver veículos nela) Delete this file. Apagar este arquivo Delivered Entregue Demand Demandado Demand: %.0f MW Demanda: %.0f MW\n Denkmal Monumento Departed Partiram Departure board Tempo viagem Departures to\n Partidas para\n Depots Depósitos Der Tunnel ist nicht frei!\n O túnel está sendo utilizado ou ele não\nlhe pertence! Destination Destino Destroying map ... Destruindo mapa antigo... Details Detalhes Die Bruecke ist nicht frei!\n A ponte está sendo utilizada ou ela não\nlhe pertence! diesel Díesel directmail folhetos Direkt erreichbare Haltestellen Paradas conectadas diretamente: disable midi Mudo Display settings Opções de vídeo Distance Distância Dock Doca Dock must be built on single slope! A doca deve ser construida sobre\na margem! Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Faltam %d meses para pagar a dívida! Durchsatz Produção máx. de Economy Economia Eigenbesitz\n Propriedade pública Ein %s\npasst hier nicht.\n Não se pode usar um\n'%s' aqui.\n Einstellungen aendern Mudar opções electric Eletricidade Electricity Eletricidade Electricity producer\n\n Produtor de eletricidade\n\n Electrics_tab Tróleibus Electrify track Eletrificar linha enlarge map Expandir mapa enter a value between %i and %i Digite um valor entre %i e %i Enter address Insira o endereço Enter Password Nome do jogador e senha Error Erro Erzeuge neue Karte.\n Criando mapa...\n\nPor favor,\naguarde enquanto um novo mapa é criado...\n\nIsso pode levar alguns minutos e fazer o programa\nnão responder! Es wird bereits\nein Fahrplan\neingegeben\n Já tem uma rota\nsendo programada.\nTermine-a antes\nde programar outra!\n Fabrikanschluss Indústrias conectadas: Fabrikname Nome Factories Fábricas factory details Visualizar cadeias factorybuilder Construtor de fábricas Fahrplan Programar Fahrtziel Destino: Fahrzeuge koennen so nicht entfernt werden O veículo ou edifício está em uso e não pode ser eliminado! Fahrzeuge: Veículos: Farbe Cores Fast forward Acelerar tempo February Fevereiro Ferry_tab Barcos Fertig Pronto Filename Arquivo: Files from: Arquivos de: Filter: Filtro: Finances of %s Finanças de %s Finanzen Finanças find mismatch Comparar seu pak fl_title Lista de fábricas Flug_tab Aviões de passageiros follow me Siga-me Follow the convoi on the map. Segue o veículo no mapa Forest Florestas Found new city Fundar nova cidade (Shift+C) Fracht Produtos Frame time: Tempo por quadro: Free Capacity Capacidade freeplay mode Modo jogo-livre Friction: Fator de atrito atual: fuel_cell Célula combustível Full load Carga mínima (%%) Fundament Arrimo Fussgaenger Pedestre Game info Jogo Online GAME PAUSED JOGO PAUSADO Game_msg Geral Gear: Câmbio: Gebaeude Edifício General Geral Generated Gerado Generation: %.0f MW Geração: %.0f MW\n Gewicht Peso Gewinn Renda: Give the selected vehicle(s) an individual schedule Cria uma programação individual gl_btn_sort_catg Tipo de carga gl_title Lista de cargas go home Ir ao depósito Goods Bens Goods AI IA Produtos Goods list Informações das cargas Gross Profit Lucro líquido Groundobj Objeto-chão Grow city Aumentar habitantes da cidade Growth Crescimento H - Parada Happy Contentes Haus kaufen Comprar edifício Helligk. Vídeo Help Ajuda Help text not found Texto de ajuda não encontrado\n hide all building Todos os edifícios ocultos hide city building Edifícios urbanos ocultos hide objects under cursor Oculta dinamicamente objetos ao redor do cursor. Tamanho é ajustável. hide station names Ocultar nomes das paradas hide transparent Usar transparência ao ocultar hide trees Ocultar árvores Hier warten/lagern: Passageiros/carga esperando: Higher transport fees, crossconnect all factories Taxas de transporte maiores, Fábricas podem enviar produtos para qualquer outra Highlite schedule Mostra as paradas da programação hl_title Lista de paradas hl_txt_filter Filtro: hl_txt_sort Classificação por: hlf_chk_airport Aeroportos hlf_chk_anleger Docas hlf_chk_bahnhof Estações de trem hlf_chk_bushalt Pontos de ônibus hlf_chk_frachthof Pátios de carga hlf_chk_keine_verb não conectado hlf_chk_maglevstop Est. de maglev hlf_chk_monorailstop Est. de monotrilho hlf_chk_name_filter Filtro por nome: hlf_chk_narrowgaugestop Est. bitola estreita hlf_chk_overflow Lotadas hlf_chk_spezial_filter Filtro especial: hlf_chk_tramstop Paradas de bonde hlf_chk_type_filter Filtro por tipo: hlf_chk_waren_abgabe Enviam: hlf_chk_waren_annahme Recebem: hlf_title Filtro da lista de paradas Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Não foi encontrado nenhum depósito na rede!\n\nVerifique se existem vias até ele, ou envie o veículo manualmente. Homeless Sem-teto hydrogene Hidrogênio Idle: Livre: ignore climates Ignorar climas In the industry legend show only currently existing factories Na legenda de indústria, só mostre fábricas existentes agora no mapa. In Transit Em trânsito Increase Industry density Aumentar densidade das indústrias increase underground view level Elevar nível de visão subterrânea industrial building Edifício industrial Init map ... Iniciando mapa... Input Entrada\n Ins Stop Inserir Insert stop before the current stop Insere paradas antes da parada selecionada Intercity road len: Extensão vias interurbanas Intro. date: Início produção: invalid inválido. Invalid coordinate Coordenada inválida isometric map Mapa isométrico January Janeiro join game Jogar online July Julho Jump to Ir para June Junho Kann Spielstand\nnicht laden.\n Impossível ler/abrir\no arquivo salvo!\n Kann Spielstand\nnicht speichern.\n Impossível abrir\no arquivo para\nsalvar!\n Kein Besitzer\n Disponível para compra\n keine nenhum(a) Keine Einzelfahrzeuge im Depot Armazenados: 0 Keyboard_Help\n Ajuda do teclado koord Coordenadas Kreuzung Cruzamento labellist_title Lista de marcadores Lade Relief Carregar terreno Laden Carregar Land attraction Atrações rurais Land industries Indústrias rurais LANG_CHOOSE\n Por Favor,\nescolha um idioma: LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Último mês: Last Year Último ano: Leaving depot! Partindo do depósito leer vazio Legend Legenda Leistung Potência Leistung: %d kW Potência: %d kW Leitung Linha de transmissão letzen Monat: diesen Monat: último mês: este mês: Line Linha Line Management Gerenciador de linhas Lineless convoys serving this stop Comboios sem linha servindo esta parada: Lines serving this stop Linhas que servem esta parada: LKW_tab Caminhões Load game Carregar jogo load height data from file Carrega relevo a partir de um arquivo Load scenario Carregar cenário loaded carregado loaded passenger/freight Passageiros/carga carregada: Loading (%i->%i%%)! Carregando (%i->%i%%) Loading addon paks ... Carregando add-ons... Loading map ... Carregando mapa... Loading paks ... Carregando pakset... Loading skins ... Carregando temas... Lock game Proibir mudança de jogador (Impossível desfazer) Lokomotive_tab Locomotivas m3 m³ maglev vehicle Veículo Maglev maglev_track Trilho de Maglev Maglevdepot Depósito de Maglev Mail Demand %d\n Demada por correio %d\n Mailbox Mensagens Mailbox Options Opções das mensagens Maintenance Manutenção make stop public (or join with public stop next) costs %i per tile and level Converter parada ao Poder público, %i$ por quadro e nível Manual (Human) Humano Manufactured: Comprado: Map roughness Aspereza map zoom Zoom March Março Margin (%%) Margem de lucro Marker Marcador max máx. Max Boost (%%) Reforço máx.(%%) Max income: Faturamento máximo: Max. speed: Velocidade máx.: Maximum 254 stops\nin a schedule!\n Máximo de 254\nparadas em uma\nprogramação de linha!\n maximum length of rivers Compr. máx. dos rios Maximum tile height difference reached. Não se pode ter mais do que 2 níveis de altura entre dois quadros adjacentes. Maxspeed vel. máxima May Maio Median Citizen per town Média moradores por cidade Meldung Mensagem Menge Quantidade MessageOptionsText \nAno novo\n\nConcorrência\n\nNotícias cidades\n\nSem rota\n\nNovas rotas\n\nChat\n\nNotícias veículos\n\nEstação lotada\n\nProblemas\n\nCongestionamento\n\nCenário min mín. minimum length of rivers Compr. mín. dos rios Missing pakfiles Faltam objetos! Modify the selected line Abre opções para modificar a linha selecionada Monate alt meses de idade Monorail Monotrilhos monorail vehicle Veículo para monotrilho monorail_track Trilho de monotrilho Monorailboden Monotrilho Monoraildepot Depósito de monotrilho month wait time Espera máx. (mês) Months Meses Monument Monumentos Monuments Monumentos Mountain height Desnível do relevo Movingobj Objeto móvel Music playing disabled/not available Sem música para tocar Music volume: Volume da música mute sound Mudo Name Nome Narrowgauge Bitola estreita Narrowgauge are not available yet! Bitola estreita não está disponível ainda! narrowgauge vehicle Veículo de bilota estreita narrowgauge_track trilho de bitola estreita Narrowgaugedepot Depósito de trem de bitola estreita Net ID: %p Rede n.o: %p\n Net Wealth Ativos Net wealth near zero Ativos próximo de zero Neue Karte Novo jogo Neue Welt Criar novo jogo new convoi Novo veículo New Line Criar linha New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Criada uma nova linha!\nVocê pode associar essa linha\nselecionando-a\nno seletor de linhas acima. New Vehicles Compra de veículos Nickname: Seu nome: no buildings hidden Nenhum edifício oculto no convois Sem veículos No goods are loaded onto this convoi. O veículo não será mais carregado e sua carga atual ainda será descarregada nas paradas corretas no goods waiting Sem cargas esperando no load Não carregar No Route Sem rota No stop here! Esta ferramenta deve ser usada em quadros de uma parada. No suitable ground! Não há local adequado! No terminal station here! Não é possível colocar\num terminal neste local! no timeline Sem linha do tempo no tree Mapa sem árvores No. of Factories Fábricas e comércios Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Programe o veículo antes de mandá-lo partir! none nenhum nord Norte nordost Nordeste nordwest Noroeste Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! A programação não pode ser modificada agora.\n\nTente mais tarde ou verifique se ela já não está sendo modificada! Not enough fields would remain. Um número insuficiente de\nquadros continuarão em volta da fazenda. November Novembro Now active as %s.\n Jogando como %s. Number of rivers Número de rios Object Objeto Odometer: %s km Odômetro: %s km Oktober Outubro On loan since %i month(s) Em débito há %i mês(es) On this map, you are not\nallowed to change player!\n Neste jogo não é permitido mudar de jogador! Only city chains Somente comércios/serviços Only first %d differing paks reported. There are probably more. Apenas os %d primeiros arquivos foram reportados. Outros podem existir. Only land chains Somente usinas elétricas Only one transformer per factory! Cada fábrica pode ter só um transformador! Only show goods which are currently handled by factories Só mostre cargas que estão sendo processadas pelas indústrias open Aberta Operation Operação Ops Profit Lucro operacional Optionen Opções Or enter a server manually: Ou digite o endereço de um servidor: Origin Origem ost Leste Output Saída Ownership Propriedade Pak which may cause severe errors: Os seguintes objetos (paks) estão faltando, isso pode causar falhas na rede de transportes: Pak which may cause visual errors: Os seguintes objetos (paks) foram substituídos por objetos similares: Pak(s) different: Arquivo(s) com diferenças: Pak(s) missing on client: Arquivo(s) faltando em seu pakset: Pak(s) not on server: Arquivo(s) faltando no servidor: Pakset differences Diferenças no pakset paletten caixas Pas_tab Trens de passageiros Passagiere Passageiros Passagierrate Índice viagens Passagierziele Destino dos passageiros/correio Passenger AI IA Passageiros Passenger Demand %d\n Demanda por passageiros %d\n Passengers %d %c, %d %c, %d no route Passageiros %d %c, %d %c, %d sem caminho Passengers %d %s, %d %s, %d no route Passageiros %d %s, %d %s, %d sem caminho Password Senha: Pause Pausar Pax <%i> Mail <%i> Passageiro <%i> Correio <%i> PaxDest Destinos Percent Electricity Percentual de usinas Planes are not available yet! Aviões ainda não estão\ndisponíveis!\n Plant tree Plantar árvore aleatória player Jogador player -1 Jogador humano player 0 Poder público player 1 Napik 128 SA player 10 Jogador 10 player 11 Jogador 11 player 12 Jogador 12 player 13 Jogador 13 player 2 Trikky Transport SA player 3 Cia. Transp. Meyer player 4 Expedição VM player 5 H-Trans Ltda player 6 PSK & Co S.A. player 7 Jogador 7 player 8 Jogador 8 player 9 Jogador 9 Please choose vehicles first\n Por favor, escolha os veículos\nantes de programar. Post Correios Postrate Índice correios Power Potência Power (MW) Potência (MW) Power: Potência: Power: %4d kW\n Potência: %4d kW\n Powerlines Linha elétrica Problems_msg Problemas Produced Produzido Production of %s has been stopped:\n%s\n A produção do %s %s foi encerrada. Production/Boost Produção/Reforço Produktion Produção Profit Lucro promote to line Criar linha q1 Primavera q2 Verão q3 Outono q4 Inverno Query server Examinar rail car veículo ferroviário random Aleat. Random age Época aleatória Random map Mapa aleatório Rathaus Prefeitura Rating Taxa ratio_pax Taxa de passageiros (%%) Relevant Relevante Reliefkarte Mapa Remove Remover remove airstrips Remover trecho de pistas remove channels Remover trecho de canais remove interm. signals Remover sinais intermediários remove maglev tracks Remover trecho de trilhos de Maglevs remove monorails Remover trecho de monotrilho remove narrowgauge tracks Remover trecho de trilhos de bitola estreita remove powerlines Remover linhas de transmissão remove roads Remover trecho de estrada remove tracks Remover trecho de trilhos Remove wayobj %s Remover objeto de via %s replace other signals Substituir outros sinais replace stop Transferir paradas request closing a se fechar. residential house Edifício residencial Restore natural slope Remover muro de arrimo Restwert: Valor de venda: Retire. date: Fim da produção: return ticket Espelhar linha Revenue Faturamento Revision: Revisão: road estrada road vehicle veículo rodoviário Roadsign Sinal Rotate map Girar mapa Rotation Rotação Routing Rotas sack sacos sail Ventos Saving map ... Salvando mapa... Scenario complete: %i%% Cenário completo: %i%% Scenario Debug Depurar Scenario Error Log Erros de script Scenario Goal Metas Scenario Info Informação Scenario information Informação Scenario Result Resultado Scenario Rules Regras Schedule changing! Alterando Programação Schienentunnel Túnel ferroviário Schiff_tab Cargueiros Schiffdepot Estaleiro Schleppkahn_tab Barcas Screenshot Capturar imagem da tela Seasons Estações do ano Sehenswuerdigkeit Atração turística Select a server to join: Selecione um servidor para entrar: Select a theme for display Tema para interface Sell the selected vehicle(s) Vende o veículo selecionado sended Enviados SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September Setembro Server did not respond! O servidor não respondeu! Serves Line: Serve linha: Service Serviço set signal spacing Espaçamento entre sinais Setting Configuração Ship Navios shops and stores Edifício comercial Show all Mostrar todos show all building Mostrar todos os edifícios Show also vehicles no longer in production. Mostra veículos que não são mais produzidos Show also vehicles that do not match for current action. Mostrar também os veículos inaptos para essa ação Show even servers with wrong version or pakset Mostra inclusive servidores com paksets e versões incompatíveis show grid Mostrar grade no terreno Show industry Indústrias Show legend Legenda Show map scale Escala Show mismatched Mostrar incompatíveis Show obsolete Mostrar obsoletos Show offline Mostrar desligados Show only used Só fábricas existentes Show schedules Mostrar programação Show servers that are offline Mostrar servidores que estão desligados Show servers where game version or pakset does not match your client Mostrar servidores cuja versão do jogo e pakset são incompatíveis show station coverage Área de captura das paradas show station names Mostrar nomes das paradas show waiting bars Mostrar barras de espera show/hide block reservations Mostrar/ocultar reservação de via Show/hide estimated arrival times Exibir os tempos de chegada e partida show/hide object owner Mostrar/ocultar objetos do jogador Show/hide statistics Mostra gráficos estatísticos Shows buttons on special topics. Mostra botões dos temas da legenda do mapa. Shows consumer/suppliers for factories Mostra as ligações dos fornecedores aos consumidores Shows the color code for several selections. Mostra a escala de cores para o tema ativo da legenda. Shows the currently selected schedule Mostra a programação de veículo ou linha agora selecionada Shrink city Diminuir habitantes da cidade shuffle midis Ordem aleatória Signal Sinal signal spacing Espaçamento dos sinais Sim: Simloops: Similar view as the main window Vista semelhante à da janela do jogo Size (%d MB): Tamanho (%d MB) sliced underground mode Visão sub. por altura slot empty --------------- Smart hide objects Auto-ocultar sob cursor Sort by Organizar por Sort waiting list by Ordenar lista por Sound Som Sound settings Opções de som Sound volume: Volume dos efeitos special freight carga especial Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Bônus a partir de: Variar limiar em:\nRodovia: %i km/h, Ferrovia: %i km/h\nHidrovia: %i km/h, Tr. Aéreo: %i km/h\n Speedlimit Vel. máxima Speichern Salvar Spieler Jogador Spieler(mz) Jogadores Spielerliste Lista de jogadores Spielstand wurde\ngeladen!\n \nJogo carregado!\n Spielstand wurde\ngespeichert!\n \nJogo salvo!\n Sprache Idioma Sprachen Idioma Stadtinformation Estatísticas da cidade Start Partir Start the selected vehicle(s) Manda o veículo selecionado começar a servir sua programação Starte Spiel Criar jogo Station tiles: Tamanho da estação: Station_msg Estações Status Status paradas steam Carvão Step timeline one year Avançar tempo em um ano Stops Paradas Storage Armazenado Storage capacity Capacidade Strassendepot Garagem Strassentunnel Túnel rodoviário street car bonde/eléctrico sued Sul suedost Sudeste suedwest Sudoeste Summer snowline Alt. neve no verão Supplied: %.0f %% Fornecido: %.0f %% Suppliers Fornecedores Tage alt dia(s) Theme selector Seleção de Tema There are still vehicles\nstored in this depot!\n Você não pode destruir!\n\nVenda ou mova os veículos armazenados neste depósito para poder destruir. This Month Este mês: This Year Este ano: Tile not empty. O local não está vazio.\nPor favor remova o\nque o ocupa antes de\nmodificar o relevo\ncom muros de arrimo.\n timeline Com linha do tempo tl_title Lista de cidades To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Para atrair mais turistas,\n%s construiu\num %s\ncom a ajuda de\n%i contribuintes. To heavy traffic\nresults in traffic jam.\n Tráfego muito intenso resulta em congestionamento!\n Toggle day/night view Alternar visão diurna/noturna Toggle vehicle tooltips Ativa/desativa dicas de veículos tonnen t Total inhabitants: Total de Habitantes: Tourist attractions Atrações turísticas Tourists Turistas Town_msg Cidades Town: %s\n Cidade de %s\n Towns Cidades track trilho Tracks Trilhos Traffic Tráfego Train Trens Trains are not available yet! Trens ainda não estão disponíveis!\n Tram Bondes tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. Bonde: %i km/h, Monotrilho: %i km/h\nMaglev: %i km/h, Bitola estreita: %i km/h. tram_track Trilho de bonde Tramdepot Depósito de bondes Trams are not available yet! Bondes ainda não\nestão disponíveis!\n Transferring game ... Transferindo jogo... Transformer only next to factory! Não pode haver transformadore\ndescolados de uma fábrica! Translation Tradução transparent station coverage Área de captura transparente Transported Transportado TrolleyBus_tab Trleibus Truck Veículos rodoviários tt_Other Outros Tunnel muss an\neinfachem\nHang beginnen!\n Um túnel deve começar no final de uma via que esteja sobre um terreno elevado e inclinado! Tunnel must start on single way! Um túnel deve começar onde termina uma via e\nter sua saída livre! Tunnelboden Túnel underground mode Visão subterrânea UNDO failed! Não é mais possível desfazer\na via. Isto só é possível se\nnada foi construído sobre a\nvia. Undo last ways construction Desfaz a última construção de via Unemployed Desempregados Unhappy Descontentes units/day /dia Update Line Modificar upgrade HQ Ampliar empresa Usage: %.0f %% Uso: %.0f %% Usage/Output Usado/Saída Use beginner mode Usar modo iniciante Use timeline start year Usar linha do tempo Vehicle %s can't find a route! O veículo %s não consegue encontrar sua rota programada! Vehicle %s is stucked! O veículo %s está parado/preso em um congestionamento. Vehicle details Detalhes do veículo Verbrauch Consumo Vergroessere die Karte\n Expandindo mapa...\n\nPor favor, aguarde enquanto o mapa é expandido...\n\nIsso pode levar alguns minutos e fazer o programa\nnão responder. Verkauf Remover agora! verkaufen Vender Verkehrsteilnehmer Veíc. urbanos Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Você tem uma dívida!\n\nFaltam %d meses\npara pagá-la!\n via Via (detalhe) via %s\n (via %s)\n via Menge Via (quant.) voranstellen À frente Waggon_tab Vagões waiting esperando Waiting for clearance! Aguardando liberação Walked Caminhado walking Andar a pé Warnings_msg Avisos Wasser Água Water água Water level Nível d'água water vehicle veículo aquático way %s cannot longer used:\n Via " %s " não pode ser utilizada:\n way %s cannot longer used:\n%s\n Via " %s " não pode ser utilizada:\n%s\n way %s now available:\n A via " %s " agora está disponível:\n Way toll Pedágio Ways not connected Vias não conectadas Wegpunkt Ponto de passagem Weight: Peso: Wert Valor west Oeste Winter snowline Alt. neve no inverno withdraw Encerrar Withdraw All Encerrar todos WRONGSAVE Versão salva\nincompatível. Impossível ler\no arquivo.\n Year %i has started. Feliz Ano Novo!\n\nEstá começando o ano de %i. Years Anos Your primary color: Sua cor primária: Your secondary color: Sua cor secundária: Zielort Destino zooming in Aumentar zoom zooming out Diminuir zoom Zu nah am Kartenrand Você não pode construir tão próximo da borda do mapa. #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Novo recorde mundial para maglevs: %.1f km/h por %s. New world record for monorails: %.1f km/h by %s. Novo recorde mundial para monotrilhos:\n %.1f km/h por %s. New world record for motorcars: %.1f km/h by %s. Novo recorde mundial para automóveis:\n %.1f km/h por %s. New world record for narrowgauges: %.1f km/h by %s. Novo recorde mundial para trens de bitola estreita: %.1f km/h por %s. New world record for planes: %.1f km/h by %s. Novo recorde mundial para aviões:\n %.1f km/h por %s. New world record for railways: %.1f km/h by %s. Novo recorde mundial para trens:\n %.1f km/h por %s. New world record for ship: %.1f km/h by %s. Novo recorde mundial para navios:\n %.1f km/h por %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL do Leste &1_CITY_SYLL do Sul &2_CITY_SYLL do Norte &3_CITY_SYLL do Oeste &4_CITY_SYLL da Barra &5_CITY_SYLL da Serra &6_CITY_SYLL d'Oeste &7_CITY_SYLL da Imperatriz &8_CITY_SYLL da Luz &9_CITY_SYLL do Alto &A_CITY_SYLL dos Campos &B_CITY_SYLL do Vale &C_CITY_SYLL da Mata &D_CITY_SYLL das Missões &E_CITY_SYLL do Planalto %0_CITY_SYLL Rancho %1_CITY_SYLL São Pedro %2_CITY_SYLL Riacho %3_CITY_SYLL São José %4_CITY_SYLL Jacaraguá %5_CITY_SYLL Rio %6_CITY_SYLL Estrada %7_CITY_SYLL Vale %8_CITY_SYLL Salto %9_CITY_SYLL Santa Laura %A_CITY_SYLL São Jorge %B_CITY_SYLL Santa Rita %C_CITY_SYLL Macaré %D_CITY_SYLL São Pedro %E_CITY_SYLL Cruzeiro %F_CITY_SYLL Morro 0center %s %s Centro Velho 0extern %s %s rural 0suburb %s %s suburbana 1center %s %s Centro Novo 1extern %s %s rural da Fazendinha 1suburb %s %s do %s 2center %s %s Centro Novo 2 2extern %s %s rural da Fazendinha 2 2suburb %s %s suburbana do %s 3center %s %s principal 3extern %s %s Descampado 3suburb %s %s suburbana de %s 4center %s %s do Centro Expandido 4extern %s %s rural de Retiro 4suburb %s %s suburbana de Vila Nova 5center %s %s central 5extern %s %s rural de baldeação 5suburb %s %s suburbana de Vila Nova 6center %s %s central de transferência 6extern %s %s rural de transferência 6suburb %s %s Jardins 7center %s %s central D. Pedro I 7extern %s %s rural de Descampado 7suburb %s %s Parque das Nações 8center %s %s central do Comércio 8extern %s %s rural %s do Bairro Bela Vista 8suburb %s %s Bairro Recanto 9center %s %s central do Eixo Urbano 9extern %s %s rural de passagem 9suburb %s %s de interligação Acenter %s %s central República Aextern %s %s rural do Bairro Bela Vista Asuburb %s %s Vila das Flores Bcenter %s %s central Liberdade Bextern %s %s rural Bairro Bem-te-vi Bsuburb %s %s Vila do Solário Ccenter Não! simutrans-124.3/simutrans/text/pt/000077500000000000000000000000001474050137200172075ustar00rootroot00000000000000simutrans-124.3/simutrans/text/pt/airtools.txt000066400000000000000000000134571474050137200216160ustar00rootroot00000000000000 Ajuda - Aeroportos

Aeroportos

A Barra Aeroportos contém ferramentas para construir uma rede de transportes aéreos. As ferramentas podem construir: pista de taxiamento e pistas de pouso para aeronaves (ou removê-las), hangares (usados para compra e manutenção dos veículos), Paradas de Aeronaves (usados para carga e descarga de bens e passageiros) e vários edifícios aeroportuários. Se jogar com a Linha do Tempo ativa, com o passar do tempo no jogo, outras opções de ferramentas poderão aparecer.

Clique no ícone do avião ao topo da tela do jogo para abrir a barra de ferramentas.
Passe o cursor do mouse por cima dos botões para poder ver o nome e, onde for o caso, o custo de construção, custo de manutenção (dentro dos parênteses) e limite de velocidade máxima.

As ferramentas podem incluir, da esquerda para direita:

Pista de taxiamento: A ferramenta constrói pistas de taxiamento (áreas de tráfego terrestre para as aeronaves irem das Paradas de Aeronaves para uma pista de decolagem). As pista de taxiamento são construídas sobre o solo na tela do jogo.
IMPORTANTE: NÃO conecte as pistas de taxiamento às extremidades de uma pista de decolagem (cabeceiras), senão as aeronaves não poderão decolar e pousar.

Para construir uma pista de taxiamento: clique sobre a ferramenta para selecioná-la (o cursor torna-se uma pista de taxiamento), então clique sobre o terreno para o ponto inicial (uma escavadora aparece sobre o cursor na tela do jogo e as coordenadas do mapa no canto inferior esquerdo da tela), e clique sobre o terreno ou sobre uma pista de decolagem para ponto final.

Pista de Pouso e Decolagem: A ferramenta constrói uma pista usada pelas aeronaves para decolar e pousar. As pistas são construídas sobre o nível do solo na tela do jogo e podem cruzar entre si.

Para construir uma pista de pouso e decolagem: clique sobre a ferramenta para selecioná-la (o cursor torna-se uma pista), então clique sobre o terreno para fixar o ponto inicial da pista de pouso e decolagem (uma escavadora aparece sobre o cursor na tela do jogo), e finalmente clique sobre o terreno para fixar o ponto final da pista.

Remover Pistas de Pouso e Decolagem: a ferramenta que remove um segmento de uma pista de taxiamento ou pista de pouso e decolagem, quando nenhuma aeronave está presente, entre dois pontos na tela do jogo. O custo do uso desta ferramenta é igual ao custo de construção.

Para remover pistas de pouso e decolagem: clique sobre o botão Remover Pistas (o cursor torna-se um X vermelho); então clique sobre o ponto inicial do segmento da pista a ser removida (um X vermelho é fixado neste ponto na tela do jogo) e finalmente clique no ponto final do segmento da pista. Todo o segmento entre os pontos marcados será removido.

Depósito de aeronaves ou hangar: A ferramenta constrói hangares para compra e gerenciamento das aeronaves. Os hangares têm um custo de manutenção e são construídos sobre o fim de uma pista de taxiamento.

Para construir hangares: clique no botão (o cursor torna-se um depósito de aeronaves), então clique sobre o fim de uma pista de taxiamento.

Paradas de Aeronaves e Ponte de Embarque: A ferramenta constrói Paradas de Aeronaves para carga e descarga de bens e passageiros na tela de jogo.
Uma Parada de Aeronaves, quando não for construída adjacentemente a uma já existente, fará com que seja criada uma nova Parada independente.
As Paradas de Aeronaves são construídas sobre o final de um trecho de uma pista de taxiamento e tem uma área de captura para bens, passageiros e correio. Uma aeronave somente irá pousar em um aeroporto se houver uma Parada de Aeronaves vazia disponível.

Para construir uma Parada de aeronaves: Clique sobre o botão para selecionar a ferramenta Parada de Aeronaves e então sobre clique sobre a extremidade de uma pista de taxiamento.

{Dica: Pressione [v] para exibir ou ocultar área de captura para bens e passageiros na tela do jogo.}

Edifícios Aeroportuários: A ferramenta constrói extensões e edifícios para Paradas de Aeronaves os quais podem incrementar a capacidade e a área de captura para bens e passageiros, assim como custo de manutenção. No canto superior esquerdo de alguns dos botões existe um pequeno ícone (usado também em Lista de Paradas e Informações da Parada) que indica quais os itens (bens, passageiros ou correio) a extensão habilita a Parada de Aeronaves a manipular.

Para construir uma extensão: Clique sobre o botão para selecionar uma extensão (o cursor torna-se a extensão selecionada), então clique na posição requerida, próxima a uma Parada de Aeronaves existente na tela do jogo. A nova extensão agora passa a ser parte da Parada de Aeronaves existente.

{Dica: Um modo de construir um aeroporto simples é:
i) construa uma pista de pouso e conecte a ela uma pista de taxiamento;
ii) coloque uma parada de aeronaves no fim da pista de taxiamento;
iii) adicione mais edifícios aeroportuários se desejar.}
{Dica: Use o botão Remover [r] para remover partes individuais das pistas de taxiamento, pouso, remover hangares e demais edifícios. O Desfazer [z] não reembolsa os custos das construções.
Pressione [v] para exibir ou ocultar área de captura para bens e passageiros na tela do jogo.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/baum_build.txt000066400000000000000000000022151474050137200220530ustar00rootroot00000000000000Ajuda - Plantação de árvores

Plantação de árvores

A caixa de diálogo é dividida em quatro seções:
· superior-esquerda, uma lista de seleção de tipos de árvore disponíveis
· inferior-esquerda, é mostrada uma figura da árvore escolhida
· superior-direto, estão algumas opções podem ser definidas
· inferior-direito, estão informações sobre a árvore escolhida

Lista de seleção

Na lista de seleção estão dados todos os tipos de árvores que estão disponíveis com as opções especificadas no canto superior-direito. Há duas abas que lhe permitirão mudar como os tipos de árvore são identificados.
· Tradução: Mostra o nome da árvore em determinado idioma. Se não houver nenhuma tradução disponível para o determinado idioma, o nome do objeto será usado.
· Objeto: Mostra o nome de objeto interno do Simutrans para o tipo de árvore.

Opções

· Ignorar climas: Esta opção desativa as restrições de clima associadas a vários tipos de árvore.
· Época aleatória: A idade da árvore a ser plantada será aleatória.

simutrans-124.3/simutrans/text/pt/citybuilding_build.txt000066400000000000000000000043601474050137200236200ustar00rootroot00000000000000Ajuda - Construção de edifícios urbanos

Construção de edifícios urbanos

A caixa de diálogo é dividida em quatro seções:
· superior-esquerda, uma lista de seleção de edifícios urbanos disponíveis
· inferior-esquerda, é mostrado uma figura do edifício urbano escolhido
· superior-direto, estão algumas opções podem ser definidas
· inferior-direito, estão informações sobre o edifício urbano escolhido

Lista de seleção

Na lista de seleção estão dados todos os edifícios urbanos que estão disponíveos com as opções especificadas no canto superior-direito. (Residêcia, Comércio, Edifício industrial). Há duas abas que lhe permitirão mudar como os edifícios urbanos são identificados.
· Tradução: Mostra o nome do edifício urbano em determinado idioma. Se não houver nenhuma tradução disponível para o determinado idioma, o nome do objeto será usado.
· Objeto: Mostra o nome de objeto interno do Simutrans para o tipo de edifício urbano.

As cores de texto têm os respectivos significados:
· azul indica que é uma residência.
· verde indica que é um comércio ou um edifício de escritórios.
· preto indica que é um edifício industrial.

Opções

· Ignorar climas: Esta opção desativa as restrições de clima associadas à varios tipos de edifícios.
· Linha do tempo a partir de: A lista de seleção listará só edifícios que estão disponíveis para o ano corrente do Simutrans.
· Mostrar obsoletos: Expande a lista de seleção para concluir também edifícios que estão obsoletos para o ano do Simutrans corrente.
· Residêcia: Haverá residências na lista de seleção.
· Comércio Haverá comércios e edifícios de escritórios na lista de seleção.
· Edifício industrial: Haverá edifícios industriais na lista de seleção.
· Rotação: Se o edifício escolhido pode ser mostrado de ângulos diferentes, então é possível escolher uma vista específica dele aqui. A parte inferior-esquerda da imagem mudará para indicar isto. Se esta opção está defina em aleatória, uma vista aleatória do edifício será usada.

simutrans-124.3/simutrans/text/pt/citylist_filter.txt000066400000000000000000000040321474050137200231600ustar00rootroot00000000000000Lista das Cidades

Lista das Cidades

Lista das Cidades apresenta detalhes sobre as áreas urbanas (cidades) e suas populações.

Para abrir: clique sobre o botão de Lista das Cidades em Listas ou tecle [T].
Lista das Cidades tem dois botões de opções que determinam a ordem em que as áreas urbanas (e suas populações) serão exibidas.
{Dica: Se os itens na lista estão parcialmente visíveis, então redimensione a Lista das Cidades ou desloque a lista usando a barra de rolagem.}

Habitantes: é o número total de habitantes do jogo (de todas as cidades). O mais recente acréscimo da população é mostrado entre parênteses.

Classificadas por: tem opções para determinar a ordem de como as cidades são apresentadas na lista.
Clique sobre os botões de opções para alternar as opções (o que faz mudar o nome do botão):

- Nome lista ordenada alfanumericamente de acordo com a ordem do código ASCII (letras maiúsculas antes das minúsculas) dos nomes atribuídos.
- Moradores ordena pelo número de habitantes.
- Crescimento ordena por de taxa de crescimento (que é dependente do tamanho da cidade e do número de passageiros transportados).

- Crescente / Decrescente inverte a ordem da lista.

Clique sobre um item listado na Lista das Cidades para ver mais informações sobre aquela cidade.
Itens listados para cada cidade incluem:

Nome atribuído à cidade (que pode ser alterado em Estatísticas da Cidade).

População da área urbana, e entre parênteses está o recente acréscimo na população.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/citywindow.txt000066400000000000000000000104551474050137200221550ustar00rootroot00000000000000 Ajuda - Estatísticas da Cidade

Estatísticas da Cidade

Estatísticas da Cidade mostra estatísticas sobre a área urbana (cidade) selecionada e pode ser usada para alterar o seu nome.

Cada cidade tem sua própria Prefeitura, ao redor da qual ela se desenvolve. O transporte de passageiros e de correio ajuda o seu crescimento, de forma que novas estradas são construídas e administradas pelo Jogador Poder Público, novos prédios aparecem na cidade, indústrias são criadas e os limites da cidade se expandem.

Clique em uma Prefeitura na tela do jogo com a Ferramenta Consultar ou em uma cidade listada em Lista das Cidades para abrir Informações das Cidades, a qual contém: um campo para o nome, estatísticas, dois mini-mapas e um gráfico informativo da área urbana.

Nome: o nome atribuído à cidade aparece num campo de nome no topo das Estatísticas da Cidade. Este nome é usado nos nomes dados às Paradas criadas.
Para alterar o nome: clique no campo do nome e digite o novo nome.
{Dica: Use [!] para alternar a visualização do nome da área urbana sobre a Prefeitura e os marcadores das diversas paradas criadas, na tela do jogo. Veja readme_citylist.txt (em ...simutrans/text/) para maior ajuda na criação de nomes para as cidades}.

Algumas estatísticas da área urbana selecionada são mostradas logo abaixo do campo do nome:
População: é o número de habitantes. O mais recente aumento da população é mostrado entre parênteses.
Edifícios: é o número de edifícios da cidade.
Coordenadas no mapa: indica os limites da cidade (são alterados conforme a cidade cresce).

As seguintes informações aumentam com o crescimento da cidade e diminuem com a construção de novos prédios:
Desempregados: o seu valor determina qual o tipo de construção (comercial/industrial) pode ser construída.
Sem-teto: a sua existência determina que residências podem ser construídas.

Mini-mapas abrangendo toda a área de jogo em Estatísticas da Cidade mostram o destino de passageiros e do correio.
Os destinos são mostrados por pontos coloridos referentes ao corrente mês do jogo (mini-mapa da direita) e ao mês anterior (mini-mapa da esquerda). A cor dos pontos indicam os seguintes detalhes sobre passageiros e correio:
- amarelo: foi encontrada uma rota e uma Parada descongestionada para início do deslocamento (rosto feliz mostrado nas Informações da Parada).
- laranja: não foi encontrada nenhuma rota para seu destino desejado.
- vermelho: foi encontrada uma rota porém a Parada estava super-congestionada (rosto zangado mostrado nas Informações da Parada).

Gráfico mostra estatísticas da cidade.
O eixo Y (vertical) indica a quantidade, o eixo X (horizontal) indica o tempo.
Clique nas abas superiores do gráfico para alterar a escala do eixo X:
Anos: mostra os valores anuais para os últimos 12 anos de jogo.
Meses: mostra os valores para os últimos 12 meses de jogo.

Clique nos botões de opções abaixo do gráfico para ver mais informações (o botão fica pressionado quando selecionado).
A cores das linhas no gráfico correspondem às cores dos botões de opções:
População: número de habitantes da cidade.
Crescimento: variação da população (depende do tamanho da cidade e do serviço de transporte de passageiros e correio providenciado).
Vol. Transportado: passageiros e correio que entraram no sistema de transporte (indicado como o rosto feliz na Informação das Paradas)
Passageiros: Número total de passageiros e correio gerados na cidade.

{Dicas: Configurações relacioandas às cidades podem ser alteradas no arquivo simuconf.tab e cityrules.tab}.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/climates.txt000066400000000000000000000033441474050137200215550ustar00rootroot00000000000000Ajuda - Controle do Clima

Controle do Clima

Controle do Clima ajusta diversas opções de aspectos topográficos e meteorológicos do jogo.

Controle do Clima abre com Criando um Novo Mundo.

Os botões de setas ajustam os parâmetros:

Opções:

Nível d'água: ajusta qual a profundidade que se encontra a água no mapa.

Desnível: ajusta a altura máxima atingida no terreno.

Aspereza: ajusta as ondulações do terreno; quanto maior o número, mais irregular será o terreno.

Opções da linha de neve:

Linha de neve no verão: ajusta a altitude que começa a aparecer a neve permanente no verão.

Linha de neve no inverno: ajusta a altitude que começa a aparecer a neve permanente no inverno.

Opções de clima:

Clima desértico: ajusta a que altitude acima do nível do mar o clima desértico começa a aparecer.

Clima tropical: ajusta a que altitude acima do nível do mar o clima tropical começa a aparecer.

Clima mediterrâneo: ajusta a que altitude acima do nível do mar o clima mediterâneo começa a aparecer.

Clima temperado: ajusta a que altitude acima do nível do mar o clima temperado começa a aparecer.

Tundra: ajusta a que altitude acima do nível do mar a tundra começa a aparecer.

Clima alpino: ajusta a que altitude acima do nível do mar o clima alpino começa a aparecer.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/color.txt000066400000000000000000000016421474050137200210710ustar00rootroot00000000000000Ajuda - Cor

Cor

Neste menu você pode alterar a cor de sua companhia de transporte.
Veículos, prédios e outros itens mostram a cor da sua companhia.

A janela Cor é aberta através das Preferências.

Clique nas cores mostradas para mudar a cor da companhia.
A barra de título da janela Cor muda para indicar que a nova cor está selecionada.

A cor-padrão do jogador humano é o azul claro.
Alguns itens não estão programados para mudar de cor e portanto permanecerão inalterados.

{Dica: para mudar a cor dos outros jogadores use a Lista de jogadores ou Mudar Jogador (P+) para selecioná-lo}.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/convoi.txt000066400000000000000000000071571474050137200212570ustar00rootroot00000000000000Lista de Veículos

Lista de Veículos

A Lista de Veículos mostra informações e tem controles para filtrar e listar diferentes Comboios (um Comboio é formado por um veículo operacional ou uma combinação de veículos).

Para abrir: clique na ferramenta de Lista de Veículos em Listas ou aperte a tecla [V]. A Lista de Veículos tem quatro botões de opções, dois são utilizados para ordenar itens em uma lista e dois são usados para aplicar as opções para selecionar os itens a serem mostrados na lista.
Abaixo dos botões existe uma lista de Comboios que se ajustam aos critérios de opções de filtros.
{Dica: Se nenhum Comboio está listado altere as opções de Filtro. Se os itens na lista estão apenas parcialmente visíveis, então reajuste a Lista de Veículos ou desça a lista usando a barra lateral.}

Clique nos botões de opções para mudá-los de acordo com as opções (o nome do botão de opções muda) ou abra os controles de Configuração de Filtros :

Classificado por: Dois botões de opções determinam a ordem dos Comboios mostrados na lista. O primeiro botão altera a ordem da lista em:

- Tipo organiza por tipo de veículo (na ordem crescente de veículo rodoviário, veículo ferroviário, navio e avião)
- Nome organiza por nome designado, alfanumericamente de acordo com a ordem do código ASCII: letras maiúsculas antes das letras minúsculas (por padrão isso é feito no primeiro veículo comprado ou montado ao Comboio).
- Lucro organiza por lucro (renda gerada menos os custos operacionais).
- ID Interno organiza pelo código de identificação único (ID) do comboio (designado por padrão quando o Comboio é comprado ou construído pela primeira vez em um Depósito e mostrado na barra de título da Informação do Comboio).

E o segundo botão, altera a ordem da lista em:
- crescente / decrescente inverte a ordem da lista.

Filtro: Dois botões de opções, ligam/desligam os critérios de seleção da lista e acessa os controles para alterar os critérios.

- Ligado / Desligado clique para alterar os critérios para os Comboios na lista.

- Parâmetros abre os controles para alterar os critérios de filtragem.

Clique no item listado para ver mais informações sobre o Comboio.

Itens listados para cada Comboio incluem:

ID Interno: um número de identificação único (designado por padrão quando um Comboio é comprado ou montado pela primeira vez em um depósito e mostrado na barra de título da Informação do Comboio).

Nome que foi designado (por padrão isso já é feito no primeiro veículo quando o Comboio é comprado ou montado).

Lucro: mostra o lucro (renda gerada menos os custos operacionais enquanto trafega).

Linha: mostra a Linha designada e indica se o Comboio está em um depósito.

Gráficos: mostra a composição e o nível atual de carregamento.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/convoi_filter.txt000066400000000000000000000045631474050137200226220ustar00rootroot00000000000000Filtro da Lista de Veículos

Filtro da Lista de Veículos

O Filtro da Lista de Veículos tem opções para determinar quais Comboios são mostrados na Lista de Veículos.

Clique em Parâmetros na Lista de Veículos para abrir o Filtro da Lista de Veículos.

Os botões de opções selecionam os Comboios a serem listados na Lista de Veículos quando a opção de filtro está ligada. Apenas os Comboios que estão dentro de todos os critérios selecionados são listados.

Clique em uma caixa de seleção para selecionar o critério para filtrar (o botão está em baixo-relevo quando selecionado):

Filtro por nome: seleciona o Comboio pelo nome. Para usar: clique no botão para selecionar, então clique na caixa de texto e digite o nome desejado exatamente (a opção diferencia letras maiúsculas de minúsculas, portanto preste muita atenção quanto a isso).

Filtro por tipo: listará os Comboios por tipo de transporte se selecionado. Para usá-lo: clique no botão para selecionar, então clique no(s) tipo(s) de transporte: Caminhões, Trens, Barcos e Aviões.

Filtro especial: seleciona os Comboios a serem listados pelos seguintes critérios (clique no botão para selecionar, então clique):
- sem rota - não pode encontrar um caminho ao próximo destino.
- sem programa - sem uma rota atribuída.
- sem renda - os veículos que não estão gerando lucros.
- em depósito - os veículos que estão em um depósito.
- sem linha - sem uma Linha atribuída.

Filtro por carga: seleciona os Comboios pela habilidade para transportar diferentes mercadorias e passageiros. Clique no botão ao lado do nome para selecionar o(s) item(ns). Use a barra lateral para ver os item(ns) na lista. As opções incluem:
- tudo seleciona todos os itens.
- nada nenhum item é selecionado.
- inv. inverte a seleção atual de itens.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/convoidetail.txt000066400000000000000000000042241474050137200224320ustar00rootroot00000000000000Ajuda - Detalhes do Comboio

Detalhes do Comboio

Os Detalhes do Comboio dão informações sobre um Comboio (um veículo operacional ou combinação de veículos) e pode ser usado para vender o Comboio imediatamente.

As informações mostradas na janela dos Detalhes do Comboio incluem:

Potência do Comboio (potência combinada de todos os veículos motorizados no Comboio).

Valor de Venda: dinheiro recebido se o Comboio for vendido (valor de compra do Comboio menos qualquer depreciação).

AVISO:

Clique no botão Vender para que o Comboio seja vendido imediatamente. Além disso, nenhuma confirmação é pedida. O Comboio é removido do jogo e o jogador recebe o valor de venda.

Detalhes do Comboio lista todos os veículos no Comboio.
As informações listadas para todos os veículos incluem:
- Ícone do veículo: uma imagem do veículo (também usado em depósitos).
- Manufaturado: mês e ano da manufatura e data de introdução do veículo se estiver jogando com a Linha do Tempo.
- Valor de venda: quantidade de dinheiro recebida se o veículo for vendido.
- Potência: potência gerada (por veículos motorizados).
- Fator de atrito atual: nível de atrito atual.
- Faturamento máximo: lucro do veículo pelo tipo de item transportado pelo Comboio.
- Itens carregados: quantidade e destino dos itens atualmente carregados pelo veículo.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/convoiinfo.txt000066400000000000000000000167341474050137200221340ustar00rootroot00000000000000Informações do Comboio

Informações do Comboio

A janela Informações do Comboio oferece informações sobre um Comboio (um veículo operacional ou uma combinação de veículos) o qual é utilizado para transportar mercadorias e passageiros.
Ela lista os itens carregados por um Comboio e também possui os controles para acessar os detalhes e vender o Comboio; seguir o Comboio na visão do jogo; e alterar o nome e a Programação de um Comboio.

Um Comboio é composto de pelo menos um veículo com força (motorizado) e qualquer tipo de reboque, como um vagão.
Exemplos de Comboios incluem: um grupo de cavalos puxando uma carruagem; ou uma locomotiva ligada a um tender e a vagões; ou um ônibus; ou uma van; ou um caminhão ligado a um reboque; ou bondes conectados entre si; ou um navio; ou um rebocador puxando uma barcaça; ou um avião.
Os Comboios são montados e comprados do depósito para o seu respectivo tipo de transporte.
{Dica: Um Comboio tem um número limite máximo de veículos em sua composição: trens, 24; veículos rodoviários, 4 .}

Clique em um Comboio enquanto estiver na visão do jogo com a ferramenta Consultar ou clique no Comboio listado na Lista de Veículos ou no Gerenciador de Linhas para abrir a janela Informações do Comboio
A barra de título da janela Informações do Comboio mostra um número de identificação único e o nome do Comboio (por padrão isso é feito quando o primeiro veículo é comprado ou montado em um depósito).
A janela Informações do Comboio contém uma caixa do nome; uma mini-visão e a informação sobre o Comboio; botões de opções; e uma lista de todos os itens atualmente sendo carregados (se todos os itens não estão visíveis reajuste a janela de Informações do Comboio ou use as barras laterais para ver os outros itens).

A informação mostrada na janela de Informações do Comboio inclui:

ID Interno: um número único de identificação para o Comboio (designado por padrão quando o Comboio é comprado ou montado pela primeira vez em um depósito).

- Nome: mostra o nome designado do Comboio (por padrão isso já é feito ao primeiro veículo comprado ou montado no Comboio em um depósito).
Clique na caixa de texto e digite um novo para alterar o nome do Comboio.

- Velocidade: velocidade atual mostrada em km/h.
Entre parênteses está localizada a velocidade máxima que pode ser atingida pelo Comboio (determinada pelo veículo mais lento no Comboio).
Uma barra de progresso verde indica a velocidade atual relativa ao limite de velocidade máxima.

- Renda: lucro gerado por veículo (renda gerada menos os custos operacionais) de acordo com o ano atual do calendário do jogo.
Entre parênteses está o custo operacional do Comboio em Créditos Hajo.

- Peso: peso combinado atual do Comboio e itens carregados em toneladas.
Entre parênteses está o peso atual dos veículos carregados.
Uma barra de progresso verde indica a capacidade usada, para carregar mercadorias e passageiros.
Uma barra amarela indica o nível de Espera (quantidade mínima de mercadorias e passageiros necessários para o Comboio prosseguir) ajustado nas opções da Linha.
{Dica: Para ajustar os níveis de Espera para todos os Comboios de uma Linha, use o botão Atualizar em Gerenciador de Linhas ou em Controles do Depósito. Para ajustar o nível de Espera para apenas um Comboio e mais nenhum outro em uma Linha atribuída, use o botão Programar na janela Informações do Comboio ou Controles do Depósito.}

- Destino: A próxima Parada ou ponto de passagem na Programação do Comboio.
Uma barra de progresso verde indica o progresso do Comboio até o próximo Destino.

- Serve a linha: indica qualquer Linha atribuída ao Comboio.

- Mini-vista mostra o Comboio.
Clique na mini-vista para centralizar a visão do jogo no Comboio.

Clique nos botões da janela Informações do Comboio para abrir os controles ou selecionar as opções:

Programar: abre os controles para modificar a rota e a quantidade mínima de mercadorias e passageiros necessários para o Comboio prosseguir.

Recolher: manda o Comboio ao depósito apropriado mais próximo. Quaisquer itens carregados serão perdidos, apesar de que o faturamento é recebido pelo transporte ao depósito.
No depósto, o Comboio mantém sua Programação e sua Linha atribuída.

Siga-me: botão que quando ativado move a visão do jogo junto com o Comboio.
Para desativar esta opção, clique no botão novamente ou clique com o botão direito no Mapa.

Gráfico: clique nesse botão para ativar/desativar o gráfico (o botão fica pressionado quando o gráfico está visível) em Informações do Comboio.
O gráfico mostra as estatísticas para os últimos 12 meses (eixo horizontal) quando uma opção do gráfico está selecionada.
Clique no botão de opção de gráfico para ver a informação no gráfico (o botão fica em baixo-relevo quando a opção está selecionada).
As cores das linhas no gráfico correspondem às cores dos botões de opção do gráfico:
- Capacidade indica o espaço sem uso no Comboio.
- Vol. Transportado indica o número de mercadorias, passageiros e correio transportados.
- Faturamento indica o lucro gerado pelo transporte.
- Operação indica os custos do Comboio enquanto está trafegando.
- Lucro indica o lucro recebido pelo transporte (Lucro Bruto menos os custos operacionais).

Detalhes abre os Detalhes do Comboio que contêm mais informações e a opção para vender o Comboio.

Passageiros/carga carregada: lista os itens carregados atualmente pelo Comboio.
A informação mostrada inclui a quantidade carregada e a capacidade do Comboio, o tipo do item, o destino final e a primeira Parada.
O botão de opção (o nome varia de acordo com a seleção) organiza os itens carregados em grupos de passageiros, correio e mercadorias por:
- Destino: organiza os itens carregados alfanumericamente de acordo com a ordem do código ASCII (letras maiúsculas antes das letras minúsculas), pelo nome designado da Parada final.
- Via (detalhe): organiza os itens carregados alfanumericamente de acordo com a ordem do código ASCII (letras maiúsculas antes das letras minúsculas), pelo nome designado da primeira Parada de transferência.
- Via (quant.): organiza os itens carregados pela quantidade levada à primeira Parada de transferência.
- Quantidade: organiza os itens carregados pela quantidade em ordem decrescente.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/curiosity_build.txt000066400000000000000000000043211474050137200231610ustar00rootroot00000000000000Construtora de atrações turísticas

Construtora de atrações turísticas

Esta caixa de diálogo é dividida em quatro seções:
· acima à esquerda está uma lista de seleção de edifícios disponíveis
· bottom left is shown a picture of the chosen building
· top right some options may be set
· bottom right is information about the chosen city building given

Lista de seleção

In the selection list are given all special buildings and landmarks that are available with the options specified top right (City attractions, Land attractions, Monumentos). There are two tabs that will allow you to change how the attraction buildings are identified.
· Translation: Shows the name of the building in the given language. If there is no translation available in the given language, the object name will be used.
· Object: Shows the Simutrans internal object name for the building type.

The color of the text has the following meaning:
· texto em azul a atração tem que ser construída nas cidades
· texto em verde a atração tem que ser construída nas zonas rurais
· texto em preto monumentos: podem ser construídos uma vez.

Opções

· Ignorar climas: This option deactivates the climate restrictions associated with various building types.
· Usar linha do tempo: The selection list will only contain buildings that are available the current Simutrans year.
· Show obsolete too: Expand the selection list to also contain buildings that are obsolete the current Simutrans year.
· City attraction: There will be city attractions in the selection list.
· Land attraction: There will be land attractions in the selection list.
· Monumentos: There will be monuments in the selection list.
· Rotation: If the chosen building can be shown from different angles, then it is possible to chose a specific view of it here. The image bottom left will change to reflect this. If this option is set to random a random view of the building will be used.

simutrans-124.3/simutrans/text/pt/curiositylist_filter.txt000066400000000000000000000044601474050137200242470ustar00rootroot00000000000000Lista de Atrações

Lista de Atrações

A Lista de Atrações mostra informações sobre todas as atrações turísticas que são um destino frequente de pessoas e correio.

Para abrir a Lista de Atrações: clique no botão de atrações turísticas em Listas.
{OBS: Se os itens só forem parcialmente visíveis, tente redimensionar a Lista de Atrações ou role a barra de rolagem.}

Classificadas por: têm a opção de determinar a ordem das atrações turísticas.
Clique nos botões para alternar ordem (o nome do botão muda ao clicar):

- Nome lista de atrações em ordem alfabética.
- Geração de viagens lista de atrações em ordem de popularidade ou destinos de passageiros ou correio.

- Crescente / Decrescente reverte a ordem da lista.

Clique no item listado na Lista de Atrações para abrir uma nova janela com informações sobre o local.
{OBS: clique na imagem que aparece na janela de informações da atração para ser levado automaticamente até ela.}

Os items listados para cada atração turística incluem:

Barra de status a cor indica a popularidade da atração:
- amarelo: não há paradas ou não há veículos para poder carregar passageiros ou correio.
- verde: a atração contém uma parada associada com passageiros.
- azul: a atração contém uma parada associada somente a correio.
- turquesa: a atração contém uma parada associada com passageiros e correio.
- laranja: a atração contém uma parada quase lotada.
- vermelho: todas as paradas da atração estão lotadas.

Ícone de prédio, se presente, indica que é uma atração da cidade.

Nome da atração turística.

Geração de viagens é um valor que indica a popularidade do destino para passageiros e correios.

{OBS: Para obter um melhor serviço, as atrações turísticas devem estar inteiramente dentro da área de captura de uma ou mais paradas.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/depot.txt000066400000000000000000000201221474050137200210600ustar00rootroot00000000000000Depósitos

Depósitos

Depósitos são usados para comprar e gerenciar veículos. Tipos diferentes de transporte possuem seus próprios depósitos. Somente aparecerão veículos elétricos no depósito se eles estiverem em vias eletrificadas.
Se estiver jogando com linha do tempo, então conforme o tempo passa no Simutrans mais veículos podem aparecer.

Ferramentas para a construção de depósitos estão disponíveis na barra de ferramentas de cada tipo de transporte: depósitos ferroviários; depósitos de monotrilhos; depósitos de bondes; garagens; estaleiros e hangares.

Clique em um depósito construído na área de jogo com a ferramenta Consultar para abrir a janela de controles do depósito, que fornecem informações e permitem a compra e o gerenciamento dos comboios (um veículo operacional ou a combinação de mais de uma unidade veicular).
A barra de título da janela do depósito indica para que tipo de veículo o depósito serve.

A janela do depósito pode ser redimensionada (clique na seta para baixo da barra de título para retornar ao tamanho original).
Clique nas setas para a direita/esquerda na barra de título para percorrer os depósitos do mesmo tipo de transporte (a área de jogo ficará centralizada no depósito).

No topo da janela, são mostrados o número de comboios no depósito, o nome e a linha.

Nome do comboio: clique nas setas existentes nos lados da caixa de nome do comboio para percorrer os comboios armazenados no depósito.
Para mudar o nome do comboio: clique na caixa de nome do comboio e digite o novo nome (por padrão isso é feito na primeira unidade veicular comprada ou montada para um novo comboio).

Nome da linha: clique nas setas existentes nos lados do nome da linha para selecionar as linhas daquele tipo de transporte, ou clique na caixa de nome para abrir uma lista das linhas existentes (clique em uma delas para selecioná-la).
Para mudar o nome da linha: clique na caixa de nome da linha e digite o novo nome (por padrão quando uma nova linha é criada ela é identificada por um número).

Gráfico: abaixo das caixas de nome, é mostrado o gráfico do comboio selecionado.
Passe o cursor do mouse por cima do gráfico das unidades veiculares do comboio selecionado para ver detalhes sobre a unidade veicular (mostrados na parte inferior da janela do depósito).
Clique em uma unidade veicular para removê-la do comboio selecionado e armazená-la no depósito.

Abaixo do gráfico são mostrados o número de unidades veiculares do comboio selecionado, bem como a quantidade de quadros de estação precisos (todas as unidades veiculares devem caber em uma parada para poder recolher e entregar mercadorias e passageiros), e a linha a que serve.

Os botões de opção (logo abaixo, clique para usar) da janela do depósito incluem:

Partir: Coloca o Comboio em funcionamento se uma rota foi programada e/ou encontrada.

Programar: abre controles para mudar a rota e quantidade de itens que um comboio esperará em uma parada.

Desmontar: armazena no depósito a(s) unidade(s) veicular(es) do comboio selecionado.

Vender: vende o comboio selecionado. O Valor de venda será creditado no balanço.

Nova linha: abre controles para definir uma programação (uma rota e quantidade mínima de itens que um comboio esperará em uma parada), que pode ser usada por múltiplos comboios.

Associar: associa a linha mostrada na caixa de nome da linha no topo da janela do depósito ao comboio selecionado.

Atualizar: abre controles para mudar a programação da linha selecionada.

Copiar comboio: compra e monta outro comboio com a mesma composição, programação e linha do comboio selecionado.

Abaixo dos botões são mostrados gráficos de todas as unidades veiculares disponíveis para compra.
Gráficos das unidades veiculares: unidades veiculares são divididas em categorias (unidades para passageiros e correio, unidades motorizadas, e aquelas que servem como reboque), que podem ser exibidas clicando nas respectivas abas.
Um número branco em cima do gráfico da unidade veicular indica a quantidade armazenada se um ou mais comboios foram desmontados. Unidades armazenadas podem ser vendidas ou usadas na montagem de um novo comboio.

Passe o cursor do mouse sobre o gráfico de uma unidade veicular para ver as seguintes informações:
Nome: e entre parênteses o tipo de energia utilizado pelas unidades motorizadas.
Preço: valor para compra e entre parênteses o custo de operação por quilômetro.
Potência: potência do motor e velocidade máxima para unidades motorizadas.
Capacidade: quantidade e nome da mercadoria suportados pela unidade veicular.
Peso: em toneladas.
Velocidade máxima: para unidades veiculares não motorizadas.
Introdução: data em que a unidade veicular se torna disponível quando se joga com linha do tempo.
Fim da produção: data em que a unidade veicular se torna obsoleta.
Construído por: pessoa que criou o veículo para o Simutrans.
Câmbio: relação de força.
Valor de venda: quantidade de dinheiro recebida se a unidade veicular anteriormente comprada for vendida.

Clique em um dos veículos abaixo das categorias para comprá-los ou vendê-los dependendo do estado do botão encontrado no canto inferior direito dos controles do depósito. O botão alterna entre as três seguintes opções:
A reboque: compra uma nova unidade veicular e a adiciona ao comboio selecionado, ou cria um novo comboio.
À frente: compra uma nova unidade veicular e a adiciona à frente do comboio selecionado, ou cria um novo comboio.
Armazenar: vende os veículos contidos no depósito.

Barras de cores abaixo dos gráficos das unidades veiculares indicam quais e em qual ordem as unidades veiculares podem ser montadas, para formar um comboio operacional (as cores podem mudar dependendo dos diferentes estados do botão do canto inferior direito e do comboio seleceionado).
Significado das cores:
- verde: a unidade veicular pode ser usada.
- vermelho: a unidade veicular não pode ser usada.
- amarelo: outra unidade veicular precisa ser conectada para montar um veículo operacional.
- azul: a unidade veicular pode ser usada, mas está obsoleta.
{Dicas: um comboio é operacional se ele mostra barras verdes em todas as unidades veiculares; se houver alguma barra amarela então é necessária outra unidade veicular.}

Mostrar obsoletos: jogando com linha do tempo, quando o botão é pressionado (clique para usar) mostra as unidade veiculares que tiveram sua produção terminada.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/display.txt000066400000000000000000000077171474050137200214310ustar00rootroot00000000000000Ajuda - Vídeo

Vídeo

A janela Ajustes de Vídeo possui controles para a aparência do jogo e fornece informações da performance do computador.

Clique no botão 'Vídeo' na janela Preferências para abrir os Ajustes de vídeo.

Clique nos botões quadrados para selecionar as opções (o botão aparece pressionado quando a opção é selecionada), ou use as setas para ajustar as configurações:

Mostrar grade: Quando ativado, mostra a terra na tela de jogo dividida em quadros para facilitar a construção. Pode ser ativada pelo atalho [#].

Vista subterrânea: Ativa a visão subterrânea, construções debaixo da terra. Pode ser ativada pelo atalho [U].

Visão subterrânea em níveis: Alterna entre os níveis de profundidade de visão subterrânea.

Alternar dia e noite: ver ciclos de dia e noite no jogo.

Luminosidade: regula o quão claro/escuro o jogo aparecerá. Valores muito distantes de zero produzem resultados estranhos; use [+] e [-] para aumentar/diminuir o valor.

Inverter deslocamento do mouse: inverte o sentido do deslocamento da tela do jogo com o mouse.

Velocidade de deslocamento: regula a velocidade do deslocamento pela tela do jogo.

Usar transparência ao ocultar: Ao ativar, quando se oculta um objeto, mostra-o transparente em vez de escondê-lo totalmente.

Ocultar árvores: Oculta as árvores da tela de jogo.

Captura transparente das paradas: Mostra uma captura transparente das paradas. Quando desativado, a captura das paradas é representada por pontos distribuídos pela tela de jogo.

Mostrar captura das paradas: Mostra/oculta a área de captura das paradas. Pode ser ativada pelo atalho [v].

Mostrar nomes das paradas: Mostra o nome das paradas. Pode ser ativado/desativado pelo atalho [!].

Mostrar barras de espera: Mostra a barra de espera das paradas. Pode ser ativado/desativado em alternância com o item anterior pelo atalho [!].

Pedestres nas cidades: permite a simulação de pedestres caminhando pelas áreas urbanas.

Ver pedestres: visualização dos pedestres que desembarcam dos veículos em paradas.

Densidade de tráfego: regula o número de carros particulares em áreas urbanas.
O número de carros novos que aparecem conforme a área urbana cresce depende do seu tamanho e da densidade de tráfego. Valores maiores que zero geram tráfego nas cidades.

{Dica: mais opções e valores padrão para quando o Simutrans inicia podem ser mudados no arquivo simuconf.tab}.


Informações de vídeo:

Abaixo dessas configurações, são mostradas informações do desempenho do computador rodando o Simutrans.
Se os números (geralmente brancos) estiverem vermelhos ou amarelos talvez você precise mudar suas configurações.
Mudanças na velocidade que o tempo passa no jogo, (usando o Avanço Rápido(>>) no topo da área de jogo, ou [,]/ [.]) podem mudar a cor do número.

Tempo por quadro: quantidade de tempo entre os quadros.

Livre: quando superior a zero, o computador tem capacidade de rodar outro software.

Q/s: taxa de quadros por segundo. Valores altos fazem os veículos parecerem se mover mais naturalmente. Se o número continuar vermelho, tente reduzir o tamanho da tela de jogo.

Simloops: se o número continuar vermelho, significa que o computador fica lento com as configurações atuais - tente um mapa menor com menos áreas urbanas.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/edittools.txt000066400000000000000000000134421474050137200217620ustar00rootroot00000000000000Ajuda - Editor de mapa

Editor de mapa

O Editor de mapa permite a personalização avançada do mundo em que se está jogando.
As ferramentas podem: aumentar/diminuir a população das cidades; construir vias urbanas, atrações, usinas de energia e indústrias; proibir a mudança de jogador e também avançar alguns anos na linha do tempo.

Esta barra de ferramentas abre quando se joga como o Poder Público, selecionado através da Lista de jogadores ou Mudar jogador (P+) nas ferramentas especiais (ou pressionando [P]). A barra irá se fechar ao mudar de jogador novamente.
Passe o cursor do mouse em cima das opções (após ter aberto ou clicado na barra de ferramentas) para ver o nome e mais informações de algumas delas.

As opções incluem, da esquerda para a direita:

Aumentar cidade: aumenta a população de uma área urbana em 100 habitantes, construindo novas estradas e prédios, se necessário.
Para aumentar a cidade: clique na ferramenta para ativá-la (o cursor mudará para uma seta vermelha apontando para cima), e clique na área urbana.

Diminuir a cidade: reduz a população de uma área urbana em 100 habitantes. Áreas urbanas somente continuarão a crescer se a quantidade de sem-tetos e desempregados aumentar.
Para diminuir a cidade: clique na ferramenta para ativá-la (o cursor mudará para uma seta vermelha apontando para baixo), e clique na área urbana.

Via urbana: constrói uma via urbana entre dois pontos, como o Poder público, que qualquer jogador pode usar. Vias urbanas podem não ser construídas em áreas ocupadas por outros prédios, e podem não encontrar um caminho através de terreno acidentado, água e obstáculos. A via urbana construída entre dois pontos pode usar estradas existentes em seu caminho.
Passe o cursor do mouse em cima das opções (após ter aberto ou clicado na barra de ferramentas) para ver o nome, custo de manutenção e construção para o Poder público e o limite máximo de velocidade. Para construir uma via urbana: clique na ferramenta para ativá-la (o cursor mudará para um trecho de via urbana), e clique na área de jogo no ponto de início da via (mostra um trator na área de jogo e as coordenadas do mapa no lado direito da barra inferior da área de jogo), e finalmente clique no local desejado para o ponto final da via.
{Dicas: tipos diferentes de estradas podem ser conectadas. Use pontes e túneis para conectar estradas através de terreno acidentado, ou para desviar de obstáculos. Use o Editor de terrenos para aplainar o relevo, possibilitando caminhos para as estradas. Use a ferramenta Remover para remover estradas e obstáculos. Use [Ctrl] ao mesmo tempo para algumas funções adicionais.}

Construir atração aleatória: constrói uma atração turística que passageiros vão querer visitar. Diferentes atrações geram quantidades diferentes de passageiros e correio. O tipo de atração construída é aleatório e somente aparece se houver espaço suficiente livre de obstáculos.
Para construir uma atração: clique na ferramenta para ativá-la (o cursor mudará para uma gota vermelha em um círculo amarelo), e clique na posição desejada na área de jogo.
{Dicas: use a ferramenta Remover jogando como Poder público para remover atrações. Use a ferramenta Remover e/ou o Editor de terrenos para criar lugares propícios para receber atrações.}

Construir usina de energia: constrói uma usina de energia elétrica (e possíveis fornecedores). O tipo de usina de energia construído é aleatório e somente aparece se houver espaço suficiente livre de obstáculos.
Para construir uma usina: clique na ferramenta ou pressione [I] para ativá-la (o cursor mudará para uma gota vermelha em um círculo amarelo), e clique na posição desejada na área de jogo.
{Dicas: use a ferramenta Remover jogando como Poder público para remover as usinas de energia. Use a ferramenta Remover e/ou o Editor de terrenos para criar lugares propícios para receber usinas.}

Construir mercado: constrói um consumidor-final de mercadorias em uma área urbana (e possíveis fornecedores, não necessariamente na área urbana). O tipo de indústria construída é aleatório e somente aparece se houver espaço suficiente livre de obstáculos.
Para construir um mercado: clique na ferramenta para ativá-la (o cursor mudará para uma gota vermelha em um círculo amarelo), e clique na área de jogo para construir um mercado na área urbana mais próxima.
{Dicas: use a ferramenta Remover jogando como Poder público para remover os mercados. Use a ferramenta Remover e/ou o Editor de terrenos para criar lugares propícios para receber mercados.}

Proibir mudança de jogador: remove a opção de atuar como outro jogador e abrir as ferramentas de Editor de mapa.
Para usá-la: clique na ferramenta para ativá-la (o cursor mudará para um cadeado), e clique em qualquer lugar na área de jogo, não é pedida confirmação ao jogador.

Pular linha do tempo em um ano: avança a data no jogo em um ano. Se estiver jogando com linha do tempo, conforme o tempo passa mais opções de transporte e construção aparecem e veículos lentos deixam de ser tão lucrativos (a receita é calculada pela velocidade média do transporte disponível).
Para avançar no tempo: clique na ferramenta, não é pedida confirmação ao jogador (a data muda no lado direito da barra inferior da tela do jogo).

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/enlarge_map.txt000066400000000000000000000005541474050137200222260ustar00rootroot00000000000000Expandir mapa

Expandir mapa

Aqui, o jogador pode expandir o mapa à direita e para baixo. Se o jogador quiser estender à esquerda e para cima, é necessário girar o mapa antes, então expande-se o mapa, e gira-se de volta.
Uma pré-visualização do mapa expandido é mostrada acima à direita da janela de diálogo.

simutrans-124.3/simutrans/text/pt/factorylist_filter.txt000066400000000000000000000051131474050137200236600ustar00rootroot00000000000000Lista das fábridas

Lista das fábricas

Lista das fábricas tem informações sobre todas as indústrias (fornecedoras e consumidoras) durante o curso do jogo.

Para abrir a Lista das fábricas: clique no botão da lista de fábricas em Listas.
{OBS: Se os itens só forem parcialmente visíveis, tente redimensionar a Listas de fábricas ou role a barra de barra de rolagem.}

Classificadas por: têm a opção de determinar a ordem das indústrias.
Clique nos botões para alternar ordem (o nome do botão muda ao clicar):

- Nome da fábrica lista de indústrias em ordem alfabética.
- Entrada ordenar por entrada de matéria-prima.
- Saída ordenar por saída de suplimentos.
- Produção ordenar por capacidade de produção.
- Taxa ordenar por barra de status (ver abaixo).
- Potência ordenar por suprimento de energia.

- Crescente / Decrescente reverte a ordem da lista.

Clique em um dos itens listados na Lista das fábricas para maiores informações da indústria.
Os itens listados sobre a indústria incluem:

Barra de status a cor indica a operação da indústria (também é usada na Informações das indústrias):
- branco: não requer matéria-prima.
- amarelo: a indústria está conectada à rede de transporte, mas com fornecimento precário.
- verde: indústria em ótimo estado.
- laranja: operacional, mas pode ser melhorado.
- vermelho: operacional, mas parte da cadeia industrial tem suprimentos em excesso.

Ícone de relâmpago vermelho, se presente, mostra que a indústria contém um suprimento de energia nos seus transformadores.

Nome da indústria: mostra o nome da indústria.

Entre parênteses, existem 3 valores que representam informações de entrada e saída:
produtos entrando: quantidade de matérias em estoque prontas a ser processadas.
produtos saindo: quantidade de produtos que já foram produzidos aguardando transporte.
produção total: mostra o quanto a indústria consegue produzir por dia.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/finances.txt000066400000000000000000000073321474050137200215430ustar00rootroot00000000000000Ajuda - Finanças

Finanças

A janela de Finanças mostra como está o fluxo de caixa de sua empresa, mostra o quanto você gastou com veiculos, tranpostes e etc.

Clique no ícone de dinheiro na parte superior de seu monitor, ou tecle [f], ou clique no nome de um Jogador, para abrir Finaças.

Os valores estão em Hajo Credits, nessa janela você pode ver seu fluxo deste ano e do ano anterior.
Este Ano: ano atual do calendário do jogo (o ano é mostrado na parte inferior a esquerda do seu monitor).
Ano passado: ano anterior do calendário do jogo.

Os valores anuais podem também ser vistos em um gráfico para os últimos doze anos, ou valores mensais para o ano passado.
Clique sobre o valor ou no botão de nome para mostrar o valor: O eixo vertical é a quantidade, o eixo horizontal é o tempo.
Clique nas abas para alterar os valores do gráfico
Últimos 12 Anos: mostra os valores anuais dos últimos doze anos do jogo.
Últimos 12 Meses: mostra os valores mensais dos últimos doze meses do jogo.

Para ver os detalhes dos valores, clique nos botões dos valores para ver os detalhes no gráfico. Os valores incluem:

Faturamento e L. Elétricas - renda total do transporte de passageiros, bens, correio e de transmissão de energia.

Operação - custo total de todas as operações dos Comboios quando em trânsito.
{OBS: A operação de quanto o comboio gastou por quilômetro pode se vista em depósitos ou em Informações de Comboios.}

Manutenção - custo total para manter a rede de transporte.
{OBS: O custo por o mês para manter a rede (Manutenção (mês) é mostrado na direita de Finanças) é deduzido no fim do mês de calendário do jogo.}

Lucro Operacional - lucro com o transporte dos bens, passageiros o correio e a transmissão de energia (lucros menos custos de manutenção e operação).

Veículos Novos - despesa e renda recebida da compra e da venda dos veículos.

Construção - custo total gasto com construção de linhas da transmissão, redes do transporte, reflorestação, alta-voltagem, e de usar a ferramenta Destruir/Remover e outras ferramentas para remoção própria (canais, estradas, aeroporto, monotrilhos).

Fluxo de Caixa - renda total menos despesa total (custos).

Vol. Transportado - é o número total dos bens, dos passageiros e de correio transportados.

Balanço - é o dinheiro atual disponível para a construção ou compra de veículos novos (mostrada também no centro da barra na parte inferior do monitor).
{OBS: Se o jogador humano está no vermelho (balanço negativo) por três meses seguidos, o jogado irá à falência e o jogo acaba}.

Valor dos Veículos - é o valor de todos os veículos da companhia no fim do último mês do calendário.
{OBS: a cada mês, os valores dos veiculos caem ligeiramente, o valor de venda atual para os veículos pode ser visto dentro de Detalhes do Comboio ou quando o veiculo está no depósito.}

Margem (%) - é a relação do lucro operacional aos rendimentos.

Ativos - é a soma entre Balanço e Valor dos Veículos.

{OBS: Alguns custos, valor inicial do balanço e as finanças no jogo podem ser mudados dentro do simuconf.tab}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/general.txt000066400000000000000000000066751474050137200214030ustar00rootroot00000000000000Ajuda do Simutrans

Ajuda geral

- Bem-vindo
- Interface/janela do jogo
- Mouse/Rato
- Configuração do teclado

Preferências
- Idioma
- Cor do jogador
- Vídeo
- Ajustes de som
- Jogadores
- Carregar jogo
- Salvar jogo
- Novo jogo
- - Carregar mapa

Menu principal
- Preferências
- Mapa
- Ferramenta de consulta
- Editor de terrenos
- Ferrovias
- Monotrilhos e Maglevs
- Bondes
- Estradas
- Navegação
- Aeroportos
- Ferramentas especiais
- - Editor de mapa
- Ferramenta Remover

Opções de Gerenciamento
- Gerenciador de linhas
- Listas
- - Lista de paradas
- - - Filtro da lista de paradas
- - Lista de veículos
- - - Filtro da lista de veículos
- - Lista das cidades
- - Lista das cargas
- - Lista das fábricas
- - Lista das atrações
- Mensagens
- Finanças

Outras opções
- Salvar imagem da tela
- Pausa
- Avanço rápido
- Ajuda

Outros diálogos
-Depósitos
-Programação de veículos
- Informações das estações
- - Detalhes da parada
- Informações do comboio
- - Detalhes de comboio/veículo
- Estatísticas da cidade
- Informações das indústrias

Se você não encontrou aqui a ajuda que procura, então tente:
http://guide.simutrans.com, or
http://wiki.simutrans.com, or
http://simutrans-tips.com, or
http://forum.simutrans.com.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008, atualizado em 07/02/2008.

Equipe de tradução do Simutrans PT-SubFórum

Quaquer problema, dúvida ou sugestão em nossas traduções, contacte-nos pelo http://pt.simutrans.com.

simutrans-124.3/simutrans/text/pt/goods_filter.txt000066400000000000000000000073421474050137200224360ustar00rootroot00000000000000Lista das cargas

Lista das cargas

A lista de Lista das cargas contém informações sobre itens variados que podem ser transportados no jogo e tem controles para mudar o lucro recebido do transporte das cargas.

Para abrir: clique no botão das Lista das cargas nas Listas ou aperte a tecla [G].

Uma lista de itens disponíveis para transporte no jogo indica: renda recebida, bônus de velocidade (medido em %), categoria das cargas e peso.
{Dica: Se os itens na lista são apenas parcialmente visíveis, então reajuste o tamanho da janela Lista das cargas ou desça a lista usando a barra de rolagem.}

Bônus a partir de: mostra a velocidade necessária para os diferentes tipos de transportes, os quais um Comboio precisa ser capaz de alcançar para receber renda extra pelo transporte rápido de mercadorias e passageiros (ou em alguns casos uma penalidade em dinheiro, se for muito devagar).
Se estiver jogando com a linha do tempo ativada, com o passar do tempo no Simutrans essas velocidades necessárias mudam com a introdução de novos veículos.
Os botões-setas ajustam o lucro recebido e a velocidade que o Comboio precisa alcançar para receber o bônus (ou receber uma penalidade caso o Comboio seja muito lento).

Classificadas por: oferece opções para determinar a ordem dos itens mostrados na lista.
Clique nos botões abaixo para escolher uma das opções (a opção ativada no momento tem o seu nome mostrado no botão):

- Sem ordem classifica em uma ordem aleatória.
- Nome classifica em ordem alfabética.
- Valor classifica pelo lucro recebido pelo transporte de uma unidade das cargas por um quadrado do jogo.
- Bônus classifica pela porcentagem de bônus de velocidade (a porcentagem de lucro extra recebida se o Comboio é capaz de alcançar a velocidade necessária para ter direito a essa porcentagem).

- Crescente / Decrescente inverte a ordem na lista.

Os detalhes listados para cada item incluem:

A cor do quadrado é a mesma cor mostrada nas barras coloridas das cargas na visão do jogo sobre uma Parada para indicar a quantidade de itens que aguardam pelo transporte.
{Dica: Pressione [!] para ativar ou desativar as barras coloridas das cargas sobre uma Parada na visão do jogo.}

O valor é a renda recebida pelo transporte de uma unidade daquela carga por um quadrado do jogo.
{Dica: Use o modo iniciante para aumentar os lucros em 150% (pode ser alterado no simuconf.tab)}

A porcentagem é a porcentagem de lucro extra recebido caso o Comboio utilizado seja capaz de transportar a carga na velocidade necessária para ganhar o bônus (ou em alguns casos em penalidade, caso o Comboio seja muito lento).
A fórmula usada para calcular o lucro é muito complexa e considera a velocidade máxima de um Comboio com a média da velocidade máxima dos outros veículos (e não apenas do veículo visto no jogo).

A categoria da carga indica o tipo de veículo necessário para o transporte daquela carga. Cargas especiais precisam de veículos específicos.
{Dica: A capacidade dos veículos mostra quais itens um veículo pode transportar}.

O peso mostrado é de uma unidade da carga em quilogramas.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 07/02/2008.

simutrans-124.3/simutrans/text/pt/haltlist.txt000066400000000000000000000074251474050137200216040ustar00rootroot00000000000000Lista de paradas

Lista de paradas

A Lista de paradas mostra todas as estações, pontos de ônibus e terminais de carga do jogo, além de ter controles para filtrar essas paradas. NOTA: as paradas que são somente aquáticas, como as plataformas de petróleo, não são listadas aqui!

Para abrir: clique no botão "Listas", e na barra que se abrir, no botão "Lista de Paradas". A Lista de paradas tem quatro botões: dois são utilizados para ordenar os itens e dois são utilizados na filtragem deles. Abaixo desses botões, vem a lista de paradas propriamente dita, com os itens que obedeçam aos critérios de filtragem já estabelecidos. (Dicas: Se nenhuma parada estiver listada, modifique as opções de filtragem.. Caso os itens apareçam parcialmente, então use o mouse/rato para redimensionar a Lista de Paradas ou para deslocar a lista com a barra de rolagem.)

Ao clicar nos botões, vão-se modificando as opções que eles contêm:

O botão mais à esquerda diz o critério de ordenamento da lista:
- Nome: ordena segundo o código ASCII: primeiro todas as letras maiúsculas, depois todas as minúsculas, em seguida as acentuadas.
- Espera: Ordena pela quantidade de passageiros ou mercadorias aguardando ser transportada
- Tipo: Ordena pelo tipo de veículo que é aceito pela parada
- Sem ordem:Ordena aleatoriamente.

O segundo botão define se a classificação é crescente ou decrescente.
O terceiro botão define se o filtro está ligado ou desligado.
O quarto abre a janela do Filtro da Lista de Paradas.

Clicando em um item na Lista de paradas, obtêm-se maiores informações sobre aquela parada.
Os dados listados por parada são:

Estado: Barra colorida onde cada cor indica o estado da parada, com relação à lotação. A mesma cor é exibida nas Informações da Parada, no Gerenciador de Linhas e na barra acima do nome da parada que se vê no jogo:
- amarelo: parada sem atendimento; nenhum veículo a utiliza.
- verde: não é necessário melhorar o atendimento; a parada não lota.
- laranja: alguma melhoria é necessária.
- vermelho: é necessário melhorar o atendimento urgentemente.
(Dica: para ver as cores do estado do serviço no jogo, clique em (!) até que apareça.)

Nome da parada. (Dica: é possível auto-numerar as paradas utilizando uma opção no arquivo simuconf.tab)

Ícones de veículos que indicam quais são os veículos aceitos na parada: ônibus/autocarro, caminhão/camião, trem/comboio, barco/navio e avião. Bondes/eléctricos são ora representados pelo símbolo de ônibus/autocarro, ora pelo de trem/comboio, conforme o tipo original da parada.

Ícones de carga que indicam o tipo de carga que a parada aceita. Podem ser passageiros, carga propriamente dita e correio. (Dica: há alguns tipos de plataforma que não aceitam nenhum tipo de carga por si sós, sendo necessário acoplar ou um quadro de um tipo de plataforma que aceite a carga desejada, ou uma extensão que aceite a carga. Para adicionar um novo tipo de carga à parada, é necessário acoplar um quadro de plataforma ou de extensão que aceite a caraga desejada. Para transportar correio, acople uma Agência Postal.)

Na segunda linha vêm os detalhes das diversas cargas esperando na parada.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/haltlist_filter.txt000066400000000000000000000051071474050137200231440ustar00rootroot00000000000000Filtro da Lista de Paradas

Filtro da Lista de Paradas

O Filtro da Lista de Paradas tem as opções para determinar quais paradas, onde os veículos acolhem e deixam passageiros e mercadorias, são mostradas na Lista de Paradas. (Isso só vale para paradas que não sejam exclusivas de veículos de transporte na água).

Para acessar o filtro, clique sobre o botão Parâmetros na Lista de Paradas para abrir o Filtro da Lista de Paradas.

Os botões de opção limitam as paradas que serão listadas na Lista de Paradas conforme o filtro desejado. Somente serão listadas as paradas que caibam em todos os critérios selecionados.

Clique sobre um botão para selecionar critérios para a filtragem (o botão fica afundado quando selecionado):

Filtro por nome: seleciona paradas pelo nome. Para usá-lo, clique sobre o botão para ativar o filtro, e clique então sobre a caixa de nome e digite o nome da parada exatamente. (a opção é sensível a maiúsculas e minúsculas (ou caixa alta e baixa) ).

Filtro por tipo: listará as paradas que atendem a pelo menos um dos tipos de veículos selecionados. Para usá-lo, clicar sobre os botões com os nomes do tipos de veículo. (Apenas as paradas exclusivas para veículos de transporte na água não são listados na lista da paradas)

Filtro especial:
- lotadas: não está funcionando.
- não conectadas seleciona paradas com nenhum serviço de transporte.

Necessidade: Seleciona as paradas de acordo com as necessidades das indústrias próximas. Use a barra de rolagem para rolar pela lista dos artigos. As opções incluem:
- tudo seleciona todos os artigos.
- nada desfaz todas as seleções.
- inv. inverte a seleção atual.

Produção: Seleciona as paradas de acordo com os produtos das indútrias próximas. Use a barra de rolagem para rolar pela lista dos artigos. As opções incluem:
- tudo seleciona todos os artigos.
- nada desfaz todas as seleções.
- inv. inverte a seleção atual.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/industry_info.txt000066400000000000000000000121311474050137200226420ustar00rootroot00000000000000Informações das indústrias

Informações das indústrias

A janela de Informações das indústrias mostra detalhes sobre uma indústria selecionada (fornecedora ou consumidora de mercadorias) e permite se deslocar na área de jogo até o local onde ela se encontra.

Fornecedoras e consumidoras de mercadorias são interdependentes, criando uma cadeia produtiva que termina em um consumidor-final. Algumas indústrias são ao mesmo tempo consumidoras e fornecedoras e se encontram no meio da cadeia produtiva. Se não se estiver jogando no modo iniciante, a indústria interromperá o fornecimento enquanto sua consumidora estiver com excesso de mercadorias.
Indústrias também podem ser um destino ou origem de passageiros e correio. Veículos recolhem e entregam mercadorias e passageiros nas indústrias através de paradas se a área de captura da parada abranger qualquer parte do prédio da indústria e se a parada for capaz de receber o item. {Dica: a área de captura das paradas em alto-mar/plataformas de petróleo/fazendas marinhas não aparecem na lista de paradas}

O número inicial de cadeias produtivas pode ser alterado quando se cria um novo mundo. Conforme as áreas urbanas crescem, mais indústrias podem aparecer. Novas indústrias aparecem toda vez que a população da área urbana dobra acima de 2000 habitantes.
{Dicas: adicione indústrias a uma área urbana usando a ferramenta Construir mercado nas ferramentas de edição do mapa. Mude quando novas indústrias são geradas no arquivo cityrules.tab (industry_increase_every = 0) o valor zero não gera nenhuma indústria nova}.

Clique em uma indústria na área de jogo com a ferramenta Consultar ou em uma indústria listada na lista das fábricas para abrir as informações das indústrias.
Use a barra de rolagem para percorrer os itens que não estiverem visíveis.

O nome da indústria selecionada é mostrado na barra de título das informações das indústrias.
Outras informações e opções sobre a indústria selecionada incluem:

Produção: quantidade máxima de mercadorias que a indústria fornece (se for uma fornecedora) ou consome (se for um consumidor-final) em unidades.
{Dica: colocando transformadores e suprindo a indústria com eletricidade faz aumentar a quantidade máxima de mercadorias consumidas/produzidas}.

Imagem da indústria: mostra uma imagem da indústria. Clique na imagem para ir até a indústria.

As cores da barra de status abaixo da imagem indicam a operação da indústria (também usada no Filtro da lista de indústrias):
- branco: a indústria não necessita de mercadorias.
- amarelo: a indústria está conectada à rede de transporte, mas com fornecimento precário.
- verde: indústria em ótimo estado.
- laranja: operacional, mas pode ser melhorado.
- vermelho: operacional, mas parte da cadeia industrial tem suprimentos em excesso.

Consumidor: mostra os destinos na cadeia produtiva para os bens produzidos na indústria selecionada.
Indústrias consumidoras e suas coordenadas no mapa são listadas ao lado de um botão em forma de seta. Clique nele para ir até a indústria.

Fornecedores: mostra a origem dos bens que devem ser fornecidos à indústria selecionada.
Indústrias fornecedoras e suas coordenadas no mapa são listadas ao lado de um botão em forma de seta. Clique nele para ir até a indústria.

Trabalhadores de: mostra em quais áreas urbanas próximas os empregados moram. Passageiros e correio dessas áreas urbanas precisarão se deslocar até a indústria.
Áreas Urbanas e suas coordenadas no mapa são listadas ao lado de um botão em forma de seta. Clique nele para ir até a cidade.

Geração de viagens: é a popularidade relativa como destino para passageiros.
Geração de correios: é a popularidade relativa como destino para correio.
{Dica: somente uma parte da indústria precisa estar na área de captura da estação/parada para ser destino de passageiros ou correio}.

Produção: dá detalhes sobre a produção da indústria.
A informação mostrada inclui: nome do item; quantidade atualmente armazenada e quantidade máxima armazenável do item; categoria; e porcentagem da saída comparada com a entrada.

Consumo: dá detalhes sobre os bens fornecidos à indústria.
A informação mostrada inclui: nome do item; quantidade atualmente armazenada e quantidade máxima armazenável do item; categoria; e porcentagem da entrada comparada com a saída.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/inspection_tool.txt000066400000000000000000000135431474050137200231660ustar00rootroot00000000000000Consultar

Consultar

A ferramenta Consultar é usada para abrir caixas de diálogo que fornecem informações ou controles para vários itens.

Clique na lupa no topo da área de jogo ou pressione [a] para abrir a ferramenta Consultar (o cursor mudará para uma lupa).

Para usar: posicione o cursor em forma de lupa no local desejado na área de jogo e clique para abrir a caixa de diálogo. Se mais de um item estiver no local desejado, outro clique abrirá uma segunda caixa de diálogo. {Dica: a opção de abrir uma ou todas as caixas de diálogo do local está disponível no arquivo simuconf.tab}

Clique nos seguintes itens na área de jogo com a ferramenta para abrir as caixas de diálogo:

Depósitos - abre controles para comprar e gerenciar veículos naquele depósito.

Paradas - abre as informações daquela parada.

Veículos - abre as informações daquele veículo.

Prefeitura - abre as informações da população daquela área urbana. {Dica: a opção para abrir a caixa de diálogo fornecendo informações sobre o prédio da prefeitura está disponível no arquivo simuconf.tab}

Indústrias - abre as informações daquela indústria.

Edifícios abrem uma caixa de diálogo que fornece informações sobre a construção (a barra de título mostra 'Edifício'). A informação contida inclui:
- Descrição: fornece informações sobre o edifício. Se não houver informação disponível então 'residência', ou 'edifício industrial', ou 'comércio e lojas' (no caso de edifícios comerciais) é mostrado.
- Cidade de: indica a qual área urbana que o edifício faz parte.
- Geração de viagens: é a popularidade relativa como destino para passageiros.
- Geração de correios: é a popularidade relativa como destino para correio.
- Construído a partir de: indica o ano que o edifício aparece quando se joga com Linha do tempo.
- Valor: indica o custo para remover o edifício com a ferramenta Remover.
- Construído por: nome da pessoa que criou o edifício para o Simutrans.

Monumentos / Atrações turísticas abrem uma caixa de diálogo que fornece informações sobre a atração (a barra de título mostra se é um monumento ou uma atração turística). A informação contida inclui:
- Propriedade pública: indica que o item não pertence a nenhuma companhia de transporte.
- Descrição: fornece informações sobre a atração.
- Geração de viagens: é a popularidade relativa como destino para passageiros.
- Geração de correios: é a popularidade relativa como destino para correio.
- Construído a partir de: indica o ano que o edifício aparece quando se joga com Linha do tempo.
- Construído por: nome da pessoa que criou a atração para o Simutrans.

Estradas e trilhos abrem uma caixa de diálogo que fornece informações sobre a estrada ou trilho (a barra de título mostra qual o tipo de via que se está usando - no caso de trilhos de bonde construídos em estradas a barra de título indica o tipo da estrada). A informação contida inclui:
- Vel. Máxima: velocidade máxima permitida na estrada ou trilho.
- Ribi (unmasked): é um contador interno que indica a direção da via.
- Ribi (masked): é um contador interno que indica a direção da via levando em conta sinais e/ou placas.
- com sinal: é mostrado se há um sinal ou placa presente.
- eletrificado / não eletrificado: indica se a via está eletrificada.
- comboios passados no último mês: indica o número de veículos que usaram a via no último mês do jogo.
- está reservado para um trem: indica qual veículo reservou o trecho de trilho para usar até ter passado.
- wayslope [aguardando definição]
- coordenadas: mostradas na barra inferior da área de jogo
Caso haja trilhos de bonde construídos em estradas as informações aparecem duas vezes, pimeiro para a estrada e depois para o trilho de bonde.

Sinais / Placas abrem uma caixa de diálogo que fornece informações sobre o sinal ou placa (a barra de título mostra se é um sinal ou uma placa). A informação contida inclui:
- direção: é um contador interno que indica a direção a que o sinal se aplica.

Linhas elétricas / Transformadores abrem uma caixa de diálogo que fornece informações sobre a distribuição de eletricidade (a barra de título nostra 'Linha de transmissão'). A informação contida inclui:
- Potência: indica a quantidade de energia fornecida.
- Disponível: o valor aparece nos transformadores das indústrias e indica a quantidade relativa de energia fornecida.
- Net: é o número de identificação da rede de distribuição. Dois pontos com o mesmo número estão conectados.

Árvores abrem uma caixa de diálogo (a barra de título mostra 'Árvore'). A informação contida inclui:
- Nome: mostra a espécie da árvore.
- Meses de idade: idade da árvore mostrada em meses.

{Dicas: opção de abrir caixas de diálogo em estradas privadas e pedestras está disponível no arquivo simuconf.tab}.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/language.txt000066400000000000000000000017301474050137200215340ustar00rootroot00000000000000Ajuda - Língua

Linguagem

Língua altera o idioma utilizado no jogo.

Língua abre a partir de Preferências ou a partir de Novo Mundo.

Para jogar com outro idioma: clique no botão ao lado do idioma desejado para selecionar este idioma; para que os lugares tenham os nomes no novo idioma, faça isso antes de começar um novo mapa.

O novo idioma pode apenas aparecer em novas ou reabertas barras de ferramentas, opções e textos no jogo.
Se uma tradução não está disponível no idioma selecionado, ele pode abrir em inglês.

Visite http://translator.simutrans.com para ajuda com traduções.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

Para ajudar na tradução do Simutrans para o seu idioma,
visite https://translator.simutrans.com

simutrans-124.3/simutrans/text/pt/linemanagement.txt000066400000000000000000000165511474050137200227440ustar00rootroot00000000000000Gerenciador de Linhas

Gerenciador de Linhas

O Gerenciador de Linhas fornece informações e ferramentas para o gerenciamento de linhas (caminhos e quantidades mínimas de carregamento requeridas por uma composição para partir) para uma composição ou mais com a mesma rota.

Linhas consistem em Paradas onde os veículos pegam e deixam mercadorias e passageiros (veículos aquáticos podem usar qualquer quadro de água na área de captura de uma doca) e pontos de passagem (usados para forçar os veículos a irem por um caminho).

Clique no ícone que (parece uma rede) na barra do alto da tela ou pressione [w] para abrir a janela do Gerenciador de Linhas, que pode ser redimensionada (clique no botão com uma seta para baixo na barra do título para retornar ao tamanho original).

O lado esquerdo do Gerenciador de Linhas lista as linhas existentes (para rolar pela lista: use a barra do lado direito da lista), que pode ser filtrado por tipo de transporte, clicando numa das abas que ficam acima da lista pra selecionar:
Todos: lista as linhas de todos os tipos de veículos.
Trem: lista as linhas para os veículos ferroviários.
Monotrilho: lista as linhas para os monotrilhos ou maglevs (trens magnéticos).
Tram: lista as linhas dos bondes/eléctricos.
Caminhões: lista as linhas para os veículos rodoviários.
Navios: lista as linhas para os veículos aquáticos.
Ar: lista as linhas para os veículos aéreos.

A cor dos nomes das linhas significam o seguinte:
branco - não há nenhum veículo associado à linha
amarelo - não operacional, ou não está dando lucro nem prejuízo
negro - linha lucrativa, com capacidade ociosa, sem necessidade de melhoria
azul - linha lucrativa, com pouca capacidade ociosa, ou com veículos obsoletos
vermelho - linha com perdas

Sob a lista das linhas existentes há alguns botões, que incluem:

Nova Linha: abre controles para definir uma Programação (caminhos e quantidades mínimas de carregamento requeridas por uma composição para partir) para uma nova linha.
Adicione tantas paradas ou pontos de passagem quanto necessários, estabeleça as quantidades de espera necessárias, e então feche a janela para criar a nova linha, clicando no botão "x" na barra de título ou com o teclado). A nova linha terá associado um número e será listada na lista do Gerenciador de Linhas.
{Dicas: Selecione o tipo de transporte nas abas antes de criar uma nova linha. Os veículos não pegam nem deixam mercadorias e passageiros nos pontos de passagem.}

Atualizar: abre os controles para modificar uma Programação existente. As mudanças afetarão todos os veículos associados à linha, assim que a janela desses controles for fechada.
Para usá-lo, é necessário selecionar uma linha na lista antes de clicar nele e editar a linha.

Apagar: apaga a linha selecionada. Para usá-lo, é necessário selecionar uma linha na lista antes de clicar nele e apagar a linha.

Quando uma linha é selecionada, ele fica destacada das outras, e as paradas que estão associadas à linha aparecem embaixo dos botões "Nova Linha", "Atualizar" e "Apagar". Clique numa parada para abrir suas informações.
Os itens listados para cada parada incluem:
barra da cor de status: as cores indicam a situação da parada com relação à sua lotação. é a mesma barra mostrada na Lista de Paradas, na janela Informações da Parada e na barra que fica acima da parada no jogo:
- amarelo: fora de serviço.
- verde: nenhuma melhoria necessária.
- laranja: melhorias possíveis.
- vermelho: melhorias necessárias.
{Dica: Use [!] para fazer aparecer a barra da cor de status acima da parada na tela do jogo.}
nome da parada.
número da parada (elas pode ser numeradas se a opção for escolhida no simuconf.tab).
ícone de veículos(s) indicam quais tipos de veículo podem usar a parada. Os ícones incluem: ônibus/autocarro (para veículos rodoviários de transporte de passageiros), cami(nh)ão (para veículos rodoviários de transporte de cargas), trem/comboio, barco e avião. Bondes/eléctricos podem ser indicados por um ônibus ou trem conforme o tipo de via da parada.
ícone de carga(s) indica com quais itens (passageiros, cargas ou correio) uma parada pode lidar (também são usados nas Informações das Paradas e na Lista de Paradas.
{Dica: adicionar extensões apropriadas pode modificar as categorias de itens que uma parada pode lidar. Agências de correio podem ser adicionadas às paradas para o transporte de correspondências}.
espera detalhes das diversas mercadorias e passageiros.

No lado direito do Gerenciador de Linhas são exibidos um gráfico com dados da linha selecionada, uma caixa de nome e uma lista das composições associadas à linha.

Clique no nome da linha pra selecioná-la. Ele ficará destacado. Clique nos botões para ver as informações sobre a linha, sendo que o eixo horizontal representa os últimos 12 meses:

- Capacidade - quantidade de mercadorias ou passageiros que puderam ser transportadas no período.

- Vol. Transportado - quantidade de mercadorias ou passageiros que realmente foram transportados.

- Faturamento - total recebido pelo transporte de mercadorias ou passageiros.

- Operação - custo da operação dos veículos, ou seja, de eles estarem rodando.

- Lucro - diferença entre o faturamento e a operação.

- Veículos - número de veículos associados à linha.

Para modificar o nome da linha: clique na caixa de nome, abaixo do gráfico, onde aparece o nome da linha, e escreva o nome desejado.

Abaixo da caixa de nomes aparece a lista dos veículos associados a ela.
No topo da lista dos veículos vem a quantidade de veículos associados a ela, a renda da linha (o lucro operacional, melhor dizendo), a capacidade e a quantidade transportada no momento, com a porcentagem da capacidade entre parênteses).
Clique num item listado para ver mais informações sobre o veículo selecionado (use a barra de rolagem para ver os outros veículos da linha).
São listados, para cada veículo:
nome nome dado do veículo, que normalmente é o do primeiro componente comprado ou montado na composição).
renda o lucro operacional do veículo: faturamento menos custo operacional.
linha: mostra o nome da linha e se o veículo está num depósito.
gráfico mostra o veículo e a capacidade utilizada do veículo no momento.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/list.txt000066400000000000000000000037771474050137200207410ustar00rootroot00000000000000Ajuda - Listas

Listas

Listas tem opções para abrir controles para informação sobre o estado atual do jogo (e também um controle para ajustar renda relativa recebida de diferentes bens, passageiros e correio).

A informação está disponível para um jogador em listas sobre: Paradas; Veículos; Áreas urbanas; rendas recebidas de diferentes bens, passageiros e correio; Fábricas; e atrações turísticas.

Clique sobre o botão Listas no topo da tela do jogo para abrir Listas.
Mova o cursor do mouse, depois de abrir ou clicar na barra de ferramentas, por cima dos botões da barra para ver o nome.

Clique sobre o botão para abrir os controles de informação, da esquerda para direita, sobre:

Lista de Paradas: Paradas, onde os veículos carregam e descarregam objetos e passageiros (paradas só marítimas não são listadas).

Lista de Veículos: veículos rodoviários e ferroviários, aeronaves e barcos.

Lista das cidades: Áreas urbanas (aldeias, vilas e cidades).

Lista das cargas: rendas, recepção de diferentes bens, passageiros e correio (está incluído um controle para ajustar renda relativa).

Lista das Fábricas: Fábricas (consumidoras e fornecedoras de bens).

Lista das atrações: atrações turísticas.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008, atualizado em 07/02/2008.

simutrans-124.3/simutrans/text/pt/load.txt000066400000000000000000000031001474050137200206610ustar00rootroot00000000000000Ajuda - Carregar jogo

Carregar jogo

A janela Carregar reabre um jogo salvo (para continuar a jogar de onde parou) e pode ser usado para apagá-los. Um jogo é reaberto por cima do mundo atual, que é perdido.

Carregar abre de Novo Mundo e Preferências ou pressionando [L], e mostra os nomes e data e hora de salvamento dos jogos disponíveis.
Se todos os jogos não estiverem visíveis: use a barra de rolagem no lado direito da lista para percorrer os nomes.

Clique em um nome da lista para reabrir o jogo, ou digite o nome na caixa de texto do topo da janela: clique na caixa, digite o nome e pressione [Enter] ou [Return] ou clique em OK.
Um nome incorreto mostra uma mensagem de erro: feche a mensagem e tente novamente.

AVISO: clique no X ao lado do nome para DELETAR o jogo imediata e permanentemente.
O nome é removido da lista e a janela se fecha. Use com cuidado.

IMPORTANTE: novas versões do Simutrans surgem regularmente e jogos de versões anteriores podem não funcionar com versões mais novas. Consulte as notas da nova versão para saber se jogos antigos são compatíveis.

Clique em Cancelar para fechar a janela Carregar, ou no X do canto superior esquerdo, ou use o teclado.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/load_relief.txt000066400000000000000000000030221474050137200222120ustar00rootroot00000000000000Ajuda - Carregar terreno

Carregar terreno

A janela Carregar terreno é usada para abrir um arquivo de mapa personalizado (para ser usado em um novo jogo) e pode ser usada para deletar esses arquivos.

Carregar terreno abre a partir da janela de Novo mundo e lista nomes, data e hora de salvamento dos mapas disponíveis.
Se todos os arquivos não estiverem visíveis: use a barra de rolagem no lado direito da lista para percorrer os nomes.

Clique em um nome da lista para usar; ou digite o nome na caixa de nome no topo da janela: clique na caixa, digite o nome e pressione [Enter] ou [Return], ou clique em OK (um nome incorreto fechará a janela, tente novamente).

AVISO: clique no X ao lado do nome para DELETAR o mapa imediata e permanentemente. O nome é removido da lista e a janela Carregar terreno se fecha. Use com cuidado.

Alguns mapas personalizados e informações de como criar um estão disponíveis na Internet em http://maps.simutrans.com.
O arquivo de mapa deverá conter a extensão .ppm e colocado no diretório (ou pasta) chamada ...simutrans/save/

Clique em Cancelar para fechar a janela Carregar terreno, ou no x do canto superior esquerdo, ou use o teclado.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/mailbox.txt000066400000000000000000000057521474050137200214140ustar00rootroot00000000000000Ajuda - Mensagens & Opç;ões das Mensagens

Mensagens

A janela Mensagens lista mensagens que o jogo lhe dá e abre controles para selecionar como são mostradas.

Para abrir a janela de mensagens, clique no ícone da caixa de correio na barra superior do jogo ou pressione [B].
Clique sobre a mensagem para abrir uma janela com a mensagem e a imagem do local dela. Clique no botão com uma flecha no canto esquerdo da mensagem para ir pro local relacionado a mensagem.

O botão Opções abre a Opções das mensagens para determinar como são exibidas as mensagens.

Opções das mensagens

A janela Opções das mensagens tem quatro colunas com botões quadrados que selecionam como são exibidas as mensagens.

Da esquerda para a direita, as colunas selecionam se as mensagens são mostradas como:
- Desativa as mensagens daquele tipo;
- Texto rolando na barra inferior do jogo;
- Janela temporária (aparece por alguns segundo); ou
- Janela permanente (fica na tela até você fechar).
{Dica: clique no X no canto superior esquedo da mensagem ou use o teclado para fechar janelas permanentes.}

Segue o tipo de mensagens exibidas por linha:

Ano novo: Mostra uma mensagem todo começo de ano avisando sobre o novo ano.

Concorrência: Mostra mensagens sobre outros jogadores.

Notícias cidades: Mostra mensagens das cidades, como construção de monumentos e novas prefeituras.

Sem rota: Mostra uma mensagem toda vez que um veiculo não pode achar uma rota para seu próximo destino (uma parada ou ponto de passagem).

Novas rotas: Toda vez que uma nova rota ficar disponível, com uma nova cadeia empresarial aparecer (um consumidor final e os fornecedores nescessários) devido ao crecimentos de uma cidade.

Chat: Mostra textos de conversas de outros usuários quando estiver jogando online.

Notícias veículos: Mostra mensagens quando um novo veículo ficar disponível, ou terminar a produção de um. (só aparecem se a opção linha do tempo estiver ligada).

Estação lotada: Se uma estação ou parada ficar cheia, aparecerá uma mensagem.

Problemas: Mensagens de quaisquer problema com sua empresa de transporte, como dívidas.

Congestionamento: Quando um veículo seu ficar parado em um congestionamento, uma mensagem vai aparecer.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 11/08/2011.
Acesse a wiki para mais informações e ajudas: http://wiki.simutrans-germany.com/

simutrans-124.3/simutrans/text/pt/map.txt000066400000000000000000000123551474050137200205330ustar00rootroot00000000000000Ajuda - Mapa

Mapa

Mapa fornece um mapa do mundo atual oferecendo informações sobre terreno, lugares importantes e redes de transporte. Ele também fornece um modo para mover a visão do jogo pelo mundo.

Clique no ícone do mapa no topo da visão do jogo ou pressione [m] para abrir o Mapa, cujo tamanho pode ser ajustado ou minimizado. Os três botões abaixo da barra de título abrem três legendas: opções do mapa(explicadas mais abaixo), escala de cor mín./máx. e a legenda das indústrias.

O mapa pode ser visto em várias tamanhos: aponte com o cursor do mouse e use o scroll, ou clique nas setas para a direita e para a esquerda na parte superior da janela para visualizar as escalas. Se a parte do mundo que deseja ver não estiver visível, mude a escala do mapa, redimensione-o, ou mova-o: enquanto clica com o botão direito do mouse no mapa, arraste-o (ou use as barras deslizantes nas laterais).

No mapa, a água é azul e as terras mais baixas são mais escuras que as terras mais altas. A parte do mundo na visão do jogo é mostrada por um quadrado com contorno amarelo no Mapa: o topo da visão do jogo corresponde ao lado superior esquerdo do retângulo amarelo (o Norte está no topo do mapa, enquanto na visão do jogo está no canto superior direito). Se o retângulo amarelo sair da área do mapa, água será vista na visão do jogo na área correspondente.

Para mover a visão do jogo por distâncias grandes no mundo, clique com o botão esquerdo no ponto desejado ou clique com o botão esquerdo do mouse e ao mesmo tempo arraste o retângulo amarelo.

Aponte o cursor do mouse em uma indústria no mapa, para ver o seu nome. Se a opção "detalhes da fábrica" estiver ativada, aparecerá uma linha branca ligando a indústria ao(s) seu(s) consumidor(es); pressionando [Shift] aparecerá uma linha vermelha ligando a indústria ao(s) seu(s) fornecedor(es).

No mapa (quando as opções não estão sendo usadas): áreas urbanas, atrações e túneis aparecem em cinza escuro; canais, azul; estradas, preto; ferrovias e trilhos de bonde, marrom escuro; pontes, cinza-claro; Paradas,vermelho; pistas de monotrilho/maglev, laranja; áreas de aeroporto, bege; e veículos, em amarelo, normalmente em movimento.

Clique nos botões de opções para mostrar/ocultar detalhes no mapa (para os botões aparecerem, clique no botão Legenda):

Cidades: nomes das áreas urbanas.

Passageiros: área de captura para passageiros por Paradas.

Correio: área de captura para correio por Paradas.

Mercadoria: nível de mercadorias e passageiros em estradas e outros tipos de vias (usa a escala de cor mín./máx.).

Qualificação: as cores indicam a operação da Parada em relação a quão lotada ela está no momento. A mesma cor é mostrada nas barras de status na Lista de Paradas e Informações das Paradas e Gerenciador de Linhas e é a mesma cor mostrada na barra de cor acima do nome de uma Parada na tela do jogo.

Serviço: nível de mercadorias e passageiros usando uma Parada (usa a escala de cor mín./máx.).

Tráfego: nível de veículos em estradas e outros tipos de vias (usa a escala de cor mín./máx.).

Origem: nível de mercadorias e passageiros que começam viagem de uma Parada (usa a escala de cor mín./máx.).

Destino: nível de mercadorias e passageiros terminando uma viagem em uma Parada (usa a escala de cor mín./máx.).

Espera: nível de mercadorias e passageiros esperando por transporte em uma Parada (usa a escala de cor mín./máx.).

Vias: ferrovias e trilhos de bonde e placas; trilhos, pontes e túneis são mostrados com a cor branca (vermelha se for eletrificado) e placas são mostradas com a cor amarela.

Vel. Máxima: estradas e pistas são mostradas pela velocidade máxima permitida (usa a escala de cor mín./máx.).

L. Elétricas: linhas elétricas (usa a escala de cor mín./máx. para visualizar o nível de abastecimento do momento em que o Mapa foi aberto).

Turistas: nível de passageiros que as atrações turísticas geram (usa a escala de cor mín./máx.); esta opção também mostra as atrações turísticas no mapa.

Fábricas: enfatiza as indústrias; destaca os consumidores e fornecedores no mapa.

Depósitos: enfatiza os depósitos. As cores indicam o tipo de transporte: navios, vermelho; estradas, amarelo; ferrovias, laranja; aviões, lilás; bondes, laranja escuro; e monotrilhos, marrom escuro.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/monorailtools.txt000066400000000000000000000203721474050137200226550ustar00rootroot00000000000000Ajuda - Monotrilhos e Maglevs

Monotrilhos e Maglevs

A Barra Monotrilhos e Maglevs mostra as ferramentas para construir uma rede de transporte de monotrilhos ou Maglevs. As ferramentas podem construir ou remover: trilhos de monotrilhos e Maglevs; pontes; túneis; sinais; depósitos; estações-plataforma e extensões. Se jogar com a Linha do Tempo ativa, com a passagem do tempo no Simutrans, novas opções podem aparecer.

Clique no ícone do monotrilho na barra de ferramentas. Mova o cursor do mouse sobre a barra de opções (após abrir ou clicar na barra de ferramentas) para ver o nome e, onde for o caso, o custo da construção, custo de manutenção (em parênteses) e limites de velocidade máxima e comprimento máximo.

A Barra Monotrilhos e Maglevs inclui, da esquerda para a direita:

Trilho de monotrilho/Maglev: ferramenta que constrói trilhos, para veículos monotrilhos e Maglevs entre dois pontos. Os trilhos só podem ser construídos em barrancos na direção dos mesmos e não podem encontrar um caminho através de terrenos acidentados, água ou obstáculos. Novos trilhos construídos entre dois pontos podem usar outros trilhos existentes em seu caminho.
Para construir trilhos: clique no botão para selecionar o trilho desejado (para monotrilho ou Maglev; então o cursor do mouse muda para o formato de um trilho), e então clicar no terreno para construir o ponto inicial para os trilhos (mostra um trator na tela do jogo e mostra as coordenadas no canto direito da barra inferior na tela) e finalmente clique em um outro ponto no terreno para construir o ponto final do trilho.
{Dica: Diferentes tipos de trilhos podem conectar (não poderão quando construídos por outras companhias). Use o Editor de terrenos para modificar o terreno, para abrir caminhos para os trilhos. Use o botão Remover para remover trilhos individuais e alguns obstáculos. Pressione [Ctrl] ao mesmo tempo para acessar funções extras. Para desfazer algo já feito aperte [z], mas isso não o reembolsará dos custos de construção.}

Remover trecho de monotrilho: essa ferramenta remove trilhos de monotrilhos e Maglevs, quando não há nenhum veículo no momento obstruíndo, entre dois pontos na tela do jogo (platformas and sinais no caminho também são removidos).
O uso dessa ferramenta implica em custos de construção.
Para remover um trilho: clique neste botão (o cursor torna-se num X vermelho); e então clique no trilho a ser destruído (nesse mesmo ponto é fixado um X vermelho); e finalmente clique em um outro ponto nos trilhos, para remover o trecho entre estes dois pontos.
{Dica: Altere o jogador para remover os trilhos de cada companhia.}

Rampas e Pontes: ferramentas que constroem pontes retas, para veículos de monotrilho/maglev passarem, entre dois treços de trilho de monotrilho/maglev na visão do jogo. As pontes têm um comprimento máximo. A ferramenta contrói pontes de uma ponta de trilho até um outro lugar adequado (outra ponta de trilho ou um barranco mais alto, dentro do limite de comprimento.
Para construir uma rampa ou ponte: clique no botão para selecioná-lo (o cursor torna-se numa ponte), e então clique no fim de um trilho (ponto inicial da ponte) para construí-la. Certas obstruções ou a falta de um local adequado para o fim da ponte evitará a construção da ponte: coloque trilhos em ambos os lados a serem conectados pela ponte, e tente novamente.
{Dica: Use o botão Remover para remover pontes (clique no fim da ponte) e alguns obstáculos à construção da ponte. Use as ferramentas para trilhos para conectar o fim das pontes aos trilhos.}

Sinais: essa ferramenta constrói sinais para monotrilhos e Maglevs num trilho na visão do jogo. Os sinais direcionam e regulam o fluxo de veículos em trilhos e pontes, cruzamentos e Paradas (onde os passageiros embarcam e desembarcam nos veículos).
Versões de sinais de mão-dupla e única podem ser construídas. Para construir um sinal de mão-dupla em um trilho: clique em um dos botões de sinais para escolher um desejado (muda-se o cursor para um sinal); e então clique no trilho. Para construir um sinal de mão-única: clique de novo no mesmo ponto, com o cursor com a forma de um sinal, para escolher entre os sinais de mão-única e dupla.
IMPORTANTE: Tome cuidado para não colocar sinais de mão-única que impeçam os veículos de chegar aos seus destinos, por padrão os veículos dirigem pela direita (isso pode ser alterado no simuconf.tab).
- Semáforo de monotrilho: os veículos prosseguem somente se o trilho à frente até o próximo semáforo ou destino na Programação (a Parada ou ponto de passagem) não estiver ocupado por um outro veículo. No modo de mão-única os veículos passam apenas em uma única direção.
- PreSignals: os veículos prosseguem se a seção do trilho à frente (ou entre três sinais consecutivos ou até o próximo destino na Programação) não estiver ocupada por um outro veículo. No modo de mão-única eles deixam os veículos passarem em apenas uma direção.
- Direcionador de monotrilho para vaga livre: direciona os veículos a uma estação vazia, em uma Parada multi-plataforma: um veículo que passa por esse sinal pode usar qualquer plataforma vazia no seu próximo destino, e não apenas aquelas que foram definidas em sua Programação. Se não for encontrada uma plataforma vazia ou um caminho vazio até o próximo destino, então os veículos aguardarão nesse sinal.
{Dica: Remova sinais com o botão Remover. Pressione [Ctrl] para colocar sinais em pontes sobre trilhos em nível inferior.}

Depósito de monotrilhos: essa ferramenta constrói um depósito para comprar e gerenciar monotrilhos e Maglevs, tanto veículos como seus vagões. Os depósitos possuem um custo de manutenção e são construídos no fim de um trilho de monotrilho/Maglev.
Para construir um depósito de monotrilhos: clique no botão (o cursor torna-se num depósito), então clique no fim de um trilho.

Estação: essa ferramenta constrói estações, utilizadas por monotrilhos e Maglevs para carregar e descarregar passageiros e correio.
Uma seção de estação quando não é construída adjacente a uma Parada já existente criará uma nova Parada.
As estações possuem um custo de manutenção e são construídos sobre trilhos (mas não em curvas e cruzamentos).
As estações possuem uma área de captura para mercadorias, passageiros e correio. Diferentes estações podem ter diferentes capacidades para mercadorias, passageiros e correio. No canto de alguns botões um ícone (utilizado em Lista de Paradas e Informações das Paradas) mostra quais itens a estação aceita.
Para construir uma estação: clique neste botão para selecionar (o cursor torna-se numa estação), e então clique em um trilho.
{Dica: Remova as estações com o botão Remover. Estender e criar estações multi-plataformas (construindo mais plataformas nos trilhos) servem para acomodar veículos mais longos e em maior número, aumentar a capacidade e área de captura. Aperte [v] para mostrar/ocultar a área de captura de mercadorias e passageiros na tela do jogo. Pressione [Ctrl] para construir em cima de pontes ou trilhos elevados sobre trilhos em nível inferior.}

Suporte para monotrilho:essa ferramenta constrói uma extensão a uma Parada e aumenta a capacidade da mesma. Fundações de monotrilhos são construídas no final de um trilho de monotrilho/Maglev e possuem um custo de manutenção.
Para construir uma fundação de monotrilho: clique neste botão para selecionar (o cursor torna-se numa fundação), então clique na posição desejada no fim de um trilho.
{Dica: Remova as fundações de monotrilho com a ferramenta Remover.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 07/02/2008.

simutrans-124.3/simutrans/text/pt/mouse.txt000066400000000000000000000025331474050137200211030ustar00rootroot00000000000000Ajuda - Mouse

Mouse

Com o mouse você pode quase comandar todo o Simutrans sem o teclado.
Com ele você pode adicionar várias ferramentas nas diversas categorias: Trilhos, Estradas, Navegação, Aviação, Transporte Terrestre, Edição do Terreno, Excluir, Mais Ajuda, Finanças, Foto, Pausa, Ferramentas Especiais, Configurações, Novo Mapa, Salvar, Carregar, Alterar Cor da Companhia, Adicionar Jogadores, Mudar Jogador, Comprar e Vender Veículos, Criar novas Linhas de Transporte, Ver Informações de Edifícios e muitas outras.

As funções dos botões:

Botão Esquerdo: aplica todas as ações ou objetos que você seleciona nos menus variados, como por exemplo criar uma rua, ver informações de um determinado edifício, modificar ruas ou até adicionar um veículo.

Botão Scroll: (em apenas alguns mouses) tem como serviço aumentar ou reduzir o zoom do jogo, girando-o para trás você reduz o zoom e girando-o para frente, você o aumenta.

Botão Direito: clicando, segurando e arrastando ao mesmo tempo, você movimenta a tela do jogo para todos os lados até local que você deseja sem precisar do teclado ou mapa.

Escrito pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 07/02/2008.

simutrans-124.3/simutrans/text/pt/new_world.txt000066400000000000000000000131031474050137200217460ustar00rootroot00000000000000Ajuda - Criar novo jogo

Começar um Novo Jogo

Criar novo jogo permite modificar as opções para um novo jogo, com um novo mapa e configurações.
As variáveis incluem: tamanho do terreno, número inicial de áreas urbanas e indústrias.
Uma prévia do terreno, com os ajustes, é mostrada.

Criar novo jogo abre com Língua e Controle do Clima quando o Simutrans é iniciado (outras opções do jogo estão desligadas) e também abre do botão Preferências (quaisquer barras de ferramentas, textos e opções no jogo atual são fechados).
Os atalhos do teclado para abrir a janela Criar novo jogo incluem apertar [Q] e [X].

Para retornar ao jogo atual, feche a janela Criar novo jogo: clicando no x no canto superior esquerdo da janela; ou você pode utilizar o teclado.

Os botões em forma de seta permitem ajustar as configurações e os botões que podem ser "apertados" (baixo/alto relevo) ligam/desligam opções ou abrem novos controles:

Número: seleciona o terreno a ser utilizado no jogo.
Clique na caixa de texto com o número e digite o número desejado ou use os botões em forma de seta para selecionar um entre vários terrenos.
A prévia mostra o terreno selecionado (a água é azul, e quanto mais baixo o nível da terra, mais escura fica a cor).

Dimensão: ajusta o tamanho do mapa (o número superior é largura, o inferior é altura).
O número em colchetes é a memória requerida pelo mapa.
IMPORTANTE: Mapas maiores precisam de mais memória e precisam de mais tempo para serem criados. O jogo e outros gráficos precisam de aproximadamente 88MB no pak64 e 144MB no pak128. Geralmente um computador com 256MB de memória consegue operar mapas com o tamanho de até 512 x 512 quadros.

Aleatório: seleciona um novo terreno com um número do mapa aleatório, mas as outras opções não são alteradas.

Carregar terreno: abre os controles para utilizar os mapas disponíveis personalizados.

Cidades: ajusta o número inicial de áreas urbanas no jogo.

Moradores por cidade: ajusta a população inicial das áreas urbanas.
Essa configuração é um valor médio, o Simutrans tentará gerar mais cidades pequenas do que cidades grandes.

Ext. vias interurbanas: ajusta a extensão inicial das estradas, entre áreas urbanas, para um novo jogo.

Dens. de tráfego: ajusta o número de carros privados nas estradas.
Valores maiores criam mais tráfego, 0 (zero) gera nenhum. Novos carros aparecerão à medida que as áreas urbanas crescem.

Indústrias rurais: ajusta o número inicial de cadeias industriais fornecedoras fora das áreas urbanas.
Se o terreno é muito irregular o espaço adequado pode não ser encontrado e menos indústrias aparecerão.

Indústrias urbanas: ajusta o número inicial de consumidores finais de mercadorias nas áreas urbanas, como lojas e postos de gasolina.
Novos consumidores (e possivelmente fornecedores, sem ser necessariamente em áreas urbanas) aparecem cada vez que a população aumenta em aproximadamente 2000 habitantes.

Atrações turísticas: ajusta o número inicial de construções fora das áreas urbanas que atraem passageiros e correio.
Essas atrações aparecem fora das áreas urbanas e em somam-se com quaisquer atrações geradas em novas vilas ou cidades no começo do jogo. Essas atrações também geram passageiros e correio.

Linha do tempo a partir de: permite alterar o ano em que o jogo começa. Quando o botão em forma de quadrado está "apertado", essa opção está selecionada e, ao passar do tempo, mais veículos e opções de construção poderão aparecer.
Quando o botão em forma de quadrado não está "apertado": o jogo ainda iniciará no ano escolhido, mas todos os veículos e opções de contrução aparecerão imediatamente; as áreas urbanas aparecerão com prédios de todas as épocas; e veículos mais lentos não são tão lucrativos (já que o lucro é calculado pela velocidade média do transporte disponível).

Permitir mudança de jogador: essa opção lhe deixa jogar como um jogador dono das empresas que são comandadas pela IA ou como o serviço público (esta opção não pode ser acessada após o jogo ser iniciado).

Modo iniciante: essa opção faz com que o jogador receba um lucro maior no jogo por transportar mercadorias e passageiros (padrão: 150% dos valores recebidos no modo normal). Além disso, as Indústrias não pararão de produzir quando o(s) consumidor(es) já tiver(em) excesso de mercadorias.

Carregar jogo: abre os controles para jogar um jogo salvo previamente, substituindo o mundo atual que é perdido ao selecionar um jogo salvo.

Criar jogo: cria um novo mundo, usando as configurações mostradas na tela. Clique nesse botão para começar a jogar - Boa Sorte e Curta o Jogo!

{Dica: Os valores usados por padrão quando o Simutrans é iniciado e outras configurações podem ser alterados no arquivo simuconf.tab}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008. Atualizado em 18/12/2010.

simutrans-124.3/simutrans/text/pt/options.txt000066400000000000000000000027041474050137200214460ustar00rootroot00000000000000Ajuda - Opções

Opções

Opções abre controles para a operação e apresentação do jogo; e sair do Simutrans a partir da janela Opções.

Clique sobre o ícone do disquete no topo da tela do jogo para abrir as Opções.

Clique sobre um botão para abrir novos controles:

Idioma: define um idioma a ser usado no jogo.

Cores: define a cor da companhia do Jogador.

Vídeo: cofigurações de como o jogo se aparentará visualmente no Simutrans.

Som: configurações para som e música no jogo.

Jogadores: abre controles para diferentes companhias dos jogadores.

Carregar: abre controles para continuar um jogo salvo.

Salvar: abre controles para gravar o atual jogo, para continuar jogar depois.

Novo jogo: abre controles para començar um novo jogo (isto fecha as barras de ferramentas, textos e opções do jogo atual).

Sair: fecha o Simutrans, e o jogo atual não é salvo.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008. Atualizado em 20/12/2010.

simutrans-124.3/simutrans/text/pt/players.txt000066400000000000000000000044731474050137200214370ustar00rootroot00000000000000Ajuda - Lista de jogadores

Lista de jogadores

A Lista de jogadores fornece informação e possui controles para as diferentes companhias dos jogadores.

Clique em 'Jogadores' na janela Preferências ou pressione [k] para abrir a Lista de jogadores, que mostra o nome das companhias e seus balanços.

Há oito jogadores: jogador humano, Poder público e seis jogadores controlados por inteligência artificial (IA). Os controles permitem jogar como outra companhia de transporte se Permitir mudança de jogador foi selecionado na criação do jogo.

Clique no botão em forma de seta para atuar como aquela companhia no jogo atual. Uma mensagem de confirmação aparece quando se é trocado o jogador: clique no x do canto superior esquerdo da mensagem ou use o teclado para fechá-la.

Clique no nome do jogador para ver suas Finanças.

Clique no botão quadrado ao lado de um jogador de IA para ativá-lo/desativá-lo (o botão aparece pressionado quando a opção é selecionada).

Jogadores de IA não vão à bancarrota e gerenciam seus veículos com máxima eficiência.
Desativando um jogador de IA durante o jogo não removerá sua rede de transporte.
Alguns jogadores de IA podem usar somente veículos de estradas ou ferrovias, alguns podem somente transportar mercadorias ou passageiros.

{Dicas: veículos não podem usar trilhos de outro jogador ou estações (de qualquer modo, veículos de todos os jogadores podem usar itens construídos pelo Poder público).
Jogadores não podem construir itens ou colocar marcadores nos trilhos ou estradas de outro jogador, ou remover itens construídos por outro jogador (de qualquer modo, alguns itens construídos pelo Poder público podem ser removidos usando a ferramenta Remover).
Desabilitar a mudança de jogador também restringe as ferramentas extras como Poder público.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/railtools.txt000066400000000000000000000235771474050137200217760ustar00rootroot00000000000000Ferrovias

Ferrovias

A Barra Ferrovias mostra as ferramentas para construir uma rede de transporte sobre trilhos. As ferramentas podem construir os trilhos (também eletrificar e demolir), pontes, túneis, sinais, depósitos, estações, plataformas e extensões. Se jogar com a Linha do Tempo ativa, com a passagem do tempo no Simutrans, novas ferramentas podem aparecer.

Clique no ícone de trem na barra de ferramentas. Mova o cursor do mouse por cima do botão, depois de abrir ou clicar na barra de ferramentas, para ver o nome e, onde for o caso, o custo da construção, custo de manutenção (dentro dos parênteses), limite de velocidade máxima e comprimento máximo.

A Barra Ferrovias inclui, da esquerda para a direita:

Trilhos: ferramenta de construir trilhos, para trens, entre dois pontos na visão do jogo. Os trilhos só podem ser construídos sobre barrancos na direção dos mesmos e não podem encontrar caminhos através de terreno acidentado ou sobre a água (só se utilizar pontes). Um trilho construído entre dois pontos pode usar um trilho existente em seu caminho.
Para construir um trilho: clique na ferramenta para selecionar o trilho (o cursor torna-se num trilho), em seguida, clique no terreno para dar o ponto de partida do trilho (mostra um trator na visão do jogo e exibe as coordenadas no mapa inferior direito do ecrã), e finalmente clique no terreno para o ponto final do trilho.
{Dica: Diferentes tipos de trilhos podem ser ligados (porém não quando construídos por diferentescompanhias). Você pode utilizar também pontes e túneis para desviar de montanhas e obstruções. Use Editor de terrenos para mudar terreno, a fim de permitir caminhos para trilhos. Use a ferramenta Remover para remover pistas individuais e algumas obstruções. Use [Ctrl] ao mesmo tempo para funções extras. Utilize o [z] para desfazer algo que já foi feito (custos não são reembolsados). Pressione [t] para ativar a ferramenta de construção do ultimo trilho utilizado.}

Eletrificar Trilhos: esta ferramenta eletrifica trilhos, pontes, depósitos e túneis, para uso dos veículos elétricos.
Clique na ferramenta ou pressione [e] (o cursor torna-se num par de postes de eletrificação), em seguida, clique no trilho na visão do jogo para dar o ponto inicial da eletrificação (o mesmo ícone do cursor é fixado neste ponto), e finalmente clique no segundo ponto no trilho, para eletrificar o trecho entre os dois pontos.
{Dica: Use a ferramenta Remover para remover a eletrificação dos trilhos.}

Remover trecho de trilhos: esta ferramenta remove trilhos eletrificados e não eletrificados, quando não há veículos entre dois pontos na visão do jogo (Nota: plataformas, sinais, túneis e pontes do trecho também são removidos). O uso da ferramenta é associada ao custo da construção.
Para remover um trecho de trilho: clique na ferramenta (cursor se muda numa cruz vermelha), depois clique no ponto inicial do trecho a ser removido (neste mesmo ponto é fixada uma cruz vermelha); e finalmente clique em outro ponto do trilho, para remover o trecho entre estes dois pontos.
{Dica: Altere o jogador para remover os trilhos de cada companhia.}

Pontes: ferramenta para construir pontes retas, para os veículos ferroviários passarem, entre duas seções de trilhos na visão do jogo. As pontes têm um comprimento máximo. A ferramenta constrói pontes de uma ponta de trilho até um outro lugar adequado (outra ponta de trilho ou um barranco mais alto, dentro do limite de comprimento).
Para construir uma ponte: clique num botão de ponte desejada (o cursor torna-se numa ponte), e clique no final de um trilho (ponto inicial da ponte) para construir. Alguns obstáculos podem ser passados, mas montanhas altas ou falta de um local adequado para a ponte finalizar podem parar a sua construção, então deve-se colocar o trilho com as pontas alinhadas em ambos os lados do local onde se estará sendo construída a ponte, e tente novamente.
{Dicas: Use a ferramenta Remover para remover pontes (clique sobre o ponto final da ponte) e alguns obstáculos à frente, como um edifício alto, por exemplo. Use as ferramentas para trilhos para conectar os fins da ponte aos trilhos.}

Túnel para trem: esta ferramenta constrói um túnel reto, para os veículos ferroviários poderem atravessar pelo subsolo, entre dois trilhos alinhados na visão do jogo. Túneis não podem ser inclinados: os veículos entram e saem na mesma altura. A ferramenta cria um túnel no fim de um trilho, sendo colocado em um barranco.
Para construir um túnel: clique na ferramenta (cursor torna-se num túnel) e, em seguida, clique no final do trilho em um baranco para a entrada do túnel. Se um túnel não encontrar uma saída adequada (um barranco livre de obstruções), ele não será construído: coloque o trilho em ambos os lados que devem ser conectados, e tente novamente.
{Dica: Use a ferramenta de Edição de terrenos e a ferramenta Remover para criar locais adequados para entradas e saídas de um túnel. Use as ferramentas para trilhos para conectar saídas de túneis aos trilhos.}

Sinais para Trilhos:constrói sinais para os veículos ferroviários em um trilho na visão do jogo. Sinais direcionam e regulam o fluxo de veículos em trilhos e pontes, e em cruzamentos e estações. Sinais bidirecionais e de mão-única também podem ser construídos.
Para construir um sinal bidirecional no trilho: clique na ferramenta para selecionar sinal (cursor torna-se num par de sinais), depois clique no trilho. Para construir um sinal de mão-única: clique novamente no mesmo ponto, com o cursor de sinais, e clique novamente para voltar a ter um sinal para os dois sentidos.
IMPORTANTE: Tome cuidado ao colocar sinais de mão única, que impede alguns veículos chegarem ao destino; por padrão veículos são conduzidos à direita (pode ser alterado em simuconf.tab).
-Semáforo ferroviário: os veículos prosseguem somente se o trilho à frente até o próximo semáforo ou até o próximo destino da Programação (uma Estação ou ponto de passagem) não está ocupado por nenhum outro veículo. No modo mão-única, estes sinais deixam passar veículos em uma única direção.
- Sentido único: veículos não prosseguem além do sinal (disponível só em modo mão-única).
-Pré-semáforo ferroviário: os veículos proseguem se a seção do trilho à frente (ou entre três consecutivos sinais ou até o próximo destino da Programação) não está ocupado por nenhum outro veículo. No modo mão-única, estes sinais deixam passar veículos em uma única direção.
-Direcionador ferroviário para vaga livre: direciona os veículos a uma plataforma vazia, em uma estação multi-plataforma: um veículo passando este sinal pode usar qualquer plataforma vazia em seu destino, e não apenas aquelas definidas em sua Programação. Se nenhuma plataforma ou rota para o próximo destino vazia é encontrada, os veículos irão esperar no sinal.
{Dica: Remova os sinais com a ferramenta Remover. Mantenha pressionada [Ctrl] para colocar sinais sobre pontes ferroviárias acima de trilhos em nível inferior.}

Depósitos ferroviários: esta ferramenta cria um depósito para compra e gerenciamento de comboios e composições. Depósitos têm um custo e manutenção e são construídos no final do trilho ferroviário na visão do jogo.
Para construir um depósito: clique na ferramenta (cursor torna-se num depósito), em seguida, clique no final do trilho.
{Dica: Para remover depósitos use a ferramenta Remover. Depósitos somente mostram veículos elétricos se estiver num trilho eletrificado.}

Estações: a ferramenta constrói plataformas, utilizadas pelos veículos para carregar e descarregar mercadorias e passageiros. Plataformas têm um custo e manutenção e são construídas no trilho (mas não em curvas e cruzamentos).
A plataforma tem uma área de captura para mercadorias, passageiros e correio. Plataformas diferentes podem ter diferentes capacidades de mercadorias e passageiros. No canto de alguns botões, um ícone (utilizado em Lista de Paradas e Informações das Paradas) mostra quais itens são tratados pela plataforma.
Para construir uma plataforma: clique na ferramenta para selecionar plataforma (cursor torna-se numa plataforma) e, em seguida, clique no trilho.
{Dica: Para remover plataformas da estação utilize a ferrementa Remover. Estender e criar estações multi-plataformas (construindo mais plataformas nos trilho) servem para acomodar mais veículos, aumentando a capacidade de carregamento. Pressione [v] para mostrar/esconder a área de captura de mercadorias e passageiros na visão do jogo. Mantenha pressionada[Ctrl] para colocar estações sobre pontes ferroviárias acima de trilhos em nível inferior.}

Extensões: esta ferramenta constrói extensões e edifícios para estações, de modo que se possa aumentar a capacidade, área de captura para passageiros e mercadorias, e o custo de manutenção. No canto de alguns botões, um ícone (usado na Lista de Paradas e Informações das Paradas), que mostra itens que são tratados pela extensão.
Para construir uma extensão: clique na ferramenta para selecionar (cursor torna-se numa estensão) e, em seguida, clique na posição exigida, ao lado de uma estação, na visão do jogo. A nova extensão é agora considerada como sendo parte da estação.
{Dica: Remova as extensões utilizando a ferramenta Remover.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/removal_tool.txt000066400000000000000000000047231474050137200224600ustar00rootroot00000000000000Ferramenta Remover

Ferramenta Remover

Ferramenta Remover é usada para destruir e remover os itens e obstáculos não desejados à construção em um único quadro do terreno na tela do jogo.

Para usar: Clique no ícone com uma cruz vermelha (ou escavadora, no pak128) no topo da tela do jogo ou pressione [a] para abrir a Ferramenta Remover (o cursor torna-se numa cruz vermelha numa nuvem de poeira).
Posicione o cursor na tela dojogo, um retângulo amarelo indica a posição em que a ferramenta irá operar (as coordenadas do mapa são indicadas na barra cinza abaixo). Então clique sobre o objeto na tela do jogo para remover.

O custo do uso da ferramenta é indicado na tela do jogo e aparece bem onde estava o item eliminado. O custo da remoção é equivalente ao custo da construção para os itens do jogador.
O custo de destruir edifícios da cidade é o mesmo valor apresentado na caixa de diálogo deste edifício aberta pela Ferramenta de consula. O custo de destruir árvores é de 100 Hajo Credits.

Ferramenta de remoção pode ser usada para remover os pedestres individuais e os carros privados.

A ordem de remoção dos itens em um quadro do terreno: carros e pedestres, sinais, paradas ou plataforma, eletrificação das vias, ponte ou túnel, vias (trilhos primeiramente se sobre estradas).

{Dicas: Para remover um veículo do jogador, venda o veículo a partir de Detalhes do Comboio.
Para remover indústrias, atrações turísticas e a prefeitura, primeiro altere para jogador Serviço Público. Por favor atenção: o uso da ferramenta de remoção em uma prefeitura removerá todos os edifícios da cidade da área urbana.
Use [Ctrl] para usar a ferramenta em objetos no nível superior.
Para destruir/remover itens de outros jogadores, primeiro faça a mudança de jogador em Lista de Jogadores.
Para remover trechos de um trilho ou estrada, use Remover trecho de trilhos também encontrado em Bondes) ou Remover trecho de estradas.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/roadtools.txt000066400000000000000000000257311474050137200217660ustar00rootroot00000000000000Ajuda - Estradas

Estradas

A Barra Estradas possibilita a construção de uma rede de transportes rodoviária para mercadorias e passageiros. As ferramentas nesta barra podem construir ou remover: estradas, pontes, túneis, sinais, depósitos, extensões e Paradas. Caso esteja jogando com a linha do tempo ativada, então com o passar do tempo mais opções poderão aparecer.

Clique no ícone do caminhão na barra de ferramentas. Mova o cursor do mouse sobre a barra de opções (após abrir ou clicar na barra de ferramentas) para ver o nome e, onde for o caso, o custo da construção, custo de manutenção (em parênteses), velocidade máxima permitida e o comprimento máximo.

A Barra Estradas inclui, da esquerda para a direita:

Estradas: ferramenta a qual constrói uma estrada entre dois pontos para veículos rodoviários. As estradas não podem ser construídas em áreas ocupadas por outras construções, e podem apenas ser construídas em barrancos na direção dos mesmos e não podem encontrar um caminho através de terrenos acidentados ou água. As novas estradas construídas podem se conectar com outras já existentes. Existem atualmente diversos tipos de estradas, com diferentes velocidades máximas permitidas e custos de construção e manutenção.
Para construir uma estrada: clique em um dos botões com a imagem de uma estrada para escolher um tipo (o cursor torna-se uma estrada), então clique na visão do jogo em um local para ser o ponto inicial da estrada (mostra um trator na visão do jogo e as coordenadas do local na barra inferior da tela no canto direito), e então clique em um outro ponto na visão do jogo para ser o ponto final da estrada.
{Dica: Diferentes tipos de estradas podem se conectar mesmo se forem construídas por companhias diferentes. Use pontes e túneis para conectar as estradas passando por terreno acidentado, ou para evitar obstáculos. Use o Editor de terrenos para alterar o terreno, abrindo caminhos para as estradas. Use o botão Remover para remover seções individuais de estradas e alguns obstáculos. Aperte [Ctrl] ao mesmo tempo para funções extras. Desfazendo alterações apertando [z] não o reembolsa dos custos da construção. Aperte [s] para selecionar a última ferramenta para construção de estradas usada.}

Remover trecho de estrada: essa ferramenta remove estradas, quando não há nenhum veículo passando, entre dois pontos na visão do jogo (qualquer Parada rodoviária, sinal, túnel ou ponte no caminho é removido junto). O uso dessa ferramenta implica em custos de construção.
Para remover um trecho de estrada: clique nessa ferramenta (muda o cursor para um X vermelho); então clique no trecho a ser destruído (nesse mesmo ponto é fixado um X vermelho); e finalmente clique em um outro ponto na estrada, para remover o trecho entre os dois pontos.
{Dica: Jogue como uma outra companhia para remover suas respectivas estradas.}

Ponte rodoviária: possibilita a construção de pontes retas, para que os veículos possam passar entre dois trechos de estrada na visão do jogo. As pontes têm uma extensão máxima. Essa ferramenta constrói as pontes a partir do fim de uma estrada até um local adequado (outro fim de estrada ou um local com uma altitude levemente superior, dentro dos limites do comprimento máximo permitido).
Para construir uma ponte: clique em uma ferramenta de construção de ponte rodoviária para selecionar um tipo (muda o cursor para uma ponte), e então clique no fim de uma estrada (ponto inicial da ponte). Certos obstáculos ou a falta de um local adequado para o fim da ponte pode cancelar a construção da ponte: construa estradas em ambos os lados a serem conectados pela ponte, e tente novamente.
{Dica: Use o botão Remover para remover pontes (clique no fim da ponte) e também certos obstáculos à construção de pontes. Use os botões de construção de Estradas para conectar as extremidades das pontes às estradas.}

Túnel rodoviário: possibilita a construção de um túnel reto, para que os veículos possam passar através da terra, entre dois trechos de estrada na visão do jogo. Os túneis não podem ser inclinados: os veículos entram e saem dos túneis a uma mesma altitude.
Essa ferramenta constrói um túnel, a partir do fim de uma estrada colocada em uma inclinação. Para construir um túnel: clique nessa ferramenta (muda o cursor para um túnel), e então clique em um fim de estrada em um uma inclinação para construir a entrada do túnel. Se o túnel não puder encontrar uma saída adequada (uma inclinação livre de obstáculos), ele não será construído: então coloque um fim de estrada em ambos os lados que serão conectados, e tente novamente.
{Dica: Use o Editor de terrenos e o botão Remover para criar locais adequados para as entradas e saídas de túneis. Use os botões de construção de estradas para conectar as saídas dos túneis às estradas.}

Sinais e bloqueadores rodoviários: constróem sinais e barreiras rodoviárias para os veículos que ali transitam, na visão do jogo. Esses sinais direcionam e regulam o fluxo de veículos em estradas e pontes, e em cruzamentos e Paradas (onde passageiros e mercadorias são carregados e descarregados). Versões de mão-única e mão-dupla de alguns sinais podem ser construídos.
IMPORTANTE: Tome cuidado para não colocar sinais que evitam os veículos a chegarem aos seus destinos, por padrão os veículos dirigem pelo lado direito (isso pode ser alterado no simuconf.tab).
- Semáforo: essa ferramenta constrói semáforos que controlam o fluxo de veículos rodoviários em cruzamentos, tanto deixando-os passarem ou fazendo-os aguardarem por um tempo. Clique nessa ferramenta para selecioná-la (muda o cursor para um semáforo), e então clique na estrada para colocar um semáforo ali. Clique novamente nos cruzamentos para alterar a orientação dos semáforos.
- Bloqueio: (disponível só em pak128) essa ferramenta constrói uma barreira para impedir veículos rodoviários de prosseguirem. Clique na ferramenta para selecionar (o cursor torna-se num bloqueio), então clique na estrada para construir.
- Sentido único: essa ferramenta constrói um sinal que evita os veículos passarem daquele ponto, usando um lado da estrada. Clique nesse botão para selecioná-lo (o cursor muda para essa placa), e então clique em um trecho na estrada para colocar a placa ali; clique novamente no mesmo lugar para mudar o lado da estrada o qual a placa está.
- Velocidade mínima de 80km/h essa ferramenta constrói uma placa que evita os veículos com velocidade máxima inferior a 80 km/h de continuar naquela estrada. Clique nesse botão para selecioná-lo (o cursor muda para essa placa), e então clique em um trecho na estrada para colocar a placa ali; clique novamente no mesmo lugar para mudar o lado da estrada o qual a placa está, alterando o lado da estrada o qual o efeito da placa será aplicado.
- Direcionador rodoviário para vaga livre: essa ferramenta constrói uma placa a qual direciona um veículo rodoviário a uma seção livre de uma Parada com várias seções para carregar/descarregar mercadorias e passageiros: um veículo que passa por este sinal pode usar qualquer seção de uma Parada livre que esteja em seu próximo destino, e não apenas a um determinado pela sua Programação. Se não houver nenhuma vaga livre ou caminho livre ao seu próximo destino, o veículo aguardará na placa. Clique nessa ferramenta para selecioná-la (o cursor muda para essa placa), e então clique em um trecho na estrada para colocar ali a placa, e clique novamente no mesmo trecho para alterar o lado da estrada o qual a placa está, alterando o lado o qual os efeitos da placa serão aplicados.
- Vias expressas: (disponível só em pak128) ferramentas que constroem um sinal que só permite veículos proceder numa direção em uma estrada se a velocidade máxima deles for mais de 80km/h.
Clique em um dos botões acima para selecionar um deles (o cursor muda para o respectivo sinal), e então clique em um trecho na estrada para colocar ali o sinal, e clique novamente no mesmo local para alterar o lado da estrada o qual o sinal está, alterando também o lado o qual os efeitos do mesmo serão aplicados.
{Dica: Remova sinais com o botão Remover. Pressione [Ctrl] para colocar sinais em pontes sobre estradas construídas em um nível inferior.}

Garagem: essa ferramenta constrói uma garagem para a compra e gerenciar veículos rodoviários e seus reboques. As garagens possuem custos de manutenção e são construídos no fim de uma estrada.
Para construir uma garagem: clique neste botão (muda o cursor para uma garagem), e então clique no fim de uma estrada.
{Dica: Use o botão Remover para destruir Garagens.}

Estacionamento: (disponível só em pak 128) ferramentas que constroem extensões para Paradas, as quais aumentam capacidade e área de captura para bens e passageiros, e o custo de manutenção.
Para construir uma extensão: clique numa ferramenta para selecionar uma extensão (cursor torna-se numa extensão), então clique na posição desejada numa estrada, ao lado de uma Parada existente na visão do jogo. A nova extensão agora passa a ser considerada parte da Parada.
{Dicas: Remova extensões com a ferramenta Remover.}

Paradas rodoviárias: essas ferramentas possibilitam a construção de locais para que os veículos rodoviários possam carregar/descarregar mercadorias e passageiros.
Quando uma seção de uma Parada rodoviária não é construída ao lado de uma Parada já existente, uma nova Parada será criada.
Paradas rodoviárias são construídas sobre estradas já existentes e possuem um custo de manutenção e uma área de captura de mercadorias, passageiros e correio. No canto de certos botões um ícone (utilizado na Lista de Paradas e na Informação da Parada) mostra quais itens a Parada aceita. Diferentes Paradas podem possuir capacidades diferentes para mercadorias, passageiros e correio.
Para construir uma Parada: clique em um dos botões de construção de um tipo de Parada (muda o cursor para a Parada correspondente), e então clique na posição desejada em uma estrada.
{Dica: Remova as Paradas com o botão Remover. Pressione [v] para mostrar/ocultar a área de captura de mercadorias e passageiros na tela do jogo. As Paradas rodoviárias não podem ser colocadas em uma estrada construída por outras companhias. Pressione [Ctrl] para construir em pontes sobre rodovias em um nível inferior. Crie Paradas com múltiplas vagas para veículos para aumentar a capacidade e a área de captura.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 07/02/2008.

simutrans-124.3/simutrans/text/pt/save.txt000066400000000000000000000041731474050137200207130ustar00rootroot00000000000000Ajuda - Salvar

Salvar

Salvar armazena o jogo atual a um arquivo (para continuar o jogo mais tarde) e pode ser usado para apagar esses arquivos.

Salvar abre-se de Opções de Jogo ou prosionando a tecla [S]; também lista nome, data e hora dos jogos precedentes.
Se todos os nomes não estiverem visíveis: use a barra de rolagem no lado direito para rolar os nomes.

O jogo atual pode ser salvo em um novo arquivo ou em cima de um jogo já existente.
Para salvar em um novo arquivo, entre com o novo nome no campo de preenchimento "Arquivo" no topo de Salvar: clique no campo "Arquivo", digite um nome e pressione [Enter] ou [Backspace] ou clique em OK; o novo nome de arquivo é listado.
IMPORTANTE: Se um nome de arquivo listado é usado: o jogo velho é substituído, pelo jogo atual e apagado.

Por padrão o jogo atual aparece no campo "Arquivo", para salvar este arquivo: clique em OK (os dados velhos serão apagados e substituídos pelos novos).
Para salvar o jogo em cima de um arquivo velho: clique em um nome da lista (o jogo velho substituído pelo jogo atual).

Os nome de arquivos podem ser combinações de letras, números e simbolos com o comprimento máximo de 57 caracteres; depois de salvar, só 20 (aprox.) caracteres são mostrados em Salvar e Carregar.

AVISO: Apertando o botão X na frente do nome de um arquivo ele será APAGADO imediatamente e pemanentemente, o arquivo será retirado da lista e o Salvarserá fechado. Use esta função cuidadosamente.

{Dica: Recomece um jogo salvo a partir do Carregar.
Mude o autosave (salvamento automático do jogo) no simuconf.tab}.

Clique em Cancelar para fechar Salvar; ou no X no canto superior esquerdo da janela; ou use o teclado.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/scenario.txt000066400000000000000000000004651474050137200215600ustar00rootroot00000000000000Ajuda - Carregar cenário

Carregar cenário

Você pode jogar com cenários prontos no Simutrans. Aqui você tem que cumprir certas metas, tais como: conectar uma fábrica, fiquar rico o mais rápido possível, ou erigir uma monumental sede empresarial.

simutrans-124.3/simutrans/text/pt/schedule.txt000066400000000000000000000113111474050137200215410ustar00rootroot00000000000000Programação

Programação

A programação é usada para configurar a rota e a quantidade mínima de mercadorias e passageiros para um comboio ou uma linha.
Ela lista as paradas (onde veículos recolhem e entregam mercadorias e passageiros) e pontos de passagem (que podem ser usados para direcionar os comboios por um caminho específico caso haja mais de um disponível ou fornecer destinos temporários) com suas coordenadas do mapa.

A janela Programar abre do botão Programar nas Informações do comboio e nos depósitos.
Controles para a programação de uma linha abrem dos botões Nova Linha e Atualizar no Gerenciador de linhas e nos depósitos.

Quando a janela Programar é aberta através das informações do comboio, o nome da linha utilizada por ele (se houver) é mostrado no topo da janela.
Serve linha: clique nos botões em forma de seta nos dois lados do nome da linha para escolher uma linha ou clique na caixa de nome para abrir uma lista suspensa (clique na linha para selecioná-la).
Clicando na caixa de texto, é possível digitar e alterar o nome da linha.

Carga mínima (%): configura a quantidade mínima de mercadorias ou passageiros que o comboio deve esperar até prosseguir. A porcentagem mostrada se refere à capacidade total do comboio e não a um tipo individual de item carregado.
O comboio esperará na parada até estar carregado com a porcentagem requerida.
Para usar: clique em uma parada na lista para selecioná-la (o > antes do nome da parada mostra que mesma está selecionada), e use os botões em forma de seta para definir a porcentagem.
{Dicas: para incluir ou alterar porcentagens para todos os comboios de uma linha, use o botão Atualizar no Gerenciador de Linhas ou no depósito. Para incluir ou alterar porcentagens para somente um comboio e não para todos da linha, use o botão Programar nas Informações do combio ou no depósito.}

Os botões de opção (clique para usar, o botão aparece pressionado quando ativo) incluem:

Adicionar: adiciona uma parada onde veículos recolhem e entregam mercadorias e passageiros (veículos aquáticos podem usar qualquer quadro da área de captura de uma doca) ou ponto de passagem na rota.
Para adicionar: clique na opção para selecioná-la (o cursor mudará para um sinal escrito "HALT"), e clique no ponto desejado na área de jogo (pode ser feito em estradas, trilhos ou água, dependendo do tipo de veículo). A parada ou ponto de passagem agora aparece na programação.
{Dica: veículos não recolhem ou entregam mercadorias e passageiros em pontos de passagem.}

Inserir: insere uma parada ou ponto de passagem na rota, antes de uma parada ou ponto de passagem existente.
Para inserir: clique em uma parada ou ponto de passagem da lista para selecioná-lo (o > antes do nome da parada mostra que mesma está selecionada), e clique no botão inserir (o cursor mudará para um sinal escrito "HALT"), e clique no ponto desejado na área de jogo (pode ser feito em estradas, trilhos ou água, dependendo do tipo de veículo).
A nova parada ou ponto de passagem é inserido na programação antes da parada ou ponto de passagem anteriormente selecionado.
{Dica: veículos não recolhem ou entregam mercadorias e passageiros em pontos de passagem.}

Eliminar: essa opção deleta uma parada ou ponto de passagem da rota.
Clique no botão para ativá-lo, e clique em um item da lista para remover.

Espelhar linha: adiciona as paradas e pontos de passagem existentes em ordem reversa na rota. Os valores de Carga mínima (%) também são replicados. Clique no botão para usá-lo: a nova rota aparecerá na programação.

Promover a linha: (somente disponível quando a janela Programar for aberta pelas Informações do comboio) cria uma nova linha utilizando a atual programação. A nova linha é identificada por um número e é listada no Gerenciador de Linhas.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/shiptools.txt000066400000000000000000000142521474050137200220000ustar00rootroot00000000000000Ajuda - Navegação

Ferramentas de navegação

As Ferramentas de navegação constróem uma rede de transporte por mares e canais. As ferramentas podem construir ou remover: canais, eclusas, vários tipos de doca e estaleiros. Se estiver jogando com linha do tempo, então conforme o tempo passa no Simutrans mais opções de ferramentas podem aparecer.

Clique no ícone de um barco no topo da área de jogo para abrir a barra de ferramentas.
Passe o cursor do mouse em cima das opções (após ter aberto ou clicado na barra de ferramentas) para ver o nome, o custo de construção, custo de manutenção (entre parênteses), e o limite máximo de velocidade.

As Ferramentas de navegação incluem, da esquerda para a direita:

Canal: constrói hidrovias para veículos aquáticos, entre dois pontos na área de jogo.
Canais podem somente ser construídos em terra firme e podem não encontrar um caminho através de terrenos acidentados. Canais construídos entre dois pontos podem usar trechos de canais existentes em seu caminho.
Para construir um canal: clique na ferramenta para ativá-la (o cursor mudará para um canal), e clique na área de jogo no ponto inicial do canal (mostra um trator na área de jogo e as coordenadas do mapa no lado direito da barra inferior do jogo), e finalmente clique na área de jogo no ponto final.
{Dicas: canais construídos por jogadores diferentes podem não se conectar. Use o Editor de terrenos para modificar o terreno, possibilitando caminhos para os canais. Use a ferrramenta Remover para remover partes individuais do canal e obstáculos. O desfazer [z] não reembolsa os custos da construção.}

Remover canais: remove partes do canal, quando não houver veículos presentes, entre dois pontos na área de jogo (Obs.: cais de canal no caminho são removidos também). O uso da ferramenta tem um custo de construção.
Para remover canais: clique na ferramenta para ativá-la (o cursor mudará para um X vermelho), e clique no canal que será removido (o ponto selecionado é mostrado por um X vermelho na área de jogo), e finalmente clique no segundo ponto em um canal conectado, para remover o trecho de canais desde o ponto inicial selecionado.

Canal elevado: constrói eclusas e uma ponte de canal para elevar/rebaixar o canal em um nível na área de jogo. A ponte possui um comprimento máximo e é construída no fim de um canal até um ponto disponível (outro final de canal ou um trecho de terra mais alto, dentro do limite).
Para construir um canal elevado: clique na ferramenta para ativá-la (o cursor mudará para um canal elevado), e clique na área de jogo no fim de um canal (ele será o ponto inicial da ponte). Obstáculos ou a falta de um lugar propício para o fim da ponte podem interromper a construção: construa canais dos dois lados que devem ser ligados pela ponte e tente novamente.
{Dicas: use a ferramenta Remover para remover pontes (clique no começo dela) ou obstáculos para a construção. Use canais para conectar pontes com hidrovias.}.

Cais de canal: constrói uma doca em um canal na área de jogo para navios e barcaças recolherem e entregarem mercadorias, passageiros e correio.
Quando uma doca não for construída ao lado de uma parada existente, será criada uma nova.
Uma doca possui uma área de captura para mercadorias, passageiros e correio. No canto superior esquerdo um ícone (usado na Lista de paradas e nas Informações das estações) mostra que tipos de itens uma parada suporta.
Para construir uma doca: clique na ferramenta para ativá-la (o cursor mudará para um cais de canal); e clique em um ponto do canal na área de jogo.
{Dicas: remova as docas com a ferramenta Remover. Pressione [v] para mostrar/ocultar a área de captura para mercadorias, passageiros e correio na área de jogo.
Paradas somente de veículos aquáticos não serão listadas na Lista de paradas/estações}.

Paradas marinhas: os vários itens a seguir constróem docas na área de jogo para veículos aquáticos.
Docas são construídas em uma porção reta da costa.
Quando uma doca não for construída ao lado de uma parada existente, será criada uma nova.
Uma doca possui uma área de captura para mercadorias, passageiros e correio. No canto superior esquerdo um ícone (usado na Lista de paradas e nas Informações das Estações) mostra que tipos de itens uma parada suporta. Diferentes docas podem ter diferentes capacidades para mercadorias, passageiros e correio.
Para construir uma doca: clique na ferramenta para ativá-la (o cursor mudará para uma doca) e então clique em um quadro adjacente ao mar.
{Dicas: remova docas com a ferramenta Remover.
O tamanho das docas pode ser incrementado construindo nos quadros adjacentes. Veículos de transporte aquático podem usar qualquer quadro de água na área de captura da doca.
Paradas somente de veículos aquáticos não serão listadas na Lista de paradas/estações}. Indústrias em alto-mar como plataformas de petróleo não precisam de docas. Veículos de transporte aquático podem usar qualquer quadro da área de captura da indústria.
Pressione [v] para mostrar/ocultar a área de captura para mercadorias, passageiros e correio na área de jogo.

Construir estaleiro: constrói um depósito para a compra e gerenciamento de navios, barcos e barcaças. Depósitos possuem um custo de manutenção e são construídos dentro d'água na área de jogo.
Para construir um estaleiro: clique na ferramenta para ativá-la (o cursor mudará para um estaleiro), e clique na água na área de jogo.
{Dicas: remova os depósitos com a ferramenta Remover.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/simutrans.txt000066400000000000000000000050211474050137200217730ustar00rootroot00000000000000Simutrans

Bem-vindo ao Simutrans...

Escolha um, entre alguns milhares, dos mundos do Simutrans. Então, ponha-se no lugar de um jovem empreendedor com um pouco de dinheiro dado por seus avós: ansioso para deixá-los orgulhosos, com a ambição de estabelecer uma companhia de transporte de sucesso, seu desafio a partir de agora é construir uma empresa vitoriosa.

Com o passar do tempo, transforme a sua pequena companhia em um grande império de transporte, mantendo as finanças equilibradas entregando cargas e satisfazendo o desejo de viajar de milhões de passageiros todos os meses.
Transporte passageiros, correio e mercadorias por estradas, ferrovias, navios e até pelo ar.

Cada mundo possui algo diferente a oferecer. Dê uma boa olhada ao seu redor... o futuro do lugar está em suas mãos e nas de seus concorrentes.

No começo, pode ser mais fácil de se começar suprindo uma usina de geração de energia com aquilo que ela precisa. A seguir, conecte outras indústrias, talvez usando estações de distribuição onde as mercadorias são recarregadas.
A desvantagem de somente transportar mercadorias é que as cidades não irão crescer e novas indústrias não aparecerão.

Ou então, você pode começar imediatamente a transportar passageiros (e correio). Este é mais desafiador, já que os habitantes deste mundo querem viajar para os locais de suas preferências.
Alguns precisam ir trabalhar nas indústrias, outros querem fazer compras no Shopping Center da cidade grande, enquanto outros decidem visitar pontos turísticos.

Se você não oferecer uma conexão até seus destinos, os passageiros não viajarão com você para sempre. Você precisará construir redes. Quando suas redes estiverem prontas, será necessário aumentar suas capacidades para absorver a demanda. Então, continue com o planejamento.
Se eles gostarem de seus serviços, as cidades crescerão, atraindo novas indústrias, e assim a economia será próspera.

Você pode jogar com o tempo que você quiser. Comece em 1880 e termine em 2050. Haverá novos veículos e edifícios durante todo esse tempo.
Jogue contra a IA ou do seu próprio jeito. Somente se ficar devendo por três meses, irá falir e será o fim de seu jogo.

O Simutrans-Team e toda a comunidade te desejam muitas horas de diversão jogando Simutrans!

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008. Veja a lista dos tradutores na Ajuda ou teclando F1.

simutrans-124.3/simutrans/text/pt/slopetools.txt000066400000000000000000000040751474050137200221610ustar00rootroot00000000000000Ajuda - Editor de terrenos

Editor de terrenos

As ferramentas do Editor de terrenos elevam e rebaixam o terreno, e podem ser usadas para obter locais viáveis para construção.

Clique no ícone de terreno que está no topo da área de jogo para abrir a barra de ferramentas.
Depois de abrir ou clicar sobre a barra de ferramentas, passe o cursor do mouse por cima das opções para ver o nome e o custo de construção.

A ferramenta funciona em áreas livres de obstáculos (exemplos: estradas, trilhos, edificações, paradas, estações etc).

Clique em um dos botões para ativar (o cursor muda-se de aparência), então posicione o cursor sobre o terreno na tela do jogo e clique para usar:

Elevar terreno/Abaixar terreno: eleva/abaixa o terreno.
O cursor mudará para uma seta para baixo ou para cima.
A ferramenta também é ativada pelas teclas [u] e [d].

Barrancos: cria um barranco na direção indicada pelo botão, podendo criar juntamente muros de arrimo verticais nas laterais
O cursor mudará para um cubo amarelo vazio que posiciona o barranco.

Abaixar quadro/Elevar quadro: abaixa/eleva um quadro específico do terreno, podendo juntamente criar muros de arrimo verticais em suas laterais.
O cursor mudará para um cubo amarelo vazio que modifica o quadro.

Restaurar relevo natural: retorna a forma natural do terreno, removendo juntamente os muros de arrimo.
O cursor mudará para um cubo amarelo vazio que restaura o terreno no quadro.

{Dica: O Editor de terreno fica mais fácil de se usar com a grade. Pressione [#] para exibir/ocultar a grade sobre o terreno.
Use a ferramenta Remover para remover obstáculos.
Dependendo do local do mapa, as ferramentas podem elevar ou rebaixar terreno dentro da água.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/sound.txt000066400000000000000000000016541474050137200211060ustar00rootroot00000000000000Ajuda - Ajustes de Som

Ajustes de Som

Ajustes de Som tem controles para efeitos de som e música.

Ajustes de Som abrem de Opções de Jogo.

Use as setas ou a barra de rolagem para aumentar ou diminuir o volume:

Volume dos efeitos: ajusta o volume de efeitos sonoros do jogo.

Volume da música: ajusta o volume da música. Se nenhuma música estiver disponível então os controles não funcionarão.

Tocando: muda a música; as setas alternam a execução das músicas disponiveis.

Nota: As músicas não são fornecidas com o Simutrans.
Ajuda para adicionar músicas está disponivel on line em http://wiki.simutrans.com

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/special.txt000066400000000000000000000145141474050137200213750ustar00rootroot00000000000000Ajuda - Ferramentas Especiais

Ferramentas Especiais

As Ferramentas Especiais constróem itens não-relacionados com tráfego e também permitem a você atuar como um de seus concorrentes dentro do jogo.

Clique no ícone representado por uma gota vermelha em um círculo amarelo (ou no de um guindaste no pak128) no topo da área de jogo para abrir a barra de ferramentas.
Passe o cursor do mouse em cima das opções (após ter aberto ou clicado na barra de ferramentas) para ver o nome e o custo de construção.

As Ferramentas Especiais incluem, da esquerda para a direita:

Agência dos Correios: esta ferramenta constrói uma agência de correios que permite a uma estação ou parada receber correspondência. Agências de correios aumentam a capacidade e a área de coberura da estação e possuem um custo de manutenção.
Para construir uma agência: clique na ferramenta para ativá-la, e na área do jogo clique ao lado de alguma estação existente. A nova agência agora fará parte da estação.
{Dica: remova as agências e os obstáculos com a ferramenta Remover.}

Extensões para estações: ferramentas que constróem prédios ou extensões para as estações. Extensões podem aumentar a capacidade e a área de coberura para cargas e passageiros, e também o custo de manutenção. No canto de algumas das opções um ícone (usado em Lista de Paradas e em Informações das Paradas) mostra quais itens a extensão permite que a parada receba.
Para construir uma extensão: clique na ferramenta para ativá-la (o cursor mudará para o desenho da extensão selecionada), e clique no local desejado, ao lado de uma estação existente, na área de jogo. A nova extensão agora fará parte da estação.
{Dica: remova as extensões com a ferramenta Remover.}

Mudar jogador (P+): permite atuar como outro jogador se a opção Permitir mudança de jogador tiver sido selecionada no início do jogo. Opções adicionais estão disponíveis se jogando como o Poder público.
Clique no botão (ou pressione [P]) para alternar entre os jogadores. Uma mensagem de confirmação aparece quando se muda o jogador: clique no [X] do canto superior esquerdo da mensagem ou use o teclado para fechá-la.

Criar nova cidade: constrói uma nova área urbana.
Para construir uma nova cidade: clique na ferramenta ou pressione [C] para ativá-la (o cursor mudará para uma pequena prefeitura), e clique no local desejado, na área do jogo. A nova cidade custa 5.000.000,00 de créditos e será construída sem pedir confirmação ao jogador.
{Dica: clique na prefeitura da cidade na área de jogo com a ferramenta Remover para demolir as construções da nova cidade.}

Plantar árvore: planta uma árvore na área de jogo.
Para plantar uma árvore: clique na ferramenta para ativá-la (o cursor mudará para uma árvore), e clique no lugar desejado.
{Dica: remova as árvores com a ferramenta Remover.}

Construir linha elétrica: constrói linhas elétricas que transportam eletricidade dos transformadores das usinas de geração de energia até as indústrias (para aumentar suas produtividades). O fornecimento de energia elétrica gera lucro. As linhas elétricas não podem cruzar trilhos e estradas na diagonal.
Para construir uma linha elétrica: clique na ferramenta ou pressione [l] para ativá-la (o cursor mudará para uma linha elétrica), e clique em um transformador situado em uma usina, e finalmente clique em um transformador situado em uma indústria.
{Dicas: linhas elétricas podem ser construídas em partes, clique nos pontos desejados na área de jogo. Remova as linhas elétricas com a ferramenta Remover.}

Construir transformador: constrói um transformador nas usinas geradoras de energia ou nas indústrias para conexão com as linhas elétricas.
Para construir um transformador: clique na ferramenta ou pressione [g] para ativá-la (o cursor mudará para uma gota vermelha em um círculo amarelo), e clique na posição desejada ao lado de uma indústria ou de uma usina de energia.
Transformadores construídos nas usinas de energia devem ser conectados com transformadores das indústrias por meio das linhas elétricas.
Se não houver eletricidade sendo fornecida, o transformador mostrará um raio de cor amarela. Quando houver fornecimento, mostrará um raio na cor vermelha.
{Dicas: indústrias e usinas de energia podem ter múltiplos transformadores para aumentar o fornecimento de eletricidade. Remova os transformadores com a ferramenta Remover.}

Marcador: abre controles para a colocação de um sinal com texto personalizado na área de jogo e pode ser usado para ir de um lugar a outro na área de jogo.
Clique na ferramenta para ativá-la ou pressione [M] (o cursor mudará para um marcador), e clique no lugar desejado para abrir a janela de controles do marcador. No topo da janela estão as coordenadas no mapa da posição selecionada e uma caixa de texto vazia, digite o texto desejado nela (clique na caixa, digite o texto e clique em OK ou pressione [Enter] ou [Return]) para colocar o marcador. O novo marcador é mostrado na área de jogo e mostrado na janela de controles do marcador (com as coordenadas do mapa) quando reaberta.
Para se deslocar até um marcador: abra a janela de controles do marcador e clique na posição desejada na lista.
Para remover um marcador: clique na ferramenta marcador ou pressione [M] para ativá-la (o cursor mudará para um marcador), e clique nas coordenadas do marcador na área de jogo; logo após, clique em Remover na janela de controles do marcador.
Para fechar os controles do marcador: clique no X do canto superior esquerdo da janela; ou clique em Cancelar; ou use o teclado.
{Dicas: as coordenadas da posição do cursor podem ser vistas no lado direito da barra inferior do jogo. Use [!] para mostrar/esconder o texto dos marcadores na área de jogo.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/station.txt000066400000000000000000000173661474050137200214460ustar00rootroot00000000000000Informações das Paradas

Informações das Paradas

As Paradas são os locais onde os veículos apanham e deixam passageiros ou cargas. A janela que se abre ao clicar em uma parada dá acesso a diversos detalhes da parada além de permitir mudar o seu nome.

Além de ser o local onde os veículos param, uma parada pode ser composta de extensões, que adicionam capacidade de armazenamento ou permitem que a parada aceite outros tipos de carga além dos originais.

As ferramentas para a construção de paradas estão disponíveis nas respectivas barras de cada tipo de transporte:
- plataformas de trem/comboio;
- plataformas de monotrilho;
- paradas de bonde/eléctrico;
- paradas de ônibus/autocarro ou caminhão/camião;
- docas;
- e aeroportos.
(Dicas: Veículos aquáticos podem usar qualquer quadro de água na área de captura de uma doca para pegar e deixar cargas e passageiros. Parada maiores podem ser construídas simplesmente adicionando mais quadros de parada. Uma parada pode aceitar mais de um tipo de veículo adicionando-se os quadros adequados nas vias próprias; ou seja, uma estação de trem pode ser colocada ao lado de uma parada de ônibus, desde que haja um trilho passando ao lado da rua onde está a parada.)

Clique numa parada na tela do jogo com a ferramenta Consultar ou numa parada listada naLista de paradas ou Gerenciador de Linhas para abrir as informações das paradas que mostra o nome da parada em sua barra de título.
A janela das paradas contém uma caixa de nome, uma vista da parada, informações sobre a parada, botões de opção e uma lista de todos os bens e passageiros prontos para serem transportados. Se não for possível ver todos os bens, ou todas as informações sobre eles, redimensione a janela da parada ou use as barras de rolagem para mostrar os itens:

Nome: O nome da parada é mostrado na caixa que fica em cima na janela de informações das Paradas.
Por padrão, um nome é atribuído automaticamente à parada quando ela é construída e depende da área urbana onde é inserida ou das indústrias próximas, dentro da área de captura da parada.
Para alterar o nome da parada, basta clicar na caixa do nome e escrever o novo nome da parada.
(dicas: Use [!] para alterar a visualização dos nomes das paradas sobre elas. Use [v] para alterar a visão da área de captura da parada. Opção para numerar as paradas está disponível no arquivo simuconf.tab [numbered_stops=])

Barra de estado Suas cores indicam a qualidade da operação da parada. Elas também são usadas na Lista das Paradas e no Gerenciador de Linhas, e são as mesmas exibidas acima da parada na tela do jogo:
- amarelo: parada sem atendimento; nenhum veículo a utiliza.
- verde: não é necessário melhorar o atendimento; a parada não lota.
- laranja: alguma melhoria é necessária.
- vermelho: é necessário melhorar o atendimento urgentemente.
(Dicas: Use [!] para alternar a visualização das barras de estado sobre as paradas na tela do jogo.)

Também há ícones que representam:
- carga(s) indicam quais itens são aceitos na parada: (passageiros, carga ou correio).
- veículo(s) indicam quais tipos de veículo podem usar a parada. Eles incluem: ônibus/autocarro, caminhão/camião, trem/comboio, barco/navio e avião. Bondes/eléctricos são ora representados pelo símbolo de ônibus/autocarro, ora pelo de trem/comboio, conforme o tipo original da parada.

Capacidade de armazenamento: o quanto de cada carga a parada pode acomodar.

Imagem da parada: uma visão da parada e quaisquer veículos visíveis.
Clique na imagem para centralizar a visão do jogo sobre a parada.

Passageiros os números indicam a quantidade de passageiros que querem iniciar sua viagem pela parada em foco:
- rosto feliz indica a quantidade de passageiros que chegaram à parada e encontraram-na sem estar lotada e encontram uma rota para o seu destino.
- rosto triste ou bravo indica a quantidade de passageiros que chegaram à parada, mas encontraram-na lotada, o que os fez desistir de viajar.
- sem caminho indica a quantidade de passageiros que chegaram à parada, mas não encontraram uma rota para chegar ao seu destino.
(Dicas: Manter os passageiros felizes ajuda a aumentar a população das cidades. É possível alterar o número máximo de transferências no arquivo simuconf.tab}.

Passageiros/mercadoria esperando: lista os itens que esperam por transporte na parada em grupos de: passageiros; correio; e tipo de mercadorias.
A informação mostrada de cada item inclui quantidade, tipo, destino final e primeira parada de transferência.
O botão de opções (que muda seu nome conforme se clica nele) organiza os itens das seguintes maneiras:
- destino: organiza os itens alfanumericamente, de acordo com a codificação ASCII (letra maiúsculas antes das minúsculas e estas, antes das acentuadas), pelo nome da parada do destino final.
- via (detalhe): organiza os itens alfanumericamente, de acordo com a codificação ASCII (letra maiúsculas antes das minúsculas e estas, antes das acentuadas), pelo nome da primeira parada de transferência.
- via (quantidade): organiza os itens pela quantidade que vai ser transferida numa parada imediatamente posterior.
- quantidade: organiza por ordem decrescente da quantidade do item em espera.
(Dicas: as barras coloridas sobre uma parada indicam a quantidade de mercadoria ou de passageiros esperando para ser transportada e são as mesmas que se vê na Lista das cargas.)

Gráfico: Clique no botão para acionar os gráficos da janela de Informações da Parada (quando a área do gráfico está visível, o botão fica afundado).
O gráfico mostra estatísticas para os últimos 12 meses (eixo horizontal) para o(s) dado(s) selecionado(s).
As cores das linha do gráfico correspondem às dos botões sobre ele:
- Contentes indica a quantidade de passageiros que chegaram à parada e encontraram-na sem estar lotada e encontram uma rota para o seu destino.
- Descontentes indica a quantidade de passageiros que chegaram à parada, mas encontraram-na lotada, o que os fez desistir de viajar.
- Sem rota indica a quantidade de passageiros que chegaram à parada, mas não encontraram uma rota para chegar ao seu destino.
- Espera: quantidade de passageiros e mercadorias à espera de transporte.
- Chegados: quantidade de passageiros e mercadorias que chegaram à parada através de veículos, não pela área de captura.
- Saídos: quantidade de passageiros e mercadorias que saíram da parada através de veículos.
- Veículos: quantidade de veículos que partiram da parada.

Detalhes: botão que abre a janela de Detalhes da Parada que fornece outras características da parada, não disponíveis na janela principal.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008, atualizado em 07/02/2008.

simutrans-124.3/simutrans/text/pt/station_details.txt000066400000000000000000000033441474050137200231420ustar00rootroot00000000000000Detalhes da Parada

Detalhes da Parada

A janela Detalhes da Parada providencia mais informações sobre a estação/parada (onde veículos recolhem e entregam mercadorias e passageiros).

A janela Detalhes da Parada abre do botão Detalhes na janela de Informações das Paradas.
Se todos os itens não estiverem visíveis redimensione a janela Detalhes da Parada ou use as barras de rolagem para percorrer os itens.

As informações listadas incluem:
Indústrias conectadas: nomes e coordenadas no mapa (em parênteses) das indústrias na área de captura da parada.
{Dica: use [v] para mostrar/exibir a área de captura de uma parada.}

Indústrias próximas precisam: lista as mercadorias requeridas pelas indústrias na área de captura da parada.

Linhas que servem esta parada: mostra as linhas que usam a parada.
Linhas são listadas pela ordem do código ASCII (letras maiúsculas antes de minúsculas).

Paradas conectadas diretamente: lista o nome das paradas que podem ser alcançadas e o tipo de itens (mercadorias e passageiros) que podem ser entregues.
Paradas são listadas pela ordem do código ASCII (letras maiúsculas antes de minúsculas) pelo tipo de transporte, nome da parada, e tipo de item que pode ser entregue (que também é mostrado por cada parada).

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/trafficlight_info.txt000066400000000000000000000004221474050137200234270ustar00rootroot00000000000000Semáforo

Semáforo

Você pode controlar a freqüência de fases vermelhas e verdes dos semáforos. Os números que você pode escolher aqui são a duração da fase verde em segundos para direções norte/sul e leste/oeste.

simutrans-124.3/simutrans/text/pt/tramtools.txt000066400000000000000000000220111474050137200217700ustar00rootroot00000000000000Ajuda - Bondes

Bondes

As ferramentas para Bondes constróem uma rede de transporte por bondes. Elas podem construir trilhos para bondes (e eletrificá-los ou removê-los), sinais, depósitos e paradas. Se você estiver jogando com linha do tempo, então conforme o tempo passa no Simutrans mais opções de ferramentas podem aparecer.

Clique no ícone de um bonde no topo da área de jogo para abrir a barra de ferramentas.
Passe o cursor do mouse em cima das opções (após ter aberto ou clicado na barra de ferramentas) para ver o nome, o custo de construção e o limite máximo de velocidade.

As ferramentas para Bondes incluem, da esquerda para a direita:

Trilho de bonde: constrói trilhos de bondes, para veículos de linha férrea entre dois pontos.
Trilhos de bonde podem ser construídos por cima das estradas e em áreas urbanas, mas não em áreas ocupadas por outros edifícios. Trilhos podem ser construídos em declives somente na direção dos mesmos e não podem ser construídos em terreno acidentado, sobre a água ou obstáculos. O novo trilho construído pode usar outros trilhos existentes em seu caminho.
Para construir um trilho: clique na ferramenta para ativá-la (o cursor mudará para um trilho), e clique na área de jogo no ponto inicial do trilho (mostra um trator na área de jogo e as coordenadas do mapa no lado direito da barra inferior do jogo), e finalmente clique na área de jogo no ponto final para o trilho.
{Dicas: tipos diferentes de trilhos podem se conectar (porém não quando construídos por jogadores diferentes). Use pontes e túneis para conectar trilhos através de terreno acidentado ou para desviar de obstáculos. Use a ferramenta Remover para remover pedaços individuais dos trilhos e algumas obstruções. Use [Ctrl] ao mesmo tempo para funções extra. O desfazer [z] não reembolsa os custos da construção.}

Rede aérea de força: ferramentas para eletrificar trilhos, pontes ou túneis entre dois pontos na área de jogo, para o uso de veículos elétricos.
Para eletrificar os trilhos: clique na ferramenta ou pressione [e] (o cursor mudará para um trilho eletrificado) para ativá-la, e clique no trilho no ponto de início da eletrificação (um ícone de rede aérea se fixa marcando o ponto), e finalmente clique em um segundo ponto do trilho, para eletrificar o trecho desde o ponto inicial selecionado.
{Dica: use a ferramenta Remover para voltar a usar trilhos não-eletrificados.}

Remover trecho de trilhos: remove trilhos (eletrificados ou não), quando não houver veículos presentes, entre dois pontos na área de jogo (plataformas de estações, paradas em estradas, sinais, túneis e pontes do caminho são removidos também). O uso da ferramenta tem um custo de construção.
Para remover um trecho de trilhos: clique na ferramenta para ativá-la (o cursor mudará para um X vermelho), e clique no trilho que será removido (o ponto selecionado é marcado por um X vermelho na área de jogo), e finalmente clique no segundo ponto em um trilho conectado, para remover o trecho de trilhos desde o ponto inicial selecionado.
{Dica: jogue como outro jogador para remover seus trilhos.}

Sinais: coloca sinais para os veículos em um trilho na área de jogo. Sinais regulam e direcionam o fluxo de veículos em trilhos, pontes, cruzamentos e estações (onde veículos recolhem e entregam mercadorias e passageiros).
Podem ser construídos sinais para vias de mão dupla ou mão única. Para construir um sinal de mão dupla nos trilhos: clique na ferramenta para ativá-la (o cursor mudará para um sinal), e clique no trilho. Para construir um sinal de mão única: clique novamente no mesmo ponto, com o cursor em forma de sinal, para alternar entre os sinais de cada lado da via, e de volta para um sinal de mão dupla.
IMPORTANTE: tome cuidado para não colocar sinais de mão única que impeçam os veículos de chegar a seu destino, por padrão os veículos andam à direita (pode ser mudado no arquivo simuconf.tab).
- Sinais: veículos prosseguem somente se o trecho de trilho até o próximo sinal ou destino na Programação (uma estação ou ponto de passagem) não estiver ocupado por outro veículo. Em sinais de mão única veículos passam em apenas uma direção.
- Sentido único: veículos não prosseguem além do sinal (disponível somente em sinais de mão única).
- PreSignals: veículos prosseguem se o trecho de trilho à frente (qualquer entre três sinais consecutivos ou para o próximo destino na Programação) não estiver ocupado por outro veículo. Em sinais de mão única eles permitem que veículos trafeguem em somente uma direção.
- Direcionador ferroviário para vaga livre: direciona veículos para uma plataforma livre da estação, em uma estação com múltiplas plataformas: um veículo passando este sinal pode usar qualquer plataforma livre até seu próximo destino, e não somente aquela descrita em sua Programação. Se não houver plataforma livre ou caminho livre até o próximo destino, o veículo esperará no sinal.
{Dicas: remova os sinais com a ferramenta Remover. Mantenha pressionada a tecla [Ctrl] para colocar sinais em pontes acima de outros trilhos.}

Construir depósito de bonde: constrói um depósito para a compra e o gerenciamento de bondes.
Depósitos possuem um custo de manutenção e são construídos em fins de trilhos na área de jogo.
Para construir um depósito de bonde: clique na ferramenta para ativá-la (o cursor mudará para um depósito), e clique no fim de um trilho.
{Dicas: depósitos somente mostrarão veículos elétricos se estiverem em um trilho eletrificado. Remova os depósitos com a ferramenta Remover.}

Paradas de bonde em ferrovias: constróem plataformas de estação, usadas por veículos ferroviários para recolher e entregar mercadorias, passageiros e correio.
Uma plataforma de estação quando não for construída adjacente a uma parada existente, criará uma nova estação.
Paradas em ferrovias possuem um custo de manutenção e são construídos em trilhos (menos em curvas e cruzamentos de ferrovias).
Elas possuem uma área de captura para mercadorias, passageiros e correio. Plataformas diferentes podem ter diferentes capacidades para passageiros e correio. No canto superior de algumas opções um ícone (usado na Lista de Paradas e Informações das paradas) mostra quais itens a plataforma permite à estação receber.
Para construir uma plataforma: clique na ferramenta para ativá-la (o cursor mudará para uma plataforma), e clique no trilho.
{Dicas: remova as paradas com a ferramenta Remover. Estenda as plataformas de estação e construa estações maiores (construindo mais seções de plataformas nos trilhos adjacentes) para acomodar veículos longos, bem como maior quantidade deles, aumentar a capacidade e a área de captura da estação. Pressione [v] para mostrar/esconder a área de captura da estação. Mantenha pressionada a tecla [Ctrl] para construir em pontes acima de outros trilhos.}

Estacionamento: (disponível somente no pak128) constrói extensões para estações que aumentam a capacidade e a área de captura para mercadorias e passageiros, e o custo de manutenção.
Para construir uma extensão: clique na ferramenta para ativá-la (o cursor mudará para uma extensão), e clique na posição desejada em uma estrada, ao lado de uma estação existente. A nova extensão agora fará parte da estação.
{Dica: remova extensões com a ferramenta Remover.}

Paradas de bonde em estradas: constróem pontos onde bondes e veículos de estrada possam recolher e entregar mercadoria, correio e passageiros.
Uma parada em estrada, quando não for construída adjacente a uma parada existente, criará uma nova parada. Elas são construídas em estradas e possuem um custo de manutenção e uma área de captura para mercadorias, passageiros e correio. No canto superior de algumas opções um ícone (usado na Lista de paradas e Informações das paradas) mostra quais itens a plataforma permite à estação receber. Diferentes paradas podem ter diferentes capacidades para mercadorias, passageiros e correio.
Para construir uma parada de bonde em estrada: clique na ferramenta para ativá-la (o cursor mudará para uma estação), e clique no local desejado da estrada na área de jogo.
{Dicas: remova as paradas com a ferramenta Remover. Mantenha pressionada a tecla [Ctrl] para construir em pontes acima de outras estradas.}

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 17/01/2008.

simutrans-124.3/simutrans/text/pt/window.txt000066400000000000000000000125621474050137200212650ustar00rootroot00000000000000Ajuda - Interface/Janela do Jogo

Interface/Janela do Jogo

O Simutrans é jogado através da Interface/Janela do Jogo, que fornece informações sobre o jogo atual; acesso às barras de ferramentas e controles do jogo, e uma visão do jogo atual.

Barra de título: o lado esquerdo da barra de título da Interface/Janela do Jogo mostra a versão e a data de lançamento do Simutrans que está sendo jogado no momento.
O lado direito da barra de título oferece controles para minimizar, maximizar a Interface/Janela do Jogo e também para sair do Simutrans.

Ícones: uma fileira de ícones, utilizada para acessar as barras de ferramentas e os controles do jogo enquanto ele está sendo jogado, está diretamente abaixo da barra de título. Os ícones (clique para usar) estão agrupados em três conjuntos:

- Os ícones do Menu Principal incluem:
- Disquete: abre as Preferências
- Mapa: abre o Mapa
- Lupa seleciona a Ferramenta Consultar
- Barranco: abre o Editor de terrenos
- Locomotiva: abre a barra de ferramentas Ferrovias
- Monotrilho/Maglev: barra de ferramentas Monotrilhos e Maglevs
- Bonde: abre a barra de ferramentas Bondes
- Caminhão: abre a barra de ferramentas Estradas
- Barco: abre a barra de ferramentas Navegação
- Avião: abre a barra de ferramentas Aeroportos
- Círculo amarelo com uma bola vermelha dentro (um guindaste no pak128): abre a barra de Ferramentas Especiais
- X vermelho (um trator no pak128): seleciona a ferramenta Remover

- Os ícones do Menu de Gerenciamento incluem:
- Rede de transportes: abre o Gerenciador de Linhas
- Lista: abre as Listas
- Caixa de correio: abre as Mensagens
- Cédula de dinheiro: abre as Finanças

- Os ícones das Outras Opções incluem:
- Câmera fotográfica: captura uma imagem do que está acontecendo no momento na Interface/Janela do Jogo (sem a barra de título) e salva a imagem como um arquivo bitmap (.bmp) na pasta ...simutrans/screenshot/
{Dica: as imagens também podem ser capturadas pressionando a tecla [c].}
- Duas barras verticais amarelas: pausa/volta ao jogo .
{Dica: Pressionando-se [p] também pausa/volta ao jogo}.
- ícone >>: ativa/desativa a função Avanço Rápido (muda a velocidade com a qual o Tempo, T, passa no jogo).
{Dica: A função Avanço Rápido também pode ser ativada/desativada pressionando-se [W]
IMPORTANTE: O jogo pode não rodar perfeitamente; a janela Vídeo, acessível a partir de Preferências, indica se o computador aceita essa função sem problemas.}
- ?: abre a Ajuda do jogo.

A visão do jogo de uma porção do mundo (jogo) atual é mostrada abaixo dos Ícones.
Você pode aumentar ou diminuir o zoom na visão do jogo e também visualizar as outras partes do mundo atual usando o mouse ou o teclado.

Uma barra deslizante temporária aparece e mostra mensagens na parte inferior da visão do jogo.
{Dica: Clique em uma mensagem para centralizar a visão do jogo para a posição informada na mensagem.}

Uma barra inferior a qual mostra informações sobre o jogo atual é mostrada na visão do jogo.
A informação fornecida, da esquerda para a direita na barra inferior inclui:
- Data e hora: a data e hora atuais do jogo carregado, seguido por um ícone e o nome da estação.
- Caixa atual: o dinheiro atualmente disponível para construção e outros custos (compra de veículos, manutenção da infra-estrutura para transportes e custos operacionais para os veículos que estão em funcionamento).
- Coordenadas: indica a posição do cursor do mouse na visão do jogo. Os números representam as coordenadas X, Y, e a altitude.
- T: indica a velocidade com a qual o tempo passa no jogo.
{Dica: Pressione [.] / [,] para acelerar/desacelerar o Tempo, (T); o menu Vídeo indica se o computador suporta esta mudança.
O uso da função Avanço substitui T por ">>" na barra inferior.}
- Linha do tempo: indica se a Linha do tempo foi ativada para o jogo atual.

Traduzido pela Equipe de tradução do Simutrans PT-SubFórum (http://pt.simutrans.com), 16/02/2008.

simutrans-124.3/simutrans/text/readme_citylist.txt000066400000000000000000000022501474050137200225050ustar00rootroot00000000000000 Simutrans city name generation help ----------------------------------- Simutrans can create city names two ways: 1) If there is a citylist_xx.txt file for the chosen language city names are read from this file. 2) Otherwise random city names are created from the syllables given in xx.tab Currently there is only one citylist per language used. I.e. for english, citylist_en.txt is used. A citylist in pak/text/ will overlay a citylist in text/. So different scenarios can have different citylists. But there are some additional citylist files supplied, i.e. citylist_en_au.txt for australian city names and citylist_de_at.tx for austrian city names. You can copy the citylist either in the folder text/ or to your pak-files e.g. pak/text/. To use them, you need to rename the files. I.e. to use the austrian city names, rename citylist_de.txt to citylist_de_de.txt and rename citylist_de_at.txt to citylist_de.tx If you don't want Simutrans to use the city name lists, delete them. Simutrans will then use the old (pre 0.82.15.5exp) scheme of random city names. written by Hansjörg Malthaner, 07-Dec-03 change by Markus Pristovsek, 14-Jan-04 simutrans-124.3/simutrans/text/ro.tab000066400000000000000000000630721474050137200177040ustar00rootroot00000000000000§Romana PROP_FONT_FILE prop-latin2.fnt ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: ro Romana # # Encoding: UTF-8 # # Font: prop-latin2.fnt # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable dezactivat cl_btn_filter_enable activat cl_btn_filter_settings Setari cl_btn_sort_asc crescator cl_btn_sort_desc descrescator cl_btn_sort_id ID intern cl_btn_sort_income Venit cl_btn_sort_name Nume cl_btn_sort_type Tip clf_btn_alle tot clf_btn_invers inv. clf_btn_keine nimic gl_btn_sort_bonus Bonus gl_btn_sort_name Nume gl_btn_sort_revenue Venit gl_btn_unsort Nesortat hl_btn_filter_disable dezactivat hl_btn_filter_enable activat hl_btn_filter_settings Setari hl_btn_sort_asc crescator hl_btn_sort_desc descrescator hl_btn_sort_name Nume hl_btn_sort_type Tip hl_btn_sort_waiting Asteapta hlf_btn_alle tot hlf_btn_invers inv. hlf_btn_keine nimic #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic clima arctica desert clima desertica mediterran clima mediteraneana rocky clima alpina temperate clima temperata tropic clima tropicala #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Cannot built depot here! Nu pot construi depou aici. Cannot built this station/building\nin underground mode here. Cladirea nu poate fi\nconstruita sub pamant.\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Nu pot creea linie generica!\nAlege tipul de linie\nfolosind filtre. Cannot create socket Nu pot creea socket Convoi handles exhausted! Numar maxim de convoaie atins. Das Feld gehoert\neinem anderen Spieler\n Aceasta parte a insulei\neste detinuta de\nun alt jucator!\n Der Besitzer erlaubt das Entfernen nicht \nNu ai permsiunea!\n Diese Zusammenstellung kann nicht fahren!\n Combinatia\nnu functioneaza!\n Flugzeughalt muss auf\nRunway liegen!\n Trebuie sa fie\n pe taxiway. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Nu poti construi\n\naeroport aici.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Aici nu se poate\nconstrui semafor!\n Lost connection\nto server! Nu exista! Lost synchronisation\nwith server. Nu exista! Maglevhalt muss auf\nMaglevschiene liegen!\n Un semafor maglev trebuie plasat pe linie maglev! Monorailhalt muss auf\nMonorail liegen!\n Statiile monorail trebuie\npuse pe linii monorail. Monorails are not available yet! Linie monorail indisponibila. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n acest stop trebuie construit pe linia specifica No through station here! Statiile trebuie plasate la capatul liniilor sau pe sectiuni in line dreapta. Not enough money! Nu ai suficienti bani\npentru a construi! On narrowgauge track only!\n Doar pe ecartament ingust!\n Post muss neben\nHaltestelle\nliegen!\n Extensia (posta, depozit)\n trebuie plasat pe loc liber\nlanga o statie existenta.\n Protocoll error (expecting game) Eroare protocol (ceva s-a stricat) Schiffhalt muss im\nWasser liegen!\n O nava poate fi\n plasata doar inapa\nlanga un doc!\n Terraforming not possible\nhere in underground view Teraformarea imposibila sub pamant. Upgrade must have\na higher level Upgrade-ul se face\ndoar cu un nivel in plus. Zughalt muss auf\nSchiene liegen!\n Statiile trebuiesc\npuse pe\nsina normala.\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Keyboard Help\n

Keyboard Help

\n Ajutor tastatura\n

Ajutor tastatura

\n

\nAjutor tastatura arata diferitele actiuni peare le poti face folosindu-te de taste.\n

\n

\nAjutor tastatura se deschide cand este apasata o tasta fara corespondenta sau din Ajutor general.\n

\n

\nScurtaturile (shortcuts) sunt case-sensitive (foloseste [Shift] pentru litere mari).\n

\n

\nFunctiile incluse contin:\n

\n

\n[Sageti]: muta camera in directia dorita.
\n[Backspace]: inchide toate ferestrele, texte ajutor si meniuri.
\n[Delete] sau [Escape]: inchide fereastra de sus, meniu sau text ajutor .
\n[Enter] sau [Return]: folosit pentru a confirma actiuni.
\n[Page-Up] sau [>]: magnificare.
\n[Page-Down] sau ["<"]: zoom-out.\n[F1]: deschide Ajutor general.

\n

\n[1]: scroll game-view south-wards.
\n[2]: scroll game-view south-east-wards.
\n[3]: scroll game-view east-wards.
\n[4]: scroll game-view south-west-wards.
\n[6]: scroll game-view north-east-wards.
\n[7]: scroll game-view west-wards.
\n[8]: scroll game-view north-west-wards.
\n[9]: scroll game-view north-wards.\n

\n

\n[Shift] + mouse: used on Map to see links in Industry Supply Chain.
\n[CTRL] + tool: construct (signals & Stops) on upper level; or build slower roads and tracks over faster ones; or build straighter (more direct) roads and tracks.
\n[CTRL] + ([F2] to [F12]): sets select current tool to keypresses [F2] to [F12].\n

\n

#____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s acum\noofera transport autobuz\nintre %s\nsi atractia\n%s\n la (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s acum\nofera transport autobuz\nintre %s\nsi fabrica\n%s\nla (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nopereaza acum\n%i camioane\n%s intre (%i,%i)\nsi %s\nla (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\na deschis o noua linie\nintre %s\nla (%i,%i) si\n%s\nla (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Transport aerian\n%s\nacum intre\n%s \nsi %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Bac oferit de\n%s acum intre\n%s \nsi %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\ndeschide un nou sistem\nde transport intre\n%s si\n%s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Unelte editare harta LISTTOOLS Liste MAGLEVTOOLS Unelte maglev MONORAILTOOLS Unelte monorail/maglev NARROWGAUGETOOLS Unelte ecartament ingust RAILTOOLS Unelte trenuri ROADTOOLS Unelte automobile SHIPTOOLS Unelte nave SLOPETOOLS Unelte pamant SPECIALTOOLS Unelte speciale TRAMTOOLS Unelte tramvai #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s's a construit un nou sediu. Factory chain extended\nfor %s near\n%s built with\n%i factories. Economie puternica:\n%s aproape de %s se extinde.\n%i are o fabrica noua. New %s now available:\n%s\n Noi %s acum disponibil:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. Crestere: Nou lant industrial\npentru %s langa\n%s, constructie cu \n%i fabrici. New vehicle now available:\n%s\n \n Un nou vehicol este\nacum disponibil:\n\n\n -- %s --\n\n Screenshot\ngespeichert.\n Imaginea \ns-a salvat.\n Sends the convoi to the last depot it departed from! Vehicolul este trimis în depoul de unde provine! #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (in depou) \nBauzeit bis pana \nBauzeit von \nApare din \nCan't open heightfield file.\n \nRelieful nu poate fi deschis.\n \ndirection: \ndirectii: \nelektrified \nelectrificat\n \nHeightfield has wrong image type.\n \nRelieful con?ine imagini\nincompatibile.\n \nnot elektrified \nneelectrificata\n %d convois %d convoi %d Einzelfahrzeuge im Depot %d sunt %s has entered a depot. %s a intrat in depou. %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s \na construit o\n noua primarie\n cand a ajuns la\n%i locuitori. 1 Einzelfahrzeug im Depot 1 vehicol 1LIGHT_CHOOSE Luminozitate: 1WORLD_CHOOSE Setari pentru joc nou: 2LIGHT_CHOOSE Nr. de culori: 2WORLD_CHOOSE Numar harta: 3LIGHT_CHOOSE Viteza de scrol: 4LIGHT_CHOOSE Scrol invers 5LIGHT_CHOOSE Pietoni in statii 5WORLD_CHOOSE Nr. de orase: 6LIGHT_CHOOSE Pietoni in orase 6WORLD_CHOOSE Densit. traficului: 8WORLD_CHOOSE Mod zi/noapte A bridge must start on a way! Nu detii capetele podului sau acestea sunt obstructionate. Abfrage Unealta informatii Abnehmer Consumator About Despre Abriss Distruge/Sterge Absenken Coboara nivel Accelerate time Accelereaza timpul Active player only Doar jucător activ Add forest Adaugă pădure Add random citycar Adaugă ma?ină de ora? aleator Add Stop Adaugă Stop Add stops for backward travel Adaugă stopuri pentru circula?ie inversă air pistă aircraft_tab Avioane de transport airplane avion Airport Aeroport AIRTOOLS Unelte Aeroport All Tot all convoi tooltips toate uneltele pentru convoi Allow city growth Permite dezvoltarea orasului Allow player change Permite schimbarea jucatorului allowed climates:\n permite clime Alters a schedule. Adauga/sterge opriri in/din program Angenommene Waren Nevoile uzinelor adiacente anhaengen Adauga Anhaenger_tab Remorci Anheben Ridica nivel Appends stops at the end of the schedule Adauga opriri la finalul programului Apply Line Aplica linie April Aprilie Arbeiter aus: Muncitorii traiesc in Arrived Sosit Assets Bunuri Aufloesen Dezansambleaza Autohalt muss auf\nStrasse liegen!\n Statiile trebuie\npuse pe drum. Available Disponibil Bahndepot Depou trenuri Bankrott:\n\nDu bist bankrott.\n Faliment:\n\nAi dat faliment!\n battery Baterie Baum Copac baum builder Planteaza copaci Baustelle Santier Bauzeit timp constructie Beenden Terminare joc Beginner mode Mod Incepator Besonderes Gebaeude Atractii turistice BF statie bio biologic Blockstrecke ist\nbelegt\n \nBlocaj folosit\nde un alt tren!\n Boden Uscat bridge is too high for its type! Podul este prea inalt! Bridge is too long for this type!\n Podul este prea lung. Bruecke Pod Bruecke muss an\neinfachem\nHang beginnen!\n Podurile incep\npe zona plata!\n Brueckenboden pod Build air depot Construieste hangar build choosesignals Contruieste platforma alege semnale Build city market Construieste piata in cel mai apropiat oras. Build drain Transformator build HQ Construieste sediu Build land consumer Construieste centrala electrica Build maglev depot Construieste depou maglev Build monorail depot Depou monorail Build narrowgauge depot Depou linie-ingusta Build powerline Statie transformator Build presignals Semnal dublu Build road depot Garaj Build ship depot Port Build signals Semnale Build train depot Depou tren Build tram depot Depou tramvai Build truck depot Garaj Building costs estimates Cost estimativ Buildings Numar cladiri Built artifical slopes Panta artificiala Built random attraction Atractie aleatoare Bus_tab Autobuze Can only move from halt to halt or waypoint to waypoint. Poti muta doar \ndin halta in halta sau \nde de la waypoint la waypoint. Cancel Anuleaza Capacity: %d%s %s\n Capacitate: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Capacitate: %s\n? %d (%d%%) Cars are not available yet! Masinile nu sunt inca disponibile cars.\nstate masini\n Cash Balanta cont Change player Schimba jucator Chart Grafic Choose direction Alege directie Choose operation executed on clicking stored/new vehicles Alege mod pentru vehicole noi/in garaj chooses a random map Alege o harta aleatoare. citicens Cetateni City attraction Atractii oras City industries Piete in oras City list Lista orase City size Dimensiune oras city_road Drum orasenesc citybuilding builder Cladiri urbane CityLimit Limite oras cl_title Lista vehicole cl_txt_sort Sorteaza dupa: Clear block reservation Arata/reseteaza cai rezervate clf_chk_aircrafts Avioane clf_chk_cars Autobuze/Camioane clf_chk_indepot intr-un depou clf_chk_maglev Maglev-uri clf_chk_monorail Monorail-uri clf_chk_name_filter Nume filtre: clf_chk_narrowgauge Trenuri ecartament mic clf_chk_noincome venit zero clf_chk_noline nicio linie clf_chk_noroute nicio ruta clf_chk_noschedule niciun program clf_chk_ships Nave clf_chk_spezial_filter Filtru special: clf_chk_stucked blocat clf_chk_trains Trenuri clf_chk_trams Tramvaie clf_chk_type_filter Tip filtru: clf_chk_waren Filtru bunuri: clf_title Filtru vehicole Climate Control Control clima closed oprit. COLOR_CHOOSE\n Alege culoarea:\n Company bankrupt Companie falimentara Congratulation\nScenario was complete in\n%i months %i years. Felicitari!\nScenariul a fost\nterminat in\n%i luni si %i ani! Connected stops Conecteaza statii Constructed by Pictat de Constructed by %s Pictat de %s Construction_Btn Costuri constructii convoi %d of %d convoi din %d %d convoi error tooltips ajutor erori convoi Convoi has been sent\nto the nearest depot\nof appropriate type.\n Convoiul a fost trimis\nin depoul cel mai\napropiat.\n Convoi is sold when all wagons are empty. Vehicolul va fi vandut imediat ce va fi descarcat. convoi mouseover tooltips ajutor convoi mouseover convoi passed last\nmonth %i\n \nconvoaie in ultima\nluna: %i\n Convois Convoaie Convois: %d\nProfit: %s Vehicole: %d\nProfit: %s Convoys Convoaie Copy Convoi Duplicare convoi Copy the selected convoi and its schedule or line Copiaza convoiul si programul/linia aferenta cost for removal Cost eliminare Costs Costuri Create a new line based on this schedule Creeaza linie noua dupa acest program curiosity builder Constructie curiozitate curlist_title Lista atractii Currently playing: Joaca: Deccelerate time Decelereaza timp December Decembrie decrease underground view level nivel superior Del Stop Elimina Delete Line Sterge linie Delete the current stop Sterge stop Delete this file. Sterge fila. Denkmal Monument Departed Plecat Depots Depouri Der Tunnel ist nicht frei!\n Tunelul nu este liber.\n Destination Sosiri Details Detalii Die Bruecke ist nicht frei!\n Podul nu este liber!\n Direkt erreichbare Haltestellen Traseu direct de aici disable midi Opreste muzica MIDI Display settings Setare monitor Distance Distanta Dock Doc Dock must be built on single slope! Docurile pot fi construite doar pe o panta. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Ai %d luni sa platesti datoria. Durchsatz Max. Economy Economie si orase Eigenbesitz\n Proprietate publica\n Ein %s\npasst hier nicht.\n '%s'\nnu se potriveste aici!\n Einstellungen aendern Schimba optiuni Electricity Electricitate Electricity producer\n\n Producator electricitate\n\n Electrics_tab Electrice Electrify track Electrifica linia enlarge map Mareste harta enter a value between %i and %i introdu o valoarea intre %i si %i Error Eroare Erzeuge neue Karte.\n Te rog asteapta pana cand\n noua harta este creata.\n\n(S-ar putea sa dureze\nceva timp pt. harti imense)\n Es wird bereits\nein Fahrplan\neingegeben\n Lucrezi deja la\nun program.\nTermina-l inainte de a\nincepe unul nou.\n Fabrikanschluss Uzine conectate Fabrikname nume fabrica Factories Fabrici factory details Legaturi fabrica factorybuilder Constructor fabrica Fahrplan Program Fahrtziel Destinatie: Fahrzeuge koennen so nicht entfernt werden Vehicolele nu pot\nfi eliminate asa!\n Fahrzeuge: Vehicole Farbe Culoare jucator Fast forward Accelerare timp February Februarie Ferry_tab Bacuri Fertig Gata Filename Nume fisier: Filter: Filtru: Finances of %s Finantele %s Finanzen Finante fl_title lista fabrici Flug_tab Avion pasageri follow me Urmareste-ma. Follow the convoi on the map. Urmareste acest convoi pe harta. Forest Padure Found new city cladeste oras nou Fracht Marfa Frame time: Timp frame: Free Capacity Spatiu ramas freeplay mode joc liber Friction: indice frecare: fuel_cell combustibil Full load Incarcatura minima: Fussgaenger Pieton GAME PAUSED Pus pe pauza Gear: Viteza: Gebaeude Cladire Gewicht Greutate Gewinn Venit: Give the selected vehicle(s) an individual schedule Da vehicolului selectat un program. gl_btn_sort_catg Categorie gl_title Lista bunuri go home La depou. Goods Bunuri Goods AI Bunuri AI Goods list Lista bunuri Gross Profit Flux bani Groundobj Obiect Grow city Creste oras. Growth Crestere oras H stop Happy Bucuros Haus kaufen Cumpara casa Helligk. Monitor Help Ajutor Help text not found Nu exista text ajutor. hide all building ascunde toate cladirile hide city building ascunde toate cladirile hide station names ascunde nume statii hide transparent transparent in loc de ascuns hide trees Ascunde copacii Hier warten/lagern: Bunuri si pasageri care asteapta: hl_title Lista statii hl_txt_filter Filtru: hl_txt_sort Sortat dupa: hlf_chk_airport Aeroporturi hlf_chk_anleger Doc hlf_chk_bahnhof Statie tren hlf_chk_bushalt Statie autobuz hlf_chk_frachthof Depou hlf_chk_keine_verb Nicio legatura hlf_chk_maglevstop Statie Maglev hlf_chk_monorailstop Statie Monorail hlf_chk_name_filter Nume filtru: hlf_chk_narrowgaugestop Statie ecartament ingust hlf_chk_overflow Peste capacitate hlf_chk_spezial_filter Filtru special: hlf_chk_tramstop Statie tramvai hlf_chk_type_filter Tip filtru: hlf_chk_waren_abgabe Bunuri iesite: hlf_chk_waren_annahme Bunuri primite: hlf_title Filtru lista statii Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depou inexistent!\nDepoul trebuie desemnat\nmanual. Homeless Cersetor hydrogene Hidrogen Idle: Inactiv: ignore climates ignora clime Increase Industry density Mareste densitate industrii increase underground view level nivel suplimentar industrial building Cladiri industriale Init map ... Creez harta ... Input input Ins Stop Insereaza Insert stop before the current stop Adauga stop inainte Intercity road len: Lungime drum intercity: Intro. date: Intro. data: invalid nedefinit Invalid coordinate Ordin invalid isometric map Vedere izometrica January Ianuarie July Iulie Jump to Sari la June Iunie Kann Spielstand\nnicht laden.\n Nu pot incarca salvarile! Kann Spielstand\nnicht speichern.\n Nu pot deschide\n fila pentru\n scriere! Kein Besitzer\n Fara proprietar\n keine nimic Keine Einzelfahrzeuge im Depot Niciun vehicol aici. Keyboard_Help\n Ajutor tastatura\n koord coordonate Kreuzung Intersectie labellist_title Lista markere Lade Relief Incarca height map Laden Incarca Land attraction Atractie Land industries Lanturi industriale: LANG_CHOOSE\n Alege limba:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE Ie6 Last Year Anul trecut: Leaving depot! Paraseste depoul! leer gol Legend Legenda harta Leistung Putere Leistung: %d kW Putere: %d kW Leitung Linie electrica letzen Monat: diesen Monat: luna trecuta: luna curenta: Line Traseu Line Management Management trasee Lines serving this stop Trasee pentru aceasta oprire LKW_tab Camioane Load game Incarca joc load height data from file Incarca inaltime din fisier. Load scenario Incarca scenariu loaded incarcat loaded passenger/freight Sorteaza pasageri/marfa dupa Loading (%i->%i%%)! Se incarca (%i->%i%%) Loading addon paks ... Incarc pakuri suplimentare ... Loading map ... Incarc harta ... Loading paks ... Incarc pakuri ... Loading skins ... Incarc skinuri ... Lock game Refuza schimbarile jucatorului (necesita confirmare). Lokomotive_tab Locomotive m3 mÂ? maglev vehicle vehicol maglev maglev_track sina maglev Maglevdepot depou maglev Mailbox Centru mesaje Mailbox Options Optiuni centru mesaje Maintenance Mentenanta make stop public (or join with public stop next) costs %i per tile and level fa statia publica (sau conecteaza la cele adiacente publice) costuri %i$ pe dala si nivel Manual (Human) Manual (Uman) Manufactured: Fabricat: Map roughness Dificultate teren: map zoom zoom March Martie Margin (%%) Margine Marker Indicator Max income: Venit maxim: Max. speed: Viteza max.: Maximum 254 stops\nin a schedule!\n Maxim 254 statii\nintr-un program!\n maximum length of rivers Lungima maxima Maximum tile height difference reached. Diferenta maxima\n intre doua dale\n a fost atinsa. May Mai Median Citizen per town Numar mediu de locuitori: Meldung Mesaj Menge cantitate MessageOptionsText \nAn nou\n\nStiri AI\n\nStiri Oras\n\nNicio ruta\n\nIndustrii noi\n\n"chat"\n\nMasini noi\n\nStatii pline\n\nProbleme\n\nAvertizari\n\nScenario min min. minimum length of rivers Lungime minima Modify the selected line Modifica traseul Monate alt luni vechime. monorail vehicle vehicol monorail monorail_track Sina monorail Monorailboden Cale elevata Monoraildepot Depou monorail month wait time luni de asteptare Months Luni Monuments Monumente Mountain height Inaltime munte Movingobj mutare obiect Music playing disabled/not available Muzica dezactivata/inexistenta. Music volume: Volum muzica: mute sound Mut Name Nume Narrowgauge Ecartament ingust Narrowgauge are not available yet! Indisponibil momentan! narrowgauge vehicle vehicol ecartament ingust narrowgauge_track linie ecartament ingust Narrowgaugedepot depou ecartament ingust Net Wealth Avere Neue Karte Harta noua Neue Welt Creeaza un joc nou new convoi Convoi nou New Line Traseu nou New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Traseul nou este gata!\nAtribuirea se face cu\nselectorul de traseu.\n New Vehicles Vehicol nou no buildings hidden nicio cladire ascunsa no convois nu este conv. No goods are loaded onto this convoi. Acest convoi nu va fi incarcat no tree fara copaci Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "Unde ma duc?"\nTrebuie sa-i dai convoiului un program sau o linie inainte de alte ordine. none nimic nord Nord nordost Nord-est nordwest Nord-vest Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Programul nu poate\n fi schimbat\n in acest moment. November Noiembrie Number of rivers Numar de rauri Oktober Octombrie On this map, you are not\nallowed to change player!\n Jocul este oprit.\nNicio modificare nu este posobila.\n Ops Profit Profit ops Optionen Optiuni Origin Origine paletten palete Passagiere pasageri Passagierrate Trafic pasageri Percent Electricity Electricitate (%% cerinta) Planes are not available yet! Avioanele nu sunt inca disponibile. player 2 Trikky Transport player 3 Meyer Moving Co. Post Post? Power Putere promote to line Traseu nou Random map Harta aleatoare return ticket Retur Revenue Venit sack sac(i) Schienentunnel Tunel feroviar Schiff_tab Nave Schiffdepot Depou nave Schleppkahn_tab Balize Sell the selected vehicle(s) Vehicolul selectat este vândut SEP_FRACTION , September Septembrie Server did not respond! Serverul nu a raspuns! Size (%d MB): Dimensiune (%d MB): Sound Sunet Sound settings Setare sunet Sound volume: Volum efecte: Spielstand wurde\ngespeichert!\n \nSalvarea jocului s-a terminat!\n Sprache Limba Sprachen Limbi Starte Spiel Incepe Jocul Status Stare steam aburi Strassentunnel Tunel Suppliers Parteneri: Tage alt zile There are still vehicles\nstored in this depot!\n Mai este vehicol\nîn depou!\n This Year Anul actual: tonnen t Tracks Trasee Traffic Trafic Train Tren Truck Camion units/day unitate/zi Update Line Actualizare traseu Verbrauch Consum verkaufen Vânzare Verkehrsteilnehmer Automobil via %s\n via %s\n Waggon_tab Vagoane Wert Valoare Years An #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL câmpie &2_CITY_SYLL sat &4_CITY_SYLL vad &6_CITY_SYLL dumbrava &7_CITY_SYLL vârf &9_CITY_SYLL cruci &A_CITY_SYLL hotar %5_CITY_SYLL Râmnicu %6_CITY_SYLL Slatina %7_CITY_SYLL Vama %8_CITY_SYLL Întorsura %B_CITY_SYLL deal 1center %s %s 2center %s centru %s 2extern %s de sus %s 3center %s principal %s 3extern %s de jos %s 4center %s secundar %s 4extern %s extern %s 5center %s transfer %s Acenter Nu există! Aextern Nu există! Asuburb Nu exista! Bcenter Nu exista! Bextern Nu exista! Bsuburb Nu exista! Ccenter Nu exista! Cextern Nu exista! Csuburb Nu exista! Dcenter Nu exista! Dextern Nu exista! Dsuburb Nu exista! Ecenter Nu exista! Eextern Nu exista! Esuburb Nu exista! Fcenter Nu exista! Fextern Nu exista! Fsuburb Nu exista! Gcenter Nu exista! Gextern Nu exista! Gsuburb Nu exista! Hcenter Nu exista! Hextern Nu exista! Hsuburb Nu exista! Icenter Nu exista! Iextern Nu exista! Isuburb Nu exista! Jcenter Nu exista! Jextern Nu exista! Jsuburb Nu exista! Kcenter Nu exista! Kextern Nu exista! Ksuburb Nu exista! Lcenter Nu exista! Lextern Nu exista! Lsuburb Nu exista! Mcenter Nu exista! Mextern Nu exista! Msuburb Nu exista! Ncenter Nu exista! simutrans-124.3/simutrans/text/ro/000077500000000000000000000000001474050137200172045ustar00rootroot00000000000000simutrans-124.3/simutrans/text/ro/airtools.txt000066400000000000000000000120031474050137200215750ustar00rootroot00000000000000Ajutor unele aeroport

Unelte aeroport

Unelte aeroport contine unelte care te ajuta sa construiesti o retea de trafic aerian. Acestea pot construi sau elimina : piste de rulare si piste de decolare/aterizare, terminale (pentru pasageri sau marfa) si alte cladiri specifice unui aeroport. Daca joci cu timeline, noi unelte apar cu trecerea timpului.

Apasa pe iconita avionului in partea de sus a meniului pentru a deschide bara de unelte.
Tine cursorul deasupra uneltelor (dupa deschiderea barei) pentru a vedea numele si costul constructiei, pretul mentenantei in paranteze si limita de viteza.

{Sfat: Un mod usor de a construi un aeroport:
i) construieste si conecteaza pistele de rulare si decolare;
ii) plaseaza terminale la capatul pistelor de rulare;
iii) adauga cladiri necesare.}

Uneltele pot include, de la stanga la dreapta:

Pista rulare: este o pista folosita de avioane pentru a traversa de la terminal la pista de decolare. Pistele de taxi sunt construite la nivelul zero (nu pot fi construite sub pamant sau suspendate).
IMPORTANT: Daca pistele de rulare sunt conectate la capatul pistelor de aterizare/decolare, avioanle nu vor putea ateriza sau decola.
Pentru a construi o pista de rulare: click pe iconita (cursorul se va schimba), click pe teren pentru un punct de pornire (arata un buldozer iar in partea din dreapta jos coordonate) iar la final click in locul in care vrei sa se termine aceasta pista.
{Sfat: Foloseste Distruge/Elimina pentru a sterge bucati din pista de rulare. Functia undo, [z] nu va returna banii.)

Pista principala: construieste o pista pentru aterizarea si decolarea avioanelor. Aceste piste sunt construite la nivelul zero (deci nu pot fi construite sub pamant sau suspendate) dar se pot suprapune.
Pentru a construi o pista principala: click pe iconita (care se va schimba), click pe teren pentru a seta inceputul pistei (se va schimba in iconita unui buldozer) iar la final click in locul in care vrei ca pista sa se termine.
{Sfat: Capetele pistei principale trebuie sa fie goale, altfel avioanele nu vor putea decola sau ateriza. Foloseste Distruge/Elimina pentru a sterge bucati din pista de rulare. Functia undo, [z] nu va returna banii.}

Eliminarea pistelor: aceasta unealta va sterge un segment din pista de rulare sau aterizare, doar atunci cand nu este folosita de un avion. Aceasta unealta necesita anumite costuri.
Pentru a sterge pista: click pe iconita (se va schimba intr-o crucie rosie), click pe inceputul pistei de care nu mai ai nevoie (iconita se va schimba din nou) iar la final click pe capatul zonei ce urmeaza a fi distrusa. {Sfat: Capetele pistei principale trebuie sa fie goale, altfel avioanele nu vor putea decola sau ateriza. Foloseste Distruge/Elimina pentru a sterge bucati din pista de rulare.}

Hangarul: este folosit pentru a cumpara si a inventaria avioane. Hangarele au costuri de mentenanta si sunt construite la capatul unei piste de rulare.
Pentru a construi un Hangar: click pe unealta (se va schimba in iconita unui hangar) si apoi click pe capatul unei piste de rulare.
{Sfat: Elimina hangare cu unealta de Distruge/Sterge.}

Terminal: aceata unealta construieste statii pentru avioane, folosite pentru imbarcarea si debarcarea pasagerilor, incarcareea si descarcarea de marfa.
Un Terminal, cand nu este construit langa un alt Terminal va actiona de sine statator (nu va imparti marfa sau pasageri cu celalalt terminal).
Terminalele sunt construite la capatul pistelor de rulare si au costuri de mentenanta. Mai mult, acestea au zone (arie de efect) care determina numarul de pasageri, posta si marfuri ce vor tranzita aeroportul. Un avion va ateriza numai la un aeroport care are un Terminal liber.
Pentru a construi un Terminal : click pe unealta si apoi click pe capatul unei piste de rulare.
{Sfat: Elimina Terminale cu unealta de Distruge/Sterge. Apasa [v] pentru a arata/ascunde aria de efect penru marfuri si pasageri.}

Cladiri aeroport: aceasta unealta permite constructia de extensii pentru Terminale care pot creste costul de mententanta, capacitatea si aria de efect a acestuia, atat pentru pasageri cat si pentru marfa. In coltul unor unelte, o unealta (folosita in Lista statii si Terminale) arata care elemente din extensie pot functiona cu terminalul.
Pentru a construi o extensie: click pe unealta pentru a selecta extensia dorita (cursorul se va schimba in forma unei extensii) iar apoi click pe zona potrivita, langa un Terminal. Noua extensie construita este acum parte din Terminal.
{Sfat: Sterge extenstiile cu unealta de Distruge/Sterge. Apasa [v] pentru a arata/ascunde aria de efect pentru marfa si pasageri.}

simutrans-124.3/simutrans/text/ro/color.txt000066400000000000000000000004711474050137200210650ustar00rootroot00000000000000Help culori

Selectare culoare

Aici poţi să-ţi alegi propria culoare. Cu culoarea aleasă sunt marcate toate proprietăţile şi vechicolele tale. Nu toate obiectele sunt marcate cu culoarea aleasă, ci depinde cum a fost obiectul implantat în joc de cel care l-a proiectat.

simutrans-124.3/simutrans/text/ro/depot.txt000066400000000000000000000024301474050137200210570ustar00rootroot00000000000000Depou

Depou

Aici poţi procura vechiculele dorite şi defineşti trasee.

Poţi găsi toate vechicolele ce pot fi cumpărate la un anumit moment. Într-u tab sunt puse angrenajele (locomotivele respectiv camioanele ), iar în altul sunt puse vagoanele sau remorcile. Nu toate combinaţiile sunt permise, acesta este semnalat printr-o linie verde (permis) sau roşie (nepermis).

În partea de jos se găsesc parametrii vehicolului dorit (preţ, putere, capacitate etc.)

Cu butonul "Start" porneşti noul convoi, însă numai atunci îl poţi porni după ce la punctul "Traseu/rută" defineşti un traseu. Cu butonul "Dezleagă" dezlegi convoiul actual fără să-ţi primeşti înapoi banii. Preţul vehicolului este returnat când alegi butonul "Vinde". Preţul scade odată cu trecerea timpului.

Achiziţionarea se face cu un click stâng pe vehicolul dorit. În partea dreaptă mai în jos poţi găsi butonul cu care alegi dacă noul vehicol este pus în faţă sau în spate. Poţi lucra deodată numai la un singur convoi!

În timpul jocului dacă vrei ca convoiul să meargă înpoi în depou insertează depoul, în traseul convoiului, sau apasă pe butonul "înapoi depou".

simutrans-124.3/simutrans/text/ro/display.txt000066400000000000000000000013111474050137200214060ustar00rootroot00000000000000Help Setare monitor

Setare monitor

Aici poţi defini setările dorite pt. monitor.

Luminozitate - Schimbă lumina.
Nr. de culori - Nefuncţional încă
Viteza de scrol - Poţi seta viteza de scrol a mapei.

Scrol invers - Defilarea mapei se schimbă
Arată pietonii - Arată sau nu pietonii din oraş.
Mod zi/noapte - Arată sau nu trecerea zile şi a nopţilor.

Îm partea de jos sunt unele informaţii nesemnificative în timpul jocului. Însă dacă ai ceva probleme cu jocul şi vrei să vorbeşti cu autorii probabil unele informaţii afişate aici vor fi foarte importante.

simutrans-124.3/simutrans/text/ro/finances.txt000066400000000000000000000016441474050137200215400ustar00rootroot00000000000000Help Finanţe

Finanţe (f)

Aici poţi afla amănunte despre starea economiei tale.Sunt afişate cele mai importante parametre care pot fi analizate anual s-au lunar.

Sunt afiÅŸate:

Construcţii - Suma cheltuită pe construcţii noi.

Vehicole noi - Suma cheltuită pt. achiziţionarea de noi vehicole.

Cost transport - Suma ce este cheltuită în timpul transporturilor.

Întreţinere - Suma necesară întreţinerii vehicolelor şi traseelor.

Venit - Venitul realizat (este semnalat şi în partea de jos a jocului)

Total - Suma consturilor şi veniturilor sus menţionate.

Balanţa - Balanţa actuală.

Întraţinere lunară - Costul înterţinerii lunare.

În partea dreaptă, sus poţi afişa grafic alte parametrii.

simutrans-124.3/simutrans/text/ro/language.txt000066400000000000000000000011621474050137200215300ustar00rootroot00000000000000Help Limba

Limba

Simutrans a fost tradus în mai multe limbi printre care şi româna. Print selectarea limbajului dorit toate inscripţiile jocului se schimbă în limbajul selectat.
Însă numele oraşelor de pe harta odată creată nu se schimbă. Pt. a folosi oraşe româneşti, prima dată trebuie selectat limba română, după care trebuie creat o nouă hartă.

Pt. eventuale alte traduceri vizitaţi: www.simutrans.de sau 128.simutrans.com

Pentru a ajuta la traducerea Simutrans în limba dvs.,
vizitati https://translator.simutrans.com

simutrans-124.3/simutrans/text/ro/load.txt000066400000000000000000000007241474050137200206670ustar00rootroot00000000000000Help Încarcă

Încărcarea jocurilor salvate:

Sub opţiunea "Încarcă" poţi găsi jocurele deja salvate. Butoanele au aceeaşi semnificaţie ca şi sub meniul "Salvare"

Dacă se încarcă un joc care deja nu mai există va apărea un mesaj de eroare.

Important! Jocurile salvate în versiunile mai vechi ale Simutrans probabil nu pot fi utilizate sub versiunile noi ale jocului.

simutrans-124.3/simutrans/text/ro/map.txt000066400000000000000000000005601474050137200205230ustar00rootroot00000000000000Help Hartă

Hartă

Este afişat o hartă în miniatură a întegului joc. Sunt afişate şi unele informaţii adiacente jocului.

Fiecare tip de unitate de producţie are propria culoare. Legenda culorilor este afişat sub hartă.

Harta poate fi mărită. Asta se face cu un click drept pe orice parte a hărţii.

simutrans-124.3/simutrans/text/ro/new_world.txt000066400000000000000000000035731474050137200217550ustar00rootroot00000000000000Help Hartă nouă

Hartă nouă

Aici se poate ajusta harta nou creată.

Nr. hartă - Aici se poate alege harta dorită. Un mic preview este afişat în partea dreaptă.
Mărime - Mărimea hărţii. Valoare iniţială este de 256.
Important!Cu cât harta e mai mare cu atât creşte şi nevoia de putere de calcul şi multă memorie.

Densit. industriei - Se poate seta densitatea unităţilor industriale. Valoarea iniţială este de 125.
Nr. oraşelor - SE poate seta nr. oraşelor (min. 2 max. 64) Valoare iniţială 16.
Densit. traficului - Se poate regla densitatea traficului din oraşe. Valoarea mai mică poate accelera jocul.

Adâncime apă - Aici se poate ajusta cantitatea de apă afişat pe hartă. Valoare mai mare cantitate mai mare. Valoare iniţială 4.
Înălţime munţi - Se poate ajusta nivelul munţilor. Valorile mai mari cauzează un teren cu mai multe culmi. Valoarea iniţială este de 160.
Dificultate teren - Se poate ajusta dificultatea terenului

Hartă aleatorie - Generare de hartă aleatorie.

Arată pietonii - Se poate seta să afişeze sau nu pietonii din oraşe. După pornirea unei noi hărţi valoarea se poate modifica in meniul "Monitor"
Mod zi/noapte - Aici se poate seta ca jocul să arate trecerea timpului sub formă de zi şi noapte. Neactivat înseamnă că întotdeauna este ziua.După pornirea unei noi hărţi valoarea se poate modifica in meniul "Monitor"

Încarcă joc - Încarcă un joc salvat. (vezi la Opţiuni meniul "Salvare".)
PorneÅŸte joc Pornirea jocului.
Terminare joc - Ieşire din joc (fără confirmare).

simutrans-124.3/simutrans/text/ro/options.txt000066400000000000000000000010201474050137200214310ustar00rootroot00000000000000Help Opţiuni

Opţiuni

Limba - Selectarea limbii
Culoare jucător - Selectarea culorii.
Monitor - Setări monitor.
Sunet - Setări sunete.
Jucători - Selectare adversari.
Încarcă - Încarcă joc salvat
Salvează - Salvare joc.
Hartă nouă - Crearea unei noi hărţi
Terminare joc - Ieşire din joc (jocul ne se salvează automat)

Detalii în help-ul meniurilor.

simutrans-124.3/simutrans/text/ro/players.txt000066400000000000000000000006271474050137200214310ustar00rootroot00000000000000Help Jucători

Jucători

Aici poţi activa sau deactiva jucătorii manipulati de calculator.

Deactivarea unui jucător înseamnă defatp "hibernarea" acestuia, adică unităţile de producţie controlate de jucătorul respectiv vor produce în continuare, însă nu se vor înfiinţa noi legături şi industrii.

Sunt afişate banii deţinuţi de jucători.

simutrans-124.3/simutrans/text/ro/railtools.txt000066400000000000000000000012031474050137200217510ustar00rootroot00000000000000Scule pt. trenuri

Scule pt. trenuri

De aici se poate procura tren, vagoane, semafoare etc.

Sunt mai multe tipuri de cale ferată, fiecare permiţând o anumită viteză maximă.

Semafoarele la început pot semnala în ambele direcţii. Pt. a impune o anumită direcţie trebuie făcut click pe semafor, până ce se obţine direcţia dorită.

La construirea tunelului trebuie luat în considerare faptul, că şinele trebuie urcate pe pantă. În caz contrar programul nu permite construirea tunelezului.

Convoiul dorit se poate asambla în combinaţia dorită în depou.

simutrans-124.3/simutrans/text/ro/roadtools.txt000066400000000000000000000004571474050137200217610ustar00rootroot00000000000000Help Scule pt. automobile

Scule pt. automobile

Aici poţi găsii toate uneltele necesare pt. managementul automobilelor procurate în depou.

Fiecare tip de şosea permite o anumită viteză maximă.

Traversă se poate construi numai pe cale ferată.

simutrans-124.3/simutrans/text/ro/save.txt000066400000000000000000000001311474050137200206760ustar00rootroot00000000000000Help Salvare

Salvare

Aici se poate salva jocul actual.

simutrans-124.3/simutrans/text/ro/schedule.txt000066400000000000000000000005731474050137200215460ustar00rootroot00000000000000Traseu/rută

Traseu/rută

Aici defineşti trasee pt. convoaiele dorite. În fiecare staţie poţi defini cât la sută din capacitatea de transport să fie utilizat. Însă trebuie luat în considerare că dacă unitatea de producţie nu poate să umple vehicolul, atunci acesta va sta în staţie până ce se va umple la capacitatea setată.

simutrans-124.3/simutrans/text/ro/shiptools.txt000066400000000000000000000003431474050137200217710ustar00rootroot00000000000000Help Scule pt. nave

Scule pt. nave

Aici găseşti toate uneltele necesare pt. construire de nave şi docuri maritime.

Locul de ancorare trebuie ales cat mai aproape de staţia dorita.

simutrans-124.3/simutrans/text/ro/sound.txt000066400000000000000000000006301474050137200210740ustar00rootroot00000000000000Help Setare sunet

Setare sunet

Aici poţi selcta efectele dorite.

Volum efecte: - Ajustarea efectelor (ex. claxonarea etc.)
Volum muzică: - Ajustarea muzicii. Atenţie în unele cazuri jocul este instalat fără muzică, în acest caz potenţiometrul nu are nici un efect. Melodia jucată este afişată cu un rând mai jos

simutrans-124.3/simutrans/text/ro/station.txt000066400000000000000000000002451474050137200214270ustar00rootroot00000000000000Help Staţii

Staţii

Sunt afişate parametrii staţiei selectate (câţi pasageri sunt, câtă materie primă staţionează etc.)

simutrans-124.3/simutrans/text/ro/station_details.txt000066400000000000000000000002521474050137200231320ustar00rootroot00000000000000Detalii staţii

Detalii staţii

Poţi analiza toate legăturile staţiei, precum şi legăturile directe cu unităţile de producţie.

simutrans-124.3/simutrans/text/ru.tab000066400000000000000000002170431474050137200177110ustar00rootroot00000000000000§Russian PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: ru Russian # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Отобразить Ð²Ñ€ÐµÐ¼Ñ ÐºÐ°Ðº "день чч:мм меÑÑц" AMBIENT_SOUND Окружающие звуки CASH_SOUND Денежные звуки cl_btn_filter_disable Отключено cl_btn_filter_enable Включено cl_btn_filter_settings ÐаÑтройки cl_btn_sort_asc По возраÑтанию cl_btn_sort_desc По убыванию cl_btn_sort_id Внутренний ID cl_btn_sort_income Доход cl_btn_sort_name Ðазвание cl_btn_sort_type Тип clf_btn_alle Ð’Ñе clf_btn_invers Обратно clf_btn_keine Ðет climate area percentage Площадь климата CROSSING_SOUND Предупреждающие звуки FACTORY_SOUND ПроизводÑтвенные шумы Find matching convois ПоиÑк подходÑщих Ñ‚/Ñ gl_btn_sort_bonus Ð‘Ð¾Ð½ÑƒÑ gl_btn_sort_name Ðазвание gl_btn_sort_revenue Выручка gl_btn_unsort Ðе отÑортировано height based Климат по уровнÑм выÑоты hl_btn_filter_disable Отключено hl_btn_filter_enable Включено hl_btn_filter_settings ÐаÑтройки hl_btn_sort_asc По возраÑтанию hl_btn_sort_desc По убыванию hl_btn_sort_name Ðазвание hl_btn_sort_type Тип hl_btn_sort_waiting Ожидание hlf_btn_alle Ð’Ñе hlf_btn_invers Обратно hlf_btn_keine Ðет humidities Граница влажноÑти Install УÑтановка набора пакетов Lake Озёра Lake height МакÑ. выÑота озёр Maximize height levels МакÑ. уровни выÑот moisture land Увеличение по Ñуше moisture water Увеличение по воде Networks Сетка Num pad keys always move map Клавиши цифровой клавиатуры вÑегда перемещают карту Open Sea Открытое море Queueing Ð¢ÐµÐ½Ð´ÐµÐ½Ñ†Ð¸Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ rainfall ВлажноÑть Reselect closes tools Повторный выбор инÑтрументов закрывает их Road toll Дорожный Ñбор Scenario Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñценарии sea МорÑкой климат Single GUI Единый GUI Sound range: Диапазон звука: Start this as a server ЗапуÑтите Ñервер Ñ Ñтой игрой temperature borders Границы температур temperature-humidity based Климат по погоде TOOL_SOUND Звуки инÑтрументов TRAFFIC_SOUND ТранÑпортные шумы Transfers ТранÑфер #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic ÐрктичеÑкий desert ПуÑтынный mediterran Средиземный rocky ÐльпийÑкий (ÑкалиÑтый) temperate Умеренный tropic ТропичеÑкий tundra СубарктичеÑкий #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Ошибка загрузки Ñкрипта ÑÑ†ÐµÐ½Ð°Ñ€Ð¸Ñ Bridge blocked by way below or above. Ð’Ñ‹Ñота моÑта не доÑтаточна Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐºÐ»Ð°Ð´ÐºÐ¸ путей под ним. Can't buy obsolete vehicles! УÑтаревшие транÑпортные ÑредÑтва покупать нельзÑ! Cannot alter water Этот водоем не может быть больше оÑушен или заполнен. Cannot build on a double slope! Может быть поÑтроено только на одиночном ÑпуÑке или плоÑкоÑти! Cannot built depot here! ЗдеÑÑŒ Ð½ÐµÐ»ÑŒÐ·Ñ Ð¿Ð¾Ñтроить депо! Cannot built this station/building\nin underground mode here. Ðевозможно поÑтроить Ñту Ñтанцию/здание\nв подземном режиме. Cannot create generic line!\nSelect line type by\nusing filter tabs. ÐÐµÐ»ÑŒÐ·Ñ Ñоздать общую линию!\nВыберите тип линии,\nиÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€. Cannot create socket Ðевозможно Ñоздать Ñоединение Cannot rotate this building! Ðевозможно вращать Ñто Ñтроение! Client closed connection during transfer Клиент закрыл Ñоединение при загрузке. Convoi handles exhausted! ДоÑтигнут макÑимум Ñ‚/Ñ. Convoy already deleted! Т/Ñ ÑƒÐ¶Ðµ удалено! Could not open file Ðевозможно открыть файл. Das Feld gehoert\neinem anderen Spieler\n Этим учаÑтком\nземли владеет\nдругой игрок!\n Der Besitzer erlaubt das Entfernen nicht Права владельца\nзапрещают удаление!\n Diese Zusammenstellung kann nicht fahren!\n Эта комбинациÑ\nне может двигатьÑÑ!\n Flugzeughalt muss auf\nRunway liegen!\n ПоÑадочный терминал\nдолжен быть на дороге!\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Это здание аÑропорта\nне может быть\nпоÑтроено здеÑÑŒ!\n Hier kann kein\nSignal aufge-\nstellt werden!\n Семафор не может\nбыть уÑтановлен здеÑÑŒ!\n In order to lock the game, you have to protect the public player by password! Ð”Ð»Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ игры, необходимо защитить текущего игрока паролем! Loading a new game will end the current server session! Загрузка новой игры закроет текущую ÑеÑÑию Ñервера! Lost connection\nto server! Ðет ÑоединениÑ\nÑ Ñервером! Lost synchronisation\nwith server. Ðет Ñинхронизации\nÑ Ñервером. Maglevhalt muss auf\nMaglevschiene liegen!\n ОÑтановка маглева\nдолжна находитьÑÑ\nна путÑÑ… маглева! Monorailhalt muss auf\nMonorail liegen!\n МонорельÑÐ¾Ð²Ð°Ñ Ð¾Ñтановка\nдолжна находитьÑÑ\nна монорельÑе! Monorails are not available yet! ÐœÐ¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ ÐµÑ‰Ñ‘ недоÑтупен! More than one possibility to build this dock found. Обнаружено неÑколько возможноÑтей поÑтроить Ñтот док. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n ОÑтановка узкоколеных Ñ‚/Ñ\nдолжна находитьÑÑ\nна узкоколейке! No bridges over runways! МоÑты над шоÑÑе запрещены! No curves on runways Взлётно-поÑÐ°Ð´Ð¾Ñ‡Ð½Ð°Ñ Ð¿Ð¾Ð»Ð¾Ñа не имеет повороты! No suitable crossing Ðет подходÑщего переÑечениÑ! (макÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÑкороÑть Ñлишком быÑтраÑ?) No suitable way on the ground! ОÑтановку можно поÑтроить только на\nпрÑмом учаÑтке траÑÑÑ‹. No through station here! Станции должны раÑполагатьÑÑ Ð½Ð° тупиковых путÑÑ… или прÑмых учаÑтках, не имеющих переÑечений. Not enough bytes transferred Передано недоÑтаточно байтов Not enough clearance. Между Ð´Ð²ÑƒÐ¼Ñ ÐºÐ»ÐµÑ‚ÐºÐ°Ð¼ Ð´Ð»Ñ Ð¿Ð¾Ñтройки пути разница выÑот должна ÑоÑтавлÑть минимум 2 уровнÑ. Not enough money! У Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтаточно денег! On narrowgauge track only!\n Только на узкоколейном пути!\n Only public player can lock games! Только публичный игрок может блокировать игру! Out of funds Ðе доÑтаточно ÑредÑтв! Post muss neben\nHaltestelle\nliegen!\n Станционные ÑтроениÑ\n должны размещатьÑÑ\nна Ñвободной клетке\nÑ€Ñдом Ñ ÑущеÑтвующей\nÑтанцией или оÑтановкой!\n Protocoll error (expecting game) Ошибка протокола (ожидание игры) Schiffhalt muss im\nWasser liegen!\n ОÑтановка Ñудна\nможет быть только\nоколо дока!\n Server busy Сервер занÑÑ‚ Server version too new Сервер иÑпользует более новую верÑию программы. Show all revenue messages Показать вÑе ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ доходах Show no revenue messages Ðе показывать ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ доходах Show only player's revenue Показывать только доход игрока Terraforming not possible\nhere in underground view Изменение ландшафта в подземном режиме не возможно! This tunnel branches. You can try Control+Click to remove. Этот тоннель разветвлÑетÑÑ. Ð’Ñ‹ можете нажать Ctrl+клик Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ. Too far away to merge stations! Слишком далеко Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñтанций! Upgrade must have\na higher level УÑовершенÑтвование должно иметь\nболее выÑокий уровень Vehicle %s cannot choose because stop too short! ТранÑпортное ÑредÑтво %s не может выбрать путь, Ñ‚.к. оÑтановка Ñлишком коротка! Zughalt muss auf\nSchiene liegen!\n Ж/д Ñтанции\nдолжны ÑтроитьÑÑ\nтолько на ж/д путÑÑ…!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Справка

Содержание

Про Simutrans

%1$s

Общие данные

%2$s

Ðачало игры

%4$s

Игровой процеÑÑ

%5$s

ИнÑтрументы

%3$s

Разное

%6$s Keyboard Help\n

Keyboard Help

\n ГорÑчие клавиши\n

Справка по клавишам управлениÑ

\n

\nСправка по клавишам ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ функции оÑновных клавиш на клавиатуре..\n

\n

\nСтраница Ñправки по клавишам ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ð²Ð°ÐµÑ‚ÑÑ, когда была нажата Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ° или из Ñтраницы Главной Ñправки.\n

\n

\nKey presses are case sensitive (use [Shift] for upper-case letters).\n

\n

\nKeys with assigned functions include:\n

\n

\n[Arrow Keys]: scroll game-view in direction of arrow.
\n[Backspace]: close all windows, toolbars and help-texts in game-view.
\n[Delete], or [Escape]: close top window, toolbar or help-text in game-view.
\n[Enter], or [Return]: used to confirm actions.
\n[Page-Up], or [>]: zoom-in game-view.
\n[Page-Down], or [ less than symbol]: zoom-out game-view.\n[F1]: open Simutrans Help.

\n

\n[1]: scroll game-view south-wards.
\n[2]: scroll game-view south-east-wards.
\n[3]: scroll game-view east-wards.
\n[4]: scroll game-view south-west-wards.
\n[6]: scroll game-view north-east-wards.
\n[7]: scroll game-view west-wards.
\n[8]: scroll game-view north-west-wards.
\n[9]: scroll game-view north-wards.\n

\n

\n[Shift] + mouse: used on Map to see links in Industry Supply Chain.
\n[CTRL] + tool: build slower roads and tracks over faster ones; or build straighter (more direct) roads and tracks.
\n

At least one stop is connected to the town. Как минимум одна оÑтановка Ñоединена Ñ Ð³Ð¾Ñ€Ð¾Ð´Ð¾Ð¼. At least one tile is connected to one stop. Как минимум одна плитка Ñоединена Ñ Ð¾Ð´Ð½Ð¾Ð¹ оÑтановкой Color according to transport capacity left Цвет ÑоответÑтвует Ñвободному меÑту транÑпорта Color-coded terrain according to altitude. Показать/Ñкрыть затенение контура рельефа. Decrease water height Уменьшить уровень воды Highlight railroad tracks Выделить железнодорожные пути Highlite depots Выделить депо Highlite electrical transmission lines Выделить линии Ñлектропередачи Highlite factories Выделить предприÑÑ‚Ð¸Ñ Highlite forests Выделить леÑа Highlite tourist attraction Выделить доÑтопримечательноÑти Increase water height Увеличить уровень воды Open station/stop details Показать информацию о Ñтанции/оÑтановке Overlay city limits Отображать границы городов. Overlay passenger destinations when a town window is open Отображать точки Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð°ÑÑажиров, когда открыто окно информации города. Overlay schedules/network Отображать вÑÑŽ транÑпортную Ñеть или только выбранный маршрут. Overlay town names Отображать Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð³Ð¾Ñ€Ð¾Ð´Ð¾Ð². Please click on the map to add\nwaypoints or stops to this\nschedule. Укажите на карте, какие точки или оÑтановки\nнеобходимо добавить к Ñтому раÑпиÑанию. Remove double stops from schedule Убрать из раÑпиÑÐ°Ð½Ð¸Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÑющиеÑÑ Ð¾Ñтановки Set tile climate %s Задать климат Ð´Ð»Ñ %s плитки Show capacity and if halt is overcrowded Отображать емкоÑть Ñкладов Ñтанции и их переполнение грузами. Show how many convoi reach a station Отображать Ñколько Ñ‚/Ñ Ð¾Ð±ÑлуживаетÑÑ Ð½Ð° ÑтанциÑÑ…. Show how many people/much is waiting at halts Отображать Ñколько паÑÑажиров на ÑтанциÑÑ… и как долго они ожидают Ñвой Ñ‚/Ñ. Show initial passenger departure Отобразать начальные точки Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°ÑÑажиров. Show level of city buildings Отображать уровни городÑких зданий. Show mail service coverage/mail network Отображать зону Ð¿Ð¾ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÑтанциÑми почты или почтовые линии. Show passenger coverage/passenger network Отображать зону Ð¿Ð¾ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÑтанциÑми паÑÑажиров или паÑÑажирÑкие линии. Show speedlimit of ways Отобразить Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ ÑкороÑти. Show the change of waiting at halts Отображать как изменилоÑÑŒ ожидание на ÑтанциÑÑ… Ñ Ð¿Ñ€Ð¾ÑˆÐ»Ð¾Ð³Ð¾ меÑÑца. Show the owenership of infrastructure Отобразить владельцев инфраÑтруктуры. Show transported freight/freight network Отображать транÑпортируемые грузы или грузовые линии. Show usage of network Отобразить загруженноÑть линий. Shows a listing with all industries on the map. Отобразить ÑпиÑок фабрик, раÑположенных на карте. Sum of departure/arrivals at halts Отображать Ñколько проиÑходит отправлений/прибытий из/на ÑтанциÑÑ…. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s теперь\nпредлагает поездки на автобуÑе\nиз %s\n до \n%s\nв (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s теперь\nперевозит рабочих из\n%s на\n%s\nв (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nзапуÑтил %i грузовиков между\n%s в (%i,%i)\nи %s\nв (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nоткрыл новую ж/д\nÑообщением %s\nв (%i,%i) -\n%s\nв (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ %s\nуже обÑлуживает линию между\n%sи %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ \n%s\nуже обÑлуживает паромную линию между\n%s и %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ %s\n уже открыла автобуÑный маршрут между\n%s и %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Редактор карты LISTTOOLS СпиÑки MAGLEVTOOLS Маглев MONORAILTOOLS ÐœÐ¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ NARROWGAUGETOOLS Ð£Ð·ÐºÐ¾ÐºÐ¾Ð»ÐµÐ¹Ð½Ð°Ñ Ð¶ÐµÐ»ÐµÐ·Ð½Ð°Ñ Ð´Ð¾Ñ€Ð¾Ð³Ð° RAILTOOLS Ð–ÐµÐ»ÐµÐ·Ð½Ð°Ñ Ð´Ð¾Ñ€Ð¾Ð³Ð° ROADTOOLS Ðвтодорога SHIPTOOLS СудоходÑтво SLOPETOOLS Редактор ландшафта SPECIALTOOLS ОÑобые поÑтройки TRAMTOOLS Трамваи/легкорельÑовые дороги #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s поÑтроил новый головной Ð¾Ñ„Ð¸Ñ (%i,%i) Factory chain extended\nfor %s near\n%s built with\n%i factories. РоÑÑ‚ Ñкономики:\n%s около %s раÑширÑет цепочку поÑтавок. \n%i оÑновано новое предприÑтие. Net wealth less than 10%% of starting capital! ЧиÑтых активов меньше 10%% от Ñтартового капитала! Это может привеÑти к банкротÑтву. New %s now available:\n%s\n Ðовый %s теперь доÑтупен:\n%s\n New factory chain\nfor %s near\n%s built with\n%i factories. РоÑÑ‚ промышленноÑти: Ð½Ð¾Ð²Ð°Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´ÑÑ‚Ð²ÐµÐ½Ð½Ð°Ñ Ñ†ÐµÐ¿Ð¾Ñ‡ÐºÐ°\n Ð´Ð»Ñ %s вблизи %s поÑтроена Ñ\n%i предприÑтий. New vehicle now available:\n%s\n \n Теперь доÑтупен новый\nтранÑпорт:\n\n\n -- %s --\n\n Now %u clients connected. Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¾ клиентов: %u. overtaking обгон Remove vehicle from map. Use with care! Убрать Ñ‚/Ñ Ñ ÐºÐ°Ñ€Ñ‚Ñ‹. ИÑпользуйте оÑторожно! Screenshot\ngespeichert.\n Скриншот\nÑохранён.\n Sends the convoi to the last depot it departed from! ПоÑлать Ñ‚/Ñ Ð² поÑледнее поÑещённое депо. Server preparing game ... Сервер ÑохранÑет игру... Trees Ð”ÐµÑ€ÐµÐ²ÑŒÑ With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Ð’ чеÑть Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ монумента\nв %s организованы большие празднованиÑ.\n%i горожан отмечают Ñто Ñобытие. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Фильтр линий #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%.2f$/km %.2f$/m) (%.2f$/км %.2f$/меÑÑц) (%.2f$/km) (%.2f$/км) (%i)- (%i) (in depot) (в депо) [0] south-facing [0] на юг [1] east-facing [1] на воÑток [2] north-facing [2] на Ñевер [3] west-facing [3] на запад [4] southeast corner [4] на юго-воÑток [5] northeast corner [5] на Ñеверо-воÑток [6] northwest corner [6] на Ñеверо-запад [7] southwest corner [7] на юго-запад \nBauzeit bis до \nBauzeit von \nДоÑтупно в период:\n \nCan't open heightfield file.\n \nÐе могу открыть карту выÑот.\n \ndirection: \nнаправлениÑ: \nelektrified \nÑлектрифицировано \nHeightfield has wrong image type.\n \nКарта выÑот имеет\nнекорректный формат\nизображениÑ.\n \nis reserved by: \nзанÑто поездом \nminimum speed: \nÐ¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÑкороÑть: \nnot elektrified \nне Ñлектрифицировано\n \nRibi (masked) \nнаправлениÑ\n (перекрыты): \nRibi (unmasked) \nÐаправлениÑ\n(открыты): \nSet phases: \nУÑтановка времени фаз\nСевер-Юг ВоÑток-Запад: \nsingle way \nодноÑтороннее движение \nway1 reserved by \nПуть 1 заразервирован \nway2 reserved by \nПуть 2 зарезервирован \nwith sign/signal\n \nÑо знаком/Ñигналом\n %d buildings\n %d зданий\n %d convois %d Ñ‚/Ñ %d Einzelfahrzeuge im Depot %d Ñ‚/Ñ Ñ…Ñ€Ð°Ð½Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ %i car(s), %i машин, %i km/h (max. %ikm/h) %i км/ч (макÑ. %i км/ч) %i years %i months old. ВозраÑÑ‚:\n%i лет и %i меÑÑцев. %s at (%i,%i) now public stop. %s в (%i,%i) теперь общедоÑтупна. %s building %s %s здание %s %s %s %s city %d %s Город %s %d %s %s factory %s %s ПредприÑтие %s %s %s %s has entered a depot. %s прибыл в депо. %s land %d %s %s облаÑть %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Ð’ %s была поÑтроена Ð½Ð¾Ð²Ð°Ñ Ð¼ÑриÑ, когда наÑеление доÑтигло %i. %s\nis crowded. %s переполнена. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nмакÑ. Ñкор.: %3$i км/ч\n\nтек. Ñкор.: %2$i км/ч.\n\n %s\nwas liquidated. ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ %s обанкротилаÑÑŒ и ликвидирована.\nÐ’Ñе операции оÑтановлены,\nвÑе активы проданы. %u Client(s)\n %u клиент(-ов)\n %u Player (%u locked)\n %u игроков (%u заблокировано)\n <очиÑтить раÑпиÑание> <Ñоздать линию> %s - %s
\n [%s]: %s
\n

Error

Ошибка: Дублирование объектов в папке пак-Ñета

Ð’

Warning

addons for

Предупреждение: Дублирование объектов в папке дополнений

Ð”Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð´Ð»Ñ <индивидуальное раÑпиÑание> <не назначен на линию> <нет раÑпиÑаниÑ> <Ð½Ð¾Ð²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ> 1 convoi 1 Ñ‚/Ñ 1 Einzelfahrzeug im Depot 1 Ñ‚/Ñ Ñ…Ñ€Ð°Ð½Ð¸Ñ‚ÑÑ Ð·Ð´ÐµÑÑŒ 100 km/h = %i tiles/month 100 км/ч = %i клеток/меÑÑц 1LIGHT_CHOOSE ЯркоÑть: 1WORLD_CHOOSE УÑтановки новой игры: 2LIGHT_CHOOSE Цвета: 2WORLD_CHOOSE Ðомер карты: 3LIGHT_CHOOSE СкороÑть прокрутки: 4LIGHT_CHOOSE ÐžÐ±Ñ€Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‚ÐºÐ° 5LIGHT_CHOOSE Пешеходы на оÑтановках 5WORLD_CHOOSE КоличеÑтво городов 6LIGHT_CHOOSE Пешеходы в городах 6WORLD_CHOOSE ПлотноÑть движениÑ: 8WORLD_CHOOSE Смена Ð´Ð½Ñ Ð¸ ночи A bridge must end on a way! МоÑÑ‚ должен заканчиватьÑÑ Ð½Ð° пути! A bridge must start on a way! МоÑÑ‚ должен начинатьÑÑ Ð² конце ÑущеÑтвующего пути. Abfrage Режим проÑмотра Abnehmer Потребитель About Про About scenario ОпиÑание Abriss Разрушить/Удалить Absenken ОпуÑтить землю Abspanntransformator ТранÑформатор Accelerate time УÑкорить Ð²Ñ€ÐµÐ¼Ñ Act. load: %u MW\n Факт. нагр.: %u МВ\n Active player only Только активный игрок Add forest ПоÑадить Ð»ÐµÑ Add random citycar Добавить городÑкое Ñ‚/Ñ add server Добавить Ñервер Add Stop Добавить Add stops for backward travel Добавить оÑтановки Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾Ð³Ð¾ пути air Ñ€ÑƒÐ»ÐµÐ¶Ð½Ð°Ñ Ð´Ð¾Ñ€Ð¾Ð¶ÐºÐ°/Ð²Ð·Ð»ÐµÑ‚Ð½Ð°Ñ Ð¿Ð¾Ð»Ð¾Ñа Aircraft ÐÐ²Ð¸Ð°Ð»Ð¸Ð½Ð¸Ñ aircraft_tab Грузовые Ñамолёты airplane Ñамолёт Airport ÐÑропорт AIRTOOLS Воздушный транÑпорт All Ð’Ñе all convoi tooltips Ð’Ñе значки над Ñ‚/Ñ Allow city growth Разрешить роÑÑ‚ города Allow player change Разрешить Ñмену игрока allowed climates:\n Разрешённые климаты:\n Alters a schedule. Добавить/удалить оÑтановки в/из раÑпиÑаниÑ. and arranged by и аранжировка Angenommene Waren Товары, необходимые близлежащим предприÑтиÑм anhaengen Добавить Anhaenger_tab Прицепы Anheben ПоднÑть землю Appends stops at the end of the schedule Добавить оÑтановки в конце раÑпиÑаниÑ. Apply Line Ðазначить линию Apr. Ðпр. April Ðпрель Arbeiter aus: Рабочие живут в: Arrivals from\n ОтправилÑÑ Ð¸Ð·:\n Arrived ДоÑтавлено Assets Фонды Aufloesen Разобрать Aufspanntransformator ТранÑформатор Aug. Ðвг. August ÐвгуÑÑ‚ auto авто Autohalt muss auf\nStrasse liegen!\n ОÑтановка должна размещатьÑÑ Ð½Ð° дороге. Available ДоÑтупно Available at custom date ДоÑтупно в выбранную дату Bahndepot Железнодорожное депо Bankrott:\n\nDu bist bankrott.\n БанкротÑтво:\n\nÐ’Ñ‹ банкрот.\n battery Ð‘Ð°Ñ‚Ð°Ñ€ÐµÑ Baum Дерево baum builder ПоÑадить дерево Baustelle МеÑто ÑтроительÑтва Bauzeit Ð²Ñ€ÐµÐ¼Ñ ÑтроительÑтва Beenden Выйти Beginner mode Режим Ð¾Ð±ÑƒÑ‡ÐµÐ½Ð¸Ñ Besonderes Gebaeude ДоÑтопримечательноÑть BF ÑÑ‚Ð°Ð½Ñ†Ð¸Ñ bio гужевой Blockstrecke ist\nbelegt\n Ж/д блок уже занÑÑ‚\nдругим поездом!\n Boden Ð—ÐµÐ¼Ð»Ñ Bonus Multiplier: %i%% Множитель бонуÑа: %i%% Bonus Speed: %i km/h БонуÑÐ½Ð°Ñ ÑкороÑть: %i км/ч Bonusspeed: %i km/h МакÑ. Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ ÑкороÑть: %i км/ч Boost (%%) УÑкорение (%%) Borderless (disabled on fullscreen) Без рамки (отключено в полноÑкранном режиме) bridge is too high for its type! Слишком выÑоко Ð´Ð»Ñ Ð¼Ð¾Ñта данного типа! Bridge is too long for this type!\n Слишком большой пролёт\nÐ´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ типа моÑтов!\n Bruecke МоÑÑ‚ Bruecke muss an\neinfachem\nHang beginnen!\n МоÑты должны\nначинатьÑÑ Ð½Ð°\nпрÑмом Ñклоне!\n Brueckenboden МоÑÑ‚ Build air depot Самолётный ангар build choosesignals ПоÑтроить Ñемафор выбора платформы(choosesignal) Build city market ПоÑтроить новый торговый центр в ближайшем городе Build drain ТранÑÑ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ñ€Ð½Ð°Ñ Ð¿Ð¾Ð´ÑÑ‚Ð°Ð½Ñ†Ð¸Ñ build HQ ПоÑтроить штаб Build land consumer ПоÑтроить новую ÑлектроÑтанцию Build maglev depot ПоÑтроить депо Ð´Ð»Ñ Ð¼Ð°Ð³Ð»ÐµÐ²Ð° Build monorail depot ПоÑтроить депо монорельÑа Build narrowgauge depot ПÑтроить депо Ð´Ð»Ñ ÑƒÐ·ÐºÐ¾ÐºÐ¾Ð»ÐµÐ¹ÐºÐ¸ Build powerline Строить ЛЭП Build presignals ПоÑтроить двуÑторонний Ñемафор Build road depot ПоÑтроить гараж Build ship depot ПоÑтроить корабельный док Build signals ПоÑтроить Ñемафор Build train depot Железнодорожное депо Build tram depot Трамвайное депо Build truck depot Гараж Building costs estimates РаÑÑ‡Ñ‘Ñ‚Ð½Ð°Ñ ÑтоимоÑть ÑтроительÑтва Buildings Ð—Ð´Ð°Ð½Ð¸Ñ Built artifical slopes ПоÑтроить иÑкуÑÑтвенные Ñклоны Built random attraction ПоÑтроить Ñлучайную доÑтопримечательноÑть Bus_tab ÐвтобуÑÑ‹ Can be overgrown Может быть зароÑшим Can only move from halt to halt or waypoint to waypoint. Может перемещатьÑÑ Ð¾Ñ‚\n оÑтановки к оÑтановке, или\n или точки до точки. Cancel Отмена Cannot connect to offline server! Ðе возможно ÑоединитьÑÑ Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ‹Ð¼ Ñервером! Capacity ÐмкоÑть Capacity: ВмеÑтимоÑть: Capacity: %.0f MW ВмеÑтимоÑть: %.0f МВт\n Capacity: %d%s %s\n ВмеÑтимоÑть: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) ВмеÑтимоÑть: %s\nЗагружено: %d (%d%%) Cars are not available yet! Ðвтомобили еще недоÑтупны! cars.\nstate машин\n Cash Ðа Ñчету Change player Сменить игрока Chart График Chat_msg Чат Choose direction Выберите направление Choose operation executed on clicking stored/new vehicles Выбрать операцию, выполнÑемую при щелчке по новому/Ñохранённому Ñ‚/Ñ chooses a random map Выбрать Ñлучайную карту citicens ÐаÑеление City attraction ДоÑтопр. в городах City industries Промышл. в городах City list СпиÑок городов City size Размер city_road ГородÑÐºÐ°Ñ Ð´Ð¾Ñ€Ð¾Ð³Ð° citybuilding builder ПоÑтроить городÑкие Ð·Ð´Ð°Ð½Ð¸Ñ CityLimit Границы cl_title СпиÑок Ñ‚/Ñ cl_txt_sort Сортировка: clamp хомут Clear block reservation Отобразить/Ñкрыть зарезервированные пути clf_chk_aircrafts Самолёты clf_chk_cars ÐвтотранÑпорт clf_chk_indepot в депо clf_chk_maglev Маглев clf_chk_monorail ÐœÐ¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ clf_chk_name_filter Фильтр по имени: clf_chk_narrowgauge Узкоколейка clf_chk_noincome нет дохода clf_chk_noline нет линии clf_chk_noroute нет пути clf_chk_noschedule нет раÑпиÑÐ°Ð½Ð¸Ñ clf_chk_obsolete УÑтарело clf_chk_ships Корабли clf_chk_spezial_filter Спец. фильтр: clf_chk_stucked закреплено clf_chk_trains Поезда clf_chk_trams Трамваи clf_chk_type_filter Фильтр по типу: clf_chk_waren Фильтр по товару: clf_title Фильтр ÑпиÑка Ñ‚/Ñ Climate Климат Climate Control ÐаÑтройки ландшафта Climates Климат closed закрыто. COLOR_CHOOSE\n ПожалуйÑта,\nвыберите цвет\nиз таблицы:\n Company bankrupt БанкротÑтво компании Company_msg Конкуренты Comparing pak files ... Сравнение графичеÑких пакетов ... Composed by Композитор Configure AI ÐаÑтроить ИИ Configure AI setttings ÐаÑтроить ИИ Congratulation\nScenario was complete in\n%i months %i years. ПоздравлÑем!\nÐ’Ñ‹ прошли Ñценарий за\n%i меÑÑцев и %i лет! Connected stops Соединённые оÑтановки Connected with server Соединение Ñ Ñервером Connections Ð¡Ð¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Constructed by ÐариÑовано: Constructed by %s ÐариÑовано: %s\n---------------------------------------- construction speed СкороÑть ÑтроительÑтва Construction_Btn ПоÑтройки Consumed ИÑпользовано contains the following doubled objects:

Ñодержит Ñледующие объекты более одного раза:

convoi %d of %d Ñ‚/Ñ %d из %d convoi error tooltips Значки ошибок над Ñ‚/Ñ Convoi has been sent\nto the nearest depot\nof appropriate type.\n Т/Ñ Ð±Ñ‹Ð»Ð¾ поÑлано\nв ближайшее депо\nподходÑщего типа. Convoi is sold when all wagons are empty. Т/Ñ Ð±ÑƒÐ´ÐµÑ‚ продано как только будет полноÑтью оÑвобождено convoi mouseover tooltips Значки над Ñ‚/Ñ Ñƒ курÑора convoi passed last\nmonth %i\n За прошлый меÑÑц\nпрошло %i Ñ‚/Ñ\n Convois ТранÑп. ед. Convois: %d\nProfit: %s Т/Ñ: %d\nПрибыль: %s Convoys ТранÑп. ед. Copy Convoi Скопировать Ñ‚/Ñ Copy the selected convoi and its schedule or line Копировать выбранное Ñ‚/Ñ Ð¸ его раÑпиÑание или линию\n\n Copy to clipboard Скопировать в буфер обмена Cost СтоимоÑть cost for removal СтоимоÑть ликвидации Cost per unit СтоимоÑть за единицу Cost: %8s (%.2f$/km %.2f$/m)\n СтоимоÑть: %s (%.2f$/км %.2f$/меÑÑц)\n Cost: %8s (%.2f$/km)\n СтоимоÑть: %8s (%.2f$/км)\n Costs Затраты Create a new line based on this schedule Создать новую линию, оÑновываÑÑÑŒ на Ñтом раÑпиÑании curiosity builder ПоÑтроить доÑтопримечательноÑть curlist_title СпиÑок доÑтопримечательноÑтей Currently playing: Ð¡ÐµÐ¹Ñ‡Ð°Ñ Ð·Ð²ÑƒÑ‡Ð¸Ñ‚: Customers live in: ПоÑетители живут в: Date format Формат даты deactivated in online mode Ðе активен в Ñети Dec. Дек. Deccelerate time Замедлить Ð²Ñ€ÐµÐ¼Ñ December Декабрь decrease underground view level уменьшить уровень подземного режима Del Stop Удалить Delete Line Удалить линию Delete the current stop Удалить данную оÑтановку Delete the selected line (if without associated convois). Удалить выбранную линию (еÑли она не обÑлуживаетÑÑ Ð½Ð¸ одним Ñ‚/Ñ) Delete this file. Удалить Ñтот файл. Delivered Отправлено Demand ПотребноÑть Demand: %.0f MW Ðужно: %.0f МВт\n Denkmal Монумент Departed Отправлено Departs at ОтправлÑетÑÑ Ð² (dd:hh:mm) Departure board Ð’Ñ€ÐµÐ¼Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Departures per month ÐžÑ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð° меÑÑц Departures to\n Отправление в\n Depots Депо Der Tunnel ist nicht frei!\n Тоннель не пуÑÑ‚!\n\n\n Destination Прибытие Destroying map ... ОчиÑтка карты... Details Детали Die Bruecke ist nicht frei!\n МоÑÑ‚ неÑвободен!\n diesel дизельный привод directmail ÐŸÐ¾Ñ‡Ñ‚Ð¾Ð²Ð°Ñ Ñ€Ð°ÑÑылка Direkt erreichbare Haltestellen ПрÑмые маршруты отÑюда: disable midi Выключить музыку Display settings ÐаÑтройки графики Distance РаÑÑтоÑние distributing cities раÑпределение городов distributing factories раÑпределение фабрик Do not show Ðе показывать Dock Порт Dock must be built on single slope! Порт должен ÑтроитьÑÑ Ð½Ð° ровном Ñклоне. Downloading Загрузка dp_title СпиÑок депо Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Ð”Ð»Ñ Ð²Ñ‹Ð¿Ð»Ð°Ñ‚Ñ‹ долга у Ð’Ð°Ñ Ð¾ÑталоÑÑŒ %d меÑÑцев. Durchsatz МакÑ. Economy Экономика и города Eigenbesitz\n МуниципальнаÑ\nÑобÑтвенноÑть\n Ein %s\npasst hier nicht.\n "%s"\nне помеÑтитÑÑ Ð·Ð´ÐµÑÑŒ!\n Einstellungen ÐаÑтройки Einstellungen aendern ÐаÑтройки игры electric Ñлектро Electricity ЭлектричеÑтво Electricity producer\n\n Производитель ÑлектричеÑтва\n\n Electrics_tab Т/c на ÑлектротÑге Electrify track Электрифицировать путь enlarge map РаÑширить карту enter a value between %i and %i Введите значение между %i и %i Enter address Введите Ð°Ð´Ñ€ÐµÑ Enter Password Ввод Ð¿Ð°Ñ€Ð¾Ð»Ñ Error Ошибка Erzeuge neue Karte.\n ПожалуйÑта, подождите,\nÑоздаётÑÑ Ð½Ð¾Ð²Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð°.\n\n (Это может занÑть\n неÑколько минут\n Ð´Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… карт)\n Es wird bereits\nein Fahrplan\neingegeben\n СоздаетÑÑ\nраÑпиÑание.\nЗакончите его\nперед упорÑдочиванием!\n Fabrikanschluss Соединенные предприÑÑ‚Ð¸Ñ Fabrikname назв. фабрики Factories Фабрики factory details Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ предприÑтии factorybuilder ПоÑтроить предприÑтие Fahrplan РаÑпиÑание Fahrtziel Прибытие: Fahrzeuge koennen so nicht entfernt werden ТранÑпортное ÑредÑтво\nне может быть убрано\nтаким образом!\n Fahrzeuge: Т/Ñ: Farbe Цвет игрока Fast forward УÑкорить Ð²Ñ€ÐµÐ¼Ñ Feb. Фев. February Февраль Ferry_tab Паромы Fertig Готово Filename Игра: Files from: Файлы из: Filter: Фильтр: Finances of %s ФинанÑÑ‹ %s Finanzen ФинанÑÑ‹ find mismatch Ðайти неÑоответÑÑ‚Ð²Ð¸Ñ fl_title СпиÑок фабрик Flug_tab ПаÑÑажирÑкие Ñамолеты follow me Следовать за Ñ‚/Ñ Follow the convoi on the map. Следовать за Ñ‚/Ñ Ð½Ð° карте. font size размер шрифта Forest Ð›ÐµÑ Found new city ОÑновать новый город FPS: Кадров в Ñек: Fracht Грузы Frame time: Ð’Ñ€ÐµÐ¼Ñ ÐºÐ°Ð´Ñ€Ð°: Free Capacity ПроÑтой freeplay mode Играть без банкротÑтва Freight Груз Friction: Текущий фактор трениÑ: fuel_cell Ñлемент Ð¿Ð¸Ñ‚Ð°Ð½Ð¸Ñ Full load Ожидание минимальной загрузки Fullscreen (changed after restart) ПолноÑкранный (изменÑетÑÑ Ð¿Ð¾Ñле перезапуÑка) Fundament Фундамент Fussgaenger Пешеход Game info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ игре GAME PAUSED ИГРРПРИОСТÐÐОВЛЕÐÐ Game_msg Общее Gear: ОÑнаÑтка: Gebaeude Строение General Общие Generated Сгенерировано Generation: %.0f MW ПроизводÑтво: %.0f МВ\n Gewicht Ð’ÐµÑ Gewinn Доход: Give the selected vehicle(s) an individual schedule Ðазначить выбранным Ñ‚/Ñ Ð¸Ð½Ð´Ð¸Ð²Ð¸Ð´ÑƒÐ°Ð»ÑŒÐ½Ð¾Ðµ раÑпиÑание gl_btn_sort_catg по категории gl_title СпиÑок грузов go home Ð’ депо Goods Грузы Goods AI ИИ грузы Goods list СпиÑок товаров Gross Profit Ð’Ð°Ð»Ð¾Ð²Ð°Ñ Ð¿Ñ€Ð¸Ð±Ñ‹Ð»ÑŒ Groundobj Ðаземный объект Grow city Увеличить город Growth РоÑÑ‚ города GUI settings ÐаÑтройка графики H оÑтановка Hangar Ðнгар Happy СчаÑтливы Haus kaufen Купить здание Helligk. Графика Help Справка по игре Help text not found ТекÑÑ‚ Ñправки не найден hide all building Скрыть вÑе Ð·Ð´Ð°Ð½Ð¸Ñ hide city building Скрыть городÑкие Ð·Ð´Ð°Ð½Ð¸Ñ hide objects under cursor Скрыть объекты вокруг курÑора радиуÑом: hide station names Ñкрыть Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¾Ñтановок hide transparent ПрозрачноÑть вмеÑто ÑÐºÑ€Ñ‹Ñ‚Ð¸Ñ hide trees Скрыть Ð´ÐµÑ€ÐµÐ²ÑŒÑ Hier warten/lagern: Ожидание грузов и паÑÑажиров Higher transport fees, crossconnect all factories Ð’Ñ‹Ñшие транÑпортные Ñборы, выключенные вовремÑ. Highlite schedule ПодÑвечивать маршрут hl_title СпиÑок Ñтанций hl_txt_filter Фильтр: hl_txt_sort Сортировать по: hlf_chk_airport ÐÑропорты hlf_chk_anleger Док hlf_chk_bahnhof Ж/д ÑÑ‚Ð°Ð½Ñ†Ð¸Ñ hlf_chk_bushalt ÐвтобуÑÐ½Ð°Ñ Ð¾Ñтановка hlf_chk_frachthof ÐŸÐ¾Ð³Ñ€ÑƒÐ·Ð¾Ñ‡Ð½Ð°Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð° hlf_chk_keine_verb нет ÑвÑзи hlf_chk_maglevstop ОÑтановка маглева hlf_chk_monorailstop ОÑтановка монорельÑа hlf_chk_name_filter Фильтр по имени: hlf_chk_narrowgaugestop ОÑтановка узкоколейки hlf_chk_overflow Сверх вмеÑтимоÑти hlf_chk_spezial_filter Спец. фильтр: hlf_chk_tramstop Ð¢Ñ€Ð°Ð¼Ð²Ð°Ð¹Ð½Ð°Ñ Ð¾Ñтановка hlf_chk_type_filter Типы фильтров: hlf_chk_waren_abgabe ПроизводÑтво: hlf_chk_waren_annahme ТребуютÑÑ Ñ‚Ð¾Ð²Ð°Ñ€Ñ‹: hlf_title Фильтр ÑпиÑка Ñтанций Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. ИÑходное депо не найдено!\nÐ’Ñ‹ должны поÑлать Ñ‚/Ñ\nв депо вручную. Homeless Бездомные hydrogene водородный привод Idle: ПроÑтой: ignore climates Игнорировать климат In the industry legend show only currently existing factories Во вкладке "ПроизводÑтво" отобразÑÑ‚ÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ текущие на карте предприÑтиÑ. In Transit Ð’ пути Increase Industry density Увеличить плотноÑть промышленноÑти increase underground view level увеличить уровень в подземном режиме industrial building Промышленное Ñтроение Init map ... Подготовка карты ... Input Потребл. Ins Stop Ð’Ñтавить Insert stop before the current stop Ð’Ñтавить оÑтановку перед текущей Insufficient funds! ÐедоÑтаточно ÑредÑтв! Intercity road len: Длина междугородних дорог Intro. date Ðачало произв. Intro. date: Ðачало ÑкÑпл.: invalid неопределенный. Invalid coordinate Ðеверные координаты isometric map ИзометричеÑкий вид карты January Январь join game Интернет July Июль Jump to Перейти к June Июнь Kann Spielstand\nnicht laden.\n Ðе могу загрузить\nÑохранённую игру!\n Kann Spielstand\nnicht speichern.\n Ðе могу открыть Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи\nфайл Ñ Ñохранением игры!\n Kein Besitzer\n Ðет владельца\n keine нет Keine Einzelfahrzeuge im Depot Т/Ñ Ð½Ðµ хранÑÑ‚ÑÑ Ð·Ð´ÐµÑÑŒ Keyboard_Help\n ГорÑчие клавиши\n koord координаты Kreuzung ПерекрёÑток labellist_title СпиÑок меток Lade Relief Загрузить рельеф Laden Загрузить Land attraction Ð—Ð°Ð³Ð¾Ñ€Ð¾Ð´Ð½Ð°Ñ Ð´Ð¾ÑтопримечательноÑть Land industries Произв. цепочки: LANG_CHOOSE\n ПожалуйÑта, выберите\nВаш Ñзык:\n LARGE_NUMBER_STRING M LARGE_NUMBER_VALUE 1e6 Last Month Ð’ прош. меÑÑце Last used tools ПоÑледние иÑпользованные инÑтрументы Last Year Прошл. год: Leaving depot! Покидает депо! leer пуÑтой Legend обознач.\n\n Leistung МощноÑть Leistung: %d kW МощноÑть: %d кВт Leitung ЛЭП length: %d длина: %d letzen Monat: diesen Monat: Пред. меÑÑц: Ñтот меÑÑц: Line Ð›Ð¸Ð½Ð¸Ñ Line Management Управление линиÑми Lineless convoys serving this stop Т/Ñ Ð±ÐµÐ· линий, обÑлуживающие Ñту оÑтановку: Lines serving this stop Линии, обÑлуживающие Ñту оÑтановку: List of industries on the map СпиÑок предприÑтий на карте LKW_tab Грузовики Load game Загрузить load height data from file Загрузить данные рельефа из файла Load scenario Сценарий loaded загружено loaded passenger/freight Сортировка паÑÑажиров/грузов: Loading (%i->%i%%)! Погрузка (%i->%i%%) Loading addon paks ... Загрузка дополнений паков ... Loading map ... Загрузка карты ... Loading paks ... Загрузка графичеÑких пакетов ... Loading skins ... Загрузка Ñкинов ... Lock game Запретить изменение игрока (нужно подтверждение) Lokomotive_tab Локомотивы m3 м³ Maglev Маглев maglev vehicle поезд маглев maglev_track Путь Ð´Ð»Ñ Ð¼Ð°Ð³Ð»ÐµÐ²Ð° Maglevdepot Депо Ð´Ð»Ñ Ð¼Ð°Ð³Ð»ÐµÐ²Ð° Mail Demand %d\n Ð¡Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ñ‡Ñ‚Ñ‹ %d\n Mailbox Центр Ñообщений Mailbox Options ÐаÑтройки Ð¾Ð¿Ð¾Ð²ÐµÑ‰ÐµÐ½Ð¸Ñ Maintenance Содержание make stop public (or join with public stop next) costs %i per tile and level Ñоздать публичную оÑтановку (или приÑоединить к ÑоÑедней публичной оÑтановке), ÑтоимоÑтью %i$ за клетку и уровень Make way or stop public (will join with neighbours), %i times maintainance Сделать путь или оÑтановку публичной (объединÑет Ñ ÑоÑедними) %i обÑлуживание Manual (Human) Ручной (Человек) Manufactured: ПоÑтроен: Map roughness ÐеровноÑть рельефа: map zoom МаÑштаб March Март Margin (%%) Маржа Marker Метка max макÑ. Max Boost (%%) МакÑ. уÑкорение (%%) Max income: МакÑ. доход: Max. speed МакÑ. Ñкор. Max. speed: МакÑ. ÑкороÑть: Maximum 254 stops\nin a schedule!\n МакÑимум 254 оÑтановки\nв раÑпиÑании!\n maximum length of rivers МакÑ. длина рек Maximum tile height difference reached. Разница выÑоты между Ð´Ð²ÑƒÐ¼Ñ ÐºÐ»ÐµÑ‚ÐºÐ°Ð¼Ð¸ не может превышать 2 ÑƒÑ€Ð¾Ð²Ð½Ñ Maxspeed МакÑ. ÑкороÑть May Май Median Citizen per town Ср. кол-во жителей на город Meldung Сообщение Menge количеÑтво MessageOptionsText \nÐовый год\n\nÐовоÑти ИИ\n\nГородÑкие новоÑти\n\nБез маршрута\n\nÐовые производÑтва\n\nболтать\n\nÐовые Ñ‚/Ñ\n\nЗаполение Ñтанций\n\nПроблемы\n\nTraffic jam\n\nScenario min мин. minimum length of rivers Мин. длина рек Minimum load ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° Missing pakfiles Объекты отÑутÑтвуют! Modify the selected line Изменить выбранную линию Monate alt меÑÑцев Monorail ÐœÐ¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ monorail vehicle МонорельÑовое Ñ‚/Ñ monorail_track ÐœÐ¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ Monorailboden ОÑнование монорельÑа Monoraildepot Депо монорельÑа month wait time Ждать, времени: Months МеÑÑцы Monument Монумент Monuments Монументы Mountain height Ð’Ñ‹Ñота гор: Movingobj перемещение объекта Music playing disabled/not available Музыка отключена или недоÑтупна Music volume: ГромкоÑть музыки: mute sound Выключить звук Name Ðазвание Narrowgauge Узкоколейка Narrowgauge are not available yet! Узкоколейка еще недоÑтупна! narrowgauge vehicle узкоколейные Ñ‚/Ñ narrowgauge_track Узкоколейка Narrowgaugedepot Депо Ð´Ð»Ñ ÑƒÐ·ÐºÐ¾ÐºÐ¾Ð»ÐµÐ¹ÐºÐ¸ Net ID: %p ID Ñети: %p\n Net Wealth ЧиÑтые активы Net wealth near zero ЧиÑтые активы близки к нулю Neue Karte ÐÐ¾Ð²Ð°Ñ Ð¸Ð³Ñ€Ð° Neue Welt Создание новой игры new convoi Ðовое Ñ‚/Ñ New Line Добавить New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Создана Ð½Ð¾Ð²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ!\nТеперь Ð’Ñ‹ можете назначить линию,\nÐ²Ñ‹Ð±Ð¸Ñ€Ð°Ñ ÐµÑ‘ из предÑтавленного\nниже ÑпиÑка. New Vehicles Ðовые Ñ‚/Ñ Nickname: ИмÑ: no buildings hidden Ðе Ñкрывать Ð·Ð´Ð°Ð½Ð¸Ñ no convois Ðет Ñ‚/Ñ No goods are loaded onto this convoi. Грузы не будут грузитьÑÑ Ð½Ð° Ñто Ñ‚/Ñ no goods waiting Ðет ожидающих грузов no load Ðе грузить No Route Ðет пути No stop here! ИнÑтрумент иÑпользуетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ на оÑтановках. No suitable ground! Ðет подходÑщей земли! No terminal station here! ЗдеÑÑŒ нет терминала! no timeline без линии времени no tree Без деревьев No. of Factories Кол-во фабрик и магазинов Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n УÑтановите раÑпиÑание \nÑ‚/Ñ Ð¿ÐµÑ€ÐµÐ´ отправкой!\n none нет nord Север nordost Северо-воÑток nordwest Северо-запад Not allowed to make publicly owned ways! Запрещено делать общедоÑтупными ÑобÑтвенные пути! Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! РаÑпиÑание Ð½ÐµÐ»ÑŒÐ·Ñ \nпоменÑть во Ð²Ñ€ÐµÐ¼Ñ \nпоиÑка пути Not enough fields would remain. Вокруг фермы оÑталоÑÑŒ Ñлишком мало полей November ÐоÑбрь now ÑÐµÐ¹Ñ‡Ð°Ñ Now active as %s.\n Теперь играем за %s.\n nowhere нигде Number of rivers КоличеÑтво рек Object Объект Odometer: %s km Одометр: %s км Ok OK Oktober ОктÑбрь On loan since %i month(s) Кредит в течении %i меÑÑца(-ев) On this map, you are not\nallowed to change player!\n Эта игра заблокирована!\nСмена игрока невозможна!\n\n\n Only city chains Только городÑкие цепочки Only first %d differing paks reported. There are probably more. Указаны только первые %d различающиеÑÑ Ð½Ð°Ð±Ð¾Ñ€Ñ‹. ВероÑтно, их неÑколько больше. Only full Unicode fonts Шрифты только Ñ Ð¿Ð¾Ð»Ð½Ñ‹Ð¼ Юникодом Only land chains Только загородные цепочки Only one transformer per factory! Только один транÑформатор на фабрику! Only show goods which are currently handled by factories Отобразить грузы, обработанные фабриками open открыть. Operation ЭкÑÐ¿Ð»ÑƒÐ°Ñ‚Ð°Ñ†Ð¸Ñ Ops Profit Оп. прибыль Optionen ÐаÑтройки Or enter a server manually: Или введите Ñервер вручную: Origin ИÑходно ost ВоÑток Output Произв. Ownership Владелец Pak which may cause severe errors: Следующие объекты (наборы) отÑутÑтвуют (может привеÑти к разрыву транÑпортных ÑвÑзей): Pak which may cause visual errors: Следующие объекты (наборы) были заменены на Ñхожие: Pak(s) different: Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ð°(-ов): Pak(s) missing on client: Ðабор(-Ñ‹), отÑутÑтвующий в клиенте: Pak(s) not on server: Ðабор(-Ñ‹), отÑутÑтвующий на Ñервере: Pakset differences Ð Ð°Ð·Ð»Ð¸Ñ‡Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ наборами paletten Ñщ. Pas_tab ПаÑÑажирÑкие поезда Passagiere ПаÑÑажиров Passagierrate Ðаличие паÑÑажиров Passagierziele Ðазначение паÑÑ./почты Passenger AI ИИ паÑÑажиры Passenger Demand %d\n Ð¡Ð¿Ñ€Ð¾Ñ Ð½Ð° паÑÑажиров %d\n Passengers %d %c, %d %c, %d no route ПаÑÑажиры %d %c, %d %c, %d без маршрута Passengers %d %s, %d %s, %d no route ПаÑÑажиры %d %s, %d %s, %d без маршрута Password Пароль: Pause ПоÑтавить игру на паузу Pax <%i> Mail <%i> ПаÑÑажиры <%i> Почта <%i> PaxDest ÐÐ°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Percent Electricity Произв. ÑлектричеÑтва (%% от ÑпроÑа): Planes are not available yet! ÐÐ²Ð¸Ð°Ñ†Ð¸Ñ ÐµÑ‰Ñ‘ недоÑтупна! Plant tree ПоÑадить дерево player Игрок player -1 Игрок 1 player 0 ГоÑударÑтво player 1 Ðапик 128 ÐС player 10 Игрок 10 player 11 Игрок 11 player 12 Игрок 12 player 13 Игрок 13 player 2 Трикки ТранÑпорт player 3 Мейер Мувинг К° player 4 ВМ ЭкÑÐ¿ÐµÐ´Ð¸Ñ†Ð¸Ñ player 5 ООО "Ðш-ТранÑ" player 6 ПСК и Ко КГ player 7 Игрок 7 player 8 Игрок 8 player 9 Игрок 9 Please choose vehicles first\n Сначала выберите Ñ‚/Ñ\n Post Почта Postrate Ðаличие почты Power МощноÑть Power (MW) Ð­Ð½ÐµÑ€Ð³Ð¸Ñ (МВт) Power: МощноÑть: Power: %4d kW\n ЭнергиÑ: %4d КВт\n Powerlines ЛЭП Price Цена Problems_msg Проблемы Produced Произведено Produces: %.1f units/minute Производит: %.1f ед./мин. Production of %s has been stopped:\n%s\n ПроизводÑтво %s было прекращено:\n%s\n Production/Boost ПроизводÑтво/РоÑÑ‚ Produktion ПроизводÑтво Profit Прибыль promote to line ÐÐ¾Ð²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ q1 ВеÑна q2 Лето q3 ОÑень q4 Зима Query server Ð—Ð°Ð¿Ñ€Ð¾Ñ Ñервера rail car РельÑомобиль random Ñлучайно Random age Случайный возраÑÑ‚ Random map Ð¡Ð»ÑƒÑ‡Ð°Ð¹Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° Rathaus Ратуша Rating Рейтинг ratio_pax Соотношение Relevant актуальные Reliefkarte Карта Remove Удалить метку remove airstrips Удалить полоÑу remove channels Удалить каналы remove interm. signals Удалить промежуточные remove maglev tracks Удалить пути маглева remove monorails Удалить пути монорельÑа remove narrowgauge tracks Удалить пути узкоколейки remove powerlines Удалить ЛЭП remove roads Удалить дорогу remove tracks Удалить ж/д пути Remove wayobj %s Удалить объект %s replace other signals заменить другие Ñемафоры replace stop Заменить оÑтановку request closing закрытие запроÑа residential house Ð–Ð¸Ð»Ð°Ñ Ð¿Ð¾Ñтройка Restore natural slope ВоÑÑтановить еÑтеÑтвенный Ñклон Restwert: \nСтоимоÑть продажи: Retire date Дата уÑтарев. Retire. date: Конец ÑкÑпл.: return ticket Путь назад Revenue Выручка Revision: ВерÑиÑ: road дорога road vehicle Ðвтомобиль Roadsign Дорожный знак Rotate map Повернуть карту Rotation Вращение Routing Прокладка маршрута sack мешков sail ветер Saving map ... Сохранение карты ... Scenario complete: %i%% Сценарий завершен на %i%% Scenario Debug Ошибки Scenario Error Log Ошибки кода Scenario Goal Цель Scenario Info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Scenario information ОпиÑание Scenario Result Результаты Scenario Rules Правила Schedule changing! Изменение раÑпиÑаниÑ! Schienentunnel ПоÑтроить ж/д туннель Schiff_tab Корабли Schiffdepot Корабельное депо Schleppkahn_tab Баржи Screenshot Сделать Ñкриншот Search: ПоиÑк: Seasons Ð’Ñ€ÐµÐ¼Ñ Ð³Ð¾Ð´Ð° Sehenswuerdigkeit ДоÑтопримечательноÑть Select a server to join: Выберите Ñервер Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ: Select a theme for display Выберите тему игрового Ñкрана Select display font Выбор шрифта Sell the selected vehicle(s) Продать выбранные Ñ‚/Ñ sended Отправлено SEP_FRACTION , SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September СентÑбрь Server did not respond! Сервер не отвечает Serves Line: ОбÑл. линию: Service ОбÑлуживание set signal spacing ÐвтораÑÑтановка Ñемафоров Setting ÐаÑтройки Ship Корабль shops and stores Магазины и офиÑÑ‹ Show all Показать вÑÑ‘ show all building Показать вÑе Ð·Ð´Ð°Ð½Ð¸Ñ Show also vehicles no longer in production. Показать также Ñ‚/Ñ, которые больше не производÑÑ‚ÑÑ. Show also vehicles that do not match for current action. Показывать также Ñ‚/Ñ, которые не могут быть иÑпользованы Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð¾Ð³Ð¾ дейÑÑ‚Ð²Ð¸Ñ Show even servers with wrong version or pakset Также отображать Ñервера Ñ Ð¸Ð½Ð¾Ð¹ верÑией или наборами. show grid Отобразить Ñетку Show industry ПроизводÑтво Show legend Легенда Show map scale Шкала выÑот Show mismatched Показать Ð¾Ñ‚Ð»Ð¸Ñ‡Ð¸Ñ Show obsolete Показать уÑтаревшие\n\n Show offline Показать отключенные Show only used Показать текущие предприÑÑ‚Ð¸Ñ Show schedules Показать раÑпиÑÐ°Ð½Ð¸Ñ Show servers that are offline Показать Ñервера, отключенные от Ñети, в данный момент. Show servers where game version or pakset does not match your client Показать Ñервера, верÑÐ¸Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… или ÑоÑтав наборов отличатÑÑ Ð¾Ñ‚ вашего клиента. show station coverage Показать покрытие Ñтанций show station names ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ñтанций/оÑтановок show waiting bars Индикатор ожидающих show/hide block reservations Вкл/выкл показ Ñ€ÐµÐ·ÐµÑ€Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² Show/hide estimated arrival times Вкл/выкл ожидаемое Ð²Ñ€ÐµÐ¼Ñ Ð¿Ñ€Ð¸Ð±Ñ‹Ñ‚Ð¸Ñ show/hide object owner Вкл/выкл показ владельца объекта Show/hide statistics Показать/Ñкрыть ÑтатиÑтику Shows buttons on special topics. Отобразить кнопки уÑловных обозаначений. Shows consumer/suppliers for factories Показать потребителей/поÑтавщиков Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¿Ñ€Ð¸Ñтий Shows the color code for several selections. Отобразить цветовую шкалу выÑот. Shows the currently selected schedule Показать текущее раÑпиÑание Shrink city Уменьшить город shuffle midis Играть в Ñлучайном порÑдке Signal Сигнал signal spacing РаÑÑтоÑние между Ñигналами Sim: Сим-циклы: Similar view as the main window Отображать карту так же, как отображаетÑÑ Ð¸Ð³Ñ€Ð¾Ð²Ð¾Ðµ окно. Size (%d MB): Размер (%d Мб): sliced underground mode Z-уровень slot empty ПуÑтой Ñлот Smart hide objects ЧаÑтичное Ñокрытие Sort by Сортировать паÑÑажиров/грузы по: Sort by: Сорт. по: Sort waiting list by Сортировка ÑпиÑка ожиданиÑ: Sound Звук Sound settings ÐаÑтройка звука Sound volume: ГромкоÑть звука: special freight оÑобый груз Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. УÑкорение:\nдорога %i км/ч, ж/д %i км/ч\nкорабли %i км/ч, Ñамолёты %i км/ч. Speedlimit Огр. ÑкороÑти Speichern Сохранить Spieler Игрок Spieler(mz) Игроки Spielerliste СпиÑок игроков Spielstand wurde\ngeladen!\n \nИгра уÑпешно загружена!\n Spielstand wurde\ngespeichert!\n \nИгра уÑпешно Ñохранена!\n Sprache Язык Sprachen Языки Stadtinformation ГородÑÐºÐ°Ñ ÑтатиÑтика Start ПуÑк Start the selected vehicle(s) Отправить на линию выбранные Ñ‚/Ñ Starte Spiel Ðачать игру Station tiles: Секции cтанции: Station_msg Станции Status Ð¡Ñ‚Ð°Ñ‚ÑƒÑ steam Ð¿Ð°Ñ€Ð¾Ð²Ð°Ñ Ñ‚Ñга Step timeline one year ПеревеÑти Ð²Ñ€ÐµÐ¼Ñ Ð½Ð° год вперёд Stops ОÑтановки Storage Склад Storage capacity ВмеÑтимоÑть Ñклада Strassendepot Гараж Strassentunnel Ðвтомобильный туннель street car ЧаÑтное авто sued Юг suedost Юго-воÑток suedwest Юго-запад Summer snowline ЛетнÑÑ Ð»Ð¸Ð½Ð¸Ñ Ñнега Supplied: %.0f %% ДоÑтавлено: %.0f %% Suppliers ПоÑтавщики Tage alt дней Theme selector Выбор темы There are still vehicles\nstored in this depot!\n ОÑталиÑÑŒ транÑпортные ÑредÑтва,\nразмещённые в депо!\n This Month Ð’ Ñтом меÑÑце This Year Ð’ Ñтом году: Tile not empty. УчаÑток не пуÑÑ‚.\nПожалуйÑта, удалите вÑÑ‘\nперед поÑтройкой\n иÑкуÑÑтвенного уклона. timeline ИÑпользовать линию времени tl_title СпиÑок городов To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Чтобы привлечь больше\nтуриÑтов в %s, \nбыл поÑтроен %s \nпо доÑтижении %i налогоплательщиков. To heavy traffic\nresults in traffic jam.\n Слишком плотное движение\nвызвало пробку на дороге.\n Toggle day/night view Вкл/выкл цикл Ð´Ð½Ñ Ð¸ ночи Toggle vehicle tooltips Вкл/выкл подÑказки по Ñ‚/Ñ tonnen Ñ‚ Total inhabitants: Общее наÑеление: Tourist attractions ДоÑтопримечательноÑти Tourists ДоÑтоприм. Town_msg Ðовые Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Town: %s\n Город %s\n Towns Города track путь Tracks Ж/д пути Traffic Движение Train Поезд Trains are not available yet! Поезда ещё недоÑтупны! Tram Трамвай tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. трамвай %i км/ч, Ð¼Ð¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ %i км/ч\nмаглев %i км/ч, узкоколейка %i км/ч. tram_track трамвайный путь Tramdepot Трамвайное депо Trams are not available yet! Трамваи ещё недоÑтупны! Transferring game ... Передача игры... Transformer only next to factory! ТранÑÑ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ñ€Ð½Ð°Ñ Ð¿Ð¾Ð´ÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть около предприÑÑ‚Ð¸Ñ Translation Перевод transparent station coverage ÐŸÑ€Ð¾Ð·Ñ€Ð°Ñ‡Ð½Ð°Ñ Ð·Ð¾Ð½Ð° Ð¿Ð¾ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Transported Перевезено Trees disabled! Ð”ÐµÑ€ÐµÐ²ÑŒÑ Ð·Ð°Ð¿Ñ€ÐµÑ‰ÐµÐ½Ñ‹! TrolleyBus_tab троллейбуÑÑ‹ Truck Грузовик tt_Other Другое Tunnel muss an\neinfachem\nHang beginnen!\n Туннели должны начинатьÑÑ\nна прÑмом Ñклоне!\n Tunnel must start on single way! Туннели должны начинатьÑÑ Ð½Ð° одиночном пути! Tunnelboden Туннель underground mode Подземный режим UNDO failed! Отмена больше недоÑтупна.\nÐ’Ñ‹ можете отменить Ñоздание \nмаршрута только еÑли на нём \nне будет поÑтроено Ñигналов /\nÑтанций / оÑтановок или ещё \nчего-нибудь. Undo last ways construction Отменить поÑледнюю поÑтройку пути Unemployed Безработные Unhappy ÐеÑчаÑтны units/day ед./меÑÑц Update Line Изменить upgrade HQ Улучшить Ð¾Ñ„Ð¸Ñ Usage: %.0f %% ИÑпользование: %.0f %% Usage/Output Потребление/производÑтво Use beginner mode Режим "новичок" Use timeline start year Режим Ñ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ Vehicle %s can't find a route! %s\nне может найти путь! Vehicle %s is stucked! %s в пробке! Vehicle details Подробнее Vehicle Name Ðазвание Vehicle Power МощноÑть Verbrauch Потребление Vergroessere die Karte\n РаÑширить карту.\n Verkauf Уничтожить verkaufen Продажа Verkehrsteilnehmer Гор. транÑп. Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n У Ð’Ð°Ñ Ð¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð»Ð°ÑÑŒ задолженноÑть!\n\nОÑталоÑÑŒ %d меÑÑц(а,ев)\nчтобы выплататить долг!\n vh_title СпиÑок вÑех транÑпортных ÑредÑтв via через (детали) via %s\n через %s\n via Menge через (кол-во) voranstellen ВывеÑти Waggon_tab Вагоны waiting ожидает Waiting for clearance! Путь занÑÑ‚! Walked Пешеходы walking Пешеходы Warnings_msg Трафик Wasser Вода Water Канал Water level Уровень воды: water vehicle Водное Ñ‚/Ñ way %s cannot longer used:\n Дороги типа %s не могут больше иÑпользоватьÑÑ.\n way %s cannot longer used:\n%s\n Дороги типа %s не могут больше иÑпользоватьÑÑ.\n%s\n way %s now available:\n Теперь доÑтупны дороги типа %s.\n Way toll Дорожный налог Ways not connected Дороги не Ñоединены Wegpunkt Точка пути Weight Ð’ÐµÑ Weight: МаÑÑа: Wert СтоимоÑть west Запад Wind direction Ðаправление ветра Winter snowline ЗимнÑÑ Ð»Ð¸Ð½Ð¸Ñ Ñнега withdraw Продать Withdraw All Продать вÑе WRONGSAVE \nÐеÑовмеÑÑ‚Ð¸Ð¼Ð°Ñ Ð²ÐµÑ€ÑиÑ\nÑохранениÑ. Ðе могу загрузить\nÑтот файл.\n Year %i has started. ÐачалÑÑ %i год. Years Годы Your primary color: ОÑновной цвет: Your secondary color: Вторичный цвет: Zielort пункт Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ zooming in Приблизить камеру zooming out Отдалить камеру Zu nah am Kartenrand Слишком близко\nк краю карты,\nчтобы что-то Ñтроить!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Ðовый мировой рекорд ÑкороÑти маглева: %.1f км/ч, %s. New world record for monorails: %.1f km/h by %s. УÑтановлен новый мировой \nрекорд ÑкороÑти Ð´Ð»Ñ \nмонорельÑовых Ñ‚/Ñ %.1f км/ч -\n%s New world record for motorcars: %.1f km/h by %s. УÑтановлен новый мировой \nрекорд ÑкороÑти Ð´Ð»Ñ \nавтомобилей %.1f км/ч -\n%s New world record for narrowgauges: %.1f km/h by %s. Ðовый мировой рекорд ÑкороÑти Ð´Ð»Ñ ÑƒÐ·ÐºÐ¾ÐºÐ¾Ð»ÐµÐ¹Ð½Ñ‹Ñ… Ñ‚/Ñ: %.1f км/ч, %s. New world record for planes: %.1f km/h by %s. УÑтановлен новый мировой \nрекорд ÑкороÑти Ð´Ð»Ñ \nавиации %.1f км/ч -\n%s New world record for railways: %.1f km/h by %s. УÑтановлен новый мировой \nрекорд ÑкороÑти на железных\nдорогах %.1f км/ч -\n%s New world record for ship: %.1f km/h by %s. УÑтановлен новый мировой \nрекорд ÑкороÑти Ð´Ð»Ñ Ð²Ð¾Ð´Ð½Ð¾Ð³Ð¾\nтранÑпорта %.1f км/ч -\n%s #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL Ð´ÐµÑ€ÐµÐ²Ð½Ñ &1_CITY_SYLL каменÑк &2_CITY_SYLL водÑк &3_CITY_SYLL дар &4_CITY_SYLL перекопÑк &5_CITY_SYLL реченÑк &6_CITY_SYLL озёрÑк &7_CITY_SYLL полье &8_CITY_SYLL горÑк &9_CITY_SYLL лодÑк &A_CITY_SYLL братÑк &B_CITY_SYLL по &C_CITY_SYLL закапывать %1_CITY_SYLL Северо %2_CITY_SYLL Мало %3_CITY_SYLL Бело %4_CITY_SYLL Дальне %5_CITY_SYLL ПÑти %6_CITY_SYLL Светло %7_CITY_SYLL Ðижне %8_CITY_SYLL Верхне %9_CITY_SYLL Ðово %A_CITY_SYLL Старо %B_CITY_SYLL Ð’Ñ‹Ñоко 0center %s центр %s 0extern %s Ñело %s 0suburb %s пригород %s 1center %s %s 1extern %s %s ветка 1suburb %s, %s%s ÑÑ‚Ð°Ð½Ñ†Ð¸Ñ 2center %s %s Ñ†ÐµÐ½Ñ‚Ñ€Ð°Ð»ÑŒÐ½Ð°Ñ 2extern %s %s ближнÑÑ 2suburb %s ÐŸÐ¾Ð»Ñ %s %s 3center %s %s Ð³Ð»Ð°Ð²Ð½Ð°Ñ 3extern %s %s облаÑть 3suburb %s Ð´ÐµÑ€ÐµÐ²Ð½Ñ %s %s 4center %s %s внутреннÑÑ 4extern %s %s дальнÑÑ 4suburb %s деревенÑкий %s 5center %s %s Ð³Ñ€ÑƒÐ·Ð¾Ð²Ð°Ñ 5extern %s переÑÐ°Ð´Ð¾Ñ‡Ð½Ð°Ñ %s 5suburb %s город %s 6center %s СвÑзь %s 6extern %s Биржа %s 6suburb %s окраина %s %s 7center %s город %s 7extern %s проÑÑ‚Ð°Ñ %s 7suburb %s парк %s 8center %s Ð´ÐµÐ»Ð¾Ð²Ð°Ñ %s 8extern %s %s запаÑÐ½Ð°Ñ %s 8suburb %s пригород %s 9center %s оÑÐµÐ²Ð°Ñ %s 9extern %s Ð¾Ð±ÑŠÐµÐ·Ð´Ð½Ð°Ñ %s 9suburb %s Ð¿Ñ€Ð¾Ð¼ÐµÐ¶ÑƒÑ‚Ð¾Ñ‡Ð½Ð°Ñ %s Acenter %s центр %s Bcenter %s центр %s Ccenter %s центр %s Dcenter %s центр %s Ecenter %s центр %s Fcenter %s центр %s Gcenter %s центр %s Hcenter %s центр %s Icenter %s центр %s Jcenter %s центр %s Kcenter %s центр %s Lcenter %s центр %s Mcenter %s центр %s Ncenter %s центр %s Ocenter %s центр %s Pcenter %s центр %s Qcenter %s центр %s Rcenter %s центр %s Scenter %s центр %s Tcenter %s центр %s Ucenter %s центр %s Vcenter %s центр %s Wcenter %s центр %s Xcenter %s центр %s Ycenter %s центр %s Zcenter %s центр %s simutrans-124.3/simutrans/text/ru/000077500000000000000000000000001474050137200172125ustar00rootroot00000000000000simutrans-124.3/simutrans/text/ru/airtools.txt000066400000000000000000000224771474050137200216230ustar00rootroot00000000000000ÐвиациÑ

ÐвиациÑ

Меню авиации Ñодержит инÑтрументы Ð´Ð»Ñ Ð¿Ð¾Ñтройки вÑех Ñлементов Ñети воздушного транÑпорта: поÑтройка и удаление рулежных и взлетно-поÑадочных полоÑ; Ñтанций, терминалов, Ñкладов и погрузочных платформ; Ñамолетных ангаров и других зданий. При игре в режиме Ñ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸, возможно поÑвление других возможноÑтей.

Ðажмите на иконку Ñамолета на главной панели инÑтрументов, чтобы открыть меню авиации.
Ð—Ð°Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°Ñ ÐºÑƒÑ€Ñор мышки над какой-либо иконкой, Ð’Ñ‹ можете видеть название объекта, цену поÑтройки, ÑтоимоÑть обÑÐ»ÑƒÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ (в круглых Ñкобках) в меÑÑц, макÑимально допуÑтимую ÑкороÑть и макÑимально возможный Ð²ÐµÑ Ñ‚/Ñ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ объекту (еÑли Ñто рулежные или взлетно-поÑадочные полоÑÑ‹)cost.

ПодÑказка: Одним из вариантов поÑтройки проÑтого аÑропорта:
1) поÑтройте взлетно-поÑадочную полоÑу;
2) Ñбоку приÑтройте к ней рулежную полоÑу;
3) на Ñвободном конце рулежной полоÑÑ‹ размеÑтите аÑровокзал или другой погрузочно-разгрузочный терминал;
4) на Ñвободном конце рулежной полоÑÑ‹ размеÑтите ангар Ð´Ð»Ñ Ñамолетов;
5) доÑтройте другие зданиÑ, еÑли Ñто необходимо.

Меню может ÑоÑтоÑть из Ñледующих кнопок (Ñлева направо):

Рулежные полоÑÑ‹: необходимы Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñамолетов по земле между взлетно-поÑадочными полоÑами, анагарами и погрузочно-разгрузочными терминалами. Они ÑтроÑÑ‚ÑÑ Ð½Ð° плоÑкой земле в главном игровом Ñкране.
Ð’ÐЖÐО: ЕÑли рулежную полоÑу приÑоединить к концу взлетно-поÑадочной, то Ñамолеты не Ñмогут пользоватьÑÑ Ð²Ð·Ð»ÐµÑ‚Ð½Ð¾-поÑадочной полоÑой.
Ð”Ð»Ñ Ð¿Ð¾Ñтройки нажмите на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид) и протÑните полоÑу в нужном меÑте. Ð’ Ñплывающем окошке будет указана ÑтоимоÑть ÑтроительÑтва.
ПодÑказка: ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ðµ нужного учаÑтка рулежной полоÑÑ‹. Отмена поÑледнего дейÑÑ‚Ð²Ð¸Ñ [z] не вернет Вам деньги, потраченные на ÑтроительÑтво.

Взлетно-поÑадочные полоÑÑ‹ (ВПП): необходимы Ð´Ð»Ñ Ð²Ð·Ð»ÐµÑ‚Ð° и поÑадки Ñамолетов. они ÑтроÑÑ‚ÑÑ Ð½Ð° плоÑкой земле в главном игровом Ñкране и могут переÑекатьÑÑ.
Ð”Ð»Ñ Ð¿Ð¾Ñтройки нажмите на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид) и протÑните полоÑу в нужном меÑте. Ð’ Ñплывающем окошке будет указана ÑтоимоÑть ÑтроительÑтва.
ПодÑказка: ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ðµ нужного учаÑтка ВПП. Отмена поÑледнего дейÑÑ‚Ð²Ð¸Ñ [z] не вернет Вам деньги, потраченные на ÑтроительÑтво.

Удалить полоÑу: удалит учаÑток рулежной или взлетно-поÑадочной полоÑÑ‹, еÑли на них нет Ñамолета. ИÑпользуйте Ñто Ð´Ð»Ñ Ð²Ð¾Ð·Ð¼ÐµÑ‰ÐµÐ½Ð¸Ñ ÑтоимоÑти поÑтройки.
Ð”Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ð°Ð¶Ð¼Ð¸Ñ‚Ðµ на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид), затем нажмите на удалÑемый Ñлемент полоÑÑ‹, протÑните Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÑкольких учаÑтков и отпуÑтите кнопку мыши.
ПодÑказка: Удалив Ñоединение ВПП Ñ Ð°Ñровокзалом, будьте готовы к тому, что Ñта полоÑа не Ñможет принимать/отправлÑть Ñамолеты. ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¾Ð´Ð¸Ð½Ð¾Ñ‡Ð½Ð¾Ð³Ð¾ учаÑтка полоÑÑ‹.

Самолетное депо (ангар): необходимо Ð´Ð»Ñ Ð¿Ð¾ÐºÑƒÐ¿ÐºÐ¸ и ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñамолетами. Их можно Ñтроить только на концах рулежных полоÑ. Ðнгары имеют ежемеÑÑчную ÑтоимоÑть обÑлуживаниÑ.
Ð”Ð»Ñ Ð¿Ð¾Ñтройки нажмите на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид) и поÑтройте ангар в нужном меÑте.
ПодÑказка: ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ðµ нужного ангара. Отмена поÑледнего дейÑÑ‚Ð²Ð¸Ñ [z] не вернет Вам деньги, потраченные на ÑтроительÑтво.

ÐÑровокзалы и поÑадочные рукава: нужны Ð´Ð»Ñ Ð¿Ð¾Ð³Ñ€ÑƒÐ·ÐºÐ¸ и разгрузки грузов и паÑÑажиров в/из Ñамолеты.
ЕÑли Ð’Ñ‹ поÑтроите здание не Ñ€Ñдом Ñ ÑƒÐ¶Ðµ ÑущеÑтвующей Ñтанцией, то получите новую Ñтанцию.
Их можно Ñтроить только на концах рулежных полоÑ. ÐÑровокзалы и терминалы имеют ежемеÑÑчную ÑтоимоÑть обÑÐ»ÑƒÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸ облаÑть охвата Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° грузов и паÑÑажиров от окружающих фабрик и зданий. Самолет приземлитьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ еÑли еÑть Ñвободный погрузочно-разгрузочный терминал.
Ð”Ð»Ñ Ð¿Ð¾Ñтройки нажмите на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид) и поÑтройте здание в нужном меÑте поверх рулежной полоÑÑ‹.
ПодÑказка: ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ðµ нужного зданиÑ. Отмена поÑледнего дейÑÑ‚Ð²Ð¸Ñ [z] не вернет Вам деньги, потраченные на ÑтроительÑтво.

Другие зданиÑ: тут перечиÑлены дополнительные зданиÑ, которые раÑширÑÑŽÑ‚ функционал уже поÑтроенных Ñтанций: увеличение емкоÑти Ñкладов, площади охвата. Они также могут иметь ежемеÑÑчную ÑтоимоÑть обÑлуживаниÑ. Ðа иконках таких зданий чаÑто указываетÑÑ, на какие грузы оно раÑчитано (паÑÑажиры, почта или грузы).
Ð”Ð»Ñ Ð¿Ð¾Ñтройки нажмите на ÑоответÑтвующую иконку (курÑор мыши должен изменить Ñвой вид) и поÑтройте здание в нужном меÑте возле ÑущеÑтвующего аÑровокзала или терминала.
ПодÑказка: ИÑпользуйте инÑтрумент Разрушить/Убрать Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð½Ðµ нужного зданиÑ. Отмена поÑледнего дейÑÑ‚Ð²Ð¸Ñ [z] не вернет Вам деньги, потраченные на ÑтроительÑтво.

simutrans-124.3/simutrans/text/ru/baum_build.txt000066400000000000000000000046021474050137200220600ustar00rootroot00000000000000ПоÑадка деревьев

ПоÑадка деревьев

Данное меню позволÑет вам выÑаживать в игре отдельные деревьÑ. Эта возможноÑть ноÑит чиÑто декоративный характер, Ñ‚.к. никако пользы от Ñтого дейÑÑ‚Ð²Ð¸Ñ Ð½ÐµÑ‚ (кроме ÑÑтетичеÑкой).

Ð’ левой чаÑти предÑтавлен ÑпиÑок вÑех ÑущеÑтвующих в игре деревьев, которые можно выÑадить. Две вкладки, Перевод и Объект позволÑÑŽÑ‚ выбрать вариант Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° - по названию дерева (Перевод) или по техничеÑкому его обозначению (Объект). Выберите какое-либо дерево и вы увидите больше информации о нем. Чтобы поÑадить дерево доÑтаточно выбрать его в ÑпиÑке и размеÑтить на игровой облаÑти Ñкрана.

Ð’ правой чаÑти перечиÑлены неÑколько параметров:
Игнорировать климат: возможноÑть раÑÑаживать Ð´ÐµÑ€ÐµÐ²ÑŒÑ Ð² любом климате.
Случайный возраÑÑ‚: обычно, ÑвежепоÑаженное дерево ÑвлÑетÑÑ Ñаженцем Ñ Ð½ÑƒÐ»ÐµÐ²Ñ‹Ð¼ возраÑтом. Затем, Ñ Ñ‚ÐµÑ‡ÐµÐ½Ð¸ÐµÐ¼ времени, дерево поÑтепенно раÑтет. Эта наÑтройка позволÑет раÑÑаживать Ð´ÐµÑ€ÐµÐ²ÑŒÑ Ñлучайного возраÑта - от Ñаженцев до Ñтарых больших деревьев.
Вращение: еÑли в графике дерева доÑтупны неÑколько вариантов его внешнего вида, Ñта наÑтройка позволит выбрать, какого именно внешнего вида будет размещаемое дерево. Также можно выбрать параметр "Ñлучайно", чтобы внешний вид дерева определÑлÑÑ Ñлучайным образом.

simutrans-124.3/simutrans/text/ru/citybuilding_build.txt000066400000000000000000000067231474050137200236300ustar00rootroot00000000000000ПоÑтройка городÑких зданий

ПоÑтройка городÑких зданий

Данный инÑтрумент дает возможноÑть Ñтроить городÑкие Ð·Ð´Ð°Ð½Ð¸Ñ Ð² любом меÑте, где Ð’Ñ‹ захотите. Ð”Ð°Ð½Ð½Ð°Ñ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾Ñть не ÑвлÑетÑÑ Ð¾Ð±Ñзательной, а более ÑÑтетичеÑкой.

Ð’ левой чаÑти предÑтавлен ÑпиÑок вÑех доÑтупных городÑких задний, которые можно поÑтройить. Две вкладки, Перевод и Объект позволÑÑŽÑ‚ выбрать вариант Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° - по названию Ð·Ð´Ð°Ð½Ð¸Ñ (Перевод) или по техничеÑкому его обозначению (Объект). Выберите какое-либо здание и вы увидите больше информации о нем. Чтобы поÑтроить здание доÑтаточно выбрать его в ÑпиÑке и размеÑтить на игровой облаÑти Ñкрана.

Ð’ правой чаÑти перечиÑлены неÑколько параметров:
Игнорировать климат: возможноÑть Ñтроить Ð·Ð´Ð°Ð½Ð¸Ñ Ð² любом климате.
Режим Ñ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸: показать только зданиÑ, доÑтупные в данный момент времени.
Показать уÑтаревшие: показать зданиÑ, которые были доÑтупны в прошлом.
Жилые зданиÑ: показать только зданиÑ, в которых проживают люди. Эти Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾ Ñамопроизвольно ÑтроÑÑ‚ÑÑ, когда город раÑширÑетÑÑ Ð¿Ñ€Ð¸ увеличении наÑелениÑ.
Магазины и офиÑÑ‹: показать только коммерчеÑкие зданиÑ. Эти Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¾ÑтавлÑÑŽÑ‚ рабочие меÑта и ведут торговлю (в том чиÑле и Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ°Ð¼Ð¸), они обычно ÑтроÑÑ‚ÑÑ Ð¿Ñ€Ð¸ большом количеÑтве безработных жителей в городе.
Промышленные зданиÑ: показать только фабрики. Эти Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¾ÑтавлÑÑŽÑ‚ рабочие меÑта и ведут торговлю (в том чиÑле и Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ°Ð¼Ð¸). Однако, в Ñтот ÑпиÑок не входÑÑ‚ большие промышленные фабрики (например, ЭлектроÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð¸Ð»Ð¸ Ð£Ð³Ð¾Ð»ÑŒÐ½Ð°Ñ ÑˆÐ°Ñ…Ñ‚Ð°), которые размещаютÑÑ Ð·Ð° городом и Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ Ñотрудничает игрок.
Вращение: еÑли в графике Ð·Ð´Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтупны неÑколько вариантов его внешнего вида, Ñта наÑтройка позволит выбрать, какого именно внешнего вида будет размещаемое здание. Также можно выбрать параметр "Ñлучайно", чтобы внешний вид Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÑлÑÑ Ñлучайным образом.

simutrans-124.3/simutrans/text/ru/color.txt000066400000000000000000000030221474050137200210660ustar00rootroot00000000000000Выбор цвета игрока

Выбор цвета игрока

ЗдеÑÑŒ Ð’Ñ‹ можете выбрать цвет компании игрока, который будет влиÑть на цвет названий оÑтановок, заголовки диалоговых окон, цвет текÑта бегущей Ñтроки новоÑтей в нижней чаÑти Ñкрана и объекты, принадлежащие игроку.

Выбор цвета игрока можно найти в игровом меню.

ПроÑто выберите, интереÑующий ВаÑ, цвет в таблице цветов.

Заголовок диалогового окна выбора цвет игрока изменитÑÑ Ð½Ð° выбранный Вами.

По умолчанию, цвет игрока - Ñветло-голубой.

Ðекоторые объекты не изменÑÑ‚ Ñвой цвет - Ñто завиÑит от, выбранного Вами, набора графики.

ПодÑказка: Чтобы изменить цвет компьютерного игрока иÑпользуйте ÑпиÑок игроков или кнопку P+ (Ñменить игрока) на панели ÑпецÑредÑтв, чтобы выбрать другого игрока.

simutrans-124.3/simutrans/text/ru/language.txt000066400000000000000000000022741474050137200215430ustar00rootroot00000000000000Языки

Окно « Языки » менÑет Ñзык, иÑпользуемый в игре. Он открываетÑÑ Ð¸Ð· окна «Параметры игры» и из окон «Создать новую игру» . Языком по умолчанию Ð´Ð»Ñ Simutrans ÑвлÑетÑÑ Ð°Ð½Ð³Ð»Ð¸Ð¹Ñкий. Чтобы играть в игру на другом Ñзыке, нажмите кнопку Ñ€Ñдом Ñ Ñзыком, на котором вы хотите играть. Язык можно изменить в любой момент во Ð²Ñ€ÐµÐ¼Ñ Ð¸Ð³Ñ€Ñ‹. Чтобы изменить Ñзык, выберите «Параметры игры» -> «Язык». Смена Ñзыка проиÑходит Ñразу при Ñоздании новой игры и при закрытии окна «Языки» при Ñмене игры в Ñередине игры.

ЕÑли перевод недоÑтупен на выбранном Ñзыке, он может поÑвитьÑÑ Ð½Ð° английÑком Ñзыке. Чтобы помочь в переводе Simutrans на ваш Ñзык, поÑетите https://translator.simutrans.com/.

simutrans-124.3/simutrans/text/sk.tab000066400000000000000000000776341474050137200177120ustar00rootroot00000000000000§Slovencina PROP_FONT_FILE prop-latin2.fnt ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: sk Slovencina # # Encoding: UTF-8 # # Font: prop-latin2.fnt # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ Absolute times Zobraz Äas ako den:hh:mm mesiaca AMBIENT_SOUND zvuky okolia CASH_SOUND zvuk pokladne cl_btn_filter_disable Vypnutý cl_btn_filter_enable Zapnutý cl_btn_filter_settings Nastavenia cl_btn_sort_asc Vzostupne cl_btn_sort_desc Zostupne cl_btn_sort_id Interné ID cl_btn_sort_income Príjem cl_btn_sort_name Názov cl_btn_sort_type Typ clf_btn_alle vÅ¡etko clf_btn_invers opak clf_btn_keine niÄ climate area percentage veľkosÅ¥ jedného podnebia Continue Game PokraÄovaÅ¥ v hre CROSSING_SOUND zvuk výstrah na križovatkách FACTORY_SOUND Zvuky tovární Find matching convois Nájdi konvoje ktoré sa zhodujú gl_btn_sort_bonus podľa príplatku gl_btn_sort_name podľa názvu gl_btn_sort_revenue podľa tržby gl_btn_unsort nezoradené height based Podnebie podľa výšky hl_btn_filter_disable Vypnutý hl_btn_filter_enable Zapnutý hl_btn_filter_settings Nastavenia hl_btn_sort_asc Vzostupne hl_btn_sort_desc Zostupne hl_btn_sort_name Názov hl_btn_sort_type Typ hl_btn_sort_waiting ÄŒakanie hlf_btn_alle vÅ¡etko hlf_btn_invers opak hlf_btn_keine niÄ humidities hranice vlhkosti Install InÅ¡talovaÅ¥ Lake Jazero Lake height max. výška jazier Maximize height levels zvýšiÅ¥ maximálnu výšku moisture land vzrast nad zemou moisture water vzrast nad vodou Networks Schéma siete Num pad keys always move map Numlock je vždy vypnutý Open Sea Oceán Queueing trend Äakania rainfall vlhkosÅ¥ Reselect closes tools vybranie nástroja znovu ho odloží Return to menu Späť do menu Road toll Mýto Scenario Info scenára sea námorné podnebie Single GUI jedno GUI Transfers Prestupy #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic arktické podnebie desert suché podnebie mediterran Subtropické podn. rocky alpská klíma temperate Mierne podnebie tropic Tropické podnebie tundra Polárne podnebie #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Nahranie scenára sa nepodarilo Cannot built depot here! Tu nemôžeÅ¡ postaviÅ¥ depo. Cannot create generic line!\nSelect line type by\nusing filter tabs. Linka nebola vygenerovaná !\nVyberte typ linky s použitím\nfiltra. Convoi handles exhausted! PoÄet konvojov dosiahol maximálnu hodnotu. Das Feld gehoert\neinem anderen Spieler\n Toto políÄko patrí inému hráÄovi !\n Der Besitzer erlaubt das Entfernen nicht Majiteľ Ti to nedovolí\nzbúrat.\n Flugzeughalt muss auf\nRunway liegen!\n Stojánka musí byÅ¥\nna rolovacej ploche. Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Tu nemôžeÅ¡ postaviÅ¥\nletiÅ¡tnú budovu.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Tu nemôžeÅ¡ postavit'\nžiadny signalizátor !\n Monorailhalt muss auf\nMonorail liegen!\n Stanica visutej železnice\nmusí byÅ¥ na trati. Monorails are not available yet! Visutá železnica eÅ¡te neexistuje. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Stanica úzkokoľajky musí ležaÅ¥ na trati. No suitable way on the ground! Nevhodný úsek pre stavbu stanice alebo zastávky! No through station here! Tu nie je možné postaviÅ¥ stanicu/zastávku. Not enough money! Nedostatok peňazí\nna stavbu. On narrowgauge track only!\n Len na úzkokoľajke!\n Only public player can lock games! Iba hrÃ¡Ä 'Verejnej služby' môže uzamknúť hru. Post muss neben\nHaltestelle\nliegen!\n PoÅ¡ta musí ležat \nvedľa zastávky !\n Schiffhalt muss im\nWasser liegen!\n Závory musia stát'\nna vode!\n Upgrade must have\na higher level Nová stanica musí byÅ¥ vyššej úrovne Vehicle %s cannot choose because stop too short! Vozidlo %s nemôže použiÅ¥ zastávku, pretože je príliÅ¡ krátka! Zughalt muss auf\nSchiene liegen!\n Stanica musí stáť\nna koľajniciach!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________ Sum of departure/arrivals at halts SúÄet množstva prijatého a odbaveného tovaru (cestujícich, poÅ¡ty) na zastávke. #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s vytvoril\npre turistov novú\nautobusovú linku\nmedzi \n%s a \n%s\n(na %i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s\nteraz prepravuje\nzamestancov z/zo \n%s\ndo závodu \n%s\n(na %i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nteraz používa\n%i nákladné vozidlá\nna prepravu medzi \n%s (na %i,%i) a \n%s (na %i,%i).\n %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\notvára novú\nželezniÄnú trat' medzi \n%s\n(na %i,%i) a \n%s\n(na %i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n SpoloÄnosÅ¥ %s\notvára leteckú linku\nmedzi mestami \n%s \na %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s\nvytvoril novú\nautobusovú linku\nmedzi \n%s a %s\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Nástroje pre tvorbu mapy LISTTOOLS Prehľady MAGLEVTOOLS Nástroje pre maglev MONORAILTOOLS Visutá železnica NARROWGAUGETOOLS Nástroje pre úzkokoľajku. RAILTOOLS ŽelezniÄná doprava ROADTOOLS Cestná doprava SHIPTOOLS Lodná doprava SLOPETOOLS ZoÅ¡ikmenie terénu SPECIALTOOLS Å peciálne nástroje TRAMTOOLS ElektriÄková doprava #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ New %s now available:\n%s\n Bola zahájená sériová výroba %s\n'%s'\n New factory chain\nfor %s near\n%s built with\n%i factories. Bolo postavené nové odvetvie\npriemyslu na %s\npri %s,\ncelkovo %i tovární\n New vehicle now available:\n%s\n Je dostupné nové vozidlo:\n>> %s <<\n Now %u clients connected. Práve je pÅ™ipojených %u hráÄov. Remove vehicle from map. Use with care! Odstránenie vozidla z mapy. PoužívaÅ¥ opatrne! Screenshot\ngespeichert.\n Screenshot uložený.\n Sends the convoi to the last depot it departed from! PoslaÅ¥ celý konvoj do nabližšieho depa ! With a big festival\n%s built\na new monument.\n%i citicens rejoiced. S veľkou parádou\nodhalilo mesto %s\nnovú atrakciu.\n%i obyvateľov oslavuje. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (v depe) \nBauzeit bis do \nBauzeit von \nVýstavba od \ndirection: \nsmery: \nelektrified \nelektrifikované \nis reserved by: \nobsadené vlakom \nminimum speed: \nnajnižšia povolená rýchlosÅ¥ \nnot elektrified \nneelektrifikované \nRibi (unmasked) \nSmery\n (skryté): \nsingle way \nJednosmerka %d buildings\n %d budov\n %d convois %d súprav %d Einzelfahrzeuge im Depot %d zoznam vozidiel v depe %i km/h (max. %ikm/h) %i km/h (max. %i km/h) %i years %i months old. %i rokov a %i mesiacov. %s at (%i,%i) now public stop. %s je teraz verejnou zastávkou. %s building %s %s %s %s %s %s city %d %s %s mesto %d %s %s has entered a depot. Vozidlo ,,%s'' priÅ¡lo do depa. %s land %d %s %s pozemok %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Mesto %s\npostavilo\nnovú radnicu,\nkeÄ dosiahlo\n%i obyvateľov. %s\nis crowded. Zastávka ,,%s'' je pret'ažená <žiadna linka> 1 convoi 1 súprava 1 Einzelfahrzeug im Depot 1 vozidlo v depe 1LIGHT_CHOOSE Svetlost': 1WORLD_CHOOSE Nastavenia pre novú mapu: 2LIGHT_CHOOSE Farebnost': 2WORLD_CHOOSE Číslo mapy: 3LIGHT_CHOOSE Rolovanie: 4LIGHT_CHOOSE Inverzné rolovanie 5LIGHT_CHOOSE Ukázat' chodcov 5WORLD_CHOOSE PoÄet miest: 6LIGHT_CHOOSE Chodci v mestách 6WORLD_CHOOSE Hustota dopravy: 8WORLD_CHOOSE Striedat' noc a deň A bridge must start on a way! Mosty musia\nzaÄínaÅ¥ na\n existujúcej ceste. Abfrage Informácie Abnehmer Odberateľ Abriss Búranie Absenken Terén znížit' Accelerate time ZrýchliÅ¥ Äas Add forest VysadiÅ¥ les Add Stop Pridat' Add stops for backward travel Rovnaká spiatoÄná trasa aircraft_tab Nákladné lietadlá Airport Letisko AIRTOOLS Letecká doprava All VÅ¡etky Allow city growth PovoliÅ¥ rast mesta Allow player change PovoliÅ¥ zmenu hráÄa Alters a schedule. PridaÅ¥/odstrániÅ¥ zastávky do/z cestovného poriadku Angenommene Waren Tovar potrebný pre Äalší priemysel anhaengen PripojiÅ¥ Anhaenger_tab Prívesy Anheben Terén zvýšit' Apply Line Použit' linku April Apríl Arbeiter aus: Zamestnanci z: Arrived Privezené Assets Majetok Aufloesen RozpojiÅ¥ Autohalt muss auf\nStrasse liegen!\n Zastávka musí byÅ¥\numiestnená na ceste. Available K dispozícii Bahndepot ŽelezniÄné depo Bankrott:\n\nDu bist bankrott.\n Bankrot:\n\nZbankrotoval si.\n Baum Strom baum builder Záhradník Baustelle Stavenisko Beenden SkonÄit' Beginner mode ZaÄiatoÄnícky mód Besonderes Gebaeude Turistický cieľ BF stanica Blockstrecke ist\nbelegt\n Blok je obsadený !\n Boden Krajina bridge is too high for its type! Tento typ mostu nemôže stáť tak vysoko. Bridge is too long for this type!\n Tento typ mostu\nnemôže byÅ¥ tak dlhý.\n Bruecke Most Bruecke muss an\neinfachem\nHang beginnen!\n Most môže byt' postavený\nlen na rovnom kopci !\n Brueckenboden most build choosesignals PostaviÅ¥ hradlo Build city market Postavit' Supermarket Build drain Postavit' elektrickú rozvodňu build HQ PostaviÅ¥ centrálu Build land consumer Postavit' veternú elektráreň Build monorail depot PostaviÅ¥ depo Alwegu Build powerline Postavit' elektrické vedenie Build presignals Stavba predsignalizácie Build road depot PostaviÅ¥ vozovňu Build ship depot Stavba lodného depa Build signals Stavba signalizácie Build train depot Stavba železniÄného depa Build tram depot Stavba elektriÄkového depa Build truck depot Stavba automobilového depa Buildings Budovy Built artifical slopes UpraviÅ¥ svah Built random attraction PostaviÅ¥ náhodnú turistickú atrakciu Bus_tab Autobusy Cancel Návrat Capacity: %d%s %s\n Kapacita : %3d%s %s\n Cars are not available yet! Vozidlá sa zatiaľ nevyrábajú. Cash Peniaze Change player ZmeniÅ¥ hráÄa Chart Grafy Choose operation executed on clicking stored/new vehicles Zvolit' vykonávanú operáciu pri kliknutí na zaparkované/nové vozidlá v depe chooses a random map VybraÅ¥ náhodnú mapu citicens Obyvatelia City attraction Mestské pamiatky City industries Mestský priemysel City list Zoznam miest City size VeľkosÅ¥ city_road Mestská cesta citybuilding builder PostaviÅ¥ mestskú budovu CityLimit Hranice mesta cl_title Zoznam vozidiel cl_txt_sort Triedenie: clf_chk_aircrafts lietadlá clf_chk_cars Busy/Nákl.autá clf_chk_indepot depá clf_chk_name_filter Filter názvov: clf_chk_noincome žiadny príjem clf_chk_noline bez trasy clf_chk_noroute žiadna cesta clf_chk_noschedule žiadny cest.por. clf_chk_ships Lode clf_chk_spezial_filter Å peciálny filter: clf_chk_stucked Uviaznuté clf_chk_trains Vlaky clf_chk_trams ElektriÄky clf_chk_type_filter Filter typov: clf_chk_waren Filter cien: clf_title Filter vozidiel: Climate Control NastaviÅ¥ podnebie COLOR_CHOOSE\n Prosím zvoľ\nTvoju farbu\nkliknutím:\n Company bankrupt SpoloÄnosÅ¥ skrachovala Company_msg Konkurenti Comparing pak files ... Porovnávanie *.pak súborov ... Configure AI NastaviÅ¥ umelú inteligenciu Congratulation\nScenario was complete in\n%i months %i years. Gratulácia!\n\nScenár bol úspeÅ¡ne uhraný za %i mesiace(ov) a %i rok(y) Connected stops Zastávky v dosahu: Connected with server Spojený so serverom Constructed by Vytvoril: Constructed by %s Vytvoril: %s construction speed rýchlosÅ¥ výstavby Construction_Btn Stavby Consumed Spotrebované convoi %d of %d konvoj %d z %d convoi error tooltips ZobraziÅ¥ len varovné nápovedy Convoi has been sent\nto the nearest depot\nof appropriate type.\n Konvoj bol poslaný do\nnajbližšieho depa prísluÅ¡ného\ntypu. Convoi is sold when all wagons are empty. Konvoj bude vyradený, keÄ budú vÅ¡etky jeho vozidlá prázdne. convoi passed last\nmonth %i\n \nkonvojov za posledný mesiac: %i\n Convois Konvoje Convois: %d\nProfit: %s Vozidiel: %d\nPZisk: %s Convoys Konvoje Copy Convoi DuplikovaÅ¥ Copy the selected convoi and its schedule or line SkopírovaÅ¥ zvolený konvoj s cest. poriadkom alebo linku Create a new line based on this schedule VytvoriÅ¥ novú linku podľa tohto cestovného poriadku curiosity builder PostaviÅ¥ kuriozitu curlist_title Zoznam atrakcií Currently playing: Zmena prehrávania : Deccelerate time SpomaliÅ¥ hru Del Stop Zmazat' Delete Line ZruÅ¡it' linku Denkmal Pomník Departed Odvezené Depots Depá Der Tunnel ist nicht frei!\n Tunel nie je voľný ! Destination Cieľ urÄenia Details Detaily Direkt erreichbare Haltestellen Priame spojenia Display settings Obrazovka : Dock Dok Dock must be built on single slope! Dok musí byÅ¥ postavený na rovnom svahu. dp_title Zoznam dep Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Máš %d mesiace na splatenie dlhu. Durchsatz Max. Eigenbesitz\n Verejný majetok\n Ein %s\npasst hier nicht.\n '%s'\nsem nepasuje.\n Einstellungen aendern Zmena nastavení electric elektro Electrics_tab Elektrické vlaky Electrify track Elektrifikovaná trat' Error Chyba Erzeuge neue Karte.\n \nProsím Äakaj,\nvytváram novú mapu...\n\n(Pri veľkých mapách\nto môže pár minút\ntrvat'...)\n Es wird bereits\nein Fahrplan\neingegeben\n Už bol jeden\ncestovný poriadok\nzadaný!\n Fabrikanschluss Spojenie s priemyslom Fabrikname názov fabriky Factories Fabriky factorybuilder PostaviÅ¥ fabriku Fahrplan Cest. poriadok Fahrtziel Smer: Fahrzeuge koennen so nicht entfernt werden Vozidlá nemôžu byt'\ntakto zruÅ¡ené.\n Fahrzeuge: Vozidlá: Farbe Farby Fast forward ZrýchliÅ¥ hru February Február Ferry_tab Trajekty Fertig Hotovo Filename Súbor : Filter: cl_btn_filter_enable Finances of %s Financie spoloÄnosti %s Finanzen Financie fl_title Zoznam fabrík Flug_tab Dopravné liatadlo follow me Sledovanie Follow the convoi on the map. Sleduj súpravu na mape Forest les Found new city Vybudovat' nové mesto (5.000.000$) Fracht Náklad Free Capacity Voľné miesto freeplay mode voľná hra Full load Vytaženie : Fussgaenger Chodec GAME PAUSED HRA POZASTAVENà Gear: PrísluÅ¡enstvo: Gebaeude Budova Gewicht Hmotnost' Gewinn Príjem Give the selected vehicle(s) an individual schedule Zadat' vybranému(ým) vozidlu(ám) osobitný cest. poriadok gl_title Zoznam služieb go home Do depa Goods Tovar Goods list Prehľady služieb Gross Profit Cash Flow groundobj builder PostaviÅ¥ objekt v krajine Grow city ZväÄsiÅ¥ mesto Growth Prírastok obyv. H Hangar Hangár Happy Uspokojené Haus kaufen KúpiÅ¥ dom Helligk. Obraz Help Nápoveda Help text not found Text nápovedy chýba. hide all building SkryÅ¥ vÅ¡etky budovy hide city building SkryÅ¥ mestské budovy hide transparent Priehľadné (neskrývaÅ¥) hide trees SkryÅ¥ stromy Hier warten/lagern: ÄŒakajúci pasažieri/tovar: hl_title Zoznam zastávok hl_txt_filter Filter: hl_txt_sort Triedenie: hlf_chk_airport Letiská hlf_chk_anleger Dok hlf_chk_bahnhof Žel.stanica hlf_chk_bushalt Zastávka hlf_chk_frachthof Nákl.rampa hlf_chk_keine_verb bez spojenia hlf_chk_name_filter Filter názvov: hlf_chk_spezial_filter Speciálny filter: hlf_chk_type_filter Filter typov: hlf_chk_waren_abgabe Produkcia: hlf_chk_waren_annahme Akcept.cena: hlf_title Filter staníc: Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Depo nebolo nájdené!\nKonvoj treba poslat'\ndo depa manuálne. Homeless Bývanie hľadá hydrogene Vodík ignore climates IgnorovaÅ¥ podnebie industrial building priemyselná budova Init map ... Vytváram mapu Ins Stop Vložit' Intercity road len: Dĺžka ciest: Intro. date: Dostupné od: Invalid coordinate -neplatné súradnice- isometric map Izometrické zobrazenie January Január join game On-line hra July Júl June Jún Kann Spielstand\nnicht laden.\n Nemôžem naÄítat' hru !\n Kann Spielstand\nnicht speichern.\n Nemôžem uložit' hru !\n Kein Besitzer\n Bez majiteľa\n keine žiadny Keine Einzelfahrzeuge im Depot V depe nie je žiadne vozidlo Kreuzung Križovatka labellist_title Zoznam znaÄiek Lade Relief NaÄítat' reliéf Laden NaÄítat' Land industries Mimomestský priemysel: LANG_CHOOSE\n Prosím zvoľ Tvoj jazyk:\n Last Month Minulý mesiac: Last used tools Nedávno použité nástroje Last Year Minulý rok: leer prázdne Legend Vysvetlivky Leistung Výkon Leistung: %d kW Výkon: %d kW Leitung Elektrické vedenie letzen Monat: diesen Monat: posledný mesiac: tento mesiac: Line Linka Line Management Manažment liniek Lines serving this stop Linky obsluhujúce túto stanicu LKW_tab Nákl. autá Load game Uložené hry Load scenario Scenáre loaded naložené loaded passenger/freight ZoradiÅ¥ náklad podľa Loading (%i->%i%%)! Naložené %i z %i%% Loading map ... Nahrávam mapu ... Lokomotive_tab Lokomotívy m3 m? Mail Demand %d\n Dopyt po poÅ¡te %d\n Mailbox Archív správ Mailbox Options Nastavenie správ Maintenance Údržba make stop public (or join with public stop next) costs %i per tile and level Sprístupnenie zastávky (prepojenie so susednými verejnými zastávkami) stojí %i$ za každé políÄko a podlažie Manual (Human) ÄŒlovek Manufactured: Vyrobené: Map roughness ÄŒlenitosÅ¥ mapy map zoom mierka mapy March Marec Margin (%%) Rentabilita tržieb Marker ZnaÄkovaÄ Max Boost (%%) Max. nárast (%%) Max income: Max. tržba: Max. speed: Max. rýchlosÅ¥: Maximum 254 stops\nin a schedule!\n Maximum\n254 staníc\nv cestovnom poriadku!\n maximum length of rivers Max. dĺžka riek Maximum tile height difference reached. Maximálný výškový rozdiel\nmedzi dvomi políÄkami\nbol presiahnutý. Maxspeed Najvyššia rýchlosÅ¥ May Máj Median Citizen per town Priem. poÄet obyvateľov: Meldung Oznámenie Menge Množstvo merge stop SpojiÅ¥ zastávky MessageOptionsText \nNový rok\n\nKonkurencia\n\nMesto\n\nBez trasy\n\nPriemysel\n\n"chat"\n\nNové vozidlá\n\nPlné zastávky\n\nProblémy\n\nTraffic jams\n\nScenario minimum length of rivers Min. dĺžka riek Missing pakfiles Chýbajú súbory grafickej sady! Modify the selected line UpraviÅ¥ zvolenú linku Monate alt mesiacov starý. Monorail Visutá železnica monorail vehicle vozidlo visutej železnice monorail_track TraÅ¥ visutej železnice Monorailboden Nosník visutej železnice Monoraildepot Depo month wait time Max. Äakanie (mes.) Months Mesiace Monument Pamätník Monuments Pamätníky Mountain height Výškový rozdiel Movingobj pohyblivý objekt Music playing disabled/not available Hudba nedostupná/vypnutá Music volume: HlasitosÅ¥ hudby: mute sound Vypnúť zvuk Name Názov Narrowgauge Úzkokoľajka Narrowgauge are not available yet! Úzkokoľajka eÅ¡te neexistuje! narrowgauge vehicle Úzkorozchodné vozidlo narrowgauge_track Úzkorozchodná traÅ¥ Narrowgaugedepot Úzkorozchodné depo Net ID: %p SieÅ¥: %p\n Net Wealth Vlastné imanie Net wealth near zero Hodnota VaÅ¡ej spoloÄnosti sa blíži nule. Neue Karte Nová mapa Neue Welt Nový svet new convoi nový konvoj New Line Nová linka New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Nová linka bola vytvorená.\nMôžete ju teraz priradiÅ¥\njej zvolením\nv hornej Äasti okna.\n New Vehicles Nové vozidlá Nickname: Prezývka no buildings hidden UkázaÅ¥ budovy no convois žiadny konvoj No goods are loaded onto this convoi. Do konvoja nebude naložený žiadny tovar no goods waiting NeÄaká žiadny tovar no load NenakladaÅ¥ No Route Bez trasy No stop here! Nástroj je prístupný len na staniciach! No suitable ground! Nevhodný terén! No terminal station here! Tu nie je možné postaviÅ¥\nkoncovú zastávku.\nMusí stáť na rovine\nna konci cesty. no timeline vÅ¡etky obdobia no tree bez stromov No. of Factories PoÄet tovární a obchodov: Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Nemáš žiadny\ncestovný poriadok!\n none niÄ nord Sever nordost Severovýchod nordwest Severozápad Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Odopreté!\nCestovný poriadok nemôže\nbyt' teraz zmenený.\nVyskúšajte neskôr ! Not enough fields would remain. Okolo tejto farmy zostáva\nmálo políÄok. Now active as %s.\n Teraz aktivny ako %s.\n Number of rivers PoÄet riek Object Podľa ID Odometer: %s km Najazdené: %s km Ok OK Oktober Október On loan since %i month(s) PoÄet mesiacov na splatenie dlhov: %i On this map, you are not\nallowed to change player!\n V tejto hre\nnemôžete hraÅ¥\nza iného hráÄa!\n Only city chains PostaviÅ¥ mestský priemysel Only first %d differing paks reported. There are probably more. Ohlásených je len %d odliÅ¡ných súborov. Ale je ich asi viac. Only land chains PostaviÅ¥ mimomestský priemysel Only one transformer per factory! Továreň môže maÅ¥ len jednu trafostanicu! Operation Prevádzka Ops Profit Zisk EBITDA Optionen Nastavenia Origin Zdroj ost Východ paletten paliet Pas_tab Osobné vlaky Passagiere cestujúcich Passagierrate Pasažieri Passagierziele Pasažierske/PoÅ¡tové ciele Passengers %d %c, %d %c, %d no route Cestujúci %d %c, %d %c, %d bez spojenia Passengers %d %s, %d %s, %d no route Cestujúci %d %s, %d %s, %d bez spojenia Pause Pauza Pax <%i> Mail <%i> Cestujúci <%i> PoÅ¡ta <%i> Planes are not available yet! Dopravné lietadla eÅ¡te neboli vyvinuté. Plant tree Zasadit' strom player -1 Älovek player 0 verejná služba player 1 Napik 128 AS player 2 Trikky Transport player 3 Meyer Moving Co. player 4 Spedition VM player 5 H-Trans GmbH player 6 PSK & Co KG Please choose vehicles first\n \nNajprv prosím vyber vozidlo ! Post poÅ¡ty Postrate PoÅ¡ta Power Energia Power: Výkon: Powerlines El. vedenie Production of %s has been stopped:\n%s\n Výroba %s\n'%s'\nbola ukonÄená.\n Produktion Produkcia Profit Zisk promote to line Linka podľa trasy q1 Jar q2 Leto q3 Jesen q4 Zima rail car železniÄného vozidla Random map Náhodná mapa Rathaus Radnica Rating Hodnotenie Reliefkarte Mapa reliéfu Remove Odstránit' remove airstrips OdstrániÅ¥ dráhu remove channels ZruÅ¡iÅ¥ kanál remove monorails DemontovaÅ¥ traÅ¥ remove roads OdstrániÅ¥ vozovku remove tracks DemontovaÅ¥ traÅ¥ replace stop VymeniÅ¥ zastávky residential house Obytný dom Restore natural slope ObnoviÅ¥ pôvodný terén Restwert: Predajná hodnota: Retire. date: Koniec výroby: return ticket SpiatoÄ.jazda Revenue Tržby road vehicle cestného vozidla Roadsign Dopravná znaÄka Rotate Building OtoÄiÅ¥ budovu (nástupiÅ¡te) Rotate map OtoÄiÅ¥ mapu Rotation OtoÄenie sack vriec sail vietor Save UložiÅ¥ hru Saving map ... Ukladám mapu ... Schienentunnel Stavba žel. tunela Schiff_tab Lode Schiffdepot Lodné depo Schleppkahn_tab TahaÄe Screenshot UrobiÅ¥ screenshot. Sehenswuerdigkeit Turistická destinácia Sell the selected vehicle(s) Predat' vybrané vozidlo(á) sended Odosl. poÅ¡ta SEP_FRACTION , Serves Line: Obsluha linky: Service Obsluha Setting KonfigurovaÅ¥ Ship Lode shops and stores Obchody a kancelárie Show all ZobraziÅ¥ vÅ¡etko show grid ZobraziÅ¥ mriežku Show industry Priemysel Show legend Vysvetlivky Show map scale Nadm. výška Show obsolete ZobraziÅ¥ zastaralé Show schedules ZobraziÅ¥ trasu linky show station coverage ZobraziÅ¥ spádové uzemie stanice Show/hide statistics Ukázat'/Skryt' Å¡tatistiku Shrink city ZmenÅ¡iÅ¥ mesto Size (%d MB): Veľkost mapy: Sort by ZoradiÅ¥ podľa Sort waiting list by Triedit' podľa Äakania Sound Hudba Sound settings Nastavenia zvukov Sound volume: Hlasitost zvukov: special freight Å pec. preprava Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Expresný príplatok\ncesty %i km/h, železnica %i km/h\nlode %i km/h, lietadlá %i km/h. Speedlimit Max. rýchlost' Speichern Uložit' Spieler HrÃ¡Ä Spieler(mz) Konkurencia Spielerliste Zoznam hráÄov Spielstand wurde\ngeladen!\n Hra bola naÄítaná !\n Spielstand wurde\ngespeichert!\n Hra bola uložená !\n Sprache Jazyk Sprachen Jazyky Stadtinformation Informácie o meste Start Å tart Start the selected vehicle(s) Vyjst' s vybraným(i) vozidlom(i) Starte Spiel Nová hra Station tiles: Rozloha stanice: Station_msg Stanice Status Stav steam para Step timeline one year Pridaj jeden rok Stops Zastávky Storage Zásoby Storage capacity Ložná kapacita Strassendepot Cestné depo Strassentunnel PostaviÅ¥ tunel street car elektriÄka sued Juh suedost Juhovýchod suedwest Juhozápad Summer snowline Letná hr. snehu Supplied: %.0f %% Dodané: %.0f %% Suppliers Dodávatelia Tage alt dní staré There are still vehicles\nstored in this depot!\n V tomto depe\nsú eÅ¡te vozidlá !\n This Month Tento mesiac: This Year Tento rok: timeline Zodpovedajúce dobe tl_title Zoznam miest To heavy traffic\nresults in traffic jam.\n Hustá doprava\nspôsobila zápchu.\n tonnen t Total inhabitants: PoÄet obyvateľov: Tourist attractions PoÄet turistických atrakcií: Tourists Turisti Town: %s\n Mesto %s.\n Towns Mestá Tracks Trasy Traffic Premávka Train Vlaky Trains are not available yet! Vlaky eÅ¡te neexistujú! Tram ElektriÄka tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. elektriÄky %i km/h, visutá železnica %i km/h\nmaglev %i km/h, úzkokoľajka %i km/h. tram_track elektriÄková traÅ¥ Tramdepot ElektriÄková vozovňa Trams are not available yet! ElektriÄky zatiaľ neexistujú. Transferring game ... Prevádzam hru... Transformer only next to factory! Trafostanice sú dostupné len\nna prázdnych a rovných políÄkach\nsusediacich s továrňou! Translation Preklad transparent station coverage Priehľadné sp. územie stanice Transported Odvezení TrolleyBus_tab Trolejbusy Truck Automobily Tunnel muss an\neinfachem\nHang beginnen!\n Tunel musí zaÄínat'\nna úpätí kopca !\n Tunnel must start on single way! Tunel musí zaÄínaÅ¥\nna voľnom konci cesty!\n Tunnelboden Tunel underground mode Pohľad do podzemia UNDO failed! Nie je možné vziaÅ¥ späť. Undo last ways construction OdvolaÅ¥ posledný krok stavby cesty Unemployed Prácu hľadá Unhappy Neuspokojené units/day jedn./mes Update Line UpraviÅ¥ linku upgrade HQ RozšíriÅ¥ centrálu Usage: %.0f %% Využitie: %.0f %% Usage/Output Spotreba/Výroba Use beginner mode ZaÄiatoÄnícky mód Use timeline start year ZaÄaÅ¥ od roku Vehicle %s can't find a route! Vozidlo %s nemôže nájsÅ¥ cestu ! Vehicle %s is stucked! Vozidlo %s uviazlo!\n Vehicle details Detaily vozidla Verbrauch Spotreba Vergroessere die Karte\n ZväÄÅ¡iÅ¥ mapu.\n Verkauf OdstrániÅ¥ verkaufen VyradiÅ¥ Verkehrsteilnehmer Osobné autá Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Máš %d mesiace\nna splatenie dlhov.\n vh_title Katalóg vozidiel via cez via %s\n cez %s\n via Menge cez (poÄet) voranstellen Na zaÄiatok Waggon_tab Vagóny waiting ÄŒaká Waiting for clearance! ÄŒaká na voľnú cestu! Warnings_msg Doprava Wasser Voda/More Water voda Water level Úroveň vody water vehicle plavidlo way %s cannot longer used:\n TraÅ¥/cesta %s sa nemôže Äalej používaÅ¥.\n Ways not connected Možné len na spojených cestách! Wegpunkt Prejazd cez Weight: HmotnosÅ¥: Wert Hodnota west Západ Winter snowline Zimná hr. snehu withdraw VyradiÅ¥ Withdraw All VyradiÅ¥ vÅ¡etky! WRONGSAVE Nekomatibilná verzia\nuloženej hry. Hra nemôže\nbyt' naÄítaná.\n Year %i has started. ZaÄal rok %i! Years Roky Your primary color: VaÅ¡a hlavná farba: Your secondary color: VaÅ¡a vedľajÅ¡ia farba: Zielort cieľ zooming in priblížiÅ¥ zooming out vzdialiÅ¥ Zu nah am Kartenrand Si príliÅ¡ blízko\nk okraju mapy,\naby si mohol\nnieÄo stavat'.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nový rýchlostný rekord visutej zeleznice dosiahol rýchlosÅ¥ou %.1f km/h\nvlak %s. New world record for monorails: %.1f km/h by %s. Nový rýchlostný rekord\nnvisutej železnice dosiahol\nrýchlosÅ¥ou %.1f km/h\nvlak %s. New world record for motorcars: %.1f km/h by %s. Nový rýchlostný rekord\nna ceste dosiahlo\nrýchlosÅ¥ou %.1f km/h\nvozidlo %s. New world record for narrowgauges: %.1f km/h by %s. Nový rýchlostný rekord\nna úzkorozchodnej železnici\ndosiahol rýchlosÅ¥ou %.1f km/h\nvlak %s. New world record for planes: %.1f km/h by %s. Nový rýchlostný rekord\nv leteckej doprave dosiahlo\nrýchlosÅ¥ou %.1f km/h\nlietadlo %s. New world record for railways: %.1f km/h by %s. Nový rýchlostný rekord\nna železnici dosiahol\nrýchlosÅ¥ou %.1f km/h\nvlak %s. New world record for ship: %.1f km/h by %s. Nový rýchlostný rekord\nna vode dosiahla\nrýchlosÅ¥ou %.1f km/h\nloÄ %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &1_CITY_SYLL ské mesto &2_CITY_SYLL ská Dedina &3_CITY_SYLL sko &4_CITY_SYLL ský Zrub &5_CITY_SYLL ská Kopanica &6_CITY_SYLL ský Tatran &7_CITY_SYLL ská Koliba &8_CITY_SYLL ovce &9_CITY_SYLL ská župa &A_CITY_SYLL ské vrchy %1_CITY_SYLL KoÅ¡ic %2_CITY_SYLL Poprad %3_CITY_SYLL Kežmar %4_CITY_SYLL Martin %5_CITY_SYLL Žilin %6_CITY_SYLL TrenÄín %7_CITY_SYLL Trnav %8_CITY_SYLL Zvolen %9_CITY_SYLL Svitov %A_CITY_SYLL Ostrav %B_CITY_SYLL PreÅ¡ov %D_CITY_SYLL Lev 0center %s Námestie 0extern %s Pod lesom 0suburb %s Predmestie 1center %s Obchodná 1extern %s Na okraji 1suburb %s Nová Doba 2center %s Dolná 2extern %s Záhradky 2suburb Kolónia 3center %s Horná 3extern %s Vidiek 3suburb %s Pod ViÅ¡kovkou 4center %s Kapitulská 4extern %s Chatky 4suburb %s Továrenská 5center %s Zámocká 5extern %s Rázcestie 5suburb %s Hronov 6center %s Kapitulská 7center %s Národná 8center %s Å tefánikova 9center %s Masarykova Acenter %s Å túrova Bcenter %s U samaritánov Ccenter %s Cintorínska Dcenter %s Kafkova Ecenter %s Národná Fcenter %s Hodžova Fsuburb %s Hurbanova Gcenter %s Blumentálska Gsuburb %s FrantiÅ¡kánska Hcenter %s Alžbetínska Hextern %s Hsuburb Icenter %s PoÅ¡tová Isuburb %s DobÅ¡inského Jcenter %s Tajovského Jsuburb %s Mateja Bela Kcenter %s Moyzesova Ksuburb %s Nová Doba Lcenter %s Satinského Mcenter %s Havlova Mextern %s Dolná Msuburb %s predmestie Ncenter %s SNP Nextern %s Mlynská Nsuburb %s Predmestie Ocenter %s BeneÅ¡ova Oextern %s Záhradná Pcenter %s Národná Qcenter %s Å oltésovej Rcenter %s Židovská Scenter %s Sokolská Tcenter %s Kapitulská Tsuburb %s Mýtna Ucenter %s Divadelná Uextern %s Tatranská Usuburb %s Dolnozemská Vcenter %s TrojiÄná Vextern %s Stodolná Vsuburb %s Lipová Wcenter %s MurgaÅ¡ova Wextern %s Lužná Wsuburb %s Záhumienok Xcenter %s Medená Xextern %s Å kolská Xsuburb %s Stráne Ycenter %s Zámocká Yextern %s Na pokraji Ysuburb %s Kolónia Zcenter %s Havlova Zextern %s Újazd Zsuburb %s Sedliacka simutrans-124.3/simutrans/text/sk/000077500000000000000000000000001474050137200172015ustar00rootroot00000000000000simutrans-124.3/simutrans/text/sk/bridges.txt000066400000000000000000000027461474050137200213720ustar00rootroot00000000000000Nástroj na stavbu mosta - pomoc

Stavba mosta

Most sa stavia podobne ako tunel.
Cestný most
Musíš mat' už vytvorené cesty, ktoré spojíš mostom. Obe musia presne lícovat' (pasovat' proti sebe). Myšou zvoľ nástroj cestného mosta. Prepojenie vytvoríš kliknutím na jeden z koncov prepájaných ciest. Most môzeš stavat' aj tak, že jeden jeho koniec bude na kopci (do výšky 1-nej pozície). Pokiaľ by sa Ti stalo, že cesta nie je prepojená, skús potiahnut' cestu ešte o jednu pozíciu pod most.

ŽelezniÄný most
Musíš mat' vytvorené železniÄné trate, ktoré spojíš mostom. Obe musia presne lícovat' (pasovat' proti sebe). MyÅ¡ou zvoľ nástroj niektorého zo železniÄných mostov. Prepojenie železniÄných tratí vytvoríš kliknutím na jeden z koncov. Most s plným dnom (bez boÄnej konÅ¡trukcie) má tú výhodu, ze môžeÅ¡ naň umiestnit' signalizáciu. Most môzeÅ¡ postavit' aj tak, ze jeden koniec bude na kopci (do výšky 1-nej pozície). Pokiaľ by sa Ti stalo, ze železniÄná trat' nie je prepojená, skús potiahnut' koľajnice eÅ¡te o jednu pozíciu pod most.

V oboch prípadoch platí, ze stavat' mosty s jedným koncom na kopci (príp. obidvomi) je možné, len ak sú steny kopca zarovnané do výšky 1-nej pozície. Mosty môzeš stavat' aj tak, že preklenieš jamu (roklinu). Obe steny jamy (rokliny) však musia mat' opät zarovnané steny do hĺbky 1-nej pozície.

simutrans-124.3/simutrans/text/sk/color.txt000066400000000000000000000005251474050137200210620ustar00rootroot00000000000000Voľba farby - pomoc

Farby

V tomto menu si môžeÅ¡ zvoliÅ¥ farbu Tvojej spoloÄnosti. Bude spoloÄná pre vÅ¡etky Tvoje dopravné prostriedky, stanice atd.

Zvoľ svoju svoju farbu jednoduchým kliknutím na niektorú zo zobrazených farieb.

Štandardne je nastavená svetlomodrá farba.

simutrans-124.3/simutrans/text/sk/convoi.txt000066400000000000000000000010351474050137200212360ustar00rootroot00000000000000Prehľad vozidiel - pomoc Prehľad ponúka nasledovné možnosti:

1.) Triedenie :
Klikaním na prvé tlaÄidlo zľava meníš kritéria, t.j. podľa Äoho bude zoznam triedený : názvu, príjmu alebo typu.
Druhým tlaÄidlom zľava si nastavujeÅ¡ vzostupné alebo zostupné triedenie.

2.) Filter :
Klikaním na tretie tlaÄidlo zľava zapínaÅ¡ alebo vypínaÅ¡ filter.
Posledným tlaÄidlom ,,Nastavenia'' zobrazíš podrobný zoznam vÅ¡etkých kritérií a možností filtrovania.

simutrans-124.3/simutrans/text/sk/depot.txt000066400000000000000000000067721474050137200210710ustar00rootroot00000000000000Depo

Depo

V depe môžeÅ¡ kupovat' a predávat' vozidlá, vytvárat' cestovné poriadky pre kúpené dopravné prostriedky prísluÅ¡ného typu, t.j. dopravné prostriedky v cestnom, želežniÄnom alebo lodnom depe.

Depo obsahuje informáciu o dopravnom prostriedku, ktorý môžeÅ¡ kúpit' (aj ktorý už vlastníš). Cenu a parametre vozidiel zobrazíš nabehnutím myÅ¡i na prísluÅ¡né vozidlo. Kliknutím na vedľajÅ¡iu záložku ,,Prívesy'' alebo ,,Vagóny'' zobrazíš zoznam prívesov alebo vagónov. Nad informaÄnou zónou (s cenou a parametrami vozidla) nájdeÅ¡ skupinu tlaÄidiel. Prvú skupinu tvoria :
,,Štart'',,,Cestovný poriadok'', ,,Rozdelit' '' a ,,Predat' ''.

TlaÄidlom ,,Å tart'' vypustíš vozidlo so zadaným cestovným poriadkom do premávky. TlaÄidlom ,,Cestovný poriadok'' zadefinujeÅ¡, odkiaľ a kam bude vozidlo premávat' a ako bude chodit vyt'ažené. TlaÄidlom ,,Rozpojit' '' dosiahneÅ¡ rozpojenie zostavy vozidla s prívesom alebo vlaku. Pod nápisom ,,Vozidlá'' je umiestnené tlaÄidlo módu. Klikaním nadobúda tri stavy ,,Pridávanie'' ,,Zostavovanie'' a ,,Predávanie''. V móde predávania si zvolíš, ktorý vlastnený dopravný prostriedok predat' (za zostatkovú cenu). Predávanie ukonÄíš prepnutím tohto tlaÄidla. Informácie o hodnote a parametroch budú zobrazené v informaÄnej zóne (tesne pod tlaÄidlami).
Predat' okamžite nejaký Tvoj privolaný dopravný prostriedok môžeÅ¡ aj tlaÄidlom ,,Predat' ''.
Pri kúpe : Ak Ti vyhovuje cena a parametre, kúpu vozidla vykonáš kliknutím na vozidlo. Kúpu prívesu alebo vagónov dosiahneÅ¡ obdobným spôsobom. Kúpené vozidlá sa objavia v prvom a Äalších poliach. Z nich si klikaním v logickom slede poskladaj dopravný prostriedok. Poskladaný dopravný prostriedok sa objaví v prvých (vrchných) poliach.

Teraz môžeÅ¡ pristúpit' k zadaniu cestovného poriadku. Musíš mat' už vytvorené stanice, zastávky alebo nákladné rampy. Zobrazeným žltým znaÄkovaÄom pooznaÄuj stanice, zastávky alebo nákladné rampy po ktorých bude premávat' dopravný prostriedok.

Klasicky zadávaÅ¡ cestovný poriadok každému vozidlu zvlášt'. Táto verzia hry vÅ¡ak umožňuje vytvorit' cestovný poriadok pre celú skupinu vozidiel - konvoj tlaÄidlami ,,Nová linka'', ,,Použit' linku'', ,,Upravit' linku'' a ,,ZruÅ¡it' linku''. StaÄí kúpit' dopravný prostriedok, priradit' k niektorej zo zadefinovaných liniek a vypustit' do premávky.
Pre lepší prehľad o linkách má hra zabudovaný tzv. Manažment liniek - kláves ,,W''.

Ak chceš poslat' dopravný prostriedok spät' do depa neskôr, do cestovného poriadku ho vlož úplne na koniec. V depe môžeš dopravný prostriedok porozkladat' (napr. oddelit' príves alebo vagóny), preusporiadat' a prípadne znova po skontrolovaní (príp. zmene) cestovného poriadku vypustit' do premávky.

Pozn. prekladateľa : Cestovný poriadok vozidla môzeÅ¡ menit' aj poÄas jazdy. MyÅ¡ou klikni na idúci dopravný prostriedok a vykonaj v jeho cestovnom poriadku úpravy. Po ukonÄení úprav potvrÄ tlaÄidlo ,,Hotovo''. PoÄas týchto úprav bude dopravný prostriedok stát'. Zaujímavost'ou je, že do cestovného poriadku môžeÅ¡ zadat' aj ,,Voľný bod trasy''. Vozidlo takto nebude zarábat'. Pri úpravách staníc, zastávok alebo nákladných rámp si treba na toto dat' pozor !

simutrans-124.3/simutrans/text/sk/display.txt000066400000000000000000000030201474050137200214020ustar00rootroot00000000000000Nastavenia obrazu

Obraz - pomoc

Tu si nastavuješ vlastnosti rolovania, zapínaš alebo vypínaš zobrazenie chodcov a zapínaš alebo vypínaš efekt, ktorý napodobňuje striedanie dňa a noci.

Rolovanie:
Pri rolovaní môzeÅ¡ klikaním na šípky nastavit' citlivost' rolovania, t.j. o akú veľkú vzdialenost' sa Ti bude posúvat' zobrazenie. Čím je hodnota väÄÅ¡ia, o tým väÄÅ¡iu vzdialenost' (gradovanie) sa budeÅ¡ presúvat' z jedného miesta na druhé už pri nepatrnom pohybe myÅ¡ou alebo povelom z klávesnice.
Ak ponecháš hodnotu rolovania na 1, môžeš dosiahnut' jemnejšieho presúvania sa po krajine.

Inverzné rolovanie:
Ak ti nevyhovuje posun po krajine voÄi pohybu myÅ¡ou a si zvyknutý na opaÄný pohyb krajiny, zapni si túto funkciu.

Ukázat' chodcov:
Zapnutím tejto funkcie dosiahneš mimoriadne efektného zobrazenia pasažierov, ktorý vystupujú z vlaku, autobusu alebo lode. Čím bude viac vystupujúcich pasažierov, tým bude efekt viditeľnejsí (skoro ako mravenisko).

Striedat' noc a deň:
Táto funkcia umožňuje napodobnit' striedanie dňa a noci. OdporúÄam ju zapnút' iba v prípade, keÄ nemáš v pláne nijaké väÄÅ¡ie budovanie Tvojej dopravy a chceÅ¡ iba také ,,oddychové'' hranie a pozeranie. Akonáhle sa pustíš do väÄÅ¡ieho budovania, tento efekt Ťa môze ruÅ¡it'. Vtedy si ho vypni.

Slovenský popis: Ján KrnáÄ
Simutrans (c) Hj. Malthaner

simutrans-124.3/simutrans/text/sk/finances.txt000066400000000000000000000024031474050137200215270ustar00rootroot00000000000000Financie - pomoc

Financie

Stav Tvojich penažných prostriedkov môžes sprístupnit' stlaÄením klávesu ,,f'' alebo voľbou ikony ,,Financie'' na hornej liÅ¡te.
Zobrazená bude informácia o Tvojich financiách za posledné dva roky : príjmov a výdavkov.

Položky sú nasledujúce:

Výdaje na stavbu - to je Äokoľvek, Äo si postavil v priebehu roka vrátane signalizácie, železnicných tratí, pôšt a pod.

Nové vozidlá - výdaje na akýkoľvek dopravný prostriedok, ktorý pribudol do Tvojho vozového parku v ktoromkoľvek depe.

Údržba vozidiel - náklady na údržbu všetkých Tvojich dopravných prostriedkov.

Príjem - súhrn Tvojich príjmov za všetok prepravený tovar a pasažierov.

Celkom - súhrn Tvojich príjmov/výdajov za rok. Toto je súhrn za všetky položky.

Zostatok - celkové obchodné saldo Tvojej spoloÄnosti. To znamená celkový stav Tvojich peňazí. Ak je kladný, môzeÅ¡ ho pouzit' na Äalsie investovanie. Táto informácia je tiež zobrazená v stavovej (dolnej) liÅ¡te obrazovky.

Podpora (mesacne) - bonifikácia, dotácie a pod. Tvojich financií (mesaÄne).

simutrans-124.3/simutrans/text/sk/general.txt000066400000000000000000000014371474050137200213640ustar00rootroot00000000000000Simutrans - pomoc

Klikni na témy :

Ovládacie klávesy
Spustenie hry s parametrami

Nastavenia hry
Nástroje na stavbu ciest
Nástroje na stavbu železnice
Nástroje na stavbu lodnej dopravy
Nástroje na stavbu mostov
Stanice a zastávky
Cestovný poriadok
Prehľad zastávok
Prehľad vozidlového parku
Prehľad financií

Slovenský popis : Ján KrnáÄ
Simutrans (c) Hj. Malthaner

simutrans-124.3/simutrans/text/sk/haltlist.txt000066400000000000000000000011601474050137200215640ustar00rootroot00000000000000Prehľad zastávok a staníc

Prehľad Tvojich zastávok, staníc a nakladacích rámp

Prehľad ponúka nasledovné možnosti:
1.) Triedenie :
Klikaním na prvé tlaÄidlo zľava meníš kritéria, t.j. podľa Äoho bude zoznam triedený : názvu, typu, Äakania alebo Äísla.
Druhým tlaÄidlom zľava si nastavujeÅ¡ vzostupné alebo zostupné triedenie.

2.) Filter :
Klikaním na tretie tlaÄidlo zľava zapínaÅ¡ alebo vypínaÅ¡ filter.
Posledným tlaÄidlom ,,Nastavenia'' zobrazíš podrobný zoznam vÅ¡etkých kritérií a možností filtrovania.

simutrans-124.3/simutrans/text/sk/language.txt000066400000000000000000000020331474050137200215230ustar00rootroot00000000000000Nastavenie jazyka - pomoc

Nastavenie jazyka

Spôsob ako zmenit nastavenie jazyka v hre Simutrans je voľbou Tvojho jazyka. Ak zvolíš jazyk predtým, ako spustíš novú hru, názvy miest už budú vytvorené podľa tohto jazyka.

Nastavenie jazyka môzeÅ¡ kedykoľvek zmenit. Obsah otvorených okien nemôže byt aktualizovaný ihneÄ, ale až po ich znovuotvorení.

Teda ak chceš mat názvy miest v Tvojom jazyku, najprv vyber svoj jazyk a až potom spusti novú hru.

Ak chýba Tvoj požadovaný jazyk, skús pohľadaÅ¥ ÄalÅ¡ie preklady na:
http://www.simutrans.de
http://www.simutrans.cjb.net
v sekcii ,,Download''.

České stránky venované tejto hre nájdeš na:
http://www.simutrans.wz.cz

Pozn. : Ale môžu to byt' starÅ¡ie verzie prekladov. VäÄÅ¡ina textov vsak býva bezprostredne aktualizovaná.

Ak chcete pomôcť s prekladom Simutranov do vášho jazyka,
navštívte stránku https://translator.simutrans.com

simutrans-124.3/simutrans/text/sk/load.txt000066400000000000000000000005011474050137200206550ustar00rootroot00000000000000NaÄítanie - pomoc

NaÄítat' uloženú hru

Napíš názov uloženej hry, alebo ju vyber zo zoznamu uložených hier. PokraÄuj kliknutím na jej názov. Týmto vybranú hru spustíš.

Hru vymažeÅ¡ kliknutím na znaÄku ,,X'' vedľa názvu (pozor na neopatrné kliknutie !).

simutrans-124.3/simutrans/text/sk/map.txt000066400000000000000000000007231474050137200205210ustar00rootroot00000000000000Mapa - pomoc

Okno mapy

Okno mapy môzeÅ¡ zobrazit stlaÄením klávesu ,,m'', alebo voľbou ikony ,,Mapa'' na hornej liÅ¡te.

Na mape máš zobrazený svet miniatúrne s farebným rozlíšením rôznych bodov ako sú priemyselné odvetvia, želežniÄné trate, cesty a mestá.

Ak chceÅ¡ zobrazit' aj konkrétny detail mapy, jednoducho klikni na prísluÅ¡ný bod, a hra hneÄ zobrazí túto pozíciu na obrazovke.

simutrans-124.3/simutrans/text/sk/new_world.txt000066400000000000000000000052321474050137200217440ustar00rootroot00000000000000Nový svet - pomoc

Nový svet

Tento režim ponúka nastavenie parametrov, ktoré budú urÄovat' charakter mapy vytvorenej pre novú hru. V ľavom hornom rohu obrazovky sa zároveň zobrazí ponuka na výber jazyka.

Číslo mapy - Äíslo ,,schémy'' mapy, vrátane množsta a umiestnenia vody, kopcov, osadenia stromov, umiestnenia miest a priemyslu. Predbežné zobrazenie (náhľad) je zobrazený pri každej mape. Å tandardne je nastavená mapa Äíslo 33.
Veľkost mapy - akú veľkú mapu chceÅ¡ hrat'. Rozmedzie je 128x128 - 576x576 stvorcekov. Å tandardné nastavenie je 256x256 Å¡tvorÄekov.
Hustota priemyslu - index urÄuje, ako husto bude priemysel rozmiestnený na mape. Čím je hustota priemyslu nižšia, tým sa stáva hra tažšou a tým sú možnosti prepravy surovín alebo tovaru menÅ¡ie. Å tandardné nastavenie je 125.
PoÄet miest - koľko miest celkom bude rozmiestnených na mape. Rozmedzie je 2 - 64 miest. Å tandardné nastavenie je 16 miest.
Hustota dopravy - index urÄuje, aká bude hustota premávky súkromných áut na cestách. Å tandardné nastavenie je 8.
Hladina vody - index urÄuje, aké množstvo vody budeÅ¡ mat' na mape. Čím bude hodnota väcsia, tým bude menej pevniny a naopak. Å tandardné nastavenie je 4.
Výškový rozdiel urÄuje rozdiel medzi hladinou vody a najvyšším vrchom, t.j. maximálnu nadmorskú výšku na mape. Å tandardné nastavenie je 160.
ÄŒlenitost' mapy - index urÄuje, Äi pôjde o prevažne rovinu, pahorkatinu alebo horskú krajinu. Rovine zodpovedá najnižšie Äíslo a horskej krajine najvyššie císlo. Rozmedzie je 1 - 3. Å tandardné nastavenie je 2.

TlaÄidlá :
Náhodná mapa - tlaÄidlom si vyberáš mapu, ktorú hra náhodne vyberie a ponúkne. Tým sa nemenia iné nastavenia parametrov mapy.
Ukázat' chodcov - zapnutím bude hra zobrazovat' chodcov na ulici alebo vystupujúcich z vlaku alebo autobusu. Toto nastavenie môžeš menit' aj neskôr v nastaveniach obrazu - Obraz.
Striedat' noc a deň - zapnutím bude bude hra napodobnovat' chovanie sa dňa a noci. Toto nastavenie môžeš menit' aj neskôr v nastaveniach obrazu Obraz.
NaÄítat' hru - umožní Ti vybrat' a spustit' niektorú z uložených hier.
NaÄítat' reliéf - umožní Ti vybrat' alternatívnu krajinu.
Spustit' hru - spustenie novej hry s tými parametrami mapy, aké máš momentálne nastavené.
Skoncit' - ukoncíš hru Simutrans.

simutrans-124.3/simutrans/text/sk/options.txt000066400000000000000000000017311474050137200214370ustar00rootroot00000000000000Nastavenia hry - pomoc

Nastavenia hry

Dialógový režim voľbou niektorej z možností ponúkne eÅ¡te ÄalÅ¡ie podúrovne nastavení. Potom sa zobrazí Å¡tandardný dialógový režim. Slúžia spravidla na zmenu vlastností, naÄítanie, uloženie alebo ukonÄenie hry.

Jazyk - zvoľ jazyk, ktorý budeš pouzívat' v hre Simutrans
Farby - ponúka možnost' zmenit' farbu Tvojej spoloÄnosti
Obraz - nastavenie vlastností obrazu
Zvuky - nastavenie hlasitosti hudby a zvukov
Konkurencia - voľba konkurenÄných hráÄov UMELEJ INTELIGENCIE
Nacítat' - naÄítanie uloženej hry
Ulozit' - uloženie rozohranej hry
Nová mapa - reštart hry a ponuka novej mapy
Skoncit' - ukonÄenie hry

simutrans-124.3/simutrans/text/sk/players.txt000066400000000000000000000011721474050137200214220ustar00rootroot00000000000000KonkurenÄní hráÄi - pomoc

Zoznam hráÄov

V tomto menu si schopný vidiet' konkurenciu - UMELÚ INTELIGENCIU s možnost'ou bud vypnutia alebo zapnutia každého z nich.

Bankový zostatok - každý konkurent je slovne zobrazený aj so zostatkom jeho úÄtu. Zapnút' alebo vypnút' ktoréhokoľvek z nich môžeÅ¡ kliknutím na prísluÅ¡né políÄko vľavo. Å tandardne je zapnutý jeden konkurent tyrkysovej farby.

Pozn. prekladateľa : Vypnutím konkurentov deaktivujeÅ¡ u nich len moznost' nového investovania. Ich dovtedajÅ¡ie investiÄné aktivity vÅ¡ak bežia naÄalej.

simutrans-124.3/simutrans/text/sk/railtools.txt000066400000000000000000000107441474050137200217600ustar00rootroot00000000000000Nástroje na stavbu železnice

Stavba koľajníc - nástrojom staviaÅ¡ železniÄnú trat' medzi dvoma ľubovolne vzdialenými bodmi (Å¡tvorÄekmi), alebo pripájaÅ¡ koľajnice Äast' po Äasti. Kliknutím na zvolené miesto vytvorených koľajníc zase vytváraÅ¡ križovatky. Postup : Klikni myÅ¡ou na symbol koľajníc a pokraÄuj kliknutím na bod, z ktorého chceÅ¡ viest' koľajnice. Kurzor bude zobrazený ako malý buldozér. Premiestni sa na koniec zamýšľanej trate a klikni tam myÅ¡ou. Simutrans vytvorí spojenie medzi týmito dvomi bodmi. Pozn. prekladateľa : Pokiaľ by sa Ti trat' zdala príliÅ¡ kľukatá, máš možnost' urobit' korekcie (zbúrat' tú Äast', kde budeÅ¡ robit' úpravy a potom pridávat' koľajnice Äast' po Äasti. Stavbu koľajníc po uhloprieÄkach je vhodnejÅ¡ie robit' Äast' po Äasti. Výsledok je lepší ;-) ). Na stavbu železnice môzeÅ¡ pouzit' len voľné pozície (Å¡tvorceky). Ak nechceÅ¡ križovat' inú trat', použi stavbu mosta alebo tunela. Ak nie je možné úspeÅ¡ne pokracovat' v budovaní trate, skús najprv vykonat' terénne úpravy.
Signalizácia - nástroj na stavbu signalizácie. Kliknutím naň bude kurzor bude zobrazený vo podobe dvoch semafórov (obojsmerný). Signalizácia slúži na organizáciu pohybu vlakov. Semafóry umiestniÅ¡ kliknutím na koľajnice napr. pred križovatku nejakého spoloÄného jednokoľajového úseku alebo na koľajovú križovatku. Opakovaným klikaním na tú istú pozíciu sa Ti zobrazuje postupnost' ponúkaných typov semafórov. Akonáhle prejde jeden vlak cez semafór, ostané semafóry budú blokovat' Äalsie vlaky, až kým sa trat' opät' neuvoľní. Semafóry potom budú púšt'at' vlaky podľa poradia, v akom priÅ¡li k semafórom.
Tunel - kliknutím na tento nástroj bude kurzor zobrazený symbolom tunela. Aby si tunel mohol úspeÅ¡ne vytvorit', musia mat' kopce rovnú stenu na oboch stranách. Pomôž si úpravou terénu. Potiahni koľajnice eÅ¡te o 1-nu pozíciu na kopec a tak isto aj na druhej strane. MyÅ¡ou klikni na nástroj tunela. PokraÄuj kliknutím na jeden z koncov koľajníc (na kopci). Ak Ti vÅ¡etko presne lícuje (t.j. trafil si sa), Simutrans urobí tunel a odpoÄíta Ti náklady na stavbu. Nadmorská výška tratí, ktoré spájaÅ¡ tunelom musí byt' rovnaká. Inak sa Ti tunel nevytvorí. Pozn. prekladateľa : Pokiaľ zabudneÅ¡ na druhej strane urobit' ukonÄenie koľajníc, alebo ich tam ani nemáš, Simutrans vie aj v tomto prípade urobit' tunel. Koľajnice potom pripojíš (po navolení koľajníc) k tomuto voľnému koncu kliknutím na vchod do tunela. ;-)
Most - klikni na text : Mosty.
Stanica - nástroj slúži na stavbu železniÄnej stanice (zvlášt' osobnej a nákladnej). Osobná stanica je zastreÅ¡ená. Kliknutím myÅ¡ou na tento symbol sa Ti kurzor zobrazí v tvare jedného segmentu stanice. Samotnú stanicu s požadovanou dĺžkou potom staviaÅ¡ klikaním na voľné kolajnice. Stanica ale musí ležat' na rovnom teréne. V takejto stanici môžeÅ¡ nakladat' a vykladat' suroviny, tovar (nákladaná) alebo pasažierov (osobná). Množstvo Äakajúcich surovín, tovaru alebo poÄet pasiažierov pritom nezávisí od dĺžky stanice (pozn. prekladateľa : ale Äím je stanica dlhÅ¡ia, tým viac toho môžeÅ¡ odniest' alebo priniest' ;-) ). Jeden takýto segment dokáže obslúžit' max. 2 vozidlá (pozn. prekladateľa : prvý segment obslúži 1 vagón - s lokomotívou a ÄalÅ¡ie vždy po 2 vagónoch). Ak je dĺžka vlaku väÄÅ¡ia, presahujúce vagóny nebudú obslúžené. Ak z nejakých dôvodov nebudeÅ¡ mat' dostatok miesta pre dlhÅ¡iu stanicu, máš možnost' postavit' ,,rohovú'' stanicu. Najprv vybuduj úsek, pokiaľ sa dá. Potom pripoj koľajnice zboku klinutím na posledný segment a pokraÄuj potom pripájaním Äalších segmentov.
Depo - nástrojom môžeÅ¡ postavit' depo na konci koľajníc, príp. urobit' odboÄku a umiestnit' ho na jej koniec. MyÅ¡ou klikni na nástroj depa a klinutím ho umiestni na žiadané miesto. VÅ¡etky ostatné informácie o nákupe vozidiel sa dozvieÅ¡ kliknutím na vybudované depo a kliknutím na otáznik (pomoc) vedľa nadpisu.
ŽelezniÄné priecestie - touto voľbou staviaÅ¡ železniÄné priecestie. Kliknutím na tento symbol sa kurzor zobrazí ako križovatka železnice s cestou. Naraz môžeÅ¡ urobit' priecestie cez jednu koľaj. Ak ich tam máš viac, musíš kliknút' na každú jednu osobitne.

simutrans-124.3/simutrans/text/sk/roadtools.txt000066400000000000000000000077021474050137200217560ustar00rootroot00000000000000Nástroje na stavbu cesty - pomoc

Stavba cesty

Tu máš prístup ku všetkým nástrojom, ktoré budeš potrebovat' na stavbu cesty, autobusových zastávok, cestných tunelov, depa a nákladných rámp.

Cesta - nástrojom staviaÅ¡ cestu medzi dvoma ľubovolne vzdialenými bodmi (Å¡tvorÄekmi), alebo cestu Äast' po Äasti. Kliknutím na zvolené miesto vytvorenej cesty zase vytváraÅ¡ križovatky. Postup : Klikni myÅ¡ou na nástroj cesty a pokraÄuj kliknutím na bod, z ktorého chceÅ¡ viest' cestu. Kurzor bude zobrazený ako malý buldozér. Premiestni sa na koniec zamýšľanej cesty a klikni tam myÅ¡ou. Simutrans vytvorí spojenie medzi týmito dvomi bodmi. Pozn. prekladateľa : pokiaľ by sa Ti cesta zdala príliÅ¡ kľukatá, máš možnost' urobit' korekcie (zbúrat' tú Äast', kde budeÅ¡ robit' úpravy a potom pridávat' cestu Äast' po Äasti. Stavbu cesty po uhloprieÄkach je vhodnejÅ¡ie robit' Äast' po Äasti. Výsledok je lepší ;-) ). Na stavbu cesty môžeÅ¡ použit' len voľné pozície (Å¡tvorÄeky). Ak nechceÅ¡ križovat' inú cestu, použi stavbu mosta alebo tunela. Ak nie je možné úspeÅ¡ne pokraÄovat' v budovaní cesty, skús najprv vykonat' terénne úpravy.
Autobusová zastávka - nástrojom staviaÅ¡ obojsmerné autobusové zastávky. MyÅ¡ou klikni na nástroj a umiestni ju na cestu. Autobusová zastávka Ti tak umožní prijímat' a vysadzovat' pasiažierov v oboch smeroch. Zastávky je možné budovat' aj za sebou. Autobus tak vždy zastaví na tej, ktorú si mu v cestovnom poriadku oznaÄil. Autobusové zastávky nemôžeÅ¡ budovat' na koľajniciach, v zákrutách alebo priamo na križovatkách.
Tunel - voľbou tohto nástroja bude kurzor zobrazený symbolom tunela. Aby si tunel mohol úspeÅ¡ne vytvorit', musia mat' kopce rovnú stenu na oboch stranách. Pomôž si úpravou terénu. Potiahni cestu eÅ¡te o 1-nu pozíciu na kopec a tak isto aj na druhej strane. MyÅ¡ou klikni na nástroj tunela. PokraÄuj kliknutím na jeden z koncov cesty (na kopci). Ak Ti vÅ¡etko presne lícuje (t.j. trafil si sa), Simutrans urobí tunel a odpoÄíta Ti náklady na stavbu. Nadmorská výška ciest, ktoré spájaÅ¡ tunelom musí byt' rovnaká. Inak sa Ti tunel nevytvorí. Pozn. prekladateľa : Pokiaľ zabudneÅ¡ na druhej strane urobit' ukonÄenie cesty, alebo ju tam ani nemáš, Simutrans vie aj v tomto prípade urobit' tunel. Cestu potom pripojíš (po navolení cesty) k tomuto voľnému koncu kliknutím na vchod do tunela ;-).
Cestný most - klikni na text : Mosty.
Nákladná rampa - nástroj slúži na stavbu nákladnej rampy. Kliknutím myÅ¡ou na tento symbol sa Ti kurzor zobrazí v tvare nákladnej rampy. Nákladná rampa musí ležat' na konci cesty alebo konci odboÄky a musí byt' na rovnom teréne. MôžeÅ¡ postavit aj niekolko rámp vedľa seba. Tu môžeÅ¡ nakladat' a vykladat' suroviny aj tovar. Nákladné autá budú chodit' iba na tie rampy, ktoré im oznaÄíš v cestovnom poriadku. Množstvo Äakajúcich surovín alebo tovaru pritom nezávisí od poÄtu takýchto rámp vedľa seba (pozn. prekladateľa : ale Äím je viac rámp vedľa seba, tým viac toho môžeÅ¡ naraz odniest' alebo priniest' ;-) ). Jedna takáto rampa dokáže obslúžit' max. 2 vozidlá (vrátane prívesov).
Depo - nástrojom môžeÅ¡ postavit' depo na konci cesty, príp. urobit' odboÄku a umiestnit' ho na jej koniec. MyÅ¡ou klikni na nástroj depa a klinutím ho umiestni na žiadané miesto. VÅ¡etky ostatné informácie o nákupe vozidiel sa dozvieÅ¡ kliknutím na vybudované depo a potom kliknutím na otáznik (pomoc) vedľa nadpisu.
ŽelezniÄné priecestie - touto voľbou staviaÅ¡ železniÄné priecestie. Kliknutím na tento symbol sa kurzor zobrazí ako križovatka železnice s cestou. Naraz môžeÅ¡ urobit' priecestie cez jednu koľaj. Ak ich tam máš viac, musíš kliknút' na každú koľaj osobitne.

simutrans-124.3/simutrans/text/sk/save.txt000066400000000000000000000010261474050137200206770ustar00rootroot00000000000000Uložit' hru - pomoc

Uložit' hru

V dialógovom okne sa zobrazí zoznam názvov všetkých dovtedy uložených súborov. Ak chceš prepísat' existujúci súbor, klikni na príšlusný názov (identifikátor) súboru. Simutrans uloží Tvoju hru s týmto názvom.

Ak chceÅ¡ ulozit' hru s novým názvom, klikni na horné textové pole a zadaj svoj názov súboru. Kliknutím na ,,OK'' bude nový súbor so zadaným názvom uložený. Hru vymazeÅ¡ kliknutím na znaÄku ,,X'' vedľa názvu.

simutrans-124.3/simutrans/text/sk/schedule.txt000066400000000000000000000043371474050137200215450ustar00rootroot00000000000000Cestovný poriadok - pomoc

Cestovný poriadok

Popis tlaÄidiel :

Pridat' - toto tlaÄidlo je aktívne hneÄ po zobrazení. Namiesto kurzora s lupou by mal byt' žltý znaÄkovaÄ, ktorým pooznaÄuj v logickom slede vÅ¡etky zastávky, stanice alebo nákladné rampy.
U každej zastávky, stanice alebo nákladnej rampy môžeÅ¡ urÄit' s akým minimálnym vyt'ažením bude dopravný prostriedok odchádzat' (u nákladných dopravných prostriedkov odporúÄam pre nakladanie 80-100%, u autobusov je lepÅ¡ie ostat' na 0%). Dĺžku vlakov odporúÄam väÄÅ¡iu ako u konkurencie.
Ak by si vykonával nejaké úpravy terénu, cesty alebo železnice poÄas zadávania cestovného poriadku a vrátil sa spät' k zadávaniu, musíš kliknút' napr. na tlaÄidlo ,,Vložit' '' a následne na ,,Pridat' ''. Tým obnovíš zobrazenie žltého znaÄkovaÄa a môžeÅ¡ pokraÄovat' v zadávaní.
Maximálny poÄet zastávok alebo staníc v cestovnom poriadku môže byt' 16 ! (Obmedzenie ich fyzického poÄtu na mape som zatiaľ nezistil).
Tip : Ak máš zapnutú konkurenciu, konkurencia môže (ale nemusí) mat' vyt'aženie menÅ¡ie ako 100% a chodit' tak poloprázdna až takmer prázdna. Vykazuje tým nižší zisk. Pri odporúÄanom nastavení vyt'aženia nákladných dopravných prostriedkov môžeÅ¡ takto konkurenciu predbehnút' v zisku. Ak prevážaÅ¡ suroviny alebo tovar, kde je aj konkurencia, tam je lepÅ¡ie nastavit' minimálne vyt'aženie na 100% (=plne naložit') ;-).

Vložit' - zapnutím tohto tlaÄidla môžeÅ¡ vložit' pred oznaÄenú zastávku alebo stanicu ÄalÅ¡iu (napr. po rozšírení siete zastávok alebo staníc). Opät' pozor na maximálny poÄet zastávok alebo staníc.

Zmazat' - zapnutím tohto tlaÄidla môzeÅ¡ vymazat' ľubovolnú zastávku, stanicu alebo nákladnú rampu z cestovného poriadku (zastávka, stanica alebo nákladná rampa ale fyzicky zostáva, až kým ju nezbúraÅ¡)

Hotovo - potvrdením ukonÄíš zadávanie cestovného poriadku.

Pozn. prekladateľa : Pri zadávaní cestovného poriadku musíš kalkulovat' s trasou tak, aby si neprekroÄil maximálny poÄet zastávok.

simutrans-124.3/simutrans/text/sk/shiptools.txt000066400000000000000000000024571474050137200217760ustar00rootroot00000000000000Lodná doprava - pomoc

Nástroje lodnej dopravy

Tu máš prístup k všetkým pomôckam, ktoré potrebuješ na vybudovanie lodného parku a dokov.

Ako prvý nástroj je prístavné mólo. Prístavné mólo musí stát' na okraji pevniny. Móla môžeÅ¡ ukladat' vedľa seba a tým zväÄÅ¡ovat' ich obslužnú kapacitu. Mólo vložíš tak, ze klikneÅ¡ myÅ¡ou na symbol ,,dlaždica'' a umiestniÅ¡ ho na požadované miesto, najÄastejÅ¡ie v blízkosti nejakého priemyselného odvetvia. Ak si ho umiestnil správne, ostane tam. ÄŽalÅ¡ou pomôckou je stavba doku.
Dok postavíš podobným spôsobom ako prístavné mólo, ale dok musí stát' na vode ! MôžeÅ¡ si vybrat' medzi ľavým a pravým dokom. Akonáhle máš dok postavený, môžeÅ¡ kupovat' lode kliknutím na dok, zadat' cestovný poriadok - Äo, odkiaľ a kam prevážat'.
Pamätaj na to, že lode budú pri väÄších mólach zastavovat' na tom úseku (mieste), na ktorom si im oznaÄil zastávku pri zadávaní cestovného poriadku.

Pozor, doky nemôžu byt' vzdialené od móla !
Musia stát' vedľa móla. Kvôli terénu sú preto k dispozícii ľavý a pravý dok. Inak sú obe zhodné a ponúkajú nákup rovnakých typov lodí.

simutrans-124.3/simutrans/text/sk/sound.txt000066400000000000000000000007321474050137200210740ustar00rootroot00000000000000Zvuky a hudba - pomoc

Nastavenia zvukov a hudby

V tomto menu nastavuješ hlasitost' zvukov, hlasitost' hudby a ktorú skladbu chceš aktuálne prehrat'.

Pre zmenu hlasitosti zvukov a hudby uchop myšou jazdec posuvníka a posuň ho do želanej polohy. Posunom vľavo uberáš a posunom vpravo pridávaš hlasitost'. Na zmenu hlasitosti a zmenu prehrávanej skladby môžeš pouzit' aj klikanie na príslušné šípky posuvníkov.

simutrans-124.3/simutrans/text/sk/station.txt000066400000000000000000000030271474050137200214250ustar00rootroot00000000000000 Stanica, zastávka

Stanica, zastávka a nákladná rampa

Tu sa dozvieÅ¡ informácie o stanici, zastávke, alebo nákladnej rampe, ktorú si zvolil. Prvou informáciou je Äakajúci tovar, ktorý je potrebný pre blízko ležiace priemyselné odvetvia a na ktoré stanice alebo zastávky sú priame spojenia.

MôžeÅ¡ tiež premenovat' svoju stanicu alebo zastávku - klikni na textové pole s názvom svojej stanice alebo zastávky. Objaví sa kurzor, Äo znamená, ze môžeÅ¡ upravovat' názov. Po úpravách názvu stlaÄ kláves Enter.

Informácia o zastávke zobrazuje, ktorý tovar alebo pasažieri Äakajú na stanici. Informácie sú usporiadané tak, že každá má svoje záhlavie pre rozdielny typ tovaru a iné, napr.
402 áut Äaká
83 pasažierov Äaká

a každá informácia z tohoto záhlavia ešte môže obsahovat' podrobnejšie údaje (podriadené). Tieto udávajú cieľ, kam má tovar íst' a presné množstvo tovaru alebo pasažierov napr.

56 pasažierov Äaká
- 25 pasažierov > Prešovská Kopanica BF
- 29 pasažierov > Trnavské Mesto cez Svitovská Dedina východ
- 2 pasažieri > Košické Mesto Hlavné H

Úplne vpravo nájdeÅ¡ tlaÄidlo ,,Detaily''. Obsahuje informácie o tovare potrebnom pre Äalší priemysel, priamych spojeniach s Äalšími stanicami alebo zastávkami a tovar, ktorý sa sem priváža alebo odtiaľto odváža preÄ. VÅ¡etko je usporiadané tak, že okamžite máš prehľad odkiaľ, Äo a kam ide.

simutrans-124.3/simutrans/text/sv.tab000066400000000000000000001156521474050137200177160ustar00rootroot00000000000000Svenska PROP_FONT_FILE Prop-Latin1.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: sv Svenska # # Encoding: ISO-8859-1 # # Font: Prop-Latin1.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ AMBIENT_SOUND omgivningsljud CASH_SOUND kassakling cl_btn_filter_disable av cl_btn_filter_enable på cl_btn_filter_settings inställningar cl_btn_sort_asc stigande cl_btn_sort_desc fallande cl_btn_sort_id ID-nummer cl_btn_sort_income intäkter cl_btn_sort_name beteckning cl_btn_sort_type typ clf_btn_alle alla clf_btn_invers byt clf_btn_keine inga gl_btn_sort_bonus bonus gl_btn_sort_name namn gl_btn_sort_revenue intäkter gl_btn_unsort osorterade hl_btn_filter_disable av hl_btn_filter_enable på hl_btn_filter_settings inställningar hl_btn_sort_asc stigande hl_btn_sort_desc fallande hl_btn_sort_name beteckning hl_btn_sort_type typ hl_btn_sort_waiting Väntande hlf_btn_alle alla hlf_btn_invers byt hlf_btn_keine inga Networks Linjenät Queueing kötrend Road toll Vägtull Scenario Scenario info #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Polarklimat desert Ökenklimat mediterran Medelhavsklimat rocky Fjällklimat temperate Tempererat klimat tropic Tropiskt klimat tundra Tundra #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Laddningen av scenario skriptet (.nut) misslyckades. Can't buy obsolete vehicles! Du kan inte köpa utgångna fordonsmodeller! Cannot built depot here! Fordonshall kan inte byggas här! Cannot built this station/building\nin underground mode here. Byggnaden kan enbart\nbyggas ovan jord.\n\n Cannot create generic line!\nSelect line type by\nusing filter tabs. Det går inte att skapa en linje av generell typ.\nVälj linjetyp med hjälp av filtreringsflikarna. Cannot create socket Kan inte skapa sockel Convoi handles exhausted! Största tillåtna antal konvojer har nåtts. Convoy already deleted! konvojen har redan raderats! Das Feld gehoert\neinem anderen Spieler\n Den här mark-\nbiten ägs av\nen annan spelare!\n Der Besitzer erlaubt das Entfernen nicht Ägaren tillåter\ninte att\ndetta tas bort!\n Diese Zusammenstellung kann nicht fahren!\n Denna kombination\nkan ej köra!\n Flugzeughalt muss auf\nRunway liegen!\n Flygplan kan bara\nlanda på flygplatser!\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Här kan man inte\nbygga den här flygplats-\nbyggnaden.\n Hier kann kein\nSignal aufge-\nstellt werden!\n Här kan man\ninte bygga\nnågon signal! In order to lock the game, you have to protect the public player by password! För att kunna låsa spelet krävs det att den allmänna spelare är skyddad med lösenord! Lost connection\nto server! Tappat anslutningen\till servern! Lost synchronisation\nwith server. Ej längre\nsynkroniserad\nmed servern! Maglevhalt muss auf\nMaglevschiene liegen!\n En magnetspårsstation måste placeras på magnetspår! Monorailhalt muss auf\nMonorail liegen!\n Monorailhållplatser\nmåste placeras på monorail. Monorails are not available yet! Det går ännu inte att bygga monorail. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Smalspårsstation måste\nligga på ett smalspår!\n No through station here! Här kan inte byggas någon hållplats. Not enough money! Pengarna räcker int\ntill för att bygga detta! On narrowgauge track only!\n En smalspårshållplats måste ligga på smalspår. Out of funds Du har inte tillräckligt med pengar för detta! Post muss neben\nHaltestelle\nliegen!\n En stationstillbyggnad (t ex\n\npostkontor, lager)\n\nmåste byggas på en fri\n\nyta i direkt anslutning\n\ntill en hållplats! Protocoll error (expecting game) Protokollfel (spel förväntades) Schiffhalt muss im\nWasser liegen!\n Fartygshållplatser\nmåste placeras\ni vatten!\n Server busy Servern upptagen Terraforming not possible\nhere in underground view Det går inte att förändra\nlandskapet på detta sätt under jord.\n Upgrade must have\na higher level Kan enbart uppgraderas till högre nivå Vehicle %s cannot choose because stop too short! %s kan inte välja plattform eftersom alla är för korta! Zughalt muss auf\nSchiene liegen!\n Tåghållplatser\nmåste placeras\npå järnvägsspår!\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Hjälp

Hjälp Index

Om Simutrans

%1$s

Att använda

%2$s

Att starta ett spel

%4$s

Hur man spelar

%5$s

Verktyg

%3$s

Övriga fönster

%6$s Keyboard Help\n

Keyboard Help

\n Tangentbordshjälp\n\n

Tangentbordshjälp

\n

\nTangentbordshjälp visar vilka funktioner som aktiveras av tangentbordets olika tangenter.\n

\n

\nTangentbordshjälp öppnas när en tangent som ej är kopplad till någon funktion trycks ner eller frånAllmän hjälp.\n

\n

\nTangentnedtryckningar är skiftlägeskänsliga (använd [Skift] för stora bokstäver).\n

\n

\nExempel på tangenter som är kopplade till en viss funktion är:\n

\n

\n[Piltangenterna]: rulla spelplanen i tangentens riktning.
\n[Bakåtsteg]: stäng alla fönster, verktygsmenyer och hjälptexter som finns öppna på spelplanen.
\n[Delete] eller [Escape]: stäng det översta fönstret, verktygsmenyn eller hjälpfönster som finns öppet på spelplanen.
\n[Enter] eller [Return]: används för att bekräfta handlingar.
\n[Page-Up] eller [>]: zooma in på spelplanen.
\n[Page-Down] eller [ mindre än-symbolen]: zooma ut på spelplanen.\n[F1]: öppna Simutrans-hjälpen.

\n

\n[1]: rulla spelplanen mot söder.
\n[2]: rulla spelplanen mot sydöst.
\n[3]: rulla spelplanen mot öster.
\n[4]: rulla spelplanen mot sydväst.
\n[6]: rulla spelplanen mot nordöst.
\n[7]: rulla spelplanen mot väster.
\n[8]: rulla spelplanen mot nordväst.
\n[9]: rulla spelplanen mot norr.\n

\n

\n[Skift] + mouse: använd på kartan för att se länkar i industrinförsörjningskedjan.
\n[CTRL] + verktyg: bygg (signaler & Stationer) på den övre nivån; eller bygg långsammare vägar and järnvägar över existerande; eller bygg rakare vägar och järnvägar.
\n[CTRL] + ([ Overlay city limits Visa stadsgränser Overlay passenger destinations when a town window is open Visa resmål för passagerare i den stad vars informations fönster är öppet Overlay town names Visa stadsnamn Show capacity and if halt is overcrowded Visa kapacitet och status Show speedlimit of ways Visa vägarnas hastighetsbegränsningar #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n Nu kan turisterna\nåka i %s regi\nmellan %s\noch %s på (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s kör nu arbetare\nfrån %s\ntill fabriken %s\n på (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nhar nu\n%i lastbilar i trafik mellan\n%s vid (%i,%i)\noch %s\nvid (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nöppnade en ny järnväg\nmellan %s\nvid (%i,%i) och\n%s\nvid (%i,%i).\n\n Airline service by\n%s\nnow between\n%s \nand %s.\n Nu flyger %s mellan\n%s och %s!\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Skepp ohoj!\n%s kryssningsfartyg\ntar nu passagerare från\s%s till %s. Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Det finns nu en ny\nförbindelse i\n%ss\nregi mellan %s\noch %s. #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS Kartredigerare LISTTOOLS Listor MAGLEVTOOLS Magnetspårsverktyg MONORAILTOOLS Monorailverktyg NARROWGAUGETOOLS Verktyg för smalspår RAILTOOLS Järnvägsverktyg ROADTOOLS Vägverktyg SHIPTOOLS Kanaler, hamnar och varv SLOPETOOLS Markhöjdsverktyg SPECIALTOOLS Specialbyggnader TRAMTOOLS Spårvägsverktyg #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). Ett nytt huvudkontor har byggts av %s. Factory chain extended\nfor %s near\n%s built with\n%i factories. Ekonomin är stark:\n%s nära %s utvidgar.\n%i nya fabriker har öppnat. New %s now available:\n%s\n %s av typen \n'%s'\nhar börjat tillverkas.\n New factory chain\nfor %s near\n%s built with\n%i factories. Industritillväxt: Ny fabrikskedja\ntill %s nära\n%s byggd med\n%i fabriker. New vehicle now available:\n%s\n \nEtt nytt fordon är\n nu tillgängligt:\n\n\n -- %s --\n\n Now %u clients connected. Just nu %i spelare anslutna. Remove vehicle from map. Use with care! Fordonet tas bort. Försäljningsvärdet tillgodoskrivs som vinst. Screenshot\ngespeichert.\n Skärmbild\nsparad.\n Sends the convoi to the last depot it departed from! Sänder konvojen till fordonshallen den startade från. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. I %s\ninvigs ett nytt\nmonument.\n%i åskådare deltar\ni festligheterna. #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (i fordonshall) \nBauzeit bis t o m \nBauzeit von \nKan byggas fr o m \nCan't open heightfield file.\n \nKan inte öppna höjdkartefilen.\n \ndirection: \nRiktningar: \nelektrified \nelektrifierad\n \nHeightfield has wrong image type.\n \nFel filtyp.\n \nis reserved by: \ntågväg är lagd för: \n \nminimum speed: \nminsta tillåtna hastighet: \nnot elektrified \nej elektrifierad\n \nRibi (masked) \nriktningar (dolda): \nRibi (unmasked) \nriktningar (alla): \nSet phases: \ange tidsintervall NS/ÖV riktning: \nsingle way \nEnkelriktat \nway1 reserved by \nväg 1 är reserverad av \nway2 reserved by \nväg 2 är reserverad av \nwith sign/signal\n \n med skylt/signal\n %d buildings\n %d byggnader\n %d convois %d konvojer %d Einzelfahrzeuge im Depot Här förvaras %d fordon %i km/h (max. %ikm/h) %i km/t (max %i km/t) %i years %i months old. %i år %i månad(er) gammal. %s building %s %s %s %s %s %s city %d %s %s %d stad %s %s factory %s %s %s %s gods%s %s has entered a depot. %s\nhar nått fordonshall %s land %d %s %s %d yttre %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. Borgmästaren vägrar frysa mer:\nNytt rådhus byggt i %s\n när staden blev %i invånare stor.\n %s\nis crowded. %s är överfull. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\nhastighet %i\nhögsta hastighet %i\ndx:%i dy:%i %s\nwas liquidated. %s är bankrutt och\nhar blivit likviderad.\nAll verksamhet har upphört\noch alla tillgångar sålts. %u Client(s)\n %i klient(er)\n %u Player (%u locked)\n %i Spelarplatser (%i lösenordsskyddade)\n < Ny linje > 1 convoi 1 konvoj 1 Einzelfahrzeug im Depot Här förvaras 1 fordon 1LIGHT_CHOOSE Ljusstyrka: 1WORLD_CHOOSE Inställningar för nytt spel: 2LIGHT_CHOOSE Färger: 2WORLD_CHOOSE Kartnummer: 3LIGHT_CHOOSE Rullningsfart: 4LIGHT_CHOOSE Omvänd rullning 5LIGHT_CHOOSE Fotgängare vid stationer 5WORLD_CHOOSE Antal städer: 6LIGHT_CHOOSE Fotgängare i städer 6WORLD_CHOOSE Trafiktäthet: 8WORLD_CHOOSE Skilj på dag och natt A bridge must start on a way! Broar måste börja/sluta\ni änden av en befintlig \nväg eller på en tom \nsluttning! Abfrage Granskningsverktyg Abnehmer Konsumenter About Om About scenario Copyright Abriss Rivningsverktyg Absenken Sänk marknivån Abspanntransformator Transformatorstation Accelerate time Accelerera tidsförlopp Act. load: %u MW\n Förbrukning: %u MW\n Active player only Endast aktiv spelare Add forest Lägg till skog Add random citycar Lägg till slumpmässig stadsbil add server Lägg till server Add Stop Lägg till Add stops for backward travel Lägg till stopp på vägen tillbaka. air flyg aircraft_tab Fraktflygplan airplane Flygplan Airport Flygplats AIRTOOLS Flygplatsverktyg All Alla all convoi tooltips alla konvojtips alltid Allow city growth Tillåt stadstillväxt Allow player change Tillåt spelarbyte allowed climates:\n Klimatzoner: Alters a schedule. Ändrar en tidtabell Angenommene Waren --Varor som kan levereras hit anhaengen Häng på Anhaenger_tab Släpvagnar Anheben Höj marknivån Appends stops at the end of the schedule Lägg till stopp i slutet av tidtabellen Apply Line Använd linje Arbeiter aus: Arbetarna bor i: Arrivals from\n Ankommande från\n Arrived Varuleverans Assets Fordonsvärde Aufloesen Upplös Aufspanntransformator Transformatorstation August Augusti Autohalt muss auf\nStrasse liegen!\n Buss- och lastbilshållplatser måste ligga på en väg.\n Available Tillgänglig Bahndepot Lokstall/vagnhall Bankrott:\n\nDu bist bankrott.\n Bankrutt:\n\nDu är bankrutt.\n battery Batteri Baum Träd baum builder Plantera träd Baustelle Byggplats Bauzeit Byggnadstid Beenden Avsluta Beginner mode Nybörjarläge Besonderes Gebaeude Turistattraktion BF station bio biologisk Blockstrecke ist\nbelegt\n Spårblocket är\nupptaget\nav ett annat tåg\n Boden Mark Bonusspeed: %i km/h Högsta möjliga hastighet: %i km/h bridge is too high for its type! Dalen är för djup för\ndenna typ av bro!\n Bridge is too long for this type!\n Spannet skulle bli för\nlångt för denna typ av bro!\n Bruecke Bro Bruecke muss an\neinfachem\nHang beginnen!\n Broar måste\nbörja på\nraka sluttningar!\n Brueckenboden Bro Build air depot Hangar build choosesignals Infartssignaler Build city market Ny affärsbyggnad Build drain Transformatorstation build HQ Huvudkontor Build land consumer En ny industrikedja kommer att byggas Build maglev depot Maglevfordonshall Build monorail depot Monorailfordonshall Build narrowgauge depot Smalspårsfordonshall Build powerline Kraftledning Build presignals Tvåblockssignaler Build road depot Garage Build ship depot Bygg skeppsvarv Build signals Bygg signaler Build train depot Bygg lokstall/vagnhall Build tram depot Bygg spårvagnshall Build truck depot Bygg garage Building costs estimates Uppskattad byggkostnad Buildings Antal hus Built artifical slopes Bygg konstgjorda sluttningar Built random attraction Ny sevärdhet Bus_tab Bussar Can only move from halt to halt or waypoint to waypoint. Kan endast flytta \nfrån hållplats till hållplats eller \nfrån vägpunkt till vägpunkt. Cancel Avbryt Cannot connect to offline server! Kan inte ansluta till server som är offline! Capacity Kapacitet Capacity: Kapacitet: Capacity: %.0f MW Kapacitet: %.0f MW\n Capacity: %d%s %s\n Kapacitet: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) Kapacitet: %s\n? %d (%d%%) Cars are not available yet! Det finns inte ens hästar än!\nBörja från första knallen... cars.\nstate fordon\n Cash Konto Change player Byt spelare Chart Statistik Chat_msg Chatt Choose direction Välj riktning Choose operation executed on clicking stored/new vehicles Välj vad som skall hända när du klickar på nya fordon eller fordon i fordonshall. chooses a random map Väljer slumpkarta. citicens Medborgare City attraction Stadsattraktion City industries Affärer i städer City list Stadslista City size Storlek city_road Gata citybuilding builder Bygg stadsbyggnader CityLimit Stadsgränser cl_title Fordonslista cl_txt_sort Sortera efter: Clear block reservation Visa/lös upp lagda tågvägar clf_chk_aircrafts Flygplan clf_chk_cars Landsvägsfordon clf_chk_indepot I fordonshall clf_chk_maglev Maglevtåg clf_chk_monorail Monorailtåg clf_chk_name_filter Filternamn: clf_chk_narrowgauge Smalspårståg clf_chk_noincome Inga intäkter clf_chk_noline Ingen linje clf_chk_noroute Ingen rutt clf_chk_noschedule Ingen tidtabell clf_chk_obsolete föråldrad clf_chk_ships Fartyg clf_chk_spezial_filter Specialfilter: clf_chk_stucked Blockerad clf_chk_trains Tåg clf_chk_trams Spårvagnar clf_chk_type_filter Filtrera typ: clf_chk_waren Varufilter: clf_title Fordonslista - inställningar Climate Control Välj klimat closed stängd COLOR_CHOOSE\n Välj en färg\nfrån paletten:\n Company bankrupt Företaget är satt i konkurs! Company_msg Konkurrenter Comparing pak files ... Jämför PAK filer ... Configure AI Konfigurera AI Configure AI setttings Justera parametrar för datormotståndare Congratulation\nScenario was complete in\n%i months %i years. Gratulationer!\nDetta scenario har \nspelats klart på \n%i månader och %i år! Connected stops Hållplatser (med anslutning till denna fabrik) Connected with server Anslut till server Constructed by Skapad av Constructed by %s Skapad av %s Construction_Btn Byggkostnader Consumed Förbrukat convoi %d of %d Konvoj %d från %d convoi error tooltips alltid konvojfel Convoi has been sent\nto the nearest depot\nof appropriate type.\n Fordonet har skickats\ntill närmaste fordons-\nhall av lämplig typ. Convoi is sold when all wagons are empty. Konvojen kommer att tas bort så fort som den är tömd. Försäljningsvärdet kommer att tillgodogöras kassan. convoi mouseover tooltips konvojstatus vid muspekning convoi passed last\nmonth %i\n \nkonvojer som passerade\nförra månaden: %i\n Convois Konvojer Convois: %d\nProfit: %s Fordon: %d\nVinst: %s Convoys Konvojer Copy Convoi Kopiera konvoj Copy the selected convoi and its schedule or line Gör en kopia av konvojen med dess tidtabell eller linje Cost Kostnad cost for removal Kostnad för att ta bort Costs Kostnader Create a new line based on this schedule Skapa en ny linje baserad på denna tidtabell. curiosity builder Bygg sevärdheter curlist_title Turistmål Currently playing: Spelar just nu: Deccelerate time Sänk spelhastigheten decrease underground view level Sänk kartans utsnittshöjd. Del Stop Ta bort Delete Line Ta bort linje Delete the current stop Ta bort nuvarande hållplats Delete this file. Ta bort denna fil. Delivered Levererat Demand Efterfrågan Demand: %.0f MW Efterfrågan: %.0f MW\n Denkmal Minnesmärke Departed Avgått Depots Fordonshallar Der Tunnel ist nicht frei!\n Tunneln är inte tom.\n Details Detaljer Die Bruecke ist nicht frei!\n Bron är inte tom!\n Direkt erreichbare Haltestellen --direkta trafikförbindelser: disable midi Tysta MIDI-musiken Display settings Visning: Distance Färdsträcka Dock Hamn Dock must be built on single slope! Hamnar måste byggas\npå en rak sluttning! Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Du har %d månader på dig att betala dina skulder. Durchsatz Max. Economy Ekonomi och städer Eigenbesitz\n Allmän egendom\n Ein %s\npasst hier nicht.\n En '%s'\npassar inte här.\n Einstellungen aendern Ändra alternativ electric elektrisk Electricity Strömförsörjning Electricity producer\n\n Elektricitetsproducent\n\n Electrics_tab Elektricitet Electrify track Elektrifiera spåret enlarge map Gör kartan större enter a value between %i and %i Välj ett värde mellan %i och %i. Enter address Server adress Enter Password Ange lösenord Error Ett fel har uppstått... Erzeuge neue Karte.\n Vänta,\nskapar en\nny karta...\n\n(Det här kan ta\nnågra minuter\npå stora kartor.)\n Es wird bereits\nein Fahrplan\neingegeben\n Du håller redan på att\nsammanställa en tidtabell! Fabrikanschluss --Fabriker som har anslutning till denna hållplats Fabrikname Fabriksnamn Factories Fabriker factory details Fabriksinformation factorybuilder Bygg industrianläggningar Fahrplan Tidtabell Fahrtziel Färdmål: Fahrzeuge koennen so nicht entfernt werden Det går inte att ta bort\nfordon/fartyg på det här sättet!\n Fahrzeuge: Fordon/fartyg: Farbe Spelarfärg Fast forward Snabbspola February Februari Ferry_tab Färjor Fertig Klar Filename Filnamn: Finances of %s Finanser för %s Finanzen Finanser fl_title Fabrikslista Flug_tab Passagerarflygplan follow me Följ mig Follow the convoi on the map. Följ denna konvoj. Forest Skog Found new city Grunda ny stad FPS: Bildhastighet (fps): Fracht Frakt Frame time: Bildfrekvens: Free Capacity Fri kapacitet freeplay mode ingen bankrutt Friction: Nuvarande friktionsfaktor: fuel_cell bränslecell Full load Minimilast: Fussgaenger Fotgängare GAME PAUSED Spelet är pausat Gear: Utväxling: Gebaeude Byggnader General Allmänt Generation: %.0f MW Produktion: %.0f MW\n Gewicht Vikt Gewinn Vinst: Give the selected vehicle(s) an individual schedule Tilldela de valda fordonen en egen tidtabell. gl_btn_sort_catg typ gl_title Varulista go home Till fordonshall Goods Varor Goods AI Frakt-AI Goods list Varuöversikt Gross Profit Bruttovinst Groundobj Föremål Grow city Utöka invånarantal Growth Tillväxt Happy Tillfreds Haus kaufen Köp hus Helligk. Visning Help Hjälp Help text not found Det går bara att\nvisa hjälptexter som\nredan finns. Ställ\ndin fråga till\nett av Simutrans-forumen. hide all building Krymp alla byggnader hide city building Krymp stadsbyggnader hide station names Dölj stationsnamn hide transparent Genomskinlig istället för krympt hide trees Krymp träd Hier warten/lagern: Väntande varor och passagerare: hl_title Stationslista hl_txt_filter Filter: hl_txt_sort Sortera efter: hlf_chk_airport Flyg hlf_chk_anleger Sjöfart hlf_chk_bahnhof Järnväg hlf_chk_bushalt Buss hlf_chk_frachthof Lastbil hlf_chk_keine_verb Otrafikerad hlf_chk_maglevstop Maglev hlf_chk_monorailstop Monorail hlf_chk_name_filter Filternamn: hlf_chk_narrowgaugestop Smalspårsstation hlf_chk_overflow Överfull hlf_chk_spezial_filter Specialfilter: hlf_chk_tramstop Spårvagn hlf_chk_type_filter Filtrera typ: hlf_chk_waren_abgabe Utgående varor: hlf_chk_waren_annahme Inkommande varor: hlf_title Stationslista - inställningar Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Vet inte var fordonet \nhör hemma! Lägg\nmanuellt till\ndetta i färdplanen. Homeless Hemlösa hydrogene vätgas Idle: Tomgång: ignore climates Alla klimatzoner In Transit Under färd Increase Industry density Höj industridensiteten increase underground view level Öka kartans utsnittshöjd. industrial building Industribyggnader Init map ... Kartan läses in... Input tillförd Ins Stop Infoga Insert stop before the current stop Infoga stopp före den valda hållplatsen Intercity road len: Längd på vägar mellan orter: Intro. date: Introduktion: invalid odefinierad Invalid coordinate Ogiltig order isometric map Isometrisk karta January Januari join game Anslut till spel! July Juli Jump to Centrera runt June Juni Kann Spielstand\nnicht laden.\n Kan inte öppna\ndet sparade spelet!\n Kann Spielstand\nnicht speichern.\n Kan inte spara\nspelet!\n Kein Besitzer\n Ingen ägare\n keine inga Keine Einzelfahrzeuge im Depot Här förvaras inga fordon Keyboard_Help\n Tangentsbordshjälp\n koord koordinater Kreuzung Järnvägskorsning labellist_title Lista över skyltar Lade Relief Läs in höjdkarta Laden Läs in Land attraction Utflyktsmål Land industries Industrinätverk LANG_CHOOSE\n Välj ditt språk:\n Last Year Förra året Leaving depot! Lämnar fordonshall! leer tom Legend Kartinfo Leistung Effekt Leistung: %d kW Effekt: %d kW Leitung Högspänningsledningar letzen Monat: diesen Monat: Förra månaden: Den här månaden: Line Linje Line Management Linjehanteraren Lineless convoys serving this stop Ej linjeanknutna konvojer som betjänar denna hållplats Lines serving this stop --Linjer som trafikerar denna hållplats LKW_tab Lastbilar Load game Ladda spel load height data from file Läs in höjddata från fil. Load scenario Ladda scenario loaded lastad loaded passenger/freight Sortera pass./varor efter Loading (%i->%i%%)! Lastar (%i->%i%%) Loading addon paks ... Läser in tilläggspaket (addon paks) Loading map ... Kartan laddas... Loading paks ... Läser in paket (pak) ... Loading skins ... Läser in skinn ... Lock game Tillåt inte spelarbyte under spelets gång (kräver konfirmation). Lokomotive_tab Lokomotiv m3 m³ Maglev Magnetspår maglev vehicle Magnetspårsfordon maglev_track Magneträls Maglevdepot Magnetspårsvagnhall Mailbox Meddelanden Mailbox Options Meddelandealternativ Maintenance Underhåll make stop public (or join with public stop next) costs %i per tile and level Skapa eller anknyt till existerande allmän hållplats (%i$ per ruta och nivå) Manual (Human) Människa (utan AI) Manufactured: Tillverkad: Map roughness Bergighet map zoom zoom March Mars Margin (%%) Marginal Marker Skapa en skylt Max income: Max. inkomst: Max. speed: maxhastighet: Maximum 254 stops\nin a schedule!\n Det får inte finnas mer än\n254 stopp i en tidtabell!\n maximum length of rivers Längsta flodlängd Maximum tile height difference reached. Höjdskillnaden\nmellan två rutor\nfår inte överstiga\ntvå steg. Maxspeed Högsta hatstighet May Maj Median Citizen per town Medianstorlek för städer: Meldung Meddelande Menge antal MessageOptionsText \nNytt år\n\nAI:n bygger\n\nStadsnyheter\n\nRutt saknas\n\nNy industri\n\n"chat"\n\nNy fordonstyp\n\nFulla stationer\n\nGenerella problem\n\nVarningar\n\nScenario min min. minimum length of rivers Minsta flodlängd Modify the selected line Ändra in den valda linjen Monate alt månader gammal. monorail vehicle Monorailfordon monorail_track Monorailräls Monorailboden Upphöjd vägsträcka Monoraildepot Monorailvagnhall month wait time Månaders väntetid Months Månader Monuments Monument Mountain height Bergshöjd Movingobj Rörliga Music playing disabled/not available Musik avstängd/ej tillgänglig Music volume: Musikvolym: mute sound Stäng av allt ljud Name Namn Narrowgauge Smalspår Narrowgauge are not available yet! Smalspår finns ännu inte tillgängligt! narrowgauge vehicle Smalspårsfordon narrowgauge_track Smalspår Narrowgaugedepot Smalspårsvagnhall Net ID: %p Nät-ID: %p\n Net Wealth Nettotillgångar Neue Karte Ny karta Neue Welt Skapa ny värld new convoi Ny konvoj New Line Ny linje New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Ny linje skapad!\nDu kan nu välja att\nknyta konvojen\ntill den ovan. New Vehicles Nya fordon no buildings hidden Inga byggnader krympta no convois Inga konvojer No goods are loaded onto this convoi. Lasta inte på mer. no goods waiting inga varor väntar no load Ingen last No Route Ingen rutt No stop here! Verktyget går enbart att använda på hållplatser! No suitable ground! Olämplig mark! No terminal station here! En ändstation kan\nendast byggas vid slutet\nav en led! no timeline utan tidslinje no tree Inga träd Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Det finns ännu inte någon\ntidtabell att köra efter! none ingen nord Norra nordost Nordöstra nordwest Nordvästra Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Detta går inte!\nFordonets tidtabell kan\nför närvarande inte ändras.\nFörsök igen senare! Not enough fields would remain. Det måste finnas ett\nvisst antal fält\nkvar runt varje bondgård. Now active as %s.\n Du är nu spelare:%s.\n Number of rivers Antal floder Object Objekt Odometer: %s km Färdmätare: %s km Ok OK On loan since %i month(s) Kontot övertrasserat i %i månad(er) On this map, you are not\nallowed to change player!\n Detta spel är låst.\nInga spelarbyten är tillåtna\npå denna karta.\n Only city chains Endast stadsnätverk Only land chains Endast fabriker utanför städer Only one transformer per factory! Endast en transformatorstation vid varje fabrik! open öppnad Operation Driftskostnader Ops Profit Driftsvinster Optionen Alternativ Origin Avgångsort ost Östra Output resultat paletten lastpallar Pas_tab Passagerartåg Passagiere Passagerare Passagierrate Passagerartal Passagierziele Destinationer för pass. och post Passenger AI Passagerar-AI Passengers %d %c, %d %c, %d no route Passagerare %d %c, %d %c, %d utan rutt Passengers %d %s, %d %s, %d no route Passagerare %d %s, %d %s, %d utan rutt Password Lösenord Pause Pausa PaxDest Resmål Percent Electricity Andel kraftverk (%%) Planes are not available yet! Flygplan har ännu inte uppfunnits! Plant tree Träd player Spelare player -1 Simutrans-spelare player 0 samhällsservice player 1 Napik 128 HB player 10 spelare 10 player 11 spelare 11 player 12 Spelare 12 player 13 Spelare 13 player 2 Trikky Transport player 3 Meyers Flytt AB player 4 Transport AB player 5 H-Trans AB player 6 PSK & Son AB player 7 Spelare 7 player 8 Spelare 8 player 9 Spelare 9 Please choose vehicles first\n Välj en konvoj först! Postrate Posttal Power Effekt Power (MW) Effekt (MW) Power: Effekt: Power: %4d kW\n Effekt: %4d kW\n Powerlines Kraftledningar Price Pris Problems_msg Problem Production of %s has been stopped:\n%s\n %s av typen \n'%s'\ntillverkas inte längre.\n Profit Vinst promote to line Ny linje q1 Vår q2 Sommar q3 Höst q4 Vinter Query server Kontaktar servern rail car Rälsfordon random slumpad Random age Slumpår Random map Slumpkarta Rathaus Rådhus Rating Rang ratio_pax Proportion Relevant Relevanta Reliefkarte Översiktskarta Remove Ta bort etikett remove airstrips Ta bort rullbana remove channels Fyll igen kanalsträcka remove interm. signals Ta bort mellanl. signaler remove maglev tracks Ta bort magnetspårssträcka remove monorails Ta bort monorailsträcka remove narrowgauge tracks Ta bort smalspårssträcka remove powerlines Ta bort kraftledningar remove roads Ta bort vägsträcka remove tracks Ta bort järnvägssträcka Remove wayobj %s Ta bort vägobjekt %s replace other signals Ersätt övr. signaler replace stop Ersätt hållplats request closing förbered nedstängning residential house Bostadshus Restore natural slope Återställ naturlig sluttning Restwert: Försäljningsvärde: Retire. date: Slopning: return ticket Spegla färdplan Revenue Inkomster road väg road vehicle Landsvägsfordon Roadsign Vägskylt Rotate map Vrid spelplanen 90° Routing Transportleder sack säckar sail vind Saving map ... Sparar karta... Scenario complete: %i%% Scenariomålen uppnådda till %i%% Scenario Debug Debug Scenario Error Log Fel Scenario Goal Mål Scenario Info Bakgrund Scenario Result Progress Scenario Rules Regler Schedule changing! Tidtabellen ändras! Schienentunnel Järnvägstunnel Schiff_tab Fartyg Schiffdepot Fartygsvarv Schleppkahn_tab Kanalpråmar Screenshot Skärmbild Seasons Årstider Sehenswuerdigkeit Sevärdhet Select a server to join: Välj server Sell the selected vehicle(s) Sälj det valda fordonet. sended Skickad post SEP_FRACTION , SEP_THOUSAND SEP_THOUSAND_EXPONENT 3 Server did not respond! Servern svarade inte! Serves Line: Trafikerar linje: Service Tillfartsvägar set signal spacing Ange signalavstånd Setting Inställningar Ship Fartyg shops and stores Affärsbyggnader Show all Visa allt show all building Visa alla byggnader Show also vehicles no longer in production. Visa även fordon som inte lägre är i produktion. Show also vehicles that do not match for current action. Visa även fordon som ej kan användas med vald handling. Show even servers with wrong version or pakset Visa även servrar som har fel version eller objektmodul show grid Visa rutnät Show industry Industrilista Show legend Information Show map scale Kartskala Show obsolete Visa även föråldrade Show offline Visa offline Show only used Visa enbart använda Show schedules Tidtabeller Show servers where game version or pakset does not match your client Visa servrar som inte är kompatibla med din version eller pakset show station coverage Visa stationstäckning show station names Visa stationsnamn show waiting bars visa staplar för väntande gods show/hide block reservations Visa/dölj blockresrvation Show/hide statistics Visa/dölj statistik Shows consumer/suppliers for factories Visar kunder (eller med skift nedtryckt: leverantörer) till fabriken under muspekaren Shows the currently selected schedule Visa aktuell tidtabell som en bild. Shrink city Minska invånarantal shuffle midis Slumpval signal spacing Signalavstånd Sim: Simloopar: Size (%d MB): Kartstorlek (%d MB): sliced underground mode Kartutsnitt slot empty tom Sort by sortera efter Sort waiting list by Sortera väntelistan efter Sound Ljud Sound settings Ljudinställningar Sound volume: Ljudvolym: special freight Specialfrakt Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. Hastighetsbonus\npå väg %i km/t, järnväg %i km/t\nfartyg %i km/t, flygplan %i km/t. Speedlimit Maxhastighet Speichern Spara Spieler Spelare Spieler(mz) Spelare Spielerliste Spelarlista Spielstand wurde\ngeladen!\n \nSpelet har lästs in!\n Spielstand wurde\ngespeichert!\n \nSpelet har sparats!\n Sprache Språk Sprachen Språkval Stadtinformation Stadsinformation Start Kör Start the selected vehicle(s) Skicka ut det valda fordonet. Starte Spiel Starta spel Station tiles: Stationsrutor: Status Hållplatsstatus steam ånga Step timeline one year Hoppa över ett år Storage Lager Storage capacity Förvaringskapacitet Strassendepot Garage Strassentunnel Bygg vägtunnel street car Spårvägsfordon sued Södra suedost Sydöstra suedwest Sydvästra Summer snowline Sommarsnögräns Suppliers Leverantörer Tage alt dagar. There are still vehicles\nstored in this depot!\n Det finns fort-\nfarande fordon här!\n This Month Denna månad This Year Hittills i år Tile not empty. Rutan är upptagen\noch kan för närvarande\ninte ändras.\n timeline med tidslinje tl_title Stadslista To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. För att attrahera fler turister har \n%s byggt\n%s\nför %i:- av skattebetalarnas pengar. To heavy traffic\nresults in traffic jam.\n Mycket trafik\norsakar trafikkaos.\n Toggle day/night view Växla mellan dag och natt Toggle vehicle tooltips Växla visning av verktygstips för fordon tonnen t Total inhabitants: Totalt antal invånare: Tourist attractions Turistattraktioner Tourists Sevärdheter Town_msg Nya resmål Town: %s\n Ligger i staden %s\n Towns Städer track räls Tracks Spår Traffic Trafik Train Tåg Trains are not available yet! Det finns ännu inte tåg! Tram Spårvagn tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. spårvagn %i km/t, monorail %i km/t\nmaglev %i km/t, smalspår %i km/t. tram_track spårvägsräls Tramdepot Spårvagnshall Trams are not available yet! Spårvagnar är ännu inte tillgängliga. Transferring game ... Överför spel... Transformer only next to factory! Transformatorer kan endast byggas\n på platt mark i anslutning\n till en industri! Translation Översättning transparent station coverage Genomskinlig stationstäckning Transported Antal resor TrolleyBus_tab Trådbuss Truck Landsvägsfordon Tunnel muss an\neinfachem\nHang beginnen!\n Tunnlar måste\nbörja på raka\nsluttningar!\n Tunnel must start on single way! Tunnel måste starta på en befintlig väg. Tunnelboden Tunnel underground mode Underjordsläge UNDO failed! Detta går inte längre\natt ångra! Man kan enbart\nångra direkt efter byggnation! Undo last ways construction Ångra senast byggda väg. Unemployed Arbetslösa Unhappy Missnöjda units/day enheter/månad Update Line Ändra linje upgrade HQ Uppgradera huvudkontor Usage: %.0f %% Användning: %.0f %% Use beginner mode Nybörjarläge Use timeline start year Följ tidslinje: Vehicle %s can't find a route! %s\nkan inte längre\nhitta någon väg! Vehicle %s is stucked! Fordon %s sitter fast! Vehicle details Fordonsdetaljer Verbrauch Konsumtion Vergroessere die Karte\n Förstora kartan\n verkaufen Sälj Verkehrsteilnehmer Stadsbilar Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n Du står i skuld!\n\nDu har %d månader på dig\natt återbetala din skuld.\n via %s\n via %s\n via Menge via (antal) voranstellen Ställ först Waggon_tab Vagnar waiting väntar Waiting for clearance! Väntar på fri väg! Warnings_msg Trafikrapport Wasser Vatten Water vatten Water level Vattennivå water vehicle Fartyg way %s cannot longer used:\n Vägtyp %s\nkan inte byggas längre!\n way %s cannot longer used:\n%s\n %s finns inte längre tillgänglig:\n way %s now available:\n Vägtyp %s kan\Nframöver byggas.\n Way toll Vägtull Ways not connected Vägarna hänger inte ihop!\n Wegpunkt Vägpunkt Weight: Vikt: Wert Värde west Västra Winter snowline Vintersnögräns withdraw Återkalla Withdraw All Återkalla alla WRONGSAVE Ej kompatibel spel-\nversion. Kan inte läsa\nin den här filen.\n Year %i has started. År %i har börjat. Years År Your primary color: Primärfärg Your secondary color: Sekundärfärg Zielort destination zooming in Zoomar in zooming out Zoomar ut Zu nah am Kartenrand För nära\nkanten på spelplanen för att kunna\nbygga någonting.\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Nytt världsrekord för magnetspårståg med: %.1f km/t av %s. New world record for monorails: %.1f km/h by %s. Ett nytt världsrekord\nför monorail: %.1f km/t\nav %s. New world record for motorcars: %.1f km/h by %s. Bengt Blyfot når\n%.1fkm/t med\n%s.\nNytt världsrekord! New world record for narrowgauges: %.1f km/h by %s. Ett nytt världsrekord för\nsmalspårtåg med %.1f km/t\nav %s. New world record for planes: %.1f km/h by %s. Lilienthals arvingar rapporterar\nnytt världsrekord:\nflög i %.f km/t\n%s. New world record for railways: %.1f km/h by %s. Där flög vevstaken\nsin väg. Lokförare\nCederlund körde i %.f km/t med \n%s. New world record for ship: %.1f km/h by %s. Ett nytt världsrekord för\nfartyg med: %.1f km/t\npå %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL by &1_CITY_SYLL stad &2_CITY_SYLL by &3_CITY_SYLL bro &4_CITY_SYLL brunn &5_CITY_SYLL berg &6_CITY_SYLL dal &7_CITY_SYLL fält &8_CITY_SYLL fors &9_CITY_SYLL sluss &A_CITY_SYLL vad &B_CITY_SYLL köping &C_CITY_SYLL hult &D_CITY_SYLL vik &E_CITY_SYLL borg %1_CITY_SYLL Lunds %2_CITY_SYLL Malm %3_CITY_SYLL Norr %4_CITY_SYLL Väster %5_CITY_SYLL Söder %6_CITY_SYLL Öster %7_CITY_SYLL Skog %8_CITY_SYLL Marie %9_CITY_SYLL Karls %A_CITY_SYLL Oskars %B_CITY_SYLL Alm %C_CITY_SYLL Böke %D_CITY_SYLL Gran %E_CITY_SYLL Tall %F_CITY_SYLL Ek 1center %s %s 1extern %s filial %s 1suburb %s %s %s 2center %s central %s 2extern %s annex %s 2suburb %s Nya %s %s 3center %s huvud%s 3extern %s landsbygd %s 3suburb %s by %s %s 4center %s inre %s 4extern %s yttre %s 4suburb %s koloni %s %s 6center %s centrum %s 6extern %s industriområde %s 7center %s stad %s simutrans-124.3/simutrans/text/sv/000077500000000000000000000000001474050137200172145ustar00rootroot00000000000000simutrans-124.3/simutrans/text/sv/airtools.txt000066400000000000000000000121321474050137200216100ustar00rootroot00000000000000Hjälp för flygplatsverktyg

Flygplatsverktyg

Flygplatsverktyg innehåller verktyg för att bygga upp ett flygtransportnätverk. Verktygen kan bygga eller ta bort taxibanor och landningsbanor för flygplan, flyghållplatser (för att hämta och lämna gods och passagerare), hangarer (för handel med och underhåll av flygfarkoster) och olika flygplatsbyggnader. Om du spelar med tidslinje aktiv så kan fler verktyg bli tillgängliga efterhand som tiden förflyter i Simutrans.

Klicka på flygplansikonen ovanför kartan för att öppna verktygsraden.
Låt muspekaren vila över ett verktygsalternativ (efter att du öppnat eller klickat på verktygsraden) för att se dess namn och där så tillämpligt: byggkostnader, underhållskostnad i parenteser, och hastighetsbegränsning.

{Tips: Ett sätt att bygga en enkel flygplats är:
i) bygg och bind samman taxibanor och landningsbanor;
ii) placera ut flyghållplatser i änden av taxibanorna;
iii) lägg till de flygplatsbyggnader som krävs.}

Bland verktygen kan finnas, från vänster till höger:

Taxibana: verktyget bygger markområden där flygplatser kan ta sig från en flyghållplats till en landningsbana. Taxibanor byggs på jämn mark på kartan.
VIKTIGT: Om taxibanor ansluter till änden av landningsbanan, så kan inte flygplan landa och lyfta.
För att bygga en taxibana: klicka på verktyget för att välja (pekaren ändras till en taxibana), klicka sedan på terrängen för att ange startpunkt (visar en bulldozer på kartan och visar kartkoordinater längst nere till höger i fönstret), och klicka slutligen på marken eller en landningsbana för att ange slutpunkt.
{Tips: Använd Förstör/Ta bort för att avlägsna enstaka bitar av en taxibana. Ångra [z] betalar inte tillbaka byggkostnader.}

Landningsbana: verktyget bygger en landningsbana där flygplan kan landa och lyfta. Landningsbanor byggs på jämn mark på kartan, och kan korsa varandra.
För att bygga en landningsbana: klicka på verktyget för att välja (pekaren ändras till en väg) och klicka sedan på marken för att ange startpunkt (visar en bulldozer på kartan) och klicka slutligen på marken för att ange slutpunkt.
{Tips: Låt ändarna av landningbanor vara fria annars så kan inte flygplan landa eller lyfta. Använd Förstör/Ta bort för att avlägsna enstaka bitar av en taxibana. Ångra [z] betalar inte tillbaka byggkostnader.}

Ta bort landnings- och taxibanor: verktyget tar bort ett segment mellan två punkter på kartan av en taxibana eller landningsbana när det inte finns några flygplan där. Det medför byggkostnader att använda verktyget.
För att ta bort en landnings- eller taxibana: klicka på verktyget (pekaren ändras till ett rött kors); klicka sedan på den bana som skall tas bort (väljer borttagningspunkt som visas som ett rött kors på kartan); klicka slutligen på en annan punkt på samma bana för att avlägsna sträckan mellan denna och den först angivna borttagningspunkten. {Tips: Låt ändarna av landningbanor vara fria annars så kan inte flygplan landa eller lyfta. Använd Förstör/Ta bort för att avlägsna enstaka bitar av en taxi- eller landningsbana.}

Hangarer: verktyg för att bygga hangarer för att köpa eller administrera flygplan. Hangarer kostar underhåll och byggs i slutet av en bit taxibana.
{Tips: Ta bort hangarer med Förstör/Ta bort.}

Flyghållplats&embarkeringsbrygga: verktyget bygger hållplatser på kartan där flygplan kan hämta och lämna gods eller passagerare.
En flyghållplats som inte byggs i anslutning till en existerande hållplats skapar en ny hållplats.
Flyghållplatser byggs i änden av en taxibana; kostar underhåll, har ett upptagningsområde för gods, passagerare och post. Ett flygplan landar enbart på en flygplats om det finns en ledig flyghållplats.
För att bygga en flyghållplats: klicka på verktyget för att välja det och klicka sedan på änden av en taxibana.
{Tips: Ta bort flyghållplatser med Förstör/Ta bort. Tryck [v] för att visa/dölja upptagningsområdet för gods och passagerare på kartan.}

Flygplatsbyggnader: verktyget bygger tillbyggnader till hållplatser som kan medföra ökade underhållskostnader och utökat upptagningsområde eller större lagringskapacitet för gods och passagerare. I hörnet av några verktygsalternativ visas en ikon (används i stationslistan & hållplatsinformation) som anger vad som tillbyggnaden möjliggör för hållplatsen att hantera.
För att bygga en tillbyggnad: klicka på verktyget för att välja tillbyggnad (pekaren ändras till tillbyggnaden) och klicka sedan på önskad plats i anslutning till en existerande hållplats på kartan. Den nya tillbyggnaden anses nu vara en del av hållplatsen..
{Tips: Ta bort tillbyggnader med Förstör/Ta bort. Tryck [v] för att visa/dölja upptagningsområdet för gods och passagerare på kartan.}

simutrans-124.3/simutrans/text/sv/baum_build.txt000066400000000000000000000017661474050137200220720ustar00rootroot00000000000000Plantera träd

Plantera träd

Dialogen är indelad i fyra sektioner.
· uppe till vänster finns en urvalslista över de trädtyper som är tillgängliga med angivna alternativ
· nere till vänster visas en bild över valt träd
· uppe till höger finns ett par alternativknappar
· nere till höger ges information om valt träd

Urvalslista

I urvalslistan ges alla tillgängliga trädtyper. Det finns två flikar som låter dig välja hur dessa trädtyper presenteras.
· Översättning: Visar trädnamnet med översatt till valt språk. Om det inte finns någon översättning så används objektnamnet i stället.
· Objekt: Visar det Simutrans-interna objektnamnet på för trädtypen.

Alternativ

· Alla klimatzoner: Detta alternativ avaktiverar de klimatbegränsningar som finns associerade med varje trädtyp.
· Slumpår: Åldern på det träd som skall planteras ges ett slumpvärde.

simutrans-124.3/simutrans/text/sv/citybuilding_build.txt000066400000000000000000000033111474050137200236200ustar00rootroot00000000000000Bygg stadsbyggnader

Bygg stadsbyggnader

Dialogen är indelad i fyra sektioner.
· uppe till vänster finns en urvalslista över de stadsbyggnader som är tillgängliga med angivna alternativ
· nere till vänster visas en bild över vald stadsbyggnad
· uppe till höger finns ett par alternativknappar
· nere till höger ges information om vald stadsbyggnad

Urvalslista

I urvalslistan ges alla tillgängliga stadsbyggnader. Det finns två flikar som låter dig välja hur dessa stadsbyggnader presenteras.
· Översättning: Visar stadsbyggnadens namn översatt till valt språk. Om det inte finns någon översättning så används objektnamnet i stället.
· Objekt: Visar det Simutrans-interna objektnamnet för stadsbyggnaden.

Alternativ

· Alla klimatzoner: Detta alternativ avaktiverar de klimatbegränsningar som finns associerade med varje byggnadstyp.
· Följ tidslinje: Urvalslistan innehåller enbart de byggnader som är tillgängliga innevarande Simutrans-år.
· Visa även föråldrade: Utöka urvalslistan med byggnader som är föråldrade innevarande Simutrans-år.
· Bostadshus: Urvalslistan innehåller bostadshus.
· Affärsbyggnader: Urvalslistan innehåller affärsbyggnader.
· Industribyggnader: Urvalslistan innehåller industribyggnader.
· Rotation: Om vald byggnad kan visas från olika vinklar, så är det här möjligt att ange vilken vinkel som skall användas. Bilden på byggnaden nere till vänster ändras och avspeglar den valda vinkeln. Om alternativet ges värdet slumpad används en slumpmässig vinkel av byggnaden.

simutrans-124.3/simutrans/text/sv/citywindow.txt000066400000000000000000000114121474050137200221540ustar00rootroot00000000000000Hjälp om Stadsinformation

Stadsinformation

Stadsinformation visar statistik om vald tätort och kan användas för att ändra dess namn. En tätort kan vara en stad, småstad eller by; nedan används beteckningen stad för alla typer av tätorter.

Varje stad har ett rådhus runt vilket det växer. Tillväxten befrämjas av att passagerare och post transporteras. Tillväxten visar sig genom att gator byggs eller tas över av samhällsservice (visas genom att vägarna kantas av trottoarer på huvudkartan) och genom att nya stadsbyggnader och industrier dyker upp, samt genom att stadens gränser flyttas utåt.

Genom att klicka på ett rådhus på huvudkartan med granskningsverktyget eller på en stad i stadslistan öppnas Stadsinformation. Här kan du se och ändra stadens namn, basuppgifter om staden, två mini-kartor samt statistiska kurvor över stadens utveckling över tid.

Namn: det namn som staden, småstaden eller byn bär visas överst i Stadsinformation i en textruta.
Detta namn används bl a när namn för hållplatser inom stadsgränserna skall skapas. För att ändra namnet, klicka helt enkelt i textrutan och skriv in ett nytt.
{Tips: Använd [!] för att växla om stadens namn visas ovanför rådhuset på huvudkartan. Läs readme_citylist.txt (finns i ...simutrans/text/) för mer information om hur stadsnamn skapas}.

Under namnrutan ges lite grundläggande information om staden:
Storlek: aktuellt invånarantal. Den senaste utvecklingen visas inom parenteser..
byggnader: antal stadsbyggnader (bostadshus/affärsbyggnader/industribyggnader) inom stadens gränser.
Kartkoordinater: anger hur vitt stadens gränser sträcker sig (dessa kommer att ändras efterhand som staden växer). Det första värdeparet anger övre vänstra hörnet och det andra nedre högra hörnet. När städer växer kan deras stadområden komma att överlappa.

Nuvarande antal arbetslösa och hemlösa invånare i staden. Dessa tal ökar när staden utökar sina gränser och minskar när stadsbyggnader byggs. Föröhållandet mellan dessa värden avgör vilken typ av stadsbyggnad som byggs/renoveras när staden bygger till.

Kryssrutan Tillåt stadstillväxt tillåter dig att aktivera eller avaktivera om staden får växa eller ej.

Minikartorna av spelvärlden i Stadsinformation visar som färgade punkter vart passagerare och post som genererats inom stadens gränser har för destination.
Den högra minikartan visar värden för innevarande spelkalendermånad, och den till vänster för föregående spelkalendermånad. Färgen på punkterna anger om destinationen kan nås eller ej:
- gul punkt: det finns en rutt och en hållplats som inte är överfull där resan kan ta sin början (motsvarande glatt ansikte i hållplatsinformationsfönstret).
- orange punkt: det finns inte någon rutt till resmålet.
- röd punkt: det finns en rutt till resmålet, men den hållplats där resan skulle påbörjas är överfull (motsvarande ledset ansikte i hållplatsinformationsfönstret.

Under minikartorna finns ett kurvdiagram som visar statistik för staden.
På y-axeln visas kvantitet och på x-axeln tid. Klicka på tabbarna ovanför fönstret för att ändra tidsskalan på x-axeln:
År: visar årliga värden för de senaste 12 spelkalenderåren.
Månader: visar månatliga värden för de senaste 12 spelkalendermånaderna

Genom att klicka på knapparna under kurvfönstret aktiverar eller avaktiverar du kurvan i fråga. En aktiverad knapp visas nedsänkt.
Kurvorna visas i samma färg som färgen på motsvarande knapp:
Medborgare: Antal människor som bor i staden
Tillväxt: Befolkningsförändringar.
Antal hus: Hur många stadsbyggnader det finns i staden.
Stadsbilar: Hur många stadsbilar som genererats.
Antal resor: Hur många passagerare som givit sig i väg på sin resa (visas som glatt ansikte i hållplatsinformationsfönstret)
Passagerare:Det sammanlagda antalet passagerare som genererats i staden.
Skickad post: Hur mycket post som har påbörjat sin färd mot sin destination
Mail: Den sammanlagda mängden post som genererats i staden.
Varor i lager:Antal gånger som kontroll fann varor i lager hos stadens fabriker
Varor:Antal gånger som lagerstatusen hos stadsfabrikerna kontrollerats.

{Tips: Inställningar som rör städer kan ändras i simuconf.tab och cityrules.tab}.

simutrans-124.3/simutrans/text/sv/depot.txt000066400000000000000000000200241474050137200210660ustar00rootroot00000000000000Fordonshallsverktyg

Fordonshallsverktyg

Fordonshallar - garage, vagnhallar, båthus och hangarer - används för att köpa och administrera fordon och fartyg. Olika transportmedel har sina egna typer av fordonshallar. Fordonshallar visar enbart elektrifierade fordonstyper om de finns på elektrifierade spår.
Om du spelar med en tidslinje så kan fler verktyg bli tillgängliga efterhand som tiden passerar i Simutrans.

Verktyg för att bygga de olika typerna av fordonshallar finns på verktygsraden för respektive fordonsslag: lokstall/vagnhall; monorailvagnhall; spårvagnshall; garage; båthus och hangar.

Klicka på en fordonshall på kartan med granskningsverktyget för att öppna fordonshallsverktygen som ger dig information om och låter dig köpa och administrera konvojer (ett eller en grupp av fordon/fartyg i trafik).
Titelraden av fordonshallsverktygen anger vilken typ av transportmedel som fordonshallen betjänar.

Fordonshallsverktygen kan ändras storlek på (klicka på nerpilen på titelraden för att återgå till ursprunglig storlek).
Klicka på vänster/högerpilar på titelraden för att stega igenom fordonshallar för samma transportslag (kartan centreras runt fordonshallen).

Högst upp i fordonshallsverktygen anges antalet konvojer i fordonshallen, konvojnamn och trafikeringslinje visas.

Konvojnamn: Klicka på vänster-/högerpilsknappar bredvid konvojnamnet för att stega igenom de konvojer som finns i fordonshallen.
Att byta konvojnamn: klicka på rutan för konvojnamnet och skriv in ett nytt namn (som förval är detta märket på första komponent som köptes eller tilldelades en ny konvoj).

Trafikeringslinjenamn: Klicka på vänster-/högerpilsknappar vid namn för att välja trafikeringslinjer för fordonshallens transporttyp, eller klicka på namnrutan för trafikeringslinjen för att öppna upp en rullgardinsmeny över trafikeringslinjer (klicka på en trafikeringslinje i rullgardinslistan för att välja denna).
Att ändra namn på trafikeringslinje: klicka på namnrutan för trafikeringslinjen och skriv in ett nytt namn (som förval tilldelas trafikeringslinjen ett nummer när den skapas).

konvoj-bild Under namnrutorna för konvoj- och trafikeringslinjenamn visas en bild av den valda konvojen.
Låt musen vila över bilden av en komponent av konvojen för att få mer detaljer om just denna komponent (visas i botten av fordonshallsverktygen).
Klicka på komponent av konvojbilden för att ta bort denna från den valda konvojen och förvara den i fordonshallen.

Nedanför bilden visas antalet komponenter i vald konvoj, längden på konvojen i rutor (alla komponenter måste få plats på en lämplig hållplats för att gods och passagerare skall kunna hämtas och lämnas där) samt vilken trafikeringslinje konvojen är knuten till.

Bland alternativknappar (klicka för att använda) för Fordonshallsverktyg finns:

Kör: skickar iväg vald konvoj om en rutt kan hittas.

Tidtabell: öppnar verktyg för att ändra rutt och hur länge en konvoj väntar (till hur fylld) vid en station.

Upplös: parkerar de fordonsenheter som den valda konvojen består av.

Sälj: säljer nuvarande konvoj, försäljningsvärdet sätts in på ditt konto.

Ny linje: öppnar verktyg för att sammanställa en tidtabell (en rutt och en minsta mängd varor/passagerare som konvojen väntar på vid varje stopp), som kan användas för flera konvojer.

Tilldela linje: knyter en linje som visas i linjenamnsrutan överst i fordonshallsverktygen till en vald konvoj.

Ändra linje: öppnar verktyg för att ändra tidtabellen (den rutt och en minsta mängd varor/passagerare som konvojen väntar på vid varje stopp) för vald linje.

Kopiera konvoj: köper och sätter samman en konvoj med samma sammansättning, tidtabell och linje som vald konvoj.

Nedanför alternativknapparna visas bilder av alla fordon och fordonskomponenter som det går att köpa.
bilder av fordons-enheter: fordonsenheter är indelade i typer som kan ses genom att klicka på indextabbarna. Indextabbarna delar in fordonsenheter i följande grupper: fordons-enheter för passagerare och post, andra motordrivna fordonsenheter, samt andra släp/vagnar.
En vit siffra över bilden av fordonsenheten visar hur många sådana enheter som finns i lager efter att en konvoj har upplösts. Lagrade fordonsenheter kan säljas eller användas i en ny konvoj.

Låt muspekaren vila över en bild av en fordonsenhet för att se mer information om denna:
Namn: och i hakparentes framdrivningstyp för motorfordon.
Kostnad: inköpspris och i hakparenteser driftskostnad per kilometer
Kraft: motorstyrka och maxhastighet för motoriserade fordon.
Kapacitet: mängd och typ av varor som kan fraktas i fordonsenheten.
Vikt: i ton.
Maxhastighet: för icke-motoriserade fordonsenheter.
Introduktion: datum när fordonsenheten blir tillgänglig om tidslinje är aktiverad.
Tillbakadragning: datum när en fordonsenhet blir föråldrad.
Skapad av: den person som skapade fordonsenheten för Simutrans.
Utväxling: ? power ratio.
Andrahandsvärde: den summa pengar som erhålls om en fordonsenhet säljs igen.

Klicka på en bild av en fordonsenhet under indextabbarna för att antingen köpa eller sälja en sådan beroende på de inställningar som gjorts med fordonsalternativknappen längst ner till vänster i fordonshallsverktygen Denna knapp har tre lägen:
Lägg till: köper en fordonsenhet och lägger till densamma i den konvoj som är vald alternativt skapar en ny konvoj om ingen är vald.
Ställ främst: köper en fordonsenhet och placerar den först i den konvoj som är vald alternativt skapar en ny konvoj om ingen är vald.
Försäljningsläge: säljer lagrade fordonsenheter.

färgstaplar under bilderna av fordonsenheter visar vilka och i vilken ordning fordonsenheter kan sammanfogas för att bilda en funktionell konvoj (färgstaplarna kan ändras beroende på inställning av fordonsalternativknappen).
Färgerna anger:
- grön: fordonsenheten kan användas.
- röd: fordonsenheten kan inte användas
- gul en annan fordonsenhet måste placeras före eller efter för att konvojen skall kunna fungera.
- blå: fordonsenheten kan användas men är föråldrad.
{Tips: en konvoj är funktionell om den visar gröna staplar för alla fordonsenheter; om det finns kvar en gul stapel, så saknas en nödvändig fordonsenhet.}

Visa föråldrade: om du spelar med en tidslinje, visas även fordonsenheter som dragits tillbaka om den fyrkantiga knappen är nedtryckt.

simutrans-124.3/simutrans/text/sv/players.txt000066400000000000000000000031141474050137200214330ustar00rootroot00000000000000Hjälp om spelarlista

Spelarlista

I spelarlistan visas alla spelare.
Allra överst återfinns den Simutrans-spelare som styrs av en människa.
Därefter finns samhällsservice. Samhällsservice sköter utbyggnad av städer och industrier samt sevärdheter och minnesmärken.

Du kan ta kontroll över en annan spelare genom att klicka på pilen framför dess namn; detta förutsatt att spelarbyte inte avaktiverats.

Härefter visas alla ett antal fält för övriga aktiva spelare; som förval finns det inte någon mer aktiverad spelare, och fälten visas därför gråa med texten tom. När du valt spelartyp (människa, AI för passagerartrafik, AI för godstrafik) visas en kryssruta först på raden med hjälp av vilken du kan aktivera eller avaktivera spelaren i fråga.

Aktiverade datorspelare (AI-spelare) bygger ett transportnät och transporterar antingen varor eller passagerare. Om du avaktiverar en datorspelare, så slutar denna spelares företag att expandera, men existerande nätverk och förbindelser fortsätter att fungera.

AI-spelare: Namnet på existerande spelares företag visas i listan med företagets färg som bakgrund. Genom att klicka på detta namn öppnas finansfönstret för företaget i fråga upp.

Längst ner i fönstret under listan över spelare finns en alternativruta där du kan aktivera eller avaktivera ingen bankrutt. Om du aktiverar detta alternativ kan inte någon spelare (inklusive du själv) gå i bankrutt även om företagets tillgångar är negativa.

simutrans-124.3/simutrans/text/sv/signal_spacing.txt000066400000000000000000000021651474050137200227420ustar00rootroot00000000000000Hjälp om signalintervall

Allmänt bruk:


-- Ctrl-klicka på signalikonen för att ta fram denna dialog.
-- Klicka-och-dra längs spår ger en förhandsvisning av de signaler som kommer att byggas; släpp knappen för att genomföra byggnationen. Signalerna kommer att byggas så att tåg kan färdas längs spåret endast i den riktning som du drog musen.
-- I nätverksspel: Ctrl-klicka först på spåret och släpp musknappen. När du håller ner musknappen och flyttar musen får du en förhandsvisning. Återigen släpper du knappen för att genomföra byggnationen.

Parametrar i denna dialog:

-- Avstånd: hur många rutor som skall skilja intilliggande signaler åt (diagonal räknas som 1/2 ruta). Detta värde visas på knappen om signalverktyget är valt.
-- Ta bort mellanliggande signaler: om aktiverad så kommer redan existerande signaler tas bort från sträckan.
-- Ersätt andra signaler: om aktiverad, så kommer existerande signaler på de rutor där nya signaler skall byggas att tas bort.

Dessa parametrar ställs in för varje signaltyp separat.

simutrans-124.3/simutrans/text/sv/simutrans.txt000066400000000000000000000054401474050137200220050ustar00rootroot00000000000000Simutrans

Välkommen till Simutrans

Du är en ung entreprenör med drömmar om att bygga ett transportnätverk. Du börjar med ett litet men tillräckligt startkapital. Välj en av de tusentals Simutrans-kartor som finns tillgängliga, eller skapa en ny baserad på en höjdkarta. Samma karta kan användas för flera olika spel och ändras då baserat på de inställningar du gjort.

Se dig omkring på kartan och gör en bedömning av situationen. Det ligger i dina händer hur denna lilla värld kommer att utvecklas. Du kan t ex välja att frakta varor (råvaror, slutprodukter) för industrierna i en industrikedja. Bygg de transportleder som behövs; välj mellan räls, landsväg, kanaler eller kanske flygrutter. Självklart kan varor lastas om eller passagerare byta fordon på mellanstationer.

Fördelen med att börja med godstransport är att du på detta sätt kan få god avkastning för liten investering. Nackdelen är att godstransport inte bidrar till din världs tillväxt.

En annan strategi är att från början stimulera stadstillväxten och att bygga eller åtminstone planera för den större kapacitet som då så småningom kommer att krävas. Om invånarna i städerna kan komma till sina önskade resmål, kan de få utlopp för sin reslust. Varje potentiell resenär bryr sig dock enbart om det finns en resväg dit denne vill, så försök att ansluta så många destinationer som möjligt till ditt transportnätverk; arbetsplatser och turistattraktioner som ruiner och gamla slott attraherar stora mängder av resenärer. Om du även transporterar den post som stadsbefolkningen vill skicka så stimuleras tillväxten av staden än mer.

God service lönar sig. Ju fler resenärer som är nöjda med din service och ju mer post du transporterar, desto mer växer staden i fråga. Nya bostäder samt affärs- och industribyggnader byggs i staden. Kompletta industrikedjor dyker upp utanför städerna. Detta öppnar nya möjligheter för expansiva transportföretag och erfarna logistiker.

Genom att noggrannt planera dina transportleder, kan du utnyttja dina järnvägs- och landsvägssträckor maximalt. Trafikera inte en linje med fler fordon än vad trafikunderlaget kräver; men snåla inte heller i onödan. En konvoj som ständigt kör halvfull går inte med vinst.

Det finns inte några tidsramar för hur länge du kan spela. Spela tills du nått dina mål. Du kan konkurrera mot upp till 6 AI-spelare. Stjäl dina konkurrenters passagerare eller frakt från rakt under deras näsa! Kanske spelar du helst helt utan konkurrenter? Det är ditt val. Expandera inte för fort i inledningsfasen; ditt transportföretag går i konkurs om du inte har positivt netto.

Simutrans-teamet och communityn runt Simutrans önskar dig mycket nöje och gnuggande av de små grå när du bygger upp din värld.

simutrans-124.3/simutrans/text/sv/underground.txt000066400000000000000000000040321474050137200223100ustar00rootroot00000000000000Att bygga under jord

Det finns två sätt att se vad som finns under jorden i Simutrans.
underjordsläge
Med U väljler du underjordsläge. Då döljs alla föremål som finns ovan mark.
kartusnitt
Med Ctrl + U väljer du att visa en höjdnivå av vad som finns under jord i Simutrans. Då döljs alla föremål som finns på en högre nivå, oavsett om dessa är under eller ovan jord.

Du byter utsnittsnivå med + (högre) och - (djupare) eller med hjälp av Visningsdialogen.

Muspekaren
underjordsläge
I underjordsläge visas rutmönstret från marknivån. För obebyggda rutor placerar sig pekaren enligt detta rutmönster, men för bebyggda rutor på rutan.
Det är ganska svårt att placera pekaren rätt m h a rutmönstret, och därför bör kartutsnitt användas när man bygger saker under jord.

kartutsnitt
Vid kartutsnitt läggs rutmönstret enbart över aktuell nivå och muspekaren kan lätt placeras på rätt ställe i detta rutmönster. Dvs muspekaren kan enbart flyttas inom aktuell nivå vilket i hög grad underlättar byggnadsarbete.

Vägbygge

Generellt


I allmänhet byggs vägsträckor under jord m h a tunnelverktygen. För att kunna bygga under jord, måste en tunnel eller tunnelingång (Ctrl + klick med tunnelverktyget på en sluttning) byggas.

Nivåbyte
För att ändra tunnelns nivå under jord används verktyget Höj/Sänk marknivå på menyn Markhöjdsverktyg. Klicka helt enkelt på vägsträckans ände med önskat verktyg.

Speciellt om spårvägar


Spårvägsräls läggs under jord med de vanliga byggverktygen.

Stationer och tillbyggnader
Endast egna stationer kan byggas ovanpå varandra.

Tillbyggnader kan inte byggas under jord.

Signaler
Kan användas som ovan jord.

simutrans-124.3/simutrans/text/th.tab000066400000000000000000000131601474050137200176700ustar00rootroot00000000000000§Thai PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: th Thai # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 2.06 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_sort_income รายรับ cl_btn_sort_name รายà¸à¸²à¸£ cl_btn_sort_type ลัà¸à¸©à¸“ะ #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic ภูมิอาà¸à¸²à¸¨à¸«à¸™à¸²à¸§ #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ allowed climates:\n ภูมิอาà¸à¸²à¸¨à¸—ี่อนุà¸à¸²à¸•:\n Alters a schedule. ปรับปรุงตารางเวลา Angenommene Waren สินค้าที่จำเป็นสำหรับอุตสาหà¸à¸£à¸£à¸¡à¹ƒà¸™à¸šà¸£à¸´à¹€à¸§à¸“ใà¸à¸¥à¹‰à¹€à¸„ียง anhaengen ส่วนต่อท้าย Anhaenger_tab รถพ่วง Anheben ยà¸à¸£à¸°à¸”ับพื้นดิน Appends stops at the end of the schedule เพิ่มจุดรับส่งในส่วนท้ายของตาราง Apply Line ใช้งานสายนี้ April เมษายน Arbeiter aus: à¹à¸£à¸‡à¸‡à¸²à¸™à¸­à¸²à¸¨à¸±à¸¢à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™: Arrived ถึงจุดหมายà¹à¸¥à¹‰à¸§ Assets สินทรัพย์ Aufspanntransformator สถานีจ่ายไฟฟ้าย่อย August สิงหาคม Autohalt muss auf\nStrasse liegen!\n จุดรับส่งผู้โดยสารนี้\nต้องสร้างบนถนนเท่านั้น Available หาได้ Bahndepot โรงซ่อมรถไฟ Bankrott:\n\nDu bist bankrott.\n ล้มละลาย:\n\nคุณล้มละลายà¹à¸¥à¹‰à¸§!\n\n battery à¹à¸šà¸•เตอร์รี่ Baum ต้นไม้\n baum builder ปลูà¸à¸•้นไม้ Baustelle เขตà¸à¹ˆà¸­à¸ªà¸£à¹‰à¸²à¸‡ Bauzeit ระยะเวลาà¸à¹ˆà¸­à¸ªà¸£à¹‰à¸²à¸‡ Beenden ออภBeginner mode โหมดสำหรับผู้เริ่มเล่น Besonderes Gebaeude สถานที่ท่องเที่ยว BF สถานี bio ชีวภาพ Blockstrecke ist\nbelegt\n \nทางวิ่งนี้ถูà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™\nจาà¸à¸‚บวนรถคันอื่น!\n Boden พื้นที่ Bonusspeed: %i km/h ใช้ความเร็วสูงสุด: %i km/h bridge is too high for its type! สะพานสูงเà¸à¸´à¸™à¹„ป Bridge is too long for this type!\n ไม่สามารถสร้างสะพานได้\nระยะทางไà¸à¸¥à¹€à¸à¸´à¸™à¹„ป Bruecke สะพาน Bruecke muss an\neinfachem\nHang beginnen!\n สร้างสะพานด้วยà¹à¸™à¸§à¸•รงเท่านั้น! Brueckenboden สะพาน Build air depot สร้างโรงซ่อมบำรุงเครื่องบิน build choosesignals สร้างสัà¸à¸à¸²à¸“ไฟเลือà¸à¸Šà¸²à¸™à¸Šà¸²à¸¥à¸² Build city market สร้างร้านค้าใหม่ในพื้นที่ใà¸à¸¥à¹‰à¹€à¸„ียง Build drain สถานีà¹à¸›à¸¥à¸‡à¸£à¸°à¸šà¸šà¹„ฟฟ้า build HQ สร้างสำนัà¸à¸‡à¸²à¸™à¹ƒà¸«à¸à¹ˆ HQ Build land consumer สร้างโรงไฟฟ้า Build maglev depot สร้างโรงซ่อมบำรุงรถไฟà¹à¸¡à¸à¹€à¸¥à¸Ÿ Build monorail depot สร้างโรงซ่อมบำรุงรถไฟโมโนเรล Build narrowgauge depot สร้างโรงซ่อมบำรุงรถรางขนาดเล็ภBuild powerline ไฟฟ้าความเร็วสูง Build presignals สร้างสัà¸à¸à¸²à¸“ไฟคู่ Build road depot สร้างอู่รถยนต์ Build ship depot สร้างอู่เรือ Build signals สร้างสัà¸à¸à¸²à¸“ Build train depot สร้างอู่รถไฟ Build tram depot สร้างอู่รถราง Build truck depot สร้างอู่ซ่อมรถ Building costs estimates ค่าà¸à¹ˆà¸­à¸ªà¸£à¹‰à¸²à¸‡à¹‚ดยประมาณ Buildings จำนวนสิ่งà¸à¹ˆà¸­à¸ªà¸£à¹‰à¸²à¸‡ Neue Karte à¸à¸²à¸£à¹Œà¸”ใหม่ Sprachen ภาษา Stadtinformation ข้อมูลของเมือง Start เริ่ม simutrans-124.3/simutrans/text/tr.tab000066400000000000000000000025061474050137200177040ustar00rootroot00000000000000§Turkish PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: tr Turkish # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 3.06 2024 # # # ################################################################################ #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ Neue Karte Yeni kart simutrans-124.3/simutrans/text/tr/000077500000000000000000000000001474050137200172115ustar00rootroot00000000000000simutrans-124.3/simutrans/text/tr/airtools.txt000066400000000000000000000114741474050137200216150ustar00rootroot00000000000000Hava Araçları

Havaalanı Araçlar hava ulaşım ağı oluşturmak için araçlar içerir. Araçlar inşa veya kaldırın: taxiways ve uçak için piste, Airstops (seçmek-up & drop-off, kargo ve yolcu) kullanılan uçak depoları (satın alma ve hava ulaşım araçları yönetmek) ve çeşitli hava binalar. Zaman Simutrans daha fazla araç geçerse Eğer zaman çizelgesi ile birlikte oynarken seçenekleri görünebilir. Tıklayın uçak-Oyunun başında icon-araç çubuğunu açmak için görüntüleyebilirsiniz.

Araç üzerinde Hover fare imleci seçeneği (açılış veya araç çubuğu üzerine tıklayarak) sonra parantez içinde ve maksimum hız sınırı adı ve nerede uygun: inşaat maliyeti, bakım maliyeti görmek için.
İpuçları: basit bir havaalanı inşa etmek için bir yolu:
i) inşa ve (ler) ve Pist (ler) hızlanma pisti bağlamak;
ii) yer airstop (lar) ucunda (lar) hızlanma pisti ve (lar);
iii) havaalanı binaları olarak gerekli ekleyin.

Araçlar, sağa soldan içerebilir:
Hızlanma pisti: araç bir Airstop bir Pist gitmek için uçak zemin hareket alanları oluşturur. Taxiways oyun seviyesi zemin görünümü oluşur.
ÖNEMLİ: Taxiways piste sonuna kadar olmayabilir uçak kapatma ve arazi bağlıdır.

Bir hızlanma pisti kurmak için: tıklayın aletine hızlanma pisti için (değişiklikler imleç) seçmek için tıklayın başlatmak için arazi üzerinde noktaya (eş-harita ekranın alt sağda ordinates), ve nihayet tıklayın oyun bir buldozer-görünümü ve gösterir arazi veya bitirmek için pist noktası.
İpuçları: Kullanım Destroy / Kaldır hızlanma pisti tek tek parça kaldırın. Geri Al [z] inşaatların maliyetleri iade etmez.

Pist: araçlar bir uçak pisti, uçak yapmak için kullanılan kapalı ve toprak yapacağız. Piste oyun seviyesi zemin görünümü ve dahili birbiriyle çapraz Mayıs

Bir Pist oluÅŸturmak için: tıklayın aletine yoludur (deÄŸiÅŸiklikler imleç seçmek için), sonra baÅŸlamak için arazi üzerinde nokta (), ve bitiÅŸ için arazi üzerinde son tıklayın noktası oyun görünümünde bir buldozer gösterir. (İpuçları: olmayabilir baÅŸka uçak-off veya arazi piste tutarsız ve biter bırakın. Kullanım Destroy / Kaldır Pist tek tek parça kaldırın. Geri Al [z] inÅŸaatların maliyetleri iade etmez.) Airstrips Kaldır: araç, iki nokta arasında oyunda hızlanma pisti veya Pist, hiç uçak mevcut, bir parça kaldırır-görüntüleyebilirsiniz. Araç kullanımı bir inÅŸaat maliyetini düşürebilir. Bir uçak pisti kaldırmak için: tıklayın aletine (deÄŸiÅŸiklikler imleç kırmızı-geçmeye); tıklatın ÅŸerit üzerinde silinmek üzere olduÄŸunu () silme noktaya oyun görünümünde bir kırmızı haç ile gösterilir seçer; ve nihayet tıklayın baÅŸka bir noktada ÅŸerit, ilk silme-noktasına kısmını kaldırın. (İpuçları: olmayabilir piste baÅŸka uçaklar ayrı sonu bırakın kapatma veya arazi. Kullanım Destroy / Kaldır airstrips bireysel adet kaldırmak için.) Hava Depo: araçlar satın alma ve uçak yönetmek için hangarlar inÅŸa. Hangarlar ve bakım maliyetini bir parça hızlanma pisti sonuna üzerine kurulmuÅŸ bulunmaktadır. Bir Hangar oluÅŸturmak için: tıklayın aletine (deÄŸiÅŸiklikler imleç bir depo için), ardından bir hızlanma pisti bir ucunda. (İpuçları: Destroy ile depoları Kaldır / Kaldır.) Airstops & binmeden köprü: araçlar oyun Durdurur inÅŸa görüntülemek, uçak için seçmek için yukarı ve açılan yolcu veya kargo kapatın. Bir Airstop bir mevcut Dur yanında yeni bir Dur oluÅŸturur yapılmış deÄŸil. Airstops bir parça hızlanma pisti sonuna üzerine kurulmuÅŸ ise; ve eÅŸya, yolcu ve posta için bir bakım maliyeti ve havza. EÄŸer bir serbest Airstop kullanılabilir bir uçak sadece havaalanında girerler. Bir Airstop oluÅŸturmak için: tıklayın aletine seçin ve ardından bir hızlanma pisti bir ucunda. (İpuçları: Destroy ile Airstops Kaldır / çıkarın. Medya [v] göstermek için mal ve yolcu oyun için havza gizlemek görüntülemek.) Havaalanı binaları: araçlar hangi mal ve yolcu için bakım maliyetleri ve kapasitesi ve havza artırabilir Durdurur için uzantıları inÅŸa. Bazı aracın köşesinde seçenekleri bir simge olarak (İstasyon Listesi & Dur Bilgiler) kullanılan bu öğeler uzantısı gösterir ele Dur saÄŸlar. Bir uzantısı oluÅŸturmak için: tıklayın aletine uzantısı için (deÄŸiÅŸiklikler imleç uzantısı seçmek için), ardından gerekli konum, oyun mevcut bir Dur-görmek için gelecek. Yeni uzantısı artık Dur bir parçası olarak kabul edilir. (Ipuçları: the Destroy ile / Kaldır uzantıları çıkarın. Medya [v] göstermek için mal ve yolcu oyun için havza gizlemek görüntülemek.) simutrans-124.3/simutrans/text/translate_users.txt000066400000000000000000000046171474050137200225530ustar00rootroot00000000000000################################################################################ # User list: all authors and contributors to Simutrans translation # # https://translator.simutrans.com # # DO NOT EDIT THIS FILE. It will be created automatically # ################################################################################ 209CATrus Ampersand An_dz note: Verified where all texts are shown BJ99 BarthVader - Bartlomiej Weclewski Citarofahrer Daikon - Daikon Ocelot Duke Dwachs Eps-Omo FLN - Francisco Flemmbrav Gauthier - Gauthier NOTTRET Green HyperSim IgorEliezer JHLee - J. H. Lee Jaroslaw - Jaroslaw JulioCesarBR - Julio Cesar Miranda Rodrigues note: Member who helps translate in Portuguese language! Kozinsky - Evgen Leartin LeitnerI MRBK note: KHOMKRIT BUTSARAKHAM (พี) Makie - Martin note: Maintainer PAK128.german & Translator Matthew NNW - Daniel Pestr - Mikhail Pestrechikhin Phystam - T. Tomai note: Simutrans Extended player pak256-Ex developer Pumuckl999 Randonn - Maico Randon Ranran Roboron - Roberto Michán Sánchez Tajia TcatalunyaT Tjoeker Umoxfo VaclavMacurek - Václav Macůrek Ves - Victor Sørensen Vladki - Vladislav Kurz Woratiklis - Woratiklis Yona-TYT - Yonatn Mejia albert.yuste - Albert Ruiz note: Albert Ruiz - Zeno alekcxjo - Alexandre Raymond cousjath gebeine note: maintainer PAK128.german gwalch iGi jamespetts - James E. Petts note: Maintainer for Simutrans-Experimental. Also works on Pak128.Britain. jk271 - Honza Kobel locidux lr19 margaret milko paintree pasichna pierohd pika polix - Pawel Rudzinski prissi sojo - Sven Osada note: maintainer pak96.comic splithor1zon stepan - Stepan stev0312 - steve0312 uci vonjo vsys - Vladimír Slávik vzrenggamani - Rengga Prakoso Nugroho note: Riyantama Wira - Vesa khrisna - Satria naail - Mikhael Theofilus - Thomas Septian whoami - Michael Olbricht wlindley - William Lindley woodman - Maxim Filippow yurrriiiy z8w38 simutrans-124.3/simutrans/text/uk.tab000066400000000000000000001774301474050137200177070ustar00rootroot00000000000000§Ukrainian PROP_FONT_FILE cyr.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: uk Ukrainian # # Encoding: UTF-8 # # Font: cyr.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable Вимкнено cl_btn_filter_enable Увімкнено cl_btn_filter_settings ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ cl_btn_sort_asc За зроÑтаннÑм cl_btn_sort_desc За ÑпаданнÑм cl_btn_sort_id Внутрішній ІД cl_btn_sort_income Прибуток cl_btn_sort_name Ðазва cl_btn_sort_type Тип clf_btn_alle уÑÑ– clf_btn_invers оберн. clf_btn_keine нічого gl_btn_sort_bonus за бонуÑом gl_btn_sort_name за назвою gl_btn_sort_revenue за прибутком gl_btn_unsort без ÑÐ¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ hl_btn_filter_disable вимкн. hl_btn_filter_enable увімкн. hl_btn_filter_settings ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ hl_btn_sort_asc за зроÑтаннÑм hl_btn_sort_desc за ÑпаданнÑм hl_btn_sort_name за назвою hl_btn_sort_type за типом hl_btn_sort_waiting ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ hlf_btn_alle уÑе hlf_btn_invers обернути hlf_btn_keine нічого Networks Лінії Queueing Черга Road toll Дорожнє мито Scenario Дані про Ñценарій Transfers Транзит #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic Ðрктичний клімат desert ПуÑтельний клімат mediterran Ñубтропічний клімат rocky гірÑький клімат temperate помірний клімат tropic тропічний клімат tundra тундра #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð´Ñƒ Ñценарію. Can't buy obsolete vehicles! Ðе можна куплÑти заÑтарілі заÑоби! Cannot alter water Ð¦Ñ Ð²Ð¾Ð´Ð¾Ð¹Ð¼Ð° не може бути згодом оÑушена або заповнена. Cannot built depot here! Тут не можна побудувати депо. Cannot built this station/building\nin underground mode here. Тут не можна побудувати цю Ñтанцію/будівлю \nу підземному режимі. Cannot create generic line!\nSelect line type by\nusing filter tabs. Ðе можна Ñтворити загальну лінію!\nВиберіть тип лінії,\nвикориÑтовуючи фільтр. Cannot create socket Ðеможливо Ñтворити з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Convoi handles exhausted! ДоÑÑгнуто макÑимальноо чиÑла заÑобів! Convoy already deleted! Колону вже вилучено! Das Feld gehoert\neinem anderen Spieler\n Цією ділÑнкою\nземлі володіє\nінший гравець!\n Der Besitzer erlaubt das Entfernen nicht Права влаÑника\n заборонÑють видаленнÑ!\n Diese Zusammenstellung kann nicht fahren!\n Ð¦Ñ ÐºÐ¾Ð¼Ð±Ñ–Ð½Ð°Ñ†Ñ–Ñ\n не може рухатиÑÑ!\n Flugzeughalt muss auf\nRunway liegen!\n ПоÑадковий термінал\n має бути на дорозі!\n Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n Ð¦Ñ Ð±ÑƒÐ´Ñ–Ð²Ð»Ñ Ð°ÐµÑ€Ð¾Ð¿Ð¾Ñ€Ñ‚Ñƒ\nне може бути\nпобудована тут!\n Hier kann kein\nSignal aufge-\nstellt werden!\n Семафор не може\nбути вÑтановлений тут!\n In order to lock the game, you have to protect the public player by password! Ð”Ð»Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ€Ð¸ вам потрібно захиÑтити відкритого Ð³Ñ€Ð°Ð²Ñ†Ñ Ð¿Ð°Ñ€Ð¾Ð»ÐµÐ¼! Lost connection\nto server! Ðемає з'єднаннÑ\n із Ñервером! Lost synchronisation\nwith server. Ðемає Ñинхронізації\nіз Ñервером. Maglevhalt muss auf\nMaglevschiene liegen!\n Зупинка поїзда на магнітній\nподушці має бути\n на відповідній колії! Monorailhalt muss auf\nMonorail liegen!\n Зупинка монорейки \n має перебувати\nна відповідній колії! Monorails are not available yet! Монорейки наразі недоÑтупні. Narrowgaugehalt muss auf\nNarrowgauge liegen!\n Зупинка вузькоколійок\nмає перебувати\nна відповідній колії! No suitable way on the ground! Перон можна побудувати тільки на\n прÑмій ділÑнці траÑи. No through station here! Тут немає транзитної Ñтанції! Not enough clearance. Між двома клітинками Ð´Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ шлÑху Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð²Ð¸Ñоти має Ñтановити принаймні 2 рівні. Not enough money! У Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтатньо грошей! On narrowgauge track only!\n Тільки на вузькоколійній траÑÑ–!\n Only public player can lock games! Тільки відкритий гравець може заблокувати гру! Out of funds Обмаль коштів! Post muss neben\nHaltestelle\nliegen!\n Станційні будівлі \n повинні розміщуватиÑÑ \n на вільній клітці \n поруч з Ñ–Ñнуючою \n Ñтанцією або зупинкою!\n Protocoll error (expecting game) Вада протоколу Schiffhalt muss im\nWasser liegen!\n Зупинка Ñудна\nможет бути тільки\nÐ±Ñ–Ð»Ñ Ð´Ð¾ÐºÑƒ!\n Server busy Сервер зайнÑтий Terraforming not possible\nhere in underground view Ð¤Ð¾Ñ€Ð¼ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ»ÑŒÑ”Ñ„Ñƒ під землею неможливе! This tunnel branches. You can try Control+Click to remove. Цей тунель розгалужуєтьÑÑ. Ви можете натиÑнути Ctrl+клік Ð´Ð»Ñ Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ. Upgrade must have\na higher level ÐœÐ¾Ð´ÐµÑ€Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð° тільки на\n вищому рівні Vehicle %s cannot choose because stop too short! ТранÑпортний заÑіб %s не може вибрати, бо зупинка надто коротка! Zughalt muss auf\nSchiene liegen!\n Залізничні Ñтанції повинні\nбути розміщені лише на\nзалізничних коліÑÑ….\n #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s Довідка

ЗміÑÑ‚

Про Simutrans

%1$s

Загальні дані

%2$s

Початок гри

%4$s

Ігровий процеÑ

%5$s

ЗаÑоби

%3$s

Інші вікна

%6$s Keyboard Help\n

Keyboard Help

\n Прив'Ñзка клавіш\n

Довідка по клавіатурі

\n

\nДовідка по клавіатурі показує функції, прив'Ñзані до різноманітних натиÑкань комбінацій клавіш на клавіатурі.\n

\n

\nДовідка по клавіатурі відкриваєтьÑÑ, коли натиÑнута нерозпізнана клавіша або із Загальної довідки.\n

\n

\nÐатиÑÐºÐ°Ð½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–Ñˆ чутливе до регіÑтру (вживайте [Shift] Ð´Ð»Ñ Ð²ÐµÐ»Ð¸ÐºÐ¸Ñ… букв).\n

\n

\nДо клавіш із призначеними функціÑми відноÑÑтьÑÑ:\n

\n

\n[Стрілки]: прокручують екран гри у напрÑмку Ñтрілки.
\n[Backspace]: закриває уÑÑ– вікна, панелі інÑтрументів та довідкові текÑти на екрані гри.
\n[Delete] або [Escape]: закриває верхнє вікно, панель інÑтрументів або довідковий текÑÑ‚ на екрані гри.
\n[Enter] або [Return]: вживаєтьÑÑ Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð´Ñ–Ð¹.
\n[Page-Up] чи [>]: Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð¼Ð°Ñштабу мапи.
\n[Page-Down] чи [ Ñимвол менше]: Ð·Ð±Ñ–Ð»ÑŒÑˆÐµÐ½Ð½Ñ Ð¼Ð°Ñштабу мапи.\n[F1]: відкриває Довідку Simutrans.

\n

\n[1]: прокручує екран гри на південь.
\n[2]: прокручує екран гри на південний Ñхід.
\n[3]: прокручує екран гри на Ñхід.
\n[4]: прокручує екран гри на південний захід.
\n[6]: прокручує екран гри на північний Ñхід.
\n[7]: прокручує екран гри на захід.
\n[8]: прокручує екран гри на північний захід.
\n[9]: прокручує екран гри на північ.\n

\n

\n[Shift] + мишка: вживаєтьÑÑ Ð½Ð° мапі Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ поÑилань у Ланцюгу промиÑлових поÑтавок.
\n[CTRL] + інÑтрумент: будує повільніше дороги та колії; або будує випрÑмленіші дороги Ñ– колії.
\n

Decrease water height Зменшити рівень води Highlight railroad tracks ПідÑвітити залізничні колії Highlite depots ПідÑвітити депо Highlite electrical transmission lines ПідÑвітити лінії електропередач Highlite factories ПідÑвітити фабрики Highlite forests ПідÑвітити ліÑи Highlite tourist attraction ПідÑвітити пам'Ñтки Increase water height Збільшити рівень води Overlay city limits Показувати межі міÑÑ‚ Overlay passenger destinations when a town window is open Відображати точки Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñажирів, коли відкрито вікно інформації міÑта. Overlay schedules/network Відображати уÑÑŽ транÑпортну мережу або тільки вибраний маршрут. Overlay town names Відображати назви міÑÑ‚ Please click on the map to add\nwaypoints or stops to this\nschedule. ÐатиÑніть на карті, щоб додати\n до цього розкладу транзитні точки або зупинки. Set tile climate %s Задати клімат Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— клітинки Ñк %s Show capacity and if halt is overcrowded Показати міÑткіÑть Ñкладів Ñ– Ñ—Ñ… Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð°Ð¼Ð¸ Show how many convoi reach a station Показати чиÑло Ñ‚/з, Ñкі обÑлуговуютьÑÑ Ð½Ð° Ñтанції Show how many people/much is waiting at halts Показати чиÑло паÑажирів та триваліÑть їхнього Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° Ñтанції Show initial passenger departure Показати початкове Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñажирів Show level of city buildings Показати рівні міÑьких Ñпоруд Show mail service coverage/mail network Показати зону Ð¾Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ Ð¿Ð¾ÑˆÑ‚Ð¾Ð²Ð¾Ñ— Ñлужби та Ñ—Ñ— мережу Show passenger coverage/passenger network Показати зону Ð¾Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ ÑтанціÑми паÑажирів та їхню мережу Show speedlimit of ways Показати Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ñті на дорогах Show the change of waiting at halts Показати зміну Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð· минулого міÑÑÑ†Ñ Ð½Ð° ÑтанціÑÑ… Show the owenership of infrastructure Показати влаÑників інфраÑтруктури Show transported freight/freight network Показати Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¾Ð¿ÐµÑ€ÐµÐ²ÐµÐ·ÐµÐ½Ð½Ñ Ñ‚Ð° їхню мережу Show usage of network Показати завантаженіÑть ліній Shows a listing with all industries on the map. Показати перелік уÑÑ–Ñ… виробництв на мапі Sum of departure/arrivals at halts ЧиÑло відправлень/прибуттів на Ñтанції #____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s тепер\nпропонує поїздки на автобуÑÑ–\nіз %s\n до \n%s\nо (%i,%i).\n %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s тепер\nперевозить робітників із\n%s на\n%s\nо (%i,%i).\n %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s\nзапуÑтив %i вантажівок між\n%s о (%i,%i)\nта %s\nо (%i,%i). %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s\nвідкрив нову залізницю\n між %s\nо (%i,%i) та \n%s\nо (%i,%i). Airline service by\n%s\nnow between\n%s \nand %s.\n Ðвіаційне ÑÐ¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ фірми\n%s\nвже діє між\n%s \nта %s.\n Ferry service by\n%s\nnow between\n%s \nand %s.\n Поромне ÑÐ¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ фірми\n%s\nвже діє між\n%s \nта %s.\n Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n Мандрівники можуть\nвже кориÑтуватиÑÑ Ð°Ð²Ñ‚Ð¾Ð±ÑƒÑним ÑполученнÑм від фірми %s\n між \n%s \nта %s.\n #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS ЗаÑоби зміни мапи LISTTOOLS СпиÑки MAGLEVTOOLS Поїзд на магнітній подушці MONORAILTOOLS Монорейка NARROWGAUGETOOLS Вузькоколійка RAILTOOLS Ð—Ð°Ð»Ñ–Ð·Ð½Ð¸Ñ†Ñ ROADTOOLS ÐвтошлÑхи SHIPTOOLS СудноплавÑтво SLOPETOOLS Рельєф SPECIALTOOLS Додаткові заÑоби TRAMTOOLS Трамвай #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s Ñпорудив новий Ð¾Ñ„Ñ–Ñ Ñƒ (%i,%i). Factory chain extended\nfor %s near\n%s built with\n%i factories. ПромиÑловіÑть зроÑтає:\n%s Ð±Ñ–Ð»Ñ %s збільшує ланцюжок.\n%i нових підприємÑтв заÑновано. Net wealth less than 10%% of starting capital! ЧиÑтих активів менше 10%% від Ñтартового капіталу! New %s now available:\n%s\n ДоÑтупний новий %s:\n%s New factory chain\nfor %s near\n%s built with\n%i factories. ПромиÑлове зроÑтаннÑ: новий ланцюжок\nÐ´Ð»Ñ %s\nÐ±Ñ–Ð»Ñ %s\nÑтворено ще %i фабрик\n. New vehicle now available:\n%s\n З'ÑвивÑÑ Ð½Ð¾Ð²Ð¸Ð¹ транÑпортний заÑіб:\n%s\n Now %u clients connected. Ðаразі вірно %u клієнтів під'єднано. Remove vehicle from map. Use with care! Прибрати Ñ‚/з з карти. ВикориÑтовуйте обережно! Screenshot\ngespeichert.\n Знімок екрану\n збережено.\n Sends the convoi to the last depot it departed from! ÐадіÑлати Ñ‚/з у оÑтаннє відвідане депо. With a big festival\n%s built\na new monument.\n%i citicens rejoiced. Ðа чеÑть Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ монумента\n %s організовані великі ÑвÑткуваннÑ.\n%i городÑн відзначають цю подію. #___________________________________obsolete____________________________________ #___________________________________obsolete____________________________________ Line Filter Фільтр ліній #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (у депо) \nBauzeit bis до \nBauzeit von \nДоÑтупно від \nCan't open heightfield file.\n \nÐеможливо відкрити карту виÑот.\n \ndirection: \nнапрÑмки: \nelektrified \nелектрифіковано \nHeightfield has wrong image type.\n \n Карта виÑот має\n некоректний формат\n зображеннÑ.\n \nis reserved by: \nзайнÑто поїздом \nminimum speed: \nнайменша швидкіÑть: \nnot elektrified \nнеелектрифіковано \nRibi (masked) \nнапрÑмки\n (перекриті): \nRibi (unmasked) \nÐапрÑмки\n(відкриті): \nSet phases: \nУÑтановити зеленого Ñвітла\nПівніч-Південь Схід-Захід: \nsingle way \nОдноÑторонній рух \nway1 reserved by \nШлÑÑ… 1 заразервований \nway2 reserved by \nШлÑÑ… 2 заразервований \nwith sign/signal\n \nпід знаком/Ñигналом\n %d buildings\n %d будівель\n %d convois %d колон %d Einzelfahrzeuge im Depot %d Ñ‚/Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ñ”Ñ‚ÑŒÑÑ Ñ‚ÑƒÑ‚ %i km/h (max. %ikm/h) %i км/год (макÑ. %i км/год) %i years %i months old. Вік:\n%i років та %i міÑÑців. %s at (%i,%i) now public stop. %s вже Ñтав громадÑькою розв'Ñзкою. %s building %s %s %s %s %s %s city %d %s МіÑто %s %d %s %s factory %s %s %s фабрика %s %s %s has entered a depot. %s прибув у депо. %s land %d %s %s облаÑть %d %s %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. МіÑто %s\nчерез збільшеннÑ\nнаÑÐµÐ»ÐµÐ½Ð½Ñ Ð´Ð¾ %i\nÑпорудило тепер нову ратушу. %s\nis crowded. Ð¡Ñ‚Ð°Ð½Ñ†Ñ–Ñ %s переповнена. %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %1$s\n\n\nмакÑимальна швидкіÑть %3$i км/год\n\nпоточна швидкіÑть %2$i км/год.\n\n %s\nwas liquidated. ÐšÐ¾Ð¼Ð¿Ð°Ð½Ñ–Ñ %s Ñтала банкрутом та\nвже ліквідована.\nУÑÑ– операції припинені\n та уÑÑ– активи вже продані. %u Client(s)\n %u клієнт(ів)\n %u Player (%u locked)\n %u гравців (%u заблоковано)\n <очиÑтити розклад> <Ñтворити нову лінію> <індивідуальний розклад> <немає лінії> <немає розкладу> <нова лініÑ> 1 convoi 1 конвой 1 Einzelfahrzeug im Depot 1 тр. заÑіб у депо 1LIGHT_CHOOSE ЯÑкравіÑть: 1WORLD_CHOOSE УÑтановки Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ñ— гри: 2LIGHT_CHOOSE Кольори: 2WORLD_CHOOSE Ðомер мапи: 3LIGHT_CHOOSE ШвидкіÑть прокрутки: 4LIGHT_CHOOSE Ð—Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ñ Ð¿Ñ€Ð¾ÐºÑ€ÑƒÑ‚ÐºÐ° 5LIGHT_CHOOSE Пішоходи на зупинках 5WORLD_CHOOSE ЧиÑло міÑÑ‚: 6LIGHT_CHOOSE Пішоходи у міÑтах 6WORLD_CHOOSE ЩільніÑть руху: 8WORLD_CHOOSE зміна Ð´Ð½Ñ Ñ– ночі A bridge must start on a way! МіÑÑ‚ має починатиÑÑ Ð² кінці наÑвного шлÑху!\n Abfrage ЗаÑіб інÑпекції Abnehmer Споживач: About Про About scenario Ðвтор Ñценарію Abriss Знищити/уÑунути Absenken Понизити терен Abspanntransformator ТранÑформатор Accelerate time ПриÑкорити Ñ‡Ð°Ñ Act. load: %u MW\n Факт. навантаж.: %u МВ\n Active player only Лише активний гравець Add forest Додати Ð»Ñ–Ñ Add random citycar Додати випадкову міÑьку машину add server Додати Ñервер Add Stop Додати зупинку Add stops for backward travel Додати зупинки Ð´Ð»Ñ Ð·Ð²Ð¾Ñ€Ð¾Ñ‚Ð½ÑŒÐ¾Ñ— дороги. air Літаки aircraft_tab Вантажні літаки airplane літак Airport Ðеропорт AIRTOOLS ÐÐ²Ñ–Ð°Ñ†Ñ–Ñ All УÑе all convoi tooltips УÑÑ– поради на Ñ‚/з Allow city growth Дозволити зроÑÑ‚Ð°Ð½Ð½Ñ Ð¼Ñ–Ñта Allow player change Дозволити зміну Ð³Ñ€Ð°Ð²Ñ†Ñ allowed climates:\n Дозволений клімат:\n Alters a schedule. Додати/видалити зупинки до/із розкладу. Angenommene Waren Товари, Ñкі потребують близько розміщеної промиÑловоÑті anhaengen Додати Anhaenger_tab Прицепи Anheben ПіднÑти терен Appends stops at the end of the schedule Додати зупинку у кінці розкладу Apply Line Призначити лінію April Квітень Arbeiter aus: Працівники живуть у: Arrivals from\n ÐŸÑ€Ð¸Ð±ÑƒÑ‚Ñ‚Ñ Ð²Ñ–Ð´\n Arrived Прибув вантаж Assets Ðктиви Aufloesen Розібрати Aufspanntransformator ТранÑформатор August Серпень Autohalt muss auf\nStrasse liegen!\n Зупинки автобуÑа чи автомобілÑ\nповинні бути\nрозміщені на дорозі. Available ДоÑтупно Bahndepot Залізничне депо Bankrott:\n\nDu bist bankrott.\n БанкрутÑтво:\n\nВи - банкрут.\n battery Ð‘Ð°Ñ‚Ð°Ñ€ÐµÑ Baum Дерево baum builder ПоÑадити дерева Baustelle МіÑце будівництва Bauzeit Ñ‡Ð°Ñ Ð±ÑƒÐ´Ñ–Ð²Ð½Ð¸Ñ†Ñ‚Ð²Ð° Beenden Вийти Beginner mode Режим Ð½Ð°Ð²Ñ‡Ð°Ð½Ð½Ñ Besonderes Gebaeude Пам'Ñтка BF ÑÑ‚Ð°Ð½Ñ†Ñ–Ñ bio гужовий Blockstrecke ist\nbelegt\n \nЗалізн. блок вже зайнÑто\nіншим поїздом!\n Boden Ð—ÐµÐ¼Ð»Ñ Bonusspeed: %i km/h Ðайб. можлива швидкіÑть: %i км/год Boost (%%) ПриÑÐºÐ¾Ñ€ÐµÐ½Ð½Ñ (%%) bridge is too high for its type! МіÑÑ‚ завиÑокий Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу! Bridge is too long for this type!\n Занадто довгий проліт\nÐ´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу моÑтів!\n Bruecke МіÑÑ‚ Bruecke muss an\neinfachem\nHang beginnen!\n МоÑти повинні\nпочинатиÑÑ Ð½Ð°\nпрÑмому Ñхилі!\n Brueckenboden міÑÑ‚ Build air depot Будувати ангар Ð´Ð»Ñ Ð»Ñ–Ñ‚Ð°ÐºÑ–Ð² build choosesignals Будувати Ñемафор вибору перону Build city market Будувати нову крамницю у найближчому міÑті. Build drain ТранÑформаторна підÑÑ‚Ð°Ð½Ñ†Ñ–Ñ build HQ Будувати Ð¾Ñ„Ñ–Ñ Build land consumer Побудувати нову електроÑтанцію Build maglev depot Побудувати депо Ð´Ð»Ñ Ð¿Ð¾Ñ—Ð·Ð´Ñ–Ð² на магнітній підвіÑці Build monorail depot Побудувати депо Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¾Ñ€ÐµÐ¹Ð¾Ðº Build narrowgauge depot Побудувати депо Ð´Ð»Ñ Ð²ÑƒÐ·ÑŒÐºÐ¾ÐºÐ¾Ð»Ñ–Ð¹ÐºÐ¸ Build powerline Побудувати лінію електропередачі Build presignals Побудувати двоÑторонній Ñемафор Build road depot Побудувати гараж Build ship depot Побудувати корабельний док Build signals Побудувати Ñемафори Build train depot Побудувати залізничне депо Build tram depot Побудувати трамвайне депо Build truck depot Побудувати гараж Ð´Ð»Ñ Ð²Ð°Ð½Ñ‚Ð°Ð¶Ñ–Ð²Ð¾Ðº Building costs estimates Орієнтовна вартіÑть будівництва Buildings МіÑькі Ñпоруди Built artifical slopes Побудувати штучні нахили Built random attraction Побудувати випадкову пам'Ñтку Bus_tab ÐвтобуÑи Can only move from halt to halt or waypoint to waypoint. Може переміщатиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸\n від зупинки до зупинки, або\n від точки до точки. Cancel СкаÑувати Cannot connect to offline server! Ðе можна з'єднатиÑÑ Ñ–Ð· Ñервером поза мережею! Capacity: МіÑткіÑть: Capacity: %.0f MW МіÑткіÑть: %.0f МВт\n Capacity: %d%s %s\n МіÑткіÑть: %3d%s %s\n Capacity: %s\nLoad: %d (%d%%) МіÑткіÑть: %s\nЗавантажено: %d (%d%%) Cars are not available yet! Ðвтомобілі ще не доÑтупні. cars.\nstate машини\n Cash Ð‘Ð°Ð»Ð°Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÑƒ Change player Змінити Ð³Ñ€Ð°Ð²Ñ†Ñ Chart Діаграма Chat_msg Балачка Choose direction Вибрати напрÑмок Choose operation executed on clicking stored/new vehicles Вибрати операцію, виконувану при клацанні по новому/збереженому Ñ‚/з chooses a random map Вибирає випадкову мапу. citicens Жителі City attraction МіÑькі пам'Ñтки City industries МіÑька промиÑловіÑть City list СпиÑок міÑÑ‚ City size Розмір міÑта city_road МіÑька дорога citybuilding builder Будувати міÑькі Ñпоруди CityLimit Межі міÑта cl_title Перелік заÑобів cl_txt_sort СортуваннÑ: Clear block reservation Показати/уÑунути зарезервовані шлÑхи clf_chk_aircrafts Літаки clf_chk_cars ÐвтотранÑпорт clf_chk_indepot у депо clf_chk_maglev Поїзд на магнітній підвіÑці clf_chk_monorail Монорейковий поїзд clf_chk_name_filter Фільтр за назвою: clf_chk_narrowgauge Вузьколійка clf_chk_noincome Без прибутку clf_chk_noline Без лінії clf_chk_noroute Без маршруту clf_chk_noschedule Ðема розкладу clf_chk_obsolete ЗаÑтаріло clf_chk_ships Кораблі clf_chk_spezial_filter ОÑобливий фільтр: clf_chk_stucked ЗаÑтрÑгнуто clf_chk_trains Поїзди clf_chk_trams Трамваї clf_chk_type_filter Типи фільрів: clf_chk_waren Фільр за товаром: clf_title Фільтр ÑпиÑку заÑобів Climate Control ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð»Ð°Ð½Ð´ÑˆÐ°Ñ„Ñ‚Ñƒ closed закрито. COLOR_CHOOSE\n Будь лаÑка, виберіть два\nкольори із\nÐ·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¾Ñ€ÑƒÑ‡: Company bankrupt БанкрутÑтво компанії Company_msg Конкуренти Comparing pak files ... ПорівнÑÐ½Ð½Ñ Ð³Ñ€Ð°Ñ„Ñ–Ñ‡Ð½Ð¸Ñ… пакетів... Configure AI Ðалаштувати параметри ШІ Configure AI setttings Ðалаштувати параметри ШІ Congratulation\nScenario was complete in\n%i months %i years. Вітаємо!\nВи завершили Ñценарій за\n%i міÑÑців та %i років! Connected stops Сполучені зупинки Connected with server З'єднано із Ñервером Constructed by Створено: Constructed by %s Ðамальовано: %s\n construction speed швидкіÑть будівництва Construction_Btn ВартіÑть будівництва Consumed Спожито convoi %d of %d ПотÑг %d із %d convoi error tooltips підказки про помилки над потÑгом Convoi has been sent\nto the nearest depot\nof appropriate type.\n Колону заÑобів надіÑлано\nу найближче депо\nвідповідного типу. Convoi is sold when all wagons are empty. ТранÑпортний заÑіб буде продано, Ñк тільки він повніÑтю звільнитьÑÑ. convoi mouseover tooltips Підказки над курÑором у колоні convoi passed last\nmonth %i\n За минулий міÑÑць \nпройшло %i Ñ‚/з\n Convois Конвої Convois: %d\nProfit: %s Т/з: %d\nПрибуток: %s Convoys Конвої Copy Convoi Копіювати конвой Copy the selected convoi and its schedule or line Копіювати обраний конвой та його розклад або лінію\n\n cost for removal ВартіÑть Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Cost: %8s (%.2f$/km %.2f$/m)\n ВартіÑть: %s (%.2f$/км %.2f$/m)\n Cost: %8s (%.2f$/km)\n ВартіÑть: %8s (%.2f$/км)\n Costs Видатки Create a new line based on this schedule Ðа оÑнові цього розкладу Ñтворити нову лінію curiosity builder Творець дивини curlist_title СпиÑок визначних міÑць Currently playing: Ðаразі звучить: Customers live in: Відвідувачі живуть у: deactivated in online mode Ðе активний поки не у мережі Deccelerate time Уповільнити Ñ‡Ð°Ñ December Грудень decrease underground view level зменшити рівень підземного оглÑду Del Stop Вилучити Delete Line Вилучити лінію Delete the current stop Вилучити поточну зупинку Delete the selected line (if without associated convois). Вилучити обрану лінію (Ñкщо відÑутні прив'Ñзані до неї заÑоби) Delete this file. Вилучити цей файл. Delivered ДоÑтавлено Demand Попит Demand: %.0f MW Попит: %.0f MW\n Denkmal Пам'Ñтник Departed Відправлено Departure board Ð§Ð°Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Departures to\n Ð’Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾\n Depots Депо Der Tunnel ist nicht frei!\n Тунель не порожній!\n Destination ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Destroying map ... Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñтарої мапи… Details Подробиці Die Bruecke ist nicht frei!\n МіÑÑ‚ не вільний!\n diesel Дизель directmail прÑма пошта Direkt erreichbare Haltestellen ПрÑмі маршрути звідÑÑ–Ð»Ñ disable midi Вимкнути музику MIDI Display settings Параметри графіки Distance ВідÑтань Dock Док Dock must be built on single slope! Порт повинен будуватиÑÑ Ð½Ð° рівній ділÑнці. Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen Ð”Ð»Ñ Ð²Ð¸Ð¿Ð»Ð°Ñ‚Ð¸ боргу у Ð’Ð°Ñ Ð·Ð°Ð»Ð¸ÑˆÐ¸Ð»Ð¾ÑÑ %d міÑÑців. Durchsatz МакÑ. Economy Економіка та міÑта Eigenbesitz\n Муніципальна влаÑніÑть\n Ein %s\npasst hier nicht.\n "%s"\nне поміÑтитьÑÑ Ñ‚ÑƒÑ‚!\n Einstellungen aendern Параметри electric Електропривід Electricity Електрика Electricity producer\n\n Виробник електрики\n\n Electrics_tab Електричні Ñ‚/з Electrify track Ð•Ð»ÐµÐºÑ‚Ñ€Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ enlarge map Збільшити карту enter a value between %i and %i Введіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¼Ñ–Ð¶ %i Ñ– %i Enter address Введіть адреÑу Enter Password Введіть пароль Error Помилка Erzeuge neue Karte.\n Будь лаÑка, почекайте,\n ÑтворюєтьÑÑ Ð½Ð¾Ð²Ð° карта.\n\n (Це може зайнÑти\n кілька хвилин\n Ð´Ð»Ñ Ð²ÐµÐ»Ð¸ÐºÐ¸Ñ… карт)\n Es wird bereits\nein Fahrplan\neingegeben\n СтворюєтьÑÑ\n розклад.\n Завершіть його\n перед упорÑдкуваннÑм!\n Fabrikanschluss З'єднані фабрики Fabrikname Ðазва фабрики Factories Фабрики factory details Подробиці про фабрику factorybuilder КонÑтруктор фабрики Fahrplan Розклад Fahrtziel ПризначеннÑ: Fahrzeuge koennen so nicht entfernt werden ТранÑпортний заÑіб\nне може бути прибрано\nтаким чином!\n Fahrzeuge: ТранÑп. заÑоби: Farbe Колір Ð³Ñ€Ð°Ð²Ñ†Ñ Fast forward ПриÑкорити Ñ‡Ð°Ñ February Лютий Ferry_tab Пороми Fertig Готово Filename Ðазва файлу: Files from: Файли із: Filter: Фільтр: Finances of %s ФінанÑи %s Finanzen ФінанÑи find mismatch знайти невідповідніÑть fl_title СпиÑок фабрик Flug_tab ПаÑажирÑькі літаки follow me Слідувати Follow the convoi on the map. Слідувати за конвоєм на мапі. Forest Ð›Ñ–Ñ Found new city заÑнувати нове міÑто FPS: Кадр/Ñ: Fracht Вантажі Frame time: Ð§Ð°Ñ ÐºÐ°Ð´Ñ€Ñƒ: Free Capacity Вільно freeplay mode Без банкрутÑтва Friction: поточний фактор тертÑ: fuel_cell елемент Ð¶Ð¸Ð²Ð»ÐµÐ½Ð½Ñ Full load Мінімальне завантаженнÑ: Fundament Фундамент Fussgaenger Пішохід Game info Дані про гру GAME PAUSED ГРР- ПРИЗУПИÐЕÐÐ Game_msg Загальне Gear: СпорÑдженнÑ: Gebaeude Ð‘ÑƒÐ´Ñ–Ð²Ð»Ñ General Загальне Generated Згенеровано Generation: %.0f MW Виробництво: %.0f МВт\n Gewicht МаÑа Gewinn Прибуток: Give the selected vehicle(s) an individual schedule Призначити обраним Ñ‚/з індивідуальний розклад gl_btn_sort_catg за категорією gl_title СпиÑок вантажів go home У депо Goods Вантажі Goods AI ШІ торговець Goods list СпиÑок товарів Gross Profit Валовий прибуток Groundobj Ðаземний об'єкт Grow city Збільшити міÑто Growth ЗроÑÑ‚Ð°Ð½Ð½Ñ Ð¼Ñ–Ñта H зупинка Hangar Ðнгар Happy ЩаÑливі Haus kaufen Купити дім Helligk. Графіка Help Довідка Help text not found ТекÑÑ‚ довідки не знайдено. hide all building приховати уÑÑ– будівлі hide city building приховати міÑькі будівлі hide objects under cursor приховати об'єкти під курÑором hide station names приховати назви Ñтанцій hide transparent прозоріÑть заміÑть Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ hide trees Приховати дерева Hier warten/lagern: Товари Ñ– паÑажири, Ñкі очікують: Higher transport fees, crossconnect all factories Вищі транÑпортні збори, вимкнути вчаÑно Highlite schedule ПідÑвітити маршрут hl_title СпиÑок Ñтанцій hl_txt_filter Фільтр: hl_txt_sort УпорÑдкувати за: hlf_chk_airport Ðеропорти hlf_chk_anleger Док hlf_chk_bahnhof Залізнична ÑÑ‚Ð°Ð½Ñ†Ñ–Ñ hlf_chk_bushalt ÐвтобуÑна зупинка hlf_chk_frachthof Ðавантажувальна платформа hlf_chk_keine_verb без з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ hlf_chk_maglevstop Ð¡Ñ‚Ð°Ð½Ñ†Ñ–Ñ Ð¼Ð°Ð³Ð½. підвіÑки hlf_chk_monorailstop Зупинка монорейки hlf_chk_name_filter Фільтрувати назви: hlf_chk_narrowgaugestop Ð¡Ñ‚Ð°Ð½Ñ†Ñ–Ñ Ð²ÑƒÐ·ÑŒÐºÐ¾ÐºÐ¾Ð»Ñ–Ð¹ÐºÐ¸ hlf_chk_overflow ÐŸÐµÑ€ÐµÐ¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ hlf_chk_spezial_filter ОÑобливий фільтр: hlf_chk_tramstop Трамвайна зупинка hlf_chk_type_filter Типи фільтрів: hlf_chk_waren_abgabe Виробництво: hlf_chk_waren_annahme Потреби: hlf_title Фільтр ÑпиÑку Ñтанцій Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. Початкове депо не знайдено!\n Ви повинні поÑлати заÑіб\n у депо вручну. Homeless Бездомні hydrogene Гідроген Idle: ПроÑтій: ignore climates ігнорувати клімат In the industry legend show only currently existing factories Відображати ÑпиÑок наÑвних у даний момент фабрик на карті. In Transit У дорозі Increase Industry density Збільшити щільніÑть промиÑловоÑті increase underground view level збільшити підземний рівень оглÑду industrial building ПромиÑлові будівлі Init map ... Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ð°Ð¿Ð¸â€¦ Input Ð¡Ð¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ins Stop Ð’Ñтавити Insert stop before the current stop Ð’Ñтавити зупинку перед поточною зупинкою Intercity road len: Довжина міжміÑьких доріг: Intro. date: Початок екÑпл.: invalid невизначений Invalid coordinate Хибні координати isometric map Ізометричний виглÑд January Січень join game Грати у мережі July Липень Jump to ПереÑтрибнути на June Червень Kann Spielstand\nnicht laden.\n Ðе можу завантажити\nзбережену гру!\n Kann Spielstand\nnicht speichern.\n Ðе можу відкрити Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу\nфайл із збереженнÑм гри!\n Kein Besitzer\n Без влаÑника\n keine нічого Keine Einzelfahrzeuge im Depot Т/з не зберігаютьÑÑ Ñ‚ÑƒÑ‚. Keyboard_Help\n Довідка з клавіатури\n koord Координати Kreuzung ПерехреÑÑ‚Ñ labellist_title СпиÑок маркерів Lade Relief Завантажити карту виÑот Laden Завантажити нову гру Land attraction ЗаміÑька пам'Ñтка Land industries Виробничі ланцюжки: LANG_CHOOSE\n Будь лаÑка, виберіть\nвашу бажану мову:\n LARGE_NUMBER_STRING М LARGE_NUMBER_VALUE 1е6 Last Month ОÑтанній міÑÑць: Last Year Торік: Leaving depot! Залишає депо! leer порожній Legend Леґенда мапи Leistung ПотужніÑть Leistung: %d kW ПотужніÑть: %d кВт Leitung Ð›Ñ–Ð½Ñ–Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‡Ñ– letzen Monat: diesen Monat: минулий міÑÑць: цей міÑÑць: Line Ð›Ñ–Ð½Ñ–Ñ Line Management Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ Ð»Ñ–Ð½Ñ–Ñми Lineless convoys serving this stop Т/з без ліній, Ñкі обÑлуговують цю зупинку Lines serving this stop Лінії, Ñкі обÑлуговують цю зупинку LKW_tab Вантажівки Load game Завантажити гру load height data from file Завантажити дані про виÑоти із файлу. Load scenario Завантажити Ñценарій loaded завантажено loaded passenger/freight УпорÑдкувати паÑажирів/товари за Loading (%i->%i%%)! ÐÐ°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ (%i->%i%%) Loading addon paks ... Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÐµÑ‚Ñ–Ð² доповнень… Loading map ... Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¼Ð°Ð¿Ð¸â€¦ Loading paks ... Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÐµÑ‚Ñ–Ð²â€¦ Loading skins ... Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¾Ð±Ð¾Ð»Ð¾Ð½Ð¾Ðºâ€¦ Lock game Ðе дозволÑти зміну Ð³Ñ€Ð°Ð²Ñ†Ñ (потрібне підтвердженнÑ). Lokomotive_tab Локомотиви m3 м³ Maglev Магн. підвіÑка maglev vehicle Поїзд на магн. підвіÑці maglev_track ÐšÐ¾Ð»Ñ–Ñ Ð´Ð»Ñ Ð¼Ð°Ð³Ð½. підвіÑки Maglevdepot Депо Ð´Ð»Ñ Ð¼Ð°Ð³Ð½. підвіÑки Mail Demand %d\n Потреба на пошту %d\n Mailbox Поштова Ñкринька Mailbox Options Параметри центру повідомлень Maintenance Ð£Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ make stop public (or join with public stop next) costs %i per tile and level Ñтворити публічну зупинку (або приєднати до ÑуÑідньої публічної зупинки) вартіÑтю %i$ за клітинку та рівень Manual (Human) Підручник (людина) Manufactured: Вироблено: Map roughness ÐерівніÑть мапи: map zoom маÑштаб March Березень Margin (%%) Ð—Ð°Ð¿Ð°Ñ Marker Знак max Ð¼Ð°ÐºÑ Max Boost (%%) МакÑ. приÑÐºÐ¾Ñ€ÐµÐ½Ð½Ñ (%%) Max income: МакÑ. дохід: Max. speed: МакÑ. швидкіÑть: Maximum 254 stops\nin a schedule!\n ДоÑÑгнуто макÑимуму 254 зупинок\nу розкладі!\n maximum length of rivers Ðайбільша довжина річок Maximum tile height difference reached. Ðайбільша виÑота\nÑ€Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð¼Ñ–Ð¶ двома\nклітинками вже\nдоÑÑгнута. Maxspeed Ðайбільша швидкіÑть May Травень Median Citizen per town Середнє чиÑло жителів на міÑто: Meldung ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Menge кількіÑть MessageOptionsText \nÐовий рік\n\nÐовини гравців\n\nМіÑькі новини\n\nБез маршруту\n\nÐові призначеннÑ\n\nБалачка\n\nÐові Ñ‚/з\n\nÐ—Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñтанцій\n\nПроблеми\n\nТранÑпортні затори\n\nСценарій min мін. minimum length of rivers Ðайменша довжина річок Missing pakfiles Загублені об'єкти! Modify the selected line Змінити вибрану лінію Monate alt міÑÑців. Monorail Монорейка monorail vehicle монорейковий Ñ‚/з monorail_track Монорейкова ÐºÐ¾Ð»Ñ–Ñ Monorailboden ОÑнова монорейки Monoraildepot Монорейкове депо month wait time Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° міÑÑць Months МіÑÑці Monument Пам'Ñтник Monuments Пам'Ñтники Mountain height ВиÑота гір: Movingobj Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±'єкту Music playing disabled/not available Музика вимкнена/недоÑтупна. Music volume: ГучніÑть музики: mute sound Без звуку Name Ðазва Narrowgauge Вузькоколійка Narrowgauge are not available yet! Вузькоколійка ще недоÑтупна! narrowgauge vehicle вузькоколійний Ñ‚/з narrowgauge_track вузькоколійний шлÑÑ… Narrowgaugedepot Вузькоколійне депо Net ID: %p ІД мережі: %p\n Net Wealth ЧиÑті активи Net wealth near zero ЧиÑті активи близькі до Ð½ÑƒÐ»Ñ Neue Karte Ðова гра Neue Welt Створити нову гру new convoi Ðовий конвой New Line Ðова Ð»Ñ–Ð½Ñ–Ñ New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. Створена нова лініÑ!\nТепер Ви можете призначити лінію,\nвибираючи Ñ—Ñ— з поданого\nнижче ÑпиÑку. New Vehicles Ðові Ñ‚/з: Nickname: ПрізвиÑько: no buildings hidden не приховувати будівлі no convois нема Ñ‚/з No goods are loaded onto this convoi. Вантажі не будуть завантажуватиÑÑ Ð½Ð° цей Ñ‚/з. no goods waiting Ðема товарів, Ñкі очікують no load Лише розвантажувати No Route Ðема шлÑху No stop here! Ðе зупинÑтиÑÑ Ñ‚ÑƒÑ‚! No suitable ground! Ðема придатної землі! No terminal station here! Тут немає терміналу! no timeline без чаÑової шкали no tree Без дерев No. of Factories ЧиÑло фабрик Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n Ð’Ñтановіть розклад \nÑ‚/з перед відправкою!\n none нема nord Північ nordost Північний Ñхід nordwest Північний захід Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! Розклад не можна \n помінÑти під Ñ‡Ð°Ñ \n пошуку шлÑху. Not enough fields would remain. Ðавколо ферми залишилоÑÑ Ð·Ð°Ð½Ð°Ð´Ñ‚Ð¾ мало полів. November ЛиÑтопад Now active as %s.\n Тепер граємо за %s.\n Number of rivers ЧиÑло річок Object Об'єкт Odometer: %s km Одометр: %s км Ok Гаразд Oktober Жовтень On loan since %i month(s) Ðа кредиті від %i міÑÑцÑ(ів) On this map, you are not\nallowed to change player!\n Ð¦Ñ Ð³Ñ€Ð° заблокована!\n Зміна Ð³Ñ€Ð°Ð²Ñ†Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð°!\n\n\n Only city chains Будувати ланцюжки міÑької промиÑловоÑті Only first %d differing paks reported. There are probably more. Повідомили лише перші %d окремі пакунки. Ðле Ñ—Ñ… Ñ”, вірогідно, більше. Only land chains Лише заміÑькі ланцюжки Only one transformer per factory! Тільки один транÑформатор на фабрику! Only show goods which are currently handled by factories Показати тільки товари, що наразі оброблені фабриками open відкрити Operation Операційні витрати Ops Profit Операційний прибуток Optionen Параметри Or enter a server manually: Ðбо введіть Ñервер вручну: Origin ÐŸÐ¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ ost Схід Output Вироблено Ownership ВлаÑник Pak which may cause severe errors: ÐаÑтупні об'єкти (пакети) відÑутні, що може призвеÑти до відмови транÑпортних ланцюжків: Pak which may cause visual errors: ÐаÑтупні об'єкти (пакети) були замінені подібними об'єктами: Pak(s) different: Пакет(и) різний(Ñ–): Pak(s) missing on client: Пакет(и) загублені на клієнті: Pak(s) not on server: Пакет(и) не на Ñервері: Pakset differences ВідмінноÑті між наборами пакетів paletten Ñщики Pas_tab ПаÑажирÑькі поїзди Passagiere ПаÑажири Passagierrate ÐаÑвніÑть паÑажирів Passagierziele ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñажирів/пошти Passenger AI ШІ паÑажирів Passenger Demand %d\n Попит на паÑажирів %d\n Passengers %d %c, %d %c, %d no route ПаÑÑажири %d %c, %d %c, %d без маршруту Passengers %d %s, %d %s, %d no route ПаÑÑажиры %d %s, %d %s, %d без маршруту Password Пароль: Pause Пауза Pax <%i> Mail <%i> ПаÑажирÑька <%i> пошта <%i> PaxDest Цілі подорожі Percent Electricity Виробництво електри (%% від потреби): Planes are not available yet! Літаки ще недоÑтупні! Plant tree ПоÑадити дерева player Гравець player -1 Людина-гравець player 0 державна Ñлужба player 1 Ðапік 128 ÐС player 10 Гравець 10 player 11 Гравець 11 player 12 Гравець 12 player 13 Гравець 13 player 2 Тріккі транÑпорт player 3 Меєр мувінґ Ко. player 4 ВМ ЕкÑпедитор player 5 ТОВ „СупертранÑ“ player 6 ПСК Ñ– Ко ÐšÒ player 7 Гравець 7 player 8 Гравець 8 player 9 Гравець 9 Please choose vehicles first\n Спершу виберіть транÑпортні заÑоби!\n Post Пошта Postrate ÐаÑвніÑть пошти Power ПотужніÑть Power (MW) ПотужніÑть (МВт) Power: ПотужніÑть: Power: %4d kW\n ПотужніÑть: %4d кВт\n Powerlines Лінії електропередач Problems_msg Проблеми Produced Вироблено Production of %s has been stopped:\n%s\n Виробництво %s було припинено:\n%s\n Production/Boost Виробництво/ЗроÑÑ‚Ð°Ð½Ð½Ñ Produktion Виробництво: Profit Прибуток promote to line Ðова Ð»Ñ–Ð½Ñ–Ñ q1 ВеÑна q2 Літо q3 ОÑінь q4 Зима Query server Сервер запиту rail car Рейкова машина random випадково Random age випадковий рік Random map Випадкова мапа Rathaus Ратуша Rating Оцінка ratio_pax Ð¡Ð¿Ñ–Ð²Ð²Ñ–Ð´Ð½Ð¾ÑˆÐµÐ½Ð½Ñ Relevant Відповідні Reliefkarte Мапа Remove Вилучити мітку remove airstrips Вилучити Ñмугу remove channels Вилучити канали remove interm. signals Вилучити вбудовані Ñемафори remove maglev tracks Вилучити колії на магн. подвіÑці remove monorails Вилучити монорейки remove narrowgauge tracks Вилучити вузькоколійки remove powerlines Вилучити ЛЕП remove roads Вилучити дороги remove tracks Вилучити колії Remove wayobj %s Вилучити дорожній об'єкт %s replace other signals замінити інші Ñемафори replace stop Замінити зупинку request closing Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ residential house Житлові будинки Restore natural slope Відновити природний Ñхил. Restwert: ВартіÑть продажу: Retire. date: Кінець екÑпл.: return ticket квиток назад Revenue Виручка Revision: ВерÑÑ–Ñ: road дорога road vehicle траÑпортний заÑіб Roadsign Дорожний знак Rotate map Повернути карту Rotation Поворот Routing Прокладка маршруту sack мішок(ів) sail вітер Saving map ... Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¼Ð°Ð¿Ð¸â€¦ Scenario complete: %i%% Перебіг Ñценарію: %i%% Scenario Debug Ð—Ð½ÐµÐ²Ð°Ð´Ð¶ÐµÐ½Ð½Ñ Scenario Error Log Помилки коду Scenario Goal Ціль Ñценарію Scenario Info ÐÐ½Ð¾Ñ‚Ð°Ñ†Ñ–Ñ Scenario information Дані про поточний Ñценарій Scenario Result Перебіг Scenario Rules Правила Schedule changing! ЗмінюєтьÑÑ Ñ€Ð¾Ð·ÐºÐ»Ð°Ð´! Schienentunnel Побудувати залізничний тунель Schiff_tab Кораблі Schiffdepot Верф Schleppkahn_tab Баржі Screenshot Знімок екрану Seasons Пори року Sehenswuerdigkeit ТуриÑтична пам'Ñтка Select a server to join: Виберіть Ñервер, аби приєднатиÑÑ: Select a theme for display Виберіть тему Ð´Ð»Ñ Ð´Ð¸Ñплею Sell the selected vehicle(s) Продати вибрані Ñ‚/з. sended ÐадіÑлати лиÑта SEP_FRACTION , SEP_THOUSAND . SEP_THOUSAND_EXPONENT 3 September ВереÑень Server did not respond! Сервер не відповідав Serves Line: Ðа лінії: Service ПоÑлуга set signal spacing Задати відÑтань між Ñигналами Setting ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ship Корабель shops and stores Магазини та офіÑи Show all Показати уÑе show all building Показати уÑÑ– будівлі Show also vehicles no longer in production. Показати також Ñ‚/з, Ñкі більше не вироблÑютьÑÑ. Show also vehicles that do not match for current action. Показати також Ñ‚/з, Ñкі не можуть бути викориÑтані Ð´Ð»Ñ Ð²Ð¸Ð±Ñ€Ð°Ð½Ð¾Ñ— дії Show even servers with wrong version or pakset Також показувати Ñервери з невірною верÑією або пакетом show grid Показати Ñітку Show industry Перелік підприємÑтв Show legend Показати леґенду Show map scale Показати шкалу виÑот Show mismatched Показати невідповідніÑть Show obsolete Показати заÑтаріле Show offline Показати поза мережею Show only used Показати лише викориÑтане Show schedules Показати розклади Show servers that are offline Показати Ñервери поза мережею Show servers where game version or pakset does not match your client Показати Ñервери, де верÑÑ–Ñ Ð³Ñ€Ð¸ чи набору не збігаєтьÑÑ Ð· верÑією вашого клієнта show station coverage Показати Ð¿Ð¾ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñтанцій show station names Показати назви Ñтанцій show waiting bars Показати Ñмуги Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ show/hide block reservations Показати/приховати Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ·ÐµÑ€Ð²ÑƒÐ²Ð°Ð½ÑŒ Show/hide estimated arrival times Показати/приховати очікуваний Ñ‡Ð°Ñ Ð¿Ñ€Ð¸Ð±ÑƒÑ‚Ñ‚Ñ show/hide object owner Показати/приховати влаÑника об'єкта Show/hide statistics Показати/приховати ÑтатиÑтику Shows buttons on special topics. Показати кнопки на Ñпеціальних темах. Shows consumer/suppliers for factories Показати Ñпоживачів/поÑтачальників Ð´Ð»Ñ Ñ„Ð°Ð±Ñ€Ð¸Ðº Shows the color code for several selections. Показати код кольору Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ñ… виділень. Shows the currently selected schedule Показати поточний обраний розклад Shrink city Зменшити міÑто shuffle midis перемішати музику Signal Семафор signal spacing ВідÑтань між Ñемафорами Sim: Sim-петлі: Similar view as the main window Відображати карту так Ñамо, Ñк відображаєтьÑÑ Ñ–Ð³Ñ€Ð¾Ð²Ðµ вікно. Size (%d MB): Розмір (%d МБ): sliced underground mode ОглÑд шарів карти slot empty Ñлот порожній Smart hide objects Кмітливо ховати об'єкти Sort by Сортувати за Sort waiting list by Сортувати ÑпиÑок Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° Sound Звук Sound settings Параметри звуку Sound volume: ГучніÑть звуку: special freight ОÑобливий вантаж Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. ЗроÑÑ‚Ð°Ð½Ð½Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ñті:\nдорога %i км/год, Ð·Ð°Ð»Ñ–Ð·Ð½Ð¸Ñ†Ñ %i км/год\nкораблі %i км/год, літаки %i км/год. Speedlimit ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ñті Speichern Зберегти Spieler Гравець Spieler(mz) Гравці Spielerliste СпиÑок гравців Spielstand wurde\ngeladen!\n \nГра уÑпішно завантажена!\n Spielstand wurde\ngespeichert!\n \nГра уÑпішно збережена!\n Sprache Мова Sprachen Мови Stadtinformation МіÑька ÑтатиÑтика Start Старт Start the selected vehicle(s) Відправити на лінію обрані Ñ‚/з. Starte Spiel Розпочати гру Station tiles: Секції Ñтанції: Station_msg Станції Status Стан steam Ð¿Ð°Ñ€Ð°Ì Step timeline one year ПеревеÑти Ñ‡Ð°Ñ Ð½Ð° рік уперед. Stops Зупинки Storage Склад Storage capacity МіÑткіÑть Ñкладу Strassendepot Гараж Strassentunnel Ðвтомобільний тунель street car трамвай sued Південь suedost Південний Ñхід suedwest Південний захід Summer snowline Ð›Ñ–Ñ‚Ð½Ñ Ð»Ñ–Ð½Ñ–Ñ Ñнігу Supplied: %.0f %% ПоÑтавлено: %.0f %% Suppliers ПоÑтачальники: Tage alt днів тому. Theme selector Вибирач тем There are still vehicles\nstored in this depot!\n ÐаÑвні транÑпортні заÑоби\nу цьому депо!\n This Month Цього міÑÑцÑ: This Year Цього року: Tile not empty. ДілÑнка не порожнÑ.\nБудь лаÑка, видаліть уÑе\nперед будівництвом\n штучного нахилу. timeline дотримуватиÑÑ Ñ‡Ð°Ñової оÑÑ– tl_title Перелік уÑÑ–Ñ… міÑÑ‚ To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. Потік транÑпорту у %1$s на піднеÑенні:\n%3$i платників податків зробили реальною побудову\nof %2$s. To heavy traffic\nresults in traffic jam.\n Ðадто щільний рух\nÑпричинив пробку на дорозі.\n Toggle day/night view Перемкнути день/ніч Toggle vehicle tooltips Перемкнути підказки Ð´Ð»Ñ Ð·Ð°Ñобів tonnen Ñ‚ Total inhabitants: Ð’Ñього жителів: Tourist attractions ТуриÑтичні принади: Tourists Пам'Ñтки Town_msg Ðові Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Town: %s\n МіÑто: %s\n Towns МіÑта track шлÑÑ… Tracks Колії Traffic Рух Train Поїзд Trains are not available yet! Поїзди ще недоÑтупні! Tram Трамвай tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. трамвай %i км/год, Ð¼Ð¾Ð½Ð¾Ñ€ÐµÐ»ÑŒÑ %i км/год\nмагнітна підвіÑка %i км/год, вузькоколійка %i км/год. tram_track Трамвайна ÐºÐ¾Ð»Ñ–Ñ Tramdepot Трамвайне депо Trams are not available yet! Трамваї ще не доÑтупні! Transferring game ... ПередаєтьÑÑ Ð³Ñ€Ð°â€¦ Transformer only next to factory! ТранÑформаторна підÑÑ‚Ð°Ð½Ñ†Ñ–Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ð° бути Ð±Ñ–Ð»Ñ Ð¿Ñ–Ð´Ð¿Ñ€Ð¸Ñ”Ð¼Ñтва! Translation Переклад transparent station coverage прозора зона Ð¿Ð¾ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Transported Перевезено TrolleyBus_tab тролейбуÑи Truck Вантажівка tt_Other Інше Tunnel muss an\neinfachem\nHang beginnen!\n Тунелі мають починатиÑÑ\nна прÑмому Ñхилі!\n Tunnel must start on single way! Тунелі повинні починатиÑÑ Ð½Ð° одному шлÑху! Tunnelboden Тунель underground mode підземний режим UNDO failed! СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ñ–Ð»ÑŒÑˆÐµ недоÑтупне.\nВи можете ÑкаÑувати ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ \nмаршруту тільки, Ñкщо на ньому \nне буде побудовано Ñигналів /\nÑтанцій / зупинок або ще \nщоÑÑŒ. Undo last ways construction СкаÑувати оÑтаннє будівництво траÑи Unemployed Безробітні Unhappy ÐещаÑливі units/day одиниць/міÑÑць Update Line Змінити лінію upgrade HQ Поліпшити Ð¾Ñ„Ñ–Ñ Usage: %.0f %% ВикориÑтаннÑ: %.0f %% Usage/Output СпоживаннÑ/виробництво Use beginner mode ВикориÑтати режим Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑ–Ð²Ñ†Ñ Use timeline start year ВикориÑтати рік чаÑової шкали: Vehicle %s can't find a route! %s не може знайти шлÑÑ…! Vehicle %s is stucked! %s у пробці! Vehicle details Дані про заÑіб Verbrauch СпоживаннÑ: Vergroessere die Karte\n Збільшити мапу.\n Verkauf Вилучити зараз! verkaufen Продати Verkehrsteilnehmer МіÑький транÑпорт Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n У Ð’Ð°Ñ ÑƒÑ‚Ð²Ð¾Ñ€Ð¸Ð»Ð°ÑÑ Ð·Ð°Ð±Ð¾Ñ€Ð³Ð¾Ð²Ð°Ð½Ñ–Ñть!\n\n ЗалишилоÑÑ %d міÑÑць(а,ів)\n щоб виплатити борг!\n via через (деталі) via %s\n через %s\n via Menge через (кількіÑть) voranstellen ПоÑтавити Ñпереду Waggon_tab Вагони waiting очікують Waiting for clearance! Очікують Ð·Ð²Ñ–Ð»ÑŒÐ½ÐµÐ½Ð½Ñ ÑˆÐ»Ñху! Walked Піші walking ходьба Warnings_msg Трафік Wasser Вода Water Море Water level Рівень води: water vehicle Водний Ñ‚/з way %s cannot longer used:\n ШлÑхи типу %s не можуть бвльше викориÑтовуватиÑÑ.\n way %s cannot longer used:\n%s\n Дороги типу %s не можуть більше викориÑтовуватиÑÑ.\n%s\n way %s now available:\n Тепер доÑтупні дороги типу %s.\n Way toll Дорожнє мито Ways not connected Дороги не з'єднані Wegpunkt Ð”Ð¾Ñ€Ð¾Ð¶Ð½Ñ Ñ‚Ð¾Ñ‡ÐºÐ° Weight: Вага: Wert Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ west Захід Winter snowline Зимова Ð»Ñ–Ð½Ñ–Ñ Ñнігу withdraw Виключити з обігу Withdraw All Виключити уÑе з обігу WRONGSAVE \n ÐеÑуміÑна верÑÑ–Ñ \n збереженнÑ. Ðе можу завантажити \n цей файл.\n Year %i has started. РозпочавÑÑ %i рік. Years Роки Your primary color: ОÑновний колір: Your secondary color: Вторинний колір: Zielort Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ zooming in Ð·Ð±Ñ–Ð»ÑŒÑˆÐµÐ½Ð½Ñ zooming out Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Zu nah am Kartenrand Занадто близько\n до краю карти,\nщоби щоÑÑŒ будувати!\n #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті поїзда на магнітній подушці: %.1f км/год, %s. New world record for monorails: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті монорейкових поїздів: %.1f км/год, %s. New world record for motorcars: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті автомобілів: %.1f км/год, %s. New world record for narrowgauges: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті вузькоколійних поїздів: %.1f км/год, %s. New world record for planes: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті літаків: %.1f км/год, %s. New world record for railways: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті поїздів: %.1f км/год, %s. New world record for ship: %.1f km/h by %s. Ðовий Ñвітовий рекорд швидкоÑті кораблів: %.1f км/год, %s. #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ 0center ÑередміÑÑ‚Ñ 0extern Ñело 0suburb передміÑÑ‚Ñ 1center %s %s 1extern %s %s Ð¾ÐºÐ¾Ð»Ð¸Ñ†Ñ 1suburb %s %s %s 2center %s %s головна 2extern %s %s Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ 2suburb %s Рівнини %s %s 3center %s оÑновна %s 3extern %s ÑільÑька %s 3suburb %s ÑільÑька %s %s 4center %s ÑередміÑÑ‚Ñ %s 4extern %s передміÑÑ‚Ñ %s 4suburb %s приміÑька %s 5center %s ділова %s 5extern %s %s транзитна 5suburb %s міÑто %s 6center %s вузол %s 6extern %s біржа %s 6suburb %s окраїна %s %s 7center %s міÑто %s 7extern %s рівнини %s 7suburb %s парк %s 8center %s ділова %s 8extern %s %s запаÑна %s 8suburb %s Ñупутник %s 9center %s оÑьова %s 9extern %s об'їзна %s 9suburb %s проміжна %s simutrans-124.3/simutrans/text/uk/000077500000000000000000000000001474050137200172035ustar00rootroot00000000000000simutrans-124.3/simutrans/text/uk/airtools.txt000066400000000000000000000223311474050137200216010ustar00rootroot00000000000000ÐвіаціÑ

ÐвіаціÑ


Меню авіації міÑтить інÑтрументи Ð´Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ вÑÑ–Ñ… елементів мережі повітрÑного транÑпорту: будівництво та Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ€ÑƒÐ»Ñ–Ð¶Ð½Ð¸Ñ… доріжок Ñ– злітно-поÑадкових Ñмуг; Ñтанцій, терміналів, Ñкладів та вантажних платформ; літакових ангарів та інших будівель. При грі в режимі плину чаÑу можлива поÑва інших можливоÑтей.

ÐатиÑніть на піктограму літака на головній панелі інÑтрументів, щоб відкрити меню авіації.

Затримуючи курÑор миші над будь-Ñкою піктограмою, Ви можете бачити назву об'єкта, ціну ÑпорудженнÑ, вартіÑть обÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ (у круглих дужках) на міÑÑць, макÑимально допуÑтиму швидкіÑть Ñ– макÑимально можливу вагу Ñ‚/з Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ об'єкту (Ñкщо це руліжні доріжки або злітно-поÑадкові Ñмуги).

Підказка: Один з варіантів побудови проÑтого аеропорту:

1) побудуйте злітно-поÑадкову Ñмугу;

2) збоку прибудуйте до неї рубіжну Ñмугу;

3) на вільному кінці руліжної доріжки розміÑтіть аеровокзал або інший вантажно-розвантажувальний термінал;

4) на вільному кінці руліжної доріжки розміÑтіть ангар Ð´Ð»Ñ Ð»Ñ–Ñ‚Ð°ÐºÑ–Ð²;

5) добудуйте інші будівлі, Ñкщо це необхідно.

Меню може ÑкладатиÑÑ Ð· наÑтупних кнопок (зліва направо):

Руліжні доріжки: необхідні Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð»Ñ–Ñ‚Ð°ÐºÑ–Ð² по землі між злітно-поÑадковими Ñмугами, ангарами Ñ– вантажно-розвантажувальними терміналами. Вони будуютьÑÑ Ð½Ð° плоÑкій землі в головному ігровому екрані.

УВÐГÐ: Якщо руліжну доріжку долучити до ÐºÑ–Ð½Ñ†Ñ Ð·Ð»Ñ–Ñ‚Ð½Ð¾-поÑадкової, то літаки не зможуть кориÑтуватиÑÑ Ð·Ð»Ñ–Ñ‚Ð½Ð¾-поÑадковою Ñмугою.

Ð”Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ натиÑніть на відповідну піктограму (курÑор повинен змінити Ñвій виглÑд) Ñ– проÑÑ‚Ñгніть доріжку в потрібному міÑці. У Ñпливному віконці буде вказана вартіÑть будівництва.

Підказка: ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ñ‚Ñ€Ñ–Ð±Ð½Ð¾Ñ— ділÑнки руліжної доріжки. СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтанньої дії [z] не поверне Вам гроші, витрачені на будівництво.

Злітно-поÑадкові Ñмуги (ЗПС): необхідні Ð´Ð»Ñ Ð·Ð»ÑŒÐ¾Ñ‚Ñƒ Ñ– поÑадки літаків. Вони будуютьÑÑ Ð½Ð° плоÑкій землі в головному ігровому екрані Ñ– можуть перетинатиÑÑ.

Ð”Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ натиÑніть на відповідну піктограму (курÑор повинен змінити Ñвій виглÑд) Ñ– проÑÑ‚Ñгніть Ñмугу в потрібному міÑці. У Ñпливному віконці буде вказана вартіÑть будівництва.

Підказка: ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ñ‚Ñ€Ñ–Ð±Ð½Ð¾Ñ— ділÑнки ЗПС. СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтанньої дії [z] не поверне Вам гроші, витрачені на будівництво.

Видалити Ñмугу: видалить ділÑнку руліжної доріжки або злітно-поÑадкової Ñмуги, Ñкщо на них немає літака. ВикориÑтовуйте це Ð´Ð»Ñ Ð²Ñ–Ð´ÑˆÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð°Ñ€Ñ‚Ð¾Ñті Ñпоруди.

Ð”Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½Ð°Ñ‚Ð¸Ñніть на відповідну піктограму (курÑор повинен змінити Ñвій виглÑд), а потім натиÑніть на знищуваний елемент Ñмуги, проÑÑ‚Ñгніть Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´ÐµÐºÑ–Ð»ÑŒÐºÐ¾Ñ… ділÑнок Ñ– відпуÑтіть кнопку миші.

Підказка: Видаливши з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð—ÐŸÐ¡ з аеровокзалом, будьте готові до того, що Ñ†Ñ Ñмуга не зможе відправлÑти/приймати літаки. ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ð´Ð½Ñ–Ñ”Ñ— ділÑнки Ñмуги.

Літакове депо (ангар): необхідне Ð´Ð»Ñ ÐºÑƒÐ¿Ñ–Ð²Ð»Ñ– та ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ Ð»Ñ–Ñ‚Ð°ÐºÐ°Ð¼Ð¸. Їх можна будувати лише на кінцÑÑ… руліжних доріжок. Ðнгари мають щоміÑÑчну вартіÑть обÑлуговуваннÑ.

Ð”Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ натиÑніть на відповідну піктограму (курÑор повинен змінити Ñвій виглÑд) Ñ– побудуйте ангар в потрібному міÑці.

Підказка: ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ñ‚Ñ€Ñ–Ð±Ð½Ð¾Ð³Ð¾ ангара. СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтанньої дії [z] не поверне Вам гроші, витрачені на будівництво.

Ðеровокзали та поÑадкові рукави: потрібні Ð´Ð»Ñ Ð½Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ– Ñ€Ð¾Ð·Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð°Ð½Ñ‚Ð°Ð¶Ñ–Ð² Ñ– паÑажирів у літаки та з них.

Якщо Ви побудуєте будинок не поруч з вже Ñ–Ñнуючою Ñтанцією, то отримаєте нову Ñтанцію.

Їх можна будувати лише на кінцÑÑ… руліжних доріжок. Ðеровокзали та термінали мають щоміÑÑчну вартіÑть обÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð¹ облаÑть Ð¾Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð¹Ð¾Ð¼Ñƒ вантажів Ñ– паÑажирів від навколишніх фабрик Ñ– будівель. Літак приземлитьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸, Ñкщо Ñ” вільний навантажувально-розвантажувальний термінал.

Ð”Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ натиÑніть на відповідну іконку (курÑор повинен змінити Ñвій виглÑд) Ñ– побудуйте будинок в потрібному міÑці поверх руліжної доріжки.

Підказка: ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ñ‚Ñ€Ñ–Ð±Ð½Ð¾Ð³Ð¾ будинку. СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтанньої дії [z] не поверне Вам гроші, витрачені на будівництво.

Інші будівлі: тут перераховані додаткові будівлі, Ñкі розширюють функціонал вже побудованих Ñтанцій: Ð·Ð±Ñ–Ð»ÑŒÑˆÐµÐ½Ð½Ñ Ð¼Ñ–ÑткоÑті Ñкладів, площі охопленнÑ. Вони також можуть мати щоміÑÑчну вартіÑть обÑлуговуваннÑ. Ðа піктограмах таких будинків чаÑто вказуєтьÑÑ, на Ñкі Ð¿ÐµÑ€ÐµÐ²ÐµÐ·ÐµÐ½Ð½Ñ Ð²Ð¾Ð½Ð¸ розраховані (паÑажири, пошта або вантажі).

Ð”Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ натиÑніть відповідну піктограму (курÑор повинен змінити Ñвій виглÑд) Ñ– побудуйте будинок в потрібному міÑці Ð±Ñ–Ð»Ñ Ñ–Ñнуючого аеровокзалу або терміналу.

Підказка: ВикориÑтовуйте інÑтрумент Зруйнувати/Прибрати Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ñ‚Ñ€Ñ–Ð±Ð½Ð¾Ð³Ð¾ будинку. СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ñтанньої дії [z] не поверне Вам гроші, витрачені на будівництво.

simutrans-124.3/simutrans/text/uk/baum_build.txt000066400000000000000000000043711474050137200220540ustar00rootroot00000000000000ПоÑадка дерев

ПоÑадка дерев

Дане меню дозволÑÑ” вам виÑаджувати в грі окремі дерева. Ð¦Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ñ–Ñть ноÑить чиÑто декоративний характер, оÑкільки жодною ді кориÑті від цього немає (крім еÑтетичної).

У лівій чаÑтині предÑтавлений ÑпиÑок вÑÑ–Ñ… Ñ–Ñнуючих в грі дерев, Ñкі можна виÑадити. Дві вкладки Переклад та Об'єкт дозволÑють вибрати варіант Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¾Ð±'єкта - за назвою дерева (Переклад) або по технічному його позначенню (Об'єкт). Оберіть будь-Ñке дерево Ñ– ви побачите більше інформації про нього. Щоб поÑадити дерево доÑить вибрати його в ÑпиÑку Ñ– розміÑтити на ігровій облаÑті екрану.

У правій чаÑтині перераховані кілька параметрів:

Ігнорувати клімат: можливіÑть розÑаджувати дерева в будь-Ñкому кліматі.

Випадковий вік: зазвичай щойно поÑаджене дерево Ñ” Ñаджанцем з нульовим віком. Потім, з плином чаÑу, дерево поÑтупово зроÑтає. Ð¦Ñ ÑƒÑтановка дозволÑÑ” розÑаджувати дерева випадкового віку - від Ñаджанців до Ñтарих великих дерев.

ОбертаннÑ: Ñкщо у графіку дерева доÑтупні кілька варіантів його зовнішнього виглÑду, Ñ†Ñ Ð½Ð°Ñтройка дозволить вибрати, Ñкого Ñаме виглÑду буде розміщений дерево. Можна також вибрати параметр "випадково", щоб зовнішній виглÑд дерева визначавÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÐ¾Ð²Ð¸Ð¼ чином.

simutrans-124.3/simutrans/text/uk/bridges.txt000066400000000000000000000041511474050137200213640ustar00rootroot00000000000000ІнÑтрумент Ð´Ð»Ñ Ð±ÑƒÐ´Ñ–Ð²Ð½Ð¸Ñ†Ñ‚Ð²Ð° моÑту - довідка

Будівництво моÑта

МіÑÑ‚ будуєтьÑÑ Ñ‚Ð°Ðº Ñамо, Ñк Ñ– тунель.

Ðвтодорожній міÑÑ‚

Ви повинні Ñпершу Ñтворити шлÑÑ…, Ñкий з'єднаєтьÑÑ Ð¼Ð¾Ñтом. Обидва шлÑхи повинні точно підходити (розташуватиÑÑ Ð¾Ð´Ð¸Ð½ навпроти іншого). Мишкою виберіть інÑтрумент автомобільний міÑÑ‚. Створіть поÑиланнÑ, натиÑнувши на один з кінців з'єднуваних доріг. МіÑÑ‚ ви можете Ñпорудити навіть так, що один його кінець буде на гірці (до виÑоти 1-це положеннÑ). Якщо трапилоÑÑ, що шлÑÑ… не під'єднаний, Ñпробуйте перетÑгнути шлÑÑ… на одну позицію нижче моÑта.

Залізничний міÑÑ‚

Маєте Ñтворити залізничну колію, Ñку потім з'єднаєте моÑтом. Обидві ділÑнки колії повинні точно підходити (розташуватиÑÑ Ð¾Ð´Ð¸Ð½ навпроти іншого). Мишкою виберіть інÑтрумент залізничний міÑÑ‚. Створіть поÑиланнÑ, натиÑнувши на один з кінців з'єднуваних колій. МіÑÑ‚ з повним дном (без бічних конÑтрукцій) має ту перевагу, що ви можете розміÑтити на ньому Ñемафори. МіÑÑ‚ ви можете Ñпорудити навіть так, що один його кінець буде на гірці (до виÑоти 1-це положеннÑ). Якщо трапилоÑÑ, що ÐºÐ¾Ð»Ñ–Ñ Ð½Ðµ під'єднана, то Ñпробуйте перетÑгнути Ñ—Ñ— на одну позицію нижче моÑта.

simutrans-124.3/simutrans/text/uk/citybuilding_build.txt000066400000000000000000000065661474050137200236260ustar00rootroot00000000000000Будівництво міÑьких будинків

Будівництво міÑьких будинків

Даний інÑтрумент дає можливіÑть будувати міÑькі будівлі в будь-Ñкому міÑці, де Ви захочете. Дана можливіÑть не Ñ” обов'Ñзковою, а більш еÑтетичною.

У лівій чаÑтині предÑтавлений ÑпиÑок вÑÑ–Ñ… доÑтупних міÑьких будівель, Ñкі можна побудувати. Дві вкладки Переклад та Об'єкт дозволÑють вибрати варіант Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¾Ð±'єкта - за назвою будівлі (Переклад) або по технічному його позначенню (Об'єкт). Виберіть Ñку-небудь будівлю Ñ– ви побачите більше інформації про неї. Щоб побудувати будинок, доÑить вибрати його в ÑпиÑку Ñ– розміÑтити на ігровій облаÑті екрану.

У правій чаÑтині перераховані кілька параметрів:

Ігнорувати клімат: можливіÑть будувати будівлі в будь-Ñкому кліматі.

Режим плину чаÑу: показати тільки будівлі, доÑтупні в даний момент чаÑу.

Показати заÑтарілі: показати будівлі, Ñкі були доÑтупні в минулому.

Житлові будівлі: показати тільки будівлі, в Ñких проживають люди. Ці будівлі зазвичай мимовільно будуютьÑÑ, коли міÑто розширюєтьÑÑ Ð¿Ñ€Ð¸ збільшенні наÑеленнÑ.

Магазини та офіÑи: показати тільки комерційні будівлі. Ці будівлі надають робочі міÑÑ†Ñ Ñ– ведуть торгівлю (у тому чиÑлі Ñ– з гравцÑми), вони зазвичай будуютьÑÑ Ð¿Ñ€Ð¸ великій кількоÑті безробітних жителів у міÑті.

ПромиÑлові будівлі: показати тільки фабрики. Ці будівлі надають робочі міÑÑ†Ñ Ñ– ведуть торгівлю (у тому чиÑлі Ñ– з гравцÑми). Однак, в цей ÑпиÑок не входÑть великі промиÑлові фабрики (наприклад, ЕлектроÑÑ‚Ð°Ð½Ñ†Ñ–Ñ Ð°Ð±Ð¾ Вугільна шахта), Ñкі розміщуютьÑÑ Ð·Ð° міÑтом Ñ– з Ñкими Ñпівпрацює гравець.

ОбертаннÑ: Ñкщо у малюнку будівлі доÑтупні кілька варіантів Ñ—Ñ— зовнішнього виглÑду, то Ñ†Ñ ÑƒÑтановка дозволить вибрати, Ñкого Ñаме виглÑду будинок буде розміщений. Можна також вибрати параметр "випадково", щоб зовнішній виглÑд будівлі визначавÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÐ¾Ð²Ð¸Ð¼ чином.

simutrans-124.3/simutrans/text/zh.tab000066400000000000000000001127241474050137200177040ustar00rootroot00000000000000§T. Chinese PROP_FONT_FILE wenquanyi_9pt.bdf ################################################################################ # DO NOT EDIT THIS FILE. # # USE https://translator.simutrans.com FOR YOUR CHANGES # # AND DOWNLOAD THIS FILE AGAIN WITH YOUR SUGGESTIONS # ################################################################################ # # # Simutrans Base Translation File # # Scenario: Base texts # # Language: zh T. Chinese # # Encoding: UTF-8 # # Font: wenquanyi_9pt.bdf # # Date Created: 20.07 2024 # # # ################################################################################ #__________________________________button_text__________________________________ #__________________________________button_text__________________________________ cl_btn_filter_disable ç¦ç”¨ cl_btn_filter_enable 啓用 cl_btn_filter_settings 設置 cl_btn_sort_asc å‡åº cl_btn_sort_desc é™åº cl_btn_sort_id 内部ID cl_btn_sort_income æ”¶å…¥ cl_btn_sort_name å稱 cl_btn_sort_type 類型 clf_btn_alle å…¨é¸ clf_btn_invers åé¸ clf_btn_keine å–æ¶ˆé¸æ“‡ gl_btn_sort_bonus 紅利 gl_btn_sort_name å稱 gl_btn_sort_revenue 收益 gl_btn_unsort æœªæŽ’åº hl_btn_filter_disable ç¦ç”¨ hl_btn_filter_enable 啓用 hl_btn_filter_settings 設置 hl_btn_sort_asc å‡åº hl_btn_sort_desc é™åº hl_btn_sort_name å稱 hl_btn_sort_type 類型 hl_btn_sort_waiting 等候 hlf_btn_alle å…¨é¸ hlf_btn_invers åé¸ hlf_btn_keine å–æ¶ˆé¸æ“‡ Networks 交通網絡 Road toll 路費 Scenario å ´æ™¯ä¿¡æ¯ #_________________________________climates_text_________________________________ #_________________________________climates_text_________________________________ arctic 極地氣候 desert 沙漠氣候 mediterran 地中海氣候 rocky 高山氣候 temperate 溫帶氣候 tropic 熱帶氣候 tundra 苔原氣候 #__________________________________error_text___________________________________ #__________________________________error_text___________________________________ Loading scenario script failed 載入場景腳本失敗 Cannot built depot here! 無法在這裡建造車庫 Cannot built this station/building\nin underground mode here. 該建築ä¸èƒ½å»ºæ–¼åœ°åº• Cannot create generic line!\nSelect line type by\nusing filter tabs. ä¸èƒ½å‰µå»ºã€Œå…¨éƒ¨ã€é¡žåž‹çš„路線\nè«‹é¸æ“‡åˆé©çš„類型,å†å‰µå»ºè·¯ç·š Cannot create socket 未能建立通訊 Convoi handles exhausted! 車輛總數已é”到最大 Convoy already deleted! 車輛已移除! Das Feld gehoert\neinem anderen Spieler\n 該陸地屬於其他玩家 Der Besitzer erlaubt das Entfernen nicht å»ºç¯‰ç‰©æ“æœ‰è€…拒絕移除建築\n汽車或行人在路上,無法移除 Diese Zusammenstellung kann nicht fahren!\n éžæ³•çµ„åˆ Flugzeughalt muss auf\nRunway liegen!\n 飛機必須放置在滑行é“上 Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n 無法在這裡建造飛機場 Hier kann kein\nSignal aufge-\nstellt werden!\n ä¸èƒ½åœ¨é€™è£¡æ”¾ç½®é“路標誌 In order to lock the game, you have to protect the public player by password! 想è¦éŽ–å®šéŠæˆ²ï¼Œå¿…é ˆè¨­ç½®å¯†ç¢¼ä»¥é˜²å…¶ä»–çŽ©å®¶ç¹¼çºŒéŠæˆ² Lost connection\nto server! 與æœå‹™å™¨å¤±åŽ»é€£æŽ¥ Lost synchronisation\nwith server. 與æœå‹™å™¨å¤±åŽ»åŒæ­¥ Maglevhalt muss auf\nMaglevschiene liegen!\n ç£æ‡¸æµ®è»Šç«™å¿…é ˆå»ºé€ åœ¨ç£æ‡¸æµ®è»Œé“上 Monorailhalt muss auf\nMonorail liegen!\n 單軌車站必須建造在單軌軌é“上 Monorails are not available yet! 單軌éµè·¯é‚„ä¸å¯ç”¨ Narrowgaugehalt muss auf\nNarrowgauge liegen!\n 窄軌車站必須建造在窄軌軌é“上 No through station here! 車站必須建造在路的盡頭或é“路直綫段上 Not enough money! 資金ä¸è¶³ On narrowgauge track only!\n åªé©ç”¨æ–¼çª„軌軌é“ï¼\n Only public player can lock games! åªæœ‰å…¬å…±æœå‹™å¯ä»¥éŽ–ä¸ŠéŠæˆ² Post muss neben\nHaltestelle\nliegen!\n 車站擴展建築必須建設在車站或碼頭附近 Protocoll error (expecting game) 傳輸å”定錯誤(等ä¾éŠæˆ²ï¼‰ Schiffhalt muss im\nWasser liegen!\n 輪船åœé é»žåªèƒ½å»ºé€ åœ¨é è¿‘碼頭的水é¢ä¸Š Server busy 伺æœå™¨ç¹å¿™ï¼ Terraforming not possible\nhere in underground view 無法在地底修整地形 Upgrade must have\na higher level éœ€è¦æ›´é«˜ç´šåˆ¥æ‰èƒ½å‡ç´š Zughalt muss auf\nSchiene liegen!\n ç«è»Šè»Šç«™å¿…須建造在éµè·¯è»Œé“上 #___________________________________help_text___________________________________ #___________________________________help_text___________________________________

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s 幫助索引\n關於模擬交通(simutrans)\n\n%1$s\n如何使用\n\n%2$s\nå¦‚ä½•é–‹å§‹éŠæˆ²\n\n%4$s\n如何æ“ä½œéŠæˆ²\n\n%5$s\n\n工具\n%3$s\n其他窗å£\n\n%6$s Keyboard Help\n

Keyboard Help

\n éµç›¤å¹«åŠ©\n

éµç›¤å¹«åŠ©

\n

\néµç›¤å¹«åŠ© 顯示快æ·éµåŠŸèƒ½\n

\n

\néµç›¤å¹«åŠ© ç•¶æŸæœªå®šç¾©å¿«æ·éµæŒ‰ä¸‹æ™‚或從一般幫助打開\n

\n

\nå¿«æ·éµå€åˆ†å¤§å°å¯« (使用[Shift]轉æ›å¤§å°å¯«)\n

\n

\n被引用的éµåŒ…括:\n

\n

\n[æ–¹å‘éµ]: éŠæˆ²åœ°åœ–按其方å‘移動
\n[Backspace]: é—œé–‰éŠæˆ²ç•Œé¢ä¸­æ‰€æœ‰çš„窗å£ã€å·¥å…·æ¬„和幫助文檔
\n[Delete]或[Escape]: é—œé–‰éŠæˆ²ç•Œé¢ä¸­æœ€ä¸Šå±¤çš„窗å£ã€å·¥å…·æ¬„或幫助文檔
\n[Enter]或[Return]: ç¢ºèªæ“作
\n[Page-Up]或[>]: æ”¾å¤§éŠæˆ²åœ°åœ–
\n[Page-Down]或[<]: 縮å°éŠæˆ²åœ°åœ–
\n[F1]: 打開Simutrans幫助

\n

\n[1]: æœå—ç§»å‹•éŠæˆ²åœ°åœ–
\n[2]: æœæ±å—æ–¹å‘ç§»å‹•éŠæˆ²åœ°åœ–
\n[3]: æœæ±ç§»å‹•éŠæˆ²åœ°åœ–
\n[4]: æœè¥¿å—æ–¹å‘ç§»å‹•éŠæˆ²åœ°åœ–
\n[6]: æœæ±åŒ—æ–¹å‘ç§»å‹•éŠæˆ²åœ°åœ–
\n[7]: æœè¥¿ç§»å‹•éŠæˆ²åœ°åœ–
\n[8]: æœè¥¿åŒ—æ–¹å‘ç§»å‹•éŠæˆ²åœ°åœ–
\n[9]: æœåŒ—ç§»å‹•éŠæˆ²åœ°åœ–\n

\n

\n[Shift] + 鼠標: 在地圖中打開工業產業éˆ
\n[CTRL] + 工具: 建設慢速公路ã€éµè»Œæˆ–更直的公路ã€éµè»Œ
\n

#____________________________________ki_text____________________________________ #____________________________________ki_text____________________________________ %s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n %s ç¾åœ¨åœ¨\n%s 和景點 %s(%i,%i)\n之間æä¾›å·´å£«æœå‹™ %s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n %s ç¾åœ¨åœ¨\n%s 和工廠 %s(%i,%i)\n之間æä¾›å·´å£«æœå‹™ %s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). %s ç¾åœ¨é‹ç‡Ÿ %i 貨車往返于\n%s(%i,%i) å’Œ %s (%i,%i) 之間 %s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). %s 在\n%s(%i,%i) å’Œ %s(%i,%i)\nä¹‹é–“é–‹è¨­äº†ä¸€æ¢æ–°éµè·¯ç¶« Airline service by\n%s\nnow between\n%s \nand %s.\n %s ç¾åœ¨åœ¨\n%s å’Œ %s\n之間æä¾›èˆªç©ºæœå‹™ Ferry service by\n%s\nnow between\n%s \nand %s.\n %s ç¾åœ¨åœ¨\n%s å’Œ %s\n之間æä¾›èˆ¹é‹æœå‹™ Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n %s ç¾åœ¨åœ¨\n%s å’Œ %s\nä¹‹é–“é–‹è¨­äº†ä¸€æ¢æ–°å·´å£«ç¶« #___________________________________menu_text___________________________________ #___________________________________menu_text___________________________________ EDITTOOLS 地圖編輯工具 LISTTOOLS åˆ—è¡¨ç®¡ç† MAGLEVTOOLS ç£æ‡¸æµ®éµè·¯å·¥å…· MONORAILTOOLS 單軌/ç£æ‡¸æµ®éµè·¯å·¥å…· NARROWGAUGETOOLS 窄軌éµè·¯å·¥å…· RAILTOOLS éµè·¯å·¥å…· ROADTOOLS é“路工具 SHIPTOOLS 船é‹å·¥å…· SLOPETOOLS 地形工具 SPECIALTOOLS 其他工具 TRAMTOOLS 電車/輕軌工具 #_________________________________message_text__________________________________ #_________________________________message_text__________________________________ %s s\nheadquarter now\nat (%i,%i). %s 興建了一個新總部 Factory chain extended\nfor %s near\n%s built with\n%i factories. ç¶“æ¿Ÿé€æ¼¸ç¹æ¦®\n%s 擴大產業, æ–¼ %s 附近建設了 %i 間工廠 New %s now available:\n%s\n æ–° %s ç¾åœ¨å¯ç”¨:\n%s New factory chain\nfor %s near\n%s built with\n%i factories. 工業發展: %s 新工業éˆ\næ–¼ %s 附近建立了 %i 工廠 New vehicle now available:\n%s\n 新交通工具ç¾åœ¨å¯ç”¨\n\n -- %s -- Now %u clients connected. ç¾åœ¨æœ‰ %u 個用戶已連接 Remove vehicle from map. Use with care! 移除該é‹è¼¸å·¥å…·(è«‹å°å¿ƒä½¿ç”¨!) Screenshot\ngespeichert.\n éŠæˆ²æˆªåœ–å·²ä¿å­˜ Sends the convoi to the last depot it departed from! å°‡é‹è¼¸éšŠèª¿å›žæœ€å¾Œçš„發車庫 With a big festival\n%s built\na new monument.\n%i citicens rejoiced. %s 為æŸç››å¤§çš„節日建立了紀念館\n%i 個市民感到å分高興 #_________________________________program_text__________________________________ #_________________________________program_text__________________________________ (%i)- (%i) (in depot) (在車廠) \nBauzeit bis 直到 \nBauzeit von å‡ºç¾æ–¼ \nCan't open heightfield file.\n 無法使用高度圖 \ndirection: æ–¹å‘ \nelektrified 電氣化 \nHeightfield has wrong image type.\n é«˜åº¦åœ–åœ–åƒæ ¼å¼ä¸æ­£ç¢º \nis reserved by: 已被ç«è»Šä½”用 \nminimum speed: 最低時速: \nnot elektrified 未電氣化 \nRibi (masked) 通行方å‘(å³): \nRibi (unmasked) 通行方å‘(å·¦): \nSet phases: 調節å—北/æ±è¥¿çš„綠燈æŒçºŒç§’數: \nsingle way å–®å‘é“è·¯ \nway1 reserved by é“è·¯1被佔用: \nway2 reserved by é“è·¯2被佔用: \nwith sign/signal\n 標誌/信號 %d buildings\n %d 建築 %d convois %d é‹è¼¸éšŠ %d Einzelfahrzeuge im Depot %d 車輛存放在這 %i km/h (max. %ikm/h) %ikm/h(最高 %ikm/h) %i years %i months old. 樹齡為 %i å¹´ %i 個月 %s at (%i,%i) now public stop. %s å·²æˆç‚ºå…¬å…±é‹è¼¸äº¤åŒ¯è™• %s building %s %s %s %s %s %s city %d %s %s %d %s %s factory %s %s %s %s %s has entered a depot. %s 已回到車庫 %s land %d %s %s %d %s 外 %s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. %s 的居民é”到 %i\n因此興建了一個新市政廳 %s\nis crowded. %s éŽåº¦æ“æ“  %s\nspeed %i\nmax_speed %i\ndx:%i dy:%i %s\n時速 %i\n最高時速 %i\ndx:%i dy:%i %s\nwas liquidated. %s 已清盤 %u Client(s)\n %u 玩家\n %u Player (%u locked)\n %u 個玩家 (%u 個已鎖定)\n <未指定路線> 1 convoi 1 é‹è¼¸éšŠ 1 Einzelfahrzeug im Depot 1輛車存放在這 1LIGHT_CHOOSE 亮度: 1WORLD_CHOOSE æ–°éŠæˆ²çš„設置: 2LIGHT_CHOOSE 顔色: 2WORLD_CHOOSE 地圖編號: 3LIGHT_CHOOSE 鼠標å·å‹•速度: 4LIGHT_CHOOSE 鼠標逆å‘å·å‹• 5LIGHT_CHOOSE 車站的行人 5WORLD_CHOOSE 城市總數: 6LIGHT_CHOOSE 鎮上的行人 6WORLD_CHOOSE 交通密度: 8WORLD_CHOOSE æ—¥å¤œæ¨¡å¼ A bridge must start on a way! 這橋的兩端åªèƒ½å»ºäºŽè‡ªå·±æ“有的平地上且需在一æ¢ç¶«ä¸Š Abfrage 視察工具 Abnehmer 消費者 About 關於 Abriss 摧毀/移除 Absenken é™ä½Žåœ°å½¢ Abspanntransformator 變壓站 Accelerate time åŠ å¿«éŠæˆ²é€Ÿåº¦ Act. load: %u MW\n 實際負è·: %u MW Active player only åƒ…é™æ´»èºçީ家 Add forest 擴大森林 Add random citycar 隨機新增ç§å®¶è»Šè¼› add server 新增æœå‹™å™¨ Add Stop 新建車站 Add stops for backward travel 為回程路段增設車站 aircraft_tab 貨機 airplane 飛機 Airport 機場 AIRTOOLS 航空工具 All 全部 all convoi tooltips 顯示所有交通工具的æç¤º Allow city growth å…許城市增長 Allow player change å…許切æ›çީ家 allowed climates:\n å…許的氣候 Alters a schedule. 調整路線資料 Angenommene Waren 鄰近工廠å¯è¼¸é€çš„物資 anhaengen 添加 Anhaenger_tab 貨車拖架 Anheben æé«˜åœ°å½¢ Appends stops at the end of the schedule 新增車站於路線的末端 Apply Line 應用路線 April 4月 Arbeiter aus: 工人居ä½åœ¨ï¼š Arrived åˆ°é” Assets 資產 Aufloesen 解散 Aufspanntransformator 變壓站 August 8月 Autohalt muss auf\nStrasse liegen!\n 巴士ã€è»Šè¼›åœé ç«™å¿…須建在é“路上 Available å¯ç”¨ Bahndepot éµè·¯è»Šå»  Bankrott:\n\nDu bist bankrott.\n 破產:\n\n你已經破產, éŠæˆ²çµæŸ battery 電池 Baum 樹木 baum builder 栽種樹木 Baustelle 建築中 Bauzeit 建築時間: Beenden çµæŸéŠæˆ² Beginner mode æ–°æ‰‹æ¨¡å¼ Besonderes Gebaeude æ—…éŠæ™¯é»ž BF ç«™ bio 動物 Blockstrecke ist\nbelegt\n \n其他列車正使用此段éµè·¯ã€‚ Boden 陸地 bridge is too high for its type! 無法在這è£å»ºé€ \n因為離地é¢çš„高度超出了其橋腳的高度é™åˆ¶ Bridge is too long for this type!\n æ©‹æ¢è·¨åº¦å¤ªå¤§\nè«‹é¸æ“‡å…¶å®ƒæ©‹æ¢æˆ–分段建造 Bruecke 橋樑 Bruecke muss an\neinfachem\nHang beginnen!\n 這橋必須建在斜å¡ä¸Š Brueckenboden æ©‹æ¢ Build air depot 興建飛機庫 build choosesignals 興建月å°é¸æ“‡ä¿¡è™Ÿ Build city market 在城市附近興建新市場 Build drain 興建變壓站 build HQ 建立總部 Build land consumer 興建發電站 Build maglev depot èˆˆå»ºç£æµ®åˆ—車廠 Build monorail depot 興建單軌列車廠 Build narrowgauge depot 興建窄軌列車廠 Build powerline 興建電纜 Build presignals 架設信號 Build road depot 與建é“路車廠 Build ship depot 與建船廠 Build signals 架設信號 Build train depot 與建éµè·¯è»Šå»  Build tram depot 與建電車車廠 Build truck depot 與建é“路車廠 Building costs estimates é è¨ˆå»ºç¯‰æˆæœ¬ Buildings å»ºç¯‰ç‰©æ•¸é‡ Built artifical slopes èˆˆå»ºäººé€ æ–œå¡ Built random attraction 隨機興建景點 Bus_tab 巴士 Can only move from halt to halt or waypoint to waypoint. åªèƒ½å¾žä¸€å€‹è»Šç«™è½‰ç§»åˆ°å¦ä¸€å€‹è»Šç«™ï¼Œæˆ–從一個途經點轉移到å¦ä¸€å€‹é€”經點。 Cancel å–æ¶ˆ Capacity: %.0f MW 負載é‡ï¼š %.0f MW\n Capacity: %d%s %s\n é‹è¼‰é‡: %3d%s %s Capacity: %s\nLoad: %d (%d%%) 容é‡: %s\n 負載: %d (%d%%) Cars are not available yet! 仿œªå¯è£½é€ è©²è»Šè¼›ã€‚ cars.\nstate 車輛\n Cash ç¾é‡‘ Change player 切æ›çީ家 Chart é‹é€åœ–表 Chat_msg èŠå¤© Choose direction 鏿“‡æ–¹å‘ Choose operation executed on clicking stored/new vehicles 請點擊在庫或新購入的é‹è¼¸å·¥å…·ï¼Œä¸¦é¸æ“‡åŸ·è¡ŒæŒ‡å®šæ“作。 chooses a random map 鏿“‡éš¨æ©Ÿåœ°åœ– citicens å±…ä½é‡ City attraction 市內景點 City industries 城市工業 City list 城市列表 City size åŸŽå¸‚å¤§å° city_road 城市é“è·¯ citybuilding builder 城市建築物工具 CityLimit 城市é™åˆ¶ cl_title 車輛列表 cl_txt_sort 排åºï¼š Clear block reservation 顯示ï¼é‡ç½®ä½”用路段 clf_chk_aircrafts 飛機 clf_chk_cars 巴士/å¡è»Š clf_chk_indepot 在車廠內 clf_chk_maglev ç£æ‡¸æµ®åˆ—車 clf_chk_monorail 單軌éµè·¯ clf_chk_name_filter 篩é¸å™¨å稱: clf_chk_narrowgauge 窄軌éµè·¯ clf_chk_noincome ç„¡æ”¶å…¥ clf_chk_noline 無指定路線 clf_chk_noroute ç„¡é©ç•¶è·¯ç·š clf_chk_noschedule 無行程表 clf_chk_ships 船 clf_chk_spezial_filter 特殊篩é¸å™¨ï¼š clf_chk_stucked å›°ä½ clf_chk_trains 列車 clf_chk_trams 電車 clf_chk_type_filter 類別: clf_chk_waren 物資: clf_title 車輛/船隻清單分類 Climate Control 氣候/地形控制 closed 欄截 COLOR_CHOOSE\n è«‹é¸æ“‡é–£ä¸‹çš„色系。\n Company bankrupt 您的公å¸å·²ç¶“ç ´ç”¢ï¼ Company_msg ç«¶çˆ­å°æ‰‹ Comparing pak files ... 正在比å°éŠæˆ²è³‡æ–™æª”案... Congratulation\nScenario was complete in\n%i months %i years. æ­å–œ!\næ­·ç¶“ %i 月 %i å¹´, æ­¤éŠæˆ²å ´æ™¯å·²å®Œæˆ! Connected stops å¯ä¾›ä½¿ç”¨çš„站: Connected with server 已連接到伺æœå™¨ Constructed by 繪畫者: Constructed by %s 繪畫者:%s Construction_Btn 建設開支 convoi %d of %d é‹è¼¸å·¥å…· %d / %d convoi error tooltips 顯示交通工具的錯誤æç¤º Convoi has been sent\nto the nearest depot\nof appropriate type.\n 該é‹è¼¸å·¥å…·å·²å¬å›ž\n至鄰近åˆé©å» æˆ¿ã€‚ Convoi is sold when all wagons are empty. 所有拖架空載時,é‹è¼¸å·¥å…·å°‡æœƒå”®å‡ºã€‚ convoi mouseover tooltips 滑鼠指標下的交通工具顯示æç¤º convoi passed last\nmonth %i\n \n上月æµé‡ï¼š %i\n Convois 交通工具 Convois: %d\nProfit: %s 車輛:%d\n利潤:%s Convoys é‹è¼¸å·¥å…· Copy Convoi è¤‡è£½ç·¨æˆ Copy the selected convoi and its schedule or line é‡è¤‡è³¼è²·æ‰€é¸é‹è¼¸å·¥å…·ä¸¦è¤‡è£½è·¯ç·šè³‡æ–™ã€‚ cost for removal 清除費用 Costs æˆæœ¬ Create a new line based on this schedule 開設基於此路線資料的新路線。 curiosity builder 景點建設工具 curlist_title 景點列表 Currently playing: 進行中: Customers live in: ä¹˜å®¢å±…ä½æ–¼: deactivated in online mode ä¸é©ç”¨æ–¼é€£ç·šéŠæˆ² Deccelerate time æ¸›æ…¢éŠæˆ²é€Ÿåº¦ December 12月 decrease underground view level å°‡åˆ‡é¢æŽ¨è½ä¸€å±¤ Del Stop 刪除 Delete Line 刪除路線 Delete the current stop 清除此站 Delete this file. 刪除此檔案 Demand: %.0f MW 需求: %.0f MW\n Denkmal å¤è¹Ÿ Departed 已出發 Depots 車廠 Der Tunnel ist nicht frei!\n éš§é“内仿œ‰è»Šè¼›åœ¨è¡Œé§› Destination åˆ°é” Destroying map ... 正在刪除地圖... Details 詳情 Die Bruecke ist nicht frei!\n 橋上存在其他玩家的所有物 diesel 柴油 Direkt erreichbare Haltestellen 從這裡開始的直é”路綫 disable midi 關閉背景音樂 Display settings 顯示設置 Distance 行走è·é›¢ Dock 碼頭 Dock must be built on single slope! 碼頭åªèƒ½å»ºç¯‰åœ¨æ²¿æµ·å–®é¢æ–œå¡ä¸Š Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen 僅餘 %d 個月還清債務 Durchsatz 最大 Economy 經濟åŠåŸŽå¸‚ Eigenbesitz\n 公共財產 Ein %s\npasst hier nicht.\n 空間ä¸è¶³, 無法建造 %s Einstellungen aendern 變更é¸é … electric é›» Electricity 電力 Electricity producer\n\n 電力供應商 Electrics_tab 電氣化 Electrify track 電氣化路軌 enlarge map 擴大地圖 enter a value between %i and %i 請輸入介乎於%i與%i之間的數值 Enter address 請輸入地å€: Enter Password 更改玩家å稱åŠå¯†ç¢¼ Error 錯誤 Erzeuge neue Karte.\n 新地圖創建中, è«‹ç¨å€™\n(大地圖耗時會ç¨ä¹…一些) Es wird bereits\nein Fahrplan\neingegeben\n 正在安排車輛計劃表\nè«‹åœ¨é‡æ–°å®‰æŽ’å‰å…ˆå®Œæˆè¨­å®š Fabrikanschluss 相關廠商 Fabrikname 工廠å稱 Factories 工廠 factory details 工廠詳情 factorybuilder 工廠工具 Fahrplan 車輛計劃表 Fahrtziel 目的地: Fahrzeuge koennen so nicht entfernt werden éžæ³•移除é‹è¼¸å·¥å…· Fahrzeuge: 車å¡ï¼š Farbe 玩家顔色 Fast forward 快速進行 February 2月 Ferry_tab 渡輪 Fertig å·²å®Œæˆ Filename 檔案å Filter: 篩é¸ï¼š Finances of %s %s 的資產 Finanzen 資產 find mismatch 比å°éŠæˆ²è³‡æ–™æª” fl_title 工廠列表 Flug_tab 客機 follow me 跟隨 Follow the convoi on the map. 在地圖上跟隨 Forest 森林 Found new city 開發新城市 Fracht 貨物 Frame time: 幀時 Free Capacity ç©ºè¼‰é‡ freeplay mode è‡ªç”±æ¨¡å¼ Friction: ç•¶å‰æ‘©æ“¦ä¿‚數 fuel_cell 燃料箱 Full load 最å°è² è¼‰ Fundament 地基 Fussgaenger 行人 Game info éŠæˆ²è³‡æ–™ GAME PAUSED éŠæˆ²å·²æš«åœ Game_msg 一般 Gear: 齒輪 Gebaeude 建築 General 一般 Generation: %.0f MW 發電é‡: %.0f MW\n Gewicht é‡é‡ Gewinn æ”¶å…¥ Give the selected vehicle(s) an individual schedule 給所é¸çš„車輛制定ç¨ç«‹çš„車輛計劃表 gl_btn_sort_catg 類別 gl_title 商å“列表 go home 回車庫 Goods 貨物 Goods AI 電腦玩家ï¼è²¨é‹ Goods list 貨物清單 Gross Profit 資金æµå‹• Groundobj 目标 Grow city 發展城市 Growth 城市發展 H 車站 Hangar 飛機庫 Happy 高興 Haus kaufen 購買房屋 Helligk. 顯示 Help 幫助 Help text not found 幫助文檔ä¸å­˜åœ¨ hide all building éš±è—æ‰€æœ‰å»ºç¯‰ hide city building éš±è—城市建築 hide station names éš±è—車站å稱 hide transparent 逿˜ŽåŒ–éš±è—建築 hide trees éš±è—æ¨¹æœ¨ Hier warten/lagern: å¾…é‹ä¹˜å®¢/貨物 Higher transport fees, crossconnect all factories æé«˜é‹è¼¸è²»ç”¨, é—œé–‰åŠæ™‚制度 hl_title 車站列表 hl_txt_filter 分類: hl_txt_sort æŽ’åºæ–¹æ³• hlf_chk_airport 機場 hlf_chk_anleger 碼頭 hlf_chk_bahnhof éµè·¯è»Šç«™ hlf_chk_bushalt 巴士站 hlf_chk_frachthof 上è½å®¢è²¨å€ hlf_chk_keine_verb 未連接 hlf_chk_maglevstop ç£æµ®åˆ—車站 hlf_chk_monorailstop 單軌éµè·¯è»Šç«™ hlf_chk_name_filter å稱: hlf_chk_narrowgaugestop 窄軌éµè·¯è»Šç«™ hlf_chk_overflow 容é‡è¶…è· hlf_chk_spezial_filter 特別: hlf_chk_tramstop 電車站 hlf_chk_type_filter 類別: hlf_chk_waren_abgabe 生產: hlf_chk_waren_annahme 物資 hlf_title è»Šç«™åˆ—è¡¨ç¯©é¸ Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. 找ä¸åˆ°è»Šåº«\n請手動設置車輛行程表令其回到車庫 Homeless æµæµªè€… hydrogene æ°«æ°£ Idle: 空閒 ignore climates 忽略氣候é™åˆ¶ Increase Industry density 增加工業 increase underground view level å°‡åˆ‡é¢æŽ¨ä¸Šä¸€å±¤ industrial building 工業建築 Init map ... åˆå§‹åŒ–地圖中... Input 原料 Ins Stop æ’å…¥ Insert stop before the current stop 在此車站å‰å¢žåŠ è»Šç«™ Intercity road len: 城市é“路長度 Intro. date: 開發日期 invalid 未定義 Invalid coordinate 指令無效 isometric map ç­‰è·è¦–圖 January 1月 join game é€£ç·šéŠæˆ² July 7月 Jump to 跳至 June 6月 Kann Spielstand\nnicht laden.\n ç„¡æ³•è¼‰å…¥å­˜å„²çš„éŠæˆ² Kann Spielstand\nnicht speichern.\n 無法打開目標文件 Kein Besitzer\n 無物主 keine 沒有 Keine Einzelfahrzeuge im Depot 無車輛åœç•™åœ¨æ­¤ Keyboard_Help\n å¿«æ·é”®å¸®åŠ© koord 座標 Kreuzung åå­—è·¯å£ labellist_title 玩家標記列表 Lade Relief 載入高度圖 Laden 載入 Land attraction 郊外景點 Land industries å·¥æ¥­éˆ LANG_CHOOSE\n è«‹é¸æ“‡ç•Œé¢èªžè¨€ LARGE_NUMBER_STRING å„„ LARGE_NUMBER_VALUE 百万 Last Year 上年度 Leaving depot! æ­£é›¢é–‹è»Šå» ï¼ leer 空的 Legend 圖例 Leistung 功率 Leistung: %d kW 功率: %d kW Leitung 電線 letzen Monat: diesen Monat: 上月 本月 Line 路線 Line Management è·¯ç·šç®¡ç† Lineless convoys serving this stop 途經本站的車輛 Lines serving this stop 途經本站的路線 LKW_tab 貨車 Load game è¼‰å…¥éŠæˆ² load height data from file 從文檔載入高度圖 Load scenario 載入場景 loaded 承載 loaded passenger/freight 排列乘客/貨é‹,按 Loading (%i->%i%%)! 載入中 (%i->%i%%) Loading addon paks ... æ­£åœ¨è¼‰å…¥é™„åŠ çš„éŠæˆ²è³‡æ–™æª”... Loading map ... 載入地圖中... Loading paks ... æ­£åœ¨è¼‰å…¥éŠæˆ²è³‡æ–™æª”... Loading skins ... 正在載入樣å¼... Lock game ç¦æ­¢åˆ‡æ›çީ家 (需確èª) Lokomotive_tab 機車 m3 立方米 Maglev ç£æµ®éµè·¯ maglev vehicle ç£æµ®éµè·¯è»Šè¼› maglev_track ç£æµ®è·¯è»Œ Maglevdepot ç£æµ®åˆ—車廠 Mail Demand %d\n é‹éƒµéœ€æ±‚ %d\n Mailbox 消æ¯ä¸­å¿ƒ Mailbox Options 消æ¯ä¸­å¿ƒé¸é … Maintenance ç¶­ä¿® make stop public (or join with public stop next) costs %i per tile and level 公有化車站(或與鄰接的公共車站åˆä½µï¼‰æ¯æ ¼æ¯ç­‰ç´šçš„æˆæœ¬ç‚º$%i Manual (Human) 人類玩家 Manufactured: 製造商 Map roughness 地圖粗糙度 map zoom 縮放 March 3月 Margin (%%) 利潤 Marker 設定標記 max 最高 Max income: 最高收入 Max. speed: 最高速度: Maximum 254 stops\nin a schedule!\n 一個車輛計劃表最多能容ç´254個途徑點 maximum length of rivers æ²³æµæœ€é•·é•·åº¦ Maximum tile height difference reached. 兩個地形格之間的高度差已é”到最大 May 5月 Median Citizen per town 城市人å£ä¸­ä½æ•¸ Meldung æ¶ˆæ¯ Menge 總數 MessageOptionsText \n新年度\n\n玩家消æ¯\n\n城市消æ¯\n\n沒有路線\n\n新目標\n\nèŠå¤©\n\n新車輛\n\n車站爆滿\n\nå•題\n\näº¤é€šæ“æ“  min 最低 minimum length of rivers æ²³æµæœ€çŸ­é•·åº¦ Modify the selected line 修改所é¸è·¯ç·š Monate alt 個月 Monorail 單軌éµè·¯ monorail vehicle 單軌列車 monorail_track 單軌路軌 Monorailboden 高架é“è·¯ Monoraildepot 單軌列車廠 month wait time 最大等候時間(月) Months 月 Monument 紀念碑 Monuments 紀念碑 Mountain height 山勢高度: Movingobj 移動物體 Music playing disabled/not available 背景音樂æ„外中止播放。 Music volume: 背景音樂音é‡ï¼š mute sound éœéŸ³ Name 城市å稱 Narrowgauge 窄軌 Narrowgauge are not available yet! 窄軌éµè·¯é‚„ä¸å¯ç”¨ narrowgauge vehicle 窄軌éµè·¯è»Šè¼› narrowgauge_track 窄軌éµè·¯ Narrowgaugedepot 窄軌éµè·¯è»Šå»  Net ID: %p 電網編號: %p\n Net Wealth 總資產 Neue Karte 新地圖 Neue Welt 建立新地圖 new convoi 購入é‹è¼¸å·¥å…· New Line 開設路線 New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. 已開設新路線ï¼\nè«‹åœ¨è·¯ç·šåˆ—è¡¨ä¸­é¸æ“‡è©²è·¯ç·šï¼Œ\n並修改路線資料。 New Vehicles 購車開支 no buildings hidden 顯示所有建築 no convois ç„¡é‹è¼¸å·¥å…· No goods are loaded onto this convoi. é‹è¼¸éšŠç„¡è¼‰è²¨ no goods waiting 沒有貨物等候 no load å–æ¶ˆæ‰¿è¼‰ No Route 無路線 No stop here! 此工具åªèƒ½æ‡‰ç”¨æ–¼è»Šç«™ No suitable ground! 地點ä¸åˆé©ï¼ No terminal station here! ä¸èƒ½åœ¨æ­¤å»ºè¨­ç¸½ç«™ï¼è«‹æª¢æŸ¥å»º\n設地點是å¦åœ¨å°æ‡‰è·¯è»Œæˆ–éµè·¯\n的末端。 no timeline ä¸ä½¿ç”¨æ™‚間軸 no tree 沒有樹林 Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n "我該去哪è£?"\n在派出車輛å‰ï¼Œå¿…須先給其制定行程表或者安排到已有的行程表 none ç„¡ nord 北 nordost æ±åŒ— nordwest 西北 Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! 尋找路綫期間,無法修改車輛路線表 Not enough fields would remain. 此農場é ç•™ç©ºé–“ä¸è¶³ November 11月 Now active as %s.\n ç•¶å‰çŽ©å®¶ç‚º%s\n Number of rivers æ²³æµæ•¸é‡ Object 物件 Odometer: %s km 里程計: %s 公里 Ok 確定 Oktober 10月 On loan since %i month(s) 負債狀æ³å·²ç¶“ç¶­æŒäº†%i個月 On this map, you are not\nallowed to change player!\n éŠæˆ²å·²éŽ–å®š, 無法切æ›çީ家\n Only city chains åªé¡¯ç¤ºåŸŽå¸‚çš„å·¥æ¥­éˆ Only first %d differing paks reported. There are probably more. åªé¡¯ç¤ºé¦–%d個ä¸ç›¸åŒçš„éŠæˆ²è³‡æ–™æª”。å¯èƒ½æœƒæœ‰æ›´å¤šã€‚ Only land chains åªé¡¯ç¤ºéƒŠå¤–çš„å·¥æ¥­éˆ Only one transformer per factory! 一間工廠åªèƒ½è¨­ç½®ä¸€å€‹è®Šå£“器 open 通行 Operation é‹ç‡Ÿè²»ç”¨ Ops Profit é‹ç‡Ÿåˆ©æ½¤ Optionen é¸é … Origin 出發地 ost æ± Output 輸出 Pak(s) different: ä¸ç›¸åŒçš„éŠæˆ²è³‡æ–™æª”: Pak(s) missing on client: ç”¨æˆ¶ç«¯æ‰€æ¬ ç¼ºçš„éŠæˆ²è³‡æ–™æª”: Pak(s) not on server: 伺æœå™¨ä¸Šæ‰€æ²’æœ‰çš„éŠæˆ²è³‡æ–™æª”: Pakset differences éŠæˆ²è³‡æ–™é›†ä¹‹é–“的差別 paletten 貨箱 Pas_tab 客é‹ç«è»Š Passagiere 乘客 Passagierrate ä¹˜å®¢é‡ Passagierziele 乘客/郵件目的地 Passenger AI 電腦玩家ï¼å®¢é‹ Passengers %d %c, %d %c, %d no route 乘客 %d %c, %d %c, %d 無路綫 Passengers %d %s, %d %s, %d no route 乘客 %d %s, %d %s, %d 無路綫 Password 密碼 Pause æš«åœ PaxDest 目的地 Percent Electricity 供電率(%%需求) Planes are not available yet! 飛機還ä¸å¯ç”¨ Plant tree ç¨®æ¤æ¨¹æœ¨ player 玩家 player -1 人 player 0 公共æœå‹™ player 1 Napik 128 AS player 10 玩家10 player 11 玩家11 player 12 玩家12 player 13 玩家13 player 2 Trikky Transport player 3 Meyer Moving Co. player 4 貨é‹ä»£ç†äºº VM player 5 H-Transå…¬å¸ player 6 PSK & Co KG player 7 玩家7 player 8 玩家8 player 9 玩家9 Please choose vehicles first\n è«‹å…ˆé¸æ“‡è»Šè¼› Post 郵件 Postrate éƒµä»¶é‡ Power 電力 Power: 功率 Powerlines 電纜 Problems_msg å•題 Production of %s has been stopped:\n%s\n %s å·²åœç”¢\n%s Produktion 生產 Profit 利潤 promote to line 改進路綫 q1 春季 q2 å¤å­£ q3 ç§‹å­£ q4 冬季 rail car ç«è»Š random 隨機 Random age 隨機樹齡 Random map 隨機地圖 Rathaus 市政府 Rating 評價 ratio_pax 乘客é‹è¼‰çއ(%%) Reliefkarte 地圖 Remove 移除標簽 remove airstrips 拆除飛機跑é“å’Œæ»‘è¡Œé“ remove channels ç§»é™¤é‹æ²³ remove interm. signals 拆除中間的信號 remove maglev tracks æ‹†é™¤ç£æµ®è·¯è»Œ remove monorails 拆除單軌éµè·¯ remove narrowgauge tracks 拆除窄軌éµè·¯ remove powerlines 拆除電纜 remove roads 拆除é“è·¯ remove tracks 拆除路軌 Remove wayobj %s 拆除é“è·¯ %s replace other signals ç½®æ›å…¶ä»–標誌 replace stop æ›´æ›è»Šç«™ request closing 請求拒絕 residential house 居民房 Restore natural slope é‚„åŽŸåŽŸä¾†çš„æ–œå¡ Restwert: 轉售價格 Retire. date: 退休日期 return ticket 複製此回程 Revenue æ”¶å…¥ Revision: 修正 road é“è·¯ road vehicle é“路車輛 Roadsign 路牌 Rotate map 旋轉地圖 Rotation 旋轉 Routing 尋找路線中 sack 袋 sail 風 Saving map ... 地圖存儲中... Scenario complete: %i%% 場景已完æˆï¼š %i%% Schedule changing! æ­£åœ¨æ›´æ–°è·¯ç·šè¡¨ï¼ Schienentunnel 建造éµè·¯éš§é“ Schiff_tab 船 Schiffdepot 造船廠 Schleppkahn_tab é§èˆ¹ Screenshot 截圖 Seasons 季節 Sehenswuerdigkeit æ—…éŠå‹åœ° Sell the selected vehicle(s) 賣出所é¸è»Šè¼› sended éƒµä»¶å·²ç™¼é€ SEP_FRACTION . SEP_THOUSAND , SEP_THOUSAND_EXPONENT 3 September 9月 Server did not respond! æœå‹™å™¨ç„¡å›žæ‡‰ Serves Line: æœå‹™è·¯ç·šï¼š Service æœå‹™ set signal spacing è¨­å®šä¿¡è™Ÿé–“è· Setting 設置 Ship 船 shops and stores 商店和辦公樓 Show all 全部顯示 show all building 顯示所有建築 Show also vehicles no longer in production. åŒæ™‚顯示ä¸å†ç”Ÿç”¢çš„車輛 Show also vehicles that do not match for current action. åŒæ™‚顯示ä¸ç¬¦åˆæ‰€é¸æŒ‡ä»¤çš„車輛 Show even servers with wrong version or pakset åŒæ™‚é¡¯ç¤ºä½¿ç”¨éŒ¯èª¤éŠæˆ²ç‰ˆæœ¬æˆ–資料集的æœå‹™å™¨ show grid 顯示網格 Show industry 顯示工業 Show legend 顯示圖例 Show map scale 顯示地圖比例 Show obsolete 顯示已淘汰的 Show schedules 顯示路綫表 show station coverage 顯示車站æœå‹™ç¯„åœ show station names 顯示車站å稱 show waiting bars 顯示等候圖表 Show/hide statistics 顯示/éš±è—æ•¸æ“šçµ±è¨ˆ Shows consumer/suppliers for factories 顯示工廠的客戶和供應商 Shows the currently selected schedule é¡¯ç¤ºç•¶å‰æ‰€é¸çš„路綫表 Shrink city 縮å°åŸŽå¸‚ shuffle midis 隨機音樂 Signal 信號 signal spacing ä¿¡è™Ÿé–“è· Sim: 模擬週期 Size (%d MB): å¤§å° (%d MB): sliced underground mode 切é¢åœ°åœ–æ¨¡å¼ slot empty 尚未使用 Sort by 排列按 Sort waiting list by 排列等候列表,按 Sound 音效 Sound settings 音效設置 Sound volume: éŸ³æ•ˆéŸ³é‡ special freight 特殊貨物 Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. 速度加æˆ\né“è·¯ %i km/h éµè·¯ %i km/h\nèˆ¹é‹ %i km/h ç©ºé‹ %i km/h Speedlimit 速度é™åˆ¶ Speichern ä¿å­˜ Spieler 玩家 Spieler(mz) 玩家 Spielerliste 玩家列表 Spielstand wurde\ngeladen!\n éŠæˆ²è¼‰å…¥æˆåŠŸ Spielstand wurde\ngespeichert!\n éŠæˆ²å­˜å„²æˆåŠŸ Sprache 語言 Sprachen 語言 Stadtinformation 城市統計數據 Start é–‹å§‹ Start the selected vehicle(s) æ´¾é£æ‰€é¸è»Šè¼› Starte Spiel é–‹å§‹éŠæˆ² Station tiles: 車站長度: Station_msg 車站 Status 車站狀態 steam 蒸汽 Step timeline one year 跳至下一年 Stops 車站 Storage capacity å®¹é‡ Strassendepot 車庫 Strassentunnel å»ºé€ è¡Œè»Šéš§é“ street car 電車 sued å— suedost æ±å— suedwest è¥¿å— Summer snowline å¤å­£é›ªç¶« Suppliers 供應商 Tage alt 天 There are still vehicles\nstored in this depot!\n 車廠内還有車輛ï¼\n This Month 本月 This Year 本年度 Tile not empty. 在使用斜å¡å·¥å…·å‰, 請先清除地é¢ç‰©ä»¶ timeline éµå¾žæ™‚代 tl_title 城市列表 To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. %s 爲了å¸å¼•更多的旅客\n興建了 %s\n(在 %i ç´ç¨…人的支æŒä¸‹) To heavy traffic\nresults in traffic jam.\n äº¤é€šéŽæ–¼ç¹å¿™å°Žè‡´äº¤é€šé˜»å¡ž Toggle day/night view åˆ‡æ›æ—¥/夜視圖 Toggle vehicle tooltips 切æ›è»Šè¼›å·¥å…·æç¤º tonnen 噸 Total inhabitants: 居民總數 Tourist attractions æ—…éŠæ™¯é»ž Tourists 景點 Town_msg 新目的地 Town: %s\n %s 市 Towns 城市 track 路轨 Tracks 路軌 Traffic 交通 Train ç«è»Š Trains are not available yet! ç«è»Šé‚„ä¸å¯ç”¨ Tram 電車 tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. 電車 %i km/h, 單軌列車 %i km/h\nç£æ‡¸æµ®åˆ—車 %i km/h, 窄軌列車 %i km/h tram_track 電車路軌 Tramdepot 電車車庫 Trams are not available yet! 電車還未å¯ä½¿ç”¨ Transferring game ... 正在傳é€éŠæˆ²... Transformer only next to factory! 變壓站必須建造在與工廠毗連的平å¦ç©ºåœ°ä¸Š Translation 翻譯 transparent station coverage 逿˜Žé¡¯ç¤ºè»Šç«™è¦†è“‹ç¯„åœ Transported 路程 TrolleyBus_tab 無軌電車 Truck 貨車 Tunnel muss an\neinfachem\nHang beginnen!\n éš§é“å…¥å£å¿…須建造在斜å¡ä¸Š Tunnel must start on single way! éš§é“å…¥å£å¿…須連接é“路或éµè·¯ Tunnelboden éš§é“ underground mode åœ°åº•æ¨¡å¼ UNDO failed! 無法撤銷上次æ“作\n僅當æŸè·¯æ®µä¸Šæ²’有信號標誌ã€è»Šç«™æˆ–其他建築物時, æ‰èƒ½ä½¿ç”¨æ’¤éŠ·é“路建設æ“作 Undo last ways construction å–æ¶ˆä¸Šæ¬¡é“路建設 Unemployed 失業 Unhappy ä¸é«˜èˆˆ units/day ä»¶/月 Update Line 更新路綫 upgrade HQ å‡ç´šç¸½éƒ¨ Usage: %.0f %% 使用率: %.0f %% Use beginner mode æ­£åœ¨ä½¿ç”¨æ–°æ‰‹æ¨¡å¼ Use timeline start year 使用時間軸: 从 Vehicle %s can't find a route! 車輛 %s 無法找到路綫 Vehicle %s is stucked! 車輛 %s 被å¡ä½äº† Vehicle details 車輛詳情 Verbrauch æ¶ˆè€—é‡ Vergroessere die Karte\n 擴大地圖 verkaufen è²©å”®æ¨¡å¼ Verkehrsteilnehmer 城市車輛 Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n 僅餘 %d 個月還清債務 via 途經站(細節) via %s\n 途經 %s\n via Menge 途經站(數é‡) voranstellen å‰ç½® Waggon_tab 車輛 waiting 等待中 Waiting for clearance! 等待清ç†ä¸­ Warnings_msg äº¤é€šç‹€æ³ Wasser æ°´ Water 鋿²³ Water level æ°´å¹³é¢ water vehicle 船隻 way %s cannot longer used:\n 無法å†å»ºé€  %s è·¯ way %s cannot longer used:\n%s\n 無法å†å»ºé€  %s è·¯ way %s now available:\n ç¾åœ¨å¯ç”¨%s 路了\n Ways not connected é“路未連接 Wegpunkt 途經點 Wert 價格 west 西 Winter snowline 冬季雪綫 withdraw 撤消 Withdraw All 全部撤消 WRONGSAVE 檔案å¯èƒ½å·²æå£ž, ç„¡æ³•è¼‰å…¥éŠæˆ² Year %i has started. %i 年己開始 Years å¹´ Zielort 目的地 zooming in 放大 zooming out ç¸®å° Zu nah am Kartenrand éŽæ–¼é è¿‘地圖邊緣, 無法建造 #__________________________________record_text__________________________________ #__________________________________record_text__________________________________ New world record for maglevs: %.1f km/h by %s. %2$s åˆ›é€ äº†æ–°ç£æ‚¬æµ®åˆ—车世界紀錄: %1$.1f km/h New world record for monorails: %.1f km/h by %s. %2$s 创造了新單軌世界紀錄: %1$.1f km/h New world record for motorcars: %.1f km/h by %s. %2$s 创造了新車輛世界紀錄: %1$.1f km/h New world record for narrowgauges: %.1f km/h by %s. %2$s 创造了新窄軌世界紀錄: %1$.1f km/h New world record for planes: %.1f km/h by %s. %2$s 创造了新航空世界紀錄: %1$.1f km/h New world record for railways: %.1f km/h by %s. %2$s 创造了新éµè·¯ä¸–界紀錄: %1$.1f km/h New world record for ship: %.1f km/h by %s. %2$s å‰µé€ äº†èˆ¹é‹æ–°ä¸–界紀錄:\n%1$.1f km/h #_______________________________unnecessary_text________________________________ #_______________________________unnecessary_text________________________________ &0_CITY_SYLL 油繩 &1_CITY_SYLL 切斯特 &2_CITY_SYLL 噸 &3_CITY_SYLL 市 &4_CITY_SYLL 集èšåœ° &5_CITY_SYLL è¡Œæ”¿å€ &6_CITY_SYLL ç«è…¿ &7_CITY_SYLL 域 &8_CITY_SYLL å£ &9_CITY_SYLL 鎖 &A_CITY_SYLL ç©¿éŽ &B_CITY_SYLL ç”± &C_CITY_SYLL åŸ‹è— &D_CITY_SYLL 用處 &E_CITY_SYLL 井 %0_CITY_SYLL æ¾æ¨¹ %1_CITY_SYLL è‰¾åª %2_CITY_SYLL 馬利 %3_CITY_SYLL æ«» %4_CITY_SYLL 泉 %5_CITY_SYLL å¤§é¸ %6_CITY_SYLL å·´éˆ %7_CITY_SYLL 赫普 %8_CITY_SYLL 布倫特 %9_CITY_SYLL 仿© %A_CITY_SYLL 舊 %B_CITY_SYLL 山丘 %C_CITY_SYLL æ–° %D_CITY_SYLL 岩山 %E_CITY_SYLL 沃尔 %F_CITY_SYLL 橡樹 0center ä¸å­˜åœ¨! 0extern ä¸å­˜åœ¨! 0suburb ä¸å­˜åœ¨ 1center %s %s 1extern %s 分支 %s 1suburb %s %s %s 2center %s 中心 %s 2extern %s 外 %s 2suburb %s è‰åœ° %s %s 3center %s 主 %s 3extern %s 土地 %s 3suburb %s æ‘莊 %s %s 4center %s 里 %s 4extern %s å¤–åœ %s 4suburb %s è¾²æ‘ %s 5center %s 市中心 %s 5extern %s è½¬æ¢ %s 5suburb %s 鎮 %s 6center %s中繼%s 6extern %s äº¤æ› %s 6suburb %s 郊外 %s %s 7center %s 城市 %s 7extern %s 平原 %s 7suburb %s 公園 %s 8center %s 商业 %s 8extern %s %s 邊 %s 8suburb %s 衛星 %s 9center %s 軸 %s 9extern %s æ—é“ %s 9suburb %s 中部 %s Acenter ä¸å­˜åœ¨ Aextern ä¸å­˜åœ¨ Asuburb ä¸å­˜åœ¨ Bcenter ä¸å­˜åœ¨ Bextern ä¸å­˜åœ¨ Bsuburb ä¸å­˜åœ¨ Ccenter ä¸å­˜åœ¨ Cextern ä¸å­˜åœ¨ Csuburb ä¸å­˜åœ¨! Dcenter ä¸å­˜åœ¨ Dextern ä¸å­˜åœ¨ Dsuburb ä¸å­˜åœ¨ Ecenter ä¸å­˜åœ¨ Eextern ä¸å­˜åœ¨ Esuburb ä¸å­˜åœ¨ Fcenter ä¸å­˜åœ¨ Fextern ä¸å­˜åœ¨ Fsuburb ä¸å­˜åœ¨ Gcenter ä¸å­˜åœ¨ Gextern ä¸å­˜åœ¨ Gsuburb ä¸å­˜åœ¨ Hcenter ä¸å­˜åœ¨ Hextern ä¸å­˜åœ¨ Hsuburb ä¸å­˜åœ¨ Icenter ä¸å­˜åœ¨ Iextern ä¸å­˜åœ¨ Isuburb ä¸å­˜åœ¨ Jcenter ä¸å­˜åœ¨ Jextern ä¸å­˜åœ¨ Jsuburb ä¸å­˜åœ¨ Kcenter ä¸å­˜åœ¨ Kextern ä¸å­˜åœ¨ Ksuburb ä¸å­˜åœ¨ Lcenter ä¸å­˜åœ¨ Lextern ä¸å­˜åœ¨ Lsuburb ä¸å­˜åœ¨ Mcenter ä¸å­˜åœ¨ Mextern ä¸å­˜åœ¨ Msuburb ä¸å­˜åœ¨ Ncenter ä¸å­˜åœ¨ Nextern ä¸å­˜åœ¨ Nsuburb ä¸å­˜åœ¨ Ocenter ä¸å­˜åœ¨ Oextern ä¸å­˜åœ¨ Osuburb ä¸å­˜åœ¨ Pcenter ä¸å­˜åœ¨ Pextern ä¸å­˜åœ¨ Psuburb ä¸å­˜åœ¨ Qcenter ä¸å­˜åœ¨ Qextern ä¸å­˜åœ¨ Qsuburb ä¸å­˜åœ¨ Rcenter ä¸å­˜åœ¨ Rextern ä¸å­˜åœ¨ Rsuburb ä¸å­˜åœ¨ Scenter ä¸å­˜åœ¨ Sextern ä¸å­˜åœ¨ Ssuburb ä¸å­˜åœ¨ Tcenter ä¸å­˜åœ¨ Textern ä¸å­˜åœ¨ Tsuburb ä¸å­˜åœ¨ Ucenter ä¸å­˜åœ¨ Uextern ä¸å­˜åœ¨ Usuburb ä¸å­˜åœ¨ Vcenter ä¸å­˜åœ¨ Vextern ä¸å­˜åœ¨ Vsuburb ä¸å­˜åœ¨ Wcenter ä¸å­˜åœ¨ Wextern ä¸å­˜åœ¨ Wsuburb ä¸å­˜åœ¨ Xcenter ä¸å­˜åœ¨! Xextern ä¸å­˜åœ¨! Xsuburb ä¸å­˜åœ¨! Ycenter ä¸å­˜åœ¨! Yextern ä¸å­˜åœ¨! Ysuburb ä¸å­˜åœ¨! Zcenter ä¸å­˜åœ¨! Zextern ä¸å­˜åœ¨! Zsuburb ä¸å­˜åœ¨! simutrans-124.3/simutrans/text/zh/000077500000000000000000000000001474050137200172055ustar00rootroot00000000000000simutrans-124.3/simutrans/text/zh/baum_build.txt000066400000000000000000000016111474050137200220500ustar00rootroot00000000000000æ¤æ¨¹

æ¤æ¨¹

æ­¤å•題å¯åˆ†ç‚º4å„部分

·左上角是å¯ä¾›é¸æ“‡çš„æ¨¹çš„類型的列表

Â·å·¦ä¸‹è§’æ˜¯é¡¯ç¤ºè¢«é¸æ“‡çš„æ¨¹çš„圖片

·å³ä¸Šè§’是一些å¯ä»¥è¢«è¨­ç½®çš„é¸é …

·å³ä¸‹è§’æ˜¯é¡¯ç¤ºè¢«é¸æ“‡çš„æ¨¹çš„相關信æ¯

鏿“‡åˆ—表

鏿“‡åˆ—表æä¾›äº†æ‰€æœ‰æ¨¹çš„類型,通éŽå³ä¸Šè§’çš„é¸é …å¯ä»¥ç²å¾—。有兩個標籤å¯ä»¥è¢«ç”¨ä¾†æ”¹è®Šæ¨¹çš„類型是如何被å€åˆ¥çš„。

· 翻譯: 使用當å‰èªžè¨€é¡¯ç¤ºæ¨¹çš„å稱,如果沒有被翻譯æˆç•¶å‰èªžè¨€ï¼Œå°è±¡çš„å稱將被使用

· å°è±¡: 樹的類型用模擬交通內部å°è±¡çš„åå­—

é¸é …

· 忽視天氣: æ­¤é¸é …使得天氣å°ä¸åŒæ¨¹çš„類型的é™åˆ¶è¢«è§£é™¤

· 隨機年份: å°‡è¦è¢«ç¨®æ¤çš„æ¨¹çš„年齡是隨機的

simutrans-124.3/simutrans/text/zh/color.txt000066400000000000000000000013301474050137200210610ustar00rootroot00000000000000

玩家é¡è‰²

玩家é¡è‰² 設置公å¸çš„é¡è‰²

交通工具,建築物和其他項目顯示公å¸çš„é¡è‰²

玩家é¡è‰² ä½¿ç”¨éŠæˆ²é¸é …打開

點擊é¡è‰²æ¢ä¾†ä¿®æ”¹å…¬å¸çš„é¡è‰²

玩家é¡è‰²çš„å稱æ¢çš„æ”¹è®Šï¼ˆæ–°çš„å…¬å¸çš„å稱æ¢çš„é¡è‰²ä¸æœƒæ”¹è®Šï¼‰æ„味著新的é¡è‰²è¢«é¸å‡º

默èªçš„人類玩家的é¡è‰²æ˜¯æ·¡è—色

一些項目沒有為é¡è‰²ç·¨ç¢¼&這些項目ä¸éœ€è¦é¸æ“‡é¡è‰²

(æç¤ºï¼šä½¿ç”¨çŽ©å®¶åˆ—è¡¨æˆ–è€…P+ Change Player改變電腦玩家的é¡è‰²ä¹‹å‰å…ˆé¸æ“‡é›»è…¦çŽ©å®¶ï¼‰ã€‚

simutrans-124.3/simutrans/text/zh/enlarge_map.txt000066400000000000000000000004261474050137200222220ustar00rootroot00000000000000地圖擴展幫助

擴展地圖

å¯ä»¥å‘å³å’Œå‘下擴展地圖. 如果想è¦å‘左或å‘上擴展地圖, 必須先將地圖旋轉, 在擴展, æœ€å¾Œå†æ—‹è½‰å›žåŽ».
地圖擴展é è¦½åœ¨å°è©±æ¡†çª—å£çš„å³ä¸Šé¡¯ç¤º.

simutrans-124.3/simutrans/text/zh/labellist_filter.txt000066400000000000000000000003231474050137200232640ustar00rootroot00000000000000標記列表幫助

玩家標記列表

這裡列出了地圖上所有的標記.
僅顯示活èºçީ家é¸é … åªé¡¯ç¤ºæ´»èºçŽ©å®¶è¨­ç½®çš„æ¨™è¨˜.

simutrans-124.3/simutrans/text/zh/save.txt000066400000000000000000000035061474050137200207100ustar00rootroot00000000000000<strong>存檔</strong>

存檔:把當å‰éŠæˆ²è¨˜éŒ„到文件中(為了å¯ä»¥åœ¨ä»¥å¾Œç¹¼çºŒé€²è¡ŒéŠæˆ²ï¼‰& 這些文件å¯ä»¥è¢«åˆªé™¤ã€‚

å­˜æª”æ‰“é–‹éŠæˆ²é¸é …或者按[S]éµ; & åˆ—å‡ºéŠæˆ²çš„å稱,日期&之å‰éŠæˆ²çš„æ™‚間。

å¦‚æžœæ‰€æœ‰çš„éŠæˆ²éƒ½çœ‹ä¸è¦‹ï¼›ä½¿ç”¨å³é‚Šçš„æ»¾å‹•æ¢å°‡å字滾出。

ç•¶å‰éŠæˆ²å¯ä»¥è¢«å„²å­˜æ‰“ä¸€å€‹æ–°çš„æ–‡ä»¶æˆ–è€…è¦†è“‹ä¸€å€‹å·²ç¶“å­˜åœ¨çš„éŠæˆ²æ–‡ä»¶ã€‚

ç‚ºäº†å„²å­˜éŠæˆ²åˆ°ä¸€å€‹æ–°çš„æ–‡ä»¶ï¼Œè«‹åœ¨å­˜æª”éµä¸Šæ–¹çš„ç›’å­è£¡å¡«å¯«ä¿å­˜æ–‡ä»¶çš„å稱,輸入å稱&æŒ‰å›žè»Šéµæˆ–è€…è¿”å›žéµæˆ–者點擊OK< /em>ï¼› 新的文件å稱被列出來。

注æ„:如果列出的文件å稱是使用éŽçš„:以å‰çš„æ–‡ä»¶å…§å®¹è¢«ç•¶å‰çš„éŠæˆ²æ–‡ä»¶å…§å®¹æ›¿ä»£ï¼Œ&以å‰çš„內容丟失。

默èªç•¶å‰éŠæˆ²å‡ºç¾åœ¨æ–‡ä»¶å稱盒å­è£¡ï¼Œé»žæ“ŠOK ä¿å­˜é€™å€‹æ–‡ä»¶ï¼ˆä»¥å‰çš„æ•¸æ“šè¢«ç•¶å‰æ•¸æ“šæ›¿ä»£è¢«ä¸Ÿå¤±ï¼‰

為了將以å‰çš„éŠæˆ²æœ‰ç•¶å‰çš„éŠæˆ²æ–‡ä»¶è¦†è“‹ï¼Œé»žæ“Šæ–‡ä»¶åˆ—表中的文件å(以å‰çš„éŠæˆ²å°‡è¦è¢«ç•¶å‰çš„éŠæˆ²æ–‡ä»¶æ›¿ä»£ï¼‰

文件åå¯ä»¥æ˜¯ä¸€å€‹ç”±å­—æ¯ï¼Œæ•¸å­—,符號組æˆçš„æœ€å¤§ä¸è¶…éŽ57個字符。ä¿å­˜å¾Œï¼ˆæœ€å¤š)åªæœ‰20個字符å¯ä»¥è¢«ç¾å¯¦åœ¨ä¿å­˜æ–‡ä»¶&è£è¼‰æ–‡ä»¶ä¸­ã€‚

è­¦å‘Šï¼šé€šéŽæ–‡ä»¶å點擊XéµéŠæˆ²å°‡è¢«ç«‹å³æœ‰å°±åˆªé™¤ï¼Œæ–‡ä»¶å將被移除列表。使用此功能è¦å°å¿ƒã€‚

{æç¤ºï¼šå¾žè¼‰å…¥éŠæˆ²ä¸­é‡æ–°é–‹å§‹ä¸€å€‹å·²ç¶“被ä¿å­˜éŽçš„éŠæˆ²ï¼Œ

改變自動ä¿å­˜{è‡ªå‹•éŠæˆ²ä¿å­˜}到simuconf.tab文件中}。

é»žæ“Šå–æ¶ˆéµç”¨ä¾†é—œé–‰å­˜æª”éµï¼›æˆ–者點擊左上角的X;或者使用éµç›¤é—œé–‰ã€‚

simutrans-124.3/simutrans/text/zh/scenario.txt000066400000000000000000000003221474050137200215460ustar00rootroot00000000000000劇本幫助

劇本

Simutrans支æŒåŠ‡æœ¬æ¨¡å¼. 在劇本中, 必須完æˆä¸€å®šçš„目標: 連接æŸå€‹å·¥å» , 迅速變富, æˆ–å»ºé€ ä¸€å€‹ä¸æœ½çš„總部.

simutrans-124.3/simutrans/text/zh/settings.txt000066400000000000000000000010541474050137200216060ustar00rootroot00000000000000擴展設置幫助

擴展設置

擴展設置å…è¨±æ”¹è®Šåœ¨éŠæˆ²å¼•擎中æ¯ä¸€å€‹åƒæ•¸(幾乎), 如åŒä¿®æ”¹ä¸­å¿ƒé…置文件simuconf.tab. å› æ­¤æ‰€æœ‰åƒæ•¸çš„命å與他們在simuconf.tabæ–‡ä»¶ä¸­ç›¸æ‡‰åƒæ•¸çš„命å相åŒ.

如果修改æŸå€‹æ­£åœ¨é€²è¡Œçš„éŠæˆ², 你需è¦é‡æ–°è¼‰å…¥éŠæˆ²ä»¥ä¾¿æ‡‰ç”¨è¨­ç½®. æŸäº›è¨­ç½®(比如工廠連接)åªæœƒå½±éŸ¿æ–°å‰µå»ºçš„é …ç›®.

注æ„:
ä¸é©å„…çš„åƒæ•¸è¨­ç½®æ©Ÿæ˜“æå£žéŠæˆ²!

simutrans-124.3/simutrans/text/zh/trafficlight_info.txt000066400000000000000000000003001474050137200234200ustar00rootroot00000000000000交通燈控制幫助

交通燈控制

控制紅綠燈的變æ›é »çއ. å…¶å¯é¸çš„æ•¸å­—是綠燈在北/å—å’Œæ±/è¥¿æ–¹å‘æŒçºŒçš„秒數.

simutrans-124.3/simutrans/thanks.txt000066400000000000000000000134321474050137200176340ustar00rootroot00000000000000Credits ======= Many people helped me with various contributions to Simutrans. This file tries to list all contributors to Simutrans. Additional programming ---------------------- * Markus Pristovsek: from 2005 team leader markus@pristovsek.de * Andreas Röver: small patches andreas_roever@yahoo.com * Rainer Bertram: Small patches hellmade@hellmade.de * Niels Roest: Many additional UI routines Simutrans' proportional font npr@hetnet.nl * Pasi Ruhanen: Help with BeOS port duck@neutech.fi * Tillman Raatz: Bugfixes for vehicle movement code mrtlee@gmx.de * Tomas Kubes: Forest creation code, new darkening, Patches Coordination of 128x128 pixel tile set creation t_kubes@yahoo.com * Markus Weber: Additional UI coding preml@gmx.net * Owen Rudge: MIDI playing routines for Windows version Finance window Command line arguments for reading custom daten.pak files Many small patches owen@osplus.co.uk * Volker Meyer: Better bridges and tunnels Rewrites of many data structures Binary save game format Many big patches volker.meyer@thales-is.com * Hendrik Siegeln: Line management Charts/Statistics Bugfixes "Master of the scrollbars" hsiegeln@tibco.com * Kieron Green: Textures Multiple freight graphics * Christoph Mallon: C-backends, Makefile, hosting SVN Help with game design --------------------- * Peter J. Dobrovka dobrovka@t-online.de Additional artwork ------------------ * Georg "MHz" Moers: Lots and lots of highest quality images * Flor Wauters: trucks, trains cars, industries and many other images many animations Artist trademark (vehicles): WF Ultd. flor.wauters@pandora.be * Tomas Kubes: Many high quality images t_kubes@yahoo.com * Jens Emmel: ships, trucks Artist trademark (vehicles): JET jens.emmel@hansenet.de * Manfred Tomaschitz: train waggons Artist trademark (vehicles): VT Vienna manfredtomaschitz@netscape.net * Oskari Saarekas: locomotives, waggons, ships and buildings Artist trademark (vehicles): TPI lopomo@mbnet.fi * Peter J. Dobrovka: buildings, some trees dobrovka@t-online.de * Rick McGreal: town buildings and factories Artist trademark (vehicles): Trikky trikky@mynock.com * Sergiu Croitor: busses and trucks Artist trademark (vehicles): Serj sheff.cib@usa.net * Seth C. Triggs: town buildings and factories sethtriggs@yahoo.com * Dirk Burkholz: cars and ships Artist trademark (vehicles): DIBU dirk@burkholz.de * Tuomas Suikkanen: old bookshop image tsuippa@yahoo.com * Daniel Töpel: improved powerline images, transformer station image toepel@talknet.de * Marcal Guardiola: town buildings margs@retemail.es * Frans van Nispen: some very nicely rendered high-level buildings xlr8@tref.nl * Paul Szczepanek: many high quality buildings * Stefan "MIP" Wuttich: cobblestone road s.wuttich@web.de * Patrick Nesbitt: lots of images * James Starr: high quality factories * Georg "MHZ" Moers: buildings and vehicles * sanchimaru: big harbour crane * timeshock: many small graphics * erin: many busses for the german set *singaporkid: german steamers, different station graphics * Timothy Baldock: lots of improved buildings, maglevs Translation ----------- * George Dragon: Hungarian translation dragon@idg.hu * Marcal Guardiola: Spanish translation margs@retemail.es * Niels Roest: Dutch translation npr@hetnet.nl * Rémi Denis-Courmont: French translation rdenis@multimania.com * Pasi Ruhanen: Finnish translation duck@neutech.fi * Ville Koskinen: Finnish translation bm@linja.net * Peter Molnar: Hungarian translation * Antti Louko: Finnish translation alou@mbnet.fi * Bram Schoenmakers: Dutch translation bram@schnmkrs.myweb.nl * Alberto Beccaria: Italian translation a.beccaria@inwind.it * Ivo Strasil: Czech translation ivo.strasil@centrum.cz * Kamil "FastIkarus" Ondrák: Czech translation fastikarus@centrum.cz * Ondrej Machulda: Czech translation translation@simutrans.wz.cz * Piotr Pietrzak: Polish translation pyotr@wp.pl * Jaroslav Pitoòák: Slovak translation jaro.pitonak@seznam.cz * Ján Krnác: Slovak translation Krnac@UZIS.Sk * Julius Grantén: Swedish translation ge_klav@hotmail.com * Eric C. Olivera: Portuguese translation ecostaoli@yahoo.com.br * Finn Rosenbech Jensen: Danish translation finnrj@ofir.dk * Ferencz Szekely: Hungary and Romanian translation phritzy74@freemail.hu * Aleks Revo: Russian translation deep-dream@narod.ru * Danilo Schöneberg: Russian BDF-font champcarracer@hotmail.com User manual, documentation and in-game texts -------------------------------------------- * Henrik Wolff: User manual extensions eMail@Henrik-Wolff.de * Seth C. Triggs: Maintaining the bug list 2000-2002 sethtriggs@yahoo.com * Dirk Burkholz: Help with german manual Webmaster of the german Simutrans forum dirk@burkholz.de * Adam Barclay: Many english in-game help texts Maintaining the bug list 2002-2003 echobeatz666@aol.com * Stefan Heinze: german in-game help texts masato@gmx.de * Joachim Baum: german tree descriptions * Isaak Eiland-Hall: hosting the Simutrans Wiki * Gotthardlok: Many german/english/french help texts Help with assembly coding -------------------------- * Frans van Nispen xlr8@tref.nl Additional thanks go to ----------------------- * Bernhard Mecl: Very first beta tester bernhard.mecl@gmx.de * Gerhard Hafner: Railway informations * Richard Tockey: Vehicle editor for Windows version darkfyre@phoenixdsl.com (The vehicle editor is no longer maintained as far as I know) * Veikka Kemppainen: Testing and suggestions and many other things vkem@kolumbus.fi Written by Hansjörg Malthaner, October 2000 added by Markus Pristovsek Last update: 6-Jul-2005 - markus@pristovsek.de simutrans-124.3/simutrans/themes/000077500000000000000000000000001474050137200170655ustar00rootroot00000000000000simutrans-124.3/simutrans/themes/aero.tab000066400000000000000000000131071474050137200205050ustar00rootroot00000000000000# # name of the theme (will be shown with file selector) name=Aero skin (standard size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #AFEEEE # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #1E90FF # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) bottom_window_darkness = 20 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #A7D1EA #################################colour stuff################################# # color used for the default titlebars default_window_title_color = #338FCC # gui_color_text = #000000 gui_color_text_highlight = #005C9E gui_color_text_shadow = #BDD3DF gui_color_text_title = #338FCC gui_color_text_strong = #E46A0B gui_color_obsolete = #2878ff gui_color_empty = #868c86 gui_color_edit_text = #000000 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #666666 gui_color_edit_background_selected = #72B2DD gui_color_edit_beam = #1E90FF gui_color_chart_background = #D6EBF7 gui_color_chart_lines_zero = #005C9E gui_color_chart_lines_odd = #FFFFFF gui_color_chart_lines_even = #336699 gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #72B2DD gui_color_button_text = #000000 gui_color_button_text_disabled = #666666 gui_color_button_text_selected = #FAFAFA gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #FAFAFA # gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #666666 gui_color_ticker_background = #D6ECF7 gui_color_ticker_divider = #6095B8 # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #72B2DD gui_color_statusbar_divider = #6095B8 gui_highlight_color = #FAFAFA gui_shadow_color = #CCDDFF gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #ff0000 # Colo loadbar, save game, load game, server... gui_color_loadingbar_progress = #6495ED gui_color_loadingbar_inner = #D6ECF7 # Color player brigth gui_player_color_dark = 1 gui_player_color_bright = 3 ##################################size stuff################################## # force main menu icon size icon_width = 32 # titlebar height gui_titlebar_height = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 18 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 16 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 icon_scaling = 100 ###################################pakstuff################################### # pak with the images for this theme themeimages=aerotheme.pak simutrans-124.3/simutrans/themes/aerotheme.pak000066400000000000000000001700161474050137200215400ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMG^”RRJµVZkRJ÷^½w½wµVÖZœs½w½wsN9gœs½w½wsNµVZkœs½wœsIMG.@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkIMGV”RcsN½w€sN½w½w9gRJ½wœsœsÖZ”R{o{o{ocsNIMGlsNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZkIMG´@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGlZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNIMG‚ï=÷^€{o{o{o1FcZkZk{o{oµVsN{oœsœs½wRJ9g½w½wÞ{ÖZsNœsÿÿ”R1F9gÿÖZ1FsNÖZIMG:@@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGv{oZkZkc”R{o{oZkZk”RœsœsœsZk1F½w½wœs”R”RÿÞ{÷^RJÞ{µVRJ1FsNcIMG`BÎ9Œ1Î9J)Œ1”RÖZ­5J)RJ”RµV1F)%Î9sN”R”RŒ1)%Î9sNsNRJIMG.@@)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµV@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGX­5RJŒ1ÖZ1FJ)µVsNÎ9J)”RsN1F)%J)”RsN1Fk-!1FIMGl)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1FIMG´@@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGl1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%IMGtk-­5ï=1FRJRJk-Î9BRJRJsNï=­51FsNµVµV­5ï=”RµVÖZŒ11F÷^c­5ï=”RRJï=IMG:@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG|RJBï=ï=­5J)sNRJ1Fï=Œ1k-ÖZ”RsNï=k-”R÷^µVRJ€Bc”RÎ9Î9÷^Î9Bï=µV÷^IMG^œsœs½wÞ{œs½wÿÿœs½wÞ{ÿÿœsÞ{Þ{Þ{Þ{œsœsÞ{Þ{Þ{Þ{IMG.@@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMGVœs½wœsÿÞ{œsÿÞ{Þ{œsÞ{Þ{Þ{½wœsÞ{Þ{Þ{½wœsIMGlÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMG´@@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMGlÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMG‚Zk½w½wÞ{Þ{Þ{9g½wÞ{Þ{Þ{Þ{œsœsÞ{Þ{Þ{Þ{€Þ{ÿÿÿ½wœsÞ{ÿÿœs{oÞ{ÿ½w{oœs½wIMG:@@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@{o{o{o{o{o{o{o{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o{o{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{oIMGvÞ{Þ{Þ{½wœsÞ{Þ{Þ{Þ{œsÞ{Þ{Þ{Þ{{oÿÿÞ{œsœsÿÿ½w{oÿœs{o{oœs½wIMG^”RRJµVZkRJ÷^½w½wµVÖZœs½w½wsN9gœs½w½wsNµVZkœs½wœsIMG.@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkIMGV”RcsN½w€sN½w½w9gRJ½wœsœsÖZ”R{o{o{ocsNIMGlsNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZkIMG´@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGlZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNIMG‚ï=÷^€{o{o{o1FcZkZk{o{oµVsN{oœsœs½wRJ9g½w½wÞ{ÖZsNœsÿÿ”R1F9gÿÖZ1FsNÖZIMG:@@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGv{oZkZkc”R{o{oZkZk”RœsœsœsZk1F½w½wœs”R”RÿÞ{÷^RJÞ{µVRJ1FsNcMENUTEXT EditfieldTEXTIMG1  IMG^”RRJµVZkRJ÷^½w½wµVÖZœs½w½w€9gœs½w½w€µVZkœs½wœsIMG.@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGV”RcsN½w€sN½w½w9gRJ½wœsœsÖZ”R{o{o{ocsNIMGvï=÷^€{o{o{o­5cZkZk{o{oï=÷^€{o{o{o­5cZkZk{o{oï=÷^€{o{o{o­5cZkZk{o{oIMG.@@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGj{oZkZkc”R{o{oZkZk”R{oZkZkc”R{o{oZkZk”R{oZkZkc”R{o{oZkZk”RIMG^µVsN{oœsœs½wRJ9g½w½wÞ{ÖZsNœsÿÿ”R1F9gÿÖZ1F€ÖZIMG.@@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGVœsœsœsZk1FÞ{½wœs”R”RÿÞ{÷^RJÞ{µVRJ1FsNcMENUTEXTListboxTEXTIMG1  IMGúJIMGúJúJIMG@@úJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJIMGªúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJúJIMGªßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkßkIMG‚ @@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[IMG~[IMGÿÿIMG@@~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[~[@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMENUTEXT RoundbuttonTEXTIMG1IMG^”RRJµVZkRJ÷^½w½wµVÖZœs½w½wsN9gœs½w½wsNµVZkœs½wœsIMG.@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkIMGV”RcsN½w€sN½w½w9gRJ½wœsœsÖZ”R{o{o{ocsNIMGlsNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZksNÖZcZkIMG´@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGlZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNZkcÖZsNIMG‚ï=÷^€{o{o{o1FcZkZk{o{oµVsN{oœsœs½wRJ9g½w½wÞ{ÖZsNœsÿÿ”R1F9gÿÖZ1FsNÖZIMG:@@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGv{oZkZkc”R{o{oZkZk”RœsœsœsZk1F½w½wœs”R”RÿÞ{÷^RJÞ{µVRJ1FsNcIMG`BÎ9Œ1Î9J)Œ1”RÖZ­5J)RJ”RµV1F)%Î9sN”R”RŒ1)%Î9sNsNRJIMG.@@)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%)%@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµV@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGX­5RJŒ1ÖZ1FJ)µVsNÎ9J)”RsN1F)%J)”RsN1Fk-!1FIMGl)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1F)%­5B1FIMG´@@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGl1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%1FB­5)%IMGtk-­5ï=1FRJRJk-Î9BRJRJsNï=­51FsNµVµV­5ï=”RµVÖZŒ11F÷^c­5ï=”RRJï=IMG:@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG|RJBï=ï=­5J)sNRJ1Fï=Œ1k-ÖZ”RsNï=k-”R÷^µVRJ€Bc”RÎ9Î9÷^Î9Bï=µV÷^IMG^œsœs½wÞ{œs½wÿÿœs½wÞ{ÿÿœsÞ{Þ{Þ{Þ{œsœsÞ{Þ{Þ{Þ{IMG.@@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMGVœs½wœsÿÞ{œsÿÞ{Þ{œsÞ{Þ{Þ{½wœsÞ{Þ{Þ{½wœsIMGlÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMG´@@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMGlÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{IMG‚Zk½w½wÞ{Þ{Þ{9g½wÞ{Þ{Þ{Þ{œsœsÞ{Þ{Þ{Þ{€Þ{ÿÿÿ½wœsÞ{ÿÿœs{oÞ{ÿ½w{oœs½wIMG:@@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@{o{o{o{o{o{o{o{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o{o{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{o{o{o€{o{o{oIMGvÞ{Þ{Þ{½wœsÞ{Þ{Þ{Þ{œsÞ{Þ{Þ{Þ{{oÿÿÞ{œsœsÿÿ½w{oÿœs{o{oœs½wMENUTEXT CheckbuttonTEXTIMG1IMG  €­5Î9Î9Î9Î9Î9Œ1 ”R½wÞ{Þ{Þ{Þ{Þ{½w½wc µVœs½w½w½w½w½w½w½wc ÖZ{oœsœsœsœsœsœsœsc ÷^{o{o€€€{o{o{oc cœsœs½w½w½w½w½w½w9g 9gÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{{o ÷^ÿÿÿÿÿÿÿÿ{o sN÷^ccccccc”RRJï=ï=ï=ï=ï=ï=1FIMG   ó»J]_]_]_]_úVd ,ó ÜFüJüJüJüJ Cx:6 Wz6¦ ¦ º>52"Ñ)¼>w ™\"" eÉ \&<"Ù Ú ¾.¾2pC9*¾2ž. <ÿ:?þ>¦ o?Cÿ:\" <"GŸOŸOC~KŸOŸOG\& ó){Gÿ_ÿ_ÿ_ÿ_ÿ_ÿ_{G21F­5­5€­5­5­51FIMG  Zk9g9g9g9g9g9gc {oÞ{Þ{Þ{Þ{Þ{Þ{Zk{o{o {oÞ{Þ{Þ{Þ{Þ{{o9g½w{o {o½wZkZkÞ{½w9gœsÞ{€ œs½w½wc{o9gZk½w½wœs œsÞ{Þ{œsc9g½wÞ{Þ{œs ½wÞ{Þ{Þ{ZkœsÞ{Þ{Þ{½w ½wÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{½w œsÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{½w½wœsœsœsœsœsœs½wMENUTEXT PosbuttonTEXTIMG1IMGúRJ1F”RRJZkcsNRJZk½w€sNRJZk½w½w9gRJRJZk½wœsœsÖZ”RRJZk{o{o{ocsNRJZk{oZkZkc”RRJZk{o{oZkZk”RRJZkœsœsœsZk1FRJZkÞ{½wœs”R”RRJZkÿÞ{÷^RJRJZkÞ{µVRJRJZk1FsNRJ1FcIMGÖZS>÷=ÖZR>zJ×9ÖZR>WzJ–-ÖZR>OÛJ96•)ÖZR>üJÜF›:·´-ÖZR>ýJÜF»:ù•uNÖZS>Ý:œ6{.[*úŽ1ÖZS>þ>Ý:¼6|.Ï9ÖZR>?GCÞ:|.Ñ)ÖZÖZR>_KCÞ:2SJÖZR>OC562BÖZR>]O3>SJÖZR>RBÖZÖZS>9gIMGú{o{oœs{oÞ{Þ{œs{oÞ{ÿÞ{œs{oÞ{ÿÿÞ{œs{oÞ{ÿÿÞ{½wœs{oÞ{Þ{Þ{Þ{½wœs{oÞ{Þ{Þ{Þ{½wœs{oÞ{Þ{Þ{Þ{Þ{œs{oÞ{ÿÿÞ{Þ{{o{oÞ{ÿÿÿœsœs{oÞ{ÿÿ½w{o{oÞ{ÿœs{o€Þ{{oœs{o{o½wMENUTEXT ScrollbarTEXTIMG1IMGZ  µV€÷^÷^÷^÷^÷^÷^÷^÷^”R µV9gZkZkZkZkZkZkZkZkÖZ €Þ{Þ{ÿÿÿÿÿÿÿÖZ µV½wÿÿÿÿ½w”RÿÿÖZ µV€ÿÿÿÖZk-)%ÿÿµV ÖZZkÿZkÎ9)%)%)%Þ{Þ{µV ÷^ZkµV!!!!!œsœssN c{oœscŒ1!!!½w½w”R 9gœs½w½w½wµVJ)!½w½wµV 9g½wÞ{Þ{Þ{Þ{½wRJÞ{Þ{ÖZ 9gœs½w½w½w½w½w½w½w½wÖZ ÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMGZ  Œ1Œ1­5­5­5Î9­5­5­5­5k- k-BBBBBBBBBŒ1 Œ1”RµVµVµVµVµVµVµVµV€ Œ1sNµVµVµVµV”RJ)µVµVŒ1 Œ1RJµVµVµV€BµVµVŒ1 €1FµV1F„µVµVŒ1 Î91FŒ1RJRJJ) Î9RJ€Î9c sNsNk- ï=sN”R”RsNk-”R”Rk- BsNµVµVµVµVsN!µVµV­5 ï=sN”R”R”R”R”R”R”R”RŒ1 Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9IMGZ  ½w½w½w½w½w½w½w½w½w½wœs œsÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{½w ½wÿÿÿÿÿÿÿÿÿ½w ½wÿÿÿÿÿÿœsÿÿ½w ½wÞ{ÿÿÿ½wc÷^ÿÿ½w ½wÞ{ÿÞ{Zk÷^÷^÷^ÿÿœs ½wÞ{œsÖZÖZÖZÖZÖZÞ{Þ{œs ½wÞ{ÿ½w9g÷^÷^÷^ÿÿœs Þ{ÿÿÿÿœsc÷^ÿÿœs Þ{ÿÿÿÿÿÿ{oÿÿ½w Þ{ÿÿÿÿÿÿÿÿÿ½w ½w½w½w½w½w½w½w½w½w½w½wIMGZ  ”R÷^÷^÷^÷^÷^÷^÷^÷^€µV ÖZZkZkZkZkZkZkZkZk9gµV ÷^Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{½w÷^ ÖZÿÿ”R½wÿÿÿÿ½wµV µVÿÿ)%k-ÖZÿÿÿ€µV µVÞ{Þ{)%)%)%Î9ZkÿZkÖZ sNœsœs!!!!!µVZk÷^ ”R½w½w!!!Œ1cœs{oc µV½w½w!J)µV½w½w½wœs9g ÖZÞ{Þ{RJ½wÞ{Þ{Þ{Þ{½w9g ÖZ½w½w½w½w½w½w½w½wœs9g ÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMGZ  k-­5­5­5­5Î9­5­5­5Œ1Œ1 Œ1BBBBBBBBBk- Î9”R”R”R”R”R”R”R”R”RÎ9 Œ1µVµVJ)”RµVµVµVµVsNŒ1 Œ1µVµVB€µVµVµVRJŒ1 Œ1µVµV„1FµV1F€ J)RJRJŒ11FÎ9 k-sNsNc Î9€RJÎ9 k-”R”Rk-sN”R”RsNï= ­5µVµV!sNµVµVµVµVsNB Œ1”R”R”R”R”R”R”R”RsNï= Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9IMGZ  œs½w½w½w½w½w½w½w½w½w½w ½wÞ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{œs ½wÿÿÿÿÿÿÿÿÿ½w ½wÿÿœsÿÿÿÿÿÿ½w ½wÿÿ÷^c½wÿÿÿÞ{½w œsÿÿ÷^÷^÷^ZkÞ{ÿÞ{½w œsÞ{Þ{ÖZÖZÖZÖZÖZœsÞ{½w œsÿÿ÷^÷^÷^9g½wÿÞ{½w œsÿÿ÷^cœsÿÿÿÿÞ{ ½wÿÿ{oÿÿÿÿÿÿÞ{ ½wÿÿÿÿÿÿÿÿÿÞ{ ½w½w½w½w½w½w½w½w½w½w½wIMGÖ”RRJµVZkRJ÷^½w½wµVÖZœs½w½w€9gœs½w½w€µVZkœs½wœsï=÷^€{o{o{o­5cZkZk{o{oµVsN{oœsœs½wRJ9g½w½wÞ{ÖZsNœsÿÿ”R1F9gÿÖZ1F€ÖZIMG^@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{Þ{@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMG”RcsN½w€sN½w½w9gRJ½wœsœsÖZ”R{o{o{ocsN{oZkZkc”R{o{oZkZk”RœsœsœsZk1FÞ{½wœs”R”RÿÞ{÷^RJÞ{µVRJ1FsNcIMGÊ XJ÷=¶5B–1×5ÛRWö9·)»FüJüNvJ•9*ÛBüJüJô1·Z*ÜBüFÜ>Ó%ù:&›6¼:½:ó)[&œ2½:Ý>Þ>SB*¾6ÿ>GG:z2??G_Kò5š:_KO>u>GµVRFIMG^@@!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!@]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c]c@=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[=[@OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO@KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK@ÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝBÝB@Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ:Þ>@ÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿB@_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K_K@OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO@ŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸSŸS@ßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßWßW¿W@R>R>R>S>S>R>R>R>R>R>S>S>R>R>R>R>R>S>S>R>R>R>R>R>R>S>S>R>R>R>R>R>S>S>R>R>R>R>R>S>S>R>R>R>R>R>S>R>R>R>R>R>R>S>R>R>R>R>R>R>S>R>S>S>@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZIMGÊ÷=zJ×9WzJ–-OÛJ96•)üJÜF›:·´-ýJÜF»:ù•uNÝ:œ6{.[*úŽ1þ>Ý:¼6|.Ï9?GCÞ:|.Ñ)ÖZ_KCÞ:2SJOC562B]O3>SJRBÖZ9gIMGr  µVµV÷^€µVµVÖZ÷^c9g9g÷^ €9g½wÞ{½w€ZkZk{oœsœs÷^ ÖZZkÞ{ÿÿÿ€œs½wÞ{½w÷^ ÖZZkÞ{ÿÿÿµVœs½wÞ{½w÷^ ÷^ZkÞ{ÿÿZk!c½wÞ{½w÷^ ÷^ZkÞ{ÿÿÎ9!Œ1½wÞ{½w÷^ ÷^ZkÞ{ÿÖZ)%!!µVÞ{½w÷^ ÷^ZkÞ{½wk-)%!!J)½w½w÷^ ÷^ZkÞ{”R)%)%!!!RJ½w÷^ ÷^ZkÞ{ÿÿÞ{œs½w½wÞ{½w÷^ ÷^ZkÞ{ÿÿÿÞ{œs½w½w½w÷^ ”RÖZ÷^ÖZÖZµVµVsN”RµVÖZ÷^IMGr  ½wœs½w½w½w½w½w½w½wÞ{Þ{½w ½wÞ{ÿÿÿÞ{Þ{Þ{Þ{ÿÿ½w ½wÞ{ÿÿÿÿÞ{ÿÿÿÿ½w ½wÞ{ÿÿÿÿœsÿÿÿÿ½w ½wÞ{ÿÿÿÞ{ÖZ½wÿÿÿ½w ½wÞ{ÿÿÿZkÖZ9gÿÿÿ½w ½wÞ{ÿÿ½w÷^ÖZ÷^œsÿÿ½w ½wÞ{ÿÿc÷^ÖZ÷^cÿÿ½w ½wÞ{ÿœs÷^÷^ÖZ÷^÷^{oÿ½w ½wÞ{ÿÿÿÿÞ{ÿÿÿÿ½w ½wÞ{ÿÿÿÿÿÞ{ÿÿÿ½w œs½w½w½w½w½wœsœsœsœs½w½wIMGr  Œ1k-Î9Œ1Œ1Œ1€Î9Î9ï=ï=Î9 Œ1B”R”RsNRJ1F1FRJsNsNÎ9 ­5B”RµVµVµVRJsNsN”RsNÎ9 €B”RµVµVµVŒ1€”RµVsNÎ9 ­5B”RµVµV1FÎ9”RµV”RÎ9 ­5B”RµVµV„c sNµV”RÎ9 ­5B”RµV€k-µV”RÎ9 ­5B”R”RBsN”RÎ9 Î9B”RJ)!”RÎ9 ­5B”RµVµVµVRJsN”RµV”RÎ9 ­5B”RµVµVµVµVRJsN”R”RÎ9 k-Œ1Î9€Œ1Œ1Œ1J)k-k-Œ1Î9IMGr  ”RÖZÖZÖZµVµVsN”RµVÖZÖZ÷^ ÷^ZkÿÿÿÞ{œs½w½wÞ{½w÷^ ÷^ZkÿÿÿÞ{œs½w½wÞ{½w÷^ ÷^Zkÿ”R)%)%!!!RJ½w÷^ ÷^Zkÿ½wk-)%!!J)½w½w÷^ ÷^ZkÿÿÖZ)%!!µVÞ{½w÷^ ÷^ZkÿÿÿÎ9!Œ1½wÞ{½w÷^ ÷^ZkÿÿÿZk!c½wÞ{½w÷^ ÷^ZkÞ{ÿÿÿµVœs½wÞ{½w÷^ ÷^Zkÿÿÿÿ€œs½wÞ{½w÷^ €9gÞ{½w€ZkZk{oœs½wœs÷^ µVµV€µVµVÖZ÷^c9g9g9g÷^IMGr  œs½w½w½w½wœsœsœsœs½w½w½w ½wÞ{ÿÿÿÿÞ{ÿÿÿÿ½w ½wÞ{ÿÿÿÿÞ{ÿÿÿÿ½w ½wÞ{ÿœs÷^÷^ÖZ÷^÷^{oÿ½w ½wÞ{ÿÿc÷^ÖZ÷^cÿÿ½w ½wÞ{ÿÿ½w÷^ÖZ÷^œsÿÿ½w ½wÞ{ÿÿÿZkÖZ9gÿÿÿ½w ½wÞ{ÿÿÿÞ{ÖZ½wÿÿÿ½w ½wÞ{ÿÿÿÿœsÿÿÿÿ½w ½wÞ{ÿÿÿÿÞ{ÿÿÿÿ½w ½wÞ{ÿÿÞ{Þ{Þ{Þ{ÿÿÿ½w ½wœs½w½w½w½w½w½wÞ{Þ{Þ{½wIMGr  k-Œ1€Œ1Œ1Œ1J)k-k-­5Œ1Î9 ­5BµVµVµVµVRJsN”RµV”RÎ9 ­5BµVµVµVµVRJsN”RµV”RÎ9 ­5BµVJ)!”RÎ9 ­5BµV”RBsN”RÎ9 Î9BµVµV€k-µV”RÎ9 ­5BµVµVµV„c sNµV”RÎ9 ­5BµVµVµV1FÎ9”RµV”RÎ9 ­5BµVµVµVµVŒ1€”RµV”RÎ9 ­5BµVµVµVµVRJsNsN”R”RÎ9 Œ1B”RsNRJ1F1FRJsNsNsNÎ9 Œ1k-Œ1Œ1Œ1€Î9Î9ï=Bï=Î9IMG¦µV­5ï=€ÖZRJsNc÷^µV€µV ”RsN9g{oZk€Zk9gÖZRJ ÖZ1Fœs½wœsZk{oœsœsœs÷^RJ 1F9gÿ½wœs{o{o½w½w½w½wµVÖZ€ÿÿÞ{½w{o{oœs½w½w½wZk”RIMGŠ@RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€RJZkÿÿÞ{½wœs{oœs½w½w½wÞ{€IMGŒc1FÞ{ÿÞ{œs{o{o{o½w½w½wc”R sNµVÞ{½wœs{oZk{oœs½w€sN RJ÷^œsœsZkZk{oœs9gsNRJ”RZkZkccÖZRJ”R1F”R”RsN”RIMG¢SBó)Ó%ô1vJ:*[&ù·•ö9 ò5z2¾6œ2:&Z*9*·)–1 >š:?ÿ>½:›6ÜBÛB»F×5÷= µVu>_K?GGÝ>¼:üFüJüJÛR¶59gRFGO_KGÞ>½:Ü>üJüNWBXJIMGŠ@ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZR>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>ßWŸSO_KÿBÞ:ÝBKO=[]c!ÖZS>¿WŸSO_KÿBÞ>ÝBKO=[]c!IMGš9gRB]OO_K?Gþ>Ý:ýJüJOWzJ÷= ÖZ3>CCCÝ:œ6ÜFÜFÛJzJ×9 SJ56Þ:Þ:¼6{.»:›:96–-2B2|.|.[*ù·•)SJÑ)ú•´-ÖZÏ9Ž1uNMENUTEXTBackTEXTIMG1  IMG IMG"@@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿIMG IMG @€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€Ùÿ€áþ€áþ€Ùÿ€ÙÿIMGŠ!@@@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€áþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþáþ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿ@€ÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿÙÿIMG IMG IMG IMG MENUTEXTGadgetTEXTIMG1  IMG†çBBçÆ%Î=RNRNÎ=%Æ cJ5sV9k{sœs9ksVJ5c ÆÆ,­MsfÖnÖnÖnÖnSf­MÇ,Æ c$ÇDçTI]‹a‹a‹a‹aI]çTÇDd$ç$…8„P„XÆ\a(a(aaÆ\„X„L…8è(B …H¤Xæ`(ejiŠiŠiji(eå`¤X…HB$B,¥PaIi‹m­qîuîuÍq‹qIie¥PB,ç4ÅTIe«qÍyz0~0~zíy«qIiÅTç8 ¤L‹iíu~Q~r~r~Q~~íu‹m¤P æ@JazQ~’~³~´~“~Q~zjeÆ@ ¥DÍmrv´zÕ~Õ~´zrzÍmÅHIA‹U/frn“r0f‹UJEkA(=(A‹EIMG’sJB1B”RSJuRg~s]o¹^òE•R UNÛb^s~ssss>o˜VTJ F¼^>o^s^s_s_s^s^okR¶V×^9Rk>oº^èÇ"n1?o>oÞf6NµVUNžbo?okÚbgÑ=_s?oþj}ZBJßfk?o_s_s_s¯9§?s?oßj¿fŒ1Jÿn?so?s?sWV"™^o?sÿnÞfŒ14Nÿn?s?s_w_w¦óE{_w?soœ^1FSJÞf?s_w{{l1új{_w_woWRµV Jo_w{Ÿm5új{{?wþj3J xZ_w{Ÿ¦ÙbŸ{o4N–Z^wŸ¿ŸŸ]wSNsNµV×^·^•VRJIMG’ç BBç Æ$1ÎERRRRÎE1Æ  c JAs^9o{s{s9os^JAd  ¥$æ<í]Ón6wWwVw6wÓní]ç@¦(ïAƒ0gUfhn‰r‰r‰r‰rhnfgU„8ïAç0EÄanBrdrev…rdrBrnÄa%Mç0b4…YnBv„z¦zÇzÇz§z„zbv#n…Yb4Â<åadv¥~è~    è~¥~dvåeÂ<GAf¦zè~*LmmL*è~¦zjGAJãaÈz*l¯¯Žl*ÈzãaJ ¥I§nK{ŽÏððÏ®L§r¦I ÄMênŽ{Ðòòñ¯{ säMèEˆV,kss-k¨ZèEPJ FBB*FPJIMG–Î9çBBçÎ9Æ!Î9RJRJÎ9!Æ dj)“N9gœo›oYg“Nk-d Æ'-6óNV_wcV_óN-6'Æï=ÄÇG.¨:ÉBÊB¨:G.ÇÄï=!e"c*ƒ2Å:Å:£6c*$"e! åc.£6çBGGå>£6c.å â %*Å:æ>JOkSkS(GCÅ:%* g!D.çBIKkS­[®[kSIKCD.‡!>#*GkS­WÎ_ïc­[kSG#*> Å%ç>lWÏ_ðgñkðgïcWèBÅ) **KÏ_ñgòoòoñkÏckO.2©B-Wcc.WÉB(6PF :22*:PFIMG–Î9çBBçÎ9Æ!Î9RJRJÎ9!Æ dj)“N9gœo›oYg“Nk-d Æ'-6óNV_wcV_óN-6'Æï=ÄÇG.¨:ÊBÉB¨:G.ÇÄï=!e"c*ƒ2Å:Å:£6c*$"e! åc.£6Å:GGC£6c.å â %*Å:æ>(GkSkSJOCÅ:%* g!D.çBIKkS­[®[kSIKCD.‡!>#*GkS­Wïcï_­[kSG#*> Å%ç>lWÏ_ðgñkðgïcWèBÅ) **KÏ_ñgòoòoñkÏckO.2©B-Wcc.WÉB(6PF :22*:PFIMG–Ô!ëddëÔ!ê.ö)X:X:ö)Nê ¨ ’!¹F\coo\c¹F’!¨  êO72úR<_<_<_<_úR76pëö)ê´!*72X6X:X:W672*´! ö).OÔ%Ô%Õ%ö)..ö)õ%Ô%Ô%q.ë³!Õ%õ%.W6X:X:X67.ö%Õ%³!ë Õ%*72x>™B™B™F™Bx>76.Õ% pÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%q*³!X:™B¹JÚNúRúRÚN¹J™BX:³!* q72¹FÚNúRWWûRÚN¹F72q pW6ÚNûR[[ûVÚNx:p‘Õ%x:ÚJÚJx>õ%’!7.²!pp³!7.IMG¾Ô!ëddëÔ!ê.ö)X:X:ö)Nê ¨ ’!¹F\coo\c¹F’!¨  êO72úR<_<_<_<_úR76pëö)ê´!*72X6X:X:W672*´! ö).OÔ%Ô%Õ%ö)..ö)õ%Ô%Ô%q.ë³!Õ%õ%.W6X:X:X67.ö%Õ%³!ë Õ%*72x>™B™B™F™Bx>76.Õ% pÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qpÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qpÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qpÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qpÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qpÕ%76x>™B¹JÚJÚJºJ™Bx>W6Õ%qIMGÐ   {o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o  {o{o{o{o{o{o{o{o{o{o IMG–çBBçÆ%Î=RNRNÎ=%Æ cJ5sV9k{sœs9ksVJ5c ÆÆ,­MsfÖnÖnÖnÖnSf­MÇ,Æ c$ÇDçTI]‹a‹a‹a‹aI]çTÇDd$ç$…8„P„XÆ\a(a(aaÆ\„X„L…8è(B …H¤Xæ`(e(edUŠiji(eå`¤X…HB$B,¥PaIi‹mdUâ4â4Íq‹qIie¥PB,ç4ÅTIe«qdUâ4â4¢$íyíy«qIiÅTç8 ¤L‹idUâ4â4¢$Q~Q~~íu‹m¤P æ@dUâ4â4¢$´~´~“~Q~zjeÆ@ dUâ4¢$rv´zÕ~Õ~´zrzÍmÅH dUâ4¢$IA‹U/frn“r0f‹UJECIâ4kA(=(A‹EMENUTEXTDividerTEXTIMG1IMG IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG simutrans-124.3/simutrans/themes/classic-large.tab000066400000000000000000000111021474050137200222610ustar00rootroot00000000000000# Default simutrans theme # # name of the theme (will be shown with file selector) name=Simutrans classic (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 tooltip_text_color = #000000 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # larger icons too icon_scaling = 150 # use the larger Button height gui_button_height = 22 # titlebar height gui_titlebar_height = 22 # width of the window elements gui_gadget_width = 22 # arrows and scrollbars gui_horizontal_arrow_height = 22 gui_horizontal_arrow_width = 22 gui_vertical_arrow_height = 22 gui_vertical_arrow_width = 22 gui_scrollbar_width = 22 gui_scrollbar_height = 22 # and a matching edit field height gui_edit_height = 22 # request larger font size (the resulting spacing is about 15% larger due to decent) font_size = 16 #################################colour stuff################################# gui_color_text = #000000 gui_color_text_highlight = #F8FCF8 gui_color_text_shadow = #000000 gui_color_text_title = #C0FC60 gui_color_text_strong = #C00000 gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #F8FC00 gui_color_edit_text = #F8FCF8 gui_color_edit_text_selected = #A8ACA8 gui_color_edit_text_disabled = #606060 gui_color_edit_background_selected = #404040 gui_color_edit_beam = #F8FCF8 gui_color_chart_background = #989898 gui_color_chart_lines_zero = #D8DCD8 gui_color_chart_lines_odd = #F8FCF8 gui_color_chart_lines_even = #686868 gui_color_list_text_selected_focus = #F8FCF8 gui_color_list_text_selected_nofocus = #C8C8C8 gui_color_list_background_selected_focus = #0000F8 gui_color_list_background_selected_nofocus = #60A0F8 gui_color_obsolete = #0000F8 gui_color_empty = #F8FCF8 gui_color_button_text = #000000 gui_color_button_text_disabled = #686868 gui_color_button_text_selected = #000000 gui_color_colored_button_text = #000000 gui_color_colored_button_text_selected = #F8FCF8 gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #686868 gui_color_ticker_background = #B0B0B0 gui_color_ticker_divider = #000000 gui_color_statusbar_text = #000000 gui_color_statusbar_background = #989898 gui_color_statusbar_divider = #D8DCD8 gui_highlight_color = #D8DCD8 gui_shadow_color = #686868 gui_color_loadingbar_inner = #A8ACA8 gui_color_loadingbar_progress = #0000F8 cursor_overlay_color = #F88000 tooltip_background_color = #7094B8 tooltip_text_color = #000000 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #D74700 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) #bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 4 gui_player_color_dark = 1 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #EEEEEE ##################################pakstuff################################## # pak with the images for this theme themeimages=classic.pak simutrans-124.3/simutrans/themes/classic.pak000066400000000000000000001343061474050137200212120ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGBÿÿÿÿÿ{o{o{oÿ{oÿÿÿ{oÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGBÿÿÿ{oÿÿÿÿÿÿÿ­5IMGlÿ{oÿÿÿ{oÿÿÿ{oÿÿÿ{oÿÿÿ{oÿÿÿ{oÿÿÿ{oÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿsN­5ÿsN­5ÿsN­5ÿsN­5ÿsN­5ÿsN­5ÿsN­5IMG4ÿ9g9g9gÿ9gsNÿIMGœ@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@IMG4ÿÿ­5­5­5­5IMG4­5­5­5­5­5­5­5­5IMGœ@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMG(­5­5sNsNIMGl­5­5sN­5­5sN­5­5sN­5­5sN­5­5sN­5­5sN­5­5sNIMG´@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGPsNÖZsNÖZsNÖZsNÖZsNÖZsNÖZsNÖZIMGB­5sNsN­5sNsN­5sNÖZ{o{o{o{oIMG"@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG2sNÖZsNÖZÖZÖZ{o{oIMGBÿÿÿÿÿ½w½w½wÿ½wœsœsÿ½wœsœsIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGBÿÿÿÎ9½wœsœsÎ9œsœsœsÎ9œsœs”RÎ9IMGlÿ½wœsœsÿ½wœsœsÿ½wœsœsÿ½wœsœsÿ½wœsœsÿ½wœsœsÿ½wœsœsIMG´@@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGlœsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9IMG4ÿœsœsœsÿœsc”RÎ9Î9Î9Î9IMGœ@@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9IMG4cc”RÎ9”R”R”RÎ9Î9Î9Î9Î9IMG9g9g9g9gIMG@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMG,{o9g9g9g9g9g9g9gIMGP9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMG´@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGB9g9g9g9g9g9g9gIMG"9g9g9g9gsN­5IMG@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGsNsNMENUTEXT RoundbuttonTEXTIMG1IMGBÿÿÿÿÿ{o{o{oÿ{o9g9gÿ{o9g9gIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGBÿÿÿ{o9g9g9g9g9g9g9g­5IMGlÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gIMG´@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGl9gsN­59gsN­59gsN­59gsN­59gsN­59gsN­59gsN­5IMG4ÿ9g9g9gÿ9gsN­5IMGœ@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@IMG4sNsN­5­5­5­5IMG4­5­5­5­5­5­5­5­5IMGœ@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMG(­5­5sNsNIMGl­5­5sN­5­5sN­5­5sN­5­5sN­5­5sN­5­5sN­5­5sNIMG´@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGPsNÖZsNÖZsNÖZsNÖZsNÖZsNÖZsNÖZIMGB­5sNsN­5sNsN­5sNÖZ{o{o{o{oIMG"@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG2sNÖZsNÖZÖZÖZ{o{oIMGBÿÿÿÿÿ½w½w½wÿ½wœsœsÿ½wœsœsIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½w½wIMGBÿÿÿÎ9½wœsœsÎ9œsœsœsÎ9œsœs”RÎ9IMGPÿ½wÿ½wÿ½wÿ½wÿ½wÿ½wÿ½wIMG IMGlœsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9œsc”RÎ9IMG4ÿœsœsœsÿœsc”RÎ9Î9Î9Î9IMGœ@@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9IMG4cc”RÎ9”R”R”RÎ9Î9Î9Î9Î9MENUTEXT EditfieldTEXTIMG1  IMG­5IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5­5IMGª­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG‚ @@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGª{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG{oIMG@@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG{oMENUTEXTListboxTEXTIMG1  IMGIMG@@IMGIMGªIMG‚ @@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMGª{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG9gIMG@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿMENUTEXTBackTEXTIMG1  IMG IMG IMG IMG @{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMGŠ!@@@“V“VöbÕ^´Z´ZÕ^”Z´Z8g“RöbÕ^rR´Z´Z“VÕ^´Z“V´ZöbÕ^´Z÷brRµZrRÕ^“RÕ^g“V“VöbÕ^´Z´ZÕ^”Z´Z8g“RöbÕ^rR´Z´Z“VÕ^´Z“V´ZöbÕ^´Z÷brRµZrRÕ^“RÕ^g@“VÖbµZÕZÕZÕ^´Z´ZgrRöbµZ“R´Z´Z“VÕ^ÕZrR´ZÕ^µZ´ZÖ^“V“V“RÕ^rRÕ^8k“V“VÖbµZÕZÕZÕ^´Z´ZgrRöbµZ“R´Z´Z“VÕ^ÕZrR´ZÕ^µZ´ZÖ^“V“V“RÕ^rRÕ^8k“V@Õ^´ZöbÕ^Õ^”Z´ZcrRöbÕZrR“VÕ^“VÕZÕ^rRÕZÕ^ÕZ´ZÕ^“V´Z“VÕ^“VÕ^8g“VrRÕ^´ZöbÕ^Õ^”Z´ZcrRöbÕZrR“VÕ^“VÕZÕ^rRÕZÕ^ÕZ´ZÕ^“V´Z“VÕ^“VÕ^8g“VrR@”ZöböbÕ^“V´ZöbQNöb´Z“V“Vöb“V´ZÕZrRµZÕZ´ZÕ^Õ^“V´Z“VÕ^“VÕ^g´Z“RÕZ”ZöböbÕ^“V´ZöbQNöb´Z“V“Vöb“V´ZÕZrRµZÕZ´ZÕ^Õ^“V´Z“VÕ^“VÕ^g´Z“RÕZ@cgÕ^“V“VöbrRöb´Z“V´Zöb“V´Z´Z“VµZ´Z´ZÕ^ÕZ´ZÕ^“VÕ^“VÕ^öb´Z“VÕZ“VcgÕ^“V“VöbrRöb´Z“V´Zöb“V´Z´Z“VµZ´Z´ZÕ^ÕZ´ZÕ^“VÕ^“VÕ^öb´Z“VÕZ“V@cÕ^“VÕ^ÕZrRµZ´Z“V´Zöb”Z´Z´Z“VÕ^´Z´ZÕ^´Z´ZÕ^´ZÕ^“V´Z´ZÕ^“VÕ^“VccÕ^“VÕ^ÕZrRµZ´Z“V´Zöb”Z´Z´Z“VÕ^´Z´ZÕ^´Z´ZÕ^´ZÕ^“V´Z´ZÕ^“VÕ^“Vc@Õ^“VÕZÕZQN“VÕZ“V“V÷b´Z“V´Z“VÕ^µZ´ZÕ^´Z´ZÖb”ZÕ^“V´Z´ZÕ^“VÕZ“VöböbÕ^“VÕZÕZQN“VÕZ“V“V÷b´Z“V´Z“VÕ^µZ´ZÕ^´Z´ZÖb”ZÕ^“V´Z´ZÕ^“VÕZ“Vöböb@´ZÕZÖ^QN“VÕ^“V“VöbµZ“V“V´ZÖ^ÕZ´ZÖ^´Z´ZÖb´ZÕ^“R´Z“Vöb”ZµZ“VöböbÕ^´ZÕZÖ^QN“VÕ^“V“VöbµZ“V“V´ZÖ^ÕZ´ZÖ^´Z´ZÖb´ZÕ^“R´Z“Vöb”ZµZ“VöböbÕ^@Õ^Õ^rR“VÕ^rR“V÷bµZ“V“V´ZöbÕ^´ZÕ^´ZµZÕ^´ZÕ^“R´Z“Rc´ZÕ^“VöbÕ^µZÕ^Õ^Õ^rR“VÕ^rR“V÷bµZ“V“V´ZöbÕ^´ZÕ^´ZµZÕ^´ZÕ^“R´Z“Rc´ZÕ^“VöbÕ^µZÕ^@Õ^rR“VÕ^rRÕ^gÕ^“V“V´ZöbÕ^´ZÖ^µZÕ^Õ^ÕZ´Z“V´ZrRg´ZµZ“RÖbÕ^´ZöbÕZÕ^rR“VÕ^rRÕ^gÕ^“V“V´ZöbÕ^´ZÖ^µZÕ^Õ^ÕZ´Z“V´ZrRg´ZµZ“RÖbÕ^´ZöbÕZ@“V“VÕZrRÕ^g´ZrRrR´ZöbÕ^´ZÕ^µZÕ^´ZÕ^´Z“V´ZrR8g´ZÕ^“RÖ^ÕZ´ZcµZÕ^“V“VÕZrRÕ^g´ZrRrR´ZöbÕ^´ZÕ^µZÕ^´ZÕ^´Z“V´ZrR8g´ZÕ^“RÖ^ÕZ´ZcµZÕ^@“V´ZrRÕ^g´ZrR“RµZgÖ^´ZÕ^Õ^Õ^´ZÕ^“V´Z´ZrRg´ZÕ^rRÕ^´Z´ZgÕZÕ^“V“V´ZrRÕ^g´ZrR“RµZgÖ^´ZÕ^Õ^Õ^´ZÕ^“V´Z´ZrRg´ZÕ^rRÕ^´Z´ZgÕZÕ^“V@´Z“VÕ^öb”ZrR“VÕZ÷böb´ZÕ^Õ^öb´ZÖb“VÕZ´ZrRg´ZµZ“VÕ^´Z´Z8kÕ^Õ^”Z“V´Z“VÕ^öb”ZrR“VÕZ÷böb´ZÕ^Õ^öb´ZÖb“VÕZ´ZrRg´ZµZ“VÕ^´Z´Z8kÕ^Õ^”Z“V@“VÕZÖb´Z“R“VöbÕ^ÕZ“VÕ^Õ^öb´Zöb“VÕ^´Z“R÷b“VÕ^“VÕ^´Z´ZYoÕZÕ^´Z“V´Z“VÕZÖb´Z“R“VöbÕ^ÕZ“VÕ^Õ^öb´Zöb“VÕ^´Z“R÷b“VÕ^“VÕ^´Z´ZYoÕZÕ^´Z“V´Z@ÕZÖbµZ“VrRÕ^öb”Z´ZöbÕ^öb“V÷brRÕ^´Z“Vc“VÕ^“VÕ^´Z´ZYk´ZÕ^µZ“V”Z´ZÕZÖbµZ“VrRÕ^öb”Z´ZöbÕ^öb“V÷brRÕ^´Z“Vc“VÕ^“VÕ^´Z´ZYk´ZÕ^µZ“V”Z´Z@Õ^ÕZ“V“VÖbÖ^´Z´ZÕ^´Zöb“VgrRöb´Z“Vöb“RÕ^“VÕ^´Z´ZYo”ZÕZÕ^“V´Z´Z´ZÕ^ÕZ“V“VÖbÖ^´Z´ZÕ^´Zöb“VgrRöb´Z“Vöb“RÕ^“VÕ^´Z´ZYo”ZÕZÕ^“V´Z´Z´Z@ÕZ”Z“VÕ^Ö^´ZöbÕ^´ZÕ^“VgrR÷b´Z“VÖbrRÕ^“VÕ^´Z´Z9k“VµZÕ^“V´ZµZÕZÕZÕZ”Z“VÕ^Ö^´ZöbÕ^´ZÕ^“VgrR÷b´Z“VÖbrRÕ^“VÕ^´Z´Z9k“VµZÕ^“V´ZµZÕZÕZ@´Z“VÕ^Õ^´Zöb“V“V´Z“VgrRöb´Z“VÕ^rRÕ^“VÕ^´Z´ZYkrR´ZÕ^“V”ZµZ´Z´ZÕZ´Z“VÕ^Õ^´Zöb“V“V´Z“VgrRöb´Z“VÕ^rRÕ^“VÕ^´Z´ZYkrR´ZÕ^“V”ZµZ´Z´ZÕZ@“VÕ^Õ^´Zöb“V´ZÕZ“VgrRÕ^´Z´ZÕ^qRÕ^´ZÖ^´Z´Z8krR´ZÕ^´Z”Z´ZÕ^´ZµZ´Z“VÕ^Õ^´Zöb“V´ZÕZ“VgrRÕ^´Z´ZÕ^qRÕ^´ZÖ^´Z´Z8krR´ZÕ^´Z”Z´ZÕ^´ZµZ´Z@µZµZ´Z÷b“VÕ^“V“VgrRÕ^öbÖ^µZrRÕ^´ZÕ^´Z´Z8kQN´Zöb´Z“V´ZÕ^´Z´ZµZ“VµZµZ´Z÷b“VÕ^“V“VgrRÕ^öbÖ^µZrRÕ^´ZÕ^´Z´Z8kQN´Zöb´Z“V´ZÕ^´Z´ZµZ“V@´Z´Zc“RÕ^“V´ZgrR´ZöbÕ^´ZqRÕ^´ZÖ^´ZµZ8g0JÕ^öb´Z“V´Zöb´Z´Z´Z“VÕ^´Z´Zc“RÕ^“V´ZgrR´ZöbÕ^´ZqRÕ^´ZÖ^´ZµZ8g0JÕ^öb´Z“V´Zöb´Z´Z´Z“VÕ^@´ZgrRöb”Z´Z÷brR´ZöbÕ^´ZqRÕ^´ZÕ^´Z´Z8gFcöb´Z“V´Zöb´Z“V´Z”ZÕ^´Z´ZgrRöb”Z´Z÷brR´ZöbÕ^´ZqRÕ^´ZÕ^´Z´Z8gFcöb´Z“V´Zöb´Z“V´Z”ZÕ^´Z@g“Rc´Z´ZcrR“VöbÕ^´ZqRÕ^”ZÕ^´Z´ZgFcöb´Z“V´Zc´Z“R´Z´ZÖ^´Z´Zg“Rc´Z´ZcrR“VöbÕ^´ZqRÕ^”ZÕ^´Z´ZgFcöb´Z“V´Zc´Z“R´Z´ZÖ^´Z´Z@“Vöb´Z´Z÷bQNöbgöbµZQNÕ^”Z´Z“V´Zg0Jgöb´Z“R´Zg´ZrR´Z´Zöb´Z´Zc“Vöb´Z´Z÷bQNöbgöbµZQNÕ^”Z´Z“V´Zg0Jgöb´Z“R´Zg´ZrR´Z´Zöb´Z´Zc@öb´Z´ZöbrRöbÕ^ÖbÕ^rRÕ^Õ^´Z´Z”ZgQNgÖ^´Z“V“R8g´ZrR´ZµZöb´Z´Zc“Vöb´Z´ZöbrRöbÕ^ÖbÕ^rRÕ^Õ^´Z´Z”ZgQNgÖ^´Z“V“R8g´ZrR´ZµZöb´Z´Zc“V@“VÕZ´ZrRöb÷böbµZrRöböb“VÕZ“VgQNgÕ^´Z“V“Vöb´ZQNÕZÕ^öb´Z´Zc´ZÖ^“VÕZ´ZrRöb÷böbµZrRöböb“VÕZ“VgQNgÕ^´Z“V“Vöb´ZQNÕZÕ^öb´Z´Zc´ZÖ^@´Z´Z“VÕ^öbÕ^Õ^rRöbÖb“VrR´ZgrRgÕ^´Z“V´Z´Z”ZQNµZÕ^c´Z´Zöb´ZÕ^“V´Z´Z“VÕ^öbÕ^Õ^rRöbÖb“VrR´ZgrRgÕ^´Z“V´Z´Z”ZQNµZÕ^c´Z´Zöb´ZÕ^“V@´Z´Z”ZÖbc“VÕ^öböbrRrR´ZgrR8gÕ^“V”Z´Z´Z´ZqRÕ^Õ^g´Z´Zöb´ZÕ^´Z´Z´Z´Z”ZÖbc“VÕ^öböbrRrR´ZgrR8gÕ^“V”Z´Z´Z´ZqRÕ^Õ^g´Z´Zöb´ZÕ^´Z´Z@´Z“V”ZgqRÕ^öbÕ^rRrRÕZ÷b“VgÕZ“V´Z“R´Z´ZrRÖb´Zc´Z´ZöbÕ^µZ´Z´Z´Z´Z“V”ZgqRÕ^öbÕ^rRrRÕZ÷b“VgÕZ“V´Z“R´Z´ZrRÖb´Zc´Z´ZöbÕ^µZ´Z´Z´Z@“VÖ^c“RÕ^cÕZrRrRÕ^öb´Z8g´Zöb“V“V“V´Z“VöbÕ^rR“VÖ^g´Zöb´ZµZ“RÕ^“VÖ^c“RÕ^cÕZrRrRÕ^öb´Z8g´Zöb“V“V“V´Z“VöbÕ^rR“VÖ^g´Zöb´ZµZ“RÕ^@Õ^grR´Zöb´Z“R“VÖbÕ^´ZYk“Vöb´Z“V“V´Z“VcÕ^rR´ZöbÕ^´Zöb“V´ZrRÕ^“VÕ^grR´Zöb´Z“R“VÖbÕ^´ZYk“Vöb´Z“V“V´Z“VcÕ^rR´ZöbÕ^´Zöb“V´ZrRÕ^“V@g“R´ZöbÖ^“R´ZÖb´Z´Z8k“Vöb´Z“V”Z´Z“VÕ^Õ^”Z´ZöbÕ^µZöb“V´ZrRÕ^“VÕ^g“R´ZöbÖ^“R´ZÖb´Z´Z8k“Vöb´Z“V”Z´Z“VÕ^Õ^”Z´ZöbÕ^µZöb“V´ZrRÕ^“VÕ^@“V“VöbÕ^´Z´ZÕ^”Z´Z8g“RöbÕ^rR´Z´Z“VÕ^´Z“V´ZöbÕ^´Z÷brRµZrRÕ^“RÕ^g“V“VöbÕ^´Z´ZÕ^”Z´Z8g“RöbÕ^rR´Z´Z“VÕ^´Z“V´ZöbÕ^´Z÷brRµZrRÕ^“RÕ^g@“VÖbµZÕZÕZÕ^´Z´ZgrRöbµZ“R´Z´Z“VÕ^ÕZrR´ZÕ^µZ´ZÖ^“V“V“RÕ^rRÕ^8k“V“VÖbµZÕZÕZÕ^´Z´ZgrRöbµZ“R´Z´Z“VÕ^ÕZrR´ZÕ^µZ´ZÖ^“V“V“RÕ^rRÕ^8k“V@Õ^´ZöbÕ^Õ^”Z´ZcrRöbÕZrR“VÕ^“VÕZÕ^rRÕZÕ^ÕZ´ZÕ^“V´Z“VÕ^“VÕ^8g“VrRÕ^´ZöbÕ^Õ^”Z´ZcrRöbÕZrR“VÕ^“VÕZÕ^rRÕZÕ^ÕZ´ZÕ^“V´Z“VÕ^“VÕ^8g“VrR@”ZöböbÕ^“V´ZöbQNöb´Z“V“Vöb“V´ZÕZrRµZÕZ´ZÕ^Õ^“V´Z“VÕ^“VÕ^g´Z“RÕZ”ZöböbÕ^“V´ZöbQNöb´Z“V“Vöb“V´ZÕZrRµZÕZ´ZÕ^Õ^“V´Z“VÕ^“VÕ^g´Z“RÕZ@cgÕ^“V“VöbrRöb´Z“V´Zöb“V´Z´Z“VµZ´Z´ZÕ^ÕZ´ZÕ^“VÕ^“VÕ^öb´Z“VÕZ“VcgÕ^“V“VöbrRöb´Z“V´Zöb“V´Z´Z“VµZ´Z´ZÕ^ÕZ´ZÕ^“VÕ^“VÕ^öb´Z“VÕZ“V@cÕ^“VÕ^ÕZrRµZ´Z“V´Zöb”Z´Z´Z“VÕ^´Z´ZÕ^´Z´ZÕ^´ZÕ^“V´Z´ZÕ^“VÕ^“VccÕ^“VÕ^ÕZrRµZ´Z“V´Zöb”Z´Z´Z“VÕ^´Z´ZÕ^´Z´ZÕ^´ZÕ^“V´Z´ZÕ^“VÕ^“Vc@Õ^“VÕZÕZQN“VÕZ“V“V÷b´Z“V´Z“VÕ^µZ´ZÕ^´Z´ZÖb”ZÕ^“V´Z´ZÕ^“VÕZ“VöböbÕ^“VÕZÕZQN“VÕZ“V“V÷b´Z“V´Z“VÕ^µZ´ZÕ^´Z´ZÖb”ZÕ^“V´Z´ZÕ^“VÕZ“Vöböb@´ZÕZÖ^QN“VÕ^“V“VöbµZ“V“V´ZÖ^ÕZ´ZÖ^´Z´ZÖb´ZÕ^“R´Z“Vöb”ZµZ“VöböbÕ^´ZÕZÖ^QN“VÕ^“V“VöbµZ“V“V´ZÖ^ÕZ´ZÖ^´Z´ZÖb´ZÕ^“R´Z“Vöb”ZµZ“VöböbÕ^@Õ^Õ^rR“VÕ^rR“V÷bµZ“V“V´ZöbÕ^´ZÕ^´ZµZÕ^´ZÕ^“R´Z“Rc´ZÕ^“VöbÕ^µZÕ^Õ^Õ^rR“VÕ^rR“V÷bµZ“V“V´ZöbÕ^´ZÕ^´ZµZÕ^´ZÕ^“R´Z“Rc´ZÕ^“VöbÕ^µZÕ^@Õ^rR“VÕ^rRÕ^gÕ^“V“V´ZöbÕ^´ZÖ^µZÕ^Õ^ÕZ´Z“V´ZrRg´ZµZ“RÖbÕ^´ZöbÕZÕ^rR“VÕ^rRÕ^gÕ^“V“V´ZöbÕ^´ZÖ^µZÕ^Õ^ÕZ´Z“V´ZrRg´ZµZ“RÖbÕ^´ZöbÕZ@“V“VÕZrRÕ^g´ZrRrR´ZöbÕ^´ZÕ^µZÕ^´ZÕ^´Z“V´ZrR8g´ZÕ^“RÖ^ÕZ´ZcµZÕ^“V“VÕZrRÕ^g´ZrRrR´ZöbÕ^´ZÕ^µZÕ^´ZÕ^´Z“V´ZrR8g´ZÕ^“RÖ^ÕZ´ZcµZÕ^@“V´ZrRÕ^g´ZrR“RµZgÖ^´ZÕ^Õ^Õ^´ZÕ^“V´Z´ZrRg´ZÕ^rRÕ^´Z´ZgÕZÕ^“V“V´ZrRÕ^g´ZrR“RµZgÖ^´ZÕ^Õ^Õ^´ZÕ^“V´Z´ZrRg´ZÕ^rRÕ^´Z´ZgÕZÕ^“V@´Z“VÕ^öb”ZrR“VÕZ÷böb´ZÕ^Õ^öb´ZÖb“VÕZ´ZrRg´ZµZ“VÕ^´Z´Z8kÕ^Õ^”Z“V´Z“VÕ^öb”ZrR“VÕZ÷böb´ZÕ^Õ^öb´ZÖb“VÕZ´ZrRg´ZµZ“VÕ^´Z´Z8kÕ^Õ^”Z“V@“VÕZÖb´Z“R“VöbÕ^ÕZ“VÕ^Õ^öb´Zöb“VÕ^´Z“R÷b“VÕ^“VÕ^´Z´ZYoÕZÕ^´Z“V´Z“VÕZÖb´Z“R“VöbÕ^ÕZ“VÕ^Õ^öb´Zöb“VÕ^´Z“R÷b“VÕ^“VÕ^´Z´ZYoÕZÕ^´Z“V´Z@ÕZÖbµZ“VrRÕ^öb”Z´ZöbÕ^öb“V÷brRÕ^´Z“Vc“VÕ^“VÕ^´Z´ZYk´ZÕ^µZ“V”Z´ZÕZÖbµZ“VrRÕ^öb”Z´ZöbÕ^öb“V÷brRÕ^´Z“Vc“VÕ^“VÕ^´Z´ZYk´ZÕ^µZ“V”Z´Z@Õ^ÕZ“V“VÖbÖ^´Z´ZÕ^´Zöb“VgrRöb´Z“Vöb“RÕ^“VÕ^´Z´ZYo”ZÕZÕ^“V´Z´Z´ZÕ^ÕZ“V“VÖbÖ^´Z´ZÕ^´Zöb“VgrRöb´Z“Vöb“RÕ^“VÕ^´Z´ZYo”ZÕZÕ^“V´Z´Z´Z@ÕZ”Z“VÕ^Ö^´ZöbÕ^´ZÕ^“VgrR÷b´Z“VÖbrRÕ^“VÕ^´Z´Z9k“VµZÕ^“V´ZµZÕZÕZÕZ”Z“VÕ^Ö^´ZöbÕ^´ZÕ^“VgrR÷b´Z“VÖbrRÕ^“VÕ^´Z´Z9k“VµZÕ^“V´ZµZÕZÕZ@´Z“VÕ^Õ^´Zöb“V“V´Z“VgrRöb´Z“VÕ^rRÕ^“VÕ^´Z´ZYkrR´ZÕ^“V”ZµZ´Z´ZÕZ´Z“VÕ^Õ^´Zöb“V“V´Z“VgrRöb´Z“VÕ^rRÕ^“VÕ^´Z´ZYkrR´ZÕ^“V”ZµZ´Z´ZÕZ@“VÕ^Õ^´Zöb“V´ZÕZ“VgrRÕ^´Z´ZÕ^qRÕ^´ZÖ^´Z´Z8krR´ZÕ^´Z”Z´ZÕ^´ZµZ´Z“VÕ^Õ^´Zöb“V´ZÕZ“VgrRÕ^´Z´ZÕ^qRÕ^´ZÖ^´Z´Z8krR´ZÕ^´Z”Z´ZÕ^´ZµZ´Z@µZµZ´Z÷b“VÕ^“V“VgrRÕ^öbÖ^µZrRÕ^´ZÕ^´Z´Z8kQN´Zöb´Z“V´ZÕ^´Z´ZµZ“VµZµZ´Z÷b“VÕ^“V“VgrRÕ^öbÖ^µZrRÕ^´ZÕ^´Z´Z8kQN´Zöb´Z“V´ZÕ^´Z´ZµZ“V@´Z´Zc“RÕ^“V´ZgrR´ZöbÕ^´ZqRÕ^´ZÖ^´ZµZ8g0JÕ^öb´Z“V´Zöb´Z´Z´Z“VÕ^´Z´Zc“RÕ^“V´ZgrR´ZöbÕ^´ZqRÕ^´ZÖ^´ZµZ8g0JÕ^öb´Z“V´Zöb´Z´Z´Z“VÕ^@´ZgrRöb”Z´Z÷brR´ZöbÕ^´ZqRÕ^´ZÕ^´Z´Z8gFcöb´Z“V´Zöb´Z“V´Z”ZÕ^´Z´ZgrRöb”Z´Z÷brR´ZöbÕ^´ZqRÕ^´ZÕ^´Z´Z8gFcöb´Z“V´Zöb´Z“V´Z”ZÕ^´Z@g“Rc´Z´ZcrR“VöbÕ^´ZqRÕ^”ZÕ^´Z´ZgFcöb´Z“V´Zc´Z“R´Z´ZÖ^´Z´Zg“Rc´Z´ZcrR“VöbÕ^´ZqRÕ^”ZÕ^´Z´ZgFcöb´Z“V´Zc´Z“R´Z´ZÖ^´Z´Z@“Vöb´Z´Z÷bQNöbgöbµZQNÕ^”Z´Z“V´Zg0Jgöb´Z“R´Zg´ZrR´Z´Zöb´Z´Zc“Vöb´Z´Z÷bQNöbgöbµZQNÕ^”Z´Z“V´Zg0Jgöb´Z“R´Zg´ZrR´Z´Zöb´Z´Zc@öb´Z´ZöbrRöbÕ^ÖbÕ^rRÕ^Õ^´Z´Z”ZgQNgÖ^´Z“V“R8g´ZrR´ZµZöb´Z´Zc“Vöb´Z´ZöbrRöbÕ^ÖbÕ^rRÕ^Õ^´Z´Z”ZgQNgÖ^´Z“V“R8g´ZrR´ZµZöb´Z´Zc“V@“VÕZ´ZrRöb÷böbµZrRöböb“VÕZ“VgQNgÕ^´Z“V“Vöb´ZQNÕZÕ^öb´Z´Zc´ZÖ^“VÕZ´ZrRöb÷böbµZrRöböb“VÕZ“VgQNgÕ^´Z“V“Vöb´ZQNÕZÕ^öb´Z´Zc´ZÖ^@´Z´Z“VÕ^öbÕ^Õ^rRöbÖb“VrR´ZgrRgÕ^´Z“V´Z´Z”ZQNµZÕ^c´Z´Zöb´ZÕ^“V´Z´Z“VÕ^öbÕ^Õ^rRöbÖb“VrR´ZgrRgÕ^´Z“V´Z´Z”ZQNµZÕ^c´Z´Zöb´ZÕ^“V@´Z´Z”ZÖbc“VÕ^öböbrRrR´ZgrR8gÕ^“V”Z´Z´Z´ZqRÕ^Õ^g´Z´Zöb´ZÕ^´Z´Z´Z´Z”ZÖbc“VÕ^öböbrRrR´ZgrR8gÕ^“V”Z´Z´Z´ZqRÕ^Õ^g´Z´Zöb´ZÕ^´Z´Z@´Z“V”ZgqRÕ^öbÕ^rRrRÕZ÷b“VgÕZ“V´Z“R´Z´ZrRÖb´Zc´Z´ZöbÕ^µZ´Z´Z´Z´Z“V”ZgqRÕ^öbÕ^rRrRÕZ÷b“VgÕZ“V´Z“R´Z´ZrRÖb´Zc´Z´ZöbÕ^µZ´Z´Z´Z@“VÖ^c“RÕ^cÕZrRrRÕ^öb´Z8g´Zöb“V“V“V´Z“VöbÕ^rR“VÖ^g´Zöb´ZµZ“RÕ^“VÖ^c“RÕ^cÕZrRrRÕ^öb´Z8g´Zöb“V“V“V´Z“VöbÕ^rR“VÖ^g´Zöb´ZµZ“RÕ^@Õ^grR´Zöb´Z“R“VÖbÕ^´ZYk“Vöb´Z“V“V´Z“VcÕ^rR´ZöbÕ^´Zöb“V´ZrRÕ^“VÕ^grR´Zöb´Z“R“VÖbÕ^´ZYk“Vöb´Z“V“V´Z“VcÕ^rR´ZöbÕ^´Zöb“V´ZrRÕ^“V@g“R´ZöbÖ^“R´ZÖb´Z´Z8k“Vöb´Z“V”Z´Z“VÕ^Õ^”Z´ZöbÕ^µZöb“V´ZrRÕ^“VÕ^g“R´ZöbÖ^“R´ZÖb´Z´Z8k“Vöb´Z“V”Z´Z“VÕ^Õ^”Z´ZöbÕ^µZöb“V´ZrRÕ^“VÕ^IMG @­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5MENUTEXT CheckbuttonTEXTIMG1IMG  ÿÿÿÿÿÿÿÿÿ ÿ{o{o{o{o{oÖZÖZÖZ ÿ{o9g9g9g9g9g9g­5 ÿ{o9g9g9g9g9g9g­5 ÿ{o9g9g9g9g9g9g­5 ÿ{o9g9g9g9g9gsN­5 ÿÖZ9g9g9g9g9gsN­5 ÿÖZÖZÖZÖZsNsNsN­5 ÿÖZ­5­5­5­5­5­5­5 IMG  ­5­5­5­5­5­5­5­5­5­5 ­5ÿ ­5­5­5­5sNsNsNsNÿ ­5­5sNsNsNsNsNsNÿ ­5­5sNsNsNsNsNÖZÿ ­5sNsNsNsNsNsNÖZÿ ­5sNsNsNsNsNsNÖZÿ ­5sNsNsNsNsNsNÖZÿ ­5sNsNÖZÖZÖZÖZÖZÿ ÿÿÿÿÿÿÿÿÿÿIMG®  ­5­5­5­5­5­5­5­5­5­5­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ ÿÿÿÿÿÿÿÿÿÿMENUTEXT PosbuttonTEXTIMG1IMGÎ  ÿÿÿÿ{o{oÿÿÿ{o9g{o{oÿÿ ÿ{o9g9g9g{o{oÿÿ ÿ{o9g9g9g9g9g{osN ÿ{o9g9g9g9gsN­5­5 ÿ{o9g9gsN­5­5ÿ{osN­5­5ÿ­5­5IMGÎ  ­5­5­5­5­5­5­5sN­5­5 ­5sNsNsN­5­5 ­5sNsNsNsNsNÿ ­5sNsNsNsNsNsNÖZÿ ­5sNsNsNsNÖZÿÿ­5sNsNÖZÿÿ­5sNÖZÿÿÿÿÿIMGž  ­5­5­5­5­5­5­5­5­5­5­5­5­5ÿ­5ÿ­5ÿÿ­5ÿÿ­5ÿÿÿÿÿMENUTEXT ScrollbarTEXTIMG1IMGÎ  ÿÿÿÿÿ{o{oÿÿ{o{o9gsN ÿÿ{o{o9g9g9gsN ÿ{o{o9g9g9g9g9gsN ­5sN9g9g9g9g9gsN ­5sN9g9g9gsN­5sN9gsN­5sNIMGÎ  ­5­5­5­5­5sN­5­5­5­5ÿ ­5­5­5­5sNsNÿ ­5­5­5sNsNsNsNÿ sNsNsNsNsNsNsNsNsNÿ ÿÿsNsNsNsNsNsNÿÿÿsNsNsNsNÿÿÿsNsNÿÿÿÿIMGž  ­5­5­5­5­5sN­5­5ÿ­5­5ÿ­5ÿ­5ÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÎ  ÿÿÿÿ{o{oÿÿÿ{o9g{o{oÿÿ ÿ{o9g9g9g{o{oÿÿ ÿ{o9g9g9g9g9g{osN ÿ{o9g9g9g9gsN­5­5 ÿ{o9g9gsN­5­5ÿ{osN­5­5ÿ­5­5IMGÎ  ­5­5­5­5­5­5­5sN­5­5 ­5sNsNsN­5­5 ­5sNsNsNsNsNÿ ­5sNsNsNsNsNsNÖZÿ ­5sNsNsNsNÖZÿÿ­5sNsNÖZÿÿ­5sNÖZÿÿÿÿÿIMGž  ­5­5­5­5­5­5­5­5­5­5­5­5­5ÿ­5ÿ­5ÿÿ­5ÿÿ­5ÿÿÿÿÿIMG IMG^@@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€@€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€IMG IMGÎÿÿÿÿÿ{o{o{oÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ{o9g9gÿ9g9g9gÿ9gsN­5IMG^@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@IMGÎÿÿÿ{o9g9g9g9g9g9g9g­59gsN­59gsN­59gsN­59gsN­59gsN­59gsN­59gsN­5sNsN­5­5­5­5IMGÎ  ÿÿ{o­5ÿ{o­5ÿ{o9g9g­5ÿ{o9g9g­5ÿ{o9g9g9g9g­5ÿ{o9g9g9g9g­5 ÿ9g9g9g9g9g9g9g­5 ÿ9g­5­5­5­5­5­5­5 IMGÎ  ­5sN­5sNÿ­5sNÿ­5­5sNsNÿ­5­5sNsNÿ­5­5sNsNsNsNÿ­5­5sNsNsNsNÿ ­5­5sNsNsNsNsNsNÿ ­5­5sNsNsNsNsNsNÿ sNÿÿÿÿÿÿÿÿÿIMGœ  ­5­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ sNÿÿÿÿÿÿÿÿÿIMGÎ  ÿÿÿÿÿÿÿÿÿ ÿ{o{o{o{o{o{o{osN ÿ{o9g9g9g9g9gsN­5ÿ{o9g9g9g9g­5ÿ{o9g9g9gsN­5ÿ9g9g9g­5ÿ9g9gsN­5ÿ9g­5ÿsN­5IMGÎ  ­5 ­5­5­5­5­5­5­5­5ÿ ­5­5sNsNsNsNsNsNÿ­5­5sNsNsNsNÿ­5­5sNsNsNsNÿ­5­5sNsNÿ­5­5sNsNÿ­5sNÿ­5sNÿsNIMGœ  ­5­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿ­5ÿIMG IMGŠ@ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿIMG IMG’ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ{o{o{o{o{o{o{o{o{o{o9g9gÿ{o9g9g9g9g9g9g9g9g9g9gsNÿ{o9g9g9g9g9g9g9g9g9g9g­5IMGŠ@ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5ÿ{o9g9g9g9g9g9g9g9g9g9g­5IMG’ÿ{o9g9g9g9g9g9g9g9g9gsN­5ÿ9g9g9gsNsNsNsNsNsNsNsN­5ÿ9g9g­5­5­5­5­5­5­5­5­5­5MENUTEXTGadgetTEXTIMG1  IMGÊ  µVÖZsN÷^ ­5cRJ1Fcï=Œ1µVÖZ÷^€€ZkµVRJsNRJ”RsN ”RÖZÎ9Œ1ÖZÖZï=B­51FIMGÞ  sN÷^ÖZc1F µVc1Fï=c”Rï=1F”R€RJBÖZ1F”RsNµV÷^ï=1F÷^9gBRJIMGz  ï=ÖZÖZÖZ÷^÷^÷^B€€ZkZk÷^Î9Œ1”RÖZ­5Œ1Î9IMG’ B1FµVBcµV1F€{o”RŒ1ÖZc”RŒ1”R€­5sN­5IMG’ BsN”RsNcRJRJ9gZksNRJ÷^c€1F”RÎ9Bï=­5IMGâ  ï=ï= ”R”RŒ1”R cZkŒ1Î9Î9Î9c ZkZkZkcZkZkcZkB cÎ9Œ1Œ1Î9Œ1c ï=Œ1Œ1Î9Œ1Œ1IMGÚ  B ï=”RcZkcÎ9Œ1Œ1Î9cŒ1Œ1Î9ZkÎ9Œ1cŒ1”RZkZkÎ9Œ1 ï=”RcZkcï=Œ1 ZkIMGÐ   {o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o  {o{o{o{o{o{o{o{o{o{o IMG tR”R•VtR sNsNÖZ×^ tR”RµVµVµVµV¶ZÖZ÷^SN×^ÖZ¶ZµV”RF ”RRJ1FÏ= sNFÎ9ï=Bï=Î9Î9MENUTEXTDividerTEXTIMG1IMG IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG simutrans-124.3/simutrans/themes/classic.tab000066400000000000000000000100641474050137200211770ustar00rootroot00000000000000# Default simutrans theme # # name of the theme (will be shown with file selector) name=Simutrans classic # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 tooltip_text_color = #000000 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # size of tools (negative number: scaling factor in %) icon_scaling = 100 #################################colour stuff################################# gui_color_text = #000000 gui_color_text_highlight = #F8FCF8 gui_color_text_shadow = #000000 gui_color_text_title = #C0FC60 gui_color_text_strong = #C00000 gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #F8FC00 gui_color_edit_text = #F8FCF8 gui_color_edit_text_selected = #A8ACA8 gui_color_edit_text_disabled = #606060 gui_color_edit_background_selected = #404040 gui_color_edit_beam = #F8FCF8 gui_color_chart_background = #989898 gui_color_chart_lines_zero = #D8DCD8 gui_color_chart_lines_odd = #F8FCF8 gui_color_chart_lines_even = #686868 gui_color_list_text_selected_focus = #F8FCF8 gui_color_list_text_selected_nofocus = #C8C8C8 gui_color_list_background_selected_focus = #0000F8 gui_color_list_background_selected_nofocus = #60A0F8 gui_color_obsolete = #0000F8 gui_color_empty = #F8FCF8 gui_color_button_text = #000000 gui_color_button_text_disabled = #686868 gui_color_button_text_selected = #000000 gui_color_colored_button_text = #000000 gui_color_colored_button_text_selected = #F8FCF8 gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #686868 gui_color_ticker_background = #B0B0B0 gui_color_ticker_divider = #000000 gui_color_statusbar_text = #000000 gui_color_statusbar_background = #989898 gui_color_statusbar_divider = #D8DCD8 gui_highlight_color = #D8DCD8 gui_shadow_color = #686868 gui_color_loadingbar_inner = #A8ACA8 gui_color_loadingbar_progress = #0000F8 cursor_overlay_color = #F88000 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #D74700 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) #bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 4 gui_player_color_dark = 1 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #EEEEEE ##################################pakstuff################################## # pak with the images for this theme themeimages=classic.pak simutrans-124.3/simutrans/themes/flat-skin-large.tab000066400000000000000000000101731474050137200225370ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 1 (to not occupy so much screen space) icon_scaling = 150 gui_titlebar_height = 22 gui_gadget_width = 22 gui_tab_header_vsize = 26 gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 toolbar_max_width = 0 toolbar_max_height = 0 gui_button_height = 24 gui_button_width = 100 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat.pak simutrans-124.3/simutrans/themes/flat-skin-touch.tab000066400000000000000000000101751474050137200225710ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat (touch) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears #toolbar_max_width = 0 toolbar_max_height = 1 (to not occupy so much screen space) icon_scaling = 200 gui_titlebar_height = 28 gui_gadget_width = 28 gui_tab_header_vsize = 26 gui_button_text_offset = 7,0,7 gui_color_button_text_offset = 7,0,7 toolbar_max_width = 0 toolbar_max_height = 0 gui_button_height = 28 gui_button_width = 100 gui_scrollbar_width = 28 gui_scrollbar_height = 28 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat-touch.pak simutrans-124.3/simutrans/themes/flat-skin.tab000066400000000000000000000077471474050137200214640ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears icon_scaling = 100 # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat.pak simutrans-124.3/simutrans/themes/flat-touch.pak000066400000000000000000003152001474050137200216310ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=IMG.@@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆIMGlÆï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=ÆIMGvÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=MENUTEXT RoundbuttonTEXTIMG1IMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=IMG.@@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆIMGlÆï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=ÆIMGvÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆÆMENUTEXT EditfieldTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG‚ @@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXTListboxTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG‚ @@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG9gIMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXTBackTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ!@@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMG @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXT TitlebarTEXTIMG1IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG MENUTEXT GadgetBackTEXTIMG166IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMGPï=ï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG MENUTEXT CheckbuttonTEXTIMG1IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ÆÆÆÆÆÆÆÆÆÆ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ ÆÆÆÆÆÆÆÆÆÆMENUTEXT PosbuttonTEXTIMG1IMGT  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€€€”Rÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGT  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿÿÿ”Rï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGT  ÆÆÆÆÆÆÆÆÆÆÆÆ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆÆÆÆÆÆÆÆÆÆÆÆMENUTEXT ScrollbarTEXTIMG1IMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMG²@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMG IMGêï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG²@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGêï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿï=ï=ÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿï=ï=ÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿï=ï=ÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿï=ï=ÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿï=ï=ÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿï=ï=ÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿï=ï=ÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿï=ï=ÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿŒ1Œ1Œ1Œ1Œ1ÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿŒ1Œ1Œ1ÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿŒ1ÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGÒBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBÿÿÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBÿÿÿBBBBBBBBBBBBBBBBBBBBBBBBBBÿBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMG IMGŠ@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMG IMGHï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ@ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=ï=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿï=IMGHï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=MENUTEXTGadgetTEXTIMG1  IMGÒŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1IMG¸ Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1IMG’ Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1  IMG   Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1  IMG Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1IMGÞ  Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1BBŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1BBŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1  IMGºŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1IMGú{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o   {o{o{o{o{o{o{o{o{o{o{o{o {o{o{o{o{o{o{o{o{o{o{o{o {o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o {o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o  {o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG‚  Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1 Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Ï=Ï=Œ1Œ1Œ1Œ1Œ1Œ1Ï=Ï=Œ1Œ1Œ1Œ1Î9Î9ï=ï=Œ1Œ1Œ1Œ1Î9Î9ï=ï=Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1  MENUTEXTDividerTEXTIMG1IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG simutrans-124.3/simutrans/themes/flat.pak000066400000000000000000002251721474050137200205210ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=IMG.@@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆIMGlÆï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=ÆIMGvÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=MENUTEXT RoundbuttonTEXTIMG1IMGvï=ï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvï=ï=ï=ï=ï=ï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=IMGlï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿIMG´@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGlÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=ÿÿÿï=IMGvï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=IMG.@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ÿÿÿÿÿï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=IMG.@@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGvÆÆÆÆÆÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆIMGlÆï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=IMG´@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGlï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=Æï=ï=ï=ÆIMGvÆï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆIMG.@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆIMGvï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=Æï=ï=ï=ï=ï=ÆÆÆÆÆÆÆMENUTEXT EditfieldTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG‚ @@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXTListboxTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG‚ @@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœs@œsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsœsIMGªï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG9gIMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXTBackTEXTIMG1  IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ!@@@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g@9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9g9gIMG @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=MENUTEXT TitlebarTEXTIMG1IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG MENUTEXT GadgetBackTEXTIMG166IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGZï=ï=ï=ï=ï=ï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”Rï=”R”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMGPï=ï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGï=ï=IMG@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=IMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG¨@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGPï=ï=ï=ï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMGlï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”RIMG´@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGl”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=”R”R”Rï=IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG MENUTEXT CheckbuttonTEXTIMG1IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿ€€€€€€ÿï= ï=ÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ÆÆÆÆÆÆÆÆÆÆ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=Æ ÆÆÆÆÆÆÆÆÆÆMENUTEXT PosbuttonTEXTIMG1IMGT  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€€€”Rÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGT  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿÿÿ”Rï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGT  ÆÆÆÆÆÆÆÆÆÆÆÆ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆÆÆÆÆÆÆÆÆÆÆÆMENUTEXT ScrollbarTEXTIMG1IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿ”R€”Rÿÿï= ï=ÿÿÿÿ”R€€”Rÿÿï= ï=ÿÿÿ”R€€€”Rÿÿï= ï=ÿÿ”R€€€€”Rÿÿï= ï=ÿÿÿ”R€€€”Rÿÿï= ï=ÿÿÿÿ”R€€”Rÿÿï= ï=ÿÿÿÿÿ”R€”Rÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=”Rÿ”Rï=ï=ï= ï=ï=ï=ï=ï=”Rÿÿ”Rï=ï=ï= ï=ï=ï=ï=”Rÿÿÿ”Rï=ï=ï= ï=ï=ï=”Rÿÿÿÿ”Rï=ï=ï= ï=ï=ï=ï=”Rÿÿÿ”Rï=ï=ï= ï=ï=ï=ï=ï=”Rÿÿ”Rï=ï=ï= ï=ï=ï=ï=ï=ï=”Rÿ”Rï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ÆÆÆÆÆÆÆÆÆÆÆÆ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1)%Æ)%Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1)%ÆÆ)%Œ1Œ1Æ ÆŒ1Œ1Œ1)%ÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1Œ1)%ÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1)%ÆÆ)%Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1)%Æ)%Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆÆÆÆÆÆÆÆÆÆÆÆIMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€€€”Rÿÿï= ï=ÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€”Rÿÿÿÿï= ï=ÿÿ”R€”Rÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿÿÿ”Rï=ï=ï= ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿ”Rï=ï=ï=ï=ï= ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  ÆÆÆÆÆÆÆÆÆÆÆÆ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆÆ)%Œ1Œ1Æ ÆŒ1Œ1)%ÆÆÆ)%Œ1Œ1Œ1Æ ÆŒ1Œ1)%ÆÆ)%Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1)%Æ)%Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆŒ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Æ ÆÆÆÆÆÆÆÆÆÆÆÆIMG IMGØ@ @”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMG IMGr ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGØ@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGr ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿ”Rÿÿÿÿÿï= ï=ÿÿÿÿ”R€”Rÿÿÿÿï= ï=ÿÿÿ”R€€€”Rÿÿÿï= ï=ÿÿ”R€€€€€”Rÿÿï= ï=ÿÿ€€€€€€€ÿÿï= ï=ÿÿ”R”R”R”R”R”R”Rÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ  ÆÆÆÆÆÆÆÆÆÆÆÆÆ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=)%ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=)%Æ)%ï=ï=ï=ï=Æ Æï=ï=ï=)%ÆÆÆ)%ï=ï=ï=Æ Æï=ï=)%ÆÆÆÆÆ)%ï=ï=Æ Æï=ï=ÆÆÆÆÆÆÆï=ï=Æ Æï=ï=)%)%)%)%)%)%)%ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ ÆÆÆÆÆÆÆÆÆÆÆÆÆIMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=”Rï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï= ï=ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=”Rÿÿÿÿÿ”Rï=ï=ï= ï=ï=ï=ÿÿÿÿÿÿÿï=ï=ï= ï=ï=ï=”R”R”R”R”R”R”Rï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿ”R”R”R”R”R”R”Rÿÿï= ï=ÿÿ€€€€€€€ÿÿï= ï=ÿÿ”R€€€€€”Rÿÿï= ï=ÿÿÿ”R€€€”Rÿÿÿï= ï=ÿÿÿÿ”R€”Rÿÿÿÿï= ï=ÿÿÿÿÿ”Rÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGŠ  ÆÆÆÆÆÆÆÆÆÆÆÆÆ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=)%)%)%)%)%)%)%ï=ï=Æ Æï=ï=ÆÆÆÆÆÆÆï=ï=Æ Æï=ï=)%ÆÆÆÆÆ)%ï=ï=Æ Æï=ï=ï=)%ÆÆÆ)%ï=ï=ï=Æ Æï=ï=ï=ï=)%Æ)%ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=)%ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ Æï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=Æ ÆÆÆÆÆÆÆÆÆÆÆÆÆIMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=”R”R”R”R”R”R”Rï=ï=ï= ï=ï=ï=ÿÿÿÿÿÿÿï=ï=ï= ï=ï=ï=”Rÿÿÿÿÿ”Rï=ï=ï= ï=ï=ï=ï=”Rÿÿÿ”Rï=ï=ï=ï= ï=ï=ï=ï=ï=”Rÿ”Rï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=”Rï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG IMG  @ ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”R ”R”R”R”R”R”R”R”R”R”R”R”R”RIMG IMG*  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG  @ ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï= ï=ÿÿÿÿÿÿÿÿÿÿÿï=IMG*  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=MENUTEXTGadgetTEXTIMG1  IMGþ  €€îƒ!!€€ïƒ!!€€ðƒ€ðƒ€!!!!!€€ §€ïƒ€!!!!€€ §!!!€€ðƒ!!!!!€€ðƒ!!€€§îƒ€!!!€€ðƒ!€€ §€ðƒ€!!€ìƒ€ðƒ€IMG˜ €íƒ€€€îƒ!!!€§€€€ §€îƒ!!!!!!!!!IMG2!!!!!!!!!!IMG€ðƒ€!€€ðƒ€ðƒ€!!€€ðƒ€ïƒ€!!!€€ðƒ€ðƒ€!!!!€€ðƒ€ðƒ€!!!!€€ðƒ€ðƒ€!!!€€ðƒ€ðƒ€!!€€ðƒ€ðƒ€!€€ðƒIMG€ðƒ€!€€ðƒ€ðƒ€!!€€ðƒ€ðƒ€!!!€€ïƒ€ðƒ€!!!!€€ðƒ€ðƒ€!!!!€€ðƒ€ðƒ€!!!€€ðƒ€ðƒ€!!€€ðƒ€ðƒ€!€€ðƒIMGæ  €ïƒ€ïƒ!€€ïƒ€ïƒ€!!!€€ïƒ€ïƒ€Œ1!€ïƒ€!!Œ1!!!! !!!!!!!!B€ïƒ€!!Œ1Œ1!Œ1!!Œ1€€ïƒ€ïƒ€Œ1!Œ1€€ïƒ€ïƒ€Œ1€ïƒ€ïƒIMGê  €ïƒ€B€€ïƒ€ïƒ€!!!!!!Œ1€€ïƒ€ïƒ€Œ1!!Œ1Œ1€€ïƒ€ïƒ€!!!€€ïƒ€ïƒ€Œ1!Œ1€€ïƒ€ïƒ€!!!!Œ1€€ïƒ€ïƒ€!!!!!!Œ1€€ïƒ€ïƒ€€€ïƒ!IMGD{o{o{o{o{oIMGj  €ðƒ€€€ïƒîƒ€ïƒ€ðƒþƒ€ðƒ€ïƒÿƒðƒ€ §€€€§€ðƒ€€€ §€!€€ðƒ€ðƒ€!€€ðƒ!€€§€§€!!€îƒ€!€€ðƒ€ðƒ€!€€§§§€€§€€§€ðƒ€!€€ §€ïƒ€!€€§€ §§íƒ€€ðƒ§€!€€§§€€€íƒMENUTEXTDividerTEXTIMG1IMG IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG simutrans-124.3/simutrans/themes/high-contrast-large.tab000066400000000000000000000122221474050137200234160ustar00rootroot00000000000000# # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=High Contrast (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #000000 # tooltip text color (240=black, 215=white) tooltip_text_color = 215 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # make the chat window transparent in network games gui_chat_window_network_transparency = 13 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #000000 #################################colour stuff################################# default_window_title_color = #194766 gui_color_text = #c98926 gui_color_text_highlight = #FAFAFA gui_color_text_shadow = #868c86 gui_color_text_title = #bee6c1 #gui_color_text_strong = #E46A0B gui_color_empty = #FAFAFA gui_color_obsolete = #2878ff gui_color_edit_text = #c98926 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #868c86 gui_color_edit_background_selected = #5686a6 gui_color_edit_beam = #ffffff gui_color_chart_background = #333333 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #39a1e6 gui_color_chart_lines_even = #ffffff gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #5686a6 gui_color_list_background_selected_nofocus = #5686a6 gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #868c86 gui_color_button_text_selected = #b3b3b3 gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #b3b3b3 gui_color_checkbox_text = #c98926 gui_color_checkbox_text_disabled = #868c86 gui_color_ticker_background = #000000 gui_color_ticker_divider = #ffffff gui_color_statusbar_text = #c98926 gui_color_statusbar_background = #000000 gui_color_statusbar_divider = #ffffff gui_highlight_color = #ffffff gui_shadow_color = #ffffff # gui_color_text_minus = #C00000 gui_color_text_plus = #c98926 # gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #000000 # Color of load bar in loag game, load serve etc gui_color_loadingbar_progress = #000000 gui_color_loadingbar_inner = #868c86 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #ffffff gui_player_color_dark = 5 gui_player_color_bright = 5 ##################################size stuff################################## # force main menu icon size icon_scaling = 150 # titlebar height gui_titlebar_height = 22 gui_gadget_width = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 26 # gui_label_size = 24 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 24 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 24 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=highcontrast-large.pak simutrans-124.3/simutrans/themes/high-contrast.tab000066400000000000000000000120751474050137200223340ustar00rootroot00000000000000# # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=High Contrast # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #000000 # tooltip text color (240=black, 215=white) tooltip_text_color = 215 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # make the chat window transparent in network games gui_chat_window_network_transparency = 13 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #000000 #################################colour stuff################################# default_window_title_color = #194766 gui_color_text = #c98926 gui_color_text_highlight = #FAFAFA gui_color_text_shadow = #868c86 gui_color_text_title = #bee6c1 #gui_color_text_strong = #E46A0B gui_color_empty = #FAFAFA gui_color_obsolete = #2878ff gui_color_edit_text = #c98926 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #868c86 gui_color_edit_background_selected = #5686a6 gui_color_edit_beam = #ffffff gui_color_chart_background = #333333 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #39a1e6 gui_color_chart_lines_even = #ffffff gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #5686a6 gui_color_list_background_selected_nofocus = #5686a6 gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #868c86 gui_color_button_text_selected = #b3b3b3 gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #b3b3b3 gui_color_checkbox_text = #c98926 gui_color_checkbox_text_disabled = #868c86 gui_color_ticker_background = #000000 gui_color_ticker_divider = #ffffff gui_color_statusbar_text = #c98926 gui_color_statusbar_background = #000000 gui_color_statusbar_divider = #ffffff gui_highlight_color = #ffffff gui_shadow_color = #ffffff # gui_color_text_minus = #C00000 gui_color_text_plus = #c98926 # gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #000000 # Color of load bar in loag game, load serve etc gui_color_loadingbar_progress = #000000 gui_color_loadingbar_inner = #868c86 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #ffffff gui_player_color_dark = 5 gui_player_color_bright = 5 ##################################size stuff################################## # force main menu icon size icon_scaling = 100 # titlebar height gui_titlebar_height = 15 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 22 # gui_label_size = 24 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 16 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=highcontrast.pak simutrans-124.3/simutrans/themes/highcontrast-large.pak000066400000000000000000002662421474050137200233630ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï= ï=ï=! ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï=IMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=c c ï=ï=!Zkÿ! ï=ï=RJÿÿ! ï=ï=Œ1!J)ÿÿB ï=ï=Bÿ÷^!c ÿÿ÷^ ï=ï=!ÿÿ÷^œsÿœs! ï=ï=Bÿÿÿÿc ï=ï=Bÿÿ! ï=ï=Î9Î9 ï=ï=IMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï= ï=ï=J)ÿÿ!!ÿÿJ) ï=ï=ÖZÿZkÆZkÿÖZ ï=ï=BœsÿÞ{ÿœsB ï=ï=!ÿÿÿ! ï=ï=Î9ÿÿÿÎ9! ï=ï=„Þ{ÿÞ{ÿÞ{„ ï=ï=cÿœs„œsÿc ï=ï=Î9ÿÿJ)J)ÿÿÎ9 ï=ï=Æ!!!!ÆIMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMG®  ||||||||||||| |||||||||||||||||||||||||||||||||IMG@@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||IMG‚ ||||||||||||||||||||||||IMG||IMG IMG||IMGJ  ||||||||||||| |||||||||||||IMG@@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||IMG||||MENUTEXT RoundbuttonTEXTIMG1IMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNIMGsNsNsNsNIMG@@@IMGsNsNsNsNIMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNIMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNIMGsNsNsNsNIMG@@@IMGsNsNsNsNIMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNIMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNIMGsNsNsNsNIMG@@@IMGsNsNsNsNIMGsNsNsNsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNsNsNsNMENUTEXT EditfieldTEXTIMG1  IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿMENUTEXTListboxTEXTIMG1  IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿMENUTEXTBackTEXTIMG1  IMGÿÿÿÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMGŠ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿMENUTEXT CheckbuttonTEXTIMG1IMGî¥BÞ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ{B¥BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBÞ{ÿBBÿÞ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ{ÿBBÿÞ{BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB¥BÞ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ{B¥IMGî¥BÞ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ{B¥BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBÞ{ÿBBÿÞ{ÿÿÿÿÿÿÿÿÿÿ!BB!ÿÿÿÿc çç¥!ÿÿÿÿ!Œ19g9g”R!„ÿÿÿÿ!çcÿÿÞ{ï=!ÿÿÿÿÆ”Rœsÿÿ½wÎ9!ÿÿÿÿc 1F½wÿÿÿc)%„ÿÿÿÿ„„!J)€ÿÿÿœsï=c ÿÿÿÿ!„ï=1Fç!!!ÖZÞ{ÿÿ€1F„ÿÿÿÿk-BZkœs÷^)%!c ”R½wÿÿÿÖZ¥ÿÿÿÿRJÖZÿÿÿ÷^çBc ­5½wÿÿÞ{c)%ÿÿÿÿk-1F½wÿÿœs”RB”RZkÿÿÿ{o)%!ÿÿÿÿ„!÷^ÿÿÿÞ{Þ{ÿÿÿÿ{o­5!ÿÿÿÿc Î9œsÿÿÿÿÿÿÿ½wÎ9Bÿÿÿÿ„BZkÿÿÿÿÿ½wsNc ÿÿÿÿ„ï=œsÿÿÿÞ{”Rç!ÿÿÿÿ„B9g½w½w÷^!!ÿÿÿÿ„€µVµVŒ1Bÿÿÿÿ!)%1F1F)%!ÿÿÞ{ÿBBÿÞ{BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB¥BÞ{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ{B¥IMGîc J)sN”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RsNJ)c J)”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RJ)sN”RJ)J)”RsN”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R!”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RsN”RJ)J)”RsNJ)”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RJ)c J)sN”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RsNJ)c MENUTEXT PosbuttonTEXTIMG1IMG:ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG: w w w w w w w w w w w w  w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w  w w w w w w w w w w w w w w w w w w w w w wIMG:sNsNsNsNsNsNsNsNsNsNsNsN sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNMENUTEXT ScrollbarTEXTIMG1IMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1ÖZcÿÿÿÿJ)”RÞ{ÿÿcÿÿÿÿÆRJœsÿÿÿÿÿcÿÿÿÿ„Î9œsÿÿÿÿÿÿÿÿcÿÿÿÿBŒ1ZkÿÿÿÿÿÿÿÿZkRJÆÿÿÿÿ!ÿÿÿÿÿÿÿÖZÎ9„ÿÿÿÿ!ÿÿÿÞ{”RJ)Bÿÿÿÿ!ÿÿÿÞ{”RJ)Bÿÿÿÿ!ÿÿÿÿÿÿÿÖZÎ9„ÿÿÿÿBŒ1ZkÿÿÿÿÿÿÿÿZkRJÆÿÿÿÿ„Î9œsÿÿÿÿÿÿÿÿcÿÿÿÿÆRJœsÿÿÿÿÿcÿÿÿÿJ)”RÞ{ÿÿcÿÿÿÿŒ1ÖZcÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@)`N Vÿÿÿÿ% F@k€s€s Vÿÿÿÿ Bg€s€s€s€s€s Vÿÿÿÿ` €1g€s€s€s€s€s€s€s€s Vÿÿÿÿ @)à^€s€s€s€s€s€s€s€sà^B ÿÿÿÿà€s€s€s€s€s€s€s`N€1` ÿÿÿÿà€s€s€s@k F% ÿÿÿÿà€s€s€s@k F% ÿÿÿÿà€s€s€s€s€s€s€s`N€1` ÿÿÿÿ @)à^€s€s€s€s€s€s€s€sà^B ÿÿÿÿ` €1g€s€s€s€s€s€s€s€s Vÿÿÿÿ Bg€s€s€s€s€s Vÿÿÿÿ% F@k€s€s Vÿÿÿÿ@)`N VÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç­5Î9ÿÿÿÿÆŒ1RJsNsNÎ9ÿÿÿÿc J)BsNsNsNsNsNÎ9ÿÿÿÿB!BsNsNsNsNsNsNsNsNÎ9ÿÿÿÿ!çï=sNsNsNsNsNsNsNsNï=J)c ÿÿÿÿ„sNsNsNsNsNsNsN­5!Bÿÿÿÿ„sNsNsNRJŒ1Æ!ÿÿÿÿ„sNsNsNRJŒ1Æ!ÿÿÿÿ„sNsNsNsNsNsNsN­5!Bÿÿÿÿ!çï=sNsNsNsNsNsNsNsNï=J)c ÿÿÿÿB!BsNsNsNsNsNsNsNsNÎ9ÿÿÿÿc J)BsNsNsNsNsNÎ9ÿÿÿÿÆŒ1RJsNsNÎ9ÿÿÿÿç­5Î9ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcÖZŒ1ÿÿÿÿcÿÿÞ{”RJ)ÿÿÿÿcÿÿÿÿÿœsRJÆÿÿÿÿcÿÿÿÿÿÿÿÿœsÎ9„ÿÿÿÿÆRJZkÿÿÿÿÿÿÿÿZkŒ1Bÿÿÿÿ„Î9ÖZÿÿÿÿÿÿÿ!ÿÿÿÿBJ)”RÞ{ÿÿÿ!ÿÿÿÿBJ)”RÞ{ÿÿÿ!ÿÿÿÿ„Î9ÖZÿÿÿÿÿÿÿ!ÿÿÿÿÆRJZkÿÿÿÿÿÿÿÿZkŒ1BÿÿÿÿcÿÿÿÿÿÿÿÿœsÎ9„ÿÿÿÿcÿÿÿÿÿœsRJÆÿÿÿÿcÿÿÞ{”RJ)ÿÿÿÿcÖZŒ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ V`N@)ÿÿÿÿ V€s€s@k F%ÿÿÿÿ V€s€s€s€s€sgB ÿÿÿÿ V€s€s€s€s€s€s€s€sg€1` ÿÿÿÿ Bà^€s€s€s€s€s€s€s€sà^@) ÿÿÿÿ` €1`N€s€s€s€s€s€s€sàÿÿÿÿ % F@k€s€s€sàÿÿÿÿ % F@k€s€s€sàÿÿÿÿ` €1`N€s€s€s€s€s€s€sàÿÿÿÿ Bà^€s€s€s€s€s€s€s€sà^@) ÿÿÿÿ V€s€s€s€s€s€s€s€sg€1` ÿÿÿÿ V€s€s€s€s€sgB ÿÿÿÿ V€s€s@k F%ÿÿÿÿ V`N@)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÎ9­5çÿÿÿÿÎ9sNsNRJŒ1ÆÿÿÿÿÎ9sNsNsNsNsNBJ)c ÿÿÿÿÎ9sNsNsNsNsNsNsNsNB!Bÿÿÿÿc J)ï=sNsNsNsNsNsNsNsNï=ç!ÿÿÿÿB!­5sNsNsNsNsNsNsN„ÿÿÿÿ!ÆŒ1RJsNsNsN„ÿÿÿÿ!ÆŒ1RJsNsNsN„ÿÿÿÿB!­5sNsNsNsNsNsNsN„ÿÿÿÿc J)ï=sNsNsNsNsNsNsNsNï=ç!ÿÿÿÿÎ9sNsNsNsNsNsNsNsNB!BÿÿÿÿÎ9sNsNsNsNsNBJ)c ÿÿÿÿÎ9sNsNRJŒ1ÆÿÿÿÿÎ9­5çÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMGš @@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@@@@@@@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@IMG IMGúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGš @@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@@@@@@@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB!!!!BÿÿÿÿŒ1ÿÿÿÿŒ1ÿÿÿÿZkÿÿÿÿZkÿÿÿÿ„ÿÿÿÿÿÿ„ÿÿÿÿÎ9ÿÿÞ{Þ{ÿÿÎ9ÿÿÿÿœsÿÿ”R”RÿÿœsÿÿÿÿÆÿÿÿJ)J)ÿÿÿÆÿÿÿÿRJÿÿÿBBÿÿÿRJÿÿÿÿœsÿÿÖZÖZÿÿœsÿÿÿÿJ)ÿÿÿÎ9Î9ÿÿÿJ)ÿÿÿÿ”Rÿÿÿ„„ÿÿÿ”RÿÿÿÿÞ{ÿÿZkZkÿÿÞ{ÿÿÿÿŒ1ÿÿÿRJRJÿÿÿŒ1ÿÿÿÿÖZÿÿÿÆÆÿÿÿÖZÿÿÿÿccccccccÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!„„„„!ÿÿÿÿçsNsNsNsNçÿÿÿÿï=sNsNsNsNï=ÿÿÿÿBsNsNsNsNsNsNBÿÿÿÿ!sNsNRJRJsNsN!ÿÿÿÿBsNsNŒ1Œ1sNsNBÿÿÿÿc sNsNsNÆÆsNsNsNc ÿÿÿÿJ)sNsNsN!!sNsNsNJ)ÿÿÿÿBsNsN­5­5sNsNBÿÿÿÿÆsNsNsN!!sNsNsNÆÿÿÿÿŒ1sNsNsNBBsNsNsNŒ1ÿÿÿÿRJsNsNï=ï=sNsNRJÿÿÿÿçsNsNsNJ)J)sNsNsNçÿÿÿÿ­5sNsNsNc c sNsNsN­5ÿÿÿÿÎ9Î9Î9Î9Î9Î9Î9Î9ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ àààà ÿÿÿÿ@)€s€s€s€s@)ÿÿÿÿà^€s€s€s€sà^ÿÿÿÿ` €s€s€s€s€s€s` ÿÿÿÿ€1€s€s@k@k€s€s€1ÿÿÿÿg€s€s F F€s€sgÿÿÿÿ €s€s€s%%€s€s€s ÿÿÿÿB€s€s€s  €s€s€sBÿÿÿÿg€s€s`N`N€s€sgÿÿÿÿ%€s€s€s€1€1€s€s€s%ÿÿÿÿ F€s€s€s` ` €s€s€s Fÿÿÿÿ@k€s€sà^à^€s€s@kÿÿÿÿ@)€s€s€sBB€s€s€s@)ÿÿÿÿ`N€s€s€s  €s€s€s`Nÿÿÿÿ V V V V V V V VÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿccccccccÿÿÿÿÖZÿÿÿÆÆÿÿÿÖZÿÿÿÿŒ1ÿÿÿRJRJÿÿÿŒ1ÿÿÿÿÞ{ÿÿZkZkÿÿÞ{ÿÿÿÿ”Rÿÿÿ„„ÿÿÿ”RÿÿÿÿJ)ÿÿÿÎ9Î9ÿÿÿJ)ÿÿÿÿœsÿÿÖZÖZÿÿœsÿÿÿÿRJÿÿÿBBÿÿÿRJÿÿÿÿÆÿÿÿJ)J)ÿÿÿÆÿÿÿÿœsÿÿ”R”RÿÿœsÿÿÿÿÎ9ÿÿÞ{Þ{ÿÿÎ9ÿÿÿÿ„ÿÿÿÿÿÿ„ÿÿÿÿZkÿÿÿÿZkÿÿÿÿŒ1ÿÿÿÿŒ1ÿÿÿÿB!!!!BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÎ9Î9Î9Î9Î9Î9Î9Î9ÿÿÿÿ­5sNsNsNc c sNsNsN­5ÿÿÿÿçsNsNsNJ)J)sNsNsNçÿÿÿÿRJsNsNï=ï=sNsNRJÿÿÿÿŒ1sNsNsNBBsNsNsNŒ1ÿÿÿÿÆsNsNsN!!sNsNsNÆÿÿÿÿBsNsN­5­5sNsNBÿÿÿÿJ)sNsNsN!!sNsNsNJ)ÿÿÿÿc sNsNsNÆÆsNsNsNc ÿÿÿÿBsNsNŒ1Œ1sNsNBÿÿÿÿ!sNsNRJRJsNsN!ÿÿÿÿBsNsNsNsNsNsNBÿÿÿÿï=sNsNsNsNï=ÿÿÿÿçsNsNsNsNçÿÿÿÿ!„„„„!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ V V V V V V V Vÿÿÿÿ`N€s€s€s  €s€s€s`Nÿÿÿÿ@)€s€s€sBB€s€s€s@)ÿÿÿÿ@k€s€sà^à^€s€s@kÿÿÿÿ F€s€s€s` ` €s€s€s Fÿÿÿÿ%€s€s€s€1€1€s€s€s%ÿÿÿÿg€s€s`N`N€s€sgÿÿÿÿB€s€s€s  €s€s€sBÿÿÿÿ €s€s€s%%€s€s€s ÿÿÿÿg€s€s F F€s€sgÿÿÿÿ€1€s€s@k@k€s€s€1ÿÿÿÿ` €s€s€s€s€s€s` ÿÿÿÿà^€s€s€s€sà^ÿÿÿÿ@)€s€s€s€s@)ÿÿÿÿ àààà ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMGŠ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMGvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMENUTEXTGadgetTEXTIMG1  IMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ)cccÖZÖZcccJ)ÿÿÿÿBœsÿÿÿBBÿÿÿœsBÿÿÿÿ!ÿÿÿÞ{„„Þ{ÿÿÿ!ÿÿÿÿRJÿÿÿÖZÖZÿÿÿRJÿÿÿÿBœsÿÿÿÿÿÿœsBÿÿÿÿ!ÿÿÿÿÿÿ!ÿÿÿÿRJÿÿÿÿRJÿÿÿÿÖZÿÿÿÿÖZÿÿÿÿJ)ÿÿÿÿÿÿJ)ÿÿÿÿ„Þ{ÿÿÞ{Þ{ÿÿÞ{„ÿÿÿÿcÿÿÿBBÿÿÿcÿÿÿÿÎ9ÿÿÿœsœsÿÿÿÎ9ÿÿÿÿ„Þ{ÿÿÿ!!ÿÿÿÞ{„ÿÿÿÿZkÿÿÿÖZÖZÿÿÿZkÿÿÿÿ!!!!BB!!!!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ)”R”R”R”RŒ1ÿÿÿÿB½wÿÿÿÿÿÿœsJ)ÿÿÿÿJ)ÿÿÿÿÿÿÿÿÿ½wÿÿÿÿÖZÿÞ{ÖZ”R”R½wÿÿÿŒ1ÿÿÿÿ÷^„çÿÿÿ”Rÿÿÿÿ„ÿÿÿRJÿÿÿÿçZkÿÿÿJ)ÿÿÿÿç÷^ÿÿÿÿ÷^ÿÿÿÿçÞ{ÿÿÿÿÖZÿÿÿÿŒ1ÿÿÿœsçÿÿÿÿŒ1ÿÿÿJ)ÿÿÿÿJ)ZkZkZkÿÿÿÿJ)ÿÿÿÿ”Rÿÿ½wçÿÿÿÿÿÿÿÿ”RÿÿÿÿœsÿÿÿŒ1ÿÿÿÿ„B”RJ)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ZkZkZkçZkZkZkZkÿÿÿÿ÷^ÿÿÿRJJ)ÿÿÿ€ÿÿÿÿï=ÿÿÿ€ÖZÿÿÿBÿÿÿÿÞ{ÿÿÿ„œsÿÿÞ{ÿÿÿÿÖZÿÿÿï=çÿÿÿ÷^ÿÿÿÿJ)ÿÿÿ÷^RJÿÿÿï=ÿÿÿÿ½wÿÿÞ{€ÿÿ½wÿÿÿÿRJÿÿÿJ)„ÿÿÿÖZÿÿÿÿçÿÿÿÖZï=ÿÿÿJ)ÿÿÿÿœsÿÿœs÷^ÿÿ½wÿÿÿÿBÿÿÿÞ{ÿÿRJÿÿÿÿ„ÿÿÿÿÿÿçÿÿÿÿ€ÿÿÿÿœsÿÿÿÿBÿÿÿÿBÿÿÿÿŒ1Œ1Œ1Œ1„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç”RBÿÿÿÿBZkÿÿ”RÿÿÿÿçÖZÞ{ÿÿÿÿ”Rÿÿÿÿ„BœsÿÿÿÿÿZkB„ÿÿÿÿJ)÷^Þ{ÿÿÿÿ½w”RçÿÿÿÿœsÿÿÿÿÞ{÷^Œ1ÿÿÿÿÿÿÿÞ{RJ„ÿÿÿÿÿÿÿÿÞ{÷^Œ1ÿÿÿÿŒ1÷^Þ{ÿÿÿÿ½w”Rçÿÿÿÿ„Bœsÿÿÿÿÿ€BÿÿÿÿçÖZÞ{ÿÿÿÿÞ{BÿÿÿÿB€ÿÿÿ”Rÿÿÿÿç”R½w”RÿÿÿÿçÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1B„ÿÿÿÿBÿÿcŒ1ÿÿÿÿBÿÿÿÿÞ{RJ„ÿÿÿÿBŒ1cÿÿÿÿÿZkŒ1Bÿÿÿÿ„BœsÿÿÿÿÞ{”RÆÿÿÿÿ!”RÞ{ÿÿÿÿZkÿÿÿÿBÎ9Þ{ÿÿÿÿÿÿÿ!”RÞ{ÿÿÿÿÿÿÿÿ„BœsÿÿÿÿÞ{”R!ÿÿÿÿŒ1ÖZÿÿÿÿÿZkŒ1BÿÿÿÿŒ1Þ{ÿÿÿÿÞ{RJ„ÿÿÿÿBÿÿÿÖZŒ1ÿÿÿÿBœsB„ÿÿÿÿ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç„ÿÿÿÿ„9gçÿÿÿÿ!ÿÎ9ÿÿÿÿÎ9ÿµVB„J)ÿÿÿÿÖZÿZk!¥œsÿ!ÿÿÿÿBZkÿ”R„œsÿÿŒ1ÿÿÿÿç”R¥€ÿÿÿk-ÿÿÿÿ„œsÿœsÞ{ÿ­5ÿÿÿÿ¥€ÿ÷^€ÿÿ{o„ÿÿÿÿ¥€ÿ÷^ç½wÿÿÿœsçÿÿÿÿ„œsÿ{oƵVÿÿÿÿÿÞ{Zk€­5ÿÿÿÿ)%ÿÿÿÿÿÿÿÿÿÿÿÿµV!ÿÿÿÿçk-k-Î9œsÿÿÿÿÿÿRJÿÿÿÿÆœsÿÞ{ÿÿsNÿÿÿÿƽwÿÿsNÿÿÿÿZkÿ1FÿÿÿÿœssNÿÿÿÿk-ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿk-ÿÿÿÿœssNÿÿÿÿZkÿ1FÿÿÿÿƽwÿÿsNÿÿÿÿÆœsÿÞ{ÿÿsNÿÿÿÿçk-k-Î9œsÿÿÿÿÿÿRJÿÿÿÿ)%ÿÿÿÿÿÿÿÿÿÿÿÿµV!ÿÿÿÿ„œsÿ{oƵVÿÿÿÿÿÞ{Zk€­5ÿÿÿÿ¥€ÿ÷^ç½wÿÿÿœsçÿÿÿÿ¥€ÿ÷^€ÿÿ{o„ÿÿÿÿ„œsÿœsÞ{ÿ­5ÿÿÿÿç”R¥€ÿÿÿk-ÿÿÿÿBZkÿ”R„œsÿÿŒ1ÿÿÿÿÖZÿZk!¥œsÿ!ÿÿÿÿÎ9ÿµVB„J)ÿÿÿÿ!ÿÎ9ÿÿÿÿ„9gçÿÿÿÿç„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGzÿÿÿ ÿ ÿÿÿÿ ÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„k-RJ”R”RRJk-„ÿÿÿÿ„sN½wÿÿÿÿÿÿ½wsN„ÿÿÿÿŒ1½wÿÿÿ½w€€½wÿÿÿ½wŒ1ÿÿÿÿÎ9ÿÿÞ{ÿ÷^„„÷^ÿÞ{ÿÿÎ9ÿÿÿÿŒ1ÿÞ{Þ{Þ{œsc BBc œsÞ{Þ{Þ{ÿŒ1ÿÿÿÿ{oÞ{½w½wÿµVc œs{oBµVÿ½w½wÞ{{oÿÿÿÿ9gÞ{½w½wÞ{”Rc {o{oB”RÞ{½w½wÞ{9gÿÿÿÿ!½w½wœs½w{oc c Bc {o½wœs½w½w!ÿÿÿÿ)%{o½wœs½wÖZ„„ÖZ½wœs½w{o)%ÿÿÿÿ¥ÖZ½wœs½wZk”R”RZk½wœs½wÖZ¥ÿÿÿÿŒ1cœs½wÞ{Þ{½wœscŒ1ÿÿÿÿ!!ï=1F1Fï=!!ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMENUTEXTDividerTEXTIMG1IMG IMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG simutrans-124.3/simutrans/themes/highcontrast.pak000066400000000000000000002027361474050137200222710ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï= ï=ï=! ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï= ï=ï=IMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=c c ï=ï=!Zkÿ! ï=ï=RJÿÿ! ï=ï=Œ1!J)ÿÿB ï=ï=Bÿ÷^!c ÿÿ÷^ ï=ï=!ÿÿ÷^œsÿœs! ï=ï=Bÿÿÿÿc ï=ï=Bÿÿ! ï=ï=Î9Î9 ï=ï=IMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMGŠ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï= ï=ï=J)ÿÿ!!ÿÿJ) ï=ï=ÖZÿZkÆZkÿÖZ ï=ï=BœsÿÞ{ÿœsB ï=ï=!ÿÿÿ! ï=ï=Î9ÿÿÿÎ9! ï=ï=„Þ{ÿÞ{ÿÞ{„ ï=ï=cÿœs„œsÿc ï=ï=Î9ÿÿJ)J)ÿÿÎ9 ï=ï=Æ!!!!ÆIMGR@ @ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@@@@@@@@@@IMG‚ ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG*  ï=ï=IMG@@IMGï=ï=IMGJ  ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï= ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGï=ï=ï=ï=IMG®  ||||||||||||| |||||||||||||||||||||||||||||||||IMG@@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||IMG‚ ||||||||||||||||||||||||IMG||IMG IMG||IMGJ  ||||||||||||| |||||||||||||IMG@@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||@||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||IMG||||MENUTEXT RoundbuttonTEXTIMG1IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMGÿIMG@@IMGÿIMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG€sIMG@@€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€sIMG€sIMG€sIMG@@IMG€sIMG€sIMG@@€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€s€sIMG€sIMGsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNIMGsNIMG@@IMGsNIMGsNIMG@@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGsNMENUTEXT EditfieldTEXTIMG1  IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿMENUTEXTListboxTEXTIMG1  IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿMENUTEXTBackTEXTIMG1  IMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@IMG @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿMENUTEXT CheckbuttonTEXTIMG1IMGª  ÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ ÿÿ ÿBÿ ÿÿ ÿBÿ ÿBÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿIMGª  ÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿ ÿÆÆÿ ÿB€ÿŒ1ÿ ÿµVÿÿŒ1ÿ ÿBBÎ9ÿÿsNÿ ÿsNÿ9gBÆÿÿ9gÿ ÿŒ1ÿÿ9g½wÿ½wBÿ ÿsNÿÿÿÿÆÿ ÿsNÿÿŒ1ÿ ÿ1F1Fÿ ÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿIMGª  µVµVµVµVµVµVµVµVµVµVµVµVµV µVµV µVµV µVBµV µVµV µVBµV µVBµV µVµV µVµV µVµV µVµV µVµV µVµVµVµVµVµVµVµVµVµVµVµVµVMENUTEXT PosbuttonTEXTIMG1IMG$ ÿk-ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿk-ÿÿÿIMG$  w 5 w w w w w w w w w w w w w w w w w w w w w w w  w w w w w w w w w w w  w w w w w w w w w w w w  w w w w w w w w w w w w w w w w w w w w w w w w w w w w 5 w w wIMG$ sNÆsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN sNsNsNsNsNsNsNsNsNsNsN sNsNsNsNsNsNsNsNsNsNsNsN sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNÆsNsNsNMENUTEXT ScrollbarTEXTIMG1IMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçÖZBÿÿ„RJœsÿÿ”Rÿÿ„Bÿÿÿÿÿÿ”Rÿÿ”RÞ{ÿÿÿÿ½w÷^ï=ÿÿZkÿÿœs”RJ)ÿÿZkÿÿœs”RJ)ÿÿ”RÞ{ÿÿÿÿ½w÷^ï=ÿÿ„Bœsÿÿÿÿÿ”Rÿÿ„RJœsÿÿ”RÿÿçÖZBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà€Rà=ÿÿ€ F k w w@Jÿÿ€à= w w w w w w@Jÿÿ@J€s w w w w`o Z 9ÿÿc w w k@J %ÿÿc w w k@J %ÿÿ@J€s w w w w`o Z 9ÿÿ€à=@k w w w w w@Jÿÿ€ F k w w@Jÿÿà€Rà=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„­5J)ÿÿBk-BsNsNŒ1ÿÿBJ)÷ZsNsNsNsNsNŒ1ÿÿŒ1RJsNsNsNsN1FÎ9)%ÿÿBsNsNBŒ1ÆÿÿBsNsNBŒ1ÆÿÿŒ1RJsNsNsNsN1FÎ9)%ÿÿBJ)1FsNsNsNsNsNŒ1ÿÿBk-BsNsNŒ1ÿÿ„­5J)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBÖZçÿÿ”RÿÿœsRJ„ÿÿ”RÿÿÿÿÿœsB„ÿÿï=÷^½wÿÿÿÿÞ{”RÿÿJ)”RœsÿÿZkÿÿJ)”RœsÿÿZkÿÿï=÷^½wÿÿÿÿÞ{”Rÿÿ”RÿÿÿÿÿÿB„ÿÿ”RÿÿœsRJ„ÿÿBÖZçÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà=€Ràÿÿ@J w w k F€ÿÿ@J w w w w w@kà=€ÿÿ 9 Z`o w w w w€s@Jÿÿ %@J k w wcÿÿ %@J k w wcÿÿ 9 Z`o w w w w€s@Jÿÿ@J w w w w w wà=€ÿÿ@J w w k F€ÿÿà=€RàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ)­5„ÿÿŒ1sNsNBk-BÿÿŒ1sNsNsNsNsN÷ZJ)Bÿÿ)%Î91FsNsNsNsNRJŒ1ÿÿÆŒ1BsNsNBÿÿÆŒ1BsNsNBÿÿ)%Î91FsNsNsNsNRJŒ1ÿÿŒ1sNsNsNsNsN1FJ)BÿÿŒ1sNsNBk-BÿÿJ)­5„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMGj@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@IMG IMGŠÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGj@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@@@@@@@@@@@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ”RZkZk”Rÿÿ„Þ{ÿÿÞ{„ÿÿBÿÿÿÿBÿÿÿÿœsœsÿœsÿÿ„ÿÿ”R”Rÿÿ„ÿÿRJÿÿJ)J)ÿÿRJÿÿœsÿ½w½wÿœsÿÿçÿÿ÷^÷^ÿÿçÿÿÖZÿÿï=ï=ÿÿÖZÿÿB”R”R”R”RBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1BBŒ1ÿÿBRJsNsNRJBÿÿJ)sNsNsNsNJ)ÿÿ÷ZsNBBsN1FÿÿBsNsNŒ1Œ1sNsNBÿÿk-sNsNÆÆsNsNk-ÿÿBsN1F1FsNBÿÿ„sNsNÎ9Î9sNsN„ÿÿ­5sNsN)%)%sNsN­5ÿÿJ)Œ1Œ1Œ1Œ1J)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@Jcc@Jÿÿ€€s w w€s€ÿÿà= w w w wà=ÿÿ w w k k w@kÿÿ€ w w@J@J w w€ÿÿ F w w % % w w Fÿÿ k w`o`o w kÿÿà w w Z Z w wàÿÿ€R w w 9 9 w w€Rÿÿà=@J@J@J@Jà=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB”R”R”R”RBÿÿÖZÿÿï=ï=ÿÿÖZÿÿçÿÿ÷^÷^ÿÿçÿÿœsÿ½w½wÿœsÿÿRJÿÿJ)J)ÿÿRJÿÿ„ÿÿ”R”Rÿÿ„ÿÿÿÿœsœsÿœsÿÿBÿÿÿÿBÿÿ„Þ{ÿÿÞ{„ÿÿ”RZkZk”RÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ)Œ1Œ1Œ1Œ1J)ÿÿ­5sNsN)%)%sNsN­5ÿÿ„sNsNÎ9Î9sNsN„ÿÿBsN1F1FsNBÿÿk-sNsNÆÆsNsNk-ÿÿBsNsNŒ1Œ1sNsNBÿÿ÷ZsNBBsN1FÿÿJ)sNsNsNsNJ)ÿÿBRJsNsNRJBÿÿŒ1BBŒ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà=@J@J@J@Jà=ÿÿ€R w w 9 9 w w€Rÿÿà w w Z Z w wàÿÿ k w`o`o w kÿÿ F w w % % w w Fÿÿ€ w w@J@J w w€ÿÿ w w k k w@kÿÿà= w w w wà=ÿÿ€€s w w€s€ÿÿ@Jcc@JÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMGŠ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG IMG0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGŠ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMENUTEXTGadgetTEXTIMG1  IMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBÿÿccÿÿBÿÿZkÿÿJ)J)ÿÿZkÿÿÆÿÿœsœsÿÿÆÿÿBÿÿÿÿBÿÿÞ{ÿÿÞ{ÿÿÎ9ÿÿÿÿÎ9ÿÿ„Þ{ÿœsœsÿÞ{„ÿÿcÿÿJ)J)ÿÿcÿÿBÿÿccÿÿBÿÿBcccÆÆcccÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB÷^ZkZkÖZŒ1ÿÿœsÿÿÿÿÿÿï=ÿÿ”RÿÞ{÷^÷^ÿÿZkÿÿB„œsÿZkÿÿ÷^ÿÿZkÿÿZkÿÿÿŒ1ÿÿ”RÿÿZkJ)ÿÿZkÿ½wÿÿB”RBÿÿJ)÷^„ÿÿJ)Þ{ÿZkÿÿB½wJ)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿB”R”Rç”R”RŒ1ÿÿÖZÿÿï=Bÿÿï=ÿÿçÿÿ÷^€ÿÞ{ÿÿœsÿ½wÞ{ÿ÷^ÿÿRJÿÿJ)ï=ÿÿŒ1ÿÿ„ÿÿ”RÖZÿ½wÿÿÿÿœs½wÿÖZÿÿBÿÿÿÿJ)ÿÿ„Þ{ÿÿœsÿÿ”RZkZkBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÆÖZÖZÿÿÎ9œsÿÿZkÿÿÆcÿÿÿÿÿ1Fÿÿ1Fœsÿÿÿÿ{oJ)ÿÿ1Fÿÿÿœs”Rÿÿ1Fÿÿÿœs”Rÿÿ”R½wÿÿÿÿZkJ)ÿÿJ)cÿÿÿÿÞ{1Fÿÿ1FœsÿÿZkÿÿÆÖZÖZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŒ1Œ1BÿÿBÿÞ{”RÆÿÿ!ZkÿÿÿœsÎ9Bÿÿ„RJœsÿÿÿ”R!ÿÿJ)”Rÿÿÿ!ÿÿJ)”Rÿÿÿ!ÿÿ„BœsÿÿÿÖZJ)ÿÿ!cÿÿÿœsÎ9„ÿÿBÿÿ”R!ÿÿŒ1Œ1BÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿBÿÿBÿÿœsÆÿÿÆœs­5œsµVÿÿ­5œsµVÿÿœsÿÿµVÿÿÿœsÿÿÿÿÿÿœsÆÿÿœsÿÿÿœsÿœsÆÿÿµVœsœsœsÿÿÿœsÆc ÿÿBBÆœsÿÿÿœs­5ÿÿÆœsÿœsÆÿÿÆœsÆÿÿ­5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­5ÿÿÆœsÆÿÿÆœsÿœsÆÿÿBBÆœsÿÿÿœs­5ÿÿµVœsœsœsÿÿÿœsÆc ÿÿœsÿÿÿœsÿœsÆÿÿÿÿÿÿœsÆÿÿµVÿÿÿœsÿÿ­5œsµVÿÿœsÿÿÆœs­5œsµVÿÿœsÆÿÿBÿÿBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGzÿÿÿ ÿ ÿÿÿÿ ÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGjÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ)sNccsNJ)ÿÿ¥cÿÿ{o{oÿÿc¥ÿÿƽwÿÿÎ9Î9ÿÿ½wÆÿÿ9gÞ{Þ{cBï=cÞ{Þ{9gÿÿ÷^Þ{Þ{cï=ï=cÞ{Þ{÷^ÿÿ„cÞ{½wŒ1­5½wÞ{c„ÿÿBRJœsÞ{ccÞ{œsRJBÿÿÆBµVµVBÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿMENUTEXTDividerTEXTIMG1IMG IMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG simutrans-124.3/simutrans/themes/menu.pak192comic.pak000066400000000000000000001761061474050137200225620ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1--IMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA‹9‹9JJIMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@J‹9íEŠ9ÌA«=íEJŠ9ÌAÍA«=ÍAJÌAŠ9‹9«=Š9«=«=‹9ÌAÍAÌAÌAŠ9Š9JíEŠ9íEJÍAŠ9‹9Š9JŠ9ÌAJ¬=Š5‹9JÌAŠ9ÌAŠ9îEŠ5‹9íEÍAŠ9ÌAŠ9«=îEŠ9‹9‹9JJIMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1íEi5H5å(-)å( i9‹=£ G1)‚å( i9(1£ £ Ä$'1Ä$&- )i5£ ¢Ä$ä(£ '1Š9ä$'1-£ ‚ '1ÌA£ G1)-¢ '1 i9ÌAä$‚‚ä(Ä$‚ Š=H1)å(Ä$-'1 )«=Ä$H5H5¢Ä$ )ÌA‚-'1¢'1 -Š9‚Ä$£ G5H5Ä$ '1Š9ä(G5-Ä$ä$ H1«A&-'1‚å(-&- £ -'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1Aa‚bb‚ƒb‚)AbÄ$&-ƒ£‚Ã$‚ƒå(ä(bb£ ‚ƒA¢'1@ @ ä$Ä$Aƒ£ '1£ƒH5£ b¤‚ä$bƒ£ ¤‚bIMGX €ðƒ€b£AA aƒƒ€øƒ€£bbab@ €ðƒ€IMGœ@@‚bA ƒaA‚ƒ£ƒAƒƒ‚bA bƒAAab‚ƒA ƒƒbƒ‚££¤ƒb¤¤A A ƒƒƒbƒƒb‚ƒ@ £ƒ@ A bb£‚A ‚bA aƒƒ@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒIMGX €ðƒ€€øƒ€£ƒ‚b¤b€ðƒ€bbaƒA b‚IMGœ@@@@ babAbA A bb£aƒbƒbaƒA¤A‚bƒƒAA ¤bbAA ƒAbƒbbbAAb‚A@ baƒƒA bbƒabaƒƒA‚‚b¤b@ƒƒaA b‚A ‚£bbA @ ƒ£@ ƒ‚bƒƒbƒƒƒA A ¤¤bƒ¤££‚ƒbƒƒA ƒ‚baAAƒbA b‚ƒƒAƒ£ƒ‚AaƒA b‚IMG@€€ðƒb£€€øƒA£b€€ðƒIMGZ  aA'1)å( bbh=,^h= bh=ywÒf,^h= b,^Òf,^,^h= £h=,^,^h=h= ƒ‚h=h=h='1 bbä(Ä$‚ Aƒ‚£ Ä$-'1 @ @ '1¢H5H5¢Ä$ ƒAÄ$ä$'1¢'1 ƒ£'1£ £ G5H5Ä$ ¤b£ H5-Ä$ä$ ƒbä$‚‚å(-&- b‚¤£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêH5i5íEH1G1£ ‹=i9£ £ (1i9¢£ i5)'1ä$Š9'1G1£ ÌA'1‚ä$ÌAi9å()H1Š=Ä$«=)-‚ÌA)Ä$‚Š9-G5ä(Š9'1'1&-«AH1£ '1-£ IMGX €ðƒ€¤æ(Š9Š9íE‹9J€øƒ€Ä$H5Š9i5'-'-€ðƒ€IMGœ@@JJ‹9‹9Š9îE«=Š9ÌAŠ9ÍAíE‹9Š5îEŠ9ÌAŠ9ÌAJ‹9Š5¬=JÌAŠ9JŠ9‹9Š9ÍAJíEŠ9íEJŠ9Š9ÌAÌAÍAÌA‹9«=«=Š9«=‹9Š9ÌAJÍA«=ÍAÌAŠ9JíE«=ÌAŠ9íE‹9J@H1Š9'-'-Š9H1i5j9«A'-«=‹=i5«=ÌAÌAŠ9«='-i5'-H1ÌA'1H1'-i5'-j9H1i5«=i5H5«AH1H1«=H1H1Š9'-Š9ÌAH1H1'-Š9ÌAŠ9H1Š9'-Š9Š=H1ÌAi5‹=H1Š9i5'-'-@IMG@íAFîE€€ðƒ«=J€€øƒ€€ðƒIMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA¢-'1IMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1IMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1'1i5H5å(-)å( i9&-£ G1)‚å( i9ä(£ £ Ä$'1Ä$&- )‚£ ¢Ä$ä(£ '1‚ä$'1-£ ‚ '1£ G1)-¢ '1 i9)ä$‚‚ä(Ä$‚ Š=ä$)å(Ä$-'1 )£ Ä$H5H5¢Ä$ )ä$‚-'1¢'1 -£ ‚Ä$£ G5H5Ä$ '1£ ä(G5-Ä$ä$ H1£ &-'1‚å(-&- £ i5'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGX €ðƒ€b£AG1¢Ä$-€øƒ€£bbab@ €ðƒ€IMGœ@@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒIMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA¢-'1IMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1IMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1'1i5H5å(-)å( i9&-£ G1)‚å( i9ä(£ £ Ä$'1Ä$&- )‚£ ¢Ä$ä(£ '1‚ä$'1-£ ‚ '1£ G1)-¢ '1 i9)ä$‚‚ä(Ä$‚ Š=ä$)å(Ä$-'1 )£ Ä$H5H5¢Ä$ )ä$‚-'1¢'1 -£ ‚Ä$£ G5H5Ä$ '1£ ä(G5-Ä$ä$ H1£ &-'1‚å(-&- £ i5'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGX €ðƒ€b£AG1¢Ä$-€øƒ€£bbab@ €ðƒ€IMGœ@@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒIMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA¢-'1IMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1IMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMG  H1'1i5)å(i9&-i9)'1'1i9)‚ Š=ä$)-'1 )£ Ä$H5H5¢Ä$ )ä$‚-'1¢'1 -£ ‚Ä$£ G5H5Ä$ '1£ ä(G5-Ä$ä$ H1£ &-'1‚å(-&- £ i5'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGX €ðƒ€b£AG1¢Ä$-€øƒ€£bbab@ €ðƒ€IMGœ@@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒMENUTEXT RoundbuttonTEXTIMG1IMGP€ðƒ€€øƒ€J«=€ðƒ€îEFíAÌ=0NqRíEIMG"@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@J‹9íEŠ9ÌA«=íEJŠ9ÌAÍA«=ÍAJÌAŠ9‹9«=Š9«=«=‹9ÌAÍAÌAÌAŠ9Š9JíEŠ9íEJÍAŠ9‹9Š9JŠ9ÌAJ¬=Š5‹9JÌAŠ9ÌAŠ9îEŠ5‹9íEÍAŠ9ÌAŠ9«=îEŠ9‹9‹9JJ@'1-¢ä$£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ å(-H5-Ä$‚Ä$£ '1&1ä$-å(à å(&-å(IMGP€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒà a‚bIMGêH1íEi5H5i9‹=£ G1i9(1£ £ )i5£ ¢'1Š9ä$'1'1ÌA£ G1i9ÌAä$‚Š=H1)å()«=Ä$)ÌA‚--Š9‚Ä$'1Š9ä(G5H1«A&-'1£ -'1£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1Aa‚bb‚ƒb‚)AbÄ$&-ƒ£‚Ã$‚ƒå(ä(bb£ ‚ƒA¢'1@ @ ä$Ä$Aƒ£ '1£ƒH5£ b¤‚ä$bƒ£ ¤‚bIMGPå$£Ä a€ðƒ€b£A€øƒ€£b€ðƒ€IMG"@@-Ä$¢G1&-‚¢G1Ä$H5'1‚‚¢Ä$å(H5Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)G1ä$&-G1-'1@‚bA ƒaA‚ƒ£ƒAƒƒ‚bA bƒAAab‚ƒA ƒƒbƒ‚££¤ƒb¤¤A A ƒƒƒbƒƒb‚ƒ@ £ƒ@ A bb£‚A ‚bA aƒƒ@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMGPå$bb‚abb€€ðƒƒ£€€øƒ€€ðƒIMGP€ðƒ€€øƒ€£ƒ€ðƒ€bba‚bbå$IMG"@@@@ babAbA A bb£aƒbƒbaƒA¤A‚bƒƒAA ¤bbAA ƒAbƒbbbAAb‚A@ baƒƒA bbƒabaƒƒA‚‚b¤b@ƒƒaA b‚A ‚£bbA @ ƒ£@ ƒ‚bƒƒbƒƒƒA A ¤¤bƒ¤££‚ƒbƒƒA ƒ‚baAAƒbA b‚ƒƒAƒ£ƒ‚AaƒA b‚@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-IMGP€€ðƒb£€€øƒA£b€€ðƒaÄ £å$IMGêaA'1à bb‚bƒ‚bA)‚£ƒ&-Ä$ƒ‚Ã$‚bbä(å(Aƒ‚£ @ @ '1¢ƒAÄ$ä$ƒ£'1£ ¤b£ H5ƒbä$‚b‚¤£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêH5i5íEH1G1£ ‹=i9£ £ (1i9¢£ i5)'1ä$Š9'1G1£ ÌA'1‚ä$ÌAi9å()H1Š=Ä$«=)-‚ÌA)Ä$‚Š9-G5ä(Š9'1'1&-«AH1£ '1-£ IMGPb‚aà €ðƒ€¤æ(Š9€øƒ€Ä$H5€ðƒ€IMG"@@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1@JJ‹9‹9Š9îE«=Š9ÌAŠ9ÍAíE‹9Š5îEŠ9ÌAŠ9ÌAJ‹9Š5¬=JÌAŠ9JŠ9‹9Š9ÍAJíEŠ9íEJŠ9Š9ÌAÌAÍAÌA‹9«=«=Š9«=‹9Š9ÌAJÍA«=ÍAÌAŠ9JíE«=ÌAŠ9íE‹9J@H1Š9'-'-Š9H1i5j9«A'-«=‹=i5«=ÌAÌAŠ9«='-i5'-H1ÌA'1H1'-i5'-j9H1i5«=i5H5«AH1H1«=H1H1Š9'-Š9ÌAH1H1'-Š9ÌAŠ9H1Š9'-Š9Š=H1ÌAi5‹=H1Š9i5'-'-@IMGPíEqR0NÌ=íAFîE€€ðƒ«=J€€øƒ€€ðƒIMGP€ðƒ€€øƒ€J«=€ðƒ€îEFíAÌ=0NqRíEIMG"@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1@'1-¢ä$£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ å(-H5-Ä$‚Ä$£ '1&1ä$-å(à å(&-å(IMGP€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒà a‚bIMGêH1'1i5H5i9&-£ G1i9ä(£ £ )‚£ ¢'1‚ä$'1'1£ G1i9)ä$‚Š=ä$)å()£ Ä$)ä$‚--£ ‚Ä$'1£ ä(G5H1£ &-'1£ i5'1£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGPå$£Ä a€ðƒ€b£A€øƒ€£b€ðƒ€IMG"@@-Ä$¢G1&-‚¢G1Ä$H5'1‚‚¢Ä$å(H5Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)G1ä$&-G1-'1@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMGPå$bb‚abb€€ðƒƒ£€€øƒ€€ðƒMENUTEXT EditfieldTEXTIMG1  IMGÄ Ä Ä h=IMG@@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=IMGÄ Ä Ä ÒfIMGÒÄ h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=IMG‚ @@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^IMGÒywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfIMGÄ h=h=ÒfIMG@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒfÒfÒfÒfMENUTEXTListboxTEXTIMG1  IMGÄ Ä Ä h=IMG@@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=IMGÄ Ä Ä ÒfIMGÒÄ h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=IMG‚ @@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfIMGÄ h=h=ÒfIMG@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒfÒfÒfÒfMENUTEXTBackTEXTIMG1  IMGÒfÒfÒfÒfIMG@@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywIMGÒfh=h=Ä IMGŠ@ÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywIMGŠ!@@@,^,^,^,^L^,^,^,^L^L^L^L^L^,^,^,^L^L^,^,^,^L^L^L^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z+^+^+^+^+^ Z Z+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^ Z+^+^ Z+^+^+^+^ Z Z Z+^+^ Z+^+^+^+^+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^+^,^,^@+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z+^+^+^+^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^,^,^,^,^,^,^+^+^+^@+^+^+^+^+^,^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^,^,^L^L^L^,^,^,^,^,^,^,^,^+^+^+^@L^L^L^L^L^L^,^L^L^L^L^,^,^,^,^,^,^,^,^+^,^+^+^ Z+^ Z Z Z Z Z Z Z+^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^,^,^,^L^L^L^L^L^L^L^L^@,^+^+^+^,^+^+^+^+^ Z+^ Z+^ Z+^+^ Z+^+^+^+^+^+^+^+^+^,^,^,^,^+^,^+^+^,^,^,^,^,^+^+^,^+^,^,^,^,^+^+^,^+^,^,^,^,^,^,^+^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z Z Z Z+^+^,^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^+^,^,^+^+^+^+^+^ Z Z+^+^+^+^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^@,^,^+^+^,^,^,^,^,^,^,^,^+^,^+^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^ Z+^+^,^,^,^+^+^+^+^+^+^+^ Z Z Z Z+^+^+^+^,^+^+^+^ Z Z Z Z Z+^+^+^+^,^,^,^,^,^+^+^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^@ Z+^+^+^+^,^,^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^ Z+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z@L^,^,^L^L^L^L^L^,^,^,^,^,^,^,^,^+^+^+^ Z+^ Z+^+^+^+^+^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^,^,^L^L^,^L^@,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^L^,^,^@,^+^+^+^+^,^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z+^+^ Z+^+^+^+^+^+^+^+^+^+^,^+^,^,^@,^+^+^ Z+^+^+^ Z+^+^ Z+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^+^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^L^,^L^L^L^,^,^,^,^,^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^,^,^,^,^+^+^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^L^,^,^L^L^,^,^,^,^,^,^,^,^,^+^,^,^+^+^,^,^,^,^,^+^+^,^,^,^,^,^@,^,^,^,^,^,^,^,^+^+^+^+^ Z+^+^+^+^+^+^+^+^+^ Z Z+^+^,^+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^+^+^+^+^+^+^,^,^,^+^+^+^,^,^+^+^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^,^,^,^,^,^L^L^L^L^L^L^,^,^,^,^,^,^@,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^L^,^L^,^,^,^,^L^L^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^,^+^+^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^+^,^,^,^+^+^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^L^,^L^L^L^L^L^,^,^,^L^L^L^L^,^,^,^,^,^,^,^,^,^+^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^@,^,^,^,^,^+^+^+^+^+^+^+^+^,^+^+^+^ Z+^+^+^+^+^+^,^,^,^,^+^,^,^,^+^+^+^,^,^+^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^,^,^L^L^L^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^+^+^+^,^,^,^+^,^+^,^+^+^+^+^+^,^,^,^,^,^+^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^ Z Z Z Z+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^@+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^,^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^ Z+^+^,^,^,^+^@+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^,^,^,^,^+^@,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^+^ Z Z Z Z+^ Z Z Z Z+^+^+^+^ Z+^ Z+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^+^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^+^+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^@L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^L^@,^,^,^+^+^ Z+^+^ Z+^+^ Z Z Z Z Z Z+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^L^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^+^+^+^,^,^,^+^,^+^,^+^+^+^+^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^+^+^+^,^+^,^,^,^+^+^+^+^,^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^@,^,^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^,^,^,^L^,^L^,^L^,^L^L^L^L^L^,^,^,^@,^,^,^,^,^,^+^+^+^+^,^+^,^,^,^,^,^,^,^+^+^,^,^+^+^+^+^+^+^+^+^ Z Z Z Z+^+^+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^ Z+^+^+^+^+^+^+^+^+^ Z+^+^+^+^+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^+^,^,^,^,^,^@+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z+^+^+^+^ Z Z+^+^+^+^+^+^,^+^+^ Z+^+^+^@ Z Z Z Z+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^,^+^+^+^ Z@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^,^,^,^+^+^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^+^,^,^+^+^+^+^+^+^+^,^+^+^ Z+^+^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^@,^+^,^,^,^,^,^,^,^+^+^+^,^+^+^,^,^+^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^+^+^,^+^,^,^,^,^+^+^,^+^,^,^,^,^,^@ Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^ Z Z Z Z@,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^,^L^,^,^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^,^+^+^+^+^+^+^,^+^+^,^,^,^,^@L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^+^+^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^@,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@ Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^+^+^,^+^+^+^+^ Z Z Z Z Z@,^,^,^,^,^,^L^L^L^L^L^L^L^,^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^L^,^L^,^,^,^,^,^@+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^+^+^+^ Z+^+^+^+^+^ Z Z+^+^+^+^,^@,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^@+^+^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z+^+^ Z+^+^ Z Z Z Z Z Z+^@ Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^ Z Z Z Z@,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^,^@L^L^L^,^,^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^@,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^L^,^L^L^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^L^,^L^L^L^,^,^,^,^,^,^,^,^,^,^+^+^,^,^+^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^+^+^+^ Z+^ Z Z+^ Z+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^@L^L^L^L^L^L^L^,^,^,^,^+^+^,^+^+^+^,^+^+^+^+^ Z Z Z Z+^+^+^+^,^,^,^,^+^,^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^IMGŠ@h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä IMGÒfÄ Ä Ä IMG@@h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä IMGh=Ä Ä Ä MENUTEXT CheckbuttonTEXTIMG1IMG6   îE«=«9ÌAJJÍA«9G1 ÍAi5å(-Š='1'-&-) ÌAh5i9H1å('1å('1) îE-'1å$H5'1å(-å ÍAH5h5)H5ª=Š9i9ƒ «=-'-i9H5'1i9-£ ÌAH5‰9G1)Š='--Ä JÄ$‰9-Š=‰9-å(¤ h5%£Ä Ä Å å$Å Å IMG6   ÅÅ å$Å Ä Ä £%h5 ¤å(-‰9Ä$J Ä-h=,^h=H5ÌA £h=ywÒf,^h=«= ƒ,^Òf,^,^h=ÍA å h=,^,^h=h=îE )'1h=h=h=h5ÌA )&-'-å(i5ÍA G1«9ÍAJJÌA«9«=îE IMG6   ÅÅ å$Å Ä Ä £%h5 ¤å(-‰9Š=-‰9Ä$J Ä-'-Š=)G1‰9H5ÌA £-i9'1H5i9'--«= ƒi9Š9ª=H5)h5H5ÍA å -å('1H5å$'1-îE )'1å('1å(H1i9h5ÌA )&-'-'1Š=-å(i5ÍA G1«9ÍAJJÌA«9«=îE MENUTEXT PosbuttonTEXTIMG1IMG6   qVJÌAÍA/NJ¬=/Ni9 N-H5i9i9Ä ¬=ywÒfi9å(£ NywywywÒfH5¤ 0Nywywywywywå$ íEywywywÒfH5å$ îIywÒfªAå() ÍAŠ=‰=Š=H5) -)£æ$¤¤¤%Å  IMG6   ¤)Ä )£¤))i9 æ$'1-h9ä(ÍA Ä ywÒfi9h5J )ywywywÒfŠ=íE Ä ywywywywyw/N Ä ywywywÒfå(íE Å ywÒf-‰=J ¤'1Š=ª='1/N ä$/N/N¬=0NíE/N0NQR IMG6   i9)-Š=h5h5ä(ªA&1 Š=-'1å()‰9 Š=,^h=)Š=i9 ªA,^,^,^h='1‰9 h9,^,^,^,^,^å( Š=,^,^,^h=&-'1 ‰9,^h=‰9'1å( å(‰9-&-‰='1 h5i9G1h5)å(ä$H5H5 MENUTEXT ScrollbarTEXTIMG1IMG6   rVÌAJÌAJíEJ¬='1 JŠ=‰9h9‰=£ Jª=Š=ÒfywÅ ÌAH5Òfywywywå$ 0Nywywywywyw¤ ÌAH5Òfywywywå$ îEH5‰9Òfyw) ÍA-'1-'1¤ å(Å £)Å %Å £æ  IMG6   ƒ)Ä å Å å$æ$Å '1 £å(å(ä(G1ÌA Ä i9'1ÒfywÌA Å -ÒfywywywíE æ$ywywywywywJ ¤Š=Òfywywyw¬= ƒ'1G1Òfyw/N Å -Š=å(å(/N Š=NíEJ¬=¬=JíE0N IMG6   h9i9G1Š=Š='1'1-- H5-i9i9å(H5 H5&-Š=h=,^‰= -ª=h=,^,^,^Š= Š=,^,^,^,^,^'1 '1'1h=,^,^,^ä( '1h5Š=h=,^i9 ‰9)i9å(H5&- Š=å(&-å(‰=-i9å(i9 IMG6   qVJÌAÍA/NJ¬=/Ni9 N-H5i9i9Ä ¬=ywÒfi9å(£ NywywywÒfH5¤ 0Nywywywywywå$ íEywywywÒfH5å$ îIywÒfªAå() ÍAŠ=‰=Š=H5) -)£æ$¤¤¤%Å  IMG6   ¤)Ä )£¤))i9 æ$'1-h9ä(ÍA Ä ywÒfi9h5J )ywywywÒfŠ=íE Ä ywywywywyw/N Ä ywywywÒfå(íE Å ywÒf-‰=J ¤'1Š=ª='1/N ä$/N/N¬=0NíE/N0NQR IMG6   i9)-Š=h5h5ä(ªA&1 Š=-'1å()‰9 Š=,^h=)Š=i9 ªA,^,^,^h='1‰9 h9,^,^,^,^,^å( Š=,^,^,^h=&-'1 ‰9,^h=‰9'1å( å(‰9-&-‰='1 h5i9G1h5)å(ä$H5H5 IMG  Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä h=h=h=h=h=h=h=h=h=h=Ä h=Ä h=Ä h=QN¬9J1Ä h=¬9æ$„æ$æ$æ$æ$Ä h=J1„cÄ h=Ä h= Ä h=ywywywywywywywywyw h=ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÌ@ @Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@@@@æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$@@@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMG  Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä h= h=h=h=h=h=h=h=h=h=h=Òf ywÒfywÒfQN¬9J1ywÒfæ$æ$æ$æ$¬9æ$„ywÒfJ1„cywÒfywÒf ÒfÒf ywywywywywywywywÒfÒfÒf ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMG  îE«=«9ÍAi5å(ÌAh5i9îE-'1ÍAH5h5«=-'-ÌAH5‰9JÄ$‰9h5%£IMGÌ@ @@ÌAJJíEJîEíEJJÌA/NÍAíE/N0NPRîEÌAÍA/NJJJÌAPRíEÌAíEJJîEíEîIJPRÌAÌAíEíEPRPRíEPRPRíEJ/N/NNÌAJÌAJJJíEíEíEPR/NÌAíE¬=‹9@-Š='1H5H5H5‰=)Š=å('1ª=H5ªAH5H5H5-G5ä(&-G1'1Š=Š=i9Š='1h9i9i9‰='1&-h5H5)‰9'1G1H5i9'1ä(G1‰=‰9ª=G1-H5å(i9G1Š=Š=Š=‰9å(G1ª='1h5ä$@H1å('1Š=h9&-h9-Š=Š=Š=-Š=i9H5ª=ä(‰9i9h9i9G1'1‰='1i9'1H5H5G1G1i9--'1H5å(&1i9H5å(-G1å(-'1å(‰9&-H5-&1-&1ª=&-ª=-&-‰=i9å(i9-@å$H5'1å(-ä(ªAŠ=ä$i9å(å(‰=&-h9-H5Š=å(i9H5)å(Š=-Š=)'1-i9å(Š=Š=ä(-å(i9G5h5‰9h9ª=Š=Š=G5Š=G5å(&-‰9&1&-i9å(i9'1-ª='1-h9ä$-)@)H5ª=G5&-ä(Š=-‰9i9Š=H5&-‰=h9i9G5h5'1H5)Š=i9&-'1-Š=ª=-å(-H5‰9H5ª=å(ä(Š=‰9'1å(‰=&-G1å(G5i9Š=h5-‰9å(‰9å('1ª=&-H5-'1i9i9H5i9@i9H5'1'1-G5ª=i9G1å(‰9G1å(H5H5‰9H5-‰9i9Š='1G1H5'1--‰=h5)å(H5Š=-'1-)‰9)‰=G1h5H5‰9ä(i9G5h5Š=G1ä$å(-'1‰9Š=i9h9i9ª=&1H5)-@G1)Š=H5&-ª=-Š=å(‰9å('1'1h5Š='1'1‰9H5i9&-h5h5G1å(&1i9H5-&1&-i9Š=H5'1å(G5‰9å(H5G5‰=Š=Š=&-‰9å(H5G1-i9Š=-Š='1h5G1H5‰=G1‰9‰9Š=å(@-Š=‰9‰='1Š=)‰9h9&-å(H5Š=-G1h9'1'1Š=ª='1Š=-)ä(--h5-Š=)h5Š=G5Š=i9-å(å(-Š=--G1-Š=i9--‰=-G1ä(-h5G1&1i9ª=-i9)-H1@Ä Ä Å Å æ$¤Ä £¤££Å ))££%£å$££å æ$Ä £Ä ))Å )££)Å )æ$)£)£)££)Å )æ$å$£ƒ)¤£Å ¤¤å$¤å$Äå æ$£æ$@IMG  ÍA«9G1'-&-)å('1)å(-å Š9i9ƒi9-£'--Ä-å(¤å$Å ÅIMG6   0N¬=JÌAîE/N¬=ÌA'1 ÍAh5'1G1‰='1h9æ$ J-‰=ywŠ=H5¤ ÍAH5ÒfywÒf'1æ$ PRH5ywywywŠ=Ä JÒfywywywÒf) ÍAywywywywywÅ íEæ$ -Ä å$ƒ£å$å )ƒ IMG6   h9i9'1ª='1G1H5-h5 å(Š=Š=H5'1'1Š=Š= G1H5i9,^h5å(i9 h9i9h=,^h=H5) &--,^,^,^å(- i9h=,^,^,^h=&- Š=,^,^,^,^,^Š= -'1 )Š=G1&-Š=G1Š=)i9 IMG6   Å £Ä )Ä å ÄÅ h5 å -å(H5i9H5h5/N å '1H5ywH5å(íE ¤-ÒfywÒfh5îI ))ywywywä(íE æ$ÒfywywywÒfJ £ywywywywywíE )¬= H5J¬=ÌAJJÌA/NQR IMG6   QRÌAJ/NíEÌAíE0N- îEæ$ 0Nywywywywyw£ /NÒfywywywÒf£ PRå(ywywywå(£ ÌAi9ÒfywÒfi9å$ /N&-'1ywh9&-Å ÍA'1Š=h5h9'1ª=Ä H5)ÄĤæ$)Ä ¤ IMG6   Š=Š=H5i9'1‰=‰9-H5 )H5 å(,^,^,^,^,^Š= -h=,^,^,^h=&1 ä(H5,^,^,^ª=- H5'1h=,^h=ª=å( H5å(i9,^)å(ä( ä(‰9H5H5‰=)&-H5 h9i9å(ä(ä(H5)-H5 IMG6   Å )Å å$Äå$£Ä - ¤0N )ywywywywyw/N )ÒfywywywÒf/N )h5ywywyw'1¬= £h5ÒfywÒfŠ=ÌA ¤-h5yw-‰=N Ä Š=H5Š=Š=-å(íE i9ÍAÌAPRN/NPR¬=qR IMG@  Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä h= Ä h=h=h=h=h=h=h=h=h=ÒfÄ h=ywÒfÄ h=ywÒfÄ h=QN¬9J1ywÒfÄ h=¬9æ$„ywÒfÄ h=J1„cywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfIMG  @Ä h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfIMG@  Ä h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=æ$ywÒfÄ h=QN¬9J1ywÒfÄ h=¬9æ$„ywÒfÄ h=J1„cywÒfÄ h=ywÒfÄ h=ÒfÒf Ä h=ywywywywywywÒfÒfÒf h=ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGv  îEÍAÌAîEÍA«=ÌAJh5 «=i5h5-H5-H5Ä$% «9å(i9'1h5'-‰9‰9£IMG  @ ‹9ä$-)i9-å(H1æ$ ¬=h5i9-H5)Š=-£ íE'1å(ä$i9H5‰9)æ$ ÌAª=i9h9i9&1‰9i9å /NG1‰=-'1ª=G1-Ä PRå(&-'1-i9‰=ª=å$ íE‰9-ª=H5h9H5i9¤ íEŠ=ª=-&-i9G1&1å$ íEŠ=&-'1ª=Š=h5G1¤ JŠ=ª=i9'1‰9'1h5¤ JG1&1å(å('1Š=-Å Ji9-i9‰9--ä(£ ÌAå(&1&-å(å(Š=G1¤ JH5-&1‰9ä$i9-) ÌA-H5‰9-G1-‰=ƒ NG1&-&-h5Š=G1-£ /Nª=‰9å(Š=h5H5-å$ /N‰9å(G5i9G5å(i9æ$ J‰='1Š=G5i9‰9Š=) íEG1-G5å(ä(&--Å PRä(å(Š=G1‰9Š=G1) PR'1G1Š=&-H5Š=-£ íEi9-ª=‰=h5‰=-£ PRH5å(h9å(G1G5Š=) PRG1H5‰9'1‰=H5-£ íE'1i9h5‰9)å(å() íE‰9&1G5Š=‰9‰9å(£ ÌA)å(i9ä()G5-) ÌAH5H5å(å(-å(i9æ$ PRh5'1-ª='1'1Š=) J&--ä(H5-H5G5Å îI'1-Š=‰9Š=Š=Š=) íE‰=i9Š=H5H5i9h5£ îEi9G1å(-å(&-)£ Ji9G1i9å()&1Š=) Jh9H5--h5--Å íE'1H5'1ª=‰=H5h5) ÌAŠ='1)Š=-i9-) íEi9i9Š=--&1-Ä PRŠ='1-'1'1å(ä(£ ÌAŠ=‰=Š=&-H5G1)Ä J'1'1å(i9G1h5-æ$ JG1G1)Š='1h5Š=å J&-i9H5)Š=&-'1£ /Nä(h9i9H5i9i9ª=£ ÍAG5i9å('1‰9H5Š=å$ ÌA-‰9Š=h5-‰9'1£ îEH5ä(H5G5H5'1'1% PRH5ª=-i9‰9'1h9£ 0NH5H5h9h9H5Š=G1£ /NªAi9&-‰=H5h5-) íEH5Š=‰=&-å('1Š=) ÍAª=-å(H5G1'1H5Å /N'1Š=å(Š=‰9å(å(£ ÌAå(Š=i9i9å(‰9&-£ JŠ=Š=ä$‰9G1å(h9¤ J)-Š=-i9Š=‰9£ íE‰=h9ªAŠ=ª=-)Ä îEH5&-ä(ä(G5ª=Š=¤ JH5h9-&--&-'1æ$ íEH5Š=å(G5'1H5‰=Å J'1'1'1ª='1Š=‰9Å JŠ=å(H5H5H5)Š=Ä ÌA-H1å$)i9G1-Ä IMGv  ÍA'-å(å(Š9i9'--å$ «9&-'1-i9--å(Å G1))å ƒ£Ä¤Å MENUTEXTGadgetTEXTIMG1  IMG  ^²fOZÓj‰Aôn²fOZÓjËI ‰AônNV RônËIh=±bÓjÓj‰AOZ6w‘b-ROZNV^OZ p^ÓjªEh=Ój²fp^ÓjìM‰AÓj²fËIìM‰A-RIMGà  OZÓj²fôn-R ‘bo RËIop^ËI Rp^²fNVìM²f Rp^OZ±bÓjËI RÓj5sìMNVIMGz  ìM²fÓjÓjÓjÓjÓjìM‰A²f6wVwÓjªEh=^²f‰Ah=ÊEIMG’  N-R±bìMo^-RoW{p^h=Ójop^h=p^OZ‰AOZ‰AIMG’  NOZp^OZo-RNV5s6wOZNVÓjôn‰A-Rp^ªE NìM‰AIMGâ  ìMìM p^p^h=p^ oVwh=ªEªEªEo VwVwVwoVwVwoVwB oªEh=h=ªEh=o ìMh=h=ªEh=h=IMGÚ  B ìMp^oVwoªEh=h=ªEoh=h=ªEVwªEh=oh=p^VwVwªEh= ìMp^oVwoìMh= VwIMG”  Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä  Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä IMG p^p^oo op^oVw oìMp^VwVwìMoVwìMoop^Vwp^h=p^ p^ìMh=ìM p^p^h=ìMìMh=h=h=MENUTEXTDividerTEXTIMG1IMG IMGœ@@h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMG simutrans-124.3/simutrans/themes/menu.pak192comicxxl.pak000066400000000000000000002401441474050137200233100ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA‹9‹9JJIMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@J‹9íEŠ9ÌA«=íEJŠ9ÌAÍA«=ÍAJÌAŠ9‹9«=Š9«=«=‹9ÌAÍAÌAÌAŠ9Š9JíEŠ9íEJÍAŠ9‹9Š9JŠ9ÌAJ¬=Š5‹9JÌAŠ9ÌAŠ9îEŠ5‹9íEÍAŠ9ÌAŠ9«=îEŠ9‹9‹9JJIMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1íEi5H5å(-)å( i9‹=£ G1)‚å( i9(1£ £ Ä$'1Ä$&- )i5£ ¢Ä$ä(£ '1Š9ä$'1-£ ‚ '1ÌA£ G1)-¢ '1 i9ÌAä$‚‚ä(Ä$‚ Š=H1)å(Ä$-'1 )«=Ä$H5H5¢Ä$ )ÌA‚-'1¢'1 -Š9‚Ä$£ G5H5Ä$ '1Š9ä(G5-Ä$ä$ H1«A&-'1‚å(-&- £ -'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1Aa‚bb‚ƒb‚)AbÄ$&-ƒ£‚Ã$‚ƒå(ä(bb£ ‚ƒA¢'1@ @ ä$Ä$Aƒ£ '1£ƒH5£ b¤‚ä$bƒ£ ¤‚bIMGX €ðƒ€b£AA aƒƒ€øƒ€£bbab@ €ðƒ€IMGœ@@‚bA ƒaA‚ƒ£ƒAƒƒ‚bA bƒAAab‚ƒA ƒƒbƒ‚££¤ƒb¤¤A A ƒƒƒbƒƒb‚ƒ@ £ƒ@ A bb£‚A ‚bA aƒƒ@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒIMGX €ðƒ€€øƒ€£ƒ‚b¤b€ðƒ€bbaƒA b‚IMGœ@@@@ babAbA A bb£aƒbƒbaƒA¤A‚bƒƒAA ¤bbAA ƒAbƒbbbAAb‚A@ baƒƒA bbƒabaƒƒA‚‚b¤b@ƒƒaA b‚A ‚£bbA @ ƒ£@ ƒ‚bƒƒbƒƒƒA A ¤¤bƒ¤££‚ƒbƒƒA ƒ‚baAAƒbA b‚ƒƒAƒ£ƒ‚AaƒA b‚IMG@€€ðƒb£€€øƒA£b€€ðƒIMGZ  aA'1)å( bbh=,^h= bh=ywÒf,^h= b,^Òf,^,^h= £h=,^,^h=h= ƒ‚h=h=h='1 bbä(Ä$‚ Aƒ‚£ Ä$-'1 @ @ '1¢H5H5¢Ä$ ƒAÄ$ä$'1¢'1 ƒ£'1£ £ G5H5Ä$ ¤b£ H5-Ä$ä$ ƒbä$‚‚å(-&- b‚¤£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêH5i5íEH1G1£ ‹=i9£ £ (1i9¢£ i5)'1ä$Š9'1G1£ ÌA'1‚ä$ÌAi9å()H1Š=Ä$«=)-‚ÌA)Ä$‚Š9-G5ä(Š9'1'1&-«AH1£ '1-£ IMGX €ðƒ€¤æ(Š9Š9íE‹9J€øƒ€Ä$H5Š9i5'-'-€ðƒ€IMGœ@@JJ‹9‹9Š9îE«=Š9ÌAŠ9ÍAíE‹9Š5îEŠ9ÌAŠ9ÌAJ‹9Š5¬=JÌAŠ9JŠ9‹9Š9ÍAJíEŠ9íEJŠ9Š9ÌAÌAÍAÌA‹9«=«=Š9«=‹9Š9ÌAJÍA«=ÍAÌAŠ9JíE«=ÌAŠ9íE‹9J@H1Š9'-'-Š9H1i5j9«A'-«=‹=i5«=ÌAÌAŠ9«='-i5'-H1ÌA'1H1'-i5'-j9H1i5«=i5H5«AH1H1«=H1H1Š9'-Š9ÌAH1H1'-Š9ÌAŠ9H1Š9'-Š9Š=H1ÌAi5‹=H1Š9i5'-'-@IMG@íAFîE€€ðƒ«=J€€øƒ€€ðƒIMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA¢-'1IMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1IMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1'1i5H5å(-)å( i9&-£ G1)‚å( i9ä(£ £ Ä$'1Ä$&- )‚£ ¢Ä$ä(£ '1‚ä$'1-£ ‚ '1£ G1)-¢ '1 i9)ä$‚‚ä(Ä$‚ Š=ä$)å(Ä$-'1 )£ Ä$H5H5¢Ä$ )ä$‚-'1¢'1 -£ ‚Ä$£ G5H5Ä$ '1£ ä(G5-Ä$ä$ H1£ &-'1‚å(-&- £ i5'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGX €ðƒ€b£AG1¢Ä$-€øƒ€£bbab@ €ðƒ€IMGœ@@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒIMGX €ðƒ€€øƒ€J«='-'-Š9H1€ðƒ€îEFíA¢-'1IMGœ@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1IMG@€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒIMGZ  H1'1i5H5å(-)å( i9&-£ G1)‚å( i9ä(£ £ Ä$'1Ä$&- )‚£ ¢Ä$ä(£ '1‚ä$'1-£ ‚ '1£ G1)-¢ '1 i9)ä$‚‚ä(Ä$‚ Š=ä$)å(Ä$-'1 )£ Ä$H5H5¢Ä$ )ä$‚-'1¢'1 -£ ‚Ä$£ G5H5Ä$ '1£ ä(G5-Ä$ä$ H1£ &-'1‚å(-&- £ i5'1£ £ Ä$å(IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGX €ðƒ€b£AG1¢Ä$-€øƒ€£bbab@ €ðƒ€IMGœ@@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMG@abb€€ðƒƒ£€€øƒ€€ðƒMENUTEXT RoundbuttonTEXTIMG1IMGP€ðƒ€€øƒ€J«=€ðƒ€îEFíAÌ=0NqRíEIMG"@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@J‹9íEŠ9ÌA«=íEJŠ9ÌAÍA«=ÍAJÌAŠ9‹9«=Š9«=«=‹9ÌAÍAÌAÌAŠ9Š9JíEŠ9íEJÍAŠ9‹9Š9JŠ9ÌAJ¬=Š5‹9JÌAŠ9ÌAŠ9îEŠ5‹9íEÍAŠ9ÌAŠ9«=îEŠ9‹9‹9JJ@'1-¢ä$£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ å(-H5-Ä$‚Ä$£ '1&1ä$-å(à å(&-å(IMGP€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒà a‚bIMGêH1íEi5H5i9‹=£ G1i9(1£ £ )i5£ ¢'1Š9ä$'1'1ÌA£ G1i9ÌAä$‚Š=H1)å()«=Ä$)ÌA‚--Š9‚Ä$'1Š9ä(G5H1«A&-'1£ -'1£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1Aa‚bb‚ƒb‚)AbÄ$&-ƒ£‚Ã$‚ƒå(ä(bb£ ‚ƒA¢'1@ @ ä$Ä$Aƒ£ '1£ƒH5£ b¤‚ä$bƒ£ ¤‚bIMGPå$£Ä a€ðƒ€b£A€øƒ€£b€ðƒ€IMG"@@-Ä$¢G1&-‚¢G1Ä$H5'1‚‚¢Ä$å(H5Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)G1ä$&-G1-'1@‚bA ƒaA‚ƒ£ƒAƒƒ‚bA bƒAAab‚ƒA ƒƒbƒ‚££¤ƒb¤¤A A ƒƒƒbƒƒb‚ƒ@ £ƒ@ A bb£‚A ‚bA aƒƒ@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMGPå$bb‚abb€€ðƒƒ£€€øƒ€€ðƒIMGP€ðƒ€€øƒ€£ƒ€ðƒ€bba‚bbå$IMG"@@@@ babAbA A bb£aƒbƒbaƒA¤A‚bƒƒAA ¤bbAA ƒAbƒbbbAAb‚A@ baƒƒA bbƒabaƒƒA‚‚b¤b@ƒƒaA b‚A ‚£bbA @ ƒ£@ ƒ‚bƒƒbƒƒƒA A ¤¤bƒ¤££‚ƒbƒƒA ƒ‚baAAƒbA b‚ƒƒAƒ£ƒ‚AaƒA b‚@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-IMGP€€ðƒb£€€øƒA£b€€ðƒaÄ £å$IMGêaA'1à bb‚bƒ‚bA)‚£ƒ&-Ä$ƒ‚Ã$‚bbä(å(Aƒ‚£ @ @ '1¢ƒAÄ$ä$ƒ£'1£ ¤b£ H5ƒbä$‚b‚¤£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêH5i5íEH1G1£ ‹=i9£ £ (1i9¢£ i5)'1ä$Š9'1G1£ ÌA'1‚ä$ÌAi9å()H1Š=Ä$«=)-‚ÌA)Ä$‚Š9-G5ä(Š9'1'1&-«AH1£ '1-£ IMGPb‚aà €ðƒ€¤æ(Š9€øƒ€Ä$H5€ðƒ€IMG"@@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1@JJ‹9‹9Š9îE«=Š9ÌAŠ9ÍAíE‹9Š5îEŠ9ÌAŠ9ÌAJ‹9Š5¬=JÌAŠ9JŠ9‹9Š9ÍAJíEŠ9íEJŠ9Š9ÌAÌAÍAÌA‹9«=«=Š9«=‹9Š9ÌAJÍA«=ÍAÌAŠ9JíE«=ÌAŠ9íE‹9J@H1Š9'-'-Š9H1i5j9«A'-«=‹=i5«=ÌAÌAŠ9«='-i5'-H1ÌA'1H1'-i5'-j9H1i5«=i5H5«AH1H1«=H1H1Š9'-Š9ÌAH1H1'-Š9ÌAŠ9H1Š9'-Š9Š=H1ÌAi5‹=H1Š9i5'-'-@IMGPíEqR0NÌ=íAFîE€€ðƒ«=J€€øƒ€€ðƒIMGP€ðƒ€€øƒ€J«=€ðƒ€îEFíAÌ=0NqRíEIMG"@@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@å(&-å(à å(-ä$&1'1£ Ä$‚Ä$-H5-å(¢ Ä$'1G1'1å(å(G5H5-H5)å(¢Ä$--ä$Ä$à &-Ä$ä(‚ä$&-)Ä$£ à £ ‚£ ¢H5'1£ G1£ -£ ä$¢-'1@'1-¢ä$£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ å(-H5-Ä$‚Ä$£ '1&1ä$-å(à å(&-å(IMGP€€ðƒH5Ä$€€øƒŠ9æ(¤€€ðƒà a‚bIMGêH1'1i5H5i9&-£ G1i9ä(£ £ )‚£ ¢'1‚ä$'1'1£ G1i9)ä$‚Š=ä$)å()£ Ä$)ä$‚--£ ‚Ä$'1£ ä(G5H1£ &-'1£ i5'1£ IMG^@@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(IMGêà '1¤a‚ä$b‚£ b‚)'1bÄ$&-Ä$£‚Ã$'1ƒå(ä(‚b£ ‚ä(A¢'1Ã$@ ä$Ä$&-ƒ£ '1)ƒH5£ ‚¤‚ä$ƒ£ ¤'1bIMGPå$£Ä a€ðƒ€b£A€øƒ€£b€ðƒ€IMG"@@-Ä$¢G1&-‚¢G1Ä$H5'1‚‚¢Ä$å(H5Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)G1ä$&-G1-'1@'1-G1&-ä$G1)Ä$Ã$Ã$Ä$)Ä$-'1£ H5å(£ ¢ £ ä$-£ ¢ ‚G5Ä$å())£ å(£ £ -‚-'1£ £ -Ã$H5å(Ä$¢‚‚'1H5Ä$G1¢‚&-G1¢Ä$-@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMGPå$bb‚abb€€ðƒƒ£€€øƒ€€ðƒMENUTEXT EditfieldTEXTIMG1  IMGÄ Ä Ä h=IMG@@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=IMGÄ Ä Ä ÒfIMGÒÄ h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=IMG‚ @@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^IMGÒywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfIMGÄ h=h=ÒfIMG@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒfÒfÒfÒfMENUTEXTListboxTEXTIMG1  IMGÄ Ä Ä h=IMG@@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=IMGÄ Ä Ä ÒfIMGÒÄ h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=IMG‚ @@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfIMGÄ h=h=ÒfIMG@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGÒfÒfÒfÒfMENUTEXTBackTEXTIMG1  IMGÒfÒfÒfÒfIMG@@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywIMGÒfh=h=Ä IMGŠ@ÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywÒfywIMGŠ!@@@,^,^,^,^L^,^,^,^L^L^L^L^L^,^,^,^L^L^,^,^,^L^L^L^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z+^+^+^+^+^ Z Z+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^ Z+^+^ Z+^+^+^+^ Z Z Z+^+^ Z+^+^+^+^+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^+^,^,^@+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z+^+^+^+^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^,^,^,^,^,^,^+^+^+^@+^+^+^+^+^,^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^,^,^L^L^L^,^,^,^,^,^,^,^,^+^+^+^@L^L^L^L^L^L^,^L^L^L^L^,^,^,^,^,^,^,^,^+^,^+^+^ Z+^ Z Z Z Z Z Z Z+^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^,^,^,^L^L^L^L^L^L^L^L^@,^+^+^+^,^+^+^+^+^ Z+^ Z+^ Z+^+^ Z+^+^+^+^+^+^+^+^+^,^,^,^,^+^,^+^+^,^,^,^,^,^+^+^,^+^,^,^,^,^+^+^,^+^,^,^,^,^,^,^+^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z Z Z Z+^+^,^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^+^,^,^+^+^+^+^+^ Z Z+^+^+^+^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^@,^,^+^+^,^,^,^,^,^,^,^,^+^,^+^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^ Z+^+^,^,^,^+^+^+^+^+^+^+^ Z Z Z Z+^+^+^+^,^+^+^+^ Z Z Z Z Z+^+^+^+^,^,^,^,^,^+^+^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^@ Z+^+^+^+^,^,^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^ Z+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z@L^,^,^L^L^L^L^L^,^,^,^,^,^,^,^,^+^+^+^ Z+^ Z+^+^+^+^+^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^,^,^L^L^,^L^@,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^L^,^,^@,^+^+^+^+^,^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z+^+^ Z+^+^+^+^+^+^+^+^+^+^,^+^,^,^@,^+^+^ Z+^+^+^ Z+^+^ Z+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^+^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^L^,^L^L^L^,^,^,^,^,^@L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^@+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^,^,^,^,^+^+^+^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^L^,^,^L^L^,^,^,^,^,^,^,^,^,^+^,^,^+^+^,^,^,^,^,^+^+^,^,^,^,^,^@,^,^,^,^,^,^,^,^+^+^+^+^ Z+^+^+^+^+^+^+^+^+^ Z Z+^+^,^+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^+^+^+^+^+^+^,^,^,^+^+^+^,^,^+^+^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^,^,^,^,^,^L^L^L^L^L^L^,^,^,^,^,^,^@,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^L^,^L^,^,^,^,^L^L^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^,^+^+^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^+^,^,^,^+^+^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^L^,^L^L^L^L^L^,^,^,^L^L^L^L^,^,^,^,^,^,^,^,^,^+^,^+^+^+^+^+^+^+^+^+^,^,^,^,^,^@,^,^,^,^,^+^+^+^+^+^+^+^+^,^+^+^+^ Z+^+^+^+^+^+^,^,^,^,^+^,^,^,^+^+^+^,^,^+^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^L^L^L^,^,^L^L^L^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^+^+^+^,^,^,^+^,^+^,^+^+^+^+^+^,^,^,^,^,^+^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^ Z Z Z Z+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^@+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^,^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^ Z+^+^,^,^,^+^@+^+^+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^,^,^,^,^+^@,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^+^ Z Z Z Z+^ Z Z Z Z+^+^+^+^ Z+^ Z+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@+^+^+^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^+^+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^@L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^L^@,^,^,^+^+^ Z+^+^ Z+^+^ Z Z Z Z Z Z+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^L^,^,^,^,^,^,^,^,^,^,^,^,^@,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^+^+^+^,^,^,^+^,^+^,^+^+^+^+^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^+^+^+^,^+^,^,^,^+^+^+^+^,^,^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^@,^,^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^,^,^,^,^L^,^L^,^L^,^L^L^L^L^L^,^,^,^@,^,^,^,^,^,^+^+^+^+^,^+^,^,^,^,^,^,^,^+^+^,^,^+^+^+^+^+^+^+^+^ Z Z Z Z+^+^+^+^+^+^+^+^ Z Z+^+^+^+^,^,^,^,^,^,^,^,^+^+^,^+^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^ Z+^+^+^+^+^+^+^+^+^ Z+^+^+^+^+^+^+^+^,^,^,^,^,^+^+^+^+^+^+^+^,^,^,^+^+^+^,^,^,^,^,^+^,^,^,^,^,^@+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z+^+^+^+^ Z Z+^+^+^+^+^+^,^+^+^ Z+^+^+^@ Z Z Z Z+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^,^+^+^+^ Z@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^,^,^,^+^+^,^,^,^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^+^,^,^+^+^+^+^+^+^+^,^+^+^ Z+^+^+^+^+^ Z+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^@,^+^,^,^,^,^,^,^,^+^+^+^,^+^+^,^,^+^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^+^+^,^+^,^,^,^,^+^+^,^+^,^,^,^,^,^@ Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^ Z Z Z Z@,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^,^L^,^,^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^,^+^+^+^+^+^+^,^+^+^,^,^,^,^@L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^+^+^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^@,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^@ Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^+^+^,^+^+^+^+^ Z Z Z Z Z@,^,^,^,^,^,^L^L^L^L^L^L^L^,^L^L^L^L^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^L^,^L^,^,^,^,^,^@+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^+^+^+^ Z+^+^+^+^+^ Z Z+^+^+^+^,^@,^,^+^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^,^,^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^,^,^L^L^L^L^L^L^L^L^L^L^L^,^,^,^,^@+^+^,^,^+^+^+^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^ Z+^+^ Z+^+^ Z Z Z Z Z Z+^@ Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^ Z Z Z Z Z Z Z Z Z Z Z Z+^+^+^+^+^+^+^+^+^+^,^,^,^+^+^+^+^+^+^ Z Z Z Z@,^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^,^@L^L^L^,^,^L^L^L^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^+^,^,^,^+^,^,^,^,^,^,^,^,^,^,^,^L^,^,^,^@,^,^,^,^,^+^,^,^,^,^,^,^,^,^,^L^,^L^L^,^,^,^,^,^,^,^,^,^,^L^,^,^,^,^,^,^,^,^,^,^,^,^L^,^L^L^L^,^,^,^,^,^,^,^,^,^,^+^+^,^,^+^+^,^@,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^,^+^,^,^+^,^+^+^+^ Z+^ Z Z+^ Z+^+^+^+^+^+^+^,^+^,^,^,^,^,^,^,^@L^L^L^L^L^L^L^,^,^,^,^+^+^,^+^+^+^,^+^+^+^+^ Z Z Z Z+^+^+^+^,^,^,^,^+^,^+^+^+^+^+^+^+^,^,^,^,^,^,^,^,^,^,^,^L^L^L^L^L^L^L^L^L^L^IMGŠ@h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä IMGÒfÄ Ä Ä IMG@@h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä IMGh=Ä Ä Ä MENUTEXT CheckbuttonTEXTIMG1IMG&«=å(aà å(‚)‚å(‚å(£ä$ƒÍA«=H1i9Ä$'1Ä$&-ä$H5£ ä$Ä$h5i9)¤ƒFPNQNÍE'1-¢ä$£ -å(à å(&-å(£ A‚bÌAQRI5H5å(G1‚£ &1‚£ £ å(-)å(à -AaJ/N£ G1ä(Ä$Ã$-å('1)‚)‚å(‚bbJÍA£ £ G1H5&-'1&-¢£ Ä$'1Ä$&-‚ƒb«=îE£ ¢Ä$G1à '1å()Ä$ä(£ ‚)AbÌAJä$'1H5Ä$H5'1-G5Ã$-£ ‚Ä$&-ƒ£ÌAPN£ G1‚£ £ Ä$‚ä$å(Ä$)-¢ '1‚Ã$‚ƒJQRä$‚Ä$Ä$Ä$H5ä$£ H5H5‚ä(Ä$‚å(ä(bbJîE)å(&-å(G1ä$£ Ã$-Ä$-'1£ ‚ƒA«=0NÄ$'1‚ä$£ &1)£ ‚H5H5¢Ä$¢'1@ @ «=PR‚-Ä$ä$H5£ Ä$H5Ã$'1¢'1ä$Ä$Aƒ¬=J‚Ä$G1Ä$Ä$å(‚H5‚£ G5H5Ä$£ '1£ƒÍAJä(G5à '1'1'1'1£ G1‚-Ä$ä$H5£ b¤ÍA0N&-'1å(-Ä$å(Ä$à å('1‚å(-&-‚ä$bƒi5ÌAi5£ å(ä$‚£ -ä$'1£ Ä$å(£ ¤‚bH5å$-£-Ä$¢G1&-G1ä$&-G1-'1å$bb‚£Å A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£IMG&bb@ @ bbA ƒA ‚A A ‚A‚bA A AƒA bAƒA AA£Ä å$Ab-R-R¢ä$£ -å(à å(-R-Rå(&-A-Rp^p^-R£ &1‚£ £ å(-Rp^Ój-RŠ9ƒ-Rp^Ójp^-Rå('1)‚-Rp^Ójp^-RÌAƒA -Rp^Ójp^-R¢-Rp^Ójp^-R0NÌAAa£ -Rp^Ójp^-R-Rp^Ójp^-R)îEÌAbbä$'1-Rp^ÓjNV-R-Rp^Ójp^-RÄ$&-/NJbƒ£ G1‚-Rp^ÓjNVp^Ójp^-R'1‚Ã$/JJƒ¤ä$‚Ä$Ä$-Rp^ÓjÓjp^-RÄ$‚å(ä(JÌA¤A)å(&-å(-Rp^ÓjÓjp^-R-'1£ ‚PN«=AƒÄ$'1-Rp^Ójp^p^Ójp^-RÄ$¢'1ÍAŠ9A£‚--Rp^ÓjOZ-R-Rp^Ójp^-Rä$Ä$íEJbb‚-Rp^Ójp^-R-Rp^Ójp^-R'1PRíEbb-Rp^Ójp^-R£ G1-Rp^Ójp^-RJJb-Rp^Ójp^-RÄ$à å('1-Rp^Ójp^-RîEA -Rp^p^-R‚£ -ä$'1£ -Rp^p^-RíEƒb-R-R¢G1&-G1ä$&-G1-R-R0N0Nb¤)Ä '1å(ä$'1-£ å$H5íEJÅ Ä Ä$'1à å(å(¢à £ Ä$£ å('1íEIMG&å(ä$Ä$å(¢-¢)‚‚)£ )ä(‚‚£ H5¢ -¢å(£ '1‚£ £ G1H5&-'1&-£ å(à G1'1-¢ä$£ -å(à å(&-å(à ‚)å(£ -‚H5å(G1‚£ &1‚£ £ å(-)å(à '1£ Ã$'1-£ G1ä(Ä$Ã$-å('1)‚)‚å(‚ä(ä$'1‚£ £ G1H5&-'1&-¢£ Ä$'1Ä$&-‚&-ä$£ à £ ¢Ä$G1à '1å()Ä$ä(£ ‚)£ å(ä$ä$ä$'1H5Ä$H5'1-G5Ã$-£ ‚Ä$&--G5å('1£ G1‚£ £ Ä$‚ä$å(Ä$)-¢ '1‚Ã$)'1'1H5ä$‚Ä$Ä$Ä$H5ä$£ H5H5‚ä(Ä$‚å(ä(å(å(H5£ )å(&-å(G1ä$£ Ã$-Ä$-'1£ ‚'1¢ £ &-Ä$'1‚ä$£ &1)£ ‚H5H5¢Ä$¢'1£ G1‚-Ä$ä$H5£ Ä$H5Ã$'1¢'1ä$Ä$¢ '1Ä$ä$‚Ä$G1Ä$Ä$å(‚H5‚£ G5H5Ä$£ '1G1-å(å(ä(G5à '1'1'1'1£ G1‚-Ä$ä$H5£ Ä$H5å('1&-'1å(-Ä$å(Ä$à å('1‚å(-&-‚ä$Ä$-‚-G5£ å(ä$‚£ -ä$'1£ Ä$å(£ å()ä$'1å(&1-Ä$¢G1&-G1ä$&-G1-'1'1Ä$Ä$-ä$G5£ )Ä$‚-Ã$£ )å(‚à '1'1à å(ä$G5å(ä$H5Ä$))£ Ä$£ ä(Ã$å(-G5MENUTEXT PosbuttonTEXTIMG1IMGòÒfÒfÒfÒfywÒfÒfÒf ÒfywywywÒfÒfÒf ÒfywÒfywywywÒfÒfÒfÒfywÒfL^ÒfywywywÒfÒfÒfÒfywÒfL^L^L^ÒfywywywÒfÒfÒfÒfywÒfL^L^L^L^L^ÒfywywywÒfÒfÒfÒfywÒfL^L^L^L^L^L^L^ÒfywywywÒfÒfÒfÒfywÒfL^L^L^L^L^L^L^L^L^ÒfywywywÒfÒfÒfÒfywÒfL^L^L^L^L^L^L^L^L^L^L^ÒfywywywÒfÒfh=ÒfywÒfL^L^L^L^L^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä ÒfywÒfL^L^L^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä ÒfywÒfL^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä ÒfywÒfL^L^L^L^L^L^ Z Zh=h=Ä Ä ÒfywÒfL^L^L^L^ Z Zh=h=Ä Ä ÒfywÒfL^L^ Z Zh=h=Ä Ä ÒfÒfL^ Z Zh=h=Ä Ä Òf Z Zh=h=Ä Ä L^h=h=Ä Ä h=Ä Ä IMGòÄ Ä Ä Ä h=h=Ä Ä Ä h= Zh=h=Ä Ä Ä h= Z Z Zh=h=Ä Ä Ä h= ZL^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^L^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^L^L^L^L^L^L^L^L^ Z Zh=h=Ä Ä Ä h= ZL^L^L^L^L^L^L^L^L^L^L^ÒfywywywÒfÒfh=Ä h= ZL^L^L^L^L^L^L^L^L^ÒfywywywÒfÒfÒfÄ h= ZL^L^L^L^L^L^L^ÒfywywywÒfÒfÒfÄ h= ZL^L^L^L^L^ÒfywywywÒfÒfÒfÄ h= ZL^L^L^ÒfywywywÒfÒfÒfÄ h= ZL^ÒfywywywÒfÒfÒf Ä h= ZywywywÒfÒfÒf Ä ZywywÒfÒfÒfh=ywÒfÒfÒfÒfÒfÒfIMGòÒfÒfÒfÒfÒfÒfÒfÒf ÒfÒfL^ÒfÒfÒfÒf ÒfÒfL^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^L^L^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^L^L^L^L^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^L^L^L^L^L^L^L^L^ÒfÒfÒfÒfÒfÒfL^L^L^L^L^L^L^L^L^L^L^L^L^L^L^ÒfÒfL^L^ÒfÒfL^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^L^h=h=ÒfÒfL^L^L^L^L^L^L^L^L^L^L^L^L^h=h=h=h=ÒfÒfL^L^L^L^L^L^L^L^L^L^L^h=h=h=h=ÒfÒfL^L^L^L^L^L^L^L^L^h=h=h=h=ÒfÒfL^L^L^L^L^L^L^h=h=h=h=ÒfÒfL^L^L^L^L^h=h=h=h= ÒfÒfL^L^L^h=h=h=h= ÒfÒfL^h=h=h=h=ÒfL^h=h=h=L^h=h=MENUTEXT ScrollbarTEXTIMG1IMG&J«='-'-i5Š9H1‹=H1Š9'-'-Š9H1H5Ä$îEFíAJ‹9íEŠ9ÌA«=îEŠ9‹9‹9JJŠ9æ(¤Ì=0NqRíE'1-¢ä$£ -å(à å(&-å(à a‚bH1íEi5H5å(G1‚£ &1‚£ £ å(-'1Aai9‹=£ G1ä(Ä$Ã$-å('1)‚ÿÿbbi9(1£ £ G1H5&-'1&-ÿÿÿÿ‚ƒb)i5£ ¢Ä$G1ÿÿÿÿÿÿ)Ab'1Š9ä$'1H5Ä$ÿÿÿÿÿÿÿÿ&-ƒ£'1ÌA£ G1ÿÿÿÿÿÿÿÿÿÿÃ$‚ƒi9ÌAä$ÿÿÿÿÿÿÿÿÿÿÿÿä(bbŠ=H1)ÿÿÿÿÿÿÿÿÿÿÿÿ‚ƒA)«=Ä$ÿÿÿÿÿÿÿÿÿÿ'1@ @ )ÌA‚-Ä$ÿÿÿÿÿÿÿÿÄ$Aƒ-Š9‚Ä$G1Ä$Ä$ÿÿÿÿÿÿ'1£ƒ'1Š9ä(G5à '1'1'1'1£ ÿÿÿÿ£ b¤H1«A&-'1å(-Ä$å(Ä$à å('1ÿÿä$bƒ£ -'1£ å(ä$‚£ -ä$'1£ Ä$¤‚bå$£Ä a-Ä$¢G1&-G1ä$&-G1-'1å$bb‚b£A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£IMG&bb@ @ bbA ƒA ‚A A ‚A‚bA A A¤AƒA bAƒA AA£¤ƒƒƒAbaå$'1-¢ä$£ -å(à å(&-å(£ a¤Ä A‚aH5å(G1‚£ &1‚£ £ å(-'1Ä$Ä$ƒ‚£ G1ä(Ä$Ã$-å('1)‚ÿÿŠ9'-ƒA £ £ G1H5&-'1&-ÿÿÿÿ‚«='-Aa£ ¢Ä$G1ÿÿÿÿÿÿ)H5'1bbä$'1H5Ä$ÿÿÿÿÿÿÿÿ&-«=Š9bƒ£ G1ÿÿÿÿÿÿÿÿÿÿÃ$Š9i9ƒ¤ä$ÿÿÿÿÿÿÿÿÿÿÿÿä(Š9'1¤A)ÿÿÿÿÿÿÿÿÿÿÿÿ‚ÌAå(AƒÄ$ÿÿÿÿÿÿÿÿÿÿ'1'-ä$A£‚-Ä$ÿÿÿÿÿÿÿÿÄ$H1i9bb‚Ä$G1Ä$Ä$ÿÿÿÿÿÿ'1ÌAH5bbä(G5à '1'1'1'1£ ÿÿÿÿ£ i5Š=bƒ&-'1å(-Ä$å(Ä$à å('1ÿÿä$i9i5A ‚G1£ å(ä$‚£ -ä$'1£ Ä$«=íEi5ƒbå$-Ä$¢G1&-G1ä$&-G1-'1ÍEqRJîEƒ)'-ÌA¬=Š9íE«=‹9ÍAÌAŠ9«=îEîEîE0N/J'-H1i5ÌAi5Š9Š9H1i5H1i9i5Š9'-ÌAPNIMG&å(ä$Ä$å(¢-¢)‚‚)£ )ä(‚‚£ H5¢ -¢å(£ '1‚£ £ G1H5&-'1&-£ å(à G1'1-¢ä$£ -å(à å(&-å(à ‚)å(£ -‚H5å(G1‚£ &1‚£ £ å(-'1£ Ã$'1-£ G1ä(Ä$Ã$-å('1)‚BBä(ä$'1‚£ £ G1H5&-'1&-BBBB‚&-ä$£ à £ ¢Ä$G1BBBBBB)£ å(ä$ä$ä$'1H5Ä$BBBBBBBB&--G5å('1£ G1BBBBBBBBBBÃ$)'1'1H5ä$BBBBBBBBBBBBä(å(å(H5£ )BBBBBBBBBBBB‚'1¢ £ &-Ä$BBBBBBBBBB'1£ G1‚-Ä$BBBBBBBBÄ$¢ '1Ä$ä$‚Ä$G1Ä$Ä$BBBBBB'1G1-å(å(ä(G5à '1'1'1'1£ BBBB£ Ä$H5å('1&-'1å(-Ä$å(Ä$à å('1BBä$Ä$-‚-G5£ å(ä$‚£ -ä$'1£ Ä$å()ä$'1å(&1-Ä$¢G1&-G1ä$&-G1-'1'1Ä$Ä$-ä$G5£ )Ä$‚-Ã$£ )å(‚à '1'1à å(ä$G5å(ä$H5Ä$))£ Ä$£ ä(Ã$å(-G5IMG&J«='-'-i5Š9H1‹=H1Š9'-'-Š9H1H5Ä$îEFíAJ‹9íEŠ9ÌA«=îEŠ9‹9‹9JJŠ9æ(¤Ì=0NqRíE'1-¢ä$£ -å(à å(&-å(à a‚bH1íEi5‚£ &1‚£ £ å(-)å(à '1Aai9‹=£ ÿÿå('1)‚)‚å(‚bbi9(1£ ÿÿÿÿ¢£ Ä$'1Ä$&-‚ƒb)i5£ ÿÿÿÿÿÿÄ$ä(£ ‚)Ab'1Š9ä$ÿÿÿÿÿÿÿÿ£ ‚Ä$&-ƒ£'1ÌA£ ÿÿÿÿÿÿÿÿÿÿ‚Ã$‚ƒi9ÌAä$ÿÿÿÿÿÿÿÿÿÿÿÿä(bbŠ=H1)ÿÿÿÿÿÿÿÿÿÿÿÿ‚ƒA)«=ÿÿÿÿÿÿÿÿÿÿ¢'1@ @ )ÌA‚ÿÿÿÿÿÿÿÿ¢'1ä$Ä$Aƒ-Š9‚ÿÿÿÿÿÿ£ G5H5Ä$£ '1£ƒ'1Š9ä(ÿÿÿÿG1‚-Ä$ä$H5£ b¤H1«A&-ÿÿÄ$à å('1‚å(-&-‚ä$bƒ£ -'1ä$‚£ -ä$'1£ Ä$å(£ ¤‚bå$£Ä a-Ä$¢G1&-G1ä$&-G1-'1å$bb‚b£A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£IMG&bb@ @ bbA ƒA ‚A A ‚A‚bA A A¤AƒA bAƒA AA£¤ƒƒƒAbaå$'1-¢ä$£ -å(à å(&-å(£ a¤Ä A‚a‚£ &1‚£ £ å(-)å(à '1Ä$Ä$ƒ‚£ ÿÿå('1)‚)‚å(‚Š9'-ƒA £ ÿÿÿÿ¢£ Ä$'1Ä$&-‚«='-Aa£ ÿÿÿÿÿÿÄ$ä(£ ‚)H5'1bbä$ÿÿÿÿÿÿÿÿ£ ‚Ä$&-«=Š9bƒ£ ÿÿÿÿÿÿÿÿÿÿ‚Ã$Š9i9ƒ¤ä$ÿÿÿÿÿÿÿÿÿÿÿÿä(Š9'1¤A)ÿÿÿÿÿÿÿÿÿÿÿÿ‚ÌAå(Aƒÿÿÿÿÿÿÿÿÿÿ¢'1'-ä$A£‚ÿÿÿÿÿÿÿÿ¢'1ä$Ä$H1i9bb‚ÿÿÿÿÿÿ£ G5H5Ä$£ '1ÌAH5bbä(ÿÿÿÿG1‚-Ä$ä$H5£ i5Š=bƒ&-ÿÿÄ$à å('1‚å(-&-‚ä$i9i5A ‚G1ä$‚£ -ä$'1£ Ä$å(£ «=íEi5ƒbå$-Ä$¢G1&-G1ä$&-G1-'1ÍEqRJîEƒ)'-ÌA¬=Š9íE«=‹9ÍAÌAŠ9«=îEîEîE0N/J'-H1i5ÌAi5Š9Š9H1i5H1i9i5Š9'-ÌAPNIMG&å(ä$Ä$å(¢-¢)‚‚)£ )ä(‚‚£ H5¢ -¢å(£ '1‚£ £ G1H5&-'1&-£ å(à G1'1-¢ä$£ -å(à å(&-å(à ‚)å(£ -‚‚£ &1‚£ £ å(-)å(à '1£ Ã$'1-£ BBå('1)‚)‚å(‚ä(ä$'1‚£ BBBB¢£ Ä$'1Ä$&-‚&-ä$£ à £ BBBBBBÄ$ä(£ ‚)£ å(ä$ä$ä$BBBBBBBB£ ‚Ä$&--G5å('1£ BBBBBBBBBB‚Ã$)'1'1H5ä$BBBBBBBBBBBBä(å(å(H5£ )BBBBBBBBBBBB‚'1¢ £ &-BBBBBBBBBB¢'1£ G1‚BBBBBBBB¢'1ä$Ä$¢ '1Ä$ä$‚BBBBBB£ G5H5Ä$£ '1G1-å(å(ä(BBBBG1‚-Ä$ä$H5£ Ä$H5å('1&-BBÄ$à å('1‚å(-&-‚ä$Ä$-‚-G5ä$‚£ -ä$'1£ Ä$å(£ å()ä$'1å(&1-Ä$¢G1&-G1ä$&-G1-'1'1Ä$Ä$-ä$G5£ )Ä$‚-Ã$£ )å(‚à '1'1à å(ä$G5å(ä$H5Ä$))£ Ä$£ ä(Ã$å(-G5IMG‚ Ä Ä Ä Ä Ä Ä Ä Ä  Ä h=h=h=h=h=h=h=h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=Ä h=QN¬9¬9J1Ä h=¬9æ$æ$„æ$æ$æ$Ä h=¬9æ$æ$„æ$æ$æ$Ä h=J1„„cÄ h=Ä h=Ä Òfh=Òfh=ywÒfywÒfyw ÒfywywywywywywywywÒfÒfÒfÒfÒfÒfÒfÒfIMGŽ@@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@@@@@@@@@æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$@æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$æ$@@@@@@@@@ywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywywyw@ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMG‚ Ä Ä Ä Ä Ä Ä Ä Ä h=h=h=h=h=h=h=h=Ä h=Ä h=Ä Òfh= Òfh= ywÒf ywÒfywÒfQN¬9¬9J1ywÒfæ$æ$æ$¬9æ$æ$„ywÒfæ$æ$æ$¬9æ$æ$„ywÒfJ1„„cywÒfywÒf ywÒf ywÒf ywÒf ywÒf ywÒfywÒf ywywywywywywywywÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGRJ«=îEFíAÌ=0NqRíEH1íEi5H5i9‹=£ G1i9(1£ £ )i5£ ¢'1Š9ä$'1'1ÌA£ G1i9ÌAä$‚Š=H1)å()«=Ä$)ÌA‚--Š9‚Ä$'1Š9ä(G5H1«A&-'1£ -'1£ å$£Ä ab£A£bIMGŽ @@@'-'-i5Š9H1‹=i5ÌAH1Š=Š9'-Š9H1Š9ÌAŠ9'-H1H1ÌAŠ9'-Š9H1H1«=H1H1«AH5i5«=i5H1j9'-i5'-H1'1ÌAH1'-i5'-«=Š9ÌAÌA«=i5‹=«='-«Aj9i5H1Š9'-'-Š9H1@J‹9íEŠ9ÌA«=íEJŠ9ÌAÍA«=ÍAJÌAŠ9‹9«=Š9«=«=‹9ÌAÍAÌAÌAŠ9Š9JíEŠ9íEJÍAŠ9‹9Š9JŠ9ÌAJ¬=Š5‹9JÌAŠ9ÌAŠ9îEŠ5‹9íEÍAŠ9ÌAŠ9«=îEŠ9‹9‹9JJ@'1-¢ä$£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ å(-H5-Ä$‚Ä$£ '1&1ä$-å(à å(&-å(@å(G1‚£ &1‚å(‚'1'1Ã$å(£ )ä(£ £ å(Ä$å('1å(£ '1‚£ å(Ä$H5‚£ --ä$)£ H5£ -Ã$å(&-Ä$-Ã$G5Ä$Ä$‚‚‚£ ‚-G1G5å(£ £ å(-)å(@ä(Ä$Ã$-å('1-Ä$£ £ &-Ä$--£ G1'1'1å(-à &1å(&-å(ä$ä$£ G1å(-‚£ ‚&-G5‚ä$Ä$‚¢£ ä(å(H5'1à '1å(Ä$ä$‚£ &-£ £ '1)‚)‚å(@G1H5&-'1&-‚å(G1'1Ä$'1H5Ã$-'1à &-‚Ä$à G5£ G1à å(à &1)å(£ '1ä$)Ä$Ä$H5Ä$å(£ ¢ä$-å(&-å(à -å(å(å(‚¢à Ä$‚&-¢£ Ä$'1Ä$&-@Ä$G1à '1'1£ -å(å(‚å(£ ä$ä$£ H5£ -‚G1'1H5)'1£ Ä$å(-Ä$-H5G1G5)Ä$£ -‚‚£ )'1'1)Ä$)'1'1G1å()Ä$ä(£ @H5Ä$H5'1-G5‚£ '1ä$£ -ä$å(å(G1Ã$)G1Ä$G1H5à £ G5‚-£ ¢'1'1£ ¢Ã$Ã$£ å(£ ‚'1å(Ã$)¢G1&1H5£ £ ‚&1å('1ä$Ä$G1Ã$-£ ‚@‚£ £ Ä$‚ä$Ä$ä$'1¢ -H5‚)ä$ä$‚Ã$‚G1Ä$¢‚-Ä$å(¢Ä$-à à H5£ Ä$£ --)‚ä$å(å(à &--G1&1ä(¢ ‚))-¢£ å(Ä$)-¢ '1@Ä$Ä$Ä$H5ä$£ -Ä$¢å(à '1-£ -Ä$Ä$£ ‚)&-à -'1-å(Ä$)à Ä$ä$£ &-¢£ H5¢G5&1-à -‚&-'1‚Ã$ä$‚H5ä$‚Ä$Ä$Ä$¢£ H5H5‚ä(Ä$‚@&-å(G1ä$£ Ã$)&-&-å(Ä$&-£ '1ä$£ ¢ -Ã$å(‚H5£ )ä(H5)Ä$H5-‚'1¢H5Ä$&-ä$‚å(å(å(-‚H5‚‚å(¢‚‚£ G5-&-G1--Ä$-'1@'1‚ä$£ &1)Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)--G1&1à )&-)£ &1¢å(£ ‚H5H5¢Ä$@Ä$ä$H5£ Ä$à ‚‚£ å(-G1-‚-£ -£ G1£ '1H5¢£ ‚£ à £ Ä$)&-ä$‚ä(Ä$&-à Ä$ä$--Ä$¢å()H5-H5G5å(å('1G1'1Ä$¢ H5Ã$'1¢'1@G1Ä$Ä$å(‚£ ¢å(&-'1ä$ä$Ä$å('1‚&-&1£ å()-ä$)‚£ &-å(ä$-‚G5Ä$¢H5'1‚Ã$Ä$Ä$ä$‚à å(G5&-'1‚‚¢ G5ä$)G5-)H5‚£ G5H5Ä$@à '1'1'1'1£ ‚£ £ G5å(‚-£ £ -¢ £ '1à ä$'1ä$¢å(‚Ä$‚£ ‚G5£ ‚Ä$&-)G1H5&-Ä$-'1‚'1å(Ä$-‚‚Ä$å(G5£ &--Ä$G1‚-Ä$ä$@å(-Ä$å(Ä$à ä$‚‚à --£ ä$)H5-&-&-'1H5Ä$Ä$à ¢ä(ä$Ä$å(å(-Ä$£ )'1¢å(Ä$‚¢H5‚'1)å(&1Ä$G1å(¢--‚£ å('1‚å(-&-@å(ä$‚£ -à G1‚å(à ‚G1-'1Ä$'1å()G1G5Ä$ä$‚£ £ Ä$à )-Ä$å(G1'1å(&---)ä(ä$Ã$))å(H5¢ '1&-¢‚-£ å(Ä$ä$'1£ Ä$å(@-Ä$¢G1&-‚¢G1Ä$H5'1‚‚¢Ä$å(H5Ã$-£ £ '1-‚-£ £ å(£ ))å(Ä$G5‚¢ £ -ä$£ ¢ £ å(H5£ '1-Ä$)Ä$Ã$Ã$Ä$)G1ä$&-G1-'1@‚bA ƒaA‚ƒ£ƒAƒƒ‚bA bƒAAab‚ƒA ƒƒbƒ‚££¤ƒb¤¤A A ƒƒƒbƒƒb‚ƒ@ £ƒ@ A bb£‚A ‚bA aƒƒ@b¤b‚‚AƒƒabaƒbbA ƒƒab@ A‚bAAbbbƒbAƒA Abb¤A Aƒƒb‚A¤Aƒabƒbƒa£bbA A bAbab@ @IMGRH5Ä$Š9æ(¤à a‚bà '1Aa‚bb‚ƒb‚)AbÄ$&-ƒ£‚Ã$‚ƒå(ä(bb£ ‚ƒA¢'1@ @ ä$Ä$Aƒ£ '1£ƒH5£ b¤‚ä$bƒ£ ¤‚bå$bb‚abbƒ£IMG&J«='-'-i5Š9H1‹=H1Š9'-'-Š9H1H5Ä$îEFíAJ‹9íEŠ9ÌA«=îEŠ9‹9‹9JJŠ9æ(¤Ì=0NqRíE'1-¢ä$£ -å(à å(&-å(à a‚bH1íEi5H5å(G1‚£ &1£ å(-)å(à '1Aai9‹=£ G1ä(Ä$Ã$-ÿÿ)‚å(‚bbi9(1£ £ G1H5&-'1ÿÿÄ$'1Ä$&-‚ƒb)i5£ ¢Ä$G1ÿÿÿÿä(£ ‚)Ab'1Š9ä$'1H5Ä$H5ÿÿÿÿ£ ‚Ä$&-ƒ£'1ÌA£ G1‚£ ÿÿÿÿÿÿ¢ '1‚Ã$‚ƒi9ÌAä$‚Ä$Ä$ÿÿÿÿÿÿÄ$‚å(ä(bbŠ=H1)å(&-ÿÿÿÿÿÿÿÿ'1£ ‚ƒA)«=Ä$'1ÿÿÿÿÿÿÿÿÄ$¢'1@ @ )ÌA‚-ÿÿÿÿÿÿÿÿÿÿä$Ä$Aƒ-Š9‚Ä$ÿÿÿÿÿÿÿÿÿÿ£ '1£ƒ'1Š9ä(ÿÿÿÿÿÿÿÿÿÿÿÿ£ b¤H1«A&-ÿÿÿÿÿÿÿÿÿÿÿÿä$bƒ£ -'1¤‚bå$£Ä a-Ä$¢G1&-G1ä$&-G1-'1å$bb‚b£A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£IMG&å(ä$Ä$å(¢-¢)‚‚)£ )ä(‚‚£ H5¢ -¢å(£ '1‚£ £ G1H5&-'1&-£ å(à G1'1-¢ä$£ -å(à å(&-å(à ‚)å(£ -‚H5å(G1‚£ &1£ å(-)å(à '1£ Ã$'1-£ G1ä(Ä$Ã$-BB)‚å(‚ä(ä$'1‚£ £ G1H5&-'1BBÄ$'1Ä$&-‚&-ä$£ à £ ¢Ä$G1BBBBä(£ ‚)£ å(ä$ä$ä$'1H5Ä$H5BBBB£ ‚Ä$&--G5å('1£ G1‚£ BBBBBB¢ '1‚Ã$)'1'1H5ä$‚Ä$Ä$BBBBBBÄ$‚å(ä(å(å(H5£ )å(&-BBBBBBBB'1£ ‚'1¢ £ &-Ä$'1BBBBBBBBÄ$¢'1£ G1‚-BBBBBBBBBBä$Ä$¢ '1Ä$ä$‚Ä$BBBBBBBBBB£ '1G1-å(å(ä(BBBBBBBBBBBB£ Ä$H5å('1&-BBBBBBBBBBBBä$Ä$-‚-G5å()ä$'1å(&1-Ä$¢G1&-G1ä$&-G1-'1'1Ä$Ä$-ä$G5£ )Ä$‚-Ã$£ )å(‚à '1'1à å(ä$G5å(ä$H5Ä$))£ Ä$£ ä(Ã$å(-G5IMG&bb@ @ bbA ƒA ‚A A ‚A‚bA A A¤AƒA bAƒA AA£¤ƒƒƒAbaå$'1-¢ä$£ -å(à å(&-å(£ a¤Ä A‚aH5å(G1‚£ &1£ å(-)å(à '1Ä$Ä$ƒ‚£ G1ä(Ä$Ã$-ÿÿ)‚å(‚Š9'-ƒA £ £ G1H5&-'1ÿÿÄ$'1Ä$&-‚«='-Aa£ ¢Ä$G1ÿÿÿÿä(£ ‚)H5'1bbä$'1H5Ä$H5ÿÿÿÿ£ ‚Ä$&-«=Š9bƒ£ G1‚£ ÿÿÿÿÿÿ¢ '1‚Ã$Š9i9ƒ¤ä$‚Ä$Ä$ÿÿÿÿÿÿÄ$‚å(ä(Š9'1¤A)å(&-ÿÿÿÿÿÿÿÿ'1£ ‚ÌAå(AƒÄ$'1ÿÿÿÿÿÿÿÿÄ$¢'1'-ä$A£‚-ÿÿÿÿÿÿÿÿÿÿä$Ä$H1i9bb‚Ä$ÿÿÿÿÿÿÿÿÿÿ£ '1ÌAH5bbä(ÿÿÿÿÿÿÿÿÿÿÿÿ£ i5Š=bƒ&-ÿÿÿÿÿÿÿÿÿÿÿÿä$i9i5A ‚G1«=íEi5ƒbå$-Ä$¢G1&-G1ä$&-G1-'1ÍEqRJîEƒ)'-ÌA¬=Š9íE«=‹9ÍAÌAŠ9«=îEîEîE0N/J'-H1i5ÌAi5Š9Š9H1i5H1i9i5Š9'-ÌAPNIMG&J«='-'-i5Š9H1‹=H1Š9'-'-Š9H1H5Ä$îEFíAJ‹9íEŠ9ÌA«=îEŠ9‹9‹9JJŠ9æ(¤Ì=0NqRíE'1-¢ä$£ -å(à å(&-å(à a‚bH1íEi5'1Aai9‹=£ ÿÿÿÿÿÿÿÿÿÿÿÿbbi9(1£ ÿÿÿÿÿÿÿÿÿÿÿÿ‚ƒb)i5£ ¢ÿÿÿÿÿÿÿÿÿÿ‚)Ab'1Š9ä$'1ÿÿÿÿÿÿÿÿÿÿÄ$&-ƒ£'1ÌA£ G1‚ÿÿÿÿÿÿÿÿ'1‚Ã$‚ƒi9ÌAä$‚Ä$ÿÿÿÿÿÿÿÿ‚å(ä(bbŠ=H1)å(&-å(ÿÿÿÿÿÿ-'1£ ‚ƒA)«=Ä$'1‚ÿÿÿÿÿÿ¢Ä$¢'1@ @ )ÌA‚-Ä$ä$ÿÿÿÿ¢'1ä$Ä$Aƒ-Š9‚Ä$G1Ä$Ä$ÿÿÿÿG5H5Ä$£ '1£ƒ'1Š9ä(G5à '1'1'1ÿÿ-Ä$ä$H5£ b¤H1«A&-'1å(-Ä$å(ÿÿ‚å(-&-‚ä$bƒ£ -'1£ å(ä$‚£ '1£ Ä$å(£ ¤‚bå$£Ä a-Ä$¢G1&-G1ä$&-G1-'1å$bb‚b£A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£IMG&å(ä$Ä$å(¢-¢)‚‚)£ )ä(‚‚£ H5¢ -¢å(£ '1‚£ £ G1H5&-'1&-£ å(à G1'1-¢ä$£ -å(à å(&-å(à ‚)å(£ -‚'1£ Ã$'1-£ BBBBBBBBBBBBä(ä$'1‚£ BBBBBBBBBBBB‚&-ä$£ à £ ¢BBBBBBBBBB‚)£ å(ä$ä$ä$'1BBBBBBBBBBÄ$&--G5å('1£ G1‚BBBBBBBB'1‚Ã$)'1'1H5ä$‚Ä$BBBBBBBB‚å(ä(å(å(H5£ )å(&-å(BBBBBB-'1£ ‚'1¢ £ &-Ä$'1‚BBBBBB¢Ä$¢'1£ G1‚-Ä$ä$BBBB¢'1ä$Ä$¢ '1Ä$ä$‚Ä$G1Ä$Ä$BBBBG5H5Ä$£ '1G1-å(å(ä(G5à '1'1'1BB-Ä$ä$H5£ Ä$H5å('1&-'1å(-Ä$å(BB‚å(-&-‚ä$Ä$-‚-G5£ å(ä$‚£ '1£ Ä$å(£ å()ä$'1å(&1-Ä$¢G1&-G1ä$&-G1-'1'1Ä$Ä$-ä$G5£ )Ä$‚-Ã$£ )å(‚à '1'1à å(ä$G5å(ä$H5Ä$))£ Ä$£ ä(Ã$å(-G5IMG&bb@ @ bbA ƒA ‚A A ‚A‚bA A A¤AƒA bAƒA AA£¤ƒƒƒAbaå$'1-¢ä$£ -å(à å(&-å(£ a¤Ä A‚a'1Ä$Ä$ƒ‚£ ÿÿÿÿÿÿÿÿÿÿÿÿŠ9'-ƒA £ ÿÿÿÿÿÿÿÿÿÿÿÿ‚«='-Aa£ ¢ÿÿÿÿÿÿÿÿÿÿ‚)H5'1bbä$'1ÿÿÿÿÿÿÿÿÿÿÄ$&-«=Š9bƒ£ G1‚ÿÿÿÿÿÿÿÿ'1‚Ã$Š9i9ƒ¤ä$‚Ä$ÿÿÿÿÿÿÿÿ‚å(ä(Š9'1¤A)å(&-å(ÿÿÿÿÿÿ-'1£ ‚ÌAå(AƒÄ$'1‚ÿÿÿÿÿÿ¢Ä$¢'1'-ä$A£‚-Ä$ä$ÿÿÿÿ¢'1ä$Ä$H1i9bb‚Ä$G1Ä$Ä$ÿÿÿÿG5H5Ä$£ '1ÌAH5bbä(G5à '1'1'1ÿÿ-Ä$ä$H5£ i5Š=bƒ&-'1å(-Ä$å(ÿÿ‚å(-&-‚ä$i9i5A ‚G1£ å(ä$‚£ '1£ Ä$å(£ «=íEi5ƒbå$-Ä$¢G1&-G1ä$&-G1-'1ÍEqRJîEƒ)'-ÌA¬=Š9íE«=‹9ÍAÌAŠ9«=îEîEîE0N/J'-H1i5ÌAi5Š9Š9H1i5H1i9i5Š9'-ÌAPNIMGl Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä h=h=ÒfÄ h=h=h=h=h=h=h=h=h=h=h=h=ÒfÒfywywÒfÄ h=ywÒfÄ h=ywÒfÄ h=QN¬9¬9J1ywÒfÄ h=¬9æ$æ$„ywÒfÄ h=¬9æ$æ$„ywÒfÄ h=J1„„cywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfIMGŠ@Ä h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfIMGl Ä h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=æ$æ$ywÒfÄ h=QN¬9¬9J1ywÒfÄ h=¬9æ$æ$„ywÒfÄ h=¬9æ$æ$„ywÒfÄ h=J1„„cywÒfÄ h=ywÒfÄ h=ywÒfÄ h=ÒfÒfywywywywywywywywywywywywywÒfÄ h=h=ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMGìJ«='-'-i5Š9H1‹=H1Š9'-'-Š9H1H5Ä$îEFíAJ‹9íEŠ9ÌA«=îEŠ9‹9‹9JJŠ9æ(¤Ì=0NqRíE'1-¢ä$£ -å(à å(&-å(à a‚bH1íEi5H5å(G1‚£ &1‚£ £ å(-)å(à '1AaIMGŠ @i9‹=£ G1ä(Ä$Ã$-å('1)‚)‚å(‚bbi9(1£ £ G1H5&-'1&-¢£ Ä$'1Ä$&-‚ƒb)i5£ ¢Ä$G1à '1å()Ä$ä(£ ‚)Ab'1Š9ä$'1H5Ä$H5'1-G5Ã$-£ ‚Ä$&-ƒ£'1ÌA£ G1‚£ £ Ä$‚ä$å(Ä$)-¢ '1‚Ã$‚ƒi9ÌAä$‚Ä$Ä$Ä$H5ä$£ H5H5‚ä(Ä$‚å(ä(bbH5‹=‚à ä$‚£ à Ã$)Ä$‚'1‚-å(-ƒbi5«=¢G1‚£ ¢‚-&--ä$£ £ å(Ä$‚£ £¤-ÌAG1‚£ å(‚£ &-Ä$'1'1G1£ '1G1A A'-«=Ä$‚à G5&-£ £ å(¢¢ ä$-'1£ '1£ bƒ-H1H5å(-å('1å('1Ä$å(-£ å(Ä$&-Ã$'1‚‚i9«='1à -‚ä$--&-à H5-å('1Ä$å(H5b@ '1«=‚£ -ä$G1‚£ '1‚ä$‚H5-¢ƒbG1Š9‚‚ä$£ Ä$--'1-)å(Ã$-£ £ ¤Aå(Š9¢G1)£ å(‚£ ä$£ ä$å(-£ )‚bbi9H1Ä$-H5-'1-£ £ -ä$å(£ '1G1ä(£ A ¤‰9Š9å('1-¢ ‚£ å(¢ Ä$‚G1ä$à '1£ à A‚-ÌAH5Ä$&-£ &--£ -Ä$Ã$Ã$ä$&-'1£ £ AA H1H5Ã$'1&-'1&1£ )Ã$£ ‚)‚å(å(Ä$A AÄ$i5-å('1à £ G1)å(‚G1£ Ä$-Ä$)bA)i5£ )H5ä$å(£ å(‚)G1H5à à å(&-b£H1Š9£ G1Ä$'1)'1Ä$H5&-Ä$Ä$£ G5&1'1ä$Ab'1‹='1G5Ä$ä$-H5G5£ à ¢G1-£ å(å(‚bA )«=-Ä$à ¢ä$¢‚)-‚H5‚G1&-£ ä(ƒ‚)H1‚ä$¢å()£ ¢ ä('1-à G1à å('1Ä$‚A'1«=-‚ä(‚‚‚£ H5-£ å(ä$‚&-bA'-¬A£ £ ä$Ä$£ £ -)å(Ä$G5'1à ä$£ à A ƒG1i5£ £ Ä$‚&-à ä$Ä$Ä$å(‚H5&1£ å(Ä$A A‰9«Aå(Ä$å(£ å(£ £ H5)¢-))G1Ä$ä$£AG1Š9£ à ‚ä$Ä$¢ -à Ä$£ '1å(å(H5-ƒƒ)ÌA))å(G5-)£ ‚Ä$-¢£ -‚-A ai9ÌA)--£ ‚&-å('1ä$à '1£ '1‚£ Ä$ƒbå(ÌAå(Ä$‚G5ä$H5¢£ à '1Ä$ä$£ -¢£ƒ)«=Ä$å(Ä$Ä$Ä$‚H5&-H5£ å()‚-å(‚bH1Š9G5G1£ ¢ä(£ Ä$¢£ ¢Ä$&-ä$)A A -ÌA‚'1)&-H5Ä$'1&-£ Ä$Ã$-Ä$G5)H5AbŠ=ÌE¢ å('1)'1&-ä$H5£ Ã$Ä$H5‚£ -A A å$H1£ &-¢G1‚à -‚¢-£ -Ä$ä$H5H5¤b)H1--å(H5Ã$Ä$Ä$å(G5-å(H5å(Ä$£ G5A A i5«=ä$-&-Ä$ä$)å(&1)£ G1£ ‚-å(bAH5«=£ )Ä$Ä$Ä$-Ä$å(-‚‚G5¢¢Ã$å(£A '1«=¢ ä(‚-ä$-Ã$à ä$'1)ä$£ å(b£H1Š9£ ä$¢'1‚Ä$Ã$--å(å(Ä$-ä(&-'1@ A)«Aå(Ã$H5‚à ¢Ä$‚‚å(Ã$£ å(å(Ä$G1AA Š=ÌAH5)‚'1å(å(H5&-à )-&-H5-'1¤b)i9)'1å(G5))‚'1&-¢‚å('1Ã$Ä$b@ h5‹=£ å(Ä$&-H5-‚‚-G1‚à à G5¢ A ƒ-«='1H5)-'1--å(Ã$G1&1£ -'1Ä$å(b‚H1'-¢ å(‚‚H5G1¢ä$&1H5)å(Ä$-A £i5ÌA-'1&1‚‚G5&1‚‚ä(£ '1å(Ä$‚H5ƒ¤'-¬AÄ$&-Ä$Ä$¢ å(à H5¢ £ å(ä$‚-@ ƒH5'-)¢G1å(G5å()‚ä$‚‚'1å(‚‚Ä$Ab-H1Ä$‚å(G5ä$&-£ ‚&1)‚£ £ ‚ƒƒŠ9j9Ã$-¢£ )'1)G5Ä$)å(Ä$¢&-‚Ä$‚ƒ'-Š9Ã$-&-G1£ -Ä$)'1)à -£ A A -ÌAÄ$£ --G5'1&1&-Ä$-ä$'1Ä$£ G1'1bƒå$Š9å(‚-Ä$¢G1¢¢Ä$'1‚£ G5&1A bå$(1)Ä$£ Ä$)¢ å(-£ £ G1G1&-'1å(ä$AbŠ=H1)å(&-å(G1ä$£ Ã$-Ä$-'1£ ‚ƒA)«=Ä$'1‚ä$£ &1)£ ‚H5H5¢Ä$¢'1@ @ )ÌA‚-Ä$ä$H5£ Ä$H5Ã$'1¢'1ä$Ä$Aƒ-Š9‚Ä$G1Ä$Ä$å(‚H5‚£ G5H5Ä$£ '1£ƒ'1Š9ä(G5à '1'1'1'1£ G1‚-Ä$ä$H5£ b¤H1«A&-'1å(-Ä$å(Ä$à å('1‚å(-&-‚ä$bƒIMGì£ -'1£ å(ä$‚£ -ä$'1£ Ä$å(£ ¤‚bå$£Ä a-Ä$¢G1&-G1ä$&-G1-'1å$bb‚b£A‚bA ƒaA‚bA aƒƒabb£bb¤b‚‚AbAbab@ ƒ£MENUTEXTGadgetTEXTIMG1  IMGv h=h=h=h=h=h=-R-R-R-Rh=h= h=h=-Rp^p^-R -Rp^Ój-Rh=h= h=h=-Rp^Ójp^-R -Rp^Ójp^-Rh=h=h=h=-Rp^Ójp^-R-Rp^Ójp^-Rh=h=h=h=-Rp^Ójp^-R-Rp^Ójp^-Rh=h=h=h=-Rp^ÓjNV-R-Rp^Ójp^-Rh=h=h=h=-Rp^ÓjNVp^Ójp^-Rh=h=h=h=-Rp^ÓjÓjp^-Rh=h= h=-Rp^ÓjÓjp^-Rh= -Rp^Ójp^p^Ójp^-R-Rp^ÓjOZ-R-Rp^Ójp^-R-Rp^Ójp^-Rh=h=-Rp^Ójp^-R-Rp^Ójp^-Rh=h=h=h=-Rp^Ójp^-R-Rp^Ójp^-Rh=h=h=h=-Rp^Ójp^-R-Rp^Ójp^-Rh=h=h=h=-Rp^Ójp^-R h=-Rp^p^-Rh=h= h=h=-Rp^p^-Rh= h=h=-R-Rh=h= h=h=-R-Rh=h=h=h=h=h=h=h=h=h=h=h=h=h= IMG -Rp^p^p^p^p^p^p^p^p^-Rp^ÓjÓjÓjÓjÓjÓjÓjÓjÓjÓjp^-R-Rp^ÓjÓjÓjp^p^-R-R-Rp^ÓjÓjÓjp^-Rp^ÓjÓjÓjp^-Rh=h=h=h=-Rp^ÓjÓjp^-R-Rp^ÓjÓjp^ Rh=h=h=-Rp^Ójp^-Rh= h=-Rp^p^-Rh=h=h=-Rp^p^-Rh=h=h=-R-Rh=h=h=-Rp^-Rh=h=h=h=h=h=h=h=h=-Rp^-Rh=h=h=h=h=h=h=-Rp^-Rh=h= h=-Rp^ Rh=h=h= h=-Rp^-Rh=h=h= h=-Rp^p^-Rh=h=-Rp^p^-Rh=h=h=-Rp^p^-Rh=-Rp^p^-Rh=h=h=-Rp^p^ Rh=h=h= R Rh=h=h=h=h=h=p^p^-Rh=p^ÓjÓjp^-Rh=p^ÓjÓjp^-Rh=-Rp^p^-R-Rh=h=-R-R-Rh=h=h=h=h=h=IMG   h=-R-R-R-R-R-R-R-R-R-R-R-Rh=h=h=h=-R-RÓjÓjÓjÓjÓjÓjÓjÓjp^p^-R-Rh=h=h=h=-RÓjp^p^p^p^p^p^p^p^p^-R-R-Rh=h=h=h=-R-Rp^p^p^p^p^p^p^-R-R-Rh=h=h=h=-R-Rp^p^p^p^p^-R-R-Rh=h=h=h=-R-Rp^p^p^-R-R-Rh=h=h= h=-R-Rp^-R-R-Rh=h=h= h=-R-R-R-Rh=h=h=h=-R-Rh=h=h=h=h=h=h=h=h= IMGÊ   h=h=h=-RÓjh=h=-RÓjp^-Rh=-RÓjp^p^-R h=-RÓjp^p^p^-R h=-RÓjp^p^p^p^-R h=-RÓjp^p^p^p^p^-R h=-RÓjp^p^p^p^p^p^-R h=h=-R-Rp^p^p^p^p^p^-R h=h=h=-R-Rp^p^p^p^p^-R h=h=h=-R-Rp^p^p^p^-R h=h=h=-R-Rp^p^p^-R h=h=h=-R-Rp^p^-R h=h=h=-R-Rp^-Rh=h=h=-R-Rh=h=h=h=h=h=h=h=h=h=h=h= IMGÊ  h=h=h=-R-Rh=-R-RÓj-Rh=-RÓjp^-R-Rh= -RÓjp^p^-R-Rh= -RÓjp^p^p^-R-Rh= -RÓjp^p^p^p^-R-Rh= -RÓjp^p^p^p^p^-R-Rh= -RÓjp^p^p^p^-R-R-Rh=h= -RÓjp^p^p^-R-R-Rh=h=h= -RÓjp^p^-R-R-Rh=h=h= -Rp^p^-R-R-Rh=h=h= -Rp^-R-R-Rh=h=h= -R-R-R-Rh=h=h=h=-R-Rh=h=h=h=h=h=h=h=h=h=h=h=h=h=IMGÚ  h= h= h=h=h=h=h=h= h=p^p^h=h=p^p^h= h=ÓjÓjp^h=h=p^ÓjÓjh= h=p^p^p^h=p^p^p^p^p^p^h=Ójp^p^h=h=p^p^p^-RÓjÓjÓjÓjÓjÓjp^p^p^p^h=p^p^p^p^h=-Rp^p^-Rp^p^p^p^p^p^Ójp^p^-Rh=p^p^p^ÓjÓjÓjÓjh=-R-R-R-R-R-R-R-R-R-RÓjp^-R-Rh=Bh=-R-R-R-R-R-Rh=-R-R-Rh=-R-R-R-R-R-RÓjp^-R-Rh=Bh=h=h=h=h=-R-R-Rh=-R-R-R-R-R-RÓj-R-R-Rh=h=-R-Rh=h=h=h=h=h=h=h=-Rh=-R-Rh= h=-Rh=h=h=h=h=h=h=h=h=h=h=h=-Rh= h=h=h=h=h=h=h=h=h=h= h=h=h=h=h=h=h=h= h=h=h=h=h=h= h= h= IMGöh=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=p^Ójp^p^-R-R-R-R-R-Rh=h=h=h=p^Ójp^p^p^-R-R-R-Rh=h=h=h=h=p^p^p^p^-R-R-Rh=h=h=h= h=h=-R-R-Rh=h=h=h=h= p^Ójp^-R-R-Rh=h= p^Ójp^-R-R-Rh=h= p^Ójp^-R-R-Rh=h= p^Ójp^-R-R-Rh=h= p^Ójp^-R-R-Rh=h= p^Ójp^-R-R-Rh=h= h=h=p^ÓjÓjÓjÓj-Rh=h=h=p^Ójp^p^p^p^-Rh=h=h=h=h=p^Ójp^p^p^-R-R-R-Rh=h=h=h=h=p^Ójp^p^-R-R-R-R-R-Rh=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=BBp^Ój-Rh=p^Ój-Rh=p^Ój-Rh=p^Ój-Rh=p^-Rp^-Rp^h=IMGˆh=Òfh=-R-Rh=h=h=h=h=-R-R-Rh=h=ÒfÒfÒfÒf-Rh=-R-R-R-R-R-Rh= h=h=h=h=h=h=h=h= -R-R-R-R-R-R-Rh=h= ÒfÒfÒfÒfÒfÒfÒfÒf-Rh= -R-R-R-R-R-R-R-R-R-Rh= h=h=h=h=h=h=h=h=h=h=h=h=-R-R-R-R-R-R-R-R-R-R-Rh=h=ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf-Rh=-R-R-R-R-R-R-R-R-R-R-R-R-R-Rh=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=-R-R-R-R-R-R-R-R-R-R-R-R-R-R-Rh=h=ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒf-Rh=-R-R-R-R-R-R-R-R-R-R-R-R-R-R-R-R-R-Rh=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=IMG¶  -R-R-R-R-R-R-R-R-RÓjÓjÓjÓjÓjÓjÓjÓjÓj-R-R-RÓjp^-Rh=h=p^p^p^Ój-R-R-RÓj-Rh=-RÓjÓj-Rp^p^Ój-R-RÓjh=-RÓjp^p^-Rp^p^-Rp^Ój-R-RÓjh= -RÓjp^-Rp^-Rp^Ój-R-RÓjh=-RÓjp^Ójp^-Rh=p^Ój-R-RÓjp^-RÓjp^ÓjÓjp^-Rh=p^Ój-R-Rp^-R-Rp^-Rp^-Rh=p^Ójh=-Rp^-R-R-Rp^p^-Rh=-RÓjh=-RÓjp^h=-R-Rp^p^-R-Rh=-Rp^h=-RÓjp^ h=-R-Rp^p^p^p^-R-Rh=-Rp^h=-RÓjp^ h=h=-R-R-R-Rh=h=-Rp^h=-RÓjp^h=h=h=h=-Rp^h=-RÓjp^p^-Rp^p^h=-R-RÓjp^p^p^-R-Rp^p^h=h=-R-Rp^p^p^p^p^p^p^p^h=h= h=h=h=h=h=h=h=h= MENUTEXTDividerTEXTIMG1IMG IMGœ@@h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=h=@Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä Ä @ÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfÒfIMG simutrans-124.3/simutrans/themes/menu.pak64german.pak000066400000000000000000004550211474050137200226530ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT-MENUTEXTBackTEXTIMG1  IMG IMG IMG IMG @{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMGŠ!@@@ccccùZccùZùZcùZcùZùZùZùZØVùZØVØVùZØVØVØVØVØVØVØVØVØVùZccc}k\g}k\g}k\g\g\g\g\g\g\g\g\gc\g\gc\gc\gcc\gc\gccc\g@cccccùZcùZcùZùZùZùZùZùZùZØVùZùZùZØVùZØVØVØVØVØVØVcccccccc}k}k\g\g}k\g\g\g\g\g\g\g\g\gc\g\gc\gc\gccccccc@cùZccùZcùZcùZùZcùZùZùZùZùZùZùZùZØVùZØVØVØVùZØVcc\gc\gccccccùZ}k\g\g\g\g\g\g\gc\gc\g\gc\g\gc\gc\gcc\gc\gc@cccccùZcùZcùZùZcùZùZùZùZùZùZØVùZØVØVùZØVcc\gccccccccccùZcc}k\g\g\g\g\g\g\g\g\gc\gc\g\gc\gcc\gcccc@\gcùZcùZccùZùZcùZùZùZùZùZùZØVùZØVùZØVùZc\gc\gc\gcc\gccccccccùZcùZ\g\g\g\g\g\gc\g\gc\gc\gc\gc\gccccc@cccccùZcùZcùZùZcùZùZùZùZØVùZùZØV\gc\gc\gccc\gccccccccùZccùZcùZc\g\g\g\g\g\gc\g\gc\gc\gccc\gc\gc@ccccùZccùZùZcùZùZùZùZùZùZùZùZc\g\gc\gc\gc\gccc\gccccccccùZcùZcùZùZùZ\g\g\gc\g\gc\gc\gc\gc\gcccc@cùZcùZcùZcùZcùZùZcùZùZùZØV\gc\gc\g\gc\gc\gc\gcccccccccccùZcùZcùZùZcùZùZ\g\g\gc\g\gcc\gccc\gcc\g@ccccccùZcùZcùZùZùZØV\g\g\g\g\gc\gc\gc\gccc\gc\gccccccùZcùZcùZcùZùZùZùZùZùZùZc\g\gc\g\gcc\gccccc@\gccùZccùZcùZùZùZùZ\g\g\gc\gc\g\g\gc\gc\gc\gcccccccccccccùZcùZcùZcùZùZùZùZØVùZc\gc\gc\gc\gcccc@cccccùZcùZùZùZ\g\g\g\g\g\g\g\g\gc\gc\g\gc\gccc\gcccccccùZcùZcùZcùZùZùZùZùZùZùZùZØVùZØV\gc\gccc\gc\gc@ccccùZcùZc\g}k\g\g\g\g\g\g\gc\g\gc\gc\gcc\gc\gcc\gcccccccùZcùZùZcùZùZùZùZùZùZùZùZØVùZùZØV\gc\gccccc@cccùZcc\g\g\g\g\g\g\g\g\gc\g\g\gc\gc\gc\gc\gccccccccccùZccùZcùZcùZùZùZùZùZùZØVùZùZùZØVØVùZØVcc\gccc@cccc\g\g}k\g\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\gcc\gc\gcccccccccùZcùZcùZùZcùZùZùZùZùZØVùZØVùZØVØVØVØVØVcccc@cc\g}k}k\g}k\g}k\g\g\g\g\g\g\gc\g\gc\gc\gc\gc\gcccccccccccùZcùZcùZcùZùZùZùZùZùZØVùZùZØVùZØVØVØVùZØVØVØVcc@}k}k}k\g\g}k\g\g\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\gccc\gcc\gcccccùZccùZcùZùZcùZùZùZùZùZùZØVùZØVùZØVùZØVØVØVØVØVØVØV@cc\g}k}k\g\g}k\g\g\g\g\g\gc\g\gc\gc\g\gc\gc\gc\gcccccccccccùZcùZùZcùZùZùZùZùZùZØVùZØVùZùZØVØVØVØVØVØVØVcc@cccùZ}k}k\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\g\gcc\gcc\gcccccccùZccùZcùZùZcùZùZùZùZùZØVùZùZØVùZØVØVØVØVØVcccc@cccccùZ}k\g\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\gccc\gccccccccccùZcùZcùZùZùZùZùZùZùZùZùZùZØVØVØVùZØVcc\gc\gc@cccccccùZ\g}k\g\g\g\g\gc\g\g\gc\gc\gc\gc\gcccc\gcccccùZccùZcùZcùZcùZùZùZùZØVùZØVùZùZØVc\gc\gcccc@cccccùZcùZcùZ\g\g\g\g\g\g\g\gc\g\gc\gc\gccc\gccccccccccùZcùZùZcùZùZùZùZùZùZùZØVùZùZc\gc\gccccc\g@ccccùZccccùZcùZ\g\g\g\gc\g\gc\g\gcc\gc\gcccc\gcccccùZccùZcùZùZùZcùZùZùZùZùZØV\gc\gc\gc\gcc\g\gc@\gccccccùZcùZùZcùZùZ\g\g\g\gc\g\gc\g\gc\gcc\gccccccccccùZcùZcùZcùZùZùZùZùZc\g\g\gc\gc\gc\gcccc@ccccùZcùZccùZùZùZcùZùZùZ\g\g\gcc\gc\gcc\gccc\gccccccùZccùZcùZùZùZùZùZùZ\g\g\gc\gc\gc\gccc\gccc@ccccccccùZcùZcùZùZùZùZùZØV\g\g\gc\gc\gcc\gcccccccccccùZcùZcùZùZùZ\g\gc\gc\gc\g\gc\gc\gccccc@ccccùZcùZccùZùZùZcùZùZùZùZùZØVùZ\gc\gc\gc\gc\gccccccccùZcccùZùZùZ\g\g\g\g\g\gc\gc\gc\gcc\gc\gc\gc@ccccccccùZcùZcùZùZùZùZùZùZùZØVùZØV\gc\gcccccc\gccccccùZcùZùZ\g\g\g\g\g\gc\g\g\gc\gc\gc\gccc\gcc@\gccccùZcccùZùZùZcùZùZùZùZùZØVùZØVùZØVØV\gc\gc\gùZcccccccùZcùZ\g\g\g\g\g\g\gc\g\gc\g\gc\gc\gc\gcccc\g@cccùZcccùZcùZcùZùZcùZùZùZùZùZØVùZØVùZùZØVùZccc\gcccccccùZ}k\g}k\g\g\g\g\g\g\g\g\gc\g\gc\gc\gcc\gcccc@cccccùZccùZcùZùZcùZùZùZùZùZùZùZùZØVùZØVØVØVØVØVcccccccùZ}k\g\g\g\g\g\g\g\g\g\gc\g\g\gc\gc\gc\gcccc\gcc@cccccccùZcùZcùZùZùZùZùZùZùZØVùZùZØVùZØVØVØVØVØVØVØVcccùZ}k\g}k\g}k\g}k\g\g\g\g\g\g\gc\g\gc\gc\gc\gccc\gc\gc@ccccccccùZcùZùZùZùZùZùZùZùZØVùZØVØVùZØVùZØVØVØVØVØVØVùZ\g}k}k\g}k\g}k\g\g\g\g\g\g\g\g\g\gc\gc\gc\gcccc\g\gccc@cccccùZcùZcùZcùZùZcùZùZùZùZØVùZùZùZØVùZØVØVØVØVØVØVcccc}k}k\g}k\g}k\g\g\g\g\g\g\g\gc\gc\g\gc\gc\gc\gccc\gc@cccùZccccùZcùZcùZùZùZùZùZùZØVùZùZØVùZØVØVØVØVØVc\gcccccc\g}k\g\g\g\g\g\g\g\g\g\g\g\g\gc\gc\gccccc\gccc@\gccccùZcccùZùZùZcùZùZùZùZùZùZùZØVØVùZØVØVØVc\gcccccccccc}k\g\g\g\g\g\g\g\gc\g\g\gc\gc\gc\gcccccc\g@ccccccùZcùZcùZcùZùZùZùZùZùZùZØVùZùZØVùZc\gc\gccc\gcccccùZcc\g\g\g\g\g\g\g\g\g\gc\gc\g\gc\gc\gc\gccc@ccccùZcccùZcùZùZcùZùZùZùZùZØVùZØVØV\gc\gcccc\gccccccccùZccùZ\g\g\g\g\gc\gc\g\g\gc\gcc\gcccc\gc@cccccccùZcùZùZcùZùZùZùZùZùZùZØV\g\gc\gc\gc\gccccc\gcccùZcùZcùZcùZ\g\g\g\g\g\g\gcc\gc\g\gccc\gccc@cccccùZccùZcùZùZcùZùZùZùZùZc\g\gc\gc\gccc\gccccccccccccùZùZcùZùZ\g\g\gc\g\g\gc\gc\gc\gcccc\g@ccccccùZccùZcùZùZùZùZùZc\g\gc\gc\gc\gc\gcc\gccccccùZccùZcùZcùZùZùZùZùZ\g\g\gc\gc\gc\gcc\gcccc@cccccccùZcùZcùZùZùZ\g\g\g\gc\gc\gc\gc\gcc\gcccccccccùZccùZùZcùZcùZùZùZùZc\g\gc\gc\gc\gccc\gc@\gccccùZcccùZùZùZ\g\g\g\gc\g\g\gc\gc\gcc\gcc\gcc\gcccùZccùZcùZcùZùZùZùZùZùZùZùZØV\gc\gcc\gcc\gccc@cccccccùZùZùZ}k\g\g\g\g\g\g\gc\g\gc\gc\gcc\gccccccccccùZccùZùZcùZùZùZùZùZùZùZØVùZØV\g\gcc\gccccc@cccccùZcùZ}k\g\g\g\g\gc\g\gc\g\gc\g\gc\gc\gc\gc\gcccccùZcccùZcùZcùZùZùZùZùZùZùZùZùZùZØVùZc\gc\gcccc@cccccùZ}k\g\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\gcccccccccccccùZccùZùZùZùZcùZùZùZùZØVùZØVùZØVØVØVØVcc\gc\gc@cccùZ}k\g}k\g\g\g\g\g\g\g\g\gc\g\gc\gc\gc\gc\gc\gcc\gccccùZccùZcùZccùZùZùZùZØVùZùZØVùZØVùZØVØVØVØVØVcccc@cc\g}k\g}k\g\g}k\g\g\g\g\g\gc\g\gc\g\gc\gc\gcccccccccccccccùZcùZùZùZcùZùZùZùZØVùZùZØVùZØVùZØVØVØVØVØVcc@}k}k}k\g}k\g}k\g\g\g\g\g\g\g\g\g\g\g\gc\gc\gc\gc\gc\gccccccccùZcùZcùZùZcùZùZùZùZùZùZùZØVùZùZùZØVØVØVØVØVØVØVØVØV@cc}k}k\g\g}k\g}k\g\g\g\g\g\g\gc\gc\g\gc\gc\gccccc\gccccccccùZcùZcùZùZcùZùZùZùZØVùZùZØVØVØVØVØVØVØVØVØVcc@cccùZ}k}k\g\g\g\g\g\g\g\g\g\g\g\g\gc\gc\gc\gc\gc\gccccccccùZcccùZùZcùZùZùZùZùZùZùZùZØVùZØVùZØVØVØVØV\gccc@cùZcùZcùZ}k\g\g\g\g\g\g\g\g\gc\gc\g\gc\gc\gccccccccccccccùZcùZcùZùZcùZùZùZùZùZØVùZØVùZØVØVØV\gcc\g\gc@cccccùZcc\g\g\g\g\g\gc\g\g\g\gc\gc\gc\gc\gc\gc\gcccccccùZcùZcùZcùZcùZùZùZùZØVùZùZØVùZØVc\gc\gcccc@cccùZccùZcùZùZ\g\g\g\g\g\gc\g\gc\gc\gc\gcccccccccccccccùZcùZùZùZùZùZùZùZùZØVùZØVØV\gc\gc\gc\gccc@\gccccùZcùZcùZùZùZ\g\g\g\g\g\gc\g\gc\gc\gc\gc\gcc\gcccccùZcùZcùZùZcùZcùZùZùZùZùZØV\g\gc\g\gc\gcc\gc\g@cccùZccùZcùZùZcùZùZùZ\g\gc\g\gc\gc\gc\gccccccccccccccùZcùZcùZùZùZùZùZùZùZ\g\gc\g\gc\gc\gc\gccc@cccccùZcùZcùZùZùZùZùZùZùZ\g\gc\g\g\gc\gc\gc\gccccccccccùZccùZcùZcùZùZùZc\gc\g\gc\gc\gc\gccc\gc@cùZcùZccùZcùZùZcùZùZùZùZùZùZùZc\gc\gc\gcc\gcc\gccccccùZccùZcùZùZùZùZùZ\g\g\g\g\g\gc\g\gc\gc\gc\gccc@cccccùZcùZcùZùZùZùZùZùZùZùZØVùZØV\gc\gc\gcc\gcccccccccccùZcùZcùZ\g\g\g\g\g\gc\g\gc\gc\gc\gcc\gcc@\gccùZccùZcùZcùZcùZùZùZØVùZùZùZØVùZØV\gc\gccc\gcccccccùZcùZcùZc\g\g\g\g\g\g\gc\g\gc\gc\gc\gc\gcccc@ccccùZccùZcùZùZùZùZùZùZùZùZØVùZùZùZØVùZØV\gc\gccc\gccccccccc}k\g\g\g\g\g\g\g\g\g\g\gc\g\gc\gc\gcccc\g@cùZcùZcùZcùZùZùZcùZùZùZùZùZØVùZØVØVØVØVØVØVØVØVcc\gccccccccc\g}k\g}k\g\g\g\g\g\g\g\g\gc\gc\g\gc\gc\gc\gcc@cccccùZccùZcùZùZcùZùZùZùZùZùZùZùZØVùZØVØVØVØVØVcccccccùZ}k\g\g\g\g\g\g\g\g\g\gc\g\g\gc\gc\gc\gcccc\gcc@cccccccùZcùZcùZùZùZùZùZùZùZØVùZùZØVùZØVØVØVØVØVØVØVcccùZ}k\g}k\g}k\g}k\g\g\g\g\g\g\gc\g\gc\gc\gc\gccc\gc\gc@ccccccccùZcùZùZùZùZùZùZùZùZØVùZØVØVùZØVùZØVØVØVØVØVØVùZ\g}k}k\g}k\g}k\g\g\g\g\g\g\g\g\g\gc\gc\gc\gcccc\g\gcccIMG @­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5MENUTEXTButtonTEXTIMG1$$IMG6µVµVµVµVµVµV”R”R”R”RIMG"@@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµV@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµV@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµV@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMG6µVµVRJµVRJ1F”RRJ1FBIMGz”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMG:@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”RIMGz”RRJ1FB”RRJ1FB”RRJ1FB”RRJ1FB”RRJ1FB”RRJ1FB”RRJ1FB”RRJ1FBIMG6”R”R”R”RRJRJRJ1F1FBIMG"@@”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R”R@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMG6RJ1FBB1FBBBBBIMG6Œ1Œ1Œ1Œ1Œ1­5Œ1Œ1­5Î9IMG"@@Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1Œ1@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9Î9@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG6Œ1­5­5Î9Î9Î9ï=ï=ï=ï=IMGzŒ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=Œ1­5Î9ï=IMG:@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMGzï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=IMG6Œ1­5Î9ï=­5Î9BÎ9BBIMG"@@ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=ï=@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBIMG6ï=ï=ï=ï=BBBBBBIMG6÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMG"@@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMG6÷^÷^ÖZ÷^ÖZÖZ÷^ÖZÖZµVIMGz÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMG:@@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^IMGz÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµV÷^ÖZÖZµVIMG6÷^÷^÷^÷^ÖZÖZÖZÖZÖZµVIMG"@@÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@µVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVµVIMG6ÖZÖZµVµVÖZµVµVµVµVµVIMG6ÿÿÿÿÿÿÿÿÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG6ÿÿÿÿÿÿÿÿÿÿIMGzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG:@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG6ÿÿÿÿÿÿÿÿÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG6ÿÿÿÿÿÿÿÿÿÿMENUTEXT CheckbuttonTEXTIMG1IMGÖZµV”R”R”RµV ÖZµV”RsNsNRJRJRJ1FsN ÖZµV”RsNsNRJRJRJ1FBBRJÖZµV”RsNsNRJRJRJ1FBBBï=1FµV”RsNsNRJRJRJ1FBBBï=Î9­5ÖZ”RsNsNRJRJRJ1FBBBï=Î9­5­5”RµVsNsNRJRJRJ1FBBBï=Î9­5­5­51F”RsNRJRJRJ1FBBBï=Î9­5­5­5Œ1Î9sNRJRJRJ1FBBBï=Î9­5­5­5Œ1Œ1Œ1”RRJRJ1FBBBï=Î9­5­5­5Œ1Œ1k-Î9µVRJ1FBBBï=Î9­5­5­5Œ1Œ1k-J)1FÖZ1FBBBï=Î9­5­5­5Œ1Œ1k-J)J)µVsNBBï=Î9­5­5­5Œ1Œ1k-J)J)Î9 RJï=Î9­5­5­5Œ1Œ1k-J)J)Î9 1F­5­5­5Œ1Œ1k-J)J)Î9€B­5Œ1Î9RJIMGV[uWsOsOSO5W v[•W”SsOsOrKQGQG0CG v[•W”SsOsOrKQGQG0C/?;Gv[•W”SsOsOrKQGQG0C/?;; 7ï>•W”SsOsOrKQGQG0C/?;; 7ë2ê.6[”SsOsOrKQGQG0C/?;; 7ë2ê.ê.òNUWsOsOrKQGQG0C/?;; 7ë2ê.ê.É*Ï>TSsOrKQGQG0C/?;; 7ë2ê.ê.É*¨&Ì2sOrKQGQG0C/?;; 7ë2ê.ê.É*¨&¨&¨&SOQGQG0C/?;; 7ë2ê.ê.É*¨&¨&§"«.4SQG0C/?;; 7ë2ê.ê.É*¨&¨&§"†Ï>[0C/?;; 7ë2ê.ê.É*¨&¨&§"†…ôRG;; 7ë2ê.ê.É*¨&¨&§"†…«. G 7ë2ê.ê.É*¨&¨&§"†…«. ï>ê.ê.É*¨&¨&§"†…«.òJÍ6Ê*©&¬2ÐBIMGsNµV÷^÷^”R€ µVcccccccc”R µVcccccccccc”RµVcccccccccccc”RccccccccccccccsNccccccccccccccsN”Rcccccccccccccc€µVccccccccccccccµV÷^cccccccccccccc÷^µVcccccccccccccc”R€ccccccccccccccRJ”Rcccccccccccccc”R”Rcccccccccccc”R ”Rcccccccccc”R ”Rcccccccc”RsN”RÖZÖZ”RRJMENUTEXTDisplayFactoryLabelTEXTIMG1  IMG^€€€€€€÷^Þ{€÷^Þ{ s€€Þ{ s sIMG.@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@ s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s÷^@ s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ sIMGL€€€€€ s€€ s÷^€€IMGŠ@€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€IMGŠ!@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGŠ@€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€€ s s€€IMG^€€÷^ s s€€ s s€€€÷^€€€€IMG.@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@ s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s@ s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@IMG^ s s÷^€€ s s€€÷^€€€€€€€MENUTEXTDisplayMarkerLabelTEXTIMG1  IMG^€€€€€€€÷^€€ZkZk€€÷^ZkZkIMG.@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk÷^@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGL€€€€€Zk€€Zk÷^€€IMGŠ@€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€IMGŠ!@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGŠ@€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€€ZkZk€€IMG^€€÷^ZkZk€€ZkZk€€€÷^€€€€IMG.@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@ZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZkZk@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@IMG^ZkZk÷^€€ZkZk€€÷^€€€€€€€IMGv ))#€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ €€€€€€€€€€€€€€€€€ €€€€€€€€€€€ €€€€€MENUTEXTDisplayStationLabelTEXTIMG1  IMGB€€€€€€€€€IMG"@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGB€€€€€€€€€IMGŠ@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGŠ!@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGŠ@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGB€€€€€€€€€IMG"@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@IMGB€€€€€€€€€MENUTEXTDisplayTextLabelTEXTIMG1  IMGB€€€€€€€€€IMG"@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€IMGB€€€€€€€€€IMGŠ@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈIMGŠ!@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈ@ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈIMGŠ@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈIMGB€€€€€€€€€IMG"@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€@IMGB€€€€€€€€€MENUTEXTDividerTEXTIMG1IMG IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG MENUTEXT EditfieldTEXTIMG1  IMG­5IMG@@­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG­5­5IMGª­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5­5IMG‚ @@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsN@sNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNsNIMGª{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG{oIMG@@{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG{oMENUTEXTGadgetTEXTIMG1  IMGfwswswswswswswsgwswswswsgwswswsgwswswswsgwswswswsgwswswswsgwsws wswsgwswswswsgwswswswsgwswsgwswswswsggwswswswsggwswswswsgwswsgwsws wswsgwswswswsgwswswswsgwswswswsgwswswswsgwswswswsgwswswsgwswswswsgwswswswswswswsIMGP wswswswswswsws wswswswsgggwswswsws wsgggwswswswswsgggwswsgggwswsgggwswswswswswswsgggwswsggggwswsggggwswsggwswswswsgggwswsgggwswsgggwswswswswsws wswswswsgggwswsgggwswswswsIMGÆwswswswswswswswswswswswswswswswsggwswswswswswsggwsws wswsggwswswswsggwsws wswsggwswsggwswswswsgwswsgwswswswsggwswswsggwswswsIMGê wswswswswswswsgwswswsggwswswsggwswswswsggwswswswsggwswswswswswsggwswswswswswswsggwswswswswsggwswswswsggwswswsgwswswswswswsIMGêwswswswswswsgwswswsggwswswswsggwswswswswsggwswswswswswswsggwswswswswswsggwswswswsggwswswswsggwswswsggwswswsgwswswswswswswsIMGÞ wswsws wswswsgws wswswswswswsggwswswswswswsggggggggws…9…9…9…9…9gggggggggggwswswswswswsggggggggws wswswswswswsggws wswswsgwswswswsIMG  wswswswswswswswsws wsgggggggws wswsgggggwswswswsgggwswswswsgggwswswsgggwswsgggwswsgggwswsgggwswsgwswsgwswsgwsws…9wsws…9ws…9…9…9IMGT…9 xsxs …9…9…9 xsxsxsxs …9…9…9…9…9 xsxsxsxsxsxs…9…9…9…9…9…9…9xsxsxsxsxsxsxsxs …9…9…9…9…9…9…9…9…9 xsxsxsxsxsxsxsxsxsxs …9…9…9…9…9…9…9…9…9…9…9 xsxsxsxsxsxsxsxsxsxsxsxs …9…9…9…9…9…9…9…9…9…9…9…9…9xsxsxsxsxsxsxsxsxsxsxsxsxsxs…9…9…9…9…9…9…9…9…9…9…9…9…9…9…9IMGx wswswswswswswsws wswsŒVŒVŒVŒVŒVŒVŒVŒVwswswsŒVŒVwswswswswswswswsŒVŒVwswsŒVwswswswsÆA…9…9wswswswswsŒVwswsŒVwswswswsws…9…9…9…9wswswsŒVwswsŒVwswswsws…9…9…9…9…9…9wswswswsŒVwswsŒVwswswsws…9…9…9…9wswswswsŒVwswsŒVwswswswswswswswswswswswsŒVwswsŒVŒVwswswswswswswswsŒVŒVws wswsŒVŒVŒVŒVŒVŒVŒVŒVwswswswswswswswswswsMENUTEXTListboxTEXTIMG1  IMGIMG@@IMGIMGªIMG‚ @@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZIMGª{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{o{oIMG9gIMG@@ùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZùZ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿÿMENUTEXT PosbuttonTEXTIMG1IMG: ÷^ÖZ÷^ÖZÖZµVµV”RµVÖZ ÖZµV”R”RsNsNRJ1FsNµV µV”R”RsNRJ1F1F1FBï=ï=1F”R”RsNsNRJ1F1FBBï=Î9Î9­5Œ1Œ1Î9RJsNRJRJ1F1FBï=ï=Î9Î9­5Œ1Œ1k-J)Î9RJ1F1F1FBï=ï=Î9­5Œ1Œ1Œ1Œ1B 1F1F1FBï=Î9Î9­5Œ1Œ1­5RJ 1FBBï=Î9Î9­5Œ1ï=”RBï=ï=Î9­5­51Fï=Î9Î9Î9sNï=B”RIMG: ÆJ)ï=ÆçççJ)Î9sN çç!!)%J)J)Œ1ï=RJ ç!)%)%J)J)k-Œ1Œ1­5Î9ï=RJ!)%)%J)k-Œ1Œ1Œ1­5Î9Î9ï=B1FBRJ)%J)J)k-Œ1Œ1­5­5Î9ï=ï=B1F1F1F1FJ)J)k-Œ1Œ1­5Î9Î9ï=ï=B1F1F1F k-k-Œ1Œ1­5Î9Î9ï=B1FBRJ Œ1Œ1­5­5Î9ï=ï=B1FsNŒ1­5Î9Î9ï=ï=B­5Î9Î9ï=1FÎ9ï=sNIMG: µVsNRJÖZÖZÖZÖZ”RsN”R ÖZÖZÖZÖZÖZÖZÖZµVsN”R ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZµV”RsNÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RsNÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZµVsN ÖZÖZÖZÖZÖZÖZÖZÖZ”R”RÖZÖZÖZÖZÖZÖZ”RÖZÖZÖZµVsNµV”R”RMENUTEXT RoundbuttonTEXTIMG1IMG6z:y:y:y:y:y:y:y:y:y:IMG"@@z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:z:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:IMG6z:y:86y:862y:862÷1IMGzy:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:IMG:@@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:@y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:y:IMGzX:862÷1X:862÷1X:862÷1X:862÷1X:862÷1X:862÷1X:862÷1X:862÷1IMG6X:X:X:X:86868622÷1IMG"@@X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:@86868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686868686@2222222222222222222222222222222222222222222222222222222222222222@÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1÷1IMG6862÷1÷12÷1÷1÷1÷1÷1IMG6÷%÷%÷%Ö%Ö%Ö%Ö%Ö%Ö%Ö%IMG"@@÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%@÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%÷%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%IMG6÷%÷%µ!Ö%µ!”!Ö%µ!”!tIMGzÖ%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%IMG:@@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%@Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%Ö%IMGzÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tÕ%µ!”!tIMG6Õ%Õ%Õ%Õ%µ!µ!µ!”!”!tIMG"@@Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%Õ%@µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!µ!@”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!”!@ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttIMG6µ!”!tt”!tttttIMG6>šFûR;!hY>™B9ldhY>yB6!hlhšFY>yBÚN3lllY>Y>yByB0!hlllY>Y>yByBûV-llll"h™FY>Y>yByBšF*"hlllllX>Y>Y>yByByB(llllllX>Y>Y>yByByBÛN$™F>CdllllLa™FX>Y>Y>yByByBšF"8:8:X>6B"hllh 8:X>Y>Y>yByByBšF[WG yB8:8:X>Y>Y>F!hl 8:X>Y>Y>yByByBšFºJ wGU;™S 868:8:X>Y>Y>yB™BôI]c ™F8:X>Y>Y>yByByBšFšJ 57U;V? y>868:8:X>Y>Y>yB™B™BÛN 8:8:X>Y>Y>yByByBšFšJûRV?57U;V?yO <_6868:8:X>Y>Y>yB™B™BšF <_8:8:X>Y>Y>yByByBšFšJºJ4357U;V?WC X>6868:8:X>Y>Y>yB™B™BšF yB8:8:X>Y>Y>yByByBšFšJºJU74357U;V?WCxO <_26868:8:X>Y>Y>yB™B™BšF 868:8:X>Y>Y>yByByBšFšJºJÛN»_3/4357U;V?WCWGyB26868:8:X>Y>Y>yB™B™BšFºJ <_868:8:X>Y>Y>yByByBšFšJºJºJT73/4357U;V?WCWGyS<_226868:8:X>Y>Y>yB™B™BšFšJ %yB868:8:X>Y>Y>yByByBšFšJºJºJúNvG4357U;V?WCzWX>226868:8:X>Y>Y>yB™B™BšFšJ $6868:8:X>Y>Y>yByByBšFšJºJºJÚN435;U;WCKö1226868:8:X>Y>Y>yB™B™BšFšJûR #<[6868:8:X>Y>Y>yByByBšFšJºJºJÛN›_ySW:ö1226868:8:X>Y>Y>yB™B™BšFšJºN!Y>6868:8:X>Y>Y>yByByBšFšJºJºJÛN7:ö1226868:8:X>Y>Y>yB™B™BšFšJºJ26868:8:X>Y>Y>yByByBšFšJºJºJ8:226868:8:X>Y>Y>yB™B™BšFšJºJ<_26868:8:X>Y>Y>yByByBšFšJºJX>26868:8:X>Y>Y>yB™B™BšFšJºJÛNyB26868:8:X>Y>Y>yByByBšFšJX>6868:8:X>Y>Y>yB™B™BšFšJºJºJ226868:8:X>Y>Y>yByByBšFX>868:8:X>Y>Y>yB™B™BšFšJºJºJ<_226868:8:X>Y>Y>yByB²ff‘f8:X>Y>Y>yB™B™BšFšJºJºJ3+T7»_ySX>226868:8:X>Y>³fMf+f b b,f‘fY>yB™B™BšFšJºJºJÚNvG3/3/U7"xOWGWGzW÷1226868:8:WB,f béaéaéaéa b²f™B™BšFšJºJºJÛN434343434343V? &yOWCWCWCWCWCO÷1226868:f béa§Yéaéa§YéaMf™BšFšJºJºJÛN;W5;57575757575757wG )™SV?V?V?V?V?V?V?WCW:ºNÛNÛNºJºJMf béaéaéaéaéaéa+bÔfšJºJºJÛNÛRySU;U;U;U;U;U;U;U;U;WG )WGU;U;U;U;U;U;U;U;U;ySÛRÛNºJºJšJMf béaéaéaéaéaéa+bÓfºJºJÛNÛNºNW:WCV?V?V?V?V?V?V?™S &wG575757575757575;57ÛNºJºJšJšFof béa§Yéaéa§YéaMf8:8:86622ö1KWCWCWCWCWCyO "V?4343434343zSÛNºJºJšJšF™B™F,féaéaéaéaéa bfX>8:8:86622ö1zWWGWGxOU73/3/vGÚNºJºJšJšF™B™ByB²f,b b b b+bofY>Y>X>8:8:86622X>yS»_T7úNºJºJšJšF™B™ByBY>Y>X>fofofÓf™ByBY>Y>X>8:8:86622<_ºJºJšJšF™B™ByBY>Y>X>8:8:86X>šF™B™ByBY>Y>X>8:8:86622ºJºJšJšF™B™ByBY>Y>X>8:8:866X>šJšF™B™ByBY>Y>X>8:8:8662yBÛNºJšJšF™B™ByBY>Y>X>8:8:8662X>ºJšJšF™B™ByBY>Y>X>8:8:8662<_ºJšJšF™B™ByBY>Y>X>8:8:866228:ºJºJšJšF™B™ByBY>Y>X>8:8:8662!ºJšJšF™B™ByBY>Y>X>8:8:86622ö17:ÛNºJºJšJšF™B™ByBY>Y>X>8:8:866X>#ºNšJšF™B™ByBY>Y>X>8:8:86622ö1W:yS57ÛNºJºJšJšF™B™ByBY>Y>X>8:8:866<_ $ûRšJšF™B™ByBY>Y>X>8:8:86622ö1KWCU;5;zSÚNºJºJšJšF™B™ByBY>Y>X>8:8:866 %šJšF™B™ByBY>Y>X>8:8:86622X>zWWCV?U;5743vGúNºJºJšJšF™B™ByBY>Y>X>8:8:86y> šJšF™B™ByBY>Y>X>8:8:86622<_ySWGWCV?U;57433/T7ºJºJšJšF™B™ByBY>Y>X>8:8:86<_ ºJšF™B™ByBY>Y>X>8:8:8662yBWGWCV?U;57433/»_ ÛNºJšJšF™B™ByBY>Y>X>8:8:86 [šF™B™ByBY>Y>X>8:8:8662<_xOWCV?U;5743U7 ºJšJšF™B™ByBY>Y>X>8:8:yB šF™B™ByBY>Y>X>8:8:866X>WCV?U;5743 ºNšJšF™B™ByBY>Y>X>8:8:\_ šF™B™ByBY>Y>X>8:8:866<_yOV?U;57V? ûRšJšF™B™ByBY>Y>X>8:8: ÛN™B™ByBY>Y>X>8:8:86y> V?U;57 šJšF™B™ByBY>Y>X>8:™F ™B™ByBY>Y>X>8:8:86<_ ™SU;wG ºJšF™B™ByBY>Y>X>8: ™B™ByBY>Y>X>8:8:yBWG [šF™B™ByBY>Y>X>8: šF™ByBY>Y>X>8:8:\_!šF™B™ByBY>Y>X>™FûV™ByBY>Y>X>8:™F$ÛN™B™ByBY>Y>X>™ByBY>Y>X>8:(™B™ByBY>Y>X>™ByBY>Y>X>™F*šF™ByBY>Y>™FÚNyBY>Y>X>-ûV™ByBY>Y>yBY>Y>™F0™ByBY>Y>yBY>Y>3ÚNyBY>šF™BY>šF6yBY>ûRY>9™BY>šF;ûRšFIMG>>šFûR;šFY>™B9Y>ûRY>yB6šFY>™BšFY>yBÚN3Y>Y>yBY>Y>yB™B0™FY>Y>yBY>Y>yB™BûV-X>Y>Y>yBÚN™FY>Y>yB™BšF*™FX>Y>Y>yByBX>Y>Y>yB™B™B(8:X>Y>Y>yByBX>Y>Y>yB™B™BÛN$™F8:X>Y>Y>yByBûV™FX>Y>Y>yB™B™BšF! <_8:8:X>Y>Y>yByBšF 8:X>Y>Y>yB™B™BšF[WG yB8:8:X>Y>Y>yByByB 8:X>Y>Y>yB™B™BšFºJ wGU;™S <_868:8:X>Y>Y>yByByB ™F8:X>Y>Y>yB™B™BšFšJ 57U;V? yB868:8:X>Y>Y>yByByBÛN 8:8:X>Y>Y>yB™B™BšFšJûRV?57U;V?yO <[6868:8:X>Y>Y>yByByBšF \_8:8:X>Y>Y>yB™B™BšFšJºN4357U;V?WC Y>6868:8:X>Y>Y>yByByBšF yB8:8:X>Y>Y>yB™B™BšFšJºJU74357U;V?WCxO<_26868:8:X>Y>Y>yByByBšF[ 868:8:X>Y>Y>yB™B™BšFšJºJÛN»_3/4357U;V?WCWGyB26868:8:X>Y>Y>yByByBšFºJ <_868:8:X>Y>Y>yB™B™BšFšJºJºJT73/4357U;V?WCWGyS<_226868:8:X>Y>Y>yByByBšFšJ %y>868:8:X>Y>Y>yB™B™BšFšJºJºJúNvG4357U;V?WCzWX>226868:8:X>Y>Y>yByByBšFšJ $6868:8:X>Y>Y>yB™B™BšFšJºJºJÚNzS5;U;WCO÷1226868:8:X>Y>Y>yByByBšFšJûR #<_6868:8:X>Y>Y>yB™B™BšFšJºJºJÛN57ySW:÷1226868:8:X>Y>Y>yByByBšFšJºJ!X>6868:8:X>Y>Y>yB™B™BšFšJºJºJÛNÛRºN226868:8:X>Y>Y>yByByBšFšJºJ26868:8:X>Y>Y>yB™B™BšFšJºJºJÛNÛN26868:8:X>Y>Y>yByByBšFšJºJ<_26868:8:X>Y>Y>yB™B™BšFšJºJºJÛN6868:8:X>Y>Y>yByByBšFšJºJÛNyB26868:8:X>Y>Y>yB™B™BšFšJºJºJ868:8:X>Y>Y>yByByBšFšJºJºJ226868:8:X>Y>Y>yB™B™BšFšJºJ8:8:X>Y>Y>yByByBšFšJºJºJ<_226868:8:X>Y>Y>yB™JofMfMffWBY>Y>yByByBšFšJºJºJúNT7»_ySX>226868:8:X>Y>²f,f b b b b,f³fyByByBšFšJºJºJÚNvG3/3/U7"xOWGWGzWö1226868:8:X>,béaéaéaéaéa bMfyByBšFšJºJºJÛN434343434343V? &yOWCWCWCWCWCKö1226868:f béa§Yéaéa§Yéa+f²fšFšJºJºJÛN›_5;57575757575757wG )™SV?V?V?V?V?V?V?WCW:ö122686of béaéaéaéaéaéa bfX>X>X>8:7:ySU;U;U;U;U;U;U;U;U;WG )WGU;U;U;U;U;U;U;U;U;yS7:8:X>X>X>of béaéaéaéaéaéa b‘f86622ö1W:WCV?V?V?V?V?V?V?™S &wG575757575757575;57ÛNºJºJšJšFÓf+béa§Yéaéa§Yéa,f8:8:86622ö1KWCWCWCWCWCyO "V?4343434343zSÛNºJºJšJšF™B™Bof béaéaéaéa b‘fX>8:8:86622ö1zWWGWGxOU73/3/vGÚNºJºJšJšF™B™ByBY>fMf+b+bMf²fY>Y>X>8:8:86622X>yS»_T7úNºJºJšJšF™B™ByBY>Y>X>8:ÓfÔf™B™ByBY>Y>X>8:8:86622<_ºJºJšJšF™B™ByBY>Y>X>8:8:ºJšJšF™B™ByBY>Y>X>8:8:86622ºJºJšJšF™B™ByBY>Y>X>8:8:86ºJºJšJšF™B™ByBY>Y>X>8:8:8662yBÛNºJšJšF™B™ByBY>Y>X>8:8:866ÛNºJºJšJšF™B™ByBY>Y>X>8:8:8662<_ºJšJšF™B™ByBY>Y>X>8:8:8662ÛNÛNºJºJšJšF™B™ByBY>Y>X>8:8:8662!ºJšJšF™B™ByBY>Y>X>8:8:86622ºNÛRÛNºJºJšJšF™B™ByBY>Y>X>8:8:866X>#ºNšJšF™B™ByBY>Y>X>8:8:86622ö1W:yS;WÛNºJºJšJšF™B™ByBY>Y>X>8:8:866<_ $ûRšJšF™B™ByBY>Y>X>8:8:86622ö1KWCU;5;43ÚNºJºJšJšF™B™ByBY>Y>X>8:8:866 %šJšF™B™ByBY>Y>X>8:8:86622X>zWWCV?U;5743vG3+ºJºJšJšF™B™ByBY>Y>X>8:8:86y> šJšF™B™ByBY>Y>X>8:8:86622<_ySWGWCV?U;57433/T7 ºJºJšJšF™B™ByBY>Y>X>8:8:86 ºJšF™B™ByBY>Y>X>8:8:8662yBWGWCV?U;57433/»_ ÛNºJšJšF™B™ByBY>Y>X>8:8:86 [šF™B™ByBY>Y>X>8:8:8662<_xOWCV?U;5743U7 ºJšJšF™B™ByBY>Y>X>8:8:yB šF™B™ByBY>Y>X>8:8:866X>WCV?U;5743 ºNšJšF™B™ByBY>Y>X>8:8: šF™B™ByBY>Y>X>8:8:866<_yOV?U;57V? ûRšJšF™B™ByBY>Y>X>8:8: ÛN™B™ByBY>Y>X>8:8:86y> V?U;57 šJšF™B™ByBY>Y>X>8:™F ™B™ByBY>Y>X>8:8:86<_ ™SU;wG ºJšF™B™ByBY>Y>X>> ™B™ByBY>Y>X>8:8:yBWGšF™B™ByBY>6BCdl šF™ByBY>Y>X>8:8:\_!šF™B™BF"hll"hûV™ByBY>Y>X>8:™F$ÛNôI!hllll™ByBY>Y>X>8:']cllllll™ByBY>Y>X>™F*hllll!hÚNyBY>Y>X>-LallllyBY>Y>™F0llllyBY>Y>3"hll!h™BY>šF6llûRY>9hlšF;dh!hIMG>>šFûR;šFY>™B9Y>ûRY>yB6šFY>™BšFY>yBÚN3Y>Y>yBY>Y>yB™B0™FY>Y>yBY>Y>yB™BûV-X>Y>Y>yBÚN™FY>Y>yB™BšF*™FX>Y>Y>yB™BX>Y>Y>yB™B™B(8:X>Y>Y>yB™BX>Y>Y>yB™B™BÛN$™F8:X>Y>Y>yB™BûV™FX>Y>Y>yB™B™BšF! \_8:8:X>Y>Y>yB™BšF 8:X>Y>Y>yB™B™BšF[WG yB8:8:X>Y>Y>yB™B™B 8:X>Y>Y>yB™B™BšFºJ wGU;™S <_868:8:X>Y>Y>yB™B™B ™F8:X>Y>Y>yB™B™BšFšJ 57U;V? y>868:8:X>Y>Y>yB™B™BÛN 8:8:X>Y>Y>yB™B™BšFšJûRV?57U;V?yO <_6868:8:X>Y>Y>yB™B™BšF \_8:8:X>Y>Y>yB™B™BšFšJºN4357U;V?WC X>6868:8:X>Y>Y>yB™B™BšF yB8:8:X>Y>Y>yB™B™BšFšJºJU74357U;V?WCxO<_26868:8:X>Y>Y>yB™B™BšF[ 868:8:X>Y>Y>yB™B™BšFšJºJÛN»_3/4357U;V?WCWGyB26868:8:X>Y>Y>yB™B™BšFºJ <_868:8:X>Y>Y>yB™B™BšFšJºJºJT73/4357U;V?WCWGyS<_226868:8:X>Y>Y>yB™B™BšFšJ %y>868:8:X>Y>Y>yB™B™BšFšJºJºJúNvG4357U;V?WCzWX>226868:8:X>Y>Y>yB™B™BšFšJ $6868:8:X>Y>Y>yB™B™BšFšJºJºJÚNzS5;U;WCKö1226868:8:X>Y>Y>yB™B™BšFšJûR #<_6868:8:X>Y>Y>yB™B™BšFšJºJºJÛN57ySW:ö1226868:8:X>Y>Y>yB™B™BšFšJºN!X>6868:8:X>Y>Y>yB™B™BšFšJºJºJÛN7:ö1226868:8:X>Y>Y>yB™B™BšFšJºJ26868:8:X>Y>Y>yB™B™BšFšJºJºJ8:226868:8:X>Y>Y>yB™B™BšFšJºJ<_26868:8:X>Y>Y>yB™B™BšFšJºJX>26868:8:X>Y>Y>yB™B™BšFšJºJÛNyB26868:8:X>Y>Y>yB™B™BšFšJX>6868:8:X>Y>Y>yB™B™BšFšJºJºJ226868:8:X>Y>Y>yB™B™BšFX>868:8:X>Y>Y>yB™B™BšFšJºJºJ<_226868:8:X>Y>Y>yB™BÓfofoffX>Y>Y>yB™B™BšFšJºJºJúNT7»_ySX>226868:8:X>Y>Y>of+b b b b,b²fyB™B™BšFšJºJºJÚNvG3/3/U7"xOWGWGzWö1226868:8:X>f béaéaéaéaéa,f˜J™BšFšJºJºJÛNzS4343434343V? &yOWCWCWCWCWCKö1226868:8:Mféa§Yéaéa§Yéa bofšFšJºJºJÛN575;57575757575757wG )™SV?V?V?V?V?V?V?WCW:ºNÛNÛNºJºJÓf+béaéaéaéaéaéa bMfšJºJºJÛNÛRySU;U;U;U;U;U;U;U;U;WG )WGU;U;U;U;U;U;U;U;U;ySÛRÛNºJºJšJÔf+béaéaéaéaéaéa bMfºJºJÛNÛNºNW:WCV?V?V?V?V?V?V?™S &wG575757575757575;;WÛNºJºJšJšF™BMféa§Yéaéa§Yéa bf8:86622÷1OWCWCWCWCWCyO "V?434343434343ÛNºJºJšJšF™B™B²f béaéaéaéa b,fWB8:8:86622÷1zWWGWGxOU73/3/vGÚNºJºJšJšF™B™ByBY>‘f,f b b+fMf³fY>X>8:8:86622X>yS»_T73+ºJºJšJšF™B™ByBY>Y>X>8:‘ff²fyByBY>Y>X>8:8:86622<_ºJºJšJšF™B™ByBY>Y>X>8:8:86X>šFyByByBY>Y>X>8:8:86622ºJºJšJšF™B™ByBY>Y>X>8:8:866X>šJšFyByByBY>Y>X>8:8:8662yBÛNºJšJšF™B™ByBY>Y>X>8:8:8662X>ºJšJšFyByByBY>Y>X>8:8:8662<_ºJšJšF™B™ByBY>Y>X>8:8:866228:ºJºJšJšFyByByBY>Y>X>8:8:8662!ºJšJšF™B™ByBY>Y>X>8:8:86622ö17:ÛNºJºJšJšFyByByBY>Y>X>8:8:866Y>#ºNšJšF™B™ByBY>Y>X>8:8:86622ö1W:yS›_ÛNºJºJšJšFyByByBY>Y>X>8:8:866<[ $ûRšJšF™B™ByBY>Y>X>8:8:86622ö1KWCU;5;43ÚNºJºJšJšFyByByBY>Y>X>8:8:866 %šJšF™B™ByBY>Y>X>8:8:86622X>zWWCV?U;5743vGúNºJºJšJšFyByByBY>Y>X>8:8:86yB šJšF™B™ByBY>Y>X>8:8:86622<_ySWGWCV?U;57433/T7ºJºJšJšFyByByBY>Y>X>8:8:86<_ ºJšF™B™ByBY>Y>X>8:8:8662yBWGWCV?U;57433/»_ ÛNºJšJšFyByByBY>Y>X>8:8:86 šF™B™ByBY>Y>X>8:8:8662<_xOWCV?U;5743U7 ºJšJšFyByByBY>Y>X>8:8:yB šF™B™ByBY>Y>X>8:8:866X>WCV?U;5743 ºJšJšFyByByBY>Y>X>8:8:<_ šF™B™ByBY>Y>X>8:8:866<_yOV?U;57V? ûRšJšFyByByBY>Y>X>8:8: ÛN™B™ByBY>Y>X>8:8:86y> V?U;57 šJšFyByByBY>Y>X>8:™F ]côI™ByBY>Y>X>8:8:86 ™SU;wG ºJšFyByByBY>Y>X>8: l!hFY>Y>X>8:8:yBWG [šFyByByBY>Y>X>8:hll"h6BX>8:8:"šFyByByBY>Y>X>™FLallllCd>™F$ÛNyByByBY>Y>X>llllll(yByByBY>Y>X>lllll"h*šFyByBY>Y>™F"hllll-ûVyByBY>Y>lll!h0yByBY>Y>lll3ÚNyBY>šFhl!h6yBY>dhl9™BY>!h;ûRšFIMG>>!hdh;šFlh9Y>ûRll6šFY>™B!hll"h3Y>Y>yBllll0™FY>Y>yBllllLa-X>Y>Y>yBÚN!hllllh*™FX>Y>Y>yB™Bllllll]c'8:X>Y>Y>yB™Bllll!hôIÛN$™F8:X>Y>Y>yB™BûV"hll"hF™B™BšF! \_8:8:X>Y>Y>yB™BšFlCd6BY>yB™B™BšFWG yB8:8:X>Y>Y>yB™B™B >X>Y>Y>yB™B™BšFºJ wGU;™S <_868:8:X>Y>Y>yB™B™B ™F8:X>Y>Y>yB™B™BšFšJ 57U;V? y>868:8:X>Y>Y>yB™B™BÛN 8:8:X>Y>Y>yB™B™BšFšJûRV?57U;V?yO <_6868:8:X>Y>Y>yB™B™BšF 8:8:X>Y>Y>yB™B™BšFšJºN4357U;V?WC X>6868:8:X>Y>Y>yB™B™BšF yB8:8:X>Y>Y>yB™B™BšFšJºJU74357U;V?WCxO<_26868:8:X>Y>Y>yB™B™BšF[ 868:8:X>Y>Y>yB™B™BšFšJºJÛN»_3/4357U;V?WCWGyB26868:8:X>Y>Y>yB™B™BšFºJ 868:8:X>Y>Y>yB™B™BšFšJºJºJT73/4357U;V?WCWGyS<_226868:8:X>Y>Y>yB™B™BšFšJ %y>868:8:X>Y>Y>yB™B™BšFšJºJºJ3+vG4357U;V?WCzWX>226868:8:X>Y>Y>yB™B™BšFšJ $6868:8:X>Y>Y>yB™B™BšFšJºJºJÚN435;U;WCKö1226868:8:X>Y>Y>yB™B™BšFšJûR #<_6868:8:X>Y>Y>yB™B™BšFšJºJºJÛN;WySW:ö1226868:8:X>Y>Y>yB™B™BšFšJºN!X>6868:8:X>Y>Y>yB™B™BšFšJºJºJÛNÛRºN226868:8:X>Y>Y>yB™B™BšFšJºJ26868:8:X>Y>Y>yB™B™BšFšJºJºJÛNÛN26868:8:X>Y>Y>yB™B™BšFšJºJ<_26868:8:X>Y>Y>yB™B™BšFšJºJºJÛN6868:8:X>Y>Y>yB™B™BšFšJºJÛNyB26868:8:X>Y>Y>yB™B™BšFšJºJºJ868:8:X>Y>Y>yB™B™BšFšJºJºJ226868:8:X>Y>Y>yB™B™BšFšJºJ8:8:X>Y>Y>yB™B™BšFšJºJºJ<_226868:8:X>Y>Y>yB™B™BÔfÓf8:X>Y>Y>yB™B™BšFšJºJºJúNT7»_ySX>226868:8:X>Y>Y>²fMf+b+bMffY>yB™B™BšFšJºJºJÚNvG3/3/U7"xOWGWGzWö1226868:8:X>‘f béaéaéaéa bof™B™BšFšJºJºJÛNzS4343434343V? &yOWCWCWCWCWCKö1226868:8:,féa§Yéaéa§Yéa+b·RšFšJºJºJÛN575;57575757575757wG )™SV?V?V?V?V?V?V?WCW:ö122686‘f béaéaéaéaéaéa bofX>X>X>8:7:ySU;U;U;U;U;U;U;U;U;WG )WGU;U;U;U;U;U;U;U;U;yS7:8:X>X>X>f béaéaéaéaéaéa bof86622ö1W:WCV?V?V?V?V?V?V?™S &wG575757575757575;›_ÛNºJºJšJšF²f+féa§Yéaéa§Yéa bf8:86622ö1KWCWCWCWCWCyO "V?434343434343ÛNºJºJšJšFyByBMf béaéaéaéaéa,bX>8:8:86622ö1zWWGWGxOU73/3/vGÚNºJºJšJšFyByByB³f,f b b b b,f²fY>X>8:8:86622X>yS»_T7úNºJºJšJšFyByByBY>Y>X>fMfMfof¸RyBY>Y>X>8:8:86622<_ºJºJšJšFyByByBY>Y>X>8:8:ºJšJšF™B™ByBY>Y>X>8:8:86622ºJºJšJšFyByByBY>Y>X>8:8:86ºJºJšJšF™B™ByBY>Y>X>8:8:8662yBÛNºJšJšFyByByBY>Y>X>8:8:866ÛNºJºJšJšF™B™ByBY>Y>X>8:8:8662<_ºJšJšFyByByBY>Y>X>8:8:8662ÛNÛNºJºJšJšF™B™ByBY>Y>X>8:8:8662!ºJšJšFyByByBY>Y>X>8:8:86622ºNÛRÛNºJºJšJšF™B™ByBY>Y>X>8:8:866X>#ºJšJšFyByByBY>Y>X>8:8:86622÷1W:yS57ÛNºJºJšJšF™B™ByBY>Y>X>8:8:866<_ $ûRšJšFyByByBY>Y>X>8:8:86622÷1OWCU;5;zSÚNºJºJšJšF™B™ByBY>Y>X>8:8:866 %šJšFyByByBY>Y>X>8:8:86622X>zWWCV?U;5743vGúNºJºJšJšF™B™ByBY>Y>X>8:8:86y> šJšFyByByBY>Y>X>8:8:86622<_ySWGWCV?U;57433/T7ºJºJšJšF™B™ByBY>Y>X>8:8:86<_ ºJšFyByByBY>Y>X>8:8:8662yBWGWCV?U;57433/»_ ÛNºJšJšF™B™ByBY>Y>X>8:8:86 [šFyByByBY>Y>X>8:8:8662<_xOWCV?U;5743U7 ºJšJšF™B™ByBY>Y>X>8:8:yB šFyByByBY>Y>X>8:8:866Y>WCV?U;5743 ºNšJšF™B™ByBY>Y>X>8:8:\_ šFyByByBY>Y>X>8:8:866<[yOV?U;57V? ûRšJšF™B™ByBY>Y>X>8:8: ÛNyByByBY>Y>X>8:8:86yB V?U;57 šJšF™B™ByBY>Y>X>8:™F yByByBY>Y>X>8:8:86<_ ™SU;wG ºJšF™B™ByBY>Y>X>8: yByByBY>Y>X>8:8:yBWG [šF™B™ByBY>Y>X>8: šFyByBY>Y>X>8:8:<_!šF™B™ByBY>Y>X>™FûVyByBY>Y>X>8:™F$ÛN™B™ByBY>Y>X>yByBY>Y>X>8:(™B™ByBY>Y>X>yByBY>Y>X>™F*šF™ByBY>Y>™FÚNyBY>Y>X>-ûV™ByBY>Y>yBY>Y>™F0™ByBY>Y>yBY>Y>3ÚNyBY>šF™BY>šF6yBY>ûRY>9™BY>šF;ûRšFSYMBTEXT CompassMapTEXTprissiIMG1IMGJ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGî  ÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿ ÿÿÿÿ ÿÿÿÿ ÿÿÿÿ ÿÿÿÿIMGJ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGî  ÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿ ÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿ ÿÿÿÿ ÿÿÿÿIMG IMG IMG IMG SYMBTEXT ElectricityTEXTIMG1IMGÚÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxÆxSYMBTEXTFlagsTEXTIMG1IMGº -0 ­5­5RJ­5­5­5¥¥­5­5¥¥ ¥¥¥÷^¼w”RuNRJ*5*5*5¥­5 ­5­5¥¥¥)%)%"­5”Rÿÿÿÿ÷^”R4R]]]!%­5”R¼wuNRJ­5#¥)%­5÷^ÿÿÿÿ÷^önuj]]]A4¥ )%)%­5­5­5­5RJ”R”R”R”R÷^÷^”RRJ­5¥­5#)%­5”Rœsÿÿÿÿ÷^ujujCqCq]A4*5­5ËEÌU4RuZ÷^÷^ÿÿÿÿœs÷^÷^RJRJ«)¥#)%RJ÷^¼wÿÿÿÿ÷^]]CqCq]"Q!5¥ CqCq]]ujön¼wön÷ÿÿÿ÷^÷^”R­5¥$)%RJ”R÷^œsÿÿÿönÌe]CqCqCq]&A*5CqCqCq]CqÌe]j¼wÿÿÿ¼w÷^”R­5¥­5$)%RJRJ”R÷^ÿÿÿönCqCqCqCqCqCq&A&A]CqCqCqCq]]saönÿÿÿÿ÷^uNRJ¥¥RJ$)%­5­5”R÷^ÿÿÿönCqCqCqCqCqCq]¡H"Q]CqCqCqCqCqCqCq¼wÿÿÿœs÷^÷^­5)%$)%­5­5”R÷^ÿÿÿönCqCqCqCqCqCq]]!5]CqCqCqCqCqCqCqujœs¼wÿœs÷^÷^­5)%$¥«)­5”R÷^ÿÿÿönCqCqCqCqCqCqCq]¥¡HCqCqCqCqCqCqCqljujönÿœs÷^÷^­5)%$¥«)­5”R÷^ÿÿÿönCqCqCqCqCqCqCq]b(¡HCqCqCqCqCqCqCqCqCqCqÿÿ¼wuNRJ­5(¥)%­5”R÷^ÿÿÿönljCqCqCqCqCq]&A¥ b(b(b(&A&ACqCqCqCqCqCqÿÿ¼w”RRJRJ¥­5)¥¥­5”R÷^ÿÿÿönönlj]]]]&A)%)%¥¥)%]]CqCqCqCqÿÿ¼w÷^uNRJ)%¥* ­5RJ”Rÿÿÿ¼w÷^”R)%)%)%)%)%)%)%¥)%]CqCqCqCqÿœs÷^uN­5)%)%*!%­5* ­5”R÷^ÿÿœs)%)%)%*¥)%)%)%)%!% **5&Ab(b(b(”RRJRJ­5)%¥ ¥+¥¥­5”R÷^ÿÿœsb(¥¥)%)%)%!% )%)%)%¥­5­5­5)%!%¥,)%RJ”R÷^¼wœs¥)%)%)%)%)%)%¥b(b(!%!%)%)%)%)%)%)%)%)%­5,­5­5RJ÷^¼wœs )%)%)%)% ¥  ¥¥*)%)%)%)%)%¥,­5­5RJ÷^¼wœs )%)%)%*5!5b( ¥)%)%)%)%)%¥!% -)%RJ”R÷^¼wœs)%)%*5¡H¡H¡HA4A4A4 ¥¥!%)%)%)%)%)%)%¥­5-)%­5RJ÷^¼wœsb(b(¡H¡H¡H]]¡H¡HA4A4b(b(¥¥)%)%)%)%)%)%!% ­5-)%­5RJ÷^¼wœsA4¡H]]]Cq]¡H¡H¡HA4A4b(¥¥)%)%)%)%)%)%!% b(­5-«)RJ÷^¼wœsb(¡H]CqCqCqCqCq]¡H¡HA4A4b(b(!%b(b()%)%)%)%)%)%)%A4A4¡H¡HA4A4A4A4­5-­5RJ÷^÷^RJb(A4¡H¡H]]CqCqCq]¡H¡H¡HA4A4A4b(A4A4¡HA4A4"Q&AA4¡H¡H¡H¡H¡HA4A4A4A4-­5RJ”R”RRJb(b(A4¡H¡H¡H]CqCqCq]]¡H¡HA4A4A4b(A4A4¡H¡H¡H]¡H¡H]]¡H¡H¡HA4A4A4A4-)%­5)%RJRJb(A4A4¡H¡H¡H]CqCqCqCqCq]¡HA4A4A4¥A4A4¡H]CqCqCqCqCqCq]¡H¡H¡HA4A4A4¥)%)%&)%)%b(A4A4¡H¡H¡H]CqCqCq]]CqCq]¡HA4b(A4A4¡H]]CqCqCqCqCq]¡H¡H¡HA4A4A4¥¥$b(A4A4¡H¡H¡H]CqCqCqCq]ÃuÃuÃu]A4b(A4A4¡H¡H]CqCqCqCqCq]¡H¡H¡HA4A4A4$b(A4A4A4A4¡H]CqÃue{e{e{e{e{ÄZCjÃe!%A4A4¡H]CqCqCqCqCqCq]¡H¡H¡HA4¡H¡H$b(A4¡H¡H]ÃeCje{e{e{e{e{e{e{CjÃu"A&A&A]]]CqCqCqCqCqCqCq]]"Q]¡H$A4¡H]ÃeÄjDke{e{e{e{e{e{e{ÄjÃuÃe&A)%ÃeÃe]CqCqCqCqCqCqÃuÃeÃeÃeÃe"Q$A4]ÃuÃue{e{e{e{e{e{e{e{Ãue{e{Ãu!5ÄZCjÃuÃuÃuÃuÃuÃuÃue{ÄjÃuÃuÃuÃe$]ÃuÃuÃuCje{e{e{e{e{e{e{e{e{CjÃu!5¥ LJÄje{e{e{e{e{e{e{e{ÄjÃuÃuÃuÃe $b(ÃuÃuÃuÃuÃuCje{e{e{e{e{DkDkCjÃuÃu¡Hb(­5Äje{e{e{e{e{e{e{e{ÄjÃuÃuÃuÃe $b(ÃuÃuÃuÃue{e{e{DkÄZÄZLJ­5b(¥ *5"Q"Q"Q!%ÃeÃue{e{e{e{e{e{e{ÄjÃuÃuÃuÃe $b(ÃuÃuÃuÃuÄjDkCj!5!%!%¢5¢E"Qê]ê]!5!5!5Ë9Äje{e{e{e{e{e{e{e{e{e{ÃuÃu"Q­5 $b(ÃuÃuÃuÃuCV#F"Qb(¥!%¢EÃuCjê]¥)%ËEDke{e{e{e{e{e{e{e{e{e{Ãu"Q"A­5 b(ÃuÃuÃuÃub(­5RJCj"Q*ŠAÃue{e{Ãue{e{e{e{e{e{ÄjÃu¢E b(ÃuÃeÂQb(Ë9­5!%!%b("AÃeÃuÄjDkÄj¢E!%!%!%!%!%!%b(  Ãu¢E!%­5RJ¥¥¥¥"AÃeÃeCV#F#F  ­5¥ uNuNuNuN¥ ¥     SYMBTEXTHappyTEXTIMG1IMGÆsx{š{™{5s /þþüÜÜýÿ” §~¶µT{””´t{•×Ê~ Âaè~“0s.Jp°NRÏf“ë~v „~æ~lIZ¦JjÊçèIlç~„~BEÅ~å~G¦jC-f†ÆÄ=eZgå~Å~BI£Yæ~F‡g§†§ˆˆ‡&æ~ÃaÄ]Æ~jŒŒŒŽŽŒhæ~j¤Qfv)Ž‘‘‘‘’²°K{ÇvfÂ$È~Ërk³³’’’³³0oënŠÁ( åYl-s­bq{’²²QwÎf.o­&V &Vé~®o{ïjïjïjïjkOwÏJ&V &V ®¯oÏÎj&V &V&VJŒ¬¬Jf^&V&Vá$-â(&VSYMBTEXTInTownTEXTIMG1IMGd„4H1H1vuuvuuuub uuuub r^R^R^R^R^r^ ‰9!Å ÅÅ Å!‰9 °b!^!^^!^!°bb^UÑjònÑjssÑjónÑjU^bu4{uòn)JqJq)ònu4{u NH1b!rb!k}k}!rb!bH1 N NH1b!rb!k}k}!rb!bH1 N NH1b!sb!!sb!bH1 N±bÌE°b!“f¬I¥¥¬I“f!°bìE±bSYMBTEXTLogoTEXTIMG1IMGÒ 2,÷^÷^*÷^÷^9g9g9g9g( ÷^÷^9g9g9g9g÷^÷^RJRJ& ÷^÷^9g9g9g9g÷^÷^RJRJBB$÷^÷^9g9g9g9g÷^÷^RJRJJ)J)BB"÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€RJB ÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€€€RJB÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€€€µVµVRJ)%÷^÷^µVBµVµV÷^÷^RJRJJ)J)€€€€µVµV)%)%÷^÷^9g9g9g9gµVµVµVµVBB€€€€µVµV)%)%÷^÷^9g9g9g9g÷^÷^RJRJBµVBB€€µVµV)%)%÷^÷^9g9g9g9g÷^÷^RJRJBBBµVBRJµVµV)%)%÷^÷^9g9g9g9g÷^÷^RJRJJ)J)BBBµVBRJ)%)%÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€RJBBµV)%RJ÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€€€RJB)%)% RJ)%÷^÷^9g9g9g9g÷^÷^RJRJJ)J)€€€€µVµVRJ)% RJ)%)%)%)%)%µVµV÷^÷^RJRJJ)J)€€€€µVµV)%)% )%)%)%)%)%RJÿ÷^µVµVBB€€€€µVµV)%)%)%RJÿ÷^­5­5BµVBB€€µVµV)%)%)%)%­5­5BµVBRJµVµV)%)%c­5÷^)%)%­5­5­5­5BµVBRJ)%)%­5ÿ)%)%)%­5­5÷^RJRJ­5­5BµV)%RJ­5÷^)%­5­5ÿ÷^­5RJ­5­5­5)%)%)%)%)%)%­5­5ÿ÷^­5­5)%­5­5)%)%­5c)%­5­5ÿ÷^­5­5)%)%)%)%cc)%÷^­5­5)%)%­5­5)%)%)%)%)%)%­5­5k-k- )%c)%)%)%­5­5)%)% k-)%)%)%)%­5­5k-k-k-k-c)%k-SYMBTEXT MaglevStopTEXTIMG1IMG . €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXTMessageTEXTIMG1IMG¢ -,¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H ¡H¡H¡H¡H¡H¡H¡H¡H¡H ¡H¡H¡H¡H¡H¡H¡H¡H¡H ¡H¡H¡H¡H¡H¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿœsœsÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿ­5­5ÿÿÿÿÿÿ¡H¡H¡H¡H ¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿ­5­5ÿÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡HÿÿÿÿÿÿÿRJRJÿÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡HÿÿÿÿÿÿÿÿRJRJÿÿÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿœsœsÿÿÿÿÿÿÿÿ¡H¡H¡H¡H¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿœsœsÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H!¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H!¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H#¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H#¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H%¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿœsœsÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H%¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H'¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H'¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿœsœsÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H)¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H)¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H+¡H¡H¡H¡H¡Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡H¡H¡H¡H+¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H-¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H-¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H+¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡H¡HSYMBTEXTMessageOptionsTEXTIMG1IMG #$$$$$###$$$$$######$###$###$###$#$$###$$$$$###$$$$###$###$###$###$##$$$$$###$$$$$######$###$###$###$#&)%€##$$$$$###$$$$ä ‰1€$###$###$###$#ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµV÷^ï=çÿï=÷^÷^÷^ÿÿ÷^ï=÷^µVÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^÷^çç÷^÷^÷^÷^÷^÷^÷^÷^çç÷^IMGŠ ÿÿÿ|ÿ|| Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&ÿQ&ÿQ&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&ÿÿÿQ&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&ÿ|ÿÿÿÿÿÿÿÿÿÿÿÿQ&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&IMGˆ  Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q& Q&ÿQ&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q& Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&ÿÿÿÿÿÿÿÿÿÿÿQ& Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&Q&SYMBTEXT MonorailStopTEXTIMG1IMG. €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXTNarrowgaugeStopTEXTIMG1IMGd. €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXTNewYearTEXTIMG1IMGŠ!@@@!BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBŒ1@!AB ƒBBF1éEF1¨=mV+N‡9§=nR+ND1 J N JKRÈElVŒ^KR°^JlZJV†= J§Ae9†=$5ÇED5¨A†=D5éEe9E5ÈE¨=E5f5¢ä$A!@!A ¤å$&-bf5+N†9+JLR+J†= JmVÈEèI R*RlVÇElVðf®^ÐbJVðbÏbJR J§A†=E9†=ÈED5§A§AD5ÈA†9†=ÈA§=‡9f5))! !@!!!!å$F-êEä$‡9+N%-LNLRêI NŽV­bèQK^k^KVèM¬^ñfkVvsÎfÏbÎbðfèImVe9D5§AÈEe=†=§Ef=§=§A†9ÈA¦=§A†9‡9‚Ab!@!bä ‚bä$‡9LRf5¨=éA- J¯^K^l^ïjb­nŒfl^kZ­^ñfÎbUoToðfîf2oKVmZ§EeA†A R†E†EÈI§I†AÇEe9ÇA†=ÈAÇA) )! !@!B A &)g5F1%-f5LRéE J†=E5KZïjînRws0{îrÎnÏjŒbkkRsðfkvwlVñf R*RÇQ†I VÈUÈQéUèU§MèI†AD5†=éEf5-¨=£! !@!ƒä$)êAéE§9f5 J*N+RÈQèUswS{S{•{Q{r{2wŒjRsswkRsoTsÎf®b®f*V*bÈY b bé]é]Lf+bÈUeA$5ÈEE1$1éE)‚! !@!! AÄ ‡9 FmR JÈA‡=LVKZlbÏnu{Q{ض·Ú•{wr{Qw1wRwSssîjÎj­fŽjKf bJnn*n j¯rŒné]†I§If9D5§=†9)aA!@!!ƒà ã$%-‡9F1©= JLV§IŒfŒn®r—{”{•¶{Øü·û“{Q{s{•{–{RwÎjïnknïvïv*jKrðvkrlr®vŒvmjé]ÈM†Af=ÈA$1ã$-b!@!!Aà F1‡9e5†5E1f5ÈI¯b ZÎrQ{ïvÛ“Ù•Úüý”{S{•{“{o–wtw­nÎrQ{îz‹v)n{kr­vïz­z®v bèU†A§A$1‡=§=£ !!@!Bƒä$)e5LRmVÈA%1f= ^jÎv{r{•üÚØÚÚ¹üÚ¶2{s1w2wR{•{Q{{îz*n¬v)nJvïz®vlr b‡M§Ee=ÈE†=Ã$A!@!B£ ä(f5§AÈA¨= FLR VKfðnðr­rÎv–ûûØýÜØØ¶¸”{”{s{wÍv1{•{wŒvkv)rrkvkrKrJné]LbéMÇAe9¨AE5b!@!!£g9 JlZmV®^lVÈEéML^LblnÏr3{”{üØ×ÚüÙÚú×·Ú¹QwT{¸{ðv­vjvkv­vJvÍzŒvÍvkrðrÈYfAÈE+R§Ae5b!@!!£ F1éALR°^òbòb°^fÏnS{T{­vkrr{ÙØÖüÙµ{·Ù·¶Ù{r{q{s{s{1{Îv­zŒzîz‹vîzîv­zÎz­v Z N+RLRèE%1! !@!!Bä,‡9 J+NZ*NÈE ZÐn3wv{S{2{{O{/{rûÚ”{ÙûýÙ¶{Ù·¶”{S{îz¬z«z•{‹v¬v{1{Ïv*^ N*NLRêE)!@!! bÄ,f=ÈEKRl^ÏjlVKZŽjsT{t{2{2{{{R{¸ØÙµûÙÙÙØ¶{•{v{w{{T{¸”{1{R{1{R{béImVKRÈA)!!@!" ‚-ÈEKVZŽZÏfmb*VKfðv4w—{¸{–{”{îz{r{×µ•¸üÛ¹T{Ðr®nÏrïr1w­vR{ïz“{¶Û—{ŽjLV‡A†=‡9)b!!@!!"!Bƒ -f=ÉE+ZlZlZ,Vlbn2w•{¶•{•{s{Ö”{Ú“{•{t{–Út{–{ïr®rïr¯r­vR{{S{”¶–{twm^mZMVE5f5E1A!@!!Bb$£(Ã(†9§E*VblZÉI¨QŒnÎr1{t{u{Q{{Q{“{µS{ñv3{T{—{—{wÏnnŽjwv{2{•{¸·wnm^klV±^mV‚!!!@!!B Ac,I‡MéUéQ RêYKf+ZÉU*nïv1{t{”{1{t{r{ðvS{3wt{˜{—wšwÒjŽfÑrñnw¯rðv{U{rÏjéYèM*R°^éEF1&-!!@!! !!Bb0b £0%U‡Q‡M ^K^*fée*bjïrÎv3{u{3{t{T{Ïz4{–{¹{¹{˜{sŽfMbònooLb+^n,ZÉU+V RKRÇA NF5a!! !@!!! ! BB b$¤@M%I%M¨Q V+blbŽfmfŽfÏnÐr3{1{2{2{4w3{6{¸{U{x{3w5s¯r,bÑnñrMbŽb+^ ZLVèM¯f§A Nf9%-1!!! !!@!!! ! ABBB b,b,‚0Ä8E©UêU Z b+b­fŽj®nLnðvu{®zt{w3{{x{w{ssPj‘rWs°fnÑnnjŽb,V¯^êYnZ%9¨A%A‚$ƒ!!! !!@!! AABB BB$ƒ<ƒ<ÄH%A%IˆQÉU¨UÉY+jLjnmrÐr®rwwòzU{{Ôvw5wÓrOfÓrônÒn±nÑrŽvmbLbLVˆMéQ9&EÄHB$B!!! !!@!!! !BB BB$b,ƒ8£8Ä@EfQ‡Y*bÈ]êa f+bLjnn¯nŽn3wŽrÑvÑvQrqn³rÕr±nÒn‘jNjôrÑv°v¯vgUªY%IEE&Qc4c8B$B "! !!@!!! ! !!!BB,B,A(b0‚4Ã<äD%IÉUgQgY©Uéa f©] jln+bMn fNn±v1rrr“nPj’nqj/fîiîi‘vÓvìqH]åHUÄDåLb4c0„@b(c@B4!!!!!!@!! !!BBBBB B$b0b0‚4Ã8EäDä@%MfQ¨YÉ]Èeée f fêi n-nìm.j0rqrPn±n/fj.nÍi¬iîmr‹eH]æTÅLÄHÅL'Y¤D¤rs¯¯¯¯qsP6q>3[Qk¯Qk3[p:²J’sWQkQkW‘sF³NÑQkóN1c¯¯¯¯¯¯1cóNQkÐN³NЯ¯{òNÓFQo¯¯QoÓFóN{¯¯ÐN³NÐPoòV[ÒJ1c1cÓJ[òVQgÐN³NЯpw[1cpw1gòRòR1cpw1g[PsÐN³NðpsW1c¯p{p{¯QgWPoÐN²NÑ[_p{{1cW°N‘FRk1_{¯¯¯¯¯¯¯¯¯¯1cRgoB0.u_²{ÒÒÒÒÒÒÒÒÒÒÒÒ²{•c0. ­!­%­%­%­%­%­%­%­%­%­%­%­%­!é SYMBTEXTSeasonsTEXTIMG1IMG*   s````````````ªªª`` ```ª±±±ª``` `ª±±±±±ª` s``ª±±±±±ª`` s `ª±±±±±ª` ```ª±±±ª`````ªªª```````````` sIMGú  Ä hAÄ hAÂ4Â4Ä Ä Â4Â4Â4#IÄ Ä #IdYdYÂ4Ä Â4Ä hAÂ4Â4Â4Ä Â4Â4Ä  #IdYdYdYÄ Â4#IÂ4Â4 Â4Â4Â4Ä Â4Â4#IÂ4hA hA#IdYÄ Â4#IÂ4Â4Ä Â4Â4Ä #IÂ4#IÂ4Ä #IÄ Â4#IÂ4Ä Ä Ä Â4Ä Ä Ä hAÂ4Ä Â4hAIMGb  cÿcÿcÿÿÿÿÿcÿ cÿcccÿcccÿc ÿcÿcÿÿÿcÿcÿ ccÿcÿcÿcc cÿcÿcÿÿÿcÿcÿc ÿÿÿÿÿÿÿÿÿÿÿÿÿ cÿcÿcÿÿÿcÿcÿc ccÿcÿcÿcc ÿcÿcÿÿÿcÿcÿ cÿcccÿcccÿcÿcÿÿÿÿÿcÿcÿcIMGx  €€àà€€€€ààà à€€€€€ €€€€€€€B€€€€ €€€€€ààà€€€€€ €€€€àà,kàà€€€€ €€€à,kàà,k€€€ àB€,kà,kà,k€BB à€€ààà,k,k€à €€€€,k,k,k€€€à €€€€€€€€€€€€ €€€€B€€€€€€B€€B€€B€SYMBTEXT ShipStopTEXTIMG1IMGz0 €€€€€€€€ €€€€€€€€€€€ €€€€€€€€€€€€ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXT TrainStopTEXTIMG1IMGŽ, € €€€€€€€€€€€€€€€€€€€€€€€€€€€€ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXT TramStopTEXTIMG1IMGÀ)   €€€€€€€€€€ç€€€€€€€€€€€€€€€€€€€€€ç€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€SYMBTEXTUnhappyTEXTIMG1IMGÆŒh¬l¬l¬l‹h ®|­t¬l¬l¬l¬l¬p­x®| ­x¬p¬l¬l¬l¬l¬l¬l¬l­p­x ­|¬x¬p¬l¬l¬l¬l¬l¬l¬l¬t­x‹l ­`‹@¬p¬t¬p¬l¬l¬l¬p¬tŒd‹8­t­xkHIJk\Œt¬t¬l¬tŒtjHJIŒhŒl®|kp‘eó-J0kpŒtk`)$IvFÍdŒt¯|Ï|klv~SI2kXkpîH‘!‹Þs/y‹pÏ|®|klpuÿÿkÿŒx‹|‘}ÿÿgÞ¬pŒpÏ|‹`tJl)p t)lI8j0)H)p p)lkl­xhH ®|¬pŒlŒhj‹8‹Pk$k4ŒlŒl­t¬p ‹h­x¬pŒd‹D¬t¬x¬d‹H¬l¬p­|gD Œl­x¬t¬p¬p¬l¬p¬p¬t®xŠ\ ‹`­x­t¬p¬l¬p­x­tiPŠ\®|Î|­tŠTSYMBTEXTWarenTEXTIMG1IMGæ$(( @@,,,Æ  (,00LH0 (ÿ0044440 (ÿÿH44LL84 (@,ÿÿL88 88 Q ’ ‰ö@,DÿL4L8 Fº*º*ÔöËöD0H4L8 r “©öö=7=7ëöD0L8 “ÿööÊööööìöH4ÆÔ3ö3ööË=7>7ööN Í* ÆÆöÿö=3ö=3ööìö7N Í* ÆÆ^7ö>7ö=7ö=7ö N N Í*ÆÆÆ _7ö^7ö^7ö N N /ÆÆ;ö^7öN N N ;8N N kSYMBTEXTfastforwardsymTEXTIMG1IMG"  ))`n)`n)`n€r)`n€r)`n€r€r)`n€r€r)`n€r€r€r)`n€r€r€r) `n€r€r€r€r)`n€r€r€r€r) `n€r€r€r€r€E`n€r€r€r€r€E`n€r€r€r€E`n€r€r€r€E`n€r€r€E`n€r€r€E`n€r€E`n€r€E`n€E`n€E€E€ESYMBTEXT networksymTEXTIMG1IMG@  BBBBBBB> B8gÞwÞwÞwÞwÞwZkB Bßw•!y:y:y:•!ßwB Bßw•!y:.Ö!•!ßwB BBBBBBBÖ!Ö!•!ÞwB B8gÞwÞwÞwÞwÞwZkB•!tÞwB Bßw•!y:y:y:•!ßwBÞwÞwZkB Bßw•!y:.Ö!•!ßwBBBB Bßw•!Ö!Ö!Ö!•!ÞwB BÞwt•!•!•!tÞwB BZkÞwÞwÞwÞwÞwZkBBBBBBBBSYMBTEXT pausesymTEXTIMG1IMGB  )))Á~)))Á~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~`n€r€rÁ~€E€E€E€E€E€E€E€ESYMBTEXT station_typeTEXTIMG1  IMG IMG IMG   ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ ~~~~~~~~~~~IMG IMG  ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ ~~~~~~~~~~~IMG IMG IMG  ~~~~~~~~~~~~ ~~ ~~ ~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~ ~ ~~~~~~~~~~~IMG SYMBTEXT timelinesymTEXTIMG1IMG.  +MÒ ó 55 MVcccccc¹* MWÚ2¹.¹*˜"w5N ˜&–:Où:ù:¸*Ù:Ù6  U*{o[_{k{o{o{o:_ ¸>{o{o{o+jèiYo|oÙ: t6{o{o|oèi„i¾wo Ð%s¾wÞw±rbeÿ{ÿ{¶B v.22ÿ{ÿ{ÿ{ÿ{ÿ{ÿ{ßs3. —69gu6ÿ{|c·Bt>µV+Ñ [gc×Z÷^ZkØN° +–:–:–:ooo+simutrans-124.3/simutrans/themes/menu.pak64german_large.pak000066400000000000000000000001051474050137200240120ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOTsimutrans-124.3/simutrans/themes/modern-large.pak000066400000000000000000001503461474050137200221470ustar00rootroot00000000000000Simutrans object file Compiled with SimObjects 0.1.3exp ëROOT MENUTEXTButtonTEXTIMG1$$IMGL€¸»Å»Ð»€·»€W2™6Û:€Å»€™6Û:Û:€Ð»€Û:Û:Û:IMG"@@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:IMGL€Ð»Å»¸»Û:™6W2€€¶»Û:Û:™6€€Ä»Û:Û:Û:€€Ð»IMGBW2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:IMG"@@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:IMGBÛ:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2IMGL€Ð»€Û:Û:Û:€Å»€™6Û:Û:€·»€W2™6Û:€¸»Å»Ð»IMG"@@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMGLÛ:Û:Û:€€Ð»Û:Û:™6€€Ä»Û:™6W2€€·»€Ð»Å»¸»IMGL€š˜§˜²˜€™˜€L°!Ò%€§˜€°!ò%ò%€²˜€Ò%ò%ò%IMG"@@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%IMGL€²˜§˜š˜Ò%°!L€€˜˜ò%ò%!€€¦˜ò%ò%Ò%€€²˜IMGBLò%ò%ò%Lò%ò%ò%Lò%ò%ò%Lò%ò%ò%IMG"@@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%IMGBò%ò%ò%Lò%ò%ò%Lò%ò%ò%Lò%ò%ò%LIMGL€²˜€Ò%ò%ò%€§˜€°!ò%ò%€™˜€L°!Ò%€š˜§˜²˜IMG"@@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIMGLò%ò%Ò%€€²˜ò%ò%!€€¦˜Ò%°!L€€™˜€²˜§˜š˜IMGL€Ë&Ë1ˀˀRJ”RÖZ€&Ë€”RÖZÖZ€1Ë€ÖZÖZÖZIMG"@@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZIMGL€1Ë&ËËÖZ”RRJ€€ËÖZÖZ”R€€%ËÖZÖZÖZ€€1ËIMGBRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZIMG"@@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZIMGBÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJIMGL€1Ë€ÖZÖZÖZ€&Ë€”RÖZÖZ€Ë€RJ”RÖZ€Ë&Ë1ËIMG"@@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGLÖZÖZÖZ€€1ËÖZÖZ”R€€%ËÖZ”RRJ€€Ë€1Ë&ËËIMGH€àÿ€ÿÿ€àÿ€ÿÿÿÿÿÿÿÿÿÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGHÿÿ€€àÿÿÿÿ€€àÿÿÿÿÿÿÿÿÿIMGBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGHÿÿÿÿÿÿÿÿ€àÿ€ÿÿÿ€àÿ€ÿÿIMG"@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGHÿÿÿÿÿÿÿÿÿÿÿ€€àÿÿÿ€€àÿMENUTEXT RoundbuttonTEXTIMG1IMGL€¸»Å»Ð»€·»€W2™6Û:€Å»€™6Û:Û:€Ð»€Û:Û:Û:IMG"@@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:IMGL€Ð»Å»¸»Û:™6W2€€¶»Û:Û:™6€€Ä»Û:Û:Û:€€Ð»IMGBW2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:IMG"@@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:IMGBÛ:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2Û:Û:Û:W2IMGL€Ð»€Û:Û:Û:€Å»€™6Û:Û:€·»€W2™6Û:€¸»Å»Ð»IMG"@@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMGLÛ:Û:Û:€€Ð»Û:Û:™6€€Ä»Û:™6W2€€·»€Ð»Å»¸»IMGL€š˜§˜²˜€™˜€L°!Ò%€§˜€°!ò%ò%€²˜€Ò%ò%ò%IMG"@@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%IMGL€²˜§˜š˜Ò%°!L€€˜˜ò%ò%!€€¦˜ò%ò%Ò%€€²˜IMGBLò%ò%ò%Lò%ò%ò%Lò%ò%ò%Lò%ò%ò%IMG"@@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%IMGBò%ò%ò%Lò%ò%ò%Lò%ò%ò%Lò%ò%ò%LIMGL€²˜€Ò%ò%ò%€§˜€°!ò%ò%€™˜€L°!Ò%€š˜§˜²˜IMG"@@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%ò%@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIMGLò%ò%Ò%€€²˜ò%ò%!€€¦˜Ò%°!L€€™˜€²˜§˜š˜IMGL€Ë&Ë1ˀˀRJ”RÖZ€&Ë€”RÖZÖZ€1Ë€ÖZÖZÖZIMG"@@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZIMGL€1Ë&ËËÖZ”RRJ€€ËÖZÖZ”R€€%ËÖZÖZÖZ€€1ËIMGBRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZIMG"@@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZIMGBÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJÖZÖZÖZRJIMGL€1Ë€ÖZÖZÖZ€&Ë€”RÖZÖZ€Ë€RJ”RÖZ€Ë&Ë1ËIMG"@@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ@RJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJRJIMGLÖZÖZÖZ€€1ËÖZÖZ”R€€%ËÖZ”RRJ€€Ë€1Ë&ËËMENUTEXT EditfieldTEXTIMG1  IMG"€¾»Ë»€Ë»€oIMG@@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG"€Ë»¾»o€€Ë»IMGW2ÿW2ÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿW2ÿW2IMG"€Ë»€o€¾»Ë»IMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMG"o€€Ë»€Ë»¾»MENUTEXTListboxTEXTIMG1  IMG"€¾»Ë»€Ë»€oIMG@@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMG"€Ë»¾»o€€Ë»IMGW2ÿW2ÿIMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIMGÿW2ÿW2IMG"€Ë»€o€¾»Ë»IMG@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMG"o€€Ë»€Ë»¾»MENUTEXTBackTEXTIMG1  IMG IMG IMG IMGŠ@W2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kIMGŠ!@@@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾kIMGŠ@¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2¾k¾k¾kW2IMGH6.žg¾k¾k€Å»€S¾k¾k€·»€W2Sžg€¸»Å»Ð»IMG"@@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMGL¾k¾kžg€€Ð»¾k¾kO€€Ä»žgSW2€€·»€Ð»Å»¸»MENUTEXT CheckbuttonTEXTIMG1IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€¶»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€¶»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿkw:W2W2W2W2w:kÿÿÿW2W2ÿÿÿw:W2W2W2W2W2W2w:ÿÿÿW2W2ÿÿÿW2W2W2W2W2W2W2W2ÿÿÿW2W2ÿÿÿW2W2W2W2W2W2W2W2ÿÿÿW2W2ÿÿÿW2W2W2W2W2W2W2W2ÿÿÿW2W2ÿÿÿW2W2W2W2W2W2W2W2ÿÿÿW2W2ÿÿÿw:W2W2W2W2W2W2w6ÿÿÿW2W2ÿÿÿkw6W2W2W2W2˜:kÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%Ë€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1ËRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJ€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%ˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËËMENUTEXT PosbuttonTEXTIMG1IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€¶»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÙF¾sÿÿÿÿÿÿÿÿW2W2ÿÿÿÿW2W2Sÿ{ÿÿÿÿÿÿW2W2ÿÿÿÿW2W2W2w6\_ÿÿÿÿÿW2W2ÿÿÿÿW2W2W2W2W2˜>kÿÿÿW2W2ÿÿÿÿW2W2W2W2W2˜>kÿÿÿW2W2ÿÿÿÿW2W2W2w6\_ÿÿÿÿÿW2W2ÿÿÿÿW2W2Sß{ÿÿÿÿÿÿW2W2ÿÿÿÿÙF¾sÿÿÿÿÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€¶»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Ä»€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»W2Û:Û:Û:Û:¾küFÛ:Û:Û:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿ~cÛ>Û:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿÿÿ{]WÛ:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿÿÿÿßwÛ:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:¾küFÛ:Û:Û:Û:Û:Û:Û:Û:W2€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Ä»€·»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%Ë€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1ËRJÖZÖZÖZÖZsNµVÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJ”RÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJ”RÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJRJsNµVÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJRJsNµVÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJ”RÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJ”RÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZsNµVÖZÖZÖZÖZÖZÖZÖZÖZRJ€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%ˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËËMENUTEXT ScrollbarTEXTIMG1IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€¶»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€Ä»€;[ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÿÿÿÿ¾sÙFÿÿÿÿW2W2ÿÿÿÿÿÿÿ{SW2W2ÿÿÿÿW2W2ÿÿÿÿÿ\_w6W2W2W2ÿÿÿÿW2W2ÿÿÿk˜>W2W2W2W2W2ÿÿÿÿW2W2ÿÿÿk˜>W2W2W2W2W2ÿÿÿÿW2W2ÿÿÿÿÿ\_w6W2W2W2ÿÿÿÿW2W2ÿÿÿÿÿÿß{SW2W2ÿÿÿÿW2W2ÿÿÿÿÿÿÿÿ¾sÙFÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Ä»€;[ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€¶»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€·»€Ä»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Å»€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»W2Û:Û:Û:Û:Û:Û:Û:Û:üF¾kÛ:Û:Û:Û:W2W2Û:Û:Û:Û:Û:Û:Û>~cÿÿÛ:Û:Û:Û:W2W2Û:Û:Û:Û:Û:]Wÿ{ÿÿÿÛ:Û:Û:Û:W2W2Û:Û:Û:~cÿÿÛ:Û:Û:Û:W2W2Û:Û:Û:Û:Û:Û:Û:Û:üF¾kÛ:Û:Û:Û:W2€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»€Ä»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Å»€·»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€%Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€&Ë€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1ËRJÖZÖZÖZÖZÖZÖZÖZÖZµVsNÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZ”RRJRJÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZ”RRJRJRJRJÖZÖZÖZÖZRJRJÖZÖZÖZµVsNRJRJRJRJRJÖZÖZÖZÖZRJRJÖZÖZÖZµVsNRJRJRJRJRJÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZ”RRJRJRJRJÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZ”RRJRJÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZµVsNÖZÖZÖZÖZRJ€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1Ë€%Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€&ˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËËIMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€¶»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÙF¾sÿÿÿÿÿÿÿÿW2W2ÿÿÿÿW2W2Sÿ{ÿÿÿÿÿÿW2W2ÿÿÿÿW2W2W2w6\_ÿÿÿÿÿW2W2ÿÿÿÿW2W2W2W2W2˜>kÿÿÿW2W2ÿÿÿÿW2W2W2W2W2˜>kÿÿÿW2W2ÿÿÿÿW2W2W2w6\_ÿÿÿÿÿW2W2ÿÿÿÿW2W2Sß{ÿÿÿÿÿÿW2W2ÿÿÿÿÙF¾sÿÿÿÿÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ;[€€Ä»€·»€W2\_ÿ{ÿÿÿÿÿÿÿÿÿ{\_W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»€·»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€¶»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Ä»€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»W2Û:Û:Û:Û:¾küFÛ:Û:Û:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿ~cÛ>Û:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿÿÿ{]WÛ:Û:Û:Û:Û:W2W2Û:Û:Û:Û:ÿÿÿÿÿßwÛ:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:¾küFÛ:Û:Û:Û:Û:Û:Û:Û:W2€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Ä»€·»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€·»€¸»Å»Ð»€W2W2W2W2W2W2W2W2€€Ð»Å»¸»IMG¢€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%Ë€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1ËRJÖZÖZÖZÖZsNµVÖZÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJ”RÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJ”RÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJRJsNµVÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJRJsNµVÖZÖZÖZRJRJÖZÖZÖZÖZRJRJRJRJ”RÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZRJRJ”RÖZÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZsNµVÖZÖZÖZÖZÖZÖZÖZÖZRJ€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€%ˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€Ë&Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë&ËËIMG IMGj@@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k@¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾k¾kIMG IMGþ€¶»Ä»Ð»€¸»€W2;[ÿ{€Å»€\_ÿÿ€Ð»€ÿ{ÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿ€Ð»€ÿ{ÿÿ€Å»€\_ÿÿ€¸»€W2;[ÿ{€¶»Ä»Ð»IMGj@@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2W2IMGþ€Ð»Ä»·»ÿ{;[W2€€¸»ÿÿ\_€€Å»ÿÿÿ{€€Ð»ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿW2ÿÿÿ{€€Ð»ÿÿ\_€€Å»ÿ{;[W2€€¸»€Ð»Ä»·»IMG¢€¶»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»·»€¸»€W2;[ÿ{ÿÿÿÿÿÿÿÿÿ{;[W2€€¸»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÿÿkkÿÿÿÿÿÿW2W2ÿÿÿÿÿÿ˜>˜>ÿÿÿÿÿÿW2W2ÿÿÿÿÿ\_W2W2\_ÿÿÿÿÿW2W2ÿÿÿÿÿ{w6W2W2w6ß{ÿÿÿÿW2W2ÿÿÿÿSW2W2W2W2SÿÿÿÿW2W2ÿÿÿ¾sW2W2W2W2W2W2¾sÿÿÿW2W2ÿÿÿÙFW2W2W2W2W2W2ÙFÿÿÿW2W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€¸»€W2;[ÿ{ÿÿÿÿÿÿÿÿÿ{;[W2€€¸»€¶»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»·»IMG¢€¶»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»·»€¸»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€¸»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Å»€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»W2Û:Û:Û:Û:Û:Û:ÿ{ÿÿÿ{ü>Û:Û:Û:Û:W2W2Û:Û:Û:Û:~cÿÿÿÿ~cÛ:Û:Û:Û:W2W2Û:Û:Û:üFÿÿÿÿÿÿüFÛ:Û:Û:W2W2Û:Û:Û:¾kÿÿÿÿÿÿ¾kÛ:Û:Û:W2W2Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:W2€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Å»€¸»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€¸»€¶»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»·»IMG¢€Ë%Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë%ËˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€&Ë€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1ËRJÖZÖZÖZÖZÖZÖZµVµVÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZsNsNÖZÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZ”RRJRJ”RÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZÖZRJRJRJRJÖZÖZÖZÖZÖZRJRJÖZÖZÖZÖZ”RRJRJRJRJ”RÖZÖZÖZÖZRJRJÖZÖZÖZµVRJRJRJRJRJRJµVÖZÖZÖZRJRJÖZÖZÖZsNRJRJRJRJRJRJsNÖZÖZÖZRJRJÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZRJ€1Ë€ÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ€€1Ë€&Ë€”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”R€€&ˀˀRJ”RÖZÖZÖZÖZÖZÖZÖZÖZÖZÖZ”RRJ€€Ë€Ë%Ë1Ë€RJRJRJRJRJRJRJRJ€€1Ë%ËËIMG¢€·»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»¶»€¸»€W2;[ÿ{ÿÿÿÿÿÿÿÿÿ{;[W2€€¸»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»W2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿW2W2ÿÿÿÙFW2W2W2W2W2W2ÙFÿÿÿW2W2ÿÿÿ¾sW2W2W2W2W2W2¾sÿÿÿW2W2ÿÿÿÿSW2W2W2W2SÿÿÿÿW2W2ÿÿÿÿß{w6W2W2w6ÿ{ÿÿÿÿW2W2ÿÿÿÿÿ\_W2W2\_ÿÿÿÿÿW2W2ÿÿÿÿÿÿ˜>˜>ÿÿÿÿÿÿW2W2ÿÿÿÿÿÿkkÿÿÿÿÿÿW2€Ð»€ÿ{ÿÿÿÿÿÿÿÿÿÿÿÿÿ{€€Ð»€Å»€\_ÿÿÿÿÿÿÿÿÿÿÿÿ\_€€Å»€¸»€W2;[ÿ{ÿÿÿÿÿÿÿÿÿ{;[W2€€¸»€·»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»¶»IMG¢€·»Ä»Ð»€W2W2W2W2W2W2W2W2€€Ð»Ä»¶»€¸»€W2™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6W2€€¸»€Å»€™6Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:™6€€Å»€Ð»€Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:€€Ð»W2Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:Û:W2W2Û:Û:Û:¾kÿÿÿÿÿÿ¾kÛ:Û:Û:W2W2Û:Û:Û:üFÿÿÿÿÿÿüFÛ:Û:Û:W2W2Û:Û:Û:Û:~cÿÿÿÿ~cÛ:Û:Û:Û:W2W2Û:Û:Û:Û:ü>ÿ{ÿÿÿ{Û>Û:Û:Û:Û:W2W2Û:Û:Û:Û:Û:]Wÿÿ]WÛ:Û:Û:Û:Û:W2W2Û:Û:Û:Û:Û:Û:ßwßwÛ:Û:Û:Û:Û:Û:W2W2Û:Û:Û:Û:Û:Û: int main() { return puts(VERSION_NUMBER) < 0; } simutrans-124.3/src/OSX/osx.mk000066400000000000000000000042411474050137200161560ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Makefile to build bundle applications for Mac OS X # bundle makes a bundle designed to work on the system it was build on # bundle_dist makes a bundle, which should work on all supported systems (custom config needed) # Variables: # CXXHOST CXX for host system. Only used when crosscompiling. # BINARY_PPC path to the binary for PPC # BINARY_i386 path to the binary for i386 (default $(PROGDIR)/$(PROG)) # SDL_PPC path to SDL.framwork for PPC # SDL_i386 path to SDL.framwork for i386 (default ../Frameworks/SDL.framework) # The name of the project is simutrans => thus we want to build the default bundle under simutrans PROGNAME = $(PROG) ifeq ($(PROGNAME),sim) PROGNAME := "simutrans" endif CXXHOST ?= $(CXX) BINARY_i386 ?= "$(PROGDIR)/$(PROG).app/Contents/MacOS/$(PROG)" SDL_i386 ?= "../Frameworks/SDL.framework" .PHONY: bundle bundle_dist "OSX/getversion": OSX/getversion.cc simversion.h @echo "===> Building $@" $(Q)$(CXXHOST) "OSX/getversion.cc" -o $@ bundle: all "OSX/getversion" @echo "===> Building bundle" $(Q)rm -fr "$(PROGDIR)/$(PROG).app" $(Q)mkdir -p "$(PROGDIR)/$(PROG).app/Contents/MacOS" $(Q)mkdir -p "$(PROGDIR)/$(PROG).app/Contents/Resources" $(Q)cp "$(PROGDIR)/$(PROG)" "$(PROGDIR)/$(PROG).app/Contents/MacOS/$(PROG)" $(Q)cp "OSX/simutrans.icns" "$(PROGDIR)/$(PROG).app/Contents/Resources/$(PROG).icns" $(Q)echo "APPL????" > "$(PROGDIR)/$(PROG).app/Contents/PkgInfo" $(Q)OSX/plistgen.sh "$(PROGDIR)/$(PROG).app" "$(PROG)" bundle_dist: bundle @echo "===> Changing bundle to be distributable" $(Q)mkdir -p "$(PROGDIR)/$(PROG).app/Contents/Frameworks" $(Q)cp "$(BINARY_i386)" "$(PROGDIR)/$(PROG).app/Contents/MacOS/$(PROG).i386" $(Q)cp "$(BINARY_PPC)" "$(PROGDIR)/$(PROG).app/Contents/MacOS/$(PROG).ppc" $(Q)cp "OSX/binary_picker.sh" "$(PROGDIR)/$(PROG).app/Contents/MacOS/$(PROG)" $(Q)cp -r "$(SDL_PPC)" "$(PROGDIR)/$(PROG).app/Contents/Frameworks/SDL-ppc.framework" $(Q)cp -r "$(SDL_i386)" "$(PROGDIR)/$(PROG).app/Contents/Frameworks/SDL-i386.framework" simutrans-124.3/src/OSX/plistgen.sh000077500000000000000000000030031474050137200171730ustar00rootroot00000000000000#!/bin/sh # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # date=`date +%Y` PROG="$2" COPYRIGHT="Copyright 1997-${date} by the simutrans team" if [ -z "$3" ]; then VERSION="`../OSX/getversion`" else VERSION=$3 fi echo "Executable $PROG" echo "$VERSION" echo " CFBundleDevelopmentRegion English CFBundleDisplayName ${PROG} CFBundleExecutable ${PROG} CFBundleGetInfoString ${VERSION}, ${COPYRIGHT} CFBundleIconFile ${PROG}.icns CFBundleIdentifier org.${PROG}.${PROG} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PROG} CFBundlePackageType APPL CFBundleShortVersionString ${VERSION} CFBundleVersion ${VERSION} NSHumanReadableCopyright ${COPYRIGHT} NSPrincipalClass NSApplication " > "$1"/Contents/Info.plist simutrans-124.3/src/OSX/simutrans.icns000066400000000000000000005207501474050137200177270ustar00rootroot00000000000000icns¡èis32ÿêîõý‰ÿŽ”¤Ãçþ†ÿsokhgt¢ã…ÿ c_ZVSOKaµúÿÿþ€ÿWRLGB=949Žõá¦þÿÿRKD>82.)$%‡z#ÐÿÿVc~ˆyY<221.Rîÿ–´ÀÄË̬oLF ˆùª”€z}Œ®«rR"–ô{nd]YY^dgiX"XäFGRX]acegjor,Sß;YÄÿþÙúƒÿWUROLJGDB?=;975420C´þÿÿÞGσÿTRNKHEB@=:741/,*('$4®þþ€pü‚ÿSPMJGDA>;741.+(&# 4¾Ø$‚ÿTRNKGCA>:8641/,*('&'&HVJíÿWTPVk€Š‡x`H:765322123) €û€ÿ[_{¦ÀÉÍÐÑͺ’aB=>==<=<¯€ÿ‚¤¾ÅÆÊÌÏÒÕÙÜУfIGHHI3 ‚:*Öÿÿ»ÀÁ¿µ­ª­µÁÎØÝßΔ[RSJ&.bñÿ¼³ƒrlihio{’¶Õ×Сc\?1</ÁÆêÿ’wutsrpnjeacwwomb`_J Jêÿÿ„ƒ}xph`YUSSUVZ]adfhcK‚`òÿvk^TMIHKPV\aeghijlnprtb'AP¦ý?>?CLTZ^``_`behkmmnprss{52Êëý<>@IYZZ]`ceeca_^^_`bfjs’y=àÿ<>?FY[YVSRQRSUWZ\^`bdef€‚7C#7lî;=?ADEFHKMOQSUWY[]_acefei[!²Õí;=?ACEGIKMPRSUWY[]_acegikl',Ðÿ€65543224:CNUWY[]_acegiknA\à&‚%‚$&,=SXZ\^`bdfhjnR(•ä‹%:VZ\^`acegilY  ¤%œÝÿòõöùü˜ÿËÌÌÎÒÙäðú”ÿ ÅÄÄÃÂÁÁÃËÛïý‘ÿ ÁÀ¿¿¾½½¼»º½Íèüÿ½¼»ºº¹¸··¶µ´·Êëþÿ¹¸·¶µ´´³²±±°°®´ÓøŒÿ¶µ´³±±°¯®­¬««ªª©¿ì‹ÿ³²°¯®­¬«ª©¨§¦¦¥¥£¯áÿþäûƒÿ°¯®­«ª©¨¦¥¤£¢¡  Ÿž¥ØþÿÿèƒÞƒÿ¯®¬«©¨§¥¤£¡ Ÿœ›šš™žÕþþªXŸü‚ÿ¯­¬ª©§¦¤£¢ Ÿœš™˜—––žÞämYfÕ‚ÿ¯®¬«©§¦¥£¢¡ Ÿœ›š™§“Z[Y†òÿ°¯­¯¶½À¾¹±¨£¡¡  Ÿ ’a[[ZZ¨ü€ÿ ²³¼ÊÓÕרØ×б¦ƒ¤£vZZYWT\Æ€ÿ¿ÊÒ€Õ ×ØÙÚÛÜØÉ´ª€©ª‘]XWUSQLfáÿÿÒÔÔÓÐÍÌÍÏÓ×ÛÝÝØÄ²®¯¥jWTRPNLafŠôÿÓÐÊÁ¼º¹¸¸º¾ÆÑÙ×ÒÁ¯°’ƒ`OMKJFdÐÓïÿÇÿ¾¿¿¾½º³ªž’Œƒ}||‚‡RJIGEC?tîÿÿÇÇÅ¿¶©š‰znfccfimpsuYwwlSDB@?=8ôÿ¦”€n`XUW[bhlprtuvxz}wS=<:9gr¶ýJHIMV^dhijjkmqtvxy{}x€V762WÓîýFHKSabdfilnon€mnprtxyw‘€=0/)[åÿFHJQacb`_^_`begjloqtvxqƒT,*DT€ðEGJLPQSUX[]`begjlnqsvxyrvs2%@¼ÚïEHJMOQSVX[^`bdgilnqsuxz}€F$#J×ÿ==<<;:8679AL[dgiknpsuwz|ƒ\&&;sä&&€%ƒ$&.Eaikmpruwz|~‚k)%F¤ç‹%@fkmoqsvx{}p,&$@±%œÝÿøúúûýþ—ÿïðïïðñôøü”ÿ€ð€ïîíîñ÷ý‘ÿïïƒîííìíõýÿîî‚íìëêíöþÿííì„ëêéïûŒÿììë‚êéèë÷‹ÿ€ë€êéƒèççóþ€ÿþÛúƒÿë€ê€é€è‚ç€æåðþÿÿàQуÿ€êéé€è€ç€æ‚åãïþþ‡wü‚ÿêê€é€èçç€æ€åäãôØ0&Å‚ÿ€ê€é€èçç€æ…åwTîÿ ëêêéæäããäå‚ç‚æé¾)€‡ü€ÿ ëêæâßÞÞÝÝÞÞâåè ççèäe ³€ÿèãàßßÞÞ€ÝÜÜÝáæé ì¨ 4Øÿÿá€àá€âáßÞ€ÜÞäêëìÓC08iñÿáãæê‚ìNëêèãÜ×Ó×áåž|48ÃÈëÿëíîïïððïìäØÉ¶Ÿ‘ŒŒ’š§‘ QëÿÿòòðëáÒÀ¬™‰~xwy|~‚„†ƒf,€N fòÿÊ· Œ|rmmptx|~€ƒ„…†ˆŠ|6 HV¨ýeccflquxyzz|}ƒ„…‡ˆŠ‰}~: 8Ëëýacdjstuwy{}~~€ƒ…‡†z‘{ Báÿabdhsuttsstuwy{}€‚„†ˆy…F (;oî`bdfhikmoqsuwy{|~€‚„†ˆ‡|€x&´Öíaceghjkmoqtvwxz|~€‚„†ˆ‰ŒŽ71ÑÿQPMKHEB??BKZmxz|~€ƒ…‡‰‹‘W !`á'&%%„$&1Pt|}ƒ…‡‰‹‘l ,˜äŠ%&Hy}~€‚„†ˆ‰‹u%¦%œl8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿih32œÿÿëÿÚããèîõû¦ÿ ’‘’•›¥´ÇÜðü¡ÿ‰‡†…„ƒ€€ƒ¤Äåúžÿ‚€~}|{zyxvv€›Åíœÿ|{zyxvvttsrqpomn®äþ™ÿvutrqponmlkjihhgedt§å˜ÿponlkjihgedccba`__]\p±ð–ÿkjhgedcb`_^]\[ZYXXWVTUzÍý”ÿfeca`_]\[YXWVTSRQQPONNKX¢ò“ÿa`^\[YXVUSRQONMLKJIHGGFEEzÜ’ÿ]\ZXVUSQPNMKJIGFECBA@@?>>;[Æþ„ÿçð‡ÿZXVTRPOMKJHFECB@?=<;:987764F³ý‚ÿúk‡ÿWUSQOMKIHFDB@?=;986542100/.-9¢ûÿ¾@î†ÿ&USQOMKIGECA?=;976420.-+*)(''%/üÿÿõR ž†ÿTRPNLJGECA?=;97531/-+)'%#" ,§ýÿ®6ä…ÿ(TRPNLJGECA?=;97531/-+)'%#" !!3¸òF{ü„ÿ"USQOMKIGDB@><;975310.,+)(''&&'('Hx€»„ÿWUSQOLJMSWVPG?:998653210/‚./0,<ãƒÿYXVSSgˆ¤´¼¿¼±ŸƒbG;::987766567"‚hö‚ÿ]ZZl–ºÆÉÊÌÍÐÓÕÖϸ‹\B>?>>ƒ=>6 •þÿbq–·ÃÄÅÆÈÊÌÎÐÒÔ×ÛÜÍ fGDEEƒD!†Áÿ™´¿ÁÁÃÅÇÉÌÍÏÑÒÔÕØÚÜÞÐaK‚LM8 „;ã€ÿ½¾¿ÀÃþ·±¯¯³ºÃÌÔØÚÛÜÝÝdžW€STL‚€ 1# fõÿÿ½¿À»©{pkhghjoyŠ¡¼Ó€Ý ßÚ§fZ[Y-% „(fÕ²}Ðÿÿ»°šƒtnmmlkjihgfeel«Îɾ¶³ˆ`bT@W0„( ÿÿûÿÿŽ€ywwvutsrrqpomkgc^^kf`^_`_aafX‚€¥ÿ!€€~}}|zwrle_ZVTSUUVXYZ\]^`acbR, …¾€ÿ#‰ˆ‡„xof]UPMLMNOQRTX[_cgjmnoonljfH„Y-Õÿÿ|qdXOIFEFGHJLPU\cimopnljihijloswxpTHn;cîÿA>>?@BCEJPXahkkgb^ZY[^bgkoqsttsppotj#-!»òÔîÿ<=>@AK\cfe`YURSX^elprrpmkhffginuxjŒ‘y€(Ê€ÿ<=>@AJTPNRX_glnmje`\Y[\^_abcehgŒ‘J€5Øÿÿ;=>?@I_ghgc^XTQOPQRUVWYZ[]^_abcef`z‘k Eåÿ;<>?@ENKIGHIJLNOPRSTVWXZ[\^_`bcdfeaswj>!˜“[”ù;<>?@BBDEGHJKLNOPRSTVWXZ[\^M_`bcdfggccl`Jçýîü;<=?@ACDEGHIKLMOPQSTUWXY[\]_`acdeghiklm-Tëÿÿ;<=?@ACDD€E#FHJMPRSTUVXYZ\]^`abdefhijloIdòÿ€4-3210/-,+**+-07ALTUVXYZ\]^`abdefhijln]  4#…÷&‚%$$„% $$%*8LVWYZ[]^_abcefgijkmgP¸¾í%$+DWYZ[]^_abcefgijkml#7Áþ’%)IXYZ[]^_abcefgijkl*€!«%Üÿÿëÿçðïñôøüþ¥ÿ ÈËÉÉËÍÑ×áëöý¡ÿÈÇÇÆÆÅÄ€ÃÇÐßðûžÿÄĀà ÂÂÁÁÀÀ¿¾ÁÌßôœÿÂÁÀÀ€¿¾¾½½€¼ººÀÔïþ™ÿ ¿¾¾½½¼¼»»ºº¹¹€¸·¶»Ñð˜ÿ¼¼»ºº¹¹¸¸··¶¶µµ€´³²¹Öö–ÿº¹¸¸·¶¶µµ´´³³²²±±€°¯®¼ãþ”ÿ··¶µ´´³²²±±°°¯¯®®€­¬¬«®Ï÷“ÿµ´´³²±±°¯¯®­­¬¬««ªª€©¨¨§¼ë’ÿ³²²±°¯®®­¬««ª©©¨¨§§¦¦¥£®àþ„ÿîô‡ÿ±±°¯®­¬¬«ª©¨¨§¦¦¥¤¤££¢¢€¡ ¦×ý‚ÿû›¼‡ÿ°¯®®­¬«ª©¨§§¦¥¤£¢¢¡  ŸŸ€ž ÍüÿÒaó†ÿ¯®­¬¬«ª©¨§¦¥¤£¢¢¡ Ÿžœ››€š ™›Ëýÿÿø‹X]½†ÿ'¯®­¬«ª©¨§¦¥¤£¢¡ Ÿžžœ›š™˜˜—–——šÑþÿÇ`[Yxì…ÿ(¯®­¬«ª©¨§¦¥¤£¢¡ Ÿžžœ›š™˜——––——ÚõƒY[[Z¥ý„ÿ¯®­¬¬«ª©¨¦¥¥¤£¢¡¡ Ÿžœœ›…š§©_€[ZeЄÿ°¯®­­«ª«­®®¬¨¥£€¢¡  Ÿ€žƒž™iZ[Y|ëƒÿ±±°¯®µÀÉÏÑÒÑÍǽ±¨¤££€¢¡ €¡¢ƒ\[ZXV—ø‚ÿ³²²·ÅÑÕ€Ö ×ØÙÚÚ×ÏÀ¯¦€¥„¤ ¥šfZ[ZYXWUTV³þÿµºÅÐÓÔÔÕÕÖ×רÙÙÚÜÜ×dz©…¨ §|ZZYXVUTRQO^ÑÿÇÏÓÓ€ÔÕÖ֨רÙÙÚÛÛÜÝØÇ²ƒ«¬•_XWVUSRQONKHpê€ÿÓ ÔÔÓÐÏÍÎÏÑÔ×ÚÛÜÝÕ¿°€®¯§kUVTSQPONLNh^IŒ÷ÿÿ€Ó1ÒÍž»¹¸··¸¹½ÂÉÒÙÜÝÝÞÝÌ·³³±evYQPNMLKIHŒßÅœÚÿÿÒÏɽ€»*ºº¹¹¸¸··¸ºÁÌÓË»¸¬£ª¡‘ª€ONMKJIHFDH¨ÿÿûÿÿÆÂÀ€¿¾¾€½ ¾¾¼¹³ªƒ|tpnoqsx~’YKKJHGFECB@I¹ÿÄăÃ$Á¼³§˜ˆzogccdfhikmnprsuvp]JFEDCA@?>;OË€ÿBÉÉÈĽ±¢‘pd]ZZ[]_adfjmqtvyz{||{{zjMBA@>=<;92WÝÿÿ­œ‡tdYSPQSUWZ]bhmru€xwv]xz|‚ƒ€nJ==;:97lŠ_ñÿMHGIKMOQU[bjprrpmjhhilpswz|~~~wwuL98763JÇôÛñÿFGIKLVdjmlhd`_`djouxz{yxw€uwy|‚n‹C4431.MÒ€ÿ=EGIJLT]ZY\bhosuurolihhijlnoqstvxyl‹_110.-)UÞÿÿEGHJKSgmonkgc`€^&`bdfgijlnoqstvwylzu=-,+01$_éÿEFHJKPYV€TVWZ\]_`bdegijlmoqrtvwyxiswu\+)'A¦¢r¢úEFHIKMNPRSUVXZ[]_`bceghjlmoprtuwyzzrrw4&&%dêýðüDFHIKLNPQSUVXZ[]^`bceghjkmoprsuwxz|~€€‚K$&&e$líÿÿDGHJKLNOPQPQRTW[^abcefhikmnprsuvxz{}€ƒc'&&%#zôÿ;;:976421/-,,-/4=JXcefhiklnpqsuvxy{}~€ƒt/%&.PA–ø&€%„$€%€$%,?Yfgiklnoqstvxy{|~€‚}9%&)hÁÇï%$-Nfijlnoqrtvwy{|~C$&&$SÊþ%&&%*Uiiklnpqstvxy{}~G#€&#A·%Üÿÿëÿðøö÷ùúüþ¥ÿíðîî€íîñôùý¡ÿñƒðïîíìíð÷üžÿðð†ïîíëìðøþ›ÿï‡îíëêíöþ™ÿƒîˆíëêí÷þ—ÿî„íˆìêèîù–ÿ€í„ì†ëêêéçòþ”ÿ‚ìƒëˆêéçíú“ÿìì‚ë„ê‡éçèõ’ÿ‚ë‚ê‚é‡èçåñþ„ÿèñ‡ÿëë‚ê‚éƒè†çäîþ‚ÿús¢‡ÿëê‚éè‚ç†æäéýÿÁKï†ÿêéè‚ç‚æ„å âéýÿÿõ\£†ÿ€êé‚èçæåƒä âìþÿ²@å…ÿ€êé‚èçæå„ä âðñP‚ü„ÿêéè‚çæˆåæž€%¿„ÿëê€éèçèèç‰æçÖCFåƒÿëë€ê èäáàßÞßßáãåçèŠçépö‚ÿ€ëèäàÞƒÝßâæ„èçéË6€šþÿìéäà€ßÞ‚ÝÜÜÝáæèéƒèéçq€'Äÿåáàà߀ނÝÜÝâçƒéì¯"€€ Dä€ÿáá€àßàá€âáàßÞÝÝ‚ÜÞåêìØD€:-löÿÿááàáäçêë€ìëëêéçäàÝÜÜÝÝÞäëííèz8a!€l×µƒÒÿÿâäçëíî‡íîíêâÖÎÆÀ¾ÅÐÚÚÒy€ ’ÿÿûÿÿìîïïƒîïïðïëã×ǵ¡…€‚…‹“¯ª, ¨ÿ"ððïïððññïéßо«˜‰~ywwy{}~€‚‚„…„p@€€ &À€ÿ#òóòîæÚÈ´ŸŒ~uppqrtvxz{~€‚ƒ…†‡‡ˆ‰Šˆc" € 3ÖÿÿÑ¿©“sliijlnprvy|„ƒ ……†ˆŠ‹Œo% € , Os@hîÿicabdfgjlpuy}~~|{zz{}‚„…‡ˆˆ‰‰Š‹}{o*  '½óÕïÿabcdfltyzzxvtstvz~ƒ‚„ƒƒ„…‡ˆ‹Šq‹‘z! .Ë€ÿ`bcdekponqtx|€€~|€{|}€‚„…†‡‡p‹‘N  ;Ùÿÿ`acdejvz|{zwutsstvwxy{|}~€‚ƒ…†‡‰uzs  Iæÿ`acdehmmkklnoprstuwxyz|}~‚ƒ„†‡ˆ†ptx}T &š•_–ù`abdefgijklnopqstuvxyz{}~K€‚ƒ„…‡ˆ‰ˆ}}~Oçýîü`abcefghjklnopqrtuvwyz{}~€‚ƒ„…‡ˆ‰ŠŽŽ=Xëÿÿ`bcdefg€fUilptvwwyz{|~€ƒ„…†ˆ‰Š‹Ž’a góÿOMJGDA>:741//03:FWjwyz{|}€‚„…†ˆ‰Š‹ŒŽz8'ˆ÷&&%‹$%/Giz{|}~€‚ƒ…†‡‰Š‹ŒŽˆ$ S¹Àí%$$/Zz|}~€‚ƒ„†‡ˆŠ‹ŒŽ2;Âþ%&%,c||}~€‚ƒ…†‡ˆ‰Š‹Ž:€&­%Üh8mk ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿit32[jýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáÿ ³²¶ÙÜÙÖÏÞìçòùúïÿŒ’‘‰”Œœ ¡²ÃËÞéöýèÿ€€Ž€ŒŒ‹Š‰‡ˆ†‹—¦»ÑãóýãÿŒŒ‹ŠŠ€‰ˆ ‡†…„ƒ„‰’¦ÂÝòýßÿ‹€Š‰‰€ˆ‡‡†€…€„ ƒƒ‚ƒ¦ÀâøÜÿˆˆ€‡€†€…„„€ƒ€‚€€ }|{ƒ–´ÛõÙÿ††……€„ƒƒ€‚€€€~€}|{yx~‘²×÷Öÿ„€ƒ‚‚€€€~~€}€|€{€zy€xvtx•¹àûÓÿ€€€€~}}€|€{€zyyx€w€vutrqz™ÐóÑÿ~~}}€|{{€z€yxx€w€v€ut€srqqnr‰´êÏÿ}€|{{zzyy€xww€v€u€tssr€qp€o€nlk¥ÜýÌÿ{zzyyxx€wvv€utt€srr€q€p€o€nml€kjgqŸÝýÊÿxxwwvv€uttss€rqq€p€onn€m€lk€j‚i€hgdp ÛüÈÿ vvuuttssrr€qppoo€nmm€l€k€j€i€h€g‚fedblœæÇÿ ttssrrqqppoo€nmmll€kjj€i€hggfe€d‚c€ba_s¨çÅÿr€qp€o nnmmllkkjj€ihh€g€feedccb€a‚`_][u»öÃÿpoonnmmllkkjjiihh€gff€edd€c€baa`€_^]‚\Z\…ÒýÁÿnmmllkkjjiihhggffee€dccbb€a``€_€^€]€\[Z‚YXV`œæÀÿlkkjjiihhggffeeddccbb€a``__€^€]\\€[€ZY€X‚WVURm¿ú¾ÿjiihhggffeeddccbbaa``__^^]]€\[[€ZYY€X€WV€U‚T‚SPU’è½ÿhggffeeddcbbaa``__^^]]\\[[€ZYY€XWW€VUUT€SRQ‚POMpÈü»ÿffeedccbbaa`__^^]]\\[[ZZYYXX€WVVUUTT€S€R€Q€PONƒMKTðºÿedccbbaa`__^^]]\[[ZZYYXXWWVVUUTT€SRRQQ€POON€ML‚KJII{Û¹ÿ#cbba``__^]]\\[[ZZYXXWWVVUUTTSSRRQQPP€ONN€MLL€KJ€IƒHGD^»û·ÿ$aa`__^^]\\[ZZYYXXWVVUUTTSRRQQPPOONNMM€LKK€J€I€H€GF‚EDBJ–î¶ÿ&`_^^]\\[[ZYYXWWVVUTTSSRRQQPOONNMMLLKKJJ€IHH€GFF€E€D‚CBA@?{ãµÿ*^^]\[[ZZYXXWWVUUTSSRRQPPOONMMLLKKJJIIHHGGFF€EDDCCB€A@„?>>€=…<;:O¼”ÿã~õ™ÿ-[[ZYYXWWVUUTSSRQQPOONNMLLKJJIIHGGFFEDDCCBBAA@@€?>>==<€;‚:„96H¥ù‘ÿý†Ä™ÿ1ZYYXWWVUUTSSRQQPOONMMLKKJIIHGGFFEDDCCBBA@@??>>==<<€;::€9€8‚7„648˜ùÿÖ"aù˜ÿ5YYXWVVUTTSRQQPOONMMLKKJIIHGGFEEDCCBAA@@??>==<<;;::9988€7€6€5‚4ƒ327˜ôŽÿùpΘÿ4XWWVUTTSRRQPPONMMLKKJIHHGFFEDDCBBA@@?>>==<<;::9987766€544€321„02vìÿÂwý—ÿ8WWVUTSSRQQPOONMLKKJIIHGGFEEDCBBA@@?>>=<<;::98877655443322€1€0€/‚.-.-+pë‹ÿù^"Õ—ÿ:VVUTSSRQQPONNMLKKJIHHGFEEDCCBAA@?>>=<<;:99887665443321100//€.--€,ˆ+)nêŠÿ±€vý–ÿ>VUTTSRQQPONNMLKKJIHHGFEEDCCBA@??>==<;::988765544322100/..--,,++€*))ˆ(&kêˆÿñF Жÿ?UUTSRQQPONNMLKKJIIGGFEDDCBAA@??>=<;;:99876654432110//.--,,+**)((€'&ƒ%€&$iê‡ÿ© ƒ`ø•ÿAUTSSRQPOONMLLKJIIHGFEEDCBBA@??>=<<;:9987655433210//.--,++*))(''&%%€$€#"€#$$!{÷…ÿîDƒ¿•ÿCUTSRQQPOONMLKKJIHGGFEECCBAA@?>==<;:9987765433210//.--,+**)(''&%%$##"€!„ !!""'‰ö„ÿ– …Wô”ÿGTTSRQQPONMMLKJJIHGGFEDCCBA@??>=<<;:9987655432110/..-,++*)(''&%$$#"!!  €!%ý‚ÿä1† ¤”ÿGTTSRQQPONMMLKJJIHGGFEDCCBA@??>=<<;:9987655432110/..-,++*)(''&%$##"!!   !!""/«ýÿŽˆ0Ü“ÿEUTSRQQPOONMLKKJIHGGFEECCBAA@?>==<;:9987765433210//.--,+**)(''&%%$##"!!€ € !!"##$#1¹€ÿã0ˆqú’ÿCUTSSRQPOONMLLKJIIHGFEEDCBBA@??>=<<;:9987655433210//.--,++*))(''&%%$$€#ƒ"€# $$%%&$DÒÿÿж’ÿAUUTSRQQPONNMLKKJIHGGFEDDCBAA@??>=<;;:99876654432110//.--,++**)((''&…%& ''((&\åÙ)ŠBê‘ÿ>VUTTSRQQPONNMLKKJIHHGFEEDCBBA@??>==<;::988765544322100/..--,,++€*))‰(€)**++(uiwúÿ>=<<;:99887665443321100//..€-€,‹+€,€-.)°ÿWWVUTSSRQQPOONMLKKJIIHGFEDCBBAA€@?>==<<;::98877655443322€100€/.‡-.€/005ßÿ!XWWVUTTSRRQPPONMMLJIHJNSW[]]ZVPJC@‚>==<<;::988776655€43321‰01223* ŽdöŽÿ5YXXWVVUTTSRQQPONLO\o‡š©³»¿ÁÂÁ¾¹°¡|iUE>==>==<<;;::9988€7€655‚4‹3ƒ4‹‚ –þÿZYYXWWVUUTSSRPP]{œ¶ÃÉÊ€ËÌÍÎÎÏÐÒÓÓÒÏ­rVC==>>==<<€;::€9€8‚76€78+ Š…Àÿ[[ZYYXWWVUUSSe²ÄÇÈÉÉÊËÌÍÍÎÏÐÐÑÒÓÕ××Ôŧ~[E>>??>>==€<€;:„9…8ƒ9:8ˆˆ;áŒÿ0]\[[ZYYXWVVf޵ÄÅÄÅÆÇÇÈÉÉÊËÌÌÍÎÎÏÐÑÒÓÓÔÕÖØÚØË¬|SA?€@??>=„<‡;‚<=* ‡‹dõ‹ÿ4^^]\\[ZYXfŒ³ÂÃÃÄÄÅÆÆÇÈÈÉÊÊËÌÍÍÎÏÐÑÑÒÓÔÔÖÖרÚÜÙÄ™hH@AB€A‚@?>?:„Ž ”þŠÿ `_^^]\[g‹±Á€Â(ÃÃÄÅÆÆÇÈÈÉÊÊËÌÍÍÎÏÐÐÑÒÓÓÕÕÖ×רÙÚÜÞÓ­uNBCDC‚BAB%„‘ÀŠÿ8aa`_^h‰®¿ÁÀÁÁÂÃÃÄÅÅÆÇÇÈÉÊÊËÌÌÍÎÏÏÐÑÒÒÓÔÕÖÖרÙÚÛÛÝÞØ¸€RDEF‚E„D‡C€DE9“=ä‰ÿ/cbaj‰­¾À¿ÀÀÁÁÂÃÄÄÅÅÆÇÇÈÉÉÊËËÌÍÎÎÏÐÑÑÒÓÔÕÕÖרÙÚÚÛ€ÜÞÚºRFHƒG‹FGE“‚jöˆÿ0dkˆ«½¿¾¿¿ÀÁÁÂÂÃÃÄÅÅÆÇÇÈÉÉÊËÌÌÍÎÎÏÐÑÑÒÓÓÔÕÖרØÙÚÚÛÜÞÙ·yOIƒJIJ4 “… ™þ‡ÿ0Š©»¾½¾¾¿¿ÀÁÁÂÂÃÃÄÅÅÆÇÇÈÉÉÊËËÌÍÍÎÏÏÐÑÒÒÓÔÕÖÖרÙÙÚÛƒÜÞÖªlML€MŽLD‘ˆɇÿ»½¼½½¾¾¿€À&ÁÂÂÃÃÄÅÅÆÇÇÈÉÉÊËËÌÍÍÎÏÏÐÑÒÒÓÔÕÕÖרØÙÚÛÛ„ÜÞÏ—]NON'‘‹Fè†ÿ»¼¼½€¾¿ÀÀÁÁÂÂÃÄÄÅÅÆÇÇÉÉÊËÌÌÍÍ΀ÏÐÑÒÒÓÔÔÕÖÖרÙÙÚÛ…ÜÝܽ{TQ‚R‡QS= †‚tú…ÿ$¼¼½½¾¾¿¿ÀÀÁÁÂÃÃÄÅÆÇÆÄÀ½º·¶´µ¸º½ÂÆÊÎÑÓÔ ÕÕÖרØÙÚÛÛ†ÜÞÕŸaSŠTUMŒ‰ &-¯…ÿ¼€½¾¾¿¿ÀÀÁÁÂÄÄÁ·¨™‹wrmji€hilotz„œ«¹ÅÏÕר×רÙÙÚÛ‡ÜÝÜ»v‹W.‡Š @ÏÌ¥xE2ß„ÿ¼½½¾¾€¿ ÀÁÂÃÁ´œ‚sjf€edcc€ba``€_afn}¥¼ÍÖÚÚÙÚÛÛˆÜÞ΋\Y€ZƒY[B € !"ƒ løÿÿõئb- föƒÿ¼½½¾¾¿¿ÀÁÁ¹¥‹ukiijii€hgg€f€e€d€cbba`_ahvެÆÖÜÛÛ‰ÜÝ×a…\ ]S/KT€‘ƒýÿý緃؃ÿ ½½¾¾¿ÀÀ¼­•~p‚mll€kjj€ihh€g€fe€d ccbadoНÎÜ݇܀ÝÛ¤e„_ ]*9U`a6“Ÿþ„ÿýƒÿ½¾¾À¾³Ÿ‡wqpqqppoo€nmm€l€k€j€i€h€g‚feedcfy¢Ì€Ý€Þ ÝÜØÕÔÒÐÑÐaƒbB>Z€cP“½‹ÿ¾¾¸§‘~vtss€rqq€p€onn€m€lk€j‚ihggff{¯ÓÎÁ²¡”‰€xurpqtl`aabcd_I[f€e`$‘„)Њÿ­š†{wxxww€vuu€tss€r€q€p€o€nm€l„k jige`cska[€XYYZ[\\]]__``aabdefggh>ˆC߉ÿ€‚{zzyy€xww€v€utt€s€r€qpƒo*nnljfc_[YWVVUWWYYZZ[[\\]]^^__``aabbcceg\Œ‹^ïˆÿ€~}}€|{{€zyy€x€w€v€u€tƒsrqokgb]YV€T%UUVVWWXXYYZZ[[\\]]^^__``aabbccddbM-ˆŽuú‡ÿ€€€~~€}||{zz€y€xƒw7vtqmga[WSRQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddefeS/ … ’þ†ÿ„€ƒ‚‚€€€€~€}€|‚{>ywsmg_YTQNONPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeefgfP$€“³†ÿ†€…„„€ƒ‚‚€€€}ztme]VPMLKLMNN€OPQQRR€S TUUVVWWXXYY€Z[€\]€^_€`a€bcdd€efghc@”'Ï…ÿˆˆ€‡€†……ƒ„ƒ€|ulcZRMIIHIJK€LM€N OOPPQQRRSST€UVVWW€X€YZ[\]`abce‚fedd€ceeffghiT …=ä„ÿ‹ŠŠ€‰‚ˆ$†ƒ}tk`VOIGEFFHHIIJJKKLLMMNNOOPPQQRRSSTUUWX\^cgmrwz~„†‡ˆ€‰ˆ‰ˆ†„}wqlgfegghi`.Œ‚^óƒÿ‚ ŒŠ…}th\SJF€CDEFFGGHHIIJJKKLLMMNNOOPPQRSVY^dkrz€…ˆŠ‹Šˆ…{yutrr€qstw{ƒˆ‹‹†}rjghhjf:ˆƒ  Šý‚ÿ#Œ‡}rdYNGB@@AACCDDEEFFGGHHIIJJKKLLMMNOPSW^enw…‰ŠŠ‡‚|vpkfc`^€\]\]]^^__``abcdhltˆŒ‡zlhiji? „… 3¾¸a5¶‚ÿE`TJB?=>>@@AABBCCDDEEFFGGHHIIJJKKLKLLOSZblw†Š‹ˆƒ|tle`\YWXWXXYZ[[\\]]^^_``aaccdcdeis‚Œ‰ylfcc=ˆ MèÿþìÅ’\'9Ùÿ;;<=>>??@@AABBCCDDEEFFGGHHIJMS[ep{„‰‹ˆ‚zpg`[VTSTTUVWWXXYYZ[[]^`bdfijklljihf€deegqƒ‹jVdnj; ‹eòÿýåºÑþ€ÿ<<==€>??@€AB€CD€EFGKPYdq}†Š‰„|sh_XTQPQQRSST€UV WY[^bflqw|€„‡‰€‹€Œ‹‹‰†yqjfefidW{ŽŽ†XŒpöˆÿ;<<==>>??@@AABBCCDHMVbo{…Šˆ‚ymbYSONMNOPPQ€RSRSSUVY^djrz†ŠŒŒ‹‡ƒ~zwtqpsuz…‹‰}phcPq€e‹û‡ÿ[;<<==>>??@@AABABEKS`mz„‰ˆvj_VOLJKKMMNNOOPOPPRTY^emu}„‰ŒŒˆ‚|vqlgd`_]^]^^__``aaccfkt€‹€eR„ƒV‹˜‡ÿ;;<<==>>??@@AACUkxƒ‰ˆwj]SLIHHIJKKLLMLMMOQV\dmw†‹Š…~wphc^[€YZZ\\]]^^__``aabbcc€dfl{‹qW‰„ˆ/ˆ·†ÿ5;<<==>>??@@AABPlwj\RJGEFFHHIIJIJJLNSYbku~†‹Œˆ‚{rjc^YW€V!WXYYZZ[[\\]]^^__``aabbccddeeffmeVˆ„‘a …… Ã…ÿ[;<<==>>??@@AABACDCCDEFFGFGGIKPW_it}…‹Œˆypg_ZUSRSSTUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffg_Q€ƒ‚ˆ7Ö„ÿ;<<==>>??@@AABBCDDEHMT]gr|…ŠŒ‹‡wmd\VRPOPP€RSTTUU€VWXXYYZZ€[\]]^^€_`aabbcc€deffgcOo„‰A€‹Eéƒÿ;€<==>>?€@ AABBEJQ[fq|„ŠŒŠ…~ukaYSOMLLMNOOPPQ€RSSTTU€VW€X YYZZ[[\\]]^^__``aabbccddeeffgVXˆƒ‰`"]ï‚ÿ;;<<==>>??@@AAFdzƒ‰‹Š„|rh^VOL€I>??@@AABRqpe[SLH€FDGHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgg[OqŽ€p`i"…"M-€ £þ€ÿ;;<<==>>??@@AABACCDEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeff€g WOh„ŽyWgoL… µëΩ}K Ä€ÿh;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghfZNTbh`Q]mmh…(€ÿ$øÜ°xAPäÿÿ;;<<==>>??@@AABBCCDDEEFFGGHH€IJKKLLMMNNOOPPQQ€RSTTUU€VWXXYYZZ[[\\]]^^€_`aabbccddeeffgg€h bXQPT`kmmoD†'΃ÿõØêÿÿ;;<<€=>>?€@AABBCDDEE€FGHH€IJJKKLMMNN€OPQQ€RSSTTU€VW€XY€Z[€\]]^^__`€abbccd€effgghhiihhjkllmna†A܇ÿ:;;<€=b>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmn/‡BÞ†ÿi:;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmpQˆ[ï…ÿj:;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmngˆeð„ÿj:;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmno1ˆ€úƒÿj:;;<<==>>??@@AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnpL‰ Œû‚ÿ:;;<<€=>??@@AA€BCDDEEF€G HHIHIIJJLLMMNOPQQRR€STUUVVWW€XY€Z[€\]€^_``aa€bccd€effggh€i jjkkllmnoa‰«þÿ::;;<€=>??@@ƒA@@>=<;97642101012469=AEJNP€QRRSSTTUUVVWWXXYYZZ[[\\]]^^__``a€bccddeeffgghhiijjkkllmmnl#…€¿ÿ‚:9987654310.-,*)(''&%‡$ %%&(+08AIOR€S7TTUUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmno7… 3×€ÿ,+*)(('&&Ÿ%$$%)0=IR€T5UUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnpK„ ‚¥vBKçÿÿ¬%$%)4EQ€U4VVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmno[ „ ‘ööجvBŠøÿ¯%:$&2ETUVVWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnoe…då€ÿôà÷ÿ±%$'7MVVWWXXYYZZ[[\\]]€^_``aa€bcddee€fgghiijj€klmmnnk†?ʃÿ³% $-FVVWWXYY€Z[[\\]€^__``a€bccdde€fgghhiijjkkllmmnn+ˆ"¦ûÿµ%4(@UWWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnp6‰ð€ÿ¶%3'@VWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnp=Šbãÿÿ·%1'DWXXYYZZ[[\\]]^^__``aabbccddeeffgghhiijjkkllmmnpCAØÿ£%Œ&‚'&.OWWXXYXYYZZ[[\\]]^^__` aabbccddeef gghhiijlE‚ˆ<Ç%ÿÿøýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáÿ ÇÆÉêìèäÛæòëôúùïÿ€ÆËÊÈÅÀÆÇ¼ÉÉÅÏØÛèî÷üèÿ€ËƒÊÉÊÉÈÈÆÆÁ€ÃÈÓàëõýãÿÊƒÉƒÈƒÇ ÆÅÃÁÁÂÈ×çôýßÿ‚ȃDŽƃÅÄÃÀ¿ÂÊÕêùÜÿǃƃńăÃÁ½½ÂÎç÷ÙÿƃŃăÄ ÁÂÁÀ½½ÂÎâøÖÿłĄÂ…ÁƒÀ¿¼¸ÃÓèûÓÿ€Ä‚ÃÁƒÀ…¿¾½º¸ÁàõÑÿ€Ã‚‚Á‚À„¿„¾†½»¸¼ÎðþÎÿ€Â‚Á‚À‚¿ƒ¾„½…¼»º¶¼ÆäüÌÿ€ÁÀƒ¿‚¾‚½„¼…»„º¹µ²ÅèýÊÿÀÀ¿‚¾ƒ½‚¼ƒ»„º…¹‚¸µ¶ÉæüÈÿ¿¿¾‚½‚¼ƒ»‚º„¹„¸†·´±ÁîÇÿ¾¾½‚¼‚»‚ºƒ¹ƒ¸„·†¶€µ³¶ÉíÅÿ½½‚¼»‚º‚¹‚¸ƒ·ƒ¶…µ…´¯µÔ÷Ãÿ¼¼»º‚¹‚¸‚·ƒ¶ƒµ„´…³²²³²¯¹áüÁÿ»»º‚¹¸·ƒ¶‚µ‚´„³†²ƒ±°¬ÂìÀÿ€º¹¸·‚¶‚µ‚´‚³„²„±‡°«¯Ôú¾ÿ€¹¸·¶‚µ´ƒ³‚²‚±„°†¯®­¨½î½ÿ€¸·¶µ´³‚²‚±ƒ°ƒ¯…®†­ª²Ýü»ÿ·¶µ€´³‚²±‚°ƒ¯‚®…­ˆ¬ª©Åôºÿ·€¶µ´³²±°‚¯‚®ƒ­„¬…«ƒª§¶æ¹ÿ¶¶€µ´³²€±°‚¯®‚­‚¬ƒ«„ª‡©§ªÕû·ÿµµ€´³²€±°¯®­‚¬‚«‚ªƒ©ˆ¨§§¨§¥Áñ¶ÿ€´³€²€±°¯€®­‚¬«‚ª‚©ƒ¨†§„¦¡´ëµÿ´€³²€±€°¯€®­¬«ª©ƒ¨ƒ§ƒ¦ˆ¥¢§ãþ”ÿþ÷šÿ³³€²€±€°¯€®­¬€«ª©‚¨§ƒ¦ƒ¥ˆ¤£¤£¢Õ”ÿêŸ÷™ÿ€²€±€°¯€®€­¬€«ª€©¨§¦‚¥ƒ¤„£†¢¡¥Æù‘ÿýªbÕ™ÿ²€±°€¯€®€­€¬€«ª€©¨§€¦¥‚¤‚£„¢ˆ¡ šÁûÿáiWú˜ÿ€±€°€¯€®€­€¬€«ª€©€¨§€¦¥¤£‚¢ƒ¡‹ Ç÷Žÿú›YZcÚ˜ÿ±€°€¯€®€­€¬€«€ª€©¨€§€¦€¥¤£¢¡‚ …Ÿ†žœ­ðÿÒa[[Y¡ý—ÿ€°€¯€®€­€¬€«€ª€©€¨€§€¦€¥¤€£€¢¡ ‚Ÿƒž‰™«ð‹ÿú‘X[[Zhß—ÿ°°€¯€®€­€¬««€ª€©€¨€§€¦€¥¤££¢€¡ €Ÿ‚ž‚‹œ˜ªïŠÿÆ`[Xžý–ÿ°€¯€®€­€¬««€ª€©€¨€§€¦€¥€¤€£€¢€¡€ Ÿ€ž‚œ„›ƒš››–¨îˆÿó~Y[ZiÝ–ÿ€¯€®€­€¬««€ª€©€¨€§¦¦€¥€¤€£€¢€¡€ €Ÿ€ž€œ›‚šˆ™š•¦î‡ÿÂ\ƒ[Yù•ÿ€¯®®€­€¬€«€ª©©€¨€§€¦€¥€¤££€¢€¡€ €Ÿ€žœ€›€š™Š˜™”´ú…ÿó€Y„[aÑ•ÿ¯¯€®€­€¬««€ª€©€¨€§¦¦€¥€¤££€¢€¡€ €Ÿ€ž€œ€›€š€™˜—–—˜˜—»÷„ÿ³†[Y‹ö”ÿ¯¯€®€­€¬««€ª€©€¨§§€¦€¥€¤££€¢€¡€ ŸŸ€ž€€œ››€š€™€˜€—€–•€–€—˜“ºý‚ÿêpY†[\¾”ÿ¯¯€®€­€¬««€ª€©€¨§§€¦€¥€¤££€¢€¡€ ŸŸ€ž€€œ››€š€™€˜——€–ƒ•––€—˜˜šÏüÿ¯Y‡[Zqä“ÿ¯¯€®€­€¬««€ª€©€¨€§¦¦€¥€¤££€¢€¡€ €Ÿ€ž€œ€›€š€™˜—–—‚˜–Ó€ÿêrZˆ[Xœû’ÿ€¯®®€­€¬€«€ª©©€¨€§€¦€¥€¤££€¢€¡€ €Ÿ€žœ€›€š™‹˜‚™žáÿÿ°Z‰[ZaÉ’ÿ€¯€®€­€¬««€ª€©€¨€§¦¦€¥€¤€£€¢€¡€ €Ÿ€ž€œ›š‹™š›™©ìânZŠ[Y~ï‘ÿ°€¯€®€­€¬««€ª€©€¨€§€¦€¥€¤€£€¢€¡€ Ÿ€žœƒ›‡šƒ›œœ™²”XŒ[ZŸúÿ°°€¯€®€­€¬««€ª€©€¨€§€¦€¥¤££¢€¡ €Ÿ‚ž“œž’`[Z_Æÿ€°€¯€®€­€¬€«€ª©©€¨€§¦€¥¤€£€¢¡ Ÿ„žž{[Yuçÿ±€°€¯€®€­€¬€«ª©ª«­®¯°°¯­¬©§¦¥¤€£¢‚¡‚ ƒŸžŸ‹žŸž€Ÿ “cŽ[ZZW’÷Žÿ€±€°€¯€®€­ ¬«­±·¿ÅËÎÑÒ€Ó ÒÐÍÇÁ»´­§¥„¤£‚¢‚¡‰ Ÿ‡ ŸwZ‹[ZZYYXXY³þÿ²€±°€¯ ®®­­²¼ÆÐÔÕ‚ÖרÙ×ÓÌ·­¦…¤‚£„¢”¡¢`Š[ ZZYYXXWWUbÐÿ€²€±€°¯´ÂÎÔ‚Õւ׀؀ÙÚÛÙÔÉ»¯§‚¥ƒ¤„£’¢£ rZˆ[ ZZYYXXWWVVURtçŒÿ³³€²€±€°µÂÏÔ‚ÕÖר€Ù€Ú ÛÛÖË»­¦¥¦¦ƒ¥†¤£¤¤¥‹]†[ZZYYXX€WVVUUTTQŽ÷‹ÿ´€³€²±±µÂÎÓ‚Ô‚ÕÖ×ØÙ€ÚÛÛÜÛÔÅ´©†¦–¥žkZ„[ZZYYXXWWVVUUTTSSRRS¯þŠÿ€´€³²¶Â΀ӂÔÕ‚ÖרÙÚ€ÛÝÝÙ̹«‡§’¦§‚„[ZZYYXXWWVVUUTTSSRRQQO]ÏŠÿµµ€´·Á΂ӂԂÕÖרÙÚ€Û€ÜÝÚϼ¬†¨§¨™d[ZZYYXX€WVVUUTTSSRRQQPPOLrê‰ÿ¶µµ¸ÁÍÒƒÓ‚Ô‚Õւר€Ù‚Ú€ÛÜÝÛм­‰©‰¨©©§xZ[[ZZYYXXWWVVUU€TS€R QQPPOONMK‘øˆÿ¶¹ÁÌÒÒ„Ó‚Ô‚ÕւרÙÚÛ‚ÜÝÛꬔª«^ZZYY€XWWVVUUTTSSRRQQPPOONNMMLLN±þ‡ÿÃÌÒƒÓƒÔ‚ÕÖׂØÙÚÛ„ÜÝÚ˶¬«¬«¬¢k€YXXWW€VUUTTSSRRQQPPOONNMMLLKKIYÕ‡ÿ‚Ò„ÓƒÔՂւרÙÚ‚Û…ÜÝØÅ±¬€­‹¬­¬YYXXWWVVUUTT€SRRQQPPOONNMMLLKKJJIGtí†ÿÒ„Ó‚ÔƒÕ‚Ö‚×Ø‚ÙÚÛˆÜÒ¼¯®¯–^XXWWVVUUTTSSRRQQPPOO€NM€LJ‚IHGF•ú…ÿÒÒ…ÓƒÔÕÔÓÓÑÐÐÏÐÑÑÒÓÕÖרÙÚ€ÙÚÛˆÜÝÚȳŒ¯ ¨mVWVVUUTT€SRRQQPPOONNMMLLKKJ^dQHEEFFELÀ…ÿÒ…ÓƒÔ ÓÑÌÇÿ¼»¹¸¸·¸¹»½ÀÃÇÌÑÔ×ÚÛÚÚ‚ÛŠÜÑ»‹° ƒWVVUTUTSSRRQQ€POONNMMLLKKJJHpÙ×¹˜rVFB@cå„ÿ†ÓÔÐÈÁ»¹¸ƒ·‚¶€µ´ µ¶¹½ÄÊÒ×ÚÜ€Û‹Ü×Á²„±³˜]UTT[qrTRRQQPPOONN€MLLKKJJIIHFùÿÿ÷ຆ_E‡÷ƒÿ„Ó€ÔÒÌýº‚¹‚¸ƒ·„¶€µ´µ·»ÃÍÕÚÜÚÈ´…³´¨iSUdŸ©lPQQPPOONNMMLL€KJII€HGFGŸýÿýìÆœßƒÿ‚ÓÔÔÓÎÇÀ¼»‚ºƒ¹ƒ¸„·¶µµ¶ºÂÎØŠÜÝÝÜʶ„´ ²{Uh‹©µ¶†RPPOO€NMMLLKKJJIIHHGGFFEDNµþ„ÿýƒÿ‚ÓÐÊþ½ƒ¼ƒ»‚º„¹„¸ƒ·¶¶·½Ê×ÜÜÝÝÞÞÝÜÙÖÕÓÒÒÓ¿±´µ¶“k­¶¶·¢[€ONN€ML€KJJIIHHGGFFEEDDAQÌ‹ÿÓÓÒÍÇÁ‚¾‚½ƒ¼ƒ»ƒº…¹†¸*¹¿ÏÖÏÅ·©ž”Œ…‚€€‚†Œ“¦©—­¹¸··²rNONNMMLLKK€JI€H GGFFEEDDCCB@ZØŠÿÏÊÄÁÀÀ„¿‚¾‚½„¼ƒ»‡º?»»º·±§™‹ƒxpkihijkllmnnoopqqsv|ˆ–¤±¸¹ŒPNNMMLLKKJJIIHHGGFFEEDDCCBB€A>må‰ÿÄÁ‚À‚¿ƒ¾„½‡¼½¼»·¯¥˜Š}rjffeggijjkklmmnooppqrr€s ttx“š^LMLLKK€JI€HGGFFEEDDCCBBAA@@??;òˆÿ€Ã‚‚Á‚À„¿„¾½‚¾6¼¶­¡“„wmfcbcdefgghhijjkklmmnooppqrrsstuuvuvwm_PKKJJIIHH€GF€EDDCCBBAA@@??>>=<‘û‡ÿ€Ä‚ƒÁƒÀ€¿ÀB¿¼µªœ~qhb__`abccdeefgghhijjkklmmnnoppqqrsstuuvvwxyyq_NIIHHGGFFEEDD€CBBAA@@??>>==<;B§þ†ÿłăÃÂÁÁÂUÀ»³¦—‡wkb]\[]^_``abbccdeeffghhiijkklmmnnoppqqrrsttuvvwwxyzzoXIGGFFEEDDCCBBAA@@??>>==<<€;8GÁ†ÿƃŃÄIÃÃÄÄÅÄÁº°¢‘€qe]YXXZ[\]]^^_``aabccddeffghhiijkkllmmnoopqqrrsttuuvwwxxyz{yfL€ED€CBBAA@@??>>==<<;;::996R×…ÿ‚Ç‚ÆÅÅ€Æ*ÇÅÁ¹­‹yj_XUTVWXYYZ[[\\]^^__`aabccddeffgghh€i jllmnpqrstuvuvuvwwxxyzz{|qTDCC€BA€@??>>==<<;;::998874bè„ÿ‚È+ÇÇÈÈÉÉÆÀ·¨–ƒrcYSQQSSUVVWWXYYZZ[\\]^^__`aabbcdeghkmptw{~„†ˆ‰ŠŠƒ‹Љ‡…‚~|yyzz{{}x[D€A@@€?>€=<<;;::987664{õƒÿ€Ê'ËËÊÇ¿³£{j]SOMNPQRRSTTUVVWWXYYZZ[\\]]^__€`abdgkptz€„ˆŠ‹Œ‹Šˆ†„‚€~}}€| }~ƒ†ˆ‹Š…€€{!|}{aC@@??>>==<<;;::9987BL;423445žý‚ÿ#ËÆ½¯œˆtcVNKJKMNOOPQQRRSTTUVVWWXYYZZ[\]_aeiov}ƒˆ‹Œ‹‰†‚}yvrpom€npoqqrsstuuwx|€†‹‹„}||~~dC>>€=<<;;::998875ZÉÅ¡~Z=1.>‚ÿ~l[OIGGIIKLLMMNOOPQQRRSTTUUVWWXX€Y=Z\`elt|ƒˆ‹ŒŠ†{upljhghghijkklmmnnoppqqrrsttuvvwwx{€ˆŽŒ„~xst_@=€<;;::998877665nëÿþïΤyMZßÿ0CDFFHHIJJKLLMMNOOPPQRRSSTUUVUVXZ_fnv†ŠŒŠ…wqlged€ceffghhiijjkklmnoqrsuwxxyzyyx€wxyyz€‰ŒnZeooU=;;::99€8 77665541ôÿýéÅ×ÿ4EFGGHHIJJKKLMMNNOPPQQRSRSTW\clw€ˆ‹‹†€yqjea_^_`abccddefgijmosw{‚…ˆŠ‹Œ„ŒŠ‡ƒ~{yzz|jV{ŽŽ†fA€988776655443323ˆ÷ˆÿEFFGHHIIJKKLLMNN€OPPSY`ju‡ŠŠ…}tkd_\\[\^^__`aa€bcdfhkpu{€…‰ŒŽŒŠ‡„€~|}~€‚†ŠŽŒ…{tSq€o?88776655443322104£ü‡ÿ EFFGHHIIJKKLL€MPU]gr~†Š‰ƒ{qh`[YXXYZ[\\]^_acfjpv|‚‡‹ŽŠ†‚~zwtrp€o€pqrsstuuvw{€‡ˆoS„ƒf8€6554433221100.8¨þ†ÿEFFGHHIIJKKLLN^p|…Љ„zpf]X€UVWXYY€Z[[]_chnu|ƒ‰ŒŽ‹ˆƒ~xsplk€jklmmnnoppqqrsstuuvvwwx}„rW‰„ˆL55€43€2 1100//.,?Æÿ4EFFGGHIIJJKLLMYqzpe\USQRSTUUVWVWWY\_eks{‚ˆŒŽŠ…€ytnkhf!hhiijkklmmnnoppqqrssttuvvwwxyy~lUˆ„l6433221100//..€-*CË…ÿEEFGGHHIJJKLLMLNPNOPQRR€STUX[aipy‡ŒŒ‰„~wpkfca€b(ddeffghhiijkkllmnnoopqqrssttuvvwwxyy{lQ€ƒ€?€21100//..--,,++(VÛ„ÿEEFGGHHIJJKKLMMNN€OGPQTX^fow€‡‹Œˆƒ|tmgb_^]^_`aabccddeffghhiijkkllmnnoopqqrrsttuvvwwxyyztRo„‰U41100//..--,,++**)%`ìƒÿ"EEFFGHHIIJKKLMMNPU[clu†‹‹‡yrjd_[€Z6[\]^^__`aabccddeffghhiijjkllmmnoopqqrrsttuuvwwxxyzz_Wˆƒ‰jH€/..€- ,,++**))(''sñ‚ÿ\EEFFGHHIIJKKLLPk}…ŠŒŠ†wog`[XVVWWYYZZ[\\]^^__`aabbcddeefgghhijjkllmmnooppqrrsstuuvvwxxyz{qPiŽ‚ƒki2..--,,++**(&&€'€&úÿ^DEFFGHHIIJKKLLM[vulc\WTRRSSUVVWWXYYZZ[\\]]^__``abbccdeefgghhijjkklmmnnoppqqrsstuuvvwxxyyz{eOqŽ€pkF,-,,++**)'AfK5(##$%/°þ€ÿgDEFFGHHIIJJKLLMMNONOPQRRSTTUUVWWXXYZZ[[\]]^__``abbccdeeffghhiijkklmmnnoppqqrsstuuvvwxxyyz{y`Oh„ŽyYw„g/€+**))(':¿íÕ´Žd>*!:Ì€ÿmDEEFGGHHIJJKLLMMNOOPPQRRSSTUUVVWXXYZZ[[\]]^^_``aabccdeeffghhiijkklmmnnoppqqrsstuuvvwxxyyzz{zdOSbh_Ri‚~C)*))((€'$EË€ÿvøáºŠZgçÿÿDEEFGGHHIJJKKLMMNNOPPQRRSSTUUVVWXXYZZ[[\]]^^_``aabccddeffghhiijkklmmnnoopqqrrsttuvvwwxyyzz{||r`VSZn‚„a*)((''&#EÔƒÿmöÝíÿÿDEEFGGHHIJJKKLMMNNOPPQRRSSTUUVVWXXYZZ[[\]]^^__`aabccddeffghhiijjkllmmnoopqqrrsttuuvwwxxyzz{{|~}{{}€‚ƒx5€'„&#[á‡ÿiDEEFGGHHIJJKKLMMNNOPPQQRSSTUUVVWXXYYZZ[\\]^^__`aabccddeefgghhijjkllmmnooppqrrsstuuvvwxxyzz{{|}}~€€‚ƒN%‡&#\â†ÿiDDEFFGHHIIJKKLLMNNOOPQQRRSTTUVVWWXYYZZ[\\]]^__``abbccdeefgghhijjkklmmnnoppqrrsstuuvvwxxyzz{{|}}~~€€‚„j*ˆ&#qñ…ÿjDDEFFGHHIIJJKLLMMNOOPQQRRSTTUUVWWXXYZZ[[\]]^__``abbccdeefgghhijjkklmmnnoppqrrsstuuvvwxxyzz{{|}}~~€‚ƒ|9%ˆ&'zñ„ÿjDDEEFGGHHIJJKLLMMNOOPPQRRSTTUUVWWXXYZZ[[\]]^__``abbccdeefgghhijjkklmmnnoppqqrsstuuvvwxxyyzz{||}~~€‚ƒ„N%Š&‘ûƒÿjDDEEFGGHHIJJKLLMMNOOPPQRRSTTUUVWWXXYZZ[[\]]^__``abbccdeeffghhiijkklmmnnoppqqrssttuvvwwxyyzz{||}~~€€‚‚…f(‰&%.›û‚ÿDDEEFGGHHIJJKLLMMNOOPPRRSTT‚UVWWXZZ\\€]@^^__`aabccddeffghhiijjkllmmnoopqqrrsttuuvwwxxyzz{{|}}~€€‚‚„x3%‰&%1·þÿ CDEEFGGHIJJ€KL KJJHGDCA><:754€5 79;@EKPW\^€`;aabccddeefgghhijjkllmmnooppqrrsttuuvwwxxyzz{{|}}~€€‚‚ƒC$†&%€&$;Çÿ‚CBAA?><:86420.,+)('&€%‰$ %&(-4=JU]a€b7cddeefgghhijjkllmmnooppqrrsttuuvwwxxyzz{{|}}~€€‚‚ƒ„S%…&,5'##%#OÛ€ÿ /.-+*)('&&€%‚$•%€$>&*4EU`ccddeefgghhijjkllmmnooppqrrsstuuvvwxxyzz{{|}}~~€€‚ƒ…d(„&%6’±‰\;) dêÿÿ$$ª%=$%*9O`ddeefgghhijjkklmmnnoppqqrsstuuvvwxxyyzz{||}~~€‚ƒ„s.%„& %8 ÷÷Ý·‰[™øÿ¯%:$'6Pbeeffghhiijkklmmnnoppqqrssttuvvwwxyyzz{||}~~€€‚‚„|6%…&%)yè€ÿöãøÿ±%$(=Z€f1ghhiijkkllmnnoopqqrrsttuvvwwxyyzz{||}}~€€‚‚ƒ?%†&%%YЃÿ³%6$/Pefgghiijjkllmmnoopqqrrsttuuvwwxyyzz{||}}~€€‚‚ƒƒI$ˆ&#@²üÿ´%5$)Iegghiijjkllmmnoopqqrrsttuuvwwxxyzz{{|}}~€€‚‚ƒ„S%‰&$/ò€ÿµ%4$'Ifghhijjkllmmnooppqrrsstuuvvwxxyzz{{|}}~~€€‚ƒ…Y%Š&%&xæÿÿ¶%2$(Mghhijjkklmmnnoppqqrsstuuvvwxxyyz{{||}~~€‚ƒ…^&$[Ýÿ¡%ˆ&‡'('1]gfgghiijkkllmnnonoppqqrss€t uuvvwxxyzz€{ ||}}€^$#$$€%‡&$WÍ%ÿÿøýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáÿÔÓÕö÷òíâìöîöûùþîÿ€ìñïíêäèèÜçäÜáæåîòøüèÿ„ñ‚ò ññïîèéäàÞâéðöüãÿŠñ€ð€ñ ðïìêåàßåíöýßÿ‚ñð ñðïëæãââïùþÛÿ“ð‚ï ððîéãßàîøþØÿŒðïðïëçâáéùÖÿ†ð—ïîëáâäíûÓÿðð”ï‰îïîéáÛêöÑÿï“îïìåÞÞôþÎÿ‰ï•îƒíîíçäÜêüÌÿ„ï’îíéÝÝïýÊÿïî™íêããîûÈÿ‹î•íˆìíêßÚóþÆÿ‡î’í‘ìíéâßñÅÿ‚îí›ìæÞäùÃÿí“ìëäÜêüÁÿŠí‘ì•ëêÞÜðÀÿ†íì˜ëêëåÙâú¾ÿƒíì“ëŽêÞÙò½ÿííŒìë–êëæÞêü»ÿŠìë•ê†éààöºÿ‡ìë‘êéäÝî¹ÿ„ìŒëê—éçÝæû·ÿì‹ëê”éˆèàÝó¶ÿììŠëŒêéèéáÚðµÿŠë‹êé˜èæÖíý”ÿþ÷šÿ‡ë‹êŒé“èˆçØæ”ÿä„õ™ÿ…ëŠê‹éŽè’çáÜù‘ÿýŒ#Ç™ÿƒë‰ê‹éŒè˜çÚÛûÿØ.iù˜ÿëŠê‰é‹è‘çˆæçàæøŽÿùx&Иÿ€ëˆê‰é‹èŒç’æâÑòÿÄ"~ý—ÿëëˆê‰é‰è‹ç—æàÒò‹ÿùf-Ö—ÿ‰êˆé‰èŠçŽæ‰åæßÑòŠÿµ€|ý–ÿˆêˆé‰è‰ç‹æåßÐñˆÿñO-Ò–ÿ‡êˆéˆè‰ç‰æ”åæßÎð‡ÿ­ƒhø•ÿ†êˆéˆè‰çˆæ‹å‰äåÞÚû…ÿïNƒ!•ÿ†êˆéˆèˆçˆæ‰åäåàÜø„ÿ›…_ô”ÿ†êˆéˆè‡çˆæˆå‘äÚÖý‚ÿå<†©”ÿ†êˆéˆè‡çˆæˆå’äßæüÿ”ˆ:Ý“ÿ†êˆéˆèˆçˆæ‰åäåØä€ÿä;ˆxú’ÿ†êˆéˆè‰çˆæ‹å‰äƒåÙëÿÿ’Š!¹’ÿ‡êˆéˆè‰ç‰æ›åäÚòÚ4ŠLê‘ÿˆêˆé‰è‰ç‹æ˜åáÚuŒ~úÿ‰êˆé‰èŠçŽæåæèÄ,Œ´ÿëëˆê‰é‰è‹ç¢æzŽ@àÿ€ëˆê†éèèç€æ€ç…èŒçœæè¿,köŽÿëŠêéèæäâáàß‚Þßßáâãåæƒè‘ç“æçãi‹‚šþÿƒë†êéåâ߃ވÝÞàâäæƒè£çê²#‰…(Ãÿ…ë‚êèäà‡ÞŠÝÜÝàãæ…èçèßWˆ…€DâŒÿ‡ëêèäà߈ފÝÜÝàãçˆè—çê †…ƒkö‹ÿ†ëéåá߈ދ݂ÜÞáåŸèéÔB„……˜þŠÿìì‚ëêåáƒßŠÞ‰Ý„ÜÝàäçœè邃……'Êÿ‚ìêæá‡ßˆÞŠÝ†Üßäè€é–èêÁ-€†…„Fä‰ÿ€ìëçâààˆßˆÞ‰ÝˆÜßäè—éäd†……qöˆÿìëçâƒà‡ß‡ÞŠÝ‰Üßå•é쥆…†þ‡ÿçã†à†ßˆÞ‰Ý‹Üàæ’éëÑ?„………(ˇÿáá‡à†ß‰ÞˆÝ‹ÜÝãèêèu‚†…† Mé†ÿá…à†ß‰ÞˆÝÜßæŽêí¯"€†…ƒ‚zú…ÿ‚á…à…ßààƒáààßßÞˆÝÜÝâé‹êëØH……† /6 ²…ÿ‚á…à ßßàáãåçèêê…ë êéèçåäâàßÞ‚ÝŽÜàçŠëꀅ† HÑͨ}L' :à„ÿƒá„àâæéëìíìëêèæãàÞÝÜÞåˆëî¯#€#VZ†…‚ røÿÿõÚ©h5l÷ƒÿƒáàáäèì†í‘ìëéæâߎÜÝãê…ë íÓA7x¿ÔKƒ†„‡ýÿý躇ڃÿ„áâäèë‘íìêçâÞŒÜÝãë„ì çk@Ôí…† £þ„ÿýƒÿ‚áãæëí‚î•í‰ìéäÞÜÜÝÝÞÝÝÜÙ×ÖÕÓÔÕßçêìí€î G•Ú€îÁ+€…†‚ $¿‹ÿâáâåéí‹î™í&ìííîëãÙÑɽ±¨ ™”‘ŽŽ‘”𢫵ÄÓÓ¨ÖðîìíâZ……† 1ÑŠÿåéíï’îŽí îïïîêâÔÁ«•‰‚~€|}€~€€€‚„ˆ¢¸Îâìï‘…†… Jà‰ÿîˆï•î€í!îîïïíèÞп¬šŒ€zxzz{||}}~~€€‚‚ƒƒ‚„‰—²¶4‚…†„ dïˆÿïîïððïìæÚʸ¤“…|wvvxyzz€{ ||}}~~€€‚‚€ƒ „„……†…†…jB…†…€ zû‡ÿðð”ïîïððïëâÕİŒwtstuwwxx€yzz{{||}}~~€€‚‚€ƒ „„……††‡‡Š‡rDƒ…†  •þ†ÿ†ð‹ïððññïéÞϼ¨”…ysqqrstuuvvwwxx€y zz{{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆˆŠˆm6†……  µ†ÿŒð€ïð€ñíæÙɵ ~uonnpprrssttuuvv€w xxyyzz{{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆˆ‰‰‹…X„…†  .Ð…ÿŠð ñòòñìãÔÁ¬—†xp€lmooppqqrrssttuu€vwwxxyyzz{{||}}~~€‚‚„……†…€† ‡‡ˆˆ‰‰‹‹r1†… ƒ  Dä„ÿ‚ñððñ€ò ðéÞκ¤~sliijklmmnnooppqqrrssttuu€vwwxxyyzz{|~€‚„†‡ˆŠ‹ŒŒ‡Œ‹ŠŠ€ˆ‰‰ŠŠB†…   cóƒÿññò€óïçÚDZ›‡xmhfghijkk€l mmnnooppqq€rssttuuvvwxz|~„‡Š‹ŽŒ‹Š‰ˆ„‡ˆ‰‰‹‹€Ž Œ‹‰ŠŠ‹ŒˆP … '  ý‚ÿ òíãÓ¿©’€qh€dfg€hiijjkkllmmnnooppqq€r sstuxz~…‰‹€ŒŠˆ†ƒ‚€‚€€‚‚€ƒ „„……†‡ˆŠŒŽŽŒ€‹Œ‹X … ƒ 9¿ºe; ¸‚ÿžŠwkdaabceeffgg€h iijjkkllmmnnoo€p qrtw{€…ˆ‹ŒŠ‡„}{{z{{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆ‰‹ŽŒ…R ƒ … RèÿþíÇ•`,>Úÿ ^_`abccddeeff€g hhiijjkkllmmnmnpsw{†ŠŒŒŠ†‚~|yxw€x-yyzz{{||}}~~€€‚‚„„††‡†‡†‡†‡‡ˆˆ‰‰‹Žq\fpqC € … jóÿýæ¼Òþ€ÿ`aabbccdd€e ffgghhiijj€klnpu{†‹ŒŠ†‚~zwvtuu€vwwxxyyzz{{|}~€‚„†ˆ‰‹Œ†ŽŒ‹Š‰ˆ‰‰ŠoV{ŽŽ†Z „ …  töˆÿ`aabbccdd€effgghhihjknsy†ŠŒŒ‰…zvt€rssttuu€v wwxxyz}‚…ˆŠŒŽ‹Š‰ˆˆ‡ˆ‰‰‹ŒŽŽŒŠŠ‚Uq€g †  ”ü‡ÿ`aabb€cddeeffggikqw~„‰Œ‹ˆƒ}xtpooppqq€rssttuuwx{~‚…ˆ‹€Ž‹ˆ‡…ƒ‚€€‚‚ƒƒ€„ ……††ˆŠŒŽŽwS„ƒY … ‚  œ‡ÿ`aabb€cddeefgp|ƒ‰Œ‹ˆƒ|vqnlmlnnoopp€q$rrtvy|…ˆ‹ŽŽ‹‰†ƒ}}|}}~~€€‚‚ƒƒ€„ ……††‡‡ˆ‰ŒrW‰„ˆ4 „ …  ¹†ÿ`€abbccddeeffn}‚|upl€j.kllmmnnoopqtwzƒˆ‹ŽŽŒŠ‡ƒ€~|zyyzz{{||}}~~€€€‚ƒƒ„„……††‡‡ˆˆ‰‹qUˆ„‘c‚ … € &Ä…ÿ ``aabbccddeeff€ghgiijjkmnqty}‚‡ŠŽŽŒ‰…‚~{xwvww€xyyzz{{||}}~~€€€‚ƒƒ„„……††‡‡ˆˆ‰ŠwQ€ƒ# † ƒ <ׄÿ ``aabbccddee€fgghjknqv{†ŠŽ‹ˆ„€{xvtsttuuvv€wxxyyzz{{||}}~~€€ ‚‚ƒƒ„„……††‡‡€ˆ‰‚To„‰I… … Iéƒÿ ``aabbccdd€e ffghkotz€…‰ŒŠ‡‚~yvsqpqqrrssttuu€v wwxxyyzz{{||}}€~ €€‚‚ƒƒ„„……€†‡€ˆ‰‰dWˆƒ‰m1 † ‚aï‚ÿ``aabb€cddeefhy„‰ŒŒŠ†{wspnmnmooppqqrr€st€u vvwwxxyyzz{{€|}€~ €€‚‚ƒƒ€„ ……††‡‡ˆˆ‰Š}RiŽ‚‚rg … € €úÿ``aabb€cddeeffoytpmkkjkllmmnnooppqqrr€st€u vvwwxxyyzz€{||}}~~€€‚‚ƒƒ€„……††‡‡ˆˆ‰‰ŠmOqŽ€psŠ1„ 'Q2 ¦þ€ÿ``aa€bccddeeffgghghiij€k llmmnnoopp€qrrssttuuvvwwxxyyzz€{ ||}}~~€€€‚ƒƒ„„……††‡‡ˆˆ‰‰Š‡fOh„Žy[ƒ’e‚ € ·ëÏ«O$  Æ€ÿ€` aabbccddeeff€ghhiijjkkllmmnnoopp€q rrssttuuvvwwxx€yzz{{||}}~~€€€‚ƒƒ„„……††‡‡ˆˆ‰‰ŠŠ‡lQSah_Sp‰. „,Ä€ÿøÝ±{DTäÿÿ_``aabbccddee€fgghhiijjkkllmmnn€o ppqqrrssttuuvv€wxxyyzz{{||}}~~€€ ‚‚ƒƒ„„……††‡‡€ˆ‰‰ŠŠ‹}fXV]w’\ †,σÿõÙëÿÿ_``aabbccddee€f gghhiijjkkll€mnnooppqqrrssttuuvv€w xxyyzz{{||}}~~€ €€‚‚ƒƒ„„……€†‡€ˆ‰‰ŠŠ‹ŒŒˆˆ‹Ž‘€†E݇ÿ_``aabbcc€deeffgghhiijjkkll€m nnooppqqrrsstt€uvvwwxxyyzz{{||}}~~€ €€‚‚ƒƒ„„……€† ‡‡ˆˆ‰‰ŠŠ‹‹ŒŒ€ŽA‡F߆ÿ_``aabbcc€d eeffgghhiijjkk€l mmnnooppqqrr€st€u vvwwxxyyzz€{||}}~~€€‚‚ƒƒ„„€… ††‡‡ˆˆ‰‰ŠŠ‹‹€ŒŽŽ’lˆ^ï…ÿ_``aa€bccddeeffgghhiijj€k llmmnnoopp€qrrssttuuvvwwxxyyzz€{ ||}}~~€€‚‚€ƒ„„……††‡‡ˆˆ‰‰ŠŠ‹‹€Œ ŽŽ‡$ˆ ið„ÿ_€` aabbccddeeffgg€hiijjkkllmmnnoopp€q rrssttuuvvwwxx€yzz{{||}}~~€€‚‚€ƒ „„……††‡‡ˆˆ‰‰€Š ‹‹ŒŒŽŽ‘Cˆ ƒúƒÿ__``aabbccddeeffgg€h iijjkkllmmnnoo€pqqrrssttuuvvwwxx€y zz{{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆˆ‰‰€Š ‹‹ŒŒŽŽ’e ‰Žû‚ÿ __``aabbccddee€f gghijjkkll€mlmopqrrsststtuuvv€w xxyyzz{{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆˆ€‰ŠŠ‹‹ŒŒŽŽ‘€‰­þÿ __``aaccdd€e5feeddba^\YVROKGC@=<<;<>BEKRZbjptuvuuvvwwxxyyzz{{||}}~~€ €€‚‚ƒƒ„„……††€‡ ˆˆ‰‰ŠŠ‹‹ŒŒ€Ž2†€!Àÿ_^]\\YXUSOMIEB>;741.,*('&%Š$%&*0:GWgqvwvwwxxyyzz{{€|}}~~€€‚‚ƒƒ„„€… ††‡‡ˆˆ‰‰ŠŠ‹‹ŒŒ€ŽŽ‘J… 7Ø€ÿ 9641.,*('&%%…$“%€$ &,:Pftxwxxyyzz€{ ||}}~~€€‚‚€ƒ„„……††‡‡ˆˆ‰‰ŠŠ‹‹ŒŒ€ŽŽ’c „ …§yF! Oèÿÿ‚$§% $%,@]syxyy€z{{||}}~~€€‚‚€ƒ „„……††‡‡ˆˆ‰‰ŠŠ€‹ ŒŒŽŽ’x„ “ööÙ®yFŒøÿ¯%$(<^vzy€z {{||}}~~€€€‚‚ƒƒ„„……††‡‡ˆˆ‰‰ŠŠ€‹ ŒŒŽŽ‘…… gå€ÿõà÷ÿ±%$)Dkzyzz{{||}}~~€€‚‚ƒƒ„„……††‡‡ˆˆ€‰ŠŠ‹‹ŒŒŽŽŒ,†Cʃÿ³% $2]xzz{{||}}~~€ €€‚‚ƒƒ„„……††€‡ ˆˆ‰‰ŠŠ‹‹ŒŒŽŽ€;ˆ&¨ûÿ´%$*Tyz{{€|}€~ €€‚‚ƒƒ„„€… ††‡‡ˆˆ‰‰ŠŠ‹‹ŒŒ€ŽŽ’J‰‚ð€ÿµ%$(Ty{{€|}€~ €€‚‚ƒƒ€„……††‡‡ˆˆ‰‰ŠŠ‹‹ŒŒ€ŽŽ’SŠ fãÿÿ¶%$)Y€{||}}~~€€‚‚ƒƒ€„ ……††‡‡ˆˆ‰‰ŠŠ€‹ ŒŒŽŽ’YŒEÙÿŸ%†&…'…( 5nzyzz{{||}~~€ €€‚‚‚ƒƒ„„……‚†‡‡ˆˆ‰‰€Š[ € ŠAÈ%ÿÿøt8mk@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿic08Š jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cÿOÿQ2ÿd#Creator: JasPer Version 1.900.1ÿR ÿ\@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ ˆÛÿ“ß‚›xÙsÅÞÇsÞ7d*l2æêF-:|ÇÁÃ"€’ay¬È_‘z!%,.¾Œà|;õF³(¯F§6ŒÝ6|Cß‚'üLܳ[87sô4`ë†Z¾mš OEjbœŸ?Ìf™%ow?AV—„¹é,SîŠ v‰š— ‡G’Ͽ߂'¤sŽ.þÄÓˆ—qC[dá¡Þõ€y pFð»]™—ÏÀÎ~Qø€.`y—íñœ¨DˆúÙ i9ê±Ô’Æ–˜:%’ûÉ"íš³sƒôë“WtÑžlö½½YÑxŒ6„Z#ïÛk„¶Š$]ŽcGXˆì`Ì#šéy ÅM¯if&Þ--Õ4lI|›²ÚèÉGãû¢‰Ô|ó™õúÞÃ×(ª»ÍFcö%ðÀdë„Õt-±u•n£C÷›Þ}p²iÍ9+UBˆ?ÞGiAÜ«_\bÏÀ²~ñø€aJܕݯÓæ‰VËæ%– ¼WÀõì¦Ñ4q<2€®›À˜ƒîÏ9í¡?ßn– T¸Ã£~ðá+ ‡µk¸ŠXPQÀ„íGPš/¿DÃ0k_Ñ÷·ä6ŸÂŸ(±°JÆÍ‚ï`³ÉÑŽß.fà «l4üóù|¦:]ÞºiÌõ¹Å;wüNø£³Ü’HfJÒìZ?ÏÀª>Ó¨ü €.`Çú$ŸW¥—Ò'ØÍ5^˜°hŸ¨ ‚央Ì5ü]\ó”TT%\§;ÙYÓU ÕYû¸ÃY–Ê3Àö!‹ˆ}Ü&í ¤þ¨3khÝUÌ„bÖÚÞ¦Ð[^ ?÷<$Çâb.Û.d cÒêÑW)<ž4èóPÿJõT®Ýº‹»kû¡Í?ÊuMÔMo =PäGæª×Ÿ£í>v&Ý\Û‰‚ã-΋Ï“Ÿ…?:Œ‡}¹QMSrožØöò¦ Ë\‡& fU8ɱÇb¤ öõ^±(ÆÙ¾QP ÈÝÇÈ´`T`œ\ØEÜ2W)Q’ƒ ÓMÇIz1p.ÂýNʆŽåH>¿âhýy§Š8å-W@„xtA4Ýÿ9kÄjáößf¯‹À™C`féNãEèÌ™»©¢S–¸¹ô؈ËþgØÛØ  ýìMŸ³íH2ÐF±ük̽¢>ô4:Ç»²Íí,’_‹ièËž]ò<÷52ÿTü òn$Š­œŒ6coÁZÚSiíá¾?z¼Fpœ,R]‘芽;y^¾œ>ÀƒýK¢tªT­†ôãúÁ¨ÐX†Ø<`/½€¿·Ð½õÐÚAÔœ¢w‡7Ü^ü§Y8tö>iÀæ ¸Ýß èžøòfÍþЧ­‰SØFÒ@šS&«ÞÊ„(¿-U߉%&æ0#Õ¥† Æl¯£{B'¾aÍ¥%µd…¤–¥{’[c”Ù^:näUZ‹[›à¨D6‚#~ÅFÂŒ‡ö«Égù0·nöªØ¹›ÅO«¯ Ö(XgX»^‹2æ%œu±>¸³ÏŸ…u?:h­"=¥ê±´qâOš„´âL£‰;Á=¶ÝŠn?¬¿Š~ëCćJ¼±C§¼¦õ$ ¸µvvø"áƒä®5äR©ÿ?©p³uà“¼d0`!ë†Ö݃Pr?»¸KµøÈí?µte·y{édдú¾aˆAïÃÅ ÞD9@›S§¿>¿âiK )¹óÄâˆ&ñÍa1Q£gŒb5ãy’¬Œ[“v†¶d¸×肊!È·mZï%¾ä÷õT|~þ+ûcKIÙÍVæýµhã(7:‹w+<Œ¡Ñ6‡%¸›»š:¯Èj ¨†øêPšv€ ‰†¢ `›õ¦štúågh޽º_t›;»Æ~ìÉîÝ¿X±ÿQ ¼¥öÙX–k[ƒÖÊ›¾t”›9)7ºd¤„SÄ­¿œ¢w‡|ܼìBóÏ¡cAiú¤ReJœí‚ªýa‘U?ùÑÅlµ†•ýS9–@ÂŒøÞÈærqPA¼ÇÖ¬J9š±Æ^_I7ë°‡ÏüøóãË€ŒÇ8õŠl¢çÉ/è½Ø—)„×c/2(F㉑!¶O¾U¨ˆ˜>Rò”a¬H%êldŒ­À1iðŠNËêL5ÅX[ÏÁê~„üé0‡}¹ 5ÞØ®œÂ­ãâ>pýc¬ ‰Vçî§n#Â÷}‰6Ð÷ bÓÅÏ%sÕו¨Ã£Ò.üJ|Ô{Öþi¥bŠõÙ3Ù=>µ½~šQþx6µ,—ä°>áþõYþ¦ØžGÈ JƒË°4ÃÑïHƒ_ ?>¿âhýy§7S¬ `BO9¹Ú__tUqÌ{7ÆÃNÄÝZÙRe»F{røØ ¼DUA<«.ó=`Ï-‹Û& ÁuRS6>B¨®ÈCšºø?¯ë>ˆµŽGPÅL‚h6.ß­yâ; îBÎF2bL[\7 Ô÷v-!Št4×GAÕCÙŽùŪ&{tجŽÇiBU—ª `G±¢” C›–Ý+ œ¢w‡H ÒA®@ ÙþZ²« üÎUÁ2ûx­ŒÚÁ™àb.]y Ë…ÏI† ¯]t ÌVkQ¸V<<Úš1×ÐTöðˆFBï« ¼œu~å§­m¦œ*ïÐôégqÛËpå&ýQü¶kü£¬ùy% 0rnο‰r~ì«Æ51u56Ÿ ! s»ÃÔCc_Ë{¶5Õ=g§à,>ÂÀ4¿ðtDêÙy¡Š¥‚ÅŠi=ÏÃ]¯Ï¢yùíøÂM|ñífŽpŽŒ´ÿ<ì<”ù¥ãšQPM†›‡9“ÿḛ$l¨Aºï£Ê±‡Šù¹`Øuͯp:fl˜&½Ó›T0Í7=U(:¶Ì[jZ(j‹€ŒE€µ )ˆAmŽØ_bt%à‚ôѰÆÊ†y^²Bóè ËC r´›Ud¥ˆCfç&Œ¸NbK–P¯ÑKìú¼1ƶ7š•õ©Ä +°õñn°ÚÿO?ûDHèïeB $—öe TmJ{þŠÜ6£O³Ùm}=ÆÆ .f—êN,®Å.µ<&ð#ü6ú¦wTþO~ÅØ5ÌßyÄVfZÛ·=SõöwÓn\<Ì>…“0jQwIÍ2õ ´[A9ôï]ÜYn`eÆÑÚª¸¤@W×!Q' 2ḧ/§‹¶Õz˜¼q©"¡æÚ,xÁsÇÉÚ%T)JË~ƒ* ÷´#;Í„xoÕ-KçYíé¶Âã^мãxOÉ~¿¼žU0à¬26 #àçq­øø°¿º×E-½t4©,ÀÝ÷ÈQ‹µx)"à ©ú-T©‰DÐ*H9‹S0+›;ÖÌ]¿z*pòö„JeJ±çü¬¼ú–ØQŸxh·! Å/ׯ‚Ê32Z\ö ¤°ÞãÑ8ôXf¿ô,|Jþ¶[ÜksÞèž\%@ÒÌÜz3H ¾r“[7;T¸#!´×i›AILpÿ@/R¦-Ý/ÇT!o±œg.ï4}ýãò…¸N P2e†‡a:J áû1:ßêdÃãIݳî¨}(¤Ñù×w£|Lo¦\Oë«7ŒdˆŽETÐÜÿ=ƒGZØ«Q<…®#}ÝŽy }ÂP3cfè«(I5³¾h¥NEûÞšP‹”qY"8µ#$Ôwy <ÍËÎDÂt‹Ÿo_àyLo¢*Éæl0ήþNÏRÛbP³”Þß4 x¤N”œßÄØ#“—û<ôÊç=º?}&oa¡žÀõœ:€Š¡%>F ý'¥WŸ©å0JœžeZ‡Ë8l lÞæcsiÑ%ÄÆÛƒ<ð6Á0ª†2ï§â‘¹UÈV]FÙµ4a¶§¶èÂÿ±O#þœË˜ ÿg¦ŒÇo¶b½Ö÷mí‰V%¹l½ÉÚTÊÏãŽ?dW²ø¨Åþo*ÏRǨ™î cRÇ90Ý­q¹FÁáïß4EŒþWÔŠÙÝæWÒZ)j'2!³i3>põÿT#[ÂõþÑ=`geÆYv¯’fÅQ—Q(l™<ð‡uŸU€d·]ªÙƒêe'…”fOµ :^ñ‘ÀË ´b¦ÄC 9KAÎYÇUÎÅS,¸+§ ñùZóÆþš Ú÷±Ø®E×®èá%WÏÃXçáÐT~PÂ+cì‰ÆÞzòW{ËÚÿ<ÀЭt&d K¸ŠE¯}…o+„°[¹x/ÏNÂJDx"ãF ›uÝKgã=š Ž'ã «('JEÿ Æ¡,}øV`› P PGöùø»ð.ˆ©)«i¦R\O“ë´JÓe„òæ+ÑqÁ5bù…Õ¹I­5Ùb÷6À›£ðªòbcK·æ.àhšŒ]ÄmhžÜrGáÆ|(X†ˆÏo3ÍdO ýûyšÐ¤y£z˜ øƒl¯0CëXòÏf´âW+Zx¡miðÚþ™Ð¿ ­°°–€Ô žTGrZ†{ép®&ý\ ÿ)o™Wœ×76H?ަ”f×®#/Q1 #—I“N41ÐÎËY!» X@E;GéätÏ骜2ñÈy4“Ad½Åf“§ßtvDsà¥ÌwÜ™£Í¶³‚G.¦ò«WŒØm8O$«>ÂóOÉrQ…›Ë%¢&ÔtŒ&ÄÁ>Õ ^~ω¿ž2º…DW4ˆw¸öÅú>ƒb&b¸ r( ^ºŸEÏ÷%ßR ø7ÉÈÝŒܠس?bpôIÜ›=ƒ‘Û•òOV(‹B¸ùfËó\ï«c20ú®'‘a€ÐmaƒìΔu£ê)l,‡Ÿ®‘ ô‡6²E§k[ÁÈrn=CWDÓ1Ú§ Wfxe[¹ÌÅ‚sY,U·P>ó¢ïþ§6qÁ=1„zoÌ?Ä€¾†ÊNƒ†ù,ˆÑ{K»¥x©Vz=Wô'­ Q°Ûï>Úë2è ±fŒ[­Ñ144^bº:§£ÇŽ“ÍR°3¡ÎDaÞ`Ìó¬žgd!@ˆYjøµµÁŒ†‘x$(©³“è1ÛcNíhdüËþë¶n@p¢#ZýF ãªsÝŸXÃ]Æ>ÝÁ¦eË;NH1ßÂ*Âlƒ×glºŸé@`œ(>^Öd–.7† …6ƒ¢7Âïõ; ï‹,Yê´2Ó“M߬¤ ð¬É’¨kv~ƒ«¤1êÂx­¯ äh£§†ƒî?b}¦ÿrǩѓH6¾Gºx]íÚ’mm^¿ ˜0põ**'Ø~˜”*"[@acQFWgá;ÕÀÆÓw8²†¾hZñ¨÷;㡬>Ök’p|( DoÐåÙÝBJ(3WZd£¡p"r–:QÀøÎ”k¸r çD%²ïÂ݇­sP-/Ñ€Ní^Ó@¿Ãˆ:g¿}TädXn¡ÈBÿ8@K°ÚÆ[ ™÷õÖt’/I‹y’u©4—[QߖØÎÞjæ-)AhNk£µ€¯4Uë1ÍR"C«÷°ˆ=à myŸ# NRe§ß ä´_ÚlKCƒÍas쎴§ºû™P5w³ÁÚ4@¶!c„“* ¦ÍUNóTÞ…õ+Ú“X‰kù8˜ ó£ïUáÀ˜¸ÏG=ædľ?ätuíC[KŒƒŸ¢]I½¼gï,‰Ò ÛÖDéZ ~„Ì3Ö{T1r…9v«‚œš ÏÃQïϧç°ÀÂM|ñíTÙu3ò+ œÖçB€57k ø÷¼XÑð0Díê¿H›Éî æÊ:?Œ‹÷hj{…Rÿ`]©Ö£Èd}Â]²}+šE<#fÿIóå#ïNEçB&ÉžÑL]-Çm\ºœað÷¸û!¸±BgdþzûQ­[Ó1Ña¢¥éðê$»äåç½1îvŽ ÂA¤pòSªÚ§6%i/Áª°ËÈÿq›çÓ¼÷v›¨ó].ÎZˆQîò|Òõ×sÏì`ù•2hVÓáÕûÆÇt*éaŠA¡hP&Ù›WðËDB~‚™]ÉLß'“V]¯ŠµMÌ8&®¶ã§Ê¼J„cà(Gn@ÂÍ«‡ŽÎ ¦ÿ}—â|§ãxOÉ~¿¼žU0Ô‰m4!XÚƒÃ7g¬>“à=ûšžQŸœó±m“[Ï$úQ#ñn©¨÷_kS#`ÓfÜ ÃÚÒzÑÛ’¨A‘Dl¨&øîÈ‘'©ÅwcgF‚dÁ†–Æìv‹àÁŸ—ß×2€®´Á„O¤„}+ÊçÔ;¥´À ²½ï¦3…ÏÀ–;”RÙ€>$ù\cçìò(ë )ûj©‰Iÿ8þ$b‡{¾—û°#ÙO<2GS×0¤pìDq!©*²?DÌ Úq]¹yø-5ü.Ià_#Pн_CÊ&FÅ÷µ0n t+/™®*¶|°3’|ƒò‘‡8´Ä·"…(~©;oM @§@‘u#©HCß²ê¤dÅ‘O¦5´!Ï{;§ôÜ©n…·`Xþœ”íf =6¥DZËùƒˆªÿ_6 Ä„¶;yÍp›„jkõ°}ü3[b&3‚©+uuqœ³R–ðÇ`ô(‚úú“Lοï@L%¤b;ÆÙ¨èÚ2Éb®'—U¼%,ç oí£ªã­wŽ^fB!¦z!`cǶX΢”;¿ü<-·uOôߟ§AŠeÇþ9@Ìét¿,½‹ëøT œñ527™6\7yˆ´n{ÔA†`û*O…•DÁà¶Cɸ…m_áïß4â»c39ûâØf@ŽÛ. <Þ‹WôÞ{¸$ƒ5[1”¢ªÝAô¸¾&E?ßWœEFu­ÙRªŠ„Á¹?,Ä‘î(Vã/ößÊÙ ˜:~Ç-:z8†`Í“Ts¢×ÈU\ÿ,Ö¬ó†ÖZ¸sGãsɘdK¶› lñ:Fä‚KÚ¬è.U“@Û)Ç"_o_-þ wÄò‚ß^|£Æ+ mb9eÁ„U{îÄÊz\ £u­x|VÐðæÍÎ{“ Æ Épe ™H=pЛöÁ±¶(ÛoÎI¾rļíÔ/ø‰ý ÌøÉ⤺„–Oþž…«ž>"ó²"AãwÐGXÖ]8'&'ÆóÞTK{ ¢«W}7‚’;£8ÏSsf,ÞËÅ÷5ë±üÃhð+^‰ÔRbO•îÅu“8 £YxH Ÿ.¿¾Ë)ÛO¹nÚû½HZ3€0º‹9ê¡ÉN¯%rð7j}¦s{•“q9ýï§¾žK ®ƒµa_ÄrÀ:$ü ú@áŽÉß>Âú©O¥ HJ¬—À0IÒYõ„ÌJH éÏîKb>óøa’ & xâB_ö†~ÈÃ%@áŒQ•íÏÃºÉøz•Gáè<êêáܵŒÏFÊžû’ýøV^ÿ#œÿd{4w›µ«Ž“fù ë•XA]0Šãõ‰ž’í©;›[ë''¼-¥d²‰JãKÍlš(.œRѧ—öb¢Ç.Œõ¸ßLÐ:BèUz^”Ëo·;˜Š.¸0“éh‘/åhZt”§–ÃcÀµÔ*hì[Îd˜Vžô¥}÷Äè““y°¤B{|v®)ÛÃN‡úM§åP¥õú¥{h [‰g§™À—ʬ´´KÜ¢W4m»ÿ ’a×ÊŠ¿ÅEìÖ ÎíiÀ‚Ëööàrƒ7ô?<Ãoud´ŒË@+Ù vr)ŒÙf\òØÉÚ4‰ÁjgC®ç¶¢¾€׌Ð÷Wà÷ Qµuæg!4mëH¹0ü¦á{Iú‰ÏIæÓ±¾áC£ 6À¤áš2a}CÝKö2gâ«ú–AÎêiüú°ùƒYô–--P–“v/ú‘¢ùM¨ÅXòtë–ÅÒ²ž+/Ü=ßñIzÛ­î¿WÕ:—ìÔã„r¤ÎÙ¹ÞŸDFD×çjxô?c«E™“OËoL1P 4Mïž*µ:ÜÞÉ“+ÖÁÑÖ&L¹I<ÛXõ°(“3á’©Ã!EÙ#[ƒ#MÒßXƒBËF«pÞúQ}Y±¬ï¨f#ÝÑ–U˜‹oÖ-jëéZï×h-TùåX-œª‹_¡°žEYLÿ+LRø¸®É0Wõ>·b 5J@Ø[ÙµÏ?ü÷©wì'œ¦ÓÏ_iö“+|Âä›A –«FÉŸuTØV®G|”eK[¤N tK)Š­q,a 2qx®Ьœ&HÛgôÑ¢â¡Ïi¹ZÇãã·µÀ§å´Ç%¶êã-Š×Ó0Yµ ^¶éV5|ù1óS Ë2?^îÇ‚l€ÅŸÖ©¢ÚOCB~¸5}Zû‰O¡aCg!“UmÓö¾½@Å6²Ø#BBD³€0)8lD¿­ea1ð g“2®ƒKDÎfV#{Dþ å•m7¾=r¤pÞwzÚ÷e®°¿Ù7I`ECñÄ&x¸Ç0à*L OyðÇoS¿9Õº+ý±åÃÕÆY—4rÛ–³Ÿkªâ¹…ððR,ÇÊβœE'³œg¤´M”2»2F5Ö«O¡1„á·wIÐÕ·‰ðA9ýä)ì¤ÎøÌ¨›Fƒ§%/íï‡4¸ð­»|g"¡ Yê;\£MÛÊÚŸà ýÈöSöUÉ”^0ý%ól¼ÕÆÇ&Æ–¢Tïø[ë~.ËÑàCï·Ç<‚ÌGî%'y4AgÏ‘yûø°Ô+½;v$Ç­´A•Pç#›¾ã)ý] ß«æ²3©ë²ƒK€ùdŸ®àô´>¿à­ø ë'Ç|bŠ3dEûtP†W(iS´ŒΞî?‡õé©xõ±×{žƒêëO¸–Õ çå¾ÐÄòéh³3™îDàžÇ¸RÞŒzÜrùz,­Æ¶°çîÔÛþ¯'<;º¼ 糨ÃТãŸntl…Ý–Æ`Ÿ8-áê¿*b5oµf³"Ð BMn Ê—ðÿUP±{£úX)"lfu*ïŸÄøoµCSÏ[)Ör Ý3Æ1×¾¦Ža;ùƒÛ4¶ôŽf5rQšéL˜…o:[Tutaþ¿€½ëÞêŸÄÿ ÁDŸx@íâ]øqúÔX,YåÔðaøufÝ"ìe"!åPÊáSK“GSý𗱉ŽÁHÔÝ8qPN‚Q0Ê©)·±ó`1JUiÁaúV‹Õõ>Ga‡&“™i>SSjËôjþ´c“NEÒ²Ob)ˆ/›×Ê=–ú-’"d`¾¡ÐìbÚ<EÒ”Õ‚‘_<‘ù!öo¯<=æ[m0¿ú3$|¾\á0±»^žÈ7ÊQkóH–fq@8ϬÃì¼ß¼Ÿ‹çXN“÷0èÝ@ùpþÈÇA½Óô½Õú3R ”& Áy;k!²ˆß"ׯAæd ÿ~bSihûÜ¿Ld€ Pmj[vÈX&î’„þ²y3<»Î ‰‹åÃÑI»Ÿ~C<=ý’Ô² Zt†ëU5ù÷Dä4Yý¥û*ÄSt=ÌòÌ2 ]«sj3Xëò°y±Þ/Ì”¿ùhs°©0l¿ÌÝYLêš50Ô¢å2†HÙÇ8æÊ9KƒÃ¥Çµú°†™Î gÚr4*!9íŸX8ì»®0XÔ'Ͳ„uR!×¢©)‰-0äbÓÒC‹GÎÆÞ4)û94Ý~–.Ù¤„ZAË 9Wˆÿ=­t¤êJPâµK¸‡akÕß«³^á‡_;ùW‚ñ¤þoÉÕK×ês4šHÿlñkqTü:z[ZoðE ‚|îõÞB%°"zthIÌ÷»øý¸XPü‚û¢£ìùØ’|rb¢ç«PÏ|£ytþV“2ÝšÀë+F© ˆº&᜺Mxõ+´é`P«ËZ×íòSÁ²¨º§¹Ž6ª(žµ#VPñ:kI„9íœbÀRDù<¥E¬;gÏúœô5¤ý‹ŸÓÅcˆ./ÖÍp¿eÅ_ò´îA!VÕN©J°ô7 »ÎU¹´ÐÒOY׉ÚOˆ`>¬:râIWד娿¯HqeÆÍ5ÿd\'Ý«¾©\üO¶ݾ×iP¹NJÌÁ§)FLNµèå0^Uß+l F´ç©ÅÖ!Üû´ZÕWÀõdeP笡ògnì¾åÁ=@m¶[6®Úú^LÒN·ÈÓRuÍϰVa2ˆM«+¶Ñø-ä[ gLbÇ~SVsU’ÍŠˆb5z›ƒhèéTß«oÊï÷¿Ü½øçíÛŸ¤dæ‚»y2µÀë£+°f‚úÕ¶ÅŒ ˜bÌcÕ3íkdòQŒ( ©`J>ñ¶ÄZ‚Òù¨„ö½Ûü%&À¡Èi¼}ÀB‘ÜÉŽú€Ãr³+ÁÆ<äZ¸…ì^q ¶Ê/^‡¨ç i„h»qšá°ùÞxíÚAZˆWª¹Sþ àÇ>êBrA¿÷¹•fÝxî‰ä¨ìŽ D½;$Ï\tç%)@…ŒGwe*PÄ&¬ƒY‚ÊŠ„¢±£qÞqCEx(º3ÿhœ˜³úÈ"›§肚X¿ÊTð«F´ùƒÉšèR<2Lð­å‹ f©¹T'UÌó1²’3dqAO¿ôRY” jªY‚²½Dv‚WñOC±"ÒWÎ?¶G«€Ôvör„y3˜ð¶Ût¡²*5úë“hcíåŒla-1¹ˆî^6§/[knÄ»Uñj*ûÎâzÒ‹e7c(owE{;îU:Cv¿—¢„aAŒ|MZ|%îˆ?°;ÿo –à—%BÎ.ºõ’<â–›ù„ý¢œá‡Í?v›Ø%ŠºbÉ ÔWãºfÜiùHe‹Ìˆ_2×X ä=ŽÐÄšó³X «OÜ*Æ9r³µày,ÿ/%*ÈnÑ$Þ¥?k¤Ìébk XÃ<¼ÌÅXAÒàX.MS0ÍËY³R¡vÈ£õ¾¢âLB3l‰éz>,¬øV'î= B™/†1€²mÚ©š©·'U˜=cꑨìÛbfš¼s`é±Ð+$V¨N®+ipžpÀGȺ“³^‡:üß)uãÎÎ{ÉñcÐ+%Ô"ÆÐ ¸¼ç±Pì.§#T`µXÅq¢ 0Eäúä&§2« ÞÁ^ù¬3†9F…^ÆQB„•ÈÛ^l®Ÿ«.G¹Û“•MÓe¹±Á$~Üq7 FyêÒÂ)uv.r;]CN/“l¨º`OŸ²>4„å“+ :Ù}  ¢wsYgÓJ¹/‚§E²7P}–þ&ÎÚßJ#wzóNu’Z(¢K›Íí`oxª)É“·›°êTu=x𻡮ËÝd1E;Ž”ŽìoÆöÔîu ģ˶·$GwŒ Fž,DYÈpðÊû)t²KJY&Õ²vÕ–¯]çÒ‰Àòrn«ó± ]‡óÈþ£·OÐTý ‰’ùRú#¦÷{ùÎ…Àqûç2QF/æ'üD"ý€3MíX ¬öMƒñYàC³~vk\5î®×2¡_²x@Z:ß'0l@€†bï9M·ªŠZçvr®¥ÔErUYˆ;ÿð ´™,#¾ aXYâ•þš‘è@óS¨ï†ùØÂ²+ÿ ‚z6ðÒ78s°`7ùb)õ Ù z‘tSÙÍ£çÆÔUº|°ÒÛK>()ZŠiõû£Aðœî_=ÈšZÚrׯ2¦Û‘}ö³nèÕ£ºÊk Ñ»©<{÷–úháE¸>›3ÿBLÇcÂÔø-jm¾[<ž— Þ<Šx]ÿûþP‘ÃødŽgß7E*ßåz°ž…Ašfã3èÛÏá‰=íÜ%ŠdŸÖó'9Äׯ<³–íÚp„¨ƒ¡y¨ËÇwqÑx4ª±¦';a€øêY2ELÎ5 örëôüwܾV,KL,P(Œ|ÙÞ]ЀÖÏÞ°I¹:ÝaD7ìpâX¥G9uƒGOË•¼aq9’„NŒ’!P|§Xxx']Ì/d_T¡}íiv?oöA$I~ÏÀK®oÌ8æ$PƒlIÞúb’n™ëùÿ=–,±µìøÁoø´ç€1bO÷´ÅX9\‡•N!j«ÓfŒ®bâ)Küw×ûíØ$ÀG!Æ4‹åÆDp$ŒÜ Azºd'×›Z)ÇäÃî=fÔ½ ëðdt8$ÅÉÀôI¥å ˜ ^0ÁHÅmâ*ó´%ÝÔ98üû‡oÖç~ÿ6=‰N|çãª2çJŸ2Gh~m/п~™õËç’œŒ!#¹kø¡Ulóþ)§WÔvTvpËÒ) I&=ʈWvpÆÒ7\)ãùùgŒå1BûwӛꪰRË1-Eì!VFgJ Jªè›Xßó⛰Ƽy®b4ü;ç-8èºtÞä Y«Žzàð vtXö¹qYjIÂÕFÚú:Æ`[¦#¯–AH1im¥Ñâ¸Pð*± F¼9Sg¿Nî„»8'ªÀð†R~7âåË^õÆ#é/ìNÇZ¸:Y¤–´>Cµx啿3¤¤€‡™­?Æ-ëŽ*jd-ƒi~3­è±¬µá¦R?»oÞ&×€ q€ÓŽ_“$4+9Õ~ÚÚaxy< Îà›jâüUómÿO®¶M<~ÄxŠ˜ÿ*E^à püp;n?7À,Œ4­Kz¦&™©–ŸÄ*ZZ>¯¿”ä¼2}™* `šÅ5)…(&—XjöˆUühøókkà[펯›Æ|Ëeå¹ìÚdÏ*ì+… tËߌ ÊÛü=©S6á&Ó·sËe‚Kúý}ïÖ«€þl'à3.:9úöx€ûw»—(#g^©\Ö]ù6¸ƒvoZ[› t ¨æ^Êxn±ÕöóªšNè¨YJÎÈUŸ$È.ÑÓùØ äÄ ¼¼íÇVÅŸ³ºõ‚Ôé«€€ ÉêÍ3ö-Ãh1ô"LnÖã˜ás/r„£KðÈõ¥ÜfX ¦cê8ºÏy¹pNÐ)ÒÆ,ü÷˜|Îìºò…Ò6ƆGÄ@aO9\ ^“­£a0j»‹ýØ¿G­nkNç-„gYÈ<úÎ3uŠFeÓ#ñ)½„hsB¾?91îšd2ÇÐ,èêÂøŒPsÊuä:<È'M,óø;bÙ÷S0½­”-š=ô'YTÏsw÷ŽúûLQB%ÄÙF€«õ ~R“¼­7ñÊ­b¼† SÐØ7O qIaÙ½!Zá|ûƒÐ³]}ÉÆ8;ðt‰:2Üì#ê60Sªjâ·ä°5Áy)<)ô=¬EEk•zWÃ{Sãy>€Þ«`Õ’1Q¤wB #_ç pZÑÌuÓa»÷ÕT¼¹‹Ç†” ¡pÒràRË}t}e±Ï+Iq;¬ŒZËÛ»¡ÈÅ© Í@<‡à!‡VÂaÊOk§˜E[ÕÌx÷{ã#myµê…º_O1ŒßJQ)œ­[¸‘@mÕ¿^&°›íP¶[¸i²zLD‰°#My ùÿ9±/úãcôªS–ˆ×Ìà5\æ$ô[F–ˆˆßìXI*ýÿ;¸MßÞåXõ&tªU‡&dùEºxP‰3ïÙ&¶‚Yòû]¾Q4Y˜Ñ%8P#@GÓñË]rhHÊ€Š1‰MÈPV1©4œêïšÓuÖdRë>u‹åV¿]ªï‰6à -#˜*Á‚]5¸·§ðwµÅSyÌãCˆ}ü!{;ëkFZ''úù;s1Ú©ãÂkÉLlPGY¼¯ÜV¡{ñOvɪಈ.¯®| б“æQø–Ά'ïÉq"’Ò u<ñg¼>~Îv@ùÝQ[•1eÆø¡ªfyðX °õîÊ¿9©ðÆR45÷Åô÷£R&4î¿À@åAþâÚkQŒ[W­¹´ç{¾Å6î¥îÚêÂ¥ñÒ¹ÅÁöxõÔ'"ý"{”zÓc?n5,3"rLÖ=&âEÌ·ÞÌ`­Ñj(Y£ÒqÊ4Ò‚Ck~=íÒ’ÖX-µ^â}@8ú³CôŠùÖK§ª':ïïp»ÐUj_äù ¨g¯þ²tN^Ƚ#y·Ôÿw1Ò˜Ùr–ßÑVl$¥r¹…ÍÅã÷)G.¦¢ÞȬ Ö¯X"ptpè­Ø¶M$a‰ ¯w/%m9è🠿v\š:‡ÝåÿÏð‰øzOGáÚèîü¬Põ¬$ªtËt—–ü¸`·XV;ºÀ–^UOêÓÔ%î R)t³„ê‘58°Õ3SsÆÓþvM×Ê®'þHyhò3Ñêöñ¿·’û›n•gûWïþÿu]8F¤¦fšèåíYÒHäÞ*¢?Dãpÿ'—c¨$ËQÝ›"‡ Šžº„Ç'Î=´ˆ²ÏÝ'@œ·H¼AØcÀœpBçÁ%^¶ðPù˜µá6yg±K6UQoÉf•ìEs³AY‡(\àfY²c¼ÓHcˆáF5¼(ní¥a÷ĺD‰hµüF«ÌŒŠY Wˆ5`¹0æ`hrÎjtÀ¤•‰p|è§CjøOJO_WDsˆÞž*Mñ˜—#ܨµžn É™°èF°"÷9 q Åa.²À~‰c–Gæsÿc„ìðgš>ôV›zÚ ¥D +lçð©·HuGMnŸø)ÒBªta-„ó³q¡©?Qâ:l.¢@QºA±Ç2×;iOÀŽŸóµ òÍ·u–§ÒúžÔc»Iù ˜tíÔW¢Ò²u¡ÐÎ>>”šôãðvÇ;®ÈZí "·k,´Âd=:¯U§8ûiõ0·ðŠb”È›55 ÒCLi±è~`ºYìÑε•€[»ám ¯ÙèMéa¶Ð‘=òÜýêu± ê怬ƒ†¸(ýz–fâQ.Ê81½TÝ ®Ðê£pý÷!Ëû„5€b<Öþ¹×î?÷µæÂQêKjP4j4&ÛšãåaÚþÕºñ–iB Rþ„½{“âNrÈJƒ9Õ±`Ðzßó(:=ë4mæÌ5s›H8 ¼Ãj Ø8¨žùòè² FÎ%Šƒ(¼JHo†|22ó¢BòÜaq¯µ½ ust3Å ÍÙ°ãÚƒÈÿøùÛjCÆÁÈjúðÙX.t,|Õ.)¼Ícéæ< ïE ÚaGù*(öømŠ_ŒÖœÖjÐ’m;þëå2€÷ïi™á!"[}}ØU’w–£¸p¨ƒ³ªH"¥÷«ùoGDVÇM¾ãÔ ŒÎ~¹Í+yi=PÅà»f×þ¨Ÿÿ~¼Õ]Í <öA]2òÝÈ̱¨žçC©>#8ªª“ói-Öb7“q÷ØRïKÙe`’«…Ë'˜b Ù_át¦Ø-†"ÚÓ,ª· ü.Àw7‰ªýîxLÕ çÊ~$t£6+ÂÙí?ÒÃ#„ÅfÛ˜±CŒb¡`æ£GØEiÊD$¿þó»S¾é!'‘Èçf§–6uœ-MÞ0>9ZˆhR~ÕëïýPf ÍÐ!Ã͇ ÆÒO7'w,Ù{,åÏ89•Ð΂ÔnvÒ/Õ^Gkœd˜çNÿ^c 6‹2AHjkczc2xû_oz¹¾JµsÌñä)ŒZÀ„_ñ·5kñÐif5èv²sµ`† MÎúH4PÔ:.†ô!÷)PR³À³nEò}œm3L398f:÷嶈h’I[ÕUQ‰çÎ ,¥vy¸D¡ñÂÉþT1Ù*LÆWÂ¥jã|Ce$ïž÷ž<…`¼÷ýgBšá04þ:CÈ…´æâ›CVàîYd²½÷{× fÈ÷æ§Ë_ ÷…[ígÅŽÄѾ“‘ Í_Þî WÆiý°½dÒïòàD}"¡„¢õi‰HWÄ«ƒVÞÄ ü&È\{ÿm¿L~Þ€ ÿP"žkŽ$ÀÎÅŠÏ7’•ß# ãI©.V¬‘GŸ_FKBÛ‡µWzÂa*¸Sí>Û"©9ƒèº3”M1 ®plÐG=ü3¤<ƒ=^«¶ÏÆ6áRÎøû‹çÇ7È¥:*“e<„>¤=[æP©ÃQˆZ£nÞ…¢› bY!8ϰÀgß]yn‘™6%ŠRºbC¡8}a4—ä@ ¢ž¹˜Žq©è>Ý&| jyæaEéïë"Ÿñ)-³ë#A§ŒNÑq­éjëvêíøè±.0YØ™ìRø‹…ŒX±ð$€ò–Ðz]*¡Ý¡…,µÑséÌ`£îŠÈŽþ‘é%Ûh´Î¢sSœÃN6áÉQhÏ jjíû3ù[hù±ó|>~ËYÞÎÎppÂùñœ¼‘Ê«!Mº”@¾C°}kݦ2–xhÔ0€No\µ æbºµŽâþ‚ù?`ÊLk‡Pèû4E·Ó8Âü Òm$¯#6òWM™ÏçıK]hý^dîÉúRU­Tn¡£qJô…7©n(ÑžåèWsÙ”½+˜ƒy}ñí-+£dÂv/?sè~üâ2vÃ\èQHdX°;%@9·äH¨×tZ³›±/)&ìžf’©]VU¾Ø0šŽ#$ϳ‹·Êã5à}+êÅ…©Æï*t«ø23x~€fðQg4CN¦g‹­¨bP€HݨÙE®“@?á¢yÁ 0‘¹`1½" ²”Kˆáa¥ô§ŠHÓ•0V¨@$iáUÑê—s•˜ÙN9—ŠÀÏ|ž´×6ì ôî­‡ÃûHAó¯kû¨(Œwísnít‚Nƒ/}gk|CºZ÷²Û" JÑcD ¬Ã‘ëñ•ï!2ÑR,ˆl͵¯’~·º -Ÿ;¿H~I ·×ŠæÐᲤ_Öä yLŸ~rÚMlG«‰…!.Š—8¥oˆÖ,äóR YŽßÒŒ^àt ô¬T…l!øóoÒS%I·g°ÖØ“ÏC)âì·K!ˆqÛÃÚífï@ßÑ™eoDíÈåŬƒã±æƒ—·l< JAì©~°÷­û9¥Ýß!6nÝØ#s@o3pñOÙÈS xÂÿ ž5ä½gÚb®i%.á&`/pôú±"ß)Ç›nŸñ»(ÛmBE(7€c"¾¾¡Ú~H•Œ…‡|½ïƒ»ÀÖׯQfbÅ~N^yÔc±Å]E¬Zƒ-ƒ-xpèÐB<Ú2ü°\Æ„‘ÄÖ9=Eù‹OnÀs0ï|§}ÔhqfñþÔƒó0aâ¨pŒ) ªÖ…C߉»Ñ !ô¨(Xs)HAq^|ÈÇUÌNè2Ŷ*/¶“µGM‘ÚãZΩ^º ´q]†Ž¨¥Ð7`¬í?Cdª¨äý¼Ö1 TL[óVs?Žë«b‹ùGGÇoî- ò,ãòT'öpE †¡Qû¥)šñ™4Õç(V¯Ãꟃ\>Ð`øP/røP1—eùþŠÉ½¸ç½·LFÀ $#^ÇÆ?~Ú”à€ÊŸ§ÿ;kÄHKá­da’ @:*£< ‘†J€D¡°3ÀÙd¨@?øP^;¸öâ|ýÁý·Ä|žšod™ü7ãøiÔú»ŠþËb}[«}·œ|þœ‡Zã·ôÔ“#ÀµT¾*}Ë)MèÐ ‰nâ±ü¦üï\f‚X ²©¡4ž–9J.>-8f F|;ž)*ÙY\xÊOD×úçœóéGžSîä¶y0.NŸ©j7t*´›_rBÉþöŒÖbˆWQðôF¯È\'28lúìôQ4þßfìãI—··¢[N#šýç±bÏ»¨Â¨ùXU‹íïØïRm“¿?I´“ðç!xÅÖ'ó>š{J¹I‡2[fû4B­7–P~8¾õ‚ñ»5ç{C ­õÈdöÂë¢Tè—öQ, ÈÏó-[ÀfExõ]<–Ø(­|üy­*–³:§õ‚  ™AyÑJmR]Ñf»…Às‰t»bÍ©Ë'w»"4R£$ö›yrI\älæŸ÷P¶ÎèX”Ì‚¾-|l21»‡ãÅ>$€÷ºÚƒ2Ú­õeÏ„·a2-öNh_"º—‚v¯É¸ µŒˆÓcŒ¸ZÄÂrÔñ£vÔ†“¨šÕùÜ”Ks/%h0½Êó^l¬_UconJ¸¿µ0ò_­Úlê7Fv꯰nsüð|‰§s=Ùªõ1,x›6Ÿ<…ù$ÛExb„ ÔËÉÆkÅÂo3?Àg^ïÊ8UO/”òäÔÓQ1Ú1ayoŽ †âJm„¹); :¿Œ…ÆÇãÅt®üRb¿~Ü«R'ш …ᯠ¶J•£ëZ®@c¦oºw¿ ³Zàéû¨×Ì´îšÞ ŸÝöî¥ýµó<Ìéñ©o[úŽÑ#ÒA­ìO€E³ˆÖÁ~=K´HÞÛÆ_M¾ÎÔ†ÐÑñ£•â¶hA³í÷Ÿ÷Žn/^c9!e­ùÿ2Éà _rcù; éþ¯gGѸ2Å:tIÞ]UŽË±pÜœÈØ ò9G*waÃiaít#ýÆÜOjãã×çenBµêWðx‚ÍÏØ?Âfe„†VçuæO–-ËZ†4Då°¹˜Î¯2nck`F- œEIiCÁÁkñ ÕBøPŠùchãš#^m\£×Pš:dÛ„˜ÜBÉÝžDŒw ¯õûãKxÒjxS¯ÈYöE²>óé#L2¦ë•'Àï\iFW/ö<)6 R”W¨çtlÜà"ü„ )7/Ò Qà·æmŽ0;üw¯-³ÐÆóݼ„û4¶€µ= üáØÎióÁ–Z*Ù´~Ê"¤¼‰¬é\+tW™3UW%DµD^j´^ ÉÚõXáÌøëª•ák-ñ±_Eswß§!Gã#¶™²í޲K+8³ÔžçÚDñ¢}:Yþ·y¼x!B€XÉìsTéÑ#ŽÓ‚jâ@„ÕFtÎ'â©~ö=õ½ä|›ŠÇšâÄÖ윰w|ˆ\®ÓìØÛ¯oÝ),k²Ú*öû¯ö,$ÞFC›C,{iŽö•­þƒJü¥|øfo¥Ê•¿!aùèªÆ(-C¨Ý¿€l[Óéñï*@øbát¹°/žfäd@¥—°xüTý7È­vôyU\³‰j¢üäúu¤º Õr§:„ŽX©ê*GÏ–¡?OæØqK·¨YùIt³DãOŸ:ý7ÃÊþ¶ix=d;imT‡¡iþï{E§óÞ›Œï«Nx5„œ­Z‹‚•)~|Ý8ú/†rGwß;Cwëy° ¾ˆP˜,ƒªårç”B`•äý™ub&†Æü×Y¶W,ؼÚ{ѯøÙH(M¾ŒwaNMY*>ÿ`Ä 'ËNVàÅÒÇâ?ê4D©Nw±Iåøµ$Á|ÎæÝ•æQҖǬæ²ÅÑŽJUô ø`þ¾°·šxÛ¢5®±ëqÞ¢éœNgR[gÑ7s>(”r”i°C_·kïø¾e»žèa‚”Þ+§O¹$ƒk<:ìärÂzcþæä[÷^}?ÔI.•Ñ•pÜßM‘ºRµ \´zØ1šÚÙð¡@ rs ±I ‚O„vê#ÀϺü?$š-îó ΆSéÏï‹E†¯çé¡“ ’Ù.güíüêÕ›»;U€‹’Ë 4ߺ 3dMœýÇîê±×GÓ bàH‰æšúu ˆÚ± É&Z~]¤wYåpèŸZØn\ ’Ø£]R’è\Ã÷=•a8wíþe¾¿µ=±˜9“€+¿ú¤ã){ñŸwr$˜dYš¸HÀÉzÌTCG"DWXZ”ß(nÿùhÉV˜šàüg§ói'õŸa7L–ý‘´õÃéµÏäÃÞFçªÀ í,!~ QL±-U ºõJ1¹òXW­ï >”VÁë䀣µ;Fÿmå:;Àê»D«W”測ê Ž]âÇT2jî†ø½ìŸ¶ØÒqþy3ö¸V]—– T*êÉlÁÔ;ª\¬áøK;ãIIwô‹‰3½ } PèQFÔAÖ±[ F„“yEBZè@’¿¢íæ cÒ’¬óÊvbs>†.º¥q™öݬô5­}0®‡Žr;Q=³çÝäó‰׋i™øoB©63–ñÂÍ»_‡,µr\žÕP!³†Þø¥ù‡ÜIiº4ì )”&rÔÍ^­§vïØ³|Ù%óèœþ=ñd•ÓúúûsDKùu&¬&e·µ®²ýŒ rt<Ûè}ÌÞÁ$p*'•vY és)í@FÍöºR+2(Wîì°}‹¢âîn´wvGÖdïõ„ÄÈ»}½>süš±ä.ɪT’kC´_éñì›X¡M}c@§eïÿ"Åeã¥K{]gS鹟fÚ:.pcÍ•UNmª@õuv¥æ5sÍbÀæ÷kp“C{òƒ(R\(nÿùni@xâMHRé°ótŒyމÖI˜–\ôŠÇwBû‡Ìy¶'Æí>C”ÞÜfthT¢»ñB;tl]1Ðw@?`+_ÛÊV±¼$;Fm‚ÂGNË$lØupl®®ÑùÑ`ŠY ²ãë׺Ÿf±þrDÑre˜3¢1äË‘òø6ˆÓQšðÕÂY‘!7½YúXÛ‘à­SXXˆÛLMŸ‰˜ùO®úq|e:ÄŽÂÁQðÍŸ ðúJþláËÌåñl .X,œv£û–’Dõ–²š €HY.~^ŠOoM¼ÜQÅ(îéf›¬d ñy‘Ï™Œƒ©üBèS´9ƒ×ž"«Ow±ý( ‚ˆ'ÞG’Æ-£Ë0¿5‡šaٳʹÚ_;Ûá=²%À›dçPÆ^_R.dÁ5§”$õ’Û{‚Öâ L›Mºáà]%¼ä¼³åv"‰¬ É[ÚÒè ój‘ÿmó…%>èa·Ýængb‹°“Ÿ +Žø9{üès÷ëB§[cÀHÃMeô|UkVʇÎÃjûë´u.ø¥?öèp”¶[õ 4ïjBÛ˜~é¹Û㨂˜šcd4òr’ÎèX*sáàIÅ0xe¶Ú¨ÏqìjPyÕV Ââô(éïäÁ¥²ðßr2“,Å7O¬»$é:}0Á!-XßFW-iÁßjí„ÒEÊNTÈÔOM~Ä  §’ ÎxÚùEïZÐOÒFÌuò–ŒtK™Ôª¿Y4úfå¾Cn"Q%GÓ}uz––Ï[¯[ Rë]Y1jï/nW~hê´UƒQª˜_ öW™³àÝDe#W1 Wß7_ȨBŸÐÝCiÒÓRŒlŒŠ´ó‡Œ$íáL@Ëo ¥Tæ’üïÁ±ñmt©‰6 Øè wCž\D“üñ¿YD;=SHa0Éé8S‚²¸ÐO2]v#ŠHåó ?G+R®ÌCÓ3¹ÔbZQ©ØÓ™ÔEùa@‡ù×@\”¸Њö““œ­’©I‘YK¯`Â\ÜS”ıúN¾ý%»†1á'…Ñ$iömëkРÅÛ­¼¢ªêŽþŠþÌöuᜰL¡òÅ$µ‘)Zº5ûŽ”„w((‚­çžö½}ïß\Ϭjª?„,ºÓÉ$uöîGxŒèkk¹žpY‰ƒú‰>¯äR¦ü¢’–\g>¦ª©ÆÌâŸc\.¶J€Ý³Ìt³Ã*™nð6 M€_KÉ\Ñ«F *‚iÅëiãì0õ߯!Ï=ñf®mÑi—¦Ý«÷ ›§'¤ /ÎîXj3Ú†fð5®fÆ×¢n²¡•,Îå.'ÉTx7d‚`Ó +¶3ñ¼ùÀRTÉÃIúïã«Ù÷ÜhTH2S—ªºÕHÚa™¢Ú”÷'©åWÕŠ¸e' ¶ð{‰Dâšœ$"*gœ~`ÐÞ\öl“–”z~°Ø7šº1l?X(TÑãd”4ºý-Îí;r]ÿþ*eŪÐc˜*9˜=gÕõJ5Üä*‚Ä„V?¿†­âznTõEBx Ó,"Fa*ß “šÂ#ŸóQ™­Òäè×Á^`|*£´zv¬¥ë‚r†³X†’çiÏY»,€¡:{¶U)ê‚Â÷eÅÔœ7ñâÄ|Á.4¥Pví«6-³<vFNk8€àeÇ…«h‚„ŽTÜSÏ` \k·;;H*ˆ;h瀯ÃÎ2² …fo|XÜ¢úLØ ˜T~‹ºÑðIbµ‡ƒÍÒŽ¨žêq~ò°:K¾›ö'ig\‚û!ÿBû¥>Cz„ðŒ´&3Ø$4pEŸ`碀5±r¢WÒË%ó;3††ƒL.†@©±ü]¤ŽA3…[ò dÖ6¦;Ö o1»"s˶ò”¼X®|ÓÇpþP’‡sŒhý MºÔX¯¼\\´Ï|‚ft$Ä  ‚³*B Ô<.³g r-úð|ÔÝ•õi]H=äÁ¹Œùã6†ÃÅ£±~‰Ì –Ö=Êr7˜£õ÷ß³J2Þ3½F¦ðJÔÇQÔWþ˜ÍíꟵ)©Ë'ÆUqgÎôbtùëx  `RÖX´T}{zbè ?ÚZ3Ý/”¬¶À¶ðï‘cÎÀY Û{2 ô„f1gi”"·ã bæ¹Ëÿ†²´Æ¡°ÿKQåF˜…AõQA‚b´Õ΂…e‹»>ò>Nwšyétæ ÛaÌÅ`y°J4Ep.lhE”¢}ìúY€q Hj®ýmv*|i1&ë,ÊCå–‰[—’kž÷h¥;/Ò«úøŸÏ“›Jó{Èø³Lüë¨R|ν¥‡»Ùí›{V–Ïz»ÅÀ¬¤â×›‹ î½2’Ð|ÀŽõ+j›­›r&ù"žÔÝ¢‘® ZöIšU%íÆÎ”Øin*†¾?j>…›ÇkmZ·^ ìÚ©÷ØÑè%a9°\ „_ÜšmD<*Ù#ƒôl¸{¦Í€H!5˜Ež4¦ÐçÔõ{Þ ¸[ó˜Ûjçÿ0y0áSx³˜>ýÎ÷ƒØ‚Ó(B: ûŠ%TVYÊd*žÀ‚['Uf:äß) ‚‘W¾Ý-sË.vœ¶gøÝ$ƮȕÑõVªÐ˜"ùŠih]gœÓ²!IÇ”óÞ­Ê[ f™ÎkR;°ÑšžÈÏ - Ü*ß'ô(6+3fž²“¹D"ÓØî„Ý•ŽûíW³«a.óûCáU«Í‰°K<\¶<;lQMaoç4jçå6 ¼¦Ê%‘¡<€.vô¤}”½óær!_Þút ÁQñ]þ~®JZñ“ªÛZ. ÓXýøµŽšâ;À®e]tÂ…Ä"4wurÅ&µå€KJ0p¢H»:ƒ*EnLúØ¿8ô¶F±®:©oä×€ºL–tÂiê/Ù ­UŠ'ã–ëäÉ«ð¿ìcëݾ~Á~|ßèñíy¶«0õ¬-2¸”S _ xzÇ&„É󂸼¨ªQ}@}/ ó«r}htG·èžÙ׿.¤, x9vb¨-»/ô`  iDêÕùÏÕˆ—½yus*æ^•ñÑý4ÀE§†Îµyiê¾Wd2×Ä)¢ñF.pEªaÖŒõ%zºd§°x§5+A+ ò»–·Ì¢ÎØAm²¢ÞôpŽ@¦Ï4k•ßN6–ä@rò£{hmõ¿Úõ nì®Úàfç„’ÂøôÓ8/ä/²¾ Nyç4!tžw‘ª a¾“?¬RÑÅH³“4 Õ(} Yà+Ó£FÔ(o9Úm!Ÿ ·é#I€?˜«õ€$oóLçëÙ‘\š•íçéBÅnܾÉß|0—$3U*œe´U/ќٵjÂf/ËÁ4&Œd?qÔå @‰•åæÖ‹¨(³"82DCWâ8o–Õºæ´D[š­!ÖCØ6G°F[:‹_µF%a¯øè Þþv9M3xËM)#²Öy­¬”㋪ Ö3s¬@•B§.öêÞ|¤é¨Þ¶Ñ ‘ð‚¦G;£[`*ˆ›†þQH™Ûe½Ù¯Gö<«#ÆtP•S!L§ý[ %•¾îÃä£Õ™…kþ’ÇÓˆ{ŠLRû«¶UÇêÍ`ñ3 0Q0cš¦”ëðBg§h‹Â[,Åì}W*v^BÜ_ÙoEy¥Ê¶3ºu£Æ)[þÐÇì¯ áŽ!/V§Jþ¦¶ëàÎ[ï{qÄ99:ïüs)/”ÁÃC÷ðÐÃèÈ;åk¡`òtÍÿaâCÀ`/=ІµÈ÷û:ŒÚ¯4ÑÓ5Æ›;jçió?Mãl]—T .kÓ¯Xâ¥Ï½Q›­§Ó7ÿKŸ6ÝæÂ‹9üüÿ{Ôf/ÙΣ‹\µ¶8ÆçOªúàUèžö`…ѦàB~bè ×W«"WÓZƒÈ‚“Ò²I%Èþ`WöÏ©–‚Š“Èà‡77´ôm‘¦„Nð›éW]My«Àe>iÈܑԞçé1焲igÐÌPZ Ç%ã?Ý” z Å]…À×Eš3–ËÆ_x óJPõ²A(\>8±p-´ ’uÓ rȇ\×>ìÒ ¶ÇÿZÕ›W†]]Í? ­ÂÖÆË©p‹ZV~i8aý¿†õPªˆ-F“˜*pyËXž¿]Íðÿ4²eå_KVØ E4‘å|Wø˜—çEmR¸í“áq»&6T<ÓHò°êÈøŸk›œ.rq&—ùµ¸œ²›%÷˜…¬,+ lžY™=§óŒš·×xœ|•Lú®9ïô°®™÷¯S÷½Gc!À0–ëaM£Æ Ë®¼ˆ>ˆS“ŒÁîe€ô…” ÃÉçv›ÛòMŸI1©M Ô¦ÖñB õO‡” vj‘çÝHhû«‹¼õ «Nn2·ñõo]+:§µƒ7î/z!?~Ÿ¢Èy*ŒÌIÄûÆ­c4eÕ/íkf»ƒc§TDÛ;M·ŸÆZ÷Ô›\cöB*'‘¦´÷ãWå! dìCwÀ’n§º^ñaì·ké)™ÏÍ+[мËe rÇ/d<»~„$áž?ƒrÓQ9J‘¾“s/N“q_°0—ÎÁu}®×0ÖRá~ÑGípÖEäð¨w+ÁtÊ2ÇŠ «îà4lùt«ëv¸]#øù±HЫOž|AžD>õeI´,žßÔ“ôŸºñé3×Jx³K“A)Ýõ1l#·¶6 ¼j-ü%ÄŒ‡­R³•9³H… £e/1ˆÔøŒŒµi‰üÁv@ ƒ™’•ÜJJ¢h’àÂÀp®=±Ð¤|Eô˜É…ÐK®mç _m%‘Ar ’A𠂍åï²j5VÐ̽íjt}p÷ÖN5Nkþ„R¶<ਟ\m:¤¸AF(à˜¬­%•?ú ØU(ß\h7¥ÒšÐfÒJjÃhÛ“[ÐokÝfV:.‡nZù|؉ve  Þ‹-o4©îbµË¯i Ö vÕY=¶Ú0XB¨ý oNDÍ2 "sj¼¦c‚-iW>\ ÚEp×*‹ÚÊ>Ð뜀ûQòí MW¤@=å m¯šJ2©´Ý(†l [FXÌÁU/™úË~̽4q»úq•©Óâ|ý±¾«¢>OEß·¸ìþ &ŸWl×Ûß–Õ¯×ÕqÇÉè‡ööLã·ôÔ“#À¶:aI5qIw€[³L©ÐŒá7ì.ÓNjŒœEVž¬iÉVÑÏVb}œ\—a¼ýÅ?‡!-0W'G?³ÏwÉ@û¼äãrusÝ…þ fÌ–Jö¬ë¬Dì³Åb*òÈNñæCq' Ø2p°RðšxXþ[È=Áà”­Qœ§ÛΉ4¹ë”»¶—{ìä‰Pˆ¥øCÂ+þÝÍ¡dÉÍ €¦a™ØÐÕ’[AyJÊh³M{Ø'K(jái—¥]‘ydˆ•Mãö]m>º5‹?hNìPÄ-ë÷¸’ÚleuúEÈÀv|s§•ž’‚t2¸ê!À¯ü!Ž!ë-ñkŒ¢ˆq¸©‹ÿFîsÓkÆ/™käebrBׯ×£fËHÜ0=Dð "@O? ~¶%×yHÂë3õÅŠTQÍ J\J”8¿a‹azIŠ[c¾}gÐÄÒBtùØëá¢Õö±rÜ–"÷e¯¾ª<ÇdL6D¼²’Å s½Éwwæä›æ&³ÖWAÎ>PM<ÂsXà‚hôÿ^®<à7NrmzÏ|¬ãÓúKL<ö²Ìpõ-“F÷¶.W²x/Èœ£|Xù£Ýy6·:¬É—9øº¢³X‡|ó.ß°eŸôz*“3œ¦ìS„ìÕ+ *)¶[v,¾¥|¦Ã‡å+·µÙsQ†”ê[˜Eø¥‡‡À¡ŽÔävH®Ù!‡êÎØRàüô’l½§/ÑÕÌô-öŽÒ»”éFØ;’KŠ|Ö¯º¡¹óX¡´Òsƒ°?\Žð4]I&Ù‚½Áiå]‘JöÞ–Vjxr`Ϋ…€Z+À¸y3….޵–š¦Î_?dåMÇùwŸ*þ¡]Ž˜¾dI+ž‚ È/øFfgèOÒòÐ+Ò$¶§¶Œ½ãÄ=Æ'tÄ1Ç[™~V¤¡&kjy!¹Æs>åþ_“’µÆïê•„û¨üªîK^'ö”À‹îù©YÙ‹tÕƒ¹üÌ1󔛿ga…± %å{ôóA¶®*Ç–:æð OõÙxg‘î([·Êz)—ʿī ÷+gDb‚†±¶xBšq‘Ï8½ :ªþrdRf0ãõÁjµ¹"0j9~ð2 †1¢CõÃNZ±OM"ÐÎ&CïÛî›ð % ©D/æ¯çI‘Tʱ>Écn/?æñ6ûÔ¹ô›ªb¿rfÑëb=AV æ£ò”¹$€$cz:CsÇ'á~h{>H,¸+h4È à¨ÔÜ}y©S`?¦aáäÓ‚’wäB8òߘ®äª„£è3G‘¨üËŠe°z€b™ñe¯×Fo gN†{sOÊc¹<цۭT82òJó ;¶gÚGâ…ÉJq¹š¶Þ‚úlGD—ò€Ë•P¢Á2é{Ûå»4ø(Tš)¶}Q˜yÄõ«œWÚÿ9Ó£¡œ è{-hªÆ©õQÉÁDø ˆa·”»$/µ»à4é«4ÇB¤ ¹­âP-vIºÇq…ñKüㆠì!!ž²þ¢Óú’QòºàÏÂBŽ™ŠÒT.ð"_»LP4E$Ñ(Éω—œ£Â¶I‰„fÐ…‰ Ú!ÓŸ½­ÛwÄó=%Ók ôƒW=Å Öà¯ò`®úþÝAáÂ3¡_Â&…á¶F»FÓáýã ‚»˜Iˆ¢÷ox¸C¸þ¯¬‰MÍ+µA>Ù“­ Æy¼V—ü7º_Ý žY>¬Œ}ZߨŸá>í6µbaî%o·©ë}ûð*²)aææ‹˜r‹ñ½ß‡âÅJ¿x¼¬T¶|ÛAÏF·Û±óߟù Ò>º€åAAÇ[jz"šAµ^±›Î±ÈCO†ãº¤6²ð(¯LXsðlöµëå )lQv ôÔ¹”]á÷¤ÞsNÂøÆK®õSžûØ ã›Èfæêíg›ÑdÏ”›³±Š%Š\'WŠúœÈ‘¸Ý»ÿ6žÌ¨ú‘IÐz y|K70åCß5pa{u—¨óÆFþ w‰T¢¨4L,’²è÷3µº¢õÓgndáÕ푨—è­HJoú`b*®#Óɬó>U›¶X„.C­,„P>|6ŸëJfŠ|‰C៘—¯¸n±lUì´e5¢²L}‰$$tÿEdLòev’3€Ò<+o(}ª˜Ô_c€ayYþOÈE±0pv–{0uŒ)×€W¹§ž@_+ÝìnÈj¾åºÏp[ßÁö¯ '¼þ”ç!¡,Š ¤ãýe_-Aë÷7²ì´9t’É¥ÅRèF^b‹ŠÀ!ú{Óu>qNe?R›†óáð\Š™eœ§Ì9©•¬rrÖñùƒÓ 9ͶÔ%[úé+2+kI>>EÁ^R•±0³çmÆ-K†ÑÐQ≞+(B)ÌÕÿVëGeÛ#WhÌ‘öÌlkÅ=ëÓ?‚}CÍñ½)ËŸ#ùqEš…a…wùy¦NŸŸ1Ó(nÿùhÉSæŽÿ‹`K_Ü6N.ÑИף›EjhøÊ”iß ®i)O \0¤À$::ï‡P¡,à8Zwí_ô¡f¹’vS°‘ l^tú™Æ¼9Üìüú]_a]ß;·Nÿ.Ò r„tQ~¬²©|ŸQl pe¾zÌxó“)RÑãv]§ÑMƒ †RëÔ“z.e%¼D"0hâè=Fy´iÍçWS¸C,ç’ö9LSšoãÚdÁÄÐF4b¿!;Øëï]uöW?^ʃöÕí©’;"pî7y}ʃ gW)óó6-) ìðøWëïSÞŠMÙYœ‹:Í"wD<>…ÙõWì|›¦ËV°UiWw”=¦Óå1TƒS*GÁM‹œïxÒœëÒ¥ü^¶?(nÿùns݇ìTÿAo1ÁK Éüv¨V7\`nŒS_²Odvqq_ ­ÄŒ:í¨=òÄ´¨‚ø×߃±Ë±r=*>"ê`º=Ú=Ö·‹:þöÃ-ÝÁÖ2€î®ÓÎ#ßK†+–ƒïPBáÁ‚‚¿ø’PmÙƒÆ+æ4–1†LƒÇ€Ë¿s.roëÖ” ¦Cü\Cy¾@"T¥C ‡>àD \çÒ:Rúüƒ`¼;hž4øè`õÔ*‡ˆºY`ê®Ýýã ê s–¿«Òåèzéd#®_9”c"¦Ö³Û ˜IG9w8ýóƒè¶m´ùÀÏ–1ò7qYWàÞÞª£†à³Ãžòå7`ÅG( Ä:Œì'®L•!ôîÆÿ{ç&@£x5J‹S§b߃ g†”òn…ºXÿ ±ÞËÃ\ÎÁK(Xüùs•ÛN¢½y«~ýÁ’ŸÑ!,[iÄ)PöÍHÀ”]È/WÁ]›:“„%\£;Ì]•ÎL…½•ƒÌ‹#f²{yCŦ²ÊHþÎîÏûÌzl3ç,r^ÚÜ 3…•®T¬lO?25®nâ@l²`FKü])i÷[ÄsܶªÉÄ.Õ*‡‰r%–3Ç›ù€O… ÇeäA$aàm[R®”!z§•dYæ6h`»ÄÂÎÿCæDMq„vJŸ[ßœ²lb£Ê¬8›»‚廊V.SºæóŠ‚>|AÌ ª€²AÖýöeò„^£øÅR¡7žvâw÷ÖÐïv•û)ÇëY|ÓúŒzÂqà{ÞHèO–„È‘¦ÊÐ~ØqVéb,°ù¡¤·Eça€Ž¢oTKâÏ:¢ÎìÝÄà£A'§§õ˜Ð9ƒ…rÊ\çöc©b`ó]Ñ;Bô£  ó&f“ÿ W~ Ûf É&Z¹Cýd9´ûh¢Úg=ví)ðÃI|D»f¶]”á6äZüΧÚjÒDN£…å$”\f ¬™gÚgCÃ.a±/†ãb÷˜¥ùF ×kL~Ë:ýc_Ï >;Z97Ï™Ü! fÌ5Y%šŒ%ñ×öÜ®‰À ÷AÛ÷-U”€Æ–hÿíòž¥•nÔ‰?Ê™ìŠ3˜bÿ;‡Õ8àÈU扤$eæ\ËøFƒdÕã«­¨7±©Ó^1jõ–¹q&Ò¤&'@ïjŒ¦5F1=8Eß( >>lÊ‹{<ÔÓpäýÉ‚ðÊËãJ,YI6Ù©8³°|£ü=… zLtk\®äÝß1ø‚SX‡‘£¨¡u…*F5É7£y¾`ämâ`Š[)õ=6>§ _öù#KÊÖ&Œ¿5 }ª8ñÄ»¿øäÚÿnÑhgl}š˜øjqÞbe°=Ô òü{yŠÎÑ~qƒ"8.—žø£,ëájê3¨ñ†€åÎd½õ¯ü”ìU% ¡ÚI£·Þ­uÙÕ©Ò¥ø˜“}„MһᩂxìÝgCÆÄĈþ-EÂ?%XËÀ\yõƒ‘± ˆƒ<áé@ˆ»ï|¸ÞÖÆŸâÏŒ¯ºâxçÉÎýƒ¢ŽÖd©ˆ5Ys g~wˆæ:åèîmGziƒÃ=ê)æ˜ôu<)b³¥µG™Æ¡Ž˜r,!Yö.0’+`!oú/Ì3m$VÊúù X8Ï—Œ¡Ñá%1K”bS·¾|TìˆRpÉÂÒš$j×a¡Öj¾¯[pñïø"’~æ@ÆJ \{I³™?6Kîm›Š!Š_j¶gŒW"b5Ÿ&¼‰²@¾Þ†XyÁ:n*¬nCœ©I¬Ô×I#Ü1=Ó=ܱþûÏT.§Y8’ñ" £e]ìþKx ·Û£+ÃïÆzÎrí»ÙWÀ<ýÇš†Cz ÃμÞ¬³sYWÒq¡BTš‹ËF3þ<ô'. Ä× Ö´š0ŽÌ‡m€ƒ;^v®5]Á¬†¼™í”­ŒJñψm¤ŠWŽ%‘ŸzõU孲˜(k[_åá¹ä¾Î&EÎ1“˜ðCì i†%âËÕöc/Å"®acg0„“ö[)|ðp¯@Bï­ƒM?x@èWá0¾}Z ~[Gp9ˆNW!@‚ÊL;°q’Eu²$v¦5×>7]…ë"1Z“w°Í@é}ÎÞÇT3t²¸ªÕ³E'#—~5Š%iðq›álJL¼&²ø .éóNÄCŠmõ`ÿ_âipiΪџ‚aüéCäµÙ÷æ]@<›8äzF@€ÜvØVÇ6nÔ€ZÀÚÓÇCp´hŒ¤ƒ¼dÊá¤Ñº(ÿù¼Ö…Ÿ›É1-mâ_è\*’_Á‰? )e™Ž¢*Æ/#Afòxʪõ°9jSŸéR~ëÇc­Lp_c$®WÜy¨›†¸)Š é&°"0„SŸuö/\¸PÈÐDOWØ“×â;ëQþÙü¥–|f¹¤’anSúÚ?Æ0ë?GÆýÈ1*N.!¥½Q–%êƒÕ»ÈÂ0ӵĞÜä:¾1(³¢ïz½a\jr:w9ëlÚl†«NuéÏÒÕ‡æII7xÚo»ÛêKÕAê¾!‹MfñaI–­%ûš=€§/ùü<@“bcèñŽ8r|ER«!Ù0¼©En€Ex(/ž:’`ûž¤½3vö#Êó¾œö­¢wø%A‚ÓýȸÀb¿ºHQÊoÞ‚ºI´+å$¾ y%âúÅ]‚²SïóÀ0HD’àÐvB«lôµ9B°]9e%ž ¶ˆ®¯•Ì!M¨RT€…ÌfßbÎÂ÷[U@º[Þƒt>´½7䕾ýÜÿ•õG쮣¦A—Fð~> Ï1›']:ã±Oäß+gâø÷Ñdµä[¤OÝ}ô.k¤™Ì©…‹7s*ЬÞ×BÀÝQtåÅi.º„žëìÕ´ß34«fQx­VèHNiQ….sHdÀ(™±ü>Ô„–9;ùþßp×y}øŠ>cßlEy›z'²¨cÎ!Ò¾jãP° vSWF¾pŸµo­ÚŒgĨoû~ºêëíÏ…Œà(Šjõ—cn†Æ“§$©ëÃC ë¹–Z•ÃÌ–:š¤´÷d#S“¾P¹ç|¨bÙ™Xªf=B.öЮ ”VÀ€y"ðô¤ÀL©mF¯mìŽ(½BV¡Ÿ° >nœé’¯f/u/ñp/˜ fÿÿMS!ûÏar?Ñ#qoŒŠi¨1cĶáÄ-äj§/ðý%üÑ7±YjàJjnË#ƒuÄËmî1#0_´ÔË÷èDÑíûHd-RÁýå“OL/óÛ¼JkT•Ÿÿ6®$ÎÛòaÏòS“Ÿý‰xÏ\~l \^[û1…ª(cÕeßQ7‡Ñ}âE»+ŸUÆôø×Ãõ²¹ éB*:.p88é+˜Ã”鲘‘Œ<ÌÅq¨/G+Â8*U¬¸ŒsôÉê˜ÉÔb„s£j!©*­Üì7!ªšÚ¬,¡Í†¼…>‹±o¬mÁryرtNƣǨ-tbþZÇqâZÑCEÒ9 ¬nnÐŒk±QWáª:Ã[¼ÝewI¥èæÙûs.U)Àž\ÇFiÝ!ñÄl‚7eL À;¸X /¯½¥êÉ–pLÄ×^™ÂlUökɇŽ9«»ÎOÜ¥dV®Ó/ˆôXi?ý–&Uu>aô×0ĵOå²ÝÀ¼zÙ kOl3’©wŸ#Ϩ¤¾²F0RSAìnk· .f 2YÙõA•„~|6g×ÀÂÃJüGî,ºÉ'ÖQZËN:ÍQdwQOìc棫Ý@ƒàÛ{õ„Rcû¶lbóÀœºû`€ø_ÔVsÅë:êbùñ§nÿn!(†&vVȺEq…ðšE2}ñ9ž0:ðÜ~9ÖopÔŒªÒÄÙ;wc%j†Æg{Žº ²PÁ«!ö‘Ÿ¸B,7+š æc;GRßò‰ËÓ^-ö?û먢†E õîÀÉݰKœ®ëËn.úN®ùd£[¤ö ¡ÇÖn Ï{ˆÆ),’ûeÀÏO½#uõÇ~ŠæšvRXžü–|®â|+ïÑpÞŸ¼^ô óñ1Ø‚]®tBåHŠL.:ö•ª©~u¹Ö´Û³DdÜÞ[œ3Ý—;v$Ì ×@®+RW.Àmº•z±ùA–èFÛ1šJÏìßÂ_á»ÙØwEü‚A1Yé–Óç`ueT ÿM°|±‘°"QJxC­˜¾ ´”0—®ÃVòÚÕÄ2_òdnAe=ÈáV2«ÇÓõ §u/àÄ;#a9 ÎêÔj¶åÝ›æ·|fÑ ¥œ‚¬s.Óf.;ôegãÃb} Ö)µJˆÔ/×ý‚*Å›2µaÜ%ÒS¯NTŽ…Î{Å t[øk2 —ý¶LÃ.œ©-šâu5UŠÿ@èßö•#‚j¾=g˜êl,Ûìźh‹ ýÛKO¶äE'›¢w­Î€šñýé:¹`…¢Òl)WŸN1žsËF"i.=cfVHðÉ.L¾ì€‰ì79<Ä”ãPƒ´œ ÛÚ2{2÷LJ.EÛ€Út·¢Ž8¿“ØÄü]2Ed¼…A¼¢[°šHÇ™+'ÑB“Óžñ“‚*§dI >'¡= @Æ R â±ÃR®E—öqŒÎÏø·Þ©:Ù— ÖÁ§i”u’;Á:­L ÛB¡ÿ;Zä1P-Ÿ­í-hÈ.ÏàßÜt¯˜{¯0¸¿g±Ž-Tqâ"ª„jw›]KIp%ÄÉù[n}ÃS3óÕ1.ª8†P“ûì?’w»@ßegŠsûX˜_ZÏ)6,>`ÑZpf´I"#;–x[Ý“Ož9ÖToð딥egœßRW€²e4Ø9°{‘SD:ýá@/,+ù51#hÕ´©OSN½îÂØCI\T/î-«W¤ ñ$Ä„ G&»šY±è8ÜëÂuÖ1åcÐ@ÕŠêNwIæA`~Åghwù-ƒZFÛœã«?Ñd4Ò Oʾã¦nÐó3ÉûE˜¿œº¾¡¤SzÅÙ2 œ¶ãÎcošÑnp¿«W”¹¼NüAIë íGq÷ÿ,PÏ($Ñ«•c.L§µaÚ IóÐ(£u}üNþ¦ç® iÎ)夢x~Œ*Ø®išÜ Ø 3Ôåºh,SÜ2 ¸µå×s»Oô”ÅGâ|ûköÚÓçíïíìË?†¢ÿO«ª{íî?ê½ï¶ÕŸ´îpã·ôÔ“#À¶:a§Éç%ºêd—Ðt¹ßµãGüÌÓH§òŸÕÌë Ðñt7½5FÁ¨»ÎYm´“" ùâ²®ÿl;o&êÈ -2,\ØŽx-ã”&ÌO>zÅðk{&( |§UöÌÜSÅòní÷À㘺 ½ºQ¿µZ9ra?XIâaìæø¯?œƒC`¥Ȼі?ÖÊ9Û íù1õ, º¶òL†rCg5_8TïuŒ¤`/ ¦¾y5£6Îc¤¾€‘ŠÇ]n@’b‡+f8J˜>%õ1_õKEVªF½ˆ6I‹QÁŠw^E (}9¤Û°ûývxæ&îWc…rÍû˜œo™"o¶Y&x–J··KÊ¡”+ü¶´É¾rßãU(„âê¹zmðM)bnW¶í»zi$J÷…ŒTé—Æf†ˆú¥å'_Ólƒ'?@²*ÓzòœòõðjcßÚ";3æYÿ0oȪ)çRc©çч¤u‘ïæè„~‰nÜ8²Ÿ Ÿ±¾-_$ò²˜G»Nîûìƒ  £å,LtV÷ Ê92/# «óyžøHnmµE˜Oóý°ž6H¾±H+…¾l« •…¡©¹ùìñ¢a-òÆ+ÛöC‘Ê®6ÚÙCJ®Ñ˜(a!ÿð‰RcÄ—í´Gx03×a¾Vz!tqÂE32Ñ«QߘÖ&­TúVºÛt™ãµðÃú„nbDè*Ý T2 xº3ÛºýTb¦Zk6øtDç¡Ñ™–t’þ[û70‚œÑ͍KžRÌ® I ¤µÊ¨ »0œÑ ½¸­eãwçà—ÅRŸü€y“,b?í-z>—Þ¶Ö¦ƹÍRYIK W§¹‡W‰€!âv¿,ae!ä=XGä–|Á<ЭƒuÆÐÔ4‹ïÌïÊ—±M >mp8Lâ½C‡tßCîø™¹¶?Anr_‚½Œ*¹ +,uô?Ñ< g¥¨uàšHÞz ÕØŽ2ÃáâYš1„ƒxûMU 'îƒÙ²¾]èbƒ8h  z™_/í*=&ÕuEªœíLP[ºðBg žu‘†E½X©Û¿‚.:ßÍøM`Ï­øÅQYG²–Dï«ÓxQJÌYså·µÑl²S"K2dòæåö=Ô¨·S·—÷H¬Wl, Œ±`ÑÎŒQü=~ F@ûÄb#‹L¶· ù­A(Qžò‚ ãitØE×iþSw3$ V$µ@•{œ‡hÞÓmÏÂ<¹O¾×1÷#÷Ê<ôÉT,Œ¼ª¦;â+ÍXÙçňÂŒ‡ó×Õ˦/úR2þP T;þXóMPу >ã>ŽÚ2–ú³'ˆ” ?õ2¶î}ˆUÂ0žîÅöÖguɇaErûµ˜q½“zbˆýix ‚bf§uÕGTuÎD¦”ú ÚÅcKŒø>×rê(±LtkãÑ0Ô~!n¡6ÆÛ—"óyû*å §'X9áýÏ;­žô3Mé—vh&·˜ÙE û~âGÓ“ j+œU7ˆ‚I‹ÔÎc-§T%Ä¦ä–ŽË Ÿ¨‹»LíÑ9ÙØ”dö @Uéà/\¦ Ë M!*‘$<´t¡‚uªgÔD/Šè=>¤¸t³MÐ57RëtAI¶·'lED‰<¾‚D%bª¹ ÇÜÌüu¨{#R["ÐAT÷8—ÊÅ?U,æ¥Ðüµ¼2_uýú¥C¹cðÞÍÄÑ;cV5‹K !`ïæ‡}Ñ€±Ê^f6U¢éÅmüxîŒËØi‚2ße‹÷ÝŸ`±&~/oSx"x ºPžGß Ï½Aü…enøí;Üž‡GˆI1²lóöÔ)•"|ôÓ÷ö³Îxs—€%ÉEHIH*e\asªÄԦࣨ¡{C.F=ôdÓ &Ë]L®0ѵYú¡çz¹•ólhzq¿“vD’£ºFB"’ò•p{éFooí€S§gïäå 1>|ÕǘýRФÅÓÔËTϦ5_(nÿùhÇóã) ì™®rLA‘+q!òCÿ4¹éHD£Ûï–ç“åÆ?†3ïäQPW*’x¾Þ“-CŒ‰w*ñABÝMe5ÆEåÚ°X%O.Æ<ýoÔå&àç­];—ƒÆ<ãx•c‡Ä^¿( w°P3ØFô…]ÊÜ}Ãû9âH,_ .lÇ kª½'FÓ|i£`wghF¿íš–sy@ðÙ½ŽŠêøÝ„‰`²æIT¾7ð‡O7àÏÀŽ×Ö‰sUQõyÀçËÌì³ÖB¿=3~ÉäøzÍ~º.s_#\4`jF=šµôw4ùjï ùŒ]x¬?ìe¹¤Â‹Å &ØÇ‹ÄaS#ü‚ÌK³ª)ì'÷,]íQãtŒƒÆ6y€4k¿Ñ(nÿùns݇ìU 7l¿»÷4¬¦Fל"²€øª5¥Ù§ícÆŽøî€©«¤ƒ»MÉó˜ŸÀ&âü­E¨˜Q:€I±2ì?˜Håßÿ—ý|:8m¬ö´EïwODkgé›,ƒí‡‡ñB„$vÃnÓ“iõE3ní–0y2†¨–ìêÔ ®ÎyK™eXéœúTS!{S?åL˜†·„Г¡WõÛñ7PL„¾ÙËËO[àb ÔX®bwy—ÛÂÖÿzm¨ÏË­ã:)-WÆc¸¢²µ=Óë·<+¡Û(Ó\€J™SÃÛ„&> 5¿`$‹ýÿ`€“„†ÿX§%÷ªˆæÐÍRÛš•îø±êðy°ÃÖÒFsÎÓ×øY^t‡ÕE²É~OV5n¦XV,*ûÓT½@RÌŸÏný ¢BÓ„?ö;¥À›ÇÚW8 É›L/OþM^¡þ•œ¸‚“謊{FøHMúHÙlÀºÍMÒ'ÄÆ{׫!¯À0}5ßQâ‡,1ê¢Õ…ÕÝ€Å&@Yû½³Õ/&åPó°i"A€Áó7þùaUÙ=Y{íÑšÎg™+OÜ¿Ö#૎pç"¹{õýŠ´XpïŠÉQ´®/8vòÁª>ÌzÜÅÞÝgºÊè"aÙQàÀ kOxÈ¿¿#} šS ̘­ƒíÓÈ"]jû•“O{z`ÍÛèÔ»“ÍV‡µÃù=éá£Ár“¦èÅ&:¦™*Z!Ä—ïWhÒWøÞÙŽ¯ël¦‰÷às͹M¡A•á|ê h|ª?7ÁÂ-²N ætÚÇô¦#«PâÉD k•”;,_F ^›¤0ʹóZ§¬!eqÛÉoô5¥îÿV¹<.j‡[Æ=MHŒ]ê”cØŸ;³¬ °€¼u¥êøþ=ÄhêJÃ@NÛh'{Ò3q–­cÏ :wu¬c‚}=öŠÞ@9æÏ_’¸hê{Æ2ËS¢õ íÃ-ÿ#7¦ßôÀ©í]·”:áãŽÄp·¬hƒœ]YÑHŽ,1HW|¡qç5š |Oõ¦2¬6n_ø(8;<šÏ_{&›P#¨?v¡[0Ä­vͱáªtÞåR„«•¶­:5äg{æ›À;{< \%‘š<,¹ð‡K$øn:÷"ÍÞ#«úý<ß6cǶcº¸†>–qw;®Lrш¨ª‘pËÆ ›H(±`5£çÿीPјü(æå„êcñÁž6028âÚxáM߸¶ÏL`ú |¶$Jˆá0-–.ã±ð×¼µïÎ4Þ¥9Îþ}GA|›IÒÖ§˜èð/·5'|Zž8_“lØŠ¥Iÿ〰¬cÐ$ѯ¸jmgIÏKî<ÛT§Üøo`ihU‚ç´4´%§…ºº1ÄdØt‰Ë`‚ާýOÒ¾†Ä‚Ž$Éb'©°8Ã-°7?"OW†ÌXšä¦þl@>ÊǹÊYB\ÊBã·t'€fÉI« Lö¾µ¡†DdQ¬iy»9#ÓºWQkªŒÝ…lpd¢éÙ»žr“mâ $—Z‚*uÕNÜÌq‡8Îj›hvJm4šWŽœ¥ÁèþÙ_0°NÜ’s=rÃ(wÇüYžöEÏpk´ÖóÅÓK„©¨Ëê#ýbù÷Ôù÷|¤F«˜¥jýÓ<÷ï"ŒõÖÚp“×. î»l³Ÿ©žW8Dô¹E¿ë/P¨*üV#¿ó4øÆVéâr'ÚK=ˆMÔÎ2r ·¥»“'œqW5YPƒž;'ºÄ†µçÐ-"„œ£êô!Åç¼8ÂK|N<ØE•‡ÔÁíÏ–,}äà§ /cq|Ú”QL¼ÁÄç.Ü,‰Ð+æ'¡DÑi%u $–0&ðKÙš.ë‚!Ê[¸ |[ÜrØ^|.VÝO5ˆXn hVë»6…áî`÷S'Ú.ÍÞ"|ï_‡üÈ‹Ÿ^áŽ"™ÓEEnÓ 7Hh"ã&aJzÃu©ü$4xboÇR‚l_hö½Í#r&Ùdzµû¼HÇ€‡jô¦¡J–@ö²øz\²›&åÕlËäß+gâøø²‚J’š^M§L7¥ƒ/ †÷€ý:îNp;cã9ÓHͶ÷µäÑsÔ'Noey÷–Ÿ¹¡…ÅYne—ÆÐØž\¯¦ëNÄ)ˆ¥T” Û®•Ï@HÁóbwí©Ú½iJ.¯øOÊ.H¦¸&×`?;¢³æ4 …ö’øDV¢%ZNrG¾|LÍ é7ûêž,:lÍæj£yÜ‘«ªÔ7o›»qe$;B—©O¸•±‡wMãÐê§Œ7e\Éc¾§_Ø©×ÀÏ ʇ¨®Göæyõ¦º4*`–\Â×âøÚþ»‰Åñ­ÞÊšå—Í@ËM£”h¹ÖßÈi/Z¨‚ª¼¤Wc€0Ãÿ„OŒG܈çÛÃSç6*î(â)Ñàè¯cï¬ôñj—;>¯\’©`ð´į޵á†êøÚšµï%öÀ Óq·*u“1Wã͇0а™œ†w5"ÁJ±úa}*Çs¶.ÿÝ7½S5*Šˆ=rÏ稽Үp1„>¸<ÀF%‹Ì_BbAÈH½úÀ'‡žT¥S¨2Ka 5ãßå}ãdN Cdi Ó[5üðN B׈t"8á õÐwx4÷«0'¥çÈÀv!¨|_w"½"©röT(y ¥všm-^"\ù}J#šqñ4¹½ ¼cì´U©’@DÈý ìþÀ#øÿD‡íøP…?iT÷(nÿùå(nÿùåøPæ„ïT¢?mÛ§åqµŸøO¾„ïçÛøO°0ßÿÙic09Qj jP ‡ ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cÿOÿQ2ÿd#Creator: JasPer Version 1.900.1ÿR ÿ\@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ]@@HHPHHPHHPHHPHHPÿ P)ÿ“ß…ò&eüf5:mó '\n­úÛC ‹•Ò|BúTÌ5sCƒ„‡¬TÑæ]õ+['ÙÙüÒ=R)PËô|N§†¢zx‰¸>Q¤=2˜zP>Vfe»´“vH· yx'¥ä–ÁŽ`õÒ ±²º¸½»ùE1_ÔÕ¢ÿ}õù~¹bĤç7(æ=sh¢v~ïðöΔ¦L ÕcAO-D$9$¹ÔüXñ‡£NZG1º‡ˆ<7Í”qÛ[©ž0ûÈx¤˜Li }«`f~Ûϧ`‚ÑtéÖøÆš$â2üÁ·†RÇ ?tÀ­Ão±Hù÷Ø0ðwp8¾«.¶3m)ì¿ß…Ö&eüf5:n(ªå ´>ÈzÀ;S*©[¾c§A×›ÆÍ¼o¢ 4”f>¿âh÷Åú¹Ýƒp§33> £g8öü9y·lt_¨RÍV'¥¶Ì³)ÄϨóEkuµúËD´Þ{ë©Ã:ß×’«ŠOó1_[1¢nrlôä‚ì5oÒézz X£;ìÖ7Ô½±#Æd–ÊO»‹bß4 ;?ã¿„Ÿ–]«€•Êijˆ®ë:1¼Oî·4PtþÕ\~äÈz¸ß}'Z;6Z|"YºNJ-Â=¶èTKå’¡:.7 ¤EJYxFŒ’Üœ¢}YFÜOϸÿVà#ú5"A?yn^ÁI«j3š{2ËE'L¥â4šmeR¼§ô3è´²‰m"þY>¦¡÷óG]}’…Fc®W`Ì»A…8,N9YVGJÇ$¶EUÄ=$5§ œ †`Ññ•T0VËpY0ñ#c›ÔkÞ¹Nˆƒ_i¼ºµCtÜ®/=uø6Ó`TfÚ£%$^];eØ[)ËÏ‚Ÿ…w?:t­"=¥ê±´qâO™ì¥á°©mB5EæL¸vSÃóü«ù7 ™ Œ¯kŽ å™@d|í£ p%;ç0¶œ2‚²Žwÿ4Ö͘9ã½$+nüç‰Ý²»}ï­¯K^FÃnú}n³•¥U´æüD™— ¨ÉÞ“ ´©ü œ„½>¿âhýð ¥Z‡ÉŠáµ"Iät‰“è3å„l½¤Œ¼¹ÝÉ)+¶¹‘(<}ßËT±= ¿®Þ1S4†Ey3ÖÃÔDܱÿ‰%t\}c3+#fl”ï)ïn oèÓÁòùU9o›n‰mäRóU…Í÷ {k‹ZÏÕ¤‚Ê…S¢,¸Àͦ ©yM”èû©ñ\¦oï'Í´ìÚQp³ªzræÐdâÑ+çZó¬šj-×;ƒJ|1ùùy‘‹_œ¢w‡|Ü Ò=¯ùô^(xE˜ÂëeãРȠߊžQ3ìÚ¯D¾Ã`<ª1 s™’¾Ó6;Ì<í{–ÐUT¦GëgM“6´·_Ú”J©“À³‘]Ûú¤ûn†´6:ý-{õ=Nˆ“ÂGwÆÏ¸š×¾ü޲¬#Œ:¾’„Þq•ï³=Ô¨¨l@Êw"šÊ6Á‹÷“ˆ&µòÿoÏÁê~„üéP‰tE €Y{ðߦ2ÆjuµŠÌ~—Ȉôåøt´Ÿ4 $hí^ҩd¨þ£Ê«¢K׫¹¸ @Çèöâ]<´DCâˆg"·dáoE‡bNÄ~ÊÀ;áü \-ö«íÊž90•ûF^L.ÔŽBç±ú>¿âhýy§7S¬ `¾&Ö~Œ~s3÷Ó ¨Lk1{Ê¥²ü°CTCË;ìºâ½Z0TtuñÄñyúП¦´°>RïlZj#»™É ”…S Ç^7óv“aª‚ 3@>ó³Jûr‹IhU&¨ïå‡5Œ:Íã&FÌÀc³2eÓ‡Öi,‚íqÔß“eJÿdIö"ƒ†ä¹ÆÒ†mè ƒë?–Ç—eÓŸ¼`;Þ¾T– ¤ã2JÖ; ÐÇzÑýÈž]ÜkŽå[f=ïz¸q· ¿ýmQ¥(jmÁm¨¼ŽÄ¸¡^¥‰•VYô¹.Ä+ñµD>=ýƦÚLˆIµãû>’ŽûJ/¾oÓ[ Â…]ÿ1A…d0Õ\†ûìÕ›ÅÄ8Ø„xë©õ¬•j~ȧà,>ÂÀ4¿ðtEÊð@a¯¾¦ ÏÃ`/Ï¢©ùîHÂM|ñífŽpŽŒ´ÿ<ü|(ëI¿XOýP<çg= 쌎?0dY±ÞÂ=ŒX¥Þƒ7ÛÓdŸ´u=ï©Ï£ºù2ÅXÎçÃøìntTd¼ØNݧXvyjÊ¡EM-¶o˜–w+¶º*¸½ÅX¥î™ž1^;vgù0ƒäÆ©™‰.éÒ•>™ˆ -ÂÇ0,’øé£·–EâîÕJ&ð‰’©© 3S€q Œ8, inöé>™wÙÃÅâÿWÉu“þ4ìjþIÙlTå5hŽüè8Œt ŒÂ"öþ¯É9þi²Ñ>Zÿf—ó©ó¶ ðÅý„?0B–G’¾ø—Õß8Ë–W#/*¦¨“éöbÙºMÀ»ôb¼”18ò<þÖ/Óÿh¸ˆîÔáúÈ™¢ÉkºûZÚôqý²pmœôG=h&ºžß2ÝuãÊ} •¦QS}kÍnHê(ÛëP¾É¬”°U…Áä0´‡Á4 <âWd¦Ðëº?á_þ»QøžJHБ]Ô@¥ÊoÍCmé`t­Jîà˜Tçê°N¨™îä]gÞ¥@É7 t&{°uÔ£eóÍŸÃßRr¹8# áTÚ]>n’T´° èÃ:"Ç[öGhºî›1XQ WXâû+¢~ìOw¤Æ%ÈÊgaD×lÕµk顾ƕ=S)Û͜ުoïÄ7­fï¿‹òúÁË.}ÊRØö`õ$p‹vøÊ_Œ¢)æ<@dÂ}Q óïß a©@ZÎKü¾ÿ}ú È»ÙÀjw?Ëó\á«Ó«HÀCBÖê׃š0©¾Ñb +>üb³WÒø 6ön€ˆò'ùžjÌQò vÈ”¾íµ¡@¸N?"ΆÒ'©8LÌC÷X¦1ÙSêê ð3ê–TÑ¢i0ºÑ¨ËL:x'ÝÊ7usKnF]ä„á3&‡P¶5eøÄåψp\¿<9hC]­Á€þ‹R^pkSu¿XŸ‚pPË=ÊWð°çr±jŽ#¤l«õkHªxß…°6[¼šOWR6/©þ”=4šôêä”p4|Òôwœ‘2˜–•Aev&"{ ×d•í‚JšÕèúTÉ·žÔ1a/¿ \(Á½û3íÈy!˜5~^Ï[qñ︞¦A>!Ð}-¥`2¾˜Ít\'ÓÝ  ©ÄDyMÄŸÊšZT Hó+•è»K:W?-¶8sìÕŸÜႚn„‚‡âë©/úR(.×Ð8è|c•Îû¤$ö¹…ž;y Í%èMÌCÅ;Oç’‰_õYêj=cÍé#t/ÆSLLOv7Ý8^†î4´°Ò jÓG‚@GÀGA·:·ÂzºîZ?R°çºk ,ïø/UHôc j/#P\WÔ°ü¤øÎ°º/Š@ϳ%Ê{RŠÞåiµõ]ý³ä‰íggZp± c~¨6#æ‘ùó—šìÕPcá!ezN ö1dŽv{µÞ ÓK|d*xœš|êî¾”·õ˜x²x‘À_´~0€â­@é:.…SôÂÈÌheÖ6ܾžÆŒq/}ý©ž—P ‡¦úr$”=±êŠaì`pï¯/¢—\ Ê ªÌVدÄOT¦ZhHƒ@^ÚðiÉˈpb -G®'ôìäaIö¶Ÿ,ß>õÓÍeî ¿®­·½fÿÐfÖê†|½”1…hG{—äÏ î.vf?[ðÅi9äîV¬u¶„U¥ßê´„™˜!¡WpÈ´%0)Fgv%BðDH)õð¤(ÌR"y ôä>m†ÚÖ5O—à$’÷&Ö¿ÏÃXçáÐlüöÔãý.G,¡ßØ&C’iÞ®‚_46©=öÂmúmƒ¯¹S¥Åú Å#öS#CÈë‚ÔŸu“;ÅŒ`0É#]âå6Sx'vn-?Ÿ›ƒl®‘×Mu+Kjà]ú1„;t'åK"ØøÓÌÁÌO“ód]Yl›ê÷däÆ:¾€Ñôç1KßP©4Û·=‘µ»Re!јVZ°„1QjÎuæ]nñÊþ5£UkÔºŸ+Äý¼eîè9v*óßQX>Ç7èéÉ ?ÕQNÜÁNãÀg] G0jØ‘}JTÅíÜÄí$`žòJä)ó3ã/PE^4ý@„·ëïRÞ^hGÃF­$Qêp0§0î-ßпw<…"Ç:ïëïG)·ë´Ûµúà‹‰|ÓÜ<­ÿ'«>Ò÷„ž4ßxã9Ê%ÜÈ.î`§½óµ/ãW¹f Ÿ3éÿf|”´VÌê ¨öÆüLK”÷Vr>ÂóOÉrQ…›Ë' ®•L8QE[/Â1¨È uê>¸sÛå釣=‡Ö–É`µdÊø\"ºR¤ØªîyIK.}­qÒº%§Ø¨^¯0Z‘²×ûÄHnb¹uòòèò[`½ ¡ñºöàV€‹½*rúr[fè„÷®gÓÿ…³åês? ’6UÉJ0 &"ÏÃV/Ï|gç²@ÂM|ñíT¤¸¹Ð ‹-ÔŸ‚Åä’÷~JÍ ¿5ÇŸÌÒl,RN¹þ9úrÞx/ù-[å.Þ#SÛfg³œ;:¨>rŠÂ|÷ÔE©–µYˆVZÕ3ºËoC¼n e—¹C:ðØ€žßSÓQW:[ÅH#ñå¾â)m÷IénâR–¼Í¥½ð\gS3WˆÅßœw"\` i¸,ÿ1ú|mEú.üÓøAµÉ-ÈôÞ¶/ j9»ËîõÚµŠxJJ <±‰,è~»I¾÷W.ÔþÞ7XÝujÐGVÑx+ò*!ýÇÄbE#ð°/çà¼m¹æz™Ô$áË%¿×°y=¨ÝÖ°u |Ó]ÁLÌõÙ)(ª Ï9‡¸pb±È!‡TÔ³³€³!WÉŠ.10Ü&Þwkõy6Nè–¿ ÷0¦}ñÙCå@Ößy4|VÎ9Çá_þ»QøžJHБ)Pgßaº“˲ÐCá½v+¡Ðª .~ÁÕÑîš± p ŸàÕðÑ[GƒŒVµX{Av†2j&ÑUSÐ[bÙ»BFLH4A§ ;3ó>Rˆv‹Æ™ádà'¡Ì§0!y¢J(¡v2+Áæ’B‚ц ·}D6g@Óà³ tôÉ MzÔ*µÇÛ­á’‚y^ÇJ0óCè‘A3Ê?/go"˜EÇÈŒ¢‚•)˜!Ñ<ÄØ6ÖÆªÇ$¸¨pÉ{›J¬ôªÔk(¦7I ‹¨Î½›"ö¨ïÆŸº(LœAÕê5„ùo–H&H*ÖÉ,ë¢Z§S0øðÐøž¸øX„M_¹áõ}éš[¾ŒÉÜÛŽ§d訆ܥ³3:.€*Sç¯ýT¹ß_‚d%BêÝ«–V|/æZæ°1‚¥Å&Ù_íÃÙ¹Ûî:ëg¿¹Jî¢Ù°€õÑëMìˆ,W¯ÎoÃn›«·R *ùa.y1`³íŸ®¦å1Æòrz–‘—ñè1…ØÞý!((¹ü½†¹kï7¹ú uÍhæV Æp¸µ“–Œ+×ÛšƒÔ†Úè †*‚!%Þºf–:àƒÞÞÅ‚_‘á:9èr9ʼ+3Óº·‚ìýáï^Ž[³=Ä[¨WÇuöD!÷·ŽªL)[±M:züsh3©œûÌfÛh3@ŒŠks-<2{Õ%a ÑëA¤‡2¯RisɵY“šxb¦Á–ÜÊÕ 6†¸!š’æ Dø 4m,ÈÜVáÂr¦–ÿq1÷nÎPÝ qIâ|šâ®WÂÏ´Þ´Óôè ávoVô„6‚qÔ—4¸ûwÈ2õÝGC øwœ³ñwz{úyEŽŽ3ì£'9B)©òÐBû®Æ£.•x›™?u,}ãA]§]ÍQØË¦¢º›¹.“¦dVWÌcÞøþ•p?¢¦ `a™úÇ‘šìd‡¢Y1†¥—<nEƒ¨Šd 5üc6M¸mäü—À¡¢Î'ŠL#•=]•]{¸ñ ©ªDIÄë—ÄÝ6a §ô4ršñ,91¿ª‚Ùq±.‡~Á)hºê°yZ.„WK°qø“oíú7çØù”½Šr r ÐaÂÿFk ú+ž„ƒT„{I%µG´¨ˆû—€0 µ7ï' †ß(s¤+†Î ?áŒQ”ÏÃÐ~­øzI€êöÇŽ„;§ÃE:yœæ5Kb˜DïfáD߀{æCB‚_¡¯™6¡Ä¦¦?Z|BÊ,‘WÀ¸©8¦mƒúL=Mg¯¿®™|äÚ,Ö™ðò¹ëNtý-‡Góe'À‘ï_¸ ¢á;xÖ|ËœçJ‘︪ë=|%ÿ.B˜·ûÄS`V俤@eû¥yv”H¢'8àVÇ>—ÊϘãÁ[´䮂{ËrΘd=ãO7á£äI|³¥½nŒF#ýº_«®šDlä5½ ò!Ùû&¡Nu^Pÿ?PcÈY0]rý|Š”þ,ºŠÅïýåùA{øúJS”Å‚á_ï|<ôRd_eÜ%%á{ÓUÀAz´êChõ§øµL¸2çî²~ë²N@;…+*гÀÕc¹¥³ÎÇÙN<|ð5Çm«c*Ç`Ý ZÜŸ²AWt}ÙZ ÄøÿPvbW¸Ôá0ÓÁD€» AA´ig¸Î ( H¹?§‘±!m‰ÅA÷F)ý/”"*wø×™fŒ#w’–i¸™å›}¼×N!Š‘k½½8eç3(YE€k®°Œ†Zºî­x^ï©2.âW§Üðlv`çèi±R¬Åz1½ðí‘2U¤uüc{Ý[ÎÜP:Úa¯éÉÆ(¹PÅwðêie{÷E¶—M2”Dù"®°HTŠ’E_n~D†äø‘™þžOlÉyJB‡¨X¶ma“?¾_Äl#ñÚΘÐfÊ4ñ†åÁ: îùÆL]Œsõ¨`tðçvÄŽ×Ì3‹×»(ãêÒµÄV‡RtfÂg¸×¿A"*jRi˜é7–ôÙŸ” $:@ñPt\q£?ž\(„‡ ÷à ×GÔ$½óŽÞiG'5º+ž×¶Ó@š^æÏÊ1ód€gEZë^oy3WP, Ÿ ræGÙ¼ëõÅâwF¯¶T?;ìµæÇŸQ¬•÷e)@_e`/†ê<Ã’Bò@x¹{Q;£Å/çߘ³/¬­B¤¨ÑÏèÁ’S-¦ê„±àÖ„Ò7¯žúp'Ïèò9 óga n½¹]}h âû²îÃc¦þnCŠ_~²ÖX¢¨²B£ûÍ^ šòR:U—М7ÛŠ÷ÙF2ê“Ù„(j2ÚÄåÂ-QBÉ”ÅQEæúüÀ£ÏM^RŒJœ®E½”Æšê–0ï„TÌfscý‚‰éú ¨­"€jÆ @ª¶ßˆ4ýÝ8M¥2'†´Ö•½áC<.C76el™ÊðQVRêR óÄð[=.ŽºÿtrTáð™èµûØËÍl—’& .àù¸rVÊ«–pa¦ 3Æû©€WD\çõ¿ùD¬È9ª ¾¨l틸³í'^S¼˜8$½õ Ô°keUk’³͇ܤÁ•†9½crÚ„ø%³]Œ½¦XXÉ2âåÞªÜEcšgþ¾ç ̦•†xÆ„wJðÀ‰ºMué/)Äÿc4M‚9lŸóÙuòÅÑwbÔ½mºˆü\à MÞT%¼ÉbUA}¤è\p–B+R§+‡å:1ïUR¥ÂéØÈŒB*­ü üàµB' áQ¶ÑD6 йEÉö¹‰? ›î-Ö¶”ø(¼óu°)?¦ˆlp ýrøÐ‹9¡£“ŸÓÄz¶Ü[àRoÿLyõ¶&/‰>e%úŽ—¯Ê…W€0eˆŠÑ}œq€ÂB=ß(MGã0Ø‘P2 _á ÈÒ( Ènògð>uQ‚,¸õjoS•Ñ8§ñˆ»Ò…^¼‘$¦Œ¯wÄ—‰X’8Þ²Oÿh/•šžà™Ö½ÔÔŸq •|0Ü4ơӼú>gD]_\”tE”5ê7ÈGóLÒi­rÃ’¸pü’X"Ü·::ˆiîV{Œ…f<ú÷ ®p·è¿ÍÌÓ‡«;¬ž’訓fê°B¯³°—H·vþ\û”ùäBå“°•¶àÒ÷òsø€ël«èëAc;®¹»¸Ú¸²»÷qúÒ@2ä«î>:§ÓeNr8ñÂN_[ì…˜ä£87…žû–GÚpkƒ7xx ЧFç6™g6΢ó]XPru,銚z»’f^õ ©7 qxR¦ÇžD3y¾ŸÈ5åÌ€¥9wíŠb­3ÿ âA¢ ÑKƲe+)x´äîÅ·’8sëe¦kèí'×ÎÔ¹ QIÚü˜| äü²ðFÏàÛ0p¶’—‹Âw—Ê0cäü8<‰Ò=#Å]YP@¢ŠŠ=˜—0Ò1X žUt‰®- O”"ÌÚÑép°«ø<^ÁpéÜNµã|ãO(ÔËòMI_Ê©B•¥²$Ë/#þµnÈž»Sû™"ºA®Üx–_*#p)«…½B™ Î«Ã@€(q‰+',Á7Ö5Ñ9ÖV¡yêUf!KÌ”§ 9VdI÷æÍ«IÉb°UH|h•º/t3<I´û•/ƒ®‹m–YBt¢+ôâ<†*ÂÙ7(Åvc 9q6{›7óÀ¶ïø†L”Úþw‰›$ÎAbîjþwàÂa£ß‰9O/SïÁ—¦¸\«Š õjÎ,‡9ˆŠªT$®é; vMtÅJØëf!’¿ÊQΙ`Ó»ã´ÇUrâæ0xþÄ=ß§2®mOó!´eû Ñäì#…7˜8wëô˜!eP‚nó{QÖ\%š”‡-Û§V†SF‡7ã$-g«PÍ?9NæH`3³·ïœmhÅ­ZT¼MqÈtÌæŒãÿ*± ˜¬:β ޤÊ3µtþ  þ.Ñ¥ãÛ$æ–éÏzˆŸG‰ød ö¬”ÑnQÌh%&Þ./°DÚÁ߬£aä:Ò´Ýiq…ði¯ #Y¿nÎvq*ÓW`»ÇFzwpÅhf’ñ®$³3¯-W™YrÇ€ÍUƒf¢È&»\½Uâ¨L"¥QÜpcÎNdgüÈFÀÍ–’CëüÛ¬ÅÂ.ÑŽ4âP~Ì¡FBq•w`û/øÂ·Zo§vr”ž^éWüWVÇ‹p Í!ݸ†ù6Q‹¨©`-Ö?¹åmõù”¯Ñ·ZþYëøÎEf ê.•‹Ö³¢gJì’pÙ^ÝõŸÃnÇV±##Ù8Ÿ®™`Ìô⎯\~Sñ- ³­” ®(ê ;à‰<&z–©Öc«ñ¤¢9Wã¾ÁK°X–|˜™c”‘7Ep„Âé1àï¹]¼^'$¡îÅHB:¾ãÚæ2>¨JÂA |«áí3]æ/VÙ@•ºo6x˜"Ç=$šûCâªñSô_Kß¾ïËÛÄT8!;=.Uwвå3íz¥ŸM8…¬¡ ë-˜ò ÅlÀð;ÉɦLÇ^Áº¿ç2âø ‘QàÇ„pý@ÀЊò5iâ…âlªJ ƒÔÎDm±m=mŠJWg?¿ÁÈ!»Ì`%BÄ&÷¹íunTu†M´ñM—z‹¿!° "åld…ç¯ËO—KC€PA"ÑA´úm3¶‡ïºOÍ›³8"QáÝt†M|ʃ_{•gd SŽ^&8ÿF?O ùôøÓt9±¢{C‹¨ÿ0m˜$ðpÍ£ïÛÑe#±ÛêLÝç‹h²dߪ­šµÈŠÝŒ-y²Ýv¹õ·›qº“¹$Ub­Y}Ûa ךTM¡rì&ÜCp9²KG+n £ÉÑô>œÒÌÍR™‰—Ò䇿áÀ‹ît ØŠòVHï}úÐÆ?cû'ìDw ¶0å’?œµi?ãÛÒÜÿçê‹–üºÓ:ÈÏçç%A)J[²n8YHû³i†òŸpåNäs‘ .û΢¬Q^<ƒ² ÜWœœ Y7V@—w¦€è¸eéÍ Ý'±8›ætCoœÆؾÓ\•k½‡lFà} ¦8¥°Ÿ[P"(ŸË»MS¦k®¥q=âd±®.À<`òÒ~d0Ž“ÿ`º{JF¯}uü”f{‚5(õUõÕ*=CÃîÖCÁ‡,z·|×rÒµ6qeû‰«7~RˆÝT/ÈNLO‡GyUm{®}?·t“RL.9o2饗“Õ½Ï)«ôì,õÅâ,Æ•W¿òçëM¥`:ø7Œ`DP‚”Cä§tŠu£xœšD«à£FÜÏûYøzšGáè€ðÙ~6Нgì¥ëXK¾³´$¬Šæ+¤6ÄE¬ÿ%‹6#í 5ÇBÌÚµ?wçWNB®.󞜯שÁ肟´lC…‘ïçd†¨̘MÈh¡! Äâªj¾âe¿]QõïªìéAK¯Ð;î×XЪo †Šƒ÷Љ ÛÐh•BT!ö—êæè[ô.?Óׄ˜Žžè<Ï¡øm’Ò…»Êl[<ÈÁUÌ­OLœàÃ[P†]ÿYþ:%§ ¡1»Ð¦H-SŒiß@|(=+,g'Э­ÖÁð!Ô.ºKF‘µâû¿çv¡{[Œ¦ìµ:`"’ðbò6÷¦DI“Ä6y·R”æ]ûH6ðçKøYýLJ¿xÂd 럣°•‘·Ñ=7´éj ê9 ²íF0hIÙ~ÔÇÚåРŸ*ɯû ­ŠµJä»¤š ˆ°M}RwË]žù©°/X²*j ”pààs?òX¹'.zxâ*ß 5»‰¾‚ÇQ_±Éx(OÉ5Nž`rÜÿ!еðTÂFpd¨é’-¼»x8jpù„–YR{µ¢Y\݈ZæU,r’˜ï;ð_õñ\²”òÑn5¶ØzÃŽ0…®[×5JEãžØ ŒÈ¡b-¦|J&±´f±|í”äSΙù›yjr (%#*t4‚†“Yï•Sa²¹iÒµ²t,ýùÁl Ž•KÒæt°mn ãñ÷6 ÿKP€ŸLÐ0•/V1¡Ýý­:ûûüj}Ñõ|i¾Ó™-g&*yÖ¸ÞG²…v šc€#ï’˜ÐÛåó©..Ïâ.Ø|@NQÀœÙZD¥wØ»ÁRd\’¥„;TuËî"Gê³™Ò•ËlD^Ϊ 'É!hAÎý é&Ï^™)$}¥‡Ü­qùÖpàUŠ)Tñ…ùœ'‰–¢çÑTñB÷“?ÙÜoÜ݇ž (b³2WhǤ¦Ž™…™‘s¾¾CÂIH—QMpIm›"Ò§j'Ñô]µÑ^*·0Âåþ¦“§Q+ç¿zWÈߟ gæuì~‘äÄ3š‡7Ñs IaÚ1]±|¦šdÖìQÖ£b©šŸü[>_É(n³¡­/7Ø:ìÃ|&p~T¹ÝñKÀ|1Læ±Ökœ¹'íå$ä*"QÆÜ]ïlš»î:AÚ,Øz×sëfjˆü*'‹ƒaæËM¹žõ @ ÆUdÄB(F¡ù+Ü (zµØwfÜŽºÿtrTãò [-À²e0ŸÛîÒ¯ã;Š”Spå÷Ɔ’¥ñ€ó7e2¢—¹¸…ѹ‰~raMUY§ïü²D7\Ëf®~ Ùœô¦ÆÚ–ÿ ²HÕ½—ÿRݦ„ô*è”AEWÁHAËéøð×Ðw¥€w‹.äÙ’Èõ–¤TïÜóVÄSîÙ˯ÇÔäRFÀgŸë=ŽÝŸí^|À©#ˆŸÚ™Û3è:zX¬a\þ'fMÇ&N“oñ逥pûÍ×›ëˆuÛmU?\¶JSaGnúÞÓ‹óO¾•vç`® ÿS¸$Ùlõÿ8uðT#á€[Å~‹5§‘ñ2ÖçÆ „„‡¤|ŽÆïžï"+åw 6ˆ­Ó¿pÜ5uꮵR(p¡çÉÉžb»„Y½0I+¢\¦‰.34X*tº·ÆRqmýc™,šÑêbóÿ{Ó©ÛÏ ×˜ýÏ¿/|.…@Uü%b” 9ºeYÍ»* ñH!ãܽ/Y»—<Œ¢ÔÇh¯–ÚÍÝÌ%4æŒORP0¢™ìjFÕOŽ&W›¢5¹ƒâ‹¸´¥´ ÌÆZeM&—J1ÔA¢W2¤À¡c•bPû8šl>6a¹+¾Å›öIZå­Tziï¶½i ;m¿xŽAªû'Ž}É 80={rî NÁü’Kzã¿ÈÀ8xbX0¨ZÃןI cïXß`sƒ½u´ŸH÷¦þL¬~zÌþ€¢3=[aÌO w5³žÿhîºZ’)VÒFŠÀu‹ÿ|ŸÆ™\#jèœ*–žÎÇ·…Eœ¾*!ƒ7:ö//Ž Ê{þXFºÅêH.Å"+h^ò2L’驾‚E¨cOz> F ÐÕ¿¿p¦HÓ˜•û›e±O<Æ%~˜‚ŽiGE*iÅÌ„N²én_ø9Á9 @$¿B,(âo‹«! yó‹5ª F²>?Èò¤Ä²*Ÿ u°IƒÅå¢ÆÖ f—Öð¹zSœÖ¤Šw”Òo1ÉuV»=pœ1îÂýÿ‘õ¯â±p¸x°zÈÔ‰ä~€ N’¯AÌ”LÜEÂVæúM©F'{âCrO»Æ÷…ád?½â |ù‹†ÐVl%õ§†0¿ ¥m6ÕÞª·˜3¾öª*ƵfÄNôZ5,Áx LþéÐþç)hb&üìX©å®CD*ê.•Á®à*2‡6Îëî3\Š|a‚òš–þâj¤çž¹48~%â^ºu­:†èªÿ\Tg|Ѱ—0Îxîý–œ¯ÉëÇ{ï`þPG:^ªØÊAÌv{e´ÑiwPNØ}80³ñ™x ÍS’g $Œor 3±¯»¿üíBÑäÙŸ—¢™¤<(,ø_kÖžßM²:âZïÁruÂhÎ^òðÝQ—t¸Û6ñ!ˆY#H'lMßþy¼-ÏíÝÍåùS!Ùµ%oI@´èƒ66ˆ+.Iž¸§ÓChþr‘n=Ï]ß<Ùc1îá”*Î'(f}‚suèød”‰†—´—[âIŒ»çÜÛBS`”^»æ‹VO¹Ö$Æž¡2@ç†|­ÏÔ©)›sƒ RDa …ÜĽX”*…S&¿îž†7”l,(<4ÁôU'ÚR÷»Œ3šº«lÇ#ø_îÝ6õ¥85 \mtxãtŽ&Ëi|½Fˆ—»%_"8zB}{„J,ÃDqOžÓèÝ!)®º‚|¡ßM¶'ÛÔ8]vräŒKI AÆ)(·‰‹KýN±S éʯŒv§¶˜óhé¡Ùó<—w’ðŽ/{—¼—°^>(ÃòÒ¹ñz ã×5Œ"“ýÇød“ÜHý³½ÎÐÍWºåei«›oñ{núî†ì0 Fm¦'2`óÁm#rhðSd㞆";™‰ãà6 ›½|]†àÈóÁ곯&F£íb)Çí¥Yì–2F#U8‘Ö° _Ÿ©ë}1xÏã&ý~†Åu+`ð÷Hy«Ä,D™[s¸ØR©º×ÀËA6 \>¸±à$†W§óÖC®§‚ò^…­­Z nÌiß¿±[üŠÈ–¢FÅ¢*5̆*^¨e",\‡@âÅ©¢³ÚO¦Ð/+! ÈÏç)Ñù6ñ‚-¼3XZxËÕxÌ‚³ûÛF1Á)Î;ôBläó oN¼S þæ õMÉŠÞ‘4Âÿ BÛ!çÚ27]ô, ZØ´f½f2£ñ7Ét°çêtcT¿ ?ÀZžúï'Ï«;;„ãð¿Ú¹PUPôaÿSÏ7Ýò7éë.szPlj~\¬LEXs! íÚWë“‚`!ñWïýôq_­³OÿCå¡$€ž¡cWŸ‰ím—Æ@ÙKhQAÜ«'}½6ž‰ëw8 ú÷+UªÉ¸ýkø½ 5ÇKªyÕ ~AtfÁ…nI“W£ýh0×Ú:¥‹þfì¯TžÂGã ×±Êr& õUÏT6Hƒ6\ŒlYÄù ŠÖ]¤8góƒK}éèVf&ãb=°U©ãhK9ëIÜrÕÿQCb ¥ùôEmNîøIûÙ¦8ÖË…ì³”kb¶¥Cl@Ï(+Z*@&ç`—M`¬&ŠúsBˆL‡Rò÷,*H?‰¹ª¾Ræ…•aC [§Íúù¤\¨³pQÔCdÌuÿy|é©Ê©sî~ãp_8­Zžm‡¥ m‰ d³õg W9€sœ›šð¹åûŠeÉ=šœ©+AH/ÓB‡ù+=ዜH Óî ~Ÿµzy¨Jžo޶åÚÏÁèqžHv/Ò¿OåÒ’ )2Jw¦êtžê‹vWúg™Ôóh-ò¨Îó.à†Êjc0 C̯I|.ÂL?Ïô øzaGáÝhêöÇŽ„;§Ãvs¼‰[æå¬Àø¢þ?8;#E™µÀM[hüz&ÿ1}{K•p;¯~H‡¬Š´ZEúªËâÿO¦A$4Qb!óëŌȌujg«MÿT~eœPÃf û‡Àˆ‘¦Ûhá]ó|Úuoûl4^äÃõç¯VûŽÕÒƒ'C{º¤¬{~S„r `¦¡ ´';Ði&9¤5ylIþ=Øâ?”áêTÒF‚Å¡­!3šW ­´Úðkl–´x\?¹%§IU’q“f‹Üæ´~ÅMù¤ ÷-O"9•øûcMckCZ])#¡dL.K.ª—ÆcWZ¯¨ìº´JfÃV/ŒùE”Ë¢_cÞ©¿P³ê`!Wfks ï[ M1Aº¯™§)潤GAk˜2GÍžGÚÒ¡w1¼å(7èÙÆz<þ­°šænóXTïA±MÊòJ¿6_wp}¬ÍÇ%Ò»4²óÌ7*§š²h³ü¼ê#‹Lˆöˆ Á»¡‹‰¬ÓHçDÀ,tmgÌ^¦É§ÛûïbE(ˆ£™ˆÛ$`÷aµqÓ «;•f®ìdÎ…àÄCéå&ì² ñöÙ«UÓ @ÝcZÔÏh]†ê%8²íiÆÛ ÉU ¢f„^ñÎûw}¯ž~Þ9)-ÑC¬VæÕé’Öº˜•8롸Ú5¤?.ª2I"L+azæåÜ x[ëëxþ yµŠå’UÐ ‡];›r€Þ{=îœæ Ò—ò}[Ò¢RfKŵxª|’«‘LO-õlÁÜ.S6eÖ:5Ú5Ôà÷^cw0hjmÿC‘T\ ñ¸F>Õ8@T4-˜lëØ¥Qœ4Þ“!¥þGLé;à1v0ÂaÕdxqÍMB¯GºçуÓÂJIõXÏ[‚»¥g¬DðÕõ2¦?¬„u¼Ù›d5×¥%ô/3’ÞÌûi»¶ ÚýbS6–£*º‘øNvíîJóű¡XÞ`²\QìP®îð‘¥YíaR>&cjNŸ«W<Ž"Ø"#«‘a§¥3&9M\óxT j£rýDZ/{oš{çýðn$ÐÔ/n ‰qÖ?ï±`‡6Àbz±oŽºÿsý2^â«%M:pnay¥¶Õß1°^Âh”©„’¼&žµgœå!)8Mrð„ nšÈ·ï‘8èòn=`T«/þw†XR|¼w7Úæñl|®MÇ}Ñ2ÙŸ.áJ ¢mAÑ:ûf`¨c ¤ÜpéàÄðÔ.¬š£èdÈÍf¨•€&hfÃÿ[²dÃɵY=ϰ…Sfû–Òt9p¡pPV.{8?˜cvöÖ= åÔ?ñÚªâé±²rÁ$^(‚¸å`¨O|/g3f…Ñ®Tð¯ÏïÚÞÏÛW²4×Èv~àŽÇ ²^,2DÇuƒÂ–ÐúÏÉ•`c rT›îZ‡Ð:ÞÈ:¿ÐL¬N<Ú÷u"I!ð8\ÓíÎìQt ¾1¾¢«Q6tK>dÿ~Ö!Ì‘€¬émMë^Ǫ‘åŒÖ©Û9^áâ¢ø™Å)w½Ob ùuçkɉ0Huó®¦ú=õ#3?(W½;ƒÄ=ÖÎãýÒšÈ þª5»lÈ/1xX4=wàSâöýX3¼×J<*2v½Smz=õY˰½qPÏñûÛlB8k&WßfFROë§Óµœ‰Ãbû¥,pf8àÝ%|‘]Z‡ˆOÿ4×+q³ù±''lÛ«æjÛvFÍM•-~|Öü&Kl"Ì¡–»\U ˜f|zÂ͹™æÊ;R —\¤ÉvåûéõTt£Qf`iíýž ó‡}ºÄräœ$˜@˜ d/¹Ÿ÷(£½Eö00Â0C=_—Ù O{Ѻ­E=>üG40·d¸óĪ/¦)ej8‘c_§.r}‰V™ªHH vj5¢Ã.0’´‹ž4,j#A>æg´cƒ)I~í¨‡uÊxÏýaÌ4à‘ñBÐ˵ˆÕ±ÕAÁ¾%^»dòŒÓ>|B`-CÓya ¶sœÕàªà®I<(™N€ã1öâ˜àò¦ç(¢THÐr¾üâ¤"Á9¡·0Î[~kn8œÚœP^+!]Ç#]´åÈcނޤD(ô‹ìï:U )f8LÞH¹Åº“¦µ&FìŒGr¤ – Œm83"¥(ª~»Ï±÷mƒN&ÒƒgßxƛβMµk|þ‹u¬=nu´Ñ‚ïAOf¾«Êã5vZJÈ­Ñ ×„Ê('[zÜŒ3ZG ÷>¥Íÿ@³¶ë´+êæ}¿°jb•ö“@JÖ΋q7Ž¡‚ÌŸN Áãõ´^î°ôfñäZ—û“&}K·îðd~9'*#ŽwåûêÕ(Êæ!Ò¡ ~…¯îáèÆê±Ýp̈D&{‡Ovxú Aµ]4ƒ¸g$ö±J3:Ýýmîs²ÌY_ý:€‘%8ö,¬Ã´ï¢òØÑ:êš ÿFíÈÖN\*mØi¢Ù42ñŠWEbj.Ly+– L56æsBáú;Ž[þ#—öGncê>#&„`ß=y8ë…èÙ1‡ª ÇõyòfB· ZMŒPêDW¨]…P¿É¸îÇ þ*îÑ™½=¡…‹iÍØÖKó'¬Žý/êêð ®ÜnúÁ˜›­I…{¸»…¯„¶bTrºzn'f‘«Úpo‰Õ²É÷Û€åe’•‡9À}…[ø9Á`šoŠWÝ„åüp)ŠòZD– ˜##Ò)Cw'tƒñ3ÛOú¡Ú6–1J¼4€ðÁcƒÃ}¨ÛÀ»ÓAut¢Haƒí„ ¯{F[¶‡]¬Ipšp)øYàq.‰ýzÉÓÛ ;¶À*·é³jE±ðMp¯§½ôè¯Â´Üm.mß)¸ÁÈìÀN¿‡2ø,@‚\ º¨ÎGˆÌ/ÐóPû1™ÊëjÓ6ÐŽä €37§ðPÚîdô'®•k/OKù>õÅ÷>ZíYeÒ!1·ÿq`Á8ëÄ08ÎɆLGiöƒ„èú¹ûyÖXø€©4Tm¶Òm 0¬ÏfH0°Í„ Ú¡ M/ÌÈ@»èûRÏ_–ýÈÄÆO&²P™•ÈKKÔ+õDÙüß‘Mh^1Ö)3‘"5Ï…)†ærÒ5,åUv±qVNœÄ뮆°òZ½¥ûŠônÜËù¡Þç ^·¤fÇý¾8&QI.LÝnl]ªŒÅu°ñUfT/›¡Ð4/ôXýúÜð7ùr#ˆgÏ_‹ºV2»' èt°ÓP"TÊ».Oër­÷Ë%‰ütHò¯à°¥Îڊ蜸Næ‹•ì׈€Ø2 üÌ BSÙˆø_$i¥ùì&žK¢m±k:Å?Ì•ºáòC´¹Læÿ!i^qfŠXV"ªMíïOÆ/î!Õ äÕ°ú ç1ôZÂÍ(~\981§¤N 7XþˆH-P3•NcD~‰›äOÀî“Rˆð8IPŽ> ß“"þãžø3lÄ̪UâÕˆÌ]–gP²6wnâÜé­1Ó ,|"†/JÚuuh)Úb¦)†mFïHÉtú'¥rÌlö^Ežþ3 U”$ËëFn>YóÙPn¯s•§9kϰŸS½€FJ{{Žæq£< ÿS#ó¶> Þ_¶bø®²k ½F¼ò)ш…IlÔ隈<~(.pžEÁžÊLY(ÙK¸r‚]“òjs…a0êëÀ±î$˜ýªÎK2 Àžä™[4ÚSKÑtž]ì:GÙÔ1E¹+LÉ+Ui{)7 ÿ5ùe„xe»»·Æ¨ë—EµUÑÍ31Þm²5ÞÁåR:›–‘=ÀƱۖ ,d;å;×Gæ/ÝüãÔÏÀùO€ó‡øP/c?ŽºÿyùÓa!/Ø G! $%û«aˆ…ðJÿyú]KWë¥/žõl6F*µ®ÑC(Ûæ3¤TøPB¥ÛÿäúºcþY?¯ŸáÝ_oY7Û®·Ûèü= ñü:Òþ“}½œÿq`ã·÷19§¬gA‰ö ;µÜ}¼ž Àrû˜·djþ¶ß }`®~6VÏYL ˆlÃøß¬æ,ôÀ$‘´Tâ,òF÷üöôQa+¢µA‰kéqc•ò(œ,a=•HpùLô¶=z|V?“±èÇtà‘çç˜ ¢í•í¶‘›9ËZ*ÊÉy0¤I0£Z8»n…›*•.èyå}¥;¾ßQvêa’³Ú(Þò’ÁV-S0º­ÈAÎåéÉÕb±Ž¨iç”cTÅ¥˜™îô8Kk’äk¤°0UVfé@i1—(eJ!à­^€˜J‹& 7‰ßÕ/{)–7i¤š+Ð!^.fdÝcÀZ{å,ó‚Ù(“üÖý#­€ìíFD? Y uǦ¦ŠGò}{øi=Ÿ~âÁMÃIžÉ¢;øFŸK]îÚ‰•ûùÑçËwî"ð"øðIlˆ7^¸¸›ÃãK[©A¹Uüú:s–®3É”ƒ‡bë¹Ì~.8ÏÂ^|‚Bu(~=•ä梎n7®]‡vÆÞ㫞CQÆÅe^ªmE‘û»2á¥øa¥ÅÁÕtq'e ÷¹ÂèÄ$/ÉÊÔM¢ïC4!>–sz姯s’B\Å[§ñ)\õà÷´’·9‰ŸÒgG_“ˆ ÃLéÑë¸dM‹Aâ-61§›È»¶ÆŽWl?£S"Ü hA4m{Èì2ÄPÙ&’¹è6¡ÏŒê o%Î`3¢¤¼Ø %!Òçî…QH¶NLïO¶§A°w2ì8Bwþ@ }Û}ºžŽÏõ2°¢}¿0hT+ïd7~ZÞ^kKa™óV¿a拉Î?Ä_<«túöv0Xëñ^÷Y¾4™¤IGFa/m$Tün h 3Š¢„`k-Àh\~ÜñÎ,7ܱ{*&˜Jw˜ÍVJSÐ4ýšNìX8º-.É ©h™‡”äm]·—æ ‘ß2½0éB{VÐÇqòþÀ–ë²ø"-.XÕíܳ¶göŽ/¿ªžqŠ€óoÁþ:@°w$ôO~Ïò¯è<|ñk–l±=*Dâ3ÀšMšèYhžØdæË9R‰2K~î—@Õ`8-»§ÑRô‡æ&Ø®I² ˜¸t2¾ü#ưÿR*•/¥Êb*CgÇ67I…߆ƾ3E†¶tJ‘I“þèÖüËV( Ü>‚Ùö2¶RâëÅ”‹õá'ÙË+e6Â<ÓuÕÊç³IØ]-ì#™'•qCð¢Ù±€Nx¬“²ßðHâ}„æ¶ŽÀ«¹B"_wÝD²ÙöÁ–þ¼Ôö‹P50+ñ(»:žà)UHò ‹V}¥F9Š/ˆ³•nóY—§*‰ËÖãZ§º ÀÞÏ{ó„¾ÊJÄ·!¿›?»OáÓõûúạ0ònÍK­¼‡ êE_ÿ}ÖçãŒGfÜ"vCÚ ž±’*¨Ø“²€¼Ûÿ@©?Y/¿ùpï&Š/;{ùXDXœ^@ÅR¢w.ø2q¿èé«å·…ÃDO‘‘h©+àó ]¢uX­žb¥$OuØg¬# Œ<à w £SõUꮵLˆB¡Wõ׆w;`¨ãDGÏ©²JÂ+]:\N‡ºÞñ/¬ÂòĘSýë¤<ø3Á³Âeôh À?é¬G/2/"iºÁì™Ò#rM òéux½ƒJWa*˜Ï†DÔ*7¶k]òì{­(Æc±.Ú|&P}1zö’Ë» o… _bm•µºüÙ@ö°H›9]3íÎoÞéSšD«§q™üqÙðG±¸v‰J4£ÄI¬ä“Ê|Ø8&]‡HŠD }à‘ž¤1D"ó>KR¡ÆoÆM4ö-JTÆ{ðÖ‹¸{lоե“â9·0ÿ 2Ž 3ìx_­Tkê7ä«cçmæ@$·m‚µ–<÷õ¹!Õ°Ùë"Ç9ƒRKÑÄ}LÜïÐâNrMÍû³é«TêÊžFs¤þ3°>^± üCãrûÆa¸I¡[(.ÙÀ©Fø ®­`ï: Ф4m H–ŠÀ齞eðJ‚Ñ“ªÇx6†°¦”k.ú5A;4Í­'Ë·=V1‡¸X o&%¯ua¥¨ž÷Û0³òVˆØ¨(GÿI ;±µ¤àq¨H‹©ß‡»VѰêBD´^«­¡7ø™Bþ> -€¦è‰­¶L>¦P   (8O›?Ô׎ÛÎ'í3dÎJ­íæÁJ8u"*´˜¶{ëÑ7V² ZÞÕM®pœMx |ð·ÛHsÄ߃ï´dh¿¾#°9’MRb;JS7»CìÞ^Ê?wYš;BÝ[è˜}‡¤ôúFÊv~èFÀÍ2±Áx‰ü‘¹Ujú iIœìC¤dÙg…KG7qÀ®­,)jMN0zvNS4µøµÏFip=áÇ'«pš£ª·ÃÃþ‚t®©¾ãCñ_$H®õw¹ÀÉCy”6¬îž(¾uÒl…å!‰)øç¨rã?›>C…ËÄÝ{«DOï†}Š˜êrº}H³bä1,žÆj–œÊX³\£ÑïŸ(IY»GšuŸ…Õ5#›Þ§±¨äNÌ(+òÛ&85 ؉Ñ8ç=îAŠ¢JH­ ñ˜ÿ0—ß³ §;ýóF6V"õÿ4ýI5ÇTÏ{`x¦­5ó¯âc‡vIDÃõ³f~!¼_i‹\Ñ¿…öÈ­œ}×ú&´Š}6ä”[+=™jŠ‚ Ìäñü#PL’È?=b0q%Ól¹2sÀ¸GE§/„ƒÎoë'ä' ¡Á Ï'Å3”IÚ£¶)~ {ëéîY<$4/ï㪠.Æ›,Æ?Oæ?ì£F*ýÈšÅ?ú‹îÈö\Â{M•fõXe<`äë_Çkœé»ù™Ý.ÜsˆÇ§Xš)á¿×vÜê[®ù­ë(€.ðóQ¿Ógk;0tÄSç°_IlµHì#¡Íªšà¡:цÖÒ¢f2ðjïXlcvÙ€ÊË‘ÇgÕ&ý·NÂb[ Ä”~µ Øu…H+@ïØ¡8•¾æ‹IÆÕ6º„6í]…J¥hl±åFp£‰€bTÀiÐPázÁO6ö¿“]o`Ím„®4Âû™¬®$È.¾ï]8/ =ìØ¨€4-´+î}ý5©-;ÄÕ‡€­ úL”V͘®~¶ë¨m%‹F$RuœúÊ–YNƧp¹Ý:ûðäè¯Ó µ$¾ÏB2Šÿ3|u:kÞ¤´£À  WcvyÖr€¬×®â¯Š`)i?V®%=nsïÆqïf¯=S‚Uë` °q*P¸¶Uʽá¼K5[.ójP‘f“à……­$§nAÌ_ª>aÅ+iûùŽ*…ô=,V>°Sr(nÿ}Z»]JÓ™ˆššÅJe²mÆ㈕FäUUÓÌÄö•Ê’¤QG$ðÄvD­ó­æ»¶ÛÓaÏø¹G_5àø¾Ùìó]{KMåjÃâæ7ŽZeï`ßÚUH'Aa”žœ•“b ëi‘Iµ«6i‘ëˆÅz‰þPlÅÿ”#c°Žö¿˜é-Ð×€úþ²¯.òªÊ<[ Lªôé§ÉyaË¡a)L?0»EµŸÈ›@©%µ`nÔÒ±—ÜÁw,ŸÆU蘓{pˆØ]vÕ`Iý“q€¢•u»ÔgÊ=Ÿ™â6\¹yˆ2Î ád¤^FÓÕÊêfÈѧS-ìm n(m‰½–êB'”<ÊÁñýZ—úýÔŠ1"Êu!‰J¤]¦‘À{‘^ ˆ“Zý›Í³ð¨7â²Ø„ÚY=ŠJß•»¸¦ü›ÛJ‡F’Ê ¶þcG‰zÇTqÕrê+ç,á‹|yÓu|‹ÿ2†ú4 cºBw°FbÙZ4ÛÛÓnkSÏ'!Sà—éWVª9'Á¸É¶õ^eqTÞ”IݦE’ÔòçìqK›™¨ü÷>“  Jªàµ*Eƒ%7a7áyź,å\o”!гܑœ‚n£Ó*÷%›¥65úÂ(?ËLÇwCí}¯±aT"íè¶ §W0*>À_æ8ÛW.[‡êbZÇ„¨‘z£ì|H!íÜ[€æ&ÄJcê²[XLRzðjTA Úå;:è|Z97Œ\Ü_ .Ì$mö¾¹ÖD¥Z¾{a˯BOϬlé.óš‚wG2ð‡óoá!"£¶öHÁJ´ø $¦QE/¦ß¤(„LZôTÊæKô#,%/ëÞmÛÕ™ù»fÈšT)eSk–¯©ºb¥ÑÈ¡ilŸÐz SP"&7ØÔ~wß3¦LxAk¡¶/þ™ Ûƒ[u¾?]q) ð€öé(nÿ”ŒË«†•û±6mü³¾PÐÜ‘‚Ø'¦™5ìêQSU' °»üïþq¤/2!WýI™ Ü~þ›¯ªâ•ë¹Ç2ãÎ/µÅ±1wj&OL ÓŽS=}ˇMîæi‚þÀx|ÙzŸxpÍñJªkúĮݥžmͯ|ïOú|Û±3y¼Öh/‚Åá°ê€}[£jMχÑWûå}Š”Í`dYÒ`#žÅrØ­»âsA‰z3xÙð|\¼á‡õìb­”É×!ç#Îe7¤©)“j•Ü, ¾˜Lº@¬ª|ðÛË뉚Y—=ùîÎnºÙé\;“tÖ ¾´Ä{i†?Ô†åô& vZ•q†%&ÿR~HýÊ‹jÖé’¡oÖIfMü—‡¶nøŸß«¹ 脾ºÍƒšá0žã$»K~ÞJÕÞ­0?–zÌ%²Û"Ýf™aLÌEO$‹m¿m×ö)çYäÈiüµa•1Ehµ© €×jò[¾Ú›—¯ Ö9À÷üúêa½%l3öËàÅåðê„w¦mZ¢ÕÓ¨Hä'ƒðç€2 ŽòÄ›Wö5\ 8P¨L MmÇ5‡`yåÀ2¶ßcxaÉ4Î!H×W2Õb¢}+n)3Ò›òk®·sê2™\3/çÕʪKÈ(¹9¡qǹ=B»<—M™K‚A‡ „‚eôx¡ù§ŒL;z´,ãï3b†tà Š_Ä’Éœ²˜þÔ^ |ôƒnÉ…¢BÚŸkâ…‘€¬Ì}ßaÊšGÈPb¸º“ÔSÊrE÷;»EÎàµÂŠzq¯¿ÿtݪÕ$•Hè÷•@]“ßK%t?3žH»¼¼ÄÔ ƒ¤¥6OÖu ™UÃêzý`󎎇å9oãœ]JH/¯¼ÃÇÓ¡Å¥£ìµª/©#îhGr©†#1+l?†[Û;S‰}YÅÔ” ÏêÿbÛ"(®7Š˜{[vþ­VÛºú+'x:·¨ C[$©«~IDÀøÚn`5Ûq½Å{Z<£ú/{ŸH`-IÛä:¼ç>¾#OxIj¤XN©i–>ö6ø“þÀI|’IÈ 7U%åˆY •š/ÚÃ¥Dó}ç´W‚7u´±ìÅÍ ñ¬¾UbAk ÝÒ²Ðò›gXbƒ!‰fµÜI¼Œr7¦º Ù<åj¯T®XØôh^6j±YXcJp°hÑèo´5 ÕÏ}·æ„eY˜ú±æÞõa’;½³g6ãIÌ$Uù×—Í¡”úéZà.ÃÐÊ m>þ^æV\7\Š×[þNè=áÈY8ç«+—@d<¤ QÝ&Hwõð¬H[µÉñï'møY·!’›³A±êä'@NŽnñÓ½åJ™ìVñWÖÛÀjbÏïÃBIzcЗà˜ã_|ý¼Ê™2MNºÆµD¢ç2«›òNdzô÷òV*= ¨¹v¶¡D¡åô]HgZå°qåùaoÇèÕ¤†þŒúŒÏ_›o)â“Ì[:’÷ì³ËäÂds›ý¾¸J”Iü7]͘C½€DDƒÿTùÛ6T{)]-©×†3D³D¤®z&ø¤ýå…{ƱL7÷}¯‚N¢‚àzo9àî¬A>Iñ¤ñý1ÝèÓÛà%E÷ÑâpÉÀ]ÌžE'AOüÞ&u2~¾ôáYúfñé·\ÿu H'ºØJám¥“£Uõì`Ì^(!Údí虩nä)ÁÞÝqö=hï;£Vlºñ5Dñƒñ$°ÛÛ‹z‚ˆˆŽqC'tðM{É’ÓöYÎÓ-vmê7Ï`õ¶¡7‰™°!ÑÅ<¡8ÍHG“*dGl+B“xȲál™øÓašmŒàX·‰‚¥ 'WM¥ÅP ‡õ&·ÓÕÿ†=UÇ]Ý,RÔ¹ïÕΜ¢MyöÛ’„ÇG·]Vn÷çxå ÷{ŸrI±Ü†ý9mÔÙâAÐßÊ£ä6s#¢Ç>ö- ågv¸¸E$ ¬±ZûØðoÏ4J$‘hñÁ3Ä’ÝA⊯ä#9=ßÒÕ5–¼UøaR›`ô\™ë!WÕ.ZKö¥ù8úgÔ‚ÜÑ„µþÝ`Yá¿ Å'm‚^3Øöt n¿[•õ¯‰JÄ-M9&29¥<‡Ø¼±ø„ý’ÛBw"˃ Ìd_FØgHÞªþÅîïq›Ûļ¶ËŠòºä@ !„ÎÓf…uH…0;œµ_÷H+ÃH'Cô'â²>}‰J¿pï” €šŽÈ°rVÿ®DŒâºÈXK„Ün¸qr» eyŽð\&j¼om ¯;Ó WòBàÅת½üNfÜ”=-. ~IT¼Íû ,»Œ˜}¥³ ZŽSy”dðJ„t¬ŠðgÑZ)÷š]‡K¾“ƒùYˆXß"‡à9õy\Õl ‚Õsæ´ÏNøã;_vgšG ßBâ¼u”¾iQ-vŒSVkŸ$n’8Ä™r+ÁÇ-Ú<Š\Í+D¸~'`z …‹çTi_ƒÒ&PÍvT7¸!Ãr¹÷Y ùòFoüÁë¶H—X_Ô,ê[™a‘À*Až2vÛ”GÜÙe]Naà jú Ò#df}úq, Â~ajO°o/Ìœ½ROÊÓöY߸0°ÂS±Ó{M}Fhö¢ÞÌ¥7/ל?rE“ÙÅ÷Aâ‡A«+;ÞÓÖßëzøŒ¦Øjëq Îr¡¤ÍÀ! mžóO7Ü­ 7 jp`\ÁÖª\äq¸dçñ¬å°e« §.X©€*™¸ÖÔ!) Ûx€$þ‹ÅÆ_|¸tÉÊ8ËæuêŸ ùÐ{Vôà5ŒëRß/ ؆:Ï»âóÒd'$ç@l@âji¯³$ôCË«% DZG÷‰cmü^‡jÀà©JǤp¥IB[–rgn( áƒë”8XÞÚ¼ÇTTp3´w=§m/錵¬+V.Ãÿ=4µl¹Ñù¸‚r´ „{º#m¼[±bÇÁøx¢V5E±ªá¡&-hØ.ò«Z:ʨMO›ÅlÍ6àÍ{xù-ã-hqYg?J,ô±ÕófS.}1¹N碞¬eçŒcì#öàïÜLýßä1‡S’»p éå^ˆä[±¡ç@¥ìjÏï!ú¬ùŸçõ¡ å^xÁ™H¶¦2~ĤWʘ,Kßb fiÔåg]›px—´×G˜ ¾™rg$\‚„&Ø-§z2``ÿyb®âØURÔsÝZP¼#@Jle)²VÊ™á˜õ'9Û¬œ¾·|Ÿù«àî¿¥Øå[ /²Áˆ`m<|Œxt›'ÿ Á˜^–e¢ ;eŒxvÙ…oýý~ÂØwƒaÕ:M¼º5?mXÛ Û¬m È*ÿc¡+¦Ëª÷Ñ…(-»‡Ä¶@Î$f´vÒ½Ð÷µ[Ò¾ï}„ÝTFÄ¿ôÊëySG p¿¾Ûvž1y¦¦á“è—RÂr§PWæúÚ çôÌyfyµÇŠCHAV’k¾ý&Pà_4k²»¾Ù#ö–ïÀ’ÌG.FGW¦üQižÅÖ‘¶[s ÒX¢)¤C´¤ ”T`e"!àèÄ q¡¥A–Úì`p”ÆHoLȃ8¯tBÓ¢´õUÑ?ÛïJX½ýÉE—æ•Ñ­®3¥QÚTEò,úŸ“"Rµ“ ñbÐÜ ]l!MY$ DVûý `ÆÂJ –W9TÂu:B¨‰C¹ÐgÂîÞéÄ7nžB6Âwdéc ÃþJ·XÈ0eyŒU òU®„Ä(Ù!æ:ÜGZ½(øSY·Ç»{˜#.&Ì á­:µºéEëL,W‡uœI€™¼î‰>;}à§jûJk‹"jÜ ìŽVÈä‡Ý`x ,W¡>Ó.u1KEVJy%&DB¦L#•[râÆ ªnˆF"G/fû\‡#aÕßo;óÄžµœÀ5­ê•?ö #è5SÕuðïuìsˆ.¼QݘVt;¦GiÜ9bAú¥•ë^ÞP =‹àž\­&Qƒ#l_GÛ"÷žvÆ“šÌrÏ=!ée»ÛÏAµðŸœvR÷ÆH „óC8½Q×l[oE#vû–á )Zµ†Ü<Ëâ­¢²È–ÐäZ`lIh™ïZ£‹d ßÞoÛº¢°Ú‹8¶ ~YzÂÞy,Fn;ÇïK…AæC1u:‹ ÐÆºhýôǬ²l¤pv{{ûצ)=¦"+8ä}Àû,¨ÍªÅÁÈžë‹áò6ßûÙk†uÚǞí|}KÄz†I&y¦LBáA›×AØmPP‘AX€ŠÊÅ_[wöêéP'ÕŠj±`Š ñ"¨aíŠ\%t“Cê-Ïá_¡‘4éšZxbÓTŒYzó-ð[ÄiL´„§g63˨EÒD\;%(ÇvÔUò”‰ßÖ`Ç“Ùá<~ÐÞ]V¡g‚÷aè ^ßXË`Ê#Ýkqƒ¾Ù@؈VIÀ͇,½MCíÁDØ2 ÙÙÃÆL`Ðen¤íNÀóõ5ºUŸÚV¢;ïï¦û¦R€Cˆ‡šIékæ˜*ÿ$á§A;ì™kö8K2¢b~Dйâñˆ¸£æx±ªÿyÃÙž–|5ЋmÎL¸øŸá?c:¹´¢ÍcÄ®¾êBu[Éݦ‹¬cÊþ•W  | ÿ†/øX3fšÜô™ 6ëþdvÅ;hH³Å1´ëŸäÕc£$¨_ú&;‘åó_«Ë&±éþäéߴݹ´¦ùwtn'Ç’ŠwGŽå_¡9„bÄ=ýèáü†ŠË¤úÎZ¶IBX/úd{K§_Jì/óΛ…H8eaZñÅYıKÙÛvéŽpcvÁÕ¬ògµÕsÑýû µq?V”¯—’ <SЗ4T¡£2ît?ÇbZkN?vº2ȃ(ƒs|‚Ša=6ê[5Óþ süeœ‘ú‘5¯±:²… ¹‹¥ˆþ(_‘ÊB"85*¬¦|q·\/ Gqu€º¦”´³é¿¸¹°ÜƉéÃõ5/`#óˆ/;6LNÞMЋY4~¨Zuºä·ÔB—À[ñq ÖÿQ6’*A­§„ÝV“µVI1¬ÖÝí›]iOb,áH$#kóLeðþGâeÓ=AZ-ÆA$±8q“ÕG/váù¬;ï1"ËâRŽWÀ2ÐQÃM¢î[¬ÍTÉ#Rä ܺ\b8)?íîØh2t­_XòE½Èõ•£\ +Ë1nRB`[¨¿YQâ¤~Gì&ÿTç\TI°µ~ ­j°ÕË,§Mí£ð­}9Ë2,;Õã죂gCED¨¶ŸÆ+v•3ë1W‡[—…y)µ‰w¯¯Eòϲˆ>·G£G^f…X[RT¸Sƒt FÃ&j䬆Öc±ÿ]õ¯S!,TS¶û\¤XMÕ›á¯äTK¬ÿbïv¼Ú§ÅE²)6ÞÄfO)íCBM‚ßÃDÛ›@MBëé—p r~Q$=–C'tê®Iž ‹o™? ëï,:柣”øŸ+úìÆžÖä–ßC gUˆË~½®ãÏß]W*èõò˜xÄq|ÜDˆ)û>¤9^ ¨¤)¼MJ:Ô³ÆO"ÉÛ¹¥` ª,7Ì. dšþ`˜ A§øWQFã´CËl?PPyÌñ:[vÁÙ£ U¢WÿmWôÇ‘ ‚ÛAk¸2P[OWì¶ECm¿ŸÕ¶êœçïH - Û§]‰WÙ¿m£:P;Ú̉x´{Æ Õ#2øBœææj¬Y\» ’.´ Ã"äú·VûtF>OßÃÐ/·¤›íÖ íïGøzBbûvÿ|4Z}]OøÀã·÷19§¬gA‰ö ;µÜq•ú}“ðgTw²ºfè@%yÚ}ÒÁdŸ:ñ ›>DÓÓ`Ä+#ÉÐç¦Z«ÖÀúÄ¢$z\zK³'8tyð…fm_«&Gz0-úIz¨4yÍ#Gvð‘öxÚÓnNÏõŠ´¥1ëßïL¨0Ù$SÿkA G9ä÷úq•îèÝñNé—¦ w6õM†q«h¼â36š4ƒÓ„¶0!Z’Èä@Qlw:Zäª zÿb¾ˆE99B?p$N&a¹6dÃX8’zšF‹¨ïÞY4,©z8Pq˜ ¤: ψJ¢o¹ò[ÆL܃ï)!ý¹ ?¿ù¤»”ÿ6n®gÇRÀp䨦=Y3<C2㽿<$Sá䎟.÷Ë’²°U\ üÈÿc-½ùM^Íð•»8RöÆD3è§J˜‹ *cðËP\“ö-&Jñ¿Ç4%«—Q(Oƒ¦5 ÷‡aaïBmÏ—Èî?qèÍ!QsFÃ?YÔÔ“Ô‡ž¤tൠퟔ7D·UôXž^¾¬ÚÑ]KÏ®ç7²/Í÷‘¢š‹r("M\øç&¬7þZ’®w%'=,»Pù×õ2<äq–l)ÁîtÐJ¶Ê”-„cM ²EÛïBð¹vG&£àh!î‘”òSm­G¢lÅ‚ ;x{}DP¶üÝ]UDŽoïr1JÓtºú·ÛÜÕzÚÖÑ{ ft8$t÷ ¯Kp‰?ƒ]0.´k¯ß8 µÎ:¢ñ^±AríRÉãˆsëËd,¢Ôѹƒw´ùÉ/Ç3û¢ ‰² ·™êÛò8]x(\ K¡¸!è¥Ë¹ÚaóNjê.ª”nW•ÔyÃI,€›­ÀRmÃgUO&se웣ÿcìJÚÀ§ðb™õ)˱=Ô¸â°ÀÂë¸÷æW`};šÊžve"ê Š# é;“ŠØ%þøHã­–þË“ÃOÇmR>õ ã‹Êê @©-ppTjµ±¦°~“™ªzkýÕ×û飮ñcšZöÚrÃ| Ò‘Q…ÿ*«÷ò¬¿'kû4:È`ìåÒÑ*77yeÚ?žöC÷t4[ÿ}!€„‹ƒŒå Ž ¤¦s«"Ž<$âÄ26ð¸y6 ·™¯¾Ãá<å™aÅÎûÛsZ Ûø¶_«N„C_¾$ù>û¡ nj(ã‹Uü9wõ¶Q;Ùu%6üßÝ@[k>?˜RF¬èK~aØ­¼¬Ÿbø\ö¬Œ…ÅCí¶ÍÀK$“yi?ƒ(¥åäÌÒøBÎÄðx•Gš†DzàÕíóÓvnŽ.D. {³Ñ%TT>å+Xþrßò–L–ˆ¿ÐG¨DÌ4²õ3]ÄüÇ¿ø™BþT ”ÁR«ó!‚B‹‚/JRÎ$+žA°»ŒDô}D±ÜIf-^²q¦× äÇ2Q ™Y+´£D¶’œ®Óî•"á›Ë÷%´,\k´Aƒ/ ++@žt<&¯Ojžƒ^±ûR¡*è­d;•Ï%ºýèâBMHŒè÷êfñ@s=ÛnÍ­"/¤J—‹6 .tçE¨h 6¹GÎX:ïïçühk$¢Œ{Æ×ÜÐØ7ÔæÅÿQYQ‹J¹Ý—„j‚HVi­+v Ï(_TBb ï’˜5fñ{YµZK°ìýäÊÀd/DùÌül>…tª×&+P‘Ñs‘ˆØ•R·U•ºÊ?QuéMôlr Ocò$¤Mpû‚Ÿ hkþׇÉÉ(³žÑÞû“m=<;&¤HQ@4ÈYë¨ÃÄäÛ‘ÏŒ­ƒðÅhláñ†Œ‘G7‹ñ„?@w1 ^µ!Q»<—‚¯ÃP.eíÍœæÁ;ÕòE¼ŒÙ¦DäåCªž«í1y `²„~…ÔöP”uéèÜ((2O6 YóLDY /võ t^O_®CÂ!‰iMvlÅnk Á¼hSKóUzVåJVunUÒ¼};€âSûUÒÈ50NÌ‚ÕJø¨O¯›Â#ñYÂG•ƒÖ‡¼ðáo¿?؇ÈÜt€Y1¶¾H }”9ûC€vÑ?Ezra™Ž§¼ø¶Màÿsôô‚Á„9Ï–«)§»¥“ ¸îoYí¯Jwžûà"¼ø-K3 ÂÇDGt9Ÿ7#EO8]¶7&GÇN"˜âÝí×Bý¦˜¦u%ÔÂUq#ÓàD±™oàGñþ`h0#m®·ˆÒs¹þ9ŒËDºn“1vÉwÊ$4ï5D‘é.Í¥÷0`ëSª RS¬kîï…›ˆ]SÁâ¿"˜Ü^r'‰<7x•Bªº'=·•Å÷ÞÆ@úlÂäfaoî#ã°Í÷FC" Ó3ž@Ãðº B˜‡ÊQËV„µ“ƒ”ס^kP6 ˜2ÊÉBgO)ôã“ÞªNEŸõñ.0¥MõÌO˜gá»â½àÿzäÚ5F‹u]ÏcÐj±H•üi89Üi6Cœvÿ¾©‘ieÏ¥Ö é³Ðôÿhºéû¹k/—²Ã³ÕÍEZ¬ù·þ¦‡H° a•Úܾ™(nÿ}Z»é‚.:ÚÊ!kî¤óqåô µYÈ"wBãŠþ6±ã1" mÿ!j•Ü7nážÏíRÄwAR.Êcû×8Ç¿‚BA„qj¿ dÚ?EôQÜôèØO'²äJ%ë©M8ÌÎ[€ÏGtÿuW„À«ƒf1XÚ]5&àT?Uî‰ÄùœŽû»¤›º?\5l}ç ‹äþfü¥aIÔ-´Ð×2Yë}#„i8z^V{€_3Å£N¼Ù…<Òþg¾‡x`2z¦Ý¨Ã0G³"Õé„/g¨â«|´ iâFÜóÓY§ù"~Ó‡È &\8Û>œü]W_Õ/ü|éʺ‹ Òé ¸¨t69þVxsÀ‘ ÓçsPÜïX "ì^K`ù‰ôõBpšGY Ákl ìÆ.2`nPíúízÎd}­Æ?=\™ôŸ:´…‚î~°•ãÈAᤠÚ,Ê ;ÐSôf4"þÜ/2>HäŒj°ƒUÛIq*Ë<ªx}˘ÁI‰ÓFA ÍÊyTe&^“çþµ]zŽG¹Ü|tÐK 6AÑübºH3YÙC< 52&ªØMi<-k°¿ç/Îf àcQòëV1Š`g¡Ûé›E·†pk53xÇ« oÐä3˜¨јRoiDlª\Ê9ÐpEUÞð¼ßêwÙža©Ü3¶®õŽN¶«Î+ÂåwH^×f {z­IùvOÎjìÅÐ*†Ò&ÐY@­(nÿ•"OÚÌ#\9lsšBì rb‡ØMºšíŒr~}±{XnLjp5óïLM§upV6d§OcTà¯@åFDeFu> ÂßåÊ-ôÑ#{tÁZ31l]¬i¸ñm£)Ru˜8³±Lí l ‡HóåØè|Ý[õÅm÷cšŸ8NZøú¶ ±º0ìOq!I#~*%SßÇŽlš©¤=;<Ü7º€¨”шB+röÅ4†˜MÜÞÁ ‰?Í|Ù•Êrpú­±Ñ)V¹u‡Q} ïçF¶(£ !t©2É+ XAM1 OÒØî÷¶6d>¶ŒÌ Wý„f4X¢ži}¢“gaZÖeº3ýèfžæÍ +Q0-Ý?Ã#(a#L¸ÑSZ!„ñUò~!³[´¶‹·˜çÅì‡(7l%o~ãØÒk,Ãϰg['\34Ø|L(Q±–×Óì·‹™È%iˆ‹Õ&AwkãqÍLÓ³o·_v6<Ö¿/’F¢û7()¿oª*ÍÖc™0šæ±Û|¦ d%ö°¥@i·1/ÐÈ@FÏs@3B¾½o…´P\…>e7”Ønp¼IvýçÉxü "N¾”QX^·-—tÞøïÊ̽ʾ}c‹ìbœŽ]W[®0Y‹qÖËœÇ ‰5wÞãÒÈ&˜Oþ`€f”V‹0ˆ6JT'‚ÿx²"š~êebp`Å¥AM„`¥6 ¶¨· ˆJ‘õ°ˆo–i¼+>¬)lH²¿Ã†`˜]nô[øÖBZŸœ[>DÀ÷(Ë}d«³ëZ¨ÇUˆ‡‚àÒÎÆþ>`qâGšJ-È–©éC‚+Z+û L~—ÿ|2=HvìXUKÕsµëWl·‚w+œ€ñú€ü1G“6v{G iMÔÑß4B7¢ŽÆôO"Ð÷îuÙ¢3ò$ÿ'4ëñò¤ÐÃ7T%aÃfiHà»el†Ù•*K{Ÿw†½Êæ½ÜoºÝ]ÃW_Ql‚Û Ù,š3X‚„Æë¼ú|þơݣñá¥G”†ôÈCoÖàôk·¯u5ªÚfÙ[Ý>†Æ“QJ¶øÁt}„î]]’Oã÷-½òÊ¡täm ëlØ ƒ µRn?$øšé‡^?$žҹà‚€Ë¥"~Ï}ɸ/'ØöZearÙG¥SUQ+“Wf ¨1çnóRšö†»¶p\z•G×Fá pT"ö˜/SøÁö@¥rÐ9*‘Öi§boblgϤlýºK‹*ߣ»(Ä%Æ ·nï©tÿroèk':/^®\`ÝØò]søçPŸ:U·`@bnÍÎ&Ú!þL¹Rœ(!..úêßYŸi#JÅgìÞ´Ô ¤“Ód÷ u†P¼ÍQò[¨¹zªþÇ)òãà€Mƒ…¾Œ ¶JƒBMëgr:Ÿ{°ÓA9³M&»R­†à<†Yä«4I­Au F• 3N½èš0(ègf$IÙ›]mLõâàÉ€05ʳP…³Tþ;ªàŸ^qø]Ééè¦ï¥- ze’4e¤²÷AjP^ s™!¥£å‘g¯-/\Ыó{:æv“ˆ æc§9#ó?•a19ï¡ÄÉS\#Á¸E´åG)†)+=W%L.6v^€?£Ëì_ûÞÝéni: ÷Ž'‡p¦ò Öaò÷~ÛµlR†|^DdAñ­ÙªÞø’~‹ÊìüAuƒ…t¨41Îwäg*›z>Ó{»8ì¸ÔX³ª­ÊãÉ5DÜ'»Ñsʤ¶Ê½W‹;¹+«†Þß´zL!™Ì h |AÝ$'V=øcØò2 Ag €©ø»XÉ K¬q€ãC1/’ä/03šæ-ÿc†1LÌ13”’ݦDÐj6¦Ý®4°âØK…þvH=O+Î„Ü ¿¿äP*LY¦]ÿIëIh ¥Õeè‰"MqЦF—ܤ¬çÁ9x4›NÛÔÒ2!Øf1‰¬×‰.nT7^v.VU\¤AÅ}Và××»ð‡PË¡_”ª>÷¬Vä…Õ ÷J+ažßNº|㘋uvjx—Ú °HTˆæU`WG±ÊHí p^JpºP+fE­LÅ:º™ùVÕ¬÷"IÂ×EÜ=—úà‘!]BL‡Þþ¦¡(J ¨ eÄ,î+kW+oÝ©8‰½{fŠù@Rµ’é·~w@§M$1‘Guº"O§O¾¤h‡|÷µbËcåIñÍß\9›D@ù³JpQY°ÄtVAäÙWÅ&ѶñÛ9ñb›]TÙüøàl0ÜXHJ_úƒ•ðcªi RÌ4ýŠÀÇ I¶à]Ï…iÎש›‡Õ\Y ×qŸß§¢‘`´ÃªP‘D,0yšaê±Ù·ƒhd„:YÏ,ßÞ®{Þ\EÞ k=v½ ëž0L¹ QëñÒ{/ýÙýåÈif†7‚¼ØiP3x_* TÀ¸'ßxìö Øo@ÿ õBû‚[%NW+Ô]ÎÜš±‹çÄ]MîšçôÊê\¿æáåΦS`ë®»2Î QY¨FcÐþØÍ[›ˆ ߇!#ŠJz gŸƒ,<÷òÁ,3YW'aU˜öÈKˆ%üðQª¢ 2×!Fä$¶ti‚¥$‘S`ƒv<ƒ`ó¼\$Mܪ­ $á;IôJâ ^eËvÍ ÉsÔK¾x'FnÔ!ä hCÆ÷ÄË„»R"z ܶXÏFC¬ÍïH3/ð„€.!˜Š,¹.½’Ë=Üðd&+]xŽŠ[aá°°‚¨Ñ/øûëë•ûöý¯wò×úÞ7Ó#ÃÜfÈW\"û3×:¯l³?ð—:æÅ%Ö2vÖ@Ψ_IðîW\À¼ÈÚ5ƒ­›þ‰‘6þŠùˆA‘¾e;À álõ¶¥'^ˆ¯¾ê(¼~ŒV,Ò 0·CÆJR›ø#D,Lývœ2lÞé¸á~œéé„#•6-+ô:³Pýr•=(²YLˆŽI™t9B<cÝl².çB”é.;`‰·aÍ ë&b5ߊožÝë'Çñ‰ìn†ŸsÅ¥X0D4f4žLqÂM€ÕZŒþöÒ•ªSœ4Þ䇲Œ»Ó bpܰq[¦!¹ë™5 ±¼C™ïʯàÍT÷e‚FîvƒÜúµB&®VIäÕâu(þ×jêËah„`}é@÷žví1-3uÎ2¦UJE2¿Îv°`£k±qxä¬|Ùÿ€‹zLœ¹dŸù…ÞKA,Dò”´…Òà¶½ Þt‹Á˜lY"„/Qᆛ ‘èýÝlÝ%mAœáaZíAæ;ÎÍ‚’KLØ«±‡›‰&¯5©£/JiôG¿~¹—&ï‚#@OÄé+D69‡·¤ÏÁ©í¹iÖžÅaFZ21S¬(Äùs6¨æ6òTfk»\u=F6M¦ß3±Bî©ÎÆ[(cÁj«1{›- ÓÊö E†T9d"e„zFb²± ?RžFãÜÇ ¸ÌUÂÝ eVâ3É}¾"(ñh C.¦Üqíþ ®^Úܧ¦ÝÀVª…Ä`Î"¿î&J d¤yþÀÉø¯aûÕï6PÄkŸ~¤Ç¬MÆU 5D IO‚1m©û Z ê/nÃù‰#ZäfÞT5+ ™ÿyF‰ ?ÌUWMLPRÍÓ©3¯Ž”úœr?Îdäƒò:‚¼VkX¾¨ˆÍšwŸÒi/øYY| Ïᛌí 3³Qp ßÿ0gÜÂýn.%…PÐ*Û€Je¢ _+†¥ckfl°ºø–C=A•YP-ÿYÉþ"*¢ÿ†ú>Uæ–)¾~3]¬¤íêUª_ܯVfÑ9ª™îå±&ŸŠkæü!ãXLtuCÁƒ#÷áDÚ„'VØ6QɯÙc ‘ÙÊM²ŠHMµ¢Ï0öNôý'K™hžÕgZà†‹öÆ–"ð)޶+Œ”¤R„ú?æÓ¤ô£¯ât7²¹Qß¹½’|ÿ6Æx^³­dñ(RïP˜ «´Ð~“ ;J#\QÕ!xª0÷/ öîŠ~ÅôdÞ­ßÁKùÅºŠø:Â9þÓzz0í`AzÕ'â±ÁÔÞì¬ÏŠ «+>Và®Ýx~ݯâŽú<Ä5·Ð¡0߇ÅLjð$4@óAÒØ?VAqÃ’—+ÐÂæ”™FéKõÏþÅe‚£áŒ‰ìî\ÏPuň<AqWŸO'v »—ªñÚ‰\E²–Á^Ú‚všýåµ´î ƒÑH.(qŠiÀ· à´ýÞI]F™øŽ}Rá¨1PÆTro,lˆÐ5Ägëù-â×^‰ÄŒY Z«³Êw5rÈ/ +¬wÄêéÙÔR¡ Å1/‹Í$'¤rx6˜Éyå;9²c”ÊIˆˆ™›£É{æ¹)&à £$Q#¦tÅ%“rz‹ƒîÔ„¬ã¤@ê(áK‘ˆ¸e~l‹w+ÕÙËó“OyC]߀ÔÏ/^V]Î Ìâ´1ƒ»dÇAÎÇÀ·á– $‘wp³#±L*Y“Æ5qÁèW«Œ9†àN8¯BeŒYSmШÃÅzÔìÖ‹OäšÐr1KØcì Q¶Ræ‚mšzzyM{½M^û*ésð«¡´ Wu|ê´Ûqcõôt† Qô65=# Ë/è5aû P–@ËÄûä‹gø™Bû*ˆ¡ˆ€å¹þá›Ä¦Às{µŒ© 'nºÔ°R´ Öì{á6@.XèÎC¾Ë‹£÷õ[*‚ÇZéúÓý,šÍ+‚v¥ É„ù”ùRÕ”Ïú¯-w¾”ºØKÍôUíª|&T½·M»Œq¾Z&¦ÊºñI×îăp=•ØÓ€ŸOM»ws£-ÔÏYÿTÍP°+Â,2©ª¡èLbØîïêÖê2“ÇÊÓ"A±™DmJo)­v”'l c=³*–wkÑ@ƒ¬=Œ®Ì²ýxø÷—†¥P€%Åz²·vÅæè³¬ÉaTTà<óÓ¼ Ðø¡Ù½e@éG/([*ضâQ'Dv;/ŽÅ~w‰3tZ«ŸeZÀ‚C:ÌÀ„?ªLµ×™âçî!ˆ€ÕØ¢~ƪ}à ¢^œgÚ]ß]~`Ñ"vÓøÄ~bŸ•uÙÝa–ÍPá`垨mW³îÇ™äÀ› SÜJéÕ ‘?À×"ôº툹#&‹V:Ÿd?¡{hCì{Î~¬4ØñÉÀ( žØÓ|‡ä:({^“…fGÄ€"5SÐPž Ï],ë   |¤ËÕÝ_ú5fï°bܪ÷GoE¥ñ¬`Í ™G¹>©)‘óÇõ:¹+ºßg’.}¹m¨Œ¸å¶!ü^´æd'ÕÀ7 ˜±öVYçBc1†êíıJac±¥‚£(ÆYßÓ>T!†óÉŠ+œ/FÍá˜*Xí*'“…Ls.öñzmêšî‰eõEWë;7ÔJæÁ)ToÄçuŒw-‘ê5ˮ߳èûMÈ|ÃI˜Èf‘RÍgŒºg¸,ˆ×•H| ÖA9+„š¤&}tÃA¬Ðбï 2ÿ=,Å£„k”ÁÖ žò6í|âœB²’ocCµyN3¬3ÿ"Âõøµ}ú=¯:Ç#HM¡Ê¡jÞàmMt Èî*ÒãñÄ ñpØ Þ9býi<ýÈ•(•»ȳÉhß{TÏŒ…¨˜{†ü·ì)¿ZÚëñ´:!²^Z;õ¦Ú3 9yÔÕ`èÜàÍ G‹0ø>x€?¬|Ú¼¢3vpÖº‚œDEýr·Œ5A9%ˆ¤k.ÙCmàȳ˜’?dF%åjªø·Fб»UÑIÍÍâ°­ŸÂä3q ¯ËÉüÈJd(òÖ«ü¦Åã”:øÀtúiØSÜ!; ¥v›zº$±Äó#Bß(nÿ}Z²³ñÕKì¢øš¡±|u©þé̇¿péÏB´}ÖrØh.*Ò‹ µºz'ÈÏ'xÎMwÍ&¨ž Þ™Ï!#ÿ()Q7÷”Ç{Ž1œ-8GÇS¨r_Æî uëi¹(AÓ]ð_0Æ7ˆ†«ƒ÷Ы2‰]ü¢§Ì;Ã7½¬`Ø™âQM÷Ûûæml£RBÛ xÏuNÂ`#n¨"!¿ÆÜ°^™ö³mD…æn‚tá¿ãŒ¡­L]Í=JÐÞc?ý²1zþxéP½A×wm4S@vÖ— «ëTÔ¼vhÐCûJ” (V^ÿö;š¦Ó ‡5E«jdÿ%´ÄõÒWÕ‘™ŒµÑÙž«jýÍá¿÷ã5 }W‡ Õç*»¾ƒdÉÞÐw~2êB8¼‘”D¾Je[CÃåë0&‚RAîðgD÷P1×ÕÕ<§xù¥]ZCXÕSÈ*&ϱêÙµô:¦•µŽ#ï(nÿ•èÀ§Lõ`ö“m)ù ù³|hzž^ÀÙ”öÃ×g'tçö³ÿhÌ%×pá:®\vÃ&)gùd7á¢vbó1ÃÏJ• ½*ç‚Vn'ñBêÇžGYKJ‚r؆ƒ¬"£îtÜÁë}b•øÔŸ+"L»œu›«~ýmšbÈÏèX? zYSÚ¶MFXCû7êMc®q5É8þ:‡9¤¢Hç–äí›;«s´‘Q-#(qŽª½;Od…LàF³L˜G6×Ú¹±Ø7‡Sâä( ¿Ç¢ °”¡TèÉòSŸ“Ú(ÁàN~ÙÃÅN"Ñ:íûˆ%äLÿUF¼t—ºˆ^/B åÒÒÀ¼l–È] Í÷3Ä­Ñf§´ç4ÅŠó”!’¢N;&é¼#Îm—ë§µÁõ¯Ÿ$&?³8³âERÏ5B*²¿n}>j\[n"Õ.Q¦b‰ÚÀÈ4ãuŽþQ*9pƒTŠåeÏDÜ:¨s8o]¶Ù|Ù†xgdJ¸×²8^?4MKkƒœ¨¸&!BöÞ‚ LÌÕDÓ!–82rã=9ÿ¡òTÚ¨£ðbd}ÆmÈnk[áëU½«¶coÈp6¥…¹®÷yÌ*þžª ©QGFб,7F ôZDÍ­ì7,J«§J‡nv§<Ë Wí¶N<¡Î ¢¿Üû›MÉÅ}¥nÅ»Ÿù@(ǯ.?·]6®Ø›ZYWí*b)\oÝ¥8«îEµªˆÙŠž¸ë[G\¨žPØÝhûôâz¢óöSÞ=X÷´“bgûü÷|ZF¥_ëʪnå–‹c)¨‚ :†/†ÒG„ jG;¿¸|ŽýæAm8À0MÏ­>€Kˆ òa¾—ê-«VÕÐY+øãQöpÇ– õù‹ŒÂ.Ü+jã·_Ûæ8 Uze’sÉÉÁ{Àȳ‚ö ×¾›ïXcw]¹b¼ßŽ~{¾zªçLŽâ «‡V ;|o£biÁŠ­© 5zíѺḘ-IÒžDÔ^†Yòô²èXý• ½°’Íegƒuÿ9¼íÞ<ÛðÂS_¡é¬`áh½F A8%–\ëó ‘/hlÝ?çéš6¥‚ê-+âtÂ¥ tÆFs?«%f-ºŒÄw¦3AÀ0èøè“Ô‡ÿ‚îÌ¡G *šÏ–¨¶gûÈV‚ýL§ˆ7KHàÆqÏïaM SlE)&UiE*Ù ÉÔÃka+(먳¥ì–4gXEþ–Ïâ*®Qû4ôjTOc^ã¬[`V¤NYG |‰T8Qܱ»à—÷ ™{A™ÒÆZJñÉî-°_öbt*æX¡ÿ8\>¾áBàªïŽü¾JCÀÈ:i­í•6_)¿n÷¡ã3R‚Ú~¡Í m $9ŠSûVPËð½×:i4cÆ…!˜Fº¡¨˜ ú­AóâpÉÀ]ÌžE'AOüÞÈw¡32:˜9•&‚:é'ÈxCW›+`íZ±q€Ô€•!©S|cÛ^BI#Ï^1ÏÆ±ÇÏŽH…¢¨G¿ÿuö€»ƒL‹tN§ZÀÍŸu96Ëé³ûéx€ÅrEçŸ/ú¾K˜Vza·n;)xŽZã)&8UmJ¼Û]¸ÝN* BçNDg$ D">˜'†8^£6›¯\Ĩ͗-›©Óçu¯%ü4É»>ºÂú†“\RtÃ׸C³j°‰£=Bdtè³,‰uáá?Ï:Ê>/ÆP÷’NQ{b$™÷O-î¡xîÉyÌ{çap äPÔ)~±E-E†;{ºßä¤'}VΩӺ$wÜCC°Rš;t2D›š^…ý7j…]Ü“Í#Ù¹Hå ûów“¥Ý.Žq?g[*=|Jÿë®Õ™f‘üÓŠ{–‘ƒáƒÃŒ6Q+qOèî?€mH³Ö "’ û—ƒb•O©Xy9‘zŒM/?´oîN|+ÜÙ´ÿ{pK·‰UlÙ_‰ŽîyÍè´‘ðªEšQ . òiË“O—ï™È™$¿mDÛCVܸÇωh”E®¿¥Ï,Úá¹õº¶ÂGŽîì”ãG çØ»gT[=wSù±Ê6][GÈÌ~I [ª`ùŒ¨Ý…h¦ä}*]mÝB«|’ —.¿³Òû ÇÙ{ ­ÃZò„_Ë:éOk鯻ùmÓY²0 ¯äN :±¹¼›§úYêMÚ4†ºBÊ2•˜çâkÀ}*â„ZÞa7‘»¢B6QEoÏLåhwŽˆi{猳^ÔÓ,ïR3Q¯ˆ¢ýcT$"é¡ftœ¥$§Ð_‘Zd‚Ïî1ÜTE$ä>eŸ ‚îäP*LYŽ‹FýÄX½äÛs ½³‡ß„zªÈK­a=ŠšM@ ‘ÿadê4Da/ðy(Á•]%cy²ï6$Ó·Æè®}CŸ‹O3ÞFÝ›ši ºWpWîÑ„BB†3Ç÷Ó³ŠSq/W¬ O,³®ŽÂK{2®{ñ6'góïÄFd5Žßu ÙÒ†ßwïJMhº €IúgêC]KŽ4®v+5é’•WÏw¿6­"ò{–p¨—­!s¸åÈë«äg¤%Ï£[j¢x´¼Ôì·SÛÚš5ßñ®d[ÿ,.dÆS¤ÓÒ†»!õyOèo³áTXM@eÒý³’`M,:à¾Úýß#­#÷—÷ô9k±5zQ¡þ ¨Ä>…cTa8í[ Ä¥€‹7ÿ‡PPmd¦ÊwF7²îº‰ž?Ÿ½dP9bëGøókPÏøE+0ôq6òýŠ¡ÎW6Ñc=kMk“¥ö<ÛÇ=剷OÖEãŠÏmŽçüz_ؘ„\Æ<¥3y©Q÷æŒ$Œ*×Ù£_àì2î÷OTÇØ}ßgН•¢Ýš»r[7Ö凛»Fì¡™“úùü_æò!¯ŸÒ·qD•ÒòÁešzg‘{ŽÅ¸!—Ì=¢`ЫNúÞ ,yix½J:2{ÒO„³HêaEÙï‡ìZuŒ1-#Pó‰ËÐh´:¯ïs*í÷ß9úÊââøTv°[éPc×tÇ¡Ý~;•ë·í ÝY+|…®Í‹Âäˆ?T¿†D…4$”±…ïiöIÞ¯ÌPìÛlÐxÔÎô²ä0jQûT«]i(ßÅʲè%-Üw•Áj¸.Ó6±%áú ‰»Žˆã7VJè C8½úˆÛHÛ€‡¨|mЯÊo•”¿1 E`ìÿ#€‡WŠø¡ø×%V[«A”O´(á+×cÀÊ·ìð‰‚\ŒBØ»e}ÇSóuCýÓƒšÛ²'¾áˆNx^´éIžß-m1Xž¶sãkñ×â^„^‹²ì†pÜJÕLá|“#„¶ 9@UáLÓŽîn›À3€WCC¿ÐCI¾Ú³€ '‹µë]G‹hs7qy<+È~ f_hÍöŒÿ7ðD?8`øP…X¦'(nÿÿp>@ö›pd9ÿÿ(nÿÿp>@ö›pd9ÿÿøQ¨/åánM`uìlUÇ¡í'ôæ$ïd¨ ´Œ’TøP€/æÉT)^qNe(¦tá’0ÉPL߀0@øO¥oþ¿ò¾­3ý¶dƒ¾ã_WBíÚŸáObù=þG|ýîý»3|¾N›ÏŸ§_·¦®†âßn…oÚûB'Õ¾WÛÒoíÞ¿ÛQgêëïõv?Ï«ª¯á¸×ÏÖŸÕ³ÓêÒ/áÒçíÑÿm®dõÏöí×öìí¦óóúFüþ…ùó÷Cöì¯çÜ7É¿gϰo@€òÒ‡ ´™;­Mƒ«—»œ±K78„¿¦ÚMv«//C牯KòÔq®¶ò« NÓ)…û}"%ôÎ@]ß"ˆàièœÖ‹‡ÞV*»b‰š„TÓÏVHÅÈ÷Jõ1Š}³~wnîà »îÖ:nj¶=ÌzÕG÷¹‚k†V¯…6M™ËW·àÛB²Þk¬n§:S”E+~XÝS ”Z:ºCPŸÎà-—£kyl9nÀ˜ÎÑð.qÚ¾­½_ÂKà'niä[ˆŠ…àC›ðŽ$œÔN•Ÿéˆ>\ƃi¦KP8ZƒnR¨ZÅ+šgÒ“›¡-[–ÀgQ{Ì+KÅ }>ûn"œ;têä1Šù“$câ8ñ f_À&ÛFµVš“$ƒýy*µ=ï[^Œ‡ô´)˜‘EØxœÓÄ¿Q²©ÌA¯ÂÍ…Ðé^÷LFåžËøœB¸­.\\8YÈGlBåå ÷…A[?j´´{1×Þü–Ô«à‡×±VÏu+ )àO±Ž aÅ}`µ„ (›w òå r|¸ø 3r¿«ûÚ.g5¼|+oÿ=èŽ0³šs•x“è;ÔäÀ” DŠ@D~SÎ☛«¢G;ï¦! ‰#’h÷:‰m4W­¤8H?«˜MBœEý¯Å޳ß]¬†û¨5¢Ô‘¬€t &ænmW¢Ã]¦ÔgC8˜ù»Š*Fåk%'úÁfΡ¼Ì£½„è¼ÄU›º’ÚEUr'>t%ŸÝýñ XÇâ%1I¯çéÈZrzO¦2ÜncÕkÁäBsm¿+vZyÜÆÁh’5A´x|ºšô´úOòs¥Má2& }Ìë‚)rFqø£ùžÏemÍ ßTZt†Ô¢Ññÿ6rS§˜~i&S¾£ƒ.ÈÓ¬[³´l+Ñ÷©‹šZ£*x}—ia-øC”…dGî«úˆN(v†?Ã*„A"Ë&dBRM‡­—¿ŠˆÔ¦.Êm”#ËÌyõ2òÜ´”I¦Mɵ‘HK7ì& … žq$Z XQWDg¥SvÁ„8“,fÚLW龜€1¿•ÔáZ• éä‚ò.Ù5ƒÏ˜„²Ãuuå`Õ’·¤Ò"÷OkŸ#BѳãÓÓq(åO­ ôpØœÔÛEGC©€YÏ俇6飧]¹ w=ž0¥ÅµåžehAô—nªiç}¼¨H–(ý–¾/¤4Rer‰°ú9#öøSca窸u5ŠÌ–&ÉK¸ÃC¢µâ½¼qDX+–¦ïP–õ1(eÕÕÝŒ„0ìdp\Œ(™°øñ/nþ¹·…šµûj¬±0šAœuÿj¯CUUµuQf ôçÎ3€^©¿:þ*ýÖÅ:PöÖ¥†àIžÓ€³°­•RûÃùiJ3íýøâ¼–|ýV¢\¶ó¦˜/þØÃ¨FQe²’ŒÅüE!<åøE¹ø¥:ßÊá–r÷ ì.Ö¿ÿj‘-úÏmoÔË¿Y¾zdþœÕ=¤ÑÎ+'Ñ|åþF«ò]=’iE4àÇÁÌj‹€˜›æõSéD˜>Ÿ‹XüHFÌX –hkm‰tBŽy¹á2Å>7ï‰i7±Kм1¿ÖÃ{î˜8 EÖÖ½ˆb¢›ÒyBk+wlèeÏ ¼b©k?¤5!Wào»Æ^DEÂ{P¡"ûmIÆ*d“ðÇ»PU7<¿köô••‹IGIÖ'WåkàÛ‰cþr~[{äà„9f»v¹¸€Ù£(îÎãtážÏÏ¥3ó¼jÈ›<˜¿9´íš¯VNAÁ®sl%j+ߢù%¦ŒtÃ#~ë6Œ}¾Ã¡6´#p*þ§Ú-œÃÛéóÑOI©¿”€ˆ¡J¢  Ì›‡Hu+襄 Ñ¥¾‡ >êb`E«?ÓªDj.ÏÐ53÷ۆߌcÍ™è@5ºWW™û[YáÊï¤(]6¿¥´Á@C-†@©Á½%À}Ù1±ÿ,÷ñ*û‹Y2¢·W-¨ ‚×5ÏlÐ|Ò¸øSàò<ÑúÙàŒ$æqËÚ)ýÿ:À>ÎN €­¥O¬B‹ÒF@Rà߬§a ÝnôVªª0‰y[ z¬´éDmQEÎn®gkvrjô> Í#B‰“Ž…–”ð$q†›ÅÉ[Š"˧žßr0„Y- 2ú&²ÎX|¯¶'ÖXáAàöZ b«ãèÝBœQêwTr—UøÚùi#KSè]QŠýiYõ]âEiã…Âs}Ð%8öœÐ´÷=:A•ÀnÀÀhéT;ìlÀfˆcȘEÁÀD8ÌÑé4ÿó!|'Ë=öCºSŠH†"Õ)0Úò#ß+ö¢œú4d6É—,*P‚Á(ˆ$Ùè\ír(¿"òöžº¢)mô¬úÅË-X&ƒõÍôäÚâ^ì¹ÈÍ6éCxQ`Ó“Õ|†H•ÉÕ¥n’wnŸŒ«ŠøVb“R8QiB…œ©X§ö+h¦Á¥YŸ·æö¥¼êÅ=ȱÈnó¬qS'¾„ÑîÍ{%—bþºßXÔmâÿ0èåÁ̶fzá׸Ä-Ò¡¸•bÓ\“5©;eË3g¾â Ûh³l‰~Ê.QGÂ,¼yÉ«zAƒ¬6qó·%ùQÑpgf€Õž”•ÜÁì©®ï7wÜE[èH¼ ß³N‘4gPШM›ã—ïÒ‰†Ò.kXGrG´ô†[J'ÀQZD}ÐýT²/¯¬sá·zq 5â5¹Ù¬.º…>³Óµæx€Z†“›‚4cÙ6àÜŒ“«  ÐR  ßà’¤*8Þ̴ȇp{qõqûM\·²÷G›†':ØìÐ+µA‡Ò€ÁíW¬ßÛÆÓ£fosèà€´äþh°ÿYwµÚpå•¥ÌÌ™¼Z[xE}<ÜÇ'4qÕ¶~" ”ü2âïbÔ¿øÕ Þ,`«ÝÞ+?Ds]J÷;ï‡ì²+Gõ#k¿Ø§u»F\¤IXr×á6¨u"~7shV™ÖNÃÎöGUuasýáèóJv%Sáój0¿Û™ƒÚÔÐùgŒ¼ß2‘>á)#|7ò jé3±’ADW@‚Ÿ3f]ëŒÁ#ijuáÜfAüa\ïO;†¼”fImÏZCÉ'ëN6ÁºÜÜVðè`ºï ¬L®®!Ú¯w÷r‡÷E*K(?ó²*¨~5o2m‘UKz Ú@JqÝ‘sC{@FæÑ~3´Y‚,¼*ŽÁn¸_õ]òæ¶Hu¨ŠêK• í²H“-,~VÙó„EAˆ}•wTÿsµ*À‰ ÆÐz’Z qáÂUÇa6š!àP¨¯´¯o²kìßâO¬¾Î•ZÔ}—Ù?úµy¬ãO¿ÝQq.±"Ávë¿Å”Ù1e»¶œüÖÜ'=¨Ö®s‡Ý8¢³©L+)8Vºˆ «oªìƒ·´^pÌõ¡VÜKi ´+)úñoY”ò“g>†‚n£¼Þï<_r ¹,rvªöЊkq© x¯zÔ ›—Šó‡ 7ÏmªÃÑ"e9i×’ŸGÅP•ê¡“cÞÛ§“HšNÛµµ`ÕÊ¡°+¶ßÒ/ÌêCÐL9 ( G!vWçâ’)©ÞÎ'pN~Wô¶i7£¸æÆÿ7ÉáÕx9+Ï@ƒ*Fð³5H܆ûþȹ¡ÙT9ÿ{¶+F ¢à‘‡¾ Xj#’JyÊ)<ײp?æ™_voÐ…9pã±ì¥äËBíäBŠ:5Š0xrUW™Ãk3(6N²‰,9­±j”ûÏȨÊsœÑw‰ˆ9Q9Åš?ÛÕçæÞ6ê¨%é~PФKس]mC,`XŸtH‹=1 ÿoº*GûçRêï×À¤±.¥ ¨ ¾úƒÜ ¤$ZÄþÓpú¿Hòø?ÉÛ¡Öâ/²°[-dc7¦F–¥¸™:á:ã°çhXOá3ZJú)Œÿ9‘Ü U>yüÌ!öãÃx¨Èíú¦üVƒ@½Û·‡uj,“Ú3çÇÃï^0:„ÚÁnJ.NÈZͱûMò–d(’I2ÒÇ/O™ñ4}k•Cª²®¯™‚ïlÝ{xÌ&Pb:Îx »:y}ŸN&_޲QÄIâegU4…âF-õG‚ñü`ºêÿdáH¦[XU4Ã=°xÉ Á2 Ò!p£w_©<+áShwÔìrš\[†’1‘h¬Ð)Ÿå™Â[KTûé€âÅ€ÒGD”»ÏM‘ÄÈ!ftùÑ» 1RUº((ÆKÉ|¥’•Pï"{üP)—ÊD={5ñV- ï~‘Í˜í£¾bÒr¹.‘8ÈI…¡´8’/Yì VùÐ$f…ðR-píÅVÊOו^缨P³¦ºn½ª…¤KK¡XÀ”à5i£Ë†\tŸ"ÝT%Ÿ##¦Pw½æ'mŸŸ“ÀOÇò‹hð%âa ­a\j3rg- ˆã3|«ëu2öÜfs³<"D·~IÊ6ËÙ­o¹¤÷g3ñJc™Å)° -¶ÛÃYTÌ[SÎ À?÷Ú»“žrYòÂK¸q+¯Ê#—oöá5ŸhÿøDÁV.MÝ€êéK›Æ ó ×á…•V²’äT6;V!_Ca®¤Xþô/ÿ\Ò9¼GMœ5—ÇrõRþpòzÿDc?9H†£jÿƒvˆ{ËËS9v!F¿4Fe²±Þ2ÁºŸÜVÄ‚={Á¯ØkùAwHÂJ˜U³oاw8ÙÅ.Å}íÊ38“P²ÿ+¦ÆZò5Æ»h÷±Fºj O›ö»#lBßÍ/ƒ¤]\%sy;Ž+Êû”F _Qè´n0óˆy˜5ø‡{쌬FYÂöRBrÔØPn~¬-‡7†ù:AycaÞ}Úçùãáª7-Zm¤ìúënþeOðºˆbQØ ÿXÄú¥tÍ?¨ñ\9|°¥ŠF°ÆÖC±Â¤˜QÎÔ—ú\¯ä¢úaÉYԶ䆵O#yÚ§1áõÒÉç©e‘sL:2N#ëÊM—uBÑ0él~×-I‘úï·J ü|üXt Ÿ/Aí?Ô ŒðÇ‹Ø@Ìéï»Nϼ%&ö ’ÙëæGýyÁìœiÉ—qeºgfÅ®§®³p1.¦²‡#èe;W$YU-ÊBíóD´GºitÛÀL€¥óabEõÇÔ’Û[V`}<ŠE‡Ø0A>DâÈO~Åw_l9ärîQ(F`C„Òš^ùº?|aIFÔ•ÖÁ òw¹BÆ®õ7=(vèøó‹q•ö¸Ò·˜ÏPÅè\OWÜ$aS~†´S%PÔû¢{BÖ¾+ëŸûA«(—TŽDóÝÀ;ïëcÛ.ÇyF¦º„F¿i= TäÜ­)Ziœ$6ë“ÅÅùã­Š °9[Á‰Õ<|<Æð ½ëRÐl©¼Q¦æIUm­×C(Rw;—ÏG¸Ü»~F A’`ÍtÓ²»»m2—†~Ïwk_²’›¦k ‚ê1a~Ï+¿Ã’PnT&Aì²Gæi{š™E|âÌuù®tÌñ´sü_\Žíd퀊øòÉp8J˜ 3&x.ÛG«†Äi%çª>™6ˆ ÃNFË ºñÝÊJE€˜Í¶§¬’^y[-‘©ºNc§*˜:¤‹ižðBu¸UWfÐ[%KvÉQlÍ›poPp@®¤2Ö²µ·Ã»¿è"Òvã4kóu™ÎœÈ½’ÍQ&>äýJ/F`L÷ÅWÕYÿ ?—_z¹Y~I77RT›î‘-ˆ4lÉuH¾ î›Y+˺‰‰(ؽÀVHØŒ“ôcòãÅŸ à9‚«éN¨û]À<ÀTpBñºd‘{m2OaÈÀ»ãòë±›±¨A¢ZÚ­q°½[jY‘7× åèXäεӘºã(ýêM#èh]|ßéÞDq<Àuý­±(-?°{„‰ýÚÒ’¡øß+Y­p츪ú™ìè½",*EÜ{w“sCÿ_VL.n?v§#L|Àez ‰n"ë/·ŠHaÈmi‡¤4—Ù‡A¼þ·ÏFÊ/~áÜÚ"éù KŒ•ÜÚYVŽSóE(ÛÒî'v ì¡0¡G=ÏûÀWKdÉÐiÝÖ?’Õ¼Ðä>¡k­šn(,Ä@2~:„Y\[R Íø8ˆ—î4ÓÈ(PÏd3 âÑð¹<âMý'çÍ DNö¶”] "R)~½Yaô½(>hàý03ýa$`è¬ë1š–ž2;¥dJtöftò›F¥º”ü™ˆˆª!"¢QGU¶9âGŽ0ÅÜ€FÉhž€çV¦,Ê\HÚ僔»¯G.cÊÛ'y øHÄLÛƒ5©§Z¡ëeñ¨«c†;щSÎE¸ÔS½T2ô4¼JêPbXlGÞ¢1TêsNTƒ3¢Î±ìþZ‡b¿žÔjxóRkK¤xÒO’Þô~©ãÇñ #¡r!o‰Êò;iÈv}¸+é "§1ó©¥PNÔúhµ°µÛ± Ó [0ì5½ý¨ñ”¨.ùPûàxVÿÿzíVÿÿzíøƒ ô «HäÁ^¬í µØS¹û¢ £Ëë4¡¼£š ˜"0ÄÍM"î®?2yŒb¯>Ö0ž=· 6u¶yæ`ôUtß•á »É¸íÎÈL%«w`®jžÂ•wl€âå¦x¿ÍíYÙ"ÎqÞm©Aí5©h§Ä ‡‚—Ó,×ùhÈ À9*„Ö,ÚäP—“ÝçBç½£= ø’äguÒ"5f`=0$EÛIfk„t{›¼—þ‚ö‚:1?h¿=—<€ÃsZÆÍÆx  >Žë}?s}¤cM3âW³¦W\²ˆpæP´{ÌŠ?J­;z«;A:­ï)=aËv ׊OÊ>ƒQGmè|Ÿµ¶ÅæêF’_ït…éá¡{]ïæ}p¬ˆ¹„ÉŽ¦j@gÈI!Œ°‘ÑëWðZ~¨: ;ââ˜nbÒû§z;QyÅ ÏhJ$ÊôMZé,c¾¤³ ;Ý/‚ª‚OTŸ S$åôØ7}K¹‚ÚÎü­FÞ ÔŠ˜Æôé²s#áUÕì*JýW{À –…íÍ[ §†ä álɘÛ›ájÇ·Œ,²™DcaõDRÜÂÐà¾s¿ ,ݸÐûù7wIxØêˆì<ÒOé®&b¦ Š¿NÊÂl…¼{Å}ÊÁ_ÊÍ`þ—Ÿ3bHV†;=y{K8F‰áÉ“;ãl¹8ô+büh+Ûƒ ˆ(Ý8%çÁá,“±õ4™Íñ?0ºã²’½ ö•š„V·šýÌ·ï0ˆ¶?S°´…”Ôr #³NóV³µOô/ÎÌM4•mµÍ¹HÙÓ2Ä"D+ l¹)Îs³7êZZåwQÀqû]'R: ¤ñ[²±>¢rK?Ìí>Áú«D:áu¡2ÍÎÞ°#µ¬y績iÁb2WÙÕ8ùQzk »fÊéjÒ†-ó\ÀO’ðÝíÞ¹äfkZ”Š»ç²ÍÁ)95RÖønîEJR©]z|y± œïÖÞ2ÊÅx÷yqé(Z".I2`3çùÅã¹¶×P N°’¿ÛÏ',óìj´¯‡¸3rµ4,¿Š¨aÍd¦mœŠ‹î¾ˆ{³iʇ_éö^`suâYŽé:X«®¼”ßíbÂëdø‹\!bø5¤zA0þâžÓŠD’h5%zxÃæDêª6¬%·ëL;¨Ó=«ôŽO«íâ\)Y$qÁê Ä":}ªšeˆ nò‡|–±ÏÍÏOšªBN=J,)ŸÈͳìªúÍþzûþßÕʼnˆ˜ C¦òŸæ–Ý‘ÁX×ã*äÜÐ*óÉ…díÊ—.V³ùn§©Ãa£þ;ƒ~ïmñ]kPÀü[5Øê+¢Ê—RîùŒRmó¹ÍêÚW÷$Zæb—À¥§‡{ýx« ”•>4ÔûoVºn{oᯊºç`•ö)—&\‡ùñ4ë*0iŸ|ÇÞԪ堩»:„¶×£;%…áÎ3fŽïZ—þ(ú‹¬‚Ïn*sWÌ`»eqM[ë¬ìòH%(±$y;±†LÌ´ßM/yûßGÅÎcû†Lgº0ס~ðÕñi:†1$hx›?ö›‡Û©F¢ÂÊëŸÓë{Oå_Þ­¬“2ë…‚ÇÝz¬!Ír¡{Kõ·Å§©D3ÜñˆÊ øøÖî‚r"f@ü¼ îc¯°G@ÎçÃ|:3·+û’ .‹>Pf¦;nò _ZeÞÊòWÐY($:÷Ε9ðX«»ƒaëjßÓÈFj¶¥XDGW¹j˜ÏèéSþúu¨˜ò@®@¤lµ[öõBè¸L»¼Ï 1ÚkŒLHZŸÇšç«J!üQ¤Ã_V’ ¥3:Øu¯ÖŸŽŸiTÕŠ/YžBÆX¤€zRþ®Õ?¦_Óí¹b PpùZ."â‰<ñÍΧÌ»t´ 9lD"NA@ÄÏð\럚·hüÀ›EÆNˆ`Óò)5§§ÿCáú_œÝm¨Ú‰-•ÙëU‚­¯G†{3Cí*9“* Žù$‚—Õðœ¿yx³ZƤ¯­* LûŠžÐáq{`¨ð}$ü̾ü¬9©S´éY”Ë`'öm2|VÈÐÈÙæ_Š(}mšt¦K‚baˆ%êèØZÍümÐ=…ˆÏEë ùý)Á?”c\¨`Ú¯)„•Ø¢h30ï èÀ8»ÔÑäâ®·ß‘PW>×Ðgšט“Xlu©MÃá õi—Í{Ïϓˮ–•6¥q KÁä‡ÔX²ê˜ïN"Èø~É”ÍÓX¨åÇuH±*Ã)sõ˜(L©J ŠmËXû_¥íÊ«V`•0kÙ_¿êv9ʉÓàùeÜ•{J»÷ÎfZ|3¥ëVÎkEÒwfBI‰PË€üˆZ($ahÁºô9w“j`´ó§ÔÔ†õëQ z6Û¬ 5MQ„'. y‘˜Š&ø²¦î:4”bÆ{ñ +¨$Õ—wõ¢e€ÿ|{¡m¯š(ÒըϨõƒc¾H€kÉ‚È>þ3N¥ÞÐW­}·¹™@›ö.(fnåèמ ¹Óã¢@”ÒÍŒó“7ªŒZ6˜×­ ŽmºAq b[ìàœ,êÚÓï¥<–®*À9¾œX‡eKÍ®âÑ×wÆÿ[…þòórÅN²= yˆÛ‰}„ÍJïOSQ®|_­Ì‰ä™±Ø±üNAA„0 ³ÔâœLեиïNß3¸E%D®¾6ŇÀ-»¯vf¢‘ö"¸|÷ß± xè²u„œ«S¸*w€!F:œ­þ¼,¶½‹ñTTÍqjé¦^¦÷`Qwñ êÃíôʺm½˜éV†ýôkèáHâkìÍ™” Ú!Ã+q\ôÙ{‚³Gâoi´Ö©_&î?¥³/'öL<‡·ÄƤ ‘iŒ!Ô;x¤ƒ®9…q)îÁùp­mÌ‹'…ˆêÖ2k¬ü)œóª-¬:x©Ûë15êï¡w%»¸nw­²&pIñoQ¸tTNÂ1­aÎý’!‡þ{HSâ¼ç«NÚhÐ…³¦$UmÉw æö˜X¥§°ÓåâžW¦mB…¿×[|\m8:,_‹ú1¯+_û¹/‡K@ܽÛ!Îóà .yä¹l(9ßv{US­‚ËE`»ZÏ ’ãR¦Î‚¢r‚m£GÚֺ͈„ëy¬ª“­<ì¡H­¹ Ÿ4õôAC"jUž*WåYÒË%ãÉ¥{¯§Ø {²’ëkçoô;JÉKžÅJEÐĩ㠢bW¨’ÞN 0™©‚¥h[Z>ñL§œõ€ —ÇÂ]ìœàyóÀ­‰?…ù˜´^§Í¦ÁPíñ&ˆnÂæ )‹„â4¼ÕŽŠÎ¡›íM×j ÊèÃۦΠÄã,Þ¦ZˆZc•$ŸÊÔõ_dÒ6º×Q_>©]𲱟éƒöwAâŪ ОMTLàãä ÜÐú﫯RxÇÐþ÷ž±^Ž8ëË…Õ/‰Sþ–¬ÂÏB |7€! Fwø[“ÅSÄID??þl2Ÿí²í¬5i;=‹bÕú-‹î:B(,ìçà‡Ó³¶ô­-¢œš‡)8NiÕ0ÛÖíEµä^ÙÈnXüq„¸ŒŒÕ2Ü3…ÊÌs¢ ýˆÌ‚ Èðñá¼­Ë”_Ó¿Ý’1¥%Õás¼±KYƒT—¨B‘J™WN”@–À#}§Cɦ•nü†©×Êôý”K ØÿK‘²¹KÒýÎ)ßcLz‚å¯[Iý†¿g>±ªÎ»Û4×®â[Wè™ 1ˆ`¾ßÚfS›dÁ9¿iÎÁæÂ°¢NœES´9Ìó@Á;IMn4ýoå½ë_‡œ'åwéYòÿ÷kÐÐ?ÛC¦‚\?_)g Ò›m.HEvzg@°¸!øoµœiðl·µ»²vÄêa³›… UǯÒ.xzzc+rÂZ÷YÖ³z#Œ)ÔLÇrß8Ô 'Lî\o8OCdß;p+PI;h@=h¥L®Íú ½¹,誈Æ]¹.[_7zˆ³ %ËS0¬"û¦4¨;ß¶®ºÛ;¶ÖÖÌ0ôlX˜l ñO]ŠºŠ©ÇÞŽST§âE9ýÚj)­59!esQÒ±dò‰˜¿èXŒ´mŠŽZzú§ÞlªÉOþÐñ4r½Lš9_¢06ç@6õº{k‹ní)4›^òÞºàPd7“©GL-¦æ‹æ>ZB™i–#ùEsᨾÜ/9HO‰Ú-©?CZìö%Ò+É/0ùMñ½ÐÞo ®}u)Ú:¥o¨ÙñG‡ÕÑ@nqHo0>ÖŒ¶²ŽÃœíùj·@ˆ2æzu"UeÚ¬]Ó¬?ö\ݰ‘œ_ŒS$eN© ŠypVâÃ$´ MsˆNÆk®œî©™¶Ùs°)fÕ’¼tp4ü}¡á)ÎZ§’Ay°0ó>ìâ³ðê °ä8…h»÷¬êtܶÙ-sÓ âUŸ÷Sꉱc@ãzç0!t_ò+‚pÉÑ|ý¢ýö,|zV¨_>:è‚f©À4sÔWšD¿dL¡#ÐÃÓiO[1ö ¾±Ma^ˆÖÙGìr]Óö#fè†3VYî¶bé¹9©|FÉÂU÷Ú„r‘ÿ\©æ†‰ îÜ ¦[évÑÕº qº5&kÝkÀL'C=3BvTHÇcBýxòÒ†Óa S;ûáÐå¢lx§œˆÁE¾±´!ZÀûÌ«ágëèâi@”˧N6·õéè°*~Bu \þÅŸ‡t¾9»D×Uýe=!‡£Š8ñèu°Œyö­®š]”°k‹Þm ¿´ŸÑ SþÔ4ÓZJ qc Mg‘Щ \<[t›}O§"#ø¢Z^ý¹Bº ð“)·.J?ÐE)LÏR%R<©h­#X1ø·>Ôüž¿lëG­Ìé'FbÅÄhw 5K²Zƒ–$Uç%&¤¸—·&]…RuK×—ÓFmú«èTÜaQ bwÑnƒ vø‘ÜãÈøö,²OŒRN– ~ê}°Q|Ë®¿ˆ”äQÁ³à?~6#àà½@=ø‚Ÿ;í®Óžéȶ·!ú:O®æTh§ÿk°p~ ¤ ñ2oØ ™Ðj𠸾ÉTÕL½Pã^T° +S/± ¾kÊ)î*Y`zRr˜fƒà_. æ£b]"ÃCÛtÆõ¼8̘þÜ}p¯€ËF Tó廽¡6,!¡¼¯VœÕøûoOG6=*t·é@;ÒìMR¦\Ó»´Æ)…Dcdƒ¸/¥Mš9‚`‰yœ"P"y4˜±˜,.*Y.eÏ7ûªr+ÛB›£Cÿ;jN5RQ|¦ö8ÁùOBpp8q ö„+ݧMÅ¡¿×~DûG·KoV´Îtÿ8¡+âÖÀ0l‡ù©ÕðyäÉGã©Ãis¯DAÒ× šÙÍÆ¼P°šÖj}•ŠÈt?2©š„1 ûÉ“­ò †âƘ^l‘Y”qlpÎ}Æÿ=j¸Jýƒ uwU šÈÞfÊ@$ÿVò)›Óôk–V!GÁBçÐ6Þ¦BBƒÁ¥{0¿´yŠÊG¸É‹3ÉaÎC)S×e…öÀl”ÂÒ|‘HsjlpƒsJ%ðåßtkæ•có)m†x²ÖNDê®r€§ùB‹1&éÝ=­6?dØIè–[Yß¶Ù8wU½´c8©½ß[þä¦ñóª"{EMâÏØ’Sò{q¥ÀõhU§pbfC„VѬÑÙS"B¥ï>®ž>Jôt0‰äSœ& ."26ŒéûÓk Wº¡K . ÇsRÖ—Ì·$¸©dõä¦'Cœ>/ ¸ß¡öùoaÚ…:þ­’~$õï6duŒoÿA¥ž±XÍ0è§²š¬E´J.}QMv·Á;¯[ö‘ ë:3Žsfˆ4Çþ{Œ}–pº+ÕtÛc0ûÄõDê\ ƒ†^1Õ4£‚aäÁÎ;Š…àÂÝ ’5Õpç7†`ÿqiqü7o/{`\mö‰bé¾JºT@r[pÇ«äÕœ‘ÊkçÊu FEJ{E§ü˜åÏ$z8-.•¬³RVÙO12@2¦Ë]>‡~ʱ‹ dŽê€}ñé²æÍ²2¨ùg+ÅT³y#©.áùøÅ-Î¥ðØ õëËÄ®0–ßTl…ƒIÛó÷!/ßÿUÐ!yàkói\Y&Uýý× ¡Ì4_}ªâËL“†É„Aæ~Þ% nAž‚žž³Ç —Ä;íïŽ PÝ4y4 Ö zµ¡àÿg£ó>ÐSp+#8C ¥SþïQþÚ”¹kGJD{,ç^ž ¤ZiÜZüN%Þ Ø«ò òO—¡}©Jv ¶Ýï×0]Gè0ó¤O¡ª‘æVBû¯k@'>$j%Ý¢Û¿HU+¹ÃRšÂ!Ò¿ñ¯A/߀æyekkËe¬zÊ[çÑAQ”ÊoNÊâð¢½ëð—ˆ ù¹¹²j3Ð8ëcPëõ÷ÍŸÆÉ# ]¦Åɤî0¨ Û–ßê ÚuGE=­£8!+äi‘E‡n3Ø'àŽb³KÅgõò'Ë"÷BpÙ ˜%™À°šÏN&V)g‚º!\uÃE31Íâ“éߌϯˆaªÐmq¹\Zf½ åï8¶š ‘Šá¾6ÌY,÷/#O‹ê®:M³­ ¸Ö¼oC¦ª$<§`)[ë«nH E&ö_Pôx” ç—øyK` ¯HC`ÓíÁlq«` ÒU¿†²£šCX¢ór.bÕ¸vfékw£€mé¦ô½ò¦e !×¹ÂLÓ´¶•¸wçÆÚ_Ù·Òº:ßYšŸ1w!_ÿO€ßÝŽ•k?Ós½Û0=Óo´Ê3ºÑv:hþÿ$ÑîȤd]«ù‚ÖÉå’J#DJ€ÿ]–ÐSä>”ÍD2–½åìÍ„k<žùëÉå9!7<írn#ªÉê…K™j#·Ù'[çÛ/Öï}¿²Á¬%°Ü?~€›Hg/\=IUcü:ÜLÜCUÌr;¹ùÉ‘qÆ(¼°jÜ"ýw¢y œ5b& ¿º2.›×Û”GyÛ9§Ö¸+&À'­Y-ä!ü¤¢™b -¹ [p¹&Ïå_¹Jw¡+Y6¾—ˆû÷ó®Q…¡!½þ E³E½(ëZ¸pbIÙ­Èòêr‹¡Û˜Êhâ":.n¼ü‘™¹»â=ñYù€§~¨Ì¡ýºR-2Î’ ±™Ð˜¯ŸÜ:ÅÚ†Ú™JÁj’$Ô/¼ׇ3§*ˆ!KyxáœþÇÆ°ÁYXI[G™(Wøàjˆ%~ݯ•œÑÛ\Ï[ ‚RËÏ&轃§îHI!0cý#Gð7ÞfY8 YÚšÇé$ºôÐY!‹?´žX#Šy~ ¾|M‹Â\Å/.È)P8auà gã:ïjD<þ‰áÁï•€YQA®â29oÝ&oôt©wý0žàåâþCµßr<ãûí¶ÆäÑä9Ð ÷õü¯ ñˆ‘h¨inÓFåÈVLŽ0zЄ‚ít}é®ÜÂ%­”*YÁcBO+94ºž®>1ô§©˜ˆ†÷®ä­mË~ˇw®Ñãî8—7K óöÄ!äµÖÀ"réT'ÏJoN¾@fU'+W¢ÃøY€Y惪Ùâ0M¦G½Ö§÷Ö2z.›;”¥'$b”F&E”}í27b–W.ü}Þ'ž8_n¾ÂnQ$ÅÅÉñe×X#šNòüÌ¿>«wyñÂrg¤e{Ô%N«ÆXCŒÈí‚—_Æf‡ÓEb_¢ÎN-"ðÊ©€ׇ@v_å<ï#À±¯ ‰ÆeÆón=µ3**ˆH¼û”OüAlìF{‡Z3•EœDG¦ÕE ÞêTí&<“UûŤüj:µ"kÁ¿€|»¶öé'³ ¤Ï¨›KMU¨üþãC2•}¦#rÁÌ3¥ õ«»äD¤urš[pÑRö)´þA®øC<ŠƒÕ;Ö5€Ue@äÆÍñ3ÑÉÍø˜”ËÚ_ožõÇbGË]vБK·Ó\R"¦<{fUÊ HC]WSì®ÏbÃ…)6M YÎ8}G¿Nï%Í]3^+{z2ó@)4—Äù¢»ƒÚ,ˆ³TÎBí(éI™ yÖëÌÚ»ˆ _ÍZB¶Ø@=†'»"ôT8tšÌáèH„Ï'&ÈóÁqIÑkÒ_ý5Ò²ÕìÆÆû]U›·¡z|Dj?ëâVEÎ!¾EÂè0~g<Ž úˆ0"³†r{^üÂpǨ÷oØ:áÈÝ£&ãÀð›1( 3)U7Fû ôS+¯ÙjC n?m¢rU0Mñ‡Ó9´~ÛBóÓ´C/P"“¢£9#&=uǶtÅ^ÒœåQÝ‹ #w<\xß‹¹©„qù© NŒ1EDÍJ½µN)e?idçÄø«ÔTáήÀ®±õéŒQ!q‡jÙ$€³häq-øZLµ@DKôªßTAŠ^èZi…ßcEî7i5éaŒe³{’*²9àæ¬®àºQãÛž[­´»ÔÜ”7lÐYF(ÜB˜Ï' ”p‹‡ÁÔ¬äÈfÓ;F¤ÈÈ‘5Y]×;­¹2–V‘ȃ_¥Èã’Ú Ý{ïU¿â%î»[´ÄC27ó—D hÇ]‹ÝRz½:ík,T̯l€Îæð¢L )ë`“4”Ùi®¨ºâ9W|Š7¯]p'‘L¯rzâ‘(¯¼Ž}ooz'Ë€€Å‘—‚£$“*¿À£OÚÄP5òSW¢îF:+Pt¦ÏÁ[“‹ßØC%l÷G…ÍíÓE(Ƽ=æW( Å4ãi\ÄçˆüÛ·Ò޳êCZÐdYÚ­]BAjº¤.4Œ~ËßE.¥Ý¥3øý `)‡ˆl<`çé—Vñt8ä”û*OFÞL$ø[¨Qe”µKæÈƯŠ7³¤Á[Ìùm~@øK™qº½©LаC9¢Ä”ûÅ;êP¼TïµSØBÁã¼  Î!ÊJO¿ëñMñ—û¶žß[c7Eð®2Ŧµá0Ü»8ñ®[´Z‚¿3-ë·)ìAj¤TM…ÕêAƒé/nò39Mž®'0è#ZDäÆÇÛ˜ûJMµÐý«È|/d®¦fÚ8á³JdKGÖãÂýÐÄ­¥Y.RÓÛËlã·óON JicCÑŠé(–Œ¡¨èYlÖBÜß´t#à'WÊØÍ(t5=Ñ%(ËÂOꛕf_O‚ñæ7Œ~KˆÆȹ¶/0Z†LÀÐ_)&6*ꇃhNaÌ܆nÐVòè.Ž”W“y‡û·zÌ8)ÿ:ežÛf=÷ô7lgQõüìâèC$•n×.Eþ×JY\Ó €oe‡(™Óe¹£<ÁQàÌ=¿eã§0 L‡ôrL£´q ƒ¼jh­ˆãdž¾ oÿM§(£ìyݹKþâðmP^nO)`ݯ爑¯äŸÅ^ëšnøæ£/§ L¸u`3R,øOøYžèï ]°Œœx›‚)uM·ˆ XFã3".i~€[rÐ)ôÚŠ®*qÀ8>PM o'Áù›ƒBîÁBsEöƻ՘˜rVæ$¡³«{F˜•á<{ îyûâñ•lìóŠl÷M2½–Ú»ÿiêâ¿ÏÁ-x¨Yt $]áÑö”É5ÙÝÉËS‘¿=e¨fè):ûXýsµ4âö›v^ûé¸'ePDÀ¶—»¹¶“+èíxå*%wY #–`ž×«BÃÌ]Wì_ä™`K®K&æYÛÖ£& ÕB!ÿf‚V]Q£?¹“ŽswS÷ðñ‰tô¯¸@>Jc Èü´) š_’ÓbîÎAÈ…¶÷os‚ÿ'`sÛÇ$Zalˆ`dsYÊ£En°ü$ <”|’è£Èöâ%¬Ü>sK¾ô¸Êz±+•§%X1%(dƒ œËQí•c§iÄÀ Êßi2ßùóP¦Îƒ>‚U¶3FwÃ8;Wa¿„´ K ¥ ÏÑÂö’ŸfÒåà¿bǢİ/Žw?úµîòµÖ—¢¯;C£‡Êj…þ$c .e+‹*Ne¨bÔ=íNDˆÉñ¾«öÕòöEõ^¿Û©¿¶›ÉðúÍ|çÏè?öôu|üýFŸ?ToVœÿ©ßmÏ¿hGí‡ÉÔ íØ?Û´7ÕRçêè“õuÏ«¯ëíê¶ùúÏú¶ª}ZSü:Æáý¶×íª¤ ïÛ¤_Û¬Ÿ¶›ËäìEòvsŸ?¢OÛÓwçÜ_Ÿ}ÏŸh~Þ–òÒ‡ ´™;­Mƒ«—»œ¬n9BÁ~ÕßWÉÕê º›¤ô±tÝ2cŸ à>‹‹©·­Sõ=²¶:4¶}ÐÇΈngŽRw†< ¢uà쑈‘A…ÄJ‘;ö¾‘€Sheƒ=è^(ˆ„€©`gÔxu$ÚâbÊ6Åié6S-ÄEîÿYß’Ÿ4¤JûÒÙîéü¼aA?@áÿ{o¿Ì96ÞÙüoG_†üä^Þ¬^¿  eƒ,!ôÁó´ä½Wô´,X¢ëoº@" Ÿ¨Ê…HB7­T‚&JðZ°v¿ÏSA÷¯Y»Ëób ÛÝßêÃBÅ^¾GÔ©Zwzpƒ–û²ïU 0À6æ¨:MãpÕ°™x°G¢§ =]6Cf%îÌ¿Ù=¥1üwÿá*1$¿2Ök8Âú)Å8·“Qššê¨'c,¢ž«¨§Ê\gÎà†%ÿE³7¿¯C²(ÛŽ?¡¤Ôl ¸ÂWSγ°Ç»>ãèÜÿT}•Æ7û¦’W¯5þAП¥Y ï»Cú›§ÙUUÜÈ»•™ºSžÚ»d[¤Íd mºOeUwá͆ÒSblè?äÐøÑÐ/!¡ô]#CnCò[ëîK­÷41/L‹:´•$ÓšET¼Œ‹Ð §NÚ~ÆüåNº‘€yP‡¡Ü»s47¤ë8d~ëM{gÔˆúCÆ· óó!|'¨GÛ,c Ž¿êû]ä¾ NÂ¥-™ž:÷‘úøD’u„1'òáëç;¾Ñ²Ì?¨“§ïCué?`z‰ÖªÕé‘øÅšÞõKœî9µý_ÈÀQø”÷–%ȬĢoƒC¦”{5¯”åÈøs¥Y7cú;ê‘ £X.ðm4$8í1->X¦ÙÁïpÌeÜv¹ñŒ´n£Ù®i4fW5Âv€Úg‘4ÖÒAøfÛ¯ÄM3S¦òޤ>•@¿nQï[¢~àAÉ@µÒíÁ•Ž“Çã‹mÒBeã`TïI­s@+†îéÖ\2­kÍÆu«’ã S‚–‰^?ª¼Äùx0Lj–õ‡™ rÅ)þÊû&æ…·6”'(Jã‹#6V3èd ]ñë5–ðQk\É'ð&N¿ÿG½ãƒp.M¶`¸Iiˉ²Ö,éG¢¹è‹¢©­ûæˆM¡ ëJNþÃ+C¶–èõúDª§2­0çT÷-kžqþ¹ÉÞîË0–ž¸ßš^Œ‡o<þð¬Ý’„%S¥/×'Š•Ïàö©ï¼†½ì4ãà×òè}ú„) ˆ¡M? êàV#œ{ÙâWÉï$ˆ`iÂìSyh¸GMì£ãäó‘ 5¥GM†è¨Áì_š!YvÄ=UWãýxöõSxäYgé§@%ôõâñíª,hH×är¥ˆm@Ǿå 2kLÆ' ²ìMžAë¹p 0áYeý×ò{’pŽõ­ûS¶¶È’û ^Ã^4EþÑo£ž}Ì£,e„nOíRæb£­êµí‡ì° %Ý;ÜC!ÇÀ3ÎùFM]ÅÛ —¶d¾ˆú“l[üCEÍ(cMàM×V·À57-”L› .%ÔŠW¡º·•Öºþ`?dÿNl0¾>û13ÜD›ö@+µØ×ÍC& ›•Qk—>$8»«¦ Áq( €Tˆ]1ÂÓz÷Ë~Ëã¤à^·®Ê²´ÇKÜæd¨ìbz’ðx±øp“Y&¢{d·'(G%¤ú+A€0%îdØØáA“±šµñŽéO®ÌOÙ¬E²Õ–®ëEÒ>H7ï²VLÕ I,—jªs•Q<ý}±ÅÐfVhò·ˆÖ¤AX#©Ë]oÑ#„&Z~LÖ~%¡ý›ü2{Ñj¦.êTÛ¡û†¤.Ú;*þ'YÀ¿¯ˆõŒúÑPÄúìÁ<Þò¦î>·YýWDÀ¦ø&ÍÌ(î‰È_Ž“;oúoúµ¨)䬾p[³ÊjuñÇk °´ŠAû3ÇkÛQž³žlâe&s›É;ºÏ³Ù -ÚÊ ,·9Q›œñƒÞ[Íá§Xa‰l=é€Öe 7‘ä¿ ‘Å»/o+`î‡]ÅlöNnSN%SÁŠ{éf¨ˆ#Ü8Î-;€f1ƒž}ñ'SœJ¸`;5Yïã˦Ì6[•*ù…8u:ã””t.q­€f “ Pc‡bÆò®†B¼`ü÷vv|»$[뺓Þqp5®”3£n¦«ÿä”Né·Œv ìÏ%ûãÎS¡k)ÐP#¯Â<æÒ±#L½›1A @¡–ØbÀlÏÞTØ€ø$~¾’0ïÕE®*ö=(ño89V›fn~–@ Îô8eæˆ4ûukKÒ÷³L•‡Ô.Cì«ûrlŸ‘`®FOÀŽÙ¬h9Jµà¯Íºé3wbg ÑB>Q®[%b\ƒƒÜž¡-¿(j)}BŠßæUýT³ˆZe’%xÀ­¨^M-ÌlTg»KÌX“Õ¢Ê,ýÐæ¤äØÖ‰²~ó«`›ÔQP»-?ÕüÂÇaå­™x%CvìfKš¾ŒqªóèwÙ1?fhB· zJyø&ë\žV…^MÎé )lØðí  NÑÕ¦øä1–³FDœ$&‘Ó]?b‹¼X¤déõ/ñÊ=ÍNd¸½3Ñ/¹aù>˜{K%f$ÊUÓÓuB1àôE‹†­ïm>mÑú>ëÜŒ®çÚòÝ·L8(ÿ;º*ÅW.Æ9u)V°¡˜H9Í_‰?§ë\íôŽï¡c‚BËôƒ†`–ŒO<˿ۋ¢æG§ùÚ u6•¾åù¼3G˜xëÚìÑ3¯½ºéÐq½²²` w–ÛŒ(Po‡ ±_ßȇ»ÒÅgÀ¶k+ö“8TŸf}G§l²­üê'å8˜×½±Öl9+ÀUÄ]ÉÀà8_e@ +¾Ð£Wr·|œÛWÇòôêÒQ~À¦\'q—]Oy៶¸À"ÏEB>+®;VÂëu#"åçH~ÿKÃŽ…©Ä-Ü>¬®gæú¹ž˜¹\mÃP4Ô§·E¼ZQt{Ð0œR8¿ÃÓ”fÎrÏË{ÓáÔL¯³Ú­ÈŽZæÅ}Wç*<øŸdk\Œû@òXÐ t½ó›ßLT¯ZØZfTχ̿%ˆ=ž‘ê_侩BÕùÜÚÐ4©tYã÷0k€R8B‘–8WDMLVˆ¸t;î¿äÀ±î½ÆåzŽ2Mˆþ=;ï½?š=HìCa± ^´óQÞÊ;!´a¢Gkµ×4v?t#q% ŠVØ”j,‚,–¾†iT˜óe\¶à1D§Ýí‹ïÜóáwÔk¬Ò÷7 Û»Ó-´cˆÐð7wKÎJ™ú‰Ù[AÁ¿Yñ˜,Êö70cø¢³FÊg¨NÔ.²ÁT©õwm!#„ :q"Å!ß÷ôað ¸ÀïIÀ^Tçôe³ã2 ³æ²“N|]´†/Ã,½ëÀ•orŽ—HB·ªÕ(Èô0àâ=•‡ðšHÔ/T/£+· #®,Y%N­À`CÅA³÷ù?ç°¡~ZB½O”rÒ±(b{ˆw²„Q*U'ç²ðÐêk T¯8žÛÌxBGJÕV6ì–A„6o0¸¬¢`é¼z–Y}C½51až6¢RêÝ{_ze0À׌}Ks9B¯lïNµ<&xP#ûv&±R류ðOûÂÉÈöÊ©ËU ZQ9ºyÀй0Þ¿B~Z” åȪoïÌ3æIÒ‰LÃ%j½–ÔïPAŽ*ÍEé…mö°šÌ*ÊìÑ›°pÂ}dtÓ÷Ì·XÿuO¶Ó´R´á?‰*Ô€A­—ÜÏÄ Ó¸M·zÀ^–óE(,U–l)ÿRrk/N½¹'4É“™ ü«¦­CvÊ ¹Í¾ì*€5(·ckC²í†Ol'S™Úmã¯â cc…u¾Î9—Ê–Êo€äicBg¸ âÍ’Ï5kfšt9Ÿûìh Ôà¦iÙ{ù8·tÚƒ{󺞇)Ð@‘TÒvµ¯äÙ4k²Âa՛òC,©3S^{›/i¡ÏmÅ›%&å«òÃÄhd¿¦ŽÇVÿ¦`intÿXãIà¨[˜,Q>ãôž Òà`«òüÚdÇbXÑùëÂö*- /£UÖál¸SfÀQžƒÐݰçê‘vwYÜÿE¡W´dDnÊ-{tAŒÃïÉ ã)VÄxôVš-Av1Ę4×ä>/;Ô_?äí,ï|Uæm–&æù}ahÛ>à:ÞõÓ‚FÛùܪÆ»îeX=È2 'fR=bo¥„ò¢îd¿ðÙŒ€î ce¸b“bµ¯ >%z©^8d—…xjFyb‹‹wVÿÿzíVÿÿzíøáçǘd_øOÙú–äE óû¬/Š—ï|ÍÝp—ÀÏF=ã¤`·È´pŽŒvÏç:z‰yæ«Â©.eN%`àVN»Ãr PÉÖôI“@¶¾ÑïY™~TTã·ª†êÊG±>zëö‘÷#i r»GÜΑåfcÔœõºóg*8÷¿Ò+yÕ [Œ€d"­ä!f¥ì̾»§gùhüB6Õ—dÍ—´¡ÄcÔUŽtòï€ñ;1ÿ¿ò[ódnÿ*Š1éÝÚÊêi¬½„dãÇ %iéÖµSúƒÀ¹Y–.çMaâZÞ ]{ã$9=H ¿Z§£%ýGƒ¥‚²d5y¡‘?»šðÒj‘º¢†¾”ö½|1'íÇág+úJÓK‡YRP) Ñ=Y­&ß-‰ÎŽè¿Ÿ%Ù1Р·‘,oÖ°P/»X{Œª: 8KóçwïÖÈïS:ì8q,Óü}2wáÐðºä€ž´ k¼7¥bV¹•™4 ?¥>™%–ML»ýÒyÈî<u3±NÕ€$&©XR×ÙÒoO‰ëÒâÞÆlÀÿáÈEHà8&ª´fVÅ\hw+þŒH±‡­[sÊ^ÕDm "ß$LØÂý>t{¬¿ ož‡PHÂû9äU)„qˆ‰H÷Pßu#ë—¤VY3t)UÖ2öÞî0c˜UØ™2d¬Õ2~ÕWÔIKÚ õ!¿û 㬠 Ð$X[m«çT [®}vÅDP½Ö'£àåcãôÈSZØ–ds,Œ„²p‚/š2Û ­vŒ~æ=psܘžÚÉú¿?Òdgƒ¸10ófÏ¿à˜|ǹú×#pºµhµ… ¸»9 iøä§/Cbê·±ƒbì¾Ø DO§kYŠÌÚ]ù±“ãïDz},«èâæg9ˆ"Í\c¿@Gjæ …ÉyØÇ=0ACâš‹¢ÔøÂÞä¢üÈÔSëƒýuÃÿ®í†|FyönÆìétŒÉÈžp6€p]l£èçšÔ6ñ_¡ôé|—Ü<1“x€ïÉA$Å:A}™g.æ‚4”]0,|ÕTD£‰:ô ýùÒ,ñ!2g'@ï^U„¨ŒzXç± Uà°‰†Z]¨í} ØpˆÈºN¥ìk3ä3óUˆ$®XÇÐ,¹ÒHs°Ï…czîø…°ü+ Ö‰;ÃÞErÿu$La½Y{ŒF7<ÆO)¤å¥ëÐ’ùrX¯­BáDä‹T[²¦8 Bµwt‰9ÀHýNAõꇙRv@ëh;)Ÿ‚9S>[ÚŒ;8 a=®dÂòU‹SŽíÁ8áÇ€~žj©ÜÛ»ÞV„EÁÛ«½¶FA†ún@êÛ9Å…`#Ýkä´W0S€øi/€“Þ‚»ÅNBy_<Qì€GídHFˆ@*´+ɳ‡˜œLÅ@ÅÃ’è rvMM¹›^JKqˆå A8a ª£Æ—þ¥lbØê VCö²Íl7RujѶ®ë—K‡×^vúi‰ixÉMåÑ¡¶Zf¿"ÐÈÁɨÅà-øÈQÃáþd¼+&?zs?I ñIé©tD,n¯ «¡_=FÄéܺdë® ¹ÙÄPÚª•šùG‰p”iôÙC.y2ªX_õ@×x KµïÕà0õ­0ãžóåÃ/çŽ{‘ál”¥öÂ`qÑû:£Õ ƶnÔÆ—iàéÇØûã4 ŠfªP`X'ø€®÷ºÐI%†R‚!G¶‡&ìì‰SLì¤oŒ8Òcöæµ_è^™"µ1 ‰mÈrÎâLù‘õ-ð€ûÛÞ§Ñ *Ù* XÃç€Aó\ª4ä%Ê[5vc#%CÞõ~cAÐv*-o²!J;nŠÝz¦yÁ»FBëcÍ…áÌõzrKvU¢\Š¡V9öì8;/A9—ô^±÷äà¨×¸æ<ˆ$Ð%ªcÛ[ÉòZïa{Æ?iÜÝÕùx¶W¦öØ›Hƒ½¾U¼ŒDb1J]h›d({÷/› ÝG+’óBÀÌÒ8Ã.r­sqoÌä=Å„{阚ÍA1Ó ¢Šu*’LgÚrGü‰…._Ãò ð¿!˜fÊ…©LcéŸ×Oâ—G˜‚=³&²þé›Ü–êÍoóAqNWŽ”»¤}Zµ<øÌ]ëózÌç®b²óytE"Ù¸Ç#:ÔŸˆ(Fo©PòJMÍ–ê/a4#ùrÔž| 0(OÑà4§1iUcž×#Gþ\ú+¤€TòšÄ÷ A‡OŠýqÖ°gÔ!!ã_5+Þé Ô¿b•rËòÜ þ•ÎÅtö1>j£YGÔÏúÊŠjæð }f5¤_™§lÎŽæØ¿Îõ—4– §ž ô…ð'¢>Ñ‹ÐèÓ/ËCê9 GÞÁ9üŠQîPi¤i]…mÊ®Êÿ³UD£1Dµ9"¢’ÛÀe÷É€üÒF|H'¸æ““0ˆ9ıž}Æf"'æ€i¥€{˜t”ÈW5?3¡}£ÆññÛ\ÊJy˜3ª4†>[L’Áš|7Õú°ÛçWAfê•ü»#{lQM‹¢]œ+l"‚j‡ªÒ±)cw%kõØxQ 2T’ÎGïv츞 á+~:—†9¯ ~ͧ.ŸVÞÁT ’(„¥ˆ8.¢Ì?½ñ¢«šÁέƒðMDúxˆr&À/EFÃýùY]ÒW ZA¸ÙGjÁ’6@µEEF!Þh1½¨|‚z£,®#õXp-µ°·íÊßË{S¥`¼hROûòÈ_•ȃGJM•â ´‡¤dŸ©íµÐÞ&Á>é˜ ø6T²ùæ©Έ|wSMK2Hiu ö å͉ù]³ïÂ1Qí?¡*6}W]4|’½{ÙvÛ¾ŸJÎ| œµL€kD-ÌUØbµ¢’ß͆F/¢¬5-J Zö©78ÏxJ}K²PÉ8™|1“Åq‰[@}¢ÈïÈ‹$j4Ñ;3q³X%-öÚû»)l{9鴳ƈêŒ8ÃM¤Ö¢Çl}#ì[1I¹‹µ´6Ïð´@ɬ)y£*{Çs5`¡±¶šáÇBpƒäß³Ëd»€w@:M•@b^n4ÈŠ¥é0õF¯ý¨r›­£îÜ%N'÷1]vš îÃ_!²X•®xÚ¢I,~“à­̆ŸPtäBy½üè8°‘£7ý&®Š3ÌÆã¦Üøž/r[Éqxé¶ndy†£Ëý¥ÿ.~±ñKH(EF»w¬…§fÃè¾ð÷jñh¬\õàI3@N¾LëYgÁèyIê’úÊ*îäÝ%³$>}1ˆ¸@–qfP]‚ã¡ßCâqx2œàáThö tøÅxÕ¿íO&l\ã·v2¤ ×_q„"¡ +[ƒ³Eþj©½û¶×Œ}è–€£Fz+É5VW(ï__öö}×´ÎO(ÇÁþ-EaO¹ Uôž‰ž~ËM%$Úµ—"Âñ· tNÓ‹Zs@=ÔÏB3ج¿ù•+–Öé·² .çû]:ªªüu‡sSQÄNCvç7J8óà)K ýÙ|ÌÑ3ˆé×|¯´¿K%¤8Z ‘$l½'õŠEæºô æÀÌoÐ %Õ†<¨ßqv`¾ŒsBÎh²÷m¥!Už$=l8ò ’:(B …ð ›z¦ádÓ|ÎÔú)ù”1áá^Ü3X"øo°@‡êˆ‹ßwº¿ÐJ¡•špºÚ€Õc¨„ÿyô[^æÚoé ?·;D\¾òOŽïû/„†FògÇú‹áÁ©뀰S–7ér¤«NŽÇmÏ>U±Y¸Þ½¸†¯‹ùaöxIf ³½·í­êS¶ŠÑÑa{Bó0F`ãjûÿ5A[V3,ò)<õ ×%z9 %÷yù©FWžÖª±Îóö49ëCÃR£Cö¿A‚!’SŠÿÀÉ›.¬% ´J«p3ÄqΈNI\×€…€l-N4ŒÀ%¦ 롉wëKåVÙvÁ´£ ],UâÇŠ«m_vÿ¸˜5ìjÝÍd‚aܽ!´Ù•×±SÙ•ýYX‰Aˆà˜G.4ìÂû4cw†ZjÚ¬µ¾l÷îz¼y% cƒÎ#ºNWM^xžf‹zøe#žF\JmHéhPW)Jóž([”‡;´6)íG9¤¦(›lÜåäX' iÌ?‰F@-•Р¸º| Ê¤„öžì¢Ç¨¤Ø— \là—–¼ƒyÕV2Ïo†ÀØeÚ{ÅM=ùµ€¶¥4H«w,„Ùå-É1çNùžNïͼûÀ× &´"µ”½‚=¦¢y×”ö<XÀͱ„†×Zh{ã(P%“—ô:†Öê¶ÌNÌ#=)<ô®ð½rqرѱw‡Ôv0Ïßi­4%Ìò„Ü86ÅEo ã£Âî’B1Í=ÂB2í€ßÖ¢`0¡L«ü "óðßj—Žxi(æ=G@îó»¯_i4–y‰ÕÃ#r ž¥WÙÀì¾Gú©ùit )ar ^ÿZwm¥Û&¶Ù‰ï5â[ç…œ=d{ª°-.ÓHÁJ¯ÁõÜ®*ZÔU‚ì‚]ïEílÎ@shPÉJél[Î}°VoÃi”_½û°Ãku8í&8®CâKN!Š×ZgÑs!`øó€€¿ý ³ÜÜlĺÏ-GòÒɰz¸N¯²» ˆSYdµèdþ[Pjô'ð¥½ÅJa«+ħBl2çr¢QÅ®p´³WœÎ”oozÀœxëøOô靿SAJdC²OYRM&rÑìj}³éºÏbmÅCë¼ÈÊŠ[Ë–ÛÚ1㓳}^ù‹ `6ßWü‰Ï̇!ýº!0Ú|4‘QªØ¨DÍ…‘ChHË‘>ÜߥUÊœÚÑùsç“j(Üÿ€‰§»ÔBT‹ÌÝn_?0@Z#È~a ;ñêR$û%$ÒFël’A"94ËK—±Z.hF½)¸Õ°\Vív™hæ¾–y€oTY;a uä…°è9»"^ÇwImuˆ'¥A¥irÇ7í“€hAP­XÕݹéÚ1réçbD™SíH`õ,“Ú€Y ô,À«¦Õáã:T WÊ÷ß}üÒeÊÀFŸxîäà;º‰ ]í䎿ô<]Ÿ÷*u>ì *bÕ%±ød¾ZÅœ¿š¨½¢ .I¦k“%R¬ppêF:~I‚¦ÍÛ1V¬-fhµµßöùß« lŽ?Ç~ZÑ눳‰õGÞ^Ǻ.Áˆö€ÎõOO†X²Ž0ðTgÎTô˜ŠT1ùÆ]ʈ›±Ax5édO•z0æ“å´iH\àÃ~ß9sÌ׉€y‚ð8Ãj#1 îH(t˜Ž†a Íÿ‚Ç;Î\ç92%Ûºáãª6ò©HøN4ÊŒ†¬×\ŽÝUäüÛH"0Êrj|ê¥ ìÉLõ<´H°¬D³TËå³®¤>Ò·æ7o>%”)Ŷ«¤dã£ù?$©Œ¹<„#r^ŒF¼eìMÙ 9Dvú*0¦¶ÏÛkpYß@åÛnÒ?gw©ý::Qö𢌜§±|1XD=I”›Ž¾‘ôÛ QÍÅq—qO`ÚÃãve:ÕGaS…œì™ˆ%¶}•—™Óذ´Ñ#µ¾¬•/gºÖNêVs¥ÿQ¹›^á Ü‹¸³j¬»H —rg‹[ï‚*ר_pcw0ò:b˜dÀ­6Š)üy”L g§ð3þ¹HL¢v²Èà ž M4ÿl@.®Z½˜>ûá ®þ*ê5¿¸ˆºÕ¿½¹1q5ðFÉßÿcZ\G ›ï#Á5Þ¡Ò“y2û˜6“ñ(lPM­F—ˆþÐà¯à­ê°ˆŸí¨“ zi<™‰Üˆ4kÇLŒÚƯñ¯A/߀æyekkËe¬zÊ[çÑB7aTÁAŠñUG$2úÞ×ë5}ôL†—¯ndŒÛΓŹñ[ÅÙð :'¿;bœ< Ô=ÜŒ” ÙÔ’G¥ÇáV<¡íÿníÔ©Î<¦½°„/ ø<VwïÚ-x¦”:ë'íⵃ½‘W»*º»L97;ÄžooNÿ2t:‚kv–eHÝôó]øªA*ï/#zé¥é[I@ø«ÀŒñ¶X=J=òdØö‹O¤—gÒ¿e[2ï‰C5¯/÷X՘ᔽŠa¢Õ^pOoüMc¼G`ãŽkvïüSíT"Æðȵ=ðY?fo¿¨b¼éÌ{a½zW¶qo! ›H~r€&À‚— u1B)z¿5º5J°w«ÌêÂÿ µf.k¸}Ïvåh+À~׫Å&å©ËdOžë¤/-sIråîÒ܆ÉËè¯ab¯vÝ …åá°qéÜ̼ƒ¨Ç 1qæ©r¦QéšEí‘v>»zöjEÍiMÆé™ÚI·Ã„ÁöüÕì;ìß8|š¬¨BFØÝ2y*‰ÁÖ„lÝ"vZg.LÉ^üô®¯ö] BŠhÎöçaÇ7“ÿ_ÒÞFT+8Ø1b“ej_yL‰Nž&¥7 &E—âé-ŸeÚ+ÃAÙÑqg¶í¸¢5£eû‡÷F&>Ñ"çÖò€aèUÅ̰ÂIá?€–‰/ñvVžguœýp 5Œ¦§›æŠ×* ‡õMz´»ŽÎ3á~é-„IM¢ÐB§Ã­#ÅrYçÁÕºß0^³ÑB­8NÆêg5JONƒ GË»˜uŒÿnJ©ÂQ×ãþg êzË(.{¯ˆÜ–gŒË¸<@ã+ÑH/ì9 $gÍŸ }m½ÍMóæf¢„E2ê¼Ûþ8ÔnûëNDïÞ±]}ƒªå{µí'vZJw|Y±-‘Ò,§FH·)£"}¦óc.¤×q—ÀâJ@„]X(©Ôu#ÿWú®ú£GÞ´èý˜(З±)øsÚ”AÃ;€ç8áˆ9™PÔEJÀ;­7ä´õÑÆY[žÓ8có@÷u*σ$ñßý'ÛÍMÕÚ$wà4ú¥Ö”¦ïÉ[ت¹:é*%’ ß%›ïº%ÃÜÒš=—…­>¿Ö&"©ygïÓOmÖ%öàÜ3<"ÌÿAÕÃÚýtõ‚X >M†=Ù¹¢”Ľp¡LJÀJNÚ''.¶ÊX™ŒˆŽ9¦EÛ±$Z¨ž{¿@âë(¥ˆ @DñæåHÅ>üQż³FÓªèúJ t E·Šé­€EãJ¶%)¨©¼Oß¾èé+wÆðé¶o˜‰Ï]Éu‚„q/r%8-¹ðP/4ø‚׈ÍH ÂF8Š}C¡ñomßí.Éæü(öH˜:Kß¹¦^äfâ?©d"RtLK&w%BȬNy3&D†T‘ó É0ìW²<Ãæaî÷¤Ëx~P‡]©úÆyûý¶"{RáÉz2Š“ñ ÎÇtíΤm{âðYM6Ö®ª˜hÜ òh£\{(ã-]8†bž1)øÔáÊà÷ذâŽ[Àç±Áú:¥LÎJý4NÔ~„“ª$óSÑuéyWÓ‚›{YR¸ûjŠšQÒ×V*èzÜ}¯Òùw>è|·œÎt÷10ã "`“5 |îèêÏüÜ”B-×Ê•êí}Es>¶ßûóÔu(a·™ªã·­6y"KÉÕX³ˆ¨£ªÁý¼Ð#òËq—,Ûo:­§À&©E¡·Ùð-ÁVIjö@dQg‰‰û¡;Óµ_M%æÇXWšÇMó W4LT…üVÝFꨧ ¶ÅÚ P_Û?‘B)…ø;Sz`¤×Z(ºØF¢^ÔÛdÊ::R˜Y %V‡µèÊiI~-»Ì·÷ˆÃEÃtùþ[О`º<sj ~²g,w.{§,"KâËAÿyÁŠ ·À–šfú Ž+H„*¹µO=^ãÌÎBI†J ÓZ° ÝØå9†B6œš–‹k!bÝêãa`”d7i®ÿMã­R³_0eH#šqöÎÓC”ò¿‡8ÓªÀãóQK®€¶§»«Yïtà6Ú"âgJ¼!2ƒ—š^ WhiC3~Cݘ{Ÿ¹UûÎÙñƸª©õÌÅÑŽ¶­Z^”ºæø•8Ír§óPTõ­c6 ]Ö“Ÿ<4À‚mÇ×½Ú\Ùq¬£Kp©+°vD¡ZEïXu” ýŸEÑ¿x™0Óƒ§í‹å©¡¢øÝí:ú_^žÁGñtyÊûêVòØñ$¦,ËÙ)`ÿIB7^ãÏ—gµ˜£i‡=äTðf«` Ø©½W×d3IÎZ’Ù-´©°J)"xg‘¦î¼þêa‰½„²ÄM 3Ñ«/ûîÞP¿61Sï'Lr搜Uó…0*ÙwÊþ€+=ÄÉÊ#ÒW« ä8ùì=<‡ûÀD5à+ìx`$èƒt¾ã£„Zìƒì.[LÃŽ’{oÂØ‡C1IÃ…¥˜4$wý“n'¨¶±ñjÉ+ôuFC`Q?ëï *³ò÷ 9 £®Ú*‡2æMZø¡µ€Õ´ŸIØ\Än:²~›–´Ñ¢cOˉ³}»Šˆû?P6Gc÷µšC{ºÇØŒN&@gvÚ B¦ »bê@ö¡o3‹TBw4–»JŒ®¯~Ïó ƒ#C#˜ömpõâö0ÕC;N0s,}EËo&ÒÛABÊêw±|¤´®Ÿ)èVíîàõ±¬Ö—ˆ·Þ„n²CwõáäùÜq„½ ¦³„£ô8ú€¡óUœsUŸÖ[ºà{ LŽºO&'TÜõ|TJ?f8%ñƒ~^CïcÁÒ l}rÒ·kšßWõGŘ˜Ð~ºŽ‘VŽ7»§áD-òpT«0{â'úÁ‹•*B>SÛèÁ]@x•ÕëÀYæ|Ì;²<U0 µ[sÝ\tÁmÿ„þéÍ0Uö˦#˜¹âÊAó÷F¼Kè*æm¼ø“åøº·$jó·z}Ï{Ù¯ˆðAyaéÙ*¬™Ü+Òã›Ðiχ}Ãyî {UsâÜÿlé8ÆU¨Ì°R¼~U«(¸›¸ß$Ñ:õÝuñéÚÿL† ¼i† L®[l¯ÂRŒzšv_€V›×yšðsPM}_$NÝô^EÞ„»|~ƒ³’™ƒàªý„%%‚_üîpÂ;¬^©ûÂÁºy?ýŽ—ÀfhF°ªÀÿpÚÄ@=ßH'Íp]ˆ>84Ügõ͸¥°.E@Æýv˜²áøÀFÒÖ”s„Ï®ÿ<îá¶[úË%‚îdõuO¬rŸøOøcKém”Æ,@Õ iSyØñ M0€¡Çå|ɵàâY-·w~z€1äÑö^pù¸w}âæ…G;…7jü½õHñ!^©±]/ϵ: qJÄšŸúf¥)0;ñg+ŽZÚž>ÃðFi!gm'ÖO¯ûhÄŽ<‹÷o@àcµ xcæ>Í—˜¥$Ìò‚8tÈqÃqêÍ>6Š Îš‘ i嬤,Ewõ„ííŠñ©Ñ“1e¿êÙmíô½•dë“#\«ËÍ/ brkßç×^t·øÑ÷ÉxϤüKUïQS—á¨Ç)AüµP„n9'®ñæ¦C§ì ™C‡\#Šß ïÞx®EïìÓÊ=lPU:B2¨XÜÉG™ÜòQf¦hCÁ€þ:5Ù¢X&;×®}@ïr$|Ÿ¨ úúÝÙ^q<7† •ûÞæ§þÌí¨kÿûÒxºw6Ó~ïùš~ƒLÅFÐ%UÒù)^˜<š $É?ûñ 4„ˆ´Û¹Z˜óƒ~Ý7xB£ÞŸÁv¶$~…û©˜œp/”›€íö©H€:ß*Wð‘¶òÎnhk´ކ_¤_—-z¿Q¦©¡è+c…:g Ó«ØWççAìʼnJI)óW+;÷ #ã‡t9ž²k0gÅ+3Ï3³ÉÈcGªËD—ÃÜ<ˆ!NXûÇËáh¿tN«È_áИ{P¢DÍj½5 2$îY™Ìm¾èß•¤'ÍÉk`aŸ„ð&wvŽwØ)F–´Æ±@o%‹è&›á· lù°Y\kZïl-Уl\ †âà<¸S#àêS1=èºB‘×óU†SwÇ´õ ¨šÎöÒ' g‹í€g~ýÒn„pÚ:¿r`þNcn++YØlÉtüÊØöq {ýüǦÈNâH}L¾™®ÂC?LÄ\° Éfd¢.ÖÕ€\ˆàÕVÈO"®*=Ö¾ûŽê¢kšú-åÙ¤Õfk Z–µ®NÈ$¶+fö$îæ¯ Íà118L]^Õ(]M|õ³5I5Ú™›ãâáµ ²·¨úëÅ0Y›^EÃZ~oçX©NµFÝѳÔ|Uȃ.$Pá[Ý~”<Ú gœb%zë‰Æ@ƒœnÒIã(&Q½„£“ó£ôó¸lèÍïsÃ7È®rV‘6LíÐÊØ­”›Ù~·1eΤ/¢Y`©èD ¤×ÅO3ÍNî}ú}f„ ÷fƒq°˜ÿ]$(÷Û_voOy¹nïL(téÂŽÌZ€+I…U‹Ò/à +e–=ûfÁâ-Úø;¥‚ÞDÐ}öäÚôSÑ7AD&¹HËoaei¨ž-¦ÔzGÃò/Ý”Á¨°ÖáÑü„"úûõÅ*-jÀ1‚cÝ:VlùÙ–­‚ñ 2Ò 3`XŽŸ“WËÚUáy´Îø¬æ"ØAŽ˜í+’V`?e´2Nì7F,­ÕÆ¿›Æ*»ùÄô…ó}¶fý¡´"‡¾Ú¿öê­õTyúµŸõnï}½/_oAÏÕÕ±3êÐïáÔ?í¦ï¶”®ÿ;~Ý=ý´¾/“}ß'Eõõn×íÝ?ϱÿvOŸYþÞ‰@òÒ‡ ´™;­Mƒ«—»œ¬ƒ¹‚Á~ÕßWÉÕêµä¾åL × 9ÿn»ÝÙÖ­©fµð ,Œsø§=u³ïÇd¢X™êdDmf …°ž$ÅÜGç­0°þs ]Þõ òàzfÂ`£+¾ ºeX·Ï3XË Ë•ÄQÈ.áDyÿ)@®Fè§bFÞ% ŠF„Ÿô´)˜7ïÆIF6¦†{6÷…Ø*žöɨ`BP“9ìš©$«Ò‚Èå[StŸaÛ÷ »‚J”ƺ;¬¨*jÆXŠ»uA>­0…u«6 ´‚Å*‰=¯,€µ,_x02·¨{N|\¾ð×ÄEÉÿ„~fè‹Ú?OîãgMíxªäŽÚC‰ÕºT:5OΜå3W‹ÜÎ2ÇsŒ’@ÛŸ ‘Ì‚î?z¤Í¼L:#Qû'~ŽÆ®V\Ä!­o¾M~Bþ-§1ÕÇðFgÆH°Ú0ZÛƒ79 û£¶íð÷ëDzŽñÆÎ ±ã÷†ÎMòñ{œEþðëP :z„áU{ÄŒ^{>| ˜‚ÁDùç¢Q‚=¦1)øŒ4Sx„‡¹ToûÞù è²SÚ°²q»ûŽí°‘ðÔ—OË ]íÆt «“Rj,/>˜æ«’±Ê6›1ÍJîô¸¢ß:=ÔþÚ[j–?è§šxŸèR!¼ ]ìQ&2AÄÿYú'òò4¹[?„&x¬DyL‹få* ×;‹a˜•Ô|2[¤Iˤ~ûË×ÀôåKC>á£ßÉÞ¬àà•)Ãkm5IpÒRà RÚ£Lìa޽YûVçV›&ÊbBæ,‘þ{ -CU«»ƒb8 7‡È*½zÉvÿ]¯4¸eÅ/G/¤FGbÚ‚ÀyýoBpƒ¸þ>”*yÑÂè5ºMTǼVSIÿ/iœ•ÂaΫ>·MÝ—…YfEœ´·ÇˆR%bé©l£"«/M¤Qͬí|XÁÜ8H*Z˧æ™Rl!êSãŒÉœZ³w/ÐikxZº5{Jì’KƒJœixº\n:pÊãàHŒÈüjyÊŽì.Ö¿ÿj–ãVN²7º’h‘Ú_bÓÊ¡Èò½ÌÒì¶á Îr^àkîÊtéëWt…ãa&JÆÓ »÷X5_ÜÊw|ÒÛ[}3‘Aò Ý£YçžÔ0EÆåA܉®gƒvÖxrýb®%Æ~êxY¦‘kߺj&í4îÙˆýÂá1÷e‹%ͯoí¸z{üiCrÆ;Éïöuõ÷JàÆ/ÞƒQQ(> ³>6Š:œ‡+Pq%éþoéò *«  œÎùï0jãh.ðKê {äè±×X¶†éæ¼’ÍF]¨g#³²rRpé¯0ÌWCAEÉéqÇHù‰ÞAè Ÿ ‡6ˆþò»¶úAô–ËnýGòtèÔ óýŒzÛIçÌ•l™WXj^k㤧5YŠ>.}œ.œTþxÑ m¨P“ÿ-¿©uŠŸCŽDRØâ³îP‹u!bOsc§z‹rRí Iþ!ë ð=2e4“,‡kJ…ºŸÐ›|?T/ôÖ(Ÿ Ûë¸Ö @²Â` ì`<{?9¥BI "WþòAgcçþ{­'/gPcv²XÎÃ{ÉäÜ•á=´§ƒ“{Ù…Œù)ˆ k‹üë sÉ=Ѝ¢§"÷Z:Џ!LØGÐU‡Ð8…°|;ÌÚpzÓPäH'óá¡4oZ è1v@Ç—¹‘„4³)…Á=,Ì *BTðMBl˜Ì»’´;2!*0$cX‡]„Y{äìÏ[®C櫽÷6£ÏŸÒŽ6–Ô!ÎÙV”[Kl×k#ºöÏŠŒ¤“Ðf‰õ-&ùQ °Ž9o&%•íó~UH[~-ƒmôo5Â#ÃÆR$“‘ °&ðüoM³îØ@…à2VˆL Š õ=czÚ꯮&ç™™rÑÞèÓ3¾†ZÂ6­“rPä»´ºìÖÿ'# —ÝXM-ÎVãÏ=Ð_6ÅÜë”|áçNEAŒq x˜E•ÀÜ”=¯Õm.†dÀd“ÔûJ%‡ÖÅûL@Ñçtš ¾ŠÃµ¼Ç1q3ü]ÄŒzê < ãë¯QÜ?òKëÓ?‰Dv$»¸ñ18æ Té娔ɯ ÜB¸Œ8š°Ô‚ŽËóêkóõÈ® :ùà?ˆÜåM9'¹‰iÑô÷ù„S'A{L¬õ¹ÿ`.ëMö TŒ„ø&úûÞ QØoÚN¯•ês»b6Õ†iÃW6›ÉÀãà ®0[Í7s«Ì_{mâ½}_KÝ)” N!ã2S\lÚV¨çþÄÿ*O(~Ô{ѧïhÌRUÑiݾ_]~énñÝ/ÏàÓ©ˆõ‰Ï@ƒnƒ‹¦NÛ—êÃÀôíÑ¿¸BgŠõTÎOsd“yð¨n‚¼-•î8-w©3F°%ÑÉtoËIio³ âvÁõ«Ÿ\ö/!GoV·Uù”~Þ?‚ó$L&‘Ìk7AkhþG¢‘)Q4z÷&ШÿìÔäý\ÍêçF)ŽzâÚ€ÎóÜêæ ÕHZS íw§|íeÉvOÖtêzBšÉ\ùã혯ò\€fºMH–öBOÚoS“å_ŠÉ4} ȧK,LW­d¢~•kÊ0“k¶ðgÉ:DàÕë_¿DŒf@¥è¹´Mך’:Jª% ®áŸ®@~|fkm±*°ÛuŽíèÙ e¢VÄ™q¯&ècùhÖ„ŒùTP(ðü€?F¬Ð´ÛŠ»¤é1 YC}.æGwÙ߬¡»¤TOâ‡Äý´qvàpiBømhQy(ðøƒ}nÝp¶Â7ªXqÌË ì'÷„nêâ­b7ÍÀ*Oko>¾CÑŽLËI¬XŽÏ*}Ô8ïÆk‚æ‚:§7 œñb­¾rF_P4Ì»ôivˆ˜· ]š?å hèÇJvË&Ï…t=!+îG¾¤Úí'xàñDãî“Ѱ²¹ è¬mÈêŠÇs7Ooó±jƒ.pV6¿™ª>§ÙÀôå+é/ßð;+UrÉEÑò!ïQd|f1ZèÌ“»ØÒ„ñ˜§1®š©ò|Cx`¨@M€‹Ùï‹IÇ!ýrŸ"Ò¹¸TÀ8PµŽ±àÙs÷[L( ݽ»àˆ>f`wæmôy€!:µéxÂþÀ´ÇZF¹¯¶;œ9ò|Ðo‹õä‚‘qKP„öЃ÷HF¸«æôäëëŽÝÀð†s†'ýKÛ ±Þ÷ åM@û×PZ­É—ãÿ _øD샟 ;«Š¦’'ªI§-^Ô{ù‰±ÿgrŠæ=ÐÆ¤œàÃKôÑTÍŒ$}K•G‹½u¸ä‰¼ž¯-ñ˜P»ë9f/íj;ÊêNRHàN~"ãÜQ­‰ól6eÙ@é¥-HDÑõdŠWO$óptyÊÅÄ"'ªí lDêSÕôfȃNcEG8ûjQ({!%M'89 ·FçË=Ưo ¤9¯Á[‘¤m•Ý©–iJÅx8r㸠ô=<ùÛËHÒÞ5 ™_ËJ9ÿÅ–ØǃÍLˆ:©QúPÔF/f>û—ñ‡ÈìËZž; õ×Üþò;jâsîÏ`yiv©ókËSpÒÑév"¬;±Õÿ\F…òØ‹HáäÙYLj}qmÌA.˜ â B'ö3e1š,T‹wóǯ%Ú™ƒ¸”Ín’m­7¾ „øt3lj×ú]bÇc±3JoÛ]@}óR¼”ÑvGþE6*†^ ñå[#ížze/(©ödØ·L%,×ó˜¸ü§£D?Zñ­ãô:)9ú¬@WD4LäÎÐ[5`;:‹·5–W="YÌÄSò‹›ï}3¶úï×mJDP&é»ê4Å"+[Jmö¥©z®vÇZ)4LO“ÅÅùã­Š °9[Á‰Õ<|<Æð ½ëRÐl©¼Q¦æIUm­×=ø¯é®LÁod… ÆïS½–ï^‰=‡D³&¶’ÕúسطÊó4û«7£:E…ÅBi0'.õ 0d’‘ â<$7—3ìd\ʿȢ‰¿Ÿ’—œ&'™z,Û‡‰1 ¾<ð³ËkA*Ò¿|ÿl;sg©/™¬ƒ{ß~ ëj;>ôcÿb ,#¾ºã-vꪃ6ú™¯+ž68j-ƒ-±JÆ„2Çå€_°ª‰1ù¿w¹Þ6ùLÉ1ܵ 0–$Â-7LJ|éÌžÁkP ¢—0’ËØ{•Ñþ²’Eµ“¼ £Éf€¹[¨?d2E¤Í9€_éT‚„ïsɹÕ:T¥*Þ {?É^Õ0·ˆÀbŽToÆzŒDã¿‹ócnÊGUWu¿_*Ôv75èëúÒÛÙÜ凧Á<ˆ)b'»-¯m©¶&Ü‹¬™;ä08\,ß–ôñKæ@Ñ]ø¿ký¿;ë¬ßQmâ¿q)äO”CVÉ;6ï¯qªw›Qž¡ÀŽý¸ ü4ÐA‡õ“)‹Ç÷Gk -K$J‹«4U±Œ:•qrôd\—KÐËà{fø¸Ù8÷ö·¢á 3>îUÍ ˆNj•ÛÇToÕCXv˜ \6“ä!SÖ;J$¼Ì#ËÙ©£sï|¡í;ÿÕ>l­-ÎdQuѶ¾ FnðþpÃÕÖ½"%ê‚M¤fÓ¡Üå…Ô +<lÑ”Þ4Öú?Î鉇m¸ ò“ª'Í£êÓA?h gÁYDSórM›0;²‹~àr?íGÉòí:€4{à˜u÷‰¤§áK‚pØÿO`â½ÂDzNqœ¹“y’ÝßOJAâHq`Ī Â-`~üO´:qŽÝu—)(K©êSÁnØ-Lu«¥7t1öz¶—š!MÆ1ôîPýh{K4¤x,SLƒ+îÁBR'VâGµˆ™E|"I‡†o¦e[/0j‚t8‡xꀓÏTѤµêöX4öZíB}³QɈ]ôÆ„pû¸ù5Àsåî6êtµµ9Aže·OÈí¸Öoçé¤þaȶ†fª»ZSв?)f6ûØD¡VìP¢(:‹€#f9q¢?Vÿ¦`imohä'’kSdÒÀýònÏT‡‡—=•³ «Ý€ýà·®blCQž&¦#÷ù^J'g´g ìýf>óÔ}’5ßV6å°…®…?R¦É… ¢EbWÛ¡ ÄW¶õ4eÃW0áb+#ù ÃýWP“m¤ÐÓñÊdkˆíÇÎ —¹j¦ãŒÄϘZ¦TîáÍ~À¥ñ…h“ÄÏ’ÑÿnÚq ØOžXEŸèõs¤\R‚26œ) *£ ) ¦P—2dVÿÿzíVÿÿzíøƒ tK¤+@Ö×/ë -ÃðÝe+Hd»°NBdL››Æv¡ ô#ðS4,©U†Uu¯­m±¸_ÉáKË™˜3V‡£>KÐåMõ„òô±ÅÝ'ξkþ§÷…œC°KÍàS¾ Êt“ý­©{|ñ¾1³‚H>Ó»ÑóS[F´·KŸ%Þiï¥$aϯÁPØØÀô4›QY9ªÍÀ7 Ÿ·Ì¿ðïñSdàÁluÆ3 МV{¤Î®è˜á̯Ç‚˜U@±ž]–ðbÁq”íÒE*+z’>dQw¾sþ›·+…Lˤ})?Û—‘í+}µªÏÞ§²bÖZìGPÑ(vÎtMq©YT—µ¹Fðfªî3Ü+ ZüºÂê‚5¿pFFXy›²‡˜ý‰Ðèí‹"h/ßox=ÿMÓR*ÓÚOiYk7 žÔ„ÖtãBdU ¬U5£¼œð+L;Ì·¾M GA#úšwÕ‚Qá)>«yÌ·DôRµ‰2ýLgÝV>Ö­¨0Ó/EÍ¡6ŽOùÍ®¨ªI‘æøÏ% Â%â_Ûuf ¯–Å«sXq„ ;&56¦dyûÌ«^ ß}O9 ÷%†‡KZh¨È0/¼£ïÚ2–Š:{yäÀª¡Uo<ýŸ”?Ìz º›µÇh]ϸDR`¾y¼d)Œò_|¿ÂÏ[K/?í~›G “:-‚‹Œx ÷ÄHv–’á>¡1^ž”¢‚'LxÈ!ø¨M1zÎy•]¬€ÁP¿ÓuNZC¢›Ã•¤Yfs½ï èצ±ôEȾ?é"”Á†xîãÜÔ[ žE=“1‘%âÜÜl_Ú¾see‡–Ó·â¿èGܯò‹oc¦J¼‡œq>¦åScUÚ¨XîÝPM­UrJ€É ¡Ø?¼Š=ª6ƒ‚Ç¿/dïqV,å¶'„«ÐÂN Í¢Í;_“K¹>ûQ0²Ú??ÖÔe@¿m€‡¶;_=Ë(æ±Bþ|a 5´¥k¦œûo)ÆOá> 5¼þåø×ñ=ætoñû ‚Y×Î 2Ý<0„1÷¿ÍÁywîÅ·/õU¥•%‰îd·¦üés Û±„™nØd®&¿¹Õ®½=s™ãç½t@oŠ¿Ópð (Œâ%Tïô¸tÊT§Ñ'ç_È`Ãë¸LU9žÌ¬]±ÛÇ‹‘Ëe©ø &ŽË’ä;{b'K?@ߪ¼päT¨ €®ƒ/}LAaѰí 1Õ“IóÐâÆµ¿´G&v8#|t>•²A|‰´Z¸Ø1*(VÞœì©ôB}­K! ëVýÜ Ð¡Šr [‡)-ð1°ÜW+qGX(ÎG ÝF¬imÝ™|y:ÿI0'¿•Ñ?µ‡Žf92X$87V+KZì\Ÿ¨ð±.€S<«Cµ-䞀¬U„<½™„ÙaX[îC—Y%’c°Áj–¿Cymtïi|YI¹ä¹RÈÈ0]CÔÈ6²“ 3=‹–~¨· ú¬=qj.¬×¯ÊþÃBa!EçϺ×6TQù§Ãã©ú²?—ü­‡,g4Û3¶ºËžNÛRQŽRM\jž[u‡Éœ•ž?(ô¨UH„|¸‰­€g|rzûWï§sùeý¹»ËY„2øÛ~½ƒf¯u{9¡È0=Ù-YR§f`e`ÿC>þÄ}‘~„ŠŸêw©áã­÷Cã׊-®ð³õ0~í2ë¹Tsgº0³èÖ„Cžy›Zû4»2TæÓ –jõpLGÍ ûñÆbS02p"ý¡}s‚NG^–Y‚NÖ¶æqyƒk&nïlCÑýb„¨à;h7s5îmŽ<ž1øxLS¤±Ôë»”-3ÇÒ_ð´@É«DÛñëa#Âã¸p —2feƒý´€;݇’\\ö/°©?RÊnqYA_ÅQþx—8ˆä7ð¡å ±™¹Øé²R—é)f;ݬ.J6ð¨.—ùÛ_!·dÜ›î~ÁT3ÿj½×ÅÞ¢x=Ș»ÙȃŒ:|)÷µË¢ÞØM]SBÓÁšÌ˜&7aèa ôÖO^{éL*7ûG·£‚oW'bs-î>´Iž¾PJÊ8é,ç°ªÿJ»O ›Á%ýs9rƒX‚÷«{ïÀ+0 ‘ü#èÒáñ‚ PQöUÀ+¹Y…å‚K …»°³å“1󴲯&ñ.:n™ÌÕNÞÆ«˜ŒSš¿Wá±ÛYžÈ…Åbÿrˆˆo­Ï¡h¬/USÁÁ`É 8GC«ÄåÐ,;ÂÝùY¹?›Ihål6äÛнAPø3ÎÎ{«Ý0±È êƒWæ6:†{Ø£·áïW$ïßÿk<Bjèå¡Ý"°ªIÝãÑùwŽFÞÜŸÎØGÓÊ¡§ÃmQuPPkïU‰¤¹J«„Ä™Îw•Î#Õ«f],x•X‰9-œ-?lLP÷ÁËÖÈ02ëOu3ÏÄ OÊSÍñ}AöÕ+ô¤Ž vuŽfI£m#ÐkPØE3ðKî‘§[Q< Ší6ì4yœþ76s¸ÎB}¿kcɶziŒáf!i昺٠l¤šmû—‰‰šo„kðKË24h9ÒÊxžÏ=ég^gt]à ´7oßœ#@±Pëç®n?h^©íÙCOy®ÔÇÖ}ib´ÐÙ¥UÜŒ!JÃò³(•éÅ‘ ]ÕõŸR †ÀŒ 1}uÊÓ±U™—J—½²=çÒ£s¹ÖËp`ɀ丽aCƒn)Aç“ÞŒ)¥ÁÕ7€5ºêü‰Ç\¥Ùƒá.ÄÛ¢ báA–ª|éöƒr©UÓÇÑg­šyœ3ìóãŽêcž"ª­:Çñ?çd-‹ë-¢!ñÖ„D4Wí,r´Ë@1‚Þ¨Ò¾•çqQ‰Yðª³'3LƒÐqÜâbª~svԤزñ’ΉAðFÑæ-b/[GžÃ·Ãe"(¸® \RÅŒÔÝK]ÈÍëq9HUBÑi.æÁÉ` òLÞŒŸGR!+Ò)ù“x¦‘a¯Ü™UÐä’‘ Yº¼¡/v Y–Y0ò×§ç°Œø:|yß”{|” ‹Ìm´b>¨<÷-þ,Úõ³'o~ÿÚ8"Y~ÞÏP‰ãW•LïÃÌ—djX/¡côs\9îºXȆ%. æ3Ô7&SÁBœy©;I¼ÉèÇ|nxòžÿJ˜ŠÕh¬)ãÝ|F²Nvqfï+aià¿móôM‰_Ô‹eµ°“ó‡ÂZ™WÐ WRôóèJ;÷æB×ú9Ip瀿¶ë‹ÊL9ëóÆHYyÄiBŸ¥»?æ9ÉÓ®Ziú·M‰OýzxÿPtg[¢†^Ý€ôý04µ|”0ôO\ó.N›ZjɢɊf­­}™LŽrW_‰ãAèCarj꺰äìÜSììšïz¡”É9®¸rRü±ï\#2°+Òû«[5d™6ëŸ=hâ, ÞRÆ[ìé#xý®ƒWoJ‹aÅRó˜•QxŠV@cJl ½åjüÙó‚£á?ÈÏ*ý¯Ÿa%œ… ,ëJ$ãõþ}t"?H¡qÆø:N7Ir½2ò@µ$#—Vÿ[oNÔ#$‚™)Ç\"–à\ÿ}Ö™º(fkhl}/L-œi¸Ýþ´ÏÞ¢©¦Ò6Ο('q£§éÿ8&S+m„wñ.ïž¹2NƒDΦ\KV°qøÞ?; ápÓ¯ŠÛijuOùroJ˜,òôæˆ,§ç™’ºoÿø‘Üé2Ñ2àM:ÒÊ8v9:Ó+¬H ¼¯wÀÝʸÿÿIŒÆ*¨qïøo9'aF‹÷¬ÁRË]+ˆ¢G ÊУàr¬ÒÝÈf'–éO³˜|:dô |W—äc½ô‡Ó²1>ñÂüs*z”$ñnëJ5àOú­†Ïn9»Ë8~¨õ-9í#ƃùºgò¶R}!¯g®ªZß, àò¨¶%ãüwiÖ‹Ø*HV‹Sû8Ð9 AxÇß]FÓs“§Øñ×°ÖE„t]ñ$gÅÅßPÕj¦7PdbÜ‚fhø¹ÕÈw3V]D²%3ÿ„?géÖu@1ºQM‡¨Ý$Û V€Ë NÞ$Ë{÷íé`òƒ o@<Ä\–_IÔŠ~ HîÖc{jáÔ_ò°ž®F×¾¾Ô·H”ËÑ6V@1wܤG -Qœ9{YE|H)ˆJ ŸÈÒ~˜ˆ¯„ø)!;AÁçPLÈB¡ þ_†¯k´¨8PÑo]f<ºQ<8ÁNÔÊÎ ¢°ÄôÄc·CÑjcl*ˆ#be™ ØMÊxÀ`óæqH,ÝÁÍ24Žtìê[MVüÊ]L„*ï?Že¶²Y¯soÍËÍÆDGFȬ®_Çì‹fD%Ø}ô)ñ“'—;)¡ (Œ!.‡S;† Á81sJžûhýŸô<]Ÿ÷*È•šŒ¶Ÿt² Ü¢£gؘ˜¸¿ ÕÇ/ºˆ×Ë-ôI:S$i­“d³¨P2hÑ+æ_«,žë ÂDîQTV†Demõo΢š©¼J‘Þ+, \.ñ‰«ëHŽé¬¸WˆÅñï€Ó Îi5¥âA¶öD¾ŽÕ{ër_&‚qþQ=‰—àÔ!m=ÔÚ¥ì18³QÖ\ê–*–+òbD“(ɸY0ÛŠ…ÍW•þwî•QPÉpÑ Ü>Ž •´Q¦Ú‹·÷è‰ørm<(ð“ÎÚUºùú]׫ðtA¢DÄþ½K÷µªIHÍR}eÞ„;¨=õØ ¸]•†÷V/ÜöJ®„š'M=£—‚XòÃ_–Zô ¿ªõpy®£éJA]nÕ^6KíL$ÀiY2€ßCÁ œ¶Â±VÍ`8.4xœl(¶WàN€Ë—¸ Ù€KÏСҎÊlBÍ“&˩ʤ6>Œ¶›èªýíMÓ²†7Eökz¦¥vc+pã{Þl~µ úœÈØGŸ¢Ó 6ø5ööz/h#ž¡ ©®0ÓþŠ ä~Cm±"ßëü5›•èDJ¼×oæno_°b[g(]û–ÑfÜ9†ô—Û¢€[£¨AYšÌòì¢[jsp•^7bI$.‡ØQ £{=D¨çQåþ¥ØÁóo Ä”ª·ÂÑBù&—Äè®41Q_2ð¡†AÄÏvT¥©Y0}àØQ;ê‡'ýÐ#ƒ ™É“ÝûÒ 7Lœ–U¶¿ƒ¢$ûßÚvk¥Î ñp `fÙÛ÷XسÌxi©²—9t³*˜+B'êã˜Ü‘œ M-X™õrò€êB98¡…~ß:ôDïŸa÷Ý;}4Š·´Î÷X՘ᔽŠa¢Õ^RM†{ï:ý¼ÚÆ…¯À1]†×%ó)kÒ} èÈãßpõ8ì­4§†wY< `B¦ü—›wrðŠÊ¾¹å›|r¾Ç7êÉÑ—Ü.eÑ]J¯ôìyTÁæƒÝL“?M±™!ãö™ãsÝ„½nut/¸ÛšPŽ?ùõñߢÅ3”Š6ï õ\·FÈ…Eå¥i Ðô1R1„tU:€š„­Iº‰}Ÿús…ƒîp½Y"ni\^çNFutÀ$å¬Ò@ùcï ³XÕ‚gõ“6 ÉlÈ:Úf^^茯‘ÅAË,•ðÄøÉžmÇ6|Ƀœ´ŸT¸°-EÀ{PÒœ<À%þøÚ;ÂÙÈùØj±,°˜¤‰n9Ól¢ýc!B=\á2ßó€ƒ×ep¤ÉevTÚ(PÕñ±%=C‘·Ëüã0Úùyø$—ÅF¢™ÖZó½> ø^)Pªdõlc¯õjRÌ|xïŒð‘<5þ«8,Quã¦_~}8NAÞ´èý˜Ÿ©¼€"ÛÙFd¶Ë9VCóš9]‰(Î̯¼EšÇã¿øP<è®áMåškÑåôØ6€lhFÌI‹;RSV’©º¹Ë÷Ü‚@íÒ„÷ò£m(ë×úß»¾ÕC%ó±÷2Šl™;ò?ÖßhB5˜ÇÍÅEÛ¥“½:äÂ{Ǿ%GÌf;cœgØè4î[ 0æQM¬54¯‚Š€YU°‡îœEf #Z¨Zu>ôÌÄÁØS׿Â@‰ÙЋ_ RuNÉÑcƒw‰ (yèÄþm£•[Üv }Ü9x9‰šÖ6Õùí§`X >i3¦¼Â"B¬D¿J… Qk_<¬wÒª~ösIËgÜ1gŸû皟éns °“~Ô™qN!Ù¿·ï»w2Q@TàìVTK=J¶Äs0ßk%#6»Ój1’#(65ùœË1±±QÖ”=qö9þ8gÄí «»2vv1æ¤ëV9µ®ˆÝ2iý77“´ ¨ºU¾Ò鋽£ü4ï¥CaÕ~S >pÈ•vdõÕ‰µò…'‰´Ý„Z¸ Ü 6ÑâkËd)<²—­*ˆQ?\‘ä颰’péÎôO?õ¶˜Êûóf¹¤’ºNxº)_¤;B‡•oåCäZèW‚ëk2[eñ V’2ð+ÂÍÅ=ö2Ë‚‰>–JTyê’œg½Xœ¾5ÙRøªþ;J¥æ‘'ÕQ yëª%]³3mšÊ¥‚¡’ŸðÁøy3™ï¹\~$ÚîcT­Ñ5]͢ —Ój`ÞÙWôuýqãm*ü#þÏ%i+ŸsšbGffÛ©¬à’å·Àü›“¿ÞsÎá!XÝPðaì¯Â½…I·n=;÷/—É‘D*¸ H+uYãÁæ'WÇñÁqQo­#_ D['<߀–Ih–ôª4âbÛ>ÿX¶+Pˆ“:9žhµþQ­ÀÈï¯DÑWå/Ãñ?¥µt¥Å–¬§}S›cíÕå ú¾^u¦ª»8Ÿ¦7@rûJ{6öð™_l‰Íäâ j¸M¢;nÆÈ4ëÇy17ÑJ íKغìEÝY®*Èɉ/‹óE¸¯ZÁŸUËЭ"ëº_"¼œ2ŒÆ2–èGRÞ9–£w=ŽlŽYGqæ¯%ñ÷Z¿ó9?å7H=ôëŠP~ùÛJ #)€vMë-è* ƒœŒxì”IƒAe—‰ß¼ži„¯æ†Â•ýýª¸Ú¡>á©hÛzH¹_ÜŽV£™ªMG4Sâ¿ {Ç÷öŸ‰°?ïÓŽù¿Ø™K›?™ý®›Û–glK';ñ}^H;Ø+u-äåý9~¸ÛšÁKMšº“óտٌəm0¢'9\Q¢mÎæ§™ 3hkËê2Ÿ&~gÜo\BÒ߬½@>†r*;Íßur®‘àîܲ²îؤ ‘ññ2p*¡þ9ÝH ¡tZ»Žû’(ܺ‚œKæDW–• &æ%yãNp\DËœ Ï/)ˆ˜>&éÿiw»zx¨m¥Çd°¥U]¤RTy«^Ëpn ³v‚e]¶më†gtIRÁ>§¡Ð˜q…ÙÔî_ªXòJS?»¿U\:Ú÷X×”­ûBøa™,ÌõWªS䇂ðpOp™T|cí%Ç•IúËëÂ}ê5®ÃüïG gˆ¹m…í9X˺']¨ïdt’–Ž|1˜»v™Ñ£a{øSö=Ï]£{HþprÅÔiVE­8xèo(ÔàM^䮆«”P½ ^\³œKÔºç"sMGÝ«\| ïMPŽ’Jm¿Øpb€…›£}Œƒ‡ýÈv\Œ·õµ¦¹±h-– u”’°‰«<D]ŸÕ¢þ®Õ”jå·ÉÂú`P€Ažc`C¾Zla{}³³ÂTOˆðAyaéÙ'-N zà3÷‰-Vžº»U¸ŠäÎ*f-÷vt¯ÐÑO©¶ÿ¤WÆSA¤«èX 5¡åð:€Œ–õD ˆâÖbê}¿eüU2fÒ]¯‘•µ„©îLUKáŸ+/Å£ö›ò&+‘gap®pHÆùH.ÇÐnc™2QqÙJu&ØK£Kw{ñné_&%G7 L¿¬›Qž1ÖÈYâÇgÓyÙõ\ª=Åå£ÿ(‚ ˆþ´7FQÑ­Ï[`øµÆb8ƒX\Ò ºiSa’|ˆÃ¼ï0ÓT¢³\s ˜ÈšS;Ñå艑Äyð§žVoïß½?œxR[Ï“6$?z‹78Úé£ßÈ…Å5Ýñ#ËÓ<õ”¿uÀ Ã×{»Z©{&3‰U «-–”}™2lðyD£ rXгvþX¹3;PÅuåÁkçAìʼnJI)òÛ¤6Þ~kDŽkœðÕr`¾Þª˜ß­—žÍm]LèÌZÒ¹×`·5à !ƒ9¿§£:LVÛx°„YJ»‹È$Q„Ó%Ov4rÕ/ŒEš¹Å‡hrõ¤gq‰ÃâI »ž ð´v…Öµâ”ôô®$ðtl0 _2‰UÖ ñÇ­Ð& 8i ÚS‰8îì*2hÜaVÀQÄ“nòU5]Mu![éo(Ó•ºöM»7Ë­>0eXõ܈µ0pé7C{Ø@è´Ÿ]¼ nȹñðúÊÝáý>äÆAÜ@I0~Çc~Â:3÷cš¹€F½5;‰4Ëd?]áÉ ì¬o?Uû9êGq¤y’Â×Í gŽŠ:Z[ˆvÚa4Ñ7~LÅ»[­G'xÜ+Åq¸/Ó_zÁšti\ßç3¾frë|Cƒ­·«ÂÔN T09¸G§«FDZ—ËòßÚùê:ñ­1VØÜÂOGïþK¹ù¿~8±M´LVçÿ tBîx?‰>â„1šRÏòg€Vꇽ4ü¡_×)XÛ&‚("Bh(ƒ]7ŒQ\­HÖ›îüHû"¤ŒiBOá-;8z§t‚œ+6¯Ïó~z/\ô]ZeT²–ÃñÍ+ !b'››2á,†,ꢄªq‰wÀÑ ÉYŽŒÞf½t¸ë ›åå=íÆ^¸b}LùÏd:p¢•c°…jòñ`(4½i~5…T•òPÒj àW7‚¶ œ¾yÙ’ °~І NÎO6ɪ£zœ³ëª•osüsÙƒ‡zEäN  +dúétÕBoRâ »‡+{>·àäê6GÔZ‰¼£ÿâ¡ Ä1DuåØò 5²ŸVe.(ÇÂ&ý[ RkŒÑQ|&I!š¼O="pf¤Ìˆ·PtG'ƒé0c˜ÜžX-cþ¾.«ûè?ȇõ¹~ÐÚ¿hGí ?ÀBûB/ÚûB$CûA@øOÛëÊÿVÿÿzíVÿÿzíVÿÿzíVÿÿzíøQ&ï8oà½Ý@äˆ~øOôé¯þ`øOôé¯þ`øOôé¯þ`øO÷ðŸÿÙsimutrans-124.3/src/OSX/simutrans.sh000077500000000000000000000003441474050137200174000ustar00rootroot00000000000000#!/bin/sh # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # "${0}.`uname -p`" if [ "$?" != "0" ] then /usr/bin/osascript <<-EOF tell application "Console" to activate EOF fi simutrans-124.3/src/Windows/000077500000000000000000000000001474050137200157745ustar00rootroot00000000000000simutrans-124.3/src/Windows/MSI/000077500000000000000000000000001474050137200164245ustar00rootroot00000000000000simutrans-124.3/src/Windows/MSI/ProgramDataClear.js000066400000000000000000000001661474050137200221350ustar00rootroot00000000000000 var fso = new ActiveXObject("Scripting.FileSystemObject"); fso.DeleteFolder("C:\\ProgramData\\Simutrans",true); simutrans-124.3/src/Windows/MSI/Simutrans SDL2.vdproj000066400000000000000000032014761474050137200223410ustar00rootroot00000000000000"DeployProject" { "VSVersion" = "3:800" "ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" "IsWebType" = "8:FALSE" "ProjectName" = "8:Simutrans SDL2 MSI" "LanguageId" = "3:0" "CodePage" = "3:1252" "UILanguageId" = "3:0" "SccProjectName" = "8:" "SccLocalPath" = "8:" "SccAuxPath" = "8:" "SccProvider" = "8:" "Hierarchy" { "Entry" { "MsmKey" = "8:_003EF520411A46E6AE484162BAEDF263" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_005ECAB11B074C5787B1F8129ACD3DB0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_00978D4D6A334BA58E0D8F5EBDCE7F18" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_00B608AD6C5F4140B9EF5D465B3E947B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_010C9071ED524D8A8DC6A171F492F08E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_01D6A70C8D5048A9BF9BED777F584437" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_029552218B4E868F9CDB0806BE6E9ED2" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_02C7691523EE4C7AAF2C42A5F56C522E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_03030B54657549EEB3FBE9CDD8F47144" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_03294D718D6D4CC89C9CC669C9E3AC45" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_03333F46557E4AA09C3D2EDA7DABEAF8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0387841035034B988BC7744F512624A4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_03C3084D08E640D7A56876BE20147A37" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_05C99C5CC13C41A9885ED5CAAC4E241C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_060F8BEC80784113B5C4D0565C7B9B1F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_06B81764E3B7488D838810FAE42C1829" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0715F183A84541F5BF5D7BA3BE88E0A3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_07484E10F2A34831B3E6D9052C6B64CE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_079B392C00696F9EFD81A8F4C6CD66E5" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_07DE11554B2143DB96B5DA78A0720AB9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0819F586738B42CAB30947A5AD8337AA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_081BCF65CEA34B1093E83B88818BB39A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_09BA1EC65CC548038440E1CCEF260625" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_09FE9501B9E54975B984B8C110C56D54" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0ACF34CBE28DD32DC79D67B59FA64626" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0AD370E81C404873BBA9F6C080DE9986" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0B4C01938497473C97E1330B603EDC0F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0B96ED126C9941A0B5862E17EBEAECB3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0C86FF1A217F45FE9BD380453833B87C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0CC8C3B5975849E7A0674BC5B24FD640" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0D3020DE4E8ED5CC4AC9098B65B48DE7" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0DF1600FFBCC494BB4B3A3B41FBD4C45" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0E07641E8CC4496389374E089BCA52E4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0E90A6C737F1457096CEA2E4EBF7F70D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0E9BE20E59D54B6EA446FB9399D2BB1F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0ED6E2E3EA9748478583F98377A57988" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0F28D5341A894A28A785BEF0499CC2B6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0F9A37FCBB244ABC8A8149D9DF2B8563" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_0FCA3DB968B942E4BF29F988842AC875" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_101DBD56305847DA96CE37AF80AC07A7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1105F13F49EB413D8862437DEC6BFD64" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_11193214718A449C82F62145CD8B2C02" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_11DBDBB9ACE64BEEB7549FDAE6CF5500" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1237F66E84B34262BFEDBDB63174DC1E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1237FFECE674421784292D366BC64FA0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1247C8B3EBBD4CF5B1EB76A31014553D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_128F2CA87D9A4682AFD96DF5D4A04141" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_12AB4359C4B54FCBAC46DA8D834EB09C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_12F07DD4BB194D0891E2C35D9E2AAE00" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1339688690AA43C3A985A46189829DFE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_133D00B493E44429BEA58682323425F9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_13506C78AA494DA6AD4BD5AB7BB66DFD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_13637737D70917BC3CEE9C780E1C321C" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_139DA0EE1A894318BFBD62365131B07D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_13CA5808023C4A98B16E6F84BA0007BA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_13EF44563D4C4ADEBB10945AE080BF57" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1440778F3A70472595A747394B138D8C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_159A716BFFBE4242A25D18DA7DF569BE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_15AD3E75D8494309B7E9D38B67792845" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_166AAB6C447F4F14987682E2AE9E49C1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1674AA7C5F1C48E5980265AC6A9165B6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_16B9E22B4A6A439993F94972FB73C067" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_17B8C2EA02764F9CB743E2C2035BF903" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_181A6C90E6B7458EAB2292B8BE635C8F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_186AA79D5784439EAD1C5E15124C7F7A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_18A83AC11E07457D9E0B0E13BFCC3E79" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_18BABDE15592474D9AF3C78276D8449D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_18BADB004C1441909DA8DE66D75CDEBC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_18C933E7D69946F5B947EC8273AEB559" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1918ADD2CE144D709D7289D49A2CAA38" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1965A5D324AA4723A6D357265F9AFFC6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_19A98DC8BB0F44B5B90253ABAAFA14C4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_19BD0EDF53564D459C8A659AD26B22E2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1A3B66C3F3284C54AFDC39383717874E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1A52BAD08FFA4CF7A52704515E265E0A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1AAFF255E23343BBB16D3EBC42EFB21C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1ABB22A9F34A4486B4D0F7D6A8ED75C9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1B742E6F5F794339B7B00E5090AE41EE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1BC8A4B2533D4A9B81A8D906E75CC892" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1D713659992B4EEB89199A782FF15A97" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1DC828055A404A2C90A33E0062965415" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1DF38A11E5C74DB9A741FC9C10A3634A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1E30A8FD30C344B29F0C9B8BADAF36B4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1E43FD6B874142DCB7A19BFB907DC4E6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1ECF0A79127649D4A462C15FE8EBDD52" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1F78A7C6DB6849A1A3352CC3B935FBBA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_1FF22B3CBBD34BDDA475ABCE7E8458FB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_20AF94701C3B4F31BE18E4C18593C65F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_216D641690CC4689BADF94365FA2B97A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_219E1B7730EC46EAA280143D520AE19C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_21AA11BC689E42B6B6697A5FC318E096" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_21AED397D928464F813731B7A635A8E8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_21C491A79E964383BBEBAFB16263BCC0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_22571262D0E1464AB1C4D661D729A7B2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_226BCA5FDA2B4579857D5F4C3AF3A482" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_230AC91992494E47953EE25EC0732E52" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2310BE29D51D4698A0E4D57439C7CF4D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_24C7BC64F7BD4CE4B1EC004A5BF37584" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_24D43BA152AF47719E58C99043546C39" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_25565CC3AFA2488FA09185A4D3536AF2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_257608DA64F7495383410A50CD623626" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2580742A58474754BB9F6E8DAF113625" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_25E373020643480BA2C6C4FE1967DF39" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2688604BC1004159AC65DA8026AAF404" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2692FE4659B3459FACB55B2ABABCEF3B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_26F725E6689A4B47B5225B9F9A6C4CB2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_280DE28E23F3432A8CDB55AB067712D2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2820718EDD1A4C0A998A555B73E7941F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_289828740CCF4491AEAE9923ABC9E630" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_28D87BD82DD242048CE3AAB274E4F224" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_28E16D55A93A44CAA25DB060E24E199F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_290A6460DE03485A9ECA056C13AB547A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_29ACEC7A06E24A1DAC101B2DBFFD8054" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_29CD1E15907F4CE2B442E61E72296DE1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_29E0B719E1D143A3B435F746D294CA48" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_29E3ABF203C04D2E8FF9FB6AE98967C1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_29E5E12EC22646BAAEDE11AE02DC2C61" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2A7AE2771A914BA7BBDEA452C9DCF2F3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2B5B075BE23041988B08F61EF1DE74AA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2B6156C249D14E63834D6BB3CAB3FF16" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2BB109D12B614A65BEE199658898234C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2D6E5C7AE3F64AC7ACE938CB8ACD252D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2D94FF39A27543EB95167C67429CF990" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2DAFA0293AE04710AD9F7E863F3BDCD4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2E231200DCCF424DBB14BCE8FE6D93BA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2E8428F464504F4CB245EFD3D16D3342" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2F1E496588C3496D8E4F6B8FEC90DF9A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2F4938DE7AA34B87B0D997F896311B0D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2F8D3E0ECE694AEDA82C5432F24C854E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_2FB0C916FA6E4D568517572F31975178" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_301A99763E6F471B96D9FCB200CE960B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3048CD4420B04A098D932C7011C16F75" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3067D12B03BD409DBED5BBA78761E959" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3075C6BC47214728B90B6AFC317EED62" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_311BBAC6B2C346929B78EDDCEAA25F52" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_314549B8854B4E04A7B69C5A1151519B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3156DFEDDFFA4625949A11A1B0F470A6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3179D684E9B144B78C3AF7E94102521C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_318FE10CEE38456B8FC8241021019358" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3194957A2F144B9DBB90D04D1202A0D5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_31BAA09A108D4F8D9457940B5856273C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_31D813A3C334427AA33385173447DCE6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_31DEDBED22EE4A4DA099BD028FB246A3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_31F6E25224B744DCBFC0141E79D10A60" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_323064989CF245F393B3FFED1FE07884" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3233EF6351004F93B9715A0A7AE4FA74" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_327F373C1E7413799B0AED3AF56713C3" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_33296DAD659B4BD39798C705F02C7834" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_33BD05ADB1C64EC8966999E905C33C9F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3487ABD4F8B94084913A128F4AB191A1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_34A049B6090F498E8A74F7782E6AC542" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_34BB38CFC48E42209DA5AF5500F6D2BA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_34DE603A33A04466AC350B9AC8D6A0A9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_34FE77A5FD59404B8CDD5D21FB0AC148" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3519CCFB2AEC4E349CCCFD738C500238" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_352D3120C5B04626B12EE20AC398F144" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3530E1B1A1844BDB81256561E663927F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_354005FEB66444AB84E610AE09EF0FE8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_364C50343A8945B59522EB0EA95F7370" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_36993815822640F6AFC910D125044DD4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3718F392451E49C8A03D48167AFFC98B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3721799D17B548DD91B4A37F71B2EA78" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_37605F6B6AC74871B93AF782EC31EA68" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_37666D0AB6CD430A955269F7E1CB6676" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_37D5EE6E06794EFDBED006661DB3CE03" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_37F86EBD13864C7986A4D05594E9C7E2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_38252595EA444B1DA8102684564FF3EE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_382A9A025A4C40BFBA389633BCC7465F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_38690161FBE14CB8B378D3A573CCF35F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_38935C206D864F57B6900428D9DB774F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_39EE9887C474434CB0593872C88614C0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3A3A98EBEADD4475AE7E4F2154758DFA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3A45C9EEAB5F4D41A9EF96EB0F70FE98" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3A4F1A9658FA4B0E805DFEAFA9B5C2EB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3B4AB35D4B814E49B374573FD9B41D9E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3BB85C849F4A45ED984521EF7EC00FF1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3BF8D681CD3B4B87B032DCF3C00FF926" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3C1CB9531BCD4293980FEBED7E010E28" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3C5211F08FDE4E4490BD5AF66C9A0EEF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3CA70B6D5F48488CA38489C0EC76229E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3CACB35ECE044CABAF73B3AF522C618B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3D42F41E95F74301B3DA30722D7F4D74" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3D6D0B1545684FB685D35EE557CBB335" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3D996E275F02498B99D4B122817672CD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3DCFF913F03C4FD48D362C46015CBA63" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3E2C5CEFA60D4DF59BC3A743C2073EE6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3E51AC108118479CA3F94EE04D6F01C0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3E5E32603E444A4BB9392F2DBAA25BF9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3EE1A722BEDA4ED7A2ACC4BEC7F4C4B8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3EF0959343750F1BB1E3683C3BB95052" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3F165DBD8D454BECB94AB3737DBE82C7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3F16D51E7A964A99A35D575CB10B1C2B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3F1AC2D8D7DD4F49B318E45AD0000E4E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3F3BE766613F4BF29D52703C4C0D0427" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_3FD7E53C07E241C3BCD00B81C59CC66E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4057B27E9E494E8CBB7D1FC8FA3EACA2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_407A3BB3FFB14445B01632174D68B032" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_40A0BE0449894903AA520D9BB5D5EA6F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_40BBCF7041234B0E91AAC36E71B548FF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_40F016A1CD6F4489B117B3264DD98F90" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4147D6D1F8A245C4AAC7DA2E72741900" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_41600A65D8804208854E48546CE03C31" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_41DFF372121244008F06B6CFE66D65DC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_422F124DFC564135884EE030F8A75A7E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4263D1383F6141CC8FB85D9C89A37DB8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_433B0BB603EE49AFBE61E4A95B62F025" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_43B4F064B408462B9CFF09DAF89256DA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_43E4EBE3CF4C483F9B9C3B22FBF18EE7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_448B7A877DFE4EE7BCCC10E684A9F9B6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_45907458AB0F4F9BB5167B3C22912220" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_45C20A6E3143435AA6855758F2D9E540" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_45F7C42A57FE478FBEC1428DE3C17C67" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_46264B5F868B4521855C85BD897A8A84" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_46456885516B4B789AE75E836C9C05E8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_465C2BCA0E3B44E98A0C2EA624307C51" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_467B5D314942411D8AE3142D49E698C0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_467BE99BEC444EB28162927D6652266A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_46B75EC9AE974FA390E7CAC4D35F7919" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_46F68A58A67F2A54B4325EB94650EE7D" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_47293CF4BAF54E8CA44A9AB83AB3CB19" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_47CFC2CBCF804F13AD453C25372C8730" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_482768525BE34C6BBB46DB7ADBB779B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_487490D85D3845FDA7F0C9B3FAB37393" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_490DF7497FD3469186609337C624758B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_49B9EB5E83934E4B8E4B0B9339FB5FAD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_49CD0D1D118547D3BE550596B2889432" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_49E3C49389E64767AEF91244E450BCF5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4A24E208D93D4E83B56C55A98B427CA4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4A85838D1D85427897D4F69693279715" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4A8CB7B7A27B416E8D5F16F16414DAB5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4AD08276500247AB8FAC3EF4B77F267D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4AD33819C37B42B1B0B339CE718E5CDE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4AF573D713344BED9E783ECD4C1284E9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4B6BF260CCD642F6AC9015FD883DC989" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4BB786F99376461988413CF1A585AED9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4BDEF13001284819BC75A57512F7E7CE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4BED95EEB2484DBD9257998035AE6209" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4CC13851778543C889504D03B5927C2E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4D3B4F373E4548D6882E71F29ADD2774" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4D4A63AD27BF461C917A7C7A92F3A084" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4D611D172DB94EF8B7C138B581301576" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4DB844664FE94090BEFB466C6763B36D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4F58BA38FA2541B58E8C52828A5272CA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_4F774CD205E24CF4BE96227A527C8539" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_502FAC792C1D8614FE7926131D186D21" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5078896E10A44B0E8322B5B2DD9ABDB2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_50DE5B28CD594DE7B5F13CFEE25C43E8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_50E96DDE2E454243BFC25EE2D771B7F7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_512BCD1EA02040ED9BEEC446FC50AF1C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5140C10690D54348A4368EE02676B691" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_519DFBFE15F34747A61A95E2B9B10BA8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_51B4379EA7764F718E23148EC7F180AB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_51EDC323F02149719E5DF86E69F1BE72" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_51EFF26BEAF246629A4975AEA01A1470" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_522CEDAB5F5347408C153DCEC08D1B91" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5241ACC17B5C411280903A620FE31CDE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5264B3188A1F41E895A034ACBCE23609" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_529822798EDE4A6EB66A8FBC79D28466" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_529ED68FA8504A2596F83E3452215DF3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_52EB158E737145259F9D9B99E3A0DC77" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5358F97ED18A0C27CFFFA550621C549F" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_539D40508C6E4E75A11EFBBB82E0CF8C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_54BDE901C9354D4294895144769BACD8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_54C84BAA19B04F939D0E0367B7F17DB5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_55455C91BDFA4715B97E7CE7754928E9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_55A356B6F2BD48BAB0EE1DC4089CCC6A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_55B15CA598B04AC8AA57ABA39B5737D6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_55F557FF2D5F4FF8B4B841480F8E02EC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_561E7344F2D3457184C0231FFA8E0D63" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5649E800E882443DBFA060EF7C6D0C54" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5713DA04E2164ED6A58DF2872113A1E1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5722A6A9D28D4A048CA3FF4C5C399AA9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_575341B1DC7743458EEA436605782806" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_57969C68E2AC43A8A53EA72F3B6933F2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_58059A5FD7D842D4A019A4BDB501153B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_583AF0963D3F49819D420B80764536CA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_584B82F1837D4263B9287A526B252157" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_585E548884E1A0024245C4DBE90F6893" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_58ADEBE3020643D893F8EAF29C412F0E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_59052B74FB614B939DD6A4414515B755" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5977CE44BF2F4CE3B66EBC2E9BF91AA5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_59E2DDBD34F64EFCA5911828555E70E6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_59F7612898734E4DBD36DF9E76F2C256" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5A61100119004DE0A914F075B53697B3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5A8A8FF3CC8D4B3595A9DAE1150F703D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5ADFCBEBD3DA466287FAE7D8B02A2907" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5AFC05EFA72649698E65D01DC3A85278" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5B4BF2BFF84142708C9EA8FC67DB3216" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5B73D425BB464648BD3F6C58AE543014" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5C6AC9E04FE740A4B6E9ECBA0CB93F7F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5C6F45BB13064E52829F43B6FFE00220" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5C9630709CED41D2929492FD463827D1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5CD15C85FBF94FBB9AD95AA7490A45F0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5D9D568EFEE54B5A8A2A88644C400E6E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5D9F5328272845C3B2E2857D1BF93E74" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5DB6AF2EEFA24BABAB9B45BCEE62029D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5E76DC3AD0814F04A545A862CD5E7DCF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5E82840C0671457C8E5FECF7032D190B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5ECEAB174780441CB6657A851C694B5A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_5FEE0DDA9A2847CB9FBD5EA59EECF525" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_604DDCD3A6294FEC9A6F72485DC08DAE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_61DEAD687F5A42A9A3CE05CF43194861" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6216B709025B45618D3CE7D60D744328" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_623197F7D11B48FEB04D649E84458841" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_62697F60BD184B3F85EF352882FF0FC6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_630392339F2C48718E8D505AE3524178" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_63090592FEF84404865D0F30FF65D3D0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_63254E53870241DEBABF85CC64023D1B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6335879001C8412CA64A127760C570A0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6336B3E3BB544A79B2748CFB446ECFB9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_639BCC27C4264E149D85E7E705C52710" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_63A60E70A6274498A49DD55849187C7F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_63AB0309FFF146E5B9A8BA431BEDB581" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_641F8E28A18740EE9672DF14F4322517" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_644E9138F1B04425AF2CA49C8C1029A9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_647D7C02726B43339F93308CE7419FC1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_65634BC992FA494598EA6E6C025512A5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_65CB95D1DE44480EA45158A755AE64BD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_65F46B0D45B646C4BDBB84B11FC74881" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_66A93844669E4AB8AFD7960F553D67E3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6702CB4A485E4C3C9B1970AC9D77FFD0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_67073B82D78742E5B9F3A6D364AF649D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6723BFD2968F488A8B21778707DD42A0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6734839905EF4389AC62192A95B835D0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_675B1F5C00FF4877883A37F4EBE1E3F5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_677C07C6147A43449F9AF59CAA3DE045" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_678A6CC7CDBE4341A42A0D8FA05D8A80" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_67C77B7A81734DCD93763CAFDB731F3D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_692C781C1C4944E3918865C3016F9231" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_695F9E0D19A94E9080FCF6161EBF07D9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_698D6BCBB25E43D6B7AA5EAA8898E4C0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_69A7859F453A4A91B8E1B6F8EE0E3623" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6A45AA5600B54C83989EF933E7D81F00" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6A709C49B7F943C691E029483C259726" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6A7B7E930C944000864ED2DC074B8944" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6A8F2A7B2D0E46B7BD05ED75ABEC07C0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6AC4A1E5DC494E24B5BCEF7E92D36816" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6AE881EFF6E147EF97DE619B22172E27" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6B365598BC624617B2B10FB965E239DE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6B5218A02D434B9BA80C49C643184341" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6B7612CAB6554AF286B04C35DA865321" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6C3CF89286EC42DAB9EF964252360D33" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6C7F90DDF17D4C6293C647A90E00E279" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6C945BE71CFF4E82B4F0DFB72C292BFA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6D01F4293A064FF2A6A6CC0F0398D328" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6D5F0504040C42649AAF5C80A6C93AF3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6D66B32FEBB94455B6BFEE30846CF33A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6D7ECB4FFD0B48E7A13074F90688F225" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6DCA48436F4847F5B3F327EE350E3AB1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6DCDE0BC21E54EEFBF9CFE05BEACF621" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6E5DAC8084104079B655A2FCAFAB3CC2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6EA80C01AAEF49228558822219AF7ECD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6EAD4002E15B498AA04B7DFB144B3917" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6EC63EB0D6364EC391551F261C4E34AF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6EEAFD65E9A14B65A1FD6C694AAEF48D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_6F75DDB2EDC24C53BFFB2A4CBDCE7D32" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_707C1BE3EF9242BE9746771AB5B6E60A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_71225218E6B24F409FAF954309A5F4FE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_71C350E8A9B4499694F7F9CCF037A2F7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7243A246D6454771A7F203730142ECF8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_72ADF54DF3BB4CB495E986114E1E2DF4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_72B1848015A8405BB280F12F7FE44143" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_74126279572F497EAE3334BC10BD9420" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_74CF407282A64494B3743E844FA0B38A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_74ED0456E40947CA92C62824E4125894" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_751BF54EFC91407790B42AD4A75C158E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_75982E571A6F4F2A8349D07115881603" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_75DB0F22A99B487FBCBF4492787CF16F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_760A7DFAB6A846738F456A2D9B75DF42" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_761869FA0B4342EE977F57311DB8CBCB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7627C3286ECB4901B7FF66783A56EAA0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_76DB0BE795FC4B5BB8D0D0A037368A67" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_76E349042CB043F2809E4858A2D9A63C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_776CD7D0F5E84BBAB5A8563DE24D69BB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_777C23F3C78F43E196CF3E5471716A92" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_77AA9368DC924035A400D7A741A3B134" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_782A3C3B9FD34371BE3AEA0EEBFECC02" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7879F46087224474AEC649E7FB71EAEE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_78FC1DE773244F7AB6CEEE32A6997506" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_791BD97D0CD441D4AB0F2291EA64362D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7A4B68C765954A77AEBA8D340DE2310D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7A873BCA0E874A5C9AA964C4EED19DBC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7AD1BF4E17F04C1485967C5A664A4E0F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7B480D9F16C7409B8547DF976679CE18" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7BC9AACD90A04AD8BA6AECA487E9DCFB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7C175A1D24E94CD485688A2AE69E37F7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7C4ED6D1255C4087B67B059046DE362C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7D2FFB8DE5D246819C5152D280523C44" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7DE009E5FC2F487FA3A2EB121E49D0F9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7E1AB3235A184CDEA7ED5DAEF4C8CF96" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7E2C2656F54F4DBCAE3C5FD9AB651368" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7E5C15BD3D26417698877173773F3DBC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F01371C7C884AA79D7B332DFE9CFB87" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F01AB5E57414138829BC412322FD334" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F1DC34C3220499EA78996207F8A9F18" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F275CAC05284C2BAF4B234E294A98AE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F473696C8894F5C827D4B1AF4EC61DA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F5E16592EE74DB2AD2B8D96120CA325" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7F86529E598F451A91EDB4A9DF245431" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_7FB25388690E4F35810256E3806D7AC7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_802286B2E6AD4D5EA5F7582550D0192B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_80718F22412647C49DC0084C574E72BB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8079B5223A464AD483F0B286A55B7CA1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_808B71735EB742128850F708235AEBB0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_80B5D3C38CAC465BA8C2550F7914F614" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_80E9BB86DA4D40C29497E5182B73AE5C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_81301366B3184A6FB5E40F909CF6AD26" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_813B3C3F7F724EB4BA5EAE500DBD41C9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8183844A6C6347D9BE1A8F17A5EDC446" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_81A24FF94CDC4E40852AA1F5B3802088" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_822E7AE56ADE4E36A4E2E5B00138756D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_825A92662B9B4407950D37C0CDB8F119" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_82C60047E4034EDE9C5AD03F08662F10" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_83189152D1FE45048CECC4A9991BFE56" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_835E8828F7DF417BF90CE0E5B3ED79A8" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_83A75CB51DCC4F87B8B9A3F8A3A215F6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_83C4B947AB2D43A09248D150A192DBF5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_846C24B81FCA43DC933E9BFA18FAE15E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_84CC521B95224F7383B53352F9151899" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_84CEE7DB1C0B407EABB654B361525004" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_85337AECC7CC496DAE6643D82A1E3F60" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_85CE5B3A65CD4D95AB6E6665907FB16B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_861479A1366940A2A130D6D3735A7D16" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_863731CD1BFC40B393D50C392C7916BD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8749AF65C301480F9E7A596349DD1367" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_879DA4798F1F4B11B5C99669556CC5B5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_87AA9DF095B146D986B7BED6B55017BE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_87E970659D104ACDA574ABA4AE56A153" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_882138DA00E9460F86B35552856298D2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_88A3256281AC4F25AAE598C1481FA990" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_88C0513F233B4CB4BB2CB756347E75F2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_88CEDD14A00441AFABAAA66D3806D822" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_89563EA02AAD48DCBD9CCFC5B5EB7A95" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8959E24FC0CD434A8A27A073FDEC71E2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_899749C5350C4225A5C30A5D6948EFDD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_899F7FB3E2F84E6A99128E5AABF039C2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_89A41FCA30A346A3A5D38B4DE2892768" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_89B354D3105949B1BF654E7853FC7F29" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A0AA6D0C786436E93BD790C69FC2AFF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8A35DF083E7D481F94A22CB3A0CF9A71" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8AE1E9F65C8340A4B7B931321BC783FA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8B1C110612BFB297E730E7DC8AC24F63" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8B37931EDEBB4DBB82D4D794F46F4C4A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8B88D692BFF14DE5890C554BD2597CC1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8B98EC4380664715AFED6BEF0777940C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8C55EDABC5B542B88FF7074E4E99A08C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8CA32EF48C9640E9B151FC50FD50DA58" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8CEB3078E8C9419588372AA47D36A472" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8D341EE4712F4242AF051C6559BAD35A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8D9FE449D76947338601A9EF5EFEFC94" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8DC1AD7B4B434F15B3326D669B5925A5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8E07E467482344D8AC909E3F8F08B953" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8E1348361EB141EB80B348E2BA434EC1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8E2B0BCBB33945F9AD9D4A62B729FCBF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8E77D1CDBDC548E9BC92AC3E05BF156E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8F60949CD512455AB188852FB8723732" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_8FC094660CBC4042BFA3CE7638801FCD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_90088DD7694749FD97D2DDE8DDC76779" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9012A62701DB4225BA55AC67F1B5A4D5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_903B35BF02DC4724854FBA8A693E7BDD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_907BB93A2A584C53B4A2808085BE7D63" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9093B505D80E44A88C5B422CF39C3F6B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_90F5B235E42C4301A5E0BE03B752C5D6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9196381DF8F04BECB29CB3A4EB358118" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_91CCEF23F60240989740162A20FFF3F6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_93076B17FB6342D9A680D2DB5CB88911" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_93553371BA0D4BA7AF534632AB28AF1C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_935E39838EEA4F03A10A26790A4CCE11" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_939311F03E484FD2894C70B30E575E58" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_93E45578B9A84ACF886B916820BC4D5C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_93FF28B992E344FDA54C83E61D5DE45B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9413D0887CEA4CEF8E077401A528CF8E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9494DEF39F564D128A2A1D77C94B41B3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_94C3E9F789844176B1A29257B7F54F25" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9512546582D04B0BA8B1EB90C25F266C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_95DBA15EEC0F44B98B81C3ACFA4A5A78" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_97AC8B571A7744588E1B5F4DD29926FB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_97B9A460977F4B43A3F262ED3C9AF963" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_97D429291A1A4B448DEDAC39AC789CF6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_982663C4E3A74AF98D1614ECF1222641" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_996EB12093BD4A92A9C8C5D7A3938DED" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_99F1C1D67C9F422685E2764F4D5E13E3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9A1181B0105A4B8F839A9E88FFA0580E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9A214C6687884ED5AE39CB9809B715B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9A88343020324D73A521C5512E5801C7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9B24FA4B5DF145758D44C5A386E1DFFF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9B45AF680D7B453183740CCC5186F98C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9B669C48C940449882D6A2D67A5396ED" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9B97A924FE8546D488A68B2055F6DEAB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9BAE51D35D6A4608B5DEDE105547B06D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9C3079C5132A47CA8F7095A52DE30568" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9C8885FA8EFF45EA9CA498CAAAF4D24B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9D2AE5121BA64CFE91973505C47CF36C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9E3176E32D8A4094A57AB6B64B17DD9B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9E747D5708814DCA9BFAD71B7650A582" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9F43E9CB3E4642B384FAE24279AB317C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9F5B93603D5E4002AB90693F485FDD9E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9F82245E13B84479A19ABB0517AFAE74" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_9FD82999B19B434586CA9147504F6B69" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A00BAB251762400FBFDB3F5F9DC7CC7F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A054E4EACE3C4ED0A06A7A05E9EBC6CD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A0774C119AFD4A54AB9DEFCD892EF3EA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A0EF7ECB8D1A450790401A38455F2FBC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A110420164074F6F80B1CCA1970AAAAF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A12A3E89B73A4D3FB21673D41DA88E76" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A13E8EA5CEB54C88BB30C6725F581FFF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A1A46558136D4B6E95B80C55A3FA5629" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A1C5832E423B46709ED06E8882B8DBD9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A1F00F4A0643448DAC8E66CF0727F09E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A2611C5487D241FF8B561E52D56B160C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A2A0A247DEBE4C00A67DE0C78793BDF3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A2B299E62D304A90BC01839FD9982CEA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A2C5C7638B7B423796BDDE1B37CC54DB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A3F9D5A01ECF47CF818A94DB7E3F30BD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A40DB08E389B4ED2A1FCD744FB4D5FC0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A438B857F43A4B91BADAD3D54FE069CF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A43ADD711918462F861281E4F45A3ED1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A46752F3A99348CCBCF9C33416BE5DDA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A4B5359306A34023A1ACFCD33C9B6B16" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A4C415F986314D75820B3ADD15F324DC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A4D653ABEC4646799283098724AAADB0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A51036CBD78E4C6CBB96191773FE82EE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A588D7D5733E64B36617EBE50FB31F3F" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A6644507B63B49799F05083DA240574B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A6A9C9BDA5A64E4DAF67877AAFA1F7E7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A6B3B56E517742D49D7AC896AB575EEA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A6EF70389C70472A8E4E4813A6CE44D3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A6FB275BE7D44AE2A24847C98A708103" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A766C5646A994F18811DC5D915ED99E1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A779E5A5C75B4577A215A6927870BB62" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A77D989F8A3F4AA52521E174DDF6EDFD" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A7B5A28B66FC487D9ACCAA1A42521224" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A7F06B6F1E2744E8B7803429C9B12AFC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A83F1194CD164AAA847A140EE8589B87" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A8778490948047EA9E74C817CFBE23C4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_A9C9120ABBFE446E8CCA925945456C1F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AA1E6DC2B3FC4067ADCECCDA4B09C94B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AA7A085BD36949179AF2196EB06CF7DF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AB7122076A2045E9A16367FAA2603934" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ABACE35D95144B839016535CE2C649AB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ABF7BAE834ED471AAC122B3BA17D4C73" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AC22050E398241C29F0A0AA66AD69C26" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AD63432954AB432DA360A092F3ABAFD4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ADC52D4B09A046849FEC19C6ECFAA4A5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AE10E8B948F646FC960CEA7D158BE1A3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AE3624817F3F4EC2BC9ECCC528D96588" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AE43098A1E4D43D29FDAEF89B96A61AF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AEE0681E6B8448B4988AB3F8BDB95FD4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AF1BDC5479324EDEB012F7C64C02297C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_AF20A26E81F541948829FB5AFDE66541" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B0115B9715024672A9C1FA4CF0465956" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B0174050546944A19CF028E1DE44908C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B038F7BAA7974FE0A200AF565B96E33F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B0F23AB72E7A44AE854EE09E4BEFBC66" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B1094D229AD5442EAB76FC665782E076" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B12A038D1C9049108A3667AE89A7D7F7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B18F2A9BB0514708B11E2E262F7D8610" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B1AA4D786277439581E192B8982152A6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B1E1D7D3CD6D49689CED7E882E2FB5F5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B257E8B4219C4B298174488F5BCB7653" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B2EB2EFA27E54709B879C952BC42BB4B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B30E29F10A116D760074368E5BEB7A1F" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B316F19F34FE4A51BE7EC51035DB90B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B371DAE4A0264666830E52D9514DA2D7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B3E5650F97D842528A636AD1DE430393" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B4B6DAC3BCDD42A99F77E9098980726B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B4E6E7EB7B9B42DABD1B411335B4429B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B566F21CC84A433381E8CE406761ECB7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B5C875785B0F4C9D9E76B3EFD305CF39" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B5DB74F3CBC44655AB3DE56EA147E4BD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B639E4ABD1444D78A8951A35EDE48EF1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B679464E4EAF4C549CB3B9BF93D9358E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B69073812BD04A2BA4FE0B6A8728F192" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B6A96A7B568E4FEF8FA8064518106BC2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B7CC8D077EFE42F9A0BC18F9A542E5C5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B7CC93E185B646E894689577E08EB81E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B7E5A578391A4BE3B786CDEBB4E7C262" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B7F6FB8254814AFE85BA148D583519C8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B82AEAEF414049BBA22FCF7C4281EBCF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B83FC3C677774402A75A2F6D613EC218" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B842BDA6FB9C4FF1B282CEF21A64CCC4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B875C187F9CA41C1AB77763828610A7A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B89E145011D34C80A50B7E8FF22318B8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B8A836BEA9F740858A2C1F1FFF645C71" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B8FCCA127BE24285B276CB6B88CA12B6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_B9BAC184AB844A96839578235935D13F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BA92F69D198449BEB1A743C8E95A3F14" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BAA758A15315551B88F9AF92A6E67840" "OwnerKey" = "8:_B02CDD54271647E084EBF14CA126EEFB" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BAC6972F9BC24F169F0B59391778F185" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BAF3091B84044FF092312FDC3C441130" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BB25C1A581B2468CA01A37B787637CCD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BB51F76CF0614FFA817E9E28765936F4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BBD31A3743C64DAAAC66C73DBC395184" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BBFE3D0B7BFB49009DA1BFF118B2CF66" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BC104A0952934C1FB24C7C72FB22ECD2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BC5B445C4A87461784901F2D6717A9C2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BD8A0A9482644575AB7586E6526EC50E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BD9E0D72052E4EF7904B45E1247AF92C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BDA2160B8AD742CE91A5BA58C603C55E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BDAB03CEB8A34A48AE15DF20C239DDB6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BE0F9941F59E4C458CB67EC2AE92F547" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BE7A191C730B4BC3AE367292A126B060" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BF735304ABC245BBB4251519F60E5828" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_BFEBF932AC564E48B0AF7256A973C278" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C0478D73D2AF4187949270E6FD38389B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C08F3403BDCD48AD83F04C9427530612" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C09716430EA54D868FD696C002FF54ED" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C0CEAECDB8F8480684B11DD07E961667" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C1ED0648FF6146B0A5C52AD0740588B6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C232E233F5334677A44AD9480882E1A4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C25D46C642324693951E9A826BAD34F4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C292DECF838E4A338B1E9381FE88862C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C2BCF04AE0144DB7809933F09C0D799B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C2E91044BE604F148A304860DFB0BAAA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C32B257727534BA496BEB71041ADF2B4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C367477479AC402B95F1AD058F17DF0A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C38EEA378E554DDC9B7516B8DDED70F7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C3C23BE233074FD6B456C2C05C5B4C15" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C45EA6EA27E24554B7E1A208734911EC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C476765DB8F94213A45B04C05F8658CD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C4DE63ED67994259861CC33EC3C8BAB3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C4E281AEA3BE44368B8891E3DD4FB96C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C4FC973F4611411EBBCDD999F5028D43" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C52BC200EEF6472E848B8CA666DC1B2C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C53EED194470430B8048AC19F45B8991" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C556B896643D459C81B361121C73C2C3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C5C315A416D34418A1655DBE35B025B3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C5FB56A197624E3C90766B9BC6F3D773" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C645106B875C414D919C4B6EF4F649BC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C66A118A06614510B5E13491D6C91EC5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C6BDDA3D38EB4DB8BACF5DA31D983E82" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C714818F8D754E9A8A9DC40733B30135" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C71AC36C9E1948349CD116DFBC84AB1E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C769223702A14E0AAB81FBF9D60B6CA7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C76E4317C8FD444E80C157DEC0DAD612" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C771425A4D4143728EDCE8CBCC90C4F3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C78E7F7C98154034B15F02B9BC53FC3F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C809E4861D6D46E78D6A32FE8124E73E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C81BAC2BED284DE786B2D681EB8E3E1F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C839E0301CEB47E1BA350AE6CDE807BB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C8DB858DCBE4427CA19FC95E46D103C6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C950F7538D1A402185228383AEE60C82" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_C98C522FC01B44D5970EBC31B95FCFE4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CA02543373D447F8B3E2C544CA97B122" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CB3347D71ED640DD9C8071E8BE50693B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CB65E5CC799546B7955219DAAE0AA9DC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CB6C6FA3B7D54809BF6148B3741134EF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CB9D6377113B44CF8E2345AC6BF1DE90" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CC048A88EB9D4ABC849A93F48E36C952" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CC991A94AFBB47B08D13C709894DCF90" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CCD22597FC2B42F3AC34751411580764" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CD0D1300C88B487CAD7E04E2A7E34C43" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CE23C05B12F5489D80D49B11021A68CD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CE49530C7C05497EAA89F5CCFE934216" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CF71964739C84F05A16D5207060275EB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CFE643C379A64FC3AE2CD23E2D2F69F5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_CFF251B9A0E448EF9DC1F492C1854571" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D00F15F4EEF340309EA04799A0DB388C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D06F117B79164DADA51936E2405D9AE0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D10559A1107F43718503FAED41A57EE6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D11CEFCB96714000B0DA55A5870D6287" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D1FF0706D277464DA9F9FD5BE0519C10" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D216427BA6A345C990A281EC393FDB6C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D2EA924E189C4134B3F6738898223CEF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D2F40D27D4D5482E9EF3866E49DBA52F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D34B18B929744F4ABE62200C7D45CFA6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D36E8BDC47C649FD9617D0A6D7AC6BEE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D37D32CEF4AB40BA8B574271FE31AC5B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D38CF487E50547C4A7BA4E1505094FE4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D3A18E1A4D144D70A6F2241EBFFEC2C2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D45DDB9BC95E46DD99772BBB7E9D9560" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D48F15ED15E74449A5E39ED62B3CDFFB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D4AC3EDE729D4D8C9CE79F3BBF4A0C64" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D4C9319AB3AA4AF3BEE5F92FBD5A4E45" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D5360EBC9ED241A2A644B6CF6529B04B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D558CB15135F433D88F6035244DCEB68" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D58F1D37A97E4C708CAAD0AA4835AD3C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D5A25B4F622C4C4FAC8096B7EEFA5F15" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D5CED9D947C04A19B2F0AE853A4E3A1E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D66C55C5935F4AB79B03B4C00AD0F796" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D6A3CA57C8B54054BC881B683F7DA82B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D70EE948D30C4F86AF2B40C54035E892" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D717157FF96A429EBD907E570F4F2BC0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D773A4CCDBBD4AF5BFE18BC2DC1AC87B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D7F83D314A5247539D7E8246AB6F6A86" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D8763B920D6D46E3AD1B6911EF951B15" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D93F09ED33D649DD84751A2F14898DA7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D94AD6C7B4804825BF99854482A4159F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D970E48380BB47F99441E94A56F62A6F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D97B480C07D844B39CAD227C1EF4B211" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_D9DB1DDB4B344A11887DF8AB3C579A37" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DA31A7B03687476B988805E3DFB3C5DC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DA44B31AF21F443D9C263A16FDA69946" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DB23FA2C15D24D49B624E736F061F420" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DB74BC92EE834DC29A1FC5FBF31A484F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DBB821B3793A46BB81E2CF2B9A19B6AB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DBC90AA5A0FD42C8A89D134FBCF0B15F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DBF5793FB8FE4AC0AEB966FDC7DEE88A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DC405B0582F34181944B53E63C15687F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DCC1BBCD7ED54FF8971DC872AE55C7B3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DCDDCA4564C04930948BD2CB44067A3E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DCF636D15E164C79AE8B74AD2919CC37" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DDD56428DD73444F974D61F9825040B5" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DE1DF054CBB64310807E5A20C2D2467C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DE58A3BDE0904A95911A189BEFC5B524" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DE66DD7DDF4F4F96ABD6C752FEF96FE2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DE7DEFD90AA142F982CC61E7D208D90C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DF35D4CBA48347EC8527CB78B44D97EA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DF443B32252641F688BF2BB51DA32B91" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_DF977ED1A9D84B27B29191B1E1047B4D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E00F0E6EB6714730B47ADA6C126DD397" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E036E1DCACD844D9B32566942128B2F1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E04B04B7A7A9412B959C5912CF5BD600" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E0626408DAE04212B7A5010F753DBEF3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E0D736AF86EA4D5FBF643F5A8F351B4C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E0F743C6A6394781852F6CE29CDC99BE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E11660ECA02941C091C88F1BEBF4B631" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E12B0D5FE8814778B773D37F3D3E6F7E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E1DDAA09A5FD465AB8577C4655CCB033" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E217CA4F66774BA5A09314963FBD6CCA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E26EBAC5B8A0472E82DC9E74A440688D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E2BB419D3B7F4E39AE594DF418F07C45" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E2CFE015582543699346EC288B70E41D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E31F68CF189145C1B8FFFD1148F95198" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E4C946F4DF9444609A09E13D9072C3C6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E4FAC1F2D0C842C3A5B6560FD284FC1B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E579728367CD44EBA04AAF7008C46384" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E58DF4184FB145939D80A4AAC090F421" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E5BFBEC26C6B41DA9D85C4D678B637BF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E5F10C067FFC4F318F8CB2D219EE87F1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E620874F18094CED984F4503FABAF303" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E622F110BE7948158581ABC21B6520E0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E627F06E09E94890A8657BDA806DC45D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E691274B91684CD2864B82DF108BEBB4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E6AD10132AC04F27ACD79BBC321F30EC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E6CF33E4349C478D8C1B381C31A2E09B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E746B80C52C54F2F9B17C580432EEFBA" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E75A3F6B76624E7AB13ECB7AD38250DC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E7864D4A83C04FFE8C5C06B03E11DEDD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E7CFF4924DC546198491DD71E7C5C9A2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E84D0915BD9B403582CBFCFE8B95B646" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E86C074859BF4775A00BD84487CF1275" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E889A14C0D074B379C16DB8CB052A0AF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E89BAA16F29B43F3B85DF8FF73598785" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E8D6C5BCE19D480C8686AA7FF5366EC2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E8E1EB3034AF439B81FC505E88623678" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E969A510B3D54FCB9AC85993634A5792" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E9E737ACC2A846EAB4DA8B8247E4F9B8" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_E9E893DFCBCE4770B1A667EB553233C3" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EA0871A0A6C94CE8B4E5C8256BD07B56" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EB211D0E657248F2A72935961F75758D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EB78E5C4CE8044F1A14092FAE05D6DA0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EC1ADB1DC1104F78A7F2F5520DB23B01" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EC5DA89F78B84B1D8A90F9ED53AD36D0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EC9766A95CC74083A11EAEBF44A688A1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ECC9F626519A414B921A8E234EF0A441" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ECDBD057B2934DB1BD42A1B33E89C357" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ECDF05EBC846419B808DA15EE0F2DAFC" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ED718DE30C0D43B1AB252B3C48074814" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ED891169792044308BA72FF3909914AE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_ED8EB9CCE7D64495894EE5DCBE629CE2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EE6428DBC5BC4BE88A90FC65A1745A29" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EE64372F00AC4267BEEAFCC9C6B58E18" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EE72B3867FE6440CA771E3550E38E396" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EEB9D46E7BE943D7AB48509C26A5C0EF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_EF47B6A3727849DAB2FE32F460BE8FF9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F07AC979B87A44A6971AE4CBB5D149D6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F09566EC6FCE4F82A31A9B0E54E7EDB1" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F0DA6488EAB24633A1F6D3634BC3769A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F0E01DD09B8D47149A4A175506C86B78" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F1140351BFBC4E629BDAF8CE39EDE591" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F11D733F5F124EA3AB8410692487A78B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F12FA89FB33848218ED0FB80A64790DE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F130429E58C6468287355F1E01AFCC4B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F2202E85444340B1B58243D1CE5AE6DF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F231DE5A2FD2486399D07279FE9E9977" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F31DAAA2A03645A7A6D5A86256991A95" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F35AEED69FF14D85906771EF9BE1E9B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F3AC087C60844BA4988566DB48C908C6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F3CD1BD309E34B28AEF60F9FAB278B9E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F40CE2B4AF78406B95630523AC31FFD2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F42AAC8BCDDA4AAEB61AC38E9E441CCF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F45743E0EE0C453B977771467658A7A0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F46B417F426B4A7FA4E56EE2126FC51F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F49FFDC689AB470F896FDB210760C4A6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F4A14191893942AAA5EA1A541CEF3E18" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F519563E51B94B8D91BDFE594EF272A6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F588BEAFF08146F780E0D1410A51FA5B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F58EA264ED0A47CAB5F5B47DEB36D2C4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F5E2A267D3AA495B8296333CCE8171B0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F61055B7AFA94AC0A725D6E7AD0725D0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F61682BC67C44421BC5B219801D9BCEB" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F64F538AB0E1481BB9AC860C911171A6" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F663097F2CCD4CA4B17CC05519AC8C4B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F6BC807749F54132AFC98F6827B8F7BF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F6F178E2FE184A6D8A42C619EA54979F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F75C5CADB5554982A153E0967CD5ECE2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F7619C72DBF2409EB37294746CCCE580" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F7CC215F650944B3A8A5DF21A79CAC48" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F84089B117984EACB3BB401593BD1B6D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F84258958801470AB39943310ED08AA4" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F8D528CC3D51483DBDACE3CB9902880F" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F92D7AC2DD14413384E88CE4B30F09B2" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F95A613A31BA451D99930AB79F14614C" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F9E9C90BDD0F45F6BB9E2735A05B5D20" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_F9F8DEA95B1448F683EE58097C23CDAD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FA6D869BE6E943D0AA0C1306C8234A82" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FAB73043E4B44747B9DB2A6C7BDE20C7" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FACA7D96D56C46339D48D794AD2B266E" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FB33BA37B5664323A82F52A0BAB31996" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FB87560927AC4EF9994BF2E6033BFC37" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FB9702887DD5457782E571E44FEE852A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FBD3810511FC4EE8BEEC600F211EC31D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FBDC94140B404C93B5E6991A4013AA96" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FBEB80FA3394476993339C5BB381BD71" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FC637EBDEAA44A81B8A7DC3B86E7B34A" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FD47CC396F5A4FCEBC4BC3A74BB463DD" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FDB3F3C4DD4B4757B915C4CDCD5CA134" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FDE16188C8F84DD4AA0718B240A13F1B" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FE391EA9A2D741FF8537B937A3757277" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FE449B821B53468E9AEBCFAFA2411C17" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FEA32CC3E67F43218123289C8920DD92" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FEF5A316BA1640CDAD18C911C28FD23D" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FF0FF8FD90F14B63A9CC7CC4D25EC5BF" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FF336FD387BD4B03B2C2120EC5C37AD9" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FF97C0E77765407A8E9B2EBDAA0C3378" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FFA020A1D53A4B4E9658D0BDB393F0F0" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } "Entry" { "MsmKey" = "8:_FFAAEFAB7D684963A4C7532968E26CEE" "OwnerKey" = "8:_UNDEFINED" "MsmSig" = "8:_UNDEFINED" } } "Configurations" { "Debug" { "DisplayName" = "8:Debug" "IsDebugOnly" = "11:TRUE" "IsReleaseOnly" = "11:FALSE" "OutputFilename" = "8:Simutrans.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:3" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" { "Enabled" = "11:TRUE" "PromptEnabled" = "11:TRUE" "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" "Items" { } } } "Release" { "DisplayName" = "8:Release" "IsDebugOnly" = "11:FALSE" "IsReleaseOnly" = "11:TRUE" "OutputFilename" = "8:Simutrans.msi" "PackageFilesAs" = "3:2" "PackageFileSize" = "3:-2147483648" "CabType" = "3:1" "Compression" = "3:2" "SignOutput" = "11:FALSE" "CertificateFile" = "8:" "PrivateKeyFile" = "8:" "TimeStampServer" = "8:" "InstallerBootstrapper" = "3:2" "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" { "Enabled" = "11:TRUE" "PromptEnabled" = "11:TRUE" "PrerequisitesLocation" = "2:1" "Url" = "8:" "ComponentsUrl" = "8:" "Items" { "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" { "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" "ProductCode" = "8:.NETFramework,Version=v4.7.2" } } } } } "Deployable" { "CustomAction" { "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_DCC2599046C94669AED6D40C55F3B615" { "Name" = "8:ProgramDataClear.js" "Condition" = "8:" "Object" = "8:_EF47B6A3727849DAB2FE32F460BE8FF9" "FileType" = "3:3" "InstallAction" = "3:4" "Arguments" = "8:" "EntryPoint" = "8:" "Sequence" = "3:1" "Identifier" = "8:_87FDDA06_4822_4A69_A489_437AD55DCF94" "InstallerClass" = "11:FALSE" "CustomActionData" = "8:" } } "DefaultFeature" { "Name" = "8:DefaultFeature" "Title" = "8:" "Description" = "8:" } "ExternalPersistence" { "LaunchCondition" { } } "File" { "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_003EF520411A46E6AE484162BAEDF263" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_005ECAB11B074C5787B1F8129ACD3DB0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_00978D4D6A334BA58E0D8F5EBDCE7F18" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_00B608AD6C5F4140B9EF5D465B3E947B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_010C9071ED524D8A8DC6A171F492F08E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_01D6A70C8D5048A9BF9BED777F584437" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_029552218B4E868F9CDB0806BE6E9ED2" { "SourcePath" = "8:VCRUNTIME140.dll" "TargetName" = "8:VCRUNTIME140.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_02C7691523EE4C7AAF2C42A5F56C522E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_03030B54657549EEB3FBE9CDD8F47144" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_03294D718D6D4CC89C9CC669C9E3AC45" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_03333F46557E4AA09C3D2EDA7DABEAF8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0387841035034B988BC7744F512624A4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_03C3084D08E640D7A56876BE20147A37" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_05C99C5CC13C41A9885ED5CAAC4E241C" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\09-Simupolitan-Swing.mid" "TargetName" = "8:09-Simupolitan-Swing.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_060F8BEC80784113B5C4D0565C7B9B1F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_06B81764E3B7488D838810FAE42C1829" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\high-contrast-large.tab" "TargetName" = "8:high-contrast-large.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0715F183A84541F5BF5D7BA3BE88E0A3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en.tab" "TargetName" = "8:en.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_07484E10F2A34831B3E6D9052C6B64CE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_079B392C00696F9EFD81A8F4C6CD66E5" { "SourcePath" = "8:api-ms-win-crt-filesystem-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-filesystem-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_07DE11554B2143DB96B5DA78A0720AB9" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\46-House-in-the-station.mid" "TargetName" = "8:46-House-in-the-station.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0819F586738B42CAB30947A5AD8337AA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_081BCF65CEA34B1093E83B88818BB39A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_09BA1EC65CC548038440E1CCEF260625" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_09FE9501B9E54975B984B8C110C56D54" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\15-The-Wayside-Blues.mid" "TargetName" = "8:15-The-Wayside-Blues.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0ACF34CBE28DD32DC79D67B59FA64626" { "SourcePath" = "8:api-ms-win-crt-math-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-math-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0AD370E81C404873BBA9F6C080DE9986" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\10-Easy-driving.mid" "TargetName" = "8:10-Easy-driving.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0B4C01938497473C97E1330B603EDC0F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0B96ED126C9941A0B5862E17EBEAECB3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv.tab" "TargetName" = "8:sv.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0C86FF1A217F45FE9BD380453833B87C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0CC8C3B5975849E7A0674BC5B24FD640" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0D3020DE4E8ED5CC4AC9098B65B48DE7" { "SourcePath" = "8:IMM32.dll" "TargetName" = "8:IMM32.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0DF1600FFBCC494BB4B3A3B41FBD4C45" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0E07641E8CC4496389374E089BCA52E4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0E90A6C737F1457096CEA2E4EBF7F70D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0E9BE20E59D54B6EA446FB9399D2BB1F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0ED6E2E3EA9748478583F98377A57988" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\factory_build.txt" "TargetName" = "8:factory_build.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0F28D5341A894A28A785BEF0499CC2B6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0F9A37FCBB244ABC8A8149D9DF2B8563" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\linedetails.txt" "TargetName" = "8:linedetails.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0FCA3DB968B942E4BF29F988842AC875" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_101DBD56305847DA96CE37AF80AC07A7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn.tab" "TargetName" = "8:cn.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1105F13F49EB413D8862437DEC6BFD64" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\17-The-Benevolent-Dictators-March.mid" "TargetName" = "8:17-The-Benevolent-Dictators-March.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_11193214718A449C82F62145CD8B2C02" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_11DBDBB9ACE64BEEB7549FDAE6CF5500" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1237F66E84B34262BFEDBDB63174DC1E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1237FFECE674421784292D366BC64FA0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1247C8B3EBBD4CF5B1EB76A31014553D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_128F2CA87D9A4682AFD96DF5D4A04141" { "SourcePath" = "8:..\\..\\..\\simutrans\\readme.txt" "TargetName" = "8:readme.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_12AB4359C4B54FCBAC46DA8D834EB09C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_12F07DD4BB194D0891E2C35D9E2AAE00" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1339688690AA43C3A985A46189829DFE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_133D00B493E44429BEA58682323425F9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_13506C78AA494DA6AD4BD5AB7BB66DFD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_13637737D70917BC3CEE9C780E1C321C" { "SourcePath" = "8:api-ms-win-crt-stdio-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-stdio-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_139DA0EE1A894318BFBD62365131B07D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_13CA5808023C4A98B16E6F84BA0007BA" { "SourcePath" = "8:..\\..\\..\\simutrans\\problem_report.txt" "TargetName" = "8:problem_report.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_13EF44563D4C4ADEBB10945AE080BF57" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1440778F3A70472595A747394B138D8C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_159A716BFFBE4242A25D18DA7DF569BE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_15AD3E75D8494309B7E9D38B67792845" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_166AAB6C447F4F14987682E2AE9E49C1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1674AA7C5F1C48E5980265AC6A9165B6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_16B9E22B4A6A439993F94972FB73C067" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\mouse.txt" "TargetName" = "8:mouse.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_17B8C2EA02764F9CB743E2C2035BF903" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\flat.pak" "TargetName" = "8:flat.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_181A6C90E6B7458EAB2292B8BE635C8F" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\prototyper.nut" "TargetName" = "8:prototyper.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_186AA79D5784439EAD1C5E15124C7F7A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_18A83AC11E07457D9E0B0E13BFCC3E79" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\server.txt" "TargetName" = "8:server.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_18BABDE15592474D9AF3C78276D8449D" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\combined_connections.nut" "TargetName" = "8:combined_connections.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_18BADB004C1441909DA8DE66D75CDEBC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_18C933E7D69946F5B947EC8273AEB559" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\citygrowth.txt" "TargetName" = "8:citygrowth.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1918ADD2CE144D709D7289D49A2CAA38" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1965A5D324AA4723A6D357265F9AFFC6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_19A98DC8BB0F44B5B90253ABAAFA14C4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_19BD0EDF53564D459C8A659AD26B22E2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\vehiclelist.txt" "TargetName" = "8:vehiclelist.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1A3B66C3F3284C54AFDC39383717874E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1A52BAD08FFA4CF7A52704515E265E0A" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\41-Libertador.mid" "TargetName" = "8:41-Libertador.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1AAFF255E23343BBB16D3EBC42EFB21C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\privatesign_info.txt" "TargetName" = "8:privatesign_info.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1ABB22A9F34A4486B4D0F7D6A8ED75C9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1B742E6F5F794339B7B00E5090AE41EE" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\27-March-Winds.mid" "TargetName" = "8:27-March-Winds.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1BC8A4B2533D4A9B81A8D906E75CC892" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1D713659992B4EEB89199A782FF15A97" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\password.txt" "TargetName" = "8:password.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1DC828055A404A2C90A33E0062965415" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\industry_manager.nut" "TargetName" = "8:industry_manager.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1DF38A11E5C74DB9A741FC9C10A3634A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1E30A8FD30C344B29F0C9B8BADAF36B4" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\new_scenario_template.nut" "TargetName" = "8:new_scenario_template.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1E43FD6B874142DCB7A19BFB907DC4E6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1ECF0A79127649D4A462C15FE8EBDD52" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\industry_connection_planner.nut" "TargetName" = "8:industry_connection_planner.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1F78A7C6DB6849A1A3352CC3B935FBBA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1FF22B3CBBD34BDDA475ABCE7E8458FB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_20AF94701C3B4F31BE18E4C18593C65F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_216D641690CC4689BADF94365FA2B97A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_219E1B7730EC46EAA280143D520AE19C" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\28-Road-to-Warm-Places.mid" "TargetName" = "8:28-Road-to-Warm-Places.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_21AA11BC689E42B6B6697A5FC318E096" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\et.tab" "TargetName" = "8:et.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_21AED397D928464F813731B7A635A8E8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_21C491A79E964383BBEBAFB16263BCC0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_22571262D0E1464AB1C4D661D729A7B2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_226BCA5FDA2B4579857D5F4C3AF3A482" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt.tab" "TargetName" = "8:pt.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_230AC91992494E47953EE25EC0732E52" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2310BE29D51D4698A0E4D57439C7CF4D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_24C7BC64F7BD4CE4B1EC004A5BF37584" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_24D43BA152AF47719E58C99043546C39" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_25565CC3AFA2488FA09185A4D3536AF2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_257608DA64F7495383410A50CD623626" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2580742A58474754BB9F6E8DAF113625" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\industry_connection_planner.nut" "TargetName" = "8:industry_connection_planner.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_25E373020643480BA2C6C4FE1967DF39" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2688604BC1004159AC65DA8026AAF404" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2692FE4659B3459FACB55B2ABABCEF3B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_26F725E6689A4B47B5225B9F9A6C4CB2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_280DE28E23F3432A8CDB55AB067712D2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2820718EDD1A4C0A998A555B73E7941F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_289828740CCF4491AEAE9923ABC9E630" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_28D87BD82DD242048CE3AAB274E4F224" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\station_manager.nut" "TargetName" = "8:station_manager.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_28E16D55A93A44CAA25DB060E24E199F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\password.txt" "TargetName" = "8:password.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_290A6460DE03485A9ECA056C13AB547A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29ACEC7A06E24A1DAC101B2DBFFD8054" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29CD1E15907F4CE2B442E61E72296DE1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\signals.txt" "TargetName" = "8:signals.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29E0B719E1D143A3B435F746D294CA48" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29E3ABF203C04D2E8FF9FB6AE98967C1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_29E5E12EC22646BAAEDE11AE02DC2C61" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2A7AE2771A914BA7BBDEA452C9DCF2F3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2B5B075BE23041988B08F61EF1DE74AA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2B6156C249D14E63834D6BB3CAB3FF16" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu.tab" "TargetName" = "8:hu.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2BB109D12B614A65BEE199658898234C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2D6E5C7AE3F64AC7ACE938CB8ACD252D" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\52-Dreamy-Oriental-Nights.mid" "TargetName" = "8:52-Dreamy-Oriental-Nights.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2D94FF39A27543EB95167C67429CF990" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2DAFA0293AE04710AD9F7E863F3BDCD4" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\38-positive-thrill.mid" "TargetName" = "8:38-positive-thrill.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2E231200DCCF424DBB14BCE8FE6D93BA" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\43-Driving-on-the-midnight-highway.mid" "TargetName" = "8:43-Driving-on-the-midnight-highway.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2E8428F464504F4CB245EFD3D16D3342" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\privatesign_info.txt" "TargetName" = "8:privatesign_info.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2F1E496588C3496D8E4F6B8FEC90DF9A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2F4938DE7AA34B87B0D997F896311B0D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2F8D3E0ECE694AEDA82C5432F24C854E" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\music.tab" "TargetName" = "8:music.tab" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2FB0C916FA6E4D568517572F31975178" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_301A99763E6F471B96D9FCB200CE960B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\lt.tab" "TargetName" = "8:lt.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3048CD4420B04A098D932C7011C16F75" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3067D12B03BD409DBED5BBA78761E959" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\11-Stucked-Convoi.mid" "TargetName" = "8:11-Stucked-Convoi.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3075C6BC47214728B90B6AFC317EED62" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_311BBAC6B2C346929B78EDDCEAA25F52" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_314549B8854B4E04A7B69C5A1151519B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3156DFEDDFFA4625949A11A1B0F470A6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3179D684E9B144B78C3AF7E94102521C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_318FE10CEE38456B8FC8241021019358" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\road_connector.nut" "TargetName" = "8:road_connector.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3194957A2F144B9DBB90D04D1202A0D5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_31BAA09A108D4F8D9457940B5856273C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_31D813A3C334427AA33385173447DCE6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro.tab" "TargetName" = "8:ro.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_31DEDBED22EE4A4DA099BD028FB246A3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_31F6E25224B744DCBFC0141E79D10A60" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_323064989CF245F393B3FFED1FE07884" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3233EF6351004F93B9715A0A7AE4FA74" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_327F373C1E7413799B0AED3AF56713C3" { "SourcePath" = "8:api-ms-win-crt-string-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-string-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_33296DAD659B4BD39798C705F02C7834" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\44-Above-the-sky.mid" "TargetName" = "8:44-Above-the-sky.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_33BD05ADB1C64EC8966999E905C33C9F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3487ABD4F8B94084913A128F4AB191A1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_34A049B6090F498E8A74F7782E6AC542" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_34BB38CFC48E42209DA5AF5500F6D2BA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_34DE603A33A04466AC350B9AC8D6A0A9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_34FE77A5FD59404B8CDD5D21FB0AC148" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3519CCFB2AEC4E349CCCFD738C500238" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it.tab" "TargetName" = "8:it.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_352D3120C5B04626B12EE20AC398F144" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh.tab" "TargetName" = "8:zh.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3530E1B1A1844BDB81256561E663927F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_354005FEB66444AB84E610AE09EF0FE8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_364C50343A8945B59522EB0EA95F7370" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_36993815822640F6AFC910D125044DD4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3718F392451E49C8A03D48167AFFC98B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3721799D17B548DD91B4A37F71B2EA78" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_37605F6B6AC74871B93AF782EC31EA68" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_37666D0AB6CD430A955269F7E1CB6676" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de.tab" "TargetName" = "8:de.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_37D5EE6E06794EFDBED006661DB3CE03" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_37F86EBD13864C7986A4D05594E9C7E2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_38252595EA444B1DA8102684564FF3EE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_382A9A025A4C40BFBA389633BCC7465F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_38690161FBE14CB8B378D3A573CCF35F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_38935C206D864F57B6900428D9DB774F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_39EE9887C474434CB0593872C88614C0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\signals.txt" "TargetName" = "8:signals.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3A3A98EBEADD4475AE7E4F2154758DFA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ru\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_6AA7E18DFDC74EFF82A4CC967B14F3F2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3A45C9EEAB5F4D41A9EF96EB0F70FE98" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3A4F1A9658FA4B0E805DFEAFA9B5C2EB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3B4AB35D4B814E49B374573FD9B41D9E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3BB85C849F4A45ED984521EF7EC00FF1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3BF8D681CD3B4B87B032DCF3C00FF926" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3C1CB9531BCD4293980FEBED7E010E28" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3C5211F08FDE4E4490BD5AF66C9A0EEF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3CA70B6D5F48488CA38489C0EC76229E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ru\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_6AA7E18DFDC74EFF82A4CC967B14F3F2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3CACB35ECE044CABAF73B3AF522C618B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3D42F41E95F74301B3DA30722D7F4D74" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3D6D0B1545684FB685D35EE557CBB335" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3D996E275F02498B99D4B122817672CD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\uk\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_789838269269425EB5ACB92A794015C0" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3DCFF913F03C4FD48D362C46015CBA63" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3E2C5CEFA60D4DF59BC3A743C2073EE6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3E51AC108118479CA3F94EE04D6F01C0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3E5E32603E444A4BB9392F2DBAA25BF9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3EE1A722BEDA4ED7A2ACC4BEC7F4C4B8" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\05-Boring-afternoon.mid" "TargetName" = "8:05-Boring-afternoon.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3EF0959343750F1BB1E3683C3BB95052" { "SourcePath" = "8:IPHLPAPI.DLL" "TargetName" = "8:IPHLPAPI.DLL" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3F165DBD8D454BECB94AB3737DBE82C7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3F16D51E7A964A99A35D575CB10B1C2B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3F1AC2D8D7DD4F49B318E45AD0000E4E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3F3BE766613F4BF29D52703C4C0D0427" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\ai_base.nut" "TargetName" = "8:ai_base.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3FD7E53C07E241C3BCD00B81C59CC66E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4057B27E9E494E8CBB7D1FC8FA3EACA2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr.tab" "TargetName" = "8:hr.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_407A3BB3FFB14445B01632174D68B032" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_40A0BE0449894903AA520D9BB5D5EA6F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_40BBCF7041234B0E91AAC36E71B548FF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_40F016A1CD6F4489B117B3264DD98F90" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4147D6D1F8A245C4AAC7DA2E72741900" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_41600A65D8804208854E48546CE03C31" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_41DFF372121244008F06B6CFE66D65DC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_422F124DFC564135884EE030F8A75A7E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4263D1383F6141CC8FB85D9C89A37DB8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_433B0BB603EE49AFBE61E4A95B62F025" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_43B4F064B408462B9CFF09DAF89256DA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_43E4EBE3CF4C483F9B9C3B22FBF18EE7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_448B7A877DFE4EE7BCCC10E684A9F9B6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_45907458AB0F4F9BB5167B3C22912220" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\13-Stephenson-blues.mid" "TargetName" = "8:13-Stephenson-blues.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_45C20A6E3143435AA6855758F2D9E540" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_45F7C42A57FE478FBEC1428DE3C17C67" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\high-contrast.tab" "TargetName" = "8:high-contrast.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46264B5F868B4521855C85BD897A8A84" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46456885516B4B789AE75E836C9C05E8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_465C2BCA0E3B44E98A0C2EA624307C51" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\astar.nut" "TargetName" = "8:astar.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_467B5D314942411D8AE3142D49E698C0" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\placefinder.nut" "TargetName" = "8:placefinder.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_467BE99BEC444EB28162927D6652266A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46B75EC9AE974FA390E7CAC4D35F7919" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46F68A58A67F2A54B4325EB94650EE7D" { "SourcePath" = "8:api-ms-win-crt-locale-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-locale-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_47293CF4BAF54E8CA44A9AB83AB3CB19" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\be.tab" "TargetName" = "8:be.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_47CFC2CBCF804F13AD453C25372C8730" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\translate_users.txt" "TargetName" = "8:translate_users.txt" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_482768525BE34C6BBB46DB7ADBB779B0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_487490D85D3845FDA7F0C9B3FAB37393" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_490DF7497FD3469186609337C624758B" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\20-Last-Trip.mid" "TargetName" = "8:20-Last-Trip.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_49B9EB5E83934E4B8E4B0B9339FB5FAD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_49CD0D1D118547D3BE550596B2889432" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_49E3C49389E64767AEF91244E450BCF5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4A24E208D93D4E83B56C55A98B427CA4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4A85838D1D85427897D4F69693279715" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4A8CB7B7A27B416E8D5F16F16414DAB5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4AD08276500247AB8FAC3EF4B77F267D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4AD33819C37B42B1B0B339CE718E5CDE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4AF573D713344BED9E783ECD4C1284E9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\bridges.txt" "TargetName" = "8:bridges.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4B6BF260CCD642F6AC9015FD883DC989" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4BB786F99376461988413CF1A585AED9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4BDEF13001284819BC75A57512F7E7CE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4BED95EEB2484DBD9257998035AE6209" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4CC13851778543C889504D03B5927C2E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4D3B4F373E4548D6882E71F29ADD2774" { "SourcePath" = "8:..\\..\\..\\simutrans\\change_request.txt" "TargetName" = "8:change_request.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4D4A63AD27BF461C917A7C7A92F3A084" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4D611D172DB94EF8B7C138B581301576" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4DB844664FE94090BEFB466C6763B36D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4F58BA38FA2541B58E8C52828A5272CA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4F774CD205E24CF4BE96227A527C8539" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\id.tab" "TargetName" = "8:id.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_502FAC792C1D8614FE7926131D186D21" { "SourcePath" = "8:api-ms-win-crt-environment-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-environment-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5078896E10A44B0E8322B5B2DD9ABDB2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_50DE5B28CD594DE7B5F13CFEE25C43E8" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\ship_connector.nut" "TargetName" = "8:ship_connector.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_50E96DDE2E454243BFC25EE2D771B7F7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_512BCD1EA02040ED9BEEC446FC50AF1C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5140C10690D54348A4368EE02676B691" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_519DFBFE15F34747A61A95E2B9B10BA8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_51B4379EA7764F718E23148EC7F180AB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_51EDC323F02149719E5DF86E69F1BE72" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_51EFF26BEAF246629A4975AEA01A1470" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_522CEDAB5F5347408C153DCEC08D1B91" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\prop-latin2.fnt" "TargetName" = "8:prop-latin2.fnt" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5241ACC17B5C411280903A620FE31CDE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5264B3188A1F41E895A034ACBCE23609" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\08-The-journey-home.mid" "TargetName" = "8:08-The-journey-home.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_529822798EDE4A6EB66A8FBC79D28466" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl.tab" "TargetName" = "8:nl.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_529ED68FA8504A2596F83E3452215DF3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_52EB158E737145259F9D9B99E3A0DC77" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5358F97ED18A0C27CFFFA550621C549F" { "SourcePath" = "8:SETUPAPI.dll" "TargetName" = "8:SETUPAPI.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_539D40508C6E4E75A11EFBBB82E0CF8C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_54BDE901C9354D4294895144769BACD8" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\16-Midnight-Express2.mid" "TargetName" = "8:16-Midnight-Express2.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_54C84BAA19B04F939D0E0367B7F17DB5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko.tab" "TargetName" = "8:ko.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_55455C91BDFA4715B97E7CE7754928E9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_55A356B6F2BD48BAB0EE1DC4089CCC6A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_55B15CA598B04AC8AA57ABA39B5737D6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_55F557FF2D5F4FF8B4B841480F8E02EC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_561E7344F2D3457184C0231FFA8E0D63" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk.tab" "TargetName" = "8:dk.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5649E800E882443DBFA060EF7C6D0C54" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5713DA04E2164ED6A58DF2872113A1E1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5722A6A9D28D4A048CA3FF4C5C399AA9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_575341B1DC7743458EEA436605782806" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_57969C68E2AC43A8A53EA72F3B6933F2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_58059A5FD7D842D4A019A4BDB501153B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_583AF0963D3F49819D420B80764536CA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_584B82F1837D4263B9287A526B252157" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_585E548884E1A0024245C4DBE90F6893" { "SourcePath" = "8:MSVCP140.dll" "TargetName" = "8:MSVCP140.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_58ADEBE3020643D893F8EAF29C412F0E" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\29-Runaway.mid" "TargetName" = "8:29-Runaway.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_59052B74FB614B939DD6A4414515B755" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\ai.nut" "TargetName" = "8:ai.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5977CE44BF2F4CE3B66EBC2E9BF91AA5" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\32-incidental-skies.mid" "TargetName" = "8:32-incidental-skies.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_59E2DDBD34F64EFCA5911828555E70E6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_59F7612898734E4DBD36DF9E76F2C256" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5A61100119004DE0A914F075B53697B3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5A8A8FF3CC8D4B3595A9DAE1150F703D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5ADFCBEBD3DA466287FAE7D8B02A2907" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5AFC05EFA72649698E65D01DC3A85278" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\readme" "TargetName" = "8:readme" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5B4BF2BFF84142708C9EA8FC67DB3216" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5B73D425BB464648BD3F6C58AE543014" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5C6AC9E04FE740A4B6E9ECBA0CB93F7F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5C6F45BB13064E52829F43B6FFE00220" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\24-needlessly-striking.mid" "TargetName" = "8:24-needlessly-striking.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5C9630709CED41D2929492FD463827D1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5CD15C85FBF94FBB9AD95AA7490A45F0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5D9D568EFEE54B5A8A2A88644C400E6E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5D9F5328272845C3B2E2857D1BF93E74" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5DB6AF2EEFA24BABAB9B45BCEE62029D" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\36-faded-things.mid" "TargetName" = "8:36-faded-things.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5E76DC3AD0814F04A545A862CD5E7DCF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5E82840C0671457C8E5FECF7032D190B" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\40-alternative.mid" "TargetName" = "8:40-alternative.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5ECEAB174780441CB6657A851C694B5A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5FEE0DDA9A2847CB9FBD5EA59EECF525" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\placefinder.nut" "TargetName" = "8:placefinder.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_604DDCD3A6294FEC9A6F72485DC08DAE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_61DEAD687F5A42A9A3CE05CF43194861" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6216B709025B45618D3CE7D60D744328" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_623197F7D11B48FEB04D649E84458841" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_62697F60BD184B3F85EF352882FF0FC6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_630392339F2C48718E8D505AE3524178" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_63090592FEF84404865D0F30FF65D3D0" { "SourcePath" = "8:..\\..\\..\\simutrans\\history.txt" "TargetName" = "8:history.txt" "Tag" = "8:" "Folder" = "8:_A5BC29A726E64EB18DA057FAEE2DD996" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_63254E53870241DEBABF85CC64023D1B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6335879001C8412CA64A127760C570A0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6336B3E3BB544A79B2748CFB446ECFB9" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\12-Steamin-across-the-prairies.mid" "TargetName" = "8:12-Steamin-across-the-prairies.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_639BCC27C4264E149D85E7E705C52710" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\03-Sunday-drivers.mid" "TargetName" = "8:03-Sunday-drivers.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_63A60E70A6274498A49DD55849187C7F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_63AB0309FFF146E5B9A8BA431BEDB581" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_641F8E28A18740EE9672DF14F4322517" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\basic.nut" "TargetName" = "8:basic.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_644E9138F1B04425AF2CA49C8C1029A9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\tr\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_DD9701F195AA4B3D96975B01836C5F7F" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_647D7C02726B43339F93308CE7419FC1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_65634BC992FA494598EA6E6C025512A5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_65CB95D1DE44480EA45158A755AE64BD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_65F46B0D45B646C4BDBB84B11FC74881" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_66A93844669E4AB8AFD7960F553D67E3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6702CB4A485E4C3C9B1970AC9D77FFD0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_67073B82D78742E5B9F3A6D364AF649D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\uk.tab" "TargetName" = "8:uk.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6723BFD2968F488A8B21778707DD42A0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6734839905EF4389AC62192A95B835D0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_675B1F5C00FF4877883A37F4EBE1E3F5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_677C07C6147A43449F9AF59CAA3DE045" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_678A6CC7CDBE4341A42A0D8FA05D8A80" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_67C77B7A81734DCD93763CAFDB731F3D" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\Prop-Latin1.bdf" "TargetName" = "8:Prop-Latin1.bdf" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_692C781C1C4944E3918865C3016F9231" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_695F9E0D19A94E9080FCF6161EBF07D9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_698D6BCBB25E43D6B7AA5EAA8898E4C0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\mainmenu.txt" "TargetName" = "8:mainmenu.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_69A7859F453A4A91B8E1B6F8EE0E3623" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6A45AA5600B54C83989EF933E7D81F00" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6A709C49B7F943C691E029483C259726" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6A7B7E930C944000864ED2DC074B8944" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6A8F2A7B2D0E46B7BD05ED75ABEC07C0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6AC4A1E5DC494E24B5BCEF7E92D36816" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6AE881EFF6E147EF97DE619B22172E27" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6B365598BC624617B2B10FB965E239DE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6B5218A02D434B9BA80C49C643184341" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6B7612CAB6554AF286B04C35DA865321" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\server.txt" "TargetName" = "8:server.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6C3CF89286EC42DAB9EF964252360D33" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6C7F90DDF17D4C6293C647A90E00E279" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\combined_connections.nut" "TargetName" = "8:combined_connections.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6C945BE71CFF4E82B4F0DFB72C292BFA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\no.tab" "TargetName" = "8:no.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6D01F4293A064FF2A6A6CC0F0398D328" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6D5F0504040C42649AAF5C80A6C93AF3" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\48-Techno-movement.mid" "TargetName" = "8:48-Techno-movement.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6D66B32FEBB94455B6BFEE30846CF33A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6D7ECB4FFD0B48E7A13074F90688F225" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\ai.nut" "TargetName" = "8:ai.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6DCA48436F4847F5B3F327EE350E3AB1" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\23-Something-for-Silver-Sand.mid" "TargetName" = "8:23-Something-for-Silver-Sand.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6DCDE0BC21E54EEFBF9CFE05BEACF621" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6E5DAC8084104079B655A2FCAFAB3CC2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6EA80C01AAEF49228558822219AF7ECD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk.tab" "TargetName" = "8:sk.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6EAD4002E15B498AA04B7DFB144B3917" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\31-Courtenay-Bridge.mid" "TargetName" = "8:31-Courtenay-Bridge.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6EC63EB0D6364EC391551F261C4E34AF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ru\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_6AA7E18DFDC74EFF82A4CC967B14F3F2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6EEAFD65E9A14B65A1FD6C694AAEF48D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6F75DDB2EDC24C53BFFB2A4CBDCE7D32" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_707C1BE3EF9242BE9746771AB5B6E60A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_71225218E6B24F409FAF954309A5F4FE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_71C350E8A9B4499694F7F9CCF037A2F7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7243A246D6454771A7F203730142ECF8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\password.txt" "TargetName" = "8:password.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_72ADF54DF3BB4CB495E986114E1E2DF4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_72B1848015A8405BB280F12F7FE44143" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\server.txt" "TargetName" = "8:server.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_74126279572F497EAE3334BC10BD9420" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_74CF407282A64494B3743E844FA0B38A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_74ED0456E40947CA92C62824E4125894" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\26-Tantalizingly-Unusual.mid" "TargetName" = "8:26-Tantalizingly-Unusual.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_751BF54EFC91407790B42AD4A75C158E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_75982E571A6F4F2A8349D07115881603" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\tool_base.nut" "TargetName" = "8:tool_base.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_75DB0F22A99B487FBCBF4492787CF16F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_760A7DFAB6A846738F456A2D9B75DF42" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_761869FA0B4342EE977F57311DB8CBCB" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\50-Snowy-Road.mid" "TargetName" = "8:50-Snowy-Road.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7627C3286ECB4901B7FF66783A56EAA0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_76DB0BE795FC4B5BB8D0D0A037368A67" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_76E349042CB043F2809E4858A2D9A63C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_776CD7D0F5E84BBAB5A8563DE24D69BB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_777C23F3C78F43E196CF3E5471716A92" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_77AA9368DC924035A400D7A741A3B134" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ru.tab" "TargetName" = "8:ru.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_782A3C3B9FD34371BE3AEA0EEBFECC02" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7879F46087224474AEC649E7FB71EAEE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_78FC1DE773244F7AB6CEEE32A6997506" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_791BD97D0CD441D4AB0F2291EA64362D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7A4B68C765954A77AEBA8D340DE2310D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7A873BCA0E874A5C9AA964C4EED19DBC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7AD1BF4E17F04C1485967C5A664A4E0F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7B480D9F16C7409B8547DF976679CE18" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7BC9AACD90A04AD8BA6AECA487E9DCFB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7C175A1D24E94CD485688A2AE69E37F7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7C4ED6D1255C4087B67B059046DE362C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7D2FFB8DE5D246819C5152D280523C44" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7DE009E5FC2F487FA3A2EB121E49D0F9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7E1AB3235A184CDEA7ED5DAEF4C8CF96" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7E2C2656F54F4DBCAE3C5FD9AB651368" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7E5C15BD3D26417698877173773F3DBC" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\51-Summer-Intersection.mid" "TargetName" = "8:51-Summer-Intersection.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F01371C7C884AA79D7B332DFE9CFB87" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F01AB5E57414138829BC412322FD334" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F1DC34C3220499EA78996207F8A9F18" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F275CAC05284C2BAF4B234E294A98AE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F473696C8894F5C827D4B1AF4EC61DA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F5E16592EE74DB2AD2B8D96120CA325" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7F86529E598F451A91EDB4A9DF245431" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7FB25388690E4F35810256E3806D7AC7" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\m+10r.bdf" "TargetName" = "8:m+10r.bdf" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_802286B2E6AD4D5EA5F7582550D0192B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_80718F22412647C49DC0084C574E72BB" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\themes.tab" "TargetName" = "8:themes.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8079B5223A464AD483F0B286A55B7CA1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_808B71735EB742128850F708235AEBB0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_80B5D3C38CAC465BA8C2550F7914F614" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_80E9BB86DA4D40C29497E5182B73AE5C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_81301366B3184A6FB5E40F909CF6AD26" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_813B3C3F7F724EB4BA5EAE500DBD41C9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8183844A6C6347D9BE1A8F17A5EDC446" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_81A24FF94CDC4E40852AA1F5B3802088" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_822E7AE56ADE4E36A4E2E5B00138756D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_825A92662B9B4407950D37C0CDB8F119" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_82C60047E4034EDE9C5AD03F08662F10" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_83189152D1FE45048CECC4A9991BFE56" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_835E8828F7DF417BF90CE0E5B3ED79A8" { "SourcePath" = "8:api-ms-win-crt-heap-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-heap-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_83A75CB51DCC4F87B8B9A3F8A3A215F6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_83C4B947AB2D43A09248D150A192DBF5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_846C24B81FCA43DC933E9BFA18FAE15E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_84CC521B95224F7383B53352F9151899" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_84CEE7DB1C0B407EABB654B361525004" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_85337AECC7CC496DAE6643D82A1E3F60" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\uk\\bridges.txt" "TargetName" = "8:bridges.txt" "Tag" = "8:" "Folder" = "8:_789838269269425EB5ACB92A794015C0" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_85CE5B3A65CD4D95AB6E6665907FB16B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_861479A1366940A2A130D6D3735A7D16" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_863731CD1BFC40B393D50C392C7916BD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8749AF65C301480F9E7A596349DD1367" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_879DA4798F1F4B11B5C99669556CC5B5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_87AA9DF095B146D986B7BED6B55017BE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_87E970659D104ACDA574ABA4AE56A153" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_882138DA00E9460F86B35552856298D2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_88A3256281AC4F25AAE598C1481FA990" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_88C0513F233B4CB4BB2CB756347E75F2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_88CEDD14A00441AFABAAA66D3806D822" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_89563EA02AAD48DCBD9CCFC5B5EB7A95" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\factory_build.txt" "TargetName" = "8:factory_build.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8959E24FC0CD434A8A27A073FDEC71E2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja.tab" "TargetName" = "8:ja.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_899749C5350C4225A5C30A5D6948EFDD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_899F7FB3E2F84E6A99128E5AABF039C2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_89A41FCA30A346A3A5D38B4DE2892768" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_89B354D3105949B1BF654E7853FC7F29" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8A0AA6D0C786436E93BD790C69FC2AFF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8A35DF083E7D481F94A22CB3A0CF9A71" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8AE1E9F65C8340A4B7B931321BC783FA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B1C110612BFB297E730E7DC8AC24F63" { "SourcePath" = "8:VERSION.dll" "TargetName" = "8:VERSION.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B37931EDEBB4DBB82D4D794F46F4C4A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B88D692BFF14DE5890C554BD2597CC1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B98EC4380664715AFED6BEF0777940C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8C55EDABC5B542B88FF7074E4E99A08C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8CA32EF48C9640E9B151FC50FD50DA58" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8CEB3078E8C9419588372AA47D36A472" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8D341EE4712F4242AF051C6559BAD35A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8D9FE449D76947338601A9EF5EFEFC94" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8DC1AD7B4B434F15B3326D669B5925A5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E07E467482344D8AC909E3F8F08B953" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E1348361EB141EB80B348E2BA434EC1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E2B0BCBB33945F9AD9D4A62B729FCBF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E77D1CDBDC548E9BC92AC3E05BF156E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8F60949CD512455AB188852FB8723732" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\mainmenu.txt" "TargetName" = "8:mainmenu.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8FC094660CBC4042BFA3CE7638801FCD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_90088DD7694749FD97D2DDE8DDC76779" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9012A62701DB4225BA55AC67F1B5A4D5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_903B35BF02DC4724854FBA8A693E7BDD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_907BB93A2A584C53B4A2808085BE7D63" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9093B505D80E44A88C5B422CF39C3F6B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_90F5B235E42C4301A5E0BE03B752C5D6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9196381DF8F04BECB29CB3A4EB358118" { "SourcePath" = "8:..\\..\\..\\simutrans\\thanks.txt" "TargetName" = "8:thanks.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_91CCEF23F60240989740162A20FFF3F6" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\37-inevitably-engrossed.mid" "TargetName" = "8:37-inevitably-engrossed.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93076B17FB6342D9A680D2DB5CB88911" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93553371BA0D4BA7AF534632AB28AF1C" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\18-Ride-that-train.mid" "TargetName" = "8:18-Ride-that-train.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_935E39838EEA4F03A10A26790A4CCE11" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\classic.tab" "TargetName" = "8:classic.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_939311F03E484FD2894C70B30E575E58" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ru\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_6AA7E18DFDC74EFF82A4CC967B14F3F2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93E45578B9A84ACF886B916820BC4D5C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93FF28B992E344FDA54C83E61D5DE45B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9413D0887CEA4CEF8E077401A528CF8E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9494DEF39F564D128A2A1D77C94B41B3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_94C3E9F789844176B1A29257B7F54F25" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9512546582D04B0BA8B1EB90C25F266C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_95DBA15EEC0F44B98B81C3ACFA4A5A78" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_97AC8B571A7744588E1B5F4DD29926FB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_97B9A460977F4B43A3F262ED3C9AF963" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_97D429291A1A4B448DEDAC39AC789CF6" { "SourcePath" = "8:..\\..\\..\\simutrans\\license.txt" "TargetName" = "8:license.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_982663C4E3A74AF98D1614ECF1222641" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_996EB12093BD4A92A9C8C5D7A3938DED" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_99F1C1D67C9F422685E2764F4D5E13E3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9A1181B0105A4B8F839A9E88FFA0580E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\zh\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_A9D6B01652F44EEEBB95F40DFA558141" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9A214C6687884ED5AE39CB9809B715B0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ca.tab" "TargetName" = "8:ca.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9A88343020324D73A521C5512E5801C7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9B24FA4B5DF145758D44C5A386E1DFFF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9B45AF680D7B453183740CCC5186F98C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9B669C48C940449882D6A2D67A5396ED" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9B97A924FE8546D488A68B2055F6DEAB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9BAE51D35D6A4608B5DEDE105547B06D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl.tab" "TargetName" = "8:pl.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9C3079C5132A47CA8F7095A52DE30568" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9C8885FA8EFF45EA9CA498CAAAF4D24B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9D2AE5121BA64CFE91973505C47CF36C" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\readme.txt" "TargetName" = "8:readme.txt" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9E3176E32D8A4094A57AB6B64B17DD9B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9E747D5708814DCA9BFAD71B7650A582" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9F43E9CB3E4642B384FAE24279AB317C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9F5B93603D5E4002AB90693F485FDD9E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9F82245E13B84479A19ABB0517AFAE74" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9FD82999B19B434586CA9147504F6B69" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A00BAB251762400FBFDB3F5F9DC7CC7F" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\prototyper.nut" "TargetName" = "8:prototyper.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A054E4EACE3C4ED0A06A7A05E9EBC6CD" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\aero.tab" "TargetName" = "8:aero.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A0774C119AFD4A54AB9DEFCD892EF3EA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A0EF7ECB8D1A450790401A38455F2FBC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A110420164074F6F80B1CCA1970AAAAF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\vehiclelist.txt" "TargetName" = "8:vehiclelist.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A12A3E89B73A4D3FB21673D41DA88E76" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A13E8EA5CEB54C88BB30C6725F581FFF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A1A46558136D4B6E95B80C55A3FA5629" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A1C5832E423B46709ED06E8882B8DBD9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A1F00F4A0643448DAC8E66CF0727F09E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A2611C5487D241FF8B561E52D56B160C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A2A0A247DEBE4C00A67DE0C78793BDF3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\id\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_A26968E6884145E79C521F92E05DD14C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A2B299E62D304A90BC01839FD9982CEA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A2C5C7638B7B423796BDDE1B37CC54DB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fi.tab" "TargetName" = "8:fi.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A3F9D5A01ECF47CF818A94DB7E3F30BD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A40DB08E389B4ED2A1FCD744FB4D5FC0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A438B857F43A4B91BADAD3D54FE069CF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\th.tab" "TargetName" = "8:th.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A43ADD711918462F861281E4F45A3ED1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A46752F3A99348CCBCF9C33416BE5DDA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A4B5359306A34023A1ACFCD33C9B6B16" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A4C415F986314D75820B3ADD15F324DC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A4D653ABEC4646799283098724AAADB0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A51036CBD78E4C6CBB96191773FE82EE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\citygrowth.txt" "TargetName" = "8:citygrowth.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A588D7D5733E64B36617EBE50FB31F3F" { "SourcePath" = "8:api-ms-win-crt-convert-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-convert-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A6644507B63B49799F05083DA240574B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A6A9C9BDA5A64E4DAF67877AAFA1F7E7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A6B3B56E517742D49D7AC896AB575EEA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A6EF70389C70472A8E4E4813A6CE44D3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A6FB275BE7D44AE2A24847C98A708103" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A766C5646A994F18811DC5D915ED99E1" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\modern-large.pak" "TargetName" = "8:modern-large.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A779E5A5C75B4577A215A6927870BB62" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A77D989F8A3F4AA52521E174DDF6EDFD" { "SourcePath" = "8:api-ms-win-crt-runtime-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-runtime-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A7B5A28B66FC487D9ACCAA1A42521224" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A7F06B6F1E2744E8B7803429C9B12AFC" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\scenario_base.nut" "TargetName" = "8:scenario_base.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A83F1194CD164AAA847A140EE8589B87" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A8778490948047EA9E74C817CFBE23C4" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\53-Where-Thomassons-Lie.mid" "TargetName" = "8:53-Where-Thomassons-Lie.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A9C9120ABBFE446E8CCA925945456C1F" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\classic-large.tab" "TargetName" = "8:classic-large.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AA1E6DC2B3FC4067ADCECCDA4B09C94B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\id\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_A26968E6884145E79C521F92E05DD14C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AA7A085BD36949179AF2196EB06CF7DF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AB7122076A2045E9A16367FAA2603934" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ABACE35D95144B839016535CE2C649AB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ABF7BAE834ED471AAC122B3BA17D4C73" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AC22050E398241C29F0A0AA66AD69C26" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AD63432954AB432DA360A092F3ABAFD4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\mouse.txt" "TargetName" = "8:mouse.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ADC52D4B09A046849FEC19C6ECFAA4A5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AE10E8B948F646FC960CEA7D158BE1A3" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\theme-large.tab" "TargetName" = "8:theme-large.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AE3624817F3F4EC2BC9ECCC528D96588" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AE43098A1E4D43D29FDAEF89B96A61AF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\bridges.txt" "TargetName" = "8:bridges.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AEE0681E6B8448B4988AB3F8BDB95FD4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AF1BDC5479324EDEB012F7C64C02297C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_AF20A26E81F541948829FB5AFDE66541" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\flat-skin-large.tab" "TargetName" = "8:flat-skin-large.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0115B9715024672A9C1FA4CF0465956" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0174050546944A19CF028E1DE44908C" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\classic.pak" "TargetName" = "8:classic.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B038F7BAA7974FE0A200AF565B96E33F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B0F23AB72E7A44AE854EE09E4BEFBC66" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B1094D229AD5442EAB76FC665782E076" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\33-Journey-to-times-gone-by.mid" "TargetName" = "8:33-Journey-to-times-gone-by.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B12A038D1C9049108A3667AE89A7D7F7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B18F2A9BB0514708B11E2E262F7D8610" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B1AA4D786277439581E192B8982152A6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B1E1D7D3CD6D49689CED7E882E2FB5F5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B257E8B4219C4B298174488F5BCB7653" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B2EB2EFA27E54709B879C952BC42BB4B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B30E29F10A116D760074368E5BEB7A1F" { "SourcePath" = "8:api-ms-win-crt-time-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-time-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B316F19F34FE4A51BE7EC51035DB90B0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B371DAE4A0264666830E52D9514DA2D7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B3E5650F97D842528A636AD1DE430393" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B4B6DAC3BCDD42A99F77E9098980726B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B4E6E7EB7B9B42DABD1B411335B4429B" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\script_compat.nut" "TargetName" = "8:script_compat.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B566F21CC84A433381E8CE406761ECB7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\convoiinfo.txt" "TargetName" = "8:convoiinfo.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B5C875785B0F4C9D9E76B3EFD305CF39" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B5DB74F3CBC44655AB3DE56EA147E4BD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B639E4ABD1444D78A8951A35EDE48EF1" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\34-flyingaway.mid" "TargetName" = "8:34-flyingaway.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B679464E4EAF4C549CB3B9BF93D9358E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B69073812BD04A2BA4FE0B6A8728F192" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B6A96A7B568E4FEF8FA8064518106BC2" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\07-Transport-chaos.mid" "TargetName" = "8:07-Transport-chaos.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B7CC8D077EFE42F9A0BC18F9A542E5C5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B7CC93E185B646E894689577E08EB81E" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\06-A-busy-day-at-the-depot.mid" "TargetName" = "8:06-A-busy-day-at-the-depot.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B7E5A578391A4BE3B786CDEBB4E7C262" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\readme_citylist.txt" "TargetName" = "8:readme_citylist.txt" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B7F6FB8254814AFE85BA148D583519C8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B82AEAEF414049BBA22FCF7C4281EBCF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B83FC3C677774402A75A2F6D613EC218" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B842BDA6FB9C4FF1B282CEF21A64CCC4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B875C187F9CA41C1AB77763828610A7A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B89E145011D34C80A50B7E8FF22318B8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B8A836BEA9F740858A2C1F1FFF645C71" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B8FCCA127BE24285B276CB6B88CA12B6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B9BAC184AB844A96839578235935D13F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BA92F69D198449BEB1A743C8E95A3F14" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BAA758A15315551B88F9AF92A6E67840" { "SourcePath" = "8:api-ms-win-crt-utility-l1-1-0.dll" "TargetName" = "8:api-ms-win-crt-utility-l1-1-0.dll" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:TRUE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BAC6972F9BC24F169F0B59391778F185" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BAF3091B84044FF092312FDC3C441130" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BB25C1A581B2468CA01A37B787637CCD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BB51F76CF0614FFA817E9E28765936F4" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\45-Misty-Forest.mid" "TargetName" = "8:45-Misty-Forest.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BBD31A3743C64DAAAC66C73DBC395184" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\22-Variable-Journeys.mid" "TargetName" = "8:22-Variable-Journeys.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BBFE3D0B7BFB49009DA1BFF118B2CF66" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\vehicle_constructor.nut" "TargetName" = "8:vehicle_constructor.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BC104A0952934C1FB24C7C72FB22ECD2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BC5B445C4A87461784901F2D6717A9C2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\underground.txt" "TargetName" = "8:underground.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BD8A0A9482644575AB7586E6526EC50E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BD9E0D72052E4EF7904B45E1247AF92C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\mouse.txt" "TargetName" = "8:mouse.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BDA2160B8AD742CE91A5BA58C603C55E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BDAB03CEB8A34A48AE15DF20C239DDB6" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\save.nut" "TargetName" = "8:save.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BE0F9941F59E4C458CB67EC2AE92F547" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BE7A191C730B4BC3AE367292A126B060" { "SourcePath" = "8:..\\..\\..\\simutrans\\script\\script_base.nut" "TargetName" = "8:script_base.nut" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BF735304ABC245BBB4251519F60E5828" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BFEBF932AC564E48B0AF7256A973C278" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C0478D73D2AF4187949270E6FD38389B" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\factorysearcher.nut" "TargetName" = "8:factorysearcher.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C08F3403BDCD48AD83F04C9427530612" { "SourcePath" = "8:..\\nsis\\download-paksets.exe" "TargetName" = "8:download-paksets.exe" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C09716430EA54D868FD696C002FF54ED" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C0CEAECDB8F8480684B11DD07E961667" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C1ED0648FF6146B0A5C52AD0740588B6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C232E233F5334677A44AD9480882E1A4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C25D46C642324693951E9A826BAD34F4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C292DECF838E4A338B1E9381FE88862C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C2BCF04AE0144DB7809933F09C0D799B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C2E91044BE604F148A304860DFB0BAAA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C32B257727534BA496BEB71041ADF2B4" { "SourcePath" = "8:..\\..\\..\\simutrans\\config\\simuconf.tab" "TargetName" = "8:simuconf.tab" "Tag" = "8:" "Folder" = "8:_397ACEE3EE1C46FE983BCD5397F6F592" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C367477479AC402B95F1AD058F17DF0A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C38EEA378E554DDC9B7516B8DDED70F7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C3C23BE233074FD6B456C2C05C5B4C15" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C45EA6EA27E24554B7E1A208734911EC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C476765DB8F94213A45B04C05F8658CD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C4DE63ED67994259861CC33EC3C8BAB3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C4E281AEA3BE44368B8891E3DD4FB96C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C4FC973F4611411EBBCDD999F5028D43" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C52BC200EEF6472E848B8CA666DC1B2C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C53EED194470430B8048AC19F45B8991" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\password.txt" "TargetName" = "8:password.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C556B896643D459C81B361121C73C2C3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\industry_info.txt" "TargetName" = "8:industry_info.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C5C315A416D34418A1655DBE35B025B3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C5FB56A197624E3C90766B9BC6F3D773" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\display.txt" "TargetName" = "8:display.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C645106B875C414D919C4B6EF4F649BC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C66A118A06614510B5E13491D6C91EC5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C6BDDA3D38EB4DB8BACF5DA31D983E82" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\bg.tab" "TargetName" = "8:bg.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C714818F8D754E9A8A9DC40733B30135" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C71AC36C9E1948349CD116DFBC84AB1E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C769223702A14E0AAB81FBF9D60B6CA7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C76E4317C8FD444E80C157DEC0DAD612" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\station_details.txt" "TargetName" = "8:station_details.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C771425A4D4143728EDCE8CBCC90C4F3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C78E7F7C98154034B15F02B9BC53FC3F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\mailbox.txt" "TargetName" = "8:mailbox.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C809E4861D6D46E78D6A32FE8124E73E" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\cyr.bdf" "TargetName" = "8:cyr.bdf" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C81BAC2BED284DE786B2D681EB8E3E1F" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\21-Dusty-Eyes.mid" "TargetName" = "8:21-Dusty-Eyes.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C839E0301CEB47E1BA350AE6CDE807BB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C8DB858DCBE4427CA19FC95E46D103C6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C950F7538D1A402185228383AEE60C82" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C98C522FC01B44D5970EBC31B95FCFE4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\enlarge_map.txt" "TargetName" = "8:enlarge_map.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CA02543373D447F8B3E2C544CA97B122" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB3347D71ED640DD9C8071E8BE50693B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\server.txt" "TargetName" = "8:server.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB65E5CC799546B7955219DAAE0AA9DC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\jump_frame.txt" "TargetName" = "8:jump_frame.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB6C6FA3B7D54809BF6148B3741134EF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB9D6377113B44CF8E2345AC6BF1DE90" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CC048A88EB9D4ABC849A93F48E36C952" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CC991A94AFBB47B08D13C709894DCF90" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CCD22597FC2B42F3AC34751411580764" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\inspection_tool.txt" "TargetName" = "8:inspection_tool.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CD0D1300C88B487CAD7E04E2A7E34C43" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CE23C05B12F5489D80D49B11021A68CD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CE49530C7C05497EAA89F5CCFE934216" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CF71964739C84F05A16D5207060275EB" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\14-Last-journey-of-the-Niagara.mid" "TargetName" = "8:14-Last-journey-of-the-Niagara.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CFE643C379A64FC3AE2CD23E2D2F69F5" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\basic.nut" "TargetName" = "8:basic.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CFF251B9A0E448EF9DC1F492C1854571" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D00F15F4EEF340309EA04799A0DB388C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D06F117B79164DADA51936E2405D9AE0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D10559A1107F43718503FAED41A57EE6" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\49-Last-Sunday.mid" "TargetName" = "8:49-Last-Sunday.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D11CEFCB96714000B0DA55A5870D6287" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\privatesign_info.txt" "TargetName" = "8:privatesign_info.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D1FF0706D277464DA9F9FD5BE0519C10" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D216427BA6A345C990A281EC393FDB6C" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\highcontrast-large.pak" "TargetName" = "8:highcontrast-large.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D2EA924E189C4134B3F6738898223CEF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D2F40D27D4D5482E9EF3866E49DBA52F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\load.txt" "TargetName" = "8:load.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D34B18B929744F4ABE62200C7D45CFA6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D36E8BDC47C649FD9617D0A6D7AC6BEE" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\road_connector.nut" "TargetName" = "8:road_connector.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D37D32CEF4AB40BA8B574271FE31AC5B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D38CF487E50547C4A7BA4E1505094FE4" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\42-Stranger-Echoes.mid" "TargetName" = "8:42-Stranger-Echoes.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D3A18E1A4D144D70A6F2241EBFFEC2C2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\gr.tab" "TargetName" = "8:gr.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D45DDB9BC95E46DD99772BBB7E9D9560" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\ship_connector.nut" "TargetName" = "8:ship_connector.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D48F15ED15E74449A5E39ED62B3CDFFB" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\39-bangin-mover.mid" "TargetName" = "8:39-bangin-mover.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D4AC3EDE729D4D8C9CE79F3BBF4A0C64" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D4C9319AB3AA4AF3BEE5F92FBD5A4E45" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D5360EBC9ED241A2A644B6CF6529B04B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es.tab" "TargetName" = "8:es.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D558CB15135F433D88F6035244DCEB68" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D58F1D37A97E4C708CAAD0AA4835AD3C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D5A25B4F622C4C4FAC8096B7EEFA5F15" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D5CED9D947C04A19B2F0AE853A4E3A1E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D66C55C5935F4AB79B03B4C00AD0F796" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\info.txt" "TargetName" = "8:info.txt" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D6A3CA57C8B54054BC881B683F7DA82B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D70EE948D30C4F86AF2B40C54035E892" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\signal_spacing.txt" "TargetName" = "8:signal_spacing.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D717157FF96A429EBD907E570F4F2BC0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D773A4CCDBBD4AF5BFE18BC2DC1AC87B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D7F83D314A5247539D7E8246AB6F6A86" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\scenario.txt" "TargetName" = "8:scenario.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D8763B920D6D46E3AD1B6911EF951B15" { "SourcePath" = "8:..\\..\\..\\simutrans\\copyright.txt" "TargetName" = "8:copyright.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D93F09ED33D649DD84751A2F14898DA7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D94AD6C7B4804825BF99854482A4159F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D970E48380BB47F99441E94A56F62A6F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\eo.tab" "TargetName" = "8:eo.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D97B480C07D844B39CAD227C1EF4B211" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D9DB1DDB4B344A11887DF8AB3C579A37" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\01-Simutrans-Main-Theme.mid" "TargetName" = "8:01-Simutrans-Main-Theme.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DA31A7B03687476B988805E3DFB3C5DC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DA44B31AF21F443D9C263A16FDA69946" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DB23FA2C15D24D49B624E736F061F420" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\factorysearcher.nut" "TargetName" = "8:factorysearcher.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DB74BC92EE834DC29A1FC5FBF31A484F" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\30-On-the-waterfront.mid" "TargetName" = "8:30-On-the-waterfront.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DBB821B3793A46BB81E2CF2B9A19B6AB" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DBC90AA5A0FD42C8A89D134FBCF0B15F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DBF5793FB8FE4AC0AEB966FDC7DEE88A" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\modern.pak" "TargetName" = "8:modern.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DC405B0582F34181944B53E63C15687F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\color.txt" "TargetName" = "8:color.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DCC1BBCD7ED54FF8971DC872AE55C7B3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DCDDCA4564C04930948BD2CB44067A3E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DCF636D15E164C79AE8B74AD2919CC37" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DDD56428DD73444F974D61F9825040B5" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DE1DF054CBB64310807E5A20C2D2467C" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\35-deep-ride.mid" "TargetName" = "8:35-deep-ride.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DE58A3BDE0904A95911A189BEFC5B524" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DE66DD7DDF4F4F96ABD6C752FEF96FE2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\privatesign_info.txt" "TargetName" = "8:privatesign_info.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DE7DEFD90AA142F982CC61E7D208D90C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DF35D4CBA48347EC8527CB78B44D97EA" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai\\station_manager.nut" "TargetName" = "8:station_manager.nut" "Tag" = "8:" "Folder" = "8:_4F550A6D8B9549C28254FE6C48EE9E9E" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DF443B32252641F688BF2BB51DA32B91" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_DF977ED1A9D84B27B29191B1E1047B4D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E00F0E6EB6714730B47ADA6C126DD397" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E036E1DCACD844D9B32566942128B2F1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E04B04B7A7A9412B959C5912CF5BD600" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E0626408DAE04212B7A5010F753DBEF3" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\rail_connector.nut" "TargetName" = "8:rail_connector.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E0D736AF86EA4D5FBF643F5A8F351B4C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E0F743C6A6394781852F6CE29CDC99BE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sv\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_F11D2625D9744C6CA3057A6D8C74A7E6" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E11660ECA02941C091C88F1BEBF4B631" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E12B0D5FE8814778B773D37F3D3E6F7E" { "SourcePath" = "8:..\\..\\..\\simutrans\\license_squirrel.txt" "TargetName" = "8:license_squirrel.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E1DDAA09A5FD465AB8577C4655CCB033" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\aerotheme.pak" "TargetName" = "8:aerotheme.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E217CA4F66774BA5A09314963FBD6CCA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\edittools.txt" "TargetName" = "8:edittools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E26EBAC5B8A0472E82DC9E74A440688D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\simutrans.txt" "TargetName" = "8:simutrans.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E2BB419D3B7F4E39AE594DF418F07C45" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E2CFE015582543699346EC288B70E41D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E31F68CF189145C1B8FFFD1148F95198" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\privatesign_info.txt" "TargetName" = "8:privatesign_info.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E4C946F4DF9444609A09E13D9072C3C6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E4FAC1F2D0C842C3A5B6560FD284FC1B" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\47-Salty-Breeze.mid" "TargetName" = "8:47-Salty-Breeze.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E579728367CD44EBA04AAF7008C46384" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\special.txt" "TargetName" = "8:special.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E58DF4184FB145939D80A4AAC090F421" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E5BFBEC26C6B41DA9D85C4D678B637BF" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\vehicle_constructor.nut" "TargetName" = "8:vehicle_constructor.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E5F10C067FFC4F318F8CB2D219EE87F1" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\prop.fnt" "TargetName" = "8:prop.fnt" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E620874F18094CED984F4503FABAF303" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\uk\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_789838269269425EB5ACB92A794015C0" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E622F110BE7948158581ABC21B6520E0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E627F06E09E94890A8657BDA806DC45D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E691274B91684CD2864B82DF108BEBB4" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\save.nut" "TargetName" = "8:save.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E6AD10132AC04F27ACD79BBC321F30EC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E6CF33E4349C478D8C1B381C31A2E09B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E746B80C52C54F2F9B17C580432EEFBA" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E75A3F6B76624E7AB13ECB7AD38250DC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E7864D4A83C04FFE8C5C06B03E11DEDD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E7CFF4924DC546198491DD71E7C5C9A2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E84D0915BD9B403582CBFCFE8B95B646" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E86C074859BF4775A00BD84487CF1275" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E889A14C0D074B379C16DB8CB052A0AF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E89BAA16F29B43F3B85DF8FF73598785" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cn\\labellist_filter.txt" "TargetName" = "8:labellist_filter.txt" "Tag" = "8:" "Folder" = "8:_50DDEE80C09B4936B9F3BD188441B081" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E8D6C5BCE19D480C8686AA7FF5366EC2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pl\\shiptools.txt" "TargetName" = "8:shiptools.txt" "Tag" = "8:" "Folder" = "8:_0E185265549642E88542EE4FC1116E88" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E8E1EB3034AF439B81FC505E88623678" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\readme.txt" "TargetName" = "8:readme.txt" "Tag" = "8:" "Folder" = "8:_095792EE20E44A23A57816A778D0137B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E969A510B3D54FCB9AC85993634A5792" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\schedule.txt" "TargetName" = "8:schedule.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E9E737ACC2A846EAB4DA8B8247E4F9B8" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E9E893DFCBCE4770B1A667EB553233C3" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EA0871A0A6C94CE8B4E5C8256BD07B56" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\linemanagement.txt" "TargetName" = "8:linemanagement.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EB211D0E657248F2A72935961F75758D" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\02-Gotta-catch-that-train.mid" "TargetName" = "8:02-Gotta-catch-that-train.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EB78E5C4CE8044F1A14092FAE05D6DA0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EC1ADB1DC1104F78A7F2F5520DB23B01" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EC5DA89F78B84B1D8A90F9ED53AD36D0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\readme.html" "TargetName" = "8:readme.html" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EC9766A95CC74083A11EAEBF44A688A1" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\flat-skin.tab" "TargetName" = "8:flat-skin.tab" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ECC9F626519A414B921A8E234EF0A441" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ECDBD057B2934DB1BD42A1B33E89C357" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\trafficlight_info.txt" "TargetName" = "8:trafficlight_info.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ECDF05EBC846419B808DA15EE0F2DAFC" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\airtools.txt" "TargetName" = "8:airtools.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED718DE30C0D43B1AB252B3C48074814" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED891169792044308BA72FF3909914AE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\monorailtools.txt" "TargetName" = "8:monorailtools.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_ED8EB9CCE7D64495894EE5DCBE629CE2" { "SourcePath" = "8:..\\..\\..\\simutrans\\themes\\highcontrast.pak" "TargetName" = "8:highcontrast.pak" "Tag" = "8:" "Folder" = "8:_9DC00CDC1F814439B7D247D84096B391" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EE6428DBC5BC4BE88A90FC65A1745A29" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\finances.txt" "TargetName" = "8:finances.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EE64372F00AC4267BEEAFCC9C6B58E18" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\railtools.txt" "TargetName" = "8:railtools.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EE72B3867FE6440CA771E3550E38E396" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EEB9D46E7BE943D7AB48509C26A5C0EF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\load_relief.txt" "TargetName" = "8:load_relief.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_EF47B6A3727849DAB2FE32F460BE8FF9" { "SourcePath" = "8:ProgramDataClear.js" "TargetName" = "8:ProgramDataClear.js" "Tag" = "8:" "Folder" = "8:_589146AE31A1480C89E8F37240599615" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F07AC979B87A44A6971AE4CBB5D149D6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F09566EC6FCE4F82A31A9B0E54E7EDB1" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fi\\new_world.txt" "TargetName" = "8:new_world.txt" "Tag" = "8:" "Folder" = "8:_6675A84858B7478194E7F18868F647F2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F0DA6488EAB24633A1F6D3634BC3769A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\map.txt" "TargetName" = "8:map.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F0E01DD09B8D47149A4A175506C86B78" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\general.txt" "TargetName" = "8:general.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F1140351BFBC4E629BDAF8CE39EDE591" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\slopetools.txt" "TargetName" = "8:slopetools.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F11D733F5F124EA3AB8410692487A78B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fp.tab" "TargetName" = "8:fp.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F12FA89FB33848218ED0FB80A64790DE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hr\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_2D7B5643FA674C72801393320CEF6786" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F130429E58C6468287355F1E01AFCC4B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F2202E85444340B1B58243D1CE5AE6DF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\citywindow.txt" "TargetName" = "8:citywindow.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F231DE5A2FD2486399D07279FE9E9977" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\25-Float-on-by.mid" "TargetName" = "8:25-Float-on-by.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F31DAAA2A03645A7A6D5A86256991A95" { "SourcePath" = "8:..\\..\\..\\simutrans\\history.txt" "TargetName" = "8:history.txt" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F35AEED69FF14D85906771EF9BE1E9B0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz.tab" "TargetName" = "8:cz.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F3AC087C60844BA4988566DB48C908C6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\uk\\citybuilding_build.txt" "TargetName" = "8:citybuilding_build.txt" "Tag" = "8:" "Folder" = "8:_789838269269425EB5ACB92A794015C0" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F3CD1BD309E34B28AEF60F9FAB278B9E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\server.txt" "TargetName" = "8:server.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F40CE2B4AF78406B95630523AC31FFD2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\factorylist_filter.txt" "TargetName" = "8:factorylist_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F42AAC8BCDDA4AAEB61AC38E9E441CCF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ro\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_457530314F624CEFA48B24EC3A1E4DC7" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F45743E0EE0C453B977771467658A7A0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\curiosity_build.txt" "TargetName" = "8:curiosity_build.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F46B417F426B4A7FA4E56EE2126FC51F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\linedetails.txt" "TargetName" = "8:linedetails.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F49FFDC689AB470F896FDB210760C4A6" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\04-Simutrans-B-Theme.mid" "TargetName" = "8:04-Simutrans-B-Theme.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F4A14191893942AAA5EA1A541CEF3E18" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\nl\\citylist_filter.txt" "TargetName" = "8:citylist_filter.txt" "Tag" = "8:" "Folder" = "8:_ADEA92C80F784C009BC3F52129DE69ED" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F519563E51B94B8D91BDFE594EF272A6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\jump_frame.txt" "TargetName" = "8:jump_frame.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F588BEAFF08146F780E0D1410A51FA5B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F58EA264ED0A47CAB5F5B47DEB36D2C4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F5E2A267D3AA495B8296333CCE8171B0" { "SourcePath" = "8:..\\..\\..\\simutrans\\music\\19-Rockin-trucker.mid" "TargetName" = "8:19-Rockin-trucker.mid" "Tag" = "8:" "Folder" = "8:_B780B35D6F7A4448A293E4643747F033" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F61055B7AFA94AC0A725D6E7AD0725D0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F61682BC67C44421BC5B219801D9BCEB" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\astar.nut" "TargetName" = "8:astar.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F64F538AB0E1481BB9AC860C911171A6" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F663097F2CCD4CA4B17CC05519AC8C4B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\window.txt" "TargetName" = "8:window.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F6BC807749F54132AFC98F6827B8F7BF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\language.txt" "TargetName" = "8:language.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F6F178E2FE184A6D8A42C619EA54979F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\station.txt" "TargetName" = "8:station.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F75C5CADB5554982A153E0967CD5ECE2" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F7619C72DBF2409EB37294746CCCE580" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\baum_build.txt" "TargetName" = "8:baum_build.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F7CC215F650944B3A8A5DF21A79CAC48" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F84089B117984EACB3BB401593BD1B6D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F84258958801470AB39943310ED08AA4" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr.tab" "TargetName" = "8:fr.tab" "Tag" = "8:" "Folder" = "8:_E5FFBD7F0C89420D9553CA08E709A59C" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F8D528CC3D51483DBDACE3CB9902880F" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F92D7AC2DD14413384E88CE4B30F09B2" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\Prop-Latin2.bdf" "TargetName" = "8:Prop-Latin2.bdf" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F95A613A31BA451D99930AB79F14614C" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\fr\\depot.txt" "TargetName" = "8:depot.txt" "Tag" = "8:" "Folder" = "8:_D80AA159986C49BB9A580BD344005969" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F9E9C90BDD0F45F6BB9E2735A05B5D20" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_F9F8DEA95B1448F683EE58097C23CDAD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\convoidetail.txt" "TargetName" = "8:convoidetail.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FA6D869BE6E943D0AA0C1306C8234A82" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ko\\goods_filter.txt" "TargetName" = "8:goods_filter.txt" "Tag" = "8:" "Folder" = "8:_1DA44BC586394673AA54DD4DB6B03B41" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FAB73043E4B44747B9DB2A6C7BDE20C7" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\players.txt" "TargetName" = "8:players.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FACA7D96D56C46339D48D794AD2B266E" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\it\\roadtools.txt" "TargetName" = "8:roadtools.txt" "Tag" = "8:" "Folder" = "8:_15A07DA91FBA4E07B1CA74A40BE82AD2" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FB33BA37B5664323A82F52A0BAB31996" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\climates.txt" "TargetName" = "8:climates.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FB87560927AC4EF9994BF2E6033BFC37" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\removal_tool.txt" "TargetName" = "8:removal_tool.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FB9702887DD5457782E571E44FEE852A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\jump_frame.txt" "TargetName" = "8:jump_frame.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FBD3810511FC4EE8BEEC600F211EC31D" { "SourcePath" = "8:..\\..\\..\\simutrans\\font\\ro_font.fnt" "TargetName" = "8:ro_font.fnt" "Tag" = "8:" "Folder" = "8:_8BAAB00D55944276B3A666BC02AD26FA" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FBDC94140B404C93B5E6991A4013AA96" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\es\\sound.txt" "TargetName" = "8:sound.txt" "Tag" = "8:" "Folder" = "8:_9C6031A6730340FF81DE6E2DB6382F19" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FBEB80FA3394476993339C5BB381BD71" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\tramtools.txt" "TargetName" = "8:tramtools.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FC637EBDEAA44A81B8A7DC3B86E7B34A" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\haltlist.txt" "TargetName" = "8:haltlist.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FD47CC396F5A4FCEBC4BC3A74BB463DD" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\en\\list.txt" "TargetName" = "8:list.txt" "Tag" = "8:" "Folder" = "8:_6A48B18D268B4269BC306957F57C5602" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FDB3F3C4DD4B4757B915C4CDCD5CA134" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\settings.txt" "TargetName" = "8:settings.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FDE16188C8F84DD4AA0718B240A13F1B" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FE391EA9A2D741FF8537B937A3757277" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\password.txt" "TargetName" = "8:password.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FE449B821B53468E9AEBCFAFA2411C17" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\cz\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_FE9928D85D6D4839856B1A55E82FF3C1" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FEA32CC3E67F43218123289C8920DD92" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\ja\\save.txt" "TargetName" = "8:save.txt" "Tag" = "8:" "Folder" = "8:_853C7D6775444583B2E5CF8612FF2482" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FEF5A316BA1640CDAD18C911C28FD23D" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\pt\\curiositylist_filter.txt" "TargetName" = "8:curiositylist_filter.txt" "Tag" = "8:" "Folder" = "8:_64307D5F4D9F47A0AAC6223079A17655" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FF0FF8FD90F14B63A9CC7CC4D25EC5BF" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\de\\haltlist_filter.txt" "TargetName" = "8:haltlist_filter.txt" "Tag" = "8:" "Folder" = "8:_5C21685B773242648E0ACAED2ED24872" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FF336FD387BD4B03B2C2120EC5C37AD9" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\sk\\options.txt" "TargetName" = "8:options.txt" "Tag" = "8:" "Folder" = "8:_499E4D5D60A446ADBAD61455C007ACDE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FF97C0E77765407A8E9B2EBDAA0C3378" { "SourcePath" = "8:..\\..\\..\\simutrans\\ai\\sqai_rail\\industry_manager.nut" "TargetName" = "8:industry_manager.nut" "Tag" = "8:" "Folder" = "8:_2A45754220784BF98E5F500D384BDF6B" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FFA020A1D53A4B4E9658D0BDB393F0F0" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\dk\\convoi_filter.txt" "TargetName" = "8:convoi_filter.txt" "Tag" = "8:" "Folder" = "8:_04068C80229D4FFA8D9C962E9E0CB785" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_FFAAEFAB7D684963A4C7532968E26CEE" { "SourcePath" = "8:..\\..\\..\\simutrans\\text\\hu\\convoi.txt" "TargetName" = "8:convoi.txt" "Tag" = "8:" "Folder" = "8:_0678692909684C3B8B9C71F487C68494" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" } } "FileType" { } "Folder" { "{3C67513D-01DD-4637-8A68-80971EB9504F}:_52BA1BC52411470C9B09D5CD28B62FAE" { "DefaultLocation" = "8:[ProgramFilesFolder]\\Simutrans" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:TARGETDIR" "Folders" { "{9EF0B969-E518-4E46-987F-47570745A589}:_095792EE20E44A23A57816A778D0137B" { "Name" = "8:ai" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_7DC2A6D314B1423892DD86B361D88A8A" "Folders" { "{9EF0B969-E518-4E46-987F-47570745A589}:_2A45754220784BF98E5F500D384BDF6B" { "Name" = "8:sqai_rail" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_0BB203E0D58444B291F18C85CD5B32FC" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_4F550A6D8B9549C28254FE6C48EE9E9E" { "Name" = "8:sqai" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_F353E86449B14ACFBAE2F81AA18A6347" "Folders" { } } } } "{9EF0B969-E518-4E46-987F-47570745A589}:_397ACEE3EE1C46FE983BCD5397F6F592" { "Name" = "8:config" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_F65526EBAB454E488E7B62FB82D6AE8D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_589146AE31A1480C89E8F37240599615" { "Name" = "8:script" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_E989ADEF3BE84A72A921BCD3FD4C3F49" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_8BAAB00D55944276B3A666BC02AD26FA" { "Name" = "8:font" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_504578582BF646E2ACF35BA50CC7AAC1" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_9DC00CDC1F814439B7D247D84096B391" { "Name" = "8:themes" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_EFDD01C448E84B8DA0AB11B4516FBC5A" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_B780B35D6F7A4448A293E4643747F033" { "Name" = "8:music" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_C5DFCC98652B4A9D98DE2932EF966655" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_E5FFBD7F0C89420D9553CA08E709A59C" { "Name" = "8:text" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_76E06520267546CCA412081ED5C9F122" "Folders" { "{9EF0B969-E518-4E46-987F-47570745A589}:_04068C80229D4FFA8D9C962E9E0CB785" { "Name" = "8:dk" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_70FAFE45E3774FDC8E10E9B6A60FA112" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_0678692909684C3B8B9C71F487C68494" { "Name" = "8:hu" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_18560D4B3A1E4A759776D6052D8B2D24" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_0DBD521BD66F4570A9CB7EDF17565613" { "Name" = "8:et" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_E499D02EA37B497F9E270521879396BE" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_0E185265549642E88542EE4FC1116E88" { "Name" = "8:pl" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_18DFD4B112274FE5BD29AD4DDA64A72F" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_15A07DA91FBA4E07B1CA74A40BE82AD2" { "Name" = "8:it" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_464389FF2590495D94C28F793B3DEBD0" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_1DA44BC586394673AA54DD4DB6B03B41" { "Name" = "8:ko" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_14BA639FCBFB449B8D5AA5C09DA21DA8" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_2D12A68841DE4C4F8AC1AE3E21C2F247" { "Name" = "8:gr" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_EB61F116DF8347658ACE6C640416FD01" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_2D7B5643FA674C72801393320CEF6786" { "Name" = "8:hr" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_A712CB08976A4A9E924B31923313925D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_3F50924EBCAB44658C46AD13CB6404F7" { "Name" = "8:eo" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_B6CA6BC70B2C41B9BC643DCEE84ADD1A" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_457530314F624CEFA48B24EC3A1E4DC7" { "Name" = "8:ro" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_D91D42A99639450CB00C1957920147AB" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_499E4D5D60A446ADBAD61455C007ACDE" { "Name" = "8:sk" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_4067FCAEA27C4F6680622B27E8325397" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_50DDEE80C09B4936B9F3BD188441B081" { "Name" = "8:cn" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_CBE82BC167A44840836980650F6ED979" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_5C21685B773242648E0ACAED2ED24872" { "Name" = "8:de" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_3C16A0C063FE4BD1B508584F204239E5" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_64307D5F4D9F47A0AAC6223079A17655" { "Name" = "8:pt" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_5CD220DC0E20426BB6CF82E8DBB3A1CC" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_6675A84858B7478194E7F18868F647F2" { "Name" = "8:fi" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_A44086DF416A414DB097C1D989ACAD44" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_6A48B18D268B4269BC306957F57C5602" { "Name" = "8:en" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_BDE71A2F2FAF4D4EB4E5AFD75DD556C2" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_6AA7E18DFDC74EFF82A4CC967B14F3F2" { "Name" = "8:ru" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_6CBDE0A9E25848479BB626B0C9B9700D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_6AFBEC71F0134B3EBE7092E5A9145B47" { "Name" = "8:no" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_40BE261FAB7644D79271EF6A0D59A6CD" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_729ABE1ACF0C4027AA858EED022538F2" { "Name" = "8:ca" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_02B97B1711904ED2A725CC0F97759065" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_789838269269425EB5ACB92A794015C0" { "Name" = "8:uk" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_EA312CB051D747B3A729729E48F31B40" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_853C7D6775444583B2E5CF8612FF2482" { "Name" = "8:ja" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_3589CA3B32FC4E24BCEFEF8B15473CBD" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_94B2E4229B2B44E895D6A98B1129B099" { "Name" = "8:bg" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_ECD5FF10ED1948FD8F8CE4A3057F857D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_9C6031A6730340FF81DE6E2DB6382F19" { "Name" = "8:es" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_5C86A757B4094458A3B33DCB065E0052" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_A26968E6884145E79C521F92E05DD14C" { "Name" = "8:id" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_E0E3D318740145EBAC8EFE9AF2A6EA2D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_A45D7C790E0C4752A4422E62C74568D6" { "Name" = "8:th" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_CF444B84B9934979911BEEBEBC97383B" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_A9D6B01652F44EEEBB95F40DFA558141" { "Name" = "8:zh" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_2BFAFDBE9A4B48F6AE8A01C57F6D7453" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_ADEA92C80F784C009BC3F52129DE69ED" { "Name" = "8:nl" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_BE262E9E92F649C58572A07000825AB1" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_BDE6662E864E49F7A98B835D4D8BF670" { "Name" = "8:fp" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_81D579FA3DC14881B0977A5B902ABE3C" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_D7C6A03AB90244D2A922A31ACEFB0F86" { "Name" = "8:lt" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_F397646C44694CAE96FC44176185BA2B" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_D80AA159986C49BB9A580BD344005969" { "Name" = "8:fr" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_4773E10ACBDA42C08F31FA2D59B20EFB" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_DA247FB0226342E8A6A415C4572F638A" { "Name" = "8:ce" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_817D0EB0EB174A478D2ED24CC9EF4BBF" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_DD9701F195AA4B3D96975B01836C5F7F" { "Name" = "8:tr" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_3E21B28F08824A1FAB617E29D9C34A1D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_E161028A40244DC890C6DF3E5C6188BA" { "Name" = "8:be" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_B1586F75B21C43BABC78DD6EFEA2C87D" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_F11D2625D9744C6CA3057A6D8C74A7E6" { "Name" = "8:sv" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_68C4677596AE44228605D620787B5C21" "Folders" { } } "{9EF0B969-E518-4E46-987F-47570745A589}:_FE9928D85D6D4839856B1A55E82FF3C1" { "Name" = "8:cz" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:_F2918120A3D34918A733CFEC430011F4" "Folders" { } } } } } } "{1525181F-901A-416C-8A58-119130FE478E}:_8286C1434FAF4646BE9D651967A10096" { "Name" = "8:#1919" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:ProgramMenuFolder" "Folders" { } } "{994432C3-9487-495D-8656-3E829A8DBDDE}:_A5BC29A726E64EB18DA057FAEE2DD996" { "DefaultLocation" = "8:[CommonAppDataFolder]\\Simutrans" "Name" = "8:Simutrans" "AlwaysCreate" = "11:TRUE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:NEWPROPERTY1" "Folders" { } } "{1525181F-901A-416C-8A58-119130FE478E}:_BCC58B92BBCB4EE89F2D7B1B590A6613" { "Name" = "8:#1916" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" "Property" = "8:DesktopFolder" "Folders" { } } } "LaunchCondition" { } "Locator" { } "MsiBootstrapper" { "LangId" = "3:0" "RequiresElevation" = "11:FALSE" } "Product" { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:Simutrans" "ProductCode" = "8:{9349912D-403F-4640-B356-0A6A248E5506}" "PackageCode" = "8:{1DF947DD-F67D-40F4-ADCA-53DF95F79A53}" "UpgradeCode" = "8:{04747FE4-03F3-4A59-8E96-C2D0DBAF2BE7}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:FALSE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:FALSE" "ProductVersion" = "8:123.0.1" "Manufacturer" = "8:Simutrans Team" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" "Title" = "8:Simutrans" "Subject" = "8:" "ARPCONTACT" = "8:Simutrans Team" "Keywords" = "8:" "ARPCOMMENTS" = "8:Installs the Simutrans Transport Simulator Game in SDL2 32 Bit version" "ARPURLINFOABOUT" = "8:" "ARPPRODUCTICON" = "8:" "ARPIconIndex" = "3:0" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" "TargetPlatform" = "3:0" "PreBuildEvent" = "8:" "PostBuildEvent" = "8:" "RunPostBuildEvent" = "3:0" } "Registry" { "HKLM" { "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_4DB56EE5F1714EB9A4200EF264D68316" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_2535A6E556814867AED8BCE9C1683C6A" { "Name" = "8:[Manufacturer]" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { } } } "Values" { } } } } "HKCU" { "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_157F22C6E58740ABAA53BEEBAB22C873" { "Name" = "8:Software" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_C45B8D428A1C44C9831FEB92A08B4520" { "Name" = "8:[Manufacturer]" "Condition" = "8:" "AlwaysCreate" = "11:FALSE" "DeleteAtUninstall" = "11:FALSE" "Transitive" = "11:FALSE" "Keys" { } "Values" { } } } "Values" { } } } } "HKCR" { "Keys" { } } "HKU" { "Keys" { } } "HKPU" { "Keys" { } } } "Sequences" { } "Shortcut" { "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_F57E5DD1DBBE473D8BB002FE2766588E" { "Name" = "8:Simutrans" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" "IconIndex" = "3:100" "Transitive" = "11:FALSE" "Target" = "8:_B02CDD54271647E084EBF14CA126EEFB" "Folder" = "8:_8286C1434FAF4646BE9D651967A10096" "WorkingFolder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Icon" = "8:_B02CDD54271647E084EBF14CA126EEFB" "Feature" = "8:" } } "UserInterface" { "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_146261DCA8F042788377A07566B20D57" { "Name" = "8:#1902" "Sequence" = "3:1" "Attributes" = "3:3" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_163F870C006A493B98CA78FAD364D09D" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFinishedDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "UpdateText" { "Name" = "8:UpdateText" "DisplayName" = "8:#1058" "Description" = "8:#1158" "Type" = "3:15" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1258" "DefaultValue" = "8:#1258" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_23B57DE408C64ECEB6BBDF2F4051DA10" { "Name" = "8:#1902" "Sequence" = "3:2" "Attributes" = "3:3" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_EBE035DE8391403C956031FD63B478E3" { "Sequence" = "3:100" "DisplayName" = "8:Finished" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_4AED4AA98F09409A8092136212DFD2D6" { "Name" = "8:#1900" "Sequence" = "3:2" "Attributes" = "3:1" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BED56C62870A449CBCDB91658BDD0FC8" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1202" "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_D882F877F4424D6783C52EEBC04ED6BC" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F2E8FF8E279544DC8401A5EA502A1738" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminFolderDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_807B77E05FC84ED0ADB496BED79BC654" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdUserInterface.wim" } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_985FF174696B4FE79C7B71E3BCCE57C3" { "Name" = "8:#1901" "Sequence" = "3:2" "Attributes" = "3:2" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BA112D1532CA4844AD4436C923BB4382" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdAdminProgressDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_98DE520552624BE185C29C0CFA506D13" { "UseDynamicProperties" = "11:FALSE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdBasicDialogs.wim" } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_A122B1B3CC12485A93B254821F99C458" { "Name" = "8:#1900" "Sequence" = "3:1" "Attributes" = "3:1" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_92139CD85F1B4416BD64CF2857F9C28F" { "Sequence" = "3:300" "DisplayName" = "8:Confirm Installation" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdConfirmDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BAAD3C448E334CEF95EE2092B2AA29C3" { "Sequence" = "3:200" "DisplayName" = "8:Installation Folder" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdFolderDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "InstallAllUsersVisible" { "Name" = "8:InstallAllUsersVisible" "DisplayName" = "8:#1059" "Description" = "8:#1159" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BB7A9B597C014906A2014E13D4DFF287" { "Sequence" = "3:100" "DisplayName" = "8:Welcome" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdWelcomeDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "CopyrightWarning" { "Name" = "8:CopyrightWarning" "DisplayName" = "8:#1002" "Description" = "8:#1102" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1202" "DefaultValue" = "8:#1202" "UsePlugInResources" = "11:TRUE" } "Welcome" { "Name" = "8:Welcome" "DisplayName" = "8:#1003" "Description" = "8:#1103" "Type" = "3:3" "ContextData" = "8:" "Attributes" = "3:0" "Setting" = "3:1" "Value" = "8:#1203" "DefaultValue" = "8:#1203" "UsePlugInResources" = "11:TRUE" } } } } } "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_A922C2038B4D4533BCB32D48FD557BA6" { "Name" = "8:#1901" "Sequence" = "3:1" "Attributes" = "3:2" "Dialogs" { "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_3BF20F731F1F4AAAAF1EC1D836B194DC" { "Sequence" = "3:100" "DisplayName" = "8:Progress" "UseDynamicProperties" = "11:TRUE" "IsDependency" = "11:FALSE" "SourcePath" = "8:\\VsdProgressDlg.wid" "Properties" { "BannerBitmap" { "Name" = "8:BannerBitmap" "DisplayName" = "8:#1001" "Description" = "8:#1101" "Type" = "3:8" "ContextData" = "8:Bitmap" "Attributes" = "3:4" "Setting" = "3:1" "UsePlugInResources" = "11:TRUE" } "ShowProgress" { "Name" = "8:ShowProgress" "DisplayName" = "8:#1009" "Description" = "8:#1109" "Type" = "3:5" "ContextData" = "8:1;True=1;False=0" "Attributes" = "3:0" "Setting" = "3:0" "Value" = "3:1" "DefaultValue" = "3:1" "UsePlugInResources" = "11:TRUE" } } } } } } "MergeModule" { } "ProjectOutput" { "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_B02CDD54271647E084EBF14CA126EEFB" { "SourcePath" = "8:..\\..\\..\\build\\SDL2\\Simutrans SDL2 Nightly.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_52BA1BC52411470C9B09D5CD28B62FAE" "Condition" = "8:" "Transitive" = "11:FALSE" "Vital" = "11:TRUE" "ReadOnly" = "11:FALSE" "Hidden" = "11:FALSE" "System" = "11:FALSE" "Permanent" = "11:FALSE" "SharedLegacy" = "11:FALSE" "PackageAs" = "3:1" "Register" = "3:1" "Exclude" = "11:FALSE" "IsDependency" = "11:FALSE" "IsolateTo" = "8:" "ProjectOutputGroupRegister" = "3:1" "OutputConfiguration" = "8:" "OutputGroupCanonicalName" = "8:Built" "OutputProjectGuid" = "8:{E74757E8-C2FD-44AD-87BD-3D55F4709484}" "ShowKeyOutput" = "11:TRUE" "ExcludeFilters" { } } } } } simutrans-124.3/src/Windows/Simutrans.manifest000066400000000000000000000016361474050137200215170ustar00rootroot00000000000000 true/PM simutrans-124.3/src/Windows/nsis/000077500000000000000000000000001474050137200167505ustar00rootroot00000000000000simutrans-124.3/src/Windows/nsis/CC-BY-SA.txt000066400000000000000000000377161474050137200206250ustar00rootroot00000000000000Simutrans is copyright (C) 1997-2004 by Hansjoerg Malthaner. (c) 2004-2007 Simutrans Team >>>>>>>>>>> NO WARRANTIES, EXPRESS OR IMPLIED. <<<<<<<<<<< Have lots of fun playing Simutrans! The following pak is under CC-BY-SA: - pak192 comic - pak48.bitlit ----------------------------------------------------------------------------- Creative Commons Attribution-ShareAlike 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part; and b. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. Additional offer from the Licensor -- Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter's License You apply. c. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. b. ShareAlike. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 1. The Adapter's License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. simutrans-124.3/src/Windows/nsis/GPL.txt000066400000000000000000001052431474050137200201400ustar00rootroot00000000000000Simutrans is copyright (C) 1997-2004 by Hansjoerg Malthaner. (c) 2004-2007 Simutrans Team >>>>>>>>>>> NO WARRANTIES, EXPRESS OR IMPLIED. <<<<<<<<<<< Have lots of fun playing Simutrans! The following paks are under GPL: - pak64 HO-scale (lost) - pak64 contrast ----------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . simutrans-124.3/src/Windows/nsis/installericon256.bmp000066400000000000000000000100221474050137200225460ustar00rootroot00000000000000BM6(9Ü !!)19BBJRZZ!Z!c9199!9BJBkks)19B1!9!B!)9B9cç”!!!)!!1!!9!!B!!J!!))!1)!9)!B)!J)!cs!ç”!çœ!)))1))9))B))J))91)B1)J1)R1)1J)çœ)111911R11Z11B91J91R91Z91ZB1¥”1çœ1ç¥1999RB9ZB9cB9cJ9kJ9ç¥9ï¥9cBBZJBcJBkJBkRBsRBZkBµœBç¥Bï¥Bç­Bï­BJJJcRJkRJkZJsZJccJ{cJï­JZRRkZRsZR{ZRscR{cR„kRŒsRç­Rï­RïµRkcZscZ{kZ„kZssZ{sZ„sZ”sZœ{Z­ŒZ½”ZÎ¥ZÖ­ZÞ­ZïµZ{kc{sc„sc„{cŒ{c¥„c­Œc½”cÆœcÎ¥cÞ­cïµcï½ckkk{sk„skŒsk„{kŒ{kŒ„k”„k¥Œk­”kï½k„ss„{sŒ{sŒ„s¥Œs½œsÖ­sçµsç½sï½s{{{„{{„„{Œ„{œŒ{¥Œ{έ{ç½{ï½{ïÆ{„„„Œ„„ŒŒ„Þµ„ïÆ„÷Æ„ŒŒŒµœŒç½ŒçÆŒïÆŒ÷ÆŒïÎŒ÷ÎŒ¥œ”­œ”½¥”Öµ”çÆ”÷ΔεœçÆœ÷Μ÷Öœµ­¥Æ­¥çÆ¥çÎ¥ïÎ¥ïÖ¥÷Ö¥ÞέçέïÖ­÷Ö­÷Þ­ÖÆµçεçÖµïÖµ÷޵ƽ½ÞνÞÖ½çÖ½ïÖ½ïÞ½÷Þ½÷ç½ÞÖÆïÞÆ÷çÆÿçÆÞÖÎ÷çÎÿçÎÿïÎÞÖÖÞÞÖçÞÖÿïÖÞÞÞÿïÞÿ÷Þÿ÷çÿ÷ï„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$*V#]qrru€‘‘‘ $*O#qrru€‘‘‘ H==3& %**>#*qrru€‘3H =3&&'&&++*.#I qruu€‘&=H=33&'-889BB98332*#Ih qruu€‘‘‘s&3H< 223,,--889BBBCJ LLLRJIA@=21 #=Qfhhh qrruu€‘‘‘ ß¹P&3H <1 #*2379BBBCJLLLRT^_`ffhhh qrru€‘‘‘ êèÃf 3=H <1#7CJLLRT^_`ffhhh qrru€‘‘‘ èæÎŽ'3=H <1#8CJLLLRT^_`fh qrru€ ‘‘‘aèæ àààÜ¥C'32<<<1 #8CJLLLR^__`fhhh qruu€‘‘‘èèæ àÝݱU'-,321 #9CJLLLR^_`fhhh qruu€ o\\o‘‘æ à ÝÙÙ¾r-'-883*#9CJLLLR^_`ffhhh qrruu€ d °°ª‘æ à ÝÙÒÒÜܺg-8897*#BCJLLLR eŒ«°°¢~f^_`ffhhh qrruu€€‹°€à ÝÙÒÜÖ»v9889BBBCJLLRT^ p–°°°«Œhffhhh qrru€\°àÝÙ ÒÖ ÐÈÈ¿“S999BBBCJLLR^°¡p^ _``q—°°°«— qrru€˜\°ÝÙ ÒÌÈÈÖÖÖÐÖÐÇÀ›bCJLLLR Tf—°°¡p__`fhhh~—«°°°¢€rrru€¢°¢\°  ÝÙ ÒÌÈÇÇÇÈÐÔÆÀ½½¦vJLLLR^ p¡°°¢~ffhhhq€—««° «Œ‹°°:ÝÝÙ ÒÌÈÇ ÀÆÐÐÐÔÔÔÐ ½¶¶­ƒ^LRT^ _```p–«°°¡qrruu€°¢€Ù ÒÌÈÈÈÇÀÆÔ޶®œw^RT^_`ffhhh~¢°°°«——€€€˜¢°°™ ÙÙÙ ÒÌÈÈÈÇÀ½ÆÏÔÔÔÏ´ ®©©©„b^_`ffhhh q€€€ ÒÌÈÈÈÇÀ½¶¶¶ÅÏÔÅ® ©Ÿ…k`ffhhh qrru€V  ÒÌÌÌÈÈÈÇÀ½¶®®ÅÏÔÔÔϳ©¨ Ÿ•‡whqrrru€t  ÒÌÌÌÈÈÈÇÀ½¶®ÉÏÔÄ Ÿ •‰‰‰ˆxrqrruu€†z  ÒÒÒÌÌÌÈÈÈÇÀ½¶®©ÉÏÏÏÔ³ •‰ŸääßÓ¸¤š”yz‰W|‰‰! ÌÌÌÈÈÈÇÀ½¶®©ŸŸÉÏÏ Ô³••‰¼ 䳉 |‰  ÌÌÈÈÇÀ½¶®©ŸÉÏ ÔÛÉŸ ‰§Éßß äl .  ÈÈÇÀ½¶®©Ÿ•ŸÏÔÛÔÔÛß ä lE ÈÇÀ½¶®©Ÿ•‰‰•Ô Ûßä² l  ÇÀ½¶®©¨Ÿ•‰ŸÔ ÛßäÛX  ÇÀ½¶®©Ÿ•‰ŸÔ ÛßäÛX   ÇÇÀ½¶®©Ÿ• ‰ÉÔ ÛßäääÔX NXN À½¶®©Ÿ• ‰lÉ Ûßä²N À½¶®©Ÿ• ‰lÄÛß¿ N FNN ÀÀÀ½¶®©Ÿ• ‰ l§¿ÉÔÉÄXNF À½¶®©Ÿ• ‰ lXN F;;;F ½¶®©Ÿ• ‰ lXN F; ½¶®©Ÿ• ‰ lXNF; /;; ½¶®©Ÿ• ‰ lXNF;/;; ½¶®©Ÿ• ‰ lXN F ;  ½½½¶®©Ÿ• ‰ lXNF !½½½¶®©¨Ÿ• ‰ lX N F  "½½¶®©Ÿ• ‰ l XN  #½½¶®©¨Ÿ• ‰l X N   %½¶®©Ÿ• ‰lX &½¶®©Ÿ•‰l X-'½½¶®©Ÿ•‰l.(½½¶®©Ÿ•‰l0*½½¶®©Ÿ•‰ l1+½½½¶®©Ÿ •‰3-½¶®© Ÿ •‰4/½¶®© Ÿ •‰61½¶ ® © Ÿ •83½¶ ® © Ÿ:6½¶ ® ©ŸŸ=8ÀÀ½¶®©?<ÀÀ ½ ¶ ®C@ÀÀÀ ½ ¶Gsimutrans-124.3/src/Windows/nsis/languages.nsh000066400000000000000000000023741474050137200214360ustar00rootroot00000000000000 !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "SpanishInternational" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "NorwegianNynorsk" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Catalan" simutrans-124.3/src/Windows/nsis/license.rtf000066400000000000000000000224711474050137200211150ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1031{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} {\f17\fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho;}{\f91\froman\fcharset238\fprq2 Times New Roman CE;}{\f92\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f94\froman\fcharset161\fprq2 Times New Roman Greek;} {\f95\froman\fcharset162\fprq2 Times New Roman Tur;}{\f96\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f97\fswiss\fcharset238\fprq2 Arial CE;}{\f98\fswiss\fcharset204\fprq2 Arial Cyr;}{\f100\fswiss\fcharset161\fprq2 Arial Greek;} {\f101\fswiss\fcharset162\fprq2 Arial Tur;}{\f102\fswiss\fcharset186\fprq2 Arial Baltic;}{\f195\fmodern\fcharset0\fprq1 MS Mincho;}{\f193\fmodern\fcharset238\fprq1 MS Mincho CE;}{\f194\fmodern\fcharset204\fprq1 MS Mincho Cyr;} {\f196\fmodern\fcharset161\fprq1 MS Mincho Greek;}{\f197\fmodern\fcharset162\fprq1 MS Mincho Tur;}{\f198\fmodern\fcharset186\fprq1 MS Mincho Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; \red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128; \red192\green192\blue192;}{\stylesheet{\nowidctlpar\adjustright \lang1031 \snext0 Normal;}{\s1\sb240\sa120\keepn\nowidctlpar\adjustright \b\fs32\lang1031 \sbasedon15 \snext16 heading 1;}{\s2\sb240\sa120\keepn\nowidctlpar\adjustright \b\i\fs28\lang1031 \sbasedon15 \snext16 heading 2;}{\*\cs10 \additive Default Paragraph Font;}{\s15\sb240\sa120\keepn\nowidctlpar\adjustright \fs28\lang1031 \sbasedon0 \snext16 Heading;}{\s16\sa120\nowidctlpar\adjustright \lang1031 \sbasedon0 \snext16 Body Text;}{ \s17\sa120\nowidctlpar\adjustright \lang1031 \sbasedon16 \snext17 List;}{\s18\sb120\sa120\nowidctlpar\adjustright \i\lang1031 \sbasedon0 \snext18 caption;}{\s19\nowidctlpar\adjustright \lang1031 \sbasedon0 \snext19 Index;}{ \s20\sa120\nowidctlpar\adjustright \lang1031 \sbasedon16 \snext20 Frame contents;}}{\info{\author Markus Pristovsek}{\operator Markus Pristovsek}{\creatim\yr2009\mo9\dy12\hr23\min14}{\revtim\yr2009\mo9\dy12\hr23\min20}{\version2}{\edmins0}{\nofpages3} {\nofwords786}{\nofchars4482}{\*\company }{\nofcharsws5504}{\vern73}}\paperw11905\paperh16837\margl1134\margr1134\margt1134\margb1134 \deftab709\widowctrl\ftnbj\aenddoc\hyphhotz425\hyphcaps0\viewkind4\viewscale100 \fet0\sectd \sbknone\linex0\headery709\footery709\colsx709\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4 \pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (} {\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \nowidctlpar\adjustright \lang1031 {This is the Simutrans source code. \par (c) 1997-2003 Hans Joerg Malthaner \par (c) since 2004 The Simutrans Team \par \par Simutrans source code is provided by the current Simutrans team (team64@simutrans.com) as copyright holder under the Artistic License. \par \par This includes the translations from: \par http://translator.simutrans.com/ \par the midi files and the fonts with the exception of the m+10r.bdf, which is taken from the M+ font project: \par http://mplus-fonts.sourceforge.jp/ \par \par \par \par }\pard\plain \s1\sb240\sa120\keepn\nowidctlpar\outlinelevel0\adjustright \b\fs32\lang1031 {\hich\af1\dbch\af17\loch\f1 The Artistic License \par }\pard\plain \nowidctlpar\adjustright \lang1031 { \par }\pard\plain \s2\fi-578\li578\sb240\sa120\keepn\nowidctlpar\outlinelevel1\adjustright \b\i\fs28\lang1031 {\hich\af1\dbch\af17\loch\f1 Preamble \par }\pard\plain \nowidctlpar\adjustright \lang1031 { \par The inten t of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. \par \par Definitions: \par \par * "Package" refers to the collection of files distributed by the \par Copyright Holder, and derivatives of that collection of files \par created through textual modification. \par * "Standard Version" refers to such a Package if it has not been \par modified, or has been modified in accordance with the wishes \par of the Copyright Holder. \par * "Copyright Holder" is whoever is named in the copyright or \par copyrights for the package. \par * "You" is you, if you're thinking about copying or distributing \par this Package. \par * "Reasonable copying fee" is whatever you can justify on the \par basis of media cost, duplication charges, time of people involved, \par and so on. (You will not be required to justify it to the \par Copyright Holder, but only to the computing community at large \par as a market that must bear the fee.) \par * "Freely Available" means that no fee is charged for the item \par itself, though there may be fees involved in handling the item. \par It also means that recipients of the item may redistribute it \par under the same conditions they received it. \par \par 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. \par \par 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. \par \par 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: \par \par a) place your modifications in the Public Domain or otherwise make them \par Freely Available, such as by posting said modifications to Usenet or \par an equivalent medium, or placing the modifications on a major archive \par site such as ftp.uu.net, or by allowing the Copyright Holder to include \par your modifications in the Standard Version of the Package. \par \par b) use the modified Package only within your corporation or organization. \par \par c) rename any non-standard executables so the names do not conflict \par with standard executables, which must also be provided, and provide \par a separate manual page for each non-standard executable that clearly \par documents how it differs from the Standard Version. \par \par d) make other distribution arrangements with the Copyright Holder. \par \par 4. You may distribute the programs of this Package in object code or \par executable form, provided that you do at least ONE of the following: \par \par a) distribute a Standard Version of the executables and library files, \par together with instructions (in the manual page or equivalent) on where \par to get the Standard Version. \par \par b) accompany the distribution with the machine-readable source of \par the Package with your modifications. \par \par c) accompany any non-standard executables with their corresponding \par Standard Version executables, giving the non-standard executables \par non-standard names, and clearly documenting the differences in manual \par pages (or equivalent), together with instructions on where to get \par the Standard Version. \par \par d) make other distribution arrangements with the Copyright Holder. \par \par 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly comm ercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. \par \par 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. \par \par 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. \par \par 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. \par \par 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. \par \par }} simutrans-124.3/src/Windows/nsis/onlineupgrade.nsi000066400000000000000000000063441474050137200223260ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; ************************************* Pakset downloader for simutrans ********************************************* ; needs the following plugins: ; nsisunz ; inetc ; CabX ; untgz ; ShellLink Unicode true !define PAKSETINSTALL 1 !include "preparation-functions.nsh" !include "languages.nsh" RequestExecutionLevel user !define MULTIUSER_INSTALLMODE_INSTDIR "Simutrans" !define MULTIUSER_EXECUTIONLEVEL Standard Name "Simutrans Pakset Installer" OutFile "download-paksets.exe" ; The default installation directory InstallDir $PROGRAMFILES\Simutrans !include "paksets.nsh" ;************************** from here on other helper stuff ***************** !include "other-functions.nsh" ;********************* from here on special own helper functions ************ ; make sure, at least one executable is installed Function .onSelChange ; Make sure at least some pak is selected SectionGetFlags ${pak} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.nippon} $R0 IntCmp $R0 ${SF_SELECTED} show_not ; SectionGetFlags ${pak64.ho-scale} $R0 ; IntOp $R0 $R0 & ${SF_SELECTED} ; IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakcontrast} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.scifi} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak96.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.britain} $R0 IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${PAK128.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.CS} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak192.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak144.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak32} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakTTD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.bitlit} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not ; not pak selected! MessageBox MB_OK|MB_ICONSTOP "At least on pak set must be selected!" /SD IDOK SetErrorLevel 4 show_not: FunctionEnd simutrans-124.3/src/Windows/nsis/other-functions.nsh000066400000000000000000000454031474050137200226170ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ;***************************************************** from here on come licence ***************************************** !include "TextFunc.nsh" ; Usage ... ; Push "|" ;divider char ; Push "string1|string2|string3|string4|string5" ;input string ; Call SplitFirstStrPart ; Pop $R0 ;1st part ["string1"] ; Pop $R1 ;rest ["string2|string3|string4|string5"] Function SplitFirstStrPart Exch $R0 Exch Exch $R1 Push $R2 Push $R3 StrCpy $R3 $R1 StrLen $R1 $R0 IntOp $R1 $R1 + 1 loop: IntOp $R1 $R1 - 1 StrCpy $R2 $R0 1 -$R1 StrCmp $R1 0 exit0 StrCmp $R2 $R3 exit1 loop exit0: StrCpy $R1 "" Goto exit2 exit1: IntOp $R1 $R1 - 1 StrCmp $R1 0 0 +3 StrCpy $R2 "" Goto +2 StrCpy $R2 $R0 "" -$R1 IntOp $R1 $R1 + 1 StrCpy $R0 $R0 -$R1 StrCpy $R1 $R2 exit2: Pop $R3 Pop $R2 Exch $R1 ;rest Exch Exch $R0 ;first FunctionEnd ; we just ask for Artistic licences, the other are only asked for certain paks PageEx license LicenseData "license.rtf" PageExEnd ; If not installed to program dir, ask for a portable installation Function CheckForPortableInstall ; defaults in progdir, and ending with simutrans StrCpy $installinsimutransfolder "1" StrCpy $multiuserinstall "1" ; if the destination directory is the program dir, we must use use own documents directory for data StrCmp $INSTDIR $PROGRAMFILES\simutrans FinishSetPortable StrCmp $INSTDIR $PROGRAMFILES64\simutrans FinishSetPortable StrCmp $INSTDIR $USERDIR FinishSetPortable StrCpy $multiuserinstall "0" ; check whether we already have a simuconf.tab, to get state from file IfFileExists "$INSTDIR\config\simuconf.tab" 0 PortableUnknown ; now we have a config. Without single_user install, it will be multiuser StrCpy $multiuserinstall "1" ${ConfigRead} "$INSTDIR\config\simuconf.tab" "singleuser_install" $R0 IfErrors PortableUnknown ; skip a leading space PortableSpaceSkip: StrCpy $1 $R0 1 StrCmp " " $1 0 +3 StrCpy $R0 $R0 100 1 Goto PortableSpaceSkip ; skip the equal char StrCpy $R0 $R0 10 1 IntOp $multiuserinstall $R0 ^ 1 Goto FinishSetPortable PortableUnknown: ; ask whether this is a portable installation ; check if there are paksets in the current folder FindFirst $R0 $R1 "$INSTDIR\pak*" IfErrors 0 YesPortable MessageBox MB_YESNO|MB_ICONINFORMATION "Should this be a portable installation?" /SD IDNO IDYES YesPortable StrCpy $multiuserinstall "1" Goto FinishSetPortable YesPortable: ; Messagebox MB_OK "singleuser" StrCpy $PAKDIR $INSTDIR StrCpy $multiuserinstall "0" Goto FinishSetPortable NoPortable: Messagebox MB_OK "Multiuser" FinishSetPortable: ; now check, whether the path ends with "simutrans" StrCpy $0 $INSTDIR 9 -9 StrCmp $0 simutrans +2 StrCpy $installinsimutransfolder "0" ; here everything is ok ; MessageBox MB_OK "$INSTDIR $PAKDIR" FunctionEnd !ifndef PAKSETINSTALL PageEx directory PageCallbacks "" "" CheckForPortableInstall PageExEnd !endif Page custom MovePre MoveLeave "Moving paks to ProgramData" ; only show this page, if there are old paks to move ... Function MovePre StrCmp $PAKDIR $INSTDIR 0 +2 Abort StrCmp $multiuserinstall "1" +2 Abort SetShellVarContext all StrCmp $PAKDIR "$LOCALAPPDATA\simutrans" +3 SetShellVarContext current Abort SetShellVarContext current ; find at least on pak to move? nsDialogs::Create 1018 Pop $0 ${NSD_CreateLabel} 0 0 100% 12u "Moving paks to ProgramData (slow)" Pop $0 IntOp $9 0 + 13 FindFirst $R0 $R1 "$INSTDIR\pak*" IfErrors 0 LoopIt Abort LoopIt: ${NSD_CreateLabel} 0 $9 100% 12u "$R1" POP $0 IntOp $9 $9 + 13 ; Messagebox MB_OK "Do some processing on $R1" FindNext $R0 $R1 IfErrors 0 LoopIt nsDialogs::Show FunctionEnd Function MoveLeave StrCmp $PAKDIR $INSTDIR0 0 +2 Abort StrCmp $multiuserinstall "1" +2 Abort FindFirst $R0 $R1 "$INSTDIR\pak*" IfErrors 0 MoveIt Abort MoveIt: CreateDirectory "$PAKDIR\$R1" CopyFiles "$INSTDIR\$R1" "$PAKDIR" RMdir /r "$INSTDIR\$R1" FindNext $R0 $R1 IfErrors 0 MoveIt ExecWait 'Icacls "$PAKDIR" /grant Users:(OI)(CI)M' FunctionEnd PageEx components PageCallbacks componentsPre PageExEnd ; If for the pak in this section exists, it will be preselected Function EnableSectionIfThere Exch $R0 Push $R1 SectionGetText $R0 $R1 ; now only use the part until the space ... Push " " Push $R1 Call SplitFirstStrPart Pop $R1 IfFileExists "$PAKDIR\$R1\ground.Outside.pak" 0 NotExistingPakNotSelected SectionGetFlags $R0 $R1 IntOp $R1 $R1 | ${SF_SELECTED} SectionSetFlags $R0 $R1 NotExistingPakNotSelected: Pop $R1 Exch $R0 FunctionEnd ; set pak for update/skip if installed Function componentsPre Push ${pak} Call EnableSectionIfThere Push ${pak64.german} Call EnableSectionIfThere Push ${pak.japan} Call EnableSectionIfThere Push ${pak.nippon} Call EnableSectionIfThere ; Push ${pak64.ho-scale} ; Call EnableSectionIfThere Push ${pakHAJO} Call EnableSectionIfThere Push ${pakcontrast} Call EnableSectionIfThere Push ${pak64.scifi} Call EnableSectionIfThere Push ${pak96.comic} Call EnableSectionIfThere Push ${pakHD} Call EnableSectionIfThere Push ${pak128} Call EnableSectionIfThere Push ${pak128.Britain} Call EnableSectionIfThere Push ${PAK128.german} Call EnableSectionIfThere Push ${pak128.japan} Call EnableSectionIfThere Push ${pak128.CS} Call EnableSectionIfThere Push ${pak144.Excentrique} Call EnableSectionIfThere Push ${pak192.comic} Call EnableSectionIfThere Push ${pak64.scifi} Call EnableSectionIfThere Push ${pak48.Excentrique} Call EnableSectionIfThere Push ${pak32} Call EnableSectionIfThere Push ${pakTTD} Call EnableSectionIfThere Push ${pak48.bitlit} Call EnableSectionIfThere FunctionEnd ; Some paksets don't have an open source license, so we have to show additional licences Function CheckForClosedSource SectionGetFlags ${pak64.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pakHAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pak.nippon} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pak96.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pakHD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pak128.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${PAK128.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW SectionGetFlags ${pak192.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showFW Abort showFW: ; here is ok FunctionEnd PageEx License LicenseData "pak128.txt" PageCallbacks CheckForClosedSource "" "" PageExEnd ; Some packs are GPL Function CheckForGPL ; SectionGetFlags ${pak64.ho-scale} $R0 ; IntOp $R0 $R0 & ${SF_SELECTED} ; IntCmp $R0 ${SF_SELECTED} showGPL SectionGetFlags ${pakcontrast} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showGPL Abort showGPL: ; here is ok FunctionEnd PageEx License LicenseData "GPL.txt" PageCallbacks CheckForGPL "" "" PageExEnd ; Some pak192.comic is CC Function CheckForCC SectionGetFlags ${pak192.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showCC SectionGetFlags ${pak48.bitlit} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} showCC Abort showCC: ; here is ok FunctionEnd PageEx License LicenseData "CC-BY-SA.txt" PageCallbacks CheckForCC "" "" PageExEnd PageEx instfiles PageExEnd ; ******************************** From here on Functions *************************** Function .oninit StrCpy $USERDIR "$LOCALAPPDATA\simutrans" SetShellVarContext all StrCpy $PAKDIR "$LOCALAPPDATA\simutrans" SetShellVarContext current !insertmacro MULTIUSER_INIT StrCpy $9 ${SDLexe} ;The default for radiobutton InitPluginsDir StrCpy $multiuserinstall "1" ; avoids two instance at the same time ... System::Call 'kernel32::CreateMutexA(i 0, i 0, t "SimutransMutex") i .r1 ?e' Pop $R0 StrCmp $R0 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." /SD IDOK Abort ; now find out, whether there is an old installation IfFileExists "$SMPROGRAMS\Simutrans\Simutrans.lnk" 0 no_previous_menu ShellLink::GetShortCutTarget "$SMPROGRAMS\Simutrans\Simutrans.lnk" Pop $0 StrCpy $INSTDIR $0 -14 ; now check for portable or not goto init_path_ok no_previous_menu: ;# call userInfo plugin to get user info. The plugin puts the result in the stack userInfo::getAccountType pop $0 ; compare the result with the string "Admin" to see if the user is admin. ; If match, jump 3 lines down. strCmp $0 "Admin" +3 ; we are not admin: default install in a different dir StrCpy $INSTDIR $USERDIR ; ok, we are admin init_path_ok: !ifdef PAKSETINSTALL Call CheckForPortableInstall !endif FunctionEnd ; ConnectInternet (uses Dialer plug-in) ; Written by Joost Verburg ; ; This function attempts to make a connection to the internet if there is no ; connection available. If you are not sure that a system using the installer ; has an active internet connection, call this function before downloading ; files with NSISdl. ; ; The function requires Internet Explorer 3, but asks to connect manually if ; IE3 is not installed. Function ConnectInternet Push $R0 ClearErrors Dialer::AttemptConnect IfErrors noie3 Pop $R0 StrCmp $R0 "online" connected MessageBox MB_OK|MB_ICONSTOP "Cannot connect to the internet." /SD IDOK Quit ;This will quit the installer. You might want to add your own error handling. noie3: ; IE3 not installed MessageBox MB_OK|MB_ICONINFORMATION "Please connect to the internet now." /SD IDOK connected: Pop $R0 FunctionEnd Function IsPakInstalledAndCurrent IntOp $R0 0 + 0 IfFileExists "$PAKDIR\$downloadname\ground.Outside.pak" +1 PakNotThere IntOp $R0 1 | 1 ; now we have outside.pak and it should have a valid number FileOpen $0 "$PAKDIR\$downloadname\ground.Outside.pak" r FileSeek $0 101 FileRead $0 $R1 FileClose $0 StrCmp $VersionString $R1 0 PakThereButOld ; now we are current IntOp $R0 2 | 2 goto PakNotThere PakThereButOld: DetailPrint "Old pak has version $R1 but current is $VersionString" PakNotThere: FunctionEnd ; $downloadlink is then name of the link, $downloadname the name of the pak for error messages Function DownloadInstallZip Call IsPakInstalledAndCurrent IntCmp $R0 2 DownloadInstallZipSkipped IntCmp $R0 0 DownloadInstallZipDo RMdir /r "$downloadname.old" Rename "$downloadname" "$downloadname.old" DetailPrint "Old $downloadname renamed to $downloadname.old" DownloadInstallZipDo: ; ok old directory rename Call ConnectInternet RMdir /r "$TEMP\simutrans" ; since https fails with builtin NSISdl ... ; NSISdl::download $downloadlink "$TEMP\$archievename" ; Pop $R0 ;Get the return value ; StrCmp $R0 "success" +3 ; MessageBox MB_OK "Download of $archievename failed: $R0" ; Quit inetc::get /WEAKSECURITY $downloadlink "$Temp\$archievename" /END Pop $0 StrCmp $0 "OK" +3 MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK Quit ; remove all old files before! RMdir /r "$OUTDIR\$downloadname" ; we need the magic with temporary copy only if the folder does not end with simutrans ... StrCmp $installinsimutransfolder "0" +4 nsisunz::Unzip "$TEMP\$archievename" "$OUTDIR\.." goto +2 nsisunz::Unzip "$TEMP\$archievename" "$TEMP" Pop $R0 ;Get the return value StrCmp $R0 "success" +4 MessageBox MB_OK|MB_ICONINFORMATION "$R0" /SD IDOK RMdir /r "$TEMP\simutrans" Quit Delete "$Temp\$archievename" StrCmp $installinsimutransfolder "1" +3 CreateDirectory "$OUTDIR" CopyFiles /silent "$TEMP\Simutrans\*.*" "$OUTDIR" RMdir /r "$TEMP\simutrans" DownloadInstallZipSkipped: FunctionEnd ; $downloadlink is then name of the link, $downloadname the name of the pak for error messages Function DownloadInstallNoRemoveZip Call ConnectInternet RMdir /r "$TEMP\simutrans" ; since https fails with builtin NSISdl ... ; NSISdl::download $downloadlink "$TEMP\$archievename" ; Pop $R0 ;Get the return value ; StrCmp $R0 "success" +3 ; MessageBox MB_OK "Download of $archievename failed: $R0" ; Quit inetc::get /WEAKSECURITY $downloadlink "$Temp\$archievename" /END Pop $0 StrCmp $0 "OK" +4 MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit ; we need the magic with temporary copy only if the folder does not end with simutrans ... StrCmp $installinsimutransfolder "0" +4 nsisunz::Unzip "$TEMP\$archievename" "$OUTDIR\.." goto +2 nsisunz::Unzip "$TEMP\$archievename" "$TEMP" Pop $R0 ;Get the return value StrCmp $R0 "success" +5 MessageBox MB_OK|MB_ICONINFORMATION "$R0" /SD IDOK RMdir /r "$TEMP\simutrans" SetErrorLevel 5 Quit Delete "$Temp\$archievename" StrCmp $installinsimutransfolder "1" +3 CreateDirectory "$OUTDIR" CopyFiles /silent "$TEMP\Simutrans\*.*" "$OUTDIR" RMdir /r "$TEMP\simutrans" FunctionEnd ; $downloadlink is then name of the link, $downloadname the name of the pak for error messages Function DownloadInstallAddonZip # DetailPrint "Download of $downloadname from\n$downloadlink to $archievename" Call ConnectInternet RMdir /r "$TEMP\simutrans" ; since https fails with builtin NSISdl ... ; NSISdl::download $downloadlink "$TEMP\$archievename" ; Pop $R0 ;Get the return value ; StrCmp $R0 "success" +3 ; MessageBox MB_OK "Download of $archievename failed: $R0" ; Quit inetc::get /WEAKSECURITY $downloadlink "$Temp\$archievename" /END Pop $0 StrCmp $0 "OK" +4 MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit nsisunz::Unzip "$TEMP\$archievename" "$DOCUMENTS" Pop $R0 ;Get the return value StrCmp $R0 "success" +5 DetailPrint "$0" ;print error message to log Delete "$TEMP\$archievename" SetErrorLevel 5 Quit Delete "$Temp\$archievename" FunctionEnd ; $downloadlink is then name of the link, $downloadname the name of the pak for error messages Function DownloadInstallAddonZipPortable # DetailPrint "Download of $downloadname from\n$downloadlink to $archievename" Call ConnectInternet RMdir /r "$TEMP\simutrans" ; since https fails with builtin NSISdl ... ; NSISdl::download $downloadlink "$TEMP\$archievename" ; Pop $R0 ;Get the return value ; StrCmp $R0 "success" +3 ; MessageBox MB_OK "Download of $archievename failed: $R0" ; Quit inetc::get /WEAKSECURITY $downloadlink "$Temp\$archievename" /END Pop $0 StrCmp $0 "OK" +4 MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit nsisunz::Unzip "$TEMP\$archievename" "$OUTDIR\.." Pop $R0 ;Get the return value StrCmp $R0 "success" +5 DetailPrint "$0" ;print error message to log Delete "$TEMP\$archievename" SetErrorLevel 5 Quit Delete "$Temp\$archievename" FunctionEnd ; $downloadlink is then name of the link, $downloadname the name of the pak for error messages Function DownloadInstallZipWithoutSimutrans Call IsPakInstalledAndCurrent IntCmp $R0 2 DownloadInstallZipWithoutSimutransSkip IntCmp $R0 0 DownloadInstallZipWithoutSimutransDo SetOutPath $OUTDIR RMdir /r "$downloadname.old" Rename "$downloadname" "$downloadname.old" DetailPrint "Old $downloadname renamed to $downloadname.old" DownloadInstallZipWithoutSimutransDo: ; ok, now install DetailPrint "Download of $downloadname from\n$downloadlink to $archievename" Call ConnectInternet RMdir /r "$TEMP\simutrans" CreateDirectory "$TEMP\simutrans" # since we also want to download from addons ... inetc::get /WEAKSECURITY $downloadlink "$Temp\simutrans\$archievename" /END POP $0 StrCmp $0 "OK" +4 MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit ; remove all old files before! RMdir /r "$OUTDIR\$downloadname" CreateDirectory "$OUTDIR" DetailPrint "Unzip $archievename to $OUTDIR" nsisunz::Unzip "$TEMP\simutrans\$archievename" "$OUTDIR" Pop $R0 StrCmp $R0 "success" +5 Delete "$Temp\simutrans\$archievename" DetailPrint "$0" ;print error message to log SetErrorLevel 5 Quit RMdir /r "$TEMP\simutrans" DownloadInstallZipWithoutSimutransSkip: FunctionEnd Function DownloadInstallCabWithoutSimutrans DetailPrint "Download of $downloadname from $downloadlink to $archievename" Call IsPakInstalledAndCurrent IntCmp $R0 2 DownloadInstallCabWithoutSimutransSkip IntCmp $R0 0 DownloadInstallCabWithoutSimutransDo SetOutPath $OUTDIR RMdir /r "$downloadname.old" Rename "$downloadname" "$downloadname.old" DetailPrint "Old $downloadname renamed to $downloadname.old" DownloadInstallCabWithoutSimutransDo: ; ok, needs update RMdir /r "$TEMP\simutrans" CreateDirectory "$TEMP\simutrans" Call ConnectInternet inetc::get /WEAKSECURITY $downloadlink "$Temp\simutrans\$archievename" /END POP $0 StrCmp $0 "OK" +5 DetailPrint "Download error $R0" ;print error message to log MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit ; not supported with Unicode ;CabDLL::CabView "$TEMP\$archievename" DetailPrint "Install of $archievename to $OUTDIR" CreateDirectory "$OUTDIR\$downloadname" CreateDirectory "$OUTDIR\$downloadname\config" CreateDirectory "$OUTDIR\$downloadname\sound" CreateDirectory "$OUTDIR\$downloadname\text" CabX::FromFile "" "$TEMP\simutrans\$archievename" "$OUTDIR" ; for ANSI installer ;CabDLL::CabExtractAll "$TEMP\$archievename" "$OUTDIR" StrCmp $R0 "0" +6 DetailPrint "$0" ;print error message to log RMdir /r "$TEMP\simutrans" MessageBox MB_OK "Could not extract $TEMP\simutrans\$archievename" SetErrorLevel 5 Quit RMdir /r "$TEMP\simutrans" DownloadInstallCabWithoutSimutransSkip: FunctionEnd Function DownloadInstallTgzWithoutSimutrans # DetailPrint "Download of $downloadname from\n$downloadlink to $archievename" Call ConnectInternet RMdir /r "$TEMP\simutrans" CreateDirectory "$TEMP\simutrans" inetc::get /WEAKSECURITY $downloadlink "$Temp\simutrans\$archievename" /END POP $0 StrCmp $0 "OK" +5 DetailPrint "Download error $R0" ;print error message to log MessageBox MB_OK "Download of $archievename failed: $R0" /SD IDOK SetErrorLevel 3 Quit CreateDirectory "$OUTDIR" ; remove all old files before! RMdir /r "$OUTDIR\$downloadname" untgz::extract -d "$OUTDIR" "$TEMP\simutrans\$archievename" StrCmp $R0 "success" +4 RMdir /r "$TEMP\simutrans" MessageBox MB_OK "Extraction of $archievename failed: $R0" /SD IDOK SetErrorLevel 5 Quit RMdir /r "$TEMP\simutrans" FunctionEnd simutrans-124.3/src/Windows/nsis/pak128.txt000066400000000000000000000006761474050137200205300ustar00rootroot00000000000000Simutrans is copyright (C) 1997-2004 by Hansjoerg Malthaner. (c) 2004-2007 Simutrans Team >>>>>>>>>>> NO WARRANTIES, EXPRESS OR IMPLIED. <<<<<<<<<<< Have lots of fun playing Simutrans! The following paks are not OpenSource but Freeware. - pak64.german - pak64.HAJO - pak96.comic - pak128.german - pak192.comic - pak128 japan (has also sources available.) Commercial distribution without written permission of the author(s) is not permitted. simutrans-124.3/src/Windows/nsis/paksets.nsh000066400000000000000000000174671474050137200211530ustar00rootroot00000000000000; Generated by "get_pak.sh -generate_h". DO NOT EDIT. SectionGroup /e "Pak64: main and addons" pak64group Section /o "pak" pak AddSize 16177 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak64/124-3/simupak64-124-3.zip" SetOutPath $PAKDIR StrCpy $archievename "simupak64-124-3.zip" StrCpy $downloadname "pak" StrCpy $VersionString "pak64 124.3 r2182" Call DownloadInstallZip SectionEnd Section /o "pak64 Food addon" AddSize 228 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak64/121-0/simupak64-addon-food-120-4.zip" StrCpy $archievename "simupak64-addon-food-120-4.zip" StrCpy $downloadname "pak" StrCpy $VersionString "" StrCmp $multiuserinstall "1" +3 ; no multiuser => install in normal directory Call DownloadInstallAddonZipPortable goto +2 Call DownloadInstallAddonZip SectionEnd SectionGroupEnd Section /o "pak128" pak128 AddSize 415604 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak128/pak128%20for%20ST%20124.3up%20%282.10.0%29/simupak128-2-10-for124-3up.zip" SetOutPath $PAKDIR StrCpy $archievename "simupak128-2-10-for124-3up.zip" StrCpy $downloadname "pak128" StrCpy $VersionString "pak128 2.10.0 for 124.3 git r hash " Call DownloadInstallZip SectionEnd Section /o "pak192.comic" pak192.comic AddSize 909748 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak192.comic/pak192.comic%20V0.7.2/pak192-comic.zip" SetOutPath $PAKDIR StrCpy $archievename "pak192-comic.zip" StrCpy $downloadname "pak192.comic" StrCpy $VersionString "Pak192.Comic V0.7.2 Rev 1296" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pak64.german" pak64.german AddSize 28660 StrCpy $downloadlink "http://simutrans-germany.com/pak.german/pak64.german_0-124-0-0-5_full.zip" SetOutPath $PAKDIR StrCpy $archievename "pak64.german_0-124-0-0-5_full.zip" StrCpy $downloadname "pak64.german" StrCpy $VersionString "pak64.german 0.124.0.0.5" Call DownloadInstallZip SectionEnd Section /o "pak.japan" pak.japan AddSize 10175 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak64.japan/123-0/simupak64.japan-123-0.zip" SetOutPath $PAKDIR StrCpy $archievename "simupak64.japan-123-0.zip" StrCpy $downloadname "pak.japan" StrCpy $VersionString "pak64.japan 123 r2101" Call DownloadInstallZip SectionEnd Section /o "pak.nippon" pak.nippon AddSize 50198 StrCpy $downloadlink "https://github.com/wa-st/pak-nippon/releases/download/v0.6.2/pak.nippon-v0.6.2.zip" SetOutPath $PAKDIR StrCpy $archievename "pak.nippon-v0.6.2.zip" StrCpy $downloadname "pak.nippon" StrCpy $VersionString "pak.nippon v0.6.2" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pak128.CS" pak128.CS AddSize 78628 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/Pak128.CS/nightly%20builds/pak128.CS-r2096.zip" SetOutPath $PAKDIR StrCpy $archievename "pak128.CS-r2096.zip" StrCpy $downloadname "pak128.CS" StrCpy $VersionString "Pak128.CS 0.3.0 r2096" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pak128.Britain" pak128.Britain AddSize 241715 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak128.britain/pak128.Britain%20for%20120-3/pak128.Britain.1.18-120-3.zip" SetOutPath $PAKDIR StrCpy $archievename "pak128.Britain.1.18-120-3.zip" StrCpy $downloadname "pak128.Britain" StrCpy $VersionString "pak128.Britain 1.18 120.3 r1991" Call DownloadInstallZip SectionEnd Section /o "PAK128.german" PAK128.german AddSize 571188 StrCpy $downloadlink "http://pak128-german.de/PAK128.german_2.3_beta.zip" SetOutPath $PAKDIR StrCpy $archievename "PAK128.german_2.3_beta.zip" StrCpy $downloadname "PAK128.german" StrCpy $VersionString "Pak128.german VS 2.3.beta (Rev. 527)" Call DownloadInstallZip SectionEnd Section /o "pak144.Excentrique" pak144.Excentrique AddSize 7621 StrCpy $downloadlink "https://github.com/Varkalandar/pak144.Excentrique/releases/download/r0.08/pak144.Excentrique_v008.zip" SetOutPath $PAKDIR StrCpy $archievename "pak144.Excentrique_v008.zip" StrCpy $downloadname "pak144.Excentrique" StrCpy $VersionString "pak144.Excentrique v0.08" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pakTTD" pakTTD AddSize 1995 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pakTTD/simupakTTD-124-0.zip" SetOutPath $PAKDIR StrCpy $archievename "simupakTTD-124-0.zip" StrCpy $downloadname "pakTTD" StrCpy $VersionString "pak64 120.4.1 r2146" Call DownloadInstallZip SectionEnd Section /o "pak48.bitlit" pak48.bitlit AddSize 1762 StrCpy $downloadlink "http://codeberg.org/Nazalassa/pak48.bitlit/releases/download/0.1d/pak48.bitlit_0.1d.zip" SetOutPath $PAKDIR StrCpy $archievename "pak48.bitlit_0.1d.zip" StrCpy $downloadname "pak48.bitlit" StrCpy $VersionString "pak48.bitlit v0.1d" Call DownloadInstallZipWithoutSimutrans SectionEnd ; OBSOLETE PAKS from here SectionGroup /e "Not currently developed" slowPakgroup Section /o "pak96.comic" pak96.comic AddSize 32526 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak96.comic/pak96.comic%20for%20111-3/pak96.comic-0.4.10-plus.zip" SetOutPath $PAKDIR StrCpy $archievename "pak96.comic-0.4.10-plus.zip" StrCpy $downloadname "pak96.comic" StrCpy $VersionString "pak96.comic V4.1 plus" Call DownloadInstallZip SectionEnd Section /o "pak128.japan" pak128.japan AddSize 27780 StrCpy $downloadlink "http://pak128.jpn.org/souko/pak128.japan.120.0.cab" SetOutPath $PAKDIR StrCpy $archievename "pak128.japan.120.0.cab" StrCpy $downloadname "pak128.japan" StrCpy $VersionString "Pak128.Japan 120.0" Call DownloadInstallCabWithoutSimutrans SectionEnd Section /o "pak32" pak32 AddSize 3420 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak32.comic/pak32.comic%20for%20102-0/pak32.comic_102-0.zip" SetOutPath $PAKDIR StrCpy $archievename "pak32.comic_102-0.zip" StrCpy $downloadname "pak32" StrCpy $VersionString "" Call DownloadInstallZip SectionEnd Section /o "pak48.Excentrique" pak48.Excentrique AddSize 2016 StrCpy $downloadlink "https://github.com/Varkalandar/pak48.Excentrique/releases/download/v0.19_RC3/pak48.excentrique_v019rc3.zip" SetOutPath $PAKDIR StrCpy $archievename "pak48.excentrique_v019rc3.zip" StrCpy $downloadname "pak48.Excentrique" StrCpy $VersionString "pak48.Excentrique v0.19" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pakcontrast" pakcontrast AddSize 1440 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak64.contrast/pak64.Contrast_910.zip" SetOutPath $PAKDIR StrCpy $archievename "pak64.Contrast_910.zip" StrCpy $downloadname "pakcontrast" StrCpy $VersionString "" Call DownloadInstallZipWithoutSimutrans SectionEnd Section /o "pakHD" pakHD AddSize 12511 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/OldFiles/PakHD_v04B_100-0.zip" SetOutPath $PAKDIR StrCpy $archievename "PakHD_v04B_100-0.zip" StrCpy $downloadname "pakHD" StrCpy $VersionString "Martin" Call DownloadInstallZip SectionEnd Section /o "pakHAJO" pakHAJO AddSize 7460 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pakHAJO/pakHAJO_102-2-2/pakHAJO_0-102-2-2.zip" SetOutPath $PAKDIR StrCpy $archievename "pakHAJO_0-102-2-2.zip" StrCpy $downloadname "pakHAJO" StrCpy $VersionString "" Call DownloadInstallZip SectionEnd Section /o "pak64.scifi" pak64.scifi AddSize 3293 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/pak64.scifi/pak64.scifi_112.x_v0.2.zip" SetOutPath $PAKDIR StrCpy $archievename "pak64.scifi_112.x_v0.2.zip" StrCpy $downloadname "pak64.scifi" StrCpy $VersionString "pak64.SciFi V0.2" Call DownloadInstallZip SectionEnd SectionGroupEnd simutrans-124.3/src/Windows/nsis/preparation-functions.nsh000066400000000000000000000013511474050137200240140ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; ************************ Preparations for installer / downloader ************************** !include "MUI2.nsh" !include "Sections.nsh" VAR /Global PAKDIR VAR /Global USERDIR ; needs the following plugins: ; nsisunz ; inetc ; CabDll ; untgz ; ShellLink ; Parameter for functions var downloadlink var downloadname var archievename var VersionString var multiuserinstall var installinsimutransfolder XPStyle on !define MUI_ICON "..\stormoog.ico" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "simutranssmall.bmp" !define MUI_BGCOLOR 000000 !define MULTIUSER_MUI !define MULTIUSER_INSTALLMODE_COMMANDLINE !include MultiUser.nsh simutrans-124.3/src/Windows/nsis/simutrans-noadmin.nsi000066400000000000000000000156561474050137200231500ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; ************************************* Pakset downloader for simutrans ********************************************* ; needs the following plugins: ; nsisunz ; inetc ; CabX ; untgz ; ShellLink !define VERSION "0.124.3.0" RequestExecutionLevel user !define MULTIUSER_EXECUTIONLEVEL user VIProductVersion "${VERSION}" VIFileVersion "${VERSION}" VIAddVersionKey "ProductName" "Simutrans" ;VIAddVersionKey "Comments" "A test comment" VIAddVersionKey "CompanyName" "Simutrans Team" VIAddVersionKey "LegalCopyright" "Artistic License" VIAddVersionKey "FileDescription" "Simutrans installer (local user)" VIAddVersionKey "FileVersion" "${VERSION}" Unicode true var group1 Name "Simutrans Transport Simulator" OutFile "simutrans-online-install-noadmin.exe" InstallDir $LOCALAPPDATA\Simutrans !define MUI_UNICON "..\stormoog.ico" !include "preparation-functions.nsh" !include "languages.nsh" SectionGroup /e !Simutrans Function PostExeInstall WriteUninstaller $INSTDIR\uninstall.exe StrCmp $multiuserinstall "1" NotPortable ; just change to simuconf.tab "singleuser_install = 1" FileOpen $0 "$INSTDIR\config\simuconf.tab" a FileSeek $0 924 FileWrite $0 "singleuser_install = 1 " FileClose $0 goto finishGDIexe NotPortable: WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayName" "Simutrans - A transport simulator" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayIcon" "$\"$INSTDIR\uninstall.exe$\"" ; make start menu entries CreateDirectory "$SMPROGRAMS\Simutrans" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans.lnk" "$INSTDIR\Simutrans.exe" "" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans (Debug).lnk" "$INSTDIR\Simutrans.exe" "-log 1 -debug 3" finishGDIexe: FunctionEnd Section /o "Executable (GDI)" GDIexe AddSize 19612 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-124-3.zip" StrCpy $archievename "simuwin-124-3.zip" StrCpy $downloadname "Simutrans Executable (GDI)" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section "Executable (SDL2)" SDLexe AddSize 21988 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-sdl-124-3.zip" StrCpy $archievename "simuwin-sdl-124-3.zip" StrCpy $downloadname "Simutrans Executable (SDL2)" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section /o "Executable (GDI 64bit)" GDI64exe AddSize 18940 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-x64-124-3.zip" StrCpy $archievename "simuwin-x64-124-3.zip" StrCpy $downloadname "Simutrans Executable (GDI) only needed for huge maps" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section /o "Executable (SDL2 64bit)" SDL64exe AddSize 21128 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-x64-sdl-124-3.zip" StrCpy $archievename "simuwin-sdl-x64-124-3.zip" StrCpy $downloadname "Simutrans Executable (SDL2) only needed for huge maps" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd SectionGroupEnd Section "Uninstall" Delete $INSTDIR\Uninstall.exe ; delete self (see explanation below why this works) Delete "$SMPROGRAMS\Simutrans\Simutrans.lnk" Delete "$SMPROGRAMS\Simutrans\Simutrans (Debug).lnk" Delete $INSTDIR\Uninst.exe ; delete self (see explanation below why this works) RMDir /r $INSTDIR SetShellVarContext all StrCpy $PAKDIR "$LOCALAPPDATA\simutrans" SetShellVarContext current DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" MessageBox MB_YESNO "Remove global paksets from $PAKDIR?" /SD IDYES IDNO +2 RMDir /r $PAKDIR SectionEnd !include "paksets.nsh" ;************************** from here on other helper stuff ***************** !include "other-functions.nsh" ;********************* from here on special own helper functions ************ ; make sure, at least one executable is installed Function .onSelChange !insertmacro StartRadioButtons $9 !insertmacro RadioButton ${GDIexe} !insertmacro RadioButton ${SDLexe} !insertmacro RadioButton ${GDI64exe} !insertmacro RadioButton ${SDL64exe} !insertmacro EndRadioButtons test_for_pak: ; save last state of SDLexe selection SectionGetFlags ${SDLexe} $R0 IntOp $group1 $R0 & ${SF_SELECTED} ; Make sure at least some pak is selected SectionGetFlags ${pak} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.nippon} $R0 IntCmp $R0 ${SF_SELECTED} show_not ; SectionGetFlags ${pak64.ho-scale} $R0 ; IntOp $R0 $R0 & ${SF_SELECTED} ; IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakcontrast} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.scifi} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak96.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.britain} $R0 IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${PAK128.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.CS} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak192.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak144.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak32} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakTTD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.bitlit} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not ; not pak selected! MessageBox MB_OK|MB_ICONSTOP "At least 1 pak set must be selected!" /SD IDOK show_not: FunctionEnd simutrans-124.3/src/Windows/nsis/simutrans-offline.nsi000066400000000000000000000265031474050137200231360ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; Section define/macro header file ; See this header file for more info !include "MUI2.nsh" !include "Sections.nsh" !include "zipdll.nsh" ; Parameter for functions var downloadlink var downloadname var archievename var group1 var multiuserinstall ;******** This script assumes, you have installed all the paks and GDI exe to this directory ******* ;******** There should be also a folder SDL containing the SDL exe and DLL ******* ;******** There should be also a folder pak64addon containing the food chain addon ******* ;******** There should be also a folder pak64addon/font with the chinese font ******* !define SP_PATH "C:\Programme\simutrans" Name "Simutrans Transport Simulator" OutFile "simutrans-offline-install.exe" ; The default installation directory InstallDir $PROGRAMFILES\Simutrans XPStyle on ; Request application privileges for Windows Vista RequestExecutionLevel admin !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "simutranssmall.bmp" !define MUI_BGCOLOR 000000 !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "SpanishInternational" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "NorwegianNynorsk" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Catalan" ; we need to start with sections first for the second licence SectionGroup !Simutrans Function PostExeInstall StrCmp $multiuserinstall "1" NotPortable ; just change to simuconf.tab "singleuser_install = 1" FileOpen $0 "$INSTDIR\config\simuconf.tab" a FileSeek $0 924 FileWrite $0 "singleuser_install = 1 " FileClose $0 goto finishGDIexe NotPortable: ; make start menu entries CreateDirectory "$SMPROGRAMS\Simutrans" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans.lnk" "$INSTDIR\Simutrans.exe" "-log 1 -debug 3" finishGDIexe: ; uninstaller not working yet ;WriteUninstaller $INSTDIR\uninstaller.exe FunctionEnd Section "Executable (GDI, Unicode)" GDIexe SetOutPath $INSTDIR File "${SP_PATH}\simutrans.exe" File "${SP_PATH}\*.txt" File /r "${SP_PATH}\text" File /r "${SP_PATH}\font" File /r "${SP_PATH}\skin" File /r "${SP_PATH}\music" File /r "${SP_PATH}\config\simuconf.tab" SectionEnd Section /o "Executable (SDL, better sound)" SDLexe SetOutPath $INSTDIR File "${SP_PATH}\SDL\*.*" File "${SP_PATH}\*.txt" File /r "${SP_PATH}\text" File /r "${SP_PATH}\font" File /r "${SP_PATH}\skin" File /r "${SP_PATH}\music" File /r "${SP_PATH}\config\simuconf.tab" SectionEnd Section /o "Chinese Font" wenquanyi_font SetOutPath $INSTDIR File /r "${SP_PATH}\pak64addon\font" SectionEnd SectionGroupEnd SectionGroup "Pak64: main and addons" pak64group Section "!pak64 (standard)" pak64 SetOutPath $INSTDIR File /r "${SP_PATH}\pak" SectionEnd Section /o "pak64 Food addon 102.2.1" StrCmp $multiuserinstall "1" InstallInUserDir ; no multiuser => install in normal directory SetOutPath $INSTDIR goto FinishFood64 InstallInUserDir: SetOutPath $DOCUMENTS\simutrans FinishFood64: File /r "${SP_PATH}\pak64addon\pak" SectionEnd SectionGroupEnd Section /o "pak64.german (Freeware)" pak64german SetOutPath $INSTDIR File /r "${SP_PATH}\pak64.german" SectionEnd Section /o "pak64.japan" pak64japan SetOutPath $INSTDIR File /r "${SP_PATH}\pak.japan" SectionEnd Section /o "pak64.Nippon" pak64nippon SetOutPath $INSTDIR File /r "${SP_PATH}\pak.nippon" SectionEnd Section /o "pak64.HO (GPL)" pak64HO SetOutPath $INSTDIR File /r "${SP_PATH}\pak64.HO" SectionEnd Section /o "pak64.SciFi" pak64SF SetOutPath $INSTDIR File /r "${SP_PATH}\pak64.ScfFi" SectionEnd Section /o "pak64 HAJO (Freeware)" pak64HAJO SetOutPath $INSTDIR File /r "${SP_PATH}\pak.HAJO" SectionEnd Section /o "pak64 contrast (GPL)" pak64contrast SetOutPath $INSTDIR File /r "${SP_PATH}\pak.HAJO" SectionEnd Section /o "pak96 Comic (beta, Freeware)" pak96comic SetOutPath $INSTDIR File /r "${SP_PATH}\pak96.comic" SectionEnd Section /o "pak96 hand drawn" pak96HD SetOutPath $INSTDIR File /r "${SP_PATH}\pakHD" SectionEnd Section /o "pak128" pak128 SetOutPath $INSTDIR File /r "${SP_PATH}\pak128" SectionEnd Section /o "pak128 German" pak128german SetOutPath $INSTDIR File /r "${SP_PATH}\pak128.german" SectionEnd Section /o "pak128 Japan" pak128japan SetOutPath $INSTDIR File /r "${SP_PATH}\pak128.japan" SectionEnd Section /o "pak128 Britain" pak128britain SetOutPath $INSTDIR File /r "${SP_PATH}\pak128.britain" SectionEnd Section /o "pak192 Comic (Freeware)" pak192comic SetOutPath $INSTDIR File /r "${SP_PATH}\pak192.comic" SectionEnd Section /o "pak32 Comic (alpha)" pak32comic SetOutPath $INSTDIR File /r "${SP_PATH}\pak32.comic" SectionEnd # create a section to define what the uninstaller does. # the section will always be named "Uninstall" section "Uninstall" Delete $INSTDIR\uninstaller.exe RMDir /r $INSTDIR sectionEnd ;***************************************************** from here on come sections ***************************************** ; we just ask for Artistic licences, the other re only asked for certain paks PageEx license LicenseData "license.rtf" PageExEnd ; If not installed to program dir, ask for a portable installation Function CheckForPortableInstall StrCpy $multiuserinstall "1" StrCmp $INSTDIR $PROGRAMFILES\Simutrans NonPortable MessageBox MB_YESNO|MB_ICONINFORMATION "Should this be a portable installation?" IDYES Portable IDNO NonPortable Portable: StrCpy $multiuserinstall "0" NonPortable: FunctionEnd PageEx directory PageCallbacks "" "" CheckForPortableInstall PageExEnd PageEx components PageExEnd ; Some paksets don't have an open source license, so we have to show additional licences Function CheckForClosedSource SectionGetFlags ${pak64german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show SectionGetFlags ${pak64HAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show SectionGetFlags ${pak96comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show SectionGetFlags ${pak128} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show SectionGetFlags ${pak192comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show Abort show: ; here is ok FunctionEnd PageEx License LicenseData "pak128.txt" PageCallbacks CheckForClosedSource "" "" PageExEnd PageEx instfiles PageExEnd ; ******************************** From here on Functions *************************** Function .oninit StrCpy $multiuserinstall "1" ; activates GDI by default StrCpy $group1 ${GDIexe} ; Group 1 - Option 1 is selected by default ; avoids two instance at the same time ... System::Call 'kernel32::CreateMutexA(i 0, i 0, t "SimutransMutex") i .r1 ?e' Pop $R0 StrCmp $R0 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running." Abort FunctionEnd ; ConnectInternet (uses Dialer plug-in) ; Written by Joost Verburg ; ; This function attempts to make a connection to the internet if there is no ; connection available. If you are not sure that a system using the installer ; has an active internet connection, call this function before downloading ; files with NSISdl. ; ; The function requires Internet Explorer 3, but asks to connect manually if ; IE3 is not installed. Function ConnectInternet Push $R0 ClearErrors Dialer::AttemptConnect IfErrors noie3 Pop $R0 StrCmp $R0 "online" connected MessageBox MB_OK|MB_ICONSTOP "Cannot connect to the internet." Quit ;This will quit the installer. You might want to add your own error handling. noie3: ; IE3 not installed MessageBox MB_OK|MB_ICONINFORMATION "Please connect to the internet now." connected: Pop $R0 FunctionEnd ; make sure, at least one executable is installed Function .onSelChange !insertmacro StartRadioButtons $group1 !insertmacro RadioButton ${GDIexe} !insertmacro RadioButton ${SDLexe} !insertmacro EndRadioButtons ; make sure GDI is installed when chinese is selected SectionGetFlags ${wenquanyi_font} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} +1 test_for_pak ; force selection of GDI exe SectionGetFlags ${GDIexe} $R0 IntOp $R0 $R0 | ${SF_SELECTED} SectionSetFlags ${GDIexe} $R0 SectionGetFlags ${SDLexe} $R0 IntOp $R0 $R0 & ${SECTION_OFF} SectionSetFlags ${SDLexe} $R0 test_for_pak: ; Make sure at least some pak is selected SectionGetFlags ${pak64} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64HAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak96comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128britain} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak192comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak32comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not ; not pak selected! MessageBox MB_OK|MB_ICONSTOP "At least on pak set must be selected!" show_not: FunctionEnd ; $downloadlink is then name of the link, $downloadanme the name of the pak for error messages Function DownloadInstall ; MessageBox MB_OK|MB_ICONINFORMATION "Download of $downloadname from\n$downloadlink$archievename" Call ConnectInternet RMdir /r "$TEMP\simutrans" NSISdl::download $downloadlink$archievename "$Temp\$archievename" Pop $R0 ;Get the return value StrCmp $R0 "success" +3 MessageBox MB_OK "Download of $archievename failed: $R0" Quit ZipDLL::extractall "$TEMP\$archievename" "$TEMP" Pop $0 StrCmp $0 "success" exeok DetailPrint "$0" ;print error message to log RMdir /r "$TEMP\simutrans" Quit exeok: CreateDirectory "$INSTDIR" CopyFiles "$TEMP\Simutrans\*.*" "$INSTDIR" RMdir /r "$TEMP\simutrans" FunctionEnd simutrans-124.3/src/Windows/nsis/simutrans-store.nsi000066400000000000000000000060501474050137200226430ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; ************************************* Pakset downloader for simutrans ********************************************* ; needs the following plugins: ; nsisunz ; inetc ; CabX ; untgz ; ShellLink !define VERSION "0.124.0.0" RequestExecutionLevel user !define MULTIUSER_EXECUTIONLEVEL user VIProductVersion "${VERSION}" VIFileVersion "${VERSION}" VIAddVersionKey "ProductName" "Simutrans" ;VIAddVersionKey "Comments" "A test comment" VIAddVersionKey "CompanyName" "Simutrans Team" VIAddVersionKey "LegalCopyright" "Artistic License" VIAddVersionKey "FileDescription" "Simutrans installer (local user)" VIAddVersionKey "FileVersion" "${VERSION}" !define INSTALLSIZE 21412 !define HELPURL "http://forum.simutrans.com/" # "Support Information" link SilentInstall silent Unicode true var group1 Name "Simutrans Transport Simulator" OutFile "simutrans-store.exe" InstallDir $LOCALAPPDATA\Simutrans !define MUI_UNICON "..\stormoog.ico" !include "preparation-functions.nsh" !include "languages.nsh" Function PostExeInstall WriteUninstaller $INSTDIR\uninstall.exe WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayName" "Simutrans - A transport simulator" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayIcon" "$\"$INSTDIR\uninstall.exe$\"" ; make start menu entries CreateDirectory "$SMPROGRAMS\Simutrans" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans.lnk" "$INSTDIR\Simutrans.exe" "" FunctionEnd Section "Executable (SDL2)" SDLexe SetOutPath $INSTDIR File /r simuwin-sdl-124-0\Simutrans\*.* ; AddSize 21412 ; StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-0/simuwin-sdl-124-0.zip" ; StrCpy $archievename "simuwin-sdl-124-0.zip" ; StrCpy $downloadname "Simutrans Executable (SDL2)" ; SetOutPath $INSTDIR ; Call DownloadInstallZip Call PostExeInstall SectionEnd Section "Uninstall" Delete $INSTDIR\Uninstall.exe ; delete self (see explanation below why this works) Delete "$SMPROGRAMS\Simutrans\Simutrans.lnk" Delete "$SMPROGRAMS\Simutrans\Simutrans (Debug).lnk" Delete $INSTDIR\Uninst.exe ; delete self (see explanation below why this works) RMDir /r $INSTDIR SetShellVarContext all StrCpy $PAKDIR "$LOCALAPPDATA\simutrans" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" SetShellVarContext current MessageBox MB_YESNO "Remove global paksets from $PAKDIR?" /SD IDYES IDNO +2 RMDir /r $PAKDIR SectionEnd ; ******************************** From here on Functions *************************** Function .oninit StrCpy $USERDIR "$LOCALAPPDATA\simutrans" SetShellVarContext all StrCpy $PAKDIR "$LOCALAPPDATA\simutrans" ; SectionSetFlags SDLexe SetShellVarContext current FunctionEnd ;********************* from here on special own helper functions ************ simutrans-124.3/src/Windows/nsis/simutrans.nsi000066400000000000000000000162101474050137200215100ustar00rootroot00000000000000; ; This file is part of the Simutrans project under the Artistic License. ; (see LICENSE.txt) ; ; ************************************* Pakset downloader for simutrans ********************************************* ; needs the following plugins: ; nsisunz ; inetc ; CabX ; untgz ; ShellLink !define VERSION "0.124.3.0" VIProductVersion "${VERSION}" VIFileVersion "${VERSION}" VIAddVersionKey "ProductName" "Simutrans" ;VIAddVersionKey "Comments" "A test comment" VIAddVersionKey "CompanyName" "Simutrans Team" VIAddVersionKey "LegalCopyright" "Artistic License" VIAddVersionKey "FileDescription" "Simutrans installer (all users)" VIAddVersionKey "FileVersion" "${VERSION}" Unicode true ; Request application privileges for Windows Vista ;RequestExecutionLevel highest !define MULTIUSER_INSTALLMODE_INSTDIR "Simutrans" !define MULTIUSER_EXECUTIONLEVEL Highest var group1 Name "Simutrans Transport Simulator" OutFile "simutrans-online-install.exe" InstallDir $PROGRAMFILES\Simutrans !define MUI_UNICON "..\stormoog.ico" !include "preparation-functions.nsh" !insertmacro MULTIUSER_PAGE_INSTALLMODE !include "languages.nsh" SectionGroup /e !Simutrans Function PostExeInstall StrCmp $multiuserinstall "1" NotPortable ; just change to simuconf.tab "singleuser_install = 1" FileOpen $0 "$INSTDIR\config\simuconf.tab" a FileSeek $0 924 FileWrite $0 "singleuser_install = 1 " FileClose $0 goto finishGDIexe NotPortable: ; make start menu entries SetShellVarContext all CreateDirectory "$SMPROGRAMS\Simutrans" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans.lnk" "$INSTDIR\Simutrans.exe" "" CreateShortCut "$SMPROGRAMS\Simutrans\Simutrans (Debug).lnk" "$INSTDIR\Simutrans.exe" "-log 1 -debug 3" ExecWait 'Icacls "$PAKDIR" /grant Users:(OI)(CI)M' WriteUninstaller $INSTDIR\uninstall.exe WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayName" "Simutrans Game" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "DisplayIcon" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" finishGDIexe: FunctionEnd Section /o "Executable (GDI)" GDIexe AddSize 19612 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-124-3.zip" StrCpy $archievename "simuwin-124-3.zip" StrCpy $downloadname "Simutrans Executable (GDI)" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section "Executable (SDL2)" SDLexe AddSize 21988 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-sdl-124-3.zip" StrCpy $archievename "simuwin-sdl-124-3.zip" StrCpy $downloadname "Simutrans Executable (SDL2)" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section /o "Executable (GDI 64bit)" GDI64exe AddSize 18940 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-x64-124-3.zip" StrCpy $archievename "simuwin-x64-124-3.zip" StrCpy $downloadname "Simutrans Executable (GDI) only needed for huge maps" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd Section /o "Executable (SDL2 64bit)" SDL64exe AddSize 21128 StrCpy $downloadlink "http://downloads.sourceforge.net/project/simutrans/simutrans/124-3/simuwin-x64-sdl-124-3.zip" StrCpy $archievename "simuwin-sdl-x64-124-3.zip" StrCpy $downloadname "Simutrans Executable (SDL2) only needed for huge maps" SetOutPath $INSTDIR Call DownloadInstallZip Call PostExeInstall SectionEnd SectionGroupEnd Section "Uninstall" SetShellVarContext all Delete $INSTDIR\Uninst.exe ; delete self (see explanation below why this works) Delete "$SMPROGRAMS\Simutrans\Simutrans.lnk" Delete "$SMPROGRAMS\Simutrans\Simutrans (Debug).lnk" Delete $INSTDIR\Uninst.exe ; delete self (see explanation below why this works) RMDir /r $INSTDIR SetShellVarContext all StrCpy $PAKDIR "$LOCALAPPDATA\simutrans" SetShellVarContext current DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Simutrans" MessageBox MB_YESNO "Remove global paksets from $PAKDIR?" /SD IDYES IDNO +2 RMDir /r $PAKDIR SectionEnd !include "paksets.nsh" ;************************** from here on other helper stuff ***************** !include "other-functions.nsh" ;********************* from here on special own helper functions ************ ; make sure, at least one executable is installed Function .onSelChange !insertmacro StartRadioButtons $9 !insertmacro RadioButton ${GDIexe} !insertmacro RadioButton ${SDLexe} !insertmacro RadioButton ${GDI64exe} !insertmacro RadioButton ${SDL64exe} !insertmacro EndRadioButtons test_for_pak: ; save last state of SDLexe selection SectionGetFlags ${SDLexe} $R0 IntOp $group1 $R0 & ${SF_SELECTED} ; Make sure at least some pak is selected SectionGetFlags ${pak} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHAJO} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak.nippon} $R0 IntCmp $R0 ${SF_SELECTED} show_not ; SectionGetFlags ${pak64.ho-scale} $R0 ; IntOp $R0 $R0 & ${SF_SELECTED} ; IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakcontrast} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak64.scifi} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak96.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakHD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.japan} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.britain} $R0 IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${PAK128.german} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak128.CS} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak192.comic} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak144.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.Excentrique} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak32} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pakTTD} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not SectionGetFlags ${pak48.bitlit} $R0 IntOp $R0 $R0 & ${SF_SELECTED} IntCmp $R0 ${SF_SELECTED} show_not ; not pak selected! MessageBox MB_OK|MB_ICONSTOP "At least 1 pak set must be selected!" /SD IDOK show_not: FunctionEnd simutrans-124.3/src/Windows/nsis/simutranssmall.bmp000066400000000000000000000645161474050137200225420ustar00rootroot00000000000000BMNi6(9i:9630-) &#"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%bSI{hX|iY}jZ~kZ~l[m\€n]o^‚p_ƒq`ƒsa„tb…uc†vd‡weˆxe‰zfŠ{g‹|hŒ}iŒ~jkŽl‚mƒn&&&&&&&&&&>;;;;;;;9741-* '""%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%zgW{hX|iY}jZ~k[~l[m\€n]o^‚p_ƒr`„sa„tb…uc†vd‡weˆyf‰zfŠ{g‹|hŒ}i~jkŽl‚mƒn&&&&&&&&&&;99;;;;;;;;;;;;;;;:77:0/:(': :;;;;;;;;;;;;8741 -!!)#"%$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%('&yfVzgW{hX|iY}jZ~k[~l[m\€n]o^‚q_ƒr`„sa…tb…uc†vd‡xeˆyf‰zgŠ{h‹|iŒ}jjŽ€kŽl‚mƒn&&&&&&&&>-,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77:..:&&; ;;;<=>?@ABBC D!E"F#G$ G%!G%!D'#?'$;'$6'%1'&,&%&%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%QF>yeUyfVzgW{hX|iY}jZ~l[~l[m\€n]p^‚q_ƒr`„sa…tb†uc†wd‡xeˆyf‰zgŠ{h‹|iŒ~jkŽ€ll‚mƒn&&&&&&&;"!;00;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:55;/.=)(?$"B D D!E"F#G$ H%!H'"I(#J)$K*%L+&M,'N-(O/)P0*Q1+Q2,R3-S5.T6/U70R60L4/E2-?/+8-*1+)*'&%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%TG?wbSxdTyeUzfVzgW{hX|iY}kZ~l[l[m\€o]p^‚q_ƒr`„sa…tb†vc‡wdˆxeˆyf‰zgŠ{h‹}iŒ~jkŽ€lm‚ntpX&&&&&&&& ';;;;;;:!!:.-;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::9998887776665554443332221111/.6-+;+)@*'G*&L+&M,'N.(O/)P0*Q1+R2,S4-S5.T6/U70V81W92X:3Y<4Z=5[>5\?6\@7]A8^C9_D:`E;aF]E6\?7]@8]B9^C9_D:`E;aFcI?dJ@eLAfMBgNBhOCiPDjQEkRFkTGlUHmVInWJoXKpZLq[Mr\Ns]Os^Pt_Qu`RvbSwcTxdUyeVzfW{gW|iX}jY}kZ~l[m\€n]o^‚p_‚q`ƒra„tb…ub†vc‡wdˆxe‰yfŠ{g‹|h‹}iŒ~jkŽ€l‚mƒn&&&&&&&&&üõëüõêüôéüôèüôçÁ¯¦w[V;;;;;;;;;::)):55;;;;;;;;;;;;:::999888777666555444333333222111000///...---,,,+++***)))((('''&&&%%%$$$###"""!!! @/*X;3Y<4Z=5[>6\?7]A8^B9^C:_D;`EcI?dK@eLAfMBgNChODiPEjQEkSFlTGlUHmVInWJoYKpZLq[Mr\Ns]Ot^Pu_QvaRvbSwcTxdUyeVzfW{hX|iY}jZ~kZl[m\€n]o^‚p_ƒq`ƒsa„tb…uc†vd‡weˆxe‰zfŠ{g‹|hŒ}iŒ~jkŽl‚mƒn&&&&&&&&üôçüóæûóåûòäûòãûñâûñáûðàûðßûïÞÖŶŒqiE ;;;;;;;<==<)(:32888777666555444333333222111000///...---,,,+++***)))(((&&&%%%$$$###"""!!! C0*X;3Y<4Z=5[?6\@7]A8^B9_C:`D;`EcH>dJ?eK@eLAfMBgNChODiQEjRFkSGlTHmUInVInWJoYKpZLq[Mr\Ns]Ot_Pu`QvaRwbSwcTxdUyeVzgW{hX|iY}jZ~k[l\m\€n]o^‚q_ƒr`„sa„tb…uc†vd‡weˆyf‰zgŠ{g‹|hŒ}ij€kŽl‚mefL&&&&&&&ûòäûñãûñáûðàûðßûïÞûïÝúïÜúîÛúîÚúíÙúíØúì×úìÖúëÕéÙÄ¡ˆ{Y72;;<=>?@AABA!<('7.-410111000///...---,,,+++***)))((('''&&&%%%$$$###"""!!! G1,X;3Y<4Z>5[?6\@7]A8^B9_C:`D;aFcI>dJ?eK@fLAfMBgNChPDiQEjRFkSGlTHmUInVJoXKoYLpZMq[Mr\Ns^Ot_Pu`QvaRwbSxcTxdUyfVzgW{hX|iY}jZ~k[m\m\€n]p^‚q_ƒr`„sa…tb…uc†vd‡xeˆyf‰zgŠ{h‹|iŒ}jjŽ€kl‚m *('&&&&ûðàûðßûïÞúïÝúîÜúîÛúíÙúíÙúì×úìÖúëÕùëÔùêÓùêÒùéÑùéÐùéÏùèÎùèÍùçÍöåɶž‹pPG?@ABCC D!E"F#G$ G%!H&"C)%:+(0,++++***)))((('''&&&%%%$$$###"""!!! K3-Y;3Z=4Z>5[?6\@7]A8^B9_C:`E;aFcI>dJ?eK@fLAgMBgOChPDiQEjRFkSGlTHmVInWJoXKpYLpZMq[Nr]Os^Ot_Pu`QvaRwbSxcTyeUyfVzgW{hX|iY}jZ~l[m\m\€o]p^‚q_ƒr`„sa…tb†vc‡wdˆxeˆyf‰zgŠ{hhaXLLLLLLicZmm + *))(' &&&úîÛúíÚúíÙúìØúì×úìÖúëÕùêÔùêÓùêÒùéÑùéÐùèÏùèÍùçÍøçËøæËøæÉøåÉøåÇøäÇøäÆøãÅ÷ãÄ÷ãÃ˳š‡i\H$!E!E#F# G$ H%!I'"I(#J)$K*%L+&M,'N.(I-(<+(.'&%%%$$$###"""!!! N5/Y<4Z=4[>5[?6\@7]A8^C9_D:`E;aFcI>dJ?eK@fLAgOCkTIhPDiQEjRFkSGlUHmVInWJoXKpYLqZMr\Nr]Os^Pt_Qu`RvaRwcSxdTyeUzfV{gW{hX|iY}kZ~l[m\€n]€o]p^‚q_ƒr`„sa…ub†vc‡wdˆxe‰yf‰zgZVRyyym$> - , , + *(('&&&úìØúì×úëÕùëÔùêÓùêÒùéÑùéÐùèÏùèÎùçÍøçÌøæËøæÊøåÉøåÈøäÇøäÆøãÅ÷ãÄ÷ãÃ÷âÂ÷âÁ÷áÀ÷á¿÷à¾÷à½÷ß¼òÞ¿íÞÄíÝŸ¢z]SI'"J(#J)$K*%L+&M-'N.(O/)P0*Q1+R2,S4-S5.O4-@.*.&$S81Y<4Z=5[>6\?7\@7]B8^C9_D:`E;aFcI?dJ@eKAfMAo[Q}qlЇ††~{ngq\PnWJoXKpYLqZMr\Ns]Os^Pt_Qu`RvbSwcTxdUyeVzfV{gW|hX|jY}kZ~l[m\€n]o^p_‚q_ƒr`„ta…ub†vc‡wdˆxe‰yf€rcmmm€ve 0 0 / . -+ + *)('ùëÔùêÓùêÒùéÑùéÐùèÏùèÎùçÍøçËøæÊøæÉøåÈøåÇøäÆøäÅøãÄ÷ãÃ÷âÂ÷âÁ÷áÀ÷á¿÷à¾÷à½÷ß¼öß»öÞºöÞ¹öÞ¸öÝ·öݶõܶíÜÂìÜÂëÛÁëÛÁíھѶ”’s^T5-N.(O/)P0*Q1+R3,S4-T5.T6/U70V81W:2X;3Y<4Z=5[>6\?7]A8^B9^C9_D:`E;aFcI?dJ@eLAfMBgNChODiPEjQEkSFlTGtbX€vp‹‰ˆˆ„skvbVt^Pu_QuaRvbSwcTxdUyeVzfW{hX|iY}jY~kZ~l[m\€n]o^‚p_‚q`ƒsa„tb…ub†vc‡wdˆxe‰zfONM> 3 2 1 0 . . - , + *ùéÑùéÐùèÏùèÍùçÌøçËøæÊøæÉøåÈøäÇøäÆøãÅ÷ãÃ÷âÂ÷âÁ÷áÀ÷á¿÷à¾÷à½÷à¼öß»öÞºöÞ¹öÞ¸öÝ·öݶöܵöÜ´öÛ³õÛ²õÛ±õÚ±óÚ²ëÚ¿ëÚ¿ëÙ¿êÙ¿êÙ¿ïײôשôÖ¨äÆœ§ˆljK>S4-T5.U6/V70V91W:2X;3Y<4Z=5[>6\@7]A8^B9_C:_D;`EdI?dK@eLAiRHŒŠ‰ƒ{xtbZjRFkSGlTGmUHmVInWJoYKpZLq[Myi^ƒzt‹‹Š†ƒ‚xp{j]yeVzgW{hX|iY}jZ~k[l\m\€n]o^‚p_ƒr`ƒsa„tb…uc†vd‡weˆyfŠqLLL‹‹‹ 6 5 4 3 1 1 0 / . -ùçÍøçËøæÊøæÉøåÈøäÇøäÆøãÅ÷ãÃ÷âÂ÷âÁ÷áÀ÷á¿÷à¾÷à½÷ß¼öß»öÞ¹öÞ¸öÝ·öݶöܵöÜ´öÛ³õÛ²õÚ±õÚ°õÙ¯õÙ®õÙ®õØ­õجõ׫ò×®êØ½êØ½éØ½é׽騽ëÖ·óÔ£ôÓ¢óÓ¢óÓ¡óÒ ðϺšv`LX:2X;3Y<4Z=5[?6\@7]A8^B9_C:`D;aFcI?dJ?eK@eLAfMBgNChODr_V‚yu„|xve]nXJoYKpZLq[Mr\Ns]Ot_Pu`QvaRwbS|ma„zt‹ˆ†ŒŠˆ‡€y„wmqb€n]€n]o^‚q_ƒr`„sa…tb…uc…vd‹…}Œ„yLKK@ 8 7 6 5 4 3 2 1 0 0øæÉøåÈøåÇøäÆøãÅ÷ãÃ÷âÂ÷âÁ÷áÀ÷á¿÷à¾÷à½÷ß»öߺöÞ¹öÞ¸öÝ·öݶöܵöÜ´õÛ³õÛ±õÚ°õÚ°õÙ®õÙ­õجõØ«ôתôתôÖ©ôÖ¨ôÕ§ôÕ¦ôÕ¥ðÕ«é×»èÖ»è×»èÖ»èÖ»çÖ»îÒ¨óÑœóМóЛóÏšòÏ™òϘòΗòΖ˩}“sY^B8]A8^B9_C:`E;aFcI?dJ?eK@fLAfMBgNChPDiQEjRFkSGlTHmUIwg^…{†€||nes_Pt_Pu`QvaRwbSxcTyeUyfVzgW{hX|iY}jZsf†}t‹…€Œ‰†ŽŒŠˆ‹†€‡zhˆyf‰zg|simmm0H, ; : 9 8 7 6 5 4 3 3øäÅøãÄ÷ãÃ÷âÁ÷áÀ÷á¿÷à¾÷à½÷ß¼öߺöÞ¹öÞ¸öÝ·öݶöܵöÛ³õÛ²õÚ±õÚ°õÙ¯õÙ®õØ­õجõ׫ôתôÖ©ôÖ¨ôÕ¦ôÕ¦ôÕ¥ôÔ¤ôÔ£óÓ¢óÓ¡óÒ óÒŸïÒ¨èÕ¹èÕ¹èÕ¹çÕ¹çÕºæÕºéÓ±ñΗòÍ–òÍ•òÍ”òÌ“òÌ’òÌ‘ñËñËñÊñÊŽÜ·¥„boSDbG=cH>dI?dJ?eK@fLAgMBhOChPDiQEjRFkSGlTHmVInWJoXKpYLqZMq[NweZwp‹ˆ‡Ž†~yqeyeUzfVzgW{hX|iY}kZ~l[m\€n]€o]p^‚q_ƒr`„sa…tb†vc‡wdˆxe‰~oŽŽŽŒ†}‹}iueG> = < ; 9 9 8 7 7 6 3 2 1÷âÂ÷âÁ÷áÀ÷á¾÷à½÷ß¼öß»öÞºöÞ¸öÝ·öݶöܵöÜ´õÛ³õÚ±õÚ°õÙ¯õÙ®õØ­õجôתôשôÖ¨ôÖ§ôÕ¦ôÕ¥ôÔ¤ôÔ£ôÓ¢óÓ¡óÒ óÒŸóÑžóÑóМóЛóКòÏ™íѦçÔ¸çÔ¸æÔ¸æÔ¸æÔ¹æÔ¹æÔ¹ìΡñËñÊñÊŽñÉñÉŒñÉ‹ñÈŠñÈŠñȉðLjðLJðLJðƆêÁ‚Ñ«v|[jPCgNBhOCiPDiQEjRFkSGlUHmVInWJoXKpYLqZMr\Nr]Os^Pt_Qu`RvaSwcT}m`‚xoˆƒ~ŽŽŽŽŠ†‚‡w†|r…ynƒwkƒuf‚sb„vg†zm‰t‹…~Ž‹‹€t‰zgŠ|h‹}iHA@?> < < ; ; : 9 8 7 6 5 4÷á¿÷à¾÷à½÷ß»öߺöÞ¹öÞ¸öÝ·öܵöÜ´öÛ³õÛ²õÚ±õÚ¯õÙ®õØ­õجõ׫ôתôÖ¨ôÖ§ôÕ¦ôÕ¥ôÔ¤ôÔ£óÓ¢óÓ óÒŸóÒŸóÑžóÑœóМóКòÏ™òϘòΗòΖòÍ•òÍ”òÌ“ìЦæÓ¶æÓ·åÓ·åÓ·åÓ¸åÓ¸äÓ¹æÑ²ïÉŽðljðLjðLJðƆðÆ…ðÆ„ðÅ„ðŃðÄ‚ðÄðÄ€ïÄ€ïÀïÃïÃ~ïÂ}àµv®‹a}aMkTGlUHmVInWJoXKpZLq[Mr\Ns]Os^Pt_Qu`RvbSwcTxdUyeVzfV{gW|iX}jY}kZ~l[m\p`ƒsd„wj…xl„vh…ve…ub†vc‡wdˆxe‰yfŠ{gŠ{gEDCBA@?? > = < ; : 9 8 7öß»öÞºöÞ¹öÝ·öݶöܵöÜ´õÛ²õÚ±õÚ°õÙ¯õÙ®õجõØ«ôתôÖ©ôÖ¨ôÕ¦ôÕ¥ôÔ¤ôÔ£óÓ¢óÓ óÒŸóÒžóÑóМóЛóКòÏ™òϘòΗòΖòÍ•òÍ”òÌ’òÌ‘ñËñËñÊŽñÊêϦåÓ¶åÒ¶åÓ¶äÒ·äÓ¸äÒ¸äÓ¸ãÓ¹éÌ ðŃðÄ‚ðÄïÀïÃïÃ~ïÂ~ïÂ}ïÂ|ïÁ|ïÁ{ïÁzïÀyïÀyïÀxî¿wî¿wî¿vî¿vë»t¾—dŽqUpZLq[Mr\Ns]Ot^Pu_QvaRvbSwcTxdUyeVzfW{hX|iY}jZ~kZl[m\€o]o^‚p_ƒq`ƒsa„tb…uc†vd‡weˆxe‰zf^iDHGFDDCBBA@? > = < ; :öÞ¹öÝ·öݶöܵöÛ³õÛ²õÚ±õÚ°õÙ®õØ­õجõ׫ôשôÖ¨ôÖ§ôÕ¦ôÔ¤ôÔ£óÓ¢óÓ¡óÒ óÒžóÑóМóЛóÏšòϘòϘòΗòÍ–òÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÉñÉŒñÈŠñÈŠðLjðLJèΧäÒµäÒ¶äÒ¶äÒ·ãÒ·ãÒ¸ãÒ¹âÒ¹ãÑ·ìÅŠïÁ|ïÁ{ïÁzïÀyïÀxî¿xî¿wî¿vî¿vî¾uî¾tî¾sî½sî½rî½qî¼qî¼pí¼pí»oí»ní»ní»mÌ¢eŸYvaQvaRwbSwcTxdUyeVzgW{hX|iY}jZ~k[l\€n]€o^o^‚q_ƒr`„sa„tb…uc†vd‡wexsYLKJIHGGFEDCBA@?> =öܵöÛ³õÛ²õÚ±õÚ°õÙ®õØ­õجôתôשôÖ¨ôÕ§ôÕ¥ôÔ¤ôÔ£óÓ¢óÓ óÒŸóÑžóÑóЛóКòÏ™òϘòΖòÍ•òÍ•òÍ”òÌ’ñË‘ñËñÊñÊŽñÉñÉ‹ñÈŠñȉðLjðLJðƆðÆ…ðÅ„ðŃðÄ‚çΩãѶãѶãÑ·ãÒ·ãÒ¸âÒ¹âÒ¹âÒºáÒ»å̤í¿vî¾uî¾tî¾sî½sî½rî¼qî¼pí¼pí»oí»ní»míºmíºlíºkí¹kí¹jí¹jí¹ií¸hí¸hí¸hì¸gì¸gì·fÚªc®‹\ƒmWzgW{hX|iY}jZ~k[m\€n]o^p^‚q_ƒr`„sa…tb…uc›dЩXONMLKJJIGGFEDCBA@?õÛ²õÚ±õÚ°õÙ®õØ­õجôתôשôÖ¨ôÕ§ôÕ¥ôÔ¤ôÔ£óÓ¡óÒ óÒŸóÑžóÑœóЛóÏšòϘòΗòΖòÍ•òÍ”òÌ’òÌ’ñËñËñÊŽñÉñÉŒñÈŠñȉðLjðLJðƆðÆ…ðÅ„ðÅ‚ðÄïÄ€ïÃïÃ~ïÂ}îÁ|åάãѶãѶâÑ·âѸâÒ¹âÒ¹áÒºáÒ»áÒ¼áÒ¼éÉí»oí»ní»ní»míºlíºkí¹jí¹jí¹ií¸hí¸gì¸gì·fì·eì·eì¶dì¶dì¶cì¶cìµbìµbìµaìµaìµ`é¼vÜÜÜÜÜÜØ××½¸´­¥§œ“šŒ~¤t­‘k¾—^΢^ë´^±šF߯Zë´_ë´_>ePONNMLKJIHGFEDCBõÙ¯õÙ®õجõ׫ôתôÖ¨ôÖ§ôÕ¦ôÔ¤ôÔ£óÓ¢óÒ óÒŸóÑžóÑœóЛòÏšòϘòΗòΖòÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÉŒñÉ‹ñÈŠðljðLJðƆðÆ…ðÅ„ðŃðÄïÄ€ïÃïÂ~ïÂ}ïÁ|ïÁzïÀyïÀxî¿wí¿wãίâѶâÑ·âѸáѹáѹáѺáÒ»àÒ¼àÒ½àÓ¾àÓ¾çËí¸hí¸hì¸gì·fì·eì¶dì¶dì¶cìµbìµaìµaìµ`ì´_ë´_ë´^ë³^ë³]ë³]ë³\äÄ“ÜÛØÜÛÚÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜäÂë±Yë±Yë±Yë±Yë±Y$] %\ ã®Wë²ZRRQPONMLKJIHGFFõØ­õØ«ôתôÖ©ôÖ§ôÕ¦ôÔ¤ôÔ£óÓ¢óÓ óÒŸóÑžóÑœóЛóÏšòϘòΗòΖòÍ”òÌ“òÌ’ñË‘ñËñÊŽñÉñÉŒñÉ‹ñÈŠðLjðLJðƆðÆ„ðŃðÄ‚ðÄïÀïÃ~ïÂ}ïÁ|ïÁ{ïÀzïÀxî¿wî¿vî¾uî¾tî½rî½qí¼râϲáÑ·áѸáѹáѺàѺàÒ»àÒ½àÒ¾àÒ¾ßÓ¿ßÓÀáϳé»uìµbìµaìµ`ì´_ë´^ë³^ë³]ë³\ë²[ë²[ë²Zë±Yæ½à϶ÜÚÖÜÚ×ÜÚØÜÛÚÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜæ¹uê¯Tê¯Tê¯Tê¯Tê¯Tê¯Tê¯TWVVew$TSRQPONMLKJJIFEDôשôÖ¨ôÕ§ôÕ¥ôÔ¤ôÓ¢óÓ¡óÒ óÒžóÑóМóКòÏ™òΘòΖòÍ•òÍ”òÌ’ñË‘ñËñÊŽñÉñÉŒñÈŠñÈŠðLjðLJðƆðÆ„ðŃðÄ‚ðÄ€ïÃïÃ~ïÂ}ïÁ{ïÁzïÀyîÀxî¿vî¾uî¾tî½sî½rî¼pí¼oí»ní»míºlìºqáеáиáѹàѺàÑ»àÒ¼àÒ½ßÒ¾ßÒ¿ßÓÀßÓÁßÓÂÞÔÃÞÔÅÞÕÆÞÕÇßѼàиÞÔÄÝ×ÌÝ×ÍÝ×ÏÝØÐÜØÒÜÙÓÜÙÕÜÚÖÜÚØÜÛÙÜÛÚÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛÚé­Pê¬Oê¬Oê¬Oê¬Oê¬Oê¬Oê¬Oê¬O¢‘6YXWVUTSRQPONMMLKJIHGôÖ¨ôÕ¦ôÕ¥ôÔ£óÓ¢óÓ¡óÒŸóÑžóÑœóЛòÏšòϘòΗòÍ–òÍ”òÌ“òÌ‘ñËñÊñÊñÉŒñÈ‹ñȉðLjðLJðƆðÆ„ðŃðÄ‚ðÄ€ïÃïÃ~ïÂ}ïÁ{ïÁzïÀyî¿wî¿vî¾uî¾tî½rî¼qî¼pí»oí»míºlíºkí¹jí¸hí¸gì·fêºoàиàѺàÑ»àÒ¼ßÒ½ßÒ¾ßÒ¿ßÒÀßÓÁÞÓÂÞÔÄÞÔÄÞÔÆÞÕÇÝÕÉÝÖÊÝÖËÝ×ÌÝ×ÎÝØÐÝØÑÜØÒÜÙÔÜÙÕÜÚÖÜÚØÜÛÚÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ㿉éªJéªJéªJéªIéªIéªIéªIéªIéªIéªJéªJ&a ZYXWVUTSRQQPONMLKJIôÔ¤ôÔ£óÓ¢óÒ óÒŸóÑóМóЛòÏ™òϘòΖòÍ•òÍ”òÌ’ñË‘ñËñÊŽñÉñÉ‹ñÈŠðLjðLJðƆðÆ…ðÅ„ðÅ‚ðÄïÀïÃ~ïÂ}ïÁ|ïÁzïÀyî¿xî¿vî¾uî¾tî½rî¼qî¼pí»ní»míºlí¹jí¹ií¸hì¸gì·fì¶dì¶cìµbìµaé¹pßѺßѼßÒ½ßÒ½ßÒ¾ßÒÀßÓÁÞÓÂÞÔÃÞÔÅÞÔÆÞÕÇÝÕÉÝÖÊÝÖÌÝ×ÍÝ×ÎÝØÐÜØÑÜØÒÜÙÔÜÚÖÜÚ×ÜÛÙÜÛÚÜÜÜÜÜÜÜÜÜÝÕÈé¨Fè¨Eè¨Eè¨Eè¨Dè¨Dè§Dè§Dè§Dè§Dè¨Dè¨Dè¨Eè¨E[[ZYXWVUUTSRQPONMLôÔ¤ôÓ¢óÓ¡óÒ óÑžóÑóЛóÏšòϘòΗòÍ–òÍ”òÌ“òÌ‘ñËñÊŽñÊñÉŒñÈŠñȉðLjðƆðÆ…ðÅ„ðŃðÄïÀïÃïÂ}ïÁ|ïÁzïÀyîÀxî¿vî¾uî¾tî½rî¼qî¼pí»ní»míºlí¹jí¹ií¸hì¸gì·eì¶dì¶cìµbìµaì´_ë³^è¹qßѼßѼßÒ½ßÒ¿ßÒ¿ÞÓÁÞÓÂÞÔÄÞÔÄÞÔÆÞÕÇÝÕÉÝÖÊÝÖËÝ×ÍÝ×ÏÝØÐÜØÑÜÙÓÜÙÕÜÚÖÜÚ×ÜÛÙÜÛÛÜÜÜÜÜÜÝÔÇç¨Fè§Cè§Cè§Bè§Bè¦Bè¦Bè¦Bè¦Aè¦Aè¦Aè¦Bè¦Bè§Bè§B^ [[ZYXWWVUTSRQPONMóÓ¡óÒ óÑžóÑóЛóÏšòϘòΗòÍ–òÍ”òÌ“ñË‘ñËñÊŽñÉñÉŒñÈŠðljðLJðƆðÆ„ðŃðÄ‚ðÄïÀïÃ~ïÂ}ïÁ{ïÁzïÀxî¿wî¿vî¾tî½sî½rî¼pí»oí»níºlíºkí¹jí¸hì¸gì·eì¶dì¶cìµbìµ`ì´_ë³^ë³\ë²[ë²Zë±Yçºuá˪ßÒ¾ÞÒÀÞÓÁÞÓÂÞÓÄÞÔÅÞÔÆÝÕÇÝÕÉÝÖÊÝÖÌÝ×ÍÝ×ÏÜØÐÜØÒÜÙÔÜÙÕÜÚ×ÜÚÙÜÛÚÜÜÜÞѾç¥@è¥?è¥?è¥>è¤>è¤=ç¤=ç¤=ç¤<ç¤<ç¤<ç¤<ç¤<ç¤<ç¤=ç¤=è¤=â¡;[[[[[ZYXWVUTSRQPóÒžóÑóЛóКòϘòΗòÍ–òÍ”òÌ“òÌ‘ñËñÊŽñÉñÉŒñÈŠðljðLJðƆðÅ„ðŃðÄ‚ðÄïÃïÂ~ïÂ|ïÁ{ïÀzïÀxî¿wî¾uî¾tî½sî¼qî¼pí»ní»míºlí¹jí¹ií¸gì·fì·eì¶cìµbìµaì´_ë³^ë³]ë²[ë²Zë±Yë°Wê°Vê¯Uê¯Té®TàβÞÓÁÞÓÃÞÓÄÞÔÅÝÔÆÝÕÈÝÕÊÝÖËÝÖÌÝ×ÎÜ×ÐÜØÑÜØÒÜÙÔÜÚÖÜÚ×ÜÛÙ⿊ç¤=ç¤<ç£;ç£:ç£:ç¢9ç¢9ç¢8ç¢8ç¢7ç¡7ç¡7ç¡7ç¡7ç¡7ç¡7ç¢7ç¢8ç¢8ç¢9Fk[[[[[[ZYXWVUTSóÑóМóКòÏ™òΗòΖòÍ”òÌ“òÌ’ñËñÊñÊñÉŒñÈŠñȉðLJðƆðÆ„ðŃðÄ‚ïÄ€ïÃïÃ~ïÂ|ïÁ{ïÀzïÀxî¿wî¾uî¾tî½rî¼qí¼pí»níºmíºkí¹jí¸hì¸gì·fì¶dì¶cìµaìµ`ë´_ë³]ë³\ë²[ë±Yë±Xê°Vê¯Uê¯Tê®Rê®Rê­Pê­Oè­QáÈ£ÞÔÄÝÔÆÝÔÇÝÕÈÝÕÊÝÖÌÝÖÍÝ×ÎÜ×ÐÜØÒÜÙÓÜÙÕàÆæ£<ç£:ç¢9ç¢8ç¢7ç¡7ç¡6ç 5æ 4æ 4æ 3æŸ3æŸ2æŸ2æŸ2æŸ2æŸ2æŸ2æŸ2æŸ2æŸ3æŸ3æ 4æ 4[[[[[[[[ZYXWWVóЛòÏšòϘòΗòÍ•òÍ”òÌ’ñË‘ñËñÊŽñÉŒñÉ‹ñȉðLjðƆðÆ…ðÅ„ðÄ‚ðÄïÃïÃ~ïÂ}ïÁ|ïÁzïÀxî¿wî¿vî¾tî½sî½qî¼pí»ní»míºlí¹jí¹iì¸gì·fì¶dì¶cìµaìµ`ë´_ë³]ë²\ë²Zë±Yë°Wê°Vê¯Uê¯Sê®Rê­Pê­Pê¬Né¬Mé«KéªJéªIè©Iäº{àÇŸßÌ®ÞϸßÌ®àÇ¢ã¸væ§Eç£;ç£:ç¢9ç¢8ç¡7ç¡5æ 4æ 3æŸ2æŸ1æž1æž0æž/æ.æ.æ-æ-æ-æœ-æœ-æœ-æ-æ-æ.æ.æž/æž0jv[[[[[[[[[[ZYòÏ™òΗòΖòÍ”òÌ“òÌ’ñËñÊñÊñÉŒñÈŠðljðLJðƆðÅ„ðŃðÄïÀïÃ~ïÂ~ïÂ|ïÁ{ïÀyîÀxî¿vî¾uî¾sî½rî¼pí»oí»míºlí¹jí¹ií¸hì·fì·eì¶cìµbìµ`ì´_ë³]ë³\ë²[ë±Yë±Xê°Vê¯Uê¯Sê®Rê­Pê­Oê¬Né¬Mé«KéªJé©Hé©Gé¨Fè§Dè§Cè¦Aè¥@è¥?è¤=ç¤<ç£:ç¢9ç¢8ç¡6ç 5æ 4æŸ2æŸ1æž0æž/æ.æœ-åœ+åœ+å›*å›)å›(åš(åš(åš'åš'åš'åš(åš(å›)å›)å›*åœ+[[[[[[[[[[[òΗòÍ–òÍ”òÌ“ñË‘ñËñÊŽñÉñÉ‹ñÈŠðLjðLJðÆ…ðÅ„ðÄ‚ðÄïÃïÂ~ïÂ}ïÁ|ïÁzïÀyî¿wî¿vî¾tî½sî½qî¼pí»ní»míºkí¹jí¸hì¸gì·eì¶dì¶cìµaì´`ë´^ë³]ë²[ë²Zë±Xë°Wê¯Uê¯Tê®Rê­Qê­Oé¬Né¬Mé«LéªJéªIé©Gé¨Fè¨Dè§Cè¦Aè¦@è¥?è¤=ç¤<ç£:ç¢9ç¡7ç¡6æ 5æŸ3æŸ2æž0æž/æ-åœ,åœ+å›)åš(åš'å™&å™%ä˜$ä˜#ä˜#ä˜"ä˜"ä˜"ä˜#ä˜#å™%å™%åš'[[[[[[[[[[òÍ•òÍ”òÌ’ñË‘ñËñÊŽñÉŒñÉ‹ñÈŠðLjðƆðÆ…ðÅ„ðÄ‚ðÄïÃïÂ~ïÂ}ïÁ{ïÁzïÀxî¿wî¿vî¾tî½rî¼qí¼pí»níºmíºkí¹jí¸hì¸gì·eì¶dì¶bìµaì´_ë³^ë³\ë²[ë±Yë±Xê°Vê¯Uê¯Sê®Rê­Qê­Oé¬Mé¬Mé«KéªJé©Hé©Gè¨Eè§Dè§Bè¦Aè¥?è¥>ç¤=ç£;ç¢9ç¢8ç¡7ç 5æ 4æŸ2æž1æž/æ.åœ,åœ+å›)åš(åš&å™%ä˜#ä˜"ä—!ä–ä–ä•ä•ä–ä–ä— ä—"ä˜#å™%[[[[[[[[[òÍ•òÍ”òÌ’ñË‘ñËñÊŽñÉŒñÉ‹ñÈŠðLjðLJðÆ…ðÅ„ðÄ‚ðÄïÃïÂ~ïÂ}ïÁ|ïÁzïÀxî¿wî¿vî¾tî½sî¼qí¼pí»níºmíºkí¹jí¸hì¸gì·eì¶dì¶bìµaì´_ë³^ë³\ë²[ë±Yë±Xë°Wê¯Uê¯Sê®Rê­Qê­Oé¬Né¬Mé«KéªJéªIé©Gè¨Eè§Dè§Cè¦Aè¥@è¥>ç¤=ç£;ç£:ç¢8ç¡7ç¡5æ 4æŸ2æŸ1æž/æ.æœ-åœ+å›*å›(åš'å™%å™$ä˜#ä—!ä— ä— ä–ä–ä–ä— ä—!ä˜#å˜$[[[[[[[[òÍ”òÌ“òÌ‘ñËñÊŽñÉñÉ‹ñÈŠðLjðLJðÆ…ðÅ„ðÅ‚ðÄïÀïÃ~ïÂ}ïÁ|ïÁzïÀyî¿wî¿vî¾tî½sî½rî¼pí»ní»míºlí¹jí¹iì¸gì·fì¶dì¶cìµaì´`ë´^ë³]ë²[ë²Zë±Yë°Wê°Vê¯Tê®Sê®Qê­Pê¬Né¬Né«LéªKéªIé©Hé¨Fè¨Eè§Cè¦Bè¦Aè¥?è¤>ç¤<ç£;ç¢9ç¢8ç¡7ç¡5æ 4æŸ2æŸ1æž0æ.æ-åœ,åœ+å›)å›(åš'åš&å™&å™%å™%å™$å™$å™%å™%å™%åš&[[[[[[òÌ“òÌ’ñËñÊñÊñÉŒñÈŠñȉðLJðƆðÆ„ðŃðÄ‚ïÀïÃïÂ~ïÂ|ïÁ{ïÀzïÀxî¿vî¾uî¾tî½rî¼qí¼oí»níºlíºkí¹ií¸hì¸fì·eì¶dì¶bìµaì´_ë³^ë³\ë²[ë±Yë±Xë°Wê¯Uê¯Tê®Rê­Qê­Oê¬Oé¬Mé«LéªKéªIé©Hé¨Fè¨Eè§Cè§Bè¦Aè¥?è¥>ç¤=ç£;ç£:ç¢9ç¢7ç¡6ç 5æ 4æŸ3æŸ1æž0æž/æ.æ-æœ,åœ,åœ+å›*å›*å›*å›*å›*å›*å›*å›*[[[[[[òÌ’ñË‘ñËñÊŽñÉñÉ‹ñÈŠðLjðLJðÆ…ðÅ„ðÅ‚ðÄïÀïÃïÂ}ïÁ|ïÁzïÀyî¿xî¿vî¾uî½sî½rî¼pí»oí»míºlí¹jí¹ií¸hì·fì·eì¶cìµbìµaì´_ë³^ë³\ë²[ë±Yë±Xë°Wê¯Uê¯Tê®Sê®Qê­Qê­Oé¬Né«Lé«KéªJé©Hé©Gé¨Fè¨Dè§Cè¦Bè¦Aè¥?è¥>ç¤=ç¤<ç£:ç¢9ç¢8ç¡7ç¡6ç 5æ 4æ 3æŸ2æŸ2æŸ1æž0æž0æž/æž/æž/æž/æž/æž/æž/[[[[òÌ’ñËñÊñÊŽñÉŒñÈ‹ñȉðLjðƆðÆ…ðÅ„ðÄ‚ðÄïÀïÃ~ïÂ}ïÁ|ïÁzïÀyî¿wî¿vî¾tî½sî½rî¼pí»oí»míºlí¹jí¹ií¸hì·fì·eì¶dì¶bìµaì´_ë´^ë³]ë²[ë²Zë±Yë°Wê°Vê¯Uê¯Sê®Sê®Qê­Pê¬Oé¬Mé«Lé«KéªIé©Hé©Gé¨Fè¨Eè§Cè§Bè¦Aè¦@è¥?è¥>ç¤=ç¤<ç£;ç£:ç¢9ç¢8ç¢8ç¡7ç¡6ç¡6ç¡5ç 5æ 5æ 4æ 4æ 4æ 4æ 4[[[[òÌ’ñËñÊñÊŽñÉŒñÈ‹ñȉðLjðƆðÆ…ðÅ„ðÄ‚ðÄïÀïÃ~ïÂ}ïÁ|ïÁzïÀyî¿xî¿vî¾uî¾sî½rî¼pí¼oí»níºlíºkí¹jí¸hì¸gì·fì¶dì¶cìµaìµ`ë´_ë³]ë³\ë²[ë²Zë±Xë°Wê°Vê¯Uê¯Tê®Sê®Qê­Pê­Oé¬Né«Mé«KéªJéªIé©Hé©Gé¨Fè¨Eè§Dè§Cè¦Bè¦Aè¦@è¥?è¥>è¤>ç¤=ç¤<ç¤<ç£;ç£;ç£:ç£:ç£:ç¢9ç¢9ç¢9ç¢9[[ñËñÊñÊŽñÉŒñÈ‹ñȉðLjðƆðÆ…ðÅ„ðŃðÄ‚ïÄ€ïÃïÂ}ïÂ|ïÁ{ïÀyïÀxî¿vî¾uî¾tî½rî¼qî¼pí»ní»míºlí¹jí¹ií¸hì¸fì·eì¶dì¶cìµaìµ`ë´_ë³]ë³\ë²[ë²Zë±Yë±Xë°Wê°Vê¯Tê¯Sê®Rê­Qê­Pê¬Oé¬Né¬Mé«LéªKéªJéªIé©Hé©Gé¨Fè¨Eè¨Eè§Dè§Cè§Bè¦Bè¦Aè¦Aè¦@è¥@è¥?è¥?è¥?è¥?è¥?è¥?[ñË‘ñËñÊŽñÉŒñÉ‹ñÈŠðLjðLJðƆðÆ…ðÅ„ðÄ‚ðÄïÃïÃ~ïÂ}ïÁ{ïÁzïÀyî¿wî¿vî¾uî¾sî½rî¼qí¼pí»ní»míºlí¹jí¹ií¸hì¸fì·eì¶dì¶cìµbìµaì´_ë´^ë³]ë²\ë²[ë²Zë±Yë±Xë°Wê°Vê¯Uê¯Sê®Sê®Qê­Qê­Pê¬Oé¬Né¬Mé«Lé«KéªKéªJéªIé©Hé©Hé©Gé©Gé¨Fé¨Fè¨Eè¨Eè¨Eè¨Dè§Dè§DñË‘ñËñÊŽñÊñÉŒñÈŠñȉðLjðLJðƆðÅ„ðŃðÄ‚ðÄ€ïÃïÂ~ïÂ|ïÁ{ïÁzïÀxî¿wî¿vî¾uî¾sî½rî¼qí¼pí»ní»míºlí¹kí¹jí¸hì¸gì·fì·eì¶dì¶cìµaìµ`ì´_ë´_ë³]ë³]ë²[ë²Zë±Yë±Xë°Wë°Wê°Uê¯Uê¯Tê®Sê®Rê®Qê­Qê­Pê­Oê¬Né¬Né¬Mé«Mé«Lé«Ké«Ké«KéªJéªJéªJéªIéªIòÌ’ñË‘ñËñÊŽñÉñÉ‹ñÈŠñȉðLjðLJðÆ…ðÅ„ðŃðÄ‚ïÄ€ïÃïÂ~ïÂ|ïÁ{ïÁzïÀyî¿wî¿vî¾uî¾tî½rî½qî¼pí»oí»níºmíºlí¹jí¹ií¸hì¸gì·fì·eì¶dì¶cì¶bìµaìµ`ì´_ë´^ë³]ë³\ë²[ë²[ë²Zë±Yë±Xë°Wë°Wê°Vê¯Uê¯Tê¯Tê¯Sê®Sê®Rê®Qê­Qê­Qê­Pê­Pê­Oê­Oê­OòÌ’ñËñÊñÊŽñÉŒñÉŒñÈ‹ñȉðLjðLJðƆðÅ„ðŃðÄ‚ðÄ€ïÃïÃ~ïÂ}ïÁ|ïÁzïÀyïÀxî¿wî¿vî¾tî¾sî½rî¼qî¼pí»oí»níºmíºlí¹kí¹jí¸hí¸hì¸fì·fì·eì¶dì¶cì¶bìµaìµaì´`ì´_ë´^ë³]ë³]ë³\ë²[ë²Zë²Zë±Yë±Yë±Xë°Wë°Wê°Vê°Vê°Vê¯Uê¯Uê¯Uê¯TòÌ“òÌ’ñËñÊñÊŽñÊñÉŒñÉ‹ñÈŠðLjðLJðƆðÆ…ðÅ„ðÄ‚ðÄïÀïÃïÂ~ïÂ|ïÁ{ïÁzïÀyïÀxî¿wî¿vî¾uî¾tî½rî½rî¼pí¼oí»ní»míºlíºlí¹jí¹jí¹ií¸hí¸gì¸fì·fì·eì¶dì¶cì¶cìµbìµaìµ`ì´`ì´_ë´_ë³^ë³]ë³]ë³\ë³\ë²[ë²[ë²[ë²Zë²ZòÌ“òÌ’òÌ‘ñËñÊñÊŽñÉñÉ‹ñÈŠñȉðLjðLJðƆðÆ„ðŃðÄ‚ðÄïÀïÃïÂ~ïÂ|ïÁ|ïÁzïÀyïÀxî¿wî¿vî¾uî¾tî¾sî½rî½qî¼pí¼pí»oí»ní»míºlíºlíºkí¹jí¹ií¸hí¸hì¸gì·fì·fì·eì·eì¶dì¶cì¶cì¶bìµbìµaìµaìµaìµ`ì´`ì´_òÍ”òÌ“òÌ’ñË‘ñËñÊñÊñÉŒñÉ‹ñÈŠñȉðLjðLJðƆðÆ„ðŃðÄ‚ðÄïÄ€ïÃïÃ~ïÂ}ïÂ|ïÁ{ïÁzïÀyïÀxî¿wî¿vî¿vî¾uî¾tî½sî½rî½rî¼qî¼pí¼oí»ní»ní»míºlíºlíºkí¹jí¹jí¹ií¹ií¸hí¸hì¸gì¸gì·fì·fì·eì·eòÍ•òÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÉŒñÉ‹ñÈŠñȉðLjðLJðƆðÆ…ðÅ„ðŃðÄ‚ðÄïÀïÃïÃ~ïÂ}ïÂ|ïÁ|ïÁ{ïÁzïÀyïÀxî¿wî¿wî¿vî¾uî¾tî¾tî½sî½rî½rî¼qî¼pî¼pí¼oí»oí»ní»ní»míºlíºlíºlíºkíºkòΖòÍ•òÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÉñÉŒñÉ‹ñÈŠñȉðLjðLJðƆðÆ…ðÅ„ðŃðÅ‚ðÄ‚ðÄïÀïÃïÃ~ïÂ}ïÂ|ïÁ|ïÁ{ïÁzïÁzïÀyïÀxîÀxî¿wî¿vî¿vî¾uî¾uî¾tî¾tî½sî½rî½rî½rî¼qî¼qòΗòΖòÍ•òÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÉñÉŒñÉ‹ñÈŠñȉðLjðLjðLJðƆðÆ…ðÅ„ðŃðÅ‚ðÄ‚ðÄïÄ€ïÀïÃïÃ~ïÂ~ïÂ}ïÂ|ïÁ|ïÁ{ïÁ{ïÁzïÀzïÀyïÀxïÀxî¿wî¿wòÏ™òΘòΗòΖòÍ•òÍ”òÌ“òÌ’ñË‘ñËñÊñÊŽñÊñÉñÉŒñÉ‹ñÈŠñȉðLjðLjðLJðƆðƆðÆ…ðÆ„ðÅ„ðŃðÅ‚ðÄ‚ðÄðÄïÀïÃïÃïÃ~ïÂ~ïÂ}ïÂ}òÏ™òϘòΗòΖòÍ•òÍ”òÌ“òÌ“òÌ’ñË‘ñËñËñÊŽñÊŽñÉñÉŒñÉŒñÉ‹ñÈŠñȉñȉðLjðLjðLJðLJðƆðÆ…ðÆ…ðÅ„ðÅ„òÏ™òÏ™òϘòΗòΖòÍ•òÍ”òÍ”òÌ“òÌ’òÌ’ñË‘ñËñËñÊñÊŽñÊŽñÊñÉŒñÉŒñÉ‹ñÉ‹simutrans-124.3/src/Windows/old.ico000066400000000000000000000056661474050137200172630ustar00rootroot00000000000000 è& ¨( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿùðÿÿöÿÿðÿÿöföÿùÿÿööföfÿÿöföoöffööfÿÿÿffföoÿ÷ÿffÿÿ÷÷ðÿÿ÷÷ÿ÷÷ÿÿ÷ÿƒÿÿûHƒ»»f`€û¿{ff€¿{ëãff@{ë»»vffHë»6;fvff`€»8Œffffff€ŒfÈÆffvfkfȈ†Æff{;ˆ†ˆÆfk눈wÆc»ˆw‡xfkxˆˆ€ˆˆ€ÿÿþÿÿøÿÿ€ÿÿ€ÿþÿþÿþÿþÿþÿÿÿÿ€ÿ?À?üðÿðÿÿðÿÿð?ÿðÿðÿðÿðÿøÿüÿÿÿÿÀÿÿðÿÊÐÿêÕÿÚÿÿÊÕÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @@€ÿ @ € ÿ @@@€@ÿ@`@`€`ÿ`€@€€€ÿ€ @ € ÿ À@À€ÀÿÀÿ@ÿ€ÿÿÿ @ € ÿ @ € ÿ @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ @@@€@ÿ@ @@ @€ @ÿ @@@@@@€@@ÿ@@`@@`@€`@ÿ`@€@@€@€€@ÿ€@ @@ @€ @ÿ @À@@À@€À@ÿÀ@ÿ@@ÿ@€ÿ@ÿÿ@`@`€`ÿ` `@ `€ `ÿ `@`@@`€@`ÿ@```@``€``ÿ``€`@€`€€`ÿ€` `@ `€ `ÿ `À`@À`€À`ÿÀ`ÿ`@ÿ`€ÿ`ÿÿ`€@€€€ÿ€ €@ €€ €ÿ €@€@@€€@€ÿ@€`€@`€€`€ÿ`€€€@€€€€€ÿ€€ €@ €€ €ÿ €À€@À€€À€ÿÀ€ÿ€@ÿ€€ÿ€ÿÿ€ @ € ÿ   @  €  ÿ  @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ À@À€ÀÿÀ À@ À€ Àÿ À@À@@À€@Àÿ@À`À@`À€`Àÿ`À€À@€À€€Àÿ€À À@ À€ Àÿ ÀÀÀ@ÀÀ€ÀÀÿÀÀÿÀ@ÿÀ€ÿÀÿÿÀÿ@ÿ€ÿÿÿ ÿ@ ÿ€ ÿÿ ÿ@ÿ@@ÿ€@ÿÿ@ÿ`ÿ@`ÿ€`ÿÿ`ÿ€ÿ@€ÿ€€ÿÿ€ÿ ÿ@ ÿ€ ÿÿ ÿÀÿ@Àÿ€ÀÿÿÀÿÿÿ@ÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿ ÿ ÿÿÿèÿÿÿÿÿ ÿ ÿ ÿÿÿÿÿÿ ÿ ÿÿ ÿÿ ÿ ÿÿÿÿÿÿ ÿ ÿ ÿÿÿÿ¶¶ÿÿÿ ÿ ÿÿÿÿÿ¶¶ÿÿ¶¶ÿÿÿÿÿÿÿ¶¶ÿÿ¶¶ÿÿÿÿÿ¶¶ÿÿ¶¶ÿÿÿÿÿÿ¶¶ÿÿÿIIÿÿÿÿþÔ&I$$IøøøÔ)))$IþøøþwÔ))))Møþwø;Ô;))))&Iwø;øøÔÔÔw)))))&I$$;øøø*Ô))w))))))$IøøOO+**))))))))))MOO+**+O+*))))w))))Ô**+OOOO*+*))))wÔÔOOO*O„OO+*)))Ô;ÔO„OOOOÛ—+*)ÔÔOOÛ—O—ÛO**)Ô—ÛOOOOOOOOOOOÿÿþÿÿøÿÿ€ÿÿ€ÿþÿþÿþÿþÿþÿÿÿÿ€ÿ?À?üðÿðÿÿðÿÿð?ÿðÿðÿðÿðÿøÿüÿÿÿÿÀÿÿðÿÊÐÿêÕÿÚÿÿÊÕÿÿÿÿÿÿÿÿÿÿÿÿÿÿsimutrans-124.3/src/Windows/simres.rc000066400000000000000000000017631474050137200176330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* ICON and Version info for Simutrans Windows */ #include #include "../simutrans/simversion.h" 100 ICON "stormoog.ico" 101 ICON "simutrans.ico" 102 ICON "old.ico" 1 VERSIONINFO FILEVERSION RES_VERSION_NUMBER PRODUCTVERSION RES_VERSION_NUMBER { BLOCK "StringFileInfo" { BLOCK "040904E4" { VALUE "CompanyName", "Simutrans Team" VALUE "FileDescription", "Simutrans" VALUE "FileVersion", VERSION_NUMBER VALUE "InternalName", "SIMUTRANS" VALUE "LegalCopyright", "\251 Hj. Malthaner '97-'04 Simutrans Team '05-'13" VALUE "OriginalFilename", "SIMUTRANS.EXE" VALUE "ProductName", "Simutrans" VALUE "ProductVersion", VERSION_NUMBER } } BLOCK "VarFileInfo" { VALUE "Translation", 2057, 1252, 1031, 1252, 1035, 1252, 1036, 1252, 1034, 1252, 1038, 1252, 1043, 1252 } } CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "Simutrans.manifest" simutrans-124.3/src/Windows/simutrans.ico000066400000000000000000000042761474050137200205260ustar00rootroot00000000000000 ¨( @€@€ÿ @ € ÿ @@@€@ÿ@`@`€`ÿ`€@€€€ÿ€ @ € ÿ À@À€ÀÿÀÿ@ÿ€ÿÿÿ @ € ÿ @ € ÿ @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ @@@€@ÿ@ @@ @€ @ÿ @@@@@@€@@ÿ@@`@@`@€`@ÿ`@€@@€@€€@ÿ€@ @@ @€ @ÿ @À@@À@€À@ÿÀ@ÿ@@ÿ@€ÿ@ÿÿ@`@`€`ÿ` `@ `€ `ÿ `@`@@`€@`ÿ@```@``€``ÿ``€`@€`€€`ÿ€` `@ `€ `ÿ `À`@À`€À`ÿÀ`ÿ`@ÿ`€ÿ`ÿÿ`€@€€€ÿ€ €@ €€ €ÿ €@€@@€€@€ÿ@€`€@`€€`€ÿ`€€€@€€€€€ÿ€€ €@ €€ €ÿ €À€@À€€À€ÿÀ€ÿ€@ÿ€€ÿ€ÿÿ€ @ € ÿ   @  €  ÿ  @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ À@À€ÀÿÀ À@ À€ Àÿ À@À@@À€@Àÿ@À`À@`À€`Àÿ`À€À@€À€€Àÿ€À À@ À€ Àÿ ÀÀÀ@ÀÀ€ÀÀÿÀÀÿÀ@ÿÀ€ÿÀÿÿÀÿ@ÿ€ÿÿÿ ÿ@ ÿ€ ÿÿ ÿ@ÿ@@ÿ€@ÿÿ@ÿ`ÿ@`ÿ€`ÿÿ`ÿ€ÿ@€ÿ€€ÿÿ€ÿ ÿ@ ÿ€ ÿÿ ÿÀÿ@Àÿ€ÀÿÿÀÿÿÿ@ÿÿ€ÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwwwwwwwww wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwÛÄwwwwwwwwwwwwÄÄýÄÄwwwwwÄÄÿm’ÄÛwwwwÄÄÿm’’mmýwwwwwwÄÄÿm’’’’m’wwwwwwwwÄÄÿm’’mmÛ’mwwwwwwwwÿm’’mm’mm’mwwwwwwww`’’mmm’’mmÛÛmwwwwwwÄ„ììm’mmm’’’mm’mmwwwwÄÄÄ„`mmmmmm’’ÛmÛ’’wwwwwÄ„m’$mÛmmm’’Û’’’mm’www’wwww„mm’$mÛm’Û’’’mmwwwwwww’wwwwwwmmm’$mmm’ÛÛmwwwwwwwwwwwwwwm’’’$mÛÛmmmwwwwwwwwwwwwwwwm$Û$Ûmmmmmmwwwwwmwww wwwwm’mmmmmmwwwwm’’mm wwww$$mmwwwww’’$$’ wwwww$wwwww$$$$wwwwwwwwwwwwwwww$wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwÿãÇÿÿÁƒÿÿÁƒÿùàœðÀààðàüðü?À˜üðÀààÀ€€>üðÐððÀùàƒŸÿáÃÿÿáÃÿÿóçÿsimutrans-124.3/src/Windows/stormoog.ico000066400000000000000000000173661474050137200203560ustar00rootroot00000000000000@@(& ¨N(@€@€ÿ @ € ÿ @@@€@ÿ@`@`€`ÿ`€@€€€ÿ€ @ € ÿ À@À€ÀÿÀÿ@ÿ€ÿÿÿ @ € ÿ @ € ÿ @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ @@@€@ÿ@ @@ @€ @ÿ @@@@@@€@@ÿ@@`@@`@€`@ÿ`@€@@€@€€@ÿ€@ @@ @€ @ÿ @À@@À@€À@ÿÀ@ÿ@@ÿ@€ÿ@ÿÿ@`@`€`ÿ` `@ `€ `ÿ `@`@@`€@`ÿ@```@``€``ÿ``€`@€`€€`ÿ€` `@ `€ `ÿ `À`@À`€À`ÿÀ`ÿ`@ÿ`€ÿ`ÿÿ`€@€€€ÿ€ €@ €€ €ÿ €@€@@€€@€ÿ@€`€@`€€`€ÿ`€€€@€€€€€ÿ€€ €@ €€ €ÿ €À€@À€€À€ÿÀ€ÿ€@ÿ€€ÿ€ÿÿ€ @ € ÿ   @  €  ÿ  @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ À@À€ÀÿÀ À@ À€ Àÿ À@À@@À€@Àÿ@À`À@`À€`Àÿ`À€À@€À€€Àÿ€À À@ À€ Àÿ ÀÀÀ@ÀÀ€ÀÀÿÀÀÿÀ@ÿÀ€ÿÀÿÿÀÿ@ÿ€ÿÿÿ ÿ@ ÿ€ ÿÿ ÿ@ÿ@@ÿ€@ÿÿ@ÿ`ÿ@`ÿ€`ÿÿ`ÿ€ÿ@€ÿ€€ÿÿ€ÿ ÿ@ ÿ€ ÿÿ ÿÀÿ@Àÿ€ÀÿÿÀÿÿÿ@ÿÿ€ÿÿÿÿÿ$$$ $ $$$$$ $$ $  $$$$$ -nmmnmn-nqnmnqnrmrmrnnrnrn$$ $$$ $$ $$ $$ $$$$  -mm-n-nmnm.mrnmnmrnnrmrnqnr $ $$$ $$$$$ $$ $  $$-m.mnmnm.mnmnnmnnrnmrmnrnrnr$$$ $$$ $$ $$  $ $$$$m-mnm-n-nmrmnqnqnqnmrnnrnqnrn$$$$$$ $ $$$$$$$$$ $$%m-nm.m-nmnmnmnmnmnnnmrnmrmrnrnq%%%%-%-e%-$%$%$$%$$$%$m-ne.mm.mmnmn-nm.mnmrmrmrnqnrnrnqnm%-%-e%-%-%m%-e--e-.e-n-m-m-m.mm.m.mnmnmn1nmnmnnmnrnqnrnr$%%-%%-e-e-%m%-e-m%m-m-e.m.m.mm.mnmm.mnmnmnnmrnqnqnmrnqnr%-%%-%-%-%m-%m-e--m-e.m-mm-mn-mmn-nmnm2mnrmrnmnrnnrnrnrm%%m%-e-%m%-e--%-e.e-m-m-m.mn-nm.mmn-nmnmnmnmnmrnmrmnmrn$%-%-%%%-%-e-%m%m-m-n%m.en-m-mm.mm.mnmnmnmrmrnrnqnmmmmnm%%%%m%-mmm-%m-m-%m%m-m-m-mmn-nm.mnmnm.mrmnnmnmnn-m’’qm-%-%-%-%mmnm’nmnmm-m-m-n-n-n-mm.mmn-nmnm.nmrmrnqmm’’’Žm%%-e-%m%-%-e-mnmrŽrnmmm-mmn-nmn-nmn-nqnmrmnnmn-’r’’,%-%%%-%m’mm-e-m-e-m.mnqŽrmrmnm-mnmnmnmnmnmnnqnqm’’Ž’‘%%-%m%m%-mnm’rmmm-e-m.m.mnmnqŽ’r’mnqnmmnmnnqŽ’re’’‘’-%-%-%-%-e--e-%mnn’rnmm-mm.mnm-nmnqn’n’’r’qnrnmqm’rmsn-e%-%m%-e-%m--m-e-nmŽrrmnm-nm-nmnmrmnmnnmrm’nmn,›{›{ssn--e-%m-%m%m-n%m-n-nmnqŽ’q’nqnmnmrmr‘rŽrnrn,{›{›{›{›ssrn.e-m--e-m.m-mn-nmn-nmnqnrmrnrnnmrmrm,  ›{›s›{{{›{›{›{srnn-m-m-n-m-m.mm.mnmnmrmnmrmrnnm {›{›{›s›{{s{{s{{s{sssn-m-nmnm.mnm.mnmnmrnmnnm      {{s{s{{{s{{s{{s{{s{{s{{ssr.m-mn-nmnm.mnnmr-,    ››{{{{s{{s{{{s{{s{{s{s{s{s{{ÛÓ’’’rnrnrs-2s3      Û›Û›{s{s{{s{s{s{s{s{s{s{{››ûÛßÛÛÛÛÿÛs{s{ .-     ÛÛÛÛß››{s{s{s{3{s{s{s{›ÛÛûÛÛßûÛÿÛÿ›s{3{33        ÛÛ›Û›Ûߛۛ››{›››››ÛÛßÛÛÛÛßÛßûÛßÛÛ›3{3s;s;-       Û›ÛÛÛÛÛÛÛÛÛßÛÛÛÛßÛÛÛÛÛßÛÿÛÛûÛßûÛ{3s;s;s3s3       ›ÛÛÛ›Û›ÛÛ›ÛÛÛßÛÛÛÛÛÛßûÛÛÛÛÿÛßÛ›3{3{3s3{3{32    {››ÛÛÛÛÛÛßÛÛÛÛÛßÛÛßÛÛÛÛÿÛÿÛÛ›s333333;333333       s{s››ÛÛÛÛÛÛÛßÛÛÛÛÛÛÛßÛßÛÛÛ›3333;33;333;33;32  {3s{s››ÛÛÛÛÛÛÛÛÛßÛßÛÛûÛÛ{3;33;33333333333333     s{3{3s{››ÛÛÛÛÛÛÛÛÛÛÛ›{33333333333333333333332 {3{3{3{3{s{››››››{s3;33;33333333333333333333   s;s3s;s33s;3;3;3333333333333333333333333333  {3{3{3s;s;3s33s333;3333333333333333333333   3s3{3s;33s33;33;3333333333333333333333  {3{3s;s3{3;3s33333333333333333333333333  s;s3{3;s33s3;333;33;333333333333333333 s;s;s3s;3s;33s;3s3333;33333333333333333333  ;ss3{3{3s;3s;3333;33333333333333333333333 s{3{s;s3{3s;3s3;s333{33;3333333333333333 {3{s;ss;s3{3s;s333{3333s33;33;333333;33 s{3{s{3{3{3s;s;s;s33;s3;3s333s33;33333{s{3{3{s{s3{s3s;s3{3s3;s3;3{33;s33{33{s{s{s{3{3{s;s{3s;s;s;s3{3s3s;s3;s3;s{s{s{s{s{s;s{3{3{s3{s3{s3{3{3s;s3{{s{{s{s{{s{s{s{s;s{3{3{3{s;s3{3{{s{{s{{s{s{{s{s{s{s{s{s{s;s{3{s{{s{s{s{s{{s{s{{{s{{s{s{s{s{s{{s{{{{{{{s{s{{s{s{{s{{{s{{s{{{›{s{“{s{{{{s{s{{s{s{s{{s{›s{›{{{›{{s›{{{{s{{{s{{{›{›{›s›{s›{s{“{s›{s{{››{›{›{›{›{›{›{{›{{››{››{››{››{›{›{›{››{››{›{›{››{››››››››››?g?ÿÿÿÿÿÿÿ?ÿÿÿŸÿÿŸÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @€@€ÿ @ € ÿ @@@€@ÿ@`@`€`ÿ`€@€€€ÿ€ @ € ÿ À@À€ÀÿÀÿ@ÿ€ÿÿÿ @ € ÿ @ € ÿ @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ @@@€@ÿ@ @@ @€ @ÿ @@@@@@€@@ÿ@@`@@`@€`@ÿ`@€@@€@€€@ÿ€@ @@ @€ @ÿ @À@@À@€À@ÿÀ@ÿ@@ÿ@€ÿ@ÿÿ@`@`€`ÿ` `@ `€ `ÿ `@`@@`€@`ÿ@```@``€``ÿ``€`@€`€€`ÿ€` `@ `€ `ÿ `À`@À`€À`ÿÀ`ÿ`@ÿ`€ÿ`ÿÿ`€@€€€ÿ€ €@ €€ €ÿ €@€@@€€@€ÿ@€`€@`€€`€ÿ`€€€@€€€€€ÿ€€ €@ €€ €ÿ €À€@À€€À€ÿÀ€ÿ€@ÿ€€ÿ€ÿÿ€ @ € ÿ   @  €  ÿ  @ @@ €@ ÿ@ ` @` €` ÿ` € @€ €€ ÿ€   @  €  ÿ  À @À €À ÿÀ ÿ @ÿ €ÿ ÿÿ À@À€ÀÿÀ À@ À€ Àÿ À@À@@À€@Àÿ@À`À@`À€`Àÿ`À€À@€À€€Àÿ€À À@ À€ Àÿ ÀÀÀ@ÀÀ€ÀÀÿÀÀÿÀ@ÿÀ€ÿÀÿÿÀÿ@ÿ€ÿÿÿ ÿ@ ÿ€ ÿÿ ÿ@ÿ@@ÿ€@ÿÿ@ÿ`ÿ@`ÿ€`ÿÿ`ÿ€ÿ@€ÿ€€ÿÿ€ÿ ÿ@ ÿ€ ÿÿ ÿÀÿ@Àÿ€ÀÿÿÀÿÿÿ@ÿÿ€ÿÿÿÿÿ$ $$$$$$$$$$$mnmn-nmmnqnq-$$ $$$$$$-nm.mnqnnrnrn,$$$$$$$$$%%-mn-mnmnmnqnmrn$%-e-e-m%m-mm.mmnmnqnrnnrnr%-%-%m%-m.m.mm.mn-nmnmrmr--%m-m--m-m-mm.mnmnmrnrmnm,%%-emmnmnnmm.mnmnmnmnm‘’m%mmmmnmmm-mnqnqnrmrnqn’’$.%-%--e-nmnnmnmnmnnqnrm,›{“snn-m-m-mmnmnqnqnrm {{{{{{sssn.m.mnmnmnm-  {{s{s{s{s{s{Û“š’ss3s   Û››{{s{{››ÛÛÛßû›3{3 -   ÛÛÛÛÛßÛÛÛßÛßûÛ{3;s;2   ›ÛÛÛÛÛÛßÛÛÛÛ{3333333     s{›ÛÛÛÛÛÛ›{3333333333  3{3{s{{3333333333333   {333{333;333333333 3s;s333333333333333  s;s;33{333333333333 s;ss3{33;333;33333 {s{3{3s;s3{3s3;s3 s{s{s{s{s;s;s;s3{{{{s{{s{s{s{s{{s{s{{s{s{s{s{›{›{s{{{{{›{›{{›{›{›››››› ???ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿsimutrans-124.3/src/android/000077500000000000000000000000001474050137200157625ustar00rootroot00000000000000simutrans-124.3/src/android/AndroidAppSettings.cfg.in000066400000000000000000000443201474050137200226150ustar00rootroot00000000000000# The application settings for Android libSDL port # Specify application name (e.x. My Application) AppName="Simutrans" # Specify reversed site name of application (e.x. com.mysite.myapp) AppFullName=com.simutrans # Application version code (integer) AppVersionCode=0@ver_major@@ver_minor@ # Application user-visible version name (string) AppVersionName="@ver_major@.@ver_minor@.@ver_patch@@nightly_suffix@" # Specify path to download application data in zip archive in the form "Description|URL|MirrorURL^Description2|URL2|MirrorURL2^..." # If you'll start Description with '!' symbol it will be enabled by default, '!!' will also hide the entry from the menu, so it cannot be disabled # If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped # If the URL does not contain 'http://' or 'https://', it is treated as file from 'project/jni/application/src/AndroidData' dir - # these files are put inside .apk package by the build system # You can specify Google Play expansion files in the form 'obb:main.12345' or 'obb:patch.12345' where 12345 is the app version for the obb file # You can mount expansion files created with jobb tool if you put 'mnt:main.12345' or 'mnt:patch.12345' # The mount directory will be returned by calling getenv("ANDROID_OBB_MOUNT_DIR") # Android app bundles do not support .obb files, they use asset packs instead. # This app project includes one pre-configured install-time asset pack. # To put your data into asset pack, copy it to the directory AndroidData/assetpack # and run changeAppSettings.sh. The asset pack zip archive will be returned by # getenv("ANDROID_ASSET_PACK_PATH"), this call will return NULL if the asset pack is not installed. # You can put "assetpack" keyword to AppDataDownloadUrl, the code will check # if the asset pack is installed and will not download the data from other URLs. # You can extract files from the asset pack the same way you extract files from the app assets. # You can use .zip.xz archives for better compression, but you need to add 'lzma' to CompiledLibraries # Generate .zip.xz files like this: zip -0 -r data.zip your-data/* ; xz -8 data.zip AppDataDownloadUrl="!!Data pak|data.zip^!!MIDI data|:TimGM6mb.sf2:TimGM6mb.sf2" # Reset SDL config when updating application to the new version (y) / (n) ResetSdlConfigForThisVersion=n # Delete application data files when upgrading (specify file/dir paths separated by spaces) DeleteFilesOnUpgrade="libsdl-DownloadFinished-0.flag" # Here you may type readme text, which will be shown during startup. Format is: # Text in English, use \\\\n to separate lines (that's four backslashes)^de:Text in Deutsch^ru:Text in Russian^button:Button that will open some URL:http://url-to-open/ ReadmeText='' # libSDL version to use (1.2/1.3/2.0) LibSdlVersion=2.0 # Specify screen orientation: (v)ertical/(p)ortrait or (h)orizontal/(l)andscape ScreenOrientation=h # Video color depth - 16 BPP is the fastest and supported for all modes, 24 bpp is supported only # with SwVideoMode=y, SDL_OPENGL mode supports everything. (16)/(24)/(32) VideoDepthBpp=16 # Enable OpenGL depth buffer (needed only for 3-d applications, small speed decrease) (y) or (n) NeedDepthBuffer=n # Enable OpenGL stencil buffer (needed only for 3-d applications, small speed decrease) (y) or (n) NeedStencilBuffer=n # Use GLES 2.x context # you need this option only if you're developing 3-d app (y) or (n) NeedGles2=n # Use GLES 3.x context # you need this option only if you're developing 3-d app (y) or (n) NeedGles3=n # Use gl4es library for provide OpenGL 1.x functionality to OpenGL ES accelerated cards (y) or (n) UseGl4es= # Application uses software video buffer - you're calling SDL_SetVideoMode() without SDL_HWSURFACE and without SDL_OPENGL, # this will allow small speed optimization. Enable this even when you're using SDL_HWSURFACE. (y) or (n) SwVideoMode=y # Application video output will be resized to fit into native device screen (y)/(n) SdlVideoResize=n # Application resizing will keep 4:3 aspect ratio, with black bars at sides (y)/(n) SdlVideoResizeKeepAspect=n # Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer InhibitSuspend=n # Create Android service, so the app is less likely to be killed while in background CreateService= # Application does not call SDL_Flip() or SDL_UpdateRects() appropriately, or draws from non-main thread - # enabling the compatibility mode will force screen update every 100 milliseconds, which is laggy and inefficient (y) or (n) CompatibilityHacksForceScreenUpdate=n # Application does not call SDL_Flip() or SDL_UpdateRects() after mouse click (ScummVM and all Amiga emulators do that) - # force screen update by moving mouse cursor a little after each click (y) or (n) CompatibilityHacksForceScreenUpdateMouseClick=n # Application initializes SDL audio/video inside static constructors (which is bad, you won't be able to run ndk-gdb) (y)/(n) CompatibilityHacksStaticInit=n # On-screen Android soft text input emulates hardware keyboard, this will only work with Hackers Keyboard app (y)/(n) CompatibilityHacksTextInputEmulatesHwKeyboard=n # Built-in text input keyboards with custom layouts for emulators, requires CompatibilityHacksTextInputEmulatesHwKeyboard=y # 0 or empty - standard Android keyboard # 1 - Simple QWERTY keyboard, no function keys, no arrow keys # 2 - Commodore 64 keyboard # 3 - Amiga keyboard # 4 - Atari800 keyboard TextInputKeyboard= # Hack for broken devices: prevent audio chopping, by sleeping a bit after pushing each audio chunk (y)/(n) CompatibilityHacksPreventAudioChopping=n # Hack for broken apps: application ignores audio buffer size returned by SDL (y)/(n) CompatibilityHacksAppIgnoresAudioBufferSize=n # Hack for VCMI: preload additional shared libraries before aplication start CompatibilityHacksAdditionalPreloadedSharedLibraries="" # Hack for Free Heroes 2, which redraws the screen inside SDL_PumpEvents(): slow and compatible SDL event queue - # do not use it with accelerometer/gyroscope, or your app may freeze at random (y)/(n) CompatibilityHacksSlowCompatibleEventQueue=n # Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState= # Application uses SDL_UpdateRects() properly, and does not draw in any region outside those rects. # This improves drawing speed, but I know only one application that does that, and it's written by me (y)/(n) CompatibilityHacksProperUsageOfSDL_UpdateRects= # Application uses mouse (y) or (n), this will show mouse emulation dialog to the user AppUsesMouse=y # Application needs two-button mouse, will also enable advanced point-and-click features (y) or (n) AppNeedsTwoButtonMouse=n # Right mouse button can do long-press/drag&drop action, necessary for some games (y) or (n) # If you disable it, swiping with two fingers will send mouse wheel events RightMouseButtonLongPress= # Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n) ShowMouseCursor=y # Screen follows mouse cursor, when it's covered by soft keyboard, this works only in software video mode (y) or (n) ScreenFollowsMouse= # Generate more touch events, by default SDL generates one event per one video frame, this is useful for drawing apps (y) or (n) GenerateSubframeTouchEvents= # Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n) ForceRelativeMouseMode=n # Show on-screen dpad/joystick, that will act as arrow keys (y) or (n) AppNeedsArrowKeys=n # On-screen dpad/joystick will appear under finger when it touches the screen (y) or (n) # Joystick always follows finger, so moving mouse requires touching the screen with other finger FloatingScreenJoystick= # Application needs text input (y) or (n), enables button for text input on screen AppNeedsTextInput=y # Application uses joystick (y) or (n), the on-screen DPAD will be used as joystick 0 axes 0-1 # This will disable AppNeedsArrowKeys option AppUsesJoystick=n # Application uses second on-screen joystick, as SDL joystick 0 axes 2-3 (y)/(n) AppUsesSecondJoystick=n # Application uses third on-screen joystick, as SDL joystick 0 axes 20-21 (y)/(n) AppUsesThirdJoystick= # Application uses accelerometer (y) or (n), the accelerometer will be used as joystick 1 axes 0-1 and 5-7 AppUsesAccelerometer=n # Application uses gyroscope (y) or (n), the gyroscope will be used as joystick 1 axes 2-4 AppUsesGyroscope=n # Application uses orientation sensor (y) or (n), reported as joystick 1 axes 8-10 AppUsesOrientationSensor= # Use gyroscope to move mouse cursor (y) or (n), it eats battery, and can be disabled in settings, do not use with AppUsesGyroscope setting MoveMouseWithGyroscope= # Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0 AppUsesMultitouch=n # Application records audio (it will use any available source, such a s microphone) # API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void); # This option will add additional permission to Android manifest (y)/(n) AppRecordsAudio=n # Application needs read/write access SD card. Always disable it, unless you want to access user photos and downloads. (y) / (n) AccessSdCard=y # Application needs to read it's own OBB file. Enable this if you are using Play Store expansion files. (y) / (n) ReadObbFile=n # Application needs Internet access. If you disable it, you'll have to bundle all your data files inside .apk (y) / (n) AccessInternet=y # Immersive mode - Android will hide on-screen Home/Back keys. Looks bad if you invoke Android keyboard. (y) / (n) ImmersiveMode=y # Draw in the display cutout area. (y) / (n) DrawInDisplayCutout= # Hide Android system mouse cursor image when USB mouse is attached (y) or (n) - the app must draw it's own mouse cursor HideSystemMousePointer=y # Application implements Android-specific routines to put to background, and will not draw anything to screen # between SDL_ACTIVEEVENT lost / gained notifications - you should check for them # rigth after SDL_Flip(), if (n) then SDL_Flip() will block till app in background (y) or (n) # This option is reported to be buggy, sometimes failing to restore video state NonBlockingSwapBuffers=n # Redefine common hardware keys to SDL keysyms # BACK hardware key is available on all devices, MENU is available on pre-ICS devices, other keys may be absent # SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices # Use word NO_REMAP if you want to preserve native functionality for certain key (volume keys are 3-rd and 4-th) # Keys: TOUCHSCREEN (works only when AppUsesMouse=n), DPAD_CENTER/SEARCH, VOLUMEUP, VOLUMEDOWN, MENU, BACK, CAMERA RedefinedKeys="LALT RETURN NO_REMAP NO_REMAP SPACE DELETE" # Number of virtual keyboard keys - currently 12 keys is the maximum AppTouchscreenKeyboardKeysAmount=0 # Define SDL keysyms for multitouch gestures - pinch-zoom in, pinch-zoom out, rotate left, rotate right RedefinedKeysScreenGestures="KP_PLUS KP_MINUS 1 2 " # Redefine on-screen keyboard keys to SDL keysyms - currently 12 keys is the maximum RedefinedKeysScreenKb="LALT RETURN KP_PLUS KP_MINUS SPACE DELETE " # Names for on-screen keyboard keys, such as Fire, Jump, Run etc, separated by spaces, they are used in SDL config menu RedefinedKeysScreenKbNames="LALT RETURN KP_PLUS KP_MINUS SPACE DELETE KP_PLUS KP_MINUS 1 2" # On-screen keys theme # 0 = Ultimate Droid by Sean Stieber (green, with cross joystick) # 1 = Simple Theme by Beholder (white, with cross joystick) # 2 = Sun by Sirea (yellow, with round joystick) # 3 = Keen by Gerstrong (multicolor, with round joystick) # 4 = Retro by Santiago Radeff (red/white, with cross joystick) # 5 = GameBoy from RetroArch # 6 = PlayStation from RetroArch # 7 = SuperNintendo from RetroArch # 8 = DualShock from RetroArch # 9 = Nintendo64 from RetroArch TouchscreenKeysTheme=2 # Redefine gamepad keys to SDL keysyms, button order is: # A B X Y L1 R1 L2 R2 LThumb RThumb Start Select Up Down Left Right LThumbUp LThumbDown LThumbLeft LThumbRight RThumbUp RThumbDown RThumbLeft RThumbRight RedefinedKeysGamepad="LALT RETURN KP_PLUS KP_MINUS SPACE DELETE KP_PLUS KP_MINUS 1 2" # Redefine keys for the second gamepad, same as the first gamepad if not set: RedefinedKeysSecondGamepad="" # Redefine keys for the third gamepad, same as the first gamepad if not set: RedefinedKeysThirdGamepad="" # Redefine keys for the fourth gamepad, same as the first gamepad if not set: RedefinedKeysFourthGamepad="" # How long to show startup menu button, in msec, 0 to disable startup menu StartupMenuButtonTimeout=3000 # Menu items to hide from startup menu, available menu items: # SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.StorageAccessConfig SettingsMenuMisc.CommandlineConfig SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced HiddenMenuOptions='SettingsMenuMouse.DisplaySizeConfig' # Menu items to show at startup - this is Java code snippet, leave empty for default # new SettingsMenuMisc.ShowReadme(), (AppUsesMouse \&\& \! ForceRelativeMouseMode \? new SettingsMenuMouse.DisplaySizeConfig(true) : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(true), new SettingsMenuMisc.GyroscopeCalibration() # Available menu items: # SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.StorageAccessConfig SettingsMenuMisc.CommandlineConfig SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout SettingsMenuKeyboard.ScreenKeyboardAdvanced FirstStartMenuOptions='' # Minimum amount of RAM application requires, in Mb, SDL will print warning to user if it's lower AppMinimumRAM=0 # GCC version, or 'clang' for CLANG NDK_TOOLCHAIN_VERSION= # Android platform version. # android-16 = Android 4.1, the earliest supported version in NDK r18. # android-18 = Android 4.3, the first version supporting GLES3. # android-21 = Android 5.1, the first version with SO_REUSEPORT defined. APP_PLATFORM= # Specify architectures to compile, 'all' or 'y' to compile for all architectures. # Available architectures: armeabi-v7a arm64-v8a x86 x86_64 MultiABI='armeabi-v7a arm64-v8a x86 x86_64' # Optional shared libraries to compile - removing some of them will save space # MP3 patents are expired, but libmad license is GPL, not LGPL # Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2 #CompiledLibraries="png freetype bzip2 ssl crypto curl zip fluidsynth c++_shared" CompiledLibraries="png freetype bzip2 fluidsynth c++_shared" # Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n) CustomBuildScript=y # Aditional CFLAGS for application AppCflags='' # Aditional C++-specific compiler flags for application, added after AppCflags AppCppflags='' # Additional LDFLAGS for application AppLdflags='' # If application has headers with the same name as system headers, this option tries to fix compiler flags to make it compilable AppOverlapsSystemHeaders= # Build only following subdirs (empty will build all dirs, ignored with custom script) AppSubdirsBuild='' # Exclude these files from build AppBuildExclude='' # Application command line parameters, including app name as 0-th param AppCmdline='simutrans -fullscreen -autodpi -debug 2 -syslog -tag com.simutrans' # Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens # Minimum screen size that application supports: (s)mall / (m)edium / (l)arge MinimumScreenSize=m # Your AdMob Publisher ID, (n) if you don't want advertisements AdmobPublisherId=n # Your AdMob test device ID, to receive a test ad AdmobTestDeviceId= # Your AdMob banner size (BANNER/FULL_BANNER/LEADERBOARD/MEDIUM_RECTANGLE/SMART_BANNER/WIDE_SKYSCRAPER/FULL_WIDTH:Height/Width:AUTO_HEIGHT/Width:Height) AdmobBannerSize= # Google Play Game Services application ID, required for cloud saves to work GooglePlayGameServicesId= # The app will open files with following extension, file path will be added to commandline params AppOpenFileExtension='' simutrans-124.3/src/android/AndroidBuild.sh000077500000000000000000000017401474050137200206630ustar00rootroot00000000000000#!/bin/sh cd simutrans ln -sf libbzip2.so ../../../../obj/local/$1/libbz2.so rm -f config.$1.txt echo VERBOSE=1 >> config.$1.txt echo OPTIMIZE=1 >> config.$1.txt echo OSTYPE=linux >> config.$1.txt echo COLOUR_DEPTH=16 >> config.$1.txt echo BACKEND=sdl2 >> config.$1.txt echo USE_SOFTPOINTER=1 >> config.$1.txt echo USE_FLUIDSYNTH_MIDI=1 >> config.$1.txt echo WITH_REVISION=1 >> config.$1.txt echo MSG_LEVEL=3 >> config.$1.txt echo DEBUG=1 >> config.$1.txt echo FLAGS ?= -DUSE_OWN_PAKINSTALL cmake -E copy_if_different config.$1.txt config.$1 echo "#define REVISION `sh tools/get_revision.sh`" > revision.h.txt cmake -E copy_if_different revision.h.txt revision.h env CFLAGS="-fpermissive -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections" \ LDFLAGS="-L`pwd`/../../../../obj/local/$1 -Wl,--gc-sections -s " \ PATH=`pwd`/../..:$PATH \ ../../setEnvironment-$1.sh sh -c " \ make -j8 CFG=$1 && \ cp -f build/$1/sim ../libapplication-$1.so" || exit 1 simutrans-124.3/src/android/AndroidPreBuild.sh000077500000000000000000000027101474050137200213300ustar00rootroot00000000000000#!/bin/sh cd simutrans || exit 1 echo "Updating translations" tools/get_lang_files.sh || exit 1 cd simutrans echo "Get pak64" ../tools/get_pak.sh pak64 || exit 1 #echo "Get pak64.german" #../tools/get_pak.sh pak.german || exit 1 echo "Get pak64.japan" ../tools/get_pak.sh pak64.japan || exit 1 cd .. echo "Adding assets" download_with_retry() { echo 'START ' $1 RESULT=-1 RETRY=5 while [ $RESULT -ne 0 ] && [ $RETRY -ne 0 ] do wget --show-progress $1 -O $2 RESULT=$? RETRY=$((RETRY-1)) done if [ $RETRY -eq 0 ] then exit 1 fi } echo "`pwd`" echo "`ls -l`" echo "`ls -l *`" mkdir -p simutrans/music [ -e simutrans/music/TimGM6mb.sf2 ] || (download_with_retry https://sourceforge.net/p/mscore/code/HEAD/tree/trunk/mscore/share/sound/TimGM6mb.sf2?format=raw TimGM6mb.sf2 && cp ./TimGM6mb.sf2 simutrans/music/TimGM6mb.sf2) || exit 1 #[ -e ../simutrans/font/RobotoCondensed-Regular.ttf ] || (download_with_retry https://fonts.google.com/download?family=Roboto%20Condensed Roboto_Condensed.zip && unzip -n Roboto_Condensed.zip -d ../simutrans/font) || exit 1 [ -e simutrans/font/Roboto-Regular.ttf ] || (download_with_retry https://github.com/googlefonts/roboto/releases/download/v2.138/roboto-android.zip Roboto.zip && unzip -n Roboto.zip Roboto-Regular.ttf -d simutrans/font) || exit 1 [ -e simutrans/get_pak.sh ] || cp src/android/unpak.sh simutrans/get_pak.sh; chmod 755 simutrans/get_pak.sh || exit 1 echo 'Done adding assets'simutrans-124.3/src/android/Simutrans-upload.keystore000066400000000000000000000051031474050137200230170ustar00rootroot000000000000000‚ ?0‚ ø *†H†÷  ‚ é‚ å0‚ á0‚} *†H†÷  ‚n‚j0‚f0‚b *†H†÷   ‚û0‚÷0) *†H†÷  0227ý{5ê[a ûaÃás…ÃP‚ÈMÉÄÃ"h,`ËZ¬ùóñ.~‹Öždù5’È}7¿D24÷¿¸(ÁxFìP®ŸÝœc³.R”öwP$;ˆÐSlÓÄÈyÍÈñd޼D¯¯‚±B¼¼è&Ua¿…šñCë7Ïô‡TQ˜¥ŽÓ8Ì:dþ& lˆGbÆ´æ '~fd»óûävée¿§ßr©M кQêé…“ºq(<2²6Dgn]¯L‰Æ).Ù ,W‹3­j†ù $ùœ 7ŽÊ渤–¯(ÁèpUm¾7¾½}³2MÎ4¸€…*õüò¶ó·gÞ y°¯ÈüŽ¿÷ça4ÙÂ¥îyJkµ²Ûß¿%²üðE:Ú7´¾ªSK— Öx–;3â¾Ú OaŒ‹µ¢k@Âiþͳ„É o[ÆÌA¬ÓÙ4m§}Q¾L5ÙUiÝ/Ó}ÔˆTÜ(Á+bñ9õÕ$MÔPæSý+ÇPyþ2iRz$òRù)¡m.¬dá$*/ _y¸°žÔÖª„8zÁãÿø{ÆC+† 3™MÇ‘ v«+ð¹;HÛ<ô¥b(Œé­`É ¨ OŸº­vkD6š^Ùv[À°¾QÉñ ” r5ÖY™v¡ÌPÖšc«}v„|Ê&ȰNYæ–³·Ýmh§ëb’,Ë/ˆÃÜã4Vs2¸û£“mebαFIˆõÙà(ý¼½/bUèª2OôMH§±e½UîhJÈšWh»½fl[€VÙ@[ÛL­šˆtoŽÏÆp<ü—L¸Æúr6®9Ï:žN§œŠa`]ÓÊó("G ÿ¶‘Ë˾”X·¹ÄÊ”¿&§j¸¤åë dVlJ[rÁÚÝlµíÒ®”å|»—ä‹Sœ`µcn0_ûõ« Á¨{Pz¨.Þ'p‹³d;_8«øáˆUA9BN/.~ù’þ¾Þ[DIœJa'ÅŽ7è¬7™õ.ö¨(‹îÚX'{–ê:hqú”­²4²vq-­ô/¹x×ÄpÞÃÇ©~ Pó6t€XÌb…D„À§Mœóèð†°ìFap©gÃ{Ñ®n+t@<õ2:—ÄêEï=‡:L”¹°‡}ø ºƒôíŸL;M{Ñ'ñ›'8Ç™çÈBn!‚ºæx'&j“lñnÝ(³+âͪý¾æìûEYèk¢„ÎGJoÔÇy: ¥¬šO¸þvyÛIƒ-ãÏ<¿L_¢hcΖýÌÐyŽìÝÒÑ^_¤¼Š2²îRJË…uSq\Š˜7’^B2ÕfëÇBÛ¢ê$vFIŒ ©2ßîaš¼ñûÙÚÊ-z%[޾ûú­³,°=[ óÃ4ä‚Å2ßç‹Ö†2WÀÿ)S鿆¡=$JVy»YX‰ z˜åk±1T0/ *†H†÷  1" simutrans-upload0! *†H†÷  1Time 16407820332780‚\ *†H†÷  ‚M0‚I0‚B *†H†÷ 0) *†H†÷  0¸Ñeú¹æ~†XI¬[Ÿ»~ÃP€‚7Ó×ÉG—t MÓ47³Ÿ³äÿhåYáH-×éç§ûm{ñ™p?9§pϳxlP@mC HˆkVÊ…¿g”ÜËeÌ{ú“Xø3ù+yµª‘õDöàËHîÛmï×xhðŽ"mÂQrcÞt¾ƒNEa*| çÞ4]‚°r[½&S°)lSŒò°DYy\°° Ct¯Ñ“ö ‚žVÚ“F¥³&pÇüù‚J©Ì¸ZÑ›b–Í×¾i ó}^‰>#?Åz# «êS…”çð¤ !ûºi¤mÍ÷i;¯p›8sZæ;?ã±\ yÊî ¢5+ýEu“’Î HfÎ"ƒ”/wÈ¥Ô(s˜Žäòu«)ÃÒèˆa%…{\H@(!åùª_]˜ pÆâ0é# ˜Ï:0•ÀS–g0kùÈ­m=¾”zVÓU¨JrœŽíUÇ›‚^ÕTíZ¬íiD¹™MÄEqÞr\0˜dmÕ¼_Ì~§ëÐMd÷Š¢ò»TUÅ çÿ%½~”HÁí ²Ž‚˜Øí{KpŽÃŽ!KY¹8ª³¯ß1ãñ¿ 5 a@¾¾ ¦MVõDÌT¿lÚ½3ª™§§kya}9Ì¿ßÖ¸JëÿbîxŒ(¨‡a³ÖM¨Ó c %#Érnt'p"˜Û»VºoÑÒ™[á¶á®ŽÁ èz]»AƃÊVÎÔiú6ݾ)BøÚÓQŠØ@ÙžÎÃ}zÁ\0³Ñ†Ì“À’mpœì¾žýR —³ù5éåÞ3½–€ÐúøÕã˜l >>9ÍÊ3}ö2×Þ¶ó…{î*пŽÝÊo¨›˜“ÚZ”‹*#½|>m†Ïݬî‘«L–~euí™=,ø'J ×h©†×}þÙƒæv½ÆQô<Í9î|`¿rñ"/Î'@@0!0 +‚è‹Fè´Ë§¢È‰…ÑÅ|=¥_á¹$ªí¯ÎÆG­Þd- WOÔ† simutrans-124.3/src/android/android.cc000066400000000000000000000003371474050137200177140ustar00rootroot00000000000000#include "android.h" #include "../simutrans/sys/simsys.h" extern "C" { JNIEXPORT jstring JNICALL Java_com_simutrans_Simutrans_getVersion(JNIEnv* env, jobject thisObject) { return env->NewStringUTF(get_version()); } } simutrans-124.3/src/android/android.h000066400000000000000000000002171474050137200175530ustar00rootroot00000000000000#include extern "C" { JNIEXPORT jstring JNICALL Java_com_simutrans_simutrans_Simutrans_getVersion(JNIEnv* env, jobject thisObject); }simutrans-124.3/src/android/debug.bat000066400000000000000000000005541474050137200175440ustar00rootroot00000000000000rem My devices, edit as needed rem G0W0T8058344F2B5 rem emulator-5554 set "tablet=emulator-5554" cd C:\temp\platform-tools adb -s %tablet% shell stop adb -s %tablet% shell setprop log.redirect-stdio true adb -s %tablet% shell am start com.simutrans/.MainActivity --es args "'-log -debug 3"' adb -s %tablet% shell start adb -s %tablet% logcat com.simutrans:V *:S simutrans-124.3/src/android/icon.png000066400000000000000000002245161474050137200174320ustar00rootroot00000000000000‰PNG  IHDR{C­)IDATxÚì½i¬mÉu¶ê¾ûÞköënv³9ˆ¤ÌA²,ÑËŽ)ìÀ?Bb’äOb#?ò;@~Øc°£@B,…¤(Ñ¢(qÉ&Ù$›ó<“MõÜoïøî<ß{ΩÜ{ÎÞUkU­UÃÎÙç¾[xÝ÷œ:µ«ÖZ_Õ®Uk­ªRO½º^ÒÊþ_+P:TÄfÒÉZ+¥ŽÿJ¹ÏÑgµ}T ÿÓº¬‚I“Æ]¢¥ tJÕ\[Ç|ÏJíZæ]$6‚â4Œþï¶kþ(¡BŸ2…d¤Åëa fñ«ýï*øÿ´úGÝUhHýK•õš~7Ì´vTaÓ§ W,RFΤ}¿g©æwÊØØ°:=Ș6Ldºl¾Ì¡|2ÉSee83£Ìo³ÕB•p.L‚ßt f?ðÍÐB ¶ßT/L³¤à¾(‚åùL¹¿CNy¯ñb(i()äÇà2ƒ/M2ïj-V /^¿(‹Xýº˜¥´N(‘U¨Ñ4Á¢ÊµóZoˆÔò#V[¤¢ ¥)J3Y¥U4SU©a )N¹ÉT5L*e°“SÃTPÞ:5ãeç ˆ³4Á4˪ ªüc׌e¡ò#ÑjUa» %3‰[9”KðÑCt©©’&³ÌR‚"cVõÚÖ[¨Hè£KŒ[ eÒ§\s…OþG¹ ÄÊ£RÈSRÃÖœ„ÌNˆ¹º¤ÉBY*•d^ý2LaóÑ×ì);e¿*1ÃGú•Y»3@ðåqáJ㾩½ÎB0º)”IWÃ~U ÷+vDTP Ô‚$s–¦*+€N¨!•VRO²´¼N±S_i=¢e•ˆéÔÊ©Sà,%¦Yó‰U¬ˆÓ‘¨Ÿæ…ÔR+’b5jÂfR¥•)lò±"C–F±CÞi¤¥-,¤‚1Uðåµ—¥”«~šÊ<-³Ôp©¾ W¼Â"x=†Yª| XÒ×pCì„€ Ä|íK]îWœ†Ë&õ„dëõ+;"´W˜B‘eYH¶4"ð:€L›G#ô+nÍ$¦ž£lÏR—Sž€MY3ÿ™ò˜Ýp½ Æ­<6‡åôö«,WY§(Og§‘ÂgiâiÖê É6SˆXÒ±­VéÒäm yÊ/¥=“bm¦ÅO:Pyù#µ™µ{Ù€‹²[oÌ‹Ha—m¦å*H0àJŽòSÔ1à)u!”‹GÔˆaEmÀÚ«<¥5õ"àJ’<4Œc$[|œc@‰ 8‚„TQbŽc šé…—E¸’⮫ Ë*Àœ‡ Ÿ¥n¦z>€Ó}꣕t¥¼ˆ‹ )-“·GW¢p*(¯Ï&«°O1SÄY{B>nþ#.ŒÍT¹šY¸ˆ0a±ˆ  pq%^äW¸¨Ãu €hèZº¥k¸š# êQˆ°8&3Ç1X¼{´Ò†aRUˆH¿JÙ¹Áj¸µðˆ‘Åè…TêÇRBPF1¤ÊxÞˆ(*d±+- +áÉDî„g©k©@–^Ô–ß~ªIy×40Å|šÊyv’ãRºÆÎX»PûÌO…ÌÏ’I³a݇ ˆSR¹JÕMS-:ìp\ñÐ JŸ§°;fPS¯RȰ rð^šY6SWNX]9r ЋT -ÂJ%»!%—$@(úB`Ç$%;œÀô+ºY7Uµ)­ù®2äα>'Ö‹”Ê :$v€ÐdîäÿQ¬l|´ÉĆeJDí†ø1VWJ²G»…b†E8ÇÄ´*»ŽÆ1åCÞC\SwT Å@¨|Ù‚³µ‚«¸ÜÐÜ c€°ƒ§–8˜.ëž2O„Tûòˆðª€@ß„zå8¢'€j#ÂðÍ8 ܯrG„Š»²ÎÒ¤ñL…ÎÒ)më”±Ó-åq¼ìT但÷¥- ÆàH^장1§Yç»`7DY ;`›¢LÊKŽØ1¾¢’ú’`&ŽeÂÄb¸•à€ÎfÊÈJ‰ÁÔ¨<Š*aNRŒ7Q¶´DÐCã´„¬Ì¼nêÏu X`¨Š+a%¦éQJq *ô«àR€Íî®-ÞÂ|©à*‹)ì–nŸG)Æ1@Ú‰ad›<"ÎÒØR•( Šq cœñëky|fÇ”–é¢Iv:ºOùÄYÊM³¬á~”uÃhÈñð R²¨_±ŠVèKÕYPÁ€Õeh0uÀ Ê;úÈ™¤é§¥ò¨’5VAVQ‚©QyÅ"£Šó)uTcOŠ:€ð¥Ä‚Žv%Ø4àzb²å£%“ò*€P #‰×_‚ «êpBªB@˜LÍÖL)§²NU Mçg×Ûà>¸øeD‡íYj4Å} Oòµ«««ÅOˆ…–%]KÝg'뾇NQžED÷ÙÉg©¥4ò¸¡/’©æó܈ .0ÄžŽr›äà)­1ó:2k2ØÚ©VpãÚ=¡ ©JŒ¿âB_Jå‘»f "zG ¯²¡?Î2KöД¨9ŽáÌ¥d ¼Â¦¼ñAX©4Ë8Æ1PFV²ž¶ŒŽ8¥§TÑ娝ÒÎ5=7îp2@(ß1ÀF1e’­ÄYj#5±x˜Æq1ÆTŸúÍUk ¢lUNáV˜l€Ö»Ð€;§ˆ³ÔPšõNö·ë€Ñ·PÈó“L*Lë²ñøÄž‰4Îx ¬ž ¦æÙWF½C•)ªc¥Øú³ÀSÓòü5Î:@‚Dµsæ~‘B¯yk­Gýʪ|UàØÁ³—ŠÊ֨ݎc³Õ2:9 „ׯèiB5€ ”cvd‹KLñSìèÜd DC·n€³Ak©º I-~ Ž*Ù M&žÚêçÄ(Ï¡p €¨]C§(ÏbBütªWœ¦äïÀfw…ƒ©Aëf2Ë\lUeçsç-S£¸éÒÉ]Íʃ3Ól¦@ŃÁÔÔ<ªF”•26R>˜ s¯uôz2¬nŸÔíJ©*AYAXaGýJ±‡æG*W¨ Ö1hkŽ,I ØFŸYÇ€„tGnÈõé#‚ÝçáÆIåAe]Zb'D•øË8å;\ p%Ñ~e†VÚˆ8K5Sc>€¬Ôý…t²EÊUÝ&Ïæ5)LÈÇ6Ôv¤sڀȩá,'Í ¦:6ô…Ã^~EŸ¬Ðp44…ê7¶ZÆ1‚fÁÛLÁÓ™½òäW" ·be<¾ãH‰A2L¦9€ ›¸ëƶd £µáGÙ†€(õx"%¢F7ÈäÍ*ƒŠªŸ–Hè u Xõ0”.ïŠT—zyC²cÀÐcýri× ¤éÌ%¡¼wk4˜;ÿš©R43!¦è,UHñ€8É'+VÝäcŠU§Ø©ozž”‡¦~k °Ób¼©[#b ˸2 }Ôf vŠÍâš½à¬-—¤°ñ€?Ÿ][Ù™`j…5FÃUâ9øáh“P05zX°Gã²#牫á¦S¨|²®”L DÒÄ1PˆQv ü´=±Œ† üÁ¢tæÚ¡Uôl,+Î#úÕˆHjïOw De¨“'Á^3ü)U@`Þí—øˆ°@0+'Þ16@(·_AÚˆ8Kéi2>€ôù©aR”WdgÒ©=g̤(? ìTZ9u‚r“©r Oš…©N³l.;YÓ)Ú(v4ªÄ<‡ €Q®mWo½Ÿ•{6Žú¢¥5â( ÷ k”V䶸ç6%Gµƒ¤'Ê¡/¬¢ Žk[¦›*‘í ì0Ž"ß‹§âQà(D&oÍ!|NŒcPNAÞiD¶e¿rVbñ½Ö-Œej~r7 èlïTâˆ8K8ÍŒaþ¬o"lÀìÞÍñ> ’$².µÙÃbw#bÒP5Ä„9x Ò, 8é߬ˆ l-mµÈ(ˆ¸`çs)˜š§Ð³z.µÕ:ŽXPãá(gíÑP.†¼ÂtåäíÈBq:!Kd’cìÊI—WþZR–"Õ1àz‘$0wæR¢cç'D›T })™æ•€ ù^] Øe³CÅòÈK±Åã±Ãwr¯’Ñ#0êWšÚðˆà€PxȲ@ÐFÏ )ÙÀf*>=¢£õ´0%ýj1%óxHèÜ8™ÄÊÝÂè{+š[ 'Q"•r6w8kÆ¡¬H¹â2åèOÚ7¼T#2ËÇ€Ð)?—˜Ü¤Î¤<’ Òˆ:y2y:ú~γ¹cùÁL³ŠUZíG›xÅŠbƒß{ªTL©c€SÄx]†ÎÑòæ)nO,2ÚeEyKÇ;pŠ•â‚©•\ÏJauÛ0ªÁÕpÒïÈ…àiBJ­¤#J Ûr ðw¹_‘Âq Êu%v  $H@p-¦­Ü5jyßXž”$òò ^1ùè\BIµ!,ã J—…Ûù£@$Ÿ>8vΓëKxÓ‰˜t8§ÓçÛ…ì"˜Ú…\SLÙ-Ó_(y±t Ž+þ~»òf¾¢wÄß^ *R^´ iÆ£nLCùv!P©³ld Á#לF;‹ÛðÆw6J²%ý cÂÞÓÉ1’²Ü¯xqÅG„¸˜Ñ¸ ­ÊˆPD¶C*Ü{:ƒý* /S‰…ÍïTv$²Gn¸rv¡j€úy¢lœ”º,kí9Žxë¥81*R¸v*Uñ ¡š(|FùÂNýNÞ) Æœü aŠÄ®C“9З¦ò5`O™®ÔŒF ‚bå;ã”w4B©)í1^ D¢KI Þ’Ù3 )TÞx>‰Å£1¾l] l]ÞѨG=¤‚9@Pч´up;!C &Ò¹a]ÌÑ5\Î9qè'Åi™CSŒpÛ dvr¾püØ Ô¯-í™bÒ€à¸zî:„¸Ó¯°a­íœ¾“ÐÉ ;BÃ@Ó'ùN©`Y…³Ö“bgJè„òØÜ+‹ò†ÙI®®>Jy¼ó‹Ýn&ëH²™&Ìç&_¾_ÂÌçî–(;ɳJTýX:p ÏÈ©[|â–(B=ªÎ/̰£ ¥¼¨UöžÎ8Ñ­vŠæ‡€8ÂÇ“)ôSšchÌhð¸o¯_•ª7î¶•€e%؇€@ý•¿ñQ^9U%¹ @ Ç»L¯D’c€¢¬ˆcÊ~¥¼q?9œ3ƒkýSœZ9ºûJë˜ÙÉ`³Q‰t_iÍzú ˆ1§Î-†ÆÈæTP^?͢ɖÌzéÑ&ìT©8E‹šrƒ5Žò7Á&[ÍfÊWÂí5gAŒ4Áfšp3æk¸¡p ‰²Š7óñž×èÿµ<4B¿’F= Ç`Ór ÄÁ.x¨ÄØ“ó`[È‚v~c (1&31¦ˆ8À,Óã@@ªcrFÄ)Kt ØU2Å4¡‰u¬Êc—(ïš"óÀR>}ì¨Pɶ(h–3Ç@,Í3&»%*1<#ÉÖî5µ¢“Ó€‰y4fª³fMÁѱ™]ɘA…I¸\66œ)œ„œdå 1ÊI÷ÐÊUÞ ³Á©·îW´º,Ç@äPeg žÅÍ‘² ‰:b@”ãÐ~e€ äqŽ”áè5ô¸“³¼óDVp èÑžD1¤Jr Ä€ ‚uY*?i|WBÖW‹:¥XeéJÝ¥ÜdæèJ-AÙ;g@tÚ5tŠòÓ·z˜EÊ#5à†£ó³"¹Ùð’‹'‰c€½†Ð 1&Sy™:¡0q ( dâÖ Å ÛâfPÜnºcÀŒ"ƒŒÈHtnè  0 jòNÝdÔmJ92»[Ã2V­.ÑîÓÎ>³”{¼Qʉ‘=±F½ŒóN×É™ª1šÔ[H áöy |ĸŽ =ÉÂ2¬éc¡«o DH¶€^82´_‘r ˜Ê#>K*[ÎMÈó>¥)a›õN‰#¦S”·ÅNç=4Y5L*M¬_Õ–B'€hËS6ÀÛH³Hk§Ü"ßNâ¹'!«`a§¼¢EKRpÅDÃUeX|Š©N¡?éÆî`Øã(¶7óÑ #¡/P1˜š+ï­œÐÍ| ïI6SåUõ+{æ’{Ê4Ï>Uê¢ýJr @ÎÏ½’aG€°ýUs¶xô«ä!».ú•vâñ9ÜÜ.²Ÿ½½Àv'ö”i'ö0›•R5]iÆá¼áÔh½Ý7ÕÕW.všâM%þ¤"4ÀNË *Õ3½@LEšE¦:߀Ku/ ÿ@6Æ–nb$¯q~òêA¾ÊÍ(vJeëe¯K‚§\’­·àÃ4RnQ<ÁÏ!öE}l¿wDèl Ã.SHs9 ÐÒÂÙ4ãH=:ˆˆl9ÇÀp¨úÑJüb—¾Câ#B&†áõ+ QÇ@ˆ€c@"½ûŽqûØÔ-->§®îê,•ê2å±åÒb·SúÚD(ØñÓ¬æÏѼ‘šý‹ˆOASø¡/*-,ר—ÅÐcŽóm¦qSkå)1?Å«ÒXJm“æ±A¶| ’Ô“ åÁŠÎ=± žOÉDP¤…¾°÷¸Ê@(Î1€Q2´º€còâ¯è29@¸f Þ ¢°ërß7îÝd™’† Q ¸¡È öòÌ¥¨c„·]= aD(æÌ%¹_åáí€P¿êHª²hÉÜà\YõP‘–v¦ûöØi[=©¯´v_“Í*Ü)vªó>F6ÚbBHtmA`oƒä^ æQÁ¦†”Làêçm¦x ¤Fýe–¯¬+/@Èr$8úùù|ôS,(ÂÚLÅ™_ѲhQâ•ÏBTÁÒ€Pe5 ¢NCŒì¡ñ…GOJ7K@pìÄï$pú•ËFToåh¶0ÐÓ„ÚÞ2.qý )#"n‹/G'wæRˆ„Nžå"ÄìXÂøO,ï:†ÂiBÝYÀTè,Ý×¶N;yÊ£ª[äØQ\‰¶€hÎC“UxÊ€è*;ÝòYÖK³hr´”…l÷®bå›A­MÍYdß‘Ëþʯ\ÃÉÚ£D] J05€{{ù—授TÚÑ@Ópfb@XÂÜãàã~WVPãjVگЙKõ€ð(wdÂ8 y!U¹—C$A`åötw™žm4ÍUV}*àP!7!–•"ߣŽëÎA;”‰c€°”ð›ÞÙGÆ–êEUÕ•º5u'+­]c‡¥ ãGÙé›Ý"§áîÑÜÊibètl‰<ëZßRf~@“#2N{ÁÝžÕ3ËÆ¨œ`e£S§šX€š¼YSÃ~Ðfê²ÃÛL 1šV<úhxn+•l¦by*^Z?î Ô€+;€HXÃ!‰q@8ýjT’*žb•O9ë<(¨<=ÙÅw%ª5VêAIr I ?øÛ™3àØQ^fh€;Žœé®œx Å)k¬äa}d3.æ"AVÈv åÑn ÜJ@xìd¸Êcm­_ýö%àà£M’"y,1ìÙ8<£Üœ½Ö â#‚xh°W¬ô ¤:B@Pà€,$Ó<4e¿²ü(±_ø9 $WYâˆh/µ»8K¹È˜ÛŸ+ë+­qc†û¶Ùi€÷SÄDØi„÷‰PÞ0e§¶á¾S¼ã4šŸAœÌA˜Ï9S o‹/fqÉx-ƒm¦‚)0¤°»º0†µÔpéK9Ñ :ª+ïdMÌŽË»o‹×Õ@&ïȲ‰_ 0޳'VKëŒïÑ[11ÉŽaáRyÔÁú "‚¥²U”$LŒ5»›_ì­^Õ€Hc':¨o­ÐŠkÙ3¦ç8la_4 ;N¿Ñ„(ŒüÛ€i‘ޏ¤_ áÓ©§ åŽHà§ø  --¾~ŠÕ;feZµøöÓƒ <6ÂûD(—öÄ6Iy; +îËTô«îƒNE¹¢£_§àXS]Y‡1«’d¶Ì3ÕÉ”ãL£å1Ö7cPö¶ŠHè‹òdÈ®}<ò€®h%ÔV넾 i¦Á­œvÌp0PúŽdàÀB–U*öÌ%Ë·i Db¿¢PÉ@”¨Å•€àëÕ¥òfç8Àë8æ'Ï1`Éu Áª¢›S‡¸KGa€‡+§”)T46À 1è ës’€ÈêäŽwªUÇ@'NÅ©œ9 këJÐd›[9Ñ.›g§%ó@×Йåí b6|¾kÃRöKjT1Ú:ðÙ8æÑàêA¨_pô'yl9'g"X[?Höĸ Æ´Šƒ P0=çÀâÕ9@(´c¸IÂ(Íž×<'A2¹%¸‡íÑ#zXÇX 7ˆïT–tÄŽU*“€0™Áe\úeÅÚ“R*¨~yDк„5™Ý4B³¼AR¿bOluÙQÞH”WìÛ&oD¤UP9Ùy¿s̤ü¤¸|eò“9ì?:¥ò@£‰™Ä•?†Oû)%² ûœ`Uuv4?à¼úC*73Ò®ráã §B)¢£BýJ%d ùz4›"^"F¡•X* t4ÀN[@ vUNádÊ•P"B%çCJ¨Dyµ7mýÂ,jÂêç¬I:úB'q˜ ¸ê}td‹Wä>Oºpùúƒ¦@7“¾Ô8í7hÌrœnºˆ¯jJaÂ";q j£¸i®DHSð~Vœ¬,1”ˆ‘†jMÞyýJI@,`pÀïW¸ð¨Oެ¤C¹û©!sC‚•®)­>"ò€PZ ­„Û¯*Œˆ¡ÄHgK"’”ËB&˜<<Ý·­¡ñ‘™fù=ÜÛŠ_OŖ̤0x…GÙvP9ë÷ ë»ð¤þ¨€³G–Ì;®]ëCèœGÉLž5!­Ó ¿MlÞ)Fç‘v·†+[ôÅ›ú-‘äzêQ×ï<i¨2•ûê¡lYÒ‰G=hŽ @Tìä¼KÙ³ Y‰)oO¢ª?uDÄ(û½åÄvþŠ@Ô² !zâ§L³@(ZiÜRš1"ÐHÔÁiÀã=cD˜ü†ìBãpÇ—†"®l—®†«Sd•;"lœ"Ç8ÂS¨ós‡IäÁÐÛ&ækWNÞ µœ¬òF’mˆ‚.¼ö^b.£ï _FOÌ  þ$?©4½”w”ªõNžòFÛ˜<;õC§l€·—f‘‰Ý1àçBO/à5ÜŠ7óá«Û¼Ã$Ø=¦ ÖTžR™ä°Ú"K<ÁZ–I,›ìd®¹T`æ§¢dPh"IŽˆ„Â1 \‰oUZã*·¤TXŠ¥Cå™Û"&®˜c€ÐnbFßcs€æwÎ1 áô«afŽ›Ò¶ƒådS¾Ðê{høJò€p2À¼m qD¤Á¦™I™ê:1ÉÁTW›ˆöS÷¯ýyP€è<;õ}“r THÃKáñ„ƒvºÅ¡/ÈTo)?ˆ¦½Ç@ñ»7…YUÁ†¾( zBd ÅàÅJ¡öiabì£6SÄ;­œµ™R DÊ]m]B3Ž*J@0ì¥ ´(¥œq ð[¢BÆnO¶ØLi'Ƕød Q˜E¥2Á1¸;{¡/l¤S9뀄‘fì¶?â˜QéØäÑ#~pihDàŸä;P Ê[D ¶Ç@"Œ¶n{n’i„ 2tÞ´õp‰ ŒHjXWãdX_¹èÔ|Þ)¥µ%ÊO ;*R¸»”›L•QCwÙé¹Y”›ÌÖ€@Â`Ūð­VeÇÀèKt5€ç(ºp ;øÙ|;SK·ÍðŽþTë7ßvD›)2ö•¹$ÚI$Iü{ÊEÄM€0ú6ü–Ë’ôu†0%¬r¾;”ûޤMžÖA <Þsm¦l05ïp"Ñ&é@p ‡! HÏ#ÊcÎ5ôÙ#‚So);žc€^°žå¯Éˆ÷mw  ½cî¨J÷Ј#BÅFࢦ ¥ë—ɸ";ò|²Ê5 ÅO;S DZü<4ÉŽ\6Ûæâ[NUª¡S”wˆYð'(CY9§i4ez.šäKVRýV¹J4àBI *ÁÇãŸÝk¹£$øa\.%âÂ;÷›A ‘U.Ö£@•£ÞÊN—Ȩ“çØC ¸~EÕžT <])¤WÆx§…iŽpûyh)€ÕÛ8e¿*úZI¡Ý†Z Ž*‘¦óç9b@¸²²?¥.aGû<´3<± DYåŽÅ,aÅN[ÂÇ.ÓE OØ6onD$ïnGW÷ìW©½NP^‰­îÑ2;ÓKyì4'‘tvƒC=8h½áv*8M@ä6;+=ÆD\(|á‡5y³fóÀ‰¹Ž~^=áîÁÎÚ) *m2§_Â.€tî«kég’NÎ2©Ž°J>a…2c®ÇN+#J¥¨ÞWŠöžW2ƒÊ@0…Y›© 9¥ª,®b¿2ôİ GíÑ9@GÂ@h}´·ùâñÿ/=þw”š-«2¯ ûXô²ˆ+Ìs”á*ó6¸–A\t’­âö UÎy[% ª]F[æÎ‚ñ¥Þy?†”Õ®:÷D(¯ÏfEvÚa8‹˜ú@tª¿5‰N³*;Ç´D™ôáÞ½ûwþLÍœ¿ðš·^xè­íðS¥l'€ˆµ;ÙWÓ,«û„(sMu¬càä¯{Ü ä8úÙPÇ˳7ó9ŽC¤z67E3\“ŸêèþÏu àú¨-éU€P!ÙJöhA°È;c)®ÃŽ$#1¹¡/ì‰7á¥@ÈÒn~¯ „ XY uÙ§¬3‡þ:@`"C@XÒqêmo,}eóþ·ÎÍ>ºûäÏοéM£E@p¹¯¢ŽbèOp Xv)•I޲ vçSHV©@N2 ŠÒxgOr)~”²¡ñ] YÑ\Õo}nSG÷M’ÓDNáî³3©dçÎAowëåÕ¹§ý£ƒ…Í•o÷–*S>y —Ù ã”ãÌœ·Í¬ûXÂÌOÛPH«Âó9Íkªy‚È»™m/@–GwÀ8ÄM€U?:ÿgØL•‘­ï “|5 ÒΧ$@¸åñ Ç,ãÐÚ.ˆRJ.‚Hl(u²Ï8°[2Ó€¸F£ÄÌ•BÚß1„È‘mÔùK†í"l×ʽ£µ•»=ؽ6ÊÜZùÞkßð»ø¥Î ìPÇúR ޼aÌïØ1À¬œ2 %1;ž-AÂ^€ £á>ŸR•·¨?+vj }•Çé¢STN•4\‘BÝ[_|fsùë&£w¸¼±üÕÞáê8yjŠ)Ë5ÉžM7^ãöX…ÝÖΦ;4ÉçÌçö§Ä ×ò7RÒm<>x“<6ÕÉJ¥ÍW(3EaDz¥ªIy›®w6ŽÑת11+ô›`¶&QK ÕpC@Œò9›i|å$Á8œÐ9õ¥R™ Dz¿‚èˆÀ+Æ_°øï†Äœh¸!Ç"/TMÚÛ¾|ÿΟ{8sóþ·Ó?:áÉ‘' DÙ¯´Ó¯”´cÀpÚÉ!<"hÃ! ÊǨcPs×vd ‘ƒÅ\Ù’ „9œ¬‡Sèò~5Ͱ¹uSruõWmÍÛ•ê­¿zèqvbemºN õ(ïàªtÐß[¼ñþƒÝ[N~ÿhumþé~o»1rŽˆö1Kð ÜšÁÔ£oxb–+’ÍÒæsÙTgTvî=&숳¯B“9É÷_š¡kÙFúc¶VËP\kÞ-Y@Pé§8°w‚ëWŠÅŠw €kîåÙ‰ÁøxòîÈ%™á~•„ãcWæ ˼¿¯Î=µ¹ü Ž"ØZùöîæ >ùŸ*5dõá²o¡´/œB½Ï‚+êW©@ÐÎ?ÜEœ:Às]e´Þö=È/J¸,v7¾( ŸŸ ™ã¦°Y›éDبé>;Óë[Ê¢0.s©¡m"ýÌÝÍ—ï~Ä1þ˜Ôïm­Üý0 ãÌO"uwuØèÛ&‘HÏ@fŒÝÔÔ$Z*?á˜_\[<^jpÆk`gŬ«YéêÓîï€Æ»i½š–tÅ¥D§KÙ8µÅ—¤' ÑÇ^a§~–ò²SxŽE}>QY Ë,—B$ î~Ô8@ˆŒëÁË*D©n;;J²‚؈pf ìˆQF ˜FeÇ•¿ß—î|è`÷&Èikõû;ëÏ>òäoº²JŠl—ñ6 T‚”/ ³>FV#ŽòeÖ æ[ÈCƒòÓˆ¡KXÍ:0‘’càø÷*>€N©„RZ \¥–œ ›RZ¦ÜdžÁ&­WžÞ\ùŽÆ ¾—ý½¥ÛÝo˜`f“lf¦é}5Í:fÔ‚ó+ÙL: D9ó§©Bœè%<Ù1€óƒŽÏûR–c€ã‚aDZGkW ]3 {hd ’£MD ¥Ð }Q¡úeMH°N£¤Œº!UŒ¤¢@¿`ˆ´Š¢T¸„C¢M€ð¹ŽˆŒc`(;NyØÙ|~mþéÞA<Ðsgý§Ûk?zôu¿þˆ~ e­óñÊ)`êrû•²_b#Âìbváøm9"L~d€Ó~U¢Ž 8ÆîHV¬º6ɳ´¥³´Ïäôê,-±s¦ÂJBÒ‰ùWGÙI‚ËtÀ‰aFçÉß~os}ù«Ûk?L1þ˜¤uowãù¥o¼“\”­+ÓRb”É@°%+÷+"K3 Ak7.³“D½·ÍHPÃ~U>W6ú7ãRÿøRÃZü¹èÚ$_“ôqkñͱ0Å@Ô&¦Ivô`gã¯îßýÄ ¿ŸûèáþÒÚÂç{‡÷Ó‰éÔѹ<…Ñ̪pü”Ï”ùŒng)¤'*¯Æ€† Ñ‚–„‰¡O—¸yòðêAX Ÿ<]É+iKD*†–}ÿ »Ìâ'ù8N½Š]R…yç€à(tú „ЯЊ%„W.ܯ¤^á•G"G2UJU"A¶æ‘¨_)LŽÏY<; Ë@,¯÷ç–ï~üpª¤þñä±¾ø¥ô~…é 1Z_b*û•rÅUŒfD$ ðâ\/²2Wv˜ÎØìˆPe¼ vúU•(  \eÔ0†Tqõ0²UþO¡¼U LÉJkEÊÇ€Ÿ ´ú÷¿³¾ôõP8s0õW6îcûz;ÄÒüz@tê½4Êgíž;/ôœƒ/pI> ¿êÕ¬XWÆãk¡l‰hÌo¸aÅ•îȵ¹ì5l /®ÜY-¥8úG¿Ç€p%ƇTQ 01éÁÔ"G<þiBà ÌS8 7Z>$Rî@†3]Þ‰NBª*‘{ v$Ѳ4»["„W]$îÅkBëõîÚ{´>‚êIo¯=»qÿ›~»š97jBŠùú1Àq@ࠈĴ‡D|€Ç„ÈeÅî„„“Ž8 !½i =ÂÛȈðú•NðdÍNcH]Öâ+´×]Ê+5\‘¬P¦ˆ±³süþŸ»öÞ£ƒŒÈ6 úÛË_ßÝzil”?ub™ž_Ŭ}¬D”SåÑ(´%3çDcx‰b¥2ϳôB¾Ñ9æ(S9$ŠÄ(ú[l jÆLÇDO¤·ûzQÀJ¥§´Jì­4ËÓp5ø× ”‡öÄ@š»šµ4GÒžg6 D€‚©AR|h–Ò…Ä¥ÒJ‰ÄMsÛPª=øý%ÆäG€(û•{ÿ0P•”ˆVå—rDèÍ•¬ÌšHÛk?ÙZùîkùÅ™s[í]|qF„ê¯ÅN²L»”=4̈ «Ržï1öšE%¿šY%ˆYfÙX\º]|‰¼Üƒo7ŨhŽdbÏLv '?NÒ•Ão7kÂ2pÇÐïìÙgâ¢>f@cd[ʧÙ…"V}âdËÙ…uB *…kvY,J‚³ %Jâï”4 »Ä0ˆ!Žˆ^oçÖËÿgeÓ¿—«óO?úÄß»ôøß>±Ò²ø³¾ƒ#"uеöF€ä=‰•ìBQ è›=é„;ò¤vr¦Å%›€—)†Hቤú­î›¹Äº„DE T¼p§(O¯aR)­û÷®þÁÁ^]ãNû;×Ö—¿Öïm2SJû–Ò)"«† ÉRÜTî`´j¸ÂyªÈòãý‡s‹LÅ—wÉ ÅÒ91£¨<%<\¹>¦¸ò„¯ZÄ–-n3½BRo`€céDvܘERos@ÈåvŠº´æ~¥èc©@ ÈS‚Wñ ;Ôè/2B¤œæ²¡Š´¤•ú/¡“—ÕëíõçîÏ}:kÛWJZ™ûäÞö•ÑBÞ%/}Dxo› £ºˆ€,¤ÆV&‚滃>ÈΨ /”¦£.C„BÌW?Ó¯‚|܇Á’8‰$—œÑM(­RCD6OÓFy§Øéõ¶î]ýÃÞázãì÷WWîýeÿÈÖ<1 ’;9t¹_)ço6‘3ì´àN8Åd‹ö\Øy•Ù86ª"0û1>çs2Ñ­ÊW©F™yà£QF_ë€'¢{8‹«Q:âPÂI)<ù ˜¥€©ÕêGµ€PIKK9Õ{é¢ÄʱØÂžۯ䥀 ¬Ó¯”²]l¤Qæaš‘ÍIÌ+ÌRRŽÏÕRèKU÷îßûäÎæ‹«ÿ£´:ÿùÝãÊ©9ž"¸Ì—RˆM )ZSr pµÈ«‰‚ÄQX"Fã_ª,jés€'UgPsVìš Ö}Êë³Ù)vº D£õÖ\ìŽ §àîÖÉ¡o½£µfÉ1Ië£ù›ïï÷·Zª¿»ýª*å5Ù §™â¹ØþcA±RÀpÝY/]£H3à¢ïž©)Üa¬=: SNý„r§vŠöæ]jÀås“s"*H9++¯$£Q€ÂެÜ'k Ry®_1í(ÎS‘„ '‚ Û Ìa%}1 |Þc²VNlå¨_Ù6pg“‰QÃëïþåÎÖeh3m¯þpóþ·‰b.±ƒàgFDìÀ>wöÈ ÆÉ…»¹‡IàêC@àuCÉF)·å”÷ÄšŬ2¦‘öçʬ‰®"9µ¹hI¹xà€#‘mÑ%s)׃þúýïlÜÿž´ÍÅüµÿïèp%›.!Q±_—…(‘3’ QBºˆ¬Žìq£Ìš¬‚U\=à‰³(<ÊÓŠF ûŽ%× ‚.4W·(Ñ"ï@dØ£ °žXBéiÐù@È(³@xZ’R5ü¢YÙJI²™Š*X*¸_~Ìs H^V@ ‘¨†a÷d?ÏÎáÞÜÊÂ3ûÁÛÞ›J{»7—îüÅð„ „á=<"Ù¦¡JAYO@Vús|Äq…EvÌnÔÙøòΈ ócQ@ŠýX%"d·™Ò_ëuk7SD5ÊU¨äÙÉBeÔÐxê÷wW—¿v¬þI.º¿rïSÃÛ%Ç”ZZ6IÍxÙåÏ€3mpªWªÂ^|äâñ‰Í”¨öñÊG™é«\Þ£Ò×(-ÓÂÀ´¨í>*+×=Òd퉠HÅ€*@ȲMÂ,aæFÕÚ`°ª@ÄØQô;ùˆáúUE ¼>ád†€U©Ëßqq>&õ«æF„Y )4^ DMñ¸Ö»›—Wç¿Ðïm¸ÒÑÁýÅÛ˜Ey'ôÁ PÞ2ŸYJë DÛìÔ¢w´¾ºø¥íçÇI³ÖG[«?Z_úh7Þ´þ‡œLõ‰i‹B¡ÞY8FŠ|"5ð§p M•›àÊìg÷8³œó¼F5wH Ï✩ƒ>5*Ê;¨øÉ!¦ í}¡2àÄ_egËQV‰1RwN¸³x|†ˆC€ ¼[5;öŽœ}–y$>" ˜~5¢=Wˆä!¡üŽiO™ z[ë?»?÷´Ö}o:^¬Ìæ‘Çÿ£‹—ÞiÙ §_;ì''&ŸÁg @S¦I~ì(!Ä’ “zBÜëWvDh¯0ª/l½³Á'³Ø!1šÏgNHkx’Ÿ´&yJ–Sͱ3©4 ôñ[xiéÎ_,M‚éÁîæË«‹Ï úµ.ޝÊ|5uª_e½mF=-LÌUÊæ¦[ßýM9›XǨãµÉL?eÓãQ‰l¦^f¦×o;,+…f2ú´}ÎVìD6T"Q¶! 8Oº×T‘L‚ö+ï± „½Ùnf*åd'CÌ€"6"L³'ëÖÞÊ—ז¿J½£õõůîn¼¨Pè ÝJÄœ>0Àe”]©ªô>Šïr à“dHÞ´&+eD„NGpyS5}Y:ˤR“Sôxk ˆ.­œ*¢3û±"åbwûÚ­Õ»ð«nÚݾ²¶ø¥£ƒ•¨`º¿*ÍJé {{ìÌ’º‘±°ÎáÔ˜bbF_ø;OA†]´ÈÙ£Á3¦;lᮃ_ô¸vS¿›YøBްPå¡"öè ìzÎq ðôðd 9'°ãÛJiaÓ¯PkÕ€ ¨^¥…šË:\Ç„œ" @pì` ”Dp0óƒû»w`¢IÖïó‘'þîoú‡J7ìjÃpé€Ú@DúUsÿ2À¾m†«Ù¡ªŽˆ(åå/šH‰…Ì«itËñ¤¦Ðn’±Ó›±zkR>trÚè.-S {mé[÷ž™[$ìÞY[|æpo>‘òî$)´41s’”ÿ?‹)“¢MDµW¡š»_‰¯|”¯‹Í“ÌåŽöf>DŒÞÜÊS.W‚ð]’ ½kzÀ¹ñÑ\òLkge…é)Ù )ìA F )Ÿ•7É'‡T)5óqøêFKŒeXV ²5K6®°Ð¯ί DŒ¼uú•Ræ’N~ ÂËä¤ZQÖu°??wóOû½ÚÞ×f’Þ\ùÞÆ¿þú·¾þäÎHËîn…tJ{Ët\„ å™ÛxýŠŽð$ ÀíWÐÀˆ@×NDpß´ä‘ZQ@Y«‡NM€YÄL/;SJywÙ©´lêå´a=8Z¼ó‰í¸y2©w´±2÷éý[IÇPW¢~á¶Ó˜GÄ,ÿ$¾w;E½ÅÏÇl¦EUÆmí:€Ú«=ã5¸J¥d34ÿ‡Ô[TE9™ûò`¦P×TœÌñîÖxaˆá'jÞ$|0fÐ ´3m'š˜ÉšÏÇ&Þ‰°‡&´lJ.ìá÷+“Ÿê`€ÀKÆD{´ „Û¯@p ¤Qæ¦;6Ö~º<ÿ…Aº”v6_\]øÜCÿµs³P6ñÞek‹‡Ò‰@„<4¥¸rÞ6ÜEÍPî¡Ip ïPÑ7-ÎÄF_©€c€ú8‰D3'•¦W‹¯8ÉÁCS©ÞWHG‹ó7þøá×þêùóƒD™éúËð­ù·Ë0«’cGD‘‹¼bõBÙ”bßcú•öxô‰TÞûª$¬•ÀésZÓXûSÿXÙéå§„°QˆæXØÝ¹~áKÚ÷›”¶Ö~¼|÷£ãlq"@Œ›r¡†Yç8šx訧á²ËH¥x])ÙTÇ80=’©N"žQ*£^ÁЗHýáù<Àj”¥¬ð_?ô¥& 1";œÍ”®vJ"•Çf¸_Y'MlŸ g€gWNM3¬Ð%/^ì–^1•¬±Š@€îï¯.~}sõÙñû“ž´î-Ýþèk_÷›—w2>ñÊ)ìà¸N‚l½~UÐbJkÔ Ž0?ôM+­ =>·Âʉ:†4å­êë‰Ý2»×¶GO*uˆúφ)l‡áúìdÐUÛC³µñâ±úß;ZoEÍ¥Ãýù¹ïô¶kʦ- *¥n{â.O’ÐÃÙk”Ê™cäÄ›’2¿()¥Èª¼G[¾ š¯^%å%¿Ù"so¹*êW¥2anêÁ6XRyÊÁßeµîQøJ ›°C€Ï\ª„ó=D9 sò|!1†‰d ð.ädÅeÄËa ³ýJ•Gõ¨Ê@ÄFF™ÂÞE1Sy@”¬¬,|eg󘂤7W´|ï)ÿ|­ eç'—1ˆg.%Á5Љ8Í(¯ íÏ.‘é#½=2G냬œ¿Yu"e­Æ6ŸWg'‡Âú”7È{}Ê ´îom½³ñbuÕ^9Ekj½ å4E¹Ýà†Ž6Õº±ªxæ´V9jsbÊ;­¤Ú£•ùbã¦QÌ›ñ dmCeƒ©ò¾õ®ØL`£&$S°\ÌŽ|´½‚’¨Û`>uÅǰly ÈÎÒ[–È—mØ£ãØÌêô+œ©« %õ+§_¹21üÿÁÞüÂOì/ÀÔ$½·ueéîÇÞöÈ;Ï¡½Á¶_‰Þ)ÛóP¿½Cün’x¿;oƒÊŽÌ–Ë»ˆ¡Ä!’ïäLù¢€êkñ“RÁΔǎ°SŸ˜Š”·Ã°â¾LˆAuùÛ«ËßéZà„ìÁþÆýo¯-|±r ˆ¨¹(™e§«°±6̽Ô9˜øVgÓ€¨‚™"t²ò´—™ú‚Bcm½ +Ä“ïFŒ.eã&ñø%‘ŠP“äè÷€)¡i@`åQ•ê­Õ²÷Z5\6˜øHÚ¯P0µ³i@”•¢B¿âpûÕP©ôƒ©cìÓÕC|D@éŒpCª†”ÑLK™Þß›»síOý=˜¶t°·°²ðù‡û›?ú7DYAèH+7¤ í‰eÏÆa*GõfŒ ,`+8иo:[Ð3v¤}ɱ¼—” ŸÊgX~˜Ô]·þ¬Ø:*#»¢Æ1F êëJè5§ò:@h}tïÆäÏ|®š+?\ÿÜ ·3iJNR9n† JNÈ€rù¨ydj¥›<¹TH#å¹£ðYë`«™ÿýE‰|šP€'?óvÂŽgPT\¨qø¨?û[œzÄ©ã@„gáRƒÙal¦ærÍ©Ds5G€à(á»R4ëHÂdŠök·°qTh¿WÔ‡ØÚxyñîSÓeüÁIVžyä‰_{â ÿ¤a¢Ôã‰û«Ó±ÝÈ÷1"d«CYÙ[‰—Â]8ÄD÷¸ðìpŽL@í gl¶­Ê,œ>µwJÙ™^ßR¹mqýåÛŸBãNÇË—ûsŸÝßkwÓÍõÂ6\3«Yp™Å4nÚ+>,™}G®C¦ S‚f6PæúPrÚGIˆW¿+®pÙ/S¦r#èè/Ù1 ò+Ý‘‹¹ ñ"aÕmD ½¨Ù°ãÕ¯D ˜‹šù~…p7 Ø=Ž0Tu dÊS°=ßö+LP¿_1Ëì` ˜K°íŽ…dzLØÂOm®?SŸ« _Z[üÆ ¿t€ ¯´]†^¨ BåÎw¡_Åz-z]8üçlàÊÛ‡œ‚raúNHöÐ*3ÇÆºzh”Ê–Cõ¡¬V´S½"‹Ê)"¹ª£ƒ•[Wß«“¼ï·©¤õáÜ÷mo¾¤=ÃË{4s ib‹ìœê¬ Hqó…’(.õmü«<‘)Ñ[ˆ…½ÉTˆ¡”•M1Ê#øÄÐùXbhõ¬z˯'°ªÏïdx ìä€()O—-•‚°()óé:# áÇ;Ä–.å©_)RÒ.ˆå´.±_™-§H! œ~·®ýÑÁÞœ–tt°|çòï•ÇØ:aàmCKâò£ošngªû•@Œÿ|Â_Ú¯N¾h¹p™‰w2Ç:¡ùiÆeÒ©Å«‚yñ¹o}L€ò3ýÃ$Äš™×v9JáÙûó_™–}¿‰ikíÇ‹·?¢™Êt´Ë@`rŸ6Š¿;/O¿pà}-3JºèOª<„ª’!ŽFD•`ª^æR|BŽfNŠôfÙQ‘&Ey;g@ä§Ao÷Î?Û?Eê¿I÷®½osí§ÌF’ašÒW“ÔÉÇ@ù *˜Ñ Ùù9‡(b£ßçSK«ª‚‡ŸôùLÍ ¹ ûñL̨òJfœ üd®Ùrg™˜ÃÇÞi„&4,õ§°&Âg Œö€¥„œY@xíÞ¤<–C¬sVš²…³€ÀýÊ+/É–Âd!‰C)`Ù¦¡…;Š6;üØ_šûüÆêOµîÁ)Lýë/ü‹Þáš “Âo c‚‘K6ܯèÛ&oD„æ§_ ›€{P`èÕ$Ÿ7ã!·©æ$ŸÇNsÌ7°(i¶ávÒ”ª`]#²»Û·ç>?UÇþ䥃½{·^ýÝ~Ç.4ž «ƒßÂl „»ïÀÛâÌFWš²æ0 ¼ÈÌ_5ØÛ ¥~eÖÎG¤Þ"Ìž…*fÏ0nè° ªÍL?žŒÛ8f>›m@ —B¿áÄ)ßUÝ—§aÎ¥¡¥`\é'l~¡²JÞjÇAúUA¤Â™•€°Aq ØKCш@ìð@8»ÛB§ØÌþ`oiîs«ÏÂiNƒÕÅ/?öº¿ûú·ü—33ç¬Fû¶Èçܯ›“~E”ñ1ʤ]“9¹Ä5 ŒX‘Þ´SøåWÑÀÍTY T§´­î+­c¦¼6+UÑ)])‹…Ž¡õàøÕ¿¼ðÕ~·]áL:õ{›ó7?°»õ p¯`'ÕG翚fØX:S©¾K1£ eøn bãålj•‚±=Z2„qì8@ˆg9g KWÃUVmP^ ={ÕUĤE‰Ó.+[‘dRABATâ–U6¸¢Ô0!*öÌä2_3@Ó¯8 lIÖªÀ}iúñ;|HUE ¬lÑ•x/èÁË8RåñBëÁöÖ•;7>|JÿÃi°¶üí×\zç›ßñ?œ¿ðDû}dDpëiîÒÐa~¹nUü"“_ÃIoZð¡¿m7‚‡oZá¶HYL¯ÚË1½ìd…¾tŠòt ³(WéÏ…òšìTn£ßÛ½wëc{»·[缓iÐß]žûÌÆýïú'ç^tÂgY©Þ‰,Óg̓Œ²B_šÜ5~â ZÔY€*Õæeew XJ’Lunsfþc ¸àÏ…I Ïçh’Guà¬ðR#f¼(§²u6 ”5y“¼Bp @ÕEtÿ@ÀCcP#æH0‚xR€À”¤ô+ÁfŠèáÕ€ðÈæØq”PJyq©‹ëpGùk+?Z¼÷4<Àé`onáÎǺôŽK½K©™ù޶(qÜëWÖ§È®WÑ« y¿"KÓX™›0"P%ýJµë¦¤šZ^Ö$ß RÞ©Ô] Ú§¼S)…òõ[WÞ?íW¾ÔO›«?Z¼ûñÞÑZJ:ah´k&øJm›½‡L4ƒj¾º/ôÅ dPnKég§H'°KöeMÌžcÀQ¥ˆ‹påœñZ,ï™êðŒËh¸ÄÐOëÅ '„-‘ÄY 0ĸk»ê@T }Q¼c•"ÚT6ŠQ”0‘ @ðýªÙý ²F„'Jg5»µùʽgö c2Ó`çXD·>|áâ.¾æ-`F¶=sÉâÎqVv•?"¨WÌ;…ŒPB¿+4TC#¢Ì2Ü/Ìù8‰ŽCª]ÝÄ(o§ÞîQ_Ýn‹Ó—ŽŽ6ç¾´¹þÂñk®ýÖ¦5 ûkËß\º÷©ÞÑ_¢¨Z2¨¬*rÒ,›ëÚ>‹LÇ1\(MY˜Ó¢6SììŽD›á½œÝU¬28?PFØ_˜E 7¿³ñ c.; öh,^Ï1àÖá~Js?+¡0xz{šo뇄]ßȪu$Ä<4®Ä4è&€RÂö+¥ë+?]œÿr¯· g)˜ŽW—î>uñ5o}Ûÿ±š¹0ÊTÈ”ŽöJ¢‚«¬,$ð²“ÇS¿8"’ߴ수ɛBÚ×pº c;õ2Ï(o„ìéeÇ¡goïÞü½Ïïnßœ4QÓ‘öwï.ÜúðÖÚ³âV‰S`u¨D¡Éú¨ÝˆŸsL¦ïpj¼djé>eÕ‚©‹/e³ÈûïèÐÎ!6áØë9€˜ÝÇ8¡/@Øïc7._4iDfácC_Re 6SÔˆ@¿Â'°W"Ea5!¤J—ˆ*ø ‡£!ƒþþêò—¿©uÎRRlo¾4wëCç/¾þáG~h'·ŽÿÌ%xh´3À¹Â8S¡(.I1˜H­!:À+¸ÊÊ­ø:5Æ)ŒQÖ©©›ÏTuk˜TbÈêWã&2?3·°ôîî»·>~tX븛-éÁáúòwï~òðpE*3Ö~UémÓÞˆ˜µuÐ9QCˆ9©Ôµ <Ê&`Gi;„hÁ‹ ð\.íd ŽªçWÙ^Pä[/úÂT!m`Œ×\H€ DÁüÈ;ßðæß™9÷p’6¾¤è™:"¼ÞˆðNebÀ5áÌ„7­èè”òXŸ˜xá1òÖ–ò8M;ìL*uk]¨K¶7¯Ý½ù±Áàp\²9Uéèpõε÷mm<¯›ª8"T¤ðØÒ̈…LÞX©ô‰S\y|!½*,~!U¢G ü«œŸb lasá}ÑF¡šieëpÙ5e£ÄØ’ôOI@¶…t52(‚ò¹T¶h¤rÌ;ÍWBaÓbÄŸÒ%=_VQÁz(GÆÖá£FŠf¸AÙ¦1"Â8ŸFÕŽFéç"ެ¼ü~ÿúå÷îï/ÂYªšöwnßxùß,Cˆ²ç“^Nz±Ÿ”;¹[R|FÄpn;¹Ó¯èC¡7­LI­Ó@ëëJÒ³Øì;¢†ÇÍNs\´Dùòâ7—–¾Ý•hÒÛ›/]éßϧÎËljoDÌ8…\M„Ó(Åz‘:†ãmú'±ÇPâ4Çh¬â|ŽØ!óy©ÞrìuÅõJÅer…‰ºª 7F½Õ|%y@à&øÂâʉh«X½ÕlaV‘µ{8\ÔS¬Ä'ÞT Þˆ1ÌjÀJÌBI›È¢Ä®ßÛ¹üòÿ+nv–2’î¯.}ãε?òau÷b§ôIlNîO+ì,ØE íWeȰÁ$~Dp/|›*s®ÈÎxSÎ߆(Ÿtš^vºFùÕËïÙÙ¾>!aœ¶4èïÍßú‹•…gÆßt¼_©Háú•W…= (@‚JDƒ©Ë‚º{÷ö§ÎÿL‡ûK·¯üá…‡ÞôØ{”#GòÐ~UüÇ„‰E^M ý p§ˆQ \QDÑá—ÛfFD+w·¤+u_ÃÍR'F¤J.Ù1vX ¦‚òj@ô{»—_ù÷ûûË¢ú´&½³}åÖ•¿·s{ô½þûjò#¢*å3asÎÄfYÉfŠ4f-ä –n…›p¯WØñ (‰#›aÛ`9H=ãœ@¡d äÙ¡îÄŠµ’* „€`ÉU‘ß©¸h8’¡0¶_ÈŽ[X9Ä`"1¦¹@P›iÐ;Eû•)q>£¢. ·n~dcí…³›Oz°±òû×ÞgŽŠ€púÕh¤Ž¨ÛB¯&à{`dD(ûeß=h¢Æ0­à=ãõó¼@ýYQÙÿkcÊ™äu iÏmÃä1­ha‹RœÇ5“΂²Im+B=GXŒá\Tb‡ÒyDŸœù|eîÎçÏöý¶“ôàpyþ ó£»ÃÉ%¡Ð~•ÖcTæO•8Óá£ÔÍu’=ñ&d®dÛ"6(¡0˜ kئÖÒµPæc3ÅM`Æ\\"1¨ t4!Ʊř9Sé]Wú¦ EdËæÏ÷Pœc@»™—Ð9vǬ Ø•›Ùœ(&¤@€Èr €h •<41e:všPˆÌ«Y=§ˆÐ¯†‹eÐß»yíCë/ÃYj-õ{Ûs7?tá¡7½ñ­ÿ…2§¢F߯L}_úU9Â…ãq½WmB|ÓÒîȾĀŒ4>‹+ ߀)?ëgáV£ƒ³›u¨œ -G¤ï]ãN/âÞ)lýÞ¥(ž¤À­vô ù¦ÉK‰}³ûP³Xž6¼¾÷|BqäFÙ”;'ñ¼{be “5dêÛ ì\ ´/Øâ<À ªP¿J™ïE ü9z.Šéá™@ø7>j:mè…ù¯,/}[ë³ ¿ÚM‡÷ï^{ÿÅ‹ozüõÿ ¨s'YxDx×þ€U¼Êo&_•ZZúÛ*^F+¼–•-¯è!%šö|”pg­š³ûI,Za§ÝHOn¢b¿Rkh…:@Õ;ówŸÙݹÓùg §Ýík·¯¾ggë*«¹uÿÕTó}5ƒ< ¤œã+ݶ¼ó%`}¦éýmǶÞ[‚öEG*7åƒÛÇØòå^ÇW,´HëâÉÆÿpa• XDqNçùä€=êLf²ç»|KvŒ{ïnóêQBå<в“(+Rùh#›ÁŠœb›úž=" 4Ð#7ƒƒcõiñ[p–Æ•6Vx÷ÆŸî/’[“ÊÄmúcGDyØ þã•®2ŽSú-!.Ï›!qøM[®:5ÑI)]iÍš»ÅNçÉžjÊ;ÏÎ`}í…¹»O÷û{Ê––î>µpûãýþN¤œÊÈîR¿Ó¬1 Ñ]H eYW$²—œ…‘EK•Ó¡v7øˆ[¢ 4¯§ïB’‰¡¦:Ò†Ù_¤ahw›­+e‹b7kÈH¶¸5ØŠìoµS¤­À ±¤Q³Óå¼lý{:~¥<x[?ë=+Ät @Ø:4®Ë4?ìtá R:8X[˜ûâúêóp–Æžn_}ÏCÿüÞò;33çM&*ÿmSüà~0#BvpÚ’ösµ7­äH°«å½iµž™äìÃñÎÌ-<"»6É·ÁcV ­=V…òÎ1ôÖ×þêέOOš4iÝ»úâ¿ÞZ{ﻮ߯Úîo5ß“Cwf²ÂSGù°c3…˜ÍÔ±™Rm¬å)ÓÆ²\þÈìÛ Æk×Ì“énN rÒôp¿ÝY¡DyܨÙRŒ<ß‘ˆ‹Q†¿»—6o".¤ÍƦ< *)¢\´·ŸZq•°ð:R`7é9Ž~å•´õŒ,jôàW>¤Jy-¦G›˜=瞸vð{m¸CÝ ©R”ÅDþ0Òc Xʃ@øçÐS¦«A …eË…ýøçØÏll[2"% s_›ûœ¥Î¤£ÃÕÅ»O]|ÍϽñÍ¿}nöa€¤£Îé¹2ll›×¯Š¸9ææw§~ÓɳG­Î)Ÿ¼¸’®Ô)MÀµ-L%;cbB|N Q¾½}óʫÿ;–öwoÏßúðÆêOýÊU$wÓ Z;f]­U82s ªp.®D‘ ǫ͊þMó%ÇM“szˆ†ëª· âQÞ Î|΃ Ú-aôlEîâ“&150;Á£‡(Šƒ[# DYEêq7*Ï%ÄìÉ •e'ëè!p¶((oDPõ‹6e–Ez;ׯþÙÖÖ 8KÝK[ë/ÌÝüóó^÷Èc¿¢fÎ%®åŒÅDæ¿TùÍL~5ѶóÞ´e‰¸ kÚ›2¦J•QCÛæQ>Nre³¾Í´m ¡<—ˆãériñ;s÷¾8´ÌôYª–ôêòwænýÅÁÞcëLKõï_j5Í:zZ‚EÉêcÊÎOÁ=±¥Y6|3ÙtÇ•d “ÕÃPµJ·ÅçÏç¬õ¯„XUi@ÆÄï…öÚNr €»t ”û@˜ {O§ïÀçŠÇ ³¼(â–çw?j̎ܯPéª@Döf`úq èrÕìu]^5S°½uóæõœ]øÕå¤õÑòÜç.\|òçá:þq¼ŽNé„ÅO)§ˆ%›øÇ‰õÐЈå—_»²%ÏxwÜå¹ìLŠúbÌZ9uŠ)¢w´s÷ÎÓkkÏŸÝ÷ÛñÔïïÍßþØâÝO9 µúcªZÊ2DÛµ>€ŒÛÏûÈ-ܼT8 _²™ð§¬@T«°ü¢Ä3àÚ³¬oY¡/E¾QI©&볓ÍOµG›Õ–.Y”0@p+§->Y§_¹+IÙ1à5"èr’Í·‚Bªr:ùñ:uåþOæî~ñðpÎR§gé9:X»sí³çû¹Ÿÿ¯ÈŸé#‚náγâN'#Â{ÝÄÊÕ ¬â+€¸¶•3áTL•êÍS“Muãd¡rò´´:ìåé5ìîÞ»sç3[[×&ÄÖY’lç?Ü_¼}å}«KÍÓ]ÿmÓÔb×»L¶™¯„;ìGÎÌ*VŠVš@’¾½`d¶Uö¶6óÖ°i=ÊÌAÒ©p±2’U±XbÍî^¤L2$«Ÿ1v< <€R•}‚c€P®¬pÙ*EÎB!Ç”w3ãÎ)W2: D¿¿¿¸ð­¥Åïg~µ˜4º½dܾJUŽDE3GŸ÷vnÞ¾úžÙó¾öu¿ìˆÈêWœ-Žˆ²_!çuÁ"f½G_¢#¢1@Vªéè”>ØiÊ[^9ƒ]©[”óíéÍËwnæÌ÷;¦T1x‡­Io®=çÚoo]Žô«X»Q"gÙi ¦~Î!&1šª˜¨’Y¡/‚cÈ,‡ÏÁ¶Z€«<:ì`{´æõA–“|G¿!Óê†ç!†ýÄÕ[ÜÑpI n Q˧%‰@(¥µ[\ ý*¯Ñì«YqqEG„v (Þ?X½sçs««ÏÁYÊMñW¹©Uf¢™ò²ÈÊY—Û@È*Î:8úpuù»ç/<ñö_ú_zø­üˆÈu•ٙ¸_êýî›B~5±ÌÐX}0y-¾ÑÙ¶»ÊcMvÆà¡i‰rœÙ¶‡¦6…)…º·ºò³»w>7TÝ\z–ÚN±i¦ßÛYžÿÒÜ­ÜŸ ™M½¯fÙrîÄÅÙ£A˜sÐTË8ÀªY4¾Íil ©œ~Oß^0,¬G–m.ŸØâ±š² Õ=îÈd`ñR`˼!R¡ºœ°Ñ’Ž3%òB_,ç|èKE í»bü•ܯM–‚hygÓV~5¤\ïï-_»ú¡½½x`“¯êÄ+–b‹— ŒZÀ[JL V‹úq>“ž$8:\[¸óÔù ¿ùmÿõìùÇÀ+f¾³ÛhrG„ì*+œÄë Ø^ŽˆJ+€vT¯úsZFa•QCÛìt-ˆ.±Ó*¹ÇZÿí[O-/ÿhBbèRÒèCs6úH[¦Ãý¥¹Yžÿ²s{såÕá8õP¡`jH´™Çðö+ÛDz0µ­[9‚J( ýÐs céfyV 1É—ÇR,£!Uá¨v DêÒÈœ:è:ÀY]dÁô+Ùf*áž&¤¬öÆ9R`d+RÎáùx†?¬­½píÚŸŸÚS2 ô@gRÀñy9z(}<š³æ; ß«&¶ê}Æã/zo÷ÎÝk¸pá‰'Þø[øavDDOß´À p4¼F¯Žb±£)é¡^¾ ÆtÚ”Çj:¥ò+îK[@tÌCS‘œ†¸è÷ö^|á÷hãOS©íC:!z°³uõÖ•÷lo¼„¯OjjDàÁBwäú+\·"…åòzø¯¸ó‰»ý‰6ªÈêW®üFË/Jè÷â®ZîªY¾Žn‰}{‹–"¯Ýhù¼yòÏ¿¸ Õƒk¡¼GØ÷ˆ‰1ª¼¼¨¹H“¬èó<"%GQà| Ê‹š½ Ñ.œo€r·ªË—ÿäþýŸ@Ç2Èèaæh(>àL›_dhãEsË %a r˶†Ÿuù<ý`>+ªÝƒû\|@MŒJØñ„þÞIn~¢Àô`sí…¯üþÁî=oäGDN¿Š+†bt*òd ‡Ï°õVɃ®ÛœÒÚ©%EVá©`gb”'W7N ––~pãÆÇ§&òg *6k‹;-4§uoýþ®½ô»½£mh­_µ—xPº†½š•Ö€Ô/ïjÝ$ éu™ ZÏŽ™*ÑýÃܺ‚‘Rê¹è)àd+aæsLŒ¿T+çûT ¨l)Ãi »iŠƒÇB•tˆÁøÆ 3@¸]Ã]Õ••$.‡ƒƒ•W^yïîî<Œ?e–¨·V£w3ÍcÚ\NTèRÏÔ(X®Ì¦R›Ö`4÷á?ºP(¥‘ÉÚÑâÈgnÅÀ¬°È_^HLnÚ¿AÿðþÂ×®¿üÿº¿(>ßÌ›V¾1›Ž¾QÁÈåOÒÌ™ò8~6+²ÓÃã¢eغ֯®^ýÐÊʳ“<ò³3FóSœú½ýÅÛŸ¾{ýƒ£¯z5…GÄ,J ùµ,u‚(-IZ Êk{­ eUþ&\…+)•EéÐ^‹yY1öÝ«2X[~®OÓ* Z¸¨v¦E”ËFò v¼MNè‹ „ªÕŽÄ,È ± óªd‹ïW»ïÁ ¦ÆDEûU…mÚ¶S™òaZ˜ÿÆ;Ï u ma"Ôór4½S«ˆ ¢w¯Hö>³™TÊþSºtmÓDóÉ!·…Ô;Ú¾}å/>ôÆ7¼õ?7roÑã5ú!|ñ†«åÈÆG¢ÑMÍùØüªS¡jî§úZ^÷Âoˆ‰Pž¥Åw–½½Å7>9<ò³¹·ÎôÍÇÊŽ+;û» 7_ýÕŸ%–-“i%¡‰1Sî»u´(ž²ìÐ ¿ 6SÇ1 J-_4àR“¸ÛDDLÆ-Õl ¸–aú☹æ:Ñ4Ls]vâ@ G¿UßÇ@Aˆ@ȼ)…Ê HPµëRvT,;±Â׃2 úò$’„è z·n=µ°ð-Ñø7.cc=1ÐÓ* ìÖ@_’S~.Â`œ0'äÆm‰sâ&Fò˜Ï¶*ÍTIéz‡Êôä3Eê$ ¶7.ßxù÷w·®—1FÅ‹ IE3]¨R¡\Ø}‰Ãgfâ”u 5 ÅwžòSDר©5kåËË?¸uë3GG›b÷,5‘rBB‹'tíþo¾ò‡{KÎOÃÿÏ Ñh+ñÔe鎚Ç;L¾àEP¥æƒÍUÖvÉWR~aÉ`ØÁ“#g’fêQJQ3·)Èœ›O›¨rGnÐÞ”j¼Cü )w/{m€sPØeÌîH¹dHóÐxìH¨Qñ:§õ{'û#Ç®Çó »»ó·o=½¾þªsÊMæ1ô€?³z,ÜŠ¶x©5š³ ãv³“OMÉçMä¤Äq‰ÄèoÿhéÞ—.\|ã;ßõÏÏ´( ,¾à]ñzÓ¦Œ\>þZF_)× €’ш3kª„áëa* Z„ró÷%`žÊ•€Èσ D;c"˜¤Jƒƒ¹¹¯Ýºõi­ÍîP]ŽJ@iæâ…Pn« ÙL¤ÏNKô³µ´ pµ¬­†Ö+©Âšý¢Ñ3Ú'E 7+iúÍ5¡9‘…ä$R[¤ DŠ7• úûs7?:wóãƒÞ¾'£bFo~DÐÌ€Y§Y«{wùÙ™¨øÙZ¡i•U0E~BS† |º£B§ 9Ä ·$,º ÐÞyЇ¢>b·3j¶r*sêQ¥žëŸ¹^9AÚê¡8„ªûq h]J] ()€P•„i‘ëW¶EErýø®XJ šâxȬ¯½òê«Òëïû”óýª|#~%å3Ю”IøamâMiߦ F(­µå×ÙøbB ÿ¥ÞÑÖÍWß{þâ“oúùßžQ0Ô‰¶Š*#Âdʶ‡¢žò¹Yà»N±@0¡C6““6{¯3Õ–Ìfp%4Z*Ý.ÁaCèɶ ÿ§í(6¹üD…Í )ov(üâ¥- (+òJ1ïIÔ;B UÚ|º]ˆ°ã™bœõ+æÂôŽ`áŽ]¨$AyVrràó«—?°¹y£1SŒ)À™}œšL•ëM,/ZrM1QI£j›Sˆµ£ƒÕk/üî…‹¯{â¿9£ÎA¢ai:¾]N™6HoÚVƒkoÝ=‘”ÁŽÊ¨¡IjêSÎ}™:Õ t&s @xi {÷NŒ?O·ØÆÞ_ãl®µÈ¤ØÑ ;»óWÿêßl¯¿R³mqDäX‰Ù4ƒK ¥±¨ÒÃÊQäR¦¸’‰›ì‡ùöÐÀ*`þaÆäsâ@f/n˜Ã‡I˜MبÏNl#81Rd#…Ú($@$ÆAy“ µÊ¨1@@Ù¯Hg3J0±Æ8U$áÊV¤Ü‚òƒ÷Óã“&$ 6Ö¯>÷Üÿ z èÛÀ·„»Ÿû{Àô3ª-”tþ¿:)£~÷ !Nf…ÙÙßÝÏÞqm³#›×¶7¯\þÙ¿ÜÛ¹g²éɉeçoïÕd2¹!®Ò«†µªv”´ú‹’ ºe¡&å][cVÊŽ¶Ÿ}ö_ïï¯fÔXÿÝt–¦!m¬üÕ•Ÿý_G‡ëì¯uGD½q2£Õ¯)…êFŠðªÙ‰“©'r?1™h€7ü°š¢«"…’>oé»Jbœ Gd5‚«Nz @œq`_ÙpAY9ÑŸSCü2Ò ª ÕˆKWí}])£_1@•Ó›NL±½k×>¶¸ø}Ds/:&wà°2N²t£y@-n\ç—-Qu;Q‹§”9ñLc`§ÕÅÇîòü×n¾ü½£MaD0ëVú¦5%SU{ˆòß8.„1í&f¶WCF½ÖÔº†›SWK‹¡úPŽˆ6–°Z¯¬<÷ÒKïeâ-O“2ša±2í>¢£õ½ë½wýýÞNû|2Iêä³xî1tkî1×c§&íFß)[Þ#B¸™-I jR¹çæ¶„•ÙÊ9A(‰M^jeIû§\ ‰©ÙJ²JÂ+¦¼ü,i¬À+­ä0 fÇ€¢-FpdËæuQ W¹Ë„, ¼‡3vŒ•|¦f3ˆŠÁÔ£ïýÅÅܺùÙÃÃMÛeÇ ŸòMø¹æ³’ äÚ߃CÂ\e}µÒ wÍë7_~ÏìùGÃ<3s^è¥ZX^TñQÞ¢ B§ ˆ6·›©þ¬8¥”OŠú«‡é"ÝñN¿nmݺrå/¶¶o3EO™Ñüô±3¶¶¼´µöâíËØYU&wMP™fÍ'Þ€ËÙ£Ì9¾c`TÚ^êÂê‰ÄxíÉK  ìj‹8Ðæa·AËŽ£QrökÖx *¤Þ2<” çg¢Ÿ„ÄUÅxÍØQH.FÝfoÐáoÆáÀ–%¢N ^ªØƒqn% \‰I+'ˆƒÃë×?µ´øc2Œë¨À‘œ_ô—jzhòˆý{•+«rÓv[›ð¶Œ—´î¯.|ûÂÅ'Þù®öšGÞÃÙðÛ†¼TíÊV™BÑ·8#Âdz¼Œ/ È'±B渓b?6ÊNË|fí‰í”‡&ÍÙIHýÁáÂüwoß~æÄø3©U^•ÿï@O˜Š4.Þù½ë;Ü_á}»É)o™îåΆµ6Þf ®ÒG —¥‹?Þù«‚Â>̤¦:Þ€[úmfš=ºÔpµãÀó¨m }aíÑ)%¡/…V‹ž°‘c@§ÁÉ–ÒðCäÌ%CX±Ä£uåQ–#y@ˆõ›i5 ˜ˆ pš9ù3ØÜ¼qíú'66®‚ŸÈ©=@›Ê²Å³poáÔ†Ñ|DU•y&Æn“Id'%V‡¼túG;s7þòÂÅ'ßú‹ÿ͹ó—°Ó/8"Pç/Ôë>~TñtÊ$}Ú"yj³S¿¹‰l«_µY€ýƒµןZXøžû³c\yŒæF«OŒdÇj•¯‰6q¬þß¾ü§K÷¾¬=¶À^M³BÄC1ËÆüËF #¶ø¨=:èYiõçr1’GÑ㯩Ò*²cæ_ß[e‡³‹zk,ß1 ¾‡£ÚyÙÖv Ô®nh‰ HcܧprôªAÿ`~î;7n<Õ;Ú£*:XUSxÉÙ³*£Ö|š&n4WH~ÄÅ6.Ú’Ü'ÀXxc„ì5q]‡Qtt ;û»÷n¾ôÞ‹½þÉŸû-`;!¿°”ÛP=n±·Á¸}lš^-¾¥Eɤø«ß(¹mA“.¿ú¡…q2ÚÑ$õÝN­©›J­-v6¯\ñv6¯Ö¯ §ÄÎâÐþ@Ò0£ô9Ðçfô ÿ;ùªN¦ /€ch%Œ;Îy=ú¬}­ú &–UÙF4Ý0Wp»¨Êq% G$ãµpã#W9¸M„LÆÆxÍ-›@R{‰ÒJ,î¦ÇCÃÙ»yÁ Ž…±´YŠ7FTÂ| Úâ}Ùö°Žô°éä¹@m¿òʇ––~Âñ¡¹¼– ôøó8æ ‘–}eµØÉµÅG ôˆÚ1H,&õ¥ßxé½ýÝÿÛC—ÞêÖäÙœÕ{yê0u xˆ’gP%³Çoùó3ƒó3ú‚œþ›Uúøß¹á¿_¹´]Y¯î\”ÓÀ`8I N惓¯‡ƒ™ƒ:Òç3GZá ü®‘9©$#ÚaÒLg]KÝâÆÏܼñ链Ì*XšÎ!m+ÂZ˜²Ún ÊÏ*X8—¤ ²Óv vªÅ;_¸pá‰wüÍÿùÂCOšÜ1ŒˆÙ_¾´õ®où@úåKñc^Ù¹t4˜9,¦„™á|p27Åê76G£MH¨‰÷³ðÒ,"kÀÝ1ŽåOtŠ„÷´° çË#ÞKn´ äÚâ=MFT;¸åyÙ Ì´ã]äkèi]¢‡3! e Œjê®(3€••^|ñý‡‡[^qÍ~‡|">€Ä÷Úq±¼Ó1œ•~À@>óQÝpŸä”ôöæn~êüC¯ûk¿ôßÏžK1àìmE%4Z·†Ý„³-½ýÓ¯p“Ä凇Óù·×Ÿé—1§_‹ï;YíNžòXcÕ€Øß_}þ¹?Üܼ56>NCðÝç5ÒÑÁÚ½k½pñuo~ç?™™¹`ò[•âlý*OãÒ®Ÿy¼V8žvçöúçvzÇft¥r à@µ¤ËŠËev¹ðPT)D5paB)Ž(§èPáò{¹'Ö€ÎÆqÙAºU}ƒÆn0-ÈÄ ò¥Ü•“g‹§@ÈŽ â ¹:R }q6 °Ž§(Îì÷_}åÏîÞýFÒHdæí¥qú[ÿÓ kà$B-ø¾¯`¬zÈã¾*ó™Ìr€³×8{âÐ{Ûwï^ùó‹½þõoùJÍ0#Âñ³EFDù#Þù¤ðéœØä¬^Ýyx·îøßNÿÜvov›Œ2S}¼ûKNQXŸò1qëÖ3W®|¢×ÛËxf Vf§¹¶ëWÉiÈ|jœ>€±MÒI%[ë¯Þ¾üÁó½îµOþ-冟¤FÊš ÀI¿LW /o_ÚîŸÛêÏn÷N¦„ÆÖ]Ë5Œæ4©Ý1`žÖZRØ0!v5À‡¾öhÁ¯PåælSZEºcÀvÊǽdk³(±õp; й½J&ȇNéÔø1Ù:=ê"3iÛ»üf•°èÎc§9!yƒ‹|Ž‹#T€ÉD>€ m¤>É<:ؘ»öñ×\zË›ßñOÎ;ÆaP 6_¡L÷mƒWÝè}¥Ôéœpú{¯-Îk|~ë‘ã™`åðüÎà\µªº¦´V¤¼Ráî²ÓZÏÏÿòåîíÞ¯BbÛ*¶ä‹l<©ë¿Ã»ù‹Áë@é`oùÆKï;^<ùæßR3çÚˆmƒÓº`Ó»-^/ï<¼|xáþÑùíÞ9]ΛXà ô â ®ö]=06D-•¤-€gÝc*9Ê*|{ À8(ÔgŸ Š{\Çø&a>ì'„ÇUâd Ê…Šë ²_߸vùòGÖׯjÍÞö[,ï¤Å;k(϶̷œ×d›GF°æ<†×º”÷,–#k¥’ƒ‘ï ™!š¶bzn”v> ›Ð»[·/ÿìßý­Koyäñ_¢±miŽwDàqVŽ‚«W>ƒbºÒ÷×_»txak8°N>¶SÑÕ¶³¾ä“æêŠWN³²ÊëPM4S ;ÄN®¬t,¯¾¬‚RbÑâ£/½ô§Ï=÷žÂøÓŽ]"U‚‘ÒQ»E½æfZeh¹/¬BÕJœ U²‰­ÅË*5óÄý×þ³?œ½ð˜óP##âAŸLúÑúcÇ3ÁZï<û‚2P¾vG#ë“—¾‡jÆŸ”ð^—+qÎ\A#fæLÞ\ÉÛâAèÇaYYzèøJbÇÖýþÑ;_ýÞwÿÅîî"THâÛ˜µ %¾Äåëuý¤jœì¦}b´XY9®‡Ælñø)î vy }×ÙÆBÕ:33çßòÎú®ßø—vwXÖˆð¾àÌÈN¿þxá*øÑÆcKÖ{çÓõ•±Fò´¯‡No`R#”omÞzö§¿Wñío’ce[ÈMƒxÔ§Ùe<¹¿ŒÙÐ6:ØH”ßÖ`p´x狯yôm¿ðîžûì™ ;ýzé4þ鿣ó7Žfû&|høÞÙb}Ø1jª-é&Óq p+AÞ»`åü§¾cÀþD©Ow _~á¨cÀyo$zhûÒšVÚ;ÜùñÿÝúÚe`SÆ‹‰ÚåÉÂÆ$5#3« ¨5?°4v²}¤š>Æ Át]¹_©`& o#DkÁ%b Ã]Ëhñ¬ž|Ölþ©T™Ë%6ï]ýØ¥ÇÞñsoÿÇ#~ȰJ3~:A‰£Âg€˜þÎI,éI8éÏ6¹³ÿÐFov´¬~DM)Vïôjñ5ÙɪÁO¯¾úá;w¾6Ðm›«åÔ0ƶd™Æ4ŒôîöÝ[/ÿ‡‡}Çc¯{41ÀGùg>€Œô͵Ççö:8±¶N*̌îqR Ïe¹nªFfwÏc(çžW^_¡¢€±ÖJ TÐ…+—÷¼¸ì#ËËÏ=ýÙÿîèh·ªñÙ+Єß0’ÚpPÛk¢ª9'ÊÒC>©ùÄSÑ[¼cµ7Ÿ'€ŽÃ`½¶”:÷¦·ý£wýúÿqñá71’Ëe:[d¤¿ÿÄúñÿŸß¾t{£óZg«IX=TJY× twý‚qv÷vïó›ÿûÑQÎ?‰iœ>€ú©ARÓMíŽÅ)¥[Hµåö§¶ÑŒvUjÒýå{߸ôØ;áWÿÙ¹ó7BÝÙÞýÈλ‡'O|oíµ÷öÚú¶Q—N´i Üîo\àßm­&S‡ [b”5ÁËwŸùÏ«ÔáÂ.…øÖèB5KÞ1@¥äS¢pa“ÅÍßÿþ¿Z_{•ÓQ±f³ÅóÆúJ#?ë‘ õ‡bqjó.x¿3û…èô¢ Åd‚¹g{è†ÐãE§ZâæÂþÑîÝ+{ø±·¿åþéñ‚üa„',v1x6TO¿ùÄÀÆ«;_ß}Íñ‚ _¼JݸóÉØ…”ý…XIûaEí›ùfö›ùΙ©b-•þô8r«u E@°åº¼Àiõ8Ä\SX Ù3gþunî¶Ðè ¡ø+K’¤ ³š M181¤nT«…àW&t|®fx‚ZpÕ‚25ó,@(ÊéŠtl}ˆ$©ÄL*>Ee—‹élÅ8 •üÂX'àÐ5T‚øÂçŸuyºCw•®˜ #ÂdõÂ.O¦´5釱À•¬ƒ‚á ä:¡u )MÆ\’Øä¶q³?7õOŒ¿œ§âM«£ÉF€¹j×oŠi^Ã[Ê&B†Ê®¬¯žÝ÷?„¢ÂÂ0ÉÄúå Ç ÓÉøÇ²©E–¥ Ëò™l¡È Æ@D½õ@*61}ñY‡+ê ô×Y”én0Œ¥ÜWІ?Í ^\¤Ó—•®ã]åU—,Ò_wäê(YVƒd=´»K72ÜP^_Ÿ<òÁ·¯^=JèØq^o]bhöì‰,Ú+Ó PÕÊQPõÝêäÃûÞ÷¤?8P9†¥ZFÉgÓ ©øL2>\K¬OdRó-@X€,Ãr9~ÐÔcÍ1eß6ôHÿ¾GmŽ6õO¤>˜  YðÁz`‰²S¬…áwæ‘/éWˆDdæ&0 2òhhõzÅÕÀ$ˆÕ”Éwü®žyj|üg,Kz@¿‹²~YÌ7‹lT37—pŽ8ôÀÓ._7À¡ tKç“©Ø$Ç ±‰äúÇéälɲšãŽ S‡ÍH­‹ä-µCwÿ}WÿHÒAèd„|1@sátÜ;O93’†€…J6P!DE(¤ö'¢Þ†h6ÀŸü®2ÑEè%D|SUÛ.·ªâêÔl;Mg.^|ñôGß§¨Xý3ŠUØl@¶ë¡`(’‡@Q¯Á8Þ@OâÊz•;=T·f+c„܆Aw™å_1Ð0› ¶o¹ïÐOÙ]aEð¨Ð8„øR(Péø Ç ëã©õS‰i†NszËRlbK'Ióèu‹ØìƒŸü~¨ë.q±†f“lŒ§ÝÓg²`ͳ–‚dJà € äœ\¿öÐl€­×˜ö€ÚšŠ¢íœÈ?;óöñãßIÄg"Ñ«1¢ü…uÆÒ7ž¢©OzßD Yï3(­ )ôlÿÂÞÃçt… Ô¶?Õ_…d¶Ï¤’œ~°z1¶v!“¼Âñ–¡^KÈA6pÿ<þþ»~ç%»+bp€Wl2€„÷ׂËy[Ž· Yd“«š]¨^Ç¡1Y«fÖçÐg‡©&a˜W°ŒSÖ•|<õòùcǾ³xõ8QaèY^:çàš–7”Òê› òhLiúæÅz:A'¤³wàË»÷Ãá )êTœ"§ó‰Tl*¾z!¶zã 4ã8A¡xq¬Bô¾£5Ú ¶îøâž;¿muø™Õ'òñÇobwš …^WnЛI2üþB,!ìDøèN4³)£1F2o`8"•^¤i]Nü†üjÒ‚`Y&—¾_½_½˜ŒMäÒKùÜj>·ÆÐ)õö’6÷–þÏï<ð §§]NüxÇ€¹¸%`¿?Å]¸ÎŸOiͪlèÕÆ7põêßT®á˜'â³ÿgñìoðn\«ÕéõusW82ÈMúÑöa·§Sx+—[=5òt]U+ÑØ€ võ‚¡OÞ|ÄR‰™ÉóÏYHÇÖ¾‡I«§I“¥[,œÞÑÍ]}³l>›J¬Žqü ÍoS±’Ï®R¹5¶@)Ë)Й¥¹w<þž]_)Ÿ©+Sh58—ô$“°‰åQk­Vå•Ê!•¡3Kë’eD&^d̨¡!d#[RWÍ d²Ùµ‘O_ûI¡ÇÚÄQ¶iõèC+ét{Ú}¾mÁ¶í[ºïéè8èötÈaêÂèó'Ž?!ÆKQ¯JP£°HL¼ÂO4¸^L༴‘¢O©¥ÇÍ}>1øC»vשׂçS$鄸âdá§åÇú)ß3%¢¡óÉÄÚ¥äÚ¥Äúx&9Oe–r™e&“íKá üËh÷ƒÒ.þÇ€ Sh9ö¥q>éYÊÛ×h›˜ Ô"ª_{¨_6¯­„šµšNOLü|ròu„{­&Apbš+ì ô´µílo¿½£ë?ÐWÚQ^qö߸ٿcÛƒ`m:îh‚6‡?Üõ[ÜY:›¾Æa•\OŧréÅlê*•].0üN懘ÿ‰Ë»…ãb‚ÄŽeSheåØe_¡m+™\¤FaÃŽ?ëu T’ Fa’TC1HF¦áDþ™é·Ž}"Ÿ#4@S@v»7¸-ˆD÷uth í´–vfÇtÔúÚÇGÞÿÖµÅ,ËbêÒS¯V;õƒ$êxë5† Am‘὇ÿ¦}ë½âzu95=]§c—™¡3éøt|õB*v9“œË¦9~À%vïü½í·ÕÉ+£reGsej- û|i—>“ð–´|åìVâõûp™9|éúÙsgŸO&æëDÒïë EvG£Cíû#Ñ!¿X´X™\níÒÅÿX^UÌþ&¨Â&Úˆ0°¾rn죧­VW¨ãàfu€2‘>‘½þð^ Tf)›LÅ&Ó±)†N¦c“vWÈb±kTdj7 œŠû–óöuÚJ‹V+ÌHS,!ϯC¸ jˆÌ“C¨œøˆØH=X®€éÚÚäȉ™ž~“arBî²Áa›–Û˜G°-´£-4Ðѱ¿³ëP ˆÞ€*î8Íãã‰×N<.ú~¡|/LxÍÍ ÚG¨üÍ@€ÐƒƒÔé@ÇÖû>ê8Pqo”ŸCÄ “-Fq•GˆÆ›À wøêOÆýËyÇ”›IÔõkÓ%š‚›­”ÊϤ—ÇÇ^ž›ûMqöÇÆ6Íœ@ 7Ýì¶G¢{mv/œµ£piéÌøØOÓ©El]-³üµé ‹ž‚Š•·š„O Âå«Ç,¤m÷ÇڢÒå7›Û¦«ÝãíÖY¯Én08H<ð-ñÚ€MØZŠ$JÜyŠ„È¬Y´éU¼¼ ¢3W‹¬ŠMUÄÄ20Ò#DÒ Ä•\I‡³(›Jç“S—ߘ˜xÊÅe¯ÊqIïX\®p´}(݉î‰D‡¼Þ®òêJQ˜Kžˆ_ûÙÊòùá!bM¡†™@§à¬òajƒ†LZšùjëd$êÀ<æ‡Ëæ—æpÂÁÀþ¯Ã{%#Bf!ÜI"ÎÊ”"r,]i:TÍ,ºSª¤Rñ¥Œ„ÉnH8TÖx6°š·©„ 5@Šß$oA=>€BšŸ?vþü ɤ^Ó?7ªCáÎ΃ÑèP8²'ØÖo«õÜí<•˜™zãÊì» Ó„#æ‰[F{P§€Mê„B!{íÊo,¤s`øh—d­m“ÇI3Ôt“ÜÀPb#qÿbÎcl|Pø ”ÆhWA. aâ [?b¡¬ €cr9ªˆ@í2V¤ë×õ.y­hœÐ½²2væôWV.ééF»½£ó@זáð®HxÐ퉊cï¸k‘§­B–¾¶xrâÒ˙̲¼×Œ„Ÿk@ÍÚÃÆCMáNŠB ¢H`ú×ÑÒï§rRj÷1ùÔâì[@î~Ä×¶C¬ô›ŠÅí"‘C ]*ñËôWœ€/CV–§‘W·˜Qh¦àf€Ã Ž®)Gº@Ö_ æølmí¦Ó×N|fñêIõÊ-Àê÷oÛÚ}w×–C‘èÞ`Ûv’™¨ò š¤-˜ˆÏ]<ÿâÚÚ µMò´‚Æ€ñµl>Ô„M%®Î¼ ,äÀízý½7èr}ÂÔn¸§->žr/ä×óvI˜PeËG Ò=K¼ØÓ¶Ä$+ÖD~©c âƒÕ ½ŽR:D+Î_(P##ß›™þ¿âùÝh I{$2¸­ç¾Ž®;Âá]^O§…´U¤0¹W¦9IQ´¢ãcÿ¹0ââ>!æ¾Ðóz£æÜÍÒZ$-AõDv(®—1 2³䩨ÂÔ/°îÚÿU—w‹Sñ-”KÞH¦÷«æ¡î*3ÀÍ»¼î:›ðÎeqÆÊªJ}7„x¢JHBÈž=óüÄ¥× ˜ uIÒѽíîÞÞ‡¢íCÁ`¿Ë"€ÚÒ CÀBfaþØÄ¥W:³ÙýÑØDM¢%©ãW.¿ÎI3»~ÝQþ/@Xöþ+›Ý‡ì*…_Mî«Ò•È1@Huœ.Wà¨A`ˆ\ðÁ™ àæ„»‚ñ»‚Ä;«m 9‡Š*Ð@餫yuS#aqñÔ™3Ï¥’ò7½ÞŽžž{û Gv=šk#¶±”^`é‘ãO-/ª½+ûdøl"b2ÎR74Ÿx•#ß¡;¿I’UêjÒrýÆj&¸™ááõ IÏTÖµNÛÄqóŠErÛ Ú1PJÀ„ýÊEP‘(-¿¢ˆÔ¢|<,Â1@Ȥ*¢*P%“ §?zveyŒ»/ËRŸkÿö‡{{ïo í(ú ŒT…n>ÅMWìý¸ªóç~43õk¨¹åÃÆøŒ.¹jT½ÆŠ-¦•%ÊñÖ’Ò댉ª»Et>1;þŠÕêÞ}ðë¤Õ!¤Ë]e¥[¨ŒÇ'0Û©b¥"%îÈš™Mp“Ã^_š»NÆ|ÓYW–­%F¨žxüJ¨A¡ó©Ñs/Ì;Ç÷Iç¦þ@°o`×ç{zz]®ø¬ÔfH[×®žº0úM§uä½Á¡õ ñ-äウÇ~ ¹ëÀ×Hkõ±hƵ5õšé¸EáP0É]ï®¶-R|ŒHÂ…Âá­Ì€Ü1@TcwI!Ewä¢lÜBU쑟î+dü J¿¿ôEñk¤Þ¡á?èí}Àëír:ƒ èãU7ƒÊd%´ßT­p ¤ÓK§O=“ÐÞjTÚN½qñ*VsL„»²[ëò=讑A‘( ·Gž&‡Ä j&ÔÆ>„6P¹UŽpŠæÎá?(v}‰’Dþ3 6B”¨ž2’G›h!â‘f2€[ ¯¥ÜS×mkÀ†Úl¦óWŽž{1™\ …vìüÝÛúÛïÛjwè= [‡> ™Ü™~°0\%ê ¿Y¾|Z ™†ËÂ\fiêâKÒ¾}襇 «AýZiÍ$l2€[ ½îá-Bîk"Šbó¥{˜”ö#Ê„Œ’ÇÍ@5Š'Ûg5Qp ©—¯®Mž}‰›|ï½ÿ›}½úü[ív_ÅœŠÆi3%:žqŒû3>öÊäÄÿÐùT½fhI’ŠÄ.îk±E„½¦ 0»¯Wž®?QVšñ~Sï°š ©Š"›ºvyôG¤ÅÞ7ø«Õ…¤CE$™ls- ñŸH6•õÀÊ!ç„Ìævз.¼½ºš³C‰2*×ÇU†Nq×Öá¡ZNl “M.Ÿšú57ùvo»×çëâ#;%ëË ®ÒZˆÏ¹0ôØO.]?+ßñ­vМˆµ0†$jý @_n$@)2›»P@adt{· ÞñXÏÀQI"ÞP!Z£{§ªD+“ÜÒp)å>Ÿòd EPbv×:¸.6 dô“’¸Ëw¶@çé4IÚ99  V‚Á™]Oæx|îãßåÄ–eDYtØÄU#®S”¢ÞŠu$ì†Ïš*TOŠÒEÈ XÜž®¡»þ¶»ÿ3«ÃØd-rÌ䜢—øªt8s#÷”7ᆃÝÞÌ—;—û\Y‹È޳‰‹= %ZH›Ó´Ù<@ØaBw uBžJNŒ½:5ù&ËÒ5ÑÐ0DD;!Þ³é"<±V1buû2©ÅÑcO,νËI**Dhô‘!"×Ìl2ˆB±;ü /Yuc^h,ÅÊBF($ÊVg —ø‡$—YœZ¹U‚Ô÷P¢Œa1 Š‹@—PÉEF–SÑTqfÈ2³³ïŽžý1¿å$J–§ ÉòŠT ˆR7ê˜xduIª€Õ¦¦º¡ñ«A(H¾¢¼„¶Áö^þÑÙlêÚé÷¾u}þ„ô&4(—Ç‘ðPLäbÒbúÐö?µL`B½™/u.msæÈFIey«‘h4s³¥çÕ•±“Ç¿—ɬlR­­&¼·(À\zùäÛ½vý´8µ~"oÔˆ0€ UøDx}Ø—ô”Ur° (æWô€’äP‘@p‚‹è·ü‘_žhe®ü%àµ(ˆEbñ]‰ Z Í…`•M/tâ™Õ•KµoJë¢ °Êºê¬·NP–Öà¶« é²DA[’iiuªD_PY5,‚ E­Ê®ùßGÖ—/”IM +%±¡ˆ\æÒ(V*#BBç@96…BL'° Jxk5´LÙ P.¨Ž8‘ïj5æ%Æå7`<¨Œêͯ¿|†¡Îž~îÈ{ÿ¤£Ü›þÒÍê â¿åF"£Ä«8/»½[îþì3üaÂJK*âGŠ%bІ&0g“¾ñ”›‚B ½6Šz(^‹a as$ææÞÿï×þ´ÀäEv×R” /!‚♬VÚݨ¼öq«†ÞT,ô¥w…_å6´*c‘áÕ  „F 3€Ò½/´óð'ŸlëØ€ùbý"4€ „_-‡×ø£ç äÊáÒTÅßq$ö ™gvÑ`ÒN¥Yå›I¨ðªòK¼ZÏV§¥Í2x@>Ÿzý•?¢³1§Íe³ØHî$i±r—XHÀÝ”~’–Ò}ùo9‘+„a™Ë”þXš¿ S(þåÓi>½@ç ¹,¦è,—+•l •¿l-ì9'5Ыò9ÿŸ½+{’Û8ï9öÞå.¹"EŠ")‘âµ$EJ´BJ²$[)ÅN9NR%¥r=D~q¥¢#J©—ãT^òç<¤â8Nüä!UyPÙI»l‰EQÔIŠ”HîÁÙݙٹqNsáèF70ÇîŠøv ;ÓhtÀ`~¿þŽnu*ç4H…í[$ät )º»¸ý¦[ÈÙ}…ë(an÷™sÏüÝÜîGS©4ˆý‹p—û›ðôìù%¶÷{f„%H¸\©Ù É©0E\V1<“†H.e¬> m‡V50Ðt§Xè-g¹fåmć:Ò$ ôHÇ[É}¼Ý6+zbhhµºZ©)åšZ©«%Q«P‡˜ ,Ì:[;XM7΄Àwän9Ý#BD8”³Q"ˆû:#z*ó™5‚ ìÞÿÔ© …­T{ZÚp)ÂÕE!¿Ò¨Io $Â)ïVgîªã Â"Ã`x@©ï8M ,á±e¿® ]´|·ðÐ^—m¬§<6rû F|Ùh4”j]«4ÔªÍ jE5$Ó2 h8N'؇Á?S‰uúÐî6$ÀeÖì=ôõ…'^Ÿ½o¡ÉQ P~¡€¾(!€D¢ÈuÑ~¼LÍÈ@D]ztb^¿ñþŒ4ºÄÑ–ãÀAд޲·ÀÐ,µ†”zs‹´h­Öp/ФÕKR~CÊ—¤õšZÖLÕ„:6 Ëè<<'ް Ô)Bðµ³||ÁÂdˆäÀé!à»$üWô‡_8ùÄk³»N©îƒ:âÿ"Ü…”„‡à %Hdù¿Ò\^Ñ,xVõ `÷íŽÛÄpo£˜©á¡} ëU úu<Àßì+´Eã~U)•m2(”催‹ÔtSÃ[3GòLCBÐÌ™"¼çhž¢ˆ§W‘bÅ|W%¥>xä·1Ìì<êÎ "ÀøW© $2h¹R›^VÆD˜ãÏD.§´ì1¥@A˜:2uK©Yr¿~jÿš÷ŠàË)é l”å|Y*bbPœP³aéNH<$´Iö@Ã=%ÏvÊ×P”aÊG¾µpáé¹Ãìf"G¿ÂiîL ‘øò_…]U3k!}GÆ#Û·£[ñ  RjÐFüª%—AÔ°$B Y’VÏ7rùú ¶ $­a癊D ‚}gÔÍty'À'ùÓO}oræAv3aŽ~Æ!íO ‘ÞäËsEmD³(l·@h€ËÕJ Ø.}ýê¼dK¶Aß’ÊHm€¾-»ŸU°€ÍLEqUTk².*†hBgÑSò‚{ô*g:&)@t¿P[ð¾§yx„ÇÅÃn‚6-"\_ÛùuèäK'¾òÊôŽƒýȃØ „ðJâJ¤Or¹:“ÓFE312ìŠ4qôía>F|ÅÒËãÛƒ}UL@³Ä²`Y*DÌk5¥ÜP«’^7íå¯ûD(àjH¾øa€[âLPˆIø}:=ràØïøÊ_pqÀ  à¦2kç‹!ÁrÆhÍ/¥½2’SâL EÞœsBÎ"D(e¯3gÏŸtž:è¼àØD-ÒMd»ÈuqrQ«Øs†[·ÛσœiLxŒ¯áWÃ}ç¥ÖÐßRb!KÔjëõ•µÚrY.`2Pt±½Z[ÂΈð‰+±2RaH»$5zV08ºû+;2uðøï{ü»SŽ/¨/  ÌÊÂO¯Jå›n\g+¸jz¯h$÷½~Úf”¬ŒÍ(ã¼ÇoÒöûã±ñ„'¶¥¼]žËk#zÛDK[°}úvÞŽh© (Ù#}ŒûölÛæÊ9‰lU1¡Q–‹kµ¥¢¸Z‘7jJI‡jk_8Ü “¸ÕèM(ÐòèÄŒŒŒÍ=tòÅ£g_ž˜~`Hð£+šá ÕQÐrAaÁrSH^šd¬´ý¼‚Ud ¿pù‰ÄŒØÂrÉvÉ0í»ÿ‘-C±A_·~Še{Ñ…ÐeÂ[STC.ŠkØ ØתÊF]­6Ÿ‹IuÅÓ1C§ð»€ÜÂå·G¬†zŠðÈØÄ}/üá‘3:>}§‡HiŒÞ%@IÒ%.ͱ5 IzÍ8L±m˜µ·Vs{|¢ÿª'Ò?ùXœ\QÆËº½Î 2 ŒøP­[JÊUçU†Ö­ÍBø„¶¬ „êj9_¿›oäÊR¡"e]BÀŠ@ ×€[úI¾ „žEXÆ'÷9ó'Ÿú£±ÉùÁ":íGïkÄZô&üæ\d‡[DWÏ l(d8"X#)›ðSB £ ÈÐåã¸Y2+ É’ë¦Rµ¤*¦{². Ì=ë''|°Ý€u;\\Ï­×WòõQ«[È"FЇ”‘Éîeð‹m÷F“3û9ûg|id|6²s"üËûZÄø2ÁŸÉèè@R¥]?ÓŠ(ØöAÚÙŽ¤à˜`M …AÊÇ‹…º(ÖâFMªbн+h’ÑÛ ê¡/I‰lŠX¬«•µúÊzm›Ø @®`þPóñ·ô S;=÷òC /e²Sá­öJ„z>{ȳÃgØñú…ˆ-Ešß ͉D6åœxLW1ü[#ÅÛ”c.Ø|˜½ÊÕ FüZCl4$Œþ I2¡Õ|þIGÊàŸ(ÝʉA°Ýÿ%­Q¬çÖ쬡Š1ïdކ¦crºx»í6ÁÓ.+&9@O„³Ápüüw1¤Ò#„ üHpi†"@oà=3n–³)ûM“’@¿|t'_­7x¼/J QRTÍ¿ò°àû”pÀ=$š¡ÅUl ¬Õ– œjØ 4!Æp46æF'À‚žøÊô,.¦f-<ñê¡…É8‘–^³KÔãYM¸FpDò qûy@Hã¤ú-Å©OÁáƒQ‡ °¡0ž‚''2ðËÍÕj¥^¯Ù¸/‰’Œû†á,"˜#Jqö>pøJmbÕÄG´U¤ù´ŠTÀ°Z[Z«.Kz=âÃ.9‘Ý-B´Ì¢|?ŸÙyøÌÓßÛä‘`PÓ·+*ðµ…€ÓbUn_›Ö¨9€§§îéÜÓïä+U û"}QVUµ¬À\-Jƒ T¨¢6ÝÞŸØ[L0 4”J¾ž[,ÝÈUn©†Ê}hDhùz¿T€enÏéSßxàáçù‡öÔrß<€;)£Ÿ>º§¦UñªHu=…ž'»²—¿0ükj&žŽ¦,ÌSóÄ=ã&z÷úR¹R%I’ ûºÑ|D­ ŠÃ‘Vˆc¬ڳЙPŸÁÖš5¥„­¥Kå/Lû<´‰)s0‚H9—;¨J®~…Tz~ïc'/¼¶÷Ð3®¥4Ú¼ò°´H4ûç‹ÔR?rÜmáZJVJ†öm9bÂu}lT°&ÒæÙ©j¿ÔÙ:òÑ|©R­Öô%ò`±á­ŠˆÐž–HÍ2»bU°ŸçžpÀÖL:³kjÏìÄ®ÝÓÜuô‹Â'¹êì<‡ÀýUm‰øîSfSî W¿ÁÒúŸ]þçt:»ûÁ‹ÌB|…vù¯jÁ=‘’è£{‚çh€ú!ÄóC!ûBzl²Cn¦§átÚ8¾Í³‰Þ¹†ûÕº(bÈ—UU× ÷rŒ¡?nƒD² (5Yš ñmqbÅõÚÊ­Â'x ûûȶØ#÷OŸšMgF÷xêäo¼2¿ïq¿è‹iû@ôúäÐÁf0‰D œûR˜ œhÁ¸g2Æ6 ´X,–Ê¥róñKÕt;‹ì{ñ—ØñWžhnœ ·õ„¶ƒØ!bhTåµÚÒçùOŠõUˆúD±·¿3¥5LÒÙñ½‡ž]¸ðêÜîSd­#"­ð¯WI1þðµ¿Nú …Žù¹Ñ¡9¾(èáãÓÎ8£Û,€ÙMÁ™´yf«:ˆÞ½¶\(•ê QQ5[t=˜ÈºœI; Ïà°HûƒÎÜ0ub¶àŸž5L· ×n¬(©Îøi³R0y⃞ à«xZq&;ñÀáß\¸øúÌÎ#í³,¼­†¨+°I"8 šÃk§i! ´Óu3›7F±e0“6ÎMo>àÁ~a£„û’¬¨º®Ùƒ}³}I\ÿ¨ÒõGrxDQ›VYàªAn6fÀí=Ý$n"|‚Iw43¶{zßôØìý;|š»|·| n©Ç½mVp‚¢Œ©Ë¹[ÿJžzò/'gö3ê³ ¯eO9x¶} € =õ%0À“óĪßö{sá–PwºYÊÚ‘Ö:\º¾²^(Vª5 úºn¦,ÒypúZbfñw÷qØ­"W³Œ:¾¼ƒ`È-SÔêKÅ›ï/ýBÒzªõÖ1¥z;Úå}#ìÈÔã¿{æé7G'vyïxxÓ=:Ã&àÉEáõ{sô3”‰JŒvX×* ì)Ç£‚5—Õ¤wèÓåý|±$Ê2} û.Ï>ÃgC.f}æËÐç÷ 2¬“{‰ÊC luÑM­"?\þõíÂ5ˆz0¾Ô€%32õð©?xô«ÎNUçpÔá'W#Έ˜gš#Äå‹Ñ~¤(nØŒ|“¢‚ígàtÚ¼¸£ú'—®ß]+äK媪aÌ7L"âsµH F@Ooš=Õ‘NwË#Æ0„u¹ð9V’hU¦<¹!¼‚W„†!È~H½˜«ÜÁ4Pl¬n‚ãµô°·ìç r¦@H·Ø:|æÏ=÷CJ´ÕÁ1V ðlàAÒHñåa—2îr†õ@"×a=@«,åx‡ÆSæ|V;=3qè³\uu½°ºž¯5DÓhYÐÝe¼Ï1²ï^PF>Rð5À‘è‚à§£0í…0êá¹}²éQð¯ZfM)¶zõ³µ«ª.]ÐOß³6•’ÉN¼ðç ^mïç €ö{t TêÝtp)CûÌî14í‡Ù_x}(í÷`gt‹Óø+LY÷eõǧˀO.ßÈaÐÏKªª™Ð„Ð ö £Z:p@ÇûÏú@Ð@`úˆ®Zd¥©jðX¤Ê‰A°Ù‚olÝÔ–6n¾¿øË’˜ÕDôÞÄÀCÇ£».¾vì±ï:ô³Gp-üä-Úh:¦_$˜? Õ]8hà>÷hÊ8{šÁlF’⺱VË­æsëë•Jõ-,Èr›(ñs@O`Îú@9†éÚçšL@?oŠö,Ïér0 1/ذ¬H—o¿½´qƒwÊX̬M²=·0àkÀÄô¾3O¿ùЩ—¼®‚Ì kÙ£«‡Ïo´V·‹(ê:q *sÚ€Ýo2¡xñá°sw"Á~´˜NÏÍ›…ïßZ¿»º~7·f/É€GúöÏÁdäN2Q˜„vT¦hYÔ¡>wóð~ ¡Ê¶*ÓCžšá­ùše]‰ô]šÓ®ç®¼wûmw-9âîÀñzxPàýðóåCc.vÌ?rö¹¿Ùwøë¾ dg{'0ƒ…Pâ‚`ÿ €Ksw!ùÜ ÷ 8bA]¬Hù%¥pG© a ·.„¹'¬·ÏŒ„LècvFpÐwK9ƒaàíL¡[®‹D=Éð ABg샊õµÿùô?ÊbçgÛ'è ÒæÑA˜ßwîÜ×þv~ÿùðoè]tëTb¡•ŸË;ºéü2¸]7ÑV…iÚAà°ˆçÏxRqã¾XX6¤š§jd ÔäðºPvïaóáG’¾÷T˜ nà¢Ð‹Ä¼œ‰M0\Á¿êïÜ| [—)~€lûCܾ{;p(äqÿ¡gÏ}í³÷¡Y}øÔt ~#M‰"E™ÙW’+_xh@ˆ6ærø’/ë"NDø’éÖ²—ØD–.֤Ⲙ_–‹+å™é€cäJÙßMÈôU Èyž¡ èñ"ñó R¡2ïbˆ«rǡĆ`e=y*³Î¨«@"½ ´Ì;…ÏÞùüg ¥BNwî‹Ð¼.Ã4¼H,” ïžüö™¯¾95{ßot'D«z&†JD&ã/ŒZyÐ2 Óñ‰=Ì··Ð2t¥VóKRaY«¨5ë½ d£•X¦4@©ÙxdzΗc1 öÜU1Œ‡Ž×‘Y3R³ÝÓIÖ¦î¤S™Ã{Nî˜ØyéóŸß-ßîób¢>qßc›RDe(²tí?GÆf.¼2>}¿Ÿ"ü{× 9:È»{÷z‡Â­#žúüîþ°#„Fð^2û¿¯4MUn0è¯È¥USSZ5ÂÆŽÔÜG‹g|AÅк¬Á=SuNwW¸ÂL=ãjËáÎòÖLDQ­}°ø««ªþM‘LAàu¾ Á¨ã³N=ùú±óߟ\ËmuðX÷Ä(ž’ÈÓ7Í›^}ˆ%†eêZ½$ïJŹ’'tÀò÷\Oçþ¤3ºÚá· XF˦êüWÁU5± z“©±Oy~f|îãåK5¥<@w[ìo,•Jeì Uû':¹véŸF'çŸ~132v*¶@ð+‘“ø“€pö!|¦@ÇíNÊЊ4`èRÛ·=<Ð}S‘¤Êº„q#‡ßwÂìè!Õ `Din{jâ eÜŸð=Ò?Âæ³`ø—§DÀö±C8NMç†Iˆ_ð[ÞøüÊí_êwÛËÜö¥]gKÊÊŒLÎÌÌd'ñÏÔ%uhêÔì­ãÔ¥§×ôb_Öc÷Vé¾oß î»¢õ¾s_rÞg²O|óÿV*=â?­vÇqb1ÅŽ»Ý‡¨lXaõmÐ×5]¬:ƒýœ\- Ò]èõh3F”ÞÝ]çt_ƒ–X§˜9‚fŸ«1îå©©Íö$èÕ @ç–;‹€PRþR ¾hï;ºcbç»7¶Rº¥›üçÒ·†A_×Ä¿|àè ªRiTë•ÅZéV£¼(‹hjö j¦©Z¦†ú¸ºu”ß/4”÷ÞúÁøÄüžƒO ©.Ô»qLøé‡z§e×?O¤‚vÎhÔÀ€ë3o`€u1 -4Ê’ÔÍp.44¿TI©¥Uq#gˆµîe%ý sUv‚&ÏWfªG”®¼5™é0L#ˆ>ø=r)FŒkh–TApínÇ(+²Øþ䞇ܩZ-`R-šIhÈùI¢N‰Cgn“Æ/ÈU³{ÔvfÍP.ñöçëÉšè‚`&O?dzîàÙ§ß8tü›Øèš†R/ßiT—VXjT–U¹MÅ0ŒÈ¦!c+´—ewØ;BT6öLÏ|òÛÿ¸kßYAHûv!€òm½Ù„(ŒA Ö#@ÜÆmÁ uÍÔMªIkRiÕ™«¥Šà¡àö QÝ?½ЇJ<9“m#SGïàªÒXš…æ<4'íBh‚µÐ¾¼iÛgìÁñÖÖ19:5SmKÁz¡S­A­©&¸Âù§µ^@p¶"çÔ¢û…äv³nmÁc³kw¯|°ø«š\ö@ë`œ Ó³{æÍǾ‘ÉŽ³ã°hJU¬®ÔÊ·Ž• ÕîêZÃÐ%lFà-¶|¡‹þ€ ¤æ÷;ÿÂßÏíYÀï}êu À³ƒí¸§ûâYŠv™Æ{NüÖÃ(iêãZÌQ1ŸPê+Ç÷ÔU ú†¦(•¢XÊÉ¥uM¬v=ûîÓ ÇQ׫ËpУ`³$àwÛÇ·z ÄÒ–Þ­§¹ ‡4˜ôÊ$p€XhByÊ©“rxºùJ MøN öÊN)»¦]’zEðá‹e!LÐáµÞ@ç×a¡+ %ÞG e.n¼wëí’˜ÇÆz_Úì¦áozvÿùç¾àØoaàH2DØDhTW°•P/ݪ•nKµœ¦Õ S‚hh"¶È¡b)àâ„T:»÷¡g{þ‡3;ÿ?{×#Çqž«º{fvv—K®,’¦VM‘T(%!%EŽbK–M‰A„I ø Gß8$‚ @€@ÈÁ@äš—}C.y(’e– ‘¢„H|î‹ûœ÷L¿»RUý¬îª®êÙ™•Œ¤ÑØíéþ»ú¯êêïUý•ú9@Eð¥k”„Ç™‰–üîG¾ëzöصÆÎ¨7&¸¿=îìbIP¼#vË @r‚B*R2aU±U«$¾T̯\¹P”ÓB 7i»ð[´²S(ÕÊ— L~B ñ t-}Šò?sø>ñ äay`yé HmˆÏšÁtÃ2`óàþ{wß$kÍOc–@^€ Æ\lg^¼þ'O\~]×k•Abbß³Ýõ^ëN¿³:h?ûK‚Þ«çyvûar€U7kŒÚü—žùÍ_xù÷?žåþ}ÎÄå[50À'3•ÀÿVò Ňeåȵǎ9rÍ¡5èŒÚ;x·ÝÀ÷ø8&uØÈ¾Eÿ029!~”Z²O0!Ë U¤—²Ãó[AÙ É"ˆ§nM‹~RXÇ@4 RdG!¾‡ˆÿæ•·ÐM„Å€ƒ€à=6È—ôÙ7—ø[íÕÝY÷—r<›v çO¿ôë±òä+ºÑHÎV‰,F®3t׆4„€íƒqÛ¶:Ö¨í˜]ÇfœkcîÄÅç~çò/§¹p*ádÊ€ 1‘àG%!£— ßs1âcÜwFýqgoÔÞw÷]k”¥™• ª €Ãj÷ƒÉð[Å /ðê6¸H‰xŠ¢¦±7&z¨kÐÀøNÞÐ"¥þÿQþþP ˆåOíÿ3õ(Øé¬pÿíÍö}Ïwg*p×Yzäü ¯~ÿì…kzmnb#´Hü`½³÷ 65s|`¬qËß·AÅmþØ/ù;®þv£¹>€Tä/ùÐrª}†83®0\ÖˆoËCXg?MÄþ†<ë!q¥ ¦\’Ï“67VöMg<°Ç«ßw÷Æí}«#öIq¬ŽãŸ)F¢K|Ìl«"¾AcÁôC‹ §Yâ»YŸ§ˆˆŠÍdc.T'_·Bu’êÝuBn3­ša ØÌ¬bC|qœèõT‘”z ÔGºqôÈió3†õQ·ŒÿxxQ:T2oaæiyÔbf©M@÷ØYä#8.aI;³|^ “¶Ö[w<ÏáŽÁé3¿ß^}ÿÍ7 ¿ðªQo!4ñNf^S^`®yïž¹Šˆ_Úö6Ið ýKl˜£–…÷ñKF=É·qçÎû?¬7Oœ{ú7jõExó¸n¥Ù„Ð'ÜDÌH9G¾gú6Þ‡=³w€5}³ÛrÌa)R^à£â0póGJé þ*¹qøOãóŹ" æQ ¹‰åÜrŠˆñQˆUÓ"”ÿjD©'ž•ý¡|¸’Cvu¡À oKzT¥qA÷Lu6º¢`uRo-+5Y31 xDvRt€ ˜‚%„ï¯kdtÀc(ByFŽÌ,Àu9³ü„®é5½~çc×wÐTŒÛ_ê¶îÝxûø-½ˆeÀ|yUAǽ„÷ð>s°K†™RË s¸o÷ðîX}2?Y° :«·ßý»ÆÜòc¯ézþÇNÕô8é%TN_ ’ùm&'3ƒPàÙ}kص½Qgã>ÖúÉh\ÑÆÑL¡™ð®BvO¡ƒ‡wYøK1nü™ …£k¨þŽâ`,$O]7ÉÁçÁ{“ ¸ ÇS¢L€Åg@ëÊx\ HÆòç€J„§Œ&lüÈ,H$Ã5ˆPd<Ą̀¦å#"  ã‡Âàè$AwÔºqÿÛ[7]ÏδSƒÄÊe‘k&_8ýóW_þÞã®åe@E¿ฆ¸ºpìá°³FÃÈ«¡q0ì࿎Ùå ¼Óg_¼zíO®¼p@™^t›Z«1Äö}{4°]¼›ý6Ñ÷{-{ˆec ïÊÕŸRå¦R^2¾ É÷-‰NH«ñ90OýÕ@ì¦gà~**êd]žìAè”&" áP?ˆ²”•ŽBbޠɹH)ÕšMK£â(D=3ü)\¾ô"Á§’ÀAÐŽ%Á8fË€×êÑqA3€Ê€“g®^yéwWžü:#f&²ôž3™†Ö^u7ÝqkÔßv­^¶²_¼Že*O2-¹‘¤=™Ö¬’Þ‚•}sÐÁˆoõ»ôûXÙ÷[tS¥ì+‡ÕÇ%7U2@™xÉIÔz€ÅRåLB,å6BvÐch„?CÇ==Ž|CÔÏd'I…?ƒÜéˆxz2üIÀ+ˆ#¥ƒ|Óvœ`µË>¥T$TApâ/†¡0@Ið\©l˜@ Ú’6С"ÁŸñð¡‘Õ÷ÎÞÞúÐõ¬|ô2‡V¹c–2Æm[íäÊsW¾úÝ• _¯ÕšUV/Ã-"Õ¼$J¸%s°MÐYÝD£î樷9ì?t­> +p€¨bÊÁkŽVeý1ÑôÛfÿÿµG}|^EëÉvJIÕ±¼ÒàÇL±rnÏËžCÅÂʤLû‡ÅR…ÜäXÈ…Z5â“¿éO#œHu„ª=UØ‘«íá Øèg€ø@üZ’e˜Î´£tJˆZCsÎÍJä¶P„»ãWY«. èt3€­,l" fÕ ð—>0{7¼óÉæû6M4¡B϶íɕ篼ôÝÇ/\‹Æ†‚|¹“"­ªÈœF®M,ƒaw#Þ×Gý-¾à=²Œ¹ô’’¶ŽDÄ D²¿MÌ0îwÌîÁ¸w`ö;Qü;.Iµ_öZ” á8ž¦F–ùÁ#(üšj ýw8˜Pz‰¸œõ:40(è0qÜg´û£ƒûHs' &ãJ‚è ã·‰¾¤¾U 6¦é¡ŒJR^Að+º‰*øˆõ:Pd PPÓP P+¡Ò °M`ùÄ&˜Eb",†f÷ƃŸ|ºù]E`¶Û©•箾ü½³—^˦c+°Ä;É'å^ Ñ”ï‘â"­cõ1úcyÿñCGÙý$f+{Iîè/ \`5a<uöGÝÖ¸{@\üÃ.Qö½ÌðM‰W]ͪd;dŸ¦nT„b.* É uV`Ä_;…{Šìµ âGCtŽjLަ1"ÕžÄp"~ñá9–†<Ê[=×ôŸ•Pñ¦”SzEØ80H—À€H‚º†*êñ«!bÀV±$˜zxË€¾Ù¹µúߟnÞ0Ñá ,ßN>võÙ—ïÜå×§€´Õ€¨ü”%˜+)Þ˜¡© cûXL´Ñ,¸C†8µLU2c€5bŠñßu°²OR2tö±šoºö°çXc‘|)Ñzr™ `‘\ÀË ”ïÁÌË`Z'e š†é)È’ç–gKtά8ecˆLqÅN“†bÈ=fÎå1â×È®Z>x;ëPmõDƘ¸‡ôGÊ>"ÙÍ‚X¯gTÍ5>Óâ%mºð¢ÂÝ%ï1DPk7l8’%.x²ÞrÍoáJ/&CK©ƒ(Ÿ3eâ7èÓôAv€°™gÐyT „"An9iÌé„~.@–†ÆÄ˜¦ÀõZj.ÿâ—~óòÉæÕd€ÐI$¼cÿáÍÞú€ú¹ŸûÕ\11?9IKͳÊD¶f“Èä¦g1 È€³êz¢ 8:4±¸¡†øa{ïXå·†={Ø·ˆ²ïæË-+DB Y?Å 1˜ ‹Ü¢ì·\Ê.¿XyÝ¥Æp¯ÕôHͯZ¿œø³ÖêòEy×p?ŽÇâºqGŒæ]Ø.ñ4V`ðE°Zõ+õ¶Ã/íÀ#`¦°È¿ŽC.XFFy’è.®‰Oâ•M 5t ðc‚érø/2}0òÈ`¡C0ÃrÉ€ñqek:…÷°}ë–È?wùפÖà!‘V¡òémFñRR©B“qü6BÎ`Qea´äSKf0ªÔà¯|Ük÷¶­]³ß&C9G}×2£EJUì„€QÞsZÈk_©Ö“0)xA(¯¢ñÐd(ºrrZ6äÜÉ–_ˆï°VÏVË?„k=d(³×5 Ö©jO@ŸhúZ-öçhôgªÝûAà…XOÿºXÍ÷#”÷Ãð,…¦g XlÛ´_@¶ñ‹ï!gdZ‘ÑÜ ·I ‚âØ‡RQ–˜k=dû, X fˆ™Êr^³}ò+¥°áRHŠXx§ASGXÍ74É¡5PÃ2Cc*¦À}øØ<±‚ÀÇ2Àv+.#ƒÇÚÖö­›?þkÜžç.¿žM!˜ûž“CT@Z €åØÄ̾ê”e)“‡Æw‡×â'”BLó Ç6‡{ýÖö°½k z6IÒ0ä¤Ú—+q\­g±$¥zMf TâWXHI,AÖ5X34‚ûF8>j±Wg¦ãsHŽIŸ ?^H#žQADÁÇXo„j>9N&ÜÒ\i`¦|×\ŸÀ=}‚þQÌ–ªö¸ç1¢Õà½A˜ó¬0˜ªœ¨HQfûRZ˜z°Ý”·zÐfÌ71×zÑ&È‘(q›/šÉ“õJr!4Î×®²Ñ„Ò>‰˜>Ä:þ¼NÂÅ%~!2ЀŒ7u™úš;¥iÄKó<ñË1×öo#$Cãê1€d |¯µõáÍwþSŸ}êº âú]¤MNòx@&6À®•’|3Z¸ÜPÀzýà`·³»ÑßÛ2‡=×9ÖØsœâMGžú†û„ >SiYíQj×È•8~“au¾a Ç5ÍÐ4º@U˜"¾ûèÉîN¨Ý±×„p¯òö¤úö¡õñ ö%ïHV®‚AP¥Ø AyŒ'snz^aÃÝÀ&i‚ˆÀÖÀ¼At|X.HV,‚¡ ÇÓ#„;ÿòâ©/_7ÑnwS鞊1€´¾¾‹eÀ·ÿ Ÿ½ôš¦×”8œ™ŸþÓ-—s©Ò¹‚ Œ‹ Ö ßÝ{ØÛ{Øoí:4ý²k›ïK|¦y~Cñ¥Ð`@LÉñ±C²<¥ŒŠ9'&âG©.ß p!~M×bŸÑ™ÜÓ­ë!'Ró‘+õtšB…®ÅSæüÕAYÂ*Š¢'ò"J‹éâÛJœïyµO£¬˜„ZU«ÅGû|XC<ÁzŒø5mëø: U{ò—ªùr^«oø›±1ÖS½žì Þ¦ s Ò÷Ìñb [ñh@Y£ó/—vq¿˜Pn°$JÝ^V˜ôÉ¥wª %^Ëj«c1 ¡Eƒ„KœB¡2aû`àaIQdf!wMšðcï>Éø iâpf ×t£>×<ñÈüñ/føb‘±¾÷­[ÿÒw&¯€b5¡¾|òÒ—¯åâ+šÆ±*!-P&Î €ÞrbÏ%Ç¡UMæÄ{4ìîl¶·Ö°Êß…KįM•ýôìQ¾qâ6’·¢¤0^@A5äÅÏùL³ÌNÉ  ¦Í @"~³:ñ#¬ŸKÇÊcз1èÓ¿Iœ–®$ÎFKIìH åÅ+UjÙö—7zÙýp‚E Ü&Äâ¾Ä+VÚ6Ê_‡‚ÏߟS’?E ï$ÉtüÑ _yýO»ð5 ê w‰‚Î9ŸD½Šã21 Óç :- úxvö èÛ¶GÞ'¢:lËS!H]2,ªJüu¡ä”)*NÔt8W×›TÁÇ»ëøpfˆO”©Y.}Ÿ‚>qéÄpŸÕîÖ m&y; fSª¢ À‘È€RÀ©D)ƒ°´Ag T:|ÂæÌ@ò^0ТN’L”l¦eݹ¿Úm·= ýpaõ:q¹¸t‹ž‚?&ÃÐëÍ¥S;ù˜ãÙŸl¼ÿÓOÿÃvÇ™º± ìºùãj€nÚ±å³/}óÏÏ^zuZ¡>#­X"\ñýÅñ ,B®cµ·Ö®vv6Ía8Ý\bvñEÇ„èT{<ûda $žqÀÐa¨Ý7Fk*zîg‚ø©‚ïbĶçû4f˜èI¿õ|Õe± QJŽ—# ˆYåp[Ê“”!Å#þ3> õ¶+m¤²÷Ë *rm Ç– 2o€{Óp8¼ÿþA»¸²ÛÒÒÒéÓ§†¦iIà ° °,«Ýn·Z-Ïó4£Ö\Z>±r>0´›÷Þ¹qïÇ~à˸;ì†m~é‹_û­¿<{éyAéI±P¡ŸL aç µµº¿v¯·¿å9Žï¹ïåçIñêZü¡€ª•ƒ*Tá?eÔ?†‰e>Ĉ?_Ó›u}¾¡×É`R@µ‘Žo¹é–˜nà¸A¯j‚ Z /€OXB ¹\.A¬>•Ê3<Ö:tv!°dQ—hN¦ØøEñ’da.:’aúð؉'¾úÍ?{â)~®ÉÉ*Žú¼øœ¼¦‘®—Uú\ÛìîníoÜkm®ŽzÀs}úDATô™®ò(h=*ø¡@Uˆ§í3Mc¼«sîµñç¨+?ì¤Ñ²MÓý€êøc‡¸tLÇ·<2€xÁÂt²R“IB0Bdda5ëG-¹O޳•AU¡þƒ¥^ÈCEnÃEÐ4ä§ë´Ä Afûëa¼Lfés‹çØ9 ü8kÍ·PœÛÇ’f«÷ÂktáÊ·²Å:Oœà–øñLQnkÌAooýîÞú½ÎΦcŽQ@S° ¹? ÷8(9[iˆµòÀjy¾^±’Ǫ–Þ„Ò<äK†ëç둚O†$„K³Îññ›"pïkút NäͼðÍ{T©.®*7[y“Àç²âT’²ª…9ôë$ÉR¼¸J˜a F9õÈÆ‹•p¨Þrôdm ’@‹XÌq èb^4?Iíà…+ý Ü$Òy/*ÍÄ’Ñ{X¬FàØÖÖÖV¿ßÏ‘5§Ÿ~+þÄ‚Vl,hÉ·¨…CŽ“ü¤K675/å[Ä~–›Ì¿œË#y}ÅŽUÈÌ<8ËYrkë$}žg̦ùSuñÈøÏ!Ä—oÙ¹˜0þ;o€dé[, ̘´ –b1B=ñb¶¡ÂKXñß]_Í‘ÍÍÍ=ûì³Ø8L«†÷.--=óÌ3ú†V;ovþÇòKWȦ“¿$Ý¢ :ëïýÛ¸”‹W¾EÖa%&wŠ/œG…[Š%¾çv[;»îüo{okI’†EÞÌ»¾}©­»º«ª«»gº‡ÓαdŠ2µP&)‘”aÀ†àóÃa°A6aýHâ­Ù€d˰áOÚ0 ‹²ih1%‹û2äôl=Ó{×^õêÕÛ—»æŽÌ¼™ˉˆ“yó¾W=óïÝ›y2òĉˆ³GÓ÷w¶Â 0Uǹ™ÀÕL³ù£K«Ð. ¥Ò´uˆ„ßDå1y‡t 9Jµ 5þŠF¼[MtüDÍïx–Kê+ü(O¿aìÁŒ£þ8`_übŽùÓ *0Ýi÷iö Hšˆ©^Æò÷ÃC„SFˆÈayÄU¼¨ˆ%÷ܵR è±ÀÀ‚Kê¯cB=ÞIiºmj²kq³q6‡Þ2ý]×}ã7fäþY‹â<Ï»qãF³Ùtï¹-â}ëà{'a_V4xÌù4C9=züµÿ÷W§që‡þªëµ€P™ò Y ðz  ó;ÎßøÏeÔ?6ßïÌÇdFÆÐ œŒ½ÕYÝmXg:ÚÙߦ×H|w‘1ý®WïäO™~j Â$Wg’úvÂx¿ÊójAWµ¸{ð}VÎGýƒ!­Þ$-^F—Š hÇpþ' ÏÄG $ŸT»O?çr`ý§´°Á<‰È }?P=“Ä`IÝ=x|GxÐq^}õÕ_|‘‰ÚñßÙÙùè£Nÿdÿ[ýp0Ç´ ®æîâæŸù™_¹ùÆ_q½Ž¼»>ŒŠúêHÞèôØîÇżð1´²UTÇ© °üLšDæ]¤.^âÛi7kj<»Oýn“ fô£Ø‰juü¹Dкf#3¾f ?㪘ºò¸ð;íxñ­äüƒ„Ñ“t[ìh:ÏB)8ß˾‘õ:¦Xmm7>Ýe­ ú>é‡qŠ‘Šª”1–(ŒŽwK¯^½zùòåypV.]ºÄ ‹wß}÷ Ñ›ß8øî0,yr@¥2<ÝýƒßøeFƒ›oÆ2@K[]tWïâ‹ÇYaª]!ÐDr#+î£Û4ÿêpÿ¥jÅ* áŠÀ÷³ØBŠ‚ìÿ™æä$ú<›ø­8~{ó»­øK#ϼœžnFýQØŸÃqœ´D@·êbhà¶Ö,¹Uœª¿è(:¥ìr™‚`°Œÿ‰Û#ËØÊƒF² ¤ÛA¨#>—ã’ºnÒÕ«éz:Æè[ãMÉžØñ¶ØóÚ&¯r¡\È•Bz\~1ÈÖ륛sPêDùz£±ë8ºFr¼sÃሚ',L)9‰¦’€’SŸœñùïÒþ€”¤à>+ƒÃÝp2æëlµZW®\ét:Ö·W.ËËËo½õVø­èÍðµwŽÞŸD~Ñù0Öùã«–ñðèw~ý—hÝú¡Ÿq¹=ã„O~!…mäÀ1ÉZàN ézP2]©¼<Ík«è—4sé¦é¸x‹……DÇg¿Ûv›n£^¦Ÿï£Fcôƒq¬à÷Çá$Ýݼ& Eé>g÷\ræÜ‘ ã‡G+nðÿÒŸ&‚¦¸Üìx÷Vì+‹¿8ùb´’â€w¼øã‡±50âåqDÕóAPâû£!+Ÿu-sUÿ3lf|öõÏúï£prð(¤Yž“0Œg(€'Ï ýñïÿßÿuNn¾ùSÍö‘exAÌü!0².\Ì®–:oh€Ï5HàÄyÓmñ½x5–×ë0ßcú~Ê`:eÓóʾO5?N¢Á$Oì‡ÍA¨F°9 Õü©_Rï¹pòMOÓcmœô$Ë6Óî›¶ï†}.$$dš;‰äØË˜Ñ'g§_ÒsíùVa- |„F¸\ÓÀ “]øãÏÄ Â ‚Ä«ãÄò A™©”qÀ”®µxãÏ8<À$Ÿ˜8 ¶§»O%‡çRRðk¾f)ì-¯¿òZðq0ŽÆ[ÃíÈz‚X …އ‡ü/þnŒ^}ëç›íÅ«öhr  W8mST.)¯£MoˆZ6§{¤r8´°(„:òüpÉïk 𛲦—3ß\ÊîÓOËkô:ÍXÍo»D'¬‘Ža²ëx˜|ü0߆iü6Œ€UÓÂd—ó$å1% )äI Žá:°äj€°œŽ}@ ÜC=ôÖ7ز |r¼A²ßuªÔ·’€mÛ›~Pco"KÅ™ºõ²ï“ 9 'eôñ‘8Sy _­N¶Âᦍ`› $… å±<4 ÀC :f¼EÄ ÎúŸb§Ãºñ6ÎíxõÃT %³ÛVÚñ’‚ã€2IRG ZÂF'‡)™V¾¸X'O´ éyW¯^L&}xêŽül2•œñÒ\/ªj÷L¯Ow¾ùÛÿ€Ñò•ÏÿµVg9O|Lml®V™»ð•B iÌ)H`Ë#¯$HÕüx%}¬6:Ób÷NÓ«Í›ŸjyaÆñ£xÏ䨥3J|;ã Ò6‹3l…OK;{j„©Z}+\ˆÅZ-$ÐCƒÓNrSÇBâ ó’S‹Sß}zî͹„j#î ›,Ü+òÉ©gÉ9hQz¾q 1Úre>"jVÅf˜.üdÂ/Œ?' cê&îN¼Žz ¬ƒˆ õõé¹äاÌΣb΄aøBcÇÝn—ý­B᪥Õj1przr8:? æàËéÁÃoþÎÿEáí·~®Ý]áoÄx##`!"ÕÈD²-H .Æ,$Èj’‚Ù£<»‰÷NI¬~¦æ3.{uâø­×‰—àÖ¿ §3œMøxãÌQÂñëùBV~ªIG“>mÎI¥¼ìŒ×­ ÑÚ /æ:À$P±U‡ŠNw„Ç€#¾žL©O÷Àa_’äËìÀúsrß§Þùhúwªàç'\Æ>œ”ݧ¶èB‰ŸÞ‘-:æl¨Ý¯fb o’…L%®>~’ÊÖ¤•æƒÁDHËAìÖ}Dñ™ï³ÕHºÇ‘U°ÛLx´ÜØèût{„b"ú£~²'MQšÍfº¿ÿ—………kW¯Ý8Þ?˜ov§‘xÁJ3›L 笜©Ã•“½{ßù½ÿ‰}yõ­Ÿous;@Ž Q`´ÀS°VÉ9sÒŽ=HÆÇ÷b'€ÓnÆ:~·3ýV­j~¬àÇs>>é0Ò¬ü`œ°~Æ ÀP¥ ñ’¥ÀÌž…‹ßò˜SœK{àÒmÒ„œÔ«Ã8þÙ;sxvŸoÂüûÔ““ð}Д>C,ëíê)se«eôL%³:žÓCÇ4ÙÉR3þ–[¤ëÑ“IžDÎd( €ü€—3.ŒÉ¬¯¯¿|õ¥ýÁÁ‰Ú†3ÇÍT,Êq,þgf¿òVî 2ãjBÍ vé“É/ºJö…¥j ó g•Ö ÄR!-K;Ic}ÍØá;;í„é·bo¾WS¦&Çñ™¦ùa4žDc?Ññ“}4 ½(z5L ‡4ÚQ¹.E5”£1…Î/S# P¿€«l•p0»Oc0ñ÷fÂâÓìûfrfýì½V¶¤½œêõa²Éá”ÝÇNX§OBFšãd¶˜@|±Ù9¤¢[´nØVÃcêD‚„À9žŽ8äo‚; "ÚÊ€¦ÊÔ`ètBOI¼…Sð{^*,V7ÎZ;ö&øäh ‹1ýpœqüH6kgkú¼–5`j˯•ØíÙ$«åCîiªU§M–Yy±Ø>ãí¦¡š”ËÓi^ÖÔkŸqüII©8â…¤(2ë¨T¢{Ï"ešŠÕÔ|{8Ã…‰ØIÈ„AìêÆyº´Õp C#ó‘'þ(s¶L ívGþúËòòòµ«×nŸŒ÷ÇGÊ–‚s,Çû÷¿ù[ÿͳÛoý¬×ìé´|[€xÙj I›‡lUõ‡|“¢ªJUÕð»o‰Ði²G3fñ¶ÉÍfƒ±ûNâÐo7ÝZ˜~zÎmçi0ŽŸv;J¶ËOþ†¢æZw®Í ez@J¡UÆQGr6 |µ²Ý z޳Ø9¹¸æÈÖ“éj»ã§Üt½U*³Ï\ÁŸÆi¢">Ÿæá¾ûä§B{¾ …rÂ}µYР@øø5¹û`Æ”9]¨BFK¡hެ {~«q)P I¬ÔŸ±_h!9xƒ5à2ÄB_"¬Ÿæ{¦`¾°ÁŒ€ýýý—O÷Ž&'ñ²€úü@²IÉ]K¿ŸìÝûú¿þûì׫_øë®Ûr„.+À‹€:BhjÐ,™Hxyyµ¦ª›2Q]¦ãÇnf¿M²wZM·ßN”¤f2?Öñý©ö)ÓgßýlË\衤Ž>笀š_l{(NÎÉö7öbgN£UxðcMÿŒ£µÙB*š.¤Jpƒ°pßÉ:Œ ÷zˆ43«×ÂÁ¯¡1V'ß™©Å ©¡OÇAœ<šñü¬?÷­;˜ rùòåöwï?(RBg)ú«–Óƒ‡ú›ÿ­ëµn}î§]¯Š%äì_IA]ÖÊæÉr€ð"'UHã˜ê V»Ù`\¾Ó*>µ8ô“ÞØ¨Šü„ݧ¼>ùĬÜ9GU…åØEN¾ Ì&¡N%¤¡¾–û£bEÜ3æ £1–D±ê¤/øŒ9{oOõúÔï¹gŽMy}òwªÔS?˜æ_J¡Z•Î@Ft›g›#‰Ö04ºîiu ¨S <–wËô›!H ˜Ë%‚°A5XÒQ·m¢‚ò˜³ ÐVƒñ^CêŒÒñèBÓ鸴]îwe}}}eiååÅß98ÎiÌ/ pD®~—/R@öýôhëOóï±7Ýúüϸn[è¨"6À„E&ë œb)ë!½Í –NÛ½¼ÚYYh5½v_ˆ};aìÒÇîû”׉C?J];i¤Ò„·=Þ ŠFh`eª­äáÕLK§M=9Þ4`ë6³üœ³Ü<'uß9ÇŸFæSß}¯ªM”ýHâ´U¼êRóBôŽÍ0.q€%\G XâlYØLcD€}dÄ!ß^3µ$s¡FKm¥Õj]»vmïpÿ“ã{ƒüИ3´þ÷¼ýoþû†ëÝPö cüE*9(Ø}ˆ¬?â {ž  Ñ’LC0¹:ÉÀ%àЖ/¤OÀq3*ßÓæýh†˜&úT*HÀ=*ªkBƒ¡` dƒìB‹íô‡8þ,Ì”½³?}߉Å@3Þ-®ëÙFϽlnn®,-¿|rý½Ã¬Z</Š$((CÅn” …§Ht¸óÉ7ë0¨oüåXˆv€ú¶ü›G€·T-v­G¸:ñ£ƒáÑédea¼²Ø^]lµ[öcU¢äÌÛTµùAÊýS÷N± ¿×<Àœ\À¥ŒÝ}7ãì©vŸ$e6¦¬?¹xfNüTÁ÷“ü«i VªÝ‡Qª–ÖÎYIVWÇhTÎ8§4VÞ Ð×™¯ŠÒx_ qH1ÐÖćÓó{ÏÝ[§„^¾²s¸÷hðôtr2kuåIK£hoë½oÿÎ?bvÀK¯ÿo€F@^¦ÛAOß*B:ÒáJœÀqò°€à-ê+¼RúDöšu_ÎåÓ´œdÅ”×'y;NÖËs/i'&þú8ùʧÛ,szޱ8œÄÆIÃJòs Ä/HºÝ‚eÕBAá¿“q’õ ŽnØdP¯fµ1jCˆ!H0 T¨Ñ'XÅ–¨’…$Hô E@È&È ]¨Q ¾ÅÆ”¹”ñ.¡Çt±é0I îßoÍf“œw¹téRç“Ö¥—¾»ûnÞ> iñÖ€@<#OK…;ßù“ ïúk?îzmn 1Þ¦(bìº1ƒÊ–Ö Ù(ZHƒA‰áqrx2^]l¯/·™6:N6SK]ùÌ\H=ûA(DúJh,õ%VW è}±U‚ pºá]3 Ò6½Ø}Ÿfgæ[e ©5k™f^ÅQ™”×G©{'ÍÕI“v¤G,mŸÝ ³ÚHÖ kªdÈQUÊh±™¹9z,5Qãó•±…Z¬A"=XØbk€¸-'Ö:‹Ç÷÷}ÿyÝnwyiy3š¬-lô÷Î2PÐ* ž=øæ·~ûdÜÿÚ­«áÁKä„@‚&¯Séâ2mvƒŠxÈ*vìØ™„'f ŒYO§þýIÀøE¤8PýˆðCòð"}¦åR¨ @nÐ5^°«ÚW½¬ÊB'™Ç;ç´Ÿ®±j%k¤=wš’Ÿækž™iœlwÇcRÕ>^`Á¸|–¨†éâ[Õ¾ w( ‡$¤+ýïˆ7f "N ÷˜0reϹj‰ðhãfD=–CÈäR\æ„NöÏU#zó‰h1cc)Df&ŸŠŽ~vȱ‰¬9pЋ¢ŸD^›8 ’ïŸ ò6ž766Žú§7Öo ØxWíBЃ¯†PñUk?D¡ÿôþŸ~óßü÷'ÛW^þbÃmr=Ë;(¦]Sf ÅY9UcoÏQÈ_9Ç$Ú ÀÕ0ƒÃ?¹À8~§é¦¼¾ÝL5ýF¾Ë=Û-‘Óuñ¾Ç‰?'ÒñNyib~Hç¾OúüG#¶Ãd¸ùxÒÏl9Š¢Y£S3NEu04;Ž˜Yθÿd2™á5u&<|¸Ùݸ²~}kïÁy¡…Á“;üö¿úû?úïþòæõf¼œŠ©Üð Ç~&Hñô™Ê%«m D¥—ȾOéBb Ê/$E«À’A 8Lá·iÎÖ3­BQâ h€èÁu€óâÙîÅûÜ5ÚɹNËMøÇ?»ši÷L©Ï9~’¢{rÒÜüâ÷§qö¥Ù NR÷øcqXeš’A[Ùæ!El5Ñ"àÅŠ}© ŠÙ'ª„`€ Eiƒ¤hTdi'¢}=õÀXŠ=É÷ g‡=H G2Ò ¼V'¶¸òüX$ñõº½%¯\{cÿxgì¹µS æÎ7Hd²ØQä?þä¾ö/~õÏþìßÙ¸ö¦-`u@©½bD$Êk=V÷;~wP °F+ªú6ñ2¤ÑcC’ñiVŒ×7Ý6û$ßM÷ŒÝ§g™ ÇŸn„]¦ŸtììðÎ}_Å]µ 5z­ƒÞ$À‡²lÖ㎵á€2ØÎ<à‘„¶øJsa´A/&¤)ðü†˜ëºëëkOwö¯®½ðâ¥Wî>ùÞœ­`Saù“Oþðãoÿø¿ÿ÷V6néÀ¼BlJ¼Åg* µžâ«Iëâ Ü ÈǯºÕLê‡=H‡4´>W"êW´hm£AÚÉ*èv¢à§‰: ÇÕü3sé¤ ~²éiÌëGÉöQ’‹Ÿq–¬©Öî§`=ÁXv ÃÑ&4¥™9[åcay,)Q À2LØimš`tB5ŒÅEºÀCüìÈ â$Br0HS— êȗ䉈Øb #wDŽ¸Í›„cøl¤ƒÉdr^{‚ò¥Ñh,--=~ò´çx·_|sïhëètO c¹(€I7= ÒÍ®ãD¯ò ñ‰E3^Ó“…æ3ÚÚÐrC‰YÙR§7¿ê¸A[u†¿ê,uÑq¼f' øký~8> Þµ´Û¥l>†/^yåúå{§ƒ£x›èÊef "ŠÂ‡ïÿöŸx¿úÕŸù[Kk/ Øf1ívÿ²>ì  Š_–ÄjP™V´QýÔx啈Õc«êãTƒmå-ÚädÊØƒßò:ñ_·Ût=¯á:ÇwÎÄ¥ÃèÀï†ÄØ=Sðã´n{d ±²6ª†“BhGk qNé²û¥'0Ó`œgÑÔ€O,>NWãm‚•«®éUdÅ\¦ö¡mˆ¤/pà ùûù¾9ÐpPc[Ñp5ñq,iãuª¹ÒZXð•3ÀŒ€ååås_–zšÍf05÷Õë?´½÷p÷p«ððŸG üѽwÓmv¾òWþ«ÅÕ„ó…`0å*y!5ïå~•r=ÚQ˜o é9½äÊô˜¦à§¼~zäáÙ)øQºçÝ(Ý )Sð£d)Vz˜­ÊÐÌÔ­S‰ k=œ ÀVs‚±ÍËŒ0$гM %H€ÄkÖ •@íœ@\da{d+&?:Ëk'Ûya“ÏÉr0&:Î0`zÖäÊÆË/^ºutºçç‘§ÄIcÜ¿ûÎ?k¶º_ü‹ÿEoù*åŽ&œ>NÄþs4^ó)$:H |MºÞ€wkä'8œ@2± ÈÍeO3ŸžCÙKþ&):”ݧÜþÌb¶£tÅÜ8þ;Â4é>^;Ai~Ú ,ºx7£i7!Î}˹vǰD¤ì P-&ó=ÁBC8ÁXÂ!{XleñÇbD9šqì‹W1Päí‚à1/ DzIÖ×tÀ j?ÿO4Ȁń²Yù%¨ZÃpƒÝ)éoµVg©Ñl‡“!_Óéééx<~›ÿLôÒv×^}ù­‡Ï>Ù?Ú®RWÎÁg±²gÇÃã¾ñë^«÷…ÿO»K—ò;žî©*.àÙÕm#æ €–K¬ŽK·åu;n/9 ¦ÛñšÉæ9 »'3ÜVÁÂá8Þcóý`èhjZBæ¶Ó 8ÅKô„r|Z‚*µYBG¨I28dŠÛÖ!D¿ûŠõ(ø­ôH2·ÓŠ9¾“(øNÂôÏ, ìÇ8‰šï'gU¦¹9OQš#'SâTˆ#¤àU‡94õñ§©K!Ô NÈI®øqժʇ5qÈ$H/K±#ÅzOjæ±¥Ê;œ\aö¿'üè³ ¦ú1çªÓn´Ex½_JóÈÀ÷N¦Xsĕ B+•®²‡Çˆy"sš”6H@Iwi½¿û„Ö÷ý£££ååås7X·zžÇ¸à® ×}óÖ—ï>~ïðtO—u;÷B ÒN¾ó»ÿ«×ì¾ñÕÿ¨Ý]v,gÃ.`‹d/£ÄÙr¥µÕÚµÀUÜx‹´Ä™ã¥^Æî=¯‘yrHÎíçÍôÓMÓFŒãbvϘ>cý‰ï~ê¾¢£ó6ÈÐ1­Ûîl÷C BÓlíÕ¡[c¾Š1Ù‘uÙV©”9k„Í$h-.;®GC!»æÙ³g—/_>w—Ð÷à p=oiqý37~äëïþVHgHš±põ÷¿þ›ÿ“ŸùÑÿ Ùìy…Øè3½ê™PWôñ!å¤L],¦¢Â)> éGDª\Á6ý¥Œø˜Q0.¿Ði.t¼^Ç[è6Óó­¦~œ¤ýg–T0öƒÁ8Œ‚aÂñ㣉÷=Í”Üd}’ŒŒ¨³i3*¿¾d)ä–´}ªT+õ!•AµÖƒ¤aŠ9(Š ª¶Þ Á.%‚¥/âWƈV±Œ°f <ì³æ£ßÑ ¬!:õªŒ8‡0sxë ‰C@Ëjhš¡ ð‘@ᵎã¶WGG»ü~¿ppÐív]·†Ó¥f/Q0av€ëz Òx󕯼ïí£ÓýŠuÕb9p•LF'_ûç¿Úî,¿ò…Ÿõˆ}Äx½¼êf©–)õ‹]Æë[K½f¯Spü³Qí§˜$ >SêcÆôƒaò7ÌwΡõô5L¨³vÏÖ™Z£”óXÎh€ÕÖתšK]!œê)U™'¥Ö®H€•'Ož\ºtéÜ@ª…Da¼bz¥Óîýðë?ö»ßøóEŒ/ãáÑïþú/{í1,éG²ÏÔäâË,AÂï¹Îg '(¼RÊ)`Ðífc±ÇØ}‹)øK±Žß œ&}f ~ÌåG~?qâ÷GAr(1I·oT¼‚²ƒ¾ð+ òÒR—ˆÖ%H@¥ Jš•l@ýir” o(_@S3[Á*É‚©­ú%€ Ìëù1_8ð5A‚üª°{fŠ­.HP 8qØ DA¯«×›Y#²±ÄÛ bÒ”1á±Q¬8" 6]ø54Bkå9=½Ðì-¶zK“pôÊéé)3®^½zî ¸&NíËÏÞüâ·?üƒ£“½sA"‹ps•Òñàø_ÿÚæQ:÷p -‹»<à¬Ù£Fy ìÅ7ØgOO©É= ¸ç¹½¶{uºÍÅn³×Žøvs‹a¿&Aì̉üøoÌôùÒòí·øœŸE¡3õŽÊžÿéÕ<«øˆ¯Dü‚ÊŒƒÂ¸ù÷ä![~ƒºt‘?›"î(Íá~S cë‰ TÀ–&áeªÛp‚f§ˆÊ)ä>FE®ëpoÕz߈NpÕBçÑ™ŽÞ-›sX’“PT—BMøÉžTnõïðƒD7ÎAÄáÀÑMõ1¹nsaãš$Xyøð!3ØÌ'çW„Á“ö á¿úS¿ôÁþÖÁöG{O?<=|…M½”ˆg€•r{‰´9+™ò^ɾ ( Ø÷=ŽôK\B¢7Z³ Z£?2ýtÁ±t¤~›F³eì¾;ñ»MÆ÷[­*§ —*”OQIæ8³ó‹?ú1¯Ÿý¡„ŠT“c€»ÙT4!©:,mmÝ[.hx‡v|ðíÕ7˜5I8ÁÍ)Cd¡ÓÕÀ¦=’…1娉æD\ĉõ¶û̬dÖƒA/3úÌ„ö/±`iîIÇiõ–›ÝØç/Ÿœœ<~üøå—_>/# Š¢éöÔ1gØî²×þ±Ÿø›ÎÒe{`NŸ}²»õÞîÓ÷÷·>ÜÛzoÔOHóû"UŠÀ=A5ß±…¢R²@ !µ,¾—Ù—ÇSílJ³x,ÉÝô­f¬Ý§¼~¡ëuÛñ¶µô™‰/ÇŒ¢Ñh4ÅVºËøøñ“èøicåšt‹q¶…•«ìóòë~ÚŠ`t¼ÿx;–»OÞ}öèÉà0 ý( Ø_ùø±*“N$£WX–P‹úW([Ðùêà>c|zZòë6zÍå^»ÛvcŽßiJçÂϩ䩖ӴKJu™vgéŒü8†Éæ÷:Ÿ”HEÅh!j=¼ îò\C¯òa4@¹µ,u±ˆ°# a[«±Œ¿n'÷Gñ«j:å¸:W#¨â V[uØsù©×—ÒQ²­ u›'oKXpÑT±~ãwn×åVÛ°ÒXö1jq j ¨c¶ÒÄ7¼v·³¼~º3ž:88ØÞÞ¾víÚÙ;‚|߇²Tô«8d2Ÿ}ØXºì4\‰$òùÞÍÎÚåÛìsûó?EâõžáÉÞÃ'ï2a°ûø{ûÛ‡‡a0I?f¯!yP" ¿n¨laúþ•µ…Ëk½Vs¾j>¥Å&9ñæhñ>øI:æ(Žc5ì‹ ¾YÛFêRV×1ƹŽñ™Îh ‘®YØjêTŠy̱ ñ™½æU­ö¹ç€þ ·Ù^\cª²dAððáÃååå………³”±'§Ÿ¹¤’=bd€ØxFŸ:«/š«rDŽÝpܕ͛ìsû­Ÿ&±}0>Þ{ ƒ'ïïm½·¿õ~àØÅÀgŸQ/‘ÃÚž¨FÛâ{ÂWÍe&ÈZO¦Gäúäïw¦uGÁ'ûCÿÅË‹ f-Û¨M³qvŸü?Aåª}Ìî'³•b¾ª4o |¦  *Q%6Xâˬ«Ï”7àæUÈÖì·-\ÞP Z#D©f,©6£.H ’Ç$ ÀI¡`€ŠBÿ«$“Cå@ÃóÀƒ¦ LO¿f¡C€æ½“‘òæSå œÉ¢£mh-¸CT¶`¶­áÒð›<بÜê-uW/îÒŸ Ïs\ÉÁžpáQ°{·µt…$wyÇŒT²tMñbò×õÚkW^cŸ×~äçHrðn,>ØÛbòàýãý“Q?˜ L”FÂ;Ä~˜éHÈ$H€£è3åê£èñÎI8yùêòêRÇsKË€Ô‡“œYŸl’Mžl“™¬·ŠÙŽü0¤ÔЪ3Uâl¦B}>S½ƒ·Jßâzô6ïÃá@Ð÷y\fÞŠŽª,ž€Ý§¯¿Û³¥eU°,C»Ò‡Ú£Þà4ÝåMxÊìÁEHéÞÞ^«Õºyó&û{62`2™°—¦ß™qâzÀ¾‰°žl»6#_®wùúçÙ'mÿ¨°ÿôÃýD°ÏàdÇŸ ˜‘äûA0ÒɨñHHN¡Hüy°·´€Í¼”bÀ‰ÈÕ‚©ÊéÍÓq¸wã…•+k½¶1 ±û)¯O´ûä\ñŸîŸ“n…¯ •p ¥Òx±Ñ<Šé/Å·Í+mÂâý‚"T&t®=|¾‡ð€„-âKR"HBŠ$—È—tF UBÔ\²ÀãÍ6 « q(ŽåTËh)¿€H#°†m60J§ÌÉݦŒOŢПûVeaý úøÁAà_¿¼¸Ðk¦¹ž¹vÏ8~˜P&G\MbÕ>þ›p|!#“Øò’ž'fU*á Ø®> Æãò¶c‡/W|ßòä “W¯^wRSE™¼I¿3•œYzÐ <|⮿ì*é@Š©=üõÕÍWV7oÝú¡Ÿ$ñ.@§‡»w˜}ðôÃíO·<Î%¢M¬.ij¬Ä¾EЫ˜ÙRu@ßÚ;=Œ_¾¶¼Øm15>¢ä\Ã`4fŸx+|ÆîÃø¬ƒŽ9艈…¨ÞZ°$ 2M i¼ßV&¨ˆ¸ìïä°QƒSO¼¬Ëi6N1?Uß³@t¡oDõƒòËÇÓk’Fͽ,{xúbAÙÃk\ KÅTp_.©¸:4£¼¨¹kÕdZH6Aƒ€o‘F.àAWLM}Hƒ6`©LNƒrµ@H#gxúµ7Z+îZ‘Thÿ˜Óp{kWüaßKíF?öi÷ö™Èž­¤Ö§ÔP…sž üï,õZÌ&ÆÑZA¶#½å\À¶LtÖSI™‚]À0637Ç‚Ž)H€"3‹‡×îZ.¡©´*ÕÈú¶¢Z†ÅÁ¢+;2stKîM ” iÌÄmšÅÞêå“ÉH͉d|ùÞ½{¬GR0xÀd2yðàAþÓõZn ´²ðXÞÆ ga ´ø9•…ÕÜWßüÑâm0Ž €DRV @$Ž Óá8˜ø±£_£\°`«Ó9µŽ±º¢9zÌLxiŸ“k1bëÈÀÖ 4ͱT¤…t€›ˆ'3r[‡x€%âe`Ç_³w;W©ªÖ†fØ#ËúÛ°w¬t´² ™õh¨w¼NÒ(^¬(.ŒA3î?ý¢Ã0|’”©UÛp»+Ýå G¾ÁÄ]Ütz«Ù&ô0Iì#Q.ÿ¨üt3…tFúƒr™ªVY3;ÀYj»\[3,î޽˭ÿr:‹« ל† …óÿò&F“¡³¸Áì~oãéiTi!jµÉzP)W;Nêr,sÆ@{ãÈ)Fy-î#¡2ÇAÎ[p/6{tôxi«0b«‘T­RÖ¯y%¬¬O ã¿aÃÉ»¯‹ƒBˆ«¢m±>§±ŽÒ>û0n§Œ`–!ÍuË$ÐáQÕ{ çmv"ŒG c٣ш /)•CA0ÝÿþýûGGGy @Ãk-n¾Ðê-*¨ËC(þúG';åKÍö"Ð"MŸTDWC/÷Õ7€‚÷è!M£Íê`æ€ë,­lwƒÚ„ôOgg f/®ÕH«â´µŠw=¼µ'‘ú¸ýübÚ:âK}–7Ï ½¬$kV2ÓFl­ú•ˆ­¥å¨iišxÄ¥Ñà4®Ûî1; ôa0™ð}?¶šÍ²QÆîÙ³;;;<`&ŸÖì..]~ÉÉ*”±U†Âààñƒ',nÞèt—°¼3ôª½¤àƒAÀ„pA`1{ŒG iå g#ˆa”[Mc HÓ*e‰X±Ö6ÑH\èæY-˜•‘ÎjàÁõ¢Q›3?‰ ¤.#X¹\QX±Õ“j¹ 9M-¸1¾Éa¸éµ;ñæ þŒW°;§§§ý~Ÿ)òì;#>ÆHY?Sù···?~\x~’Òp½¥Ë/·W´¨*C¡Õì|ðîÿ·³soóÅ7Û%ræÅ½ýæZu4Ø Jt݃µ‚ÏÍ^žjò™*Ì ã OðîSR>H€äL± ãƒ¶±„u¹À$ŸÝz˜=ÅhVé…ð4Ö“ßê”™]Bð;:ÙMc€çà›è·n³åuºl†“q±ŽXÒì T0³ Š¢ä pG 0!1ö÷÷Ÿ&eww—I ¦·qmq3Û‚ÒˆM·õ'_ûÇ“qýêkÞŠªÝË…`Pµ™)àȼñì´J‹ýðkÊï;d†°½¸†LóRÙ1޹&xó ^¥«ñÉÝúäþZZ«¼ÌVE–. \Ó>†ØíªÖ†-¢ÁøiPb°Õ0àñYwT\tR­é† >Ç~©ÀÆñÚ½…nsp¸ùðžÉŒéŸ&ÅuÝ………^¯×l6[IImÆèÇãqú÷ää$ßíY*ÍÞÒâæ ù>ÏøÍw/¯¿°¾¼ùÎþ³V¾ôþæú•Wó[D 8K†4\Ï‹{û¯[ŒzùÆ®$°‘¹°[$"Vç—ùÅVÿ‘]‰³´ ë×@z¬k±ÌJ#Ò-dmn@#l „‚á€1 k«´Z²Œ €Š±I(líóÍêÆÒWÑp=&× Ç#„™Äe,žIf1^Ͼ0­oo]IýEà³ ¯¹|õVka™ †„jÃi°WßyðÎþöÇþèteóå^|l¤B;Nu—T{å¾xÝnå¦'ü½Z|³ù l` ‘ês iY†•ZGïÙbžž¸&=xQ7ÄÊ"¬^ BÖÇ;òUVÒ àO—°‘lþ@ÛD™Ù1!Ðî¹Ív¼a󵀯ÛÏ“¤°/æã·÷_Ø|±·zÉÉGHÝ2îv–>yôÝÑðä`çîðô`yýÅÅ•+f ËÛ~pá€ú[ŠÓvìŽeÈ ·ò™:å†}IÀ™/ܸ¬an‰Õ0-´± н`,ô°2][¥°uH¹ AéFØ4:H¼*›nÔTbŽ›á|4ØÂ¼Ôn_Îdï‰MÇ-¸Áa›õhÃkwS1ø#éð€YŠÛê.n¾¸°~¥gþÀ“Ú±õµçµNúû;ûÃ`r´{p²³²ñòÂÊ•ôH™DU”þ"6 ¶—ÿðWÁÀ€Qd¸cÌhK®4¤<` äçIÄ|à4"õ%V—Õ8@lLô@¨²óØ@ÿøfm„¾9P‹±2Õôìf MŽ#~C#ûÈwÊŒüŠ6Aâ2 8Ñ2Àñâ°p‰vI—Tª4»‹‹—®wW7ÅÙ/Ф¶ýkyí;¿1ÑNŽ÷m­mÞ\X¹œõ¬ÍyP‚Ÿ ÝW>û•Œ>¶æ"óÙèŸ )&×' 1²&ìø2<ê˜Á2„5–´‚µ¬`È~³…Yå2Ù¨u”h‡m@ŸE€˜ÇjeH íþœ< êÆËh°5^«Óì,¸­N|ŠHTŽÓZXYܼÞYZgÖ…­ÅvÂ0#€Y'ýø@±(ô÷í=X»r{qù2´¤¬ÚóMs0=Y§ŸÂ@pUœ^d ÈyŒpý2 ÒLÐcR§ •­wKñ€È}k„œƒA ÇVPM€¤ 0N#뛟@}e޵Õ>Š4Õ˜.8ÖŒ¡Æ«º­Îb³·ä6[É#(§P’ÚÓh-,÷Ö¯-¬_mõ–Š´¼ð‡ãÄ¡àèÁÖéÏ( Nïo²qõõÅÕ«ŽÕ8¶Q[˜ø²®”M€òx#Ø›8p¨ê]…G[|•â|¦N¶g½Õ †7TI¿jB˜MLäp–`1Õ,_5×ú‚[™.Z”Âx-´Õq'á²1œP€dcÉ€-ÿ«˜Uqx"öÚ:‹”9¤A€Z«Pjv”UвuÌh¶âÀ@g¡½¸âuØ…(ð‰fÅ@üPÃí¬l.^ºÞY½Ô^\õZmÑ?#„5³øAlÁu V?»;žLÓLiž<Ùyòîæµ×—7^âjpøoRûÁEŽøá (#2&‚·÷bÎd0‡S|ÁÍÌv»–Ío´ݪT9ÀW;Á,hصÃ;Ì”v2éåƒ-™ ØÝz¿»°¾yíu¥ _0'1ðeµ lb5ŽÍ£ K'V£‚|ƒ0Aj@@A¶|bumr¿êˆ7­.ÐVë3ÐXÂ˃ ”Ú<ÄÂ`+i_bÇsÙ vݼݿ©6¾Z[slPµx08àfwˆ1~£-bÑ)¾Ìf_úÁ4ãÝ4Ä ·÷( tpº·¿ýqgauã…ϤÒ(ݶ(‹=ä²ÒQ;ˆ Hx¥ÆÑ"¯Zë!19Íå«!Hãcõú…à«ÛùË«®e$“c»‡a;Æi0ƒ g³€0ƒÂï#­aŒ)\*HCB8Ö¾ù¹Œ®[,Hƒ¶7kôév×WQæ4Ž™— æÃÉmxc¼µ{7åæ˜°žîím}Ø[\߸úº#œ8æh¾Û‹ûÊg¾ =ýÀqe¤Y0kRÕÀBòðúD!Æ­ªµyÀÍnÈxZ0³üšAzÙ¸O-ýL¤AzP¬ã}vk㡱Êë°×¿ãù8ÁØ¢Š”ÅÖþéà¬z±Žk3úHFiX¥ÑÁѳtA€\˜ èìm}°°|eíÊíé:áüÈß©ŠŸú0Šð*åÌ€Ü0a†T‹¦?pÀÎS¹=5ió›Ÿ@pm ‘~V@j™(2B˜•iá²µì ÆðŒÂc²pP6B\Ù*›AÈ´¨IàÇ<Á>#b¬€ÎXª4ø³ÒôZÇýƒí½‡p+b;`ûÑw—ׯ¯mÞäW!è^¬#JÚ½î­Ï~ [ú ÚãÂè¼,œ›&šàv>™W€bÄSdÙ A©Œ97(Ž`óJ¢ æ)ZJ/p î+c³D?¿íþ‹µ­«ŸÂ:–tQMÀŸ`l[÷P `ƒªMþS Ï0'Ýpâ€-)sšj-Øp€FÊ¥“Öì#ÂÔ­!Ó Ž“Jn"«b­GÕD&«óÌÖZ¹Áxוœuûˆ”ºpDÂ8ì¦Wñ†ÉÜb}DêU "‘ýÅ‹×<ì‰Í5JH»Õ;<ÞÙÙlþ¸ÿñw~óÚ­/®]º™qÌÜuòØ?TøOZÜ[Ÿù²Ñr±­¢lHd^`!ž]^üì‹Ñ¼+Î+¯®œ¨¬7 z Ô²®…ĈmÄíKÞ$mk+ûˆJ ørÀæsUV±) zŸ‚ÑÜûLËHþ#}DXzÕæó4íÿâà‚ž£Ýƒ'c>},/a0yÿ¿ñÂÍ/.o¾ÔpŽÚÕ1©“­b(®f7¤6ËÅXf6ðKÙÔxZÆ/a‰ÏÇd®ÙG„nù™x´l£XH{©ÙßX¥û{Pâgþµ¥°­ÕGV[$)ÅæÃL¬ ¼±zuiaÓêÐý_ÿË/|ôÍeçá\0ÓâÞz= £œ é©÷!Üh)^>އ¦ >£I²´ÒÙìe«QbÇhœÌR=»Òj,•ð7ê!qŽ¿Ú·!²:{p¨*Yý¢¦æÀØâmä°Gx r,ìfN^ 2ßgf»,Áò›¦ùfqþ”ðµ›ÝÃ'ûGÛT¿9]^˜ðøã?^Z½¶~åv#Ù›ZpõhýB±æÞúÌ—@Ìf˜ú““ æÎajDUøV»(å0%Öù`ujb¦öI„ˆÔü®º~®èùq_ÂC¤i N:#œ,ÄÞ… Zˆ‰¯=¹9@tÃÊêȱ{T“ª±|âD3dÇã᳃G~€:Ãr2î?½ÿ­îÂúÆÕW“Óip”gÀÍÏ| ÂRðÛš\Wš OMÄksÒzJ`[6¯Î À!‹5ˆnðÂ×.EÍØZ¾—ÚÈ™¹éèÆ¦‰ÆÃVÓbâö*Ì8óžT´%„¾t µl¢X™ ES¨‰ÜQ2°å!´A€K’­aA>ôœçµž<»3\Ÿ=ún»³´qõ5×kñuËÝ›’Žˆ-½@H:³,üž“ ¨®õ@W4¶sr Ô¼Õã`U­JÞD¬C@K«¶„i"²ßÐØjë°³>¼é àíݤÂ7‚«»ŒFßt¼V…A-ÿߪÛCÀuÉ‚0Í0Ón‰é¹v«»½ÿððd_a2`÷ÉûÞêÚ•W]¯‰™i À€"Œ¨Ñ5ý3UYAë)±Þ¸¶¶×–Å6½cE"‡CYÁ¦1nbH;»­9q+ªØ6`+/.÷¶Ùå±Ì Ÿ±ÚÎZl‘ÃGhÒV»•mrx¢ä~Ø#í8à!»ªdoUG9þäéî}`_ }¶¾Ó]X]¿ôŠÛlñ´u¸O¾'Ââ"˜™ ߯b-cC¨­sž†V@l#Ǻ˜3ÁŸ`e‰Öéi‹lËi5pUGÿ° ¡â²8óiÖ!T4 ¤ñIª,f£Hû,²²( +¶Î?ŒX›ýDûìk«Ù¾ÿäýñd`§W&£“íïô–6×.Ýr›m30_4agYw-èãÆ$}yó¹ñ/ˆÝA¤ÇVÿZOk=K+¹ø¿œ ݨÑ^.‡ƒö«6He^C[”˜›cÁvNAàµÅh(µÒ pÐc¶ZA¬¡‘«5¢Î_6÷Iì3°Æ”9/û€Ç¯¡Q¨ghŽŽÐm§Õì<Ù½sÜß'%ËdtúäîÛ½åKë—_ñ¼¶úÖÜ- Š˜ùàž×Á¨Pœ« å|6N(1 ¬ãÆiV3ʾA‹-¾.;:ðcœA|ÿ§GhвªGÄî×Ï1{SÛ*óu¤¨/ÖÓÕ즎/”9î‚ó0Ј_¬™ãñ`k÷>&T*þdðèã¯-¯^[»rÛõZ:üÜ›¯}Ix±mÐM¥êö²ñµX[hBÏÇái#|C¶w`RæJÆõ/.£Ã×Îæ¬“HÀÌ}¶km.’ÜÙ»„«Ž [™nˆaO,ìMî.K÷ÁÀõ¤2Ñkð×,$«j.C/æ~ynëÎÃw¨ʆ?¡?zðáï¯l¼´vùVÐoT¨÷ b±ßôFm+-©¤$êŸÖRjáîüÛK˼¿¦]óI¢´²ƒž›ŽVUë1aKÔµXZ°[K@ú —ƒmt¦ Ñ?S:H0§ñ ¯Œ®~ üŒ³£’A Ãã†gM(s¿×–XmñböìÑÉîîáRµ“Áöƒïô–/­^ºé5ÛüñN&ˆ©ß­KÖ]Ư¦*0²ààÃÉ€6"%åæLኵP‘¿‰=À’XgZ™´R¦Ï¬MC0[u³çQh]À06@õ0¶€Ñ³rØ‘¿ †p™ËÜAËŒ·^=üé:ÄÆA;–°êÊà xæ¦_"Þ}ü=2CNâsÄ–.­lÞðļ ÷Æk_„:SÏõ¾½e|¦f†aK˜ùdï"p]¼X¾†Õzæ´ªžà¦ÚŽãî”X\f©ËîW¶Š,kK`YjÀô3"gÔôc6l\ñ½ˆx­ò€í1ä$­A@/*?쌽URkZÍ·÷¿E!™¡ŒúÏîô7V6^Še€3}¿{3Ý•˜±† rղ뜵uÎcÓ5m°¡šßDeK£@ËÛée·<%ŽuhFˆé‚u kk)‘á¦G©oh:wÍ>ÎH»èJ‘Å˃ªØÚíl|ÜxfÉaÂëì†=vi‘µ'Ÿ‡Íw1>",/¨Ž-zzÚ‘!ì× p ÝB)7žº ïÞֻȭ¡­åôðéÑÞÃ¥µ««›7y 7ˆ…ê%:Ð<P*öÌ~Ay@^z³²…!’•+Ô/bDk€-ÏÕ±º®É4ˆÒ7øßÏ –y¨ÇÉjNc°EyªÅoŒA€ ª¨ao!¿£y†I9“Ch˜Ci´søøøtÏÖHl9=Ü:Ú}°¼vͽñêmöru™Vbè¡ b ¢+V­L¿ Qöò\O0Ö·6ÃðØ! jqØ–Ãj}¦ sªî 7xË â;8X¨€y[© ~É"è…i.DC™1¤aá¶¶€±€×-ÜCH’‘áètk÷® _N·žÝ5¯F¯”+s.¼,³Ì¸Ø™W{b[‹hn™Å~øUŠ%W.Öw ëÌGà–:†MLMøŒ¹_Ú3rÑØ–YzjžÓ™Àç°®Y]•¦k÷qï/udwÙ×£n”bMnÃÝX}¡ÑpËPÃ^¶î}#±øb5„ëò™Zm<‹{güY-sñ ©GëAºUM¾$‘êÒÇí¨>'! {uĬ’Yïa<1uͰÁzÜf÷!çª~¶ \£X}¼Â°/åEáÁ"Â&ãÚêd¬b8žì|2ž q-Á–óÛ hÆ}C*‰èó,óÁ’¢ëÅC’2*µkËÕ¨p¶½z6›çÔµÏ|°­sg¤†jÏik£ŠevâCM·µ¶|¥vdÝ—_ý| ‡ àý¶ðö-¥ŽЖùl÷ÏߘÏnBšáûŠ=h{Ǻî!G¶B€ÆIÊ›—˜á›f' .è —ž¾å¬t„l&l¡ËØ ¥¹D˦’Åx0éºù›K½khbðç•!O0VÛ€³ hxôt÷žvåJƒÈò¦”+ët›[x™‡ì.àY›ËC”òÛÚ®•Qóçå3 ¶5F¤æ¡ÑØ¢S߆®¶êì+1àmô(@) ÊU‹Ç¦Vƒ?œª â}¡›«‹—܆W'êñ^@·D¸»­n-{Ð3ðnL &VŸ)Òï]i¡MíAžFà‡‘Û ¡Kê èkD+kæ…[lu˜¯=ì5½SQ×4§â¦*4—ŒC̈ r@Ï'HéãuÄœæ‘2‡cUÎ$?Ý»?öë À1€³ðÔ~:<÷蜩ÒQjÏùJYŸM0%¿dù>Ûþ9WgЈ¸Ì?eîLKÕÁÖnv–ÖêÅÅ}ùöN®ü‡ãL>S÷C_©¢õØ]Óó ”7P[‰Ø¬M÷!ŽHu(·÷‘ñýiìAï·•Õ"Ô69%ƒXâÖv@‚ /´ƒž”š•œüçÒ(F>æd[÷ÿ/ôÒ#­‡¬Ó¶†4L84Û½ÍomÞúâÂò¥FÃŒûQXå¤0¾¤%jn¥xæ®ÁuY²¢p&›cmpÕx. Q q;¶Ð7é9j¬—G–Z¦@RŠ!Ô¾zÓÔ0 ™ðÝÇݰw ¡¯ ÖN+Aûx†‡£æµø¦á+ÑA¶ÏmJÑnn¬©fòÕq®^yíÕÏ|5ðG¾?œŒú‡{÷ž~¼ó䃽ížÝ Jï €Ä›NuXºËÑ:ʱ&[®•Šò¡ü¸µ²97JeNEhîÅTxTÁrÕÂþ8ª´LQq Ô©ø6 ”'èà¤ÿ¥\Kà ¬Á¢SNhZ L‰ÒBþÊ5F‚;šÁɵÈ_q¤PRzšœ*Í~Ic‰Ï\u  Ëá°¤2$‘‡‰ïqî†mp»Jò¢8Žø˜P—tÄdš¸ðZž|ŽX­Œ*Q_Ánv;Ï•”.äªåúÁQ:…kŽÐHÒC`rP“¹LEvkB”û ÌÄ'rhD¿Óì¸Ë›ìèåßôßøóL“‘?l={ü½§¾³õàÃ{a0!¶R1¦<«Nª¹Q¢Z«¬ùJëûjò3#Z¸RõÙ[&@ªŠ¢¹Ø—Øáôœ«>n·/g ç×^ À¹Ï¨’Ä/ç?ǃ`xìv‘è¸^‹}Hw9¹Mׯ޾þêW˜0`"axºÿôá÷¶îóñ·wž¼Ï®€¸8?ö—ÿãJG¤Š‚†€+y!Ü¡„;°ÞŒa´ lm~T±ûp㬖#ReW¬þµbµï5 |„LCv`A›Ó#llÕˆ[C­ý ¦Ù¡ §²žÚŸ—Þ†<îXdcVŠ–üè —)H„pÊíÊe&‡¬ªh.¬®îÏ-\ÿ Ì™¥4b@L|äNŸ>xgëÁ··î}{ûáw§û9˜Élº¨šƒx­§Œ+ïá-a?:i™ A ÛN¨$(A2*v© GýewH[°ïW z•½ÒxÃ[šúæ1ž™ýç¥Bø Ê”J܆LO¨ Ñ©ú"dÖ WlàýŽÓðšöiw—éÒ¥åë·?ÿ—¢Ð÷'£ýgwžÜyûñÝ·ŸÜû†G‰è†$«è3Õ8™%gãÔQldूÙÉ¿NH¥ý«ôåp‚ªÄAnW¶…‘”A~T‘Ð ™ i•BR¾ `°q¤‘:ö7Ëu4A®Z‰j€* N 7«'È=+"v £ñĵPV$œ¶¼ƒPó¡©1­läÄÜ×Y÷‰ b < 5š mà^$Ï8ñe0/(`Ô XñCe!"ý´RÌô↾ÃA«'OMGá*ÉÌA"NC€(ñ+)¤ù“`xJÃÀq=fú*µåotÝû°ï]\¾tý•/…aEAC‡Ç¬ÅZO¥•Ò ñw¨ÒÞ„®sJµ÷¨jöÞ©kœœM¡¶kÖÞCw_•«£9szí ƒõ ›sf\Ëô(EV2ãºú`tÊìÐLÀ]d¶ëzíV»ÇŒ·›¹×‹ÊŠI?ÒÊ` w'Ó¼­ PþEµlª>íÈ¢\ÆLÒfµ6,($çdZEV«¢°š‘L©rN…wÒ)ŒâÒ”,>g'é`H‡)Äí°¯³ ¨RƒÁJš;-JÈê@¥|!H@ˆ‚™j¼qTÔ’†móâ‘B_ÊèHd‚Mq[ˆø<Æ6ÒÈWÌ·¼E@÷9À˜Ÿv ™Qwß–x(iƒu¨ É`(ìŒ#å³ð¢¢f[Ñ6s¨Š*ɇ“€„Q­a¹?å †44¹ÇÃÑ õ›½eGäžç‡7§ÝÊ}ù•žÕ; Ì&³¦=úaƒIûËŸ·ÔmÂÖÁý06œ?vŠèñ´ýÐ׎ÀV¦›*ÿ†@=½æXa`›ÓµöÅ÷znx7;¬Ã3* ûšÇsvÁÒbLZw~·Žt¶¶ÙA°Ã^ÄA$hvX{~¶?è„­vwíš›xî£"Î^˜ €/¨4²7œ öͶ6~¡cûjÇêã´Ã ·9È€çWˆ¯D² ùÍg&O|û˜ÀèðsØ1OÌÃÞ4æ‘¿,UX0ÁKuKʪŠcü†|Æ: ±ÃÞX_i킜ȧÁäoÿÓýëWn·;‹Ž­V]Eéu÷¥[_ÐóYK÷L2#‘, L `©‚·’¬Ø:²D[G…¼ºÌ˜¦±J£äoR¢ˆ’(ýÑ0þ’_ɇ•éwewå‰Âønò!¬¶¤Þä“¿&o/£õàß"ZX_li¯šjmõ#öÆÈGgcëß ë“EàÁ‚YòxZ‰4h`MÑšâµå”4#†šXKï™:PÚ+~«•t;‰{÷ÞÛúO¶½³yõÕÞâFC ƒó;ýHÆ‚£¦>gyu¥²í 8ð!}Æ(ôœW—óÓô>Mü©£Íüô\.“ÛcÓa@c.F)Ëž~ Fä_™º²â†ã:i4â¯ìoò“}cã¥_w“_ìo“YŽ ·Ç##ý› Št½eRÒÿšÞ¡Ž±û¸keRåÊìú`)•°nè|öÍ6àÁy¤¶îúãe«¶˜ž6â×»Î:U³÷Yû¡L# R)Ô¾2—E ¥f_ØS½ÎR«Ù¹ûÞïýïþÆ_øëës_ùùNo9Ëe‹7}½ˆ­Èþr•isÌ«Ëhê@W•{âþyRLéQ:UÏ Ç¶iMK~8NÊâSÝ:ææ <æãQ賋aÀ®Ä\ž1tš$Z±ë:fÞ… &âÿu“ûî&]öÅk%B"N,Z˜8‰ÅDC$if3«bK ®gá=±øšY’bh€¥¡Á[×x”×óCUL|V•Ï"ϰ%  b‹¸çR—Õ¡Í_•d2Phšq˜ˆ5äw2Y_•c)f’ˆ_ùX°oZèëtʾcvûXr>žø[‚Ô3úœ§úYù #?fŸÉèD¸î4<¯í¶:Íf'ùÛeª‡Ç,†D ¤¨†ë:ÀiY"kV‘^•’ê$¡ÞÚ@S¢Ê 'ÏÁUbR†!h sjd®ñ÷  fJ 5á¹›ô‚gŸ¬ÏSñ2o€wÀlM…»Èo£Jµ*Û ¾臺6´@€J$wÍjÆRnës„„íK‘<Ùûà±”Z¨–špÈj×âÐi-4½6Ðþ³;ÿòÿøoÝùÓ/ÿ;¿°qåÕf«;­VjŒÒS™ í ‡o˜|¦©s%"㦓ŸòñLOŸjâÙß„_§QPÊ«äIÀ”†$¹N.ÊÙ&Ký!ûðÆCJì¯Ùm¶{­Î"ûÞˆ%—Ä<Íb„J>S3v¥÷¦ÆxÊëB5jˆÚo`¬ˆ­uSt b‹Mü Ùp||³ŽF©n#¤ÝêŠ .ãáñ7~ï×¶~ïGÿârë³?¾°¼›ŽeôxÅ»Šÿ M@9ùH§*9™òÓÔ×’8‰%ãÝi¦ŠÊdzô•Øñ’ðñ ­üSXX“!ûr^‰ýGíÅT°¿ì»Â$Axh¸ùs SWp>«Šbíð2’£šk €M@T|~0$¨ððÙ!-ëã¼ÖÇÝ窔ibÚg%ýR(Úêb; •²A Á6ýªà<ÓT*‰Ž äUh ðØCRí²·Ã!W΀9#q™‚Š/3 ä®zÁõŸ¯Ñd2€ÙÚ‘È*G}tçëû;wøÏü‡Ÿÿê¿wùÅ7\NN€/ QR9©Ý8åìü’9X¢)R~qóÌ—2½˜úÐiœ¼HÈ+ÿÁ-qapÈ>É/Çm¶Zí…D$,´:½iäÙkÅIlU<¼\™Ýëú\9ÈÏ Û:bqä³îM].K©¢aS[©¡)‹W§ÕcÓ' €ÞàdïþÕ?Úºÿí¯üÄ/ÜüÌõ–6 õxÓ§”„„F¹bžñúÄ?žsöfèE¹(j¡¡?²Oº­ÓhÅ–ÁR»»Ôì,ÆAf}šIüŠßå@L6Ê ld®XM  È´°jRT¾©½ å‘8šçįZƒ€È:?¡Åû·y¦"‹9âÿây*a›…4¤*²t LHƒCXÁÖž8”½D$ª<Ú"Ñø—Q±û4ØNsE$¹s'Iá —]:²M¶u¹9j@8Ñn{És›~ Iá ôÞ¿¿ýè]&>÷•Ÿß¼öz¬fI¶NRÜåÅf09 &ýЄÁ0 FQ8ŽÂ ü,Ýå‚õ_”Ú ƒÉdt:<Ýœì°/þ„ ¿I²Z"ˆgjÃÍø8”§ÕR»Û,È…nå°\…!5(ZŸ³#ll¹Ê1õ7àÆ8Ú*€kó>ÄØÔ"äóü%¹Åî1 f:šL}˜½Ù±h©ôÙhÜßÞ¿?Ñó’–ÀÞÿð÷vÖ–Ö½fW…q766ÈE¹(çWÒàÁxp48~6<=˜ ORa…¡“¬|„4züž!Xÿ}¯Gó_ƒŒc|Xûܬ«7áÇýª* H¶xa@,]]FIнÌ*Ú¬cÉÑ‹ A0ÒLÒ‚ÐßÚ½3šômØýgwßù:›GÝÅõno5ÎÙvŠÊ/ÀEyŽ “™0ˆÍ‚`Ì$Á8–Ž$ ¬Û* 7l3Rª´6@@ÞUÊä05 U]U@t2¢¼ƒ 8@¬c a‚–20 æ±¹ððÙ‡)?[SFƒÃÇw¿qz¼Ýî,õ7¼f;¯ÿB\”ç´„þx<<žìO†Çþdc†ñ*ƒ†§a¼[@P[ü—€a¼,,­”ÚiÙ®†‹bÔ»+—èš–°¡*_Õ¬{Üî@µP3L"*7ØèM^¨'’bk)VÍÂÑ’€LJ£á>Üþàtxh{÷´0Ej÷ɇ;[0ƒ{aå2“d‰ÿ…¸(Ïy¡lìÆ’àt2: ÆÃÀ³AœEŒù‚Ým$ึÝvp¬ÀV}|6P‚­[·æÄ è¨µ‚Áhi,Œ *1:È`?ÐÆÁÒÀèð2>ˆ‘D`!ÀÙÚ½{ÜßÇÇhÙ¬99|ºõà;l*µ»Ë‹+—®w!.ʧ¤PšØG£Ó2HÄ—Ä;Rà5Û]T:³õ` ÔZ]PVƒú§ƒÃ["µ‡4ô"ã~³ lŒŸX[ƒcól-DÚ9|txò¬ì^þx°ýè{;÷"®l¼t!.ʧ¬LƒÆýÃÉè4œŒ¢0ˆW»êJã’‡`Åu¸¬¬tö@1A0-€á ‚fÌ¿5¤S†”&‰g·»Ê˜Ðc¨ U»Ø;ÚÚ?ÚŠÊï€ÀfÐáÞƒ§Þö÷/ÀEù”–©A0žø£~àâÒÝ–cb%ƒ´ ° BA@ À¿¥šg®c„â«x™MÀÖÃ_8P‘x€¥}@Ò D”¥^fF]MûX A¨®ãþÞ³ÃGaœ6]¥ŒG'[÷¿]çn 墜q¡”úã>û N÷†'ûÝŵîÒf»»Î$Í>,`µ%VžÚ7)²¾ÞR˲¢´Ä‚WëiÚjñ/.ƒ-¥Ôñ]eÃÌþ|¥…»¥vò©a7!¨Únk¡Qé €¼„¡a\”ï‡ï[:Œ‡ÇLþ¸Á¬¯eVù­'3À^Tû Ƥ5H€Ã£wÎécá² Íýª)ÛàçdÃÖÎŽ¨ôU5×e‡ÔSäÌ‘Ž÷jµâ ¹ÖnöðF*X.,€‹òƒUh NöÂ`²¼ñÒâÊ•$2œé–¢óUU “«ü]Y6Š ½f/âÏ„âÏõ£¼ü±³ œ*N¯¦P¥ÅYÀFHY­ÍE½MšSƒ+‡)§ÞòtTmå¼±ì ªÐÔاÒJ‡”<°Ìp‚±Š­µ«€Nø’P/Pƒ±åîP¾®¹M·]X•Ê…pQ~ð Æƒãƒ§lß üYÖÑ”šyV½7»_¦V<ì¼öCëûsǬ”毃¤¶:f7êCÚóšÀE¹( üÑñÞÃ( W/ßôšäÚô–ðsy;‚:…¢’ L3HîZVaÁD² AjÉ‹’Û]>Á˜ˆÉɵm®ZÉ×.œSP­¥"*J’¾ˆ…¨Á‚'‹$þ2 „¼x q°Š\c¶ùø+ dŠ+ÍÑ„CB`Hƒ*5‹ÅÀlà¸(?¸%Š‚“ƒÇû[Mƽ#^ã·5^µzxk€ÕÚê/Ò°±ak±åj%›@S«-H`ë*| zHÃJ1M½øèì*´ÊË…pQ~  ÂþÑvàO6_ül³Ýƒ´qÂû`)¸W  ^ŠéB€ç™P>wVéøÄ‡–àª-‚œá"ºÖeVýåÏ f¸ÎŠ#¼½(´DT…^h—hxˆŠ=g€°%L*jQSÁ²Ô//¹ ’Èöƒd€ã(µŠƒMî^ —¨Ñ˜Uƒ¿°.Êz¡4õ÷Ÿ=ünàJ¤°àê®RA](P,5ü²¼ ¯³Î£x¥ÖÞ™wÓ½FkFÐÅJà‹rQâãÑéáâêÕä¤IÎïo_¸+ é›6H=†Ä!Ó qÛýgvË2c„´®MžñcyÕ/¶~Åc+¬tp´›+.­ HÂ÷Ÿ…4"2ÃÉÉ£gT8&/ÀE¹(Ó2oÝýFJÔXæŸ^£mWúi‰¯šæÔ$À˜(–VVê>DïX›[&H€_Í ^ÏC­üÿV…ª™PÍ6ÏIEND®B`‚simutrans-124.3/src/android/signBundle.sh000077500000000000000000000034311474050137200204140ustar00rootroot00000000000000#!/bin/sh # Set path to your Android keystore and your keystore alias here, or put them in your environment APPNAME=`grep AppName AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---'` APPVER=`grep AppVersionName AndroidAppSettings.cfg | sed 's/.*=//' | tr -d '"' | tr " '/" '---'` # Fix Gradle compilation error [ -z "$ANDROID_NDK_HOME" ] && export ANDROID_NDK_HOME="`which ndk-build | sed 's@/ndk-build@@'`" cd project ./gradlew bundleRelease || exit 1 ../copyAssets.sh pack-binaries-bundle app/build/outputs/bundle/release/app-release.aab cd app/build/outputs/bundle/release || exit 1 #[[ ! -z "$STORE_PASS" ]] && jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore /android-sdl/project/jni/application/simutrans/simutrans/src/android/Simutrans-upload.keystore --storepass $STORE_PASS app-release.aab $STORE_ALIAS wget https://github.com/google/bundletool/releases/download/1.8.2/bundletool-all-1.8.2.jar mv bundletool-all-1.8.2.jar bundletool.jar if [ -z "$STORE_PASS" ] then # no key defined java -jar bundletool.jar build-apks --bundle=app-release.aab --output=simutrans-multi.apks --mode=universal else java -jar bundletool.jar build-apks --bundle=app-release.aab --output=simutrans-multi.apks --mode=universal --ks=/android-sdl/project/jni/application/simutrans/simutrans/src/android/Simutrans-upload.keystore --ks-pass=pass:$STORE_PASS --ks-key-alias=$STORE_ALIAS fi unzip -p simutrans-multi.apks universal.apk > simuandroid-multi-nightly.apk mv app-release.aab simutrans-nightly.aab # prepare for Play Store upload to beta track cp simutrans-nightly.aab simutrans-nightly-r`cd /android-sdl/project/jni/application/simutrans/simutrans/;tools/get_revision.sh`.aab mkdir whatsNewDirectory echo `git log --pretty=format:'%s' -1` > whatsNewDirectory/whatsnew-en-US simutrans-124.3/src/android/unpak.sh000077500000000000000000000004731474050137200174430ustar00rootroot00000000000000#!/bin/sh URL=$1 pakzippath="${URL##http*\/}" rm -rf $pakzippath wget $URL unzip -l "$pakzippath" | grep "simutrans/" if [ $? -eq 1 ]; then # Not matched - We only have a simutrans/ directory unzip -qo "$pakzippath" else unzip -qo "$pakzippath" cp -RF simutrans/* . rm -rf simutrans fi rm -rf "$pakzippath" simutrans-124.3/src/base.tab000066400000000000000000002224271474050137200157550ustar00rootroot00000000000000# text group = 'message_text' # text group = 'button_text' # text group = 'climates_text' # text group = 'error_text' # text group = 'help_text' # text group = 'menu_text' # text group = 'program_text' # text group = 'record_text' # text group = 'ki_text' # text group = 'unnecessary_text' #obj= <-> text group #name= <-> object name #note= <-> description for object #- #obj=program_text #name=!0_STATION_CROWDED #- #obj=program_text #name=!1_DEPOT_REACHED #- obj=unnecessary_text name=%0_CITY_SYLL - obj=unnecessary_text name=%1_CITY_SYLL - obj=unnecessary_text name=%2_CITY_SYLL - obj=unnecessary_text name=%3_CITY_SYLL - obj=unnecessary_text name=%4_CITY_SYLL - obj=unnecessary_text name=%5_CITY_SYLL - obj=unnecessary_text name=%6_CITY_SYLL - obj=unnecessary_text name=%7_CITY_SYLL - obj=unnecessary_text name=%8_CITY_SYLL - obj=unnecessary_text name=%9_CITY_SYLL - obj=unnecessary_text name=%A_CITY_SYLL - obj=unnecessary_text name=%B_CITY_SYLL - obj=unnecessary_text name=%C_CITY_SYLL - obj=unnecessary_text name=%D_CITY_SYLL - obj=unnecessary_text name=%E_CITY_SYLL - obj=unnecessary_text name=%F_CITY_SYLL - obj=program_text name=%d buildings\n - obj=program_text name=%d convois - obj=program_text name=%d Einzelfahrzeuge im Depot - obj=program_text name=%i km/h (max. %ikm/h) - obj=program_text name=%s building %s %s - obj=program_text name=%s city %d %s - obj=program_text name=%s land %d %s - obj=program_text name=%s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants. - obj=program_text name=%s\nspeed %i\nmax_speed %i\ndx:%i dy:%i - obj=program_text name=%s\nwas liquidated. - obj=unnecessary_text name=&1_CITY_SYLL - obj=unnecessary_text name=&2_CITY_SYLL - obj=unnecessary_text name=&3_CITY_SYLL - obj=unnecessary_text name=&4_CITY_SYLL - obj=unnecessary_text name=&5_CITY_SYLL - obj=unnecessary_text name=&6_CITY_SYLL - obj=unnecessary_text name=&7_CITY_SYLL - obj=unnecessary_text name=&8_CITY_SYLL - obj=unnecessary_text name=&9_CITY_SYLL - obj=unnecessary_text name=&A_CITY_SYLL - obj=program_text name=(%i)- - obj=program_text name=(in depot) - obj=program_text name=1 Einzelfahrzeug im Depot - obj=unnecessary_text name=1center - obj=unnecessary_text name=1extern - obj=program_text name=1LIGHT_CHOOSE - obj=unnecessary_text name=1suburb - obj=unnecessary_text name=2center - obj=unnecessary_text name=2extern - obj=program_text name=2LIGHT_CHOOSE - obj=unnecessary_text name=2suburb - obj=program_text name=2WORLD_CHOOSE - obj=unnecessary_text name=3center - obj=unnecessary_text name=3extern - obj=program_text name=3LIGHT_CHOOSE - obj=unnecessary_text name=3suburb - #obj=program_text #name=3WORLD_CHOOSE #- obj=unnecessary_text name=4center - obj=unnecessary_text name=4extern - obj=program_text name=4LIGHT_CHOOSE - obj=unnecessary_text name=4suburb - obj=unnecessary_text name=5center - obj=unnecessary_text name=5extern - obj=program_text name=5LIGHT_CHOOSE - obj=unnecessary_text name=5suburb - obj=program_text name=5WORLD_CHOOSE - obj=unnecessary_text name=6center - obj=unnecessary_text name=6extern - obj=program_text name=6LIGHT_CHOOSE - obj=program_text name=6WORLD_CHOOSE - obj=unnecessary_text name=7center - obj=unnecessary_text name=8center - obj=program_text name=8WORLD_CHOOSE - obj=unnecessary_text name=9center - obj=program_text name=%C - %s
\n - obj=program_text name= - obj=help_text name=Keyboard Help\n

Keyboard Help

\n - #obj=program_text #name=A bridge must end on a way! #- #obj=program_text #name=A bridge must start on a way! - obj=program_text name=Abfrage - obj=program_text name=Abnehmer - obj=program_text name=About - obj=program_text name=Abriss - obj=program_text name=Absenken - obj=program_text name=Accelerate time - obj=program_text name=Add Stop - obj=program_text name=Add stops for backward travel - obj=program_text name=aircraft_tab - obj=program_text name=airplane - obj=program_text name=air note=waytype for run/taxiways - obj=program_text name=Airport - obj=program_text name=AIRTOOLS - obj=program_text name=All - obj=program_text name=Allow player change - obj=program_text name=allowed climates:\n - obj=program_text name=Alters a schedule. - obj=program_text name=Angenommene Waren - obj=program_text name=anhaengen - obj=program_text name=Anhaenger_tab - obj=program_text name=Anheben - obsolete=program_text name=Appends stops at the end of the schedule - obj=program_text name=Apply Line - obj=program_text name=April - obj=program_text name=Arbeiter aus: - obj=climates_text name=arctic - obj=program_text name=Arrived - obj=program_text name=Assets - obj=program_text name=August - obj=program_text name=Autohalt muss auf\nStrasse liegen!\n - obj=program_text name=Available - obj=program_text name=Bahndepot - obj=program_text name=Bankrott:\n\nDu bist bankrott.\n - obj=program_text name=battery - obj=program_text name=Baum - obj=program_text name=baum builder - obj=program_text name=Baustelle - obj=program_text name=Bauzeit - obj=program_text name=Beenden - obj=program_text name=Beginner mode - obj=program_text name=Besonderes Gebaeude - obj=program_text name=BF - obj=program_text name=bio - obj=program_text name=Blockstrecke ist\nbelegt\n - obj=program_text name=Boden - obj=program_text name=bridge is too high for its type! - obj=program_text name=Bridge is too long for this type!\n - obj=program_text name=Bruecke - obj=program_text name=Bruecke muss an\neinfachem\nHang beginnen!\n - obj=program_text name=Brueckenboden - obj=program_text name=build choosesignals - obj=program_text name=Build city market - obj=program_text name=Build drain - obj=program_text name=build HQ note=finance window - obj=program_text name=Build land consumer - obj=program_text name=Build monorail depot - obj=program_text name=Build powerline - obj=program_text name=Build presignals - obj=program_text name=Build road depot - obj=program_text name=Build ship depot - obj=program_text name=Build signals - obj=program_text name=Build train depot - obj=program_text name=Build tram depot - obj=program_text name=Build truck depot - obj=program_text name=Building costs estimates - obj=program_text name=Buildings - obj=program_text name=Built artifical slopes - obj=program_text name=Built random attraction - obj=program_text name=Bus_tab - obj=program_text name=Can only move from halt to halt or waypoint to waypoint. - obj=program_text name=Cancel - obj=program_text name=Capacity: %s\nLoad: %d (%d%%) - obj=program_text name=Cars are not available yet! - obj=program_text name=Cash - obj=program_text name=Change player - obj=program_text name=Chart - obj=program_text name=Choose operation executed on clicking stored/new vehicles - obj=program_text name=chooses a random map - obj=program_text name=citicens - obj=program_text name=Cities can only be built on flat empty ground! note=Error message when building city manually - obj=program_text name=City attraction - obj=program_text name=City industries - obj=program_text name=City list - obj=program_text name=City size - obj=program_text name=citybuilding builder - obj=program_text name=CityLimit - obj=program_text name=city_road - obj=program_text name=Clear block reservation - obj=button_text name=clf_btn_alle - obj=button_text name=clf_btn_invers - obj=button_text name=clf_btn_keine - obj=program_text name=clf_chk_indepot - obj=program_text name=clf_chk_noincome - obj=program_text name=clf_chk_noline - obj=program_text name=clf_chk_noroute - obj=program_text name=clf_chk_noschedule - obj=program_text name=clf_chk_spezial_filter - obj=program_text name=clf_chk_stucked - - obj=program_text name=clf_chk_type_filter - obj=program_text name=clf_chk_waren - obj=program_text name=clf_title - obj=program_text name=Climate Control - obj=button_text name=cl_btn_filter_settings - obsolete=button_text name=cl_btn_sort_asc - obsolete=button_text name=cl_btn_sort_desc - obj=button_text name=cl_btn_sort_id - obj=button_text name=cl_btn_sort_income - obj=button_text name=cl_btn_sort_name - obj=button_text name=cl_btn_sort_type - obj=program_text name=cl_title - obj=program_text name=Filter: - obj=program_text name=cl_txt_sort - obj=program_text name=COLOR_CHOOSE\n - obj=program_text name=Company bankrupt - obj=program_text name=Congratulation\nScenario was complete in\n%i months %i years. - obj=program_text name=Connected stops - obj=program_text name=Constructed by - obj=program_text name=Constructed by %s - obj=program_text name=Construction_Btn - obj=program_text name=convoi %d of %d - obj=program_text name=Convoi has been sent\nto the nearest depot\nof appropriate type.\n - obj=program_text name=Convoi is sold when all wagons are empty. - obj=program_text name=convoi passed last\nmonth %i\n - obj=program_text name=Convois - obj=program_text name=Convois: %d\nProfit: %s - obj=program_text name=Convoys - obj=program_text name=Copy Convoi - obj=program_text name=Copy the selected convoi and its schedule or line - obj=program_text name=cost for removal - obj=program_text name=Create a new line based on this schedule - obj=program_text name=curiosity builder - obj=program_text name=curlist_title - obj=program_text name=Currently playing: - obj=error_text name=Das Feld gehoert\neinem anderen Spieler\n - obj=program_text name=Deccelerate time - obj=program_text name=December - obsolete=program_text name=Del Stop - obj=program_text name=Delete Line - obj=program_text name=Delete the current stop - obj=program_text name=Delete this file. - obj=program_text name=Denkmal - obj=program_text name=Departed - obj=program_text name=Depots - obj=error_text name=Depots must be built on flat dead-end way tiles! note=Error text when building depot fails - obj=error_text name=Depots cannot be built on runways! note=Error text when building depot fails - obj=error_text name=Ship depots must be built on water! note=Error text when building depot fails - obj=program_text name=Depot - obj=error_text name=Der Besitzer erlaubt das Entfernen nicht - obj=program_text name=Der Tunnel ist nicht frei!\n - obj=climates_text name=desert - obj=program_text name=Destination - obj=program_text name=Details - obj=error_text name=Diese Zusammenstellung kann nicht fahren!\n - obj=program_text name=diesel - obj=program_text name=Direkt erreichbare Haltestellen - obj=program_text name=Dock - obj=program_text name=Dock must be built on single slope! - obj=program_text name=Du hast %d Monate Zeit, deine Schulden zurueckzuzahlen - obj=program_text name=Durchsatz - obj=menu_text name=EDITTOOLS - obj=program_text name=Eigenbesitz\n - obj=program_text name=Ein %s\npasst hier nicht.\n - obj=program_text name=Einstellungen - obj=program_text name=Einstellungen aendern - obj=program_text name=electric - obj=program_text name=Electricity - obj=program_text name=Electricity producer\n\n - obj=program_text name=Electrify track - obj=program_text name=Error - obj=program_text name=Erzeuge neue Karte.\n - obj=program_text name=Es wird bereits\nein Fahrplan\neingegeben\n - obj=program_text name=Fabrikanschluss - obj=program_text name=Fabrikname - obj=program_text name=Factories - obj=message_text name=Factory chain extended\nfor %s near\n%s built with\n%i factories. - obj=program_text name=factory details - obj=program_text name=factorybuilder - obj=program_text name=Fahrplan - obj=program_text name=Fahrtziel - obj=program_text name=Fahrzeuge koennen so nicht entfernt werden - obj=program_text name=Fahrzeuge: - obj=program_text name=Farbe - obj=program_text name=Fast forward - obj=program_text name=February - obj=program_text name=Ferry_tab - obj=program_text name=Fertig - obj=program_text name=Filename - obj=program_text name=Finances of %s - obj=program_text name=Finanzen - obj=error_text name=Flugzeughalt muss auf\nRunway liegen!\n - obj=program_text name=Flug_tab - obj=program_text name=fl_title - obj=program_text name=follow me - obj=program_text name=Follow the convoi on the map. - obj=program_text name=Forest - obj=program_text name=Found new city - obj=program_text name=FPS: - obj=program_text name=Fracht - obj=program_text name=Frame time: - obj=program_text name=Free Capacity - obj=program_text name=Friction: - obj=program_text name=fuel_cell - obj=program_text name=Full load - obj=program_text name=Fussgaenger - obj=program_text name=GAME PAUSED - obj=program_text name=Gear: - obj=program_text name=Gebaeude - obj=program_text name=Gewicht - obj=program_text name=Gewinn - obj=program_text name=Give the selected vehicle(s) an individual schedule - obj=button_text name=gl_btn_sort_bonus - obj=button_text name=gl_btn_sort_name - obj=button_text name=gl_btn_sort_revenue - obj=button_text name=gl_btn_unsort - obj=program_text name=gl_title - obj=program_text name=go home - obj=program_text name=Goods - obj=program_text name=Goods list - obj=program_text name=Gross Profit - obj=program_text name=Groundobj - obj=program_text name=Grow city - obj=program_text name=Growth - obj=program_text name=H - obj=program_text name=Hangar - obj=program_text name=Happy - obj=program_text name=Display settings - obj=program_text name=Help - obj=program_text name=Help text not found - obj=program_text name=hide all building - obj=program_text name=hide city building - obj=program_text name=hide station names - obj=program_text name=hide transparent - obj=program_text name=hide trees - obj=error_text name=Hier kann dieses\nFlughafengebaeude nicht\ngebaut werden!\n - obj=error_text name=Hier kann kein\nSignal aufge-\nstellt werden!\n - obj=program_text name=Hier warten/lagern: - obj=button_text name=hlf_btn_alle - obj=button_text name=hlf_btn_invers - obj=button_text name=hlf_btn_keine - obj=program_text name=hlf_chk_airport - obj=program_text name=hlf_chk_anleger - obj=program_text name=hlf_chk_bahnhof - obj=program_text name=hlf_chk_bushalt - obj=program_text name=hlf_chk_frachthof - obj=program_text name=hlf_chk_keine_verb - obj=program_text name=hlf_chk_name_filter - obj=program_text name=hlf_chk_overflow - obj=program_text name=hlf_chk_spezial_filter - obj=program_text name=hlf_chk_type_filter - obj=program_text name=hlf_chk_waren_abgabe - obj=program_text name=hlf_chk_waren_annahme - obj=program_text name=hlf_title - obj=button_text name=hl_btn_filter_disable - obj=button_text name=hl_btn_filter_enable - obj=button_text name=hl_btn_filter_settings - obj=button_text name=hl_btn_sort_asc - obj=button_text name=hl_btn_sort_desc - obj=button_text name=hl_btn_sort_name - obj=button_text name=hl_btn_sort_type - obj=button_text name=hl_btn_sort_waiting - obj=program_text name=hl_title - obj=program_text name=hl_txt_filter - obj=program_text name=hl_txt_sort - obj=program_text name=Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually. - obj=program_text name=Homeless - obj=program_text name=hydrogene - obj=program_text name=Idle: - obj=program_text name=ignore climates - obj=program_text name=Increase Industry density - obj=program_text name=industrial building - obj=program_text name=Init map ... - obj=program_text name=Input - obj=program_text name=Ins Stop - obsolete=program_text name=Insert stop before the current stop - obj=program_text name=Intercity road len: - obj=program_text name=Intro. date: - obj=program_text name=Invalid coordinate - obj=program_text name=isometric map - obj=program_text name=January - obj=program_text name=July - obj=program_text name=Jump to - obj=program_text name=June - obj=program_text name=Kann Spielstand\nnicht laden.\n - obj=program_text name=Kann Spielstand\nnicht speichern.\n - obj=program_text name=keine - obj=program_text name=Keine Einzelfahrzeuge im Depot - obj=program_text name=Keyboard_Help\n - obj=program_text name=Kreuzung - obj=program_text name=Lade Relief - obj=program_text name=Laden - obj=program_text name=Land attraction - - obj=program_text name=LANG_CHOOSE\n - obj=program_text name=Last Year - obj=program_text name=leer - obj=program_text name=Legend - obj=program_text name=Leistung - obj=program_text name=Leistung: %d kW - obj=program_text name=Leitung - obj=program_text name=letzen Monat: diesen Monat: - obj=program_text name=Line - obj=program_text name=Line Management - obj=program_text name=Lines serving this stop - obj=menu_text name=LISTTOOLS - obj=program_text name=LKW_tab - obj=program_text name=Load game - obj=program_text name=load height data from file - obj=program_text name=Load scenario - obj=program_text name=loaded - obj=program_text name=loaded passenger/freight - obj=program_text name=Loading map ... - obj=program_text name=Lock game - obj=program_text name=Lokomotive_tab - obj=program_text name=m3 - obj=error_text name=Maglevhalt muss auf\nMaglevschiene liegen!\n - obj=program_text name=Mailbox - obj=program_text name=Mailbox Options - obj=program_text name=Maintenance - obj=program_text name=Manufactured: - obj=program_text name=Map roughness - obj=program_text name=map zoom - obj=program_text name=March - obj=program_text name=Margin (%%) - obj=program_text name=Marker - obj=program_text name=max - obj=program_text name=Max income: - obj=program_text name=Max. speed: - obj=program_text name=Maximum 254 stops\nin a schedule!\n - obj=program_text name=Maximum tile height difference reached. - obj=program_text name=May - obj=program_text name=Median Citizen per town - obj=climates_text name=mediterran - obj=program_text name=Meldung - obj=program_text name=Menge - obj=program_text name=MessageOptionsText - obj=program_text name=min - obj=program_text name=Modify the selected line - obj=program_text name=Monorail - obj=program_text name=monorail vehicle - obj=program_text name=Monorailboden - obj=program_text name=Monoraildepot - obj=error_text name=Monorailhalt muss auf\nMonorail liegen!\n - obj=error_text name=Monorails are not available yet! - obj=menu_text name=MONORAILTOOLS - obsolete=program_text name=month wait time - obj=program_text name=Months - obj=program_text name=Monument - obj=program_text name=Monuments - obj=program_text name=Mountain height - obj=program_text name=Movingobj - obj=program_text name=Music playing disabled/not available - obj=program_text name=Music volume: - obj=program_text name=mute sound - obj=program_text name=Name - obj=program_text name=Net Wealth - obj=program_text name=Neue Karte - obj=program_text name=Neue Welt - obj=message_text name=New %s now available:\n%s\n - obj=program_text name=new convoi - obj=message_text name=New factory chain\nfor %s near\n%s built with\n%i factories. - obj=program_text name=New Line - obj=program_text name=New line created!\nYou can assign the line now\nby selecting it from the\nline selector above. - obj=message_text name=New vehicle now available:\n%s\n - obj=program_text name=New Vehicles - obj=record_text name=New world record for monorails: %.1f km/h by %s. - obj=record_text name=New world record for motorcars: %.1f km/h by %s. - obj=record_text name=New world record for planes: %.1f km/h by %s. - obj=record_text name=New world record for railways: %.1f km/h by %s. - obj=record_text name=New world record for ship: %.1f km/h by %s. - obj=record_text name=New world record for narrowgauges: %.1f km/h by %s. - obj=record_text name=New world record for maglevs: %.1f km/h by %s. - obj=program_text name=no convois - obj=program_text name=No goods are loaded onto this convoi. - obj=program_text name=no goods waiting - obj=program_text name=no load - obj=program_text name=No Route - obj=program_text name=No suitable ground! - obj=program_text name=No suitable townhall available for this climate! note=Error message when building city manually - obj=program_text name=No terminal station here! - obj=error_text name=No through station here! - obj=program_text name=no timeline - obj=program_text name=no tree - obj=program_text name=Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n - obj=program_text name=none - obj=program_text name=nord - obj=program_text name=nordost - obj=program_text name=nordwest - obj=program_text name=Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later! - obj=program_text name=Not enough fields would remain. - obj=program_text name=November - obj=program_text name=Now active as %s.\n - obj=program_text name=Object - obj=program_text name=Ok - obj=program_text name=Oktober - obj=program_text name=On loan since %i month(s) - obj=error_text name=On narrowgauge track only!\n - obj=program_text name=On this map, you are not\nallowed to change player!\n - obj=program_text name=Only city chains - obj=program_text name=Only land chains - obj=program_text name=Operation - obj=program_text name=Ops Profit - obj=program_text name=Optionen - obj=program_text name=Origin - obj=program_text name=ost - obj=program_text name=Output - obj=program_text name=paletten - obj=program_text name=Passagiere - obj=program_text name=Passagierrate - obj=program_text name=Passengers %d %c, %d %c, %d no route - obj=program_text name=Pas_tab - obj=program_text name=Pause - obj=program_text name=Percent Electricity - obj=program_text name=Planes are not available yet! - obj=program_text name=Plant tree - obj=program_text name=player -1 - obj=program_text name=player 0 - obj=program_text name=player 1 - obj=program_text name=player 2 - obj=program_text name=player 3 - obj=program_text name=player 4 - obj=program_text name=player 5 - obj=program_text name=player 6 - obj=program_text name=player 7 - obj=program_text name=player 8 - obj=program_text name=player 9 - obj=program_text name=player 10 - obj=program_text name=player 11 - obj=program_text name=player 12 - obj=program_text name=player 13 - obj=program_text name=Please choose vehicles first\n - obj=program_text name=Post - obj=error_text name=Post muss neben\nHaltestelle\nliegen!\n - obj=program_text name=Postrate - obj=program_text name=Power - obj=program_text name=Power: - obj=program_text name=Powerlines - obj=program_text name=Produktion - obj=program_text name=Profit - obj=program_text name=promote to line - obj=program_text name=q1 - obj=program_text name=q2 - obj=program_text name=q3 - obj=program_text name=q4 - obj=program_text name=rail car - obj=menu_text name=RAILTOOLS - obj=program_text name=random - obj=program_text name=Random age - obj=program_text name=Random map - obj=program_text name=Rathaus - obj=program_text name=Rating - obj=program_text name=ratio_pax - obj=program_text name=Reliefkarte - obj=program_text name=remove airstrips - obj=program_text name=remove channels - obj=program_text name=remove monorails - obj=program_text name=remove roads - obj=program_text name=remove tracks - obj=program_text name=remove powerlines - obj=message_text name=Remove vehicle from map. Use with care! - obj=program_text name=replace stop - obj=program_text name=residential house - obj=program_text name=Restore natural slope - obj=program_text name=Restwert: - obj=program_text name=Retire. date: - obj=program_text name=return ticket - obj=program_text name=Revenue - obj=program_text name=road vehicle - obj=program_text name=Roadsign - obj=menu_text name=ROADTOOLS - obj=climates_text name=rocky - obj=program_text name=Rotate map - obj=program_text name=Rotation - obj=program_text name=sack - obj=program_text name=sail - obj=program_text name=Saving map ... - obj=program_text name=Scenario complete: %i%% - obj=program_text name=Schienentunnel - obj=program_text name=Schiffdepot - obj=error_text name=Schiffhalt muss im\nWasser liegen!\n - obj=program_text name=Schiff_tab - obj=program_text name=Schleppkahn_tab - obj=program_text name=Screenshot - obj=message_text name=Screenshot\ngespeichert.\n - obj=program_text name=Sehenswuerdigkeit - obj=program_text name=Sell the selected vehicle(s) - obj=program_text name=sended - obj=message_text name=Sends the convoi to the last depot it departed from! - obj=program_text name=September - obj=program_text name=SEP_FRACTION - obj=program_text name=SEP_THOUSAND - obj=program_text name=Serves Line: - obj=program_text name=Service - obj=program_text name=Ship - obj=menu_text name=SHIPTOOLS - obj=program_text name=shops and stores - obj=program_text name=Show all - obj=program_text name=show all building - obj=program_text name=Show also vehicles no longer in production. - obj=program_text name=Show also vehicles that do not match for current action. - obj=program_text name=show grid - obj=program_text name=show HQ note=finance window - obj=program_text name=Show industry - obj=program_text name=Show legend - obj=program_text name=Show map scale - obj=program_text name=Show obsolete - obj=program_text name=Show schedules - obj=program_text name=show station coverage - obj=program_text name=show waiting bars - obj=program_text name=Show/hide statistics - obj=program_text name=Shows consumer/suppliers for factories - obj=program_text name=Shows the currently selected schedule - obj=program_text name=Shrink city - obj=program_text name=shuffle midis - obj=program_text name=Sim: - obj=menu_text name=SLOPETOOLS - obj=program_text name=Sort by - obj=program_text name=Sort waiting list by - obj=program_text name=Sound - obj=program_text name=Sound settings - obj=program_text name=Sound volume: - obj=program_text name=special freight - obj=menu_text name=SPECIALTOOLS - obj=program_text name=Speedlimit - obj=program_text name=Save note=button and window title - obj=program_text name=Spieler - obj=program_text name=Spieler(mz) - obj=program_text name=Spielerliste - obj=program_text name=Spielstand wurde\ngeladen!\n - obj=program_text name=Spielstand wurde\ngespeichert!\n - obj=program_text name=Sprache - obj=program_text name=Sprachen - obj=program_text name=Stadtinformation - obj=program_text name=Start - obj=program_text name=Start the selected vehicle(s) - obj=program_text name=Starte Spiel - obj=program_text name=Station tiles: - obj=program_text name=Status - obj=program_text name=steam - obj=program_text name=Step timeline one year - obj=program_text name=Storage capacity - obj=program_text name=Strassendepot - obj=program_text name=Strassentunnel - obj=program_text name=street car - obj=program_text name=sued - obj=program_text name=suedost - obj=program_text name=suedwest - obj=program_text name=Summer snowline - obj=program_text name=Suppliers - obj=program_text name=Tage alt - obj=climates_text name=temperate - obj=program_text name=There are still vehicles\nstored in this depot!\n - obj=program_text name=This Month - obj=program_text name=This Year - obj=program_text name=Tile not empty. - obj=program_text name=timeline - obj=program_text name=tl_title - obj=program_text name=To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers. - obj=program_text name=To heavy traffic\nresults in traffic jam.\n - obj=program_text name=tonnen - obj=program_text name=Total inhabitants: - obj=program_text name=Tourist attractions - obj=program_text name=Tourists - obj=program_text name=Town: %s\n - obj=program_text name=Towns - obj=program_text name=Tracks - obj=program_text name=Traffic - obj=program_text name=Train - obj=program_text name=Trains are not available yet! - obj=program_text name=Tram - obj=program_text name=Tramdepot - obj=program_text name=Trams are not available yet! - obj=menu_text name=TRAMTOOLS - obj=program_text name=Transformer only next to factory! - obj=program_text name=Translation - obj=program_text name=transparent station coverage - obj=program_text name=Transported - obj=climates_text name=tropic - obj=program_text name=Truck - obj=climates_text name=tundra - obj=program_text name=Tunnel muss an\neinfachem\nHang beginnen!\n - obj=program_text name=Tunnel must start on single way! - obj=program_text name=Tunnelboden - obj=program_text name=underground mode - obj=program_text name=UNDO failed! - obj=program_text name=Undo last ways construction - obj=program_text name=Unemployed - obj=program_text name=Unhappy - obj=program_text name=units/day - obj=program_text name=Update Line - obj=program_text name=upgrade HQ note=HQ info window - obj=program_text name=Use timeline start year - obj=program_text name=Verbrauch - obj=program_text note=button in convoi dialogue to remove a convoi completely name=Verkauf - obj=program_text name=verkaufen - obj=program_text name=Verkehrsteilnehmer - obj=program_text name=Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n - obj=program_text name=via - obj=program_text name=via %s\n - obj=program_text name=via Menge - obj=program_text name=voranstellen - obj=program_text name=Waggon_tab - obj=program_text name=waiting - obj=program_text name=Water level - obj=program_text name=water vehicle - obj=program_text name=way %s cannot longer used:\n - obj=program_text name=way %s cannot longer used:\n%s\n - obj=program_text name=way %s now available:\n - obj=program_text name=Ways not connected - obj=program_text name=Wegpunkt - obj=program_text name=Wert - obj=program_text name=west - obj=program_text name=Winter snowline - obj=message_text name=With a big festival\n%s built\na new monument.\n%i citicens rejoiced. - obj=program_text name=withdraw - obj=program_text name=WRONGSAVE - obj=program_text name=Year %i has started. - obj=program_text name=Years - obj=program_text name=Zielort - obj=program_text name=zooming in - obj=program_text name=zooming out - obj=program_text name=Zu nah am Kartenrand - obj=error_text name=Zughalt muss auf\nSchiene liegen!\n - obj=program_text name=\nBauzeit bis - obj=program_text name=\nBauzeit von - obj=program_text name=\nCan't open heightfield file.\n - obj=program_text name=\ndirection: - obj=program_text name=\nelektrified - obj=program_text name=\nHeightfield has wrong image type.\n - obj=program_text name=\nis reserved by: - obj=program_text name=\nminimum speed: - obj=program_text name=\nnot elektrified - obj=program_text name=\nRibi (masked) - obj=program_text name=\nsingle way - obj=program_text name=\nwith sign/signal\n - obj=program_text name=Passagierziele - obj=program_text name=Production of %s has been stopped:\n%s\n - obj=unnecessary_text name=6suburb - obj=unnecessary_text name=7extern - obj=unnecessary_text name=7suburb - obj=unnecessary_text name=8extern - obj=unnecessary_text name=8suburb - obj=unnecessary_text name=9extern - obj=ki_text name=%s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n - obj=ki_text name=%s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n - obj=ki_text name=%s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i). - obj=ki_text name=%s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i). - obj=ki_text name=Airline service by\n%s\nnow between\n%s \nand %s.\n -- obj=program_text name=Add forest -- obj=program_text name=Build narrowgauge depot - obj=menu_text name=NARROWGAUGETOOLS - obj=program_text name=remove narrowgauge tracks - obj=program_text name=Narrowgauge - obj=program_text name=narrowgauge vehicle - obj=program_text name=Narrowgaugedepot - obj=error_text name=Narrowgaugehalt muss auf\nNarrowgauge liegen!\n - obj=program_text name=Narrowgauge are not available yet! - obj=program_text name=Speedbonus\nroad %i km/h, rail %i km/h\nships %i km/h, planes %i km/h. - obj=program_text name=tram %i km/h, monorail %i km/h\nmaglev %i km/h, narrowgauge %i km/h. - obj=program_text name=\nRibi (unmasked) - obj=program_text name=\nway1 reserved by - obj=program_text name=\nway2 reserved by - obj=message_text name=%s s\nheadquarter now\nat (%i,%i). - obj=program_text name=Build air depot - obj=program_text name=Build maglev depot - obj=program_text name=cars.\nstate - obj=program_text name=clf_chk_monorail - obj=program_text name=clf_chk_narrowgauge - obj=program_text name=closed - obj=program_text name=disable midi - obj=program_text name=Electrics_tab - obj=program_text name=enlarge map - obj=program_text name=enter a value between %i and %i - obj=ki_text name=Ferry service by\n%s\nnow between\n%s \nand %s.\n - obj=program_text name=freeplay mode - obj=program_text name=Goods AI - obj=program_text name=hlf_chk_maglevstop - obj=program_text name=hlf_chk_monorailstop - obj=program_text name=hlf_chk_narrowgaugestop - obj=program_text name=hlf_chk_tramstop - obj=program_text name=invalid - obj=program_text name=LARGE_NUMBER_STRING - obj=program_text name=LARGE_NUMBER_VALUE - obj=program_text name=Make way or stop public (will join with neighbours), %i times maintainance - obj=program_text name=Manual (Human) - obj=program_text name=No stop here! - obj=program_text name=open - obj=program_text name=Passenger AI - obj=program_text name=Remove - obj=program_text name=remove maglev tracks - obj=program_text name=request closing - obj=program_text name=slot empty - obj=program_text name=Toggle day/night view - obj=ki_text name=Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n - obj=program_text name=TrolleyBus_tab - obj=program_text name=Vergroessere die Karte\n - obj=program_text name=clf_chk_maglev -- obj=unnecessary_text name=&0_CITY_SYLL -- obj=unnecessary_text name=&B_CITY_SYLL -- obj=unnecessary_text name=&C_CITY_SYLL -- obj=unnecessary_text name=&D_CITY_SYLL -- obj=unnecessary_text name=&E_CITY_SYLL -- obj=unnecessary_text name=&F_CITY_SYLL -- obj=unnecessary_text name=%G_CITY_SYLL - obj=unnecessary_text name=%H_CITY_SYLL - obj=unnecessary_text name=%I_CITY_SYLL - obj=unnecessary_text name=%J_CITY_SYLL - obj=unnecessary_text name=%K_CITY_SYLL - obj=unnecessary_text name=%L_CITY_SYLL - obj=unnecessary_text name=%M_CITY_SYLL - obj=unnecessary_text name=%N_CITY_SYLL - obj=unnecessary_text name=%O_CITY_SYLL - obj=unnecessary_text name=%P_CITY_SYLL - obj=unnecessary_text name=%Q_CITY_SYLL - obj=unnecessary_text name=%R_CITY_SYLL - obj=unnecessary_text name=%S_CITY_SYLL - obj=unnecessary_text name=%T_CITY_SYLL - obj=unnecessary_text name=%U_CITY_SYLL - obj=unnecessary_text name=%V_CITY_SYLL - obj=unnecessary_text name=%W_CITY_SYLL - obj=unnecessary_text name=%X_CITY_SYLL - obj=unnecessary_text name=%Y_CITY_SYLL - obj=unnecessary_text name=%Z_CITY_SYLL - obj=unnecessary_text name=&G_CITY_SYLL - obj=unnecessary_text name=&H_CITY_SYLL - obj=unnecessary_text name=&I_CITY_SYLL - obj=unnecessary_text name=&J_CITY_SYLL - obj=unnecessary_text name=&K_CITY_SYLL - obj=unnecessary_text name=&L_CITY_SYLL - obj=unnecessary_text name=&M_CITY_SYLL - obj=unnecessary_text name=&N_CITY_SYLL - obj=unnecessary_text name=&O_CITY_SYLL - obj=unnecessary_text name=&P_CITY_SYLL - obj=unnecessary_text name=&Q_CITY_SYLL - obj=unnecessary_text name=&R_CITY_SYLL - obj=unnecessary_text name=&S_CITY_SYLL - obj=unnecessary_text name=&T_CITY_SYLL - obj=unnecessary_text name=&U_CITY_SYLL - obj=unnecessary_text name=&V_CITY_SYLL - obj=unnecessary_text name=&W_CITY_SYLL - obj=unnecessary_text name=&X_CITY_SYLL - obj=unnecessary_text name=&Y_CITY_SYLL - obj=unnecessary_text name=&Z_CITY_SYLL - obj=unnecessary_text name=0center -- obj=unnecessary_text name=0extern -- obj=unnecessary_text name=0suburb -- obj=program_text name=Die Bruecke ist nicht frei!\n -- obj=program_text name=Maglev -- obj=program_text name=Maglevdepot -- obj=program_text name=Number of rivers -- obj=program_text name=minimum length of rivers -- obj=program_text name=maximum length of rivers -- obj=program_text name=maglev vehicle -- obj=program_text name=labellist_title -- obj=program_text name=Active player only -- obj=program_text name=koord note=sort option in halt and depot list -- obj=program_text name=gl_btn_sort_catg note=sort option for goods_list window -- obj=program_text name=Leaving depot! -- obj=program_text name=Schedule changing! -- obj=program_text name=Waiting for clearance! -- obj=program_text name=Withdraw All -- obj=program_text name=sliced underground mode -- obj=program_text name=increase underground view level -- obj=program_text name=decrease underground view level -- obj=error_text name=Cannot built this station/building\nin underground mode here. -- obj=error_text name=Terraforming not possible\nhere in underground view -- obj=program_text name=Remove wayobj %s - obj=program_text name=[HOME] - obj=program_text name=[END] - obj=program_text name=[CTRL] - obj=program_text name=[SHIFT] - obj=program_text name=[ESC] - obj=program_text name=[DELETE] - obj=program_text name=[SCROLLLOCK] - obj=error_text name=Upgrade must have\na higher level - obj=error_text name=Not enough money! - obj=program_text name=Allow city growth - obj=program_text name=Setting - obj=program_text name=General - obj=program_text name=Economy - obj=program_text name=Routing - obj=program_text name=Costs - obj=error_text name=Cannot create socket - obj=error_text name=Protocoll error (expecting game) - obj=program_text name=Distance - obj=program_text name=Odometer: %s km - obj=error_text name=Lost synchronisation\nwith server. - obj=error_text name=Lost connection\nto server! - obj=program_text name=\nSet phases: - obj=program_text name=%s factory %s %s - obj=unnecessary_text name=Asuburb - obj=unnecessary_text name=Bsuburb - obj=unnecessary_text name=Csuburb - obj=unnecessary_text name=Dsuburb - obj=unnecessary_text name=Esuburb - obj=unnecessary_text name=Fsuburb - obj=unnecessary_text name=Gsuburb - obj=unnecessary_text name=Hsuburb - obj=unnecessary_text name=Isuburb - obj=unnecessary_text name=Jsuburb - obj=unnecessary_text name=Ksuburb - obj=unnecessary_text name=Lsuburb - obj=unnecessary_text name=Msuburb - obj=unnecessary_text name=Nsuburb - obj=unnecessary_text name=Osuburb - obj=unnecessary_text name=Psuburb - obj=unnecessary_text name=Qsuburb - obj=unnecessary_text name=Rsuburb - obj=unnecessary_text name=Ssuburb - obj=unnecessary_text name=Tsuburb - obj=unnecessary_text name=Usuburb - obj=unnecessary_text name=Vsuburb - obj=unnecessary_text name=Wsuburb - obj=unnecessary_text name=Xsuburb - obj=unnecessary_text name=Ysuburb - obj=unnecessary_text name=Zsuburb - obj=unnecessary_text name=Acenter - obj=unnecessary_text name=Bcenter - obj=unnecessary_text name=Ccenter - obj=unnecessary_text name=Dcenter - obj=unnecessary_text name=Ecenter - obj=unnecessary_text name=Fcenter - obj=unnecessary_text name=Gcenter - obj=unnecessary_text name=Hcenter - obj=unnecessary_text name=Icenter - obj=unnecessary_text name=Jcenter - obj=unnecessary_text name=Kcenter - obj=unnecessary_text name=Lcenter - obj=unnecessary_text name=Mcenter - obj=unnecessary_text name=Ncenter - obj=unnecessary_text name=Ocenter - obj=unnecessary_text name=Pcenter - obj=unnecessary_text name=Qcenter - obj=unnecessary_text name=Rcenter - obj=unnecessary_text name=Scenter - obj=unnecessary_text name=Tcenter - obj=unnecessary_text name=Ucenter - obj=unnecessary_text name=Vcenter - obj=unnecessary_text name=Wcenter - obj=unnecessary_text name=Xcenter - obj=unnecessary_text name=Ycenter - obj=unnecessary_text name=Zcenter - obj=unnecessary_text name=Aextern - obj=unnecessary_text name=Bextern - obj=unnecessary_text name=Cextern - obj=unnecessary_text name=Dextern - obj=unnecessary_text name=Eextern - obj=unnecessary_text name=Fextern - obj=unnecessary_text name=Gextern - obj=unnecessary_text name=Hextern - obj=unnecessary_text name=Iextern - obj=unnecessary_text name=Jextern - obj=unnecessary_text name=Kextern - obj=unnecessary_text name=Lextern - obj=unnecessary_text name=Mextern - obj=unnecessary_text name=Nextern - obj=unnecessary_text name=Oextern - obj=unnecessary_text name=Pextern - obj=unnecessary_text name=Qextern - obj=unnecessary_text name=Rextern - obj=unnecessary_text name=Sextern - obj=unnecessary_text name=Textern - obj=unnecessary_text name=Uextern - obj=unnecessary_text name=Vextern - obj=unnecessary_text name=Wextern - obj=unnecessary_text name=Xextern - obj=unnecessary_text name=Yextern - obj=unnecessary_text name=Zextern - obj=program_text name=SEP_THOUSAND_EXPONENT - obj=program_text name=Transferring game ... note=transfer game over network - obj=program_text name=Lineless convoys serving this stop note=halt detail window - obj=program_text name=Net ID: %p note=powernet info window - obj=program_text name=Capacity: %.0f MW note=powernet info window - obj=program_text name=Demand: %.0f MW note=powernet info window - obj=program_text name=Generation: %.0f MW note=powernet info window - obj=program_text name=Usage: %.0f %% note=powernet info window - obj=program_text name=Supplied: %.0f %% note=powernet info window - obj=program_text name=%i years %i months old. note=tree info dialog - obj=program_text name=Only one transformer per factory! - obj=message_text name=Now %u clients connected. - obj=program_text name=Revision: - obj=program_text name=%u Player (%u locked)\n - obj=program_text name=%u Client(s)\n - obj=program_text name=join game - obj=program_text name=Show even servers with wrong version or pakset - obj=program_text name=add server - obj=program_text name=set signal spacing - obj=program_text name=signal spacing - obj=program_text name=remove interm. signals - obj=program_text name=replace other signals - obj=program_text name=Connected with server - obj=program_text name=Chat_msg - obj=program_text name=Problems_msg - obj=program_text name=Warnings_msg - obj=program_text name=Station_msg - obj=program_text name=Town_msg - obj=program_text name=Company_msg - obj=program_text name=Game_msg - obj=program_text name=Signal note=title of signal info window --- obj=program_text name=Game info note=title of play-online window --- obj=program_text name=find mismatch note=play-online window: button to compare paksets of client and server --- obj=program_text name=Aircraft note=tooltip in linemanagement window --- obj=program_text name=Wasser note=title of tile-info window of water tiles --- obj=program_text name=Comparing pak files ... --- obj=program_text name=Pakset differences --- obj=program_text name=Pak(s) not on server: --- obj=program_text name=Pak(s) different: --- obj=program_text name=Pak(s) missing on client: --- obj=program_text name=Only first %d differing paks reported. There are probably more. --- obj=program_text name=Enter Password note=title of cmpany name/password dialoge --- obj=program_text name=Password --- obj=program_text name=%s at (%i,%i) now public stop. --- obj=program_text name=deactivated in online mode --- obj=program_text name=Use beginner mode --- obj=program_text name=Higher transport fees, crossconnect all factories --- obj=button_text name=Road toll --- obj=program_text name=Pax <%i> Mail <%i> -- obj=program_text name=Production/Boost -- obj=program_text name=Boost (%%) -- obj=program_text name=Max Boost (%%) -- obj=program_text name=Demand -- obj=program_text name=Power (MW) -- obj=program_text name=Storage -- obj=program_text name=Consumed -- obj=program_text name=Produced -- obj=program_text name=Generated -- obj=error_text name=Server busy -- obj=error_text name=Only public player can lock games! -- obj=program_text name=Destroying map ... -- obj=program_text name=Passenger Demand %d\n -- obj=program_text name=Mail Demand %d\n -- obj=program_text name=Customers live in: -- obj=program_text name=Enter address -- obj=program_text name=show/hide block reservations -- obj=program_text name=show/hide object owner -- obj=program_text name=Walked -- obj=program_text name=Configure AI setttings -- obj=program_text name=Configure AI -- obj=program_text name=construction speed -- obj=program_text name=Smart hide objects -- obj=program_text name=hide objects under cursor -- obj=program_text name=Show only used -- obj=program_text name=In the industry legend show only currently existing factories -- obj=program_text name=Only show goods which are currently handled by factories -- obj=program_text name=clf_chk_obsolete -- obj=program_text name=Relevant note=depot window: show vehicles that transport goods produced by factories in game -- obj=program_text name=Missing pakfiles -- obj=program_text name=Pak which may cause severe errors: -- obj=program_text name=Pak which may cause visual errors: -- obj=program_text name=Bonusspeed: %i km/h note=maximum speed possible on a route. This is used for bonus calculation -- obj=program_text name=Maxspeed note=button with statistics of possible maxspeed of a convoi during all trips -- obj=program_text name=Ownership note=button in minimap to show owner -- obj=program_text name=player note=button in marker list sorting -- obj=help_text name=Please click on the map to add\nwaypoints or stops to this\nschedule. note=Shown when a schedule is empty. -- obj=program_text name=Highlite schedule note=button in visual setting dialog -- obj=program_text name=Similar view as the main window note=tooltip in minimap -- #obj=program_text #name=List of industries on the map #note=tooltip in minimap -- obj=program_text name=Shows the color code for several selections. note=tooltip in minimap -- obj=program_text name=Shows buttons on special topics. note=tooltip in minimap -- obj=program_text name=Delete the selected line (if without associated convois). note=tooltip in line schedule -- obj=obsolete name=Line Filter note=text in lin window for searching lines containing -- obj=program_text name=Last Month note=text in finance window -- obj=program_text name=Your primary color: note=text in player color choose dialog -- obj=program_text name=Your secondary color: note=text in player color choose dialog -- name=Show servers that are offline obj=program_text note=Tooltip in server information window --- name=Show mismatched obj=program_text note=Option in server information window --- name=Show offline obj=program_text note=Option in server information window --- name=Server did not respond! obj=program_text note=Server information window --- name=Query server obj=program_text note=Server information window --- name=Cannot connect to offline server! obj=program_text note=Server information window --- name=Nickname: obj=program_text --- name=Or enter a server manually: obj=program_text note=Server information window --- name=Show servers where game version or pakset does not match your client obj=program_text note=Tooltip in server information window --- name=Select a server to join: obj=program_text note=Server information window --- obj=error_text name=Vehicle %s cannot choose because stop too short! note=message at choose signs when the first stop is too short --- obj=help_text name=

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s note=string of which the index will be built -- obj=program_text name=Net wealth near zero note=text when net wealth nearly consumed -- obj=button_text name=Networks note=show network overlay in minimap -- obj=button_text name=Queueing note=show station waiting number change overlay in minimap -- obj=button_text name=Transfers note=show station arrival+departure overlay in minimap -- obj=help_text name=Overlay town names note=tooltip in minimap -- obj=help_text name=Overlay city limits note=tooltip in minimap -- obj=help_text name=Show level of city buildings note=tooltip in minimap -- obj=help_text name=Overlay passenger destinations when a town window is open note=tooltip in minimap -- obj=help_text name=Highlite tourist attraction note=tooltip in minimap -- obj=help_text name=Highlite factories note=tooltip in minimap -- obj=help_text name=Overlay schedules/network note=tooltip in minimap -- obj=help_text name=Show passenger coverage/passenger network note=tooltip in minimap -- obj=help_text name=Show mail service coverage/mail network note=tooltip in minimap -- obj=help_text name=Show transported freight/freight network note=tooltip in minimap -- obj=help_text name=Show capacity and if halt is overcrowded note=tooltip in minimap -- obj=help_text name=Show how many people/much is waiting at halts note=tooltip in minimap -- obj=help_text name=Show the change of waiting at halts note=tooltip in minimap -- obj=help_text name=Show how many convoi reach a station note=tooltip in minimap -- obj=help_text name=Sum of departure/arrivals at halts note=tooltip in minimap -- obj=help_text name=Show initial passenger departure note=tooltip in minimap -- obj=help_text name=Show usage of network note=tooltip in minimap -- obj=help_text name=Show speedlimit of ways note=tooltip in minimap -- obj=help_text name=Highlight railroad tracks note=tooltip in minimap -- obj=help_text name=Highlite depots note=tooltip in minimap -- obj=help_text name=Highlite electrical transmission lines note=tooltip in minimap -- obj=help_text name=Highlite forests note=tooltip in minimap -- obj=help_text name=Show the owenership of infrastructure note=tooltip in minimap -- obj=help_text name=Shows a listing with all industries on the map. note=tooltip in minimap -- obj=error_text name=Out of funds note=Shown when an action is forbidden because of negative net wealth -- obj=error_text name=No suitable way on the ground! note=show when building stations without ways/on slopes/on tunnels -- obj=button_text name=Scenario - obj=error_text name= Loading scenario script failed - obj=program_text note=tab in scenario info window name=Scenario Info - obj=program_text note=tab in scenario info window name=Scenario Goal - obj=program_text note=tab in scenario info window name=Scenario Rules - obj=program_text note=tab in scenario info window name=Scenario Result - obj=program_text note=tab in scenario info window name=About scenario - obj=program_text note=tab in scenario info window name=Scenario Error Log - obj=program_text note=tab in scenario info window name=Scenario Debug - obj=program_text note=Title of scenario info dialogue name=Scenario information - obj=program_text note=button in map creation dialoge to set number of factories name=No. of Factories - obj=program_text note=item in depot line selector name= - obj=program_text note=item in depot line selector name= - obj=program_text note=item in depot line selector name= - obj=program_text note=item in depot line selector name= - obj=program_text note=item in depot line selector name= - obj=error_text name=Can't buy obsolete vehicles! - obj=program_text note=info in depot name=Cost: %8s (%.2f$/km)\n - obj=program_text note=info in depot name=Power: %4d kW\n - obj=program_text note=info in depot name=Weight: - obj=program_text note=info in depot name=Capacity: - obj=program_text note=info in depot name=1 convoi - obj=program_text note=factory chart for goods in transit name=In Transit - obj=program_text name=Files from: note=open savegame window - obj=program_text name=distributing factories note=for progress bar - obj=program_text name=distributing cities note=for progress bar - obj=program_text note=finance window: misc. transport type name=tt_Other - obj=program_text note=halt window, departure board name=Departure board - obj=program_text note=halt window, departure board name=Show/hide estimated arrival times - obj=program_text note=halt window, departure board name=Departures to\n - obj=program_text note=halt window, departure board name=Arrivals from\n - obj=program_text note=halt window, departure board name=now - obj=program_text note=Way toll button in charts name=Way toll - obj=program_text note=Char(s) to indicate truncated text name=... - obj=program_text note=title/tooltip of thememanager name=Select a theme for display - obj=help_text note=tooltext to indicate climate conversion of a tile name=Set tile climate %s - obj=help_text note=tooltext for filling a bassin name=Increase water height - obj=help_text note=tooltext for draining a bassin name=Decrease water height - obj=error_text note=Failure or drainign/filling a bassin name=Cannot alter water - obj=program_text name=Cost: %8s (%.2f$/km %.2f$/m)\n note=Text in depot for convoi with monthly fixed cost - obj=error_text name=Cannot connect to the\ncenter of a double slope! note=Bridges ending in the middle of a slope - obj=error_text name=Cannot build on a double slope! - obj=error_text name=No bridges over runways! - obj=program_text name=Water note=Climate name of water areas - obj=error_text name=This tunnel branches. You can try Control+Click to remove. - obj=program_text name=nowhere - obj=help_text name=Color according to transport capacity left note=tooltip in minimap window - obj=error_text name=Not enough clearance. note=Error when building a way with not enough clearance above or below. -- obj=message_text name=Net wealth less than 10%% of starting capital! -- obj=message_text name=Server preparing game ... note=Shown while server is saving the game -- obj=program_text name=Theme selector note=Loading a GUI theme dialog -- obj=program_text name=Last used tools note=Toolbar with the last used tools -- obj=help_text name=Open station/stop details note=Tooltip -- obj=program_text name=Insufficient funds! note=text for when not enough funds are owned to use a tool - obj=program_text name=Trees disabled! note=text for when a tool fails due to trees being disabled - obj=program_text name=Not allowed to make publicly owned ways! note=text for when trying to make a public way when public ways are disabled - obj=error_text name=Server version too new note=Error message when questioning future server versions - obj=program_text name=Produces: %.1f units/minute note=Factory production per minute text - obj=program_text name=%s %.0f%% : %.0f/%.0f @ %.1f%% note=JIT2 factory output formater - obj=program_text name=%s %.0f%% : %.0f+%u/%.0f @ %.1f%% note=JIT2 factory input formater - obj=program_text name=%i car(s), note=length of assembled convoi in depot frame, only shown if more than one - obj=error_text name=Loading a new game will end the current server session! - obj=button_text name=Start this as a server note=used in loading games/scenario dialoge - obj=error_text name=More than one possibility to build this dock found. - obj=error_text name=Bridge blocked by way below or above. note=height clearance not enough for a bridge at this position - obj=program_text name=Select display font - obj=program_text name=font size - obj=program_text name=Only full Unicode fonts - obj=error_text name=Cannot rotate this building! - obj=error_text name=Not enough bytes transferred note=server did not send enough bytes when transmitting a game - obj=error_text name=Client closed connection during transfer - obj=error_text name=Show all revenue messages - obj=error_text name=Show only player's revenue - obj=error_text name=Show no revenue messages - obj=program_text name=length: %d - obj=program_text name=

Error

- obj=program_text name=contains the following doubled objects:

- obj=program_text name=

Warning

addons for - obj=program_text name=Connections note=Tab in factory window/station dialog - obj=program_text name=Freight note=Tab in convoy-info window - obj=program_text name=Scenario_ note=in finance window - obj=program_text name=Show finances for transport type note=in finance window - obj=program_text name=Size (%d MB): note=in enlarge map and new map window - obj=error_text name=Too far away to merge stations! - obj=program_text name=Bonus Speed: %i km/h note=Goods frame current average speed of line type - obj=program_text name=Bonus Multiplier: %i%% note=Goods frame speed bonus multiplier in percent - obj=program_text name=No vehicles are available for purchase. note=Goods frame displayed if no vehicles of the selected line type are available for purchase - obj=program_text name=GUI settings note=tab in display setting - obj=program_text name=map view note=tab in display setting - obj=program_text name=transparencies note=tab in display setting - obj=program_text name=station labels note=tab in display setting - obj=program_text name=traffic settings note=tab in display setting - obj=program_text name=Convoi following mode note=label in trafic display setting - obj=button_text name=TOOL_SOUND note=label in sound frame - obj=button_text name=TRAFFIC_SOUND note=label in sound frame - obj=button_text name=AMBIENT_SOUND note=label in sound frame - obj=button_text name=FACTORY_SOUND note=label in sound frame - obj=button_text name=CROSSING_SOUND note=label in sound frame - obj=button_text name=CASH_SOUND note=label in sound frame - obj=button_text name=Sound range: note=label in sound frame - obj=program_text name=dp_title note=list of depots - obj=program_text name=waytype - obj=program_text name=vehicles stored note=sort option in depot list - obj=program_text name=vh_title note=vehicle list title - obj=program_text name=Vehicle Name note=vehicle sort option - obj=program_text name=Capacity note=vehicle sort option - obj=program_text name=Price note=vehicle sort option - obj=program_text name=Cost note=vehicle sort option - obj=program_text name=Cost per unit note=vehicle sort option - obj=program_text name=Max. speed note=vehicle sort option - obj=program_text name=Vehicle Power note=vehicle sort option - obj=program_text name=Weight note=vehicle sort option - obj=program_text name=Intro. date note=vehicle sort option - obj=program_text name=Retire date note=vehicle sort option - obj=program_text name=Show future note=vehicle list option - obj=program_text name=Copy to clipboard note=In chat window - obj=error_text name=Only up and down movement in the underground! note=Tried to use a directional slope in the underground - obj=program_text name=Show contour note=Option in minimap - obj=help_text name=Color-coded terrain according to altitude. note=Option in minimap - obj=program_text name=line name mouseover tooltips note=option in display settings - obj=help_text name=At least one stop is connected to the town. note=tooltip in citylist - obj=program_text name=Served by note=option in citylist - obj=help_text name=At least one tile is connected to one stop. note=tooltip in factorylist - obj=program_text name=(%.2f$/km %.2f$/m) note=info for cars with running and fixed cost - obj=program_text name=(%.2f$/km) note=info for cars with running cost only - obj=button_text name=height based note=tab in climate dialog: Climate by heigh level - obj=button_text name=temperature-humidity based note=tab in climate dialog: climates by temperature and humidity - obj=button_text name=climate area percentage note=text in climate dialog, sizeof climate patches - obj=button_text name=moisture land note=text in climate dialog - obj=button_text name=moisture water note=text in climate dialog - obj=button_text name=humidities note=text in climate dialog - obj=button_text name=temperature borders note=text in climate dialog - obj=button_text name=rainfall note=text in climate dialog, trees vial simulated rainfall - obj=button_text name=Lake height note=text in climate dialog, maximum height of lakes - obj=button_text name=Num pad keys always move map note=Numloock is ignored with this - obj=program_text name=Move the map note=name of tool to move map view - obj=button_text name=Find matching convois info=line management window - obj=tooltip_text name=Add convois with similar schedule to this line. info=line management window - obj=program_text name=legacy (small heights) info=Heightmap window - obj=program_text name=legacy (large heights) info=Heightmap window - obj=program_text name=linear info=Heightmap window - obj=program_text name=clamp info=Heightmap window - obj=program_text name=Load mode: info=Heightmap window - obj=program_text name=Install graphics info=title of pakset installer - obj=program_text name=Wind direction info=Climate window - obj=program_text name=Select one or more graphics to install (Ctrl+click): note=pakinstaller window - obj=program_text name=The following graphics are unmaintained: note=pakinstaller window - obj=program_text name=groundobj builder note=groundobj edit window - obj=program_text name=Has Snow note=groundobj edit window - obj=program_text name=Has slope graphics note=groundobj edit window - obj=program_text name=Can be overgrown note=groundobj edit window - obj=program_text name=[0] south-facing note=Extended edit option - obj=program_text name=[1] east-facing note=Extended edit option - obj=program_text name=[2] north-facing note=Extended edit option - obj=program_text name=[3] west-facing note=Extended edit option - obj=program_text name=[4] southeast corner note=Extended edit option - obj=program_text name=[5] northeast corner note=Extended edit option - obj=program_text name=[6] northwest corner note=Extended edit option - obj=program_text name=[7] southwest corner note=Extended edit option - obj=program_text name=Pax level note=Extended edit option - obj=program_text name=Mail level note=Extended edit option - obj=program_text name=Size (area) note=Extended edit option - obj=program_text name=Available at custom date note=Extended edit option - obj=program_text name=Loading (%i->%i%%)! -- obj=program_text name=Loading (%i%%) departure %s! note=tooltip for convoi state scheduled loading - obj=program_text name=Loading (%i%%)! note=tooltip for convoi state scheduled loading without minimum load - obj=program_text name=Unloading (%i%%)! note=tooltip for convoi state scheduled unloading - obj=program_text name=Toolbar position: note=display setting option - obj=program_text name=1th note=ordinal number en - obj=program_text name=2th note=ordinal number en - obj=program_text name=3th note=ordinal number en - obj=program_text name=21th note=ordinal number en - obj=program_text name=22th note=ordinal number en - obj=program_text name=23th note=ordinal number en - obj=program_text name=31th note=ordinal number en - obj=program_text name=ORDINAL_DAY_SYMBOL note=ordinal day symbol (English th, german . frensh e - obj=program_text name=Monthly departures note=absolute departure time - obj=program_text name=Departure after note=relative departure time on loading - obj=program_text name=on the note=absolute departure time after the repetion box - obj=button_text name=Single GUI note=Button in line lines, please short translations! -- obj=program_text name=Closes topmost line window when new line selected. note=tooltip for button in line list enforcing single window gui - obj=button_text name=Absolute times note=absolute departure time instead relative in departure board - obj=program_text name=The gradient does not fit a tunnel note=Shown when building a tunnel in invalid slope - obj=program_text name=Do not show note=option for factory tooltips -- obj=program_text name=On mouseover note=option for factory tooltips -- obj=program_text name=Served by me note=option for factory tooltips -- obj=program_text name=Show always note=option for factory tooltips -- obj=program_text name=Industry overlay note=label for factory tooltips -- obj=program_text name=Display bars above factory to show the status note=tooltip help for factory tooltips -- obj=program_text name=Date format note=label for date format combobox -- obj=program_text name=Fullscreen (changed after restart) note=button in display setting -- obj=program_text name=Borderless (disabled on fullscreen) note=button in display setting -- obj=program_text name=Screen scale: note=button in display setting -- obj=button_text name=Lake note=Name of water above groundlevel -- obj=button_text name=Open Sea note=Name of water at groundlevel -- obj=button_text name=sea note=climate of water -- obj=program_text name=Climates -- obj=button_text name=Reselect closes tools note=display option -- obj=button_text name=Install note=Option to install new pak sets -- obj=program_text name=Show climates note=minimap display setting -- obj=program_text name=Show outline note=minimap display setting -- obj=program_text name=Month note=in exted edit dialogues -- obj=program_text name=Year note=in exted edit dialogues -- obj=program_text name=auto note=in exted edit dialogues -- obj=program_text name=Departures per month note=label in schedule edit -- obj=program_text name=Departs at note=label in schedule edit -- obj=program_text name=Minimum load note=label in schedule edit -- obj=program_text name=Max. waiting time note=label in schedule edit -- obj=program_text name=No player note=text to indicate to use for served by no one -- obj=program_text name=Cleanup schedule note=Appear in schedule if there are double entries -- obj=help_text name=Remove double stops from schedule note=toolytip for button that appears in schedule if there are double entries -- obj=program_text name=Infinite mouse scrolling note=button in display options -- obj=program_text name=Infinite scrolling using mouse note=tooltip in display options -- obj=program_text name=Scroll threshold note=distance moved before starting map scrolling when a general tool is selected -- obj=program_text name=Downloading note=loadingbar during http download of content -- obj=program_text name=Extract files note=loadingbar during zip file extrating of paks -- obj=program_text name=Install paks note=loadingbar during paks download and install -- obj=program_text name=remove signal note=button/tool tooltip on removing signals -- obj=program_text name=transparent background -- obj=program_text name=Show networks -- obj=program_text name=Shows buttons on network overlay. note=tooltip to Show networks -- obj=program_text name=Loading time: note=Time for full load -- obj=error_text name=No suitable crossing note=Displayed when a route search failed as one possible cause -- obj=error_text name=No curves on runways note=Displayed when a route search failed as one possible cause -- obj=error_text name=A building blocks the construction note=Displayed when a route search failed as one possible cause -- obj=tooltip_text name=Mirrors order of stops note=tooltip for mirror stop order button -- obj=program_text name=Revert schedule note=button to restore original schedule -- obj=tooltip_text name=Revert to original schedule note=tooltip to restore original schedule -- obj=program_text name=Invert stops note=button to invert stop order -- obj=tooltip_text name=Enter intervall in days, hours, minutes note=tooltip for timeinput gui element -- obj=program_text name=Single toolbar only note=button in display setting -- obj=program_text name=Vehicle count: note=number of convoi vehicles in the convoi details -- obj=program_text name=Climate note=dialoque to build object -- obj=program_text name=Composed by note=music credits -- obj=program_text name=and arranged by note=music credits -- obj=program_text name=Load Scripted AI note=script Ai text player list and load dialoque -- obj=program_text name=Load script tool note=mouseover and dialogue title -- obj=button_text name=Tutorial note=Button in the banner window -- obj=tooltip_text name=Tutorial not available for this pakset. Please try loading Pak128. note=Tooltip text for the button in the banner window -- obj=button_text name=Continue Game note=Button in the banner window -- obj=program_text name=Load '%s' note=Tooltip for Continue Game button in banner window -- obj=button_text name=Return to menu note=Button to return to banner menu -- obj=program_text name=Welcome to Simutrans note=Text in banner window. It may be followed by a version string (i.e. "Nightly") -- obj=program_text name=Developed by the Simutrans Team note=Text in banner window -- obj=program_text name=under the Artistic License note=Text in banner window -- obj=program_text name=based on Simutrans 84.22.1 note=Text in banner window -- obj=program_text name=Selling of the program is forbidden. note=Text in banner window -- obj=program_text name=For questions and support please visit: note=Text in banner window -- obj=program_text name=/month note=Text in tooltip for way and building tool icons -- obj=program_text name=Revenue/unit/100 tiles note=Column header in goods list -- obj=program_text name=Speed Bonus note=Column header in goods list -- obj=program_text name=Category note=Column header in goods list -- obj=program_text name=Weight/unit note=Column header in goods list -- obj=program_text name=Hide labels note=Option in display settings/stations -- obj=program_text name=Change label style note=Option in display settings/stations -- obj=program_text name=%s now known as %s. note=Shown as message if a client renames himself. -- obj=program_text name=Welcome, %s! note=Shown as message if a client connects -- obj=program_text name=%s has left. note=Shown as message if a client leaves -- obj=program_text name=Lock Control key note=Tool button tooltip -- obj=program_text name=1 year ago note=chat window -- obj=program_text name=%u years ago note=chat window -- obj=program_text name=%u days ago note=chat window -- obj=program_text name=%u hours ago note=chat window -- obj=program_text name=1 minute ago note=chat window -- obj=program_text name=%u minutes ago note=chat window -- obj=program_text name=just now note=chat window -- obj=tooltip_text name=Attach current coordinate to the comment note=chat window -- obj=program_text name=%u Client(s)\n note=chat window -- obj=program_text name=direct_chat_to: note=chat window -- obj=program_text name=To: %s note=chat window -- obj=program_text name=public_chat note=tab in chat window -- obj=program_text name=company_chat note=tab in chat window -- obj=program_text name=Player ranking note=player ranking window -- obj=program_text name=Click to open the finance dialog. note=player ranking window -- obj=program_text name=Not online note=message when offline in chat window -- obj=program_text name=Current game note=loading default in extended settings -- obj=program_text name=Load settings from note=loading setting in extended settings -- obj=program_text name=Left button drags minimap too note=in display settings -- obj=program_text name=The script cannot be saved!\n note=Script generator -- obj=program_text name=The generated script was saved!\n note=Script generator -- obj=error_text name=Not allowed to copy object. note=Pipette tool -- obj=program_text name=generate script note= tooltip -- obj=program_text name=Pipette note= tooltip -- obj=error_text name=Watertable reached note=too deep lowering failed -- obj=program_text name=Icon size: note=text in diplay options -- obj=error_text name=Forbidden by scenario note=error on trying to select and execute a forbidden tool -- obj=error_text name=Could not open file note=Whenever one cannot access a file -- obj=error_text name=Not initialized note=Could not initilise extrenal library -- obj=error_text name=Unknown error note=General error occured -- obj=error_text name=Not enough empty space note=not written as much bytes as requested => disk full or device busy -- obj=error_text name=Failed to write file note=write operation could not finish or did not even start (permissions?) -- obj=error_text name=Corrupt file note=reading failed due to Corrupt or incomplete file -- #obj=help_text #name=Lower values mean more local sounds #note=tooltip in sound frame #-- #obj=program_text #name= #- # text group = 'message_text' # text group = 'button_text' # text group = 'climates_text' # text group = 'error_text' # text group = 'help_text' # text group = 'menu_text' # text group = 'program_text' # text group = 'record_text' # text group = 'ki_text' #obj= <-> text group #name= <-> objecr name #note= <-> description for object #*************** Zuviel/falsch/obsolet ********************** #- #obj=program_text #name=Land industries #- #obj=error_text #name=Cannot create generic line!\nSelect line type by\nusing filter tabs. #- # Obsolete vor 102.2 #obj=program_text #name=Vehicle %s is stucked! #-- #obj=program_text #name=Vehicle %s can't find a route! #-- #obj=program_text #name=%s's\nheadquarter now\nat (%i,%i). #-- #obj=program_text #name=1nord #-- #obj=program_text #name=1nordost #-- #obj=program_text #name=1nordwest #-- #obj=program_text #name=1ost #-- #obj=program_text #name=1sued #-- #obj=program_text #name=1suedost #-- #obj=program_text #name=1suedwest #-- #obj=program_text #name=1west #-- #obj=program_text #name=Ambiguous signal combination.\nTry removing by clicking the\nother side of the signal.\n #-- #obj=ki_text #name=Ferry service by %s now between %s nand %s. #-- #obj=program_text #name=Monorailhalt #- #obj=program_text #name=Narrowgaugehalt #- #obj=program_text #name=Narrowgaugeboden #- #obj=program_text #name=Passengers %d %c, %d %c, %d no route\n\nCapacity: %i\n #- #obj=message_text #name=Production of vehicle has been stopped:\n%s\n #- #obj=error_text #name=Station already\nhas a post office!\n #- #obj=ki_text #name=Travellers now use %s's busses between %s nand %s. #- #obj=program_text #name=Tunnelmuendung #- #obj=program_text #name=Wagen im Block #- #obj=program_text #name=Zeiger #- #obj=program_text #name=Zu nah an einem\nanderen Signal!\n #- #obj=program_text #name=\nRail block #- #obj=program_text #name=\n\nRibi (unmasked) #- #obj=program_text #name=attractionbuilder #-- #obj=program_text #name=housebuilder #-- #obj=program_text #name=treebuilder #-- #obj=record_text #name=New world record for maglev: %.1f km/h by %s. #-- #obj=record_text #name=New world record for narrowgauge: %.1f km/h by %s. #-- #obj=program_text #name=Tunnel must end on single way! #-- #obj=program_text #name=Headquartern and %li trains #- #obj=program_text #name=Monate alt #- #obj=program_text #name=Einstellungsfenster #- #obj=program_text #name=Move the selected vehicle(s) back to the depot #- #obj=program_text #name=Lines are used to manage groups of vehicles #- #obj=program_text #name=Add the selected vehicle(s) to the selected line #- #obj=program_text #name=Aufloesen #- #obj=program_text #name=LOCO_CAP #- #obj=program_text #name=LOCO_INFO #- #obj=program_text #name=WAGGON_INFO #- #obj=program_text #name=Cost: %6d$ (%.2f$/km)\n #- #obj=program_text #name=Vehicle details #- #obj=program_text #name=%i years %i months old #-- #obj=program_text #name=Stucked! #-- #obj=program_text #name=Can't find a route! #-- #obj=program_text #name=Not loading! #-- #obj=program_text #name=Going to depot! #-- #obj=button_text #name=Maximize height levels #note=Indicates that the heightmap should be stretched over more height levels #-- #obj=program_text #name=clf_chk_name_filter #- #obj=program_text #name=clf_chk_ships #- #obj=program_text #name=clf_chk_trains #- #obj=program_text #name=clf_chk_trams #- #obj=program_text #name=clf_chk_aircrafts #- #obj=program_text #name=clf_chk_cars #- #obj=button_text #name=cl_btn_filter_disable #- #obj=button_text #name=cl_btn_filter_enable #- #obj=button_text #name=Select soundfont #- #obj=program_text #name=Soundfonts are located in the music directory. #- #obj=program_text #name=Soundfont not found. Please select a soundfont below. #- #obj=error_text #name=No soundfont found!\n\nMusic won't play until you load a soundfont from the sound options menu. #- #obj=program_text #name=Helligk. #- #obj=program_text #name=\nAct. Load: %u MW\n #note=powernet info window (depricated) #- #obj=program_text #name=show station names #- #obj=program_text #name=Account above %s #name=Supply %s at (%i,%i) #name=Connect factory #name=Headquarter and %li trains #name=Transport %li passengers #note=old scenarion descriptions simutrans-124.3/src/external/000077500000000000000000000000001474050137200161645ustar00rootroot00000000000000simutrans-124.3/src/external/miniz.h000066400000000000000000014130061474050137200174700ustar00rootroot00000000000000#ifndef MINIZ_EXPORT #define MINIZ_EXPORT #endif /* miniz.c 3.0.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Low-level Deflate/Inflate implementation notes: Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses approximately as well as zlib. Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateReset/inflateEnd compress, compress2, compressBound, uncompress CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but there are no guarantees that miniz.c pulls this off perfectly. * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to get the job done with minimal fuss. There are simple API's to retrieve file information, read files from existing archives, create new archives, append new files to existing archives, or clone archive data from one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), or you can specify custom file read/write callbacks. - Archive reading: Just call this function to read a single file from a disk archive: void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); The locate operation can optionally check file comments too, which (as one example) can be used to identify multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data to disk and builds an exact image of the central directory in memory. The central directory image is written all at once at the end of the archive file when the archive is finalized. The archive writer can optionally align each file's local header and file data to any power of 2 alignment, which can be useful when the archive will be read from optical media. Also, the writer supports placing arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still readable by any ZIP tool. - Archive appending: The simple way to add a single file to an archive is to call this function: mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); The archive will be created if it doesn't already exist, otherwise it'll be appended to. Note the appending is done in-place and is not an atomic operation, so if something goes wrong during the operation it's possible the archive could be left without a central directory (although the local file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and you're done. This is safe but requires a bunch of temporary disk space or heap memory. 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), append new files as needed, then finalize the archive which will write an updated central directory to the original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: No spanning support. Extraction functions can only handle unencrypted, stored or deflated files. Requires streams capable of seeking. * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. * Important: For best perf. be sure to customize the below macros for your target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #pragma once /* Defines to completely disable specific portions of miniz.c: If all macros here are defined the only functionality remaining will be CRC-32 and adler-32. */ /* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on * stdio for file I/O. */ /*#define MINIZ_NO_STDIO */ /* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able * to get the current time, or */ /* get/set file times, and the C run-time funcs that get/set times won't be * called. */ /* The current downside is the times written to your archives will be from 1979. */ /*#define MINIZ_NO_TIME */ /* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */ /*#define MINIZ_NO_DEFLATE_APIS */ /* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */ /*#define MINIZ_NO_INFLATE_APIS */ /* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_APIS */ /* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP * archive API's. */ /*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ /* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression * API's. */ /*#define MINIZ_NO_ZLIB_APIS */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent * conflicts against stock zlib. */ /*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ /* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ /*#define MINIZ_NO_MALLOC */ #ifdef MINIZ_NO_INFLATE_APIS #define MINIZ_NO_ARCHIVE_APIS #endif #ifdef MINIZ_NO_DEFLATE_APIS #define MINIZ_NO_ARCHIVE_WRITING_APIS #endif #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) /* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc * on Linux */ #define MINIZ_NO_TIME #endif #include #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) #include #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ defined(__i386) || defined(__i486__) || defined(__i486) || \ defined(i386) || defined(__ia64__) || defined(__x86_64__) /* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ #define MINIZ_X86_OR_X64_CPU 1 #else #define MINIZ_X86_OR_X64_CPU 0 #endif /* Set MINIZ_LITTLE_ENDIAN only if not set */ #if !defined(MINIZ_LITTLE_ENDIAN) #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif #else #if MINIZ_X86_OR_X64_CPU #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif #endif #endif /* Using unaligned loads and stores causes errors when using UBSan */ #if defined(__has_feature) #if __has_feature(undefined_behavior_sanitizer) #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #endif /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) #if MINIZ_X86_OR_X64_CPU /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient * integer loads and stores from unaligned addresses. */ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #define MINIZ_UNALIGNED_USE_MEMCPY #else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ defined(__x86_64__) /* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are * reasonably fast (and don't involve compiler generated calls to helper * functions). */ #define MINIZ_HAS_64BIT_REGISTERS 1 #else #define MINIZ_HAS_64BIT_REGISTERS 0 #endif #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API Definitions. */ /* For more compatibility with zlib, miniz.c uses unsigned long for some * parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ typedef unsigned long mz_ulong; /* mz_free() internally uses the MZ_FREE() macro (which by default calls free() * unless you've modified the MZ_MALLOC macro) to release a block allocated from * the heap. */ MINIZ_EXPORT void mz_free(void *p); #define MZ_ADLER32_INIT (1) /* mz_adler32() returns the initial adler-32 value to use when called with * ptr==NULL. */ MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) /* mz_crc32() returns the initial CRC-32 value to use when called with * ptr==NULL. */ MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); /* Compression strategies. */ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; /* Method */ #define MZ_DEFLATED 8 /* Heap allocation callbacks. Note that mz_alloc_func parameter types purposely differ from zlib's: items/size is size_t, not unsigned long. */ typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); /* Compression levels: 0-9 are the standard zlib-style levels, 10 is best * possible compression (not zlib compatible, and may be very slow), * MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; #define MZ_VERSION "11.0.2" #define MZ_VERNUM 0xB002 #define MZ_VER_MAJOR 11 #define MZ_VER_MINOR 2 #define MZ_VER_REVISION 0 #define MZ_VER_SUBREVISION 0 #ifndef MINIZ_NO_ZLIB_APIS /* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The * other values are for advanced use (refer to the zlib docs). */ enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; /* Return status codes. MZ_PARAM_ERROR is non-standard. */ enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; /* Window bits */ #define MZ_DEFAULT_WINDOW_BITS 15 struct mz_internal_state; /* Compression/decompression stream struct. */ typedef struct mz_stream_s { const unsigned char *next_in; /* pointer to next byte to read */ unsigned int avail_in; /* number of bytes available at next_in */ mz_ulong total_in; /* total number of bytes consumed so far */ unsigned char *next_out; /* pointer to next byte to write */ unsigned int avail_out; /* number of bytes that can be written to next_out */ mz_ulong total_out; /* total number of bytes produced so far */ char *msg; /* error msg (unused) */ struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ mz_free_func zfree; /* optional heap free function (defaults to free) */ void *opaque; /* heap alloc function user pointer */ int data_type; /* data_type (unused) */ mz_ulong adler; /* adler32 of the source or uncompressed data */ mz_ulong reserved; /* not used */ } mz_stream; typedef mz_stream *mz_streamp; /* Returns the version string of miniz.c. */ MINIZ_EXPORT const char *mz_version(void); #ifndef MINIZ_NO_DEFLATE_APIS /* mz_deflateInit() initializes a compressor with default options: */ /* Parameters: */ /* pStream must point to an initialized mz_stream struct. */ /* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ /* level 1 enables a specially optimized compression function that's been * optimized purely for performance, not ratio. */ /* (This special func. is currently only enabled when * MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if the input parameters are bogus. */ /* MZ_MEM_ERROR on out of memory. */ MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level); /* mz_deflateInit2() is like mz_deflate(), except with more control: */ /* Additional parameters: */ /* method must be MZ_DEFLATED */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with * zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no * header or footer) */ /* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); /* Quickly resets a compressor without having to reallocate anything. Same as * calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream); /* mz_deflate() compresses the input to output, consuming as much of the input * and producing as much output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update * the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or * MZ_FINISH. */ /* Return values: */ /* MZ_OK on success (when flushing, or if more input is needed but not * available, and/or there's more output to be written but the output buffer is * full). */ /* MZ_STREAM_END if all input has been consumed and all output bytes have been * written. Don't call mz_deflate() on the stream anymore. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input and/or * output buffers are empty. (Fill up the input buffer or free up some output * space and try again.) */ MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); /* mz_deflateEnd() deinitializes a compressor: */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream); /* mz_deflateBound() returns a (very) conservative upper bound on the amount of * data that could be generated by deflate(), assuming flush is set to only * MZ_NO_FLUSH or MZ_FINISH. */ MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); /* Single-call compression functions mz_compress() and mz_compress2(): */ /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on * failure. */ MINIZ_EXPORT int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); MINIZ_EXPORT int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); /* mz_compressBound() returns a (very) conservative upper bound on the amount of * data that could be generated by calling mz_compress(). */ MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len); #endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ #ifndef MINIZ_NO_INFLATE_APIS /* Initializes a decompressor. */ MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream); /* mz_inflateInit2() is like mz_inflateInit() with an additional option that * controls the window size and whether or not the stream has been wrapped with * a zlib header/footer: */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or * -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits); /* Quickly resets a compressor without having to reallocate anything. Same as * calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream); /* Decompresses the input stream to the output, consuming only as much of the * input as needed, and writing as much to the output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update * the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ /* On the first call, if flush is MZ_FINISH it's assumed the input and output * buffers are both sized large enough to decompress the entire stream in a * single call (this is slightly faster). */ /* MZ_FINISH implies that there are no more source bytes available beside * what's already in the input buffer, and that the output buffer is large * enough to hold the rest of the decompressed data. */ /* Return values: */ /* MZ_OK on success. Either more input is needed but not available, and/or * there's more output to be written but the output buffer is full. */ /* MZ_STREAM_END if all needed input has been consumed and all output bytes * have been written. For zlib streams, the adler-32 of the decompressed data * has also been verified. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_DATA_ERROR if the deflate stream is invalid. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input buffer is * empty but the inflater needs more input to continue, or if the output buffer * is not large enough. Call mz_inflate() again */ /* with more input data, or with more room in the output buffer (except when * using single call decompression, described above). */ MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush); /* Deinitializes a decompressor. */ MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream); /* Single-call decompression. */ /* Returns MZ_OK on success, or one of the error codes from mz_inflate() on * failure. */ MINIZ_EXPORT int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); MINIZ_EXPORT int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len); #endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ /* Returns a string description of the specified error code, or NULL if the * error code is invalid. */ MINIZ_EXPORT const char *mz_error(int err); /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used * as a drop-in replacement for the subset of zlib that miniz.c supports. */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you * use zlib in the same project. */ #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; typedef mz_ulong uLong; typedef Byte Bytef; typedef uInt uIntf; typedef char charf; typedef int intf; typedef void *voidpf; typedef uLong uLongf; typedef void *voidp; typedef void *const voidpc; #define Z_NULL 0 #define Z_NO_FLUSH MZ_NO_FLUSH #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH #define Z_SYNC_FLUSH MZ_SYNC_FLUSH #define Z_FULL_FLUSH MZ_FULL_FLUSH #define Z_FINISH MZ_FINISH #define Z_BLOCK MZ_BLOCK #define Z_OK MZ_OK #define Z_STREAM_END MZ_STREAM_END #define Z_NEED_DICT MZ_NEED_DICT #define Z_ERRNO MZ_ERRNO #define Z_STREAM_ERROR MZ_STREAM_ERROR #define Z_DATA_ERROR MZ_DATA_ERROR #define Z_MEM_ERROR MZ_MEM_ERROR #define Z_BUF_ERROR MZ_BUF_ERROR #define Z_VERSION_ERROR MZ_VERSION_ERROR #define Z_PARAM_ERROR MZ_PARAM_ERROR #define Z_NO_COMPRESSION MZ_NO_COMPRESSION #define Z_BEST_SPEED MZ_BEST_SPEED #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY #define Z_FILTERED MZ_FILTERED #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY #define Z_RLE MZ_RLE #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS #define alloc_func mz_alloc_func #define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream #ifndef MINIZ_NO_DEFLATE_APIS #define deflateInit mz_deflateInit #define deflateInit2 mz_deflateInit2 #define deflateReset mz_deflateReset #define deflate mz_deflate #define deflateEnd mz_deflateEnd #define deflateBound mz_deflateBound #define compress mz_compress #define compress2 mz_compress2 #define compressBound mz_compressBound #endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ #ifndef MINIZ_NO_INFLATE_APIS #define inflateInit mz_inflateInit #define inflateInit2 mz_inflateInit2 #define inflateReset mz_inflateReset #define inflate mz_inflate #define inflateEnd mz_inflateEnd #define uncompress mz_uncompress #define uncompress2 mz_uncompress2 #endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ #define crc32 mz_crc32 #define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 #define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION #define zlibVersion mz_version #define zlib_version mz_version() #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ #endif /* MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif #pragma once #include #include #include #include /* ------------------- Types and macros */ typedef unsigned char mz_uint8; typedef signed short mz_int16; typedef unsigned short mz_uint16; typedef unsigned int mz_uint32; typedef unsigned int mz_uint; typedef int64_t mz_int64; typedef uint64_t mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) /* Works around MSVC's spammy "warning C4127: conditional expression is * constant" message. */ #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #define MZ_FILE FILE #endif /* #ifdef MINIZ_NO_STDIO */ #ifdef MINIZ_NO_TIME typedef struct mz_dummy_time_t_tag { mz_uint32 m_dummy1; mz_uint32 m_dummy2; } mz_dummy_time_t; #define MZ_TIME_T mz_dummy_time_t #else #define MZ_TIME_T time_t #endif #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC #define MZ_MALLOC(x) NULL #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else #define MZ_MALLOC(x) malloc(x) #define MZ_FREE(x) free(x) #define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj)) #define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) \ ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) \ ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #define MZ_READ_LE64(p) \ (((mz_uint64)MZ_READ_LE32(p)) | \ (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \ << 32U)) #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif #ifdef __cplusplus extern "C" { #endif extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address); extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); #define MZ_UINT16_MAX (0xFFFFU) #define MZ_UINT32_MAX (0xFFFFFFFFU) #ifdef __cplusplus } #endif #pragma once #ifndef MINIZ_NO_DEFLATE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression API Definitions */ /* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly * slower, and raw/dynamic blocks will be output more frequently). */ #define TDEFL_LESS_MEMORY 0 /* tdefl_init() compression flags logically OR'd together (low 12 bits contain * the max. number of probes per dictionary search): */ /* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes * per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap * compression), 4095=Huffman+LZ (slowest/best compression). */ enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; /* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before * the deflate data, and the Adler-32 of the source data at the end. Otherwise, * you'll get raw deflate data. */ /* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even * when not writing zlib headers). */ /* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more * efficient lazy parsing. */ /* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's * initialization time to the minimum, but the output may vary from run to run * given the same input (depending on the contents of memory). */ /* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ /* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ /* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ /* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ /* The low 12 bits are reserved to control the max # of hash probes per * dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; /* High level compression functions: */ /* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block * allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ /* flags: The max match finder probes (default is 128) logically OR'd against * the above flags. Higher probes are slower but improve compression. */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pOut_len will be set to the compressed data's size, which could be larger * than src_buf_len on uncompressible data. */ /* The caller must free() the returned block when it's no longer needed. */ MINIZ_EXPORT void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in * memory. */ /* Returns 0 on failure. */ MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* Compresses an image to a compressed PNG file in memory. */ /* On entry: */ /* pImage, w, h, and num_chans describe the image to compress. num_chans may be * 1, 2, 3, or 4. */ /* The image pitch in bytes per scanline will be w*num_chans. The leftmost * pixel on the top scanline is stored first in memory. */ /* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, * MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ /* If flip is true, the image will be flipped on the Y axis (useful for OpenGL * apps). */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pLen_out will be set to the size of the PNG image file. */ /* The caller must mz_free() the returned heap block (which will typically be * larger than *pLen_out) when it's no longer needed. */ MINIZ_EXPORT void * tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); /* Output stream interface. The compressor uses this interface to write * compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); /* tdefl_compress_mem_to_output() compresses a block to an output stream. The * above helpers use this function internally. */ MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output( const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; /* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed * output block (using static/fixed Huffman codes). */ #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #endif /* The low-level tdefl functions below may be used directly if the above helper * functions aren't flexible enough. The low-level functions don't make any heap * allocations, unlike the above helper functions. */ typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1 } tdefl_status; /* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; /* tdefl's compression state structure. */ typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; /* Initializes the compressor. */ /* There is no corresponding deinit() function because the tdefl API's do not * dynamically allocate memory. */ /* pBut_buf_func: If NULL, output data will be supplied to the specified * callback. In this case, the user should call the tdefl_compress_buffer() API * for compression. */ /* If pBut_buf_func is NULL the user should always call the tdefl_compress() * API. */ /* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, * etc.) */ MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); /* Compresses a block of data, consuming as much of the specified input buffer * as possible, and writing as much compressed data to the specified output * buffer as possible. */ MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a * non-NULL tdefl_put_buf_func_ptr. */ /* tdefl_compress_buffer() always consumes the entire input buffer. */ MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor *d); /* Create tdefl_compress() flags given zlib-style compression parameters. */ /* level may range from [0,10] (where 10 is absolute max compression, but may be * much slower on some files) */ /* window_bits may be -15 (raw deflate) or 15 (zlib) */ /* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, * MZ_RLE, or MZ_FIXED */ MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); #ifndef MINIZ_NO_MALLOC /* Allocate the tdefl_compressor structure in C so that */ /* non-C language bindings to tdefl_ API don't need to worry about */ /* structure size and allocation mechanism. */ MINIZ_EXPORT tdefl_compressor *tdefl_compressor_alloc(void); MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp); #endif #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ #pragma once /* ------------------- Low-level Decompression API Definitions */ #ifndef MINIZ_NO_INFLATE_APIS #ifdef __cplusplus extern "C" { #endif /* Decompression flags used by tinfl_decompress(). */ /* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and * ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the * input is a raw deflate stream. */ /* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available * beyond the end of the supplied input buffer. If clear, the input buffer * contains all remaining input. */ /* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large * enough to hold the entire decompressed stream. If clear, the output buffer is * at least the size of the dictionary (typically 32KB). */ /* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the * decompressed bytes. */ enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, TINFL_FLAG_COMPUTE_ADLER32 = 8 }; /* High level decompression functions: */ /* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block * allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data * to decompress. */ /* On return: */ /* Function returns a pointer to the decompressed data, or NULL on failure. */ /* *pOut_len will be set to the decompressed data's size, which could be larger * than src_buf_len on uncompressible data. */ /* The caller must call mz_free() on the returned block when it's no longer * needed. */ MINIZ_EXPORT void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block * in memory. */ /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes * written on success. */ #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an * internal 32KB buffer, and a user provided callback function will be called to * flush the buffer. */ /* Returns 1 on success or 0 on failure. */ typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); MINIZ_EXPORT int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; #ifndef MINIZ_NO_MALLOC /* Allocate the tinfl_decompressor structure in C so that */ /* non-C language bindings to tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ MINIZ_EXPORT tinfl_decompressor *tinfl_decompressor_alloc(void); MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor *pDecomp); #endif /* Max size of LZ dictionary. */ #define TINFL_LZ_DICT_SIZE 32768 /* Return status. */ typedef enum { /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ TINFL_STATUS_BAD_PARAM = -3, /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ TINFL_STATUS_ADLER32_MISMATCH = -2, /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ TINFL_STATUS_FAILED = -1, /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ TINFL_STATUS_DONE = 0, /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ TINFL_STATUS_NEEDS_MORE_INPUT = 1, /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ /* so I may need to add some code to address this. */ TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; /* Initializes the decompressor to its initial state. */ #define tinfl_init(r) \ do { \ (r)->m_state = 0; \ } \ MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 /* Main low-level decompressor coroutine function. This is the only function * actually needed for decompression. All the other functions are just * high-level helpers for improved usability. */ /* This is a universal API, i.e. it can be used as a building block to build any * desired higher level decompression API. In the limit case, it can be called * once per every byte input or output. */ MINIZ_EXPORT tinfl_status tinfl_decompress( tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); /* Internal/private bits follow. */ enum { TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #else #define TINFL_USE_64BIT_BITBUF 0 #endif #if TINFL_USE_64BIT_BITBUF typedef mz_uint64 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) #endif struct tinfl_decompressor_tag { mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE]; mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2]; mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2]; mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0]; mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1]; mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ #pragma once /* ------------------- ZIP archive reading/writing */ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif enum { /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 }; typedef struct { /* Central directory file index. */ mz_uint32 m_file_index; /* Byte offset of this entry in the archive's central directory. Note we * currently only support up to UINT_MAX or less bytes in the central dir. */ mz_uint64 m_central_dir_ofs; /* These fields are copied directly from the zip's central dir. */ mz_uint16 m_version_made_by; mz_uint16 m_version_needed; mz_uint16 m_bit_flag; mz_uint16 m_method; /* CRC-32 of uncompressed data. */ mz_uint32 m_crc32; /* File's compressed size. */ mz_uint64 m_comp_size; /* File's uncompressed size. Note, I've seen some old archives where directory * entries had 512 bytes for their uncompressed sizes, but when you try to * unpack them you actually get 0 bytes. */ mz_uint64 m_uncomp_size; /* Zip internal and external file attributes. */ mz_uint16 m_internal_attr; mz_uint32 m_external_attr; /* Entry's local header file offset in bytes. */ mz_uint64 m_local_header_ofs; /* Size of comment in bytes. */ mz_uint32 m_comment_size; /* MZ_TRUE if the entry appears to be a directory. */ mz_bool m_is_directory; /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip * doesn't support) */ mz_bool m_is_encrypted; /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a * compression method we support. */ mz_bool m_is_supported; /* Filename. If string ends in '/' it's a subdirectory entry. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; /* Comment field. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; #ifdef MINIZ_NO_TIME MZ_TIME_T m_padding; #else MZ_TIME_T m_time; #endif } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef enum { MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000, /*After adding a compressed file, seek back to local file header and set the correct sizes*/ MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000 } mz_zip_flags; typedef enum { MZ_ZIP_TYPE_INVALID = 0, MZ_ZIP_TYPE_USER, MZ_ZIP_TYPE_MEMORY, MZ_ZIP_TYPE_HEAP, MZ_ZIP_TYPE_FILE, MZ_ZIP_TYPE_CFILE, MZ_ZIP_TOTAL_TYPES } mz_zip_type; /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or * modify this enum. */ typedef enum { MZ_ZIP_NO_ERROR = 0, MZ_ZIP_UNDEFINED_ERROR, MZ_ZIP_TOO_MANY_FILES, MZ_ZIP_FILE_TOO_LARGE, MZ_ZIP_UNSUPPORTED_METHOD, MZ_ZIP_UNSUPPORTED_ENCRYPTION, MZ_ZIP_UNSUPPORTED_FEATURE, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, MZ_ZIP_NOT_AN_ARCHIVE, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, MZ_ZIP_UNSUPPORTED_MULTIDISK, MZ_ZIP_DECOMPRESSION_FAILED, MZ_ZIP_COMPRESSION_FAILED, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, MZ_ZIP_CRC_CHECK_FAILED, MZ_ZIP_UNSUPPORTED_CDIR_SIZE, MZ_ZIP_ALLOC_FAILED, MZ_ZIP_FILE_OPEN_FAILED, MZ_ZIP_FILE_CREATE_FAILED, MZ_ZIP_FILE_WRITE_FAILED, MZ_ZIP_FILE_READ_FAILED, MZ_ZIP_FILE_CLOSE_FAILED, MZ_ZIP_FILE_SEEK_FAILED, MZ_ZIP_FILE_STAT_FAILED, MZ_ZIP_INVALID_PARAMETER, MZ_ZIP_INVALID_FILENAME, MZ_ZIP_BUF_TOO_SMALL, MZ_ZIP_INTERNAL_ERROR, MZ_ZIP_FILE_NOT_FOUND, MZ_ZIP_ARCHIVE_TOO_LARGE, MZ_ZIP_VALIDATION_FAILED, MZ_ZIP_WRITE_CALLBACK_FAILED, MZ_ZIP_TOTAL_ERRORS } mz_zip_error; typedef struct { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; /* We only support up to UINT32_MAX files in zip64 mode. */ mz_uint32 m_total_files; mz_zip_mode m_zip_mode; mz_zip_type m_zip_type; mz_zip_error m_last_error; mz_uint64 m_file_offset_alignment; mz_alloc_func m_pAlloc; mz_free_func m_pFree; mz_realloc_func m_pRealloc; void *m_pAlloc_opaque; mz_file_read_func m_pRead; mz_file_write_func m_pWrite; mz_file_needs_keepalive m_pNeeds_keepalive; void *m_pIO_opaque; mz_zip_internal_state *m_pState; } mz_zip_archive; typedef struct { mz_zip_archive *pZip; mz_uint flags; int status; mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf; void *pWrite_buf; size_t out_blk_remain; tinfl_decompressor inflator; #ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS mz_uint padding; #else mz_uint file_crc32; #endif } mz_zip_reader_extract_iter_state; /* -------- ZIP reading */ /* Inits a ZIP archive reader. */ /* These functions read and validate the archive's central directory. */ MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); #ifndef MINIZ_NO_STDIO /* Read a archive from a disk file. */ /* file_start_ofs is the file offset where the archive actually begins, or 0. */ /* actual_archive_size is the true total size of the archive, which may be * smaller than the file's actual size on disk. If zero the entire file is * treated as the archive. */ MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); /* Read an archive from an already opened FILE, beginning at the current file * position. */ /* The archive is assumed to be archive_size bytes long. If archive_size is 0, * then the entire rest of the file is assumed to contain the archive. */ /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); #endif /* Ends archive reading, freeing all allocations, and closing the input archive * file if mz_zip_reader_init_file() was used. */ MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive *pZip); /* -------- ZIP reading or writing */ /* Clears a mz_zip_archive struct to all zeros. */ /* Important: This must be done before passing the struct to any mz_zip * functions. */ MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive *pZip); MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); /* Returns the total number of files in the archive. */ MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); MINIZ_EXPORT mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); MINIZ_EXPORT MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. * These functions retrieve/manipulate this field. */ /* Note that the m_last_error functionality is not thread safe. */ MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err); /* MZ_TRUE if the archive file entry is a directory entry. */ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the file is encrypted/strong encrypted. */ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the compression method is supported, and the file is not * encrypted, and the file is not a compressed patch file. */ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); /* Retrieves the filename of an archive file entry. */ /* Returns the number of bytes written to pFilename, or if filename_buf_size is * 0 this function returns the number of bytes needed to fully store the * filename. */ MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); /* Attempts to locates a file in the archive's central directory. */ /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ /* Returns -1 if the file cannot be found. */ MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); /* Returns detailed information about an archive file entry. */ MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); /* MZ_TRUE if the file is in zip64 format. */ /* A file is considered zip64 if it contained a zip64 end of central directory * marker, or if it contained any zip64 extended file information fields in the * central directory. */ MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); /* Returns the total central directory size in bytes. */ /* The current max supported size is <= MZ_UINT32_MAX. */ MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); /* Extracts a archive file to a memory buffer using no memory allocation. */ /* There must be at least enough room on the stack to store the inflator's state * (~34KB or so). */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc( mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); /* Extracts a archive file to a memory buffer. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); /* Extracts a archive file to a dynamically allocated heap buffer. */ /* The memory will be allocated via the mz_zip_archive's alloc/realloc * functions. */ /* Returns NULL and sets the last error on failure. */ MINIZ_EXPORT void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); MINIZ_EXPORT void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); /* Extracts a archive file using a callback function to output the file's data. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback( mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback( mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); /* Extract a file iteratively */ MINIZ_EXPORT mz_zip_reader_extract_iter_state * mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); MINIZ_EXPORT mz_zip_reader_extract_iter_state * mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read( mz_zip_reader_extract_iter_state *pState, void *pvBuf, size_t buf_size); MINIZ_EXPORT mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state *pState); #ifndef MINIZ_NO_STDIO /* Extracts a archive file to a disk file and sets its last accessed and * modified times. */ /* This function only extracts files, not archive directory records. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file( mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); /* Extracts a archive file starting at the current position in the destination * FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile( mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); #endif #if 0 /* TODO */ typedef void *mz_zip_streaming_extract_state_ptr; mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs); size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); #endif /* This function compares the archive's local headers, the optional local zip64 * extended information block, and the optional descriptor following the * compressed data vs. the data in the central directory. */ /* It also validates that each file can be successfully uncompressed unless the * MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); /* Validates an entire archive by calling mz_zip_validate_file() on each file. */ MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); /* Misc utils/helpers, valid for ZIP reading or writing */ MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); #ifndef MINIZ_NO_STDIO MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); #endif /* Universal end function - calls either mz_zip_reader_end() or * mz_zip_writer_end(). */ MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive *pZip); /* -------- ZIP writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS /* Inits a ZIP archive writer. */ /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init * or mz_zip_writer_init_v2*/ /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases * only by n*/ MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_writer_init_heap( mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2( mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); #ifndef MINIZ_NO_STDIO MINIZ_EXPORT mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2( mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); #endif /* Converts a ZIP archive reader object into a writer object, to allow efficient * in-place file appends to occur on an existing archive. */ /* For archives opened using mz_zip_reader_init_file, pFilename must be the * archive's filename so it can be reopened for writing. If the file can't be * reopened, mz_zip_reader_end() will be called. */ /* For archives opened using mz_zip_reader_init_mem, the memory block must be * growable using the realloc callback (which defaults to realloc unless you've * overridden it). */ /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's * user provided m_pWrite function cannot be NULL. */ /* Note: In-place archive modification is not recommended unless you know what * you're doing, because if execution stops or something goes wrong before */ /* the archive is finalized the file's central directory will be hosed. */ MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2_noreopen( mz_zip_archive *pZip, const char *pFilename, mz_uint flags); /* Adds the contents of a memory buffer to an archive. These functions record * the current local time into the archive. */ /* To add a directory entry, call this method with an archive name ending in a * forwardslash with an empty buffer. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or * just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, * and optionally supply the function with already compressed data. */ /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA * flag is specified. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex( mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2( mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); /* Adds the contents of a file to an archive. This function also records the * disk file's modified time into the archive. */ /* File data is supplied via a read callback function. User * mz_zip_writer_add_(c)file to add a file directly.*/ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO /* Adds the contents of a disk file to an archive. This function also records * the disk file's modified time into the archive. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or * just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_file( mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes); /* Like mz_zip_writer_add_file(), except the file data is read from the * specified FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #endif /* Adds a file to an archive by fully cloning the data from another archive. */ /* This function fully clones the source file's compressed data (no * recompression), along with its full filename, extra data (it may add or * modify the zip64 local header extra data field), and the optional descriptor * following the compressed data. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader( mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); /* Finalizes the archive by writing the central directory records followed by * the end of central directory record. */ /* After an archive is finalized, the only valid call on the mz_zip_archive * struct is mz_zip_writer_end(). */ /* An archive must be manually finalized by calling this function for it to be * valid. */ MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); /* Finalizes a heap archive, returning a pointer to the heap block and its size. */ /* The heap block will be allocated using the mz_zip_archive's alloc/realloc * callbacks. */ MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); /* Ends archive writing, freeing all allocations, and closing the output file if * mz_zip_writer_init_file() was used. */ /* Note for the archive to be valid, it *must* have been finalized before ending * (this function will not do it for you). */ MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive *pZip); /* -------- Misc. high-level helper functions: */ /* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) * appends a memory blob to a ZIP archive. */ /* Note this is NOT a fully safe operation. If it crashes or dies in some way * your archive can be left in a screwed up state (without a central directory). */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or * just set to MZ_DEFAULT_COMPRESSION. */ /* TODO: Perhaps add an option to leave the existing central dir in place in * case the add dies? We could then truncate the file (so the old central dir * would be at the end) if something goes wrong. */ MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place( const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2( const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); #ifndef MINIZ_NO_STDIO /* Reads a single file from an archive into a heap block. */ /* If pComment is not NULL, only the file with the specified comment will be * extracted. */ /* Returns NULL on failure. */ MINIZ_EXPORT void * mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2( const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); #endif #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifdef __cplusplus } #endif #endif /* MINIZ_NO_ARCHIVE_APIS */ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API's */ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C * implementation that balances processor cache usage against speed": * http://www.geocities.com/malbrain/ */ #if 0 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } return ~crcu32; } #elif defined(USE_EXTERNAL_MZCRC) /* If USE_EXTERNAL_CRC is defined, an external module will export the * mz_crc32() symbol for us to use, e.g. an SSE-accelerated version. * Depending on the impl, it may be necessary to ~ the input/output crc values. */ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len); #else /* Faster, but larger CPU cache footprint. */ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; while (buf_len >= 4) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; pByte_buf += 4; buf_len -= 4; } while (buf_len) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++pByte_buf; --buf_len; } return ~crc32; } #endif void mz_free(void *p) { MZ_FREE(p); } MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } const char *mz_version(void) { return MZ_VERSION; } #ifndef MINIZ_NO_ZLIB_APIS #ifndef MINIZ_NO_DEFLATE_APIS int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { tdefl_compressor *pComp; mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); if (!pStream) return MZ_STREAM_ERROR; if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; pStream->msg = NULL; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; if (!pStream->avail_out) return MZ_BUF_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; for (;;) { tdefl_status defl_status; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; } else if (!pStream->avail_out) break; else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; /* Can't make forward progress without some input. */ } } return mz_status; } int mz_deflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; /* This is really over conservative. (And lame, but it's actually pretty * tricky to compute a true upper bound given the way tdefl's blocking works.) */ return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong pSource_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ #else if ((mz_uint64)(pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; #endif stream.next_in = pSource; stream.avail_in = (mz_uint32)pSource_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); if (status != MZ_OK) return status; status = mz_deflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } *pDest_len = stream.total_out; return mz_deflateEnd(&stream); } int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } #endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ #ifndef MINIZ_NO_INFLATE_APIS typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); if (!pDecomp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; pDecomp->m_window_bits = window_bits; return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflateReset(mz_streamp pStream) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; pDecomp = (inflate_state *)pStream->state; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; /* pDecomp->m_window_bits = window_bits */; return MZ_OK; } int mz_inflate(mz_streamp pStream, int flush) { inflate_state *pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState = (inflate_state *)pStream->state; if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; first_call = pState->m_first_call; pState->m_first_call = 0; if (pState->m_last_status < 0) return MZ_DATA_ERROR; if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); if ((flush == MZ_FINISH) && (first_call)) { /* MZ_FINISH on the first call implies that the input and output buffers are * large enough to hold the entire compressed/decompressed file. */ decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } /* flush != MZ_FINISH then we must assume there's more input. */ if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } for (;;) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; status = tinfl_decompress( &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ else if (flush == MZ_FINISH) { /* The output buffer MUST be large to hold the remaining uncompressed data * when flush==MZ_FINISH. */ if (status == TINFL_STATUS_DONE) return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's * at least 1 more byte on the way. If there's no more room left in the * output buffer then something is wrong. */ else if (!pStream->avail_out) return MZ_BUF_ERROR; } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) break; } return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong *pSource_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ #else if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; #endif stream.next_in = pSource; stream.avail_in = (mz_uint32)*pSource_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_inflateInit(&stream); if (status != MZ_OK) return status; status = mz_inflate(&stream, MZ_FINISH); *pSource_len = *pSource_len - stream.avail_in; if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_uncompress2(pDest, pDest_len, pSource, &source_len); } #endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ const char *mz_error(int err) { static struct { int m_err; const char *m_pDesc; } s_error_descs[] = {{MZ_OK, ""}, {MZ_STREAM_END, "stream end"}, {MZ_NEED_DICT, "need dictionary"}, {MZ_ERRNO, "file error"}, {MZ_STREAM_ERROR, "stream error"}, {MZ_DATA_ERROR, "data error"}, {MZ_MEM_ERROR, "out of memory"}, {MZ_BUF_ERROR, "buf error"}, {MZ_VERSION_ERROR, "version error"}, {MZ_PARAM_ERROR, "parameter error"}}; mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; return NULL; } #endif /*MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifndef MINIZ_NO_DEFLATE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression (independent from all decompression * API's) */ /* Purposely making these tables static for faster init and thread safety. */ static const mz_uint16 s_tdefl_len_sym[256] = { 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285}; static const mz_uint8 s_tdefl_len_extra[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; /* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted * values. */ typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_ARR(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32 *pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq *t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } /* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, * alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next = 1; next < n - 1; next++) { if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key; if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); } A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; while (avbl > 0) { while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } while (avbl > used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2 * used; dpth++; used = 0; } } /* Limits canonical Huffman code table's max code size. */ enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_ARR(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]); MZ_CLEAR_ARR(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) \ do { \ mz_uint bits = b; \ mz_uint len = l; \ MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); \ d->m_bits_in += len; \ while (d->m_bits_in >= 8) { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } \ MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() \ { \ if (rle_repeat_count) { \ if (rle_repeat_count < 3) { \ d->m_huff_count[2][prev_code_size] = \ (mz_uint16)(d->m_huff_count[2][prev_code_size] + \ rle_repeat_count); \ while (rle_repeat_count--) \ packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } else { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 16; \ packed_code_sizes[num_packed_code_sizes++] = \ (mz_uint8)(rle_repeat_count - 3); \ } \ rle_repeat_count = 0; \ } \ } #define TDEFL_RLE_ZERO_CODE_SIZE() \ { \ if (rle_z_count) { \ if (rle_z_count < 3) { \ d->m_huff_count[2][0] = \ (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ while (rle_z_count--) \ packed_code_sizes[num_packed_code_sizes++] = 0; \ } else if (rle_z_count <= 10) { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 17; \ packed_code_sizes[num_packed_code_sizes++] = \ (mz_uint8)(rle_z_count - 3); \ } else { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 18; \ packed_code_sizes[num_packed_code_sizes++] = \ (mz_uint8)(rle_z_count - 11); \ } \ rle_z_count = 0; \ } \ } static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS( d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) \ { \ bit_buffer |= (((mz_uint64)(b)) << bits_in); \ bits_in += (l); \ } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0]; mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64)); pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ MINIZ_HAS_64BIT_REGISTERS */ static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { const mz_uint8 cmf = 0x78; mz_uint8 flg, flevel = 3; mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint); /* Determine compression level by reversing the process in * tdefl_create_comp_flags_from_zip_params() */ for (i = 0; i < mz_un; i++) if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF)) break; if (i < 2) flevel = 0; else if (i < 6) flevel = 1; else if (i == 6) flevel = 2; header = cmf << 8 | (flevel << 6); header += 31 - (header % 31); flg = header & 0xFF; TDEFL_PUT_BITS(cmf, 8); TDEFL_PUT_BITS(flg, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); /* If the block gets expanded, forget the current contents of the output * buffer and send a raw block instead. */ if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS( d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); } else if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN( (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #ifdef MINIZ_UNALIGNED_USE_MEMCPY static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8 *p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16 *p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } #else #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) #define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) #endif static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || \ ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16 *)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) continue; p = s; probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || \ ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && \ (d->m_dict[probe_pos + match_len - 1] == c1)) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #ifdef MINIZ_UNALIGNED_USE_MEMCPY static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8 *p) { mz_uint32 ret; memcpy(&ret, p, sizeof(mz_uint32)); return ret; } #else #define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) #endif static mz_bool tdefl_compress_fast(tdefl_compressor *d) { /* Faster, minimally featured LZRW1-style match+parse loop with better * register utilization. Intended for applications where raw throughput is * valued more highly than ratio. */ mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32( d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); #ifdef MINIZ_UNALIGNED_USE_MEMCPY memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); #else *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; #endif pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; /* Update dictionary and hash chains. Keeps the lookahead size equal to * TDEFL_MAX_MATCH_LEN. */ if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; /* Simple lazy/greedy parsing state machine. */ len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } /* Move the lookahead forward by len_to_move bytes. */ d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); /* Check if it's time to flush the current LZ codes to the internal output * buffer. */ if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_ARR(d->m_hash); MZ_CLEAR_ARR(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_ARR(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; *d->m_pLZ_flags = 0; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_ARR(d->m_dict); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); MZ_FREE(pComp); return succeeded; } typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; if (new_size > p->m_capacity) { size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; } memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; return MZ_TRUE; } void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output( pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_buf) return 0; out_buf.m_pBuf = (mz_uint8 *)pOut_buf; out_buf.m_capacity = out_buf_len; if (!tdefl_compress_mem_to_output( pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; return out_buf.m_size; } /* level may actually range from [0,10] (10 is a "hidden" max level, where we * want a bit more compression and it's fine if throughput to fall off a cliff * on some files). */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4204) /* nonstandard extension used : non-constant \ aggregate initializer (also supported by \ GNU C and C99, so no big deal) */ #endif /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was * defined. */ static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; if (!pComp) return NULL; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } /* write dummy header */ for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); /* compress image data */ tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } /* write real header */ *pLen_out = out_buf.m_size - 41; { static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; mz_uint8 pnghdr[41] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x44, 0x41, 0x54}; pnghdr[18] = (mz_uint8)(w >> 8); pnghdr[19] = (mz_uint8)w; pnghdr[22] = (mz_uint8)(h >> 8); pnghdr[23] = (mz_uint8)h; pnghdr[25] = chans[num_chans]; pnghdr[33] = (mz_uint8)(*pLen_out >> 24); pnghdr[34] = (mz_uint8)(*pLen_out >> 16); pnghdr[35] = (mz_uint8)(*pLen_out >> 8); pnghdr[36] = (mz_uint8)*pLen_out; c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); for (i = 0; i < 4; ++i, c <<= 8) ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); memcpy(out_buf.m_pBuf, pnghdr, 41); } /* write footer (IDAT CRC-32, followed by IEND chunk) */ if (!tdefl_output_buffer_putter( "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i < 4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); /* compute final size of file, grab compressed data buffer and return */ *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; } void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we * can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's * where #defined out) */ return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } #ifndef MINIZ_NO_MALLOC /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tdefl_compressor *tdefl_compressor_alloc(void) { return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); } void tdefl_compressor_free(tdefl_compressor *pComp) { MZ_FREE(pComp); } #endif #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifndef MINIZ_NO_INFLATE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Decompression (completely independent from all * compression API's) */ #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) #define TINFL_CR_BEGIN \ switch (r->m_state) { \ case 0: #define TINFL_CR_RETURN(state_index, result) \ do { \ status = result; \ r->m_state = state_index; \ goto common_exit; \ case state_index:; \ } \ MZ_MACRO_END #define TINFL_CR_RETURN_FOREVER(state_index, result) \ do { \ for (;;) { \ TINFL_CR_RETURN(state_index, result); \ } \ } \ MZ_MACRO_END #define TINFL_CR_FINISH } #define TINFL_GET_BYTE(state_index, c) \ do { \ while (pIn_buf_cur >= pIn_buf_end) { \ TINFL_CR_RETURN(state_index, \ (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) \ ? TINFL_STATUS_NEEDS_MORE_INPUT \ : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ } \ c = *pIn_buf_cur++; \ } \ MZ_MACRO_END #define TINFL_NEED_BITS(state_index, n) \ do { \ mz_uint c; \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < (mz_uint)(n)) #define TINFL_SKIP_BITS(state_index, n) \ do { \ if (num_bits < (mz_uint)(n)) { \ TINFL_NEED_BITS(state_index, n); \ } \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END #define TINFL_GET_BITS(state_index, b, n) \ do { \ if (num_bits < (mz_uint)(n)) { \ TINFL_NEED_BITS(state_index, n); \ } \ b = bit_buf & ((1 << (n)) - 1); \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END /* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes * remaining in the input buffer falls below 2. */ /* It reads just enough bytes from the input stream that are needed to decode * the next Huffman code (and absolutely no more). It works by trying to fully * decode a */ /* Huffman code by using whatever bits are currently present in the bit buffer. * If this fails, it reads another byte, and tries again until it succeeds or * until the */ /* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ #define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \ do { \ temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ if (temp >= 0) { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ break; \ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); \ if (temp >= 0) \ break; \ } \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < 15); /* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex * than you would initially expect because the zlib API expects the decompressor * to never read */ /* beyond the final byte of the deflate stream. (In other words, when this macro * wants to read another byte from the input, it REALLY needs another byte in * order to fully */ /* decode the next Huffman code.) Handling this properly is particularly * important on raw deflate (non-zlib) streams, which aren't followed by a byte * aligned adler-32. */ /* The slow path is only executed at the very end of the input buffer. */ /* v1.16: The original macro handled the case at the very end of the passed-in * input buffer, but we also need to handle the case where the user passes in * 1+zillion bytes */ /* following the deflate data and our non-conservative read-ahead path won't * kick in here on this code. This is much trickier. */ #define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \ do { \ int temp; \ mz_uint code_len, c; \ if (num_bits < 15) { \ if ((pIn_buf_end - pIn_buf_cur) < 2) { \ TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \ } else { \ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ pIn_buf_cur += 2; \ num_bits += 16; \ } \ } \ if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while (temp < 0); \ } \ sym = temp; \ bit_buf >>= code_len; \ num_bits -= code_len; \ } \ MZ_MACRO_END static void tinfl_clear_tree(tinfl_decompressor *r) { if (r->m_type == 0) MZ_CLEAR_ARR(r->m_tree_0); else if (r->m_type == 1) MZ_CLEAR_ARR(r->m_tree_1); else MZ_CLEAR_ARR(r->m_tree_2); } tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { static const mz_uint16 s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const mz_uint8 s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; static const mz_uint16 s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const mz_uint8 s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; static const mz_uint16 s_min_table_sizes[3] = {257, 1, 4}; mz_int16 *pTrees[3]; mz_uint8 *pCode_sizes[3]; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next ? pOut_buf_next + *pOut_buf_size : NULL; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; /* Ensure the output buffer's size is a power of 2, unless the output buffer * is large enough to hold the entire output file (in which case it doesn't * matter). */ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } pTrees[0] = r->m_tree_0; pTrees[1] = r->m_tree_1; pTrees[2] = r->m_tree_2; pCode_sizes[0] = r->m_code_size_0; pCode_sizes[1] = r->m_code_size_1; pCode_sizes[2] = r->m_code_size_2; num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; TINFL_CR_BEGIN bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } } do { TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } while (counter) { size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } while (pIn_buf_cur >= pIn_buf_end) { TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); } n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; } } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { mz_uint8 *p = r->m_code_size_0; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_code_size_1, 5, 32); for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; } else { for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } MZ_CLEAR_ARR(r->m_code_size_2); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for (; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; mz_int16 *pLookUp; mz_int16 *pTree; mz_uint8 *pCode_size; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pLookUp = r->m_look_up[r->m_type]; pTree = pTrees[r->m_type]; pCode_size = pCode_sizes[r->m_type]; MZ_CLEAR_ARR(total_syms); TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0])); tinfl_clear_tree(r); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pCode_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pLookUp[rev_code] = k; rev_code += (1 << code_size); } continue; } if (0 == (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); if (!pTree[-tree_cur - 1]) { pTree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); pTree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { mz_uint s; TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; } if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for (;;) { mz_uint8 *pSrc; for (;;) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)counter; } else { int sym2; mz_uint code_len; #if TINFL_USE_64BIT_BITBUF if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; bit_buf >>= code_len; num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; } pOut_buf_cur[1] = (mz_uint8)sym2; pOut_buf_cur += 2; } } if ((counter &= 511) == 256) break; num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; if ((dist == 0 || dist > dist_from_out_buf_start || dist_from_out_buf_start == 0) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { while (counter--) { while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); do { #ifdef MINIZ_UNALIGNED_USE_MEMCPY memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32) * 2); #else ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; #endif pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); if ((counter &= 7) < 3) { if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } continue; } } #endif while (counter > 2) { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; pOut_buf_cur += 3; pSrc += 3; counter -= 3; } if (counter > 0) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } } } } while (!(r->m_final & 1)); /* Ensure byte alignment and put back any bytes from the bitbuf if we've * looked ahead too far on gzip, or other Deflate streams followed by * arbitrary data. */ /* I'm being super conservative here. A number of simplifications can be made * to the byte alignment part, and the Adler32 check shouldn't ever need to * worry about reading from the bitbuf now. */ TINFL_SKIP_BITS(32, num_bits & 7); while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits); MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: /* As long as we aren't telling the caller that we NEED more input to make * forward progress: */ /* Put back any bytes from the bitbuf in case we've looked ahead too far on * gzip, or other Deflate streams followed by arbitrary data. */ /* We need to be very careful here to NOT push back any bytes we definitely * know we need to make forward progress, though, or we'll lock the caller up * into an inf loop. */ if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) { while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } } r->m_num_bits = num_bits; r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits); r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } /* Higher level helper functions. */ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for (;;) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; tinfl_status status = tinfl_decompress( &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; if (status == TINFL_STATUS_DONE) break; new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); if (!pNew_buf) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; } return pBuf; } size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; memset(pDict, 0, TINFL_LZ_DICT_SIZE); tinfl_init(&decomp); for (;;) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); } MZ_FREE(pDict); *pIn_buf_size = in_buf_ofs; return result; } #ifndef MINIZ_NO_MALLOC tinfl_decompressor *tinfl_decompressor_alloc(void) { tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); if (pDecomp) tinfl_init(pDecomp); return pDecomp; } void tinfl_decompressor_free(tinfl_decompressor *pDecomp) { MZ_FREE(pDecomp); } #endif #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * Copyright 2016 Martin Raiber * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- .ZIP archive reading */ #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #if defined(_MSC_VER) || defined(__MINGW64__) #define WIN32_LEAN_AND_MEAN #include static WCHAR *mz_utf8z_to_widechar(const char *str) { int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); WCHAR *wStr = (WCHAR *)malloc(reqChars * sizeof(WCHAR)); MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars); return wStr; } static FILE *mz_fopen(const char *pFilename, const char *pMode) { WCHAR *wFilename = mz_utf8z_to_widechar(pFilename); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; #ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN pFile = _wfopen(wFilename, wMode); #else errno_t err = _wfopen_s(&pFile, wFilename, wMode); #endif free(wFilename); free(wMode); #ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN return pFile; #else return err ? NULL : pFile; #endif } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { WCHAR *wPath = mz_utf8z_to_widechar(pPath); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; #ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN pFile = _wfreopen(wPath, wMode, pStream); #else errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); #endif free(wPath); free(wMode); #ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN return pFile; #else return err ? NULL : pFile; #endif } static int mz_stat64(const char *path, struct __stat64 *buffer) { WCHAR *wPath = mz_utf8z_to_widechar(path); int res = _wstat64(wPath, buffer); free(wPath); return res; } static int mz_mkdir(const char *pDirname) { WCHAR *wDirname = mz_utf8z_to_widechar(pDirname); int res = _wmkdir(wDirname); free(wDirname); return res; } #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT _stat64 #define MZ_FILE_STAT mz_stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove #define MZ_MKDIR(d) mz_mkdir(d) #elif defined(__MINGW32__) || defined(__WATCOMC__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #define MZ_MKDIR(d) _mkdir(d) #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #if defined(_WIN32) || defined(_WIN64) #define MZ_MKDIR(d) _mkdir(d) #else #define MZ_MKDIR(d) mkdir(d, 0755) #endif #elif defined(__USE_LARGEFILE64) /* gcc, clang */ #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT stat64 #define MZ_FILE_STAT stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove #define MZ_MKDIR(d) mkdir(d, 0755) #elif defined(__APPLE__) || defined(__FreeBSD__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen(p, m, s) #define MZ_DELETE_FILE remove #define MZ_MKDIR(d) mkdir(d, 0755) #else #pragma message( \ "Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #ifdef __STRICT_ANSI__ #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #else #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #endif #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #define MZ_MKDIR(d) mkdir(d, 0755) #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ #ifndef CHMOD // Upon successful completion, a value of 0 is returned. // Otherwise, a value of -1 is returned and errno is set to indicate the error. // int chmod(const char *path, mode_t mode); #define CHMOD(f, m) chmod(f, m) #endif #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler * alignment and platform endian issues, miniz.c doesn't use structs for any of * this stuff. */ enum { /* ZIP archive identifiers and record sizes */ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, /* ZIP64 archive identifier and record sizes */ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, /* Central directory header record offsets */ MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, /* Local directory header offsets */ MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, /* End of central directory offsets */ MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, /* ZIP64 End of central directory locator offsets */ MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ /* ZIP64 End of central directory header offsets */ MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 }; typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; /* The flags passed in when the archive is initially opened. */ mz_uint32 m_init_flags; /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ mz_bool m_zip64; /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 * will also be slammed to true too, even if we didn't find a zip64 end of * central dir header, etc.) */ mz_bool m_zip64_has_extended_info_fields; /* These fields are used by the file, FILE, memory, and memory/heap read/write * helpers. */ MZ_FILE *m_pFile; mz_uint64 m_file_archive_start_ofs; void *m_pMem; size_t m_mem_size; size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ (array_ptr)->m_element_size = element_size #if defined(DEBUG) || defined(_DEBUG) static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) { MZ_ASSERT(index < pArray->m_size); return index; } #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ ((element_type *)((array_ptr) \ ->m_p))[mz_zip_array_range_check(array_ptr, index)] #else #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ ((element_type *)((array_ptr)->m_p))[index] #endif static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) { memset(pArray, 0, sizeof(mz_zip_array)); pArray->m_element_size = element_size; } static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } pArray->m_size = new_size; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; if (n > 0) memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); if (err) { *pDOS_date = 0; *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); #endif /* #ifdef _MSC_VER */ *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifndef MINIZ_NO_STDIO #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) { struct MZ_FILE_STAT_STRUCT file_stat; /* On Linux with x86 glibc, this call will fail on large files (I think >= * 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; *pTime = file_stat.st_mtime; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) { struct utimbuf t; memset(&t, 0, sizeof(t)); t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_TIME */ static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) { if (pZip) pZip->m_last_error = err_num; return MZ_FALSE; } static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; pZip->m_last_error = MZ_ZIP_NO_ERROR; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_init_flags = flags; pZip->m_pState->m_zip64 = MZ_FALSE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; pZip->m_zip_mode = MZ_ZIP_MODE_READING; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) \ do { \ mz_uint32 t = a; \ a = b; \ b = t; \ } \ MZ_MACRO_END /* Heap sort of lowercased filenames, used to help accelerate plain central * directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), * but it could allocate memory.) */ static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices; mz_uint32 start, end; const mz_uint32 size = pZip->m_total_files; if (size <= 1U) return; pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); start = (size - 2U) >> 1U; for (;;) { mz_uint64 child, root = start; for (;;) { if ((child = (root << 1U) + 1U) >= size) break; child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } if (!start) break; start--; } end = size - 1; while (end > 0) { mz_uint64 child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); for (;;) { if ((child = (root << 1U) + 1U) >= end) break; child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } end--; } } static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) { mz_int64 cur_file_ofs; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; /* Basic sanity checks - reject files which are too small */ if (pZip->m_archive_size < record_size) return MZ_FALSE; /* Find the record by scanning the file from the end towards the beginning. */ cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); for (;;) { int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) { mz_uint s = MZ_READ_LE32(pBuf + i); if (s == record_sig) { if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) break; } } if (i >= 0) { cur_file_ofs += i; break; } /* Give up if we've searched the entire file, or we've gone back "too far" * (~64kb) */ if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } *pOfs = cur_file_ofs; return MZ_TRUE; } static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; mz_uint64 cdir_ofs = 0; mz_int64 cur_file_ofs = 0; const mz_uint8 *p; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); mz_uint32 zip64_end_of_central_dir_locator_u32 [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; mz_uint32 zip64_end_of_central_dir_header_u32 [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; mz_uint64 zip64_end_of_central_dir_ofs = 0; /* Basic sanity checks - reject files which are too small, and check the first * 4 bytes of the file to make sure a local header is there. */ if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_locate_header_sig( pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); /* Read and verify the end of central directory record. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) { if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) { if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) { zip64_end_of_central_dir_ofs = MZ_READ_LE64( pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { pZip->m_pState->m_zip64 = MZ_TRUE; } } } } } pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); if (pZip->m_pState->m_zip64) { mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64( pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64( pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64( pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (zip64_total_num_of_disks != 1U) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); /* Check for miniz's practical limits */ if (zip64_cdir_total_entries > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; /* Check for miniz's current practical limits (sorry, this should be enough * for millions of files) */ if (zip64_size_of_central_directory > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); cdir_size = (mz_uint32)zip64_size_of_central_directory; num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); } if (pZip->m_total_files != cdir_entries_on_this_disk) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (cdir_size < (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; /* Read the entire central directory into a heap block, and allocate another * heap block to hold the unsorted central dir file record offsets, and * possibly another to hold the sorted indices. */ if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (sort_central_dir) { if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); /* Now create an index into the central directory file records, do some * basic sanity checking on each record */ p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; mz_uint64 comp_size, decomp_size, local_header_ofs; if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && (ext_data_size) && (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) { /* Attempt to find zip64 extended information field in the entry's extra * data */ mz_uint32 extra_size_remaining = ext_data_size; if (extra_size_remaining) { const mz_uint8 *pExtra_data; void *buf = NULL; if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) { buf = MZ_MALLOC(ext_data_size); if (buf == NULL) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } pExtra_data = (mz_uint8 *)buf; } else { pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; } do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { /* Ok, the archive didn't have any zip64 headers but it uses a * zip64 extended information field so mark it as zip64 anyway * (this can occur with infozip's zip util when it reads * compresses files from stdin). */ pZip->m_pState->m_zip64 = MZ_TRUE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); MZ_FREE(buf); } } /* I've seen archives that aren't marked as zip64 that uses zip64 ext * data, argh */ if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) { if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (comp_size != MZ_UINT32_MAX) { if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); n -= total_header_size; p += total_header_size; } } if (sort_central_dir) mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); return MZ_TRUE; } void mz_zip_zero_struct(mz_zip_archive *pZip) { if (pZip) MZ_CLEAR_PTR(pZip); } static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_bool status = MZ_TRUE; if (!pZip) return MZ_FALSE; if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { if (set_last_error) pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_pFree(pZip->m_pAlloc_opaque, pState); } pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { return mz_zip_reader_end_internal(pZip, MZ_TRUE); } mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) { if ((!pZip) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_archive_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) { if (!pMem) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pNeeds_keepalive = NULL; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); } mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) { mz_uint64 file_size; MZ_FILE *pFile; if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); file_size = archive_size; if (!file_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); } file_size = MZ_FTELL64(pFile); } /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_zip_type = MZ_ZIP_TYPE_FILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) { mz_uint64 file_size; MZ_FILE *pFile; if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pFile = MZ_FOPEN(pFilename, "r+b"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); file_size = archive_size; if (!file_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); } file_size = MZ_FTELL64(pFile); } /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_zip_type = MZ_ZIP_TYPE_FILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) { mz_uint64 cur_file_ofs; if ((!pZip) || (!pFile)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); cur_file_ofs = MZ_FTELL64(pFile); if (!archive_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); archive_size = MZ_FTELL64(pFile) - cur_file_ofs; if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = archive_size; pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) return NULL; return &MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; } mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) { mz_uint bit_flag; mz_uint method; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if ((method != 0) && (method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); return MZ_FALSE; } if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); return MZ_FALSE; } if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { mz_uint filename_len, attribute_mapping_id, external_attr; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } /* Bugfix: This code was also checking if the internal attribute was non-zero, * which wasn't correct. */ /* Most/all zip writers (hopefully) set DOS file/directory attributes in the * low 16-bits, so check for the DOS directory flag and ignore the source OS * ID in the created by field. */ /* FIXME: Remove this check? Is it necessary - we already check the filename. */ attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; (void)attribute_mapping_id; external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) { return MZ_TRUE; } return MZ_FALSE; } static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) { mz_uint n; const mz_uint8 *p = pCentral_dir_header; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_FALSE; if ((!p) || (!pStat)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Extract fields from the central directory record. */ pStat->m_file_index = file_index; pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); /* Copy as much of the filename and comment as possible. */ n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; /* Set some flags for convienance */ pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); /* See if we need to read any zip64 extended information fields. */ /* Confusingly, these zip64 fields can be present even on non-zip64 archives * (Debian zip on a huge files from stdin piped to stdout creates them). */ if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) { /* Attempt to find zip64 extended information field in the entry's extra * data */ mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if (extra_size_remaining) { const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; mz_uint32 field_data_remaining = field_data_size; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_TRUE; if (pStat->m_uncomp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_uncomp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_comp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_comp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_local_header_ofs == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); } } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); for (i = 0; i < len; ++i) if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; return MZ_TRUE; } static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( &pState->m_sorted_central_dir_offsets, mz_uint32, 0); const mz_uint32 size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); if (pIndex) *pIndex = 0; if (size) { /* yes I could use uint32_t's, but then we would have to add some special * case checks in the loop, argh, and */ /* honestly the major expense here on 32-bit CPU's will still be the * filename compare */ mz_int64 l = 0, h = (mz_int64)size - 1; while (l <= h) { mz_int64 m = l + ((h - l) >> 1); mz_uint32 file_index = pIndices[(mz_uint32)m]; int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } else if (comp < 0) l = m + 1; else h = m - 1; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { mz_uint32 index; if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) return -1; else return (int)index; } mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) { mz_uint file_index; size_t name_len, comment_len; if (pIndex) *pIndex = 0; if ((!pZip) || (!pZip->m_pState) || (!pName)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* See if we can use a binary search */ if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) { return mz_zip_locate_file_binary_search(pZip, pName, pIndex); } /* Locate the entry by scanning the entire central directory */ name_len = strlen(pName); if (name_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); comment_len = pComment ? strlen(pComment) : 0; if (comment_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); for (file_index = 0; file_index < pZip->m_total_files; file_index++) { const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; if (comment_len) { mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) continue; } if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; do { if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; pFilename += ofs; filename_len -= ofs; } if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } static mz_bool mz_zip_reader_extract_to_mem_no_alloc1( mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size, const mz_zip_archive_file_stat *st) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (st) { file_stat = *st; } else if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Ensure supplied output buffer is large enough. */ needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (buf_size < needed_size) return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); /* Read and parse the local directory entry. */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) { if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); } #endif return MZ_TRUE; } /* Decompress the file either directly from memory or from a file input * buffer. */ tinfl_init(&inflator); if (pZip->m_pState->m_pMem) { /* Read directly from the archive in memory. */ pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else if (pUser_read_buf) { /* Use a user provided read buffer. */ if (!user_read_buf_size) return MZ_FALSE; pRead_buf = (mz_uint8 *)pUser_read_buf; read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } else { /* Temporarily allocate a read buffer. */ read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } do { /* The size_t cast here should be OK because we've verified that the output * buffer is >= file_stat.m_uncomp_size above */ size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress( &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); if (status == TINFL_STATUS_DONE) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); status = TINFL_STATUS_FAILED; } #endif } if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); } mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size, NULL); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, NULL, 0, NULL); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { mz_zip_archive_file_stat file_stat; mz_uint64 alloc_size; void *pBuf; if (pSize) *pSize = 0; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return NULL; alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); return NULL; } if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, (size_t)alloc_size, flags, NULL, 0, &file_stat)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } if (pSize) *pSize = (size_t)alloc_size; return pBuf; } void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) { if (pSize) *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int status = TINFL_STATUS_DONE; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS mz_uint file_crc32 = MZ_CRC32_INIT; #endif mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf = NULL; void *pWrite_buf = NULL; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Read and do some minimal validation of the local directory entry (this * doesn't crack the zip64 stuff, which we already have from the central dir) */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); /* Decompress the file either directly from memory or from a file input * buffer. */ if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pState->m_pMem) { if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); #endif } cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; comp_remaining = 0; } else { while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { file_crc32 = (mz_uint32)mz_crc32( file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); } #endif if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; out_buf_ofs += read_buf_avail; comp_remaining -= read_buf_avail; } } } else { tinfl_decompressor inflator; tinfl_init(&inflator); if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); status = TINFL_STATUS_FAILED; } else { do { mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress( &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; if (out_buf_size) { if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); #endif if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; break; } } } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (file_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; } #endif } if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } mz_zip_reader_extract_iter_state * mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_reader_extract_iter_state *pState; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; /* Argument sanity check */ if ((!pZip) || (!pZip->m_pState)) return NULL; /* Allocate an iterator status structure */ pState = (mz_zip_reader_extract_iter_state *)pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); if (!pState) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } /* Fetch file details */ if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Encryption and patch files are not supported. */ if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Init state - save args */ pState->pZip = pZip; pState->flags = flags; /* Init state - reset variables to defaults */ pState->status = TINFL_STATUS_DONE; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS pState->file_crc32 = MZ_CRC32_INIT; #endif pState->read_buf_ofs = 0; pState->out_buf_ofs = 0; pState->pRead_buf = NULL; pState->pWrite_buf = NULL; pState->out_blk_remain = 0; /* Read and parse the local directory entry. */ pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Decompress the file either directly from memory or from a file input * buffer. */ if (pZip->m_pState->m_pMem) { pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; pState->comp_remaining = pState->file_stat.m_comp_size; } else { if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, therefore intermediate read buffer required */ pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } else { /* Decompression not required - we will be reading directly into user * buffer, no temp buf required */ pState->read_buf_size = 0; } pState->read_buf_avail = 0; pState->comp_remaining = pState->file_stat.m_comp_size; } if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, init decompressor */ tinfl_init(&pState->inflator); /* Allocate write buffer */ if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pState->pRead_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } return pState; } mz_zip_reader_extract_iter_state * mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_uint32 file_index; /* Locate file index by name */ if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return NULL; /* Construct iterator */ return mz_zip_reader_extract_iter_new(pZip, file_index, flags); } size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state *pState, void *pvBuf, size_t buf_size) { size_t copied_to_caller = 0; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) return 0; if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data, calc * amount to return. */ copied_to_caller = (size_t)MZ_MIN(buf_size, pState->comp_remaining); /* Zip is in memory....or requires reading from a file? */ if (pState->pZip->m_pState->m_pMem) { /* Copy data to caller's buffer */ memcpy(pvBuf, pState->pRead_buf, copied_to_caller); pState->pRead_buf = ((mz_uint8 *)pState->pRead_buf) + copied_to_caller; } else { /* Read directly into caller's buffer */ if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) { /* Failed to read all that was asked for, flag failure and alert user */ mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; copied_to_caller = 0; } } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Compute CRC if not returning compressed data only */ if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) pState->file_crc32 = (mz_uint32)mz_crc32( pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); #endif /* Advance offsets, dec counters */ pState->cur_file_ofs += copied_to_caller; pState->out_buf_ofs += copied_to_caller; pState->comp_remaining -= copied_to_caller; } else { do { /* Calc ptr to write buffer - given current output pos and block size */ mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); /* Calc max output size - given current output pos and block size */ size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if (!pState->out_blk_remain) { /* Read more data from file if none available (and reading from file) */ if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) { /* Calc read size */ pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) { mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Advance offsets, dec counters */ pState->cur_file_ofs += pState->read_buf_avail; pState->comp_remaining -= pState->read_buf_avail; pState->read_buf_ofs = 0; } /* Perform decompression */ in_buf_size = (size_t)pState->read_buf_avail; pState->status = tinfl_decompress( &pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); pState->read_buf_avail -= in_buf_size; pState->read_buf_ofs += in_buf_size; /* Update current output block size remaining */ pState->out_blk_remain = out_buf_size; } if (pState->out_blk_remain) { /* Calc amount to return. */ size_t to_copy = MZ_MIN((buf_size - copied_to_caller), pState->out_blk_remain); /* Copy data to caller's buffer */ memcpy((mz_uint8 *)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Perform CRC */ pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); #endif /* Decrement data consumed from block */ pState->out_blk_remain -= to_copy; /* Inc output offset, while performing sanity check */ if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Increment counter of data copied to caller */ copied_to_caller += to_copy; } } while ((copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT))); } /* Return how many bytes were copied into user buffer */ return copied_to_caller; } mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state *pState) { int status; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) return MZ_FALSE; /* Was decompression completed and requested? */ if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); pState->status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (pState->file_crc32 != pState->file_stat.m_crc32) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; } #endif } /* Free buffers */ if (!pState->pZip->m_pState->m_pMem) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); if (pState->pWrite_buf) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); /* Save status */ status = pState->status; /* Free context */ pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); return status == TINFL_STATUS_DONE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); } mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); status = mz_zip_reader_extract_to_callback( pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) { if (status) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) if (status) mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif return status; } mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) { mz_zip_archive_file_stat file_stat; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return mz_zip_reader_extract_to_callback( pZip, file_index, mz_zip_file_write_callback, pFile, flags); } mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); } #endif /* #ifndef MINIZ_NO_STDIO */ static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_uint32 *p = (mz_uint32 *)pOpaque; (void)file_ofs; *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); return n; } mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_archive_file_stat file_stat; mz_zip_internal_state *pState; const mz_uint8 *pCentral_dir_header; mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint64 local_header_ofs = 0; mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; mz_bool has_data_descriptor; mz_uint32 local_header_bit_flags; mz_zip_array file_data_array; mz_zip_array_init(&file_data_array, 1); if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (file_index > pZip->m_total_files) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_is_encrypted) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports stored and deflate. */ if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); if (!file_stat.m_is_supported) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); /* Read and parse the local directory entry. */ local_header_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); has_data_descriptor = (local_header_bit_flags & 8) != 0; if (local_header_filename_len != strlen(file_stat.m_filename)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (!mz_zip_array_resize( pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); goto handle_failure; } if (local_header_filename_len) { if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } /* I've seen 1 archive that had the same pathname, but used backslashes in * the local dir and forward slashes in the central dir. Do we care about * this? For now, this case will fail validation. */ if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_uint32 extra_size_remaining = local_header_extra_len; const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); goto handle_failure; } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); goto handle_failure; } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); goto handle_failure; } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } /* TODO: parse local header extra data when local_header_comp_size is * 0xFFFFFFFF! (big_descriptor.zip) */ /* I've seen zips in the wild with the data descriptor bit set, but proper * local header values and bogus data descriptors */ if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) { mz_uint8 descriptor_buf[32]; mz_bool has_id; const mz_uint8 *pSrc; mz_uint32 file_crc32; mz_uint64 comp_size = 0, uncomp_size = 0; mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; file_crc32 = MZ_READ_LE32(pSrc); if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); } else { comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); } if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } else { if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } mz_zip_array_clear(pZip, &file_data_array); if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) { if (!mz_zip_reader_extract_to_callback( pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) return MZ_FALSE; /* 1 more check to be sure, although the extract checks too. */ if (uncomp_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); return MZ_FALSE; } } return MZ_TRUE; handle_failure: mz_zip_array_clear(pZip, &file_data_array); return MZ_FALSE; } mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) { mz_zip_internal_state *pState; mz_uint32 i; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Basic sanity checks */ if (!pState->m_zip64) { if (pZip->m_total_files > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (pZip->m_archive_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } else { if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } for (i = 0; i < pZip->m_total_files; i++) { if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) { mz_uint32 found_index; mz_zip_archive_file_stat stat; if (!mz_zip_reader_file_stat(pZip, i, &stat)) return MZ_FALSE; if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) return MZ_FALSE; /* This check can fail if there are duplicate filenames in the archive * (which we don't check for when writing - that's up to the user) */ if (found_index != i) return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); } if (!mz_zip_validate_file(pZip, i, flags)) return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if ((!pMem) || (!size)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if (!pFilename) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #endif /* #ifndef MINIZ_NO_STDIO */ /* ------------------- .ZIP archive writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) { mz_write_le32(p, (mz_uint32)v); mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); } #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); if (!n) return 0; /* An allocation this big is likely to just fail on 32-bit systems, so don't * even go there. */ if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); return 0; } if (new_size > pState->m_mem_capacity) { void *pNew_block; size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; if (NULL == (pNew_block = pZip->m_pRealloc( pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return 0; } pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) { mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) { if (!pZip->m_pRead) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (pZip->m_file_offset_alignment) { /* Ensure user specified file offset alignment is a power of 2. */ if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_zip64 = zip64; pZip->m_pState->m_zip64_has_extended_info_fields = zip64; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { return mz_zip_writer_init_v2(pZip, existing_size, 0); } mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_pState->m_mem_capacity = initial_allocation_size; } return MZ_TRUE; } mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) { mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); return 0; } return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); } mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; if (NULL == (pFile = MZ_FOPEN( pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } pZip->m_pState->m_pFile = pFile; pZip->m_zip_type = MZ_ZIP_TYPE_FILE; if (size_to_reserve_at_beginning) { mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_ARR(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_ofs += n; size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) { pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, 0, flags)) return MZ_FALSE; pZip->m_pState->m_pFile = pFile; pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) { /* We don't support converting a non-zip64 file to zip64 - this seems like * more trouble than it's worth. (What about the existing 32-bit data * descriptors that could follow the compressed data?) */ if (!pZip->m_pState->m_zip64) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* No sense in trying to write to an archive that's already at the support max * size */ if (pZip->m_pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO (void)pFilename; return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); #else if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (!pFilename) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Archive is being read from stdio and was originally opened only for * reading. Try to reopen as writable. */ if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { /* The mz_zip_archive is now in a bogus state because pState->m_pFile is * NULL, so just close it. */ mz_zip_reader_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } } pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; #endif /* #ifdef MINIZ_NO_STDIO */ } else if (pState->m_pMem) { /* Archive lives in a memory block. Assume it's from the heap that we can * resize using the realloc callback. */ if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; } /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ else if (!pZip->m_pWrite) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Start writing new files at the archive's current central directory * location. */ /* TODO: We could add a flag that lets the user start writing immediately * AFTER the existing central dir - this would be safer. */ pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_central_directory_file_ofs = 0; /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ /* Even though we're now in write mode, files can still be extracted and * verified, but file locates will be slow. */ /* TODO: We could easily maintain the sorted central directory offsets. */ mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init_from_reader_v2_noreopen(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) { /* We don't support converting a non-zip64 file to zip64 - this seems like * more trouble than it's worth. (What about the existing 32-bit data * descriptors that could follow the compressed data?) */ if (!pZip->m_pState->m_zip64) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* No sense in trying to write to an archive that's already at the support max * size */ if (pZip->m_pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO (void)pFilename; return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); #else if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (!pFilename) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; #endif /* #ifdef MINIZ_NO_STDIO */ } else if (pState->m_pMem) { /* Archive lives in a memory block. Assume it's from the heap that we can * resize using the realloc callback. */ if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; } /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ else if (!pZip->m_pWrite) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Start writing new files at the archive's current central directory * location. */ /* TODO: We could add a flag that lets the user start writing immediately * AFTER the existing central dir - this would be safer. */ pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_central_directory_file_ofs = 0; /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ /* Even though we're now in write mode, files can still be extracted and * verified, but file locates will be slow. */ /* TODO: We could easily maintain the sorted central directory offsets. */ mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); } /* TODO: pArchive_name is a terrible name here! */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE \ (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \ (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) { mz_uint8 *pDst = pBuf; mz_uint32 field_size = 0; MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); MZ_WRITE_LE16(pDst + 2, 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { MZ_WRITE_LE64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pComp_size) { MZ_WRITE_LE64(pDst, *pComp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pLocal_header_ofs) { MZ_WRITE_LE64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } MZ_WRITE_LE16(pBuf + 2, field_size); return (mz_uint32)(pDst - pBuf); } static mz_bool mz_zip_writer_create_local_dir_header( mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; } static mz_bool mz_zip_writer_create_central_dir_header( mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); return MZ_TRUE; } static mz_bool mz_zip_writer_add_to_central_dir( mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; if (!pZip->m_pState->m_zip64) { if (local_header_ofs > 0xFFFFFFFF) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!mz_zip_writer_create_central_dir_header( pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { /* Try to resize the central directory array back into its original state. */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } return MZ_TRUE; } static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { /* Basic ZIP archive filename validity checks: Valid filenames cannot start * with a forward slash, cannot contain a drive letter, and cannot use * DOS-style backward slashes. */ if (*pArchive_name == '/') return MZ_FALSE; /* Making sure the name does not contain drive letters or DOS style backward * slashes is the responsibility of the program using miniz*/ return MZ_TRUE; } static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); } static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_file_ofs += s; n -= s; } return MZ_TRUE; } mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { return mz_zip_writer_add_mem_ex_v2( pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); } mz_bool mz_zip_writer_add_mem_ex_v2( mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint16 bit_flags = 0; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); #ifndef MINIZ_NO_TIME if (last_modified != NULL) { mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); } else { MZ_TIME_T cur_time; time(&cur_time); mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } #endif /* #ifndef MINIZ_NO_TIME */ if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { /* Set DOS Subdirectory attribute bit. */ ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; /* Subdirectories cannot contain data. */ if ((buf_size) || (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* Try to do any allocations before writing to the archive, so if an * allocation fails the file remains unmodified. (A good idea if we're doing * an in-place modification.) */ if ((!mz_zip_array_ensure_room( pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if ((!store_data_uncompressed) && (buf_size)) { if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes; MZ_CLEAR_ARR(local_dir_header); if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { method = MZ_DEFLATED; } if (pState->m_zip64) { if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header( pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pExtra_data != NULL) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header( pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (store_data_uncompressed) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += buf_size; comp_size = buf_size; } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params( level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pComp = NULL; if (uncomp_size) { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir( pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 gen_flags; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_zip_internal_state *pState; mz_uint64 file_ofs = 0, cur_archive_header_file_ofs; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) ? 0 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) { /* Source file is too large for non-zip64 */ /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ pState->m_zip64 = MZ_TRUE; } /* We could support this, but why? */ if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } } archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } #ifndef MINIZ_NO_TIME if (pFile_time) { mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); } #endif if (max_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_archive_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } if (max_size && level) { method = MZ_DEFLATED; } MZ_CLEAR_ARR(local_dir_header); if (pState->m_zip64) { if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); else extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, NULL, NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header( pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header( pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (max_size) { void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!level) { while (1) { size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); if (n == 0) break; if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } file_ofs += n; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); cur_archive_file_ofs += n; } uncomp_size = file_ofs; comp_size = uncomp_size; } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params( level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); } for (;;) { tdefl_status status; tdefl_flush flush = TDEFL_NO_FLUSH; size_t n = read_callback(callback_opaque, file_ofs, pRead_buf, MZ_ZIP_MAX_IO_BUF_SIZE); if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); break; } file_ofs += n; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) flush = TDEFL_FULL_FLUSH; if (n == 0) flush = TDEFL_FINISH; status = tdefl_compress_buffer(pComp, pRead_buf, n, flush); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; } else if (status != TDEFL_STATUS_OKAY) { mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); break; } } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return MZ_FALSE; } uncomp_size = file_ofs; comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } if (!(level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)) { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) { if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header( pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size, (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); cur_archive_header_file_ofs = local_dir_header_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); if (pExtra_data != NULL) { cur_archive_header_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_header_file_ofs += archive_name_size; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_header_file_ofs += extra_size; } } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir( pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pSrc_file); } mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { return mz_zip_writer_add_read_buf_callback( pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, pFile_time, pComment, comment_size, level_and_flags, ext_attributes, user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); } mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes) { MZ_FILE *pSrc_file = NULL; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; MZ_TIME_T *pFile_time = NULL; mz_bool status; memset(&file_modified_time, 0, sizeof(file_modified_time)); #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) pFile_time = &file_modified_time; if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); #endif pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); MZ_FSEEK64(pSrc_file, 0, SEEK_END); uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); status = mz_zip_writer_add_cfile( pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, ext_attributes, NULL, 0, NULL, 0); MZ_FCLOSE(pSrc_file); return status; } #endif /* #ifndef MINIZ_NO_STDIO */ static mz_bool mz_zip_writer_update_zip64_extension_block( mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, mz_uint32 ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) { /* + 64 should be enough for any new zip64 data */ if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) { mz_uint8 new_ext_block[64]; mz_uint8 *pDst = new_ext_block; mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); mz_write_le16(pDst + sizeof(mz_uint16), 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { mz_write_le64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); } if (pComp_size) { mz_write_le64(pDst, *pComp_size); pDst += sizeof(mz_uint64); } if (pLocal_header_ofs) { mz_write_le64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); } if (pDisk_start) { mz_write_le32(pDst, *pDisk_start); pDst += sizeof(mz_uint32); } mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if ((pExt) && (ext_len)) { mz_uint32 extra_size_remaining = ext_len; const mz_uint8 *pExtra_data = pExt; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } return MZ_TRUE; } /* TODO: This func is now pretty freakin complex due to zip64, split it up? */ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; void *pBuf; const mz_uint8 *pSrc_central_header; mz_zip_archive_file_stat src_file_stat; mz_uint32 src_filename_len, src_comment_len, src_ext_len; mz_uint32 local_header_filename_size, local_header_extra_len; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Don't support copying files from zip64 archives to non-zip64, even though * in some cases this is possible */ if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Get pointer to the source central dir header and crack it */ if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 * fudge factor in case we need to add more extra data) */ if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); if (!pState->m_zip64) { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { /* TODO: Our zip64 support still has some 32-bit limits that may not be * worth fixing. */ if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) return MZ_FALSE; cur_src_file_ofs = src_file_stat.m_local_header_ofs; cur_dst_file_ofs = pZip->m_archive_size; /* Read the source archive's local dir header */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Compute the total size we need to copy (filename+extra data+compressed * data) */ local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; /* Try to find a zip64 extended information field */ if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_zip_array file_data_array; const mz_uint8 *pExtra_data; mz_uint32 extra_size_remaining = local_header_extra_len; mz_zip_array_init(&file_data_array, 1); if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } pExtra_data = (const mz_uint8 *)file_data_array.m_p; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64( pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); mz_zip_array_clear(pZip, &file_data_array); } if (!pState->m_zip64) { /* Try to detect if the new archive will most likely wind up too big and * bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which * could be present, +64 is a fudge factor). */ /* We also check when the archive is finalized so this doesn't need to be * perfect. */ mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; if (approx_new_archive_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } /* Write dest archive padding */ if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } /* The original zip's local header+ext block doesn't change, even with zip64, * so we can just copy it over to the dest zip */ if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Copy over the source archive bytes to the dest archive, also ensure we have * enough buf space to handle optional data descriptor */ if (NULL == (pBuf = pZip->m_pAlloc( pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); while (src_archive_bytes_remaining) { n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } cur_src_file_ofs += n; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_dst_file_ofs += n; src_archive_bytes_remaining -= n; } /* Now deal with the optional data descriptor */ bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); if (bit_flags & 8) { /* Copy data descriptor */ if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { /* src is zip64, dest must be zip64 */ /* name uint32_t's */ /* id 1 (optional in zip64?) */ /* crc 1 */ /* comp_size 2 */ /* uncomp_size 2 */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); } else { /* src is NOT zip64 */ mz_bool has_id; if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); if (pZip->m_pState->m_zip64) { /* dest is zip64, so upgrade the data descriptor */ const mz_uint8 *pSrc_descriptor = (const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0); const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor); const mz_uint64 src_comp_size = MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32)); const mz_uint64 src_uncomp_size = MZ_READ_LE32(pSrc_descriptor + 2 * sizeof(mz_uint32)); mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); n = sizeof(mz_uint32) * 6; } else { /* dest is NOT zip64, just copy it as-is */ n = sizeof(mz_uint32) * (has_id ? 4 : 3); } } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_src_file_ofs += n; cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); /* Finally, add the new central dir header */ orig_central_dir_size = pState->m_central_dir.m_size; memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); if (pState->m_zip64) { /* This is the painful part: We need to write a new central dir header + ext * block with updated zip64 fields, and ensure the old fields (if any) are * not included. */ const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; mz_zip_array new_ext_block; mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); if (!mz_zip_writer_update_zip64_extension_block( &new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) { mz_zip_array_clear(pZip, &new_ext_block); return MZ_FALSE; } MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) { mz_zip_array_clear(pZip, &new_ext_block); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } mz_zip_array_clear(pZip, &new_ext_block); } else { /* sanity checks */ if (cur_dst_file_ofs > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (local_dir_header_ofs >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } } /* This shouldn't trigger unless we screwed up during the initial sanity * checks */ if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) { /* TODO: Support central dirs >= 32-bits in size */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); } n = (mz_uint32)orig_central_dir_size; if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_total_files++; pZip->m_archive_size = cur_dst_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[256]; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } central_dir_ofs = 0; central_dir_size = 0; if (pZip->m_total_files) { /* Write central directory */ central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += central_dir_size; } if (pState->m_zip64) { /* Write zip64 end of central directory header */ mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; MZ_CLEAR_ARR(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; /* Write zip64 end of central directory locator */ MZ_CLEAR_ARR(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; } /* Write end of central directory record */ MZ_CLEAR_ARR(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) { if ((!ppBuf) || (!pSize)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); *ppBuf = NULL; *pSize = 0; if ((!pZip) || (!pZip->m_pState)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_pWrite != mz_zip_heap_write_func) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; *ppBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; pZip->m_pState->m_pMem = NULL; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; } mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { return mz_zip_writer_end_internal(pZip, MZ_TRUE); } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place( const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { return mz_zip_add_mem_to_archive_file_in_place_v2( pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); } mz_bool mz_zip_add_mem_to_archive_file_in_place_v2( const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; mz_zip_zero_struct(&zip_archive); if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (!mz_zip_writer_validate_archive_name(pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_FILENAME; return MZ_FALSE; } /* Important: The regular non-64 bit version of stat() can fail here if the * file is very large, which could cause the archive to be overwritten. */ /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { /* Create a new archive. */ if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } created_new_archive = MZ_TRUE; } else { /* Append to an existing archive. */ if (!mz_zip_reader_init_file_v2( &zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); return MZ_FALSE; } } status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); actual_err = zip_archive.m_last_error; /* Always finalize, even if adding failed for some reason, so we have a valid * central directory. (This may not always succeed, but we can try.) */ if (!mz_zip_writer_finalize_archive(&zip_archive)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if (!mz_zip_writer_end_internal(&zip_archive, status)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if ((!status) && (created_new_archive)) { /* It's a new archive and something went wrong, so just delete it. */ int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; } if (pErr) *pErr = actual_err; return status; } void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) { mz_uint32 file_index; mz_zip_archive zip_archive; void *p = NULL; if (pSize) *pSize = 0; if ((!pZip_filename) || (!pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return NULL; } mz_zip_zero_struct(&zip_archive); if (!mz_zip_reader_init_file_v2( &zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return NULL; } if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) { p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); } mz_zip_reader_end_internal(&zip_archive, p != NULL); if (pErr) *pErr = zip_archive.m_last_error; return p; } void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ /* ------------------- Misc utils */ mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; } mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; } mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = err_num; return prev_err; } mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) { if (!pZip) return MZ_ZIP_INVALID_PARAMETER; return pZip->m_last_error; } mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) { return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); } mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = MZ_ZIP_NO_ERROR; return prev_err; } const char *mz_zip_get_error_string(mz_zip_error mz_err) { switch (mz_err) { case MZ_ZIP_NO_ERROR: return "no error"; case MZ_ZIP_UNDEFINED_ERROR: return "undefined error"; case MZ_ZIP_TOO_MANY_FILES: return "too many files"; case MZ_ZIP_FILE_TOO_LARGE: return "file too large"; case MZ_ZIP_UNSUPPORTED_METHOD: return "unsupported method"; case MZ_ZIP_UNSUPPORTED_ENCRYPTION: return "unsupported encryption"; case MZ_ZIP_UNSUPPORTED_FEATURE: return "unsupported feature"; case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: return "failed finding central directory"; case MZ_ZIP_NOT_AN_ARCHIVE: return "not a ZIP archive"; case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: return "invalid header or archive is corrupted"; case MZ_ZIP_UNSUPPORTED_MULTIDISK: return "unsupported multidisk archive"; case MZ_ZIP_DECOMPRESSION_FAILED: return "decompression failed or archive is corrupted"; case MZ_ZIP_COMPRESSION_FAILED: return "compression failed"; case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: return "unexpected decompressed size"; case MZ_ZIP_CRC_CHECK_FAILED: return "CRC-32 check failed"; case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: return "unsupported central directory size"; case MZ_ZIP_ALLOC_FAILED: return "allocation failed"; case MZ_ZIP_FILE_OPEN_FAILED: return "file open failed"; case MZ_ZIP_FILE_CREATE_FAILED: return "file create failed"; case MZ_ZIP_FILE_WRITE_FAILED: return "file write failed"; case MZ_ZIP_FILE_READ_FAILED: return "file read failed"; case MZ_ZIP_FILE_CLOSE_FAILED: return "file close failed"; case MZ_ZIP_FILE_SEEK_FAILED: return "file seek failed"; case MZ_ZIP_FILE_STAT_FAILED: return "file stat failed"; case MZ_ZIP_INVALID_PARAMETER: return "invalid parameter"; case MZ_ZIP_INVALID_FILENAME: return "invalid filename"; case MZ_ZIP_BUF_TOO_SMALL: return "buffer too small"; case MZ_ZIP_INTERNAL_ERROR: return "internal error"; case MZ_ZIP_FILE_NOT_FOUND: return "file not found"; case MZ_ZIP_ARCHIVE_TOO_LARGE: return "archive is too large"; case MZ_ZIP_VALIDATION_FAILED: return "validation failed"; case MZ_ZIP_WRITE_CALLBACK_FAILED: return "write callback failed"; case MZ_ZIP_TOTAL_ERRORS: return "total errors"; default: break; } return "unknown error"; } /* Note: Just because the archive is not zip64 doesn't necessarily mean it * doesn't have Zip64 extended information extra field, argh. */ mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return MZ_FALSE; return pZip->m_pState->m_zip64; } size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_central_dir.m_size; } mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) { if (!pZip) return 0; return pZip->m_archive_size; } mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_file_archive_start_ofs; } MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_pFile; } size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); } mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { if (filename_buf_size) pFilename[0] = '\0'; mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return 0; } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; } return n + 1; } mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { return mz_zip_file_stat_internal( pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); } mz_bool mz_zip_end(mz_zip_archive *pZip) { if (!pZip) return MZ_FALSE; if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) return mz_zip_reader_end(pZip); #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) return mz_zip_writer_end(pZip); #endif return MZ_FALSE; } #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ simutrans-124.3/src/external/readme.txt000066400000000000000000000001031474050137200201540ustar00rootroot00000000000000These files are from https://github.com/kuba--/zip/tree/master/src simutrans-124.3/src/external/refresh.sh000077500000000000000000000003131474050137200201560ustar00rootroot00000000000000#!/bin/sh wget "https://github.com/kuba--/zip/zipball/master/" -O master.zip subdir="$(unzip -lqq master.zip | grep -o -e "kuba---zip-[^/]*" | uniq)" unzip -j master.zip "$subdir/src/*" rm -f master.zip simutrans-124.3/src/external/zip.c000066400000000000000000001516101474050137200171360ustar00rootroot00000000000000/* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #define __STDC_WANT_LIB_EXT1__ 1 #include #include #include #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) /* Win32, DOS, MSVC, MSVS */ #include #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) #define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ (P)[1] == ':') #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) #else #include // needed for symlink() #define STRCLONE(STR) ((STR) ? strdup(STR) : NULL) #endif #ifdef __MINGW32__ #include #include #endif #include "miniz.h" #include "zip.h" #ifdef _MSC_VER #include #define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0)) #define fileno _fileno #endif #if defined(__TINYC__) && (defined(_WIN32) || defined(_WIN64)) #include #define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0)) #define fileno _fileno #endif #ifndef HAS_DEVICE #define HAS_DEVICE(P) 0 #endif #ifndef FILESYSTEM_PREFIX_LEN #define FILESYSTEM_PREFIX_LEN(P) 0 #endif #ifndef ISSLASH #define ISSLASH(C) ((C) == '/' || (C) == '\\') #endif #define CLEANUP(ptr) \ do { \ if (ptr) { \ free((void *)ptr); \ ptr = NULL; \ } \ } while (0) #define UNX_IFDIR 0040000 /* Unix directory */ #define UNX_IFREG 0100000 /* Unix regular file */ #define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */ #define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */ #define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */ #define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */ #define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */ struct zip_entry_t { ssize_t index; char *name; mz_uint64 uncomp_size; mz_uint64 comp_size; mz_uint32 uncomp_crc32; mz_uint64 dir_offset; mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint64 header_offset; mz_uint16 method; mz_zip_writer_add_state state; tdefl_compressor comp; mz_uint32 external_attr; time_t m_time; }; struct zip_t { mz_zip_archive archive; mz_uint level; struct zip_entry_t entry; }; enum zip_modify_t { MZ_KEEP = 0, MZ_DELETE = 1, MZ_MOVE = 2, }; struct zip_entry_mark_t { ssize_t file_index; enum zip_modify_t type; mz_uint64 m_local_header_ofs; size_t lf_length; }; static const char *const zip_errlist[33] = { NULL, "not initialized\0", "invalid entry name\0", "entry not found\0", "invalid zip mode\0", "invalid compression level\0", "no zip 64 support\0", "memset error\0", "cannot write data to entry\0", "cannot initialize tdefl compressor\0", "invalid index\0", "header not found\0", "cannot flush tdefl buffer\0", "cannot write entry header\0", "cannot create entry header\0", "cannot write to central dir\0", "cannot open file\0", "invalid entry type\0", "extracting data using no memory allocation\0", "file not found\0", "no permission\0", "out of memory\0", "invalid zip archive name\0", "make dir error\0", "symlink error\0", "close archive error\0", "capacity size too small\0", "fseek error\0", "fread error\0", "fwrite error\0", "cannot initialize reader\0", "cannot initialize writer\0", "cannot initialize writer from reader\0", }; const char *zip_strerror(int errnum) { errnum = -errnum; if (errnum <= 0 || errnum >= 33) { return NULL; } return zip_errlist[errnum]; } static const char *zip_basename(const char *name) { char const *p; char const *base = name += FILESYSTEM_PREFIX_LEN(name); int all_slashes = 1; for (p = name; *p; p++) { if (ISSLASH(*p)) base = p + 1; else all_slashes = 0; } /* If NAME is all slashes, arrange to return `/'. */ if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; return base; } static int zip_mkpath(char *path) { char *p; char npath[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1]; int len = 0; int has_device = HAS_DEVICE(path); memset(npath, 0, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1); if (has_device) { // only on windows npath[0] = path[0]; npath[1] = path[1]; len = 2; } for (p = path + len; *p && len < MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE; p++) { if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) { #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if ('\\' == *p) { *p = '/'; } #endif if (MZ_MKDIR(npath) == -1) { if (errno != EEXIST) { return ZIP_EMKDIR; } } } npath[len++] = *p; } return 0; } static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) { char c; size_t i; char *rpl = (char *)calloc((1 + n), sizeof(char)); char *begin = rpl; if (!rpl) { return NULL; } for (i = 0; (i < n) && (c = *str++); ++i) { if (c == oldchar) { c = newchar; } *rpl++ = c; } return begin; } static char *zip_name_normalize(char *name, char *const nname, size_t len) { size_t offn = 0; size_t offnn = 0, ncpy = 0; if (name == NULL || nname == NULL || len <= 0) { return NULL; } // skip trailing '/' while (ISSLASH(*name)) name++; for (; offn < len; offn++) { if (ISSLASH(name[offn])) { if (ncpy > 0 && strcmp(&nname[offnn], ".\0") && strcmp(&nname[offnn], "..\0")) { offnn += ncpy; nname[offnn++] = name[offn]; // append '/' } ncpy = 0; } else { nname[offnn + ncpy] = name[offn]; ncpy++; } } // at the end, extra check what we've already copied if (ncpy == 0 || !strcmp(&nname[offnn], ".\0") || !strcmp(&nname[offnn], "..\0")) { nname[offnn] = 0; } return nname; } static mz_bool zip_name_match(const char *name1, const char *name2) { char *nname2 = NULL; #ifdef ZIP_RAW_ENTRYNAME nname2 = STRCLONE(name2); #else nname2 = zip_strrpl(name2, strlen(name2), '\\', '/'); #endif if (!nname2) { return MZ_FALSE; } mz_bool res = (strcmp(name1, nname2) == 0) ? MZ_TRUE : MZ_FALSE; CLEANUP(nname2); return res; } static int zip_archive_truncate(mz_zip_archive *pzip) { mz_zip_internal_state *pState = pzip->m_pState; mz_uint64 file_size = pzip->m_archive_size; if ((pzip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { return 0; } if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) { if (pState->m_pFile) { int fd = fileno(pState->m_pFile); return ftruncate(fd, file_size); } } return 0; } static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { int err = 0; mz_uint i, n; char path[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1]; char symlink_to[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE + 1]; mz_zip_archive_file_stat info; size_t dirlen = 0, filename_size = MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE; mz_uint32 xattr = 0; memset(path, 0, sizeof(path)); memset(symlink_to, 0, sizeof(symlink_to)); dirlen = strlen(dir); if (dirlen + 1 > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE) { return ZIP_EINVENTNAME; } memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); #if defined(_MSC_VER) strcpy_s(path, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, dir); #else strncpy(path, dir, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE); #endif if (!ISSLASH(path[dirlen - 1])) { #if defined(_WIN32) || defined(__WIN32__) path[dirlen] = '\\'; #else path[dirlen] = '/'; #endif ++dirlen; } if (filename_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - dirlen) { filename_size = MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - dirlen; } // Get and print information about each file in the archive. n = mz_zip_reader_get_num_files(zip_archive); for (i = 0; i < n; ++i) { if (!mz_zip_reader_file_stat(zip_archive, i, &info)) { // Cannot get information about zip archive; err = ZIP_ENOENT; goto out; } if (!zip_name_normalize(info.m_filename, info.m_filename, strlen(info.m_filename))) { // Cannot normalize file name; err = ZIP_EINVENTNAME; goto out; } #if defined(_MSC_VER) strncpy_s(&path[dirlen], filename_size, info.m_filename, filename_size); #else strncpy(&path[dirlen], info.m_filename, filename_size); #endif err = zip_mkpath(path); if (err < 0) { // Cannot make a path goto out; } if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == 19)) // if zip is produced on Unix or macOS (3 and 19 from // section 4.4.2.2 of zip standard) && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 // is directory) #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if (info.m_uncomp_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE || !mz_zip_reader_extract_to_mem_no_alloc( zip_archive, i, symlink_to, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, 0, NULL, 0)) { err = ZIP_EMEMNOALLOC; goto out; } symlink_to[info.m_uncomp_size] = '\0'; if (symlink(symlink_to, path) != 0) { err = ZIP_ESYMLINK; goto out; } #endif } else { if (!mz_zip_reader_is_file_a_directory(zip_archive, i)) { if (!mz_zip_reader_extract_to_file(zip_archive, i, path, 0)) { // Cannot extract zip archive to file err = ZIP_ENOFILE; goto out; } } #if defined(_MSC_VER) || defined(PS4) (void)xattr; // unused #else xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { if (CHMOD(path, (mode_t)xattr) < 0) { err = ZIP_ENOPERM; goto out; } } #endif } if (on_extract) { if (on_extract(path, arg) < 0) { goto out; } } } out: // Close the archive, freeing any resources it was using if (!mz_zip_reader_end(zip_archive)) { // Cannot end zip reader err = ZIP_ECLSZIP; } return err; } static inline void zip_archive_finalize(mz_zip_archive *pzip) { mz_zip_writer_finalize_archive(pzip); zip_archive_truncate(pzip); } static ssize_t zip_entry_mark(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, const ssize_t n, char *const entries[], const size_t len) { ssize_t i = 0; ssize_t err = 0; if (!zip || !entry_mark || !entries) { return ZIP_ENOINIT; } mz_zip_archive_file_stat file_stat; mz_uint64 d_pos = UINT64_MAX; for (i = 0; i < n; ++i) { if ((err = zip_entry_openbyindex(zip, i))) { return (ssize_t)err; } mz_bool name_matches = MZ_FALSE; { size_t j; for (j = 0; j < len; ++j) { if (zip_name_match(zip->entry.name, entries[j])) { name_matches = MZ_TRUE; break; } } } if (name_matches) { entry_mark[i].type = MZ_DELETE; } else { entry_mark[i].type = MZ_KEEP; } if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) { return ZIP_ENOENT; } zip_entry_close(zip); entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs; entry_mark[i].file_index = (ssize_t)-1; entry_mark[i].lf_length = 0; if ((entry_mark[i].type) == MZ_DELETE && (d_pos > entry_mark[i].m_local_header_ofs)) { d_pos = entry_mark[i].m_local_header_ofs; } } for (i = 0; i < n; ++i) { if ((entry_mark[i].m_local_header_ofs > d_pos) && (entry_mark[i].type != MZ_DELETE)) { entry_mark[i].type = MZ_MOVE; } } return err; } static ssize_t zip_entry_markbyindex(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, const ssize_t n, size_t entries[], const size_t len) { ssize_t i = 0; ssize_t err = 0; if (!zip || !entry_mark || !entries) { return ZIP_ENOINIT; } mz_zip_archive_file_stat file_stat; mz_uint64 d_pos = UINT64_MAX; for (i = 0; i < n; ++i) { if ((err = zip_entry_openbyindex(zip, i))) { return (ssize_t)err; } mz_bool matches = MZ_FALSE; { size_t j; for (j = 0; j < len; ++j) { if ((size_t)i == entries[j]) { matches = MZ_TRUE; break; } } } if (matches) { entry_mark[i].type = MZ_DELETE; } else { entry_mark[i].type = MZ_KEEP; } if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) { return ZIP_ENOENT; } zip_entry_close(zip); entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs; entry_mark[i].file_index = (ssize_t)-1; entry_mark[i].lf_length = 0; if ((entry_mark[i].type) == MZ_DELETE && (d_pos > entry_mark[i].m_local_header_ofs)) { d_pos = entry_mark[i].m_local_header_ofs; } } for (i = 0; i < n; ++i) { if ((entry_mark[i].m_local_header_ofs > d_pos) && (entry_mark[i].type != MZ_DELETE)) { entry_mark[i].type = MZ_MOVE; } } return err; } static ssize_t zip_index_next(mz_uint64 *local_header_ofs_array, ssize_t cur_index) { ssize_t new_index = 0, i; for (i = cur_index - 1; i >= 0; --i) { if (local_header_ofs_array[cur_index] > local_header_ofs_array[i]) { new_index = i + 1; return new_index; } } return new_index; } static ssize_t zip_sort(mz_uint64 *local_header_ofs_array, ssize_t cur_index) { ssize_t nxt_index = zip_index_next(local_header_ofs_array, cur_index); if (nxt_index != cur_index) { mz_uint64 temp = local_header_ofs_array[cur_index]; ssize_t i; for (i = cur_index; i > nxt_index; i--) { local_header_ofs_array[i] = local_header_ofs_array[i - 1]; } local_header_ofs_array[nxt_index] = temp; } return nxt_index; } static int zip_index_update(struct zip_entry_mark_t *entry_mark, ssize_t last_index, ssize_t nxt_index) { ssize_t j; for (j = 0; j < last_index; j++) { if (entry_mark[j].file_index >= nxt_index) { entry_mark[j].file_index += 1; } } entry_mark[nxt_index].file_index = last_index; return 0; } static int zip_entry_finalize(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, const ssize_t n) { ssize_t i = 0; mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64)); if (!local_header_ofs_array) { return ZIP_EOOMEM; } for (i = 0; i < n; ++i) { local_header_ofs_array[i] = entry_mark[i].m_local_header_ofs; ssize_t index = zip_sort(local_header_ofs_array, i); if (index != i) { zip_index_update(entry_mark, i, index); } entry_mark[i].file_index = index; } size_t *length = (size_t *)calloc(n, sizeof(size_t)); if (!length) { CLEANUP(local_header_ofs_array); return ZIP_EOOMEM; } for (i = 0; i < n - 1; i++) { length[i] = (size_t)(local_header_ofs_array[i + 1] - local_header_ofs_array[i]); } length[n - 1] = (size_t)(zip->archive.m_archive_size - local_header_ofs_array[n - 1]); for (i = 0; i < n; i++) { entry_mark[i].lf_length = length[entry_mark[i].file_index]; } CLEANUP(length); CLEANUP(local_header_ofs_array); return 0; } static ssize_t zip_entry_set(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, ssize_t n, char *const entries[], const size_t len) { ssize_t err = 0; if ((err = zip_entry_mark(zip, entry_mark, n, entries, len)) < 0) { return err; } if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) { return err; } return 0; } static ssize_t zip_entry_setbyindex(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, ssize_t n, size_t entries[], const size_t len) { ssize_t err = 0; if ((err = zip_entry_markbyindex(zip, entry_mark, n, entries, len)) < 0) { return err; } if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) { return err; } return 0; } static ssize_t zip_mem_move(void *pBuf, size_t bufSize, const mz_uint64 to, const mz_uint64 from, const size_t length) { uint8_t *dst = NULL, *src = NULL, *end = NULL; if(!pBuf) { return ZIP_EINVIDX; } end = (uint8_t *)pBuf + bufSize; if(to > bufSize) { return ZIP_EINVIDX; } if(from > bufSize) { return ZIP_EINVIDX; } dst = (uint8_t *)pBuf + to; src = (uint8_t *)pBuf + from; if(((dst + length) > end) || ((src + length) > end)) { return ZIP_EINVIDX; } memmove(dst, src, length); return length; } static ssize_t zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to, const mz_uint64 from, const size_t length, mz_uint8 *move_buf, const size_t capacity_size) { if (length > capacity_size) { return ZIP_ECAPSIZE; } if (MZ_FSEEK64(m_pFile, from, SEEK_SET)) { return ZIP_EFSEEK; } if (fread(move_buf, 1, length, m_pFile) != length) { return ZIP_EFREAD; } if (MZ_FSEEK64(m_pFile, to, SEEK_SET)) { return ZIP_EFSEEK; } if (fwrite(move_buf, 1, length, m_pFile) != length) { return ZIP_EFWRITE; } return (ssize_t)length; } static ssize_t zip_files_move(struct zip_t *zip, mz_uint64 writen_num, mz_uint64 read_num, size_t length) { ssize_t n = 0; const size_t page_size = 1 << 12; // 4K mz_zip_internal_state *pState = zip->archive.m_pState; mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size); if (!move_buf) { return ZIP_EOOMEM; } ssize_t moved_length = 0; ssize_t move_count = 0; while ((mz_int64)length > 0) { move_count = (length >= page_size) ? page_size : length; if(pState->m_pFile) { n = zip_file_move(pState->m_pFile, writen_num, read_num, move_count, move_buf, page_size); } else if(pState->m_pMem) { n = zip_mem_move(pState->m_pMem, pState->m_mem_size, writen_num, read_num, move_count); } else { return ZIP_ENOFILE; } if (n < 0) { moved_length = n; goto cleanup; } if (n != move_count) { goto cleanup; } writen_num += move_count; read_num += move_count; length -= move_count; moved_length += move_count; } cleanup: CLEANUP(move_buf); return moved_length; } static int zip_central_dir_move(mz_zip_internal_state *pState, int begin, int end, int entry_num) { if (begin == entry_num) { return 0; } size_t l_size = 0; size_t r_size = 0; mz_uint32 d_size = 0; mz_uint8 *next = NULL; mz_uint8 *deleted = &MZ_ZIP_ARRAY_ELEMENT( &pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin)); l_size = (size_t)(deleted - (mz_uint8 *)(pState->m_central_dir.m_p)); if (end == entry_num) { r_size = 0; } else { next = &MZ_ZIP_ARRAY_ELEMENT( &pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, end)); r_size = pState->m_central_dir.m_size - (mz_uint32)(next - (mz_uint8 *)(pState->m_central_dir.m_p)); d_size = (mz_uint32)(next - deleted); } if (next && l_size == 0) { memmove(pState->m_central_dir.m_p, next, r_size); pState->m_central_dir.m_p = MZ_REALLOC(pState->m_central_dir.m_p, r_size); { int i; for (i = end; i < entry_num; i++) { MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -= d_size; } } } if (next && l_size * r_size != 0) { memmove(deleted, next, r_size); { int i; for (i = end; i < entry_num; i++) { MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -= d_size; } } } pState->m_central_dir.m_size = l_size + r_size; return 0; } static int zip_central_dir_delete(mz_zip_internal_state *pState, int *deleted_entry_index_array, int entry_num) { int i = 0; int begin = 0; int end = 0; int d_num = 0; while (i < entry_num) { while ((i < entry_num) && (!deleted_entry_index_array[i])) { i++; } begin = i; while ((i < entry_num) && (deleted_entry_index_array[i])) { i++; } end = i; zip_central_dir_move(pState, begin, end, entry_num); } i = 0; while (i < entry_num) { while ((i < entry_num) && (!deleted_entry_index_array[i])) { i++; } begin = i; if (begin == entry_num) { break; } while ((i < entry_num) && (deleted_entry_index_array[i])) { i++; } end = i; int k = 0, j; for (j = end; j < entry_num; j++) { MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin + k) = (mz_uint32)MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, j); k++; } d_num += end - begin; } pState->m_central_dir_offsets.m_size = sizeof(mz_uint32) * (entry_num - d_num); return 0; } static ssize_t zip_entries_delete_mark(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, int entry_num) { mz_uint64 writen_num = 0; mz_uint64 read_num = 0; size_t deleted_length = 0; size_t move_length = 0; int i = 0; size_t deleted_entry_num = 0; ssize_t n = 0; mz_bool *deleted_entry_flag_array = (mz_bool *)calloc(entry_num, sizeof(mz_bool)); if (deleted_entry_flag_array == NULL) { return ZIP_EOOMEM; } mz_zip_internal_state *pState = zip->archive.m_pState; zip->archive.m_zip_mode = MZ_ZIP_MODE_WRITING; if(pState->m_pFile) { if (MZ_FSEEK64(pState->m_pFile, 0, SEEK_SET)) { CLEANUP(deleted_entry_flag_array); return ZIP_ENOENT; } } while (i < entry_num) { while ((i < entry_num) && (entry_mark[i].type == MZ_KEEP)) { writen_num += entry_mark[i].lf_length; read_num = writen_num; i++; } while ((i < entry_num) && (entry_mark[i].type == MZ_DELETE)) { deleted_entry_flag_array[i] = MZ_TRUE; read_num += entry_mark[i].lf_length; deleted_length += entry_mark[i].lf_length; i++; deleted_entry_num++; } while ((i < entry_num) && (entry_mark[i].type == MZ_MOVE)) { move_length += entry_mark[i].lf_length; mz_uint8 *p = &MZ_ZIP_ARRAY_ELEMENT( &pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i)); if (!p) { CLEANUP(deleted_entry_flag_array); return ZIP_ENOENT; } mz_uint32 offset = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); offset -= (mz_uint32)deleted_length; MZ_WRITE_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS, offset); i++; } n = zip_files_move(zip, writen_num, read_num, move_length); if (n != (ssize_t)move_length) { CLEANUP(deleted_entry_flag_array); return n; } writen_num += move_length; read_num += move_length; } zip->archive.m_archive_size -= (mz_uint64)deleted_length; zip->archive.m_total_files = (mz_uint32)entry_num - (mz_uint32)deleted_entry_num; zip_central_dir_delete(pState, deleted_entry_flag_array, entry_num); CLEANUP(deleted_entry_flag_array); return (ssize_t)deleted_entry_num; } struct zip_t *zip_open(const char *zipname, int level, char mode) { int errnum = 0; return zip_openwitherror(zipname, level, mode, &errnum); } struct zip_t *zip_openwitherror(const char *zipname, int level, char mode, int *errnum) { struct zip_t *zip = NULL; *errnum = 0; if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL *errnum = ZIP_EINVZIPNAME; goto cleanup; } if (level < 0) level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; goto cleanup; } zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); if (!zip) { // out of memory *errnum = ZIP_EOOMEM; goto cleanup; } zip->level = (mz_uint)level; switch (mode) { case 'w': // Create a new archive. if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0, MZ_ZIP_FLAG_WRITE_ZIP64)) { // Cannot initialize zip_archive writer *errnum = ZIP_EWINIT; goto cleanup; } break; case 'r': if (!mz_zip_reader_init_file_v2( &(zip->archive), zipname, zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { // An archive file does not exist or cannot initialize // zip_archive reader *errnum = ZIP_ERINIT; goto cleanup; } break; case 'a': case 'd': if (!mz_zip_reader_init_file_v2_rpb( &(zip->archive), zipname, zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { // An archive file does not exist or cannot initialize // zip_archive reader *errnum = ZIP_ERINIT; goto cleanup; } if ((mode == 'a' || mode == 'd')) { if (!mz_zip_writer_init_from_reader_v2_noreopen(&(zip->archive), zipname, 0)) { *errnum = ZIP_EWRINIT; mz_zip_reader_end(&(zip->archive)); goto cleanup; } } break; default: *errnum = ZIP_EINVMODE; goto cleanup; } return zip; cleanup: CLEANUP(zip); return NULL; } void zip_close(struct zip_t *zip) { if (zip) { mz_zip_archive *pZip = &(zip->archive); // Always finalize, even if adding failed for some reason, so we have a // valid central directory. if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) { mz_zip_writer_finalize_archive(pZip); } if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING || pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) { zip_archive_truncate(pZip); mz_zip_writer_end(pZip); } if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) { mz_zip_reader_end(pZip); } CLEANUP(zip); } } int zip_is64(struct zip_t *zip) { if (!zip || !zip->archive.m_pState) { // zip_t handler or zip state is not initialized return ZIP_ENOINIT; } return (int)zip->archive.m_pState->m_zip64; } static int _zip_entry_open(struct zip_t *zip, const char *entryname, int case_sensitive) { size_t entrylen = 0; mz_zip_archive *pzip = NULL; mz_uint num_alignment_padding_bytes, level; mz_zip_archive_file_stat stats; int err = 0; mz_uint16 dos_time = 0, dos_date = 0; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint64 local_dir_header_ofs = 0; if (!zip) { return ZIP_ENOINIT; } local_dir_header_ofs = zip->archive.m_archive_size; if (!entryname) { return ZIP_EINVENTNAME; } entrylen = strlen(entryname); if (entrylen == 0) { return ZIP_EINVENTNAME; } /* .ZIP File Format Specification Version: 6.3.3 4.4.17.1 The name of the file, with optional relative path. The path stored MUST not contain a drive or device letter, or a leading slash. All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' for compatibility with Amiga and UNIX file systems etc. If input came from standard input, there is no file name field. */ if (zip->entry.name) { CLEANUP(zip->entry.name); } #ifdef ZIP_RAW_ENTRYNAME zip->entry.name = STRCLONE(entryname); #else zip->entry.name = zip_strrpl(entryname, entrylen, '\\', '/'); #endif if (!zip->entry.name) { // Cannot parse zip entry name return ZIP_EINVENTNAME; } pzip = &(zip->archive); if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { zip->entry.index = (ssize_t)mz_zip_reader_locate_file( pzip, zip->entry.name, NULL, case_sensitive ? MZ_ZIP_FLAG_CASE_SENSITIVE : 0); if (zip->entry.index < (ssize_t)0) { err = ZIP_ENOENT; goto cleanup; } if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) { err = ZIP_ENOENT; goto cleanup; } zip->entry.comp_size = stats.m_comp_size; zip->entry.uncomp_size = stats.m_uncomp_size; zip->entry.uncomp_crc32 = stats.m_crc32; zip->entry.dir_offset = stats.m_central_dir_ofs; zip->entry.header_offset = stats.m_local_header_ofs; zip->entry.method = stats.m_method; zip->entry.external_attr = stats.m_external_attr; #ifndef MINIZ_NO_TIME zip->entry.m_time = stats.m_time; #endif return 0; } level = zip->level & 0xF; zip->entry.index = (ssize_t)zip->archive.m_total_files; zip->entry.comp_size = 0; zip->entry.uncomp_size = 0; zip->entry.uncomp_crc32 = MZ_CRC32_INIT; zip->entry.dir_offset = zip->archive.m_archive_size; zip->entry.header_offset = zip->archive.m_archive_size; memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); zip->entry.method = level ? MZ_DEFLATED : 0; // UNIX or APPLE #if MZ_PLATFORM == 3 || MZ_PLATFORM == 19 // regular file with rw-r--r-- permissions zip->entry.external_attr = (mz_uint32)(0100644) << 16; #else zip->entry.external_attr = 0; #endif num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { // Invalid zip mode err = ZIP_EINVMODE; goto cleanup; } if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { // Invalid zip compression level err = ZIP_EINVLVL; goto cleanup; } if (!mz_zip_writer_write_zeros(pzip, zip->entry.dir_offset, num_alignment_padding_bytes)) { // Cannot memset zip entry header err = ZIP_EMEMSET; goto cleanup; } local_dir_header_ofs += num_alignment_padding_bytes; zip->entry.m_time = time(NULL); #ifndef MINIZ_NO_TIME mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date); #endif // ZIP64 header with NULL sizes (sizes will be in the data descriptor, just // after file data) extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, NULL, NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); if (!mz_zip_writer_create_local_dir_header( pzip, zip->entry.header, entrylen, (mz_uint16)extra_size, 0, 0, 0, zip->entry.method, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 | MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR, dos_time, dos_date)) { // Cannot create zip entry header err = ZIP_EMEMSET; goto cleanup; } zip->entry.header_offset = zip->entry.dir_offset + num_alignment_padding_bytes; if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, zip->entry.header, sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { // Cannot write zip entry header err = ZIP_EMEMSET; goto cleanup; } if (pzip->m_file_offset_alignment) { MZ_ASSERT( (zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0); } zip->entry.dir_offset += num_alignment_padding_bytes + sizeof(zip->entry.header); if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, zip->entry.name, entrylen) != entrylen) { // Cannot write data to zip entry err = ZIP_EWRTENT; goto cleanup; } zip->entry.dir_offset += entrylen; if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, extra_data, extra_size) != extra_size) { // Cannot write ZIP64 data to zip entry err = ZIP_EWRTENT; goto cleanup; } zip->entry.dir_offset += extra_size; if (level) { zip->entry.state.m_pZip = pzip; zip->entry.state.m_cur_archive_file_ofs = zip->entry.dir_offset; zip->entry.state.m_comp_size = 0; if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, &(zip->entry.state), (int)tdefl_create_comp_flags_from_zip_params( (int)level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { // Cannot initialize the zip compressor err = ZIP_ETDEFLINIT; goto cleanup; } } return 0; cleanup: CLEANUP(zip->entry.name); return err; } int zip_entry_open(struct zip_t *zip, const char *entryname) { return _zip_entry_open(zip, entryname, 0); } int zip_entry_opencasesensitive(struct zip_t *zip, const char *entryname) { return _zip_entry_open(zip, entryname, 1); } int zip_entry_openbyindex(struct zip_t *zip, size_t index) { mz_zip_archive *pZip = NULL; mz_zip_archive_file_stat stats; mz_uint namelen; const mz_uint8 *pHeader; const char *pFilename; if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } pZip = &(zip->archive); if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) { // open by index requires readonly mode return ZIP_EINVMODE; } if (index >= (size_t)pZip->m_total_files) { // index out of range return ZIP_EINVIDX; } if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT( &pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, index)))) { // cannot find header in central directory return ZIP_ENOHDR; } namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; /* .ZIP File Format Specification Version: 6.3.3 4.4.17.1 The name of the file, with optional relative path. The path stored MUST not contain a drive or device letter, or a leading slash. All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' for compatibility with Amiga and UNIX file systems etc. If input came from standard input, there is no file name field. */ if (zip->entry.name) { CLEANUP(zip->entry.name); } #ifdef ZIP_RAW_ENTRYNAME zip->entry.name = STRCLONE(pFilename); #else zip->entry.name = zip_strrpl(pFilename, namelen, '\\', '/'); #endif if (!zip->entry.name) { // local entry name is NULL return ZIP_EINVENTNAME; } if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) { return ZIP_ENOENT; } zip->entry.index = (ssize_t)index; zip->entry.comp_size = stats.m_comp_size; zip->entry.uncomp_size = stats.m_uncomp_size; zip->entry.uncomp_crc32 = stats.m_crc32; zip->entry.dir_offset = stats.m_central_dir_ofs; zip->entry.header_offset = stats.m_local_header_ofs; zip->entry.method = stats.m_method; zip->entry.external_attr = stats.m_external_attr; #ifndef MINIZ_NO_TIME zip->entry.m_time = stats.m_time; #endif return 0; } int zip_entry_close(struct zip_t *zip) { mz_zip_archive *pzip = NULL; mz_uint level; tdefl_status done; mz_uint16 entrylen; mz_uint16 dos_time = 0, dos_date = 0; int err = 0; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; if (!zip) { // zip_t handler is not initialized err = ZIP_ENOINIT; goto cleanup; } pzip = &(zip->archive); if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { goto cleanup; } level = zip->level & 0xF; if (level) { done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { // Cannot flush compressed buffer err = ZIP_ETDEFLBUF; goto cleanup; } zip->entry.comp_size = zip->entry.state.m_comp_size; zip->entry.dir_offset = zip->entry.state.m_cur_archive_file_ofs; zip->entry.method = MZ_DEFLATED; } entrylen = (mz_uint16)strlen(zip->entry.name); #ifndef MINIZ_NO_TIME mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date); #endif MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, zip->entry.uncomp_crc32); MZ_WRITE_LE64(local_dir_footer + 8, zip->entry.comp_size); MZ_WRITE_LE64(local_dir_footer + 16, zip->entry.uncomp_size); if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) { // Cannot write zip entry header err = ZIP_EWRTHDR; goto cleanup; } zip->entry.dir_offset += local_dir_footer_size; pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data( extra_data, (zip->entry.uncomp_size >= MZ_UINT32_MAX) ? &zip->entry.uncomp_size : NULL, (zip->entry.comp_size >= MZ_UINT32_MAX) ? &zip->entry.comp_size : NULL, (zip->entry.header_offset >= MZ_UINT32_MAX) ? &zip->entry.header_offset : NULL); if ((entrylen) && (zip->entry.name[entrylen - 1] == '/') && !zip->entry.uncomp_size) { /* Set DOS Subdirectory attribute bit. */ zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } if (!mz_zip_writer_add_to_central_dir( pzip, zip->entry.name, entrylen, pExtra_data, (mz_uint16)extra_size, "", 0, zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 | MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR, dos_time, dos_date, zip->entry.header_offset, zip->entry.external_attr, NULL, 0)) { // Cannot write to zip central dir err = ZIP_EWRTDIR; goto cleanup; } pzip->m_total_files++; pzip->m_archive_size = zip->entry.dir_offset; cleanup: if (zip) { zip->entry.m_time = 0; CLEANUP(zip->entry.name); } return err; } const char *zip_entry_name(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized return NULL; } return zip->entry.name; } ssize_t zip_entry_index(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized return (ssize_t)ZIP_ENOINIT; } return zip->entry.index; } int zip_entry_isdir(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } if (zip->entry.index < (ssize_t)0) { // zip entry is not opened return ZIP_EINVIDX; } return (int)mz_zip_reader_is_file_a_directory(&zip->archive, (mz_uint)zip->entry.index); } unsigned long long zip_entry_size(struct zip_t *zip) { return zip_entry_uncomp_size(zip); } unsigned long long zip_entry_uncomp_size(struct zip_t *zip) { return zip ? zip->entry.uncomp_size : 0; } unsigned long long zip_entry_comp_size(struct zip_t *zip) { return zip ? zip->entry.comp_size : 0; } unsigned int zip_entry_crc32(struct zip_t *zip) { return zip ? zip->entry.uncomp_crc32 : 0; } unsigned long long zip_entry_dir_offset(struct zip_t *zip) { return zip ? zip->entry.dir_offset : 0; } unsigned long long zip_entry_header_offset(struct zip_t *zip) { return zip ? zip->entry.header_offset : 0; } int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { mz_uint level; mz_zip_archive *pzip = NULL; tdefl_status status; if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } pzip = &(zip->archive); if (buf && bufsize > 0) { zip->entry.uncomp_size += bufsize; zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); level = zip->level & 0xF; if (!level) { if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, buf, bufsize) != bufsize)) { // Cannot write buffer return ZIP_EWRTENT; } zip->entry.dir_offset += bufsize; zip->entry.comp_size += bufsize; } else { status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize, TDEFL_NO_FLUSH); if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { // Cannot compress buffer return ZIP_ETDEFLBUF; } } } return 0; } int zip_entry_fwrite(struct zip_t *zip, const char *filename) { int err = 0; size_t n = 0; MZ_FILE *stream = NULL; mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE]; struct MZ_FILE_STAT_STRUCT file_stat; mz_uint16 modes; if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE); memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT)); if (MZ_FILE_STAT(filename, &file_stat) != 0) { // problem getting information - check errno return ZIP_ENOENT; } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; zip->entry.external_attr = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } #endif zip->entry.m_time = file_stat.st_mtime; if (!(stream = MZ_FOPEN(filename, "rb"))) { // Cannot open filename return ZIP_EOPNFILE; } while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > 0) { if (zip_entry_write(zip, buf, n) < 0) { err = ZIP_EWRTENT; break; } } fclose(stream); return err; } ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { mz_zip_archive *pzip = NULL; mz_uint idx; size_t size = 0; if (!zip) { // zip_t handler is not initialized return (ssize_t)ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < (ssize_t)0) { // the entry is not found or we do not have read access return (ssize_t)ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory return (ssize_t)ZIP_EINVENTTYPE; } *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0); if (*buf && bufsize) { *bufsize = size; } return (ssize_t)size; } ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) { mz_zip_archive *pzip = NULL; if (!zip) { // zip_t handler is not initialized return (ssize_t)ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < (ssize_t)0) { // the entry is not found or we do not have read access return (ssize_t)ZIP_ENOENT; } if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index, buf, bufsize, 0, NULL, 0)) { return (ssize_t)ZIP_EMEMNOALLOC; } return (ssize_t)zip->entry.uncomp_size; } int zip_entry_fread(struct zip_t *zip, const char *filename) { mz_zip_archive *pzip = NULL; mz_uint idx; mz_uint32 xattr = 0; mz_zip_archive_file_stat info; if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < (ssize_t)0) { // the entry is not found or we do not have read access return ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory return ZIP_EINVENTTYPE; } if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) { return ZIP_ENOFILE; } #if defined(_MSC_VER) || defined(PS4) (void)xattr; // unused #else if (!mz_zip_reader_file_stat(pzip, idx, &info)) { // Cannot get information about zip archive; return ZIP_ENOFILE; } xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { if (CHMOD(filename, (mode_t)xattr) < 0) { return ZIP_ENOPERM; } } #endif return 0; } int zip_entry_extract(struct zip_t *zip, size_t (*on_extract)(void *arg, uint64_t offset, const void *buf, size_t bufsize), void *arg) { mz_zip_archive *pzip = NULL; mz_uint idx; if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } pzip = &(zip->archive); if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < (ssize_t)0) { // the entry is not found or we do not have read access return ZIP_ENOENT; } idx = (mz_uint)zip->entry.index; return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) ? 0 : ZIP_EINVIDX; } ssize_t zip_entries_total(struct zip_t *zip) { if (!zip) { // zip_t handler is not initialized return ZIP_ENOINIT; } return (ssize_t)zip->archive.m_total_files; } ssize_t zip_entries_delete(struct zip_t *zip, char *const entries[], size_t len) { ssize_t n = 0; ssize_t err = 0; struct zip_entry_mark_t *entry_mark = NULL; if (zip == NULL || (entries == NULL && len != 0)) { return ZIP_ENOINIT; } if (entries == NULL && len == 0) { return 0; } n = zip_entries_total(zip); entry_mark = (struct zip_entry_mark_t *)calloc( (size_t)n, sizeof(struct zip_entry_mark_t)); if (!entry_mark) { return ZIP_EOOMEM; } zip->archive.m_zip_mode = MZ_ZIP_MODE_READING; err = zip_entry_set(zip, entry_mark, n, entries, len); if (err < 0) { CLEANUP(entry_mark); return err; } err = zip_entries_delete_mark(zip, entry_mark, (int)n); CLEANUP(entry_mark); return err; } ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[], size_t len) { ssize_t n = 0; ssize_t err = 0; struct zip_entry_mark_t *entry_mark = NULL; if (zip == NULL || (entries == NULL && len != 0)) { return ZIP_ENOINIT; } if (entries == NULL && len == 0) { return 0; } n = zip_entries_total(zip); entry_mark = (struct zip_entry_mark_t *)calloc( (size_t)n, sizeof(struct zip_entry_mark_t)); if (!entry_mark) { return ZIP_EOOMEM; } zip->archive.m_zip_mode = MZ_ZIP_MODE_READING; err = zip_entry_setbyindex(zip, entry_mark, n, entries, len); if (err < 0) { CLEANUP(entry_mark); return err; } err = zip_entries_delete_mark(zip, entry_mark, (int)n); CLEANUP(entry_mark); return err; } int zip_stream_extract(const char *stream, size_t size, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { mz_zip_archive zip_archive; if (!stream || !dir) { // Cannot parse zip archive stream return ZIP_ENOINIT; } if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) { // Cannot memset zip archive return ZIP_EMEMSET; } if (!mz_zip_reader_init_mem(&zip_archive, stream, size, 0)) { // Cannot initialize zip_archive reader return ZIP_ENOINIT; } return zip_archive_extract(&zip_archive, dir, on_extract, arg); } struct zip_t *zip_stream_open(const char *stream, size_t size, int level, char mode) { int errnum = 0; return zip_stream_openwitherror(stream, size, level, mode, &errnum); } struct zip_t *zip_stream_openwitherror(const char *stream, size_t size, int level, char mode, int *errnum) { struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); if (!zip) { // out of memory *errnum = ZIP_EOOMEM; return NULL; } if (level < 0) { level = MZ_DEFAULT_LEVEL; } if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; goto cleanup; } zip->level = (mz_uint)level; if ((stream != NULL) && (size > 0) && (mode == 'r')) { if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) { *errnum = ZIP_ERINIT; goto cleanup; } } else if ((stream == NULL) && (size == 0) && (mode == 'w')) { // Create a new archive. if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) { // Cannot initialize zip_archive writer *errnum = ZIP_EWINIT; goto cleanup; } } else { *errnum = ZIP_EINVMODE; goto cleanup; } *errnum = 0; return zip; cleanup: CLEANUP(zip); return NULL; } ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize) { size_t n; if (!zip) { return (ssize_t)ZIP_ENOINIT; } zip_archive_finalize(&(zip->archive)); n = (size_t)zip->archive.m_archive_size; if (bufsize != NULL) { *bufsize = n; } *buf = calloc(sizeof(unsigned char), n); memcpy(*buf, zip->archive.m_pState->m_pMem, n); return (ssize_t)n; } void zip_stream_close(struct zip_t *zip) { if (zip) { mz_zip_writer_end(&(zip->archive)); mz_zip_reader_end(&(zip->archive)); CLEANUP(zip); } } int zip_create(const char *zipname, const char *filenames[], size_t len) { int err = 0; size_t i; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; mz_uint32 ext_attributes = 0; mz_uint16 modes; if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL return ZIP_EINVZIPNAME; } // Create a new archive. if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { // Cannot memset zip archive return ZIP_EMEMSET; } if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive writer return ZIP_ENOINIT; } if (!memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT))) { return ZIP_EMEMSET; } for (i = 0; i < len; ++i) { const char *name = filenames[i]; if (!name) { err = ZIP_EINVENTNAME; break; } if (MZ_FILE_STAT(name, &file_stat) != 0) { // problem getting information - check errno err = ZIP_ENOFILE; break; } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; ext_attributes = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } #endif if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0, ZIP_DEFAULT_COMPRESSION_LEVEL, ext_attributes)) { // Cannot add file to zip_archive err = ZIP_ENOFILE; break; } } mz_zip_writer_finalize_archive(&zip_archive); mz_zip_writer_end(&zip_archive); return err; } int zip_extract(const char *zipname, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { mz_zip_archive zip_archive; if (!zipname || !dir) { // Cannot parse zip archive name return ZIP_EINVZIPNAME; } if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) { // Cannot memset zip archive return ZIP_EMEMSET; } // Now try to open the archive. if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive reader return ZIP_ENOINIT; } return zip_archive_extract(&zip_archive, dir, on_extract, arg); } simutrans-124.3/src/external/zip.h000066400000000000000000000423501474050137200171430ustar00rootroot00000000000000/* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef ZIP_H #define ZIP_H #include #include #include #ifndef ZIP_SHARED #define ZIP_EXPORT #else #ifdef _WIN32 #ifdef ZIP_BUILD_SHARED #define ZIP_EXPORT __declspec(dllexport) #else #define ZIP_EXPORT __declspec(dllimport) #endif #else #define ZIP_EXPORT __attribute__((visibility("default"))) #endif #endif #ifdef __cplusplus extern "C" { #endif #if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER) // 64-bit Windows is the only mainstream platform // where sizeof(long) != sizeof(void*) #ifdef _WIN64 typedef long long ssize_t; /* byte count or error */ #else typedef long ssize_t; /* byte count or error */ #endif #endif /** * @mainpage * * Documentation for @ref zip. */ /** * @addtogroup zip * @{ */ /** * Default zip compression level. */ #define ZIP_DEFAULT_COMPRESSION_LEVEL 6 /** * Error codes */ #define ZIP_ENOINIT -1 // not initialized #define ZIP_EINVENTNAME -2 // invalid entry name #define ZIP_ENOENT -3 // entry not found #define ZIP_EINVMODE -4 // invalid zip mode #define ZIP_EINVLVL -5 // invalid compression level #define ZIP_ENOSUP64 -6 // no zip 64 support #define ZIP_EMEMSET -7 // memset error #define ZIP_EWRTENT -8 // cannot write data to entry #define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor #define ZIP_EINVIDX -10 // invalid index #define ZIP_ENOHDR -11 // header not found #define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer #define ZIP_ECRTHDR -13 // cannot create entry header #define ZIP_EWRTHDR -14 // cannot write entry header #define ZIP_EWRTDIR -15 // cannot write to central dir #define ZIP_EOPNFILE -16 // cannot open file #define ZIP_EINVENTTYPE -17 // invalid entry type #define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation #define ZIP_ENOFILE -19 // file not found #define ZIP_ENOPERM -20 // no permission #define ZIP_EOOMEM -21 // out of memory #define ZIP_EINVZIPNAME -22 // invalid zip archive name #define ZIP_EMKDIR -23 // make dir error #define ZIP_ESYMLINK -24 // symlink error #define ZIP_ECLSZIP -25 // close archive error #define ZIP_ECAPSIZE -26 // capacity size too small #define ZIP_EFSEEK -27 // fseek error #define ZIP_EFREAD -28 // fread error #define ZIP_EFWRITE -29 // fwrite error #define ZIP_ERINIT -30 // cannot initialize reader #define ZIP_EWINIT -31 // cannot initialize writer #define ZIP_EWRINIT -32 // cannot initialize writer from reader /** * Looks up the error message string corresponding to an error number. * @param errnum error number * @return error message string corresponding to errnum or NULL if error is not * found. */ extern ZIP_EXPORT const char *zip_strerror(int errnum); /** * @struct zip_t * * This data structure is used throughout the library to represent zip archive - * forward declaration. */ struct zip_t; /** * Opens zip archive with compression level using the given mode. * * @param zipname zip archive file name. * @param level compression level (0-9 are the standard zlib-style levels). * @param mode file access mode. * - 'r': opens a file for reading/extracting (the file must exists). * - 'w': creates an empty file for writing. * - 'a': appends to an existing archive. * * @return the zip archive handler or NULL on error */ extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level, char mode); /** * Opens zip archive with compression level using the given mode. * The function additionally returns @param errnum - * * @param zipname zip archive file name. * @param level compression level (0-9 are the standard zlib-style levels). * @param mode file access mode. * - 'r': opens a file for reading/extracting (the file must exists). * - 'w': creates an empty file for writing. * - 'a': appends to an existing archive. * @param errnum 0 on success, negative number (< 0) on error. * * @return the zip archive handler or NULL on error */ extern ZIP_EXPORT struct zip_t * zip_openwitherror(const char *zipname, int level, char mode, int *errnum); /** * Closes the zip archive, releases resources - always finalize. * * @param zip zip archive handler. */ extern ZIP_EXPORT void zip_close(struct zip_t *zip); /** * Determines if the archive has a zip64 end of central directory headers. * * @param zip zip archive handler. * * @return the return code - 1 (true), 0 (false), negative number (< 0) on * error. */ extern ZIP_EXPORT int zip_is64(struct zip_t *zip); /** * Opens an entry by name in the zip archive. * * For zip archive opened in 'w' or 'a' mode the function will append * a new entry. In readonly mode the function tries to locate the entry * in global dictionary. * * @param zip zip archive handler. * @param entryname an entry name in local dictionary. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname); /** * Opens an entry by name in the zip archive. * * For zip archive opened in 'w' or 'a' mode the function will append * a new entry. In readonly mode the function tries to locate the entry * in global dictionary (case sensitive). * * @param zip zip archive handler. * @param entryname an entry name in local dictionary (case sensitive). * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_opencasesensitive(struct zip_t *zip, const char *entryname); /** * Opens a new entry by index in the zip archive. * * This function is only valid if zip archive was opened in 'r' (readonly) mode. * * @param zip zip archive handler. * @param index index in local dictionary. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, size_t index); /** * Closes a zip entry, flushes buffer and releases resources. * * @param zip zip archive handler. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip); /** * Returns a local name of the current zip entry. * * The main difference between user's entry name and local entry name * is optional relative path. * Following .ZIP File Format Specification - the path stored MUST not contain * a drive or device letter, or a leading slash. * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' * for compatibility with Amiga and UNIX file systems etc. * * @param zip: zip archive handler. * * @return the pointer to the current zip entry name, or NULL on error. */ extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip); /** * Returns an index of the current zip entry. * * @param zip zip archive handler. * * @return the index on success, negative number (< 0) on error. */ extern ZIP_EXPORT ssize_t zip_entry_index(struct zip_t *zip); /** * Determines if the current zip entry is a directory entry. * * @param zip zip archive handler. * * @return the return code - 1 (true), 0 (false), negative number (< 0) on * error. */ extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip); /** * Returns the uncompressed size of the current zip entry. * Alias for zip_entry_uncomp_size (for backward compatibility). * * @param zip zip archive handler. * * @return the uncompressed size in bytes. */ extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip); /** * Returns the uncompressed size of the current zip entry. * * @param zip zip archive handler. * * @return the uncompressed size in bytes. */ extern ZIP_EXPORT unsigned long long zip_entry_uncomp_size(struct zip_t *zip); /** * Returns the compressed size of the current zip entry. * * @param zip zip archive handler. * * @return the compressed size in bytes. */ extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip); /** * Returns CRC-32 checksum of the current zip entry. * * @param zip zip archive handler. * * @return the CRC-32 checksum. */ extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip); /** * Returns byte offset of the current zip entry * in the archive's central directory. * * @param zip zip archive handler. * * @return the offset in bytes. */ extern ZIP_EXPORT unsigned long long zip_entry_dir_offset(struct zip_t *zip); /** * Returns the current zip entry's local header file offset in bytes. * * @param zip zip archive handler. * * @return the entry's local header file offset in bytes. */ extern ZIP_EXPORT unsigned long long zip_entry_header_offset(struct zip_t *zip); /** * Compresses an input buffer for the current zip entry. * * @param zip zip archive handler. * @param buf input buffer. * @param bufsize input buffer size (in bytes). * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize); /** * Compresses a file for the current zip entry. * * @param zip zip archive handler. * @param filename input file. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename); /** * Extracts the current zip entry into output buffer. * * The function allocates sufficient memory for a output buffer. * * @param zip zip archive handler. * @param buf output buffer. * @param bufsize output buffer size (in bytes). * * @note remember to release memory allocated for a output buffer. * for large entries, please take a look at zip_entry_extract function. * * @return the return code - the number of bytes actually read on success. * Otherwise a negative number (< 0) on error. */ extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); /** * Extracts the current zip entry into a memory buffer using no memory * allocation. * * @param zip zip archive handler. * @param buf preallocated output buffer. * @param bufsize output buffer size (in bytes). * * @note ensure supplied output buffer is large enough. * zip_entry_size function (returns uncompressed size for the current * entry) can be handy to estimate how big buffer is needed. * For large entries, please take a look at zip_entry_extract function. * * @return the return code - the number of bytes actually read on success. * Otherwise a negative number (< 0) on error (e.g. bufsize is not large * enough). */ extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize); /** * Extracts the current zip entry into output file. * * @param zip zip archive handler. * @param filename output file. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename); /** * Extracts the current zip entry using a callback function (on_extract). * * @param zip zip archive handler. * @param on_extract callback function. * @param arg opaque pointer (optional argument, which you can pass to the * on_extract callback) * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_entry_extract(struct zip_t *zip, size_t (*on_extract)(void *arg, uint64_t offset, const void *data, size_t size), void *arg); /** * Returns the number of all entries (files and directories) in the zip archive. * * @param zip zip archive handler. * * @return the return code - the number of entries on success, negative number * (< 0) on error. */ extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip); /** * Deletes zip archive entries. * * @param zip zip archive handler. * @param entries array of zip archive entries to be deleted. * @param len the number of entries to be deleted. * @return the number of deleted entries, or negative number (< 0) on error. */ extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip, char *const entries[], size_t len); /** * Deletes zip archive entries. * * @param zip zip archive handler. * @param entries array of zip archive entries indices to be deleted. * @param len the number of entries to be deleted. * @return the number of deleted entries, or negative number (< 0) on error. */ extern ZIP_EXPORT ssize_t zip_entries_deletebyindex(struct zip_t *zip, size_t entries[], size_t len); /** * Extracts a zip archive stream into directory. * * If on_extract is not NULL, the callback will be called after * successfully extracted each zip entry. * Returning a negative value from the callback will cause abort and return an * error. The last argument (void *arg) is optional, which you can use to pass * data to the on_extract callback. * * @param stream zip archive stream. * @param size stream size. * @param dir output directory. * @param on_extract on extract callback. * @param arg opaque pointer. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_stream_extract(const char *stream, size_t size, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg); /** * Opens zip archive stream into memory. * * @param stream zip archive stream. * @param size stream size. * @param level compression level (0-9 are the standard zlib-style levels). * @param mode file access mode. * - 'r': opens a file for reading/extracting (the file must exists). * - 'w': creates an empty file for writing. * - 'a': appends to an existing archive. * * @return the zip archive handler or NULL on error */ extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size, int level, char mode); /** * Opens zip archive stream into memory. * The function additionally returns @param errnum - * * @param stream zip archive stream. * @param size stream size.* * @param level compression level (0-9 are the standard zlib-style levels). * @param mode file access mode. * - 'r': opens a file for reading/extracting (the file must exists). * - 'w': creates an empty file for writing. * - 'a': appends to an existing archive. * @param errnum 0 on success, negative number (< 0) on error. * * @return the zip archive handler or NULL on error */ extern ZIP_EXPORT struct zip_t *zip_stream_openwitherror(const char *stream, size_t size, int level, char mode, int *errnum); /** * Copy zip archive stream output buffer. * * @param zip zip archive handler. * @param buf output buffer. User should free buf. * @param bufsize output buffer size (in bytes). * * @return copy size */ extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize); /** * Close zip archive releases resources. * * @param zip zip archive handler. * * @return */ extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip); /** * Creates a new archive and puts files into a single zip archive. * * @param zipname zip archive file. * @param filenames input files. * @param len: number of input files. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[], size_t len); /** * Extracts a zip archive file into directory. * * If on_extract_entry is not NULL, the callback will be called after * successfully extracted each zip entry. * Returning a negative value from the callback will cause abort and return an * error. The last argument (void *arg) is optional, which you can use to pass * data to the on_extract_entry callback. * * @param zipname zip archive file. * @param dir output directory. * @param on_extract_entry on extract callback. * @param arg opaque pointer. * * @return the return code - 0 on success, negative number (< 0) on error. */ extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir, int (*on_extract_entry)(const char *filename, void *arg), void *arg); /** @} */ #ifdef __cplusplus } #endif #endif simutrans-124.3/src/linux/000077500000000000000000000000001474050137200155015ustar00rootroot00000000000000simutrans-124.3/src/linux/com.simutrans.Simutrans.metainfo.xml.in000066400000000000000000000033151474050137200252210ustar00rootroot00000000000000 com.simutrans.Simutrans CC0-1.0 Artistic-1.0 Simutrans

Open source transportation simulation game

Simutrans is a freeware and open-source transportation simulator. Your goal is to establish a successful transport company. Transport passengers, mail and goods by rail, road, ship, and even air. Interconnect districts, cities, public buildings, industries and tourist attractions.

simutrans.desktop https://simutrans-germany.com/wiki/wiki/display858 https://simutrans-germany.com/wiki/wiki/display864 https://simutrans-germany.com/wiki/wiki/display837 https://simutrans-germany.com/wiki/wiki/display1687 https://www.simutrans.com/ The Simutrans Team simutrans mild moderate simutrans-124.3/src/linux/simutrans.desktop000066400000000000000000000004271474050137200211240ustar00rootroot00000000000000[Desktop Entry] Name=Simutrans GenericName=Transportation Simulation Game Comment=Transportation simulator Exec=simutrans Icon=simutrans Terminal=false Type=Application Categories=Game;Simulation; X-Purism-FormFactor=Workstation;Mobile; X-KDE-FormFactors=desktop;tablet;handset; simutrans-124.3/src/makeobj/000077500000000000000000000000001474050137200157525ustar00rootroot00000000000000simutrans-124.3/src/makeobj/CMakeLists.txt000066400000000000000000000053241474050137200205160ustar00rootroot00000000000000# # This file is part of the Simutrans project under the artistic licence. # (see licence.txt) # add_executable(makeobj makeobj.cc ) target_compile_options(makeobj PRIVATE ${SIMUTRANS_COMMON_COMPILE_OPTIONS}) target_compile_definitions(makeobj PRIVATE MAKEOBJ=1 COLOUR_DEPTH=0) target_compile_definitions(makeobj PRIVATE MSG_LEVEL=${SIMUTRANS_MSG_LEVEL}) if (SIMUTRANS_USE_SYSLOG) target_compile_definitions(simutrans PRIVATE SYSLOG=1) endif () if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND SIMUTRANS_BUILD_32BIT) target_compile_options(makeobj PRIVATE -m32) set_target_properties(makeobj PROPERTIES LINK_FLAGS "-m32") endif () target_link_libraries(makeobj PNG::PNG ) # These source files are unique to makeobj target_sources(makeobj PRIVATE ../simutrans/descriptor/writer/bridge_writer.cc ../simutrans/descriptor/writer/building_writer.cc ../simutrans/descriptor/writer/citycar_writer.cc ../simutrans/descriptor/writer/crossing_writer.cc ../simutrans/descriptor/writer/factory_writer.cc ../simutrans/descriptor/writer/get_climate.cc ../simutrans/descriptor/writer/get_waytype.cc ../simutrans/descriptor/writer/good_writer.cc ../simutrans/descriptor/writer/groundobj_writer.cc ../simutrans/descriptor/writer/ground_writer.cc ../simutrans/descriptor/writer/image_writer.cc ../simutrans/descriptor/writer/imagelist2d_writer.cc ../simutrans/descriptor/writer/imagelist_writer.cc ../simutrans/descriptor/writer/obj_node.cc ../simutrans/descriptor/writer/obj_writer.cc ../simutrans/descriptor/writer/pedestrian_writer.cc ../simutrans/descriptor/writer/roadsign_writer.cc ../simutrans/descriptor/writer/root_writer.cc ../simutrans/descriptor/writer/sim_writer.cc ../simutrans/descriptor/writer/skin_writer.cc ../simutrans/descriptor/writer/sound_writer.cc ../simutrans/descriptor/writer/text_writer.cc ../simutrans/descriptor/writer/tree_writer.cc ../simutrans/descriptor/writer/tunnel_writer.cc ../simutrans/descriptor/writer/vehicle_writer.cc ../simutrans/descriptor/writer/way_writer.cc ../simutrans/descriptor/writer/way_obj_writer.cc ../simutrans/descriptor/writer/xref_writer.cc ) # These source files produce the same object code in makeobj and simutrans target_sources(makeobj PRIVATE ../simutrans/descriptor/image.cc ../simutrans/dataobj/freelist.cc ../simutrans/io/raw_image.cc ../simutrans/simio.cc ../simutrans/simdebug.cc ../simutrans/simmem.cc ../simutrans/utils/simstring.cc ../simutrans/utils/searchfolder.cc ) # These source files produce different object code in makeobj and simutrans target_sources(makeobj PRIVATE ../simutrans/dataobj/tabfile.cc ../simutrans/io/classify_file.cc ../simutrans/io/raw_image_bmp.cc ../simutrans/io/raw_image_png.cc ../simutrans/io/raw_image_ppm.cc ../simutrans/utils/log.cc ) simutrans-124.3/src/makeobj/Makefile000066400000000000000000000115031474050137200174120ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # CFG ?= default -include ../../config.$(CFG) OSTYPES = beos cygwin freebsd haiku linux mingw mac ifeq ($(findstring $(OSTYPE), $(OSTYPES)),) $(error Unkown OSTYPE "$(OSTYPE)", must be one of "$(OSTYPES)") endif PNG_CONFIG ?= pkg-config libpng ifneq ($(PNG_CONFIG),) PNG_CFLAGS := $(shell $(PNG_CONFIG) --cflags) PNG_LDFLAGS := $(shell $(PNG_CONFIG) --libs) endif CFLAGS += $(PNG_CFLAGS) LDFLAGS += $(PNG_LDFLAGS) # Absolutely essential CXXFLAGS += -DMAKEOBJ STD_LIBS += -lz -lbz2 -lpng ifeq ($(OSTYPE),cygwin) OS_INC ?= -I/usr/include/mingw OS_OPT ?= -mwin32 STD_LIBS += -lwinmm endif ifeq ($(OSTYPE),mingw) OS_OPT ?= -DPNG_STATIC -DZLIB_STATIC -march=pentium LDFLAGS += -static-libgcc -static-libstdc++ -static # we need the libraries EXACTLY in this order to link STD_LIBS = -lmingw32 -lpng -lz endif ifeq ($(OSTYPE),mac) CXXFLAGS += -DUSE_HW -DUSE_C endif ifeq ($(OSTYPE),freebsd) CXXFLAGS += -I/usr/local/include endif ifdef OPTIMISE ifeq ($(shell expr $(OPTIMISE) \>= 1), 1) CXXFLAGS += -O3 # clang does not support fno-schedule-insns ifeq ($(findstring clang, $(CXX)),) CXXFLAGS += -fno-schedule-insns endif endif else CXXFLAGS += -O endif ifdef DEBUG ifeq ($(shell expr $(DEBUG) \>= 1), 1) CXXFLAGS += -g -DDEBUG endif ifeq ($(shell expr $(DEBUG) \>= 2), 1) CXXFLAGS += -fno-inline endif ifeq ($(shell expr $(DEBUG) \>= 3), 1) CXXFLAGS += -O0 endif else CXXFLAGS += -DNDEBUG endif ifdef PROFILE ifeq ($(shell expr $(PROFILE) \>= 1), 1) CXXFLAGS += -pg -DPROFILE -fno-inline LDFLAGS += -pg endif endif CXXFLAGS += -DREVISION -Wall -Wextra -Wcast-qual -Wpointer-arith -Wcast-align $(OS_INC) $(OS_OPT) $(FLAGS) # SOLO_SOURCES contains files which are unique to makeobj; # SHARED_SOURCES contains those with the exact same object code in makeobj and simutrans; # VARIANT_SOURCES contains those which need different .o files for makeobj and simutrans. # At the moment they're all treated identically, of course. SOLO_SOURCES += makeobj.cc SOLO_SOURCES += ../simutrans/descriptor/writer/bridge_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/building_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/citycar_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/crossing_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/factory_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/get_climate.cc SOLO_SOURCES += ../simutrans/descriptor/writer/get_waytype.cc SOLO_SOURCES += ../simutrans/descriptor/writer/good_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/groundobj_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/ground_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/image_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/imagelist2d_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/imagelist_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/obj_node.cc SOLO_SOURCES += ../simutrans/descriptor/writer/obj_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/pedestrian_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/roadsign_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/root_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/sim_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/skin_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/sound_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/text_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/tree_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/tunnel_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/vehicle_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/way_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/way_obj_writer.cc SOLO_SOURCES += ../simutrans/descriptor/writer/xref_writer.cc SHARED_SOURCES += ../simutrans/descriptor/image.cc SHARED_SOURCES += ../simutrans/dataobj/freelist.cc SHARED_SOURCES += ../simutrans/io/raw_image.cc SHARED_SOURCES += ../simutrans/simio.h SHARED_SOURCES += ../simutrans/simdebug.cc SHARED_SOURCES += ../simutrans/simmem.cc SHARED_SOURCES += ../simutrans/utils/simstring.cc SHARED_SOURCES += ../simutrans/utils/searchfolder.cc VARIANT_SOURCES += ../simutrans/dataobj/tabfile.cc VARIANT_SOURCES += ../simutrans/io/classify_file.cc VARIANT_SOURCES += ../simutrans/io/raw_image_bmp.cc VARIANT_SOURCES += ../simutrans/io/raw_image_png.cc VARIANT_SOURCES += ../simutrans/io/raw_image_ppm.cc VARIANT_SOURCES += ../simutrans/utils/log.cc SOURCES ?= $(SOLO_SOURCES) $(SHARED_SOURCES) $(VARIANT_SOURCES) BUILDDIR ?= build/$(CFG) TOOL = makeobj PROG ?= makeobj ifeq ($(origin MAKEOBJ_PROGDIR), undefined) MAKEOBJ_PROGDIR := ../../$(BUILDDIR)/$(TOOL) endif BUILDDIR := ../../$(BUILDDIR) TOOL_PROGDIR = $(MAKEOBJ_PROGDIR) include ../../uncommon.mk simutrans-124.3/src/makeobj/Makeobj.sln000066400000000000000000000020651474050137200200430ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Makeobj", "Makeobj.vcxproj", "{9944405A-74A3-443D-83A6-F4B9DBE23DB2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9944405A-74A3-443D-83A6-F4B9DBE23DB2}.Debug|x86.ActiveCfg = Debug|Win32 {9944405A-74A3-443D-83A6-F4B9DBE23DB2}.Debug|x86.Build.0 = Debug|Win32 {9944405A-74A3-443D-83A6-F4B9DBE23DB2}.Release|x86.ActiveCfg = Release|Win32 {9944405A-74A3-443D-83A6-F4B9DBE23DB2}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {179303F5-62B6-4464-85DF-782B62356351} EndGlobalSection EndGlobal simutrans-124.3/src/makeobj/Makeobj.vcxproj000066400000000000000000000316341474050137200207460ustar00rootroot00000000000000 Debug Win32 Release Win32 {9944405A-74A3-443D-83A6-F4B9DBE23DB2} Makeobj Application $(DefaultPlatformToolset) true <_ProjectFileVersion>16.0.28916.169 $(SolutionDir)..\build\makeobj\$(Configuration)\ $(SolutionDir)..\build\makeobj\$(Configuration)\ $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) true x86-windows-static true x86-windows-static true Level3 true true 4250;4373;4800;4996 true Console MachineX86 ProgramDatabase Disabled MAKEOBJ;DEBUG=3 MultiThreadedDebug EnableFastChecks true false MaxSpeed true Speed MAKEOBJ;NDEBUG MultiThreaded false true simutrans-124.3/src/makeobj/Makeobj.vcxproj.filters000066400000000000000000000015041474050137200224060ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 simutrans-124.3/src/makeobj/RightClickCompileDat2PakSystem.reg000066400000000000000000000075161474050137200243720ustar00rootroot00000000000000ÿþWindows Registry Editor Version 5.00 ; This file will include two context menu options for compiling DAT files to PAK ; YOU MUST EDIT IT TO REFLECT THE CURRENT MAKEOBJ LOCATION AND PAK SIZE! [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat] ; This sets the default action to run when opening a dat file, uncomment to make it compile the pak automatically, change to makeobjCustom to make it ask for a size. ; @="makeobj" [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat\shell] ; This and the next entry add a command that will automatically compile the DAT to a PAK [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat\shell\makeobj] ; Text that will show in the context menu @="Compile to pakNUMBER" ; Icon that will show in the context menu, remove if you don't want an icon ; Change DIR to the location of the icon, notice that backslashes must be double "Icon"="DIR\\makeobj.ico" [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat\shell\makeobj\Command] ; Change NUMBER to the pakset size you want to compile automatically ; Change PATH to your makeobj executable ; e.g. C:\\Users\\Me\\Documents\\makeobj.exe @="cmd /v:on /c set file=%1&set file=!file:%W\\=!&PATH pakNUMBER ./ \"!file!\"" ; These two last entries add an option that will ask you to enter the pakset size to compile, useful to compile other sizes you don't work all the time [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat\shell\makeobjCustom] ; Text that will show in the context menu @="Compile to pak" ; Icon that will show in the context menu, remove if you don't want an icon ; Change DIR to the location of the icon, notice that backslashes must be double "Icon"="DIR\\makeobj.ico" [HKEY_CLASSES_ROOT\SystemFileAssociations\.dat\shell\makeobjCustom\Command] ; Change PATH to your makeobj executable ; e.g. C:\\Users\\Me\\Documents\\makeobj.exe @="cmd /v:on /c set file=%1&set file=!file:%W\\=!&set /p size=\"Enter size: \"&PATH pak!size! ./ \"!file!\"" simutrans-124.3/src/makeobj/makeobj.cc000066400000000000000000000127151474050137200176770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simutrans/utils/log.h" log_t::level_t debuglevel = log_t::LEVEL_WARN; #include "../simutrans/simdebug.h" #include "../simutrans/simtypes.h" #include "../simutrans/simversion.h" #include "../simutrans/utils/simstring.h" #include "../simutrans/descriptor/writer/obj_pak_exception.h" #include "../simutrans/descriptor/writer/root_writer.h" #include "../simutrans/descriptor/writer/image_writer.h" // Needed to avoid linking problems uint32 dr_time(void) { return 0; } int main(int argc, char* argv[]) { argv++; argc--; init_logging("stderr", true, true, "", "makeobj"); debuglevel = log_t::LEVEL_WARN; // only warnings and errors while( argc && ( !STRICMP(argv[0], "quiet") || !STRICMP(argv[0], "verbose") || !STRICMP(argv[0], "debug") ) ) { if (argc && !STRICMP(argv[0], "debug")) { argv++; argc--; debuglevel = log_t::LEVEL_DEBUG; // everything } else if (argc && !STRICMP(argv[0], "verbose")) { argv++; argc--; debuglevel = log_t::LEVEL_MSG; // only messages errors } else if (argc && !STRICMP(argv[0], "quiet")) { argv++; argc--; debuglevel = log_t::LEVEL_ERROR; // only fatal errors } } if( debuglevel>=log_t::LEVEL_WARN ) { puts( "Makeobj version " MAKEOBJ_VERSION " for Simutrans " VERSION_NUMBER " and higher" ); puts( "(c) 2002-2012 V. Meyer, Hj. Malthaner, M. Pristovsek & Simutrans development team\n" ); } if (argc && !STRICMP(argv[0], "capabilities")) { argv++; argc--; root_writer_t::instance()->capabilites(); return 0; } if (argc && !STRICMP(argv[0], "pak")) { argv++; argc--; try { const char* dest; if (argc) { dest = argv[0]; argv++; argc--; } else { dest = "./"; } root_writer_t::instance()->write(dest, argc, argv); } catch (const obj_pak_exception_t& e) { dbg->error( e.get_class(), e.get_info() ); return 1; } return 0; } if (argc && STRNICMP(argv[0], "pak", 3) == 0) { const int img_size = atoi(argv[0] + 3); if (img_size >= 16 && img_size < 32766) { dbg->message( "Image size", "Now set to %dx%d", img_size, img_size ); obj_writer_t::set_img_size(img_size); argv++; argc--; try { const char* dest; if (argc) { dest = argv[0]; argv++; argc--; } else { dest = "./"; } root_writer_t::instance()->write(dest, argc, argv); } catch (const obj_pak_exception_t& e) { dbg->error( e.get_class(), e.get_info() ); return 1; } return 0; } } if (argc && !STRICMP(argv[0], "expand")) { argv++; argc--; try { const char* dest; if (argc) { dest = argv[0]; argv++; argc--; } else { dest = "./"; } root_writer_t::instance()->expand_dat(dest, argc, argv); } catch (const obj_pak_exception_t& e) { dbg->error( e.get_class(), e.get_info() ); return 1; } return 0; } if (argc > 1) { if (!STRICMP(argv[0], "dump")) { argv++; argc--; root_writer_t::instance()->dump(argc, argv); return 0; } if (!STRICMP(argv[0], "list")) { argv++; argc--; root_writer_t::instance()->list(argc, argv); return 0; } if (!STRICMP(argv[0], "extract")) { argv++; argc--; root_writer_t::instance()->uncopy(argv[0]); return 0; } if (!STRICMP(argv[0], "merge")) { argv++; argc--; try { const char* dest = argv[0]; argv++; argc--; root_writer_t::instance()->copy(dest, argc, argv); } catch (const obj_pak_exception_t& e) { dbg->error( e.get_class(), e.get_info() ); return 1; } return 0; } } puts( "\n Usage: MakeObj [QUIET|VERBOSE|DEBUG] \n" "\n" " MakeObj CAPABILITIES\n" " Gives the list of objects, this program can read\n" " MakeObj PAK \n" " Creates a ready to use pak file for Simutrans from the dat files\n" " MakeObj pak128 \n" " Creates a special pak file for with 128x128 images\n" " Works with PAK16 up to PAK32767 but only up to 255 are tested\n" " MakeObj LIST \n" " Lists the contents of the given pak files\n" " MakeObj DUMP \n" " List the internal nodes of a file\n" " MakeObj MERGE \n" " Merges multiple pak files into one new pak file library\n" " MakeObj EXPAND \n" " Expands minified notation to complete notation on dat file(s)\n" " MakeObj EXTRACT \n" " Creates single files from a pak file library\n" "\n" " with a trailing slash a directory is searched rather than a file\n" " default for PAK is PAK ./ ./\n" "\n" " with QUIET as first arg status and copyright messages are omitted\n" "\n" " with VERBOSE as first arg also unused lines\n" " and unassigned entries are printed\n" "\n" " DEBUG dumps extended information about the pak process.\n" " Source: interpreted line from .dat file\n" " Image: .png file name\n" " X: X start position in .png to pack\n" " Y: Y start position in .png to pack\n" " Off X: X offset in image\n" " Off Y: Y offset in image\n" " Width: image width\n" " Width: image height\n" " Zoom: If image is zoomable or not\n" ); return 3; } simutrans-124.3/src/makeobj/vcpkg.json000066400000000000000000000002431474050137200177560ustar00rootroot00000000000000{ "name": "makeobj", "version-string": "1.0.0", "dependencies": [ "libpng" ], "builtin-baseline": "3c76dc55f8bd2b7f4824bcd860055094bfbbb9ea" }simutrans-124.3/src/nettool/000077500000000000000000000000001474050137200160265ustar00rootroot00000000000000simutrans-124.3/src/nettool/CMakeLists.txt000066400000000000000000000027751474050137200206010ustar00rootroot00000000000000# # This file is part of the Simutrans project under the artistic licence. # (see licence.txt) # add_executable(nettool nettool.cc ) target_compile_options(nettool PRIVATE ${SIMUTRANS_COMMON_COMPILE_OPTIONS}) target_compile_definitions(nettool PRIVATE NETTOOL=1 COLOUR_DEPTH=0) target_compile_definitions(nettool PRIVATE MSG_LEVEL=${SIMUTRANS_MSG_LEVEL}) if (SIMUTRANS_USE_SYSLOG) target_compile_definitions(nettool PRIVATE SYSLOG=1) endif () if (NOT SIMUTRANS_USE_IPV6) target_compile_definitions(nettool PRIVATE USE_IP4_ONLY=1) endif () if (NOT CMAKE_SIZEOF_VOID_P EQUAL 4 AND SIMUTRANS_BUILD_32BIT) target_compile_options(nettool PRIVATE -m32) set_target_properties(nettool PROPERTIES LINK_FLAGS "-m32") endif () # these source files produce the same object code in nettool and simutrans target_sources(nettool PRIVATE ../simutrans/dataobj/freelist.cc ../simutrans/network/memory_rw.cc ../simutrans/network/network_address.cc ../simutrans/network/network_cmd.cc ../simutrans/network/network_packet.cc ../simutrans/network/network_socket_list.cc ../simutrans/simdebug.cc ../simutrans/simmem.cc ../simutrans/utils/simstring.cc ../simutrans/utils/fetchopt.cc ../simutrans/utils/sha1.cc ../simutrans/utils/sha1_hash.cc ) # these source files produce different object code in nettool and simutrans target_sources(nettool PRIVATE ../simutrans/utils/log.cc ../simutrans/network/network.cc ../simutrans/network/network_file_transfer.cc ) if (WIN32) target_link_libraries(nettool PRIVATE ws2_32) endif (WIN32) simutrans-124.3/src/nettool/Makefile000066400000000000000000000055111474050137200174700ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # CFG ?= default -include ../../config.$(CFG) OSTYPES = beos cygwin freebsd haiku linux mingw mac ifeq ($(findstring $(OSTYPE), $(OSTYPES)),) $(error Unkown OSTYPE "$(OSTYPE)", must be one of "$(OSTYPES)") endif # Absolutely essential CXXFLAGS += -DNETTOOL ifeq ($(OSTYPE),cygwin) OS_INC ?= -I/usr/include/mingw OS_OPT ?= -mwin32 STD_LIBS += -lwinmm -lcurses endif ifeq ($(OSTYPE),mingw) CC ?= gcc OS_OPT ?= -march=pentium # we need the libraries EXACTLY in this order to link STD_LIBS = -lmingw32 -lstdc++ -lws2_32 endif ifeq ($(OSTYPE),mac) CXXFLAGS += -DUSE_HW -DUSE_C endif ifdef OPTIMISE ifeq ($(shell expr $(OPTIMISE) \>= 1), 1) CXXFLAGS += -O3 # clang does not support fno-schedule-insns ifeq ($(findstring clang, $(CXX)),) CXXFLAGS += -fno-schedule-insns endif endif else CXXFLAGS += -O endif ifdef DEBUG ifeq ($(shell expr $(DEBUG) \>= 1), 1) CXXFLAGS += -g -DDEBUG endif ifeq ($(shell expr $(DEBUG) \>= 2), 1) CXXFLAGS += -fno-inline endif ifeq ($(shell expr $(DEBUG) \>= 3), 1) CXXFLAGS += -O0 endif else CXXFLAGS += -DNDEBUG endif ifdef PROFILE ifeq ($(shell expr $(PROFILE) \>= 1), 1) CXXFLAGS += -pg -DPROFILE -fno-inline LDFLAGS += -pg endif endif CXXFLAGS += -DREVISION -Wall -Wextra -Wcast-qual -Wpointer-arith -Wcast-align $(OS_INC) $(OS_OPT) $(FLAGS) # SOLO_SOURCES contains files which are unique to nettool; # SHARED_SOURCES contains those with the exact same object code in nettool and simutrans; # VARIANT_SOURCES contains those which need different .o files for nettool and simutrans. # At the moment they're all treated identically, of course. SOLO_SOURCES += nettool.cc SHARED_SOURCES += ../simutrans/dataobj/freelist.cc SHARED_SOURCES += ../simutrans/network/memory_rw.cc SHARED_SOURCES += ../simutrans/network/network_address.cc SHARED_SOURCES += ../simutrans/network/network_cmd.cc SHARED_SOURCES += ../simutrans/network/network_packet.cc SHARED_SOURCES += ../simutrans/network/network_socket_list.cc SHARED_SOURCES += ../simutrans/simdebug.cc SHARED_SOURCES += ../simutrans/simmem.cc SHARED_SOURCES += ../simutrans/utils/simstring.cc SHARED_SOURCES += ../simutrans/utils/fetchopt.cc SHARED_SOURCES += ../simutrans/utils/sha1.cc SHARED_SOURCES += ../simutrans/utils/sha1_hash.cc VARIANT_SOURCES += ../simutrans/utils/log.cc VARIANT_SOURCES += ../simutrans/network/network.cc VARIANT_SOURCES += ../simutrans/network/network_file_transfer.cc SOURCES ?= $(SOLO_SOURCES) $(SHARED_SOURCES) $(VARIANT_SOURCES) BUILDDIR ?= build/$(CFG) TOOL = nettool PROG ?= nettool ifeq ($(origin NETTOOL_PROGDIR), undefined) NETTOOL_PROGDIR := ../../$(BUILDDIR)/$(TOOL) endif BUILDDIR := ../../$(BUILDDIR) TOOL_PROGDIR = $(NETTOOL_PROGDIR) include ../../uncommon.mk simutrans-124.3/src/nettool/Nettool.sln000066400000000000000000000020651474050137200201730ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Nettool", "Nettool.vcxproj", "{6E485CA6-1FC1-45D2-97DC-0FD5197BF746}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6E485CA6-1FC1-45D2-97DC-0FD5197BF746}.Debug|x86.ActiveCfg = Debug|Win32 {6E485CA6-1FC1-45D2-97DC-0FD5197BF746}.Debug|x86.Build.0 = Debug|Win32 {6E485CA6-1FC1-45D2-97DC-0FD5197BF746}.Release|x86.ActiveCfg = Release|Win32 {6E485CA6-1FC1-45D2-97DC-0FD5197BF746}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BDF946B2-9B0A-44E7-974A-39C03A80EC45} EndGlobalSection EndGlobal simutrans-124.3/src/nettool/Nettool.vcxproj000066400000000000000000000176221474050137200210770ustar00rootroot00000000000000 Debug Win32 Release Win32 {6E485CA6-1FC1-45D2-97DC-0FD5197BF746} Nettool Application $(DefaultPlatformToolset) true <_ProjectFileVersion>16.0.28916.169 $(SolutionDir)..\build\nettool\$(Configuration)\ $(SolutionDir)..\build\nettool\$(Configuration)\ $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) $(SimIncludePath);$(IncludePath) $(SimLibraryPath);$(LibraryPath) Level3 true true 4250;4373;4800;4996 zlibstat.lib;Ws2_32.lib;wsock32.lib true Console MachineX86 ProgramDatabase Disabled NETTOOL;DEBUG=3;NOMINMAX MultiThreadedDebug EnableFastChecks true false MaxSpeed true Speed NETTOOL;NDEBUG;NOMINMAX MultiThreaded false true simutrans-124.3/src/nettool/nettool.cc000066400000000000000000000423761474050137200200350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * Network server control tool for Simutrans */ #include #include #include // Needed for interaction with console // also needed, but this is included by networking code #ifndef _WIN32 #include #endif #include "../simutrans/network/network.h" #include "../simutrans/network/network_cmd.h" #include "../simutrans/network/network_packet.h" #include "../simutrans/network/network_socket_list.h" #include "../simutrans/simmem.h" #include "../simutrans/simtypes.h" #include "../simutrans/simversion.h" #include "../simutrans/utils/simstring.h" #include "../simutrans/utils/fetchopt.h" #include "../simutrans/utils/sha1.h" // dummy implementation // only receive nwc_service_t here // called from network_check_activity network_command_t* network_command_t::read_from_packet(packet_t *p) { // check data if (p==NULL || p->has_failed() || !p->check_version()) { delete p; dbg->warning("network_command_t::read_from_packet", "error in packet"); return NULL; } network_command_t* nwc = NULL; switch (p->get_id()) { case NWC_SERVICE: nwc = new nwc_service_t(); break; default: dbg->warning("network_command_t::read_from_socket", "received unknown packet id %d", p->get_id()); } if (nwc) { if (!nwc->receive(p) || p->has_failed()) { dbg->warning("network_command_t::read_from_packet", "error while reading cmd from packet"); delete nwc; nwc = NULL; } } return nwc; } network_command_t* network_receive_command(uint16 id) { // wait for command with id, ignore other commands for(uint8 i=0; i<5; i++) { network_command_t* nwc = network_check_activity( 10000 ); if (nwc && nwc->get_id() == id) { return nwc; } delete nwc; } dbg->warning("network_receive_command", "no command with id=%d received", id); return NULL; } // echo() used to set whether terminal should echo user input or not // Used for more secure password entry #ifdef _WIN32 void echo(bool on) { DWORD mode; HANDLE hConIn = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(hConIn, &mode); mode = on ? (mode | ENABLE_ECHO_INPUT) : (mode & ~(ENABLE_ECHO_INPUT)); SetConsoleMode(hConIn, mode); } #else // Should be good for POSIX platforms void echo(bool on) { struct termios settings; tcgetattr(STDIN_FILENO, &settings); settings.c_lflag = on ? (settings.c_lflag | ECHO) : (settings.c_lflag & ~(ECHO)); tcsetattr(STDIN_FILENO, TCSANOW, &settings); } #endif /** * Sets nwcs.flag = command_id, text to argv[1], number to argv[0]. * @returns true upon success */ bool fill_nwc_service(nwc_service_t &nwcs, uint32 command_id, int argc, char **argv) { nwcs.flag = command_id; switch (argc) { case 2: // second argument is a string if (argv[1]) { nwcs.text = strdup( argv[1] ); } case 1: // first argument is a positive number { int _n = atoi(argv[0]); if (_n >=0) { nwcs.number = _n; } else { return false; } } default: break; } return true; } // Simple commands specify only a command ID to perform an action on the server int simple_command(SOCKET socket, uint32 command_id, int argc, char **argv) { nwc_service_t nwcs; if ( !fill_nwc_service(nwcs, command_id, argc, argv) ) { return 3; } if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } return 0; } // Simple command to send command ID to server and receive and print a text buffer int simple_gettext_command(SOCKET socket, uint32 command_id, int argc, char **argv) { nwc_service_t nwcs; if ( !fill_nwc_service(nwcs, command_id, argc, argv) ) { return 3; } if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } nwc_service_t *nws = (nwc_service_t*)network_receive_command(NWC_SERVICE); if (nws==NULL) { return 3; } if (nws->flag != command_id) { delete nws; return 3; } if (nws->text) { printf("%s", nws->text); } else { printf("Nothing received.\n"); } delete nws; return 0; } int get_client_list(SOCKET socket, uint32 command_id, int, char **) { nwc_service_t nwcs; nwcs.flag = command_id; if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } nwc_service_t *nws = (nwc_service_t*)network_receive_command(NWC_SERVICE); if (nws==NULL) { return 3; } if (nws->flag != command_id || nws->socket_info==NULL) { delete nws; return 3; } // now get client list from packet vector_tpl &list = *(nws->socket_info); bool head = false; for(uint32 i=0; istate==socket_info_t::playing) { if (!head) { printf("List of playing clients:\n"); head = true; } uint32 ip = list[i]->address.ip; printf(" [%3d] .. %02d.%02d.%02d.%02d\n", i, (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); } } if (!head) { printf("No playing clients.\n"); } delete nws; return 0; } int kick_client(SOCKET socket, uint32 command_id, int, char **argv) { int client_nr = 0; client_nr = atoi(argv[0]); if (client_nr<=0) { return 3; } nwc_service_t nwcs; nwcs.flag = command_id; nwcs.number = client_nr; if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } return 0; } int ban_client(SOCKET socket, uint32 command_id, int, char **argv) { int client_nr = 0; client_nr = atoi(argv[0]); if (client_nr<=0) { return 3; } nwc_service_t nwcs; nwcs.flag = command_id; nwcs.number = client_nr; if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } return 0; } int get_blacklist(SOCKET socket, uint32 command_id, int, char **) { nwc_service_t nwcs; nwcs.flag = command_id; if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } nwc_service_t *nws = (nwc_service_t*)network_receive_command(NWC_SERVICE); if (nws==NULL) { return 3; } if (nws->flag != command_id || nws->address_list==NULL) { delete nws; return 3; } // now get list from packet address_list_t &list = *(nws->address_list); if (list.empty()) { printf("Blacklist empty\n"); } else { printf("List of banned addresses:\n"); } for(uint32 i=0; i=0; j-=8) { uint32 m = (list[i].mask >> j) & 0xff; if (m) { printf("%02d", (list[i].ip >> j) & 0xff); if ( m != 0xff) { printf("[%02x]", m); } if (j > 0) { printf("."); } } else { break; } } printf("\n"); } delete nws; return 0; } int ban_ip(SOCKET socket, uint32 command_id, int, char **argv) { net_address_t address(argv[0]); if (address.ip) { nwc_service_t nwcs; nwcs.flag = command_id; nwcs.text = strdup(argv[0]); if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } } return 0; } int unban_ip(SOCKET socket, uint32 command_id, int, char **argv) { net_address_t address(argv[0]); if (address.ip) { nwc_service_t nwcs; nwcs.flag = command_id; nwcs.text = strdup(argv[0]); if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } } return 0; } int say(SOCKET socket, uint32 command_id, int argc, char **argv) { nwc_service_t nwcs; nwcs.flag = command_id; // Cat all arguments together into message to send const int maxlen = 513; int remaining = maxlen - 1; char msg[maxlen]; int ind = 0; tstrncpy(msg, argv[ind], remaining); remaining -= strlen(argv[ind]); ind++; while (ind < argc && remaining > 1) { strcat(msg, " "); remaining -= 1; strncat(msg, argv[ind], remaining); remaining -= strlen(argv[ind]); ind++; } nwcs.text = strdup(msg); if (!nwcs.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } return 0; } int lock_company(SOCKET socket, uint32, int argc, char **argv) { // player number int _n = atoi(argv[0]); if (_n < 0 || _n >= 15 /*PLAYER_UNOWNED*/ ) { return 3; } uint8 player_nr = _n; // password source bool pwd_from_cl = strcmp(argv[1], "-F") != 0; if (!pwd_from_cl && argc<3) { return 3; } const char* password = NULL; // password if (pwd_from_cl) { password = argv[1]; } else { if (strcmp(argv[2], "-")==0) { // Read password from stdin char* password_in = MALLOCN(char, 256); fprintf(stderr, "Password: "); echo(false); scanf("%255s", password_in); echo(true); printf("\n"); password = password_in; } else if (FILE* const fd = fopen(argv[2], "r")) { // malloc ok here as utility is short-lived so no need to free() size_t const size = 256; char* password_in = MALLOCN(char, size); fgets(password_in, size, fd); password_in[strcspn(password_in, "\n")] = '\0'; fclose(fd); password = password_in; } else { return 3; } } printf("new password: %s\n",password); pwd_hash_t pwd_hash; { SHA1 sha1; sha1.Input(password, strlen(password)); sha1.Result(pwd_hash); } // now send nwc_auth_t command nwc_auth_player_t nwca(player_nr, pwd_hash); if (!nwca.send(socket)) { fprintf(stderr, "Could not send request!\n"); return 2; } return 0; } // Print usage and exit void usage() { fprintf(stderr, "nettool for Simutrans " VERSION_NUMBER " and higher\n" "\n" " Usage:\n" "\n" " nettool [options] [command argument]\n" "\n" " Options:\n" " -s : Specify server to connect to (default is localhost:13353)\n" " -p : Set password on command line\n" " -P : Read password from file specified (use '-' to read from stdin)\n" " -q : Quiet mode, copyright message will be omitted\n" "\n" " Commands:\n" " announce\n" " Request server announce itself to the central listing server\n" "\n" " clients\n" " Receive list of playing clients from server\n" "\n" " companies\n" " Receive list of running companies from server\n" "\n" " info-company \n" " Show detailed info for company\n" "\n" " lock-company \n" " lock-company -F \n" " Set password, read from file if specified (use '-' to read from stdin)\n" "\n" " unlock-company \n" " Clear password of company, effectively unlocking it for all clients\n" "\n" " remove-company \n" " Immediately remove company and all its belongings\n" "\n" " kick-client \n" " ban-client \n" " Kick / ban client (use clients command to get client number)\n" "\n" " ban-ip \n" " unban-ip \n" " Ban / unban ip address\n" "\n" " blacklist\n" " Display list of banned clients\n" "\n" " say \n" " Send admin message to all clients (maximum of 512 characters)\n" "\n" " shutdown\n" " Shut down server\n" "\n" " force-sync\n" " Force server to send sync command in order to save & reload the game\n" "\n" " Return codes:\n" " 0 .. success\n" " 1 .. server not reachable\n" " 2 .. could not send message to server\n" " 3 .. misc errors\n" "\n" ); exit(3); } // For each command, set: // name - char* - name of command as specified on command line // needs_auth - bool - specifies whether authentication is required for command // command_id - int - nwc_service_t command ID for the command in question // arguments - int - does this command require arguments, and if so how many? // function - function* - function pointer to function to evaluate for this command struct command_t { const char *name; bool needs_auth; uint32 command_id; int numargs; int (*func)(SOCKET, uint32, int, char**); }; int main(int argc, char* argv[]) { init_logging("stderr", true, true, NULL, "nettool"); // Use Fetchopt to parse option flags Fetchopt_t fetchopt(argc, argv, "hp:P:qs:"); bool opt_q = false; char default_server_address[] = "localhost:13353"; char *server_address = default_server_address; char *password = NULL; int ch; while ((ch = fetchopt.next()) != -1) { switch (ch) { case 'p': // Password specified on command line password = fetchopt.get_optarg(); break; case 'P': // Read password in from file specified // if filename is '-', read in from stdin if (!strcmp(fetchopt.get_optarg(), "-")) { // Password will be asked for later } else if (FILE* const fd = fopen(fetchopt.get_optarg(), "r")) { // malloc ok here as utility is short-lived so no need to free() size_t const size = 256; password = MALLOCN(char, size); fgets(password, size, fd); password[strcspn(password, "\n")] = '\0'; fclose(fd); } else { // Failure, file empty fprintf(stderr, "Unable to open file \"%s\" to read password\n", fetchopt.get_optarg()); } break; case 'q': opt_q = true; break; case 's': server_address = fetchopt.get_optarg(); break; case '?': case 'h': default: usage(); /* NOTREACHED */ } } // argc is length of argv, so argv[0] is first arg (name of program) // and argv[argc-1] is the last argument // After parsing arguments fetchopt.get_optind() will return the index // of the next argv after the last option // If this is equal to argc then there are no more arguments, this means // that the command has been omitted (which is a failure condition so usage // should be printed) // For commands which should take an argument, check that fetchopt.get_optind()+1 // is less than argc as well if (fetchopt.get_optind() >= argc) { usage(); } command_t commands[] = { {"announce", false, nwc_service_t::SRVC_ANNOUNCE_SERVER, 0, &simple_command}, {"clients", true, nwc_service_t::SRVC_GET_CLIENT_LIST, 0, &get_client_list}, {"kick-client", true, nwc_service_t::SRVC_KICK_CLIENT, 1, &kick_client}, {"ban-client", true, nwc_service_t::SRVC_BAN_CLIENT, 1, &ban_client}, {"blacklist", true, nwc_service_t::SRVC_GET_BLACK_LIST, 0, &get_blacklist}, {"ban-ip", true, nwc_service_t::SRVC_BAN_IP, 1, &ban_ip}, {"unban-ip", true, nwc_service_t::SRVC_UNBAN_IP, 1, &unban_ip}, {"say", true, nwc_service_t::SRVC_ADMIN_MSG, 1, &say}, {"shutdown", true, nwc_service_t::SRVC_SHUTDOWN, 0, &simple_command}, {"force-sync", true, nwc_service_t::SRVC_FORCE_SYNC, 0, &simple_command}, {"companies", true, nwc_service_t::SRVC_GET_COMPANY_LIST, 0, &simple_gettext_command}, {"info-company", true, nwc_service_t::SRVC_GET_COMPANY_INFO, 1, &simple_gettext_command}, {"unlock-company", true, nwc_service_t::SRVC_UNLOCK_COMPANY, 1, &simple_command}, {"remove-company", true, nwc_service_t::SRVC_REMOVE_COMPANY, 1, &simple_command}, {"lock-company", true, nwc_service_t::SRVC_LOCK_COMPANY, 2, &lock_company} }; int numcommands = lengthof(commands); // Determine which command we're running & validate any arguments int cmdindex; for (cmdindex = 0; cmdindex < numcommands; cmdindex++) { if (strcmp(commands[cmdindex].name, argv[fetchopt.get_optind()]) == 0) { // Validate number of parameters if (fetchopt.get_optind() + commands[cmdindex].numargs >= argc) { usage(); } break; } } // Unknown command if (cmdindex == numcommands) { usage(); } // Print copyright notice unless quiet flag set if (!opt_q) { fprintf(stderr, "nettool for Simutrans " VERSION_NUMBER " and higher\n" ); } // If command requires authentication and password is not set then // ask for password from stdin (interactive) if( commands[cmdindex].needs_auth && password == NULL ) { // Read password from stdin // malloc ok here as utility is short-lived so no need to free() password = MALLOCN(char, 256); fprintf(stderr, "Password: "); echo(false); scanf("%255s", password); echo(true); printf("\n"); } // This is done whether we're executing a password protected command or not... const char *error = NULL; SOCKET const socket = network_open_address(server_address, error); if (error) { fprintf(stderr, "Could not connect to server at %s: %s\n", server_address, error); return 1; } // now we are connected socket_list_t::add_client(socket); // If authentication required, perform authentication if( commands[cmdindex].needs_auth ) { // try to authenticate us nwc_service_t nwcs; nwcs.flag = nwc_service_t::SRVC_LOGIN_ADMIN; nwcs.text = strdup(password); if (!nwcs.send(socket)) { fprintf(stderr, "Could not send login data!\n"); return 2; } // wait for acknowledgement nwc_service_t *nws = (nwc_service_t*)network_receive_command(NWC_SERVICE); if( nws==NULL || nws->flag != nwc_service_t::SRVC_LOGIN_ADMIN ) { fprintf(stderr, "Authentication failed!\n"); delete nws; return 3; } if( nws->number == 0 ) { fprintf(stderr, "Wrong password!\n"); delete nws; return 3; } network_set_client_id( nws->number ); delete nws; } // Execute command function and exit with return code const int first_arg = fetchopt.get_optind() + 1; char **argv_in; int argc_in; if (first_arg >= argc) { argv_in = NULL; argc_in = 0; } else { argv_in = argv + first_arg; argc_in = argc - first_arg; } return commands[cmdindex].func(socket, commands[cmdindex].command_id, argc_in, argv_in); } simutrans-124.3/src/paksetinfo.h000066400000000000000000000057361474050137200166710ustar00rootroot00000000000000// Generated by "get_pak.sh -generate_h". DO NOT EDIT. #define PAKSET_COUNT 20 #define OBSOLETE_FROM (12) paksetinfo_t pakinfo[PAKSET_COUNT] = { { "http://downloads.sourceforge.net/project/simutrans/pak64/124-3/simupak64-124-3.zip", "pak", "pak64 124.3 r2182", 16177 }, { "http://downloads.sourceforge.net/project/simutrans/pak128/pak128%20for%20ST%20124.3up%20%282.10.0%29/simupak128-2-10-for124-3up.zip", "pak128", "pak128 2.10.0 for 124.3 git r hash ", 415604 }, { "http://downloads.sourceforge.net/project/simutrans/pak192.comic/pak192.comic%20V0.7.2/pak192-comic.zip", "pak192.comic", "Pak192.Comic V0.7.2 Rev 1296", 909748 }, { "http://simutrans-germany.com/pak.german/pak64.german_0-124-0-0-5_full.zip", "pak64.german", "pak64.german 0.124.0.0.5", 28660 }, { "http://downloads.sourceforge.net/project/simutrans/pak64.japan/123-0/simupak64.japan-123-0.zip", "pak.japan", "pak64.japan 123 r2101", 10175 }, { "https://github.com/wa-st/pak-nippon/releases/download/v0.6.2/pak.nippon-v0.6.2.zip", "pak.nippon", "pak.nippon v0.6.2", 50198 }, { "http://downloads.sourceforge.net/project/simutrans/Pak128.CS/nightly%20builds/pak128.CS-r2096.zip", "pak128.CS", "Pak128.CS 0.3.0 r2096", 78628 }, { "http://downloads.sourceforge.net/project/simutrans/pak128.britain/pak128.Britain%20for%20120-3/pak128.Britain.1.18-120-3.zip", "pak128.Britain", "pak128.Britain 1.18 120.3 r1991", 241715 }, { "http://pak128-german.de/PAK128.german_2.3_beta.zip", "PAK128.german", "Pak128.german VS 2.3.beta (Rev. 527)", 571188 }, { "https://github.com/Varkalandar/pak144.Excentrique/releases/download/r0.08/pak144.Excentrique_v008.zip", "pak144.Excentrique", "pak144.Excentrique v0.08", 7621 }, { "http://downloads.sourceforge.net/project/simutrans/pakTTD/simupakTTD-124-0.zip", "pakTTD", "pak64 120.4.1 r2146", 1995 }, { "http://codeberg.org/Nazalassa/pak48.bitlit/releases/download/0.1d/pak48.bitlit_0.1d.zip", "pak48.bitlit", "pak48.bitlit v0.1d", 1762 }, { "http://downloads.sourceforge.net/project/simutrans/pak96.comic/pak96.comic%20for%20111-3/pak96.comic-0.4.10-plus.zip", "pak96.comic", "pak96.comic V4.1 plus", 32526 }, { "http://pak128.jpn.org/souko/pak128.japan.120.0.cab", "pak128.japan", "Pak128.Japan 120.0", 27780 }, { "http://downloads.sourceforge.net/project/simutrans/pak32.comic/pak32.comic%20for%20102-0/pak32.comic_102-0.zip", "pak32", "", 3420 }, { "https://github.com/Varkalandar/pak48.Excentrique/releases/download/v0.19_RC3/pak48.excentrique_v019rc3.zip", "pak48.Excentrique", "pak48.Excentrique v0.19", 2016 }, { "http://downloads.sourceforge.net/project/simutrans/pak64.contrast/pak64.Contrast_910.zip", "pakcontrast", "", 1440 }, { "http://downloads.sourceforge.net/project/simutrans/OldFiles/PakHD_v04B_100-0.zip", "pakHD", "Martin", 12511 }, { "http://downloads.sourceforge.net/project/simutrans/pakHAJO/pakHAJO_102-2-2/pakHAJO_0-102-2-2.zip", "pakHAJO", "", 7460 }, { "http://downloads.sourceforge.net/project/simutrans/pak64.scifi/pak64.scifi_112.x_v0.2.zip", "pak64.scifi", "pak64.SciFi V0.2", 3293 }, }; simutrans-124.3/src/patches/000077500000000000000000000000001474050137200157715ustar00rootroot00000000000000simutrans-124.3/src/patches/dump-png.diff000066400000000000000000000134121474050137200203530ustar00rootroot00000000000000Index: descriptor/image.cc =================================================================== --- descriptor/image.cc (revision 10146) +++ descriptor/image.cc (working copy) @@ -189,3 +189,46 @@ } return target_image; } + + +/** + * decodes an image into a 32 bit bitmap (needed to dump images only) + */ +void image_t::decode_img(sint16 , sint16 , uint32 *target, uint32 target_width, uint32 target_height ) const +{ + if( h > 0 && w > 0 ) { + + // now: unpack the image + uint16 const *src = data; + for( sint32 yy = y; yy < h+y; yy++ ) { + uint16 runlen; + sint16 max_w = x; + uint8* p = ((uint8*)target) + x * 3 + yy * target_width * 3; + + // decode line + runlen = *src++; + do { + // clear run + p += runlen*3; + // color pixel + runlen = *src++; + while (runlen--) { + // get rgb components + uint16 s = *src++; + if( s>=0x8000 ) { + // special color + *p++ = rgbtab[s&0x001F]>>16; + *p++ = rgbtab[s&0x001F]>>8; + *p++ = rgbtab[s&0x001F]; + } + else { + *p++ = ((s>>10) & 0x001F)<<3; + *p++ = ((s>>5) & 0x001F)<<3; + *p++ = ((s) & 0x001F)<<3; + } + } + runlen = *src++; + } while( runlen!=0); + } + } +} Index: descriptor/image.h =================================================================== --- descriptor/image.h (revision 10146) +++ descriptor/image.h (working copy) @@ -80,6 +80,8 @@ void register_image() { ::register_image(this); } + void decode_img(sint16 xoff, sint16 yoff, uint32* target, uint32 target_width, uint32 target_height) const; + private: friend class image_reader_t; }; Index: descriptor/reader/image_reader.cc =================================================================== --- descriptor/reader/image_reader.cc (revision 10146) +++ descriptor/reader/image_reader.cc (working copy) @@ -19,6 +19,11 @@ #include "../../tpl/array_tpl.h" +#ifdef MAKEOBJ +#undef COLOUR_DEPTH +#define COLOUR_DEPTH 16 +#endif + // if without graphics backend, do not copy any pixel #if COLOUR_DEPTH != 0 #define skip_reading_pixels_if_no_graphics @@ -186,6 +191,7 @@ } } +#if !defined(MAKEOBJ) if (desc->len != 0) { // get the adler hash (since we have zlib on board anyway ... ) bool do_register_image = true; @@ -221,6 +227,7 @@ desc = same; } } +#endif return desc; } Index: descriptor/reader/image_reader.h =================================================================== --- descriptor/reader/image_reader.h (revision 10146) +++ descriptor/reader/image_reader.h (working copy) @@ -17,6 +17,13 @@ { OBJ_READER_DEF(image_reader_t, obj_image, "image"); +#ifdef MAKEOBJ +#undef COLOUR_DEPTH +#define COLOUR_DEPTH 16 + + void register_reader() {} +#endif + public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; Index: descriptor/writer/image_writer.cc =================================================================== --- descriptor/writer/image_writer.cc (revision 10146) +++ descriptor/writer/image_writer.cc (working copy) @@ -31,7 +31,41 @@ int ymax; }; +#include "../reader/image_reader.h" +#include +static image_reader_t ir; + +static int image_nr = 0; + + +void image_writer_t::dump_node(FILE* infp, const obj_node_info_t& node) +{ + image_t *desc = (image_t *)ir.read_node( infp, (obj_node_info_t& )node ); + + /* now we can dump the image as we like it ... */ + uint16 width = min( 64, desc->w+desc->x ); + uint16 height = min( 64, desc->h+desc->y ); + + raw_image_t rawimg(width, height, raw_image_t::FMT_RGB888); + uint8* target = rawimg.access_pixel(0, 0); + + for( uint32 i=0; idecode_img( 0, 0, (uint32 *)rawimg.access_pixel(0, 0), rawimg.get_width(), height ); + + // PNG + char fname[256]; + sprintf( fname, "image%i.png", image_nr++ ); + rawimg.write_png(fname); +} + + + std::string image_writer_t::last_img_file; raw_image_t image_writer_t::input_img; Index: descriptor/writer/image_writer.h =================================================================== --- descriptor/writer/image_writer.h (revision 10146) +++ descriptor/writer/image_writer.h (working copy) @@ -37,6 +37,8 @@ static void set_img_size(int _img_size) { img_size = _img_size; } obj_type get_type() const OVERRIDE { return obj_image; } + virtual void dump_node(FILE* infp, const obj_node_info_t& node); + const char* get_type_name() const OVERRIDE { return "image"; } void write_obj(FILE* fp, obj_node_t& parent, std::string imagekey, uint32 index); Index: makeobj/Makefile =================================================================== --- makeobj/Makefile (revision 10146) +++ makeobj/Makefile (working copy) @@ -118,6 +118,7 @@ SOLO_SOURCES += ../descriptor/writer/way_obj_writer.cc SOLO_SOURCES += ../descriptor/writer/xref_writer.cc SHARED_SOURCES += ../descriptor/image.cc +SHARED_SOURCES += ../descriptor/reader/image_reader.cc SHARED_SOURCES += ../dataobj/freelist.cc SHARED_SOURCES += ../io/raw_image.cc SHARED_SOURCES += ../simio.h Index: makeobj/Makeobj.vcxproj =================================================================== --- makeobj/Makeobj.vcxproj (revision 10146) +++ makeobj/Makeobj.vcxproj (working copy) @@ -88,6 +88,7 @@ + @@ -133,6 +134,7 @@ + simutrans-124.3/src/patches/experimental-hierachical-patchfinder.diff000066400000000000000000000264651474050137200260540ustar00rootroot00000000000000Index: gui/karte.cc =================================================================== --- gui/karte.cc (revision 1232) +++ gui/karte.cc (working copy) @@ -233,6 +233,7 @@ #endif color = calc_hoehe_farbe((welt->lookup_hgt(gr->gib_pos().gib_2d())/Z_TILE_STEP)+height, welt->gib_grundwasser()/Z_TILE_STEP); //color = COL_BLUE; // water with boat? + color = route_t::add_to_minimap(welt,gr); } else { color = dt->get_fabrik()->gib_kennfarbe(); Index: dataobj/route.cc =================================================================== --- dataobj/route.cc (revision 1232) +++ dataobj/route.cc (working copy) @@ -19,8 +19,187 @@ #include "umgebung.h" +// sorted heap, since we only need insert and pop +#include "../tpl/array2d_tpl.h" // fastest +#include "../tpl/array_tpl.h" // fastest +#include "../tpl/minivec_tpl.h" // fastest + +class region_node { +public: + koord center; + minivec_tpl conn; + uint8 marked; +}; + +static array_tpl connections; +static array2d_tpl *water_regions = NULL; +static int REGION_SIZE = 16; +static uint8 current_mark = 1; +#define REGION_MASK (~(REGION_SIZE-1)) + + +static void fill_region(karte_t *welt, int x, int y, uint16 region_nr ) +{ + const uint16 replace_nr = water_regions->at(x,y); + const int xmin = (x & REGION_MASK); + const int xmax = min( welt->gib_groesse_x(), xmin+REGION_SIZE ); + // fill one line + int xl, xr; + xl = xr = x; + while(xl>=x && water_regions->at(xl,y)==replace_nr ) xl--; + if(xlat(xr,y)==replace_nr ) xr++; + if(xr==xmax) xr--; + // first fill with color + for( x=xl; x<=xr; x++ ) { + water_regions->at(x,y) = region_nr; + } + // and then recursion + const int ymin = (y & REGION_MASK); + const int ymax = min( welt->gib_groesse_y(), ymin+REGION_SIZE ); + y--; + if(y>=ymin) { + for( x=xl; xat(x,y)==replace_nr) { + fill_region( welt, x, y, region_nr ); + } + } + } + y += 2; + if(yat(x,y)==replace_nr) { + fill_region( welt, x, y, region_nr ); + } + } + } +} + + +static void init_regions(karte_t *welt) +{ + if(water_regions) { + delete water_regions; + water_regions = NULL; + } + const int xw = welt->gib_groesse_x(); + const int yw = welt->gib_groesse_y(); + // what region size? + REGION_SIZE = 1; + while( max(xw,yw)/REGION_SIZE>=256 ) { + REGION_SIZE <<= 1; + } + if(REGION_SIZE<4) { + REGION_SIZE = 0; + return; + } + water_regions = new array2d_tpl( xw, yw ); + // init land with zero, water with 1 + memset( (void *)(water_regions->to_array()), 0, sizeof(uint16)*xw*yw ); + for( int y=0; ylookup_kartenboden(koord(x,y))->gib_weg_ribi(water_wt)) { + water_regions->at(x,y) = 1; + } + } + } + /* now finde the regions + * we go from top to bottom and from left to right + */ + int region = 2; + for( int y=0; yat(xoff,yoff)==1) { + fill_region( welt, xoff, yoff, region++ ); + } + } + } + } + } + // finally: init new nodelist + connections.resize(region); + for( int i=0; iat(x,yh)>1 && water_regions->at(x,yh+1)>1) { + connections[water_regions->at(x,yh)].conn.append_unique(water_regions->at(x,yh+1)); + connections[water_regions->at(x,yh)].center = center; + } + } + } + const int ymax = min(yw,yh); + if(xb+1at(xb,y)>1 && water_regions->at(xb+1,y)>1) { + connections[water_regions->at(xb,y)].conn.append_unique(water_regions->at(xb+1,y)); + connections[water_regions->at(xb,y)].center = center; + } + } + } + int y = yh & REGION_MASK; + if(y>0) { + for( int x=xb-(REGION_SIZE-1); xat(x,y)>1 && water_regions->at(x,y-1)>1) { + connections[water_regions->at(x,y)].conn.append_unique(water_regions->at(x,y-1)); + connections[water_regions->at(x,y)].center = center; + } + } + } + int x = xb & REGION_MASK; + if(x>0) { + for( int y=yh-(REGION_SIZE-1); yat(x,y)>1 && water_regions->at(x-1,y)>1) { + connections[water_regions->at(x,y)].conn.append_unique(water_regions->at(x-1,y)); + connections[water_regions->at(x,y)].center = center; + } + } + } + } + } + // now, in principle, we can free the region tile array ... + + // debug + for( int i=2; i%i",i-2,connections[i].conn[j]-2); + } + } +} + +// debug +uint8 route_t::add_to_minimap(karte_t *welt, const grund_t *gr) +{ + if(water_regions==NULL) init_regions(welt); + if(REGION_SIZE==0) { + return 3; + } + if(water_regions->get_width()!=welt->gib_groesse_x() || water_regions->get_height()!=welt->gib_groesse_y()) init_regions(welt); + uint16 node = water_regions->at( gr->gib_pos().x, gr->gib_pos().y ); + return connections[node].marked==current_mark ? 15 : ((node*241)%242)+16; +} + + + + // if defined, print some profiling informations into the file -//#define DEBUG_ROUTES +#define DEBUG_ROUTES // this is WAY slower than the sorted_heap! (also not always finding best routes, but was the original algorithms) //#include "../tpl/prioqueue_tpl.h" // ~100-250% slower @@ -36,6 +215,10 @@ // sorted heap, since we only need insert and pop #include "../tpl/binary_heap_tpl.h" // fastest +#ifdef DEBUG_ROUTES +#include "../gui/karte.h" +#include "../simsys.h" +#endif void @@ -324,9 +507,145 @@ -bool route_t::intern_calc_route(karte_t *welt, const koord3d ziel, const koord3d start, fahrer_t *fahr, const uint32 max_speed, const uint32 max_cost) +#define NODE_TO_KOORD(i) koord((i)%welt->gib_groesse_x(),(i)/welt->gib_groesse_x()) +#define GRUND_TO_NODE(i) ((i)->gib_pos().x+(i)->gib_pos().y*welt->gib_groesse_x()) +#define NODE_DISTANCE(i,j) (abs_distance(connections[i].center,connections[j].center)+((i)!=(j))) + +// ships may use a hierachical pathfinder +bool route_t::intern_calc_route_water(karte_t *welt, const koord3d ziel, const koord3d start, fahrer_t *fahr, const uint32 max_speed, const uint32 max_cost) { + // first, find a route in the node list + uint16 start_node = water_regions->at(start.x,start.y); + uint16 end_node = water_regions->at(ziel.x,ziel.y); + + uint16 node=0; + bool ziel_erreicht = false; + + // memory in static list ... + if(nodes==NULL) { + MAX_STEP = umgebung_t::max_route_steps; // may need very much memory => configurable + nodes = new ANode[MAX_STEP + 4 + 2]; + } + /* now find the shortest route beteen them with A* */ + + // there are several variant for maintaining the open list + // however, only binary heap and HOT queue with binary heap are worth considering +#if defined(tpl_HOT_queue_tpl_h) + static HOT_queue_tpl queue; +#elif defined(tpl_binary_heap_tpl_h) + static binary_heap_tpl queue; +#elif defined(tpl_sorted_heap_tpl_h) + static sorted_heap_tpl queue; +#else + static prioqueue_tpl queue; +#endif + GET_NODE(); + + // use different mark + current_mark ++; + + // clear the queue (should be empty anyhow) + route.clear(); + queue.clear(); + + uint32 step = 0; + ANode* tmp = &nodes[step]; + step ++; + + tmp->parent = NULL; + tmp->gr = welt->lookup_kartenboden(NODE_TO_KOORD(start_node)); + tmp->f = NODE_DISTANCE(start_node,end_node); + tmp->g = 0; + tmp->dir = 0; + tmp->count = 0; + + queue.insert(tmp); + + uint32 beat=1; + do { + // Hajo: this is too expensive to be called each step + if((beat++ & 255) == 0) { + INT_CHECK("route 161"); + } + + ANode *test_tmp = queue.pop(); + uint16 test_node = GRUND_TO_NODE(test_tmp->gr); + + if(connections[test_node].marked==current_mark) { + // we were already here on a faster route, thus ignore this branch + // (trading speed against memory consumption) + continue; + } + + // we took the target pos out of the closed list + if(end_node==node) { + ziel_erreicht = true; + break; + } + + tmp = test_tmp; + node = test_node; + connections[node].marked = current_mark; + + for(int n=0; ng + 1; + + // no check for curves ... + + const uint32 new_f = new_g + NODE_DISTANCE(to_node,end_node); + + // add new + ANode* k = &nodes[step]; + step ++; + + k->parent = tmp; + k->gr = welt->lookup_kartenboden(NODE_TO_KOORD(to_node)); + k->g = new_g; + k->f = new_f; + k->count = tmp->count+1; + + queue.insert( k ); + } + } + + } while (!queue.empty() && !ziel_erreicht && stepgg,max_cost); + //reliefkarte_t::gib_karte()->calc_map(); +#endif + vector_tplnodes(tmp->count+16); + + // target reached? + if(!ziel_erreicht || step >= MAX_STEP || tmp->parent==NULL) { + dbg->warning("route_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,MAX_STEP); + return false; + } + else { + // reached => construct route + current_mark ++; + while(tmp != NULL) { + uint16 n = GRUND_TO_NODE(tmp->gr); + nodes.append( n ); + connections[n].marked = current_mark; + tmp = tmp->parent; + } + } + + RELEASE_NODE(); + + return false; +} + + + +bool route_t::intern_calc_route(karte_t *welt, const koord3d ziel, const koord3d start, fahrer_t *fahr, const uint32 max_speed, const uint32 max_cost) +{ bool ok = false; // check for existing koordinates Index: dataobj/route.h =================================================================== --- dataobj/route.h (revision 1232) +++ dataobj/route.h (working copy) @@ -28,6 +28,12 @@ { private: /** + * an experimental hierachical pathfinder + * @author Hj. Malthaner + */ + bool intern_calc_route_water(karte_t *w, koord3d start, koord3d ziel, fahrer_t *fahr, const uint32 max_kmh, const uint32 max_cost); + + /** * Die eigentliche Routensuche * @author Hj. Malthaner */ @@ -36,6 +42,8 @@ vector_tpl route; // Die Koordinaten fuer die Fahrtroute public: + static uint8 add_to_minimap(karte_t *welt, const grund_t *gr); + // this class save the nodes during route search class ANode { public: simutrans-124.3/src/patches/sun.diff000077500000000000000000000035011474050137200174320ustar00rootroot00000000000000Index: simworld.cc =================================================================== --- simworld.cc (revision 2029) +++ simworld.cc (working copy) @@ -2032,6 +2032,8 @@ if(letzter_monat>11) { letzter_monat = 0; } + view->update_darkness( 52, letzter_monat ); + DBG_MESSAGE("karte_t::neuer_monat()","Month %d has started", letzter_monat); DBG_MESSAGE("karte_t::neuer_monat()","sync_step %u objects", sync_list.count() ); Index: simview.cc =================================================================== --- simview.cc (revision 2031) +++ simview.cc (working copy) @@ -5,6 +5,7 @@ */ #include +#include #include "simworld.h" #include "simview.h" @@ -22,13 +23,17 @@ #include "dataobj/umgebung.h" #include "dings/zeiger.h" +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + karte_ansicht_t::karte_ansicht_t(karte_t *welt) { this->welt = welt; } -static const sint8 hours2night[] = +static sint8 hours2night[48] = { 4,4,4,4,4,4,4,4, 4,4,4,4,3,2,1,0, @@ -40,6 +45,20 @@ +void karte_ansicht_t::update_darkness(double latitude, int month) +{ + // first we need the approxiamate day + const double day = 10.0 + (30.4*month) +182.5; + const double delta = (-23.45*M_PI/180.0) * cos(2.0*M_PI/365.0*day); + for( int i=0; i<48; i++ ) { + const double tau = i*M_PI/24.0; + double arcsin_h = cos(delta)*cos(tau)*cos(latitude*M_PI/180.0) + sin(delta)*sin(latitude*M_PI/180.0); + hours2night[ i ] = (int)((1.0+arcsin_h)*3.0); + } +} + + + void karte_ansicht_t::display(bool force_dirty) { Index: simview.h =================================================================== --- simview.h (revision 2029) +++ simview.h (working copy) @@ -21,6 +21,7 @@ public: karte_ansicht_t(karte_t *welt); + void update_darkness(double latitude, int month); void display(bool dirty); }; simutrans-124.3/src/script_ai_text.dat000066400000000000000000000014661474050137200200640ustar00rootroot00000000000000obj=script_ai_text name=%s build road line from %s (%s) to %s (%s) - obj=script_ai_text name=%s build ship line from %s (%s) to %s (%s) - obj=script_ai_text name=%s build rail line from %s (%s) to %s (%s) - obj=script_ai_text name=%s optimize way line from %s (%s) to %s (%s) - obj=script_ai_text name=%s extends the route from %s (%s) to %s (%s) - obj=script_ai_text name=%s build additional convoy to line: %s - obj=script_ai_text name=%s removes convoys from line: %s - obj=script_ai_text name=vehicles of the line %s were retired - obj=script_ai_text name=%s electrified the line %s - obj=script_ai_text name=%s removes line: %s - obj=script_ai_text name=%s expand the station %s (%s) and station %s (%s) - obj=script_ai_text name=%s - last month: operating profit %d net wealth %d -simutrans-124.3/src/simutrans/000077500000000000000000000000001474050137200163675ustar00rootroot00000000000000simutrans-124.3/src/simutrans/Simutrans-full.svg000066400000000000000000000223251474050137200220410ustar00rootroot00000000000000 image/svg+xml simutrans-124.3/src/simutrans/builder/000077500000000000000000000000001474050137200200155ustar00rootroot00000000000000simutrans-124.3/src/simutrans/builder/brueckenbauer.cc000066400000000000000000001165641474050137200231560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../tool/simtool.h" #include "brueckenbauer.h" #include "wegbauer.h" #include "../world/simworld.h" #include "../simhalt.h" #include "../obj/depot.h" #include "../player/simplay.h" #include "../simtypes.h" #include "../simachievements.h" #include "../ground/boden.h" #include "../ground/brueckenboden.h" #include "../gui/tool_selector.h" #include "../gui/minimap.h" #include "../descriptor/bridge_desc.h" #include "../dataobj/marker.h" #include "../dataobj/scenario.h" #include "../obj/bruecke.h" #include "../obj/leitung2.h" #include "../obj/pillar.h" #include "../obj/signal.h" #include "../dataobj/crossing_logic.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" karte_ptr_t bridge_builder_t::welt; /// All bridges hashed by name static stringhashtable_tpl desc_table; void bridge_builder_t::register_desc(bridge_desc_t *desc) { // avoid duplicates with same name if( const bridge_desc_t *old_desc = desc_table.remove(desc->get_name()) ) { tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); delete old_desc; } // add the tool tool_build_bridge_t *tool = new tool_build_bridge_t(); tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param(desc->get_name()); tool_t::general_tool.append( tool ); desc->set_builder( tool ); desc_table.put(desc->get_name(), desc); } const bridge_desc_t *bridge_builder_t::get_desc(const char *name) { return (name ? desc_table.get(name) : NULL); } const bridge_desc_t *bridge_builder_t::find_bridge(const waytype_t wtyp, const sint32 min_speed, const uint16 time) { const bridge_desc_t *find_desc=NULL; for(auto const& i : desc_table) { bridge_desc_t const* const desc = i.value; if( desc->get_waytype()==wtyp && desc->is_available(time) ) { if( find_desc==NULL || (find_desc->get_topspeed()get_topspeed()get_topspeed()) || (desc->get_topspeed()>=min_speed && desc->get_maintenance()get_maintenance()) ) { find_desc = desc; } } } return find_desc; } /** * Compares the maximum speed of two bridges. * @param a the first bridge. * @param b the second bridge. * @return true, if the speed of the second bridge is greater. */ static bool compare_bridges(const bridge_desc_t* a, const bridge_desc_t* b) { return a->get_topspeed() < b->get_topspeed(); } void bridge_builder_t::fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, sint16 /*sound_ok*/) { // check if scenario forbids this if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_BRIDGE | GENERAL_TOOL, wtyp)) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_BRIDGE | GENERAL_TOOL, wtyp, 0); const uint16 time = welt->get_timeline_year_month(); vector_tpl matching(desc_table.get_count()); // list of matching types (sorted by speed) for(auto const& i : desc_table) { bridge_desc_t const* const b = i.value; if ( b->get_waytype()==wtyp && b->is_available(time) ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_BRIDGE | GENERAL_TOOL, wtyp,b->get_name())) { matching.insert_ordered(b, compare_bridges); } } } // now sorted ... for(bridge_desc_t const *i : matching) { i->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_BRIDGE | GENERAL_TOOL, wtyp, i->get_name()); tool_selector->add_tool_selector(i->get_builder()); } } const vector_tpl& bridge_builder_t::get_available_bridges(const waytype_t wtyp) { static vector_tpl dummy; dummy.clear(); const uint16 time = welt->get_timeline_year_month(); for(auto const& i : desc_table) { bridge_desc_t const* const b = i.value; if (b->get_waytype()==wtyp && b->is_available(time) && b->get_builder()) { dummy.append(b); } } return dummy; } inline bool ribi_check( ribi_t::ribi ribi, ribi_t::ribi check_ribi ) { // either check for single (if nothing given) otherwise ensure exact match return check_ribi ? ribi == check_ribi : ribi_t::is_single( ribi ); } /** * if check_ribi==0, then any single tile is ok * @returns either (1) error_message (must abort bridge here) (2) "" if it could end here or (3) NULL if it must end here */ const char *check_tile( const grund_t *gr, const player_t *player, waytype_t wt, ribi_t::ribi check_ribi ) { static karte_ptr_t welt; // not overbuilt transformers if( gr->find()!=NULL || gr->find()!=NULL ) { return "A bridge must start on a way!"; } if( !slope_t::is_way(gr->get_weg_hang()) ) { // it's not a straight slope return "Bruecke muss an\neinfachem\nHang beginnen!\n"; } if( gr->is_halt() || gr->get_depot() ) { // something in the way return "Tile not empty."; } if( wt != powerline_wt && gr->get_leitung() ) { return "Tile not empty."; } // we can build a ramp when there is one (or with tram two) way in our direction and no stations/depot etc. if( weg_t *w = gr->get_weg_nr(0) ) { if( w->get_removal_error(player) != NULL ) { // not our way return "Das Feld gehoert\neinem anderen Spieler\n"; } // now check for direction ribi_t::ribi ribi = w->get_ribi_unmasked(); if( weg_t *w2 = gr->get_weg_nr(1) ) { if( w2->get_removal_error(player) != NULL ) { // not our way return "Das Feld gehoert\neinem anderen Spieler\n"; } if( !gr->ist_uebergang() ) { // If road and tram, we have to check both ribis. ribi = gr->get_weg_nr(0)->get_ribi_unmasked() | gr->get_weg_nr(1)->get_ribi_unmasked(); } else { // else only the straight ones ribi = gr->get_weg_ribi_unmasked(wt); } // same waytype, same direction, no stop or depot or any other stuff */ if( gr->get_weg(wt) && ribi_check(ribi, check_ribi) ) { // ok too return NULL; } return "A bridge must start on a way!"; } if( w->get_waytype() != wt ) { // now check for perpendicular and crossing if( (ribi_t::doubles(ribi) ^ ribi_t::doubles(check_ribi) ) == ribi_t::all && crossing_logic_t::get_crossing(wt, w->get_waytype(), 0, 0, welt->get_timeline_year_month() ) ) { return NULL; } return "A bridge must start on a way!"; } // same waytype, check direction if( w->get_waytype() == wt && ribi_check(ribi, check_ribi ) ) { // ok too return NULL; } // one or two non-matching ways where I cannot built a crossing return "A bridge must start on a way!"; } else if( wt == powerline_wt ) { if( leitung_t *lt = gr->get_leitung() ) { if( lt->get_removal_error(player) == NULL && ribi_check( lt->get_ribi(), check_ribi ) ) { // matching powerline return NULL; } return "A bridge must start on a way!"; } } // something here which we cannot remove => fail too if( obj_t *obj=gr->obj_bei(0) ) { if( const char *err_msg = obj->get_removal_error(player) ) { return err_msg; } } return ""; // could end here but need not end here } bool bridge_builder_t::is_blocked(koord3d pos, ribi_t::ribi check_ribi, const char *&error_msg) { /* can't build directly above or below a way if height clearance == 2 */ // take slopes on grounds below into accout const sint8 clearance = welt->get_settings().get_way_height_clearance()-1; for(int dz = -clearance -2; dz <= clearance; dz++) { grund_t *gr2 = NULL; if (dz != 0 && (gr2 = welt->lookup(pos + koord3d(0,0,dz)))) { const slope_t::type slope = gr2->get_weg_hang(); if (dz < -clearance) { if (dz + slope_t::max_diff(slope) + gr2->get_weg_yoff() / TILE_HEIGHT_STEP < -clearance ) { // too far below continue; } } if (dz + slope_t::max_diff(slope) == 0 && gr2->ist_karten_boden() && ribi_type(gr2->get_grund_hang())==check_ribi) { // potentially connect to this slope continue; } weg_t *w = gr2->get_weg_nr(0); if (w && w->get_max_speed() > 0) { error_msg = "Bridge blocked by way below or above."; return true; } } } // first check for elevated ground exactly in our height if( grund_t *gr2 = welt->lookup( pos ) ) { if( gr2->get_typ() != grund_t::boden && gr2->get_typ() != grund_t::tunnelboden ) { // not through bridges // monorail tiles will be checked in is_monorail_junction error_msg = "Tile not empty."; return true; } } return false; } // return true if bridge can be connected to monorail tile bool bridge_builder_t::is_monorail_junction(koord3d pos, player_t *player, const bridge_desc_t *desc, const char *&error_msg) { // first check for elevated ground exactly in our height if( grund_t *gr2 = welt->lookup( pos ) ) { if( gr2->get_typ() == grund_t::monorailboden ) { // now check if our way if( weg_t *w = gr2->get_weg_nr(0) ) { if( !player_t::check_owner(w->get_owner(),player) ) { // not our way error_msg = "Das Feld gehoert\neinem anderen Spieler\n"; return false; } if( w->get_waytype() == desc->get_waytype() ) { // ok, all fine return true; } } error_msg = "Tile not empty."; } } return false; } #define height_okay(h) (((h) < min_bridge_height || (h) > max_height) ? false : height_okay_array[h-min_bridge_height]) // 2 to suppress warnings when h=start_height+x and min_bridge_height=start_height #define height_okay2(h) (((h) > max_height) ? false : height_okay_array[h-min_bridge_height]) koord3d bridge_builder_t::find_end_pos(player_t *player, koord3d pos, const koord zv, const bridge_desc_t *desc, const char *&error_msg, sint8 &bridge_height, bool ai_bridge, uint32 min_length, bool high_bridge ) { const grund_t *const gr2 = welt->lookup( pos ); if( !gr2 ) { error_msg = "A bridge must start on a way!"; return koord3d::invalid; } // get initial height of bridge from start tile // flat -> height is 1 if only shallow ramps, else height 2 // single height -> height is 1 // double height -> height is 2 // if start tile is tunnel mouth then min = max = pos.z = start_height const slope_t::type slope = gr2->get_weg_hang(); const sint8 start_height = gr2->get_hoehe() + slope_t::max_diff(slope); sint8 min_bridge_height = start_height; /* was + (slope==0) */ sint8 min_height = start_height - (1+desc->has_double_ramp()) + (slope==0); sint8 max_height = start_height + (slope || gr2->ist_tunnel() ? 0 : (1+desc->has_double_ramp())); // when a bridge starts on an elevated way, only downwards ramps are allowed if( !gr2->ist_karten_boden() ) { // cannot start on a sloped elevated way if( slope ) { error_msg = "A bridge must start on a way!"; return koord3d::invalid; } // must be at least an elevated way for starting, no bridge or tunnel if( gr2->get_typ() != grund_t::monorailboden ) { error_msg = "A bridge must start on a way!"; return koord3d::invalid; } max_height = start_height; min_height = max_height - (1+desc->has_double_ramp()); min_bridge_height = start_height; } bool height_okay_array[256]; for (int i = 0; i < max_height+1 - min_bridge_height; i++) { height_okay_array[i] = true; } if( slope_t::max_diff(slope)==2 && !desc->has_double_start() ) { error_msg = "Cannot build on a double slope!"; return koord3d::invalid; } scenario_t *scen = welt->get_scenario(); error_msg = NULL; uint16 length = 0; do { length ++; pos = pos + zv; // test scenario conditions if( (error_msg = scen->is_work_allowed_here(player, TOOL_BUILD_BRIDGE|GENERAL_TOOL, desc->get_finance_waytype(), desc->get_name(), pos)) != NULL ) { // fail silent? return koord3d::invalid; } // test max length if( desc->get_max_length() > 0 && length > desc->get_max_length() ) { error_msg = "Bridge is too long for this type!\n"; return koord3d::invalid; } if( !welt->is_within_limits(pos.get_2d()) ) { error_msg = "Bridge is too long for this type!\n"; return koord3d::invalid; } // now so some special checks for grounds grund_t *gr = welt->lookup_kartenboden( pos.get_2d() ); if( !gr ) { // end of map! break; } if( gr->get_hoehe() == max_height-1 && desc->get_waytype() != powerline_wt && gr->get_leitung() ) { error_msg = "Tile not empty."; return koord3d::invalid; } // check for height if( desc->get_max_height() && max_height-gr->get_hoehe() > desc->get_max_height() ) { error_msg = "bridge is too high for its type!"; return koord3d::invalid; } if( gr->hat_weg(air_wt) && gr->get_styp(air_wt)==type_runway ) { error_msg = "No bridges over runways!"; return koord3d::invalid; } bool abort = true; for(sint8 z = min_bridge_height; z <= max_height; z++) { if(height_okay(z)) { if(is_blocked(koord3d(pos.get_2d(), z), ribi_type(zv), error_msg)) { height_okay_array[z-min_bridge_height] = false; // connect to suitable monorail tiles if possible if(is_monorail_junction(koord3d(pos.get_2d(), z), player, desc, error_msg)) { gr = welt->lookup(koord3d(pos.get_2d(), z)); bridge_height = z - start_height; return gr->get_pos(); } } else { abort = false; } } } if(abort) { return koord3d::invalid; } const slope_t::type end_slope = gr->get_weg_hang(); const sint16 hang_height = gr->get_hoehe() + slope_t::max_diff(end_slope) + gr->get_weg_yoff()/TILE_HEIGHT_STEP; if(hang_height > max_height) { error_msg = "Cannot connect to the\ncenter of a double slope!"; return koord3d::invalid; } if(hang_height < min_height) { continue; } // now check for end of bridge conditions if(length >= min_length && slope_t::is_way(end_slope) && (gr->get_typ()==grund_t::boden || gr->get_typ()==grund_t::tunnelboden)) { bool finish = false; if(height_okay(hang_height) && end_slope == slope_t::flat && (hang_height == max_height || ai_bridge || min_length)) { /* now we have a flat tile below */ error_msg = check_tile( gr, player, desc->get_waytype(), ribi_type(zv) ); if( !error_msg || (!*error_msg) ) { // success for(sint8 z = hang_height + 3; z <= max_height; z++) { height_okay_array[z-min_bridge_height] = false; } for(sint8 z = min_bridge_height; z < hang_height; z++) { height_okay_array[z-min_bridge_height] = false; } finish = true; } } else if( height_okay(hang_height) && (hang_height == max_height || ai_bridge || min_length) ) { // here is a slope that ends at the bridge height if( slope_t::max_diff(end_slope)==2 && !desc->has_double_start() ) { // cannot end on a double slope if we do not have the matching ramp error_msg = "Cannot build on a double slope!"; } else { // first check slope if( ribi_type(end_slope) == ribi_type(zv) ) { // slope matches error_msg = check_tile( gr, player, desc->get_waytype(), ribi_type(zv) ); if( !error_msg || !*error_msg ) { // success bridge_height = hang_height - start_height; return gr->get_pos(); } } } } else if (end_slope == slope_t::flat) { if ((hang_height+1 >= start_height && height_okay(hang_height+1)) || (hang_height+2 >= start_height && height_okay(hang_height+2))) { /* now we have a flat tile below */ error_msg = check_tile( gr, player, desc->get_waytype(), ribi_type(zv) ); if( hang_height < max_height && ( gr->has_two_ways() || ( gr->get_weg_nr(0) && (gr->get_weg_nr(0)->get_waytype() != desc->get_waytype() || gr->get_weg_ribi_unmasked(desc->get_waytype())!=ribi_type(zv) ) ) ) ) { // no crossing or curve here (since it will a slope ramp) error_msg = "A bridge must start on a way!"; } if (gr->ist_tunnel()) { // non-flat bridges should not end in tunnels error_msg = "Tile not empty."; } if( !error_msg ) { for(sint8 z = hang_height + 3; z <= max_height; z++) { height_okay_array[z-min_bridge_height] = false; } finish = true; } else if( *error_msg == 0 ) { if( (ai_bridge || min_length) ) { for(sint8 z = hang_height + 3; z <= max_height; z++) { height_okay_array[z-min_bridge_height] = false; } // in the way, or find shortest and empty => ok finish = true; } } } } if( finish ) { if( high_bridge ) { if( height_okay2( start_height + 2 ) ) { bridge_height = 2; } else if( height_okay2( start_height + 1 ) ) { bridge_height = 1; } else if( height_okay2( start_height ) ) { bridge_height = 0; } else { assert(false); } } else { if( height_okay2( start_height ) ) { bridge_height = 0; } else if( height_okay2( start_height + 1 ) ) { bridge_height = 1; } else if( height_okay2( start_height + 2 ) ) { bridge_height = 2; } else { assert(false); } } // there is no point in building flat, one-tile bridges if (bridge_height == 0 && length == 1) { error_msg = ""; return koord3d::invalid; } return gr->get_pos(); } // slope, which ends too low => we can continue } const slope_t::type end_ground_slope = gr->get_grund_hang(); const sint16 hang_ground_height = gr->get_hoehe()+slope_t::max_diff(end_ground_slope); // sorry, this is in the way if( hang_ground_height >= max_height ) { break; } for(sint8 z = min_bridge_height; z <= hang_ground_height; z++) { if(height_okay(z)) { height_okay_array[z-min_bridge_height] = false; } } } while( !ai_bridge || length <= welt->get_settings().way_max_bridge_len ); // not too long in case of AI error_msg = "A bridge must start on a way!"; return koord3d::invalid; } bool bridge_builder_t::is_start_of_bridge( const grund_t *gr ) { if( gr->ist_bruecke() ) { if( gr->ist_karten_boden() ) { // ramp => true return true; } // now check for end of rampless bridges ribi_t::ribi ribi = gr->get_weg_ribi_unmasked( gr->get_leitung() ? powerline_wt : gr->get_weg_nr(0)->get_waytype() ); for( int i=0; i<4; i++ ) { if( ribi_t::nesw[i] & ribi ) { grund_t *to = welt->lookup( gr->get_pos()+koord(ribi_t::nesw[i]) ); if( to && !to->ist_bruecke() ) { return true; } } } } return false; } bool bridge_builder_t::can_place_ramp(player_t *player, const grund_t *gr, waytype_t wt, ribi_t::ribi r ) { // bridges can only start or end above ground if( gr->get_typ()!=grund_t::boden && gr->get_typ()!=grund_t::monorailboden && gr->get_typ()!=grund_t::tunnelboden ) { return false; } // wrong slope if(!slope_t::is_way(gr->get_grund_hang())) { return false; } // blocked from above koord3d pos = gr->get_pos(); if( welt->lookup( pos + koord3d(0, 0, 1)) || (welt->get_settings().get_way_height_clearance()==2 && welt->lookup( pos + koord3d(0, 0, 2) )) ) { return false; } // check for ribis and crossings bool test_ribi = r != ribi_t::none; if (wt==powerline_wt) { if (gr->hat_wege()) { return false; } if (test_ribi && gr->find() && (gr->find()->get_ribi() & ~r) != 0) { return false; } } else { if (gr->find()) { return false; } if(wt!=road_wt) { // only road bridges can have other ways on it (ie trams) if(gr->has_two_ways() || (gr->hat_wege() && gr->get_weg(wt) == NULL) ) { return false; } if (test_ribi && (gr->get_weg_ribi_unmasked(wt) & ~r) != 0) { return false; } } else { // If road and tram, we have to check both ribis. ribi_t::ribi ribi = ribi_t::none; for(int i=0;i<2;i++) { if (const weg_t *w = gr->get_weg_nr(i)) { if (w->get_waytype()!=road_wt && !w->get_desc()->is_tram()) { return false; } ribi |= w->get_ribi_unmasked(); } else break; } if (test_ribi && (ribi & ~r) != 0) { return false; } } } // ribi from slope if (test_ribi && gr->get_grund_hang() && (ribi_type(gr->get_grund_hang()) & ~r) != 0) { return false; } // check everything else const char *error_msg = check_tile( gr, player, wt, r ); return (error_msg == NULL || *error_msg == 0 ); } const char *bridge_builder_t::build( player_t *player, const koord3d pos, const bridge_desc_t *desc) { const grund_t *gr = welt->lookup(pos); if( !(gr && desc) ) { return ""; } DBG_MESSAGE("bridge_builder_t::build()", "called on %d,%d for bridge type '%s'", pos.x, pos.y, desc->get_name()); koord zv; ribi_t::ribi ribi = ribi_t::none; const weg_t *weg = gr->get_weg(desc->get_waytype()); leitung_t *lt = gr->find(); if( desc->get_waytype()==powerline_wt ) { if( gr->hat_wege() ) { return "Tile not empty."; } if(lt) { ribi = lt->get_ribi(); } } else { if( lt ) { return "Tile not empty."; } if( weg ) { ribi = weg->get_ribi_unmasked(); } } if( !can_place_ramp(player, gr,desc->get_waytype(),ribi) ) { DBG_MESSAGE( "bridge_builder_t::build()", "no way %x found", desc->get_waytype() ); return "A bridge must start on a way!"; } if( gr->kann_alle_obj_entfernen(player) ) { return "Tile not empty."; } if(gr->get_weg_hang() == slope_t::flat) { if(!ribi_t::is_single(ribi)) { ribi = 0; } } else { ribi_t::ribi hang_ribi = ribi_type(gr->get_weg_hang()); if(ribi & ~hang_ribi) { ribi = 0; } else { // take direction from slope of tile ribi = hang_ribi; } } if(!ribi) { return "A bridge must start on a way!"; } // test scenario conditions if (const char* err = welt->get_scenario()->is_work_allowed_here(player, TOOL_BUILD_BRIDGE | GENERAL_TOOL, desc->get_finance_waytype(), desc->get_name(), pos)) { return err; } zv = koord(ribi_t::backward(ribi)); // search for suitable bridge end tile const char *msg; sint8 bridge_height; koord3d end = find_end_pos(player, gr->get_pos(), zv, desc, msg, bridge_height ); // found something? if( koord3d::invalid == end ) { DBG_MESSAGE("bridge_builder_t::build()", "end not ok"); return msg; } // check ownership grund_t * gr_end = welt->lookup(end); if(gr_end->kann_alle_obj_entfernen(player)) { return "Tile not empty."; } // check way ownership if(gr_end->hat_wege()) { if(gr_end->get_weg_nr(0)->get_removal_error(player)!=NULL) { return "Tile not empty."; } if(gr_end->has_two_ways() && gr_end->get_weg_nr(1)->get_removal_error(player)!=NULL) { return "Tile not empty."; } } // associated way const way_desc_t* way_desc; if (weg) { way_desc = weg->get_desc(); } else if (lt) { way_desc = lt->get_desc(); } else { way_desc = way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat); } // Start and end have been checked, we can start to build eventually build_bridge(player, gr->get_pos(), end, zv, bridge_height, desc, way_desc ); return NULL; } void bridge_builder_t::build_bridge(player_t *player, const koord3d start, const koord3d end, koord zv, sint8 bridge_height, const bridge_desc_t *desc, const way_desc_t *way_desc) { ribi_t::ribi ribi = ribi_type(zv); DBG_MESSAGE("bridge_builder_t::build()", "build from %s", start.get_str() ); grund_t *start_gr = welt->lookup( start ); const slope_t::type slope = start_gr->get_weg_hang(); // get initial height of bridge from start tile uint8 add_height = 0; // end tile height depends on whether slope matches direction... slope_t::type end_slope = welt->lookup(end)->get_weg_hang(); sint8 end_slope_height = end.z; if( end_slope != slope_type(zv) && end_slope != slope_type(zv)*2 ) { end_slope_height += slope_t::max_diff(end_slope); } if( slope!=slope_t::flat || bridge_height != 0 ) { // needs a ramp to start on ground add_height = slope!=slope_t::flat ? slope_t::max_diff(slope) : bridge_height; build_ramp( player, start, ribi, slope!=slope_t::flat ? slope_t::flat : slope_type(zv)*add_height, desc ); if( desc->get_waytype() != powerline_wt ) { ribi = welt->lookup(start)->get_weg_ribi_unmasked(desc->get_waytype()); } } else { // start at cliff if( desc->get_waytype() == powerline_wt ) { leitung_t *lt = start_gr->get_leitung(); if(!lt) { lt = new leitung_t(start_gr->get_pos(), player); lt->set_desc( way_desc ); start_gr->obj_add( lt ); lt->finish_rd(); } } else if( !start_gr->weg_erweitern( desc->get_waytype(), ribi ) ) { // builds new way weg_t * const weg = weg_t::alloc( desc->get_waytype() ); weg->set_desc( way_desc ); player_t::book_construction_costs( player, -start_gr->neuen_weg_bauen( weg, ribi, player ) -weg->get_desc()->get_price(), end.get_2d(), weg->get_waytype()); } start_gr->calc_image(); } koord3d pos = start+koord3d( zv.x, zv.y, add_height ); // update limits if( welt->min_height > pos.z ) { welt->min_height = pos.z; } else if( welt->max_height < pos.z ) { welt->max_height = pos.z; } while( pos.get_2d() != end.get_2d() ) { brueckenboden_t *bruecke = new brueckenboden_t( pos, slope_t::flat, slope_t::flat ); welt->access(pos.get_2d())->boden_hinzufuegen(bruecke); if( desc->get_waytype() != powerline_wt ) { weg_t * const weg = weg_t::alloc(desc->get_waytype()); weg->set_desc(way_desc); bruecke->neuen_weg_bauen(weg, ribi_t::doubles(ribi), player); } else { leitung_t *lt = new leitung_t(bruecke->get_pos(), player); bruecke->obj_add( lt ); lt->finish_rd(); } grund_t *gr = welt->lookup_kartenboden(pos.get_2d()); sint16 height = pos.z - gr->get_pos().z; bruecke_t *br = new bruecke_t(bruecke->get_pos(), player, desc, desc->get_straight(ribi,height-slope_t::max_diff(gr->get_grund_hang()))); bruecke->obj_add(br); bruecke->calc_image(); br->finish_rd(); //DBG_MESSAGE("bool bridge_builder_t::build_bridge()","at (%i,%i)",pos.x,pos.y); if(desc->get_pillar()>0) { // make a new pillar here if(desc->get_pillar()==1 || (pos.x*zv.x+pos.y*zv.y)%desc->get_pillar()==0) { //DBG_MESSAGE("bool bridge_builder_t::build_bridge()","h1=%i, h2=%i",pos.z,gr->get_pos().z); while(height-->0) { if( TILE_HEIGHT_STEP*height <= 127) { // eventual more than one part needed, if it is too high ... gr->obj_add( new pillar_t(gr->get_pos(),player,desc,desc->get_pillar(ribi), TILE_HEIGHT_STEP*height) ); } } } } pos = pos + zv; } // must determine end tile: on a slope => likely need auffahrt bool need_auffahrt = pos.z != end_slope_height; if( need_auffahrt ) { if( weg_t const* const w = welt->lookup(end)->get_weg( way_desc->get_wtyp() ) ) { need_auffahrt &= w->get_desc()->get_styp() != type_elevated; } } grund_t *gr = welt->lookup(end); if( need_auffahrt ) { // not ending at a bridge build_ramp(player, end, ribi_type(-zv), gr->get_weg_hang()?0:slope_type(-zv)*(pos.z-end.z), desc); } else { // ending on a slope/elevated way if(desc->get_waytype() != powerline_wt) { // just connect to existing way ribi = ribi_t::backward( ribi_type(zv) ); if( !gr->weg_erweitern( desc->get_waytype(), ribi ) ) { // builds new way weg_t * const weg = weg_t::alloc( desc->get_waytype() ); weg->set_desc( way_desc ); player_t::book_construction_costs( player, -gr->neuen_weg_bauen( weg, ribi, player ) -weg->get_desc()->get_price(), end.get_2d(), weg->get_waytype()); } gr->calc_image(); } else { leitung_t *lt = gr->get_leitung(); if( lt==NULL ) { lt = new leitung_t(end, player ); player_t::book_construction_costs(player, -way_desc->get_price(), gr->get_pos().get_2d(), powerline_wt); gr->obj_add(lt); lt->set_desc(way_desc); lt->finish_rd(); } lt->calc_neighbourhood(); } } // if start or end are single way, and next tile is not, try to connect if( desc->get_waytype() != powerline_wt && player ) { koord3d endtiles[] = {start, end}; for(uint i=0; ilookup(pos) ) { ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(desc->get_waytype()); grund_t *to = NULL; if( ribi_t::is_single(ribi) && gr->get_neighbour(to, invalid_wt, ribi_t::backward(ribi))) { // connect to open sea, calc_image will recompute ribi at to. if (desc->get_waytype() == water_wt && to->is_water()) { gr->weg_erweitern(water_wt, ribi_t::backward(ribi)); to->calc_image(); continue; } // only single tile under bridge => try to connect to next tile way_builder_t bauigel(player); bauigel.set_keep_existing_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(20); bauigel.init_builder( (way_builder_t::bautyp_t)desc->get_waytype(), way_desc, NULL, NULL ); bauigel.calc_route( pos, to->get_pos() ); if( bauigel.get_count() == 2 ) { bauigel.build(); } } } } } } void bridge_builder_t::build_ramp(player_t* player, koord3d end, ribi_t::ribi ribi_neu, slope_t::type weg_hang, const bridge_desc_t* desc) { assert(weg_hang <= slope_t::max_number); grund_t *alter_boden = welt->lookup(end); brueckenboden_t *bruecke; slope_t::type grund_hang = alter_boden->get_grund_hang(); bridge_desc_t::img_t img; bruecke = new brueckenboden_t(end, grund_hang, weg_hang); // add the ramp img = desc->get_end( bruecke->get_grund_hang(), grund_hang, weg_hang ); weg_t *weg = NULL; if(desc->get_waytype() != powerline_wt) { weg = alter_boden->get_weg( desc->get_waytype() ); } // take care of everything on that tile ... bruecke->take_obj_from( alter_boden ); welt->access(end.get_2d())->kartenboden_setzen( bruecke ); if(desc->get_waytype() != powerline_wt) { if( !bruecke->weg_erweitern( desc->get_waytype(), ribi_neu) ) { // needs still one weg = weg_t::alloc( desc->get_waytype() ); player_t::book_construction_costs(player, -bruecke->neuen_weg_bauen( weg, ribi_neu, player ), end.get_2d(), desc->get_waytype()); } weg->set_max_speed( desc->get_topspeed() ); } else { leitung_t *lt = bruecke->get_leitung(); if(!lt) { lt = new leitung_t(bruecke->get_pos(), player); bruecke->obj_add( lt ); } else { // remove maintenance - it will be added in leitung_t::finish_rd player_t::add_maintenance( player, -lt->get_desc()->get_maintenance(), powerline_wt); } // connect to neighbor tiles and networks, add maintenance lt->finish_rd(); } bruecke_t *br = new bruecke_t(end, player, desc, img); bruecke->obj_add( br ); br->finish_rd(); bruecke->calc_image(); } const char *bridge_builder_t::remove(player_t *player, koord3d pos_start, waytype_t wegtyp) { marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y); slist_tpl end_list; slist_tpl part_list; slist_tpl tmp_list; const char *msg; tmp_list.insert(pos_start); marker.mark(welt->lookup(pos_start)); waytype_t delete_wegtyp = wegtyp==powerline_wt ? invalid_wt : wegtyp; koord3d pos; do { pos = tmp_list.remove_first(); // weg_position_t changed to grund_t::get_neighbour() grund_t *from = welt->lookup(pos); grund_t *to; koord zv = koord::invalid; if( pos != pos_start && from->ist_karten_boden() ) { // gr is start/end - test only one direction if( from->get_grund_hang() != slope_t::flat ) { zv = -koord(from->get_grund_hang()); } else if( from->get_weg_hang() != slope_t::flat ) { zv = koord(from->get_weg_hang()); } end_list.insert(pos); } else if( pos == pos_start ) { if( from->ist_karten_boden() ) { // gr is start/end - test only one direction if( from->get_grund_hang() != slope_t::flat ) { zv = -koord(from->get_grund_hang()); } else if( from->get_weg_hang() != slope_t::flat ) { zv = koord(from->get_weg_hang()); } end_list.insert(pos); } else { ribi_t::ribi r = wegtyp==powerline_wt ? from->get_leitung()->get_ribi() : from->get_weg_nr(0)->get_ribi_unmasked(); ribi_t::ribi dir1 = r & ribi_t::northeast; ribi_t::ribi dir2 = r & ribi_t::southwest; grund_t *to; // test if we are at the end of a bridge: // 1. test direction must be single or zero bool is_end1 = (dir1 == ribi_t::none); // 2. if single direction: test for neighbor in that direction // there must be no neighbor or no bridge if (ribi_t::is_single(dir1)) { is_end1 = !from->get_neighbour(to, delete_wegtyp, dir1) || !to->ist_bruecke(); } // now do the same for the reverse direction bool is_end2 = (dir2 == ribi_t::none); if (ribi_t::is_single(dir2)) { is_end2 = !from->get_neighbour(to, delete_wegtyp, dir2) || !to->ist_bruecke(); } if(!is_end1 && !is_end2) { return "Cannot delete a bridge from its centre"; } // if one is an end then go towards the other direction zv = koord(is_end1 ? dir2 : dir1); part_list.insert(pos); } } else if(from->ist_bruecke()) { part_list.insert(pos); } // can we delete everything there? msg = from->kann_alle_obj_entfernen(player); if(msg != NULL || (from->get_halt().is_bound() && from->get_halt()->get_owner()!=player)) { simachievements_t::set_achievement(ACH_TOOL_REMOVE_BUSY_BRIDGE); return "Die Bruecke ist nicht frei!\n"; } // search neighbors for(int r = 0; r < 4; r++) { if( (zv == koord::invalid || zv == koord::nesw[r]) && from->get_neighbour(to, delete_wegtyp, ribi_t::nesw[r]) && !marker.is_marked(to) && to->ist_bruecke() ) { if( wegtyp != powerline_wt || (to->find() && to->find()->get_desc()->get_waytype() == powerline_wt) ) { tmp_list.insert(to->get_pos()); marker.mark(to); } } } } while (!tmp_list.empty()); // now delete the bridge bool first = true; while (!part_list.empty()) { pos = part_list.remove_first(); grund_t *gr = welt->lookup(pos); // the following code will check if this is the first of last tile, end then tries to remove the superflous ribis from it if( first || end_list.empty() ) { // starts on slope or elevated way, or it consist only of the ramp ribi_t::ribi bridge_ribi = gr->get_weg_ribi_unmasked( wegtyp ); for( uint i = 0; i < 4; i++ ) { if( bridge_ribi & ribi_t::nesw[i] ) { grund_t *prev; // if we have a ramp, then only check the higher end! if( gr->get_neighbour( prev, wegtyp, ribi_t::nesw[i]) && !prev->ist_bruecke() && !end_list.is_contained(prev->get_pos()) ) { if( weg_t *w = prev->get_weg( wegtyp ) ) { // now remove ribi (or full way) w->set_ribi( (~ribi_t::backward( ribi_t::nesw[i] )) & w->get_ribi_unmasked() ); if( w->get_ribi_unmasked() == 0 ) { // nowthing left => then remove completel prev->remove_everything_from_way( player, wegtyp, bridge_ribi ); // removes stop and signals correctly prev->weg_entfernen( wegtyp, true ); if( prev->get_typ() == grund_t::monorailboden ) { welt->access( prev->get_pos().get_2d() )->boden_entfernen( prev ); delete prev; } } else { w->calc_image(); } } } } } } first = false; // first: remove bridge bruecke_t *br = gr->find(); br->cleanup(player); delete br; gr->remove_everything_from_way(player,wegtyp,ribi_t::none); // removes stop and signals correctly // remove also the second way on the bridge if(gr->get_weg_nr(0)!=0) { gr->remove_everything_from_way(player,gr->get_weg_nr(0)->get_waytype(),ribi_t::none); } // we may have a second way/powerline here ... gr->obj_loesche_alle(player); gr->mark_image_dirty(); welt->access(pos.get_2d())->boden_entfernen(gr); delete gr; // finally delete all pillars (if there) gr = welt->lookup_kartenboden(pos.get_2d()); while (obj_t* const p = gr->find()) { p->cleanup(p->get_owner()); delete p; } // refresh map minimap_t::get_instance()->calc_map_pixel(pos.get_2d()); } // finally delete the bridge ends (all are kartenboden) while( !end_list.empty() ) { pos = end_list.remove_first(); grund_t *gr = welt->lookup(pos); // starts on slope or elevated way, or it consist only of the ramp ribi_t::ribi bridge_ribi = gr->get_weg_ribi_unmasked( wegtyp ); for( uint i = 0; i < 4; i++ ) { if( bridge_ribi & ribi_t::nesw[i] ) { grund_t *prev; // if we have a ramp, then only check the higher end! if( gr->get_neighbour( prev, wegtyp, ribi_t::nesw[i]) && prev->get_hoehe() > gr->get_hoehe() ) { if( weg_t *w = prev->get_weg( wegtyp ) ) { // now remove ribi (or full way) w->set_ribi( (~ribi_t::backward( ribi_t::nesw[i] )) & w->get_ribi_unmasked() ); if( w->get_ribi_unmasked() == 0 ) { // nothing left => then remove completly prev->remove_everything_from_way( player, wegtyp, bridge_ribi ); // removes stop and signals correctly prev->weg_entfernen( wegtyp, true ); if( prev->get_typ() == grund_t::monorailboden ) { welt->access( prev->get_pos().get_2d() )->boden_entfernen( prev ); delete prev; } else if( prev->get_typ() == grund_t::tunnelboden && !prev->hat_wege() ) { grund_t* gr_new = new boden_t(prev->get_pos(), prev->get_grund_hang()); welt->access(prev->get_pos().get_2d())->kartenboden_setzen(gr_new); } } else { w->calc_image(); } } } } } if(wegtyp==powerline_wt) { while (obj_t* const br = gr->find()) { br->cleanup(player); delete br; } leitung_t *lt = gr->get_leitung(); if (lt) { player_t *old_owner = lt->get_owner(); // first delete powerline to decouple from the bridge powernet lt->cleanup(old_owner); delete lt; // .. now create powerline to create new powernet lt = new leitung_t(gr->get_pos(), old_owner); lt->finish_rd(); gr->obj_add(lt); } } else { ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(wegtyp); ribi_t::ribi bridge_ribi; if(gr->get_weg_hang() != slope_t::flat) { bridge_ribi = ~ribi_t::backward(ribi_type(gr->get_weg_hang())); } else { bridge_ribi = ~ribi_type(gr->get_weg_hang()); } bridge_ribi &= ~(ribi_t::backward(~bridge_ribi)); ribi &= bridge_ribi; bruecke_t *br = gr->find(); br->cleanup(player); delete br; // stops on flag bridges ends with road + track on it // are not correctly deleted if ways are kept if (gr->is_halt()) { haltestelle_t::remove(player, gr->get_pos()); } // depots at bridge ends needs to be deleted as well if (depot_t *dep = gr->get_depot()) { dep->cleanup(player); delete dep; } // removes single signals, bridge head, pedestrians, stops, changes catenary etc weg_t *weg=gr->get_weg_nr(1); if(weg) { gr->remove_everything_from_way(player,weg->get_waytype(),bridge_ribi); } gr->remove_everything_from_way(player,wegtyp,bridge_ribi); // removes stop and signals correctly // corrects the ways weg = gr->get_weg(wegtyp); if( weg ) { // needs checks, since this fails if it was the last tile weg->set_desc( weg->get_desc() ); weg->set_ribi( ribi ); if( slope_t::max_diff(gr->get_weg_hang())>=2 && !weg->get_desc()->has_double_slopes() ) { // remove the way totally, if is is on a double slope gr->weg_entfernen( weg->get_waytype(), true ); } } } // then add the new ground, copy everything and replace the old one grund_t *gr_new = new boden_t(pos, gr->get_grund_hang()); gr_new->take_obj_from( gr ); welt->access(pos.get_2d())->kartenboden_setzen( gr_new ); if( wegtyp == powerline_wt ) { gr_new->get_leitung()->calc_neighbourhood(); // Recalc the image. calc_image() doesn't do the right job... } } welt->set_dirty(); return NULL; } simutrans-124.3/src/simutrans/builder/brueckenbauer.h000066400000000000000000000125351474050137200230110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_BRUECKENBAUER_H #define BUILDER_BRUECKENBAUER_H #include "../simtypes.h" #include "../dataobj/koord.h" #include "../dataobj/koord3d.h" class bridge_desc_t; class grund_t; class karte_ptr_t; class player_t; class way_desc_t; class tool_selector_t; /** * Bridge management: builds bridges, manages list of available bridge types * Bridges should not be built directly but always by calling bridge_builder_t::build(). */ class bridge_builder_t { private: bridge_builder_t() {} ///< private -> no instance please static karte_ptr_t welt; static bool is_blocked(koord3d pos, ribi_t::ribi check_ribi, const char *&error_msg); static bool is_monorail_junction(koord3d pos, player_t *player, const bridge_desc_t *desc, const char *&error_msg); public: /** * Finds the position of the end of the bridge. Does all kind of checks. * Uses two methods: * -# If ai_bridge==false then looks for end location at a sloped tile. * -# If ai_bridge==true returns the first location (taking min_length into account) * for the bridge end (including flat tiles). * @param player active player, needed to check scenario conditions * @param pos the position of the start of the bridge * @param zv desired direction of the bridge * @param desc the description of the bridge * @param error_msg an error message when the search fails. * @param bridge_height on success, the height of the bridge that we can build * @param ai_bridge if this bridge is being built by an AI * @param min_length the minimum length of the bridge. * @param high_bridge * @return the position of the other end of the bridge or koord3d::invalid if no possible end is found */ static koord3d find_end_pos(player_t *player, koord3d pos, const koord zv, const bridge_desc_t *desc, const char *&error_msg, sint8 &bridge_height, bool ai_bridge=false, uint32 min_length=0, bool high_bridge = false ); /** * Checks whether given tile @p gr is suitable for placing bridge ramp. * * @param player the player wanting to build the bridge. * @param gr the ground to check. * @param wt * @param r is ribi_t::none of the direction from bridge to ground. * @return true, if bridge ramp can be built here. */ static bool can_place_ramp(player_t *player, const grund_t *gr, waytype_t wt, ribi_t::ribi r ); /** * Checks if a bridge starts on @p gr * * @param gr the ground to check. * @return true, if bridge ends/starts here */ static bool is_start_of_bridge( const grund_t *gr ); /** * Build a bridge ramp. * * @param player the player wanting to build the bridge * @param end the position of the ramp * @param ribi_neu * @param weg_hang * @param desc the bridge description. */ static void build_ramp(player_t *player, koord3d end, ribi_t::ribi ribi_neu, slope_t::type weg_hang, const bridge_desc_t *desc); /** * Actually builds the bridge without checks. * Therefore checks should be done before in * bridge_builder_t::build(). * * @param player the master builder of the bridge. * @param start start position. * @param end end position * @param zv direction the bridge will face * @param bridge_height the height above start.z that the bridge will have * @param desc bridge description. * @param way_desc description of the way to be built on the bridge */ static void build_bridge(player_t *player, const koord3d start, const koord3d end, koord zv, sint8 bridge_height, const bridge_desc_t *desc, const way_desc_t *way_desc); /** * Registers a new bridge type and adds it to the list of build tools. * * @param desc Description of the bridge to register. */ static void register_desc(bridge_desc_t *desc); /** * Method to retrieve bridge descriptor * @param name name of the bridge * @return bridge descriptor or NULL if not found */ static const bridge_desc_t *get_desc(const char *name); /** * Builds the bridge and performs all checks. * This is the main construction routine. * * @param player The player wanting to build the bridge. * @param pos the start of the bridge. * @param desc Description of the bridge to build * @return NULL on success or error message otherwise */ static const char *build( player_t *player, const koord3d pos, const bridge_desc_t *desc); /** * Removes a bridge * @param player the demolisher and owner of the bridge * @param pos position anywhere on a bridge. * @param wegtyp way type of the bridge * @return An error message if the bridge could not be removed, NULL otherwise */ static const char *remove(player_t *player, koord3d pos, waytype_t wegtyp); /** * Find a matching bridge. * @param wtyp way type * @param min_speed desired lower bound for speed limit * @param time current in-game time * @return bridge descriptor or NULL */ static const bridge_desc_t *find_bridge(const waytype_t wtyp, const sint32 min_speed,const uint16 time); /** * Fill menu with icons for all ways of the given waytype * * @param tool_selector gui object of the toolbar * @param wtyp way type * @param sound_ok */ static void fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, sint16 sound_ok); /** * Returns a list with available bridge types. */ static const vector_tpl& get_available_bridges(const waytype_t wtyp); }; #endif simutrans-124.3/src/simutrans/builder/fabrikbauer.cc000066400000000000000000001154641474050137200226140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "fabrikbauer.h" #include "hausbauer.h" #include "../world/simworld.h" #include "../simintr.h" #include "../simfab.h" #include "../simmesg.h" #include "../utils/simrandom.h" #include "../world/simcity.h" #include "../simhalt.h" #include "../player/simplay.h" #include "../ground/grund.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../network/pakset_info.h" #include "../dataobj/translator.h" #include "../tpl/vector_tpl.h" #include "../tpl/array_tpl.h" #include "../world/building_placefinder.h" #include "../utils/cbuffer.h" #include "../descriptor/objversion.h" #include "../gui/minimap.h" // to update map after construction of new industry karte_ptr_t factory_builder_t::welt; /// Default factory spacing static int DISTANCE = 40; /// all factories and their exclusion areas static array_tpl fab_map; /// width of the factory map static sint32 fab_map_w=0; /** * Marks factories and their exclusion region in the position map. */ static void add_factory_to_fab_map(karte_t const* const welt, fabrik_t const* const fab) { koord3d const& pos = fab->get_pos(); sint16 const spacing = welt->get_settings().get_min_factory_spacing(); building_desc_t const& bdsc = *fab->get_desc()->get_building(); uint8 const rotate = fab->get_rotate(); sint16 const start_y = max(0, pos.y - spacing); sint16 const start_x = max(0, pos.x - spacing); sint16 const end_y = min(welt->get_size().y - 1, pos.y + bdsc.get_y(rotate) + spacing); sint16 const end_x = min(welt->get_size().x - 1, pos.x + bdsc.get_x(rotate) + spacing); for (sint16 y = start_y; y < end_y; ++y) { for (sint16 x = start_x; x < end_x; ++x) { fab_map[fab_map_w * y + x / 8] |= 1 << (x % 8); } } } /** * Creates map with all factories and exclusion area. */ void init_fab_map( karte_t *welt ) { fab_map_w = ((welt->get_size().x+7)/8); fab_map.resize( fab_map_w*welt->get_size().y ); for( int i=0; iget_size().y; i++ ) { fab_map[i] = 0; } for(fabrik_t* const f : welt->get_fab_list()) { add_factory_to_fab_map(welt, f); } if( welt->get_settings().get_max_factory_spacing_percent() > 0 ) { DISTANCE = (welt->get_size_max() * welt->get_settings().get_max_factory_spacing_percent()) / 100l; } else { DISTANCE = welt->get_settings().get_max_factory_spacing(); } } /** * @param x,y world position, needs to be valid coordinates * @returns true, if factory coordinate */ inline bool is_factory_at(sint16 x, sint16 y) { uint32 idx = (fab_map_w*y)+(x/8); return idx < fab_map.get_count() && (fab_map[idx]&(1<<(x%8)))!=0; } void factory_builder_t::new_world() { init_fab_map( welt ); } /** * Searches for a suitable building site using suche_platz(). * The site is chosen so that there is a street next to the building site. */ class factory_site_searcher_t: public building_placefinder_t { factory_desc_t::site_t site; public: factory_site_searcher_t(karte_t* welt, factory_desc_t::site_t site_) : building_placefinder_t(welt), site(site_) {} bool is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const OVERRIDE { if( !building_placefinder_t::is_area_ok(pos, w, h, cl) ) { return false; } uint16 mincond = 0; uint16 condmet = 0; switch(site) { case factory_desc_t::forest: mincond = w*h+w+h; // at least w*h+w+h trees, i.e. few tiles with more than one tree break; case factory_desc_t::shore: case factory_desc_t::river: case factory_desc_t::City: default: mincond = 1; } // needs to run one tile wider than the factory on all sides for (sint16 y = -1; y <= h; y++) { for (sint16 x = -1; x <= w; x++) { koord k(pos + koord(x,y)); grund_t *gr = welt->lookup_kartenboden(k); if (!gr) { return false; } // do not build on an existing factory if( is_factory_at(k.x, k.y) ) { return false; } if( 0 <= x && x < w && 0 <= y && y < h ) { // actual factorz tile: is there something top like elevated monorails? if( gr->get_leitung()!=NULL || welt->lookup(gr->get_pos()+koord3d(0,0,1) )!=NULL) { // something on top (monorail or power lines) return false; } // check for trees unless the map was generated without trees if( site==factory_desc_t::forest && welt->get_settings().get_tree_distribution()!=settings_t::TREE_DIST_NONE && condmet < mincond ) { for(uint8 i=0; i< gr->obj_count(); i++) { if (gr->obj_bei(i)->get_typ() == obj_t::baum) { condmet++; } } } } else { // border tile: check for road, shore, river if( condmet < mincond && (-1==x || x==w) && (-1==y || y==h) ) { switch (site) { case factory_desc_t::City: condmet += gr->hat_weg(road_wt); break; case factory_desc_t::shore: condmet += welt->get_climate(k)==water_climate; break; case factory_desc_t::river: if( welt->get_settings().get_river_number() >0 ) { weg_t* river = gr->get_weg(water_wt); if (river && river->get_desc()->get_styp()==type_river) { condmet++; DBG_DEBUG("factory_site_searcher_t::is_area_ok()", "Found river near %s", pos.get_str()); } break; } else { // always succeeds on maps without river ... condmet++; break; } default: ; } } } } } if( site==factory_desc_t::forest && condmet>=3 ) { dbg->message("", "found %d at %s", condmet, pos.get_str() ); } return condmet >= mincond; } }; stringhashtable_tpl factory_builder_t::desc_table; /** * Compares factory descriptors by their name. * Used in get_random_consumer(). * @return true, if @p a < @p b, false otherwise. */ static bool compare_fabrik_desc(const factory_desc_t* a, const factory_desc_t* b) { const int diff = strcmp( a->get_name(), b->get_name() ); return diff < 0; } // returns a random consumer const factory_desc_t *factory_builder_t::get_random_consumer(bool electric, climate_bits cl, uint16 timeline ) { // get a random city factory weighted_vector_tpl consumer; for(auto const& i : desc_table) { factory_desc_t const* const current = i.value; // only insert end consumers if ( current->is_consumer_only() && current->get_building()->is_allowed_climate_bits(cl) && (electric ^ !current->is_electricity_producer()) && current->get_building()->is_available(timeline) ) { consumer.insert_unique_ordered(current, current->get_distribution_weight(), compare_fabrik_desc); } } // no consumer installed? if (consumer.empty()) { DBG_MESSAGE("factory_builder_t::get_random_consumer()","No suitable consumer found"); return NULL; } // now find a random one factory_desc_t const* const fd = pick_any_weighted(consumer); DBG_MESSAGE("factory_builder_t::get_random_consumer()", "consumer %s found.", fd->get_name()); return fd; } const factory_desc_t *factory_builder_t::get_desc(const char *factory_name) { return desc_table.get(factory_name); } void factory_builder_t::register_desc(factory_desc_t *desc) { uint16 p=desc->get_productivity(); if(p&0x8000) { koord k=desc->get_building()->get_size(); // to be compatible with old factories, since new code only steps once per factory, not per tile desc->set_productivity( (p&0x7FFF)*k.x*k.y ); DBG_DEBUG("factory_builder_t::register_desc()","Correction for old factory: Increase production from %i by %i",p&0x7FFF,k.x*k.y); } if( const factory_desc_t *old_desc = desc_table.remove(desc->get_name()) ) { delete old_desc; } desc_table.put(desc->get_name(), desc); } bool factory_builder_t::successfully_loaded() { for(auto const& i : desc_table) { factory_desc_t const* const current = i.value; if( field_group_desc_t * fg = const_cast(current->get_field_group()) ) { // initialize weighted vector for the field class indices fg->init_field_class_indices(); } // check for crossconnects for( int j=0; j < current->get_supplier_count(); j++ ) { weighted_vector_tplproducer; find_producer( producer, current->get_supplier(j)->get_input_type(), 0 ); if( producer.is_contained(current) ) { // must not happen else dbg->fatal( "factory_builder_t::successfully_loaded()", "Factory %s output %s cannot be its own input!", i.key, current->get_supplier(j)->get_input_type()->get_name() ); } } checksum_t *chk = new checksum_t(); current->calc_checksum(chk); pakset_info_t::append(current->get_name(), "factory", chk); } return true; } int factory_builder_t::count_producers(const goods_desc_t *ware, uint16 timeline) { int count=0; // iterate over all factories and check if they produce this good... for(auto const& t : desc_table) { factory_desc_t const* const tmp = t.value; for (uint i = 0; i < tmp->get_product_count(); i++) { const factory_product_desc_t *product = tmp->get_product(i); if( product->get_output_type()==ware && tmp->get_distribution_weight()>0 && tmp->get_building()->is_available(timeline) ) { count++; } } } DBG_MESSAGE("factory_builder_t::count_producers()","%i producer for good '%s' found.", count, translator::translate(ware->get_name())); return count; } /* * Finds a random producer producing @p ware. * @param timeline the current time(months) */ void factory_builder_t::find_producer(weighted_vector_tpl &producer, const goods_desc_t *ware, uint16 timeline ) { // find all producers producer.clear(); for(auto const& t : desc_table) { factory_desc_t const* const tmp = t.value; if ( tmp->get_distribution_weight()>0 && tmp->get_building()->is_available(timeline) ) { for( uint i=0; iget_product_count(); i++ ) { const factory_product_desc_t *product = tmp->get_product(i); if( product->get_output_type()==ware ) { producer.insert_unique_ordered(tmp, tmp->get_distribution_weight(), compare_fabrik_desc); break; } } } } // no producer installed? if( producer.empty() ) { dbg->error("factory_builder_t::find_producer()", "no producer for good '%s' was found.", translator::translate(ware->get_name())); } DBG_MESSAGE("factory_builder_t::find_producer()", "%i producer for good '%s' found.", producer.get_count(), translator::translate(ware->get_name()) ); } bool factory_builder_t::check_construction_site(koord pos, koord size, factory_desc_t::site_t site, bool is_factory, climate_bits cl) { // check for water (no shore in sight!) if(site==factory_desc_t::Water) { for(int y=0;ylookup_kartenboden(pos+koord(x,y)); if(gr==NULL || !gr->is_water() || gr->get_grund_hang()!=slope_t::flat) { return false; } } } } else { if (is_factory && site!=factory_desc_t::Land) { return factory_site_searcher_t(welt, site).is_area_ok(pos, size.x, size.y, cl); } else { // check on land // do not build too close or on an existing factory if( !welt->is_within_limits(pos) || is_factory_at(pos.x, pos.y) ) { return false; } return welt->square_is_free(pos, size.x, size.y, NULL, cl); } } return true; } koord3d factory_builder_t::find_random_construction_site(koord pos, int radius, koord size, factory_desc_t::site_t site, const building_desc_t *desc, bool ignore_climates, uint32 max_iterations) { bool is_factory = desc->get_type()==building_desc_t::factory; bool wasser = site == factory_desc_t::Water; if(wasser) { // to ensure at least 3x3 water around (maybe this should be the station catchment area+1?) size += koord(6,6); } climate_bits climates = !ignore_climates ? desc->get_allowed_climate_bits() : ALL_CLIMATES; if (ignore_climates && site != factory_desc_t::Water) { //site = factory_desc_t::Land; } uint32 diam = 2*radius + 1; uint32 area = diam * diam; uint32 index = simrand(area); koord k; max_iterations = min( area/(size.x*size.y)+1, max_iterations ); const uint32 a = diam+1; const uint32 c = 37; // very unlikely to have this as a factor in somewhere ... // in order to stop on the first occurence, one has to iterate over all tiles in a reproducable but random enough manner for( uint32 i = 0; iget_name(), pos.get_str(), max_iterations); } return koord3d::invalid; finish: if(wasser) { // take care of offset return welt->lookup_kartenboden(k+koord(3, 3))->get_pos(); } return welt->lookup_kartenboden(k)->get_pos(); } // Create a certain number of tourist attractions void factory_builder_t::distribute_attractions(int max_number) { // current number of tourist attractions constructed int current_number=0; // select without timeline disappearing dates if(hausbauer_t::get_random_attraction(welt->get_timeline_year_month(),true,temperate_climate)==NULL) { // nothing at all? return; } // very fast, so we do not bother updating progress bar dbg->message("factory_builder_t::distribute_attractions()", "Distributing %i tourist attractions", max_number); int retrys = max_number*4; while(current_number0) { koord3d pos=koord3d( koord::koord_random(welt->get_size().x,welt->get_size().y),1); const building_desc_t *attraction=hausbauer_t::get_random_attraction(welt->get_timeline_year_month(),true,(climate)simrand((int)arctic_climate+1)); // no attractions for that climate or too new if(attraction==NULL || (welt->use_timeline() && attraction->get_intro_year_month()>welt->get_current_month()) ) { continue; } int rotation=simrand(attraction->get_all_layouts()-1); pos = find_random_construction_site(pos.get_2d(), 20, attraction->get_size(rotation), factory_desc_t::Land, attraction, false, 0x0FFFFFFF); // so far -> land only if(welt->lookup(pos)) { // space found, build attraction hausbauer_t::build(welt->get_public_player(), pos.get_2d(), rotation, attraction); current_number ++; retrys = max_number*4; } } // update an open map minimap_t::get_instance()->calc_map_size(); } /** * Compares cities by their distance to an origin. */ class RelativeDistanceOrdering { private: const koord m_origin; public: RelativeDistanceOrdering(const koord& origin) : m_origin(origin) { /* nothing */ } /// @returns true if @p a is closer to the origin than @p b, otherwise false. bool operator()(const stadt_t *a, const stadt_t *b) const { return koord_distance(m_origin, a->get_pos()) < koord_distance(m_origin, b->get_pos()); } }; /* * Builds a single new factory. */ fabrik_t* factory_builder_t::build_factory(koord3d* parent, const factory_desc_t* info, sint32 initial_prod_base, int rotate, koord3d pos, player_t* owner) { fabrik_t * fab = new fabrik_t(pos, owner, info, initial_prod_base); // now build factory fab->build(rotate, true /*add fields*/, initial_prod_base != -1 /* force initial prodbase ? */); welt->add_fab(fab); add_factory_to_fab_map(welt, fab); if(parent) { fab->add_consumer(parent->get_2d()); } // make all water station if(info->get_placement() == factory_desc_t::Water) { const building_desc_t *desc = info->get_building(); koord dim = desc->get_size(rotate); // create water halt halthandle_t halt = haltestelle_t::create(pos.get_2d(), welt->get_public_player()); if(halt.is_bound()) { // add all other tiles of the factory to the halt for( int x=pos.x; xis_within_limits(x,y)) { grund_t *gr = welt->lookup_kartenboden(x,y); // build the halt on factory tiles on open water only, // since the halt can't be removed otherwise if(gr->is_water() && !(gr->hat_weg(water_wt)) && gr->find()) { halt->add_grund( gr ); } } } } halt->set_name( translator::translate(info->get_name()) ); halt->recalc_station_type(); } } else { // connect factory to stations // search for nearby stations and connect factory to them koord dim = info->get_building()->get_size(rotate); for( int x=pos.x; xaccess(x,y); const halthandle_t *halt_list = plan->get_haltlist(); for( unsigned h=0; hget_haltlist_count(); h++ ) { if (halt_list[h]->connect_factory(fab)) { if (x != pos.x || y != pos.y) { // factory halt list is already correct at pos fab->link_halt(halt_list[h]); } } // cannot call halt_list[h]->verbinde_fabriken() here, // as it modifies halt_list in its calls to fabrik_t::unlink_halt and fabrik_t::link_halt } } } } // add passenger to pax>0, (so no suicide diver at the fish swarm) if(info->get_pax_level()>0) { const weighted_vector_tpl& staedte = welt->get_cities(); vector_tpldistance_stadt( staedte.get_count() ); for(stadt_t* const i : staedte) { distance_stadt.insert_ordered(i, RelativeDistanceOrdering(fab->get_pos().get_2d())); } settings_t const& s = welt->get_settings(); for(stadt_t* const i : distance_stadt) { uint32 const ntgt = fab->get_target_cities().get_count(); if (ntgt >= s.get_factory_worker_maximum_towns()) break; if (ntgt < s.get_factory_worker_minimum_towns() || koord_distance(fab->get_pos(), i->get_pos()) < s.get_factory_worker_radius()) { fab->add_target_city(i); } } } return fab; } // Check if we have to rotate the factories before building this tree bool factory_builder_t::can_factory_tree_rotate( const factory_desc_t *desc ) { // we are finished: we cannot rotate if(!desc->get_building()->can_rotate()) { return false; } // now check all suppliers if they can rotate for( int i=0; iget_supplier_count(); i++ ) { const goods_desc_t *ware = desc->get_supplier(i)->get_input_type(); // unfortunately, for every for iteration we have to check all factories ... for(auto const& t : desc_table) { factory_desc_t const* const tmp = t.value; // now check if we produce this good... for (uint i = 0; i < tmp->get_product_count(); i++) { if(tmp->get_product(i)->get_output_type()==ware && tmp->get_distribution_weight()>0) { if(!can_factory_tree_rotate( tmp )) { return false; } // check next factory break; } } } } // all good -> true; return true; } /* * Builds a new full chain of factories. Precondition before calling this function: * @p pos is suitable for factory construction and number of chains * is the maximum number of good types for which suppliers chains are built * (meaning there are no unfinished factory chains). */ int factory_builder_t::build_link(koord3d* parent, const factory_desc_t* info, sint32 initial_prod_base, int rotate, koord3d* pos, player_t* player, int number_of_chains, bool ignore_climates) { int n = 1; int org_rotation = -1; if(info==NULL) { // no industry found return 0; } // no cities at all? if (info->get_placement() == factory_desc_t::City && welt->get_cities().empty()) { return 0; } // if a factory is not rotate-able, rotate the world until we can save it if(welt->cannot_save() && parent==NULL && !can_factory_tree_rotate(info) ) { org_rotation = welt->get_settings().get_rotation(); for( int i=0; i<3 && welt->cannot_save(); i++ ) { pos->rotate90( welt->get_size().y-info->get_building()->get_y(rotate) ); welt->rotate90(); } assert( !welt->cannot_save() ); } // in town we need a different place search if (info->get_placement() == factory_desc_t::City) { koord size=info->get_building()->get_size(0); // build consumer (factory) in town stadt_t *city = welt->find_nearest_city(pos->get_2d()); climate_bits cl = ignore_climates ? ALL_CLIMATES : info->get_building()->get_allowed_climate_bits(); /* Three variants: * A: * A building site, preferably close to the town hall with a street next to it. * This could be a temporary problem, if a city has no such site and the search * continues to the next city. * Otherwise seems to me the most realistic. */ bool is_rotate=info->get_building()->get_all_layouts()>1 && size.x!=size.y && info->get_building()->can_rotate(); // first try with standard orientation koord k = factory_site_searcher_t(welt, factory_desc_t::City).find_place(city->get_pos(), size.x, size.y, cl ); // second try: rotated koord k1 = koord::invalid; if (is_rotate && (k == koord::invalid || simrand(256)<128)) { k1 = factory_site_searcher_t(welt, factory_desc_t::City).find_place(city->get_pos(), size.y, size.x, cl ); } rotate = simrand( info->get_building()->get_all_layouts() ); if (k1 == koord::invalid) { if (size.x != size.y) { rotate &= 2; // rotation must be even number } } else { k = k1; rotate |= 1; // rotation must be odd number } if (!info->get_building()->can_rotate()) { rotate = 0; } INT_CHECK( "fabrikbauer 588" ); /* B: * Also good. The final factories stand possibly somewhat outside of the city however not far away. * (does not obey climates though!) */ #if 0 k = find_random_construction_site(welt, welt->lookup(city->get_pos())->get_boden()->get_pos(), 3, land_bau.dim).get_2d(); #endif /* C: * A building site, as near as possible to the city hall. * If several final factories land in one city, they are often * often hidden behind a row of houses, cut off from roads. */ #if 0 k = building_placefinder_t(welt).find_place(city->get_pos(), land_bau.dim.x, land_bau.dim.y, info->get_building()->get_allowed_climate_bits(), &is_rotate); #endif if(k != koord::invalid) { *pos = welt->lookup_kartenboden(k)->get_pos(); } else { return 0; } } DBG_MESSAGE("factory_builder_t::build_link","Construction of %s at (%i,%i).",info->get_name(),pos->x,pos->y); INT_CHECK("fabrikbauer 594"); const fabrik_t *our_fab=build_factory(parent, info, initial_prod_base, rotate, *pos, player); INT_CHECK("fabrikbauer 596"); // now build supply chains for all products for(int i=0; iget_supplier_count() && i update map if needed if(parent==NULL) { DBG_MESSAGE("factory_builder_t::build_link()","update karte"); // update the map if needed minimap_t::get_instance()->calc_map_size(); INT_CHECK( "fabrikbauer 730" ); // must rotate back? if(org_rotation>=0) { for (int i = 0; i < 4 && welt->get_settings().get_rotation() != org_rotation; ++i) { pos->rotate90( welt->get_size().y-1 ); welt->rotate90(); } welt->update_map(); } } return n; } int factory_builder_t::build_chain_link(const fabrik_t* our_fab, const factory_desc_t* info, int supplier_nr, player_t* player) { int n = 0; // number of additional factories /* first we try to connect to existing factories and will do some * cross-connect (if wanted) * We must take care to add capacity for cross-connected factories! */ const factory_supplier_desc_t *supplier = info->get_supplier(supplier_nr); const goods_desc_t *ware = supplier->get_input_type(); const int producer_count=count_producers( ware, welt->get_timeline_year_month() ); if(producer_count==0) { dbg->error("factory_builder_t::build_chain_link()","No producer for %s found, chain incomplete!",ware->get_name() ); return 0; } // how much do we need? sint32 consumption = our_fab->get_base_production()*supplier->get_consumption(); slist_tpl factories_to_correct; slist_tpl new_factories; // since the cross-correction must be done later slist_tpl crossconnected_supplier; // also done after the construction of new chains int lcount = supplier->get_supplier_count(); int lfound = 0; // number of found producers DBG_MESSAGE("factory_builder_t::build_chain_link","supplier_count %i, lcount %i (need %i of %s)",info->get_supplier_count(),lcount,consumption,ware->get_name()); // search if there already is one or two (cross-connect everything if possible) for(fabrik_t* const fab : welt->get_fab_list()) { // Try to find matching factories for this consumption, but don't find more than two times number of factories requested. if ( (lcount != 0 || consumption <= 0) && lcount < lfound + 1 ) break; // connect to an existing one if this is a producer if( fab->get_output_stock(ware) > -1 ) { const int distance = koord_distance(fab->get_pos(),our_fab->get_pos()); if( distance > welt->get_settings().get_min_factory_spacing() && distance <= DISTANCE ) { // ok, this would match but can she supply enough? // now guess how much this factory can supply const factory_desc_t* const fd = fab->get_desc(); for (uint gg = 0; gg < fd->get_product_count(); gg++) { if (fd->get_product(gg)->get_output_type() == ware && fab->get_consumer().get_count() < 10) { // does not make sense to split into more ... sint32 production_left = fab->get_base_production() * fd->get_product(gg)->get_factor(); const vector_tpl & consumer = fab->get_consumer(); // decrease remaining production by supplier demand for(koord const& i : consumer) { if (production_left <= 0) break; fabrik_t* const zfab = fabrik_t::get_fab(i); for(int zz=0; zzget_desc()->get_supplier_count(); zz++) { if(zfab->get_desc()->get_supplier(zz)->get_input_type()==ware) { production_left -= zfab->get_base_production()*zfab->get_desc()->get_supplier(zz)->get_consumption(); break; } } } // here is actually capacity left (or sometimes just connect anyway)! if (production_left > 0 || simrand(100) < (uint32)welt->get_settings().get_crossconnect_factor()) { if(production_left>0) { consumption -= production_left; fab->add_consumer(our_fab->get_pos().get_2d()); DBG_MESSAGE("factory_builder_t::build_chain_link","supplier %s can supply approx %i of %s to us", fd->get_name(), production_left, ware->get_name()); } else { /* we steal something; however the total capacity * needed is the same. Therefore, we just keep book * from whose factories from how many we stole */ crossconnected_supplier.append(fab); for(koord const& t : consumer) { fabrik_t* zfab = fabrik_t::get_fab(t); for(int zz=0; zzget_desc()->get_supplier_count(); zz++) { if(zfab->get_desc()->get_supplier(zz)->get_input_type()==ware) { slist_tpl::iterator i = std::find(factories_to_correct.begin(), factories_to_correct.end(), factories_to_crossconnect_t(zfab, 0)); if (i == factories_to_correct.end()) { factories_to_correct.append(factories_to_crossconnect_t(zfab, 1)); } else { i->demand += 1; } } } } // the needed production to be built does not change! } lfound ++; } break; // since we found the product ... } } } } } INT_CHECK( "fabrikbauer 670" ); /* try to add all types of factories until demand is satisfied */ weighted_vector_tplproducer; find_producer( producer, ware, welt->get_timeline_year_month() ); if( producer.empty() ) { // can happen with timeline if(!info->is_consumer_only()) { dbg->error( "factory_builder_t::build_chain_link()", "no producer for %s!", ware->get_name() ); return 0; } else { // only consumer: Will do with partly covered chains dbg->error( "factory_builder_t::build_chain_link()", "no producer for %s!", ware->get_name() ); } } bool ignore_climates = false; // ignore climates after some retrys int retry=25; // and not more than 25 (happens mostly in towns) while( (lcount>lfound || lcount==0) && consumption>0 && retry>0 ) { const factory_desc_t *producer_d = pick_any_weighted( producer ); int rotate = simrand(producer_d->get_building()->get_all_layouts()-1); koord3d parent_pos = our_fab->get_pos(); // ignore climates after 40 tries // if climates are ignored, then placement as well ... factory_desc_t::site_t placement = ignore_climates ? (producer_d->get_placement() == factory_desc_t::City ? factory_desc_t::City : factory_desc_t::Land) : producer_d->get_placement(); INT_CHECK("fabrikbauer 697"); koord3d k = find_random_construction_site( our_fab->get_pos().get_2d(), DISTANCE, producer_d->get_building()->get_size(rotate), placement, producer_d->get_building(), ignore_climates, 20000 ); if( k == koord3d::invalid ) { // this factory cannot buuild in the desired vincinity producer.remove( producer_d ); if( producer.empty() ) { if( ignore_climates ) { // absolutely no place to construct something here break; } find_producer( producer, ware, welt->get_timeline_year_month() ); ignore_climates = true; } continue; } INT_CHECK("fabrikbauer 697"); DBG_MESSAGE("factory_builder_t::build_chain_link","Try to built supplier %s at (%i,%i) r=%i for %s.",producer_d->get_name(),k.x,k.y,rotate,info->get_name()); n += build_link(&parent_pos, producer_d, -1 /*random prodbase */, rotate, &k, player, 10000, ignore_climates); lfound ++; INT_CHECK( "fabrikbauer 702" ); // now subtract current supplier fabrik_t *fab = fabrik_t::get_fab(k.get_2d() ); if(fab==NULL) { DBG_MESSAGE( "factory_builder_t::build_chain_link", "Failed to build at %s", k.get_str() ); retry --; continue; } new_factories.append(fab); // connect new supplier to us const factory_desc_t* const fd = fab->get_desc(); for (uint gg = 0; gg < fab->get_desc()->get_product_count(); gg++) { if (fd->get_product(gg)->get_output_type() == ware) { sint32 production = fab->get_base_production() * fd->get_product(gg)->get_factor(); // the take care of how much this factory could supply consumption -= production; DBG_MESSAGE("factory_builder_t::build_chain_link", "new supplier %s can supply approx %i of %s to us", fd->get_name(), production, ware->get_name()); break; } } } // now we add us to all cross-connected factories for(fabrik_t* const i : crossconnected_supplier) { i->add_consumer(our_fab->get_pos().get_2d()); } /* now the cross-connect part: * connect also the factories we stole from before ... */ for(fabrik_t* const fab : new_factories) { for (slist_tpl::iterator i = factories_to_correct.begin(), end = factories_to_correct.end(); i != end;) { i->demand -= 1; fab->add_consumer(i->fab->get_pos().get_2d()); i->fab->add_supplier(fab->get_pos().get_2d()); if (i->demand < 0) { i = factories_to_correct.erase(i); } else { ++i; } } } INT_CHECK( "fabrikbauer 723" ); return n; } /* * This function is called whenever it is time for industry growth. * If there is still a pending consumer, this method will first complete another chain for it. * If not, it will decide to either build a power station (if power is needed) * or build a new consumer near the indicated position. * @return number of factories built */ int factory_builder_t::increase_industry_density( bool tell_me ) { int nr = 0; fabrik_t *last_built_consumer = NULL; #if MSG_LEVEL >= 3 const goods_desc_t *last_built_consumer_ware = NULL; #endif // find last consumer minivec_tplware_needed; if(!welt->get_fab_list().empty()) { for(fabrik_t* const fab : welt->get_fab_list()) { if (fab->get_desc()->is_consumer_only()) { last_built_consumer = fab; break; } } // ok, found consumer if( last_built_consumer ) { ware_needed.clear(); ware_needed.resize( last_built_consumer->get_desc()->get_supplier_count() ); for( int i=0; i < last_built_consumer->get_desc()->get_supplier_count(); i++ ) { ware_needed.append_unique( last_built_consumer->get_desc()->get_supplier(i)->get_input_type() ); } for(koord const& j : last_built_consumer->get_suppliers()) { factory_desc_t const* const fd = fabrik_t::get_fab(j)->get_desc(); for (uint32 k = 0; k < fd->get_product_count(); k++) { ware_needed.remove( fd->get_product(k)->get_output_type() ); } } } } // first: do we have to continue unfinished factory chains? if( !ware_needed.empty() && last_built_consumer ) { int org_rotation = -1; // rotate until we can save it if one of the factories is non-rotate-able ... if(welt->cannot_save() && !can_factory_tree_rotate(last_built_consumer->get_desc()) ) { org_rotation = welt->get_settings().get_rotation(); for( int i=0; i<3 && welt->cannot_save(); i++ ) { welt->rotate90(); } assert( !welt->cannot_save() ); } uint32 last_suppliers = last_built_consumer->get_suppliers().get_count(); do { // we have the ware but not the supplier for it ... int last_built_consumer_missing_supplier = 99999; for( int i=0; i < last_built_consumer->get_desc()->get_supplier_count(); i++ ) { if( last_built_consumer->get_desc()->get_supplier(i)->get_input_type() == ware_needed[0] ) { last_built_consumer_missing_supplier = i; break; } } nr += build_chain_link( last_built_consumer, last_built_consumer->get_desc(), last_built_consumer_missing_supplier, welt->get_public_player() ); #if MSG_LEVEL >=3 last_built_consumer_ware = ware_needed[ 0 ]; #endif ware_needed.remove_at( 0 ); } while( !ware_needed.empty() && last_built_consumer->get_suppliers().get_count()==last_suppliers ); // must rotate back? if(org_rotation>=0) { for (int i = 0; i < 4 && welt->get_settings().get_rotation() != org_rotation; ++i) { welt->rotate90(); } welt->update_map(); } // only return if successful if( last_built_consumer->get_suppliers().get_count() > last_suppliers ) { DBG_MESSAGE( "factory_builder_t::increase_industry_density()", "added ware %s to factory %s", last_built_consumer_ware->get_name(), last_built_consumer->get_name() ); // tell the player if(tell_me) { stadt_t *s = welt->find_nearest_city( last_built_consumer->get_pos().get_2d() ); const char *stadt_name = s ? s->get_name() : translator::translate("nowhere"); cbuffer_t buf; buf.printf( translator::translate("Factory chain extended\nfor %s near\n%s built with\n%i factories."), translator::translate(last_built_consumer->get_name()), stadt_name, nr ); welt->get_message()->add_message(buf, last_built_consumer->get_pos(), message_t::industry, CITY_KI, last_built_consumer->get_desc()->get_building()->get_tile(0)->get_background(0, 0, 0)); } minimap_t::get_instance()->calc_map(); return nr; } else { DBG_MESSAGE( "factory_builder_t::increase_industry_density()", "failed to add ware %s to factory %s", last_built_consumer_ware->get_name(), last_built_consumer->get_name() ); } } // ok, no chains to finish, thus we must start anew // first determine electric supply and demand uint32 electric_supply = 0; uint32 electric_demand = 1; for(fabrik_t* const fab : welt->get_fab_list()) { if( fab->get_desc()->is_electricity_producer() ) { electric_supply += fab->get_scaled_electric_demand() / PRODUCTION_DELTA_T; } else { electric_demand += fab->get_scaled_electric_demand() / PRODUCTION_DELTA_T; } } // now decide producer of electricity or normal ... sint32 promille = (electric_supply*1000l)/electric_demand; int no_electric = promille > welt->get_settings().get_electric_promille(); // =1 -> build normal factories only DBG_MESSAGE( "factory_builder_t::increase_industry_density()", "production of electricity/total production is %i/%i (%i o/oo)", electric_supply, electric_demand, promille ); while( no_electric<2 ) { bool ignore_climates = false; for(int retries=20; retries>0; retries-- ) { const factory_desc_t *fab=get_random_consumer( no_electric==0, ALL_CLIMATES, welt->get_timeline_year_month() ); if(fab) { const bool in_city = fab->get_placement() == factory_desc_t::City; if (in_city && welt->get_cities().empty()) { // we cannot build this factory here continue; } koord3d pos; int rotation = simrand( fab->get_building()->get_all_layouts() ); if(!in_city) { // find somewhere on the map pos = find_random_construction_site( koord(welt->get_size().x/2,welt->get_size().y/2), welt->get_size_max()/2, fab->get_building()->get_size(rotation),fab->get_placement(),fab->get_building(),ignore_climates,10000); } else { // or within the city limit const stadt_t *city = pick_any_weighted(welt->get_cities()); koord diff = city->get_rechtsunten()-city->get_linksoben(); pos = find_random_construction_site( city->get_center(), max(diff.x,diff.y)/2, fab->get_building()->get_size(rotation),fab->get_placement(),fab->get_building(),ignore_climates, 1000); } if(welt->lookup(pos)) { // Space found... nr += build_link(NULL, fab, -1 /* random prodbase */, rotation, &pos, welt->get_public_player(), 1, ignore_climates); if(nr>0) { fabrik_t *our_fab = fabrik_t::get_fab( pos.get_2d() ); minimap_t::get_instance()->calc_map_size(); // tell the player if(tell_me) { stadt_t* s = welt->find_nearest_city(our_fab->get_pos().get_2d()); const char* stadt_name = s ? s->get_name() : translator::translate("nowhere"); cbuffer_t buf; buf.printf( translator::translate("New factory chain\nfor %s near\n%s built with\n%i factories."), translator::translate(our_fab->get_name()), stadt_name, nr ); welt->get_message()->add_message(buf, pos, message_t::industry, CITY_KI, our_fab->get_desc()->get_building()->get_tile(0)->get_background(0, 0, 0)); } return nr; } } else if( retries==1 && !ignore_climates ) { // from now on, we will ignore climates to avoid broken chains ignore_climates = true; retries = 20; } } } // try building normal factories if building power plants was not successful no_electric++; } // we should not reach here, because it means neither land nor city industries exist ... dbg->warning( "factory_builder_t::increase_industry_density()", "No suitable city industry found => pak missing something?" ); return 0; } simutrans-124.3/src/simutrans/builder/fabrikbauer.h000066400000000000000000000130451474050137200224460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_FABRIKBAUER_H #define BUILDER_FABRIKBAUER_H #include "../tpl/stringhashtable_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../dataobj/koord3d.h" #include "../descriptor/factory_desc.h" class stadt_t; class karte_ptr_t; class player_t; class fabrik_t; /** * This class builds factories. Never construct factories directly * but always by calling factory_builder_t::build() (for a single factory) * or factory_builder_t::baue_hierachie() (for a full chain of suppliers). */ class factory_builder_t { private: static karte_ptr_t welt; /** * @class factories_to_crossconnect_t * Used for cross-connection checks between factories. * This is necessary for finding producers for factory supply. */ class factories_to_crossconnect_t { public: fabrik_t *fab; ///< The factory sint32 demand; ///< To how many factories this factory needs to connect to factories_to_crossconnect_t() { fab = NULL; demand = 0; } factories_to_crossconnect_t(fabrik_t *f, sint32 d) { fab = f; demand = d; } bool operator == (const factories_to_crossconnect_t& x) const { return fab == x.fab; } bool operator != (const factories_to_crossconnect_t& x) const { return fab != x.fab; } }; /// Table of all factories that can be built static stringhashtable_tpl desc_table; /// @returns the number of producers producing @p ware static int count_producers(const goods_desc_t *ware, uint16 timeline); /** * Finds a random producer producing @p ware. * * @param producer * @param ware * @param timeline the current time (months) */ static void find_producer(weighted_vector_tpl &producer, const goods_desc_t *ware, uint16 timeline ); public: /// Registers the factory description so the factory can be built in-game. static void register_desc(factory_desc_t *desc); /** * Initializes weighted vector for farm field class indices. * @returns true */ static bool successfully_loaded(); /** * Tells the factory builder a new map is being loaded or generated. * In this case the list of all factory positions must be reinitialized. */ static void new_world(); /// Creates a certain number of tourist attractions. static void distribute_attractions(int max_number); /// @returns a factory description for a factory name static const factory_desc_t *get_desc(const char *factory_name); /// @returns the table containing all factory descriptions static const stringhashtable_tpl& get_factory_table() { return desc_table; } /** * @param electric true to limit search to electricity producers only * @param cl allowed climates * @param timeline * @returns a random consumer */ static const factory_desc_t *get_random_consumer(bool electric, climate_bits cl, uint16 timeline ); /** * Builds a single new factory. * * @param parent location of the parent factory * @param info Description for the new factory * @param initial_prod_base Initial base production (-1 to disable) * @param rotate building rotation (0..3) * @param pos * @param owner * @returns The newly constructed factory. */ static fabrik_t* build_factory(koord3d* parent, const factory_desc_t* info, sint32 initial_prod_base, int rotate, koord3d pos, player_t* owner); /** * Builds a new full chain of factories. Precondition before calling this function: * @p pos is suitable for factory construction and number of chains * is the maximum number of good types for which suppliers chains are built * (meaning there are no unfinished factory chains). * @returns number of factories built */ static int build_link(koord3d* parent, const factory_desc_t* info, sint32 initial_prod_base, int rotate, koord3d* pos, player_t* player, int number_of_chains, bool ignore_climates ); /** * Helper function for baue_hierachie(): builds the connections (chain) for one single product) * @returns number of factories built */ static int build_chain_link(const fabrik_t* our_fab, const factory_desc_t* info, int supplier_nr, player_t* player); /** * This function is called whenever it is time for industry growth. * If there is still a pending consumer, this method will first complete another chain for it. * If not, it will decide to either build a power station (if power is needed) * or build a new consumer near the indicated position. * @returns number of factories built */ static int increase_industry_density( bool tell_me ); private: /** * Checks if the site at @p pos is suitable for construction. * * @param pos * @param size Size of the building site * @param site * @param is_factory * @param cl allowed climates */ static bool check_construction_site(koord pos, koord size, factory_desc_t::site_t site, bool is_factory, climate_bits cl); /** * Find a random site to place a factory. * * @param pos * @param radius Radius of the search circle around @p pos * @param size size of the building site * @param site * @param desc * @param ignore_climates * @param max_iterations */ static koord3d find_random_construction_site(koord pos, int radius, koord size, factory_desc_t::site_t site, const building_desc_t *desc, bool ignore_climates, uint32 max_iterations); /** * Checks if all factories in this factory tree can be rotated. * This method is called recursively on all potential suppliers. * @returns true if all factories in this tree can be rotated. */ static bool can_factory_tree_rotate( const factory_desc_t *desc ); }; #endif simutrans-124.3/src/simutrans/builder/goods_manager.cc000066400000000000000000000120351474050137200231320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../descriptor/goods_desc.h" #include "../descriptor/spezial_obj_tpl.h" #include "../simware.h" #include "../simcolor.h" #include "goods_manager.h" #include "../dataobj/translator.h" stringhashtable_tpl goods_manager_t::desc_table; vector_tpl goods_manager_t::goods; uint8 goods_manager_t::max_catg_index = 0; const goods_desc_t *goods_manager_t::passengers = NULL; const goods_desc_t *goods_manager_t::mail = NULL; const goods_desc_t *goods_manager_t::none = NULL; goods_desc_t *goods_manager_t::load_passengers = NULL; goods_desc_t *goods_manager_t::load_mail = NULL; goods_desc_t *goods_manager_t::load_none = NULL; static special_obj_tpl const special_objects[] = { { &goods_manager_t::passengers, "Passagiere" }, { &goods_manager_t::mail, "Post" }, { &goods_manager_t::none, "None" }, { NULL, NULL } }; bool goods_manager_t::successfully_loaded() { if(!::successfully_loaded(special_objects)) { return false; } // Put special items in front goods.insert_at(0,load_none); goods.insert_at(0,load_mail); goods.insert_at(0,load_passengers); if(goods.get_count()>=255) { dbg->fatal("goods_manager_t::successfully_loaded()","Too many different goods %i>255",goods.get_count()-1 ); } // assign indexes for( uint8 i=3; igoods_index = i; } // now assign unique category indexes for unique categories max_catg_index = 0; // first assign special freight (which always needs an own category) for(goods_desc_t* const i : goods) { if (i->get_catg() == 0) { i->catg_index = max_catg_index++; } } // mapping of waren_t::catg to catg_index, map[catg] = catg_index uint8 map[255] = {0}; for(goods_desc_t* const i : goods) { uint8 const catg = i->get_catg(); if( catg > 0 ) { if( map[catg] == 0 ) { // We didn't found this category yet -> just create new index. map[catg] = max_catg_index++; } i->catg_index = map[catg]; } } // init the lookup table in ware_t for( unsigned i=0; i<256; i++ ) { if(i>=goods.get_count()) { // these entries will be never looked at; // however, if then this will generate an error ware_t::index_to_desc[i] = NULL; } else { assert(goods[i]->get_index()==i); ware_t::index_to_desc[i] = goods[i]; if(goods[i]->color==255) { goods[i]->color = 16+4+((i-2)*8)%207; } } } // passenger and mail colors if(goods[0]->color==255) { goods[0]->color = COL_GREY3; } if(goods[1]->color==255) { goods[1]->color = COL_YELLOW; } // none should never be loaded to something ... // however, some place do need the dummy ... ware_t::index_to_desc[2] = NULL; DBG_MESSAGE("goods_manager_t::successfully_loaded()","total goods %i, different kind of categories %i", goods.get_count(), max_catg_index ); return true; } static bool compare_ware_desc(const goods_desc_t* a, const goods_desc_t* b) { int diff = strcmp(a->get_name(), b->get_name()); return diff < 0; } bool goods_manager_t::register_desc(goods_desc_t *desc) { desc->value = desc->base_value; ::register_desc(special_objects, desc); // avoid duplicates with same name if( const goods_desc_t *old_desc = desc_table.remove(desc->get_name()) ) { goods.remove( const_cast(old_desc) ); delete old_desc; } desc_table.put(desc->get_name(), desc); if(desc==passengers) { desc->goods_index = INDEX_PAS; load_passengers = desc; } else if(desc==mail) { desc->goods_index = INDEX_MAIL; load_mail = desc; } else if(desc != none) { goods.insert_ordered(desc,compare_ware_desc); } else { load_none = desc; desc->goods_index = INDEX_NONE; } return true; } const goods_desc_t *goods_manager_t::get_info(const char* name) { const goods_desc_t *ware = desc_table.get(name); if( ware==NULL ) { ware = desc_table.get(translator::compatibility_name(name)); } if( ware == NULL ) { // to avoid crashed with NULL pointer in skripts return good NONE dbg->warning( "goods_manager_t::get_info()", "No desc for %s", name ); ware = goods_manager_t::none; } return ware; } const goods_desc_t *goods_manager_t::get_info_catg(const uint8 catg) { if(catg>0) { for(unsigned i=0; icatg==catg) { return goods[i]; } } } dbg->warning("goods_manager_t::get_info()", "No info for good catg %d available, set to passengers", catg); return goods[0]; } const goods_desc_t *goods_manager_t::get_info_catg_index(const uint8 catg_index) { for(unsigned i=0; iget_catg_index()==catg_index) { return goods[i]; } } // return none as default return goods[2]; } // adjuster for dummies ... void goods_manager_t::set_multiplier(sint32 multiplier) { //DBG_MESSAGE("goods_manager_t::set_multiplier()","new factor %i",multiplier); for(unsigned i=0; ibase_value; goods[i]->value = (uint16)((long_base_value*multiplier)/1000l); } } simutrans-124.3/src/simutrans/builder/goods_manager.h000066400000000000000000000031241474050137200227730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_GOODS_MANAGER_H #define BUILDER_GOODS_MANAGER_H #include "../tpl/vector_tpl.h" #include "../tpl/stringhashtable_tpl.h" class goods_desc_t; /** * Factory-Class for Goods. */ class goods_manager_t { private: static stringhashtable_tpl desc_table; static vector_tpl goods; static goods_desc_t *load_passengers; static goods_desc_t *load_mail; static goods_desc_t *load_none; // number of different good classes; static uint8 max_catg_index; public: enum { INDEX_PAS = 0, INDEX_MAIL = 1, INDEX_NONE = 2 }; static const goods_desc_t *passengers; static const goods_desc_t *mail; static const goods_desc_t *none; static bool successfully_loaded(); static bool register_desc(goods_desc_t *desc); static uint8 get_max_catg_index() { return max_catg_index; } /** * Search the good 'name' information and return * its description. Return NULL when the Good is * unknown. * * @param name the non-translated good name */ static const goods_desc_t *get_info(const char* name); static const goods_desc_t *get_info(uint16 idx) { return goods[idx]; } static uint8 get_count() { return (uint8)goods.get_count(); } // good by catg static const goods_desc_t *get_info_catg(const uint8 catg); // good by catg_index static const goods_desc_t *get_info_catg_index(const uint8 catg_index); /* * allow to multiply all prices, 1000=1.0 * used for the beginner mode */ static void set_multiplier(sint32 multiplier); }; #endif simutrans-124.3/src/simutrans/builder/hausbauer.cc000066400000000000000000000773271474050137200223230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../descriptor/building_desc.h" #include "../descriptor/skin_desc.h" #include "../descriptor/spezial_obj_tpl.h" #include "../ground/boden.h" #include "../ground/wasser.h" #include "../ground/fundament.h" #include "../dataobj/ribi.h" #include "../dataobj/scenario.h" #include "../obj/leitung2.h" #include "../obj/tunnel.h" #include "../obj/zeiger.h" #include "../gui/minimap.h" #include "../gui/tool_selector.h" #include "../world/simcity.h" #include "../simdebug.h" #include "../obj/depot.h" #include "../simfab.h" #include "../simhalt.h" #include "../utils/simrandom.h" #include "../tool/simtool.h" #include "../world/simworld.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../tpl/vector_tpl.h" #include "hausbauer.h" karte_ptr_t hausbauer_t::welt; /* * The different building groups are sorted into separate lists */ static vector_tpl city_residential; ///< residential buildings (res) static vector_tpl city_commercial; ///< commercial buildings (com) static vector_tpl city_industry; ///< industrial buildings (ind) vector_tpl hausbauer_t::attractions_land; vector_tpl hausbauer_t::attractions_city; vector_tpl hausbauer_t::townhalls; vector_tpl hausbauer_t::monuments; vector_tpl hausbauer_t::unbuilt_monuments; /** * List of all registered house descriptors. * Allows searching for a desc by its name */ static stringhashtable_tpl desc_table; const building_desc_t *hausbauer_t::elevated_foundation_desc = NULL; vector_tpl hausbauer_t::station_building; vector_tpl hausbauer_t::headquarters; /// special objects directly needed by the program static special_obj_tpl const special_objects[] = { { &hausbauer_t::elevated_foundation_desc, "MonorailGround" }, { NULL, NULL } }; sint16 hausbauer_t::largest_city_building_area = 1; /** * Compares house descriptors. * Order of comparison: * -# by level * -# by name * @return true if @p a < @p b */ static bool compare_building_desc(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_level() - b->get_level(); if (diff == 0) { /* As a last resort, sort by name to avoid ambiguity */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } /** * Compares headquarters. * Order of comparison: * -# by level * -# by name * @return true if @p a < @p b */ static bool compare_hq_desc(const building_desc_t* a, const building_desc_t* b) { // the headquarters level is in the extra-variable int diff = a->get_extra() - b->get_extra(); if (diff == 0) { diff = a->get_level() - b->get_level(); } if (diff == 0) { /* As a last resort, sort by name to avoid ambiguity */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } /** * Compares stations. * Order of comparison: * -# by good category * -# by capacity * -# by level * -# by name * @return true if @p a < @p b */ static bool compare_station_desc(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_enabled() - b->get_enabled(); if( diff == 0 ) { diff = a->get_capacity() - b->get_capacity(); } if( diff == 0 ) { diff = a->get_level() - b->get_level(); } if( diff == 0 ) { /* As a last resort, sort by name to avoid ambiguity */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } bool hausbauer_t::successfully_loaded() { for(auto const& i : desc_table) { building_desc_t const* const desc = i.value; // now insert the desc into the correct list. switch(desc->get_type()) { case building_desc_t::city_res: if( desc->get_x()*desc->get_y() > 9 ) { dbg->fatal( "hausbauer_t::successfully_loaded()", "maximum city building size (3x3) but %s is (%sx%i)", desc->get_name(), desc->get_x(), desc->get_y() ); } if( desc->get_x()*desc->get_y() > largest_city_building_area ) { largest_city_building_area = desc->get_x()*desc->get_y(); } city_residential.insert_ordered(desc,compare_building_desc); break; case building_desc_t::city_ind: if( desc->get_x()*desc->get_y() > 9 ) { dbg->fatal( "hausbauer_t::successfully_loaded()", "maximum city building size (3x3) but %s is (%sx%i)", desc->get_name(), desc->get_x(), desc->get_y() ); } if( desc->get_x()*desc->get_y() > largest_city_building_area ) { largest_city_building_area = desc->get_x()*desc->get_y(); } city_industry.insert_ordered(desc,compare_building_desc); break; case building_desc_t::city_com: if( desc->get_x()*desc->get_y() > 9 ) { dbg->fatal( "hausbauer_t::successfully_loaded()", "maximum city building size (3x3) but %s is (%ix%i)", desc->get_name(), desc->get_x(), desc->get_y() ); } if( desc->get_x()*desc->get_y() > largest_city_building_area ) { largest_city_building_area = desc->get_x()*desc->get_y(); } city_commercial.insert_ordered(desc,compare_building_desc); break; case building_desc_t::monument: monuments.insert_ordered(desc,compare_building_desc); break; case building_desc_t::attraction_land: attractions_land.insert_ordered(desc,compare_building_desc); break; case building_desc_t::headquarters: headquarters.insert_ordered(desc,compare_hq_desc); break; case building_desc_t::townhall: townhalls.insert_ordered(desc,compare_building_desc); break; case building_desc_t::attraction_city: attractions_city.insert_ordered(desc,compare_building_desc); break; case building_desc_t::factory: break; case building_desc_t::dock: case building_desc_t::flat_dock: case building_desc_t::depot: case building_desc_t::generic_stop: case building_desc_t::generic_extension: station_building.insert_ordered(desc,compare_station_desc); break; case building_desc_t::others: if(strcmp(desc->get_name(),"MonorailGround")==0) { // foundation for elevated ways elevated_foundation_desc = desc; break; } /* FALLTHROUGH */ default: // obsolete object, usually such pak set will not load properly anyway (old objects should be caught before!) dbg->error("hausbauer_t::successfully_loaded()","unknown subtype %i of \"%s\" ignored",desc->get_type(), desc->get_name()); } } // now sort them according level warn_missing_objects(special_objects); return true; } bool hausbauer_t::register_desc(building_desc_t *desc) { ::register_desc(special_objects, desc); // avoid duplicates with same name const building_desc_t *old_desc = desc_table.get(desc->get_name()); if(old_desc) { // do not overlay existing factories if the new one is not a factory if (old_desc->is_factory() && !desc->is_factory()) { dbg->error( "hausbauer_t::register_desc()", "Object %s could not be registered since it would overlay an existing factory building!", desc->get_name() ); delete desc; return false; } desc_table.remove(desc->get_name()); tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); delete old_desc; } // probably needs a tool if it has a cursor const skin_desc_t *sd = desc->get_cursor(); if( sd && sd->get_image_id(1)!=IMG_EMPTY) { tool_t *tool; if( desc->get_type()==building_desc_t::depot ) { tool = new tool_build_depot_t(); } else if( desc->get_type()==building_desc_t::headquarters ) { tool = new tool_headquarter_t(); } else { // station if( desc->get_type()==building_desc_t::flat_dock || desc->get_type()==building_desc_t::dock ) { if( desc->get_size().x>1 && desc->get_size().y>1 ) { // no multile docks in both directions => do not register dbg->warning( "hausbauer_t::register_desc()", "Multitile dock %s ignored!", desc->get_name() ); return false; } } else if( desc->get_type()==building_desc_t::generic_stop && desc->get_size().x+desc->get_size().y > 2 ) { // no multile docks in both directions => do not register dbg->warning( "hausbauer_t::register_desc()", "Way stops must be single tile! %s ignored!", desc->get_name() ); return false; } tool = new tool_build_station_t(); } tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param(desc->get_name()); tool_t::general_tool.append( tool ); desc->set_builder( tool ); } else { desc->set_builder( NULL ); } desc_table.put(desc->get_name(), desc); /* Supply the tiles with a pointer back to the matching description. * This is necessary since each building consists of separate tiles, * even if it is part of the same description (building_desc_t) */ const int max_index = desc->get_all_layouts()*desc->get_size().x*desc->get_size().y; for( int i=0; i(desc->get_tile(i))->set_desc(desc); } return true; } void hausbauer_t::fill_menu(tool_selector_t* tool_selector, building_desc_t::btype btype, waytype_t wt, sint16 /*sound_ok*/) { // check if scenario forbids this uint16 toolnr = 0; switch(btype) { case building_desc_t::depot: toolnr = TOOL_BUILD_DEPOT | GENERAL_TOOL; break; case building_desc_t::dock: case building_desc_t::flat_dock: case building_desc_t::generic_stop: case building_desc_t::generic_extension: toolnr = TOOL_BUILD_STATION | GENERAL_TOOL; break; default: break; } if( toolnr > 0 && !welt->get_scenario()->is_tool_allowed(welt->get_active_player(), toolnr, wt) ) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), toolnr | GENERAL_TOOL, wt, 0); const uint16 time = welt->get_timeline_year_month(); DBG_DEBUG("hausbauer_t::fill_menu()","maximum %i",station_building.get_count()); for(building_desc_t const* const desc : station_building ) { // DBG_DEBUG("hausbauer_t::fill_menu()", "try to add %s (%p)", desc->get_name(), desc); if( desc->get_type()==btype && desc->get_builder() && (btype==building_desc_t::headquarters || desc->get_extra()==(uint16)wt) ) { if( desc->is_available(time) ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), toolnr, wt, desc->get_name())) { desc->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), toolnr | GENERAL_TOOL, wt, desc->get_name()); tool_selector->add_tool_selector( desc->get_builder() ); } } } } } void hausbauer_t::new_world() { unbuilt_monuments.clear(); for(building_desc_t const* const i : monuments) { unbuilt_monuments.append(i); } } void hausbauer_t::remove( player_t *player, gebaeude_t *gb ) { const building_tile_desc_t *tile = gb->get_tile(); if( tile->get_desc()->get_type() == building_desc_t::headquarters ) { gb->get_owner()->add_headquarter( 0, koord::invalid ); } if(tile->get_desc()->get_type()==building_desc_t::monument) { unbuilt_monuments.append_unique(tile->get_desc()); } // iterate over all places to check if there is already an open window static vector_tpl gb_tiles; gb->get_tile_list( gb_tiles ); // then remove factory fabrik_t *fab = gb->get_fabrik(); if(fab) { for(grund_t* gr : gb_tiles ) { const koord3d pos = gr->get_pos(); planquadrat_t *plan = welt->access( pos.get_2d() ); gebaeude_t* gb_part = gr->find(); gb_part->set_fab( NULL ); for (size_t i = plan->get_haltlist_count(); i-- != 0;) { halthandle_t halt = plan->get_haltlist()[i]; halt->remove_fabriken( fab ); plan->remove_from_haltlist( halt ); } } // tell players of the deletion for(uint8 i=0; iget_player(i); if (player) { player->notify_factory(player_t::notify_delete, fab); } } // remove all transformers while(1) { vector_tplconst& trans = fab->get_transformers(); if( trans.empty() ) { break; } leitung_t* sk = trans[0]; sk->mark_image_dirty( sk->get_image(), 0 ); delete sk; } // cleared transformers successfully, now remove factory. welt->rem_fab(fab); } vector_tplrecalc_boden; // delete our house only for(grund_t* gr : gb_tiles ) { const koord3d pos = gr->get_pos(); gebaeude_t* gb_part = gr->find(); gb_part->cleanup( player ); delete gb_part; // if this was a station building: delete ground if(gr->get_halt().is_bound()) { haltestelle_t::remove(player, pos); } // and maybe restore land below if(gr->get_typ()==grund_t::fundament) { const koord newk = pos.get_2d(); sint8 new_hgt; slope_t::type new_slope; welt->get_height_slope_from_grid(newk, new_hgt, new_slope); // test for ground at new height const grund_t *gr2 = welt->lookup(koord3d(newk,new_hgt)); if( (gr2==NULL || gr2==gr) && new_slope!=slope_t::flat ) { // and for ground above new sloped tile gr2 = welt->lookup(koord3d(newk, new_hgt+1)); if( gr==0 && slope_t::max_diff(new_slope) == 2 ) { gr2 = welt->lookup(koord3d(newk, new_hgt + 2)); } } if( gr2 && gr2!=gr ) { // there is another ground below or above // => do not change height, keep foundation welt->access(newk)->kartenboden_setzen( new boden_t( pos, slope_t::flat ) ); } else { boden_t* bd = new boden_t(koord3d(newk, new_hgt), new_slope); welt->access(newk)->kartenboden_setzen(bd); recalc_boden.append(bd); } } else if (wasser_t* sea = dynamic_cast(gr)) { sea->recalc_water_neighbours(); } } for(boden_t * gr : recalc_boden) { // the grid height might not be fully appropriate, so now we checlk for superflous walls const koord newk = gr->get_pos().get_2d(); sint8 new_hgt = gr->get_pos().z; const uint8 new_slope = welt->recalc_natural_slope(newk, new_hgt); if (new_hgt < welt->get_water_hgt(newk) || (new_hgt == welt->get_water_hgt(newk) && new_slope == slope_t::flat)) { wasser_t* sea = new wasser_t(koord3d(newk, new_hgt)); welt->access(newk)->kartenboden_setzen(sea); welt->calc_climate(newk, true); sea->recalc_water_neighbours(); } else { boden_t* bd = new boden_t(koord3d(newk, new_hgt), new_slope); welt->access(newk)->kartenboden_setzen(bd); // climate is stored in planquadrat, and hence automatically preserved } // there might be walls from foundations left => thus some tiles may need to be redrawn if (grund_t* gr = welt->lookup_kartenboden(newk + koord::east)) { gr->calc_image(); } if (grund_t* gr = welt->lookup_kartenboden(newk + koord::south)) { gr->calc_image(); } welt->set_grid_hgt_nocheck(newk, new_hgt + corner_nw(new_slope)); } } gebaeude_t* hausbauer_t::build(player_t* player, koord pos, int org_layout, const building_desc_t* desc, void* param) { gebaeude_t* first_building = NULL; koord k; koord dim; uint8 layout = desc->adjust_layout(org_layout); dim = desc->get_size(org_layout); bool needs_ground_recalc = false; sint8 base_h = -128; if( dim.y+dim.x > 2 ) { for( k.y = 0; k.y < dim.y; k.y++ ) { for( k.x = 0; k.x < dim.x; k.x++ ) { if( grund_t* gr = welt->lookup_kartenboden( pos + k ) ) { base_h = max( base_h, gr->get_hoehe() ); if( gr->get_hoehe()!=base_h && welt->lookup( koord3d( pos+k, base_h ) ) ) { // there is already a ground here! dbg->error("hausbauer_t::build","Will create new ground at (%s) where there is ground above!", pos.get_str() ); } } else { return NULL; } } } } else { // single tile grund_t* gr = welt->lookup_kartenboden( pos + k ); base_h = gr->get_hoehe() + +slope_t::max_diff( gr->get_grund_hang() ); } // now we must raise all grounds to base_h during construction for(k.y = 0; k.y < dim.y; k.y ++) { for(k.x = 0; k.x < dim.x; k.x ++) { //DBG_DEBUG("hausbauer_t::build()","get_tile() at %i,%i",k.x,k.y); const building_tile_desc_t *tile = desc->get_tile(layout, k.x, k.y); // skip empty tiles if (tile == NULL || ( !(desc->get_type() == building_desc_t::dock || desc->get_type() == building_desc_t::flat_dock) && tile->get_background(0, 0, 0) == IMG_EMPTY && tile->get_foreground(0, 0) == IMG_EMPTY )) { // may have a rotation that is not recoverable DBG_MESSAGE("hausbauer_t::build()","get_tile() empty at %i,%i",k.x,k.y); continue; } gebaeude_t *gb = new gebaeude_t(koord3d(pos + k,base_h), player, tile); if (first_building == NULL) { first_building = gb; } if(desc->is_factory()) { gb->set_fab((fabrik_t *)param); } // try to fake old building else if(welt->get_ticks() < 2) { // after staring a new map, build fake old buildings gb->add_alter(10000); } grund_t *gr = welt->lookup_kartenboden(pos + k); if(gr->is_water()) { gr->obj_add(gb); } else if( desc->get_type() == building_desc_t::dock || desc->get_type() == building_desc_t::flat_dock ) { // it's a dock! gr->obj_add(gb); } else { // mostly remove everything vector_tpl keptobjs; if(!gr->hat_wege()) { // save certain object types for( uint8 i = 0; i < gr->obj_count(); i++ ) { obj_t *const obj = gr->obj_bei(i); obj_t::typ const objtype = obj->get_typ(); if( objtype == obj_t::leitung || objtype == obj_t::pillar ) { keptobjs.append(obj); } } for( size_t i = 0; i < keptobjs.get_count(); i++ ) { gr->obj_remove(keptobjs[i]); } // delete everything except vehicles gr->obj_loesche_alle(player); } // build new foundation needs_ground_recalc |= gr->get_grund_hang()!=slope_t::flat || gr->get_hoehe()!=base_h; grund_t *gr2 = new fundament_t( koord3d(pos+k,base_h), slope_t::flat); welt->access(pos+k)->boden_ersetzen(gr, gr2); gr = gr2; //DBG_DEBUG("hausbauer_t::build()","ground count now %i",gr->obj_count()); gr->obj_add( gb ); // restore saved objects for( size_t i = 0; i < keptobjs.get_count(); i++ ) { gr->obj_add(keptobjs[i]); } if(needs_ground_recalc && welt->is_within_limits(pos+k+koord(1,1)) && (k.y+1==dim.y || k.x+1==dim.x)) { welt->lookup_kartenboden(pos+k+koord(1,0))->calc_image(); welt->lookup_kartenboden(pos+k+koord(0,1))->calc_image(); welt->lookup_kartenboden(pos+k+koord(1,1))->calc_image(); } } gb->set_pos( gr->get_pos() ); if(desc->is_attraction()) { welt->add_attraction( gb ); } if (!desc->is_city_building()) { if(station_building.is_contained(desc)) { (*static_cast(param))->add_grund(gr); } if( desc->get_type() == building_desc_t::dock || desc->get_type() == building_desc_t::flat_dock ) { // its a dock! gb->set_yoff(0); if (wasser_t* sea = dynamic_cast(gr)) { sea->recalc_water_neighbours(); } } } gr->calc_image(); minimap_t::get_instance()->calc_map_pixel(gr->get_pos().get_2d()); } } // remove only once ... if(desc->get_type()==building_desc_t::monument) { monument_erected(desc); } return first_building; } gebaeude_t *hausbauer_t::build_station_extension_depot(player_t *player, koord3d pos, int built_layout, const building_desc_t *desc, void *param) { uint8 corner_layout = 6; // assume single building (for more than 4 layouts) // adjust layout of neighbouring building if(desc->is_transport_building() && desc->get_all_layouts()>1) { int layout = built_layout & 9; // detect if we are connected at far (north/west) end sint8 offset = welt->lookup( pos )->get_weg_yoff()/TILE_HEIGHT_STEP; koord3d checkpos = pos+koord3d( (layout & 1 ? koord::east : koord::south), offset); grund_t * gr = welt->lookup( checkpos ); if(!gr) { // check whether bridge end tile grund_t * gr_tmp = welt->lookup( pos+koord3d( (layout & 1 ? koord::east : koord::south),offset - 1) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) { gr = gr_tmp; } else { gr_tmp = welt->lookup( pos+koord3d( (layout & 1 ? koord::east : koord::south),offset - 2) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 2) { gr = gr_tmp; } } } if(gr) { gebaeude_t* gb = gr->find(); if(gb==NULL) { // no building on same level, check other levels const planquadrat_t *pl = welt->access(checkpos.get_2d()); if (pl) { for( uint8 i=0; iget_boden_count(); i++ ) { gr = pl->get_boden_bei(i); if(gr->is_halt() && gr->get_halt().is_bound() ) { break; } } } gb = gr->find(); } if( gb && gb->get_tile()->get_desc()->is_transport_building() ) { corner_layout &= ~2; // clear near bit if(gb->get_tile()->get_desc()->get_all_layouts()>4) { koord xy = gb->get_tile()->get_offset(); uint8 layoutbase = gb->get_tile()->get_layout(); if((layoutbase & 1) == (layout & 1)) { layoutbase &= 0xb; // clear near bit on neighbour gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false ); } } } } // detect if near (south/east) end gr = welt->lookup( pos+koord3d( (layout & 1 ? koord::west : koord::north), offset) ); if(!gr) { // check whether bridge end tile grund_t * gr_tmp = welt->lookup( pos+koord3d( (layout & 1 ? koord::west : koord::north),offset - 1) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) { gr = gr_tmp; } else { gr_tmp = welt->lookup( pos+koord3d( (layout & 1 ? koord::west : koord::north),offset - 2) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 2) { gr = gr_tmp; } } } if(gr) { gebaeude_t* gb = gr->find(); if(gb && gb->get_tile()->get_desc()->is_transport_building()) { corner_layout &= ~4; // clear far bit if(gb->get_tile()->get_desc()->get_all_layouts()>4) { koord xy = gb->get_tile()->get_offset(); uint8 layoutbase = gb->get_tile()->get_layout(); if((layoutbase & 1) == (layout & 1)) { layoutbase &= 0xd; // clear far bit on neighbour gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false ); } } } } } // adjust layouts of the new building if(desc->get_all_layouts()>4) { built_layout = (corner_layout | (built_layout&9) ) % desc->get_all_layouts(); } const building_tile_desc_t *tile = desc->get_tile(built_layout, 0, 0); gebaeude_t *gb; if( desc->get_type() == building_desc_t::depot ) { switch( desc->get_extra() ) { case track_wt: gb = new bahndepot_t(pos, player, tile); break; case tram_wt: gb = new tramdepot_t(pos, player, tile); break; case monorail_wt: gb = new monoraildepot_t(pos, player, tile); break; case maglev_wt: gb = new maglevdepot_t(pos, player, tile); break; case narrowgauge_wt: gb = new narrowgaugedepot_t(pos, player, tile); break; case road_wt: gb = new strassendepot_t(pos, player, tile); break; case water_wt: gb = new schiffdepot_t(pos, player, tile); break; case air_wt: gb = new airdepot_t(pos, player, tile); break; default: dbg->fatal("hausbauer_t::build_station_extension_depot()","waytpe %i has no depots!", desc->get_extra() ); } } else { gb = new gebaeude_t(pos, player, tile); } //DBG_MESSAGE("hausbauer_t::build_station_extension_depot()","building stop pri=%i",pri); // remove pointer grund_t *gr = welt->lookup(pos); zeiger_t* zeiger = gr->find(); if( zeiger ) { gr->obj_remove(zeiger); zeiger->set_flag(obj_t::not_on_map); } gr->obj_add(gb); if( station_building.is_contained(desc) && desc->get_type()!=building_desc_t::depot ) { // is a station/bus stop (*static_cast(param))->add_grund(gr); gr->calc_image(); } else { gb->calc_image(); } if(desc->is_attraction()) { welt->add_attraction( gb ); } // update minimap minimap_t::get_instance()->calc_map_pixel(gb->get_pos().get_2d()); return gb; } const building_tile_desc_t *hausbauer_t::find_tile(const char *name, int org_idx) { if (org_idx < 0) { return NULL; } const building_desc_t *desc = desc_table.get(name); if(!desc) { // DBG_MESSAGE("hausbauer_t::find_tile()","\"%s\" not in hashtable",name); return NULL; } const int size = desc->get_y()*desc->get_x(); int idx = org_idx; if( idx >= desc->get_all_layouts()*size ) { idx %= desc->get_all_layouts()*size; DBG_MESSAGE("gebaeude_t::rdwr()","%s using tile %i instead of %i",name,idx,org_idx); } return desc->get_tile(idx); } const building_desc_t* hausbauer_t::get_desc(const char *name) { return desc_table.get(name); } const building_desc_t* hausbauer_t::get_random_station(const building_desc_t::btype type, const waytype_t wt, const uint16 time, const uint8 enables) { weighted_vector_tpl stops; if( wt < 0 ) { return NULL; } for(building_desc_t const* const desc : station_building) { if( desc->get_type()==type && desc->get_extra()==(uint32)wt && (enables==0 || (desc->get_enabled()&enables)!=0) ) { // skip underground stations if( !desc->can_be_built_aboveground() ) { continue; } // ok, now check timeline if( desc->is_available(time) ) { stops.append(desc,max(1,16-desc->get_level()*desc->get_x()*desc->get_y())); } } } return stops.empty() ? 0 : pick_any_weighted(stops); } const building_desc_t* hausbauer_t::get_special(uint32 bev, building_desc_t::btype type, uint16 time, bool ignore_retire, climate cl) { weighted_vector_tpl auswahl(16); vector_tpl *list = NULL; switch(type) { case building_desc_t::townhall: list = &townhalls; break; case building_desc_t::attraction_city: list = &attractions_city; break; default: return NULL; } for(building_desc_t const* const desc : *list) { // extra data contains number of inhabitants for building if( desc->get_extra()==bev ) { if( cl==MAX_CLIMATES || desc->is_allowed_climate(cl) ) { // ok, now check timeline if( time==0 || (desc->get_intro_year_month()<=time && (ignore_retire || desc->get_retire_year_month() > time) ) ) { auswahl.append(desc, desc->get_distribution_weight()); } } } } if (auswahl.empty()) { return 0; } else if(auswahl.get_count()==1) { return auswahl.front(); } // now there is something to choose return pick_any_weighted(auswahl); } /** * Tries to find a matching house desc from @p list. * This method will never return NULL if there is at least one valid entry in the list. * @param start_level the minimum level of the house/station * @param cl allowed climates */ static const building_desc_t* get_city_building_from_list(const vector_tpl& list, int start_level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ) { weighted_vector_tpl selections(16); int level = start_level; // DBG_MESSAGE("hausbauer_t::get_aus_liste()","target level %i", level ); const building_desc_t *desc_at_least=NULL; for(building_desc_t const* const desc : list) { const int thislevel = desc->get_level(); if( thislevel > level ) { if (selections.empty()) { // Nothing of the correct level. Continue with search on a higher level. level = thislevel; } else { // We already found something of the correct or an higher level; stop break; } } if( (desc->is_allowed_climate(cl) || cl==MAX_CLIMATES ) && desc->get_distribution_weight() > 0 && desc->is_available(time) && // size check ( (desc->get_x() <= maxsize.x && desc->get_y() <= maxsize.y && desc->get_x() >= minsize.x && desc->get_y() >= minsize.y ) || (desc->get_x() <= maxsize.y && desc->get_y() <= maxsize.x && desc->get_x() >= minsize.y && desc->get_y() >= minsize.x ) ) ) { desc_at_least = desc; if( thislevel == level ) { // DBG_MESSAGE("hausbauer_t::get_city_building_from_list()","appended %s at %i", desc->get_name(), thislevel ); /* Level, time period, and climate are all OK. * Now modify the chance rating by a factor based on the clusters. */ // FIXME: the factor should be configurable by the pakset/ int chance = desc->get_distribution_weight(); if( clusters ) { uint32 my_clusters = desc->get_clusters(); if( my_clusters & clusters ) { chance *= stadt_t::get_cluster_factor(); } else { chance /= stadt_t::get_cluster_factor(); } } selections.append(desc, chance); } } } if(selections.get_sum_weight()==0) { // this is some level below, but at least it is something return desc_at_least; } if(selections.get_count()==1) { return selections.front(); } // now there is something to choose return pick_any_weighted(selections); } const building_desc_t* hausbauer_t::get_commercial(int level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ) { return get_city_building_from_list(city_commercial, level, time, cl, clusters, minsize, maxsize ); } const building_desc_t* hausbauer_t::get_industrial(int level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ) { return get_city_building_from_list(city_industry, level, time, cl, clusters, minsize, maxsize ); } const building_desc_t* hausbauer_t::get_residential(int level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ) { return get_city_building_from_list(city_residential, level, time, cl, clusters, minsize, maxsize ); } const building_desc_t* hausbauer_t::get_headquarters(int level, uint16 time) { if( level<0 ) { return NULL; } for(building_desc_t const* const desc : hausbauer_t::headquarters) { if( desc->get_extra()==(uint32)level && desc->is_available(time) ) { return desc; } } return NULL; } const building_desc_t *hausbauer_t::get_random_desc(vector_tpl &list, uint16 time, bool ignore_retire, climate cl) { if (!list.empty()) { // previously just returned a random object; however, now we look at the chance entry weighted_vector_tpl auswahl(16); for(building_desc_t const* const desc : list) { if((cl==MAX_CLIMATES || desc->is_allowed_climate(cl)) && desc->get_distribution_weight()>0 && (time==0 || (desc->get_intro_year_month()<=time && (ignore_retire || desc->get_retire_year_month()>time) ) ) ) { // DBG_MESSAGE("hausbauer_t::get_random_desc()","appended %s at %i", desc->get_name(), thislevel ); auswahl.append(desc, desc->get_distribution_weight()); } } // now look what we have got ... if(auswahl.get_sum_weight()==0) { return NULL; } if(auswahl.get_count()==1) { return auswahl.front(); } // now there is something to choose return pick_any_weighted(auswahl); } return NULL; } const vector_tpl* hausbauer_t::get_list(const building_desc_t::btype typ) { switch (typ) { case building_desc_t::monument: return &unbuilt_monuments; case building_desc_t::attraction_land: return &attractions_land; case building_desc_t::headquarters: return &headquarters; case building_desc_t::townhall: return &townhalls; case building_desc_t::attraction_city: return &attractions_city; case building_desc_t::dock: case building_desc_t::flat_dock: case building_desc_t::depot: case building_desc_t::generic_stop: case building_desc_t::generic_extension: return &station_building; default: return NULL; } } const vector_tpl* hausbauer_t::get_citybuilding_list(const building_desc_t::btype typ) { switch (typ) { case building_desc_t::city_res: return &city_residential; case building_desc_t::city_com: return &city_commercial; case building_desc_t::city_ind: return &city_industry; default: return NULL; } } simutrans-124.3/src/simutrans/builder/hausbauer.h000066400000000000000000000152311474050137200221470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_HAUSBAUER_H #define BUILDER_HAUSBAUER_H #include "../descriptor/building_desc.h" #include "../dataobj/koord3d.h" #include "../simtypes.h" #include "../tpl/vector_tpl.h" class gebaeude_t; class karte_ptr_t; class player_t; class tool_selector_t; /** * This class deals with building single- and multi-tile buildings. It knows the descriptions * of (nearly) all buildings as regards type, height, size, images and animations. * To be able to build a new house the house description must be registered by register_desc(). * * To ensure all monuments are only present once per map, there is a list * which monuments have been built and which not. * There's no need to construct an instance since everything is static here. */ class hausbauer_t { private: static sint16 largest_city_building_area; static vector_tpl attractions_land; ///< Sights outside of cities static vector_tpl attractions_city; ///< Sights within cities static vector_tpl townhalls; ///< Town halls static vector_tpl monuments; ///< All monuments static vector_tpl unbuilt_monuments; ///< All unbuilt monuments static vector_tpl headquarters; ///< Company headquarters static vector_tpl station_building; ///< All station buildings /// @returns a random entry from @p list static const building_desc_t* get_random_desc(vector_tpl& list, uint16 time, bool ignore_retire, climate cl); /// our game world static karte_ptr_t welt; public: static sint16 get_largest_city_building_area() { return largest_city_building_area; } /// description for elevated monorail (mandatory description) static const building_desc_t* elevated_foundation_desc; /** * Finds a station building enabling pax/mail/goods for the AI. * If @p time == 0 the timeline will be ignored. * * @param utype * @param wt * @param time * @param enables station enabled flags (see haltestelle_t::station_flags) * @returns a random station that can be built above ground. */ static const building_desc_t* get_random_station(const building_desc_t::btype utype, const waytype_t wt, const uint16 time, const uint8 enables); /// Finds and returns the tile at position @p idx static const building_tile_desc_t* find_tile(const char* name, int idx); /// @returns the house description with name @p name static const building_desc_t* get_desc(const char *name); /** * Registers the house description so the house can be built in-game. * @returns true */ static bool register_desc(building_desc_t *desc); /// Sorts all house descriptions into their respective lists. static bool successfully_loaded(); /** * Fills menu with icons of buildings of a given waytype. * This is needed for station extensions and headquarters. */ static void fill_menu(tool_selector_t* tool_selector, building_desc_t::btype, waytype_t wt, sint16 sound_ok); /// @returns a random commercial building matching the requirements. static const building_desc_t* get_commercial(int level, uint16 time, climate c, uint32 clusters, koord minsize, koord maxsize ); /// @returns a random industrial building matching the requirements. static const building_desc_t* get_industrial(int level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ); /// @returns a random residential building matching the requirements. static const building_desc_t* get_residential(int level, uint16 time, climate cl, uint32 clusters, koord minsize, koord maxsize ); /// @returns headquarters with level @p level (takes the first matching one) static const building_desc_t* get_headquarters(int level, uint16 time); /// @returns a random tourist attraction matching the requirements. static const building_desc_t* get_random_attraction(uint16 time, bool ignore_retire, climate cl) { return get_random_desc(attractions_land, time, ignore_retire, cl); } /// @returns a random unbuilt monument. static const building_desc_t* get_random_monument(uint16 time = 0) { return get_random_desc(unbuilt_monuments, time, false, MAX_CLIMATES); } /** * Tells the house builder a new map is being loaded or generated. * In this case the list of unbuilt monuments must be refilled * to ensure each monument is only present once per map. */ static void new_world(); /// @returns true if this monument has not yet been built. static bool is_valid_monument(const building_desc_t* desc) { return unbuilt_monuments.is_contained(desc); } /// Tells the house builder a monument has been built. static void monument_erected(const building_desc_t* desc) { unbuilt_monuments.remove(desc); } /// Called for a city attraction or a town hall with a certain number of inhabitants (bev). static const building_desc_t* get_special(uint32 bev, building_desc_t::btype utype, uint16 time, bool ignore_retire, climate cl); /** * Removes an arbitrary building. * It will also take care of factories and foundations. * * @param player the player wanting to remove the building. * @param gb */ static void remove(player_t *player, gebaeude_t *gb); /** * Main function to build all non-traffic buildings, including factories. * Building size can be larger than 1x1. * Also the underlying ground will be changed to foundation. * * @param player * @param pos * @param layout * @param desc * @param param if building a factory, pointer to the factory, * if building a stop, pointer to the halt handle. * Can only build houses on map ground! * * @return The first built part of the building. Usually at @p pos, if this * building tile is not empty. */ static gebaeude_t* build(player_t* player, koord pos, int layout, const building_desc_t* desc, void* param = NULL); /** * Build all kind of stops and depots. The building size must be 1x1. * Stations with layout>4 may change the layout of neighbouring buildings. (->end of rail platforms) * * @param player * @param pos * @param layout * @param desc * @param param if building a stop, pointer to the halt handle */ static gebaeude_t* build_station_extension_depot(player_t* player, koord3d pos, int layout, const building_desc_t* desc, void* param = NULL); /// @returns house list of type @p typ static const vector_tpl *get_list(building_desc_t::btype typ); /// @returns city building list of type @p typ (res/com/ind) static const vector_tpl *get_citybuilding_list(building_desc_t::btype typ); }; #endif simutrans-124.3/src/simutrans/builder/tree_builder.cc000066400000000000000000000253401474050137200227750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "tree_builder.h" #include "../dataobj/settings.h" #include "../obj/baum.h" #include "../obj/groundobj.h" #include "../world/simworld.h" #include "../utils/simrandom.h" #include static karte_ptr_t welt; static const uint8 tree_age_index[(baum_t::AGE_LIMIT >> 6) + 1] = { 0,1,2,3,3,3,3,3,3,4,4,4 }; vector_tpl tree_builder_t::tree_list(0); weighted_vector_tpl tree_builder_t::tree_list_per_climate[MAX_CLIMATES]; stringhashtable_tpl tree_builder_t::desc_table; vector_tpl tree_builder_t::loaded_tree_names; /// Quick lookup of an image, assuring always five seasons and five ages. /// Missing images just have identical entries. /// Seasons are: 0=summer, 1=autumn, 2=winter, 3=spring, 4=snow /// Snow image is used if tree is above snow line, or for arctic climate static image_id tree_id_to_image[256][5*5]; image_id tree_builder_t::get_tree_image(uint8 tree_id, uint32 age, uint8 season) { const uint8 tree_age_idx = tree_age_index[min(age>>6, 11u)]; assert(tree_age_idx < 5); return tree_id_to_image[ tree_id ][ season*5 + tree_age_idx ]; } const tree_desc_t *tree_builder_t::find_tree(const char *tree_name) { return tree_list.empty() ? NULL : desc_table.get(tree_name); } uint8 tree_builder_t::plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count) { grund_t *gr = welt->lookup_kartenboden(pos); if( gr ) { if( has_trees_for_climate( welt->get_climate(pos) ) && gr->ist_natur() && gr->obj_count() < maximum_count ) { obj_t *obj = gr->obj_bei(0); if(obj) { switch(obj->get_typ()) { case obj_t::cloud: case obj_t::air_vehicle: case obj_t::baum: case obj_t::leitung: case obj_t::label: case obj_t::zeiger: // ok to build here break; case obj_t::groundobj: if(((groundobj_t *)obj)->get_desc()->can_build_trees_here()) { break; } /* FALLTHROUGH */ // leave these (and all other empty) default: return 0; } } const uint8 count_planted = min( maximum_count - gr->obj_count(), count); for (uint8 i=0; iobj_add( new baum_t(gr->get_pos()) ); //plants the tree(s) } return count_planted; } } return 0; } bool tree_builder_t::plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age) { // none there if( desc_table.empty() ) { return false; } grund_t *gr = welt->lookup_kartenboden(pos); if( gr ) { if( gr->ist_natur() && gr->obj_count() < welt->get_settings().get_max_no_of_trees_on_square() && (!check_climate || desc->is_allowed_climate( welt->get_climate(pos) )) ) { if( gr->obj_count() > 0 ) { switch(gr->obj_bei(0)->get_typ()) { case obj_t::cloud: case obj_t::air_vehicle: case obj_t::baum: case obj_t::leitung: case obj_t::label: case obj_t::zeiger: // ok to built here break; case obj_t::groundobj: if(((groundobj_t *)(gr->obj_bei(0)))->get_desc()->can_build_trees_here()) { break; } /* FALLTHROUGH */ // leave these (and all other empty) default: return false; } } baum_t *b = new baum_t(gr->get_pos(), desc); //plants the tree if( random_age ) { b->geburt = welt->get_current_month() - simrand(baum_t::AGE_LIMIT-1); b->calc_off( welt->lookup( b->get_pos() )->get_grund_hang() ); } gr->obj_add( b ); return true; //tree was planted - currently unused value is not checked } } return false; } uint32 tree_builder_t::create_forest(koord new_center, koord wh, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom) { // none there if( desc_table.empty() ) { return 0; } const sint16 xpos_f = new_center.x; const sint16 ypos_f = new_center.y; uint32 number_of_new_trees = 0; for( sint16 j = 0; j < wh.x; j++) { for( sint16 i = 0; i < wh.y; i++) { const sint32 x_tree_pos = (j-(wh.x>>1)); const sint32 y_tree_pos = (i-(wh.y>>1)); if( xtop > (xpos_f + x_tree_pos) || (xpos_f + x_tree_pos) >= xbottom ) { continue; } if( ytop > (ypos_f + y_tree_pos) || (ypos_f + y_tree_pos) >= ybottom ) { continue; } const uint64 distance = 1 + sqrt_i64( ((uint64)x_tree_pos*x_tree_pos*(wh.y*wh.y) + (uint64)y_tree_pos*y_tree_pos*(wh.x*wh.x))); const uint32 tree_probability = (uint32)( ( 8 * (uint32)((wh.x*wh.x)+(wh.y*wh.y)) ) / distance ); if (tree_probability < 38) { continue; } uint8 number_to_plant = 0; uint8 const max_trees_here = min(welt->get_settings().get_max_no_of_trees_on_square(), (tree_probability - 38 + 1) / 2); for (uint8 c2 = 0 ; c2get_settings().get_max_no_of_trees_on_square(); number_of_new_trees += plant_tree_on_coordinate(tree_pos, max_trees_per_square, number_to_plant); } } return number_of_new_trees; } void tree_builder_t::fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ) { // none there if( desc_table.empty() ) { return; } DBG_MESSAGE("tree_builder_t::fill_trees", "distributing single trees"); koord pos; for( pos.y=ytop; pos.ylookup_kartenboden(pos); if(gr->obj_count() == 0 && gr->get_typ() == grund_t::boden) { // plant spare trees, (those with low preffered density) or in an entirely tree climate const uint16 cl = 1 << welt->get_climate(pos); const settings_t &s = welt->get_settings(); if ((cl & s.get_no_tree_climates()) == 0 && ((cl & s.get_tree_climates()) != 0 || simrand(s.get_forest_inverse_spare_tree_density() * dichte) < 100)) { plant_tree_on_coordinate(pos, 1, 1); } } } } } static bool compare_tree_desc(const tree_desc_t *a, const tree_desc_t *b) { // same level - we do an artificial but unique sorting by (untranslated) name return strcmp(a->get_name(), b->get_name())<0; } bool tree_builder_t::successfully_loaded() { if( desc_table.empty() ) { DBG_MESSAGE("tree_builder_t::successfully_loaded", "No trees found - feature disabled"); } for(auto const& i : desc_table) { tree_list.insert_ordered(i.value, compare_tree_desc); if( tree_list.get_count()==255 ) { dbg->error( "tree_builder_t::successfully_loaded", "Maximum tree count exceeded! (%u > 255)", desc_table.get_count() ); break; } } tree_list.append( NULL ); // clear cache memset( tree_id_to_image, -1, sizeof(tree_id_to_image) ); // now register all trees for all fitting climates for( uint32 typ=0; typis_allowed_climate((climate)j) ) { assert(typ <= 255); tree_list_per_climate[j].append((uint8)typ, tree_list[typ]->get_distribution_weight()); } } // create cache images for( uint8 season = 0; season < 5; season++ ) { uint8 use_season = 0; const sint16 seasons = tree_list[typ]->get_seasons(); if( seasons > 1 ) { use_season = season; // three possibilities if( seasons < 4 ) { // only summer and winter => season 4 with winter image use_season = (season == 4); } else if( seasons == 4 ) { // all there, but the snowy special image missing if( season == 4 ) { // take spring image (gave best results with pak64, pak.german) ////// but season 2 is winter???? use_season = 2; } } } for( uint8 age_idx = 0; age_idx < 5; age_idx++ ) { tree_id_to_image[typ][season * 5 + age_idx] = tree_list[typ]->get_image_id( use_season, age_idx ); } } } return true; } bool tree_builder_t::register_desc(const tree_desc_t *desc) { // avoid duplicates with same name if(const tree_desc_t *old = desc_table.remove(desc->get_name()) ) { delete old; } desc_table.put(desc->get_name(), desc ); return true; } void tree_builder_t::distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom) { // now we can proceed to tree planting routine itself // best forests results are produced if forest size is tied to map size - // but there is some nonlinearity to ensure good forests on small maps settings_t const& s = welt->get_settings(); sint32 const x = welt->get_size().x; sint32 const y = welt->get_size().y; unsigned const t_forest_size = (uint32)pow(((double)x * (double)y), 0.25) * s.get_forest_base_size() / 11 + (x + y) / (2 * s.get_forest_map_size_divisor()); uint32 const c_forest_count = (uint32)pow(((double)x * (double)y), 0.5) / s.get_forest_count_divisor(); DBG_MESSAGE("tree_builder_t::distribute_trees", "Creating %i forests", c_forest_count); for (uint32 c1 = 0; c1 < c_forest_count ; c1++) { // to have same execution order for simrand koord const start = koord::koord_random(x, y); koord const size = koord(t_forest_size,t_forest_size) + koord::koord_random(t_forest_size, t_forest_size); create_forest( start, size, xtop, ytop, xbottom, ybottom ); } fill_trees( dichte, xtop, ytop, xbottom, ybottom ); } const tree_desc_t *tree_builder_t::random_tree_for_climate(climate cl) { const uint16 b = random_tree_id_for_climate(cl); return b!=0xFFFF ? tree_list[b] : NULL; } uint16 tree_builder_t::random_tree_id_for_climate(climate cl) { // now weight their distribution weighted_vector_tpl const &t = tree_list_per_climate[cl]; return t.empty() ? 0xFFFF : pick_any_weighted(t); } bool tree_builder_t::spawn_tree_near(const baum_t *tree, int radius) { // to have same execution order for simrand const sint16 sx = simrand(2*radius + 1)-radius; const sint16 sy = simrand(2*radius + 1)-radius; const koord k = tree->get_pos().get_2d() + koord(sx,sy); return plant_tree_on_coordinate(k, tree->get_desc(), true, false); } void tree_builder_t::rdwr_tree_ids(loadsave_t *file) { xml_tag_t tag(file, "tree_ids"); uint8 num_trees = tree_list.get_count()-1; file->rdwr_byte(num_trees); if (file->is_loading()) { loaded_tree_names.clear(); plainstring str; for (uint8 i = 0; i < num_trees; ++i) { file->rdwr_str(str); loaded_tree_names.append(str); } } else { for (uint8 i = 0; i < num_trees; ++i) { plainstring str = tree_list[i]->get_name(); file->rdwr_str(str); } } } const char *tree_builder_t::get_loaded_desc_name(uint8 loaded_id) { return (loaded_id < loaded_tree_names.get_count()) ? loaded_tree_names[loaded_id].c_str() : NULL; } simutrans-124.3/src/simutrans/builder/tree_builder.h000066400000000000000000000070111474050137200226320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_TREE_BUILDER_H #define BUILDER_TREE_BUILDER_H #include "../tpl/stringhashtable_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../tpl/vector_tpl.h" #include "../utils/plainstring.h" #include "../dataobj/koord.h" #include "../display/simimg.h" class tree_desc_t; class baum_t; /// Handles desc management and distribution of trees. class tree_builder_t { private: static stringhashtable_tpl desc_table; ///< Mapping desc_name -> desc static vector_tpl tree_list; ///< Mapping tree_id -> desc static weighted_vector_tpl tree_list_per_climate[MAX_CLIMATES]; ///< index vector into tree_list, accessible per climate static vector_tpl loaded_tree_names; ///< Maps loaded_id -> loaded_desc_name public: static void rdwr_tree_ids(loadsave_t *file); /// Tree IDs never change after loading paks, so when loading a save /// which was saved with a different set of tree paks the tree ID from the save /// has to be translated to the one used in the current game. /// This is done by mapping /// loaded_id -> loaded_desc_name -> real_desc_name -> real_id /// This function does the first mapping based on the data stored in the save file. /// Returns NULL if no desc name could be found. /// @sa boden_t::boden_t static const char *get_loaded_desc_name(uint8 loaded_id); static const tree_desc_t *get_desc_by_name(const char * tree_name) { return desc_table.get(tree_name); } static const tree_desc_t *get_desc_by_id(uint8 tree_id) { return tree_id < get_num_trees() ? tree_list[tree_id] : NULL; } static uint8 get_id_by_desc(const tree_desc_t *desc) { return tree_list.index_of(desc); } static image_id get_tree_image(uint8 idx, uint32 age, uint8 season); static bool has_trees() { return get_num_trees() > 0; } static bool has_trees_for_climate(climate cl) { return !tree_list_per_climate[cl].empty(); } static sint32 get_num_trees() { return tree_list.get_count()-1; } /// Fill rectangular region with trees. static void fill_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom); static bool register_desc(const tree_desc_t *desc); static bool successfully_loaded(); /// @returns list of all registered descriptors static const vector_tpl &get_all_desc() { return tree_list; } /// Plant a new tree in a (2n+1) * (2n+1) square around @p tree. static bool spawn_tree_near(const baum_t *tree, int radius = 3); static uint32 create_forest(koord center, koord size, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom); public: /// distributes trees in a rectangular region of the map static void distribute_trees(int dichte, sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom); /// tree planting function - it takes care of checking suitability of area static bool plant_tree_on_coordinate(koord pos, const tree_desc_t *desc, const bool check_climate, const bool random_age); /// tree planting function - it takes care of checking suitability of area static uint8 plant_tree_on_coordinate(koord pos, const uint8 maximum_count, const uint8 count); static const tree_desc_t *find_tree( const char *tree_name ); static const tree_desc_t *random_tree_for_climate(climate cl); /// also checks for distribution values /// @returns the tree_id, or 0xFFFF if no trees exist for the requested climate. static uint16 random_tree_id_for_climate(climate cl); }; #endif simutrans-124.3/src/simutrans/builder/tunnelbauer.cc000066400000000000000000000620771474050137200226640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "tunnelbauer.h" #include "../gui/minimap.h" #include "../world/simworld.h" #include "../player/simplay.h" #include "../tool/simtool.h" #include "../descriptor/tunnel_desc.h" #include "../ground/tunnelboden.h" #include "../dataobj/scenario.h" #include "../dataobj/environment.h" #include "../dataobj/marker.h" #include "../obj/tunnel.h" #include "../obj/leitung2.h" #include "../obj/signal.h" #include "../gui/messagebox.h" #include "../gui/tool_selector.h" #include "wegbauer.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "../world/terraformer.h" karte_ptr_t tunnel_builder_t::welt; static stringhashtable_tpl tunnel_by_name; void tunnel_builder_t::register_desc(tunnel_desc_t *desc) { // avoid duplicates with same name if( const tunnel_desc_t *old_desc = tunnel_by_name.remove(desc->get_name()) ) { tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); // we cannot delete old_desc, since then xref-resolving will crash } // add the tool tool_build_tunnel_t *tool = new tool_build_tunnel_t(); tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param( desc->get_name() ); tool_t::general_tool.append( tool ); desc->set_builder( tool ); tunnel_by_name.put(desc->get_name(), desc); } const tunnel_desc_t *tunnel_builder_t::get_desc(const char *name) { return (name ? tunnel_by_name.get(name) : NULL); } /** * Find a matching tunnel */ const tunnel_desc_t *tunnel_builder_t::get_tunnel_desc(const waytype_t wtyp, const sint32 min_speed, const uint16 time) { const tunnel_desc_t *find_desc = NULL; for(auto const& i : tunnel_by_name) { tunnel_desc_t* const desc = i.value; if( desc->get_waytype()==wtyp ) { if( desc->is_available(time) ) { if( find_desc==NULL || (find_desc->get_topspeed()get_topspeed()get_topspeed()) || (desc->get_topspeed()>=min_speed && desc->get_maintenance()get_maintenance()) ) { find_desc = desc; } } } } return find_desc; } static bool compare_tunnels(const tunnel_desc_t* a, const tunnel_desc_t* b) { int cmp = a->get_topspeed() - b->get_topspeed(); if(cmp==0) { cmp = (int)a->get_intro_year_month() - (int)b->get_intro_year_month(); } if(cmp==0) { cmp = strcmp(a->get_name(), b->get_name()); } return cmp<0; } /** * Fill menu with icons of given waytype */ void tunnel_builder_t::fill_menu(tool_selector_t* tool_selector, const waytype_t wtyp, sint16 /*sound_ok*/) { // check if scenario forbids this if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_TUNNEL | GENERAL_TOOL, wtyp, 0)) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_TUNNEL | GENERAL_TOOL, wtyp, 0); const uint16 time=welt->get_timeline_year_month(); vector_tpl matching(tunnel_by_name.get_count()); for(auto const& i : tunnel_by_name) { tunnel_desc_t* const desc = i.value; if( desc->get_waytype()==wtyp && desc->is_available(time) ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_TUNNEL | GENERAL_TOOL, wtyp, desc->get_name())) { matching.insert_ordered(desc, compare_tunnels); } } } // now sorted ... for(tunnel_desc_t const* const i : matching) { i->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_TUNNEL | GENERAL_TOOL, wtyp, i->get_name()); tool_selector->add_tool_selector(i->get_builder()); } } const vector_tpl& tunnel_builder_t::get_available_tunnels(const waytype_t wtyp) { static vector_tpl dummy; dummy.clear(); const uint16 time = welt->get_timeline_year_month(); for(auto const& i : tunnel_by_name) { tunnel_desc_t const* const b = i.value; if (b->get_waytype()==wtyp && b->is_available(time) && b->get_builder()) { dummy.append(b); } } return dummy; } /* now construction stuff */ koord3d tunnel_builder_t::find_end_pos(player_t *player, koord3d pos, koord zv, const tunnel_desc_t *desc, bool full_tunnel, const char** msg) { const grund_t *gr; leitung_t *lt; waytype_t wegtyp = desc->get_waytype(); // use the is_allowed_step routine of way_builder_t, needs an instance way_builder_t bauigel(player); bauigel.init_builder( way_builder_t::tunnel_flag | (way_builder_t::bautyp_t)wegtyp, way_builder_t::weg_search( wegtyp, 1, 0, type_flat ), desc); sint32 dummy; while(true) { pos = pos + zv; if(!welt->is_within_limits(pos.get_2d())) { return koord3d::invalid; } // check if ground is below tunnel level gr = welt->lookup_kartenboden(pos.get_2d()); // steep slopes and we are appearing at the top of one if( gr->get_hoehe() == pos.z-1 && welt->get_settings().get_way_height_clearance()==1 ) { const slope_t::type new_slope = slope_type(-zv); sint8 hsw = pos.z + corner_sw(new_slope); sint8 hse = pos.z + corner_se(new_slope); sint8 hne = pos.z + corner_ne(new_slope); sint8 hnw = pos.z + corner_nw(new_slope); terraformer_t raise(terraformer_t::raise, welt); raise.add_node(pos.x, pos.y, hsw, hse, hne, hnw); raise.generate_affected_tile_list(); if (raise.can_raise_all(player)) { // returned true therefore error reported return koord3d::invalid; } // if we can adjust height here we can build an entrance so don't need checks below return pos; } if( gr->get_hoehe() < pos.z ){ return koord3d::invalid; } // check water level if (gr->is_water() && welt->lookup_hgt(pos.get_2d()) <= pos.z) { return koord3d::invalid; } if (const char* err = welt->get_scenario()->is_work_allowed_here(player, TOOL_BUILD_TUNNEL|GENERAL_TOOL, desc->get_finance_waytype(), desc->get_name(), pos)) { if (msg) { *msg = err; } return koord3d::invalid; } // next tile gr = welt->lookup(pos); if( gr == NULL ) { // check for slope down ... gr = welt->lookup(pos + koord3d(0,0,-1)); if( !gr ) { gr = welt->lookup(pos + koord3d(0,0,-2)); } if( gr && gr->get_weg_hang() == slope_t::flat ) { // Don't care about _flat_ tunnels below. gr = NULL; } if( !gr && welt->get_settings().get_way_height_clearance()==2 ) { // check for one above gr = welt->lookup(pos + koord3d(0,0,1)); } } if(gr) { // if there is a tunnel try to connect if( gr->ist_tunnel() ) { if( gr->get_vmove(ribi_type(-zv))!=pos.z) { // wrong slope return koord3d::invalid; } // fake tunnel tile tunnelboden_t from(pos - zv, slope_t::flat); if (bauigel.is_allowed_step(&from, gr, &dummy)) { return gr->get_pos(); } else { return koord3d::invalid; } } const uint8 slope = gr->get_grund_hang(); const slope_t::type new_slope = slope_type(-zv) * welt->get_settings().get_way_height_clearance(); if( gr->ist_karten_boden() && ( slope!=new_slope || pos.z!=gr->get_pos().z ) ) { // lower terrain to match - most of time shouldn't need to raise // however player might have manually altered terrain so check this anyway sint8 hsw = pos.z + corner_sw(new_slope); sint8 hse = pos.z + corner_se(new_slope); sint8 hne = pos.z + corner_ne(new_slope); sint8 hnw = pos.z + corner_nw(new_slope); terraformer_t raise(terraformer_t::raise, welt); terraformer_t lower(terraformer_t::lower, welt); raise.add_node(pos.x, pos.y, hsw, hse, hne, hnw); lower.add_node(pos.x, pos.y, hsw, hse, hne, hnw); raise.generate_affected_tile_list(); lower.generate_affected_tile_list(); if (raise.can_raise_all(player)!= NULL || lower.can_lower_all(player)!=NULL) { // returned non-null therefore error reported return koord3d::invalid; } // if we can adjust height here we can build an entrance so don't need checks below return pos; } if( gr->get_typ() != grund_t::boden || slope != new_slope || gr->is_halt() || ((wegtyp != powerline_wt) ? gr->get_leitung() != NULL : gr->hat_wege()) ) { // must end on boden_t and correct slope and not on halts // ways cannot end on powerlines, powerlines cannot end on ways return koord3d::invalid; } if( gr->has_two_ways() && wegtyp != road_wt ) { // Only road tunnels allowed here. return koord3d::invalid; } ribi_t::ribi ribi = 0; if(wegtyp != powerline_wt) { ribi = gr->get_weg_ribi_unmasked(wegtyp); } else { if(gr->get_leitung()) { ribi = gr->get_leitung()->get_ribi(); } } if( ribi && koord(ribi) == zv ) { // There is already a way (with correct ribi) return pos; } if( !ribi ) { // End of the slope - Missing end rail or has no ribis // we still consider if we interfere with a way if(wegtyp != powerline_wt) { if( !gr->hat_wege() || gr->hat_weg(wegtyp) ) { return pos; } } else { lt = gr->find(); if(!gr->hat_wege() || lt) { return pos; } } } return koord3d::invalid; // Was im Weg (slope hillside or so) } // stop if we only want to check tile behind tunnel mouth if (!full_tunnel) { return pos; } // All free - keep looking } } const char *tunnel_builder_t::build( player_t *player, koord pos, const tunnel_desc_t *desc, bool full_tunnel ) { assert( desc ); const grund_t *gr = welt->lookup_kartenboden(pos); if(gr==NULL) { return "Tunnel must start on single way!"; } koord zv; const waytype_t wegtyp = desc->get_waytype(); const slope_t::type slope = gr->get_grund_hang(); if( wegtyp != powerline_wt ) { const weg_t *weg = gr->get_weg(wegtyp); if( gr->get_typ() != grund_t::boden || gr->is_halt() || gr->get_leitung()) { return "Tunnel must start on single way!"; } // If there is a way on this tile, it must have the right ribis. if( weg && (weg->get_ribi_unmasked() & ~ribi_t::backward( ribi_type(slope) )) ) { return "Tunnel must start on single way!"; } } else { leitung_t *lt = gr->find(); if( gr->get_typ() != grund_t::boden || gr->hat_wege() ) { return "Tunnel must start on single way!"; } if( lt && (lt->get_ribi() & ~ribi_t::backward( ribi_type(slope) )) ) { return "Tunnel must start on single way!"; } } if( !slope_t::is_single(slope) ) { return "Tunnel muss an\neinfachem\nHang beginnen!\n"; } /************************************** FIX ME *************************************************** ********************** THIS MUST BE RATHER A PROPERTY OF THE TUNNEL IN QUESTION ! ****************/ // for conversion factor 1, must be single height, for conversion factor 2, must be double if( (welt->get_settings().get_way_height_clearance() == 1 && !is_one_high(slope)) || (welt->get_settings().get_way_height_clearance() == 2 && is_one_high(slope)) ) { return "Tunnel muss an\neinfachem\nHang beginnen!\n"; } if( gr->has_two_ways() && wegtyp != road_wt ) { return "Tunnel must start on single way!"; } zv = koord(slope); if (const char* err = welt->get_scenario()->is_work_allowed_here(player, TOOL_BUILD_TUNNEL | GENERAL_TOOL, desc->get_finance_waytype(), desc->get_name(), gr->get_pos())) { return err; } // Search tunnel end and check intermediate tiles const char *err = NULL; koord3d end = koord3d::invalid; if (!full_tunnel) { // if there is no tunnel behind set end to start position const grund_t *gr_end = welt->lookup(end); if (gr_end == NULL || !gr_end->ist_tunnel()) { end = gr->get_pos(); } } else { end = find_end_pos(player, gr->get_pos(), zv, desc, full_tunnel, &err); if (err) { return err; } } if(!welt->is_within_limits(end.get_2d())) { return "Tunnel must start on single way!"; } // check ownership const grund_t *end_gr = welt->lookup(end); if (end_gr) { if (weg_t *weg_end = end_gr->get_weg(wegtyp)) { if (weg_end->get_removal_error(player)!=NULL) { return "Das Feld gehoert\neinem anderen Spieler\n"; } if( full_tunnel && end_gr->get_typ() == grund_t::tunnelboden ) { full_tunnel = false; } } } // Begin and end found, we can build slope_t::type end_slope = slope_type(-zv) * welt->get_settings().get_way_height_clearance(); if( full_tunnel && (!end_gr || end_gr->get_grund_hang()!=end_slope) ) { // end slope not at correct height - we have already checked in find_end_pos that we can change this sint8 hsw = end.z + corner_sw(end_slope); sint8 hse = end.z + corner_se(end_slope); sint8 hne = end.z + corner_ne(end_slope); sint8 hnw = end.z + corner_nw(end_slope); terraformer_t raise(terraformer_t::raise, welt); terraformer_t lower(terraformer_t::lower, welt); raise.add_node(end.x, end.y, hsw, hse, hne, hnw); lower.add_node(end.x, end.y, hsw, hse, hne, hnw); raise.generate_affected_tile_list(); lower.generate_affected_tile_list(); err = raise.can_raise_all(player); if (!err) err = lower.can_lower_all(player); if (err) return 0; // TODO: this is rather hackish as 4 seems to come from nowhere but works most of the time // feel free to change if you have a better idea! const int n = (raise.apply() + lower.apply()) / 4; player_t::book_construction_costs(player, welt->get_settings().cst_alter_land * n, end.get_2d(), desc->get_waytype()); } if(!build_tunnel(player, gr->get_pos(), end, zv, desc)) { return "Ways not connected"; } return NULL; } bool tunnel_builder_t::build_tunnel(player_t *player, koord3d start, koord3d end, koord zv, const tunnel_desc_t *desc) { ribi_t::ribi ribi = 0; weg_t *weg = NULL; leitung_t *lt = NULL; koord3d pos = start; int cost = 0; const way_desc_t *way_desc; waytype_t wegtyp = desc->get_waytype(); DBG_MESSAGE("tunnel_builder_t::build()","build from (%d,%d,%d) to (%d,%d,%d) ", pos.x, pos.y, pos.z, end.x, end.y, end.z ); // now we search a matching way for the tunnels top speed way_desc = desc->get_way_desc(); if(way_desc==NULL) { // ignore timeline to get consistent results way_desc = way_builder_t::weg_search( wegtyp, desc->get_topspeed(), 0, type_flat ); } build_tunnel_portal(player, pos, zv, desc, way_desc, cost, start != end); ribi = ribi_type(-zv); // move on pos = pos + zv; // calc back image to remove wall blocking tunnel portal for active underground view if(grund_t::underground_mode) { grund_t *gr = welt->lookup_kartenboden(pos.get_2d()); gr->calc_image(); gr->set_flag(grund_t::dirty); } if( end == start ) { // already finished return true; } // Now we build the invisible part while(pos.get_2d()!=end.get_2d()) { tunnelboden_t *tunnel = new tunnelboden_t(pos, slope_t::flat); welt->access(pos.get_2d())->boden_hinzufuegen(tunnel); if(wegtyp != powerline_wt) { weg = weg_t::alloc(desc->get_waytype()); weg->set_desc(way_desc); weg->set_max_speed(desc->get_topspeed()); tunnel->neuen_weg_bauen(weg, ribi_t::doubles(ribi), player); player_t::add_maintenance( player, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype() ); } else { lt = new leitung_t(tunnel->get_pos(), player); lt->set_desc(way_desc); tunnel->obj_add( lt ); lt->finish_rd(); } tunnel->obj_add(new tunnel_t(pos, player, desc)); tunnel->calc_image(); tunnel->set_flag(grund_t::dirty); assert(!tunnel->ist_karten_boden()); player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype() ); cost += desc->get_price(); pos = pos + zv; } // if end is tunnel then connect grund_t *gr_end = welt->lookup(end); if (gr_end) { if (gr_end->ist_tunnel()) { gr_end->weg_erweitern(desc->get_waytype(), ribi); } else if (gr_end->ist_karten_boden()) { // if end is above ground construct an exit build_tunnel_portal(player, pos, -zv, desc, way_desc, cost, true); gr_end = NULL; // invalid - replaced by tunnel ground // calc new back image for the ground if (end!=start && grund_t::underground_mode) { grund_t *gr = welt->lookup_kartenboden(pos.get_2d()-zv); gr->calc_image(); gr->set_flag(grund_t::dirty); } } else { // good luck assert(0); } } else { // construct end tunnel tile tunnelboden_t *tunnel = new tunnelboden_t(pos, slope_t::flat); welt->access(pos.get_2d())->boden_hinzufuegen(tunnel); if(wegtyp != powerline_wt) { weg = weg_t::alloc(desc->get_waytype()); weg->set_desc(way_desc); weg->set_max_speed(desc->get_topspeed()); tunnel->neuen_weg_bauen(weg, ribi, player); player_t::add_maintenance( player, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype() ); } else { lt = new leitung_t(tunnel->get_pos(), player); lt->set_desc(way_desc); tunnel->obj_add( lt ); lt->finish_rd(); } tunnel->obj_add(new tunnel_t(pos, player, desc)); tunnel->calc_image(); tunnel->set_flag(grund_t::dirty); assert(!tunnel->ist_karten_boden()); player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype() ); cost += desc->get_price(); } player_t::book_construction_costs(player, -cost, start.get_2d(), desc->get_waytype()); return true; } void tunnel_builder_t::build_tunnel_portal(player_t *player, koord3d end, koord zv, const tunnel_desc_t *desc, const way_desc_t *way_desc, int &cost, bool connect_inside) { grund_t *alter_boden = welt->lookup(end); ribi_t::ribi ribi = 0; if(desc->get_waytype()!=powerline_wt) { ribi = alter_boden->get_weg_ribi_unmasked(desc->get_waytype()); } if (connect_inside) { ribi |= ribi_type(zv); } tunnelboden_t *tunnel = new tunnelboden_t( end, alter_boden->get_grund_hang()); tunnel->obj_add(new tunnel_t(end, player, desc)); weg_t *weg = NULL; if(desc->get_waytype()!=powerline_wt) { weg = alter_boden->get_weg( desc->get_waytype() ); } // take care of everything on that tile ... tunnel->take_obj_from( alter_boden ); welt->access(end.get_2d())->kartenboden_setzen( tunnel ); if(desc->get_waytype() != powerline_wt) { if(weg) { // has already a way tunnel->weg_erweitern(desc->get_waytype(), ribi); } else { // needs still one weg = weg_t::alloc( desc->get_waytype() ); if( way_desc ) { weg->set_desc( way_desc ); } tunnel->neuen_weg_bauen( weg, ribi, player ); } player_t::add_maintenance( player, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype() ); weg->set_max_speed( desc->get_topspeed() ); } else { leitung_t *lt = tunnel->get_leitung(); if(!lt) { lt = new leitung_t(tunnel->get_pos(), player); lt->set_desc(way_desc); tunnel->obj_add( lt ); } else { // subtract maintenance once since leitung_t::finish_rd will add it again player_t::add_maintenance( player, -1*lt->get_desc()->get_maintenance(), powerline_wt ); } lt->finish_rd(); } // remove sidewalk weg_t *str = tunnel->get_weg( road_wt ); if( str && str->hat_gehweg()) { str->set_gehweg(false); } tunnel->calc_image(); tunnel->set_flag(grund_t::dirty); // Auto-connect to a way outside the new tunnel mouth grund_t *ground_outside = welt->lookup(end-zv); if (!ground_outside) { ground_outside = welt->lookup_kartenboden(end.get_2d() - zv); if (ground_outside) { if (!ground_outside->hat_weg(desc->get_waytype()) || ground_outside->get_weg_hang() != slope_t::flat || (end.z - ground_outside->get_pos().z) != slope_t::max_diff(ground_outside->get_grund_hang()) ) { // Not the correct slope/height ground_outside = NULL; } } } // check if we can connect if( ground_outside) { weg_t *way_outside = ground_outside->get_weg( desc->get_waytype() ); if( way_outside ) { // use the check_owner routine of way_builder_t (not player_t!), needs an instance way_builder_t bauigel(player); bauigel.init_builder( (way_builder_t::bautyp_t)desc->get_waytype(), way_outside->get_desc()); sint32 dummy; if(bauigel.is_allowed_step(tunnel, ground_outside, &dummy)) { tunnel->weg_erweitern(desc->get_waytype(), ribi_type(-zv)); ground_outside->weg_erweitern(desc->get_waytype(), ribi_type(zv)); } } if (desc->get_waytype()==water_wt && ground_outside->is_water()) { // connect to the sea tunnel->weg_erweitern(desc->get_waytype(), ribi_type(-zv)); ground_outside->calc_image(); // to recalculate ribis } } if(player!=NULL) { player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype() ); } cost += desc->get_price(); } const char *tunnel_builder_t::remove(player_t *player, koord3d start, waytype_t wegtyp, bool remove_all ) { marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y); slist_tpl end_list; slist_tpl part_list; slist_tpl tmp_list; koord3d pos = start; // First check if all tunnel parts can be removed tmp_list.insert(pos); grund_t *from = welt->lookup(pos); marker.mark(from); waytype_t delete_wegtyp = wegtyp==powerline_wt ? invalid_wt : wegtyp; do { pos = tmp_list.remove_first(); grund_t *from = welt->lookup(pos); grund_t *to; koord zv = koord::invalid; if(from->ist_karten_boden()) { // Der Grund ist Tunnelanfang/-ende - hier darf nur in // eine Richtung getestet werden. zv = koord(from->get_grund_hang()); end_list.insert(pos); } else { part_list.insert(pos); } if( from->kann_alle_obj_entfernen(player) ) { return "Der Tunnel ist nicht frei!\n"; } ribi_t::ribi waytype_ribi = ribi_t::none; if( wegtyp == powerline_wt ) { if( from->get_leitung() ) { waytype_ribi = from->get_leitung()->get_ribi(); } } else { waytype_ribi = from->get_weg_ribi_unmasked(delete_wegtyp); } if( !remove_all && ribi_t::is_threeway(waytype_ribi) ) { return "This tunnel branches. You can try Control+Click to remove."; } // Nachbarn raussuchen for(int r = 0; r < 4; r++) { if((zv == koord::invalid || zv == koord::nesw[r]) && from->get_neighbour(to, delete_wegtyp, ribi_t::nesw[r]) && !marker.is_marked(to) && (wegtyp != powerline_wt || to->get_leitung())) { tmp_list.insert(to->get_pos()); marker.mark(to); } } } while (!tmp_list.empty()); // Now we can delete the tunnel grounds while (!part_list.empty()) { pos = part_list.remove_first(); grund_t *gr = welt->lookup(pos); // remove the second way first in the tunnel if(gr->get_weg_nr(1)) { gr->remove_everything_from_way(player,gr->get_weg_nr(1)->get_waytype(),ribi_t::none); } gr->remove_everything_from_way(player,wegtyp,ribi_t::none); // removes stop and signals correctly // remove everything else gr->obj_loesche_alle(player); gr->mark_image_dirty(); welt->access(pos.get_2d())->boden_entfernen(gr); delete gr; minimap_t::get_instance()->calc_map_pixel( pos.get_2d() ); } // And now we can delete the tunnel ends while (!end_list.empty()) { pos = end_list.remove_first(); grund_t *gr = welt->lookup(pos); if(wegtyp == powerline_wt) { // remove tunnel portals tunnel_t *t = gr->find(); if(t) { t->cleanup(player); delete t; } if (leitung_t *lt = gr->get_leitung()) { // remove single powerlines if ( (lt->get_ribi() & ~ribi_type(gr->get_grund_hang())) == ribi_t::none ) { lt->cleanup(player); delete lt; } } } else { ribi_t::ribi mask = gr->get_grund_hang()!=slope_t::flat ? ~ribi_type(gr->get_grund_hang()) : ~ribi_type(slope_t::opposite(gr->get_weg_hang())); // remove the second way first in the tunnel if(gr->get_weg_nr(1)) { gr->remove_everything_from_way(player,gr->get_weg_nr(1)->get_waytype(),gr->get_weg_nr(1)->get_ribi_unmasked() & mask); } // removes single signals, bridge head, pedestrians, stops, changes catenary etc ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(wegtyp) & mask; tunnel_t *t = gr->find(); uint8 broad_type = t->get_broad_type(); gr->remove_everything_from_way(player,wegtyp,ribi); // removes stop and signals correctly // remove tunnel portals t = gr->find(); if(t) { t->cleanup(player); delete t; } if( broad_type ) { slope_t::type hang = gr->get_grund_hang(); ribi_t::ribi dir = ribi_t::rotate90( ribi_type( hang ) ); if( broad_type & 1 ) { const grund_t *gr_l = welt->lookup(pos + dir); tunnel_t* tunnel_l = gr_l ? gr_l->find() : NULL; if( tunnel_l ) { tunnel_l->calc_image(); } } if( broad_type & 2 ) { const grund_t *gr_r = welt->lookup(pos - dir); tunnel_t* tunnel_r = gr_r ? gr_r->find() : NULL; if( tunnel_r ) { tunnel_r->calc_image(); } } } // corrects the ways weg_t *weg=gr->get_weg_nr(0); if(weg) { // fails if it was previously the last ribi weg->set_desc(weg->get_desc()); weg->set_ribi( ribi ); if(gr->get_weg_nr(1)) { gr->get_weg_nr(1)->set_ribi( ribi ); } } } // then add the new ground, copy everything and replace the old one grund_t *gr_new = new boden_t(pos, gr->get_grund_hang()); welt->access(pos.get_2d())->kartenboden_setzen(gr_new); if(gr_new->get_leitung()) { gr_new->get_leitung()->finish_rd(); } // recalc image of ground grund_t *kb = welt->access(pos.get_2d()+koord(gr_new->get_grund_hang()))->get_kartenboden(); kb->calc_image(); kb->set_flag(grund_t::dirty); } return NULL; } simutrans-124.3/src/simutrans/builder/tunnelbauer.h000066400000000000000000000033131474050137200225120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_TUNNELBAUER_H #define BUILDER_TUNNELBAUER_H #include "../simtypes.h" #include "../dataobj/koord.h" #include "../dataobj/koord3d.h" class karte_ptr_t; class player_t; class tunnel_desc_t; class way_desc_t; class tool_selector_t; /** * Baut Tunnel. Tunnel sollten nicht direkt instanziiert werden * sondern immer vom tunnel_builder_t erzeugt werden. * * Es gibt keine Instanz - nur statische Methoden. */ class tunnel_builder_t { private: static karte_ptr_t welt; static bool build_tunnel(player_t *player, koord3d pos, koord3d end, koord zv, const tunnel_desc_t *desc); static void build_tunnel_portal(player_t *player, koord3d end, koord zv, const tunnel_desc_t *desc, const way_desc_t *way_desc, int &cost, bool connect_inside); tunnel_builder_t() {} // private -> no instance please public: static koord3d find_end_pos(player_t *player, koord3d pos, koord zv, const tunnel_desc_t *desc, bool full_tunnel=true, const char** msg=NULL); static void register_desc(tunnel_desc_t *desc); static const tunnel_desc_t *get_desc(const char *); static const tunnel_desc_t *get_tunnel_desc(const waytype_t wtyp, const sint32 min_speed,const uint16 time); static void fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, sint16 sound_ok); /** * Returns a list with available tunnel types. */ static const vector_tpl& get_available_tunnels(const waytype_t wtyp); static const char *build( player_t *player, koord pos, const tunnel_desc_t *desc, bool full_tunnel ); static const char *remove(player_t *player, koord3d pos, waytype_t wegtyp, bool all); }; #endif simutrans-124.3/src/simutrans/builder/vehikelbauer.cc000066400000000000000000000500351474050137200227750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../player/simplay.h" #include "../simdebug.h" #include "../utils/simrandom.h" #include "../simtypes.h" #include "../dataobj/environment.h" #include "../dataobj/tabfile.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../descriptor/vehicle_desc.h" #include "../gui/depot_frame.h" #include "vehikelbauer.h" #include "../tpl/stringhashtable_tpl.h" #include "../vehicle/air_vehicle.h" #include "../vehicle/rail_vehicle.h" #include "../vehicle/road_vehicle.h" #include "../vehicle/water_vehicle.h" const char* vehicle_builder_t::engine_type_names[9] = { "unknown", "steam", "diesel", "electric", "bio", "sail", "fuel_cell", "hydrogene", "battery" }; const char *vehicle_builder_t::vehicle_sort_by[vehicle_builder_t::sb_length] = { "Fracht", "Vehicle Name", "Capacity", "Price", "Cost", "Cost per unit", "Max. speed", "Vehicle Power", "Weight", "Intro. date", "Retire date" }; static stringhashtable_tpl name_fahrzeuge; // index 0 aur, 1...8 at normal waytype index #define GET_WAYTYPE_INDEX(wt) ((int)(wt)>8 ? 0 : (wt)) static slist_tpl typ_fahrzeuge[vehicle_builder_t::sb_length][9]; static uint8 tmp_sort_idx; class bonus_record_t { public: sint32 year; sint32 speed; bonus_record_t( sint32 y=0, sint32 kmh=0 ) { year = y*12; speed = kmh; } void rdwr(loadsave_t *file) { file->rdwr_long(year); file->rdwr_long(speed); } }; // speed bonus static vector_tplspeedbonus[8]; static sint32 default_speedbonus[8] = { 60, // road 80, // track 35, // water 350, // air 80, // monorail 200, // maglev 60, // tram 60 // narrowgauge }; bool vehicle_builder_t::speedbonus_init() { tabfile_t bonusconf; // first take user data, then user global data if (!bonusconf.open((env_t::pak_dir+"config/speedbonus.tab").c_str())) { dbg->warning("vehicle_builder_t::speedbonus_init()", "Can't read speedbonus.tab" ); return false; } tabfileobj_t contents; bonusconf.read(contents); /* init the values from line with the form year, speed, year, speed * must be increasing order! */ for( int j=0; j<8; j++ ) { vector_tpl tracks = contents.get_ints(weg_t::waytype_to_string(j==3?air_wt:(waytype_t)(j+1))); if((tracks.get_count() % 2) != 0) { dbg->warning( "vehicle_builder_t::speedbonus_init()", "Ill formed line in speedbonus.tab\nFormat is year,speed[,year,speed]!" ); tracks.pop_back(); } speedbonus[j].reserve( tracks.get_count()/2 ); for( uint32 i=0; i const& b = speedbonus[typ]; if (!b.empty()) { uint i=0; while (i < b.get_count() && monthyear >= b[i].year) { i++; } if (i == b.get_count()) { // maxspeed already? return b[i - 1].speed; } else if(i==0) { // minspeed below return b[0].speed; } else { // interpolate linear sint32 const delta_speed = b[i].speed - b[i - 1].speed; sint32 const delta_years = b[i].year - b[i - 1].year; return delta_speed * (monthyear - b[i - 1].year) / delta_years + b[i - 1].speed; } } else { sint32 speed_sum = 0; sint32 num_averages = 0; // needs to do it the old way => iterate over all vehicles with this type ... for(vehicle_desc_t const* const info : typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) { if( info->get_power()>0 && info->is_available(monthyear) ) { speed_sum += info->get_topspeed(); num_averages ++; } } if( num_averages>0 ) { return speed_sum / num_averages; } } // no vehicles => return default return default_speedbonus[typ]; } void vehicle_builder_t::rdwr_speedbonus(loadsave_t *file) { for( int j=0; j<8; j++ ) { uint32 count = speedbonus[j].get_count(); file->rdwr_long(count); if (file->is_loading()) { speedbonus[j].clear(); speedbonus[j].reserve(count); } for(uint32 i=0; iis_loading()) { speedbonus[j].append(bonus_record_t()); } speedbonus[j][i].rdwr(file); } } } vehicle_t* vehicle_builder_t::build(koord3d k, player_t* player, convoi_t* cnv, const vehicle_desc_t* vb ) { vehicle_t* v; switch (vb->get_waytype()) { case road_wt: v = new road_vehicle_t( k, vb, player, cnv); break; case monorail_wt: v = new monorail_vehicle_t(k, vb, player, cnv); break; case track_wt: case tram_wt: v = new rail_vehicle_t( k, vb, player, cnv); break; case water_wt: v = new water_vehicle_t( k, vb, player, cnv); break; case air_wt: v = new air_vehicle_t( k, vb, player, cnv); break; case maglev_wt: v = new maglev_vehicle_t( k, vb, player, cnv); break; case narrowgauge_wt:v = new narrowgauge_vehicle_t(k, vb, player, cnv); break; default: dbg->fatal("vehicle_builder_t::build()", "cannot built a vehicle with waytype %i", vb->get_waytype()); } player->book_new_vehicle(-(sint64)vb->get_price(), k.get_2d(), vb->get_waytype() ); return v; } bool vehicle_builder_t::register_desc(const vehicle_desc_t *desc) { // register waytype list const int wt_idx = GET_WAYTYPE_INDEX( desc->get_waytype() ); // first hashtable vehicle_desc_t const *old_desc = name_fahrzeuge.get( desc->get_name() ); if( old_desc ) { name_fahrzeuge.remove( desc->get_name() ); } name_fahrzeuge.put(desc->get_name(), desc); // now add it to sorter (may be more than once!) for( int sort_idx = 0; sort_idx < vehicle_builder_t::sb_length; sort_idx++ ) { if( old_desc ) { typ_fahrzeuge[sort_idx][wt_idx].remove(old_desc); } typ_fahrzeuge[sort_idx][wt_idx].append(desc); } // we cannot delete old_desc, since then xref-resolving will crash return true; } // compare funcions to sort vehicle in the list static int compare_freight(const vehicle_desc_t* a, const vehicle_desc_t* b) { int cmp = a->get_freight_type()->get_catg() - b->get_freight_type()->get_catg(); if (cmp != 0) return cmp; if (a->get_freight_type()->get_catg() == 0) { cmp = a->get_freight_type()->get_index() - b->get_freight_type()->get_index(); } return cmp; } static int compare_capacity(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_capacity() - b->get_capacity(); } static int compare_engine(const vehicle_desc_t* a, const vehicle_desc_t* b) { return (a->get_capacity() + a->get_power() == 0 ? (uint8)vehicle_desc_t::steam : a->get_engine_type()) - (b->get_capacity() + b->get_power() == 0 ? (uint8)vehicle_desc_t::steam : b->get_engine_type()); } static int compare_price(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_price() - b->get_price(); } static int compare_cost(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_running_cost() - b->get_running_cost(); } static int compare_cost_per_unit(const vehicle_desc_t* a, const vehicle_desc_t* b) { return a->get_running_cost()*b->get_capacity() - b->get_running_cost()*a->get_capacity(); } static int compare_topspeed(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_topspeed() - b->get_topspeed();} static int compare_power(const vehicle_desc_t* a, const vehicle_desc_t* b) {return (a->get_power() == 0 ? 0x7FFFFFF : a->get_power()) - (b->get_power() == 0 ? 0x7FFFFFF : b->get_power());} static int compare_weight(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_weight() - b->get_weight();} static int compare_intro_year_month(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_intro_year_month() - b->get_intro_year_month();} static int compare_retire_year_month(const vehicle_desc_t* a, const vehicle_desc_t* b) {return a->get_retire_year_month() - b->get_retire_year_month();} // default compare function with mode parameter bool vehicle_builder_t::compare_vehicles(const vehicle_desc_t* a, const vehicle_desc_t* b, sort_mode_t mode ) { int cmp = 0; switch (mode) { case sb_freight: cmp = compare_freight(a, b); if (cmp != 0) return cmp < 0; break; case sb_name: cmp = strcmp(translator::translate(a->get_name()), translator::translate(b->get_name())); if (cmp != 0) return cmp < 0; break; case sb_capacity: cmp = compare_capacity(a, b); if (cmp != 0) return cmp < 0; break; case sb_price: cmp = compare_price(a, b); if (cmp != 0) return cmp < 0; // fall-through case sb_cost: cmp = compare_cost(a, b); if (cmp != 0) return cmp < 0; cmp = compare_price(a, b); if (cmp != 0) return cmp < 0; break; case sb_cost_per_unit: cmp = compare_cost_per_unit(a,b); if (cmp != 0) return cmp < 0; break; case sb_speed: cmp = compare_topspeed(a, b); if (cmp != 0) return cmp < 0; break; case sb_weight: cmp = compare_weight(a, b); if (cmp != 0) return cmp < 0; break; case sb_power: cmp = compare_power(a, b); if (cmp != 0) return cmp < 0; break; case sb_intro_date: cmp = compare_intro_year_month(a, b); if (cmp != 0) return cmp < 0; // fall-through case sb_retire_date: cmp = compare_retire_year_month(a, b); if (cmp != 0) return cmp < 0; cmp = compare_intro_year_month(a, b); if (cmp != 0) return cmp < 0; break; default: ; } // Sort by: // 1. cargo category // 2. cargo (if special freight) // 3. engine_type // 4. speed // 5. power // 6. intro date // 7. name cmp = compare_freight(a, b); if (cmp != 0) return cmp < 0; cmp = compare_capacity(a, b); if (cmp != 0) return cmp < 0; cmp = compare_engine(a, b); if (cmp != 0) return cmp < 0; cmp = compare_topspeed(a, b); if (cmp != 0) return cmp < 0; cmp = compare_power(a, b); if (cmp != 0) return cmp < 0; cmp = compare_intro_year_month(a, b); if (cmp != 0) return cmp < 0; cmp = strcmp(translator::translate(a->get_name()), translator::translate(b->get_name())); return cmp < 0; } static bool compare( const vehicle_desc_t* a, const vehicle_desc_t* b ) { return vehicle_builder_t::compare_vehicles( a, b, (vehicle_builder_t::sort_mode_t)tmp_sort_idx ); } bool vehicle_builder_t::successfully_loaded() { // first: check for bonus tables DBG_MESSAGE("vehicle_builder_t::sort_lists()","called"); for ( int sort_idx = 0; sort_idx < vehicle_builder_t::sb_length; sort_idx++ ) { for( int wt_idx=0; wt_idx<9; wt_idx++ ) { tmp_sort_idx = sort_idx; slist_tpl& typ_liste = typ_fahrzeuge[sort_idx][wt_idx]; uint count = typ_liste.get_count(); if (count == 0) { continue; } const vehicle_desc_t** const tmp = new const vehicle_desc_t*[count]; const vehicle_desc_t** const tmp_end = tmp + count; for( const vehicle_desc_t** tmpptr = tmp; tmpptr != tmp_end; tmpptr++ ) { *tmpptr = typ_liste.remove_first(); } std::sort(tmp, tmp_end, compare); for( const vehicle_desc_t** tmpptr = tmp; tmpptr != tmp_end; tmpptr++ ) { typ_liste.append(*tmpptr); } delete [] tmp; } } return true; } const vehicle_desc_t *vehicle_builder_t::get_info(const char *name) { return name_fahrzeuge.get(name); } slist_tpl const & vehicle_builder_t::get_info(waytype_t const typ, uint8 sortkey) { return typ_fahrzeuge[sortkey][GET_WAYTYPE_INDEX(typ)]; } /** * extended search for vehicles for AI * checks also timeline and constraints * tries to get best with but adds a little random action */ const vehicle_desc_t *vehicle_builder_t::vehicle_search( waytype_t wt, const uint16 month_now, const uint32 target_weight, const sint32 target_speed, const goods_desc_t * target_freight, bool include_electric, bool not_obsolete ) { const vehicle_desc_t *desc = NULL; sint32 desc_index = -100000; if( target_freight==NULL && target_weight==0 ) { // no power, no freight => no vehicle to search return NULL; } for(vehicle_desc_t const* const test_desc : typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) { // no constricts allow for rail vehicles concerning following engines if(wt==track_wt && !test_desc->can_follow_any() ) { continue; } // do not buy incomplete vehicles if(wt==road_wt && !test_desc->can_lead(NULL)) { continue; } // engine, but not allowed to lead a convoi, or no power at all or no electrics allowed if(target_weight) { if(test_desc->get_power()==0 || !test_desc->can_follow(NULL) || (!include_electric && test_desc->get_engine_type()==vehicle_desc_t::electric) ) { continue; } } // check for waytype too if(test_desc->get_waytype()!=wt || test_desc->is_future(month_now) ) { continue; } if( not_obsolete && test_desc->is_retired(month_now) ) { // not using vintage cars here! continue; } uint32 power = (test_desc->get_power()*test_desc->get_gear())/64; if(target_freight) { // this is either a railcar/trailer or a truck/boat/plane if( test_desc->get_capacity()==0 || !test_desc->get_freight_type()->is_interchangeable(target_freight) ) { continue; } sint32 difference=0; // smaller is better // assign this vehicle if we have not found one yet, or we only found one too weak if( desc!=NULL ) { // is it cheaper to run? (this is most important) difference += (desc->get_capacity()*1000)/(1+desc->get_running_cost()) < (test_desc->get_capacity()*1000)/(1+test_desc->get_running_cost()) ? -20 : 20; if( target_weight>0 ) { // is it stronger? difference += (desc->get_power()*desc->get_gear())/64 < power ? -10 : 10; } // is it faster? (although we support only up to 120km/h for goods) difference += (desc->get_topspeed() < test_desc->get_topspeed())? -10 : 10; // is it cheaper? (not so important) difference += (desc->get_price() > test_desc->get_price())? -5 : 5; // add some malus for obsolete vehicles if(test_desc->is_retired(month_now)) { difference += 5; } } // ok, final check if( desc==NULL || difference<(int)simrand(25) ) { // then we want this vehicle! desc = test_desc; DBG_MESSAGE( "vehicle_builder_t::vehicle_search","Found car %s",desc->get_name()); } } else { // engine/tugboat/truck for trailer if( test_desc->get_capacity()!=0 || !test_desc->can_follow(NULL) ) { continue; } // finally, we might be able to use this vehicle sint32 speed = test_desc->get_topspeed(); uint32 max_weight = power/( (speed*speed)/2500 + 1 ); // we found a useful engine sint32 current_index = (power * 100) / (1 + test_desc->get_running_cost()) + test_desc->get_topspeed() - test_desc->get_weight() / 1000 - (sint32)(test_desc->get_price() / 25000); // too slow? if(speed < target_speed) { current_index -= 250; } // too weak to reach full speed? if( max_weight < target_weight+test_desc->get_weight()/1000 ) { current_index += max_weight - (sint32)(target_weight+test_desc->get_weight()/1000); } current_index += simrand(100); if( current_index > desc_index ) { // then we want this vehicle! desc = test_desc; desc_index = current_index; DBG_MESSAGE( "vehicle_builder_t::vehicle_search","Found engine %s",desc->get_name()); } } } // no vehicle found! if( desc==NULL ) { DBG_MESSAGE( "vehicle_builder_t::vehicle_search()","could not find a suitable vehicle! (speed %i, weight %i)",target_speed,target_weight); } return desc; } /** * extended search for vehicles for replacement on load time * tries to get best match (no random action) * if prev_desc==NULL, then the convoi must be able to lead a convoi */ const vehicle_desc_t *vehicle_builder_t::get_best_matching( waytype_t wt, const uint16 month_now, const uint32 target_weight, const uint32 target_power, const sint32 target_speed, const goods_desc_t * target_freight, bool not_obsolete, const vehicle_desc_t *prev_veh, bool is_last ) { const vehicle_desc_t *desc = NULL; sint32 desc_index = -100000; for(vehicle_desc_t const* const test_desc : typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) { if(target_power>0 && test_desc->get_power()==0) { continue; } // will test for first (prev_veh==NULL) or matching following vehicle if(!test_desc->can_follow(prev_veh)) { continue; } // not allowed as last vehicle if(is_last && test_desc->get_trailer_count()>0 && test_desc->get_trailer(0)!=NULL ) { continue; } // not allowed as non-last vehicle if(!is_last && test_desc->get_trailer_count()==1 && test_desc->get_trailer(0)==NULL ) { continue; } // check for waytype too if(test_desc->get_waytype()!=wt || test_desc->is_future(month_now) ) { continue; } // ignore vehicles that need electrification if(test_desc->get_power()>0 && test_desc->get_engine_type()==vehicle_desc_t::electric) { continue; } // likely tender => replace with some engine ... if(target_freight==0 && target_weight==0) { if( test_desc->get_capacity()!=0 ) { continue; } } if( not_obsolete && test_desc->is_retired(month_now) ) { // not using vintage cars here! continue; } uint32 power = (test_desc->get_power()*test_desc->get_gear())/64; if(target_freight) { // this is either a railcar/trailer or a truck/boat/plane if( test_desc->get_capacity()==0 || !test_desc->get_freight_type()->is_interchangeable(target_freight) ) { continue; } sint32 difference=0; // smaller is better // assign this vehicle if we have not found one yet, or we only found one too weak if( desc!=NULL ) { // is it cheaper to run? (this is most important) difference += (desc->get_capacity()*1000)/(1+desc->get_running_cost()) < (test_desc->get_capacity()*1000)/(1+test_desc->get_running_cost()) ? -20 : 20; if( target_weight>0 ) { // is it stronger? difference += (desc->get_power()*desc->get_gear())/64 < power ? -10 : 10; } // is it faster? (although we support only up to 120km/h for goods) difference += (desc->get_topspeed() < test_desc->get_topspeed())? -10 : 10; // is it cheaper? (not so important) difference += (desc->get_price() > test_desc->get_price())? -5 : 5; // add some malus for obsolete vehicles if(test_desc->is_retired(month_now)) { difference += 5; } } // ok, final check if( desc==NULL || difference<12 ) { // then we want this vehicle! desc = test_desc; DBG_MESSAGE( "vehicle_builder_t::get_best_matching","Found car %s",desc->get_name()); } } else { // finally, we might be able to use this vehicle sint32 speed = test_desc->get_topspeed(); uint32 max_weight = power/( (speed*speed)/2500 + 1 ); // we found a useful engine sint32 current_index = (power * 100) / (1 + test_desc->get_running_cost()) + test_desc->get_topspeed() - (sint16)test_desc->get_weight() / 1000 - (sint32)(test_desc->get_price() / 25000); // too slow? if(speed < target_speed) { current_index -= 250; } // too weak to reach full speed? if( max_weight < target_weight+test_desc->get_weight()/1000 ) { current_index += max_weight - (sint32)(target_weight+test_desc->get_weight()/1000); } current_index += 50; if( current_index > desc_index ) { // then we want this vehicle! desc = test_desc; desc_index = current_index; DBG_MESSAGE( "vehicle_builder_t::get_best_matching","Found engine %s",desc->get_name()); } } } // no vehicle found! if( desc==NULL ) { DBG_MESSAGE( "vehicle_builder_t::get_best_matching()","could not find a suitable vehicle! (speed %i, weight %i)",target_speed,target_weight); } return desc; } sint32 vehicle_builder_t::get_fastest_vehicle_speed(waytype_t wt, uint16 const month_now, bool const use_timeline, bool const allow_obsolete) { sint32 fastest_speed = 0; for(vehicle_desc_t const* const vehicle_descriptor : typ_fahrzeuge[0][GET_WAYTYPE_INDEX(wt)]) { if (vehicle_descriptor->get_power() == 0 || (use_timeline && ( vehicle_descriptor->is_future(month_now) || (!allow_obsolete && vehicle_descriptor->is_retired(month_now))))) { continue; } sint32 const speed = vehicle_descriptor->get_topspeed(); if (fastest_speed < speed) { fastest_speed = speed; } } return fastest_speed; } simutrans-124.3/src/simutrans/builder/vehikelbauer.h000066400000000000000000000047701474050137200226440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_VEHIKELBAUER_H #define BUILDER_VEHIKELBAUER_H #include "../dataobj/koord3d.h" #include "../simtypes.h" #include class vehicle_t; class player_t; class convoi_t; class vehicle_desc_t; class goods_desc_t; template class slist_tpl; /** * Baut Fahrzeuge. Fahrzeuge sollten nicht direct instanziiert werden * sondern immer von einem vehicle_builder_t erzeugt werden. */ class vehicle_builder_t { public: // sorting categories enum sort_mode_t { sb_freight, sb_name, sb_capacity, sb_price, sb_cost, sb_cost_per_unit, sb_speed, sb_power, sb_weight, sb_intro_date, sb_retire_date, sb_length }; static const char *vehicle_sort_by[sb_length]; // default compare function static bool compare_vehicles( const vehicle_desc_t* a, const vehicle_desc_t* b, sort_mode_t mode ); static const char *engine_type_names[9]; static bool speedbonus_init(); static sint32 get_speedbonus( sint32 monthyear, waytype_t wt ); static void rdwr_speedbonus(loadsave_t *file); static bool register_desc(const vehicle_desc_t *desc); static bool successfully_loaded(); static vehicle_t* build(koord3d k, player_t* player, convoi_t* cnv, const vehicle_desc_t* vb ); static const vehicle_desc_t * get_info(const char *name); static slist_tpl const& get_info(waytype_t, uint8 sortkey = vehicle_builder_t::sb_name); /** extended search for vehicles for AI */ static const vehicle_desc_t *vehicle_search(waytype_t typ,const uint16 month_now,const uint32 target_power,const sint32 target_speed, const goods_desc_t * target_freight, bool include_electric, bool not_obsolete ); /* for replacement during load time * prev_veh==NULL equals leading of convoi */ static const vehicle_desc_t *get_best_matching( waytype_t wt, const uint16 month_now, const uint32 target_weight, const uint32 target_power, const sint32 target_speed, const goods_desc_t * target_freight, bool not_obsolete, const vehicle_desc_t *prev_veh, bool is_last ); /* Resolves the fastest achieveable speed in km/h for the specified way type. * This is the speed of the fastest powered vehicle for the way type that is available within the time constraints. * This does not factor in limits applied by logically dependant vehicles or buildable ways. */ static sint32 get_fastest_vehicle_speed(waytype_t wt, uint16 const month_now, bool const use_timeline, bool const allow_obsolete); }; #endif simutrans-124.3/src/simutrans/builder/wegbauer.cc000066400000000000000000003102651474050137200221340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../world/simworld.h" #include "../tool/simtool.h" #include "../simhalt.h" #include "../simmesg.h" #include "../simintr.h" #include "../player/simplay.h" #include "../world/simplan.h" #include "../obj/depot.h" #include "wegbauer.h" #include "brueckenbauer.h" #include "tunnelbauer.h" #include "../descriptor/way_desc.h" #include "../descriptor/tunnel_desc.h" #include "../descriptor/building_desc.h" #include "../descriptor/crossing_desc.h" #include "../obj/way/strasse.h" #include "../obj/way/schiene.h" #include "../obj/way/monorail.h" #include "../obj/way/maglev.h" #include "../obj/way/narrowgauge.h" #include "../obj/way/kanal.h" #include "../obj/way/runway.h" #include "../ground/brueckenboden.h" #include "../ground/monorailboden.h" #include "../ground/tunnelboden.h" #include "../ground/grund.h" #include "../ground/wasser.h" #include "../dataobj/environment.h" #include "../dataobj/route.h" #include "../dataobj/marker.h" #include "../dataobj/translator.h" #include "../dataobj/scenario.h" #include "../utils/simrandom.h" // binary heap, since we only need insert and pop #include "../tpl/binary_heap_tpl.h" // fastest #include "../obj/field.h" #include "../obj/gebaeude.h" #include "../obj/bruecke.h" #include "../obj/tunnel.h" #include "../obj/crossing.h" #include "../obj/leitung2.h" #include "../obj/groundobj.h" #include "../obj/wayobj.h" #include "../vehicle/simtestdriver.h" #include "../tpl/array_tpl.h" #include "../tpl/stringhashtable_tpl.h" #include "../gui/minimap.h" // for debugging #include "../gui/tool_selector.h" #include "../gui/messagebox.h" #ifdef DEBUG_ROUTES #include "../sys/simsys.h" #endif // #define AUTOMATIC_BRIDGES // build bridges automatically // #define AUTOMATIC_TUNNELS // build tunnels automatically #define REVERSE_CALC_ROUTE_TOO // lookup also return route and take the better of the two karte_ptr_t way_builder_t::welt; const way_desc_t *way_builder_t::leitung_desc = NULL; static stringhashtable_tpl desc_table; static void set_default(way_desc_t const*& def, waytype_t const wtyp, systemtype_t const system_type = type_flat, sint32 const speed_limit = 1) { def = way_builder_t::weg_search(wtyp, speed_limit, 0, system_type); if (def == NULL) { def = way_builder_t::weg_search(wtyp, 1, 0, type_all); } } bool way_builder_t::successfully_loaded() { // some defaults to avoid hardcoded values set_default(strasse_t::default_strasse, road_wt, type_flat, 50); if( strasse_t::default_strasse == NULL ) { dbg->fatal( "way_builder_t::successfully_loaded()", "No road found at all!" ); } set_default(schiene_t::default_schiene, track_wt, type_flat, 80); set_default(monorail_t::default_monorail, monorail_wt, type_elevated); // Only elevated? set_default(maglev_t::default_maglev, maglev_wt, type_elevated); // Only elevated? set_default(narrowgauge_t::default_narrowgauge, narrowgauge_wt); set_default(kanal_t::default_kanal, water_wt, type_all); // Also find hidden rivers. set_default(runway_t::default_runway, air_wt, type_runway); set_default(way_builder_t::leitung_desc, powerline_wt); return true; } bool way_builder_t::register_desc(way_desc_t *desc) { if( const way_desc_t *old_desc = desc_table.remove(desc->get_name()) ) { tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); delete old_desc; } if( desc->get_cursor()->get_image_id(1)!=IMG_EMPTY ) { // add the tool tool_build_way_t *tool = new tool_build_way_t(); tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param(desc->get_name()); tool_t::general_tool.append( tool ); desc->set_builder( tool ); } else { desc->set_builder( NULL ); } desc_table.put(desc->get_name(), desc); return true; } const vector_tpl& way_builder_t::get_way_list(const waytype_t wtyp, systemtype_t styp) { static vector_tpl dummy; dummy.clear(); const uint16 time = welt->get_timeline_year_month(); for(auto const& i : desc_table) { way_desc_t const* const test = i.value; if (test->get_wtyp()==wtyp && test->get_styp()== styp && test->is_available(time) && test->get_builder()) { dummy.append(test); } } return dummy; } /** * Finds a way with a given speed limit for a given waytype * It finds: * - the slowest way, as fast as speed limit * - if no way faster than speed limit, the fastest way. * The timeline is also respected. */ const way_desc_t* way_builder_t::weg_search(const waytype_t wtyp, const sint32 speed_limit, const uint16 time, const systemtype_t system_type) { const way_desc_t* best = NULL; bool best_allowed = false; // Does the best way fulfil the timeline? for(auto const& iter : desc_table) { way_desc_t const* const test = iter.value; if( ((test->get_wtyp()==wtyp && (test->get_styp()==system_type || system_type==type_all)) || (test->get_wtyp()==track_wt && test->get_styp()==type_tram && wtyp==tram_wt)) && test->get_cursor()->get_image_id(1)!=IMG_EMPTY ) { const bool test_allowed = test->get_intro_year_month()<=time && timeget_retire_year_month(); if( !best_allowed || time==0 || test_allowed ) { if( best==NULL || ( best->get_topspeed() < test->get_topspeed() && test->get_topspeed() <= speed_limit ) || // closer to desired speed (from the low end) ( speed_limit < best->get_topspeed() && test->get_topspeed() < best->get_topspeed()) || // respects speed_limit better ( time!=0 && !best_allowed && test_allowed) // current choice is actually not really allowed, timewise ) { best = test; best_allowed = test_allowed; } } } } return best; } const way_desc_t *way_builder_t::get_earliest_way(const waytype_t wtyp) { const way_desc_t *desc = NULL; for(auto const &iter : desc_table) { way_desc_t const *const test = iter.value; if( test->get_wtyp()==wtyp && (desc==NULL || test->get_intro_year_month()get_intro_year_month()) ) { desc = test; } } return desc; } const way_desc_t *way_builder_t::get_latest_way(const waytype_t wtyp) { const way_desc_t *desc = NULL; for(auto const& iter : desc_table) { way_desc_t const* const test = iter.value; if( test->get_wtyp()==wtyp && (desc==NULL || test->get_retire_year_month()>desc->get_retire_year_month()) ) { desc = test; } } return desc; } // ture if the way is available with timely bool way_builder_t::waytype_available( const waytype_t wtyp, uint16 time ) { if( time==0 ) { return true; } for(auto const& i : desc_table) { way_desc_t const* const test = i.value; if( test->get_wtyp()==wtyp && test->get_intro_year_month()<=time && test->get_retire_year_month()>time ) { return true; } } return false; } const way_desc_t *way_builder_t::get_desc(const char * way_name, const uint16 time) { //DBG_MESSAGE("way_builder_t::get_desc","return desc for %s in (%i)",way_name, time/12); const way_desc_t *desc = desc_table.get(way_name); if( desc && desc->is_available(time) ) { return desc; } return NULL; } // generates timeline message void way_builder_t::new_month() { const uint16 current_month = welt->get_timeline_year_month(); if(current_month!=0) { // check, what changed slist_tpl matching; for(auto const& i : desc_table) { way_desc_t const* const desc = i.value; cbuffer_t buf; const uint16 intro_month = desc->get_intro_year_month(); if(intro_month == current_month) { buf.printf( translator::translate("way %s now available:\n"), translator::translate(desc->get_name()) ); welt->get_message()->add_message(buf,koord3d::invalid,message_t::new_vehicle,NEW_VEHICLE,desc->get_image_id(5,0)); } const uint16 retire_month = desc->get_retire_year_month(); if(retire_month == current_month) { buf.printf( translator::translate("way %s cannot longer used:\n"), translator::translate(desc->get_name()) ); welt->get_message()->add_message(buf,koord3d::invalid,message_t::new_vehicle,NEW_VEHICLE,desc->get_image_id(5,0)); } } } } static bool compare_ways(const way_desc_t* a, const way_desc_t* b) { int cmp = a->get_topspeed() - b->get_topspeed(); if(cmp==0) { cmp = (int)a->get_intro_year_month() - (int)b->get_intro_year_month(); } if(cmp==0) { cmp = strcmp(a->get_name(), b->get_name()); } return cmp<0; } /** * Fill menu with icons of given waytype, return number of added entries */ void way_builder_t::fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, const systemtype_t styp, sint16 /*ok_sound*/) { // check if scenario forbids this const waytype_t rwtyp = wtyp!=track_wt || styp!=type_tram ? wtyp : tram_wt; if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_WAY | GENERAL_TOOL, rwtyp, 0)) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_WAY | GENERAL_TOOL, rwtyp, 0); const uint16 time = welt->get_timeline_year_month(); // list of matching types (sorted by speed) vector_tpl matching; for(auto const &iter : desc_table) { way_desc_t const* const desc = iter.value; if ( desc->get_styp()==styp && desc->get_wtyp()==wtyp && desc->get_builder() && desc->is_available(time) ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_WAY | GENERAL_TOOL, rwtyp, desc->get_name())) { matching.append(desc); } } } std::sort(matching.begin(), matching.end(), compare_ways); // now add sorted ways for(way_desc_t const* const i : matching) { i->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_WAY | GENERAL_TOOL, rwtyp, i->get_name()); tool_selector->add_tool_selector(i->get_builder()); } } /// allow for railroad crossing bool way_builder_t::check_crossing(const koord zv, const grund_t *bd, waytype_t wtyp0, const player_t *player) const { const waytype_t wtyp = wtyp0==tram_wt ? track_wt : wtyp0; // nothing to cross here if (!bd->hat_wege()) { return true; } // no triple crossings please if (bd->has_two_ways() && !bd->hat_weg(wtyp)) { return false; } const weg_t *w = bd->get_weg_nr(0); const uint8 iwtyp = w->get_waytype() != wtyp; // index of our wtype at the tile (must exist due to triple-crossing-check above) // get the other way if(iwtyp==0) { w = bd->get_weg_nr(1); // no other way here if (w==NULL) { return true; } } // special case: tram track on road if ( (wtyp==road_wt && w->get_waytype()==track_wt && w->get_desc()->get_styp()==type_tram) || (wtyp0==tram_wt && w->get_waytype()==road_wt) ) { return true; } // right owner of the other way // exception: allow if we want to build road and road already exists, since this is passable for us if(!check_owner(w->get_owner(),player) && ! (wtyp==road_wt && bd->has_two_ways()) ) { return false; } // check for existing crossing crossing_t *cr = bd->find(); if (cr) { // index of the waytype in ns-direction at the crossing const uint8 ns_way = cr->get_dir(); // only cross with the right direction return (ns_way==iwtyp ? ribi_t::is_straight_ns(ribi_type(zv)) : ribi_t::is_straight_ew(ribi_type(zv))); } // no crossings in tunnels if((bautyp & tunnel_flag)!=0 || bd->ist_tunnel()) { return false; } // no crossings on elevated ways if((bautyp & elevated_flag)!=0 || bd->get_typ()==grund_t::monorailboden) { return false; } // crossing available and ribis ok if(crossing_logic_t::get_crossing(wtyp, w->get_waytype(), desc ? desc->get_topspeed() : 0, w->get_max_speed(), welt->get_timeline_year_month())!=NULL) { const ribi_t::ribi w_ribi = w->get_ribi_unmasked(); // it is our way we want to cross: can we build a crossing here? // both ways must be straight and no ends return ribi_t::is_straight(w_ribi) && !ribi_t::is_single(w_ribi) && ribi_t::is_straight(ribi_type(zv)) && (w_ribi&ribi_type(zv))==0; } // cannot build crossing here return false; } /** crossing of powerlines, or no powerline */ bool way_builder_t::check_powerline(const koord zv, const grund_t *bd) const { if(zv==koord(0,0)) { return true; } leitung_t* lt = bd->find(); if(lt!=NULL) { ribi_t::ribi lt_ribi = lt->get_ribi(); // it is our way we want to cross: can we build a crossing here? // both ways must be straight and no ends return ribi_t::is_straight(lt_ribi) && !ribi_t::is_single(lt_ribi) && ribi_t::is_straight(ribi_type(zv)) && (lt_ribi&ribi_type(zv))==0 && !bd->ist_tunnel(); } // check for transformer if (bd->find() != NULL || bd->find() != NULL) { return false; } // ok, there is not high power transmission stuff going on here return true; } // allowed slope? bool way_builder_t::check_slope( const grund_t *from, const grund_t *to ) { const koord from_pos=from->get_pos().get_2d(); const koord to_pos=to->get_pos().get_2d(); const koord zv=to_pos-from_pos; if( !desc->has_double_slopes() && ( (from->get_weg_hang() && !is_one_high(from->get_weg_hang())) || (to->get_weg_hang() && !is_one_high(to->get_weg_hang())) ) ) { return false; } if(from==to) { if(!slope_t::is_way(from->get_weg_hang())) { return false; } } else { if(from->get_weg_hang()!=slope_t::flat && ribi_t::doubles(ribi_type(from->get_weg_hang()))!=ribi_t::doubles(ribi_type(zv))) { return false; } if(to->get_weg_hang()!=slope_t::flat && ribi_t::doubles(ribi_type(to->get_weg_hang()))!=ribi_t::doubles(ribi_type(zv))) { return false; } } return true; } // allowed owner? bool way_builder_t::check_owner( const player_t *player1, const player_t *player2 ) const { // unowned, mine or public property or superuser ... ? return player1==NULL || player1==player2 || player1==welt->get_public_player() || player2==welt->get_public_player(); } /// do not go through depots, station buildings etc. /// direction results from layout bool way_builder_t::check_building( const grund_t *to, const koord dir ) const { if( dir==koord(0,0) || to->first_no_way_obj()==0 ) { return true; } // first find all kind of buildings gebaeude_t *building = to->find(); if(building==NULL) { // but depots might be overlooked ... depot_t* depot = to->get_depot(); // no road to tram depot and vice-versa if (depot) { if ( (waytype_t)(bautyp&bautyp_mask) != depot->get_waytype() ) { return false; } } building = depot; } // check, if we may enter if(building) { // now check for directions uint8 layouts = building->get_tile()->get_desc()->get_all_layouts(); uint8 layout = building->get_tile()->get_layout(); ribi_t::ribi r = ribi_type(dir); if( layouts&1 ) { return false; } if( layouts==4 ) { return r == ribi_t::layout_to_ribi[layout]; } return ribi_t::is_straight( r | ribi_t::doubles(ribi_t::layout_to_ribi[layout&1]) ); } return true; } // helper function for building parallel ways bool way_builder_t::has_neighbour_with_way(koord3d pos, waytype_t wt) const { for (int i = 0; i < 8; i++) { if (grund_t* gr = welt->lookup(pos + koord::neighbours[i])) { if (gr->get_weg(wt)) { return true; } } } return false; } /** * This is the core routine for the way search * it will check * A) allowed step * B) if allowed, calculate the cost for the step from from to to */ bool way_builder_t::is_allowed_step(const grund_t *from, const grund_t *to, sint32 *costs, bool is_upperlayer ) { const koord from_pos = from->get_pos().get_2d(); const koord to_pos = to->get_pos().get_2d(); const koord zv = to_pos-from_pos; // fake empty elevated tiles static monorailboden_t from_dummy(koord3d::invalid, slope_t::flat); static monorailboden_t to_dummy(koord3d::invalid, slope_t::flat); if (desc == NULL) { return false; } if(bautyp==luft && (from->get_grund_hang()+to->get_grund_hang()!=0 || (from->hat_wege() && from->hat_weg(air_wt)==0) || (to->hat_wege() && to->hat_weg(air_wt)==0))) { // absolutely no slopes for runways, neither other ways return false; } bool to_flat = false; // to tile will be flattened if(from==to) { if((bautyp&tunnel_flag) && !slope_t::is_way(from->get_weg_hang())) { return false; } } else { // check slopes bool ok_slope = from->get_weg_hang() == slope_t::flat || ribi_t::doubles(ribi_type(from->get_weg_hang()))==ribi_t::doubles(ribi_type(zv)); ok_slope &= to->get_weg_hang() == slope_t::flat || ribi_t::doubles(ribi_type(to->get_weg_hang()))==ribi_t::doubles(ribi_type(zv)); // try terraforming if (!ok_slope) { uint8 dummy,to_slope; if ( (bautyp & terraform_flag) != 0 && from->ist_natur() && to->ist_natur() && check_terraforming(from,to,&dummy,&to_slope) ) { to_flat = to_slope == slope_t::flat; } else { // slopes not ok and no terraforming possible return false; } } } // ok, slopes are ok bool ok = true; // check scenario conditions if (welt->get_scenario()->is_work_allowed_here(player_builder, (bautyp&tunnel_flag ? TOOL_BUILD_TUNNEL : TOOL_BUILD_WAY)|GENERAL_TOOL, bautyp&bautyp_mask, desc->get_name(), to->get_pos()) != NULL) { return false; } // universal check for elevated things ... if(bautyp&elevated_flag) { if( is_upperlayer ) { if( (to->get_typ() != grund_t::monorailboden || to->get_weg_nr(0)->get_desc()->get_wtyp()!=desc->get_wtyp() || !check_owner(to->obj_bei(0)->get_owner(),player_builder) ) || (from->get_typ() != grund_t::monorailboden || from->get_weg_nr(0)->get_desc()->get_wtyp()!=desc->get_wtyp() || !check_owner(from->obj_bei(0)->get_owner(),player_builder) ) ) { return false; } } else { if( to->hat_weg(air_wt) || welt->lookup_hgt( to_pos ) < welt->get_water_hgt( to_pos ) || !check_powerline( zv, to ) || (!to->ist_karten_boden() && to->get_typ() != grund_t::monorailboden) || to->get_typ() == grund_t::brueckenboden || to->get_typ() == grund_t::tunnelboden ) { // no suitable ground below! return false; } gebaeude_t *gb = to->find(); if(gb==NULL) { // but depots might be overlooked ... gb = to->get_depot(); } if(gb) { // no halt => citybuilding => do not touch // also check for too high buildings ... if(!check_owner(gb->get_owner(),player_builder) || gb->get_tile()->get_background(0,1,0)!=IMG_EMPTY) { return false; } // building above houses is expensive ... avoid it! *costs += 4; } // absolutely nothing allowed here for set which want double clearance if( welt->get_settings().get_way_height_clearance()==2 && welt->lookup( to->get_pos()+koord3d(0,0,1) ) ) { return false; } // up to now 'to' and 'from' referred to the ground one height step below the elevated way // now get the grounds at the right height koord3d pos = to->get_pos() + koord3d( 0, 0, welt->get_settings().get_way_height_clearance() ); grund_t *to2 = welt->lookup(pos); if(to2) { if(to2->get_weg_nr(0)) { // already an elevated ground here => it will have always a way object, that indicates ownership ok = to2->get_typ()==grund_t::monorailboden && check_owner(to2->obj_bei(0)->get_owner(),player_builder); ok &= to2->get_weg_nr(0)->get_desc()->get_wtyp()==desc->get_wtyp(); } else { ok = to2->find()==NULL; } if (!ok) { return false; } to = to2; } else { // simulate empty elevated tile to_dummy.set_pos(pos); to_dummy.set_grund_hang(to->get_grund_hang()); to = &to_dummy; } pos = from->get_pos() + koord3d( 0, 0, welt->get_settings().get_way_height_clearance() ); grund_t *from2 = welt->lookup(pos); if(from2) { from = from2; } else { // simulate empty elevated tile from_dummy.set_pos(pos); from_dummy.set_grund_hang(from->get_grund_hang()); from = &from_dummy; } // now 'from' and 'to' point to grounds at the right height } } if( welt->get_settings().get_way_height_clearance()==2 ) { // cannot build if conversion factor 2, we aren't powerline and way with maximum speed > 0 or powerline 1 tile below grund_t *to2 = welt->lookup( to->get_pos() + koord3d(0, 0, -1) ); if( to2 && (((bautyp&bautyp_mask)!=leitung && to2->get_weg_nr(0) && to2->get_weg_nr(0)->get_desc()->get_topspeed()>0) || to2->get_leitung()) ) { return false; } // tile above cannot have way unless we are a way (not powerline) with a maximum speed of 0, or be surface if we are underground to2 = welt->lookup( to->get_pos() + koord3d(0, 0, 1) ); if( to2 && ((to2->get_weg_nr(0) && (desc->get_topspeed()>0 || (bautyp&bautyp_mask)==leitung)) || (bautyp & tunnel_flag) != 0) ) { return false; } } if ((zv.x | zv.y) != 0) { // the forrowing checks make only sense if we actually connect two tiles // universal check for depots/stops/... if( !check_building( from, zv ) || !check_building( to, -zv ) ) { warn_fail = translator::translate("A building blocks the construction"); return false; } // universal check for bridges: enter bridges in bridge direction if( from->get_typ()==grund_t::brueckenboden ) { if (weg_t *w = from->get_weg((waytype_t)(bautyp_mask & bautyp))) { if (ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(w->get_ribi_unmasked())) { return false; } } if ((bautyp_mask & bautyp)==leitung && from->get_leitung()) { if (ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(from->get_leitung()->get_ribi())) { return false; } } } if( to->get_typ()==grund_t::brueckenboden ) { if (weg_t* w = to->get_weg((waytype_t)(bautyp_mask & bautyp))) { if (ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(w->get_ribi_unmasked())) { return false; } } if ((bautyp_mask & bautyp) == leitung && to->get_leitung()) { if (ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(to->get_leitung()->get_ribi())) { return false; } } } } // universal check: do not switch to tunnel through cliffs! if( from->get_typ()==grund_t::tunnelboden && to->get_typ() != grund_t::tunnelboden && !from->ist_karten_boden() ) { return false; } if( to->get_typ()==grund_t::tunnelboden && from->get_typ() != grund_t::tunnelboden && !to->ist_karten_boden() ) { return false; } // do not connect to the side of a sloped elevated way if the ground is flat if (from->get_typ() == grund_t::monorailboden && to->get_typ() != grund_t::monorailboden && !from->ist_karten_boden()) { // we try to connect to an elevated way. For bridges, only allowed, if both are parallel if (to->get_typ() == grund_t::brueckenboden) { weg_t* w = to->get_weg(desc->get_wtyp()); if (!w || ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(w->get_ribi_unmasked()) ) { // we are not allowed to connect here return false; } } } if (to->get_typ() == grund_t::monorailboden && from->get_typ() != grund_t::monorailboden && !to->ist_karten_boden()) { // we try to connect to an elevated way. For bridges, only allowed, if both are parallel if (from->get_typ() == grund_t::brueckenboden) { weg_t* w = to->get_weg(desc->get_wtyp()); if (!w || ribi_t::doubles(ribi_t::ribi(ribi_type(zv))) != ribi_t::doubles(w->get_ribi_unmasked())) { // we are not allowed to connect here return false; } } } // universal check for crossings if (to!=from && (bautyp&bautyp_mask)!=leitung) { waytype_t const wtyp = (bautyp == river) ? water_wt : (waytype_t)(bautyp & bautyp_mask); if(!check_crossing(zv,to,wtyp,player_builder) || !check_crossing(-zv,from,wtyp,player_builder)) { warn_fail = translator::translate("No suitable crossing"); return false; } } // universal check for building under powerlines if ((bautyp&bautyp_mask)!=leitung) { if (!check_powerline(zv,to) || !check_powerline(-zv,from)) { return false; } } bool fundament = to->get_typ()==grund_t::fundament; // now check way specific stuff settings_t const& s = welt->get_settings(); switch(bautyp&bautyp_mask) { case strasse: { const weg_t *str=to->get_weg(road_wt); // we allow connection to any road ok = (str || !fundament) && !to->is_water(); if(!ok) { return false; } // check for end/start of bridge or tunnel // fail if no proper way exists, or the way's ribi are not 0 and are not matching the slope type ribi_t::ribi test_ribi = (str ? str->get_ribi_unmasked() : 0) | ribi_type(zv); if(to->get_weg_hang()!=to->get_grund_hang() && (str==NULL || !(ribi_t::is_straight(test_ribi) || test_ribi==0 ))) { return false; } // test if we are next to a way if (!str && prefer_parallel) { if (to->get_weg(road_wt)) { // we have to join? make it expensive *costs = s.way_count_leaving_way; } else if (has_neighbour_with_way(from->get_pos(), road_wt)) { // we are parallel => make it cheap *costs = s.way_count_straight; } else { // new way not parallel to an existing *costs = s.way_count_no_way; } } else { // calculate costs *costs = (!str ^ prefer_parallel) ? s.way_count_no_way : s.way_count_straight; } if((!str && to->hat_wege()) || (str && to->has_two_ways())) { *costs += s.way_count_avoid_crossings; // avoid crossings } if (to->get_weg_hang() != 0 && !to_flat) { *costs += s.way_count_slope; } } break; case schiene: default: { waytype_t wt = desc->get_wtyp(); const weg_t *sch=to->get_weg(wt); // extra check for AI construction (not adding to existing tracks!) if((bautyp&bot_flag)!=0 && (sch || to->get_halt().is_bound())) { return false; } // ok, regular construction here // if no way there: check for right ground type, otherwise check owner ok = sch==NULL ? (!fundament && !to->is_water()) : check_owner(sch->get_owner(),player_builder); if(!ok) { return false; } // check for end/start of bridge or tunnel // fail if no proper way exists, or the way's ribi are not 0 and are not matching the slope type ribi_t::ribi test_ribi = (sch ? sch->get_ribi_unmasked() : 0) | ribi_type(zv); if(to->get_weg_hang()!=to->get_grund_hang() && (sch==NULL || !(ribi_t::is_straight(test_ribi) || test_ribi==0 ))) { return false; } // test if we are next to a way if (!sch && prefer_parallel) { if (to->get_weg(wt)) { // we have to join? make it expensive *costs = s.way_count_leaving_way; } else if (has_neighbour_with_way(from->get_pos(), wt)) { // we are parallel => make it cheap *costs = s.way_count_straight; } else { // new way not parallel to an existing *costs = s.way_count_no_way; } } else { // calculate costs *costs = (!sch ^ prefer_parallel) ? s.way_count_no_way : s.way_count_straight; } if((sch && to->has_two_ways()) || (!sch && to->hat_wege())) { *costs += s.way_count_avoid_crossings; // avoid crossings } if(to->get_weg_hang()!=0 && !to_flat) { *costs += s.way_count_slope; } } break; case schiene_tram: // Dario: Tramway { const weg_t *sch=to->get_weg(track_wt); // roads are checked in check_crossing // if no way there: check for right ground type, otherwise check owner ok = sch==NULL ? (!fundament && !to->is_water()) : check_owner(sch->get_owner(),player_builder); // tram track allowed in road tunnels, but only along existing roads / tracks if(from!=to) { if(from->ist_tunnel()) { const ribi_t::ribi ribi = from->get_weg_ribi_unmasked(road_wt) | from->get_weg_ribi_unmasked(track_wt) | ribi_t::doubles(ribi_type(from->get_grund_hang())); ok = ok && ((ribi & ribi_type(zv))==ribi_type(zv)); } if(to->ist_tunnel()) { const ribi_t::ribi ribi = to->get_weg_ribi_unmasked(road_wt) | to->get_weg_ribi_unmasked(track_wt) | ribi_t::doubles(ribi_type(to->get_grund_hang())); ok = ok && ((ribi & ribi_type(-zv))==ribi_type(-zv)); } } if(ok) { // calculate costs *costs += sch ? s.way_count_straight : s.way_count_no_way; // prefer own track a little more if(to->hat_weg(road_wt)) { *costs += s.way_count_straight; } if(to->get_weg_hang()!=0 && !to_flat) { *costs += s.way_count_slope; } } } break; case leitung: ok = !to->is_water() && (to->get_weg(air_wt)==NULL); ok &= !(to->ist_tunnel() && to->hat_wege()); if(to->get_weg_nr(0)!=NULL) { // only 90 deg crossings, only a single way ribi_t::ribi w_ribi= to->get_weg_nr(0)->get_ribi_unmasked(); ok &= ribi_t::is_straight(w_ribi) && !ribi_t::is_single(w_ribi) && ribi_t::is_straight(ribi_type(zv)) && (w_ribi&ribi_type(zv))==0; } if(to->has_two_ways()) { // only 90 deg crossings, only for trams ... ribi_t::ribi w_ribi= to->get_weg_nr(1)->get_ribi_unmasked(); ok &= ribi_t::is_straight(w_ribi) && !ribi_t::is_single(w_ribi) && ribi_t::is_straight(ribi_type(zv)) && (w_ribi&ribi_type(zv))==0; } // do not connect to other powerlines { leitung_t *lt = to->get_leitung(); ok &= (lt==NULL) || check_owner(player_builder, lt->get_owner()); } if(to->get_typ()!=grund_t::tunnelboden) { // only fields are allowed if(to->get_typ()==grund_t::fundament) { ok &= to->find()!=NULL; } // no bridges and monorails here in the air ok &= (welt->access(to_pos)->get_boden_in_hoehe(to->get_pos().z+1)==NULL); } // calculate costs if(ok) { *costs = s.way_count_straight; if( !to->get_leitung() ) { // extra malus for not following an existing line or going on ways *costs += s.way_count_leaving_way + (to->hat_wege() ? s.way_count_avoid_crossings : 0); // prefer existing powerlines } } break; case wasser: { const weg_t *canal = to->get_weg(water_wt); // if no way there: check for right ground type, otherwise check owner ok = canal || !fundament; // calculate costs if(ok) { if (to->is_water()) { *costs = 0; // prefer water very much } else if (canal) { *costs = s.way_count_straight; // next prefer existing canal } else { *costs = s.way_count_leaving_way; // new canal very expensive } if(to->get_weg_hang()!=0 && !to_flat) { *costs += s.way_count_slope * 2; } } break; } case river: if( to->is_water() ) { ok = true; // do not care while in ocean *costs = 1; } else { // only downstream ok = from->get_pos().z>=to->get_pos().z && (to->hat_weg(water_wt) || !to->hat_wege()); // calculate costs if(ok) { // prefer existing rivers: *costs = to->hat_weg(water_wt) ? 10 : 10+simrand(s.way_count_90_curve); if(to->get_weg_hang()!=0 && !to_flat) { *costs += s.way_count_slope * 10; } } } break; case luft: // runway { const weg_t *w = to->get_weg(air_wt); if( w && w->get_desc()->get_styp()==type_runway && desc->get_styp()!=type_runway && ribi_t::is_single(w->get_ribi_unmasked()) ) { // cannot go over the end of a runway with a taxiway return false; } ok = !to->is_water() && (w || !to->hat_wege()) && to->find()==NULL && !fundament; // calculate costs *costs = s.way_count_straight; } break; } return ok; } bool way_builder_t::check_terraforming( const grund_t *from, const grund_t *to, uint8* new_from_slope, uint8* new_to_slope) const { // only for normal green tiles const slope_t::type from_slope = from->get_weg_hang(); const slope_t::type to_slope = to->get_weg_hang(); const sint8 from_hgt = from->get_hoehe(); const sint8 to_hgt = to->get_hoehe(); // we may change slope of a tile if it is sloped already if( (from_slope == slope_t::flat || from->get_hoehe() == welt->get_water_hgt( from->get_pos().get_2d() )) && (to_slope == slope_t::flat || to->get_hoehe() == welt->get_water_hgt( to->get_pos().get_2d() )) ) { return false; } else if( abs( from_hgt - to_hgt ) <= (desc->has_double_slopes() ? 2 : 1) ) { // extra check for double heights if( abs( from_hgt - to_hgt) == 2 && (welt->lookup( from->get_pos() - koord3d(0,0,2) ) != NULL || welt->lookup( from->get_pos() + koord3d(0, 0, 2) ) != NULL || welt->lookup( to->get_pos() - koord3d(0, 0, 2) ) != NULL || welt->lookup( to->get_pos() + koord3d(0, 0, 2) ) != NULL) ) { return false; } // monorail above / tunnel below if (welt->lookup(from->get_pos() - koord3d(0,0,1))!=NULL || welt->lookup(from->get_pos() + koord3d(0,0,1))!=NULL || welt->lookup(to->get_pos() - koord3d(0,0,1))!=NULL || welt->lookup(to->get_pos() + koord3d(0,0,1))!=NULL) { return false; } // can safely change slope of at least one of the tiles if (new_from_slope == NULL) { return true; } // now calculate new slopes assert(new_from_slope); assert(new_to_slope); // direction of way const koord dir = (to->get_pos() - from->get_pos()).get_2d(); sint8 start = from_hgt * 2; sint8 middle = from_hgt * 2; sint8 end = to_hgt * 2; // get 3 heights - start (min start from, but should be same), middle (average end from/average start to), end (min end to) if( dir == koord::north ) { start += corner_sw(from_slope) + corner_se(from_slope); middle += corner_ne(from_slope) + corner_nw(from_slope); end += corner_ne(to_slope) + corner_nw(to_slope); } else if( dir == koord::east ) { start += corner_sw(from_slope) + corner_nw(from_slope); middle += corner_se(from_slope) + corner_ne(from_slope); end += corner_se(to_slope) + corner_ne(to_slope); } else if( dir == koord::south ) { start += corner_ne(from_slope) + corner_nw(from_slope); middle += corner_sw(from_slope) + corner_se(from_slope); end += corner_sw(to_slope) + corner_se(to_slope); } else if( dir == koord::west ) { start += corner_se(from_slope) + corner_ne(from_slope); middle += corner_sw(from_slope) + corner_nw(from_slope); end += corner_sw(to_slope) + corner_nw(to_slope); } // work out intermediate height: if( end == start ) { middle = start; } else { // end < start to ist wegbar?assert from ist_wegbar:middle = end + 1 // end > start to ist wegbar?assert from ist_wegbar:middle = end - 1 if( !slope_t::is_way( to_slope ) ) { middle = (start + end) / 2; } } // prevent middle being invalid if( middle >> 1 > from_hgt + 2 ) { middle = (from_hgt + 2) * 2; } if( middle >> 1 > to_hgt + 2 ) { middle = (to_hgt + 2) * 2; } if( middle >> 1 < from_hgt ) { middle = from_hgt * 2; } if( middle >> 1 < to_hgt ) { middle = to_hgt * 2; } const uint8 m_from = (middle >> 1) - from_hgt; const uint8 m_to = (middle >> 1) - to_hgt; // write middle heights if( dir == koord::north ) { *new_from_slope = encode_corners(corner_sw(from_slope), corner_se(from_slope), m_from, m_from); *new_to_slope = encode_corners(m_to, m_to, corner_ne(to_slope), corner_nw(to_slope)); } else if( dir == koord::east ) { *new_from_slope = encode_corners(corner_sw(from_slope), m_from, m_from, corner_nw(from_slope)); *new_to_slope = encode_corners(m_to, corner_se(to_slope), corner_ne(to_slope), m_to); } else if( dir == koord::south ) { *new_from_slope = encode_corners(m_from, m_from, corner_ne(from_slope), corner_nw(from_slope)); *new_to_slope = encode_corners(corner_sw(to_slope), corner_se(to_slope), m_to, m_to); } else if( dir == koord::west ) { *new_from_slope = encode_corners(m_from, corner_se(from_slope), corner_ne(from_slope), m_from); *new_to_slope = encode_corners(corner_sw(to_slope), m_to, m_to, corner_nw(to_slope)); } return true; } return false; } void way_builder_t::do_terraforming() { uint32 last_terraformed = terraform_index.get_count(); for(uint32 const i : terraform_index) { // index in route grund_t *from = welt->lookup(route[i]); uint8 from_slope = from->get_grund_hang(); grund_t *to = welt->lookup(route[i+1]); uint8 to_slope = to->get_grund_hang(); // calculate new slopes check_terraforming(from, to, &from_slope, &to_slope); bool changed = false; // change slope of from if( from_slope != from->get_grund_hang() ) { if( from_slope == slope_t::all_up_two ) { from->set_hoehe( from->get_hoehe() + 2 ); from->set_grund_hang( slope_t::flat ); route[i].z = from->get_hoehe(); } else if( from_slope != slope_t::all_up_one ) { // bit of a hack to recognise single height slopes shifted up 1 if( from_slope > slope_t::all_up_one && slope_t::is_single( from_slope-slope_t::all_up_one ) ) { from->set_hoehe( from->get_hoehe() + 1 ); from_slope -= slope_t::all_up_one; route[i].z = from->get_hoehe(); } from->set_grund_hang( from_slope ); } else { from->set_hoehe( from->get_hoehe() + 1 ); from->set_grund_hang( slope_t::flat ); route[i].z = from->get_hoehe(); } changed = true; if (last_terraformed != i) { // charge player player_t::book_construction_costs(player_builder, welt->get_settings().cst_set_slope, from->get_pos().get_2d(), ignore_wt); } } // change slope of to if( to_slope != to->get_grund_hang() ) { if( to_slope == slope_t::all_up_two ) { to->set_hoehe( to->get_hoehe() + 2 ); to->set_grund_hang( slope_t::flat ); route[i + 1].z = to->get_hoehe(); } else if( to_slope != slope_t::all_up_one ) { // bit of a hack to recognise single height slopes shifted up 1 if( to_slope > slope_t::all_up_one && slope_t::is_single( to_slope-slope_t::all_up_one ) ) { to->set_hoehe( to->get_hoehe() + 1 ); to_slope -= slope_t::all_up_one; route[i + 1].z = to->get_hoehe(); } to->set_grund_hang(to_slope); } else { to->set_hoehe( to->get_hoehe() + 1); to->set_grund_hang(slope_t::flat); route[i+1].z = to->get_hoehe(); } changed = true; // charge player player_t::book_construction_costs(player_builder, welt->get_settings().cst_set_slope, to->get_pos().get_2d(), ignore_wt); last_terraformed = i+1; // do not pay twice for terraforming one tile } // recalc slope image of neighbors if (changed) { for(uint8 j=0; j<2; j++) { for(uint8 x=0; x<2; x++) { for(uint8 y=0; y<2; y++) { grund_t *gr = welt->lookup_kartenboden(route[i+j].get_2d()+koord(x,y)); if (gr) { gr->calc_image(); } } } } } } } void way_builder_t::check_for_bridge(const grund_t* parent_from, const grund_t* from, const vector_tpl &ziel) { // wrong starting slope or tile already occupied with a way ... if (!slope_t::is_way(from->get_grund_hang())) { return; } /* * now check existing ways: * no tunnels/bridges at crossings and no track tunnels/bridges on roads (but road tunnels/bridges on tram are allowed). * (keep in mind, that our waytype isn't currently on the tile and will be built later) */ const weg_t *way0 = from->get_weg_nr(0); const weg_t *way1 = from->get_weg_nr(1); if( way0 ) { switch( bautyp&bautyp_mask ) { case schiene_tram: case strasse: { const weg_t *other = way1; if ( way0->get_waytype() != desc->get_wtyp() ) { if ( way1 ) { // two different ways return; } other = way0; } if ( other ) { if ( (bautyp&bautyp_mask) == strasse ) { if ( other->get_waytype() != track_wt || other->get_desc()->get_styp()!=type_tram ) { // road only on tram return; } } else { if ( other->get_waytype() != road_wt ) { // tram only on road return; } } } } /* FALLTHROUGH */ default: if (way0->get_waytype()!=desc->get_wtyp() || way1!=NULL) { // no other ways allowed return; } } } const koord zv=from->get_pos().get_2d()-parent_from->get_pos().get_2d(); const ribi_t::ribi ribi = ribi_type(zv); // now check ribis of existing ways const ribi_t::ribi wayribi = way0 ? way0->get_ribi_unmasked() | (way1 ? way1->get_ribi_unmasked() : (ribi_t::ribi)ribi_t::none) : (ribi_t::ribi)ribi_t::none; if ( wayribi & (~ribi) ) { // curves at bridge start return; } // ok, so now we do a closer investigation if( bridge_desc && ( ribi_type(from->get_grund_hang()) == ribi_t::backward(ribi_type(zv)) || from->get_grund_hang() == 0 ) && bridge_builder_t::can_place_ramp(player_builder, from, desc->get_wtyp(),ribi_t::backward(ribi_type(zv))) ) { // Try a bridge. const sint32 cost_difference = desc->get_maintenance() > 0 ? (bridge_desc->get_maintenance() * 4l + 3l) / desc->get_maintenance() : 16; // try eight possible lengths .. uint32 min_length = 1; for (uint8 i = 0; i < 8 && min_length <= welt->get_settings().way_max_bridge_len; ++i) { sint8 bridge_height; const char *error = NULL; koord3d end = bridge_builder_t::find_end_pos( player_builder, from->get_pos(), zv, bridge_desc, error, bridge_height, true, min_length ); const grund_t* gr_end = welt->lookup(end); if( gr_end == NULL) { // no valid end point found min_length++; continue; } uint32 length = koord_distance(from->get_pos(), end); if(!ziel.is_contained(end) && bridge_builder_t::can_place_ramp(player_builder, gr_end, desc->get_wtyp(), ribi_type(zv))) { // If there is a slope on the starting tile, it's taken into account in is_allowed_step, but a bridge will be flat! sint8 num_slopes = (from->get_grund_hang() == slope_t::flat) ? 1 : -1; // On the end tile, we haven't to subtract way_count_slope, since is_allowed_step isn't called with this tile. num_slopes += (gr_end->get_grund_hang() == slope_t::flat) ? 1 : 0; next_gr.append(next_gr_t(welt->lookup(end), length * cost_difference + num_slopes*welt->get_settings().way_count_slope, build_straight | build_tunnel_bridge)); min_length = length+1; } else { break; } } return; } if( tunnel_desc && ribi_type(from->get_grund_hang()) == ribi_type(zv) ) { // uphill hang ... may be tunnel? const sint32 cost_difference = desc->get_maintenance() > 0 ? (tunnel_desc->get_maintenance() * 4l + 3l) / desc->get_maintenance() : 16; koord3d end = tunnel_builder_t::find_end_pos( player_builder, from->get_pos(), zv, tunnel_desc); if( end != koord3d::invalid && !ziel.is_contained(end) ) { uint32 length = koord_distance(from->get_pos(), end); next_gr.append(next_gr_t(welt->lookup(end), length * cost_difference, build_straight | build_tunnel_bridge )); return; } } } way_builder_t::way_builder_t(player_t* player) : next_gr(32) , player_builder(player) , bautyp(strasse) // kann mit init_builder() gesetzt werden , keep_existing_ways(false) , keep_existing_faster_ways(false) , keep_existing_city_roads(false) , prefer_parallel(false) , build_sidewalk(false) { maximum = welt->get_settings().way_count_maximum; // building cost, (curves etc.) } /** * If a way is built on top of another way, should the type * of the former way be kept or replaced (true == keep) */ void way_builder_t::set_keep_existing_ways(bool yesno) { keep_existing_ways = yesno; keep_existing_faster_ways = false; } void way_builder_t::set_keep_existing_faster_ways(bool yesno) { keep_existing_ways = false; keep_existing_faster_ways = yesno; } void way_builder_t::init_builder(bautyp_t wt, const way_desc_t *b, const tunnel_desc_t *tunnel, const bridge_desc_t *br) { bautyp = wt; desc = b; bridge_desc = br; tunnel_desc = tunnel; if(wt&tunnel_flag && tunnel==NULL) { dbg->fatal("way_builder_t::init_builder()","needs a tunnel description for an underground route!"); } if((wt&bautyp_mask)==luft) { wt &= bautyp_mask | bot_flag; } if(player_builder==NULL) { bridge_desc = NULL; tunnel_desc = NULL; } else if( bautyp != river ) { #ifdef AUTOMATIC_BRIDGES if(!bridge_desc) { bridge_desc = bridge_builder_t::find_bridge(b->get_wtyp(), 25, welt->get_timeline_year_month()); } #endif #ifdef AUTOMATIC_TUNNELS if(!tunnel_desc) { tunnel_desc = tunnel_builder_t::get_tunnel_desc(b->get_wtyp(), 25, welt->get_timeline_year_month()); } #endif } DBG_MESSAGE("way_builder_t::init_builder()", "setting way type to %d, desc=%s, bridge_desc=%s, tunnel_desc=%s", bautyp, desc ? desc->get_name() : "NULL", bridge_desc ? bridge_desc->get_name() : "NULL", tunnel_desc ? tunnel_desc->get_name() : "NULL" ); } static void get_mini_maxi( const vector_tpl &ziel, koord3d &mini, koord3d &maxi ) { mini = maxi = ziel[0]; for(koord3d const& current : ziel) { if ( current.x < mini.x ) { mini.x = current.x; } else if( current.x > maxi.x ) { maxi.x = current.x; } if ( current.y < mini.y ) { mini.y = current.y; } else if( current.y > maxi.y ) { maxi.y = current.y; } if ( current.z < mini.z ) { mini.z = current.z; } else if( current.z > maxi.z ) { maxi.z = current.z; } } } /** * this routine uses A* to calculate the best route * beware: change the cost and you will mess up the system! * (but you can try, look at simuconf.tab) */ sint32 way_builder_t::intern_calc_route(const vector_tpl &start, const vector_tpl &ziel) { assert((get_random_mode() & SYNC_STEP_RANDOM) == 0); // we clear it here probably twice: does not hurt ... route.clear(); terraform_index.clear(); // check for existing koordinates bool has_target_ground = false; for(koord3d const& i : ziel) { has_target_ground |= welt->lookup(i) != 0; } if( !has_target_ground ) { return -1; } // check scenario conditions for start and endpoint for (koord3d const& pos : start) { if (welt->get_scenario()->is_work_allowed_here(player_builder, TOOL_BUILD_WAY | GENERAL_TOOL, bautyp & bautyp_mask, desc->get_name(), pos) != NULL) { return -1; } } for (koord3d const& pos : ziel) { if (welt->get_scenario()->is_work_allowed_here(player_builder, TOOL_BUILD_WAY | GENERAL_TOOL, bautyp & bautyp_mask, desc->get_name(), pos) != NULL) { return -1; } } // calculate the minimal cuboid containing 'ziel' koord3d mini, maxi; get_mini_maxi( ziel, mini, maxi ); // memory in static list ... if(route_t::nodes==NULL) { route_t::MAX_STEP = welt->get_settings().get_max_route_steps(); // may need very much memory => configurable route_t::nodes = new route_t::ANode[route_t::MAX_STEP+4+1]; } static binary_heap_tpl queue; // initialize marker field marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y); // clear the queue (should be empty anyhow) queue.clear(); // some thing for the search grund_t *to; koord3d gr_pos; // just the last valid pos ... route_t::ANode *tmp=NULL; uint32 step = 0; const grund_t* gr=NULL; for(koord3d const& i : start) { gr = welt->lookup(i); // is valid ground? sint32 dummy; if( !gr || !is_allowed_step(gr,gr,&dummy) ) { // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z); continue; } tmp = &(route_t::nodes[step]); step ++; tmp->parent = NULL; tmp->gr = gr; tmp->f = calc_distance(i, mini, maxi); tmp->g = 0; tmp->dir = 0; tmp->count = 0; queue.insert(tmp); } if( queue.empty() ) { // no valid ground to start. return -1; } INT_CHECK("wegbauer 347"); // get exclusively the tile list route_t::GET_NODE(); // to speed up search, but may not find all shortest ways uint32 min_dist = 99999999; //DBG_MESSAGE("route_t::itern_calc_route()","calc route from %d,%d,%d to %d,%d,%d",ziel.x, ziel.y, ziel.z, start.x, start.y, start.z); do { route_t::ANode *test_tmp = queue.pop(); if(marker.test_and_mark(test_tmp->gr)) { // we were already here on a faster route, thus ignore this branch // (trading speed against memory consumption) continue; } tmp = test_tmp; gr = tmp->gr; gr_pos = gr->get_pos(); #ifdef DEBUG_ROUTES DBG_DEBUG("insert to close","(%i,%i,%i) f=%i",gr->get_pos().x,gr->get_pos().y,gr->get_pos().z,tmp->f); #endif // already there if( ziel.is_contained(gr_pos) || tmp->g>maximum) { // we added a target to the closed list: we are finished break; } // the four possible directions plus any additional stuff due to already existing brides plus new ones ... next_gr.clear(); // only one direction allowed ... const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gr->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all; // test directions // .. use only those that are allowed by current slope // .. do not go backward const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gr->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gr->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none); const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir) : straight_dir; // testing all four possible directions for(ribi_t::ribi r=1; (r&16)==0; r<<=1) { if((r & test_dir)==0) { // not allowed to go this direction continue; } bool do_terraform = false; const koord zv(r); if(!gr->get_neighbour(to,invalid_wt,r) || !check_slope(gr, to)) { // slopes do not match // terraforming enabled? if (bautyp==river || (bautyp & terraform_flag) == 0) { continue; } // check terraforming (but not in curves) if (gr->get_grund_hang()==0 || (tmp->parent!=NULL && tmp->parent->parent!=NULL && r==straight_dir)) { to = welt->lookup_kartenboden(gr->get_pos().get_2d() + zv); if (to==NULL || (check_slope(gr, to) && gr->get_vmove(r)!=to->get_vmove(ribi_t::backward(r)))) { continue; } else { do_terraform = true; } } else { continue; } } // something valid? if(marker.is_marked(to)) { continue; } sint32 new_cost = 0; bool is_ok = is_allowed_step(gr,to,&new_cost); if(is_ok) { // now add it to the array ... next_gr.append(next_gr_t(to, new_cost, do_terraform ? build_straight | terraform : 0)); } else if(tmp->parent!=NULL && r==straight_dir && (tmp->count & build_tunnel_bridge)==0) { // try to build a bridge or tunnel here, since we cannot go here ... check_for_bridge(tmp->parent->gr,gr,ziel); } } // now check all valid ones ... for(next_gr_t const& r : next_gr) { to = r.gr; if( to==NULL) { continue; } // new values for cost g uint32 new_g = tmp->g + r.cost; settings_t const& s = welt->get_settings(); // check for curves (usually, one would need the lastlast and the last; // if not there, then we could just take the last uint8 current_dir; if(tmp->parent!=NULL) { current_dir = ribi_type( tmp->parent->gr->get_pos(), to->get_pos() ); if(tmp->dir!=current_dir) { new_g += s.way_count_curve; if(tmp->parent->dir!=tmp->dir) { // discourage double turns new_g += s.way_count_double_curve; } else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) { // discourage v turns heavily new_g += s.way_count_90_curve; } } else if(bautyp==leitung && ribi_t::is_bend(current_dir)) { new_g += s.way_count_double_curve; } // extra malus leave an existing road after only one tile waytype_t const wt = desc->get_wtyp(); if (tmp->parent->gr->hat_weg(wt) && !gr->hat_weg(wt) && to->hat_weg(wt)) { // but only if not straight track if(!ribi_t::is_straight(tmp->dir)) { new_g += s.way_count_leaving_way; } } } else { current_dir = ribi_type( gr->get_pos(), to->get_pos() ); } const uint32 new_dist = calc_distance( to->get_pos(), mini, maxi ); // special check for kinks at the end if(new_dist==0 && current_dir!=tmp->dir) { // discourage turn on last tile new_g += s.way_count_double_curve; } if (new_dist == 0 && r.flag & terraform) { // no terraforming near target continue; } if(new_distmin_dist+50) { // skip, if too far from current minimum tile // will not find some ways, but will be much faster ... // also it will avoid too big detours, which is probably also not the way, the builder intended continue; } const uint32 new_f = new_g+new_dist; if((step&0x03)==0) { INT_CHECK( "wegbauer 1347" ); #ifdef DEBUG_ROUTES if((step&1023)==0) {minimap_t::get_instance()->calc_map();} #endif } // not in there or taken out => add new route_t::ANode *k=&(route_t::nodes[step]); step++; k->parent = tmp; k->gr = to; k->g = new_g; k->f = new_f; k->dir = current_dir; // count is unused here, use it as flag-variable instead k->count = r.flag; queue.insert( k ); #ifdef DEBUG_ROUTES DBG_DEBUG("insert to open","(%i,%i,%i) f=%i",to->get_pos().x,to->get_pos().y,to->get_pos().z,k->f); #endif } } while (!queue.empty() && step < route_t::MAX_STEP); #ifdef DEBUG_ROUTES DBG_DEBUG("way_builder_t::intern_calc_route()","steps=%i (max %i) in route, open %i, cost %u",step,route_t::MAX_STEP,queue.get_count(),tmp->g); #endif INT_CHECK("wegbauer 194"); route_t::RELEASE_NODE(); // target reached? if( !ziel.is_contained(gr->get_pos()) || step>=route_t::MAX_STEP || tmp->parent==NULL || tmp->g > maximum ) { if (step>=route_t::MAX_STEP) { dbg->warning("way_builder_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,route_t::MAX_STEP); } return -1; } else { const sint32 cost = tmp->g; // reached => construct route while(tmp != NULL) { route.append(tmp->gr->get_pos()); if (tmp->count & terraform) { terraform_index.append(route.get_count()-1); } tmp = tmp->parent; } return cost; } } void way_builder_t::intern_calc_straight_route(const koord3d start, const koord3d ziel) { const koord3d koordup(0, 0, welt->get_settings().get_way_height_clearance()); sint32 dummy_cost; const grund_t *test_bd = welt->lookup(start); bool ok = false; if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost) ) { //there is a legal ground at the start ok = true; } if (ok && (bautyp&tunnel_flag) && !test_bd->ist_tunnel()) { return; // start tunnelbuilding in tunnels } if (bautyp&elevated_flag) { test_bd = welt->lookup(start + koordup); if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost, true) ) { //there is a legal way at the upper layer of start ok = true; } } if (!ok) { //target is not suitable return; } test_bd = welt->lookup(ziel); // we have to reach target height if no tunnel building or (target ground does not exists or is underground). // in full underground mode if there is no tunnel under cursor, kartenboden gets selected const bool target_3d = (bautyp&tunnel_flag)==0 || test_bd==NULL || !test_bd->ist_karten_boden(); if((bautyp&tunnel_flag)==0) { //same thing to the target point ok = false; if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost) ) { //there is a legal ground at the target ok = true; } if (bautyp&elevated_flag) { test_bd = welt->lookup(ziel + koordup); if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost, true) ) { //there is a legal way at the upper layer of the target ok = true; } } if(!ok) { return; } } koord3d pos=start; route.clear(); route.append(start); terraform_index.clear(); bool check_terraform = start.x==ziel.x || start.y==ziel.y; while(pos.get_2d()!=ziel.get_2d() && ok) { bool do_terraform = false; // shortest way ribi_t::ribi diff; if(abs(pos.x-ziel.x)>=abs(pos.y-ziel.y)) { diff = (pos.x>ziel.x) ? ribi_t::west : ribi_t::east; } else { diff = (pos.y>ziel.y) ? ribi_t::north : ribi_t::south; } if(bautyp&tunnel_flag) { // create fake tunnel grounds if needed bool bd_von_new = false, bd_nach_new = false; grund_t *bd_von = welt->lookup(pos); if( bd_von == NULL ) { bd_von = new tunnelboden_t(pos, slope_t::flat); bd_von_new = true; } // take care of slopes pos.z = bd_von->get_vmove(diff); // check next tile grund_t *bd_nach = welt->lookup(pos + diff); if( !bd_nach ) { // check for slope down ... bd_nach = welt->lookup(pos + diff + koord3d(0,0,-1)); if( !bd_nach ) { bd_nach = welt->lookup(pos + diff + koord3d(0,0,-2)); } if( bd_nach && bd_nach->get_weg_hang() == slope_t::flat ) { // Don't care about _flat_ tunnels below. bd_nach = NULL; } } if( bd_nach == NULL ){ bd_nach = new tunnelboden_t(pos + diff, slope_t::flat); bd_nach_new = true; } // check for tunnel and right slope ok = ok && bd_nach->ist_tunnel() && bd_nach->get_vmove(ribi_t::backward(diff))==pos.z; // all other checks are done here (crossings, stations etc) ok = ok && is_allowed_step(bd_von, bd_nach, &dummy_cost); // advance position pos = bd_nach->get_pos(); // check new tile: ground must be above tunnel and below sea grund_t *gr = welt->lookup_kartenboden(pos.get_2d()); ok = ok && (gr->get_hoehe() > pos.z) && (!gr->is_water() || (welt->lookup_hgt(pos.get_2d()) > pos.z) ); if (bd_von_new) { delete bd_von; } if (bd_nach_new) { delete bd_nach; } } else { grund_t *bd_von = welt->lookup(pos); ok = false; grund_t *bd_nach = NULL; if ( bd_von ) { if (bd_von->get_neighbour(bd_nach, invalid_wt, diff) && check_slope(bd_von, bd_nach)) { ok = true; } else { // slopes do not match // terraforming enabled? or able to follow upper layer? if ((bautyp==river || (bautyp & terraform_flag) == 0) && (bautyp&elevated_flag) == 0 ) { break; } // check terraforming (but not in curves) if (check_terraform) { bd_nach = welt->lookup_kartenboden(bd_von->get_pos().get_2d() + diff); if (bd_nach==NULL || (check_slope(bd_von, bd_nach) && bd_von->get_vmove(diff)!=bd_nach->get_vmove(ribi_t::backward(diff)))) { ok = false; } else { do_terraform = true; ok = true; } } } // allowed ground? ok = ok && bd_nach && is_allowed_step(bd_von,bd_nach,&dummy_cost); if (ok) { pos = bd_nach->get_pos(); } } // if failed if (!ok && bautyp&elevated_flag) { //search following the upper layer bd_von = welt->lookup(pos + koordup); if(bd_von && bd_von->get_neighbour(bd_nach, invalid_wt, diff) && check_slope(bd_von, bd_nach) && is_allowed_step(bd_von, bd_nach, &dummy_cost, true) ) { ok = true; pos = bd_nach->get_pos() - koordup; } } check_terraform = pos.x==ziel.x || pos.y==ziel.y; } route.append(pos); if (do_terraform) { terraform_index.append(route.get_count()-2); } DBG_MESSAGE("way_builder_t::calc_straight_route()","step %s = %i",koord(diff).get_str(),ok); } ok = ok && ( target_3d ? pos==ziel : pos.get_2d()==ziel.get_2d() ); // we can build a straight route? if(ok) { DBG_MESSAGE("way_builder_t::intern_calc_straight_route()","found straight route max_n=%i",get_count()-1); } else { route.clear(); terraform_index.clear(); } } /* this routine uses A* to calculate the best route * beware: change the cost and you will mess up the system! * (but you can try, look at simuconf.tab) */ /* It should not be river/airport/tunnel/bridge/terraformable */ sint32 way_builder_t::intern_calc_route_elevated(const koord3d start, const koord3d ziel) { // we clear it here probably twice: does not hurt ... route.clear(); terraform_index.clear(); const koord3d koordup(0, 0, welt->get_settings().get_way_height_clearance()); // check for existing koordinates const bool has_target_ground = welt->lookup(ziel) || welt->lookup(ziel + koordup); if( !has_target_ground ) { return -1; } // memory in static list ... if(route_t::nodes==NULL) { route_t::MAX_STEP = welt->get_settings().get_max_route_steps(); // may need very much memory => configurable route_t::nodes = new route_t::ANode[route_t::MAX_STEP+4+1]; } static binary_heap_tpl queue; // initialize marker field marker_t& markerbelow = marker_t::instance(welt->get_size().x, welt->get_size().y); marker_t& markerabove = marker_t::instance_second(welt->get_size().x, welt->get_size().y); // clear the queue (should be empty anyhow) queue.clear(); // some thing for the search grund_t *to; koord3d gr_pos; // just the last valid pos ... route_t::ANode *tmp=NULL; uint32 step = 0; const grund_t *gr=NULL, *gu = NULL; gr = welt->lookup(start); // is valid ground? sint32 dummy; if( gr && is_allowed_step(gr,gr,&dummy) ) { // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z); tmp = &(route_t::nodes[step]); step ++; tmp->parent = NULL; tmp->gr = gr; tmp->f = calc_distance(start, ziel, ziel); tmp->g = 0; tmp->dir = 0; tmp->count = 0; queue.insert(tmp); } gu = welt->lookup(start + koordup); if( gu && is_allowed_step(gu,gu,&dummy, true) ) { // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z); tmp = &(route_t::nodes[step]); step ++; tmp->parent = NULL; tmp->gr = gu; tmp->f = calc_distance(start, ziel, ziel); tmp->g = 0; tmp->dir = 0; tmp->count = is_upperlayer; queue.insert(tmp); } if( queue.empty() ) { // no valid ground to start. return -1; } INT_CHECK("wegbauer 347"); // get exclusively the tile list route_t::GET_NODE(); // to speed up search, but may not find all shortest ways uint32 min_dist = 99999999; //DBG_MESSAGE("route_t::itern_calc_route()","calc route from %d,%d,%d to %d,%d,%d",ziel.x, ziel.y, ziel.z, start.x, start.y, start.z); do { route_t::ANode *test_tmp = queue.pop(); if( (test_tmp->count&is_upperlayer?markerabove:markerbelow).test_and_mark(test_tmp->gr) ) { // we were already here on a faster route, thus ignore this branch // (trading speed against memory consumption) continue; } tmp = test_tmp; if(test_tmp->count & is_upperlayer) { gu = tmp->gr; gr_pos = gu->get_pos() - koordup; gr = welt->lookup(gr_pos); } else { gr = tmp->gr; gr_pos = gr->get_pos(); gu = welt->lookup(gr_pos + koordup); } #ifdef DEBUG_ROUTES DBG_DEBUG("insert to close","(%i,%i,%i) f=%i",gr->get_pos().x,gr->get_pos().y,gr->get_pos().z,tmp->f); #endif // already there if( ziel == gr_pos || tmp->g>maximum) { // we added a target to the closed list: we are finished break; } // the four possible directions plus any additional stuff due to already existing brides plus new ones ... next_gr.clear(); //search following the lower layer if(gr) { // only one direction allowed ... const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gr->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all; // test directions // .. use only those that are allowed by current slope // .. do not go backward const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gr->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gr->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none); const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir) : straight_dir; // testing all four possible directions for(ribi_t::ribi r=1; (r&16)==0; r<<=1) { if((r & test_dir)==0) { // not allowed to go this direction continue; } const koord zv(r); if(!gr->get_neighbour(to,invalid_wt,r) || !check_slope(gr, to)) { // slopes do not match continue; } // something valid? if(markerbelow.is_marked(to)) { continue; } sint32 new_cost = 0; bool is_ok = is_allowed_step(gr,to,&new_cost); if(is_ok) { // now add it to the array ... next_gr.append(next_gr_t(to, new_cost, 0)); } } } //search following the upper layer if(gu) { // only one direction allowed ... const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gu->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all; // test directions // .. use only those that are allowed by current slope // .. do not go backward const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gu->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gu->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none); const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir) : straight_dir; // testing all four possible directions for(ribi_t::ribi r=1; (r&16)==0; r<<=1) { if((r & test_dir)==0) { // not allowed to go this direction continue; } const koord zv(r); if(!gu->get_neighbour(to,invalid_wt,r) || !check_slope(gu, to)) { // slopes do not match continue; } // something valid? if(markerabove.is_marked(to)) { continue; } sint32 new_cost = 0; bool is_ok = is_allowed_step(gu,to,&new_cost, true); if(is_ok) { // now add it to the array ... next_gr.append(next_gr_t(to, new_cost, is_upperlayer)); } } } // now check all valid ones ... for(next_gr_t const& r : next_gr) { to = r.gr; if( to==NULL) { continue; } // new values for cost g uint32 new_g = tmp->g + r.cost; settings_t const& s = welt->get_settings(); // check for curves (usually, one would need the lastlast and the last; // if not there, then we could just take the last uint8 current_dir; if(tmp->parent!=NULL) { current_dir = ribi_type( tmp->parent->gr->get_pos(), to->get_pos() ); if(tmp->dir!=current_dir) { new_g += s.way_count_curve; if(tmp->parent->dir!=tmp->dir) { // discourage double turns new_g += s.way_count_double_curve; } else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) { // discourage v turns heavily new_g += s.way_count_90_curve; } } else if(bautyp==leitung && ribi_t::is_bend(current_dir)) { new_g += s.way_count_double_curve; } // extra malus leave an existing road after only one tile waytype_t const wt = desc->get_wtyp(); if (tmp->parent->gr->hat_weg(wt) && !(gr? gr: gu)->hat_weg(wt) && to->hat_weg(wt)) { // but only if not straight track if(!ribi_t::is_straight(tmp->dir)) { new_g += s.way_count_leaving_way; } } } else { current_dir = ribi_type( gr_pos, to->get_pos() ); } const uint32 new_dist = calc_distance( to->get_pos(), ziel, ziel ); // special check for kinks at the end if(new_dist==0 && current_dir!=tmp->dir) { // discourage turn on last tile new_g += s.way_count_double_curve; } if(new_distmin_dist+50) { // skip, if too far from current minimum tile // will not find some ways, but will be much faster ... // also it will avoid too big detours, which is probably also not the way, the builder intended continue; } const uint32 new_f = new_g+new_dist; if((step&0x03)==0) { INT_CHECK( "wegbauer 1347" ); #ifdef DEBUG_ROUTES if((step&1023)==0) {minimap_t::get_instance()->calc_map();} #endif } // not in there or taken out => add new route_t::ANode *k=&(route_t::nodes[step]); step++; k->parent = tmp; k->gr = to; k->g = new_g; k->f = new_f; k->dir = current_dir; // count is unused here, use it as flag-variable instead k->count = r.flag; queue.insert( k ); #ifdef DEBUG_ROUTES DBG_DEBUG("insert to open","(%i,%i,%i) f=%i",to->get_pos().x,to->get_pos().y,to->get_pos().z,k->f); #endif } } while (!queue.empty() && step < route_t::MAX_STEP); #ifdef DEBUG_ROUTES DBG_DEBUG("way_builder_t::intern_calc_route()","steps=%i (max %i) in route, open %i, cost %u",step,route_t::MAX_STEP,queue.get_count(),tmp->g); #endif INT_CHECK("wegbauer 194"); route_t::RELEASE_NODE(); // target reached? if( !(ziel == gr_pos) || step>=route_t::MAX_STEP || tmp->parent==NULL || tmp->g > maximum ) { if (step>=route_t::MAX_STEP) { dbg->warning("way_builder_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,route_t::MAX_STEP); } return -1; } else { const sint32 cost = tmp->g; // reached => construct route while(tmp != NULL) { if(tmp->count & is_upperlayer) { route.append(tmp->gr->get_pos() - koordup); } else { route.append(tmp->gr->get_pos() ); } tmp = tmp->parent; } return cost; } } // special for starting/landing runways bool way_builder_t::intern_calc_route_runways(koord3d start3d, const koord3d ziel3d) { route.clear(); terraform_index.clear(); const koord start=start3d.get_2d(); const koord ziel=ziel3d.get_2d(); // check for straight line! const ribi_t::ribi ribi = ribi_type( start, ziel ); if( !ribi_t::is_straight(ribi) ) { // only straight runways! warn_fail = "No curves on runways"; return false; } const ribi_t::ribi ribi_straight = ribi_t::doubles(ribi); // not too close to the border? if( !(welt->is_within_limits(start-koord(5,5)) && welt->is_within_limits(start+koord(5,5))) || !(welt->is_within_limits(ziel-koord(5,5)) && welt->is_within_limits(ziel+koord(5,5))) ) { if(player_builder==welt->get_active_player()) { create_win( new news_img("Zu nah am Kartenrand"), w_time_delete, magic_none); return false; } } // now try begin and endpoint const koord zv(ribi); // end start const grund_t *gr = welt->lookup_kartenboden(start); const weg_t *weg = gr->get_weg(air_wt); if(weg && !ribi_t::is_straight(weg->get_ribi()|ribi_straight) ) { // cannot connect with curve at the end return false; } if( weg && weg->get_desc()->get_styp()==type_flat ) { // could not continue taxiway with runway return false; } // check end gr = welt->lookup_kartenboden(ziel); weg = gr->get_weg(air_wt); if(weg && !ribi_t::is_straight(weg->get_ribi()|ribi_straight) ) { // cannot connect with curve at the end return false; } if( weg && weg->get_desc()->get_styp()==type_flat ) { // could not continue taxiway with runway return false; } // now try a straight line with no crossings and no curves at the end const int dist=koord_distance( ziel, start ); grund_t *from = welt->lookup_kartenboden(start); for( int i=0; i<=dist; i++ ) { grund_t *to = welt->lookup_kartenboden(start+zv*i); sint32 dummy; if (!is_allowed_step(from, to, &dummy)) { return false; } weg = to->get_weg(air_wt); if( weg && weg->get_desc()->get_styp()==type_runway && (ribi_t::is_threeway(weg->get_ribi_unmasked()|ribi_straight)) && (weg->get_ribi_unmasked()|ribi_straight)!=ribi_t::all ) { // only fourway crossings of runways allowed, no threeways => fail return false; } from = to; } // now we can build here route.clear(); terraform_index.clear(); route.reserve(dist + 2); for( int i=0; i<=dist; i++ ) { route.append(welt->lookup_kartenboden(start + zv * i)->get_pos()); } return true; } /* * calc_straight_route (maximum one curve, including diagonals) */ const char *way_builder_t::calc_straight_route(koord3d start, const koord3d ziel) { warn_fail = 0; DBG_MESSAGE("way_builder_t::calc_straight_route()","from %d,%d,%d to %d,%d,%d",start.x,start.y,start.z, ziel.x,ziel.y,ziel.z ); if(bautyp==luft && desc->get_styp()==type_runway) { // these are straight anyway ... intern_calc_route_runways(start, ziel); } else { intern_calc_straight_route(start,ziel); if (route.empty()) { intern_calc_straight_route(ziel,start); } } return warn_fail; } const char *way_builder_t::calc_route(const koord3d &start, const koord3d &ziel) { vector_tpl start_vec(1), ziel_vec(1); warn_fail = 0; start_vec.append(start); ziel_vec.append(ziel); calc_route(start_vec, ziel_vec); return warn_fail; } const char *way_builder_t::calc_route(const vector_tpl &start, const vector_tpl &ziel) { #ifdef DEBUG_ROUTES uint32 ms = dr_time(); #endif INT_CHECK("simbau 740"); warn_fail = 0; if(bautyp==luft && desc->get_styp()==type_runway) { assert( start.get_count() == 1 && ziel.get_count() == 1 ); intern_calc_route_runways(start[0], ziel[0]); } else if(bautyp==river) { assert( start.get_count() == 1 && ziel.get_count() == 1 ); // river only go downwards => start and end are clear ... if( start[0].z > ziel[0].z ) { intern_calc_route( start, ziel ); } else { intern_calc_route( ziel, start ); } while (route.get_count()>1 && welt->lookup(route[0])->get_grund_hang() == slope_t::flat && welt->lookup(route[1])->is_water()) { // remove leading water ... route.remove_at(0); } } else { keep_existing_city_roads |= (bautyp&bot_flag)!=0; sint32 cost2; if(desc->get_styp() == type_elevated) { cost2 = intern_calc_route_elevated(start[0], ziel[0]); INT_CHECK("wegbauer 1165"); if(cost2 < 0) { intern_calc_route_elevated(ziel[0], start[0]); return warn_fail; } } else { cost2 = intern_calc_route( start, ziel ); INT_CHECK("wegbauer 1165"); if(cost2 < 0) { intern_calc_route( ziel, start ); return warn_fail; } } #ifdef REVERSE_CALC_ROUTE_TOO vector_tpl route2(0); vector_tpl terraform_index2(0); swap(route, route2); swap(terraform_index, terraform_index2); sint32 cost; if(desc->get_styp() == type_elevated) { cost = intern_calc_route_elevated(start[0], ziel[0]); } else { cost = intern_calc_route( start, ziel ); } INT_CHECK("wegbauer 1165"); // the cheaper will survive ... if( cost2 < cost || cost < 0 ) { swap(route, route2); swap(terraform_index, terraform_index2); } #endif } INT_CHECK("wegbauer 778"); #ifdef DEBUG_ROUTES DBG_MESSAGE("calc_route::calc_route", "took %u ms", dr_time() - ms ); #endif return 0; } void way_builder_t::build_tunnel_and_bridges() { if(bridge_desc==NULL && tunnel_desc==NULL) { return; } // check for bridges and tunnels (no tunnel/bridge at last/first tile) for(uint32 i=1; i 1 || d.y > 1 || d.x < -1 || d.y < -1) { if(d.x*d.y!=0) { dbg->error("way_builder_t::build_tunnel_and_bridges()", "Cannot build a bridge between %s (n=%i, max_n=%i) and %s", route[i].get_str(),i,get_count()-1,route[i+1].get_str()); continue; } DBG_MESSAGE("way_builder_t::build_tunnel_and_bridges", "Built bridge %p between %s and %s", bridge_desc, route[i].get_str(), route[i + 1].get_str()); const grund_t* start = welt->lookup(route[i]); const grund_t* end = welt->lookup(route[i + 1]); if(start->get_weg_hang()!=start->get_grund_hang()) { // already a bridge/tunnel there ... continue; } if(end->get_weg_hang()!=end->get_grund_hang()) { // already a bridge/tunnel there ... continue; } if(start->get_grund_hang()==slope_t::flat || start->get_grund_hang()==slope_type(zv*(-1)) || start->get_grund_hang()==2*slope_type(zv*(-1))) { // code derived from tool/simtool sint8 bridge_height = 0; const char *error; koord3d end = bridge_builder_t::find_end_pos(player_builder, route[i], zv, bridge_desc, error, bridge_height, false, koord_distance(route[i], route[i+1]), false); if (end == route[i+1]) { bridge_builder_t::build_bridge( player_builder, route[i], route[i+1], zv, bridge_height, bridge_desc, way_builder_t::weg_search(bridge_desc->get_waytype(), bridge_desc->get_topspeed(), welt->get_timeline_year_month(), type_flat)); } } else { // tunnel tunnel_builder_t::build( player_builder, route[i].get_2d(), tunnel_desc, true ); } INT_CHECK( "wegbauer 1584" ); } // Don't build short tunnels/bridges if they block a bridge/tunnel behind! else if( bautyp != leitung && koord_distance(route[i + 2], route[i + 1]) == 1 ) { grund_t *gr_i = welt->lookup(route[i]); grund_t *gr_i1 = welt->lookup(route[i+1]); if( gr_i->get_weg_hang() != gr_i->get_grund_hang() || gr_i1->get_weg_hang() != gr_i1->get_grund_hang() ) { // Here is already a tunnel or a bridge. continue; } slope_t::type h = gr_i->get_weg_hang(); waytype_t const wt = desc->get_wtyp(); if(h!=slope_t::flat && slope_t::opposite(h)==gr_i1->get_weg_hang()) { // either a short mountain or a short dip ... // now: check ownership weg_t *wi = gr_i->get_weg(wt); weg_t *wi1 = gr_i1->get_weg(wt); if(wi->get_owner()==player_builder && wi1->get_owner()==player_builder) { // we are the owner if( h != slope_type(zv) ) { // its a bridge if( bridge_desc ) { wi->set_ribi(ribi_type(h)); wi1->set_ribi(ribi_type(slope_t::opposite(h))); bridge_builder_t::build( player_builder, route[i], bridge_desc); } } else if( tunnel_desc ) { // make a short tunnel wi->set_ribi(ribi_type(slope_t::opposite(h))); wi1->set_ribi(ribi_type(h)); tunnel_builder_t::build( player_builder, route[i].get_2d(), tunnel_desc, true ); } INT_CHECK( "wegbauer 1584" ); } } } } } /* * returns the amount needed to build this way */ sint64 way_builder_t::calc_costs() { sint64 costs=0; koord3d offset = koord3d( 0, 0, bautyp & elevated_flag ? welt->get_settings().get_way_height_clearance() : 0 ); sint32 single_cost; sint32 new_speedlimit; if( bautyp&tunnel_flag ) { assert( tunnel_desc ); single_cost = tunnel_desc->get_price(); new_speedlimit = tunnel_desc->get_topspeed(); } else { single_cost = desc->get_price(); new_speedlimit = desc->get_topspeed(); } // calculate costs for terraforming uint32 last_terraformed = terraform_index.get_count(); for(uint32 const i : terraform_index) { // index in route grund_t *from = welt->lookup(route[i]); uint8 from_slope = from->get_grund_hang(); grund_t *to = welt->lookup(route[i+1]); uint8 to_slope = to->get_grund_hang(); // calculate new slopes check_terraforming(from, to, &from_slope, &to_slope); // change slope of from if (from_slope != from->get_grund_hang()) { if (last_terraformed != i) { costs -= welt->get_settings().cst_set_slope; } } // change slope of to if (to_slope != to->get_grund_hang()) { costs -= welt->get_settings().cst_set_slope; last_terraformed = i+1; // do not pay twice for terraforming one tile } } for(uint32 i=0; ilookup(route[i] + offset); if( gr ) { if( bautyp&tunnel_flag ) { const tunnel_t *tunnel = gr->find(); assert( tunnel ); if( tunnel->get_desc() == tunnel_desc ) { continue; // Nothing to pay on this tile. } old_speedlimit = tunnel->get_desc()->get_topspeed(); } else { if( desc->get_wtyp() == powerline_wt ) { if( leitung_t *lt=gr->get_leitung() ) { old_speedlimit = lt->get_desc()->get_topspeed(); } } else { if (weg_t const* const weg = gr->get_weg(desc->get_wtyp())) { replace_cost = weg->get_desc()->get_price(); if( weg->get_desc() == desc ) { continue; // Nothing to pay on this tile. } if( desc->get_styp() == type_flat && weg->get_desc()->get_styp() == type_tram && gr->get_weg_nr(0)->get_waytype() == road_wt ) { // Don't replace a tram on a road with a normal track. continue; } old_speedlimit = weg->get_desc()->get_topspeed(); } else if (desc->get_wtyp()==water_wt && gr->is_water()) { old_speedlimit = new_speedlimit; } } } // eventually we have to remove trees for( uint8 i=0; iobj_count(); i++ ) { obj_t *obj = gr->obj_bei(i); switch(obj->get_typ()) { case obj_t::baum: costs -= welt->get_settings().cst_remove_tree; break; case obj_t::groundobj: costs += ((groundobj_t *)obj)->get_desc()->get_price(); break; default: break; } } } if( !keep_existing_faster_ways || old_speedlimit < new_speedlimit ) { costs += max(single_cost, replace_cost); } // last tile cannot be start of tunnel/bridge if(i+1 either bridge or tunnel if(d.x > 1 || d.y > 1 || d.x < -1 || d.y < -1) { koord zv = koord (sgn(d.x), sgn(d.y)); const grund_t* start = welt->lookup(route[i]); const grund_t* end = welt->lookup(route[i + 1]); if(start->get_weg_hang()!=start->get_grund_hang()) { // already a bridge/tunnel there ... continue; } if(end->get_weg_hang()!=end->get_grund_hang()) { // already a bridge/tunnel there ... continue; } if(start->get_grund_hang()==0 || start->get_grund_hang()==slope_type(zv*(-1))) { // bridge costs += bridge_desc->get_price()*(sint64)(koord_distance(route[i], route[i+1])+1); continue; } else { // tunnel costs += tunnel_desc->get_price()*(sint64)(koord_distance(route[i], route[i+1])+1); continue; } } } } DBG_MESSAGE("way_builder_t::calc_costs()","construction estimate: %f",costs/100.0); return costs; } // adds the ground before underground construction bool way_builder_t::build_tunnel_tile() { sint64 cost = 0; for(uint32 i=0; ilookup(route[i]); const way_desc_t *wb = tunnel_desc->get_way_desc(); if(wb==NULL) { // now we search a matching way for the tunnels top speed // ignore timeline to get consistent results wb = way_builder_t::weg_search( tunnel_desc->get_waytype(), tunnel_desc->get_topspeed(), 0, type_flat ); } if(gr==NULL) { // make new tunnelboden tunnelboden_t* tunnel = new tunnelboden_t(route[i], slope_t::flat); welt->access(route[i].get_2d())->boden_hinzufuegen(tunnel); if( tunnel_desc->get_waytype() != powerline_wt ) { weg_t *weg = weg_t::alloc(tunnel_desc->get_waytype()); weg->set_desc( wb ); tunnel->neuen_weg_bauen(weg, route.get_ribi(i), player_builder); tunnel->obj_add(new tunnel_t(route[i], player_builder, tunnel_desc)); weg->set_max_speed(tunnel_desc->get_topspeed()); player_t::add_maintenance( player_builder, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); } else { tunnel->obj_add(new tunnel_t(route[i], player_builder, tunnel_desc)); leitung_t *lt = new leitung_t(tunnel->get_pos(), player_builder); lt->set_desc( wb ); tunnel->obj_add( lt ); lt->finish_rd(); } tunnel->calc_image(); cost -= tunnel_desc->get_price(); player_t::add_maintenance( player_builder, tunnel_desc->get_maintenance(), tunnel_desc->get_finance_waytype() ); } else if( gr->get_typ() == grund_t::tunnelboden ) { // check for extension only ... if( tunnel_desc->get_waytype() != powerline_wt ) { gr->weg_erweitern( tunnel_desc->get_waytype(), route.get_ribi(i) ); tunnel_t *tunnel = gr->find(); assert( tunnel ); // take the faster way if( !keep_existing_faster_ways || (tunnel->get_desc()->get_topspeed() < tunnel_desc->get_topspeed()) ) { player_t::add_maintenance(player_builder, -tunnel->get_desc()->get_maintenance(), tunnel->get_desc()->get_finance_waytype()); player_t::add_maintenance(player_builder, tunnel_desc->get_maintenance(), tunnel->get_desc()->get_finance_waytype() ); tunnel->set_desc(tunnel_desc); weg_t *weg = gr->get_weg(tunnel_desc->get_waytype()); weg->set_desc(wb); weg->set_max_speed(tunnel_desc->get_topspeed()); // respect max speed of catenary wayobj_t const* const wo = gr->get_wayobj(tunnel_desc->get_waytype()); if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) { weg->set_max_speed( wo->get_desc()->get_topspeed() ); } gr->calc_image(); // respect speed limit of crossing weg->count_sign(); cost -= tunnel_desc->get_price(); } } else { leitung_t *lt = gr->get_leitung(); if(!lt) { lt = new leitung_t(gr->get_pos(), player_builder); lt->set_desc( wb ); gr->obj_add( lt ); } } } } player_t::book_construction_costs(player_builder, cost, route[0].get_2d(), tunnel_desc->get_waytype()); return true; } void way_builder_t::build_elevated() { for(koord3d & i : route) { planquadrat_t* const plan = welt->access(i.get_2d()); grund_t* const gr0 = plan->get_boden_in_hoehe(i.z); i.z += welt->get_settings().get_way_height_clearance(); grund_t* const gr = plan->get_boden_in_hoehe(i.z); if(gr==NULL) { slope_t::type hang = gr0 ? gr0->get_grund_hang() : 0; // add new elevated ground monorailboden_t* const monorail = new monorailboden_t(i, hang); plan->boden_hinzufuegen(monorail); monorail->calc_image(); } } } void way_builder_t::build_road() { // only public player or cities (sp==NULL) can build cityroads with sidewalk bool add_sidewalk = build_sidewalk && (player_builder==NULL || player_builder->is_public_service()); if(add_sidewalk) { player_builder = NULL; } // init undo if(player_builder!=NULL) { // intercity roads have no owner, so we must check for an owner player_builder->init_undo(road_wt,get_count()); } for( uint32 i=0; ilookup(route[i]); sint64 cost = 0; bool extend = gr->weg_erweitern(road_wt, route.get_short_ribi(i)); // bridges/tunnels have their own track type and must not upgrade if(gr->get_typ()==grund_t::brueckenboden || gr->get_typ()==grund_t::tunnelboden) { continue; } if(extend) { weg_t * weg = gr->get_weg(road_wt); // keep faster ways or if it is the same way, or it is the way under the halt of an existing player if(weg->get_desc()==desc || keep_existing_ways || (keep_existing_city_roads && weg->hat_gehweg()) || (keep_existing_faster_ways && weg->get_desc()->get_topspeed()>desc->get_topspeed()) || (player_builder!=NULL && weg->get_removal_error(player_builder)!=NULL) || (gr->get_typ()==grund_t::monorailboden && (bautyp&elevated_flag)==0) || (gr->has_two_ways() && gr->get_weg_nr(1)->get_removal_error(player_builder)!=NULL) // do not replace public roads crossing rails of other players || (gr->get_halt().is_bound() && !check_owner(gr->get_halt()->get_owner(), player_builder)) ) { //nothing to be done } else { // we take ownership => we take care to maintain the roads completely ... player_t *s = weg->get_owner(); player_t::add_maintenance(s, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); // cost is the more expensive one, so downgrading is between removing and new building cost -= max( weg->get_desc()->get_price(), desc->get_price() ); weg->set_desc(desc); // respect max speed of catenary wayobj_t const* const wo = gr->get_wayobj(desc->get_wtyp()); if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) { weg->set_max_speed( wo->get_desc()->get_topspeed() ); } weg->set_gehweg(add_sidewalk); player_t::add_maintenance( player_builder, weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); weg->set_owner(player_builder); upgrade_crossing_if_needed(gr); } } else { // make new way strasse_t * str = new strasse_t(); str->set_desc(desc); str->set_gehweg(add_sidewalk); cost = -gr->neuen_weg_bauen(str, route.get_short_ribi(i), player_builder)-desc->get_price(); // into UNDO-list, so we can remove it later if(player_builder!=NULL) { // intercity roads have no owner, so we must check for an owner player_builder->add_undo( route[i] ); } } gr->calc_image(); // because it may be a crossing ... minimap_t::get_instance()->calc_map_pixel(k); player_t::book_construction_costs(player_builder, cost, k, road_wt); } // for } void way_builder_t::build_track() { if (get_count() <= 1) { return; } // init undo player_builder->init_undo(desc->get_wtyp(), get_count()); // build tracks for( uint32 i=0; ilookup(route[i]); ribi_t::ribi ribi = route.get_short_ribi(i); if(gr->get_typ()==grund_t::wasser) { // not building on the sea ... continue; } const bool extend = gr->weg_erweitern(desc->get_wtyp(), ribi); // bridges/tunnels have their own track type and must not upgrade if((gr->get_typ()==grund_t::brueckenboden || gr->get_typ()==grund_t::tunnelboden) && gr->get_weg_nr(0)->get_waytype()==desc->get_wtyp()) { continue; } if(extend) { weg_t* const weg = gr->get_weg(desc->get_wtyp()); bool change_desc = true; // do not touch fences, tram way etc. if there is already same way with different type // keep faster ways or if it is the same way if (weg->get_desc() == desc || (desc->get_styp() == 0 && weg->get_desc()->get_styp() == type_tram && gr->has_two_ways()) || keep_existing_ways || (keep_existing_faster_ways && weg->get_desc()->get_topspeed() > desc->get_topspeed()) || (gr->get_typ() == grund_t::monorailboden && !(bautyp & elevated_flag) && gr->get_weg_nr(0)->get_waytype()==desc->get_wtyp())) { //nothing to be done change_desc = false; } // build tram track over crossing -> remove crossing if( gr->has_two_ways() && desc->get_styp()==type_tram && weg->get_desc()->get_styp() != type_tram ) { if( crossing_t *cr = gr->find(2) ) { // change to tram track cr->mark_image_dirty( cr->get_image(), 0); cr->cleanup(player_builder); delete cr; change_desc = true; // tell way we have no crossing any more, restore speed limit gr->get_weg_nr(0)->clear_crossing(); gr->get_weg_nr(0)->set_desc( gr->get_weg_nr(0)->get_desc() ); gr->get_weg_nr(1)->clear_crossing(); } } if( change_desc ) { // we take ownership => we take care to maintain the roads completely ... player_t *s = weg->get_owner(); player_t::add_maintenance( s, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); // cost is the more expensive one, so downgrading is between removing and new buidling cost -= max( weg->get_desc()->get_price(), desc->get_price() ); weg->set_desc(desc); // respect max speed of catenary wayobj_t const* const wo = gr->get_wayobj(desc->get_wtyp()); if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) { weg->set_max_speed( wo->get_desc()->get_topspeed() ); } player_t::add_maintenance( player_builder, weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); weg->set_owner(player_builder); // respect speed limit of crossing weg->count_sign(); upgrade_crossing_if_needed(gr); } } else { weg_t* const sch = weg_t::alloc(desc->get_wtyp()); sch->set_desc(desc); cost = -gr->neuen_weg_bauen(sch, ribi, player_builder)-desc->get_price(); // connect canals to sea if( desc->get_wtyp() == water_wt ) { // do not connect across slopes ribi_t::ribi slope_ribi = ribi_t::all; if (gr->get_grund_hang()!=slope_t::flat) { slope_ribi = ribi_t::doubles( ribi_type(gr->get_weg_hang()) ); } for( int j = 0; j < 4; j++ ) { if (ribi_t::nesw[j] & slope_ribi) { grund_t *sea = NULL; if (gr->get_neighbour(sea, invalid_wt, ribi_t::nesw[j]) && sea->is_water() ) { gr->weg_erweitern( water_wt, ribi_t::nesw[j] ); sea->calc_image(); } } } } // into UNDO-list, so we can remove it later player_builder->add_undo( route[i] ); } gr->calc_image(); minimap_t::get_instance()->calc_map_pixel( gr->get_pos().get_2d() ); player_t::book_construction_costs(player_builder, cost, gr->get_pos().get_2d(), desc->get_finance_waytype()); if((i&3)==0) { INT_CHECK( "wegbauer 1584" ); } } } void way_builder_t::build_powerline() { if( get_count() < 1 ) { return; } // no undo player_builder->init_undo(powerline_wt,get_count()); for( uint32 i=0; ilookup(route[i]); leitung_t* lt = gr->get_leitung(); bool build_powerline = false; // ok, really no lt here ... if(lt==NULL) { if(gr->ist_natur()) { // remove trees etc. sint64 cost = gr->remove_trees(); player_t::book_construction_costs(player_builder, -cost, gr->get_pos().get_2d(), powerline_wt); } lt = new leitung_t(route[i], player_builder ); gr->obj_add(lt); // into UNDO-list, so we can remove it later player_builder->add_undo( route[i] ); build_powerline = true; } else { // modernize the network if(lt->get_typ() == obj_t::leitung && (!keep_existing_faster_ways || lt->get_desc()->get_topspeed() < desc->get_topspeed()) ) { build_powerline = true; player_t::add_maintenance( lt->get_owner(), -lt->get_maintenance(), powerline_wt ); } } if (build_powerline) { lt->set_desc(desc); player_t::book_construction_costs(player_builder, -desc->get_price(), gr->get_pos().get_2d(), powerline_wt); // this adds maintenance lt->leitung_t::finish_rd(); minimap_t::get_instance()->calc_map_pixel( gr->get_pos().get_2d() ); } if((i&3)==0) { INT_CHECK( "wegbauer 1584" ); } } } // this can drive any river, even a river that has max_speed=0 class fluss_test_driver_t : public test_driver_t { bool check_next_tile(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi_unmasked(water_wt)!=0; } ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi_unmasked(water_wt); } waytype_t get_waytype() const OVERRIDE { return ignore_wt; } int get_cost(const grund_t *, const weg_t *, const sint32, ribi_t::ribi) const OVERRIDE { return 1; } bool is_target(const grund_t *cur,const grund_t *) const OVERRIDE { return cur->is_water() && cur->get_hoehe()<=world()->get_groundwater(); } }; // make a river void way_builder_t::build_river() { /* since the constraints of the wayfinder ensures that a river flows always downwards * we can assume that the first tiles are the ocean. * Usually the wayfinder would find either direction! * route.front() tile at the ocean, route.back() the spring of the river */ uint32 start_n = 0; uint32 end_n = get_count(); // first find coast ... for( uint32 idx=start_n; idxlookup(route[idx])->get_hoehe() == welt->get_water_hgt(route[idx].get_2d()) ) { start_n = idx; } else { break; } } // Do we join an other river? for( uint32 idx=start_n; idxlookup( route[idx] )->get_weg(water_wt) ) { // river or channel start_n = idx; } } // No spring on a slope while( end_n>start_n ) { if( welt->lookup( route[end_n-1] )->get_grund_hang() == slope_t::flat ) { break; } end_n --; } if( start_n == get_count()-1 ) { // completely joined another river => nothing to do return; } // first check then lower riverbed sint8 start_h = max(route[start_n].z,welt->get_groundwater()); vector_tpl lower_tile( end_n ); // This contains the tiles which can be lowered. vector_tpl lower_tile_h( end_n ); // to this value // first: find possible valley for( uint32 i=0; i < end_n; i++ ) { bool can_lower = true; if( route[i].z < start_h ) { // skip all tiles below last sea level can_lower = false; } grund_t *gr = welt->lookup( route[i] ); if( gr->is_water() ) { // not lowering the sea or lakes start_h = welt->get_water_hgt( route[i].get_2d() ); can_lower = false; } if( gr->hat_weg(water_wt) ) { // not lowering exiting rivers start_h = route[i].z; can_lower = false; } // check if( can_lower ) { can_lower = welt->can_flatten_tile( NULL, route[i].get_2d(), max( route[i].z-1, start_h ) ); } lower_tile.append( can_lower ); lower_tile_h.append( start_h ); sint8 current_h = route[i].z+slope_t::max_diff(gr->get_grund_hang()); if( current_h > start_h + 1 ) { start_h++; } } // now lower all tiles for( uint32 i=start_n; iflatten_tile( NULL, route[i].get_2d(), lower_tile_h[i] ) ) { // illegal slope encountered, give up ... return; } } } // and raise all tiles that resulted in slopes on curves for( uint32 i = max(end_n, 2) - 2; i > start_n+1; i-- ) { grund_t *gr = welt->lookup_kartenboden( route[i].get_2d() ); if( !gr->get_weg_ribi( water_wt ) && gr->get_grund_hang()!=slope_t::flat ) { if( !ribi_t::is_straight(ribi_type(route[i+1].get_2d()-route[i-1].get_2d())) ) { welt->flatten_tile( NULL, route[i].get_2d(), gr->get_hoehe()+1 ); DBG_MESSAGE( "wrong river slope", route[i].get_str() ); } } } // now build the river uint32 last_common_water_tile = start_n; grund_t *gr_first = NULL; for( uint32 i=start_n; ilookup_kartenboden(route[i].get_2d()); if( gr_first == NULL) { gr_first = gr; } if( gr->get_typ()!=grund_t::wasser ) { // get direction ribi_t::ribi ribi = iweg_erweitern(water_wt, ribi); if( !extend ) { weg_t *river=weg_t::alloc(water_wt); river->set_desc(desc); gr->neuen_weg_bauen(river, ribi, NULL); } else { last_common_water_tile = i; } } else { dynamic_cast(gr)->recalc_water_neighbours(); last_common_water_tile = i; } } gr_first->calc_image(); // to calculate ribi of water tiles // we will make rivers gradually larger by stepping up their width // Since we cannot quickly find out if a lake has another influx, we just assume all rivers after a lake are navigable if( env_t::river_types>1 ) { // now all rivers will end in the sea (or a lake) and thus there must be a valid route! // unless weare the first and there is no lake on the way. route_t to_the_sea; fluss_test_driver_t river_tester; if (to_the_sea.calc_route(welt, welt->lookup_kartenboden(route[last_common_water_tile].get_2d())->get_pos(), welt->lookup_kartenboden(route[0].get_2d())->get_pos(), &river_tester, 0, 0x7FFFFFFF)) { for(koord3d const& entry : to_the_sea.get_route()) { if (weg_t* const w = welt->lookup(entry)->get_weg(water_wt)) { int type; for( type=env_t::river_types-1; type>0; type-- ) { // lookup type if( w->get_desc()==desc_table.get(env_t::river_type[type]) ) { break; } } // still room to expand if( type>0 ) { // thus we enlarge w->set_desc( desc_table.get(env_t::river_type[type-1]) ); w->calc_image(); } } } } } } void way_builder_t::build() { if(get_count()<2 || get_count() > (uint32)maximum) { DBG_MESSAGE("way_builder_t::build()","called, but no valid route."); // no valid route here ... return; } DBG_MESSAGE("way_builder_t::build()", "type=%d max_n=%d start=%d,%d end=%d,%d", bautyp, get_count() - 1, route.front().x, route.front().y, route.back().x, route.back().y); #ifdef DEBUG_ROUTES uint32 ms = dr_time(); #endif if ( (bautyp&terraform_flag)!=0 && (bautyp&(tunnel_flag|elevated_flag))==0 && bautyp!=river) { // do the terraforming do_terraforming(); } // first add all new underground tiles ... (and finished if successful) if(bautyp&tunnel_flag) { build_tunnel_tile(); return; } // add elevated ground for elevated tracks if(bautyp&elevated_flag) { build_elevated(); } INT_CHECK("simbau 1072"); switch(bautyp&bautyp_mask) { case wasser: case schiene: case schiene_tram: // Dario: Tramway case monorail: case maglev: case narrowgauge: case luft: DBG_MESSAGE("way_builder_t::build", "schiene"); build_track(); break; case strasse: build_road(); DBG_MESSAGE("way_builder_t::build", "strasse"); break; case leitung: build_powerline(); break; case river: build_river(); break; default: break; } INT_CHECK("simbau 1087"); build_tunnel_and_bridges(); INT_CHECK("simbau 1087"); #ifdef DEBUG_ROUTES DBG_MESSAGE("way_builder_t::build", "took %u ms", dr_time() - ms ); #endif } uint32 way_builder_t::calc_distance( const koord3d &pos, const koord3d &mini, const koord3d &maxi ) { uint32 dist = 0; if ( pos.x < mini.x ) { dist += mini.x - pos.x; } else if( pos.x > maxi.x ) { dist += pos.x - maxi.x; } if ( pos.y < mini.y ) { dist += mini.y - pos.y; } else if( pos.y > maxi.y ) { dist += pos.y - maxi.y; } settings_t const& settings = welt->get_settings(); dist *= settings.way_count_straight; if ( pos.z < mini.z ) { dist += (mini.z - pos.z) * settings.way_count_slope; } else if( pos.z > maxi.z ) { dist += (pos.z - maxi.z) * settings.way_count_slope; } return dist; } void way_builder_t::upgrade_crossing_if_needed( const grund_t* gr ) { crossing_t *crossing = gr->find(); if( !gr->ist_uebergang() || !crossing ) { return; // A crossing does not exist on the given tile. } crossing->finish_rd(); } simutrans-124.3/src/simutrans/builder/wegbauer.h000066400000000000000000000156021474050137200217730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef BUILDER_WEGBAUER_H #define BUILDER_WEGBAUER_H #include "../simtypes.h" #include "../dataobj/koord3d.h" #include "../tpl/vector_tpl.h" class way_desc_t; class bridge_desc_t; class tunnel_desc_t; class karte_ptr_t; class player_t; class grund_t; class tool_selector_t; /** * way building class with its own route finding */ class way_builder_t { static karte_ptr_t welt; public: static const way_desc_t *leitung_desc; static bool register_desc(way_desc_t *desc); static bool successfully_loaded(); // generates timeline message static void new_month(); /** * Finds a way with a given speed limit for a given waytype */ static const way_desc_t *weg_search(const waytype_t wtyp,const sint32 speed_limit, const uint16 time, const systemtype_t system_type); static const way_desc_t *get_desc(const char *way_name,const uint16 time=0); static const way_desc_t *get_earliest_way(const waytype_t wtyp); static const way_desc_t *get_latest_way(const waytype_t wtyp); static bool waytype_available( const waytype_t wtyp, uint16 time ); static const vector_tpl& get_way_list(waytype_t, systemtype_t system_type); /** * Fill menu with icons of given waytype */ static void fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, const systemtype_t styp, sint16 ok_sound); enum bautyp_t { strasse = road_wt, schiene = track_wt, schiene_tram = tram_wt, monorail = monorail_wt, maglev = maglev_wt, wasser = water_wt, luft = air_wt, narrowgauge = narrowgauge_wt, leitung = powerline_wt, river = 0x7F, bautyp_mask = 0xFF, bot_flag = 1 << 8, ///< do not connect to other ways elevated_flag = 1 << 9, ///< elevated structure terraform_flag = 1 << 10, tunnel_flag = 1 << 11, ///< underground structure }; private: /// flags used in intern_calc_route, saved in the otherwise unused route_t::ANode->count enum build_type_t { build_straight = 1 << 0, ///< next step has to be straight terraform = 1 << 1, ///< terraform this tile build_tunnel_bridge = 1 << 2, ///< bridge/tunnel ends here is_upperlayer = 1 << 3 ///< only used when elevated true:upperlayer }; struct next_gr_t { next_gr_t() {} next_gr_t(grund_t* gr_, sint32 cost_, uint8 flag_=0) : gr(gr_), cost(cost_), flag(flag_) {} grund_t* gr; sint32 cost; uint8 flag; }; vector_tpl next_gr; player_t *player_builder; /// Type of building operation bautyp_t bautyp; /// Which way to build const way_desc_t *desc; /// Type of bridge to build (null => no bridges) const bridge_desc_t *bridge_desc; /// Type of tunnel to build (null => no bridges) const tunnel_desc_t *tunnel_desc; /** * If a way is built on top of another way, should the type * of the former way be kept or replaced (true == keep) */ bool keep_existing_ways; bool keep_existing_faster_ways; bool keep_existing_city_roads; // try to keep a way close to existing ways bool prefer_parallel; bool build_sidewalk; sint32 maximum; // highest cost koord3d_vector_t route; // index in route with terraformed tiles vector_tpl terraform_index; // has a warning message, why the route may have failed (could be wrong!) const char *warn_fail; public: /** * This is the core routine for the way search * it will check * A) allowed step * B) if allowed, calculate the cost for the step from @p from to @p to */ bool is_allowed_step(const grund_t *from, const grund_t *to, sint32 *costs, bool is_upperlayer = false ); private: bool has_neighbour_with_way(koord3d pos, waytype_t wt) const; // checks, if we can build a bridge here ... // may modify next_gr array! void check_for_bridge(const grund_t* parent_from, const grund_t* from, const vector_tpl &ziel); sint32 intern_calc_route(const vector_tpl &start, const vector_tpl &ziel); void intern_calc_straight_route(const koord3d start, const koord3d ziel); sint32 intern_calc_route_elevated(const koord3d start, const koord3d ziel); // runways need to meet some special conditions enforced here bool intern_calc_route_runways(koord3d start, const koord3d ziel); void build_tunnel_and_bridges(); // adds the ground before underground construction (always called before the following construction routines) bool build_tunnel_tile(); // adds the grounds for elevated tracks void build_elevated(); void build_road(); void build_track(); void build_powerline(); void build_river(); void upgrade_crossing_if_needed(const grund_t*); /** * This function calculates the distance of pos to the cuboid * spanned up by mini and maxi. * The result is already weighted according to * welt->get_settings().get_way_count_{straight,slope}(). */ uint32 calc_distance( const koord3d &pos, const koord3d &mini, const koord3d &maxi ); public: const koord3d_vector_t &get_route() const { return route; } uint32 get_count() const { return route.get_count(); } void set_prefer_parallel(bool yesno) { prefer_parallel = yesno; } /** * If a way is built on top of another way, should the type * of the former way be kept or replaced (true == keep) */ void set_keep_existing_ways(bool yesno); /** * If a way is built on top of another way, should the type * of the former way be kept or replaced, if the current way is faster (true == keep) */ void set_keep_existing_faster_ways(bool yesno); /** * Always keep city roads (for AI) */ void set_keep_city_roads(bool yesno) { keep_existing_city_roads = yesno; } void set_build_sidewalk(bool yesno) { build_sidewalk = yesno; } void init_builder(bautyp_t wt, const way_desc_t * desc, const tunnel_desc_t *tunnel_desc=NULL, const bridge_desc_t *bridge_desc=NULL); void set_maximum(uint32 n) { maximum = n; } way_builder_t(player_t *player); const char *calc_straight_route(const koord3d start, const koord3d ziel); const char *calc_route(const koord3d &start3d, const koord3d &ziel); const char *calc_route(const vector_tpl &start3d, const vector_tpl &ziel); /// returns the amount needed to build this way sint64 calc_costs(); bool check_crossing(const koord zv, const grund_t *bd,waytype_t wtyp, const player_t *player) const; bool check_powerline(const koord zv, const grund_t *bd) const; // allowed owner? bool check_owner( const player_t *player1, const player_t *player2 ) const; // checks whether buildings on the tile allow to leave in direction dir bool check_building( const grund_t *to, const koord dir ) const; // allowed slope? bool check_slope( const grund_t *from, const grund_t *to ); bool check_terraforming( const grund_t *from, const grund_t *to, uint8* new_from_slope=NULL, uint8* new_to_slope=NULL) const; void do_terraforming(); void build(); }; ENUM_BITSET(way_builder_t::bautyp_t); #endif simutrans-124.3/src/simutrans/convoihandle.h000066400000000000000000000004021474050137200212050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef CONVOIHANDLE_H #define CONVOIHANDLE_H #include "tpl/quickstone_tpl.h" class convoi_t; typedef quickstone_tpl convoihandle_t; #endif simutrans-124.3/src/simutrans/dataobj/000077500000000000000000000000001474050137200177735ustar00rootroot00000000000000simutrans-124.3/src/simutrans/dataobj/crossing_logic.cc000066400000000000000000000253251474050137200233150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../vehicle/vehicle_base.h" #include "../world/simworld.h" #include "../simsound.h" #include "translator.h" #include "../descriptor/crossing_desc.h" #include "../utils/cbuffer.h" #include "../tpl/slist_tpl.h" #include "crossing_logic.h" #include "../obj/crossing.h" karte_ptr_t crossing_logic_t::welt; crossing_logic_t::crossing_logic_t( const crossing_desc_t *desc ) { state = CROSSING_INVALID; this->desc = desc; request_close = NULL; } /** * @param[out] buf string; currently unused but useful for debugging */ void crossing_logic_t::info(cbuffer_t & buf) const { static char const* const state_str[NUM_CROSSING_STATES] = { "invalid", "open", "request closing", "closed" }; buf.printf("%s%u%s%u%s%s\n", translator::translate("\nway1 reserved by"), on_way1.get_count(), translator::translate("\nway2 reserved by"), on_way2.get_count(), translator::translate("cars.\nstate"), translator::translate(state_str[state]) ); } // after merging or splitting two crossings ... void crossing_logic_t::recalc_state() { if( !crossings.empty() ) { on_way1.clear(); on_way2.clear(); for(crossing_t* const i : crossings) { // add vehicles already there if (grund_t* const gr = welt->lookup(i->get_pos())) { for( uint8 i=3; iobj_count(); i++ ) { if( vehicle_base_t const* const v = obj_cast(gr->obj_bei(i)) ) { add_to_crossing( v ); } } } } } request_close = NULL; if(state==CROSSING_INVALID) { // now just set the state, if needed if(on_way2.empty()) { set_state( CROSSING_OPEN ); } else { set_state( CROSSING_CLOSED ); } } } // request permission to pass crossing bool crossing_logic_t::request_crossing( const vehicle_base_t *v ) { if(v->get_waytype()==desc->get_waytype(0)) { if(on_way2.empty() && state == CROSSING_OPEN) { // way2 is empty ... return true; } // passage denied, since there are vehicle on way2 // which has priority // => ok only if I am already crossing return on_way1.is_contained(v); } else if(v->get_waytype()==desc->get_waytype(1)) { // vehicle from way2 arrives if(on_way1.get_count()) { // sorry, still things on the crossing, but we will prepare set_state( CROSSING_REQUEST_CLOSE ); return false; } else { request_close = v; set_state( CROSSING_CLOSED ); return true; } } // likely an airplane ... return true; } // request permission to pass crossing void crossing_logic_t::add_to_crossing( const vehicle_base_t *v ) { if( v->get_typ()!=obj_t::pedestrian ) { if(v->get_waytype()==desc->get_waytype(0)) { on_way1.append_unique(v); } else if (v->get_waytype() == desc->get_waytype(1)) { // add it and close crossing on_way2.append_unique(v); if( request_close==v ) { request_close = NULL; } set_state( CROSSING_CLOSED ); } } } // called after passing of the last vehicle (in a convoi) // or of a city car; releases the crossing which may switch state void crossing_logic_t::release_crossing( const vehicle_base_t *v ) { if( v->get_waytype() == desc->get_waytype(0) ) { on_way1.remove(v); if( state == CROSSING_REQUEST_CLOSE && on_way1.empty() ) { set_state( CROSSING_CLOSED ); } } else { on_way2.remove(v); if( request_close == v ) { request_close = NULL; } if( on_way2.empty() && request_close == NULL ) { set_state( CROSSING_OPEN ); } } } // change state; mark dirty and plays sound void crossing_logic_t::set_state( crossing_state_t new_state ) { // play sound (if there and closing) if(new_state==CROSSING_CLOSED && desc->get_sound()>=0 && !welt->is_fast_forward()) { welt->play_sound_area_clipped(crossings[0]->get_pos().get_2d(), desc->get_sound(), CROSSING_SOUND ); } if(new_state!=state) { state = new_state; for(crossing_t* const i : crossings) { i->state_changed(); } } } /* static stuff from here on ... */ /** * nothing can cross airways, so waytype 0..7 is enough * only save this entries: * way0 way1 * 0 .. 1 2 3 4 5 6 7 8 * 1 .. 2 3 4 5 6 7 8 * 2 .. 3 4 5 6 7 8 * .. ... */ minivec_tpl crossing_logic_t::can_cross_array[36]; /** * compare crossings for the same waytype-combinations */ int compare_crossing(const crossing_desc_t *c0, const crossing_desc_t *c1) { // sort descending wrt maxspeed int diff = c1->get_maxspeed(0) - c0->get_maxspeed(0); if (diff==0) { diff = c1->get_maxspeed(1) - c0->get_maxspeed(1); } if (diff==0) { diff = strcmp(c0->get_name(), c1->get_name()); } return diff; } void crossing_logic_t::register_desc(crossing_desc_t *desc) { // mark if crossing possible const waytype_t way0 = (waytype_t)min(desc->get_waytype(0), desc->get_waytype(1)); const waytype_t way1 = (waytype_t)max(desc->get_waytype(0), desc->get_waytype(1)); if (way1 == way0) { dbg->error("crossing_logic_t::register_desc()", "Crossing %s has waytype %s for both ways! (Crossing ignored)", desc->get_name(), weg_t::waytype_to_string(way0)); return; } if( way0<8 && way1<9 ) { uint8 index = way0 * 9 + way1 - ((way0+2)*(way0+1))/2; // max index = 7*9 + 8 - 9*4 = 71-36 = 35 // .. overwrite double entries minivec_tpl &vec = can_cross_array[index]; // first check for existing crossing with the same name for(uint8 i=0; iget_name(), desc->get_name())==0) { delete vec[i]; vec.remove_at(i); } } DBG_DEBUG( "crossing_logic_t::register_desc()","%s", desc->get_name() ); // .. then make sorted insert for(uint8 i=0; iis_available(timeline_year_month) ) { continue; } // match maxspeed of first way uint8 const swap_way = i->get_waytype(0) != way0; sint32 const imax0 = i->get_maxspeed(swap_way); sint32 const bmax0 = best ? best->get_maxspeed(swap_way) : 9999; if( imax0 >= speed0 && imax0 <= bmax0 ) { // match maxspeed of second way sint32 const imax1 = i->get_maxspeed(!swap_way); sint32 const bmax1 = best ? best->get_maxspeed(!swap_way) : 9999; if( imax1 >= speed1 && imax1 <= bmax1 ) { best = i; } } } } return best; } /** * compare crossings for the same waytype-combinations */ bool have_crossings_same_wt(const crossing_desc_t *c0, const crossing_desc_t *c1) { return c0->get_waytype(0) == c1->get_waytype(0) && c0->get_waytype(1) == c1->get_waytype(1); } // returns a new or an existing crossing_logic_t object // new, of no matching crossings are next to it void crossing_logic_t::add( crossing_t *start_cr, crossing_state_t state ) { koord3d pos = start_cr->get_pos(); const koord zv = start_cr->get_dir() ? koord::west : koord::north; slist_tplcrossings; minivec_tplcrossings_logics; crossings.append_unique( start_cr ); if (crossing_logic_t *start_logic = start_cr->get_logic() ) { crossings_logics.append(start_logic); } // go north/west while(1) { pos += zv; grund_t *gr = welt->lookup( pos ); if(gr==NULL) { break; } crossing_t *found_cr = gr->find(); if(found_cr==NULL || !have_crossings_same_wt(found_cr->get_desc(),start_cr->get_desc()) || start_cr->get_dir() != found_cr->get_dir()) { break; } crossings.append( found_cr ); if( found_cr->get_logic()!=NULL ) { crossings_logics.append_unique( found_cr->get_logic() ); } } // go east/south pos = start_cr->get_pos(); while(1) { pos -= zv; grund_t *gr = welt->lookup( pos ); if(gr==NULL) { break; } crossing_t *found_cr = gr->find(); if(found_cr==NULL || !have_crossings_same_wt(found_cr->get_desc(),start_cr->get_desc()) || start_cr->get_dir() != found_cr->get_dir()) { break; } crossings.append( found_cr ); if( found_cr->get_logic()!=NULL ) { crossings_logics.append_unique( found_cr->get_logic() ); } } // remove all old crossing logics crossing_logic_t *found_logic = NULL; if( crossings_logics.get_count()>=1 ) { // leave one logic to be used further while( crossings_logics.get_count()>1 ) { crossing_logic_t *cl = crossings_logics[0]; crossings_logics.remove_at(0); delete cl; } found_logic = crossings_logics[0]; } // no old logic there create a new one if( found_logic == NULL ) { found_logic = new crossing_logic_t( start_cr->get_desc() ); } // set new crossing logic to all for(crossing_t* const cr : crossings) { cr->set_logic( found_logic ); found_logic->append_crossing( cr ); } found_logic->set_state( state ); found_logic->recalc_state(); } // removes a crossing logic, if all crossings are removed void crossing_logic_t::remove( crossing_t *cr ) { crossings.remove( cr ); if( crossings.empty() ) { delete this; } else { // check for a crossing to the east/south koord3d pos = cr->get_pos(); const koord zv = cr->get_dir() ? koord::west : koord::north; const grund_t *gr = welt->lookup( pos-zv ); if( gr ) { crossing_t *found_cr = gr->find(); if( found_cr && have_crossings_same_wt(found_cr->get_desc(),cr->get_desc()) ) { // crossing to the east/south so split logic from any found to the north/west crossing_logic_t *split_logic = NULL; while(1) { pos += zv; gr = welt->lookup( pos ); if( gr == NULL ) { break; } found_cr = gr->find(); if( found_cr == NULL || !have_crossings_same_wt(found_cr->get_desc(),cr->get_desc()) ) { break; } assert(this==found_cr->get_logic()); if( !split_logic ) { split_logic = new crossing_logic_t( cr->get_desc() ); } crossings.remove( found_cr ); found_cr->set_logic( split_logic ); split_logic->append_crossing( found_cr ); } if( split_logic ) { split_logic->set_state( CROSSING_INVALID ); split_logic->recalc_state(); } } } set_state( CROSSING_INVALID ); recalc_state(); } } simutrans-124.3/src/simutrans/dataobj/crossing_logic.h000066400000000000000000000050551474050137200231550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_CROSSING_LOGIC_H #define DATAOBJ_CROSSING_LOGIC_H #include "../simtypes.h" #include "../tpl/minivec_tpl.h" #include "../tpl/slist_tpl.h" class cbuffer_t; class crossing_t; class karte_ptr_t; class crossing_desc_t; class vehicle_base_t; /** * road sign for traffic (one way minimum speed, traffic lights) */ class crossing_logic_t { public: enum crossing_state_t { CROSSING_INVALID = 0, CROSSING_OPEN, CROSSING_REQUEST_CLOSE, CROSSING_CLOSED, NUM_CROSSING_STATES }; protected: static karte_ptr_t welt; // the last vehicle that requested a closing const vehicle_base_t *request_close; crossing_state_t state; const crossing_desc_t *desc; minivec_tplcrossings; void set_state( crossing_state_t new_state ); public: minivec_tplon_way1; minivec_tplon_way2; public: crossing_logic_t( const crossing_desc_t *desc ); /** * @param[out] buf string (only used for debug at the moment) */ void info(cbuffer_t & buf) const; // recalcs the current state void recalc_state(); // returns true, if the crossing can be passed by this vehicle bool request_crossing( const vehicle_base_t * ); // adds to crossing void add_to_crossing( const vehicle_base_t *v ); // removes the vehicle from the crossing void release_crossing( const vehicle_base_t * ); /* states of the crossing; * since way2 has priority over way1 there is a third state, during a closing request */ crossing_state_t get_state() { return state; } void append_crossing( crossing_t *cr ) { crossings.append_unique(cr); } // static routines from here private: static slist_tpl list; // save all desc' only for waytype0 < waytype1 static minivec_tpl can_cross_array[36]; public: static void register_desc(crossing_desc_t *desc); /** * returns descriptor for crossing wrt timeline * tries to match max-speeds: * (1) find crossings with maxspeed close to requested maxspeed * (2) prefer crossings with maxspeed larger than requested */ static const crossing_desc_t *get_crossing(const waytype_t ns, const waytype_t ow, sint32 way_0_speed, sint32 way_1_speed, uint16 timeline_year_month); // returns a new or an existing crossing_logic_t object // new, of no matching crossings are next to it static void add( crossing_t *cr, crossing_logic_t::crossing_state_t state ); // remove logic from crossing(s) void remove( crossing_t *cr ); }; #endif simutrans-124.3/src/simutrans/dataobj/environment.cc000066400000000000000000000440551474050137200226560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "environment.h" #include "loadsave.h" #include "../pathes.h" #include "../simversion.h" #include "../simconst.h" #include "../simtypes.h" #include "../sys/simsys.h" #include "../simmesg.h" #include "../utils/simrandom.h" void rdwr_win_settings(loadsave_t *file); // simwin char env_t::base_dir[PATH_MAX]; char env_t::install_dir[PATH_MAX]; char env_t::user_dir[PATH_MAX]; std::string env_t::pak_dir; std::string env_t::pak_name; #ifndef __ANDROID__ sint16 env_t::menupos = MENU_TOP; bool env_t::single_toolbar_mode = false; sint16 env_t::dpi_scale = 100; bool env_t::single_info = 1; #else sint16 env_t::menupos = MENU_BOTTOM; bool env_t::single_toolbar_mode = true; sint16 env_t::dpi_scale = -1; bool env_t::single_info = 0; #endif sint16 env_t::fullscreen = WINDOWED; sint16 env_t::display_scale_percent = 100; bool env_t::reselect_closes_tool = true; sint8 env_t::pak_tile_height_step = 16; sint8 env_t::pak_height_conversion_factor = 1; env_t::height_conversion_mode env_t::height_conv_mode = env_t::HEIGHT_CONV_LINEAR; bool env_t::simple_drawing = false; bool env_t::simple_drawing_fast_forward = true; sint16 env_t::simple_drawing_normal = 4; sint16 env_t::simple_drawing_default = 24; uint8 env_t::follow_convoi_underground = 2; bool env_t::random_pedestrians = true; bool env_t::stop_pedestrians = true; plainstring env_t::default_theme; const char *env_t::savegame_version_str = SAVEGAME_VER_NR; bool env_t::straight_way_without_control = false; bool env_t::networkmode = false; bool env_t::restore_UI = false; extern uint16 network_server_port; uint16 const &env_t::server = network_server_port; uint8 env_t::just_in_time = 1; // Disable announce by default uint32 env_t::server_announce = 0; bool env_t::easy_server = false; // Minimum is every 60 seconds, default is every 15 minutes (900 seconds), maximum is 86400 (1 day) sint32 env_t::server_announce_interval = 900; int env_t::server_port = env_t::server ? env_t::server : 13353; std::string env_t::server_dns; std::string env_t::server_alt_dns; // for dualstack systems std::string env_t::server_name; std::string env_t::server_comments; std::string env_t::server_email; std::string env_t::server_pakurl; std::string env_t::server_infurl; std::string env_t::server_admin_pw; std::string env_t::server_motd_filename; uint8 env_t::chat_unread_public = 0; uint8 env_t::chat_unread_company = 0; uint8 env_t::chat_unread_whisper = 0; vector_tpl env_t::listen; bool env_t::server_save_game_on_quit = false; bool env_t::reload_and_save_on_quit = true; uint8 env_t::network_heavy_mode = 0; sint32 env_t::server_frames_ahead = 4; sint32 env_t::additional_client_frames_behind = 4; sint32 env_t::network_frames_per_step = 4; uint32 env_t::server_sync_steps_between_checks = 24; bool env_t::pause_server_no_clients = false; std::string env_t::nickname = ""; // this is explicitly and interactively set by user => we do not touch it on init const char *env_t::language_iso = "en"; sint16 env_t::scroll_multi = -1; // start with same scrool as mouse as nowadays standard bool env_t::scroll_infinite = false; // since it fails with touch devices uint16 env_t::scroll_threshold = 8; sint16 env_t::global_volume = 127; uint32 env_t::sound_distance_scaling; sint16 env_t::midi_volume = 127; uint16 env_t::specific_volume[MAX_SOUND_TYPES]; std::string env_t::soundfont_filename = ""; std::string env_t::pakset_tutorial_dir = "tutorial"; bool env_t::global_mute_sound = false; bool env_t::mute_midi = false; bool env_t::shuffle_midi = true; sint16 env_t::window_snap_distance = 8; sint16 env_t::iconscaling=100; scr_size env_t::iconsize( 32, 32 ); uint8 env_t::chat_window_transparency = 75; bool env_t::hide_rail_return_ticket = true; bool env_t::numpad_always_moves_map = true; bool env_t::leftdrag_in_minimap = true; // only used internally => do not touch further bool env_t::quit_simutrans = false; // default settings for new games settings_t env_t::default_settings; // what finances are shown? (default bank balance) bool env_t::player_finance_display_account = true; // the following initialisation is not important; set values in init()! bool env_t::night_shift; bool env_t::hide_with_transparency; bool env_t::hide_trees; uint8 env_t::hide_buildings; bool env_t::hide_under_cursor; uint16 env_t::cursor_hide_range; bool env_t::use_transparency_station_coverage; uint8 env_t::station_coverage_show; sint32 env_t::show_names; sint32 env_t::message_flags[4]; uint32 env_t::water_animation; uint32 env_t::ground_object_probability; uint32 env_t::moving_object_probability; bool env_t::road_user_info; bool env_t::tree_info; bool env_t::ground_info; uint8 env_t::show_factory_storage_bar; bool env_t::townhall_info; bool env_t::single_line_gui; bool env_t::window_buttons_right; bool env_t::second_open_closes_win; bool env_t::remember_window_positions; bool env_t::window_frame_active; log_t::level_t env_t::verbose_debug; uint8 env_t::default_sortmode; uint32 env_t::default_mapmode; uint8 env_t::show_month; sint32 env_t::intercity_road_length; plainstring env_t::river_type[10]; uint8 env_t::river_types; sint32 env_t::autosave; uint32 env_t::fps; uint32 env_t::ff_fps; sint16 env_t::max_acceleration; uint8 env_t::num_threads; bool env_t::show_tooltips; rgb888_t env_t::tooltip_color_rgb; PIXVAL env_t::tooltip_color; rgb888_t env_t::tooltip_textcolor_rgb; PIXVAL env_t::tooltip_textcolor; sint8 env_t::toolbar_max_width; sint8 env_t::toolbar_max_height; rgb888_t env_t::cursor_overlay_color_rgb; PIXVAL env_t::cursor_overlay_color; rgb888_t env_t::background_color_rgb; PIXVAL env_t::background_color; bool env_t::draw_earth_border; bool env_t::draw_outside_tile; uint8 env_t::show_vehicle_states; bool env_t::visualize_schedule; sint8 env_t::daynight_level; bool env_t::left_to_right_graphs; uint32 env_t::tooltip_delay; uint32 env_t::tooltip_duration; sint8 env_t::show_money_message; uint8 env_t::gui_player_color_dark = 1; uint8 env_t::gui_player_color_bright = 4; #ifdef __ANDROID__ uint8 env_t::fontsize = 17; #else uint8 env_t::fontsize = 11; #endif std::string env_t::fontname; rgb888_t env_t::front_window_text_color_rgb; PIXVAL env_t::front_window_text_color; rgb888_t env_t::bottom_window_text_color_rgb; PIXVAL env_t::bottom_window_text_color; rgb888_t env_t::default_window_title_color_rgb; PIXVAL env_t::default_window_title_color; uint8 env_t::bottom_window_darkness; uint16 env_t::compass_map_position; uint16 env_t::compass_screen_position; uint32 env_t::default_ai_construction_speed; #ifdef __ANDROID__ // autoshow keyboard on textinput bool env_t::hide_keyboard = true; #else bool env_t::hide_keyboard = false; #endif // Define default settings. void env_t::init() { fontname = dr_get_system_font(); // settings for messages message_flags[0] = 0x017F; message_flags[1] = 0x0108; message_flags[2] = 0x0080; message_flags[3] = 0; night_shift = true; hide_with_transparency = true; hide_trees = false; hide_buildings = env_t::NOT_HIDE; hide_under_cursor = false; cursor_hide_range = 5; scroll_infinite = false; scroll_threshold = 16; visualize_schedule = true; /* station stuff */ use_transparency_station_coverage = true; station_coverage_show = 0; show_names = 3; player_finance_display_account = true; water_animation = 250; // 250ms per wave stage ground_object_probability = 10; // every n-th tile moving_object_probability = 1000; // every n-th tile follow_convoi_underground = 2; // slice through map road_user_info = false; tree_info = true; ground_info = false; townhall_info = false; single_info = true; single_line_gui = false; random_pedestrians = true; stop_pedestrians = true; window_buttons_right = false; window_frame_active = false; second_open_closes_win = false; remember_window_positions = true; // debug level (0: only fatal, 1: error, 2: warning, 3: all verbose_debug = log_t::LEVEL_FATAL; default_sortmode = 1; // sort by amount default_mapmode = 0; // show cities savegame_version_str = SAVEGAME_VER_NR; show_month = DATE_FMT_US; show_factory_storage_bar = 0; intercity_road_length = 200; river_types = 0; // autosave every x months (0=off) autosave = 0; reload_and_save_on_quit = true; // default: make 25 frames per second (if possible) and 10 for faster fast forward fps = 25; ff_fps = 10; // maximum speedup set to 1000 (effectively no limit) max_acceleration=50; #ifdef MULTI_THREAD num_threads = min(MAX_THREADS,dr_get_max_threads()); #else num_threads = 1; #endif sound_distance_scaling = 10; show_tooltips = true; tooltip_color_rgb = { 0x39, 0x64, 0xD0 }; // COL_SOFT_BLUE tooltip_textcolor_rgb = { 0x00, 0x00, 0x00 }; // COL_BLACK toolbar_max_width = 0; toolbar_max_height = 0; cursor_overlay_color_rgb = { 0xFF, 0x80, 0x00 }; // COL_ORANGE background_color_rgb = { 0x40, 0x40, 0x40 }; // COL_GREY2 draw_earth_border = true; draw_outside_tile = false; show_vehicle_states = 1; daynight_level = 0; // midi/sound option global_volume = 127; midi_volume = 127; global_mute_sound = false; mute_midi = false; shuffle_midi = true; for( int i = 0; i < MAX_SOUND_TYPES; i++ ) { specific_volume[ i ] = 255; } left_to_right_graphs = false; tooltip_delay = 500; tooltip_duration = 5000; front_window_text_color_rgb = { 0xFF, 0xFF, 0xFF }; // COL_WHITE bottom_window_text_color_rgb = { 0xDD, 0xDD, 0xDD }; default_window_title_color_rgb = { 0xD7, 0x6B, 0x00 }; bottom_window_darkness = 25; default_ai_construction_speed = 8000; // upper right compass_map_position = ALIGN_RIGHT|ALIGN_TOP; // lower right compass_screen_position = 0; // disbale, other could be ALIGN_RIGHT|ALIGN_BOTTOM; // Listen on all addresses by default listen.append_unique("::"); listen.append_unique("0.0.0.0"); show_money_message = 0; #ifndef __ANDROID__ env_t::menupos = MENU_TOP; env_t::single_toolbar_mode = false; env_t::dpi_scale = 100; env_t::single_info = 1; env_t::hide_keyboard = false; #else // here for Android env_t::menupos = MENU_BOTTOM; env_t::single_toolbar_mode = true; env_t::dpi_scale = -1; env_t::single_info = 0; // autoshow keyboard on textinput env_t::hide_keyboard = true; #endif } // save/restore environment void env_t::rdwr(loadsave_t *file) { // env_t used to be called umgebung_t - keep old name when saving and loading for compatibility xml_tag_t u( file, "umgebung_t" ); file->rdwr_short( scroll_multi ); file->rdwr_bool( night_shift ); file->rdwr_byte( daynight_level ); file->rdwr_long( water_animation ); if( file->is_version_less(110, 7) ) { bool dummy_b = 0; file->rdwr_bool( dummy_b ); } file->rdwr_byte( show_month ); file->rdwr_bool( use_transparency_station_coverage ); file->rdwr_byte( station_coverage_show ); file->rdwr_long( show_names ); file->rdwr_bool( hide_with_transparency ); file->rdwr_byte( hide_buildings ); file->rdwr_bool( hide_trees ); file->rdwr_long( message_flags[0] ); file->rdwr_long( message_flags[1] ); file->rdwr_long( message_flags[2] ); file->rdwr_long( message_flags[3] ); if ( file->is_loading() ) { if( file->is_version_less(110, 0) ) { // did not know about chat message, so we enable it message_flags[0] |= (1 << message_t::chat); // ticker message_flags[1] &= ~(1 << message_t::chat); // permanent window off message_flags[2] &= ~(1 << message_t::chat); // timed window off message_flags[3] &= ~(1 << message_t::chat); // do not ignore completely } if( file->is_version_less(112, 3) ) { // did not know about scenario message, so we enable it message_flags[0] &= ~(1 << message_t::scenario); // ticker off message_flags[1] |= (1 << message_t::scenario); // permanent window on message_flags[2] &= ~(1 << message_t::scenario); // timed window off message_flags[3] &= ~(1 << message_t::scenario); // do not ignore completely } } file->rdwr_bool( show_tooltips ); if ( file->is_version_less(120, 5) ) { uint8 color_idx = COL_SOFT_BLUE; file->rdwr_byte( color_idx ); env_t::tooltip_color_rgb = get_color_rgb(color_idx); color_idx = COL_BLACK; file->rdwr_byte( color_idx ); env_t::tooltip_textcolor_rgb = get_color_rgb(color_idx); } file->rdwr_long( autosave ); file->rdwr_long( fps ); if (file->is_version_atleast(121, 1)) { file->rdwr_long(ff_fps); } file->rdwr_short( max_acceleration ); file->rdwr_bool( road_user_info ); file->rdwr_bool( tree_info ); file->rdwr_bool( ground_info ); file->rdwr_bool( townhall_info ); file->rdwr_bool( single_info ); file->rdwr_byte( default_sortmode ); if( file->is_version_less(111, 4) ) { sint8 mode = log2(env_t::default_mapmode)-1; file->rdwr_byte( mode ); env_t::default_mapmode = mode>=0 ? 1 << mode : 0; } else { file->rdwr_long( env_t::default_mapmode ); } file->rdwr_bool( window_buttons_right ); file->rdwr_bool( window_frame_active ); if( file->is_version_less(112, 1) ) { // set by command-line, it does not make sense to save it. uint8 v = verbose_debug; file->rdwr_byte( v ); } file->rdwr_long( intercity_road_length ); if( file->is_version_less(102, 3) ) { bool no_tree = false; file->rdwr_bool( no_tree ); } file->rdwr_long( ground_object_probability ); file->rdwr_long( moving_object_probability ); if( file->is_loading() ) { // these three bytes will be lost ... const char *c = NULL; file->rdwr_str( c ); language_iso = c; } else { file->rdwr_str( language_iso ); } file->rdwr_short( global_volume ); file->rdwr_short( midi_volume ); file->rdwr_bool( global_mute_sound ); if( file->is_version_atleast( 121, 1 ) ) { for( int i = 0; i <= 5; i++ ) { file->rdwr_short( specific_volume[ i ] ); } } file->rdwr_bool( mute_midi ); file->rdwr_bool( shuffle_midi ); if( file->is_version_atleast(102, 2) ) { file->rdwr_byte( show_vehicle_states ); file->rdwr_bool( left_to_right_graphs ); } if( file->is_version_atleast(102, 3) ) { file->rdwr_long( tooltip_delay ); file->rdwr_long( tooltip_duration ); if ( file->is_version_less(120, 5) ) { uint8 color = COL_WHITE; file->rdwr_byte( color ); // to skip old parameter front_window_bar_color file->rdwr_byte( color ); env_t::front_window_text_color_rgb = get_color_rgb(color); file->rdwr_byte( color ); // to skip old parameter bottom_window_bar_color color = 209; // CITY_KI file->rdwr_byte( color ); env_t::bottom_window_text_color_rgb = get_color_rgb(color); } } if( file->is_version_atleast(110, 0) ) { bool dummy = false; file->rdwr_bool(dummy); //was add_player_name_to_message file->rdwr_short( window_snap_distance ); } if( file->is_version_atleast(111, 1) ) { file->rdwr_bool( hide_under_cursor ); file->rdwr_short( cursor_hide_range ); } if( file->is_version_atleast(111, 2) ) { file->rdwr_bool( visualize_schedule ); } if( file->is_version_atleast(111, 3) ) { plainstring str = nickname.c_str(); file->rdwr_str(str); if (file->is_loading()) { nickname = str ? str.c_str() : ""; } } if( file->is_version_atleast(112, 6) ) { if( file->is_version_less(120, 5) ) { uint8 color = COL_GREY2; file->rdwr_byte( color ); env_t::background_color_rgb = get_color_rgb(color); } file->rdwr_bool( draw_earth_border ); file->rdwr_bool( draw_outside_tile ); } if( file->is_version_atleast(112, 7) ) { file->rdwr_bool( second_open_closes_win ); file->rdwr_bool( remember_window_positions ); } if( file->is_version_atleast(112, 8) && file->is_version_less(123, 2) ) { bool show_delete_buttons = false; file->rdwr_bool( show_delete_buttons ); } if( file->is_version_atleast(120, 1) ) { file->rdwr_str( default_theme ); } if( file->is_version_atleast(120, 2) ) { if( file->is_version_atleast(122, 1)) { sint32 conv_mode = height_conv_mode; file->rdwr_long( conv_mode ); if (file->is_loading()) { height_conv_mode = (env_t::height_conversion_mode)::clamp(conv_mode, 0, (int)env_t::NUM_HEIGHT_CONV_MODES-1); } } else { bool new_convert = height_conv_mode != env_t::HEIGHT_CONV_LEGACY_SMALL; file->rdwr_bool( new_convert ); height_conv_mode = new_convert ? env_t::HEIGHT_CONV_LEGACY_LARGE : env_t::HEIGHT_CONV_LEGACY_SMALL; } } if( file->is_version_atleast(120, 5) ) { file->rdwr_color( background_color_rgb ); file->rdwr_color( tooltip_color_rgb ); file->rdwr_color( tooltip_textcolor_rgb ); file->rdwr_color( default_window_title_color_rgb ); file->rdwr_color( front_window_text_color_rgb ); file->rdwr_color( bottom_window_text_color_rgb ); file->rdwr_byte( bottom_window_darkness ); } if( file->is_version_atleast(120, 6) ) { plainstring str = fontname.c_str(); file->rdwr_str( str ); if (file->is_loading()) { fontname = str ? str.c_str() : ""; } file->rdwr_byte( fontsize ); } if( file->is_version_atleast(120, 7) ) { file->rdwr_byte(show_money_message); } if (file->is_version_atleast(120, 8)) { rdwr_win_settings(file); } if (file->is_version_atleast(120, 9)) { file->rdwr_byte(follow_convoi_underground); } if (file->is_version_atleast(121, 1)) { file->rdwr_long(sound_distance_scaling); file->rdwr_byte( gui_player_color_dark ); file->rdwr_byte( gui_player_color_bright ); } if( file->is_version_atleast( 122, 1 ) ) { file->rdwr_bool( env_t::numpad_always_moves_map ); plainstring str = soundfont_filename.c_str(); file->rdwr_str( str ); if( file->is_loading() ) { soundfont_filename = str ? str.c_str() : ""; } file->rdwr_short( menupos ); menupos &= 3; file->rdwr_bool( reselect_closes_tool ); file->rdwr_bool( single_line_gui ); file->rdwr_byte( show_factory_storage_bar ); file->rdwr_short( fullscreen ); } if( file->is_version_atleast(123, 1) ) { file->rdwr_short(display_scale_percent); file->rdwr_bool(scroll_infinite); } if( file->is_version_atleast(123, 2) ) { file->rdwr_short(scroll_threshold); file->rdwr_bool(single_toolbar_mode); file->rdwr_short(dpi_scale); if( file->is_loading() ) { dr_set_screen_scale(dpi_scale); } file->rdwr_bool(random_pedestrians); file->rdwr_bool(stop_pedestrians); } if (file->is_version_atleast(124, 2)) { file->rdwr_bool(leftdrag_in_minimap); } // server settings are not saved, since they are server specific // and could be different on different servers on the same computers } simutrans-124.3/src/simutrans/dataobj/environment.h000066400000000000000000000342611474050137200225160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_ENVIRONMENT_H #define DATAOBJ_ENVIRONMENT_H #include #include "../simtypes.h" #include "../simconst.h" #include "../simcolor.h" #include "settings.h" #include "../display/scr_coord.h" #include "../tpl/vector_tpl.h" #include "../utils/plainstring.h" #include "../utils/log.h" #define TILE_HEIGHT_STEP (env_t::pak_tile_height_step) enum { MENU_LEFT, MENU_TOP, MENU_RIGHT, MENU_BOTTOM }; /** * Class to save all environment parameters, ie everything that changes * the look and feel of the game. Most of them can be changed by command-line * parameters or simuconf.tab files. */ class env_t { public: /// Points to the simutrans data directory which hosts translation theme etc. /// This directory may be write protected or only accesible for certain users /// May contain pak, scripts and addons static char base_dir[PATH_MAX]; /// Points to a global writable directory, where downloaded content content is stored /// This directory is writable to all users to store global content (like paksets) static char install_dir[PATH_MAX]; /// Points to a the user's writable directory /// This directory writable to the local user static char user_dir[PATH_MAX]; /// the selected pak (whole path, can be write protected) static std::string pak_dir; /// the folder name of the selected pak (with trailing path separator) static std::string pak_name; static sint16 menupos; static bool single_toolbar_mode; static sint16 fullscreen; static sint16 dpi_scale; /// Controls size of the virtual display static sint16 display_scale_percent; static bool reselect_closes_tool; /// version for which the savegames should be created static const char *savegame_version_str; /// this the the preferred GUI theme at startup static plainstring default_theme; /** * @name Network-related settings */ /// @{ /// true, if we are in networkmode static bool networkmode; /// number of simulation frames server runs ahead of clients static sint32 server_frames_ahead; /// additional number of frames client is behind server static sint32 additional_client_frames_behind; /// number of sync_steps before one step /// @see karte_t::interactive() static sint32 network_frames_per_step; /// server sends information to clients for checking synchronization /// after this number of sync_steps /// @see karte_t::interactive() static uint32 server_sync_steps_between_checks; /// when true, restore the windows from a savegame static bool restore_UI; /// if we are the server, we are at this port /// @see network_init_server() static const uint16 &server; /// enable/disable server announcement static uint32 server_announce; static uint8 chat_unread_public; static uint8 chat_unread_company; static uint8 chat_unread_whisper; /// number of seconds between announcements static sint32 server_announce_interval; static uint8 chat_window_transparency; /// if true a kill event will save the game under recovery#portnr#.sve static bool server_save_game_on_quit; /// if true save game under autosave-#paksetname#.sve and reload it upon startup static bool reload_and_save_on_quit; static uint8 network_heavy_mode; /// @} end of Network-related settings /** * @name Information about server which is send to list-server */ /// @{ /// If set, we are in easy server mode, assuming the IP can change any moment and thus query it before announce) static bool easy_server; /// Default port to start a new server static int server_port; /// DNS name or IP address clients should use to connect to server static std::string server_dns; /// second DNS name or more liekly IP address (for a dualstack machine) to connect to our server static std::string server_alt_dns; /// Name of server for display on list server static std::string server_name; /// Comments about server for display on list server static std::string server_comments; /// Email address of server maintainer static std::string server_email; /// Download location for pakset needed to play on server static std::string server_pakurl; /// Link to further information about server static std::string server_infurl; /// Text to be show on startup; can be formatted like helpfiles static std::string server_motd_filename; /// @} end of Information about server /** * @name Network-related settings */ /// @{ /// Server admin password (for use with nettool) static std::string server_admin_pw; /// IP addresses to listen on/send announcements on static vector_tpl listen; /// pause server if no client connected static bool pause_server_no_clients; /// nickname of player static std::string nickname; /// @} end of Network-related settings /** * @name GUI settings and windows behavior */ /// @{ /// current language static const char *language_iso; /// controls scrolling speed and scrolling direction static sint16 scroll_multi; /// enables infinite scrolling with trackball or mouse, by may fail with sytlus static bool scroll_infinite; /// scrolling with general tool (like building stops or setting halts) after dragging a threshold static uint16 scroll_threshold; /// converts numpad keys to arrows no matter of numlock state static bool numpad_always_moves_map; /// the leftbutton grags the minimap, not to real location static bool leftdrag_in_minimap; /// open info windows for pedestrian and private cars static bool road_user_info; /// open info windows for trees static bool tree_info; /// open info windows for ground tiles static bool ground_info; /// open info windows for townhalls static bool townhall_info; /// open only one info window per click on a map-square static bool single_info; /// pedestrians in cities static bool random_pedestrians; /// pedestrians at stops static bool stop_pedestrians; /// linelist enforcing single line GUI static bool single_line_gui; /// for schedules with rails hide the back ticket button static bool hide_rail_return_ticket; /// how to sort destination of goods /// @see freight_list_sorter_t::sort_mode_t static uint8 default_sortmode; /// default behavior of the map-window static uint32 default_mapmode; /// cut through the map when following convois? static uint8 follow_convoi_underground; ///which messages to display where? /** * message_flags[i] is bitfield, where bit is set if message should be show at location i, * where 0 = show message in ticker, 1 = open auto-close window, 2 = open persistent window, 3 = ignore message * @see message_option_t */ static sint32 message_flags[4]; static bool left_to_right_graphs; /** * window button at right corner (like Windows) */ static bool window_buttons_right; static bool second_open_closes_win; static bool remember_window_positions; static sint16 window_snap_distance; static sint16 iconscaling; static scr_size iconsize; /// customize your tooltips static bool show_tooltips; static rgb888_t tooltip_color_rgb; static PIXVAL tooltip_color; static rgb888_t tooltip_textcolor_rgb; static PIXVAL tooltip_textcolor; static uint32 tooltip_delay; static uint32 tooltip_duration; /// limit width and height of menu toolbars static sint8 toolbar_max_width; static sint8 toolbar_max_height; // how to highlight topped (untopped windows) static bool window_frame_active; static rgb888_t front_window_text_color_rgb; static PIXVAL front_window_text_color; static rgb888_t bottom_window_text_color_rgb; static PIXVAL bottom_window_text_color; static rgb888_t default_window_title_color_rgb; static PIXVAL default_window_title_color; static uint8 bottom_window_darkness; static uint8 gui_player_color_dark; static uint8 gui_player_color_bright; // default font name and -size static std::string fontname; static uint8 fontsize; // display compass static uint16 compass_map_position; static uint16 compass_screen_position; // what finances are shown? (default bank balance) static bool player_finance_display_account; /// @} end of GUI settings /** * @name Settings to control display of game world */ /// @{ /// show day-night cycle static bool night_shift; /// fixed day/night view level static sint8 daynight_level; /// show error/info tooltips over the vehicles static uint8 show_vehicle_states; /// show station coverage indicators static uint8 station_coverage_show; /// display station coverage by transparent overlay /// (otherwise by colored squares) static bool use_transparency_station_coverage; /// use transparency to hide buildings and trees static bool hide_with_transparency; /// which is the deafult economy? static uint8 just_in_time; /// Three states to control hiding of building enum hide_buildings_states { NOT_HIDE = 0, ///< show all buildings SOME_HIDDEN_BUILDING, ///< hide buildings near cursor ALL_HIDDEN_BUILDING ///< hide all buildings }; /// hide buildings if this is not NOT_HIDE static uint8 hide_buildings; /** * Set to true to hide all trees. "Hiding" is implemented by showing the * first pic which should be very small. */ static bool hide_trees; /// If hide_under_cursor is true then /// buildings and trees near mouse cursor will be hidden. static bool hide_under_cursor; /// Hide buildings and trees within range of mouse cursor static uint16 cursor_hide_range; /// color used for cursor overlay blending static rgb888_t cursor_overlay_color_rgb; static PIXVAL cursor_overlay_color; static sint8 show_money_message; /// color used for solid background draw static rgb888_t background_color_rgb; static PIXVAL background_color; /// true if the border shut be shown as cut through the earth static bool draw_earth_border; /// true if the outside tiles should be shown static bool draw_outside_tile; /** * Show labels (city and station names, ...) * and waiting indicator bar for stations * @see grund_t::display_overlay */ static sint32 show_names; /// Show factory storage bar static uint8 show_factory_storage_bar; /// if a schedule is open, show tiles which are used by it static bool visualize_schedule; /// time per water animation frame (0=off) static uint32 water_animation; /// how many internal pixel per height step (default 16) static sint8 pak_tile_height_step; /// new height for old slopes after conversion - 1=single height, 2=double height /// Only use during loading of old games! static sint8 pak_height_conversion_factor; enum height_conversion_mode { HEIGHT_CONV_LEGACY_SMALL, ///< Old (fixed) height conversion, small height difference HEIGHT_CONV_LEGACY_LARGE, ///< Old (fixed) height conversion, larger height difference HEIGHT_CONV_LINEAR, ///< linear interpolation between min_/max_allowed_height HEIGHT_CONV_CLAMP, ///< Use 1 height level per 1 greyscale level, clamp to allowed height (cut off mountains) NUM_HEIGHT_CONV_MODES }; static height_conversion_mode height_conv_mode; /// use the faster drawing routine (and allow for clipping errors) static bool simple_drawing; /// if tile-size is less than this value (will be updated automatically) static sint16 simple_drawing_normal; /// if tile-size is less than this value (set by simuconf.tab) static sint16 simple_drawing_default; /// always use fast drawing in fast forward static bool simple_drawing_fast_forward; /// format in which date is shown enum date_fmt { DATE_FMT_SEASON = 0, DATE_FMT_MONTH = 1, DATE_FMT_JAPANESE = 2, DATE_FMT_US = 3, DATE_FMT_GERMAN = 4, DATE_FMT_JAPANESE_NO_SEASON = 5, DATE_FMT_US_NO_SEASON = 6, DATE_FMT_GERMAN_NO_SEASON = 7 }; /** * show month in date? */ static uint8 show_month; /// @} end of Settings to control display of game world /** * @name Settings to control the simulation (to some extent) */ /// @{ static uint32 fps; ///< target frame rate static uint32 ff_fps; ///< target fps during fast forward static const uint32 min_fps = 5; ///< minimum target fps (actual fps may be lower for large zoom out on slow machines) static const uint32 max_fps = 100; /// maximum acceleration with fast forward static sint16 max_acceleration; /// number of threads to use (if MULTI_THREAD defined) static uint8 num_threads; /// false to quit the programs static bool quit_simutrans; /// @} end of Settings to control the simulation /** * @name Settings used at world creation */ /// @{ /// probability for ground objects (if exists) static uint32 ground_object_probability; /// probability for moving objects (if there) static uint32 moving_object_probability; /// maximum length of city connections static sint32 intercity_road_length; // AI construction speed for new games (default 8000) static uint32 default_ai_construction_speed; /** * Name of rivers; first the river with the lowest number */ static plainstring river_type[10]; /// number of different river types static uint8 river_types; /// @} /// Produce more debug info: /// can be set by command-line switch '-debug' static log_t::level_t verbose_debug; /// do autosave every month? static sint32 autosave; /** * @name Midi/sound options */ /// @{ static sint16 global_volume, midi_volume; static bool mute_midi, shuffle_midi; static bool global_mute_sound; static uint16 specific_volume[MAX_SOUND_TYPES]; /// how dast are distant sounds fading (1: very fast 25: very little) static uint32 sound_distance_scaling; // FluidSynth MIDI parameters static std::string soundfont_filename; /// @} /// if true this will show a softkeyboard only when editing text /// default is off static bool hide_keyboard; /// default settings /// read in simmain.cc from various tab files /// @see simmain.cc static settings_t default_settings; /// construct always straight ways /// as if ctrl-key permanently pressed /// cannot be used in network mode static bool straight_way_without_control; /// initialize with default values static void init(); /** * load/saving these from file (settings.xml) * @see simmain.cc */ static void rdwr(loadsave_t *file); /// Name of tutorial scenario for the current pakset. /// Defaults to "tutorial". static std::string pakset_tutorial_dir; }; #endif simutrans-124.3/src/simutrans/dataobj/freelist.cc000066400000000000000000000027131474050137200221220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simtypes.h" #include "../simmem.h" #include "freelist.h" #include "../tpl/freelist_tpl.h" // for 64 bit, set this to 128 #define MAX_LIST_INDEX (128) // list for nodes size 8...64 #define NUM_LIST ((MAX_LIST_INDEX/4)+1) static freelist_size_t* all_lists[NUM_LIST] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; #ifdef MULTI_THREAD static pthread_mutex_t freelist_mutex_create = PTHREAD_MUTEX_INITIALIZER;; #endif void* freelist_t::gimme_node(size_t size) { size_t idx = (size + 3) / 4; if (idx > NUM_LIST) { return xmalloc(size); } if (all_lists[idx] == NULL) { #ifdef MULTI_THREAD pthread_mutex_lock(&freelist_mutex_create); #endif all_lists[idx] = new freelist_size_t(size * 4); #ifdef MULTI_THREAD pthread_mutex_unlock(&freelist_mutex_create); #endif } return all_lists[idx]->gimme_node(); } void freelist_t::putback_node(size_t size, void* p) { size = (size + 3) / 4; if (size > NUM_LIST) { free(p); } else { all_lists[size]->putback_node(p); } } void free_all_nodes() { for (int size = 0; size < NUM_LIST; size++) { if (all_lists[size]) { delete all_lists[size]; all_lists[size] = NULL; } } } simutrans-124.3/src/simutrans/dataobj/freelist.h000066400000000000000000000006421474050137200217630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_FREELIST_H #define DATAOBJ_FREELIST_H /** * Helper class to organize small memory objects i.e. nodes for linked lists * and such. */ class freelist_t { public: static void *gimme_node( size_t size ); static void putback_node( size_t size, void *p ); static void free_all_nodes(); }; #endif simutrans-124.3/src/simutrans/dataobj/gameinfo.cc000066400000000000000000000121661474050137200220750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gameinfo.h" #include "../network/network.h" #include "../network/network_socket_list.h" #include "settings.h" #include "translator.h" #include "environment.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../world/simcity.h" #include "../simhalt.h" #include "../descriptor/ground_desc.h" #include "../player/simplay.h" #include "../gui/minimap.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "loadsave.h" #include "../network/pakset_info.h" #include "../simversion.h" #define MINIMAP_SIZE (64) gameinfo_t::gameinfo_t(karte_t *welt) : map_idx(MINIMAP_SIZE,MINIMAP_SIZE), map_rgb(MINIMAP_SIZE,MINIMAP_SIZE), game_comment(""), file_name(""), pak_name("") { size_x = welt->get_size().x; size_y = welt->get_size().y; // create a minimap industries = welt->get_fab_list().get_count(); tourist_attractions = welt->get_attractions().get_count(); city_count = welt->get_cities().get_count(); citizen_count = 0; for(stadt_t* const i : welt->get_cities()) { citizen_count += i->get_einwohner(); } const int gr_x = welt->get_size().x; const int gr_y = welt->get_size().y; for( uint16 i = 0; i < MINIMAP_SIZE; i++ ) { for( uint16 j = 0; j < MINIMAP_SIZE; j++ ) { const koord pos(i * gr_x / MINIMAP_SIZE, j * gr_y / MINIMAP_SIZE); const grund_t* gr = welt->lookup_kartenboden(pos); map_rgb.at(i,j) = minimap_t::calc_ground_color(gr); map_idx.at(i,j) = color_rgb_to_idx( map_rgb.at(i,j) ); } } total_pass_transported = welt->get_finance_history_month(1,karte_t::WORLD_PAS_RATIO); total_mail_transported = welt->get_finance_history_month(1,karte_t::WORLD_MAIL_RATIO); total_goods_transported = welt->get_finance_history_month(1,karte_t::WORLD_GOODS_RATIO); convoi_count = welt->convoys().get_count(); for( int i=0; iget_player(i) ) { player_type[i] = player->get_ai_id(); if( !player->access_password_hash().empty() ) { player_type[i] |= player_t::PASSWORD_PROTECTED; } } } clients = socket_list_t::get_playing_clients(); halt_count = haltestelle_t::get_alle_haltestellen().get_count(); settings_t const& s = welt->get_settings(); freeplay = s.is_freeplay(); use_timeline = welt->get_timeline_year_month()!=0; current_starting_money = s.get_starting_money(welt->get_last_year()); current_year_month = welt->get_current_month(); bits_per_month = s.get_bits_per_month(); // names of the stations ... tstrncpy(language_code_names, translator::get_langs()[s.get_name_language_id()].iso, lengthof(language_code_names)); // will contain server-IP/name for network games file_name = s.get_filename(); // comment currently not used char const* const copyright = ground_desc_t::outside->get_copyright(); if (copyright && STRICMP("none", copyright) != 0) { // construct from outside object copyright string pak_name = copyright; } else { // construct from pak name pak_name = env_t::pak_name; pak_name.erase( pak_name.length()-1 ); } #ifdef REVISION game_engine_revision = atol( QUOTEME(REVISION) ); #else game_engine_revision = 0; #endif pakset_checksum = *(pakset_info_t::get_checksum()); } gameinfo_t::gameinfo_t(loadsave_t *file) : map_idx(MINIMAP_SIZE,MINIMAP_SIZE), map_rgb(MINIMAP_SIZE,MINIMAP_SIZE), game_comment(""), file_name(""), pak_name("") { rdwr( file ); } void gameinfo_t::rdwr(loadsave_t *file) { xml_tag_t e( file, "gameinfo_t" ); file->rdwr_long( size_x ); file->rdwr_long( size_y ); for( int y=0; yrdwr_short( map_idx.at(x,y) ); if (file->is_loading()) { map_rgb.at(x,y) = color_idx_to_rgb(map_idx.at(x,y)); } } } file->rdwr_long( industries ); file->rdwr_long( tourist_attractions ); file->rdwr_long( city_count ); file->rdwr_long( citizen_count ); file->rdwr_short( convoi_count ); file->rdwr_short( halt_count ); file->rdwr_longlong( total_pass_transported ); file->rdwr_longlong( total_mail_transported ); file->rdwr_longlong( total_goods_transported ); file->rdwr_longlong( total_goods_transported ); file->rdwr_bool( freeplay ); file->rdwr_bool( use_timeline ); file->rdwr_longlong( current_starting_money ); file->rdwr_long( current_year_month ); file->rdwr_short( bits_per_month ); file->rdwr_str(language_code_names, lengthof(language_code_names) ); char temp[PATH_MAX]; tstrncpy( temp, game_comment.c_str(), lengthof(temp) ); file->rdwr_str( temp, lengthof(temp) ); // game_comment if( file->is_loading() ) { game_comment = temp; } tstrncpy( temp, file_name.c_str(), lengthof(temp) ); file->rdwr_str( temp, lengthof(temp) ); // file_name if( file->is_loading() ) { file_name = temp; } tstrncpy( temp, pak_name.c_str(), lengthof(temp) ); file->rdwr_str( temp, lengthof(temp) ); // pak_name if( file->is_loading() ) { pak_name = temp; } file->rdwr_long( game_engine_revision ); for( int i=0; i<16; i++ ) { file->rdwr_byte( player_type[i] ); } file->rdwr_byte( clients ); pakset_checksum.rdwr(file); } simutrans-124.3/src/simutrans/dataobj/gameinfo.h000066400000000000000000000051621474050137200217350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_GAMEINFO_H #define DATAOBJ_GAMEINFO_H #include #include "../simtypes.h" #include "../simconst.h" #include "../simcolor.h" #include "../tpl/array2d_tpl.h" #include "../network/checksum.h" class karte_t; class loadsave_t; /** * Info about the current game */ class gameinfo_t { private: sint32 size_x, size_y; /** * Two pixel arrays: one with indexed colors (sent by servers), * one with rgb colors (will be displayed) */ array2d_tpl map_idx, map_rgb; sint32 industries; sint32 tourist_attractions; sint32 city_count; sint32 citizen_count; uint16 convoi_count; uint16 halt_count; sint64 total_pass_transported; sint64 total_mail_transported; sint64 total_goods_transported; bool freeplay; bool use_timeline; sint64 current_starting_money; uint32 current_year_month; sint16 bits_per_month; // names of the stations ... char language_code_names[4]; std::string game_comment; std::string file_name; std::string pak_name; uint32 game_engine_revision; checksum_t pakset_checksum; // 0 = empty, otherwise some value from simplay uint8 player_type[MAX_PLAYER_COUNT]; uint8 clients; // currently connected players public: gameinfo_t( karte_t *welt ); gameinfo_t( loadsave_t *file ); void rdwr( loadsave_t *file ); sint32 get_size_x() const {return size_x;} sint32 get_size_y() const {return size_y;} const array2d_tpl *get_map() const { return &map_rgb; } sint32 get_industries() const {return industries;} sint32 get_tourist_attractions() const {return tourist_attractions;} sint32 get_city_count() const {return city_count;} sint32 get_citizen_count() const {return citizen_count;} sint32 get_convoi_count() const {return convoi_count;} sint32 get_halt_count() const {return halt_count;} uint8 get_use_timeline() const {return use_timeline;} sint16 get_current_year() const {return current_year_month/12;} sint16 get_current_month() const {return (current_year_month%12);} sint16 get_bits_per_month() const {return bits_per_month;} bool is_freeplay() const { return freeplay; } sint64 get_current_starting_money() const {return current_starting_money;} uint32 get_game_engine_revision() const { return game_engine_revision; } const char *get_name_language_iso() const { return language_code_names; } const char *get_pak_name() const { return pak_name.c_str(); } uint8 get_player_type(uint8 i) const { return player_type[i]; } uint8 get_clients() const { return clients; } const checksum_t & get_pakset_checksum() const { return pakset_checksum; } }; #endif simutrans-124.3/src/simutrans/dataobj/height_map_loader.cc000066400000000000000000000056331474050137200237440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "height_map_loader.h" #include "environment.h" #include "../simio.h" #include "../sys/simsys.h" #include "../simmem.h" #include "../macros.h" #include "../io/raw_image.h" #include #include #include height_map_loader_t::height_map_loader_t(sint8 min_height, sint8 max_height, env_t::height_conversion_mode mode) : min_allowed_height(min_height), max_allowed_height(max_height), conv_mode(mode) { } // read height data from bmp or ppm files bool height_map_loader_t::get_height_data_from_file( const char *filename, sint8 groundwater, sint8 *&hfield, sint16 &ww, sint16 &hh, bool update_only_values ) { hfield = NULL; raw_image_t heightmap_img; if (!heightmap_img.read_from_file(filename)) { dbg->error("height_map_loader_t::get_height_data_from_file", "Cannot read heightmap file '%s'", filename); return false; } // report only values if( update_only_values ) { ww = heightmap_img.get_width(); hh = heightmap_img.get_height(); return true; } // ok, now read them in hfield = MALLOCN(sint8, heightmap_img.get_width()*heightmap_img.get_height()); if (!hfield) { dbg->error("height_map_loader_t::get_height_data_from_file", "Not enough memory"); return false; } memset( hfield, groundwater, heightmap_img.get_width()*heightmap_img.get_height() ); for (uint32 y=0; y(h0/32 - 28, min_allowed_height, max_allowed_height); // -28..19 } else { return ::clamp(h0/64 - 14, min_allowed_height, max_allowed_height); // -14..9 } } case env_t::HEIGHT_CONV_LEGACY_LARGE: { // new style, heights more spread out if( env_t::pak_height_conversion_factor == 2 ) { return ::clamp(h0/24 - 34, min_allowed_height, max_allowed_height); // -34..29 } else { return ::clamp(h0/48 - 18, min_allowed_height, max_allowed_height); // -18..13 } } case env_t::HEIGHT_CONV_LINEAR: { return min_allowed_height + (h0*(max_allowed_height-min_allowed_height)) / 0x5FA; } case env_t::HEIGHT_CONV_CLAMP: { return ::clamp((sint8)(((h0 * 0xFF) / 0x5FA) - 128), min_allowed_height, max_allowed_height); } default: dbg->fatal("height_map_loader_t::rgb_to_height", "Unhandled height conversion mode %d", conv_mode); } } simutrans-124.3/src/simutrans/dataobj/height_map_loader.h000066400000000000000000000027341474050137200236050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_HEIGHT_MAP_LOADER_H #define DATAOBJ_HEIGHT_MAP_LOADER_H #include "../simtypes.h" #include "environment.h" /** * Loads height data from BMP or PPM files. */ class height_map_loader_t { public: height_map_loader_t(sint8 min_allowed_height, sint8 max_allowed_height, env_t::height_conversion_mode conv_mode); /** * Reads height data from 8 or 24 bit bmp or ppm files. * * @param filename the file to load the height data from. * @param groundwater * @param update_only_values When true, do not allocate the height field; instead, only update @p ww and @p hh * @param[out] hfield 2d array of height values. * @param[out] ww width of @p hfield. On failure, this value is undefined. * @param[out] hh height of @p hfield. On failure, this value is undefined. * * @return true on success, false on failure. On success, @p hfield contains * the height field data (must be free()'d by the caller unless @p update_only_values is set). * On failure, @p hfield is set to NULL (Does not need to be free()'d) */ bool get_height_data_from_file( const char *filename, sint8 groundwater, sint8 *&hfield, sint16 &ww, sint16 &hh, bool update_only_values ); private: sint8 rgb_to_height( const int r, const int g, const int b ); private: const sint8 min_allowed_height; const sint8 max_allowed_height; const env_t::height_conversion_mode conv_mode; }; #endif simutrans-124.3/src/simutrans/dataobj/koord.cc000066400000000000000000000104121474050137200214160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "koord.h" #include "loadsave.h" #include "../display/scr_coord.h" #include "../utils/simrandom.h" #include "../simconst.h" // default: close and far away does not matter uint32 koord::locality_factor = 10000; const scr_coord scr_coord::invalid(-1, -1); const scr_size scr_size::invalid(-1, -1); const scr_size scr_size::inf(0x7fffffff, 0x7fffffff); const koord koord::invalid(-1, -1); const koord koord::north( 0, -1); const koord koord::east( 1, 0); const koord koord::south( 0, 1); const koord koord::west( -1, 0); const koord koord::nesw[] = { koord( 0, -1), koord( 1, 0), koord( 0, 1), koord(-1, 0) }; const koord koord::neighbours[] = { koord( -1, -1), koord( -1, 0 ), koord( -1, 1 ), koord( 0, 1 ), koord( 1, 1 ), koord( 1, 0 ), koord( 1, -1 ), koord( 0, -1 ) }; const koord koord::from_ribi[] = { koord( 0, 0), // none koord( 0, -1), // north (1) koord( 1, 0), // east (2) koord( 1, -1), // north-east (3) koord( 0, 1), // south (4) koord( 0, 0), // north-south (5) koord( 1, 1), // south-east (6) koord( 1, 0), // north-south-east (7) koord(-1, 0), // west (8) koord(-1, -1), // north-west (9) koord( 0, 0), // east-west (10) koord( 0, -1), // north-east-west (11) koord(-1, 1), // south-west (12) koord(-1, 0), // north-south-west (13) koord( 0, 1), // south-east-west (14) koord( 0, 0) // all }; const koord koord::from_hang[] = { koord( 0, 0), // 0:flat koord( 0, 0), // 1: koord( 0, 0), // 2: koord( 0, 0), // 3: koord( 0, 1), // 4:north single height slope koord( 0, 0), // 5: koord( 0, 0), // 6: koord( 0, 0), // 7: koord( 0, 1), // 8:north double height slope koord( 0, 0), // 9: koord( 0, 0), // 10: koord( 0, 0), // 11: koord( 1, 0), // 12:west single height slope koord( 0, 0), // 13: koord( 0, 0), // 14: koord( 0, 0), // 15: koord( 0, 0), // 16: koord( 0, 0), // 17: koord( 0, 0), // 18: koord( 0, 0), // 19: koord( 0, 0), // 20: koord( 0, 0), // 21: koord( 0, 0), // 22: koord( 0, 0), // 23: koord( 1, 0), // 24:west double height slope koord( 0, 0), // 25: koord( 0, 0), // 26: koord( 0, 0), // 27: koord(-1, 0), // 28:east single height slope koord( 0, 0), // 29: koord( 0, 0), // 30: koord( 0, 0), // 31: koord( 0, 0), // 32: koord( 0, 0), // 33: koord( 0, 0), // 34: koord( 0, 0), // 35: koord( 0, -1), // 36:south single height slope koord( 0, 0), // 37: koord( 0, 0), // 38: koord( 0, 0), // 39: koord( 0, 0), // 40: koord( 0, 0), // 41: koord( 0, 0), // 42: koord( 0, 0), // 43: koord( 0, 0), // 44: koord( 0, 0), // 45: koord( 0, 0), // 46: koord( 0, 0), // 47: koord( 0, 0), // 48: koord( 0, 0), // 49: koord( 0, 0), // 50: koord( 0, 0), // 51: koord( 0, 0), // 52: koord( 0, 0), // 53: koord( 0, 0), // 54: koord( 0, 0), // 55: koord(-1, 0), // 56:east double height slope koord( 0, 0), // 57: koord( 0, 0), // 58: koord( 0, 0), // 59: koord( 0, 0), // 60: koord( 0, 0), // 61: koord( 0, 0), // 62: koord( 0, 0), // 63: koord( 0, 0), // 64: koord( 0, 0), // 65: koord( 0, 0), // 66: koord( 0, 0), // 67: koord( 0, 0), // 68: koord( 0, 0), // 69: koord( 0, 0), // 70: koord( 0, 0), // 71: koord( 0, -1), // 72:south double height slope koord( 0, 0), // 73: koord( 0, 0), // 74: koord( 0, 0), // 75: koord( 0, 0), // 76: koord( 0, 0), // 77: koord( 0, 0), // 78: koord( 0, 0), // 79: koord( 0, 0) // 80: }; void koord::rdwr(loadsave_t *file) { xml_tag_t k( file, "koord" ); file->rdwr_short(x); file->rdwr_short(y); } // for debug messages... const char *koord::get_str() const { static char pos_str[32]; if(x==-1 && y==-1) { return "koord invalid"; } sprintf( pos_str, "%i,%i", x, y ); return pos_str; } const char *koord::get_fullstr() const { static char pos_str[32]; if(x==-1 && y==-1) { return "koord invalid"; } sprintf( pos_str, "(%i,%i)", x, y ); return pos_str; } // obey order of simrand among different compilers koord koord::koord_random( uint16 xrange, uint16 yrange ) { koord ret; ret.x = simrand(xrange); ret.y = simrand(yrange); return ret; } simutrans-124.3/src/simutrans/dataobj/koord.h000066400000000000000000000066361474050137200212750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_KOORD_H #define DATAOBJ_KOORD_H #include "ribi.h" #include "../simtypes.h" #include class loadsave_t; /** * 2D Coordinates */ class koord { public: // this is set by einstelugen_t static uint32 locality_factor; sint16 x; sint16 y; koord() : x(0), y(0) {} koord(sint16 xp, sint16 yp) : x(xp), y(yp) {} koord(ribi_t::ribi ribi) { *this = from_ribi[ribi]; } koord(slope_t::type slope) { *this = from_hang[slope]; } // use this instead of koord(simrand(x),simrand(y)) to avoid // different order on different compilers static koord koord_random(uint16 xrange, uint16 yrange); void rdwr(loadsave_t *file); const char *get_str() const; const char *get_fullstr() const; // including brackets const koord& operator += (const koord & k) { x += k.x; y += k.y; return *this; } const koord& operator -= (const koord & k) { x -= k.x; y -= k.y; return *this; } void rotate90( sint16 y_size ) { if( (x&y)<0 ) { // do not rotate illegal coordinates return; } sint16 new_x = y_size-y; y = x; x = new_x; } inline void clip_min( koord k_min ) { if (x < k_min.x) { x = k_min.x; } if (y < k_min.y) { y = k_min.y; } } inline void clip_max( koord k_max ) { if (x > k_max.x) { x = k_max.x; } if (y > k_max.y) { y = k_max.y; } } static const koord invalid; static const koord north; static const koord south; static const koord east; static const koord west; // the 4 basic directions as an Array static const koord nesw[4]; // 8 next neighbours static const koord neighbours[8]; private: static const koord from_ribi[16]; static const koord from_hang[81]; }; static inline uint32 koord_distance(const koord &a, const koord &b) { return abs(a.x - b.x) + abs(a.y - b.y); } // shortest distance in cardinal (N, E, S, W) and ordinal (NE, SE, SW, NW) directions static inline uint32 shortest_distance(const koord &a, const koord &b) { const uint32 x_offset = abs(a.x - b.x); const uint32 y_offset = abs(a.y - b.y); // square root of 2 is estimated by 181/128; 64 is for rounding if( x_offset>=y_offset ) { return (x_offset - y_offset) + ( ((y_offset * 181u) + 64u) >> 7 ); } else { return (y_offset - x_offset) + ( ((x_offset * 181u) + 64u) >> 7 ); } } // multiply the value by the distance weight static inline uint32 weight_by_distance(const sint32 value, const uint32 distance) { return value<=0 ? 0 : 1+(uint32)( ( ((sint64)value<<8) * koord::locality_factor ) / ( (sint64)koord::locality_factor + (sint64)(distance < 4u ? 4u : distance) ) ); } static inline koord operator * (const koord &k, const sint16 m) { return koord(k.x * m, k.y * m); } static inline koord operator / (const koord &k, const sint16 m) { return koord(k.x / m, k.y / m); } static inline bool operator == (const koord &a, const koord &b) { // only this works with O3 optimisation! return ((a.x-b.x)|(a.y-b.y))==0; } static inline bool operator != (const koord &a, const koord &b) { // only this works with O3 optimisation! return ((a.x-b.x)|(a.y-b.y))!=0; } static inline koord operator + (const koord &a, const koord &b) { return koord(a.x + b.x, a.y + b.y); } static inline koord operator - (const koord &a, const koord &b) { return koord(a.x - b.x, a.y - b.y); } static inline koord operator - (const koord &a) { return koord(-a.x, -a.y); } #endif simutrans-124.3/src/simutrans/dataobj/koord3d.cc000066400000000000000000000043371474050137200216560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "koord3d.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" const koord3d koord3d::invalid(-1, -1, -1); void koord3d::rotate90( sint16 y_diff ) { sint16 new_x = y_diff-y; y = x; x = new_x; } void koord3d::rdwr(loadsave_t *file) { xml_tag_t k( file, "koord3d" ); sint16 v16; v16 = x; file->rdwr_short(v16); x = v16; v16 = y; file->rdwr_short(v16); y = v16; if(file->is_version_less(99, 5)) { file->rdwr_short(v16); if(v16!=-1) { z = (v16/16); } else { // keep invalid position z = -1; } } else { sint8 v8=z; file->rdwr_byte(v8); z = v8; } if( file->is_loading() && file->is_version_less(112, 7) && x != -1 && y != -1 ) { // convert heights from old single height saved game z *= env_t::pak_height_conversion_factor; } } // for debug messages... const char *koord3d::get_str() const { static char pos_str[32]; if(x==-1 && y==-1 && z==-1) { return "koord3d invalid"; } sprintf( pos_str, "%i,%i,%i", x, y, z ); return pos_str; } // for debug messages... const char *koord3d::get_fullstr() const { static char pos_str[32]; if(x==-1 && y==-1 && z==-1) { return "koord3d invalid"; } sprintf( pos_str, "(%i,%i,%i)", x, y, z ); return pos_str; } ribi_t::ribi koord3d_vector_t::get_ribi( uint32 index ) const { ribi_t::ribi ribi = ribi_t::none; koord3d pos = operator[](index); if( index > 0 ) { ribi |= ribi_type( operator[](index-1) - pos ); } if( index+1 < get_count() ) { ribi |= ribi_type( operator[](index+1) - pos ); } return ribi; } ribi_t::ribi koord3d_vector_t::get_short_ribi( uint32 index ) const { ribi_t::ribi ribi = ribi_t::none; const koord pos = operator[](index).get_2d(); if( index > 0 ) { const koord pos2 = operator[](index-1).get_2d(); if (koord_distance(pos,pos2)<=1) { ribi |= ribi_type( pos2-pos ); } } if( index+1 < get_count() ) { const koord pos2 = operator[](index+1).get_2d(); if (koord_distance(pos,pos2)<=1) { ribi |= ribi_type( pos2-pos ); } } return ribi; } void koord3d_vector_t::rotate90( sint16 y_size ) { for(koord3d & i : *this) { i.rotate90(y_size); } } simutrans-124.3/src/simutrans/dataobj/koord3d.h000066400000000000000000000053161474050137200215160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_KOORD3D_H #define DATAOBJ_KOORD3D_H #include "koord.h" #include "ribi.h" #include "../simtypes.h" #include "../tpl/vector_tpl.h" /** * 3D Coordinates */ class koord3d { public: sint16 x; sint16 y; sint8 z; koord3d() : x(0), y(0), z(0) {} koord3d(sint16 xp, sint16 yp, sint8 zp) : x(xp), y(yp), z(zp) {} koord3d(koord xyp, sint8 zp) : x(xyp.x), y(xyp.y), z(zp) {} const char *get_str() const; const char *get_fullstr() const; // including brackets void rotate90( sint16 y_diff ); void rdwr(loadsave_t* file); static const koord3d invalid; koord get_2d() const { return koord(x, y); } const koord3d& operator += (const koord3d& a) { x += a.x; y += a.y; z += a.z; return *this; } const koord3d& operator -= (const koord3d& a) { x -= a.x; y -= a.y; z -= a.z; return *this; } const koord3d& operator += (const koord& a) { x += a.x; y += a.y; return *this; } const koord3d& operator -= (const koord& a) { x -= a.x; y -= a.y; return *this; } } GCC_PACKED; static inline koord3d operator + (const koord3d& a, const koord3d& b) { return koord3d(a.x + b.x, a.y + b.y, a.z + b.z); } static inline koord3d operator - (const koord3d& a, const koord3d& b) { return koord3d(a.x - b.x, a.y - b.y, a.z - b.z); } static inline bool operator == (const koord3d& a, const koord3d& b) { // return a.x == b.x && a.y == b.y && a.z == b.z; return ((a.x-b.x)|(a.y-b.y)|(a.z-b.z))==0; } static inline bool operator != (const koord3d& a, const koord3d& b) { // return a.x != b.x || a.y != b.y || a.z != b.z; return ((a.x-b.x)|(a.y-b.y)|(a.z-b.z))!=0; } static inline koord3d operator - (const koord3d& a) { return koord3d(-a.x, -a.y, -a.z); } static inline koord3d operator + (const koord3d& a, const koord& b) { return koord3d(a.x + b.x, a.y + b.y, a.z); } static inline koord3d operator - (const koord3d& a, const koord& b) { return koord3d(a.x - b.x, a.y - b.y, a.z); } static inline uint32 koord_distance(koord3d a, koord b) { return abs(a.x - b.x) + abs(a.y - b.y); } static inline uint32 koord_distance(koord a, koord3d b) { return abs(a.x - b.x) + abs(a.y - b.y); } static inline uint32 koord_distance(koord3d a, koord3d b) { return abs(a.x - b.x) + abs(a.y - b.y); } /** * This class defines a vector_tpl with some * helper functions */ class koord3d_vector_t : public vector_tpl< koord3d > { public: // computes ribi at position i ribi_t::ribi get_ribi( uint32 index ) const; // computes ribi at position i only if distance to previous/next is not larger than 1 ribi_t::ribi get_short_ribi( uint32 index ) const; void rotate90( sint16 ); }; #endif simutrans-124.3/src/simutrans/dataobj/loadsave.cc000066400000000000000000000766731474050137200221230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include #include "../sys/simsys.h" #include "../simtypes.h" #include "../macros.h" #include "../simversion.h" #include "../simmem.h" #include "../simdebug.h" #include "../utils/plainstring.h" #include "../utils/simstring.h" #include "loadsave.h" #include "translator.h" #include "../io/rdwr/bzip2_file_rdwr_stream.h" #include "../io/rdwr/raw_file_rdwr_stream.h" #include "../io/rdwr/zlib_file_rdwr_stream.h" #if USE_ZSTD #include "../io/rdwr/zstd_file_rdwr_stream.h" #endif #include "../io/rdwr/compare_file_rd_stream.h" #define INVALID_RDWR_ID (-1) //#undef MULTI_THREAD // buffer size for read/write - bzip2 gains up to 8M for non-threaded, 1M for threaded. binary, zipped ok with 256K or smaller. #define LS_BUF_SIZE (1 << 20) // 1 MiB #define LS_MAX_STRING_LEN (0x7FFF) #define LS_STRING_BUF_SIZE (0x8000) // includes the trailing 0 #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_t ls_thread; static simthread_barrier_t loadsave_barrier; static pthread_mutex_t loadsave_mutex; static pthread_mutex_t readdata_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t readdata_cond = PTHREAD_COND_INITIALIZER; static int readdata_flag = 0; // > 0 read more, < 0 no data needed/error while reading // parameters passed starting a thread typedef struct{ loadsave_t *loadsave_routine; } loadsave_param_t; static loadsave_param_t ls; /* * Multi-threaded loading: * more complicated synchronization due to different sources of errors * - less data available than needed (noticed within load_thread) * - more data available than needed (main thread finishes reading but load_thread still waits) * * Communication of error by variable readdata_flag, protected by readdata_mutex * * Intended program flow: * * main load_thread * (data processing) (finalize) fill_buffer * < -- thread_barrier_wait ------------------------------------------------> * (error handling) pthread_cond_wait * if readdata_flag < 0 * load_thread already exited * not enough data -> fatal error * * readdata_flag = 1 readdata_flag = -1 * pthread_cond_broadcast ---------------------------------------------------> * repeat (error handling) * if readdata_flag < 0 * <------ end thread * if error occurred during previous fill_buffer * readdata_flag = -1 * (join threads) <------ end thread * repeat */ void *load_thread( void *ptr ) { loadsave_param_t *lsp = reinterpret_cast(ptr); int buf = 1; while(true) { const size_t bytes_read = lsp->loadsave_routine->fill_buffer(buf); // always wait to sync with main thread before filling the next buffer pthread_mutex_lock(&readdata_mutex); simthread_barrier_wait(&loadsave_barrier); while( readdata_flag == 0 ) { pthread_cond_wait(&readdata_cond, &readdata_mutex); } if (readdata_flag < 0) { // leave if no more data needed pthread_mutex_unlock(&readdata_mutex); break; } if (bytes_read == 0) { // nothing read into buffer, or error occurred // flag error to main thread readdata_flag = -1; pthread_mutex_unlock(&readdata_mutex); break; } readdata_flag = 0; pthread_mutex_unlock(&readdata_mutex); // switch buffer buf = (buf+1)&1; } return ptr; } void loading_trigger_fill_buffer() { // sync with other thread, tell to read more data simthread_barrier_wait(&loadsave_barrier); pthread_mutex_lock(&readdata_mutex); if (readdata_flag < 0) { pthread_mutex_unlock(&readdata_mutex); // reading thread exited due to error dbg->fatal("loadsave_t::read", "savegame corrupt, not enough data"); } readdata_flag = 1; // more data please pthread_cond_broadcast(&readdata_cond); pthread_mutex_unlock(&readdata_mutex); } void loading_finalize() { simthread_barrier_wait(&loadsave_barrier); // reader thread waits, signal end of loadingdata pthread_mutex_lock(&readdata_mutex); readdata_flag = -1; // no more data pthread_cond_broadcast(&readdata_cond); pthread_mutex_unlock(&readdata_mutex); } /* * Multi-threaded saving: * * - synchronization is done with barriers * - end-of-saving is signaled to thread with get_buf_pos(buf)==0, * which is protected by loadsave_mutex */ void *save_thread( void *ptr ) { loadsave_param_t *lsp = reinterpret_cast(ptr); int buf = 1; while(true) { // wait to sync with main thread before flushing the buffer simthread_barrier_wait(&loadsave_barrier); buf = (buf+1)&1; if( lsp->loadsave_routine->get_buf_pos(buf)==0 ) { // empty buffer after sync - signal to exit break; } lsp->loadsave_routine->flush_buffer(buf); } return ptr; } void saving_trigger_flush() { // sync with thread to flush the buffer simthread_barrier_wait(&loadsave_barrier); } void saving_finalize() { // first sync with thread causes buffer to be flushed simthread_barrier_wait(&loadsave_barrier); // second sync with empty buffer signals thread to exit simthread_barrier_wait(&loadsave_barrier); } #endif loadsave_t::mode_t loadsave_t::save_mode = bzip2; // default to use for saving loadsave_t::mode_t loadsave_t::autosave_mode = zipped; // default to use for autosaving int loadsave_t::save_level = 6; int loadsave_t::autosave_level = 1; void NORETURN loadsave_t::fatal(const char* who, const char* format, ...) { va_list argptr; va_start(argptr, format); static char formatbuffer[512]; const char* fn = filename.c_str(); sprintf(formatbuffer, "FATAL ERROR during reading of \"%s\"\n" "The file has been renamed to \"%s-error\"\n\n" "%s: %s\n" "\n" "Aborting program execution ...\n" "Please try to restart Simutrans again!\n", fn, fn, who, format); static char buffer[8192]; vsprintf(buffer, formatbuffer, argptr); va_end(argptr); close(); std::string fn_new = filename + "-error"; dr_remove(fn_new.c_str()); dr_rename(fn, fn_new.c_str()); dbg->custom_fatal(buffer); } loadsave_t::loadsave_t() : mode(binary), buffered(false), stream(NULL) { curr_buff = 0; } loadsave_t::~loadsave_t() { set_buffered(false); const bool saving = is_saving(); const char *errmsg = close(); if( errmsg ) { dbg->error( "loadsave_t::~loadsave_t", "Could not %s save file: %s", (saving ? "save" : "load"), errmsg ); } } void loadsave_t::set_buffered(bool enable) { if( enable ) { if( !buffered ) { buffered = true; curr_buff = 0; buff[0].pos = buff[1].pos = 0; buff[0].len = buff[1].len = 0; buff[0].buf = new char[LS_BUF_SIZE]; #ifdef MULTI_THREAD buff[1].buf = new char[LS_BUF_SIZE]; // second buffer only when multithreaded simthread_barrier_init(&loadsave_barrier, NULL, 2); pthread_mutex_init(&loadsave_mutex, NULL); pthread_mutex_init(&readdata_mutex, NULL); readdata_flag = 0; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); ls.loadsave_routine = this; pthread_create(&ls_thread, &attr, is_saving() ? save_thread : load_thread, (void *)&ls); pthread_attr_destroy(&attr); #endif } } else { if( buffered ) { if( is_saving() && buff[curr_buff].pos>0 ) { #ifdef MULTI_THREAD saving_finalize(); #else flush_buffer(curr_buff); #endif } #ifdef MULTI_THREAD if( !is_saving() ) { loading_finalize(); } pthread_join(ls_thread,NULL); pthread_mutex_destroy(&loadsave_mutex); pthread_mutex_destroy(&readdata_mutex); simthread_barrier_destroy(&loadsave_barrier); delete[] buff[1].buf; // second buffer only when multithreaded #endif delete[] buff[0].buf; buffered = false; } } } loadsave_t::file_status_t loadsave_t::rd_open(const char *filename_utf8) { close(); const file_classify_status_t cl_status = classify_save_file(filename_utf8, &finfo); if (cl_status != FILE_CLASSIFY_OK) { // file likely does not exist dbg->warning("loadsave_t::rd_open", "File '%s' does not exist or is not accessible", filename_utf8); return FILE_STATUS_ERR_INACCESSIBLE; } else if( finfo.version == INVALID_FILE_VERSION ) { return FILE_STATUS_ERR_NO_VERSION; } else if( finfo.version > (SIM_VERSION_MAJOR*1000 + SIM_SERVER_MINOR) ) { /* * Reading future versions will almost certainly lead to exceptions; so we close here. * It would be nice to give a detailed message what failed (like the fatal error does) * But this error may happening also in regular installations after running a nighly * so we just record the failure. */ return FILE_STATUS_ERR_FUTURE_VERSION; } // now open the file assert(stream == NULL); mode = 0; switch (finfo.file_type) { case file_info_t::TYPE_XML_ZSTD: mode = xml; // fallthrough case file_info_t::TYPE_ZSTD: mode |= zstd; #if USE_ZSTD stream = new zstd_file_rdwr_stream_t(filename_utf8, false, 0); break; #else dbg->warning("loadsave_t::rd_open", "Cannot read from '%s': Unsupported save file compression 'zstd'", filename_utf8); return FILE_STATUS_ERR_UNSUPPORTED_COMPRESSION; #endif case file_info_t::TYPE_XML_BZIP2: mode = xml; // fallthrough case file_info_t::TYPE_BZIP2: mode |= bzip2; stream = new bzip2_file_rdwr_stream_t(filename_utf8, false); break; case file_info_t::TYPE_XML_ZIPPED: mode = xml; // fallthrough case file_info_t::TYPE_ZIPPED: mode |= zipped; stream = new zlib_file_rdwr_stream_t(filename_utf8, false, 0); break; case file_info_t::TYPE_XML: mode = xml; // fallthrough default: stream = new raw_file_rdwr_stream_t(filename_utf8, false); break; } if (!stream || stream->get_status() != rdwr_stream_t::STATUS_OK) { const char *errmsg = close(); // file likely does not exist any longer if (errmsg) { dbg->warning("loadsave_t::rd_open", "Cannot read from '%s': %s", filename_utf8, errmsg); } else { dbg->warning("loadsave_t::rd_open", "Cannot read from '%s'", filename_utf8); } return FILE_STATUS_ERR_INACCESSIBLE; } // skip header size_t header_size = finfo.header_size; while (header_size != 0) { char buf[128]; const size_t sz = min(header_size, 128); stream->read(buf, sz); header_size -= sz; } filename = filename_utf8; return FILE_STATUS_OK; } loadsave_t::file_status_t loadsave_t::wr_open( const char *filename_utf8, mode_t m, int level, const char *pak_extension, const char *savegame_version ) { mode = m; close(); #if !USE_ZSTD if( mode & zstd ) { mode &= ~zstd; mode |= bzip2; dbg->warning( "loadsave_t::wr_open", "Compiled without zstd support, using bzip2!" ); } #endif assert(stream == NULL); switch (mode & ~xml) { #if USE_ZSTD case zstd: stream = new zstd_file_rdwr_stream_t(filename_utf8, true, level); break; #endif case bzip2: stream = new bzip2_file_rdwr_stream_t(filename_utf8, true); break; case zipped: stream = new zlib_file_rdwr_stream_t(filename_utf8, true, level); break; case binary: stream = new raw_file_rdwr_stream_t(filename_utf8, true); break; default: dbg->error("loadsave_t::wr_open", "Unsupported save file compression"); return FILE_STATUS_ERR_UNSUPPORTED_COMPRESSION; } if (stream->get_status() != rdwr_stream_t::STATUS_OK) { dbg->error("loadsave_t::wr_open", "Cannot open '%s' for writing!", filename_utf8); return (stream->get_status() == rdwr_stream_t::STATUS_ERR_FILE_INACCESSIBLE) ? FILE_STATUS_ERR_INACCESSIBLE : FILE_STATUS_ERR_CORRUPT; } set_buffered( true ); // get the right extension const char *start = pak_extension; const char *end = pak_extension + strlen(pak_extension)-1; const char *c = pak_extension; // find the start while(*c<*end) { if(*c==':' || *c=='\\' || *c=='/') { start = c+1; } c++; } assert(start\n\n", savegame_version, finfo.pak_extension ); write( str, n ); indent = 1; } return FILE_STATUS_OK; } const char *loadsave_t::close() { if (!stream) { return NULL; } if( is_xml() && stream->is_writing() && stream->get_status() == rdwr_stream_t::STATUS_OK) { // only write when close and no error occurred const char *end = "\n\n"; write( end, strlen(end) ); } if (buffered) { // flush buffers set_buffered(false); } const char *errmsg = NULL; switch (stream->get_status()) { case rdwr_stream_t::STATUS_OK: case rdwr_stream_t::STATUS_EOF: errmsg = NULL; break; case rdwr_stream_t::STATUS_ERR_NOT_INITIALIZED: errmsg = "Not initialized"; break; case rdwr_stream_t::STATUS_ERR_GENERIC_ERROR: errmsg = "Unknown error"; break; case rdwr_stream_t::STATUS_ERR_FILE_INACCESSIBLE: errmsg = "Could not open file"; break; case rdwr_stream_t::STATUS_ERR_FULL: errmsg = "Not enough empty space"; break; case rdwr_stream_t::STATUS_ERR_WRITEFAILURE: errmsg = "Failed to write file"; break; case rdwr_stream_t::STATUS_ERR_NO_VERSION: errmsg = "Unversioned save file"; break; // unused case rdwr_stream_t::STATUS_ERR_FUTURE_VERSION: errmsg = "Save file version too new"; break; // unused case rdwr_stream_t::STATUS_ERR_OBSOLETE_VERSION: errmsg = "Save file version too old"; break; // unused case rdwr_stream_t::STATUS_ERR_CORRUPT: errmsg = "Corrupt file"; break; } delete stream; stream = NULL; return errmsg ? translator::translate(errmsg) : NULL; } /************* from here on the actual data in/out routines ****************/ /** * Checks end-of-file */ bool loadsave_t::is_eof() { #ifdef MULTI_THREAD if (buffered) { pthread_mutex_lock( &loadsave_mutex ); } #endif const bool eof = (!buffered || (buff[0].pos >= buff[0].len && buff[1].pos >= buff[1].len)) && stream->get_status() == rdwr_stream_t::STATUS_EOF; #ifdef MULTI_THREAD if (buffered) { pthread_mutex_unlock(&loadsave_mutex); } #endif return eof; } void loadsave_t::lsputc(int c) { uint8 ch = c; write( &ch, 1 ); } int loadsave_t::lsgetc() { uint8 c[2]; if( read(c,1) ) { return c[0]; } return -1; } size_t loadsave_t::write(const void *buf, size_t len) { if (!buffered) { return stream->write(buf, len); } if( buff[curr_buff].pos+len<=LS_BUF_SIZE ) { // room in the buffer, copy it all for( unsigned i=0; iget_status() == rdwr_stream_t::STATUS_OK && buff[buf_num].pos > 0) { stream->write(buff[buf_num].buf, buff[buf_num].pos); } buff[buf_num].pos = 0; #ifdef MULTI_THREAD pthread_mutex_unlock(&loadsave_mutex); #endif } void loadsave_t::write_indent() { static const int max_indent = 64; static const char spaces[max_indent] = " "; write(spaces, min(indent, max_indent) ); } size_t loadsave_t::read(void *buf, size_t len) { if (!buffered) { return stream->read( buf, len); } if( len>=LS_BUF_SIZE*2 ) { dbg->fatal("loadsave_t::read()","Request for %d too long", len); } if( buff[curr_buff].pos+len<=buff[curr_buff].len ) { // room in the buffer, copy it all for( unsigned i=0; i0 ) { const unsigned left = buff[curr_buff].len-buff[curr_buff].pos; while( ibuff[curr_buff].len ) { dbg->fatal("loadsave_t::read","savegame corrupt, not enough data"); } // copy the rest while( iread(buff[ buf_num ].buf, LS_BUF_SIZE); #ifdef MULTI_THREAD pthread_mutex_lock(&loadsave_mutex); #endif const rdwr_stream_t::status_t status = stream->get_status(); const bool stream_ok = (status == rdwr_stream_t::STATUS_EOF || status == rdwr_stream_t::STATUS_OK); assert((status == rdwr_stream_t::STATUS_OK) == (sz == LS_BUF_SIZE)); buff[buf_num].pos = 0; buff[buf_num].len = stream_ok ? sz : 0; // buf_len is unsigned, set to zero in case of error #ifdef MULTI_THREAD pthread_mutex_unlock(&loadsave_mutex); #endif return sz; } /*************** High level routines to read/write data types ************* * (check also for Intel/Motorola) etc */ void loadsave_t::rdwr_byte(sint8 &c) { if(!is_xml()) { if(is_saving()) { lsputc(c); } else { c = (sint8)lsgetc(); } } else { sint64 ll = c; rdwr_xml_number( ll, "i8" ); c = (sint8)ll; } } void loadsave_t::rdwr_byte(uint8 &c) { sint8 cc=c; rdwr_byte(cc); c = (uint8)cc; } void loadsave_t::rdwr_short(sint16 &i) { if(!is_xml()) { if (is_saving()) { #ifdef SIM_BIG_ENDIAN sint16 ii = endian(i); write(&ii, sizeof(sint16)); #else write(&i, sizeof(sint16)); #endif } else { #ifdef SIM_BIG_ENDIAN uint16 ii; read(&ii, sizeof(sint16)); i = endian(ii); #else read(&i, sizeof(sint16)); #endif } } else { sint64 ll = i; rdwr_xml_number( ll, "i16" ); i = (sint16)ll; } } void loadsave_t::rdwr_short(uint16 &i) { sint16 ii=i; rdwr_short(ii); i = (uint16)ii; } void loadsave_t::rdwr_long(sint32 &l) { if(!is_xml()) { if (is_saving()) { #ifdef SIM_BIG_ENDIAN uint32 ii = endian(l); write(&ii, sizeof(uint32)); #else write(&l, sizeof(sint32)); #endif } else { #ifdef SIM_BIG_ENDIAN uint32 ii; read(&ii, sizeof(uint32)); l = endian(ii); #else read(&l, sizeof(sint32)); #endif } } else { sint64 ll = l; rdwr_xml_number( ll, "i32" ); l = (sint32)ll; } } void loadsave_t::rdwr_long(uint32 &l) { sint32 ll=l; rdwr_long(ll); l = (uint32)ll; } void loadsave_t::rdwr_color(rgb888_t &col) { uint32 v = col.r<<16 | col.g<<8 | col.b; rdwr_long(v); col.r = v >> 16; col.g = v >> 8; col.b = v >> 0; } void loadsave_t::rdwr_longlong(sint64 &ll) { if(!is_xml()) { if (is_saving()) { #ifdef SIM_BIG_ENDIAN sint64 ii = endian(ll); write(&ii, sizeof(sint64)); #else write(&ll, sizeof(sint64)); #endif } else { #ifdef SIM_BIG_ENDIAN uint64 ii; read(&ii, sizeof(sint64)); ll = endian(ii); #else read(&ll, sizeof(sint64)); #endif } } else { rdwr_xml_number( ll, "i64" ); } } void loadsave_t::rdwr_double(double &dbl) { if(!is_xml()) { if(is_saving()) { write(&dbl, sizeof(double)); } else { read(&dbl, sizeof(double)); } } else { // so far only with 3 digit precision, but this is ok for only two locations used sint64 ll= (sint64)((dbl*1000.0)+0.5); rdwr_xml_number( ll, "d1000" ); dbl = (((double)ll)+0.000001)/1000.0; } } void loadsave_t::rdwr_bool(bool &i) { if( !is_xml() ) { if(is_saving()) { lsputc(i ? '1' : '0'); } else { i = lsgetc()=='1'; } } else { // bool xml if(is_saving()) { write_indent(); if( i ) { write( "true\n", sizeof("true\n")-1 ); } else { write( "false\n", sizeof("false\n")-1 ); } } else { // find start of tag while( lsgetc()!='<' ) { /* nothing */ } // check for correct tag char buffer[7]; read( buffer, 5 ); buffer[5] = 0; if( strcmp("bool>",buffer)!=0 ) { fatal( "loadsave_t::rdwr_bool()","expected \"\", got \"<%s\"", buffer ); } read( buffer, 4 ); buffer[4] = 0; i = strcmp("true",buffer)==0; while( lsgetc()!='<' ) { /* nothing */ } read( buffer, 6 ); buffer[6] = 0; if( strcmp("/bool>",buffer)!=0 ) { fatal( "loadsave_t::rdwr_bool()","expected \"\", got \"<%s\"", buffer ); } } } } void loadsave_t::rdwr_xml_number(sint64 &s, const char *typ) { if(is_saving()) { static char nr[256]; size_t len = sprintf( nr, "%*s<%s>%.0f\n", indent, "", typ, (double)s, typ ); write( nr, len ); } else { const int len = (int)strlen(typ); assert(len<256); // find start of tag and handle eof correctly while( 1 ) { int ch = lsgetc(); if( ch == '<' ) { break; } if( ch < 0 ) { fatal( "loadsave_t::rdwr_xml_number()", "Reached end of file while trying to read <%s>", typ ); } } // check for correct tag char buffer[256]; read( buffer, len ); buffer[len] = 0; if( strcmp(typ,buffer)!=0 ) { fatal( "loadsave_t::rdwr_xml_number()","expected \"<%s>\", got \"<%s>\"", typ, buffer ); } while( lsgetc()!='>' ) ; // read number; s = 0; bool minus = false; while(!is_eof()) { const int c = lsgetc(); if(c>='0' && c<='9' ) { s = (s*10)+(c-'0'); } else { if(s==0) { if( c=='-') { minus = true; continue; } else if(c=='+') { minus = false; continue; } } if(c==' ') { while( lsgetc()!='<' ) { /* nothing */ } break; } else if(c=='<') { break; } else { fatal( "loadsave_t::rdwr_xml_number()", "type %s, found %c in number!", typ, c ); } } } if(minus) { s = -s; } if( lsgetc()!='/' ) { fatal( "loadsave_t::rdwr_xml_number()", "missing '/' (not closing tag)" ); } read( buffer, len ); buffer[6] = 0; if( strcmp(typ,buffer)!=0 ) { fatal( "loadsave_t::rdwr_xml_number()","expected \"\", got \"\"", typ, buffer ); } while( lsgetc()!='>' ) ; } } // s is a malloc-ed string (will be freed and newly allocated on load time!) void loadsave_t::rdwr_str(const char *&s) { if(!is_xml()) { sint16 size; if(is_saving()) { size = s ? (sint16)min(LS_MAX_STRING_LEN,strlen(s)) : 0; #ifdef SIM_BIG_ENDIAN { uint16 ii = endian(size); write(&ii, sizeof(sint16)); } #else write(&size, sizeof(sint16)); #endif if(size > 0) { write(s, size); } } else { #ifdef SIM_BIG_ENDIAN { uint16 ii; read(&ii, sizeof(uint16)); size = endian(ii); } #else read(&size, sizeof(sint16)); #endif char *sneu = NULL; if(size > 0) { sneu = MALLOCN(char, size + 1); read(sneu, size); sneu[size] = '\0'; } if(s) { free(const_cast(s)); } s = sneu; } } else { // use CDATA tag: if(is_saving()) { write_indent(); write( "\n", 4 ); } else { char buffer[LS_STRING_BUF_SIZE]; rdwr_str( buffer, LS_STRING_BUF_SIZE ); if(s) { free(const_cast(s)); } s = buffer[0]!=0 ? strdup(buffer) : NULL; } } } // read a string into a preallocated buffer void loadsave_t::rdwr_str( char* result_buffer, size_t const size) { if(!is_xml()) { uint16 len; if(is_saving()) { len = (uint16)min(LS_MAX_STRING_LEN,strlen(result_buffer)); #ifdef SIM_BIG_ENDIAN { sint16 ii = endian(len); write(&ii, sizeof(sint16)); } #else write(&len, sizeof(uint16)); #endif write(result_buffer, len); } else { read(&len, sizeof(uint16)); len = endian(len); if( len >= size) { fatal( "loadsave_t::rdwr_str()","string longer (%i) than allowed size (%i)", len, size ); } read(result_buffer, len); result_buffer[len] = '\0'; } } else { // use CDATA tag: char *s = result_buffer; if(is_saving()) { write_indent(); write( "\n", 4 ); } else { // find start of tag while( lsgetc()!='<' ) { /* nothing */ } // check for correct tag char buffer[10]; read( buffer, 7 ); bool string = true; if (!strstart(buffer, "string>")) { if (!strstart(buffer, "![CDATA") || lsgetc() != '[') { buffer[7] = 0; fatal( "loadsave_t::rdwr_str()","expected str \"' ) { if (i >= 8 && strstart(s - 8, "=2 && strstart(s-3,"]]>") ) { s[-3] = 0; strcpy( result_buffer, temp ); return; } } *s = 0; fatal( "loadsave_t::rdwr_str()","string too long (exceeded %i characters)", size ); } } } } void loadsave_t::rdwr_str(plainstring& s) { if( is_loading() ) { const char* buf = NULL; rdwr_str(buf); if( buf ) { s = buf; free( const_cast(buf) ); } else { s = ""; } } else { char const* tmp = s.c_str(); rdwr_str(tmp); } } void loadsave_t::start_tag(const char *tag) { if( is_xml() ) { if(is_saving()) { write_indent(); write( "<", 1 ); write( tag, strlen(tag) ); write( ">\n", 2 ); indent ++; } else { char buf[256]; // find start of tag while( lsgetc()!='<' ) { /* nothing */ } read( buf, strlen(tag) ); if( !strstart(buf, tag) ) { fatal( "loadsave_t::start_tag()","expected \"%s\", got \"%s\"", tag, buf ); } while( lsgetc()!='>' ) ; } } } void loadsave_t::end_tag(const char *tag) { if( is_xml() ) { if(is_saving()) { indent --; write_indent(); write( "\n", 2 ); } else { // just use start tag with the end character ... char buf[256]; tstrncpy( buf+1, tag, 254 ); buf[0] = '/'; start_tag(buf); } } } void loadsave_t::wr_obj_id(sint16 id) { if(!is_saving()) { dbg->fatal( "loadsave_t::wr_obj_id()", "must be only called during saving!" ); } if(!is_xml()) { lsputc( id ); } else { sint64 ll=id; rdwr_xml_number( ll, "id" ); } } sint16 loadsave_t::rd_obj_id() { if(is_saving()) { dbg->fatal( "loadsave_t::rd_obj_id()", "must be only called during reading!" ); return INVALID_RDWR_ID; } if(!is_xml()) { sint8 idc; read(&idc, sizeof(sint8)); return (sint8)idc; } else { sint64 ll; rdwr_xml_number( ll, "id" ); return (sint16)ll; } } void loadsave_t::wr_obj_id(const char *id_text) { if(is_saving()) { if( !is_xml() ) { write( id_text, strlen(id_text) ); lsputc( 10 ); } else { write( "\n", 3 ); } } } void loadsave_t::rd_obj_id(char *id_buf, int size) { if(!is_saving()) { if( !is_xml() ) { int i=0; *id_buf = 0; do { id_buf[i++] = lsgetc(); } while (i < size && id_buf[i - 1] != 10); id_buf[i-1] = 0; } else { char buf[6]; // find start of tag while( lsgetc()!='<' ) { /* nothing */ } read( buf, 6 ); buf[5] = 0; if (!strstart(buf, "")) { fatal( "loadsave_t::rd_obj_id()","id tag not properly closed!" ); } } } } uint32 loadsave_t::int_version(const char *version_text, char *pak_extension_str) { // major number (0..) uint32 v0 = atoi(version_text); while(*version_text && *version_text++ != '.') ; if(!*version_text) { return 0; } // middle number (.99.) uint32 v1 = atoi(version_text); while(*version_text && *version_text++ != '.') ; if(!*version_text) { return 0; } // minor number (..08) uint32 v2 = atoi(version_text); uint32 version = v0 * 1000000 + v1 * 1000 + v2; while(*version_text && isdigit(*version_text)) { version_text++; } // simutrans-experimental savegame? // the next char is either 'b'/'z'/'-', // if it is '.' the we try to load a simutrans-experimental savegame if(*version_text == '.') { // Simutrans Extended savegame, we can't load it, return version=0 if (pak_extension_str) { std::strcpy(pak_extension_str,"(st-exp)"); } return 0; } if( version<=102002 ) { /* the compression and the mode we determined already ourselves * (otherwise we cannot read this => leave the mode alone but for unknown modes!) */ if (strstart(version_text, "bin")) { version_text += 3; } else if (strstart(version_text, "zip")) { version_text += 3; } else if( *version_text ) { // illegal version ... if (pak_extension_str) { std::strcpy(pak_extension_str,"(broken)"); } return 0; } } else { // skip the minus sign if (*version_text=='-') { version_text++; } } if( pak_extension_str ) { if( *version_text ) { // also pak extension was saved if(version>=99008) { while( *version_text>=32 ) { *pak_extension_str = *version_text; pak_extension_str++; version_text++; } } } *pak_extension_str = 0; } return version; } stream_loadsave_t::stream_loadsave_t(rdwr_stream_t *stream) { this->stream = stream; finfo.version = int_version(VERSION_NUMBER, NULL); } compare_loadsave_t::compare_loadsave_t(loadsave_t *file1, loadsave_t *file2) { stream = new compare_file_rd_stream_t(file1->stream, file2->stream); finfo.version = int_version(VERSION_NUMBER, NULL); set_buffered(false); file1->set_buffered(false); file2->set_buffered(false); } compare_loadsave_t::~compare_loadsave_t() { delete stream; stream = NULL; } simutrans-124.3/src/simutrans/dataobj/loadsave.h000066400000000000000000000142061474050137200217450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_LOADSAVE_H #define DATAOBJ_LOADSAVE_H #include #include #include "../simtypes.h" #include "../io/classify_file.h" #include "../io/rdwr/rdwr_stream.h" class plainstring; struct rgb888_t; /** * This class replaces the FILE when loading and saving games. * * Can now read and write 3 formats: text, binary and zipped * Input format is automatically detected. * Output format has a default, changeable with set_savemode, but can be * overwritten in wr_open. */ class loadsave_t { private: // during reading, a fatal error will rename the file to "oldnam"-error, so one can try again void NORETURN fatal(const char* who, const char* format, ...); struct buf_t { size_t pos; size_t len; char *buf; }; public: enum mode_t { binary = 0, text = 1 << 0, xml = 1 << 1, zipped = 1 << 2, bzip2 = 1 << 3, zstd = 1 << 4, xml_zipped = xml | zipped, xml_bzip2 = xml | bzip2, xml_zstd = xml | zstd }; enum file_status_t { FILE_STATUS_OK = 0, FILE_STATUS_ERR_GENERIC_ERROR, FILE_STATUS_ERR_INACCESSIBLE, FILE_STATUS_ERR_CORRUPT, FILE_STATUS_ERR_NO_VERSION, FILE_STATUS_ERR_FUTURE_VERSION, FILE_STATUS_ERR_UNSUPPORTED_COMPRESSION }; protected: int mode; ///< See mode_t bool buffered; unsigned curr_buff; buf_t buff[2]; int indent; // only for XML formatting file_info_t finfo; std::string filename; rdwr_stream_t *stream; /// @sa putc inline void lsputc(int c); /// @sa getc inline int lsgetc(); size_t read(void *buf, size_t len); size_t write(const void *buf, size_t len); void write_indent(); void rdwr_xml_number(sint64 &s, const char *typ); loadsave_t(const loadsave_t&); loadsave_t& operator=(const loadsave_t&); friend void *save_thread( void *ptr ); friend void *load_thread( void *ptr ); /** * Reads into buffer number @p buf_num. * @returns number of bytes read or -1 in case of error */ size_t fill_buffer(int buf_num); void flush_buffer(int buf_num); bool is_xml() const { return mode&xml; } public: static mode_t save_mode; ///< default to use for saving static mode_t autosave_mode; ///< default to use for autosaves and network mode client temp saves static int save_level; ///< default to use for compression (various libraries allow for size/speed settings) static int autosave_level; /** * Parses the version information from @p version_text to a version number. * * @param version_text * @param[out] pak Pointer to a sufficiently large buffer (>= 64 chars); when the function returns, * @p pak contains the pakset extension string. May be NULL. * @retval 0 if an error occurred or the save cannot be loaded * @retval !=0 the save version; in this case we can read the save file. */ static uint32 int_version(const char *version_text, char *pak); loadsave_t(); ~loadsave_t(); /// Open save file for reading. File format is detected automatically. file_status_t rd_open(const char *filename); /// Open save file for writing. file_status_t wr_open(const char *filename, mode_t mode, int level, const char *pak_extension, const char *savegame_version ); /// Close an open save file. Returns an error message if saving was unsuccessful, the empty string otherwise. const char *close(); static void set_savemode(mode_t mode) { save_mode = mode; } static void set_autosavemode(mode_t mode) { autosave_mode = mode; } static void set_savelevel(int level) { save_level = level; } static void set_autosavelevel(int level) { autosave_level = level; } /** * Checks end-of-file */ bool is_eof(); void set_buffered(bool enable); unsigned get_buf_pos(int buf_num) const { return buff[buf_num].pos; } bool is_loading() const { return stream && !stream->is_writing(); } bool is_saving() const { return stream && stream->is_writing(); } const char *get_pak_extension() const { return finfo.pak_extension; } uint32 get_version_int() const { return finfo.version; } inline bool is_version_atleast(uint32 major, uint32 save_minor) const { return !is_version_less(major, save_minor); } inline bool is_version_less(uint32 major, uint32 save_minor) const { return finfo.version < major * 1000U + save_minor; } inline bool is_version_equal(uint32 major, uint32 save_minor) const { return finfo.version == major * 1000U + save_minor; } void rdwr_byte(sint8 &c); void rdwr_byte(uint8 &c); void rdwr_short(sint16 &i); void rdwr_short(uint16 &i); void rdwr_long(sint32 &i); void rdwr_long(uint32 &i); void rdwr_longlong(sint64 &i); void rdwr_bool(bool &i); void rdwr_double(double &dbl); void rdwr_color(rgb888_t &color); void wr_obj_id(short id); short rd_obj_id(); void wr_obj_id(const char *id_text); void rd_obj_id(char *id_buf, int size); // s is a malloc-ed string (will be freed and newly allocated on load time!) void rdwr_str(const char *&s); /// @p s is a buf of size given /// @p size includes space for the trailing 0 void rdwr_str(char *s, size_t size); /** * Read/Write plainstring. * @param str the string to be read/written * @post str should not be NULL after reading. */ void rdwr_str(plainstring& str); // only meaningful for XML void start_tag( const char *tag ); void end_tag( const char *tag ); // use this for enum types template void rdwr_enum(X &x) { sint32 int_x; if(is_saving()) { int_x = (sint32)x; } rdwr_long(int_x); if(is_loading()) { x = (X)int_x; } } friend class compare_loadsave_t; // to access stream }; /** * Class used to produce hash of savegame_version */ class stream_loadsave_t : public loadsave_t { public: stream_loadsave_t(rdwr_stream_t *stream); }; /** * Class used to compare two savegames */ class compare_loadsave_t : public loadsave_t { public: compare_loadsave_t(loadsave_t *file1, loadsave_t *file2); ~compare_loadsave_t(); }; // this produces semi-automatic hierarchies class xml_tag_t { private: loadsave_t *file; const char *tag; public: xml_tag_t( loadsave_t *f, const char *t ) : file(f), tag(t) { file->start_tag(tag); } ~xml_tag_t() { file->end_tag(tag); } }; #endif simutrans-124.3/src/simutrans/dataobj/marker.cc000066400000000000000000000044771474050137200215770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simtypes.h" #include "../simdebug.h" #include "../ground/grund.h" #include "marker.h" marker_t marker_t::the_instance; marker_t marker_t::second_instance; void marker_t::init(int world_size_x, int world_size_y) { // do not reallocate it, if same size ... cached_size_x = world_size_x; int new_bits_length = (world_size_x*world_size_y + bit_mask) / (bit_unit); if( bits_length != new_bits_length ) { bits_length = new_bits_length; delete [] bits; if(bits_length) { bits = new unsigned char[bits_length]; } else { bits = NULL; } } unmark_all(); } marker_t& marker_t::instance(int world_size_x, int world_size_y) { the_instance.init(world_size_x, world_size_y); return the_instance; } marker_t& marker_t::instance_second(int world_size_x, int world_size_y) { second_instance.init(world_size_x, world_size_y); return second_instance; } marker_t::~marker_t() { delete [] bits; } void marker_t::unmark_all() { if(bits) { MEMZERON(bits, bits_length); } more.clear(); } void marker_t::mark(const grund_t *gr) { if(gr != NULL) { if(gr->ist_karten_boden()) { // ground level const int bit = gr->get_pos().y*cached_size_x+gr->get_pos().x; bits[bit/bit_unit] |= 1 << (bit & bit_mask); } else { more.set(gr, true); } } } void marker_t::unmark(const grund_t *gr) { if(gr != NULL) { if(gr->ist_karten_boden()) { // ground level const int bit = gr->get_pos().y*cached_size_x+gr->get_pos().x; bits[bit/bit_unit] &= ~(1 << (bit & bit_mask)); } else { more.remove(gr); } } } bool marker_t::is_marked(const grund_t *gr) const { if(gr==NULL) { return false; } if(gr->ist_karten_boden()) { // ground level const int bit = gr->get_pos().y*cached_size_x+gr->get_pos().x; return (bits[bit/bit_unit] & (1 << (bit & bit_mask))) != 0; } else { return more.get(gr); } } bool marker_t::test_and_mark(const grund_t *gr) { if(gr != NULL) { if(gr->ist_karten_boden()) { // ground level const int bit = gr->get_pos().y*cached_size_x+gr->get_pos().x; if ((bits[bit/bit_unit] & (1 << (bit & bit_mask))) != 0) { return true; } bits[bit/bit_unit] |= 1 << (bit & bit_mask); } else { return more.set(gr, true); } } return false; } simutrans-124.3/src/simutrans/dataobj/marker.h000066400000000000000000000040621474050137200214270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_MARKER_H #define DATAOBJ_MARKER_H #include "../tpl/ptrhashtable_tpl.h" class grund_t; /** * Class to mark tiles as visited during route search. * Singleton. */ class marker_t { // added bit mask, because it allows a more efficient // implementation (use & instead of %) enum { bit_unit = (8 * sizeof(unsigned char)), bit_mask = (8 * sizeof(unsigned char))-1 }; /// bit-field to mark ground tiles unsigned char *bits; /// length of field int bits_length; /// bit-field is made for this x-size int cached_size_x; /// hashtable to mark non-ground tiles (bridges, tunnels) ptrhashtable_tpl more; marker_t() : bits(NULL) { init(0, 0); } ~marker_t(); /** * Initializes marker. Set all tiles to not marked. * @param world_size_x x-size of map * @param world_size_y y-size of map */ void init(int world_size_x, int world_size_y); /// the instance static marker_t the_instance; static marker_t second_instance; public: /** * Return handle to marker instance. * @param world_size_x x-size of map * @param world_size_y y-size of map * @returns handle to the singleton instance */ static marker_t& instance(int world_size_x, int world_size_y); /** * Return handle to marker instance. * @param world_size_x x-size of map * @param world_size_y y-size of map * @returns handle to the singleton instance */ static marker_t& instance_second(int world_size_x, int world_size_y); /** * Marks tile as visited. */ void mark(const grund_t *gr); /** * Unmarks tile as visited. */ void unmark(const grund_t *gr); /** * Checks if tile is visited. * @returns true if tile was already visited */ bool is_marked(const grund_t *gr) const; /** * Checks if tile is visited. Marks tile as visited if not visited before. * @returns true if tile was already visited */ bool test_and_mark(const grund_t *gr); /** * Marks all fields as not visited. */ void unmark_all(); }; #endif simutrans-124.3/src/simutrans/dataobj/objlist.cc000066400000000000000000001155551474050137200217640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../simdebug.h" #include "../display/simgraph.h" #include "../world/simworld.h" #include "../builder/hausbauer.h" #include "../obj/dummy.h" #include "../obj/wolke.h" #include "../obj/zeiger.h" #include "../obj/crossing.h" #include "../obj/baum.h" #include "../obj/bruecke.h" #include "../obj/field.h" #include "../obj/pillar.h" #include "../obj/tunnel.h" #include "../obj/gebaeude.h" #include "../obj/signal.h" #include "../obj/label.h" #include "../obj/leitung2.h" #include "../obj/wayobj.h" #include "../obj/roadsign.h" #include "../obj/groundobj.h" #include "../simtypes.h" #include "../obj/depot.h" #include "../simmem.h" #include "../player/simplay.h" #include "../vehicle/air_vehicle.h" #include "../vehicle/simroadtraffic.h" #include "../vehicle/pedestrian.h" #include "../vehicle/movingobj.h" #include "../descriptor/building_desc.h" #include "../descriptor/groundobj_desc.h" #include "../dataobj/loadsave.h" #include "../dataobj/freelist.h" #include "../dataobj/environment.h" #include "objlist.h" // priority for inserting into objlist #define PRI_WAY (0) // ways (always at the top!) #define PRI_DEPOT (1) // depots (must be before tunnel!) #define PRI_CROSSING (1) // crossings, treated like bridges or tunnels #define PRI_GROUNDOBJ (1) #define PRI_BRIDGE (2) #define PRI_TUNNEL (2) #define PRI_BUILDING (3) #define PRI_FIELD (3) #define PRI_TRANSFORMER (4) #define PRI_RAUCHER (5) #define PRI_SIGNAL (6) #define PRI_ROADSIGN PRI_SIGNAL #define PRI_PILLAR (7) #define PRI_WAYOBJ (8) #define PRI_LABEL (9) #define PRI_TREE (50) #define PRI_MOVABLE (100) // priority of moving things: should be smaller than the priority of powerlines #define PRI_AIRCRAFT (PRI_MOVABLE + 1) #define PRI_MOVINGOBJ (PRI_MOVABLE + 1) #define PRI_POWERLINE (150) #define PRI_CLOUD (200) #define PRI_ZEIGER (254) #define PRI_INVALID (255) // Maps obj_t::type -> objlist insertion order // unused entries have PRI_INVALID static uint8 type_to_pri[256] = { PRI_INVALID, // obj PRI_TREE, // baum PRI_ZEIGER, // cursor/pointers PRI_CLOUD, // wolke PRI_CLOUD, // sync_wolke PRI_CLOUD, // async_wolke PRI_INVALID, // gebaeude_alt, unused PRI_BUILDING, // gebaeude PRI_SIGNAL, // signal PRI_BRIDGE, // bridge PRI_TUNNEL, // tunnel PRI_INVALID, // old_gebaeudefundament, unused PRI_DEPOT, // bahndepot PRI_DEPOT, // strassendepot PRI_DEPOT, // schiffdepot PRI_RAUCHER, // smoke generator (not used any more) PRI_POWERLINE, // poweline PRI_TRANSFORMER, // pumpe PRI_TRANSFORMER, // senke PRI_ROADSIGN, // roadsign PRI_PILLAR, // pillar PRI_DEPOT, // airdepot PRI_DEPOT, // monoraildepot PRI_DEPOT, // tramdepot PRI_DEPOT, // maglevdepot PRI_WAYOBJ, // way objects (electrification) PRI_WAY, // way PRI_LABEL, // label, indicates ownership: insert before trees PRI_FIELD, // field (factory extension) PRI_CROSSING, // crossing PRI_GROUNDOBJ, // groundobjs, overlays over bare ground like lakes etc. PRI_DEPOT, // narrowgaugedepot // 32-63 left empty (old numbers) PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_MOVABLE, // pedestrians PRI_MOVABLE, // city cars PRI_MOVABLE, // road vehicle PRI_MOVABLE, // rail vehicle PRI_MOVABLE, // monorail PRI_MOVABLE, // maglev PRI_MOVABLE, // narrowgauge PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_MOVABLE, // ship PRI_AIRCRAFT, // aircraft (no trailer, could be handled by normal method) PRI_MOVINGOBJ, // movingobject (no trailer, could be handled by normal method) // 83-95 left empty (for other moving stuff); 95 is reserved for old choosesignals PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, // 96-128 left empty (old numbers) PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, // 128-255 left empty PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID, PRI_INVALID }; static void dl_free(obj_t** p, uint8 size) { assert(size > 1); if (size <= 16) { freelist_t::putback_node(sizeof(*p) * size, p); } else { free(p); } } static obj_t** dl_alloc(uint8 size) { assert(size > 1); obj_t** p; if (size <= 16) { p = static_cast(freelist_t::gimme_node(sizeof(*p) * size )); } else { p = MALLOCN(obj_t*, size); } return p; } objlist_t::objlist_t() { obj.one = NULL; capacity = 0; top = 0; } objlist_t::~objlist_t() { if( capacity == 1 ) { obj.one->set_flag(obj_t::not_on_map); if(!obj.one->has_managed_lifecycle()) { delete obj.one; } } else { for( uint8 i=0; iset_flag(obj_t::not_on_map); if(!object->has_managed_lifecycle()) { delete object; } } } if(capacity>1) { dl_free(obj.some, capacity); } obj.some = NULL; capacity = top = 0; } void objlist_t::set_capacity(uint16 req_cap) { // DBG_MESSAGE("objlist_t::set_capacity()", "old cap=%d, new cap=%d", capacity, new_cap); const uint8 new_cap = req_cap >= 255 ? 254 : (uint8)req_cap; // a single object is stored differentially if(new_cap==0) { if(capacity>1) { dl_free( obj.some, capacity ); } obj.one = NULL; capacity = 0; top = 0; } else if(new_cap==1) { if(capacity>1) { obj_t *tmp=NULL; // we have an obj to save into the list tmp = obj.some[0]; dl_free( obj.some, capacity ); obj.one = tmp; assert(top<2); } else if(top==0) { obj.one = NULL; } capacity = top; } else if(capacity<=1) { // this means we extend from 0 or 1 elements to more than 1 obj_t *tmp=obj.one; obj.some = dl_alloc(new_cap); MEMZERON(obj.some, new_cap); obj.some[0] = tmp; capacity = new_cap; assert(top<=1); } else { // we need to copy old list to large list assert( top<=new_cap ); // get memory obj_t **tmp = dl_alloc(new_cap); // free old memory if(obj.some) { memcpy( tmp, obj.some, sizeof(obj_t *)*top ); dl_free(obj.some, capacity); } obj.some = tmp; capacity = new_cap; } } bool objlist_t::grow_capacity() { if(capacity==0) { return true; } else if(capacity==1) { set_capacity( 4 ); return true; } else if(capacity>=254) { // capacity exceeded ... (and no need for THAT many objects here ... ) return false; } else { // size exceeded, extent uint16 new_cap = (uint16)capacity+4; set_capacity( new_cap ); return true; } } void objlist_t::shrink_capacity(uint8 o_top) { // strategy: avoid freeing mem if not needed. Only if we hold lots of memory then free it. // this is almost only called when deleting ways in practice if( capacity > 16 && o_top <= 4 ) { set_capacity(o_top); } } inline void objlist_t::intern_insert_at(obj_t* new_obj, uint8 pri) { // we have more than one object here, thus we can use obj.some exclusively! for( uint8 i=top; i>pri; i-- ) { obj.some[i] = obj.some[i-1]; } obj.some[pri] = new_obj; top++; } // only used internal for loading. DO NOT USE OTHERWISE! bool objlist_t::append(obj_t *new_obj) { if(capacity==0) { // the first one save direct obj.one = new_obj; top = 1; capacity = 1; return true; } if(top>=capacity && !grow_capacity()) { // memory exceeded return false; } intern_insert_at(new_obj, top); return true; } // this will automatically give the right order for citycars and the like ... bool objlist_t::intern_add_moving(obj_t* new_obj) { // we are more than one object, thus we exclusively use obj.some here! // it would be nice, if also the objects are inserted according to their priorities as // vehicles types (number returned by get_typ()). However, this would increase // the calculation even further. :( // insert at this lane uint8 lane = ((vehicle_base_t*)new_obj)->get_disp_lane(); // find out about the first car etc. moving thing. // We can start to insert between (start) and (end) uint8 start=0; while(startis_moving() || ((vehicle_base_t*)obj.some[start])->get_disp_lane() < lane) ) { start ++; } uint8 end = top; while( end>start && (!obj.some[end-1]->is_moving() || ((vehicle_base_t*)obj.some[end-1])->get_disp_lane() > lane) ) { end--; } /* Vehicles are sorted back to front by their disp_lane. Here we append them in tile entry order within their disp_lane, last one displayed in front. Those moving downwards on screen (direction NE, E, SE, S) must be prepended, first one in front. */ auto v = static_cast(new_obj); const uint8 direction = v->get_direction(); if (direction == ribi_t::north || (direction & ribi_t::west)) { start = end; // append } intern_insert_at(new_obj, start); return true; } /** * @returns true if tree1 must be sorted before tree2 (tree1 stands behind tree2) */ bool compare_trees(const obj_t *tree1, const obj_t *tree2) { // the tree with larger yoff is in front sint8 diff = tree2->get_yoff() - tree1->get_yoff(); if (diff==0) { // .. or the one that is the left most (ie xoff is small) diff = tree1->get_xoff() - tree2->get_xoff(); } return diff>0; } void objlist_t::sort_trees(uint8 index, uint8 count) { if(top>=index+count) { std::sort(&obj.some[index], &obj.some[index+count], compare_trees); } } bool objlist_t::add(obj_t* new_obj) { if(capacity==0) { // the first one save direct obj.one = new_obj; top = 1; capacity = 1; return true; } if(top>=capacity && !grow_capacity()) { // memory exceeded return false; } if(top==0) { intern_insert_at( new_obj, 0 ); return true; } // now top>0 // now insert it a the correct place const uint8 pri=type_to_pri[new_obj->get_typ()]; // vehicles need a special order if(pri==PRI_MOVABLE) { return intern_add_moving(new_obj); } // roads must be first! if(pri==0) { // check for other ways to keep order! (maximum is two ways per tile at the moment) weg_t const* const w = obj_cast(obj.some[0]); uint8 const pos = w && w->get_waytype() < static_cast(new_obj)->get_waytype() ? 1 : 0; intern_insert_at(new_obj, pos); return true; } uint8 i; for( i=0; itype_to_pri[obj.some[i]->get_typ()]; i++ ) ; // now i contains the position, where we either insert of just add ... if(i==top) { obj.some[top] = new_obj; top++; } else { if(pri==PRI_TREE) { /* trees are a little tricky, since they cast a shadow * therefore the y-order must be correct! */ for( ; i(obj.some[i]); if (!tree || compare_trees(new_obj, tree)) { break; } } } else if (pri == PRI_PILLAR) { // pillars have to be sorted wrt their y-offset, too. for( ; i(obj.some[i]); if (!pillar || new_obj->get_yoff() > pillar->get_yoff() ) { break; } } } else if( pri == PRI_WAYOBJ && obj.some[i]->get_typ()==obj_t::wayobj ) { wayobj_t const* const wo = obj_cast(obj.some[i]); if( wo && wo->get_waytype() < obj_cast(new_obj)->get_waytype() ) { // insert after a lower waytype i += 1; } } intern_insert_at(new_obj, i); } // then correct the upper border return true; } // take the thing out from the list // use this only for temporary removing // since it does not shrink list or checks for ownership obj_t *objlist_t::remove_last() { obj_t *last_obj=NULL; if(capacity==0) { // nothing } else if(capacity==1) { last_obj = obj.one; obj.one = NULL; capacity = top = 0; } else { if(top>0) { top --; last_obj = obj.some[top]; obj.some[top] = NULL; } } return last_obj; } bool objlist_t::remove(const obj_t* remove_obj) { if( capacity == 0 ) { return false; } else if( capacity == 1 ) { if( obj.one == remove_obj ) { obj.one = NULL; capacity = 0; top = 0; return true; } return false; } // we keep the array dense! for( uint8 i=0; i(remove_obj); if (v && remove_obj->get_typ() != obj_t::pedestrian && remove_obj->get_typ() != obj_t::road_user && remove_obj->get_typ() != obj_t::movingobj) { v->leave_tile(); } else { remove_obj->cleanup(player); remove_obj->set_flag(obj_t::not_on_map); // all objects except zeiger (pointer) are destroyed here // zeiger's will be deleted if their associated tool terminates if (!remove_obj->has_managed_lifecycle()) { delete remove_obj; } } } bool objlist_t::loesche_alle(player_t *player, uint8 offset) { if(top<=offset) { return false; } // something to delete? bool ok=false; if(capacity>1) { while( top>offset ) { top --; local_delete_object(obj.some[top], player); obj.some[top] = NULL; ok = true; } } else { if(capacity==1) { local_delete_object(obj.one, player); ok = true; obj.one = NULL; capacity = top = 0; } } shrink_capacity(top); return ok; } /* Rotates the display order of moving objects 90 deg CW. The objects themselves are not rotated, that is expected to happen afterwards. */ void objlist_t::rotate90_moving() { if (capacity < 2) return; // has no obj.some uint begin, end; for (begin = 0; begin < top; ++begin) { if (obj.some[begin]->is_moving()) break; } for (end = top; end > begin; --end) { if (obj.some[end - 1]->is_moving()) break; } if (end - begin < 2) return; obj_t **old_some = obj.some; obj_t* temp_some[254]; obj.some = temp_some; uint old_top = top; for (top = 0; top < begin; ++top) obj.some[top] = old_some[top]; /* intern_add_moving() appends vehicles in the order they enter a tile. To sort them back to front it reverses, i.e. prepends those moving downwards on screen (direction NE, E, SE, S). Additionally it sorts vehicles on different road lanes by their disp_lane, numbers which ascend back to front. We must maintain the original entry order, reverse vehicles which were prepended, and insert based on the rotated disp_lane and direction. Lane numbers are mirrored when a vehicle moves to the left side of the screen, so disp_lane will be mirrored if the current direction is NE, E, SW, or W. The order is lost if vehicles entered the same lane in different directions, that may cause a visual glitch but shouldn't really happen. */ static const uint append_dirs = ( (1 << ribi_t::southwest) | (1 << ribi_t::west) | (1 << ribi_t::northwest) | (1 << ribi_t::north)); static const uint rotated_append_dirs = ( (1 << ribi_t::southeast) | (1 << ribi_t::south) | (1 << ribi_t::southwest) | (1 << ribi_t::west)); static const uint rotated_mirror_dirs = ( (1 << ribi_t::northeast) | (1 << ribi_t::east) | (1 << ribi_t::southwest) | (1 << ribi_t::west)); auto rotated_disp_lane = [] (uint& dir_mask, const obj_t* o) { auto v = static_cast(o); dir_mask = 1 << v->get_direction(); uint lane = v->get_disp_lane(); return (rotated_mirror_dirs & dir_mask) ? 4 - lane : lane; }; auto insert = [&] (obj_t *o) { uint dir_mask, dm; uint lane = rotated_disp_lane(dir_mask, o); uint i; // Insert in the same disp_lane, first position. for (i = begin; i < top; ++i) { if (rotated_disp_lane(dm, obj.some[i]) >= lane) break; } // Append if the vehicle will move upwards on screen after // rotation, same as in intern_add_moving(). if (rotated_append_dirs & dir_mask) { for (; i < top; ++i) { if (rotated_disp_lane(dm, obj.some[i]) > lane) break; } } intern_insert_at(o, i); }; const vehicle_base_t* v; auto disp_lane = [&v] (const obj_t* o) { v = static_cast(o); return v->get_disp_lane(); }; uint prev_lane = disp_lane(old_some[begin]); for (uint i = begin; i < end;) { uint prepended_begin = i; uint lane; // Find the first appended vehicle. for (; i < end; ++i) { lane = disp_lane(old_some[i]); if (lane != prev_lane) break; if (append_dirs & (1 << v->get_direction())) break; } for (uint j = i; j > prepended_begin; --j) { insert(old_some[j - 1]); } for (; i < end; ++i) { lane = disp_lane(old_some[i]); if (lane != prev_lane) break; insert(old_some[i]); } prev_lane = lane; } while (top < old_top) obj.some[top++] = old_some[end++]; memcpy(old_some, obj.some, sizeof(void*) * top); obj.some = old_some; } /* returns the text of an error message, if obj could not be removed */ const char *objlist_t::kann_alle_entfernen(const player_t *player, uint8 offset) const { if(top<=offset) { return NULL; } if(capacity==1) { return obj.one->get_removal_error(player); } else { const char * msg = NULL; for(uint8 i=offset; iget_removal_error(player); if(msg != NULL) { return msg; } } } return NULL; } /* recalculates all images */ void objlist_t::calc_image() { if(capacity==0) { // nothing } else if(capacity==1) { obj.one->calc_image(); } else { for(uint8 i=0; icalc_image(); } } } void objlist_t::set_all_dirty() { if( capacity == 0 ) { // nothing } else if( capacity == 1 ) { obj.one->set_flag( obj_t::dirty ); } else { for( uint8 i = 0; i < top; i++ ) { obj.some[i]->set_flag( obj_t::dirty ); } } } /* check for obj */ bool objlist_t::ist_da(const obj_t* test_obj) const { if(capacity<=1) { return obj.one==test_obj; } else { for(uint8 i=0; i= top ) { // start==0 and top==0 is already covered by this too return NULL; } if( capacity <= 1 ) { // it will crash on capacity==1 and top==0, but this should never happen! // this is only reached for top==1 and start==0 return obj.one->get_typ()!=typ ? NULL : obj.one; } else { // else we have to search the list for(uint8 i=start; iget_typ()==typ) { return tmp; } } } return NULL; } obj_t *objlist_t::get_leitung() const { if( top == 0 ) { return NULL; } if( capacity <= 1 ) { // it will crash on capacity==1 and top==0, but this should never happen! if( obj.one->get_typ() >= obj_t::leitung && obj.one->get_typ() <= obj_t::senke ) { return obj.one; } } else { // else we have to search the list for( uint8 i=0; iget_typ(); if( typ >= obj_t::leitung && typ <= obj_t::senke ) { return obj.some[i]; } } } return NULL; } obj_t *objlist_t::get_convoi_vehicle() const { if( top == 0 ) { return NULL; } if( capacity <= 1 ) { // it will crash on capacity==1 and top==0, but this should never happen! // only ships and aircraft can go on tiles without ways => only test for those uint8 t = obj.one->get_typ(); if( t == obj_t::air_vehicle || t == obj_t::water_vehicle ) { return obj.one; } } else { for( uint8 i=0; i < top; i++ ) { uint8 typ = obj.some[i]->get_typ(); if( typ >= obj_t::road_vehicle && typ <= obj_t::air_vehicle ) { return obj.some[i]; } } } return NULL; } void objlist_t::rdwr(loadsave_t *file, koord3d current_pos) { if(file->is_loading()) { sint32 max_object_index; if( file->is_version_less(110, 1) ) { file->rdwr_long(max_object_index); if(max_object_index>254) { dbg->error("objlist_t::laden()","Too many objects (%i) at (%i,%i), some vehicle may not appear immediately.",max_object_index,current_pos.x,current_pos.y); } } else { uint8 obj_count; file->rdwr_byte(obj_count); max_object_index = -1+(sint32)obj_count; } for(sint32 i=0; i<=max_object_index; i++) { obj_t::typ typ = (obj_t::typ)file->rd_obj_id(); // DBG_DEBUG("objlist_t::laden()", "Thing type %d", typ); if(typ == -1) { continue; } obj_t *new_obj = NULL; switch(typ) { case obj_t::bruecke: new_obj = new bruecke_t(file); break; case obj_t::tunnel: new_obj = new tunnel_t(file); break; case obj_t::pumpe: new_obj = new pumpe_t(file); break; case obj_t::leitung: new_obj = new leitung_t(file); break; case obj_t::senke: new_obj = new senke_t(file); break; case obj_t::zeiger: new_obj = new zeiger_t(file); break; case obj_t::signal: new_obj = new signal_t(file); break; case obj_t::label: new_obj = new label_t(file); break; case obj_t::crossing: new_obj = new crossing_t(file); break; case obj_t::wayobj: { wayobj_t* const wo = new wayobj_t(file); if (wo->get_desc() == NULL) { // ignore missing wayobjs wo->set_flag(obj_t::not_on_map); delete wo; new_obj = NULL; } else { new_obj = wo; } break; } // some old offsets will be converted to new ones case obj_t::old_fussgaenger: typ = obj_t::pedestrian; /* FALLTHROUGH */ case obj_t::pedestrian: { pedestrian_t* const pedestrian = new pedestrian_t(file); if (pedestrian->get_desc() == NULL) { // no pedestrians ... delete this pedestrian->set_flag(obj_t::not_on_map); delete pedestrian; new_obj = NULL; } else { new_obj = pedestrian; } break; } case obj_t::old_verkehr: typ = obj_t::road_user; /* FALLTHROUGH */ case obj_t::road_user: { private_car_t* const car = new private_car_t(file); if (car->get_desc() == NULL) { // no citycars ... delete this car->set_flag(obj_t::not_on_map); delete car; } else { new_obj = car; } break; } case obj_t::old_monoraildepot: typ = obj_t::monoraildepot; /* FALLTHROUGH */ case obj_t::monoraildepot: new_obj = new monoraildepot_t(file); break; case obj_t::old_tramdepot: typ = obj_t::tramdepot; /* FALLTHROUGH */ case obj_t::tramdepot: new_obj = new tramdepot_t(file); break; case obj_t::strassendepot: new_obj = new strassendepot_t(file); break; case obj_t::schiffdepot: new_obj = new schiffdepot_t(file); break; case obj_t::old_airdepot: typ = obj_t::airdepot; /* FALLTHROUGH */ case obj_t::airdepot: new_obj = new airdepot_t(file); break; case obj_t::maglevdepot: new_obj = new maglevdepot_t(file); break; case obj_t::narrowgaugedepot: new_obj = new narrowgaugedepot_t(file); break; case obj_t::bahndepot: { // for compatibility reasons we may have to convert them to tram and monorail depots bahndepot_t* bd; gebaeude_t gb(file); building_tile_desc_t const* const tile = gb.get_tile(); if( tile ) { switch (tile->get_desc()->get_extra()) { case monorail_wt: bd = new monoraildepot_t( gb.get_pos(), gb.get_owner(), tile); break; case tram_wt: bd = new tramdepot_t( gb.get_pos(), gb.get_owner(), tile); break; default: bd = new bahndepot_t( gb.get_pos(), gb.get_owner(), tile); break; } } else { bd = new bahndepot_t( gb.get_pos(), gb.get_owner(), NULL ); } bd->rdwr_vehicles(file); new_obj = bd; typ = new_obj->get_typ(); // do not remove from this position, since there will be nothing gb.set_flag(obj_t::not_on_map); } break; // check for pillars case obj_t::old_pillar: typ = obj_t::pillar; /* FALLTHROUGH */ case obj_t::pillar: { pillar_t *p = new pillar_t(file); if(p->get_desc()!=NULL && p->get_desc()->get_pillar()!=0) { new_obj = p; } else { // has no pillar ... // do not remove from this position, since there will be nothing p->set_flag(obj_t::not_on_map); delete p; } } break; case obj_t::baum: { baum_t *b = new baum_t(file); if( !b->get_desc() ) { // is there a replacement possible if( const tree_desc_t *desc = tree_builder_t::random_tree_for_climate( world()->get_climate_at_height(current_pos.z) ) ) { b->set_desc( desc ); } else { // do not remove from map on this position, since there will be nothing b->set_flag(obj_t::not_on_map); delete b; b = NULL; } } else { new_obj = b; } } break; case obj_t::groundobj: { groundobj_t* const groundobj = new groundobj_t(file); if(groundobj->get_desc() == NULL) { // do not remove from this position, since there will be nothing groundobj->set_flag(obj_t::not_on_map); delete groundobj; } else { new_obj = groundobj; } break; } case obj_t::movingobj: { movingobj_t* const movingobj = new movingobj_t(file); if (movingobj->get_desc() == NULL) { // no citycars ... delete this movingobj->set_flag(obj_t::not_on_map); delete movingobj; } else { new_obj = movingobj; } break; } case obj_t::gebaeude: { gebaeude_t *gb = new gebaeude_t(file); if(gb->get_tile()==NULL) { // do not remove from this position, since there will be nothing gb->set_flag(obj_t::not_on_map); delete gb; gb = NULL; } else { new_obj = gb; } } break; case obj_t::old_roadsign: typ = obj_t::roadsign; /* FALLTHROUGH */ case obj_t::roadsign: { roadsign_t *rs = new roadsign_t(file); if(rs->get_desc()==NULL) { // roadsign_t without description => ignore rs->set_flag(obj_t::not_on_map); delete rs; } else { new_obj = rs; } } break; // will be ignored, was only used before 86.09 case obj_t::old_gebaeudefundament: { dummy_obj_t d(file); break; } // only factories can smoke; but then, the smoker is reinstated after loading case obj_t::old_raucher: { raucher_t r(file); break; } // wolke is not saved any more case obj_t::cloud: { wolke_t w(file); break; } case obj_t::old_async_wolke: { async_wolke_t w(file); break; } default: dbg->fatal("objlist_t::laden()", "During loading: Unknown object type '%d'", typ); } if(new_obj && new_obj->get_typ()!=typ) { dbg->warning( "objlist_t::rdwr()","typ error : %i instead %i on %i,%i, object ignored!", new_obj->get_typ(), typ, new_obj->get_pos().x, new_obj->get_pos().y ); new_obj = NULL; } if(new_obj && new_obj->get_pos()==koord3d::invalid) { new_obj->set_pos( current_pos ); } if(new_obj && new_obj->get_pos()!=current_pos) { dbg->warning("objlist_t::rdwr()","position error: %i,%i,%i instead %i,%i,%i (object will be ignored)",new_obj->get_pos().x,new_obj->get_pos().y,new_obj->get_pos().z,current_pos.x,current_pos.y,current_pos.z); new_obj = NULL; } if(new_obj) { append(new_obj); } } } else { /* here is the saving part ... * first: construct a list of stuff really needed to save */ obj_t *save[256]; sint32 max_object_index = 0; for( uint16 i=0; iget_typ()==obj_t::way // do not save smoke || new_obj->get_typ()==obj_t::cloud // fields will be built by factory || new_obj->get_typ()==obj_t::field // do not save factory buildings => factory will reconstruct them || (new_obj->get_typ()==obj_t::gebaeude && ((gebaeude_t *)new_obj)->get_fabrik()) // things with convoi will not be saved || (new_obj->get_typ()>=66 && new_obj->get_typ()<82) || (new_obj->get_typ()==obj_t::baum && file->is_version_atleast(110, 1) && (env_t::server || file->is_version_atleast(122, 2))) // trees are saved from boden_t ) { // these objects are simply not saved } else { save[max_object_index++] = new_obj; } } // now we know the number of stuff to save max_object_index --; if( file->is_version_less(110, 1) ) { file->rdwr_long( max_object_index ); } else { uint8 obj_count = max_object_index+1; file->rdwr_byte( obj_count ); } for(sint32 i=0; i<=max_object_index; i++) { obj_t *new_obj = save[i]; if(new_obj->get_pos()==current_pos) { file->wr_obj_id(new_obj->get_typ()); new_obj->rdwr(file); } else if (new_obj->get_pos().get_2d() == current_pos.get_2d()) { // ok, just error in z direction => we will correct it dbg->warning( "objlist_t::rdwr()","position error: z pos corrected on %i,%i from %i to %i", new_obj->get_pos().x, new_obj->get_pos().y, new_obj->get_pos().z, current_pos.z); file->wr_obj_id(new_obj->get_typ()); new_obj->set_pos(current_pos); new_obj->rdwr(file); } else { dbg->error("objlist_t::rdwr()","unresolvable position error: %i,%i instead %i,%i (object type %i will be not saved!)", new_obj->get_pos().x, new_obj->get_pos().y, current_pos.x, current_pos.y, new_obj->get_typ()); file->wr_obj_id(-1); } } } } /** display all things, faster, but will lead to clipping errors */ #ifdef MULTI_THREAD void objlist_t::display_obj_quick_and_dirty( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const sint8 clip_num ) const #else void objlist_t::display_obj_quick_and_dirty( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const bool is_global ) const #endif { if(capacity==0) { return; } else if(capacity==1) { if(start_offset==0) { // only draw background on request obj.one->display( xpos, ypos CLIP_NUM_PAR); } // foreground need to be drawn in any case #ifdef MULTI_THREAD obj.one->display_after(xpos, ypos, clip_num ); #else obj.one->display_after( xpos, ypos, is_global ); if( is_global ) { obj.one->clear_flag( obj_t::dirty ); } #endif return; } for( uint8 n = start_offset; n < top; n++ ) { // is there an object ? obj.some[n]->display( xpos, ypos CLIP_NUM_PAR); } // foreground (needs to be done backwards! for( size_t n = top; n-- != 0; ) { #ifdef MULTI_THREAD obj.some[n]->display_after( xpos, ypos, clip_num ); #else obj.some[n]->display_after( xpos, ypos, is_global ); if( is_global ) { obj.some[n]->clear_flag( obj_t::dirty ); } #endif } } /** * Routine to display background images of non-moving things * powerlines have to be drawn after vehicles (and thus are in the obj-array inserted after vehicles) * @return the index of the first moving thing (or powerline) * * objlist_t::display_obj_bg() .. called by the methods in grund_t * local_display_obj_bg() .. local function to avoid code duplication, returns false if the first non-valid obj is reached */ inline bool local_display_obj_bg(const obj_t *obj, const sint16 xpos, const sint16 ypos CLIP_NUM_DEF) { const bool display_obj = !obj->is_moving(); if( display_obj ) { obj->display( xpos, ypos CLIP_NUM_PAR); } return display_obj; } uint8 objlist_t::display_obj_bg( const sint16 xpos, const sint16 ypos, const uint8 start_offset CLIP_NUM_DEF) const { if( start_offset >= top ) { return start_offset; } if( capacity == 1 ) { return local_display_obj_bg( obj.one, xpos, ypos CLIP_NUM_PAR); } for( uint8 n = start_offset; n < top; n++ ) { if( !local_display_obj_bg( obj.some[n], xpos, ypos CLIP_NUM_PAR) ) { return n; } } return top; } /** * Routine to draw vehicles * .. vehicles are draws if driving in direction ribi (with special treatment of flying aircrafts) * .. clips vehicle only along relevant edges (depends on ribi and vehicle direction) * * @param draw_obj * @param xpos * @param ypos * @param ribi * @ param ontile if true then vehicles are on the tile that defines the clipping * @param CLIP_NUM_DEF * @return the index of the first non-moving thing * * objlist_t::display_obj_vh() .. called by the methods in grund_t * local_display_obj_vh() .. local function to avoid code duplication, returns false if the first non-valid obj is reached */ inline bool local_display_obj_vh(const obj_t *draw_obj, const sint16 xpos, const sint16 ypos, const ribi_t::ribi ribi, const bool ontile CLIP_NUM_DEF) { vehicle_base_t const* const v = obj_cast(draw_obj); air_vehicle_t const* a; if( v && (ontile || !(a = obj_cast(v)) || a->is_on_ground()) ) { const ribi_t::ribi veh_ribi = v->get_direction(); if( ontile || (veh_ribi & ribi) == ribi || (ribi_t::backward(veh_ribi) & ribi )== ribi || draw_obj->get_typ() == obj_t::air_vehicle ) { // activate clipping only for our direction masked by the ribi argument // use non-convex clipping (16) only if we are on the currently drawn tile or its n/w neighbours activate_ribi_clip( ((veh_ribi|ribi_t::backward(veh_ribi))&ribi) | (ontile || ribi == ribi_t::north || ribi == ribi_t::west ? 16 : 0) CLIP_NUM_PAR); draw_obj->display( xpos, ypos CLIP_NUM_PAR); } return true; } else { // if !ontile starting_offset is not correct, hence continue searching till the end return !ontile; } } uint8 objlist_t::display_obj_vh( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const ribi_t::ribi ribi, const bool ontile CLIP_NUM_DEF) const { if( start_offset >= top ) { return start_offset; } if( capacity <= 1 ) { uint8 i = local_display_obj_vh( obj.one, xpos, ypos, ribi, ontile CLIP_NUM_PAR); activate_ribi_clip( ribi_t::all CLIP_NUM_PAR); return i; } uint8 nr_v = start_offset; for( uint8 n = start_offset; n < top; n++ ) { if( local_display_obj_vh( obj.some[n], xpos, ypos, ribi, ontile CLIP_NUM_PAR) ) { nr_v = n; } else { break; } } activate_ribi_clip( ribi_t::all CLIP_NUM_PAR); return nr_v+1; } /** * Routine to draw foreground images of everything on the tile (no clipping) and powerlines * * @param xpos * @param ypos * @param start_offset .. draws also background images of all objects with index>=start_offset * @param is_global will be only true for the main display; all miniworld windows should still reset main window */ #ifdef MULTI_THREAD void objlist_t::display_obj_fg( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const sint8 clip_num ) const #else void objlist_t::display_obj_fg( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const bool is_global ) const #endif { if( top == 0 ) { // nothing => finish return; } // now draw start_offset background and all foreground! if( capacity == 1 ) { if( start_offset == 0 ) { obj.one->display( xpos, ypos CLIP_NUM_PAR); } #ifdef MULTI_THREAD obj.one->display_after( xpos, ypos, clip_num ); #else obj.one->display_after( xpos, ypos, is_global ); if( is_global ) { obj.one->clear_flag(obj_t::dirty); } #endif return; } for( uint8 n = start_offset; n < top; n++ ) { obj.some[n]->display( xpos, ypos CLIP_NUM_PAR); } // foreground (needs to be done backwards!) for( size_t n = top; n-- != 0; ) { #ifdef MULTI_THREAD obj.some[n]->display_after( xpos, ypos, clip_num ); #else obj.some[n]->display_after( xpos, ypos, is_global ); if( is_global ) { obj.some[n]->clear_flag( obj_t::dirty ); } #endif } return; } #ifdef MULTI_THREAD void objlist_t::display_obj_overlay(const sint16 xpos, const sint16 ypos) const { if( top == 0 ) { return; // nothing => finish } if( capacity == 1 ) { obj.one->display_overlay( xpos, ypos ); obj.one->clear_flag( obj_t::dirty ); } else { for( size_t n = top; n-- != 0; ) { obj.some[n]->display_overlay( xpos, ypos ); obj.some[n]->clear_flag( obj_t::dirty ); } } } #endif void objlist_t::check_season(const bool calc_only_season_change) { if( 0 == top ) { return; } if( capacity <= 1 ) { // lets check here for consistency if( top != capacity ) { dbg->fatal( "objlist_t::check_season()", "top not matching!" ); } obj_t *check_obj = obj.one; if( !check_obj->check_season( calc_only_season_change ) ) { delete check_obj; } } else { // copy object pointers to check them vector_tpl list; for( uint8 i = 0; i < top; i++ ) { list.append(obj.some[i]); } // now work on the copied list // check_season may change this list (by planting new trees) for( uint8 i = 0, end = list.get_count(); i < end; i++ ) { obj_t *check_obj = list[i]; if( !check_obj->check_season( calc_only_season_change ) ) { delete check_obj; } } } } simutrans-124.3/src/simutrans/dataobj/objlist.h000066400000000000000000000075501474050137200216210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_OBJLIST_H #define DATAOBJ_OBJLIST_H #include "../simtypes.h" #include "../obj/simobj.h" /** * All things including ways are stored in this structure. * The entries are packed, i.e. the first free entry is at the top. * To save memory, a single element (like in the case for houses or a single tree) * is stored directly (obj.one) and capacity==1. Otherwise obj.some points to an * array. * The objects are sorted according to their drawing order. * ways are always first. */ class objlist_t { private: union { obj_t **some; // valid if capacity > 1 obj_t *one; // valid if capacity == 1 (and NULL if top or capacity==0!) } obj; /** * Number of items which can be stored without expanding * zero indicates empty list */ uint8 capacity; /** * 0-based index of the next free entry after the last element * therefore also the count of number of items which are stored */ uint8 top; void set_capacity(uint16 new_cap); bool grow_capacity(); void shrink_capacity(uint8 last_index); inline void intern_insert_at(obj_t* new_obj, uint8 pri); // only used internal for loading. DO NOT USE OTHERWISE! Use add instead! bool append(obj_t *obj); // this will automatically give the right order for citycars and the like ... bool intern_add_moving(obj_t* new_obj); objlist_t(objlist_t const&); objlist_t& operator=(objlist_t const&); public: objlist_t(); ~objlist_t(); void rdwr(loadsave_t *file,koord3d current_pos); obj_t * suche(obj_t::typ typ,uint8 start) const; // since this is often needed, it is defined here obj_t * get_leitung() const; obj_t * get_convoi_vehicle() const; /** * @param n thing index (unsigned value!) * @return thing at index n or NULL if n is out of bounds */ inline obj_t * bei(uint8 n) const { if( n >= top ) { return NULL; } return (capacity<=1) ? obj.one : obj.some[n]; } // usually used only for copying by grund_t obj_t *remove_last(); /// This routine will automatically obey the correct order of things during insertion. bool add(obj_t *obj); bool remove(const obj_t* obj); bool loesche_alle(player_t *player,uint8 offset); bool ist_da(const obj_t* obj) const; void rotate90_moving(); inline uint8 get_top() const {return top;} /** * sorts the trees according to their offsets */ void sort_trees(uint8 index, uint8 count); /** * @return NULL when OK, or message, why not? */ const char *kann_alle_entfernen(const player_t *player, uint8 offset) const; /** recalcs all objects on this tile */ void calc_image(); /** * Sets all objects dirty to prevent artifacts with smart hide cursor */ void set_all_dirty(); /** * Called whenever the season or snowline height changes */ void check_season(const bool calc_only_season_change); /** display all things, faster, but will lead to clipping errors */ #ifdef MULTI_THREAD void display_obj_quick_and_dirty( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const sint8 clip_num ) const; #else void display_obj_quick_and_dirty( const sint16 xpos, const sint16 ypos, const uint8 start_offset, const bool is_global ) const; #endif /** * display all things, called by the routines in grund_t */ uint8 display_obj_bg(const sint16 xpos, const sint16 ypos, const uint8 start_offset CLIP_NUM_DEF) const; uint8 display_obj_vh(const sint16 xpos, const sint16 ypos, const uint8 start_offset, const ribi_t::ribi ribi, const bool ontile CLIP_NUM_DEF) const; #ifdef MULTI_THREAD void display_obj_fg(const sint16 xpos, const sint16 ypos, const uint8 start_offset, const sint8 clip_num ) const; void display_obj_overlay(const sint16 xpos, const sint16 ypos) const; #else void display_obj_fg(const sint16 xpos, const sint16 ypos, const uint8 start_offset, const bool is_global ) const; #endif } GCC_PACKED; #endif simutrans-124.3/src/simutrans/dataobj/pakset_downloader.cc000066400000000000000000000272001474050137200240100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "pakset_downloader.h" #include "environment.h" #include "../sys/simsys.h" #include "../simloadingscreen.h" #ifdef _WIN32 #ifdef USE_URLMON // needs to add urlmon.lib to the linker #include #endif #endif #define USE_OWN_PAKINSTALL #ifdef __ANDROID__ // since the script does only work on few devices #define USE_OWN_PAKINSTALL #endif // check if pakset is installed, and if yes, check version string bool pak_need_update(const paksetinfo_t *pi) { cbuffer_t outside; outside.append(env_t::install_dir); outside.append(pi->name); outside.append(PATH_SEPARATOR); outside.append("ground.Outside.pak"); if( FILE* f = dr_fopen(outside.get_str(), "r") ) { fseek(f, 99, SEEK_SET); uint8 len = fgetc(f); fgetc(f); char versionstring[256]; fgets(versionstring, len, f); fclose(f); versionstring[len] = 0; // needs update, if string mismatch return strcmp(versionstring, pi->version); } return false; } // check, if we can handle this pak with the current configuration bool pak_can_download(const paksetinfo_t *pi) { #ifndef USE_OWN_PAKINSTALL // check script install #ifdef _WIN32 if (strstr(pi->url, ".zip")) { return true; } #else #ifndef __ANDROID__ return true; #endif // install with scripts does not work in Android return false; #endif #else #ifdef __ANDROID__ // no https for Android for now if (strncmp(pi->url, "https://",8)==0) { return false; } #endif // own routines, require http (for Android) and zip if (strstr(pi->url, ".zip")) { return true; } #endif return false; } #ifndef USE_OWN_PAKINSTALL // download and install pak into current path: skript method bool pak_download(vector_tplpaks) { // now install dr_mkdir( env_t::install_dir ); dr_chdir( env_t::install_dir ); loadingscreen_t ls("Install paks", paks.get_count(), true, false); int j = 0; for(paksetinfo_t *pi : paks) { cbuffer_t param; ls.set_info(ps->name); #ifdef _WIN32 param.append("powershell -ExecutionPolicy ByPass -NoExit "); param.append(env_t::install_dir); param.append("get_pak.ps1 \"" ); #else #ifndef __ANDROID__ param.append( env_t::install_dir); param.append("get_pak.sh \""); #else param.append("sh "); param.append(env_t::install_dir); param.append("get_pak.sh \""); #endif #endif param.append(ps->url); param.append("\""); const int retval = system( param ); DBG_DEBUG("pakinstaller_t::action_triggered", "Command '%s' returned %d", param.get_str(), retval); ls.set_progress(++j); } return true; } #else #include "../utils/simstring.h" #include "../network/network_file_transfer.h" #ifdef __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wundef" # pragma GCC diagnostic ignored "-Wcast-qual" # ifndef __clang__ # pragma GCC diagnostic ignored "-Wcalloc-transposed-args" # endif #endif #define STDC #define voidpc voidpczip #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES extern "C" { #include "../../external/zip.c" }; #ifdef __GNUC__ # pragma GCC diagnostic pop #endif static void extract_pak_from_zip(const char* zipfile) { struct zip_t* zip = zip_open(zipfile, 0, 'r'); const int n = zip_entries_total(zip); bool has_simutrans_folder = false; loadingscreen_t ls("Extract files", n, true, false); for (int i = 0; i < n && i < 10 && !has_simutrans_folder; ++i) { zip_entry_openbyindex(zip, i); { int isdir = zip_entry_isdir(zip); if (isdir) { has_simutrans_folder = STRNICMP("simutrans", zip_entry_name(zip), 9) == 0; } } zip_entry_close(zip); } // now extract for (int i = 0; i < n; i++) { zip_entry_openbyindex(zip, i); { int isdir = zip_entry_isdir(zip); const char* name = zip_entry_name(zip) + (has_simutrans_folder ? 10 : 0); if (isdir) { // create directory (may fail if exists ... dr_mkdir(name); } else { // or extract file DBG_DEBUG("Install pak file", "%s", name); zip_entry_fread(zip, name); } } zip_entry_close(zip); ls.set_progress(i); } zip_close(zip); } // download and install pak into install path: using own zip/http routines bool pak_download(vector_tplpaks) { bool all_good=true; dr_mkdir(env_t::install_dir); dr_chdir(env_t::install_dir); loadingscreen_t ls("Install paks", paks.get_count() * 2, true, false); char outfilename[PATH_MAX]; int j = 0; for (paksetinfo_t* pi : paks) { ls.set_info(pi->name); if (strncmp(pi->url, "https://", 6) == 0) { #ifdef _WIN32 #ifndef USE_URLMON sprintf(outfilename, "powershell \"(New-Object System.Net.WebClient).DownloadFile('%s', 'temp.zip')\"", pi->url); system(outfilename); #else // use if (URLDownloadToFile(NULL, pi->url, "temp.zip", 0, NULL) != 0) { dbg->warning("pak_download()", "Pakset download failed"); j += 2; ls.set_progress(j); all_good = false; continue; } strcpy(outfilename, "temp.zip"); #endif #else #ifndef __ANDROID__ sprintf(outfilename, "curl --progress-bar -L '%s' > 'temp.zip'", pi->url); system(outfilename); strcpy(outfilename, "temp.zip"); #endif #endif } else { // download using our simutrans code sprintf(outfilename, "%s.zip", pi->name); const char* url = pi->url + 7; // minus http:// char site_ip[1024]; tstrncpy(site_ip, url, lengthof(site_ip)); const char* site_path = strchr(url, '/'); site_ip[site_path - url] = 0; strcat(site_ip, ":80"); const char* err = NULL; err = network_http_get_file(site_ip, site_path, outfilename); if (err) { dbg->warning("Pakset download failed with", "%s", err); j += 2; ls.set_progress(j); all_good = false; continue; } } ls.set_progress(++j); DBG_DEBUG(__FUNCTION__, "pak target %s", pi->name); DBG_DEBUG(__FUNCTION__, "download successful to %s, attempting extract", outfilename); extract_pak_from_zip(outfilename); dr_remove(outfilename); ls.set_progress(++j); } return all_good; } #endif #if 0 // curl code broken for now #include // linux/android specific, function to create folder makes use of opendir (linux system call) and mkdir (via system) static bool create_folder_if_required(const char* extracted_path) { char extracted_folder_name[FILENAME_MAX]; strcpy(extracted_folder_name, extracted_path); char* last_occurence = strrchr(extracted_folder_name, '/'); if (last_occurence != NULL) { last_occurence[0] = '\0'; } else { DBG_DEBUG(__FUNCTION__, "Error searching for path? %s", extracted_folder_name); return false; } char current_path[PATH_MAX]; dr_getcwd(current_path, PATH_MAX); if (dr_chdir(extracted_folder_name) != 0) { dr_mkdir(extracted_folder_name); DBG_DEBUG(__FUNCTION__, "- - Created folder %s", extracted_folder_name); } if (dr_chdir(extracted_folder_name) != 0) { DBG_DEBUG(__FUNCTION__, "Failed to create %s", extracted_folder_name); return false; } dr_chdir(current_path); return true; } static void extract_pak_from_zip(const char* outfilename) { zip_t* zip_archive; int err; if ((zip_archive = zip_open(outfilename, ZIP_RDONLY, &err)) == NULL) { zip_error_t error; zip_error_init_with_code(&error, err); DBG_DEBUG(__FUNCTION__, "cannot open zip archive \"%s\": %s : %d", outfilename, zip_error_strerror(&error), error); zip_error_fini(&error); } DBG_DEBUG(__FUNCTION__, "zip archive opened"); zip_uint64_t nentry = (zip_uint64_t)zip_get_num_entries(zip_archive, 0); for (zip_uint64_t idx = 0; idx < nentry; idx++) { struct zip_stat st; if (zip_stat_index(zip_archive, idx, 0, &st) == -1) { DBG_DEBUG(__FUNCTION__, "cannot read file stat %d in zip archive: %s", idx, zip_strerror(zip_archive)); continue; } zip_file_t* zip_file; if ((zip_file = zip_fopen_index(zip_archive, idx, 0)) == NULL) { DBG_DEBUG(__FUNCTION__, "cannot open file %s (index %d) in zip_archive: %s", st.name, idx, zip_strerror(zip_archive)); continue; } char* contents = new char[st.size]; zip_int64_t read_size; if ((read_size = zip_fread(zip_file, contents, st.size)) == -1) { DBG_DEBUG(__FUNCTION__, "failed to read content in file %s (index %d) of zip_archive: %s", st.name, idx, zip_file_strerror(zip_file)); } else { if (read_size != (zip_int64_t)st.size) { DBG_DEBUG(__FUNCTION__, "unexpected content size in file %s (index %d) of zip_archive; is %d, should be %d: %s", st.name, idx, read_size, st.size); } else { // path may start with simutrans/, in which case it can be removed safely bool start_with_simutrans = STRNICMP(st.name, "simutrans", 9) == 0; const char* target_filename = start_with_simutrans ? st.name + 10 : st.name; char extracted_path[PATH_MAX]; sprintf(extracted_path, "%s%s", env_t::install_dir, target_filename); DBG_DEBUG(__FUNCTION__, "- %s: %d", extracted_path, st.size); if (!create_folder_if_required(extracted_path)) { continue; } if (st.size > 0) { if (FILE* f = dr_fopen(extracted_path, "wb")) { fwrite(contents, st.size, 1, f); fclose(f); } else { DBG_DEBUG(__FUNCTION__, "Error writing file"); } } } } zip_fclose(zip_file); } if (zip_close(zip_archive) == -1) { DBG_DEBUG(__FUNCTION__, "cannot close zip archive: %s", zip_strerror(zip_archive)); } dr_chdir(env_t::install_dir); dr_remove(outfilename); } #include static size_t curl_write_data(void* ptr, size_t size, size_t nmemb, FILE* stream) { size_t written = fwrite(ptr, size, nmemb, stream); return written; } static CURLcode curl_download_file(CURL* curl, const char* target_file, const char* url) { FILE* fp = dr_fopen(target_file, "wb"); CURLcode res; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); char cabundle_path[PATH_MAX]; sprintf(cabundle_path, "%s%s", env_t::base_dir, "cacert.pem"); FILE* cabundle_file; if ((cabundle_file = dr_fopen(cabundle_path, "r"))) { fclose(cabundle_file); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_CAINFO, cabundle_path); } else { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); dbg->warning(__FUNCTION__, "ssl certificate authority bundle not found at %s; https calls will not be validated; this may be a security concern", cabundle_path); } curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); res = curl_easy_perform(curl); fclose(fp); return res; } // download and install pak into install path: using curl and libzip (huge certificate storage) bool pak_download(vector_tplpaks) { CURL* curl = curl_easy_init(); // can only be called once during program lifecycle if (curl) { DBG_DEBUG(__FUNCTION__, "libcurl initialized"); char outfilename[FILENAME_MAX]; loadingscreen_t ls("Install paks", paks.get_count() * 2, true, false); int j = 0; for (paksetinfo_t *pi : paks.get_selections()) { ls.set_info(pi->name); sprintf(outfilename, "%s.zip", pi->name); dr_chdir(env_t::install_dir); CURLcode res = curl_download_file(curl, outfilename, pi->url); ls.set_progress(++j); DBG_DEBUG(__FUNCTION__, "pak target %s", pi->url); if (res == 0) { DBG_DEBUG(__FUNCTION__, "download successful to %s, attempting extract", outfilename); read_zip(outfilename); } else { DBG_DEBUG(__FUNCTION__, "download failed with error code %s, check curl errors; skipping", curl_easy_strerror(res)); } ls.set_progress(++j); } curl_easy_cleanup(curl); } else { DBG_DEBUG(__FUNCTION__, "libcurl failed to initialize, pakset not downloaded"); } finish_install = true; return false; } #endif simutrans-124.3/src/simutrans/dataobj/pakset_downloader.h000066400000000000000000000012721474050137200236530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PAKSET_DOWNLOADER_H #define PAKSET_DOWNLOADER_H #include "../simtypes.h" #include "../tpl/vector_tpl.h" typedef struct { const char *url; const char *name; const char *version; uint size; } paksetinfo_t; // download and install pak into current path bool pak_download(vector_tpl); // check if pakset is installed, and if yes, check version string bool pak_need_update(const paksetinfo_t *); // check, if we can handle these kindS of paks with the current configuration bool pak_can_download(const paksetinfo_t *); bool pak_remove(const paksetinfo_t*); #endif simutrans-124.3/src/simutrans/dataobj/pakset_manager.cc000066400000000000000000000322731474050137200232720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "pakset_manager.h" #include "../utils/searchfolder.h" #include "../display/simgraph.h" #include "../sys/simsys.h" #include "../simskin.h" #include "../simloadingscreen.h" #include "../descriptor/ground_desc.h" #include "../descriptor/reader/obj_reader.h" #include "../descriptor/vehicle_desc.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "../dataobj/translator.h" #include "../gui/help_frame.h" #include "../gui/simwin.h" #include "../dataobj/environment.h" #include "../network/pakset_info.h" pakset_manager_t::obj_map_t* pakset_manager_t::registered_readers; inthashtable_tpl > pakset_manager_t::loaded; pakset_manager_t::unresolved_map_t pakset_manager_t::unresolved; ptrhashtable_tpl pakset_manager_t::fatals; std::string pakset_manager_t::doublettes; stringhashtable_tpl pakset_manager_t::missing_pak_names; std::string pakset_manager_t::overlaid_warning; void pakset_manager_t::register_reader(obj_reader_t *reader) { if(!registered_readers) { registered_readers = new obj_map_t; } registered_readers->put(reader->get_type(), reader); //printf("This program can read %s objects\n", get_type_name()); } const char* pakset_manager_t::get_doubled_warning_message() { return translator::translate("Doubled objects detected. Click to see details."); } void pakset_manager_t::load_pakset(bool load_addons) { dbg->message("pakset_manager_t::load_pakset", "Reading object data from %s...", env_t::pak_dir.c_str()); if (!load_paks_from_directory( env_t::pak_dir.c_str(), load_addons, translator::translate("Loading paks ...") )) { dbg->fatal("pakset_manager_t::load_pakset", "Failed to load pakset. Please re-download or select another pakset."); } overlaid_warning.clear(); if( had_overlaid() ) { overlaid_warning.append( translator::translate("

Error

") ); overlaid_warning.append( env_t::pak_name + translator::translate("contains the following doubled objects:

") + get_overlaid() + "

" ); clear_overlaid(); } if( load_addons ) { // try to read addons from private directory dr_chdir( env_t::user_dir ); // Do not disable addons after failing to find addon objects // because a user might only have addon scenarios but no addon objects. // So do not check the return value here. load_paks_from_directory("addons/" + env_t::pak_name, true, translator::translate("Loading addon paks ...")); dr_chdir( env_t::base_dir ); if( had_overlaid() ) { overlaid_warning.append( translator::translate("

Warning

addons for") + env_t::pak_name + translator::translate("contains the following doubled objects:

") + get_overlaid() ); clear_overlaid(); } } if (!finish_loading()) { dbg->fatal("pakset_manager_t::load_pakset", "Failed to load pakset. Please re-download or select another pakset."); } pakset_info_t::calculate_checksum(); if( env_t::verbose_debug >= log_t::LEVEL_DEBUG ) { pakset_info_t::debug(); } } void pakset_manager_t::open_doubled_warning_window() { help_frame_t *win = new help_frame_t(); win->set_text( overlaid_warning.c_str() ); create_win(win, w_info, magic_none); } bool pakset_manager_t::load_paks_from_directory(const std::string &path, bool load_addons, const char *message) { const bool drawing = is_display_init(); // step is a bitmask to decide when it's time to update the progress bar. // It takes the biggest power of 2 less than the number of elements and // divides it in 256 sub-steps at most (the -7 comes from here) searchfolder_t find; const searchfolder_t::search_flags_t addon_flags = load_addons ? searchfolder_t::SF_NONE : searchfolder_t::SF_NOADDONS; const sint32 max = find.search(path, "pak", addon_flags | searchfolder_t::SF_PREPEND_PATH, 4); sint32 step = -7; for( sint32 bit = 1; bit < max; bit += bit ) { step++; } if( step < 0 ) { step = 0; } step = (2<warning("pakset_manager_t::load_paks_from_directory", "File 'symbol.BigLogo.pak' cannot be read, startup logo will not be displayed!"); } } loadingscreen_t ls( message, max, true ); if( ground_desc_t::outside==NULL ) { // define the pak tile width if (!load_pak_file(path + "ground.Outside.pak")) { return false; } if(ground_desc_t::outside==NULL) { dbg->warning("pakset_manager_t::load_paks_from_directory", "File ground.Outside.pak not found, cannot guess tile size! (driving on left will not work!)"); } else if (char const* const copyright = ground_desc_t::outside->get_copyright()) { ls.set_info(copyright); } } DBG_MESSAGE("pakset_manager_t::load_paks_from_directory", "Reading from '%s'", path.c_str()); uint n = 0; for (char* const& pak_filename : find) { if (!load_pak_file(pak_filename)) { dbg->warning("pakset_manager_t::load_paks_from_directory", "Cannot load '%s', some objects might be unavailable!", pak_filename); } if ((n++ & step) == 0 && drawing) { ls.set_progress(n); } } ls.set_progress(max); return find.begin()!=find.end(); } bool pakset_manager_t::load_pak_file(const std::string &filename) { // added trace DBG_DEBUG("pakset_manager_t::load_pak_file", "filename='%s'", filename.c_str()); FILE* const fp = dr_fopen(filename.c_str(), "rb"); if (!fp) { dbg->error("pakset_manager_t::load_pak_file", "Reading '%s' failed!", filename.c_str()); return false; } // This is the normal header reading code int c; uint32 n = 0; do { c = fgetc(fp); n ++; } while(c != EOF && c != 0x1a); if(c == EOF) { dbg->error("pakset_manager_t::load_pak_file", "Unexpected end of file after %u bytes while reading '%s'!", n, filename.c_str()); fclose(fp); return false; } // Compiled Version char dummy[4]; n = fread(dummy, 4, 1, fp); if (n != 1) { fclose(fp); return false; } char *p = dummy; const uint32 version = decode_uint32(p); DBG_DEBUG("pakset_manager_t::load_pak_file", "Read %u blocks, file version is %x", n, version); if(version <= COMPILER_VERSION_CODE) { obj_desc_t *data = NULL; if (!read_nodes(fp, data, 0, version)) { fclose(fp); return false; } } else { DBG_DEBUG("pakset_manager_t::load_pak_file", "Version of '%s' is too old, %u instead of %u", filename.c_str(), version, COMPILER_VERSION_CODE ); fclose(fp); return false; } fclose(fp); return true; } /* * Do the last loading procedures * Resolve all xrefs */ bool pakset_manager_t::finish_loading() { // vehicle to follow to mark something cannot lead a convoi (prev[0]=any) or cannot end a convoi (next[0]=any) vehicle_desc_t::any_vehicle = new vehicle_desc_t(ignore_wt, 1, vehicle_desc_t::unknown); // first we add the any_vehicle to xrefs obj_for_xref( obj_vehicle, "any", vehicle_desc_t::any_vehicle ); resolve_xrefs(); for(auto const& elem : *registered_readers) { DBG_MESSAGE("pakset_manager_t::finish_loading", "Checking %s objects...", elem.value->get_type_name()); if (!elem.value->successfully_loaded()) { dbg->warning("pakset_manager_t::finish_loading", "... failed!"); return false; } } return true; } void pakset_manager_t::clear_missing_paks() { missing_pak_names.clear(); } // store missing obj during load and their severity void pakset_manager_t::add_missing_paks( const char *name, missing_level_t level ) { if( missing_pak_names.get( name )==NOT_MISSING ) { missing_pak_names.put( strdup(name), level ); } } void pakset_manager_t::warn_if_paks_missing() { if( missing_pak_names.empty() ) { return; // everything OK } cbuffer_t msg; msg.append(""); msg.append(translator::translate("Missing pakfiles")); msg.append("\n"); cbuffer_t error_paks; cbuffer_t warning_paks; cbuffer_t paklog; paklog.append( "\n" ); for(auto const& i : missing_pak_names) { if (i.value <= MISSING_ERROR) { error_paks.append(translator::translate(i.key)); error_paks.append("
\n"); paklog.append( i.key ); paklog.append("\n" ); } else { warning_paks.append(translator::translate(i.key)); warning_paks.append("
\n"); } } if( error_paks.len()>0 ) { msg.append("

"); msg.append(translator::translate("Pak which may cause severe errors:")); msg.append("


\n"); msg.append("
\n"); msg.append( error_paks ); msg.append("
\n"); dbg->warning( "The following paks are missing and may cause errors", paklog ); } if( warning_paks.len()>0 ) { msg.append("

"); msg.append(translator::translate("Pak which may cause visual errors:")); msg.append("


\n"); msg.append("
\n"); msg.append( warning_paks ); msg.append("
\n"); } help_frame_t *win = new help_frame_t(); win->set_text( msg ); create_win(win, w_info, magic_pakset_info_t); } static bool read_node_info(obj_node_info_t& node, FILE* const f, uint32 const version) { char data[EXT_OBJ_NODE_INFO_SIZE]; if (fread(data, OBJ_NODE_INFO_SIZE, 1, f) != 1) { return false; } char *p = data; node.type = decode_uint32(p); node.nchildren = decode_uint16(p); node.size = decode_uint16(p); // can have larger records if (version != COMPILER_VERSION_CODE_11 && node.size == LARGE_RECORD_SIZE) { if (fread(p, sizeof(data) - OBJ_NODE_INFO_SIZE, 1, f) != 1) { return false; } node.size = decode_uint32(p); } return true; } bool pakset_manager_t::read_nodes(FILE *fp, obj_desc_t *&data, int node_depth, uint32 version) { obj_node_info_t node; if (!read_node_info(node, fp, version)) { return false; } obj_reader_t *reader = registered_readers->get(static_cast(node.type)); if(reader) { //dbg->debug("pakset_manager_t::read_nodes", "Reading %.4s-node of length %d with '%s'", reinterpret_cast(&node.type), node.size, reader->get_type_name()); data = reader->read_node(fp, node); if (!data) { return false; } if (node.nchildren != 0) { data->children = new obj_desc_t *[node.nchildren]; for (int i = 0; i < node.nchildren; i++) { if (!read_nodes(fp, data->children[i], node_depth + 1, version)) { // Note: cannot delete siblings of data->children[i], since equal images point to the same desc delete data; // data->children is delete[]'d by the destructor data = NULL; return false; } } } //DBG_DEBUG("obj_reader_t","registering with '%s'", reader->get_type_name()); if(node_depth<2 || node.type!=obj_cursor) { // since many buildings are with cursors that do not need registration reader->register_obj(data); } } else { // no reader found ... dbg->warning("pakset_manager_t::read_nodes", "Skipping unknown %.4s-node\n", reinterpret_cast(&node.type)); if (fseek(fp, node.size, SEEK_CUR) != 0) { return false; } for(int i = 0; i < node.nchildren; i++) { if (!skip_nodes(fp,version)) { return false; } } data = NULL; } return true; } bool pakset_manager_t::skip_nodes(FILE *fp,uint32 version) { obj_node_info_t node; if (!read_node_info(node, fp, version)) { return false; } if (fseek(fp, node.size, SEEK_CUR) != 0) { return false; } for(int i = 0; i < node.nchildren; i++) { if (!skip_nodes(fp,version)) { return false; } } return true; } void pakset_manager_t::resolve_xrefs() { slist_tpl xref_nodes; for(auto const& u : unresolved) { for(auto const& i : u.value) { obj_desc_t *obj_loaded = NULL; if (!strempty(i.key)) { if (stringhashtable_tpl* const objtype_loaded = loaded.access(u.key)) { obj_loaded = objtype_loaded->get(i.key); } } for(obj_desc_t** const x : i.value) { if (!obj_loaded && fatals.get(x)) { dbg->fatal("pakset_manager_t::resolve_xrefs", "Cannot resolve '%4.4s-%s'", &u.key, i.key); } // delete old xref-node xref_nodes.append(*x); *x = obj_loaded; } } } while (!xref_nodes.empty()) { delete xref_nodes.remove_first(); } loaded.clear(); unresolved.clear(); fatals.clear(); } void pakset_manager_t::obj_for_xref(obj_type type, const char *name, obj_desc_t *data) { stringhashtable_tpl *objtype_loaded = loaded.access(type); if(!objtype_loaded) { loaded.put(type); objtype_loaded = loaded.access(type); } objtype_loaded->remove(name); objtype_loaded->put(name, data); } void pakset_manager_t::xref_to_resolve(obj_type type, const char *name, obj_desc_t **dest, bool fatal) { stringhashtable_tpl< slist_tpl > *typeunresolved = unresolved.access(type); if(!typeunresolved) { unresolved.put(type); typeunresolved = unresolved.access(type); } slist_tpl *list = typeunresolved->access(name); if(!list) { typeunresolved->put(name); list = typeunresolved->access(name); } list->insert(dest); if(fatal) { fatals.put(dest, 1); } } void pakset_manager_t::doubled(const char *what, const char *name) { doublettes.append( (std::string)what+"::"+name+"
" ); } simutrans-124.3/src/simutrans/dataobj/pakset_manager.h000066400000000000000000000074411474050137200231330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_PAKSET_MANAGER_H #define DATAOBJ_PAKSET_MANAGER_H #include "../descriptor/objversion.h" #include "../tpl/inthashtable_tpl.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/ptrhashtable_tpl.h" class obj_desc_t; class obj_reader_t; /// Missing things during loading: /// factories, vehicles, roadsigns or catenary may be severe enum missing_level_t { NOT_MISSING = 0, MISSING_FACTORY = 1, MISSING_VEHICLE = 2, MISSING_SIGN = 3, MISSING_WAYOBJ = 4, MISSING_ERROR = 4, MISSING_BRIDGE, MISSING_BUILDING, MISSING_WAY }; class pakset_manager_t { /// table of registered obj readers sorted by id typedef inthashtable_tpl obj_map_t; static obj_map_t *registered_readers; // // object addresses needed for resolving xrefs later // - stored in a hash table with type and name // static inthashtable_tpl > loaded; typedef inthashtable_tpl > > unresolved_map_t; static unresolved_map_t unresolved; static ptrhashtable_tpl fatals; /// Read a descriptor node. /// @param fp File to read from /// @param[out] data If reading is successful, contains descriptor for the object, else NULL. /// @param register_nodes Nesting level for desc-nodes, should normally be 0 /// @param version File format version static bool read_nodes(FILE *fp, obj_desc_t *&data, int register_nodes, uint32 version); static bool skip_nodes(FILE *fp, uint32 version); static std::string doublettes; static std::string overlaid_warning; static stringhashtable_tpl missing_pak_names; public: static void register_reader(obj_reader_t *reader); /// Loads pakset data from env_t::pak_dir, and also from env_t::user_dir/addons/env_t::pak_name if @p load_addons is true static void load_pakset(bool load_addons); /// Only for single files, must take care of all the cleanup/registering matrix themselves static bool load_pak_file(const std::string &filename); /// special error handling for double objects static void doubled(const char *what, const char *name); static void clear_missing_paks(); /// For warning, when stuff had to be removed/replaced /// level must be >=1 (1: factory, 2: vehicles, >=4: not so important) /// may be refined later static void add_missing_paks(const char *name, missing_level_t critical_level); // Display and log a warning if there are missing paks after loading a saved game static void warn_if_paks_missing(); static void xref_to_resolve(obj_type type, const char *name, obj_desc_t **dest, bool fatal); static void obj_for_xref(obj_type type, const char *name, obj_desc_t *data); // Warnings for doubled objects // Message sent when doubled objects were loaded static const char* get_doubled_warning_message(); // Return true if doubled objects were loaded static bool needs_doubled_warning_message() { return !overlaid_warning.empty(); } // Open a window to display the full warning static void open_doubled_warning_window(); private: /** * Loads all pak files from a directory and its subdirectories, displaying a progress bar if the display is initialized. * @param path Directory to be scanned for PAK files * @param load_addons true to also load paks from subdirectories named "addons" * @param message Label to show over the progress bar */ static bool load_paks_from_directory(const std::string &path, bool load_addons, const char *message); static bool finish_loading(); static bool had_overlaid() { return !doublettes.empty(); } static void clear_overlaid() { doublettes.clear(); } static std::string get_overlaid() { return doublettes; } static void resolve_xrefs(); }; #endif simutrans-124.3/src/simutrans/dataobj/powernet.cc000066400000000000000000000045431474050137200221530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "powernet.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t netlist_mutex = PTHREAD_MUTEX_INITIALIZER; #endif extern const uint32 POWER_TO_MW; // defined in leitung2 // maximum possible limit is (1 << (63 - FRACTION_PRECISION)) const uint64 powernet_t::max_capacity = (uint64)4000000 << POWER_TO_MW; // (4 TW) const uint8 powernet_t::FRACTION_PRECISION = 16; slist_tpl powernet_t::powernet_list; void powernet_t::new_world() { while(!powernet_list.empty()) { powernet_t *net = powernet_list.remove_first(); delete net; } } void powernet_t::step_all(uint32 delta_t) { for(powernet_t* const p : powernet_list) { p->step(delta_t); } } powernet_t::powernet_t() { #ifdef MULTI_THREAD pthread_mutex_lock( &netlist_mutex ); #endif powernet_list.insert( this ); #ifdef MULTI_THREAD pthread_mutex_unlock( &netlist_mutex ); #endif power_supply = 0; power_demand = 0; norm_demand = 0 << FRACTION_PRECISION; norm_supply = 0 << FRACTION_PRECISION; } powernet_t::~powernet_t() { #ifdef MULTI_THREAD pthread_mutex_lock( &netlist_mutex ); #endif powernet_list.remove( this ); #ifdef MULTI_THREAD pthread_mutex_unlock( &netlist_mutex ); #endif } /** * Computes a normalized supply/demand value. * If demand fully satisfies supply or supply is 0 then output is 1. */ sint32 compute_norm_sd(uint64 const demand, uint64 const supply) { // compute demand factor if( (demand >= supply) || (supply == 0) ) { return (sint32)1 << powernet_t::FRACTION_PRECISION; } else { return (sint32)((demand << powernet_t::FRACTION_PRECISION) / supply); } } void powernet_t::step(uint32 delta_t) { if( delta_t==0 ) { return; } // get limited values uint64 const supply = get_supply(); uint64 const demand = get_demand(); // compute normalized demand norm_demand = compute_norm_sd(demand, supply); norm_supply = compute_norm_sd(supply, demand); } /** * Clamps a power value to be within the maximum capacity. */ uint64 clamp_power(uint64 const power) { return power > powernet_t::max_capacity ? powernet_t::max_capacity : power; } uint64 powernet_t::get_supply() const { return clamp_power(power_supply); } uint64 powernet_t::get_demand() const { return clamp_power(power_demand); } simutrans-124.3/src/simutrans/dataobj/powernet.h000066400000000000000000000051051474050137200220100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_POWERNET_H #define DATAOBJ_POWERNET_H #include "../simtypes.h" #include "../tpl/slist_tpl.h" /** @file powernet.h Data structure to manage a net of powerlines - a powernet */ /** * Data class for power networks. A two phase queue to store * and hand out power. */ class powernet_t { public: /** * Max power capacity of each network. * Avoids possible overflows while providing a human friendly number. */ static const uint64 max_capacity; // number of fractional bits for network load values static const uint8 FRACTION_PRECISION; /** * Must be called when a new map is started or loaded. Clears the table of networks. */ static void new_world(); /// Steps all powernets static void step_all(uint32 delta_t); private: static slist_tpl powernet_list; // Network power supply. uint64 power_supply; // Network power demand. uint64 power_demand; // Computed normalized demand. sint32 norm_demand; // Computed normalized supply. sint32 norm_supply; // Just transfers power demand and supply to current step void step(uint32 delta_t); public: powernet_t(); ~powernet_t(); uint64 get_max_capacity() const { return max_capacity; } /** * Add power supply for next step. */ void add_supply(const uint32 p) { power_supply += (uint64)p; } /** * Subtract power supply for next step. */ void sub_supply(const uint32 p) { power_supply -= (uint64)p; } /** * Get the total power supply of the network. */ uint64 get_supply() const; /** * Add power demand for next step. */ void add_demand(const uint32 p) { power_demand += (uint64)p; } /** * Subtract power demand for next step. */ void sub_demand(const uint32 p) { power_demand -= (uint64)p; } /** * Get the total power demand of the network. */ uint64 get_demand() const; /** * Return the normalized value of demand in the network. * Will have a logical value between 0 (no demand) and 1 (all supply consumed). * Will have a logical value of 0 when no supply is present. * Return value is fixed point with FRACTION_PRECISION fractional bits. */ sint32 get_normal_demand() const { return norm_demand; } /** * Return the normalized value of supply in the network. * Will have a logical value between 0 (no supply) and 1 (all demand supplied). * Will have a logical value of 0 when no demand is present. * Return value is fixed point with FRACTION_PRECISION fractional bits. */ sint32 get_normal_supply() const { return norm_supply; } }; #endif simutrans-124.3/src/simutrans/dataobj/records.cc000066400000000000000000000075371474050137200217570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "records.h" #include "loadsave.h" #include "translator.h" #include "../player/simplay.h" #include "../simcolor.h" #include "../simmesg.h" #include "../simconvoi.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "../vehicle/vehicle.h" #include "../macros.h" void records_t::speed_record_t::rdwr(loadsave_t* f) { f->rdwr_long(speed); f->rdwr_long(year_month); pos.rdwr(f); f->rdwr_byte(player_nr); if (f->is_loading()) { // for now it is not saved cnv = convoihandle_t(); } f->rdwr_str(name, lengthof(name)); } void records_t::rdwr(loadsave_t* f) { max_rail_speed.rdwr(f); max_monorail_speed.rdwr(f); max_maglev_speed.rdwr(f); max_narrowgauge_speed.rdwr(f); max_road_speed.rdwr(f); max_ship_speed.rdwr(f); max_air_speed.rdwr(f); } sint32 records_t::get_record_speed( waytype_t w ) const { switch(w) { case road_wt: return max_road_speed.speed; case track_wt: case tram_wt: return max_rail_speed.speed; case monorail_wt: return max_monorail_speed.speed; case maglev_wt: return max_maglev_speed.speed; case narrowgauge_wt: return max_narrowgauge_speed.speed; case water_wt: return max_ship_speed.speed; case air_wt: return max_air_speed.speed; default: return 0; } } void records_t::clear_speed_records() { max_road_speed.speed = 0; max_rail_speed.speed = 0; max_monorail_speed.speed = 0; max_maglev_speed.speed = 0; max_narrowgauge_speed.speed = 0; max_ship_speed.speed = 0; max_air_speed.speed = 0; } void records_t::notify_record( convoihandle_t cnv, sint32 max_speed, koord3d k, uint32 current_month ) { speed_record_t *sr = NULL; switch (cnv->front()->get_waytype()) { case road_wt: sr = &max_road_speed; break; case track_wt: case tram_wt: sr = &max_rail_speed; break; case monorail_wt: sr = &max_monorail_speed; break; case maglev_wt: sr = &max_maglev_speed; break; case narrowgauge_wt: sr = &max_narrowgauge_speed; break; case water_wt: sr = &max_ship_speed; break; case air_wt: sr = &max_air_speed; break; default: assert(0); } // avoid the case of two convois with identical max speed ... if(cnv!=sr->cnv && sr->speed+1==max_speed) { return; } // really new/faster? if(k!=sr->pos || sr->speed+1cnv = cnv; sr->speed = max_speed-1; sr->year_month = current_month; sr->pos = k; sr->player_nr = PLAYER_UNOWNED; // will be set, when accepted } else { // repeted same speed, same place sr->cnv = cnv; sr->speed = max_speed-1; sr->pos = k; // same convoi and same position if(sr->player_nr==PLAYER_UNOWNED && current_month!=sr->year_month) { // notify the world of this new record sr->speed = max_speed-1; sr->player_nr = cnv->get_owner()->get_player_nr(); tstrncpy(sr->name, cnv->get_internal_name(), lengthof(sr->name)); const char* text; switch (cnv->front()->get_waytype()) { default: NOT_REACHED case road_wt: text = "New world record for motorcars: %.1f km/h by %s."; break; case track_wt: case tram_wt: text = "New world record for railways: %.1f km/h by %s."; break; case monorail_wt: text = "New world record for monorails: %.1f km/h by %s."; break; case maglev_wt: text = "New world record for maglevs: %.1f km/h by %s."; break; case narrowgauge_wt: text = "New world record for narrowgauges: %.1f km/h by %s."; break; case water_wt: text = "New world record for ship: %.1f km/h by %s."; break; case air_wt: text = "New world record for planes: %.1f km/h by %s."; break; } cbuffer_t buf; buf.printf( translator::translate(text), speed_to_kmh(10*sr->speed)/10.0, sr->cnv->get_name() ); msg->add_message( buf, sr->pos, message_t::new_vehicle, PLAYER_FLAG|sr->player_nr ); } } } simutrans-124.3/src/simutrans/dataobj/records.h000066400000000000000000000032641474050137200216120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_RECORDS_H #define DATAOBJ_RECORDS_H #include "koord3d.h" #include "../convoihandle.h" class message_t; class player_t; class loadsave_t; /** * World record speed management. * Keeps track of the fastest vehicles in game. */ class records_t { public: records_t(message_t *_msg) : msg(_msg) {} ~records_t() {} /** Returns the current speed record for the given way type. */ sint32 get_record_speed( waytype_t w ) const; /** Posts a message that a new speed record has been set. */ void notify_record( convoihandle_t cnv, sint32 max_speed, koord3d k, uint32 current_month ); /** Resets all speed records. */ void clear_speed_records(); void rdwr(loadsave_t* f); private: // Destination for world record notifications. message_t *msg; /** * Class representing a word speed record. */ class speed_record_t { public: convoihandle_t cnv; char name[128]; sint32 speed; koord3d pos; sint8 player_nr; // Owner uint32 year_month; speed_record_t() : cnv(), speed(0), pos(koord3d::invalid), player_nr(PLAYER_UNOWNED), year_month(0) { name[0] = 0; } void rdwr(loadsave_t* f); }; /// World rail speed record speed_record_t max_rail_speed; /// World monorail speed record speed_record_t max_monorail_speed; /// World maglev speed record speed_record_t max_maglev_speed; /// World narrowgauge speed record speed_record_t max_narrowgauge_speed; /// World road speed record speed_record_t max_road_speed; /// World ship speed record speed_record_t max_ship_speed; /// World air speed record speed_record_t max_air_speed; }; #endif simutrans-124.3/src/simutrans/dataobj/rect.cc000066400000000000000000000057771474050137200212570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "rect.h" rect_t::rect_t() : origin(0, 0), size(0, 0) { } rect_t::rect_t(koord const origin, koord const size) : origin(origin), size(size) { } rect_t::rect_t(koord const origin, sint16 const x, sint16 const y) : origin(origin), size(x, y) { } size_t rect_t::fragment_difference(rect_t const &remove, rect_t *const result, size_t const result_length) const { if (result_length < rect_t::MAX_FRAGMENT_DIFFERENCE_COUNT) { assert("rect_t::fragment_difference : attempting to fragment when space in result array is less than MAX_FRAGMENT_DIFFERENCE_COUNT"); } rect_t internal_remove = remove; internal_remove.mask(*this); rect_t *fragment = result; if (internal_remove == *this) { // area subset of remove so nothing returned } else if(internal_remove.has_no_area()) { // no overlap so entire area unchanged *fragment = *this; fragment++; } else { // partial overlap so fragmentation occurs koord const internal_remove_extent = internal_remove.origin + internal_remove.size; koord const extent = origin + size; if (origin.y < internal_remove.origin.y) { // fragment at bottom of remove rect fragment->origin = origin; fragment->size.x = size.x; fragment->size.y = internal_remove.origin.y - origin.y; fragment++; } if (origin.x < internal_remove.origin.x) { // fragment at left of remove rect fragment->origin.x = origin.x; fragment->origin.y = internal_remove.origin.y; fragment->size.x = internal_remove.origin.x - origin.x; fragment->size.y = internal_remove.size.y; fragment++; } if (extent.x > internal_remove_extent.x) { // fragment at right of remove rect fragment->origin.x = internal_remove_extent.x; fragment->origin.y = internal_remove.origin.y; fragment->size.x = extent.x - internal_remove_extent.x; fragment->size.y = internal_remove.size.y; fragment++; } if (extent.y > internal_remove_extent.y) { // fragment at top of remove rect fragment->origin.x = origin.x; fragment->origin.y = internal_remove_extent.y; fragment->size.x = size.x; fragment->size.y = extent.y - internal_remove_extent.y; fragment++; } } return (size_t) (fragment - result); } void rect_t::mask(rect_t const &mask_rect) { koord extent = origin + size; koord const mask_extent = mask_rect.origin + mask_rect.size; if (origin.x >= mask_extent.x || extent.x <= mask_rect.origin.x || origin.y >= mask_extent.y || extent.y <= mask_rect.origin.y) { // completly masked origin = size = koord(0, 0); } else { // partially masked origin.clip_min(mask_rect.origin); extent.clip_max(mask_extent); size = extent - origin; } } bool rect_t::has_no_area() const { return size == koord(0, 0); } void rect_t::discard_area() { size = koord(0, 0); } bool rect_t::operator==(rect_t const &rhs) const { return origin == rhs.origin && size == rhs.size; } bool rect_t::operator!=(rect_t const &rhs) const { return !(*this == rhs); } simutrans-124.3/src/simutrans/dataobj/rect.h000066400000000000000000000043531474050137200211060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_RECT_H #define DATAOBJ_RECT_H #include "koord.h" #include class rect_t { public: /** * @brief Map index is prepared value. */ static size_t const MAX_FRAGMENT_DIFFERENCE_COUNT = 4; /** * @brief Origin coordinates of this rect. * * The position of the lower left corner of this rect. */ koord origin; /** * @brief Size of dimensions of this rect. * * The size of the dimensions of this rect. This is the number of elements * covered by each dimension of this rect starting from the origin. Must * only ever be greater than or equal to 0. */ koord size; public: rect_t(); rect_t(koord const origin, koord const size); rect_t(koord const origin, sint16 const x, sint16 const y); /** * @brief Fragment this rect so as to remove area from another rect. * * Fragments this rect such that the resulting rects cover all area * contained by this rect that is not contained in the remove rect. The * returned value is the number of valid rect elements in the result array * that make up the requested area. Result length specifies the space * available in the result array to store fragmented rects and must be at * least MAX_FRAGMENT_DIFFERENCE_COUNT long. The fragmentation is baised * towards wide rects. */ size_t fragment_difference(rect_t const &remove, rect_t *const result, size_t const result_length) const; /** * @brief Mask part of this rect using a masking rect. * * Transforms this rect into the rect containing the intersection area * between this rect and the mask rect. Useful to clamp rects to map bounds. */ void mask(rect_t const &mask_rect); /** * @brief Returns true if this rect represents no area. * * Returns true of the size of area is 0. Such rects can occur after masking * operations or as place holder rects representing no map area. */ bool has_no_area() const; /** * @brief discard the current area of the rect. * * Set the size of this rect to 0. Useful to invalidate a rect. The origin * is not changed. */ void discard_area(); bool operator==(rect_t const &rhs) const; bool operator!=(rect_t const &rhs) const; }; #endif simutrans-124.3/src/simutrans/dataobj/ribi.cc000066400000000000000000000267471474050137200212470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../simconst.h" #include "ribi.h" #include "koord.h" #include "koord3d.h" // since we have now a dummy function instead an array const ribi_t::_nesw ribi_t::nesw;; // same like the layouts of buildings const ribi_t::ribi ribi_t::layout_to_ribi[4] = { south, east, north, west }; const int ribi_t::flags[16] = { 0, // none single | straight_ns, // north single | straight_ew, // east bend | twoway, // north-east single | straight_ns, // south straight_ns | twoway, // north-south bend | twoway, // south-east threeway, // north-south-east single | straight_ew, // west bend | twoway, // north-west straight_ew | twoway, // east-west threeway, // north-east-west bend | twoway, // south-west threeway, // north-south-west threeway, // south-east-west threeway, // all }; const ribi_t::ribi ribi_t::backwards[16] = { all, // none south, // north west, // east southwest, // north-east north, // south northsouth, // north-south northwest, // south-east west, // north-south-east east, // west southeast, // north-west eastwest, // east-west south, // north-east-west northeast, // south-west east, // north-south-west north, // south-east-west none // all }; const ribi_t::ribi ribi_t::doppelr[16] = { none, // none northsouth, // north eastwest, // east none, // north-east northsouth, // south northsouth, // north-south none, // south-east none, // north-south-east eastwest, // west none, // north-west eastwest, // east-west none, // north-east-west none, // south-west none, // north-south-west none, // south-east-west none // all }; static const ribi_t::ribi from_hang[81] = { ribi_t::none, // ribi_t::none:flat ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::south, // 4:north single height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::south, // 8:north doubles height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::east, // 12:west single height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::east, // 24:west doubles height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::west, // 28:east single height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::north, // 36:south single height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::west, // 56:east doubles height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::north, // 72:south doubles height slope ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none, ribi_t::none // 80:all of the above }; const int slope_t::flags[81] = { way_ns | way_ew, // slope 0 # flat straight ns|ew 0, // slope 1 # sw1 doubles, // slope 2 # sw2 0, // slope 3 # se1 way_ns | single, // slope 4 # se1,sw1 straight ns doubles, // slope 5 # se1,sw2 doubles, // slope 6 # se2 doubles, // slope 7 # se2,sw1 way_ns | single | doubles, // slope 8 # se2,sw2 straight ns2 0, // slope 9 # ne1 0, // slope 10 # ne1, sw1 doubles, // slope 11 # ne1, sw2 way_ew | single, // slope 12 # ne1,se1 straight ew 0, // slope 13 # ne1,se1,sw1 doubles, // slope 14 # ne1,se1,sw2 doubles, // slope 15 # ne1,se2 doubles, // slope 16 # ne1,se2,sw1 doubles, // slope 17 # ne1,se2,sw2 doubles, // slope 18 # ne2 doubles, // slope 19 # ne2, sw1 doubles, // slope 20 # ne2, sw2 doubles, // slope 21 # ne2,se1 doubles, // slope 22 # ne2,se1,sw1 doubles, // slope 23 # ne2,se1,sw2 way_ew | single | doubles, // slope 24 # ne2,se2 straight ew2 doubles, // slope 25 # ne2,se2,sw1 doubles, // slope 26 # ne2,se2,sw2 0, // slope 27 # nw1 way_ew | single, // slope 28 # nw1, sw1 straight ew doubles, // slope 29 # nw1, sw2 0, // slope 30 # nw1, se1 0, // slope 31 # nw1, se1,sw1 doubles, // slope 32 # nw1, se1,sw2 doubles, // slope 33 # nw1, se2 doubles, // slope 34 # nw1, se2,sw1 doubles, // slope 35 # nw1, se2,sw2 way_ns | single, // slope 36 # nw1,ne1 straight ns 0, // slope 37 # nw1,ne1, sw1 doubles, // slope 38 # nw1,ne1, sw2 0, // slope 39 # nw1,ne1,se1 way_ns | way_ew | all_up, // slope 40 # nw1,ne1,se1,sw1 TODO 0 up 1 doubles | all_up, // slope 41 # nw1,ne1,se1,sw2 TODO 1 up 1 doubles, // slope 42 # nw1,ne1,se2 doubles | all_up, // slope 43 # nw1,ne1,se2,sw1 TODO 3 up 1 way_ns | single | doubles | all_up, // slope 44 # nw1,ne1,se2,sw2 TODO ns 4 up 1 doubles, // slope 45 # nw1,ne2 doubles, // slope 46 # nw1,ne2, sw1 doubles, // slope 47 # nw1,ne2, sw2 doubles, // slope 48 # nw1,ne2,se1 doubles | all_up, // slope 49 # nw1,ne2,se1,sw1 TODO 9 up 1 doubles | all_up, // slope 50 # nw1,ne2,se1,sw2 TODO 10 up 1 doubles, // slope 51 # nw1,ne2,se2 way_ew | single | doubles | all_up, // slope 52 # nw1,ne2,se2,sw1 TODO ew 12 up 1 doubles | all_up, // slope 53 # nw1,ne2,se2,sw2 TODO 13 up 1 doubles, // slope 54 # nw2 doubles, // slope 55 # nw2, sw1 way_ew | single | doubles, // slope 56 # nw2, sw2 straight ew2 doubles, // slope 57 # nw2, se1 doubles, // slope 58 # nw2, se1,sw1 doubles, // slope 59 # nw2, se1,sw2 doubles, // slope 60 # nw2, se2 doubles, // slope 61 # nw2, se2,sw1 doubles, // slope 62 # nw2, se2,sw2 doubles, // slope 63 # nw2,ne1 doubles, // slope 64 # nw2,ne1, sw1 doubles, // slope 65 # nw2,ne1, sw2 doubles, // slope 66 # nw2,ne1,se1 doubles | all_up, // slope 67 # nw2,ne1,se1,sw1 TODO 27 up 1 way_ew | single | doubles | all_up, // slope 68 # nw2,ne1,se1,sw2 TODO ew 28 up 1 doubles, // slope 69 # nw2,ne1,se2 doubles | all_up, // slope 70 # nw2,ne1,se2,sw1 TODO 30 up 1 doubles | all_up, // slope 71 # nw2,ne1,se2,sw2 TODO 31 up 1 way_ns | single | doubles, // slope 72 # nw2,ne2 straight ns2 doubles, // slope 73 # nw2,ne2, sw1 doubles, // slope 74 # nw2,ne2, sw2 doubles, // slope 75 # nw2,ne2,se1 way_ns | single | doubles | all_up, // slope 76 # nw2,ne2,se1,sw1 TODO ns 36 up 1 doubles | all_up, // slope 77 # nw2,ne2,se1,sw2 TODO 37 up 1 doubles, // slope 78 # nw2,ne2,se2 doubles | all_up, // slope 79 # nw2,ne2,se2,sw1 TODO 39 up 1 doubles | way_ns | way_ew | all_up // slope 80 # nw2,ne2,se2,sw2 TODO 0 up 2 }; const slope_t::type slope_from_ribi[16] = { 0, slope_t::south, slope_t::west, 0, slope_t::north, 0, 0, 0, slope_t::east, 0, 0, 0, 0, 0, 0, 0 }; const ribi_t::dir ribi_t::dirs[16] = { dir_invalid, // none dir_north, // north dir_east, // east dir_northeast, // north-east dir_south, // south dir_invalid, // north-south dir_southeast, // south-east dir_invalid, // north-south-east dir_west, // west dir_northwest, // north-west dir_invalid, // east-west dir_invalid, // north-east-west dir_southwest, // south-west dir_invalid, // north-south-west dir_invalid, // south-east-west dir_invalid // all }; ribi_t::ribi ribi_type(slope_t::type hang) // north slope -> south, ... ! { return from_hang[hang]; } ribi_t::ribi ribi_typ_intern(sint16 dx, sint16 dy) { ribi_t::ribi ribi = ribi_t::none; if(dx<0) { ribi |= ribi_t::west; } else if(dx>0) { ribi |= ribi_t::east; } if(dy<0) { ribi |= ribi_t::north; } else if(dy>0) { ribi |= ribi_t::south; } return ribi; } ribi_t::ribi ribi_type(const koord& dir) { return ribi_typ_intern(dir.x, dir.y); } ribi_t::ribi ribi_type(const koord3d& dir) { return ribi_typ_intern(dir.x, dir.y); } /** * check, if two directions are orthogonal * works with diagonals too */ bool ribi_t::is_perpendicular(ribi x, ribi y) { // for straight direction x use doppelr lookup table if(is_straight(x)) { return (doppelr[x] | doppelr[y]) == all; } // now diagonals (more tricky) if(x!=y) { return ((x-y)%3)==0; } // ok, then they are not orthogonal return false; } sint16 get_sloping_upwards(const slope_t::type slope, const ribi_t::ribi from) { // slope upwards relative to direction 'from' const slope_t::type from_slope = slope_type(from); if (from_slope == slope) { return 1; } else if (2*from_slope == slope) { return 2; } return 0; } slope_t::type slope_type(koord dir) { if(dir.x == 0) { if(dir.y < 0) { // north direction -> south slope return slope_t::south; } if(dir.y > 0) { return slope_t::north; // south direction -> north slope } } if(dir.y == 0) { if(dir.x < 0) { return slope_t::east; // west direction -> east slope } if(dir.x > 0) { return slope_t::west; // east direction -> west slope } } return slope_t::flat; // ??? } slope_t::type slope_type(ribi_t::ribi r) { return slope_from_ribi[r]; } simutrans-124.3/src/simutrans/dataobj/ribi.h000066400000000000000000000255631474050137200211040ustar00rootroot00000000000000 /* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_RIBI_H #define DATAOBJ_RIBI_H #include "../simtypes.h" #include "../simconst.h" #include "../simdebug.h" class koord; class koord3d; /** * Slopes of tiles. */ class slope_t { /// Static lookup table static const int flags[81]; /// Named constants for the flags table enum { doubles = 1 << 0, ///< two-height difference slopes way_ns = 1 << 1, ///< way possible in north-south direction way_ew = 1 << 2, ///< way possible in east-west direction single = 1 << 3, ///< way possible all_up = 1 << 4 ///< all corners raised }; public: typedef sint8 type; /** * Named constants for special cases. */ enum _type { flat = 0, northwest = 27, ///< NW corner northeast = 9, ///< NE corner southeast = 3, ///< SE corner southwest = 1, ///< SW corner north = slope_t::southeast+slope_t::southwest, ///< North slope west = slope_t::northeast+slope_t::southeast, ///< West slope east = slope_t::northwest+slope_t::southwest, ///< East slope south = slope_t::northwest+slope_t::northeast, ///< South slope all_up_one = slope_t::southwest+slope_t::southeast+slope_t::northeast+slope_t::northwest, ///all corners 1 high all_up_two = slope_t::all_up_one * 2, ///all corners 2 high raised = all_up_two, ///< special meaning: used as slope of bridgeheads and in terraforming tools (keep for compatibility) max_number = all_up_two }; /* * Macros to access the height of the 4 corners: */ #define corner_sw(i) ((i)%slope_t::southeast) // sw corner #define corner_se(i) (((i)/slope_t::southeast)%slope_t::southeast) // se corner #define corner_ne(i) (((i)/slope_t::northeast)%slope_t::southeast) // ne corner #define corner_nw(i) ((i)/slope_t::northwest) // nw corner #define encode_corners(sw, se, ne, nw) ( (sw) * slope_t::southwest + (se) * slope_t::southeast + (ne) * slope_t::northeast + (nw) * slope_t::northwest ) #define is_one_high(i) (i & 7) // quick method to know whether a slope is one high - relies on two high slopes being divisible by 8 -> i&7=0 (only works for slopes with flag single) /// Compute the slope opposite to @p x. Returns flat if @p x does not allow ways on it. static type opposite(type x) { return is_single(x) ? (is_one_high(x) ? (slope_t::all_up_one - x) : (slope_t::all_up_two - x)) : flat; } /// Rotate. static type rotate90(type x) { return ( ( (x % slope_t::southeast) * slope_t::northwest ) + ( ( x - (x % slope_t::southeast) ) / slope_t::southeast ) ); } /// Returns true if @p x has all corners raised. static bool is_all_up(type x) { return (flags[x] & all_up)>0; } /// Returns maximal height difference between the corners of this slope. static uint8 max_diff(type x) { return (x!=0)+(flags[x]&doubles); } /// Computes minimum height differnce between corners of @p high and @p low. static sint8 min_diff(type high, type low) { return min( min( corner_sw(high) - corner_sw(low), corner_se(high)-corner_se(low) ), min( corner_ne(high) - corner_ne(low), corner_nw(high) - corner_nw(low) ) ); } /// Returns if slope prefers certain way directions (either n/s or e/w). static bool is_single(type x) { return (flags[x] & single) != 0; } /// Returns if way can be build on this slope. static bool is_way(type x) { return (flags[x] & (way_ns | way_ew)) != 0; } /// Returns if way in n/s direction can be build on this slope. static bool is_way_ns(type x) { return (flags[x] & way_ns) != 0; } /// Returns if way in e/w direction can be build on this slope. static bool is_way_ew(type x) { return (flags[x] & way_ew) != 0; } }; /** * Old implementation of slopes: one bit per corner. * Used as bitfield to refer to specific corners of a tile * as well as for compatibility. */ struct slope4_t { /* bit-field: * Bit 0 is set if southwest corner is raised * Bit 1 is set if southeast corner is raised * Bit 2 is set if northeast corner is raised * Bit 3 is set if northwest corner is raised * * Don't get confused - the southern/southward slope has its northern corners raised * * Macros to access the height of the 4 corners for single slope: * One bit per corner */ enum _corners { corner_SW = 1 << 0, corner_SE = 1 << 1, corner_NE = 1 << 2, corner_NW = 1 << 3 }; typedef sint8 type; type value; public: explicit slope4_t(type v) : value(v) {} slope4_t(_corners c) : value(c) {} }; static inline sint8 scorner_sw(slope4_t sl) { return (sl.value & slope4_t::corner_SW) != 0; } // sw corner static inline sint8 scorner_se(slope4_t sl) { return (sl.value & slope4_t::corner_SE) != 0; } // se corner static inline sint8 scorner_ne(slope4_t sl) { return (sl.value & slope4_t::corner_NE) != 0; } // ne corner static inline sint8 scorner_nw(slope4_t sl) { return (sl.value & slope4_t::corner_NW) != 0; } // nw corner static inline slope_t::type slope_from_slope4(slope4_t sl, sint8 pak_height_factor) { return encode_corners(scorner_sw(sl) * pak_height_factor, scorner_se(sl) * pak_height_factor, scorner_ne(sl) * pak_height_factor, scorner_nw(sl) * pak_height_factor); } /** * Directions in simutrans. * ribi_t = Richtungs-Bit = Directions-Bitfield */ class ribi_t { /// Static lookup table static const int flags[16]; /// Named constants for properties of directions enum { single = 1 << 0, ///< only one bit set, way ends here straight_ns = 1 << 1, ///< contains straight n/s connection straight_ew = 1 << 2, ///< contains straight e/w connection bend = 1 << 3, ///< is a bend twoway = 1 << 4, ///< two bits set threeway = 1 << 5 ///< three bits set }; public: /** * Named constants for all possible directions. * 1=North, 2=East, 4=South, 8=West */ enum _ribi { none = 0, north = 1, east = 2, northeast = 3, south = 4, northsouth = 5, southeast = 6, northsoutheast = 7, west = 8, northwest = 9, eastwest = 10, northeastwest = 11, southwest = 12, northsouthwest = 13, southeastwest = 14, all = 15 }; typedef uint8 ribi; /** * Named constants to translate direction to image number for vehicles, signs. */ enum _dir { dir_invalid = 0, dir_south = 0, dir_west = 1, dir_southwest = 2, dir_southeast = 3, dir_north = 4, dir_east = 5, dir_northeast = 6, dir_northwest = 7 }; typedef uint8 dir; private: /// Lookup table to compute backward direction static const ribi backwards[16]; /// Lookup table ... static const ribi doppelr[16]; /// Lookup table to convert ribi to dir. static const dir dirs[16]; public: /// Table containing the four compass directions (now as function) struct _nesw { ribi operator [] ( const uint8 i ) const { return 1< ns), map all others to zero static ribi doubles(ribi x) { return doppelr[x]; } /// Backward direction for single ribi's, bitwise-NOT for all others static ribi backward(ribi x) { return backwards[x]; } /// Convert ribi to dir static dir get_dir(ribi x) { return dirs[x]; } #else #ifdef USE_GCC_POPCOUNT static uint8 get_numways(ribi x) { return (__builtin_popcount(x)); } static bool is_twoway(ribi x) { return get_numways(x) == 2; } static bool is_threeway(ribi x) { return get_numways(x) > 2; } static bool is_single(ribi x) { return get_numways(x) == 1; } #else static bool is_twoway(ribi x) { return (0x1668 >> x) & 1; } static bool is_threeway(ribi x) { return (0xE880 >> x) & 1; } static bool is_single(ribi x) { return (0x0116 >> x) & 1; } #endif static bool is_bend(ribi x) { return (0x1248 >> x) & 1; } static bool is_straight(ribi x) { return (0x0536 >> x) & 1; } static bool is_straight_ns(ribi x) { return (0x0032 >> x) & 1; } static bool is_straight_ew(ribi x) { return (0x0504 >> x) & 1; } static ribi doubles(ribi x) { return (INT64_C(0x00000A0A00550A50) >> (x * 4)) & 0x0F; } static ribi backward(ribi x) { return (INT64_C(0x01234A628951C84F) >> (x * 4)) & 0x0F; } /// Convert ribi to dir static dir get_dir(ribi x) { return (INT64_C(0x0002007103006540) >> (x * 4)) & 0x7; } #endif /** * Same as backward, but for single directions only. * Effectively does bit rotation. Avoids lookup table backwards. * @returns backward(x) for single ribis, 0 for x==0. */ static inline ribi reverse_single(ribi x) { return ((x | x<<4) >> 2) & 0xf; } /// Rotate 90 degrees to the right. Does bit rotation. static ribi rotate90(ribi x) { return ((x | x<<4) >> 3) & 0xf; } /// Rotate 90 degrees to the left. Does bit rotation. static ribi rotate90l(ribi x) { return ((x | x<<4) >> 1) & 0xf; } static ribi rotate45(ribi x) { return (is_single(x) ? x|rotate90(x) : x&rotate90(x)); } // 45 to the right static ribi rotate45l(ribi x) { return (is_single(x) ? x|rotate90l(x) : x&rotate90l(x)); } // 45 to the left }; /** * Calculate slope from directions. * Go upward on the slope: going north translates to slope_t::south. */ slope_t::type slope_type(koord dir); /** * Calculate slope from directions. * Go upward on the slope: going north translates to slope_t::south. */ slope_t::type slope_type(ribi_t::ribi); /** * Check if the slope is upwards, relative to the direction @p from. * @returns 1 for single upwards and 2 for double upwards */ sint16 get_sloping_upwards(const slope_t::type slope, const ribi_t::ribi from); /** * Calculate direction bit from coordinate differences. */ ribi_t::ribi ribi_typ_intern(sint16 dx, sint16 dy); /** * Calculate direction bit from direction. */ ribi_t::ribi ribi_type(const koord& dir); ribi_t::ribi ribi_type(const koord3d& dir); /** * Calculate direction bit from slope. * Note: slope_t::north (slope north) will be translated to ribi_t::south (direction south). */ ribi_t::ribi ribi_type(slope_t::type slope); /** * Calculate direction bit for travel from @p from to @p to. */ template ribi_t::ribi ribi_type(const K1&from, const K2& to) { return ribi_typ_intern(to.x - from.x, to.y - from.y); } #endif simutrans-124.3/src/simutrans/dataobj/route.cc000066400000000000000000000510751474050137200214500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../world/simworld.h" #include "../simintr.h" #include "../simhalt.h" #include "../obj/way/weg.h" #include "../ground/grund.h" #include "../ground/wasser.h" #include "../dataobj/marker.h" #include "../vehicle/simtestdriver.h" #include "loadsave.h" #include "route.h" #include "environment.h" #include"../utils/simrandom.h" // define USE_VALGRIND_MEMCHECK to make // valgrind aware of the memory pool for A* nodes #ifdef USE_VALGRIND_MEMCHECK #include #endif // if defined, print some profiling informations into the file //#define DEBUG_ROUTES // binary heap, the fastest #include "../tpl/binary_heap_tpl.h" #ifdef DEBUG_ROUTES #include "../sys/simsys.h" #endif void route_t::append(const route_t *r) { assert(r != NULL); const uint32 hops = r->get_count()-1; route.reserve(hops+1+route.get_count()); while (!route.empty() && back() == r->front()) { // skip identical end tiles route.pop_back(); } // then append for( unsigned int i=0; i<=hops; i++ ) { route.append(r->at(i)); } } void route_t::insert(koord3d k) { route.insert_at(0,k); } void route_t::remove_koord_from(uint32 i) { while( i+1 < get_count() ) { route.pop_back(); } } /** * Appends a straight line from the last koord3d in route to the desired target. * Will return false if failed */ bool route_t::append_straight_route(karte_t *welt, koord3d dest ) { const koord ziel=dest.get_2d(); if( !welt->is_within_limits(ziel) ) { return false; } // then try to calculate direct route koord pos = back().get_2d(); route.reserve( route.get_count()+koord_distance(pos,ziel)+2 ); DBG_MESSAGE("route_t::append_straight_route()","start from (%i,%i) to (%i,%i)",pos.x,pos.y,dest.x,dest.y); while(pos!=ziel) { // shortest way if(abs(pos.x-ziel.x)>=abs(pos.y-ziel.y)) { pos.x += (pos.x>ziel.x) ? -1 : 1; } else { pos.y += (pos.y>ziel.y) ? -1 : 1; } if(!welt->is_within_limits(pos)) { break; } route.append(welt->lookup_kartenboden(pos)->get_pos()); } DBG_MESSAGE("route_t::append_straight_route()","to (%i,%i) found.",ziel.x,ziel.y); return pos==ziel; } // node arrays route_t::ANode* route_t::nodes=NULL; uint32 route_t::MAX_STEP=0; #ifdef DEBUG bool route_t::node_in_use=false; #endif /** * find the route to an unknown location * * @param welt */ bool route_t::find_route(karte_t *welt, const koord3d start, test_driver_t *tdriver, const uint32 max_khm, uint8 start_dir, uint32 max_depth ) { bool ok = false; // check for existing koordinates const grund_t* g = welt->lookup(start); if( g == NULL ) { return false; } // some thing for the search const waytype_t wegtyp = tdriver->get_waytype(); // memory in static list ... if( nodes == NULL ) { MAX_STEP = welt->get_settings().get_max_route_steps(); nodes = new ANode[MAX_STEP]; } INT_CHECK("route 347"); // we clear it here probably twice: does not hurt ... route.clear(); // first tile is not valid?!? if( !tdriver->check_next_tile(g) ) { return false; } static binary_heap_tpl queue; GET_NODE(); #ifdef USE_VALGRIND_MEMCHECK VALGRIND_MAKE_MEM_UNDEFINED(nodes, sizeof(ANode)*MAX_STEP); #endif uint32 step = 0; ANode* tmp = &nodes[step++]; tmp->parent = NULL; tmp->gr = g; tmp->count = 0; tmp->f = 0; tmp->g = 0; tmp->dir = 0; assert(start_dir == ribi_t::all || ribi_t::is_single(start_dir) ); // start_dir is direction to start with, adjust ribi_from such that bit mask boiles down to start_dir tmp->ribi_from = ribi_t::reverse_single(start_dir) ^ 0x0f; // assert that mask in first step is equal to start_dir assert( (uint8)(~ribi_t::reverse_single(tmp->ribi_from)& 0xf) == start_dir); // nothing in lists marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y); queue.clear(); queue.insert(tmp); bool target_reached = false; do { // this is too expensive to be called each step if((step & 4095) == 0) { INT_CHECK("route 161"); } tmp = queue.pop(); const grund_t* gr = tmp->gr; if( marker.test_and_mark(gr) ) { // we were already here on a faster route, thus ignore this branch // (trading speed against memory consumption) continue; } // tile is marked as visited // already there if( tdriver->is_target( gr, tmp->parent==NULL ? NULL : tmp->parent->gr ) ) { // we added a target to the closed list: check for length target_reached = true; break; } // testing all four possible directions const ribi_t::ribi ribi = tdriver->get_ribi(gr) & ( ~ribi_t::reverse_single(tmp->ribi_from) ); for( int r=0; r<4; r++ ) { // a way goes here, and it is not marked (i.e. in the closed list) grund_t* to = NULL; if( (ribi & ribi_t::nesw[r] )!=0 // do not go backwards && koord_distance(start, gr->get_pos() + koord::nesw[r])get_neighbour(to, wegtyp, ribi_t::nesw[r]) // is connected && !marker.is_marked(to) // not already tested && tdriver->check_next_tile(to) // can be driven on && step < MAX_STEP // do not overrun nodes[] ) { // not in there or taken out => add new ANode* k = &nodes[step++]; k->parent = tmp; k->gr = to; k->count = tmp->count+1; k->f = 0; k->g = tmp->g + tdriver->get_cost(to, to->get_weg(wegtyp), max_khm, ribi_t::nesw[r]); k->ribi_from = ribi_t::nesw[r]; uint8 current_dir = ribi_t::nesw[r]; if(tmp->parent!=NULL) { current_dir |= tmp->ribi_from; if(tmp->dir!=current_dir) { k->g += 3; if(tmp->parent->dir!=tmp->dir && tmp->parent->parent!=NULL) { // discourage 90 degree turns k->g += 10; } else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) { // discourage v turns heavily k->g += 25; } } } k->dir = current_dir; // insert here queue.insert(k); } } } while( !queue.empty() && step < MAX_STEP && queue.get_count() < max_depth ); INT_CHECK("route 194"); // target reached? if(!target_reached || step >= MAX_STEP) { if( step >= MAX_STEP ) { dbg->warning("route_t::find_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,MAX_STEP); } } else { // reached => construct route route.store_at( tmp->count, tmp->gr->get_pos() ); while(tmp != NULL) { route[ tmp->count ] = tmp->gr->get_pos(); tmp = tmp->parent; } ok = !route.empty(); } RELEASE_NODE(); return ok; } ribi_t::ribi *get_next_dirs(const koord3d& gr_pos, const koord3d& ziel) { static ribi_t::ribi next_ribi[4]; if( abs(gr_pos.x-ziel.x)>abs(gr_pos.y-ziel.y) ) { next_ribi[0] = (ziel.x>gr_pos.x) ? ribi_t::east : ribi_t::west; next_ribi[1] = (ziel.y>gr_pos.y) ? ribi_t::south : ribi_t::north; } else { next_ribi[0] = (ziel.y>gr_pos.y) ? ribi_t::south : ribi_t::north; next_ribi[1] = (ziel.x>gr_pos.x) ? ribi_t::east : ribi_t::west; } next_ribi[2] = ribi_t::reverse_single( next_ribi[1] ); next_ribi[3] = ribi_t::reverse_single( next_ribi[0] ); return next_ribi; } bool route_t::intern_calc_route(karte_t *welt, const koord3d ziel, const koord3d start, test_driver_t *tdriver, const sint32 max_speed, const sint32 max_cost) { assert((get_random_mode() & SYNC_STEP_RANDOM) == 0); bool ok = false; // check for existing koordinates const grund_t *gr=welt->lookup(start); if( gr == NULL || welt->lookup(ziel) == NULL) { return false; } // we clear it here probably twice: does not hurt ... route.clear(); // first tile is not valid?!? if( !tdriver->check_next_tile(gr) ) { return false; } // some thing for the search const waytype_t wegtyp = tdriver->get_waytype(); const bool is_airplane = tdriver->get_waytype()==air_wt; const uint32 cost_upslope = tdriver->get_cost_upslope(); /* On water we will try jump point search (jps): * - If going straight do not turn, only if near an obstacle. * - If going diagonally only proceed in the two directions defining the diagonal. * Ideally, no water tile is visited twice. * Needs postprocessing to eliminate unnecessary turns. * * Reference: * Harabor D. and Grastien A. 2011. Online Graph Pruning for Pathfinding on Grid Maps. * In Proceedings of the 25th National Conference on Artificial Intelligence (AAAI), San Francisco, USA. * https://users.cecs.anu.edu.au/~dharabor/data/papers/harabor-grastien-aaai11.pdf */ const bool use_jps = tdriver->get_waytype()==water_wt; bool ziel_erreicht=false; // memory in static list ... if( nodes == NULL ) { MAX_STEP = welt->get_settings().get_max_route_steps(); // may need very much memory => configurable nodes = new ANode[MAX_STEP + 4 + 2]; } INT_CHECK("route 347"); static binary_heap_tpl queue; GET_NODE(); #ifdef USE_VALGRIND_MEMCHECK VALGRIND_MAKE_MEM_UNDEFINED(nodes, sizeof(ANode)*MAX_STEP); #endif uint32 step = 0; ANode* tmp = &nodes[step]; step ++; tmp->parent = NULL; tmp->gr = gr; tmp->f = calc_distance(start,ziel); tmp->g = 0; tmp->dir = 0; tmp->count = 0; tmp->ribi_from = ribi_t::none; tmp->jps_ribi = ribi_t::all; // nothing in lists marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y); // clear the queue (should be empty anyhow) queue.clear(); queue.insert(tmp); ANode* new_top = NULL; uint32 beat=1; do { // this is too expensive to be called each step if((beat++ & 4095) == 0) { INT_CHECK("route 161"); } if (new_top) { // this is not in closed list, no check necessary tmp = new_top; new_top = NULL; gr = tmp->gr; marker.mark(gr); } else { tmp = queue.pop(); gr = tmp->gr; if(marker.test_and_mark(gr)) { // we were already here on a faster route, thus ignore this branch // (trading speed against memory consumption) continue; } } // we took the target pos out of the closed list if( ziel == gr->get_pos() ) { ziel_erreicht = true; break; } uint32 topnode_f = !queue.empty() ? queue.front()->f : max_cost; const ribi_t::ribi way_ribi = tdriver->get_ribi(gr); // testing all four possible directions // mask direction we came from const ribi_t::ribi ribi = way_ribi & ( ~ribi_t::reverse_single(tmp->ribi_from) ) & tmp->jps_ribi; const ribi_t::ribi *next_ribi = get_next_dirs(gr->get_pos(), ziel); for(int r=0; r<4; r++) { // a way in our direction? if( (ribi & next_ribi[r])==0 ) { continue; } grund_t* to = NULL; if(is_airplane) { to = welt->lookup_kartenboden(gr->get_pos().get_2d()+koord(next_ribi[r])); } // a way goes here, and it is not marked (i.e. in the closed list) if((to || gr->get_neighbour(to, wegtyp, next_ribi[r])) && tdriver->check_next_tile(to) && !marker.is_marked(to)) { weg_t *w = to->get_weg(wegtyp); // Do not go on a tile, where a oneway sign forbids going. // This saves time and fixed the bug, that a oneway sign on the final tile was ignored. if (w && w->get_ribi_maske() && ribi_t::reverse_single(next_ribi[r]) == w->get_ribi()) { // there is a signal, and the only direction leaving the next tile // is back to our position continue; } // new values for cost g (without way it is either in the air or in water => no costs) uint32 new_g = tmp->g + (w ? tdriver->get_cost(to, w, max_speed, next_ribi[r]) : 1); // check for curves (usually, one would need the lastlast and the last; // if not there, then we could just take the last uint8 current_dir; if(tmp->parent!=NULL) { current_dir = next_ribi[r] | tmp->ribi_from; if(tmp->dir!=current_dir) { new_g += 3; if(tmp->parent->dir!=tmp->dir && tmp->parent->parent!=NULL) { // discourage 90 degree turns new_g += 10; } else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) { // discourage v turns heavily new_g += 25; } } } else { current_dir = next_ribi[r]; } uint32 dist = calc_distance( to->get_pos(), ziel ); // count how many 45 degree turns are necessary to get to target sint8 turns = 0; if (dist>1) { ribi_t::ribi to_target = ribi_type(to->get_pos(), ziel ); if (to_target && (to_target!=current_dir)) { if (ribi_t::is_single(current_dir) != ribi_t::is_single(to_target)) { to_target = ribi_t::rotate45(to_target); turns ++; } while(to_target!=current_dir) { to_target = ribi_t::rotate90(to_target); turns +=2; } if (turns>4) turns = 8-turns; } } // add 3*turns to the heuristic bound // take height difference into account when calculating distance uint32 costup = 0; if (cost_upslope) { costup = cost_upslope * max(ziel.z - to->get_vmove(next_ribi[r]), 0); } const uint32 new_f = new_g + dist + turns * 3 + costup; if (step >= MAX_STEP) { break; // Do not overrun nodes[] } // add new ANode* k = &nodes[step++]; k->parent = tmp; k->gr = to; k->g = new_g; k->f = new_f; k->dir = current_dir; k->ribi_from = next_ribi[r]; k->count = tmp->count+1; k->jps_ribi = ribi_t::all; if (use_jps && to->is_water()) { // only check previous direction plus directions not available on this tile // if going straight only check straight direction // if going diagonally check both directions that generate this diagonal // also enter all available canals and turn to get around canals if (tmp->parent!=NULL) { k->jps_ribi = ~way_ribi | current_dir | ((wasser_t*)to)->get_canal_ribi(); if (gr->is_water()) { // turn on next tile to enter possible neighbours of canal tiles k->jps_ribi |= ((const wasser_t*)gr)->get_canal_ribi(); } } } if( new_f <= topnode_f ) { // do not put in queue if the new node is the best one topnode_f = new_f; if( new_top ) { queue.insert(new_top); } new_top = k; } else { queue.insert( k ); } } } } while ( (!queue.empty() || new_top) && step < MAX_STEP && tmp->g < max_cost ); #ifdef DEBUG_ROUTES // display marked route //minimap_t::get_instance()->calc_map(); DBG_DEBUG("route_t::intern_calc_route()","steps=%i (max %i) in route, open %i, cost %u (max %u)",step,MAX_STEP,queue.get_count(),tmp->g,max_cost); #endif INT_CHECK("route 194"); // target reached? if(!ziel_erreicht || step >= MAX_STEP || tmp->g >= max_cost || tmp->parent==NULL) { if( step >= MAX_STEP ) { dbg->warning("route_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,MAX_STEP); } } else { #ifdef DEBUG sint32 best = tmp->g; #endif // reached => construct route route.store_at( tmp->count, tmp->gr->get_pos() ); while(tmp != NULL) { #ifdef DEBUG // debug heuristics if (tmp->f > best) { uint32 dist = calc_distance( tmp->gr->get_pos(), ziel); dbg->warning("route_t::intern_calc_route()", "Problem with heuristic: from %s to %s at %s, best = %d, cost = %d, heur = %d, dist = %d, turns = %d", start.get_str(), ziel.get_fullstr(), tmp->gr->get_pos().get_2d().get_str(), best, tmp->g, tmp->f, dist, tmp->f - tmp->g - dist); } #endif route[ tmp->count ] = tmp->gr->get_pos(); tmp = tmp->parent; } if (use_jps && tdriver->get_waytype()==water_wt) { postprocess_water_route(welt); } ok = true; } RELEASE_NODE(); return ok; } /* * Postprocess routes created by jump-point search. * These routes never turn when going straight. * So something like this can happen: * * >--+ * +--+ * +--> * This method tries to eliminate extra turns to make routes look more like * * >----+ * ++ * +--> */ void route_t::postprocess_water_route(karte_t *welt) { if (route.get_count() < 5) return; // direction of last straight part (and last index of straight part) ribi_t::ribi straight_ribi = ribi_type(route[0], route[1]); uint32 straight_end = 0; // search for route parts: // straight - diagonal - straight (same direction as first straight part) - diagonal // phase 0 1 2 <- postprocess after next change to diagonal uint8 phase = 0; uint32 i = 1; while( i < route.get_count()-1 ) { ribi_t::ribi ribi = ribi_type(route[i-1], route[i+1]); if (ribi_t::is_single(ribi)) { if (ribi == straight_ribi) { if (phase == 1) { // third part starts phase = 2; } else { if (phase == 0) { // still on first part straight_end = i; } } } else { // straight direction different than before - start anew phase = 0; straight_end = i; straight_ribi = ribi; } } else { if (phase < 1) { // second phase phase = 1; } else if (phase == 2) { // fourth phase // postprocess here bool ok = ribi_type(route[straight_end], route[i+1]) == ribi; // try to find straight route, which avoids one diagonal part koord3d_vector_t post; post.append( route[straight_end] ); koord3d &end = route[i]; for(uint32 j = straight_end; j < i && ok; j++) { ribi_t::ribi next = 0; koord diff = (end - post.back()).get_2d(); if (abs(diff.x)>=abs(diff.y)) { next = diff.x > 0 ? ribi_t::east : ribi_t::west; if (abs(diff.x)==abs(diff.y) && next == straight_ribi) { next = diff.y > 0 ? ribi_t::south : ribi_t::north; } } else { next = diff.y > 0 ? ribi_t::south : ribi_t::north; } koord3d pos = post.back() + koord(next); ok = false; if (grund_t *gr = welt->lookup(pos)) { if (gr->is_water()) { ok = true; post.append(pos); } } } // now substitute the new route part into the route if (ok) { for(uint32 j = straight_end; j < i && ok; j++) { route[j] = post[j-straight_end]; } // start again with the first straight part i = straight_end; } else { // set second straight part to be the first straight_end = i-1; } // start new search phase = 0; } } i++; } } /** * searches route, uses intern_calc_route() for distance between stations * handles only driving in stations by itself */ route_t::route_result_t route_t::calc_route(karte_t *welt, const koord3d ziel, const koord3d start, test_driver_t *tdriver, const sint32 max_khm, sint32 max_len ) { route.clear(); INT_CHECK("route 336"); #ifdef DEBUG_ROUTES const uint32 ms = dr_time(); #endif bool ok = intern_calc_route(welt, start, ziel, tdriver, max_khm, INT32_MAX); #ifdef DEBUG_ROUTES if(tdriver->get_waytype()==water_wt) { DBG_DEBUG("route_t::calc_route()", "route from %d,%d to %d,%d with %i steps in %u ms found.", start.x, start.y, ziel.x, ziel.y, route.get_count()-1, dr_time()-ms ); } #endif INT_CHECK("route 343"); if( !ok ) { DBG_MESSAGE("route_t::calc_route()","No route from %d,%d to %d,%d found",start.x, start.y, ziel.x, ziel.y); // no route found route.reserve(1); route.append(start); // just to be safe return no_route; } // advance so all convoi fits into a halt (only set for trains and cars) else if( max_len>1 ) { // we need a halt of course ... halthandle_t halt = welt->lookup(start)->get_halt(); if( halt.is_bound() ) { // first: find out how many tiles I am already in the station for( size_t i = route.get_count(); i-- != 0 && max_len != 0 && halt == haltestelle_t::get_halt(route[i], NULL); --max_len) { } // and now go forward, if possible if( max_len>0 ) { const uint32 max_n = route.get_count()-1; const koord3d zv = route[max_n] - route[max_n - 1]; const int ribi = ribi_type(zv); grund_t *gr = welt->lookup(start); const waytype_t wegtyp = tdriver->get_waytype(); ribi_t::ribi way_ribi = tdriver->get_ribi(gr); while( max_len>0 && ((way_ribi & ribi) != 0) && gr->get_neighbour(gr,wegtyp,ribi) && gr->get_halt()==halt && tdriver->check_next_tile(gr)) { // Do not go on a tile, where a oneway sign forbids going. // This saves time and fixed the bug, that a oneway sign on the final tile was ignored. ribi_t::ribi go_dir=gr->get_weg(wegtyp)->get_ribi_maske(); if( (ribi&go_dir)!=0 ) { break; } route.append(gr->get_pos()); max_len--; way_ribi = tdriver->get_ribi(gr); } // station too short => warning! if( max_len>0 ) { return valid_route_halt_too_short; } } } } return valid_route; } void route_t::rdwr(loadsave_t *file) { xml_tag_t r( file, "route_t" ); sint32 max_n = route.get_count()-1; file->rdwr_long(max_n); if(file->is_loading()) { koord3d k; route.clear(); route.reserve(max_n+2); for(sint32 i=0; i<=max_n; i++ ) { k.rdwr(file); route.append(k); } } else { // writing for(sint32 i=0; i<=max_n; i++) { route[i].rdwr(file); } } } simutrans-124.3/src/simutrans/dataobj/route.h000066400000000000000000000074301474050137200213060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_ROUTE_H #define DATAOBJ_ROUTE_H #include "../simdebug.h" #include "../dataobj/koord3d.h" #include "../tpl/vector_tpl.h" class karte_t; class test_driver_t; class grund_t; /** * Route, e.g. for vehicles */ class route_t { public: typedef uint16 index_t; static const index_t INVALID_INDEX = 0xFFFA; private: /** * The actual route search */ bool intern_calc_route(karte_t *w, koord3d start, koord3d ziel, test_driver_t *tdriver, const sint32 max_kmh, const sint32 max_cost); koord3d_vector_t route; // The coordinates for the vehicle route void postprocess_water_route(karte_t *welt); static inline uint32 calc_distance( const koord3d &p1, const koord3d &target ) { return koord_distance(p1, target); } public: enum route_result_t { no_route = 0, valid_route = 1, valid_route_halt_too_short = 3 }; /** * Nodes for A* or breadth-first search */ class ANode { public: ANode * parent; const grund_t* gr; sint32 f; ///< heuristic for cost to reach target sint32 g; ///< cost to reach this tile uint8 dir; ///< driving direction uint8 ribi_from; ///< we came from this direction uint16 count; ///< length of route up to here uint8 jps_ribi; ///< extra ribi mask for jump-point search /// sort nodes first with respect to f, then with respect to g inline bool operator <= (const ANode &k) const { return f==k.f ? g<=k.g : f<=k.f; } }; static ANode *nodes; static uint32 MAX_STEP; #ifdef DEBUG // a semaphore, since we only have a single version of the array in memory static bool node_in_use; static void GET_NODE() {if(node_in_use){ dbg->fatal("GET_NODE","called while list in use");} node_in_use =1; } static void RELEASE_NODE() {if(!node_in_use){ dbg->fatal("RELEASE_NODE","called while list free");} node_in_use =0; } #else static void GET_NODE() {} static void RELEASE_NODE() {} #endif const koord3d_vector_t &get_route() const { return route; } void rotate90( sint16 y_size ) { route.rotate90( y_size ); } bool is_contained(const koord3d &k) const { return route.is_contained(k); } uint32 index_of(const koord3d &k) const { return (uint32)(route.index_of(k)); } /** * @return Coordinate at index @p n. */ const koord3d& at(const uint16 n) const { return route[n]; } koord3d const& front() const { return route.front(); } koord3d const& back() const { return route.back(); } uint32 get_count() const { return route.get_count(); } bool empty() const { return route.get_count()<2; } /** * Appends the other route to ours. */ void append(const route_t *route); /** * Inserts @p k at position 0. */ void insert(koord3d k); /** * Appends position @p k. */ inline void append(koord3d k) { route.append(k); } /** * removes all tiles from the route */ void clear() { route.clear(); } /** * Removes all tiles at indices >@p i. */ void remove_koord_from(uint32 i); /** * Appends a straight line to the @p target. * Will return fals if fails */ bool append_straight_route( karte_t *w, koord3d target); /** * Finds route to a location, where @p tdriver->is_target becomes true. * * @param start * @param tdriver * @param max_khm * @param start_dir * @param max_depth is the maximum length of a route */ bool find_route(karte_t *w, const koord3d start, test_driver_t *tdriver, const uint32 max_khm, uint8 start_dir, uint32 max_depth ); /** * Calculates the route from @p start to @p target */ route_result_t calc_route(karte_t *welt, koord3d start, koord3d target, test_driver_t *tdriver, const sint32 max_speed_kmh, sint32 max_tile_len ); /** * Load/Save of the route. */ void rdwr(loadsave_t *file); }; #endif simutrans-124.3/src/simutrans/dataobj/scenario.cc000066400000000000000000001016541474050137200221140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../sys/simsys.h" #include "../simconst.h" #include "../simtypes.h" #include "../simdebug.h" #include "../player/simplay.h" #include "../world/simworld.h" #include "../simmesg.h" #include "../simmem.h" #include "../tool/simmenu.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../network/network.h" #include "../network/network_cmd_scenario.h" #include "../dataobj/schedule.h" #include "../utils/cbuffer.h" // error popup #include "../gui/simwin.h" #include "../gui/scenario_info.h" // scripting #include "../script/script.h" #include "../script/script_loader.h" #include "../script/api/api.h" #include "../script/api_param.h" #include "../script/api_class.h" #include "../script/api/api_simple.h" #include "../tpl/plainstringhashtable_tpl.h" #include "scenario.h" #include const int LOCAL_CACHE_TIME = 750; const int NETWORK_CACHE_TIME = 10000; // cache the scenario text files static plainstringhashtable_tpl cached_text_files; scenario_t::scenario_t(karte_t *w) : description_text("get_short_description"), info_text("get_info_text"), goal_text("get_goal_text"), rule_text("get_rule_text"), result_text("get_result_text"), about_text("get_about_text"), debug_text("get_debug_text") { welt = w; what_scenario = 0; script = NULL; won = false; lost = false; rdwr_error = false; need_toolbar_update = false; cached_text_files.clear(); } scenario_t::~scenario_t() { delete script; clear_rules(); cached_text_files.clear(); } const char* scenario_t::init( const char *scenario_base, const char *scenario_name_, karte_t *welt ) { this->welt = welt; scenario_name = scenario_name_; // path to scenario files cbuffer_t buf; buf.printf("%s%s/", scenario_base, scenario_name_); scenario_path = buf; // scenario script file buf.append("scenario.nut"); if (!load_script( buf )) { dbg->warning("scenario_t::init", "could not load script file %s", (const char*)buf); return "Loading scenario script failed"; } const char *err = NULL; plainstring mapfile; // load savegame if ((err = script->call_function(script_vm_t::FORCE, "get_map_file", mapfile))) { dbg->warning("scenario_t::init", "error [%s] calling get_map_file", err); return "No scenario map specified"; } // if savegame-string == "" then do not load a savegame, just attach to running game. if ( strcmp(mapfile, "") ) { // savegame location buf.clear(); buf.printf("%s%s/%s", scenario_base, scenario_name_, mapfile.c_str()); if (!welt->load( buf )) { dbg->warning("scenario_t::init", "error loading savegame %s", err, (const char*)buf); return "Could not load scenario map!"; } // set savegame name buf.clear(); buf.printf("%s.sve", scenario_name.c_str()); welt->get_settings().set_filename( strdup(buf) ); welt->type_of_generation = karte_t::SCENARIO_WORLD; // re-initialize coordinate and rotation handling script_api::coordinate_transform_t::initialize(); } script_loader_t::load_compatibility_script(script); // load translations translator::load_files_from_folder( scenario_path.c_str(), "scenario" ); cached_text_files.clear(); what_scenario = SCRIPTED; dynamic_string::CACHE_TIME = LOCAL_CACHE_TIME; // callback script->register_callback(&scenario_t::set_completion, "scenario_t_set_completed"); // register ourselves welt->set_scenario(this); welt->get_message()->clear(); welt->get_chat_message()->clear(); // set start time sint32 const time = welt->get_current_month(); welt->get_settings().set_starting_year( time / 12); welt->get_settings().set_starting_month( time % 12); // set my player number to PLAYER_UNOWNED script->set_my_player(PLAYER_UNOWNED); // now call startup function if ((err = script->call_function(script_vm_t::QUEUE, "start"))) { dbg->warning("scenario_t::init", "error [%s] calling start", err); } return NULL; } bool scenario_t::load_script(const char* filename) { delete script; // start vm script = script_loader_t::start_vm("scenario_base.nut", "script-scenario.log", scenario_path.c_str(), true); if (script == NULL) { return false; } // init strings dynamic_string::init(script); // register callback if (env_t::server) { nwc_scenario_t::init(script); } // load scenario definition if (const char* err = script->call_script(filename)) { dbg->error("scenario_t::load_script", "error [%s] calling %s", err, filename); return false; } return true; } void scenario_t::koord_sq2w(koord &k) const { script_api::coordinate_transform_t::koord_sq2w(k); } const char* scenario_t::get_forbidden_text() { static cbuffer_t buf; buf.clear(); buf.append("

Forbidden stuff:


"); for(uint pnr=0; pnr"); } } return buf; } sint32 scenario_t::forbidden_t::diff(const forbidden_t& other) const { sint32 diff = (sint32)type - (sint32)other.type; if (diff == 0) { diff = (sint32)toolnr - (sint32)other.toolnr; if (diff == 0) { // trick is waytype invalid is at end => finding also all previous waytypes first diff = (sint32)waytype - (sint32)other.waytype; if (diff == 0) { // trick is emopty hash is at end => finding also all previous hashes first diff = (sint32)parameter_hash - (sint32)other.parameter_hash; if (diff == 0 && type == forbidden_t::allow_tool_rect) { diff = pos_nw.x - other.pos_nw.x; if (diff == 0) { diff = pos_nw.y - other.pos_nw.y; if (diff == 0) { diff = (pos_nw.x - pos_se.x) * (pos_nw.y - pos_se.y) - (other.pos_nw.x - other.pos_se.x) * (other.pos_nw.y - other.pos_se.y); } } } } } } return diff; } bool scenario_t::forbidden_t::operator <(const forbidden_t &other) const { return diff(other) < 0; } bool scenario_t::forbidden_t::operator ==(const forbidden_t &other) const { bool eq = diff(other)==0; if (eq && type==forbid_tool_rect) { eq = eq && (hmin == other.hmin) && (hmax == other.hmax); eq = eq && (pos_nw == other.pos_nw); eq = eq && (pos_se == other.pos_se); } return eq; } scenario_t::forbidden_t::forbidden_t(const forbidden_t& other) : type(other.type), toolnr(other.toolnr), waytype(other.waytype), parameter_hash(other.parameter_hash), pos_nw(other.pos_nw), pos_se(other.pos_se), hmin(other.hmin), hmax(other.hmax), error(other.error) { } void scenario_t::forbidden_t::rotate90(const sint16 y_size) { switch(type) { case forbid_tool_rect: { pos_nw.rotate90(y_size); pos_se.rotate90(y_size); sint16 x = pos_nw.x; pos_nw.x = pos_se.x; pos_se.x = x; } default: ; } } uint32 scenario_t::find_first(const forbidden_t &other, uint player_nr) const { if (forbidden_tools[player_nr].empty() || *forbidden_tools[player_nr].back() < other) { // empty vector, or everything is smaller return forbidden_tools[player_nr].get_count(); } if (other < *forbidden_tools[player_nr][0]) { // everything is larger return forbidden_tools[player_nr].get_count(); } else if ( other <= *forbidden_tools[player_nr][0] ) { return 0; } // now: low < other <= high uint32 low = 0, high = forbidden_tools[player_nr].get_count()-1; while(low+1 < high) { uint32 mid = (low+high) / 2; if (*forbidden_tools[player_nr][mid] < other) { low = mid; // now low < other } else { high = mid; // now other <= high } }; // still: low < other <= high return high; } // only match type and toolnumber and return frist match (other could follow) uint32 scenario_t::find_first_type_tool_wt(const forbidden_t& other, uint player_nr) const { if (forbidden_tools[player_nr].empty()) { // empty return 0; } if(forbidden_tools[player_nr].back()->type < other.type || (forbidden_tools[player_nr].back()->type == other.type && forbidden_tools[player_nr].back()->toolnr < other.toolnr) ) { // everything is smaller return forbidden_tools[player_nr].get_count(); } if (forbidden_tools[player_nr][0]->type > other.type || (forbidden_tools[player_nr][0]->type == other.type && forbidden_tools[player_nr][0]->toolnr > other.toolnr)) { // everything is smaller return forbidden_tools[player_nr].get_count(); } else if(forbidden_tools[player_nr][0]->type == other.type && forbidden_tools[player_nr][0]->toolnr == other.toolnr ) { // first is matching return 0; } // now binary search: low < other <= high uint32 low = 0, high = forbidden_tools[player_nr].get_count() - 1; uint32 mid = high; while (low + 1 < high) { mid = (low + high) / 2; sint32 result = forbidden_tools[player_nr][mid]->diff(other); if(result<0) { low = mid; // now low < other } else if(result>0) { high = mid; // now other <= high } else { // exact match return mid; } }; // did we find something? if (forbidden_tools[player_nr][high]->toolnr == other.toolnr && forbidden_tools[player_nr][high]->type == other.type) { return high; } return forbidden_tools[player_nr].get_count(); } void scenario_t::intern_forbid(forbidden_t* test, uint player_nr, bool add_rule) { bool changed = false; forbidden_t::forbid_type type = test->type; if (test->waytype < 0) { test->waytype = 0; } bool current_add = add_rule; for (int i=0; i<1+add_rule; i++) { if(add_rule && type!=forbidden_t::forbid_tool) { if (type == forbidden_t::allow_tool_rect) { // before adding an allow rule, remove a identical forbid rule test->type = (i == 0) ? forbidden_t::forbid_tool_rect : forbidden_t::allow_tool_rect; } else if (type == forbidden_t::forbid_tool_rect) { // before adding a forbind rule, remove a identical allowed rule test->type = (i == 0) ? forbidden_t::allow_tool_rect : forbidden_t::forbid_tool_rect; } current_add = i; // first pass remove, next pass add } for (uint32 i = find_first(*test, player_nr); i < forbidden_tools[player_nr].get_count() && *forbidden_tools[player_nr][i] <= *test; i++) { if (*test == *forbidden_tools[player_nr][i]) { // entry exists already delete test; if (!current_add) { delete forbidden_tools[player_nr][i]; forbidden_tools[player_nr].remove_at(i); changed = true; } goto end; } } } // entry does not exist if (add_rule) { forbidden_tools[player_nr].insert_ordered(test, scenario_t::forbidden_t::compare); changed = true; } end: if (changed && type==forbidden_t::forbid_tool) { need_toolbar_update = true; } } void scenario_t::call_forbid_tool(forbidden_t *test, uint player_nr, bool forbid) { if (env_t::server) { // send information over network nwc_scenario_rules_t *nws = new nwc_scenario_rules_t(welt->get_sync_steps() + 1, welt->get_map_counter()); nws->rule = test; nws->forbid = forbid; nws->player_nr = player_nr; network_send_all(nws, false); } else { // directly apply intern_forbid(test, player_nr, forbid); } } void scenario_t::forbid_tool(uint8 player_nr, uint16 tool_id) { forbidden_t *test = new forbidden_t(forbidden_t::forbid_tool, tool_id, ignore_wt); call_forbid_tool(test, player_nr, true); } void scenario_t::clear_forbid_tool(uint8 player_nr, uint16 tool_id) { forbidden_t *test = new forbidden_t(forbidden_t::forbid_tool, tool_id, ignore_wt); call_forbid_tool(test, player_nr, false); } void scenario_t::forbid_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param) { forbidden_t *test = new forbidden_t(forbidden_t::forbid_tool, tool_id, wt, param); call_forbid_tool(test, player_nr, true); } void scenario_t::clear_forbid_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param) { forbidden_t *test = new forbidden_t(forbidden_t::forbid_tool, tool_id, wt, param); call_forbid_tool(test, player_nr, false); } void scenario_t::forbid_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw, koord pos_se, plainstring err) { forbid_way_tool_cube(player_nr, tool_id, wt, param, koord3d(pos_nw, -128), koord3d(pos_se, 127), err); } void scenario_t::clear_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw, koord pos_se, bool allow) { clear_way_tool_cube(player_nr, tool_id, wt, param, koord3d(pos_nw, -128), koord3d(pos_se, 127), allow); } void scenario_t::allow_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw, koord pos_se) { allow_way_tool_cube(player_nr, tool_id, wt, param, koord3d(pos_nw, -128), koord3d(pos_se, 127)); } void scenario_t::forbid_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord3d pos_nw_0, koord3d pos_se_0, plainstring err) { koord pos_nw( min(pos_nw_0.x, pos_se_0.x), min(pos_nw_0.y, pos_se_0.y)); koord pos_se( max(pos_nw_0.x, pos_se_0.x), max(pos_nw_0.y, pos_se_0.y)); sint8 hmin( min(pos_nw_0.z, pos_se_0.z) ); sint8 hmax( max(pos_nw_0.z, pos_se_0.z) ); forbidden_t *test = new forbidden_t(tool_id, wt, param, pos_nw, pos_se, hmin, hmax); test->error = err; call_forbid_tool(test, player_nr, true); } void scenario_t::clear_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord3d pos_nw_0, koord3d pos_se_0, bool allow) { koord pos_nw(min(pos_nw_0.x, pos_se_0.x), min(pos_nw_0.y, pos_se_0.y)); koord pos_se(max(pos_nw_0.x, pos_se_0.x), max(pos_nw_0.y, pos_se_0.y)); sint8 hmin(min(pos_nw_0.z, pos_se_0.z)); sint8 hmax(max(pos_nw_0.z, pos_se_0.z)); forbidden_t* test = new forbidden_t(tool_id, wt, param, pos_nw, pos_se, hmin, hmax); test->type = allow ? forbidden_t::allow_tool_rect : forbidden_t::forbid_tool_rect; call_forbid_tool(test, player_nr, false); } void scenario_t::allow_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char *param, koord3d pos_nw_0, koord3d pos_se_0) { koord pos_nw( min(pos_nw_0.x, pos_se_0.x), min(pos_nw_0.y, pos_se_0.y)); koord pos_se( max(pos_nw_0.x, pos_se_0.x), max(pos_nw_0.y, pos_se_0.y)); sint8 hmin( min(pos_nw_0.z, pos_se_0.z) ); sint8 hmax( max(pos_nw_0.z, pos_se_0.z) ); forbidden_t *test = new forbidden_t(tool_id, wt, param, pos_nw, pos_se, hmin, hmax); test->type = forbidden_t::allow_tool_rect; call_forbid_tool(test, player_nr, true); } void scenario_t::clear_rules() { for (uint pnr = 0; pnr < MAX_PLAYER_COUNT; pnr++) { clear_ptr_vector(forbidden_tools[pnr]); } need_toolbar_update = true; } // intern helper function, searches with wildcards sint32 scenario_t::matching_rule(const uint8 player_nr, const forbidden_t &test, koord3d pos ) const { if (!forbidden_tools[player_nr].empty()) { forbidden_t test_wildcard = test; test_wildcard.parameter_hash = 0; // to find any hash test_wildcard.waytype = ignore_wt; // find if there is a a wildcard matchiung tool for (uint32 i = find_first_type_tool_wt(test_wildcard, player_nr); i < forbidden_tools[player_nr].get_count(); i++) { // there is something, we need to test more forbidden_t const& f = *forbidden_tools[player_nr][i]; if (f.type != test.type || f.toolnr != test.toolnr || f.waytype > test.waytype) { // reached end of forbidden tools with this id => done break; } if (f.waytype == ignore_wt || f.waytype == test.waytype) { if (f.parameter_hash == forbidden_t::EMPTY_HASH || f.parameter_hash == test.parameter_hash) { // parameter matches too => forbidden if (f.type == forbidden_t::forbid_tool) { return i; // matching rule found } // need to match retangle if (f.pos_nw.x <= pos.x && f.pos_nw.y <= pos.y && pos.x <= f.pos_se.x && pos.y <= f.pos_se.y) { // check height if (f.hmin <= pos.z && pos.z <= f.hmax) { return i; } } } } } } return -1; } void scenario_t::clear_player_rules(uint8 player_nr) { clear_ptr_vector(forbidden_tools[player_nr]); need_toolbar_update = true; } bool scenario_t::is_tool_allowed(const player_t* player, uint16 tool_id, sint16 wt, const char* param) { if (what_scenario != SCRIPTED && what_scenario != SCRIPTED_NETWORK) { return true; } // first test the list uint8 player_nr = player ? player->get_player_nr() : PLAYER_UNOWNED; forbidden_t test(forbidden_t::forbid_tool, tool_id, wt, param); sint32 idx = matching_rule(player_nr, test, koord3d::invalid); if (idx == -1 && player_nr != PLAYER_UNOWNED) { // retry as public player player_nr = PLAYER_UNOWNED; idx = matching_rule(player_nr, test, koord3d::invalid); } if (idx >= 0) { // we found a forbidden rule const char* err = forbidden_tools[player_nr][idx]->error.c_str(); if (err == NULL) { err = ""; } return false; } // then call script if available if (what_scenario == SCRIPTED) { bool ok = true; const char* err = script->call_function(script_vm_t::FORCE, "is_tool_allowed", ok, (uint8)(player ? player->get_player_nr() : PLAYER_UNOWNED), tool_id, wt, param); return err != NULL || ok; } return true; } const char* scenario_t::is_work_allowed_here(const player_t* player, uint16 tool_id, sint16 wt, const char* param, koord3d pos) { if (what_scenario != SCRIPTED && what_scenario != SCRIPTED_NETWORK) { return NULL; } // first test for allowed tools uint8 player_nr = player ? player->get_player_nr() : PLAYER_UNOWNED; forbidden_t test(forbidden_t::allow_tool_rect, tool_id, wt, param); sint32 idx = matching_rule(player_nr, test, pos); if (idx == -1 && player_nr != PLAYER_UNOWNED) { // retry as public player player_nr = PLAYER_UNOWNED; idx = matching_rule(player_nr, test, pos); } if (idx == -1) { // not allowed => test for forbidden area player_nr = player ? player->get_player_nr() : PLAYER_UNOWNED; test.type = forbidden_t::forbid_tool; idx = matching_rule(player_nr, test, koord3d::invalid); if (idx == -1 && player_nr != PLAYER_UNOWNED) { // retry as public player player_nr = PLAYER_UNOWNED; idx = matching_rule(player_nr, test, koord3d::invalid); } if (idx >= 0) { // we found a forbidden rule const char* err = forbidden_tools[player_nr][idx]->error.c_str(); if (err == NULL) { err = ""; } return err; } // not found => test rectangles if (idx == -1) { // not found player_nr = player ? player->get_player_nr() : PLAYER_UNOWNED; test.type = forbidden_t::forbid_tool_rect; idx = matching_rule(player_nr, test, pos); if (idx == -1 && player_nr != PLAYER_UNOWNED) { // retry as public player player_nr = PLAYER_UNOWNED; idx = matching_rule(player_nr, test, pos); } if (idx >= 0) { // we found a forbidden rule const char* err = forbidden_tools[player_nr][idx]->error.c_str(); if (err == NULL) { err = ""; } return err; } } } // then call the script // cannot be done for two_click_tool_t's as they depend on routefinding, // which is done per client if (what_scenario == SCRIPTED) { koord3d start_pos = pos; bool is_drag_tool = false; bool is_ctrl = false; bool is_shift = false; uint8 player_nr = player ? player->get_player_nr() : PLAYER_UNOWNED; if(player_nr != PLAYER_UNOWNED){ if (two_click_tool_t *two_tool = dynamic_cast(welt->get_tool(player_nr))) { start_pos = two_tool->get_start_pos(); is_drag_tool = !two_tool->is_first_click(); is_ctrl = two_tool->is_ctrl_pressed(); is_shift = two_tool->is_shift_pressed(); } else if (tool_t *tool = dynamic_cast(welt->get_tool(player_nr))) { is_ctrl = tool->is_ctrl_pressed(); is_shift = tool->is_shift_pressed(); } } static plainstring msg; const char *err = script->call_function(script_vm_t::FORCE, "is_work_allowed_here", msg, player_nr, tool_id, param, pos, script_api::mytool_data_t(start_pos, is_drag_tool, is_ctrl, is_shift)); return err == NULL ? msg.c_str() : NULL; } return NULL; } const char* scenario_t::is_schedule_allowed(const player_t* player, const schedule_t* schedule) { // sanity checks if (schedule == NULL) { return ""; } if (env_t::server) { // networkgame: allowed return NULL; } // call script if (what_scenario == SCRIPTED) { static plainstring msg; const char *err = script->call_function(script_vm_t::FORCE, "is_schedule_allowed", msg, (uint8)(player ? player->get_player_nr() : PLAYER_UNOWNED), schedule); return err == NULL ? msg.c_str() : NULL; } return NULL; } const char* scenario_t::is_convoy_allowed(const player_t* player, convoihandle_t cnv, depot_t* depot) { // sanity checks if (!cnv.is_bound() || depot == NULL) { return ""; } if (env_t::server) { // networkgame: allowed return NULL; } // call script if (what_scenario == SCRIPTED) { static plainstring msg; const char *err = script->call_function(script_vm_t::FORCE, "is_convoy_allowed", msg, (uint8)(player ? player->get_player_nr() : PLAYER_UNOWNED), cnv, (obj_t*)depot); return err == NULL ? msg.c_str() : NULL; } return NULL; } bool scenario_t::is_tool_enabled(const player_t * player, uint16 tool_id, sint16 wt, const char *param) { if (what_scenario != SCRIPTED && what_scenario != SCRIPTED_NETWORK) { return true; } // then call script if available if (what_scenario == SCRIPTED) { bool ok = true; const char* err = script->call_function(script_vm_t::FORCE, "is_tool_active", ok, (uint8)(player ? player->get_player_nr() : PLAYER_UNOWNED), tool_id, wt, param); return err != NULL || ok; } return true; } const char* scenario_t::jump_to_link_executed(koord3d pos) { if (env_t::server) { // networkgame: allowed return NULL; } // call script if (what_scenario == SCRIPTED) { static plainstring msg; const char *err = script->call_function(script_vm_t::FORCE, "jump_to_link_executed", msg, pos); return err == NULL ? msg.c_str() : NULL; } return NULL; } const char* scenario_t::get_error_text() { if (script) { return script->get_error(); } return NULL; } void scenario_t::step() { if (!script) { // update texts at clients if info window open if (env_t::networkmode && !env_t::server ) { // update texts if (scenario_info_t* win = (scenario_info_t*)win_get_magic(magic_scenario_info)) { update_scenario_texts(win->get_open_tab()); } else if (win_get_magic(magic_scenario_info)) { update_scenario_texts(DESCRIPTION); } } return; } uint16 new_won = 0; uint16 new_lost = 0; // first check, whether win/loss state of any player changed for(uint32 i=0; iget_player(i); uint16 mask = 1 << i; // player exists and has not won/lost yet if (player && (((won | lost) & mask)==0)) { sint32 percentage = 0; // callback script->prepare_callback("scenario_t_set_completed", 2, i, percentage ); // call script const char *err = script->call_function(script_vm_t::QUEUE, "is_scenario_completed", percentage, i); // clear callback script->clear_pending_callback(); // script might have deleted the player player = welt->get_player(i); if (player == NULL) { continue; } // call completed? if (script_vm_t::is_call_suspended(err)) { continue; } player->set_scenario_completion(percentage); // won ? if (percentage >= 100) { new_won |= mask; } // lost ? else if (percentage < 0) { new_lost |= mask; } } } update_won_lost(new_won, new_lost); // update texts if (scenario_info_t *win = (scenario_info_t*)win_get_magic(magic_scenario_info) ) { update_scenario_texts(win->get_open_tab()); } else if (win_get_magic(magic_scenario_info)) { update_scenario_texts(DESCRIPTION); } // update toolbars if necessary if (need_toolbar_update) { tool_t::update_toolbars(); need_toolbar_update = false; // reset active tool if now forbidden // check scenario conditions for all players for(uint8 player_nr = 0; player_nr < PLAYER_UNOWNED; player_nr++) { if (player_t *player = welt->get_player(player_nr)) { tool_t *tool = welt->get_tool(player_nr); if (!is_tool_allowed(player, tool->get_id(), tool->get_waytype(), tool->get_default_param())) { welt->local_set_tool(tool_t::general_tool[TOOL_QUERY], player); } } } } } void scenario_t::new_month() { if (script) { script->call_function(script_vm_t::QUEUE, "new_month"); } } void scenario_t::new_year() { if (script) { script->call_function(script_vm_t::QUEUE, "new_year"); } } void scenario_t::update_won_lost(uint16 new_won, uint16 new_lost) { // server sends the new state to the clients if (env_t::server && (new_won | new_lost)) { nwc_scenario_t *nwc = new nwc_scenario_t(); nwc->won = new_won; nwc->lost = new_lost; nwc->what = nwc_scenario_t::UPDATE_WON_LOST; network_send_all(nwc, true); } // we are the champions if (new_won) { won |= new_won; // those are the losers new_lost = ~new_won; } if (new_lost) { lost |= new_lost; } // notify active player if ( (new_won|new_lost) & (1<get_active_player_nr()) ) { // most likely result text has changed, force update result_text.update(script, welt->get_active_player(), true); open_info_win(); } } void scenario_t::update_scenario_texts(int what) { player_t* player = welt->get_active_player(); switch (what) { case INFO: info_text.update(script, player); return; case GOAL: goal_text.update(script, player); return; case RULE: rule_text.update(script, player); return; case RESULT: result_text.update(script, player); return; case ABOUT: about_text.update(script, player); return; case SCRIPT_DEBUG: debug_text.update(script, player); return; case DESCRIPTION: description_text.update(script, player); return; case ALL: info_text.update(script, player); goal_text.update(script, player); rule_text.update(script, player); result_text.update(script, player); about_text.update(script, player); debug_text.update(script, player); description_text.update(script, player); return; } } plainstring scenario_t::load_language_file(const char* filename) { if (filename == NULL) { return "(null)"; } std::string path = scenario_path.c_str(); // try user language std::string wanted_file = path + translator::get_lang()->iso + PATH_SEPARATOR + filename; const plainstring& cached = cached_text_files.get(wanted_file.c_str()); if (cached != NULL) { // file already cached return cached; } // not cached: try to read file FILE* file = dr_fopen(wanted_file.c_str(), "rb"); if (file == NULL) { // try English file = dr_fopen((path + "en" + PATH_SEPARATOR + filename).c_str(), "rb"); } if (file == NULL) { // try scenario directory file = dr_fopen((path + filename).c_str(), "rb"); } plainstring text = ""; if (file) { fseek(file,0,SEEK_END); long len = ftell(file); if(len>0) { char* const buf = MALLOCN(char, len + 1); fseek(file,0,SEEK_SET); if (fread(buf, 1, len, file) == (size_t)len) { buf[len] = '\0'; text = buf; } free(buf); } fclose(file); } // store text to cache cached_text_files.put(wanted_file.c_str(), text); return text; } bool scenario_t::open_info_win(const char* tab) const { // pop up for the win scenario_info_t *si = (scenario_info_t*)win_get_magic(magic_scenario_info); if (si == NULL) { si = new scenario_info_t(); if (create_win(si, w_info, magic_scenario_info) < 0) { // failed return false; } } si->open_tab(tab); return true; // dummy return value } void scenario_t::rdwr(loadsave_t *file) { file->rdwr_short(what_scenario); if (file->is_version_less(111, 5)) { uint32 city_nr = 0; file->rdwr_long(city_nr); sint64 factor = 0; file->rdwr_longlong(factor); koord k(0,0); k.rdwr( file ); } if (what_scenario != SCRIPTED && what_scenario != SCRIPTED_NETWORK) { if (file->is_loading()) { what_scenario = 0; } return; } script_api::coordinate_transform_t::rdwr(file); file->rdwr_short(won); file->rdwr_short(lost); file->rdwr_str(scenario_name); // load scripts and scenario files if (what_scenario == SCRIPTED) { if (file->is_loading()) { // load persistent scenario data plainstring str; file->rdwr_str(str); dbg->warning("scenario_t::rdwr", "loaded persistent scenario data: %s", str.c_str()); if (env_t::networkmode && !env_t::server) { // client playing network scenario game: // script files are not available what_scenario = SCRIPTED_NETWORK; script = NULL; } else { // load script cbuffer_t script_filename; // assume error rdwr_error = true; // try addon directory first if (env_t::default_settings.get_with_private_paks()) { scenario_path = ( std::string("addons/") + env_t::pak_name + "scenario" + PATH_SEPARATOR + scenario_name.c_str() + "/").c_str(); script_filename.printf("%sscenario.nut", scenario_path.c_str()); rdwr_error = !load_script(script_filename); } // failed, try scenario from pakset directory if (rdwr_error) { scenario_path = (env_t::pak_dir + "scenario/" + scenario_name.c_str() + PATH_SEPARATOR).c_str(); script_filename.clear(); script_filename.printf("%sscenario.nut", scenario_path.c_str()); rdwr_error = !load_script(script_filename); } if (!rdwr_error) { script_loader_t::load_compatibility_script(script); // restore persistent data const char* err = script->eval_string(str); if (err) { dbg->warning("scenario_t::rdwr", "error [%s] evaluating persistent scenario data", err); rdwr_error = true; } // load translations translator::load_files_from_folder( scenario_path.c_str(), "scenario" ); // callback script->register_callback(&scenario_t::set_completion, "scenario_t_set_completed"); } else { dbg->warning("scenario_t::rdwr", "could not load script file %s", (const char*)script_filename); } } } else { plainstring str; script->call_function(script_vm_t::FORCEX, "save", str); dbg->warning("scenario_t::rdwr", "write persistent scenario data: %s", str.c_str()); file->rdwr_str(str); } } // load forbidden tool if (file->is_loading()) { clear_rules(); } for (uint pnr = 0; pnr < MAX_PLAYER_COUNT; pnr++) { uint32 count = forbidden_tools[pnr].get_count(); file->rdwr_long(count); for (uint32 i = 0; i < count; i++) { if (file->is_loading()) { forbidden_tools[pnr].append(new forbidden_t()); } forbidden_tools[pnr][i]->rdwr(file); } } // cached strings if (file->is_version_atleast(120, 3)) { dynamic_string::rdwr_cache(file); } if (what_scenario == SCRIPTED && file->is_loading() && !rdwr_error) { const char* err = script->call_function(script_vm_t::FORCEX, "resume_game"); if (err) { dbg->warning("scenario_t::rdwr", "error [%s] calling resume_game", err); rdwr_error = true; } } // client side of scripted game but not on a client if ( (what_scenario == SCRIPTED_NETWORK) ^ (env_t::networkmode && env_t::server==0) ) { what_scenario = 0; rdwr_error = true; } dynamic_string::CACHE_TIME = what_scenario == SCRIPTED ? LOCAL_CACHE_TIME : NETWORK_CACHE_TIME; } void scenario_t::rotate90(const sint16 y_size) { for (uint pnr = 0; pnr < MAX_PLAYER_COUNT; pnr++) { for (uint32 i = 0; i < forbidden_tools[pnr].get_count(); i++) { forbidden_tools[pnr][i]->rotate90(y_size); } } } // return percentage completed sint32 scenario_t::get_completion(int player_nr) { if ( what_scenario == 0 || player_nr < 0 || player_nr >= PLAYER_UNOWNED) { return 0; } // check if won / lost uint32 pl = player_nr; if (won & (1<get_player(player_nr); if ( what_scenario == SCRIPTED ) { // take cached value if (player) { percentage = player->get_scenario_completion(); } } else if ( what_scenario == SCRIPTED_NETWORK ) { cbuffer_t buf; buf.printf("is_scenario_completed(%d)", pl); const char *ret = dynamic_string::fetch_result((const char*)buf, NULL, NULL); percentage = ret ? atoi(ret) : 0; // cache value if (player) { player->set_scenario_completion(percentage); } } return min( 100, percentage); } bool scenario_t::set_completion(sint32 player_nr, sint32 percentage) { if ( player_nr < 0 || player_nr >= PLAYER_UNOWNED) { return false; } player_t *player = welt->get_player(player_nr); if (player == NULL) { return false; } player->set_scenario_completion(percentage - player->get_scenario_completion()); uint16 mask = 1 << player_nr; // check won/lost if (percentage < 0 && (lost & mask)==0) { update_won_lost(0, mask); } else if (percentage >= 100 && (won & mask)==0) { update_won_lost(mask, 0); } return true; } const char* scenario_t::eval_string(const char* squirrel_string) const { if (what_scenario == SCRIPTED) { return script->eval_string(squirrel_string); } return ""; } simutrans-124.3/src/simutrans/dataobj/scenario.h000066400000000000000000000406621474050137200217570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_SCENARIO_H #define DATAOBJ_SCENARIO_H /** @file scenario.h declarations for scenario interface */ #include "koord3d.h" #include "../utils/plainstring.h" #include "../utils/simstring.h" #include "../script/dynamic_string.h" #include "../dataobj/ribi.h" #include "../convoihandle.h" #include "../tool/simmenu.h" class loadsave_t; class stadt_t; class fabrik_t; class karte_t; class schedule_t; class depot_t; /** * @class scenario_t * Controls scenarios in connection to a simutrans world. * * Scenarios are scripted. In network games, only the server has access to the script, * clients will be sent some results of the script. * * Each instance of karte_t carries a non-NULL pointer to a scenario_t * thus also the need for inactive scenarios. */ class scenario_t { private: /// possible states of scenario enum scenario_state_t { INACTIVE = 0, ///< scenario inactive SCRIPTED = 7, ///< scenario active (non-network game or at server) SCRIPTED_NETWORK = 8 ///< scenario active, network game at client }; /// state of the current scenario @see scenario_state_t uint16 what_scenario; /// the world we are scripting in karte_t *welt; /// name of scenario, files are searched in scenario_path/scenario_name/... /// e.g. my_scenario plainstring scenario_name; /// path to scenario directory (relative to env_t::user_dir) /// e.g. pak/scenario/my_scenario/ plainstring scenario_path; /** * loads scenario file with the given name * @param filename name scenario script file (including .nut extension) */ bool load_script(const char* filename); /// is set, if an error occurred during loading of savegame /// e.g. re-starting of scenario failed due to script error bool rdwr_error; /// pointer to virtual machine script_vm_t *script; /// @{ /// @name Interface to forbid tools in-game /** * Struct to store information about forbidden tools * * Necessary in network games: there, the list of forbidden tools * is transferred to clients. Needed to apply conditions to e.g. way-building * tools or to have toolbars reflect allowed tools. */ struct forbidden_t { static const uint32 EMPTY_HASH=0; enum forbid_type { forbid_tool = 1, allow_tool_rect = 2, forbid_tool_rect = 3 }; forbid_type type; /// id of tool to be forbidden, as set by constructors of classes derived from /// tool_t, @see tool/simtool.h uint16 toolnr; /// waytype of tool, @see waytype_t sint16 waytype; uint32 parameter_hash; koord pos_nw, pos_se; sint8 hmin, hmax; /// error message to be displayed if user tries to work with the tool plainstring error; /// constructor: forbid tool/etc for a certain player forbidden_t(forbid_type type_=forbid_tool, uint16 toolnr_=0, sint16 waytype_= ignore_wt, const char *param_=NULL) : type(type_), toolnr(toolnr_), waytype(waytype_ < 0 ? (sint16)ignore_wt : waytype_), pos_nw(koord::invalid), pos_se(koord::invalid), hmin(-128), hmax(127), error() { if (toolnr == (GENERAL_TOOL|TOOL_SCHEDULE_INS) || toolnr == (GENERAL_TOOL | TOOL_SCHEDULE_ADD)) { // paramter is pointer to binary => not checking parameter_hash = 0; return; } parameter_hash = string_to_hash(param_)&0x7FFFFFFul; } /// constructor: forbid tool for a certain player at certain locations (and heights) forbidden_t(uint16 toolnr_, sint16 waytype_, const char *param_, koord nw, koord se, sint8 hmin_=-128, sint8 hmax_=127) : type(forbid_tool_rect), toolnr(toolnr_), waytype(waytype_ < 0 ? (sint16)ignore_wt : waytype_), pos_nw(nw), pos_se(se), hmin(hmin_), hmax(hmax_), error() { parameter_hash = string_to_hash(param_) & 0x7FFFFFFul; } // copy constructor forbidden_t(const forbidden_t&); /** * @returns difference */ sint32 diff(const forbidden_t&) const; /** * @returns if this < other, compares: type, playernr, tool, wt, parameter * DIRTY: (a <= b) && (b <= a) DOES NOT imply a == b */ bool operator <(const forbidden_t &) const; bool operator <=(const forbidden_t &other) const { return !(other < *this); } static bool compare(const forbidden_t *a, const forbidden_t *b) { return a->diff(*b) < 0; } /** * compares everything (including coordinates) * DIRTY: (a <= b) && (b <= a) DOES NOT imply a == b */ bool operator ==(const forbidden_t &other) const; /** * templated load/save support */ template void rdwr(T *file) { uint8 t = (uint8)type; file->rdwr_byte(t); type= (forbid_type)t; file->rdwr_short(toolnr); file->rdwr_short(waytype); file->rdwr_long(parameter_hash); file->rdwr_short(pos_nw.x); file->rdwr_short(pos_nw.y); file->rdwr_short(pos_se.x); file->rdwr_short(pos_se.y); file->rdwr_byte(hmin); file->rdwr_byte(hmax); file->rdwr_str(error); } void rotate90(const sint16 y_size); private: const forbidden_t& operator=(const forbidden_t&); }; /// list of forbidden tools for each player (last is all players) vector_tplforbidden_tools[MAX_PLAYER_COUNT]; /// set to true if rules changed to update toolbars, /// toolbars and active tools will be updated in next call to step() bool need_toolbar_update; /** * helper function: * * @param other given record and the player_nr to test for (or PLAYER_UNOWNED) * @param player_nr player * @returns first index i such that * forbidden_tools[i-1] < other <= forbidden_tools[i] <= other * or returns forbidden_tools.get_count() if no such index is found */ uint32 find_first(const forbidden_t &other, uint player_nr) const; /** * helper function: * * @param other given record and the player_nr to test for (or PLAYER_UNOWNED) * @param player_nr player * @returns first index i such that * that the type, toolnumber, and waytype matches (but parameter may be wrong) * or returns forbidden_tools.get_count() if no such index is found */ uint32 find_first_type_tool_wt(const forbidden_t& other, uint player_nr) const; /** * Helper function: * Puts/removes new record into/from forbidden_tools list, checks for identical entries. * Only call this method from call_forbid_tool(forbidden_t *,bool) * * @param test must be pointer to allocated memory, will be invalid after call * @param player_nr player * @param add_rule if true add rule, if false removes rule from list * @returns value 1 if added rule, and 2 deleted previous rule, return 0 on error */ void intern_forbid(forbidden_t *test, uint player_nr, bool add_rule); /** * Helper function: works on forbidden_tools directly (if not in network-mode) * or sends information over network (if at server) * * @param test must be pointer to allocated memory, will be invalid after call * @param player_nr player * @param forbid if true forbids, if false allows the record */ void call_forbid_tool(forbidden_t *test, uint player_nr, bool forbid); /// @} // internal function, returns the idx of the first matching rule of 0xFFFFFF sint32 matching_rule(const uint8 player, const forbidden_t& test, koord3d pos) const; /// bit set if player has won / lost uint16 won; uint16 lost; /// function to update the won / lost bitset /// called if this information changes for some players void update_won_lost(uint16 new_won, uint16 new_lost); public: scenario_t(karte_t *w); ~scenario_t(); /** * Initializes scripted scenario */ const char* init( const char *scenario_base, const char *scenario_name, karte_t *welt ); /** * Load file with translations. Tries to load files in the following order * (1) script_addon_path/iso/filename * (2) script_addon_path/en/filename * (3) script_path/iso/filename * * Here, iso refers to iso-abbreviation of currently active language * @return content of loaded file */ plainstring load_language_file(const char* filename); /// Load/save support void rdwr(loadsave_t *file); /// @returns true if loading succeed, false if script failed during loading bool rdwr_ok() const { return !rdwr_error; } /** * Stop scenario */ void stop() { what_scenario = INACTIVE; } /// @return true if a scenario is present bool active() const { return what_scenario != INACTIVE; } /// @return true if scenario is scripted bool is_scripted() const { return what_scenario == SCRIPTED || what_scenario == SCRIPTED_NETWORK; } /// @return true if scenario is scripted and local bool is_local() const { return what_scenario == SCRIPTED; } /** * compiles and executes given string * @returns error msg (or NULL if succeeded) */ const char* eval_string(const char* squirrel_string) const; /** * Get percentage of scenario completion. Does not call script to update this value. * On clients: call server for update via dynamic_string logic. * Returns percentage of scenario completion. * @param player_nr player * @returns percentage of scenario completion: * if >= 100 then scenario is won * if < 0 then scenario is lost */ sint32 get_completion(int player_nr); /** * Sets percentage of scenario completion. Used as callback if script call got suspended. * * @param player_nr player * @param percentage * @returns dummy return value */ bool set_completion(sint32 player_nr, sint32 percentage); void rotate90(const sint16 y_size); /** * rotate original coordinates to actual world coordinates * uses the methods in script_api */ void koord_sq2w(koord &) const; /** * Text to be displayed in the finance info window * i.e. short description of scenario */ dynamic_string description_text; /// @{ /// @name Text to be displayed in the scenario info window dynamic_string info_text; dynamic_string goal_text; dynamic_string rule_text; dynamic_string result_text; dynamic_string about_text; dynamic_string debug_text; /// @} enum {INFO=0, GOAL, RULE, RESULT, ABOUT, SCRIPT_DEBUG, DESCRIPTION, ALL=-1}; /** * Called to update the scenario texts * @see dynamic_string::update */ void update_scenario_texts(int which); /** * opens scenario info window at tab @p tab. */ bool open_info_win(const char* tab = "result") const; /** * Last error of script */ const char* get_error_text(); /** * Calls scripted is_scenario_completed. Caches this value in statistics of player_t. * Server sends update of won/lost if necessary. */ void step(); /** * Called upon month change: at 0:00 of the first day of the new month. */ void new_month(); /** * Called upon new year: at 0:00 January 1st. */ void new_year(); /// @{ /// @name Interface to forbid tools in-game /** * Forbid tool * @ingroup squirrel-scen-api * * @param player_nr number of player this rule applies to, * if this is set to MAX_PLAYER_COUNT then this acts for all players except public player * @param tool_id id of tool */ void forbid_tool(uint8 player_nr, uint16 tool_id); /** * @ingroup squirrel-scen-api * @see forbid_tool */ void clear_forbid_tool(uint8 player_nr, uint16 tool_id); /** * Forbid tool with certain waytype * @ingroup squirrel-scen-api * * @param player_nr number of player this rule applies to, * if this is set to MAX_PLAYER_COUNT then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param param */ void forbid_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param); /** * Forbid tool with certain waytype within rectangular region on the map * @ingroup squirrel-scen-api * * @param player_nr number of player this rule applies to, * if this is set to MAX_PLAYER_COUNT then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param param * @param pos_nw coordinate of north-western corner of rectangle * @param pos_se coordinate of south-eastern corner of rectangle * @param err error message presented to user when trying to apply this tool */ void forbid_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw, koord pos_se, plainstring err); /** * Forbid tool with certain waytype within cubic region on the map. * @ingroup squirrel-scen-api * * @param player_nr number of player this rule applies to, * if this is set to MAX_PLAYER_COUNT then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param param * @param pos_nw coordinate of north-western corner of cube * @param pos_se coordinate of south-eastern corner of cube * @param err error message presented to user when trying to apply this tool */ void forbid_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord3d pos_nw, koord3d pos_se, plainstring err); /** * @ingroup squirrel-scen-api * @see forbid_way_tool */ void clear_forbid_way_tool(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param); void clear_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw_0, koord pos_se_0, bool allow); /** * clear rule with certain waytype within cubic region on the map. * @ingroup squirrel-scen-api * * @param player_nr number of player this rule applies to, * if this is set to MAX_PLAYER_COUNT then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param param * @param pos_nw_0 coordinate of north-western corner of cube * @param pos_se_0 coordinate of south-eastern corner of cube * @param allow clear and allow rule (true) or clear a forbid rule (false) */ void clear_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord3d pos_nw_0, koord3d pos_se_0, bool allow); /** * Clears all rules. * @ingroup squirrel-scen-api */ void clear_rules(); /** * Clears all rules for a player selec * @ingroup squirrel-scen-api */ void clear_player_rules(uint8 player_nr); /** * @ingroup squirrel-scen-api * @see forbid_way_tool_rect */ void allow_way_tool_rect(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord pos_nw, koord pos_se); /** * @ingroup squirrel-scen-api * @see forbid_way_tool_cube */ void allow_way_tool_cube(uint8 player_nr, uint16 tool_id, waytype_t wt, const char* param, koord3d pos_nw, koord3d pos_se); /** * Toolbars/active tools need an update due to changed rules; update is done in step(). * @ingroup squirrel-scen-api */ void gui_needs_update() { need_toolbar_update = true; } /** * Checks if player can use this tool at all. * Called for instance in karte_t::local_set_tool to change active tool or when filling toolbars. * @return true if player can use this tool. */ bool is_tool_allowed(const player_t* player, uint16 tool_id, sint16 wt = ignore_wt, const char *param=0); /** * Checks if player can use the tool at this position. * @return NULL if allowed otherwise error message */ const char* is_work_allowed_here(const player_t* player, uint16 tool_id, sint16 wt, const char *param, koord3d pos); /** * Checks if player can use this schedule. * * @param player player * @param schedule the schedule * * @return null if allowed, an error message otherwise */ const char* is_schedule_allowed(const player_t* player, const schedule_t* schedule); /** * Checks if player can use this convoy. * Called when player wants to start convoy at depot. * * @param player player * @param cnv convoy * @param depot depot * * @return null if allowed, an error message otherwise */ const char* is_convoy_allowed(const player_t* player, convoihandle_t cnv, depot_t* depot); /** * Checks if this tool is currently available to the player * Checks if player can use this tool at all. * Called for instance in karte_t::local_set_tool to change active tool or when filling toolbars. * @return true if player can use this tool and false (and the tool is greyed out). */ bool is_tool_enabled(const player_t* player, uint16 tool_id, sint16 wt, const char *param); /** * Called when player click link in scenario windows, after position changed. * * @param pos coordinate go to in link * * @return an error message otherwise or null */ const char* jump_to_link_executed(koord3d pos); /// @return debug dump of forbidden tools const char* get_forbidden_text(); /// @} friend class nwc_scenario_t; ///< to access vm, update_won_lost() friend class nwc_scenario_rules_t; ///< to access forbidden_tool stuff }; #endif simutrans-124.3/src/simutrans/dataobj/schedule.cc000066400000000000000000000354641474050137200221120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../gui/simwin.h" #include "../simtypes.h" #include "../world/simworld.h" #include "../simhalt.h" #include "../display/simimg.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../gui/messagebox.h" #include "../descriptor/building_desc.h" #include "../ground/grund.h" #include "../obj/gebaeude.h" #include "../player/simplay.h" #include "../obj/depot.h" #include "loadsave.h" #include "translator.h" #include "schedule.h" #include "../tpl/slist_tpl.h" schedule_entry_t schedule_t::dummy_entry(koord3d::invalid, 0, 0); // copy all entries from schedule src to this and adjusts current_stop void schedule_t::copy_from(const schedule_t *src) { // make sure, we can access both if( src==NULL ) { dbg->fatal("schedule_t::copy_to()","cannot copy from NULL"); } entries.clear(); for(schedule_entry_t const& i : src->entries) { entries.append(i); } set_current_stop( src->get_current_stop() ); editing_finished = src->is_editing_finished(); } bool schedule_t::is_stop_allowed(const grund_t *gr) const { // first: check, if we can go here waytype_t const my_waytype = get_waytype(); bool ok = gr->hat_weg(my_waytype); if( !ok ) { if( my_waytype==air_wt ) { // everywhere is ok but not on stops (we have to load at airports only ...) ok = !gr->get_halt().is_bound(); } else if( my_waytype==water_wt && gr->get_typ()==grund_t::wasser ) { ok = true; } else if( my_waytype==tram_wt ) { // tram rails are track internally ok = gr->hat_weg(track_wt); } } if( ok ) { // ok, we can go here; but we must also check, that we are not entering a foreign depot depot_t *dp = gr->get_depot(); ok &= (dp==NULL || (int)dp->get_tile()->get_desc()->get_extra()==my_waytype); } return ok; } /* returns a valid halthandle if there is a next halt in the schedule; * it may however not be allowed to load there, if the owner mismatches! */ halthandle_t schedule_t::get_next_halt( player_t *player, halthandle_t halt ) const { if( entries.get_count()>1 ) { for( uint i=1; i < entries.get_count(); i++ ) { halthandle_t h = haltestelle_t::get_halt( entries[ (current_stop+i) % entries.get_count() ].pos, player ); if( h.is_bound() && h != halt ) { return h; } } } return halthandle_t(); } /* returns a valid halthandle if there is a previous halt in the schedule; * it may however not be allowed to load there, if the owner mismatches! */ halthandle_t schedule_t::get_prev_halt( player_t *player ) const { if( entries.get_count()>1 ) { for( uint i=1; i < entries.get_count()-1u; i++ ) { halthandle_t h = haltestelle_t::get_halt( entries[ (current_stop+entries.get_count()-i) % entries.get_count() ].pos, player ); if( h.is_bound() ) { return h; } } } return halthandle_t(); } bool schedule_t::insert(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time ) { // too many stops or wrong kind of stop if (entries.get_count()>=254 || !is_stop_allowed(gr)) { return false; } entries.insert_at(current_stop, schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time)); current_stop ++; make_current_stop_valid(); return true; } bool schedule_t::append(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time) { // too many stops or wrong kind of stop if (entries.get_count()>=254 || !is_stop_allowed(gr)) { return false; } entries.append(schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time), 4); return true; } // cleanup a schedule void schedule_t::make_valid() { remove_double_entries(); if( entries.get_count() == 1 ) { // schedules with one entry not allowed entries.clear(); } make_current_stop_valid(); } void schedule_t::remove_double_entries() { if( entries.get_count() < 2 ) { return; // nothing to check } // first and last must not be the same! koord3d lastpos = entries.back().pos; // now we have to check all entries ... for( uint8 i=0; i delete_enty ) { current_stop--; } entries.remove_at(delete_enty); make_current_stop_valid(); } void schedule_t::move_entry_forward( uint8 cur ) { if( entries.get_count() <= 1 ) { return; } // not last entry if( cur < entries.get_count()-1 ) { // just append everything entries.insert_at( cur+2, entries[ cur ] ); entries.remove_at( cur ); } else { // last entry, just append everything entries.insert_at( 0, entries[cur] ); entries.remove_at( cur+1 ); } // if cur was not at end of list then cur and other changed places uint8 other = (cur + entries.get_count() + 1 ) % entries.get_count(); if (cur == entries.get_count()-1) { // all entries moved down one index current_stop = (current_stop + 1 + entries.get_count()) % entries.get_count(); } else if (current_stop == other) { current_stop = cur; } else if (current_stop == cur) { current_stop = other; } } void schedule_t::move_entry_backward( uint8 cur ) { if( entries.get_count() <= 1 ) { return; } if( cur==0 ) { //first entry entries.append( entries[0] ); entries.remove_at( 0 ); } else { // now move all to new position afterwards entries.insert_at( cur-1, entries[ cur ] ); entries.remove_at( cur+1 ); } // if cur was not at start of list then cur and other changed places uint8 other = (cur + entries.get_count() - 1 ) % entries.get_count(); if (cur == 0) { // all entries moved up one index current_stop = (current_stop - 1 + entries.get_count()) % entries.get_count(); } else if (current_stop == other) { current_stop = cur; } else if (current_stop == cur) { current_stop = other; } } void schedule_t::rdwr(loadsave_t *file) { xml_tag_t f( file, "fahrplan_t" ); assert(!file->is_loading() || entries.empty()); make_current_stop_valid(); uint8 size = entries.get_count(); if( file->is_version_less(101, 1) ) { uint32 dummy=current_stop; file->rdwr_long(dummy); current_stop = (uint8)dummy; sint32 maxi=size; file->rdwr_long(maxi); DBG_MESSAGE("schedule_t::rdwr()","read schedule %p with %i entries",this,maxi); if(file->is_version_less(86, 10)) { // old array had different maxi-counter maxi ++; } size = (uint8)max(0,maxi); } else { file->rdwr_byte(current_stop); file->rdwr_byte(size); } entries.resize(size); if(file->is_version_less(99, 12)) { for( uint8 i=0; irdwr_long(dummy); entries.append(schedule_entry_t(pos, (uint8)dummy, 0)); } } else { // loading/saving new version for( uint8 i=0; irdwr_byte(entries[i].minimum_loading); if(file->is_version_atleast(99, 18)) { if( file->is_version_atleast( 122, 1 ) ) { file->rdwr_short(entries[i].waiting_time); } else if(file->is_loading()) { uint8 wl=0; file->rdwr_byte(wl); if( entries[i].minimum_loading <= 100 ) { if( wl > 0 ) { // old value: maximum waiting time in 1/2^(16-n) parts of a month entries[ i ].waiting_time = 65535u / (1 << (16u - wl)); } } else if( entries[i].minimum_loading > 100 ) { // hack to store absolute departure times in old games entries[ i ].waiting_time = wl << 8; } } else { uint8 wl = entries[ i ].waiting_time >> 8; // loosing precision, but what can we do ... if( entries[ i ].minimum_loading <= 100 && entries[ i ].waiting_time > 0 ) { wl = log2( (uint32)entries[ i ].waiting_time )+1; } file->rdwr_byte(wl); } } } } if(file->is_loading()) { editing_finished = true; } if(current_stop>=entries.get_count() ) { if (!entries.empty()) { dbg->error("schedule_t::rdwr()","current_stop %i >count %i => current_stop = 0", current_stop, entries.get_count() ); } current_stop = 0; } } void schedule_t::rotate90( sint16 y_size ) { // now we have to rotate all entries ... for(schedule_entry_t & i : entries) { i.pos.rotate90(y_size); } } /** * compare this schedule (schedule) with another, passed in schedule */ bool schedule_t::matches(karte_t *welt, const schedule_t *schedule) { if( schedule == NULL ) { return false; } // same pointer => equal! if( this==schedule ) { return true; } // no match for empty schedules if( schedule->entries.empty() || entries.empty() ) { return false; } // now we have to check all entries ... // we need to do this that complicated, because the last stop may make the difference uint16 f1=0, f2=0; while( f1+f2entries.get_count() ) { if(f1entries.get_count() && schedule->entries[(uint8)f2].pos == entries[(uint8)f1].pos) { // minimum_loading/waiting ignored: identical f1++; f2++; } else { bool ok = false; if( f1lookup(entries[(uint8)f1].pos); if( gr1 && gr1->get_depot() ) { // skip depot f1++; ok = true; } } if( f2entries.get_count() ) { grund_t *gr2 = welt->lookup(schedule->entries[(uint8)f2].pos); if( gr2 && gr2->get_depot() ) { ok = true; f2++; } } // no depot but different => do not match! if( !ok ) { /* in principle we could also check for same halt; but this is dangerous, * since a rebuilding of a single square might change that */ return false; } } } return f1==entries.get_count() && f2==schedule->entries.get_count(); } /** * Ordering based on halt id */ class HaltIdOrdering { public: bool operator()(const halthandle_t& a, const halthandle_t& b) const { return a.get_id() < b.get_id(); } }; /** * compare this schedule (schedule) with another, ignoring order and exact positions and waypoints */ bool schedule_t::similar( const schedule_t *schedule, const player_t *player ) { if( schedule == NULL ) { return false; } // same pointer => equal! if( this == schedule ) { return true; } // unequal count => not equal const uint8 min_count = min( schedule->entries.get_count(), entries.get_count() ); if( min_count == 0 ) { return false; } // now we have to check all entries: So we add all stops to a vector we will iterate over vector_tpl halts; for( uint8 idx = 0; idx < this->entries.get_count(); idx++ ) { koord3d p = this->entries[idx].pos; halthandle_t halt = haltestelle_t::get_halt( p, player ); if( halt.is_bound() ) { halts.insert_unique_ordered( halt, HaltIdOrdering() ); } } vector_tpl other_halts; for( uint8 idx = 0; idx < schedule->entries.get_count(); idx++ ) { koord3d p = schedule->entries[idx].pos; halthandle_t halt = haltestelle_t::get_halt( p, player ); if( halt.is_bound() ) { other_halts.insert_unique_ordered( halt, HaltIdOrdering() ); } } // now compare them if( other_halts.get_count() != halts.get_count() ) { return false; } // number of unique halt similar => compare them now for( uint32 idx = 0; idx < halts.get_count(); idx++ ) { if( halts[idx] != other_halts[idx] ) { return false; } } return true; } void schedule_t::add_return_way(bool append_mirror) { if( append_mirror ) { // add mirror entries if( entries.get_count()<127 && entries.get_count()>1 ) { for( uint8 maxi=entries.get_count()-2; maxi>0; maxi-- ) { entries.append(entries[maxi]); } } } else { // invert if( entries.get_count()>1 ) { for( uint8 i=0; ierror( "schedule_t::sscanf_schedule()","incomplete entry termination!" ); return false; } p++; // then schedule type int type = atoi( p ); // .. check for correct type if( type != (int)get_type()) { dbg->error( "schedule_t::sscanf_schedule()","schedule has wrong type (%d)! should have been %d.", type, get_type() ); return false; } while( *p && *p!='|' ) { p++; } if( *p!='|' ) { dbg->error( "schedule_t::sscanf_schedule()","incomplete entry termination!" ); return false; } p++; // now scan the entries while( *p>0 ) { sint16 values[5]; for( sint8 i=0; i<5; i++ ) { values[i] = atoi( p ); while( *p && (*p!=',' && *p!='|') ) { p++; } if( i<4 && *p!=',' ) { dbg->error( "schedule_t::sscanf_schedule()","incomplete string!" ); return false; } if( i==4 && *p!='|' ) { dbg->error( "schedule_t::sscanf_schedule()","incomplete entry termination!" ); return false; } p++; } // ok, now we have a complete entry entries.append(schedule_entry_t(koord3d(values[0], values[1], (sint8)values[2]), (uint8)values[3], (uint16)values[4])); } make_valid(); return true; } void schedule_t::gimme_stop_name(cbuffer_t& buf, karte_t* welt, player_t const* const player_, schedule_entry_t const& entry, int const max_chars) { const char *p; halthandle_t halt = haltestelle_t::get_halt(entry.pos, player_); if(halt.is_bound()) { p = halt->get_name(); } else { const grund_t* gr = welt->lookup(entry.pos); if(gr==NULL) { p = translator::translate("Invalid coordinate"); } else if(gr->get_depot() != NULL) { p = translator::translate("Depot"); } else { p = translator::translate("Wegpunkt"); } } // finally append if(max_chars > 0 && strlen(p)>(unsigned)max_chars) { buf.printf("%.*s...", max_chars - 3, p); } else { buf.append(p); } // position (when no length restriction) if (max_chars <= 0) { buf.printf(" (%s)", entry.pos.get_str()); } } simutrans-124.3/src/simutrans/dataobj/schedule.h000066400000000000000000000215761474050137200217530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_SCHEDULE_H #define DATAOBJ_SCHEDULE_H #include "schedule_entry.h" #include "../halthandle.h" #include "../tpl/minivec_tpl.h" class cbuffer_t; class grund_t; class player_t; class karte_t; /** * Class to hold schedule of vehicles in Simutrans. */ class schedule_t { bool editing_finished; uint8 current_stop; static schedule_entry_t dummy_entry; /** * Fix up current_stop value, which we may have made out of range */ void make_current_stop_valid() { uint8 count = entries.get_count(); if( count == 0 ) { current_stop = 0; } else if( current_stop >= count ) { current_stop = count-1; } } protected: schedule_t() : editing_finished(false), current_stop(0) {} public: enum schedule_type { schedule = 0, truck_schedule = 1, train_schedule = 2, ship_schedule = 3, airplane_schedule = 4, monorail_schedule = 5, tram_schedule = 6, maglev_schedule = 7, narrowgauge_schedule = 8 }; minivec_tpl entries; /** * Returns error message if stops are not allowed */ virtual char const* get_error_msg() const = 0; /** * Returns true if this schedule allows stop at the * given tile. */ bool is_stop_allowed(const grund_t *gr) const; bool empty() const { return entries.empty(); } uint8 get_count() const { return entries.get_count(); } virtual schedule_type get_type() const = 0; virtual waytype_t get_waytype() const = 0; // remove this entry void remove_entry( uint8 entry ); // move the entry to front (and wrap) // you must use this function so all groups of departue entries are moved together void move_entry_forward( uint8 entry ); // move the entry to back (and wrap) // you must use this function so all groups of departue entries are moved together void move_entry_backward( uint8 entry ); /** * Get current stop of the schedule. */ uint8 get_current_stop() const { return current_stop; } /// returns the current stop, always a valid entry schedule_entry_t const& get_current_entry() const { return current_stop >= entries.get_count() ? dummy_entry : entries[current_stop]; } /** * Set the current stop of the schedule . * If new value is bigger than stops available, the max stop will be used. */ void set_current_stop(uint8 new_current_stop) { current_stop = new_current_stop; make_current_stop_valid(); } /// advance current_stop by one void advance() { if( !entries.empty() ) { if( entries[ current_stop ].minimum_loading > 100 ) { // skip the whole departure group for( uint8 next_stop = (current_stop + 1) % entries.get_count(); next_stop != current_stop; next_stop = (next_stop + 1) % entries.get_count() ) { if( entries[ next_stop ].pos != entries[ current_stop ].pos ) { current_stop = next_stop; break; } } } else { current_stop = (current_stop+1)%entries.get_count(); } } } inline bool is_editing_finished() const { return editing_finished; } void finish_editing() { editing_finished = true; } void start_editing() { editing_finished = false; } virtual ~schedule_t() {} /** * returns a halthandle for the next halt in the schedule (or unbound) */ halthandle_t get_next_halt( player_t *player, halthandle_t halt ) const; /** * returns a halthandle for the previous halt in the schedule (or unbound) */ halthandle_t get_prev_halt( player_t *player ) const; /** * Inserts a coordinate at current_stop into the schedule. */ bool insert(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0); /** * Appends a coordinate to the schedule. */ bool append(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0); /** * Makes schedule valid for driving: * - remove double entries * - clear schedule if it contains just one entry * - call make_current_stop_valid */ void make_valid(); /** * Remove double entries. */ void remove_double_entries(); /** * Remove current_stop entry from the schedule. */ bool remove(); void rdwr(loadsave_t *file); void rotate90( sint16 y_size ); /** * if the passed in schedule matches "this", then return true */ bool matches(karte_t *welt, const schedule_t *schedule); /** * Compare this schedule with another, ignoring order and exact positions and waypoints, wazting/scheduling. */ bool similar( const schedule_t *schedule, const player_t *player ); /** * Calculates a return way for this schedule. * Will add elements 1 to end in reverse order to schedule if ture * Or just mirror order if false */ void add_return_way(bool); virtual schedule_t* copy() = 0;//{ return new schedule_t(this); } // copy all entries from schedule src to this and adjusts current_stop void copy_from(const schedule_t *src); // fills the given buffer with a schedule void sprintf_schedule( cbuffer_t &buf ) const; /** * Converts this string into a schedule. * Ensure valid schedule. * @returns true reading worked and schedule is non-empty */ bool sscanf_schedule( const char * ); /** * Append description of entry to buf. * If @p max_chars > 0 then append short version, without loading level and position. */ static void gimme_stop_name(cbuffer_t& buf, karte_t* welt, player_t const* player_, schedule_entry_t const& entry, int max_chars); }; /** * Schedules with stops on tracks. */ class train_schedule_t : public schedule_t { public: train_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new train_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Zughalt muss auf\nSchiene liegen!\n"; } schedule_type get_type() const OVERRIDE { return train_schedule; } waytype_t get_waytype() const OVERRIDE { return track_wt; } }; /** * Schedules with stops on tram tracks. */ class tram_schedule_t : public train_schedule_t { public: tram_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new tram_schedule_t(); s->copy_from(this); return s; } schedule_type get_type() const OVERRIDE { return tram_schedule; } waytype_t get_waytype() const OVERRIDE { return tram_wt; } }; /** * Schedules with stops on roads. */ class truck_schedule_t : public schedule_t { public: truck_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new truck_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Autohalt muss auf\nStrasse liegen!\n"; } schedule_type get_type() const OVERRIDE { return truck_schedule; } waytype_t get_waytype() const OVERRIDE { return road_wt; } }; /** * Schedules with stops on water. */ class ship_schedule_t : public schedule_t { public: ship_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new ship_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Schiffhalt muss im\nWasser liegen!\n"; } schedule_type get_type() const OVERRIDE { return ship_schedule; } waytype_t get_waytype() const OVERRIDE { return water_wt; } }; /** * Schedules for airplanes. */ class airplane_schedule_t : public schedule_t { public: airplane_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new airplane_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Flugzeughalt muss auf\nRunway liegen!\n"; } schedule_type get_type() const OVERRIDE { return airplane_schedule; } waytype_t get_waytype() const OVERRIDE { return air_wt; } }; /** * Schedules with stops on mono-rails. */ class monorail_schedule_t : public schedule_t { public: monorail_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new monorail_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Monorailhalt muss auf\nMonorail liegen!\n"; } schedule_type get_type() const OVERRIDE { return monorail_schedule; } waytype_t get_waytype() const OVERRIDE { return monorail_wt; } }; /** * Schedules with stops on maglev tracks. */ class maglev_schedule_t : public schedule_t { public: maglev_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new maglev_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "Maglevhalt muss auf\nMaglevschiene liegen!\n"; } schedule_type get_type() const OVERRIDE { return maglev_schedule; } waytype_t get_waytype() const OVERRIDE { return maglev_wt; } }; /** * Schedules with stops on narrowgauge tracks. */ class narrowgauge_schedule_t : public schedule_t { public: narrowgauge_schedule_t() {} schedule_t* copy() OVERRIDE { schedule_t *s = new narrowgauge_schedule_t(); s->copy_from(this); return s; } const char *get_error_msg() const OVERRIDE { return "On narrowgauge track only!\n"; } schedule_type get_type() const OVERRIDE { return narrowgauge_schedule; } waytype_t get_waytype() const OVERRIDE { return narrowgauge_wt; } }; #endif simutrans-124.3/src/simutrans/dataobj/schedule_entry.h000066400000000000000000000032171474050137200231640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_SCHEDULE_ENTRY_H #define DATAOBJ_SCHEDULE_ENTRY_H #include "koord3d.h" #include "../tpl/minivec_tpl.h" #include "../world/simworld.h" /** * A schedule entry. */ struct schedule_entry_t { public: schedule_entry_t() {} schedule_entry_t(koord3d const& pos, uint8 const minimum_loading, uint16 const waiting_time) : pos(pos), minimum_loading(minimum_loading), waiting_time(waiting_time) {} /** * target position */ koord3d pos; /** * Wait for % load at this stops * (ignored on waypoints) * If this value is greater than 100, waiting_time_shift contains the first departure time, for 100-minimum loading times per month */ uint8 minimum_loading; /** * (only active if minimum_loading!=0) * contains a departing time in ticks, relative to the length of the month * The actual tick value is waiting_time << (tick_bit_per_month-16) */ uint16 waiting_time; uint32 get_waiting_ticks() const { return world()->ticks_per_world_month_shift >= 16 ? (uint32)waiting_time << (world()->ticks_per_world_month_shift - 16) : (uint32)waiting_time >> (16 - world()->ticks_per_world_month_shift); } // true if this is an absolute dparture time and not maximum waiting time uint8 get_absolute_departures() const { return minimum_loading > 100 ? minimum_loading - 100 : 0; } }; inline bool operator ==(const schedule_entry_t &a, const schedule_entry_t &b) { return a.pos == b.pos && a.minimum_loading == b.minimum_loading && a.waiting_time == b.waiting_time; } #endif simutrans-124.3/src/simutrans/dataobj/settings.cc000066400000000000000000002164771474050137200221630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "settings.h" #include "environment.h" #include "../pathes.h" #include "../simconst.h" #include "../simtypes.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../builder/wegbauer.h" #include "../descriptor/way_desc.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../vehicle/vehicle_base.h" #include "../player/finance.h" #include "../player/simplay.h" #include "../sys/simsys.h" #include "loadsave.h" #include "tabfile.h" #include "translator.h" #include "../tpl/minivec_tpl.h" #define NEVER 0xFFFFU settings_t::settings_t() : filename(""), heightfield("") { size_x = 256; size_y = 256; map_number = 33; /* new setting since version 0.85.01 */ factory_count = 12; tourist_attractions = 16; city_count = 16; mean_citizen_count = 1600; station_coverage_size = 2; traffic_level = 5; // default maximum length of convoi max_rail_convoi_length = 24; max_road_convoi_length = 4; max_ship_convoi_length = 4; max_air_convoi_length = 1; world_maximum_height = 32; world_minimum_height = -12; // default climate zones set_default_climates( ); climate_generator = HEIGHT_BASED; groundwater = -2; winter_snowline = 7; // not mediterranean max_mountain_height = 160; //can be 0-160.0 map_roughness = 0.6; //can be 0-1 river_number = 16; min_river_length = 16; max_river_length = 256; // since the turning rules are different, driving must now be saved here drive_on_left = false; signals_on_left = false; // forest setting ... forest_base_size = 36; // Base forest size - minimal size of forest - map independent forest_map_size_divisor = 38; // Map size divisor - smaller it is the larger are individual forests forest_count_divisor = 16; // Forest count divisor - smaller it is, the more forest are generated forest_inverse_spare_tree_density = 5; // Determines how often are spare trees going to be planted (works inversely) max_no_of_trees_on_square = 3; // Number of trees on square 2 - minimal usable, 3 good, 5 very nice looking tree_climates = 0; // bit set, if this climate is to be covered with trees entirely no_tree_climates = 0; // bit set, if this climate is to be void of random trees tree_distribution = TREE_DIST_RANDOM; // 0=no trees may be useful for low end engines, 1=random, 2=rainfall lake_height = 8; // lakes will be generated below this height above groundwater // some settings more allow_player_change = true; use_timeline = 2; starting_year = 1930; starting_month = 0; bits_per_month = 20; beginner_mode = false; beginner_price_factor = 1500; rotation = 0; origin_x = origin_y = 0; // passenger manipulation factor (=16 about old value) passenger_factor = 16; // town growth factors passenger_multiplier = 40; mail_multiplier = 20; goods_multiplier = 20; electricity_multiplier = 0; // Also there are size dependent factors (0 causes crash !) growthfactor_small = 400; growthfactor_medium = 200; growthfactor_large = 100; minimum_city_distance = 16; industry_increase = 2000; special_building_distance = 3; factory_worker_percentage = 33; tourist_percentage = 16; for( int i=0; i<10; i++ ) { locality_factor_per_year[i].year = 0; locality_factor_per_year[i].factor = 0; } locality_factor_per_year[0].factor = 100; factory_worker_radius = 77; // try to have at least a single town connected to a factory factory_worker_minimum_towns = 1; // not more than four towns should supply to a factory factory_worker_maximum_towns = 4; factory_arrival_periods = 4; factory_enforce_demand = true; factory_maximum_intransit_percentage = 0; electric_promille = 330; #ifdef OTTD_LIKE // crossconnect all factories (like OTTD and similar games) crossconnect_factories=true; crossconnect_factor=100; #else /* crossconnect a certain number */ crossconnect_factories=false; crossconnect_factor=33; #endif /* minimum spacing between two factories */ min_factory_spacing = 6; max_factory_spacing = 40; max_factory_spacing_percentage = 0; // off just_in_time = env_t::just_in_time; stadtauto_duration = 36; // three years // to keep names consistent numbered_stations = false; num_city_roads = 0; num_intercity_roads = 0; city_road_speed_limit_num = 0; max_route_steps = 1000000; max_choose_route_steps = 200; max_transfers = 9; max_hops = 2000; no_routing_over_overcrowding = false; bonus_basefactor = 125; /* multiplier for steps on diagonal: * 1024: TT-like, factor 2, vehicle will be too long and too fast * 724: correct one, factor sqrt(2) */ pak_diagonal_multiplier = 724; // read default from env_t // should be set in simmain.cc (taken from pak-set simuconf.tab way_height_clearance = env_t::default_settings.get_way_height_clearance(); if (way_height_clearance >2) { // if outside bounds, then set to default = 1 way_height_clearance = 1; } strcpy( language_code_names, "en" ); // default AIs active for( int i=0; iis_version_less(86, 0)) { uint32 dummy; file->rdwr_long(size_x ); size_y = size_x; file->rdwr_long(map_number ); // to be compatible with previous savegames dummy = 0; file->rdwr_long(dummy ); //dummy! factory_count = 12; tourist_attractions = 12; // now towns mean_citizen_count = 1600; dummy = city_count; file->rdwr_long(dummy ); dummy &= 127; if(dummy>63) { dbg->warning("settings_t::rdwr()", "This game was saved with too many cities! (%i of maximum 63). Simutrans may crash!", dummy); } city_count = dummy; // rest file->rdwr_long(dummy ); // scroll ignored file->rdwr_long(traffic_level ); file->rdwr_long(dummy); // pedestrians at stops dummy = groundwater; file->rdwr_long(dummy ); groundwater = (sint16)(dummy/16); file->rdwr_double(max_mountain_height ); file->rdwr_double(map_roughness ); station_coverage_size = 3; beginner_mode = false; rotation = 0; } else { // newer versions file->rdwr_long(size_x ); file->rdwr_long(map_number ); // industries file->rdwr_long(factory_count ); if(file->is_version_less(99, 18)) { uint32 dummy; // was city chains file->rdwr_long(dummy ); } else { file->rdwr_long( electric_promille ); } file->rdwr_long(tourist_attractions ); // now towns file->rdwr_long(mean_citizen_count ); file->rdwr_long(city_count ); // rest if(file->is_version_less(101, 0)) { uint32 dummy; // was scroll dir file->rdwr_long(dummy ); } file->rdwr_long(traffic_level ); if (file->is_version_less(123, 2)) { sint32 dummy = env_t::stop_pedestrians; file->rdwr_long(dummy); env_t::stop_pedestrians = dummy; } sint32 dummy = groundwater; file->rdwr_long(dummy ); if(file->is_version_less(99, 5)) { groundwater = (sint16)(dummy/16); } else { groundwater = (sint16)dummy; } file->rdwr_double(max_mountain_height ); file->rdwr_double(map_roughness ); if(file->is_version_atleast(86, 3)) { dummy = station_coverage_size; file->rdwr_long(dummy ); station_coverage_size = (uint16)dummy; } if(file->is_version_atleast(86, 6)) { // handle also size on y direction file->rdwr_long(size_y ); } else { size_y = size_x; } if(file->is_version_atleast(86, 11)) { // some more settings file->rdwr_byte(allow_player_change ); file->rdwr_byte(use_timeline ); file->rdwr_short(starting_year ); } else { allow_player_change = 1; use_timeline = 1; starting_year = 1930; } if(file->is_version_atleast(88, 5)) { file->rdwr_short(bits_per_month ); } else { bits_per_month = 18; } if(file->is_version_atleast(89, 3)) { file->rdwr_bool(beginner_mode ); } else { beginner_mode = false; } if( file->is_version_atleast(120, 1) ){ file->rdwr_byte( just_in_time ); } else if( file->is_version_atleast(89, 4) ) { bool compat = just_in_time > 0; file->rdwr_bool( compat ); just_in_time = 0; if( compat ) { just_in_time = env_t::just_in_time ? env_t::just_in_time : 1; } } // rotation of the map with respect to the original value if(file->is_version_atleast(99, 15)) { file->rdwr_byte(rotation ); } else { rotation = 0; } // clear the name when loading ... if(file->is_loading()) { filename = ""; } // climate borders, no overlapping borders are possible if( file->is_version_atleast(91, 0) ){ if( file->is_version_less(121,1) ) { sint16 old_climate_borders[ MAX_CLIMATES ]; for( int cl = 0; cl < MAX_CLIMATES; cl++ ) { old_climate_borders[cl] = climate_borders[cl][0]; } if( file->is_version_less(120, 6) ) { old_climate_borders[arctic_climate] -= groundwater; } for( int i=0; i<8; i++ ) { file->rdwr_short(old_climate_borders[i] ); } if( file->is_version_less(120, 6) ) { old_climate_borders[arctic_climate] += groundwater; } if( file->is_loading() && file->is_version_less(112, 7) ) { groundwater *= env_t::pak_height_conversion_factor; for( int i = 0; i < MAX_CLIMATES; i++ ) { old_climate_borders[i] *= env_t::pak_height_conversion_factor; } } // convert to new borders if loading, es keep the current if( file->is_loading() ) { for( int cl = 0; cl < MAX_CLIMATES-1; cl++ ) { climate_borders[cl][0] = old_climate_borders[cl]; climate_borders[cl][1] = old_climate_borders[cl+1]; } climate_borders[0][1] = old_climate_borders[0]; climate_borders[arctic_climate][1] = old_climate_borders[arctic_climate]; } } else { for( int i=0; i<8; i++ ) { file->rdwr_short( climate_borders[i][0] ); file->rdwr_short( climate_borders[i][1] ); } file->rdwr_byte( tropic_humidity ); file->rdwr_byte( desert_humidity ); for( int i=0; i<5; i++ ) { file->rdwr_byte( climate_temperature_borders[i] ); } file->rdwr_byte( patch_size_percentage ); } file->rdwr_short( winter_snowline ); } // vehicle may need realignment afterwards! if(file->is_version_less(99, 19)) { vehicle_base_t::set_diagonal_multiplier( pak_diagonal_multiplier, 1024 ); } else { uint16 old_multiplier = pak_diagonal_multiplier; file->rdwr_short( old_multiplier ); vehicle_base_t::set_diagonal_multiplier( pak_diagonal_multiplier, old_multiplier ); // since vehicle will need realignment afterwards! } if(file->is_version_atleast(101, 0)) { // game mechanics file->rdwr_short(origin_x ); file->rdwr_short(origin_y ); file->rdwr_long(passenger_factor ); // town grow stuff if(file->is_version_atleast(102, 2)) { file->rdwr_long(passenger_multiplier ); file->rdwr_long(mail_multiplier ); file->rdwr_long(goods_multiplier ); file->rdwr_long(electricity_multiplier ); file->rdwr_long(growthfactor_small ); file->rdwr_long(growthfactor_medium ); file->rdwr_long(growthfactor_large ); file->rdwr_short(factory_worker_percentage ); file->rdwr_short(tourist_percentage ); file->rdwr_short(factory_worker_radius ); } file->rdwr_long(electric_promille ); file->rdwr_short(min_factory_spacing ); file->rdwr_bool(crossconnect_factories ); file->rdwr_short(crossconnect_factor ); if (file->is_version_less(123, 2)) { file->rdwr_bool(env_t::random_pedestrians); } file->rdwr_long(stadtauto_duration ); file->rdwr_bool(numbered_stations ); if( file->is_version_less(102, 3) ) { if( file->is_loading() ) { num_city_roads = 1; city_roads[0].intro = 0; city_roads[0].retire = 0; // intercity roads were not saved in old savegames num_intercity_roads = 0; } file->rdwr_str(city_roads[0].name, lengthof(city_roads[0].name) ); } else { // several roads ... file->rdwr_short(num_city_roads ); if( num_city_roads>=10 ) { dbg->fatal("settings_t::rdwr()", "Too many (%i) city roads!", num_city_roads); } for( int i=0; irdwr_str(city_roads[i].name, lengthof(city_roads[i].name) ); file->rdwr_short(city_roads[i].intro ); file->rdwr_short(city_roads[i].retire ); } // several intercity roads ... file->rdwr_short(num_intercity_roads ); if( num_intercity_roads>=10 ) { dbg->fatal("settings_t::rdwr()", "Too many (%i) intercity roads!", num_intercity_roads); } for( int i=0; irdwr_str(intercity_roads[i].name, lengthof(intercity_roads[i].name) ); file->rdwr_short(intercity_roads[i].intro ); file->rdwr_short(intercity_roads[i].retire ); } } file->rdwr_long(max_route_steps ); file->rdwr_long(max_transfers ); file->rdwr_long(max_hops ); file->rdwr_long(beginner_price_factor ); // name of stops file->rdwr_str(language_code_names, lengthof(language_code_names) ); // restore AI state for( int i=0; i<15; i++ ) { if(file->is_version_less(122,1)) { bool player_active = true; file->rdwr_bool(player_active); } file->rdwr_byte(player_type[i] ); if( file->is_version_less(102, 3) ) { char dummy[2] = { 0, 0 }; file->rdwr_str(dummy, lengthof(dummy) ); } } // cost section ... file->rdwr_bool(freeplay ); if( file->is_version_atleast(102, 3) ) { file->rdwr_longlong(starting_money ); // these must be saved, since new player will get different amounts eventually for( int i=0; i<10; i++ ) { file->rdwr_short(startingmoneyperyear[i].year ); file->rdwr_longlong(startingmoneyperyear[i].money ); file->rdwr_bool(startingmoneyperyear[i].interpol ); } } else { // compatibility code sint64 save_starting_money = starting_money; if( file->is_saving() ) { if(save_starting_money==0) { save_starting_money = get_starting_money(starting_year ); } if(save_starting_money==0) { save_starting_money = env_t::default_settings.get_starting_money(starting_year ); } if(save_starting_money==0) { save_starting_money = 20000000; } } file->rdwr_longlong(save_starting_money ); if(file->is_loading()) { if(save_starting_money==0) { save_starting_money = env_t::default_settings.get_starting_money(starting_year ); } if(save_starting_money==0) { save_starting_money = 20000000; } starting_money = save_starting_money; } } file->rdwr_long(maint_building ); file->rdwr_longlong(cst_multiply_dock ); file->rdwr_longlong(cst_multiply_station ); file->rdwr_longlong(cst_multiply_roadstop ); file->rdwr_longlong(cst_multiply_airterminal ); file->rdwr_longlong(cst_multiply_post ); file->rdwr_longlong(cst_multiply_headquarter ); file->rdwr_longlong(cst_depot_rail ); file->rdwr_longlong(cst_depot_road ); file->rdwr_longlong(cst_depot_ship ); file->rdwr_longlong(cst_depot_air ); if( file->is_version_less(102, 2) ) { sint64 dummy64 = 100000; file->rdwr_longlong(dummy64 ); file->rdwr_longlong(dummy64 ); file->rdwr_longlong(dummy64 ); } // alter landscape file->rdwr_longlong(cst_buy_land ); file->rdwr_longlong(cst_alter_land ); file->rdwr_longlong(cst_set_slope ); file->rdwr_longlong(cst_found_city ); file->rdwr_longlong(cst_multiply_found_industry ); file->rdwr_longlong(cst_remove_tree ); file->rdwr_longlong(cst_multiply_remove_haus ); file->rdwr_longlong(cst_multiply_remove_field ); // cost for transformers file->rdwr_longlong(cst_transformer ); file->rdwr_longlong(cst_maintain_transformer ); if( file->is_version_atleast(120, 3) ) { file->rdwr_longlong(cst_make_public_months); } if( file->is_version_atleast(120, 9) ) { file->rdwr_longlong(cst_multiply_merge_halt); } // wayfinder file->rdwr_long(way_count_straight ); file->rdwr_long(way_count_curve ); file->rdwr_long(way_count_double_curve ); file->rdwr_long(way_count_90_curve ); file->rdwr_long(way_count_slope ); file->rdwr_long(way_count_tunnel ); file->rdwr_long(way_max_bridge_len ); file->rdwr_long(way_count_leaving_way ); } else { // name of stops set_name_language_iso( env_t::language_iso ); // default AIs active for( int i=0; iis_version_atleast(101, 1)) { file->rdwr_bool( separate_halt_capacities ); file->rdwr_byte( pay_for_total_distance ); file->rdwr_short(starting_month ); file->rdwr_short( river_number ); file->rdwr_short( min_river_length ); file->rdwr_short( max_river_length ); } if(file->is_version_atleast(102, 1)) { file->rdwr_bool( avoid_overcrowding ); } if(file->is_version_atleast(102, 2)) { file->rdwr_bool( no_routing_over_overcrowding ); if (file->is_version_less(123, 2)) { file->rdwr_bool( with_private_paks ); } } if(file->is_version_atleast(102, 3)) { // network stuff // Superseded by simrand_rdwr in newer versions if (file->is_version_less(122, 1)) { random_counter = get_random_seed( ); file->rdwr_long( random_counter ); } if( !env_t::networkmode || env_t::server ) { frames_per_second = clamp(env_t::fps, env_t::min_fps, env_t::max_fps); // update it on the server to the current setting frames_per_step = env_t::network_frames_per_step; } file->rdwr_long( frames_per_second ); file->rdwr_long( frames_per_step ); if( !env_t::networkmode || env_t::server ) { frames_per_second = env_t::fps; // update it on the server to the current setting frames_per_step = env_t::network_frames_per_step; } file->rdwr_bool( allow_buying_obsolete_vehicles ); file->rdwr_long( factory_worker_minimum_towns ); file->rdwr_long( factory_worker_maximum_towns ); // forest stuff file->rdwr_byte( forest_base_size ); file->rdwr_byte( forest_map_size_divisor ); file->rdwr_byte( forest_count_divisor ); file->rdwr_short( forest_inverse_spare_tree_density ); file->rdwr_byte( max_no_of_trees_on_square ); file->rdwr_short( tree_climates ); file->rdwr_short( no_tree_climates ); bool no_trees = (tree_distribution==TREE_DIST_NONE); file->rdwr_bool( no_trees ); if( file->is_loading() ) { tree_distribution = no_trees ? TREE_DIST_NONE : TREE_DIST_RANDOM; } file->rdwr_long( minimum_city_distance ); file->rdwr_long( industry_increase ); } if( file->is_version_atleast(110, 0) ) { if( !env_t::networkmode || env_t::server ) { server_frames_ahead = env_t::server_frames_ahead; } file->rdwr_long( server_frames_ahead ); if( !env_t::networkmode || env_t::server ) { server_frames_ahead = env_t::server_frames_ahead; } file->rdwr_short( used_vehicle_reduction ); } if( file->is_version_atleast(110, 1) ) { file->rdwr_bool( default_player_color_random ); for( int i=0; irdwr_byte( default_player_color[i][0] ); file->rdwr_byte( default_player_color[i][1] ); } } else if( file->is_loading() ) { default_player_color_random = false; for( int i=0; iis_version_atleast(110, 5) ) { file->rdwr_short(factory_arrival_periods); file->rdwr_bool(factory_enforce_demand); } if( file->is_version_atleast(110, 7) ) { for( int i=0; i<10; i++ ) { file->rdwr_short(locality_factor_per_year[i].year ); file->rdwr_long(locality_factor_per_year[i].factor ); } file->rdwr_bool( drive_on_left ); file->rdwr_bool( signals_on_left ); file->rdwr_long( way_toll_runningcost_percentage ); file->rdwr_long( way_toll_waycost_percentage ); } if( file->is_version_atleast(111, 2) ) { file->rdwr_long( bonus_basefactor ); } else if( file->is_loading() ) { bonus_basefactor = 125; } if( file->is_version_atleast(111, 4) ) { file->rdwr_bool( allow_underground_transformers ); } if( file->is_version_atleast(111, 5) ) { file->rdwr_short( special_building_distance ); } if( file->is_version_atleast(112, 1) ) { file->rdwr_short( factory_maximum_intransit_percentage ); } if( file->is_version_atleast(112, 2) ) { file->rdwr_short( remove_dummy_player_months ); file->rdwr_short( unprotect_abandoned_player_months ); } if( file->is_version_atleast(112, 3) ) { file->rdwr_short( max_factory_spacing ); file->rdwr_short( max_factory_spacing_percentage ); } if( file->is_version_atleast(112, 8) ) { file->rdwr_longlong( cst_alter_climate ); file->rdwr_byte( way_height_clearance ); } if( file->is_version_atleast(120, 2) ) { file->rdwr_long( default_ai_construction_speed ); } else if( file->is_loading() ) { default_ai_construction_speed = env_t::default_ai_construction_speed; } if( file->is_version_atleast(122,0) ) { file->rdwr_byte(lake_height); file->rdwr_short(tree_distribution); } else if( file->is_version_atleast(120, 2) ) { bool this_lake = lake_height > 0; file->rdwr_bool(this_lake); bool no_trees = (tree_distribution==TREE_DIST_NONE); file->rdwr_bool( no_trees ); if( file->is_loading() ) { lake_height = this_lake ? 8 : 0; tree_distribution = no_trees ? TREE_DIST_NONE : TREE_DIST_RANDOM; } } if( file->is_version_atleast(120, 2) ) { file->rdwr_long( max_choose_route_steps ); } if( file->is_version_atleast(120, 4) ) { file->rdwr_bool(disable_make_way_public); } if( file->is_version_atleast(120, 6) ) { file->rdwr_byte(max_rail_convoi_length); file->rdwr_byte(max_road_convoi_length); file->rdwr_byte(max_ship_convoi_length); file->rdwr_byte(max_air_convoi_length); } if( file->is_version_atleast(120, 7) ) { file->rdwr_byte(world_maximum_height); file->rdwr_byte(world_minimum_height); world_maximum_height = clamp(world_maximum_height, 16, 127); world_minimum_height = clamp(world_minimum_height, -127, -12); } if( file->is_version_atleast(120, 9) ) { file->rdwr_long(allow_merge_distant_halt); } if( file->is_version_atleast(122, 1) ) { file->rdwr_enum(climate_generator); file->rdwr_byte(wind_direction); bool dummy = true; file->rdwr_bool(dummy /*was departures_on_time */); } else if( file->is_loading() ) { climate_generator = HEIGHT_BASED; switch (rotation) { default: case 0: wind_direction = ribi_t::west; break; case 1: wind_direction = ribi_t::north; break; case 2: wind_direction = ribi_t::east; break; case 3: wind_direction = ribi_t::south; break; } } if( file->is_version_atleast(122, 2) ) { file->rdwr_bool(stop_halt_as_scheduled); } // restoring the city speed limit vector if (file->is_version_atleast(123, 2)) { file->rdwr_short(city_road_speed_limit_num); for (uint16 i = 0; i < city_road_speed_limit_num; i++) { file->rdwr_short(city_road_speed_limit[i]); } } // otherwise the default values of the last one will be used if (file->is_version_atleast(124, 2)) { file->rdwr_long(way_count_no_way); file->rdwr_long(way_count_avoid_crossings); file->rdwr_long(way_count_maximum); } } // sometimes broken savegames could have no legal direction for take off ... if( !ribi_t::is_single( wind_direction ) ) { wind_direction = ribi_t::west; } } // read the settings from this file void settings_t::parse_simuconf( tabfile_t& simuconf, sint16& disp_width, sint16& disp_height, sint16 &fullscreen, std::string& objfilename ) { tabfileobj_t contents; simuconf.read( contents ); #if COLOUR_DEPTH != 0 // special day/night colors for( int i = 0; i < LIGHT_COUNT; i++ ) { char str[ 256 ]; sprintf( str, "special_color[%i]", i ); const vector_tpl c = contents.get_ints( str ); if( c.get_count() >= 6 ) { // now update RGB values display_day_lights[i].r = c[0]; display_day_lights[i].g = c[1]; display_day_lights[i].b = c[2]; display_night_lights[i].r = c[3]; display_night_lights[i].g = c[4]; display_night_lights[i].b = c[5]; } } #endif // check for fontname, must be a valid name! // will be only changed if default! std::string fname = trim( contents.get_string( "fontname", env_t::fontname.c_str() ) ); if( FILE* f = dr_fopen( fname.c_str(), "r" ) ) { fclose( f ); env_t::fontname = fname; } env_t::fontsize = contents.get_int( "fontsize", env_t::fontsize ); env_t::water_animation = contents.get_int_clamped( "water_animation_ms", env_t::water_animation, 0, INT_MAX); env_t::ground_object_probability = contents.get_int_clamped( "random_grounds_probability", env_t::ground_object_probability, 0, INT_MAX); env_t::moving_object_probability = contents.get_int_clamped( "random_wildlife_probability", env_t::moving_object_probability, 0, INT_MAX); env_t::straight_way_without_control = contents.get_int( "straight_way_without_control", env_t::straight_way_without_control ) != 0; env_t::road_user_info = contents.get_int( "pedes_and_car_info", env_t::road_user_info ) != 0; env_t::tree_info = contents.get_int( "tree_info", env_t::tree_info ) != 0; env_t::ground_info = contents.get_int( "ground_info", env_t::ground_info ) != 0; env_t::townhall_info = contents.get_int( "townhall_info", env_t::townhall_info ) != 0; env_t::single_info = contents.get_int( "only_single_info", env_t::single_info ) != 0; env_t::single_line_gui = contents.get_int( "single_line_gui", env_t::single_line_gui ) != 0; env_t::compass_map_position = contents.get_int( "compass_map_position", env_t::compass_map_position ); env_t::compass_screen_position = contents.get_int( "compass_screen_position", env_t::compass_screen_position ); env_t::window_snap_distance = contents.get_int( "window_snap_distance", env_t::window_snap_distance ); env_t::window_buttons_right = contents.get_int( "window_buttons_right", env_t::window_buttons_right ) != 0; env_t::left_to_right_graphs = contents.get_int( "left_to_right_graphs", env_t::left_to_right_graphs ) != 0; env_t::window_frame_active = contents.get_int( "window_frame_active", env_t::window_frame_active ) != 0; env_t::second_open_closes_win = contents.get_int( "second_open_closes_win", env_t::second_open_closes_win ) != 0; env_t::remember_window_positions = contents.get_int( "remember_window_positions", env_t::remember_window_positions ) != 0; env_t::menupos = contents.get_int_clamped( "menubar_position", env_t::menupos, 0, 3); env_t::reselect_closes_tool = contents.get_int( "reselect_closes_tool", env_t::reselect_closes_tool ) != 0; env_t::single_toolbar_mode = contents.get_int( "single_toolbar", env_t::single_toolbar_mode ) != 0; env_t::dpi_scale = contents.get_int( "dpi_scaling", env_t::dpi_scale ); env_t::show_tooltips = contents.get_int( "show_tooltips", env_t::show_tooltips ) != 0; env_t::tooltip_delay = contents.get_int_clamped( "tooltip_delay", env_t::tooltip_delay, 0, INT_MAX); env_t::tooltip_duration = contents.get_int_clamped( "tooltip_duration", env_t::tooltip_duration, 0, INT_MAX); env_t::toolbar_max_width = contents.get_int_clamped( "toolbar_max_width", env_t::toolbar_max_width, 0, INT_MAX); env_t::toolbar_max_height = contents.get_int_clamped( "toolbar_max_height", env_t::toolbar_max_height, 0, INT_MAX); // how to show the stuff outside the map env_t::draw_earth_border = contents.get_int( "draw_earth_border", env_t::draw_earth_border ) != 0; env_t::draw_outside_tile = contents.get_int( "draw_outside_tile", env_t::draw_outside_tile ) != 0; // display stuff env_t::show_names = contents.get_int_clamped( "show_names", env_t::show_names, 0, 7 ); env_t::show_month = contents.get_int_clamped( "show_month", env_t::show_month, 0, 7 ); env_t::show_vehicle_states = contents.get_int_clamped( "show_vehicle_states", env_t::show_vehicle_states, 0, 3 ); env_t::follow_convoi_underground = contents.get_int_clamped( "follow_convoi_underground", env_t::follow_convoi_underground, 0, 2 ); env_t::max_acceleration = contents.get_int_clamped( "fast_forward", env_t::max_acceleration, 0, 0x7FFF ); env_t::fps = contents.get_int_clamped( "frames_per_second", env_t::fps, env_t::min_fps, env_t::max_fps ); env_t::ff_fps = contents.get_int_clamped( "fast_forward_frames_per_second", env_t::ff_fps, env_t::min_fps, env_t::max_fps ); env_t::num_threads = contents.get_int_clamped( "threads", env_t::num_threads, 1, min(dr_get_max_threads(), MAX_THREADS) ); env_t::simple_drawing_default = contents.get_int_clamped( "simple_drawing_tile_size", env_t::simple_drawing_default, 2, 256 ); env_t::simple_drawing_fast_forward = contents.get_int( "simple_drawing_fast_forward", env_t::simple_drawing_fast_forward ) != 0; env_t::visualize_schedule = contents.get_int( "visualize_schedule", env_t::visualize_schedule ) != 0; env_t::hide_rail_return_ticket = contents.get_int( "hide_rail_return_ticket", env_t::hide_rail_return_ticket ) != 0; env_t::chat_window_transparency = contents.get_int_clamped( "chat_transparency", env_t::chat_window_transparency, 0, 100); env_t::hide_keyboard = contents.get_int( "hide_keyboard", env_t::hide_keyboard ) != 0; env_t::numpad_always_moves_map = contents.get_int( "numpad_always_moves_map", env_t::numpad_always_moves_map ) != 0; env_t::leftdrag_in_minimap = contents.get_int( "leftdrag_in_minimap", env_t::leftdrag_in_minimap ) != 0; env_t::player_finance_display_account = contents.get_int( "player_finance_display_account", env_t::player_finance_display_account ) != 0; // network stuff env_t::server_frames_ahead = contents.get_int_clamped( "server_frames_ahead", env_t::server_frames_ahead, 0, INT_MAX ); env_t::additional_client_frames_behind = contents.get_int_clamped( "additional_client_frames_behind", env_t::additional_client_frames_behind, 0, INT_MAX ); env_t::network_frames_per_step = contents.get_int_clamped( "server_frames_per_step", env_t::network_frames_per_step, 1, INT_MAX ); env_t::server_sync_steps_between_checks = contents.get_int_clamped( "server_frames_between_checks", env_t::server_sync_steps_between_checks, 1, INT_MAX ); env_t::pause_server_no_clients = contents.get_int( "pause_server_no_clients", env_t::pause_server_no_clients ) != 0; env_t::server_save_game_on_quit = contents.get_int( "server_save_game_on_quit", env_t::server_save_game_on_quit ) != 0; env_t::reload_and_save_on_quit = contents.get_int( "reload_and_save_on_quit", env_t::reload_and_save_on_quit ) != 0; if( !env_t::server ) { env_t::server_port = contents.get_int_clamped( "server_port", env_t::server_port, 0, 0xFFFF ); } else { env_t::server_port = env_t::server; } env_t::server_announce = contents.get_int( "announce_server", env_t::server_announce ) != 0; env_t::server_announce = contents.get_int( "server_announce", env_t::server_announce ) != 0; env_t::server_announce_interval = contents.get_int_clamped( "server_announce_intervall", env_t::server_announce_interval, 60, 24*60*60); env_t::server_announce_interval = contents.get_int_clamped( "server_announce_interval", env_t::server_announce_interval, 60, 24*60*60); if( *contents.get( "server_dns" ) ) { env_t::server_dns = ltrim( contents.get( "server_dns" ) ); } if( *contents.get( "server_altdns" ) ) { env_t::server_alt_dns = ltrim( contents.get( "server_altdns" ) ); } if( *contents.get( "server_name" ) ) { env_t::server_name = ltrim( contents.get( "server_name" ) ); } if( *contents.get( "server_comments" ) ) { env_t::server_comments = ltrim( contents.get( "server_comments" ) ); } if( *contents.get( "server_email" ) ) { env_t::server_email = ltrim( contents.get( "server_email" ) ); } if( *contents.get( "server_pakurl" ) ) { env_t::server_pakurl = ltrim( contents.get( "server_pakurl" ) ); } if( *contents.get( "server_infurl" ) ) { env_t::server_infurl = ltrim( contents.get( "server_infurl" ) ); } if( *contents.get( "server_admin_pw" ) ) { env_t::server_admin_pw = ltrim( contents.get( "server_admin_pw" ) ); } if( *contents.get( "nickname" ) ) { env_t::nickname = ltrim( contents.get( "nickname" ) ); } if( *contents.get( "server_motd_filename" ) ) { env_t::server_motd_filename = ltrim( contents.get( "server_motd_filename" ) ); } // listen directive is a comma separated list of IP addresses to listen on if( *contents.get( "listen" ) ) { env_t::listen.clear(); std::string s = ltrim( contents.get( "listen" ) ); // Find index of first ',' copy from start of string to that position // Set start index to last position, then repeat // When ',' not found, copy remainder of string size_t start = 0; size_t end; end = s.find_first_of( "," ); env_t::listen.append_unique( ltrim( s.substr( start, end ).c_str() ) ); while( end != std::string::npos ) { start = end; end = s.find_first_of( ",", start + 1 ); env_t::listen.append_unique( ltrim( s.substr( start + 1, end - 1 - start ).c_str() ) ); } } // listen directive is a comma separated list of years and cityroad speeds if (*contents.get("cityroad_speeds")) { const char *start = ltrim(contents.get("cityroad_speeds")); city_road_speed_limit_num = 0; city_road_speed_limit[city_road_speed_limit_num++]=atoi(start); while (*start && city_road_speed_limit_num<20) { start++; if (*start == ',') { start++; city_road_speed_limit[city_road_speed_limit_num++] = atoi(start); } } // make sure we have pairs if (city_road_speed_limit_num & 1) { dbg->error("Wrong number of entries in city_road_speed_limit", "Expected pairs yers,speed but only %i values", city_road_speed_limit_num); } } drive_on_left = contents.get_int( "drive_left", drive_on_left ) != 0; signals_on_left = contents.get_int( "signals_on_left", signals_on_left ) != 0; allow_underground_transformers = contents.get_int( "allow_underground_transformers", allow_underground_transformers ) != 0; disable_make_way_public = contents.get_int( "disable_make_way_public", disable_make_way_public ) != 0; // up to ten rivers are possible for( int i = 0; i < 10; i++ ) { char name[ 32 ]; sprintf( name, "river_type[%i]", i ); const char *test = ltrim( contents.get( name ) ); if( *test ) { const int add_river = i < env_t::river_types ? i : env_t::river_types; env_t::river_type[ add_river ] = test; if( add_river == env_t::river_types ) { env_t::river_types++; } } } // old syntax for single city road const char *str = ltrim( contents.get( "city_road_type" ) ); if( str[ 0 ] ) { num_city_roads = 1; tstrncpy( city_roads[ 0 ].name, str, lengthof( city_roads[ 0 ].name ) ); rtrim( city_roads[ 0 ].name ); // default her: always available city_roads[ 0 ].intro = 1; city_roads[ 0 ].retire = NEVER; } // new: up to ten city_roads are possible if( *contents.get( "city_road[0]" ) ) { // renew them always when a table is encountered ... num_city_roads = 0; for( int i = 0; i < 10; i++ ) { char name[ 256 ]; sprintf( name, "city_road[%i]", i ); // format is "city_road[%i]=name_of_road,using from (year), using to (year)" const char *test = ltrim( contents.get( name ) ); if( *test ) { const char *p = test; while( *p && *p != ',' ) { p++; } tstrncpy( city_roads[ num_city_roads ].name, test, (unsigned)(p - test) + 1 ); // default her: intro/retire=0 -> set later to intro/retire of way-desc city_roads[ num_city_roads ].intro = 0; city_roads[ num_city_roads ].retire = 0; if( *p == ',' ) { ++p; city_roads[ num_city_roads ].intro = atoi( p ) * 12; while( *p && *p != ',' ) { p++; } } if( *p == ',' ) { city_roads[ num_city_roads ].retire = atoi( p + 1 ) * 12; } num_city_roads++; } } } if( num_city_roads == 0 ) { // take fallback value: "city_road" tstrncpy( city_roads[ 0 ].name, "city_road", lengthof( city_roads[ 0 ].name ) ); // default her: always available city_roads[ 0 ].intro = 1; city_roads[ 0 ].retire = NEVER; num_city_roads = 1; } // intercity roads // old syntax for single intercity road str = ltrim( contents.get( "intercity_road_type" ) ); if( str[ 0 ] ) { num_intercity_roads = 1; tstrncpy( intercity_roads[ 0 ].name, str, lengthof( intercity_roads[ 0 ].name ) ); rtrim( intercity_roads[ 0 ].name ); // default her: always available intercity_roads[ 0 ].intro = 1; intercity_roads[ 0 ].retire = NEVER; } // new: up to ten intercity_roads are possible if( *contents.get( "intercity_road[0]" ) ) { // renew them always when a table is encountered ... num_intercity_roads = 0; for( int i = 0; i < 10; i++ ) { char name[ 256 ]; sprintf( name, "intercity_road[%i]", i ); // format is "intercity_road[%i]=name_of_road,using from (year), using to (year)" const char *test = ltrim( contents.get( name ) ); if( *test ) { const char *p = test; while( *p && *p != ',' ) { p++; } tstrncpy( intercity_roads[ num_intercity_roads ].name, test, (unsigned)(p - test) + 1 ); // default her: intro/retire=0 -> set later to intro/retire of way-desc intercity_roads[ num_intercity_roads ].intro = 0; intercity_roads[ num_intercity_roads ].retire = 0; if( *p == ',' ) { ++p; intercity_roads[ num_intercity_roads ].intro = atoi( p ) * 12; while( *p && *p != ',' ) { p++; } } if( *p == ',' ) { intercity_roads[ num_intercity_roads ].retire = atoi( p + 1 ) * 12; } num_intercity_roads++; } } } if( num_intercity_roads == 0 ) { // take fallback value: "asphalt_road" tstrncpy( intercity_roads[ 0 ].name, "asphalt_road", lengthof( intercity_roads[ 0 ].name ) ); // default her: always available intercity_roads[ 0 ].intro = 1; intercity_roads[ 0 ].retire = NEVER; num_intercity_roads = 1; } env_t::autosave = contents.get_int_clamped( "autosave", env_t::autosave, 0, INT_MAX ); // routing stuff max_route_steps = contents.get_int_clamped( "max_route_steps", max_route_steps, 1, INT_MAX ); max_choose_route_steps = contents.get_int_clamped( "max_choose_route_steps", max_choose_route_steps, 1, INT_MAX ); max_hops = contents.get_int_clamped( "max_hops", max_hops, 0, INT_MAX ); max_transfers = contents.get_int_clamped( "max_transfers", max_transfers, 0, INT_MAX ); bonus_basefactor = contents.get_int_clamped( "bonus_basefactor", bonus_basefactor, 0, 1000 ); special_building_distance = contents.get_int_clamped( "special_building_distance", special_building_distance, 1, INT_MAX ); minimum_city_distance = contents.get_int_clamped( "minimum_city_distance", minimum_city_distance, 1, INT_MAX ); industry_increase = contents.get_int_clamped( "industry_increase_every", industry_increase, 0, INT_MAX ); passenger_factor = contents.get_int_clamped( "passenger_factor", passenger_factor, 0, INT_MAX ); /* this can manipulate the passenger generation */ factory_worker_percentage = contents.get_int_clamped( "factory_worker_percentage", factory_worker_percentage, 0, 100 ); factory_worker_radius = contents.get_int_clamped( "factory_worker_radius", factory_worker_radius, 0, 0x7FFF ); factory_worker_minimum_towns = contents.get_int_clamped( "factory_worker_minimum_towns", factory_worker_minimum_towns, 0, 0x7FFF ); factory_worker_maximum_towns = contents.get_int_clamped( "factory_worker_maximum_towns", factory_worker_maximum_towns, 0, 0x7FFF ); factory_arrival_periods = contents.get_int_clamped( "factory_arrival_periods", factory_arrival_periods, 1, 16 ); factory_maximum_intransit_percentage = contents.get_int_clamped( "maximum_intransit_percentage", factory_maximum_intransit_percentage, 0, 0x7FFF ); factory_enforce_demand = contents.get_int( "factory_enforce_demand", factory_enforce_demand ) != 0; tourist_percentage = contents.get_int_clamped( "tourist_percentage", tourist_percentage, 0, 100 ); // .. read twice: old and right spelling separate_halt_capacities = contents.get_int( "seperate_halt_capacities", separate_halt_capacities ) != 0; separate_halt_capacities = contents.get_int( "separate_halt_capacities", separate_halt_capacities ) != 0; pay_for_total_distance = contents.get_int_clamped( "pay_for_total_distance", pay_for_total_distance, 0, 2 ); avoid_overcrowding = contents.get_int( "avoid_overcrowding", avoid_overcrowding ) != 0; no_routing_over_overcrowding = contents.get_int( "no_routing_over_overcrowded", no_routing_over_overcrowding ) != 0; // city stuff passenger_multiplier = contents.get_int_clamped( "passenger_multiplier", passenger_multiplier, 0, 100 ); mail_multiplier = contents.get_int_clamped( "mail_multiplier", mail_multiplier, 0, 100 ); goods_multiplier = contents.get_int_clamped( "goods_multiplier", goods_multiplier, 0, 100 ); electricity_multiplier = contents.get_int_clamped( "electricity_multiplier", electricity_multiplier, 0, 10000 ); growthfactor_small = contents.get_int_clamped( "growthfactor_villages", growthfactor_small, 1, 10000 ); growthfactor_medium = contents.get_int_clamped( "growthfactor_cities", growthfactor_medium, 1, 10000 ); growthfactor_large = contents.get_int_clamped( "growthfactor_capitals", growthfactor_large, 1, 10000 ); env_t::random_pedestrians = contents.get_int("random_pedestrians", env_t::random_pedestrians) != 0; env_t::stop_pedestrians = contents.get_int("stop_pedestrians", env_t::stop_pedestrians) != 0; allow_buying_obsolete_vehicles = contents.get_int( "allow_buying_obsolete_vehicles", allow_buying_obsolete_vehicles ) != 0; used_vehicle_reduction = contents.get_int_clamped( "used_vehicle_reduction", used_vehicle_reduction, 0, 1000 ); traffic_level = contents.get_int_clamped( "citycar_level", traffic_level, 0, 16); stadtauto_duration = contents.get_int_clamped( "default_citycar_life", stadtauto_duration, 0, 1200 ); // starting money starting_money = contents.get_int64( "starting_money", starting_money ); /* up to ten blocks year, money, interpolation={0,1} are possible: * starting_money[i]=y,m,int * y .. year * m .. money (in 1/100 Cr) * int .. interpolation: 0 - no interpolation, !=0 linear interpolated * (m) is the starting money for player start after (y), if (i)!=0, the starting money * is linearly interpolated between (y) and the next greater year given in another entry. * starting money for given year is: */ int j = 0; for( int i = 0; i < 10; i++ ) { char name[ 32 ]; sprintf( name, "starting_money[%i]", i ); const vector_tpl test = contents.get_sint64s( name ); if( (test.get_count() > 1) && (test.get_count() <= 3) ) { // insert sorted by years int k = 0; for( k = 0; k < i; k++ ) { if( startingmoneyperyear[ k ].year > test[ 0 ] ) { for( int l = j; l >= k; l-- ) memcpy( &startingmoneyperyear[ l + 1 ], &startingmoneyperyear[ l ], sizeof( yearmoney ) ); break; } } startingmoneyperyear[ k ].year = (sint16)test[ 0 ]; startingmoneyperyear[ k ].money = test[ 1 ]; if( test.get_count() == 3 ) { startingmoneyperyear[ k ].interpol = test[ 2 ] != 0; } else { startingmoneyperyear[ k ].interpol = false; } j++; } else { // invalid entry } } // at least one found => use this now! if( j > 0 && startingmoneyperyear[ 0 ].money > 0 ) { starting_money = 0; // fill remaining entries for( int i = j + 1; i < 10; i++ ) { startingmoneyperyear[ i ].year = 0; startingmoneyperyear[ i ].money = 0; startingmoneyperyear[ i ].interpol = 0; } } /* up to ten blocks year, locality_factor={0...2000000000} * locality_factor[i]=y,l * y .. year * l .. factor, the larger the more widespread */ j = 0; for( int i = 0; i < 10; i++ ) { char name[ 256 ]; sprintf( name, "locality_factor[%i]", i ); const vector_tpl test = contents.get_sint64s( name ); // two arguments, and then factor natural number if( test.empty() ) { continue; } else if( test.get_count() != 2 ) { // invalid entry dbg->warning("settings_t::parse_simuconf", "Parameter locality_factor[%i] has wrong syntax (Parameter ignored)", i); } else if( test[ 1 ] <= 0 ) { dbg->warning("settings_t::parse_simuconf", "Parameter locality_factor[%i] second value must be larger than zero! (Parameter ignored)", i ); } else { // insert sorted by years int k = 0; for( k = 0; k < i; k++ ) { if( locality_factor_per_year[ k ].year > test[ 0 ] ) { for( int l = j; l >= k; l-- ) memcpy( &locality_factor_per_year[ l + 1 ], &locality_factor_per_year[ l ], sizeof( yearly_locality_factor_t ) ); break; } } locality_factor_per_year[ k ].year = (sint16)test[ 0 ]; locality_factor_per_year[ k ].factor = (uint32)test[ 1 ]; j++; } } // add default, if nothing found if( j == 0 && locality_factor_per_year[ 0 ].factor == 0 ) { locality_factor_per_year[ 0 ].year = 0; locality_factor_per_year[ 0 ].factor = 100; j++; } // fill remaining entries while( j > 0 && j < 9 ) { j++; locality_factor_per_year[ j ].year = 0; locality_factor_per_year[ j ].factor = 0; } // player stuff remove_dummy_player_months = contents.get_int_clamped( "remove_dummy_player_months", remove_dummy_player_months, 0, MAX_PLAYER_HISTORY_YEARS*12 ); // .. read twice: old and correct spelling unprotect_abandoned_player_months = contents.get_int_clamped( "unprotect_abondoned_player_months", unprotect_abandoned_player_months, 0, MAX_PLAYER_HISTORY_YEARS*12 ); unprotect_abandoned_player_months = contents.get_int_clamped( "unprotect_abandoned_player_months", unprotect_abandoned_player_months, 0, MAX_PLAYER_HISTORY_YEARS*12 ); default_player_color_random = contents.get_int( "random_player_colors", default_player_color_random ) != 0; for( int i = 0; i < MAX_PLAYER_COUNT; i++ ) { char name[ 32 ]; sprintf( name, "player_color[%i]", i ); const char *command = contents.get( name ); int c1, c2; if( sscanf( command, "%i,%i", &c1, &c2 ) == 2 ) { default_player_color[ i ][ 0 ] = c1; default_player_color[ i ][ 1 ] = c2; } } default_ai_construction_speed = env_t::default_ai_construction_speed = contents.get_int_clamped( "ai_construction_speed", env_t::default_ai_construction_speed, 0, 1000000000 ); maint_building = contents.get_int_clamped( "maintenance_building", maint_building, 1, 100000000 ); numbered_stations = contents.get_int( "numbered_stations", numbered_stations ) != 0; station_coverage_size = contents.get_int_clamped( "station_coverage", station_coverage_size, 0, 64); // time stuff bits_per_month = contents.get_int_clamped( "bits_per_month", bits_per_month, 1, 31 ); use_timeline = contents.get_int_clamped( "use_timeline", use_timeline, 0, 3 ); starting_year = contents.get_int_clamped( "starting_year", starting_year, 0, 0x7FFF); starting_month = contents.get_int_clamped( "starting_month", starting_month+1, 1, 12 ) - 1; env_t::height_conv_mode = (env_t::height_conversion_mode)contents.get_int_clamped("new_height_map_conversion", (int)env_t::height_conv_mode, 0, env_t::NUM_HEIGHT_CONV_MODES-1); river_number = contents.get_int_clamped( "river_number", river_number, 0, 0x7FFF ); min_river_length = contents.get_int_clamped( "river_min_length", min_river_length, 0, 0x7FFF ); max_river_length = contents.get_int_clamped( "river_max_length", max_river_length, 0, 0x7FFF ); // forest stuff (now part of simuconf.tab) forest_base_size = contents.get_int_clamped( "forest_base_size", forest_base_size, 10, 255 ); forest_map_size_divisor = contents.get_int_clamped( "forest_map_size_divisor", forest_map_size_divisor, 2, 255 ); forest_count_divisor = contents.get_int_clamped( "forest_count_divisor", forest_count_divisor, 2, 255 ); forest_inverse_spare_tree_density = contents.get_int_clamped( "forest_inverse_spare_tree_density", forest_inverse_spare_tree_density, 33, 10000 ); max_no_of_trees_on_square = contents.get_int_clamped( "max_no_of_trees_on_square", max_no_of_trees_on_square, 0, 0xFF ); tree_climates = contents.get_int_clamped( "tree_climates", tree_climates, 0, 0xFFFF ); no_tree_climates = contents.get_int_clamped( "no_tree_climates", no_tree_climates, 0, 0xFFFF ); if (contents.get("no_trees")) { const bool no_trees = contents.get_int("no_trees", tree_distribution == TREE_DIST_NONE); tree_distribution = no_trees ? TREE_DIST_NONE : TREE_DIST_RANDOM; } tree_distribution = contents.get_int_clamped( "tree_distribution", tree_distribution, TREE_DIST_NONE, TREE_DIST_COUNT-1 ); lake_height = (contents.get_int("no_lakes", (lake_height == 0) )) ? 0 : 8; lake_height = contents.get_int_clamped("lake_height", lake_height, 0, INT_MAX ); // these are pak specific; the diagonal length affect travelling time (is game critical) pak_diagonal_multiplier = contents.get_int_clamped("diagonal_multiplier", pak_diagonal_multiplier, 1, INT_MAX ); // the height in z-direction will only cause pixel errors but not a different behaviour env_t::pak_tile_height_step = contents.get_int_clamped("tile_height", env_t::pak_tile_height_step, 1, INT_MAX ); // new height for old slopes after conversion - 1=single height, 2=double height // Must be only overwrite when reading from pak dir ... env_t::pak_height_conversion_factor = contents.get_int_clamped("height_conversion_factor", env_t::pak_height_conversion_factor, 1, 2 ); // minimum clearance under under bridges: 1 or 2? (HACK: value only zero during loading of pak set config) const uint8 bounds = (way_height_clearance!=0); way_height_clearance = contents.get_int_clamped("way_height_clearance", way_height_clearance, bounds, 2 ); min_factory_spacing = contents.get_int_clamped("factory_spacing", min_factory_spacing, 0, 0x7FFF ); min_factory_spacing = contents.get_int_clamped("min_factory_spacing", min_factory_spacing, 0, 0x7FFF ); max_factory_spacing = contents.get_int_clamped("max_factory_spacing", max_factory_spacing, 0, 0x7FFF ); max_factory_spacing_percentage = contents.get_int_clamped("max_factory_spacing_percentage", max_factory_spacing_percentage, 0, 100 ); crossconnect_factor = contents.get_int_clamped("crossconnect_factories_percentage", crossconnect_factor, 0, 100 ); electric_promille = contents.get_int_clamped("electric_promille", electric_promille, 0, 1000 ); crossconnect_factories = contents.get_int("crossconnect_factories", crossconnect_factories ) != 0; env_t::just_in_time = contents.get_int_clamped("just_in_time", env_t::just_in_time, 0, 2); just_in_time = env_t::just_in_time; beginner_price_factor = contents.get_int_clamped("beginner_price_factor", beginner_price_factor, 1, 250000 ); /* this manipulates the good prices in beginner mode */ beginner_mode = contents.get_int("first_beginner", beginner_mode ) != 0; /* start in beginner mode */ way_toll_runningcost_percentage = contents.get_int_clamped("toll_runningcost_percentage", way_toll_runningcost_percentage, 0, 100 ); way_toll_waycost_percentage = contents.get_int_clamped("toll_waycost_percentage", way_toll_waycost_percentage, 0, 100 ); /* now the cost section */ cst_multiply_dock = contents.get_int64("cost_multiply_dock", cst_multiply_dock /(-100) ) * -100; cst_multiply_station = contents.get_int64("cost_multiply_station", cst_multiply_station /(-100) ) * -100; cst_multiply_roadstop = contents.get_int64("cost_multiply_roadstop", cst_multiply_roadstop /(-100) ) * -100; cst_multiply_airterminal = contents.get_int64("cost_multiply_airterminal", cst_multiply_airterminal/(-100) ) * -100; cst_multiply_post = contents.get_int64("cost_multiply_post", cst_multiply_post /(-100) ) * -100; cst_multiply_headquarter = contents.get_int64("cost_multiply_headquarter", cst_multiply_headquarter/(-100) ) * -100; cst_depot_air = contents.get_int64("cost_depot_air", cst_depot_air /(-100) ) * -100; cst_depot_rail = contents.get_int64("cost_depot_rail", cst_depot_rail /(-100) ) * -100; cst_depot_road = contents.get_int64("cost_depot_road", cst_depot_road /(-100) ) * -100; cst_depot_ship = contents.get_int64("cost_depot_ship", cst_depot_ship /(-100) ) * -100; allow_merge_distant_halt = contents.get_int_clamped("allow_merge_distant_halt", allow_merge_distant_halt, 0, INT_MAX); cst_multiply_merge_halt = contents.get_int64("cost_multiply_merge_halt", cst_multiply_merge_halt/(-100) ) * -100; // alter landscape cst_buy_land = contents.get_int64("cost_buy_land", cst_buy_land /(-100) ) * -100; cst_alter_land = contents.get_int64("cost_alter_land", cst_alter_land /(-100) ) * -100; cst_set_slope = contents.get_int64("cost_set_slope", cst_set_slope /(-100) ) * -100; cst_alter_climate = contents.get_int64("cost_alter_climate", cst_alter_climate /(-100) ) * -100; cst_found_city = contents.get_int64("cost_found_city", cst_found_city /(-100) ) * -100; cst_multiply_found_industry = contents.get_int64("cost_multiply_found_industry", cst_multiply_found_industry/(-100) ) * -100; cst_remove_tree = contents.get_int64("cost_remove_tree", cst_remove_tree /(-100) ) * -100; cst_multiply_remove_haus = contents.get_int64("cost_multiply_remove_haus", cst_multiply_remove_haus /(-100) ) * -100; cst_multiply_remove_field = contents.get_int64("cost_multiply_remove_field", cst_multiply_remove_field /(-100) ) * -100; // powerlines cst_transformer = contents.get_int64("cost_transformer", cst_transformer /(-100) ) * -100; cst_maintain_transformer = contents.get_int64("cost_maintain_transformer", cst_maintain_transformer/(-100) ) * -100; cst_make_public_months = contents.get_int64("cost_make_public_months", cst_make_public_months); /* now the way builder */ way_count_straight = contents.get_int_clamped("way_straight", way_count_straight, 1, INT_MAX ); way_count_curve = contents.get_int_clamped("way_curve", way_count_curve, 1, INT_MAX ); way_count_double_curve = contents.get_int_clamped("way_double_curve", way_count_double_curve, 1, INT_MAX ); way_count_90_curve = contents.get_int_clamped("way_90_curve", way_count_90_curve, 1, INT_MAX ); way_count_slope = contents.get_int_clamped("way_slope", way_count_slope, 1, INT_MAX ); way_count_tunnel = contents.get_int_clamped("way_tunnel", way_count_tunnel, 1, INT_MAX ); way_max_bridge_len = contents.get_int_clamped("way_max_bridge_len", way_max_bridge_len, 1, INT_MAX); way_count_leaving_way = contents.get_int_clamped("way_leaving_road", way_count_leaving_way, 1, INT_MAX); way_count_no_way = contents.get_int_clamped("way_no_way", way_count_no_way, 1, INT_MAX); way_count_avoid_crossings = contents.get_int_clamped("way_avoid_crossings", way_count_avoid_crossings, 1, INT_MAX); way_count_maximum = contents.get_int_clamped("way_count_maximum", way_count_maximum, 1, INT_MAX); /* * Selection of savegame format through inifile */ str = contents.get("saveformat" ); while (*str == ' ') str++; if (strcmp(str, "binary") == 0) { loadsave_t::set_savemode(loadsave_t::binary ); } else if(strcmp(str, "zipped") == 0) { loadsave_t::set_savemode(loadsave_t::zipped ); } else if(strcmp(str, "xml") == 0) { loadsave_t::set_savemode(loadsave_t::xml ); } else if(strcmp(str, "xml_zipped") == 0) { loadsave_t::set_savemode(loadsave_t::xml_zipped ); } else if(strcmp(str, "bzip2") == 0) { loadsave_t::set_savemode(loadsave_t::bzip2 ); } else if(strcmp(str, "xml_bzip2") == 0) { loadsave_t::set_savemode(loadsave_t::xml_bzip2 ); } else if(strcmp(str, "zstd") == 0) { loadsave_t::set_savemode(loadsave_t::zstd ); } else if(strcmp(str, "xml_zstd") == 0) { loadsave_t::set_savemode(loadsave_t::xml_zstd ); } str = contents.get("autosaveformat" ); while (*str == ' ') str++; if (strcmp(str, "binary") == 0) { loadsave_t::set_autosavemode(loadsave_t::binary ); } else if(strcmp(str, "zipped") == 0) { loadsave_t::set_autosavemode(loadsave_t::zipped ); } else if(strcmp(str, "xml") == 0) { loadsave_t::set_autosavemode(loadsave_t::xml ); } else if(strcmp(str, "xml_zipped") == 0) { loadsave_t::set_autosavemode(loadsave_t::xml_zipped ); } else if(strcmp(str, "bzip2") == 0) { loadsave_t::set_autosavemode(loadsave_t::bzip2 ); } else if(strcmp(str, "xml_bzip2") == 0) { loadsave_t::set_autosavemode(loadsave_t::xml_bzip2 ); } else if(strcmp(str, "zstd") == 0) { loadsave_t::set_autosavemode(loadsave_t::zstd ); } else if(strcmp(str, "xml_zstd") == 0) { loadsave_t::set_autosavemode(loadsave_t::xml_zstd ); } loadsave_t::save_level = contents.get_int("save_level", loadsave_t::save_level ); loadsave_t::autosave_level = contents.get_int("autosave_level", loadsave_t::autosave_level ); /* * Default resolution */ disp_width = contents.get_int_clamped("display_width", disp_width, 0, 0x7FFF ); disp_height = contents.get_int_clamped("display_height", disp_height, 0, 0x7FFF ); fullscreen = contents.get_int_clamped("fullscreen", fullscreen, 0, 2 ); with_private_paks = contents.get_int("with_private_paks", with_private_paks)!=0; max_rail_convoi_length = contents.get_int_clamped("max_rail_convoi_length", max_rail_convoi_length, 1, 254); max_road_convoi_length = contents.get_int_clamped("max_road_convoi_length", max_road_convoi_length, 1, 254); max_ship_convoi_length = contents.get_int_clamped("max_ship_convoi_length", max_ship_convoi_length, 1, 254); max_air_convoi_length = contents.get_int_clamped("max_air_convoi_length", max_air_convoi_length, 1, 254); // note: no need to check for min_height < max_height, since -12 < 16 world_maximum_height = contents.get_int_clamped("world_maximum_height", world_maximum_height, 16, 127); world_minimum_height = contents.get_int_clamped("world_minimum_height", world_minimum_height, -127, -12); stop_halt_as_scheduled = contents.get_int("stop_halt_as_scheduled", stop_halt_as_scheduled); // Default pak file path objfilename = ltrim(contents.get_string("pak_file_path", objfilename.c_str() ) ); // FluidSynth MIDI parameters if( *contents.get("soundfont_filename") ) { env_t::soundfont_filename = ltrim(contents.get("soundfont_filename")); } env_t::pakset_tutorial_dir = ltrim( contents.get_string("pakset_tutorial_dir", env_t::pakset_tutorial_dir.c_str()) ); } // colour stuff can only be parsed when the graphic system has already started void settings_t::parse_colours(tabfile_t& simuconf) { tabfileobj_t contents; simuconf.read( contents ); env_t::default_window_title_color = contents.get_color("default_window_title_color", env_t::default_window_title_color, &env_t::default_window_title_color_rgb ); env_t::front_window_text_color = contents.get_color("front_window_text_color", env_t::front_window_text_color, &env_t::front_window_text_color_rgb ); env_t::bottom_window_text_color = contents.get_color("bottom_window_text_color", env_t::bottom_window_text_color, &env_t::bottom_window_text_color_rgb ); env_t::tooltip_color = contents.get_color("tooltip_background_color", env_t::tooltip_color, &env_t::tooltip_color_rgb ); env_t::tooltip_textcolor = contents.get_color("tooltip_text_color", env_t::tooltip_textcolor, &env_t::tooltip_textcolor_rgb ); env_t::cursor_overlay_color = contents.get_color("cursor_overlay_color", env_t::cursor_overlay_color, &env_t::cursor_overlay_color_rgb ); env_t::background_color = contents.get_color("background_color", env_t::background_color, &env_t::background_color_rgb ); env_t::bottom_window_darkness = contents.get_int("env_t::bottom_window_darkness", env_t::bottom_window_darkness); } int settings_t::get_name_language_id() const { int lang = -1; if( env_t::networkmode ) { lang = translator::get_language( language_code_names ); } if( lang == -1 ) { lang = translator::get_language(); } return lang; } sint64 settings_t::get_starting_money(sint16 const year) const { if( starting_money>0 ) { return starting_money; } // search entry with startingmoneyperyear[i].year > year int i; for( i=0; i<10; i++ ) { if(startingmoneyperyear[i].year!=0) { if (startingmoneyperyear[i].year>year) { break; } } else { // year is behind the latest given date return startingmoneyperyear[i>0 ? i-1 : 0].money; } } if (i==0) { // too early: use first entry return startingmoneyperyear[0].money; } else { // now: startingmoneyperyear[i-1].year <= year < startingmoneyperyear[i].year if (startingmoneyperyear[i-1].interpol) { // linear interpolation return startingmoneyperyear[i-1].money + (startingmoneyperyear[i].money-startingmoneyperyear[i-1].money) * (year-startingmoneyperyear[i-1].year) /(startingmoneyperyear[i].year-startingmoneyperyear[i-1].year ); } else { // no interpolation return startingmoneyperyear[i-1].money; } } } uint32 settings_t::get_locality_factor(sint16 const year) const { int i; for( i=0; i<10; i++ ) { if( locality_factor_per_year[i].year!=0 ) { if( locality_factor_per_year[i].year > year ) { break; } } else { // year is behind the latest given date return locality_factor_per_year[max(i-1,0)].factor; } } if( i==0 ) { // too early: use first entry return locality_factor_per_year[0].factor; } else { #if 0 // linear interpolation return locality_factor_per_year[i-1].factor + (locality_factor_per_year[i].factor-locality_factor_per_year[i-1].factor) * (year-locality_factor_per_year[i-1].year) /(locality_factor_per_year[i].year-locality_factor_per_year[i-1].year ); #else // exponential evaluation sint32 diff = (locality_factor_per_year[i].factor-locality_factor_per_year[i-1].factor); double a = exp((year-locality_factor_per_year[i-1].year)/20.0); double b = exp((locality_factor_per_year[i].year-locality_factor_per_year[i-1].year)/20.0); return locality_factor_per_year[i-1].factor + (sint32)((diff*(a-1.0))/(b-1.0) + 0.5); #endif } } /** * returns newest way-desc for road_timeline_t arrays * @param roads must be an array with at least @p num_roads elements, no range checks! */ static const way_desc_t *get_timeline_road_type( uint16 year, uint16 num_roads, road_timeline_t* roads) { const way_desc_t *desc = NULL; const way_desc_t *test; for( int i=0; iget_intro_year_month( ); } if( roads[i].retire==0 ) { // fill in real retire date roads[i].retire = test->get_retire_year_month( ); if( roads[i].retire==0 ) { roads[i].retire = NEVER; } } // find newest available ... if( year>=roads[i].intro && yearget_intro_year_month()get_intro_year_month() ) { desc = test; } } } } return desc; } way_desc_t const* settings_t::get_city_road_type(uint16 const year) { return get_timeline_road_type(year, num_city_roads, city_roads ); } uint16 settings_t::get_city_road_speed_limit(uint16 year) { uint16 limit = 50; sint32 last_year = -1; for (int i = 0; i < city_road_speed_limit_num; i += 2) { if (city_road_speed_limit[i] <= year && last_year < city_road_speed_limit[i]) { last_year = city_road_speed_limit[i]; limit = city_road_speed_limit[i + 1]; } } return limit; } way_desc_t const* settings_t::get_intercity_road_type(uint16 const year) { return get_timeline_road_type(year, num_intercity_roads, intercity_roads ); } void settings_t::copy_city_road(settings_t const& other) { num_city_roads = other.num_city_roads; for( int i=0; i<10; i++ ) { city_roads[i] = other.city_roads[i]; } } void settings_t::set_default_player_color(uint8 player_nr, uint8 color1, uint8 color2) { if (player_nr < MAX_PLAYER_COUNT) { default_player_color[player_nr][0] = color1 < 28 ? color1 : 255; default_player_color[player_nr][1] = color2 < 28 ? color2 : 255; } } // returns default player colors for new players void settings_t::set_player_color_to_default(player_t* const player) const { karte_ptr_t welt; uint8 color1 = default_player_color[player->get_player_nr()][0]; if( color1 == 255 ) { if( default_player_color_random ) { // build a vector with all colors minivec_tplall_colors1(28); for( uint8 i=0; i<28; i++ ) { all_colors1.append(i); } // remove all used colors for( uint8 i=0; iget_player(i); if( test_sp && player!=test_sp ) { uint8 rem = 1<<(player->get_player_color1()/8); if( all_colors1.is_contained(rem) ) { all_colors1.remove( rem ); } } else if( default_player_color[i][0]!=255 ) { uint8 rem = default_player_color[i][0]; if( all_colors1.is_contained(rem) ) { all_colors1.remove( rem ); } } } // now choose a random empty color color1 = pick_any(all_colors1); } else { color1 = player->get_player_nr(); } } uint8 color2 = default_player_color[player->get_player_nr()][1]; if( color2 == 255 ) { if( default_player_color_random ) { // build a vector with all colors minivec_tplall_colors2(28); for( uint8 i=0; i<28; i++ ) { all_colors2.append(i); } // remove color1 all_colors2.remove( color1/8 ); // remove all used colors for( uint8 i=0; iget_player(i); if( test_sp && player!=test_sp ) { uint8 rem = 1<<(player->get_player_color2()/8); if( all_colors2.is_contained(rem) ) { all_colors2.remove( rem ); } } else if( default_player_color[i][1]!=255 ) { uint8 rem = default_player_color[i][1]; if( all_colors2.is_contained(rem) ) { all_colors2.remove( rem ); } } } // now choose a random empty color color2 = pick_any(all_colors2); } else { color2 = player->get_player_nr() + 3; } } player->set_player_color( color1*8, color2*8 ); } simutrans-124.3/src/simutrans/dataobj/settings.h000066400000000000000000000522721474050137200220140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_SETTINGS_H #define DATAOBJ_SETTINGS_H #include #include "../simtypes.h" #include "../simconst.h" #include "ribi.h" class player_t; class loadsave_t; class tabfile_t; class way_desc_t; struct road_timeline_t { char name[64]; uint16 intro; uint16 retire; }; /** * Game settings */ class settings_t { // these are the only classes, that are allowed to modify elements from settings_t // for all remaining special cases there are the set_...() routines friend class settings_general_stats_t; friend class settings_routing_stats_t; friend class settings_economy_stats_t; friend class settings_costs_stats_t; friend class settings_frame_t; friend class settings_climates_stats_t; friend class climate_gui_t; friend class welt_gui_t; public: typedef enum { HEIGHT_BASED = 0, HUMIDITY_BASED, MAP_BASED } climate_generate_t; private: sint32 size_x, size_y; sint32 map_number; /* new setting since version 0.85.01 */ sint32 factory_count; sint32 electric_promille; sint32 tourist_attractions; sint32 city_count; sint32 mean_citizen_count; // town growth factors sint32 passenger_multiplier; sint32 mail_multiplier; sint32 goods_multiplier; sint32 electricity_multiplier; // Also there are size dependent factors (0=no growth) sint32 growthfactor_small; sint32 growthfactor_medium; sint32 growthfactor_large; sint16 special_building_distance; // distance between attraction to factory or other special buildings uint32 minimum_city_distance; uint32 industry_increase; // percentage of routing sint16 factory_worker_percentage; sint16 tourist_percentage; // higher number: passengers are more evenly distributed around the map struct yearly_locality_factor_t { sint16 year; uint32 factor; }; yearly_locality_factor_t locality_factor_per_year[10]; // radius for factories sint16 factory_worker_radius; sint32 factory_worker_minimum_towns; sint32 factory_worker_maximum_towns; // number of periods for averaging the amount of arrived pax/mail at factories uint16 factory_arrival_periods; // whether factory pax/mail demands are enforced bool factory_enforce_demand; uint16 station_coverage_size; // the maximum length of each convoi uint8 max_rail_convoi_length; uint8 max_road_convoi_length; uint8 max_ship_convoi_length; uint8 max_air_convoi_length; /** * At which level buildings generate traffic? */ sint32 traffic_level; /** * the maximum and minimum allowed world height. */ sint8 world_maximum_height; sint8 world_minimum_height; /** * waterlevel, climate borders, lowest snow in winter */ climate_generate_t climate_generator; sint16 groundwater; sint16 winter_snowline; sint16 climate_borders[MAX_CLIMATES][2]; sint8 climate_temperature_borders[5]; sint8 tropic_humidity; sint8 desert_humidity; ribi_t::ribi wind_direction; ///< Wind is coming from this direction. Must be single! (N/W/S/E) sint8 patch_size_percentage; // average size of a climate patch, if there are overlapping climates sint8 moisture; // how much increase of moisture per tile sint8 moisture_water; // how much increase of moisture per water tile double max_mountain_height; double map_roughness; // river stuff sint16 river_number; sint16 min_river_length; sint16 max_river_length; // forest stuff uint8 forest_base_size; uint8 forest_map_size_divisor; uint8 forest_count_divisor; uint16 forest_inverse_spare_tree_density; uint8 max_no_of_trees_on_square; uint16 tree_climates; uint16 no_tree_climates; public: enum tree_distribution_t { TREE_DIST_NONE = 0, TREE_DIST_RANDOM = 1, TREE_DIST_RAINFALL = 2, TREE_DIST_COUNT }; private: uint16 tree_distribution; sint8 lake_height; //relative to sea height // game mechanics uint8 allow_player_change; uint8 use_timeline; sint16 starting_year; sint16 starting_month; sint16 bits_per_month; std::string filename; bool beginner_mode; sint32 beginner_price_factor; /* Industry supply model used. * 0 : Classic (no flow control?) * 1 : JIT Classic (maximum transit and storage limited) * 2 : JIT Version 2 (demand buffers with better consumption model) */ uint8 just_in_time; // default 0, will be incremented after each 90 degree rotation until 4 uint8 rotation; sint16 origin_x, origin_y; sint32 passenger_factor; sint16 min_factory_spacing; sint16 max_factory_spacing; sint16 max_factory_spacing_percentage; /*no goods will put in route, when stored>gemax_storage and goods_in_transit*maximum_intransit_percentage/100>max_storage */ uint16 factory_maximum_intransit_percentage; /* crossconnect all factories (like OTTD and similar games) */ bool crossconnect_factories; /* crossconnect all factories (like OTTD and similar games) */ sint16 crossconnect_factor; sint32 stadtauto_duration; bool freeplay; sint64 starting_money; struct yearmoney { sint16 year; sint64 money; bool interpol; }; yearmoney startingmoneyperyear[10]; uint16 num_city_roads; road_timeline_t city_roads[10]; uint16 num_intercity_roads; road_timeline_t intercity_roads[10]; // pairs of year,speed uint16 city_road_speed_limit_num; uint16 city_road_speed_limit[20]; /** * Use numbering for stations? */ bool numbered_stations; /* maximum number of steps for breath search */ sint32 max_route_steps; // maximum length for route search at signs/signals sint32 max_choose_route_steps; // max steps for good routing sint32 max_hops; /* maximum number of steps for breath search */ sint32 max_transfers; /* multiplier for steps on diagonal: * 1024: TT-like, factor 2, vehicle will be too long and too fast * 724: correct one, factor sqrt(2) */ uint16 pak_diagonal_multiplier; // names of the stations ... char language_code_names[4]; // true, if the different capacities (passengers/mail/freight) are counted separately bool separate_halt_capacities; /** * payment is only for the distance that got shorter between target and start * three modes: * 0 = pay for travelled manhattan distance * 1 = pay for distance difference to next transfer stop * 2 = pay for distance to destination * 0 allows chaeting, but the income with 1 or two are much lower */ uint8 pay_for_total_distance; /* if set, goods will avoid being routed over overcrowded stops */ bool avoid_overcrowding; /* if set, goods will not routed over overcrowded stations but rather try detours (if possible) */ bool no_routing_over_overcrowding; // lowest possible income with speedbonus (1000=1) default 125 sint32 bonus_basefactor; // true, if this pak should be used with extensions (default=false) bool with_private_paks = false; /// what is the minimum clearance required under bridges uint8 way_height_clearance; // if true, you can buy obsolete stuff bool allow_buying_obsolete_vehicles; // vehicle value is decrease by this factor/1000 when a vehicle leaved the depot sint16 used_vehicle_reduction; uint32 random_counter; uint32 frames_per_second; // only used in network mode ... uint32 frames_per_step; uint32 server_frames_ahead; bool drive_on_left; bool signals_on_left; // fraction of running costs charged for going on other players way sint32 way_toll_runningcost_percentage; sint32 way_toll_waycost_percentage; // true if transformers are allowed to built underground bool allow_underground_transformers; // true if companies can make ways public bool disable_make_way_public; // only for trains. If true, trains stop at the position designated in the schdule.. bool stop_halt_as_scheduled; public: /* the big cost section */ sint32 maint_building; // normal building sint64 cst_multiply_dock; sint64 cst_multiply_station; sint64 cst_multiply_roadstop; sint64 cst_multiply_airterminal; sint64 cst_multiply_post; sint64 cst_multiply_headquarter; sint64 cst_depot_rail; sint64 cst_depot_road; sint64 cst_depot_ship; sint64 cst_depot_air; // cost to merge station uint32 allow_merge_distant_halt; sint64 cst_multiply_merge_halt; // alter landscape sint64 cst_buy_land; sint64 cst_alter_land; sint64 cst_alter_climate; sint64 cst_set_slope; sint64 cst_found_city; sint64 cst_multiply_found_industry; sint64 cst_remove_tree; sint64 cst_multiply_remove_haus; sint64 cst_multiply_remove_field; sint64 cst_transformer; sint64 cst_maintain_transformer; // maintainance cost in months to make something public sint64 cst_make_public_months; // costs for the way searcher sint32 way_count_straight; sint32 way_count_curve; sint32 way_count_double_curve; sint32 way_count_90_curve; sint32 way_count_slope; sint32 way_count_tunnel; sint32 way_count_no_way; sint32 way_count_avoid_crossings; sint32 way_count_leaving_way; sint32 way_count_maximum; sint32 way_count_way_parallel; uint32 way_max_bridge_len; // 0 = empty, otherwise some value from simplay uint8 player_type[MAX_PLAYER_COUNT]; // how fast new AI will built something uint32 default_ai_construction_speed; // player color suggestions for new games bool default_player_color_random; uint8 default_player_color[MAX_PLAYER_COUNT][2]; // remove dummy companies and remove password from abandoned companies uint16 remove_dummy_player_months; uint16 unprotect_abandoned_player_months; public: /** * If map is read from a heightfield, this is the name of the heightfield. * Set to empty string in order to avoid loading. */ std::string heightfield; settings_t(); void rdwr(loadsave_t *file); void copy_city_road(settings_t const& other); // init from this file ... void parse_simuconf(tabfile_t& simuconf, sint16& disp_width, sint16& disp_height, sint16& fullscreen, std::string& objfilename); // init without screen parameters ... void parse_simuconf(tabfile_t& simuconf) { sint16 idummy = 0; std::string sdummy; parse_simuconf(simuconf, idummy, idummy, idummy, sdummy); } void parse_colours(tabfile_t& simuconf); void set_size_x(sint32 g) {size_x=g;} void set_size_y(sint32 g) {size_y=g;} void set_size(sint32 x, sint32 y) {size_x = x; size_y=y;} sint32 get_size_x() const {return size_x;} sint32 get_size_y() const {return size_y;} sint32 get_map_number() const {return map_number;} void set_factory_count(sint32 d) { factory_count=d; } sint32 get_factory_count() const {return factory_count;} sint32 get_electric_promille() const {return electric_promille;} void set_tourist_attractions( sint32 n ) { tourist_attractions = n; } sint32 get_tourist_attractions() const {return tourist_attractions;} void set_city_count(sint32 n) {city_count=n;} sint32 get_city_count() const {return city_count;} void set_mean_citizen_count( sint32 n ) {mean_citizen_count = n;} sint32 get_mean_citizen_count() const {return mean_citizen_count;} void set_traffic_level(sint32 l) {traffic_level=l;} sint32 get_traffic_level() const {return traffic_level;} sint8 get_maximumheight() const { return world_maximum_height; } sint8 get_minimumheight() const { return world_minimum_height; } sint8 get_groundwater() const {return (sint8)groundwater;} double get_max_mountain_height() const {return max_mountain_height;} double get_map_roughness() const {return map_roughness;} uint16 get_station_coverage() const {return station_coverage_size;} uint8 get_max_rail_convoi_length() const {return max_rail_convoi_length;} uint8 get_max_road_convoi_length() const {return max_road_convoi_length;} uint8 get_max_ship_convoi_length() const {return max_ship_convoi_length;} uint8 get_max_air_convoi_length() const {return max_air_convoi_length;} void set_allow_player_change(char n) {allow_player_change=n;} uint8 get_allow_player_change() const {return allow_player_change;} void set_use_timeline(char n) {use_timeline=n;} uint8 get_use_timeline() const {return use_timeline;} void set_starting_year( sint16 n ) { starting_year = n; } sint16 get_starting_year() const {return starting_year;} void set_starting_month( sint16 n ) { starting_month = n; } sint16 get_starting_month() const {return starting_month;} sint16 get_bits_per_month() const {return bits_per_month;} void set_filename(const char *n) {filename=n;} const char* get_filename() const { return filename.c_str(); } bool get_beginner_mode() const {return beginner_mode;} void set_just_in_time(uint8 b) { just_in_time = b; } uint8 get_just_in_time() const {return just_in_time;} void rotate90() { rotation = (rotation+1)&3; set_size( size_y, size_x ); wind_direction = ribi_t::rotate90(wind_direction); } uint8 get_rotation() const { return rotation; } void set_origin_x(sint16 x) { origin_x = x; } void set_origin_y(sint16 y) { origin_y = y; } sint16 get_origin_x() const { return origin_x; } sint16 get_origin_y() const { return origin_y; } bool is_freeplay() const { return freeplay; } void set_freeplay( bool f ) { freeplay = f; } sint32 get_max_route_steps() const { return max_route_steps; } sint32 get_max_choose_route_steps() const { return max_choose_route_steps; } sint32 get_max_hops() const { return max_hops; } sint32 get_max_transfers() const { return max_transfers; } sint64 get_starting_money(sint16 year) const; sint16 get_special_building_distance() const { return special_building_distance; } sint16 get_min_factory_spacing() const { return min_factory_spacing; } sint16 get_max_factory_spacing() const { return max_factory_spacing; } sint16 get_max_factory_spacing_percent() const { return max_factory_spacing_percentage; } sint16 get_crossconnect_factor() const { return crossconnect_factor; } bool is_crossconnect_factories() const { return crossconnect_factories; } bool get_numbered_stations() const { return numbered_stations; } sint32 get_stadtauto_duration() const { return stadtauto_duration; } sint32 get_beginner_price_factor() const { return beginner_price_factor; } const way_desc_t *get_city_road_type( uint16 year ); const way_desc_t *get_intercity_road_type( uint16 year ); uint16 get_city_road_speed_limit(uint16 year); void set_pak_diagonal_multiplier(uint16 n) { pak_diagonal_multiplier = n; } uint16 get_pak_diagonal_multiplier() const { return pak_diagonal_multiplier; } int get_name_language_id() const; void set_name_language_iso( const char *iso ) { language_code_names[0] = iso[0]; language_code_names[1] = iso[1]; language_code_names[2] = 0; } void set_player_type(uint8 i, uint8 t) { player_type[i] = t; } uint8 get_player_type(uint8 i) const { return player_type[i]; } bool is_separate_halt_capacities() const { return separate_halt_capacities ; } // allowed modes are 0,1,2 enum { TO_PREVIOUS = 0, TO_TRANSFER, TO_DESTINATION }; uint8 get_pay_for_total_distance_mode() const { return pay_for_total_distance ; } // do not take people to overcrowded destinations bool is_avoid_overcrowding() const { return avoid_overcrowding; } // do not allow routes over overcrowded destinations bool is_no_routing_over_overcrowding() const { return no_routing_over_overcrowding; } sint16 get_river_number() const { return river_number; } sint16 get_min_river_length() const { return min_river_length; } sint16 get_max_river_length() const { return max_river_length; } // true, if this pak should be used with extensions (default) void set_with_private_paks(bool b ) { with_private_paks = b; } bool get_with_private_paks() const { return with_private_paks; } sint32 get_passenger_factor() const { return passenger_factor; } // town growth stuff sint32 get_passenger_multiplier() const { return passenger_multiplier; } sint32 get_mail_multiplier() const { return mail_multiplier; } sint32 get_goods_multiplier() const { return goods_multiplier; } sint32 get_electricity_multiplier() const { return electricity_multiplier; } // Also there are size dependent factors (0=no growth) sint32 get_growthfactor_small() const { return growthfactor_small; } sint32 get_growthfactor_medium() const { return growthfactor_medium; } sint32 get_growthfactor_large() const { return growthfactor_large; } // percentage of passengers for different kinds of trips sint16 get_factory_worker_percentage() const { return factory_worker_percentage; } sint16 get_tourist_percentage() const { return tourist_percentage; } // radius from factories to get workers from towns (usually set to 77 but 1/8 of map size may be meaningful too) uint16 get_factory_worker_radius() const { return factory_worker_radius; } // any factory will be connected to at least this number of next cities uint32 get_factory_worker_minimum_towns() const { return factory_worker_minimum_towns; } void set_factory_worker_minimum_towns(uint32 n) { factory_worker_minimum_towns = n; } // any factory will be connected to not more than this number of next cities uint32 get_factory_worker_maximum_towns() const { return factory_worker_maximum_towns; } void set_factory_worker_maximum_towns(uint32 n) { factory_worker_maximum_towns = n; } // number of periods for averaging the amount of arrived pax/mail at factories uint16 get_factory_arrival_periods() const { return factory_arrival_periods; } // whether factory pax/mail demands are enforced bool get_factory_enforce_demand() const { return factory_enforce_demand; } uint16 get_factory_maximum_intransit_percentage() const { return factory_maximum_intransit_percentage; } uint32 get_locality_factor(sint16 year) const; // disallow using obsolete vehicles in depot bool get_allow_buying_obsolete_vehicles() const { return allow_buying_obsolete_vehicles; } // forest stuff uint8 get_forest_base_size() const { return forest_base_size; } uint8 get_forest_map_size_divisor() const { return forest_map_size_divisor; } uint8 get_forest_count_divisor() const { return forest_count_divisor; } uint16 get_forest_inverse_spare_tree_density() const { return forest_inverse_spare_tree_density; } uint8 get_max_no_of_trees_on_square() const { return max_no_of_trees_on_square; } uint16 get_tree_climates() const { return tree_climates; } uint16 get_no_tree_climates() const { return no_tree_climates; } tree_distribution_t get_tree_distribution() const { return (tree_distribution_t)tree_distribution; } void set_tree_distribution(tree_distribution_t value) { tree_distribution = value; } void set_default_climates(); sint8 get_climate_borders( sint8 climate, sint8 start_end ) const { return (sint8)climate_borders[climate][start_end]; } sint8 get_tropic_humidity() const { return tropic_humidity; } sint8 get_desert_humidity() const { return desert_humidity; } sint8 get_climate_temperature_borders( sint8 border ) const { return climate_temperature_borders[border]; } climate_generate_t get_climate_generator() const { return climate_generator; } void set_climate_generator(climate_generate_t generator) { climate_generator = generator; } sint8 get_moisture() const { return moisture; } sint8 get_moisture_water() const { return moisture_water; } sint16 get_winter_snowline() const { return winter_snowline; } sint8 get_lakeheight() const { return lake_height; } void set_lakeheight(sint8 h) { lake_height = h; } /// Wind is coming from this direction ribi_t::ribi get_wind_dir() const { return wind_direction; } ribi_t::ribi get_approach_dir() const { return wind_direction | ribi_t::rotate90(wind_direction); } sint8 get_patch_size_percentage() const { return patch_size_percentage; } uint32 get_industry_increase_every() const { return industry_increase; } void set_industry_increase_every( uint32 n ) { industry_increase = n; } uint32 get_minimum_city_distance() const { return minimum_city_distance; } sint16 get_used_vehicle_reduction() const { return used_vehicle_reduction; } void set_player_color_to_default( player_t *player ) const; void set_default_player_color(uint8 player_nr, uint8 color1, uint8 color2); // usually only used in network mode => no need to set them! uint32 get_random_counter() const { return random_counter; } uint32 get_frames_per_second() const { return frames_per_second; } uint32 get_frames_per_step() const { return frames_per_step; } uint32 get_server_frames_ahead() const { return server_frames_ahead; } bool is_drive_left() const { return drive_on_left; } bool is_signals_left() const { return signals_on_left; } sint32 get_way_toll_runningcost_percentage() const { return way_toll_runningcost_percentage; } sint32 get_way_toll_waycost_percentage() const { return way_toll_waycost_percentage; } sint32 get_bonus_basefactor() const { return bonus_basefactor; } bool get_allow_underground_transformers() const { return allow_underground_transformers; } bool get_disable_make_way_public() const { return disable_make_way_public; } uint32 get_allow_merge_distant_halt() const { return allow_merge_distant_halt; } uint16 get_remove_dummy_player_months() const { return remove_dummy_player_months; } uint16 get_unprotect_abandoned_player_months() const { return unprotect_abandoned_player_months; } uint8 get_way_height_clearance() const { return way_height_clearance; } void set_way_height_clearance( uint8 n ) { way_height_clearance = n; } uint32 get_default_ai_construction_speed() const { return default_ai_construction_speed; } void set_default_ai_construction_speed( uint32 n ) { default_ai_construction_speed = n; } bool get_stop_halt_as_scheduled() const { return stop_halt_as_scheduled; } void set_stop_halt_as_scheduled(bool b) { stop_halt_as_scheduled = b; } // some settigns are not to be saved in the global settings void reset_after_global_settings_reload(); }; #endif simutrans-124.3/src/simutrans/dataobj/sve_cache.cc000066400000000000000000000110421474050137200222200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "sve_cache.h" #include #include "../dataobj/loadsave.h" #include "../utils/simstring.h" #include "../pathes.h" #include "../sys/simsys.h" #include "../simversion.h" #include "../dataobj/environment.h" #include stringhashtable_tpl sve_cache_t::cached_info; sve_info_t::sve_info_t() : pak("") , mod_time(0) , file_size(0) , file_exists(false) { } sve_info_t::sve_info_t(const char *pak_, time_t mod_, sint32 fs) : pak("") , mod_time(mod_) , file_size(fs) { if(pak_) { pak = pak_; file_exists = true; } } bool sve_info_t::operator== (const sve_info_t &other) const { return (mod_time==other.mod_time) && (file_size == other.file_size) && (pak.compare(other.pak)==0); } void sve_info_t::rdwr(loadsave_t *file) { const char *s = strdup(pak.c_str()); file->rdwr_str(s); if (file->is_loading()) { pak = s ? s : ""; } free(const_cast(s)); file->rdwr_longlong(mod_time); file->rdwr_long(file_size); } void sve_cache_t::load_cache() { // load cached entries if (!cached_info.empty()) { // already loaded return; } loadsave_t file; // We rename the old cache file and remove any incomplete read version. // Upon an error the cache will be rebuilt then next time. dr_rename( SAVE_PATH_X "_cached.xml", SAVE_PATH_X "_load_cached.xml" ); if( file.rd_open(SAVE_PATH_X "_load_cached.xml") != loadsave_t::FILE_STATUS_OK ) { return; } // ignore comment const char *text = NULL; file.rdwr_str(text); bool ok = true; do { xml_tag_t t(&file, "save_game_info"); // first filename file.rdwr_str(text); if ((ok = !strempty(text))) { sve_info_t *svei = new sve_info_t(); svei->rdwr(&file); cached_info.put(text, svei); text = NULL; // it is used as key, do not delete it } } while (ok); if (text) { free(const_cast(text)); } file.close(); dr_rename( SAVE_PATH_X "_load_cached.xml", SAVE_PATH_X "_cached.xml" ); } void sve_cache_t::write_cache() { static const char *cache_file = SAVE_PATH_X "_cached.xml"; loadsave_t file; if( file.wr_open(cache_file, loadsave_t::xml, 0, "cache", SAVEGAME_VER_NR) != loadsave_t::FILE_STATUS_OK ) { return; } const char *text = "Automatically generated file. Do not edit. An invalid file may crash the game. Deleting is allowed though."; file.rdwr_str(text); for(auto const& i : cached_info) { // save only existing files if (i.value->file_exists) { xml_tag_t t(&file, "save_game_info"); char const* filename = i.key; file.rdwr_str(filename); i.value->rdwr(&file); } } // mark end with empty entry { xml_tag_t t(&file, "save_game_info"); text = ""; file.rdwr_str(text); } file.close(); } const char *sve_cache_t::get_info(const std::string &fname) { static char date[1024]; std::string pak_extension; // get file information struct stat sb; if (dr_stat(fname.c_str(), &sb) != 0) { // file not found? date[0] = 0; return date; } // check hash table sve_info_t *svei = cached_info.get(fname.c_str()); if (svei && svei->file_size == sb.st_size && svei->mod_time == sb.st_mtime) { // compare size and mtime // if both are equal then most likely the files are the same // no need to read the file for pak_extension pak_extension = svei->pak.c_str(); svei->file_exists = true; } else { // read pak_extension from file loadsave_t test; test.rd_open(fname.c_str()); // add pak extension pak_extension = test.get_pak_extension(); // now insert in hash_table sve_info_t *svei_new = new sve_info_t(pak_extension.c_str(), sb.st_mtime, sb.st_size ); // copy filename char *key = strdup(fname.c_str()); sve_info_t *svei_old = cached_info.set(key, svei_new); delete svei_old; } // write everything in string // add pak extension const size_t n = snprintf( date, lengthof(date), "%s - ", pak_extension.c_str()); // add the time too struct tm *tm = localtime(&sb.st_mtime); if(tm) { strftime(date+n, 18, "%Y-%m-%d %H:%M", tm); } else { tstrncpy(date, "??.??.???? ??:??", lengthof(date)); } date[lengthof(date)-1] = 0; return date; } std::string sve_cache_t::get_most_recent_compatible_save() { const char *best_filename = ""; sint64 best_time = 0; for (stringhashtable_tpl::iterator it = cached_info.begin(); it != cached_info.end(); ++it) { if (it->value->pak+PATH_SEPARATOR == env_t::pak_name && it->value->mod_time > best_time) { best_filename = it->key; best_time = it->value->mod_time; } } return best_filename; } simutrans-124.3/src/simutrans/dataobj/sve_cache.h000066400000000000000000000015311474050137200220640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_SVE_CACHE_H #define DATAOBJ_SVE_CACHE_H #include "../simtypes.h" #include "../tpl/stringhashtable_tpl.h" #include class loadsave_t; class sve_info_t { public: std::string pak; sint64 mod_time; sint32 file_size; bool file_exists; public: sve_info_t(); sve_info_t(const char *pak_, time_t mod_, sint32 fs); public: bool operator==(const sve_info_t &) const; void rdwr(loadsave_t *file); }; class sve_cache_t { static stringhashtable_tpl cached_info; public: static void load_cache(); static void write_cache(); // if the file is not already in the cache, it is added. static const char *get_info(const std::string &fname); static std::string get_most_recent_compatible_save(); }; #endif simutrans-124.3/src/simutrans/dataobj/tabfile.cc000066400000000000000000000514701474050137200217170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #ifdef MAKEOBJ #include "../descriptor/writer/obj_writer.h" #define dr_fopen fopen #endif #include "../sys/simsys.h" #include "../simdebug.h" #include "../descriptor/image.h" #include "koord.h" #include "tabfile.h" #define LINEBUFFER_SIZE (4096) bool tabfile_t::open(const char *filename) { close(); file = dr_fopen(filename, "r"); current_line_number = 0; return file != NULL; } void tabfile_t::close() { if(file) { fclose(file); file = NULL; } } const char *tabfileobj_t::get(const char *key) { obj_info_t *result = objinfo.access(key); if( result ) { result->retrieved = true; return result->str; } return ""; } /** * Get the string value for a key - key must be lowercase * @return def if key isn't found, value otherwise */ const char *tabfileobj_t::get_string(const char *key, const char * def) { obj_info_t *result = objinfo.access(key); if( result ) { result->retrieved = true; return result->str; } return def; } bool tabfileobj_t::put(const char *key, const char *value) { if(objinfo.get(key).str) { return false; } objinfo.put(strdup(key), obj_info_t(false,strdup(value)) ); return true; } void tabfileobj_t::clear() { #ifdef MAKEOBJ obj_writer_t::last_name = ""; #endif for(auto const& i : objinfo) { free(const_cast(i.key)); free(const_cast(i.value.str)); } objinfo.clear(); } // private helps to get x y value pairs needed for koord etc. template bool tabfileobj_t::get_x_y( const char *key, I &x, I &y ) { const char *value = get_string(key,NULL); const char *tmp; if(!value) { return false; } // 2. Determine value for(tmp = value; *tmp != ','; tmp++) { if(!*tmp) { return false; } } x = atoi(value); y = atoi(tmp + 1); return true; } const koord &tabfileobj_t::get_koord(const char *key, koord def) { static koord ret; ret = def; get_x_y( key, ret.x, ret.y ); return ret; } const scr_size &tabfileobj_t::get_scr_size(const char *key, scr_size def) { static scr_size ret; ret = def; get_x_y( key, ret.w, ret.h ); return ret; } PIXVAL tabfileobj_t::get_color(const char *key, PIXVAL def, rgb888_t *color_rgb) { const char *value = get_string(key,NULL); if(!value) { return def; } else { // skip spaces/tabs while ( *value>0 && *value<=32 ) { value ++; } #ifndef MAKEOBJ if( *value=='#' ) { const uint32 v = strtoul( value+1, NULL, 16 ) & 0xFFFFFFul; const rgb888_t col = { (uint8)(v >> 16), (uint8)(v >> 8), (uint8)(v >> 0) }; // we save in settings as RGB888 if (color_rgb) { *color_rgb = col; } // but the functions expect in the system colour (like RGB565) return get_system_color(col); } else { // this inputs also hex correct uint8 index = (uint8)strtoul( value, NULL, 0 ); // we save in settings as RGB888 if (color_rgb) { *color_rgb = get_color_rgb(index); } // but the functions expect in the system colour (like RGB565) return color_idx_to_rgb(index); } #else (void)color_rgb; return (uint8)strtoul( value, NULL, 0 ); #endif } } int tabfileobj_t::get_int(const char *key, int def) { const char *value = get_string(key,NULL); if(!value) { return def; } // skip spaces/tabs while ( *value>0 && *value<=32 ) { value ++; } // this inputs also hex correct return strtol( value, NULL, 0 ); } int tabfileobj_t::get_int_clamped(const char *key, int def, int min_value, int max_value) { const int int_value = get_int(key, def); const int clamped_value = clamp(int_value, min_value, max_value); if (clamped_value != int_value) { dbg->warning("tabfileobj_t::get_int_clamped()", "Value %d for key %s out of range %d..%d, resetting to %d", int_value, key, min_value, max_value, clamped_value); } return clamped_value; } sint64 atosint64(const char* a) { return (sint64)(atof(a)+0.5); } sint64 tabfileobj_t::get_int64(const char *key, sint64 def) { const char *value = get_string(key,NULL); if(!value) { return def; } else { return atosint64(value); } } vector_tpl tabfileobj_t::get_ints(const char *key) { const char *value = get_string(key,NULL); const char *tmp; int count = 0; vector_tpl result; if(!value) { return result; } // Determine number for(tmp = value; *tmp; tmp++) { if(*tmp == ',') { count++; } } // Create result vector and fill result.reserve(count); result.append(strtol( value, NULL, 0 )); for(tmp = value; *tmp; tmp++) { if(*tmp == ',') { // skip spaces/tabs do { tmp ++; } while ( *tmp>0 && *tmp<=32 ); // this inputs also hex correct result.append(strtol( tmp, NULL, 0 )); } } return result; } vector_tpl tabfileobj_t::get_sint64s(const char *key) { const char *value = get_string(key,NULL); const char *tmp; int count = 0; vector_tpl result; if(!value) { return result; } // Determine number for(tmp = value; *tmp; tmp++) { if(*tmp == ',') { count++; } } // Create result vector and fill result.reserve(count); result.append(atosint64(value)); for(tmp = value; *tmp; tmp++) { if(*tmp == ',') { result.append(atosint64(tmp + 1)); } } return result; } void tabfileobj_t::unused( const char *exclude_start_chars ) { for(auto const& i : objinfo) { if( !i.value.retrieved ) { // never retrieved if( !exclude_start_chars || !strchr( exclude_start_chars, *i.value.str ) ) { #ifdef MAKEOBJ dbg->warning( obj_writer_t::last_name, "Entry \"%s=%s\" ignored (check spelling)", i.key, i.value.str ); #else dbg->warning( "tabfile_t", "Entry \"%s=%s\" ignored (check spelling)", i.key, i.value.str ); #endif } objinfo.access( i.key )->retrieved = true; } } } bool tabfile_t::read(tabfileobj_t &objinfo, FILE *fp) { bool lines = false; char line[LINEBUFFER_SIZE]; char line_expand[LINEBUFFER_SIZE]; char delim_expand[LINEBUFFER_SIZE]; char buffer[LINEBUFFER_SIZE]; char *param[10]; char *expansion[10]; current_line_number = 0; objinfo.clear(); do { while(read_line(line, sizeof(line)) && *line != '-') { char *delim = strchr(line, '='); if(delim) { *delim++ = '\0'; format_key(line); if (line[0] == 0) { return false; } int parameters = 0; int expansions = 0; /* @line, the whole parameter text (everything before =) @delim, the whole value text (everything after =) @parameters, number of fields enclosed by square brackets [] @expansions, number of expansions included in the value (text inside angle brackets <>) @param, array containing the text inside each [] field @expansion, array containing the text inside each <> field */ if(find_parameter_expansion(line, delim, ¶meters, &expansions, param, expansion) > 0) { int parameter_value[10][256]; int parameter_length[10]; int parameter_values[10]; // number of possible 'values' inside each [] field | e.g. [0-4]=5 / [n,s,w]=3 char parameter_name[256][6]; // non-numeric ribis strings for all parameter fields consecutively bool parameter_ribi[10]; // true if parameters are ribi strings int combinations=1; int names = 0; // total number of ribi parameters // analyse and obtain all parameter expansions for(int i=0; i= 256) { dbg->fatal("tabfile_t::read", "Invalid number range %d-%d (Max range %d values) in line %d", start_range, end_range, 256 - parameter_values[i], current_line_number); } for(int range=start_range; range0) { // warp values around the number of parameters the expansion has for(int j=0; j0) { int expansion_length[10]; int expansion_value[10]; for(int i=0; i")-1; sprintf(buffer, "%.*s", expansion_length[i]+1, expansion[i]); expansion_value[i] = calculate(buffer, parameter_value, parameters, combination); } sprintf(delim_expand, "%.*s%d", (int)(expansion[0]-delim), delim, expansion_value[0]); for(int i=1; imessage("tabfile_t::read", "Parameter expansion: %s = %s", line_expand, delim_expand); objinfo.put(line_expand, delim_expand); if (fp != NULL) { fprintf(fp, "%s=%s\n", line_expand, delim_expand); } } } else { objinfo.put(line, delim); if (fp != NULL) { fprintf(fp, "%s=%s\n", line, delim); } } lines = true; } else if( *line ) { dbg->warning( "tabfile_t::read", "No data in \"%s\"", line ); } } } while(!lines && !feof(file)); // skip empty objects return lines; } bool tabfile_t::read_line(char *dest, size_t dest_size) { char *r; size_t l; do { current_line_number++; r = fgets(dest, dest_size, file); } while(r != NULL && (*dest == '#' || *dest == ' ') ); if(r) { l = strlen(r); while( l && (r[l-1] == '\n' || r[l-1] == '\r') ) { r[--l] = '\0'; } } return r != NULL; } int tabfile_t::find_parameter_expansion(char *key, char *data, int *parameters, int *expansions, char *param_ptr[10], char *expansion_ptr[10]) { // find params in key bool in_bracket = false; for(char *s = key; *s; s++) { if(*s == '[') { in_bracket = true; bool parameter = false; s++; char *t = s; while(*s && *s != ']') { if( (*s == ',' || *s == '-') && *(s-1) != '[' ) { parameter = true; } s++; } if(parameter) { if (*parameters >= 10) { dbg->error("tabfile_t::find_parameter_expansion", "Too many parameters (Only 10 allowed)"); return 0; } param_ptr[*parameters] = t; (*parameters)++; } } else if (*s == ']') { if (!in_bracket) { dbg->error("tabfile_t::find_parameter_expansion", "Found ']' before '['"); return 0; // invalid key } else { in_bracket = false; } } else if (!isalpha(*s) && !isdigit(*s) && *s != '_' && *s != '.') { // only allow [a-zA-Z0-9_.] in keys ('.' is required for city rules) dbg->error("tabfile_t::find_parameter_expansion", "Found invalid character '%c' in key of parameter expansion (Only alphanumeric characters, '.' and '_' allowed)", *s); return 0; } } // find expansions in data for(char *s = data; *s; s++) { if(*s == '<') { char *t = s; while(*s) { if(*s == '>') { if (*expansions >= 10) { dbg->error("tabfile_t::find_parameter_expansion", "Too many expansions (only $0 .. $9 allowed)"); return 0; } expansion_ptr[*expansions] = t; (*expansions)++; break; } s++; } } } return (*parameters)+(*expansions); } int tabfile_t::calculate(char *expression, const int (¶meter_value)[10][256], int parameters, int combination[10]) { char processed[LINEBUFFER_SIZE]; add_operator_parens(expression, processed); return calculate_internal(processed, parameter_value, parameters, combination, 0); } void tabfile_t::add_operator_parens(char *expression, char *processed) { char buffer[LINEBUFFER_SIZE]; char operators[5] = { '%','/','*','-','+' }; // first remove any spaces int j = 0; for(uint16 i = 0; i<=strlen(expression); i++) { if(expression[i]!=' ') { buffer[j++]=expression[i]; } } strcpy(processed, buffer); // add brackets around each operator to ensure processed in correct order // e.g. v+w*x+y/z becomes (((v+(w*x))+(y/z)) and x/y/z = ((x/y)/z) // for each operator take 'a operator b' and turn into '(a operator b)' for(size_t operator_loop = 0 ; operator_loop=processed && !expression_start) { switch(expression_pos[0]) { case ')': { int paren_level = 1; expression_start = expression_pos-1; while(expression_start>processed && paren_level>0) { switch(expression_start[0]) { case ')': paren_level++; break; case '(': paren_level--; break; } expression_start--; } if(paren_level>0) { dbg->fatal( "tabfile_t::add_operator_parens", "Mismatched parentheses in line %d", current_line_number ); } break; } case '%': case '/': case '*': case '+': case '-': case '(': case '<': expression_start = expression_pos; break; } expression_pos--; } if(expression_start==NULL) { expression_start = expression_pos; } // find b expression_pos = expression_ptr+1; char *expression_end = NULL; while(expression_pos[0]!='\0' && !expression_end) { switch(expression_pos[0]) { case '(': { int paren_level = 1; expression_end = expression_pos+1; while(expression_end[0]!='\0' && paren_level>0) { switch(expression_end[0]) { case '(': paren_level++; break; case ')': paren_level--; break; } expression_end++; } if(paren_level>0) { dbg->fatal( "tabfile_t::add_operator_parens", "Mismatched parentheses in line %d", current_line_number ); } break; } case '%': case '/': case '*': case '+': case '-': expression_end = expression_pos; break; } expression_pos++; } if(expression_end==NULL) { expression_end = expression_pos; } // construct expression with brackets around 'a operator b' const int prefix_len = (int)(expression_start-processed+1); const int lhs_len = (int)(expression_ptr-expression_start-1); const int rhs_len = (int)(expression_end-expression_ptr); const int suffix_len = strlen(expression_end); // make sure we have enough room if (prefix_len + 1 + lhs_len + rhs_len + 1 + suffix_len >= LINEBUFFER_SIZE-1) { dbg->fatal("tabfile_t::add_operator_parens", "Line too long to add operators in line %d", current_line_number); } sprintf(buffer,"%.*s(%.*s%.*s)%s", prefix_len, processed, lhs_len, expression_start+1, rhs_len, expression_ptr, expression_end); strcpy(processed, buffer); operator_count++; expression_ptr = strchr(processed, operators[operator_loop]); for(int i=0; ifatal("tabfile_t::calculate_internal", "Unable to tokenize '%s' in line %d", expression, current_line_number); } if(token_ptr[0]=='(') { token_ptr++; } while (token_ptr= 0 && parameter < parameters) { value = parameter_value[parameter][combination[parameter]]; } else { dbg->fatal("tabfile_t::calculate_internal", "Invalid reference to parameter $%d in line %d", parameter, current_line_number); } } else if(token_ptr[0]=='(') { size_t paren_expression_len; int paren_level=1; for(paren_expression_len=1; paren_expression_len0; paren_expression_len++) { switch(original[token_ptr-expression+paren_expression_len]) { case '(': paren_level++; break; case ')': paren_level--; break; } } // Note: We have to avoid too deep recursion here to avoid a stack overflow (each recursion adds > 8 kB to the stack) if (paren_expression_len >= LINEBUFFER_SIZE-1 || nest_level > 20) { dbg->fatal("tabfile_t::calculate_internal", "Cannot calculate expression (too nested or line too long) in line %d", current_line_number); } char buffer[LINEBUFFER_SIZE]; sprintf(buffer, "%.*s", (int)paren_expression_len, original+(token_ptr-expression)-1); value = calculate_internal(buffer+1, parameter_value, parameters, combination, nest_level+1); token_ptr += paren_expression_len; } else { value = atoi(token_ptr); } switch(operator_char) { case '+': answer += value; break; case '-': answer -= value; break; case '*': answer *= value; break; case '/': if (value == 0) { dbg->fatal("tabfile_t::calculate_internal", "Cannot divide by 0 in line %d", current_line_number); } answer /= value; break; case '%': if (value == 0) { dbg->fatal("tabfile_t::calculate_internal", "Cannot divide modulo 0 in line %d", current_line_number); } answer %= value; break; case '<': case '(': answer = value; break; } token_ptr += strcspn(token_ptr, "<-+*/%")+1; } return answer; } void tabfile_t::format_key(char *key) { char *s = key + strlen(key); char *t; // trim right while(s > key && s[-1] == ' ') { *--s = '\0'; } // make lowercase for(s = key; *s; s++) { *s = tolower(*s); } // skip spaces inside [] for(s = t = key; *s; s++) { if(*s == '[') { *t++ = *s++; while(*s && *s != ']') { if(*s == ' ') { s++; } else { *t++ = *s++; } } s--; } else { *t++ = *s; } } *t = '\0'; } simutrans-124.3/src/simutrans/dataobj/tabfile.h000066400000000000000000000116321474050137200215550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_TABFILE_H #define DATAOBJ_TABFILE_H #include #include "../simcolor.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" class tabfileobj_t; class koord; class scr_coord; class scr_size; class obj_info_t { public: bool retrieved; const char *str; obj_info_t() { retrieved=false; str=0; } obj_info_t(bool b, const char *s ) { retrieved=b; str=s; } }; /** * This class can be used instead of FILE to read a game definition file, * usually with extension .tab in simutrans. * For the start only bridges.tab is read by this class. * Maybe we can make it a standard class for all tab-files, using the same * format in all. * * File format: * - Lines starting with '#' or ' ' are comment lines. * - The file content is treated as a list of objects. * - Objects are separated by a line starting with a dash (-) * - Each object can contain any number of lines in the format '<Key>=' * These line are NOT ordered * - If keys are duplicated for one object, the first value is used * - Keys are not case sensitive */ class tabfile_t { public: tabfile_t() : file(NULL) {} ~tabfile_t() { close(); } public: bool open(const char *filename); void close(); /** * Read an entire object from the open file. * * @param[out] objinfo will receive the object info * @param fp file * @return bool false, if empty object or eof */ bool read(tabfileobj_t &objinfo, FILE *fp = NULL); private: /** * Read one non-comment line from input. * Lines starting with ' ' are comment lines here. This differs from the * global read_line() function. * * @param dest line buffer * @param dest_size size of line buffer * * @returns false in case of eof */ bool read_line(char *dest, size_t dest_size); /** * Return parameters and expansions */ int find_parameter_expansion(char *key, char *data, int *parameters, int *expansions, char *parameter_ptr[10], char *expansion_ptr[10]); /** * Calculates expression provided in buffer, substituting parameters provided */ int calculate(char *expression, const int (¶meter_value)[10][256], int parameters, int combination[10]); /** * Adds brackets to expression to ensure calculate_internal processes expression correctly */ void add_operator_parens(char *expression, char *processed); /** * Calculates expression provided in buffer (do not call directly!) */ int calculate_internal(char *expression, const int (¶meter_value)[10][256], int parameters, int combination[10], int nest_level); /** * Format the key string (trimright and lowercase) */ void format_key(char *key); private: FILE *file; int current_line_number; }; /* * This class represents an object read from a tabfile_t. * It contains all strings key/value pairs read by tabfile_t::read(). * It may be reused for reading more objects. */ class tabfileobj_t { private: stringhashtable_tpl objinfo; template bool get_x_y( const char *key, I &x, I &y ); public: tabfileobj_t() { } ~tabfileobj_t() { clear(); } /** * prints all unused options lines in the file which do not start with a character from exclude_start_chars */ void unused( const char *exclude_start_chars ); /** * add a key/value pair - should only be used be tabfile_t::read */ bool put(const char *key, const char *value); /** * reinitializes this object */ void clear(); /** * Get the value for a key - key must be lowercase * * @return const char *returns at least an empty string, never NULL. */ const char *get(const char *key); /** * Get the string value for a key - key must be lowercase * @return def if key isn't found, value otherwise */ const char *get_string(const char *key, const char * def); /** * Get the value for a koord key - key must be lowercase * * @return def, if key is not found */ const koord &get_koord(const char *key, koord def); const scr_size &get_scr_size(const char *key, scr_size def); /** * Get a color in the system format when given a #AABBCC * and optionally set RGB888 for a chosen var with color_rgb */ PIXVAL get_color(const char *key, PIXVAL def, rgb888_t *color_rgb = NULL); /** * Get an int */ int get_int(const char *key, int def); /** * Get an int value. If the value is not between @p min_value and @p max_value, a warning * is emitted and the value is clamped to either @p min_value or @p max_value. */ int get_int_clamped(const char *key, int def, int min_value, int max_value); /** * Get an sint64 (actually uses double, thus only 48 bits are retrievable) */ sint64 get_int64(const char *key, sint64 def); /** * Parses a value with the format ",,..," * and returns a vector with these values. */ vector_tpl get_ints(const char *key); vector_tpl get_sint64s(const char *key); }; #endif simutrans-124.3/src/simutrans/dataobj/translator.cc000066400000000000000000000572621474050137200225070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include "../macros.h" #include "../simdebug.h" #include "../sys/simsys.h" #include "../simtypes.h" #include "../display/simgraph.h" // for unicode stuff #include "translator.h" #include "loadsave.h" #include "environment.h" #include "../simmem.h" #include "../utils/cbuffer.h" #include "../utils/searchfolder.h" #include "../utils/simstring.h" #include "../utils/unicode.h" #include "../tpl/vector_tpl.h" using std::string; // allow all kinds of line feeds static char *fgets_line(char *buffer, int max_len, FILE *file) { char *result = fgets(buffer, max_len, file); size_t len = strlen(buffer); // remove all trailing junk while( len>1 && (buffer[len-1]==13 || buffer[len-1]==10) ) { buffer[len-1] = 0; len--; } return result; } const char *translator::lang_info::translate(const char *text) const { if( text == NULL ) { return "(null)"; } if( text[0] == '\0' ) { return text; } const char *trans = texts.get(text); return trans != NULL ? trans : text; } /* Made to be dynamic, allowing any number of languages to be loaded */ static translator::lang_info langs[40]; static translator::lang_info *current_langinfo = langs; static stringhashtable_tpl compatibility; translator translator::single_instance; const translator::lang_info* translator::get_lang() { return current_langinfo; } const translator::lang_info* translator::get_langs() { return langs; } /* first two file functions needed in connection with utf */ /** * checks, if we need a unicode translation */ static bool is_unicode_file(FILE* f) { unsigned char str[2]; int pos = ftell(f); // DBG_DEBUG("is_unicode_file()", "checking for unicode"); // fflush(NULL); if (fread( str, 1, 2, f ) != 2) { return false; } // DBG_DEBUG("is_unicode_file()", "file starts with %x%x",str[0],str[1]); // fflush(NULL); if (str[0] == 0xC2 && str[1] == 0xA7) { // the first line must contain an UTF8 coded paragraph (Latin A7, UTF8 C2 A7), then it is unicode DBG_DEBUG("is_unicode_file()", "file is UTF-8"); return true; } if( str[0]==0xEF && str[1]==0xBB && fgetc(f)==0xBF ) { // the first letter is the byte order mark => may need to skip a paragraph (Latin A7, UTF8 C2 A7) pos = ftell(f); if (fread( str, 1, 2, f ) != 2) { return false; } if( str[0] != 0xC2 || str[1] == 0xA7 ) { fseek(f, pos, SEEK_SET); dbg->error( "is_unicode_file()", "file is UTF-8 but has no paragraph" ); } DBG_DEBUG("is_unicode_file()", "file is UTF-8"); return true; } fseek(f, pos, SEEK_SET); return false; } // recodes string to put them into the tables static char *recode(const char *src, bool translate_from_utf, bool translate_to_utf, bool is_latin2 ) { char *base; if( translate_to_utf != translate_from_utf ) { // worst case base = MALLOCN(char, strlen(src) * 2 + 2); } else { base = MALLOCN(char, strlen(src) + 2); } char *dst = base; uint8 c = 0; do { if (*src =='\\') { if (*(src + 1) == 0) { // backslash at end of line -> corrupted break; } src += 2; *dst++ = c = '\n'; } else { c = *src; if(c>127) { if( translate_from_utf == translate_to_utf ) { // but copy full letters! (or, if ASCII, copy more than one letter, does not matter do { *dst++ = *src++; } while (is_cont_char(*src)); c = *src; } else if( translate_to_utf ) { if( !is_latin2 ) { // make UTF8 from latin1 dst += c = utf16_to_utf8((unsigned char)*src++, (utf8*)dst); } else { dst += c = utf16_to_utf8( latin2_to_unicode( (uint8)*src++ ), (utf8*)dst ); } } else if( translate_from_utf ) { // make latin from UTF8 (ignore overflows!) const utf8 *p = reinterpret_cast(src); if( !is_latin2 ) { *dst++ = c = (uint8)utf8_decoder_t::decode(p); } else { *dst++ = c = unicode_to_latin2(utf8_decoder_t::decode(p)); } src = reinterpret_cast(p); } } else if(c>=13) { // just copy src ++; *dst++ = c; } else { // ignore this character src ++; } } } while (c != '\0'); *dst = 0; return base; } // List of custom city and streetnames vector_tpl translator::city_name_list; vector_tpl translator::street_name_list; // fills a list from a file with the given prefix followed by a language code void translator::load_custom_list( int lang, vector_tpl&name_list, const char *fileprefix ) { FILE *file; // Clean up all names for(char* const i : name_list) { free(i); } name_list.clear(); // first try in pakset { string local_file_name(env_t::user_dir); local_file_name = local_file_name + "addons/" + env_t::pak_name + "text/" + fileprefix + langs[lang].iso_base + ".txt"; DBG_DEBUG("translator::load_custom_list()", "try to read city name list from '%s'", local_file_name.c_str()); file = dr_fopen(local_file_name.c_str(), "rb"); } // not found => try user location if( file==NULL ) { string local_file_name(env_t::user_dir); local_file_name = local_file_name + fileprefix + langs[lang].iso_base + ".txt"; file = dr_fopen(local_file_name.c_str(), "rb"); DBG_DEBUG("translator::load_custom_list()", "try to read city name list from '%s'", local_file_name.c_str()); } // not found => try pak location if( file==NULL ) { string local_file_name(env_t::pak_dir + "text/" + fileprefix + langs[lang].iso_base + ".txt"); DBG_DEBUG("translator::load_custom_list()", "try to read city name list from '%s'", local_file_name.c_str()); file = dr_fopen(local_file_name.c_str(), "rb"); } // not found => try global translations if( file==NULL ) { string local_file_name(env_t::base_dir); local_file_name = local_file_name + "text/" + fileprefix + langs[lang].iso_base + ".txt"; DBG_DEBUG("translator::load_custom_list()", "try to read city name list from '%s'", local_file_name.c_str()); file = dr_fopen(local_file_name.c_str(), "rb"); } fflush(NULL); if (file != NULL) { // ok, could open file char buf[256]; bool file_is_utf = is_unicode_file(file); while( !feof(file) ) { if (fgets_line(buf, sizeof(buf), file)) { rtrim(buf); char *c = recode(buf, file_is_utf, true, langs[lang].is_latin2_based ); if( *c!=0 && *c!='#' ) { name_list.append(c); } } } fclose(file); DBG_DEBUG("translator::load_custom_list()","Loaded list %s_%s.txt.", fileprefix, langs[lang].iso_base ); } else { DBG_DEBUG("translator::load_custom_list()","No list %s_%s.txt found, using defaults.", fileprefix, langs[lang].iso_base ); } } /** * the city list is now reloaded after the language is changed * new cities will get their appropriate names */ void translator::init_custom_names(int lang) { // init names. There are two options: // // 1.) read list from file // 2.) create random names (only for cities) // try to read list load_custom_list( lang, city_name_list, "citylist_" ); load_custom_list( lang, street_name_list, "streetlist_" ); if (city_name_list.empty()) { DBG_MESSAGE("translator::init_city_names", "reading failed, creating random names."); // try to read list failed, create random names for( uint i = 0; i < 36; i++ ) { char name[32]; sprintf( name, "%%%c_CITY_SYLL", i+(i<10 ? '0' : 'A'-10 ) ); const char *s1 = translator::translate(name,lang); if(s1==name) { // name not available ... continue; } // now add all second name extensions ... const size_t l1 = strlen(s1); for( uint j = 0; j < 36; j++ ) { sprintf( name, "&%c_CITY_SYLL", j+(j<10 ? '0' : 'A'-10 ) ); const char *s2 = translator::translate(name,lang); if(s2==name) { // name not available ... continue; } const size_t l2 = strlen(s2); char *const c = MALLOCN(char, l1 + l2 + 1); sprintf(c, "%s%s", s1, s2); city_name_list.append(c); } } } } /* now on to the translate stuff */ static bool is_special_format_string(const char* str) { // %._CITY_SYLL if (*str == '%' && *(str+1) && strcmp(str+2, "_CITY_SYLL")==0) { return true; } // .center, .suburb, .extern if (*str && (strcmp(str+1, "center")==0 || strcmp(str+1, "suburb")==0 || strcmp(str+1, "extern")==0) ) { return true; } return false; } static void load_language_file_body(FILE* file, stringhashtable_tpl* table, bool language_is_utf, bool file_is_utf, bool language_is_latin2 ) { char buffer1 [4096]; char buffer2 [4096]; bool convert_to_unicode = language_is_utf && !file_is_utf; do { fgets_line(buffer1, sizeof(buffer1), file); if( buffer1[0] == '#' ) { // ignore comments continue; } if( !feof(file) ) { fgets_line(buffer2, sizeof(buffer2), file); if( strcmp(buffer1,buffer2) ) { // only add line which are actually different char *raw = recode(buffer1, file_is_utf, false, language_is_latin2 ); char *translated = recode(buffer2, false, convert_to_unicode,language_is_latin2); char *repaired = NULL; // check format strings (only for unicode, ignore special strings) if(language_is_utf) { if (!is_special_format_string(raw)) { // check and possibly repair the format string if (!cbuffer_t::check_and_repair_format_strings(raw, translated, &repaired) ) { free(raw); free(translated); continue; } } } if (repaired) { free(translated); translated = repaired; } table->set( raw, translated ); } } } while (!feof(file)); } void translator::load_language_file(FILE* file) { char buffer1[256]; bool file_is_utf = is_unicode_file(file); // Read language name fgets_line(buffer1, sizeof(buffer1), file); langs[single_instance.lang_count].name = strdup(buffer1); if( !file_is_utf ) { // find out the font if not unicode (and skip it) while( !feof(file) ) { fgets_line( buffer1, sizeof(buffer1), file ); if( buffer1[0] == '#' ) { continue; } if( strcmp(buffer1,"PROP_FONT_FILE") == 0 ) { fgets_line( buffer1, sizeof(buffer1), file ); // HACK: so we guess about latin2 from the font name! langs[single_instance.lang_count].is_latin2_based = STRNICMP( buffer1+5, "latin2", 6 )==0; // we must register now a unicode font langs[single_instance.lang_count].texts.set( "PROP_FONT_FILE", langs[single_instance.lang_count].is_latin2_based ? "cyr.bdf" : strdup(buffer1) ); break; } } } else { // since it is anyway UTF8 langs[single_instance.lang_count].is_latin2_based = false; } //load up translations, putting them into //language table of index 'lang' load_language_file_body(file, &langs[single_instance.lang_count].texts, true, file_is_utf, langs[single_instance.lang_count].is_latin2_based ); } static translator::lang_info* get_lang_by_iso(const char *iso) { for( translator::lang_info* i = langs; i != langs + translator::get_language_count(); ++i ) { if( i->iso_base[0] == iso[0] && i->iso_base[1] == iso[1] ) { return i; } } return NULL; } static uint32 get_highest_character( const utf8 *str ) { size_t len = 0; uint32 max_char = 0, symbol; do { symbol = utf8_decoder_t::decode( str, len ); str += len; if( symbol > max_char ) { max_char = symbol; } } while( symbol > 0 ); return max_char; } uint32 translator::guess_highest_unicode(int n) { const char* T1 = langs[n].texts.get( "Bruecke muss an\neinfachem\nHang beginnen!\n" ); uint32 max_char = 0xDF; if( T1 ) { max_char = get_highest_character( (const utf8 *)T1 ); } const char* T2 = langs[n].texts.get( "Start" ); if( T2 ) { uint32 max_char2 = get_highest_character( (const utf8 *)T2 ); max_char = max( max_char, max_char2 ); } return max_char; } void translator::load_files_from_folder(const char *folder_name, const char *what) { searchfolder_t folder; const int num_pak_lang_dat = folder.search(folder_name, "tab"); DBG_MESSAGE("translator::load_files_from_folder()", "search folder \"%s\" and found %i files", folder_name, num_pak_lang_dat); (void)num_pak_lang_dat; // read now the basic language infos // we allow either "LA.*.tab" or "*.LA.tab" whe LA is the ISO language code for(const char* const& filename : folder) { lang_info* lang = NULL; const char *filestr1 = strrchr(filename, '/'); const char *filestr2 = strrchr(filename, '\\'); const char *filestr = filestr1 > filestr2 ? filestr1 : filestr2; if (filestr) { if( filestr[3] == '.' ) { // try the start of the string first lang = get_lang_by_iso(filestr + 1); } } else if(filename[2] == '.') { // try the start of the filename if no path separator found lang = get_lang_by_iso(filename); } if (!lang) { const char *langcode = strrchr(filename, '.'); if( langcode ) { if( ((langcode - filename) > 3 && !isalnum(langcode[-3])) || (langcode - filename) == -2 ) { // try before the point lang = get_lang_by_iso(langcode - 2); } } } if (lang != NULL) { DBG_MESSAGE("translator::load_files_from_folder()", "loading %s translations from %s for language %s", what, filename, lang->iso_base); if (FILE* const file = dr_fopen(filename, "rb")) { bool file_is_utf = is_unicode_file(file); load_language_file_body(file, &lang->texts, true, file_is_utf, lang->is_latin2_based ); fclose(file); } else { dbg->warning("translator::load_files_from_folder()", "cannot open '%s'", filename); } } else { dbg->warning("translator::load_files_from_folder()", "%s no language '%s'", filename, what ); } } } bool translator::load() { //initialize these values to 0(ie. nothing loaded) single_instance.current_lang = -1; single_instance.lang_count = 0; DBG_MESSAGE("translator::load()", "Loading languages..."); dr_chdir( env_t::base_dir ); searchfolder_t folder; folder.search("text/", "tab"); //read now the basic language infos for (searchfolder_t::const_iterator i = folder.begin(), end = folder.end(); i != end; ++i) { const string fileName(*i); size_t pstart = fileName.rfind('/') + 1; const string iso = fileName.substr(pstart, fileName.size() - pstart - 4); if (FILE* const file = dr_fopen(fileName.c_str(), "rb")) { DBG_MESSAGE("translator::load()", "base file \"%s\" - iso: \"%s\"", fileName.c_str(), iso.c_str()); load_language_iso(iso); load_language_file(file); fclose(file); langs[single_instance.lang_count].highest_character = guess_highest_unicode( single_instance.lang_count ); single_instance.lang_count++; if (single_instance.lang_count == (int)lengthof(langs)) { if (++i != end) { // some languages were not loaded, let the user know what happened dbg->warning("translator::load()", "some languages were not loaded, limit reached"); for (; i != end; ++i) { dbg->warning("translator::load()", " %s not loaded", *i); } } break; } } } // now read the pakset specific text // there can be more than one file per language, provided it is name like iso_xyz.tab load_files_from_folder((env_t::pak_dir+"text"+PATH_SEPARATOR).c_str(), "pak"); if( env_t::default_settings.get_with_private_paks() ) { dr_chdir( env_t::user_dir ); // now read the pakset specific text // there can be more than one file per language, provided it is name like iso_xyz.tab const string folderName("addons/" + env_t::pak_name + "text/"); load_files_from_folder(folderName.c_str(), "pak addons"); dr_chdir( env_t::base_dir ); } //if NO languages were loaded then game cannot continue if (single_instance.lang_count < 1) { return false; } // now we try to read the compatibility stuff if (FILE* const file = dr_fopen((env_t::pak_dir + "compat.tab").c_str(), "rb")) { load_language_file_body(file, &compatibility, false, false, false ); DBG_MESSAGE("translator::load()", "pakset compatibility texts loaded."); fclose(file); } else { DBG_MESSAGE("translator::load()", "no pakset compatibility texts"); } // also addon compatibility ... if( env_t::default_settings.get_with_private_paks() ) { dr_chdir( env_t::user_dir ); if (FILE* const file = dr_fopen(string("addons/"+env_t::pak_name + "compat.tab").c_str(), "rb")) { load_language_file_body(file, &compatibility, false, false, false ); DBG_MESSAGE("translator::load()", "pakset addon compatibility texts loaded."); fclose(file); } dr_chdir( env_t::base_dir ); } // use english if available current_langinfo = get_lang_by_iso("en"); // it's all ok return true; } void translator::load_language_iso(const string &iso) { string base(iso); langs[single_instance.lang_count].iso = strdup(iso.c_str()); int loc = iso.find('_'); if (loc != -1) { base = iso.substr(0, loc); } langs[single_instance.lang_count].iso_base = strdup(base.c_str()); } void translator::set_language(int lang) { if( 0 <= lang && lang < single_instance.lang_count ) { single_instance.current_lang = lang; current_langinfo = langs+lang; env_t::language_iso = langs[lang].iso; env_t::default_settings.set_name_language_iso( langs[lang].iso ); init_custom_names(lang); current_langinfo->ellipsis_width = proportional_string_width( translate("...") ); DBG_MESSAGE("translator::set_language()", "%s, unicode %d", langs[lang].name, true); } else { dbg->warning("translator::set_language()", "Out of bounds : %d", lang); } } // returns the id for this language or -1 if not there int translator::get_language(const char *iso) { for( int i = 0; i < single_instance.lang_count; i++ ) { const char *iso_base = langs[i].iso_base; if( iso_base[0] == iso[0] && iso_base[1] == iso[1] ) { return i; } } return -1; } bool translator::set_language(const char *iso) { for( int i = 0; i < single_instance.lang_count; i++ ) { const char *iso_base = langs[i].iso_base; if( iso_base[0] == iso[0] && iso_base[1] == iso[1] ) { set_language(i); return true; } } // if the request language does not exist if( single_instance.current_lang == -1 ) { for( int i = 0; i < single_instance.lang_count; i++ ) { const char* iso_base = langs[i].iso_base; if( iso_base[0] == 'e' && iso_base[1] == 'n' ) { set_language( i ); return false; } } // not even english found ... set_language(0); } return false; } const char *translator::translate(const char *str) { return get_lang()->translate(str); } const char *translator::translate(const char *str, int lang) { return langs[lang].translate(str); } const char* translator::get_obj_info(cbuffer_t &buf,const char *name) { buf.append(translator::translate(name)); buf.rtrim(); buf.append("\n\n"); // append extra info if it is a short name if (strlen(name) < 238) { char ei[256]; sprintf(ei, "obj_%s_details", name); const char* translated_ei = translate(ei); if (ei != translated_ei) { buf.append(translated_ei); buf.rtrim(); buf.append("\n\n"); } } return NULL; } const char *translator::get_month_name(uint16 month) { static const char *const month_names[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "Oktober", "November", "December" }; return translate(month_names[month % lengthof(month_names)]); } const char *translator::get_short_month_name(uint16 month) { static const char *const short_month_names[] = { "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec." }; return translate(short_month_names[month % lengthof(short_month_names)]); } const char *translator::get_date(uint16 year, uint16 month) { char const* const month_ = get_month_name(month); char const* const year_sym = strcmp("YEAR_SYMBOL", translate("YEAR_SYMBOL")) ? translate("YEAR_SYMBOL") : ""; static char sdate[256]; switch (env_t::show_month) { case env_t::DATE_FMT_JAPANESE: case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf(sdate, "%4d%s %s", year, year_sym, month_); break; case env_t::DATE_FMT_GERMAN: case env_t::DATE_FMT_GERMAN_NO_SEASON: case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: default: sprintf(sdate, "%s %4d%s", month_, year, year_sym); break; } return sdate; } const char *translator::get_date(uint16 year, uint16 month, uint16 day, char const* season) { char const* const month_ = get_month_name(month); char const* const year_sym = strcmp("YEAR_SYMBOL", translate("YEAR_SYMBOL")) ? translate("YEAR_SYMBOL") : ""; char const* const day_sym = strcmp("DAY_SYMBOL", translate("DAY_SYMBOL")) ? translate("DAY_SYMBOL") : ""; static char date[256]; switch(env_t::show_month) { case env_t::DATE_FMT_GERMAN: sprintf(date, "%s %d. %s %d%s ", season, day, month_, year, year_sym); break; case env_t::DATE_FMT_GERMAN_NO_SEASON: sprintf(date, "%d. %s %d%s ", day, month_, year, year_sym); break; case env_t::DATE_FMT_US: sprintf(date, "%s %s %d %d%s ", season, month_, day, year, year_sym); break; case env_t::DATE_FMT_US_NO_SEASON: sprintf(date, "%s %d %d%s ", month_, day, year, year_sym); break; case env_t::DATE_FMT_JAPANESE: sprintf(date, "%s %d%s %s %d%s ", season, year, year_sym, month_, day, day_sym); break; case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf(date, "%d%s %s %d%s ", year, year_sym, month_, day, day_sym); break; case env_t::DATE_FMT_MONTH: sprintf(date, "%s, %s %d%s ", month_, season, year, year_sym); break; case env_t::DATE_FMT_SEASON: sprintf(date, "%s %d%s ", season, year, year_sym); break; } return date; } const char *translator::get_short_date(uint16 year, uint16 month) { char const* const month_ = get_short_month_name(month); char const* const year_sym = strcmp("YEAR_SYMBOL", translate("YEAR_SYMBOL")) ? translate("YEAR_SYMBOL") : ""; static char sdate[256]; switch (env_t::show_month) { case env_t::DATE_FMT_JAPANESE: case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf(sdate, "%4d%s %s", year, year_sym , month_); break; case env_t::DATE_FMT_GERMAN: case env_t::DATE_FMT_GERMAN_NO_SEASON: case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: default: sprintf(sdate, "%s %4d%s", month_, year, year_sym); break; } return sdate; } const char* translator::get_month_date( uint16 month, uint16 day ) { char const* const month_ = get_month_name( month ); char const* const day_sym = strcmp( "DAY_SYMBOL", translate( "DAY_SYMBOL" ) )?translate( "DAY_SYMBOL" ):""; static char date[256]; switch( env_t::show_month ) { case env_t::DATE_FMT_GERMAN: case env_t::DATE_FMT_GERMAN_NO_SEASON: sprintf( date, "%d. %s ", day, month_ ); break; case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: sprintf( date, "%s %d ", month_, day ); break; case env_t::DATE_FMT_JAPANESE: case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf( date, "%s %d%s", month_, day, day_sym ); break; case env_t::DATE_FMT_SEASON: case env_t::DATE_FMT_MONTH: sprintf( date, "%s, ", month_ ); break; } return date; } const char* translator::get_day_date(uint16 day) { char const* const day_sym = strcmp("ORDINAL_DAY_SYMBOL", translate("ORDINAL_DAY_SYMBOL")) ? translate("ORDINAL_DAY_SYMBOL") : "th "; static char date[256]; switch( env_t::show_month ) { case env_t::DATE_FMT_GERMAN: case env_t::DATE_FMT_GERMAN_NO_SEASON: sprintf( date, "%d%s", day, day_sym ); return translator::translate( date ); case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: sprintf( date, "%d%s", day, day_sym ); return translator::translate( date ); case env_t::DATE_FMT_JAPANESE: case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf( date, "%d%s", day, day_sym ); return translator::translate( date ); case env_t::DATE_FMT_SEASON: case env_t::DATE_FMT_MONTH: break; } return ""; } /* get a name for a non-matching object */ const char *translator::compatibility_name(const char *str) { if( str==NULL ) { return "(null)"; } if( str[0]=='\0' ) { return str; } const char *trans = compatibility.get(str); return trans != NULL ? trans : str; } simutrans-124.3/src/simutrans/dataobj/translator.h000066400000000000000000000101651474050137200223400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DATAOBJ_TRANSLATOR_H #define DATAOBJ_TRANSLATOR_H #include #include #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" class cbuffer_t; /** * Central location for loading and translating language text for the * UI of Simutrans. * * The languages are 0 based index, with a valid range of(with lang being * required language): 0 <= lang < lang_count. */ class translator { private: //cannot be instantiated outside translator translator() { current_lang = -1; } int current_lang; int lang_count; /* The single instance that this class will use to gain access to * the member variables such as language names */ static translator single_instance; static uint32 guess_highest_unicode(int lang); /* Methods related to loading a language file into memory */ static void load_language_file(FILE* file); static void load_language_iso(const std::string &iso); static vector_tpl city_name_list; static vector_tpl street_name_list; static void load_custom_list( int lang, vector_tpl &name_list, const char *fileprefix ); public: struct lang_info { const char* translate(const char* text) const; stringhashtable_tpl texts; const char *name; const char *iso; const char *iso_base; bool is_latin2_based; uint32 highest_character; uint8 ellipsis_width; }; static void init_custom_names(int lang); static const vector_tpl &get_city_name_list() { return city_name_list; } static const vector_tpl &get_street_name_list() { return street_name_list; } /** * Loads up all files of language type from the 'language' directory. * This method must be called for languages to be loaded up, undefined * behaviour may follow if calls to translate message or similar are * called before load has been called */ static bool load(); /** * Loads all language file in folder folder_name * folder_name is relative to current dir (set by chdir) */ static void load_files_from_folder(const char* folder_name, const char* what); /** * Get/Set the currently selected language, based on the * index number */ static int get_language() { return single_instance.current_lang; } // returns the id for this language or -1 if not there static int get_language(const char* iso); /** Get information about the currently selected language */ static const lang_info* get_lang(); static const lang_info* get_langs(); /** * First checks to see whether the language is in bounds, will * then change what language is being used, otherwise prints * an error message, leaving the language as it is */ static void set_language(int lang); static bool set_language(const char* iso); /** * Returns the number of loaded languages. */ static int get_language_count() { return single_instance.lang_count; } /** * Translates a given string(key) to its locale * specific counterpart, using the current language * table. * the second variant just uses the language with the index * @return translated string, (null) if string is null, * or the string if the translation is not found */ static const char *translate(const char* str); static const char *translate(const char* str, int lang); /** * Fills the buffer with the obj name and detail translation (if there is any) */ static const char *get_obj_info(cbuffer_t &buf, const char *name); /** * @return replacement info for almost any object within the game */ static const char *compatibility_name(const char* str); // return the name of the month static const char *get_month_name(uint16 month); // return the short name of the month static const char *get_short_month_name(uint16 month); // return date in selected format static const char *get_date(uint16 year, uint16 month); static const char *get_date(uint16 year, uint16 month, uint16 day, char const* season); static const char* get_short_date(uint16 year, uint16 month); static const char* get_month_date(uint16 month, uint16 day); static const char* get_day_date( uint16 day ); }; #endif simutrans-124.3/src/simutrans/descriptor/000077500000000000000000000000001474050137200205455ustar00rootroot00000000000000simutrans-124.3/src/simutrans/descriptor/bridge_desc.cc000066400000000000000000000071101474050137200233050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "bridge_desc.h" #include "ground_desc.h" #include "../network/checksum.h" /** * Returns image index of a straight piece (excluding start pieces) */ bridge_desc_t::img_t bridge_desc_t::get_straight(ribi_t::ribi ribi, uint8 height) const { if( height>1 && get_background(NS_Segment2, 0)!=IMG_EMPTY ) { return (ribi & ribi_t::northsouth) ? NS_Segment2 : OW_Segment2; } else { return (ribi & ribi_t::northsouth) ? NS_Segment : OW_Segment; } } // ditto for pillars bridge_desc_t::img_t bridge_desc_t::get_pillar(ribi_t::ribi ribi) { return (ribi & ribi_t::northsouth) ? NS_Pillar : OW_Pillar; } /** * Returns image index of a straight bridge-start piece (on slope) */ bridge_desc_t::img_t bridge_desc_t::get_start(slope_t::type slope) const { // if double heights enabled and desc has 2 height images present then use these if( ground_desc_t::double_grounds && get_background(N_Start2, 0) != IMG_EMPTY ) { switch( slope ) { case slope_t::north: return N_Start; case slope_t::south: return S_Start; case slope_t::east: return O_Start; case slope_t::west: return W_Start; case slope_t::north * 2: return N_Start2; case slope_t::south * 2: return S_Start2; case slope_t::east * 2: return O_Start2; case slope_t::west * 2: return W_Start2; } } else { switch( slope ) { case slope_t::north: case slope_t::north * 2: return N_Start; case slope_t::south: case slope_t::south * 2: return S_Start; case slope_t::east: case slope_t::east * 2: return O_Start; case slope_t::west: case slope_t::west * 2: return W_Start; } } return (img_t) - 1; } /** * Returns image index of a ramp piece */ bridge_desc_t::img_t bridge_desc_t::get_ramp(slope_t::type slope) const { if( ground_desc_t::double_grounds && has_double_ramp() ) { switch( slope ) { case slope_t::north: return S_Ramp; case slope_t::south: return N_Ramp; case slope_t::east: return W_Ramp; case slope_t::west: return O_Ramp; case slope_t::north * 2: return S_Ramp2; case slope_t::south * 2: return N_Ramp2; case slope_t::east * 2: return W_Ramp2; case slope_t::west * 2: return O_Ramp2; } } else { switch( slope ) { case slope_t::north: case slope_t::north * 2: return S_Ramp; case slope_t::south: case slope_t::south * 2: return N_Ramp; case slope_t::east: case slope_t::east * 2: return W_Ramp; case slope_t::west: case slope_t::west * 2: return O_Ramp; } } return (img_t) - 1; } /** * returns image index for appropriate ramp or start image given ground and way slopes */ bridge_desc_t::img_t bridge_desc_t::get_end(slope_t::type test_slope, slope_t::type ground_slope, slope_t::type way_slope) const { img_t end_image; if( test_slope == slope_t::flat ) { end_image = get_ramp( way_slope ); } else { end_image = get_start( ground_slope ); } return end_image; } /** * returns whether desc has double height images for ramps */ bool bridge_desc_t::has_double_ramp() const { return (get_background(bridge_desc_t::N_Ramp2, 0)!=IMG_EMPTY || get_foreground(bridge_desc_t::N_Ramp2, 0)!=IMG_EMPTY); } bool bridge_desc_t::has_double_start() const { return (get_background(bridge_desc_t::N_Start2, 0) != IMG_EMPTY || get_foreground(bridge_desc_t::N_Start2, 0) != IMG_EMPTY); } void bridge_desc_t::calc_checksum(checksum_t *chk) const { obj_desc_transport_infrastructure_t::calc_checksum(chk); chk->input(pillars_every); chk->input(pillars_asymmetric); chk->input(max_length); chk->input(max_height); } simutrans-124.3/src/simutrans/descriptor/bridge_desc.h000066400000000000000000000070431474050137200231540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_BRIDGE_DESC_H #define DESCRIPTOR_BRIDGE_DESC_H #include "skin_desc.h" #include "image_list.h" #include "text_desc.h" #include "../simtypes.h" #include "../display/simimg.h" #include "../dataobj/ribi.h" class tool_t; class checksum_t; /* * BEWARE: non-standard node structure! * 0 Foreground-images * 1 Background-images * 2 Cursor/Icon * 3 Foreground-images - snow * 4 Background-images - snow */ class bridge_desc_t : public obj_desc_transport_infrastructure_t { friend class bridge_reader_t; private: uint8 pillars_every; // =0 off bool pillars_asymmetric; // =0 off else leave one off for north/west slopes uint offset; // flag, because old bridges had their name/copyright at the wrong position uint8 max_length; // =0 off, else maximum length uint8 max_height; // =0 off, else maximum length // number of seasons (0 = none, 1 = no snow/snow sint8 number_of_seasons; public: /* * Numbering of all image pieces */ enum img_t { NS_Segment, OW_Segment, N_Start, S_Start, O_Start, W_Start, N_Ramp, S_Ramp, O_Ramp, W_Ramp, NS_Pillar, OW_Pillar, NS_Segment2, OW_Segment2, N_Start2, S_Start2, O_Start2, W_Start2, N_Ramp2, S_Ramp2, O_Ramp2, W_Ramp2, NS_Pillar2, OW_Pillar2 }; /* * Name and Copyright used to be saved only with the Cursor */ const char *get_name() const { return get_cursor()->get_name(); } const char *get_copyright() const { return get_cursor()->get_copyright(); } skin_desc_t const* get_cursor() const { return get_child(2 + offset); } image_id get_background(img_t img, uint8 season) const { const image_t *image = NULL; if(season && number_of_seasons == 1) { image = get_child(3 + offset)->get_image(img); } if(image == NULL) { image = get_child(0 + offset)->get_image(img); } return image != NULL ? image->get_id() : IMG_EMPTY; } image_id get_foreground(img_t img, uint8 season) const { const image_t *image = NULL; if(season && number_of_seasons == 1) { image = get_child(4 + offset)->get_image(img); } if(image == NULL) { image = get_child(1 + offset)->get_image(img); } return image != NULL ? image->get_id() : IMG_EMPTY; } img_t get_straight(ribi_t::ribi ribi, uint8 height) const; img_t get_start(slope_t::type slope) const; img_t get_ramp(slope_t::type slope) const; static img_t get_pillar(ribi_t::ribi ribi); /** * @return true if this bridge can raise two level from flat terrain */ bool has_double_ramp() const; /** * @return true if this bridge can start or end on a double slope */ bool has_double_start() const; img_t get_end(slope_t::type test_slope, slope_t::type ground_slope, slope_t::type way_slope) const; /** * There is no way to distinguish between train bridge and tram bridge. * However there are no real tram bridges possible in the game. */ waytype_t get_finance_waytype() const { return get_waytype(); } /** * Distance of pillars (=0 for no pillars) */ uint8 get_pillar() const { return pillars_every; } /** * skips lowest pillar on south/west slopes? */ bool has_pillar_asymmetric() const { return pillars_asymmetric; } /** * maximum bridge span (=0 for infinite) */ uint8 get_max_length() const { return max_length; } /** * maximum bridge height (=0 for infinite) */ uint8 get_max_height() const { return max_height; } void calc_checksum(checksum_t *chk) const; }; #endif simutrans-124.3/src/simutrans/descriptor/building_desc.cc000066400000000000000000000121271474050137200236520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../world/simworld.h" #include "building_desc.h" #include "../network/checksum.h" /** * Calculate which layout the tile belongs to from the index. */ uint8 building_tile_desc_t::get_layout() const { koord size = get_desc()->get_size(); return index / (size.x * size.y); } /** * Return the relative position of an image in the whole building image */ koord building_tile_desc_t::get_offset() const { const building_desc_t *desc = get_desc(); koord size = desc->get_size(get_layout()); // rotate if necessary return koord( index % size.x, (index / size.x) % size.y ); } waytype_t building_desc_t::get_finance_waytype() const { switch( get_type() ) { case dock: return water_wt; case flat_dock: return water_wt; case depot: case generic_stop: case generic_extension: return (waytype_t) get_extra(); default: return ignore_wt; } } /** * Mail generation level */ uint16 building_desc_t::get_mail_level() const { switch (type) { default: case city_res: return level; case city_com: return level * 2; case city_ind: return level / 2; } } /** * true, if this building needs a connection with a town */ bool building_desc_t::is_connected_with_town() const { switch(get_type()) { case city_res: case city_com: case city_ind: // normal town buildings (RES, COM, IND) case monument: // monuments case townhall: // townhalls case headquarters: // headquarters return true; default: return false; } } /** * Returns the correct tile image on that position depending on the layout */ const building_tile_desc_t *building_desc_t::get_tile(uint8 layout, sint16 x, sint16 y) const { layout = adjust_layout(layout); koord dims = get_size(layout); if( x < 0 || y < 0 || layout >= layouts || x >= get_x(layout) || y >= get_y(layout) ) { dbg->fatal("building_tile_desc_t::get_tile()", "invalid request for l=%d, x=%d, y=%d on building %s (l=%d, x=%d, y=%d)", layout, x, y, get_name(), layouts, size.x, size.y); } return get_tile(layout * dims.x * dims.y + y * dims.x + x); } /** * Layout normalisation. Returns number of different layouts */ uint8 building_desc_t::adjust_layout(uint8 layout) const { if(layout >= 4 && layouts <= 4) { layout -= 4; } if(layout >= 2 && layouts <= 2) { // if layouts C and D are not defined, we use A and B as substitutes layout -= 2; } if(layout > 0 && layouts <= 1) { // if layout B is not defined and the building is squared, we us A as substitute if(size.x == size.y) { layout--; } } return layout; } void building_desc_t::calc_checksum(checksum_t *chk) const { obj_desc_timelined_t::calc_checksum(chk); chk->input((uint8)type); chk->input(animation_time); chk->input(extra_data); chk->input(size.x); chk->input(size.y); chk->input((uint8)flags); chk->input(level); chk->input(layouts); chk->input(enables); chk->input(distribution_weight); chk->input((uint8)allowed_climates); chk->input(maintenance); chk->input(price); chk->input(capacity); chk->input(allow_underground); // now check the layout for(uint8 i=0; ihas_image()) { chk->input((sint16)(x+y+i)); } } } } chk->input(preservation_year_month); } /** * get functions - see building_desc.h for variable information */ sint32 building_desc_t::get_maintenance(karte_t *world) const { if( maintenance == PRICE_MAGIC ) { return world->get_settings().maint_building*get_level(); } else { return maintenance; } } sint32 building_desc_t::get_price(karte_t *world) const { if( price == PRICE_MAGIC ) { settings_t const& s = world->get_settings(); switch (get_type()) { case dock: case flat_dock: return -s.cst_multiply_dock * get_level(); case generic_extension: return -s.cst_multiply_post * get_level(); case generic_stop: switch(get_extra()) { case road_wt: return -s.cst_multiply_roadstop * get_level(); case track_wt: case monorail_wt: case maglev_wt: case narrowgauge_wt: case tram_wt: return -s.cst_multiply_station * get_level(); case water_wt: return -s.cst_multiply_dock * get_level(); case air_wt: return -s.cst_multiply_airterminal * get_level(); case 0: return -s.cst_multiply_post * get_level(); default: return 0; } case depot: switch(get_extra()) { case road_wt: return -s.cst_depot_road; case track_wt: case monorail_wt: case tram_wt: case maglev_wt: case narrowgauge_wt: return -s.cst_depot_rail; case water_wt: return -s.cst_depot_ship; case air_wt: return -s.cst_depot_air; default: return 0; } case headquarters: return -s.cst_multiply_headquarter * get_level(); default: return -s.cst_multiply_remove_haus * get_level(); } } else { return price; } } simutrans-124.3/src/simutrans/descriptor/building_desc.h000066400000000000000000000237271474050137200235240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_BUILDING_DESC_H #define DESCRIPTOR_BUILDING_DESC_H #include #include "image_array.h" #include "obj_base_desc.h" #include "skin_desc.h" #include "../dataobj/koord.h" class building_desc_t; class tool_t; class karte_t; class checksum_t; /** * Data for one tile of a potentially multi-tile building. * * Child nodes: * 0 Imagelist2D season 0 back * 1 Imagelist2D season 0 front * 2 Imagelist2D season 1 back * 3 Imagelist2D season 1 front * ... ... */ class building_tile_desc_t : public obj_desc_t { friend class tile_reader_t; const building_desc_t *building; uint8 seasons; uint8 phases; ///< number of animation phases uint16 index; public: void set_desc(const building_desc_t *building_desc) { building = building_desc; } const building_desc_t *get_desc() const { return building; } uint16 get_index() const { return index; } uint8 get_seasons() const { return seasons; } uint8 get_phases() const { return phases; } bool has_image() const { return get_background(0,0,0)!=IMG_EMPTY || get_foreground(0,0)!=IMG_EMPTY; } image_id get_background(uint16 phase, uint16 height, uint8 season) const { image_array_t const* const imglist = get_child(0 + 2 * season); if(phase>0 && phaseget_image(height, phase)) { return image->get_id(); } } // here if this phase does not exists ... image_t const* const image = imglist->get_image(height, 0); return image != NULL ? image->get_id() : IMG_EMPTY; } // returns true, if the background is animated bool is_background_animated(uint8 season) const { image_array_t const* const imglist = get_child(0 + 2 * season); const uint16 max_h = imglist->get_count(); for( uint16 phase=1; phaseget_image( h, phase ) ) { return true; } } } return false; } image_id get_foreground(uint16 phase, uint8 season) const { image_array_t const* const imglist = get_child(1 + 2 * season); if(phase>0 && phaseget_image(0, phase)) { return image->get_id(); } } // here if this phase does not exists ... image_t const* const image = imglist->get_image(0, 0); return image != NULL ? image->get_id() : IMG_EMPTY; } koord get_offset() const; uint8 get_layout() const; }; /** * Data for one building, consists of potentially more than one tile. * * Child nodes: * 0 Name * 1 Copyright * 2 Tile 1 * 3 Tile 2 * ... ... */ class building_desc_t : public obj_desc_timelined_t { friend class building_reader_t; public: /** * Building types */ enum btype { unknown = 0, attraction_city = 1, attraction_land = 2, monument = 3, factory = 4, townhall = 5, others = 6, ///< monorail foundation headquarters = 7, dock = 11, ///< dock, build on sloped coast // in these, the extra data points to a waytype depot = 33, generic_stop = 34, generic_extension = 35, flat_dock = 36, ///< dock, but can start on a flat coast line // city buildings city_res = 37, ///< residential city buildings city_com = 38, ///< commercial city buildings city_ind = 39 ///< industrial city buildings }; enum flag_t { FLAG_NULL = 0, FLAG_NO_INFO = 1 << 0, ///< do not show info window FLAG_NO_PIT = 1 << 1, ///< do not show construction pit FLAG_NEED_GROUND = 1 << 2, ///< needs ground drawn below FLAG_HAS_CURSOR = 1 << 3 ///< there is cursor/icon for this }; private: /** * Old named constants, only used for compatibility to load very old paks. * These will be converted in building_reader_t::register_obj to a valid btype. */ enum old_building_types_t { bahnhof = 8, bushalt = 9, ladebucht = 10, binnenhafen = 12, airport = 13, monorailstop = 14, bahnhof_geb = 16, bushalt_geb = 17, ladebucht_geb = 18, hafen_geb = 19, binnenhafen_geb = 20, airport_geb = 21, monorail_geb = 22, wartehalle = 30, mail = 31, lagerhalle = 32 }; building_desc_t::btype type; uint16 animation_time; // in ms uint32 extra_data; // extra data: // minimum population to build for city attractions, // waytype for depots // player level for headquarters // cluster number for city buildings (0 means no clustering) koord size; flag_t flags; uint16 level; // or passengers; uint8 layouts; // 1 2, 4, 8 or 16 uint8 enables; // if it is a stop, what is enabled ... uint8 distribution_weight; // chance to build, special buildings, only other is weight factor /** * Additional fields for separate capacity/maintenance * If these are not specified in the .dat file, they are set to * PRICE_MAGIC then calculated from the "level" in the old way. */ sint32 price; sint32 maintenance; uint16 capacity; #define PRICE_MAGIC (2147483647) climate_bits allowed_climates; /** * Whether this building can or must be built underground. * Only relevant for stations (generic_stop). * 0 = cannot be built underground * 1 = can only be built underground * 2 = can be built either underground or above ground. */ uint8 allow_underground; uint16 preservation_year_month; bool is_type(building_desc_t::btype u) const { return type == u; } tool_t *builder; public: koord get_size(uint8 layout = 0) const { return (layout & 1) ? koord(size.y, size.x) : size; } // size of the building sint16 get_y(uint8 layout = 0) const { return (layout & 1) ? size.x: size.y; } sint16 get_x(uint8 layout = 0) const { return (layout & 1) ? size.y : size.x; } uint8 get_all_layouts() const { return layouts; } uint32 get_extra() const { return extra_data; } /** Returns waytype used for finance stats (distinguishes between tram track and train track) */ waytype_t get_finance_waytype() const; // ground is transparent bool needs_ground() const { return (flags & FLAG_NEED_GROUND) != 0; } // no construction stage bool no_construction_pit() const { return (flags & FLAG_NO_PIT) != 0; } // do not open info for this bool no_info_window() const { return (flags & FLAG_NO_INFO) != 0; } // never replace this building for renovation (to create historic city centres) uint16 no_renovation_month() const { return preservation_year_month; } building_desc_t::btype get_type() const { return type; } bool is_townhall() const { return is_type(townhall); } bool is_headquarters() const { return is_type(headquarters); } bool is_attraction() const { return is_type(attraction_land) || is_type(attraction_city); } bool is_monument() const { return is_type(monument); } bool is_factory() const { return is_type(factory); } bool is_city_building() const { return is_type(city_res) || is_type(city_com) || is_type(city_ind); } bool is_transport_building() const { return type > headquarters && type <= flat_dock; } bool is_depot() const { return is_type(depot); } bool is_connected_with_town() const; /// @returns headquarters level (or -1 if building is not headquarters) sint32 get_headquarters_level() const { return (is_headquarters() ? get_extra() : -1) ; } /** * the level is used in many places: for price, for capacity, ... */ uint16 get_level() const { return level; } /** * Mail generation level */ uint16 get_mail_level() const; // how often will this appear uint8 get_distribution_weight() const { return distribution_weight; } const building_tile_desc_t *get_tile(uint16 index) const { assert(index < layouts * size.x * size.y); return get_child(index + 2); } const building_tile_desc_t *get_tile(uint8 layout, sint16 x, sint16 y) const; // returns true,if building can be rotated bool can_rotate() const { if(size.x!=size.y && layouts==1) { return false; } // check for missing tiles after rotation for( sint16 x=0; xhas_image() ^ get_tile( 1, get_x(1)-y-1, x )->has_image()) { return false; } } } return true; } uint8 adjust_layout(uint8 layout) const; /** * Skin: cursor (index 0) and icon (index 1) */ const skin_desc_t * get_cursor() const { return flags & FLAG_HAS_CURSOR ? get_child(2 + size.x * size.y * layouts) : 0; } // the right house for this area? bool is_allowed_climate( climate cl ) const { return ((1< 0; } bool can_be_built_aboveground() const { return allow_underground != 1; } uint32 get_clusters() const { // Only meaningful for res, com, ind return is_city_building() ? extra_data : 0; } }; ENUM_BITSET(building_desc_t::flag_t) #endif simutrans-124.3/src/simutrans/descriptor/citycar_desc.h000066400000000000000000000022431474050137200233530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_CITYCAR_DESC_H #define DESCRIPTOR_CITYCAR_DESC_H #include "obj_base_desc.h" #include "image_list.h" #include "../dataobj/ribi.h" #include "../simtypes.h" #include "../network/checksum.h" /** * Private city cars, not player owned. They automatically appear in cities. * * Child nodes: * 0 Name * 1 Copyright * 2 Image-list */ class citycar_desc_t : public obj_desc_timelined_t { friend class citycar_reader_t; uint16 distribution_weight; /// topspeed in internal speed units !!! not km/h!!! uint16 topspeed; public: image_id get_image_id(ribi_t::dir dir) const { image_t const* const image = get_child(2)->get_image(dir); return image != NULL ? image->get_id() : IMG_EMPTY; } uint16 get_distribution_weight() const { return distribution_weight; } /// topspeed in internal speed units !!! not km/h!!! uint16 get_topspeed() const { return topspeed; } void calc_checksum(checksum_t *chk) const { obj_desc_timelined_t::calc_checksum(chk); chk->input(distribution_weight); chk->input(topspeed); } }; #endif simutrans-124.3/src/simutrans/descriptor/crossing_desc.h000066400000000000000000000040641474050137200235470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_CROSSING_DESC_H #define DESCRIPTOR_CROSSING_DESC_H #include "obj_base_desc.h" #include "image.h" #include "image_list.h" #include "../simtypes.h" #include "../network/checksum.h" class checksum_t; /** * Child nodes: * 0 Name * 1 Copyright * 2 Image-list */ class crossing_desc_t : public obj_desc_timelined_t { friend class crossing_reader_t; private: waytype_t waytype1; waytype_t waytype2; sint8 sound; uint32 closed_animation_time; uint32 open_animation_time; sint32 topspeed1; // the topspeed depeds strongly on the crossing ... sint32 topspeed2; public: /* the imagelists are: * open_ns * open_ew * front_open_ns * front_open_ew * closed_ns * .... * =>ns=0 NorthSouth ns=1, East-West */ const image_t *get_background(uint8 ns, bool open, uint16 phase) const { if(open) { return get_child(2 + ns)->get_image(phase); } else { image_list_t const* const imglist = get_child(6 + ns); return imglist ? imglist->get_image(phase) : NULL; } } const image_t *get_foreground(uint8 ns, bool open, uint16 phase) const { uint8 const n = ns + (open ? 4 : 8); image_list_t const* const imglist = get_child(n); return imglist ? imglist->get_image(phase) : 0; } waytype_t get_waytype(int i) const { return i==0? waytype1 : waytype2; } sint32 get_maxspeed(int i) const { return i==0 ? topspeed1 : topspeed2; } uint16 get_phases(bool open, bool front) const { return get_child(6 - 4 * open + 2 * front)->get_count(); } uint32 get_animation_time(bool open) const { return open ? open_animation_time : closed_animation_time; } sint8 get_sound() const { return sound; } void calc_checksum(checksum_t *chk) const { chk->input(waytype1); chk->input(waytype2); chk->input(closed_animation_time); chk->input(open_animation_time); chk->input(topspeed1); chk->input(topspeed2); chk->input(intro_date); chk->input(retire_date); } }; #endif simutrans-124.3/src/simutrans/descriptor/factory_desc.cc000066400000000000000000000051071474050137200235240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "factory_desc.h" #include "xref_desc.h" #include "../network/checksum.h" void field_class_desc_t::calc_checksum(checksum_t *chk) const { chk->input(production_per_field); chk->input(storage_capacity); chk->input(spawn_weight); } void field_group_desc_t::calc_checksum(checksum_t *chk) const { chk->input(probability); chk->input(max_fields); chk->input(min_fields); chk->input(field_classes); for(uint16 i=0; icalc_checksum(chk); } } void factory_supplier_desc_t::calc_checksum(checksum_t *chk) const { chk->input(capacity); chk->input(supplier_count); chk->input(consumption); chk->input(get_input_type()->get_name()); } void factory_product_desc_t::calc_checksum(checksum_t *chk) const { chk->input(capacity); chk->input(factor); chk->input(get_output_type()->get_name()); } void factory_desc_t::correct_smoke() { if( smokerotations == 0 && get_smoke() ) { // old type of factory, we have to build the tile and smoke offsets here const smoke_desc_t *oldsmoke = get_smoke(); const koord size = get_building()->get_size(0)-koord(1,1); smokerotations = get_building()->get_all_layouts(); for( int i = 0; i < smokerotations; i++ ) { smoketile[i] = oldsmoke->get_pos_off(size,i); smokeoffset[i] = oldsmoke->get_xy_off(i); smokeoffset[i] -= koord(0, LEGACY_SMOKE_YOFFSET); } smokeuplift = DEFAULT_SMOKE_UPLIFT; smokelifetime = DEFAULT_FACTORYSMOKE_TIME; } } void factory_desc_t::calc_checksum(checksum_t *chk) const { chk->input((uint8)placement); chk->input(productivity); chk->input(range); chk->input(distribution_weight); chk->input(color); chk->input(supplier_count); chk->input(product_count); chk->input(fields); chk->input(pax_level); chk->input(electricity_producer); chk->input(expand_probability); chk->input(expand_minimum); chk->input(expand_range); chk->input(expand_times); chk->input(electric_boost); chk->input(pax_boost); chk->input(mail_boost); chk->input(electric_demand); chk->input(pax_demand); chk->input(mail_demand); for (uint8 i=0; icalc_checksum(chk); } for (uint8 i=0; icalc_checksum(chk); } const field_group_desc_t *field_group = get_field_group(); if (field_group) { field_group->calc_checksum(chk); } get_building()->calc_checksum(chk); } simutrans-124.3/src/simutrans/descriptor/factory_desc.h000066400000000000000000000214231474050137200233650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_FACTORY_DESC_H #define DESCRIPTOR_FACTORY_DESC_H #include "obj_desc.h" #include "building_desc.h" #include "skin_desc.h" #include "goods_desc.h" #include "../dataobj/koord.h" #include "../tpl/weighted_vector_tpl.h" #define DEFAULT_FACTORYSMOKE_TIME (2499) #define DEFAULT_SMOKE_UPLIFT (16) #define LEGACY_SMOKE_YOFFSET (8) class checksum_t; /** * this desc will store data specific to each class of fields * Fields are xref'ed from skin_desc_t */ class field_class_desc_t : public obj_desc_t { friend class factory_field_class_reader_t; friend class factory_field_group_reader_t; // this is a special case due to desc restructuring private: uint8 snow_image; // 0 or 1 for snow uint16 production_per_field; uint16 storage_capacity; uint16 spawn_weight; public: skin_desc_t const* get_images() const { return get_child(0); } const char *get_name() const { return get_images()->get_name(); } const char *get_copyright() const { return get_images()->get_copyright(); } uint8 has_snow_image() const { return snow_image; } uint16 get_field_production() const { return production_per_field; } uint16 get_storage_capacity() const { return storage_capacity; } uint16 get_spawn_weight() const { return spawn_weight; } void calc_checksum(checksum_t *chk) const; }; // this desc now only contains common, shared data regarding fields class field_group_desc_t : public obj_desc_t { friend class factory_field_group_reader_t; private: uint16 probability; // between 0 ...10000 uint16 max_fields; // maximum number of fields around a single factory uint16 min_fields; // minimum number of fields around a single factory uint16 start_fields; // number of fields between min and start_fields to spawn on creation uint16 field_classes; // number of field classes weighted_vector_tpl field_class_indices; public: // fills the array, is only called once during successfully_loaded() after resolve xrefs void init_field_class_indices() { if( field_classes>0 ) { field_class_indices.clear(); field_class_indices.resize( field_classes ); for( uint16 i=0 ; iget_spawn_weight() ); } } } uint16 get_probability() const { return probability; } uint16 get_max_fields() const { return max_fields; } uint16 get_min_fields() const { return min_fields; } uint16 get_start_fields() const { return start_fields; } uint16 get_field_class_count() const { return field_classes; } field_class_desc_t const* get_field_class(uint16 const idx) const { return idx < field_classes ? get_child(idx) : 0; } const weighted_vector_tpl &get_field_class_indices() const { return field_class_indices; } void calc_checksum(checksum_t *chk) const; }; /** * Smoke objects for factories. * * Child nodes: * 0 SKin */ class smoke_desc_t : public obj_desc_t { friend class factory_smoke_reader_t; private: koord pos_off; koord xy_off; public: const char *get_name() const { return get_images()->get_name(); } const char *get_copyright() const { return get_images()->get_copyright(); } skin_desc_t const* get_images() const { return get_child(0); } // get the tile with the smoke koord get_pos_off( koord size, uint8 rotation) const { switch( rotation%4 ) { case 1: return koord( size.y-pos_off.y, pos_off.x ); case 2: return koord( size.x-pos_off.x, size.y-pos_off.y ); case 3: return koord( pos_off.y, size.x-pos_off.x ); } return pos_off; } // offset in pixel (depends on OBJECT_OFFSET_STEPS==16) koord get_xy_off(uint8 rotation) const { switch( rotation%4 ) { case 1: return koord( 0, xy_off.y+xy_off.x/2 ); case 2: return koord( -xy_off.x, xy_off.y ); case 3: return koord( 0, xy_off.y-xy_off.x/2 ); } return xy_off; } }; /** * Information about required goods for production * * Child nodes: * 0 Ware */ class factory_supplier_desc_t : public obj_desc_t { friend class factory_supplier_reader_t; private: uint16 capacity; uint16 supplier_count; uint16 consumption; public: goods_desc_t const* get_input_type() const { return get_child(0); } uint16 get_capacity() const { return capacity; } uint16 get_supplier_count() const { return supplier_count; } uint16 get_consumption() const { return consumption; } void calc_checksum(checksum_t *chk) const; }; /** * Information about produced goods of a factory * * Child nodes: * 0 Ware */ class factory_product_desc_t : public obj_desc_t { friend class factory_product_reader_t; private: uint16 capacity; /** * How much of this product is derived from one unit of factory * production? 256 means 1.0 */ uint16 factor; public: goods_desc_t const* get_output_type() const { return get_child(0); } uint16 get_capacity() const { return capacity; } uint16 get_factor() const { return factor; } void calc_checksum(checksum_t *chk) const; }; /** * Factory. * * Child nodes: * 0 House descriptor * 1 Smoke descriptor * 2 Supplier descriptor 1 * 3 Supplier descriptor 2 * ... ... * n+1 Supplier descriptor n * n+2 Consumer descriptor 1 * n+3 Consumer descriptor 2 * ... ... */ class factory_desc_t : public obj_desc_t { friend class factory_reader_t; public: enum site_t { Land, Water, City, river, shore, forest }; private: site_t placement; uint16 productivity; uint16 range; uint16 distribution_weight; // probability of construction of this factory uint8 color; uint16 supplier_count; uint16 product_count; uint8 fields; // only if there are any ... uint16 pax_level; bool electricity_producer; uint16 expand_probability; uint16 expand_minimum; uint16 expand_range; uint16 expand_times; uint16 electric_boost; uint16 pax_boost; uint16 mail_boost; uint16 electric_demand; uint16 pax_demand; uint16 mail_demand; uint16 smokeuplift; uint16 smokelifetime; koord smoketile[4]; koord smokeoffset[4]; uint8 smokerotations; sint8 sound_id; uint32 sound_interval; public: const char *get_name() const { return get_building()->get_name(); } const char *get_copyright() const { return get_building()->get_copyright(); } building_desc_t const* get_building() const { return get_child(0); } smoke_desc_t const* get_smoke() const { return get_child(1); } void correct_smoke(); koord get_smoketile( uint8 rot ) const { return smoketile[ rot%smokerotations ]; } koord get_smokeoffset( uint8 rot ) const { return smokeoffset[ rot%smokerotations ]; } uint16 get_smokeuplift() const { return smokeuplift; } uint16 get_smokelifetime() const { return smokelifetime; } // we must take care, for the case of no producer/consumer const factory_supplier_desc_t *get_supplier(uint16 i) const { return i < supplier_count ? get_child(2 + i) : 0; } const factory_product_desc_t *get_product(uint16 i) const { return i < product_count ? get_child(2 + supplier_count + i) : 0; } const field_group_desc_t *get_field_group() const { if(!fields) { return NULL; } return get_child(2 + supplier_count + product_count); } bool is_consumer_only() const { return product_count == 0; } bool is_producer_only() const { return supplier_count == 0; } uint16 get_supplier_count() const { return supplier_count; } uint16 get_product_count() const { return product_count; } /* where to built */ site_t get_placement() const { return placement; } uint16 get_distribution_weight() const { return distribution_weight; } PIXVAL get_color() const { return color_idx_to_rgb(color); } void set_productivity(uint16 p) { productivity=p; } uint16 get_productivity() const { return productivity; } uint16 get_range() const { return range; } /* level for mail and passenger generation */ uint16 get_pax_level() const { return pax_level; } bool is_electricity_producer() const { return electricity_producer; } uint16 get_expand_probability() const { return expand_probability; } uint16 get_expand_minimum() const { return expand_minimum; } uint16 get_expand_range() const { return expand_range; } uint16 get_expand_times() const { return expand_times; } uint16 get_electric_boost() const { return electric_boost; } uint16 get_pax_boost() const { return pax_boost; } uint16 get_mail_boost() const { return mail_boost; } uint16 get_electric_demand() const { return electric_demand; } uint16 get_pax_demand() const { return pax_demand; } uint16 get_mail_demand() const { return mail_demand; } // more effects when producing sint8 get_sound() const { return sound_id; } uint32 get_sound_interval_ms() const { return sound_interval; } void calc_checksum(checksum_t *chk) const; }; #endif simutrans-124.3/src/simutrans/descriptor/goods_desc.cc000066400000000000000000000017001474050137200231630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "goods_desc.h" static const char * catg_names[32] = { "special freight", "CATEGORY_01", // was "piece goods", "CATEGORY_02", // was "bulk goods", "CATEGORY_03", // was "oil/gasoline", "CATEGORY_04", // was "cooled goods", "CATEGORY_05", // was "liquid food", "CATEGORY_06", // was "long goods", "CATEGORY_07", "CATEGORY_08", "CATEGORY_09", "CATEGORY_10", "CATEGORY_11", "CATEGORY_12", "CATEGORY_13", "CATEGORY_14", "CATEGORY_15", "CATEGORY_16", "CATEGORY_17", "CATEGORY_18", "CATEGORY_19", "CATEGORY_20", "CATEGORY_21", "CATEGORY_22", "CATEGORY_23", "CATEGORY_24", "CATEGORY_25", "CATEGORY_26", "CATEGORY_27", "CATEGORY_28", "CATEGORY_29", "CATEGORY_30", "CATEGORY_31", }; /** * @return Name of the category of the good */ const char * goods_desc_t::get_catg_name() const { return catg_names[catg & 31]; } simutrans-124.3/src/simutrans/descriptor/goods_desc.h000066400000000000000000000046551474050137200230410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_GOODS_DESC_H #define DESCRIPTOR_GOODS_DESC_H #include "obj_base_desc.h" #include "../simcolor.h" #include "../display/simgraph.h" #include "../network/checksum.h" class checksum_t; /** * Child nodes: * 0 Name * 1 Copyright * 2 Text: Name of measurement unit */ class goods_desc_t : public obj_named_desc_t { friend class goods_reader_t; friend class goods_manager_t; /// base value uint16 base_value; /** * Value used in revenue calculation. * Will be set by goods_manager_t. */ uint16 value; /** * Category of the good */ uint8 catg; /** * total index, all ware with same catg_index will be compatible, * including special freight * assigned during registration */ uint8 catg_index; /** * index of the type, * assigned during registration */ uint8 goods_index; uint8 color; /** * Bonus for fast transport given in percent! */ uint16 speed_bonus; /** * Weight in KG per unit of this good */ uint16 weight_per_unit; public: // the measure for that good (crates, people, bags ... ) const char *get_mass() const { return get_child(2)->get_text(); } uint16 get_value() const { return value; } /** * @return speed bonus value of the good */ uint16 get_speed_bonus() const { return speed_bonus; } /** * @return Category of the good */ uint8 get_catg() const { return catg; } /** * @return Category of the good */ uint8 get_catg_index() const { return catg_index; } /** * @return internal index (just a number, passenger, then mail, then something ... ) */ uint8 get_index() const { return goods_index; } /** * @return weight in KG per unit of the good */ uint16 get_weight_per_unit() const { return weight_per_unit; } /** * @return Name of the category of the good */ const char * get_catg_name() const; /** * Checks if this good can be interchanged with the other, in terms of * transportability. * * Inline because called very often */ bool is_interchangeable(const goods_desc_t *other) const { return catg_index == other->get_catg_index(); } /** * @return color for good table and waiting bars */ PIXVAL get_color() const { return color_idx_to_rgb(color); } void calc_checksum(checksum_t *chk) const { chk->input(base_value); chk->input(catg); chk->input(speed_bonus); chk->input(weight_per_unit); } }; #endif simutrans-124.3/src/simutrans/descriptor/ground_desc.cc000066400000000000000000001117341474050137200233570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../world/simworld.h" #include "../display/simgraph.h" #include "../simconst.h" #include "spezial_obj_tpl.h" #include "ground_desc.h" #include "../dataobj/environment.h" //const int totalslopes_single = 16; const int totalslopes = 81; /**************************************************************************************************** * some functions for manipulations/blending images * maybe they should be put in their own module, even though they are only used here ... */ #if COLOUR_DEPTH != 0 #define red_comp(pix) (((pix)>>10)&0x001f) #define green_comp(pix) (((pix)>>5)&0x001f) #define blue_comp(pix) ((pix)&0x001f) #endif /* combines a texture and a lightmap * just weights all pixels by the lightmap * @param binary if true, then a binary decision is made: if lightmap is grey then take original pixel, if not set to black */ static image_t* create_textured_tile(const image_t* image_lightmap, const image_t* image_texture, bool binary = false) { if( image_lightmap == NULL ) { image_t *image_dest = image_t::create_single_pixel(); image_dest->register_image(); return image_dest; } image_t *image_dest = image_lightmap->copy_rotate(0); #if COLOUR_DEPTH != 0 PIXVAL* dest = image_dest->get_data(); PIXVAL const* const texture = image_texture->get_data(); sint16 const x_y = image_texture->get_pic()->w; // now mix the images for (int j = 0; j < image_dest->get_pic()->h; j++) { sint32 x = *dest++; assert(x >= 0); const sint32 offset = (image_dest->get_pic()->y + j - image_texture->get_pic()->y) * (x_y + 3) + 2; // position of the pixel in a rectangular map do { sint16 runlen = *dest++; assert(runlen >= 0); for(int i=0; i0); uint16 mix = texture[offset+x]; if (!binary) { uint16 grey = *dest; uint16 rc = (red_comp(grey)*red_comp(mix))/16; if(rc>=32) { rc = 31; } uint16 gc = (green_comp(grey)*green_comp(mix))/16; if(gc>=32) { gc = 31; } uint16 bc = (blue_comp(grey)*blue_comp(mix))/16; if(bc>=32) { bc = 31; } *dest++ = (rc<<10) | (gc<<5) | bc; } else { if (*dest) { *dest = mix;} dest++; } x ++; } x += *dest; } while( (*dest++)!=0 ); } assert(dest - image_dest->get_data() == (ptrdiff_t)image_dest->get_pic()->len); #else (void)image_texture; (void)binary; #endif image_dest->register_image(); return image_dest; } /* combines a texture and a lightmap * does a very simple stretching of the texture and the mix images * BEWARE: Assumes all images but image_lightmap are square! * BEWARE: no special colors or your will see literally blue! */ static image_t* create_alpha_tile(const image_t* image_lightmap, slope_t::type slope, const image_t* image_alphamap) { if( image_lightmap == NULL || image_alphamap == NULL || image_alphamap->get_pic()->w < 2 ) { image_t *image_dest = image_t::create_single_pixel(); image_dest->register_image(); return image_dest; } assert( image_alphamap->get_pic()->w == image_alphamap->get_pic()->h); image_t *image_dest = image_lightmap->copy_rotate(0); PIXVAL const* const alphamap = image_alphamap->get_data(); const sint32 x_y = image_dest->get_pic()->w; const sint32 mix_x_y = image_alphamap->get_pic()->w; sint16 tile_x, tile_y; /* * to go from mixmap xy to tile xy is simple: * (x,y)_tile = (mixmap_x+mixmap_y)/2 , (mixmap_y-mixmap_x)/4+(3/4)*tilesize * This is easily inverted to * (x,y)mixmap = x_tile-2*y_tile+(3/2)*tilesize, x_tile+2*y_tile-(3/2)*tilesize * tricky are slopes. There we have to add an extra distortion * /4\ * 1+3 * \2/ * Luckily this distortion is only for the y direction. * for corner 1: max(0,(tilesize-(x+y))*HEIGHT_STEP)/tilesize ) * for corner 2: max(0,((y-x)*HEIGHT_STEP)/tilesize ) * for corner 3: max(0,((x+y)-tilesize)*HEIGHT_STEP)/tilesize ) * for corner 4: max(0,((x-y)*HEIGHT_STEP)/tilesize ) * the maximum operators make the inversion of the above equation nearly impossible. */ // we will need them very often ... const sint16 corner_sw_y = (3 * x_y) / 4 - corner_sw(slope) * tile_raster_scale_y( TILE_HEIGHT_STEP, x_y ); const sint16 corner_se_y = x_y - corner_se(slope) * tile_raster_scale_y( TILE_HEIGHT_STEP, x_y ); const sint16 corner_ne_y = (3 * x_y) / 4 - corner_ne(slope) * tile_raster_scale_y( TILE_HEIGHT_STEP, x_y ); const sint16 corner_nw_y = (x_y / 2) - corner_nw(slope) * tile_raster_scale_y( TILE_HEIGHT_STEP, x_y ); const sint16 middle_y = (corner_se_y + corner_nw_y) / 2; // now mix the images PIXVAL* dest = image_dest->get_data(); for( int j = 0; j < image_dest->get_pic()->h; j++ ) { tile_y = image_dest->get_pic()->y + j; tile_x = *dest++; do { sint16 runlen = *dest++; for( int i = 0; i < runlen; i++ ) { // now we must calculate the target pixel // after the upper explanation, you will understand this is longish: sint16 tile_y_corrected; // first; check, if we are front or back half // back half means, we are above a line from the left_y (corner_sw), middle_y, right_y (corner_se) const sint16 back_y = (x_y < 2) ? 0 : ( (tile_x < x_y / 2) ? corner_sw_y + ((middle_y - corner_sw_y) * tile_x) / (x_y / 2) : middle_y + ((corner_ne_y - middle_y) * (tile_x - (x_y / 2))) / (x_y / 2) ); // in the middle? then it is just the diagonal in the mixmap if( back_y == tile_y ) { tile_y_corrected = 0; } else if( back_y > tile_y ) { // left quadrant calulation: mirror of right quadrat sint16 x = tile_x; if( x >= x_y / 2 ) { x = x_y - tile_x; } // we are in the back tile => calculate border y sint16 backborder_y; if( tile_x > x_y / 2 ) { backborder_y = corner_nw_y + ((corner_ne_y - corner_nw_y) * (x_y / 2 - x)) / (x_y / 2); } else { backborder_y = corner_sw_y + ((corner_nw_y - corner_sw_y) * x) / (x_y / 2); } // ok, now we have to calculate the y coordinate ... if( backborder_y < tile_y ) { tile_y_corrected = -((back_y - tile_y) * x) / (back_y - backborder_y); } else { tile_y_corrected = -x; } } else { // left quadrant calulation: mirror of right quadrat sint16 x = tile_x; // put condition this way, testing (x >= x_y) breaks if x_y == 1. if( 2*x >= x_y ) { x = x_y - tile_x; } // we are in the front tile => calculate border y sint16 frontborder_y = 0; if( tile_x > x_y / 2 ) { frontborder_y = corner_se_y + ((corner_ne_y - corner_se_y) * (x_y / 2 - x)) / (x_y / 2); } else if( x_y >=2 ) { frontborder_y = corner_sw_y + ((corner_se_y - corner_sw_y) * x) / (x_y / 2); } // ok, now we have to calculate the y coordinate ... if( frontborder_y > tile_y ) { tile_y_corrected = -((back_y - tile_y) * x) / (frontborder_y - back_y); } else { tile_y_corrected = x; } } // now we have calulated the y_t of square tile that is rotated by 45 degree // so we just have to do a 45 deg backtransform ... // (and do not forget: tile_y_corrected middle = 0! sint32 x_t = tile_x - tile_y_corrected; sint32 y_t = tile_y_corrected + tile_x; // due to some inexactness of integer arithmethics, we have to take care of overflow and underflow x_t = clamp(x_t, 0, x_y-1); y_t = clamp(y_t, 0, x_y-1); sint32 alphamap_offset = ((y_t * mix_x_y) / x_y) * (mix_x_y + 3) + 2 + (x_t * mix_x_y) / x_y; // see only the mixmap for mixing // // clear 0x8000 bit as it has special meaning, // confuses rezoom_img() and crashes later *dest++ = alphamap[alphamap_offset] & 0x7fff; tile_x++; } tile_x += *dest; } while( *dest++ != 0 ); } image_dest->register_image(); return image_dest; } // copy ref texture, copy pixels from image into new texture static image_t* create_texture_from_tile(const image_t* image, const image_t* ref) { if( image == NULL || image->get_pic()->w < 2 ) { image_t *image_dest = image_t::create_single_pixel(); return image_dest; } // assumes ref is texture image with no clear runs, full rows. image_t *image_dest = image_t::copy_image(*ref); PIXVAL *const sp2 = image_dest->get_data(); assert(ref->w == ref->y + ref->h && ref->x == 0); const sint32 ref_w = ref->w; const sint32 height= image->get_pic()->h; // decode image and put it into dest const PIXVAL* sp = image->get_data(); for(int y = 0; y < height; y++ ) { int x = image->x; uint16 runlen = *sp++; do { // we start with a clear run x += runlen; // now get colored pixels runlen = (*sp++); for(uint16 i=0; iy <= (yy) && (yy) < ref->h && 0 <= (xx) && (xx) < ref_w) { \ size_t const index = (ref_w + 3) * (yy - ref->y) + xx + 2; \ assert(index < image_dest->len); \ sp2[index] = p; \ } /* Put multiple copies into dest image * * image is assumed to be tile shaped, * and is copied four times to cover tiles of neighboring tiles. * * copy + copy * | / \ | * + image + * | \ / | * copy + copy * * ref image is assumed to be rectangular, * it is used to fill holes due to missing pixels in image. */ copypixel(x, y + image->y); copypixel(x + ref_w/2, y + image->y + ref_w/4); copypixel(x - ref_w/2, y + image->y + ref_w/4); copypixel(x + ref_w/2, y + image->y - ref_w/4); copypixel(x - ref_w/2, y + image->y - ref_w/4); x++; } } while( (runlen = *sp++) ); } // image_dest not registered return image_dest; #undef copypixel } /**************************************************************************************************** * the real textures are registered/calculated below */ karte_t *ground_desc_t::world = NULL; /* convert double to single slopes */ const uint8 ground_desc_t::slopetable[80] = { 0, 1, 0xFF, 2, 3, 0xFF, 0xFF, 0xFF, 0xFF, 4, 5, 0xFF, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 8, 9, 0xFF, 10, 11, 0xFF, 0xFF, 0xFF, 0xFF, 12, 13, 0xFF, 14, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // since we only use valid slope (to gain some more image slots) we use this lookup table // 255 slopes are invalid /* for double slope it should look like this, and for single slope like above 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 255, 255, 40, 255, 255, 41, 42, 43, 44, 255, 255, 45, 255, 255, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 255, 255, 59, 255, 255, 60, 61, 62, 63, 255, 255, 64, 255, 255 */ uint16 doubleslope_to_imgnr[81]; // how many animation stages we got for waves uint16 ground_desc_t::water_animation_stages = 1; sint16 ground_desc_t::water_depth_levels = 0; // are double_grounds available in this pakset ? bool ground_desc_t::double_grounds = true; static const ground_desc_t* boden_texture = NULL; static const ground_desc_t* light_map = NULL; static const ground_desc_t* transition_water_texture = NULL; static const ground_desc_t* transition_slope_texture = NULL; const ground_desc_t *ground_desc_t::shore = NULL; const ground_desc_t *ground_desc_t::fundament = NULL; const ground_desc_t *ground_desc_t::slopes = NULL; const ground_desc_t *ground_desc_t::fences = NULL; const ground_desc_t *ground_desc_t::marker = NULL; const ground_desc_t *ground_desc_t::borders = NULL; const ground_desc_t *ground_desc_t::sea = NULL; const ground_desc_t *ground_desc_t::outside = NULL; static special_obj_tpl const grounds[] = { { &ground_desc_t::shore, "Shore" }, { &boden_texture, "ClimateTexture" }, { &light_map, "LightTexture" }, { &transition_water_texture, "ShoreTrans" }, { &transition_slope_texture, "SlopeTrans" }, { &ground_desc_t::fundament, "Basement" }, { &ground_desc_t::slopes, "Slopes" }, { &ground_desc_t::fences, "Fence" }, { &ground_desc_t::marker, "Marker" }, { &ground_desc_t::borders, "Borders" }, { &ground_desc_t::sea, "Water" }, { &ground_desc_t::outside, "Outside" }, { NULL, NULL } }; // the water and seven climates static const char* const climate_names[MAX_CLIMATES] = { "sea", "desert", "tropic", "mediterran", "temperate", "tundra", "rocky", "arctic" }; // from this number on there will be all ground images // i.e. 15 times slopes + 7 image_id ground_desc_t::image_offset = IMG_EMPTY; static const uint8 number_of_climates = 7; static slist_tpl ground_image_list; static image_id climate_image[32], water_image; image_id alpha_image[totalslopes]; image_id alpha_corners_image[totalslopes * 15]; image_id alpha_water_image[totalslopes * 15]; /* * called every time an object is read * the object will be assigned according to its name */ bool ground_desc_t::register_desc(const ground_desc_t *desc) { if(strcmp("Outside", desc->get_name())==0) { image_t const* const image = desc->get_child(2)->get_image(0,0); dbg->message("ground_desc_t::register_desc()", "setting raster width to %i", image->get_pic()->w); display_set_base_raster_width(image->get_pic()->w); } // find out water animation stages if(strcmp("Water", desc->get_name())==0) { water_animation_stages = 0; while( desc->get_image(0, water_animation_stages)!=IMG_EMPTY ) { DBG_MESSAGE( "water", "image(0,%i)=%u", water_animation_stages, desc->get_image(0, water_animation_stages) ); water_animation_stages ++; } // then ignore all ms settings if(water_animation_stages==1) { env_t::water_animation = 0; } water_depth_levels = desc->get_child(2)->get_count()-2; if(water_depth_levels<=0) { water_depth_levels = 0; } } return ::register_desc(grounds, desc); } /* * called after loading; usually checks for completeness * however, we have to calculate all textures * and put them into images */ bool ground_desc_t::successfully_loaded() { DBG_MESSAGE("ground_desc_t::successfully_loaded()","boden"); return ::successfully_loaded(grounds+1); } /* returns the untranslated name of the matching climate */ char const* ground_desc_t::get_climate_name_from_bit(climate n) { return nget_image_ptr(0)->get_pic()->w == ground_desc_t::outside->get_image_ptr(0)->get_pic()->w); // create rotations of the mixer image_t *all_rotations_beach[totalslopes]; // water->sand->texture image_t *all_rotations_slope[totalslopes]; // texture1->texture2 image_t *final_tile = NULL; bool full_climate = true; // check if there are double slopes available for( int imgindex = 16; imgindex < totalslopes; imgindex++ ) { if( light_map->get_image_ptr(imgindex) == NULL ) { double_grounds = false; break; } } for( int imgindex = 4; imgindex < 15; imgindex++ ) { if( transition_slope_texture->get_image_ptr(imgindex) == NULL || (imgindex<=11 && transition_water_texture->get_image_ptr(imgindex) == NULL) ) { full_climate = false; break; } } // double slope needs full climates assert(!double_grounds || full_climate); // calculate the matching slopes ... doubleslope_to_imgnr[0] = 0; for( int slope = 1, slopeimgnr=1; slope < totalslopes; slope++ ) { all_rotations_beach[slope] = NULL; all_rotations_slope[slope] = NULL; doubleslope_to_imgnr[slope] = 255; if( slope != 80 && (slope_t::is_all_up(slope) || (!double_grounds && slope_t::max_diff(slope)>1) ) ) { // no need to initialize unneeded slopes // slope 80 is needed below continue; } // now add this image doubleslope_to_imgnr[slope] = slopeimgnr++; image_t *tmp_pic = NULL; switch( slope ) { case slope_t::north: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(180); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(180); break; } case slope_t::east: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(90); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(90); break; } case slope_t::south: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(0); break; } case slope_t::west: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(270); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(270); break; } case slope_t::northwest + slope_t::northeast + slope_t::southeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(1)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(1)->copy_rotate(0); break; } case slope_t::northeast + slope_t::southeast + slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(1)->copy_rotate(270); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(1)->copy_rotate(270); break; } case slope_t::southeast + slope_t::southwest + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(1)->copy_rotate(180); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(1)->copy_rotate(180); break; } case slope_t::southwest + slope_t::northwest + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(1)->copy_rotate(90); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(1)->copy_rotate(90); break; } case slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(2)->copy_rotate(90); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(2)->copy_rotate(90); break; } case slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(2)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(2)->copy_rotate(0); break; } case slope_t::southeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(2)->copy_rotate(270); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(2)->copy_rotate(270); break; } case slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(2)->copy_rotate(180); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(2)->copy_rotate(180); break; } case slope_t::southwest + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(3)->copy_rotate(90); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(3)->copy_rotate(90); break; } case slope_t::southeast + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(3)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(3)->copy_rotate(0); break; } case slope_t::southwest + slope_t::northeast + slope_t::southeast + slope_t::northwest: { if( double_grounds ) { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(14)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(11)->copy_rotate(0); } else { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(0); } break; } default: { if( full_climate ) { switch( slope ) { case slope_t::north * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(4)->copy_rotate(180); break; } case slope_t::east * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(4)->copy_rotate(90); break; } case slope_t::south * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(4)->copy_rotate(0); break; } case slope_t::west * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(4)->copy_rotate(270); break; } case slope_t::northwest * 2 + slope_t::northeast * 2 + slope_t::southeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(5)->copy_rotate(0); break; } case slope_t::northeast * 2 + slope_t::southeast * 2 + slope_t::southwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(5)->copy_rotate(270); break; } case slope_t::southeast * 2 + slope_t::southwest * 2 + slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(5)->copy_rotate(180); break; } case slope_t::southwest * 2 + slope_t::northwest * 2 + slope_t::northeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(5)->copy_rotate(90); break; } case slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(6)->copy_rotate(90); break; } case slope_t::northeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(6)->copy_rotate(0); break; } case slope_t::southeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(6)->copy_rotate(270); break; } case slope_t::southwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(6)->copy_rotate(180); break; } case slope_t::southwest * 2 + slope_t::northeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(7)->copy_rotate(90); break; } case slope_t::southeast * 2 + slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(7)->copy_rotate(0); break; } case slope_t::northwest + slope_t::northeast * 2 + slope_t::southeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(13)->copy_rotate(0); break; } case slope_t::northeast + slope_t::southeast * 2+slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(13)->copy_rotate(270); break; } case slope_t::southeast + slope_t::southwest * 2 + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(13)->copy_rotate(180); break; } case slope_t::southwest + slope_t::northwest * 2 + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(13)->copy_rotate(90); break; } case slope_t::northeast * 2 + slope_t::southeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(8)->copy_rotate(270); break; } case slope_t::southeast * 2 + slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(8)->copy_rotate(180); break; } case slope_t::southwest * 2 + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(8)->copy_rotate(90); break; } case slope_t::northwest * 2 + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(8)->copy_rotate(0); break; } case slope_t::northwest + slope_t::northeast * 2: { tmp_pic = transition_slope_texture->get_image_ptr(8)->copy_rotate(0); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::northeast + slope_t::southeast * 2: { tmp_pic = transition_slope_texture->get_image_ptr(8)->copy_rotate(90); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::southeast + slope_t::southwest * 2: { tmp_pic = transition_slope_texture->get_image_ptr(8)->copy_rotate(0); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::northwest * 2 + slope_t::southwest: { tmp_pic = transition_slope_texture->get_image_ptr(8)->copy_rotate(90); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::northwest * 2 + slope_t::southeast + slope_t::southwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(12)->copy_rotate(270); break; } case slope_t::northwest * 2 + slope_t::northeast * 2 + slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(12)->copy_rotate(180); break; } case slope_t::northwest + slope_t::northeast * 2 + slope_t::southeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(12)->copy_rotate(90); break; } case slope_t::northeast + slope_t::southeast * 2 + slope_t::southwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(12)->copy_rotate(0); break; } case slope_t::northeast * 2 + slope_t::southeast * 2 + slope_t::southwest: { tmp_pic = transition_slope_texture->get_image_ptr(12)->copy_rotate(270); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::northwest + slope_t::southeast * 2 + slope_t::southwest * 2: { tmp_pic = transition_slope_texture->get_image_ptr(12)->copy_rotate(180); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::northwest * 2 + slope_t::northeast + slope_t::southwest * 2: { tmp_pic = transition_slope_texture->get_image_ptr(12)->copy_rotate(90); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::northwest * 2 + slope_t::northeast * 2 + slope_t::southeast: { tmp_pic = transition_slope_texture->get_image_ptr(12)->copy_rotate(0); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::southwest + slope_t::southeast + slope_t::northeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(10)->copy_rotate(270); break; } case slope_t::southwest + slope_t::northwest + slope_t::southeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(10)->copy_rotate(180); break; } case slope_t::northwest + slope_t::northeast + slope_t::southwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(10)->copy_rotate(90); break; } case slope_t::southeast + slope_t::northeast + slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(10)->copy_rotate(0); break; } case slope_t::southwest + slope_t::southeast + slope_t::northwest * 2: { tmp_pic = transition_slope_texture->get_image_ptr(10)->copy_rotate(270); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::southwest + slope_t::northwest + slope_t::northeast * 2: { tmp_pic = transition_slope_texture->get_image_ptr(10)->copy_rotate(180); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::northwest + slope_t::northeast + slope_t::southeast * 2: { tmp_pic = transition_slope_texture->get_image_ptr(10)->copy_rotate(90); all_rotations_slope[slope] = tmp_pic->copy_flipvertical(); delete tmp_pic; break; } case slope_t::southeast + slope_t::northeast + slope_t::southwest * 2: { tmp_pic = transition_slope_texture->get_image_ptr(10)->copy_rotate(0); all_rotations_slope[slope] = tmp_pic->copy_fliphorizontal(); delete tmp_pic; break; } case slope_t::southeast + slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(9)->copy_rotate(270); break; } case slope_t::southwest + slope_t::northeast * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(9)->copy_rotate(180); break; } case slope_t::southeast * 2 + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(9)->copy_rotate(90); break; } case slope_t::southwest * 2 + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(9)->copy_rotate(0); break; } case slope_t::southeast * 2 + slope_t::northwest * 2 + slope_t::southwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(11)->copy_rotate(270); break; } case slope_t::southwest * 2 + slope_t::northeast * 2 + slope_t::northwest: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(11)->copy_rotate(180); break; } case slope_t::southeast * 2 + slope_t::northwest * 2 + slope_t::northeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(11)->copy_rotate(90); break; } case slope_t::southwest * 2 + slope_t::northeast * 2 + slope_t::southeast: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(11)->copy_rotate(0); break; } case slope_t::southwest * 2 + slope_t::northeast * 2 + slope_t::southeast * 2 + slope_t::northwest * 2: { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(14)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(11)->copy_rotate(0); break; } } } else { all_rotations_slope[slope] = NULL; if (slope == slope_t::southwest * 2 + slope_t::northeast * 2 + slope_t::southeast * 2 + slope_t::northwest * 2) { all_rotations_slope[slope] = transition_slope_texture->get_image_ptr(0)->copy_rotate(0); all_rotations_beach[slope] = transition_water_texture->get_image_ptr(0)->copy_rotate(0); } } break; } } } // from here on the images are generated by us => deletion also by us then image_offset = get_image_count(); DBG_MESSAGE("ground_desc_t::init_ground_textures()","image_offset=%d", image_offset ); // water images for water and overlay water_image = image_offset; image_t **water_stage_texture = new image_t*[water_animation_stages]; for(uint16 stage = 0; stage < water_animation_stages; stage++) { water_stage_texture[stage] = create_texture_from_tile(sea->get_image_ptr(0 /*depth*/, stage), boden_texture->get_image_ptr(water_climate)); } for( int dslope = 0; dslope < totalslopes - 1; dslope++ ) { for(uint16 stage = 0; stage < water_animation_stages; stage++) { if( doubleslope_to_imgnr[dslope] != 255 ) { int slope = double_grounds ? dslope : slopetable[dslope]; final_tile = create_textured_tile( light_map->get_image_ptr( slope ), water_stage_texture[stage], true); ground_image_list.append( final_tile ); } } } for(uint16 stage = 0; stage < water_animation_stages; stage++) { delete water_stage_texture[stage]; } delete [] water_stage_texture; // now the other transitions for( int i=0; i < number_of_climates; i++ ) { // normal tile (no transition, not snow) climate_image[i] = get_image_count(); for( int dslope = 0; dslope < totalslopes - 1; dslope++ ) { if( doubleslope_to_imgnr[dslope] != 255 ) { int slope = double_grounds ? dslope : slopetable[dslope]; final_tile = create_textured_tile( light_map->get_image_ptr( slope ), boden_texture->get_image_ptr( i+1 ) ); ground_image_list.append( final_tile ); } } } // finally full snow climate_image[number_of_climates] = final_tile->get_id() + 1; for( int dslope = 0; dslope < totalslopes - 1; dslope++ ) { if( doubleslope_to_imgnr[dslope] != 255 ) { int slope = double_grounds ? dslope : slopetable[dslope]; final_tile = create_textured_tile( light_map->get_image_ptr( slope ), boden_texture->get_image_ptr( arctic_climate ) ); ground_image_list.append( final_tile ); } } // alpha slopes for snowline for( int dslope = 1; dslope < totalslopes - 1; dslope++ ) { if( doubleslope_to_imgnr[dslope] != 255 ) { int slope = double_grounds ? dslope : slopetable[dslope]; final_tile = create_alpha_tile( light_map->get_image_ptr( slope ), dslope, all_rotations_slope[dslope] ); alpha_image[dslope] = final_tile->get_id(); } else { alpha_image[dslope] = IMG_EMPTY; } } // alpha transitions for climates for( int dslope = 0; dslope < totalslopes - 1; dslope++ ) { for( int corners = 1; corners < 16; corners++ ) { if( doubleslope_to_imgnr[dslope] != 255 ) { // slope of tile int slope = double_grounds ? dslope : slopetable[dslope]; // corners with transition uint8 double_corners = corners == 15 ? 80 : slope_from_slope4(slope4_t(corners), 1); // create alpha image final_tile = create_alpha_tile( light_map->get_image_ptr( slope ), dslope, all_rotations_slope[double_corners] ); alpha_corners_image[dslope * 15 + corners - 1] = final_tile->get_id(); double_corners = corners == 15 ? 80 : slope_from_slope4(slope4_t(15-corners), 1); if( all_rotations_beach[double_corners] ) { final_tile = create_alpha_tile( light_map->get_image_ptr( slope ), dslope, all_rotations_beach[double_corners] ); alpha_water_image[dslope * 15 + corners - 1] = final_tile->get_id(); } } else { alpha_corners_image[dslope * 15 + corners - 1] = IMG_EMPTY; alpha_water_image[dslope * 15 + corners - 1] = IMG_EMPTY; } } } #if COLOUR_DEPTH != 0 // free the helper bitmap for( int slope = 1; slope < totalslopes; slope++ ) { delete all_rotations_slope[slope]; delete all_rotations_beach[slope]; } #endif //dbg->message("ground_desc_t::calc_water_level()", "Last image nr %u", final_tile->get_pic()->imageid); DBG_DEBUG("ground_desc_t::init_ground_textures()", "Init ground textures successful"); } /* returns a ground image for all ground tiles * current is the current climate * transition is true, if the next level is another climate * snow is true, if above slowline * * Since not all of the climates are used in their numerical order, we use a * private (static table "height_to_texture_climate" for lookup) */ image_id ground_desc_t::get_ground_tile(grund_t *gr) { slope_t::type slope = gr->get_grund_hang(); sint16 height = gr->get_hoehe(); koord k = gr->get_pos().get_2d(); const sint16 tile_h = height - world->get_water_hgt(k); if( tile_h < 0 || (tile_h == 0 && slope == slope_t::flat) ) { // deep water image_array_t const* const list = sea->get_child(2); int nr = min( -tile_h, list->get_count() - 2 ); return list->get_image( nr, 0 )->get_id(); } else { const bool snow = height >= world->get_snowline(); const sint16 climate_nr = snow ? number_of_climates : (world->get_climate(k) > 1 ? world->get_climate(k) - 1 : 0); // returns base climate for tile, transitions will be overlayed later return climate_image[climate_nr] + doubleslope_to_imgnr[slope]; } return IMG_EMPTY; } image_id ground_desc_t::get_water_tile(slope_t::type slope, int stage) { return water_image + stage + water_animation_stages*doubleslope_to_imgnr[slope]; } image_id ground_desc_t::get_climate_tile(climate cl, slope_t::type slope) { return climate_image[cl <= 0 ? 0 : cl - 1] + doubleslope_to_imgnr[slope]; } image_id ground_desc_t::get_snow_tile(slope_t::type slope) { return climate_image[number_of_climates] + doubleslope_to_imgnr[slope]; } image_id ground_desc_t::get_beach_tile(slope_t::type slope, uint8 corners) { return alpha_water_image[slope * 15 + corners - 1]; } image_id ground_desc_t::get_alpha_tile(slope_t::type slope, uint8 corners) { return alpha_corners_image[slope * 15 + corners - 1]; } image_id ground_desc_t::get_alpha_tile(slope_t::type slope) { return alpha_image[slope]; } simutrans-124.3/src/simutrans/descriptor/ground_desc.h000066400000000000000000000062551474050137200232220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_GROUND_DESC_H #define DESCRIPTOR_GROUND_DESC_H #include "obj_base_desc.h" #include "image_array.h" #include "../simtypes.h" #include "../dataobj/ribi.h" class grund_t; class karte_t; /** * Images of all possible surface tiles: slopes, climates, transitions, etc. * * Child nodes: * 0 Name * 1 Copyright * 2 Image-array */ class ground_desc_t : public obj_named_desc_t { private: static karte_t *world; static image_id image_offset; public: static uint16 water_animation_stages; static sint16 water_depth_levels; // only these textures need external access static const ground_desc_t *shore; // nicer shore graphics, optional static const ground_desc_t *fundament; static const ground_desc_t *slopes; static const ground_desc_t *fences; static const ground_desc_t *marker; static const ground_desc_t *borders; static const ground_desc_t *sea; // different water depth static const ground_desc_t *outside; static char const* get_climate_name_from_bit(climate n); static bool double_grounds; static const uint8 slopetable[80]; // returns the pointer to an image structure const image_t *get_image_ptr(uint16 typ, uint16 stage=0) const { image_array_t const* const imgarray = get_child(2); image_list_t const* const list = imgarray->get_list(typ); if(list && list->get_count() > 0) { image_t const* const image = imgarray->get_image(typ, stage); return image; } return NULL; } // image for all non-climate stuff like foundations ... image_id get_image(uint16 typ, uint16 stage=0) const { image_t const* const image = get_image_ptr(typ, stage); return image ? image->get_id() : IMG_EMPTY; } // image for all ground tiles static image_id get_ground_tile(grund_t *gr); static image_id get_water_tile(slope_t::type slope, int stage); static image_id get_climate_tile(climate cl, slope_t::type slope); static image_id get_snow_tile(slope_t::type slope); static image_id get_beach_tile(slope_t::type slope, uint8 corners); static image_id get_alpha_tile(slope_t::type slope); static image_id get_alpha_tile(slope_t::type slope, uint8 corners); static bool register_desc(const ground_desc_t *desc); static bool successfully_loaded(); /** * Generates ground texture images, transition maps, etc. */ static void init_ground_textures(karte_t *world); static image_id get_marker_image(slope_t::type slope_in, bool background) { uint8 slope = double_grounds ? slope_in : slopetable[slope_in]; uint8 index = background ? (double_grounds ? (slope % 3) + 3 * ((uint8)(slope / 9)) + 27 : ((slope & 1) + ((slope >> 1) & 6) + 8)) : (double_grounds ? slope % 27 : (slope & 7 )); return marker->get_image(index); } static image_id get_border_image(slope_t::type slope_in) { uint8 slope = double_grounds ? slope_in : slopetable[slope_in]; uint8 index = double_grounds ? (slope % 3) + 3 * ((uint8)(slope / 9)) : (slope & 1) + ((slope >> 1) & 6); return borders->get_image(index); } }; #endif simutrans-124.3/src/simutrans/descriptor/groundobj_desc.h000066400000000000000000000047071474050137200237150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_GROUNDOBJ_DESC_H #define DESCRIPTOR_GROUNDOBJ_DESC_H #include "../simtypes.h" #include "obj_base_desc.h" #include "image_array.h" #include "../network/checksum.h" /** * This is the description for ground objects like small lakes, hunting post, birds, flower patch, stones, sheeps, ... * these can either reside on a tile (moving=0) * or move around the map (water_t=only on water, air_t=everywhere) * They are removable with certain costs. * * Child nodes: * 0 Name * 1 Copyright * 2 Image-array */ class groundobj_desc_t : public obj_named_desc_t { friend class groundobj_reader_t; friend class groundobj_t; friend class movingobj_t; climate_bits allowed_climates; uint16 distribution_weight; uint8 number_of_seasons; sint32 speed; uint16 index; bool trees_on_top; waytype_t wtyp; sint32 price; public: uint16 get_distribution_weight() const { return distribution_weight; } bool is_allowed_climate( climate cl ) const { return ((1<(2)->get_image(phase, season); } image_id get_image_id(uint8 season, uint16 phase) const { const image_t *image = get_child(2)->get_image(phase, season); return image != NULL ? image->get_id() : IMG_EMPTY; } // moving stuff should have eight // otherwise up to 16 for all slopes are ok // if count==1, this will not appear on slopes uint16 get_phases() const { return get_child(2)->get_count(); } uint8 get_seasons() const { return number_of_seasons; } sint32 get_speed() const { return speed; } bool can_build_trees_here() const { return trees_on_top; } waytype_t get_waytype() const { return wtyp; } sint32 get_price() const { return price; } uint16 get_index() const { return index; } void calc_checksum(checksum_t *chk) const { chk->input((uint8)allowed_climates); chk->input(distribution_weight); chk->input(number_of_seasons); chk->input(speed); chk->input(trees_on_top); chk->input((uint8)wtyp); chk->input(price); } }; #endif simutrans-124.3/src/simutrans/descriptor/image.cc000066400000000000000000000111241474050137200221350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "image.h" #include "../display/simgraph.h" #include "../simtypes.h" #include "../simdebug.h" #include "../macros.h" #include #include /** * Definition of special colors */ const uint32 image_t::rgbtab[SPECIAL] = { 0x244B67, // Player color 1 0x395E7C, 0x4C7191, 0x6084A7, 0x7497BD, 0x88ABD3, 0x9CBEE9, 0xB0D2FF, 0x7B5803, // Player color 2 0x8E6F04, 0xA18605, 0xB49D07, 0xC6B408, 0xD9CB0A, 0xECE20B, 0xFFF90D, 0x57656F, // Dark windows, lit yellowish at night 0x7F9BF1, // Lighter windows, lit blueish at night 0xFFFF53, // Yellow light 0xFF211D, // Red light 0x01DD01, // Green light 0x6B6B6B, // Non-darkening grey 1 (menus) 0x9B9B9B, // Non-darkening grey 2 (menus) 0xB3B3B3, // non-darkening grey 3 (menus) 0xC9C9C9, // Non-darkening grey 4 (menus) 0xDFDFDF, // Non-darkening grey 5 (menus) 0xE3E3FF, // Nearly white light at day, yellowish light at night 0xC1B1D1, // Windows, lit yellow 0x4D4D4D, // Windows, lit yellow 0xFF017F, // purple light 0x0101FF, // blue light }; image_t* image_t::copy_image(const image_t& other) { image_t* img = new image_t(other.len); img->len = other.len; img->x = other.x; img->y = other.y; img->w = other.w; img->h = other.h; img->imageid = IMG_EMPTY; img->zoomable = other.zoomable; memcpy(img->data, other.data, other.len * sizeof(PIXVAL)); return img; } // creates a single pixel dummy picture image_t* image_t::create_single_pixel() { image_t* desc = new image_t(4); desc->len = 4; desc->x = 0; desc->y = 0; desc->w = 1; desc->h = 1; desc->zoomable = 0; desc->data[0] = 0; desc->data[1] = 0; desc->data[2] = 0; desc->data[3] = 0; return desc; } /* rotate_image_data - produces a (rotated) image * only rotates by 90 degrees or multiples thereof, and assumes a square image * Otherwise it will only succeed for angle=0; */ image_t *image_t::copy_rotate(const sint16 angle) const { #if COLOUR_DEPTH == 0 (void)angle; return create_single_pixel(); #endif assert(angle == 0 || (w == h && x == 0 && y == 0)); image_t* target_image = copy_image(*this); // the format is // transparent PIXELVAL number // PIXEL number of pixels, data*PIXVAL // repeated until zero transparent pixels // in pak64 case it is 0 64 64*PIXVAL 0 for a single line, e.g. 70 bytes per line for pak64 // first data will have an offset of two PIXVAL // now you should understand below arithmetics ... sint16 const x_y = w; PIXVAL const* const src = get_data(); PIXVAL* const target = target_image->get_data(); switch(angle) { case 90: for(int j=0; jget_data(); for( int j = 0; j < x_y; j++ ) { for( int i = 0; i < x_y; i++ ) { target[i * (x_y + 3) + j + 2] = src[(x_y - i - 1) * (x_y + 3) + j + 2]; } } return target_image; } image_t *image_t::copy_fliphorizontal() const { image_t* target_image = copy_image(*this); // the format is // transparent PIXELVAL number // PIXEL number of pixels, data*PIXVAL // repeated until zero transparent pixels // in pak64 case it is 0 64 64*PIXVAL 0 for a single line, e.g. 70 bytes per line for pak64 // first data will have an offset of two PIXVAL // now you should understand below arithmetics ... sint16 const x_y = w; PIXVAL const* const src = get_data(); PIXVAL* const target = target_image->get_data(); for( int i = 0; i < x_y; i++ ) { for( int j = 0; j < x_y; j++ ) { target[i * (x_y + 3) + j + 2] = src[i * (x_y + 3) + (x_y - j - 1) + 2]; } } return target_image; } simutrans-124.3/src/simutrans/descriptor/image.h000066400000000000000000000034071474050137200220040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_IMAGE_H #define DESCRIPTOR_IMAGE_H #include "../display/simgraph.h" #include "../display/simimg.h" #include "obj_desc.h" // number of special colors #define SPECIAL (31) #define SPECIAL_TRANSPARENT (0x00E7FFFF) /** * Data of one image * * Child nodes: * (none) */ class image_t : public obj_desc_t { public: static const uint32 rgbtab[SPECIAL]; size_t len; ///< length of data[] in PIXVAL units scr_coord_val x; ///< x offset of data[] image scr_coord_val y; ///< y offset of data[] image scr_coord_val w; ///< width of data[] image scr_coord_val h; ///< height of data[] image image_id imageid; ///< set by register_image() uint8 zoomable; ///< some images may not be zoomed i.e. icons PIXVAL *data; ///< RLE encoded image data image_t(size_t len_=0) : data(NULL) { if (len_) { alloc(len_); } } ~image_t() { delete [] data; } void alloc(size_t len_) { delete [] data; data = new PIXVAL[len_]; len = len_; } static image_t* copy_image(const image_t& other); const image_t* get_pic() const { return this; } uint16 const* get_data() const { return data; } uint16* get_data() { return data; } image_id get_id() const { return imageid; } /* rotate_image_data - produces a (rotated) image * only rotates by 90 degrees or multiples thereof, and assumes a square image * Otherwise it will only succeed for angle=0; */ image_t* copy_rotate(const sint16 angle) const; image_t* copy_flipvertical() const; image_t* copy_fliphorizontal() const; static image_t* create_single_pixel(); void register_image() { ::register_image(this); } private: friend class image_reader_t; }; #endif simutrans-124.3/src/simutrans/descriptor/image_array.h000066400000000000000000000013671474050137200232050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_IMAGE_ARRAY_H #define DESCRIPTOR_IMAGE_ARRAY_H #include "image_list.h" /** * Two-dimensional array of images * * Child nodes: * 0 1st Image-list * 1 2nd Image-list * ... ... */ class image_array_t : public obj_desc_t { friend class imagelist2d_reader_t; uint16 count; public: image_array_t() : count(0) {} uint16 get_count() const { return count; } image_list_t const* get_list(uint16 i) const { return i < count ? get_child(i) : 0; } image_t const* get_image(uint16 i, uint16 j) const { return i < count ? get_child(i)->get_image(j) : 0; } }; #endif simutrans-124.3/src/simutrans/descriptor/image_list.h000066400000000000000000000013101474050137200230260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_IMAGE_LIST_H #define DESCRIPTOR_IMAGE_LIST_H #include "image.h" /** * One-dimensional image list. * * Child nodes: * 0 1st Image * 1 2nd Image * ... ... */ class image_list_t : public obj_desc_t { friend class imagelist_reader_t; uint16 count; public: image_list_t() : count(0) {} uint16 get_count() const { return count; } image_t const* get_image(uint16 i) const { return i < count ? get_child(i) : 0; } image_id get_image_id(uint16 i) const { const image_t *image = get_image(i); return image != NULL ? image->get_id() : IMG_EMPTY; } }; #endif simutrans-124.3/src/simutrans/descriptor/intro_dates.h000066400000000000000000000005051474050137200232310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_INTRO_DATES_H #define DESCRIPTOR_INTRO_DATES_H // just some default intro and retirement dates, if nothing else is defined #define DEFAULT_INTRO_DATE (1900) #define DEFAULT_RETIRE_DATE (2999) #endif simutrans-124.3/src/simutrans/descriptor/obj_base_desc.cc000066400000000000000000000010051474050137200236120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "obj_base_desc.h" #include "../network/checksum.h" void obj_desc_timelined_t::calc_checksum(checksum_t *chk) const { chk->input(intro_date); chk->input(retire_date); } void obj_desc_transport_related_t::calc_checksum(checksum_t *chk) const { obj_desc_timelined_t::calc_checksum(chk); chk->input(maintenance); chk->input(price); chk->input(wtyp); chk->input(topspeed); chk->input(axle_load); } simutrans-124.3/src/simutrans/descriptor/obj_base_desc.h000066400000000000000000000057471474050137200234750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_OBJ_BASE_DESC_H #define DESCRIPTOR_OBJ_BASE_DESC_H #include "text_desc.h" class checksum_t; class tool_t; /** * Common base class for all object descriptors, which get their name and * copyright information from child 0 and 1 */ class obj_named_desc_t : public obj_desc_t { public: const char *get_name() const { return get_child(0)->get_text(); } const char *get_copyright() const { const text_desc_t *const ts = get_child(1); if (!ts) { return 0; } const char *const text = ts->get_text(); return text[0] != '\0' ? text : NULL; } }; /** * Base class for all stuff that depends on timeline. */ class obj_desc_timelined_t : public obj_named_desc_t { protected: uint16 intro_date; ///< this thing is available from this date uint16 retire_date; ///< this thing is available until this date public: obj_desc_timelined_t() : obj_named_desc_t(), intro_date(0), retire_date(0) {} uint16 get_intro_year_month() const { return intro_date; } uint16 get_retire_year_month() const { return retire_date; } /// @return true if this object is available with timeline. bool is_available(const uint16 month_now) const { return month_now==0 || (intro_date<=month_now && retire_date>month_now); } /// @return true if this is still not available bool is_future(const uint16 month_now) const { return month_now && (intro_date > month_now); } /// @return true if this is obsolete bool is_retired(const uint16 month_now) const { return month_now && (retire_date <= month_now); } void calc_checksum(checksum_t *chk) const; }; /** * Base class for all transport related stuff. */ class obj_desc_transport_related_t : public obj_desc_timelined_t { protected: sint32 maintenance; ///< monthly cost for bits_per_month=18 sint32 price; ///< cost to build this thing [1/100 credits] per tile/object uint16 axle_load; ///< up to this load vehicle may pass (default 9999) uint8 wtyp; ///< waytype of this thing sint32 topspeed; ///< maximum allowed speed in km/h public: obj_desc_transport_related_t() : obj_desc_timelined_t(), maintenance(0), price(0), axle_load(9999), wtyp(255), topspeed(0) {} sint32 get_maintenance() const { return maintenance; } sint32 get_price() const { return price; } waytype_t get_waytype() const { return static_cast(wtyp); } waytype_t get_wtyp() const { return get_waytype(); } sint32 get_topspeed() const { return topspeed; } uint16 get_axle_load() const { return axle_load; } void calc_checksum(checksum_t *chk) const; }; /** * Base class for all transport infrastructure. */ class obj_desc_transport_infrastructure_t : public obj_desc_transport_related_t { protected: tool_t *builder; ///< default tool for building public: tool_t *get_builder() const { return builder; } void set_builder( tool_t *tool ) { builder = tool; } }; #endif simutrans-124.3/src/simutrans/descriptor/obj_desc.h000066400000000000000000000023531474050137200224710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_OBJ_DESC_H #define DESCRIPTOR_OBJ_DESC_H #include #include "../simtypes.h" /** * Basis of all desc_t classes, which are loaded from the .pak files. * No virtual methods are allowed! */ class obj_desc_t { friend class pakset_manager_t; public: obj_desc_t() : children() {} ~obj_desc_t() { delete [] children; } void* operator new(size_t size) { return ::operator new(size); } void* operator new(size_t size, size_t extra) { return ::operator new(size + extra); } /* * Only support basic delete operator. * Prevents C++14 and newer compilers from implicitly adding a sized delete operator. * The sized delete operator conflicts with the definiton of the placement new operator. */ void operator delete(void* ptr) { return ::operator delete(ptr); } protected: template T const* get_child(int const i) const { return static_cast(children[i]); } private: /* * Internal Node information - the derived class knows, * how many node child nodes really exist. */ obj_desc_t** children; friend class factory_field_group_reader_t; friend class obj_reader_t; }; #endif simutrans-124.3/src/simutrans/descriptor/obj_node_info.h000066400000000000000000000011201474050137200235020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_OBJ_NODE_INFO_H #define DESCRIPTOR_OBJ_NODE_INFO_H #include "../simtypes.h" // these are the sizes of the divers heades on the disk // if the uint16 size is LARGE_RECORD_SIZE the actual length is in a following uint32 #define OBJ_NODE_INFO_SIZE (8) #define EXT_OBJ_NODE_INFO_SIZE (12) #define LARGE_RECORD_SIZE (0xFFFFu) /** * Stored structure of a pak node inside the file. */ struct obj_node_info_t { uint32 type; uint16 nchildren; uint32 size; }; #endif simutrans-124.3/src/simutrans/descriptor/objversion.h000066400000000000000000000043051474050137200231000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_OBJVERSION_H #define DESCRIPTOR_OBJVERSION_H #include "../simtypes.h" #define COMPILER_VERSION "0.1.3exp" #define COMPILER_VERSION_CODE_11 (0 * 1000000 + 1 * 1000 + 1) #define COMPILER_VERSION_CODE (0 * 1000000 + 1 * 1000 + 3) /* * obj_type value are stored inside the pak-files. Values are choosen to make * them somewhat readable (up to 4 uppercase letters describing the type). * obj as 4 byte: 3073094 bytes total * obj as 2 byte: 3063046 bytes total * obj as 1 byte: 3058022 bytes total * saves 4 to 1: 15072 bytes = 0,5% not worth it */ #define C4ID(a, b ,c ,d) (((uint32)a) | ((uint32)b) << 8 | ((uint32)c) << 16 | ((uint32)d) << 24) enum obj_type : uint32 { obj_bridge = C4ID('B','R','D','G'), obj_building = C4ID('B','U','I','L'), obj_citycar = C4ID('C','C','A','R'), obj_crossing = C4ID('C','R','S','S'), obj_cursor = C4ID('C','U','R','S'), obj_factory = C4ID('F','A','C','T'), obj_ffield = C4ID('F','F','I','E'), obj_ffldclass = C4ID('F','F','C','L'), obj_field = C4ID('F','I','E','L'), obj_fproduct = C4ID('F','P','R','O'), obj_fsmoke = C4ID('F','S','M','O'), obj_fsupplier = C4ID('F','S','U','P'), obj_good = C4ID('G','O','O','D'), obj_ground = C4ID('G','R','N','D'), obj_groundobj = C4ID('G','O','B','J'), obj_image = C4ID('I','M','G', 0 ), obj_imagelist = C4ID('I','M','G','1'), obj_imagelist2d = C4ID('I','M','G','2'), obj_menu = C4ID('M','E','N','U'), obj_miscimages = C4ID('M','I','S','C'), obj_pedestrian = C4ID('P','A','S','S'), obj_roadsign = C4ID('S','I','G','N'), obj_root = C4ID('R','O','O','T'), obj_smoke = C4ID('S','M','O','K'), obj_sound = C4ID('S','O','U','N'), obj_symbol = C4ID('S','Y','M','B'), obj_text = C4ID('T','E','X','T'), obj_tile = C4ID('T','I','L','E'), obj_tree = C4ID('T','R','E','E'), obj_tunnel = C4ID('T','U','N','L'), obj_vehicle = C4ID('V','H','C','L'), obj_way = C4ID('W','A','Y', 0 ), obj_way_obj = C4ID('W','Y','O','B'), obj_xref = C4ID('X','R','E','F') }; #endif simutrans-124.3/src/simutrans/descriptor/pedestrian_desc.h000066400000000000000000000025451474050137200240600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_PEDESTRIAN_DESC_H #define DESCRIPTOR_PEDESTRIAN_DESC_H #include "obj_base_desc.h" #include "image_array.h" #include "image_list.h" #include "../dataobj/ribi.h" #include "../network/checksum.h" /** * Pedestrians. * * Child nodes: * 0 Name * 1 Copyright * 2 Image-list or 2d */ class pedestrian_desc_t : public obj_desc_timelined_t { friend class pedestrian_reader_t; uint16 distribution_weight; uint16 steps_per_frame; uint16 offset; public: image_id get_image_id(ribi_t::dir dir, uint16 phase=0) const { image_t const* image = NULL; if (steps_per_frame > 0) { image = get_child(2)->get_image(dir, phase); } else { image = get_child(2)->get_image(dir); } return image != NULL ? image->get_id() : IMG_EMPTY; } uint16 get_distribution_weight() const { return distribution_weight; } uint16 get_steps_per_frame() const { return steps_per_frame; } uint16 get_animation_count(ribi_t::dir dir) const { return steps_per_frame>0 ? get_child(2)->get_list(dir)->get_count() : 1; } void calc_checksum(checksum_t *chk) const { chk->input(distribution_weight); } // images are offset steps away from boundary uint16 get_offset() const { return offset; } }; #endif simutrans-124.3/src/simutrans/descriptor/reader/000077500000000000000000000000001474050137200220075ustar00rootroot00000000000000simutrans-124.3/src/simutrans/descriptor/reader/bridge_reader.cc000066400000000000000000000124161474050137200251000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../builder/brueckenbauer.h" #include "../bridge_desc.h" #include "../intro_dates.h" #include "bridge_reader.h" #include "../obj_node_info.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void bridge_reader_t::register_obj(obj_desc_t *&data) { bridge_desc_t *desc = static_cast(data); bridge_builder_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } obj_desc_t *bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; // some defaults bridge_desc_t *desc = new bridge_desc_t(); desc->maintenance = 800; desc->pillars_every = 0; desc->pillars_asymmetric = false; desc->max_length = 0; desc->max_height = 0; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->number_of_seasons = 0; if(version == 1) { // Versioned node, version 1 desc->wtyp = (uint8)decode_uint16(p); desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); } else if (version == 2) { // Versioned node, version 2 desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); } else if (version == 3) { // Versioned node, version 3 // pillars added desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = 0; } else if (version == 4) { // Versioned node, version 3 // pillars added desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = decode_uint8(p); } else if (version == 5) { // Versioned node, version 5 // timeline desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else if (version == 6) { // Versioned node, version 6 // snow desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->number_of_seasons = decode_uint8(p); } else if (version==7 || version==8) { // Versioned node, version 7/8 // max_height, asymmetric pillars desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->pillars_asymmetric = (decode_uint8(p)!=0); desc->max_height = decode_uint8(p); desc->number_of_seasons = decode_uint8(p); } else if (version==9) { desc->topspeed = decode_uint16(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->pillars_every = decode_uint8(p); desc->max_length = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->pillars_asymmetric = (decode_uint8(p)!=0); desc->axle_load = decode_uint16(p); // new desc->max_height = decode_uint8(p); desc->number_of_seasons = decode_uint8(p); } else { if( version ) { dbg->fatal( "bridge_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 desc->wtyp = (uint8)v; decode_uint16(p); // Menupos, no more used desc->price = decode_uint32(p); desc->topspeed = 999; // Safe default ... } // pillars cannot be higher than this to avoid drawing errors if(desc->pillars_every>0 && desc->max_height==0) { desc->max_height = 7; } // indicate for different copyright/name lookup desc->offset = version<8 ? 0 : 2; if( version < 9 ) { desc->axle_load = 9999; } DBG_DEBUG("bridge_reader_t::read_node()", "version=%d, waytype=%d, price=%d, maintenance=%d, topspeed=%d, axle_load=%i, max_length=%i, max_height=%i, pillars=%i, asymmetric=%i, seasons=%i, intro=%i/%i, retire=%i/%i", version, desc->wtyp, desc->price, desc->maintenance, desc->topspeed, desc->axle_load, desc->max_length, desc->max_height, desc->pillars_every, desc->pillars_asymmetric, desc->number_of_seasons, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/bridge_reader.h000066400000000000000000000010371474050137200247370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_BRIDGE_READER_H #define DESCRIPTOR_READER_BRIDGE_READER_H #include "obj_reader.h" class bridge_reader_t : public obj_reader_t { OBJ_READER_DEF(bridge_reader_t, obj_bridge, "bridge"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/building_reader.cc000066400000000000000000000377001474050137200254440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../builder/hausbauer.h" #include "../../simdebug.h" #include "../building_desc.h" #include "../intro_dates.h" #include "../obj_node_info.h" #include "building_reader.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" /** * Old building types, for compatibility ... */ struct old_btyp { /** * From type "unknown" also come special buildings e.q. Townhall */ enum typ { wohnung, gewerbe, industrie, unknown }; }; obj_desc_t * tile_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the highest bit was always cleared. const uint16 v = decode_uint16(p); const int version = (v & 0x8000)!=0 ? v&0x7FFF : 0; building_tile_desc_t *desc = new building_tile_desc_t(); if(version == 2) { // DBG_DEBUG("tile_reader_t::read_node()","version=1"); // Versioned node, version 1 desc->phases = (uint8)decode_uint16(p); desc->index = decode_uint16(p); desc->seasons = decode_uint8(p); desc->building = NULL; } else if(version == 1) { // DBG_DEBUG("tile_reader_t::read_node()","version=1"); // Versioned node, version 1 desc->phases = (uint8)decode_uint16(p); desc->index = decode_uint16(p); desc->seasons = 1; desc->building = NULL; } else { if( version ) { dbg->fatal( "tile_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // skip the pointer ... p += 2; desc->phases = (uint8)decode_uint16(p); desc->index = decode_uint16(p); desc->seasons = 1; desc->building = NULL; } DBG_DEBUG("tile_reader_t::read_node()","phases=%i, index=%i, seasons=%i", desc->phases, desc->index, desc->seasons ); return desc; } void building_reader_t::register_obj(obj_desc_t *&data) { building_desc_t *desc = static_cast(data); if( desc->type == building_desc_t::factory ) { if( desc->enables == 0 ) { // this stuff is just for compatibility if( strcmp("Oelbohrinsel",desc->get_name())==0 ) { desc->enables = 1|2|4; } else if( strcmp("fish_swarm",desc->get_name())==0 ) { desc->enables = 4; } } } if( desc->type == building_desc_t::others && desc->enables == 0x80 ) { // this stuff is just for compatibility size_t checkpos = strlen(desc->get_name()); desc->enables = 0; // before station buildings were identified by their name ... if( strcmp("BusStop",desc->get_name()+checkpos-7)==0 ) { desc->type = building_desc_t::generic_stop; desc->extra_data = road_wt; desc->enables = 1; } if( strcmp("CarStop",desc->get_name()+checkpos-7)==0 ) { desc->type = building_desc_t::generic_stop; desc->extra_data = road_wt; desc->enables = 4; } else if( strcmp("TrainStop",desc->get_name()+checkpos-9)==0 ) { desc->type = building_desc_t::generic_stop; desc->extra_data = track_wt; desc->enables = 1|4; } else if( strcmp("ShipStop",desc->get_name()+checkpos-8)==0 ) { desc->type = building_desc_t::dock; desc->extra_data = water_wt; desc->enables = 1|4; } else if( strcmp("ChannelStop",desc->get_name()+checkpos-11)==0 ) { desc->type = building_desc_t::generic_stop; desc->extra_data = water_wt; desc->enables = 1|4; } else if( strcmp("PostOffice",desc->get_name()+checkpos-10)==0 ) { desc->type = building_desc_t::generic_extension; desc->extra_data = 0; desc->enables = 2; } else if( strcmp("StationBlg",desc->get_name()+checkpos-10)==0 ) { desc->type = building_desc_t::generic_extension; desc->extra_data = 0; desc->enables = 1|4; } } // now old style depots ... else if( desc->type==building_desc_t::others ) { size_t checkpos = strlen(desc->get_name()); if( strcmp("AirDepot",desc->get_name()+checkpos-8)==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)air_wt; } else if( strcmp("TrainDepot",desc->get_name())==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)track_wt; } else if( strcmp("TramDepot",desc->get_name())==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)tram_wt; } else if( strcmp("MonorailDepot",desc->get_name())==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)monorail_wt; } else if( strcmp("CarDepot",desc->get_name())==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)road_wt; } else if( strcmp("ShipDepot",desc->get_name())==0 ) { desc->type = building_desc_t::depot; desc->extra_data = (uint16)water_wt; } } // and finally old stations ... // correct all building types in building_desc_t::old_building_types_t else if( (uint8)desc->get_type()>=building_desc_t::bahnhof && (uint8)desc->get_type()<=building_desc_t::lagerhalle) { // compatibility stuff static uint16 old_to_new_waytype[16] = { track_wt, road_wt, road_wt, water_wt, water_wt, air_wt, monorail_wt, 0, track_wt, road_wt, road_wt, 0 , water_wt, air_wt, monorail_wt, 0 }; uint8 type = desc->type; desc->extra_data = type <= building_desc_t::monorail_geb ? old_to_new_waytype[type-building_desc_t::bahnhof] : 0; if( type !=building_desc_t::dock ) { desc->type = type < building_desc_t::bahnhof_geb ? building_desc_t::generic_stop : building_desc_t::generic_extension; } } // after this point all building_desc_t's have type in building_desc_t::btype // allowed layouts are 1,2,4,8,16, where 8,16 is reserved for stations uint8 l = desc->type == building_desc_t::generic_stop ? 16 : 4; while (l > 0) { if ((desc->layouts & l) != 0 && (desc->layouts != l)) { dbg->error( "building_reader_t::register_obj()", "Building %s has %i layouts (illegal) => set to %i", desc->get_name(), desc->layouts, l ); desc->layouts = l; break; } l >>= 1; } if( desc->allow_underground == 255 ) { // only old stops were allowed underground desc->allow_underground = desc->type==building_desc_t::generic_stop ? 2 : 0; } if (hausbauer_t::register_desc(desc)) { DBG_DEBUG("building_reader_t::register_obj", "Loaded '%s'", desc->get_name()); // do not calculate checksum of factory, will be done in factory_reader_t if( desc->type != building_desc_t::factory ) { checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } } } bool building_reader_t::successfully_loaded() const { return hausbauer_t::successfully_loaded(); } obj_desc_t * building_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char * p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the highest bit was always cleared. const uint16 v = decode_uint16(p); const int version = (v & 0x8000)!=0 ? v&0x7FFF : 0; old_btyp::typ btyp; building_desc_t *desc = new building_desc_t(); if(version == 10) { // preservation date added btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = (climate_bits)(decode_uint16(p) & ALL_CLIMATES); desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = decode_uint16(p); desc->capacity = decode_uint16(p); desc->maintenance = decode_sint32(p); desc->price = decode_sint32(p); desc->allow_underground = decode_uint8(p); desc->preservation_year_month = decode_uint16(p); } else if(version == 8 || version == 9) { // Versioned node, version 8 // station price, maintenance and capacity added btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = (climate_bits)(decode_uint16(p) & ALL_CLIMATES); desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = decode_uint16(p); desc->capacity = decode_uint16(p); desc->maintenance = decode_sint32(p); desc->price = decode_sint32(p); desc->allow_underground = decode_uint8(p); } else if(version == 7) { // Versioned node, version 7 // underground mode added btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = (climate_bits)(decode_uint16(p) & ALL_CLIMATES); desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = decode_uint16(p); desc->allow_underground = decode_uint8(p); } else if(version == 5 || version==6) { // Versioned node, version 5 or 6 (only level logic is different) // animation interval in ms added btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = (climate_bits)(decode_uint16(p) & ALL_CLIMATES); desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = decode_uint16(p); } else if(version == 4) { // Versioned node, version 4 // climates and seasons added btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = (climate_bits)(decode_uint16(p) & ALL_CLIMATES); desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = 300; } else if(version == 3) { // Versioned node, version 3 btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = all_but_water_climate; // all but water desc->enables = decode_uint8(p); desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = 300; } else if(version == 2) { // Versioned node, version 2 btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = all_but_water_climate; // all but water desc->enables = 0x80; desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->animation_time = 300; } else if(version == 1) { // Versioned node, version 1 btyp = (old_btyp::typ)decode_uint8(p); desc->type = (building_desc_t::btype)decode_uint8(p); desc->level = decode_uint16(p); desc->extra_data = decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint8(p); desc->allowed_climates = all_but_water_climate; // all but water desc->enables = 0x80; desc->flags = (building_desc_t::flag_t)decode_uint8(p); desc->distribution_weight = decode_uint8(p); desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->animation_time = 300; } else { if( version ) { dbg->fatal( "building_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 btyp = (old_btyp::typ)v; decode_uint16(p); desc->type = (building_desc_t::btype)decode_uint32(p); desc->level = decode_uint32(p); desc->extra_data= decode_uint32(p); desc->size.x = decode_uint16(p); desc->size.y = decode_uint16(p); desc->layouts = decode_uint32(p); desc->allowed_climates = all_but_water_climate; // all but water desc->enables = 0x80; desc->flags = (building_desc_t::flag_t)decode_uint32(p); desc->distribution_weight = 100; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->animation_time = 300; } // there are additional nodes for cursor/icon if( node.nchildren > 2+desc->size.x*desc->size.y*desc->layouts ) { desc->flags |= building_desc_t::FLAG_HAS_CURSOR; } // correct old station buildings ... if( version<=3 && ((uint8)desc->type >= building_desc_t::bahnhof || desc->type == building_desc_t::factory || desc->type == building_desc_t::depot) && desc->level==0 ) { DBG_DEBUG("building_reader_t::read_node()","old station building -> set level to 4"); desc->level = 4; } else if( version<=5 && (desc->type == building_desc_t::factory || desc->type == building_desc_t::depot) ) { desc->level ++; DBG_DEBUG("building_reader_t::read_node()","old station building -> increment level by one to %i", desc->level ); } if( version<=6 ) { // only stops were allowed underground desc->allow_underground = 255; } if( version<=7 ) { // capacity, maintenance and price were set from level desc->capacity = desc->level * 32; desc->maintenance = PRICE_MAGIC; desc->price = PRICE_MAGIC; } if (desc->level == 65535) { desc->level = 0; // apparently wrong level dbg->warning("building_reader_t::read_node()","level was 65535, intended was probably 0 => changed." ); } if ( version < 9 ) { switch(btyp) { case old_btyp::wohnung: desc->type = building_desc_t::city_res; break; case old_btyp::gewerbe: desc->type = building_desc_t::city_com; break; case old_btyp::industrie: desc->type = building_desc_t::city_ind; break; default: ; } } if( version < 10 ) { // can always replace desc->preservation_year_month = DEFAULT_RETIRE_DATE*12; } DBG_DEBUG("building_reader_t::read_node()", "version=%d," " btyp=%d," " type=%d," " price=%d," " maintenance=%d," " capacity=%d," " level=%d," " extra_data=%d," " size.x=%d," " size.y=%d," " layouts=%d," " enables=%x," " flags=%d," " chance=%d," " climates=%X," " metro=%d," " anim=%d," " intro=%d/%d," " retire=%d/%d,", version, btyp, desc->type, desc->price, desc->maintenance, desc->capacity, desc->level, desc->extra_data, desc->size.x, desc->size.y, desc->layouts, desc->enables, desc->flags, desc->distribution_weight, desc->allowed_climates, desc->allow_underground, desc->animation_time, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12 ); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/building_reader.h000066400000000000000000000015341474050137200253020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_BUILDING_READER_H #define DESCRIPTOR_READER_BUILDING_READER_H #include "obj_reader.h" class tile_reader_t : public obj_reader_t { OBJ_READER_DEF(tile_reader_t, obj_tile, "tile"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class building_reader_t : public obj_reader_t { OBJ_READER_DEF(building_reader_t, obj_building, "building"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/citycar_reader.cc000066400000000000000000000052631474050137200253040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simunits.h" #include "../../vehicle/vehicle.h" #include "../../vehicle/simroadtraffic.h" #include "../citycar_desc.h" #include "../intro_dates.h" #include "citycar_reader.h" #include "../obj_node_info.h" #include "../../simdebug.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void citycar_reader_t::register_obj(obj_desc_t *&data) { citycar_desc_t *desc = static_cast(data); private_car_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool citycar_reader_t::successfully_loaded() const { return private_car_t::successfully_loaded(); } obj_desc_t * citycar_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; citycar_desc_t *desc = new citycar_desc_t(); if(version == 2) { // Versioned node, version 1 desc->distribution_weight = decode_uint16(p); desc->topspeed = kmh_to_speed(decode_uint16(p)/16); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else if(version == 1) { // Versioned node, version 1 desc->distribution_weight = decode_uint16(p); desc->topspeed = kmh_to_speed(decode_uint16(p)/16); uint16 intro_date = decode_uint16(p); desc->intro_date = (intro_date/16)*12 + (intro_date%12); uint16 retire_date = decode_uint16(p); desc->retire_date= (retire_date/16)*12 + (retire_date%12); } else { if( version ) { dbg->fatal( "citycar_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old version 0 ... desc->distribution_weight = v; desc->topspeed = kmh_to_speed(80); desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; } // zero speed not allowed, we want something that moves! if( desc->topspeed<=16 ) { dbg->warning( "citycar_reader_t::read_node()", "citycar must have minimum speed => changed to 1.25 km/h!" ); desc->topspeed = 16; } DBG_DEBUG("citycar_reader_t::read_node()","version=%i, speed=%i, chance=%i, intro=%i/%i, retire=%i/%i", version, speed_to_kmh(desc->topspeed), desc->distribution_weight, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/citycar_reader.h000066400000000000000000000012021474050137200251330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_CITYCAR_READER_H #define DESCRIPTOR_READER_CITYCAR_READER_H #include "obj_reader.h" class citycar_reader_t : public obj_reader_t { OBJ_READER_DEF(citycar_reader_t, obj_citycar, "citycar"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/crossing_reader.cc000066400000000000000000000053421474050137200254730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/crossing_logic.h" #include "../sound_desc.h" #include "../crossing_desc.h" #include "crossing_reader.h" #include "../obj_node_info.h" #include "../../simdebug.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void crossing_reader_t::register_obj(obj_desc_t *&data) { crossing_desc_t *desc = static_cast(data); if(desc->topspeed1!=0) { crossing_logic_t::register_desc(desc); } checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } obj_desc_t * crossing_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; crossing_desc_t *desc = new crossing_desc_t(); if(version == 0) { dbg->error("crossing_reader_t::read_node()","Old version of crossings cannot be used!"); desc->waytype1 = (waytype_t)v; desc->waytype2 = (waytype_t)decode_uint16(p); desc->topspeed1 = 0; desc->topspeed2 = 0; } else if( version==1 || version==2 ) { desc->waytype1 = (waytype_t)decode_uint8(p); desc->waytype2 = (waytype_t)decode_uint8(p); desc->topspeed1 = decode_uint16(p); desc->topspeed2 = decode_uint16(p); desc->open_animation_time = decode_uint32(p); desc->closed_animation_time = decode_uint32(p); desc->sound = decode_sint8(p); if(desc->sound==LOAD_SOUND) { uint8 len=decode_sint8(p); char wavname[256]; wavname[len] = 0; for(uint8 i=0; isound = (sint8)sound_desc_t::get_sound_id(wavname); } else if(desc->sound>=0 && desc->sound<=MAX_OLD_SOUNDS) { sint16 old_id = desc->sound; desc->sound = (sint8)sound_desc_t::get_compatible_sound_id((sint8)old_id); } desc->intro_date = 0; desc->retire_date = 65535; if (version >= 2 ) { desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } } else { dbg->fatal( "crossing_reader_t::read_node()", "Cannot handle too new node version %i", version ); } DBG_DEBUG("crossing_reader_t::read_node()", "version=%i, waytype1=%d, waytype2=%d, topspeed1=%i, topspeed2=%i, open_time=%i, close_time=%i, sound=%i", version, desc->waytype1, desc->waytype2, desc->topspeed1, desc->topspeed2, desc->open_animation_time, desc->closed_animation_time, desc->sound); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/crossing_reader.h000066400000000000000000000010531474050137200253300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_CROSSING_READER_H #define DESCRIPTOR_READER_CROSSING_READER_H #include "obj_reader.h" class crossing_reader_t : public obj_reader_t { OBJ_READER_DEF(crossing_reader_t, obj_crossing, "crossing"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/factory_reader.cc000066400000000000000000000356771474050137200253310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simfab.h" #include "../../builder/fabrikbauer.h" #include "../../simdebug.h" #include "../obj_node_info.h" #include "../sound_desc.h" #include "../factory_desc.h" #include "../xref_desc.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" #include "factory_reader.h" // determine the combined probability of 256 rounds of chances uint16 rescale_probability(const uint16 p) { if( p ) { // probability is p / 10000 if (p >= 10000) { // too large, will lead to overflow here return 10000; } sint64 pp = ( (sint64)p << 30 ) / 10000LL; sint64 qq = ( 1LL << 30 ) - pp; uint16 ss = 256u; while( (ss >>= 1) ) { pp += (pp * qq) >> 30; qq = (qq * qq) >> 30; } return (uint16)(((pp * 10000LL) + (1LL << 29)) >> 30); } return p; } obj_desc_t *factory_field_class_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); uint16 v = decode_uint16(p); field_class_desc_t *desc = new field_class_desc_t(); if( v==0x8001 ) { // field class specific data desc->snow_image = decode_uint8(p); desc->production_per_field = decode_uint16(p); desc->storage_capacity = decode_uint16(p); desc->spawn_weight = decode_uint16(p); DBG_DEBUG("factory_field_class_reader_t::read_node()", "version=%i, has_snow=%i, production=%i, capacity=%i, spawn_weight=%i", v, desc->snow_image, desc->production_per_field, desc->storage_capacity, desc->spawn_weight); } else { dbg->fatal("factory_field_class_reader_t::read_node()","Cannot handle too new node version %i", v&0x00ff ); } return desc; } obj_desc_t *factory_field_group_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); uint16 v = decode_uint16(p); field_group_desc_t *desc = new field_group_desc_t(); if( v==0x8003 ) { desc->probability = rescale_probability( decode_uint16(p) ); desc->max_fields = decode_uint16(p); desc->min_fields = decode_uint16(p); desc->start_fields = decode_uint16(p); desc->field_classes = decode_uint16(p); } else if( v==0x8002 ) { // this version only store shared, common data desc->probability = rescale_probability( decode_uint16(p) ); desc->max_fields = decode_uint16(p); desc->min_fields = decode_uint16(p); desc->field_classes = decode_uint16(p); } else if( v==0x8001 ) { /* * leave shared, common data in field desc * field class specific data goes to field class desc */ field_class_desc_t *const field_class_desc = new field_class_desc_t(); field_class_desc->snow_image = decode_uint8(p); desc->probability = rescale_probability( decode_uint16(p) ); field_class_desc->production_per_field = decode_uint16(p); desc->max_fields = decode_uint16(p); desc->min_fields = decode_uint16(p); desc->field_classes = 1; field_class_desc->storage_capacity = 0; field_class_desc->spawn_weight = 1000; /* * store it in a static variable for further processing * later in factory_field_reader_t::register_obj() */ incomplete_field_class_desc = field_class_desc; DBG_DEBUG("factory_field_group_reader_t::read_node()", "version=%i, probability=%i, fields: max=%i / min=%i / start=%i, field classes=%i, storage=%i, field_prod=%i, chance=%i, has_snow=%i", v, desc->probability, desc->max_fields, desc->min_fields, desc->start_fields, desc->field_classes, field_class_desc->storage_capacity, field_class_desc->production_per_field, field_class_desc->spawn_weight, field_class_desc->snow_image); } else { dbg->fatal("factory_field_group_reader_t::read_node()","Cannot handle too new node version %i", v ); } if ( v>0x8001 ) { DBG_DEBUG("factory_field_group_reader_t::read_node()", "version=%i, probability=%i, fields: max=%i / min=%i / start=%i, field classes=%i", v, desc->probability, desc->max_fields, desc->min_fields, desc->start_fields, desc->field_classes); } return desc; } void factory_field_group_reader_t::register_obj(obj_desc_t *&data) { field_group_desc_t *const desc = static_cast(data); // check if we need to continue with the construction of field class desc if (field_class_desc_t *const field_class_desc = incomplete_field_class_desc) { // we *must* transfer the obj_desc_t array and not just the desc object itself // as xref reader has already logged the address of the array element for xref resolution field_class_desc->children = desc->children; desc->children = new obj_desc_t*[1]; desc->children[0] = field_class_desc; incomplete_field_class_desc = NULL; } } obj_desc_t *factory_smoke_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); sint16 x = decode_sint16(p); sint16 y = decode_sint16(p); smoke_desc_t *desc = new smoke_desc_t(); desc->pos_off = koord( x, y ); x = decode_sint16(p); y = decode_sint16(p); desc->xy_off = koord( x, y ); /*smoke speed*/ decode_sint16(p); DBG_DEBUG("factory_smoke_reader_t::read_node()","(size %i)",node.size); return desc; } obj_desc_t *factory_supplier_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; factory_supplier_desc_t *desc = new factory_supplier_desc_t(); if(version == 1) { // Versioned node, version 1 // not there yet ... } else { // old node, version 0 desc->capacity = v; desc->supplier_count = decode_uint16(p); desc->consumption = decode_uint16(p); } DBG_DEBUG("factory_product_reader_t::read_node()", "version=%d, capacity=%d, count=%d, consumption=%d", 0, desc->capacity, desc->supplier_count, desc->consumption); return desc; } obj_desc_t *factory_product_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; factory_product_desc_t *desc = new factory_product_desc_t(); if(version == 1) { // Versioned node, version 1 desc->capacity = decode_uint16(p); desc->factor = decode_uint16(p); } else { if( version ) { dbg->fatal( "factory_product_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 decode_uint16(p); desc->capacity = v; desc->factor = 256; } DBG_DEBUG("factory_product_reader_t::read_node()", "version=%d, capacity=%d, factor=%x", version, desc->capacity, desc->factor); return desc; } obj_desc_t *factory_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; factory_desc_t *desc = new factory_desc_t(); desc->sound_id = NO_SOUND; desc->sound_interval = 0xFFFFFFFFul; desc->smokerotations = 0; typedef factory_desc_t::site_t site_t; if(version == 5) { // Versioned node, version 5 with smoke offsets desc->placement = (site_t)decode_uint16(p); desc->productivity = decode_uint16(p); desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = decode_uint8(p); desc->fields = decode_uint8(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = decode_uint16(p); desc->expand_probability = rescale_probability( decode_uint16(p) ); desc->expand_minimum = decode_uint16(p); desc->expand_range = decode_uint16(p); desc->expand_times = decode_uint16(p); desc->electric_boost = decode_uint16(p); desc->pax_boost = decode_uint16(p); desc->mail_boost = decode_uint16(p); desc->electric_demand = decode_uint16(p); desc->pax_demand = decode_uint16(p); desc->mail_demand = decode_uint16(p); desc->sound_interval = decode_uint32(p); desc->sound_id = decode_sint8(p); desc->smokerotations = decode_sint8(p); for( int i = 0; i < 4; i++ ) { desc->smoketile[i].x = decode_sint16(p); desc->smoketile[i].y = decode_sint16(p); desc->smokeoffset[i].x = decode_sint16(p); desc->smokeoffset[i].y = decode_sint16(p); } desc->smokeuplift = decode_uint16(p); desc->smokelifetime = decode_uint16(p); } else if(version == 4) { // Versioned node, version 4 with sound and animation desc->placement = (site_t)decode_uint16(p); desc->productivity = decode_uint16(p); desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = decode_uint8(p); desc->fields = decode_uint8(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = decode_uint16(p); desc->expand_probability = rescale_probability( decode_uint16(p) ); desc->expand_minimum = decode_uint16(p); desc->expand_range = decode_uint16(p); desc->expand_times = decode_uint16(p); desc->electric_boost = decode_uint16(p); desc->pax_boost = decode_uint16(p); desc->mail_boost = decode_uint16(p); desc->electric_demand = decode_uint16(p); desc->pax_demand = decode_uint16(p); desc->mail_demand = decode_uint16(p); desc->sound_interval = decode_uint32(p); desc->sound_id = decode_sint8(p); } else if(version == 3) { // Versioned node, version 3 desc->placement = (site_t)decode_uint16(p); desc->productivity = decode_uint16(p); desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = decode_uint8(p); desc->fields = decode_uint8(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = decode_uint16(p); desc->expand_probability = rescale_probability( decode_uint16(p) ); desc->expand_minimum = decode_uint16(p); desc->expand_range = decode_uint16(p); desc->expand_times = decode_uint16(p); desc->electric_boost = decode_uint16(p); desc->pax_boost = decode_uint16(p); desc->mail_boost = decode_uint16(p); desc->electric_demand = decode_uint16(p); desc->pax_demand = decode_uint16(p); desc->mail_demand = decode_uint16(p); } else if(version == 2) { // Versioned node, version 2 desc->placement = (site_t)decode_uint16(p); desc->productivity = decode_uint16(p); desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = decode_uint8(p); desc->fields = decode_uint8(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = decode_uint16(p); desc->expand_probability = 0; desc->expand_minimum = 0; desc->expand_range = 0; desc->expand_times = 0; desc->electric_boost = 256; desc->pax_boost = 0; desc->mail_boost = 0; desc->electric_demand = 65535; desc->pax_demand = 65535; desc->mail_demand = 65535; } else if(version == 1) { // Versioned node, version 1 desc->placement = (site_t)decode_uint16(p); desc->productivity = decode_uint16(p); desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = (uint8)decode_uint16(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = decode_uint16(p); desc->fields = 0; desc->expand_probability = 0; desc->expand_minimum = 0; desc->expand_range = 0; desc->expand_times = 0; desc->electric_boost = 256; desc->pax_boost = 0; desc->mail_boost = 0; desc->electric_demand = 65535; desc->pax_demand = 65535; desc->mail_demand = 65535; } else { if( version ) { dbg->fatal( "factory_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0, without pax_level desc->placement = (site_t)v; decode_uint16(p); // alsways zero desc->productivity = decode_uint16(p)|0x8000; desc->range = decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->color = (uint8)decode_uint16(p); desc->supplier_count = decode_uint16(p); desc->product_count = decode_uint16(p); desc->pax_level = 12; desc->fields = 0; desc->expand_probability = 0; desc->expand_minimum = 0; desc->expand_range = 0; desc->expand_times = 0; desc->electric_boost = 256; desc->pax_boost = 0; desc->mail_boost = 0; desc->electric_demand = 65535; desc->pax_demand = 65535; desc->mail_demand = 65535; } DBG_DEBUG("factory_reader_t::read_node()", "version=%i, place=%i, productivity=%i, suppliers=%i, products=%i, fields=%i, range=%i, level=%i" "Demands: pax=%i / mail=%i / electric=%i," "Boosts: pax=%i / mail=%i / electric=%i," "Expand: prob=%i / min=%i / range=%i / times=%i" "chance=%i, sound: id=%i / interval=%i, color=%i", version, desc->placement, desc->productivity, desc->supplier_count, desc->product_count, desc->fields, desc->range, desc->pax_level, desc->pax_demand, desc->mail_demand, desc->electric_demand, desc->pax_boost, desc->mail_boost, desc->electric_boost, desc->expand_probability, desc->expand_minimum, desc->expand_range, desc->expand_times, desc->distribution_weight, desc->sound_id, desc->sound_interval, desc->color); if(desc->sound_id==LOAD_SOUND) { uint8 len=decode_sint8(p); char wavname[256]; wavname[len] = 0; for(uint8 i=0; isound_id = (sint8)sound_desc_t::get_sound_id(wavname); DBG_MESSAGE("vehicle_reader_t::register_obj()","sound %s to %i",wavname,desc->sound_id); } else if(desc->sound_id>=0 && desc->sound_id<=MAX_OLD_SOUNDS) { sint16 old_id = desc->sound_id; desc->sound_id = (sint8)sound_desc_t::get_compatible_sound_id((sint8)old_id); DBG_MESSAGE("vehicle_reader_t::register_obj()","old sound %i to %i",old_id,desc->sound_id); } return desc; } void factory_reader_t::register_obj(obj_desc_t *&data) { factory_desc_t* desc = static_cast(data); size_t fab_name_len = strlen( desc->get_name() ); desc->electricity_producer = (fab_name_len>=10 && strcmp(desc->get_name()+fab_name_len-9, "kraftwerk")==0) || (fab_name_len>=12 && strcmp(desc->get_name()+fab_name_len-11, "Power Plant")==0); desc->correct_smoke(); factory_builder_t::register_desc(desc); } bool factory_reader_t::successfully_loaded() const { return factory_builder_t::successfully_loaded(); } simutrans-124.3/src/simutrans/descriptor/reader/factory_reader.h000066400000000000000000000043321474050137200251530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_FACTORY_READER_H #define DESCRIPTOR_READER_FACTORY_READER_H #include "obj_reader.h" class field_class_desc_t; // new reader for field class desc class factory_field_class_reader_t : public obj_reader_t { friend class factory_field_group_reader_t; // this is a special case due to desc restructuring OBJ_READER_DEF(factory_field_class_reader_t, obj_ffldclass, "factory field class"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class factory_field_group_reader_t : public obj_reader_t { OBJ_READER_DEF(factory_field_group_reader_t, obj_ffield, "factory field"); // hold a field class desc under construction static field_class_desc_t* incomplete_field_class_desc; protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class factory_smoke_reader_t : public obj_reader_t { OBJ_READER_DEF(factory_smoke_reader_t, obj_fsmoke, "factory smoke"); public: /// @copydoc obj_reader_t::read_node obj_desc_t* read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class factory_supplier_reader_t : public obj_reader_t { OBJ_READER_DEF(factory_supplier_reader_t, obj_fsupplier, "factory supplier"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class factory_product_reader_t : public obj_reader_t { OBJ_READER_DEF(factory_product_reader_t, obj_fproduct, "factory product"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; class factory_reader_t : public obj_reader_t { OBJ_READER_DEF(factory_reader_t, obj_factory, "factory"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/good_reader.cc000066400000000000000000000050041474050137200245670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../builder/goods_manager.h" #include "good_reader.h" #include "../obj_node_info.h" #include "../goods_desc.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void goods_reader_t::register_obj(obj_desc_t *&data) { goods_desc_t *desc = static_cast(data); goods_manager_t::register_desc(desc); DBG_DEBUG("goods_reader_t::register_obj()","loaded good '%s'", desc->get_name()); pakset_manager_t::obj_for_xref(get_type(), desc->get_name(), data); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool goods_reader_t::successfully_loaded() const { return goods_manager_t::successfully_loaded(); } obj_desc_t * goods_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; // some defaults goods_desc_t *desc = new goods_desc_t(); desc->speed_bonus = 0; desc->weight_per_unit = 100; desc->color = 255; if(version == 1) { // Versioned node, version 1 desc->base_value = decode_uint16(p); desc->catg = (uint8)decode_uint16(p); desc->speed_bonus = decode_uint16(p); desc->weight_per_unit = 100; } else if(version == 2) { // Versioned node, version 2 desc->base_value = decode_uint16(p); desc->catg = (uint8)decode_uint16(p); desc->speed_bonus = decode_uint16(p); desc->weight_per_unit = decode_uint16(p); } else if(version == 3) { // Versioned node, version 3 desc->base_value = decode_uint16(p); desc->catg = decode_uint8(p); desc->speed_bonus = decode_uint16(p); desc->weight_per_unit = decode_uint16(p); desc->color = decode_uint8(p); } else { if( version ) { dbg->fatal( "goods_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 desc->base_value = v; desc->catg = (uint8)decode_uint16(p); } DBG_DEBUG("goods_reader_t::read_node()","version=%d, value=%d, catg=%d, bonus=%d, weight=%i, color=%i", version, desc->base_value, desc->catg, desc->speed_bonus, desc->weight_per_unit, desc->color); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/good_reader.h000066400000000000000000000011621474050137200244320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_GOOD_READER_H #define DESCRIPTOR_READER_GOOD_READER_H #include "obj_reader.h" class goods_reader_t : public obj_reader_t { OBJ_READER_DEF(goods_reader_t, obj_good, "good"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/ground_reader.cc000066400000000000000000000010661474050137200251410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../ground_desc.h" #include "ground_reader.h" void ground_reader_t::register_obj(obj_desc_t *&data) { ground_desc_t *desc = static_cast(data); ground_desc_t::register_desc(desc); } bool ground_reader_t::successfully_loaded() const { return ground_desc_t::successfully_loaded(); } obj_desc_t* ground_reader_t::read_node(FILE*, obj_node_info_t& info) { return obj_reader_t::read_node(info); } simutrans-124.3/src/simutrans/descriptor/reader/ground_reader.h000066400000000000000000000011741474050137200250030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_GROUND_READER_H #define DESCRIPTOR_READER_GROUND_READER_H #include "obj_reader.h" class ground_reader_t : public obj_reader_t { OBJ_READER_DEF(ground_reader_t, obj_ground, "ground"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/groundobj_reader.cc000066400000000000000000000043201474050137200256300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simunits.h" #include "../../obj/simobj.h" #include "../../simdebug.h" #include "../../obj/groundobj.h" #include "../../vehicle/movingobj.h" #include "../groundobj_desc.h" #include "../obj_node_info.h" #include "groundobj_reader.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void groundobj_reader_t::register_obj(obj_desc_t *&data) { groundobj_desc_t *desc = static_cast(data); if(desc->speed==0) { groundobj_t::register_desc(desc); } else { movingobj_t::register_desc(desc); } checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool groundobj_reader_t::successfully_loaded() const { bool gok = groundobj_t::successfully_loaded(); return movingobj_t::successfully_loaded() && gok; } obj_desc_t * groundobj_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the highest bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; groundobj_desc_t *desc = new groundobj_desc_t(); if(version == 1) { desc->allowed_climates = (climate_bits)decode_uint16(p); desc->distribution_weight = decode_uint16(p); desc->number_of_seasons = decode_uint8(p); desc->trees_on_top = (bool)decode_uint8(p); desc->speed = kmh_to_speed( decode_uint16(p) ); desc->wtyp = (waytype_t)decode_uint16(p); desc->price = decode_sint32(p); } else { // version 0, never existed dbg->fatal( "groundobj_reader_t::read_node()", "Cannot handle too new node version %i", version ); } DBG_DEBUG("groundobj_reader_t::read_node()", "version=%i, climates=$%X, seasons=%i, chance=%i, speed=%i, ways=%i, cost=%d, trees_on_top=%i", version, desc->allowed_climates, desc->number_of_seasons, desc->distribution_weight, speed_to_kmh(desc->speed), desc->wtyp, desc->price, desc->trees_on_top); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/groundobj_reader.h000066400000000000000000000012111474050137200254660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_GROUNDOBJ_READER_H #define DESCRIPTOR_READER_GROUNDOBJ_READER_H #include "obj_reader.h" class groundobj_reader_t : public obj_reader_t { OBJ_READER_DEF(groundobj_reader_t, obj_groundobj, "groundobj"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t*&) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/image_reader.cc000066400000000000000000000134551474050137200247320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../display/simgraph.h" #include "../../simdebug.h" #include "../../display/simimg.h" #include "../image.h" #include "image_reader.h" #include "../obj_node_info.h" #include #include "../../tpl/inthashtable_tpl.h" #include "../../tpl/array_tpl.h" // if without graphics backend, do not copy any pixel #if COLOUR_DEPTH != 0 #define skip_reading_pixels_if_no_graphics #else #define skip_reading_pixels_if_no_graphics goto adjust_image #endif obj_desc_t *image_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin()+6; // always zero in old version, since length was always less than 65535 // because a node could not hold more data uint8 version = decode_uint8(p); p = desc_buf.begin(); #if COLOUR_DEPTH != 0 image_t *desc = new image_t(); #else // reserve space for one single pixel and initialize data image_t *desc = image_t::create_single_pixel(); #endif if(version==0) { desc->x = decode_uint8(p); desc->w = decode_uint8(p); desc->y = decode_uint8(p); desc->h = decode_uint8(p); desc->alloc(decode_uint32(p)); // len desc->imageid = IMG_EMPTY; p += 2; // dummys desc->zoomable = decode_uint8(p); skip_reading_pixels_if_no_graphics; //DBG_DEBUG("image_t::read_node()","x,y=%d,%d w,h=%d,%d, len=%i",desc->x,desc->y,desc->w,desc->h, desc->len); uint16* dest = desc->data; p = desc_buf.begin()+12; if (desc->h > 0) { for (uint i = 0; i < desc->len; i++) { uint16 data = decode_uint16(p); if(data>=0x8000u && data<=0x800Fu) { // player color offset changed data ++; } *dest++ = data; } } } else if(version<=2) { desc->x = decode_sint16(p); desc->y = decode_sint16(p); desc->w = decode_uint8(p); desc->h = decode_uint8(p); p++; // skip version information desc->alloc(decode_uint16(p)); // len desc->zoomable = decode_uint8(p); desc->imageid = IMG_EMPTY; skip_reading_pixels_if_no_graphics; uint16* dest = desc->data; if (desc->h > 0) { for (uint i = 0; i < desc->len; i++) { *dest++ = decode_uint16(p); } } } else if(version==3) { desc->x = decode_sint16(p); desc->y = decode_sint16(p); desc->w = decode_sint16(p); p++; // skip version information desc->h = decode_sint16(p); desc->alloc((node.size-10)/2); // len desc->zoomable = decode_uint8(p); desc->imageid = IMG_EMPTY; skip_reading_pixels_if_no_graphics; uint16* dest = desc->data; if (desc->h > 0) { for (uint i = 0; i < desc->len; i++) { *dest++ = decode_uint16(p); } } } else { dbg->fatal( "image_reader_t::read_node()", "Cannot handle too new node version %i", version ); } #if COLOUR_DEPTH == 0 adjust_image: // reset image parameters, but only for non-empty images if( desc->h > 0 ) { desc->h = 1; } if( desc->w > 0 ) { desc->w = 1; } if( desc->len > 0 ) { desc->len = 4; memset(desc->data, 0, desc->len*sizeof(PIXVAL)); } desc->x = 0; desc->y = 0; #else if (!image_has_valid_data(desc)) { delete desc; return NULL; } #endif // check for left corner if(version<2 && desc->h>0) { // find left border uint16 left = 255; uint16 *dest = desc->data; uint16 *end = desc->data + desc->len; for( uint8 y=0; yh; y++ ) { if (dest >= end) { delete desc; return NULL; } left = min(left, *dest); // skip rest of the line do { dest++; if (dest >= end) { delete desc; return NULL; } dest += *dest + 1; if (dest >= end) { delete desc; return NULL; } } while (*dest != 0); dest++; // skip trailing zero } if(leftx) { dbg->warning( "image_reader_t::read_node()","left(%i)x ); } /// No need to check for valid dest pointer here, the code has the same structure as above dest = desc->data; for( uint8 y=0; yh; y++ ) { *dest -= left; // skip rest of the line do { dest++; dest += *dest + 1; } while (*dest != 0); dest++; // skip trailing zero } } if (desc->len != 0) { // get the adler hash (since we have zlib on board anyway ... ) bool do_register_image = true; uint32 adler = adler32(0L, NULL, 0 ); // remember len is sizeof(uint16)! adler = adler32(adler, (const Bytef *)(desc->data), desc->len*2 ); static inthashtable_tpl images_adlers; image_t *same = images_adlers.get(adler); if (same) { // same checksum => if same then skip! image_t const& a = *desc; image_t const& b = *same; do_register_image = a.x != b.x || a.y != b.y || a.w != b.w || a.h != b.h || a.zoomable != b.zoomable || a.len != b.len || memcmp(a.data, b.data, sizeof(*a.data) * a.len) != 0; } // unique image here if( do_register_image ) { if(!same) { images_adlers.put(adler,desc); // still with imageid == IMG_EMPTY! } // register image adds this image to the internal array maintained by simgraph??.cc register_image(desc); } else { // no need to load doubles ... delete desc; desc = same; } } return desc; } #define TRANSPARENT_RUN (0x8000u) bool image_reader_t::image_has_valid_data(image_t *image_in) const { PIXVAL *src = image_in->data; PIXVAL *end = image_in->data + image_in->len; for( int y = 0; y < image_in->h; ++y ) { // decode line uint16 runlen = *src++; do { if (src >= end) { return false; } runlen = *src++ & ~TRANSPARENT_RUN; src += runlen; if (src >= end) { return false; } runlen = *src++; } while( runlen!=0 ); // end of row: runlen == 0 } return src == end; } simutrans-124.3/src/simutrans/descriptor/reader/image_reader.h000066400000000000000000000007771474050137200245770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_IMAGE_READER_H #define DESCRIPTOR_READER_IMAGE_READER_H #include "obj_reader.h" class image_t; class image_reader_t : public obj_reader_t { OBJ_READER_DEF(image_reader_t, obj_image, "image"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; private: bool image_has_valid_data(image_t *img) const; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/imagelist2d_reader.cc000066400000000000000000000013001474050137200260360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../image_array.h" #include "imagelist2d_reader.h" #include "../obj_node_info.h" #include "../../tpl/array_tpl.h" obj_desc_t * imagelist2d_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); image_array_t *desc = new image_array_t(); desc->count = decode_uint16(p); // DBG_DEBUG("imagelist2d_reader_t::read_node()", "count=%d data read (node.size=%i)",desc->count, node.size); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/imagelist2d_reader.h000066400000000000000000000007261474050137200257130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_IMAGELIST2D_READER_H #define DESCRIPTOR_READER_IMAGELIST2D_READER_H #include "obj_reader.h" class imagelist2d_reader_t : public obj_reader_t { OBJ_READER_DEF(imagelist2d_reader_t, obj_imagelist2d, "imagelist2d"); public: /// @copydoc obj_reader::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/imagelist_reader.cc000066400000000000000000000011111474050137200256100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../image_list.h" #include "imagelist_reader.h" #include "../obj_node_info.h" #include "../../tpl/array_tpl.h" obj_desc_t * imagelist_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); image_list_t *desc = new image_list_t(); desc->count = decode_uint16(p); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/imagelist_reader.h000066400000000000000000000007141474050137200254620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_IMAGELIST_READER_H #define DESCRIPTOR_READER_IMAGELIST_READER_H #include "obj_reader.h" class imagelist_reader_t : public obj_reader_t { OBJ_READER_DEF(imagelist_reader_t, obj_imagelist, "imagelist"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/obj_reader.cc000066400000000000000000000001771474050137200244170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "obj_reader.h" simutrans-124.3/src/simutrans/descriptor/reader/obj_reader.h000066400000000000000000000053451474050137200242630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_OBJ_READER_H #define DESCRIPTOR_READER_OBJ_READER_H #include #include "../obj_node_info.h" #include "../objversion.h" #include "../../simdebug.h" #include "../../simtypes.h" #include "../../dataobj/pakset_manager.h" class obj_desc_t; template class inthashtable_tpl; template class stringhashtable_tpl; template class ptrhashtable_tpl; template class slist_tpl; /** * Reads uint8 from memory area. Advances pointer by 1 byte. */ inline uint8 decode_uint8(char * &data) { const sint8 v = *((sint8 *)data); data ++; return v; } #define decode_sint8(data) (sint8)decode_uint8(data) /** * Reads uint16 from memory area. Advances pointer by 2 bytes. */ inline uint16 decode_uint16(char * &data) { uint16 const v = (uint16)(uint8)data[0] | (uint16)(uint8)data[1] << 8; data += sizeof(v); return v; } #define decode_sint16(data) (sint16)decode_uint16(data) /** * Reads uint32 from memory area. Advances pointer by 4 bytes. */ inline uint32 decode_uint32(char * &data) { uint32 const v = (uint32)(uint8)data[0] | (uint32)(uint8)data[1] << 8 | (uint32)(uint8)data[2] << 16 | (uint32)(uint8)data[3] << 24; data += sizeof(v); return v; } #define decode_sint32(data) (sint32)decode_uint32(data) #define OBJ_READER_DEF(classname, ty, ty_name) \ public: \ classname() { pakset_manager_t::register_reader(this); } \ obj_type get_type() const OVERRIDE { return ty; } \ const char *get_type_name() const OVERRIDE { return ty_name; } \ static classname *instance() { return &the_instance; } \ private: \ static classname the_instance class obj_reader_t { public: obj_reader_t() { /* Beware: Cannot register_reader() here! */ } virtual ~obj_reader_t() {} public: /// Read a descriptor from @p fp. Does version check and compatibility transformations. /// @returns The descriptor on success, or NULL on failure virtual obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) = 0; /// Register descriptor so the object described by the descriptor can be built in-game. virtual void register_obj(obj_desc_t *&/*desc*/) {} /// Does post-loading checks. /// @returns true if everything ok virtual bool successfully_loaded() const { return true; } template static T* read_node(obj_node_info_t const& node) { if (node.size != 0) { dbg->fatal("obj_reader_t::read_node()", "node of type %.4s must have size 0, but has size %u", reinterpret_cast(&node.type), node.size); } return new T(); } public: virtual obj_type get_type() const = 0; virtual const char *get_type_name() const = 0; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/pedestrian_reader.cc000066400000000000000000000042651474050137200260050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../vehicle/pedestrian.h" #include "../pedestrian_desc.h" #include "../obj_node_info.h" #include "../intro_dates.h" #include "pedestrian_reader.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void pedestrian_reader_t::register_obj(obj_desc_t *&data) { pedestrian_desc_t *desc = static_cast(data); pedestrian_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool pedestrian_reader_t::successfully_loaded() const { return pedestrian_t::successfully_loaded(); } /** * Read a pedestrian info node. Does version check and * compatibility transformations. */ obj_desc_t * pedestrian_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; pedestrian_desc_t *desc = new pedestrian_desc_t(); desc->steps_per_frame = 0; desc->offset = 20; // always there and never retire desc->intro_date = 1; desc->retire_date = 0xFFFEu; if (version == 1) { desc->distribution_weight = decode_uint16(p); desc->steps_per_frame = decode_uint16(p); desc->offset = decode_uint16(p); } else if(version == 2) { desc->distribution_weight = decode_uint16(p); desc->steps_per_frame = decode_uint16(p); desc->offset = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else { if( version ) { dbg->fatal( "pedestrian_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old, nonversion node desc->distribution_weight = v; } DBG_DEBUG("pedestrian_reader_t::read_node()", "version=%i, chance=%i", version, desc->distribution_weight); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/pedestrian_reader.h000066400000000000000000000012241474050137200256370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_PEDESTRIAN_READER_H #define DESCRIPTOR_READER_PEDESTRIAN_READER_H #include "obj_reader.h" class pedestrian_reader_t : public obj_reader_t { OBJ_READER_DEF(pedestrian_reader_t, obj_pedestrian, "pedestrian"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/roadsign_reader.cc000066400000000000000000000065621474050137200254570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../obj/roadsign.h" #include "../../simunits.h" // for kmh to speed conversion #include "../roadsign_desc.h" #include "../intro_dates.h" #include "roadsign_reader.h" #include "../obj_node_info.h" #include "../../simdebug.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void roadsign_reader_t::register_obj(obj_desc_t *&data) { roadsign_desc_t *desc = static_cast(data); roadsign_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool roadsign_reader_t::successfully_loaded() const { return roadsign_t::successfully_loaded(); } obj_desc_t * roadsign_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; roadsign_desc_t *desc = new roadsign_desc_t(); if(version==5) { // Versioned node, version 5 desc->min_speed = kmh_to_speed(decode_uint16(p)); desc->price = decode_uint32(p); desc->flags = decode_uint16(p); desc->offset_left = decode_sint8(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else if(version==4) { // Versioned node, version 4 desc->min_speed = kmh_to_speed(decode_uint16(p)); desc->price = decode_uint32(p); desc->flags = decode_uint8(p); desc->offset_left = decode_sint8(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else if(version==3) { // Versioned node, version 3 desc->min_speed = kmh_to_speed(decode_uint16(p)); desc->price = decode_uint32(p); desc->flags = decode_uint8(p); desc->offset_left = 14; desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); } else if(version==2) { // Versioned node, version 2 desc->min_speed = kmh_to_speed(decode_uint16(p)); desc->price = decode_uint32(p); desc->flags = decode_uint8(p); desc->offset_left = 14; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->wtyp = road_wt; } else if(version==1) { // Versioned node, version 1 desc->min_speed = kmh_to_speed(decode_uint16(p)); desc->price = 50000; desc->flags = decode_uint8(p); desc->offset_left = 14; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->wtyp = road_wt; } else { dbg->fatal( "roadsign_reader_t::read_node()", "Cannot handle too new node version %i", version ); } if( version<=3 && ( desc->is_choose_sign() || desc->is_private_way() ) && desc->get_waytype() == road_wt ) { // do not shift these signs to the left for compatibility desc->offset_left = 0; } DBG_DEBUG("roadsign_reader_t::read_node()", "version=%i, min_speed=%i, price=%i, flags=%x, wtyp=%i, offset_left=%i, intro=%i/%i, retire=%i/%i", version, desc->min_speed, desc->price/100, desc->flags, desc->wtyp, desc->offset_left, desc->intro_date%12+1, desc->intro_date/12, desc->retire_date%12+1, desc->retire_date/12); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/roadsign_reader.h000066400000000000000000000012031474050137200253040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_ROADSIGN_READER_H #define DESCRIPTOR_READER_ROADSIGN_READER_H #include "obj_reader.h" class roadsign_reader_t : public obj_reader_t { OBJ_READER_DEF(roadsign_reader_t, obj_roadsign, "roadsign"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t*&) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/root_reader.cc000066400000000000000000000005531474050137200246260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../obj_desc.h" #include "root_reader.h" void root_reader_t::register_obj(obj_desc_t *&data) { delete data; data = NULL; } obj_desc_t* root_reader_t::read_node(FILE*, obj_node_info_t& info) { return obj_reader_t::read_node(info); } simutrans-124.3/src/simutrans/descriptor/reader/root_reader.h000066400000000000000000000010231474050137200244610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_ROOT_READER_H #define DESCRIPTOR_READER_ROOT_READER_H #include "obj_reader.h" class root_reader_t : public obj_reader_t { OBJ_READER_DEF(root_reader_t, obj_root, "root"); public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/sim_reader.cc000066400000000000000000000055241474050137200244360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simskin.h" #include "text_reader.h" #include "image_reader.h" #include "imagelist_reader.h" #include "imagelist2d_reader.h" #include "bridge_reader.h" #include "tunnel_reader.h" #include "building_reader.h" #include "roadsign_reader.h" #include "citycar_reader.h" #include "pedestrian_reader.h" #include "crossing_reader.h" #include "factory_reader.h" #include "good_reader.h" #include "ground_reader.h" #include "groundobj_reader.h" #include "way_reader.h" #include "way_obj_reader.h" #include "root_reader.h" #include "xref_reader.h" #include "sound_reader.h" #include "skin_reader.h" #include "tree_reader.h" #include "vehicle_reader.h" /** * static data * * These classes are self-registering. The linker will not notify if there is a missing class, since it * may be also instantiated in the class itself. Therefore, all classes MUST be declared here to force * the linking and raise an error if we lack any of them. */ text_reader_t text_reader_t::the_instance; image_reader_t image_reader_t::the_instance; imagelist_reader_t imagelist_reader_t::the_instance; imagelist2d_reader_t imagelist2d_reader_t::the_instance; root_reader_t root_reader_t::the_instance; xref_reader_t xref_reader_t::the_instance; sound_reader_t sound_reader_t::the_instance; menuskin_reader_t menuskin_reader_t::the_instance; cursorskin_reader_t cursorskin_reader_t::the_instance; symbolskin_reader_t symbolskin_reader_t::the_instance; miscimages_reader_t miscimages_reader_t::the_instance; goods_reader_t goods_reader_t::the_instance; ground_reader_t ground_reader_t::the_instance; groundobj_reader_t groundobj_reader_t::the_instance; way_reader_t way_reader_t::the_instance; way_obj_reader_t way_obj_reader_t::the_instance; crossing_reader_t crossing_reader_t::the_instance; bridge_reader_t bridge_reader_t::the_instance; tunnel_reader_t tunnel_reader_t::the_instance; smoke_reader_t smoke_reader_t::the_instance; fieldskin_reader_t fieldskin_reader_t::the_instance; building_reader_t building_reader_t::the_instance; tile_reader_t tile_reader_t::the_instance; factory_reader_t factory_reader_t::the_instance; factory_supplier_reader_t factory_supplier_reader_t::the_instance; factory_product_reader_t factory_product_reader_t::the_instance; factory_smoke_reader_t factory_smoke_reader_t::the_instance; factory_field_group_reader_t factory_field_group_reader_t::the_instance; field_class_desc_t* factory_field_group_reader_t::incomplete_field_class_desc = NULL; factory_field_class_reader_t factory_field_class_reader_t::the_instance; vehicle_reader_t vehicle_reader_t::the_instance; roadsign_reader_t roadsign_reader_t::the_instance; citycar_reader_t citycar_reader_t::the_instance; pedestrian_reader_t pedestrian_reader_t::the_instance; tree_reader_t tree_reader_t::the_instance; simutrans-124.3/src/simutrans/descriptor/reader/skin_reader.cc000066400000000000000000000017541474050137200246130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../obj/simobj.h" #include "../../simdebug.h" #include "../../simskin.h" #include "../../obj/wolke.h" #include "../skin_desc.h" #include "skin_reader.h" void skin_reader_t::register_obj(obj_desc_t *&data) { skin_desc_t* desc = static_cast(data); if(get_skintype() != skinverwaltung_t::nothing) { skinverwaltung_t::register_desc(get_skintype(), desc); } else { pakset_manager_t::obj_for_xref(get_type(), desc->get_name(), data); // smoke needs its own registering if( get_type()==obj_smoke ) { wolke_t::register_desc(desc); } } } bool skin_reader_t::successfully_loaded() const { DBG_MESSAGE("skin_reader_t::successfully_loaded()",""); return skinverwaltung_t::successfully_loaded(get_skintype()); } obj_desc_t* skin_reader_t::read_node(FILE*, obj_node_info_t& info) { return obj_reader_t::read_node(info); } simutrans-124.3/src/simutrans/descriptor/reader/skin_reader.h000066400000000000000000000044251474050137200244530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_SKIN_READER_H #define DESCRIPTOR_READER_SKIN_READER_H #include "../../simskin.h" #include "../../tpl/slist_tpl.h" #include "obj_reader.h" class skin_reader_t : public obj_reader_t { public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; /// @returns type of skin this reader is able to read virtual skinverwaltung_t::skintyp_t get_skintype() const = 0; }; class menuskin_reader_t : public skin_reader_t { OBJ_READER_DEF(menuskin_reader_t, obj_menu, "menu"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::menu; } }; class cursorskin_reader_t : public skin_reader_t { OBJ_READER_DEF(cursorskin_reader_t, obj_cursor, "cursor"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::cursor; } }; class symbolskin_reader_t : public skin_reader_t { OBJ_READER_DEF(symbolskin_reader_t, obj_symbol, "symbol"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::symbol; } }; class fieldskin_reader_t : public skin_reader_t { OBJ_READER_DEF(fieldskin_reader_t, obj_field, "field"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::nothing; } }; class smoke_reader_t : public skin_reader_t { OBJ_READER_DEF(smoke_reader_t, obj_smoke, "smoke"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::nothing; } }; class miscimages_reader_t : public skin_reader_t { OBJ_READER_DEF(miscimages_reader_t, obj_miscimages, "misc"); protected: /// @copydoc skin_reader_t::get_skintype skinverwaltung_t::skintyp_t get_skintype() const OVERRIDE { return skinverwaltung_t::misc; } }; #endif simutrans-124.3/src/simutrans/descriptor/reader/sound_reader.cc000066400000000000000000000023771474050137200250010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../sound_desc.h" #include "sound_reader.h" #include "../obj_node_info.h" #include "../../simdebug.h" #include "../../tpl/array_tpl.h" void sound_reader_t::register_obj(obj_desc_t *&data) { sound_desc_t *desc = static_cast(data); sound_desc_t::register_desc(desc); DBG_DEBUG("sound_reader_t::read_node()","sound %s registered at %i",desc->get_name(),desc->sound_id); delete desc; } obj_desc_t * sound_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; sound_desc_t *desc = new sound_desc_t(); if(version==1) { // Versioned node, version 2 desc->nr = decode_uint16(p); } else if( version == 2 ) { // Versioned node, version 2 desc->nr = decode_uint16(p); uint16 len = decode_uint16(p); if( len>0 ) { desc->nr = desc->get_sound_id(p); } } else { dbg->fatal( "sound_reader_t::read_node()", "Cannot handle too new node version %i", version ); } return desc; } simutrans-124.3/src/simutrans/descriptor/reader/sound_reader.h000066400000000000000000000010311474050137200246250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_SOUND_READER_H #define DESCRIPTOR_READER_SOUND_READER_H #include "obj_reader.h" class sound_reader_t : public obj_reader_t { OBJ_READER_DEF(sound_reader_t, obj_sound, "sound"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/text_reader.cc000066400000000000000000000010351474050137200246230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../text_desc.h" #include "text_reader.h" #include "../obj_node_info.h" obj_desc_t *text_reader_t::read_node(FILE *fp, obj_node_info_t &node) { text_desc_t *desc = new(node.size) text_desc_t(); // Read data if (fread(desc->text, node.size, 1, fp) != 1) { delete desc; return NULL; } // DBG_DEBUG("text_reader_t::read_node()", "%s",desc->get_text() ); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/text_reader.h000066400000000000000000000006611474050137200244710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_TEXT_READER_H #define DESCRIPTOR_READER_TEXT_READER_H #include "obj_reader.h" class text_reader_t : public obj_reader_t { OBJ_READER_DEF(text_reader_t, obj_text, "text"); public: /// @copydoc obj_reader_t::register_obj obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/tree_reader.cc000066400000000000000000000041441474050137200246020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../obj/simobj.h" #include "../../simdebug.h" #include "../../obj/baum.h" #include "../tree_desc.h" #include "../obj_node_info.h" #include "tree_reader.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void tree_reader_t::register_obj(obj_desc_t *&data) { tree_desc_t *desc = static_cast(data); tree_builder_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool tree_reader_t::successfully_loaded() const { return tree_builder_t::successfully_loaded(); } obj_desc_t * tree_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the highest bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; tree_desc_t *desc = new tree_desc_t(); if(version==2) { // Versioned node, version 2 desc->allowed_climates = (climate_bits)decode_uint16(p); desc->distribution_weight = (uint8)decode_uint8(p); desc->number_of_seasons = (uint8)decode_uint8(p); } else if(version == 1) { // Versioned node, version 1 desc->allowed_climates = all_but_arctic_climate; desc->number_of_seasons = 0; decode_uint8(p); // ignore hoehenlage desc->distribution_weight = (uint8)decode_uint8(p); } else { if( version ) { dbg->fatal( "tree_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 desc->number_of_seasons = 0; desc->allowed_climates = all_but_arctic_climate; desc->distribution_weight = 3; } DBG_DEBUG("tree_reader_t::read_node()", "version=%i, climates=$%X, seasons=%i, chance=%i (node.size=%i)", version, desc->allowed_climates, desc->number_of_seasons, desc->distribution_weight, node.size); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/tree_reader.h000066400000000000000000000011601474050137200244370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_TREE_READER_H #define DESCRIPTOR_READER_TREE_READER_H #include "obj_reader.h" class tree_reader_t : public obj_reader_t { OBJ_READER_DEF(tree_reader_t, obj_tree, "tree"); protected: /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/tunnel_reader.cc000066400000000000000000000107151474050137200251510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../dataobj/ribi.h" #include "../intro_dates.h" #include "../tunnel_desc.h" #include "../obj_desc.h" #include "../obj_node_info.h" #include "tunnel_reader.h" #include "../../builder/tunnelbauer.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void tunnel_reader_t::register_obj(obj_desc_t *&data) { tunnel_desc_t *desc = static_cast(data); if(desc->get_topspeed()==0) { convert_old_tunnel(desc); } DBG_DEBUG("tunnel_reader_t::register_obj", "Loaded '%s'", desc->get_name()); tunnel_builder_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } /** * Sets default data for ancient tunnel paks */ void tunnel_reader_t::convert_old_tunnel(tunnel_desc_t *desc) { // old style, need to convert if(strcmp(desc->get_name(),"RoadTunnel")==0) { desc->wtyp = (uint8)road_wt; desc->topspeed = 120; } else { desc->wtyp = (uint8)track_wt; desc->topspeed = 280; } desc->maintenance = 500; desc->price = 200000; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->has_way = false; } obj_desc_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node) { tunnel_desc_t *desc = new tunnel_desc_t(); desc->topspeed = 0; // indicate, that we have to convert this to reasonable date, when read completely if(node.size==0) { return desc; } array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { delete desc; return NULL; } char *p = desc_buf.begin(); const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; if( version == 5 ) { // versioned node, version 5 - axle load desc->topspeed = decode_uint32(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->axle_load = decode_uint16(p); // new desc->number_of_seasons = decode_uint8(p); desc->has_way = decode_uint8(p); desc->broad_portals = decode_uint8(p); } else if( version == 4 ) { // versioned node, version 4 - broad portal support desc->topspeed = decode_uint32(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->number_of_seasons = decode_uint8(p); desc->has_way = decode_uint8(p); desc->broad_portals = decode_uint8(p); } else if(version == 3) { // versioned node, version 3 - underground way image support desc->topspeed = decode_uint32(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->number_of_seasons = decode_uint8(p); desc->has_way = decode_uint8(p); desc->broad_portals = 0; } else if(version == 2) { // versioned node, version 2 - snow image support desc->topspeed = decode_uint32(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->number_of_seasons = decode_uint8(p); desc->has_way = 0; desc->broad_portals = 0; } else if(version == 1) { // first versioned node, version 1 desc->topspeed = decode_uint32(p); desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->wtyp = decode_uint8(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->number_of_seasons = 0; desc->has_way = 0; desc->broad_portals = 0; } else { dbg->fatal( "tunnel_reader_t::read_node()", "Cannot handle too new node version %i", version ); } if( version < 5 ) { desc->axle_load = 9999; } DBG_DEBUG("tunnel_reader_t::read_node()", "version=%d, waytype=%d, price=%d, maintenance=%d, topspeed=%d, intro=%d/%d, retire=%d/%d, axle_load=%d, has_way=%i, seasons=%i, b_portals=%i", version, desc->wtyp, desc->price, desc->maintenance, desc->topspeed, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12, desc->axle_load, desc->has_way, desc->number_of_seasons, desc->broad_portals); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/tunnel_reader.h000066400000000000000000000011551474050137200250110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_TUNNEL_READER_H #define DESCRIPTOR_READER_TUNNEL_READER_H #include "obj_reader.h" class tunnel_desc_t; class tunnel_reader_t : public obj_reader_t { OBJ_READER_DEF(tunnel_reader_t, obj_tunnel, "tunnel"); static void convert_old_tunnel(tunnel_desc_t *desc); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/vehicle_reader.cc000066400000000000000000000250211474050137200252570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../simconst.h" #include "../../builder/vehikelbauer.h" #include "../sound_desc.h" #include "../vehicle_desc.h" #include "../intro_dates.h" #include "vehicle_reader.h" #include "../obj_node_info.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void vehicle_reader_t::register_obj(obj_desc_t *&data) { vehicle_desc_t *desc = static_cast(data); vehicle_builder_t::register_desc(desc); pakset_manager_t::obj_for_xref(get_type(), desc->get_name(), data); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool vehicle_reader_t::successfully_loaded() const { return vehicle_builder_t::successfully_loaded(); } obj_desc_t *vehicle_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const int version = v & 0x8000 ? v & 0x7FFF : 0; vehicle_desc_t *desc = new vehicle_desc_t(); if(version == 1) { // Versioned node, version 1 desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint16(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->gear = decode_uint8(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->retire_date = (DEFAULT_RETIRE_DATE*16); } else if(version == 2) { // Versioned node, version 2 desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint16(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->gear = decode_uint8(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->engine_type = decode_uint8(p); desc->retire_date = (DEFAULT_RETIRE_DATE*16); } else if (version==3 || version==4 || version==5) { // Versioned node, version 3 with retire date // version 4 identical, just other values for the waytype // version 5 just uses the new scheme for data calculation desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint16(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint8(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->engine_type = decode_uint8(p); } else if (version==6) { // version 5 just 32 bit for power and 16 Bit for gear desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); } else if (version==7) { // different length of cars ... desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->len = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); } else if (version==8) { // multiple freight images... desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->len = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->freight_image_type = decode_uint8(p); } else if (version==9) { // new: fixed_cost, loading_time, axle_load desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->loading_time = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->axle_load = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->maintenance = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->len = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->freight_image_type = decode_uint8(p); } else if (version==10) { // new: weight in kgs desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->loading_time = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint32(p); desc->axle_load = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->maintenance = decode_uint16(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->len = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->freight_image_type = decode_uint8(p); } else if (version==11) { // new: fix cost as uint32 desc->price = decode_uint32(p); desc->capacity = decode_uint16(p); desc->loading_time = decode_uint16(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint32(p); desc->axle_load = decode_uint16(p); desc->power = decode_uint32(p); desc->running_cost = decode_uint16(p); desc->maintenance = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->gear = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->sound = decode_sint8(p); desc->engine_type = decode_uint8(p); desc->len = decode_uint8(p); desc->leader_count = decode_uint8(p); desc->trailer_count = decode_uint8(p); desc->freight_image_type = decode_uint8(p); } else { if( version ) { dbg->fatal( "vehicle_reader_t::read_node()", "Cannot handle too new node version %i", version ); } // old node, version 0 desc->wtyp = (sint8)v; desc->capacity = decode_uint16(p); desc->price = decode_uint32(p); desc->topspeed = decode_uint16(p); desc->weight = decode_uint16(p); desc->power = decode_uint16(p); desc->running_cost = decode_uint16(p); desc->sound = (sint8)decode_sint16(p); desc->leader_count = (sint8)decode_uint16(p); desc->trailer_count = (sint8)decode_uint16(p); desc->intro_date = DEFAULT_INTRO_DATE*16; desc->retire_date = (DEFAULT_RETIRE_DATE*16); desc->gear = 64; } // correct the engine type for old vehicles if(version<2) { // steam eangines usually have a sound of 3 // electric engines will be overridden further down ... desc->engine_type = (desc->sound==3) ? vehicle_desc_t::steam : vehicle_desc_t::diesel; } //change the vehicle type if(version<4) { if(desc->wtyp==4) { desc->engine_type = vehicle_desc_t::electric; desc->wtyp = 1; } // convert to new standard static const waytype_t convert_from_old[8]={road_wt, track_wt, water_wt, air_wt, invalid_wt, monorail_wt, invalid_wt, tram_wt }; desc->wtyp = convert_from_old[desc->wtyp]; } // before version 5 dates were based on base 12 ... if(version<5) { uint16 date=desc->intro_date; desc->intro_date = (date/16)*12 + (date%16); date=desc->retire_date; desc->retire_date = (date/16)*12 + (date%16); } // before the length was always 1/8 (=half a tile) if(version<7) { desc->len = CARUNITS_PER_TILE/2; } // adjust length for different offset step sizes (which may arise in future) desc->len *= OBJECT_OFFSET_STEPS/CARUNITS_PER_TILE; // before version 8 vehicles could only have one freight image in each direction if(version<8) { desc->freight_image_type=0; } if(version<9) { desc->maintenance = 0; desc->axle_load = 0; desc->loading_time = 1000; } // old weights were tons if(version<10) { desc->weight *= 1000; } if(desc->sound==LOAD_SOUND) { uint8 len=decode_sint8(p); char wavname[256]; wavname[len] = 0; for(uint8 i=0; isound = (sint8)sound_desc_t::get_sound_id(wavname); DBG_MESSAGE("vehicle_reader_t::register_obj()","sound %s to %i",wavname,desc->sound); } else if(desc->sound>=0 && desc->sound<=MAX_OLD_SOUNDS) { sint16 old_id = desc->sound; desc->sound = (sint8)sound_desc_t::get_compatible_sound_id((sint8)old_id); DBG_MESSAGE("vehicle_reader_t::register_obj()","old sound %i to %i",old_id,desc->sound); } DBG_DEBUG("vehicle_reader_t::read_node()", "version=%d " "way=%d capacity=%d price=%d topspeed=%d weight=%g axle_load=%d power=%d " "running_cost=%d fixed_cost=%d sound=%d prev=%d next=%d loading_time=%d" "date=%d/%d retire=%d/%d gear=%d engine_type=%d freigh_imgs=%d len=%d", version, desc->wtyp, desc->capacity, desc->price, desc->topspeed, desc->weight/1000.0, desc->axle_load, desc->power, desc->running_cost, desc->maintenance, desc->sound, desc->leader_count, desc->trailer_count, desc->loading_time, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12, desc->gear, desc->engine_type, desc->freight_image_type, desc->len); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/vehicle_reader.h000066400000000000000000000011751474050137200251250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_VEHICLE_READER_H #define DESCRIPTOR_READER_VEHICLE_READER_H #include "obj_reader.h" class vehicle_reader_t : public obj_reader_t { OBJ_READER_DEF(vehicle_reader_t, obj_vehicle, "vehicle"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t*&) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/way_obj_reader.cc000066400000000000000000000037571474050137200253060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../utils/simstring.h" #include "../way_obj_desc.h" #include "../../obj/wayobj.h" #include "way_obj_reader.h" #include "../obj_node_info.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void way_obj_reader_t::register_obj(obj_desc_t *&data) { way_obj_desc_t *desc = static_cast(data); wayobj_t::register_desc(desc); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool way_obj_reader_t::successfully_loaded() const { return wayobj_t::successfully_loaded(); } obj_desc_t * way_obj_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. const uint16 v = decode_uint16(p); const uint16 version = v & 0x7FFF; way_obj_desc_t *desc = new way_obj_desc_t(); if(version==1) { // Versioned node, version 3 desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->own_wtyp = decode_uint8(p); } else { dbg->fatal( "way_obj_reader_t::read_node()", "Cannot handle too new node version %i", version ); } DBG_DEBUG("way_obj_reader_t::read_node()", "version=%d price=%d maintenance=%d topspeed=%d wtype=%d own_wtype=%d intro=%i/%i, retire=%i/%i", version, desc->price, desc->maintenance, desc->topspeed, desc->wtyp, desc->own_wtyp, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/way_obj_reader.h000066400000000000000000000012051474050137200251320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_WAY_OBJ_READER_H #define DESCRIPTOR_READER_WAY_OBJ_READER_H #include "obj_reader.h" class way_obj_reader_t : public obj_reader_t { OBJ_READER_DEF(way_obj_reader_t, obj_way_obj, "way-object"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/way_reader.cc000066400000000000000000000121331474050137200244400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../utils/simstring.h" #include "../way_desc.h" #include "../intro_dates.h" #include "../../builder/wegbauer.h" #include "way_reader.h" #include "../obj_node_info.h" #include "../../network/pakset_info.h" #include "../../tpl/array_tpl.h" void way_reader_t::register_obj(obj_desc_t *&data) { way_desc_t *desc = static_cast(data); way_builder_t::register_desc(desc); pakset_manager_t::obj_for_xref(get_type(), desc->get_name(), data); checksum_t *chk = new checksum_t(); desc->calc_checksum(chk); pakset_info_t::append(desc->get_name(), get_type_name(), chk); } bool way_reader_t::successfully_loaded() const { return way_builder_t::successfully_loaded(); } obj_desc_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node) { array_tpl desc_buf(node.size); if (fread(desc_buf.begin(), node.size, 1, fp) != 1) { return NULL; } char *p = desc_buf.begin(); // old versions of PAK files have no version stamp. // But we know, the higher most bit was always cleared. int version = 0; way_desc_t *desc = new way_desc_t(); if(node.size == 0) { // old node, version 0, compatibility code desc->price = 10000; desc->maintenance = 800; desc->topspeed = 999; desc->max_weight = 999; desc->intro_date = DEFAULT_INTRO_DATE*12; desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->wtyp = road_wt; desc->styp = type_flat; desc->draw_as_obj = false; desc->number_of_seasons = 0; } else { const uint16 v = decode_uint16(p); version = v & 0x7FFF; if(version==6) { // version 6, now with axle load desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->max_weight = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->axle_load = decode_uint16(p); // new desc->wtyp = decode_uint8(p); desc->styp = decode_uint8(p); desc->draw_as_obj = decode_uint8(p); desc->number_of_seasons = decode_sint8(p); } else if(version==4 || version==5) { // Versioned node, version 4+5 desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->max_weight = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->styp = decode_uint8(p); desc->draw_as_obj = decode_uint8(p); desc->number_of_seasons = decode_sint8(p); } else if(version==3) { // Versioned node, version 3 desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->max_weight = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->styp = decode_uint8(p); desc->draw_as_obj = decode_uint8(p); desc->number_of_seasons = 0; } else if(version==2) { // Versioned node, version 2 desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->max_weight = decode_uint32(p); desc->intro_date = decode_uint16(p); desc->retire_date = decode_uint16(p); desc->wtyp = decode_uint8(p); desc->styp = decode_uint8(p); desc->draw_as_obj = false; desc->number_of_seasons = 0; } else if(version == 1) { // Versioned node, version 1 desc->price = decode_uint32(p); desc->maintenance = decode_uint32(p); desc->topspeed = decode_uint32(p); desc->max_weight = decode_uint32(p); uint32 intro_date= decode_uint32(p); desc->intro_date = (intro_date/16)*12 + (intro_date%16); desc->wtyp = decode_uint8(p); desc->styp = decode_uint8(p); desc->retire_date = DEFAULT_RETIRE_DATE*12; desc->draw_as_obj = false; desc->number_of_seasons = 0; } else { dbg->fatal( "way_reader_t::read_node()", "Cannot handle too new node version %i", version ); } } // some internal corrections to pay for previous confusion with two waytypes if(desc->wtyp==tram_wt) { desc->styp = type_tram; desc->wtyp = track_wt; } else if(desc->styp==5 && desc->wtyp==track_wt) { desc->wtyp = monorail_wt; desc->styp = type_flat; } else if(desc->wtyp==128) { desc->wtyp = powerline_wt; } if(version<=2 && desc->wtyp==air_wt && desc->topspeed>=250) { // runway! desc->styp = type_runway; } if( version < 6 ) { desc->axle_load = 9999; } // front images from version 5 on desc->front_images = version > 4; DBG_DEBUG("way_reader_t::read_node()", "version=%d, price=%d, maintenance=%d, topspeed=%d, max_weight=%d, " "wtype=%d, styp=%d, intro=%i/%i, retire=%i/%i, axle_load=%d, ding=%i, seasons=%i", version, desc->price, desc->maintenance, desc->topspeed, desc->max_weight, desc->wtyp, desc->styp, (desc->intro_date%12)+1, desc->intro_date/12, (desc->retire_date%12)+1, desc->retire_date/12, desc->axle_load, desc->draw_as_obj, desc->number_of_seasons); return desc; } simutrans-124.3/src/simutrans/descriptor/reader/way_reader.h000066400000000000000000000011521474050137200243010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_WAY_READER_H #define DESCRIPTOR_READER_WAY_READER_H #include "obj_reader.h" class way_reader_t : public obj_reader_t { OBJ_READER_DEF(way_reader_t, obj_way, "way"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; /// @copydoc obj_reader_t::successfully_loaded bool successfully_loaded() const OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/reader/xref_reader.cc000066400000000000000000000020201474050137200245760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../xref_desc.h" #include "xref_reader.h" #include "../obj_node_info.h" obj_desc_t *xref_reader_t::read_node(FILE *fp, obj_node_info_t &node) { char buf[4 + 1]; if (fread(buf, 1, 5, fp) != 5) { return NULL; } const uint32 name_len = node.size - 4 - 1; char *p = buf; xref_desc_t* desc = new(name_len) xref_desc_t(); desc->type = static_cast(decode_uint32(p)); desc->fatal = (decode_uint8(p) != 0); if (fread(desc->name, 1, name_len, fp) != name_len) { delete desc; return NULL; } // DBG_DEBUG("xref_reader_t::read_node()", "%s",desc->get_text() ); return desc; } void xref_reader_t::register_obj(obj_desc_t *&data) { xref_desc_t* desc = static_cast(data); if (desc->name[0] != '\0' || desc->fatal) { pakset_manager_t::xref_to_resolve(desc->type, desc->name, &data, desc->fatal); } else { delete data; data = NULL; } } simutrans-124.3/src/simutrans/descriptor/reader/xref_reader.h000066400000000000000000000010301474050137200244400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_READER_XREF_READER_H #define DESCRIPTOR_READER_XREF_READER_H #include "obj_reader.h" class xref_reader_t : public obj_reader_t { OBJ_READER_DEF(xref_reader_t, obj_xref, "reference"); protected: /// @copydoc obj_reader_t::register_obj void register_obj(obj_desc_t *&desc) OVERRIDE; public: /// @copydoc obj_reader_t::read_node obj_desc_t *read_node(FILE *fp, obj_node_info_t &node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/roadsign_desc.h000066400000000000000000000054011474050137200235220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_ROADSIGN_DESC_H #define DESCRIPTOR_ROADSIGN_DESC_H #include "obj_base_desc.h" #include "image_list.h" #include "skin_desc.h" #include "../dataobj/ribi.h" #include "../simtypes.h" #include "../network/checksum.h" /** * Road signs * * Child nodes: * 0 Name * 1 Copyright * 2 Image list */ class roadsign_desc_t : public obj_desc_transport_infrastructure_t { friend class roadsign_reader_t; private: uint16 flags; sint8 offset_left; // default 14 uint16 min_speed; // 0 = no min speed public: enum types { NONE = 0, ONE_WAY = 1U << 0, CHOOSE_SIGN = 1U << 1, PRIVATE_ROAD = 1U << 2, SIGN_SIGNAL = 1U << 3, SIGN_PRE_SIGNAL = 1U << 4, ONLY_BACKIMAGE = 1U << 5, SIGN_LONGBLOCK_SIGNAL = 1U << 6, END_OF_CHOOSE_AREA = 1U << 7, SIGN_PRIORITY_SIGNAL = 1U << 8 }; image_id get_image_id(ribi_t::dir dir) const { image_t const* const image = get_child(2)->get_image(dir); return image != NULL ? image->get_id() : IMG_EMPTY; } uint16 get_count() const { return get_child(2)->get_count(); } skin_desc_t const* get_cursor() const { return get_child(3); } uint16 get_min_speed() const { return min_speed; } bool is_single_way() const { return (flags & ONE_WAY) != 0; } bool is_private_way() const { return (flags & PRIVATE_ROAD) != 0; } bool is_choose_sign() const { return (flags & CHOOSE_SIGN) != 0; } // return true for signal bool is_simple_signal() const { return (flags & ( SIGN_SIGNAL | SIGN_PRE_SIGNAL | SIGN_PRIORITY_SIGNAL | SIGN_LONGBLOCK_SIGNAL | CHOOSE_SIGN)) == SIGN_SIGNAL; } // return true for presignal bool is_pre_signal() const { return (flags & SIGN_PRE_SIGNAL) != 0; } // return true for priority signal bool is_priority_signal() const { return (flags & SIGN_PRIORITY_SIGNAL) != 0; } // return true for single track section signal bool is_longblock_signal() const { return (flags & SIGN_LONGBLOCK_SIGNAL) != 0; } bool is_end_choose_signal() const { return (flags & END_OF_CHOOSE_AREA) != 0; } bool is_signal_type() const { return (flags&( SIGN_SIGNAL | SIGN_PRE_SIGNAL | SIGN_PRIORITY_SIGNAL | SIGN_LONGBLOCK_SIGNAL) ) != 0; } // return true for a traffic light bool is_traffic_light() const { return !is_signal_type() && get_count() > 4; } uint16 get_flags() const { return flags; } sint8 get_offset_left() const { return offset_left; } void calc_checksum(checksum_t *chk) const { obj_desc_transport_infrastructure_t::calc_checksum(chk); chk->input(flags); chk->input(min_speed); } }; ENUM_BITSET(roadsign_desc_t::types) #endif simutrans-124.3/src/simutrans/descriptor/skin_desc.h000066400000000000000000000014241474050137200226610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_SKIN_DESC_H #define DESCRIPTOR_SKIN_DESC_H #include "../display/simimg.h" #include "obj_base_desc.h" #include "image_array.h" /** * An image list, with name and author attributes. Mostly used for gui purposes. * * Child nodes: * 0 Name * 1 Copyright * 2 Image list */ class skin_desc_t : public obj_named_desc_t { public: image_t const* get_image(uint16 i) const { return get_child(2)->get_image(i); } uint16 get_count() const { return get_child(2)->get_count(); } image_id get_image_id(uint16 i) const { const image_t *image = get_image(i); return image != NULL ? image->get_id() : IMG_EMPTY; } }; #endif simutrans-124.3/src/simutrans/descriptor/sound_desc.cc000066400000000000000000000103651474050137200232070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../simdebug.h" #include "../dataobj/tabfile.h" #include "../dataobj/environment.h" #include "../macros.h" #include "../sound/sound.h" #include "../utils/simstring.h" #include "../tpl/stringhashtable_tpl.h" #include "spezial_obj_tpl.h" #include "sound_desc.h" #include "ground_desc.h" /* * sound of the program */ class sound_ids { public: std::string filename; sint16 id; sound_ids() { id=NO_SOUND; } sound_ids(sint16 i) { id=i; } sound_ids(sint16 i, const char* fn) : filename(fn), id(i) {} }; static stringhashtable_tpl name_sound; static bool sound_on=false; static std::string sound_path; sint16 sound_desc_t::compatible_sound_id[MAX_OLD_SOUNDS]= { NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND }; // sound with the names of climates and "beaches" and "forest" are reserved for ambient noises sint16 sound_desc_t::beach_sound = NO_SOUND; sint16 sound_desc_t::forest_sound = NO_SOUND; sint16 sound_desc_t::climate_sounds[MAX_CLIMATES]= { NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND, NO_SOUND }; sint16 sound_desc_t::message_sound; /* init sounds */ /* standard sounds and old sounds are found in the file /sound/sound.tab */ void sound_desc_t::init(const std::string &pak_dir) { // ok, now init sound_on = true; sound_path = pak_dir + "sound/"; tabfile_t soundconf; const std::string tabfilename = pak_dir + "sound/sound.tab"; if (!soundconf.open(tabfilename.c_str())) { return; } DBG_MESSAGE("sound_desc_t::init()","successfully opened sound/sound.tab" ); tabfileobj_t contents; soundconf.read(contents); // max. 16 old sounds ... for( unsigned i=0; i0) { DBG_MESSAGE("sound_desc_t::init()","reading sound %s", fn ); compatible_sound_id[i] = get_sound_id( fn ); DBG_MESSAGE("sound_desc_t::init()","assigned system sound %d to sound %s (id=%i)", i, (const char *)fn, compatible_sound_id[i] ); } message_sound = get_sound_id("message.wav"); } // now assign special sounds for climates, beaches and forest beach_sound = get_sound_id( "beaches.wav" ); forest_sound = get_sound_id( "forest.wav" ); for( int i=0; iid!=NO_SOUND) { DBG_MESSAGE("sound_desc_t::get_sound_id()", "Successfully retrieved sound \"%s\" with internal id %hi", s->filename.c_str(), s->id ); return s->id; } // not loaded: try to load it const sint16 sample_id = dr_load_sample((sound_path + name).c_str()); if(sample_id==NO_SOUND) { dbg->warning("sound_desc_t::get_sound_id()", "Sound \"%s\" not found", name ); return NO_SOUND; } s = new sound_ids(sample_id, name); name_sound.put(s->filename.c_str(), s ); DBG_MESSAGE("sound_desc_t::get_sound_id()", "Successfully loaded sound \"%s\" with internal id %hi", s->filename.c_str(), s->id ); return s->id; } /* * if there is already such a sound => fail, else success and get an internal sound id * do not store desc as it will be deleted anyway */ bool sound_desc_t::register_desc(sound_desc_t *desc) { if( !sound_on ) { return false; } // register, if not there (all done by this one here) desc->sound_id = get_sound_id( desc->get_name() ); if(desc->sound_id!=NO_SOUND) { if(desc->nr>=0 && desc->nr<=8) { compatible_sound_id[desc->nr] = desc->sound_id; DBG_MESSAGE("sound_desc_t::register_desc", "Successfully registered sound %s internal id %i as compatible sound %i", desc->get_name(), desc->sound_id, desc->nr ); return true; } } dbg->warning("sound_desc_t::register_desc", "Failed to register sound %s internal id %i", desc->get_name(), desc->sound_id); return false; } simutrans-124.3/src/simutrans/descriptor/sound_desc.h000066400000000000000000000032021474050137200230410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_SOUND_DESC_H #define DESCRIPTOR_SOUND_DESC_H #include "obj_base_desc.h" #include "../simtypes.h" #include #define NO_SOUND (sint16)(0xFFFFu) #define LOAD_SOUND (sint8)(0xFFFEu) #define AMBIENT_SOUND_INTERVALL (13000) #define SFX_CASH sound_desc_t::get_compatible_sound_id(15) #define SFX_REMOVER sound_desc_t::get_compatible_sound_id(14) #define SFX_DOCK sound_desc_t::get_compatible_sound_id(13) #define SFX_GAVEL sound_desc_t::get_compatible_sound_id(12) #define SFX_JACKHAMMER sound_desc_t::get_compatible_sound_id(11) #define SFX_FAILURE sound_desc_t::get_compatible_sound_id(10) #define SFX_SELECT sound_desc_t::get_compatible_sound_id(9) #define MAX_OLD_SOUNDS (16) /** * Sounds in the game; name is the file name * ingame, sounds are referred to by their number * * Child nodes: * 0 Name * 1 Copyright */ class sound_desc_t : public obj_named_desc_t { friend class sound_reader_t; private: static sint16 compatible_sound_id[MAX_OLD_SOUNDS]; sint16 sound_id; sint16 nr; // for old sounds/system sounds etc. public: // sounds for ambient static sint16 beach_sound; static sint16 forest_sound; static sint16 climate_sounds[MAX_CLIMATES]; // sound for message notification static sint16 message_sound; static sint16 get_sound_id(const char *name); static bool register_desc(sound_desc_t *desc); static void init(const std::string &pak_dir); /* return old sound id from index */ static sint16 get_compatible_sound_id(const sint8 nr) { return compatible_sound_id[nr&(15)]; } }; #endif simutrans-124.3/src/simutrans/descriptor/spezial_obj_tpl.h000066400000000000000000000040171474050137200241000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_SPEZIAL_OBJ_TPL_H #define DESCRIPTOR_SPEZIAL_OBJ_TPL_H #include #include #include "../simdebug.h" /** * @file spezial_obj_tpl.h * * Routines to manage special object descriptors lists used in the program. */ /** * Descriptors of required objects. The following functions manage * the list. The list is "{NULL, NULL}" terminated. */ template struct special_obj_tpl { const desc_t** desc; const char* name; }; /** * An object pointer is set on the passed list, if the name of the * object belongs to one of the objects mentioned in the list. * @param so List to operate over. * @param desc Descriptor to add. */ template bool register_desc(special_obj_tpl const* so, desc_t const* const desc) { for (; so->name; ++so) { if (strcmp(so->name, desc->get_name()) == 0) { if (*so->desc != NULL ) { // these doublettes are harmless, and hence only recored at debug level 3 // dbg->doubled( "object", desc->get_name() ); dbg->message("register_desc()", "Notice: obj %s already defined", so->name); } *so->desc = desc; return true; } } return false; } /** * Verifies the passed list for all objects to be not NULL, ie are loaded. * @param so List to check. */ template bool successfully_loaded(special_obj_tpl const* so) { for (; so->name; ++so) { if (!*so->desc) { dbg->fatal("successfully_loaded()", "%s-object %s not found.\n*** PLEASE INSTALL PROPER BASE FILE AND CHECK PATH ***", typeid(**so->desc).name(), so->name); return false; } } return true; } /** * Shows debug messages showing which descriptors lack definition. * @param so List to check. */ template void warn_missing_objects(special_obj_tpl const* so) { for (; so->name; ++so) { if (!*so->desc) { dbg->message("warn_missing_objects", "Object %s not found, feature disabled", so->name); } } } #endif simutrans-124.3/src/simutrans/descriptor/text_desc.h000066400000000000000000000006051474050137200227010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_TEXT_DESC_H #define DESCRIPTOR_TEXT_DESC_H #include "obj_desc.h" class text_desc_t : public obj_desc_t { public: const char* get_text() const { return text; } using obj_desc_t::operator new; private: char text[]; friend class text_reader_t; }; #endif simutrans-124.3/src/simutrans/descriptor/tree_desc.h000066400000000000000000000027471474050137200226650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_TREE_DESC_H #define DESCRIPTOR_TREE_DESC_H #include "../simtypes.h" #include "obj_base_desc.h" #include "image_array.h" #include "../network/checksum.h" /** * Tree type description in Simutrans * * Child nodes: * 0 Name * 1 Copyright * 2 Image-array * * season 0 is always summer * season 1 is winter for two seasons * otherwise 0 summer, next seasons (autumn, winter, spring) .... */ class tree_desc_t : public obj_named_desc_t { friend class tree_reader_t; climate_bits allowed_climates; uint8 distribution_weight; uint8 number_of_seasons; public: uint16 get_distribution_weight() const { return distribution_weight; } bool is_allowed_climate( climate cl ) const { return ((1<(2)->get_image(i, season)->get_id(); } // old style trees and new style tree support ... uint8 get_seasons() const { if(number_of_seasons==0) { return get_child(2)->get_count() / 5; } return number_of_seasons; } void calc_checksum(checksum_t *chk) const { chk->input((uint8)allowed_climates); chk->input(distribution_weight); } }; #endif simutrans-124.3/src/simutrans/descriptor/tunnel_desc.cc000066400000000000000000000026241474050137200233630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../dataobj/ribi.h" #include "tunnel_desc.h" int tunnel_desc_t::slope_indices[81] = { -1, // 0: -1, // 1: -1, // 2: -1, // 3: 1, // 4:north slope -1, // 5: -1, // 6: -1, // 7: 1, // 8:north slope -1, // 9: -1, // 10: -1, // 11: 2, // 12:west slope -1, // 13: -1, // 14: -1, // 15: -1, // 16: -1, // 17: -1, // 18: -1, // 19: -1, // 20: -1, // 21: -1, // 22: -1, // 23: 2, // 24:west slope -1, // 25: -1, // 26: -1, // 27: 3, // 28:east slope -1, // 29: -1, // 30: -1, // 31: -1, // 32: -1, // 33: -1, // 34: -1, // 35: 0, // 36:south slope -1, // 37: -1, // 38: -1, // 39: -1, // 40: -1, // 41: -1, // 42: -1, // 43: -1, // 44: -1, // 45: -1, // 46: -1, // 47: -1, // 48: -1, // 49: -1, // 50: -1, // 51: -1, // 52: -1, // 53: -1, // 54: -1, // 55: 3, // 56:east slope -1, // 57: -1, // 58: -1, // 59: -1, // 60: -1, // 61: -1, // 62: -1, // 63: -1, // 64: -1, // 65: -1, // 66: -1, // 67: -1, // 68: -1, // 69: -1, // 70: -1, // 71: 0, // 72:south slope -1, // 73: -1, // 74: -1, // 75: -1, // 76: -1, // 77: -1, // 78: -1, // 79: -1 // 80: }; waytype_t tunnel_desc_t::get_finance_waytype() const { return ((get_way_desc() && (get_way_desc()->get_styp() == type_tram)) ? tram_wt : get_waytype()) ; } simutrans-124.3/src/simutrans/descriptor/tunnel_desc.h000066400000000000000000000043761474050137200232330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_TUNNEL_DESC_H #define DESCRIPTOR_TUNNEL_DESC_H #include "../display/simimg.h" #include "../simtypes.h" #include "obj_base_desc.h" #include "skin_desc.h" #include "image_array.h" #include "way_desc.h" /* * node structure: * 0 Name * 1 Copyright * 2 Image-list Background * 3 Image-list Foreground * 4 cursor(image 0) and icon (image 1) *[ 5 Image-list Background - snow ] (if present) *[ 6 Image-list Foreground - snow ] (if present) *[ 7 (or 5 if no snow image) underground way ] (if present) */ class tunnel_desc_t : public obj_desc_transport_infrastructure_t { friend class tunnel_reader_t; friend class tunnel_builder_t; // to convert the old tunnels to new ones private: static int slope_indices[81]; /* number of seasons (0 = none, 1 = no snow/snow */ sint8 number_of_seasons; /* has underground way image ? ( 0 = no, 1 = yes ) [way parameter] */ uint8 has_way; /* Has broad portals? */ uint8 broad_portals; public: const image_t *get_background(slope_t::type slope, uint8 season, uint8 type ) const { const uint8 n = season && number_of_seasons == 1 ? 5 : 2; return get_child(n)->get_image(slope_indices[slope] + 4 * type); } image_id get_background_id(slope_t::type slope, uint8 season, uint8 type ) const { const image_t *desc = get_background(slope, season, type ); return desc != NULL ? desc->get_id() : IMG_EMPTY; } const image_t *get_foreground(slope_t::type slope, uint8 season, uint8 type ) const { const uint8 n = season && number_of_seasons == 1 ? 6 : 3; return get_child(n)->get_image(slope_indices[slope] + 4 * type); } image_id get_foreground_id(slope_t::type slope, uint8 season, uint8 type) const { const image_t *desc = get_foreground(slope, season, type ); return desc != NULL ? desc->get_id() :IMG_EMPTY; } skin_desc_t const* get_cursor() const { return get_child(4); } waytype_t get_finance_waytype() const; const way_desc_t *get_way_desc() const { if(has_way) { return get_child(5 + number_of_seasons * 2); } return NULL; } bool has_broad_portals() const { return (broad_portals != 0); } }; #endif simutrans-124.3/src/simutrans/descriptor/vehicle_desc.cc000066400000000000000000000016241474050137200234740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "vehicle_desc.h" #include "xref_desc.h" #include "../network/checksum.h" vehicle_desc_t *vehicle_desc_t::any_vehicle = NULL; void vehicle_desc_t::calc_checksum(checksum_t *chk) const { obj_desc_transport_related_t::calc_checksum(chk); chk->input(capacity); chk->input(loading_time); chk->input(weight); chk->input(power); chk->input(running_cost); chk->input(maintenance); chk->input(gear); chk->input(len); chk->input(leader_count); chk->input(trailer_count); chk->input(engine_type); // freight const xref_desc_t *xref = get_child(2); chk->input(xref ? xref->get_name() : "NULL"); // vehicle constraints for(uint16 i=0; i(6+i); chk->input(xref ? xref->get_name() : "NULL"); } } simutrans-124.3/src/simutrans/descriptor/vehicle_desc.h000066400000000000000000000160671474050137200233450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_VEHICLE_DESC_H #define DESCRIPTOR_VEHICLE_DESC_H #include "obj_base_desc.h" #include "goods_desc.h" #include "image_list.h" #include "image_array.h" #include "skin_desc.h" #include "sound_desc.h" #include "../dataobj/ribi.h" #include "../simtypes.h" #include "../simunits.h" class checksum_t; /** * Vehicle type description - all attributes of a vehicle type * * Child nodes: * 0 Name * 1 Copyright * 2 freight * 3 smoke * 4 empty 1d image list * 5 either 1d (freight_image_type==0) or 2d image list * 6 required leading vehicle 1 * 7 required leading vehicle 2 * ... ... * n+5 required leading vehicle n * n+6 allowed trailing vehicle 1 * n+7 allowed trailing vehicle 2 * ... ... * n+m+5 allowed trailing vehicle m * n+m+6 freight for which special images are defined */ class vehicle_desc_t : public obj_desc_transport_related_t { friend class vehicle_reader_t; friend class vehicle_builder_t; public: /** * Engine type */ enum engine_t { unknown = -1, steam = 0, diesel, electric, bio, sail, fuel_cell, hydrogene, battery }; private: uint16 capacity; uint16 loading_time; // time per full loading/unloading uint32 weight; uint32 power; uint16 running_cost; uint16 gear; // engine gear (power multiplier), 64=100 uint8 len; // length (=8 is half a tile, the old default) sint8 sound; uint8 leader_count; // all defined leading vehicles uint8 trailer_count; // all defined trailer uint8 engine_type; // diesel, steam, electric (requires electrified ways), fuel_cell, etc. sint8 freight_image_type; // number of freight images (displayed for different goods) public: // dummy vehicle for the XREF reader static vehicle_desc_t *any_vehicle; // since we have a second constructor vehicle_desc_t() { } // default vehicle (used for way search and similar tasks) // since it has no images and not even a name node any calls to this will case a crash vehicle_desc_t(uint8 wtype, uint16 speed, engine_t engine) { maintenance = freight_image_type = price = capacity = axle_load = running_cost = intro_date = leader_count = trailer_count = 0; power = weight = 1; loading_time = 1000; gear = 64; len = 8; sound = -1; wtyp = wtype; engine_type = (uint8)engine; topspeed = speed; } goods_desc_t const* get_freight_type() const { return get_child(2); } skin_desc_t const* get_smoke() const { return get_child(3); } image_id get_base_image() const { return get_image_id(ribi_t::dir_south, get_freight_type() ); } // returns the number of different directions uint8 get_dirs() const { return get_child(4)->get_image(4) ? 8 : 4; } // return a matching image // beware, there are three classes of vehicles // vehicles with and without freight images, and vehicles with different freight images // they can have 4 or 8 directions ... image_id get_image_id(ribi_t::dir dir, const goods_desc_t *ware) const { const image_t *image=0; const image_list_t *list=0; if(freight_image_type>0 && ware!=NULL) { // more freight images and a freight: find the right one sint8 goods_index=0; // freight images: if not found use first freight for( sint8 i=0; i(6 + trailer_count + leader_count + i)) { goods_index = i; break; } } // vehicle has freight images and we want to use - get appropriate one (if no list then fallback to empty image) image_array_t const* const list2d = get_child(5); image=list2d->get_image(dir, goods_index); if(!image) { if(dir>3) { image = list2d->get_image(dir - 4, goods_index); } } if (image != NULL) return image->get_id(); } // only try 1d freight image list for old style vehicles if(freight_image_type==0 && ware!=NULL) { list = get_child(5); } if(!list) { list = get_child(4); if(!list) { return IMG_EMPTY; } } image = list->get_image(dir); if(!image) { if(dir>3) { image = list->get_image(dir - 4); } if(!image) { return IMG_EMPTY; } } return image->get_id(); } /** * Returns allowed leader vehicles. * If get_leader(0) == NULL then either all or no leaders are allowed. * To distinguish these cases check get_leader_count(). */ const vehicle_desc_t *get_leader(uint8 i) const { if( i >= leader_count ) { return 0; } return get_child(6 + i); } uint8 get_leader_count() const { return leader_count; } /** * Returns vehicles that this vehicle is allowed to pull. * If get_trailer(0) == NULL then either all or no followers are allowed. * To distinguish these cases check get_trailer_count(). */ const vehicle_desc_t *get_trailer(uint8 i) const { if( i >= trailer_count ) { return 0; } return get_child(6 + leader_count + i); } uint8 get_trailer_count() const { return trailer_count; } /* returns true, if this veh can be before the next_veh * uses NULL to indicate end of convoi */ bool can_lead(const vehicle_desc_t *next_veh) const { if( trailer_count==0 ) { return true; } for( uint8 i=0; i(6 + leader_count + i); if( veh==next_veh ) { return true; } // not leading and "any" => we can follow if( next_veh!=NULL && veh==vehicle_desc_t::any_vehicle ) { return true; } } // only here if not allowed return false; } /* returns true, if this veh can be after the prev_veh * uses NULL to indicate front of convoi */ bool can_follow(const vehicle_desc_t *prev_veh) const { if( leader_count==0 ) { return true; } for( uint8 i=0; i(6 + i); if( veh==prev_veh ) { return true; } // not leading and "any" => we can follow if( prev_veh!=NULL && veh==vehicle_desc_t::any_vehicle ) { return true; } } // only here if not allowed return false; } bool can_follow_any() const { return trailer_count==0; } uint16 get_capacity() const { return capacity; } uint16 get_loading_time() const { return loading_time; } // ms per full loading/unloading uint32 get_weight() const { return weight; } uint32 get_power() const { return power; } uint32 get_running_cost() const { return running_cost; } sint32 get_fixed_cost() const { return get_maintenance(); } sint8 get_sound() const { return sound; } /** * 64 = 1.00 * @return gear value */ uint16 get_gear() const { return gear; } /** * @return engine type * eletric engines require an electrified way to run */ uint8 get_engine_type() const { return engine_type; } /** * @return the vehicles length in 1/8 of the normal len */ uint8 get_length() const { return len; } uint32 get_length_in_steps() const { return get_length() * VEHICLE_STEPS_PER_CARUNIT; } void calc_checksum(checksum_t *chk) const; }; #endif simutrans-124.3/src/simutrans/descriptor/way_desc.cc000066400000000000000000000007211474050137200226520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "way_desc.h" #include "../network/checksum.h" waytype_t way_desc_t::get_finance_waytype() const { return get_styp() == type_tram ? tram_wt : get_wtyp(); } void way_desc_t::calc_checksum(checksum_t *chk) const { obj_desc_transport_infrastructure_t::calc_checksum(chk); chk->input(max_weight); chk->input(styp); chk->input(has_double_slopes()); } simutrans-124.3/src/simutrans/descriptor/way_desc.h000066400000000000000000000123411474050137200225150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WAY_DESC_H #define DESCRIPTOR_WAY_DESC_H #include "image_list.h" #include "obj_base_desc.h" #include "skin_desc.h" #include "../dataobj/ribi.h" class checksum_t; class tool_t; /** * Way type description. Contains all needed values to describe a * way type in Simutrans. * * Child nodes: * 0 Name * 1 Copyright * 2 Images for flat ways (indexed by ribi) * 3 Images for slopes * 4 Images for straight diagonal ways * 5 Skin (cursor and icon) * if number_of_seasons == 0 (no winter images) * 6-8 front images of image lists 2-4 * else * 6-8 winter images of image lists 2-4 * 9-11 front images of image lists 2-4 * 12-14 front winter images of image lists 2-4 */ class way_desc_t : public obj_desc_transport_infrastructure_t { friend class way_reader_t; private: /** * Max weight */ uint32 max_weight; /** * Way system type: i.e. for wtyp == track this * can be used to select track system type (tramlike=7, elevated=1, ignore=255) */ uint8 styp; /* true, if a tile with this way should be always drawn as a thing */ uint8 draw_as_obj; /* number of seasons (0 = none, 1 = no snow/snow */ sint8 number_of_seasons; /// if true front_images lists exists as nodes bool front_images; /** * calculates index of image list for flat ways * for winter and/or front images * add +1 and +2 to get slope and straight diagonal images, respectively */ uint16 image_list_base_index(bool snow, bool front) const { if (number_of_seasons == 0 || !snow) { if (front && front_images) { return (number_of_seasons == 0) ? 6 : 9; } else { return 2; } } else { // winter images if (front && front_images) { return 12; } else { return 6; } } } public: /** * @return waytype used in finance stats (needed to distinguish \ * between train track and tram track */ waytype_t get_finance_waytype() const; /** * returns the system type of this way (mostly used with rails) * @see systemtype_t */ systemtype_t get_styp() const { return (systemtype_t)styp; } bool is_tram() const { return wtyp == track_wt && styp == type_tram; } image_id get_image_id(ribi_t::ribi ribi, uint8 season, bool front = false) const { if (front && !front_images) { return IMG_EMPTY; } const uint16 n = image_list_base_index(season, front); return get_child(n)->get_image_id(ribi); } image_id get_switch_image_id(ribi_t::ribi ribi, uint8 season, bool nw, bool front = false) const { if (front && !front_images) { return IMG_EMPTY; } const uint16 n = image_list_base_index(season, front); image_list_t const* const imglist = get_child(n); // only do this if extended switches are there if( imglist->get_count()>16 ) { static uint8 ribi_to_extra[16] = { 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 1, 255, 2, 3, 4 }; return imglist->get_image_id( ribi_to_extra[ribi]+16+(nw*5) ); } // else return standard values return imglist->get_image_id( ribi ); } image_id get_slope_image_id(slope_t::type slope, uint8 season, bool front = false) const { if (front && !front_images) { return IMG_EMPTY; } const uint16 n = image_list_base_index(season, front) + 1; uint16 nr; switch(slope) { case slope_t::north: nr = 0; break; case slope_t::west: nr = 1; break; case slope_t::east: nr = 2; break; case slope_t::south: nr = 3; break; case slope_t::north*2: nr = 4; break; case slope_t::west*2: nr = 5; break; case slope_t::east*2: nr = 6; break; case slope_t::south*2: nr = 7; break; default: return IMG_EMPTY; } image_id slope_img = get_child(n)->get_image_id(nr); if( nr > 3 && slope_img == IMG_EMPTY && get_child(n)->get_count()<=4 ) { // hack for old ways without double height images to use single slope images for both nr -= 4; slope_img = get_child(n)->get_image_id(nr); } return slope_img; } image_id get_diagonal_image_id(ribi_t::ribi ribi, uint8 season, bool front = false) const { if (front && !front_images) { return IMG_EMPTY; } const uint16 n = image_list_base_index(season, front) + 2; return get_child(n)->get_image_id(ribi / 3 - 1); } bool has_double_slopes() const { return get_child(3)->get_count() > 4 || get_child(image_list_base_index(false, true) + 1)->get_count() > 4; } bool has_diagonal_image() const { return get_child(4)->get_image_id(0) != IMG_EMPTY || get_child(image_list_base_index(false, true)+2)->get_image_id(0) != IMG_EMPTY; } bool has_switch_image() const { return get_child(2)->get_count() > 16 || get_child(image_list_base_index(false, true))->get_count() > 16; } /* true, if this tile is to be drawn as a normal thing */ bool is_draw_as_obj() const { return draw_as_obj; } /** * Skin: cursor (index 0) and icon (index 1) */ const skin_desc_t * get_cursor() const { return get_child(5); } void calc_checksum(checksum_t *chk) const; }; #endif simutrans-124.3/src/simutrans/descriptor/way_obj_desc.h000066400000000000000000000100441474050137200233450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WAY_OBJ_DESC_H #define DESCRIPTOR_WAY_OBJ_DESC_H #include "image_list.h" #include "obj_base_desc.h" #include "skin_desc.h" #include "../dataobj/ribi.h" #include "../network/checksum.h" class tool_t; class checksum_t; /** * Way objects type description (like overhead lines). * * Child nodes: * 0 Name * 1 Copyright * 2 Image on flat ways * 3 Image on sloped ways * 4 Image on diagonal ways * 5 Skin (cursor and icon) */ class way_obj_desc_t : public obj_desc_transport_infrastructure_t { friend class way_obj_reader_t; private: /** * Type of the object, only overheadlines_wt is currently used. */ uint8 own_wtyp; public: bool is_overhead_line() const { return (waytype_t)own_wtyp == overheadlines_wt; } // way objects can have a front and a backimage, unlike ways ... image_id get_front_image_id(ribi_t::ribi ribi) const { return get_child(2)->get_image_id(ribi); } image_id get_crossing_image_id(ribi_t::ribi ribi, bool nw, bool front = false) const { if( front && !get_child(2)->get_count() ) { return IMG_EMPTY; } image_list_t const* const imglist = get_child(3-front); // only do this if extended switches are there if( imglist->get_count()>16 ) { static uint8 ribi_to_extra[16] = { 255, 255, 255, 255, 255, 255, 255, 0, 255, 255, 255, 1, 255, 2, 3, 4 }; return ribi < 16 ? imglist->get_image_id( ribi_to_extra[ribi]+16+(nw*5) ) : IMG_EMPTY; } // else return standard values return imglist->get_image_id( ribi ); } image_id get_back_image_id(ribi_t::ribi ribi) const { return get_child(3)->get_image_id(ribi); } image_id get_front_slope_image_id(slope_t::type slope) const { uint16 nr; switch(slope) { case 4: nr = 0; break; case 12: nr = 1; break; case 28: nr = 2; break; case 36: nr = 3; break; case 8: nr = 4; break; case 24: nr = 5; break; case 56: nr = 6; break; case 72: nr = 7; break; default: return IMG_EMPTY; } image_id slope_img = get_child(4)->get_image_id(nr); if( nr > 3 && slope_img == IMG_EMPTY ) { // hack for old ways without double height images to use single slope images for both nr -= 4; slope_img = get_child(4)->get_image_id(nr); } return slope_img; } image_id get_back_slope_image_id(slope_t::type slope) const { uint16 nr; switch(slope) { case 4: nr = 0; break; case 12: nr = 1; break; case 28: nr = 2; break; case 36: nr = 3; break; case 8: nr = 4; break; case 24: nr = 5; break; case 56: nr = 6; break; case 72: nr = 7; break; default: return IMG_EMPTY; } image_id slope_img = get_child(5)->get_image_id(nr); if( nr > 3 && slope_img == IMG_EMPTY ) { // hack for old ways without double height images to use single slope images for both nr -= 4; slope_img = get_child(5)->get_image_id(nr); } return slope_img; } image_id get_front_diagonal_image_id(ribi_t::ribi ribi) const { if(!ribi_t::is_bend(ribi)) { return IMG_EMPTY; } return get_child(6)->get_image_id(ribi / 3 - 1); } image_id get_back_diagonal_image_id(ribi_t::ribi ribi) const { if(!ribi_t::is_bend(ribi)) { return IMG_EMPTY; } return get_child(7)->get_image_id(ribi / 3 - 1); } bool has_diagonal_image() const { if (get_child(4)->get_image(0)) { // has diagonal fontimage return true; } if (get_child(5)->get_image(0)) { // or diagonal back image return true; } return false; } /** * Skin: cursor (index 0) and icon (index 1) */ skin_desc_t const* get_cursor() const { return get_child(8); } void calc_checksum(checksum_t *chk) const { obj_desc_transport_infrastructure_t::calc_checksum(chk); chk->input(own_wtyp); } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/000077500000000000000000000000001474050137200220615ustar00rootroot00000000000000simutrans-124.3/src/simutrans/descriptor/writer/bridge_writer.cc000066400000000000000000000115721474050137200252260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "obj_pak_exception.h" #include "../bridge_desc.h" #include "text_writer.h" #include "imagelist_writer.h" #include "skin_writer.h" #include "get_waytype.h" #include "bridge_writer.h" using std::string; void write_bridge_images(FILE* outfp, obj_node_t& node, tabfileobj_t& obj, int season) { slist_tpl backkeys; slist_tpl frontkeys; static const char* const names[] = { "image", "ns", "ew", NULL, "start", "n", "s", "e", "w", NULL, "ramp", "n", "s", "e", "w", NULL, "pillar", "s", "w", NULL, "image2", "ns", "ew", NULL, "start2", "n", "s", "e", "w", NULL, "ramp2", "n", "s", "e", "w", NULL, "pillar2", "s", "w", NULL, NULL }; const char* const * ptr = names; const char* keyname = *ptr++; char keybuf[40]; do { const char* keyindex = *ptr++; do { string value; if( season < 0 ) { sprintf( keybuf, "back%s[%s]", keyname, keyindex ); value = obj.get( keybuf ); backkeys.append( value ); //intf("BACK: %s -> %s\n", keybuf, value.chars()); sprintf( keybuf, "front%s[%s]", keyname, keyindex ); } else { sprintf( keybuf, "back%s[%s][%d]", keyname, keyindex, season ); value = obj.get( keybuf ); backkeys.append( value ); //intf("BACK: %s -> %s\n", keybuf, value.chars()); sprintf( keybuf, "front%s[%s][%d]", keyname, keyindex, season ); } // must append to front keys even if empty to keep order correct (but warn anyway) value = obj.get( keybuf ); frontkeys.append( value ); //intf("FRNT: %s -> %s\n", keybuf, value.chars()); if( value.size() <= 2 ) { dbg->warning( obj_writer_t::last_name, "No %s specified (might still work)", keybuf ); } keyindex = *ptr++; } while( keyindex ); keyname = *ptr++; } while( keyname ); imagelist_writer_t::instance()->write_obj( outfp, node, backkeys ); imagelist_writer_t::instance()->write_obj( outfp, node, frontkeys ); if( season <= 0 ) { slist_tpl cursorkeys; cursorkeys.append( string( obj.get("cursor") ) ); cursorkeys.append( string( obj.get("icon") ) ); cursorskin_writer_t::instance()->write_obj( outfp, node, obj, cursorkeys ); cursorkeys.clear(); } backkeys.clear(); frontkeys.clear(); } void bridge_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 24, &parent); uint8 wegtyp = get_waytype(obj.get("waytype")); uint16 topspeed = obj.get_int("topspeed", 999); uint32 price = obj.get_int("cost", 0); uint32 maintenance = obj.get_int("maintenance", 1000); uint8 pillars_every = obj.get_int("pillar_distance",0); // distance==0 is off uint8 pillar_asymmetric = obj.get_int("pillar_asymmetric",0); // middle of tile uint8 max_length = obj.get_int("max_lenght",0); // max_lenght==0: unlimited max_length = obj.get_int("max_length",max_length); // with correct spelling uint8 max_height = obj.get_int("max_height",0); // max_height==0: unlimited uint16 axle_load = obj.get_int("axle_load", 9999); // timeline uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro_date += obj.get_int("intro_month", 1) - 1; uint16 retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire_date += obj.get_int("retire_month", 1) - 1; sint8 number_of_seasons = 0; // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend uint16 version = 0x8009; node.write_uint16(outfp, version, 0); node.write_uint16(outfp, topspeed, 2); node.write_uint32(outfp, price, 4); node.write_uint32(outfp, maintenance, 8); node.write_uint8 (outfp, wegtyp, 12); node.write_uint8 (outfp, pillars_every, 13); node.write_uint8 (outfp, max_length, 14); node.write_uint16(outfp, intro_date, 15); node.write_uint16(outfp, retire_date, 17); node.write_uint8 (outfp, pillar_asymmetric, 19); node.write_uint16(outfp, axle_load, 20); node.write_uint8 (outfp, max_height, 22); char keybuf[40]; string str = obj.get("backimage[ns][0]"); if (str.empty()) { node.write_data_at(outfp, &number_of_seasons, 23, sizeof(uint8)); write_head(outfp, node, obj); write_bridge_images( outfp, node, obj, -1 ); } else { while(number_of_seasons < 2) { sprintf(keybuf, "backimage[ns][%d]", number_of_seasons+1); string str = obj.get(keybuf); if (!str.empty()) { number_of_seasons++; } else { break; } } node.write_data_at(outfp, &number_of_seasons, 23, sizeof(uint8)); write_head(outfp, node, obj); for(uint8 season = 0 ; season <= number_of_seasons ; season++) { write_bridge_images( outfp, node, obj, season ); } } // node.write_data(outfp, &desc); node.write(outfp); } simutrans-124.3/src/simutrans/descriptor/writer/bridge_writer.h000066400000000000000000000013671474050137200250710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_BRIDGE_WRITER_H #define DESCRIPTOR_WRITER_BRIDGE_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class bridge_writer_t : public obj_writer_t { private: static bridge_writer_t the_instance; bridge_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: /// Writes bridge node data to file void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_bridge; } const char* get_type_name() const OVERRIDE { return "bridge"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/building_writer.cc000066400000000000000000000277521474050137200255760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../utils/simstring.h" #include "../../dataobj/tabfile.h" #include "../building_desc.h" #include "obj_pak_exception.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist2d_writer.h" #include "get_waytype.h" #include "get_climate.h" #include "building_writer.h" #include "skin_writer.h" using std::string; void tile_writer_t::write_obj(FILE* fp, obj_node_t& parent, int index, int seasons, slist_tpl > >& backkeys, slist_tpl > >& frontkeys ) { obj_node_t node(this, 7, &parent); uint8 phases = 0; for (int i = 0; i < seasons; i++) { for(slist_tpl const& s : backkeys.at(i)) { if (phases < s.get_count()) { phases = s.get_count(); } } for(slist_tpl const& s : frontkeys.at(i)) { if (phases < s.get_count()) { phases = s.get_count(); } } } for (int i = 0; i < seasons; i++) { imagelist2d_writer_t::instance()->write_obj(fp, node, backkeys.at(i)); imagelist2d_writer_t::instance()->write_obj(fp, node, frontkeys.at(i)); } // write version data uint16 v16 = 0x8002; node.write_uint16(fp, v16, 0); v16 = phases; node.write_uint16(fp, v16, 2); v16 = index; node.write_uint16(fp, v16, 4); uint8 uv8 = seasons; node.write_uint8(fp, uv8, 6); node.write(fp); } // Subroutine for write_obj, to avoid duplicated code static uint32 get_cluster_data(tabfileobj_t& obj) { uint32 clusters = 0; vector_tpl ints = obj.get_ints("clusters"); for( uint32 i = 0; i < ints.get_count(); i++ ) { if( ints[i] >= 1 && ints[i] <= 32 ) { // Sanity check clusters |= 1<<(ints[i]-1); } } return clusters; } void building_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { // take care, hardcoded size of node on disc here! obj_node_t node(this, 39, &parent); write_head(fp, node, obj); koord size(1, 1); uint8 layouts = 0; vector_tpl ints = obj.get_ints("dims"); switch (ints.get_count()) { default: case 3: layouts = ints[2]; /* FALLTHROUGH */ case 2: size.y = ints[1]; /* FALLTHROUGH */ case 1: size.x = ints[0]; /* FALLTHROUGH */ case 0: break; } if (layouts == 0) { layouts = size.x == size.y ? 1 : 2; } if (size.x*size.y == 0) { dbg->fatal("building_writer_t::write_obj", "Cannot create a building with zero size (%i,%i)", size.x, size.y); } building_desc_t::btype type = building_desc_t::unknown; uint32 extra_data = 0; uint8 enables = 0; uint16 level = obj.get_int("level", 1) - 1; // get the allowed area for this building climate_bits allowed_climates = all_but_water_climate; // all but water const char* climate_str = obj.get("climates"); if (climate_str && strlen(climate_str) > 4) { allowed_climates = get_climate_bits(climate_str); } building_desc_t::flag_t const flags = (obj.get_int("noinfo", 0) > 0 ? building_desc_t::FLAG_NO_INFO : building_desc_t::FLAG_NULL) | (obj.get_int("noconstruction", 0) > 0 ? building_desc_t::FLAG_NO_PIT : building_desc_t::FLAG_NULL) | (obj.get_int("needs_ground", 0) > 0 ? building_desc_t::FLAG_NEED_GROUND : building_desc_t::FLAG_NULL); uint16 const animation_time = obj.get_int("animation_time", 300); const char* type_name = obj.get("type"); if (!STRICMP(type_name, "res")) { extra_data = get_cluster_data(obj); type = building_desc_t::city_res; } else if (!STRICMP(type_name, "com")) { extra_data = get_cluster_data(obj); type = building_desc_t::city_com; } else if (!STRICMP(type_name, "ind")) { extra_data = get_cluster_data(obj); type = building_desc_t::city_ind; } else if (!STRICMP(type_name, "cur")) { extra_data = obj.get_int("build_time", 0); level = obj.get_int("passengers", level); type = extra_data == 0 ? building_desc_t::attraction_land : building_desc_t::attraction_city; } else if (!STRICMP(type_name, "mon")) { type = building_desc_t::monument; level = obj.get_int("passengers", level); } else if (!STRICMP(type_name, "tow")) { level = obj.get_int("passengers", level); extra_data = obj.get_int("build_time", 0); type = building_desc_t::townhall; } else if (!STRICMP(type_name, "hq")) { level = obj.get_int("passengers", level); extra_data = obj.get_int("hq_level", 0); type = building_desc_t::headquarters; } else if (!STRICMP(type_name, "habour") || !STRICMP(type_name, "harbour")) { // buildable only on sloped shores type = building_desc_t::dock; extra_data = water_wt; } else if (!STRICMP(type_name, "dock")) { // buildable only on flat shores type = building_desc_t::flat_dock; extra_data = water_wt; } else if (!STRICMP(type_name, "fac")) { type = building_desc_t::factory; enables |= 4; } else if (!STRICMP(type_name, "stop")) { type = building_desc_t::generic_stop; extra_data = get_waytype(obj.get("waytype")); } else if (!STRICMP(type_name, "extension")) { type = building_desc_t::generic_extension; const char *wt = obj.get("waytype"); if(wt && *wt>' ') { // no waytype => just a generic extension that fits all extra_data = get_waytype(wt); } } else if (!STRICMP(type_name, "depot")) { type = building_desc_t::depot; extra_data = get_waytype(obj.get("waytype")); } else if (!STRICMP(type_name, "any") || *type_name == '\0') { // for instance "MonorailGround" type = building_desc_t::others; } else if ( !STRICMP(type_name, "station") || !STRICMP(type_name, "railstop") || !STRICMP(type_name, "monorailstop") || !STRICMP(type_name, "busstop") || !STRICMP(type_name, "carstop") || !STRICMP(type_name, "airport") || !STRICMP(type_name, "wharf") ) { dbg->fatal("building_writer_t::write_obj()","%s is obsolete type for %s; use stop/extension and waytype!", type_name, obj.get("name") ); } else if (!STRICMP(type_name, "hall") || !STRICMP(type_name, "post") || !STRICMP(type_name, "shed") ) { dbg->fatal("building_writer_t::write_obj()","%s is obsolete type for %s; use extension and waytype!", type_name, obj.get("name") ); } else { dbg->fatal( "building_writer_t::write_obj()","%s is obsolete type for %s", type_name, obj.get("name") ); } // is is an station extension building? if (obj.get_int("extension_building", 0) > 0) { dbg->fatal("building_writer_t::write_obj()","extension_building is obsolete keyword for %s; use stop/extension and waytype!", obj.get("name") ); } if (obj.get_int("enables_pax", 0) > 0) { enables |= 1; } if (obj.get_int("enables_post", 0) > 0) { enables |= 2; } if( type == building_desc_t::factory || obj.get_int("enables_ware", 0) > 0 ) { enables |= 4; } if( type == building_desc_t::generic_extension || type == building_desc_t::generic_stop || type == building_desc_t::dock || type == building_desc_t::depot || type == building_desc_t::factory ) { // since level was reduced by one beforehand ... ++level; } // read chance - default is 100% chance to be built uint8 const chance = obj.get_int("chance", 100); // timeline for buildings uint16 const intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12 + obj.get_int("intro_month", 1) - 1; uint16 const retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12 + obj.get_int("retire_month", 1) - 1; uint16 const preservation_date = obj.get_int("preservation_year", DEFAULT_RETIRE_DATE) * 12 + obj.get_int("preservation_month", 1) - 1; // capacity and price information. // Stands in place of the "level" setting, but uses "level" data by default. //NOTE: Default for maintenance and price must be set when loading so use magic default here //also check for "station_xx" for experimental compatibility sint32 capacity = obj.get_int("capacity", level * 32); if( capacity == level * 32 ) { capacity = obj.get_int("station_capacity", level * 32); } sint32 maintenance = obj.get_int("maintenance", PRICE_MAGIC); if( maintenance == PRICE_MAGIC ) { maintenance = obj.get_int("station_maintenance", PRICE_MAGIC); } sint32 price = obj.get_int("cost", PRICE_MAGIC); if( price == PRICE_MAGIC ) { price = obj.get_int("station_price", PRICE_MAGIC); } uint8 allow_underground = obj.get_int("allow_underground", 2); if(allow_underground > 2) { // Prohibit illegal values here. allow_underground = 2; } // scan for most number of seasons int seasons = 1; for (int l = 0; l < layouts; l++) { // each layout int const h = l & 1 ? size.x : size.y; int const w = l & 1 ? size.y : size.x; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { // each tile for (int pos = 0; pos < 2; pos++) { for (int season = seasons; season < 12; season++) { char buf[40]; sprintf(buf, "%simage[%d][%d][%d][%d][%d][%d]", pos ? "back" : "front", l, y, x, 0, 0, season); string str = obj.get(buf); if (str.size() != 0) { seasons = season + 1; } else { break; } } } } } } int tile_index = 0; for (int l = 0; l < layouts; l++) { // each layout int const h = l & 1 ? size.x : size.y; int const w = l & 1 ? size.y : size.x; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { // each tile slist_tpl > > backkeys; slist_tpl > > frontkeys; for (int season = 0; season < seasons; season++) { backkeys.append(); frontkeys.append(); for (int pos = 0; pos < 2; pos++) { slist_tpl > >& keys = pos ? backkeys : frontkeys; for (unsigned int h = 0; ; h++) { // each height for (int phase = 0; ; phase++) { // each animation char buf[40]; sprintf(buf, "%simage[%d][%d][%d][%d][%d][%d]", pos ? "back" : "front", l, y, x, h, phase, season); string str = obj.get(buf); // if no string check to see whether using format without seasons parameter if (str.empty() && seasons == 1) { sprintf(buf, "%simage[%d][%d][%d][%d][%d]", pos ? "back" : "front", l, y, x, h, phase); str = obj.get(buf); } if (str.empty()) { #if 0 printf("Not found: %s\n", buf); fflush(NULL); #endif break; } else { // no higher front images if (h > 0 && pos == 0) { dbg->error( obj_writer_t::last_name, "Frontimage height MUST be one tile only!"); break; } } if (phase == 0) { keys.at(season).append(); } keys.at(season).at(h).append(str); } if (keys.at(season).get_count() <= h) { break; } } } } tile_writer_t::instance()->write_obj(fp, node, tile_index++, seasons, backkeys, frontkeys); } } } // write version data node.write_uint16(fp, 0x800A, 0); // write desc data node.write_uint8 (fp, 0, 2); // was gtyp node.write_uint8 (fp, type, 3); node.write_uint16(fp, level, 4); node.write_uint32(fp, extra_data, 6); node.write_uint16(fp, size.x, 10); node.write_uint16(fp, size.y, 12); node.write_uint8 (fp, layouts, 14); node.write_uint16(fp, allowed_climates, 15); node.write_uint8 (fp, enables, 17); node.write_uint8 (fp, flags, 18); node.write_uint8 (fp, chance, 19); node.write_uint16(fp, intro_date, 20); node.write_uint16(fp, retire_date, 22); node.write_uint16(fp, animation_time, 24); node.write_uint16(fp, capacity, 26); node.write_sint32(fp, maintenance, 28); node.write_sint32(fp, price, 32); node.write_uint8 (fp, allow_underground,36); node.write_uint16(fp, preservation_date,37); // probably add some icons, if defined slist_tpl cursorkeys; string c = string(obj.get("cursor")); string i = string(obj.get("icon")); cursorkeys.append(c); cursorkeys.append(i); if (!c.empty() || !i.empty()) { cursorskin_writer_t::instance()->write_obj(fp, node, obj, cursorkeys); } node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/building_writer.h000066400000000000000000000025411474050137200254250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_BUILDING_WRITER_H #define DESCRIPTOR_WRITER_BUILDING_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" template class slist_tpl; class tile_writer_t : public obj_writer_t { private: static tile_writer_t the_instance; tile_writer_t() { register_writer(false); } public: static tile_writer_t *instance() { return &the_instance; } virtual void write_obj(FILE* fp, obj_node_t &parent, int index, int seasons, slist_tpl > >& backkeys, slist_tpl > >& frontkeys ); protected: obj_type get_type() const OVERRIDE { return obj_tile; } const char *get_type_name() const OVERRIDE { return "tile"; } }; class building_writer_t : public obj_writer_t { private: static building_writer_t the_instance; building_writer_t() { register_writer(true); } public: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } static building_writer_t* instance() { return &the_instance; } virtual void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_building; } const char* get_type_name() const OVERRIDE { return "building"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/citycar_writer.cc000066400000000000000000000026151474050137200254260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist_writer.h" #include "citycar_writer.h" void citycar_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { int i; obj_node_t node(this, 10, &parent); uint16 const dist_weight = obj.get_int("distributionweight", 1); uint16 const intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12 + obj.get_int("intro_month", 1) - 1; uint16 const retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12 + obj.get_int("retire_month", 1) - 1; uint16 const topspeed = obj.get_int("speed", 80) * 16; // new version with intro and obsolete dates node.write_uint16(fp, 0x8002, 0); // version information node.write_uint16(fp, dist_weight, 2); node.write_uint16(fp, topspeed, 4); node.write_uint16(fp, intro_date, 6); node.write_uint16(fp, retire_date, 8); write_head(fp, node, obj); static const char* const dir_codes[] = { "s", "w", "sw", "se", "n", "e", "ne", "nw" }; slist_tpl keys; std::string str; for (i = 0; i < 8; i++) { char buf[40]; sprintf(buf, "image[%s]", dir_codes[i]); str = obj.get(buf); keys.append(str); } imagelist_writer_t::instance()->write_obj(fp, node, keys); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/citycar_writer.h000066400000000000000000000014231474050137200252640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_CITYCAR_WRITER_H #define DESCRIPTOR_WRITER_CITYCAR_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" /** * Description of the automatically generated cars */ class citycar_writer_t : public obj_writer_t { private: static citycar_writer_t the_instance; citycar_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_citycar; } const char* get_type_name() const OVERRIDE { return "citycar"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/crossing_writer.cc000066400000000000000000000114211474050137200256120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../../utils/simstring.h" #include "../../dataobj/tabfile.h" #include "../sound_desc.h" #include "obj_node.h" #include "obj_pak_exception.h" #include "text_writer.h" #include "image_writer.h" #include "get_waytype.h" #include "imagelist_writer.h" #include "crossing_writer.h" #include "xref_writer.h" using std::string; static void make_list(tabfileobj_t &obj, slist_tpl& list, char const* const key) { for (int i = 0;; ++i) { char buf[40]; sprintf(buf, "%s[%i]", key, i); string str(obj.get(buf)); if (str.empty()) { break; } // We have this direction list.append(str); } } static void write_list(FILE* const fp, obj_node_t& node, slist_tpl const& list) { if (list.empty()) { xref_writer_t::instance()->write_obj(fp, node, obj_imagelist, "", false); } else { imagelist_writer_t::instance()->write_obj(fp, node, list); } } void crossing_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { int total_len = 21; // must be done here, since it may affect the len of the header! string sound_str = ltrim( obj.get("sound") ); sint8 sound_id=NO_SOUND; if (!sound_str.empty()) { // ok, there is some sound sound_id = atoi(sound_str.c_str()); if (sound_id == 0 && sound_str[0] == '0') { sound_id = 0; sound_str = ""; } else if (sound_id != 0) { // old style id sound_str = ""; } if (!sound_str.empty()) { sound_id = LOAD_SOUND; total_len += sound_str.size() + 1; } } // ok, node can be allocated now obj_node_t node(this, total_len, &parent); write_head(fp, node, obj); // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend uint16 uv16 = 0x8002; node.write_uint16(fp, uv16, 0); // waytypes, waytype 2 will be on top uint8 waytype1 = get_waytype(obj.get("waytype[0]")); uint8 waytype2 = get_waytype(obj.get("waytype[1]")); if(waytype1==waytype2) { dbg->fatal( "Crossing", "Identical ways (%s) cannot cross (check waytypes)!", obj.get("waytype[0]") ); } node.write_uint8(fp, waytype1, 2); node.write_uint8(fp, waytype2, 3); // Top speed of this way uv16 = obj.get_int("speed[0]", 0); if(uv16==0) { dbg->fatal( "Crossing", "A maxspeed MUST be given for both ways!"); } node.write_uint16(fp, uv16, 4); uv16 = obj.get_int("speed[1]", 0); if(uv16==0) { dbg->fatal( "Crossing", "A maxspeed MUST be given for both ways!"); } node.write_uint16(fp, uv16, 6); // time between frames for animation uint32 uv32 = obj.get_int("animation_time_open", 0); node.write_uint32(fp, uv32, 8); uv32 = obj.get_int("animation_time_closed", 0); node.write_uint32(fp, uv32, 12); node.write_uint8(fp, sound_id, 16); uint8 index = 17; if (!sound_str.empty()) { sint8 sv8 = sound_str.size(); node.write_data_at(fp, &sv8, 17, sizeof(sint8)); node.write_data_at(fp, sound_str.c_str(), 18, sound_str.size()); index += 1 + sound_str.size(); } uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro_date += obj.get_int("intro_month", 1) - 1; uint16 retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire_date += obj.get_int("retire_month", 1) - 1; node.write_uint16(fp, intro_date, index); index += 2; node.write_uint16(fp, retire_date, index); index += 2; // now the image stuff slist_tpl openkeys_ns; slist_tpl openkeys_ew; slist_tpl front_openkeys_ns; slist_tpl front_openkeys_ew; slist_tpl closekeys_ns; slist_tpl closekeys_ew; slist_tpl front_closekeys_ns; slist_tpl front_closekeys_ew; // open crossings ... make_list(obj, openkeys_ns, "openimage[ns]"); make_list(obj, openkeys_ew, "openimage[ew]"); // these must exists! if (openkeys_ns.empty() || openkeys_ew.empty()) { dbg->fatal( "Crossing", "Missing images (at least one openimage! (but %i and %i found)!)", openkeys_ns.get_count(), openkeys_ew.get_count() ); } write_list(fp, node, openkeys_ns); write_list(fp, node, openkeys_ew); // foreground make_list(obj, front_openkeys_ns, "front_openimage[ns]"); make_list(obj, front_openkeys_ew, "front_openimage[ew]"); // the following lists are optional write_list(fp, node, front_openkeys_ns); write_list(fp, node, front_openkeys_ew); // closed crossings ... make_list(obj, closekeys_ns, "closedimage[ns]"); make_list(obj, closekeys_ew, "closedimage[ew]"); write_list(fp, node, closekeys_ns); write_list(fp, node, closekeys_ew); // foreground make_list(obj, front_closekeys_ns, "front_closedimage[ns]"); make_list(obj, front_closekeys_ew, "front_closedimage[ew]"); write_list(fp, node, front_closekeys_ns); write_list(fp, node, front_closekeys_ew); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/crossing_writer.h000066400000000000000000000013371474050137200254610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_CROSSING_WRITER_H #define DESCRIPTOR_WRITER_CROSSING_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class crossing_writer_t : public obj_writer_t { private: static crossing_writer_t the_instance; crossing_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE *fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE *fp, obj_node_t &parent, tabfileobj_t &obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_crossing; } const char *get_type_name() const OVERRIDE { return "crossing"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/factory_writer.cc000066400000000000000000000306131474050137200254360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../utils/simstring.h" #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "../skin_desc.h" #include "../factory_desc.h" #include "../sound_desc.h" #include "text_writer.h" #include "building_writer.h" #include "factory_writer.h" #include "xref_writer.h" using std::string; void factory_field_class_writer_t::write_obj(FILE* outfp, obj_node_t& parent, const char* field_name, int snow_image, int production, int capacity, int weight) { obj_node_t node(this, 9, &parent); xref_writer_t::instance()->write_obj(outfp, node, obj_field, field_name, true); // data specific to each field class node.write_uint16(outfp, 0x8001, 0); // version node.write_uint8 (outfp, snow_image, 2); node.write_uint16(outfp, production, 3); node.write_uint16(outfp, capacity, 5); node.write_uint16(outfp, weight, 7); node.write(outfp); } void factory_field_group_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 12, &parent); uint16 field_classes; if( *obj.get("fields") ) { // format with no square-bracketed subscripts field_classes = 1; const char *field_name = obj.get("fields"); int snow_image = obj.get_int("has_snow", 1); int production = obj.get_int("production_per_field", 16); int capacity = obj.get_int("storage_capacity", 0); // default is 0 to avoid breaking the balance of existing pakset objects int weight = obj.get_int("spawn_weight", 1000); factory_field_class_writer_t::instance()->write_obj(outfp, node, field_name, snow_image, production, capacity, weight); } else { // for each field class, retrieve its data and write a field class node for (field_classes = 0;; ++field_classes) { char buf[64]; sprintf(buf, "fields[%d]", field_classes); const char *field_name = obj.get(buf); if( !field_name || !*field_name ) { break; } sprintf(buf, "has_snow[%d]", field_classes); int snow_image = obj.get_int(buf, 1); sprintf(buf, "production_per_field[%d]", field_classes); int production = obj.get_int(buf, 16); sprintf(buf, "storage_capacity[%d]", field_classes); int capacity = obj.get_int(buf, 0); // default is 0 to avoid breaking the balance of existing pakset objects sprintf(buf, "spawn_weight[%d]", field_classes); int weight = obj.get_int(buf, 1000); factory_field_class_writer_t::instance()->write_obj(outfp, node, field_name, snow_image, production, capacity, weight); } } // common, shared field data uint16 probability = obj.get_int("probability_to_spawn", 10); // 0,1 % uint16 const max_fields = obj.get_int("max_fields", 25); uint16 const min_fields = obj.get_int("min_fields", 5); uint16 const start_fields = obj.get_int("start_fields", 5); if (probability >= 10000) { printf("probability_to_spawn too large, set to 10,000\n"); probability = 10000; } node.write_uint16(outfp, 0x8003, 0); // version node.write_uint16(outfp, probability, 2); node.write_uint16(outfp, max_fields, 4); node.write_uint16(outfp, min_fields, 6); node.write_uint16(outfp, start_fields, 8); node.write_uint16(outfp, field_classes, 10); node.write(outfp); } void factory_smoke_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 10, &parent); xref_writer_t::instance()->write_obj(outfp, node, obj_smoke, obj.get("smoke"), true); koord const pos_off = obj.get_koord("smoketile", koord(0, 0)); koord const xy_off = obj.get_koord("smokeoffset", koord(0, 0)); sint16 const smokespeed = 0; /* was obj.get_int("smokespeed", 0); */ node.write_sint16(outfp, pos_off.x, 0); node.write_sint16(outfp, pos_off.y, 2); node.write_sint16(outfp, xy_off.x, 4); node.write_sint16(outfp, xy_off.y, 6); node.write_sint16(outfp, smokespeed, 8); node.write(outfp); } void factory_product_writer_t::write_obj(FILE* outfp, obj_node_t& parent, int capacity, int factor, const char* warename) { obj_node_t node(this, sizeof(uint16) * 3, &parent); xref_writer_t::instance()->write_obj(outfp, node, obj_good, warename, true); // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversioned // new version 2: pax-level added node.write_uint16(outfp, 0x8001, 0); node.write_uint16(outfp, capacity, 2); node.write_uint16(outfp, factor, 4); node.write(outfp); } void factory_supplier_writer_t::write_obj(FILE* outfp, obj_node_t& parent, int capacity, int count, int consumption, const char* warename) { obj_node_t node(this, 8, &parent); xref_writer_t::instance()->write_obj(outfp, node, obj_good, warename, true); node.write_uint16(outfp, capacity, 0); node.write_uint16(outfp, count, 2); node.write_uint16(outfp, consumption, 4); node.write_uint16(outfp, 0, 6); //dummy, unused (and uninitialized in past versions) node.write(outfp); } void factory_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { char const* const placing = obj.get("location"); factory_desc_t::site_t const placement = !STRICMP(placing, "land") ? factory_desc_t::Land : !STRICMP(placing, "water") ? factory_desc_t::Water : !STRICMP(placing, "city") ? factory_desc_t::City : !STRICMP(placing, "river") ? factory_desc_t::river : !STRICMP(placing, "shore") ? factory_desc_t::shore : !STRICMP(placing, "forest")? factory_desc_t::forest : factory_desc_t::Land; uint16 const productivity = obj.get_int("productivity", 10); uint16 const range = obj.get_int("range", 10); uint16 const chance = obj.get_int("distributionweight", 1); uint8 const color = obj.get_color("mapcolor", 255); if (color == 255) { dbg->fatal( "Factory", "%s missing an identification color! (mapcolor)", obj_writer_t::last_name ); } uint16 const pax_level = obj.get_int("pax_level", 12); uint16 expand_probability = obj.get_int("expand_probability", 0); if (expand_probability >= 10000) { printf("expand_probability too large, set to 10,000\n"); expand_probability = 10000; } uint16 const expand_minimum = obj.get_int("expand_minimum", 0); uint16 const expand_range = obj.get_int("expand_range", 0); uint16 const expand_times = obj.get_int("expand_times", 0); uint16 const electric_boost = (obj.get_int("electricity_boost", 1000) * 256 + 500) / 1000; uint16 const pax_boost = (obj.get_int("passenger_boost", 0) * 256 + 500) / 1000; uint16 const mail_boost = (obj.get_int("mail_boost", 0) * 256 + 500) / 1000; uint16 electric_demand = obj.get_int("electricity_amount", 65535); electric_demand = obj.get_int("electricity_demand", electric_demand); uint16 const pax_demand = obj.get_int("passenger_demand", 65535); uint16 const mail_demand = obj.get_int("mail_demand", 65535); // how long between sounds uint32 const sound_interval = obj.get_int("sound_interval", 0xFFFFFFFFul ); uint16 total_len = 80; // must be done here, since it may affect the len of the header! string sound_str = ltrim( obj.get("sound") ); sint8 sound_id=NO_SOUND; if (!sound_str.empty()) { // ok, there is some sound sound_id = atoi(sound_str.c_str()); if (sound_id == 0 && sound_str[0] == '0') { sound_id = 0; sound_str = ""; } else if (sound_id != 0) { // old style id sound_str = ""; } if (!sound_str.empty()) { sound_id = LOAD_SOUND; total_len += sound_str.size() + 1; } } obj_node_t node(this, total_len, &parent); obj.put("type", "fac"); // name/copyright is in building - write_head(fp, node, obj); building_writer_t::instance()->write_obj(fp, node, obj); if (*obj.get("smoke")) { factory_smoke_writer_t::instance()->write_obj(fp, node, obj); } else { xref_writer_t::instance()->write_obj(fp, node, obj_smoke, "", false); } uint16 supplier_count; for (supplier_count = 0;; ++supplier_count) { char buf[40]; sprintf(buf, "inputgood[%d]", supplier_count); const char* good = obj.get(buf); if (!good || !*good) { break; } sprintf(buf, "inputsupplier[%d]", supplier_count); int supp = obj.get_int(buf, 0); sprintf(buf, "inputcapacity[%d]", supplier_count); int cap = obj.get_int(buf, 0); sprintf(buf, "inputfactor[%d]", supplier_count); int consumption = (obj.get_int(buf, 100) * 256) / 100; factory_supplier_writer_t::instance()->write_obj(fp, node, cap, supp, consumption, good); } uint16 product_count; for (product_count = 0;; ++product_count) { char buf[40]; sprintf(buf, "outputgood[%d]", product_count); const char* good = obj.get(buf); if (!good || !*good) { break; } sprintf(buf, "outputcapacity[%d]", product_count); int cap = obj.get_int(buf, 0); if( cap<11 ) { dbg->error( "factory_writer_t::write_obj()", "Factory outputcapacity must be larger than 10! (currently %i)", cap ); } sprintf(buf, "outputfactor[%d]", product_count); int fac = (obj.get_int(buf, 100) * 256) / 100; factory_product_writer_t::instance()->write_obj(fp, node, cap, fac, good); } // fields (careful, are xref'ed) uint8 fields = 0; if( *obj.get("fields") || *obj.get("fields[0]") ) { // at least one field class available fields = 1; factory_field_group_writer_t::instance()->write_obj(fp, node, obj); } // now used here instead with the smoke koord pos_off[ 4 ]; koord xy_off[ 4 ]; uint8 num_smoke_offsets = 0; sint16 const smokeuplift = obj.get_int("smokeuplift", DEFAULT_SMOKE_UPLIFT ); sint16 const smokelifetime = obj.get_int("smokelifetime", DEFAULT_FACTORYSMOKE_TIME ); char str_smoketile[] = "smoketile[0]"; char str_smokeoffset[] = "smokeoffset[0]"; if( *obj.get( str_smoketile ) ) { for( int i = 0; i < 4; i++ ) { str_smoketile[10] = '0' + i; str_smokeoffset[12] = '0' + i; if( !*obj.get( str_smoketile ) ) { break; } pos_off[ i ] = obj.get_koord( str_smoketile, koord( 0, 0 ) ); if( !*obj.get( str_smokeoffset ) ) { dbg->error( "factory_writer_t::write_obj", "%s defined but not %s!", str_smoketile, str_smokeoffset ); } xy_off[ i ] = obj.get_koord( str_smokeoffset, koord( 0, 0 ) ); num_smoke_offsets++; } } else { pos_off[0] = obj.get_koord( "smoketile", koord( 0, 0 ) ); xy_off[0] = obj.get_koord( "smokeoffset", koord( 0, 0 ) ); } // new version with pax_level, and smoke offsets part of factory node.write_uint16(fp, 0x8005, 0); // version node.write_uint16(fp, placement, 2); node.write_uint16(fp, productivity, 4); node.write_uint16(fp, range, 6); node.write_uint16(fp, chance, 8); node.write_uint8 (fp, color, 10); node.write_uint8 (fp, fields, 11); node.write_uint16(fp, supplier_count, 12); node.write_uint16(fp, product_count, 14); node.write_uint16(fp, pax_level, 16); node.write_uint16(fp, expand_probability, 18); node.write_uint16(fp, expand_minimum, 20); node.write_uint16(fp, expand_range, 22); node.write_uint16(fp, expand_times, 24); node.write_uint16(fp, electric_boost, 26); node.write_uint16(fp, pax_boost, 28); node.write_uint16(fp, mail_boost, 30); node.write_uint16(fp, electric_demand, 32); node.write_uint16(fp, pax_demand, 34); node.write_uint16(fp, mail_demand, 36); node.write_uint32(fp, sound_interval, 38); node.write_uint8 (fp, sound_id, 42); node.write_uint8 (fp, num_smoke_offsets, 43); for( int i = 0; i < 4; i++ ) { node.write_sint16( fp, pos_off[i].x, 44+i*8 ); node.write_sint16( fp, pos_off[i].y, 46+i*8 ); node.write_sint16( fp, xy_off[i].x, 48+i*8 ); node.write_sint16( fp, xy_off[i].y, 50+i*8 ); } node.write_sint16(fp, smokeuplift, 76); node.write_sint16(fp, smokelifetime, 78); // this should be always at the end sint8 sound_str_len = sound_str.size(); if (sound_str_len > 0) { node.write_sint8 (fp, sound_str_len, 80); node.write_data_at(fp, sound_str.c_str(), 81, sound_str_len); } node.write(fp); } std::string factory_writer_t::get_node_name(FILE* fp) const { obj_node_info_t node; // Name is inside building (BUIL) node, which is a child of factory (FACT) node fread(&node, sizeof(node), 1, fp); if (node.type != obj_building) return ""; // If BUIL node not found, return blank to at least not crash fseek(fp, node.size, SEEK_CUR); return building_writer_t::instance()->get_node_name(fp); } simutrans-124.3/src/simutrans/descriptor/writer/factory_writer.h000066400000000000000000000062021474050137200252750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_FACTORY_WRITER_H #define DESCRIPTOR_WRITER_FACTORY_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" // new writer class for field class desc class factory_field_class_writer_t : public obj_writer_t { private: static factory_field_class_writer_t the_instance; factory_field_class_writer_t() { register_writer(false); } public: static factory_field_class_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_ffldclass; } const char* get_type_name() const OVERRIDE { return "factory field class"; } void write_obj(FILE* fp, obj_node_t& parent, const char* field_name, int snow_image, int production, int capacity, int weight); }; class factory_field_group_writer_t : public obj_writer_t { private: static factory_field_group_writer_t the_instance; factory_field_group_writer_t() { register_writer(false); } public: static factory_field_group_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_ffield; } const char *get_type_name() const OVERRIDE { return "factory field"; } void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; }; class factory_smoke_writer_t : public obj_writer_t { private: static factory_smoke_writer_t the_instance; factory_smoke_writer_t() { register_writer(false); } public: static factory_smoke_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_fsmoke; } const char *get_type_name() const OVERRIDE { return "factory smoke"; } void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; }; class factory_product_writer_t : public obj_writer_t { private: static factory_product_writer_t the_instance; factory_product_writer_t() { register_writer(false); } public: static factory_product_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_fproduct; } const char* get_type_name() const OVERRIDE { return "factory product"; } void write_obj(FILE* outfp, obj_node_t& parent, int capacity, int factor, const char* warename); }; class factory_supplier_writer_t : public obj_writer_t { private: static factory_supplier_writer_t the_instance; factory_supplier_writer_t() { register_writer(false); } public: static factory_supplier_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_fsupplier; } const char* get_type_name() const OVERRIDE { return "factory supplier"; } void write_obj(FILE* outfp, obj_node_t& parent, int capacity, int count, int consumption, const char* warename); }; class factory_writer_t : public obj_writer_t { private: static factory_writer_t the_instance; factory_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE; public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_factory; } const char* get_type_name() const OVERRIDE { return "factory"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/get_climate.cc000066400000000000000000000021361474050137200246470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simtypes.h" #include #include "../../utils/simstring.h" // for STRICMP #include "../ground_desc.h" #include "../../dataobj/tabfile.h" // the water and seven climates static const char* const climate_names[MAX_CLIMATES] = { "water", "desert", "tropic", "mediterran", "temperate", "tundra", "rocky", "arctic" }; /** * Convert climates string to bitfield */ climate_bits get_climate_bits(const char* climate_str) { uint16 uv16 = 0; uint16 i; const char* c = climate_str; do { while (*c == ' ' || *c == ',') { c++; } char end[256]; // skip the rest for (i = 0; i < 255 && *c > ' ' && *c != ','; i++, c++) { end[i] = *c; } end[i] = 0; // search for the string for (int i = 0; i < MAX_CLIMATES; i++) { if (STRICMP(end, climate_names[i]) == 0) { uv16 |= 1 << i; break; } } // allow "sea" as synonym for water if( uv16 == 0 && STRICMP(end,"sea") == 0) { uv16 |= 1; } } while (*c > 0 && *c != '#'); return (climate_bits)uv16; } simutrans-124.3/src/simutrans/descriptor/writer/get_climate.h000066400000000000000000000005071474050137200245110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_GET_CLIMATE_H #define DESCRIPTOR_WRITER_GET_CLIMATE_H #include "../../simtypes.h" /** * Convert climates string to bitfield */ climate_bits get_climate_bits(const char* climate_str); #endif simutrans-124.3/src/simutrans/descriptor/writer/get_waytype.cc000066400000000000000000000024321474050137200247320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../utils/simstring.h" // for STRICMP #include "../../dataobj/tabfile.h" /** * Convert waytype string to enum waytype_t */ waytype_t get_waytype(const char* waytype) { waytype_t uv8 = road_wt; if (!STRICMP(waytype, "none")) { uv8 = ignore_wt; } else if (!STRICMP(waytype, "road")) { uv8 = road_wt; } else if (!STRICMP(waytype, "track")) { uv8 = track_wt; } else if (!STRICMP(waytype, "electrified_track")) { uv8 = overheadlines_wt; } else if (!STRICMP(waytype, "maglev_track")) { uv8 = maglev_wt; } else if (!STRICMP(waytype, "monorail_track")) { uv8 = monorail_wt; } else if (!STRICMP(waytype, "narrowgauge_track")) { uv8 = narrowgauge_wt; } else if (!STRICMP(waytype, "water")) { uv8 = water_wt; } else if (!STRICMP(waytype, "air")) { uv8 = air_wt; } else if (!STRICMP(waytype, "schiene_tram")) { uv8 = tram_wt; } else if (!STRICMP(waytype, "tram_track")) { uv8 = tram_wt; } else if (!STRICMP(waytype, "power")) { uv8 = powerline_wt; } else if (!STRICMP(waytype, "decoration")) { uv8 = decoration_wt; } else { dbg->fatal("get_waytype()","invalid waytype \"%s\"\n", waytype); } return uv8; } simutrans-124.3/src/simutrans/descriptor/writer/get_waytype.h000066400000000000000000000005001474050137200245660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_GET_WAYTYPE_H #define DESCRIPTOR_WRITER_GET_WAYTYPE_H #include "../../simtypes.h" /** * Convert waytype string to enum waytype_t */ waytype_t get_waytype(char const* waytype); #endif simutrans-124.3/src/simutrans/descriptor/writer/good_writer.cc000066400000000000000000000020041474050137200247100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../dataobj/tabfile.h" #include "../goods_desc.h" #include "obj_node.h" #include "text_writer.h" #include "good_writer.h" void goods_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 10, &parent); write_head(fp, node, obj); text_writer_t::instance()->write_obj(fp, node, obj.get("metric")); uint16 value; uint8 val8; // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversioned node.write_uint16(fp, 0x8003, 0); value = obj.get_int("value", 0); node.write_uint16(fp, value, 2); val8 = obj.get_int("catg", 0); node.write_uint8 (fp, val8, 4); value = obj.get_int("speed_bonus", 0); node.write_uint16(fp, value, 5); value = obj.get_int("weight_per_unit", 100); node.write_uint16(fp, value, 7); val8 = obj.get_int("mapcolor", 255); node.write_uint8 (fp, val8, 9); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/good_writer.h000066400000000000000000000013531474050137200245600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_GOOD_WRITER_H #define DESCRIPTOR_WRITER_GOOD_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class goods_writer_t : public obj_writer_t { private: static goods_writer_t the_instance; goods_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: /// Writes goods node data to file void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_good; } const char *get_type_name() const OVERRIDE { return "good"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/ground_writer.cc000066400000000000000000000016351474050137200252670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "../ground_desc.h" #include "text_writer.h" #include "imagelist2d_writer.h" #include "ground_writer.h" void ground_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 0, &parent); write_head(fp, node, obj); slist_tpl > keys; // summer images for (int slope = 0; slope < 128; slope++) { keys.append(); for (int phase = 0; ; phase++) { char buf[40]; sprintf(buf, "image[%d][%d]", slope, phase); std::string str = obj.get(buf); if (str.empty()) { break; } keys.at(slope).append(str); } // empty entries? if (keys.at(slope).empty()) { break; } } imagelist2d_writer_t::instance()->write_obj(fp, node, keys); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/ground_writer.h000066400000000000000000000013211474050137200251210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_GROUND_WRITER_H #define DESCRIPTOR_WRITER_GROUND_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class ground_writer_t : public obj_writer_t { private: static ground_writer_t the_instance; ground_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_ground; } const char *get_type_name() const OVERRIDE { return "ground"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/groundobj_writer.cc000066400000000000000000000065361474050137200257670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist2d_writer.h" #include "get_climate.h" #include "get_waytype.h" #include "groundobj_writer.h" using std::string; void groundobj_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 16, &parent); write_head(fp, node, obj); climate_bits allowed_climates; const char *climate_str = obj.get("climates"); if (climate_str) { allowed_climates = get_climate_bits(climate_str); } else { dbg->warning( obj_writer_t::last_name, "No climates (using default)!"); allowed_climates = all_but_arctic_climate; } // seasons = 1: no seasons // otherwise the year will be divided by the (number_of_seasons-1) // The last image is always the snow image! uint8 const number_of_seasons = obj.get_int("seasons", 1); // distribution probability for all of this set uint16 const distribution_weight = obj.get_int("distributionweight", 3); // how much for removal sint32 const price = obj.get_int("cost", 0); // !=0 for moving objects (sheeps, birds) uint16 const speed = obj.get_int("speed", 0); // 1 for to allow trees on this objects bool const trees_on_top = obj.get_int("trees_on_top", 1) != 0; // waytype for moving stuff; meaningful air for birds, water for fish, does not matter for everything else char const* const waytype_txt = obj.get("waytype"); waytype_t const waytype = waytype_txt && waytype_txt[0] != '\0' ? get_waytype(waytype_txt) : ignore_wt; // now for the images slist_tpl > keys; if (speed == 0) { // fixed stuff for (unsigned int phase = 0; 1; phase++) { keys.append(); for (int seasons = 0; seasons < number_of_seasons; seasons++) { char buf[40]; // Images of the tree // age is 1..5 (usually five stages, seasons is the seasons sprintf(buf, "image[%d][%d]", phase, seasons); string str = obj.get(buf); if (str.empty()) { if(seasons==0) { goto finish_images; } else { dbg->fatal("groundobj_writer_t","Season image for season %i missing!",seasons); } } keys.at(phase).append(str); } } } else { // moving stuff const char* const dir_codes[] = { "s", "w", "sw", "se", "n", "e", "ne", "nw" }; for (unsigned int dir = 0; dir<8; dir++) { keys.append(); for (int seasons = 0; seasons < number_of_seasons; seasons++) { char buf[40]; // Images of the tree // age is 1..5 (usually five stages, seasons is the seasons sprintf(buf, "image[%s][%d]", dir_codes[dir], seasons); string str = obj.get(buf); if( str.empty() ) { dbg->fatal("groundobj_writer_t","Season image for season %i missing (expected %s)!", seasons, buf ); } keys.at(dir).append(str); } } } finish_images: imagelist2d_writer_t::instance()->write_obj(fp, node, keys); // write version data node.write_uint16(fp, 0x8001, 0); node.write_uint16(fp, allowed_climates, 2); node.write_uint16(fp, distribution_weight, 4); node.write_uint8 (fp, number_of_seasons, 6); node.write_uint8 (fp, trees_on_top, 7); node.write_uint16(fp, speed, 8); node.write_uint16(fp, waytype, 10); node.write_sint32(fp, price, 12); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/groundobj_writer.h000066400000000000000000000013471474050137200256240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_GROUNDOBJ_WRITER_H #define DESCRIPTOR_WRITER_GROUNDOBJ_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class groundobj_writer_t : public obj_writer_t { private: static groundobj_writer_t the_instance; groundobj_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_groundobj; } const char *get_type_name() const OVERRIDE { return "ground_obj"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/image_writer.cc000066400000000000000000000323021474050137200250460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include "image_writer.h" #include "root_writer.h" #include "obj_node.h" #include "obj_pak_exception.h" #include "../image.h" #include "../../macros.h" #include "../../utils/simstring.h" #include "../../simdebug.h" #include "../../io/raw_image.h" #ifndef _WIN32 #include #include #endif struct dimension { int xmin; int xmax; int ymin; int ymax; }; std::string image_writer_t::last_img_file; raw_image_t image_writer_t::input_img; int image_writer_t::img_size = 64; uint32 image_writer_t::block_getpix(int x, int y) { const uint8 *pixel_data = input_img.access_pixel(x, y); switch (input_img.get_format()) { case raw_image_t::FMT_GRAY8: { const uint8 gray_level = pixel_data[0]; return gray_level << 0 | gray_level << 8 | gray_level << 16; } case raw_image_t::FMT_RGBA8888: { const uint32 pixel = (pixel_data[2] << 0) + // B (pixel_data[1] << 8) + // G (pixel_data[0] << 16) + // R (pixel_data[3] << 24); // A // invert alpha channel, we want 0 == opaque return pixel ^ 0xFF000000; } case raw_image_t::FMT_RGB888: { return (pixel_data[2] << 0) | // B (pixel_data[1] << 8) | // G (pixel_data[0] << 16); // R } default: dbg->fatal("image_writer_t::block_getpix", "Unsupported input image format"); } } // colors with higher alpha are considered transparent #define ALPHA_THRESHOLD (0xF8000000u) /** * Encodes image data into the internal representation, * considers special colors. */ static uint16 pixrgb_to_pixval(uint32 rgb) { uint16 pix; // first: find about alpha assert( rgb < ALPHA_THRESHOLD ); int alpha = 30 - (rgb >> 24)/8; // transparency in 32 steps, but simutrans uses internally the reverse format if( rgb > 0x00FFFFFF ) { // alpha is now between 0 ... 30 // first see if this is a transparent special color (like player color) for (int i = 0; i < SPECIAL; i++) { if (image_t::rgbtab[i] == (uint32)(rgb & 0x00FFFFFFu)) { // player or light color pix = 0x8020 + i*31 + alpha; return endian(pix); } } // else store color as 3 red, 4, green, 3 red pix = ((rgb >> 14) & 0x0380) | ((rgb >> 9) & 0x0078) | ((rgb >> 5) & 0x07); pix = 0x8020 + 31*31 + pix*31 + alpha; return pix; } // non-transparent pixel for (int i = 0; i < SPECIAL; i++) { if (image_t::rgbtab[i] == (uint32)rgb) { pix = 0x8000 + i; return pix; } } const int r = (rgb >> 16); const int g = (rgb >> 8) & 0xFF; const int b = (rgb >> 0) & 0xFF; // RGB 555 pix = ((r & 0xF8) << 7) | ((g & 0xF8) << 2) | ((b & 0xF8) >> 3); return pix; } // true if transparent inline bool is_transparent( const uint32 pix ) { return (pix & 0x00FFFFFF) == SPECIAL_TRANSPARENT || (pix >= ALPHA_THRESHOLD); } static void init_dim(uint32 *image, dimension *dim, int img_size) { int x,y; bool found = false; dim->ymin = dim->xmin = img_size; dim->ymax = dim->xmax = 0; for (y = 0; y < img_size; y++) { for (x = 0; x < img_size; x++) { if( !is_transparent(image[x + y * img_size]) ) { if (x < dim->xmin) dim->xmin = x; if (y < dim->ymin) dim->ymin = y; if (x > dim->xmax) dim->xmax = x; if (y > dim->ymax) dim->ymax = y; found = true; } } } if (!found) { // Negative values not usable dim->xmin = 1; dim->ymin = 1; } } /** * Encodes an image into a sprite data structure, considers * special colors. */ uint16 *image_writer_t::encode_image(int x, int y, dimension* dim, int* len) { int line; uint16 *dest; uint16 *dest_base = new uint16[img_size * img_size * 2]; uint16 *colored_run_counter; dest = dest_base; x += dim->xmin; y += dim->ymin; const int img_width = dim->xmax - dim->xmin + 1; const int img_height = dim->ymax - dim->ymin + 1; for( line = 0; line < img_height; line++ ) { int row_px_count = 0; // index of the currently handled pixel uint16 clear_colored_run_pair_count = 0; uint32 pix = block_getpix( x + row_px_count, y + line ); row_px_count++; do { // read one row uint16 count = 0; // read transparent pixels while( is_transparent(pix) ) { count ++; if (row_px_count >= img_width) { // end of line ? break; } pix = block_getpix( x + row_px_count, y + line ); row_px_count++; } // write number of transparent pixels *dest++ = endian(count); // position to write number of colored pixels to colored_run_counter = dest++; count = 0; PIXVAL has_transparent = 0; while( !is_transparent(pix) ) { // write the colored pixel PIXVAL pixval = pixrgb_to_pixval(pix); if( pixval >= 0x8020 && !has_transparent ) { if( count ) { *colored_run_counter = endian(uint16(count)); *dest++ = endian(uint16(0x8000)); colored_run_counter = dest++; count = 0; } has_transparent = 0x8000; } else if( pixval < 0x8020 && has_transparent ) { if( count ) { *colored_run_counter = endian(uint16(count+has_transparent)); *dest++ = endian(uint16(0x8000)); colored_run_counter = dest++; count = 0; } has_transparent = 0; } *dest++ = endian(uint16(pixval)); count++; if (row_px_count >= img_width) { // end of line ? break; } pix = block_getpix( x + row_px_count, y + line ); row_px_count++; } /* * If it is not the first clear-colored-run pair and its colored run is empty * --> it is superfluous and can be removed by rolling back the pointer */ if( clear_colored_run_pair_count > 0 && count == 0 ) { dest -= 2; // this only happens at the end of a line, so no need to increment clear_colored_run_pair_count } else { *colored_run_counter = endian(uint16(count + has_transparent)); clear_colored_run_pair_count++; } } while( row_px_count < img_width ); *dest++ = 0; } *len = dest - dest_base; return dest_base; } bool image_writer_t::block_load(const char *fname) { // The last image file is cached // Note that this method accepts any file name if the content has a supported format, // even though makeobj only supports image file names with a ".png" suffix. // See image_writer_t::write_obj for details. if( last_img_file == fname ) { return true; } else if (load_image_from_file(fname)) { if ((input_img.get_width()%img_size != 0) || (input_img.get_height()%img_size != 0)) { dbg->error("image_writer_t::block_load", "Cannot load image file '%s': " "Size not divisible by %d.", fname, img_size); last_img_file = ""; return false; } last_img_file = fname; return true; } // error message is handled by image_writer_t::write_obj last_img_file = ""; return false; } bool image_writer_t::load_image_from_file(const char* fname) { if (input_img.read_from_file(fname)) { return true; } // Not an exact match, try to case-insensitive search. #ifndef _WIN32 std::string actual_path; size_t len = strlen(fname); actual_path.reserve(len); const char * sep_beg = fname; const char * sep_end = sep_beg + strspn(sep_beg, "/"); if (sep_end == sep_beg) { // relative actual_path = "./"; } char const * end = fname + len; std::string name; while (true) { actual_path.insert(actual_path.end(), sep_beg, sep_end); sep_beg = sep_end + strcspn(sep_end, "/"); if (sep_beg == sep_end) { break; } name.assign(sep_end, sep_beg); DIR * dir = opendir(actual_path.c_str()); if (!dir) { break; } struct dirent * ent = NULL; while ((ent = readdir(dir)) != NULL) { if (!STRICMP(ent->d_name, name.c_str())) { actual_path += ent->d_name; break; } } closedir(dir); if (!ent) { break; } if (sep_beg == end) { return input_img.read_from_file(actual_path.c_str()); } sep_end = sep_beg + strspn(sep_beg, "/"); } #endif return false; } /* the syntax for image the string is * "-" empty image * [> ]imagefilename_without_extension[[[[.row].col],xoffset],yoffset] * leading "> " set the flag for a non-zoomable image * after the dots also spaces and comments are allowed */ void image_writer_t::write_obj(FILE* outfp, obj_node_t& parent, std::string an_imagekey, uint32 index) { image_t image; dimension dim; uint16 *pixdata = NULL; MEMZERO(image); // if first char is a '>' then this image is not zoomable if( an_imagekey[0] == '>' ) { an_imagekey = an_imagekey.substr(1); image.zoomable = false; } else { image.zoomable = true; } std::string imagekey = trim(an_imagekey); if( imagekey != "-" && imagekey != "" ) { // divide key in filename and image number int row = -1, col = -1; std::string numkey; int j = imagekey.rfind('/'); if( j == -1 ) { numkey = imagekey; } else { numkey = imagekey.substr(j + 1, std::string::npos); } int i = numkey.find('.'); if( i == -1 ) { char reason[1024]; sprintf(reason, "no image number in %s", imagekey.c_str() ); throw obj_pak_exception_t("image_writer_t", reason); } numkey = numkey.substr( i+1, std::string::npos ); imagekey = root_writer_t::get_inpath() + imagekey.substr( 0, imagekey.size()-numkey.size() - 1 ) + ".png"; row = atoi(numkey.c_str()); i = numkey.find('.'); if(i != -1) { col = atoi( numkey.c_str()+i+1 ); // add image offsets int comma_pos = numkey.find(','); if(comma_pos != -1) { numkey = numkey.substr( comma_pos+1, std::string::npos); image.x = atoi( numkey.c_str() ); comma_pos = numkey.find(','); if(comma_pos != -1) { image.y = atoi(numkey.substr( comma_pos + 1, std::string::npos).c_str()); } } } // Load complete file if (!block_load(imagekey.c_str())) { char reason[1024]; sprintf(reason, "cannot open %s", imagekey .c_str()); throw obj_pak_exception_t("image_writer_t", reason); } if (col == -1) { col = row % (input_img.get_width() / img_size); row = row / (input_img.get_height() / img_size); } if (col >= (int)(input_img.get_width() / img_size) || row >= (int)(input_img.get_height() / img_size)) { char reason[1024]; sprintf(reason, "invalid image number in %s.%s", imagekey.c_str(), numkey.c_str()); throw obj_pak_exception_t("image_writer_t", reason); } row *= img_size; col *= img_size; // Temp. read image and determine drawing area. uint32 *image_data = new uint32[img_size * img_size]; for (int x = 0; x < img_size; x++) { for (int y = 0; y < img_size; y++) { image_data[x + y * img_size] = block_getpix(x + col, y + row); } } init_dim(image_data, &dim, img_size); delete [] image_data; image.x += dim.xmin; image.y += dim.ymin; image.w = dim.xmax - dim.xmin + 1; image.h = dim.ymax - dim.ymin + 1; image.len = 0; if (image.h > 0) { int len; pixdata = encode_image(col, row, &dim, &len); image.len = len; } dbg->debug( "", "image[%3u] =%-30s %-20s %5u %5u %5u %5u %5u %6u %4s", index, an_imagekey.c_str(), imagekey.c_str(), col, row, image.x, image.y, image.w, image.h, (image.zoomable) ? "yes" : "no" ); } else { dbg->debug( "", "image[%3u] =%-30s %-20s %5u %5u %5u %5u %5u %6u %4s", index, an_imagekey.c_str(), imagekey.c_str(), 0, 0, image.x, image.y, image.w, image.h, (image.zoomable) ? "yes" : "no" ); } #ifdef IMG_VERSION0 // version 0 obj_node_t node(this, 12 + (image.len * sizeof(uint16)), &parent); // to avoid any problems due to structure changes, we write manually the data node.write_uint8 (outfp, image.x, 0); node.write_uint8 (outfp, image.w, 1); node.write_uint8 (outfp, image.y, 2); node.write_uint8 (outfp, image.h, 3); node.write_uint32(outfp, image.len, 4); node.write_uint16(outfp, 0, 8); node.write_uint8 (outfp, image.zoomable, 10); node.write_uint8 (outfp, 0, 11); if (image.len) { // only called, if there is something to store node.write_data_at(outfp, pixdata, 12, image.len * sizeof(PIXVAL)); delete [] pixdata; } #elif IMG_VERSION2 // version 1 or 2 obj_node_t node(this, 10 + (image.len * sizeof(uint16)), &parent); // to avoid any problems due to structure changes, we write manually the data node.write_uint16(outfp, image.x, 0); node.write_uint16(outfp, image.y, 2); node.write_uint8 (outfp, image.w, 4); node.write_uint8 (outfp, image.h, 5); node.write_uint8 (outfp, 2, 6); // version node.write_uint16(outfp, image.len, 7); node.write_uint8 (outfp, image.zoomable, 9); if (image.len) { // only called, if there is something to store node.write_data_at(outfp, pixdata, 10, image.len * sizeof(PIXVAL)); delete [] pixdata; } #else // version 3 obj_node_t node(this, 10 + (image.len * sizeof(uint16)), &parent); // to avoid any problems due to structure changes, we write manually the data node.write_uint16(outfp, image.x, 0); node.write_uint16(outfp, image.y, 2); node.write_uint16(outfp, image.w, 4); node.write_uint8 (outfp, 3, 6); // version, always at position 6! node.write_uint16(outfp, image.h, 7); // len is now automatically calculated node.write_uint8 (outfp, image.zoomable, 9); if (image.len) { // only called, if there is something to store node.write_data_at(outfp, pixdata, 10, image.len * sizeof(uint16)); delete [] pixdata; } #endif node.write(outfp); } simutrans-124.3/src/simutrans/descriptor/writer/image_writer.h000066400000000000000000000025111474050137200247070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_IMAGE_WRITER_H #define DESCRIPTOR_WRITER_IMAGE_WRITER_H #include #include #include "obj_writer.h" #include "../objversion.h" #include "../../io/raw_image.h" class obj_node_t; struct dimension; class image_writer_t : public obj_writer_t { private: static image_writer_t the_instance; static std::string last_img_file; static raw_image_t input_img; static int img_size; // default 64 image_writer_t() { register_writer(false); } static uint32 block_getpix(int x, int y); public: static image_writer_t* instance() { return &the_instance; } static void set_img_size(int _img_size) { img_size = _img_size; } obj_type get_type() const OVERRIDE { return obj_image; } const char* get_type_name() const OVERRIDE { return "image"; } void write_obj(FILE* fp, obj_node_t& parent, std::string imagekey, uint32 index); private: bool block_load(const char* fname); /// Loads @ref input_img with the contents of @p fname, ignores case of @p filename. /// @returns true on success bool load_image_from_file(const char *fname); /// Encodes an image into a sprite data structure, considers /// special colors. static uint16 *encode_image(int x, int y, dimension* dim, int* len); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/imagelist2d_writer.cc000066400000000000000000000011671474050137200261750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../tpl/slist_tpl.h" #include "obj_node.h" #include "imagelist_writer.h" #include "imagelist2d_writer.h" void imagelist2d_writer_t::write_obj(FILE* fp, obj_node_t& parent, const slist_tpl >& keys) { obj_node_t node(this, 4, &parent); uint16 const count = keys.get_count(); for(slist_tpl const& s : keys) { imagelist_writer_t::instance()->write_obj(fp, node, s); } node.write_uint16(fp, count, 0); node.write_uint16(fp, 0, 2); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/imagelist2d_writer.h000066400000000000000000000014161474050137200260340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_IMAGELIST2D_WRITER_H #define DESCRIPTOR_WRITER_IMAGELIST2D_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" template class slist_tpl; class imagelist2d_writer_t : public obj_writer_t { private: static imagelist2d_writer_t the_instance; imagelist2d_writer_t() { register_writer(false); } public: static imagelist2d_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_imagelist2d; } const char* get_type_name() const OVERRIDE { return "imagelist2d"; } void write_obj(FILE* fp, obj_node_t& parent, const slist_tpl >& keys); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/imagelist_writer.cc000066400000000000000000000021061474050137200257410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../tpl/slist_tpl.h" #include "obj_node.h" #include "image_writer.h" #include "obj_pak_exception.h" #include "imagelist_writer.h" void imagelist_writer_t::write_obj(FILE* fp, obj_node_t& parent, const slist_tpl& keys) { obj_node_t node(this, 4, &parent); unsigned int count = 0; if( !keys.empty() && debuglevel>2 ) { dbg->debug("", "Source image X Y Off X Off Y Width Height Zoom\n"); dbg->debug("", "------------------------------------------ -------------------- ----- ----- ----- ----- ----- ------ ----\n"); } for(std::string const& s : keys) { image_writer_t::instance()->write_obj(fp, node, s, count); count ++; } if (count < keys.get_count()) { dbg->warning( obj_writer_t::last_name, "Expected %i but found %i images (might be correct)!\n", keys.get_count(), count); } node.write_uint16(fp, count, 0); node.write_uint16(fp, 0, 2); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/imagelist_writer.h000066400000000000000000000014271474050137200256100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_IMAGELIST_WRITER_H #define DESCRIPTOR_WRITER_IMAGELIST_WRITER_H #include #include #include "obj_writer.h" #include "../objversion.h" template class slist_tpl; class obj_node_t; class imagelist_writer_t : public obj_writer_t { private: static imagelist_writer_t the_instance; imagelist_writer_t() { register_writer(false); } public: static imagelist_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_imagelist; } const char* get_type_name() const OVERRIDE { return "imagelist"; } void write_obj(FILE* fp, obj_node_t& parent, const slist_tpl& keys); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/obj_node.cc000066400000000000000000000057571474050137200241650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "obj_pak_exception.h" #include "obj_writer.h" #include "obj_node.h" #include "../obj_desc.h" uint32 obj_node_t::free_offset; // next free offset in file obj_node_t::obj_node_t(obj_writer_t* writer, uint32 size, obj_node_t* parent) { this->parent = parent; desc.type = writer->get_type(); desc.nchildren = 0; desc.size = size; if( sizedesc.nchildren++; } } void obj_node_t::write_data(FILE* fp, const void* data) { write_data_at(fp, data, 0, desc.size); } void obj_node_t::write_data_at(FILE* fp, const void* data, int offset, int size) { if (offset < 0 || size < 0 || (uint32)(offset + size) > desc.size) { char reason[1024]; sprintf(reason, "invalid parameters (offset=%d, size=%d, obj_size=%d)", offset, size, desc.size); throw obj_pak_exception_t("obj_node_t", reason); } fseek(fp, write_offset + offset, SEEK_SET); fwrite(data, size, 1, fp); } void obj_node_t::write_uint8(FILE* fp, uint8 data, int offset) { this->write_data_at(fp, &data, offset, 1); } void obj_node_t::write_uint16(FILE* fp, uint16 data, int offset) { uint16 data2 = endian(data); this->write_data_at(fp, &data2, offset, 2); } void obj_node_t::write_uint32(FILE* fp, uint32 data, int offset) { uint32 data2 = endian(data); this->write_data_at(fp, &data2, offset, 4); } simutrans-124.3/src/simutrans/descriptor/writer/obj_node.h000066400000000000000000000035641474050137200240210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_OBJ_NODE_H #define DESCRIPTOR_WRITER_OBJ_NODE_H #include "../obj_node_info.h" #include class obj_writer_t; class obj_node_t { private: static uint32 free_offset; // next free offset in file obj_node_info_t desc; uint32 write_offset; // Start of node data in file (after node.desc) obj_node_t* parent; public: // set_start_offset() - set offset of first node in file // ONLY CALL BEFORE ANY NODES ARE CREATED !!! static void set_start_offset(uint32 offset) { free_offset = offset; } // reads a node into a given obj_node_info_t static bool read_node(FILE* fp, obj_node_info_t &node ); /// construct a new node. /// @param writer object, that writes the node to the file /// @param size space needed for node data /// @param parent parent node obj_node_t(obj_writer_t* writer, uint32 size, obj_node_t* parent); // Write the complete node data to the file void write_data(FILE* fp, const void* data); // Write part of the node data to the file // The caller is responsible that all areas are written y multiple calls // Throws obj_pak_exception_t void write_data_at(FILE* fp, const void* data, int offset, int size); void write_uint8(FILE* fp, uint8 data, int offset); void write_uint16(FILE* fp, uint16 data, int offset); void write_uint32(FILE* fp, uint32 data, int offset); void write_sint8(FILE* fp, sint8 data, int offset) { this->write_uint8(fp, (uint8) data, offset); } void write_sint16(FILE* fp, sint16 data, int offset) { this->write_uint16(fp, (uint16) data, offset); } void write_sint32(FILE* fp, sint32 data, int offset) { this->write_uint32(fp, (sint32) data, offset); } // Write the internal node info to the file // DO THIS AFTER ALL CHILD NODES ARE WRITTEN !!! void write(FILE* fp); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/obj_pak_exception.h000066400000000000000000000010431474050137200257130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_OBJ_PAK_EXCEPTION_H #define DESCRIPTOR_WRITER_OBJ_PAK_EXCEPTION_H #include class obj_pak_exception_t { private: std::string classname; std::string problem; public: obj_pak_exception_t(const char* clsname, const char* prob) { classname = clsname; problem = prob; } const char* get_class() const { return classname.c_str(); } const char* get_info() const { return problem.c_str(); } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/obj_writer.cc000066400000000000000000000113301474050137200245340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../utils/simstring.h" #include "../../dataobj/tabfile.h" #include "../../tpl/stringhashtable_tpl.h" #include "../../tpl/inthashtable_tpl.h" #include "obj_node.h" #include "obj_writer.h" #include "image_writer.h" #include "text_writer.h" #include "xref_writer.h" const char *obj_writer_t::last_name = ""; int obj_writer_t::default_image_size = 64; void obj_writer_t::register_writer(bool main_obj) { if (!writer_by_name) { writer_by_name = new stringhashtable_tpl; writer_by_type = new inthashtable_tpl; } if (main_obj) { writer_by_name->put(get_type_name(), this); } writer_by_type->put(get_type(), this); /// printf("This program can compile %s objects\n", get_type_name()); } void obj_writer_t::write(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { const char *type = obj.get("obj"); const char *name = obj.get("name"); obj_writer_t *writer = writer_by_name->get(type); if (!writer) { printf("Skipping unknown %s object %s\n", type, name); return; } // now get the image size image_writer_t::set_img_size(obj.get_int("cell_size",default_image_size)); last_name = name; if (debuglevel >= log_t::LEVEL_WARN) { printf(" packing %s.%s\n", type, name); } writer->write_obj(fp, parent, obj); } void obj_writer_t::write_head(FILE* fp, obj_node_t& node, tabfileobj_t& obj) { const char* name = obj.get("name"); const char* msg = obj.get("copyright"); last_name = name; text_writer_t::instance()->write_obj(fp, node, name); text_writer_t::instance()->write_obj(fp, node, msg); } bool obj_writer_t::dump_nodes(FILE* infp, int level, uint16 index) { obj_node_info_t node; if (!obj_node_t::read_node(infp, node) ) { return false; } const long next_pos = ftell(infp) + node.size; obj_writer_t* writer = writer_by_type->get(node.type); if (writer) { printf("%*s%03u %4.4s-node (%s)", 3 * level, " ", index, (const char*)&node.type, writer->get_type_name()); bool ok = writer->dump_node(infp, node); printf("\n"); if (!ok) { return false; } } if (fseek(infp, next_pos, SEEK_SET) != 0) { return false; } for (int child_idx = 0; child_idx < node.nchildren; child_idx++) { if (!dump_nodes(infp, level + 1, child_idx)) { return false; } } return true; } bool obj_writer_t::list_nodes(FILE *infp) { obj_node_info_t node; if (!obj_node_t::read_node( infp, node ) || node.size == 0) { return false; } const long next_pos = ftell(infp) + node.size; obj_writer_t *writer = writer_by_type->get((obj_type)node.type); if (writer) { if (fseek(infp, node.size, SEEK_CUR) != 0) { return false; } const std::string node_name = writer->get_node_name(infp); printf("%-16s %-30s %5u ", writer->get_type_name(), node_name.c_str(), node.nchildren); } else { printf("(unknown %4.4s) %30.30s %5.5s ", (const char *)&node.type, " ", " "); } if (fseek(infp, next_pos, SEEK_SET) != 0) { return false; } size_t offset = 0; for (int i = 0; i < node.nchildren; i++) { if (!skip_nodes(infp, offset)) { return false; } } printf("%10lu\n", offset); return true; } void obj_writer_t::show_capabilites() { slist_tpl list; const char *min_s="A"; while (true) { const char *max_s = "zzz"; for(auto const& i : *writer_by_name) { if( STRICMP(i.key, min_s) > 0 && STRICMP(i.key, max_s) < 0 ) { max_s = i.key; } } if( strcmp(max_s,"zzz")==0 ) { break; } printf(" %s\n", max_s); min_s = max_s; } } std::string obj_writer_t::name_from_next_node(FILE *fp) const { std::string ret; obj_node_info_t node; if (!obj_node_t::read_node( fp, node ) || node.type!=obj_text || node.size == 0xFFFFFFFFu) { return ""; } char *buf = new char[node.size+1]; if (!buf) { return ""; } if (fread(buf, node.size, 1, fp) != 1) { delete[] buf; return ""; } buf[node.size] = 0; ret = buf; delete[] buf; return ret; } bool obj_writer_t::skip_nodes(FILE *fp, size_t &offset) { obj_node_info_t node; if (!obj_node_t::read_node( fp, node ) || fseek(fp, node.size, SEEK_CUR) != 0) { return false; } offset += node.size; for (int i = 0; i < node.nchildren; i++) { if (!skip_nodes(fp, offset)) { return false; } } return true; } bool obj_writer_t::dump_node(FILE */*infp*/, const obj_node_info_t& node) { printf(" %5u bytes", node.size); return true; } const char* obj_writer_t::node_writer_name(FILE* infp) const { obj_node_info_t node; obj_node_t::read_node( infp, node ); fseek(infp, node.size, SEEK_CUR); obj_writer_t* writer = writer_by_type->get(node.type); if (writer) { return writer->get_type_name(); } return "unknown"; } simutrans-124.3/src/simutrans/descriptor/writer/obj_writer.h000066400000000000000000000032011474050137200243740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_OBJ_WRITER_H #define DESCRIPTOR_WRITER_OBJ_WRITER_H #include #include #include "../intro_dates.h" #include "../objversion.h" class obj_node_t; struct obj_node_info_t; class tabfileobj_t; template class stringhashtable_tpl; template class inthashtable_tpl; class obj_writer_t { private: static stringhashtable_tpl* writer_by_name; static inthashtable_tpl *writer_by_type; static int default_image_size; protected: obj_writer_t() { /* Beware: Cannot register here! */ } void register_writer(bool main_obj); bool dump_nodes(FILE *infp, int level, uint16 index = 0); bool list_nodes(FILE *infp); bool skip_nodes(FILE* fp, size_t &offset); void show_capabilites(); std::string name_from_next_node(FILE* fp) const; const char* node_writer_name(FILE* infp) const; virtual std::string get_node_name(FILE* /*fp*/) const { return ""; } virtual bool dump_node(FILE *infp, const obj_node_info_t& node); virtual void write_obj(FILE */*fp*/, obj_node_t& /*parent*/, tabfileobj_t& /*obj*/) {} void write_head(FILE* fp, obj_node_t& node, tabfileobj_t& obj); public: // contains the name of the last obj/name header static const char *last_name; virtual ~obj_writer_t() {} virtual obj_type get_type() const = 0; virtual const char* get_type_name() const = 0; static void write(FILE* fp, obj_node_t& parent, tabfileobj_t& obj); static void set_img_size(int img_size) { obj_writer_t::default_image_size = img_size; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/pedestrian_writer.cc000066400000000000000000000044771474050137200261360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist_writer.h" #include "imagelist2d_writer.h" #include "pedestrian_writer.h" void pedestrian_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { int i; obj_node_t node(this, 12, &parent); write_head(fp, node, obj); uint16 const distribution_weight = obj.get_int("distributionweight", 1); static const char* const dir_codes[] = { "s", "w", "sw", "se", "n", "e", "ne", "nw" }; slist_tpl keys; slist_tpl > keys_animated; std::string str; char buf[40]; // test for animation images uint16 is_animated = 0; for (i = 0; i < 8; i++) { sprintf(buf, "image[%s][0]", dir_codes[i]); str = obj.get(buf); is_animated += !str.empty(); } for (i = 0; i < 8; i++) { if (is_animated) { for (uint16 j = 0; j<500; j++) { keys_animated.append(); sprintf(buf, "image[%s][%d]", dir_codes[i], j); str = obj.get(buf); printf("%s : %s\n", buf, str.c_str()); if (str.empty()) { break; } keys_animated.at(i).append(str); } } else { sprintf(buf, "image[%s]", dir_codes[i]); str = obj.get(buf); keys.append(str); } } uint16 steps_per_frame = is_animated ? max(obj.get_int("steps_per_frame", 1), 1) : 0; if (is_animated) { imagelist2d_writer_t::instance()->write_obj(fp, node, keys_animated); } else { imagelist_writer_t::instance()->write_obj(fp, node, keys); } uint16 offset = obj.get_int("offset", 20); uint16 const intro_date = obj.get_int("intro_year", 1) * 12 + // no DEFAULT_INTRO_DATE here obj.get_int("intro_month", 1) - 1; uint16 const retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12 + obj.get_int("retire_month", 1) - 1; // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend uint16 version = 0x8002; node.write_uint16(fp, version, 0); node.write_uint16(fp, distribution_weight, 2); node.write_uint16(fp, steps_per_frame, 4); node.write_uint16(fp, offset, 6); node.write_uint16(fp, intro_date, 8); node.write_uint16(fp, retire_date, 10); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/pedestrian_writer.h000066400000000000000000000013551474050137200257700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_PEDESTRIAN_WRITER_H #define DESCRIPTOR_WRITER_PEDESTRIAN_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class pedestrian_writer_t : public obj_writer_t { private: static pedestrian_writer_t the_instance; pedestrian_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_pedestrian; } const char* get_type_name() const OVERRIDE { return "pedestrian"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/roadsign_writer.cc000066400000000000000000000121771474050137200256020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../dataobj/tabfile.h" #include "../roadsign_desc.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist_writer.h" #include "roadsign_writer.h" #include "get_waytype.h" #include "skin_writer.h" static const char* private_sign_directions[] = {"ns", "ew"}; static const char* traffic_light_directions[] = {"n", "s", "w", "e", "nw", "se", "sw", "ne"}; static const char* general_sign_directions[] = {"n", "s", "w", "e"}; // parse "image[direction][state]" syntax void parse_images_2d(slist_tpl& keys, tabfileobj_t& obj, roadsign_desc_t::types flags) { const char** directions; uint8 dir_cnt; // how many directions are there? if( flags&roadsign_desc_t::PRIVATE_ROAD ) { directions = private_sign_directions; dir_cnt = lengthof(private_sign_directions); } else if( *obj.get("image[ne][0]") ) { // Assume this is a traffic light. directions = traffic_light_directions; dir_cnt = lengthof(traffic_light_directions); } else { // Normal road sign or railway signal directions = general_sign_directions; dir_cnt = lengthof(general_sign_directions); } for( uint8 state=0; state<8; state++ ) { for( uint8 idx = 0; idx < dir_cnt; idx++ ) { char buf[64]; sprintf(buf, "image[%s][%i]", directions[idx], state); const char* img = obj.get(buf); if( !*img ){ if( state>(dir_cnt==2) && idx==0 ) { // Assume all further state numbers are invalid. return; } // image in the middle is missing => fatal error dbg->fatal("roadsign_writer", "%s is missing!", buf); } // append image number keys.append(img); } } } // parse "image[number]" syntax void parse_images_numbered(slist_tpl& keys, tabfileobj_t& obj) { for (int i = 0; i < 32; i++) { char buf[40]; sprintf(buf, "image[%i]", i); const char *str = obj.get(buf); // make sure, there are always 4, 8, 12, ... images (for all directions) if( !*str ) { if( i % 4 ) { dbg->fatal("roadsign_writer", "image count is %d but must be multiple of 4!", i); } break; } keys.append(str); } } void roadsign_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 16, &parent); uint32 const price = obj.get_int("cost", 500) * 100; uint16 const min_speed = obj.get_int("min_speed", 0); sint8 const offset_left = obj.get_int("offset_left", 14); uint8 const wtyp = get_waytype(obj.get("waytype")); roadsign_desc_t::types flags = roadsign_desc_t::NONE; if( obj.get_int("is_signal",0) ) { flags = roadsign_desc_t::SIGN_SIGNAL; if( obj.get_int("free_route",0) ) { flags |= roadsign_desc_t::CHOOSE_SIGN; } } else if( obj.get_int("is_presignal",0) ) { flags = roadsign_desc_t::SIGN_PRE_SIGNAL; } else if( obj.get_int("is_prioritysignal",0) ) { flags = roadsign_desc_t::SIGN_PRIORITY_SIGNAL; } else if( obj.get_int("is_longblocksignal",0) ) { flags = roadsign_desc_t::SIGN_LONGBLOCK_SIGNAL; } else { // road or airsigns ... flags = (obj.get_int("single_way", 0) > 0 ? roadsign_desc_t::ONE_WAY : roadsign_desc_t::NONE) | (obj.get_int("free_route", 0) > 0 ? roadsign_desc_t::CHOOSE_SIGN : roadsign_desc_t::NONE) | (obj.get_int("is_private", 0) > 0 ? roadsign_desc_t::PRIVATE_ROAD : roadsign_desc_t::NONE) | (obj.get_int("no_foreground", 0) > 0 ? roadsign_desc_t::ONLY_BACKIMAGE : roadsign_desc_t::NONE) | (obj.get_int("end_of_choose", 0) > 0 ? roadsign_desc_t::END_OF_CHOOSE_AREA : roadsign_desc_t::NONE); } // this causes unused entries to give a warning that they are ignored // write version data node.write_uint16(fp, 0x8005, 0); // version 5 node.write_uint16(fp, min_speed, 2); node.write_uint32(fp, price, 4); node.write_uint16(fp, flags, 8); node.write_uint8 (fp, offset_left,10); node.write_uint8 (fp, wtyp, 11); uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro_date += obj.get_int("intro_month", 1) - 1; node.write_uint16(fp, intro_date, 12); uint16 retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire_date += obj.get_int("retire_month", 1) - 1; node.write_uint16(fp, retire_date, 14); write_head(fp, node, obj); // add the images slist_tpl keys; if( *obj.get("image[0]") ) { // image[0] is defined. // assume that images are defined in image[number] syntax. parse_images_numbered(keys, obj); } else { // image[0] is not defined. // assume that images are defined in image[direction][state] syntax. parse_images_2d(keys, obj, flags); } imagelist_writer_t::instance()->write_obj(fp, node, keys); // probably add some icons, if defined slist_tpl cursorkeys; const char *c = obj.get("cursor"), *i=obj.get("icon"); cursorkeys.append(c); cursorkeys.append(i); if (*c || *i) { cursorskin_writer_t::instance()->write_obj(fp, node, obj, cursorkeys); } node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/roadsign_writer.h000066400000000000000000000013371474050137200254400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_ROADSIGN_WRITER_H #define DESCRIPTOR_WRITER_ROADSIGN_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class roadsign_writer_t : public obj_writer_t { private: static roadsign_writer_t the_instance; roadsign_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_roadsign; } const char *get_type_name() const OVERRIDE { return "roadsign"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/root_writer.cc000066400000000000000000000335531474050137200247600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../dataobj/tabfile.h" #include "../../utils/searchfolder.h" #include "../obj_desc.h" #include "obj_node.h" #include "obj_writer.h" #include "root_writer.h" using std::string; string root_writer_t::inpath; void root_writer_t::write_header(FILE* fp) { fprintf(fp, "Simutrans object file\n" "Compiled with SimObjects " COMPILER_VERSION "\n\x1A" ); uint32 l = endian(uint32(COMPILER_VERSION_CODE)); fwrite(&l, 1, sizeof(uint32), fp); // Compiler version to check obj_node_t::set_start_offset(ftell(fp)); } // makes pak file(s) void root_writer_t::write(const char* filename, int argc, char* argv[]) { searchfolder_t find; FILE* outfp = NULL; obj_node_t* node = NULL; bool separate = false; string file = find.complete(filename, "pak"); if (file[file.size()-1] == '/') { printf("writing individual files to %s\n", filename); separate = true; } else { outfp = fopen(file.c_str(), "wb"); if (!outfp) { dbg->fatal( "Write pak", "Cannot create destination file %s", filename ); } if (debuglevel >= log_t::LEVEL_WARN) { printf("Writing file %s\n", filename); } write_header(outfp); node = new obj_node_t(this, 0, NULL); } for( int i=0; i==0 || i= log_t::LEVEL_WARN) { printf(" Reading file %s\n", i); } inpath = arg; string::size_type n = inpath.rfind('/'); if(n!=string::npos) { inpath = inpath.substr(0, n + 1); } else { inpath = ""; } while(infile.read(obj)) { if(separate) { string name(filename); name = name + obj.get("obj") + "." + obj.get("name") + ".pak"; outfp = fopen(name.c_str(), "wb"); if (!outfp) { dbg->fatal( "Write pak", "Cannot create destination file %s", filename ); } if (debuglevel >= log_t::LEVEL_WARN) { printf(" Writing file %s\n", name.c_str()); } write_header(outfp); node = new obj_node_t(this, 0, NULL); } obj_writer_t::write(outfp, *node, obj); obj.unused( "#;-/" ); if(separate) { node->write(outfp); delete node; fclose(outfp); } } } else { dbg->warning( "Write pak", "Cannot read %s", i); } } } if (!separate) { node->write(outfp); delete node; fclose(outfp); } } void root_writer_t::write_obj_node_info_t(FILE* outfp, const obj_node_info_t &root) { uint32 type = endian(root.type); uint16 children = endian(root.nchildren); uint16 root_size = endian(uint16(root.size)); fwrite(&type, 4, 1, outfp); fwrite(&children, 2, 1, outfp); if( root.size>=LARGE_RECORD_SIZE ) { root_size = LARGE_RECORD_SIZE; fwrite(&root_size, 2, 1, outfp); uint32 size = endian(root.size); fwrite(&size, 4, 1, outfp); } else { fwrite(&root_size, 2, 1, outfp); } } static bool skip_header(FILE* const f) { for (;;) { int const c = fgetc(f); if (c == EOF) { dbg->error( "skip_header", "reached end of file while skipping header"); return false; } if (c == '\x1A') { return true; } } } bool root_writer_t::do_dump(const char* open_file_name) { FILE *const infp = fopen(open_file_name, "rb"); if (!infp) { return false; } if (!skip_header(infp)) { fclose(infp); return false; } // Compiled Version uint32 version; if (fread(&version, sizeof(version), 1, infp) != 1) { fclose(infp); return false; } printf("File %s (version %d):\n", open_file_name, endian(version)); if (!dump_nodes(infp, 0)) { fclose(infp); return false; } fclose(infp); return true; } // dumps the node structure onto the screen void root_writer_t::dump(int argc, char* argv[]) { for (int i = 0; i < argc; i++) { bool any = false; // this is necessary to avoid the hassle with "./*.pak" otherwise if (strchr(argv[i], '*') == NULL) { any = do_dump(argv[i]); } else { searchfolder_t find; find.search(argv[i], "pak"); for(const char* const& i : find) { any |= do_dump(i); } } if (!any) { dbg->error( "root_writer_t::dump", "Could not read pak file or dir %s (not found or file corrupted)", argv[i] ); } } } bool root_writer_t::do_list(const char *open_file_name) { FILE *const infp = fopen(open_file_name, "rb"); if (!infp) { return false; } if (!skip_header(infp)) { fclose(infp); return false; } // Compiled Version uint32 version; if (fread(&version, sizeof(version), 1, infp) != 1) { fclose(infp); return false; } printf("Contents of file %s (pak version %u):\n", open_file_name, endian(version)); printf("type name nodes size\n" "---------------- ------------------------------ ----- ----------\n"); obj_node_info_t node; if (!obj_node_t::read_node( infp, node ) || fseek(infp, node.size, SEEK_CUR) != 0) { fclose(infp); return false; } for (int i = 0; i < node.nchildren; i++) { if (!list_nodes(infp)){ fclose(infp); return false; } } fclose(infp); return true; } // list the content of a file void root_writer_t::list(int argc, char* argv[]) { for (int i = 0; i < argc; i++) { bool any = false; // this is necessary to avoid the hassle with "./*.pak" otherwise if (strchr(argv[i],'*') == NULL) { any = do_list(argv[i]); } else { searchfolder_t find; find.search(argv[i], "pak"); for(const char* const& i : find) { any |= do_list(i); } } if (!any) { dbg->error( "root_writer_t::list", "Could not read pak file or dir %s (not found or file corrupted)", argv[i] ); } } } bool root_writer_t::do_copy(FILE* outfp, obj_node_info_t& root, const char* open_file_name) { bool any = false; if (FILE* const infp = fopen(open_file_name, "rb")) { if (skip_header(infp)) { // Compiled Version check (since the ancient ending was also pak) uint32 version; fread(&version, sizeof(version), 1, infp); if (endian(version) <= COMPILER_VERSION_CODE) { printf(" copying file %s\n", open_file_name); obj_node_info_t info; obj_node_t::read_node( infp, info ); root.nchildren += info.nchildren; copy_nodes(outfp, infp, info); any = true; } else { dbg->warning( "root_writer_t::do_copy", "skipping file %s - version mismatch (need same version to merge!)", open_file_name); } } fclose(infp); } return any; } // merges pak files into an archive // void root_writer_t::copy(const char* name, int argc, char* argv[]) { searchfolder_t find; FILE* outfp = NULL; if (strchr(name, '*') == NULL) { // is not a wildcard name outfp = fopen(name, "wb"); } if (outfp == NULL) { name = find.complete(name, "pak").c_str(); outfp = fopen(name, "wb"); } if (!outfp) { dbg->fatal( "Merge", "Cannot open destination file %s", name); } fclose(outfp); if (remove(name) != 0) { dbg->warning("Merge", "Could not delete %s"); } // create temporary file std::string tmpfile_name = name; tmpfile_name += ".tmp"; outfp = fopen(tmpfile_name.c_str(), "wb"); printf("writing to temporary file %s\n", tmpfile_name.c_str()); write_header(outfp); long start = ftell(outfp); // remember position for adding children obj_node_info_t root; root.nchildren = 0; // we will change this later root.size = 0; root.type = obj_root; this->write_obj_node_info_t(outfp, root); for( int i=0; iwarning( "Merge", "Skipping reading from output file"); } } } if (!any) { dbg->warning( "Merge", "file or dir %s not found\n", argv[i]); } } fseek(outfp, start, SEEK_SET); this->write_obj_node_info_t(outfp, root); fclose(outfp); printf("renaming temporary file %s to %s\n", tmpfile_name.c_str(), name); rename(tmpfile_name.c_str(), name); } /* makes single files from a merged file */ void root_writer_t::uncopy(const char* name) { FILE* infp = NULL; if (strchr(name,'*') == NULL) { // is not a wildcard name infp = fopen(name, "rb"); } if (infp == NULL) { searchfolder_t find; name = find.complete(name, "pak").c_str(); infp = fopen(name, "rb"); } if (!infp) { dbg->fatal( "Unmerge", "Cannot open archive file %s\n", name); } if (skip_header(infp)) { // check version of pak format uint32 version; fread(&version, sizeof(version), 1, infp); if (endian(version) <= COMPILER_VERSION_CODE) { // read root node obj_node_info_t root; obj_node_t::read_node( infp, root ); if (root.nchildren == 1) { dbg->error( "Unmerge", "%s is not an archive (aborting)", name); fclose(infp); exit(3); } printf(" found %d files to extract\n\n", root.nchildren); // now iterate over the archive for ( int number=0; numberwarning( "Unmerge", "%s has no name! (using %s) as default", writer.c_str(), (const char *)random_name ); node_name = random_name; } string outfile = writer + "." + node_name + ".pak"; FILE* outfp = fopen(outfile.c_str(), "wb"); if (!outfp) { dbg->error( "Unmerge", "Could not open %s for writing (aborting)", outfile.c_str()); fclose(infp); exit(3); } printf(" writing '%s' ... \n", outfile.c_str()); // now copy the nodes fseek(infp, start_pos, SEEK_SET); write_header(outfp); // write the root for the new pak file obj_node_info_t root; root.nchildren = 1; root.size = 0; root.type = obj_root; write_obj_node_info_t( outfp, root ); copy_nodes(outfp, infp, root); // this advances also the input to the next position fclose(outfp); } } else { dbg->warning( "Unmerge", "Skipping file %s - version mismatch", name); } } fclose(infp); } void root_writer_t::copy_nodes(FILE* outfp, FILE* infp, obj_node_info_t& start) { for( int i=0; ifatal( "Write dat", "Cannot create destination file %s", filename ); } if (debuglevel >= log_t::LEVEL_WARN) { printf("Writing file %s\n", filename); } } for( int i=0; i==0 || i= log_t::LEVEL_WARN) { printf(" Reading file %s\n", i); } inpath = arg; string::size_type n = inpath.rfind('/'); if(n!=string::npos) { inpath = inpath.substr(0, n + 1); } else { inpath = ""; } if(generate_name) { string name(i); name.replace(name.size() - 3, 3, "expanded.dat"); outfp = fopen(name.c_str(), "wb"); if (!outfp) { dbg->fatal( "Write pak", "Cannot create destination file %s", name.c_str() ); } if (debuglevel >= log_t::LEVEL_WARN) { printf(" Writing file %s\n", name.c_str()); } } // fprintf(outfp, "# Expanded file by makeobj\n"); while(infile.read(obj, outfp)) { fprintf(outfp, "---\n"); } if(generate_name) { fclose(outfp); } } else { dbg->warning( "Write dat", "Cannot read %s", i); } } } if(!generate_name) { fclose(outfp); } } simutrans-124.3/src/simutrans/descriptor/writer/root_writer.h000066400000000000000000000034131474050137200246120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_ROOT_WRITER_H #define DESCRIPTOR_WRITER_ROOT_WRITER_H #include #include #include "obj_writer.h" #include "../objversion.h" struct obj_node_info_t; class root_writer_t : public obj_writer_t { private: static root_writer_t the_instance; static std::string inpath; root_writer_t() { register_writer(false); } void copy_nodes(FILE* outfp, FILE* infp, obj_node_info_t& info); void write_header(FILE* fp); void write_obj_node_info_t(FILE* outfp, const obj_node_info_t &root); public: void capabilites(); static root_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_root; } const char *get_type_name() const OVERRIDE { return "root"; } void write(const char* name, int argc, char* argv[]); void dump(int argc, char* argv[]); void list(int argc, char* argv[]); void copy(const char* name, int argc, char* argv[]); /** * @brief Expands makeobj pre-processor stuff * * Dat files can contain 'minified' pre-processor-like features, this * function will run the dat on the tabfile reader and return write * its output to a $filename-expanded.dat file. * * @param name Filename of the output file or folder * @param argc Number of input files * @param argv List of input files' paths */ void expand_dat(const char* name, int argc, char* argv[]); /* makes single files from a merged file */ void uncopy(const char* name); static const std::string & get_inpath() { return inpath; } private: bool do_copy(FILE* outfp, obj_node_info_t& root, const char* open_file_name); bool do_dump(const char* open_file_name); bool do_list(const char* open_file_name); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/sim_writer.cc000066400000000000000000000055641474050137200245660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "text_writer.h" #include "image_writer.h" #include "imagelist_writer.h" #include "imagelist2d_writer.h" #include "bridge_writer.h" #include "tunnel_writer.h" #include "building_writer.h" #include "roadsign_writer.h" #include "citycar_writer.h" #include "pedestrian_writer.h" #include "crossing_writer.h" #include "factory_writer.h" #include "good_writer.h" #include "ground_writer.h" #include "groundobj_writer.h" #include "way_writer.h" #include "way_obj_writer.h" #include "root_writer.h" #include "xref_writer.h" #include "skin_writer.h" #include "sound_writer.h" #include "tree_writer.h" #include "vehicle_writer.h" /** * static data * * These classes are self-registering. The linker will not notify if there is a missing class, since it * may be also instantiated in the class itself. Therefore, all classes MUST be declared here to force * the linking and raise an error if we lack any of them. */ stringhashtable_tpl* obj_writer_t::writer_by_name = NULL; inthashtable_tpl *obj_writer_t::writer_by_type = NULL; text_writer_t text_writer_t::the_instance; image_writer_t image_writer_t::the_instance; imagelist_writer_t imagelist_writer_t::the_instance; imagelist2d_writer_t imagelist2d_writer_t::the_instance; root_writer_t root_writer_t::the_instance; xref_writer_t xref_writer_t::the_instance; sound_writer_t sound_writer_t::the_instance; menuskin_writer_t menuskin_writer_t::the_instance; cursorskin_writer_t cursorskin_writer_t::the_instance; symbolskin_writer_t symbolskin_writer_t::the_instance; miscimages_writer_t miscimages_writer_t::the_instance; goods_writer_t goods_writer_t::the_instance; ground_writer_t ground_writer_t::the_instance; way_writer_t way_writer_t::the_instance; way_obj_writer_t way_obj_writer_t::the_instance; crossing_writer_t crossing_writer_t::the_instance; bridge_writer_t bridge_writer_t::the_instance; tunnel_writer_t tunnel_writer_t::the_instance; field_writer_t field_writer_t::the_instance; groundobj_writer_t groundobj_writer_t::the_instance; smoke_writer_t smoke_writer_t::the_instance; building_writer_t building_writer_t::the_instance; tile_writer_t tile_writer_t::the_instance; factory_writer_t factory_writer_t::the_instance; factory_supplier_writer_t factory_supplier_writer_t::the_instance; factory_product_writer_t factory_product_writer_t::the_instance; factory_smoke_writer_t factory_smoke_writer_t::the_instance; factory_field_group_writer_t factory_field_group_writer_t::the_instance; factory_field_class_writer_t factory_field_class_writer_t::the_instance; vehicle_writer_t vehicle_writer_t::the_instance; roadsign_writer_t roadsign_writer_t::the_instance; citycar_writer_t citycar_writer_t::the_instance; pedestrian_writer_t pedestrian_writer_t::the_instance; tree_writer_t tree_writer_t::the_instance; simutrans-124.3/src/simutrans/descriptor/writer/skin_writer.cc000066400000000000000000000020101474050137200247210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simdebug.h" #include "../../dataobj/tabfile.h" #include "../skin_desc.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist_writer.h" #include "skin_writer.h" using std::string; void skin_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { slist_tpl keys; for( int i = 0; ; i++ ) { char buf[40]; sprintf(buf, "image[%d]", i); string str = obj.get(buf); if( str.empty() ) { break; } if( debuglevel > 2 ) { printf("%10sImage[%3u] =%s\n", " ", i, str.c_str()); } keys.append(str); } write_obj(fp, parent, obj, keys); } void skin_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj, const slist_tpl& imagekeys) { slist_tpl keys; obj_node_t node(this, 0, &parent); write_head(fp, node, obj); imagelist_writer_t::instance()->write_obj(fp, node, imagekeys); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/skin_writer.h000066400000000000000000000055321474050137200245770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_SKIN_WRITER_H #define DESCRIPTOR_WRITER_SKIN_WRITER_H #include "obj_writer.h" #include "../objversion.h" #include "../../tpl/slist_tpl.h" #include class skin_writer_t : public obj_writer_t { protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj, const slist_tpl& imagekeys); obj_type get_type() const OVERRIDE = 0; const char* get_type_name() const OVERRIDE = 0; }; class menuskin_writer_t : public skin_writer_t { private: static menuskin_writer_t the_instance; menuskin_writer_t() { register_writer(true); } public: static menuskin_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_menu; } const char* get_type_name() const OVERRIDE { return "menu"; } }; class cursorskin_writer_t : public skin_writer_t { private: static cursorskin_writer_t the_instance; cursorskin_writer_t() { register_writer(true); } public: static cursorskin_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_cursor; } const char* get_type_name() const OVERRIDE { return "cursor"; } }; class symbolskin_writer_t : public skin_writer_t { private: static symbolskin_writer_t the_instance; symbolskin_writer_t() { register_writer(true); } public: static symbolskin_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_symbol; } const char* get_type_name() const OVERRIDE { return "symbol"; } }; class smoke_writer_t : public skin_writer_t { private: static smoke_writer_t the_instance; smoke_writer_t() { register_writer(true); } public: static smoke_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_smoke; } const char* get_type_name() const OVERRIDE { return "smoke"; } }; class field_writer_t : public skin_writer_t { private: static field_writer_t the_instance; field_writer_t() { register_writer(true); } public: static field_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_field; } const char* get_type_name() const OVERRIDE { return "field"; } }; /* * Used for images needed by the game but not yet integrated as real objects */ class miscimages_writer_t : public skin_writer_t { private: static miscimages_writer_t the_instance; miscimages_writer_t() { register_writer(true); } public: static miscimages_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_miscimages; } const char* get_type_name() const OVERRIDE { return "misc"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/sound_writer.cc000066400000000000000000000016241474050137200251170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "../sound_desc.h" #include "text_writer.h" #include "sound_writer.h" void sound_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { // eventual direct name input std::string str = obj.get("sound_name"); uint16 len = str.size(); obj_node_t node(this, 6+len+1, &parent); write_head(fp, node, obj); // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversioned uint16 uv16 = 0x8002; node.write_uint16(fp, uv16, 0); uv16 = obj.get_int("sound_nr", NO_SOUND); // for compatibility reasons; the old nr of a sound node.write_uint16(fp, uv16, 2); node.write_uint16(fp, len, 4); node.write_data_at(fp, str.c_str(), 6, len + 1); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/sound_writer.h000066400000000000000000000013121474050137200247530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_SOUND_WRITER_H #define DESCRIPTOR_WRITER_SOUND_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class sound_writer_t : public obj_writer_t { private: static sound_writer_t the_instance; sound_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_sound; } const char* get_type_name() const OVERRIDE { return "sound"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/text_writer.cc000066400000000000000000000014461474050137200247550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../text_desc.h" #include "obj_node.h" #include "text_writer.h" void text_writer_t::write_obj(FILE* outfp, obj_node_t& parent, const char* text) { if (!text) { text = ""; } const size_t len = strlen(text); obj_node_t node(this, len + 1, &parent); node.write_data(outfp, text); node.write(outfp); } bool text_writer_t::dump_node(FILE* infp, const obj_node_info_t& node) { if (!obj_writer_t::dump_node(infp, node)) { return false; } char *buf = new char[node.size+1]; if (!buf) { return false; } if (fread(buf, node.size, 1, infp) != 1) { delete[] buf; return false; } buf[node.size] = 0; printf(" '%s'", buf); delete[] buf; return true; } simutrans-124.3/src/simutrans/descriptor/writer/text_writer.h000066400000000000000000000013531474050137200246140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_TEXT_WRITER_H #define DESCRIPTOR_WRITER_TEXT_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class obj_node_t; class text_writer_t : public obj_writer_t { private: static text_writer_t the_instance; text_writer_t() { register_writer(false); } public: static text_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_text; } const char* get_type_name() const OVERRIDE { return "text"; } bool dump_node(FILE *infp, const obj_node_info_t& node) OVERRIDE; void write_obj(FILE *fp, obj_node_t& parent, const char* text); }; #endif simutrans-124.3/src/simutrans/descriptor/writer/tree_writer.cc000066400000000000000000000034461474050137200247320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "text_writer.h" #include "imagelist2d_writer.h" #include "get_climate.h" #include "tree_writer.h" using std::string; void tree_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 6, &parent); write_head(fp, node, obj); climate_bits allowed_climates; const char *climate_str = obj.get("climates"); if (climate_str) { allowed_climates = get_climate_bits(climate_str); } else { printf("WARNING: old syntax without climates!\n"); allowed_climates = all_but_arctic_climate; } // seasons = 1: no seasons // seasons = 2: 0=summer, 1=winter // seasons = 4, normal four seasons, starting with summer // seasons = 5, normal four seasons and snowy image uint8 const number_of_seasons = obj.get_int("seasons", 1); uint8 const distribution_weight = obj.get_int("distributionweight", 3); slist_tpl > keys; for (unsigned int age = 0; age < 5; age++) { keys.append(); for (int seasons = 0; seasons < number_of_seasons; seasons++) { char buf[40]; // Images of the tree // age is 1..5 (usually five stages, seasons is the seaons sprintf(buf, "image[%d][%d]", age, seasons); string str = obj.get(buf); if (str.empty()) { // else missing image dbg->fatal( "Tree", "Missing %s!", buf); } keys.at(age).append(str); } } imagelist2d_writer_t::instance()->write_obj(fp, node, keys); // write version data node.write_uint16(fp, 0x8002, 0); node.write_uint16(fp, allowed_climates, 2); node.write_uint8( fp, distribution_weight, 4); node.write_uint8( fp, number_of_seasons, 5); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/tree_writer.h000066400000000000000000000013031474050137200245620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_TREE_WRITER_H #define DESCRIPTOR_WRITER_TREE_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class tree_writer_t : public obj_writer_t { private: static tree_writer_t the_instance; tree_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_tree; } const char* get_type_name() const OVERRIDE { return "tree"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/tunnel_writer.cc000066400000000000000000000073151474050137200252770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "../../dataobj/ribi.h" #include "../tunnel_desc.h" #include "obj_node.h" #include "text_writer.h" #include "xref_writer.h" #include "imagelist_writer.h" #include "skin_writer.h" #include "get_waytype.h" #include "tunnel_writer.h" using std::string; void tunnel_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { obj_node_t node(this, 24, &parent); sint32 topspeed = obj.get_int("topspeed", 999); uint32 price = obj.get_int("cost", 0); uint32 maintenance = obj.get_int("maintenance", 1000); uint8 wtyp = get_waytype(obj.get("waytype")); uint16 axle_load = obj.get_int("axle_load", 9999); // timeline uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro_date += obj.get_int("intro_month", 1) - 1; uint16 retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire_date += obj.get_int("retire_month", 1) - 1; // predefined string for directions static const char* const indices[] = { "n", "s", "e", "w" }; static const char* const add[] = { "", "l", "r", "m" }; char buf[40]; // Check for seasons sint8 number_of_seasons = 0; sprintf(buf, "%simage[%s][1]", "front", indices[0]); string str = obj.get(buf); if( str.size() != 0 ) { // Snow images are present. number_of_seasons = 1; } // Check for broad portals uint8 number_portals = 1; sprintf(buf, "%simage[%s%s][0]", "front", indices[0], add[1]); str = obj.get(buf); if (str.empty()) { // Test short version sprintf(buf, "%simage[%s%s]", "front", indices[0], add[1]); str = obj.get(buf); } if( str.size() != 0 ) { number_portals = 4; } // Version uses always high bit set as trigger // version 4: snow images + underground way image + broad portals uint16 version = 0x8005; node.write_uint16(fp, version, 0); node.write_sint32(fp, topspeed, 2); node.write_uint32(fp, price, 6); node.write_uint32(fp, maintenance, 10); node.write_uint8 (fp, wtyp, 14); node.write_uint16(fp, intro_date, 15); node.write_uint16(fp, retire_date, 17); node.write_uint16(fp, axle_load, 19); node.write_sint8(fp, number_of_seasons, 21); // has was (uint8) is here but filled later node.write_sint8(fp, (number_portals==4), 23); write_head(fp, node, obj); // and now the images slist_tpl backkeys; slist_tpl frontkeys; slist_tpl cursorkeys; cursorkeys.append(string(obj.get("cursor"))); cursorkeys.append(string(obj.get("icon"))); for( uint8 season = 0; season <= number_of_seasons; season++ ) { for( uint8 pos = 0; pos < 2; pos++ ) { for( uint8 j = 0; j < number_portals; j++ ) { for( uint8 i = 0; i < 4; i++ ) { sprintf(buf, "%simage[%s%s][%d]", pos ? "back" : "front", indices[i], add[j], season); string str = obj.get(buf); if (str.empty() && season == 0) { // Test also the short version. sprintf(buf, "%simage[%s%s]", pos ? "back" : "front", indices[i], add[j]); str = obj.get(buf); } (pos ? &backkeys : &frontkeys)->append(str); } } } imagelist_writer_t::instance()->write_obj(fp, node, backkeys); imagelist_writer_t::instance()->write_obj(fp, node, frontkeys); backkeys.clear(); frontkeys.clear(); if(season == 0) { cursorskin_writer_t::instance()->write_obj(fp, node, obj, cursorkeys); } } str = obj.get("way"); if (!str.empty()) { xref_writer_t::instance()->write_obj(fp, node, obj_way, str.c_str(), false); node.write_sint8(fp, 1, 22); } else { node.write_sint8(fp, 0, 22); } cursorkeys.clear(); node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/tunnel_writer.h000066400000000000000000000013211474050137200251300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_TUNNEL_WRITER_H #define DESCRIPTOR_WRITER_TUNNEL_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class tunnel_writer_t : public obj_writer_t { private: static tunnel_writer_t the_instance; tunnel_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_tunnel; } const char* get_type_name() const OVERRIDE { return "tunnel"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/vehicle_writer.cc000066400000000000000000000241731474050137200254120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../../utils/simstring.h" #include "../../dataobj/tabfile.h" #include "../vehicle_desc.h" #include "../sound_desc.h" #include "obj_pak_exception.h" #include "obj_node.h" #include "text_writer.h" #include "xref_writer.h" #include "imagelist_writer.h" #include "imagelist2d_writer.h" #include "get_waytype.h" #include "vehicle_writer.h" using std::string; /** * Calculate numeric engine type from engine type string */ static vehicle_desc_t::engine_t get_engine_type(char const* const engine_type) { vehicle_desc_t::engine_t uv8 = vehicle_desc_t::diesel; if (!STRICMP(engine_type, "diesel")) { uv8 = vehicle_desc_t::diesel; } else if (!STRICMP(engine_type, "electric")) { uv8 = vehicle_desc_t::electric; } else if (!STRICMP(engine_type, "steam")) { uv8 = vehicle_desc_t::steam; } else if (!STRICMP(engine_type, "bio")) { uv8 = vehicle_desc_t::bio; } else if (!STRICMP(engine_type, "sail")) { uv8 = vehicle_desc_t::sail; } else if (!STRICMP(engine_type, "fuel_cell")) { uv8 = vehicle_desc_t::fuel_cell; } else if (!STRICMP(engine_type, "hydrogene")) { uv8 = vehicle_desc_t::hydrogene; } else if (!STRICMP(engine_type, "battery")) { uv8 = vehicle_desc_t::battery; } else if (!STRICMP(engine_type, "unknown")) { uv8 = vehicle_desc_t::unknown; } // printf("Engine type %s -> %d\n", engine_type, uv8); return uv8; } /** * Writes vehicle node data to file */ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) { int i; uint8 uv8; int total_len = 41; // must be done here, since it may affect the len of the header! string sound_str = ltrim( obj.get("sound") ); sint8 sound_id=NO_SOUND; if (!sound_str.empty()) { // ok, there is some sound sound_id = atoi(sound_str.c_str()); if (sound_id == 0 && sound_str[0] == '0') { sound_id = 0; sound_str = ""; } else if (sound_id != 0) { // old style id sound_str = ""; } if (!sound_str.empty()) { sound_id = LOAD_SOUND; total_len += sound_str.size() + 1; } } obj_node_t node(this, total_len, &parent); write_head(fp, node, obj); uint16 pos = 0; // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversioned uint16 version = 0x800B; node.write_uint16(fp, version, pos); pos += sizeof(uint16); // Price of this vehicle in cent uint32 price = obj.get_int("cost", 0); node.write_uint32(fp, price, pos); pos += sizeof(uint32); // Maximum payload of this vehicle uint16 capacity = obj.get_int("payload", 0); node.write_uint16(fp, capacity, pos); pos += sizeof(uint16); // ms per loading/unloading everything uint16 loading_time = obj.get_int("loading_time", 1000 ); node.write_uint16(fp, loading_time, pos); pos += sizeof(uint16); // Top speed of this vehicle. Must be greater than 0 uint16 topspeed = obj.get_int("speed", 0); node.write_uint16(fp, topspeed, pos); pos += sizeof(uint16); // Total weight of this vehicle in tons const char *weight_str = obj.get("weight"); uint32 weight = (uint32)(atof( weight_str )*1000.0 + 0.5); node.write_uint32(fp, weight, pos); pos += sizeof(uint32); // axle_load (determine ways usage) uint16 axle_load = obj.get_int("axle_load", 0); node.write_uint16(fp, axle_load, pos); pos += sizeof(uint16); // Power of this vehicle in KW uint32 power = obj.get_int("power", 0); node.write_uint32(fp, power, pos); pos += sizeof(uint32); // Running costs, given in cent per square uint16 running_cost = obj.get_int("runningcost", 0); node.write_uint16(fp, running_cost, pos); pos += sizeof(uint16); // monthly maintenance uint32 fixed_cost = obj.get_int("fixed_cost", 0xFFFFFFFFul ); if( fixed_cost == 0xFFFFFFFFul ) { fixed_cost = obj.get_int("maintenance", 0); } node.write_uint32(fp, fixed_cost, pos); pos += sizeof(uint32); // Introduction date (year * 12 + month) uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro_date += obj.get_int("intro_month", 1) - 1; node.write_uint16(fp, intro_date, pos); pos += sizeof(uint16); // retire date (year * 12 + month) uint16 retire_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire_date += obj.get_int("retire_month", 1) - 1; node.write_uint16(fp, retire_date, pos); pos += sizeof(uint16); // Engine gear (power multiplier) uint16 gear = (obj.get_int("gear", 100) * 64) / 100; node.write_uint16(fp, gear, pos); pos += sizeof(uint16); // Type of way this vehicle drives on char const* const waytype_name = obj.get("waytype"); waytype_t const waytype = get_waytype(waytype_name); uv8 = waytype != overheadlines_wt ? waytype : track_wt; node.write_uint8(fp, uv8, pos); pos += sizeof(uint8); // sound id byte node.write_sint8(fp, sound_id, pos); pos += sizeof(uint8); // engine if (waytype == overheadlines_wt) { // compatibility for old style DAT files uv8 = vehicle_desc_t::electric; } else { const char* engine_type = obj.get("engine_type"); uv8 = get_engine_type(engine_type); } node.write_uint8(fp, uv8, pos); pos += sizeof(uint8); // the length (default 8) uint8 length = obj.get_int("length", 8); node.write_uint8(fp, length, pos); pos += sizeof(uint8); // The freight type const char* freight = obj.get("freight"); if (!*freight) { freight = "None"; } xref_writer_t::instance()->write_obj(fp, node, obj_good, freight, true); xref_writer_t::instance()->write_obj(fp, node, obj_smoke, obj.get("smoke"), false); // Now comes the Image-list static const char* const dir_codes[] = { "s", "w", "sw", "se", "n", "e", "ne", "nw" }; slist_tpl emptykeys; slist_tpl > freightkeys; slist_tpl freightkeys_old; string str; int freight_image_type = 0; bool has_8_images = false; // first: find out how many freight? for (i = 0; i < 127; i++) { char buf[40]; sprintf(buf, "freightimage[%d][%s]", i, dir_codes[0]); str = obj.get(buf); if (str.empty()) { freight_image_type = i; break; } } // now load the images strings for (i = 0; i < 8; i++) { char buf[40]; // Empty vehicle image for direction, direction in "s", "w", "sw", "se", unsymmetrical vehicles need also "n", "e", "ne", "nw" sprintf(buf, "emptyimage[%s]", dir_codes[i]); str = obj.get(buf); if (!str.empty()) { emptykeys.append(str); if (i >= 4) { has_8_images = true; } } else { // stop when empty string is found break; } if (freight_image_type == 0) { // a single freight image // old style definition - just [direction] sprintf(buf, "freightimage[%s]", dir_codes[i]); str = obj.get(buf); if (!str.empty()) { freightkeys_old.append(str); } } else { freightkeys.append(); for(int freight = 0; freight < freight_image_type; freight++) { sprintf(buf, "freightimage[%d][%s]", freight, dir_codes[i]); str = obj.get(buf); if (str.empty()) { dbg->fatal( "Vehicle", "Missing freightimage[%d][%s]!", freight, dir_codes[i]); } freightkeys.at(i).append(str); } } } // added more error checks if (has_8_images && emptykeys.get_count() < 8) { dbg->fatal( "Vehicle", "Missing images (must be either 4 or 8 directions (but %i found)!)", emptykeys.get_count()); } if (!freightkeys_old.empty() && emptykeys.get_count() != freightkeys_old.get_count()) { dbg->fatal( "Vehicle", "Missing freigthimages (must be either 4 or 8 directions (but %i found)!)", freightkeys_old.get_count()); } imagelist_writer_t::instance()->write_obj(fp, node, emptykeys); if (freight_image_type > 0) { imagelist2d_writer_t::instance()->write_obj(fp, node, freightkeys); } else { if (freightkeys_old.get_count() == emptykeys.get_count()) { imagelist_writer_t::instance()->write_obj(fp, node, freightkeys_old); } else { // really empty list ... xref_writer_t::instance()->write_obj(fp, node, obj_imagelist, "", false); } } // // following/leader vehicle constrains // uint8 leader_count = 0; bool found; do { char buf[40]; // Constraints for previous vehicles, "none" means only suitable at front of an convoi sprintf(buf, "constraint[prev][%d]", leader_count); str = obj.get(buf); found = !str.empty(); if (found) { if (!STRICMP(str.c_str(), "none")) { str = ""; } xref_writer_t::instance()->write_obj(fp, node, obj_vehicle, str.c_str(), false); leader_count++; } } while (found); uint8 trailer_count = 0; do { char buf[40]; // Constraints for next vehicle, "none" to disallow any followers sprintf(buf, "constraint[next][%d]", trailer_count); str = obj.get(buf); found = !str.empty(); if (found) { if (!STRICMP(str.c_str(), "none")) { str = ""; } xref_writer_t::instance()->write_obj(fp, node, obj_vehicle, str.c_str(), false); trailer_count++; } } while (found); // multiple freight image types - define what good uses each index // good without index will be an error for (i = 0; i <= freight_image_type; i++) { char buf[40]; sprintf(buf, "freightimagetype[%d]", i); str = obj.get(buf); if (i == freight_image_type) { // check for superfluous definitions if (str.size() > 0) { dbg->warning( obj_writer_t::last_name, "More freightimagetype (%i) than freight_images (%i)!", i, freight_image_type); fflush(NULL); } break; } if (str.size() == 0) { dbg->fatal( obj_writer_t::last_name, "Missing freightimagetype[%i] for %i freight_images!", i, freight_image_type + 1); } xref_writer_t::instance()->write_obj(fp, node, obj_good, str.c_str(), false); } // if no index defined then add default as vehicle good // if not using freight images then store zero string if (freight_image_type > 0) { xref_writer_t::instance()->write_obj(fp, node, obj_good, freight, false); } node.write_sint8(fp, leader_count, pos); pos += sizeof(uint8); node.write_sint8(fp, trailer_count, pos); pos += sizeof(uint8); node.write_uint8(fp, (uint8) freight_image_type, pos); pos += sizeof(uint8); sint8 sound_str_len = sound_str.size(); if (sound_str_len > 0) { node.write_sint8 (fp, sound_str_len, pos); pos += sizeof(uint8); node.write_data_at(fp, sound_str.c_str(), pos, sound_str_len); pos += sound_str_len; } node.write(fp); } simutrans-124.3/src/simutrans/descriptor/writer/vehicle_writer.h000066400000000000000000000013761474050137200252540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_VEHICLE_WRITER_H #define DESCRIPTOR_WRITER_VEHICLE_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class vehicle_writer_t : public obj_writer_t { private: static vehicle_writer_t the_instance; vehicle_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: /// Writes vehicle node data to file void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_vehicle; } const char *get_type_name() const OVERRIDE { return "vehicle"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/way_obj_writer.cc000066400000000000000000000075221474050137200254240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "obj_node.h" #include "obj_pak_exception.h" #include "../way_obj_desc.h" #include "text_writer.h" #include "imagelist_writer.h" #include "skin_writer.h" #include "get_waytype.h" #include "way_obj_writer.h" using std::string; /** * Write a way object (lamps, overheadwires) */ void way_obj_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) { static const char* const ribi_codes[26] = { "-", "n", "e", "ne", "s", "ns", "se", "nse", "w", "nw", "ew", "new", "sw", "nsw", "sew", "nsew", "nse1", "new1", "nsw1", "sew1", "nsew1", // different crossings: northwest/southeast is oneway "nse2", "new2", "nsw2", "sew2", "nsew2", }; int ribi, slope; obj_node_t node(this, 20, &parent); // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend uint16 version = 0x8001; uint32 price = obj.get_int("cost", 100); uint32 maintenance = obj.get_int("maintenance", 100); sint32 topspeed = obj.get_int("topspeed", 999); uint16 intro = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro += obj.get_int("intro_month", 1) - 1; uint16 retire = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire += obj.get_int("retire_month", 1) - 1; uint8 wtyp = get_waytype(obj.get("waytype")); uint8 own_wtyp = get_waytype(obj.get("own_waytype")); node.write_uint16(outfp, version, 0); node.write_uint32(outfp, price, 2); node.write_uint32(outfp, maintenance, 6); node.write_sint32(outfp, topspeed, 10); node.write_uint16(outfp, intro, 14); node.write_uint16(outfp, retire, 16); node.write_uint8 (outfp, wtyp, 18); node.write_uint8 (outfp, own_wtyp, 19); write_head(outfp, node, obj); slist_tpl front_list; slist_tpl back_list; for (ribi = 0; ribi < lengthof(ribi_codes); ribi++) { char buf[40]; sprintf(buf, "frontimage[%s]", ribi_codes[ribi]); string str = obj.get(buf); front_list.append(str); sprintf(buf, "backimage[%s]", ribi_codes[ribi]); string str2 = obj.get(buf); back_list.append(str2); } imagelist_writer_t::instance()->write_obj(outfp, node, front_list); imagelist_writer_t::instance()->write_obj(outfp, node, back_list); front_list.clear(); back_list.clear(); for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "frontimageup[%d]", slope ); string str = obj.get(buf); front_list.append(str); sprintf( buf, "backimageup[%d]", slope ); string str2 = obj.get(buf); back_list.append(str2); } for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "frontimageup2[%d]", slope ); string str = obj.get(buf); if( !str.empty() ) { front_list.append(str); } sprintf( buf, "backimageup2[%d]", slope ); string str2 = obj.get(buf); if( !str2.empty() ) { back_list.append(str2); } } imagelist_writer_t::instance()->write_obj(outfp, node, front_list); imagelist_writer_t::instance()->write_obj(outfp, node, back_list); front_list.clear(); back_list.clear(); for (ribi = 3; ribi <= 12; ribi += 3) { char buf[40]; sprintf(buf, "frontdiagonal[%s]", ribi_codes[ribi]); string str = obj.get(buf); front_list.append(str); sprintf(buf, "backdiagonal[%s]", ribi_codes[ribi]); string str2 = obj.get(buf); back_list.append(str2); } imagelist_writer_t::instance()->write_obj(outfp, node, front_list); imagelist_writer_t::instance()->write_obj(outfp, node, back_list); slist_tpl cursorkeys; cursorkeys.append(string(obj.get("cursor"))); cursorkeys.append(string(obj.get("icon"))); cursorskin_writer_t::instance()->write_obj(outfp, node, obj, cursorkeys); // node.write_data(fp, &desc); node.write(outfp); } simutrans-124.3/src/simutrans/descriptor/writer/way_obj_writer.h000066400000000000000000000014051474050137200252600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_WAY_OBJ_WRITER_H #define DESCRIPTOR_WRITER_WAY_OBJ_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class way_obj_writer_t : public obj_writer_t { private: static way_obj_writer_t the_instance; way_obj_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE *fp) const OVERRIDE { return name_from_next_node(fp); } public: /// Write a way-object description node void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_way_obj; } const char *get_type_name() const OVERRIDE { return "way-object"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/way_writer.cc000066400000000000000000000144211474050137200245660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../dataobj/tabfile.h" #include "../../utils/simstring.h" #include "obj_node.h" #include "obj_pak_exception.h" #include "../way_desc.h" #include "text_writer.h" #include "imagelist_writer.h" #include "skin_writer.h" #include "get_waytype.h" #include "way_writer.h" using std::string; /** * Write a waytype description node */ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) { static const char* const ribi_codes[26] = { "-", "n", "e", "ne", "s", "ns", "se", "nse", "w", "nw", "ew", "new", "sw", "nsw", "sew", "nsew", "nse1", "new1", "nsw1", "sew1", "nsew1", // different crossings: northwest/southeast is straight "nse2", "new2", "nsw2", "sew2", "nsew2", }; int ribi, slope; obj_node_t node(this, 28, &parent); // Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend uint16 version = 0x8006; uint32 price = obj.get_int("cost", 100); uint32 maintenance = obj.get_int("maintenance", 100); sint32 topspeed = obj.get_int("topspeed", 999); uint32 max_weight = obj.get_int("max_weight", 999); uint16 axle_load = obj.get_int("axle_load", 9999); uint16 intro = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro += obj.get_int("intro_month", 1) - 1; uint16 retire = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12; retire += obj.get_int("retire_month", 1) - 1; uint8 wtyp = get_waytype(obj.get("waytype")); uint8 styp = obj.get_int("system_type", 0); // compatibility conversions if (wtyp == track_wt && styp == 5) { wtyp = monorail_wt; } else if (wtyp == track_wt && styp == 7) { wtyp = tram_wt; } // true to draw as foregrund and not much earlier (default) uint8 draw_as_ding = (obj.get_int("draw_as_ding", 0) == 1); sint8 number_of_seasons = 0; node.write_uint16(outfp, version, 0); node.write_uint32(outfp, price, 2); node.write_uint32(outfp, maintenance, 6); node.write_sint32(outfp, topspeed, 10); node.write_uint32(outfp, max_weight, 14); node.write_uint16(outfp, intro, 18); node.write_uint16(outfp, retire, 20); node.write_uint16(outfp, axle_load, 22); node.write_uint8 (outfp, wtyp, 24); node.write_uint8 (outfp, styp, 25); node.write_uint8 (outfp, draw_as_ding, 26); static const char* const image_type[] = { "", "front" }; slist_tpl keys; char buf[40]; sprintf(buf, "image[%s][0]", ribi_codes[0]); string str = obj.get(buf); if (str.empty()) { node.write_data_at(outfp, &number_of_seasons, 27, 1); write_head(outfp, node, obj); sprintf(buf, "image[%s]", ribi_codes[0]); string str = obj.get(buf); if (str.empty()) { dbg->fatal("way_writer_t::write_obj", "image with label %s missing", buf); } for(int backtofront = 0; backtofront<2; backtofront++) { // way images defined without seasons char buf[40]; sprintf(buf, "%simage[new2]", image_type[backtofront]); // test for switch images const uint8 ribinr = *(obj.get(buf))==0 ? 16 : 26; for (ribi = 0; ribi < ribinr; ribi++) { char buf[40]; sprintf(buf, "%simage[%s]", image_type[backtofront], ribi_codes[ribi]); string str = obj.get(buf); keys.append(str); } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "%simageup[%d]", image_type[backtofront], slope ); string str = obj.get(buf); keys.append(str); } for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "%simageup2[%d]", image_type[backtofront], slope ); string str = obj.get(buf); if( !str.empty() ) { keys.append(str); } } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); for (ribi = 3; ribi <= 12; ribi += 3) { char buf[40]; sprintf(buf, "%sdiagonal[%s]", image_type[backtofront], ribi_codes[ribi]); string str = obj.get(buf); keys.append(str); } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); if(backtofront == 0) { slist_tpl cursorkeys; cursorkeys.append(string(obj.get("cursor"))); cursorkeys.append(string(obj.get("icon"))); cursorskin_writer_t::instance()->write_obj(outfp, node, obj, cursorkeys); } } } else { sprintf(buf, "image[%s][%d]", ribi_codes[0], number_of_seasons+1); if (!strempty(obj.get(buf))) { number_of_seasons++; } node.write_data_at(outfp, &number_of_seasons, 27, 1); write_head(outfp, node, obj); // has switch images for both directions? const uint8 ribinr = *(obj.get("image[new2][0]"))==0 ? 16 : 26; for(int backtofront = 0; backtofront<2; backtofront++) { for (uint8 season = 0; season <= number_of_seasons ; season++) { for (ribi = 0; ribi < ribinr; ribi++) { char buf[40]; sprintf(buf, "%simage[%s][%d]", image_type[backtofront], ribi_codes[ribi], season); string str = obj.get(buf); keys.append(str); } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "%simageup[%d][%d]", image_type[backtofront], slope, season ); string str = obj.get(buf); keys.append(str); } for( slope = 3; slope <= 12; slope += 3 ) { char buf[40]; sprintf( buf, "%simageup2[%d][%d]", image_type[backtofront], slope, season ); string str = obj.get(buf); if( !str.empty() ) { keys.append(str); } } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); for (ribi = 3; ribi <= 12; ribi += 3) { char buf[40]; sprintf(buf, "%sdiagonal[%s][%d]", image_type[backtofront], ribi_codes[ribi], season); string str = obj.get(buf); keys.append(str); } imagelist_writer_t::instance()->write_obj(outfp, node, keys); keys.clear(); if(season == 0 && backtofront == 0) { slist_tpl cursorkeys; cursorkeys.append(string(obj.get("cursor"))); cursorkeys.append(string(obj.get("icon"))); cursorskin_writer_t::instance()->write_obj(outfp, node, obj, cursorkeys); } } } } node.write(outfp); } simutrans-124.3/src/simutrans/descriptor/writer/way_writer.h000066400000000000000000000013421474050137200244260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_WAY_WRITER_H #define DESCRIPTOR_WRITER_WAY_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class way_writer_t : public obj_writer_t { private: static way_writer_t the_instance; way_writer_t() { register_writer(true); } protected: std::string get_node_name(FILE* fp) const OVERRIDE { return name_from_next_node(fp); } public: /// Write a waytype descriptor node void write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj) OVERRIDE; obj_type get_type() const OVERRIDE { return obj_way; } const char* get_type_name() const OVERRIDE { return "way"; } }; #endif simutrans-124.3/src/simutrans/descriptor/writer/xref_writer.cc000066400000000000000000000021621474050137200247310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../text_desc.h" #include "obj_node.h" #include "xref_writer.h" void xref_writer_t::write_obj(FILE* outfp, obj_node_t& parent, obj_type type, const char* text, bool fatal) { if (!text) { text = ""; } int len = strlen(text); obj_node_t node( this, sizeof(char) + // Fatal-Flag sizeof(obj_type) + // type of dest node len + 1, // 0-terminated name of dest node &parent ); char c = fatal ? 1 : 0; node.write_uint32(outfp, (uint32) type, 0); node.write_uint8 (outfp, c, 4); node.write_data_at(outfp, text, 5, len + 1); node.write(outfp); } bool xref_writer_t::dump_node(FILE* infp, const obj_node_info_t& node) { if (!obj_writer_t::dump_node(infp, node)) { return false; } if( node.size<5 ) { return false; } char* buf = new char[node.size+1]; buf[node.size] = 0; if (fread(buf, node.size, 1, infp) != 1) { delete[] buf; return false; } printf(" -> %4.4s-node (%s) '%s'", buf, buf[4] ? "required" : "optional", buf+5 ); delete[] buf; return true; } simutrans-124.3/src/simutrans/descriptor/writer/xref_writer.h000066400000000000000000000014061474050137200245730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_WRITER_XREF_WRITER_H #define DESCRIPTOR_WRITER_XREF_WRITER_H #include #include "obj_writer.h" #include "../objversion.h" class obj_node_t; class xref_writer_t : public obj_writer_t { private: static xref_writer_t the_instance; xref_writer_t() { register_writer(false); } public: static xref_writer_t* instance() { return &the_instance; } obj_type get_type() const OVERRIDE { return obj_xref; } const char *get_type_name() const OVERRIDE { return "xref"; } void write_obj(FILE *fp, obj_node_t& parent, obj_type type, const char* text, bool fatal); bool dump_node(FILE *infp, const obj_node_info_t& node) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/descriptor/xref_desc.h000066400000000000000000000006751474050137200226700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DESCRIPTOR_XREF_DESC_H #define DESCRIPTOR_XREF_DESC_H #include "obj_desc.h" #include "objversion.h" class xref_desc_t : public obj_desc_t { public: const char* get_name() const { return name; } using obj_desc_t::operator new; private: obj_type type; bool fatal; char name[]; friend class xref_reader_t; }; #endif simutrans-124.3/src/simutrans/display/000077500000000000000000000000001474050137200200345ustar00rootroot00000000000000simutrans-124.3/src/simutrans/display/clip_num.h000066400000000000000000000025441474050137200220200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_CLIP_NUM_H #define DISPLAY_CLIP_NUM_H #include "../simtypes.h" /** * Macros to pass clip_num parameter around for * multi-threaded drawing. */ #ifdef MULTI_THREAD #define CLIP_NUM_VAR clip_num #define CLIP_NUM_PDECL const sint8 #define CLIP_NUM_DEFAULT_VALUE 0 #define CLIP_NUM_COMMA , #define CLIP_NUM_DEFAULT_ZERO = CLIP_NUM_DEFAULT_VALUE #define CLIP_NUM_INDEX [clip_num] #else #define CLIP_NUM_VAR #define CLIP_NUM_PDECL #define CLIP_NUM_COMMA #define CLIP_NUM_DEFAULT_VALUE #define CLIP_NUM_DEFAULT_ZERO #define CLIP_NUM_INDEX #endif /// parameter declaration to be used as first parameter #define CLIP_NUM_DEF0 CLIP_NUM_PDECL CLIP_NUM_VAR /// parameter declaration to be used as non-first parameter #define CLIP_NUM_DEF CLIP_NUM_COMMA CLIP_NUM_DEF0 /// parameter declaration to be used as first parameter, no variable name #define CLIP_NUM_DEF_NOUSE0 CLIP_NUM_PDECL /// parameter declaration to be used as non-first parameter, no variable name #define CLIP_NUM_DEF_NOUSE CLIP_NUM_COMMA CLIP_NUM_DEF_NOUSE0 /// pass clip_num as parameter #define CLIP_NUM_PAR CLIP_NUM_COMMA CLIP_NUM_VAR /// default value for passing clip_num around #define CLIP_NUM_DEFAULT CLIP_NUM_COMMA CLIP_NUM_DEFAULT_VALUE #endif simutrans-124.3/src/simutrans/display/font.cc000066400000000000000000000275311474050137200213210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "font.h" #include "../macros.h" #include "../simdebug.h" #include "../sys/simsys.h" #include "../simtypes.h" #include "../utils/simstring.h" #if COLOUR_DEPTH != 0 #include "../dataobj/environment.h" #endif #include #include #include #include #include font_t::glyph_t::glyph_t() : height(0), width(0), advance(0xFF), top(0) { bitmap = 0; } font_t::font_t() : linespace (0), descent(0) { fname[0] = 0; } #if 0 // FIXME /// Decodes a single line of a glyph static void dsp_decode_bdf_data_row(font_t::glyph_t *target, int y, int xoff, int g_width, const char *str) { char buf[3]; buf[0] = str[0]; buf[1] = str[1]; buf[2] = '\0'; uint16 data = (uint16)strtol(buf, NULL, 16)<<8; // read second byte but use only first nibble if( g_width > 8 ) { buf[0] = str[2]; buf[1] = str[3]; buf[2] = '\0'; data |= strtol(buf, NULL, 16); } data >>= xoff; // now store them, and the second nibble store interleaved target->bitmap[y] = data>>8; if( g_width+xoff > 8 ) { target->bitmap[y+GLYPH_BITMAP_HEIGHT] = data; } } /// Reads a single glyph. /// @returns index of glyph successfully read, or -1 on error static sint32 dsp_read_bdf_glyph(FILE *bdf_file, std::vector &data, int glyph_limit, int f_height, int f_desc) { sint32 glyph_nr = 0; int g_width = 0, h = 0, g_desc = 0; int glyph_advance = -1; int xoff = 0; while( !feof(bdf_file) ) { char str[256]; if( fgets(str, sizeof(str), bdf_file)==NULL && !feof(bdf_file) ) { return -1; } // encoding (sint8 number) in decimal if( strstart(str, "ENCODING") ) { glyph_nr = atoi(str + 8); if( glyph_nr <= 0 || glyph_nr >= glyph_limit ) { dbg->error("dsp_read_bdf_glyph", "Unexpected glyph (%i) for %i glyph font!\n", glyph_nr, glyph_limit); glyph_nr = 0; } continue; } // information over size and coding if( strstart(str, "BBX") ) { sscanf(str + 3, "%d %d %d %d", &g_width, &h, &xoff, &g_desc); continue; } // information over size and coding if( strstart(str, "DWIDTH") ) { glyph_advance = atoi(str + 6); continue; } // start if bitmap data if (strstart(str, "BITMAP")) { const int top = f_height + f_desc - h - g_desc; // maximum size GLYPH_HEIGHT pixels h = min(h + top, (int)GLYPH_BITMAP_HEIGHT); // read for height times for (int y = top; y < h; y++) { if( fgets(str, sizeof(str), bdf_file)==NULL && !feof(bdf_file) ) { return -1; } if( y>=0 ) { dsp_decode_bdf_data_row(&data[glyph_nr], y, xoff, g_width, str); } } continue; } // finally add width information (width = 0: not there!) if( strstart(str, "ENDCHAR") ) { uint8 start_h = 0; // find the start offset for( uint8 i=0; iwarning( "dsp_read_bdf_glyph", "BDF warning: Glyph %i has no advance (screen width) assigned!\n", glyph_nr); glyph_advance = g_width + 1; } data[glyph_nr].advance = glyph_advance; // finished return glyph_nr; } } return -1; } bool font_t::load_from_bdf(FILE *bdf_file) { dbg->message("font_t::load_from_bdf", "Loading BDF font '%s'", fname); glyphs.clear(); uint32 f_height = 0; int f_desc = 0; int f_numglyphs = 0; sint32 max_glyph = 0; while( !feof(bdf_file) ) { char str[256]; if( fgets(str, sizeof(str), bdf_file)==NULL && !feof(bdf_file) ) { return false; } if( strstart(str, "FONTBOUNDINGBOX") ) { sscanf(str + 15, "%*d %d %*d %d", &f_height, &f_desc); continue; } if( strstart(str, "CHARS") && str[5] <= ' ' ) { // the characters 0xFFFF and 0xFFFE are guaranteed to be non-unicode characters f_numglyphs = atoi(str + 5) <= 0x100 ? 0x100 : 0xFFFE; glyphs.resize(max(f_numglyphs, 0)); glyphs[(uint32)' '].advance = clamp(f_height / 2, 3u, GLYPH_BITMAP_HEIGHT); continue; } if( strstart(str, "STARTCHAR") && f_numglyphs > 0 ) { const sint32 glyph = dsp_read_bdf_glyph(bdf_file, glyphs, f_numglyphs, f_height, f_desc); max_glyph = max(max_glyph, glyph); continue; } } // ok, was successful? if( f_numglyphs <= 0 ) { return false; } // init default glyph for missing glyphs (just a box) const int real_font_height = min(f_height, (int)GLYPH_BITMAP_HEIGHT); int h = 2; glyphs[0].bitmap[1] = 0x7E; // 0111 1110 for( ; h < real_font_height-2; h++ ) { glyphs[0].bitmap[h] = 0x42; // 0100 0010 } glyphs[0].bitmap[h++] = 0x7E; // 0111 1110 glyphs[0].yoff = 1; // y-offset glyphs[0].width = 7; // real width glyphs[0].advance = 8; linespace = f_height; descent = f_desc; // Use only needed amount glyphs.resize( (uint32)max_glyph+1 ); return true; } #endif #if COLOUR_DEPTH != 0 #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_TRUETYPE_TABLES_H #include FT_BITMAP_H bool font_t::load_from_freetype(const char *fname, int pixel_height) { dbg->message( "font_t::load_from_freetype", "trying to load '%s' in size %d", fname, pixel_height); FT_Library ft_library = NULL; if( FT_Init_FreeType(&ft_library) != FT_Err_Ok ) { dbg->error( "font_t::load_from_freetype", "Freetype initialization failed" ); return false; } // Ok, we guessed something about the filename, now actually load it FT_Face face; if( FT_New_Face( ft_library, fname, 0, &face ) != FT_Err_Ok ) { dbg->warning( "font_t::load_from_freetype", "Cannot load %s", fname ); FT_Done_FreeType( ft_library ); return false; } if( FT_Set_Pixel_Sizes( face, 0, pixel_height ) != FT_Err_Ok ) { dbg->warning( "font_t::load_from_freetype", "Cannot set pixel size %d for %s", pixel_height, fname); // try to find closest available pixel_height int best = -1; for (int i=0; inum_fixed_sizes; i++) { int h = (face->available_sizes[i].y_ppem + 32) >> 6; if (best == -1 || abs(best - pixel_height) > abs(h - pixel_height)) { best = h; } } if (best == -1) { // failed FT_Done_Face(face); FT_Done_FreeType(ft_library); return false; } if( FT_Set_Pixel_Sizes( face, 0, best) != FT_Err_Ok ) { dbg->warning( "font_t::load_from_freetype", "Cannot set pixel size %d for %s", best, fname); } // continue anyway } glyphs.resize(0x10000); ascent = face->size->metrics.ascender/64; linespace = face->size->metrics.height/64; descent = face->size->metrics.descender/64; tstrncpy( this->fname, fname, lengthof(this->fname) ); uint32 num_glyphs = 0; // 8 bit bitmap FT_Bitmap bitmap_8; FT_Bitmap_Init(&bitmap_8); for( uint32 glyph_nr=0; glyph_nr<0xFFFF; glyph_nr++ ) { if (glyph_nr > 0) { uint32 c = FT_Get_Char_Index(face, glyph_nr); if (c == 0) { // glyph not in font => nothing to render glyphs[glyph_nr].advance = 0xFF; continue; } } /* load glyph image into the slot (erase previous one) */ if( FT_Load_Char( face, glyph_nr, FT_LOAD_RENDER) != FT_Err_Ok ) { // glyph not there ... glyphs[glyph_nr].advance = 0xFF; continue; } const FT_Error error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); if(error != FT_Err_Ok) { // glyph not there ... glyphs[glyph_nr].advance = 0xFF; continue; } // use only needed amount num_glyphs = glyph_nr+1; /* now render into cache * the bitmap is at slot->bitmap * the glyph base is at slot->bitmap_left, CELL_HEIGHT - slot->bitmap_top */ glyph_t & glyph = glyphs[glyph_nr]; FT_Bitmap *bitmap = &face->glyph->bitmap; bool one_bit_pp = false; // check bit depth, for some reason bdf fonts get bitmaps with 1 bit per pixel if (face->glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) { // need to convert if (FT_Bitmap_Convert(ft_library, &face->glyph->bitmap, &bitmap_8, 4) != FT_Err_Ok) { // should not happen continue; } bitmap = &bitmap_8; one_bit_pp = true; } // set glyph size glyph.height = bitmap->rows; glyph.width = bitmap->width; glyph.advance = (face->glyph->advance.x + 31) / 64; // the bitmaps are all top aligned. Bitmap top is the ascent // above the base line // to find the real top position, we must take the font ascent // and reduce it by the glyph ascent glyph.top = ascent - face->glyph->bitmap_top - 1; glyph.left = face->glyph->bitmap_left; // transform glyph to Simutrans bitmap glyph.bitmap = (uint8*)calloc(glyph.height * glyph.width, 1); if (!one_bit_pp) { // 8 bit alpha per pixel for(int y = 0; y < glyph.height; y++) { for(int x = 0; x < glyph.width; x++) { uint16 alpha = bitmap->buffer[y * bitmap->pitch + x]; // simgraph blend routines want alpha in 0..32 glyph.bitmap[y * glyph.width + x] = (alpha * 32) / 255; } } } else { // 1 bit per pixel for(int y = 0; y < glyph.height; y++) { for(int x = 0; x < glyph.width; x++) { uint16 alpha = bitmap->buffer[y * bitmap->pitch + x]; // simgraph blend routines want alpha in 0..32 glyph.bitmap[y * glyph.width + x] = (alpha * 32); } } } // find out if invalid character if (glyph_nr && glyph.height>0 && glyphs[0].height == glyph.height && glyphs[0].width == glyph.width && memcmp(glyphs[0].bitmap, glyph.bitmap, glyph.height * glyph.width) == 0) { // same bitmap as character zero ?!?! glyph.advance = 0xFF; } } FT_Bitmap_Done(ft_library, &bitmap_8); if(num_glyphs < 0x80) { FT_Done_Face( face ); FT_Done_FreeType( ft_library ); return false; } // hack for not rendered full width space if( glyphs[0x3000].advance == 0xFF && glyphs[0x3001].advance != 0xFF ) { glyphs[0x3000].advance = glyphs[0x3001].advance; glyphs[0x3000].width = 0; glyphs[0x3000].top = 0; } if (glyphs[' '].advance == 0xFF) { glyphs[' '].advance = glyphs['n'].advance; } // Use only needed amount glyphs.resize(num_glyphs); FT_Done_Face( face ); FT_Done_FreeType( ft_library ); return true; } #endif void font_t::print_debug() const { dbg->debug("font_t::print_debug", "Loaded font %s with %i glyphs\n", get_fname(), get_num_glyphs()); dbg->debug("font_t::print_debug", "height: %i, descent: %i", linespace, descent ); /* for(uint8 glyph_nr = ' '; glyph_nr<128; glyph_nr ++) { char msg[128 + GLYPH_BITMAP_HEIGHT * (GLYPH_BITMAP_WIDTH+1)]; // +1 for trailing newline char *c = msg + sprintf(msg, "glyph %c: width %i, top %i\n", glyph_nr, get_glyph_width(glyph_nr), get_glyph_yoffset(glyph_nr) ); for( uint32 y = 0; y < GLYPH_BITMAP_HEIGHT; y++ ) { for( uint32 x = 0; x < (uint32)min(GLYPH_BITMAP_WIDTH, get_glyph_width(glyph_nr)); x++ ) { const uint8 data = get_glyph_bitmap(glyph_nr)[y+(x/CHAR_BIT)*GLYPH_BITMAP_HEIGHT]; const bool bit_set = (data & (0x80>>(x%CHAR_BIT))) != 0; *c++ = bit_set ? '*' : ' '; } *c++ = '\n'; } *c++ = 0; dbg->debug("font_t::print_debug", "glyph data: %s", msg ); } */ } bool font_t::load_from_file(const char *srcfilename) { tstrncpy( fname, srcfilename, lengthof(fname) ); #if COLOUR_DEPTH != 0 bool ok = load_from_freetype( fname, env_t::fontsize ); #if MSG_LEVEL>=4 if( ok ) { print_debug(); } #endif return ok; #else return true; #endif } sint16 font_t::get_glyph_advance(utf32 c) const { if( !is_loaded() ) { return 0; } else if( c >= get_num_glyphs() || glyphs[c].advance == 0xFF ) { return glyphs[0].advance; } return glyphs[c].advance; } const font_t::glyph_t& font_t::get_glyph(utf32 c) const { static glyph_t dummy; if (is_loaded()) { if (c < get_num_glyphs() && glyphs[c].advance < 0xFF) { return glyphs[c]; } else { return glyphs[0]; } } return dummy; } simutrans-124.3/src/simutrans/display/font.h000066400000000000000000000037661474050137200211670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_FONT_H #define DISPLAY_FONT_H #include "../simtypes.h" #include "../utils/unicode.h" #include #include /** * Terminology: * - glyph: display data of a single character * - font: a collection of glyphs (usually called a font face) * - width,height: size of the glyph * - advance: number of pixels between the start of a glyph and the next glyph * (not necessarily equal to width) */ class font_t { public: /// glyph data is stored dense in an array /// 23 rows of bytes, second column for widths between 8 and 16 struct glyph_t { glyph_t(); uint8* bitmap; sint16 height; sint16 width; sint16 advance; sint16 top; sint16 left; }; public: font_t(); // returns true if this character is contained in the font static bool is_char_in_freetype_font(const char* fname, utf16 testchar); public: /// @returns true on success bool load_from_file(const char *fname); bool is_loaded() const { return !glyphs.empty(); } const char *get_fname() const { return fname; } sint16 get_linespace() const { return linespace; } sint16 get_ascent() const { return ascent; } /// @returns true if this is a valid (defined) glyph bool is_valid_glyph(utf32 c) const { return is_loaded() && c < get_num_glyphs() && glyphs[c].advance != 0xFF; } /// @returns size in pixels between the start of this glyph and the next glyph sint16 get_glyph_advance(utf32 c) const; /// @returns glyph data for this utf32 char const glyph_t& get_glyph(utf32 c) const; private: #if COLOUR_DEPTH != 0 /// Load a freetype font bool load_from_freetype(const char *fname, int pixel_height); #endif void print_debug() const; uint32 get_num_glyphs() const { return glyphs.size(); } private: char fname[PATH_MAX]; sint16 linespace; sint16 ascent; sint16 descent; public: // for simgraph has_character() std::vector glyphs; }; #endif simutrans-124.3/src/simutrans/display/scr_coord.h000066400000000000000000000223061474050137200221650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_SCR_COORD_H #define DISPLAY_SCR_COORD_H #include #include "../dataobj/loadsave.h" #include "../simtypes.h" class koord; // Screen coordinate type typedef sint32 scr_coord_val; // Rectangle relations enum rect_relation_t { RECT_RELATION_INSIDE, RECT_RELATION_OVERLAP, RECT_RELATION_OUTSIDE }; // Two dimensional coordinate type class scr_coord { public: scr_coord_val x; scr_coord_val y; // Constructors scr_coord( ) { x = y = 0; } scr_coord( scr_coord_val x_, scr_coord_val y_ ) { x = x_; y=y_; } bool operator ==(const scr_coord& other) const { return ((x-other.x) | (y-other.y)) == 0; } bool operator !=(const scr_coord& other) const { return !(other == *this ); } const scr_coord operator +(const scr_coord& other ) const { return scr_coord( other.x + x, other.y + y); } const scr_coord operator -(const scr_coord& other ) const { return scr_coord( x - other.x, y - other.y ); } void rdwr(loadsave_t *file) { xml_tag_t k( file, "koord" ); file->rdwr_long(x); file->rdwr_long(y); } const scr_coord& operator +=(const scr_coord& other ) { x += other.x; y += other.y; return *this; } const scr_coord& operator -=(const scr_coord& other ) { x -= other.x; y -= other.y; return *this; } void add_offset( scr_coord_val delta_x, scr_coord_val delta_y ) { x += delta_x; y += delta_y; } void set( scr_coord_val x_par, scr_coord_val y_par ) { x = x_par; y = y_par; } inline void clip_lefttop( scr_coord scr_lefttop ) { if (x < scr_lefttop.x) { x = scr_lefttop.x; } if (y < scr_lefttop.y) { y = scr_lefttop.y; } } inline void clip_rightbottom( scr_coord scr_rightbottom ) { if (x > scr_rightbottom.x) { x = scr_rightbottom.x; } if (y > scr_rightbottom.y) { y = scr_rightbottom.y; } } static const scr_coord invalid; private: // conversions to/from koord not allowed anymore scr_coord( const koord); operator koord() const; }; static inline scr_coord operator * (const scr_coord &k, const sint16 m) { return scr_coord(k.x * m, k.y * m); } static inline scr_coord operator / (const scr_coord &k, const sint16 m) { return scr_coord(k.x / m, k.y / m); } // Very simple scr_size struct. class scr_size { public: scr_coord_val w; scr_coord_val h; public: // Constructors scr_size( ) { w = h = 0; } scr_size( scr_coord_val w_par, scr_coord_val h_par) { w = w_par; h = h_par; } operator scr_coord() const { return scr_coord(w,h); } //operator bool() const { return ((w != 0) && (h != 0)); } // or you get silent conversions to int!!! bool operator ==(const scr_size& other) const { return ((w-other.w) | (h-other.h)) == 0; } bool operator !=(const scr_size& other) const { return !(other == *this ); } const scr_size operator +(const scr_size& other ) const { return scr_size( other.w + w, other.h + h); } const scr_size operator -(const scr_size& other ) const { return scr_size( w - other.w, h - other.h ); } const scr_size operator +(const scr_coord& other ) const { return scr_size( other.x + w, other.y + h); } const scr_size operator -(const scr_coord& other ) const { return scr_size( w - other.x, h - other.y ); } const scr_size operator *(const scr_coord_val& i) const { return scr_size(w*i, h*i); } void rdwr(loadsave_t *file) { xml_tag_t k( file, "koord" ); file->rdwr_long(w); file->rdwr_long(h); } inline void clip_lefttop( scr_coord scr_lefttop ) { if (w < scr_lefttop.x) { w = scr_lefttop.x; } if (h < scr_lefttop.y) { h = scr_lefttop.y; } } inline void clip_rightbottom( scr_coord scr_rightbottom ) { if (w > scr_rightbottom.x) { w = scr_rightbottom.x; } if (h > scr_rightbottom.y) { h = scr_rightbottom.y; } } const scr_size& operator +=(const scr_size& other ) { w += other.w; h += other.h; return *this; } const scr_size& operator -=(const scr_size& other ) { w -= other.w; h -= other.h; return *this; } const scr_size& operator +=(const scr_coord& other ) { w += other.x; h += other.y; return *this; } const scr_size& operator -=(const scr_coord& other ) { w -= other.x; h -= other.y; return *this; } static const scr_size invalid; static const scr_size inf; private: // conversions to/from koord not allowed anymore operator koord() const; }; // Rectangle type class scr_rect { public: scr_coord_val x; scr_coord_val y; scr_coord_val w; scr_coord_val h; // to set it in one line ... void set( scr_coord_val x_par, scr_coord_val y_par, scr_coord_val w_par, scr_coord_val h_par ) { x = x_par; y = y_par; w = w_par; h = h_par; } // Constructors scr_rect() { set(0,0,0,0); } scr_rect( const scr_coord& pt ) { set( pt.x, pt.y, 0, 0 ); } scr_rect( const scr_coord& pt, scr_coord_val w, scr_coord_val h ) { set( pt.x, pt.y, w, h ); } scr_rect( const scr_coord& pt, const scr_size& sz ) { set( pt.x, pt.y, sz.w, sz.h ); } scr_rect( scr_coord_val x, scr_coord_val y, scr_coord_val w, scr_coord_val h ) { set( x, y, w, h ); } scr_rect( scr_size size ) { w = size.w; h=size.h; x=0; y=0; } scr_rect( const scr_coord& point1, const scr_coord& point2 ) { set( point1.x, point1.y, point2.x-point1.x, point2.y-point1.y ); } // Type cast operators operator scr_size() const { return scr_size (w,h); } operator scr_coord() const { return scr_coord(x,y); } // Unary operators const scr_rect operator +(const scr_coord& other ) const { scr_rect rect(x + other.x, y + other.y, w, h ); return rect; } const scr_rect operator -(const scr_coord& other ) const { scr_rect rect(x - other.x, y - other.y, w, h ); return rect; } const scr_rect operator +(const scr_size& sz ) const { return scr_rect(x,y, w+sz.w, h+sz.h ); } const scr_rect operator -(const scr_size& sz ) const { return scr_rect(x,y, w-sz.w, h-sz.h ); } // Validation functions bool is_empty() const { return (w|h) == 0; } bool is_valid() const { return !is_empty(); } // Helper functions scr_coord get_pos() const { return scr_coord( x, y ); } void set_pos( const scr_coord point ) { w = (x+w) - point.x; h = (y+h) - point.y; x = point.x; y = point.y; } const scr_coord get_bottomright() const { return scr_coord( x+w, y+h ); } void set_bottomright( const scr_coord& point ) { w = point.x - x; h = point.y - y; } scr_coord_val get_width() const { return w; } scr_coord_val get_right() const { return x+w; } scr_coord_val get_height() const { return h; } scr_coord_val get_bottom() const { return y+h; } void set_right(scr_coord_val right) { w = right-x; } void set_bottom(scr_coord_val bottom) { h = bottom-y; } // now just working on two of the four coordinates void move_to( scr_coord_val x_par, scr_coord_val y_par ) { x = x_par; y = y_par; } void move_to( const scr_coord& point ) { move_to( point.x, point.y ); } // and the other two with the size const scr_size get_size() const { return scr_size( w, h ); } void set_size( const scr_size &sz ) { w = sz.w; h = sz.h; } void set_size( scr_coord_val width, scr_coord_val height) { w = width; h = height; } // add to left, right and top, bottom void expand( scr_coord_val delta_x_par, scr_coord_val delta_y_par ) { x -= delta_x_par; y -= delta_y_par; w += (delta_x_par<<1); h += (delta_y_par<<1); } // Adjust rect to the bounding rect of this and rect. void outer_bounds( const scr_rect &rect ) { scr_coord pt( min(x,rect.x), min(y,rect.y) ); w = max(x+w,rect.x+rect.w)-pt.x; h = max(y+h,rect.y+rect.h)-pt.y; x = pt.x; y = pt.y; } // Enforce a positive width and height void normalize() { if( w<0 ) { x -= w; w = -w; } if( h<0 ) { y -= h; h = -h; } } // point in rect; border (x+w) is still counting as contained bool contains( const scr_coord& pt ) const { return ( x <= pt.x && x+w >= pt.x && y <=pt.y && y+h >= pt.y ); } // Now rect/rect functions: First check if rect is completely surrounded by this // maybe surrounds would be a better name, but contains seems more consistent bool contains( const scr_rect& rect ) const { return ( x <= rect.x && x+w >= rect.x+rect.w && y <= rect.y && y+h >= rect.y+rect.h ); } bool is_overlapping( const scr_rect &rect ) const { return !( (get_bottomright().x < rect.x) || (get_bottomright().y < rect.y) || (rect.get_bottomright().x < x) || (rect.get_bottomright().y < y) ); } rect_relation_t relation( const scr_rect& rect ) const { if( contains(rect) ) { return RECT_RELATION_INSIDE; } else if( is_overlapping( rect ) ) { return RECT_RELATION_OVERLAP; } return RECT_RELATION_OUTSIDE; } /** * reduces the current rect to the intersection area of two rects * in case of no overlap the new size is negative * @note maybe this could rather return a new rect */ void clip( const scr_rect clip_rect ) { x = max(x, clip_rect.x); set_right( min(x+w, clip_rect.x+clip_rect.w) ); y = max(y, clip_rect.y); set_bottom( min(y+h, clip_rect.y+clip_rect.h) ); } bool operator ==(const scr_rect& rect) const { return ( (x-rect.x) | (y-rect.y) | (w-rect.w) | (h-rect.h) ) == 0; } bool operator !=(const scr_rect& rect_par) const { return !(rect_par==*this); } private: // conversions to/from koord not allowed anymore scr_rect( const koord&); operator koord() const; }; #endif simutrans-124.3/src/simutrans/display/simgraph.h000066400000000000000000000377131474050137200220320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_SIMGRAPH_H #define DISPLAY_SIMGRAPH_H #include "../simcolor.h" #include "../simtypes.h" #include "clip_num.h" #include "simimg.h" #include "scr_coord.h" #if COLOUR_DEPTH != 0 #ifndef ZOOM_NEUTRAL #define MAX_ZOOM_FACTOR (9) #define ZOOM_NEUTRAL (3) extern const sint32 zoom_num[MAX_ZOOM_FACTOR + 1]; extern const sint32 zoom_den[MAX_ZOOM_FACTOR + 1]; #endif extern scr_coord_val default_font_ascent; extern scr_coord_val default_font_linespace; # define LINEASCENT (default_font_ascent) # define LINESPACE (default_font_linespace) #else # define LINEASCENT 0 // a font height of zero could cause division by zero errors, even though it should not be used in a server # define LINESPACE 1 #ifndef ZOOM_NEUTRAL #define MAX_ZOOM_FACTOR (0) #define ZOOM_NEUTRAL (0) extern const sint32 zoom_num[1]; extern const sint32 zoom_den[1]; #endif #endif /** * Alignment enum to align controls against each other. * Vertical and horizontal alignment can be masked together * Unused bits are reserved for future use, set to 0. */ enum control_alignments_t { ALIGN_NONE = 0x00, ALIGN_TOP = 0x01, ALIGN_CENTER_V = 0x02, ALIGN_BOTTOM = 0x03, ALIGN_LEFT = 0x04, ALIGN_CENTER_H = 0x08, ALIGN_RIGHT = 0x0C, // These flags does not belong in here but // are defined here until we sorted this out. // They are only used in display_text_proportional_len_clip_rgb() DT_CLIP = 0x4000 }; typedef uint16 control_alignment_t; struct clip_dimension { scr_coord_val x, xx, w, y, yy, h; }; // helper macros // save the current clipping and set a new one #define PUSH_CLIP(x,y,w,h) \ {\ clip_dimension const p_cr = display_get_clip_wh(); \ display_set_clip_wh(x, y, w, h); // save the current clipping and set a new one // fit it to old clipping region #define PUSH_CLIP_FIT(x,y,w,h) \ {\ clip_dimension const p_cr = display_get_clip_wh(); \ display_set_clip_wh(x, y, w, h CLIP_NUM_DEFAULT, true); // restore a saved clipping rect #define POP_CLIP() \ display_set_clip_wh(p_cr.x, p_cr.y, p_cr.w, p_cr.h); \ } /** * */ PIXVAL color_idx_to_rgb(PIXVAL idx); PIXVAL color_rgb_to_idx(PIXVAL color); /* * Get 24bit RGB888 colour from an index of the old 8bit palette */ rgb888_t get_color_rgb(uint8 idx); /* * Environment colours from RGB888 to system format */ void env_t_rgb_to_system_colors(); /** * Helper functions for clipping along tile borders. */ void add_poly_clip(int x0_,int y0_, int x1, int y1, int ribi CLIP_NUM_DEF); void clear_all_poly_clip(CLIP_NUM_DEF0); void activate_ribi_clip(int ribi CLIP_NUM_DEF); /* Do no access directly, use the get_tile_raster_width() * function instead. */ extern scr_coord_val tile_raster_width; inline scr_coord_val get_tile_raster_width(){return tile_raster_width;} extern scr_coord_val base_tile_raster_width; inline scr_coord_val get_base_tile_raster_width(){return base_tile_raster_width;} /* changes the raster width after loading */ scr_coord_val display_set_base_raster_width(scr_coord_val new_raster); int zoom_factor_up(); int zoom_factor_down(); /** * Initialises the graphics module */ bool simgraph_init(scr_size window_size, sint16 fullscreen); bool is_display_init(); void simgraph_exit(); void simgraph_resize(scr_size new_window_size); /** * Loads the font, returns the number of characters in it * @param fname * @param reload if true forces reload */ bool display_load_font(const char *fname, bool reload = false); image_id get_image_count(); void register_image(class image_t *); // delete all images above a certain number ... void display_free_all_images_above( image_id above ); // unzoomed offsets void display_get_base_image_offset( image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw ); // zoomed offsets void display_get_image_offset( image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw ); void display_mark_img_dirty( image_id image, scr_coord_val x, scr_coord_val y ); void mark_rect_dirty_wc(scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2); // clips to screen only void mark_rect_dirty_clip(scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2 CLIP_NUM_DEF); // clips to clip_rect void mark_screen_dirty(); scr_coord_val display_get_width(); scr_coord_val display_get_height(); void display_set_height(scr_coord_val); void display_set_actual_width(scr_coord_val); // get next smallest size when scaling to percent scr_size display_get_best_matching_size(const image_id n, sint16 zoom_percent); // force a certain size on a image (for rescaling tool images) void display_fit_img_to_width( const image_id n, sint16 new_w ); void display_day_night_shift(int night); // scrolls horizontally, will ignore clipping etc. void display_scroll_band( const scr_coord_val start_y, const scr_coord_val x_offset, const scr_coord_val h ); // set first and second company color for player void display_set_player_color_scheme(const int player, const uint8 col1, const uint8 col2 ); // only used for GUI, display image inside a rect void display_img_aligned( const image_id n, scr_rect area, int align, const bool dirty); // display image with day and night change void display_img_aux(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const bool daynight, const bool dirty CLIP_NUM_DEF); /** * draws the images with alpha, either blended or as outline */ void display_rezoomed_img_blend(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF); #define display_img_blend( n, x, y, c, dn, d ) display_rezoomed_img_blend( (n), (x), (y), 0, (c), (dn), (d) CLIP_NUM_DEFAULT) #define ALPHA_RED 0x1 #define ALPHA_GREEN 0x2 #define ALPHA_BLUE 0x4 void display_rezoomed_img_alpha(const image_id n, const image_id alpha_n, const unsigned alpha_flags, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF); #define display_img_alpha( n, a, f, x, y, c, dn, d ) display_rezoomed_img_alpha( (n), (a), (f), (x), (y), 0, (c), (dn), (d) CLIP_NUM_DEFAULT) // display image with color (if there) and optional day and night change void display_color_img(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const bool daynight, const bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); // display unzoomed image void display_base_img(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const bool daynight, const bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); typedef image_id stretch_map_t[3][3]; // this displays a 3x3 array of images to fit the scr_rect void display_img_stretch( const stretch_map_t &imag, scr_rect area ); // this displays a 3x3 array of images to fit the scr_rect like above, but blend the color void display_img_stretch_blend( const stretch_map_t &imag, scr_rect area, FLAGGED_PIXVAL color ); // display unzoomed image with alpha, either blended or as outline void display_base_img_blend(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); void display_base_img_alpha(const image_id n, const image_id alpha_n, const unsigned alpha_flags, scr_coord_val xp, scr_coord_val yp, const sint8 player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); // pointer to image display procedures typedef void (*display_image_proc)(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const bool daynight, const bool dirty CLIP_NUM_DEF); typedef void (*display_blend_proc)(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF); typedef void (*display_alpha_proc)(const image_id n, const image_id alpha_n, const unsigned alpha_flags, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF); // variables for storing currently used image procedure set and tile raster width extern display_image_proc display_normal; extern display_image_proc display_color; extern display_blend_proc display_blend; extern display_alpha_proc display_alpha; extern signed short current_tile_raster_width; // call this instead of referring to current_tile_raster_width directly #define get_current_tile_raster_width() (current_tile_raster_width) // for switching between image procedure sets and setting current tile raster width inline void display_set_image_proc( bool is_global ) { if( is_global ) { display_normal = display_img_aux; display_color = display_color_img; display_blend = display_rezoomed_img_blend; display_alpha = display_rezoomed_img_alpha; current_tile_raster_width = get_tile_raster_width(); } else { display_normal = display_base_img; display_color = display_base_img; display_blend = display_base_img_blend; display_alpha = display_base_img_alpha; current_tile_raster_width = get_base_tile_raster_width(); } } // Blends two colors PIXVAL display_blend_colors(PIXVAL background, PIXVAL foreground, int percent_blend); // blends a rectangular region void display_blend_wh_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, int percent_blend ); void display_fillbox_wh_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty); void display_fillbox_wh_clip_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); void display_filled_roundbox_clip(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty); void display_vline_wh_clip_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val h, PIXVAL c, bool dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); void display_flush_buffer(); void display_show_pointer(int yesno); void display_set_pointer(int pointer); void display_show_load_pointer(int loading); void display_array_wh(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, const PIXVAL *arr); // compound painting routines void display_outline_proportional_rgb(scr_coord_val xpos, scr_coord_val ypos, PIXVAL text_color, PIXVAL shadow_color, const char *text, int dirty, sint32 len=-1); void display_shadow_proportional_rgb(scr_coord_val xpos, scr_coord_val ypos, PIXVAL text_color, PIXVAL shadow_color, const char *text, int dirty, sint32 len=-1); void display_ddd_box_rgb(scr_coord_val x1, scr_coord_val y1, scr_coord_val w, scr_coord_val h, PIXVAL tl_color, PIXVAL rd_color, bool dirty); void display_ddd_box_clip_rgb(scr_coord_val x1, scr_coord_val y1, scr_coord_val w, scr_coord_val h, PIXVAL tl_color, PIXVAL rd_color); // unicode save moving in strings size_t get_next_char(const char* text, size_t pos); sint32 get_prev_char(const char* text, sint32 pos); scr_coord_val display_get_char_width(utf32 c); scr_coord_val display_get_number_width(); /* returns true, if this is a valid character */ bool has_character( utf16 char_code ); /** * For the next logical character in the text, returns the character code * as well as retrieves the char byte count and the screen pixel width * CAUTION : The text pointer advances to point to the next logical character */ utf32 get_next_char_with_metrics(const char* &text, unsigned char &byte_length, unsigned char &pixel_width); /** * For the previous logical character in the text, returns the character code * as well as retrieves the char byte count and the screen pixel width * CAUTION : The text pointer recedes to point to the previous logical character */ utf32 get_prev_char_with_metrics(const char* &text, const char *const text_start, unsigned char &byte_length, unsigned char &pixel_width); /* * returns the index of the last character that would fit within the width * If an ellipsis len is given, it will only return the last character up to this len if the full length cannot be fitted * @returns index of next character. if text[index]==0 the whole string fits */ size_t display_fit_proportional( const char *text, scr_coord_val max_width); /* routines for string len (macros for compatibility with old calls) */ #define proportional_string_width(text) display_calc_proportional_string_len_width(text, 0x7FFF) #define proportional_string_len_width(text, len) display_calc_proportional_string_len_width(text, len) // length of a string in pixel scr_coord_val display_calc_proportional_string_len_width(const char* text, size_t len); // box which will contain the multi (or single) line of text void display_calc_proportional_multiline_string_len_width( int &xw, int &yh, const char *text); /* * len parameter added - use -1 for previous behaviour. * completely renovated for unicode and 10 bit width and variable height */ // #ifdef MULTI_THREAD scr_coord_val display_text_proportional_len_clip_rgb(scr_coord_val x, scr_coord_val y, const char* txt, control_alignment_t flags, const PIXVAL color, bool dirty, sint32 len CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); /* macro are for compatibility */ #define display_proportional_rgb( x, y, txt, align, color, dirty) display_text_proportional_len_clip_rgb( x, y, txt, align, color, dirty, -1 ) #define display_proportional_clip_rgb( x, y, txt, align, color, dirty) display_text_proportional_len_clip_rgb( x, y, txt, align | DT_CLIP, color, dirty, -1 ) /// Display a string that is abbreviated by the (language specific) ellipsis character if too wide /// If enough space is given, it just display the full string void display_proportional_ellipsis_rgb( scr_rect r, const char *text, int align, const PIXVAL color, const bool dirty, bool shadowed = false, PIXVAL shadow_color = 0 ); void display_ddd_proportional_clip(scr_coord_val xpos, scr_coord_val ypos, FLAGGED_PIXVAL ddd_farbe, FLAGGED_PIXVAL text_farbe, const char *text, int dirty CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); scr_coord_val display_multiline_text_rgb(scr_coord_val x, scr_coord_val y, const char *inbuf, PIXVAL color); // line drawing primitives void display_direct_line_rgb(const scr_coord_val x, const scr_coord_val y, const scr_coord_val xx, const scr_coord_val yy, const PIXVAL color); void display_direct_line_dotted_rgb(const scr_coord_val x, const scr_coord_val y, const scr_coord_val xx, const scr_coord_val yy, const scr_coord_val draw, const scr_coord_val dontDraw, const PIXVAL color); void display_circle_rgb( scr_coord_val x0, scr_coord_val y0, int radius, const PIXVAL color ); void display_filled_circle_rgb( scr_coord_val x0, scr_coord_val y0, int radius, const PIXVAL color ); void draw_bezier_rgb(scr_coord_val Ax, scr_coord_val Ay, scr_coord_val Bx, scr_coord_val By, scr_coord_val ADx, scr_coord_val ADy, scr_coord_val BDx, scr_coord_val BDy, const PIXVAL colore, scr_coord_val draw, scr_coord_val dontDraw); void display_right_triangle_rgb(scr_coord_val x, scr_coord_val y, scr_coord_val height, const PIXVAL colval, const bool dirty); void display_signal_direction_rgb(scr_coord_val x, scr_coord_val y, uint8 way_dir, uint8 sig_dir, PIXVAL col1, PIXVAL col1_dark, bool is_diagonal=false, uint8 slope = 0 ); void display_set_clip_wh(scr_coord_val x, scr_coord_val y, scr_coord_val w, scr_coord_val h CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO, bool fit = false); clip_dimension display_get_clip_wh(CLIP_NUM_DEF0 CLIP_NUM_DEFAULT_ZERO); void display_push_clip_wh(scr_coord_val x, scr_coord_val y, scr_coord_val w, scr_coord_val h CLIP_NUM_DEF CLIP_NUM_DEFAULT_ZERO); void display_swap_clip_wh(CLIP_NUM_DEF0); void display_pop_clip_wh(CLIP_NUM_DEF0); bool display_snapshot( const scr_rect &area ); #if COLOUR_DEPTH != 0 extern rgb888_t display_day_lights [LIGHT_COUNT]; extern rgb888_t display_night_lights[LIGHT_COUNT]; #endif #endif simutrans-124.3/src/simutrans/display/simgraph0.cc000066400000000000000000000206451474050137200222440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simconst.h" #include "../sys/simsys.h" #include "../descriptor/image.h" #include "simgraph.h" scr_coord_val tile_raster_width = 16; // zoomed scr_coord_val base_tile_raster_width = 16; // original extern const sint32 zoom_num[1] = { 1 }; extern const sint32 zoom_den[1] = { 1 }; PIXVAL color_idx_to_rgb(PIXVAL idx) { return idx; } PIXVAL color_rgb_to_idx(PIXVAL color) { return color; } rgb888_t get_color_rgb(uint8) { return {0,0,0}; } void env_t_rgb_to_system_colors() { } scr_coord_val display_set_base_raster_width(scr_coord_val) { return 0; } void set_zoom_factor(int) { } int zoom_factor_up() { return false; } int zoom_factor_down() { return false; } void mark_rect_dirty_wc(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val) { } void mark_rect_dirty_clip(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val CLIP_NUM_DEF_NOUSE) { } void mark_screen_dirty() { } void display_mark_img_dirty(image_id, scr_coord_val, scr_coord_val) { } bool display_load_font(const char*, bool) { return true; } scr_coord_val display_get_width() { return 0; } scr_coord_val display_get_height() { return 0; } void display_set_height(scr_coord_val) { } void display_set_actual_width(scr_coord_val) { } void display_day_night_shift(int) { } void display_set_player_color_scheme(const int, const uint8, const uint8) { } void register_image(image_t* image) { image->imageid = 1; } bool display_snapshot(const scr_rect &) { return false; } void display_get_image_offset(image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw) { if( image < 2 ) { // initialize offsets with dummy values *xoff = 0; *yoff = 0; *xw = 0; *yw = 0; } } void display_get_base_image_offset(image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw) { if( image < 2 ) { // initialize offsets with dummy values *xoff = 0; *yoff = 0; *xw = 0; *yw = 0; } } clip_dimension display_get_clip_wh(CLIP_NUM_DEF_NOUSE0) { clip_dimension clip_rect; clip_rect.x = 0; clip_rect.xx = 0; clip_rect.w = 0; clip_rect.y = 0; clip_rect.yy = 0; clip_rect.h = 0; return clip_rect; } void display_set_clip_wh(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val CLIP_NUM_DEF_NOUSE, bool) { } void display_push_clip_wh(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val CLIP_NUM_DEF_NOUSE) { } void display_swap_clip_wh(CLIP_NUM_DEF_NOUSE0) { } void display_pop_clip_wh(CLIP_NUM_DEF_NOUSE0) { } void display_scroll_band(const scr_coord_val, const scr_coord_val, const scr_coord_val) { } void display_img_aux(const image_id, scr_coord_val, scr_coord_val, const sint8, const bool, const bool CLIP_NUM_DEF_NOUSE) { } void display_color_img(const image_id, scr_coord_val, scr_coord_val, const sint8, const bool, const bool CLIP_NUM_DEF_NOUSE) { } scr_size display_get_best_matching_size(const image_id, sint16) { return scr_size(32, 32); // default size } void display_base_img(const image_id, scr_coord_val, scr_coord_val, const sint8, const bool, const bool CLIP_NUM_DEF_NOUSE) { } void display_fit_img_to_width( const image_id, sint16) { } void display_img_stretch( const stretch_map_t &, scr_rect) { } void display_img_stretch_blend( const stretch_map_t &, scr_rect, FLAGGED_PIXVAL) { } void display_rezoomed_img_blend(const image_id, scr_coord_val, scr_coord_val, const sint8, const FLAGGED_PIXVAL, const bool, const bool CLIP_NUM_DEF_NOUSE) { } void display_rezoomed_img_alpha(const image_id, const image_id, const unsigned, scr_coord_val, scr_coord_val, const sint8, const FLAGGED_PIXVAL, const bool, const bool CLIP_NUM_DEF_NOUSE) { } void display_base_img_blend(const image_id, scr_coord_val, scr_coord_val, const sint8, const FLAGGED_PIXVAL, const bool, const bool CLIP_NUM_DEF_NOUSE) { } void display_base_img_alpha(const image_id, const image_id, const unsigned, scr_coord_val, scr_coord_val, const sint8, const FLAGGED_PIXVAL, const bool, bool CLIP_NUM_DEF_NOUSE) { } // variables for storing currently used image procedure set and tile raster width display_image_proc display_normal = display_base_img; display_image_proc display_color = display_base_img; display_blend_proc display_blend = display_base_img_blend; display_alpha_proc display_alpha = display_base_img_alpha; signed short current_tile_raster_width = 0; PIXVAL display_blend_colors(PIXVAL, PIXVAL, int) { return 0; } void display_blend_wh_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, int ) { } void display_fillbox_wh_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, bool ) { } void display_fillbox_wh_clip_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, bool CLIP_NUM_DEF_NOUSE) { } void display_vline_wh_clip_rgb(scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, bool CLIP_NUM_DEF_NOUSE) { } void display_filled_roundbox_clip(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, bool) { } void display_array_wh(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, const PIXVAL *) { } scr_coord_val display_get_char_width(utf32) { return 0; } scr_coord_val display_get_number_width() { return 0; } utf32 get_next_char_with_metrics(const char* &, unsigned char &, unsigned char &) { return 0; } utf32 get_prev_char_with_metrics(const char* &, const char *const, unsigned char &, unsigned char &) { return 0; } bool has_character( utf16 ) { return false; } size_t display_fit_proportional(const char *, scr_coord_val) { return 0; } scr_coord_val display_calc_proportional_string_len_width(const char*, size_t) { return 0; } void display_calc_proportional_multiline_string_len_width( int &xw, int &yh, const char *) { xw = yh = 0;; } scr_coord_val display_text_proportional_len_clip_rgb(scr_coord_val, scr_coord_val, const char*, control_alignment_t , const PIXVAL, bool, sint32 CLIP_NUM_DEF_NOUSE) { return 0; } void display_outline_proportional_rgb(scr_coord_val, scr_coord_val, PIXVAL, PIXVAL, const char *, int, sint32) { } void display_shadow_proportional_rgb(scr_coord_val, scr_coord_val, PIXVAL, PIXVAL, const char *, int, sint32) { } void display_ddd_box_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, PIXVAL, bool) { } void display_ddd_box_clip_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, PIXVAL, PIXVAL) { } void display_ddd_proportional_clip(scr_coord_val, scr_coord_val, FLAGGED_PIXVAL, FLAGGED_PIXVAL, const char *, int CLIP_NUM_DEF_NOUSE) { } scr_coord_val display_multiline_text_rgb(scr_coord_val, scr_coord_val, const char *, PIXVAL) { return 0; } void display_flush_buffer() { } void display_show_pointer(int) { } void display_set_pointer(int) { } void display_show_load_pointer(int) { } bool simgraph_init(scr_size, sint16) { return true; } bool is_display_init() { return false; } void display_free_all_images_above(image_id) { } void simgraph_exit() { dr_os_close(); } void simgraph_resize(scr_size) { } void display_snapshot() { } void display_direct_line_rgb(const scr_coord_val, const scr_coord_val, const scr_coord_val, const scr_coord_val, const PIXVAL) { } void display_direct_line_dotted_rgb(const scr_coord_val, const scr_coord_val, const scr_coord_val, const scr_coord_val, const scr_coord_val, const scr_coord_val, const PIXVAL) { } void display_circle_rgb( scr_coord_val, scr_coord_val, int, const PIXVAL ) { } void display_filled_circle_rgb( scr_coord_val, scr_coord_val, int, const PIXVAL ) { } void draw_bezier_rgb(scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, scr_coord_val, const PIXVAL, scr_coord_val, scr_coord_val ) { } void display_right_triangle_rgb(scr_coord_val, scr_coord_val, scr_coord_val, const PIXVAL, const bool) { } void display_signal_direction_rgb( scr_coord_val, scr_coord_val, uint8, uint8, PIXVAL, PIXVAL, bool, uint8 ) { } void display_img_aligned( const image_id, scr_rect, int, bool ) { } void display_proportional_ellipsis_rgb( scr_rect, const char *, int, PIXVAL, bool, bool, PIXVAL) { } image_id get_image_count() { return 0; } #ifdef MULTI_THREAD void add_poly_clip(int, int, int, int, int CLIP_NUM_DEF_NOUSE) { } void clear_all_poly_clip(const sint8) { } void activate_ribi_clip(int CLIP_NUM_DEF_NOUSE) { } #else void add_poly_clip(int, int, int, int, int) { } void clear_all_poly_clip() { } void activate_ribi_clip(int) { } #endif simutrans-124.3/src/simutrans/display/simgraph16.cc000066400000000000000000004276271474050137200223460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include "../simtypes.h" /* * Zoom factor (must be done before including simgraph) */ #define MAX_ZOOM_FACTOR (9) #define ZOOM_NEUTRAL (3) uint32 zoom_factor = ZOOM_NEUTRAL; extern const sint32 zoom_num[MAX_ZOOM_FACTOR + 1] = { 2, 3, 4, 1, 3, 5, 1, 3, 1, 1 }; extern const sint32 zoom_den[MAX_ZOOM_FACTOR + 1] = { 1, 2, 3, 1, 4, 8, 2, 8, 4, 8 }; #include "../macros.h" #include "font.h" #include "../pathes.h" #include "../simconst.h" #include "../sys/simsys.h" #include "../simmem.h" #include "../simdebug.h" #include "../descriptor/image.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../utils/unicode.h" #include "../simticker.h" #include "../utils/simstring.h" #include "../utils/unicode.h" #include "../io/raw_image.h" #include "../gui/simwin.h" #include "../dataobj/environment.h" #include "../obj/roadsign.h" // for signal status indicator #include "simgraph.h" #ifdef _MSC_VER # include # define W_OK 2 #else # include #endif #ifdef MULTI_THREAD #include "../utils/simthread.h" // currently just redrawing/rezooming static pthread_mutex_t rezoom_img_mutex[MAX_THREADS]; static pthread_mutex_t recode_img_mutex; #endif // to pass the extra clipnum when not needed use this #ifdef MULTI_THREAD #define CLIPNUM_IGNORE , 0 #else #define CLIPNUM_IGNORE #endif #include "simgraph.h" // undefine for debugging the update routines //#define DEBUG_FLUSH_BUFFER #ifdef USE_SOFTPOINTER static int softpointer = -1; #endif static int standard_pointer = -1; #ifdef USE_SOFTPOINTER /* * Icon bar needs to redrawn on mouse hover */ int old_my = -1; #endif /* * struct to hold the information about visible area * at screen line y * associated to some clipline */ struct xrange { sint64 sx, sy; scr_coord_val y; bool non_convex_active; }; class clip_line_t { private: // line from (x0,y0) to (x1 y1) // clip (do not draw) everything right from the ray (x0,y0)->(x1,y1) // pixels on the ray are not drawn // (not_convex) if y0>=y1 then clip along the path (x0,-inf)->(x0,y0)->(x1,y1) // (not_convex) if y0(x1,y1)->(x1,+inf) int x0, y0; int dx, dy; sint64 sdy, sdx; sint64 inc; bool non_convex; public: void clip_from_to(int x0_, int y0_, int x1, int y1, bool non_convex_) { x0 = x0_; dx = x1 - x0; y0 = y0_; dy = y1 - y0; non_convex = non_convex_; int steps = (abs(dx) > abs(dy) ? abs(dx) : abs(dy)); if( steps == 0 ) { return; } sdx = ((sint64)dx << 16) / steps; sdy = ((sint64)dy << 16) / steps; // to stay right from the line // left border: xmin <= x // right border: x < xmax if( dy > 0 ) { if( dy > dx ) { inc = 1 << 16; } else { inc = ((sint64)dx << 16) / dy - (1 << 16); } } else if( dy < 0 ) { if( dy < dx ) { inc = 0; // (+1)-1 << 16; } else { inc = 0; } } } // clip if // ( x-x0) . ( y1-y0 ) // ( y-y0) . (-(x1-x0)) < 0 // -- initialize the clipping // has to be called before image will be drawn // return interval for x coordinate inline void get_x_range(scr_coord_val y, xrange &r, bool use_non_convex) const { // do everything for the previous row y--; r.y = y; r.non_convex_active = false; if( non_convex && use_non_convex && y < y0 && y < (y0 + dy) ) { r.non_convex_active = true; y = min(y0, y0+dy) - 1; } if( dy != 0 ) { // init Bresenham algorithm const sint64 t = (((sint64)y - y0) << 16) / sdy; // sx >> 16 = x // sy >> 16 = y r.sx = t * sdx + inc + ((sint64)x0 << 16); r.sy = t * sdy + ((sint64)y0 << 16); } } // -- step one line down, return interval for x coordinate inline void inc_y(xrange &r, int &xmin, int &xmax) const { r.y++; // switch between clip vertical and along ray if( r.non_convex_active ) { if( r.y == min( y0, y0 + dy ) ) { r.non_convex_active = false; } else { if( dy < 0 ) { const int r_xmax = x0 + dx; if( xmax > r_xmax ) { xmax = r_xmax; } } else { const int r_xmin = x0 + 1; if( xmin < r_xmin ) { xmin = r_xmin; } } return; } } // go along the ray, Bresenham if( dy != 0 ) { if( dy > 0 ) { do { r.sx += sdx; r.sy += sdy; } while( (r.sy >> 16) < r.y ); const int r_xmin = r.sx >> 16; if( xmin < r_xmin ) { xmin = r_xmin; } } else { do { r.sx -= sdx; r.sy -= sdy; } while( (r.sy >> 16) < r.y ); const int r_xmax = r.sx >> 16; if( xmax > r_xmax ) { xmax = r_xmax; } } } // horizontal clip else { const bool clip = dx * (r.y - y0) > 0; if( clip ) { // invisible row xmin = +1; xmax = -1; } } } }; #define MAX_POLY_CLIPS 6 MSVC_ALIGN(64) struct clipping_info_t { // current clipping rectangle clip_dimension clip_rect; // clipping rectangle to be swapped by display_clip_wh_toggle clip_dimension clip_rect_swap; bool swap_active; // poly clipping variables int number_of_clips; uint8 active_ribi; uint8 clip_ribi[MAX_POLY_CLIPS]; clip_line_t poly_clips[MAX_POLY_CLIPS]; xrange xranges[MAX_POLY_CLIPS]; } GCC_ALIGN(64); // aligned to separate cachelines #ifdef MULTI_THREAD clipping_info_t clips[MAX_THREADS]; #define CR0 clips[0] #else clipping_info_t clips; #define CR0 clips #endif #define CR clips CLIP_NUM_INDEX static font_t default_font; // needed for resizing gui int default_font_ascent = 0; int default_font_linespace = 0; static int default_font_numberwidth = 0; #define RGBMAPSIZE (0x8000+LIGHT_COUNT+MAX_PLAYER_COUNT+1024 /* 343 transparent */) // RGB 555/565 specific functions // different masks needed for RGB 555 and RGB 565 for blending #ifdef RGB555 #define ONE_OUT (0x3DEF) // mask out bits after applying >>1 #define TWO_OUT (0x1CE7) // mask out bits after applying >>2 #define MASK_32 (0x03e0f81f) // mask out bits after transforming to 32bit inline PIXVAL rgb(PIXVAL r, PIXVAL g, PIXVAL b) { return (r << 10) | (g << 5) | b; } inline PIXVAL red(PIXVAL rgb) { return rgb >> 10; } inline PIXVAL green(PIXVAL rgb) { return (rgb >> 5) & 0x1F; } #else #define ONE_OUT (0x7bef) // mask out bits after applying >>1 #define TWO_OUT (0x39E7) // mask out bits after applying >>2 #define MASK_32 (0x07e0f81f) // mask out bits after transforming to 32bit inline PIXVAL rgb(PIXVAL r, PIXVAL g, PIXVAL b) { return (r << 11) | (g << 5) | b; } inline PIXVAL red(PIXVAL rgb) { return rgb >> 11; } inline PIXVAL green(PIXVAL rgb) { return (rgb >> 5) & 0x3F; } #endif inline PIXVAL blue(PIXVAL rgb) { return rgb & 0x1F; } /** * Implement shift-and-mask for rgb values: * shift-right by 1 or 2, and mask it to a valid rgb number. */ inline PIXVAL rgb_shr1(PIXVAL c) { return (c >> 1) & ONE_OUT; } inline PIXVAL rgb_shr2(PIXVAL c) { return (c >> 2) & TWO_OUT; } /* * mapping tables for RGB 555 to actual output format * plus the special (player, day&night) colors appended * * 0x0000 - 0x7FFF: RGB colors * 0x8000 - 0x800F: Player colors * 0x8010 - 0x001F: Day&Night special colors * The following transparent colors are not in the colortable * 0x8020 - 0xFFE1: 3 4 3 RGB transparent colors in 31 transparency levels */ static PIXVAL rgbmap_day_night[RGBMAPSIZE]; /* * same as rgbmap_day_night, but always daytime colors */ static PIXVAL rgbmap_all_day[RGBMAPSIZE]; /* * used by pixel copy functions, is one of rgbmap_day_night * rgbmap_all_day */ static PIXVAL *rgbmap_current = 0; /* * mapping table for special-colors (AI player colors) * to actual output format - day&night mode * 16 sets of 16 colors */ static PIXVAL specialcolormap_day_night[256]; /* * mapping table for special-colors (AI player colors) * to actual output format - all day mode * 16 sets of 16 colors */ PIXVAL specialcolormap_all_day[256]; // offsets of first and second company color static uint8 player_offsets[MAX_PLAYER_COUNT][2]; /* * Image map descriptor structure */ struct imd { sint16 x; // current (zoomed) min x offset sint16 y; // current (zoomed) min y offset sint16 w; // current (zoomed) width sint16 h; // current (zoomed) height uint8 recode_flags; uint16 player_flags; // bit # is player number, ==1 cache image needs recoding PIXVAL* data[MAX_PLAYER_COUNT]; // current data - zoomed and recolored (player + daynight) PIXVAL* zoom_data; // zoomed original data uint32 len; // current zoom image data size (or base if not zoomed) (used for allocation purposes only) sint16 base_x; // min x offset sint16 base_y; // min y offset sint16 base_w; // width sint16 base_h; // height PIXVAL* base_data; // original image data }; // Flags for recoding #define FLAG_HAS_PLAYER_COLOR (1) #define FLAG_HAS_TRANSPARENT_COLOR (2) #define FLAG_ZOOMABLE (4) #define FLAG_REZOOM (8) //#define FLAG_POSITION_CHANGED (16) #define TRANSPARENT_RUN (0x8000u) static scr_coord_val disp_width = 640; static scr_coord_val disp_actual_width = 640; static scr_coord_val disp_height = 480; /* * Static buffers for rezoom_img() */ static uint8 *rezoom_baseimage[MAX_THREADS]; static PIXVAL *rezoom_baseimage2[MAX_THREADS]; static size_t rezoom_size[MAX_THREADS]; /* * Image table */ static struct imd* images = NULL; /* * Number of loaded images */ static image_id anz_images = 0; /* * Number of allocated entries for images * (>= anz_images) */ static image_id alloc_images = 0; /* * Output framebuffer */ static PIXVAL* textur = NULL; /* * dirty tile management structures */ #define DIRTY_TILE_SIZE 16 #define DIRTY_TILE_SHIFT 4 static uint32 *tile_dirty = NULL; static uint32 *tile_dirty_old = NULL; static int tiles_per_line = 0; static int tile_buffer_per_line = 0; // number of tiles that fit the allocated buffer per line - maintain alignment - x=0 is always first bit in a word for each row static int tile_lines = 0; static int tile_buffer_length = 0; static int light_level = 0; static int night_shift = -1; /* * special colors during daytime */ rgb888_t display_day_lights[LIGHT_COUNT] = { { 0x57, 0x65, 0x6F }, // Dark windows, lit yellowish at night { 0x7F, 0x9B, 0xF1 }, // Lighter windows, lit blueish at night { 0xFF, 0xFF, 0x53 }, // Yellow light { 0xFF, 0x21, 0x1D }, // Red light { 0x01, 0xDD, 0x01 }, // Green light { 0x6B, 0x6B, 0x6B }, // Non-darkening grey 1 (menus) { 0x9B, 0x9B, 0x9B }, // Non-darkening grey 2 (menus) { 0xB3, 0xB3, 0xB3 }, // non-darkening grey 3 (menus) { 0xC9, 0xC9, 0xC9 }, // Non-darkening grey 4 (menus) { 0xDF, 0xDF, 0xDF }, // Non-darkening grey 5 (menus) { 0xE3, 0xE3, 0xFF }, // Nearly white light at day, yellowish light at night { 0xC1, 0xB1, 0xD1 }, // Windows, lit yellow { 0x4D, 0x4D, 0x4D }, // Windows, lit yellow { 0xE1, 0x00, 0xE1 }, // purple light for signals { 0x01, 0x01, 0xFF } // blue light }; /* * special colors during nighttime */ rgb888_t display_night_lights[LIGHT_COUNT] = { { 0xD3, 0xC3, 0x80 }, // Dark windows, lit yellowish at night { 0x80, 0xC3, 0xD3 }, // Lighter windows, lit blueish at night { 0xFF, 0xFF, 0x53 }, // Yellow light { 0xFF, 0x21, 0x1D }, // Red light { 0x01, 0xDD, 0x01 }, // Green light { 0x6B, 0x6B, 0x6B }, // Non-darkening grey 1 (menus) { 0x9B, 0x9B, 0x9B }, // Non-darkening grey 2 (menus) { 0xB3, 0xB3, 0xB3 }, // non-darkening grey 3 (menus) { 0xC9, 0xC9, 0xC9 }, // Non-darkening grey 4 (menus) { 0xDF, 0xDF, 0xDF }, // Non-darkening grey 5 (menus) { 0xFF, 0xFF, 0xE3 }, // Nearly white light at day, yellowish light at night { 0xD3, 0xC3, 0x80 }, // Windows, lit yellow { 0xD3, 0xC3, 0x80 }, // Windows, lit yellow { 0xE1, 0x00, 0xE1 }, // purple light for signals { 0x01, 0x01, 0xFF } // blue light }; // the players colors and colors for simple drawing operations // each 8 colors are a player color static const rgb888_t special_pal[SPECIAL_COLOR_COUNT] = { { 36, 75, 103 }, { 57, 94, 124 }, { 76, 113, 145 }, { 96, 132, 167 }, { 116, 151, 189 }, { 136, 171, 211 }, { 156, 190, 233 }, { 176, 210, 255 }, { 88, 88, 88 }, { 107, 107, 107 }, { 125, 125, 125 }, { 144, 144, 144 }, { 162, 162, 162 }, { 181, 181, 181 }, { 200, 200, 200 }, { 219, 219, 219 }, { 17, 55, 133 }, { 27, 71, 150 }, { 37, 86, 167 }, { 48, 102, 185 }, { 58, 117, 202 }, { 69, 133, 220 }, { 79, 149, 237 }, { 90, 165, 255 }, { 123, 88, 3 }, { 142, 111, 4 }, { 161, 134, 5 }, { 180, 157, 7 }, { 198, 180, 8 }, { 217, 203, 10 }, { 236, 226, 11 }, { 255, 249, 13 }, { 86, 32, 14 }, { 110, 40, 16 }, { 134, 48, 18 }, { 158, 57, 20 }, { 182, 65, 22 }, { 206, 74, 24 }, { 230, 82, 26 }, { 255, 91, 28 }, { 34, 59, 10 }, { 44, 80, 14 }, { 53, 101, 18 }, { 63, 122, 22 }, { 77, 143, 29 }, { 92, 164, 37 }, { 106, 185, 44 }, { 121, 207, 52 }, { 0, 86, 78 }, { 0, 108, 98 }, { 0, 130, 118 }, { 0, 152, 138 }, { 0, 174, 158 }, { 0, 196, 178 }, { 0, 218, 198 }, { 0, 241, 219 }, { 74, 7, 122 }, { 95, 21, 139 }, { 116, 37, 156 }, { 138, 53, 173 }, { 160, 69, 191 }, { 181, 85, 208 }, { 203, 101, 225 }, { 225, 117, 243 }, { 59, 41, 0 }, { 83, 55, 0 }, { 107, 69, 0 }, { 131, 84, 0 }, { 155, 98, 0 }, { 179, 113, 0 }, { 203, 128, 0 }, { 227, 143, 0 }, { 87, 0, 43 }, { 111, 11, 69 }, { 135, 28, 92 }, { 159, 45, 115 }, { 183, 62, 138 }, { 230, 74, 174 }, { 245, 121, 194 }, { 255, 156, 209 }, { 20, 48, 10 }, { 44, 74, 28 }, { 68, 99, 45 }, { 93, 124, 62 }, { 118, 149, 79 }, { 143, 174, 96 }, { 168, 199, 113 }, { 193, 225, 130 }, { 54, 19, 29 }, { 82, 44, 44 }, { 110, 69, 58 }, { 139, 95, 72 }, { 168, 121, 86 }, { 197, 147, 101 }, { 226, 173, 115 }, { 255, 199, 130 }, { 8, 11, 100 }, { 14, 22, 116 }, { 20, 33, 139 }, { 26, 44, 162 }, { 41, 74, 185 }, { 57, 104, 208 }, { 76, 132, 231 }, { 96, 160, 255 }, { 43, 30, 46 }, { 68, 50, 85 }, { 93, 70, 110 }, { 118, 91, 130 }, { 143, 111, 170 }, { 168, 132, 190 }, { 193, 153, 210 }, { 219, 174, 230 }, { 63, 18, 12 }, { 90, 38, 30 }, { 117, 58, 42 }, { 145, 78, 55 }, { 172, 98, 67 }, { 200, 118, 80 }, { 227, 138, 92 }, { 255, 159, 105 }, { 11, 68, 30 }, { 33, 94, 56 }, { 54, 120, 81 }, { 76, 147, 106 }, { 98, 174, 131 }, { 120, 201, 156 }, { 142, 228, 181 }, { 164, 255, 207 }, { 64, 0, 0 }, { 96, 0, 0 }, { 128, 0, 0 }, { 192, 0, 0 }, { 255, 0, 0 }, { 255, 64, 64 }, { 255, 96, 96 }, { 255, 128, 128 }, { 0, 128, 0 }, { 0, 196, 0 }, { 0, 225, 0 }, { 0, 240, 0 }, { 0, 255, 0 }, { 64, 255, 64 }, { 94, 255, 94 }, { 128, 255, 128 }, { 0, 0, 128 }, { 0, 0, 192 }, { 0, 0, 224 }, { 0, 0, 255 }, { 0, 64, 255 }, { 0, 94, 255 }, { 0, 106, 255 }, { 0, 128, 255 }, { 128, 64, 0 }, { 193, 97, 0 }, { 215, 107, 0 }, { 235, 118, 0 }, { 255, 128, 0 }, { 255, 149, 43 }, { 255, 170, 85 }, { 255, 193, 132 }, { 8, 52, 0 }, { 16, 64, 0 }, { 32, 80, 4 }, { 48, 96, 4 }, { 64, 112, 12 }, { 84, 132, 20 }, { 104, 148, 28 }, { 128, 168, 44 }, { 164, 164, 0 }, { 180, 180, 0 }, { 193, 193, 0 }, { 215, 215, 0 }, { 235, 235, 0 }, { 255, 255, 0 }, { 255, 255, 64 }, { 255, 255, 128 }, { 32, 4, 0 }, { 64, 20, 8 }, { 84, 28, 16 }, { 108, 44, 28 }, { 128, 56, 40 }, { 148, 72, 56 }, { 168, 92, 76 }, { 184, 108, 88 }, { 64, 0, 0 }, { 96, 8, 0 }, { 112, 16, 0 }, { 120, 32, 8 }, { 138, 64, 16 }, { 156, 72, 32 }, { 174, 96, 48 }, { 192, 128, 64 }, { 32, 32, 0 }, { 64, 64, 0 }, { 96, 96, 0 }, { 128, 128, 0 }, { 144, 144, 0 }, { 172, 172, 0 }, { 192, 192, 0 }, { 224, 224, 0 }, { 64, 96, 8 }, { 80, 108, 32 }, { 96, 120, 48 }, { 112, 144, 56 }, { 128, 172, 64 }, { 150, 210, 68 }, { 172, 238, 80 }, { 192, 255, 96 }, { 32, 32, 32 }, { 48, 48, 48 }, { 64, 64, 64 }, { 80, 80, 80 }, { 96, 96, 96 }, { 172, 172, 172 }, { 236, 236, 236 }, { 255, 255, 255 }, { 41, 41, 54 }, { 60, 45, 70 }, { 75, 62, 108 }, { 95, 77, 136 }, { 113, 105, 150 }, { 135, 120, 176 }, { 165, 145, 218 }, { 198, 191, 232 } }; /* * tile raster width */ scr_coord_val tile_raster_width = 16; // zoomed scr_coord_val base_tile_raster_width = 16; // original // variables for storing currently used image procedure set and tile raster width display_image_proc display_normal = NULL; display_image_proc display_color = NULL; display_blend_proc display_blend = NULL; display_alpha_proc display_alpha = NULL; signed short current_tile_raster_width = 0; static inline rgb888_t pixval_to_rgb888(PIXVAL colour) { // Scale each colour channel from 5 or 6 bits to 8 bits #ifdef RGB555 return { uint8(((colour >> 10) & 0x1F) * 0xFF / 0x1F), // R uint8(((colour >> 5) & 0x1F) * 0xFF / 0x1F), // G uint8(((colour >> 0) & 0x1F) * 0xFF / 0x1F) // B }; #else return { uint8(((colour >> 11) & 0x1F) * 0xFF / 0x1F), // R uint8(((colour >> 5) & 0x3F) * 0xFF / 0x3F), // G uint8(((colour >> 0) & 0x1F) * 0xFF / 0x1F) // B }; #endif } static inline PIXVAL pixval_to_rgb343(PIXVAL rgb) { // msb lsb // rgb555: xrrrrrgggggbbbbb // rgb565: rrrrrggggggbbbbb // rgb343: rrrggggbbb #ifdef RGB555 return ((rgb >> 5) & 0x0380) | ((rgb >> 3) & 0x0078) | ((rgb >> 2) & 0x07); #else return ((rgb >> 6) & 0x0380) | ((rgb >> 4) & 0x0078) | ((rgb >> 2) & 0x07); #endif } /* * Gets a colour index and returns RGB888 */ rgb888_t get_color_rgb(uint8 idx) { // special_pal has 224 rgb colors if (idx < SPECIAL_COLOR_COUNT) { return special_pal[idx]; } // if it uses one of the special light colours it's under display_day_lights if (idx < SPECIAL_COLOR_COUNT + LIGHT_COUNT) { return display_day_lights[idx - SPECIAL_COLOR_COUNT]; } // Return black for anything else return rgb888_t{0,0,0}; } /** * Convert indexed colors to rgb and back */ PIXVAL color_idx_to_rgb(PIXVAL idx) { return (specialcolormap_all_day[(idx)&0x00FF]); } PIXVAL color_rgb_to_idx(PIXVAL color) { for(PIXVAL i=0; i<=0xff; i++) { if (specialcolormap_all_day[i] == color) { return i; } } return 0; } /* * Convert env_t colours from RGB888 to the system format */ void env_t_rgb_to_system_colors() { // get system colours for the default colours or settings.xml env_t::default_window_title_color = get_system_color(env_t::default_window_title_color_rgb); env_t::front_window_text_color = get_system_color(env_t::front_window_text_color_rgb); env_t::bottom_window_text_color = get_system_color(env_t::bottom_window_text_color_rgb); env_t::tooltip_color = get_system_color(env_t::tooltip_color_rgb); env_t::tooltip_textcolor = get_system_color(env_t::tooltip_textcolor_rgb); env_t::cursor_overlay_color = get_system_color(env_t::cursor_overlay_color_rgb); env_t::background_color = get_system_color(env_t::background_color_rgb); } /* changes the raster width after loading */ scr_coord_val display_set_base_raster_width(scr_coord_val new_raster) { scr_coord_val old = base_tile_raster_width; base_tile_raster_width = new_raster; tile_raster_width = (new_raster * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; return old; } // ----------------------------------- clipping routines ------------------------------------------ scr_coord_val display_get_width() { return disp_actual_width; } // only use, if you are really really sure! void display_set_actual_width(scr_coord_val w) { disp_actual_width = w; } scr_coord_val display_get_height() { return disp_height; } void display_set_height(scr_coord_val const h) { disp_height = h; } /** * Clips intervall [x,x+w] such that left <= x and x+w <= right. * If @p w is negative, it stays negative. * @returns difference between old and new value of @p x. */ inline int clip_intv(scr_coord_val &x, scr_coord_val &w, const scr_coord_val left, const scr_coord_val right) { scr_coord_val xx = min(x+w, right); scr_coord_val xoff = left - x; if (xoff > 0) { // equivalent to x < left x = left; } else { xoff = 0; } w = xx - x; return xoff; } /// wrapper for clip_intv static int clip_wh(scr_coord_val *x, scr_coord_val *w, const scr_coord_val left, const scr_coord_val right) { return clip_intv(*x, *w, left, right); } /// wrapper for clip_intv, @returns whether @p w is positive static bool clip_lr(scr_coord_val *x, scr_coord_val *w, const scr_coord_val left, const scr_coord_val right) { clip_intv(*x, *w, left, right); return *w > 0; } /** * Get the clipping rectangle dimensions */ clip_dimension display_get_clip_wh(CLIP_NUM_DEF0) { return CR.clip_rect; } /** * Set the clipping rectangle dimensions * * here, a pixel at coordinate xp is displayed if * clip. x <= xp < clip.xx * the right-most pixel of an image located at xp with width w is displayed if * clip.x < xp+w <= clip.xx * analogously for the y coordinate */ void display_set_clip_wh(scr_coord_val x, scr_coord_val y, scr_coord_val w, scr_coord_val h CLIP_NUM_DEF, bool fit) { if (!fit) { clip_wh( &x, &w, 0, disp_width); clip_wh( &y, &h, 0, disp_height); } else { clip_wh( &x, &w, CR.clip_rect.x, CR.clip_rect.xx); clip_wh( &y, &h, CR.clip_rect.y, CR.clip_rect.yy); } CR.clip_rect.x = x; CR.clip_rect.y = y; CR.clip_rect.w = w; CR.clip_rect.h = h; CR.clip_rect.xx = x + w; // watch out, clips to scr_coord_val max CR.clip_rect.yy = y + h; // watch out, clips to scr_coord_val max } void display_push_clip_wh(scr_coord_val x, scr_coord_val y, scr_coord_val w, scr_coord_val h CLIP_NUM_DEF) { assert(!CR.swap_active); // save active clipping rectangle CR.clip_rect_swap = CR.clip_rect; // active rectangle provided by parameters display_set_clip_wh(x, y, w, h CLIP_NUM_PAR); CR.swap_active = true; } void display_swap_clip_wh(CLIP_NUM_DEF0) { if (CR.swap_active) { // swap clipping rectangles clip_dimension save = CR.clip_rect; CR.clip_rect = CR.clip_rect_swap; CR.clip_rect_swap = save; } } void display_pop_clip_wh(CLIP_NUM_DEF0) { if (CR.swap_active) { // swap original clipping rectangle back CR.clip_rect = CR.clip_rect_swap; CR.swap_active = false; } } /* * Add clipping line through (x0,y0) and (x1,y1) * with associated ribi * if ribi & 16 then non-convex clipping. */ void add_poly_clip(int x0,int y0, int x1, int y1, int ribi CLIP_NUM_DEF) { if( CR.number_of_clips < MAX_POLY_CLIPS ) { CR.poly_clips[CR.number_of_clips].clip_from_to( x0, y0, x1, y1, ribi&16 ); CR.clip_ribi[CR.number_of_clips] = ribi&15; CR.number_of_clips++; } } /* * Clears all clipping lines */ void clear_all_poly_clip(CLIP_NUM_DEF0) { CR.number_of_clips = 0; CR.active_ribi = 15; // set all to active } /* * Activates clipping lines associated with ribi * ie if clip_ribi[i] & active_ribi */ void activate_ribi_clip(int ribi CLIP_NUM_DEF) { CR.active_ribi = ribi; } /* * Initialize clipping region for image starting at screen line y */ static inline void init_ranges(int y CLIP_NUM_DEF) { for( uint8 i = 0; i < CR.number_of_clips; i++ ) { if( (CR.clip_ribi[i] & CR.active_ribi) ) { CR.poly_clips[i].get_x_range( y, CR.xranges[i], CR.active_ribi & 16 ); } } } /* * Returns left/right border of visible area * Computes l/r border for the next line (ie y+1) * takes also clipping rectangle into account */ inline void get_xrange_and_step_y(int &xmin, int &xmax CLIP_NUM_DEF) { xmin = CR.clip_rect.x; xmax = CR.clip_rect.xx; for( uint8 i = 0; i < CR.number_of_clips; i++ ) { if( (CR.clip_ribi[i] & CR.active_ribi) ) { CR.poly_clips[i].inc_y( CR.xranges[i], xmin, xmax ); } } } // ------------------------------ dirty tile stuff -------------------------------- /* * Simutrans keeps a list of dirty areas, i.e. places that received new graphics * and must be copied to the screen after an update */ static inline void mark_tile_dirty(const int x, const int y) { const int bit = x + y * tile_buffer_per_line; #if 0 assert(bit / 8 < tile_buffer_length); #endif tile_dirty[bit >> 5] |= 1 << (bit & 31); } /** * Mark tile as dirty, with _NO_ clipping */ static void mark_rect_dirty_nc(scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2) { // floor to tile size x1 >>= DIRTY_TILE_SHIFT; y1 >>= DIRTY_TILE_SHIFT; x2 >>= DIRTY_TILE_SHIFT; y2 >>= DIRTY_TILE_SHIFT; #if 0 assert(x1 >= 0); assert(x1 < tiles_per_line); assert(y1 >= 0); assert(y1 < tile_lines); assert(x2 >= 0); assert(x2 < tiles_per_line); assert(y2 >= 0); assert(y2 < tile_lines); #endif for( ; y1 <= y2; y1++ ) { int bit = y1 * tile_buffer_per_line + x1; const int end = bit + x2 - x1; do { tile_dirty[bit >> 5] |= 1 << (bit & 31); } while( ++bit <= end ); } } /** * Mark tile as dirty, with clipping */ void mark_rect_dirty_wc(scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2) { // inside display? if( x2 >= 0 && y2 >= 0 && x1 < disp_width && y1 < disp_height ) { if( x1 < 0 ) { x1 = 0; } if( y1 < 0 ) { y1 = 0; } if( x2 >= disp_width ) { x2 = disp_width - 1; } if( y2 >= disp_height ) { y2 = disp_height - 1; } mark_rect_dirty_nc( x1, y1, x2, y2 ); } } void mark_rect_dirty_clip(scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2 CLIP_NUM_DEF) { // inside clip_rect? if( x2 >= CR.clip_rect.x && y2 >= CR.clip_rect.y && x1 < CR.clip_rect.xx && y1 < CR.clip_rect.yy ) { if( x1 < CR.clip_rect.x ) { x1 = CR.clip_rect.x; } if( y1 < CR.clip_rect.y ) { y1 = CR.clip_rect.y; } if( x2 >= CR.clip_rect.xx ) { x2 = CR.clip_rect.xx-1; } if( y2 >= CR.clip_rect.yy ) { y2 = CR.clip_rect.yy-1; } mark_rect_dirty_nc( x1, y1, x2, y2 ); } } /** * Mark the whole screen as dirty. * */ void mark_screen_dirty() { memset( tile_dirty, 0xFFFFFFFF, sizeof(uint32) * tile_buffer_length ); } /** * the area of this image need update */ void display_mark_img_dirty(image_id image, scr_coord_val xp, scr_coord_val yp) { if( image < anz_images ) { mark_rect_dirty_wc( xp + images[image].x, yp + images[image].y, xp + images[image].x + images[image].w - 1, yp + images[image].y + images[image].h - 1 ); } } // ------------------------- rendering images for display -------------------------------- /* * Simutrans caches player colored images, to allow faster drawing of them * They are derived from a base image, which may need zooming too */ /** * Flag all images for rezoom on next draw */ static void rezoom() { for( image_id n = 0; n < anz_images; n++ ) { if( (images[n].recode_flags & FLAG_ZOOMABLE) != 0 && images[n].base_h > 0 ) { images[n].recode_flags |= FLAG_REZOOM; } } } void set_zoom_factor(int z) { // do not zoom beyond 4 pixels if( (base_tile_raster_width * zoom_num[z]) / zoom_den[z] > 4 ) { zoom_factor = z; tile_raster_width = (base_tile_raster_width * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; dbg->message("set_zoom_factor()", "Zoom level now %d (%i/%i)", zoom_factor, zoom_num[zoom_factor], zoom_den[zoom_factor] ); rezoom(); } } int zoom_factor_up() { // zoom out, if size permits if( zoom_factor > 0 ) { set_zoom_factor( zoom_factor-1 ); return true; } return false; } int zoom_factor_down() { if( zoom_factor < MAX_ZOOM_FACTOR ) { set_zoom_factor( zoom_factor+1 ); return true; } return false; } static uint8 player_night=0xFF; static uint8 player_day=0xFF; static void activate_player_color(sint8 player_nr, bool daynight) { // caches the last settings if(!daynight) { if(player_day!=player_nr) { int i; player_day = player_nr; for(i=0; i<8; i++ ) { rgbmap_all_day[0x8000+i] = specialcolormap_all_day[player_offsets[player_day][0]+i]; rgbmap_all_day[0x8008+i] = specialcolormap_all_day[player_offsets[player_day][1]+i]; } } rgbmap_current = rgbmap_all_day; } else { // changing color table if(player_night!=player_nr) { int i; player_night = player_nr; for(i=0; i<8; i++ ) { rgbmap_day_night[0x8000+i] = specialcolormap_day_night[player_offsets[player_night][0]+i]; rgbmap_day_night[0x8008+i] = specialcolormap_day_night[player_offsets[player_night][1]+i]; } } rgbmap_current = rgbmap_day_night; } } /** * Flag all images to recode colors on next draw */ static void recode() { for( image_id n = 0; n < anz_images; n++ ) { images[n].player_flags = 0xFFFF; // recode all player colors } } /** * Convert a certain image data to actual output data */ static void recode_img_src_target(scr_coord_val h, PIXVAL *src, PIXVAL *target) { if( h > 0 ) { do { uint16 runlen = *target++ = *src++; // decode rows do { // clear run is always ok runlen = *target++ = *src++; if( runlen & TRANSPARENT_RUN ) { runlen &= ~TRANSPARENT_RUN; while( runlen-- ) { if( *src < 0x8020+(31*16) ) { // expand transparent player color const uint8 alpha = (*src-0x8020) % 31; const PIXVAL colour = rgbmap_day_night[(*src-0x8020)/31+0x8000]; *target++ = 0x8020 + 31*31 + pixval_to_rgb343(colour)*31 + alpha; src ++; } else { *target++ = *src++; } } } else { // now just convert the color pixels while( runlen-- ) { *target++ = rgbmap_day_night[*src++]; } } // next clear run or zero = end } while( (runlen = *target++ = *src++) ); } while( --h ); } } image_id get_image_count() { return anz_images; } /** * Handles the conversion of an image to the output color */ static void recode_img(const image_id n, const sint8 player_nr) { // may this image be zoomed #ifdef MULTI_THREAD pthread_mutex_lock( &recode_img_mutex ); if( (images[n].player_flags & (1< return transparent } // pixel transparent but all three neighbors not -> interpolate uint8 valid=0; uint8 r=0, g=0, b=0; SumSubpixel(pab); SumSubpixel(prl); if(valid==0) { return 0x73FE; } else if(valid==255) { return (0x8000 | r) + (((uint16)g)<<5) + (((uint16)b)<<10); } else { return (r/valid) + (((uint16)(g/valid))<<5) + (((uint16)(b/valid))<<10); } } else { if ( (pab[0] & prl[0] & pdia[0])!=255) { // pixel and one neighbor not transparent return compress_pixel(p); } return 0x73FE; } } /** * Convert base image data to actual image size * Uses averages of all sampled points to get the "real" value * Blurs a bit */ static void rezoom_img(const image_id n) { // may this image be zoomed if( n < anz_images && images[n].base_h > 0 ) { #ifdef MULTI_THREAD pthread_mutex_lock( &rezoom_img_mutex[n % env_t::num_threads] ); if( (images[n].recode_flags & FLAG_REZOOM) == 0 ) { // other routine did already the re-zooming ... pthread_mutex_unlock( &rezoom_img_mutex[n % env_t::num_threads] ); return; } #endif // we may need night conversion afterwards images[n].player_flags = 0xFFFF; // recode all player colors // we recalculate the len (since it may be larger than before) // thus we have to free the old caches if( images[n].zoom_data != NULL ) { free( images[n].zoom_data ); images[n].zoom_data = NULL; } for( uint8 i = 0; i < MAX_PLAYER_COUNT; i++ ) { if( images[n].data[i] != NULL ) { free( images[n].data[i] ); images[n].data[i] = NULL; } } // just restore original size? if( zoom_factor == ZOOM_NEUTRAL || (images[n].recode_flags&FLAG_ZOOMABLE) == 0 ) { // this we can do be a simple copy ... images[n].x = images[n].base_x; images[n].w = images[n].base_w; images[n].y = images[n].base_y; images[n].h = images[n].base_h; // recalculate length sint16 h = images[n].base_h; PIXVAL *sp = images[n].base_data; while( h-- > 0 ) { do { // clear run + colored run + next clear run sp++; sp += (*sp)&(~TRANSPARENT_RUN); // MSVC crashes on (*sp)&(~TRANSPARENT_RUN) + 1 !!! sp ++; } while( *sp ); sp++; } images[n].len = (uint32)(size_t)(sp - images[n].base_data); images[n].recode_flags &= ~FLAG_REZOOM; #ifdef MULTI_THREAD pthread_mutex_unlock( &rezoom_img_mutex[n % env_t::num_threads] ); #endif return; } // now we want to downsize the image // just divide the sizes images[n].x = (images[n].base_x * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; images[n].y = (images[n].base_y * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; images[n].w = (images[n].base_w * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; images[n].h = (images[n].base_h * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; if( images[n].h > 0 && images[n].w > 0 ) { // just recalculate the image in the new size PIXVAL *src = images[n].base_data; PIXVAL *dest = NULL; // embed the baseimage in an image with margin ~ remainder const sint16 x_rem = (images[n].base_x * zoom_num[zoom_factor]) % zoom_den[zoom_factor]; const sint16 y_rem = (images[n].base_y * zoom_num[zoom_factor]) % zoom_den[zoom_factor]; const sint16 xl_margin = max( x_rem, 0); const sint16 xr_margin = max(-x_rem, 0); const sint16 yl_margin = max( y_rem, 0); const sint16 yr_margin = max(-y_rem, 0); // baseimage top-left corner is at (xl_margin, yl_margin) // ... low-right corner is at (xr_margin, yr_margin) sint32 orgzoomwidth = ((images[n].base_w + zoom_den[zoom_factor] - 1 ) / zoom_den[zoom_factor]) * zoom_den[zoom_factor]; sint32 newzoomwidth = (orgzoomwidth*zoom_num[zoom_factor])/zoom_den[zoom_factor]; sint32 orgzoomheight = ((images[n].base_h + zoom_den[zoom_factor] - 1 ) / zoom_den[zoom_factor]) * zoom_den[zoom_factor]; sint32 newzoomheight = (orgzoomheight * zoom_num[zoom_factor]) / zoom_den[zoom_factor]; // we will unpack, re-sample, pack it // thus the unpack buffer must at least fit the window => find out maximum size // Note: This value is certainly way bigger than the average size we'll get, // but it's the worst scenario possible, a succession of solid - transparent - solid - transparent // pattern. // This would encode EACH LINE as: // 0x0000 (0 transparent) 0x0001 PIXWORD 0x0001 (every 2 pixels, 3 words) 0x0000 (EOL) // The extra +1 is to make sure we cover divisions with module != 0 // We end with an over sized buffer for the normal usage, but since it's re-used for all re-zooms, // it's not performance critical and we are safe from all possible inputs. size_t new_size = ( ( (newzoomwidth * 3) / 2 ) + 1 + 2) * newzoomheight * sizeof(PIXVAL); size_t unpack_size = (xl_margin + orgzoomwidth + xr_margin) * (yl_margin + orgzoomheight + yr_margin) * 4; if( unpack_size > new_size ) { new_size = unpack_size; } new_size = ((new_size * 128) + 127) / 128; // enlarge slightly to try and keep buffers on their own cacheline for multithreaded access. A portable aligned_alloc would be better. if( rezoom_size[n % env_t::num_threads] < new_size ) { free( rezoom_baseimage2[n % env_t::num_threads] ); free( rezoom_baseimage[n % env_t::num_threads] ); rezoom_size[n % env_t::num_threads] = new_size; rezoom_baseimage[n % env_t::num_threads] = MALLOCN( uint8, new_size ); rezoom_baseimage2[n % env_t::num_threads] = (PIXVAL *)MALLOCN( uint8, new_size ); } memset( rezoom_baseimage[n % env_t::num_threads], 255, new_size ); // fill with invalid data to mark transparent regions // index of top-left corner uint32 baseoff = 4 * (yl_margin * (xl_margin + orgzoomwidth + xr_margin) + xl_margin); sint32 basewidth = xl_margin + orgzoomwidth + xr_margin; // now: unpack the image for( sint32 y = 0; y < images[n].base_h; ++y ) { uint16 runlen; uint8 *p = rezoom_baseimage[n % env_t::num_threads] + baseoff + y * (basewidth * 4); // decode line runlen = *src++; do { // clear run p += (runlen & ~TRANSPARENT_RUN) * 4; // color pixel runlen = (*src++) & ~TRANSPARENT_RUN; while( runlen-- ) { // get rgb components PIXVAL s = *src++; *p++ = (s>>15); *p++ = (s & 31); s >>= 5; *p++ = (s & 31); s >>= 5; *p++ = (s & 31); } runlen = *src++; } while( runlen != 0 ); } // now we have the image, we do a repack then dest = rezoom_baseimage2[n % env_t::num_threads]; switch( zoom_den[zoom_factor] ) { case 1: { assert(zoom_num[zoom_factor]==2); // first half row - just copy values, do not fiddle with neighbor colors uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff; for( sint16 x = 0; x < orgzoomwidth; x++ ) { PIXVAL c1 = compress_pixel_transparent( p1 + (x * 4) ); // now set the pixel ... dest[x * 2] = c1; dest[x * 2 + 1] = c1; } // skip one line dest += newzoomwidth; for( sint16 y = 0; y < orgzoomheight - 1; y++ ) { uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + y * (basewidth * 4); // copy leftmost pixels dest[0] = compress_pixel_transparent( p1 ); dest[newzoomwidth] = compress_pixel_transparent( p1 + basewidth * 4 ); for( sint16 x = 0; x < orgzoomwidth - 1; x++ ) { uint8 *px1 = p1 + (x * 4); // pixel at 2,2 in 2x2 superpixel dest[x * 2 + 1] = zoomin_pixel( px1, px1 + 4, px1 + basewidth * 4, px1 + basewidth * 4 + 4 ); // 2x2 superpixel is transparent but original pixel was not // preserve one pixel if( dest[x * 2 + 1] == 0x73FE && px1[0] != 255 && dest[x * 2] == 0x73FE && dest[x * 2 - newzoomwidth] == 0x73FE && dest[x * 2 - newzoomwidth - 1] == 0x73FE ) { // preserve one pixel dest[x * 2 + 1] = compress_pixel( px1 ); } // pixel at 2,1 in next 2x2 superpixel dest[x * 2 + 2] = zoomin_pixel( px1 + 4, px1, px1 + basewidth * 4 + 4, px1 + basewidth * 4 ); // pixel at 1,2 in next row 2x2 superpixel dest[x * 2 + newzoomwidth + 1] = zoomin_pixel( px1 + basewidth * 4, px1 + basewidth * 4 + 4, px1, px1 + 4 ); // pixel at 1,1 in next row next 2x2 superpixel dest[x * 2 + newzoomwidth + 2] = zoomin_pixel( px1 + basewidth * 4 + 4, px1 + basewidth * 4, px1 + 4, px1 ); } // copy rightmost pixels dest[2 * orgzoomwidth - 1] = compress_pixel_transparent( p1 + 4 * (orgzoomwidth - 1) ); dest[2 * orgzoomwidth + newzoomwidth - 1] = compress_pixel_transparent( p1 + 4 * (orgzoomwidth - 1) + basewidth * 4 ); // skip two lines dest += 2 * newzoomwidth; } // last half row - just copy values, do not fiddle with neighbor colors p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + (orgzoomheight - 1) * (basewidth * 4); for( sint16 x = 0; x < orgzoomwidth; x++ ) { PIXVAL c1 = compress_pixel_transparent( p1 + (x * 4) ); // now set the pixel ... dest[x * 2] = c1; dest[x * 2 + 1] = c1; } break; } case 2: for( sint16 y = 0; y < newzoomheight; y++ ) { uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 0 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p2 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 1 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); for( sint16 x = 0; x < newzoomwidth; x++ ) { uint8 valid = 0; uint8 r = 0, g = 0, b = 0; sint16 xreal1 = ((x * zoom_den[zoom_factor] + 0 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal2 = ((x * zoom_den[zoom_factor] + 1 - x_rem) / zoom_num[zoom_factor]) * 4; SumSubpixel( p1 + xreal1 ); SumSubpixel( p1 + xreal2 ); SumSubpixel( p2 + xreal1 ); SumSubpixel( p2 + xreal2 ); if( valid == 0 ) { *dest++ = 0x73FE; } else if( valid == 255 ) { *dest++ = (0x8000 | r) + (((uint16)g)<<5) + (((uint16)b)<<10); } else { *dest++ = (r/valid) + (((uint16)(g/valid))<<5) + (((uint16)(b/valid))<<10); } } } break; case 3: for( sint16 y = 0; y < newzoomheight; y++ ) { uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 0 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p2 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 1 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p3 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 2 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); for( sint16 x = 0; x < newzoomwidth; x++ ) { uint8 valid = 0; uint16 r = 0, g = 0, b = 0; sint16 xreal1 = ((x * zoom_den[zoom_factor] + 0 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal2 = ((x * zoom_den[zoom_factor] + 1 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal3 = ((x * zoom_den[zoom_factor] + 2 - x_rem) / zoom_num[zoom_factor]) * 4; SumSubpixel( p1 + xreal1 ); SumSubpixel( p1 + xreal2 ); SumSubpixel( p1 + xreal3 ); SumSubpixel( p2 + xreal1 ); SumSubpixel( p2 + xreal2 ); SumSubpixel( p2 + xreal3 ); SumSubpixel( p3 + xreal1 ); SumSubpixel( p3 + xreal2 ); SumSubpixel( p3 + xreal3 ); if( valid == 0 ) { *dest++ = 0x73FE; } else if( valid == 255 ) { *dest++ = (0x8000 | r) + (((uint16)g)<<5) + (((uint16)b)<<10); } else { *dest++ = (r/valid) | (((uint16)(g/valid))<<5) | (((uint16)(b/valid))<<10); } } } break; case 4: for( sint16 y = 0; y < newzoomheight; y++ ) { uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 0 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p2 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 1 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p3 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 2 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p4 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 3 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); for( sint16 x = 0; x < newzoomwidth; x++ ) { uint8 valid = 0; uint16 r = 0, g = 0, b = 0; sint16 xreal1 = ((x * zoom_den[zoom_factor] + 0 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal2 = ((x * zoom_den[zoom_factor] + 1 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal3 = ((x * zoom_den[zoom_factor] + 2 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal4 = ((x * zoom_den[zoom_factor] + 3 - x_rem) / zoom_num[zoom_factor]) * 4; SumSubpixel( p1 + xreal1 ); SumSubpixel( p1 + xreal2 ); SumSubpixel( p1 + xreal3 ); SumSubpixel( p1 + xreal4 ); SumSubpixel( p2 + xreal1 ); SumSubpixel( p2 + xreal2 ); SumSubpixel( p2 + xreal3 ); SumSubpixel( p2 + xreal4 ); SumSubpixel( p3 + xreal1 ); SumSubpixel( p3 + xreal2 ); SumSubpixel( p3 + xreal3 ); SumSubpixel( p3 + xreal4 ); SumSubpixel( p4 + xreal1 ); SumSubpixel( p4 + xreal2 ); SumSubpixel( p4 + xreal3 ); SumSubpixel( p4 + xreal4 ); if( valid == 0 ) { *dest++ = 0x73FE; } else if( valid == 255 ) { *dest++ = (0x8000 | r) + (((uint16)g)<<5) + (((uint16)b)<<10); } else { *dest++ = (r/valid) | (((uint16)(g/valid))<<5) | (((uint16)(b/valid))<<10); } } } break; case 8: for( sint16 y = 0; y < newzoomheight; y++ ) { uint8 *p1 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 0 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p2 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 1 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p3 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 2 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p4 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 3 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p5 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 4 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p6 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 5 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p7 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 6 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); uint8 *p8 = rezoom_baseimage[n % env_t::num_threads] + baseoff + ((y * zoom_den[zoom_factor] + 7 - y_rem) / zoom_num[zoom_factor]) * (basewidth * 4); for( sint16 x = 0; x < newzoomwidth; x++ ) { uint8 valid = 0; uint16 r = 0, g = 0, b = 0; sint16 xreal1 = ((x * zoom_den[zoom_factor] + 0 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal2 = ((x * zoom_den[zoom_factor] + 1 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal3 = ((x * zoom_den[zoom_factor] + 2 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal4 = ((x * zoom_den[zoom_factor] + 3 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal5 = ((x * zoom_den[zoom_factor] + 4 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal6 = ((x * zoom_den[zoom_factor] + 5 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal7 = ((x * zoom_den[zoom_factor] + 6 - x_rem) / zoom_num[zoom_factor]) * 4; sint16 xreal8 = ((x * zoom_den[zoom_factor] + 7 - x_rem) / zoom_num[zoom_factor]) * 4; SumSubpixel( p1 + xreal1 ); SumSubpixel( p1 + xreal2 ); SumSubpixel( p1 + xreal3 ); SumSubpixel( p1 + xreal4 ); SumSubpixel( p1 + xreal5 ); SumSubpixel( p1 + xreal6 ); SumSubpixel( p1 + xreal7 ); SumSubpixel( p1 + xreal8 ); SumSubpixel( p2 + xreal1 ); SumSubpixel( p2 + xreal2 ); SumSubpixel( p2 + xreal3 ); SumSubpixel( p2 + xreal4 ); SumSubpixel( p2 + xreal5 ); SumSubpixel( p2 + xreal6 ); SumSubpixel( p2 + xreal7 ); SumSubpixel( p2 + xreal8 ); SumSubpixel( p3 + xreal1 ); SumSubpixel( p3 + xreal2 ); SumSubpixel( p3 + xreal3 ); SumSubpixel( p3 + xreal4 ); SumSubpixel( p3 + xreal5 ); SumSubpixel( p3 + xreal6 ); SumSubpixel( p3 + xreal7 ); SumSubpixel( p3 + xreal8 ); SumSubpixel( p4 + xreal1 ); SumSubpixel( p4 + xreal2 ); SumSubpixel( p4 + xreal3 ); SumSubpixel( p4 + xreal4 ); SumSubpixel( p4 + xreal5 ); SumSubpixel( p4 + xreal6 ); SumSubpixel( p4 + xreal7 ); SumSubpixel( p4 + xreal8 ); SumSubpixel( p5 + xreal1 ); SumSubpixel( p5 + xreal2 ); SumSubpixel( p5 + xreal3 ); SumSubpixel( p5 + xreal4 ); SumSubpixel( p5 + xreal5 ); SumSubpixel( p5 + xreal6 ); SumSubpixel( p5 + xreal7 ); SumSubpixel( p5 + xreal8 ); SumSubpixel( p6 + xreal1 ); SumSubpixel( p6 + xreal2 ); SumSubpixel( p6 + xreal3 ); SumSubpixel( p6 + xreal4 ); SumSubpixel( p6 + xreal5 ); SumSubpixel( p6 + xreal6 ); SumSubpixel( p6 + xreal7 ); SumSubpixel( p6 + xreal8 ); SumSubpixel( p7 + xreal1 ); SumSubpixel( p7 + xreal2 ); SumSubpixel( p7 + xreal3 ); SumSubpixel( p7 + xreal4 ); SumSubpixel( p7 + xreal5 ); SumSubpixel( p7 + xreal6 ); SumSubpixel( p7 + xreal7 ); SumSubpixel( p7 + xreal8 ); SumSubpixel( p8 + xreal1 ); SumSubpixel( p8 + xreal2 ); SumSubpixel( p8 + xreal3 ); SumSubpixel( p8 + xreal4 ); SumSubpixel( p8 + xreal5 ); SumSubpixel( p8 + xreal6 ); SumSubpixel( p8 + xreal7 ); SumSubpixel( p8 + xreal8 ); if( valid == 0 ) { *dest++ = 0x73FE; } else if( valid == 255 ) { *dest++ = (0x8000 | r) + (((uint16)g)<<5) + (((uint16)b)<<10); } else { *dest++ = (r/valid) | (((uint16)(g/valid))<<5) | (((uint16)(b/valid))<<10); } } } break; default: assert(0); } // now encode the image again dest = (PIXVAL*)rezoom_baseimage[n % env_t::num_threads]; for( sint16 y = 0; y < newzoomheight; y++ ) { PIXVAL *line = ((PIXVAL *)rezoom_baseimage2[n % env_t::num_threads]) + (y * newzoomwidth); PIXVAL count; sint16 x = 0; uint16 clear_colored_run_pair_count = 0; do { // check length of transparent pixels for( count = 0; x < newzoomwidth && line[x] == 0x73FE; count++, x++ ) {} // first runlength: transparent pixels *dest++ = count; uint16 has_alpha = 0; // copy for non-transparent count = 0; while( x < newzoomwidth && line[x] != 0x73FE ) { PIXVAL pixval = line[x++]; if( pixval >= 0x8020 && !has_alpha ) { if( count ) { *dest++ = count; dest += count; count = 0; *dest++ = TRANSPARENT_RUN; } has_alpha = TRANSPARENT_RUN; } else if( pixval < 0x8020 && has_alpha ) { if( count ) { *dest++ = count+TRANSPARENT_RUN; dest += count; count = 0; *dest++ = TRANSPARENT_RUN; } has_alpha = 0; } count++; dest[count] = pixval; } /* * If it is not the first clear-colored-run pair and its colored run is empty * --> it is superfluous and can be removed by rolling back the pointer */ if( clear_colored_run_pair_count > 0 && count == 0 ) { dest--; // this only happens at the end of a line, so no need to increment clear_colored_run_pair_count } else { *dest++ = count+has_alpha; // number of colored pixels dest += count; // skip them clear_colored_run_pair_count++; } } while( x < newzoomwidth ); *dest++ = 0; // mark line end } // something left? images[n].w = newzoomwidth; images[n].h = newzoomheight; if( newzoomheight > 0 ) { const size_t zoom_len = (size_t)(((uint8 *)dest) - ((uint8 *)rezoom_baseimage[n % env_t::num_threads])); images[n].len = (uint32)(zoom_len / sizeof(PIXVAL)); images[n].zoom_data = MALLOCN(PIXVAL, images[n].len); assert( images[n].zoom_data ); memcpy( images[n].zoom_data, rezoom_baseimage[n % env_t::num_threads], zoom_len ); } } else { // if (images[n].w <= 0) { // // h=0 will be ignored, with w=0 there was an error! // printf("WARNING: image%d w=0!\n", n); // } images[n].h = 0; } images[n].recode_flags &= ~FLAG_REZOOM; #ifdef MULTI_THREAD pthread_mutex_unlock( &rezoom_img_mutex[n % env_t::num_threads] ); #endif } } // get next smallest size when scaling to percent scr_size display_get_best_matching_size(const image_id n, sint16 zoom_percent) { if (n < anz_images && images[n].base_h > 0) { int new_w = (images[n].base_w * zoom_percent + 1) / 100; for (int i = 0; i <= MAX_ZOOM_FACTOR; i++) { int zoom_w = (images[n].base_w * zoom_num[i]) / zoom_den[i]; int zoom_h = (images[n].base_h * zoom_num[i]) / zoom_den[i]; if (zoom_w <= new_w) { // first size smaller or equal to requested return scr_size(zoom_w, zoom_h); } } } return scr_size(32, 32); // default size } // force a certain size on a image (for rescaling tool images) void display_fit_img_to_width( const image_id n, sint16 new_w ) { if( n < anz_images && images[n].base_h > 0 && images[n].w != new_w ) { int old_zoom_factor = zoom_factor; for( int i=0; i<=MAX_ZOOM_FACTOR; i++ ) { int zoom_w = (images[n].base_w * zoom_num[i]) / zoom_den[i]; if( zoom_w <= new_w ) { uint8 old_zoom_flag = images[n].recode_flags & FLAG_ZOOMABLE; images[n].recode_flags |= FLAG_REZOOM | FLAG_ZOOMABLE; zoom_factor = i; rezoom_img(n); images[n].recode_flags &= ~FLAG_ZOOMABLE; images[n].recode_flags |= old_zoom_flag; zoom_factor = old_zoom_factor; return; } } } } static void calc_base_pal_from_night_shift(const int night) { const int night2 = min(night, 4); const int day = 4 - night2; unsigned int i; // constant multiplier 0,66 - dark night 255 will drop to 49, 55 to 10 // 0,7 - dark, but all is visible 61 13 // 0,73 72 15 // 0,75 - quite bright 80 17 // 0,8 bright 104 22 const double RG_night_multiplier = pow(0.75, night) * ((light_level + 8.0) / 8.0); const double B_night_multiplier = pow(0.83, night) * ((light_level + 8.0) / 8.0); for (i = 0; i < 0x8000; i++) { // (1<<15) this is total no of all possible colors in RGB555) // RGB 555 input int R = (i & 0x7C00) >> 7; int G = (i & 0x03E0) >> 2; int B = (i & 0x001F) << 3; // lines generate all possible colors in 555RGB code - input // however the result is in 888RGB - 8bit per channel R = (int)(R * RG_night_multiplier); G = (int)(G * RG_night_multiplier); B = (int)(B * B_night_multiplier); rgbmap_day_night[i] = get_system_color({ (uint8)R, (uint8)G, (uint8)B }); } // again the same but for transparent colors for (i = 0; i < 0x0400; i++) { // RGB 343 input int R = (i & 0x0380) >> 2; int G = (i & 0x0078) << 1; int B = (i & 0x0007) << 5; // lines generate all possible colors in 343RGB code - input // however the result is in 888RGB - 8bit per channel R = (int)(R * RG_night_multiplier); G = (int)(G * RG_night_multiplier); B = (int)(B * B_night_multiplier); PIXVAL color = get_system_color({ (uint8)R, (uint8)G, (uint8)B }); rgbmap_day_night[0x8000 +MAX_PLAYER_COUNT + LIGHT_COUNT + i] = color; } // player color map (and used for map display etc.) for (i = 0; i < SPECIAL_COLOR_COUNT; i++) { const int R = (int)(special_pal[i].r * RG_night_multiplier); const int G = (int)(special_pal[i].g * RG_night_multiplier); const int B = (int)(special_pal[i].b * B_night_multiplier); specialcolormap_day_night[i] = get_system_color({ (uint8)R, (uint8)G, (uint8)B }); } // special light colors (actually, only non-darkening greys should be used) for(i=0; i> 2; const int G = (day_G * day + night_G * night2) >> 2; const int B = (day_B * day + night_B * night2) >> 2; PIXVAL color = get_system_color({ (uint8)max(R,0), (uint8)max(G,0), (uint8)max(B,0) }); rgbmap_day_night[0x8000 + MAX_PLAYER_COUNT + i] = color; } // convert to RGB xxx recode(); } void display_day_night_shift(int night) { if( night != night_shift ) { night_shift = night; calc_base_pal_from_night_shift(night); mark_screen_dirty(); } } // set first and second company color for player void display_set_player_color_scheme(const int player, const uint8 col1, const uint8 col2 ) { if(player_offsets[player][0]!=col1 || player_offsets[player][1]!=col2) { // set new player colors player_offsets[player][0] = col1; player_offsets[player][1] = col2; if(player==player_day || player==player_night) { // and recalculate map (and save it) calc_base_pal_from_night_shift(0); memcpy(rgbmap_all_day, rgbmap_day_night, RGBMAPSIZE * sizeof(PIXVAL)); if(night_shift!=0) { calc_base_pal_from_night_shift(night_shift); } // calc_base_pal_from_night_shift resets player_night to 0 player_day = player_night; } recode(); mark_screen_dirty(); } } void register_image(image_t *image_in) { struct imd *image; /* valid image? */ if( image_in->len == 0 || image_in->h == 0 ) { dbg->warning("register_image()", "Ignoring image %d because of missing data", anz_images); image_in->imageid = IMG_EMPTY; return; } if( anz_images == alloc_images ) { if( images==NULL ) { alloc_images = 510; } else { alloc_images += 512; } if( anz_images > alloc_images ) { // overflow dbg->fatal( "register_image", "*** Out of images (more than %li!) ***", anz_images ); } images = REALLOC(images, imd, alloc_images); } image_in->imageid = anz_images; image = &images[anz_images]; anz_images++; image->x = image_in->x; image->w = image_in->w; image->y = image_in->y; image->h = image_in->h; image->recode_flags = FLAG_REZOOM; if( image_in->zoomable ) { image->recode_flags |= FLAG_ZOOMABLE; } image->player_flags = 0xFFFF; // recode all player colors // find out if there are really player colors for( PIXVAL *src = image_in->data, y = 0; y < image_in->h; ++y ) { uint16 runlen; // decode line runlen = *src++; do { // clear run .. nothing to do runlen = *src++; if( runlen & TRANSPARENT_RUN ) { image->recode_flags |= FLAG_HAS_TRANSPARENT_COLOR; runlen &= ~TRANSPARENT_RUN; } // no this many color pixel while( runlen-- ) { // get rgb components PIXVAL s = *src++; if( s>=0x8000 && s<0x8010 ) { image->recode_flags |= FLAG_HAS_PLAYER_COLOR; } } runlen = *src++; } while( runlen!=0 ); // end of row: runlen == 0 } for( uint8 i = 0; i < MAX_PLAYER_COUNT; i++ ) { image->data[i] = NULL; } image->zoom_data = NULL; image->len = image_in->len; image->base_x = image_in->x; image->base_w = image_in->w; image->base_y = image_in->y; image->base_h = image_in->h; // since we do not recode them, we can work with the original data image->base_data = image_in->data; // now find out, it contains player colors } // delete all images above a certain number ... // (mostly needed when changing climate zones) void display_free_all_images_above( image_id above ) { while( above < anz_images ) { anz_images--; if( images[anz_images].zoom_data != NULL ) { free( images[anz_images].zoom_data ); } for( uint8 i = 0; i < MAX_PLAYER_COUNT; i++ ) { if( images[anz_images].data[i] != NULL ) { free( images[anz_images].data[i] ); } } } } // query offsets void display_get_image_offset(image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw) { if( image < anz_images ) { *xoff = images[image].x; *yoff = images[image].y; *xw = images[image].w; *yw = images[image].h; } } // query un-zoomed offsets void display_get_base_image_offset(image_id image, scr_coord_val *xoff, scr_coord_val *yoff, scr_coord_val *xw, scr_coord_val *yw) { if( image < anz_images ) { *xoff = images[image].base_x; *yoff = images[image].base_y; *xw = images[image].base_w; *yw = images[image].base_h; } } // ------------------ display all kind of images from here on ------------------------------ // forward declaration, implementation is further below PIXVAL colors_blend_alpha32(PIXVAL background, PIXVAL foreground, int alpha); /** * Copy Pixel from src to dest */ static inline void pixcopy(PIXVAL *dest, const PIXVAL *src, const PIXVAL * const end) { // for gcc this seems to produce the optimal code ... while (src < end) { *dest++ = *src++; } } /** * Copy pixel, replace player color */ static inline void colorpixcopy(PIXVAL* dest, const PIXVAL* src, const PIXVAL* const end) { if (*src < 0x8020) { while (src < end) { *dest++ = rgbmap_current[*src++]; } } else { while (src < end) { // a semi-transparent pixel uint16 aux = *src++ - 0x8020; uint16 alpha = (aux % 31) + 1; *dest = colors_blend_alpha32(*dest, rgbmap_day_night[0x8000 + aux / 31], alpha); dest++; } } } /** * Copy pixel, replace player color */ static inline void colorpixcopydaytime(PIXVAL* dest, const PIXVAL* src, const PIXVAL* const end) { if (*src < 0x8020) { while (src < end) { *dest++ = rgbmap_current[*src++]; } } else { while (src < end) { // a semi-transparent pixel uint16 aux = *src++ - 0x8020; uint16 alpha = (aux % 31) + 1; *dest = colors_blend_alpha32(*dest, rgbmap_all_day[0x8000 + aux / 31], alpha); dest++; } } } /** * templated pixel copy routines * to be used in display_img_pc */ enum pixcopy_routines { plain = 0, /// simply copies the pixels colored = 1, /// replaces player colors daytime = 2 /// use daytime color lookup for transparent pixels }; template void templated_pixcopy(PIXVAL *dest, const PIXVAL *src, const PIXVAL * const end); template<> void templated_pixcopy(PIXVAL *dest, const PIXVAL *src, const PIXVAL * const end) { pixcopy(dest, src, end); } template<> void templated_pixcopy(PIXVAL* dest, const PIXVAL* src, const PIXVAL* const end) { colorpixcopy(dest, src, end); } template<> void templated_pixcopy(PIXVAL* dest, const PIXVAL* src, const PIXVAL* const end) { colorpixcopydaytime(dest, src, end); } /** * draws image with clipping along arbitrary lines */ template static void display_img_pc(scr_coord_val h, const scr_coord_val xp, const scr_coord_val yp, const PIXVAL *sp CLIP_NUM_DEF) { if( h > 0 ) { PIXVAL *tp = textur + yp * disp_width; // initialize clipping init_ranges( yp CLIP_NUM_PAR); do { // line decoder int xpos = xp; // display image int runlen = *sp++; // get left/right boundary, step int xmin, xmax; get_xrange_and_step_y( xmin, xmax CLIP_NUM_PAR ); do { // we start with a clear run (which may be 0 pixels) xpos += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = *sp++; uint16 has_alpha = runlen & TRANSPARENT_RUN; runlen &= ~TRANSPARENT_RUN; // something to display? if (xmin < xmax && xpos + runlen > xmin && xpos < xmax) { const int left = (xpos >= xmin ? 0 : xmin - xpos); const int len = (xmax - xpos >= runlen ? runlen : xmax - xpos); if( !has_alpha ) { templated_pixcopy(tp + xpos + left, sp + left, sp + len); } else { colorpixcopy(tp + xpos + left, sp + left, sp + len); } } sp += runlen; xpos += runlen; } while ((runlen = *sp++)); tp += disp_width; } while (--h); } } /** * Draw image with horizontal clipping */ static void display_img_wc(scr_coord_val h, const scr_coord_val xp, const scr_coord_val yp, const PIXVAL *sp CLIP_NUM_DEF) { if( h > 0 ) { PIXVAL *tp = textur + yp * disp_width; do { // line decoder int xpos = xp; // display image uint16 runlen = *sp++; do { // we start with a clear run xpos += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = *sp++; uint16 has_alpha = runlen & TRANSPARENT_RUN; runlen &= ~TRANSPARENT_RUN; // something to display? if( xpos + runlen > CR.clip_rect.x && xpos < CR.clip_rect.xx ) { const int left = (xpos >= CR.clip_rect.x ? 0 : CR.clip_rect.x - xpos); const int len = (CR.clip_rect.xx - xpos >= runlen ? runlen : CR.clip_rect.xx - xpos); if( !has_alpha ) { pixcopy(tp + xpos + left, sp + left, sp + len); } else { colorpixcopy(tp + xpos + left, sp + left, sp + len); } } sp += runlen; xpos += runlen; } while ((runlen = *sp++)); tp += disp_width; } while (--h); } } /** * Draw each image without clipping */ static void display_img_nc(scr_coord_val h, const scr_coord_val xp, const scr_coord_val yp, const PIXVAL *sp) { if (h > 0) { PIXVAL *tp = textur + xp + yp * disp_width; do { // line decoder uint16 runlen = *sp++; PIXVAL *p = tp; // one line decoder do { // we start with a clear run p += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = *sp++; if( runlen & TRANSPARENT_RUN ) { runlen &= ~TRANSPARENT_RUN; colorpixcopy( p, sp, sp+runlen ); p += runlen; sp += runlen; } else { #ifdef LOW_LEVEL #ifdef SIM_BIG_ENDIAN // low level c++ without any unrolling while( runlen-- ) { *p++ = *sp++; } #else // trying to merge reads and writes if( runlen ) { // align to 4 bytes, should use uintptr_t but not available if( reinterpret_cast(p) & 0x2 ) { *p++ = *sp++; runlen--; } // aligned fast copy loop bool const postalign = runlen & 1; runlen >>= 1; uint32 *ld = (uint32 *)p; while (runlen--) { #if defined _MSC_VER // MSVC can read unaligned *ld++ = *(uint32 const *const)sp; #else // little endian order, assumed by default *ld++ = (uint32(sp[1]) << 16) | uint32(sp[0]); #endif sp += 2; } p = (PIXVAL*)ld; // finish unaligned remainder if( postalign ) { *p++ = *sp++; } } #endif #else // high level c++ const PIXVAL *const splast = sp + runlen; p = std::copy(sp, splast, p); sp = splast; #endif } runlen = *sp++; } while (runlen != 0); tp += disp_width; } while (--h > 0); } } // only used for GUI void display_img_aligned( const image_id n, scr_rect area, int align, const bool dirty) { if( n < anz_images ) { scr_coord_val x,y; // align the image horizontally x = area.x; if( (align & ALIGN_RIGHT) == ALIGN_CENTER_H ) { x -= images[n].x; x += (area.w-images[n].w)/2; } else if( (align & ALIGN_RIGHT) == ALIGN_RIGHT ) { x = area.get_right() - images[n].x - images[n].w; } // align the image vertically y = area.y; if( (align & ALIGN_BOTTOM) == ALIGN_CENTER_V ) { y -= images[n].y; y += (area.h-images[n].h)/2; } else if( (align & ALIGN_BOTTOM) == ALIGN_BOTTOM ) { y = area.get_bottom() - images[n].y - images[n].h; } display_color_img( n, x, y, 0, false, dirty CLIP_NUM_DEFAULT); } } /** * Draw image with vertical clipping (quickly) and horizontal (slowly) */ void display_img_aux(const image_id n, scr_coord_val xp, scr_coord_val yp, const sint8 player_nr_raw, const bool /*daynight*/, const bool dirty CLIP_NUM_DEF) { if( n < anz_images ) { // only use player images if needed const sint8 use_player = (images[n].recode_flags & FLAG_HAS_PLAYER_COLOR) * player_nr_raw; // need to go to nightmode and or re-zoomed? PIXVAL *sp; if( use_player > 0 ) { // player colour images are rezoomed/recoloured in display_color_img sp = images[n].data[use_player]; if( sp == NULL ) { dbg->warning("display_img_aux", "CImg[%i] %u failed!", use_player, n); return; } } else { if( (images[n].recode_flags & FLAG_REZOOM) ) { rezoom_img( n ); recode_img( n, 0 ); } else if( (images[n].player_flags & 1) ) { recode_img( n, 0 ); } sp = images[n].data[0]; if( sp == NULL ) { dbg->warning("display_img_aux", "Img %u failed!", n); return; } } // now, since zooming may have change this image yp += images[n].y; scr_coord_val h = images[n].h; // may change due to vertical clipping // in the next line the vertical clipping will be handled // by that way the drawing routines must only take into account the horizontal clipping // this should be much faster in most cases // must the height be reduced? scr_coord_val reduce_h = yp + h - CR.clip_rect.yy; if( reduce_h > 0 ) { h -= reduce_h; } // still something to draw if( h <= 0 ) { return; } // vertically lines to skip (only bottom is visible scr_coord_val skip_lines = CR.clip_rect.y - (int)yp; if( skip_lines > 0 ) { if( skip_lines >= h ) { // not visible at all return; } h -= skip_lines; yp += skip_lines; // now skip them while (skip_lines--) { do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp ++; } while (*sp); sp++; } // now sp is the new start of an image with height h } // new block for new variables { // needed now ... const scr_coord_val w = images[n].w; xp += images[n].x; // clipping at poly lines? if( CR.number_of_clips > 0 ) { display_img_pc( h, xp, yp, sp CLIP_NUM_PAR ); // since height may be reduced, start marking here if( dirty ) { mark_rect_dirty_clip( xp, yp, xp + w - 1, yp + h - 1 CLIP_NUM_PAR ); } } else { // use horizontal clipping or skip it? if( xp >= CR.clip_rect.x && xp + w <= CR.clip_rect.xx ) { // marking change? if( dirty ) { mark_rect_dirty_nc( xp, yp, xp + w - 1, yp + h - 1 ); } display_img_nc( h, xp, yp, sp ); } else if( xp < CR.clip_rect.xx && xp + w > CR.clip_rect.x ) { display_img_wc( h, xp, yp, sp CLIP_NUM_PAR); // since height may be reduced, start marking here if( dirty ) { mark_rect_dirty_clip( xp, yp, xp + w - 1, yp + h - 1 CLIP_NUM_PAR ); } } } } } } // local helper function for tiles buttons static void display_three_image_row( image_id i1, image_id i2, image_id i3, scr_rect row, FLAGGED_PIXVAL) { if( i1!=IMG_EMPTY ) { scr_coord_val w = images[i1].w; display_color_img( i1, row.x, row.y, 0, false, true CLIP_NUM_DEFAULT); row.x += w; row.w -= w; } // right if( i3!=IMG_EMPTY ) { scr_coord_val w = images[i3].w; display_color_img( i3, row.get_right()-w, row.y, 0, false, true CLIP_NUM_DEFAULT); row.w -= w; } // middle if( i2!=IMG_EMPTY ) { scr_coord_val w = images[i2].w; // tile it wide while( w <= row.w ) { display_color_img( i2, row.x, row.y, 0, false, true CLIP_NUM_DEFAULT); row.x += w; row.w -= w; } // for the rest we have to clip the rectangle if( row.w > 0 ) { clip_dimension const cl = display_get_clip_wh(); display_set_clip_wh( cl.x, cl.y, max(0,min(row.get_right(),cl.xx)-cl.x), cl.h ); display_color_img( i2, row.x, row.y, 0, false, true CLIP_NUM_DEFAULT); display_set_clip_wh(cl.x, cl.y, cl.w, cl.h ); } } } static scr_coord_val get_img_width(image_id img) { return img != IMG_EMPTY ? images[ img ].w : 0; } static scr_coord_val get_img_height(image_id img) { return img != IMG_EMPTY ? images[ img ].h : 0; } typedef void (*DISP_THREE_ROW_FUNC)(image_id, image_id, image_id, scr_rect, FLAGGED_PIXVAL); /** * Base method to display a 3x3 array of images to fit the scr_rect. * Special cases: * - if images[*][1] are empty, display images[*][0] vertically aligned * - if images[1][*] are empty, display images[0][*] horizontally aligned */ static void display_img_stretch_intern( const stretch_map_t &imag, scr_rect area, DISP_THREE_ROW_FUNC display_three_image_rowf, FLAGGED_PIXVAL color) { scr_coord_val h_top = max(max( get_img_height(imag[0][0]), get_img_height(imag[1][0])), get_img_height(imag[2][0])); scr_coord_val h_middle = max(max( get_img_height(imag[0][1]), get_img_height(imag[1][1])), get_img_height(imag[2][1])); scr_coord_val h_bottom = max(max( get_img_height(imag[0][2]), get_img_height(imag[1][2])), get_img_height(imag[2][2])); // center vertically if images[*][1] are empty, display images[*][0] if( imag[0][1] == IMG_EMPTY && imag[1][1] == IMG_EMPTY && imag[2][1] == IMG_EMPTY ) { scr_coord_val h = max(h_top, get_img_height(imag[1][1])); // center vertically area.y += (area.h-h)/2; } // center horizontally if images[1][*] are empty, display images[0][*] if( imag[1][0] == IMG_EMPTY && imag[1][1] == IMG_EMPTY && imag[1][2] == IMG_EMPTY ) { scr_coord_val w_left = max(max( get_img_width(imag[0][0]), get_img_width(imag[0][1])), get_img_width(imag[0][2])); // center vertically area.x += (area.w-w_left)/2; } // top row display_three_image_rowf( imag[0][0], imag[1][0], imag[2][0], area, color); // bottom row if( h_bottom > 0 ) { scr_rect row( area.x, area.y+area.h-h_bottom, area.w, h_bottom ); display_three_image_rowf( imag[0][2], imag[1][2], imag[2][2], row, color); } // now stretch the middle if( h_middle > 0 ) { scr_rect row( area.x, area.y+h_top, area.w, area.h-h_top-h_bottom); // tile it wide while( h_middle <= row.h ) { display_three_image_rowf( imag[0][1], imag[1][1], imag[2][1], row, color); row.y += h_middle; row.h -= h_middle; } // for the rest we have to clip the rectangle if( row.h > 0 ) { clip_dimension const cl = display_get_clip_wh(); display_set_clip_wh( cl.x, cl.y, cl.w, max(0,min(row.get_bottom(),cl.yy)-cl.y) ); display_three_image_rowf( imag[0][1], imag[1][1], imag[2][1], row, color); display_set_clip_wh(cl.x, cl.y, cl.w, cl.h ); } } } void display_img_stretch( const stretch_map_t &imag, scr_rect area) { display_img_stretch_intern(imag, area, display_three_image_row, 0); } static void display_three_blend_row( image_id i1, image_id i2, image_id i3, scr_rect row, FLAGGED_PIXVAL color ) { if( i1!=IMG_EMPTY ) { scr_coord_val w = images[i1].w; display_rezoomed_img_blend( i1, row.x, row.y, 0, color, false, true CLIPNUM_IGNORE ); row.x += w; row.w -= w; } // right if( i3!=IMG_EMPTY ) { scr_coord_val w = images[i3].w; display_rezoomed_img_blend( i3, row.get_right()-w, row.y, 0, color, false, true CLIPNUM_IGNORE ); row.w -= w; } // middle if( i2!=IMG_EMPTY ) { scr_coord_val w = images[i2].w; // tile it wide while( w <= row.w ) { display_rezoomed_img_blend( i2, row.x, row.y, 0, color, false, true CLIPNUM_IGNORE ); row.x += w; row.w -= w; } // for the rest we have to clip the rectangle if( row.w > 0 ) { clip_dimension const cl = display_get_clip_wh(); display_set_clip_wh( cl.x, cl.y, max(0,min(row.get_right(),cl.xx)-cl.x), cl.h ); display_rezoomed_img_blend( i2, row.x, row.y, 0, color, false, true CLIPNUM_IGNORE ); display_set_clip_wh(cl.x, cl.y, cl.w, cl.h ); } } } // this displays a 3x3 array of images to fit the scr_rect like above, but blend the color void display_img_stretch_blend( const stretch_map_t &imag, scr_rect area, FLAGGED_PIXVAL color ) { display_img_stretch_intern(imag, area, display_three_blend_row, color); } /** * Draw Image, replace player color, * assumes height is ok and valid data are calculated. * color replacement needs the original data => sp points to non-cached data */ static void display_color_img_wc(const PIXVAL* sp, scr_coord_val x, scr_coord_val y, scr_coord_val h CLIP_NUM_DEF) { PIXVAL* tp = textur + y * disp_width; do { // line decoder int xpos = x; // Display image uint16 runlen = *sp++; do { // we start with a clear run xpos += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = (*sp++) & ~TRANSPARENT_RUN; // we recode anyway, so no need to do it explicitely // something to display? if (xpos + runlen > CR.clip_rect.x && xpos < CR.clip_rect.xx) { const int left = (xpos >= CR.clip_rect.x ? 0 : CR.clip_rect.x - xpos); const int len = (CR.clip_rect.xx - xpos > runlen ? runlen : CR.clip_rect.xx - xpos); colorpixcopy(tp + xpos + left, sp + left, sp + len); } sp += runlen; xpos += runlen; } while ((runlen = *sp++)); tp += disp_width; } while (--h); } /** * Draw Image, replace player color, as above, but uses daytime colors for transparent pixels */ static void display_color_img_wc_daytime(const PIXVAL* sp, scr_coord_val x, scr_coord_val y, scr_coord_val h CLIP_NUM_DEF) { PIXVAL* tp = textur + y * disp_width; do { // line decoder int xpos = x; // Display image uint16 runlen = *sp++; do { // we start with a clear run xpos += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = (*sp++) & ~TRANSPARENT_RUN; // we recode anyway, so no need to do it explicitely // something to display? if (xpos + runlen > CR.clip_rect.x && xpos < CR.clip_rect.xx) { const int left = (xpos >= CR.clip_rect.x ? 0 : CR.clip_rect.x - xpos); const int len = (CR.clip_rect.xx - xpos > runlen ? runlen : CR.clip_rect.xx - xpos); colorpixcopydaytime(tp + xpos + left, sp + left, sp + len); } sp += runlen; xpos += runlen; } while ((runlen = *sp++)); tp += disp_width; } while (--h); } /** * Draw Image, replaced player color */ void display_color_img(const image_id n, scr_coord_val xp, scr_coord_val yp, sint8 player_nr_raw, const bool daynight, const bool dirty CLIP_NUM_DEF) { if( n < anz_images ) { // do we have to use a player nr? const sint8 player_nr = (images[n].recode_flags & FLAG_HAS_PLAYER_COLOR) * player_nr_raw; // first: size check if( (images[n].recode_flags & FLAG_REZOOM) ) { rezoom_img( n ); } if( daynight || night_shift == 0 ) { // ok, now we could use the same faster code as for the normal images if( (images[n].player_flags & (1<= CR.clip_rect.xx || y >= CR.clip_rect.yy || x + w <= CR.clip_rect.x || y + h <= CR.clip_rect.y ) { // not visible => we are done // happens quite often ... return; } if( dirty ) { mark_rect_dirty_wc( x, y, x + w - 1, y + h - 1 ); } activate_player_color( player_nr, daynight ); // color replacement needs the original data => sp points to non-cached data const PIXVAL *sp = images[n].zoom_data != NULL ? images[n].zoom_data : images[n].base_data; // clip top/bottom scr_coord_val yoff = clip_wh( &y, &h, CR.clip_rect.y, CR.clip_rect.yy ); if( h > 0 ) { // clipping may have reduced it // clip top while( yoff ) { yoff--; do { // clear run + colored run + next clear run ++sp; sp += (*sp) & (~TRANSPARENT_RUN); sp++; } while (*sp); sp++; } // clipping at poly lines? if( CR.number_of_clips > 0 ) { daynight ? display_img_pc(h, x, y, sp CLIP_NUM_PAR) : display_img_pc(h, x, y, sp CLIP_NUM_PAR); } else { daynight ? display_color_img_wc(sp, x, y, h CLIP_NUM_PAR) : display_color_img_wc_daytime(sp, x, y, h CLIP_NUM_PAR); } } } } // number ok } /** * draw unscaled images, replaces base color */ void display_base_img(const image_id n, scr_coord_val xp, scr_coord_val yp, const sint8 player_nr, const bool daynight, const bool dirty CLIP_NUM_DEF) { if( base_tile_raster_width==tile_raster_width ) { // same size => use standard routine display_color_img( n, xp, yp, player_nr, daynight, dirty CLIP_NUM_PAR); } else if( n < anz_images ) { // now test if visible and clipping needed const scr_coord_val x = images[n].base_x + xp; scr_coord_val y = images[n].base_y + yp; const scr_coord_val w = images[n].base_w; scr_coord_val h = images[n].base_h; if( h <= 0 || x >= CR.clip_rect.xx || y >= CR.clip_rect.yy || x + w <= CR.clip_rect.x || y + h <= CR.clip_rect.y ) { // not visible => we are done // happens quite often ... return; } if (dirty) { mark_rect_dirty_wc(x, y, x + w - 1, y + h - 1); } // colors for 2nd company color if(player_nr>=0) { activate_player_color( player_nr, daynight ); } else { // no player activate_player_color( 0, daynight ); } // color replacement needs the original data => sp points to non-cached data const PIXVAL *sp = images[n].base_data; // clip top/bottom scr_coord_val yoff = clip_wh( &y, &h, CR.clip_rect.y, CR.clip_rect.yy ); if( h > 0 ) { // clipping may have reduced it // clip top while( yoff ) { yoff--; do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp++; } while (*sp); sp++; } // clipping at poly lines? if( CR.number_of_clips > 0 ) { daynight ? display_img_pc(h, x, y, sp CLIP_NUM_PAR) : display_img_pc(h, x, y, sp CLIP_NUM_PAR); } else { daynight ? display_color_img_wc(sp, x, y, h CLIP_NUM_PAR) : display_color_img_wc_daytime(sp, x, y, h CLIP_NUM_PAR); } } } // number ok } inline PIXVAL colors_blend25(PIXVAL background, PIXVAL foreground) { return rgb_shr1(background) + rgb_shr2(background) + rgb_shr2(foreground); } inline PIXVAL colors_blend50(PIXVAL background, PIXVAL foreground) { return rgb_shr1(background) + rgb_shr1(foreground); } inline PIXVAL colors_blend75(PIXVAL background, PIXVAL foreground) { return rgb_shr2(background) + rgb_shr1(foreground) + rgb_shr2(foreground); } inline PIXVAL colors_blend_alpha32(PIXVAL background, PIXVAL foreground, int alpha) { uint32 b = ((background << 16) | background) & MASK_32; uint32 f = ((foreground << 16) | foreground) & MASK_32; uint32 r = ((f * alpha + (32-alpha) * b) >> 5) & MASK_32; return r | (r >> 16); } // Blends two colors. Possible values for alpha: 0..32 PIXVAL display_blend_colors_alpha32(PIXVAL background, PIXVAL foreground, int alpha) { // alpha takes values 0 .. 32 switch(alpha) { case 0: // nothing to do ... return background; case 8: return colors_blend25(background, foreground); case 16: return colors_blend50(background, foreground); case 24: return colors_blend75(background, foreground); case 32: return foreground; default: return colors_blend_alpha32(background, foreground, alpha); } } // Blends two colors PIXVAL display_blend_colors(PIXVAL background, PIXVAL foreground, int percent_blend) { return display_blend_colors_alpha32(background, foreground, (percent_blend*32)/100); } /* from here code for transparent images */ typedef void (*blend_proc)(PIXVAL *dest, const PIXVAL *src, const PIXVAL colour, const PIXVAL len); // templated structures to specialize for the different blend modes: 25/50/75 percent struct blend25_t { static inline PIXVAL blend(PIXVAL background, PIXVAL foreground) { return 3 * rgb_shr2(background) + rgb_shr2(foreground); } }; struct blend50_t { static inline PIXVAL blend(PIXVAL background, PIXVAL foreground) { return rgb_shr1(background) + rgb_shr1(foreground); } }; struct blend75_t { static inline PIXVAL blend(PIXVAL background, PIXVAL foreground) { return rgb_shr2(background) + 3 * rgb_shr2(foreground); } }; template void pix_blend_tpl(PIXVAL *dest, const PIXVAL *src, const PIXVAL , const PIXVAL len) { const PIXVAL *const end = dest + len; while (dest < end) { *dest = F::blend(*dest, *src); dest++; src++; } } // the following 6 functions are for display_base_img_blend() template void pix_blend_recode_tpl(PIXVAL *dest, const PIXVAL *src, const PIXVAL , const PIXVAL len) { const PIXVAL *const end = dest + len; while (dest < end) { *dest = F::blend(*dest, rgbmap_current[*src]); dest++; src++; } } template void pix_outline_tpl(PIXVAL *dest, const PIXVAL *, const PIXVAL colour, const PIXVAL len) { const PIXVAL *const end = dest + len; while (dest < end) { *dest = F::blend(*dest, colour); dest++; } } // save them for easier access static blend_proc blend[3] = { pix_blend_tpl, pix_blend_tpl, pix_blend_tpl }; static blend_proc blend_recode[3] = { pix_blend_recode_tpl, pix_blend_recode_tpl, pix_blend_recode_tpl}; static blend_proc outline[3] = { pix_outline_tpl, pix_outline_tpl, pix_outline_tpl}; /** * Blends a rectangular region with a color */ void display_blend_wh_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL colval, int percent_blend ) { if( clip_lr( &xp, &w, CR0.clip_rect.x, CR0.clip_rect.xx ) && clip_lr( &yp, &h, CR0.clip_rect.y, CR0.clip_rect.yy ) ) { const PIXVAL alpha = (percent_blend*64)/100; switch( alpha ) { case 0: // nothing to do ... break; case 16: case 32: case 48: { // fast blending with 1/4 | 1/2 | 3/4 percentage blend_proc blend = outline[ (alpha>>4) - 1 ]; for( scr_coord_val y=0; y0; yp++, h-- ) { PIXVAL *dest = textur + yp*disp_width + xp; const PIXVAL *const end = dest + w; while (dest < end) { const PIXVAL r_dest = red(*dest); const PIXVAL g_dest = green(*dest); const PIXVAL b_dest = blue(*dest); const PIXVAL r = r_dest + ( ( (r_src - r_dest) * alpha ) >> 6 ); const PIXVAL g = g_dest + ( ( (g_src - g_dest) * alpha ) >> 6 ); const PIXVAL b = b_dest + ( ( (b_src - b_dest) * alpha ) >> 6 ); *dest++ = rgb(r, g, b); } } } break; } } } static void display_img_blend_wc(scr_coord_val h, const scr_coord_val xp, const scr_coord_val yp, const PIXVAL *sp, int colour, blend_proc p CLIP_NUM_DEF ) { if( h > 0 ) { PIXVAL *tp = textur + yp * disp_width; do { // line decoder int xpos = xp; // display image uint16 runlen = *sp++; do { // we start with a clear run xpos += (runlen & ~TRANSPARENT_RUN); // now get colored pixels runlen = (*sp++) & (~TRANSPARENT_RUN); // something to display? if( xpos + runlen > CR.clip_rect.x && xpos < CR.clip_rect.xx ) { const int left = (xpos >= CR.clip_rect.x ? 0 : CR.clip_rect.x - xpos); const int len = (CR.clip_rect.xx - xpos >= runlen ? runlen : CR.clip_rect.xx - xpos); p(tp + xpos + left, sp + left, colour, len - left); } sp += runlen; xpos += runlen; } while ((runlen = *sp++)); tp += disp_width; } while (--h); } } /* from here code for transparent images */ static PIXVAL get_alpha_mask(const unsigned alpha_flags) { PIXVAL mask = alpha_flags & ALPHA_RED ? 0x7c00 : 0; if (alpha_flags & ALPHA_GREEN) { mask |= 0x03e0; } if (alpha_flags & ALPHA_BLUE) { mask |= 0x001f; } return mask; } typedef void (*alpha_proc)(PIXVAL *dest, const PIXVAL *src, const PIXVAL *alphamap, const PIXVAL alpha_mask, const PIXVAL colour, const PIXVAL len); static void alpha(PIXVAL *dest, const PIXVAL *src, const PIXVAL *alphamap, const PIXVAL alpha_mask, const PIXVAL , const PIXVAL len) { const PIXVAL *const end = dest + len; while( dest < end ) { // read mask components - always 15bpp uint16 masked = *alphamap & alpha_mask; uint16 alpha_value = (masked & 0x1f) + ((masked >> 5) & 0x1f) + ((masked >> 10) & 0x1f); if( alpha_value > 30 ) { // opaque, just copy source *dest = *src; } else if( alpha_value > 0 ) { alpha_value = alpha_value > 15 ? alpha_value + 1 : alpha_value; *dest = colors_blend_alpha32(*dest, *src, alpha_value); } dest++; src++; alphamap++; } } static void alpha_recode(PIXVAL *dest, const PIXVAL *src, const PIXVAL *alphamap, const PIXVAL alpha_mask, const PIXVAL , const PIXVAL len) { const PIXVAL *const end = dest + len; while( dest < end ) { // read mask components - always 15bpp uint16 masked = *alphamap & alpha_mask; uint16 alpha_value = (masked & 0x1f) + ((masked >> 5) & 0x1f) + ((masked >> 10) & 0x1f); if( alpha_value > 30 ) { // opaque, just copy source *dest = rgbmap_current[*src]; } else if( alpha_value > 0 ) { alpha_value = alpha_value > 15 ? alpha_value + 1 : alpha_value; *dest = colors_blend_alpha32(*dest, rgbmap_current[*src], alpha_value); } dest++; src++; alphamap++; } } static void display_img_alpha_wc(scr_coord_val h, const scr_coord_val xp, const scr_coord_val yp, const PIXVAL *sp, const PIXVAL *alphamap, const PIXVAL alpha_mask, int colour, alpha_proc p CLIP_NUM_DEF ) { if( h > 0 ) { PIXVAL *tp = textur + yp * disp_width; do { // line decoder int xpos = xp; // display image uint16 runlen = *sp++; alphamap++; do { // we start with a clear run xpos += runlen; // now get colored pixels runlen = ((*sp++) & ~TRANSPARENT_RUN); alphamap++; // something to display? if( xpos + runlen > CR.clip_rect.x && xpos < CR.clip_rect.xx ) { const int left = (xpos >= CR.clip_rect.x ? 0 : CR.clip_rect.x - xpos); const int len = (CR.clip_rect.xx - xpos >= runlen ? runlen : CR.clip_rect.xx - xpos); p( tp + xpos + left, sp + left, alphamap + left, alpha_mask, colour, len - left ); } sp += runlen; alphamap += runlen; xpos += runlen; alphamap++; } while( (runlen = *sp++) ); tp += disp_width; } while( --h ); } } /** * draws the transparent outline of an image */ void display_rezoomed_img_blend(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char /*player_nr*/, const FLAGGED_PIXVAL color_index, const bool /*daynight*/, const bool dirty CLIP_NUM_DEF) { if( n < anz_images ) { // need to go to nightmode and or rezoomed? if( (images[n].recode_flags & FLAG_REZOOM) ) { rezoom_img( n ); recode_img( n, 0 ); } else if( (images[n].player_flags & 1) ) { recode_img( n, 0 ); } PIXVAL *sp = images[n].data[0]; // now, since zooming may have change this image xp += images[n].x; yp += images[n].y; scr_coord_val h = images[n].h; // may change due to vertical clipping // in the next line the vertical clipping will be handled // by that way the drawing routines must only take into account the horizontal clipping // this should be much faster in most cases // must the height be reduced? scr_coord_val reduce_h = yp + h - CR.clip_rect.yy; if( reduce_h > 0 ) { h -= reduce_h; } // still something to draw if( h <= 0 ) return; // vertically lines to skip (only bottom is visible) scr_coord_val skip_lines = CR.clip_rect.y - (int)yp; if( skip_lines > 0 ) { if( skip_lines >= h ) { // not visible at all return; } h -= skip_lines; yp += skip_lines; // now skip them while (skip_lines--) { do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp++; } while (*sp); sp++; } // now sp is the new start of an image with height h } // new block for new variables { // needed now ... const scr_coord_val w = images[n].w; // get the real color const PIXVAL color = color_index & 0xFFFF; // we use function pointer for the blend runs for the moment ... blend_proc pix_blend = (color_index&OUTLINE_FLAG) ? outline[ (color_index&TRANSPARENT_FLAGS)/TRANSPARENT25_FLAG - 1 ] : blend[ (color_index&TRANSPARENT_FLAGS)/TRANSPARENT25_FLAG - 1 ]; // marking change? if( dirty ) { mark_rect_dirty_wc( xp, yp, xp + w - 1, yp + h - 1 ); } display_img_blend_wc( h, xp, yp, sp, color, pix_blend CLIP_NUM_PAR ); } } } void display_rezoomed_img_alpha(const image_id n, const image_id alpha_n, const unsigned alpha_flags, scr_coord_val xp, scr_coord_val yp, const sint8 /*player_nr*/, const FLAGGED_PIXVAL color_index, const bool /*daynight*/, const bool dirty CLIP_NUM_DEF) { if( n < anz_images && alpha_n < anz_images ) { // need to go to nightmode and or rezoomed? if( (images[n].recode_flags & FLAG_REZOOM) ) { rezoom_img( n ); recode_img( n, 0 ); } else if( (images[n].player_flags & 1) ) { recode_img( n, 0 ); } if( (images[alpha_n].recode_flags & FLAG_REZOOM) ) { rezoom_img( alpha_n ); } PIXVAL *sp = images[n].data[0]; // alphamap image uses base data as we don't want to recode PIXVAL *alphamap = images[alpha_n].zoom_data != NULL ? images[alpha_n].zoom_data : images[alpha_n].base_data; // now, since zooming may have change this image xp += images[n].x; yp += images[n].y; scr_coord_val h = images[n].h; // may change due to vertical clipping // in the next line the vertical clipping will be handled // by that way the drawing routines must only take into account the horizontal clipping // this should be much faster in most cases // must the height be reduced? scr_coord_val reduce_h = yp + h - CR.clip_rect.yy; if( reduce_h > 0 ) { h -= reduce_h; } // still something to draw if( h <= 0 ) { return; } // vertically lines to skip (only bottom is visible scr_coord_val skip_lines = CR.clip_rect.y - (int)yp; if( skip_lines > 0 ) { if( skip_lines >= h ) { // not visible at all return; } h -= skip_lines; yp += skip_lines; // now skip them while( skip_lines-- ) { do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp++; alphamap++; alphamap += (*alphamap) & (~TRANSPARENT_RUN); alphamap++; } while( *sp ); sp++; alphamap++; } // now sp is the new start of an image with height h (same for alphamap) } // new block for new variables { // needed now ... const scr_coord_val w = images[n].w; // get the real color const PIXVAL color = color_index & 0xFFFF; // marking change? if( dirty ) { mark_rect_dirty_wc( xp, yp, xp + w - 1, yp + h - 1 ); } display_img_alpha_wc( h, xp, yp, sp, alphamap, get_alpha_mask(alpha_flags), color, alpha CLIP_NUM_PAR ); } } } // For blending or outlining unzoomed image. Adapted from display_base_img() and display_unzoomed_img_blend() void display_base_img_blend(const image_id n, scr_coord_val xp, scr_coord_val yp, const signed char player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF) { if( base_tile_raster_width == tile_raster_width ) { // same size => use standard routine display_rezoomed_img_blend( n, xp, yp, player_nr, color_index, daynight, dirty CLIP_NUM_PAR ); } else if( n < anz_images ) { // now test if visible and clipping needed scr_coord_val x = images[n].base_x + xp; scr_coord_val y = images[n].base_y + yp; scr_coord_val w = images[n].base_w; scr_coord_val h = images[n].base_h; if( h == 0 || x >= CR.clip_rect.xx || y >= CR.clip_rect.yy || x + w <= CR.clip_rect.x || y + h <= CR.clip_rect.y ) { // not visible => we are done // happens quite often ... return; } PIXVAL *sp = images[n].base_data; // must the height be reduced? scr_coord_val reduce_h = y + h - CR.clip_rect.yy; if( reduce_h > 0 ) { h -= reduce_h; } // vertical lines to skip (only bottom is visible) scr_coord_val skip_lines = CR.clip_rect.y - (int)y; if( skip_lines > 0 ) { h -= skip_lines; y += skip_lines; // now skip them while (skip_lines--) { do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp++; } while (*sp); sp++; } // now sp is the new start of an image with height h } // new block for new variables { const PIXVAL color = color_index & 0xFFFF; blend_proc pix_blend = (color_index&OUTLINE_FLAG) ? outline[ (color_index&TRANSPARENT_FLAGS)/TRANSPARENT25_FLAG - 1 ] : blend_recode[ (color_index&TRANSPARENT_FLAGS)/TRANSPARENT25_FLAG - 1 ]; // recode is needed only for blending if( !(color_index&OUTLINE_FLAG) ) { // colors for 2nd company color if(player_nr>=0) { activate_player_color( player_nr, daynight ); } else { // no player activate_player_color( 0, daynight ); } } if( dirty ) { mark_rect_dirty_wc( x, y, x + w - 1, y + h - 1 ); } display_img_blend_wc( h, x, y, sp, color, pix_blend CLIP_NUM_PAR ); } } // number ok } void display_base_img_alpha(const image_id n, const image_id alpha_n, const unsigned alpha_flags, scr_coord_val xp, scr_coord_val yp, const sint8 player_nr, const FLAGGED_PIXVAL color_index, const bool daynight, const bool dirty CLIP_NUM_DEF) { if( base_tile_raster_width == tile_raster_width ) { // same size => use standard routine display_rezoomed_img_alpha( n, alpha_n, alpha_flags, xp, yp, player_nr, color_index, daynight, dirty CLIP_NUM_PAR ); } else if( n < anz_images ) { // now test if visible and clipping needed scr_coord_val x = images[n].base_x + xp; scr_coord_val y = images[n].base_y + yp; scr_coord_val w = images[n].base_w; scr_coord_val h = images[n].base_h; if( h == 0 || x >= CR.clip_rect.xx || y >= CR.clip_rect.yy || x + w <= CR.clip_rect.x || y + h <= CR.clip_rect.y ) { // not visible => we are done // happens quite often ... return; } PIXVAL *sp = images[n].base_data; PIXVAL *alphamap = images[alpha_n].base_data; // must the height be reduced? scr_coord_val reduce_h = y + h - CR.clip_rect.yy; if( reduce_h > 0 ) { h -= reduce_h; } // vertical lines to skip (only bottom is visible) scr_coord_val skip_lines = CR.clip_rect.y - (int)y; if( skip_lines > 0 ) { h -= skip_lines; y += skip_lines; // now skip them while( skip_lines-- ) { do { // clear run + colored run + next clear run sp++; sp += (*sp) & (~TRANSPARENT_RUN); sp++; } while( *sp ); do { // clear run + colored run + next clear run alphamap++; alphamap += (*alphamap) & (~TRANSPARENT_RUN); alphamap++; } while( *alphamap ); sp++; alphamap++; } // now sp is the new start of an image with height h } // new block for new variables { const PIXVAL color = color_index & 0xFFFF; // recode is needed only for blending if( !(color_index & OUTLINE_FLAG) ) { // colors for 2nd company color if( player_nr >= 0 ) { activate_player_color( player_nr, daynight ); } else { // no player activate_player_color( 0, daynight ); } } if( dirty ) { mark_rect_dirty_wc( x, y, x + w - 1, y + h - 1 ); } display_img_alpha_wc( h, x, y, sp, alphamap, get_alpha_mask(alpha_flags), color, alpha_recode CLIP_NUM_PAR ); } } // number ok } // ----------------- basic painting procedures ---------------- // scrolls horizontally, will ignore clipping etc. void display_scroll_band(scr_coord_val start_y, scr_coord_val x_offset, scr_coord_val h) { start_y = max(start_y, 0); x_offset = min(x_offset, disp_width); h = min(h, disp_height); const PIXVAL *const src = textur + start_y * disp_width + x_offset; PIXVAL *const dst = textur + start_y * disp_width; const size_t amount = sizeof(PIXVAL) * (h * disp_width - x_offset); memmove(dst, src, amount); } /** * Draw one Pixel */ #ifdef DEBUG_FLUSH_BUFFER static void display_pixel(scr_coord_val x, scr_coord_val y, PIXVAL color, bool mark_dirty=true) #else static void display_pixel(scr_coord_val x, scr_coord_val y, PIXVAL color) #endif { if( x >= CR0.clip_rect.x && x < CR0.clip_rect.xx && y >= CR0.clip_rect.y && y < CR0.clip_rect.yy ) { PIXVAL* const p = textur + x + y * disp_width; *p = color; #ifdef DEBUG_FLUSH_BUFFER if( mark_dirty ) { #endif mark_tile_dirty(x >> DIRTY_TILE_SHIFT, y >> DIRTY_TILE_SHIFT); #ifdef DEBUG_FLUSH_BUFFER } #endif } } /** * Draw filled rectangle */ static void display_fb_internal(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL colval, bool dirty, scr_coord_val cL, scr_coord_val cR, scr_coord_val cT, scr_coord_val cB) { if (clip_lr(&xp, &w, cL, cR) && clip_lr(&yp, &h, cT, cB)) { PIXVAL *p = textur + xp + yp * disp_width; const int dx = disp_width - w; if (dirty) { mark_rect_dirty_nc(xp, yp, xp + w - 1, yp + h - 1); } #if defined USE_ASSEMBLER && defined __GNUC__ && defined __i686__ // GCC might not use "rep stos" so force its use const uint32 longcolval = (colval << 16) | colval; do { unsigned int count = w; asm volatile ( // uneven words to copy? "shrl %1\n\t" "jnc 0f\n\t" // set first word "stosw\n\t" "0:\n\t" // now we set long words ... "rep\n\t" "stosl" : "+D" (p), "+c" (count) : "a" (longcolval) : "cc", "memory" ); p += dx; } while (--h); #elif defined LOW_LEVEL // low level c++ const uint32 colvald = (colval << 16) | colval; do { scr_coord_val count = w; // align to 4 bytes, should use uintptr_t but not available if( reinterpret_cast(p) & 0x2 ) { *p++ = (PIXVAL)colvald; count--; } // aligned fast fill loop bool const postalign = count & 1; count >>= 1; uint32 *lp = (uint32 *)p; while(count--) { *lp++ = colvald; } p = (PIXVAL *)lp; // finish unaligned remainder if( postalign ) { *p++ = (PIXVAL)colvald; } p += dx; } while (--h); #else // high level c++ do { PIXVAL *const fillend = p + w; std::fill(p, fillend, colval); p = fillend + dx; } while (--h); #endif } } void display_fillbox_wh_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty) { display_fb_internal(xp, yp, w, h, color, dirty, 0, disp_width, 0, disp_height); } void display_fillbox_wh_clip_rgb(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty CLIP_NUM_DEF) { display_fb_internal( xp, yp, w, h, color, dirty, CR.clip_rect.x, CR.clip_rect.xx, CR.clip_rect.y, CR.clip_rect.yy ); } void display_filled_roundbox_clip(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, PIXVAL color, bool dirty) { display_fillbox_wh_clip_rgb(xp+2, yp, w-4, h, color, dirty); display_fillbox_wh_clip_rgb(xp, yp+2, 1, h-4, color, dirty); display_fillbox_wh_clip_rgb(xp+1, yp+1, 1, h-2, color, dirty); display_fillbox_wh_clip_rgb(xp+w-1, yp+2, 1, h-4, color, dirty); display_fillbox_wh_clip_rgb(xp+w-2, yp+1, 1, h-2, color, dirty); } /** * Draw vertical line */ static void display_vl_internal(const scr_coord_val xp, scr_coord_val yp, scr_coord_val h, const PIXVAL colval, int dirty, scr_coord_val cL, scr_coord_val cR, scr_coord_val cT, scr_coord_val cB) { if (xp >= cL && xp < cR && clip_lr(&yp, &h, cT, cB)) { PIXVAL *p = textur + xp + yp * disp_width; if (dirty) mark_rect_dirty_nc(xp, yp, xp, yp + h - 1); do { *p = colval; p += disp_width; } while (--h != 0); } } void display_vline_wh_rgb(const scr_coord_val xp, scr_coord_val yp, scr_coord_val h, const PIXVAL color, bool dirty) { display_vl_internal(xp, yp, h, color, dirty, 0, disp_width, 0, disp_height); } void display_vline_wh_clip_rgb(const scr_coord_val xp, scr_coord_val yp, scr_coord_val h, const PIXVAL color, bool dirty CLIP_NUM_DEF) { display_vl_internal( xp, yp, h, color, dirty, CR.clip_rect.x, CR.clip_rect.xx, CR.clip_rect.y, CR.clip_rect.yy ); } /** * Draw raw Pixel data */ void display_array_wh(scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, const PIXVAL *arr) { const int arr_w = w; const scr_coord_val xoff = clip_wh( &xp, &w, CR0.clip_rect.x, CR0.clip_rect.xx ); const scr_coord_val yoff = clip_wh( &yp, &h, CR0.clip_rect.y, CR0.clip_rect.yy ); if( w > 0 && h > 0 ) { PIXVAL *p = textur + xp + yp * disp_width; const PIXVAL *arr_src = arr; mark_rect_dirty_nc(xp, yp, xp + w - 1, yp + h - 1); if( xp == CR0.clip_rect.x ) arr_src += xoff; if( yp == CR0.clip_rect.y ) arr_src += yoff * arr_w; do { unsigned int ww = w; do { *p++ = *arr_src++; } while (--ww > 0); arr_src += arr_w - w; p += disp_width - w; } while (--h != 0); } } // --------------------------------- text rendering stuff ------------------------------ bool display_load_font(const char *fname, bool reload) { font_t loaded_fnt; if( fname == NULL ) { dbg->error( "display_load_font", "NULL filename" ); return false; } // skip reloading if already in memory, if bdf font if( !reload && default_font.is_loaded() && strcmp( default_font.get_fname(), fname ) == 0 ) { return true; } if( loaded_fnt.load_from_file(fname) ) { default_font = loaded_fnt; default_font_ascent = default_font.get_ascent(); default_font_linespace = default_font.get_linespace(); // find default number width const char* digits = "0123456789"; default_font_numberwidth = 0; while (*digits) { int pixel = default_font.get_glyph_advance(*digits++); if (pixel > default_font_numberwidth) { default_font_numberwidth = pixel; } } env_t::fontname = fname; return default_font.is_loaded(); } return false; } scr_coord_val display_get_char_width(utf32 c) { return default_font.get_glyph_advance(c); } scr_coord_val display_get_number_width() { return default_font_numberwidth; } /** * For the next logical character in the text, returns the character code * as well as retrieves the char byte count and the screen pixel width * CAUTION : The text pointer advances to point to the next logical character */ utf32 get_next_char_with_metrics(const char* &text, unsigned char &byte_length, unsigned char &pixel_width) { size_t len = 0; utf32 const char_code = utf8_decoder_t::decode((utf8 const *)text, len); if( char_code==UNICODE_NUL || char_code == '\n') { // case : end of text reached -> do not advance text pointer // also stop at linebreaks byte_length = 0; pixel_width = 0; return 0; } else { text += len; byte_length = (uint8)len; pixel_width = default_font.get_glyph_advance(char_code); } return char_code; } /* returns true, if this is a valid character */ bool has_character(utf16 char_code) { return default_font.is_valid_glyph(char_code); } /* * returns the index of the last character that would fit within the width * If an ellipsis len is given, it will only return the last character up to this len if the full length cannot be fitted * @returns index of next character. if text[index]==0 the whole string fits */ size_t display_fit_proportional( const char *text, scr_coord_val max_width) { size_t max_idx = 0; uint8 byte_length = 0; uint8 pixel_width = 0; scr_coord_val current_offset = 0; const char *tmp_text = text; while( get_next_char_with_metrics(tmp_text, byte_length, pixel_width) && max_width > (current_offset+pixel_width) ) { current_offset += pixel_width; max_idx += byte_length; } return max_idx; } /** * For the previous logical character in the text, returns the character code * as well as retrieves the char byte count and the screen pixel width * CAUTION : The text pointer recedes to point to the previous logical character */ utf32 get_prev_char_with_metrics(const char* &text, const char *const text_start, unsigned char &byte_length, unsigned char &pixel_width) { if( text<=text_start ) { // case : start of text reached or passed -> do not move the pointer backwards byte_length = 0; pixel_width = 0; return 0; } utf32 char_code; // determine the start of the previous logical character do { --text; } while ( text>text_start && (*text & 0xC0)==0x80 ); size_t len = 0; char_code = utf8_decoder_t::decode((utf8 const *)text, len); byte_length = (uint8)len; pixel_width = default_font.get_glyph_advance(char_code); return char_code; } /* proportional_string_width with a text of a given length * extended for universal font routines with unicode support */ scr_coord_val display_calc_proportional_string_len_width(const char *text, size_t len) { uint8 byte_length = 0; uint8 pixel_width = 0; size_t idx = 0; scr_coord_val width = 0; while (get_next_char_with_metrics(text, byte_length, pixel_width) && idx < len) { width += pixel_width; idx += byte_length; } return width; } /* display_calc_proportional_multiline_string_len_width * calculates the width and hieght of a box containing the text inside */ void display_calc_proportional_multiline_string_len_width(int &xw, int &yh, const char *text) { const font_t* const fnt = &default_font; int width = 0; bool last_cr = false; xw = yh = 0; const utf8 *p = reinterpret_cast(text); while (const utf32 iUnicode = utf8_decoder_t::decode(p)) { if( iUnicode == '\n' ) { // new line: record max width xw = max( xw, width ); yh += LINESPACE; width = 0; last_cr = true; continue; } last_cr = false; width += fnt->get_glyph_advance(iUnicode); } xw = max( xw, width ); if (!last_cr) { // extra CR of the last was not already a CR yh += LINESPACE; } } /** * len parameter added - use -1 for previous behaviour. * completely renovated for unicode and 10 bit width and variable height */ scr_coord_val display_text_proportional_len_clip_rgb(scr_coord_val x, scr_coord_val y, const char* txt, control_alignment_t flags, const PIXVAL color, bool dirty, sint32 len CLIP_NUM_DEF) { scr_coord_val cL, cR, cT, cB; // TAKE CARE: Clipping area may be larger than actual screen size if( (flags & DT_CLIP) ) { cL = CR.clip_rect.x; cR = CR.clip_rect.xx; cT = CR.clip_rect.y; cB = CR.clip_rect.yy; } else { cL = 0; cR = disp_width; cT = 0; cB = disp_height; } if (len < 0) { // don't know len yet len = 0x7FFF; } // adapt x-coordinate for alignment switch (flags & ( ALIGN_LEFT | ALIGN_CENTER_H | ALIGN_RIGHT) ) { case ALIGN_LEFT: // nothing to do break; case ALIGN_CENTER_H: x -= display_calc_proportional_string_len_width(txt, len) / 2; break; case ALIGN_RIGHT: x -= display_calc_proportional_string_len_width(txt, len); break; } // still something to display? const font_t *const fnt = &default_font; if (x >= cR || y >= cB || y + fnt->get_linespace() <= cT) { // nothing to display return 0; } // store the initial x (for dirty marking) const scr_coord_val x0 = x; // big loop, draw char by char utf8_decoder_t decoder((utf8 const*)txt); size_t iTextPos = 0; // pointer on text position while (iTextPos < (size_t)len && decoder.has_next()) { // decode char utf32 c = decoder.next(); iTextPos = decoder.get_position() - (utf8 const*)txt; if( c == '\n' ) { // stop at linebreak break; } // print unknown character? else if( !fnt->is_valid_glyph(c) ) { c = 0; } // get the data from the font const font_t::glyph_t& glyph = fnt->get_glyph(c); const uint8 *p = glyph.bitmap; int screen_pos = (y + glyph.top) * disp_width + x + glyph.left; // glyph x clipping int g_left = max(cL - x - glyph.left, 0); int g_right = min(cR - x - glyph.left, glyph.width); // all visible rows for (int h = 0; h < glyph.height; h++) { const int line = y + glyph.top + h; if(line >= cT && line < cB) { PIXVAL* dst = textur + screen_pos + g_left; // all columns for(int gx=g_left; gx 31) { // opaque *dst++ = color; } else { // partially transparent -> blend it PIXVAL old_color = *dst; *dst++ = colors_blend_alpha32(old_color, color, alpha); } } } screen_pos += disp_width; } x += fnt->get_glyph_advance(c); } if( dirty ) { // here, because only now we know the length also for ALIGN_LEFT text mark_rect_dirty_clip( x0, y, x - 1, y + LINESPACE - 1 CLIP_NUM_PAR); } // warning: actual len might be longer, due to clipping! return x - x0; } /// Displays a string which is abbreviated by the (language specific) ellipsis character if too wide /// If enough space is given then it just displays the full string void display_proportional_ellipsis_rgb( scr_rect r, const char *text, int align, const PIXVAL color, const bool dirty, bool shadowed, PIXVAL shadow_color) { const scr_coord_val ellipsis_width = translator::get_lang()->ellipsis_width; const scr_coord_val max_screen_width = r.w; size_t max_idx = 0; uint8 byte_length = 0; uint8 pixel_width = 0; scr_coord_val current_offset = 0; if( align & ALIGN_CENTER_V ) { r.y += (r.h - LINESPACE)/2; align &= ~ALIGN_CENTER_V; } const char *tmp_text = text; while( get_next_char_with_metrics(tmp_text, byte_length, pixel_width) && max_screen_width >= (current_offset+ellipsis_width+pixel_width) ) { current_offset += pixel_width; max_idx += byte_length; } size_t max_idx_before_ellipsis = max_idx; scr_coord_val max_offset_before_ellipsis = current_offset; // now check if the text would fit completely if( ellipsis_width && pixel_width > 0 ) { // only when while above failed because of exceeding length current_offset += pixel_width; max_idx += byte_length; // check the rest ... while( get_next_char_with_metrics(tmp_text, byte_length, pixel_width) && max_screen_width >= (current_offset+pixel_width) ) { current_offset += pixel_width; max_idx += byte_length; } // if it does not fit if( max_screen_width < (current_offset+pixel_width) ) { scr_coord_val w = 0; // since we know the length already, we try to center the text with the remaining pixels of the last character if( align & ALIGN_CENTER_H ) { w = (max_screen_width-max_offset_before_ellipsis-ellipsis_width)/2; } if (shadowed) { display_text_proportional_len_clip_rgb( r.x+w+1, r.y+1, text, ALIGN_LEFT | DT_CLIP, shadow_color, dirty, max_idx_before_ellipsis CLIP_NUM_DEFAULT); } w += display_text_proportional_len_clip_rgb( r.x+w, r.y, text, ALIGN_LEFT | DT_CLIP, color, dirty, max_idx_before_ellipsis CLIP_NUM_DEFAULT); if (shadowed) { display_text_proportional_len_clip_rgb( r.x+w+1, r.y+1, translator::translate("..."), ALIGN_LEFT | DT_CLIP, shadow_color, dirty, -1 CLIP_NUM_DEFAULT); } display_text_proportional_len_clip_rgb( r.x+w, r.y, translator::translate("..."), ALIGN_LEFT | DT_CLIP, color, dirty, -1 CLIP_NUM_DEFAULT); return; } else { // if this fits, end of string max_idx += byte_length; current_offset += pixel_width; } } switch (align & ALIGN_RIGHT) { case ALIGN_CENTER_H: r.x += (max_screen_width - current_offset)/2; break; case ALIGN_RIGHT: r.x += max_screen_width - current_offset; default: ; } if (shadowed) { display_text_proportional_len_clip_rgb( r.x+1, r.y+1, text, ALIGN_LEFT | DT_CLIP, shadow_color, dirty, -1 CLIP_NUM_DEFAULT); } display_text_proportional_len_clip_rgb( r.x, r.y, text, ALIGN_LEFT | DT_CLIP, color, dirty, -1 CLIP_NUM_DEFAULT); } /** * Draw shaded rectangle using direct color values */ void display_ddd_box_rgb(scr_coord_val x1, scr_coord_val y1, scr_coord_val w, scr_coord_val h, PIXVAL tl_color, PIXVAL rd_color, bool dirty) { display_fillbox_wh_rgb(x1, y1, w, 1, tl_color, dirty); display_fillbox_wh_rgb(x1, y1 + h - 1, w, 1, rd_color, dirty); h -= 2; display_vline_wh_rgb(x1, y1 + 1, h, tl_color, dirty); display_vline_wh_rgb(x1 + w - 1, y1 + 1, h, rd_color, dirty); } void display_outline_proportional_rgb(scr_coord_val xpos, scr_coord_val ypos, PIXVAL text_color, PIXVAL shadow_color, const char *text, int dirty, sint32 len) { const int flags = ALIGN_LEFT | DT_CLIP; display_text_proportional_len_clip_rgb(xpos - 1, ypos , text, flags, shadow_color, dirty, len CLIP_NUM_DEFAULT); display_text_proportional_len_clip_rgb(xpos + 1, ypos + 2, text, flags, shadow_color, dirty, len CLIP_NUM_DEFAULT); display_text_proportional_len_clip_rgb(xpos, ypos + 1, text, flags, text_color, dirty, len CLIP_NUM_DEFAULT); } void display_shadow_proportional_rgb(scr_coord_val xpos, scr_coord_val ypos, PIXVAL text_color, PIXVAL shadow_color, const char *text, int dirty, sint32 len) { const int flags = ALIGN_LEFT | DT_CLIP; display_text_proportional_len_clip_rgb(xpos + 1, ypos + 1 + (12 - LINESPACE) / 2, text, flags, shadow_color, dirty, len CLIP_NUM_DEFAULT); display_text_proportional_len_clip_rgb(xpos, ypos + (12 - LINESPACE) / 2, text, flags, text_color, dirty, len CLIP_NUM_DEFAULT); } /** * Draw shaded rectangle using direct color values */ void display_ddd_box_clip_rgb(scr_coord_val x1, scr_coord_val y1, scr_coord_val w, scr_coord_val h, PIXVAL tl_color, PIXVAL rd_color) { display_fillbox_wh_clip_rgb(x1, y1, w, 1, tl_color, true); display_fillbox_wh_clip_rgb(x1, y1 + h - 1, w, 1, rd_color, true); h -= 2; display_vline_wh_clip_rgb(x1, y1 + 1, h, tl_color, true); display_vline_wh_clip_rgb(x1 + w - 1, y1 + 1, h, rd_color, true); } /** * display text in 3d box with clipping */ void display_ddd_proportional_clip(scr_coord_val xpos, scr_coord_val ypos, FLAGGED_PIXVAL ddd_color, FLAGGED_PIXVAL text_color, const char *text, int dirty CLIP_NUM_DEF) { const int vpadding = LINESPACE / 7; const int hpadding = LINESPACE / 4; scr_coord_val width = proportional_string_width(text); PIXVAL lighter = display_blend_colors_alpha32(ddd_color, color_idx_to_rgb(COL_WHITE), 8 /* 25% */); PIXVAL darker = display_blend_colors_alpha32(ddd_color, color_idx_to_rgb(COL_BLACK), 8 /* 25% */); display_fillbox_wh_clip_rgb( xpos+1, ypos - vpadding + 1, width+2*hpadding-2, LINESPACE+2*vpadding-1, ddd_color, dirty CLIP_NUM_PAR); display_fillbox_wh_clip_rgb( xpos, ypos - vpadding, width + 2*hpadding - 2, 1, lighter, dirty ); display_fillbox_wh_clip_rgb( xpos, ypos + LINESPACE + vpadding, width + 2*hpadding - 2, 1, darker, dirty ); display_vline_wh_clip_rgb( xpos, ypos - vpadding, LINESPACE + vpadding * 2, lighter, dirty ); display_vline_wh_clip_rgb( xpos + width + 2*hpadding - 2, ypos - vpadding, LINESPACE + vpadding * 2, darker, dirty ); display_text_proportional_len_clip_rgb( xpos+hpadding, ypos+1, text, ALIGN_LEFT | DT_CLIP, text_color, dirty, -1); } /** * Draw multiline text */ scr_coord_val display_multiline_text_rgb(scr_coord_val x, scr_coord_val y, const char *buf, PIXVAL color) { scr_coord_val max_px_len = 0; if (buf != NULL && *buf != '\0') { const char *next; do { next = strchr(buf, '\n'); const scr_coord_val px_len = display_text_proportional_len_clip_rgb( x, y, buf, ALIGN_LEFT | DT_CLIP, color, true, next != NULL ? (int)(size_t)(next - buf) : -1 ); if( px_len>max_px_len ) { max_px_len = px_len; } y += LINESPACE; } while ((void)(buf = (next ? next+1 : NULL)), buf != NULL); } return max_px_len; } /** * draw line from x,y to xx,yy **/ void display_direct_line_rgb(const scr_coord_val x, const scr_coord_val y, const scr_coord_val xx, const scr_coord_val yy, const PIXVAL colval) { int i, steps; sint64 xp, yp; sint64 xs, ys; const int dx = xx - x; const int dy = yy - y; steps = (abs(dx) > abs(dy) ? abs(dx) : abs(dy)); if (steps == 0) { steps = 1; } xs = ((sint64)dx << 16) / steps; ys = ((sint64)dy << 16) / steps; xp = (sint64)x << 16; yp = (sint64)y << 16; for (i = 0; i <= steps; i++) { #ifdef DEBUG_FLUSH_BUFFER display_pixel(xp >> 16, yp >> 16, colval, false); #else display_pixel(xp >> 16, yp >> 16, colval); #endif xp += xs; yp += ys; } } //taken from function display_direct_line() above, to draw a dotted line: draw=pixels drawn, dontDraw=pixels skipped void display_direct_line_dotted_rgb(const scr_coord_val x, const scr_coord_val y, const scr_coord_val xx, const scr_coord_val yy, const scr_coord_val draw, const scr_coord_val dontDraw, const PIXVAL colval) { int i, steps; sint64 xp, yp; sint64 xs, ys; int counter=0; bool mustDraw=true; const int dx = xx - x; const int dy = yy - y; steps = (abs(dx) > abs(dy) ? abs(dx) : abs(dy)); if (steps == 0) { steps = 1; } xs = ((sint64)dx << 16) / steps; ys = ((sint64)dy << 16) / steps; xp = (sint64)x << 16; yp = (sint64)y << 16; for( i = 0; i <= steps; i++ ) { counter ++; if( mustDraw ) { if( counter == draw ) { mustDraw = !mustDraw; counter = 0; } } if( !mustDraw ) { if( counter == dontDraw ) { mustDraw=!mustDraw; counter=0; } } if( mustDraw ) { display_pixel( xp >> 16, yp >> 16, colval ); } xp += xs; yp += ys; } } // bresenham circle (from wikipedia ...) void display_circle_rgb( scr_coord_val x0, scr_coord_val y0, int radius, const PIXVAL colval ) { int f = 1 - radius; int ddF_x = 1; int ddF_y = -2 * radius; int x = 0; int y = radius; display_pixel( x0, y0 + radius, colval ); display_pixel( x0, y0 - radius, colval ); display_pixel( x0 + radius, y0, colval ); display_pixel( x0 - radius, y0, colval ); while(x < y) { // ddF_x == 2 * x + 1; // ddF_y == -2 * y; // f == x*x + y*y - radius*radius + 2*x - y + 1; if(f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; display_pixel( x0 + x, y0 + y, colval ); display_pixel( x0 - x, y0 + y, colval ); display_pixel( x0 + x, y0 - y, colval ); display_pixel( x0 - x, y0 - y, colval ); display_pixel( x0 + y, y0 + x, colval ); display_pixel( x0 - y, y0 + x, colval ); display_pixel( x0 + y, y0 - x, colval ); display_pixel( x0 - y, y0 - x, colval ); } } // bresenham circle (from wikipedia ...) void display_filled_circle_rgb( scr_coord_val x0, scr_coord_val y0, int radius, const PIXVAL colval ) { int f = 1 - radius; int ddF_x = 1; int ddF_y = -2 * radius; int x = 0; int y = radius; display_fb_internal( x0-radius, y0, radius+radius+1, 1, colval, false, CR0.clip_rect.x, CR0.clip_rect.xx, CR0.clip_rect.y, CR0.clip_rect.yy ); display_pixel( x0, y0 + radius, colval ); display_pixel( x0, y0 - radius, colval ); display_pixel( x0 + radius, y0, colval ); display_pixel( x0 - radius, y0, colval ); while(x < y) { // ddF_x == 2 * x + 1; // ddF_y == -2 * y; // f == x*x + y*y - radius*radius + 2*x - y + 1; if(f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; display_fb_internal( x0-x, y0+y, x+x, 1, colval, false, CR0.clip_rect.x, CR0.clip_rect.xx, CR0.clip_rect.y, CR0.clip_rect.yy ); display_fb_internal( x0-x, y0-y, x+x, 1, colval, false, CR0.clip_rect.x, CR0.clip_rect.xx, CR0.clip_rect.y, CR0.clip_rect.yy ); display_fb_internal( x0-y, y0+x, y+y, 1, colval, false, CR0.clip_rect.x, CR0.clip_rect.xx, CR0.clip_rect.y, CR0.clip_rect.yy ); display_fb_internal( x0-y, y0-x, y+y, 1, colval, false, CR0.clip_rect.x, CR0.clip_rect.xx, CR0.clip_rect.y, CR0.clip_rect.yy ); } // mark_rect_dirty_wc( x0-radius, y0-radius, x0+radius+1, y0+radius+1 ); } void display_signal_direction_rgb(scr_coord_val x, scr_coord_val y, uint8 way_dir, uint8 sig_dir, PIXVAL col1, PIXVAL col1_dark, bool is_diagonal, uint8 slope ) { uint8 width = is_diagonal ? current_tile_raster_width/6*0.353 :current_tile_raster_width/6; const uint8 height = is_diagonal ?current_tile_raster_width/6*0.353 :current_tile_raster_width/12; const uint8 thickness = max( current_tile_raster_width/36, 2); x += current_tile_raster_width/2; y += (current_tile_raster_width*9)/16; if (is_diagonal) { if (way_dir == ribi_t::northeast || way_dir == ribi_t::southwest) { // vertical x += (way_dir==ribi_t::northeast) ?current_tile_raster_width/4 : (-current_tile_raster_width/4); y += current_tile_raster_width/16; width = width<<2; // 4x // upper for (uint8 xoff = 0; xoff < width/2; xoff++) { const uint8 yoff = (uint8)((xoff+1)/2); // up if (sig_dir & ribi_t::east || sig_dir & ribi_t::south) { display_vline_wh_clip_rgb(x + xoff, y+yoff, width/4 - yoff, col1, true); display_vline_wh_clip_rgb(x-xoff-1, y+yoff, width/4 - yoff, col1, true); } // down if (sig_dir & ribi_t::west || sig_dir & ribi_t::north) { display_vline_wh_clip_rgb(x + xoff, y+current_tile_raster_width/6, width/4-yoff, col1, true); display_vline_wh_clip_rgb(x + xoff, y+current_tile_raster_width/6+width/4-yoff, thickness, col1_dark, true); display_vline_wh_clip_rgb(x-xoff-1, y+current_tile_raster_width/6, width/4-yoff, col1, true); display_vline_wh_clip_rgb(x-xoff-1, y+current_tile_raster_width/6+width/4-yoff, thickness, col1_dark, true); } } // up if (sig_dir & ribi_t::east || sig_dir & ribi_t::south) { display_fillbox_wh_clip_rgb(x - width/2, y + width/4, width, thickness, col1_dark, true); } } else { // horizontal y -= current_tile_raster_width/12; if (way_dir == ribi_t::southeast) { y += current_tile_raster_width/4; } for (uint8 xoff = 0; xoff < width*2; xoff++) { const uint8 h = width*2 - (scr_coord_val)(xoff + 1); // left if (sig_dir & ribi_t::north || sig_dir & ribi_t::east) { display_vline_wh_clip_rgb(x - xoff - width*2, y + (scr_coord_val)((xoff+1)/2), h, col1, true); display_vline_wh_clip_rgb(x - xoff - width*2, y + (scr_coord_val)((xoff+1)/2)+h, thickness, col1_dark, true); } // right if (sig_dir & ribi_t::south || sig_dir & ribi_t::west) { display_vline_wh_clip_rgb(x + xoff + width*2, y + (scr_coord_val)((xoff+1)/2), h, col1, true); display_vline_wh_clip_rgb(x + xoff + width*2, y + (scr_coord_val)((xoff+1)/2)+h, thickness, col1_dark, true); } } } } else { if (sig_dir & ribi_t::south) { // upper right scr_coord_val slope_offset_y = corner_se( slope )*TILE_HEIGHT_STEP; for (uint8 xoff = 0; xoff < width; xoff++) { display_vline_wh_clip_rgb( x + xoff, y - slope_offset_y, (scr_coord_val)(xoff/2) + 1, col1, true ); display_vline_wh_clip_rgb( x + xoff, y - slope_offset_y + (scr_coord_val)(xoff/2) + 1, thickness, col1_dark, true ); } } if (sig_dir & ribi_t::east) { scr_coord_val slope_offset_y = corner_se( slope )*TILE_HEIGHT_STEP; for (uint8 xoff = 0; xoff < width; xoff++) { display_vline_wh_clip_rgb(x - xoff - 1, y - slope_offset_y, (scr_coord_val)(xoff/2) + 1, col1, true); display_vline_wh_clip_rgb(x - xoff - 1, y - slope_offset_y + (scr_coord_val)(xoff/2) + 1, thickness, col1_dark, true); } } if (sig_dir & ribi_t::west) { scr_coord_val slope_offset_y = corner_nw( slope )*TILE_HEIGHT_STEP; for (uint8 xoff = 0; xoff < width; xoff++) { display_vline_wh_clip_rgb(x + xoff, y - slope_offset_y + height*2 - (scr_coord_val)(xoff/2) + 1, (scr_coord_val)(xoff/2) + 1, col1, true); display_vline_wh_clip_rgb(x + xoff, y - slope_offset_y + height*2 + 1, thickness, col1_dark, true); } } if (sig_dir & ribi_t::north) { scr_coord_val slope_offset_y = corner_nw( slope )*TILE_HEIGHT_STEP; for (uint8 xoff = 0; xoff < width; xoff++) { display_vline_wh_clip_rgb(x - xoff - 1, y - slope_offset_y + height*2 - (scr_coord_val)(xoff/2) + 1, (scr_coord_val)(xoff/2) + 1, col1, true); display_vline_wh_clip_rgb(x - xoff - 1, y - slope_offset_y + height*2 + 1, thickness, col1_dark, true); } } } } /** * Print a bezier curve between points A and B * @param Ax,Ay start coordinate of Bezier curve * @param Bx,By end coordinate of Bezier curve * @param ADx,ADy vector for start direction of curve * @param BDx,BDy vector for end direction of Bezier curve * @param colore color for curve to be drawn * @param draw for dotted lines, how many pixels to be drawn (leave 0 for solid line) * @param dontDraw for dotted lines, how many pixels to not be drawn (leave 0 for solid line) */ void draw_bezier_rgb(scr_coord_val Ax, scr_coord_val Ay, scr_coord_val Bx, scr_coord_val By, scr_coord_val ADx, scr_coord_val ADy, scr_coord_val BDx, scr_coord_val BDy, const PIXVAL colore, scr_coord_val draw, scr_coord_val dontDraw) { scr_coord_val Cx,Cy,Dx,Dy; Cx = Ax + ADx; Cy = Ay + ADy; Dx = Bx + BDx; Dy = By + BDy; /* float a,b,rx,ry,oldx,oldy; for (float t=0.0;t<=1;t+=0.05) { a = t; b = 1.0 - t; if (t>0.0) { oldx=rx; oldy=ry; } rx = Ax*b*b*b + 3*Cx*b*b*a + 3*Dx*b*a*a + Bx*a*a*a; ry = Ay*b*b*b + 3*Cy*b*b*a + 3*Dy*b*a*a + By*a*a*a; if (t>0.0) if (!draw && !dontDraw) display_direct_line_rgb(rx,ry,oldx,oldy,colore); else display_direct_line_dotted_rgb(rx,ry,oldx,oldy,draw,dontDraw,colore); } */ sint32 rx = Ax*32*32*32; // init with a=0, b=32 sint32 ry = Ay*32*32*32; // init with a=0, b=32 // fixed point: we cycle between 0 and 32, rather than 0 and 1 for( sint32 a=1; a<=32; a++ ) { const sint32 b = 32 - a; const sint32 oldx = rx; const sint32 oldy = ry; rx = Ax*b*b*b + 3*Cx*b*b*a + 3*Dx*b*a*a + Bx*a*a*a; ry = Ay*b*b*b + 3*Cy*b*b*a + 3*Dy*b*a*a + By*a*a*a; // fixed point: due to cycling between 0 and 32 (1<<5), we divide by 32^3 == 1<<15 because of cubic interpolation if( !draw && !dontDraw ) { display_direct_line_rgb( rx>>15, ry>>15, oldx>>15, oldy>>15, colore ); } else { display_direct_line_dotted_rgb( rx>>15, ry>>15, oldx>>15, oldy>>15, draw, dontDraw, colore ); } } } // Only right facing at the moment void display_right_triangle_rgb(scr_coord_val x, scr_coord_val y, scr_coord_val height, const PIXVAL colval, const bool dirty) { y += (height / 2); while( height > 0 ) { display_vline_wh_rgb( x, y-(height/2), height, colval, dirty ); x++; height -= 2; } } // ------------------- other support routines that actually interface with the OS ----------------- /// Returns the index of the least significant set bit of a number, e.g. returns 2 for @p val == 12. /// Returns 0 for @p val == 0. static inline uint32 get_lowest_set_bit(uint32 val) { static const uint8 MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; return MultiplyDeBruijnBitPosition[(((val & -val) * 0x077CB531U)) >> 27]; } /** * copies only the changed areas to the screen using the "tile dirty buffer" * To get large changes, actually the current and the previous one is used. */ void display_flush_buffer() { #ifdef USE_SOFTPOINTER ex_ord_update_mx_my(); const scr_coord_val ticker_ypos_bottom = display_get_height() - win_get_statusbar_height() - (env_t::menupos == MENU_BOTTOM) * env_t::iconsize.h; const scr_coord_val ticker_ypos_top = ticker_ypos_bottom - TICKER_HEIGHT; // use mouse pointer image if available if (softpointer != -1 && standard_pointer >= 0) { display_color_img(standard_pointer, sys_event.mx, sys_event.my, 0, false, true CLIP_NUM_DEFAULT); // if software emulated mouse pointer is over the ticker, redraw it totally at next occurs if (!ticker::empty() && sys_event.my+images[standard_pointer].h >= ticker_ypos_top && sys_event.my <= ticker_ypos_bottom) { ticker::set_redraw_all(true); } } // no pointer image available, draw a crosshair else { display_fb_internal(sys_event.mx - 1, sys_event.my - 3, 3, 7, color_idx_to_rgb(COL_WHITE), true, 0, disp_width, 0, disp_height); display_fb_internal(sys_event.mx - 3, sys_event.my - 1, 7, 3, color_idx_to_rgb(COL_WHITE), true, 0, disp_width, 0, disp_height); display_direct_line_rgb( sys_event.mx-2, sys_event.my, sys_event.mx+2, sys_event.my, color_idx_to_rgb(COL_BLACK) ); display_direct_line_rgb( sys_event.mx, sys_event.my-2, sys_event.mx, sys_event.my+2, color_idx_to_rgb(COL_BLACK) ); // if crosshair is over the ticker, redraw it totally at next occurs if(!ticker::empty() && sys_event.my+2 >= ticker_ypos_top && sys_event.my-2 <= ticker_ypos_bottom) { ticker::set_redraw_all(true); } } old_my = sys_event.my; #endif // combine current with last dirty tiles for( int i = 0; i < tile_buffer_length; i++ ) { tile_dirty_old[i] |= tile_dirty[i]; } const int tile_words_per_line = tile_buffer_per_line >> 5; ALLOCA( uint32, masks, tile_words_per_line ); for( int x1 = 0; x1 < tiles_per_line; x1++ ) { const uint32 x_search_mask = 1 << (x1 & 31); // bit mask for finding bit x set int y1 = 0; do { const int word_max = (0 + (y1 + 1) * tile_buffer_per_line) >> 5; // first word on next line. limit search to < max const int word_x1 = (x1 + y1 * tile_buffer_per_line) >> 5; if( (tile_dirty_old[word_x1] & x_search_mask) == x_search_mask ) { // found dirty tile at x1, now find contiguous block of dirties - x2 const uint32 testval = ~((~(0xFFFFFFFF << (x1 & 31))) | tile_dirty_old[word_x1]); int word_x2 = word_x1; int x2; if( testval == 0 ) { // dirty block spans words masks[0] = tile_dirty_old[word_x1]; word_x2++; while( word_x2 < word_max && tile_dirty_old[word_x2] == 0xFFFFFFFF ) { masks[word_x2 - word_x1] = 0xFFFFFFFF; // dirty block spans this entire word word_x2++; } if( word_x2 >= word_max // dirty tiles extend all the way to screen edge || !(tile_dirty_old[word_x2] & 1) ) { // dirty block actually ended on the word edge x2 = 32; // set to whole word word_x2--; // masks already set in while loop above } else { // dirty block ends in word_x2 x2 = get_lowest_set_bit(~tile_dirty_old[word_x2]); masks[word_x2-word_x1] = 0xFFFFFFFF >> (32 - x2); } } else { // dirty block is all within one word - word_x1 x2 = get_lowest_set_bit(testval); masks[0] = (0xFFFFFFFF << (32 - x2 + (x1 & 31))) >> (32 - x2); } for( int i = word_x1; i <= word_x2; i++ ) { // clear dirty tile_dirty_old[i] &= ~masks[i - word_x1]; } // x2 from bit index to tile coords x2 += (x1 & ~31) + ((word_x2 - word_x1) << 5); // find how many rows can be combined into one rectangle int y2 = y1 + 1; bool xmatch = true; while( y2 < tile_lines && xmatch ) { const int li = (x1 + y2 * tile_buffer_per_line) >> 5; const int ri = li + word_x2 - word_x1; for( int i = li; i <= ri; i++ ) { if( (tile_dirty_old[i] & masks[i - li]) != masks[i - li] ) { xmatch = false; break; } } if( xmatch ) { for( int i = li; i <= ri; i++ ) { // clear dirty tile_dirty_old[i] &= ~masks[i - li]; } y2++; } } #ifdef DEBUG_FLUSH_BUFFER display_vline_wh_rgb( (x1 << DIRTY_TILE_SHIFT) - 1, y1 << DIRTY_TILE_SHIFT, (y2 - y1) << DIRTY_TILE_SHIFT, color_idx_to_rgb(COL_YELLOW), false); display_vline_wh_rgb( x2 << DIRTY_TILE_SHIFT, y1 << DIRTY_TILE_SHIFT, (y2 - y1) << DIRTY_TILE_SHIFT, color_idx_to_rgb(COL_YELLOW), false); display_fillbox_wh_rgb( x1 << DIRTY_TILE_SHIFT, y1 << DIRTY_TILE_SHIFT, (x2 - x1) << DIRTY_TILE_SHIFT, 1, color_idx_to_rgb(COL_YELLOW), false); display_fillbox_wh_rgb( x1 << DIRTY_TILE_SHIFT, (y2 << DIRTY_TILE_SHIFT) - 1, (x2 - x1) << DIRTY_TILE_SHIFT, 1, color_idx_to_rgb(COL_YELLOW), false); display_direct_line_rgb( x1 << DIRTY_TILE_SHIFT, y1 << DIRTY_TILE_SHIFT, x2 << DIRTY_TILE_SHIFT, (y2 << DIRTY_TILE_SHIFT) - 1, color_idx_to_rgb(COL_YELLOW) ); display_direct_line_rgb( x1 << DIRTY_TILE_SHIFT, (y2 << DIRTY_TILE_SHIFT) - 1, x2 << DIRTY_TILE_SHIFT, y1 << DIRTY_TILE_SHIFT, color_idx_to_rgb(COL_YELLOW) ); #else dr_textur( x1 << DIRTY_TILE_SHIFT, y1 << DIRTY_TILE_SHIFT, (x2 - x1) << DIRTY_TILE_SHIFT, (y2 - y1) << DIRTY_TILE_SHIFT ); #endif y1 = y2; // continue search from bottom of found rectangle } else { y1++; } } while( y1 < tile_lines ); } #ifdef DEBUG_FLUSH_BUFFER dr_textur(0, 0, disp_actual_width, disp_height ); #endif // swap tile buffers uint32 *tmp = tile_dirty_old; tile_dirty_old = tile_dirty; tile_dirty = tmp; // _old was cleared to 0 in above loops } /** * Turn mouse pointer visible/invisible */ void display_show_pointer(int yesno) { #ifdef USE_SOFTPOINTER softpointer = yesno; #else show_pointer(yesno); #endif } /** * mouse pointer image */ void display_set_pointer(int pointer) { standard_pointer = pointer; } /** * mouse pointer image */ void display_show_load_pointer(int loading) { #ifdef USE_SOFTPOINTER softpointer = !loading; #else set_pointer(loading); #endif } /** * Initialises the graphics module */ bool simgraph_init(scr_size window_size, sint16 full_screen) { disp_actual_width = window_size.w; disp_height = window_size.h; #ifdef MULTI_THREAD pthread_mutex_init( &recode_img_mutex, NULL ); #endif // init rezoom_img() for( int i = 0; i < MAX_THREADS; i++ ) { #ifdef MULTI_THREAD pthread_mutex_init( &rezoom_img_mutex[i], NULL ); #endif rezoom_baseimage[i] = NULL; rezoom_baseimage2[i] = NULL; rezoom_size[i] = 0; } // get real width from os-dependent routines disp_width = dr_os_open(window_size, full_screen); if( disp_width<=0 ) { dr_fatal_notify( "Cannot open window!" ); return false; } textur = dr_textur_init(); // init, load, and check fonts if (!display_load_font(env_t::fontname.c_str())) { env_t::fontname = dr_get_system_font(); if (!display_load_font(env_t::fontname.c_str())) { env_t::fontname = FONT_PATH_X "cyr.bdf"; if (!display_load_font(env_t::fontname.c_str())) { dr_fatal_notify("No fonts found!"); return false; } } } // allocate dirty tile flags tiles_per_line = (disp_width + DIRTY_TILE_SIZE - 1) / DIRTY_TILE_SIZE; tile_buffer_per_line = (tiles_per_line + 31) & ~31; tile_lines = (disp_height + DIRTY_TILE_SIZE - 1) / DIRTY_TILE_SIZE; tile_buffer_length = (tile_lines * tile_buffer_per_line / 32); tile_dirty = MALLOCN( uint32, tile_buffer_length ); tile_dirty_old = MALLOCN( uint32, tile_buffer_length ); mark_screen_dirty(); MEMZERON( tile_dirty_old, tile_buffer_length ); // init player colors for( int i = 0; i < MAX_PLAYER_COUNT; i++ ) { player_offsets[i][0] = i*8; player_offsets[i][1] = i*8+24; } display_set_clip_wh(0, 0, disp_width, disp_height); // Calculate daylight rgbmap and save it for unshaded tile drawing player_day = 0; display_day_night_shift(0); memcpy(specialcolormap_all_day, specialcolormap_day_night, 256 * sizeof(PIXVAL)); memcpy(rgbmap_all_day, rgbmap_day_night, RGBMAPSIZE * sizeof(PIXVAL)); // find out bit depth { PIXVAL c = get_system_color({ 0, 0xFF, 0 }); while ((c&1)==0) { c >>= 1; } if(c==0x1F) { // 5 bits for green channel -> 15 bits per pixel) #ifndef RGB555 dr_fatal_notify( "Compiled for 16 bit color depth but using 15!" ); #endif } else { #ifdef RGB555 dr_fatal_notify( "Compiled for 15 bit color depth but using 16!" ); #endif } } return true; } /** * Check if the graphic module already was initialized. */ bool is_display_init() { return textur != NULL && default_font.is_loaded() && images!=NULL; } /** * Close the Graphic module */ void simgraph_exit() { dr_os_close(); free( tile_dirty_old ); free( tile_dirty ); display_free_all_images_above(0); free(images); tile_dirty = tile_dirty_old = NULL; images = NULL; #ifdef MULTI_THREAD pthread_mutex_destroy( &recode_img_mutex ); for( int i = 0; i < MAX_THREADS; i++ ) { pthread_mutex_destroy( &rezoom_img_mutex[i] ); } #endif } /* changes display size */ void simgraph_resize(scr_size new_window_size) { disp_actual_width = max( 16, new_window_size.w ); if( new_window_size.h<=0 ) { new_window_size.h = 64; } // only resize, if internal values are different if (disp_width != new_window_size.w || disp_height != new_window_size.h) { scr_coord_val new_pitch = dr_textur_resize(&textur, new_window_size.w, new_window_size.h); if( new_pitch!=disp_width || disp_height != new_window_size.h) { disp_width = new_pitch; disp_height = new_window_size.h; free( tile_dirty_old ); free( tile_dirty); // allocate dirty tile flags tiles_per_line = (disp_width + DIRTY_TILE_SIZE - 1) / DIRTY_TILE_SIZE; tile_buffer_per_line = (tiles_per_line + 31) & ~31; tile_lines = (disp_height + DIRTY_TILE_SIZE - 1) / DIRTY_TILE_SIZE; tile_buffer_length = (tile_lines * tile_buffer_per_line / 32); tile_dirty = MALLOCN( uint32, tile_buffer_length ); tile_dirty_old = MALLOCN( uint32, tile_buffer_length ); display_set_clip_wh(0, 0, disp_actual_width, disp_height); } mark_screen_dirty(); MEMZERON( tile_dirty_old, tile_buffer_length ); } } /** * Take Screenshot */ bool display_snapshot( const scr_rect &area ) { if (access(SCREENSHOT_PATH_X, W_OK) == -1) { return false; // directory not accessible } static int number = 0; char filename[80]; // find the first not used screenshot image do { sprintf(filename, SCREENSHOT_PATH_X "simscr%02d.png", number++); } while (access(filename, W_OK) != -1); // now save the screenshot scr_rect clipped_area = area; clipped_area.clip(scr_rect(0, 0, disp_actual_width, disp_height)); raw_image_t img(clipped_area.w, clipped_area.h, raw_image_t::FMT_RGB888); for (scr_coord_val y = clipped_area.y; y < clipped_area.y + clipped_area.h; ++y) { uint8 *dst = img.access_pixel(0, y); const PIXVAL *row = textur + clipped_area.x + y*disp_width; for (scr_coord_val x = clipped_area.x; x < clipped_area.x + clipped_area.w; ++x) { const rgb888_t pixel = pixval_to_rgb888(*row++); *dst++ = pixel.r; *dst++ = pixel.g; *dst++ = pixel.b; } } return img.write_png(filename); } simutrans-124.3/src/simutrans/display/simimg.h000066400000000000000000000004451474050137200214750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_SIMIMG_H #define DISPLAY_SIMIMG_H #include "../simtypes.h" /* * Defines to handle images */ typedef uint32 image_id; #define IMG_EMPTY ((image_id)0xFFFFFFFFu) #endif simutrans-124.3/src/simutrans/display/simview.cc000066400000000000000000000520451474050137200220340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "simview.h" #include "simgraph.h" #include "viewport.h" #include "../simticker.h" #include "../simdebug.h" #include "../obj/simobj.h" #include "../simconst.h" #include "../world/simplan.h" #include "../tool/simmenu.h" #include "../player/simplay.h" #include "../descriptor/ground_desc.h" #include "../ground/wasser.h" #include "../dataobj/environment.h" #include "../obj/zeiger.h" #include "../utils/simrandom.h" uint16 win_get_statusbar_height(); // simwin.h main_view_t::main_view_t(karte_t *welt) { this->welt = welt; outside_visible = true; viewport = welt->get_viewport(); assert(welt && viewport); } #if COLOUR_DEPTH != 0 static const sint8 hours2night[] = { 4,4,4,4,4,4,4,4, 4,4,4,4,3,2,1,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1, 2,3,4,4,4,4,4,4 }; #endif #ifdef MULTI_THREAD #include "../utils/simthread.h" bool spawned_threads=false; // global job indicator array static simthread_barrier_t display_barrier_start; static simthread_barrier_t display_barrier_end; // to start a thread typedef struct{ main_view_t *show_routine; koord lt_cl, wh_cl; // pos/size of clipping rect for this thread koord lt, wh; // pos/size of region to display. set larger than clipping for correct display of trees at thread seams sint16 y_min; sint16 y_max; sint8 thread_num; } display_region_param_t; // now the parameters static display_region_param_t ka[MAX_THREADS]; void *display_region_thread( void *ptr ) { display_region_param_t *view = reinterpret_cast(ptr); while(true) { simthread_barrier_wait( &display_barrier_start ); // wait for all to start clear_all_poly_clip( view->thread_num ); display_set_clip_wh( view->lt_cl.x, view->lt_cl.y, view->wh_cl.x, view->wh_cl.y, view->thread_num ); view->show_routine->display_region( view->lt, view->wh, view->y_min, view->y_max, false, true, view->thread_num ); simthread_barrier_wait( &display_barrier_end ); // wait for all to finish } } /* The following mutex is only needed for smart cursor */ // mutex for changing settings on hiding buildings/trees static pthread_mutex_t hide_mutex = PTHREAD_MUTEX_INITIALIZER; static bool threads_req_pause = false; // set true to pause all threads to display smartcursor region single threaded static uint8 num_threads_paused = 0; // number of threads in the paused state static pthread_cond_t hiding_cond = PTHREAD_COND_INITIALIZER; static pthread_cond_t waiting_cond = PTHREAD_COND_INITIALIZER; #if COLOUR_DEPTH != 0 static bool can_multithreading = true; #endif #endif void main_view_t::display(bool force_dirty) { const uint32 rs = get_random_seed(); #if COLOUR_DEPTH != 0 DBG_DEBUG4("main_view_t::display", "starting ..."); display_set_image_proc(true); const sint16 disp_width = display_get_width(); const sint16 disp_real_height = display_get_height(); const sint16 IMG_SIZE = get_tile_raster_width(); const sint16 disp_height = display_get_height() - win_get_statusbar_height() - (!ticker::empty() ? TICKER_HEIGHT : 0); scr_rect clip_rr(0, env_t::iconsize.w, disp_width, disp_height - env_t::iconsize.h); switch (env_t::menupos) { case MENU_TOP: // rect default break; case MENU_BOTTOM: clip_rr.y = win_get_statusbar_height() + (!ticker::empty() ? TICKER_HEIGHT : 0); break; case MENU_LEFT: clip_rr = scr_rect(env_t::iconsize.w, 0, disp_width - env_t::iconsize.w, disp_height); break; case MENU_RIGHT: clip_rr = scr_rect(0, 0, disp_width - env_t::iconsize.w, disp_height); break; } display_set_clip_wh(clip_rr.x, clip_rr.y, clip_rr.w, clip_rr.h); // redraw everything? force_dirty = force_dirty || welt->is_dirty(); welt->unset_dirty(); if( force_dirty ) { mark_screen_dirty(); welt->set_background_dirty(); force_dirty = false; } const int dpy_width = display_get_width()/IMG_SIZE + 2; const int dpy_height = (disp_real_height*4)/IMG_SIZE; const int i_off = viewport->get_world_position().x + viewport->get_viewport_ij_offset().x; const int j_off = viewport->get_world_position().y + viewport->get_viewport_ij_offset().y; const int const_x_off = viewport->get_x_off(); const int const_y_off = viewport->get_y_off(); // change to night mode? // images will be recalculated only, when there has been a change, so we set always if(grund_t::underground_mode == grund_t::ugm_all) { display_day_night_shift(0); } else if(!env_t::night_shift) { display_day_night_shift(env_t::daynight_level); } else { // calculate also days if desired uint32 month = welt->get_last_month(); const uint32 ticks_this_month = welt->get_ticks() % welt->ticks_per_world_month; uint32 hours2; if (env_t::show_month > env_t::DATE_FMT_MONTH) { static sint32 days_per_month[12]={31,28,31,30,31,30,31,31,30,31,30,31}; hours2 = (((sint64)ticks_this_month*days_per_month[month]) >> (welt->ticks_per_world_month_shift-17)); hours2 = ((hours2*3) / 8192) % 48; } else { hours2 = ( (ticks_this_month * 3) >> (welt->ticks_per_world_month_shift-4) )%48; } display_day_night_shift(hours2night[hours2]+env_t::daynight_level); } // not very elegant, but works: // fill everything with black for Underground mode ... if( grund_t::underground_mode ) { display_fillbox_wh_rgb(clip_rr.x, clip_rr.y, clip_rr.w, clip_rr.h, color_idx_to_rgb(COL_BLACK), force_dirty); } else if( welt->is_background_dirty() && outside_visible ) { // we check if background will be visible, no need to clear screen if it's not. display_background(clip_rr.x, clip_rr.y, clip_rr.w, clip_rr.h, force_dirty); welt->unset_background_dirty(); // reset outside_visible = false; } // to save calls to grund_t::get_disp_height // gr->get_disp_height() == min(gr->get_hoehe(), hmax_ground) const sint8 hmax_ground = (grund_t::underground_mode==grund_t::ugm_level) ? grund_t::underground_level : 127; // lower limit for y: display correctly water/outside graphics at upper border of screen int y_min = (-const_y_off + 4*tile_raster_scale_y( min(hmax_ground, welt->min_height)*TILE_HEIGHT_STEP, IMG_SIZE ) + 4*(clip_rr.y-IMG_SIZE)-IMG_SIZE/2-1) / IMG_SIZE; // prepare view rect_t const world_rect(koord(0, 0), welt->get_size()); koord const estimated_min(((y_min+(-2-((y_min+dpy_width) & 1))) >> 1) + i_off, ((y_min-(clip_rr.w - const_x_off) / (IMG_SIZE/2) - 1) >> 1) + j_off); sint16 const worst_case_mountain_extra = (welt->max_height - welt->min_height) / 2; koord const estimated_max((((dpy_height+4*4)+(disp_width - const_x_off) / (IMG_SIZE/2) - 1) >> 1) + i_off + worst_case_mountain_extra, (((dpy_height+4*4)-(-2-(((dpy_height+4*4)+dpy_width) & 1))) >> 1) + j_off + worst_case_mountain_extra); rect_t view_rect(estimated_min, estimated_max - estimated_min + koord(1, 1)); view_rect.mask(world_rect); if (view_rect != viewport->prepared_rect) { welt->prepare_tiles(view_rect, viewport->prepared_rect); viewport->prepared_rect = view_rect; } #ifdef MULTI_THREAD if( can_multithreading ) { if( !spawned_threads ) { // we can do the parallel display using posix threads ... pthread_t thread[MAX_THREADS]; /* Initialize and set thread detached attribute */ pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); // init barrier simthread_barrier_init( &display_barrier_start, NULL, env_t::num_threads ); simthread_barrier_init( &display_barrier_end, NULL, env_t::num_threads ); for( int t = 0; t < env_t::num_threads - 1; t++ ) { if( pthread_create( &thread[t], &attr, display_region_thread, (void *)&ka[t] ) ) { can_multithreading = false; dbg->error( "main_view_t::display()", "cannot multi-thread, error at thread #%i", t+1 ); return; } } spawned_threads = true; pthread_attr_destroy( &attr ); } // set parameter for each thread const scr_coord_val wh_x = clip_rr.w / env_t::num_threads; scr_coord_val lt_x = clip_rr.x; for( int t = 0; t < env_t::num_threads - 1; t++ ) { ka[t].show_routine = this; ka[t].lt_cl = koord( lt_x, clip_rr.y ); ka[t].wh_cl = koord( wh_x, clip_rr.h ); ka[t].lt = ka[t].lt_cl - koord( IMG_SIZE/2, 0 ); // process tiles IMG_SIZE/2 outside clipping range for correct tree display at thread seams ka[t].wh = ka[t].wh_cl + koord( IMG_SIZE, 0 ); ka[t].y_min = y_min; ka[t].y_max = dpy_height + 4 * 4; ka[t].thread_num = t; lt_x += wh_x; } // init variables required to draw smart cursor threads_req_pause = false; num_threads_paused = 0; // and start drawing simthread_barrier_wait( &display_barrier_start ); // the last we can run ourselves, setting clip_wh to the screen edge instead of wh_x (in case disp_width % num_threads != 0) clear_all_poly_clip( env_t::num_threads - 1 ); display_set_clip_wh( lt_x, clip_rr.y, clip_rr.w, clip_rr.h, env_t::num_threads - 1 ); display_region( koord( lt_x - IMG_SIZE / 2, clip_rr.y ), koord( clip_rr.x + clip_rr.w + IMG_SIZE, clip_rr.h ), y_min, dpy_height + 4 * 4, false, true, env_t::num_threads - 1 ); simthread_barrier_wait( &display_barrier_end ); clear_all_poly_clip( 0 ); display_set_clip_wh(clip_rr.x, clip_rr.y, clip_rr.w, clip_rr.h); } else { // slow serial way of display clear_all_poly_clip( 0 ); display_region( koord(clip_rr.x, clip_rr.y), koord(clip_rr.w, clip_rr.h), y_min, dpy_height + 4 * 4, false, false, 0 ); } #else clear_all_poly_clip(); display_region(koord(clip_rr.x, clip_rr.y), koord(clip_rr.w, clip_rr.h), y_min, dpy_height + 4 * 4, false ); #endif // and finally overlays (station coverage and signs) bool plotted = false; // display overlays even on very large mountains for(sint16 y=y_min; y> 1) + i_off; const sint16 j = ((y - x) >> 1) + j_off; const sint16 xpos = x * (IMG_SIZE / 2) + const_x_off; if( xpos+IMG_SIZE>0 ) { const planquadrat_t *plan=welt->access(i,j); if(plan && plan->get_kartenboden()) { const grund_t *gr = plan->get_kartenboden(); sint16 yypos = ypos - tile_raster_scale_y( min(gr->get_hoehe(),hmax_ground)*TILE_HEIGHT_STEP, IMG_SIZE); if( yypos-IMG_SIZE < clip_rr.get_bottom() && yypos+IMG_SIZE>=clip_rr.y ) { plan->display_overlay( xpos, yypos ); plotted = true; } } } } } obj_t *zeiger = welt->get_zeiger(); DBG_DEBUG4("main_view_t::display", "display pointer"); if( zeiger && zeiger->get_pos() != koord3d::invalid ) { bool dirty = zeiger->get_flag(obj_t::dirty); scr_coord background_pos = viewport->get_screen_coord(zeiger->get_pos()); scr_coord pointer_pos = background_pos + viewport->scale_offset(koord(zeiger->get_xoff(),zeiger->get_yoff())); // mark the cursor position for all tools (except lower/raise) if(zeiger->get_yoff()==Z_PLAN) { grund_t *gr = welt->lookup( zeiger->get_pos() ); if(gr && gr->is_visible()) { const FLAGGED_PIXVAL transparent = TRANSPARENT25_FLAG|OUTLINE_FLAG| env_t::cursor_overlay_color; if( gr->get_image()==IMG_EMPTY ) { if( gr->hat_wege() ) { display_img_blend( gr->obj_bei(0)->get_image(), background_pos.x, background_pos.y, transparent, 0, dirty ); } else { display_img_blend( ground_desc_t::get_ground_tile(gr), background_pos.x, background_pos.y, transparent, 0, dirty ); } } else if( gr->get_typ()==grund_t::wasser ) { display_img_blend( ground_desc_t::sea->get_image(gr->get_image(),wasser_t::stage), background_pos.x, background_pos.y, transparent, 0, dirty ); } else { display_img_blend( gr->get_image(), background_pos.x, background_pos.y, transparent, 0, dirty ); } } } zeiger->display( pointer_pos.x , pointer_pos.y CLIP_NUM_DEFAULT); zeiger->clear_flag( obj_t::dirty ); } if(welt) { // show players income/cost messages switch (env_t::show_money_message) { case 0: // show messages of all players for(int x=0; xget_player(x) ) { welt->get_player(x)->display_messages(); } } break; case 1: // show message of active player if (welt->get_active_player()) { welt->get_active_player()->display_messages(); } break; default: // no messages break; } } assert( rs == get_random_seed() ); (void)rs; #else (void)force_dirty; (void)rs; #endif } void main_view_t::clear_prepared() const { viewport->prepared_rect.discard_area(); } #ifdef MULTI_THREAD void main_view_t::display_region( koord lt, koord wh, sint16 y_min, sint16 y_max, bool /*force_dirty*/, bool threaded, const sint8 clip_num ) #else void main_view_t::display_region( koord lt, koord wh, sint16 y_min, sint16 y_max, bool /*force_dirty*/ ) #endif { const sint16 IMG_SIZE = get_tile_raster_width(); const int i_off = viewport->get_world_position().x + viewport->get_viewport_ij_offset().x; const int j_off = viewport->get_world_position().y + viewport->get_viewport_ij_offset().y; const int const_x_off = viewport->get_x_off(); const int const_y_off = viewport->get_y_off(); const int dpy_width = display_get_width() / IMG_SIZE + 2; // to save calls to grund_t::get_disp_height const sint8 hmax_ground = (grund_t::underground_mode == grund_t::ugm_level) ? grund_t::underground_level : 127; // prepare for selectively display const koord cursor_pos = welt->get_zeiger() ? welt->get_zeiger()->get_pos().get_2d() : koord(-1000, -1000); const bool needs_hiding = !env_t::hide_trees || (env_t::hide_buildings != env_t::ALL_HIDDEN_BUILDING); for( int y = y_min; y < y_max; y++ ) { const sint16 ypos = y * (IMG_SIZE / 4) + const_y_off; // plotted = we plotted something bool plotted = false; for( sint16 x = -2 - ((y +dpy_width) & 1); (x * (IMG_SIZE / 2) + const_x_off) < (lt.x + wh.x); x += 2 ) { const sint16 i = ((y + x) >> 1) + i_off; const sint16 j = ((y - x) >> 1) + j_off; const sint16 xpos = x * (IMG_SIZE / 2) + const_x_off; if( xpos + IMG_SIZE > lt.x ) { const koord pos(i, j); if( grund_t* const kb = welt->lookup_kartenboden(pos) ) { const sint16 yypos = ypos - tile_raster_scale_y( min( kb->get_hoehe(), hmax_ground ) * TILE_HEIGHT_STEP, IMG_SIZE ); if( yypos - IMG_SIZE < lt.y + wh.y && yypos + IMG_SIZE > lt.y ) { #ifdef MULTI_THREAD bool force_show_grid = false; if( env_t::hide_under_cursor ) { const uint32 cursor_dist = shortest_distance( pos, cursor_pos ); if( cursor_dist <= env_t::cursor_hide_range + 2u ) { // +2 to allow for rapid diagonal movement kb->set_flag( grund_t::dirty ); if( cursor_dist <= env_t::cursor_hide_range ) { force_show_grid = true; } } } kb->display_if_visible( xpos, yypos, IMG_SIZE, clip_num, force_show_grid ); #else if( env_t::hide_under_cursor ) { const bool saved_grid = grund_t::show_grid; const uint32 cursor_dist = shortest_distance( pos, cursor_pos ); if( cursor_dist <= env_t::cursor_hide_range + 2u ) { kb->set_flag( grund_t::dirty ); if( cursor_dist <= env_t::cursor_hide_range ) { grund_t::show_grid = true; } } kb->display_if_visible( xpos, yypos, IMG_SIZE ); grund_t::show_grid = saved_grid; } else { kb->display_if_visible( xpos, yypos, IMG_SIZE ); } #endif plotted = true; } // not on screen? We still might need to plot the border ... else if( env_t::draw_earth_border && (pos.x-welt->get_size().x+1 == 0 || pos.y-welt->get_size().y+1 == 0) ) { kb->display_border( xpos, yypos, IMG_SIZE CLIP_NUM_PAR); } } else { // check if outside visible outside_visible = true; if( env_t::draw_outside_tile ) { const sint16 yypos = ypos - tile_raster_scale_y( welt->min_height * TILE_HEIGHT_STEP, IMG_SIZE ); display_normal( ground_desc_t::outside->get_image(0), xpos, yypos, 0, true, false CLIP_NUM_PAR); } } } } // increase lower bound if nothing is visible if( !plotted ) { if (y == y_min) { y_min++; } } // increase upper bound if something is visible else { if (y == y_max-1) { y_max++; } } } // and then things (and other ground) // especially necessary for vehicles for( int y = y_min; y < y_max; y++ ) { const sint16 ypos = y * (IMG_SIZE / 4) + const_y_off; for( sint16 x = -2 - ((y + dpy_width) & 1); (x * (IMG_SIZE / 2) + const_x_off) < (lt.x + wh.x); x += 2 ) { const int i = ((y + x) >> 1) + i_off; const int j = ((y - x) >> 1) + j_off; const int xpos = x * (IMG_SIZE / 2) + const_x_off; if( xpos + IMG_SIZE > lt.x ) { const planquadrat_t *plan = welt->access(i,j); if( plan && plan->get_kartenboden() ) { const grund_t *gr = plan->get_kartenboden(); // minimum height: ground height for overground, // for the definition of underground_level see grund_t::set_underground_mode const sint8 hmin = min( gr->get_hoehe(), grund_t::underground_level ); // maximum height: 127 for overground, underground level for sliced, ground height-1 for complete underground view const sint8 hmax = grund_t::underground_mode == grund_t::ugm_all ? gr->get_hoehe() - (!gr->ist_tunnel()) : grund_t::underground_level; /* long version switch(grund_t::underground_mode) { case ugm_all: hmin = -128; hmax = gr->get_hoehe()-(!gr->ist_tunnel()); underground_level = -128; break; case ugm_level: hmin = min(gr->get_hoehe(), underground_level); hmax = underground_level; underground_level = level; break; case ugm_none: hmin = gr->get_hoehe(); hmax = 127; underground_level = 127; } */ sint16 yypos = ypos - tile_raster_scale_y( min( gr->get_hoehe(), hmax_ground ) * TILE_HEIGHT_STEP, IMG_SIZE ); if( yypos - IMG_SIZE * 3 < wh.y + lt.y && yypos + IMG_SIZE > lt.y ) { const koord pos(i,j); if( env_t::hide_under_cursor && needs_hiding ) { // If the corresponding setting is on, then hide trees and buildings under mouse cursor #ifdef MULTI_THREAD if( threaded ) { pthread_mutex_lock( &hide_mutex ); if( threads_req_pause ) { // another thread is requesting we pause num_threads_paused++; pthread_cond_broadcast( &waiting_cond ); // signal the requesting thread that another thread has paused // wait until no longer requested to pause while( threads_req_pause ) { pthread_cond_wait( &hiding_cond, &hide_mutex ); } num_threads_paused--; } if( shortest_distance( pos, cursor_pos ) <= env_t::cursor_hide_range ) { // wait until all threads are paused threads_req_pause = true; while( num_threads_paused < env_t::num_threads - 1 ) { pthread_cond_wait( &waiting_cond, &hide_mutex ); } // proceed with drawing in the hidden area singlethreaded const bool saved_hide_trees = env_t::hide_trees; const uint8 saved_hide_buildings = env_t::hide_buildings; env_t::hide_trees = true; env_t::hide_buildings = env_t::ALL_HIDDEN_BUILDING; plan->display_obj( xpos, yypos, IMG_SIZE, true, hmin, hmax, clip_num ); env_t::hide_trees = saved_hide_trees; env_t::hide_buildings = saved_hide_buildings; // unpause all threads threads_req_pause = false; pthread_cond_broadcast( &hiding_cond ); pthread_mutex_unlock( &hide_mutex ); } else { // not in the hidden area, draw multithreaded pthread_mutex_unlock( &hide_mutex ); plan->display_obj( xpos, yypos, IMG_SIZE, true, hmin, hmax, clip_num ); } } else { #endif if( shortest_distance( pos, cursor_pos ) <= env_t::cursor_hide_range ) { const bool saved_hide_trees = env_t::hide_trees; const uint8 saved_hide_buildings = env_t::hide_buildings; env_t::hide_trees = true; env_t::hide_buildings = env_t::ALL_HIDDEN_BUILDING; plan->display_obj( xpos, yypos, IMG_SIZE, true, hmin, hmax CLIP_NUM_PAR); env_t::hide_trees = saved_hide_trees; env_t::hide_buildings = saved_hide_buildings; } else { plan->display_obj( xpos, yypos, IMG_SIZE, true, hmin, hmax CLIP_NUM_PAR); } #ifdef MULTI_THREAD } #endif } else { // hiding turned off, draw multithreaded plan->display_obj( xpos, yypos, IMG_SIZE, true, hmin, hmax CLIP_NUM_PAR); } } } } } } #ifdef MULTI_THREAD // show thread as paused when finished if( threaded ) { pthread_mutex_lock( &hide_mutex ); num_threads_paused++; pthread_cond_broadcast( &waiting_cond ); pthread_mutex_unlock( &hide_mutex ); } #endif } void main_view_t::display_background( scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, bool dirty ) { if( !(env_t::draw_earth_border && env_t::draw_outside_tile) ) { display_fillbox_wh_rgb(xp, yp, w, h, env_t::background_color, dirty ); } } simutrans-124.3/src/simutrans/display/simview.h000066400000000000000000000062101474050137200216670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_SIMVIEW_H #define DISPLAY_SIMVIEW_H #include "simgraph.h" class karte_t; class viewport_t; /** * World view class, it contains the routines that handle world display to the pixel buffer. * @brief View for the simulated world. */ class main_view_t { private: /// The simulated world this view is associated to. karte_t *welt; /// We cache the camera here, it's the camera what we are supposed to render, not the whole world. viewport_t *viewport; /// Cached value from last display run to determine if the background was visible, we'll save redraws if it was not. bool outside_visible; public: main_view_t(karte_t *welt); /** * Draws the visible world on screen. * @param dirty If set to true, will mark the whole screen as dirty. * @see display_flush_buffer() for the consequences of setting screen areas dirty. */ void display(bool dirty); /** * @brief Clears the prepared area of the view. * * Sets the prepared area of this view to no area. The entire view will have * to be reprepared on next display call. Intended when the entire world has * changed, eg switching underground mode or layer. */ void clear_prepared() const; /** * Draws the simulated world in the specified rectangular area of the pixel buffer. This is a internal function of the class. *
* See lt and wt as the absolute limit a pixel this routine can draw, a clipping rectangle. y_min and y_max are the coordinates this routine starts, * locating and drawing objects. This mechanic is due to the fact objects are drawn in relation of their top-left pixel, and that coordinate might be outside * the clipping rectangle. Think of water tiles on the top of screen of high buildings that fall over the bottom of screen, but so high that their top has to * remain visible. * * @param lt Top-left pixel coordinate of the rectangle. In pixels. * @param wh Width and height f the rectangle. In pixels. * @param y_min Minimum height of the screen (top pixel row) to start processing objects to draw. * @param y_max Maximum height of the screen (bottom pixel row) to start processing objects to draw. * @param force_dirty If set to true, will mark the whole rectangle as dirty. * @param threaded If set to true, indicates there are more threads drawing on screen, and this routine will use mutexes when needed. */ #ifdef MULTI_THREAD void display_region( koord lt, koord wh, sint16 y_min, const sint16 y_max, bool force_dirty, bool threaded, const sint8 clip_num ); #else void display_region( koord lt, koord wh, sint16 y_min, const sint16 y_max, bool force_dirty ); #endif private: /** * Draws background in the specified rectangular screen coordinates. * @param xp X screen coordinate of the left-top corner. * @param yp Y screen coordinate y of the left-top corner. * @param w Width of the rectangle to draw. * @param h Height of the rectangle to draw. * @param dirty Mark the specified area as dirty. */ void display_background( scr_coord_val xp, scr_coord_val yp, scr_coord_val w, scr_coord_val h, bool dirty ); }; #endif simutrans-124.3/src/simutrans/display/viewport.cc000066400000000000000000000240531474050137200222260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "viewport.h" #include "simgraph.h" #include "../world/simworld.h" #include "../dataobj/environment.h" #include "../dataobj/koord3d.h" #include "../ground/grund.h" #include "../obj/zeiger.h" void viewport_t::set_viewport_ij_offset( const koord &k ) { view_ij_off=k; update_cached_values(); } koord viewport_t::get_map2d_coord( const koord3d &viewpos ) const { // just calculate the offset from the z-position const sint16 new_yoff = tile_raster_scale_y(viewpos.z*TILE_HEIGHT_STEP,cached_img_size); sint16 lines = 0; if(new_yoff>0) { lines = (new_yoff + (cached_img_size/4))/(cached_img_size/2); } else { lines = (new_yoff - (cached_img_size/4))/(cached_img_size/2); } return world->get_closest_coordinate( viewpos.get_2d() - koord( lines, lines ) ); } koord viewport_t::get_viewport_coord( const koord& coord ) const { return coord+cached_aggregated_off; } scr_coord viewport_t::get_screen_coord( const koord3d& pos, const koord& off) const { // Historic disheartening comment to be preserved: // better not try to twist your brain to follow the retransformation ... koord scr_pos_2d = get_viewport_coord(pos.get_2d()); const sint16 x = (scr_pos_2d.x-scr_pos_2d.y)*(cached_img_size/2) + tile_raster_scale_x(off.x, cached_img_size) + x_off; const sint16 y = (scr_pos_2d.x+scr_pos_2d.y)*(cached_img_size/4) + tile_raster_scale_y(off.y-pos.z*TILE_HEIGHT_STEP, cached_img_size) + ((cached_disp_width/cached_img_size)&1)*(cached_img_size/4) + y_off; return scr_coord(x,y); } scr_coord viewport_t::scale_offset( const koord &value ) { return scr_coord(tile_raster_scale_x( value.x, cached_img_size ), tile_raster_scale_y( value.x, cached_img_size )); } // change the center viewport position void viewport_t::change_world_position( koord new_ij, sint16 new_xoff, sint16 new_yoff ) { // truncate new_xoff, modify new_ij.x new_ij.x -= new_xoff/cached_img_size; new_ij.y += new_xoff/cached_img_size; new_xoff %= cached_img_size; // truncate new_yoff, modify new_ij.y int lines = 0; if(new_yoff>0) { lines = (new_yoff + (cached_img_size/4))/(cached_img_size/2); } else { lines = (new_yoff - (cached_img_size/4))/(cached_img_size/2); } new_ij -= koord( lines, lines ); new_yoff -= (cached_img_size/2)*lines; new_ij = world->get_closest_coordinate(new_ij); //position changed? => update and mark dirty if(new_ij!=ij_off || new_xoff!=x_off || new_yoff!=y_off) { ij_off = new_ij; x_off = new_xoff; y_off = new_yoff; world->set_dirty(); update_cached_values(); } } void viewport_t::switch_underground_mode(const koord3d& pos) { if (grund_t *gr = world->lookup(pos)) { if (!gr->is_visible()) { if (gr->ist_tunnel()) { // position is underground (and not visible), change to sliced mode grund_t::set_underground_mode(grund_t::ugm_level, gr->get_hoehe()); } else if (!gr->ist_karten_boden() || grund_t::underground_mode != grund_t::ugm_all) { // position is overground, change to normal view // but not if we are in full underground view and gr is kartenboden grund_t::set_underground_mode(grund_t::ugm_none, 0); } // make dirty etc world->update_underground(); } } } // change the center viewport position for a certain ground tile // any possible convoi to follow will be disabled void viewport_t::change_world_position( const koord3d& new_ij ) { follow_convoi = convoihandle_t(); switch_underground_mode(new_ij); change_world_position( get_map2d_coord( new_ij ) ); } void viewport_t::change_world_position(const koord3d& pos, const koord& off, scr_coord sc) { switch_underground_mode(pos); // see get_viewport_coord and update_cached_values koord scr_pos_2d = pos.get_2d() - view_ij_off; const sint16 c2 = cached_img_size/2; const sint16 c4 = cached_img_size/4; // see get_screen_coord - do not twist your brain etc // solve (-ijx + ijy)*(cached_img_size/2) + x_off = sc.x - xfix; // note: xfix and yfix need 32-bit precision or will overflow const sint32 xfix = (scr_pos_2d.x - scr_pos_2d.y)*(cached_img_size/2) + tile_raster_scale_x(off.x, cached_img_size); // solve (-ijx - ijy)*(cached_img_size/4) + y_off = sc.y - yfix; const sint32 yfix = (scr_pos_2d.x + scr_pos_2d.y)*(cached_img_size/4) + tile_raster_scale_y(off.y-pos.z*TILE_HEIGHT_STEP, cached_img_size) + ((cached_disp_width/cached_img_size)&1)*(cached_img_size/4); // calculate center position const sint16 new_ij_x = (-(c2*(sc.y - yfix ))/c4 - (sc.x - xfix) ) / (2*c2); const sint16 new_ij_y = (-(c2*(sc.y - yfix ))/c4 + (sc.x - xfix) ) / (2*c2); // set new offsets to solve equation const sint16 new_x_off = sc.x - xfix - (-new_ij_x + new_ij_y) * c2; const sint16 new_y_off = sc.y - yfix - (-new_ij_x - new_ij_y) * c4; change_world_position(koord(new_ij_x, new_ij_y), new_x_off, new_y_off); } grund_t* viewport_t::get_ground_on_screen_coordinate(scr_coord screen_pos, sint32 &found_i, sint32 &found_j, const bool intersect_grid) const { const int rw1 = cached_img_size; const int rw2 = rw1/2; const int rw4 = rw1/4; /* * berechnung der basis feldkoordinaten in i und j * this would calculate raster i,j koordinates if there was no height * die formeln stehen hier zur erinnerung wie sie in der urform aussehen int base_i = (screen_x+screen_y)/2; int base_j = (screen_y-screen_x)/2; int raster_base_i = (int)floor(base_i / 16.0); int raster_base_j = (int)floor(base_j / 16.0); */ screen_pos.y += - y_off - rw2 - ((cached_disp_width/rw1)&1)*rw4; screen_pos.x += - x_off - rw2; const int i_off = rw4*(ij_off.x+get_viewport_ij_offset().x); const int j_off = rw4*(ij_off.y+get_viewport_ij_offset().y); bool found = false; // uncomment to: ctrl-key selects ground //bool select_karten_boden = event_get_last_control_shift()==2; // fallback: take kartenboden if nothing else found grund_t *bd = NULL; grund_t *gr = NULL; // for the calculation of hmin/hmax see simview.cc // for the definition of underground_level see grund_t::set_underground_mode const sint8 hmin = grund_t::underground_mode != grund_t::ugm_all ? min( world->get_groundwater() - 4, grund_t::underground_level ) : world->get_min_allowed_height(); const sint8 hmax = grund_t::underground_mode == grund_t::ugm_all ? world->get_max_allowed_height() : min( grund_t::underground_level, world->get_max_allowed_height() ); // find matching and visible grund for(sint8 hgt = hmax; hgt>=hmin; hgt--) { const int base_i = (screen_pos.x/2 + screen_pos.y + tile_raster_scale_y((hgt*TILE_HEIGHT_STEP),rw1))/2; const int base_j = (screen_pos.y - screen_pos.x/2 + tile_raster_scale_y((hgt*TILE_HEIGHT_STEP),rw1))/2; found_i = (base_i + i_off) / rw4;; found_j = (base_j + j_off) / rw4;; gr = world->lookup(koord3d(found_i,found_j,hgt)); if (gr != NULL) { found = /*select_karten_boden ? gr->ist_karten_boden() :*/ gr->is_visible(); if( ( gr->get_typ() == grund_t::tunnelboden || gr->get_typ() == grund_t::monorailboden ) && gr->get_weg_nr(0) == NULL && !gr->get_leitung() && gr->find()) { // This is only a dummy ground placed by tool_build_tunnel_t or tool_build_way_t as a preview. found = false; } if (found) { break; } if (bd==NULL && gr->ist_karten_boden()) { bd = gr; } } if (grund_t::underground_mode==grund_t::ugm_level && hgt==hmax) { // fallback in sliced mode, if no ground is under cursor bd = world->lookup_kartenboden(found_i,found_j); } else if (intersect_grid){ // We try to intersect with virtual nonexistent border tiles in south and east. if( (gr = world->lookup_gridcoords( koord3d( found_i, found_j, hgt ) )) ){ found = true; break; } } // Last resort, try to intersect with the same tile +1 height, seems to be necessary on steep slopes // *NOTE* Don't do it on border tiles, since it will extend the range in which the cursor will be considered to be // inside world limits. if( found_i==(world->get_size().x-1) || found_j == (world->get_size().y-1) ) { continue; } gr = world->lookup(koord3d(found_i,found_j,hgt+1)); if(gr != NULL) { found = /*select_karten_boden ? gr->ist_karten_boden() :*/ gr->is_visible(); if( gr->is_dummy_ground() && gr->find()) { // This is only a dummy ground placed by tool_build_tunnel_t or tool_build_way_t as a preview. found = false; } if (found) { break; } if (bd==NULL && gr->ist_karten_boden()) { bd = gr; } } } if(found) { return gr; } else { if(bd!=NULL){ found_i = bd->get_pos().x; found_j = bd->get_pos().y; return bd; } return NULL; } } koord3d viewport_t::get_new_cursor_position( const scr_coord &screen_pos, bool grid_coordinates ) { const int rw4 = cached_img_size/4; int offset_y = 0; if(world->get_zeiger()->get_yoff() == Z_PLAN) { // already ok } else { // shifted by a quarter tile offset_y += rw4; } sint32 grid_x, grid_y; const grund_t *bd = get_ground_on_screen_coordinate(scr_coord(screen_pos.x, screen_pos.y + offset_y), grid_x, grid_y, grid_coordinates); // no suitable location found (outside map, ...) if (!bd) { return koord3d::invalid; } // offset needed for the raise / lower tool. sint8 groff = 0; if( bd->is_visible() && grid_coordinates) { groff = bd->get_hoehe(world->get_corner_to_operate(koord(grid_x, grid_y))) - bd->get_hoehe(); } return koord3d(grid_x, grid_y, bd->get_disp_height() + groff); } void viewport_t::metrics_updated() { cached_disp_width = display_get_width(); cached_disp_height = display_get_height(); cached_img_size = get_tile_raster_width(); set_viewport_ij_offset(koord( - cached_disp_width/(2*cached_img_size) - cached_disp_height/cached_img_size, cached_disp_width/(2*cached_img_size) - cached_disp_height/cached_img_size ) ); } void viewport_t::rotate90( sint16 y_size ) { ij_off.rotate90(y_size); update_cached_values(); } viewport_t::viewport_t( karte_t *world, const koord ij_off , sint16 x_off , sint16 y_off ) : prepared_rect() { this->world = world; assert(world); follow_convoi = convoihandle_t(); this->ij_off = ij_off; this->x_off = x_off; this->y_off = y_off; metrics_updated(); } simutrans-124.3/src/simutrans/display/viewport.h000066400000000000000000000203511474050137200220650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef DISPLAY_VIEWPORT_H #define DISPLAY_VIEWPORT_H #include "../simtypes.h" #include "scr_coord.h" #include "../dataobj/koord.h" #include "../dataobj/koord3d.h" #include "../dataobj/rect.h" #include "../convoihandle.h" class karte_t; class grund_t; /** * @brief Map viewing camera. * Describes a camera, looking at our world. Contains various routines to handle the coordinates conversion. * * We handle four level of coordinates, described here: * - map_coord: It's a three dimensional coordinate, located in the simulated world. Implemented with koord3d, most game objects are positioned like this. * - map2d_coord: Two-dimensional coordinate, located in the simulated world, they are assumed z=0. Implemented with koord. * - viewport_coord: Two-dimensional coordinate, with our camera transformations applied, where 0,0 is the center of screen. * - screen_coord: Final transformation, exact coordinate on the output frame buffer. * * Diagram of a viewport screen, each viewport_coord corresponds to one of the diamonds: * -------------------- * |\/\/\/\/\/\/\/\/\/| * |/\/\/\/\/\/\/\/\/\| * |\/\/\/\/\/\/\/\/\/| * |/\/\/\/\/\/\/\/\/\| * |\/\/\/\/\/\/\/\/\/| * |/\/\/\/\/\/\/\/\/\| * |\/\/\/\/\/\/\/\/\/| * -------------------- */ class viewport_t { public: /** * @brief The prepared area of the view port. * * The area that has already been prepared for this view port. When the view * port is moved then only the new area not already prepared will be * prepared. If the view port is stationary no area will be prepared. */ rect_t prepared_rect; private: /// The simulated world this view is associated to. karte_t *world; /** * @name Camera position * This variables are related to the view camera position. * @{ */ /** * Current view position, expressed in 2D map coordinates. * @see x_off * @see y_off */ koord ij_off; sint16 x_off; //!< Fine scrolling x offset. Units in pixels. sint16 y_off; //!< Fine scrolling y offset. Units in pixels. /** * This is the current offset for getting from tile to screen. * @note Extra offset, if added to ij_off it will give us the 2D coordinate of the tile on the *BOTTOM-RIGHT* of screen. */ koord view_ij_off; /** * For performance reasons, we cache ( (0,0)-ij_off-view_ij_off ) here */ koord cached_aggregated_off; /** * @} */ sint16 cached_disp_width; ///< Cached window width sint16 cached_disp_height; ///< Cached window height sint16 cached_img_size; ///< Cached base raster image size /** * Sets current ij offsets of this viewport, depends of its proportions and the zoom level. */ void set_viewport_ij_offset( const koord &k ); /** * The current convoi to follow. */ convoihandle_t follow_convoi; /** * Converts map_coord to map2d_coord actually used for main view. */ koord get_map2d_coord( const koord3d& ) const; /** * Returns the viewport_coord coordinates of the requested map2d_coord coordinate. */ koord get_viewport_coord( const koord& coord ) const; /** * Updates the transformation vector we have cached. */ void update_cached_values() { cached_aggregated_off = -ij_off-view_ij_off; } public: /** * @name Coordinate transformations. * This methods handle the projection from the map coordinates, to 2D, screen coordinates. * @{ */ /** * Takes a in-game 3D coordinates and returns which coordinate in screen corresponds to it. * @param pos 3D in-map coordinate. * @param off offset to add to the final coordinates, in pixels (will be scaled to zoom level). */ scr_coord get_screen_coord( const koord3d& pos, const koord& off = koord(0,0) ) const; /** * Scales the 2D dimensions, expressed on base raster size pixels, to the current viewport. */ scr_coord scale_offset(const koord &value); /** * Checks a 3d in-map coordinate, to know if it's centered on the current viewport. * @param pos 3D map coordinate to check. * @return true if the requested map coordinates are on the center of the viewport, false otherwise. */ bool is_on_center(const koord3d &pos) const { return ( (get_x_off() | get_y_off()) == 0 && get_world_position() == get_map2d_coord( pos ) ); } /** * @} */ /** * @name Camera position * This methods are related to the view camera position. * @{ */ /** * Viewpoint in tile coordinates. i,j coordinate of the tile in center of screen. */ koord get_world_position() const { return ij_off; } /** * Offset from tile on center to tile in top-left corner of screen. */ koord get_viewport_ij_offset() const { return view_ij_off; } /** * Set center viewport position. */ void change_world_position( koord ij, sint16 x=0, sint16 y=0 ); /** * Set center viewport position, taking height into account. * Possibly switches underground mode. */ void change_world_position( const koord3d& ij ); /** * Set center viewport position, placing a in-game koord3d under the desired screen position. * Possibly switches underground mode. * @param pos map position to consider. * @param off extra offset. * @param sc screen position "pos" should be under. */ void change_world_position(const koord3d& pos, const koord& off, scr_coord sc); /** * Switch underground mode if target position @p pos is not visible. */ void switch_underground_mode(const koord3d& pos); /** * Fine offset within the viewport tile. */ int get_x_off() const {return x_off;} /** * Fine offset within the viewport tile. */ void set_x_off(sint16 value) {x_off = value;} /** * Fine offset within the viewport tile. */ int get_y_off() const {return y_off;} /** * Fine offset within the viewport tile. */ void set_y_off(sint16 value) {y_off = value;} /** * @} */ /** * @name Ray tracing * This methods are related to the act of finding a in-map entity, given a screen_cord. Used for player interaction, mainly. * @{ */ /** * Searches for the ground_t that's under the requested screen position. * @param screen_pos Screen coordinates to check for. * @param intersect_grid Special case for the lower/raise tool, will return a limit border tile if we are on the south/east border of screen. * @param found_i out parameter, i-coordinate of the found tile. It's necessary because it might point to a grid position that doesn't map to a real in-map coordinate, on border tiles (south and east border). * @param found_j out parameter, j-coordinate of the found tile. It's necessary because it might point to a grid position that doesn't map to a real in-map coordinate, on border tiles (south and east border). * @return the grund_t that's under the desired screen coordinate. NULL if we are outside map or we can't find it. */ grund_t* get_ground_on_screen_coordinate(scr_coord screen_pos, sint32 &found_i, sint32 &found_j, const bool intersect_grid=false) const; /** * Gets a new world position, under the requested screen coordinates. Used to move the cursor. * @param screen_pos Screen position to check. Input parameter. * @param grid_coordinates indicates if this function is to check against the map tiles, or the grid of heights. Input parameter. * @return koord3d::invalid if no position exists under the requested coordinate, a 3d koord directly under it otherwise. */ koord3d get_new_cursor_position(const scr_coord &screen_pos, bool grid_coordinates); /** * @} */ /** * @name Convoi following * This methods are related to the mechanics of a viewport follow a vehicle. * @{ */ /** * Function for following a convoi on the map give an unbound handle to unset. */ void set_follow_convoi(convoihandle_t cnv) { follow_convoi = cnv; } /** * Returns the convoi this viewport is following (if any). */ convoihandle_t get_follow_convoi() const { return follow_convoi; } /** * @} */ /** * This class caches the viewport dimensions, and the base image size. On zoom or viewport resize, call this * method to force its recalculation. */ void metrics_updated(); /** * (A better description is needed here) * Operations needed on map rotation. */ void rotate90( sint16 y_size ); viewport_t( karte_t *world, const koord ij_off = koord::invalid, sint16 x_off = 0, sint16 y_off = 0 ); }; #endif simutrans-124.3/src/simutrans/freight_list_sorter.cc000066400000000000000000000203511474050137200227600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "freight_list_sorter.h" #include "simhalt.h" #include "simtypes.h" #include "simware.h" #include "simfab.h" #include "simmem.h" #include "world/simworld.h" #include "dataobj/translator.h" #include "tpl/slist_tpl.h" #include "tpl/vector_tpl.h" #include "utils/cbuffer.h" karte_ptr_t freight_list_sorter_t::welt; freight_list_sorter_t::sort_mode_t freight_list_sorter_t::sortby=by_name; /** * @return whether w1 is less than w2 */ bool freight_list_sorter_t::compare_ware(ware_t const& w1, ware_t const& w2) { // sort according to freight // if w1 and w2 differ, they are sorted according to catg_index and index // we sort with respect to catg_indexfirst, since freights with the same category // will be displayed together int idx = w1.get_desc()->get_catg_index() - w2.get_desc()->get_catg_index(); if( idx == 0 ) { idx = w1.get_desc()->get_index() - w2.get_desc()->get_index(); } if( idx != 0 ) { return idx < 0; } switch (sortby) { default: dbg->error("freight_list_sorter::compare_ware()", "illegal sort mode!"); /* FALLTHROUGH */ case by_via_sum: case by_amount: { // sort by ware amount int const order = w2.amount - w1.amount; if( order != 0 ) { return order < 0; } } /* FALLTHROUGH */ case by_via: { // sort by via_destination name halthandle_t const v1 = w1.get_via_halt(); halthandle_t const v2 = w2.get_via_halt(); if( v1.is_bound() && v2.is_bound() ) { int const order = strcmp(v1->get_name(), v2->get_name()); if( order != 0) return order < 0; } else if( v1.is_bound() ) { return false; } else if( v2.is_bound() ) { return true; } } /* FALLTHROUGH */ case by_name: { // sort by destination name halthandle_t const d1 = w1.get_target_halt(); halthandle_t const d2 = w2.get_target_halt(); if( d1.is_bound() && d2.is_bound() ) { const fabrik_t *fab = NULL; const char *const name1 = ( w1.to_factory ? ( (fab=fabrik_t::get_fab(w1.get_target_pos())) ? fab->get_name() : "Invalid Factory" ) : d1->get_name() ); const char *const name2 = ( w2.to_factory ? ( (fab=fabrik_t::get_fab(w2.get_target_pos())) ? fab->get_name() : "Invalid Factory" ) : d2->get_name() ); return strcmp(name1, name2) < 0; } else if( d1.is_bound() ) { return false; } else if( d2.is_bound() ) { return true; } } } return false; } void freight_list_sorter_t::add_ware_heading( cbuffer_t &buf, uint64 sum, uint32 max, const ware_t *ware, const char *what_doing ) { uint32 const max_display = ~0; // not the first line? if( buf.len() > 0 ) { buf.append("\n"); } if (sum > max_display) { buf.printf(">%u", max_display); } else { buf.printf("%u", (uint32)sum); } if( max != 0 ) { // convois buf.printf("/%u", max); } goods_desc_t const& desc = *ware->get_desc(); char const* const unit = translator::translate(desc.get_mass()); // special freight (catg == 0) needs own name char const* const name = translator::translate(ware->get_catg() != 0 ? desc.get_catg_name() : desc.get_name()); char const* const what = translator::translate(what_doing); buf.printf("%s %s %s\n", unit, name, what); } void freight_list_sorter_t::sort_freight(vector_tpl const& warray, cbuffer_t& buf, sort_mode_t sort_mode, const slist_tpl* full_list, const char* what_doing) { sortby = sort_mode; // added sorting to ware's destination list int pos = 0; ware_t* wlist = MALLOCN( ware_t, warray.get_count() ); // track any lost good amounts during packet merger // only created when needed uint64* categories_goods_amount_lost = NULL; for(ware_t const& ware : warray) { if( ware.get_desc() == goods_manager_t::none || ware.amount == 0 ) { continue; } wlist[pos] = ware; if( sort_mode == by_via_sum ) { // via sort mode merges packets with a common next stop for( int i=0; i 0 ) { // reached goods amount limit, have to discard amount and track category totals separatly if( categories_goods_amount_lost == NULL ) { categories_goods_amount_lost = new uint64[256](); // this should be tied to a category index limit constant } categories_goods_amount_lost[wi.get_desc()->get_catg_index()]+= remaining_amount; } --pos; break; } } } pos++; } // if there, give the capacity for each freight slist_tpl const dummy; slist_tpl const& list = full_list ? *full_list : dummy; slist_tpl::const_iterator full_i = list.begin(); slist_tpl::const_iterator const full_end = list.end(); // at least some capacity added? if( pos != 0 ) { // sort the ware's list std::sort( wlist, wlist + pos, compare_ware ); // print the ware's list to buffer int last_goods_index = -1; int last_ware_catg = -1; for( int j = 0; j < pos; j++ ) { halthandle_t const halt = wlist[j].get_target_halt(); halthandle_t const via_halt = wlist[j].get_via_halt(); const char * name = "Error in Routing"; if( halt.is_bound() ) { name = halt->get_name(); } ware_t const& ware = wlist[j]; if( last_goods_index!=ware.get_index() && last_ware_catg!=ware.get_catg() ) { uint64 sum = categories_goods_amount_lost != NULL ? categories_goods_amount_lost[ware.get_desc()->get_catg_index()] : 0; last_goods_index = ware.get_index(); // special freight => handle different last_ware_catg = (ware.get_catg()!=0) ? ware.get_catg() : -1; for( int i=j; i=%u%s %s > " : " %u%s %s > "; buf.printf(good_description_format, ware.amount, translator::translate(desc.get_mass()), translator::translate(desc.get_name())); // the target name is not correct for the via sort const bool is_factory_going = ( sortby!=by_via_sum && ware.to_factory ); // exclude merged packets if( sortby!=by_via_sum || via_halt==halt ) { if( is_factory_going ) { const fabrik_t *const factory = fabrik_t::get_fab( ware.get_target_pos() ); buf.printf("%s <%i,%i>", (factory ? factory->get_name() : "Invalid Factory"), ware.get_target_pos().x, ware.get_target_pos().y); } else { buf.append(name); } } if( via_halt!=halt || is_factory_going ) { if( via_halt.is_bound() ) { buf.printf(translator::translate("via %s\n"), via_halt->get_name()); } else { if( sortby == by_via_sum ) { // do not show undecided transfer halts buf.append(name); } buf.append("\n"); } } else { buf.append("\n"); } // debug end } } if (categories_goods_amount_lost != NULL) { delete[] categories_goods_amount_lost; } // still entire left? for( ; full_i != full_end; ++full_i ) { ware_t const& g = *full_i; add_ware_heading(buf, 0, g.amount, &g, what_doing); } free( wlist ); } simutrans-124.3/src/simutrans/freight_list_sorter.h000066400000000000000000000016351474050137200226260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef FREIGHT_LIST_SORTER_H #define FREIGHT_LIST_SORTER_H // same sorting for stations and vehicle/convoi freight ... #include "simtypes.h" template class slist_tpl; template class vector_tpl; class ware_t; class cbuffer_t; class karte_ptr_t; class freight_list_sorter_t { public: enum sort_mode_t { by_name = 0, by_via = 1, by_via_sum = 2, by_amount = 3 }; static void sort_freight(vector_tpl const& warray, cbuffer_t& buf, sort_mode_t sort_mode, const slist_tpl* full_list, const char* what_doing); private: static karte_ptr_t welt; static sort_mode_t sortby; static bool compare_ware(ware_t const& w1, ware_t const& w2); static void add_ware_heading( cbuffer_t &buf, uint64 sum, uint32 max, const ware_t *ware, const char *what_doing ); }; #endif simutrans-124.3/src/simutrans/ground/000077500000000000000000000000001474050137200176655ustar00rootroot00000000000000simutrans-124.3/src/simutrans/ground/boden.cc000066400000000000000000000075431474050137200212740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../world/simworld.h" #include "../simskin.h" #include "../obj/baum.h" #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "boden.h" #include "../descriptor/ground_desc.h" #include "../descriptor/skin_desc.h" boden_t::boden_t(loadsave_t *file, koord pos ) : grund_t( koord3d(pos,0) ) { grund_t::rdwr( file ); // restoring trees (disadvantage: losing offsets but much smaller savegame footprint) if( file->is_version_atleast(110, 1) ) { sint16 id = file->rd_obj_id(); while( id!=-1 ) { if (id != (uint8)id) { dbg->warning("boden_t::boden_t", "Invalid tree id %hd, using %hhu", id, (uint8)id); } uint16 age; if (file->is_version_atleast(122, 2)) { file->rdwr_short(age); age &= 0xFFF; } else { sint32 val; file->rdwr_long(val); age = (uint32)val & 0xFFF; } // check if we still have this tree const tree_desc_t *desc = NULL; const char *desc_name = tree_builder_t::get_loaded_desc_name((uint8)id); if (desc_name) { desc = tree_builder_t::get_desc_by_name(desc_name); if (!desc) { desc = tree_builder_t::get_desc_by_name(translator::compatibility_name(desc_name)); } } else { desc = tree_builder_t::get_desc_by_id((uint8)id); } if (desc) { baum_t *tree = new baum_t( get_pos(), (uint8)id, age, slope ); objlist.add( tree ); } else { dbg->warning( "boden_t::boden_t()", "Could not restore tree type %hhu at (%s)", (uint8)id, pos.get_str() ); } // check for next tree id = file->rd_obj_id(); } } } boden_t::boden_t(koord3d pos, slope_t::type sl) : grund_t(pos) { slope = sl; } // only for more compact saving of trees void boden_t::rdwr(loadsave_t *file) { grund_t::rdwr(file); if( file->is_version_atleast(110, 1) ) { // a server sends the smallest possible savegames to clients, i.e. saves only types and age of trees if( (env_t::server || file->is_version_atleast(122, 2)) && !hat_wege() ) { for( uint8 i=0; iget_typ()==obj_t::baum ) { baum_t *tree = (baum_t *)obj; file->wr_obj_id( tree->get_desc_id() ); if (file->is_version_atleast(122, 2)) { uint16 age = tree->get_age(); file->rdwr_short( age ); } else { uint32 age = tree->get_age(); file->rdwr_long( age ); } } } } file->wr_obj_id( -1 ); } } const char *boden_t::get_name() const { if( ist_uebergang() ) { return "Kreuzung"; } else if( hat_wege() ) { return get_weg_nr(0)->get_name(); } else { return "Boden"; } } void boden_t::calc_image_internal(const bool calc_only_snowline_change) { const slope_t::type slope_this = get_disp_slope(); const weg_t *const weg = get_weg( road_wt ); if( weg && weg->hat_gehweg() ) { // single or double slope const uint8 imageid = (!slope_this || is_one_high(slope_this)) ? ground_desc_t::slopetable[slope_this] : ground_desc_t::slopetable[slope_this >> 1] + 12; if( (get_hoehe() >= welt->get_snowline() || welt->get_climate(pos.get_2d()) == arctic_climate) && skinverwaltung_t::fussweg->get_image_id(imageid + 1) != IMG_EMPTY ) { // snow images set_image( skinverwaltung_t::fussweg->get_image_id(imageid + 1) ); } else if( slope_this != 0 && get_hoehe() == welt->get_snowline() - 1 && skinverwaltung_t::fussweg->get_image_id(imageid + 2) != IMG_EMPTY ) { // transition images set_image( skinverwaltung_t::fussweg->get_image_id(imageid + 2) ); } else { set_image( skinverwaltung_t::fussweg->get_image_id(imageid) ); } } else { set_image( ground_desc_t::get_ground_tile(this) ); } if( !calc_only_snowline_change ) { grund_t::calc_back_image( get_disp_height(), slope_this ); } } simutrans-124.3/src/simutrans/ground/boden.h000066400000000000000000000015721474050137200211320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GROUND_BODEN_H #define GROUND_BODEN_H #include "grund.h" /** * boden_t are nature tiles (maybe with ways, powerlines, trees and beware: harbor buildings) */ class boden_t : public grund_t { protected: /// @copydoc grund_t::calc_image_internal void calc_image_internal(const bool calc_only_snowline_change) OVERRIDE; public: boden_t(loadsave_t *file, koord pos ); boden_t(koord3d pos, slope_t::type slope); public: /// @copydoc grund_t::rdwr void rdwr(loadsave_t *file) OVERRIDE; /// @copydoc grund_t::ist_natur inline bool ist_natur() const OVERRIDE { return !hat_wege() && !is_halt(); } /// @copydoc grund_t::get_name const char *get_name() const OVERRIDE; /// @copydoc grund_t::get_typ grund_t::typ get_typ() const OVERRIDE { return boden; } }; #endif simutrans-124.3/src/simutrans/ground/brueckenboden.cc000066400000000000000000000103631474050137200230050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../world/simworld.h" #include "../obj/bruecke.h" #include "../builder/brueckenbauer.h" #include "../descriptor/ground_desc.h" #include "../descriptor/bridge_desc.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../utils/cbuffer.h" #include "brueckenboden.h" #include "../obj/way/weg.h" #include "../vehicle/vehicle_base.h" brueckenboden_t::brueckenboden_t(koord3d pos, slope_t::type grund_hang, slope_t::type weg_hang) : grund_t(pos), weg_hang(weg_hang) { slope = grund_hang; } void brueckenboden_t::calc_image_internal(const bool calc_only_snowline_change) { if( ist_karten_boden() ) { set_image( ground_desc_t::get_ground_tile(this) ); if( !calc_only_snowline_change ) { grund_t::calc_back_image( get_pos().z, slope ); set_flag( draw_as_obj ); if( (get_grund_hang() == slope_t::west && abs(back_imageid) > 11) || (get_grund_hang() == slope_t::north && get_back_image(0) != IMG_EMPTY) ) { // must draw as obj, since there is a slop here nearby koord pos = get_pos().get_2d() + koord( get_grund_hang() ); grund_t *gr = welt->lookup_kartenboden( pos ); gr->set_flag( grund_t::draw_as_obj ); } } } else { clear_back_image(); set_image(IMG_EMPTY); } } void brueckenboden_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "brueckenboden_t" ); grund_t::rdwr(file); if(file->is_version_less(88, 9)) { uint8 sl; file->rdwr_byte(sl); slope = sl; } if( file->is_saving() && file->is_version_less(112, 7) ) { // truncate double weg_hang to single weg_hang, better than nothing uint8 sl = min( corner_sw(weg_hang), 1 ) + min( corner_se(weg_hang), 1 ) * 2 + min( corner_ne(weg_hang), 1 ) * 4 + min( corner_nw(weg_hang), 1 ) * 8; file->rdwr_byte(sl); } else { file->rdwr_byte(weg_hang); } if( file->is_loading() && file->is_version_less(112, 7) ) { // convert slopes from old single height saved game weg_hang = slope_from_slope4(slope4_t(weg_hang), env_t::pak_height_conversion_factor); } if(!find()) { dbg->error( "brueckenboden_t::rdwr()", "No bridge on bridge ground at (%s); try replacement", pos.get_str() ); weg_t *w = get_weg_nr(0); if(w) { const bridge_desc_t *br_desc = bridge_builder_t::find_bridge( w->get_waytype(), w->get_max_speed(), 0 ); if (!br_desc) { dbg->fatal("brueckenboden_t::rdwr", "No suitable bridge found for bridge ground at (%s)!", pos.get_str()); } const grund_t *kb = welt->lookup_kartenboden(get_pos().get_2d()); int height = 1; if( kb && get_pos().z - kb->get_pos().z > 1 ) { height = 2; } bruecke_t *br = new bruecke_t( get_pos(), welt->get_public_player(), br_desc, ist_karten_boden() ? br_desc->get_end( slope, get_grund_hang(), get_weg_hang() ) : br_desc->get_straight( w->get_ribi_unmasked(), height ) ); obj_add( br ); } } } void brueckenboden_t::rotate90() { if( sint8 way_offset = get_weg_yoff() ) { pos.rotate90( welt->get_size().y-1 ); slope = slope_t::rotate90( slope ); // since the y_off contains also the way height, we need to remove it before rotations and add it back afterwards for( uint8 i = 0; i < objlist.get_top(); i++ ) { obj_t * obj = obj_bei( i ); if( !dynamic_cast(obj) ) { obj->set_yoff( obj->get_yoff() + way_offset ); obj->rotate90(); obj->set_yoff( obj->get_yoff() - way_offset ); } else { // vehicle corrects its offset themselves obj->rotate90(); } } } else { weg_hang = slope_t::rotate90( weg_hang ); grund_t::rotate90(); } } sint8 brueckenboden_t::get_weg_yoff() const { if( ist_karten_boden() && weg_hang == 0 ) { // we want to find maximum height of slope corner shortcut as we know this is n, s, e or w and single heights are not integer multiples of 8 return TILE_HEIGHT_STEP * slope_t::max_diff(slope); } else { return 0; } } void brueckenboden_t::info(cbuffer_t & buf) const { const bruecke_t *bridge = find(); if(bridge && bridge->get_desc()) { const bridge_desc_t *desc = bridge->get_desc(); buf.append(translator::translate(desc->get_name())); buf.append("\n"); } grund_t::info(buf); } simutrans-124.3/src/simutrans/ground/brueckenboden.h000066400000000000000000000022321474050137200226430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GROUND_BRUECKENBODEN_H #define GROUND_BRUECKENBODEN_H #include "grund.h" class brueckenboden_t : public grund_t { private: slope_t::type weg_hang; ///< for e.g. ramps protected: /// @copydoc grund_t::calc_image_internal void calc_image_internal(const bool calc_only_snowline_change) OVERRIDE; public: brueckenboden_t(loadsave_t *file, koord pos ) : grund_t(koord3d(pos,0) ) { rdwr(file); } brueckenboden_t(koord3d pos, slope_t::type grund_hang, slope_t::type weg_hang); public: /// @copydoc grund_t::rdwr void rdwr(loadsave_t *file) OVERRIDE; /// @copydoc grund_t::rotate90 void rotate90() OVERRIDE; /// @copydoc grund_t::get_weg_yoff sint8 get_weg_yoff() const OVERRIDE; /// @copydoc grund_t::get_weg_hang slope_t::type get_weg_hang() const OVERRIDE { return weg_hang; } /// @copydoc grund_t::get_name const char *get_name() const OVERRIDE { return "Brueckenboden"; } /// @copydoc grund_t::get_typ typ get_typ() const OVERRIDE { return brueckenboden; } /// @copydoc grund_t::info void info(cbuffer_t & buf) const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/ground/fundament.cc000066400000000000000000000015121474050137200221540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simconst.h" #include "../descriptor/ground_desc.h" #include "../dataobj/loadsave.h" #include "grund.h" #include "fundament.h" fundament_t::fundament_t(loadsave_t *file, koord pos) : grund_t(koord3d(pos,0)) { rdwr(file); slope = slope_t::flat; } fundament_t::fundament_t(koord3d pos, slope_t::type hang) : grund_t(pos) { set_image( IMG_EMPTY ); if(hang != slope_t::flat) { pos = get_pos(); pos.z += slope_t::max_diff(hang); set_pos( pos ); } slope = slope_t::flat; } void fundament_t::calc_image_internal(const bool calc_only_snowline_change) { set_image( ground_desc_t::get_ground_tile(this) ); if( !calc_only_snowline_change ) { grund_t::calc_back_image( get_disp_height(), slope_t::flat ); } } simutrans-124.3/src/simutrans/ground/fundament.h000066400000000000000000000013271474050137200220220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GROUND_FUNDAMENT_H #define GROUND_FUNDAMENT_H #include "grund.h" /** * The foundation serves as base ground for all buildings in Simutrans. */ class fundament_t : public grund_t { protected: /// The foundation always has the same image. void calc_image_internal(const bool calc_only_snowline_change) OVERRIDE; public: fundament_t(loadsave_t *file, koord pos); fundament_t(koord3d pos, slope_t::type hang); public: /// @copydoc grund_t::get_name const char *get_name() const OVERRIDE { return "Fundament"; } /// @copydoc grund_t::get_typ typ get_typ() const OVERRIDE { return fundament; } }; #endif simutrans-124.3/src/simutrans/ground/grund.cc000066400000000000000000002216501474050137200213210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simcolor.h" #include "../simconst.h" #include "../simdebug.h" #include "../obj/depot.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../simhalt.h" #include "../display/simimg.h" #include "../player/simplay.h" #include "../gui/simwin.h" #include "../world/simworld.h" #include "../simfab.h" #include "../builder/wegbauer.h" #include "../descriptor/ground_desc.h" #include "../descriptor/building_desc.h" #include "../descriptor/crossing_desc.h" #include "../descriptor/tunnel_desc.h" #include "../descriptor/way_desc.h" #include "../dataobj/freelist.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../obj/baum.h" #include "../obj/bruecke.h" #include "../obj/crossing.h" #include "../obj/groundobj.h" #include "../obj/label.h" #include "../obj/leitung2.h" #include "../obj/roadsign.h" #include "../obj/signal.h" #include "../obj/tunnel.h" #include "../obj/wayobj.h" #include "../obj/zeiger.h" #include "../gui/ground_info.h" #include "../gui/minimap.h" #include "../tpl/inthashtable_tpl.h" #include "../utils/cbuffer.h" #include "../vehicle/pedestrian.h" #include "../obj/way/kanal.h" #include "../obj/way/maglev.h" #include "../obj/way/monorail.h" #include "../obj/way/narrowgauge.h" #include "../obj/way/runway.h" #include "../obj/way/schiene.h" #include "../obj/way/strasse.h" #include "../obj/way/weg.h" #include "fundament.h" #include "grund.h" #include "tunnelboden.h" #include "wasser.h" /** * Pointer to the world of this ground. Static to conserve space. * Change to instance variable once more than one world is available. */ karte_ptr_t grund_t::welt; volatile bool grund_t::show_grid = false; uint8 grund_t::offsets[4]={0,1,2/*illegal!*/,2}; sint8 grund_t::underground_level = 127; uint8 grund_t::underground_mode = ugm_none; // ---------------------- text handling from here ---------------------- /** * Table of ground texts */ static inthashtable_tpl ground_texts; #define get_ground_text_key(k) ( (uint64)(k).x + ((uint64)(k).y << 16) + ((uint64)(k).z << 32) ) // and the reverse operation #define get_ground_koord3d_key(key) koord3d( (key) & 0x00007FFF, ((key)>>16) & 0x00007fff, (sint8)((key)>>32) ) void grund_t::set_text(const char *text) { if (text==NULL && !get_flag(has_text)) { // no text to delete return; } const uint64 n = get_ground_text_key(pos); if( text ) { char *new_text = strdup(text); free(ground_texts.remove(n)); ground_texts.put(n, new_text); set_flag(has_text); } else if( get_flag(has_text) ) { char *txt=ground_texts.remove(n); free(txt); clear_flag(has_text); } set_flag(dirty); welt->set_dirty(); } const char *grund_t::get_text() const { const char *result = 0; if( get_flag(has_text) ) { result = ground_texts.get( get_ground_text_key(pos) ); if(result==NULL) { return "undef"; } assert(result); } return result; } const player_t* grund_t::get_label_owner() const { const player_t* player = NULL; // if this ground belongs to a halt, the color should reflect the halt owner, not the ground owner! // Now, we use the color of label_t owner if(is_halt() && find()==NULL) { // only halt label const halthandle_t halt = get_halt(); player=halt->get_owner(); } // else color according to current owner else if(obj_bei(0)) { player = obj_bei(0)->get_owner(); // for cityhall const label_t* l = find(); if(l) { player = l->get_owner(); } } return player; } // ---------------- init, rdwr, and destruct from here --------------------- void* grund_t::operator new(size_t s) { return freelist_t::gimme_node(s); } void grund_t::operator delete(void* p, size_t s) { return freelist_t::putback_node(s, p); } void grund_t::rdwr(loadsave_t *file) { koord k = pos.get_2d(); // water saves its correct height => no need to save grid heights anymore sint8 z = welt->lookup_hgt( k ); // save grid height for water tiles - including partial water tiles sint8 z_w = welt->get_water_hgt( k ); if( !(get_typ() == grund_t::boden || get_typ() == grund_t::wasser) || pos.z > z_w || z > z_w ) { z = pos.z; // all other tiles save ground height } planquadrat_t *plan = welt->access( k ); uint8 climate_data = plan->get_climate() + (plan->get_climate_corners() << 4); xml_tag_t g( file, "grund_t" ); if(file->is_version_less(101, 0)) { pos.rdwr(file); z_w = welt->get_groundwater(); } else if( file->is_version_less(112, 7) ) { file->rdwr_byte(z); pos.z = get_typ() == grund_t::wasser ? welt->get_groundwater() : z; z_w = welt->get_groundwater(); } else { file->rdwr_byte(z); file->rdwr_byte(z_w); if( file->is_loading() && !is_water() && !welt->lookup_kartenboden( k ) && z < z_w ) { // partially in water, restore correct ground height while keeping grid height // if kartenboden doesn't exist we will become it pos.z = z_w; } else if( file->is_loading() ) { pos.z = get_typ() == grund_t::wasser ? z_w : z; } file->rdwr_byte(climate_data); plan->set_climate((climate)(climate_data & 7)); plan->set_climate_corners((climate_data >> 4)); } if( file->is_loading() && file->is_version_less(112, 7) ) { // convert heights from old single height saved game - water already at correct height pos.z = get_typ() == grund_t::wasser ? pos.z : pos.z * env_t::pak_height_conversion_factor; z = z * env_t::pak_height_conversion_factor; } if(file->is_saving()) { const char *text = get_text(); file->rdwr_str(text); } else { const char *text = 0; file->rdwr_str(text); if(text) { set_text(text); free(const_cast(text)); } } if(file->is_version_less(99, 7)) { bool label; file->rdwr_bool(label); if(label) { objlist.add( new label_t(pos, welt->get_player(0), get_text() ) ); } } sint8 owner_n=-1; if(file->is_version_less(99, 5)) { file->rdwr_byte(owner_n); } if(file->is_version_atleast(88, 9)) { uint8 sl = slope; if( file->is_version_less(112, 7) && file->is_saving() ) { // truncate double slopes to single slopes, better than nothing sl = min( corner_sw(slope), 1 ) + min( corner_se(slope), 1 ) * 2 + min( corner_ne(slope), 1 ) * 4 + min( corner_nw(slope), 1 ) * 8; } file->rdwr_byte(sl); if( file->is_loading() ) { slope = sl; } } else { // safe init for old version slope = 0; } if( file->is_loading() ) { if( file->is_version_less(112, 7) ) { // convert slopes from old single height saved game slope = slope_from_slope4(slope4_t(slope), env_t::pak_height_conversion_factor); } if( !ground_desc_t::double_grounds ) { // truncate double slopes to single slopes slope = encode_corners(min( corner_sw(slope), 1 ), min( corner_se(slope), 1 ), min( corner_ne(slope), 1 ), min( corner_nw(slope), 1 )); } } // restore grid if( file->is_loading() ) { if( get_typ() == grund_t::boden || get_typ() == grund_t::fundament ) { /* since those must be on the ground and broken grids occurred in the past * (due to incorrect restoration of grid heights on house slopes) * we simply reset the grid height to our current height */ z = pos.z; } // for south/east map edges we need to restore more than one point if( pos.x == welt->get_size().x-1 && pos.y == welt->get_size().y-1 ) { sint8 z_southeast = z; if( get_typ() == grund_t::wasser && z_southeast > z_w ) { z_southeast = z_w; } else { z_southeast += corner_se(slope); } welt->set_grid_hgt_nocheck( k + koord(1,1), z_southeast ); } if( pos.x == welt->get_size().x-1 ) { sint8 z_east = z; if( get_typ() == grund_t::wasser && z_east > z_w ) { z_east = z_w; } else { z_east += corner_ne(slope); } welt->set_grid_hgt_nocheck( k + koord(1,0), z_east ); } if( pos.y == welt->get_size().y-1 ) { sint8 z_south = z; if( get_typ() == grund_t::wasser && z_south > z_w ) { z_south = z_w; } else { z_south += corner_sw(slope); } welt->set_grid_hgt_nocheck( k + koord(0,1), z_south ); } if( get_typ() == grund_t::wasser && z > z_w ) { z = z_w; } else { z += corner_nw(slope); } welt->set_grid_hgt_nocheck( k, z ); welt->set_water_hgt_nocheck( k, z_w ); } // loading ways from here on if(file->is_loading()) { waytype_t wtyp; int i = -1; do { wtyp = (waytype_t)file->rd_obj_id(); weg_t *weg = NULL; if(++i < 2) { switch(wtyp) { default: #if MSG_LEVEL if( wtyp != invalid_wt ) { dbg->error( "grund_t::rdwr()", "invalid waytype %i!", (int)wtyp ); wtyp = invalid_wt; } #endif break; case road_wt: weg = new strasse_t(file); break; case monorail_wt: weg = new monorail_t(file); break; case maglev_wt: weg = new maglev_t(file); break; case narrowgauge_wt: weg = new narrowgauge_t(file); break; case track_wt: { schiene_t *sch = new schiene_t(file); if(sch->get_desc()->get_wtyp()==monorail_wt) { dbg->warning("grund_t::rdwr()", "converting railroad to monorail at (%i,%i)",get_pos().x, get_pos().y); // compatibility code: Convert to monorail monorail_t *w= new monorail_t(); w->set_desc(sch->get_desc()); w->set_max_speed(sch->get_max_speed()); w->set_ribi(sch->get_ribi_unmasked()); delete sch; weg = w; } else { weg = sch; } } break; case tram_wt: weg = new schiene_t(file); if(weg->get_desc()->get_styp()!=type_tram) { weg->set_desc(way_builder_t::weg_search(tram_wt,weg->get_max_speed(),0,type_tram)); } break; case water_wt: // ignore old type dock ... if(file->is_version_atleast(87, 0)) { weg = new kanal_t(file); } else { uint8 d8; sint16 d16; sint32 d32; file->rdwr_byte(d8); file->rdwr_short(d16); file->rdwr_long(d32); file->rdwr_long(d32); file->rdwr_long(d32); file->rdwr_long(d32); DBG_MESSAGE("grund_t::rdwr()","at (%i,%i) dock ignored",get_pos().x, get_pos().y); } break; case air_wt: weg = new runway_t(file); break; } if(weg) { if(get_typ()==fundament) { // remove this (but we can not correct the other ways, since possibly not yet loaded) dbg->error("grund_t::rdwr()","removing way from foundation at %i,%i",pos.x,pos.y); // we do not delete them, to keep maintenance costs correct } else { assert((flags&has_way2)==0); // maximum two ways on one tile ... weg->set_pos(pos); if(owner_n!=-1) { weg->set_owner(welt->get_player(owner_n)); } objlist.add(weg); if(flags&has_way1) { flags |= has_way2; } flags |= has_way1; } } } } while(wtyp != invalid_wt); flags |= dirty; } else { // saving all ways ... if (weg_t* const w = get_weg_nr(0)) { file->wr_obj_id(w->get_waytype()); w->rdwr(file); } if (weg_t* const w = get_weg_nr(1)) { file->wr_obj_id(w->get_waytype()); w->rdwr(file); } file->wr_obj_id(-1); // Way end } // all objects on this tile objlist.rdwr(file, get_pos()); // need to add a crossing for old games ... if (file->is_loading() && ist_uebergang() && !find(2)) { const crossing_desc_t *cr_desc = crossing_logic_t::get_crossing( ((weg_t *)obj_bei(0))->get_waytype(), ((weg_t *)obj_bei(1))->get_waytype(), ((weg_t *)obj_bei(0))->get_max_speed(), ((weg_t *)obj_bei(1))->get_max_speed(), 0 ); if(cr_desc==NULL) { dbg->warning("crossing_t::rdwr()","requested for waytypes %i and %i not available, try to load object without timeline", ((weg_t *)obj_bei(0))->get_waytype(), ((weg_t *)obj_bei(1))->get_waytype() ); cr_desc = crossing_logic_t::get_crossing( ((weg_t *)obj_bei(0))->get_waytype(), ((weg_t *)obj_bei(1))->get_waytype(), 0, 0, 0); } if(cr_desc==0) { dbg->fatal("crossing_t::crossing_t()","requested for waytypes %i and %i but nothing defined!", ((weg_t *)obj_bei(0))->get_waytype(), ((weg_t *)obj_bei(1))->get_waytype() ); } crossing_t *cr = new crossing_t(obj_bei(0)->get_owner(), pos, cr_desc, ribi_t::is_straight_ns(get_weg(cr_desc->get_waytype(1))->get_ribi_unmasked()) ); objlist.add( cr ); crossing_logic_t::add( cr, crossing_logic_t::CROSSING_INVALID ); } } grund_t::grund_t(koord3d pos) { this->pos = pos; flags = 0; set_image(IMG_EMPTY); // set flags = dirty; back_imageid = 0; } grund_t::~grund_t() { destroy_win((ptrdiff_t)this); // remove text from table set_text(NULL); if(flags&is_halt_flag) { get_halt()->rem_grund(this); } } void grund_t::sort_trees() { if (get_typ() != boden) { return; } uint8 trees = 0, offset = 0; for( int i=0; iget_typ() == obj_t::baum) { trees++; offset = i; } } if(trees > 1) { objlist.sort_trees(offset-trees+1u, trees); } } void grund_t::rotate90() { pos.rotate90( welt->get_size().y-1 ); slope = slope_t::rotate90( slope ); // then rotate the things on this tile if (obj_count() == 254) { dbg->warning("grund_t::rotate90()", "Too many stuff on (%s)", pos.get_str()); } objlist.rotate90_moving(); uint8 trees = 0, offset = 0; for( uint8 i=0; irotate90(); if (obj_bei(i)->get_typ() == obj_t::baum) { trees++; offset = i; } } // if more than one tree on a tile .. resort since offsets changed if(trees > 1) { objlist.sort_trees(offset-trees+1u, trees); } } // after processing the last tile, we recalculate the hashes of the ground texts void grund_t::finish_rotate90() { inthashtable_tpl ground_texts_rotating; // first get the old hashes for(auto iter : ground_texts) { koord3d k = get_ground_koord3d_key( iter.key ); k.rotate90( welt->get_size().y-1 ); ground_texts_rotating.put( get_ground_text_key(k), iter.value ); } ground_texts.clear(); // then transfer all rotated texts for(auto iter : ground_texts_rotating) { ground_texts.put(iter.key, iter.value); } ground_texts_rotating.clear(); } void grund_t::enlarge_map( sint16, sint16 /*new_size_y*/ ) { inthashtable_tpl ground_texts_enlarged; // we have recalculate the keys for(auto iter : ground_texts) { koord3d k = get_ground_koord3d_key( iter.key ); ground_texts_enlarged.put( get_ground_text_key(k), iter.value ); } ground_texts.clear(); // then transfer all texts back for(auto iter : ground_texts_enlarged) { ground_texts.put(iter.key, iter.value); } ground_texts_enlarged.clear(); } // moves all objects from the old to the new grund_t void grund_t::take_obj_from(grund_t* other_gr) { // transfer all things while( other_gr->obj_count() ) { objlist.add( other_gr->obj_remove_top() ); } // transfer the way flags if(other_gr->get_flag(has_way1)) { flags |= has_way1; other_gr->clear_flag(has_way1); } if(other_gr->get_flag(has_way2)) { flags |= has_way2; other_gr->clear_flag(has_way2); } } void grund_t::open_info_window() { if(env_t::ground_info || hat_wege()) { if (hat_wege()) { } create_win(new grund_info_t(this), w_info, (ptrdiff_t)this); } } void grund_t::info(cbuffer_t& buf) const { if(!is_water()) { if(flags&has_way1) { // bridges / tunnels only carry dummy ways if (!ist_tunnel() && !ist_bruecke()) { translator::get_obj_info(buf, get_weg_nr(0)->get_name()); } obj_bei(0)->info(buf); // creator of bridge or tunnel graphic const char* maker = NULL; if (ist_tunnel()) { if (tunnel_t* tunnel = find(1)) { maker = tunnel->get_desc()->get_copyright(); } } if (ist_bruecke()) { if (bruecke_t* bridge = find(1)) { maker = bridge->get_desc()->get_copyright(); } } if (maker) { buf.printf(translator::translate("Constructed by %s"), maker); buf.append("\n\n"); } // second way if(flags&has_way2) { //translator::get_obj_info(buf, get_weg_nr(0)->get_name()) // might get too long ... buf.append(translator::translate(get_weg_nr(1)->get_name())); buf.append("\n"); obj_bei(1)->info(buf); buf.append("\n"); if(ist_uebergang()) { crossing_t* crossing = find(2); crossing->info(buf); } } } buf.append(translator::translate(ground_desc_t::get_climate_name_from_bit(welt->get_climate(get_pos().get_2d())))); } #if MSG_LEVEL >= 4 buf.printf("\nflags $%0X", flags ); buf.printf("\n\npos: (%s)",pos.get_str()); buf.printf("\nslope: %i",get_grund_hang()); buf.printf("\nback0: %i",abs(back_imageid)%11); buf.printf("\nback1: %i",(abs(back_imageid)/11)+11); if( get_weg_nr(0) ) { buf.printf("\nway slope %i", (int)get_weg_hang() ); } if(get_weg_ribi_unmasked(water_wt)) { buf.printf("\nwater ribi: %i",get_weg_ribi_unmasked(water_wt)); } if(is_water()) { buf.printf("\ncanal ribi: %i", ((const wasser_t*)this)->get_canal_ribi()); } buf.printf("\ndraw_as_obj= %i",(flags&draw_as_obj)!=0); #endif } void grund_t::set_halt(halthandle_t halt) { bool add = halt.is_bound(); if( add ) { // ok, we want to add a stop: first check if it can apply to water if( get_weg_ribi(water_wt) || is_water() || (ist_karten_boden() && welt->get_climate(pos.get_2d())==water_climate) ) { add = (halt->get_station_type() & haltestelle_t::dock) > 0; } } // then add or remove halt flag // and record the halt if( add ) { this_halt = halt; flags |= is_halt_flag|dirty; } else { this_halt = halthandle_t(); flags &= ~is_halt_flag; flags |= dirty; } } halthandle_t grund_t::get_halt() const { return (flags&is_halt_flag) ? this_halt : halthandle_t(); } // ----------------------- image calculation stuff from here ------------------ void grund_t::calc_image() { // will automatically recalculate ways ... objlist.calc_image(); // since bridges may alter images of ways, this order is needed! calc_image_internal( false ); } void grund_t::set_underground_mode(const uint8 ugm, const sint8 level) { underground_mode = ugm; switch(ugm) { case ugm_all: underground_level = -128; break; case ugm_level: underground_level = level; break; case ugm_none: default: underground_mode = ugm_none; underground_level = 127; } } image_id grund_t::get_back_image(int leftback) const { if(back_imageid==0) { return IMG_EMPTY; } uint16 back_image = abs(back_imageid); back_image = leftback ? (back_image / grund_t::WALL_IMAGE_COUNT) + grund_t::WALL_IMAGE_COUNT : back_image % grund_t::WALL_IMAGE_COUNT; if(back_imageid<0) { return ground_desc_t::fundament->get_image(back_image); } else { return ground_desc_t::slopes->get_image(back_image); } } // with double height ground tiles! // can also happen with single height tiles static inline uint8 get_back_image_from_diff(sint8 h1, sint8 h2) { sint8 min_diff = min( h1, h2 ); while( min_diff > 2 || (min_diff > 0 && h1 != h2) ) { h1 -= min_diff > 1 ? 2 : 1; h2 -= min_diff > 1 ? 2 : 1; min_diff -= 2; } if(h1*h2<0) { // middle slop of double height return h1<0 ? 9 : 10; } else { return (h1>0?h1:0)+(h2>0?h2:0)*3; } } /** * if ground is deleted mark the old spot as dirty */ void grund_t::mark_image_dirty() const { // see obj_t::mark_image_dirty if(imageid!=IMG_EMPTY) { const scr_coord scr_pos = welt->get_viewport()->get_screen_coord(koord3d(pos.get_2d(),get_disp_height())); display_mark_img_dirty( imageid, scr_pos.x, scr_pos.y ); } } // artificial walls from here on ... void grund_t::calc_back_image(const sint8 hgt, const slope_t::type slope_this) { // full underground mode or not ground -> no back image, no need for draw_as_obj if( underground_mode == ugm_all || !ist_karten_boden() ) { clear_flag(grund_t::draw_as_obj); this->back_imageid = 0; return; } // store corner heights sw, nw, ne scaled to screen dimensions const sint16 scale_z_step = tile_raster_scale_y(TILE_HEIGHT_STEP,64); const sint16 scale_y_step = 64/2; sint16 corners[grund_t::BACK_CORNER_COUNT] = {(sint16)(scale_z_step*(hgt + corner_sw(slope_this))), (sint16)(scale_z_step*(hgt + corner_nw(slope_this))), (sint16)(scale_z_step*(hgt + corner_ne(slope_this)))}; sint16 corners_add[grund_t::BACK_CORNER_COUNT] = {0,0,0}; // extra height of possible back-image // now calculate back image sint8 back_imageid=0; bool is_building = get_typ()==grund_t::fundament; const bool isvisible = is_visible(); bool fence[grund_t::BACK_WALL_COUNT] = {false, false}; const koord k = get_pos().get_2d(); clear_flag(grund_t::draw_as_obj); weg_t const* w; if( ( (w = get_weg_nr(0)) && w->get_desc()->is_draw_as_obj() ) || ( (w = get_weg_nr(1)) && w->get_desc()->is_draw_as_obj() ) ) { set_flag(grund_t::draw_as_obj); } for( size_t i=0; ilookup_kartenboden(k + koord::nesw[(i+3)&3]) ) { const uint8 back_height = min(corner_nw(slope_this),(i==0?corner_sw(slope_this):corner_ne(slope_this))); const sint16 left_hgt=gr->get_disp_height()-back_height; const slope_t::type slope=gr->get_disp_slope(); const uint8 corner_a = (i==0?corner_sw(slope_this):corner_nw(slope_this))-back_height; const uint8 corner_b = (i==0?corner_nw(slope_this):corner_ne(slope_this))-back_height; sint8 diff_from_ground_1 = left_hgt+(i==0?corner_se(slope):corner_sw(slope))-hgt; sint8 diff_from_ground_2 = left_hgt+(i==0?corner_ne(slope):corner_se(slope))-hgt; if (underground_mode==ugm_level) { const bool gr_is_visible = gr->is_visible(); // if exactly one of (this) and (gr) is visible, show full walls if ( isvisible && !gr_is_visible){ diff_from_ground_1 += 1; diff_from_ground_2 += 1; set_flag(grund_t::draw_as_obj); fence[i] = corner_a==corner_b; } else if ( !isvisible && gr_is_visible){ diff_from_ground_1 = max(diff_from_ground_1, 1); diff_from_ground_2 = max(diff_from_ground_2, 1); } // avoid walls that cover the tunnel mounds if ( gr_is_visible && (gr->get_typ()==grund_t::tunnelboden) && ist_karten_boden() && gr->get_pos().z==underground_level && corner_se( gr->get_grund_hang() ) > 0 /* se corner */) { diff_from_ground_1 = 0; diff_from_ground_2 = 0; } if ( isvisible && (get_typ()==grund_t::tunnelboden) && ist_karten_boden() && pos.z==underground_level && corner_nw( get_grund_hang() ) > 0 /* nw corner */) { if ( (i==0) ^ (corner_sw( get_grund_hang() )==0) ) { diff_from_ground_1 = 0; diff_from_ground_2 = 0; } } } // up slope hiding something ... if(diff_from_ground_1-corner_a<0 || diff_from_ground_2-corner_b<0) { if( corner_a==corner_b ) { // ok, we need a fence here, if there is not a vertical bridgehead weg_t const* w; fence[i] = !(w = get_weg_nr(0)) || ( !(w->get_ribi_unmasked() & ribi_t::nesw[(i+3)&3]) && (!(w = get_weg_nr(1)) || !(w->get_ribi_unmasked() & ribi_t::nesw[(i+3)&3])) ); // no fences between water tiles or between invisible tiles if( fence[i] && ( (is_water() && gr->is_water()) || (!isvisible && !gr->is_visible()) ) ) { fence[i] = false; } } } // any height difference AND something to see? if( (diff_from_ground_1-corner_a>0 || diff_from_ground_2-corner_b>0) && (diff_from_ground_1>0 || diff_from_ground_2>0) ) { back_imageid += get_back_image_from_diff( diff_from_ground_1, diff_from_ground_2 )*(i==0?1:grund_t::WALL_IMAGE_COUNT); is_building |= gr->get_typ()==grund_t::fundament; } // update corner heights if (diff_from_ground_1 > corner_a) { corners_add[i] = max(corners_add[i], scale_z_step * (diff_from_ground_1-corner_a)); } if (diff_from_ground_2 > corner_b) { corners_add[i+1] = max(corners_add[i+1], scale_z_step * (diff_from_ground_2 - corner_b)); } } } for(uint i=0; i
tag while (*tail) { if (*lead == '<') { bool endtag = false; if (lead[1] == '/') { endtag = true; lead++; tail++; } // parse a tag (not allowed to exceed sizeof(word) letters) for (uint i = 0; *lead != '>' && *lead > 0 && i+2 < sizeof(word); i++) { lead++; } strncpy(word, (const char*)tail + 1, lead - tail - 1); word[lead - tail - 1] = '\0'; lead++; if (word[0] == 'p' || (word[0] == 'b' && word[1] == 'r')) { // unlike http, we can have as many newlines as we like att = ATT_NEWLINE; } else if (word[0] == 'a') { if (!endtag) { att = ATT_A_START; // search for href attributes // .. ignore any number of spaces // .. accept link string enclosed by " and ' // skip a and ' ' char* start = word; while(*start == 'a' || *start == ' ') start++; start = const_cast( strstart(start, "href") ); if (start) { // skip ",=, and ' ' while(*start == '"' || *start == ' ' || *start == '=' || *start == '\'') start++; char *end = start; // find first ',", terminate string there while(*end && *end != '"' && *end != '\'') end++; *end = 0; param = start; } else { param = ""; } link_it = true; } else { if (link_it) { att = ATT_A_END; links.append(hyperlink_t(param)); link_it = false; } else { // ignore closing without opening att = ATT_UNKNOWN; } } } else if (word[0] == 'h' && word[1] == '1') { att = endtag ? ATT_H1_END : ATT_H1_START; } else if (word[0] == 'i') { att = endtag ? ATT_IT_END : ATT_IT_START; } else if (word[0] == 'e' && word[1] == 'm') { att = endtag ? ATT_EM_END : ATT_EM_START; } else if (word[0] == 's' && word[1] == 't') { att = endtag ? ATT_STRONG_END : ATT_STRONG_START; } else if (!endtag && strcmp(word, "title") == 0) { // title tag const unsigned char* title_start = lead; // parse title tag (again, enforce 511 limit) for (int i = 0; *lead != '<' && *lead > 0 && i < 511; i++) { lead++; } strncpy(title, (const char*)title_start, lead - title_start); title[lead - title_start] = '\0'; // close title tag (again, enforce 511 limit) for (int i = 0; *lead != '>' && *lead > 0 && i < 511; i++) { lead++; } if (*lead == '>') { lead++; } att = ATT_UNKNOWN; } else { // ignore all unknown att = ATT_UNKNOWN; } // end of commands } else if( lead[0]=='&' ) { if( lead[2]=='t' && lead[3]==';' ) { // either gt or lt strcpy( word, lead[1]=='l' ? "<" : ">" ); lead += 4; } else if( lead[1]=='#' ) { // decimal number word[0] = atoi( (const char *)lead+2 ); word[1] = 0; while( *lead++!=';' ) { } } else { // only copy ampersand strcpy( word, "&" ); lead ++; } att = *lead<=32 ? ATT_NONE : ATT_NO_SPACE; } else { // parse a word (and obey limits) att = ATT_NONE; for( uint i = 0; *lead != '<' && (*lead > 32 || (i==0 && *lead==32)) && i+1 < sizeof(word) && *lead != '&'; i++) { if( *lead>128 ) { size_t len = 0; utf32 symbol = utf8_decoder_t::decode(lead, len); if( symbol == 0x3000 ) { // space ... break; } lead += len; i += len; if( symbol == 0x3001 || symbol == 0x3002 ) { att = ATT_NO_SPACE; // CJK full stop, comma, space break; } // every CJK symbol could be used to break, so break after 10 characters if( symbol >= 0x2E80 && symbol <= 0xFE4F && i>6 ) { att = ATT_NO_SPACE; break; } } else { lead++; } } strncpy(word, (const char*)tail, lead - tail); if( *lead>32 && word[0]!=32 ) { att = ATT_NO_SPACE; } word[lead - tail] = '\0'; if( *word==0 ) { // do not add empty strings att = ATT_UNKNOWN; } } if( att != ATT_UNKNOWN ) { // only add know commands nodes.append(node_t(word, att)); } if( att==ATT_UNKNOWN || att==ATT_NONE || att==ATT_NO_SPACE || att==ATT_NEWLINE ) { // skip white spaces while (*lead <= 32 && *lead > 0) { lead++; } // skip wide spaces utf8 const *lead_search = lead; while( utf8_decoder_t::decode(lead_search) == 0x3000 ){ lead = lead_search; } } tail = lead; } dirty = true; // save size preferred_size = output(scr_size(0, 0), false, true); } const char* gui_flowtext_intern_t::get_title() const { return title; } void gui_flowtext_intern_t::set_size(scr_size size_par) { gui_component_t::set_size(size_par); // update preferred_size preferred_size = output(scr_size(0, 0), false, true); } /** * preferred size of text: * * get_preferred_size().w = max(width, maximal word length) * get_preferred_size().h = displayed height */ scr_size gui_flowtext_intern_t::get_preferred_size() const { return preferred_size; // cached result of output(scr_size(0, 0), false, true); } /** * wider than current width */ scr_size gui_flowtext_intern_t::get_text_size() { return output(scr_size(0, 0), false, false); } void gui_flowtext_intern_t::draw(scr_coord offset) { offset += pos; if(offset!=last_offset) { dirty = true; last_offset = offset; } output(offset, true); } scr_size gui_flowtext_intern_t::output(scr_coord offset, bool doit, bool return_max_width) { const int width = size.w-D_MARGIN_LEFT-D_MARGIN_RIGHT; slist_tpl::iterator link = links.begin(); int xpos = 0; int ypos = 0; PIXVAL color = SYSCOL_TEXT; PIXVAL double_color = SYSCOL_TEXT_SHADOW; bool double_it = false; bool link_it = false; // true, if currently underlining for a link int extra_pixel = 0; // extra pixel before next line int last_link_x = 0; // at this position ye need to continue underline drawing int max_width = width; int text_width = width; const int space_width = proportional_string_width(" "); for(node_t const& i : nodes) { switch (i.att) { case ATT_NONE: case ATT_NO_SPACE: { int nxpos = xpos + proportional_string_width(i.text.c_str()); if (nxpos >= text_width) { text_width = nxpos; } // too wide if( nxpos >= width ) { if (nxpos - xpos > max_width) { // word too long max_width = nxpos-xpos; } nxpos -= xpos; // now word length, new xpos after linebreak if (xpos > 0) { if( xpos!=last_link_x && link_it ) { if( doit ) { // close the link display_fillbox_wh_clip_rgb( offset.x + last_link_x + D_MARGIN_LEFT, ypos + offset.y + LINESPACE-1, xpos-last_link_x, 1, color, false); } extra_pixel = 1; } xpos = 0; last_link_x = 0; ypos += LINESPACE+extra_pixel; extra_pixel = 0; } } if( i.att == ATT_NONE ) { // add trailing space nxpos += space_width; } if (doit) { if (double_it) { display_proportional_clip_rgb(offset.x + xpos + 1 + D_MARGIN_LEFT, offset.y + ypos + 1, i.text.c_str(), 0, double_color, false); extra_pixel |= 1; } scr_coord_val width = display_proportional_clip_rgb(offset.x + xpos + D_MARGIN_LEFT, offset.y + ypos, i.text.c_str(), 0, color, false); if( link_it ) { display_fillbox_wh_clip_rgb( offset.x + last_link_x + D_MARGIN_LEFT, ypos + offset.y + LINESPACE-1, (xpos+width)-last_link_x, 1, color, false); last_link_x = xpos+width; } } if( link_it ) { extra_pixel = 1; } xpos = nxpos; break; } case ATT_NEWLINE: xpos = 0; if( last_link_x is missing if (link!=links.end()) { link->tl.x = xpos; link->tl.y = ypos; last_link_x = xpos; link_it = true; } break; case ATT_A_END: link->br.x = xpos; link->br.y = ypos + LINESPACE; ++link; link_it = false; color = SYSCOL_TEXT; break; case ATT_H1_START: color = SYSCOL_TEXT_TITLE; double_it = true; break; case ATT_H1_END: double_it = false; if(doit) { display_fillbox_wh_clip_rgb(offset.x + 1 + D_MARGIN_LEFT, offset.y + ypos + LINESPACE, xpos, 1, color, false); display_fillbox_wh_clip_rgb(offset.x + D_MARGIN_LEFT, offset.y + ypos + LINESPACE-1, xpos, 1, double_color, false); } xpos = 0; extra_pixel = 0; ypos += LINESPACE+2; color = SYSCOL_TEXT; break; case ATT_EM_START: color = SYSCOL_TEXT_HIGHLIGHT; break; case ATT_EM_END: color = SYSCOL_TEXT; break; case ATT_IT_START: color = SYSCOL_TEXT_HIGHLIGHT; double_it = true; break; case ATT_IT_END: color = SYSCOL_TEXT; double_it = false; break; case ATT_STRONG_START: if( !double_it ) { color = SYSCOL_TEXT_STRONG; } break; case ATT_STRONG_END: if( !double_it ) { color = SYSCOL_TEXT; } break; default: break; } } ypos += LINESPACE; if(dirty) { mark_rect_dirty_wc( offset.x + D_MARGIN_LEFT, offset.y, offset.x+max_width + D_MARGIN_LEFT, offset.y+ypos ); dirty = false; } return scr_size( (return_max_width ? max_width : text_width)+D_MARGIN_LEFT+D_MARGIN_RIGHT, ypos); } bool gui_flowtext_intern_t::infowin_event(const event_t* ev) { if (IS_LEFTRELEASE(ev)) { // scan links for hit const scr_coord evpos = ev->click_pos; // - get_pos(); for(hyperlink_t const& link : links) { if( link.tl.y+LINESPACE == link.br.y ) { if( link.tl.x <= evpos.x && evpos.x < link.br.x && link.tl.y <= evpos.y && evpos.y < link.br.y ) { call_listeners((void const*)link.param.c_str()); return true; } } else { // multi lined box => more difficult if( link.tl.x <= evpos.x && evpos.x < get_size().w && link.tl.y <= evpos.y && evpos.y < link.tl.y+LINESPACE ) { // in top line call_listeners((void const*)link.param.c_str()); return true; } else if( 0 <= evpos.x && evpos.x < link.br.x && link.br.y-LINESPACE <= evpos.y && evpos.y < link.br.y ) { // in last line call_listeners((void const*)link.param.c_str()); return true; } else if( 0 <= evpos.x && evpos.x < get_size().w && link.tl.y+LINESPACE <= evpos.y && evpos.y < link.br.y-LINESPACE ) { // line in between call_listeners((void const*)link.param.c_str()); return true; } } } } return false; } /** Implementation of the wrapping class **/ gui_flowtext_t::gui_flowtext_t() : gui_scrollpane_t(NULL, true, true) { flowtext = new gui_flowtext_intern_t(); set_component(flowtext); flowtext->add_listener(this); } gui_flowtext_t::~gui_flowtext_t() { delete flowtext; flowtext = NULL; } void gui_flowtext_t::set_text(const char* text) { // reset position if text is changed set_scroll_position(0, 0); flowtext->set_text(text); } const char* gui_flowtext_t::get_title() const { return flowtext->get_title(); } void gui_flowtext_t::set_size(scr_size size_par) { gui_scrollpane_t::set_size(size_par); // compute and set height flowtext->set_size( flowtext->get_preferred_size() ); // recalc twice to get correct scrollbar visibility recalc_sliders(get_size()); recalc_sliders(get_size()); } scr_size gui_flowtext_t::get_preferred_size() const { return flowtext->get_preferred_size(); } bool gui_flowtext_t::action_triggered(gui_action_creator_t*, value_t extra) { call_listeners(extra); return true; } simutrans-124.3/src/simutrans/gui/components/gui_flowtext.h000066400000000000000000000017611474050137200242360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_FLOWTEXT_H #define GUI_COMPONENTS_GUI_FLOWTEXT_H #include "action_listener.h" #include "gui_action_creator.h" #include "gui_scrollpane.h" class gui_flowtext_intern_t; /** * A component for floating text wrapped into a scrollpane. */ class gui_flowtext_t : public gui_action_creator_t, public action_listener_t, public gui_scrollpane_t { gui_flowtext_intern_t* flowtext; using gui_scrollpane_t::set_component; public: gui_flowtext_t(); ~gui_flowtext_t(); /** * Sets the text to display. */ void set_text(const char* text); const char* get_title() const; /** * Updates size and preferred_size. */ void set_size(scr_size size_par) OVERRIDE; /** * Computes and returns preferred size. * Depends on current width. */ scr_size get_preferred_size() const; bool action_triggered(gui_action_creator_t *comp, value_t extra) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_image.cc000066400000000000000000000042441474050137200236010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_image.h" #include "../gui_frame.h" gui_image_t::gui_image_t( const image_id i, const uint8 p, control_alignment_t alignment_par, bool remove_offset_enabled ) : alignment(alignment_par), player_nr(p), remove_offset(0,0), remove_enabled(remove_offset_enabled), color_index(0) { set_image(i,remove_offset_enabled); } scr_size gui_image_t::get_min_size() const { if( id != IMG_EMPTY ) { scr_coord_val x=0, y=0, w=0, h=0; display_get_base_image_offset( id, &x, &y, &w, &h ); if (remove_enabled) { return scr_size(w, h); } else { // FIXME assert(0); return scr_size(x+w, y+h); } } return gui_component_t::get_min_size(); } void gui_image_t::set_size( scr_size size_par ) { if( id != IMG_EMPTY ) { scr_coord_val x=0, y=0, w=0, h=0; display_get_base_image_offset( id, &x, &y, &w, &h ); if( remove_enabled ) { remove_offset = scr_coord(-x,-y); } size_par = scr_size( x+w+remove_offset.x, y+h+remove_offset.y ); } gui_component_t::set_size(size_par); } void gui_image_t::set_image( const image_id i, bool remove_offsets ) { id = i; remove_enabled = remove_offsets; if( id ==IMG_EMPTY ) { remove_offset = scr_coord(0,0); remove_enabled = false; } set_size( size ); } /** * Draw the component */ void gui_image_t::draw( scr_coord offset ) { if( id!=IMG_EMPTY ) { scr_coord_val x=0, y=0, w=0, h=0; display_get_base_image_offset( id, &x, &y, &w, &h ); switch (alignment) { case ALIGN_RIGHT: offset.x += size.w - w + remove_offset.x; break; case ALIGN_BOTTOM: offset.y += size.h - h + remove_offset.y; break; case ALIGN_CENTER_H: offset.x += D_GET_CENTER_ALIGN_OFFSET(w,size.w); break; case ALIGN_CENTER_V: offset.y += D_GET_CENTER_ALIGN_OFFSET(h,size.h); break; } if (color_index) { display_base_img_blend(id , pos.x+offset.x+remove_offset.x, pos.y+offset.y+remove_offset.y, player_nr, color_index, false, true); } else { display_base_img( id, pos.x+offset.x+remove_offset.x, pos.y+offset.y+remove_offset.y, (sint8)player_nr, false, true ); } } } simutrans-124.3/src/simutrans/gui/components/gui_image.h000066400000000000000000000022731474050137200234430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_IMAGE_H #define GUI_COMPONENTS_GUI_IMAGE_H #include "../../display/simimg.h" #include "../../display/simgraph.h" #include "gui_component.h" /** * Just displays an image */ class gui_image_t : public gui_component_t { control_alignment_t alignment; image_id id; uint16 player_nr; scr_coord remove_offset; bool remove_enabled; FLAGGED_PIXVAL color_index; public: gui_image_t( const image_id i=IMG_EMPTY, const uint8 p=0, control_alignment_t alignment_par = ALIGN_NONE, bool remove_offset = false ); public: void set_player_nr(uint8_t player) { player_nr = player; } void set_size( scr_size size_par ) OVERRIDE; void set_image( const image_id i, bool remove_offsets = false ); void enable_offset_removal(bool remove_offsets) { set_image(id,remove_offsets); } void set_transparent(FLAGGED_PIXVAL c) { color_index = c; } //// Draw the component void draw( scr_coord offset ) OVERRIDE; scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE { return get_min_size(); } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_image_list.cc000066400000000000000000000077321474050137200246410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simdebug.h" #include "gui_image_list.h" #include "../../display/simgraph.h" #include "../../simevent.h" #include "../../simcolor.h" gui_image_list_t::gui_image_list_t(vector_tpl *images) : grid(16, 16), placement(16, 16) { this->images = images; player_nr = 0; max_rows = -1; max_width = -1; } /** * Events are notified to GUI components via this method */ bool gui_image_list_t::infowin_event(const event_t *ev) { int sel_index = index_at(scr_coord(0,0)-pos, ev->mouse_pos.x, ev->mouse_pos.y); if( sel_index != -1 && (IS_LEFTDBLCLK(ev) || IS_LEFTRELEASE(ev)) ) { value_t p; p.i = sel_index; call_listeners( p ); return true; } return false; } int gui_image_list_t::index_at(scr_coord parent_pos, int xpos, int ypos) const { xpos -= parent_pos.x + pos.x + BORDER; ypos -= parent_pos.y + pos.y + BORDER; if(xpos>=0 && ypos>=0 && xposget_count() && (*images)[index]->image != IMG_EMPTY) { return index; } } return -1; } void gui_image_list_t::draw(scr_coord parent_pos) { const int columns = (size.w - 2 * BORDER) / grid.x; // sel_index should come from infowin_event, but it is not sure? int sel_index = index_at(parent_pos, get_mouse_pos().x, get_mouse_pos().y); // Show available wagon types int xmin = parent_pos.x + pos.x + BORDER; int ymin = parent_pos.y + pos.y + BORDER; int xmax = xmin + columns * grid.x; int xpos = xmin; int ypos = ymin; for(image_data_t* const& iptr : *images) { image_data_t const& idata = *iptr; if(idata.count>=0) { // display mark if(idata.lcolor!=EMPTY_IMAGE_BAR) { display_fillbox_wh_clip_rgb( xpos + 1, ypos + grid.y - 5, grid.x/2 - 1, 4, idata.lcolor, true); } if(idata.rcolor!=EMPTY_IMAGE_BAR) { display_fillbox_wh_clip_rgb( xpos + grid.x/2, ypos + grid.y - 5, grid.x - grid.x/2 - 1, 4, idata.rcolor, true); } if (sel_index-- == 0) { display_ddd_box_clip_rgb(xpos, ypos, grid.x, grid.y, color_idx_to_rgb(MN_GREY4), color_idx_to_rgb(MN_GREY0)); } // Get image data scr_coord_val x,y,w,h; display_get_base_image_offset( idata.image, &x, &y, &w, &h ); // calculate image offsets y = -y + (grid.y-h) - 6; // align to bottom mark x = -x + 2; // Add 2 pixel margin //display_base_img(idata.image, xpos + placement.x, ypos + placement.y, player_nr, false, true); display_base_img(idata.image, xpos + x, ypos + y, player_nr, false, true); // If necessary, display a number: if(idata.count > 0) { char text[20]; sprintf(text, "%d", idata.count); // Let's make a black background to ensure visibility for(int iy = -3; iy < 0; iy++) { for(int ix = 1; ix < 4; ix++) { display_proportional_clip_rgb(xpos + ix, ypos + iy, text, ALIGN_LEFT, color_idx_to_rgb(COL_BLACK), true); } } // Display the number white on black display_proportional_clip_rgb(xpos + 2, ypos - 2, text, ALIGN_LEFT, color_idx_to_rgb(COL_WHITE), true); } } // advance x, y to next position xpos += grid.x; if(xpos == xmax) { xpos = xmin; ypos += grid.y; } } } scr_size gui_image_list_t::get_min_size() const { return get_max_size(); } scr_size gui_image_list_t::get_max_size() const { if (max_rows > 0) { // this many images per column sint32 cols = (images->get_count() + max_rows - 1) / max_rows; return scr_size(cols*grid.x + 2*BORDER, max_rows*grid.y + 2*BORDER); } else if (max_width > 0) { sint32 cols = (max_width - 2*BORDER) / grid.x; sint32 rows = (images->get_count() + cols - 1) / cols; return scr_size(cols*grid.x + 2*BORDER, rows*grid.y + 2*BORDER); } return scr_size((images->get_count()+1)*grid.x + 2*BORDER, grid.y + 2*BORDER); } simutrans-124.3/src/simutrans/gui/components/gui_image_list.h000066400000000000000000000052541474050137200245000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_IMAGE_LIST_H #define GUI_COMPONENTS_GUI_IMAGE_LIST_H #include "gui_action_creator.h" #include "gui_component.h" #include "../../tpl/vector_tpl.h" #include "../../display/simimg.h" #include "../../simcolor.h" #define EMPTY_IMAGE_BAR (255) /** * A component that represents a list of images. * * Updated! class is used only for the vehicle dialog. SO I changed some things * for the new one:: * - cannot select no-image fields any more * - numbers can be drawn ontop an images * - color bar can be added to the images */ class gui_image_list_t : public gui_action_creator_t, public gui_component_t { public: struct image_data_t { const char *text; ///< can be NULL, used to store external data image_id image; ///< the image sint16 count; ///< display this number as overlay PIXVAL lcolor; ///< color of left half of color bar, use EMPTY_IMAGE_BAR to display no bar PIXVAL rcolor; ///< color of right half of color bar, use EMPTY_IMAGE_BAR to display no bar image_data_t(const char *text_, image_id image_, sint16 count_=0, PIXVAL lcolor_=EMPTY_IMAGE_BAR, PIXVAL rcolor_=EMPTY_IMAGE_BAR) : text(text_), image(image_), count(count_), lcolor(lcolor_), rcolor(rcolor_) {} }; /** * Graphic layout: * size of borders around the whole area (there are no borders around * individual images) */ enum { BORDER = 4 }; private: vector_tpl *images; scr_coord grid; scr_coord placement; /** * Player number to obtain player color used to display the images. */ sint8 player_nr; scr_coord_val max_width; sint32 max_rows; public: /** * Constructor: takes pointer to vector with image_data_t * @param images pointer to vector of pointers to image_data_t */ gui_image_list_t(vector_tpl *images); /** * This set horizontal and vertical spacing for the images. */ void set_grid(scr_coord grid) { this->grid = grid; } /** * This set the offset for the images. */ void set_placement(scr_coord placement) { this->placement = placement; } void set_player_nr(sint8 player_nr) { this->player_nr = player_nr; } bool infowin_event(event_t const*) OVERRIDE; /** * Draw/record the picture */ void draw(scr_coord offset) OVERRIDE; /** * Looks for the image at given position. * xpos and ypos relative to parent window. */ int index_at(scr_coord parent_pos, int xpos, int ypos) const; void set_max_rows(sint32 r) { max_rows = r; } void set_max_width(scr_coord_val w) { max_width = w; } scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_label.cc000066400000000000000000000105601474050137200235740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_label.h" #include "../gui_frame.h" #include "../../dataobj/translator.h" #include "../../utils/simstring.h" #include "../simwin.h" /* * just displays a text, will be auto-translated */ static scr_coord_val separator_width = 0; static scr_coord_val large_money_width = 0; gui_label_t::gui_label_t(const char* text, PIXVAL color_, align_t align_) : align(align_), tooltip(NULL) { separator_width = proportional_string_width( ",00$" ); if (get_large_money_string()) { cbuffer_t buf; buf.printf("%s$", get_large_money_string()); large_money_width = proportional_string_width((const char*) buf); } else { large_money_width = 0; } set_size( scr_size( D_BUTTON_WIDTH, D_LABEL_HEIGHT ) ); init( text, scr_coord (0,0), color_, align_); shadowed = false; } scr_size gui_label_t::get_min_size() const { return scr_size( text ? display_calc_proportional_string_len_width(text,strlen(text)) : D_BUTTON_WIDTH, D_LABEL_HEIGHT ); } scr_size gui_label_t::get_max_size() const { return align == left ? get_min_size() : scr_size(scr_size::inf.w, get_min_size().h); } void gui_label_t::set_text(const char *text, bool autosize) { if (text != NULL) { set_text_pointer(translator::translate(text), autosize); } else { set_text_pointer(NULL, false); } } void gui_label_t::set_text_pointer(const char *text_par, bool autosize) { text = text_par; if (autosize && text && *text != '\0') { set_size( scr_size( display_calc_proportional_string_len_width(text,strlen(text)),size.h ) ); } } void gui_label_t::draw(scr_coord offset) { if( align == money_right) { if(text) { const char *separator = NULL; const bool not_a_number = atol(text)==0 && !isdigit(*text) && *text != '-'; scr_coord right = pos + offset; if( !not_a_number ) { // find first letter of large_money_width in text if (get_large_money_string()!=NULL) { separator = strrchr(text, *(get_large_money_string()) ); if (separator) { right.x += get_size().w - large_money_width; } } // look for fraction_sep (e.g., comma) if (separator==NULL) { // everything else align at decimal separator right.x += get_size().w - separator_width; separator = strrchr(text, get_fraction_sep()); } } if(separator) { display_proportional_clip_rgb(right.x, right.y, separator, ALIGN_LEFT, color, true); if( separator!=text ) { if (shadowed) { display_text_proportional_len_clip_rgb(right.x+1, right.y+1, text, ALIGN_RIGHT | DT_CLIP, color_shadow, true, separator - text); } display_text_proportional_len_clip_rgb(right.x, right.y, text, ALIGN_RIGHT | DT_CLIP, color, true, separator-text ); } } else { // integer or normal text if (shadowed) { display_proportional_clip_rgb(right.x + 1, right.y + 1, text, ALIGN_RIGHT | DT_CLIP, color_shadow, true); } display_proportional_clip_rgb(right.x, right.y, text, ALIGN_RIGHT, color, true); } } } else if(text) { const scr_rect area( offset+pos, size ); int a = align == left ? ALIGN_LEFT : ( align == right ? ALIGN_RIGHT : ALIGN_CENTER_H); display_proportional_ellipsis_rgb( area, text, a | DT_CLIP, color, true, shadowed, color_shadow ); } if ( tooltip && getroffen(get_mouse_pos() - offset) ) { const scr_coord tooltip_base_pos{ get_mouse_pos().x, offset.y + pos.y + size.h }; win_set_tooltip(tooltip_base_pos + TOOLTIP_MOUSE_OFFSET, tooltip, this); } } void gui_label_t::set_tooltip(const char * t) { tooltip = t; } void gui_label_buf_t::init(PIXVAL color_par, align_t align_par) { gui_label_t::init(NULL, get_pos(), color_par, align_par); buf_changed = false; } void gui_label_buf_t::update() { buffer_read = buffer_write; buffer_write.clear(); gui_label_t::set_text_pointer( (const char*)buffer_read, false /*no autoresize*/ ); buf_changed = false; } void gui_label_buf_t::draw(scr_coord offset) { if (buf_changed) { update(); } gui_label_t::draw(offset); } void gui_label_buf_t::set_min_width(scr_coord_val w) { min_width = w; } scr_size gui_label_buf_t::get_min_size() const { scr_size min_size = gui_label_t::get_min_size(); min_size.w = max(min_size.w, min_width); return min_size; } void gui_label_buf_t::append_money(double money) { buffer_write.append_money(money); set_color(money >= 0 ? MONEY_PLUS : MONEY_MINUS); } simutrans-124.3/src/simutrans/gui/components/gui_label.h000066400000000000000000000062771474050137200234500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_LABEL_H #define GUI_COMPONENTS_GUI_LABEL_H #include "gui_component.h" #include "../../simcolor.h" #include "../gui_theme.h" #include "../../simskin.h" #include "../../utils/cbuffer.h" /** * The label component * just displays a text, will be auto-translated */ class gui_label_t : virtual public gui_component_t { public: enum align_t { left, centered, right, money_right }; private: align_t align; /** * Color of the Labels */ PIXVAL color; bool shadowed; PIXVAL color_shadow; const char * text; // only for direct access of non-translatable things. Do not use! const char * tooltip; protected: using gui_component_t::init; public: gui_label_t(const char* text=NULL, PIXVAL color=SYSCOL_TEXT, align_t align=left); void init( const char* text_par, scr_coord pos_par, PIXVAL color_par=SYSCOL_TEXT, align_t align_par=left) { set_pos ( pos_par ); set_text ( text_par ); set_color( color_par ); set_align( align_par ); } /** * Sets the text to display, after translating it. */ void set_text(const char *text, bool autosize=true); /** * Sets the text without translation. */ void set_text_pointer(const char *text, bool autosize=true); /** * returns the pointer (i.e. for freeing untranslated contents) */ const char * get_text_pointer() const { return text; } /** * returns the tooltip pointer (i.e. for freeing untranslated contents) */ const char * get_tooltip_pointer() { return tooltip; } /** * Draws the component. */ void draw(scr_coord offset) OVERRIDE; /** * Sets the colour of the label */ void set_color(PIXVAL colour) { this->color = colour; } virtual PIXVAL get_color() const { return color; } /** * Toggles shadow and sets shadow color. */ void set_shadow(PIXVAL color_shadow, bool shadowed) { this->color_shadow = color_shadow; this->shadowed = shadowed; } /** * Sets the alignment of the label */ void set_align(align_t align) { this->align = align; } /** * Sets the tooltip of this component. */ void set_tooltip(const char * t); scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; /** * Label with own buffer. */ class gui_label_buf_t : public gui_label_t { bool buf_changed; cbuffer_t buffer_write, buffer_read; scr_coord_val min_width = 0; public: gui_label_buf_t(PIXVAL color=SYSCOL_TEXT, align_t align=left) : gui_label_t(NULL, color, align), buf_changed(true) { } void init(PIXVAL color_par=SYSCOL_TEXT, align_t align_par=left); /** * Has to be called after access to buf() is finished. * Otherwise size calculations will be off. * Called by @ref draw. */ void update(); cbuffer_t& buf() { if (!buf_changed) { buffer_write.clear(); } buf_changed = true; return buffer_write; } /** * appends money string to write buf, sets color */ void append_money(double money); void draw(scr_coord offset) OVERRIDE; void set_min_width(scr_coord_val w); scr_size get_min_size() const OVERRIDE; protected: using gui_label_t::get_text_pointer; using gui_label_t::set_text; using gui_label_t::set_text_pointer; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_location_view.h000066400000000000000000000014411474050137200252170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_LOCATION_VIEW_H #define GUI_COMPONENTS_GUI_LOCATION_VIEW_H #include "gui_world_view.h" /** * Displays a location on the world */ class location_view_t : public world_view_t { private: koord3d location; /**< The location to display. */ public: location_view_t(koord3d const location, scr_size const size) : world_view_t(size), location(location) {} /** Set the location to be displayed. */ void set_location(koord3d const l) { location = l; } void map_rotate90(sint16 const new_ysize) { location.rotate90(new_ysize); } void draw(scr_coord offset) OVERRIDE { internal_draw(offset, 0); } koord3d get_location() OVERRIDE { return location; } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_map_preview.cc000066400000000000000000000004701474050137200250320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_map_preview.h" #include "../../world/simworld.h" gui_map_preview_t::gui_map_preview_t() : gui_component_t() { map_data = NULL; set_size (scr_size( MAP_PREVIEW_SIZE_X,MAP_PREVIEW_SIZE_Y )); } simutrans-124.3/src/simutrans/gui/components/gui_map_preview.h000066400000000000000000000023621474050137200246760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_MAP_PREVIEW_H #define GUI_COMPONENTS_GUI_MAP_PREVIEW_H #include "gui_component.h" #include "../../simcolor.h" #include "../../display/simgraph.h" #include "../../tpl/array2d_tpl.h" #define MAP_PREVIEW_SIZE_X ((scr_coord_val)(64)) #define MAP_PREVIEW_SIZE_Y ((scr_coord_val)(64)) /** * A map preview component * */ class gui_map_preview_t : public gui_component_t { private: array2d_tpl *map_data; public: gui_map_preview_t(); void set_map_data(array2d_tpl *map_data_par) { map_data = map_data_par; } /** * Draws the component. */ void draw(scr_coord offset) OVERRIDE { display_ddd_box_clip_rgb(pos.x + offset.x, pos.y + offset.y, size.w, size.h, color_idx_to_rgb(MN_GREY0), color_idx_to_rgb(MN_GREY4)); if(map_data) { display_array_wh(pos.x + offset.x + 1, pos.y + offset.y + 1, map_data->get_width(), map_data->get_height(), map_data->to_array()); } } scr_size get_min_size() const OVERRIDE { return scr_size(MAP_PREVIEW_SIZE_X, MAP_PREVIEW_SIZE_Y); } scr_size get_max_size() const OVERRIDE { return scr_size(MAP_PREVIEW_SIZE_X, MAP_PREVIEW_SIZE_Y); } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_numberinput.cc000066400000000000000000000226771474050137200251010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_numberinput.h" #include "../gui_frame.h" #include "../simwin.h" #include "../../display/simgraph.h" #include "../../macros.h" #include "../../dataobj/translator.h" uint32 log10( uint32 ); // simrandom.h char gui_numberinput_t::tooltip[256]; gui_numberinput_t::gui_numberinput_t() : gui_component_t(true) { bt_left.set_typ(button_t::repeatarrowleft ); bt_left.set_pos( scr_coord(0,2) ); bt_left.add_listener(this ); textinp.set_alignment( ALIGN_RIGHT ); textinp.set_color( SYSCOL_EDIT_TEXT ); textinp.add_listener( this ); bt_right.set_typ(button_t::repeatarrowright ); bt_right.add_listener(this ); set_limits(0, 9999); textbuffer[0] = 0; // start with empty buffer value = 0; textinp.set_text(textbuffer, 20); set_increment_mode( 1 ); wrap_mode( true ); b_enabled = true; no_tooltip = false; digits = 5; set_size( scr_size( D_BUTTON_WIDTH, D_EDIT_HEIGHT ) ); } void gui_numberinput_t::set_size(scr_size size_par) { gui_component_t::set_size(size_par); textinp.set_size( scr_size( size_par.w - bt_left.get_size().w - bt_right.get_size().w - D_H_SPACE, size_par.h) ); bt_left.set_pos( scr_coord(0,(size.h-D_ARROW_LEFT_HEIGHT)/2) ); textinp.align_to( &bt_left, scr_coord( D_H_SPACE / 2, 0) ); bt_right.align_to( &textinp, scr_coord( D_H_SPACE / 2, 0) ); } scr_size gui_numberinput_t::get_max_size() const { return get_min_size(); } scr_size gui_numberinput_t::get_min_size() const { return scr_size(max_numbertext_width + D_ARROW_LEFT_WIDTH + D_ARROW_RIGHT_WIDTH + 2*D_H_SPACE, max(LINESPACE+4, max( max(D_ARROW_LEFT_HEIGHT, D_ARROW_RIGHT_HEIGHT), D_EDIT_HEIGHT)) ); } void gui_numberinput_t::set_value(sint32 new_value) { // range check value = clamp( new_value, min_value, max_value ); gui_frame_t *win = win_get_top(); if( win && win->get_focus()!=this ) { // final value should be correct, but during editing wrong values are allowed new_value = value; } // To preserve cursor position if text was edited, only set new text if changed (or empty before) if( textbuffer[0]<32 || new_value != get_text_value() ) { sprintf(textbuffer, "%d", new_value); textinp.set_text(textbuffer, 20); } textinp.set_color( value == new_value ? (b_enabled ? SYSCOL_EDIT_TEXT : SYSCOL_EDIT_TEXT_DISABLED) : color_idx_to_rgb(COL_RED) ); value = new_value; } sint32 gui_numberinput_t::get_text_value() { return (sint32)atol( textinp.get_text() ); } sint32 gui_numberinput_t::get_value() { return clamp( value, min_value, max_value ); } bool gui_numberinput_t::check_value(sint32 _value) { return (_value >= min_value) && (_value <= max_value); } void gui_numberinput_t::set_limits(sint32 _min, sint32 _max) { min_value = _min; max_value = _max; // minus sign max_numbertext_width = (min_value > 0) ? 0 : display_get_char_width('-'); // count digits uint32 max_abs = max_value > 0 ? max_value : -max_value; if (min_value < 0 && (uint32) (-min_value) > max_abs) { max_abs = -min_value; } // width of digits while (max_abs) { max_numbertext_width += display_get_number_width(); max_abs /= 10; } // enforce a min width of 5 digits if (max_numbertext_width < 5 * display_get_number_width()) { max_numbertext_width = 5 * display_get_number_width(); } } bool gui_numberinput_t::action_triggered( gui_action_creator_t *comp, value_t /* */) { if( comp == &textinp ) { // .. if enter / esc pressed set_value( get_text_value() ); if(check_value(value)) { call_listeners(value_t(value)); } } else if( comp == &bt_left || comp == &bt_right ) { // value changed and feasible sint32 new_value = (comp == &bt_left) ? get_prev_value() : get_next_value(); if( new_value!=value ) { set_value( new_value ); if(check_value(new_value)) { // check for valid change - call listeners call_listeners(value_t(value)); } } } return false; } static const sint8 load_percents[7] = { 0, 1, 5, 10, 20, 50, 100 }; sint32 gui_numberinput_t::get_next_value() { if( value>=max_value ) { // turn over return (wrapping && value==max_value) ? min_value : max_value; } switch( step_mode ) { // automatic linear case AUTOLINEAR: { sint64 diff = (sint64)max_value - (sint64)min_value; sint32 one_percent = (sint32) (diff / 100l); return clamp( value+max(1,one_percent), min_value, max_value ); } // power of 2 case POWER2: { sint32 new_value=1; for( int i=0; i<32; i++ ) { if( value<(new_value<=0; i-- ) { if( value>(new_value<=0; i-- ) { if( value-min_value > ((diff*load_percents[i])/100l) ) { return min_value+(sint32)((diff*load_percents[i])/100l); } } return min_value; } // default value is step size default: return clamp( value-step_mode, min_value, max_value ); } } // all init in one ... void gui_numberinput_t::init( sint32 value, sint32 min, sint32 max, sint32 mode, bool wrap, uint16 digits_, bool tooltip ) { set_limits( min, max ); set_value( value ); set_increment_mode( mode ); wrap_mode( wrap ); allow_tooltip(tooltip); digits = digits_; } bool gui_numberinput_t::infowin_event(const event_t *ev) { // no action if disabled if (!b_enabled) { return false; } // buttons pressed if( bt_left.getroffen(ev->click_pos) && ev->ev_code == MOUSE_LEFTBUTTON ) { event_t ev2 = *ev; ev2.move_origin(bt_left.get_pos()); return bt_left.infowin_event(&ev2); } else if( bt_right.getroffen(ev->click_pos) && ev->ev_code == MOUSE_LEFTBUTTON ) { event_t ev2 = *ev; ev2.move_origin(bt_right.get_pos()); return bt_right.infowin_event(&ev2); } else if( ev->ev_class == INFOWIN && ev->ev_code == WIN_UNTOP ) { // losing focus set_value( get_text_value() ); // just to be sure, value may be the same call_listeners(value_t(value)); return false; } else { // since button have different callback ... bool result = false; sint32 new_value = value; // mouse wheel -> fast increase / decrease if (getroffen(ev->mouse_pos + this->pos)) { if(IS_WHEELUP(ev)) { new_value = get_next_value(); result = true; } else if(IS_WHEELDOWN(ev)){ new_value = get_prev_value(); result = true; } } // catch non-number keys if( ev->ev_class == EVENT_KEYBOARD || value==new_value ) { // assume false input bool call_textinp = ev->ev_class != EVENT_KEYBOARD; // editing keys, arrows, hom/end switch (ev->ev_code) { case '-': call_textinp = min_value <0; break; case 1: // allow Ctrl-A (select all text) to function case 3: // allow Ctrl-C (copy text to clipboard) case 8: case 9: // allow text input to handle unfocus event case 22: // allow Ctrl-V (paste text from clipboard) case 24: // allow Ctrl-X (cut text and copy to clipboard) case 127: case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case SIM_KEY_LEFT: case SIM_KEY_RIGHT: case SIM_KEY_HOME: case SIM_KEY_END: call_textinp = true; break; case SIM_KEY_UP: case SIM_KEY_DOWN: // next/previous choice new_value = (ev->ev_code==SIM_KEY_DOWN) ? get_prev_value() : get_next_value(); } if( call_textinp ) { event_t ev2 = *ev; ev2.move_origin(textinp.get_pos()); result = textinp.infowin_event(&ev2); new_value = get_text_value(); } } // value changed and feasible if( new_value!=value ) { set_value( new_value ); if(check_value(new_value)) { // check for valid change - call listeners call_listeners(value_t(value)); result = true; } } return result; } } /** * Draw the component */ void gui_numberinput_t::draw(scr_coord offset) { scr_coord new_offset = pos+offset; bt_left.draw(new_offset); textinp.display_with_focus( new_offset, (win_get_focus()==this) ); bt_right.draw(new_offset); if(!no_tooltip && getroffen( get_mouse_pos() - offset )) { sprintf( tooltip, translator::translate("enter a value between %i and %i"), min_value, max_value ); const scr_coord tooltip_base_pos{ get_mouse_pos().x, new_offset.y + size.h }; win_set_tooltip(tooltip_base_pos + TOOLTIP_MOUSE_OFFSET, tooltip, this); } } simutrans-124.3/src/simutrans/gui/components/gui_numberinput.h000066400000000000000000000056641474050137200247400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_NUMBERINPUT_H #define GUI_COMPONENTS_GUI_NUMBERINPUT_H #include "../../simtypes.h" #include "../../display/scr_coord.h" #include "action_listener.h" #include "gui_action_creator.h" #include "gui_textinput.h" #include "gui_button.h" #include "../gui_theme.h" /** * An input field for integer numbers (with arrow buttons for dec/inc) */ class gui_numberinput_t : public gui_action_creator_t, public gui_component_t, public action_listener_t { private: bool check_value(sint32 _value); scr_coord_val max_numbertext_width; // more sophisticated increase routines sint32 get_prev_value(); sint32 get_next_value(); // transformation char* -> int sint32 get_text_value(); // the input field gui_textinput_t textinp; // arrow buttons for increasing / decr. button_t bt_left, bt_right; sint32 value; sint32 min_value, max_value; // number of digits, // used to determine min size uint16 digits; char textbuffer[20]; sint32 step_mode; bool wrapping : 1; bool b_enabled : 1; bool no_tooltip : 1; // since only the last will prevail static char tooltip[256]; public: gui_numberinput_t(); void set_size(scr_size size) OVERRIDE; // all init in one ... void init( sint32 value, sint32 min, sint32 max, sint32 mode = 1, bool wrap = true, uint16 digits = 5, bool tooltip=true); /** * sets and get the current value. * return current value (or min or max in currently set to outside value) */ sint32 get_value(); void set_value(sint32); /** * digits: length of textbuffer */ void set_limits(sint32 _min, sint32 _max); enum { AUTOLINEAR = 0, POWER2 = -1, PROGRESS = -2 }; /** * AUTOLINEAR: linear increment, scroll wheel 1% range * POWER2: 16, 32, 64, ... * PROGRESS: 0, 1, 5, 10, 25, 50, 75, 90, 95, 99, 100% of range * any other mode value: actual step size */ void set_increment_mode( sint32 m ) { step_mode = m; } // true, if the component wraps around bool wrap_mode( bool new_mode ) { bool m=wrapping; wrapping=new_mode; return m; } bool infowin_event(event_t const*) OVERRIDE; void draw(scr_coord offset) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void enable() { b_enabled = true; set_focusable(true); bt_left.enable(); bt_right.enable(); set_value(value); } void disable() { b_enabled = false; set_focusable(false); bt_left.disable(); bt_right.disable(); set_value(value); } bool enabled() const { return b_enabled; } bool is_focusable() OVERRIDE { return b_enabled && gui_component_t::is_focusable(); } void enable( bool yesno ) { if( yesno && !gui_component_t::is_focusable() ) { enable(); } else if( !yesno && gui_component_t::is_focusable() ) { disable(); } } void allow_tooltip(bool b) { no_tooltip = !b; } scr_size get_max_size() const OVERRIDE; scr_size get_min_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_obj_view.cc000066400000000000000000000011641474050137200243210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_obj_view.h" #include "../../vehicle/air_vehicle.h" obj_view_t::obj_view_t(obj_t const* d, scr_size const size) : world_view_t(size), obj(d) { set_size(size); } void obj_view_t::set_size(scr_size size) { sint16 max_dy_off = 5; if( obj ) { air_vehicle_t const* const plane = obj_cast(obj); if( plane ) { max_dy_off = 11; } } gui_component_t::set_size(size); world_view_t::calc_offsets(size, max_dy_off); } koord3d obj_view_t::get_location() { return obj->get_pos(); } simutrans-124.3/src/simutrans/gui/components/gui_obj_view.h000066400000000000000000000015331474050137200241630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_OBJ_VIEW_H #define GUI_COMPONENTS_GUI_OBJ_VIEW_H #include "gui_world_view.h" class obj_t; /** * Displays a thing on the world */ class obj_view_t : public world_view_t { private: obj_t const *obj; /**< The object to display */ protected: koord3d get_location() OVERRIDE; public: obj_view_t(scr_size const size) : world_view_t(size), obj(NULL) {} obj_view_t(obj_t const *d, scr_size const size); obj_t const *get_obj() const { return obj; } void set_obj( obj_t const *d ) { obj = d; } void draw(scr_coord offset) OVERRIDE { internal_draw(offset, obj); } /** * resize window in response to a resize event * need to recalculate the list of offsets */ void set_size(scr_size size) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_schedule.cc000066400000000000000000000556751474050137200243310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simline.h" #include "../../simcolor.h" #include "../../simintr.h" #include "../../simhalt.h" #include "../../world/simworld.h" #include "../../tool/simmenu.h" #include "../../simconvoi.h" #include "../../display/simgraph.h" #include "../../display/viewport.h" #include "../../utils/simstring.h" #include "../../utils/cbuffer.h" #include "../../ground/grund.h" #include "../../obj/zeiger.h" #include "../../dataobj/schedule.h" #include "../../dataobj/loadsave.h" #include "../../dataobj/translator.h" #include "../../dataobj/environment.h" #include "../../player/simplay.h" #include "../../tpl/vector_tpl.h" #include "gui_button.h" #include "gui_image.h" #include "gui_textarea.h" #include "gui_timeinput.h" #include "gui_component.h" #include "gui_schedule.h" static karte_ptr_t welt; #define DELETE_FLAG (0x8000) #define UP_FLAG (0x4000) #define DOWN_FLAG (0x2000) /** * One entry in the list of schedule entries. */ class gui_schedule_entry_t : public gui_aligned_container_t, public gui_action_creator_t, public action_listener_t { schedule_entry_t entry; bool is_current; uint number; player_t* player; gui_label_buf_t stop; button_t arrow, up, down, del; gui_label_buf_t stop_extra; bool valid; public: gui_schedule_entry_t(player_t* pl, schedule_entry_t e, uint n) { player = pl; entry = e; number = n; is_current = false; valid = true; set_table_layout(6,1); arrow.init( button_t::posbutton_automatic, "" ); up.init( button_t::arrowup, "" ); up.add_listener( this ); down.init( button_t::arrowdown, "" ); down.add_listener( this ); add_component(&arrow); add_component(&stop); add_component(&up); add_component(&down); del.init( button_t::imagebox, NULL ); del.set_image( skinverwaltung_t::gadget->get_image_id(SKIN_GADGET_CLOSE) ); del.set_size( gui_theme_t::gui_arrow_left_size ); del.add_listener( this ); del.set_tooltip( "Delete the current stop" ); add_component( &del ); add_component(&stop_extra); update_label(); } void update_label() { arrow.set_targetpos3d(entry.pos); stop.buf().printf("%i) ", number+1); schedule_t::gimme_stop_name(stop.buf(), welt, player, entry, -1); stop.update(); if( haltestelle_t::get_halt( entry.pos, player ).is_bound() ) { if( !entry.get_absolute_departures() ) { if (entry.minimum_loading > 0) { if( entry.waiting_time > 0 ) { // relative waiting time stop_extra.buf().printf( "(%d%% %s%s)", (int)entry.minimum_loading, translator::translate( "in " ), difftick_to_string( entry.get_waiting_ticks(), false ) ); } else { stop_extra.buf().printf( "(%i%%)", entry.minimum_loading ); } } } else { // absolute departure time uint16 i = 0; uint32 starttick = entry.get_waiting_ticks(); uint32 delta = welt->ticks_per_world_month/entry.get_absolute_departures(); stop_extra.buf().append( tick_to_string( starttick, true ) ); while( ++i < entry.get_absolute_departures() ) { stop_extra.buf().append( ", " ); stop_extra.buf().append( tick_to_string( starttick+i*delta, true ) ); } } } stop_extra.update(); list_dirty = false; // or the first mouseclick will be swallowed! } void draw(scr_coord offset) OVERRIDE { update_label(); if (is_current || !valid) { display_fillbox_wh_clip_rgb(pos.x + offset.x, pos.y + offset.y, size.w, size.h, valid ? SYSCOL_LIST_BACKGROUND_SELECTED_F : MONEY_MINUS, false); } gui_aligned_container_t::draw(offset); } void set_active(bool yesno) { is_current = yesno; stop.set_color(yesno ? SYSCOL_TEXT_HIGHLIGHT : SYSCOL_TEXT); stop_extra.set_color(yesno ? SYSCOL_TEXT_HIGHLIGHT : SYSCOL_TEXT); } bool action_triggered( gui_action_creator_t *c, value_t ) OVERRIDE { if( c == &up ) { call_listeners( UP_FLAG | number ); return true; } if( c == &down ) { call_listeners( DOWN_FLAG | number ); return true; } if( c == &del ) { call_listeners( DELETE_FLAG | number ); return true; } return false; } bool infowin_event(const event_t *ev) OVERRIDE { if( IS_RIGHTRELEASE(ev) ) { // just center on it welt->get_viewport()->change_world_position( entry.pos ); return true; } else if(ev->button_state==1 ){ set_focus( this ); if( !gui_aligned_container_t::infowin_event( ev ) && stop.getroffen( ev->click_pos ) ) { // not handled, so we make i aktive call_listeners( number ); } return true; } return gui_aligned_container_t::infowin_event(ev); } void mark_valid(bool valid) { this->valid = valid; } }; /** * List of displayed schedule entries. */ class schedule_gui_stats_t : public gui_aligned_container_t, public action_listener_t, public gui_action_creator_t { static cbuffer_t buf; vector_tpl entries; schedule_t *last_schedule; ///< last displayed schedule zeiger_t *current_stop_mark; ///< mark current stop on map bool invalid_entries; public: schedule_t *schedule; ///< schedule under editing player_t* player; schedule_gui_stats_t() { set_table_layout(1,0); last_schedule = schedule = NULL; invalid_entries = false; current_stop_mark = new zeiger_t(koord3d::invalid, NULL ); current_stop_mark->set_image( tool_t::general_tool[TOOL_SCHEDULE_ADD]->cursor ); } ~schedule_gui_stats_t() { delete current_stop_mark; delete last_schedule; } // shows/deletes highlighting of tiles void highlight_schedule(bool marking) { marking &= env_t::visualize_schedule; for(schedule_entry_t const& i : schedule->entries) { if (grund_t* const gr = welt->lookup(i.pos)) { for( uint idx=0; idxobj_count(); idx++ ) { obj_t *obj = gr->obj_bei(idx); if( marking ) { if( !obj->is_moving() ) { obj->set_flag( obj_t::highlight ); } } else { obj->clear_flag( obj_t::highlight ); } } gr->set_flag( grund_t::dirty ); // here on water if( gr->is_water() || gr->ist_natur() ) { if( marking ) { gr->set_flag( grund_t::marked ); } else { gr->clear_flag( grund_t::marked ); } } } } // always remove if( grund_t *old_gr = welt->lookup(current_stop_mark->get_pos()) ) { current_stop_mark->mark_image_dirty( current_stop_mark->get_image(), 0 ); old_gr->obj_remove( current_stop_mark ); old_gr->set_flag( grund_t::dirty ); current_stop_mark->set_pos( koord3d::invalid ); } // add if required if( marking && schedule->get_current_stop() < schedule->get_count() ) { current_stop_mark->set_pos( schedule->entries[schedule->get_current_stop()].pos ); if( grund_t *gr = welt->lookup(current_stop_mark->get_pos()) ) { gr->obj_add( current_stop_mark ); current_stop_mark->set_flag( obj_t::dirty ); gr->set_flag( grund_t::dirty ); } } current_stop_mark->clear_flag( obj_t::highlight ); } void update_schedule(bool highlight) { // compare schedules bool ok = (last_schedule != NULL) && last_schedule->entries.get_count() == schedule->entries.get_count(); for(uint i=0; ok && ientries.get_count(); i++) { ok = last_schedule->entries[i] == schedule->entries[i]; } if (ok) { if (!last_schedule->empty()) { entries[ last_schedule->get_current_stop() ]->set_active(false); entries[ schedule->get_current_stop() ]->set_active(true); last_schedule->set_current_stop( schedule->get_current_stop() ); } } else { remove_all(); entries.clear(); invalid_entries = false; buf.clear(); buf.append(translator::translate("Please click on the map to add\nwaypoints or stops to this\nschedule.")); if (schedule->empty()) { new_component(&buf); } else { for(uint i=0; ientries.get_count(); i++) { gui_schedule_entry_t* entry = new_component(player, schedule->entries[i], i); // mark double entries as invalid bool valid = (schedule->entries[i].pos != schedule->entries[ (i+1) % schedule->entries.get_count() ].pos) && (schedule->entries[i].pos != schedule->entries[ (i-1+schedule->entries.get_count()) % schedule->entries.get_count() ].pos); entry->mark_valid(valid); entry->add_listener( this ); entries.append(entry); invalid_entries |= schedule->entries.get_count() > 1 && !valid; } entries[ schedule->get_current_stop() ]->set_active(true); } if (last_schedule) { last_schedule->copy_from(schedule); } else { last_schedule = schedule->copy(); } set_size(get_min_size()); call_listeners( schedule->get_current_stop() ); } if (highlight) { highlight_schedule(true); } } void draw(scr_coord offset) OVERRIDE { if( schedule ) { update_schedule(true); } gui_aligned_container_t::draw(offset); } bool action_triggered(gui_action_creator_t *, value_t v) OVERRIDE { // has to be one of the entries if( v.i & DELETE_FLAG ) { uint8 delete_stop = v.i & 0x00FF; highlight_schedule( false ); schedule->remove_entry( delete_stop ); highlight_schedule( true ); call_listeners( schedule->get_current_stop() ); } else if( v.i & UP_FLAG ) { uint8 up_stop = v.i & 0x00FF; schedule->move_entry_backward( up_stop ); call_listeners( schedule->get_current_stop() ); } else if( v.i & DOWN_FLAG ) { uint8 down_stop = v.i & 0x00FF; schedule->move_entry_forward( down_stop ); call_listeners( schedule->get_current_stop() ); } else { call_listeners(v); } return true; } bool has_invalid_entries() const { return invalid_entries; } }; cbuffer_t schedule_gui_stats_t::buf; schedule_t *gui_schedule_t::get_old_schedule() const { if( convoi_mode.is_bound() ) { return convoi_mode->get_schedule(); } else if( line_mode.is_bound() ) { return line_mode->get_schedule(); } return old_schedule; } void gui_schedule_t::highlight_schedule( bool hl ) { stats->highlight_schedule(hl); update_tool(hl); } gui_schedule_t::gui_schedule_t() : stats( new schedule_gui_stats_t() ), scrolly( stats ), departure( NULL ) { scrolly.set_maximize( true ); old_schedule = schedule = NULL; player = NULL; set_table_layout(1,0); // loading level and waiting time loading_details = add_table( 3, 3 ); loading_details->set_margin( scr_size(D_MARGIN_LEFT,0), scr_size(D_MARGIN_RIGHT,0) ); { add_component(&cb_wait,2); cb_wait.add_listener( this ); cb_wait.new_component( translator::translate( "Full load" ), SYSCOL_TEXT ); cb_wait.new_component( translator::translate( "Monthly departures" ), SYSCOL_TEXT ); cb_wait.set_rigid(true); new_component(); add_component(&lb_load_str); lb_load_str.set_rigid(true); numimp_load.add_listener(this); numimp_load.set_rigid(true); add_component(&numimp_load); new_component(); add_component(&lb_departure_str); lb_departure_str.set_rigid(true); departure.set_rigid(true); departure.add_listener(this); add_component(&departure); new_component(); } end_table(); // action button row button_row = add_table( 3, 1 ); button_row->set_margin( scr_size(D_MARGIN_LEFT,0), scr_size(D_MARGIN_RIGHT,0) ); { insert_mode.new_component(translator::translate("Ins Stop"), SYSCOL_TEXT); insert_mode.new_component(translator::translate("Add Stop"), SYSCOL_TEXT); insert_mode.set_selection( 1 ); insert_mode.add_listener(this); add_component(&insert_mode); bt_revert.init(button_t::roundbox | button_t::flexible, "Revert schedule"); bt_revert.set_tooltip("Revert to original schedule"); bt_revert.add_listener(this); bt_revert.pressed = false; bt_revert.enable(false); // schedule was not changed yet add_component(&bt_revert); bt_return.init(button_t::roundbox | button_t::flexible, "return ticket"); bt_return.add_listener(this); add_component(&bt_return); bt_remove_double.init(button_t::roundbox | button_t::flexible, "Cleanup schedule"); bt_remove_double.set_tooltip("Remove double stops from schedule"); bt_remove_double.add_listener(this); bt_remove_double.set_visible(false); add_component(&bt_remove_double); } end_table(); scrolly.set_show_scroll_x(true); scrolly.set_scroll_amount_y(LINESPACE+1); add_component(&scrolly); stats->add_listener(this); current_schedule_rotation = welt->get_settings().get_rotation(); scrolly.set_maximize(true); set_size( gui_aligned_container_t::get_min_size() ); } gui_schedule_t::~gui_schedule_t() { stats->highlight_schedule( false ); update_tool(false); delete stats; delete schedule; } void gui_schedule_t::init(schedule_t* schedule_, player_t* player, convoihandle_t cnv, linehandle_t lin, bool force) { if( force || old_schedule != schedule_ ) { if( old_schedule ) { stats->highlight_schedule( false ); update_tool( false ); } // initialization this->convoi_mode = cnv; this->line_mode = lin; this->player = player; current_schedule_rotation = welt->get_settings().get_rotation(); // prepare editing if (schedule != schedule_) { delete schedule; } schedule = schedule_->copy(); make_return = (schedule->get_waytype() == road_wt || schedule->get_waytype() == air_wt || schedule->get_waytype() == water_wt); if( make_return ) { // return tickets bt_return.set_text("return ticket"); bt_return.set_tooltip("Add stops for backward travel"); } else { bt_return.set_text("Invert stops"); bt_return.set_tooltip("Mirrors order of stops"); } stats->player = player; stats->schedule = schedule; stats->update_schedule(false); numimp_load.set_value( schedule->get_current_entry().minimum_loading ); // not allow to change entries beyond waiting time no_editing = (convoi_mode.is_bound() && line_mode.is_bound()); bt_return.enable( !no_editing ); update_selection(); this->old_schedule = schedule_; } else { schedule->set_current_stop(schedule_->get_current_stop()); update_selection(); } set_size(gui_aligned_container_t::get_min_size()); } void gui_schedule_t::update_tool(bool set) { if (set) { uint16 toolnr = insert_mode.get_selection() == 0 ? TOOL_SCHEDULE_INS : TOOL_SCHEDULE_ADD; tool_t::general_tool[toolnr]->set_default_param((const char *)schedule); welt->set_tool(tool_t::general_tool[toolnr], player ); } else { // we have to reset the tool (in particular, when window closes) if(welt->get_tool(player->get_player_nr())==tool_t::general_tool[TOOL_SCHEDULE_ADD]) { if(tool_t::general_tool[TOOL_SCHEDULE_ADD]->get_default_param()==(const char *)schedule) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); } } else if(welt->get_tool(player->get_player_nr())==tool_t::general_tool[TOOL_SCHEDULE_INS]) { if(tool_t::general_tool[TOOL_SCHEDULE_INS]->get_default_param()==(const char *)schedule) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); } } } } void gui_schedule_t::update_selection() { // set all elements invisible first cb_wait.set_visible(false); numimp_load.set_visible(false); departure.set_visible(false); lb_load_str.set_visible(false); lb_departure_str.set_visible(false); if( !schedule->empty() ) { schedule->set_current_stop( min(schedule->get_count()-1,schedule->get_current_stop()) ); const uint8 current_stop = schedule->get_current_stop(); if( haltestelle_t::get_halt(schedule->entries[current_stop].pos, player).is_bound() ) { cb_wait.set_visible(true); if( schedule->entries[current_stop].get_absolute_departures() ) { cb_wait.set_selection( 1 ); lb_load_str.set_visible(true); lb_load_str.set_text("Departures per month"); numimp_load.set_visible( true ); numimp_load.set_value( schedule->entries[current_stop].get_absolute_departures() ); numimp_load.set_limits( 1, 154 ); numimp_load.set_increment_mode( 1 ); lb_departure_str.set_visible( true ); lb_departure_str.set_text( "Departs at" ); departure.set_visible( true ); departure.set_ticks( schedule->entries[current_stop].waiting_time, true); } else { cb_wait.set_selection( 0 ); lb_load_str.set_visible(true); lb_load_str.set_text("Minimum load"); numimp_load.set_visible( true ); numimp_load.set_value( schedule->entries[current_stop].minimum_loading ); numimp_load.set_limits( 0, 100 ); numimp_load.set_increment_mode( gui_numberinput_t::PROGRESS ); lb_departure_str.set_text( "Max. waiting time" ); lb_departure_str.set_visible( true ); departure.set_visible( true ); departure.set_ticks( schedule->entries[current_stop].waiting_time, false ); } } else { // waypoint } } loading_details->set_size( loading_details->get_size() ); set_size(size); } bool gui_schedule_t::action_triggered( gui_action_creator_t *comp, value_t p) { if (comp == &bt_revert) { // revert changes and tell listener if (schedule) { stats->highlight_schedule(false); delete schedule; schedule = NULL; } schedule = get_old_schedule()->copy(); stats->schedule = schedule; stats->update_schedule(true); update_selection(); value_t v; v.p = NULL; call_listeners(v); } else if( comp == &bt_remove_double) { schedule->remove_double_entries(); stats->update_schedule(true); update_selection(); } else if( comp == &cb_wait) { if( p.i==1 && schedule->entries[schedule->get_current_stop()].get_absolute_departures()==0 ) { // absolute departure mode schedule->entries[schedule->get_current_stop()].minimum_loading = 101; } if( p.i==0 && schedule->entries[schedule->get_current_stop()].get_absolute_departures() ) { schedule->entries[schedule->get_current_stop()].minimum_loading = 0; } update_selection(); } else if( comp == &numimp_load ) { if (!schedule->empty()) { if( schedule->entries[schedule->get_current_stop()].minimum_loading <=100 ) { schedule->entries[schedule->get_current_stop()].minimum_loading = min( (uint8)p.i, 100 ); } else { schedule->entries[schedule->get_current_stop()].minimum_loading = max( 101, min(255,(uint8)p.i+100) ); // clip waiting time to 1/nth of the month if( schedule->entries[schedule->get_current_stop()].waiting_time>65535/(schedule->entries[schedule->get_current_stop()].minimum_loading-100) ) { schedule->entries[schedule->get_current_stop()].waiting_time=65535/(schedule->entries[schedule->get_current_stop()].minimum_loading-100); } } update_selection(); } } else if(comp == &departure) { if(!schedule->empty()) { schedule->entries[schedule->get_current_stop()].waiting_time = (uint16)p.i; // clip waiting time to 1/nth of the month if absolute departure time uint16 wt = schedule->entries[schedule->get_current_stop()].minimum_loading; if( wt>100 && schedule->entries[schedule->get_current_stop()].waiting_time>65535/(wt-100) ) { schedule->entries[schedule->get_current_stop()].waiting_time = 65535/(wt-100); } update_selection(); } } else if(comp == &bt_return) { schedule->add_return_way(make_return); } else if (comp == stats) { // click on one of the schedule entries const int line = p.i; if( line >= 0 && line < schedule->get_count() ) { schedule->set_current_stop( line ); update_selection(); } else if (schedule->empty()) { update_selection(); } } // do not reset tool during initialisation if (old_schedule) { update_tool(true); } return true; } void gui_schedule_t::draw(scr_coord pos) { if( schedule ) { // check if we missed a map rotation const uint8 world_rotation = world()->get_settings().get_rotation(); while( current_schedule_rotation != world_rotation ) { current_schedule_rotation = (current_schedule_rotation + 1) % 4; schedule->rotate90( (4+current_schedule_rotation - world_rotation) & 1 ? world()->get_size().y-1 : world()->get_size().x-1 ); } schedule_t *scd = get_old_schedule(); // change current entry while convois drives on koord3d current = scd->get_current_entry().pos; int idx = 0; bool is_allowed = player==welt->get_active_player() && !welt->get_active_player()->is_locked(); bool is_all_same = scd->get_count()==schedule->get_count(); is_all_same &= scd->get_current_stop() == schedule->get_current_stop(); is_all_same &= !(convoi_mode.is_bound() && line_mode.is_bound() && line_mode != convoi_mode->get_line()); for(schedule_entry_t ent : schedule->entries ) { #if 0 if( ent.pos == current ) { schedule->set_current_stop( idx ); } #else (void)current; (void)ent; #endif if( is_all_same ) { is_all_same = scd->entries[idx] == schedule->entries[idx]; } idx++; } bt_revert.enable( !is_all_same && is_allowed ); cb_wait.enable( is_allowed ); numimp_load.enable( is_allowed ); departure.enable( is_allowed ); bt_return.enable( is_allowed ); bool invalid = stats->has_invalid_entries(); bt_return.set_visible(!invalid); bt_remove_double.set_visible(invalid); button_row->set_size(button_row->get_size()); } // always dirty, to cater for shortening of halt names and change of selections gui_aligned_container_t::draw(pos); } /** * Set window size and adjust component sizes and/or positions accordingly */ void gui_schedule_t::set_size(scr_size size) { gui_aligned_container_t::set_size(size); size = get_size(); // make scrolly take all of space scrolly.set_size( scr_size(scrolly.get_size().w, get_size().h - scrolly.get_pos().y)); } void gui_schedule_t::rdwr(loadsave_t *file) { // convoy data convoi_t::rdwr_convoihandle_t(file, convoi_mode); simline_t::rdwr_linehandle_t(file, line_mode); departure.rdwr( file ); if( file->is_loading() ) { uint16 schedule_type, player_nr; schedule_t *load_schedule; file->rdwr_short(player_nr); player = welt->get_player(player_nr); file->rdwr_short(schedule_type); switch (schedule_type) { case schedule_t::truck_schedule: load_schedule = new truck_schedule_t(); break; case schedule_t::train_schedule: load_schedule = new train_schedule_t(); break; case schedule_t::ship_schedule: load_schedule = new ship_schedule_t(); break; case schedule_t::airplane_schedule: load_schedule = new airplane_schedule_t(); break; case schedule_t::monorail_schedule: load_schedule = new monorail_schedule_t(); break; case schedule_t::tram_schedule: load_schedule = new maglev_schedule_t(); break; case schedule_t::maglev_schedule: load_schedule = new truck_schedule_t(); break; case schedule_t::narrowgauge_schedule: load_schedule = new narrowgauge_schedule_t(); break; default: load_schedule = new train_schedule_t(); dbg->error("schedule_gui_t::rdwr", "Could not restore schedule window for generic schdule"); load_schedule->rdwr(file); delete load_schedule; return; } load_schedule->rdwr( file ); init(load_schedule, player, convoi_mode, line_mode); delete load_schedule; get_min_size(); set_size(size); } else { uint16 schedule_type = schedule->get_type(); uint16 player_nr = player->get_player_nr(); file->rdwr_short(player_nr); file->rdwr_short(schedule_type); schedule->rdwr( file ); } } simutrans-124.3/src/simutrans/gui/components/gui_schedule.h000066400000000000000000000052521474050137200241550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_SCHEDULE_H #define GUI_COMPONENTS_GUI_SCHEDULE_H #include "gui_label.h" #include "gui_numberinput.h" #include "gui_aligned_container.h" #include "gui_button.h" #include "gui_action_creator.h" #include "gui_combobox.h" #include "gui_scrollpane.h" #include "gui_scrolled_list.h" #include "gui_timeinput.h" #include "action_listener.h" #include "../../convoihandle.h" #include "../../linehandle.h" #include "../../tpl/vector_tpl.h" class schedule_t; class player_t; class cbuffer_t; class loadsave_t; class schedule_gui_stats_t; /** * GUI for Schedule dialog */ class gui_schedule_t : public gui_action_creator_t, public gui_aligned_container_t, public action_listener_t { private: // always needed button_t bt_revert, bt_return, bt_remove_double; gui_label_t lb_load_str, lb_departure_str; gui_numberinput_t numimp_load; gui_combobox_t cb_wait, insert_mode; schedule_gui_stats_t* stats; gui_scrollpane_t scrolly; gui_aligned_container_t *loading_details, *button_row; gui_timeinput_t departure; bool make_return; // either reverting line or add mirror bool no_editing; // if convoi schedule is part of a line, if has to be removed from it // set the correct tool now ... void update_tool(bool set); // changes the waiting/loading levels if allowed void update_selection(); schedule_t *get_old_schedule() const; protected: // schedule of this line (or of convoi belonging to this line) is being edited linehandle_t line_mode; // schedule of this convoi is being edited convoihandle_t convoi_mode; // the schedule that is edited, copy of old_schedule schedule_t *schedule; // the original schedule (used to detect calls to init with same original schedule), might be non-null but invalid, do not dereference schedule_t *old_schedule; player_t *player; uint8 current_schedule_rotation; // to detect the rotation of the map independently public: gui_schedule_t(); void init(schedule_t* schedule = NULL, player_t* player = NULL, convoihandle_t cnv = convoihandle_t(), linehandle_t lin = linehandle_t(), bool force=false ); virtual ~gui_schedule_t(); void draw(scr_coord pos) OVERRIDE; // true if the schedule has changed bool has_pending_changes() { return bt_revert.enabled(); } scr_size get_max_size() const OVERRIDE { return scr_size::inf; } void set_size(scr_size size) OVERRIDE; schedule_t *get_schedule() const { return schedule; } void highlight_schedule( bool hl ); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr( loadsave_t *file ); bool is_marginless() const OVERRIDE { return true; } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_scrollbar.cc000066400000000000000000000176751474050137200245160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simdebug.h" #include "../../simcolor.h" #include "../../display/simgraph.h" #include "../../simskin.h" #include "../../macros.h" #include "../../descriptor/skin_desc.h" #include "action_listener.h" #include "gui_scrollbar.h" #include "../gui_theme.h" scrollbar_t::scrollbar_t(type_t type) : type(type), dragging(false), sticky_bottom(false), knob_offset(0), knob_size(10), total_size(20), knob_scroll_amount(LINESPACE), // equals one line knob_scroll_discrete(false) { visible_mode = show_auto; if (type == vertical) { size = scr_size(D_SCROLLBAR_WIDTH,40); // 40 = default scrollbar height button_def[left_top_arrow_index].set_typ(button_t::arrowup); button_def[right_bottom_arrow_index].set_typ(button_t::arrowdown); } else { // horizontal size = scr_size(40,D_SCROLLBAR_HEIGHT); // 40 = default scrollbar length button_def[left_top_arrow_index].set_typ(button_t::arrowleft); button_def[right_bottom_arrow_index].set_typ(button_t::arrowright); } button_def[left_top_arrow_index].set_pos(scr_coord(0,0)); button_def[right_bottom_arrow_index].set_pos(scr_coord(0,0)); reposition_buttons(); } void scrollbar_t::set_size(scr_size size) { if (type == vertical) { this->size.h = size.h; } else { this->size.w = size.w; } reposition_buttons(); } scr_size scrollbar_t::get_min_size() const { if(type == vertical) { scr_size size = D_ARROW_UP_SIZE; size.clip_lefttop(D_ARROW_DOWN_SIZE); size.w = max(size.w, D_SCROLLBAR_WIDTH); size.h += 40; return size; } else { scr_size size = D_ARROW_LEFT_SIZE; size.clip_lefttop(D_ARROW_RIGHT_SIZE); size.h = max(size.h, D_SCROLLBAR_HEIGHT); size.w += 40; return size; } } scr_size scrollbar_t::get_max_size() const { scr_size min_size = get_min_size(); if(type == vertical) { return scr_size(min_size.w, scr_size::inf.h); } else { return scr_size(scr_size::inf.w, min_size.h); } } void scrollbar_t::set_sticky_bottom(bool b) { sticky_bottom = b; reposition_buttons(); } void scrollbar_t::set_knob(sint32 new_visible_size, sint32 new_total_size) { if( new_total_size != total_size ) { knob_offset = (sint32)( (double)knob_offset * ( (double)new_total_size / (double) total_size ) + 0.5 ); } total_size = max(1,new_total_size); knob_size = clamp( new_visible_size, 1, total_size ); knob_offset = clamp( knob_offset, 0, total_size-knob_size ); reposition_buttons(); } // reset variable position and size values of the three buttons void scrollbar_t::reposition_buttons() { const sint32 area = (type == vertical ? max(size.h - D_ARROW_UP_HEIGHT - D_ARROW_DOWN_HEIGHT, 0) : size.w - D_ARROW_LEFT_WIDTH - D_ARROW_RIGHT_WIDTH); // area will be actual area knob can move in if (!sticky_bottom) { knob_offset = clamp(knob_offset, 0, total_size - knob_size); } else { knob_offset = total_size - knob_size; } double size_ratio = (double)knob_size / (double)total_size; scr_coord_val length = min( area, (scr_coord_val)( area*size_ratio+0.5) ); if( type == vertical ) { length = max( length, D_SCROLL_MIN_HEIGHT ); } else { length = max( length, D_SCROLL_MIN_WIDTH ); } double offset_ratio = (double)knob_offset / (double)total_size; int offset = (int)( offset_ratio*area+0.5 ); offset = clamp( offset, 0, area-length ); if(type == vertical) { button_def[left_top_arrow_index].set_pos( scr_coord( (D_SCROLLBAR_WIDTH - D_ARROW_UP_WIDTH)/2, 0) ); button_def[right_bottom_arrow_index].set_pos( scr_coord( (D_SCROLLBAR_WIDTH - D_ARROW_DOWN_WIDTH)/2, max(D_ARROW_UP_HEIGHT+D_SCROLL_MIN_HEIGHT,size.h-D_ARROW_DOWN_HEIGHT) ) ); sliderarea.set( 0, D_ARROW_UP_HEIGHT, D_SCROLLBAR_WIDTH, area ); knobarea.set( 0, D_ARROW_UP_HEIGHT + max(offset,0), D_SCROLLBAR_WIDTH, length ); } else { // horizontal button_def[left_top_arrow_index].set_pos( scr_coord(0,(D_SCROLLBAR_HEIGHT - D_ARROW_LEFT_HEIGHT)/2) ); button_def[right_bottom_arrow_index].set_pos( scr_coord(size.w - D_ARROW_RIGHT_WIDTH, (D_SCROLLBAR_HEIGHT - D_ARROW_RIGHT_HEIGHT)/2) ); sliderarea.set( D_ARROW_LEFT_WIDTH, 0, area, D_SCROLLBAR_HEIGHT ); knobarea.set( D_ARROW_LEFT_WIDTH + offset, 0, length, D_SCROLLBAR_HEIGHT ); } full = (total_size<=knob_size); set_visible( !full ); } // actually handles crolling, callback etc. void scrollbar_t::scroll(sint32 updown) { sint32 new_knob_offset = clamp( knob_offset+updown, 0, total_size-knob_size ); if( new_knob_offset != knob_offset ) { sticky_bottom = false; knob_offset = new_knob_offset; call_listeners((long)knob_offset); reposition_buttons(); } } bool scrollbar_t::infowin_event(const event_t *ev) { const scr_coord click_pos = ev->click_pos; int i; if( IS_WHEELUP(ev) && (type == vertical) != IS_SHIFT_PRESSED(ev) ) { scroll( -knob_scroll_amount ); return true; } else if (IS_WHEELDOWN(ev) && (type == vertical) != IS_SHIFT_PRESSED(ev)) { scroll( +knob_scroll_amount ); return true; } else if( is_visible() && !full ) { // don't respond to these messages if not visible if( IS_LEFTCLICK(ev) ) { if( button_def[0].getroffen(click_pos) ) { button_def[0].pressed = true; scroll( -knob_scroll_amount ); } else if( button_def[1].getroffen(click_pos) ) { button_def[1].pressed = true; scroll( +knob_scroll_amount ); } else if( !dragging ) { // click above/below the slider? if( type == vertical ) { if( click_pos.y < knobarea.y ) { scroll( -knob_size); } else if( click_pos.y > knobarea.get_bottom() ) { scroll( +knob_size ); } else { dragging = true; } } else { if( click_pos.x < knobarea.x ) { scroll( -knob_size ); } else if( click_pos.x > knobarea.get_right() ) { scroll( +knob_size ); } else { dragging = true; } } } return true; } else if( IS_LEFTDRAG(ev) || (dragging && IS_LEFT_BUTTON_PRESSED(ev)) ) { // now dragging the slider ... if( knobarea.contains( click_pos ) || dragging ) { sint32 delta, change; // added vertical/horizontal check if(type == vertical) { delta = ev->mouse_pos.y - ev->click_pos.y; change = (sint32)(delta*( (double)total_size / (double) sliderarea.h ) + 0.5); delta = knobarea.y; scroll( change ); change_drag_start({ 0, knobarea.y-delta }); } else { delta = ev->mouse_pos.x - ev->click_pos.x; change = (sint32)(delta*( (double)total_size / (double) sliderarea.w ) + 0.5); delta = knobarea.x; scroll( change ); change_drag_start({ knobarea.x-delta, 0 }); } dragging = true; return true; } } else if (IS_LEFTRELEASE(ev)) { dragging = false; for (i=0;i<2;i++) { if (button_def[i].getroffen(click_pos)) { button_def[i].pressed = false; return true; } } } } return false; } void scrollbar_t::draw(scr_coord pos_par) { // Don't draw control if not visible if( (visible_mode != show_auto) && (!is_visible() || (visible_mode == show_never) ) ) { return; } pos_par += pos; // Draw place holder if scrollbar is full in auto mode if ( visible_mode == show_auto && full ) { // Draw place holder themed with scrollbar background display_img_stretch( gui_theme_t::v_scroll_back_tiles, scr_rect( pos_par, size ) ); return; } // Draw scrollbar as normal button_def[left_top_arrow_index].draw(pos_par); button_def[right_bottom_arrow_index].draw(pos_par); // now background and slider if( type == vertical ) { display_img_stretch( gui_theme_t::v_scroll_back_tiles, scr_rect( pos_par + sliderarea.get_pos(), sliderarea.get_size() ) ); display_img_stretch( gui_theme_t::v_scroll_knob_tiles, scr_rect( pos_par + knobarea.get_pos(), knobarea.get_size() ) ); } else { display_img_stretch( gui_theme_t::h_scroll_back_tiles, scr_rect( pos_par + sliderarea.get_pos(), sliderarea.get_size() ) ); display_img_stretch( gui_theme_t::h_scroll_knob_tiles, scr_rect( pos_par + knobarea.get_pos(), knobarea.get_size() ) ); } } simutrans-124.3/src/simutrans/gui/components/gui_scrollbar.h000066400000000000000000000056721474050137200243520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_SCROLLBAR_H #define GUI_COMPONENTS_GUI_SCROLLBAR_H #include "gui_action_creator.h" #include "../../simevent.h" #include "gui_button.h" #include "../gui_theme.h" /** * Scrollbar class * scrollbar can be horizontal or vertical */ class scrollbar_t : public gui_action_creator_t, public gui_component_t { public: enum type_t { vertical, ///< Vertical scrollbar horizontal ///< Horizontal scrollbar }; enum visible_mode_t { show_never, ///< Never show the scrollbar show_always, ///< Always show the scrollbar, even at maximum show_disabled, ///< Disable scrollbar at maximum value show_auto ///< Hide scrollbar at maximum value, else show }; private: // private button indexes enum button_element_index { left_top_arrow_index, right_bottom_arrow_index }; type_t type; visible_mode_t visible_mode; // Show, hide or auto hide bool full; // Scrollbar is full bool dragging; // to handle event even when outside the knob ... bool sticky_bottom; // stays at the bottom until first scrolling (default off) // the following three values are from host (e.g. list), NOT actual size. sint32 knob_offset; // offset from top-left sint32 knob_size; sint32 total_size; /** * number of elements to scroll with arrow button press. default: 11 */ sint32 knob_scroll_amount; bool knob_scroll_discrete; // if true, knob_offset forced to be integer multiples of knob_scroll_amount // arrow buttons button_t button_def[2]; // size of button area scr_rect knobarea, sliderarea; void reposition_buttons(); void scroll( sint32 amout_to_scroll ); public: // type is either scrollbar_t::horizontal or scrollbar_t::vertical scrollbar_t(type_t type); void set_size(scr_size size) OVERRIDE; void set_scroll_amount(sint32 sa) { knob_scroll_amount = sa; } void set_scroll_discrete(const bool sd) { knob_scroll_discrete = sd; } /** * knob_size is visible size, total_size is total size (of whatever unit) * Scroolbars are not directly related to pixels! */ void set_knob(sint32 knob_size, sint32 total_size); sint32 get_knob_offset() const { // return clamped offset if really desired return knob_offset - ((knob_scroll_discrete && total_size!=knob_offset+knob_size) ? (knob_offset % knob_scroll_amount) : 0); } bool is_bottom() const { return total_size <= knob_offset + knob_size; } void set_knob_offset(sint32 v) { knob_offset = v; reposition_buttons(); } // repositioning sliders so it is always at the bottom until scrolled once void set_sticky_bottom(bool); void set_visible_mode(visible_mode_t vm) { visible_mode = vm; } visible_mode_t get_visible_mode() { return visible_mode; } bool infowin_event(event_t const*) OVERRIDE; void draw(scr_coord pos) OVERRIDE; scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_scrolled_list.cc000066400000000000000000000226631474050137200253660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "gui_scrollbar.h" #include "gui_scrolled_list.h" #include "../simwin.h" #include "../../display/simgraph.h" #include "../../descriptor/skin_desc.h" #include "../../simskin.h" // help for sorting bool gui_scrolled_list_t::scrollitem_t::compare(const gui_component_t *aa, const gui_component_t *bb ) { const scrollitem_t* a = dynamic_cast(aa); const scrollitem_t* b = dynamic_cast(bb); assert(a && b && a->get_text() != NULL && b->get_text() != NULL); return strcmp(a->get_text(), b->get_text() ); } scr_size gui_scrolled_list_t::const_text_scrollitem_t::get_min_size() const { if (!is_editable()) { const char* text = get_text(); return scr_size(2*D_H_SPACE + (text ? display_calc_proportional_string_len_width(text,strlen(text)) : D_BUTTON_WIDTH), LINESPACE); } else { return scr_size(D_BUTTON_WIDTH, LINESPACE); } } scr_size gui_scrolled_list_t::const_text_scrollitem_t::get_max_size() const { return scr_size(scr_size::inf.w, LINESPACE); } // draws a single line of text void gui_scrolled_list_t::const_text_scrollitem_t::draw(scr_coord pos) { pos += get_pos(); if(selected) { // selected element display_fillbox_wh_clip_rgb( pos.x+D_H_SPACE/2, pos.y-1, get_size().w-D_H_SPACE, get_size().h + 1, (focused ? SYSCOL_LIST_BACKGROUND_SELECTED_F : SYSCOL_LIST_BACKGROUND_SELECTED_NF), true); display_proportional_clip_rgb( pos.x+D_H_SPACE, pos.y, get_text(), ALIGN_LEFT, (focused ? SYSCOL_LIST_TEXT_SELECTED_FOCUS : SYSCOL_LIST_TEXT_SELECTED_NOFOCUS), true); } else { // normal text display_proportional_clip_rgb( pos.x+D_H_SPACE, pos.y, get_text(), ALIGN_LEFT, get_color(), true); } } gui_scrolled_list_t::gui_scrolled_list_t(enum type type, item_compare_func cmp) : gui_scrollpane_t(NULL, true), item_list(container.get_components()) { container.set_table_layout(1,0); set_component(&container); this->type = type; compare = cmp; size = scr_size(0,0); pos = scr_coord(0,0); multiple_selection = false; maximize = false; sliders_dirty = true; } // set the scrollbar offset, so that the selected item is visible void gui_scrolled_list_t::show_selection(int sel) { set_selection(sel); cleanup_elements(); show_focused(); } void gui_scrolled_list_t::set_selection(int s) { if (s<0 || ((uint32)s)>=item_list.get_count()) { container.set_focus(NULL); return; } gui_component_t* new_focus = item_list[s]; // reset selected status for(gui_component_t* v : item_list) { scrollitem_t* item = dynamic_cast(v); if( item ) { item->selected = item==new_focus; } } container.set_focus(new_focus); } sint32 gui_scrolled_list_t::get_selection() const { scrollitem_t* focus = get_selected_item(); return focus ? item_list.index_of(focus) : -1; } gui_scrolled_list_t::scrollitem_t* gui_scrolled_list_t::get_selected_item() const { scrollitem_t* focus = dynamic_cast( comp->get_focus() ); return focus && item_list.is_contained(focus) ? focus : NULL; } vector_tpl gui_scrolled_list_t::get_selections() const { vector_tpl selections; for( uint32 i=0; i (item_list[i]); if( item && item->selected ) { selections.append(i); } } return selections; } void gui_scrolled_list_t::clear_elements() { container.remove_all(); } void gui_scrolled_list_t::sort( int offset ) { cleanup_elements(); if (compare == 0 || item_list.get_count() <= 1) { reset_container_size(); return; } if (offset >=0 && (uint32)offset < item_list.get_count()) { vector_tpl::iterator start = item_list.begin(); for(int i=0; i( comp->get_focus() ); event_t ev2 = *ev; // translate key up/down to tab/shift-tab if( ev->ev_class==EVENT_KEYBOARD && ev->ev_code == SIM_KEY_UP && get_selection()>0) { ev2.ev_code = SIM_KEY_TAB; ev2.ev_key_mod |= SIM_MOD_SHIFT; } if( ev->ev_class==EVENT_KEYBOARD && ev->ev_code == SIM_KEY_DOWN && (uint32)(get_selection()+1) < item_list.get_count()) { ev2.ev_code = SIM_KEY_TAB; ev2.ev_key_mod &= ~SIM_MOD_SHIFT; } bool swallowed = gui_scrollpane_t::infowin_event(&ev2); scrollitem_t* const new_focus = dynamic_cast( comp->get_focus() ); // if different element is focused, calculate selection and call listeners if ( focus != new_focus || (new_focus && IS_LEFTRELEASE(&ev2) && new_focus->getroffen(ev2.mouse_pos)) ) { calc_selection(focus, new_focus, *ev); const int new_selection = get_selection(); call_listeners((long)new_selection); swallowed = true; } return swallowed; } void gui_scrolled_list_t::calc_selection(scrollitem_t* old_focus, scrollitem_t* new_focus, event_t ev) { if( !new_focus ) { // do nothing. return; } else if( !multiple_selection || ev.ev_key_mod==0 ) { // simply select new_focus for(gui_component_t* v : item_list) { scrollitem_t* item = dynamic_cast(v); if( item ) { item->selected = item==new_focus; } } } else if( multiple_selection && IS_CONTROL_PRESSED(&ev) ) { // control key is pressed. select or deselect the focused one. new_focus->selected = !new_focus->selected; } else if( IS_SHIFT_PRESSED(&ev) ) { // shift key is pressed. sint32 old_idx = item_list.index_of(old_focus); sint32 new_idx = item_list.index_of(new_focus); if( old_idx==-1 || new_idx==-1 ) { // out of index!? return; } const bool sel = !new_focus->selected; for( sint32 i=min(old_idx,new_idx); i<=max(old_idx,new_idx); i++ ) { scrollitem_t* item = dynamic_cast(item_list[i]); if( item && i!=old_idx ) { item->selected = sel; } } } } void gui_scrolled_list_t::cleanup_elements(bool resize) { bool reset = false; for( vector_tpl::iterator iter = item_list.begin(); iter != item_list.end(); ) { if (scrollitem_t* const item = dynamic_cast( *iter ) ) { if( !item->is_valid() ) { container.remove_component(item); reset = resize; } else { ++iter; } } } if (reset) { reset_container_size(); } } void gui_scrolled_list_t::show_bottom() { scroll_y.set_sticky_bottom(true); } void gui_scrolled_list_t::draw(scr_coord offset) { // set focus scrollitem_t* focus = dynamic_cast( comp->get_focus() ); if( focus ) { for(gui_component_t* v : item_list) { scrollitem_t* item = dynamic_cast(v); if( item ) { item->focused = item->selected && win_get_focus()==focus; } } } cleanup_elements(); if (item_list.get_count() > 0) { scr_rect rect(pos + offset, get_size()); switch(type) { case windowskin: display_img_stretch( gui_theme_t::windowback, rect); break; case listskin: display_img_stretch( gui_theme_t::listbox, rect); break; case transparent: break; } } if (sliders_dirty) { recalc_sliders_visible(size); } gui_scrollpane_t::draw(offset); // find actual height and reset positions in case of size changes (as the final size is only know after redraws) scr_coord_val w = 0; scr_coord_val h = 0; for (vector_tpl::iterator iter = item_list.begin(); iter != item_list.end(); ++iter) { if ((*iter)->is_visible()) { (*iter)->set_pos(scr_coord(D_H_SPACE, h)); h += (*iter)->get_size().h; w = max(w, (*iter)->get_min_size().w); } } scr_size new_size(w + D_H_SPACE * 2, h); bool has_vscroll = new_size.h > size.h || (new_size.w > size.w && h + new_size.h > size.h); scr_coord_val client_width = size.w - 2 * D_H_SPACE - has_vscroll * D_SCROLLBAR_WIDTH; if (w < client_width) { w = client_width; new_size.w = client_width + 2 * D_H_SPACE; } for (vector_tpl::iterator iter = item_list.begin(); iter != item_list.end(); ++iter) { if ((*iter)->is_visible()) { scr_size c_size = (*iter)->get_size(); if (c_size.h == 0) { (*iter)->set_size(scr_size(w, (*iter)->get_min_size().h)); } else if (sliders_dirty || c_size.w < w ) { (*iter)->set_size(scr_size(w, c_size.h)); } } } // now reset the positions in case of height changes if (container.get_size() != new_size) { container.gui_component_t::set_size(new_size); } if(sliders_dirty) { // reset sliders recalc_sliders_visible(size); recalc_sliders(size); } sliders_dirty = false; // to avoid flicker } simutrans-124.3/src/simutrans/gui/components/gui_scrolled_list.h000066400000000000000000000113651474050137200252250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_SCROLLED_LIST_H #define GUI_COMPONENTS_GUI_SCROLLED_LIST_H #include "gui_aligned_container.h" #include "gui_scrollpane.h" #include "action_listener.h" #include "gui_action_creator.h" #include "gui_label.h" #include "../../simcolor.h" #include "../../tpl/vector_tpl.h" /** * Helper class to access the list of components in the scrolling container. */ class scroll_container_t : public gui_aligned_container_t { public: vector_tpl & get_components() { return components; } }; /** * Scrollable list of components that can be sorted, and has component selection. * * Displays list, scrollbuttons up/down, dragbar. * Has a min and a max size, and can be displayed with any size in between. * Does ONLY cater for vertical offset (yet). * two possible types: * -list. simply lists some items. * -selection. is a list, but additionally, one item can be selected. */ class gui_scrolled_list_t : public gui_action_creator_t, public gui_scrollpane_t { public: enum type { windowskin, listskin, transparent }; /** * Base class for elements in lists. Virtual inheritance. */ class scrollitem_t : virtual public gui_component_t { public: /// constructor: set focusable to true. /// focused element will be used to determine selection in gui_scrolled_list_t scrollitem_t() : gui_component_t(true /* focusable */), focused(false), selected(false) { } virtual char const* get_text() const = 0; virtual void set_text(char const *) {} virtual bool is_valid() const { return true; } // can be used to indicate invalid entries virtual bool is_editable() const { return false; } /// compares using get_text static bool compare(const gui_component_t *a, const gui_component_t *b ); bool focused, selected; protected: using gui_component_t::draw; }; typedef bool (*item_compare_func)(const gui_component_t* a, const gui_component_t* b); /** * Text entry, non-editable */ class const_text_scrollitem_t : public gui_label_t, public scrollitem_t { public: const_text_scrollitem_t(char const* const t, PIXVAL const col) : gui_label_t(NULL, col) { set_text_pointer(t); } char const* get_text() const OVERRIDE { return get_text_pointer(); } scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; void set_text(char const *) OVERRIDE {} void draw(scr_coord pos) OVERRIDE; using gui_label_t::get_color; private: using gui_label_t::set_text; }; private: enum type type; bool maximize; // true if to expand to bottom right corner bool sliders_dirty; // true if sliders need attention during next redraw scr_coord_val c_old_width; item_compare_func compare; bool multiple_selection; // true when multiple selection is enabled. void calc_selection(scrollitem_t*, scrollitem_t*, event_t); protected: scroll_container_t container; vector_tpl & item_list; void reset_container_size(); /// deletes invalid elements from list void cleanup_elements(bool resize=true); public: scr_size get_container_min_size() const { return container.get_min_size(); } virtual void set_skin_type(enum type t) { this->type = t; } void set_cmp(item_compare_func cmp) { compare = cmp; } void set_checkered(bool c) { container.set_checkered(c); } gui_scrolled_list_t(enum type t= windowskin, item_compare_func cmp = 0); ~gui_scrolled_list_t() { clear_elements(); } void show_selection(int s); void set_selection(int s); sint32 get_selection() const; vector_tpl get_selections() const; scrollitem_t* get_selected_item() const; uint32 get_count() const { return item_list.get_count(); } void enable_multiple_selection() { multiple_selection = true; } /* when rebuilding a list, be sure to call recalculate the slider * with recalculate_slider() to update the scrollbar properly. */ void clear_elements(); scrollitem_t *get_element(sint32 i) const { return (i>=0 && (uint32)i(item_list[i]) : NULL; } template void new_component(const As &... as) { return container.new_component(as...)->set_focusable(true); } void take_component(gui_component_t* comp) { container.take_component(comp, 1); } /** * Sorts the list. * Calls the virtual method scrollitem_t::sort of element at position @p offset. * Adjusts scrollbar. * @param offset sort list from element offset to end */ void sort( int offset); void set_size(scr_size size) OVERRIDE; bool infowin_event(event_t const*) OVERRIDE; void draw(scr_coord pos) OVERRIDE; bool is_marginless() const OVERRIDE { return maximize; } void set_maximize(bool b) { maximize = b; } void show_bottom(); }; #endif simutrans-124.3/src/simutrans/gui/components/gui_scrollpane.cc000066400000000000000000000235201474050137200246570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simdebug.h" #include "../gui_frame.h" #include "gui_scrollpane.h" #include "gui_scrollbar.h" #include "gui_button.h" #include "../../dataobj/loadsave.h" #include "../../dataobj/environment.h" #include "../../display/simgraph.h" #include "../../simcolor.h" /** * @param comp the scrolling component */ gui_scrollpane_t::gui_scrollpane_t(gui_component_t* comp, bool b_scroll_x, bool b_scroll_y) : scroll_x(scrollbar_t::horizontal), scroll_y(scrollbar_t::vertical) { this->comp = comp; max_width = D_DEFAULT_WIDTH - D_MARGIN_LEFT - D_MARGIN_RIGHT; max_height = D_DEFAULT_HEIGHT / 2 - D_MARGIN_TOP - D_MARGIN_BOTTOM; b_show_scroll_x = b_scroll_x; b_show_scroll_y = b_scroll_y; b_has_size_corner = true; b_can_drag = true; b_is_dragging = false; old_comp_size = scr_size::invalid; maximize = false; } scr_size gui_scrollpane_t::get_min_size() const { // the component does not have a minimum scroll size // use min_size and limit it with max_width/height scr_size csize = comp->get_min_size(); csize.w = min(csize.w, max_width); csize.h = min(csize.h, max_height); if (scroll_x.is_visible() && !b_show_scroll_y) { // need to add space for x-scroolbar as y-scrolling is out of question csize.h += D_SCROLLBAR_HEIGHT; } csize.w = max(csize.w, scroll_x.get_min_size().w); csize.h = max(csize.h, scroll_y.get_min_size().h); return csize; } scr_size gui_scrollpane_t::get_max_size() const { scr_size csize = comp->get_max_size(); if (csize.h!=scr_size::inf.h && scroll_x.is_visible() && !b_show_scroll_y) { // need to add space for x-scroolbar as y-scrolling is out of question csize.h += D_SCROLLBAR_HEIGHT; } return csize; } /** * recalc the scroll bar sizes */ void gui_scrollpane_t::recalc_sliders(scr_size size) { scroll_x.set_pos(scr_coord(0, size.h - D_SCROLLBAR_HEIGHT)); scroll_y.set_pos(scr_coord(size.w - D_SCROLLBAR_WIDTH, 0)); scr_coord_val off_x = (b_show_scroll_x && scroll_x.is_visible()); scr_coord_val off_y = (b_show_scroll_y && scroll_y.is_visible()); bool need_sizecorner = off_x | off_y; off_x |= need_sizecorner; off_y |= need_sizecorner; scroll_x.set_size(size - D_SCROLLBAR_SIZE*off_y); scroll_x.set_knob(size.w - D_SCROLLBAR_WIDTH*off_y, comp->get_size().w + comp->get_pos().x); scroll_y.set_size(size - D_SCROLLBAR_SIZE*off_x); scroll_y.set_knob(size.h - D_SCROLLBAR_HEIGHT*off_x, comp->get_size().h + comp->get_pos().y); old_comp_size = comp->get_size(); } // just hide or show then sliders according to the object size void gui_scrollpane_t::recalc_sliders_visible(scr_size size) { scr_coord k = comp->get_size() + comp->get_pos(); bool need_x = (k.x > size.w) && b_show_scroll_x; bool need_y = (k.y + need_x * D_SCROLLBAR_HEIGHT > size.h) && b_show_scroll_y; need_x = (k.x + need_y*D_SCROLLBAR_WIDTH > size.w) && b_show_scroll_x; scroll_x.set_visible(need_x); scroll_y.set_visible(need_y); } /** * Scrollpanes _must_ be used in this method to set the size */ void gui_scrollpane_t::set_size(scr_size size) { gui_component_t::set_size(size); recalc_sliders_visible(size); // automatically increase/decrease slider area scr_size c_size = size - comp->get_pos(); // resize scrolled component if (scroll_x.is_visible()) { c_size.h -= D_SCROLLBAR_HEIGHT; } if (scroll_y.is_visible()) { c_size.w -= D_SCROLLBAR_WIDTH; } c_size.clip_lefttop( comp->get_min_size() ); c_size.clip_rightbottom( comp->get_max_size() ); comp->set_size(c_size); recalc_sliders(size); show_focused(); } scr_size gui_scrollpane_t::request_size(scr_size request) { // do not enlarge past max size of comp scr_size cmax = comp->get_max_size(); if (cmax.w < request.w - comp->get_pos().x && cmax.h < request.h - comp->get_pos().y) { request = cmax; } set_size(request); return get_size(); } /** * Events are notified to GUI components via this method */ bool gui_scrollpane_t::infowin_event(const event_t *ev) { bool swallow = false; if( (b_show_scroll_y && scroll_y.is_visible()) && ev->ev_class!=EVENT_KEYBOARD && (scroll_y.getroffen(ev->mouse_pos) || scroll_y.getroffen(ev->click_pos)) ) { event_t ev2 = *ev; ev2.move_origin(scroll_y.get_pos()); b_is_dragging = false; return scroll_y.infowin_event(&ev2); } else if( (b_show_scroll_x && scroll_x.is_visible()) && ev->ev_class!=EVENT_KEYBOARD && (scroll_x.getroffen(ev->mouse_pos) || scroll_x.getroffen(ev->click_pos))) { event_t ev2 = *ev; ev2.move_origin(scroll_x.get_pos()); b_is_dragging = false; return scroll_x.infowin_event(&ev2); } else if( ev->ev_classmouse_pos.x>=0 && ev->mouse_pos.y>=0 && ev->mouse_pos.x<=size.w && ev->mouse_pos.y<=size.h) || b_is_dragging ) { // since we get can grab the focus to get keyboard events, we must make sure to handle mouse events only if we are hit if( ev->ev_class < EVENT_CLICK || IS_WHEELUP(ev) || IS_WHEELDOWN(ev) ) { b_is_dragging = false; } // we will handle dragging ourselves inf not prevented if( b_is_dragging && ev->ev_class < INFOWIN ) { // now drag: scrollbars are not in pixel, but we will scroll one unit per pixels ... scroll_x.set_sticky_bottom(false); scroll_y.set_sticky_bottom(false); scroll_x.set_knob_offset(scroll_x.get_knob_offset() - (ev->mouse_pos.x - origin.x)); scroll_y.set_knob_offset(scroll_y.get_knob_offset() - (ev->mouse_pos.y - origin.y)); origin = ev->mouse_pos; // and finally end dragging on release of any button if( ev->ev_class == EVENT_RELEASE ) { b_is_dragging = false; if( abs(ev->mouse_pos.x - ev->click_pos.x) >= 5 || abs(ev->click_pos.x-ev->mouse_pos.x)+abs(ev->click_pos.y-ev->mouse_pos.y) >= env_t::scroll_threshold ) { // dragged a lot => swallow click return true; } } else { // continue dragging, swallow other events return true; } } // translate according to scrolled position event_t ev2 = *ev; const scr_coord offset(scroll_x.get_knob_offset(), scroll_y.get_knob_offset()); ev2.move_origin(comp->get_pos() - offset); gui_component_t *focused = get_focus(); // hand event to component swallow = comp->infowin_event(&ev2); // now process wheel-events that are not swallowed by component, scroll the pane if(!swallow) { if( (IS_WHEELUP(ev) || IS_WHEELDOWN(ev)) && (((b_show_scroll_y && scroll_y.is_visible()) && !IS_SHIFT_PRESSED(ev)) || ((b_show_scroll_x && scroll_x.is_visible()) && IS_SHIFT_PRESSED(ev))) ) { // otherwise these events are only registered where directly over the scroll region // (and sometime even not then ... ) return IS_SHIFT_PRESSED(ev) ? scroll_x.infowin_event(ev) : scroll_y.infowin_event(ev); } } if( !swallow && b_can_drag && (ev->ev_class == EVENT_CLICK || ev->ev_class == EVENT_DRAG) ) { // init dragging? (Android SDL starts dragging without preceeding click!) if(!b_is_dragging) { origin = ev->mouse_pos; b_is_dragging = true; return true; } } // check if we need to scroll to the focused component gui_component_t *new_focus = get_focus(); if(new_focus && focused != new_focus) { show_focused(); } // hack: component could have changed size // this recalculates the scrollbars if( old_comp_size!=comp->get_size() ) { recalc_sliders(get_size()); } } return swallow; } void gui_scrollpane_t::show_focused() { const gui_component_t *const focused_comp = comp->get_focus(); if( focused_comp ) { const scr_size comp_size = focused_comp->get_size(); const scr_coord relative_pos = comp->get_focus_pos(); if( b_show_scroll_x ) { const sint32 knob_offset_x = scroll_x.get_knob_offset(); const sint32 view_width = size.w-D_SCROLLBAR_WIDTH; if( relative_pos.x+comp_size.wknob_offset_x+view_width ) { scroll_x.set_knob_offset(relative_pos.x+comp_size.w-view_width); } } if( b_show_scroll_y ) { const sint32 knob_offset_y = scroll_y.get_knob_offset(); const sint32 view_height = (b_has_size_corner || b_show_scroll_x) ? size.h-D_SCROLLBAR_HEIGHT : size.h; if( relative_pos.y+comp_size.hknob_offset_y+view_height ) { scroll_y.set_knob_offset(relative_pos.y+comp_size.h-view_height); } } } } /** * Set the position of the Scrollbars */ void gui_scrollpane_t::set_scroll_position(int x, int y) { scroll_x.set_knob_offset(x); scroll_y.set_knob_offset(y); } sint32 gui_scrollpane_t::get_scroll_x() const { return scroll_x.get_knob_offset(); } sint32 gui_scrollpane_t::get_scroll_y() const { return scroll_y.get_knob_offset(); } scr_rect gui_scrollpane_t::get_client( void ) { scr_rect client( pos, pos+size ); if( b_show_scroll_x && scroll_x.is_visible() ) { client.h -= D_SCROLLBAR_HEIGHT; } if( b_show_scroll_y && scroll_y.is_visible() ) { client.w -= D_SCROLLBAR_WIDTH; } return client; } /** * Draw the component */ void gui_scrollpane_t::draw(scr_coord pos) { // check, if we need to recalc slider size if( old_comp_size != comp->get_size() ) { recalc_sliders( size ); } // get client area (scroll panel - scrollbars) scr_rect client = get_client() + pos; PUSH_CLIP_FIT( client.x, client.y, client.w, client.h ) comp->draw( client.get_pos()-scr_coord(scroll_x.get_knob_offset(), scroll_y.get_knob_offset()) ); POP_CLIP() // sliding bar background color is now handled by the scrollbar! if( b_show_scroll_x && scroll_x.is_visible() ) { scroll_x.draw( pos+get_pos() ); } if( b_show_scroll_y && scroll_y.is_visible() ) { scroll_y.draw( pos+get_pos() ); } } void gui_scrollpane_t::rdwr( loadsave_t *file ) { sint32 x = get_scroll_x(); sint32 y = get_scroll_y(); file->rdwr_long(x); file->rdwr_long(y); if (file->is_loading()) { set_scroll_position(x, y); } } simutrans-124.3/src/simutrans/gui/components/gui_scrollpane.h000066400000000000000000000067241474050137200245300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_SCROLLPANE_H #define GUI_COMPONENTS_GUI_SCROLLPANE_H #include "gui_component.h" #include "gui_scrollbar.h" class loadsave_t; /* * this is a scrolling area in which subcomponents are drawn */ class gui_scrollpane_t : public gui_component_t { private: scr_size old_comp_size; bool b_show_scroll_x:1; bool b_show_scroll_y:1; bool b_has_size_corner:1; bool maximize:1; bool b_can_drag:1; bool b_is_dragging:1; // start of dragging scr_coord origin; protected: /** * The scrolling component */ gui_component_t *comp; /** * Scrollbar X/Y */ scrollbar_t scroll_x, scroll_y; // for oversized entries scr_coord_val max_width; scr_coord_val max_height; void recalc_sliders_visible(scr_size size); void recalc_sliders(scr_size size); public: /** * @param comp the scrolling component * @param b_scroll_x * @param b_scroll_y */ gui_scrollpane_t(gui_component_t *comp, bool b_scroll_x = false, bool b_scroll_y = true); void set_component(gui_component_t *comp) { this->comp = comp; } void set_allow_dragging(bool b) { b_can_drag = b; } /** * this is the maximum width a scrollbar requests as minimum size * default is the stadard width of a dialoge (4*button width+3*space) * @param width the minimum width it should strech to */ virtual void set_min_width( scr_coord_val width ) { max_width = width; } /** * This method MUST be used to set the size of scrollpanes. */ void set_size(scr_size size) OVERRIDE; /** * Request other pane-size. * @returns realized size. */ scr_size request_size(scr_size request); /** * Set the position of the Scrollbars */ void set_scroll_position(int x, int y); scr_rect get_client( void ) OVERRIDE; int get_scroll_x() const; int get_scroll_y() const; void set_scroll_amount_x(const sint32 sa) { scroll_x.set_scroll_amount(sa); } void set_scroll_amount_y(const sint32 sa) { scroll_y.set_scroll_amount(sa); } void set_scroll_discrete_x(const bool sd) { scroll_x.set_scroll_discrete(sd); } void set_scroll_discrete_y(const bool sd) { scroll_y.set_scroll_discrete(sd); } bool infowin_event(event_t const*) OVERRIDE; /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; void set_show_scroll_x(bool yesno) { b_show_scroll_x = yesno; } void set_show_scroll_y(bool yesno) { b_show_scroll_y = yesno; } void set_scrollbar_mode(scrollbar_t::visible_mode_t mode) { scroll_x.set_visible_mode(mode); scroll_y.set_visible_mode(mode); } void set_size_corner(bool yesno) { b_has_size_corner = yesno; } /** * Returns true if the hosted component is focusable */ bool is_focusable() OVERRIDE { return comp->is_focusable(); } /** * returns element that has the focus */ gui_component_t *get_focus() OVERRIDE { return comp->get_focus(); } /** * Adjust scrollbars to make focused element visible if necessary */ void show_focused(); /** * Get the relative position of the focused component. * Used for auto-scrolling inside a scroll pane. */ scr_coord get_focus_pos() OVERRIDE { return pos + ( comp->get_focus_pos() - scr_coord( scroll_x.get_knob_offset(), scroll_y.get_knob_offset() ) ); } scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; /// load/save scrollbar positions void rdwr( loadsave_t *file ); bool is_marginless() const OVERRIDE { return maximize; } void set_maximize(bool b) { maximize = b; } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_speedbar.cc000066400000000000000000000101261474050137200243000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "gui_speedbar.h" #include "../gui_theme.h" #include "../../display/simgraph.h" #include "../../simcolor.h" #include "../../simtypes.h" void gui_speedbar_t::set_base(sint32 base) { this->base = base!=0 ? base : 1; } void gui_speedbar_t::add_color_value(const sint32 *value, PIXVAL color) { info_t next = { color, value, -1 }; values.insert(next); } scr_size gui_speedbar_t::get_min_size() const { return D_INDICATOR_SIZE; } scr_size gui_speedbar_t::get_max_size() const { return scr_size(scr_size::inf.w, D_INDICATOR_HEIGHT); } void gui_speedbar_t::draw(scr_coord offset) { offset += pos; if(vertical) { sint32 from = size.h; for(info_t const& i : values) { sint32 const to = size.h - min(*i.value, base) * size.h / base; if(to < from) { display_fillbox_wh_clip_rgb(offset.x, offset.y + to, size.w, from - to, i.color, true); from = to - 1; } } if(from > 0) { display_fillbox_wh_clip_rgb( offset.x, offset.y, size.w, from, color_idx_to_rgb(MN_GREY0), true); } } else { sint32 from = 0; for(info_t const& i : values) { sint32 const to = min(*i.value, base) * size.w / base; if(to > from) { display_fillbox_wh_clip_rgb(offset.x + from, offset.y, to - from, size.h, i.color, true); from = to + 1; } } if(from < size.w) { display_fillbox_wh_clip_rgb(offset.x + from, offset.y, size.w - from, size.h, color_idx_to_rgb(MN_GREY0), true); } } } void gui_speedbar_fixed_length_t::draw(scr_coord offset) { offset += pos; sint32 from = 0; for (info_t const& i : values) { sint32 const to = min(*i.value, base) * fixed_width / base; if (to > from) { display_fillbox_wh_clip_rgb(offset.x + from, offset.y, to - from, size.h, i.color, true); from = to + 1; } if (from > size.w) { // reached size already break; } } if (from < size.w) { display_fillbox_wh_clip_rgb(offset.x + from, offset.y, size.w - from, size.h, color_idx_to_rgb(MN_GREY0), true); } } void gui_routebar_t::set_base(sint32 base) { this->base = base != 0 ? base : 1; } void gui_routebar_t::set_reservation(const sint32 *value, PIXVAL color) { reserve_value = value; reserved_color= color; } void gui_routebar_t::init(const sint32 *value, uint8 state) { this->value = value; this->state = state; } void gui_routebar_t::set_state(uint8 state) { this->state = state; } void gui_routebar_t::draw(scr_coord offset) { uint8 h = size.h % 2 ? size.h : size.h-1; if (h < 5) { h = 5; set_size( scr_size(size.w, h) ); } const uint16 w = size.w - h/2; offset += pos; display_fillbox_wh_clip_rgb(offset.x, offset.y+h/2-1, w, 3, color_idx_to_rgb(MN_GREY1), true); PIXVAL col; for (uint8 i = 0; i<5; i++) { col = i % 2 ? COL_GREY4-1 : MN_GREY0; display_vline_wh_clip_rgb(offset.x + h/2 + w*i/4, offset.y+i%2, h-(i%2)*2, color_idx_to_rgb(col), true); } sint32 const to = min(*value, base) * w / base; if (reserve_value && *reserve_value) { sint32 const reserved_to = min(*reserve_value, base) * w / base; display_fillbox_wh_clip_rgb(offset.x + h / 2, offset.y + h / 2 - 1, reserved_to, 3, reserved_color, true); } display_fillbox_wh_clip_rgb(offset.x+h/2, offset.y+h/2-1, to, 3, color_idx_to_rgb(43), true); switch (state) { case 1: display_fillbox_wh_clip_rgb(offset.x + to + 1, offset.y + 1, h - 2, h - 2, color_idx_to_rgb(COL_YELLOW), true); break; case 2: display_fillbox_wh_clip_rgb(offset.x + to + 1, offset.y + 1, h - 2, h - 2, color_idx_to_rgb(COL_ORANGE), true); break; case 3: display_fillbox_wh_clip_rgb(offset.x + to + 1, offset.y + 1, h - 2, h - 2, color_idx_to_rgb(COL_RED), true); break; case 0: default: display_fillbox_wh_clip_rgb( offset.x+h/2, offset.y + 1, to-2, h - 2, color_idx_to_rgb( COL_GREEN ), true ); display_right_triangle_rgb(offset.x + to, offset.y, h, color_idx_to_rgb(COL_MAGENTA), true); break; } } scr_size gui_routebar_t::get_min_size() const { return scr_size(D_INDICATOR_WIDTH, height); } scr_size gui_routebar_t::get_max_size() const { return scr_size(scr_size::inf.w, height); } simutrans-124.3/src/simutrans/gui/components/gui_speedbar.h000066400000000000000000000037051474050137200241470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_SPEEDBAR_H #define GUI_COMPONENTS_GUI_SPEEDBAR_H #include "gui_component.h" #include "../../tpl/slist_tpl.h" class gui_speedbar_t : public gui_component_t { protected: struct info_t { PIXVAL color; const sint32 *value; sint32 last; }; slist_tpl values; sint32 base; bool vertical; public: gui_speedbar_t() { base = 100; vertical = false; } void add_color_value(const sint32 *value, PIXVAL color); void set_base(sint32 base); void set_vertical(bool vertical) { this->vertical = vertical; } /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; class gui_speedbar_fixed_length_t : public gui_speedbar_t { scr_coord_val fixed_width; public: gui_speedbar_fixed_length_t() : gui_speedbar_t(), fixed_width(10) { set_vertical(false); } scr_size get_max_size() const OVERRIDE { return scr_size(fixed_width, gui_speedbar_t::get_min_size().h); } void set_width(scr_coord_val w) { fixed_width = w; } void draw(scr_coord offset) OVERRIDE; }; // route progress bar class gui_routebar_t : public gui_component_t { private: const sint32 *value; const sint32 *reserve_value; sint32 base; uint8 state; PIXVAL reserved_color; scr_coord_val height; public: gui_routebar_t() { base = 100; state = 0; height = 9; value = 0; reserve_value = 0; } void set_reservation(const sint32 *value, PIXVAL color = color_idx_to_rgb(COL_BLUE)); void set_reserved_color(PIXVAL color) { reserved_color = color; }; void set_base(sint32 base); void init(const sint32 *value, uint8 state); void set_state(uint8 state); /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; void set_height(scr_coord_val h) { height = h; }; scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_tab_panel.cc000066400000000000000000000254321474050137200244460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_tab_panel.h" #include "../gui_frame.h" #include "../../simevent.h" #include "../../dataobj/environment.h" #include "../../display/simgraph.h" #include "../../simcolor.h" #include "../simwin.h" #include "../../world/simworld.h" #include "../../descriptor/skin_desc.h" #define IMG_WIDTH 20 scr_coord_val gui_tab_panel_t::header_vsize = 18; gui_tab_panel_t::gui_tab_panel_t() : required_size( 8, D_TAB_HEADER_HEIGHT ) { active_tab = 0; tab_offset_x = 0; is_dragging = false; left.init( button_t::arrowleft, NULL, scr_coord(0,0) ); left.add_listener( this ); right.init( button_t::arrowright, NULL, scr_coord(0,0) ); right.add_listener( this ); } void gui_tab_panel_t::add_tab(gui_component_t *c, const char *name, const skin_desc_t *desc, const char *tooltip ) { tabs.append( tab(c, desc?NULL:name, desc?desc->get_image(0):NULL, tooltip) ); // only call set_size, if size was already assigned if (size.w > 0 && size.h > 0) { set_size( get_size() ); } } void gui_tab_panel_t::set_size(scr_size size) { gui_component_t::set_size(size); required_size = scr_size( 8, required_size.h ); gui_component_t *last_component = NULL; for(tab & i : tabs) { i.x_offset = required_size.w - 4; if( i.title ) { i.width = D_H_SPACE*2 + proportional_string_width( i.title ); required_size.h = max( required_size.h, LINESPACE + D_V_SPACE ); } else if( i.img ) { i.width = max( 2 + i.img->get_pic()->w, D_H_SPACE*2+IMG_WIDTH );; required_size.h = max( required_size.h, i.img->get_pic()->h + D_V_SPACE ); } else { i.width = 8+IMG_WIDTH; } required_size.w += i.width; if (i.component != last_component) { i.component->set_pos(scr_coord(0, required_size.h)); i.component->set_size(get_size() - scr_size(0, required_size.h)); last_component = i.component; } } if( required_size.w > size.w || tab_offset_x > 0 ) { left.set_pos( scr_coord( 0, 0 ) ); left.set_size( scr_size( D_ARROW_LEFT_WIDTH, required_size.h ) ); right.set_pos( scr_coord( size.w-D_ARROW_RIGHT_WIDTH, 0 ) ); right.set_size( scr_size( D_ARROW_RIGHT_WIDTH, required_size.h ) ); } else { tab_offset_x = 0; } } scr_size gui_tab_panel_t::get_min_size() const { scr_size t_size(0, required_size.h); scr_size c_size(0, 0); gui_component_t *last_component = NULL; for(tab const& iter : tabs) { if (iter.title) { t_size.h = max(t_size.h, LINESPACE + D_V_SPACE); } if (iter.component != last_component) { scr_size cs = iter.component->get_min_size(); if (!iter.component->is_marginless()) { cs.h += D_MARGIN_BOTTOM; } c_size.clip_lefttop( cs ); last_component = iter.component; } } return t_size+c_size; } bool gui_tab_panel_t::action_triggered(gui_action_creator_t *comp, value_t) { if( comp == &right ) { tab_offset_x += 32; } else if( comp == &left ) { tab_offset_x -= 32; } tab_offset_x = clamp(tab_offset_x, 0, required_size.w - size.w); return true; } bool gui_tab_panel_t::tab_getroffen(scr_coord p) { return p.x >= 0 && p.x < size.w && p.y >= 0 && p.y < required_size.h; } bool gui_tab_panel_t::infowin_event(const event_t *ev) { if (gui_component_t *t=get_aktives_tab()) { if (t->get_focus()) { // we must go through the containers or we do not get the correct offsets event_t ev2 = *ev; ev2.move_origin(t->get_pos()); if (t->infowin_event(&ev2)) { return true; } } } // since we get can grab the focus to get keyboard events, we must make sure to handle mouse events only if we are hit if (ev->ev_class < EVENT_CLICK || IS_WHEELUP(ev) || IS_WHEELDOWN(ev)) { is_dragging = false; } if( required_size.w > size.w && tab_getroffen(ev->click_pos) ) { if (!is_dragging) { // handle scroll buttons pressed if( left.getroffen(ev->click_pos) ) { event_t ev2 = *ev; ev2.move_origin(left.get_pos()); return left.infowin_event(&ev2); } if( right.getroffen(ev->click_pos) ) { event_t ev2 = *ev; ev2.move_origin(right.get_pos()); return right.infowin_event(&ev2); } } if (ev->ev_class == EVENT_CLICK || ev->ev_class == EVENT_DRAG) { // init dragging? (Android SDL starts dragging without preceeding click!) is_dragging = true; return true; } } // we will handle dragging ourselves inf not prevented if(is_dragging && ev->ev_class < INFOWIN) { // now drag: scrollbars are not in pixel, but we will scroll one unit per pixels ... tab_offset_x -= (ev->mouse_pos.x - ev->click_pos.x); tab_offset_x = clamp(tab_offset_x, 0, required_size.w - size.w); // and finally end dragging on release of any button if (ev->ev_class == EVENT_RELEASE) { is_dragging = false; if (abs(ev->mouse_pos.x - ev->click_pos.x) >= 5 || abs(ev->click_pos.x - ev->mouse_pos.x) + abs(ev->click_pos.y - ev->mouse_pos.y) >= env_t::scroll_threshold) { // dragged a lot => swallow click return true; } } else { // continue dragging, swallow other events return true; } } if( IS_LEFTRELEASE(ev) && tab_getroffen(ev->click_pos) ) { // tab selector was hit int text_x = (required_size.w>size.w ? D_ARROW_LEFT_WIDTH : 0) + D_H_SPACE - tab_offset_x; int k=0; for(tab const& i : tabs) { if (!i.component->is_visible()) { continue; } if (text_x <= ev->mouse_pos.x && text_x + i.width > ev->mouse_pos.x) { // either tooltip or change active_tab = k; call_listeners((long)active_tab); return true; } k++; text_x += i.width; } return false; } // navigate among the tabs using shift+tab and tab if( ev->ev_class==EVENT_KEYBOARD && ev->ev_code == SIM_KEY_TAB ) { int di = 1; // tab -> go to the next tab if( IS_SHIFT_PRESSED(ev) ) { // shift+tab -> go to the previous tab di = -1; } // change index by di*i for(int i = 1; i<(int)tabs.get_count(); i++) { const int next_tab_idx = (active_tab + tabs.get_count() + di*i) % tabs.get_count(); if (tabs.at(next_tab_idx).component->is_visible()) { active_tab = next_tab_idx; call_listeners((long)active_tab); break; } } return true; } if( ev->ev_class == EVENT_KEYBOARD || DOES_WINDOW_CHILDREN_NEED(ev) || get_aktives_tab()->getroffen(ev->mouse_pos) || get_aktives_tab()->getroffen(ev->click_pos)) { // active tab was hit event_t ev2 = *ev; ev2.move_origin(get_aktives_tab()->get_pos()); return get_aktives_tab()->infowin_event(&ev2); } return false; } void gui_tab_panel_t::draw(scr_coord parent_pos) { // if active tab is invisible, choose the previous visible one if (!tabs.at(active_tab).component->is_visible()) { for(int i = 1; i<(int)tabs.get_count(); i++) { const int next_tab_idx = (active_tab + tabs.get_count() - i) % tabs.get_count(); if (tabs.at(next_tab_idx).component->is_visible()) { active_tab = next_tab_idx; break; } } } // Position in screen/window int xpos = parent_pos.x + pos.x; const int ypos = parent_pos.y + pos.y; if( required_size.w>size.w || tab_offset_x > 0) { left.draw( parent_pos+pos ); right.draw( parent_pos+pos ); //display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 10, 1, SYSCOL_TEXT_HIGHLIGHT, true); display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, D_ARROW_LEFT_WIDTH, 1, SYSCOL_HIGHLIGHT, true); xpos += D_ARROW_LEFT_WIDTH; } int text_x = xpos + D_H_SPACE; int text_y = ypos + (required_size.h - LINESPACE)/2; //display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 4, 1, color_idx_to_rgb(COL_WHITE), true); display_fillbox_wh_clip_rgb(xpos, ypos+required_size.h-1, 4, 1, SYSCOL_HIGHLIGHT, true); // do not draw under right button int xx = required_size.w>get_size().w ? get_size().w-(D_ARROW_LEFT_WIDTH+2+D_ARROW_RIGHT_WIDTH) : get_size().w; text_x -= tab_offset_x; int i=0; for(tab const& iter : tabs) { if (!iter.component->is_visible()) { continue; } // set clipping PUSH_CLIP_FIT(xpos, ypos, xx, required_size.h); // only start drawing here ... char const* const text = iter.title; if (i != active_tab) { // Non active tabs display_fillbox_wh_clip_rgb(text_x+1, ypos+2, iter.width-2, 1, SYSCOL_HIGHLIGHT, true); display_fillbox_wh_clip_rgb(text_x, ypos+required_size.h-1, iter.width-2, 1, SYSCOL_HIGHLIGHT, true); display_vline_wh_clip_rgb(text_x, ypos+3, required_size.h-4, SYSCOL_HIGHLIGHT, true); display_vline_wh_clip_rgb(text_x+iter.width-1, ypos+3, required_size.h-4, SYSCOL_SHADOW, true); if(text) { display_proportional_clip_rgb(text_x+D_H_SPACE, text_y+2, text, ALIGN_LEFT, SYSCOL_TEXT, true); } else { scr_coord_val const y = ypos - iter.img->get_pic()->y + required_size.h / 2 - iter.img->get_pic()->h / 2 + 1; scr_coord_val const x = text_x - iter.img->get_pic()->x + iter.width / 2 - iter.img->get_pic()->w / 2; // display_img_blend(iter.img->get_id(), x, y, TRANSPARENT50_FLAG, false, true); display_base_img(iter.img->get_id(), x, y, 1, false, true); } } else { // Active tab display_fillbox_wh_clip_rgb(text_x+1, ypos, iter.width-2, 1, SYSCOL_HIGHLIGHT, true); display_vline_wh_clip_rgb(text_x, ypos+1, required_size.h-2, SYSCOL_HIGHLIGHT, true); display_vline_wh_clip_rgb(text_x+iter.width-1, ypos+1, required_size.h-2, SYSCOL_SHADOW, true); if(text) { display_proportional_clip_rgb(text_x+D_H_SPACE, text_y, text, ALIGN_LEFT, SYSCOL_TEXT_HIGHLIGHT, true); } else { scr_coord_val const y = ypos - iter.img->get_pic()->y + required_size.h / 2 - iter.img->get_pic()->h / 2 - 1; scr_coord_val const x = text_x - iter.img->get_pic()->x + iter.width / 2 - iter.img->get_pic()->w / 2; display_base_img(iter.img->get_id(), x, y, 1, false, true); } } text_x += iter.width; // reset clipping POP_CLIP(); i++; } display_fillbox_wh_clip_rgb(text_x, ypos+required_size.h-1, xpos+size.w-text_x, 1, SYSCOL_HIGHLIGHT, true); // draw tab content after tab row // (combobox may open to above, and tab row may draw into it) get_aktives_tab()->draw(parent_pos + pos); // now for tooltips ... int my = get_mouse_pos().y-parent_pos.y-pos.y-6; if(my>=0 && my < required_size.h-1) { // Reiter getroffen? int mx = get_mouse_pos().x-parent_pos.x-pos.x; int text_x = D_H_SPACE + tab_offset_x; for(tab const& iter : tabs) { if(text_x <= mx && text_x+iter.width > mx && (required_size.w<=get_size().w || mx < right.get_pos().x-12)) { // tooltip or change const scr_coord tooltip_pos{ get_mouse_pos().x + 16, ypos + required_size.h + 12 }; win_set_tooltip(tooltip_pos, iter.tooltip, &iter, this); break; } text_x += iter.width; } } } void gui_tab_panel_t::clear() { tabs.clear(); active_tab = 0; } void gui_tab_panel_t::take_tabs(gui_tab_panel_t* other) { tabs.append_list(other->tabs); } void gui_tab_panel_t::rdwr( loadsave_t *file ) { sint32 a = get_active_tab_index(); file->rdwr_long(a); if (file->is_loading()) { set_active_tab_index(a); } } simutrans-124.3/src/simutrans/gui/components/gui_tab_panel.h000066400000000000000000000056101474050137200243040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_TAB_PANEL_H #define GUI_COMPONENTS_GUI_TAB_PANEL_H #include "../../display/simimg.h" #include "../../descriptor/skin_desc.h" #include "gui_action_creator.h" #include "gui_component.h" #include "gui_button.h" class image_t; class loadsave_t; /** * A class for distribution of tabs through the gui_component_t component. */ class gui_tab_panel_t : public gui_action_creator_t, public action_listener_t, public gui_component_t { private: struct tab { tab(gui_component_t* c, const char *name, const image_t *b, const char *tool) : component(c), title(name), img(b), tooltip(tool), x_offset(4) {} gui_component_t* component; const char *title; const image_t *img; const char *tooltip; sint16 x_offset; sint16 width; }; slist_tpl tabs; int active_tab; scr_size required_size; scr_coord_val tab_offset_x; button_t left, right; bool is_dragging; bool tab_getroffen(scr_coord p); public: static scr_coord_val header_vsize; gui_tab_panel_t(); /** * Add new tab to tab bar * * @param c is tab component * @param name is name for tab component * @param b * @param tooltip */ void add_tab(gui_component_t *c, const char *name, const skin_desc_t *b=NULL, const char *tooltip=NULL ); /** * Get the active component/active tab */ gui_component_t* get_aktives_tab() const { return get_tab(active_tab); } gui_component_t* get_tab( uint8 i ) const { return i < tabs.get_count() ? tabs.at(i).component : NULL; } int get_active_tab_index() const { return min((int)tabs.get_count()-1,active_tab); } void set_active_tab_index( int i ) { active_tab = min((int)tabs.get_count()-1,i); } bool infowin_event(event_t const*) OVERRIDE; /** * Draw tabs */ void draw(scr_coord offset) OVERRIDE; /** * Resizing must be propagated! */ void set_size(scr_size size) OVERRIDE; /** * Remove all tabs. */ void clear(); /** * How many tabs we have? */ uint32 get_count () const { return tabs.get_count(); } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; /** * Returns true if the hosted component of the active tab is focusable */ bool is_focusable() OVERRIDE { return get_aktives_tab()->is_focusable(); } gui_component_t *get_focus() OVERRIDE { return get_aktives_tab()->get_focus(); } /** * Get the relative position of the focused component. * Used for auto-scrolling inside a scroll pane. */ scr_coord get_focus_pos() OVERRIDE { return pos + get_aktives_tab()->get_focus_pos(); } scr_size get_min_size() const OVERRIDE; // size of tab header scr_size get_required_size() const { return required_size; } bool is_marginless() const OVERRIDE { return true; } /** * Take tabs from other tab. */ void take_tabs(gui_tab_panel_t* other); /// save active tab void rdwr( loadsave_t *file ); }; #endif simutrans-124.3/src/simutrans/gui/components/gui_textarea.cc000066400000000000000000000054501474050137200243340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "gui_textarea.h" #include "../../display/simgraph.h" #include "../../simdebug.h" #include "../../simcolor.h" #include "../../simskin.h" #include "../gui_theme.h" #include "../../utils/cbuffer.h" #define L_PADDING_RIGHT (10) gui_textarea_t::gui_textarea_t(cbuffer_t* buf_) { set_buf(buf_); } void gui_textarea_t::set_buf( cbuffer_t* buf_ ) { buf = buf_; recalc_size(); } scr_size gui_textarea_t::get_min_size() const { return calc_size(); } scr_size gui_textarea_t::get_max_size() const { return get_min_size(); } void gui_textarea_t::recalc_size() { set_size(calc_size()); } scr_size gui_textarea_t::calc_size() const { if (buf) { const char *text(*buf); // since we also want to dynamically change the size of the component int new_lines=0; scr_coord_val x_size = 0; if ( (text != NULL) && (*text != '\0') ) { const char *buf=text; const char *next; do { next = strchr(buf, '\n'); const size_t len = next ? next-buf : 99999; const int px_len = display_calc_proportional_string_len_width(buf, len); if( px_len > x_size ) { x_size = px_len; } new_lines += LINESPACE; } while( next != NULL && ((void)(buf = next+1), *buf!=0) ); } if (x_size > 0) { x_size += L_PADDING_RIGHT; } return scr_size( x_size, new_lines ); } else { return scr_size(0, 0); } } /** * Draw the component */ void gui_textarea_t::draw(scr_coord offset) { const char *text(*buf); // we cannot use: display_multiline_text(pos.x+offset.x, pos.y+offset.y+10, text, color_idx_to_rgb(COL_BLACK)); // since we also want to dynamically change the size of the component scr_coord_val new_lines = 0; // keep previous maximum width scr_coord_val x_size = get_size().w - L_PADDING_RIGHT; if ( (text != NULL) && (*text != '\0') ) { const char *buf=text; const char *next; const scr_coord_val x = pos.x+offset.x; scr_coord_val y = pos.y+offset.y; do { next = strchr(buf, '\n'); const size_t len = next != NULL ? next - buf : -1; scr_coord_val const draw_y = y + new_lines; int px_len; if ( -LINESPACE <= draw_y && draw_y <= display_get_height() + LINESPACE) { // draw when in screen area px_len = display_text_proportional_len_clip_rgb(x, draw_y, buf, ALIGN_LEFT | DT_CLIP, SYSCOL_TEXT, true, len); } else { // track required length when out of screen area px_len = display_calc_proportional_string_len_width(buf, len); } if(px_len>x_size) { x_size = px_len; } new_lines += LINESPACE; } while( next != NULL && ((void)(buf = next+1), *buf!=0) ); } scr_size size( max( x_size + L_PADDING_RIGHT, get_size().w ), new_lines ); if( size!=get_size() ) { set_size(size); } } simutrans-124.3/src/simutrans/gui/components/gui_textarea.h000066400000000000000000000016011474050137200241700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_TEXTAREA_H #define GUI_COMPONENTS_GUI_TEXTAREA_H #include "gui_component.h" class cbuffer_t; /** * A text display component */ class gui_textarea_t : public gui_component_t { private: /** * The text to display. May be multi-lined. */ cbuffer_t* buf; /** * recalc the current size, needed for speculative size calculations * @returns size necessary to show the component */ scr_size calc_size() const; public: gui_textarea_t(cbuffer_t* buf_); void set_buf( cbuffer_t* buf_ ); /** * recalc the current size, needed for speculative size calculations */ void recalc_size(); /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_textinput.cc000066400000000000000000000631751474050137200245730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "gui_textinput.h" #include "../simwin.h" #include "../../dataobj/translator.h" #include "../../utils/simstring.h" #include "../../utils/unicode.h" #include "../../sys/simsys.h" gui_textinput_t::gui_textinput_t() : gui_component_t(true), text(NULL), composition(), composition_target_start(0), composition_target_length(0), max(0), head_cursor_pos(0), tail_cursor_pos(0), scroll_offset(0), align(ALIGN_LEFT), textcol(SYSCOL_EDIT_TEXT), text_dirty(false), focus_received(false), notify_all_changes_delay(0xFFFF), cursor_reference_time(0) { } scr_size gui_textinput_t::get_min_size() const { return scr_size(4*LINESPACE, ::max(LINESPACE+4, D_EDIT_HEIGHT) ); } scr_size gui_textinput_t::get_max_size() const { return scr_size( scr_size::inf.w, ::max(LINESPACE+4, D_EDIT_HEIGHT) ); } /** * determine new cursor position from event coordinates */ size_t gui_textinput_t::calc_cursor_pos(const int x) { size_t new_cursor_pos = 0; if( text ) { const char* tmp_text = text; uint8 byte_length = 0; uint8 pixel_width = 0; scr_coord_val current_offset = 0; const scr_coord_val adjusted_offset = x - 1 + scroll_offset; while( get_next_char_with_metrics(tmp_text, byte_length, pixel_width) && adjusted_offset>(current_offset+(pixel_width>>1)) ) { current_offset += pixel_width; new_cursor_pos += byte_length; } } return new_cursor_pos; } /** * Remove selected text portion, if any. * Returns true if some selected text is actually deleted. */ bool gui_textinput_t::remove_selection() { if( head_cursor_pos!=tail_cursor_pos ) { size_t len = strlen(text); size_t start_pos = min(head_cursor_pos, tail_cursor_pos); size_t end_pos = min(len, ::max(head_cursor_pos, tail_cursor_pos) ); tail_cursor_pos = head_cursor_pos = start_pos; do { text_dirty = true; text[start_pos++] = text[end_pos]; } while( text[end_pos++]!=0 ); return true; } return false; } void gui_textinput_t::set_composition_status( char *c, int start, int length ) { composition.clear(); if( win_get_focus()==this ) { if( c && c[0]!='\0' ) { if( head_cursor_pos!=tail_cursor_pos ) { remove_selection(); } composition.clear(); composition.append( (char *)c ); composition_target_start = start; composition_target_length = length; const scr_coord gui_xy = win_get_pos( win_get_top() ); const int offset_to_target = proportional_string_len_width( composition.get_str(), composition_target_start ); const scr_coord_val x = pos.x + gui_xy.x + get_current_cursor_x() + offset_to_target; const scr_coord_val y = pos.x + gui_xy.y + D_TITLEBAR_HEIGHT; dr_notify_input_pos({ x, y }); } } } /** * Events are notified to GUI components via this method */ bool gui_textinput_t::infowin_event(const event_t *ev) { if( ev->ev_class==EVENT_KEYBOARD ) { if( text ) { size_t len = strlen(text); switch(ev->ev_code) { // handled by container case SIM_KEY_ENTER: if( text_dirty ) { text_dirty = false; call_listeners((long)INPUT_FINISHED); } head_cursor_pos = len; tail_cursor_pos = 0; return false; case SIM_KEY_TAB: // focus is going to be lost -> reset cursor positions to select the whole text by default head_cursor_pos = len; tail_cursor_pos = 0; return false; case SIM_KEY_ESCAPE: return false; case 1: // if Ctrl-A -> select the whole text if( IS_CONTROL_PRESSED(ev) ) { head_cursor_pos = len; tail_cursor_pos = 0; } break; case 3: // if Ctrl-C -> copy selected text to clipboard if( IS_CONTROL_PRESSED(ev) && head_cursor_pos!=tail_cursor_pos ) { const size_t start_pos = min(head_cursor_pos, tail_cursor_pos); const size_t end_pos = ::max(head_cursor_pos, tail_cursor_pos); dr_copy(text + start_pos, end_pos - start_pos); } break; case 22: // if Ctrl-V -> paste selected text to cursor position if( IS_CONTROL_PRESSED(ev) ) { if( remove_selection() ) { // recalculate text length after deleting selection len = strlen(text); } tail_cursor_pos = ( head_cursor_pos += dr_paste(text + head_cursor_pos, max - len - 1) ); text_dirty = true; next_update_call = notify_all_changes_delay == 0xFFFFu ? 0xFFFFFFFFul : dr_time() + notify_all_changes_delay; } break; case 24: // if Ctrl-X -> cut and copy selected text to clipboard if( IS_CONTROL_PRESSED(ev) && head_cursor_pos!=tail_cursor_pos ) { const size_t start_pos = min(head_cursor_pos, tail_cursor_pos); const size_t end_pos = ::max(head_cursor_pos, tail_cursor_pos); dr_copy(text + start_pos, end_pos - start_pos); remove_selection(); text_dirty = true; next_update_call = notify_all_changes_delay == 0xFFFFu ? 0xFFFFFFFFul : dr_time() + notify_all_changes_delay; } break; case SIM_KEY_DOWN: // down arrow // not used currently break; case SIM_KEY_LEFT: // left arrow if( head_cursor_pos>0 ) { // Ctrl key pressed -> skip over to the start of the previous word (as delimited by space(s)) if( IS_CONTROL_PRESSED(ev) ) { const char* tmp_text = text + head_cursor_pos; uint8 byte_length = 0; uint8 pixel_width = 0; // first skip over all contiguous space characters to the left while( head_cursor_pos>0 && get_prev_char_with_metrics(tmp_text, text, byte_length, pixel_width)==SIM_KEY_SPACE ) { head_cursor_pos -= byte_length; } // revert text pointer for further processing if( head_cursor_pos>0 ) { tmp_text += byte_length; } // then skip over all contiguous non-space characters further to the left while( head_cursor_pos>0 && get_prev_char_with_metrics(tmp_text, text, byte_length, pixel_width)!=SIM_KEY_SPACE ) { head_cursor_pos -= byte_length; } } else { head_cursor_pos = utf8_get_prev_char(text, head_cursor_pos); } } // do not update tail cursor if SHIFT key is pressed -> enables text selection if( !IS_SHIFT_PRESSED(ev) ) { tail_cursor_pos = head_cursor_pos; } break; case SIM_KEY_RIGHT: // right arrow if( head_cursor_pos skip over to the start of the next word (as delimited by space(s)) if( IS_CONTROL_PRESSED(ev) ) { const char* tmp_text = text + head_cursor_pos; uint8 byte_length = 0; uint8 pixel_width = 0; // first skip over all contiguous non-space characters to the right while( head_cursor_pos enables text selection if( !IS_SHIFT_PRESSED(ev) ) { tail_cursor_pos = head_cursor_pos; } break; case SIM_KEY_UP: // up arrow // not used currently break; case SIM_KEY_HOME: // home head_cursor_pos = 0; // do not update tail cursor if SHIFT key is pressed -> enables text selection if( !IS_SHIFT_PRESSED(ev) ) { tail_cursor_pos = head_cursor_pos; } break; case SIM_KEY_END: // end head_cursor_pos = len; // do not update tail cursor if SHIFT key is pressed -> enables text selection if( !IS_SHIFT_PRESSED(ev) ) { tail_cursor_pos = head_cursor_pos; } break; case SIM_KEY_BACKSPACE: // backspace // check and remove any selected text first if( !remove_selection() && head_cursor_pos>0 ) { if ( head_cursor_pos 0) { text_dirty = true; next_update_call = notify_all_changes_delay == 0xFFFFu ? 0xFFFFFFFFul : dr_time() + notify_all_changes_delay; } } break; case SIM_KEY_DELETE: // delete // check and remove any selected text first if( !remove_selection() && head_cursor_pos<=len ) { size_t next_pos = utf8_get_next_char(text, head_cursor_pos); for( size_t pos=head_cursor_pos; posev_code < 32) { // ignore special keys not handled so far break; } else if (ev->ev_code>=SIM_KEY_NUMPAD_BASE && ev->ev_code<=SIM_KEY_NUMPAD_BASE+9) { // ignore numpad keys if numlock is off // Could also return false here to move the map diagonally but this does not work for 2/4/6/8 // (SIM_KEY_LEFT/_RIGHT moves the cursor already) break; } // insert letters, numbers, and special characters // first check if it is necessary to remove selected text portion if( remove_selection() ) { // recalculate text length after deleting selection len = strlen(text); } // test, if we have top convert letter char letter[16]; if(ev->ev_code>=128) { sprintf( letter, "CHR%X", ev->ev_code ); //DBG_MESSAGE( "gui_textinput_t::gui_textinput_t()","%i=%s",ev->ev_code,letter); const char *more_letter=translator::translate(letter); // could not convert ... if(letter==more_letter) { char *out=letter; out[ utf16_to_utf8(ev->ev_code, (utf8 *)out) ] = 0; } else { // successful converted letter strcpy( letter, more_letter ); } } else { letter[0] = ev->ev_code; letter[1] = 0; } const size_t num_letter = strlen(letter); if(len+num_letter>=max) { // too many chars ... break; } // insert into text? if (head_cursor_pos < len) { // copy the trailing '\0' too for( sint64 pos=len; pos>=(sint64)head_cursor_pos; pos-- ) { text[pos+num_letter] = text[pos]; } memcpy( text+head_cursor_pos, letter, num_letter ); } else { // append to text memcpy( text+len, letter, num_letter ); text[len+num_letter] = 0; } text_dirty = true; next_update_call = notify_all_changes_delay == 0xFFFFu ? 0xFFFFFFFFul : dr_time() + notify_all_changes_delay; tail_cursor_pos = ( head_cursor_pos += num_letter ); /* end default */ } } else { DBG_MESSAGE("gui_textinput_t::infowin_event", "called but text is NULL"); } cursor_reference_time = dr_time(); // update reference time for cursor blinking if (text_dirty && next_update_call < dr_time()) { // time to update content text_dirty = false; call_listeners((long)INPUT_CHANGED); } return true; } else if( ev->ev_class==EVENT_STRING ) { composition.clear(); // UTF8 multi-byte sequence if( text && ev->ev_ptr ) { size_t len = strlen(text); utf8 *in = (utf8 *)ev->ev_ptr; size_t in_pos = 0; // first check if it is necessary to remove selected text portion if( remove_selection() ) { // recalculate text length after deleting selection len = strlen(text); } while( *in ) { utf32 const uc = utf8_decoder_t::decode(in, in_pos); text_dirty = true; size_t num_letter = in_pos; char letter[16]; // test, if we have top convert letter sprintf( letter, "CHR%X", uc ); const char *more_letter = translator::translate(letter); // could not convert ... if( letter == more_letter ) { tstrncpy( letter, (const char *)in, in_pos+1 ); } else { // successful converted letter strcpy( letter, more_letter ); num_letter = strlen(more_letter); } in += in_pos; if( len+num_letter >= max ) { // too many chars ... break; } // insert into text? if( len>0 && head_cursor_pos < len ) { for( sint64 pos=len+num_letter; pos>=(sint64)head_cursor_pos; pos-- ) { text[pos] = text[pos-num_letter]; } memcpy( text+head_cursor_pos, letter, num_letter ); } else { // append to text memcpy( text+len, letter, num_letter ); text[len+num_letter] = 0; } text_dirty = true; tail_cursor_pos = ( head_cursor_pos += num_letter ); len += num_letter; } /* while still characters in string */ } if (text_dirty && notify_all_changes_delay ==0) { // time to update content text_dirty = false; call_listeners((long)INPUT_CHANGED); } else { text_dirty = true; next_update_call = notify_all_changes_delay == 0xFFFFu ? 0xFFFFFFFFul : dr_time() + notify_all_changes_delay; } return false; } else if( IS_LEFTCLICK(ev) ) { // since now the focus could be received while the mouse no there, we must release it scr_rect this_comp( get_size() ); if( !this_comp.contains(scr_coord(ev->click_pos.x,ev->click_pos.y) ) ) { // not us, just in old focus from previous selection or tab return false; } // acting on release causes unwanted recalculations of cursor position for long strings and (scroll_offset>0) // moreover, only (click) or (release) event happened inside textinput, the other one could lie outside // use mouse *click* position; update both head and tail cursors tail_cursor_pos = 0; if( text ) { tail_cursor_pos = head_cursor_pos = display_fit_proportional( text, ev->click_pos.x - 2 + scroll_offset ); } cursor_reference_time = dr_time(); // update reference time for cursor blinking return true; } else if( IS_LEFTDRAG(ev) ) { // since now the focus could be received while the mouse is not there, we must release it scr_rect this_comp( get_size() ); if( !this_comp.contains(scr_coord(ev->click_pos.x,ev->click_pos.y) ) ) { // not us, just in old focus from previous selection or tab return false; } // use mouse *move* position; update head cursor only in order to enable text selection head_cursor_pos = 0; if( text ) { head_cursor_pos = display_fit_proportional( text, ev->mouse_pos.x - 1 + scroll_offset ); } cursor_reference_time = dr_time(); // update reference time for cursor blinking return true; } else if( IS_LEFTDBLCLK(ev) ) { // since now the focus could be received while the mouse is not there, we must release it scr_rect this_comp( get_size() ); if( !this_comp.contains(scr_coord(ev->click_pos.x,ev->click_pos.y) ) ) { // not us, just in old focus from previous selection or tab return false; } // select a word as delimited by spaces // for tail cursor pos -> skip over all contiguous non-space characters to the left const char* tmp_text = text + tail_cursor_pos; uint8 byte_length; uint8 pixel_width; while( tail_cursor_pos>0 && get_prev_char_with_metrics(tmp_text, text, byte_length, pixel_width)!=SIM_KEY_SPACE ) { tail_cursor_pos -= byte_length; } // for head cursor pos -> skip over all contiguous non-space characters to the right const size_t len = strlen(text); tmp_text = text + head_cursor_pos; while( head_cursor_posclick_pos.x,ev->click_pos.y) ) ) { // not us, just in old focus from previous selection or tab return false; } // select the whole text head_cursor_pos = strlen(text); tail_cursor_pos = 0; } else if( ev->ev_class==INFOWIN && ev->ev_code==WIN_UNTOP ) { if( text_dirty ) { text_dirty = false; call_listeners((long)INPUT_UNTOP); } return true; } else if( ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE && focus_received ) { // release focus on close and close keyboard dr_stop_textinput(); if (text_dirty) { // note all pending changes text_dirty = false; call_listeners((long)INPUT_UNTOP); } focus_received = false; } if (text_dirty && next_update_call < dr_time()) { // time to update content text_dirty = false; call_listeners((long)INPUT_CHANGED); } return false; } /** * Draw the component */ void gui_textinput_t::draw(scr_coord offset) { display_with_focus( offset, (win_get_focus()==this) ); if (text_dirty && next_update_call < dr_time()) { // need to trigger a dummy event for next processing event_t* ev = new event_t(); ev->ev_class = EVENT_KEYBOARD; ev->ev_code = 0; ev->ev_key_mod = 0; queue_event(ev); } } /** * Detect change of focus state and determine whether cursor should be displayed, * and call the function that performs the actual display */ void gui_textinput_t::display_with_focus(scr_coord offset, bool has_focus) { // check if focus state has changed if( focus_received!=has_focus ) { if( has_focus ) { // update reference time for cursor blinking if focus has just been received cursor_reference_time = dr_time(); dr_start_textinput(); const scr_coord gui_xy = win_get_pos( win_get_top() ); const scr_coord_val x = pos.x + gui_xy.x + get_current_cursor_x(); const scr_coord_val y = pos.x + gui_xy.y + D_TITLEBAR_HEIGHT; dr_notify_input_pos({ x, y }); } else { dr_stop_textinput(); } focus_received = has_focus; } display_with_cursor( offset, has_focus, (has_focus && ((dr_time()-cursor_reference_time)&512ul)==0) ); } void gui_textinput_t::display_with_cursor(scr_coord offset, bool cursor_active, bool cursor_visible) { display_img_stretch( gui_theme_t::editfield, scr_rect( pos+offset, size ) ); if( text ) { if (head_cursor_pos == 0xFFFF) { // since before the first draw, the text was likely not set correctly head_cursor_pos = strlen(text); } // recalculate scroll offset const int text_width = proportional_string_width(text); const scr_coord_val view_width = size.w - 3; const int cursor_offset = cursor_active ? proportional_string_len_width(text, head_cursor_pos) : 0; if( text_width<=view_width ) { // case : text is shorter than displayable width of the text input // -> the only case where left and right alignments differ // -> pad empty spaces on the left if right-aligned scroll_offset = align==ALIGN_RIGHT ? text_width - view_width : 0; } else { if( scroll_offset<0 ) { // case : if text is longer than displayable width of the text input // but there is empty space to the left // -> the text should move leftwards to fill up the empty space scroll_offset = 0; } if( cursor_offset-scroll_offset>view_width ) { // case : cursor has moved too far off the right side scroll_offset = cursor_offset - view_width; } else if( cursor_offsettext_width ) { // case : if text is longer than displayable width of the text input // but there is empty space to the right // -> the text should move rightwards to fill up the empty space scroll_offset = text_width - view_width; } } // set clipping to be within textinput button const int text_clip_x = pos.x + offset.x + 1; const int text_clip_w = size.w - 2; const int text_clip_y = pos.y + offset.y + 1; const int text_clip_h = size.h - 2; PUSH_CLIP_FIT(text_clip_x, text_clip_y, text_clip_w, text_clip_h); const int x_base_offset = pos.x+offset.x+2-scroll_offset; const int y_offset = pos.y+offset.y+D_GET_CENTER_ALIGN_OFFSET(LINESPACE,size.h); // display text (before composition) display_text_proportional_len_clip_rgb(x_base_offset, y_offset, text, ALIGN_LEFT | DT_CLIP, textcol, true, head_cursor_pos); int x_offset = proportional_string_len_width(text, head_cursor_pos); // IME text to display? if( composition.len() ) { // assert(head_cursor_pos==tail_cursor_pos); display_proportional_clip_rgb(x_base_offset+x_offset, y_offset, composition.get_str(), ALIGN_LEFT | DT_CLIP, textcol, true); // draw underline int composition_width = proportional_string_width(composition.get_str()); display_direct_line_rgb(x_base_offset+x_offset, y_offset+LINESPACE, x_base_offset+x_offset+composition_width, y_offset+LINESPACE-1, textcol); // mark targeted part in a similar manner to selected text int start_offset = proportional_string_len_width(composition.get_str(), composition_target_start); int highlight_width = proportional_string_len_width(composition.get_str()+composition_target_start, composition_target_length); display_fillbox_wh_clip_rgb(x_base_offset+x_offset+start_offset, y_offset, highlight_width, LINESPACE, SYSCOL_EDIT_BACKGROUND_SELECTED, true); display_text_proportional_len_clip_rgb(x_base_offset+x_offset+start_offset, y_offset, composition.get_str()+composition_target_start, ALIGN_LEFT|DT_CLIP, SYSCOL_EDIT_TEXT_SELECTED, false, composition_target_length); x_offset += composition_width; } // display text (after composition) display_proportional_clip_rgb(x_base_offset+x_offset, y_offset, text+head_cursor_pos, ALIGN_LEFT | DT_CLIP, textcol, true); if( cursor_active ) { // display selected text block with light grey text on charcoal bounding box if( head_cursor_pos!= tail_cursor_pos ) { const size_t start_pos = min(head_cursor_pos, tail_cursor_pos); size_t end_pos = ::max(head_cursor_pos, tail_cursor_pos); const scr_coord_val start_offset = proportional_string_len_width(text, start_pos); const scr_coord_val highlight_width = proportional_string_len_width(text+start_pos, end_pos-start_pos); display_fillbox_wh_clip_rgb(x_base_offset+start_offset, y_offset, highlight_width, LINESPACE, SYSCOL_EDIT_BACKGROUND_SELECTED, true); display_text_proportional_len_clip_rgb(x_base_offset+start_offset, y_offset, text+start_pos, ALIGN_LEFT|DT_CLIP, SYSCOL_EDIT_TEXT_SELECTED, false, end_pos-start_pos); } // display blinking cursor if( cursor_visible ) { display_fillbox_wh_clip_rgb(x_base_offset+cursor_offset-1, y_offset, 1, LINESPACE, SYSCOL_CURSOR_BEAM, true); } } // reset clipping POP_CLIP(); } } void gui_textinput_t::set_text(char *t, size_t max) { char *old_text = text; this->text = t; this->max = max; if (old_text && tail_cursor_pos == head_cursor_pos) { // if same, keep positions } else { // whole text is selected by default head_cursor_pos = 0xFFFF; tail_cursor_pos = 0; } text_dirty = false; } // needed to set the cursor on the right position bool gui_hidden_textinput_t::infowin_event(const event_t *ev) { if( IS_LEFTRELEASE(ev) ) { // since now the focus could be received while the mouse no there, we must release it scr_rect this_comp( get_size() ); if( !this_comp.contains(scr_coord(ev->click_pos.x,ev->click_pos.y) ) ) { // not us, just in old focus from previous selection or tab return false; } // acting on release causes unwanted recalculations of cursor position for long strings and (cursor_offset>0) // moreover, only (click) or (release) event happened inside textinput, the other one could lie outside sint16 asterix_width = display_calc_proportional_string_len_width("*",1); head_cursor_pos = 0; if ( text ) { head_cursor_pos = min( strlen(text), ev->click_pos.x/asterix_width ); } cursor_reference_time = dr_time(); // update reference time for cursor blinking return true; } else { return gui_textinput_t::infowin_event( ev ); } } void gui_hidden_textinput_t::display_with_cursor(scr_coord const offset, bool, bool const cursor_visible) { display_img_stretch( gui_theme_t::editfield, scr_rect( pos+offset, size ) ); if( text ) { // the text will be all asterisk, thus we draw them letter by letter // set clipping to be within textinput button const clip_dimension old_clip = display_get_clip_wh(); int text_clip_x = pos.x+offset.x + 1, text_clip_w = size.w - 2; // something to draw? if (text_clip_x >= old_clip.xx || text_clip_x+text_clip_w <= old_clip.x || text_clip_w<=0) { return; } const int clip_x = old_clip.x > text_clip_x ? old_clip.x : text_clip_x; display_set_clip_wh( clip_x, old_clip.y, min(old_clip.xx, text_clip_x+text_clip_w)-clip_x, old_clip.h); utf8 const *text_pos = (utf8 const*)text; utf8 const *end = (utf8 const*)text + max; sint16 xpos = pos.x+offset.x+2; utf32 c = 0; do { // cursor? if( cursor_visible && text_pos == (utf8 const*)text + head_cursor_pos ) { display_fillbox_wh_clip_rgb( xpos, pos.y+offset.y+1+(size.h-LINESPACE)/2, 1, LINESPACE, SYSCOL_CURSOR_BEAM, true); } c = utf8_decoder_t::decode((utf8 const *&)text_pos); if(c) { xpos += display_proportional_clip_rgb( xpos, pos.y+offset.y+1+(size.h-LINESPACE)/2, "*", ALIGN_LEFT | DT_CLIP, textcol, true); } } while( text_pos < end && c != UNICODE_NUL ); // reset clipping display_set_clip_wh(old_clip.x, old_clip.y, old_clip.w, old_clip.h); } } simutrans-124.3/src/simutrans/gui/components/gui_textinput.h000066400000000000000000000072001474050137200244200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_TEXTINPUT_H #define GUI_COMPONENTS_GUI_TEXTINPUT_H #include "gui_action_creator.h" #include "gui_component.h" #include "../../simcolor.h" #include "../../display/simgraph.h" #include "../../utils/cbuffer.h" /** * A simple text input field. It has no Text Buffer, * only a pointer to a buffer created by someone else. */ class gui_textinput_t : public gui_action_creator_t, public gui_component_t { protected: /** * The string buffer */ char *text; // text, which has not yet inputted (i.e. by an IME) cbuffer_t composition; size_t composition_target_start; size_t composition_target_length; /** * Maximum length of the string buffer */ size_t max; /** * position of head cursor to the text * represents front end of the selected text portion */ size_t head_cursor_pos; /** * position of tail cursor to the text * represent rear end of the selected text portion */ size_t tail_cursor_pos; /** * offset for controlling horizontal text scroll */ scr_coord_val scroll_offset; /** * text alignment */ uint8 align; PIXVAL textcol; // true if there were changed but no notification was sent yet bool text_dirty : 1; /** * whether focus has been received */ bool focus_received : 1; /** * whether focus has been received */ uint16 notify_all_changes_delay; uint32 next_update_call; /** * reference time for regulating cursor blinking */ uint32 cursor_reference_time; /** * determine new cursor position from event coordinates */ size_t calc_cursor_pos(const int x); /** * Remove selected text portion, if any. * Returns true if some selected text is actually deleted. */ bool remove_selection(); public: // three messages for the calling enum { INPUT_UNTOP = 0, INPUT_FINISHED, INPUT_CHANGED }; gui_textinput_t(); // update changes with delay (in ms), 0=immeadiately 0xFFFF=never void set_notify_all_changes_delay(uint16 _n) { notify_all_changes_delay = _n; } /** * Sets the Text buffer */ void set_text(char *text, size_t max); // text which is not yet inputed (i.e. for east asian text), assuming either native or utf8 encoding void set_composition_status( char *composition, int target_start, int target_length ); /** * Return the Text buffer */ char *get_text() const { return text; } const char *get_composition() const { return composition.get_str(); } bool infowin_event(event_t const*) OVERRIDE; /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; // x position of the current cursor (for IME purposes) scr_coord_val get_current_cursor_x() { return calc_cursor_pos(head_cursor_pos); } /** * Detect change of focus state and determine whether cursor should be displayed, * and call the function that performs the actual display */ void display_with_focus(scr_coord offset, bool has_focus); // function that performs the actual display virtual void display_with_cursor(scr_coord offset, bool cursor_active, bool cursor_visible); // to allow for right-aligned text void set_alignment(uint8 _align){ align = _align;} // to set text color void set_color(PIXVAL col){ textcol = col;} scr_size get_max_size() const OVERRIDE; scr_size get_min_size() const OVERRIDE; }; class gui_hidden_textinput_t : public gui_textinput_t { // and set the cursor right when clicking with the mouse bool infowin_event(event_t const*) OVERRIDE; // function that performs the actual display; just draw with stars ... void display_with_cursor(scr_coord offset, bool cursor_active, bool cursor_visible) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/components/gui_timeinput.cc000066400000000000000000000044661474050137200245430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_timeinput.h" #include "../simwin.h" #include "../../display/simgraph.h" #include "../../macros.h" #include "../../dataobj/translator.h" #include "../../simevent.h" #include "../../dataobj/environment.h" gui_timeinput_t::gui_timeinput_t(const char *) { bool has_days = env_t::show_month > env_t::DATE_FMT_MONTH; set_table_layout(3+has_days, 1); set_alignment(ALIGN_LEFT | ALIGN_TOP); set_margin(scr_size(D_H_SPACE, 0), scr_size(D_H_SPACE, 0)); days.set_visible(has_days); days.init(0, 0, 31); days.add_listener(this); days.allow_tooltip(false); add_component(&days); hours.init(0, 0, 23); hours.add_listener(this); hours.allow_tooltip(false); add_component(&hours); new_component(":"); minutes.init(0, 0, 59); minutes.add_listener(this); minutes.allow_tooltip(false); add_component(&minutes); b_enabled = true; } sint32 gui_timeinput_t::get_ticks() { sint32 dms = (days.get_value()-b_absolute) * 24 * 60 + hours.get_value() * 60 + minutes.get_value(); if (dms == 0) { return 0; } if (env_t::show_month <= env_t::DATE_FMT_MONTH) { return (dms * 65536u) / (24 * 60)+1; } return (dms * 65536u) / (31 * 24 * 60)+1; } void gui_timeinput_t::set_ticks(uint16 t,bool absolute) { sint32 ticks = t; b_absolute = absolute; days.set_limits( 0+absolute, 30+absolute ); // this is actually ticks*daylength*24*60/65536 but to avoid overflow the factor 32 was removed from both) sint32 new_dms = (ticks * (env_t::show_month == env_t::DATE_FMT_MONTH ? 1 : 31) * 3 * 15) / (2048); days.set_value(new_dms / (24 * 60)+absolute); hours.set_value((new_dms / 60) % 24); minutes.set_value(new_dms % 60); } bool gui_timeinput_t::action_triggered(gui_action_creator_t*, value_t) { uint16 t = get_ticks(); call_listeners(t); return false; } void gui_timeinput_t::draw(scr_coord offset) { gui_aligned_container_t::draw(offset); if(b_enabled && getroffen( get_mouse_pos() - offset )) { win_set_tooltip(get_mouse_pos() + TOOLTIP_MOUSE_OFFSET, translator::translate("Enter intervall in days, hours, minutes" ), this); } } void gui_timeinput_t::rdwr( loadsave_t *file ) { uint16 ticks=get_ticks(); file->rdwr_short( ticks ); file->rdwr_bool( b_absolute ); set_ticks(ticks,b_absolute); } simutrans-124.3/src/simutrans/gui/components/gui_timeinput.h000066400000000000000000000020421474050137200243710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_TIMEINPUT_H #define GUI_COMPONENTS_GUI_TIMEINPUT_H #include "../../simtypes.h" #include "../../display/scr_coord.h" #include "gui_action_creator.h" #include "gui_label.h" #include "gui_button.h" #include "gui_aligned_container.h" #include "gui_numberinput.h" /** * An input field for game time (internally as ticks) * The actual input is 0...65535, which is minute precision and then shifted by bit_shift_per_month-16 */ class gui_timeinput_t : public gui_action_creator_t, public gui_aligned_container_t, public action_listener_t { private: gui_numberinput_t days, hours, minutes; bool b_enabled, b_absolute; public: gui_timeinput_t(const char *null_text); sint32 get_ticks(); void set_ticks(uint16 t,bool absolute); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr( loadsave_t *file ); void draw(scr_coord offset) OVERRIDE; void enable(bool b) { b_enabled = b; } }; #endif simutrans-124.3/src/simutrans/gui/components/gui_waytype_tab_panel.cc000066400000000000000000000063321474050137200262260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_waytype_tab_panel.h" #include "../../simskin.h" #include "../../simhalt.h" #include "../../builder/vehikelbauer.h" #include "../../obj/way/kanal.h" #include "../../obj/way/maglev.h" #include "../../obj/way/monorail.h" #include "../../obj/way/narrowgauge.h" #include "../../obj/way/runway.h" #include "../../obj/way/schiene.h" #include "../../obj/way/strasse.h" #include "../../dataobj/translator.h" #include "../../descriptor/skin_desc.h" void gui_waytype_tab_panel_t::init_tabs(gui_component_t* c) { uint8 max_idx = 0; add_tab(c, translator::translate("All")); tabs_to_waytype[max_idx++] = ignore_wt; // now add all specific tabs if (maglev_t::default_maglev) { add_tab(c, translator::translate("Maglev"), skinverwaltung_t::maglevhaltsymbol, translator::translate("Maglev")); tabs_to_waytype[max_idx++] = maglev_wt; } if (monorail_t::default_monorail) { add_tab(c, translator::translate("Monorail"), skinverwaltung_t::monorailhaltsymbol, translator::translate("Monorail")); tabs_to_waytype[max_idx++] = monorail_wt; } if (schiene_t::default_schiene) { add_tab(c, translator::translate("Train"), skinverwaltung_t::zughaltsymbol, translator::translate("Train")); tabs_to_waytype[max_idx++] = track_wt; } if (narrowgauge_t::default_narrowgauge) { add_tab(c, translator::translate("Narrowgauge"), skinverwaltung_t::narrowgaugehaltsymbol, translator::translate("Narrowgauge")); tabs_to_waytype[max_idx++] = narrowgauge_wt; } if (!vehicle_builder_t::get_info(tram_wt).empty()) { add_tab(c, translator::translate("Tram"), skinverwaltung_t::tramhaltsymbol, translator::translate("Tram")); tabs_to_waytype[max_idx++] = tram_wt; } if (strasse_t::default_strasse) { add_tab(c, translator::translate("Truck"), skinverwaltung_t::autohaltsymbol, translator::translate("Truck")); tabs_to_waytype[max_idx++] = road_wt; } if (!vehicle_builder_t::get_info(water_wt).empty()) { add_tab(c, translator::translate("Ship"), skinverwaltung_t::schiffshaltsymbol, translator::translate("Ship")); tabs_to_waytype[max_idx++] = water_wt; } if (runway_t::default_runway) { add_tab(c, translator::translate("Aircraft"), skinverwaltung_t::airhaltsymbol, translator::translate("Aircraft")); tabs_to_waytype[max_idx++] = air_wt; } } void gui_waytype_tab_panel_t::set_active_tab_waytype(waytype_t wt) { for(uint32 i=0; i < get_count(); i++ ) { if (wt == tabs_to_waytype[i]) { set_active_tab_index(i); return; } } // assume invalid type set_active_tab_index(0); } haltestelle_t::stationtyp gui_waytype_tab_panel_t::get_active_tab_stationtype() const { switch(get_active_tab_waytype()) { case air_wt: return haltestelle_t::airstop; case road_wt: return haltestelle_t::loadingbay | haltestelle_t::busstop; case track_wt: return haltestelle_t::railstation; case water_wt: return haltestelle_t::dock; case monorail_wt: return haltestelle_t::monorailstop; case maglev_wt: return haltestelle_t::maglevstop; case tram_wt: return haltestelle_t::tramstop; case narrowgauge_wt: return haltestelle_t::narrowgaugestop; default: return haltestelle_t::invalid; } } simutrans-124.3/src/simutrans/gui/components/gui_waytype_tab_panel.h000066400000000000000000000016671474050137200260760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_WAYTYPE_TAB_PANEL_H #define GUI_COMPONENTS_GUI_WAYTYPE_TAB_PANEL_H #include "../../simtypes.h" #include "../../simhalt.h" #include "gui_tab_panel.h" // panel that show the available waytypes class gui_waytype_tab_panel_t : public gui_tab_panel_t { private: // since waytypes may change during timeline waytype_t tabs_to_waytype[9]; public: gui_waytype_tab_panel_t() { gui_tab_panel_t(); } // all tabs habe the same gui_component with this! void init_tabs(gui_component_t *c); waytype_t get_active_tab_waytype() const { return tabs_to_waytype[get_active_tab_index()]; } void set_active_tab_waytype(waytype_t wt); haltestelle_t::stationtyp get_active_tab_stationtype() const; waytype_t get_tab_waytype(int i) const { return 0<=i && (uint32)i #include "gui_world_view.h" #include "../../world/simworld.h" #include "../../display/viewport.h" #include "../../obj/simobj.h" #include "../../obj/zeiger.h" #include "../../display/simgraph.h" #include "../../simcolor.h" #include "../../ground/grund.h" #include "../../dataobj/environment.h" #include "../../dataobj/koord3d.h" #include "../../vehicle/air_vehicle.h" vector_tpl world_view_t::view_list; void world_view_t::invalidate_all() { world_view_t *const *const endpointer = world_view_t::view_list.end(); for (world_view_t *const *pointer = world_view_t::view_list.begin() ; pointer != endpointer ; pointer++) { (*pointer)->prepared_rect.discard_area(); } } world_view_t::world_view_t(scr_size size ) : prepared_rect(), display_rect(), raster(get_base_tile_raster_width()) { set_size( size ); min_size = size; world_view_t::view_list.append(this); } world_view_t::world_view_t() : prepared_rect(), display_rect(), raster(get_base_tile_raster_width()) { world_view_t::view_list.append(this); } world_view_t::~world_view_t() { world_view_t::view_list.remove(this); } /** * Events are notified to GUI components via this method */ bool world_view_t::infowin_event(const event_t* ev) { if(IS_LEFTRELEASE(ev)) { koord3d const& pos = get_location(); if (welt->is_within_limits(pos.get_2d())) { welt->get_viewport()->change_world_position(pos); welt->get_zeiger()->change_pos( pos ); } return true; } return false; } void world_view_t::internal_draw(const scr_coord offset, obj_t const* const obj) { display_set_image_proc(false); const koord3d here3d = get_location(); const koord here = here3d.get_2d(); scr_coord fine_here = scr_coord(0, 0); sint16 y_offset = 0; if(obj) { // offsets? fine_here = scr_coord(tile_raster_scale_x(-obj->get_xoff(), raster), tile_raster_scale_y(-obj->get_yoff() % (OBJECT_OFFSET_STEPS * 2), raster)); y_offset = obj->get_yoff() / (OBJECT_OFFSET_STEPS * 2); if(vehicle_base_t const* const v = obj_cast(obj)) { int x = 0; int y = 0; v->get_screen_offset(x, y, raster); fine_here -= scr_coord(x, y); } } koord const height_offset(y_offset, y_offset); grund_t const* const kb = welt->lookup_kartenboden(here); if(!kb) { return; } int hgt = tile_raster_scale_y(here3d.z * TILE_HEIGHT_STEP, raster); if(obj) { air_vehicle_t const* const plane = obj_cast(obj); if(plane) { hgt += tile_raster_scale_y(plane->get_flyingheight(), raster); } } const scr_coord pos = get_pos() + offset + scr_coord(1, 1); // do not draw outside (may happen with scroll bars) const clip_dimension old_clip = display_get_clip_wh(); // something to draw? const scr_size size = get_size() - scr_size(2, 2); if( old_clip.xx <= pos.x || pos.x + size.w <= old_clip.x || size.w <= 0 ) { return; } if( old_clip.yy <= pos.y || pos.y + size.h <= old_clip.y || size.h <= 0 ) { return; } // prepare view rect_t const world_rect(koord(0, 0), welt->get_size()); rect_t view_rect = display_rect; view_rect.origin+= here + height_offset; view_rect.mask(world_rect); if (view_rect != prepared_rect) { welt->prepare_tiles(view_rect, prepared_rect); prepared_rect = view_rect; } // prepare clip area const int clip_x = max(old_clip.x, pos.x); const int clip_y = max(old_clip.y, pos.y); display_set_clip_wh(clip_x, clip_y, min(old_clip.xx, pos.x + size.w) - clip_x, min(old_clip.yy, pos.y + size.h) - clip_y); mark_rect_dirty_wc(pos.x, pos.y, pos.x + size.w, pos.y + size.h); /* Not very elegant, but works: Fill everything with black for underground * mode. */ if( grund_t::underground_mode ) { display_fillbox_wh_clip_rgb(pos.x, pos.y, size.w, size.h, color_idx_to_rgb(COL_BLACK), true); } else { display_fillbox_wh_clip_rgb(pos.x, pos.y, size.w, size.h, env_t::background_color, true); } const sint16 yoff = obj && obj->is_moving() ? size.h / 2 - raster * 3 / 4 : // align 1/4 raster from the bottom of the image size.h - raster; // align the bottom of the image const scr_coord display_off = scr_coord((size.w - raster) / 2, hgt + yoff) + fine_here; // display grounds for(koord const& off : offsets) { const koord k = here + off + height_offset; const sint16 off_x = (off.x - off.y) * 32 * raster / 64 + display_off.x; if( off_x + raster < 0 || size.w < off_x || k.x < 0 || k.y < 0 ) { continue; } grund_t *kb = welt->lookup_kartenboden(k); if( !kb ) { continue; } const sint16 yypos = display_off.y + (off.y + off.x) * 16 * raster / 64 - tile_raster_scale_y(kb->get_disp_height() * TILE_HEIGHT_STEP, raster); if( size.h < yypos ) { break; // enough with grounds } else if( 0 <= yypos + raster ) { #ifdef MULTI_THREAD kb->display_if_visible( pos.x + off_x, pos.y + yypos, raster, 0 ); #else kb->display_if_visible( pos.x + off_x, pos.y + yypos, raster ); #endif } } // display things for(koord const& off : offsets) { const koord k = here + off + height_offset; const sint16 off_x = (off.x - off.y) * 32 * raster / 64 + display_off.x; if( off_x + raster < 0 || size.w < off_x || k.x < 0 || k.y < 0 ) { continue; } const planquadrat_t * const plan = welt->access(k); if(!plan) { continue; } const grund_t * const kb = plan->get_kartenboden(); if(!kb) { continue; } const sint8 h = kb->get_hoehe(); // minimum height: ground height for overground, // for the definition of underground_level see grund_t::set_underground_mode const sint8 hmin = min(h, grund_t::underground_level); // maximum height: 127 for overground, underground level for sliced, ground height-1 for complete underground view const sint8 hmax = grund_t::underground_mode == grund_t::ugm_all ? h - !kb->ist_tunnel() : grund_t::underground_level; const sint16 yypos = display_off.y + (off.y + off.x) * 16 * raster / 64 - tile_raster_scale_y(kb->get_disp_height() * TILE_HEIGHT_STEP, raster); if( 0 <= yypos + raster && yypos - raster * 2 < size.h ) { #ifdef MULTI_THREAD plan->display_obj( pos.x + off_x, pos.y + yypos, raster, false, hmin, hmax, 0 ); #else plan->display_obj( pos.x + off_x, pos.y + yypos, raster, false, hmin, hmax ); #endif } else if( yypos > size.h ) { break; // now we can finish } } // this should only happen for airplanes: out of image, so we need to extra display them if( y_offset != 0 ) { const grund_t * const g = welt->lookup(obj->get_pos()); const sint16 yypos = display_off.y - tile_raster_scale_y(2 * y_offset * 16, raster) - tile_raster_scale_y(g->get_disp_height() * TILE_HEIGHT_STEP, raster); #ifdef MULTI_THREAD g->display_obj_all( pos.x + display_off.x, pos.y + yypos, raster, false, 0 ); #else g->display_obj_all( pos.x + display_off.x, pos.y + yypos, raster, false ); #endif } display_set_clip_wh(old_clip.x, old_clip.y, old_clip.w, old_clip.h); display_ddd_box_clip_rgb(pos.x - 1, pos.y - 1, size.w + 2, size.h + 2, color_idx_to_rgb(MN_GREY0), color_idx_to_rgb(MN_GREY4)); } /** * Resize the contents of the window */ void world_view_t::set_size(scr_size size) { gui_component_t::set_size(size); calc_offsets(size, 5); } /** * Recalculates the number of tiles needed */ void world_view_t::calc_offsets(scr_size size, sint16 dy_off) { const sint16 max_dx = size.w/(raster/2) + 2; const sint16 max_dy = (size.h/(raster/2) + dy_off)&0x0FFE; // build offset list offsets.clear(); for( sint16 dy = -max_dy; dy <= 5; ) { { for( sint16 dx =- 2; dx < max_dx; dx += 2 ) { const koord check( (dy + dx) / 2, (dy - dx) / 2); offsets.append(check); } } dy++; for( sint16 dx = -1; dx < max_dx; dx += 2 ) { const koord check( (dy + dx) / 2, (dy - dx) / 2); offsets.append(check); } dy++; } // determine preparation extents koord offset_extent_min(0, 0); koord offset_extent_max(0, 0); koord const *const iter_end = offsets.end(); for (koord const *iter = offsets.begin() ; iter != iter_end ; iter++) { sint16 const x = iter->x; sint16 const y = iter->y; if (x < offset_extent_min.x) { offset_extent_min.x = x; }else if (x > offset_extent_max.x) { offset_extent_max.x = x; } if (y < offset_extent_min.y) { offset_extent_min.y = y; }else if (y > offset_extent_max.y) { offset_extent_max.y = y; } } display_rect = rect_t(offset_extent_min, offset_extent_max - offset_extent_min + koord(1, 1)); } simutrans-124.3/src/simutrans/gui/components/gui_world_view.h000066400000000000000000000044761474050137200245510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_COMPONENTS_GUI_WORLD_VIEW_H #define GUI_COMPONENTS_GUI_WORLD_VIEW_H #include "gui_component.h" #include "../../dataobj/koord3d.h" #include "../../tpl/vector_tpl.h" #include "../../dataobj/rect.h" class obj_t; /** * Displays a little piece of the world */ class world_view_t : public gui_world_component_t { private: /** * @brief Contains a reference to every world_view_t object. * * Used to allow mass invalidating of all prepared area for cases such as * changing underground mode and snow levels. */ static vector_tpl view_list; /** * @brief The prepared area of the view port. * * The area that has already been prepared for this view port. When the view * port is moved then only the new area not already prepared will be * prepared. If the view port is stationary no area will be prepared. */ rect_t prepared_rect; /** * @brief The display area centered around the map origin. * * The area used by this view to display the world. It is centered around * the origin but can easilly be shifted to where the actual view is * focused. */ rect_t display_rect; vector_tpl offsets; /**< Offsets are stored. */ sint16 raster; /**< For this rastersize. */ scr_size min_size; ///< set by constructor protected: virtual koord3d get_location() = 0; void internal_draw(scr_coord offset, obj_t const *); void calc_offsets(scr_size size, sint16 dy_off); public: /** * @brief Clears all prepared area. * * Set prepared rect to have no area. Used when all views must be reprepared * such as changing underground mode or slice. This method is required * because object views use completly separate draw logic from the main map * view and must also have their prepared area invalidated for correct * graphic reproduction. */ static void invalidate_all(); world_view_t(scr_size size); world_view_t(); ~world_view_t(); bool infowin_event(event_t const*) OVERRIDE; /** * resize window in response to a resize event * need to recalculate the list of offsets */ void set_size(scr_size size) OVERRIDE; scr_size get_min_size() const OVERRIDE { return min_size; } scr_size get_max_size() const OVERRIDE { return min_size; } }; #endif simutrans-124.3/src/simutrans/gui/convoi_detail.cc000066400000000000000000000152761474050137200223140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "convoi_detail.h" #include "components/gui_divider.h" #include "components/gui_image.h" #include "components/gui_textarea.h" #include "../simconvoi.h" #include "../vehicle/vehicle.h" #include "../simcolor.h" #include "../world/simworld.h" #include "../simware.h" #include "../simintr.h" #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" karte_ptr_t convoi_detail_t::welt; class gui_vehicleinfo_t : public gui_aligned_container_t { vehicle_t *v; cbuffer_t freight_info; gui_label_buf_t label_resale, label_friction, label_freight_summary; gui_textarea_t freight; public: gui_vehicleinfo_t(vehicle_t *v, sint32 cnv_kmh) : freight(&freight_info) { this->v = v; set_table_layout(2,0); set_alignment(ALIGN_TOP | ALIGN_LEFT); const int month_now = world()->get_timeline_year_month(); // image new_component(v->get_loaded_image(), v->get_owner_nr())->enable_offset_removal(true); add_table(1,0); { // name new_component( v->get_desc()->get_name(), world()->use_timeline() && v->get_desc()->is_retired(month_now) ? SYSCOL_OBSOLETE : SYSCOL_TEXT); // age gui_label_buf_t* l = new_component(); const sint32 month = v->get_purchase_time(); l->buf().printf("%s %s %i", translator::translate("Manufactured:"), translator::get_month_name(month%12), month/12 ); l->update(); // value add_component(&label_resale); // max income sint64 max_income = - v->get_operating_cost(); // cnv_kmh == SPEED_UNLIMITED means that meaningful revenue // cannot be calculated yet (e.g. vehicle in depot or stopped at station) if(v->get_cargo_max() > 0 && cnv_kmh != SPEED_UNLIMITED) { max_income += (v->get_cargo_max() * ware_t::calc_revenue(v->get_cargo_type(), v->get_waytype(), cnv_kmh))/3000; } add_table(2,1); { new_component("Max income:"); l = new_component(); l->buf().append_money(max_income/100.0); l->update(); } end_table(); // loading time if (v->get_desc()->get_capacity() > 0) { l = new_component(); l->buf().printf("%s%s", translator::translate("Loading time:"), difftick_to_string(v->get_desc()->get_loading_time(),false) ); l->update(); } // power if(v->get_desc()->get_power()>0) { l = new_component(); l->buf().printf("%s %i kW, %s %.2f", translator::translate("Power:"), v->get_desc()->get_power(), translator::translate("Gear:"), v->get_desc()->get_gear()/64.0 ); l->update(); } // friction add_component(&label_friction); if(v->get_cargo_max() > 0) { add_component( &label_freight_summary ); add_component(&freight); } } end_table(); update_labels(); } void update_labels() { label_resale.buf().printf("%s ", translator::translate("Restwert:")); label_resale.buf().append_money(v->calc_sale_value() / 100.0); if( sint64 fix_cost = world()->scale_with_month_length((sint64)v->get_desc()->get_maintenance()) ) { cbuffer_t temp_buf; temp_buf.printf( translator::translate("(%.2f$/km %.2f$/m)"), (double)v->get_desc()->get_running_cost()/100.0, (double)fix_cost/100.0 ); label_resale.buf().append( temp_buf ); } else { cbuffer_t temp_buf; temp_buf.printf( translator::translate("(%.2f$/km)"), (double)v->get_desc()->get_running_cost()/100.0 ); label_resale.buf().append( temp_buf ); } label_resale.update(); label_friction.buf().printf( "%s %i", translator::translate("Friction:"), v->get_frictionfactor() ); label_friction.update(); if(v->get_cargo_max() > 0) { // freight type goods_desc_t const& g = *v->get_cargo_type(); char const* const name = translator::translate( g.get_catg() == 0?g.get_name():g.get_catg_name() ); label_freight_summary.buf().printf( "%u/%u%s %s", v->get_total_cargo(), v->get_cargo_max(), translator::translate( v->get_cargo_mass() ), name ); label_freight_summary.update(); freight_info.clear(); v->get_cargo_info(freight_info); } } void draw(scr_coord offset) OVERRIDE { update_labels(); gui_aligned_container_t::draw(offset); } }; convoi_detail_t::convoi_detail_t(convoihandle_t cnv) : scrolly(&container_veh) { if (cnv.is_bound()) { init(cnv); } } void convoi_detail_t::init(convoihandle_t cnv) { this->cnv = cnv; set_table_layout(1,0); add_component( &container_txt ); container_txt.set_margin( scr_size(D_MARGIN_LEFT,0), scr_size(D_MARGIN_RIGHT,0) ); container_txt.set_table_layout(1,0); container_txt.add_component(&label_power); container_txt.add_component(&label_odometer); container_txt.add_component(&label_length); container_txt.add_component(&label_resale); container_txt.add_component(&label_speed); add_component(&scrolly); const sint32 cnv_kmh = (cnv->front()->get_waytype() == air_wt) ? speed_to_kmh(cnv->get_min_top_speed()) : cnv->get_speedbonus_kmh(); container_veh.set_table_layout(1,0); container_veh.set_checkered(true); container_veh.new_component(); for(unsigned veh=0; vehget_vehicle_count(); veh++ ) { // if(veh>0) { // only on non-checkred lists // container_veh.new_component(); // } vehicle_t *v = cnv->get_vehicle(veh); container_veh.new_component(v, cnv_kmh); } update_labels(); } void convoi_detail_t::update_labels() { char number[128]; number_to_string( number, (double)cnv->get_total_distance_traveled(), 0 ); label_odometer.buf().printf(translator::translate("Odometer: %s km"), number ); label_odometer.update(); label_power.buf().printf( translator::translate("Leistung: %d kW"), cnv->get_sum_power() ); label_power.update(); if( cnv->get_vehicle_count()>0 && cnv->get_vehicle( 0 )->get_desc()->get_waytype()==water_wt ) { label_length.buf().printf( "%s %i", translator::translate( "Vehicle count:" ), cnv->get_vehicle_count() ); } else { label_length.buf().printf( "%s %i %s %s %i %s", translator::translate( "Vehicle count:" ), cnv->get_vehicle_count(), "(", translator::translate( "Station tiles:" ), cnv->get_tile_length(), ")"); } label_length.update(); label_resale.buf().printf("%s ", translator::translate("Restwert:")); label_resale.buf().append_money( cnv->calc_restwert() / 100.0 ); label_resale.update(); label_speed.buf().printf(translator::translate("Bonusspeed: %i km/h"), cnv->get_speedbonus_kmh() ); label_speed.update(); } void convoi_detail_t::draw(scr_coord offset) { update_labels(); scrolly.set_size(scrolly.get_size()); gui_aligned_container_t::draw(offset); } void convoi_detail_t::rdwr(loadsave_t *file) { scrolly.rdwr(file); } simutrans-124.3/src/simutrans/gui/convoi_detail.h000066400000000000000000000022211474050137200221400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CONVOI_DETAIL_H #define GUI_CONVOI_DETAIL_H #include "components/gui_aligned_container.h" #include "components/gui_scrollpane.h" #include "components/gui_label.h" #include "../convoihandle.h" class scr_coord; class karte_ptr_t; /** * Convoi details component * Fills information table for convoi */ class convoi_detail_t : public gui_aligned_container_t { public: enum sort_mode_t { by_destination = 0, by_via = 1, by_amount_via = 2, by_amount = 3, SORT_MODES = 4 }; private: gui_aligned_container_t container_veh, container_txt; gui_scrollpane_t scrolly; gui_label_buf_t label_power, label_odometer, label_resale, label_length, label_speed; convoihandle_t cnv; static karte_ptr_t welt; public: convoi_detail_t(convoihandle_t cnv = convoihandle_t()); /** * Initializes layout, @p cnv needs to be valid. */ void init(convoihandle_t cnv); void draw(scr_coord offset) OVERRIDE; void update_labels(); void rdwr( loadsave_t *file ); bool is_marginless() const OVERRIDE { return true; } }; #endif simutrans-124.3/src/simutrans/gui/convoi_filter_frame.cc000066400000000000000000000116621474050137200235040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "convoi_filter_frame.h" #include "convoi_frame.h" #include "components/gui_convoiinfo.h" #include "../simcolor.h" #include "../descriptor/goods_desc.h" #include "../builder/goods_manager.h" #include "../dataobj/translator.h" const char *convoi_filter_frame_t::filter_buttons_text[FILTER_BUTTONS] = { "clf_chk_spezial_filter", "clf_chk_waren", "clf_chk_noroute", "clf_chk_stucked", "clf_chk_noincome", "clf_chk_indepot", "clf_chk_noschedule", "clf_chk_noline", "clf_chk_obsolete" }; convoi_filter_frame_t::filter_flag_t convoi_filter_frame_t::filter_buttons_types[FILTER_BUTTONS] = { special_filter, ware_filter, noroute_filter, stucked_filter, noincome_filter, indepot_filter, noschedule_filter, noline_filter, obsolete_filter }; slist_tplconvoi_filter_frame_t::active_ware; uint32 convoi_filter_frame_t::filter_flags = 0; convoi_filter_frame_t::convoi_filter_frame_t(player_t *player, convoi_frame_t *m) : gui_frame_t( translator::translate("clf_title"), player), main_frame(m), ware_scrolly(&ware_cont) { for( int i=0; i < FILTER_BUTTONS; i++ ) { filter_buttons[i].init(button_t::square_state, filter_buttons_text[i]); filter_buttons[i].add_listener(this); if(filter_buttons_types[i] < sub_filter) { filter_buttons[i].background_color = color_idx_to_rgb(COL_WHITE); } filter_buttons[i].pressed = get_filter(filter_buttons_types[i]); } set_table_layout(1,0); set_alignment(ALIGN_TOP); add_table(3,0); { ware_alle.init(button_t::roundbox, "clf_btn_alle"); ware_alle.add_listener(this); add_component(&ware_alle); ware_keine.init(button_t::roundbox, "clf_btn_keine"); ware_keine.add_listener(this); add_component(&ware_keine); ware_invers.init(button_t::roundbox, "clf_btn_invers"); ware_invers.add_listener(this); add_component(&ware_invers); } end_table(); add_table( 2, 0 ); { add_table(2,0); { // special buttons add_component(filter_buttons, 2); for( int i=2; i(); add_component(filter_buttons + i); } } end_table(); ware_scrolly.set_scroll_amount_y(D_BUTTON_HEIGHT); add_component( &ware_scrolly ); } end_table(); ware_cont.set_table_layout(2,0); all_ware.clear(); ware_cont.add_component(filter_buttons + 1,2); for( int i=0; i < goods_manager_t::get_count(); i++ ) { const goods_desc_t *ware = goods_manager_t::get_info(i); if( ware == goods_manager_t::none ) { continue; } if( ware->get_catg() == 0 ) { // Special freight: Each good is special ware_cont.new_component(); ware_item_t *item = ware_cont.new_component(this, ware); item->init(button_t::square_state, translator::translate(ware->get_name())); item->pressed = active_ware.is_contained(ware); all_ware.append(item); } } // now add other good categories for( int i=1; i < goods_manager_t::get_max_catg_index(); i++ ) { const goods_desc_t *ware = goods_manager_t::get_info_catg(i); if( ware->get_catg() != 0 ) { ware_cont.new_component(); ware_item_t *item = ware_cont.new_component(this, ware); item->init(button_t::square_state, translator::translate(ware->get_catg_name())); item->pressed = active_ware.is_contained(ware); all_ware.append(item); } } set_resizemode(diagonal_resize); reset_min_windowsize(); } void convoi_filter_frame_t::init(uint32 filter_flags, const slist_tpl* wares) { for (int i = 0; i < FILTER_BUTTONS; i++) { set_filter(filter_buttons_types[i], filter_flags & filter_buttons_types[i]); filter_buttons[i].pressed = get_filter(filter_buttons_types[i]); } if (&active_ware != wares) { active_ware.clear(); if (wares) { for(ware_item_t* wi : all_ware) { wi->pressed = wares->is_contained(wi->ware); if (wi->pressed) { active_ware.append(wi->ware); } } } } } /** * This method is called if an action is triggered */ bool convoi_filter_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { for( int i = 0; i < FILTER_BUTTONS; i++) { if(comp == filter_buttons + i) { filter_buttons[i].pressed ^= 1; set_filter( filter_buttons_types[i], !get_filter(filter_buttons_types[i]) ); sort_list(); return true; } } if(comp == &ware_alle) { for(ware_item_t * wi : all_ware ) { wi->pressed = true; } sort_list(); return true; } if(comp == &ware_keine) { for(ware_item_t * wi : all_ware ) { wi->pressed = false; } sort_list(); return true; } if( comp == &ware_invers ) { for(ware_item_t * wi : all_ware ) { wi->pressed ^= true; } sort_list(); return true; } return false; } void convoi_filter_frame_t::sort_list() { active_ware.clear(); for(ware_item_t * wi : all_ware ) { if( wi->pressed ) { active_ware.append( wi->ware ); } } main_frame->sort_list( filter_flags, &active_ware ); } simutrans-124.3/src/simutrans/gui/convoi_filter_frame.h000066400000000000000000000060261474050137200233440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CONVOI_FILTER_FRAME_H #define GUI_CONVOI_FILTER_FRAME_H #include "gui_frame.h" #include "components/gui_label.h" #include "components/gui_scrollpane.h" #include "components/action_listener.h" #include "components/gui_button.h" class convoi_frame_t; class player_t; class goods_desc_t; /** * Displays a filter settings dialog for the convoi list */ class convoi_filter_frame_t : public gui_frame_t , private action_listener_t { public: enum filter_flag_t { any_filter = 1 << 0, special_filter = 1 << 1, ware_filter = 1 << 2, noroute_filter = 1 << 3, noschedule_filter = 1 << 4, noincome_filter = 1 << 5, indepot_filter = 1 << 6, noline_filter = 1 << 7, stucked_filter = 1 << 8, monorail_filter = 1 << 9, maglev_filter = 1 << 10, narrowgauge_filter = 1 << 11, tram_filter = 1 << 12, obsolete_filter = 1 << 13, // number of first special filter sub_filter = noroute_filter }; enum { FILTER_BUTTONS = 9 }; private: static uint32 filter_flags; bool get_filter(convoi_filter_frame_t::filter_flag_t filter) { return (filter_flags & filter) != 0; } void set_filter(convoi_filter_frame_t::filter_flag_t filter, bool on) { filter_flags = (on ? (filter_flags | filter) : (filter_flags & ~filter) ); } /* * Helper class for the entries of the scrollable list of goods. * Needed since a button_t does not know its parent. */ class ware_item_t : public button_t { public: const goods_desc_t *ware; convoi_filter_frame_t *parent; ware_item_t(convoi_filter_frame_t *parent, const goods_desc_t *ware) { this->ware = ware; this->parent = parent; } bool infowin_event(event_t const* const ev) OVERRIDE { bool swallow = button_t::infowin_event(ev); if( IS_LEFTRELEASE(ev) && swallow ) { pressed ^= 1; parent->sort_list(); } return swallow; } }; slist_tplall_ware; static slist_tplactive_ware; static filter_flag_t filter_buttons_types[FILTER_BUTTONS]; static const char *filter_buttons_text[FILTER_BUTTONS]; /* * We are bound to this window. All filter states are stored in main_frame. */ convoi_frame_t *main_frame; /* * All gui elements of this dialog: */ button_t filter_buttons[FILTER_BUTTONS]; button_t typ_filter_enable; button_t ware_alle; button_t ware_keine; button_t ware_invers; gui_aligned_container_t ware_cont; gui_scrollpane_t ware_scrolly; public: void sort_list(); /** * Constructor. Generates all necessary Subcomponents. */ convoi_filter_frame_t(player_t *player, convoi_frame_t *parent); void init(uint32 filter_flags, const slist_tpl* wares); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "convoi_filter.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/convoi_frame.cc000066400000000000000000000234601474050137200221360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "components/gui_convoiinfo.h" #include "convoi_frame.h" #include "convoi_filter_frame.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../obj/way/kanal.h" #include "../obj/way/maglev.h" #include "../obj/way/monorail.h" #include "../obj/way/narrowgauge.h" #include "../obj/way/runway.h" #include "../obj/way/schiene.h" #include "../obj/way/strasse.h" #include "simwin.h" #include "../simconvoi.h" #include "../world/simworld.h" #include "../utils/unicode.h" #include "../descriptor/goods_desc.h" #include "../builder/goods_manager.h" #include "../dataobj/translator.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../vehicle/vehicle.h" /** * All filter and sort settings are static, so the old settings are * used when the window is reopened. */ convoi_frame_t::sort_mode_t convoi_frame_t::sortby = convoi_frame_t::nach_name; bool convoi_frame_t::sortreverse = false; const char *convoi_frame_t::sort_text[SORT_MODES] = { "cl_btn_sort_name", "cl_btn_sort_income", "cl_btn_sort_type", "cl_btn_sort_id" }; const slist_tpl* convoi_frame_t::waren_filter = NULL; waytype_t convoi_frame_t::current_wt = waytype_t::ignore_wt; uint32 convoi_frame_t::filter_flags = 0; char convoi_frame_t::last_name_filter[256] = ""; char convoi_frame_t::name_filter[256] = ""; /** * Scrolled list of gui_convoiinfo_ts. * Filters (by setting visibility) and sorts. */ class gui_scrolled_convoy_list_t : public gui_scrolled_list_t { convoi_frame_t *main; static convoi_frame_t *main_static; public: gui_scrolled_convoy_list_t(convoi_frame_t *m) : gui_scrolled_list_t(gui_scrolled_list_t::windowskin) { main = m; set_cmp(compare); } void sort() { main_static = main; gui_scrolled_list_t::sort(0); } static bool compare(const gui_component_t *aa, const gui_component_t *bb) { const gui_convoiinfo_t *a = dynamic_cast(aa); const gui_convoiinfo_t *b = dynamic_cast(bb); return main_static->compare_convois(a->get_cnv(), b->get_cnv()); } }; convoi_frame_t* gui_scrolled_convoy_list_t::main_static; bool convoi_frame_t::passes_filter(convoihandle_t cnv) { if(current_wt && cnv->front()->get_desc()->get_waytype() != current_wt ) { // not the right kind of vehivle return false; } if( name_filter[0]!=0 && !utf8caseutf8(cnv->get_name(), name_filter) ) { // not the right name return false; } if( get_filter(convoi_filter_frame_t::special_filter) ) { if ((!get_filter(convoi_filter_frame_t::noroute_filter) || cnv->get_state() != convoi_t::NO_ROUTE) && (!get_filter(convoi_filter_frame_t::stucked_filter) || (cnv->get_state() != convoi_t::WAITING_FOR_CLEARANCE_TWO_MONTHS && cnv->get_state() != convoi_t::CAN_START_TWO_MONTHS)) && (!get_filter(convoi_filter_frame_t::indepot_filter) || !cnv->in_depot()) && (!get_filter(convoi_filter_frame_t::noline_filter) || cnv->get_line().is_bound()) && (!get_filter(convoi_filter_frame_t::noschedule_filter) || cnv->get_schedule()) && (!get_filter(convoi_filter_frame_t::noincome_filter) || cnv->get_jahresgewinn() >= 100) && (!get_filter(convoi_filter_frame_t::obsolete_filter) || !cnv->has_obsolete_vehicles())) { return false; } } if( get_filter(convoi_filter_frame_t::ware_filter) ) { unsigned i; for( i = 0; i < cnv->get_vehicle_count(); i++) { const goods_desc_t *wb = cnv->get_vehicle(i)->get_cargo_type(); if( wb->get_catg()!=0 ) { wb = goods_manager_t::get_info_catg(wb->get_catg()); } if( waren_filter->is_contained(wb) ) { return true; } } if( i == cnv->get_vehicle_count() ) { return false; } } return true; } bool convoi_frame_t::compare_convois(convoihandle_t const cnv1, convoihandle_t const cnv2) { sint32 result = 0; switch (sortby) { default: case nach_name: result = strcmp(cnv1->get_internal_name(), cnv2->get_internal_name()); break; case nach_gewinn: result = sgn(cnv1->get_jahresgewinn() - cnv2->get_jahresgewinn()); break; case nach_typ: if(cnv1->get_vehicle_count()*cnv2->get_vehicle_count()>0) { vehicle_t const* const fahr1 = cnv1->front(); vehicle_t const* const fahr2 = cnv2->front(); result = fahr1->get_typ() - fahr2->get_typ(); if(result == 0) { result = fahr1->get_cargo_type()->get_catg_index() - fahr2->get_cargo_type()->get_catg_index(); if(result == 0) { result = fahr1->get_base_image() - fahr2->get_base_image(); } } } break; case nach_id: result = cnv1.get_id()-cnv2.get_id(); break; } return sortreverse ? result > 0 : result < 0; } void convoi_frame_t::fill_list() { last_world_convois = welt->convoys().get_count(); current_wt = tabs.get_active_tab_waytype(); const bool all = owner->is_public_service(); scrolly->clear_elements(); for(convoihandle_t const cnv : welt->convoys()) { if( all || cnv->get_owner()==owner ) { if( passes_filter( cnv ) ) { scrolly->new_component( cnv ); } } } sort_list(); scrolly->set_size(scr_size(get_windowsize().w, scrolly->get_size().h)); } void convoi_frame_t::sort_list() { scrolly->sort(); sortedby.set_selection(sortby); } void convoi_frame_t::sort_list( uint32 filter, const slist_tpl *wares ) { waren_filter = wares; filter_flags = filter; fill_list(); } convoi_frame_t::convoi_frame_t() : gui_frame_t( translator::translate("cl_title"), welt->get_active_player()) { owner = welt->get_active_player(); set_table_layout(1,0); add_table(4,2); { new_component("Filter:"); name_filter_input.set_text(name_filter, lengthof(name_filter)); name_filter_input.set_notify_all_changes_delay(500); name_filter_input.add_listener(this); add_component(&name_filter_input); name_filter_input.add_listener(this); filter_details.init(button_t::roundbox, "cl_btn_filter_settings"); filter_details.add_listener(this); add_component(&filter_details); new_component(); new_component("cl_txt_sort"); sortedby.set_unsorted(); // do not sort for( size_t i=0; i < lengthof(sort_text); i++ ) { sortedby.new_component(translator::translate(sort_text[i]),SYSCOL_TEXT); } sortedby.set_selection(get_sortierung()); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_automatic, NULL); sorteddir.add_listener(this); sorteddir.pressed = get_reverse(); add_component(&sorteddir); new_component(); } end_table(); scrolly = new gui_scrolled_convoy_list_t(this); scrolly->set_maximize( true ); scrolly->set_checkered( true ); tabs.init_tabs(scrolly); for( uint32 i = 0; i < tabs.get_count(); i++ ) { if(current_wt == tabs.get_tab_waytype(i)) { tabs.set_active_tab_index(i); break; } } tabs.add_listener(this); add_component(&tabs); fill_list(); set_resizemode(diagonal_resize); reset_min_windowsize(); } convoi_frame_t::~convoi_frame_t() { destroy_win( magic_convoi_list_filter+owner->get_player_nr() ); } bool convoi_frame_t::infowin_event(const event_t *ev) { if(ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE) { destroy_win( magic_convoi_list_filter+owner->get_player_nr() ); } return gui_frame_t::infowin_event(ev); } /** * This method is called if an action is triggered */ bool convoi_frame_t::action_triggered( gui_action_creator_t *comp, value_t /* */ ) { if( comp == &name_filter_input ) { fill_list(); } else if( comp == &tabs ) { fill_list(); } else if( comp == &sortedby ) { set_sortierung( (sort_mode_t)((get_sortierung() + 1) % SORT_MODES) ); sort_list(); } else if( comp == &sorteddir ) { set_reverse( !get_reverse() ); sort_list(); } else if( comp == &filter_details ) { if( !destroy_win( magic_convoi_list_filter+owner->get_player_nr() ) ) { convoi_filter_frame_t *gui_cff = new convoi_filter_frame_t(owner, this); gui_cff->init(filter_flags, waren_filter); create_win( gui_cff, w_info, magic_convoi_list_filter+owner->get_player_nr() ); } } return true; } void convoi_frame_t::draw(scr_coord pos, scr_size size) { filter_details.pressed = win_get_magic( magic_convoi_list_filter+owner->get_player_nr() ); sorteddir.pressed = get_reverse(); if (last_world_convois != welt->convoys().get_count()) { // some deleted/ added => resort fill_list(); } gui_frame_t::draw(pos, size); } void convoi_frame_t::rdwr( loadsave_t *file ) { scr_size size = get_windowsize(); uint8 player_nr = owner->get_player_nr(); sint16 sort_mode = sortby; file->rdwr_byte( player_nr ); size.rdwr( file ); tabs.rdwr( file ); scrolly->rdwr( file ); file->rdwr_str( name_filter, lengthof( name_filter ) ); file->rdwr_short( sort_mode ); file->rdwr_bool( sortreverse ); file->rdwr_long( filter_flags ); if( file->is_saving() ) { uint8 good_nr = get_filter(convoi_filter_frame_t::ware_filter) ? waren_filter->get_count() : 0; file->rdwr_byte( good_nr ); if (good_nr > 0) { for(const goods_desc_t * const i : *waren_filter ) { char *name = const_cast(i->get_name()); file->rdwr_str(name,256); } } } else { uint8 good_nr; file->rdwr_byte( good_nr ); if( good_nr > 0 ) { static slist_tplwaren_filter_rd; for( sint16 i = 0; i < good_nr; i++ ) { char name[256]; file->rdwr_str(name, lengthof(name)); if (const goods_desc_t *gd = goods_manager_t::get_info(name)) { waren_filter_rd.append(gd); } } waren_filter = &waren_filter_rd; } sortby = (sort_mode_t)sort_mode; owner = welt->get_player( player_nr ); win_set_magic(this, magic_convoi_list+player_nr ); current_wt = tabs.get_active_tab_waytype(); fill_list(); set_windowsize( size ); } } simutrans-124.3/src/simutrans/gui/convoi_frame.h000066400000000000000000000054501474050137200217770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CONVOI_FRAME_H #define GUI_CONVOI_FRAME_H #include "gui_frame.h" #include "simwin.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_textinput.h" #include "components/gui_waytype_tab_panel.h" #include "../convoihandle.h" class player_t; class goods_desc_t; class gui_scrolled_convoy_list_t; /** * Displays a scrollable list of all convois of a player */ class convoi_frame_t : public gui_frame_t, private action_listener_t { public: enum sort_mode_t { nach_name = 0, nach_gewinn = 1, nach_typ = 2, nach_id = 3, SORT_MODES = 4 }; private: player_t *owner; static const char *sort_text[SORT_MODES]; /// number of convoys the last time we checked. uint32 last_world_convois; // these are part of the top UI gui_combobox_t sortedby; button_t sorteddir; button_t filter_details; static char name_filter[256], last_name_filter[256]; gui_textinput_t name_filter_input; // scroll container of list of convois gui_scrolled_convoy_list_t *scrolly; gui_waytype_tab_panel_t tabs; // actual filter setting static const slist_tpl*waren_filter; static uint32 filter_flags; static waytype_t current_wt; bool get_filter(uint32 filter) { return (filter_flags & filter) != 0; } void set_filter(uint32 filter, bool on) { filter_flags = on ? (filter_flags | filter) : (filter_flags & ~filter); } /// sort & filter convoys in list void sort_list(); /// refill the list of convoy info elements void fill_list(); /* * All filter settings are static, so they are not reset each * time the window closes. */ static sort_mode_t sortby; static bool sortreverse; public: static bool compare_convois(convoihandle_t, convoihandle_t); /** * Check all filters for one convoi. * returns true, if it is not filtered away. */ bool passes_filter(convoihandle_t cnv); /** * Resorts convois */ void sort_list( uint32 filter, const slist_tpl *wares ); convoi_frame_t(); ~convoi_frame_t(); /** * Events are notified to GUI components via this method */ bool infowin_event(const event_t *ev) OVERRIDE; void draw(scr_coord pos, scr_size size) OVERRIDE; const char * get_help_filename() const OVERRIDE {return "convoi.txt"; } static sort_mode_t get_sortierung() { return sortby; } static void set_sortierung(sort_mode_t sm) { sortby = sm; } static bool get_reverse() { return sortreverse; } static void set_reverse(bool reverse) { sortreverse = reverse; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_convoi_list; } }; #endif simutrans-124.3/src/simutrans/gui/convoi_info.cc000066400000000000000000000551241474050137200220010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "convoi_info.h" #include "minimap.h" #include "../vehicle/rail_vehicle.h" #include "../simcolor.h" #include "../display/viewport.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "simwin.h" #include "../dataobj/schedule.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" #include "../simconvoi.h" #include "../simline.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "depot_frame.h" #include "line_item.h" #include "convoi_detail.h" #include "line_management_gui.h" #define CHART_HEIGHT (100) static const char cost_type[convoi_t::MAX_CONVOI_COST][64] = { "Free Capacity", "Transported", "Revenue", "Operation", "Profit", "Distance", "Maxspeed", "Way toll" }; static const uint8 cost_type_color[convoi_t::MAX_CONVOI_COST] = { COL_FREE_CAPACITY, COL_TRANSPORTED, COL_REVENUE, COL_OPERATION, COL_PROFIT, COL_DISTANCE, COL_MAXSPEED, COL_TOLL }; static const bool cost_type_money[convoi_t::MAX_CONVOI_COST] = { false, false, true, true, true, false, false, true }; bool convoi_info_t::route_search_in_progress=false; /** * This variable defines by which column the table is sorted * Values: 0 = destination * 1 = via * 2 = via_amount * 3 = amount */ const char *convoi_info_t::sort_text[SORT_MODES] = { "Zielort", "via", "via Menge", "Menge" }; convoi_info_t::convoi_info_t(convoihandle_t cnv, bool edit_schedule) : gui_frame_t(""), text(&freight_info), view(scr_size(max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width() * 7) / 8))), scroll_freight(&container_freight, true, true) { is_saving_gui = false; if( cnv.is_bound() ) { init( cnv ); if( edit_schedule ) { change_schedule(); } } } void convoi_info_t::init(convoihandle_t cnv) { this->cnv = cnv; this->mean_convoi_speed = speed_to_kmh(cnv->get_akt_speed()*4); this->max_convoi_speed = speed_to_kmh(cnv->get_min_top_speed()*4); gui_frame_t::set_name(cnv->get_name()); gui_frame_t::set_owner(cnv->get_owner()); minimap_t::get_instance()->set_selected_cnv(cnv); set_table_layout(1,0); input.add_listener(this); reset_cnv_name(); input.set_notify_all_changes_delay(500); add_component(&input); // top part: speedbars, view, buttons add_table(2,0)->set_alignment(ALIGN_TOP); { container_top = add_table(1,0); { add_table(2,1); add_component(&speed_label); add_component(&speed_bar); end_table(); add_table(3,1); new_component("Gewinn"); profit_label.set_align(gui_label_t::left); add_component(&profit_label); add_component(&running_cost_label); end_table(); add_table(2,1); add_component(&weight_label); add_component(&filled_bar); end_table(); add_table(2,1); add_component(&target_label); add_component(&route_bar); end_table(); add_table(2,1); line_button2.init( button_t::arrowright, NULL ); line_button2.add_listener( this ); add_component( &line_button2 ); add_component( &line_label ); end_table(); } end_table(); add_component(&view); view.set_obj(cnv->front()); } end_table(); // tab panel: connections, chart panels, details add_component(&switch_mode); switch_mode.add_listener( this ); switch_mode.add_tab(&scroll_freight, translator::translate("Freight")); container_freight.set_table_layout(1,0); container_freight.add_table(2,1); { container_freight.new_component("loaded passenger/freight"); sort_button.init(button_t::roundbox, sort_text[env_t::default_sortmode]); sort_button.set_tooltip("Sort by"); sort_button.add_listener(this); container_freight.add_component(&sort_button); } container_freight.end_table(); container_freight.add_component(&text); switch_mode.add_tab(&container_schedule, translator::translate("Fahrplan")); // tooltip would be set_tooltip("Alters a schedule."); container_schedule.set_table_layout(1, 0); container_schedule.add_table( 3, 1 ); { container_schedule.new_component("Serves Line:"); line_selector.clear_elements(); container_schedule.add_component(&line_selector); line_selector.add_listener(this); line_button.init( button_t::roundbox, "Update Line" ); line_button.set_tooltip("Modify the selected line"); line_button.add_listener(this); container_schedule.add_component(&line_button); } container_schedule.end_table(); scd.init(cnv->get_schedule(), cnv->get_owner(), cnv, cnv->get_line() ); old_schedule_count = scd.get_schedule()->get_count()+1; init_line_selector(); container_schedule.add_component(&scd); scd.add_listener(this); switch_mode.add_tab(&container_stats, translator::translate("Chart")); container_stats.set_table_layout(1,0); chart.set_dimension(12, 10000); chart.set_background(SYSCOL_CHART_BACKGROUND); chart.set_min_size(scr_size(0, CHART_HEIGHT)); container_stats.add_component(&chart); container_stats.add_table(D_BUTTONS_PER_ROW,0)->set_force_equal_columns(true); for (int cost = 0; costget_finance_history(), convoi_t::MAX_CONVOI_COST, cost, MAX_MONTHS, cost_type_money[cost], false, true, cost_type_money[cost]*2 ); button_t *b = container_stats.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, cost_type[cost]); b->background_color = color_idx_to_rgb(cost_type_color[cost]); b->pressed = false; button_to_chart.append(b, &chart, curve); } container_stats.end_table(); cnv->set_sortby( env_t::default_sortmode ); // convoy details in tab switch_mode.add_tab(&container_details, translator::translate("Vehicle details")); container_details.set_table_layout(1,0); container_details.add_table(D_BUTTONS_PER_ROW, 0)->set_force_equal_columns(true); { no_load_button.init(button_t::roundbox | button_t::flexible, "no load"); no_load_button.set_tooltip("No goods are loaded onto this convoi."); no_load_button.add_listener(this); container_details.add_component(&no_load_button); withdraw_button.init(button_t::roundbox | button_t::flexible, "withdraw"); withdraw_button.set_tooltip("Convoi is sold when all wagons are empty."); withdraw_button.add_listener(this); container_details.add_component(&withdraw_button); go_home_button.init(button_t::roundbox | button_t::flexible, "go home"); go_home_button.set_tooltip("Sends the convoi to the last depot it departed from!"); go_home_button.add_listener(this); container_details.add_component(&go_home_button); sale_button.init(button_t::roundbox | button_t::flexible, "Verkauf"); sale_button.set_tooltip("Remove vehicle from map. Use with care!"); sale_button.add_listener(this); container_details.add_component(&sale_button); } container_details.end_table(); details = container_details.new_component(cnv); // indicator bars filled_bar.add_color_value(&cnv->get_loading_limit(), color_idx_to_rgb(COL_YELLOW)); filled_bar.add_color_value(&cnv->get_loading_level(), color_idx_to_rgb(COL_GREEN)); speed_bar.set_base(max_convoi_speed); speed_bar.set_vertical(false); speed_bar.add_color_value(&mean_convoi_speed, color_idx_to_rgb(COL_GREEN)); // we update this ourself! route_bar.init(&cnv_route_index, 0); if( cnv->get_vehicle_count()>0 && dynamic_cast(cnv->front()) ) { // only for trains etc. route_bar.set_reservation( &next_reservation_index ); } route_bar.set_height(9); update_labels(); reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(diagonal_resize); } // only handle a pending renaming ... convoi_info_t::~convoi_info_t() { button_to_chart.clear(); // rename if necessary rename_cnv(); } // apply new schedule void convoi_info_t::apply_schedule() { if( (!cnv.is_bound()) || (cnv->get_state()!=convoi_t::EDIT_SCHEDULE && cnv->get_state()!=convoi_t::INITIAL) ) { // no change allowed (one can only enter this state when editing was allowed) return; } // do not send changes if the convoi is about to be deleted if (cnv->get_state() != convoi_t::SELF_DESTRUCT) { if (cnv->in_depot()) { const grund_t* const ground = welt->lookup(cnv->get_home_depot()); if (ground) { const depot_t* const depot = ground->get_depot(); if (depot) { depot_frame_t* const frame = dynamic_cast(win_get_magic((ptrdiff_t)depot)); if (frame) { frame->update_data(); } } } } // update new line instead if (line != cnv->get_line()) { char id[16]; sprintf(id, "%i,%i", line.get_id(), cnv->get_schedule()->get_current_stop()); cnv->call_convoi_tool('l', id); } // since waiting times might be different from line cbuffer_t buf; scd.get_schedule()->sprintf_schedule(buf); cnv->call_convoi_tool('g', buf); } } void convoi_info_t::init_line_selector() { if (cnv.is_bound()) { line_selector.clear_elements(); int selection = 0; vector_tpl lines; cnv->get_owner()->simlinemgmt.get_lines(cnv->get_schedule()->get_type(), &lines); bool new_bound = false; for(linehandle_t other_line : lines) { if( scd.get_schedule()->matches( world(), other_line->get_schedule() ) ) { if( line != other_line ) { line = other_line; reset_min_windowsize(); scd.init( scd.get_schedule(), cnv->get_owner(), cnv, line ); } new_bound = true; break; } } if( !new_bound && line.is_bound() ) { // remove linehandle from schedule line = linehandle_t(); scd.init( scd.get_schedule(), cnv->get_owner(), cnv, line ); } int offset = 2; if (!line.is_bound()) { selection = 0; offset = 3; line_selector.new_component(translator::translate(""), SYSCOL_TEXT); line_selector.new_component(translator::translate(""), SYSCOL_TEXT); line_selector.new_component("--------------------------------", SYSCOL_TEXT); } for(linehandle_t other_line : lines) { line_selector.new_component(other_line); if (line == other_line) { selection = line_selector.count_elements() - 1; } } line_selector.set_selection(selection); line_scrollitem_t::sort_mode = line_scrollitem_t::SORT_BY_NAME; line_selector.sort(offset); old_line_count = cnv->get_owner()->simlinemgmt.get_line_count(); } } void convoi_info_t::update_labels() { switch (cnv->get_state()) { case convoi_t::DRIVING: route_bar.set_state(0); break; case convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH: case convoi_t::WAITING_FOR_CLEARANCE_TWO_MONTHS: case convoi_t::CAN_START_ONE_MONTH: case convoi_t::CAN_START_TWO_MONTHS: route_bar.set_state(2); break; case convoi_t::NO_ROUTE: route_bar.set_state(3); break; default: route_bar.set_state(1); break; } // use median speed to avoid flickering mean_convoi_speed += speed_to_kmh(cnv->get_akt_speed()*4); mean_convoi_speed /= 2; speed_label.buf().printf( translator::translate("%i km/h (max. %ikm/h)"), (mean_convoi_speed+3)/4, speed_to_kmh(cnv->get_min_top_speed()) ); speed_label.update(); profit_label.append_money(cnv->get_jahresgewinn()/100.0); profit_label.update(); running_cost_label.buf().append("("); running_cost_label.append_money(cnv->get_running_cost()/100.0); running_cost_label.buf().append("/km)"); running_cost_label.update(); weight_label.buf().append( translator::translate("Gewicht") ); weight_label.buf().append( ": " ); weight_label.buf().append( cnv->get_sum_gesamtweight()/1000.0, 1 ); weight_label.buf().append( "t (" ); weight_label.buf().append( (cnv->get_sum_gesamtweight()-cnv->get_sum_weight())/1000.0, 1 ); weight_label.buf().append( "t)" ); weight_label.update(); // next stop target_label.buf().append(translator::translate("Fahrtziel")); schedule_t::gimme_stop_name(target_label.buf(), welt, cnv->get_owner(), cnv->get_schedule()->get_current_entry(), 34); target_label.update(); // only show assigned line, if there is one! if( cnv->get_line().is_bound() ) { line_label.buf().append(cnv->get_line()->get_name()); line_label.set_color(cnv->get_line()->get_state_color()); } else { line_label.buf().clear(); } line_button2.set_visible( cnv->get_line().is_bound() ); line_label.update(); // buffer update now only when needed by convoi itself => dedicated buffer for this const int old_len=freight_info.len(); cnv->get_freight_info(freight_info); if( old_len!=freight_info.len() ) { text.recalc_size(); scroll_freight.set_size( scroll_freight.get_size() ); } // realign container - necessary if strings changed length container_top->set_size( container_top->get_size() ); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void convoi_info_t::draw(scr_coord pos, scr_size size) { if(!cnv.is_bound()) { destroy_win(this); return; } next_reservation_index = cnv->get_next_reservation_index(); bool is_change_allowed = cnv->get_owner() == welt->get_active_player() && !welt->get_active_player()->is_locked(); if( line_selector.get_selection()>1 && !line.is_bound() ) { init_line_selector(); } if( !scd.get_schedule()->empty() && line_selector.get_selection()==1 && !line.is_bound() ) { // catch new schedule if promoting to line init_line_selector(); if( !line.is_bound() ) { line_selector.set_selection(1); } reset_min_windowsize(); } else if( old_schedule_count != scd.get_schedule()->get_count() ) { // entry added or removed init_line_selector(); reset_min_windowsize(); old_schedule_count = scd.get_schedule()->get_count(); } else if( old_line_count != cnv->get_owner()->simlinemgmt.get_line_count() ) { // line added or removed init_line_selector(); reset_min_windowsize(); } line_button.enable( dynamic_cast(line_selector.get_selected_item()) ); line_button2.enable( line.is_bound() ); go_home_button.enable(!route_search_in_progress && is_change_allowed); if( grund_t* gr=welt->lookup(cnv->get_schedule()->get_current_entry().pos) ) { go_home_button.pressed = gr->get_depot() != NULL; } no_load_button.pressed = cnv->get_no_load(); no_load_button.enable(is_change_allowed); withdraw_button.enable(is_change_allowed); sale_button.enable(is_change_allowed); line_selector.enable( is_change_allowed ); withdraw_button.pressed = cnv->get_withdraw(); update_labels(); route_bar.set_base(cnv->get_route()->get_count()-1); cnv_route_index = cnv->front()->get_route_index() - 1; // all gui stuff set => display it gui_frame_t::draw(pos, size); } bool convoi_info_t::is_weltpos() { return (welt->get_viewport()->get_follow_convoi()==cnv); } koord3d convoi_info_t::get_weltpos( bool set ) { if( set ) { if( !is_weltpos() ) { welt->get_viewport()->set_follow_convoi( cnv ); } else { welt->get_viewport()->set_follow_convoi( convoihandle_t() ); } return koord3d::invalid; } else { return cnv.is_bound() ? cnv->get_pos() : koord3d::invalid; } } /** * This method is called if an action is triggered */ bool convoi_info_t::action_triggered( gui_action_creator_t *comp, value_t v) { minimap_t::get_instance()->set_selected_cnv(cnv); if( comp == &line_button ) { // open selected line as schedule if( line_scrollitem_t* li = dynamic_cast(line_selector.get_selected_item()) ) { if( li->get_line().is_bound() ) { cnv->get_owner()->simlinemgmt.show_lineinfo( cnv->get_owner(), li->get_line(), 0 ); } } } else if( comp == &line_button2 ) { // open selected line as schedule if( cnv->get_line().is_bound() ) { cnv->get_owner()->simlinemgmt.show_lineinfo( cnv->get_owner(), cnv->get_line(), -1 ); } } else if( comp == &input ) { // rename if necessary rename_cnv(); } // sort by what else if( comp == &sort_button ) { // sort by what env_t::default_sortmode = (sort_mode_t)((int)(cnv->get_sortby()+1)%(int)SORT_MODES); sort_button.set_text(sort_text[env_t::default_sortmode]); cnv->set_sortby( env_t::default_sortmode ); } bool edit_allowed = (cnv.is_bound() && (cnv->get_owner() == welt->get_active_player() || welt->get_active_player()->is_public_service())); if (comp == &switch_mode) { if (v.i == 1) { if(edit_allowed && !cnv->in_depot()) { // if not in depot: // set state to EDIT_SCHEDULE, calls cnv->schedule->start_editing(), reset in gui_schedule_t::~gui_schedule_t cnv->call_convoi_tool('s', "1"); scd.init(cnv->get_schedule(), cnv->get_owner(), cnv, cnv->get_line()); reset_min_windowsize(); } } else if(cnv->get_state()==convoi_t::EDIT_SCHEDULE || cnv->get_state()==convoi_t::INITIAL) { apply_schedule(); } scd.highlight_schedule(v.i == 1); } // some actions only allowed, when I am the player if(edit_allowed) { if( comp == &no_load_button && !route_search_in_progress ) { cnv->call_convoi_tool( 'n', NULL ); return true; } if( comp == &go_home_button && !route_search_in_progress ) { // limit update to certain states that are considered to be safe for schedule updates int state = cnv->get_state(); if(state==convoi_t::EDIT_SCHEDULE || cnv->get_state()==convoi_t::INITIAL) { return true; } grund_t* gr = welt->lookup(cnv->get_schedule()->get_current_entry().pos); const bool enable_gohome = gr && gr->get_depot() == NULL; if( enable_gohome ) { // go to depot route_search_in_progress = true; cnv->call_convoi_tool( 'd', NULL ); } else { // back to normal schedule schedule_t* schedule = cnv->get_schedule()->copy(); schedule->remove(); // remove depot entry cbuffer_t buf; schedule->sprintf_schedule( buf ); cnv->call_convoi_tool( 'g', buf ); delete schedule; } } // end go home button if (comp == &sale_button) { cnv->call_convoi_tool('x', NULL); return true; } else if (comp == &withdraw_button) { cnv->call_convoi_tool('w', NULL); return true; } else if (comp == &scd) { if( v.p == NULL ) { scd.init( cnv->get_schedule(), cnv->get_owner(), cnv, cnv->get_line() ); // revert schedule init_line_selector(); reset_min_windowsize(); } } else if (comp == &line_selector) { uint32 selection = v.i; if( line_scrollitem_t* li = dynamic_cast(line_selector.get_element(selection)) ) { line = li->get_line(); scd.init(line->get_schedule(), cnv->get_owner(), cnv, line); reset_min_windowsize(); } else if( v.i==1 ) { // create line schedule via tool! tool_t* tool = create_tool(TOOL_CHANGE_LINE | SIMPLE_TOOL); cbuffer_t buf; buf.printf("c,0,%i,%ld,", (int)scd.get_schedule()->get_type(), (long)(intptr_t)cnv->get_schedule()); scd.get_schedule()->sprintf_schedule(buf); tool->set_default_param(buf); welt->set_tool(tool, cnv->get_owner()); // since init always returns false, it is safe to delete immediately delete tool; } else { // remove line line = linehandle_t(); line_selector.set_selection(0); schedule_t *temp = scd.get_schedule()->copy(); scd.init(temp, cnv->get_owner(), cnv, line); reset_min_windowsize(); delete temp; } return true; } } return false; } void convoi_info_t::change_schedule() { if( switch_mode.get_aktives_tab() != &container_schedule ) { switch_mode.set_active_tab_index(1); scd.highlight_schedule( true ); value_t v( 1 ); action_triggered( &switch_mode, 1 ); } } void convoi_info_t::update_schedule() { cnv->check_pending_updates(); scd.init(cnv->get_schedule(), cnv->get_owner(), cnv, cnv->get_line(),true); change_schedule(); if (switch_mode.get_aktives_tab() == &container_schedule) { cnv->set_state(convoi_t::EDIT_SCHEDULE); scd.highlight_schedule(true); } } bool convoi_info_t::infowin_event(const event_t *ev) { if( ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE ) { if( switch_mode.get_aktives_tab() == &container_schedule && !is_saving_gui ) { // apply schedule here, to reset wait_lock for convoys in convoi_t::set_schedule apply_schedule(); } scd.highlight_schedule(false); minimap_t::get_instance()->set_selected_cnv(convoihandle_t()); } if( ev->ev_class == INFOWIN && ev->ev_code == WIN_TOP ) { if( switch_mode.get_aktives_tab() == &container_schedule && !cnv->in_depot() ) { cnv->call_convoi_tool( 's', "1" ); scd.highlight_schedule( true ); } minimap_t::get_instance()->set_selected_cnv(cnv); } is_saving_gui = false; return gui_frame_t::infowin_event(ev); } void convoi_info_t::reset_cnv_name() { // change text input of selected line if (cnv.is_bound()) { tstrncpy(old_cnv_name, cnv->get_name(), sizeof(old_cnv_name)); tstrncpy(cnv_name, cnv->get_name(), sizeof(cnv_name)); input.set_text(cnv_name, sizeof(cnv_name)); } } void convoi_info_t::rename_cnv() { if (cnv.is_bound()) { const char *t = input.get_text(); // only change if old name and current name are the same // otherwise some unintended undo if renaming would occur if( t && t[0] && strcmp(t, cnv->get_name()) && strcmp(old_cnv_name, cnv->get_name())==0) { // text changed => call tool cbuffer_t buf; buf.printf( "c%u,%s", cnv.get_id(), t ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param(buf); welt->set_tool(tool, cnv->get_owner()); // since init always returns false, it is safe to delete immediately delete tool; // do not trigger this command again tstrncpy(old_cnv_name, t, sizeof(old_cnv_name)); } } } void convoi_info_t::rdwr(loadsave_t *file) { is_saving_gui = true; // so we do not apply the schedule on window closing // handle convoi_t::rdwr_convoihandle_t(file, cnv); file->rdwr_byte( env_t::default_sortmode ); // window size scr_size size = get_windowsize(); size.rdwr( file ); // init window if( file->is_loading() && cnv.is_bound()) { init(cnv); win_set_magic(this, magic_convoi_info + cnv.get_id()); } // after initialization // components scroll_freight.rdwr(file); switch_mode.rdwr(file); // schedule stuff simline_t::rdwr_linehandle_t(file, line); scd.rdwr(file); // button-to-chart array button_to_chart.rdwr(file); // convoi details details->rdwr(file); // convoy vanished if( !cnv.is_bound() ) { dbg->error( "convoi_info_t::rdwr()", "Could not restore convoi info window of (%d)", cnv.get_id() ); destroy_win( this ); return; } if( file->is_loading() ) { reset_min_windowsize(); set_windowsize(size); if (switch_mode.get_aktives_tab() == &container_schedule) { cnv->set_state(convoi_t::EDIT_SCHEDULE); scd.highlight_schedule(true); } } } simutrans-124.3/src/simutrans/gui/convoi_info.h000066400000000000000000000072201474050137200216350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CONVOI_INFO_H #define GUI_CONVOI_INFO_H #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_button_to_chart.h" #include "components/gui_chart.h" #include "components/gui_combobox.h" #include "components/gui_label.h" #include "components/gui_obj_view.h" #include "components/gui_schedule.h" #include "components/gui_scrollpane.h" #include "components/gui_speedbar.h" #include "components/gui_tab_panel.h" #include "components/gui_textarea.h" #include "components/gui_textinput.h" #include "../convoihandle.h" #include "simwin.h" #include "../utils/cbuffer.h" class convoi_detail_t; /** * Displays an information window for a convoi */ class convoi_info_t : public gui_frame_t, private action_listener_t { public: enum sort_mode_t { by_destination = 0, by_via = 1, by_amount_via = 2, by_amount = 3, SORT_MODES = 4 }; private: /** * Buffer for freight info text string. */ cbuffer_t freight_info; gui_textarea_t text; obj_view_t view; gui_label_buf_t speed_label, profit_label, running_cost_label, weight_label, target_label, line_label; gui_textinput_t input; gui_speedbar_t filled_bar; gui_speedbar_t speed_bar; gui_routebar_t route_bar; sint32 next_reservation_index; gui_chart_t chart; gui_tab_panel_t switch_mode; gui_aligned_container_t container_freight, container_schedule, container_stats, *container_top, container_details; convoi_detail_t *details; gui_scrollpane_t scroll_freight; button_t sort_button; button_t line_button, line_button2; bool line_bound; // schedule handling button_t go_home_button; button_t no_load_button; button_t sale_button; button_t withdraw_button; gui_combobox_t line_selector; // to add new lines automatically uint32 old_line_count; uint8 old_schedule_count; linehandle_t line; gui_schedule_t scd; convoihandle_t cnv; sint32 mean_convoi_speed; sint32 max_convoi_speed; // current pointer to route ... sint32 cnv_route_index; char cnv_name[256],old_cnv_name[256]; void update_labels(); // resets textinput to current convoi name // necessary after convoi was renamed void reset_cnv_name(); // rename selected convoi // checks if possible / necessary void rename_cnv(); static bool route_search_in_progress; static const char *sort_text[SORT_MODES]; void show_hide_statistics( bool show ); gui_button_to_chart_array_t button_to_chart; void init(convoihandle_t cnv); void apply_schedule(); bool is_saving_gui; public: convoi_info_t(convoihandle_t cnv = convoihandle_t(), bool change_schedule = false); virtual ~convoi_info_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "convoiinfo.txt"; } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool is_weltpos() OVERRIDE; koord3d get_weltpos( bool set ) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; /** * called when convoi was renamed */ void update_data() { reset_cnv_name(); set_dirty(); } void init_line_selector(); bool infowin_event( const event_t *ev ) OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_convoi_info+cnv.get_id(); } void route_search_finished() { route_search_in_progress = false; } void change_schedule(); void update_schedule(); }; #endif simutrans-124.3/src/simutrans/gui/convoy_item.cc000066400000000000000000000015201474050137200220130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "convoy_item.h" #include "../simconvoi.h" #include "../tool/simmenu.h" #include "../world/simworld.h" #include "../utils/cbuffer.h" const char* convoy_scrollitem_t::get_text() const { return cnv->get_name(); } PIXVAL convoy_scrollitem_t::get_color() const { return cnv->get_status_color(); } void convoy_scrollitem_t::set_text(char const* const t) { if( t && t[0] && strcmp( t, cnv->get_name() ) ) { // text changed => call tool cbuffer_t buf; buf.printf("c%u,%s", cnv.get_id(), t ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); world()->set_tool( tool, cnv->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } } simutrans-124.3/src/simutrans/gui/convoy_item.h000066400000000000000000000015701474050137200216620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CONVOY_ITEM_H #define GUI_CONVOY_ITEM_H #include "components/gui_scrolled_list.h" #include "../convoihandle.h" /** * Container for list entries - consisting of text and color */ class convoy_scrollitem_t : public gui_scrolled_list_t::const_text_scrollitem_t { private: convoihandle_t cnv; public: convoy_scrollitem_t( convoihandle_t c ) : gui_scrolled_list_t::const_text_scrollitem_t( NULL, color_idx_to_rgb(COL_ORANGE) ) { cnv = c; } PIXVAL get_color() const OVERRIDE; convoihandle_t get_convoy() const { return cnv; } char const* get_text() const OVERRIDE; void set_text(char const*) OVERRIDE; bool is_editable() const OVERRIDE { return true; } bool is_valid() const OVERRIDE { return cnv.is_bound(); } // can be used to indicate invalid entries }; #endif simutrans-124.3/src/simutrans/gui/curiosity_edit.cc000066400000000000000000000271731474050137200225330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "../tool/simtool.h" #include "../builder/hausbauer.h" #include "../descriptor/ground_desc.h" #include "../descriptor/intro_dates.h" #include "../dataobj/translator.h" #include "../utils/cbuffer.h" #include "curiosity_edit.h" #include "components/gui_label.h" // new tool definition tool_build_house_t curiosity_edit_frame_t::haus_tool=tool_build_house_t(); cbuffer_t curiosity_edit_frame_t::param_str; bool curiosity_edit_frame_t::sortreverse = false; static bool compare_building_desc(const building_desc_t* a, const building_desc_t* b) { int diff = strcmp( a->get_name(), b->get_name() ); return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_name(const building_desc_t* a, const building_desc_t* b) { int diff = strcmp( translator::translate(a->get_name()), translator::translate(b->get_name()) ); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_level_pax(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_level() - b->get_level(); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_level_mail(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_mail_level() - b->get_mail_level(); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_date_intro(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_intro_year_month() - b->get_intro_year_month(); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_date_retire(const building_desc_t* a, const building_desc_t* b) { int diff = a->get_retire_year_month() - b->get_retire_year_month(); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_building_desc_size(const building_desc_t* a, const building_desc_t* b) { koord a_koord = a->get_size(); koord b_koord = b->get_size(); int diff = a_koord.x * a_koord.y - b_koord.x * b_koord.y; if( diff==0 ) { //same area - sort by side to seperate different shapes diff = a_koord.x - b_koord.x; } if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return curiosity_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } curiosity_edit_frame_t::curiosity_edit_frame_t(player_t* player_) : extend_edit_gui_t(translator::translate("curiosity builder"), player_), building_list(16) { desc = NULL; haus_tool.set_default_param(NULL); haus_tool.cursor = tool_t::general_tool[TOOL_BUILD_HOUSE]->cursor; bt_city_attraction.init( button_t::square_state, "City attraction"); bt_city_attraction.add_listener(this); bt_city_attraction.pressed = true; cont_filter.add_component(&bt_city_attraction,3); bt_land_attraction.init( button_t::square_state, "Land attraction"); bt_land_attraction.add_listener(this); bt_land_attraction.pressed = true; cont_filter.add_component(&bt_land_attraction,3); bt_monuments.init( button_t::square_state, "Monument"); bt_monuments.add_listener(this); cont_filter.add_component(&bt_monuments,3); // add to sorting selection cb_sortedby.new_component(gui_sorting_item_t::BY_LEVEL_PAX); cb_sortedby.new_component(gui_sorting_item_t::BY_LEVEL_MAIL); cb_sortedby.new_component(gui_sorting_item_t::BY_DATE_INTRO); cb_sortedby.new_component(gui_sorting_item_t::BY_DATE_RETIRE); cb_sortedby.new_component(gui_sorting_item_t::BY_SIZE); // rotation gui_aligned_container_t *tbl = cont_options.add_table(2,0); tbl->new_component("Rotation"); tbl->add_component(&cb_rotation); cb_rotation.add_listener(this); cb_rotation.new_component(gui_rotation_item_t::random); cont_options.end_table(); fill_list(); reset_min_windowsize(); } // put item in list according to filter/sorter void curiosity_edit_frame_t::put_item_in_list( const building_desc_t* desc ) { const bool allow_obsolete = bt_obsolete.pressed; const bool use_timeline = bt_timeline.pressed | bt_timeline_custom.pressed; const sint32 month_now = bt_timeline.pressed ? welt->get_current_month() : bt_timeline_custom.pressed ? ni_timeline_year.get_value()*12 + ni_timeline_month.get_value()-1 : 0; const uint8 chosen_climate = get_climate(); const uint8 sortedby = get_sortedby(); sortreverse = sort_order.pressed; if( (!use_timeline || (!desc->is_future(month_now) && (!desc->is_retired(month_now) || allow_obsolete)) ) && ( desc->get_allowed_climate_bits() & chosen_climate) ) { // timeline allows for this, and so does climates setting switch(sortedby) { case gui_sorting_item_t::BY_NAME_TRANSLATED: building_list.insert_ordered( desc, compare_building_desc_name ); break; case gui_sorting_item_t::BY_LEVEL_PAX: building_list.insert_ordered( desc, compare_building_desc_level_pax ); break; case gui_sorting_item_t::BY_LEVEL_MAIL: building_list.insert_ordered( desc, compare_building_desc_level_mail ); break; case gui_sorting_item_t::BY_DATE_INTRO: building_list.insert_ordered( desc, compare_building_desc_date_intro ); break; case gui_sorting_item_t::BY_DATE_RETIRE: building_list.insert_ordered( desc, compare_building_desc_date_retire ); break; case gui_sorting_item_t::BY_SIZE: building_list.insert_ordered( desc, compare_building_desc_size ); break; default: building_list.insert_ordered( desc, compare_building_desc ); } } } // fill the current building_list void curiosity_edit_frame_t::fill_list() { building_list.clear(); if(bt_city_attraction.pressed) { for(building_desc_t const* const desc : *hausbauer_t::get_list(building_desc_t::attraction_city)) { put_item_in_list(desc); } } if(bt_land_attraction.pressed) { for(building_desc_t const* const desc : *hausbauer_t::get_list(building_desc_t::attraction_land)) { put_item_in_list(desc); } } if(bt_monuments.pressed) { for(building_desc_t const* const desc : *hausbauer_t::get_list(building_desc_t::monument)) { put_item_in_list(desc); } } // now build scrolled list scl.clear_elements(); scl.set_selection(-1); for(building_desc_t const* const i : building_list) { // color code for objects: BLACK: normal, YELLOW: consumer only, GREEN: source only PIXVAL color; switch (i->get_type()) { case building_desc_t::attraction_city: color = color_idx_to_rgb(COL_DARK_BLUE+env_t::gui_player_color_dark); break; case building_desc_t::attraction_land: color = color_idx_to_rgb(40 + env_t::gui_player_color_dark); break; default: color = SYSCOL_TEXT; break; } char const* const name = get_sortedby()==gui_sorting_item_t::BY_NAME_OBJECT ? i->get_name() : translator::translate(i->get_name()); scl.new_component(name, color); if (i == desc) { scl.set_selection(scl.get_count()-1); } } // always update current selection (since the tool may depend on it) change_item_info( scl.get_selection() ); } bool curiosity_edit_frame_t::action_triggered( gui_action_creator_t *comp,value_t e) { // only one chain can be shown if( comp==&bt_city_attraction ) { bt_city_attraction.pressed ^= 1; fill_list(); } else if( comp==&bt_land_attraction ) { bt_land_attraction.pressed ^= 1; fill_list(); } else if( comp==&bt_monuments ) { bt_monuments.pressed ^= 1; fill_list(); } else if( comp == &cb_rotation) { change_item_info( scl.get_selection() ); } return extend_edit_gui_t::action_triggered(comp,e); } void curiosity_edit_frame_t::change_item_info(sint32 entry) { if(entry>=0 && entry<(sint32)building_list.get_count()) { const building_desc_t *new_desc = building_list[entry]; if(new_desc!=desc) { buf.clear(); desc = new_desc; if(desc->get_type()==building_desc_t::attraction_city) { buf.printf("%s (%s: %i)",translator::translate( "City attraction" ), translator::translate("Bauzeit"),desc->get_extra()); } else if(desc->get_type()==building_desc_t::attraction_land) { buf.append( translator::translate( "Land attraction" ) ); } else if(desc->get_type()==building_desc_t::monument) { buf.append( translator::translate( "Monument" ) ); } buf.append("\n\n"); buf.append( translator::translate( desc->get_name() ) ); buf.trim(); buf.append("\n\n"); // climates buf.append( translator::translate("allowed climates:\n") ); uint16 cl = desc->get_allowed_climate_bits(); if(cl==0) { buf.append( translator::translate("none") ); buf.append("\n"); } else { for(uint16 i=0; i<=arctic_climate; i++ ) { if(cl & (1<get_level()); if(desc->get_type()==building_desc_t::attraction_land) { // same with passengers buf.printf("%s: %i\n",translator::translate("Postrate"),desc->get_level()); } else { buf.printf("%s: %i\n",translator::translate("Postrate"),desc->get_mail_level()); } buf.printf("%s%u", translator::translate("\nBauzeit von"), desc->get_intro_year_month() / 12); if(desc->get_retire_year_month()!=DEFAULT_RETIRE_DATE*12) { buf.printf("%s%u", translator::translate("\nBauzeit bis"), desc->get_retire_year_month() / 12); } buf.append("\n"); if (char const* const maker = desc->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); buf.append("\n"); } // reset combobox cb_rotation.clear_elements(); cb_rotation.new_component(gui_rotation_item_t::random); for(uint8 i = 0; iget_all_layouts(); i++) { cb_rotation.new_component(i); } // orientation (255=random) if(desc->get_all_layouts()>1) { cb_rotation.set_selection(0); } else { cb_rotation.set_selection(1); } } uint8 rotation = get_rotation(); uint8 rot = (rotation==255) ? 0 : rotation; building_image.init(desc, rot); // the tools will be always updated, even though the data up there might be still current param_str.clear(); param_str.printf("%i%c%s", bt_climates.pressed, rotation==255 ? '#' : '0'+rotation, desc->get_name() ); haus_tool.set_default_param(param_str); welt->set_tool( &haus_tool, player ); } else { desc = NULL; if(welt->get_tool(player->get_player_nr())==&haus_tool) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); } building_image.init(NULL, 0); cb_rotation.clear_elements(); cb_rotation.new_component(gui_rotation_item_t::random); buf.clear(); } reset_min_windowsize(); } void curiosity_edit_frame_t::draw(scr_coord pos, scr_size size) { // remove constructed monuments from list if(desc && desc->get_type()==building_desc_t::monument && !hausbauer_t::is_valid_monument(desc) ) { change_item_info(0x7FFFFFFF); scl.set_selection(-1); fill_list(); } extend_edit_gui_t::draw(pos,size); } simutrans-124.3/src/simutrans/gui/curiosity_edit.h000066400000000000000000000026451474050137200223720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CURIOSITY_EDIT_H #define GUI_CURIOSITY_EDIT_H #include "extend_edit.h" class tool_build_house_t; class building_desc_t; /* * Curiosity (attractions) builder dialog */ class curiosity_edit_frame_t : public extend_edit_gui_t { private: static tool_build_house_t haus_tool; static cbuffer_t param_str; const building_desc_t *desc; vector_tplbuilding_list; button_t bt_city_attraction; button_t bt_land_attraction; button_t bt_monuments; void fill_list() OVERRIDE; void put_item_in_list(const building_desc_t* desc ); void change_item_info( sint32 i ) OVERRIDE; public: curiosity_edit_frame_t(player_t* player); static bool sortreverse; /** * in top-level windows the name is displayed in titlebar * @return the non-translated component name */ const char* get_name() const { return "curiosity builder"; } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char* get_help_filename() const OVERRIDE { return "curiosity_build.txt"; } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/curiositylist_frame.cc000066400000000000000000000127051474050137200235670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "curiositylist_frame.h" #include "curiositylist_stats.h" #include "components/gui_label.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../simcolor.h" #include "../world/simworld.h" #include "../player/simplay.h" #include "../obj/gebaeude.h" #include "../descriptor/building_desc.h" #include "../utils/unicode.h" char curiositylist_frame_t::name_filter[256]; const char* sort_text[curiositylist::SORT_MODES] = { "hl_btn_sort_name", "Passagierrate" }; class playername_const_scroll_item_t : public gui_scrolled_list_t::const_text_scrollitem_t { public: const uint8 player_nr; playername_const_scroll_item_t( player_t *pl ) : gui_scrolled_list_t::const_text_scrollitem_t( pl->get_name(), color_idx_to_rgb(pl->get_player_color1()+env_t::gui_player_color_dark) ), player_nr(pl->get_player_nr()) { } }; curiositylist_frame_t::curiositylist_frame_t() : gui_frame_t( translator::translate("curlist_title") ), scrolly(gui_scrolled_list_t::windowskin, curiositylist_stats_t::compare) { attraction_count = 0; scrolly.set_checkered(true); scrolly.set_maximize(true); set_table_layout(3,0); new_component("Filter:"); name_filter_input.set_text(name_filter, lengthof(name_filter)); name_filter_input.set_notify_all_changes_delay(0); name_filter_input.add_listener(this); add_component(&name_filter_input); new_component(); filter_by_owner.init(button_t::square_automatic, "Served by"); filter_by_owner.add_listener(this); filter_by_owner.set_tooltip("At least one tile is connected to one stop."); add_component(&filter_by_owner); filterowner.new_component(translator::translate("No player"), SYSCOL_TEXT); for (int i = 0; i < MAX_PLAYER_COUNT; i++) { if (player_t* pl = welt->get_player(i)) { filterowner.new_component(pl); if (pl == welt->get_active_player()) { filterowner.set_selection(filterowner.count_elements() - 1); } } } filterowner.add_listener(this); add_component(&filterowner); new_component(); new_component("hl_txt_sort"); sortedby.set_unsorted(); // do not sort for (size_t i = 0; i < lengthof(sort_text); i++) { sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); } sortedby.set_selection(curiositylist_stats_t::sortby); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_state, NULL); sorteddir.add_listener(this); sorteddir.pressed = curiositylist_stats_t::sortby; add_component(&sorteddir); add_component(&scrolly,3); fill_list(); set_resizemode(diagonal_resize); scrolly.set_maximize(true); reset_min_windowsize(); } void curiositylist_frame_t::fill_list() { scrolly.clear_elements(); const weighted_vector_tpl& world_attractions = welt->get_attractions(); attraction_count = world_attractions.get_count(); player_t* pl = (filter_by_owner.pressed && filterowner.get_selection() >= 0) ? welt->get_player(((const playername_const_scroll_item_t*)(filterowner.get_selected_item()))->player_nr) : NULL; if (filter_by_owner.pressed && filterowner.get_selection() == 0) { for(gebaeude_t* const geb : world_attractions) { if (geb != NULL && geb->get_first_tile() == geb && geb->get_passagier_level() != 0) { bool add = (name_filter[0] == 0 || utf8caseutf8(translator::translate(geb->get_tile()->get_desc()->get_name()), name_filter)); for (int i = 0; add && i < MAX_PLAYER_COUNT; i++) { if (player_t* pl = welt->get_player(i)) { if (geb->is_within_players_network(pl)) { // already connected add = false; } } } if (add) { scrolly.new_component(geb); } } } } else { for(gebaeude_t* const geb : world_attractions) { if (geb != NULL && geb->get_first_tile() == geb && geb->get_passagier_level() != 0) { if( pl == NULL || geb->is_within_players_network( pl ) ) { curiositylist_stats_t* cs = new curiositylist_stats_t(geb); if( name_filter[0] == 0 || utf8caseutf8(cs->get_text(), name_filter) ) { scrolly.take_component(cs); } else { delete cs; } } } } } scrolly.sort(0); scrolly.set_size(scr_size(get_windowsize().w, scrolly.get_size().h)); } bool curiositylist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) { if(comp == &sortedby) { curiositylist_stats_t::sortby = (curiositylist::sort_mode_t)v.i; scrolly.sort(0); } else if(comp == &sorteddir) { curiositylist_stats_t::sortreverse = !curiositylist_stats_t::sortreverse; sorteddir.pressed = curiositylist_stats_t::sortreverse; scrolly.sort(0); } else if (comp == &name_filter_input) { fill_list(); } else if (comp == &filterowner) { if( filter_by_owner.pressed ) { fill_list(); } } else if( comp == &filter_by_owner ) { fill_list(); } return true; } void curiositylist_frame_t::rdwr(loadsave_t* file) { scr_size size = get_windowsize(); sint16 sort_mode = curiositylist_stats_t::sortby; size.rdwr(file); scrolly.rdwr(file); file->rdwr_str(name_filter, lengthof(name_filter)); file->rdwr_short(sort_mode); file->rdwr_bool(curiositylist_stats_t::sortreverse); if (file->is_loading()) { curiositylist_stats_t::sortby = (curiositylist::sort_mode_t)sort_mode; fill_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/curiositylist_frame.h000066400000000000000000000021521474050137200234240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CURIOSITYLIST_FRAME_H #define GUI_CURIOSITYLIST_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_scrolled_list.h" #include "components/gui_button.h" #include "components/gui_combobox.h" /** * Curiosity list window */ class curiositylist_frame_t : public gui_frame_t, private action_listener_t { private: gui_combobox_t sortedby; button_t sorteddir; gui_scrolled_list_t scrolly; gui_aligned_container_t list; button_t filter_by_owner; gui_combobox_t filterowner; uint32 attraction_count; static char name_filter[256]; gui_textinput_t name_filter_input; public: curiositylist_frame_t(); void fill_list(); const char *get_help_filename() const OVERRIDE {return "curiositylist_filter.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE { fill_list(); } void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_curiositylist; } }; #endif simutrans-124.3/src/simutrans/gui/curiositylist_stats.cc000066400000000000000000000115531474050137200236330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "curiositylist_stats.h" #include "components/gui_image.h" #include "../simtypes.h" #include "../simcolor.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../simhalt.h" #include "../simskin.h" #include "../obj/gebaeude.h" #include "../descriptor/building_desc.h" #include "../descriptor/skin_desc.h" #include "../dataobj/translator.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" curiositylist::sort_mode_t curiositylist_stats_t::sortby = curiositylist::by_name; bool curiositylist_stats_t::sortreverse = false; static karte_ptr_t welt; bool curiositylist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb ) { const curiositylist_stats_t* ca = dynamic_cast(aa); const curiositylist_stats_t* cb = dynamic_cast(bb); const gebaeude_t* a = ca->attraction; const gebaeude_t* b = cb->attraction; int cmp = 0; switch (sortby) { default: NOT_REACHED case curiositylist::by_paxlevel: if (a->get_passagier_level() != b->get_passagier_level()) { cmp = a->get_passagier_level() - b->get_passagier_level(); break; } // fall-through case curiositylist::by_name: { const char* a_name = translator::translate(a->get_tile()->get_desc()->get_name()); const char* b_name = translator::translate(b->get_tile()->get_desc()->get_name()); cmp = STRICMP(a_name, b_name); break; } } return sortreverse ? cmp > 0 : cmp < 0; } curiositylist_stats_t::curiositylist_stats_t(gebaeude_t *att) { attraction = att; // pos button set_table_layout(4,1); button_t *b = new_component(); b->set_typ(button_t::posbutton_automatic); b->set_targetpos3d(attraction->get_pos()); // indicator bar add_component(&indicator); indicator.set_max_size(scr_size(D_INDICATOR_WIDTH,D_INDICATOR_HEIGHT)); // city attraction images if (attraction->get_tile()->get_desc()->get_extra() != 0) { new_component(skinverwaltung_t::intown->get_image_id(0), 0, ALIGN_NONE, true); } else { new_component(); } // name gui_label_buf_t *l = new_component(); l->buf().printf("%s (%d)", get_text(), attraction->get_passagier_level()); l->update(); } const char* curiositylist_stats_t::get_text() const { const unsigned char *name = (const unsigned char *)ltrim( translator::translate(attraction->get_tile()->get_desc()->get_name()) ); static char short_name[256]; char* dst = short_name; int cr = 0; for( int j=0; name[j]>0 && j<255 && cr<10; j++ ) { if(name[j]<=' ') { cr++; if( name[j]<32 ) { break; } if (dst != short_name && dst[-1] != ' ') { *dst++ = ' '; } } else { *dst++ = name[j]; } } *dst = '\0'; // now we have a short name ... return short_name; } bool curiositylist_stats_t::is_valid() const { return world()->get_attractions().is_contained(attraction); } /** * Events are notified to GUI components via this method */ bool curiositylist_stats_t::infowin_event(const event_t * ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if (!swallowed) { // either open dialog or goto (with control or right click) if (IS_LEFTRELEASE(ev)) { if ((event_get_last_control_shift() ^ tool_t::control_invert) == 2) { world()->get_viewport()->change_world_position(attraction->get_pos()); } else { attraction->show_info(); } return true; } if (IS_RIGHTRELEASE(ev)) { world()->get_viewport()->change_world_position(attraction->get_pos()); return true; } } return swallowed; } /** * Draw the component */ void curiositylist_stats_t::draw(scr_coord offset) { // is connected? => decide on indicatorfarbe (indicator color) PIXVAL indicatorfarbe; bool mail=false; bool pax=false; bool all_crowded=true; bool some_crowded=false; const planquadrat_t *plan = welt->access(attraction->get_pos().get_2d()); const halthandle_t *halt_list = plan->get_haltlist(); for( unsigned h=0; (mail&pax)==0 && hget_haltlist_count(); h++ ) { halthandle_t halt = halt_list[h]; if (halt->get_pax_enabled()) { pax = true; if (halt->get_pax_unhappy() > 40) { some_crowded |= true; } else { all_crowded = false; } } if (halt->get_mail_enabled()) { mail = true; if (halt->get_pax_unhappy() > 40) { some_crowded |= true; } else { all_crowded = false; } } } // now decide on color if(some_crowded) { indicatorfarbe = color_idx_to_rgb(all_crowded ? COL_RED : COL_ORANGE); } else if(pax) { indicatorfarbe = color_idx_to_rgb(mail ? COL_TURQUOISE : COL_DARK_GREEN); } else { indicatorfarbe = color_idx_to_rgb(mail ? COL_BLUE : COL_YELLOW); } indicator.set_color(indicatorfarbe); gui_aligned_container_t::draw(offset); } simutrans-124.3/src/simutrans/gui/curiositylist_stats.h000066400000000000000000000020221474050137200234640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_CURIOSITYLIST_STATS_H #define GUI_CURIOSITYLIST_STATS_H #include "components/gui_aligned_container.h" #include "components/gui_colorbox.h" #include "components/gui_scrolled_list.h" class gebaeude_t; namespace curiositylist { enum sort_mode_t { by_name=0, by_paxlevel, // by_maillevel, SORT_MODES }; }; /** * Where curiosity (attractions) stats are calculated for list dialog */ class curiositylist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: gebaeude_t* attraction; gui_colorbox_t indicator; public: static curiositylist::sort_mode_t sortby; static bool sortreverse; static bool compare(const gui_component_t *a, const gui_component_t *b ); curiositylist_stats_t(gebaeude_t *att); char const* get_text() const OVERRIDE; bool is_valid() const OVERRIDE; bool infowin_event(event_t const*) OVERRIDE; void draw(scr_coord offset) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/depot_frame.cc000066400000000000000000001533351474050137200217610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * The depot window, where to buy convois */ #include #include #include #include "../simunits.h" #include "../simintr.h" #include "../world/simworld.h" #include "../vehicle/vehicle.h" #include "../simconvoi.h" #include "../obj/depot.h" #include "simwin.h" // #include "../simcolor.h" #include "../simdebug.h" #include "../display/viewport.h" #include "../simline.h" #include "../simlinemgmt.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "../tpl/slist_tpl.h" #include "line_management_gui.h" #include "line_item.h" #include "convoy_item.h" #include "messagebox.h" #include "depot_frame.h" #include "schedule_list.h" #include "components/gui_divider.h" #include "../descriptor/goods_desc.h" #include "../descriptor/intro_dates.h" #include "../builder/vehikelbauer.h" #include "../dataobj/schedule.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "../builder/goods_manager.h" #include "../obj/way/weg.h" #include "../utils/unicode.h" char depot_frame_t::name_filter_value[64] = ""; class depot_convoi_capacity_t : public gui_aligned_container_t { private: gui_label_buf_t labels[3]; gui_image_t images[3]; uint32 total_pax; uint32 total_mail; uint32 total_goods; public: depot_convoi_capacity_t() { set_table_layout(6, 1); set_spacing(scr_size(D_H_SPACE, 0)); total_pax = 0; total_mail = 0; total_goods = 0; images[0].set_image(skinverwaltung_t::passengers->get_image_id(0), true); images[1].set_image(skinverwaltung_t::mail->get_image_id(0), true); images[2].set_image(skinverwaltung_t::goods->get_image_id(0), true); for(int i=0; i<3; i++) { add_component(&labels[i]); add_component(&images[i]); } } void set_totals(uint32 pax, uint32 mail, uint32 goods) { total_pax = pax; total_mail = mail; total_goods = goods; update(); } void update() { labels[0].buf().printf("%s %d", translator::translate("Capacity:"), total_pax); labels[1].buf().printf("%d", total_mail); labels[2].buf().printf("%d", total_goods); for(int i=0; i<3; i++) { labels[i].update(); } } }; class gui_aligned_container_zero_width_t : public gui_aligned_container_t { public: scr_size get_min_size() const OVERRIDE { return scr_size(0, gui_aligned_container_t::get_min_size().h); } }; // Labels with dynamic buffers, index into labels[] enum { // convoi properties LB_CNV_COUNT, LB_CNV_COST, LB_CNV_VALUE, LB_CNV_POWER, LB_CNV_WEIGHT, LB_CNV_SPEED, // vehicle properties LB_VEH_NAME, LB_VEH_COST, LB_VEH_WEIGHT, LB_VEH_CAPACITY, LB_VEH_DATE, LB_VEH_SPEED, LB_VEH_AUTHOR, LB_VEH_POWER, LB_VEH_VALUE, LB_VEH_LOADINGTIME, LB_MAX, LB_CNV_ALL = LB_VEH_NAME }; static int sort_by_action; bool depot_frame_t::show_retired_vehicles = false; bool depot_frame_t::show_all = true; depot_frame_t::depot_frame_t(depot_t* depot) : gui_frame_t("", NULL), depot(depot), icnv(-1), convoi(&convoi_pics), scrolly_convoi(&cont_convoi, true, false), pas(&pas_vec), electrics(&electrics_vec), loks(&loks_vec), waggons(&waggons_vec), scrolly_pas(&pas), scrolly_electrics(&electrics), scrolly_loks(&loks), scrolly_waggons(&waggons), line_selector(line_scrollitem_t::compare) { old_vehicle_count = 0; if (depot) { old_vehicle_count = depot->get_vehicle_list().get_count() + 1; old_veh_type = NULL; init(depot); } } void depot_frame_t::init(depot_t *dep) { depot = dep; set_name(translator::translate(depot->get_name())); set_owner(depot->get_owner()); icnv = depot->convoi_count()-1; veh_action = va_append; last_selected_line = depot->get_last_selected_line(); no_schedule_text = translator::translate(""); clear_schedule_text = translator::translate(""); unique_schedule_text = translator::translate(""); new_line_text = translator::translate(""); line_seperator = translator::translate("--------------------------------"); new_convoy_text = translator::translate("new convoi"); promote_to_line_text = translator::translate(""); // allocate labels for(int i=0; iget_image_id(0), true); img_bolt.set_rigid(true); // second row // goto line button line_button.set_typ(button_t::posbutton); line_button.set_targetpos3d(koord3d::invalid); line_button.add_listener(this); add_component(&line_button); new_component("Serves Line:", SYSCOL_TEXT, gui_label_t::left); /* * [SELECT ROUTE]: */ line_selector.add_listener(this); line_selector.set_wrapping(false); add_component(&line_selector); new_component(); end_table(); /* * [CONVOI] */ cont_convoi.set_table_layout(1,0); cont_convoi.set_margin(scr_size(0,0), scr_size(0,0)); cont_convoi.set_spacing(scr_size(0,0)); cont_convoi.add_component(&convoi); convoi.set_max_rows(1); sb_convoi_length.set_base( depot->get_max_convoi_length() * CARUNITS_PER_TILE / 2 - 1); convoi_length_ok_sb = 0; convoi_length_slower_sb = 0; convoi_length_too_slow_sb = 0; convoi_tile_length_sb = 0; new_vehicle_length_sb = 0; if( depot->get_max_convoi_length() > 1 ) { // no convoy length bar for ships or aircraft sb_convoi_length.add_color_value(&convoi_tile_length_sb, color_idx_to_rgb(COL_BROWN)); sb_convoi_length.add_color_value(&new_vehicle_length_sb, color_idx_to_rgb(COL_DARK_GREEN)); sb_convoi_length.add_color_value(&convoi_length_ok_sb, color_idx_to_rgb(COL_GREEN)); sb_convoi_length.add_color_value(&convoi_length_slower_sb, color_idx_to_rgb(COL_ORANGE)); sb_convoi_length.add_color_value(&convoi_length_too_slow_sb, color_idx_to_rgb(COL_RED)); cont_convoi.add_component(&sb_convoi_length); } add_component(&scrolly_convoi); { gui_aligned_container_t* t = add_table(2, 4); t->set_force_equal_columns(true); t->set_spacing(scr_size(D_H_SPACE, 0)); add_component(labels[LB_CNV_COUNT]); cont_convoi_capacity = new_component(); add_component(labels[LB_CNV_COST]); add_component(labels[LB_CNV_VALUE]); add_component(labels[LB_CNV_POWER]); add_component(labels[LB_CNV_WEIGHT]); add_component(labels[LB_CNV_SPEED], 2); end_table(); } /* * [ACTIONS] */ add_table(4,0)->set_force_equal_columns(true); bt_start.init(button_t::roundbox | button_t::flexible, "Start"); bt_start.add_listener(this); bt_start.set_tooltip("Start the selected vehicle(s)"); add_component(&bt_start); bt_schedule.init(button_t::roundbox | button_t::flexible, "Fahrplan"); bt_schedule.add_listener(this); bt_schedule.set_tooltip("Give the selected vehicle(s) an individual schedule"); // translated to "Edit the selected vehicle(s) individual schedule or assigned line" add_component(&bt_schedule); bt_copy_convoi.init(button_t::roundbox | button_t::flexible, "Copy Convoi"); bt_copy_convoi.add_listener(this); bt_copy_convoi.set_tooltip("Copy the selected convoi and its schedule or line"); add_component(&bt_copy_convoi); bt_sell.init(button_t::roundbox | button_t::flexible, "verkaufen"); bt_sell.add_listener(this); bt_sell.set_tooltip("Sell the selected vehicle(s)"); add_component(&bt_sell); end_table(); /* * [PANEL] */ add_component(&tabs); /* * [BOTTOM] */ new_component(); cont_veh_action = add_table(4,0); { // put columns 1-3 in extra container to force correct button width in 4th column gui_aligned_container_t *cont_3cols = new_component_span(3,0,3); cont_3cols->add_component(&lb_convoi_count); cont_3cols->new_component(); cont_3cols->new_component("Fahrzeuge:", SYSCOL_TEXT, gui_label_t::right); } bt_veh_action.set_typ(button_t::roundbox | button_t::flexible); bt_veh_action.add_listener(this); bt_veh_action.set_tooltip("Choose operation executed on clicking stored/new vehicles"); add_component(&bt_veh_action); { // put columns 1-4 in extra container to force correct button width in last column gui_aligned_container_t *cont_4cols = new_component_span(4,0,3); bt_obsolete.init(button_t::square_state, "Show obsolete"); bt_obsolete.pressed = show_retired_vehicles; if( welt->get_settings().get_allow_buying_obsolete_vehicles() ) { bt_obsolete.add_listener(this); bt_obsolete.set_tooltip("Show also vehicles no longer in production."); cont_4cols->add_component(&bt_obsolete); } else { cont_4cols->new_component(); } cont_4cols->new_component("Filter:", SYSCOL_TEXT, gui_label_t::right); vehicle_filter.add_listener(this); cont_4cols->add_component(&vehicle_filter); cont_4cols->new_component("Search:", SYSCOL_TEXT, gui_label_t::right); } name_filter_input.set_text(name_filter_value, 60); add_component(&name_filter_input); name_filter_input.add_listener(this); { // put columns 1-3 in extra container to force correct button width in 4th column gui_aligned_container_t *cont_3cols = new_component_span(3,0,3); bt_show_all.init(button_t::square_state, "Show all"); bt_show_all.add_listener(this); bt_show_all.set_tooltip("Show also vehicles that do not match for current action."); bt_show_all.pressed = show_all; cont_3cols->add_component(&bt_show_all); cont_3cols->new_component(); cont_3cols->new_component("Sort by:", SYSCOL_TEXT, gui_label_t::right); } sort_by.add_listener(this); add_component(&sort_by); end_table(); new_component(); /* * [VEHICLE] */ // special container with min-width == zero // (prevents mouse-over-events to spoil the layout and force a large min-width) cont_vehicle_labels = new gui_aligned_container_zero_width_t(); cont_vehicle_labels->set_table_layout(2,0); cont_vehicle_labels->set_force_equal_columns(true); cont_vehicle_labels->set_spacing(scr_size(D_H_SPACE, 0)); cont_vehicle_labels->add_component(labels[LB_VEH_NAME],2); cont_vehicle_labels->add_component(labels[LB_VEH_COST]); cont_vehicle_labels->add_component(labels[LB_VEH_WEIGHT]); cont_vehicle_labels->add_component(labels[LB_VEH_CAPACITY]); cont_vehicle_labels->add_component(labels[LB_VEH_LOADINGTIME]); cont_vehicle_labels->add_component(labels[LB_VEH_SPEED]); cont_vehicle_labels->add_component(labels[LB_VEH_DATE]); cont_vehicle_labels->add_component(labels[LB_VEH_POWER]); cont_vehicle_labels->add_component(labels[LB_VEH_VALUE]); cont_vehicle_labels->add_component(labels[LB_VEH_AUTHOR]); add_component(cont_vehicle_labels); /* * [END OF WINDOW] */ // initialize image lists, scrollies, speedbar { /* * These parameter are adjusted to resolution. * - Some extra space looks nicer. */ scr_coord placement; scr_coord grid; grid.x = depot->get_x_grid() * get_base_tile_raster_width() / 64 + 4; grid.y = depot->get_y_grid() * get_base_tile_raster_width() / 64 + 6; placement.x = depot->get_x_placement() * get_base_tile_raster_width() / 64 + 2; placement.y = depot->get_y_placement() * get_base_tile_raster_width() / 64 + 2; scr_coord_val grid_dx = depot->get_x_grid() * get_base_tile_raster_width() / 64 / 2; scr_coord_val placement_dx = depot->get_x_grid() * get_base_tile_raster_width() / 64 / 4; sb_convoi_length.set_width(depot->get_max_convoi_length() * (grid.x - grid_dx)); gui_image_list_t* ilists[] = {&convoi, &pas, &electrics, &loks, &waggons}; for(uint32 i = 0; iset_grid(scr_coord(grid.x - grid_dx, grid.y)); il->set_placement(scr_coord(placement.x - placement_dx, placement.y)); il->set_player_nr(depot->get_owner_nr()); il->add_listener(this); // only convoi list gets overlapping images grid_dx = 0; placement_dx = 0; } gui_scrollpane_t* scrollies[] = {&scrolly_convoi, &scrolly_pas, &scrolly_electrics, &scrolly_loks, &scrolly_waggons}; for(uint32 i = 0; iset_scrollbar_mode( scrollbar_t::show_disabled ); scrolly->set_size_corner(false); } } // update all the elements build_vehicle_lists(); update_data(); reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode( diagonal_resize ); depot->clear_command_pending(); } // free memory: all the image_data_t depot_frame_t::~depot_frame_t() { clear_ptr_vector(pas_vec); clear_ptr_vector(electrics_vec); clear_ptr_vector(loks_vec); clear_ptr_vector(waggons_vec); } // returns position of depot on the map koord3d depot_frame_t::get_weltpos(bool) { return depot->get_pos(); } bool depot_frame_t::is_weltpos() { return ( welt->get_viewport()->is_on_center( get_weltpos(false) ) ); } void depot_frame_t::set_windowsize( scr_size size ) { // set width of image-lists gui_image_list_t* ilists[] = {&pas, &electrics, &loks, &waggons}; for(uint32 i = 0; iset_max_width(size.w); } sb_convoi_length.set_size(scr_size(size.w - D_MARGINS_X, D_INDICATOR_HEIGHT)); gui_frame_t::set_windowsize(size); } void depot_frame_t::activate_convoi( convoihandle_t c ) { icnv = -1; // deselect for( uint i = 0; i < depot->convoi_count(); i++ ) { if( c == depot->get_convoi(i) ) { icnv = i; break; } } build_vehicle_lists(); } // true if already stored here bool depot_frame_t::is_in_vehicle_list(const vehicle_desc_t *info) { for(vehicle_t* const v : depot->get_vehicle_list()) { if( v->get_desc() == info ) { return true; } } return false; } // add a single vehicle (helper function) void depot_frame_t::add_to_vehicle_list(const vehicle_desc_t *info) { // Check if vehicle should be filtered const goods_desc_t *freight = info->get_freight_type(); // Only filter when required and never filter engines if (depot->selected_filter > 0 && info->get_capacity() > 0) { if (depot->selected_filter == VEHICLE_FILTER_RELEVANT) { if(freight->get_catg_index() >= 3) { bool found = false; for(goods_desc_t const* const i : welt->get_goods_list()) { if (freight->get_catg_index() == i->get_catg_index()) { found = true; break; } } // If no current goods can be transported by this vehicle, don't display it if (!found) return; } } else if (depot->selected_filter > VEHICLE_FILTER_RELEVANT) { // Filter on specific selected good uint32 goods_index = depot->selected_filter - VEHICLE_FILTER_GOODS_OFFSET; if (goods_index < welt->get_goods_list().get_count()) { const goods_desc_t *selected_good = welt->get_goods_list()[goods_index]; if (freight->get_catg_index() != selected_good->get_catg_index()) { return; // This vehicle can't transport the selected good } } } } gui_image_list_t::image_data_t* img_data = new gui_image_list_t::image_data_t(info->get_name(), info->get_base_image()); if( info->get_engine_type() == vehicle_desc_t::electric && (info->get_freight_type()==goods_manager_t::passengers || info->get_freight_type()==goods_manager_t::mail) ) { electrics_vec.append(img_data); } // since they come "pre-sorted" from the vehikelbauer, we have to do nothing to keep them sorted else if(info->get_freight_type() == goods_manager_t::passengers || info->get_freight_type() == goods_manager_t::mail) { pas_vec.append(img_data); } else if(info->get_power() > 0 || info->get_capacity()==0) { loks_vec.append(img_data); } else { waggons_vec.append(img_data); } // add reference to map vehicle_map.set(info, img_data); } // add all current vehicles void depot_frame_t::build_vehicle_lists() { if (depot->get_vehicle_type().empty()) { // there are tracks etc. but no vehicles => do nothing // at least initialize some data update_data(); update_tabs(); return; } const int month_now = welt->get_timeline_year_month(); // free vectors clear_ptr_vector(pas_vec); clear_ptr_vector(electrics_vec); clear_ptr_vector(loks_vec); clear_ptr_vector(waggons_vec); // clear map vehicle_map.clear(); // we do not allow to built electric vehicle in a depot without electrification const waytype_t wt = depot->get_waytype(); const weg_t *w = welt->lookup(depot->get_pos())->get_weg(wt!=tram_wt ? wt : track_wt); const bool weg_electrified = w ? w->is_electrified() : false; img_bolt.set_visible(weg_electrified); sort_by_action = depot->selected_sort_by; vector_tpl typ_list; if(!show_all && veh_action==va_sell) { // show only sellable vehicles for(vehicle_t* const v : depot->get_vehicle_list()) { vehicle_desc_t const* const d = v->get_desc(); typ_list.append(d); } } else { slist_tpl const& tmp_list = depot->get_vehicle_type(sort_by_action); for(slist_tpl::const_iterator itr = tmp_list.begin(); itr != tmp_list.end(); ++itr) { typ_list.append(*itr); } } // use this to show only sellable vehicles if(!show_all && veh_action==va_sell) { // just list the one to sell for(vehicle_desc_t const* const info : typ_list) { if (vehicle_map.get(info)) continue; add_to_vehicle_list(info); } } else { // list only matching ones for(vehicle_desc_t const* const info : typ_list) { const vehicle_desc_t *veh = NULL; convoihandle_t cnv = depot->get_convoi(icnv); if(cnv.is_bound() && cnv->get_vehicle_count()>0) { veh = (veh_action == va_insert ? cnv->front() : cnv->back())->get_desc(); } // current vehicle if( is_in_vehicle_list(info) || ((weg_electrified || info->get_engine_type()!=vehicle_desc_t::electric) && ((!info->is_future(month_now)) && (show_retired_vehicles || (!info->is_retired(month_now)) ) ) )) { // check, if allowed bool append = true; if(!show_all) { if(veh_action == va_insert) { append = info->can_lead(veh) && (veh==NULL || veh->can_follow(info)); } else if(veh_action == va_append) { append = info->can_follow(veh) && (veh==NULL || veh->can_lead(info)); } } if(append) { // name filter. Try to check both object name and translation name (case sensitive though!) if( name_filter_value[0]==0 || (utf8caseutf8(info->get_name(), name_filter_value) || utf8caseutf8(translator::translate(info->get_name()), name_filter_value)) ) { add_to_vehicle_list( info ); } } } } } DBG_DEBUG("depot_frame_t::build_vehicle_lists()","finally %i passenger vehicle, %i engines, %i good wagons",pas_vec.get_count(),loks_vec.get_count(),waggons_vec.get_count()); update_data(); update_tabs(); } static void get_line_list(const depot_t* depot, vector_tpl* lines) { depot->get_owner()->simlinemgmt.get_lines(depot->get_line_type(), lines); } void depot_frame_t::update_data() { static const char *txt_veh_action[3] = { "anhaengen", "voranstellen", "verkaufen" }; // change green into blue for retired vehicles const int month_now = welt->get_timeline_year_month(); bt_veh_action.set_text(txt_veh_action[veh_action]); cbuffer_t &txt_convois = lb_convois.buf(); switch( depot->convoi_count() ) { case 0: { txt_convois.append( translator::translate("no convois") ); break; } case 1: { if( icnv == -1 ) { txt_convois.append( translator::translate("1 convoi") ); } else { txt_convois.printf( translator::translate("convoi %d of %d"), icnv + 1, depot->convoi_count() ); } break; } default: { if( icnv == -1 ) { txt_convois.printf( translator::translate("%d convois"), depot->convoi_count() ); } else { txt_convois.printf( translator::translate("convoi %d of %d"), icnv + 1, depot->convoi_count() ); } break; } } lb_convois.update(); /* * Reset counts and check for valid vehicles */ convoihandle_t cnv = depot->get_convoi( icnv ); // update convoy selector convoy_selector.clear_elements(); convoy_selector.new_component( new_convoy_text, SYSCOL_TEXT ) ; convoy_selector.set_selection(0); // check all matching convoys for(convoihandle_t const c : depot->get_convoy_list()) { convoy_selector.new_component(c) ; if( cnv.is_bound() && c == cnv ) { convoy_selector.set_selection( convoy_selector.count_elements() - 1 ); } } const vehicle_desc_t *veh = NULL; scr_size old_convoi_size = convoi.get_min_size(); clear_ptr_vector( convoi_pics ); if( cnv.is_bound() && cnv->get_vehicle_count() > 0 ) { for( unsigned i=0; i < cnv->get_vehicle_count(); i++ ) { // just make sure, there is this vehicle also here! const vehicle_desc_t *info=cnv->get_vehicle(i)->get_desc(); if( vehicle_map.get( info ) == NULL ) { add_to_vehicle_list( info ); } gui_image_list_t::image_data_t* img_data = new gui_image_list_t::image_data_t(info->get_name(), info->get_base_image()); convoi_pics.append(img_data); } /* color bars for current convoi: */ convoi_pics[0]->lcolor = color_idx_to_rgb(cnv->front()->get_desc()->can_follow(NULL) ? COL_GREEN : COL_YELLOW); { unsigned i; for( i = 1; i < cnv->get_vehicle_count(); i++ ) { convoi_pics[i - 1]->rcolor = color_idx_to_rgb(cnv->get_vehicle(i-1)->get_desc()->can_lead(cnv->get_vehicle(i)->get_desc()) ? COL_GREEN : COL_RED); convoi_pics[i]->lcolor = color_idx_to_rgb(cnv->get_vehicle(i)->get_desc()->can_follow(cnv->get_vehicle(i-1)->get_desc()) ? COL_GREEN : COL_RED); } convoi_pics[i - 1]->rcolor = color_idx_to_rgb(cnv->get_vehicle(i-1)->get_desc()->can_lead(NULL) ? COL_GREEN : COL_YELLOW); } // change green into blue for vehicles that are not available for( unsigned i = 0; i < cnv->get_vehicle_count(); i++ ) { if( !cnv->get_vehicle(i)->get_desc()->is_available(month_now) ) { if( convoi_pics[i]->lcolor == color_idx_to_rgb(COL_GREEN) ) { convoi_pics[i]->lcolor = gui_theme_t::gui_color_obsolete; } if( convoi_pics[i]->rcolor == color_idx_to_rgb(COL_GREEN) ) { convoi_pics[i]->rcolor = gui_theme_t::gui_color_obsolete; } } } veh = (veh_action == va_insert ? cnv->front() : cnv->back())->get_desc(); } for(auto const& i : vehicle_map) { vehicle_desc_t const* const info = i.key; gui_image_list_t::image_data_t& img = *i.value; const PIXVAL ok_color = info->is_available(month_now) ? color_idx_to_rgb(COL_GREEN) : gui_theme_t::gui_color_obsolete; img.count = 0; img.lcolor = ok_color; img.rcolor = ok_color; /* * color bars for current convoi: * green/green okay to append/insert * red/red cannot be appended/inserted * green/yellow append okay, cannot be end of train * yellow/green insert okay, cannot be start of train */ if(veh_action == va_insert) { if(!info->can_lead(veh) || (veh && !veh->can_follow(info))) { img.lcolor = color_idx_to_rgb(COL_RED); img.rcolor = color_idx_to_rgb(COL_RED); } else if(!info->can_follow(NULL)) { img.lcolor = color_idx_to_rgb(COL_YELLOW); } } else if(veh_action == va_append) { if(!info->can_follow(veh) || (veh && !veh->can_lead(info))) { img.lcolor = color_idx_to_rgb(COL_RED); img.rcolor = color_idx_to_rgb(COL_RED); } else if(!info->can_lead(NULL)) { img.rcolor = color_idx_to_rgb(COL_YELLOW); } } else if( veh_action == va_sell ) { img.lcolor = color_idx_to_rgb(COL_RED); img.rcolor = color_idx_to_rgb(COL_RED); } } for(vehicle_t* const v : depot->get_vehicle_list()) { // can fail, if currently not visible if (gui_image_list_t::image_data_t* const imgdat = vehicle_map.get(v->get_desc())) { imgdat->count++; if(veh_action == va_sell) { imgdat->lcolor = color_idx_to_rgb(COL_GREEN); imgdat->rcolor = color_idx_to_rgb(COL_GREEN); } } } // update the line selector line_selector.clear_elements(); if( !last_selected_line.is_bound() ) { // new line may have a valid line now last_selected_line = selected_line; // if still nothing, resort to line management dialoge if( !last_selected_line.is_bound() ) { // try last specific line last_selected_line = schedule_list_gui_t::selected_line[ depot->get_owner_nr() ][ depot->get_line_type() ]; } if( !last_selected_line.is_bound() ) { // try last general line last_selected_line = schedule_list_gui_t::selected_line[ depot->get_owner_nr() ][ 0 ]; if( last_selected_line.is_bound() && last_selected_line->get_linetype() != depot->get_line_type() ) { last_selected_line = linehandle_t(); } } } if( cnv.is_bound() && cnv->get_schedule() && !cnv->get_schedule()->empty() ) { if( cnv->get_line().is_bound() ) { line_selector.new_component( clear_schedule_text, SYSCOL_TEXT ) ; line_selector.new_component( new_line_text, SYSCOL_TEXT ) ; } else { line_selector.new_component( unique_schedule_text, SYSCOL_TEXT ) ; line_selector.new_component( promote_to_line_text, SYSCOL_TEXT ) ; } } else { line_selector.new_component( no_schedule_text, SYSCOL_TEXT ) ; line_selector.new_component( new_line_text, SYSCOL_TEXT ) ; } if( last_selected_line.is_bound() ) { line_selector.new_component( last_selected_line ) ; } line_selector.new_component( line_seperator, SYSCOL_TEXT ) ; // check all matching lines if( cnv.is_bound() ) { selected_line = cnv->get_line(); } vector_tpl lines; get_line_list(depot, &lines); // select "create new schedule" line_selector.set_selection( 0 ); for(linehandle_t const line : lines ) { line_selector.new_component(line) ; if( selected_line.is_bound() && selected_line == line ) { line_selector.set_selection( line_selector.count_elements() - 1 ); } } if( line_selector.get_selection() == 0 ) { // no line selected selected_line = linehandle_t(); } line_selector.sort( last_selected_line.is_bound()+3 ); // Update vehicle filter vehicle_filter.clear_elements(); vehicle_filter.new_component(translator::translate("All"), SYSCOL_TEXT); vehicle_filter.new_component(translator::translate("Relevant"), SYSCOL_TEXT); for(goods_desc_t const* const i : welt->get_goods_list()) { vehicle_filter.new_component(translator::translate(i->get_name()), SYSCOL_TEXT); } if( depot->selected_filter > (sint32)vehicle_filter.count_elements() ) { depot->selected_filter = VEHICLE_FILTER_RELEVANT; } vehicle_filter.set_selection(depot->selected_filter); vehicle_filter.set_size(vehicle_filter.get_size()); sort_by.clear_elements(); for(int i = 0; i < vehicle_builder_t::sb_length; i++) { sort_by.new_component(translator::translate(vehicle_builder_t::vehicle_sort_by[i]), SYSCOL_TEXT); } sort_by.set_size(sort_by.get_size()); if( depot->selected_sort_by > (sint32)sort_by.count_elements() ) { depot->selected_sort_by = vehicle_builder_t::sb_name; } sort_by.set_selection(depot->selected_sort_by); // finally: update text uint32 total_pax = 0; uint32 total_mail = 0; uint32 total_goods = 0; uint64 total_power = 0; uint32 total_empty_weight = 0; uint32 total_selected_weight = 0; uint32 total_max_weight = 0; uint32 total_min_weight = 0; bool use_sel_weight = true; if( cnv.is_bound() && cnv->get_vehicle_count() > 0 ) { { uint8 selected_good_index = 0; if( depot->selected_filter > VEHICLE_FILTER_RELEVANT ) { // Filter is set to specific good const uint32 goods_index = depot->selected_filter - VEHICLE_FILTER_GOODS_OFFSET; if( goods_index < welt->get_goods_list().get_count() ) { selected_good_index = welt->get_goods_list()[goods_index]->get_index(); } } for( unsigned i = 0; i < cnv->get_vehicle_count(); i++ ) { const vehicle_desc_t *desc = cnv->get_vehicle(i)->get_desc(); total_power += desc->get_power()*desc->get_gear(); uint32 sel_weight = 0; // actual weight using vehicle filter selected good to fill uint32 max_weight = 0; uint32 min_weight = 100000; bool sel_found = false; for( uint32 j=0; jget_freight_type()->get_catg_index() == ware->get_catg_index() ) { max_weight = max(max_weight, (uint32)ware->get_weight_per_unit()); min_weight = min(min_weight, (uint32)ware->get_weight_per_unit()); // find number of goods in in this category. TODO: gotta be a better way... uint8 catg_count = 0; for(goods_desc_t const* const i : welt->get_goods_list()) { if( ware->get_catg_index() == i->get_catg_index() ) { catg_count++; } } if( ware->get_index() == selected_good_index || catg_count < 2 ) { sel_found = true; sel_weight = ware->get_weight_per_unit(); } } } if( !sel_found ) { // vehicle carries more than one good, but not the selected one use_sel_weight = false; } total_empty_weight += desc->get_weight(); total_selected_weight += desc->get_weight() + sel_weight * desc->get_capacity(); total_max_weight += desc->get_weight() + max_weight * desc->get_capacity(); total_min_weight += desc->get_weight() + min_weight * desc->get_capacity(); const goods_desc_t* const ware = desc->get_freight_type(); switch( ware->get_catg_index() ) { case goods_manager_t::INDEX_PAS: { total_pax += desc->get_capacity(); break; } case goods_manager_t::INDEX_MAIL: { total_mail += desc->get_capacity(); break; } default: { total_goods += desc->get_capacity(); break; } } } sint32 empty_kmh, sel_kmh, max_kmh, min_kmh; if( cnv->front()->get_waytype() == air_wt ) { // flying aircraft have 0 friction --> speed not limited by power, so just use top_speed empty_kmh = sel_kmh = max_kmh = min_kmh = speed_to_kmh( cnv->get_min_top_speed() ); } else { empty_kmh = speed_to_kmh(convoi_t::calc_max_speed(total_power, total_empty_weight, cnv->get_min_top_speed())); sel_kmh = speed_to_kmh(convoi_t::calc_max_speed(total_power, total_selected_weight, cnv->get_min_top_speed())); max_kmh = speed_to_kmh(convoi_t::calc_max_speed(total_power, total_min_weight, cnv->get_min_top_speed())); min_kmh = speed_to_kmh(convoi_t::calc_max_speed(total_power, total_max_weight, cnv->get_min_top_speed())); } const sint32 convoi_length = (cnv->get_vehicle_count()) * CARUNITS_PER_TILE / 2 - 1; convoi_tile_length_sb = convoi_length + (cnv->get_tile_length() * CARUNITS_PER_TILE - cnv->get_length()); cbuffer_t& txt_convoi_count = labels[LB_CNV_COUNT]->buf(); if( cnv->get_vehicle_count()>1 ) { txt_convoi_count.printf( translator::translate("%i car(s),"), cnv->get_vehicle_count() ); } txt_convoi_count.append( translator::translate("Station tiles:") ); txt_convoi_count.append( (double)cnv->get_tile_length(), 0 ); cbuffer_t& txt_convoi_speed = labels[LB_CNV_SPEED]->buf(); if( empty_kmh > 3 && empty_kmh != (use_sel_weight ? sel_kmh : min_kmh) ) { convoi_length_ok_sb = 0; if( max_kmh != min_kmh && !use_sel_weight ) { txt_convoi_speed.printf("%s %d km/h, %d-%d km/h %s", translator::translate("Max. speed:"), empty_kmh, min_kmh, max_kmh, translator::translate("loaded") ); if( max_kmh != empty_kmh ) { // lightest good in category slows convoi => too_slow convoi_length_slower_sb = 0; convoi_length_too_slow_sb = convoi_length; } else { // heaviest good in category slows convoi, but not lightest => slower convoi_length_slower_sb = convoi_length; convoi_length_too_slow_sb = 0; } } else { // all goods possible have same weight slowing convoi => too_slow txt_convoi_speed.printf("%s %d km/h, %d km/h %s", translator::translate("Max. speed:"), empty_kmh, use_sel_weight ? sel_kmh : min_kmh, translator::translate("loaded") ); convoi_length_slower_sb = 0; convoi_length_too_slow_sb = convoi_length; } } else { txt_convoi_speed.printf("%s %d km/h", translator::translate("Max. speed:"), empty_kmh ); convoi_length_slower_sb = 0; if( empty_kmh > 3) { // convoi is same acceptable speed loaded or empty => ok convoi_length_ok_sb = convoi_length; convoi_length_too_slow_sb = 0; } else { // convoi way too slow => too_slow convoi_length_ok_sb = 0; convoi_length_too_slow_sb = convoi_length; } } { char buf[128]; cbuffer_t& txt_convoi_value = labels[LB_CNV_VALUE]->buf(); money_to_string( buf, cnv->calc_restwert() / 100.0, false ); txt_convoi_value.printf("%s %8s", translator::translate("Restwert:"), buf ); cbuffer_t& txt_convoi_cost = labels[LB_CNV_COST]->buf(); if( sint64 fix_cost = cnv->get_fixed_cost() ) { money_to_string( buf, (double)cnv->get_purchase_cost() / 100.0, false ); txt_convoi_cost.printf( translator::translate("Cost: %8s (%.2f$/km %.2f$/m)\n"), buf, (double)cnv->get_running_cost()/100.0, (double)fix_cost/100.0 ); } else { money_to_string( buf, cnv->get_purchase_cost() / 100.0, false ); txt_convoi_cost.printf( translator::translate("Cost: %8s (%.2f$/km)\n"), buf, (double)cnv->get_running_cost() / 100.0 ); } } cbuffer_t& txt_convoi_power = labels[LB_CNV_POWER]->buf(); txt_convoi_power.printf( translator::translate("Power: %4d kW\n"), cnv->get_sum_power() ); cbuffer_t& txt_convoi_weight = labels[LB_CNV_WEIGHT]->buf(); if( total_empty_weight != (use_sel_weight ? total_selected_weight : total_max_weight) ) { if( total_min_weight != total_max_weight && !use_sel_weight ) { txt_convoi_weight.printf("%s %.1ft, %.1f-%.1ft", translator::translate("Weight:"), total_empty_weight / 1000.0, total_min_weight / 1000.0, total_max_weight / 1000.0 ); } else { txt_convoi_weight.printf("%s %.1ft, %.1ft", translator::translate("Weight:"), total_empty_weight / 1000.0, (use_sel_weight ? total_selected_weight : total_max_weight) / 1000.0 ); } } else { txt_convoi_weight.printf("%s %.1ft", translator::translate("Weight:"), total_empty_weight / 1000.0 ); } sb_convoi_length.set_visible(true); cont_convoi_capacity->set_totals( total_pax, total_mail, total_goods ); cont_convoi_capacity->set_visible(true); } } else { sb_convoi_length.set_visible(false); cont_convoi_capacity->set_visible(false); for(uint32 i=0; ibuf(); } labels[LB_CNV_COUNT]->buf().append(translator::translate("Keine Einzelfahrzeuge im Depot")); } for(uint32 i=0; iupdate(); } // update window if convoi container size changed if (old_convoi_size.w != convoi.get_min_size().w) { resize(scr_size(0,0)); } } sint64 depot_frame_t::calc_restwert(const vehicle_desc_t *veh_type) { sint64 wert = 0; for(vehicle_t* const v : depot->get_vehicle_list()) { if( v->get_desc() == veh_type ) { wert += v->calc_sale_value(); } } return wert; } void depot_frame_t::image_from_storage_list(gui_image_list_t::image_data_t *image_data) { if( image_data->lcolor != color_idx_to_rgb(COL_RED) && image_data->rcolor != color_idx_to_rgb(COL_RED) ) { if( veh_action == va_sell ) { depot->call_depot_tool('s', convoihandle_t(), image_data->text ); } else { convoihandle_t cnv = depot->get_convoi( icnv ); if( !cnv.is_bound() && !depot->get_owner()->is_locked() ) { // adding new convoi, block depot actions until command executed // otherwise in multiplayer it's likely multiple convois get created // rather than one new convoi with multiple vehicles depot->set_command_pending(); } depot->call_depot_tool( veh_action == va_insert ? 'i' : 'a', cnv, image_data->text ); } } } void depot_frame_t::image_from_convoi_list(uint nr, bool to_end) { const convoihandle_t cnv = depot->get_convoi( icnv ); if( cnv.is_bound() && nr < cnv->get_vehicle_count() ) { // we remove all connected vehicles together! // find start unsigned start_nr = nr; while( start_nr > 0 ) { start_nr--; const vehicle_desc_t *info = cnv->get_vehicle(start_nr)->get_desc(); if( info->get_trailer_count() != 1 ) { start_nr++; break; } } cbuffer_t start; start.printf("%u", start_nr); const char tool = to_end ? 'R' : 'r'; depot->call_depot_tool( tool, cnv, start ); } } bool depot_frame_t::action_triggered( gui_action_creator_t *comp, value_t p) { convoihandle_t cnv = depot->get_convoi( icnv ); if( depot->is_command_pending() ) { // block new commands until last command is executed return true; } if( comp != NULL ) { // message from outside! if( comp == &bt_start ) { if( cnv.is_bound() ) { //first: close schedule (will update schedule on clients) destroy_win( (ptrdiff_t)cnv->get_schedule() ); // only then call the tool to start char tool = (event_get_last_control_shift() ^ tool_t::control_invert)==2 ? 'B' : 'b'; // start all with CTRL-click depot->call_depot_tool( tool, cnv, NULL); } } else if( comp == &bt_schedule ) { if( line_selector.get_selection() == 1 && !line_selector.is_dropped() ) { // create new line // promote existing individual schedule to line cbuffer_t buf; if( cnv.is_bound() && !selected_line.is_bound() ) { schedule_t* schedule = cnv->get_schedule(); if( schedule ) { schedule->sprintf_schedule( buf ); } } depot->call_depot_tool('l', convoihandle_t(), buf); return true; } else { open_schedule_editor(); return true; } } else if( comp == &line_button ) { if( cnv.is_bound() ) { cnv->get_owner()->simlinemgmt.show_lineinfo( cnv->get_owner(), cnv->get_line(), 0 ); welt->set_dirty(); } } else if( comp == &bt_sell ) { char tool = (event_get_last_control_shift() ^ tool_t::control_invert)==2 ? 'V' : 'v'; // sell all with CTRL-click depot->call_depot_tool( tool, cnv, NULL); } // image list selection here ... else if( comp == &convoi ) { image_from_convoi_list( p.i, last_meta_event_get_class() == EVENT_DOUBLE_CLICK); } else if( comp == &pas && last_meta_event_get_class() != EVENT_DOUBLE_CLICK ) { image_from_storage_list(pas_vec[p.i]); } else if( comp == &electrics && last_meta_event_get_class() != EVENT_DOUBLE_CLICK ) { image_from_storage_list(electrics_vec[p.i]); } else if( comp == &loks && last_meta_event_get_class() != EVENT_DOUBLE_CLICK ) { image_from_storage_list(loks_vec[p.i]); } else if( comp == &waggons && last_meta_event_get_class() != EVENT_DOUBLE_CLICK ) { image_from_storage_list(waggons_vec[p.i]); } // convoi filters else if( comp == &bt_obsolete ) { show_retired_vehicles = (show_retired_vehicles == 0); bt_obsolete.pressed = show_retired_vehicles; depot_t::update_all_win(); } else if( comp == &bt_show_all ) { show_all = (show_all == 0); bt_show_all.pressed = show_all; depot_t::update_all_win(); } else if( comp == &name_filter_input ) { depot_t::update_all_win(); } else if( comp == &bt_veh_action ) { if( veh_action == va_sell ) { veh_action = va_append; } else { veh_action++; } } else if( comp == &sort_by ) { depot->selected_sort_by = sort_by.get_selection(); } else if( comp == &bt_copy_convoi ) { if( cnv.is_bound() ) { if( !welt->use_timeline() || welt->get_settings().get_allow_buying_obsolete_vehicles() || depot->check_obsolete_inventory( cnv ) ) { depot->call_depot_tool('c', cnv, NULL); } else { create_win( new news_img("Can't buy obsolete vehicles!"), w_time_delete, magic_none ); } } return true; } else if( comp == &convoy_selector ) { icnv = p.i - 1; } else if( comp == &line_selector ) { const int selection = p.i; if( selection == 0 ) { // unique if( selected_line.is_bound() ) { selected_line = linehandle_t(); apply_line(); } return true; } else if( selection == 1 ) { // create new line if( line_selector.is_dropped() ) { // but not from next/prev buttons // promote existing individual schedule to line cbuffer_t buf; if( cnv.is_bound() && !selected_line.is_bound() ) { schedule_t* schedule = cnv->get_schedule(); if( schedule ) { schedule->sprintf_schedule( buf ); } } last_selected_line = linehandle_t(); // clear last selected line so we can get a new one ... depot->call_depot_tool('l', convoihandle_t(), buf); } return true; } if( last_selected_line.is_bound() ) { if( selection == 2 ) { // last selected line selected_line = last_selected_line; apply_line(); return true; } } // access the selected element to get selected line line_scrollitem_t *item = dynamic_cast(line_selector.get_element(selection)); if( item ) { selected_line = item->get_line(); depot->set_last_selected_line( selected_line ); last_selected_line = selected_line; apply_line(); return true; } } else if( comp == &vehicle_filter ) { depot->selected_filter = vehicle_filter.get_selection(); } else { return false; } build_vehicle_lists(); } else { update_data(); update_tabs(); } return true; } bool depot_frame_t::infowin_event(const event_t *ev) { // enable disable button actions if( ev->ev_class < INFOWIN && (depot == NULL || welt->get_active_player() != depot->get_owner()) ) { return false; } const bool swallowed = gui_frame_t::infowin_event(ev); if(IS_WINDOW_CHOOSE_NEXT(ev)) { bool dir = (ev->ev_code==NEXT_WINDOW); depot_t *next_dep = depot_t::find_depot( depot->get_pos(), depot->get_typ(), depot->get_owner(), dir == NEXT_WINDOW ); if(next_dep == NULL) { if(dir == NEXT_WINDOW) { // check the next from start of map next_dep = depot_t::find_depot( koord3d(-1,-1,0), depot->get_typ(), depot->get_owner(), true ); } else { // respective end of map next_dep = depot_t::find_depot( koord3d(8192,8192,127), depot->get_typ(), depot->get_owner(), false ); } } if(next_dep && next_dep!=this->depot) { // Replace our depot_frame_t with a new at the same position. const scr_coord pos = win_get_pos(this); destroy_win( this ); next_dep->show_info(); win_set_pos(win_get_magic((ptrdiff_t)next_dep), pos); welt->get_viewport()->change_world_position(next_dep->get_pos()); } else { // recenter on current depot welt->get_viewport()->change_world_position(depot->get_pos()); } return true; } if (ev->ev_code == WIN_TOP) { update_data(); } if( swallowed && get_focus()==&name_filter_input && (ev->ev_class == EVENT_KEYBOARD || ev->ev_class == EVENT_STRING) ) { depot_t::update_all_win(); } return swallowed; } void depot_frame_t::draw(scr_coord pos, scr_size size) { const bool action_allowed = welt->get_active_player() == depot->get_owner(); bt_copy_convoi.enable( action_allowed ); bt_start.enable( action_allowed ); bt_schedule.enable( action_allowed ); bt_sell.enable( action_allowed ); bt_obsolete.enable( action_allowed ); bt_show_all.enable( action_allowed ); bt_veh_action.enable( action_allowed ); line_button.enable( action_allowed ); convoihandle_t cnv = depot->get_convoi(icnv); // check for data inconsistencies (can happen with withdraw-all and vehicle in depot) if( !cnv.is_bound() && !convoi_pics.empty() ) { icnv=0; update_data(); cnv = depot->get_convoi(icnv); } if (win_get_top() == this) { update_vehicle_info_text(pos); } gui_frame_t::draw(pos, size); } void depot_frame_t::apply_line() { if( icnv > -1 ) { convoihandle_t cnv = depot->get_convoi( icnv ); // if no convoi is selected, do nothing if( !cnv.is_bound() ) { return; } if( selected_line.is_bound() ) { // set new route only, a valid route is selected: char id[16]; sprintf( id, "%i", selected_line.get_id() ); cnv->call_convoi_tool('l', id ); } else { // sometimes the user might wish to remove convoy from line // => we clear the schedule completely schedule_t *dummy = cnv->create_schedule()->copy(); dummy->entries.clear(); cbuffer_t buf; dummy->sprintf_schedule(buf); cnv->call_convoi_tool('g', (const char*)buf ); delete dummy; } } } void depot_frame_t::open_schedule_editor() { convoihandle_t cnv = depot->get_convoi( icnv ); if( cnv.is_bound() && cnv->get_vehicle_count() > 0 ) { if( selected_line.is_bound() && (event_get_last_control_shift() ^ tool_t::control_invert)==2 ) { // update line with CTRL-click create_win( new line_management_gui_t( selected_line, depot->get_owner(), 0 ), w_info, (ptrdiff_t)selected_line.get_rep() ); } else { // edit individual schedule // this can happen locally, since any update of the schedule is done during closing window cnv->open_schedule_window( welt->get_active_player() == cnv->get_owner() ); } } else { create_win( new news_img("Please choose vehicles first\n"), w_time_delete, magic_none ); } } void depot_frame_t::update_vehicle_info_text(scr_coord pos) { // number of convoys if (old_vehicle_count != depot->get_vehicle_list().get_count()) { const uint32 count = depot->get_vehicle_list().get_count(); switch (count) { case 0: { lb_convoi_count.buf().append( translator::translate("Keine Einzelfahrzeuge im Depot") ); break; } case 1: { lb_convoi_count.buf().append( translator::translate("1 Einzelfahrzeug im Depot") ); break; } default: { lb_convoi_count.buf().printf( translator::translate("%d Einzelfahrzeuge im Depot"), count ); break; } } old_vehicle_count = count; lb_convoi_count.update(); cont_veh_action->set_size(cont_veh_action->get_size()); } // unmark vehicle for(gui_image_list_t::image_data_t* const& iptr : convoi_pics) { iptr->count = 0; } // Find vehicle under mouse cursor gui_component_t const* const tab = tabs.get_aktives_tab(); gui_image_list_t const* const lst = tab == &scrolly_pas ? &pas : tab == &scrolly_electrics ? &electrics : tab == &scrolly_loks ? &loks : &waggons; const scr_coord mouse_pos = get_mouse_pos(); double resale_value = -1.0; const vehicle_desc_t *veh_type = NULL; bool new_vehicle_length_sb_force_zero = false; sint16 convoi_number = -1; scr_coord relpos = scr_coord(0, ((gui_scrollpane_t *)tabs.get_aktives_tab())->get_scroll_y()); int sel_index = lst->index_at( pos + tabs.get_pos() - relpos, mouse_pos.x, mouse_pos.y - D_TITLEBAR_HEIGHT - tabs.get_required_size().h); if( (sel_index != -1) && (tabs.getroffen({ mouse_pos.x-pos.x, mouse_pos.y-pos.y-D_TITLEBAR_HEIGHT })) ) { // cursor over a vehicle in the selection list const vector_tpl& vec = (lst == &electrics ? electrics_vec : (lst == &pas ? pas_vec : (lst == &loks ? loks_vec : waggons_vec))); veh_type = vehicle_builder_t::get_info( vec[sel_index]->text ); if( vec[sel_index]->lcolor == color_idx_to_rgb(COL_RED) || veh_action == va_sell ) { // don't show new_vehicle_length_sb when can't actually add the highlighted vehicle, or selling from inventory new_vehicle_length_sb_force_zero = true; } if( vec[sel_index]->count > 0 ) { resale_value = (double)calc_restwert( veh_type ); } } else { // cursor over a vehicle in the convoi relpos = scr_coord(scrolly_convoi.get_scroll_x(), 0); convoi_number = sel_index = convoi.index_at(pos - relpos + scrolly_convoi.get_pos(), mouse_pos.x, mouse_pos.y - D_TITLEBAR_HEIGHT); if( sel_index != -1 ) { convoihandle_t cnv = depot->get_convoi( icnv ); veh_type = cnv->get_vehicle( sel_index )->get_desc(); resale_value = cnv->get_vehicle( sel_index )->calc_sale_value(); new_vehicle_length_sb_force_zero = true; // mark selected vehicle in convoi convoi_pics[convoi_number]->count = convoi_number+1; } } if( veh_type && veh_type != old_veh_type) { labels[LB_VEH_NAME]->buf().printf( "%s", translator::translate( veh_type->get_name(), welt->get_settings().get_name_language_id() ) ); if( veh_type->get_power() > 0 ) { // engine type labels[LB_VEH_NAME]->buf().printf( " (%s)\n", translator::translate( vehicle_builder_t::engine_type_names[veh_type->get_engine_type()+1] ) ); } if( sint64 fix_cost = welt->scale_with_month_length( veh_type->get_fixed_cost() ) ) { char tmp[128]; money_to_string( tmp, veh_type->get_price() / 100.0, false ); labels[LB_VEH_COST]->buf().printf( translator::translate("Cost: %8s (%.2f$/km %.2f$/m)\n"), tmp, veh_type->get_running_cost()/100.0, fix_cost/100.0 ); } else { char tmp[128]; money_to_string( tmp, veh_type->get_price() / 100.0, false ); labels[LB_VEH_COST]->buf().printf( translator::translate("Cost: %8s (%.2f$/km)\n"), tmp, veh_type->get_running_cost()/100.0 ); } if( veh_type->get_capacity() > 0 ) { // must translate as "Capacity: %3d%s %s\n" labels[LB_VEH_CAPACITY]->buf().printf( translator::translate("Capacity: %d%s %s\n"), veh_type->get_capacity(), translator::translate( veh_type->get_freight_type()->get_mass() ), veh_type->get_freight_type()->get_catg()==0 ? translator::translate( veh_type->get_freight_type()->get_name() ) : translator::translate( veh_type->get_freight_type()->get_catg_name() ) ); labels[LB_VEH_LOADINGTIME]->buf().printf("%s%s", translator::translate("Loading time:"), difftick_to_string(veh_type->get_loading_time(), false)); } else { labels[LB_VEH_CAPACITY]->buf().clear(); labels[LB_VEH_LOADINGTIME]->buf().clear(); } labels[LB_VEH_SPEED]->buf().printf( "%s %3d km/h\n", translator::translate("Max. speed:"), veh_type->get_topspeed() ); if( veh_type->get_power() > 0 ) { if( veh_type->get_gear() != 64 ){ labels[LB_VEH_POWER]->buf().printf( "%s %4d kW (x%0.2f)\n", translator::translate("Power:"), veh_type->get_power(), veh_type->get_gear() / 64.0 ); } else { labels[LB_VEH_POWER]->buf().printf( translator::translate("Power: %4d kW\n"), veh_type->get_power() ); } } // column 2 labels[LB_VEH_WEIGHT]->buf().printf( "%s %4.1ft\n", translator::translate("Weight:"), veh_type->get_weight() / 1000.0 ); labels[LB_VEH_DATE]->buf().printf( "%s: %s - ", translator::translate("Available"), translator::get_short_date(veh_type->get_intro_year_month() / 12, veh_type->get_intro_year_month() % 12) ); if( veh_type->get_retire_year_month() != DEFAULT_RETIRE_DATE * 12 ) { labels[LB_VEH_DATE]->buf().printf( "%s\n", translator::get_short_date(veh_type->get_retire_year_month() / 12, veh_type->get_retire_year_month() % 12) ); } if( char const* const copyright = veh_type->get_copyright() ) { labels[LB_VEH_AUTHOR]->buf().printf( translator::translate("Constructed by %s"), copyright ); } else { labels[LB_VEH_AUTHOR]->buf().clear(); } if( resale_value != -1.0 ) { char tmp[128]; money_to_string( tmp, resale_value / 100.0, false ); labels[LB_VEH_VALUE]->buf().printf( "%s %8s", translator::translate("Restwert:"), tmp ); } else { labels[LB_VEH_VALUE]->buf().clear(); } // update speedbar new_vehicle_length_sb = new_vehicle_length_sb_force_zero ? 0 : convoi_length_ok_sb + convoi_length_slower_sb + convoi_length_too_slow_sb + veh_type->get_length(); } else if (veh_type == NULL) { new_vehicle_length_sb = 0; for(uint32 i=LB_CNV_ALL; ibuf().clear(); } } if (veh_type != old_veh_type) { old_veh_type = veh_type; // update labels and size for(uint32 i=LB_CNV_ALL; iupdate(); } cont_vehicle_labels->set_size(cont_vehicle_labels->get_size()); } } void depot_frame_t::update_tabs() { gui_component_t *old_tab = tabs.get_aktives_tab(); tabs.clear(); bool one = false; // add only if there are any if( !pas_vec.empty() ) { tabs.add_tab(&scrolly_pas, translator::translate( depot->get_passenger_name() ) ); one = true; } // add only if there are any trolleybuses if( !electrics_vec.empty() ) { tabs.add_tab(&scrolly_electrics, translator::translate( depot->get_electrics_name() ) ); one = true; } // add, if wagons are there ... if( !loks_vec.empty() || !waggons_vec.empty() ) { tabs.add_tab(&scrolly_loks, translator::translate( depot->get_zieher_name() ) ); one = true; } // only add, if there are wagons if( !waggons_vec.empty() ) { tabs.add_tab(&scrolly_waggons, translator::translate( depot->get_haenger_name() ) ); one = true; } if( !one ) { // add passenger as default tabs.add_tab(&scrolly_pas, translator::translate( depot->get_passenger_name() ) ); } // Look, if there is our old tab present again (otherwise it will be 0 by tabs.clear()). for( uint8 i = 0; i < tabs.get_count(); i++ ) { if( old_tab == tabs.get_tab(i) ) { // Found it! tabs.set_active_tab_index(i); break; } } } uint32 depot_frame_t::get_rdwr_id() { return magic_depot; } void depot_frame_t::rdwr( loadsave_t *file) { if (file->is_version_less(120, 9)) { destroy_win(this); return; } // depot position koord3d pos; if( file->is_saving() ) { pos = depot->get_pos(); } pos.rdwr( file ); // window size scr_size size = get_windowsize(); size.rdwr( file ); if( file->is_loading() ) { depot_t *dep = welt->lookup(pos)->get_depot(); if (dep) { init(dep); } } tabs.rdwr(file); vehicle_filter.rdwr(file); file->rdwr_byte(veh_action); file->rdwr_long(icnv); sort_by.rdwr(file); simline_t::rdwr_linehandle_t(file, selected_line); if( depot && file->is_loading() ) { update_data(); update_tabs(); reset_min_windowsize(); set_windowsize(size); win_set_magic(this, (ptrdiff_t)depot); } if (depot == NULL) { destroy_win(this); } } simutrans-124.3/src/simutrans/gui/depot_frame.h000066400000000000000000000141411474050137200216120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_DEPOT_FRAME_H #define GUI_DEPOT_FRAME_H #include "gui_frame.h" #include "components/gui_label.h" #include "components/gui_image.h" #include "components/gui_image_list.h" #include "components/gui_textinput.h" #include "components/gui_combobox.h" #include "../tpl/ptrhashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "components/gui_tab_panel.h" #include "components/gui_button.h" #include "components/action_listener.h" #include "components/gui_scrollpane.h" #include "components/gui_speedbar.h" #include "../simtypes.h" #include "../utils/cbuffer.h" #include "../linehandle.h" #include "../convoihandle.h" class depot_t; class vehicle_desc_t; class depot_convoi_capacity_t; class gui_aligned_container_zero_width_t; /** * Depot frame, handles all interaction with a vehicle depot. */ class depot_frame_t : public gui_frame_t, public action_listener_t { private: /** * The depot to display */ depot_t *depot; /** * The current convoi to display. */ int icnv; /** * show retired vehicles (same for all depot) */ static bool show_retired_vehicles; /** * show retired vehicles (same for all depot) */ static bool show_all; /** * Gui elements */ gui_label_buf_t lb_convois, lb_convoi_count; /// contains the current translation of "new convoi" const char* new_convoy_text; gui_combobox_t convoy_selector; button_t line_button; // goto line ... vector_tpl labels; gui_aligned_container_t *cont_veh_action; gui_aligned_container_zero_width_t *cont_vehicle_labels; depot_convoi_capacity_t* cont_convoi_capacity; gui_speedbar_fixed_length_t sb_convoi_length; sint32 convoi_length_ok_sb, convoi_length_slower_sb, convoi_length_too_slow_sb, convoi_tile_length_sb, new_vehicle_length_sb; button_t bt_start; button_t bt_schedule; button_t bt_sell; button_t bt_obsolete; button_t bt_show_all; gui_combobox_t sort_by; static char name_filter_value[64]; gui_textinput_t name_filter_input; gui_tab_panel_t tabs; button_t bt_veh_action; button_t bt_copy_convoi; vector_tpl convoi_pics; gui_image_list_t convoi; gui_aligned_container_t cont_convoi; gui_scrollpane_t scrolly_convoi; /// image list of passenger cars vector_tpl pas_vec; /// image list of electrified passenger carrier units vector_tpl electrics_vec; /// image list of all other powered vehicles (and vehicles without freight capacity) vector_tpl loks_vec; /// image list of all other cars (freight, non-powered) vector_tpl waggons_vec; gui_image_list_t pas; gui_image_list_t electrics; gui_image_list_t loks; gui_image_list_t waggons; gui_scrollpane_t scrolly_pas; gui_scrollpane_t scrolly_electrics; gui_scrollpane_t scrolly_loks; gui_scrollpane_t scrolly_waggons; /// contains the current translation of "" const char* no_schedule_text; /// contains the current translation of "" const char* clear_schedule_text; /// contains the current translation of "" const char* unique_schedule_text; /// contains the current translation of "" const char* new_line_text; /// contains the current translation of "" const char* promote_to_line_text; /// "-----------" between header items and lines const char* line_seperator; gui_combobox_t line_selector; gui_combobox_t vehicle_filter; gui_image_t img_bolt; linehandle_t selected_line, last_selected_line; enum { va_append, va_insert, va_sell }; uint8 veh_action; /** * A helper map to update loks_vec and waggons_Vec. All entries from * loks_vec and waggons_vec are referenced here. */ typedef ptrhashtable_tpl vehicle_image_map; vehicle_image_map vehicle_map; /** * Update the info text for the vehicle the mouse is over - if any. */ void update_vehicle_info_text(scr_coord pos); // cache old values uint32 old_vehicle_count; const vehicle_desc_t *old_veh_type; /** * Calculate the values of the vehicles of the given type owned by the * player. */ sint64 calc_restwert(const vehicle_desc_t *veh_type); /// true if already stored here bool is_in_vehicle_list(const vehicle_desc_t *info); /// add a single vehicle (helper function) void add_to_vehicle_list(const vehicle_desc_t *info); /// for convoi image void image_from_convoi_list(uint nr, bool to_end); void image_from_storage_list(gui_image_list_t::image_data_t *image_data); /// initialize everything void init(depot_t *depot); public: // the next two are only needed for depot_t update notifications void activate_convoi( convoihandle_t cnv ); int get_icnv() const { return icnv; } /** * Update texts, image lists and buttons according to the current state. */ void update_data(); // more general functions ... depot_frame_t(depot_t* depot = NULL); ~depot_frame_t(); /** * Set the window size */ void set_windowsize(scr_size size) OVERRIDE; /** * Create and fill loks_vec and waggons_vec. */ void build_vehicle_lists(); /** * Will update the tabs (don't show empty ones). */ void update_tabs(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "depot.txt";} /** * Does this window need a next button in the title bar? * @return true if such a button is needed */ bool has_next() const OVERRIDE {return true;} koord3d get_weltpos(bool) OVERRIDE; bool is_weltpos() OVERRIDE; /** * Open dialog for schedule entry. */ void open_schedule_editor(); bool infowin_event(event_t const*) OVERRIDE; /** * Draw the Frame */ void draw(scr_coord pos, scr_size size) OVERRIDE; void apply_line(); void set_selected_line(linehandle_t line) { selected_line = line; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; uint32 get_rdwr_id() OVERRIDE; void rdwr( loadsave_t * ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/depotlist_frame.cc000066400000000000000000000143211474050137200226440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "depotlist_frame.h" #include "gui_theme.h" #include "../player/simplay.h" #include "../obj/depot.h" #include "../simskin.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../dataobj/translator.h" #include "../descriptor/skin_desc.h" depotlist_stats_t::depotlist_stats_t(depot_t *d) { this->depot = d; // pos button set_table_layout(3,1); gotopos.set_typ(button_t::posbutton_automatic); gotopos.set_targetpos3d(depot->get_pos()); add_component(&gotopos); // now add all specific tabs switch( d->get_waytype() ) { case maglev_wt: waytype_symbol.set_image( skinverwaltung_t::maglevhaltsymbol->get_image_id(0), true ); break; case monorail_wt: waytype_symbol.set_image( skinverwaltung_t::monorailhaltsymbol->get_image_id(0), true ); break; case track_wt: waytype_symbol.set_image( skinverwaltung_t::zughaltsymbol->get_image_id(0), true ); break; case tram_wt: waytype_symbol.set_image( skinverwaltung_t::tramhaltsymbol->get_image_id(0), true ); break; case narrowgauge_wt: waytype_symbol.set_image( skinverwaltung_t::narrowgaugehaltsymbol->get_image_id(0), true ); break; case road_wt: waytype_symbol.set_image( skinverwaltung_t::autohaltsymbol->get_image_id(0), true ); break; case water_wt: waytype_symbol.set_image( skinverwaltung_t::schiffshaltsymbol->get_image_id(0), true ); break; case air_wt: waytype_symbol.set_image( skinverwaltung_t::airhaltsymbol->get_image_id(0), true ); break; default: ; } add_component(&waytype_symbol); add_component(&label); update_label(); } void depotlist_stats_t::update_label() { cbuffer_t &buf = label.buf(); buf.append( translator::translate(depot->get_name()) ); buf.printf( " %s ", depot->get_pos().get_2d().get_fullstr() ); int cnvs = depot->convoi_count(); if( cnvs == 0 ) { // buf.append( translator::translate( "no convois" ) ); } else if( cnvs == 1 ) { buf.append( translator::translate( "1 convoi" ) ); buf.append(" "); } else { buf.printf( translator::translate( "%d convois" ), cnvs ); buf.append(" "); } int vhls = depot->get_vehicle_list().get_count(); if( vhls == 0 ) { buf.append( translator::translate( "Keine Einzelfahrzeuge im Depot" ) ); } else if( vhls == 1 ) { buf.append( translator::translate( "1 Einzelfahrzeug im Depot" ) ); } else { buf.printf( translator::translate( "%d Einzelfahrzeuge im Depot" ), vhls ); } label.update(); } void depotlist_stats_t::set_size(scr_size size) { gui_aligned_container_t::set_size(size); label.set_size(scr_size(get_size().w - label.get_pos().x, label.get_size().h)); } bool depotlist_stats_t::is_valid() const { return depot_t::get_depot_list().is_contained(depot); } bool depotlist_stats_t::infowin_event(const event_t * ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if (!swallowed) { // either open dialog or goto (with control or right click) if (IS_LEFTRELEASE(ev)) { if ((event_get_last_control_shift() ^ tool_t::control_invert) == 2) { world()->get_viewport()->change_world_position(depot->get_pos()); } else { depot->show_info(); } return true; } if (IS_RIGHTRELEASE(ev)) { world()->get_viewport()->change_world_position(depot->get_pos()); } } return swallowed; } void depotlist_stats_t::draw(scr_coord pos) { update_label(); gui_aligned_container_t::draw(pos); } bool depotlist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb) { const depotlist_stats_t* fa = dynamic_cast(aa); const depotlist_stats_t* fb = dynamic_cast(bb); // good luck with mixed lists assert(fa != NULL && fb != NULL); depot_t *a=fa->depot, *b=fb->depot; int cmp = a->convoi_count() - b->convoi_count(); if( cmp == 0 ) { cmp = a->get_vehicle_list().get_count() - b->get_vehicle_list().get_count(); } if (cmp == 0) { cmp = koord_distance( a->get_pos(), koord( 0, 0 ) ) - koord_distance( b->get_pos(), koord( 0, 0 ) ); if( cmp == 0 ) { cmp = a->get_pos().x - b->get_pos().x; } } return cmp > 0; } depotlist_frame_t::depotlist_frame_t(player_t *player) : gui_frame_t( translator::translate("dp_title"), player ), scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare) { this->player = player; last_depot_count = 0; set_table_layout(1,0); scrolly.set_maximize(true); scrolly.set_checkered(true); tabs.init_tabs(&scrolly); tabs.add_listener(this); add_component(&tabs); fill_list(); set_resizemode(diagonal_resize); reset_min_windowsize(); } depotlist_frame_t::depotlist_frame_t() : gui_frame_t(translator::translate("dp_title"), NULL), scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare) { player = NULL; last_depot_count = 0; set_table_layout(1, 0); scrolly.set_maximize(true); tabs.init_tabs(&scrolly); tabs.add_listener(this); add_component(&tabs); set_resizemode(diagonal_resize); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool depotlist_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if (comp == &tabs) { fill_list(); } return true; } void depotlist_frame_t::fill_list() { scrolly.clear_elements(); for(depot_t* const depot : depot_t::get_depot_list()) { if( depot->get_owner() == player ) { if( tabs.get_active_tab_index() == 0 || depot->get_waytype() == tabs.get_active_tab_waytype() ) { scrolly.new_component(depot); } } } scrolly.sort(0); scrolly.set_size(scr_size(get_windowsize().w, scrolly.get_size().h)); last_depot_count = depot_t::get_depot_list().get_count(); } void depotlist_frame_t::draw(scr_coord pos, scr_size size) { if( depot_t::get_depot_list().get_count() != last_depot_count ) { fill_list(); } gui_frame_t::draw(pos,size); } void depotlist_frame_t::rdwr(loadsave_t* file) { scr_size size = get_windowsize(); uint8 player_nr = player ? player->get_player_nr() : 0; file->rdwr_byte(player_nr); size.rdwr(file); tabs.rdwr(file); scrolly.rdwr(file); if (file->is_loading()) { player = welt->get_player(player_nr); win_set_magic(this, magic_depotlist + player_nr); fill_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/depotlist_frame.h000066400000000000000000000031621474050137200225070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_DEPOTLIST_FRAME_H #define GUI_DEPOTLIST_FRAME_H #include "gui_frame.h" #include "simwin.h" #include "components/gui_scrollpane.h" #include "components/gui_scrolled_list.h" #include "components/gui_waytype_tab_panel.h" #include "components/gui_label.h" #include "components/gui_image.h" class depot_t; class depotlist_frame_t : public gui_frame_t, private action_listener_t { private: gui_scrolled_list_t scrolly; gui_waytype_tab_panel_t tabs; uint32 last_depot_count; player_t *player; public: depotlist_frame_t(); depotlist_frame_t(player_t* player); void fill_list(); const char *get_help_filename() const OVERRIDE {return "depotlist.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void draw(scr_coord pos, scr_size size) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE { fill_list(); } void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_depotlist; } }; class depotlist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: depot_t *depot; gui_label_buf_t label; gui_image_t waytype_symbol; button_t gotopos; void update_label(); public: depotlist_stats_t(depot_t *); void draw( scr_coord pos) OVERRIDE; char const* get_text() const OVERRIDE { return ""; /* label.buf().get_str(); */ } bool infowin_event(const event_t *) OVERRIDE; bool is_valid() const OVERRIDE; void set_size(scr_size size) OVERRIDE; static bool compare(const gui_component_t *a, const gui_component_t *b ); }; #endif simutrans-124.3/src/simutrans/gui/display_settings.cc000066400000000000000000000677121474050137200230640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "display_settings.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../display/simimg.h" #include "../simintr.h" #include "../simcolor.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../obj/baum.h" #include "../obj/zeiger.h" #include "../display/simgraph.h" #include "../tool/simmenu.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../sys/simsys.h" #include "gui_theme.h" #include "themeselector.h" #include "loadfont_frame.h" #include "simwin.h" // display text label in player colors void display_text_label(sint16 xpos, sint16 ypos, const char* text, const player_t *player, bool dirty); // grund.cc enum { IDBTN_SCROLL_INVERSE, IDBTN_IGNORE_NUMLOCK, IDBTN_PEDESTRIANS_AT_STOPS, IDBTN_PEDESTRIANS_IN_TOWNS, IDBTN_DAY_NIGHT_CHANGE, IDBTN_TRANSPARENT_INSTEAD_OF_HIDDEN, IDBTN_HIDE_TREES, IDBTN_TRANSPARENT_STATION_COVERAGE, IDBTN_SHOW_STATION_COVERAGE, IDBTN_UNDERGROUND_VIEW, IDBTN_SHOW_GRID, IDBTN_HIDE_LABELS, IDBTN_LABEL_STYLE_ARROW, IDBTN_SHOW_WAITING_BARS, IDBTN_SHOW_SLICE_MAP_VIEW, IDBTN_HIDE_BUILDINGS, IDBTN_SHOW_SCHEDULES_STOP, IDBTN_SHOW_THEMEMANAGER, IDBTN_SIMPLE_DRAWING, IDBTN_CHANGE_FONT, IDBTN_INFINITE_SCROLL, IDBTN_LEFTDRAG_MINIMAP, COLORS_MAX_BUTTONS }; static button_t buttons[COLORS_MAX_BUTTONS]; /** * class to visualize station names IDBTN_SHOW_FACTORY_STORAGE, */ class gui_label_stationname_t : public gui_label_t { karte_ptr_t welt; public: gui_label_stationname_t(const char* text) : gui_label_t(text) {} void draw(scr_coord offset) OVERRIDE { scr_coord p = pos + offset; const player_t* player = welt->get_active_player(); const char *text = get_text_pointer(); display_text_label(p.x, p.y, text, player, true); } scr_size get_min_size() const OVERRIDE { return gui_label_t::get_min_size() + scr_size(LINESPACE + D_H_SPACE, 4); } }; gui_settings_t::gui_settings_t() { set_table_layout( 3, 0 ); // Show thememanager buttons[ IDBTN_SHOW_THEMEMANAGER ].init( button_t::roundbox_state | button_t::flexible, "Select a theme for display" ); add_component( buttons + IDBTN_SHOW_THEMEMANAGER, 3 ); // Change font buttons[ IDBTN_CHANGE_FONT ].init( button_t::roundbox_state | button_t::flexible, "Select display font" ); add_component( buttons + IDBTN_CHANGE_FONT, 3 ); // screen scale number input new_component("Screen scale:"); add_table(2,0); { screen_scale_numinp.init(dr_get_screen_scale(), 25, 400, 25, false); screen_scale_numinp.add_listener(this); add_component(&screen_scale_numinp); screen_scale_auto.init(button_t::roundbox_state, "Auto"); screen_scale_auto.add_listener(this); add_component(&screen_scale_auto); } end_table(); new_component(); // screen scale number input new_component("Icon size:"); base_icon_height = 32; if (tool_t::general_tool[TOOL_QUERY]->get_icon(NULL) != IMG_EMPTY) { scr_coord_val dummy; display_get_base_image_offset(tool_t::general_tool[TOOL_QUERY]->get_icon(NULL), &dummy, &dummy, &dummy, &base_icon_height); } // find current zoom factor for (icon_zoom = 0; icon_zoom <= MAX_ZOOM_FACTOR; icon_zoom++) { if (env_t::iconsize.h >= (base_icon_height * zoom_num[icon_zoom]) / zoom_den[icon_zoom]) { // since we go from large size break; } } add_table(2, 0); { icon_scale_down.set_typ(button_t::arrowleft); icon_scale_down.add_listener(this); add_component(&icon_scale_down); icon_scale_up.set_typ(button_t::arrowright); icon_scale_up.add_listener(this); add_component(&icon_scale_up); } end_table(); new_component(); // position of menu new_component("Toolbar position:"); switch (env_t::menupos) { case MENU_TOP: toolbar_pos.init(button_t::arrowup, NULL); break; case MENU_LEFT: toolbar_pos.init(button_t::arrowleft, NULL); break; case MENU_BOTTOM: toolbar_pos.init(button_t::arrowdown, NULL); break; case MENU_RIGHT: toolbar_pos.init(button_t::arrowright, NULL); break; } add_component(&toolbar_pos,2); single_toolbar.init( button_t::square_state, "Single toolbar only" ); single_toolbar.pressed = ( env_t::single_toolbar_mode ); add_component( &single_toolbar, 3 ); reselect_closes_tool.init( button_t::square_state, "Reselect closes tools" ); reselect_closes_tool.pressed = env_t::reselect_closes_tool; add_component( &reselect_closes_tool, 3 ); fullscreen.init( button_t::square_state, "Fullscreen (changed after restart)" ); fullscreen.pressed = ( dr_get_fullscreen() == FULLSCREEN ); fullscreen.enable(dr_has_fullscreen()); add_component( &fullscreen, 3 ); borderless.init( button_t::square_state, "Borderless (disabled on fullscreen)" ); borderless.enable ( dr_get_fullscreen() != FULLSCREEN ); borderless.pressed = ( dr_get_fullscreen() == BORDERLESS ); add_component( &borderless, 3 ); // Frame time label new_component("Frame time:"); frame_time_value_label.buf().printf(" 9999 ms"); frame_time_value_label.update(); add_component( &frame_time_value_label, 2 ); // Idle time label new_component("Idle:"); idle_time_value_label.buf().printf(" 9999 ms"); idle_time_value_label.update(); add_component( &idle_time_value_label, 2 ); // FPS label new_component("FPS:"); fps_value_label.buf().printf(" 99.9 fps"); fps_value_label.update(); add_component( &fps_value_label, 2 ); // Simloops label new_component("Sim:"); simloops_value_label.buf().printf(" 999.9"); simloops_value_label.update(); add_component( &simloops_value_label, 2 ); } void gui_settings_t::draw(scr_coord offset) { // Update label buffers frame_time_value_label.buf().printf(" %d ms", get_frame_time() ); frame_time_value_label.update(); idle_time_value_label.buf().printf(" %d ms", world()->get_idle_time() ); idle_time_value_label.update(); // fps_label uint32 target_fps = world()->is_fast_forward() ? env_t::ff_fps : env_t::fps; uint32 loops = world()->get_realFPS(); PIXVAL color = SYSCOL_TEXT_HIGHLIGHT; if( loops < (target_fps*16*3)/4 ) { color = color_idx_to_rgb(( loops <= target_fps*16/2 ) ? COL_RED : COL_YELLOW); } fps_value_label.set_color(color); fps_value_label.buf().printf(" %d fps", loops/16 ); #if MSG_LEVEL >= 3 if( env_t::simple_drawing ) { fps_value_label.buf().append( "*" ); } #endif fps_value_label.update(); //simloops_label loops = world()->get_simloops(); color = SYSCOL_TEXT_HIGHLIGHT; if( loops <= 30 ) { color = color_idx_to_rgb((loops<=20) ? COL_RED : COL_YELLOW); } simloops_value_label.set_color(color); simloops_value_label.buf().printf(" %d%c%d", loops/10, get_fraction_sep(), loops%10 ); simloops_value_label.update(); // All components are updated, now draw them... gui_aligned_container_t::draw(offset); } bool gui_settings_t::action_triggered(gui_action_creator_t *comp, value_t v) { if (comp == &screen_scale_numinp) { env_t::dpi_scale = v.i; dr_set_screen_scale(v.i); } else if (comp == &screen_scale_auto) { env_t::dpi_scale = -1; dr_set_screen_scale(-1); screen_scale_numinp.set_value(dr_get_screen_scale()); } else if (comp == &icon_scale_down) { if (icon_zoom < MAX_ZOOM_FACTOR) { icon_scale_up.enable(true); icon_zoom++; goto icon_resize; } icon_scale_down.enable(false); } else if (comp == &icon_scale_up) { if (icon_zoom > 0) { icon_scale_down.enable(true); icon_zoom--; goto icon_resize; } icon_scale_up.enable(false); } return true; icon_resize: scr_coord_val new_size = (zoom_num[icon_zoom] * base_icon_height) / zoom_den[icon_zoom]; env_t::iconsize.h = env_t::iconsize.w = new_size; // reload windows to update event_t* ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event(ev); return true; } map_settings_t::map_settings_t() { set_table_layout( 2, 0 ); // Show grid checkbox buttons[ IDBTN_SHOW_GRID ].init( button_t::square_state, "show grid" ); add_component( buttons + IDBTN_SHOW_GRID, 2 ); // Underground view checkbox buttons[ IDBTN_UNDERGROUND_VIEW ].init( button_t::square_state, "underground mode" ); add_component( buttons + IDBTN_UNDERGROUND_VIEW, 2 ); // Show slice map view checkbox buttons[ IDBTN_SHOW_SLICE_MAP_VIEW ].init( button_t::square_state, "sliced underground mode" ); add_component( buttons + IDBTN_SHOW_SLICE_MAP_VIEW ); // underground slice edit inp_underground_level.set_value( grund_t::underground_mode == grund_t::ugm_level ? grund_t::underground_level : world()->get_zeiger()->get_pos().z ); inp_underground_level.set_limits( world()->get_groundwater() - 10, 32 ); inp_underground_level.add_listener( this ); add_component( &inp_underground_level ); // Day/night change checkbox buttons[ IDBTN_DAY_NIGHT_CHANGE ].init( button_t::square_state, "8WORLD_CHOOSE" ); add_component( buttons + IDBTN_DAY_NIGHT_CHANGE, 2 ); // Brightness label new_component( "1LIGHT_CHOOSE" ); // brightness edit brightness.set_value( env_t::daynight_level ); brightness.set_limits( 0, 9 ); brightness.add_listener( this ); add_component( &brightness ); // Numpad key buttons[IDBTN_IGNORE_NUMLOCK].init(button_t::square_state, "Num pad keys always move map"); buttons[IDBTN_IGNORE_NUMLOCK].pressed = env_t::numpad_always_moves_map; add_component(buttons + IDBTN_IGNORE_NUMLOCK, 2); // Numpad key buttons[IDBTN_LEFTDRAG_MINIMAP].init(button_t::square_state, "Left button drags minimap too"); buttons[IDBTN_LEFTDRAG_MINIMAP].pressed = env_t::leftdrag_in_minimap; add_component(buttons + IDBTN_LEFTDRAG_MINIMAP, 2); // Scroll inverse checkbox buttons[IDBTN_SCROLL_INVERSE].init(button_t::square_state, "4LIGHT_CHOOSE"); add_component(buttons + IDBTN_SCROLL_INVERSE, 2); // Scroll infinite checkbox buttons[IDBTN_INFINITE_SCROLL].init(button_t::square_state, "Infinite mouse scrolling"); buttons[IDBTN_INFINITE_SCROLL].set_tooltip("Infinite scrolling using mouse"); add_component(buttons + IDBTN_INFINITE_SCROLL, 2); // scroll with genral tool selected if moved above a threshold new_component("Scroll threshold"); scroll_threshold.init(env_t::scroll_threshold, 1, 64, 1, false); scroll_threshold.add_listener(this); add_component(&scroll_threshold); // Scroll speed label new_component( "3LIGHT_CHOOSE" ); // Scroll speed edit scrollspeed.set_value( abs( env_t::scroll_multi ) ); scrollspeed.set_limits( 1, 9 ); scrollspeed.add_listener( this ); add_component( &scrollspeed ); #ifdef DEBUG // Toggle simple drawing for debugging buttons[IDBTN_SIMPLE_DRAWING].init(button_t::square_state, "Simple drawing"); add_component(buttons+IDBTN_SIMPLE_DRAWING, 2); #endif // Set date format new_component( "Date format" ); time_setting.set_focusable( false ); uint8 old_show_month = env_t::show_month; sint32 current_tick = world()->get_ticks(); for( env_t::show_month = 0; env_t::show_month<8; env_t::show_month++ ) { tstrncpy( time_str[env_t::show_month], tick_to_string( current_tick ), 64 ); time_setting.new_component( time_str[env_t::show_month], SYSCOL_TEXT ); } env_t::show_month = old_show_month; time_setting.set_selection( old_show_month ); add_component( &time_setting ); time_setting.add_listener( this ); } bool map_settings_t::action_triggered( gui_action_creator_t *comp, value_t v ) { // Brightness edit if( &brightness == comp ) { env_t::daynight_level = (sint8)v.i; } // Scroll speed edit else if (&scroll_threshold == comp) { env_t::scroll_threshold = v.i; } // Scroll speed edit else if (&scrollspeed == comp) { env_t::scroll_multi = (sint16)(buttons[IDBTN_SCROLL_INVERSE].pressed ? -v.i : v.i); } // underground slice edit else if( comp == &inp_underground_level ) { if( grund_t::underground_mode == grund_t::ugm_level ) { grund_t::underground_level = inp_underground_level.get_value(); // calc new images world()->update_underground(); } } else if( comp == &time_setting ) { env_t::show_month = v.i; return true; } return true; } transparency_settings_t::transparency_settings_t() { set_table_layout( 2, 0 ); // Transparent instead of hidden checkbox buttons[ IDBTN_TRANSPARENT_INSTEAD_OF_HIDDEN ].init( button_t::square_state, "hide transparent" ); add_component( buttons + IDBTN_TRANSPARENT_INSTEAD_OF_HIDDEN, 2 ); // Hide trees checkbox buttons[ IDBTN_HIDE_TREES ].init( button_t::square_state, "hide trees" ); add_component( buttons + IDBTN_HIDE_TREES, 2 ); // Hide buildings hide_buildings.set_focusable( false ); hide_buildings.new_component( translator::translate( "no buildings hidden" ), SYSCOL_TEXT ); hide_buildings.new_component( translator::translate( "hide city building" ), SYSCOL_TEXT ); hide_buildings.new_component( translator::translate( "hide all building" ), SYSCOL_TEXT ); hide_buildings.set_selection( env_t::hide_buildings ); add_component( &hide_buildings, 2 ); hide_buildings.add_listener( this ); buttons[ IDBTN_HIDE_BUILDINGS ].set_tooltip( "hide objects under cursor" ); buttons[ IDBTN_HIDE_BUILDINGS ].init( button_t::square_state, "Smart hide objects" ); add_component( buttons + IDBTN_HIDE_BUILDINGS ); // Smart hide objects edit cursor_hide_range.set_value( env_t::cursor_hide_range ); cursor_hide_range.set_limits( 0, 10 ); cursor_hide_range.add_listener( this ); add_component( &cursor_hide_range ); new_component( "Industry overlay" )->set_tooltip( translator::translate( "Display bars above factory to show the status" ) ); factory_tooltip.set_focusable( false ); factory_tooltip.new_component( translator::translate( "Do not show" ), SYSCOL_TEXT ); factory_tooltip.new_component( translator::translate( "On mouseover" ), SYSCOL_TEXT ); factory_tooltip.new_component( translator::translate( "Served by me" ), SYSCOL_TEXT ); factory_tooltip.new_component( translator::translate( "Show always" ), SYSCOL_TEXT ); factory_tooltip.set_selection( env_t::show_factory_storage_bar ); add_component( &factory_tooltip ); factory_tooltip.add_listener( this ); } bool transparency_settings_t::action_triggered( gui_action_creator_t *comp, value_t v ) { // Smart hide objects edit if( &cursor_hide_range == comp ) { env_t::cursor_hide_range = cursor_hide_range.get_value(); } // Hide building if( &hide_buildings == comp ) { env_t::hide_buildings = (uint8)v.i; world()->set_dirty(); } if( comp == &factory_tooltip ) { env_t::show_factory_storage_bar = (uint8)v.i; world()->set_dirty(); return true; } return true; } void transparency_settings_t::draw( scr_coord offset ) { hide_buildings.set_selection( env_t::hide_buildings ); gui_aligned_container_t::draw(offset); } station_settings_t::station_settings_t() { set_table_layout( 2, 0 ); // Transparent station coverage buttons[ IDBTN_TRANSPARENT_STATION_COVERAGE ].init( button_t::square_state, "transparent station coverage" ); buttons[ IDBTN_TRANSPARENT_STATION_COVERAGE ].pressed = env_t::use_transparency_station_coverage; add_component( buttons + IDBTN_TRANSPARENT_STATION_COVERAGE, 2 ); // Show station coverage buttons[ IDBTN_SHOW_STATION_COVERAGE ].init( button_t::square_state, "show station coverage" ); add_component( buttons + IDBTN_SHOW_STATION_COVERAGE, 2 ); // Show station coverage buttons[IDBTN_HIDE_LABELS].init(button_t::square_state, "Hide labels"); add_component(buttons + IDBTN_HIDE_LABELS, 2); // Show station names arrow add_table( 2, 1 ); { buttons[ IDBTN_LABEL_STYLE_ARROW ].set_typ( button_t::arrowright ); buttons[ IDBTN_LABEL_STYLE_ARROW ].set_tooltip( "Change label style" ); add_component( buttons + IDBTN_LABEL_STYLE_ARROW ); new_component( "Change label style" ); } end_table(); new_component(); // Show waiting bars checkbox buttons[ IDBTN_SHOW_WAITING_BARS ].init( button_t::square_state, "show waiting bars" ); buttons[ IDBTN_SHOW_WAITING_BARS ].pressed = env_t::show_names & 2; add_component( buttons + IDBTN_SHOW_WAITING_BARS, 2 ); } traffic_settings_t::traffic_settings_t() { set_table_layout( 2, 0 ); // Pedestrians in towns checkbox buttons[IDBTN_PEDESTRIANS_IN_TOWNS].init(button_t::square_state, "6LIGHT_CHOOSE"); buttons[IDBTN_PEDESTRIANS_IN_TOWNS].pressed = env_t::random_pedestrians; add_component(buttons+IDBTN_PEDESTRIANS_IN_TOWNS, 2); // Pedestrians at stops checkbox buttons[IDBTN_PEDESTRIANS_AT_STOPS].init(button_t::square_state, "5LIGHT_CHOOSE"); buttons[IDBTN_PEDESTRIANS_AT_STOPS].pressed = env_t::stop_pedestrians; add_component(buttons+IDBTN_PEDESTRIANS_AT_STOPS, 2); // Traffic density label new_component("6WORLD_CHOOSE"); // Traffic density edit traffic_density.set_value(world()->get_settings().get_traffic_level()); traffic_density.set_limits( 0, 16 ); traffic_density.add_listener(this); add_component(&traffic_density); // Convoy tooltip convoy_tooltip.set_focusable(false); convoy_tooltip.new_component(translator::translate("convoi error tooltips"), SYSCOL_TEXT); convoy_tooltip.new_component(translator::translate("convoi mouseover tooltips"), SYSCOL_TEXT); convoy_tooltip.new_component(translator::translate("line name mouseover tooltips"), SYSCOL_TEXT); convoy_tooltip.new_component(translator::translate("all convoi tooltips"), SYSCOL_TEXT); convoy_tooltip.set_selection(env_t::show_vehicle_states); add_component(&convoy_tooltip, 2); convoy_tooltip.add_listener(this); // Convoy follow mode new_component("Convoi following mode"); follow_mode.set_focusable(false); follow_mode.new_component(translator::translate("None"), SYSCOL_TEXT); follow_mode.new_component(translator::translate("underground mode"), SYSCOL_TEXT); follow_mode.new_component(translator::translate("sliced underground mode"), SYSCOL_TEXT); follow_mode.set_selection(env_t::follow_convoi_underground); add_component(&follow_mode); follow_mode.add_listener(this); // Show schedule's stop checkbox buttons[IDBTN_SHOW_SCHEDULES_STOP].init( button_t::square_state , "Highlite schedule" ); add_component(buttons+IDBTN_SHOW_SCHEDULES_STOP, 2); // convoi booking message options money_booking.set_focusable( false ); money_booking.new_component(translator::translate("Show all revenue messages"), SYSCOL_TEXT ); money_booking.new_component(translator::translate("Show only player's revenue"), SYSCOL_TEXT ); money_booking.new_component(translator::translate("Show no revenue messages"), SYSCOL_TEXT ); money_booking.set_selection( env_t::show_money_message ); add_component(&money_booking, 2); money_booking.add_listener(this); } bool traffic_settings_t::action_triggered( gui_action_creator_t *comp, value_t v ) { // Traffic density edit if( &traffic_density == comp ) { if( !env_t::networkmode || world()->get_active_player_nr() == PLAYER_PUBLIC_NR ) { static char level[ 16 ]; sprintf( level, "%li", v.i ); tool_t::simple_tool[ TOOL_TRAFFIC_LEVEL & 0xFFF ]->set_default_param( level ); world()->set_tool( tool_t::simple_tool[ TOOL_TRAFFIC_LEVEL & 0xFFF ], world()->get_active_player() ); } else { traffic_density.set_value( world()->get_settings().get_traffic_level() ); } } // Convoy tooltip if( &convoy_tooltip == comp ) { env_t::show_vehicle_states = (uint8)v.i; } if( &follow_mode == comp ) { env_t::follow_convoi_underground = (uint8)v.i; } if( &money_booking == comp ) { env_t::show_money_message = (sint8)v.i; } return true; } color_gui_t::color_gui_t() : gui_frame_t( translator::translate( "Display settings" ) ), scrolly_gui(&gui_settings), scrolly_map(&map_settings), scrolly_transparency(&transparency_settings), scrolly_station(&station_settings), scrolly_traffic(&traffic_settings) { set_table_layout( 1, 0 ); scrolly_gui.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_map.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_transparency.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_station.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_traffic.set_scroll_amount_y(D_BUTTON_HEIGHT/2); tabs.add_tab(&scrolly_gui, translator::translate("GUI settings")); tabs.add_tab(&scrolly_map, translator::translate("map view")); tabs.add_tab(&scrolly_transparency, translator::translate("transparencies")); tabs.add_tab(&scrolly_station, translator::translate("station labels")); tabs.add_tab(&scrolly_traffic, translator::translate("traffic settings")); add_component(&tabs); for( int i = 0; i < COLORS_MAX_BUTTONS; i++ ) { buttons[ i ].add_listener( this ); } gui_settings.toolbar_pos.add_listener( this ); gui_settings.single_toolbar.add_listener(this); gui_settings.reselect_closes_tool.add_listener(this); gui_settings.fullscreen.add_listener( this ); gui_settings.borderless.add_listener( this ); set_resizemode(diagonal_resize); set_min_windowsize( gui_settings.get_min_size()+scr_size(0,D_TAB_HEADER_HEIGHT) ); set_windowsize( scr_size(get_min_windowsize().w, map_settings.get_min_size().h) ); resize( scr_coord( 0, 0 ) ); } bool color_gui_t::action_triggered( gui_action_creator_t *comp, value_t) { if( comp == &gui_settings.toolbar_pos ) { env_t::menupos++; env_t::menupos &= 3; switch (env_t::menupos) { case MENU_TOP: gui_settings.toolbar_pos.set_typ(button_t::arrowup); break; case MENU_LEFT: gui_settings.toolbar_pos.set_typ(button_t::arrowleft); break; case MENU_BOTTOM: gui_settings.toolbar_pos.set_typ(button_t::arrowdown); break; case MENU_RIGHT: gui_settings.toolbar_pos.set_typ(button_t::arrowright); break; } welt->set_dirty(); // move all windows event_t* ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event(ev); return true; } if( comp == &gui_settings.fullscreen ) { gui_settings.fullscreen.pressed = !gui_settings.fullscreen.pressed; env_t::fullscreen = gui_settings.fullscreen.pressed; gui_settings.borderless.pressed = false; return true; } if( comp == &gui_settings.borderless ) { env_t::fullscreen = dr_toggle_borderless(); gui_settings.borderless.pressed = dr_get_fullscreen(); gui_settings.fullscreen.pressed = false; return true; } if( comp == &gui_settings.reselect_closes_tool ) { env_t::reselect_closes_tool = !env_t::reselect_closes_tool; gui_settings.reselect_closes_tool.pressed = env_t::reselect_closes_tool; return true; } if( comp == &gui_settings.single_toolbar ) { env_t::single_toolbar_mode = !env_t::single_toolbar_mode; gui_settings.single_toolbar.pressed = env_t::single_toolbar_mode; return true; } int i; for( i=0; iset_tool( tool_t::simple_tool[ TOOL_TOOGLE_PAX & 0xFFF ], welt->get_active_player() ); break; case IDBTN_PEDESTRIANS_IN_TOWNS: welt->set_tool( tool_t::simple_tool[ TOOL_TOOGLE_PEDESTRIANS & 0xFFF ], welt->get_active_player() ); break; case IDBTN_HIDE_TREES: env_t::hide_trees = !env_t::hide_trees; baum_t::recalc_outline_color(); break; case IDBTN_DAY_NIGHT_CHANGE: env_t::night_shift = !env_t::night_shift; break; case IDBTN_TRANSPARENT_INSTEAD_OF_HIDDEN: env_t::hide_with_transparency = !env_t::hide_with_transparency; baum_t::recalc_outline_color(); break; case IDBTN_TRANSPARENT_STATION_COVERAGE: env_t::use_transparency_station_coverage = !env_t::use_transparency_station_coverage; break; case IDBTN_SHOW_STATION_COVERAGE: env_t::station_coverage_show = env_t::station_coverage_show == 0 ? 0xFF : 0; break; case IDBTN_UNDERGROUND_VIEW: // see tool/simtool.cc::tool_show_underground_t::init grund_t::set_underground_mode( buttons[ IDBTN_UNDERGROUND_VIEW ].pressed ? grund_t::ugm_none : grund_t::ugm_all, map_settings.inp_underground_level.get_value() ); // calc new images welt->update_underground(); // renew toolbar tool_t::update_toolbars(); break; case IDBTN_SHOW_GRID: grund_t::toggle_grid(); break; case IDBTN_LABEL_STYLE_ARROW: { int label_style = ((env_t::show_names >> 2)+1)%3; env_t::show_names = (env_t::show_names & 3) + (label_style << 2); } break; case IDBTN_SHOW_WAITING_BARS: env_t::show_names ^= 2; break; case IDBTN_HIDE_LABELS: env_t::show_names ^= 1; break; case IDBTN_SHOW_SLICE_MAP_VIEW: // see tool/simtool.cc::tool_show_underground_t::init grund_t::set_underground_mode( buttons[ IDBTN_SHOW_SLICE_MAP_VIEW ].pressed ? grund_t::ugm_none : grund_t::ugm_level, map_settings.inp_underground_level.get_value() ); // calc new images welt->update_underground(); // renew toolbar tool_t::update_toolbars(); break; case IDBTN_HIDE_BUILDINGS: // see tool/simtool.cc::tool_hide_under_cursor_t::init env_t::hide_under_cursor = !env_t::hide_under_cursor && env_t::cursor_hide_range > 0; // renew toolbar tool_t::update_toolbars(); break; case IDBTN_SHOW_SCHEDULES_STOP: env_t::visualize_schedule = !env_t::visualize_schedule; break; case IDBTN_SHOW_THEMEMANAGER: create_win( new themeselector_t(), w_info, magic_themes ); break; case IDBTN_SIMPLE_DRAWING: env_t::simple_drawing = !env_t::simple_drawing; break; case IDBTN_CHANGE_FONT: create_win( new loadfont_frame_t(), w_info, magic_font ); break; default: assert( 0 ); } welt->set_dirty(); return true; } void color_gui_t::draw(scr_coord pos, scr_size size) { // Update button states that was changed with keyboard ... buttons[IDBTN_PEDESTRIANS_AT_STOPS].pressed = env_t::stop_pedestrians; buttons[IDBTN_PEDESTRIANS_IN_TOWNS].pressed = env_t::random_pedestrians; buttons[IDBTN_HIDE_TREES].pressed = env_t::hide_trees; buttons[IDBTN_HIDE_BUILDINGS].pressed = env_t::hide_under_cursor; buttons[IDBTN_SHOW_STATION_COVERAGE].pressed = env_t::station_coverage_show; buttons[IDBTN_UNDERGROUND_VIEW].pressed = grund_t::underground_mode == grund_t::ugm_all; buttons[IDBTN_SHOW_GRID].pressed = grund_t::show_grid; buttons[IDBTN_SHOW_WAITING_BARS].pressed = (env_t::show_names&2)!=0; buttons[IDBTN_HIDE_LABELS].pressed = (env_t::show_names & 1) == 0; buttons[IDBTN_SHOW_SLICE_MAP_VIEW].pressed = grund_t::underground_mode == grund_t::ugm_level; buttons[IDBTN_SHOW_SCHEDULES_STOP].pressed = env_t::visualize_schedule; buttons[IDBTN_SIMPLE_DRAWING].pressed = env_t::simple_drawing; buttons[IDBTN_SIMPLE_DRAWING].enable(welt->is_paused()); buttons[IDBTN_SCROLL_INVERSE].pressed = env_t::scroll_multi < 0; buttons[IDBTN_INFINITE_SCROLL].pressed = env_t::scroll_infinite; buttons[IDBTN_DAY_NIGHT_CHANGE].pressed = env_t::night_shift; buttons[IDBTN_SHOW_SLICE_MAP_VIEW].pressed = grund_t::underground_mode == grund_t::ugm_level; buttons[IDBTN_UNDERGROUND_VIEW].pressed = grund_t::underground_mode == grund_t::ugm_all; buttons[IDBTN_TRANSPARENT_STATION_COVERAGE].pressed = env_t::use_transparency_station_coverage; buttons[IDBTN_TRANSPARENT_INSTEAD_OF_HIDDEN].pressed = env_t::hide_with_transparency; // All components are updated, now draw them... gui_frame_t::draw(pos, size); } void color_gui_t::rdwr(loadsave_t *f) { tabs.rdwr(f); scrolly_gui.rdwr(f); scrolly_map.rdwr(f); scrolly_transparency.rdwr(f); scrolly_station.rdwr(f); scrolly_traffic.rdwr(f); } simutrans-124.3/src/simutrans/gui/display_settings.h000066400000000000000000000056711474050137200227220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_DISPLAY_SETTINGS_H #define GUI_DISPLAY_SETTINGS_H #include "simwin.h" #include "gui_frame.h" #include "components/gui_divider.h" #include "components/gui_label.h" #include "components/gui_button.h" #include "components/gui_numberinput.h" #include "components/gui_combobox.h" #include "components/gui_tab_panel.h" /** * Menu with display settings */ class gui_settings_t : public gui_aligned_container_t, public action_listener_t { private: gui_numberinput_t screen_scale_numinp; button_t icon_scale_down, icon_scale_up; button_t screen_scale_auto; scr_coord_val base_icon_height; uint icon_zoom; gui_label_buf_t frame_time_value_label, idle_time_value_label, fps_value_label, simloops_value_label; public: button_t toolbar_pos, reselect_closes_tool, single_toolbar, fullscreen, borderless; gui_settings_t(); void draw( scr_coord offset ) OVERRIDE; bool action_triggered( gui_action_creator_t *comp, value_t v) OVERRIDE; }; class map_settings_t : public gui_aligned_container_t, public action_listener_t { private: char time_str[8][64]; gui_combobox_t time_setting; public: gui_numberinput_t inp_underground_level, brightness, scrollspeed, scroll_threshold; map_settings_t(); bool action_triggered( gui_action_creator_t *comp, value_t v ) OVERRIDE; }; class station_settings_t : public gui_aligned_container_t { public: station_settings_t(); }; class transparency_settings_t : public gui_aligned_container_t, public action_listener_t { private: gui_numberinput_t cursor_hide_range; gui_combobox_t hide_buildings; gui_combobox_t factory_tooltip; public: transparency_settings_t(); bool action_triggered( gui_action_creator_t *comp, value_t v ) OVERRIDE; void draw(scr_coord offset) OVERRIDE; }; class traffic_settings_t : public gui_aligned_container_t, public action_listener_t { private: gui_numberinput_t traffic_density; gui_combobox_t convoy_tooltip, money_booking, follow_mode; public: traffic_settings_t(); bool action_triggered( gui_action_creator_t *comp, value_t v ) OVERRIDE; }; /** * Display settings dialog */ class color_gui_t : public gui_frame_t, private action_listener_t { private: gui_settings_t gui_settings; map_settings_t map_settings; transparency_settings_t transparency_settings; station_settings_t station_settings; traffic_settings_t traffic_settings; gui_scrollpane_t scrolly_gui, scrolly_map, scrolly_transparency, scrolly_station, scrolly_traffic; gui_tab_panel_t tabs; public: color_gui_t(); /** * Some windows have associated help text. * @return The help file name or NULL */ const char * get_help_filename() const OVERRIDE { return "display.txt"; } void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_color_gui_t; } void rdwr(loadsave_t*) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/enlarge_map_frame.cc000066400000000000000000000140531474050137200231110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "enlarge_map_frame.h" #include "minimap.h" #include "welt.h" #include "components/gui_divider.h" #include "../simdebug.h" #include "../world/simworld.h" #include "simwin.h" #include "../display/simimg.h" #include "../dataobj/settings.h" #include "../dataobj/translator.h" #include "../simcolor.h" #include "../display/simgraph.h" #include "../utils/simrandom.h" koord enlarge_map_frame_t::koord_from_rotation(settings_t const* const sets, sint16 const x, sint16 const y, sint16 const w, sint16 const h) { koord offset( sets->get_origin_x(), sets->get_origin_y() ); switch( sets->get_rotation() ) { default: case 0: return offset+koord(x,y); case 1: return offset+koord(y,w-x); case 2: return offset+koord(w-x,h-y); case 3: return offset+koord(h-y,x); } } enlarge_map_frame_t::enlarge_map_frame_t() : gui_frame_t( translator::translate("enlarge map") ), sets(new settings_t(welt->get_settings())), // Make a copy. map(MAP_PREVIEW_SIZE_X-2, MAP_PREVIEW_SIZE_Y-2) { sets->set_size_x(welt->get_size().x); sets->set_size_y(welt->get_size().y); changed_number_of_towns = false; // Component creation set_table_layout(1,0); // top part: preview, maps size add_table(2,1); { // input fields add_table(2,2); { // map seed number label map_number_label.init(); map_number_label.buf().printf("%s %d", translator::translate("2WORLD_CHOOSE"), welt->get_settings().get_map_number()); map_number_label.update(); add_component(&map_number_label); // Map X size edit inp_x_size.init( sets->get_size_x(), welt->get_size().x, 32766, sets->get_size_x()>=512 ? 128 : 64, false ); inp_x_size.add_listener(this); add_component( &inp_x_size ); // Map size label size_label.init(); size_label.buf().printf(translator::translate("Size (%d MB):"), 9999); size_label.update(); add_component( &size_label ); // Map size Y edit inp_y_size.init( sets->get_size_y(), sets->get_size_y(), 32766, sets->get_size_y()>=512 ? 128 : 64, false ); inp_y_size.add_listener(this); add_component( &inp_y_size ); } end_table(); // Map preview (will be initialized in update_preview add_component( &map_preview ); } end_table(); // specify map parameters add_table(2,0); { // Number of towns new_component("5WORLD_CHOOSE"); inp_number_of_towns.add_listener(this); inp_number_of_towns.init(abs(sets->get_city_count()), 0, 999); add_component( &inp_number_of_towns ); // Town size new_component("Median Citizen per town"); inp_town_size.add_listener(this); inp_town_size.set_limits(0,999999); inp_town_size.set_increment_mode(50); inp_town_size.set_value( sets->get_mean_citizen_count() ); add_component( &inp_town_size ); } end_table(); new_component(); // start game start_button.init( button_t::roundbox | button_t::flexible, "enlarge map"); start_button.add_listener( this ); add_component( &start_button ); welt_gui_t::update_memory(&size_label, sets); update_preview(); reset_min_windowsize(); set_windowsize(get_min_windowsize()); } enlarge_map_frame_t::~enlarge_map_frame_t() { delete sets; } /** * This method is called if an action is triggered */ bool enlarge_map_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) { if(comp==&inp_x_size) { sets->set_size_x( v.i ); inp_x_size.set_increment_mode( v.i>=64 ? (v.i>=512 ? 128 : 64) : 8 ); update_preview(); } else if(comp==&inp_y_size) { sets->set_size_y( v.i ); inp_y_size.set_increment_mode( v.i>=64 ? (v.i>=512 ? 128 : 64) : 8 ); update_preview(); } else if(comp==&inp_number_of_towns) { sets->set_city_count( v.i ); } else if(comp==&inp_town_size) { sets->set_mean_citizen_count( v.i ); } else if(comp==&start_button) { destroy_all_win( true ); welt->enlarge_map(sets, NULL); } else { return false; } return true; } void enlarge_map_frame_t::draw(scr_coord pos, scr_size size) { while (welt->get_settings().get_rotation() != sets->get_rotation()) { // map was rotated while we are active ... => rotate too! sets->rotate90(); sets->set_size( sets->get_size_y(), sets->get_size_x() ); update_preview(); } gui_frame_t::draw(pos, size); } /** * Calculate the new Map-Preview. Initialize the new RNG! */ void enlarge_map_frame_t::update_preview() { // reset noise seed setsimrand(0xFFFFFFFF, welt->get_settings().get_map_number()); // "welt" still knows the old size. The new size is saved in "sets". uint16 old_x = welt->get_size().x; uint16 old_y = welt->get_size().y; uint16 pre_x = min(sets->get_size_x(), map.get_width()); uint16 pre_y = min(sets->get_size_y(), map.get_height()); const int mx = sets->get_size_x()/pre_x; const int my = sets->get_size_y()/pre_y; for( int j=0; jlookup_hgt( pos ); color = minimap_t::calc_height_color(height, sets->get_groundwater()); } } else { // new part const sint16 height = karte_t::perlin_hoehe(sets, pos, koord(old_x,old_y) ); color = minimap_t::calc_height_color(height, sets->get_groundwater()); } map.at(i,j) = color; } } for( uint j=0; jheightfield = ""; if(!changed_number_of_towns){// Interpolate number of towns. sint32 new_area = sets->get_size_x() * sets->get_size_y(); sint32 old_area = old_x * old_y; sint32 const towns = welt->get_settings().get_city_count(); sets->set_city_count( towns * new_area / old_area - towns ); inp_number_of_towns.set_value(abs(sets->get_city_count()) ); } // guess the new memory needed welt_gui_t::update_memory(&size_label, sets); } simutrans-124.3/src/simutrans/gui/enlarge_map_frame.h000066400000000000000000000032611474050137200227520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_ENLARGE_MAP_FRAME_H #define GUI_ENLARGE_MAP_FRAME_H #include "gui_frame.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "components/gui_numberinput.h" #include "components/gui_map_preview.h" class settings_t; /* * Dialogue to increase map size. */ class enlarge_map_frame_t : public gui_frame_t, private action_listener_t { private: // local settings of the new world ... settings_t* sets; /** * Mini Map-Preview */ array2d_tpl map; gui_map_preview_t map_preview; bool changed_number_of_towns; gui_numberinput_t inp_x_size, inp_y_size, inp_number_of_towns, inp_town_size; /* * Label to display current map seed number. */ gui_label_buf_t map_number_label; button_t start_button; gui_label_buf_t size_label; // memory requirement public: static inline koord koord_from_rotation(settings_t const*, sint16 y, sint16 x, sint16 w, sint16 h); enlarge_map_frame_t(); ~enlarge_map_frame_t(); /** * Calculate the new Map-Preview. Initialize the new RNG! * public, because also the climate dialog need it */ void update_preview(); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "enlarge_map.txt";} /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/extend_edit.cc000066400000000000000000000231411474050137200217570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "../simevent.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../descriptor/ground_desc.h" #include "../player/simplay.h" #include "extend_edit.h" gui_rotation_item_t::gui_rotation_item_t(uint8 r) : gui_scrolled_list_t::const_text_scrollitem_t(NULL, SYSCOL_TEXT) { rotation = r; switch(rotation) { case 0: text = translator::translate("[0] south-facing"); break; case 1: text = translator::translate("[1] east-facing"); break; case 2: text = translator::translate("[2] north-facing"); break; case 3: text = translator::translate("[3] west-facing"); break; case 4: text = translator::translate("[4] southeast corner"); break; case 5: text = translator::translate("[5] northeast corner"); break; case 6: text = translator::translate("[6] northwest corner"); break; case 7: text = translator::translate("[7] southwest corner"); break; case automatic: text = translator::translate("auto"); break; case random: text = translator::translate("random"); break; default: text = ""; } } gui_climates_item_t::gui_climates_item_t(uint8 c) : gui_scrolled_list_t::const_text_scrollitem_t(NULL, SYSCOL_TEXT) { if(c(); // right column add_component(&cont_right,2); cont_right.set_table_layout(1,0); // add object settings (rotations, ...) cont_right.add_component(&cont_options); cont_options.set_table_layout(1,0); // add divider element cont_right.new_component(); // add scrollable element cont_right.add_component(&scrolly); cont_right.new_component(); //cont scrolly is already in scrolly cont_scrolly.set_table_layout(2,0); cont_scrolly.set_margin( scr_size( 0, D_V_SPACE ), scr_size( 0, D_V_SPACE ) ); // add object description cont_scrolly.add_component(&info_text,2); // add object image cont_scrolly.add_component(&building_image); cont_scrolly.new_component(true,false); cont_scrolly.new_component_span(false,true,2); //end of layouting. Now fill elements // init scrolled list scl.set_selection(-1); scl.add_listener(this); scl.set_min_width( (D_DEFAULT_WIDTH-D_MARGIN_LEFT-D_MARGIN_RIGHT-2*D_H_SPACE)/2 ); // start filling cont_timeline--------------------------------------------------------------------------------------------- bt_timeline.init( button_t::square_state, "timeline"); bt_timeline.pressed = welt->get_settings().get_use_timeline(); bt_timeline.add_listener(this); cont_timeline.add_component(&bt_timeline, 4); bt_timeline_custom.init( button_t::square_state, "Available at custom date"); bt_timeline_custom.add_listener(this); cont_timeline.add_component(&bt_timeline_custom, 4); // respect year/month order according to language settings bool year_month_order = ( env_t::show_month == env_t::DATE_FMT_JAPANESE || env_t::show_month == env_t::DATE_FMT_JAPANESE_NO_SEASON ); if( !year_month_order ) { // month first then year cont_timeline.new_component("Month"); cont_timeline.add_component(&ni_timeline_month); } cont_timeline.new_component("Year"); cont_timeline.add_component(&ni_timeline_year); if( year_month_order ) { // year first then month cont_timeline.new_component("Month"); cont_timeline.add_component(&ni_timeline_month); } ni_timeline_month.init( (sint32)(welt->get_current_month()%12+1), 1, 12, 1, true ); ni_timeline_month.add_listener(this); ni_timeline_year.init( (sint32)(welt->get_current_month()/12), 0, 2999, 1, false ); ni_timeline_year.add_listener(this); bt_obsolete.init( button_t::square_state, "Show obsolete"); bt_obsolete.add_listener(this); cont_timeline.add_component(&bt_obsolete, 4); // end filling cont_timeline--------------------------------------------------------------------------------------------- // start filling cont_filter--------------------------------------------------------------------------------------------- // climate filter cont_filter.new_component("Climate"); cont_filter.add_component(&cb_climates, 2); cb_climates.add_listener(this); cb_climates.new_component(climate::MAX_CLIMATES); for(uint8 i=climate::desert_climate; i(i); } cb_climates.set_selection(0); // Sorting box cont_filter.new_component("Sort by"); cont_filter.add_component(&cb_sortedby); sort_order.init(button_t::sortarrow_state, ""); sort_order.set_tooltip(translator::translate("hl_btn_sort_order")); sort_order.add_listener(this); sort_order.pressed = false; cont_filter.add_component(&sort_order); cb_sortedby.add_listener(this); cb_sortedby.new_component(gui_sorting_item_t::BY_NAME_TRANSLATED); cb_sortedby.new_component(gui_sorting_item_t::BY_NAME_OBJECT); cb_sortedby.set_selection(0); // end filling cont_filter--------------------------------------------------------------------------------------------- //filling cont_options bt_climates.init( button_t::square_state, "ignore climates"); bt_climates.add_listener(this); cont_options.add_component(&bt_climates); //setting scrollable content box scrolly.set_visible(true); scrolly.set_min_width( (D_DEFAULT_WIDTH-D_MARGIN_LEFT-D_MARGIN_RIGHT-2*D_H_SPACE)/2 ); } /** * Mouse click are hereby reported to its GUI-Components */ bool extend_edit_gui_t::infowin_event(const event_t *ev) { if(ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE) { change_item_info(-1); } return gui_frame_t::infowin_event(ev); } // resize flowtext to avoid horizontal scrollbar void extend_edit_gui_t::set_windowsize( scr_size s ) { gui_frame_t::set_windowsize( s ); info_text.set_width( scrolly.get_client().w ); } bool extend_edit_gui_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if (comp == &scl) { // select an item of scroll list ? change_item_info(scl.get_selection()); } else if( comp==&bt_obsolete ) { bt_obsolete.pressed ^= 1; fill_list(); } else if( comp==&bt_climates ) { bt_climates.pressed ^= 1; fill_list(); } else if( comp==&bt_timeline ) { bt_timeline_custom.pressed = false; bt_timeline.pressed ^= 1; fill_list(); } else if ( comp==&bt_timeline_custom ) { bt_timeline.pressed = false; bt_timeline_custom.pressed ^= 1; fill_list(); } else if ( comp==&ni_timeline_year && bt_timeline_custom.pressed) { fill_list(); } else if ( comp==&ni_timeline_month && bt_timeline_custom.pressed) { fill_list(); } else if( comp==&cb_climates ) { fill_list(); change_item_info(scl.get_selection()); } else if( comp==&cb_sortedby ) { fill_list(); } else if( comp == &sort_order ) { sort_order.pressed = !sort_order.pressed; fill_list(); } return true; } uint8 extend_edit_gui_t::get_rotation() const { if (gui_rotation_item_t *item = dynamic_cast( cb_rotation.get_selected_item() ) ) { return item->get_rotation(); } return 0; } uint8 extend_edit_gui_t::get_climate() const { if (gui_climates_item_t *item = dynamic_cast( cb_climates.get_selected_item() ) ) { return item->get_climate(); } return ALL_CLIMATES; } uint8 extend_edit_gui_t::get_sortedby() const { if (gui_sorting_item_t *item = dynamic_cast( cb_sortedby.get_selected_item() ) ) { return item->get_sortedby(); } return ALL_CLIMATES; } simutrans-124.3/src/simutrans/gui/extend_edit.h000066400000000000000000000070741474050137200216300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_EXTEND_EDIT_H #define GUI_EXTEND_EDIT_H #include "gui_frame.h" #include "components/gui_textinput.h" #include "components/gui_scrolled_list.h" #include "components/gui_scrollpane.h" #include "components/gui_tab_panel.h" #include "components/gui_button.h" #include "components/gui_image.h" #include "components/gui_fixedwidth_textarea.h" #include "components/gui_building.h" #include "components/gui_combobox.h" #include "components/gui_numberinput.h" #include "components/gui_divider.h" #include "../utils/cbuffer.h" #include "../simtypes.h" class player_t; /** * Entries for rotation selection. */ class gui_rotation_item_t : public gui_scrolled_list_t::const_text_scrollitem_t { private: const char *text; uint8 rotation; ///< 0-3, 255 = random public: enum special_rotations_t { automatic = 254, random = 255 }; gui_rotation_item_t(uint8 r); char const* get_text () const OVERRIDE { return text; } sint8 get_rotation() const { return rotation; } }; /** * Entries for climate selection. */ class gui_climates_item_t : public gui_scrolled_list_t::const_text_scrollitem_t { private: const char *text; uint8 climate_; public: gui_climates_item_t(uint8 r); char const* get_text () const OVERRIDE { return text; } sint8 get_climate() const { return climate_; } }; /** * Entries for sorting selection. */ class gui_sorting_item_t : public gui_scrolled_list_t::const_text_scrollitem_t { private: const char *text; uint8 sorted_by; public: enum sorting_options { BY_NAME_TRANSLATED, BY_NAME_OBJECT, BY_LEVEL_PAX, BY_LEVEL_MAIL, BY_DATE_INTRO, BY_DATE_RETIRE, BY_SIZE, BY_COST, BY_GOODS_NUMBER, BY_REMOVAL }; gui_sorting_item_t(uint8 r); char const* get_text () const OVERRIDE { return text; } sint8 get_sortedby() const { return sorted_by; } }; /** * Base class map editor dialogues to select object to place on map. */ class extend_edit_gui_t : public gui_frame_t, public action_listener_t { protected: player_t *player; /// cont_left: left column, cont_right: right column gui_aligned_container_t cont_left, cont_right; /// cont_filter: Settings about the content of the list (above list) /// cont_timeline: timeline-related filter settings /// cont_options: Settings about the active object (eg. rotation) /// cont_scrolly: the scrollable container (image + desc) gui_aligned_container_t cont_filter, cont_options, cont_timeline, cont_scrolly; cbuffer_t buf; gui_fixedwidth_textarea_t info_text; //container for object description gui_scrollpane_t scrolly; gui_scrolled_list_t scl; //image gui_building_t building_image; button_t bt_obsolete, bt_timeline, bt_climates, bt_timeline_custom, sort_order; // we make this available for child classes gui_combobox_t cb_rotation, cb_climates, cb_sortedby; gui_numberinput_t ni_timeline_year, ni_timeline_month; virtual void fill_list() {} virtual void change_item_info( sint32 /*entry, -1= none */ ) {} /** * @returns selected rotation of cb_rotation. * assumes that cb_rotation only contains gui_rotation_item_t-items. * defaults to zero. */ uint8 get_rotation() const; /** * @returns selected climate of cb_climates. */ uint8 get_climate() const; /** * @returns selected sorting method. */ uint8 get_sortedby() const; public: extend_edit_gui_t(const char *name, player_t* player_); void set_windowsize( scr_size s ) OVERRIDE; bool infowin_event(event_t const*) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/fabrik_info.cc000066400000000000000000000301141474050137200217320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "fabrik_info.h" #include "components/gui_label.h" #include "help_frame.h" #include "factory_chart.h" #include "../simfab.h" #include "../simcolor.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../world/simcity.h" #include "simwin.h" #include "../tool/simmenu.h" #include "../player/simplay.h" #include "../world/simworld.h" #include "../simskin.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../utils/simstring.h" /** * Helper class: one row of entries in consumer / supplier table */ class gui_factory_connection_t : public gui_aligned_container_t { const fabrik_t *fab; koord target; bool supplier; gui_image_t* image; bool is_active() const { if (supplier) { if( const fabrik_t *src = fabrik_t::get_fab(target) ) { return src->is_active_consumer(fab->get_pos().get_2d()); } } else { return fab->is_active_consumer(target); } return false; } public: gui_factory_connection_t(const fabrik_t* f, koord t, bool s) : fab(f), target(t), supplier(s) { set_table_layout(3,1); button_t* b = new_component(); b->set_typ(button_t::posbutton_automatic); b->set_targetpos(target); image = new_component(skinverwaltung_t::goods->get_image_id(0)); image->enable_offset_removal(true); gui_label_buf_t* l = new_component(); if (const fabrik_t *other = fabrik_t::get_fab(target) ) { l->buf().printf("%s (%d,%d)", other->get_name(), target.x, target.y); l->update(); } } void draw(scr_coord offset) OVERRIDE { image->set_transparent(is_active() ? 0 : TRANSPARENT50_FLAG); gui_aligned_container_t::draw(offset); } }; fabrik_info_t::fabrik_info_t(fabrik_t* fab_, const gebaeude_t* gb) : gui_frame_t(""), fab(fab_), chart(NULL), view(scr_size( max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width() * 7) / 8))), prod(&prod_buf), txt(&info_buf), scroll_info(&container_info) { if (fab) { init(fab, gb); } } void fabrik_info_t::init(fabrik_t* fab_, const gebaeude_t* gb) { fab = fab_; // window name tstrncpy( fabname, fab->get_name(), lengthof(fabname) ); gui_frame_t::set_name(fab->get_name()); set_owner(fab->get_owner()); set_table_layout(1,0); // input name input.set_text( fabname, lengthof(fabname) ); input.set_notify_all_changes_delay(500); // since it triggers a tool input.add_listener(this); add_component(&input); highlight_suppliers.set_text("Suppliers"); highlight_suppliers.set_typ(button_t::roundbox_state); highlight_suppliers.add_listener(this); highlight_consumers.set_text("Abnehmer"); highlight_consumers.set_typ(button_t::roundbox_state); highlight_consumers.add_listener(this); // top part: production number & details, boost indicators, factory view add_table(6,0)->set_alignment(ALIGN_LEFT | ALIGN_TOP); { // production details per input/output fab->info_prod( prod_buf ); prod.recalc_size(); add_component( &prod ); new_component(); // indicator for possible boost by electricity, passengers, mail if (fab->get_desc()->get_electric_boost() ) { boost_electric.set_image(skinverwaltung_t::electricity->get_image_id(0), true); add_component(&boost_electric); } if (fab->get_desc()->get_pax_boost() ) { boost_passenger.set_image(skinverwaltung_t::passengers->get_image_id(0), true); add_component(&boost_passenger); } if (fab->get_desc()->get_mail_boost() ) { boost_mail.set_image(skinverwaltung_t::mail->get_image_id(0), true); add_component(&boost_mail); } // world view object with boost overlays add_table(1,0)->set_spacing( scr_size(0,0)); { add_component(&view); view.set_obj(gb); add_component(&indicator_color); indicator_color.set_max_size(view.get_max_size()); } end_table(); } end_table(); // tab panel: connections, chart panels, details add_component(&switch_mode); switch_mode.add_tab(&scroll_info, translator::translate("Connections")); // connection information container_info.set_table_layout(1,0); container_info.add_component(&all_suppliers); container_info.add_component(&all_consumers); container_info.add_component(&all_cities); container_info.add_component(&txt); fab->info_conn(info_buf); // initialize to zero, update_info will do the rest old_suppliers_count = 0; old_consumers_count = 0; old_stops_count = 0; old_cities_count = 0; update_info(); // take-over chart tabs into our chart.set_factory(fab); switch_mode.take_tabs(chart.get_tab_panel()); // factory description in tab { bool add_tab = false; details_buf.clear(); // factory details char key[256]; sprintf(key, "factory_%s_details", fab->get_desc()->get_name()); const char * value = translator::translate(key); if(value && *value != 'f') { details_buf.append(value); add_tab = true; } if (char const* const maker = fab->get_desc()->get_copyright()) { details_buf.append("

"); details_buf.printf(translator::translate("Constructed by %s"), maker); add_tab = true; } if (add_tab) { switch_mode.add_tab(&container_details, translator::translate("Details")); container_details.set_table_layout(1,0); gui_flowtext_t* f = container_details.new_component(); f->set_text( (const char*)details_buf); } } reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(gui_frame_t::diagonal_resize); } fabrik_info_t::~fabrik_info_t() { rename_factory(); fabname[0] = 0; if (highlight_consumers.pressed) { highlight(fab->get_consumer(), false); } if (highlight_suppliers.pressed) { highlight(fab->get_suppliers(), false); } } void fabrik_info_t::rename_factory() { if( fabname[0] && welt->get_fab_list().is_contained(fab) && strcmp(fabname, fab->get_name()) ) { // text changed and factory still exists => call tool cbuffer_t buf; buf.printf( "f%s,%s", fab->get_pos().get_str(), fabname ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); welt->set_tool( tool, welt->get_public_player()); // since init always returns false, it is safe to delete immediately delete tool; } } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void fabrik_info_t::draw(scr_coord pos, scr_size size) { update_components(); // boost stuff boost_electric.set_transparent(fab->get_prodfactor_electric()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); boost_passenger.set_transparent(fab->get_prodfactor_pax()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); boost_mail.set_transparent(fab->get_prodfactor_mail()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); indicator_color.set_color( color_idx_to_rgb(fabrik_t::status_to_color[fab->get_status()]) ); chart.update(); gui_frame_t::draw(pos, size); } bool fabrik_info_t::is_weltpos() { return ( welt->get_viewport()->is_on_center( get_weltpos(false) ) ); } /** * This method is called if an action is triggered * * Returns true, if action is done and no more * components should be triggered. */ bool fabrik_info_t::action_triggered( gui_action_creator_t *comp, value_t) { if( comp == &input ) { rename_factory(); return false; } else if (comp == &highlight_consumers) { highlight_consumers.pressed ^= 1; highlight(fab->get_consumer(), highlight_consumers.pressed); } else if (comp == &highlight_suppliers) { highlight_suppliers.pressed ^= 1; highlight(fab->get_suppliers(), highlight_suppliers.pressed); } return true; } void fabrik_info_t::map_rotate90(sint16) { // force update old_suppliers_count ++; old_consumers_count ++; old_stops_count ++; old_cities_count ++; update_components(); } // update name and buffers void fabrik_info_t::update_info() { tstrncpy( fabname, fab->get_name(), lengthof(fabname) ); gui_frame_t::set_name(fab->get_name()); input.set_text( fabname, lengthof(fabname) ); update_components(); } // update all buffers void fabrik_info_t::update_components() { // update texts fab->info_prod( prod_buf ); fab->info_conn( info_buf ); // consumers if( fab->get_consumer().get_count() != old_consumers_count ) { all_consumers.remove_all(); all_consumers.set_table_layout(1,0); all_consumers.set_margin(scr_size(0,0), scr_size(0,D_V_SPACE)); all_consumers.add_component(&highlight_consumers); for(koord k : fab->get_consumer() ) { all_consumers.new_component(fab, k, false); } old_consumers_count = fab->get_consumer().get_count(); } // suppliers if( fab->get_suppliers().get_count() != old_suppliers_count ) { all_suppliers.remove_all(); all_suppliers.set_table_layout(1,0); all_suppliers.set_margin(scr_size(0,0), scr_size(0,D_V_SPACE)); all_suppliers.add_component(&highlight_suppliers); for(koord k : fab->get_suppliers() ) { if( const fabrik_t *src = fabrik_t::get_fab(k) ) { all_suppliers.new_component(fab, src->get_pos().get_2d(), true); } } old_suppliers_count = fab->get_suppliers().get_count(); } // cities if( fab->get_target_cities().get_count() != old_cities_count ) { all_cities.remove_all(); all_cities.set_table_layout(6,0); all_cities.set_margin(scr_size(0,0), scr_size(0,D_V_SPACE)); all_cities.new_component_span(fab->is_end_consumer() ? "Customers live in:" : "Arbeiter aus:", 6); // no new class for entries to get better alignment for columns for(stadt_t* const c : fab->get_target_cities()) { button_t* b = all_cities.new_component(); b->set_typ(button_t::posbutton_automatic); b->set_targetpos(c->get_center()); // name gui_label_buf_t *l = all_cities.new_component(); l->buf().printf("%s", c->get_name()); l->update(); stadt_t::factory_entry_t const* const pax_entry = c->get_target_factories_for_pax().get_entry(fab); stadt_t::factory_entry_t const* const mail_entry = c->get_target_factories_for_mail().get_entry(fab); assert( pax_entry && mail_entry ); // passengers l = all_cities.new_component(); l->buf().printf("%i", pax_entry->supply); l->update(); l->set_align(gui_label_t::right); all_cities.new_component(skinverwaltung_t::passengers->get_image_id(0))->enable_offset_removal(true); // mail l = all_cities.new_component(); l->buf().printf("%i", mail_entry->supply); l->update(); l->set_align(gui_label_t::right); all_cities.new_component(skinverwaltung_t::mail->get_image_id(0))->enable_offset_removal(true); } old_cities_count = fab->get_target_cities().get_count(); } container_info.set_size(container_info.get_min_size()); set_dirty(); } /***************** Saveload stuff from here *****************/ void fabrik_info_t::rdwr( loadsave_t *file ) { // the factory first koord fabpos; if( file->is_saving() ) { fabpos = fab->get_pos().get_2d(); } fabpos.rdwr( file ); // window size scr_size size = get_windowsize(); size.rdwr( file ); if( file->is_loading() ) { fab = fabrik_t::get_fab(fabpos ); gebaeude_t* gb = welt->lookup_kartenboden( fabpos )->find(); if (fab != NULL && gb != NULL) { init(fab, gb); } win_set_magic(this, (ptrdiff_t)fab); } chart.rdwr(file); scroll_info.rdwr(file); switch_mode.rdwr(file); if( file->is_loading() ) { reset_min_windowsize(); set_windowsize(size); } } void fabrik_info_t::highlight(vector_tpl fab_koords, bool marking) { fab_koords.append(fab->get_pos().get_2d()); for (uint i = 0; i < fab_koords.get_count(); i++) { vector_tpl fab_tiles; if(grund_t *gr = welt->lookup_kartenboden(fab_koords[i])) { if(gebaeude_t *gb=gr->find() ) { gb->get_tile_list(fab_tiles); for(grund_t* gr : fab_tiles ) { // no need for check, we just did before ... gebaeude_t* gb = gr->find(); if( marking ) { gb->set_flag( obj_t::highlight ); } else { gb->clear_flag( obj_t::highlight ); } gr->set_flag( grund_t::dirty ); } } } } } simutrans-124.3/src/simutrans/gui/fabrik_info.h000066400000000000000000000046761474050137200216120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_FABRIK_INFO_H #define GUI_FABRIK_INFO_H #include "simwin.h" #include "factory_chart.h" #include "components/action_listener.h" #include "components/gui_scrollpane.h" #include "components/gui_textarea.h" #include "components/gui_textinput.h" #include "components/gui_obj_view.h" #include "components/gui_container.h" #include "components/gui_colorbox.h" #include "components/gui_image.h" #include "components/gui_tab_panel.h" #include "../utils/cbuffer.h" class welt_t; class fabrik_t; class gebaeude_t; class button_t; /** * Info window for factories */ class fabrik_info_t : public gui_frame_t, public action_listener_t { private: fabrik_t *fab; cbuffer_t info_buf, prod_buf, details_buf; factory_chart_t chart; obj_view_t view; char fabname[256]; gui_textinput_t input; gui_textarea_t prod, txt; gui_colorbox_t indicator_color; gui_tab_panel_t switch_mode; gui_image_t boost_electric, boost_passenger, boost_mail; gui_aligned_container_t container_info, container_details; gui_aligned_container_t all_suppliers, all_consumers, all_stops, all_cities; uint32 old_suppliers_count, old_consumers_count, old_stops_count, old_cities_count; gui_scrollpane_t scroll_info; button_t highlight_suppliers; button_t highlight_consumers; void rename_factory(); void update_components(); public: // refreshes text, images, indicator void update_info(); fabrik_info_t(fabrik_t* fab = NULL, const gebaeude_t* gb = NULL); virtual ~fabrik_info_t(); void init(fabrik_t* fab, const gebaeude_t* gb); fabrik_t* get_factory() { return fab; } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "industry_info.txt";} koord3d get_weltpos(bool) OVERRIDE { return fab->get_pos(); } bool is_weltpos() OVERRIDE; /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // rotated map need new info ... void map_rotate90( sint16 ) OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_factory_info; } void highlight(vector_tpl fab_koords, bool marking); }; #endif simutrans-124.3/src/simutrans/gui/factory_chart.cc000066400000000000000000000265241474050137200223230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../obj/leitung2.h" #include "../dataobj/translator.h" #include "factory_chart.h" #define CHART_HEIGHT (90) #define MAX_GOODS_COLOR (24) static const uint8 goods_color[MAX_GOODS_COLOR] = { /* greyish blue */ 0, /* bright orange */ 33, /* cyan */ 48, /* lemon yellow */ 24, /* purple */ 57, /* greyish green */ 80, /* lilac */ 105, /* pale brown */ 89, /* blue */ COL_DARK_BLUE, /* dark green */ 161, /* dark brown */ 177, /* dark blue */ 97, /* green */ 41, /* reddish brown */ 113, /* magenta */ COL_DARK_PURPLE, /* turquoise */ 121, /* red */ 129, /* muddy yellow */ 192, /* bright green */ COL_DARK_GREEN, /* dull orange */ 65, /* pale yellow */ 167, /* pale green */ 201, /* orange */ 152, /* pale purple */ 217 }; static const char *const input_type[MAX_FAB_GOODS_STAT] = { "Storage", "Arrived", "Consumed", "In Transit" }; static const char *const output_type[MAX_FAB_GOODS_STAT] = { "Storage", "Delivered", "Produced", "In Transit" }; static const gui_chart_t::convert_proc goods_convert[MAX_FAB_GOODS_STAT] = { convert_goods, NULL, convert_goods, NULL }; static const char *const prod_type[MAX_FAB_STAT] = { "Produktion", "Usage/Output", "Electricity", "Passagiere", "Post", "Generated", "Departed", "Arrived", "Generated", "Departed", "Arrived" }; static const char *const ref_type[MAX_FAB_REF_LINE] = { "Electricity", "Passagiere", "Post", "Electricity", "Passagiere", "Post", }; static const uint8 prod_color[MAX_FAB_STAT] = { COL_LILAC, COL_LEMON_YELLOW, COL_LIGHT_GREEN, 23, COL_LIGHT_PURPLE, COL_LIGHT_TURQUOISE, 51, 49, COL_LIGHT_ORANGE, COL_ORANGE, COL_DARK_ORANGE }; static const gui_chart_t::convert_proc prod_convert[MAX_FAB_STAT] = { NULL, convert_power, convert_boost, convert_boost, convert_boost, NULL, NULL, NULL, NULL, NULL, NULL }; static const gui_chart_t::convert_proc ref_convert[MAX_FAB_REF_LINE] = { convert_boost, convert_boost, convert_boost, convert_power, NULL, NULL }; static const uint8 ref_color[MAX_FAB_REF_LINE] = { 137, COL_LIGHT_BLUE, COL_LIGHT_RED, COL_DARK_GREEN, COL_SOFT_BLUE, COL_OPERATION }; static const char *const label_text[MAX_PROD_LABEL] = { "Boost (%%)", "Max Boost (%%)", "Demand", "Passagiere", "Post", "Power (MW)" }; // Mappings from cell position to buttons, labels, charts static const uint8 prod_cell_button[] = { FAB_PRODUCTION, MAX_FAB_STAT, MAX_FAB_STAT, FAB_POWER, MAX_FAB_STAT, FAB_BOOST_ELECTRIC, FAB_BOOST_PAX, FAB_BOOST_MAIL, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, MAX_FAB_STAT, FAB_PAX_GENERATED, FAB_PAX_DEPARTED, FAB_PAX_ARRIVED, MAX_FAB_STAT, FAB_MAIL_GENERATED, FAB_MAIL_DEPARTED, FAB_MAIL_ARRIVED, }; static const uint8 prod_cell_label[] = { MAX_PROD_LABEL, MAX_PROD_LABEL, 5, MAX_PROD_LABEL, 0, MAX_PROD_LABEL, MAX_PROD_LABEL, MAX_PROD_LABEL, 1, MAX_PROD_LABEL, MAX_PROD_LABEL, MAX_PROD_LABEL, 2, MAX_PROD_LABEL, MAX_PROD_LABEL, MAX_PROD_LABEL, 3, MAX_PROD_LABEL, MAX_PROD_LABEL, MAX_PROD_LABEL, 4, MAX_PROD_LABEL, MAX_PROD_LABEL, MAX_PROD_LABEL, }; static const uint8 prod_cell_ref[] = { MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, FAB_REF_MAX_BOOST_ELECTRIC, FAB_REF_MAX_BOOST_PAX, FAB_REF_MAX_BOOST_MAIL, MAX_FAB_REF_LINE, FAB_REF_DEMAND_ELECTRIC, FAB_REF_DEMAND_PAX, FAB_REF_DEMAND_MAIL, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, MAX_FAB_REF_LINE, }; factory_chart_t::factory_chart_t(const fabrik_t *_factory) : goods_pane(&goods_cont, true, true), prod_pane(&prod_cont, true, true) { set_factory(_factory); } void factory_chart_t::set_factory(const fabrik_t *_factory) { factory = _factory; if (factory == NULL) { return; } remove_all(); goods_cont.remove_all(); prod_cont.remove_all(); button_to_chart.clear(); set_table_layout(1,0); add_component( &tab_panel ); const uint32 input_count = factory->get_input().get_count(); const uint32 output_count = factory->get_output().get_count(); if( input_count>0 || output_count>0 ) { // only add tab if there is something to display goods_cont.set_table_layout(4, 0); goods_cont.set_force_equal_columns(true); goods_cont.add_component(&goods_chart,4); // GUI components for goods input/output statistics goods_chart.set_min_size(scr_size(D_DEFAULT_WIDTH - D_MARGIN_LEFT - D_MARGIN_RIGHT, CHART_HEIGHT)); goods_chart.set_dimension(12, 10000); goods_chart.set_background(SYSCOL_CHART_BACKGROUND); uint32 count = 0; // first tab: charts for goods production/consumption if (input_count > 0) { // create table of buttons, insert curves to chart goods_cont.new_component_span("Verbrauch", 4); const array_tpl& input = factory->get_input(); for (uint32 g = 0; g < input_count; ++g) { goods_cont.new_component(input[g].get_typ()->get_name()); for (int s = 0; s < MAX_FAB_GOODS_STAT; ++s) { uint16 curve = goods_chart.add_curve(color_idx_to_rgb(goods_color[count % MAX_GOODS_COLOR] + (s * 3) / 2), input[g].get_stats(), MAX_FAB_GOODS_STAT, s, MAX_MONTH, false, false, true, 0, goods_convert[s]); button_t* b = goods_cont.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, input_type[s]); b->background_color = color_idx_to_rgb(goods_color[count % MAX_GOODS_COLOR] + (s * 3) / 2); b->pressed = false; button_to_chart.append(b, &goods_chart, curve); if ((s % 2) == 1) { // skip last cell in current row, first cell in next row goods_cont.new_component(); if (s + 1 < MAX_FAB_GOODS_STAT) { goods_cont.new_component(); } } } count++; } } if (output_count > 0) { goods_cont.new_component_span("Produktion", 4); const array_tpl& output = factory->get_output(); for (uint32 g = 0; g < output_count; ++g) { goods_cont.new_component(output[g].get_typ()->get_name()); for (int s = 0; s < 3; ++s) { uint16 curve = goods_chart.add_curve(color_idx_to_rgb(goods_color[count % MAX_GOODS_COLOR] + s * 2), output[g].get_stats(), MAX_FAB_GOODS_STAT, s, MAX_MONTH, false, false, true, 0, goods_convert[s]); button_t* b = goods_cont.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, output_type[s]); b->background_color = color_idx_to_rgb(goods_color[count % MAX_GOODS_COLOR] + s * 2); b->pressed = false; button_to_chart.append(b, &goods_chart, curve); } count++; } } goods_cont.new_component(); scr_size contsz = goods_cont.get_min_size(); if (contsz.w > display_get_width()) { tab_panel.add_tab(&goods_pane, translator::translate("Goods")); } else { tab_panel.add_tab(&goods_cont, translator::translate("Goods")); } } prod_cont.set_table_layout(1,0); prod_cont.add_component( &prod_chart ); prod_cont.add_table(4, 0)->set_force_equal_columns(true); // GUI components for other production-related statistics prod_chart.set_min_size( scr_size( D_DEFAULT_WIDTH-D_MARGIN_LEFT-D_MARGIN_RIGHT, CHART_HEIGHT ) ); prod_chart.set_dimension(12, 10000); prod_chart.set_background(SYSCOL_CHART_BACKGROUND); for( int row = 0, cell = 0; row<6; row++) { for( int col = 0; col<4; col++, cell++) { // labels if (prod_cell_label[cell] < MAX_PROD_LABEL) { prod_cont.new_component(label_text[ prod_cell_label[cell] ]); } // chart, buttons for production else if (prod_cell_button[cell] < MAX_FAB_STAT) { uint8 s = prod_cell_button[cell]; // add curve uint16 curve = prod_chart.add_curve( color_idx_to_rgb(prod_color[s]), factory->get_stats(), MAX_FAB_STAT, s, MAX_MONTH, (2<=s && s<=4) ? gui_chart_t::PERCENT : gui_chart_t::STANDARD, false, true, 0, prod_convert[s] ); // only show buttons, if the is something to do ... if( (s==FAB_BOOST_ELECTRIC && (factory->get_desc()->is_electricity_producer() || factory->get_desc()->get_electric_boost()==0)) || (s==FAB_BOOST_PAX && factory->get_desc()->get_pax_boost()==0) || (s==FAB_BOOST_MAIL && factory->get_desc()->get_mail_boost()==0) ) { prod_cont.new_component(); continue; } // add button button_t *b = prod_cont.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, prod_type[s]); b->background_color = color_idx_to_rgb(prod_color[s]); b->pressed = false; button_to_chart.append(b, &prod_chart, curve); } // chart, buttons for reference lines else if (prod_cell_ref[cell] < MAX_FAB_REF_LINE) { uint8 r = prod_cell_ref[cell]; // add curve uint16 curve = prod_chart.add_curve( color_idx_to_rgb(ref_color[r]), prod_ref_line_data + r, 0, 0, MAX_MONTH, r<3 ? gui_chart_t::PERCENT : gui_chart_t::STANDARD, false, true, 0, ref_convert[r] ); if( (r==FAB_REF_MAX_BOOST_ELECTRIC && (factory->get_desc()->is_electricity_producer() || factory->get_desc()->get_electric_boost()==0)) || (r==FAB_REF_MAX_BOOST_PAX && factory->get_desc()->get_pax_boost()==0) || (r==FAB_REF_MAX_BOOST_MAIL && factory->get_desc()->get_mail_boost()==0) || (r==FAB_REF_DEMAND_ELECTRIC && (factory->get_desc()->is_electricity_producer() || factory->get_desc()->get_electric_demand()==0)) || (r==FAB_REF_DEMAND_PAX && factory->get_desc()->get_pax_demand()==0) || (r==FAB_REF_DEMAND_MAIL && factory->get_desc()->get_mail_demand()==0) ) { prod_cont.new_component(); continue; } // add button button_t *b = prod_cont.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, ref_type[r]); b->background_color = color_idx_to_rgb(ref_color[r]); b->pressed = false; button_to_chart.append(b, &prod_chart, curve); } else { prod_cont.new_component(); } } } prod_cont.end_table(); prod_cont.new_component(); scr_size sz = prod_cont.get_min_size(); if (sz.w > display_get_width()) { tab_panel.add_tab(&prod_pane, translator::translate("Production/Boost")); } else { tab_panel.add_tab(&prod_cont, translator::translate("Production/Boost")); } set_size(get_min_size()); // initialize reference lines' data (these do not change over time) prod_ref_line_data[FAB_REF_MAX_BOOST_ELECTRIC] = factory->get_desc()->get_electric_boost(); prod_ref_line_data[FAB_REF_MAX_BOOST_PAX] = factory->get_desc()->get_pax_boost(); prod_ref_line_data[FAB_REF_MAX_BOOST_MAIL] = factory->get_desc()->get_mail_boost(); } factory_chart_t::~factory_chart_t() { button_to_chart.clear(); } void factory_chart_t::update() { // update reference lines' data (these might change over time) prod_ref_line_data[FAB_REF_DEMAND_ELECTRIC] = ( factory->get_desc()->is_electricity_producer() ? 0 : factory->get_scaled_electric_demand() ); prod_ref_line_data[FAB_REF_DEMAND_PAX] = factory->get_scaled_pax_demand(); prod_ref_line_data[FAB_REF_DEMAND_MAIL] = factory->get_scaled_mail_demand(); } void factory_chart_t::rdwr( loadsave_t *file ) { // button-to-chart array button_to_chart.rdwr(file); } simutrans-124.3/src/simutrans/gui/factory_chart.h000066400000000000000000000030311474050137200221510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_FACTORY_CHART_H #define GUI_FACTORY_CHART_H #define MAX_PROD_LABEL (7-1) #include "../simfab.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_label.h" #include "components/gui_button.h" #include "components/gui_button_to_chart.h" #include "components/gui_chart.h" #include "components/gui_tab_panel.h" #include "components/gui_aligned_container.h" #include "components/gui_button_to_chart.h" #include "components/gui_scrollpane.h" class factory_chart_t : public gui_aligned_container_t { private: const fabrik_t *factory; // Tab panel for grouping 2 sets of statistics gui_tab_panel_t tab_panel; // GUI components for input/output goods' statistics gui_aligned_container_t goods_cont; gui_chart_t goods_chart; // GUI components for other production-related statistics gui_aligned_container_t prod_cont; gui_chart_t prod_chart; // use only if dialog too wide for screen gui_scrollpane_t goods_pane, prod_pane; // Variables for reference lines sint64 prod_ref_line_data[MAX_FAB_REF_LINE]; gui_button_to_chart_array_t button_to_chart; public: factory_chart_t(const fabrik_t *_factory); virtual ~factory_chart_t(); void set_factory(const fabrik_t *_factory); void update(); void rdwr( loadsave_t *file ); /** * factory window will take our tabs, * we only initialize them and update charts */ gui_tab_panel_t* get_tab_panel() { return &tab_panel; } }; #endif simutrans-124.3/src/simutrans/gui/factory_edit.cc000066400000000000000000000355451474050137200221520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "../tool/simtool.h" #include "../builder/fabrikbauer.h" #include "../descriptor/ground_desc.h" #include "../descriptor/intro_dates.h" #include "../descriptor/factory_desc.h" #include "../dataobj/translator.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "factory_edit.h" #include "components/gui_label.h" // new tool definition tool_build_land_chain_t factory_edit_frame_t::land_chain_tool = tool_build_land_chain_t(); tool_city_chain_t factory_edit_frame_t::city_chain_tool = tool_city_chain_t(); tool_build_factory_t factory_edit_frame_t::fab_tool = tool_build_factory_t(); cbuffer_t factory_edit_frame_t::param_str; bool factory_edit_frame_t::sortreverse = false; static bool compare_factory_desc(const factory_desc_t* a, const factory_desc_t* b) { int diff = strcmp( a->get_name(), b->get_name() ); return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_name(const factory_desc_t* a, const factory_desc_t* b) { int diff = strcmp( translator::translate(a->get_name()), translator::translate(b->get_name()) ); if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_level_pax(const factory_desc_t* a, const factory_desc_t* b) { int diff = (a->get_pax_demand() != 65535 ? a->get_pax_demand() : a->get_pax_level()) -(b->get_pax_demand() != 65535 ? b->get_pax_demand() : b->get_pax_level()); if ( diff == 0 ) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_level_mail(const factory_desc_t* a, const factory_desc_t* b) { int diff = (a->get_mail_demand() != 65535 ? a->get_mail_demand() : a->get_pax_level()>>2) -(b->get_mail_demand() != 65535 ? b->get_mail_demand() : b->get_pax_level()>>2); if ( diff == 0 ) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_date_intro(const factory_desc_t* a, const factory_desc_t* b) { int diff = a->get_building()->get_intro_year_month() - b->get_building()->get_intro_year_month(); if ( diff == 0) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_date_retire(const factory_desc_t* a, const factory_desc_t* b) { int diff = a->get_building()->get_retire_year_month() - b->get_building()->get_retire_year_month(); if ( diff == 0) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_size(const factory_desc_t* a, const factory_desc_t* b) { koord a_koord = a->get_building()->get_size(); koord b_koord = b->get_building()->get_size(); int diff = a_koord.x * a_koord.y - b_koord.x * b_koord.y; if( diff==0 ) { //same area - sort by side to seperate different shapes diff = a_koord.x - b_koord.x; } if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_factory_desc_goods_number(const factory_desc_t* a, const factory_desc_t* b) { int diff = a->get_product_count() - b->get_product_count(); if( diff==0 ) { //same number of products - go by number of required goods diff = a->get_supplier_count() - b->get_supplier_count(); } if( diff==0 ) { diff = strcmp(a->get_name(), b->get_name()); } return factory_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } factory_edit_frame_t::factory_edit_frame_t(player_t* player_) : extend_edit_gui_t(translator::translate("factorybuilder"), player_), factory_list(16) { land_chain_tool.cursor = city_chain_tool.cursor = fab_tool.cursor = tool_t::general_tool[TOOL_BUILD_FACTORY]->cursor; fac_desc = NULL; bt_city_chain.init( button_t::square_state, "Only city chains"); bt_city_chain.add_listener(this); cont_filter.add_component(&bt_city_chain,3); bt_land_chain.init( button_t::square_state, "Only land chains"); bt_land_chain.add_listener(this); cont_filter.add_component(&bt_land_chain,3); // add water to climate selection cb_climates.new_component(climate::water_climate); // add to sorting selection cb_sortedby.new_component(gui_sorting_item_t::BY_LEVEL_PAX); cb_sortedby.new_component(gui_sorting_item_t::BY_LEVEL_MAIL); cb_sortedby.new_component(gui_sorting_item_t::BY_DATE_INTRO); cb_sortedby.new_component(gui_sorting_item_t::BY_DATE_RETIRE); cb_sortedby.new_component(gui_sorting_item_t::BY_SIZE); cb_sortedby.new_component(gui_sorting_item_t::BY_GOODS_NUMBER); // rotation, production gui_aligned_container_t *tbl = cont_options.add_table(2,2); tbl->new_component("Rotation"); tbl->add_component(&cb_rotation); cb_rotation.add_listener(this); cb_rotation.new_component(translator::translate("random"), SYSCOL_TEXT) ; tbl->new_component("Produktion"); inp_production.set_limits(0,9999); inp_production.add_listener( this ); tbl->add_component(&inp_production); cont_options.end_table(); fill_list(); reset_min_windowsize(); } // fill the current factory_list void factory_edit_frame_t::fill_list() { const bool allow_obsolete = bt_obsolete.pressed; const bool use_timeline = bt_timeline.pressed | bt_timeline_custom.pressed; const bool city_chain = bt_city_chain.pressed; const bool land_chain = bt_land_chain.pressed; const sint32 month_now = bt_timeline.pressed ? welt->get_current_month() : bt_timeline_custom.pressed ? ni_timeline_year.get_value()*12 + ni_timeline_month.get_value()-1 : 0; const uint8 sortedby = get_sortedby(); sortreverse = sort_order.pressed; factory_list.clear(); // timeline will be obeyed; however, we may show obsolete ones ... for(auto const& i : factory_builder_t::get_factory_table()) { factory_desc_t const* const desc = i.value; if(desc->get_distribution_weight()>0) { // DistributionWeight=0 is obsoleted item, only for backward compatibility if( (!use_timeline || (!desc->get_building()->is_future(month_now) && (!desc->get_building()->is_retired(month_now) || allow_obsolete))) && ( desc->get_building()->get_allowed_climate_bits() & get_climate()) ) { // timeline allows for this, and so does climates setting if( ( city_chain && (desc->get_placement() == factory_desc_t::City && desc->is_consumer_only() ) ) || ( land_chain && (desc->get_placement() != factory_desc_t::City && desc->is_consumer_only() ) ) || (!city_chain && !land_chain) ) { switch(sortedby) { case gui_sorting_item_t::BY_NAME_TRANSLATED: factory_list.insert_ordered( desc, compare_factory_desc_name ); break; case gui_sorting_item_t::BY_LEVEL_PAX: factory_list.insert_ordered( desc, compare_factory_desc_level_pax ); break; case gui_sorting_item_t::BY_LEVEL_MAIL: factory_list.insert_ordered( desc, compare_factory_desc_level_mail ); break; case gui_sorting_item_t::BY_DATE_INTRO: factory_list.insert_ordered( desc, compare_factory_desc_date_intro ); break; case gui_sorting_item_t::BY_DATE_RETIRE: factory_list.insert_ordered( desc, compare_factory_desc_date_retire ); break; case gui_sorting_item_t::BY_SIZE: factory_list.insert_ordered( desc, compare_factory_desc_size ); break; case gui_sorting_item_t::BY_GOODS_NUMBER: factory_list.insert_ordered( desc, compare_factory_desc_goods_number ); break; default: factory_list.insert_ordered( desc, compare_factory_desc ); } } } } } // now build scrolled list scl.clear_elements(); scl.set_selection(-1); for(factory_desc_t const* const i : factory_list) { PIXVAL const color = i->is_consumer_only() ? color_idx_to_rgb(COL_DARK_BLUE + env_t::gui_player_color_dark) : i->is_producer_only() ? color_idx_to_rgb(40 + env_t::gui_player_color_dark) : SYSCOL_TEXT; char const* const name = get_sortedby()==gui_sorting_item_t::BY_NAME_OBJECT ? i->get_name() : translator::translate(i->get_name()); scl.new_component(name, color); if (i == fac_desc) { scl.set_selection(scl.get_count()-1); } } // always update current selection (since the tool may depend on it) change_item_info( scl.get_selection() ); reset_min_windowsize(); } bool factory_edit_frame_t::action_triggered( gui_action_creator_t *comp,value_t e) { // only one chain can be shown if( comp==&bt_city_chain ) { bt_city_chain.pressed ^= 1; if(bt_city_chain.pressed) { bt_land_chain.pressed = 0; } fill_list(); } else if( comp==&bt_land_chain ) { bt_land_chain.pressed ^= 1; if(bt_land_chain.pressed) { bt_city_chain.pressed = 0; } fill_list(); } else if( comp == &cb_rotation) { change_item_info( scl.get_selection() ); } else if(fac_desc) { if (comp==&inp_production) { production = inp_production.get_value(); } // update info ... change_item_info( scl.get_selection() ); } return extend_edit_gui_t::action_triggered(comp,e); } void factory_edit_frame_t::change_item_info(sint32 entry) { if(entry>=0 && entry<(sint32)factory_list.get_count()) { const factory_desc_t *new_fac_desc = factory_list[entry]; if(new_fac_desc!=fac_desc) { fac_desc = new_fac_desc; production = fac_desc->get_productivity() + sim_async_rand( fac_desc->get_range() ); // should also consider the effects of the minimum number of fields const field_group_desc_t *const field_group_desc = fac_desc->get_field_group(); if( field_group_desc && field_group_desc->get_field_class_count()>0 ) { const weighted_vector_tpl &field_class_indices = field_group_desc->get_field_class_indices(); sint32 min_fields = field_group_desc->get_min_fields(); while( min_fields-- > 0 ) { const uint16 field_class_index = field_class_indices.at_weight( sim_async_rand( field_class_indices.get_sum_weight() ) ); production += field_group_desc->get_field_class(field_class_index)->get_field_production(); } } production = welt->scale_with_month_length(production); inp_production.set_value( production); // show produced goods buf.clear(); if (!fac_desc->is_consumer_only()) { buf.append( translator::translate("Produktion") ); buf.append("\n"); for (uint i = 0; i < fac_desc->get_product_count(); i++) { buf.append(" - "); buf.append( translator::translate(fac_desc->get_product(i)->get_output_type()->get_name()) ); buf.append( " (" ); buf.append( translator::translate(fac_desc->get_product(i)->get_output_type()->get_catg_name()) ); buf.append( ")\n" ); } buf.append("\n"); } // show consumed goods if (!fac_desc->is_producer_only()) { buf.append( translator::translate("Verbrauch") ); buf.append("\n"); for( int i=0; iget_supplier_count(); i++ ) { buf.append(" - "); buf.append( translator::translate(fac_desc->get_supplier(i)->get_input_type()->get_name()) ); buf.append( " (" ); buf.append( translator::translate(fac_desc->get_supplier(i)->get_input_type()->get_catg_name()) ); buf.append( ")\n" ); } buf.append("\n"); } if(fac_desc->is_electricity_producer()) { buf.append( translator::translate( "Electricity producer\n\n" ) ); } // now the house stuff const building_desc_t *desc = fac_desc->get_building(); // climates buf.append( translator::translate("allowed climates:\n") ); uint16 cl = desc->get_allowed_climate_bits(); if(cl==0) { buf.append( translator::translate("none") ); buf.append("\n"); } else { for(uint16 i=0; i<=arctic_climate; i++ ) { if(cl & (1<> 2); buf.printf("%s%u", translator::translate("\nBauzeit von"), desc->get_intro_year_month() / 12); if(desc->get_retire_year_month()!=DEFAULT_RETIRE_DATE*12) { buf.printf("%s%u", translator::translate("\nBauzeit bis"), desc->get_retire_year_month() / 12); } if (char const* const maker = desc->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); } buf.append("\n"); // reset combobox cb_rotation.clear_elements(); cb_rotation.new_component(gui_rotation_item_t::random); for(uint8 i = 0; iget_all_layouts(); i++) { cb_rotation.new_component(i); } // orientation (255=random) if(desc->get_all_layouts()>1) { cb_rotation.set_selection(0); } else { cb_rotation.set_selection(1); } // now for the tool fac_desc = factory_list[entry]; } const building_desc_t *desc = fac_desc->get_building(); uint8 rotation = get_rotation(); uint8 rot = (rotation==255) ? 0 : rotation; building_image.init(desc, rot); // the tools will be always updated, even though the data up there might be still current param_str.clear(); param_str.printf("%i%c%i,%s", bt_climates.pressed, rotation==255 ? '#' : '0'+rotation, production, fac_desc->get_name() ); if(bt_land_chain.pressed) { land_chain_tool.set_default_param(param_str); welt->set_tool( &land_chain_tool, player ); } else if(bt_city_chain.pressed) { city_chain_tool.set_default_param(param_str); welt->set_tool( &city_chain_tool, player ); } else { fab_tool.set_default_param(param_str); welt->set_tool( &fab_tool, player ); } } else if(fac_desc!=NULL) { cb_rotation.clear_elements(); cb_rotation.new_component(gui_rotation_item_t::random); building_image.init(NULL, 0); fac_desc = NULL; welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); buf.clear(); } info_text.recalc_size(); reset_min_windowsize(); } void factory_edit_frame_t::set_windowsize(scr_size size) { extend_edit_gui_t::set_windowsize(size); // manually set width of cb_rotation and inp_production scr_size cbs = cb_rotation.get_size(); scr_size nis = inp_production.get_size(); scr_coord_val w = max(cbs.w, nis.w); cb_rotation.set_size(scr_size(w, cbs.h)); inp_production.set_size(scr_size(w, nis.h)); } simutrans-124.3/src/simutrans/gui/factory_edit.h000066400000000000000000000026421474050137200220040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_FACTORY_EDIT_H #define GUI_FACTORY_EDIT_H #include "extend_edit.h" #include "components/gui_numberinput.h" #include "../utils/cbuffer.h" class factory_desc_t; class tool_build_land_chain_t; class tool_city_chain_t; class tool_build_factory_t; /* * Factories builder dialog */ class factory_edit_frame_t : public extend_edit_gui_t { private: static tool_build_land_chain_t land_chain_tool; static tool_city_chain_t city_chain_tool; static tool_build_factory_t fab_tool; static cbuffer_t param_str; const factory_desc_t *fac_desc; uint32 production; vector_tplfactory_list; button_t bt_city_chain; button_t bt_land_chain; gui_numberinput_t inp_production; void fill_list() OVERRIDE; void change_item_info( sint32 i ) OVERRIDE; public: factory_edit_frame_t(player_t* player); static bool sortreverse; /** * in top-level windows the name is displayed in titlebar * @return the non-translated component name */ const char* get_name() const { return "factorybuilder"; } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char* get_help_filename() const OVERRIDE { return "factory_build.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void set_windowsize(scr_size size) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/factorylist_frame.cc000066400000000000000000000114761474050137200232100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "factorylist_frame.h" #include "gui_theme.h" #include "../dataobj/translator.h" #include "../player/simplay.h" #include "../world/simworld.h" #include "../dataobj/environment.h" #include "../utils/unicode.h" char factorylist_frame_t::name_filter[256]; const char *factorylist_frame_t::sort_text[factorylist::SORT_MODES] = { "Fabrikname", "Input", "Output", "Produktion", "Rating", "Power" }; class playername_const_scroll_item_t : public gui_scrolled_list_t::const_text_scrollitem_t { public: const uint8 player_nr; playername_const_scroll_item_t( player_t *pl ) : gui_scrolled_list_t::const_text_scrollitem_t( pl->get_name(), color_idx_to_rgb(pl->get_player_color1()+env_t::gui_player_color_dark) ), player_nr(pl->get_player_nr()) { } }; factorylist_frame_t::factorylist_frame_t() : gui_frame_t( translator::translate("fl_title") ), scrolly(gui_scrolled_list_t::windowskin, factorylist_stats_t::compare) { scrolly.set_checkered(true); set_table_layout(3,4); new_component("Filter:"); name_filter_input.set_text(name_filter, lengthof(name_filter)); name_filter_input.set_notify_all_changes_delay(0); name_filter_input.add_listener(this); add_component(&name_filter_input); new_component(); filter_by_owner.init(button_t::square_automatic, "Served by"); filter_by_owner.add_listener(this); filter_by_owner.set_tooltip("At least one tile is connected to one stop."); add_component(&filter_by_owner); filterowner.new_component(translator::translate("No player"), SYSCOL_TEXT); for (int i = 0; i < MAX_PLAYER_COUNT; i++) { if (player_t* pl = welt->get_player(i)) { filterowner.new_component(pl); if (pl == welt->get_active_player()) { filterowner.set_selection(filterowner.count_elements() - 1); } } } filterowner.add_listener(this); add_component(&filterowner); new_component(); new_component("hl_txt_sort"); sortedby.set_unsorted(); // do not sort for (size_t i = 0; i < lengthof(sort_text); i++) { sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); } sortedby.set_selection(factorylist_stats_t::sort_mode); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_state, NULL); sorteddir.add_listener(this); sorteddir.pressed = factorylist_stats_t::reverse; add_component(&sorteddir); add_component(&scrolly,3); scrolly.set_maximize(true); fill_list(); set_resizemode(diagonal_resize); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool factorylist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) { if (comp == &sortedby) { factorylist_stats_t::sort_mode = v.i; scrolly.sort(0); } else if (comp == &sorteddir) { factorylist_stats_t::reverse = !factorylist_stats_t::reverse; sorteddir.pressed = factorylist_stats_t::reverse; scrolly.sort(0); } else if(comp == &filterowner) { if( filter_by_owner.pressed ) { fill_list(); } } else if (comp == &filter_by_owner) { fill_list(); } else if (comp == &name_filter_input) { fill_list(); } return true; } void factorylist_frame_t::fill_list() { old_factories_count = world()->get_fab_list().get_count(); // to avoid too many redraws ... scrolly.clear_elements(); if (filter_by_owner.pressed && filterowner.get_selection() == 0) { for(fabrik_t* fab : world()->get_fab_list()) { bool add = (name_filter[0] == 0 || utf8caseutf8(fab->get_name(), name_filter)); for( int i = 0; add && i < MAX_PLAYER_COUNT; i++ ) { if( player_t* pl = welt->get_player(i) ) { if (fab->is_within_players_network(pl)) { // already connected add = false; } } } if (add) { scrolly.new_component(fab); } } } else { player_t* pl = (filter_by_owner.pressed && filterowner.get_selection() >= 1) ? welt->get_player(((const playername_const_scroll_item_t*)(filterowner.get_selected_item()))->player_nr) : NULL; for(fabrik_t * fab : world()->get_fab_list()) { if( pl == NULL || fab->is_within_players_network( pl ) ) { if( name_filter[0] == 0 || utf8caseutf8(fab->get_name(), name_filter)) { scrolly.new_component( fab ); } } } } scrolly.sort(0); scrolly.set_size(scr_size(get_windowsize().w, scrolly.get_size().h)); } void factorylist_frame_t::rdwr(loadsave_t* file) { scr_size size = get_windowsize(); size.rdwr(file); scrolly.rdwr(file); file->rdwr_str(name_filter, lengthof(name_filter)); file->rdwr_short(factorylist_stats_t::sort_mode); file->rdwr_bool(factorylist_stats_t::reverse); if (file->is_loading()) { fill_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/factorylist_frame.h000066400000000000000000000023001474050137200230340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_FACTORYLIST_FRAME_H #define GUI_FACTORYLIST_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "components/gui_scrollpane.h" #include "components/gui_label.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "factorylist_stats.h" /* * Factory list window */ class factorylist_frame_t : public gui_frame_t, private action_listener_t { private: static const char *sort_text[factorylist::SORT_MODES]; gui_combobox_t sortedby; button_t sorteddir; button_t filter_by_owner; gui_combobox_t filterowner; gui_scrolled_list_t scrolly; static char name_filter[256]; gui_textinput_t name_filter_input; uint32 old_factories_count; public: factorylist_frame_t(); // can be called externally when open or crash! void fill_list(); const char *get_help_filename() const OVERRIDE {return "factorylist_filter.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE { fill_list(); } void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_factorylist; } }; #endif simutrans-124.3/src/simutrans/gui/factorylist_stats.cc000066400000000000000000000117051474050137200232470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "factorylist_stats.h" #include "../simskin.h" #include "../simfab.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "../builder/goods_manager.h" #include "../descriptor/skin_desc.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" sint16 factorylist_stats_t::sort_mode = factorylist::by_name; bool factorylist_stats_t::reverse = false; factorylist_stats_t::factorylist_stats_t(fabrik_t *fab) { this->fab = fab; // pos button set_table_layout(0,1); button_t *b = new_component(); b->set_typ(button_t::posbutton_automatic); b->set_targetpos3d(fab->get_pos()); // indicator bar add_component(&indicator); indicator.set_max_size(scr_size(D_INDICATOR_WIDTH,D_INDICATOR_HEIGHT)); // boost images if (fab->get_desc()->get_electric_boost() ) { boost_electric.set_image(skinverwaltung_t::electricity->get_image_id(0), true); add_component(&boost_electric); } if (fab->get_desc()->get_pax_boost() ) { boost_passenger.set_image(skinverwaltung_t::passengers->get_image_id(0), true); add_component(&boost_passenger); } if (fab->get_desc()->get_mail_boost() ) { boost_mail.set_image(skinverwaltung_t::mail->get_image_id(0), true); add_component(&boost_mail); } // factory name update_label(); add_component(&label); } void factorylist_stats_t::update_label() { cbuffer_t &buf = label.buf(); buf.append(fab->get_name()); buf.append(" ("); if (!fab->get_input().empty()) { buf.printf( "%i+%i", fab->get_total_in(), fab->get_total_transit() ); } else { buf.append("-"); } buf.append(", "); if (!fab->get_output().empty()) { buf.append(fab->get_total_out(),0); } else { buf.append("-"); } buf.append(", "); buf.append(fab->get_current_production(),0); buf.append(") "); label.update(); } bool factorylist_stats_t::is_valid() const { return world()->get_fab_list().is_contained(fab); } bool factorylist_stats_t::infowin_event(const event_t * ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if (!swallowed) { // either open dialog or goto (with control or right click) if (IS_LEFTRELEASE(ev)) { if ((event_get_last_control_shift() ^ tool_t::control_invert) == 2) { world()->get_viewport()->change_world_position(fab->get_pos()); } else { fab->open_info_window(); } return true; } if (IS_RIGHTRELEASE(ev)) { world()->get_viewport()->change_world_position(fab->get_pos()); return true; } } return swallowed; } void factorylist_stats_t::draw(scr_coord pos) { update_label(); // boost stuff boost_electric.set_transparent(fab->get_prodfactor_electric()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); boost_passenger.set_transparent(fab->get_prodfactor_pax()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); boost_mail.set_transparent(fab->get_prodfactor_mail()>0 ? 0 : TRANSPARENT50_FLAG | OUTLINE_FLAG | SYSCOL_IMAGE_TRANSPARENCY); indicator.set_color( color_idx_to_rgb(fabrik_t::status_to_color[fab->get_status()]) ); gui_aligned_container_t::draw(pos); } bool factorylist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb) { const factorylist_stats_t* fa = dynamic_cast(aa); const factorylist_stats_t* fb = dynamic_cast(bb); // good luck with mixed lists assert(fa != NULL && fb != NULL); fabrik_t *a=fa->fab, *b=fb->fab; int cmp; switch (sort_mode) { default: case factorylist::by_name: cmp = 0; break; case factorylist::by_input: { int a_in = a->get_input().empty() ? -1 : (int)a->get_total_in(); int b_in = b->get_input().empty() ? -1 : (int)b->get_total_in(); cmp = a_in - b_in; break; } case factorylist::by_transit: { int a_transit = a->get_input().empty() ? -1 : (int)a->get_total_transit(); int b_transit = b->get_input().empty() ? -1 : (int)b->get_total_transit(); cmp = a_transit - b_transit; break; } case factorylist::by_available: { int a_in = a->get_input().empty() ? -1 : (int)(a->get_total_in()+a->get_total_transit()); int b_in = b->get_input().empty() ? -1 : (int)(b->get_total_in()+b->get_total_transit()); cmp = a_in - b_in; break; } case factorylist::by_output: { int a_out = a->get_output().empty() ? -1 : (int)a->get_total_out(); int b_out = b->get_output().empty() ? -1 : (int)b->get_total_out(); cmp = a_out - b_out; break; } case factorylist::by_maxprod: cmp = a->get_base_production()*a->get_prodfactor() - b->get_base_production()*b->get_prodfactor(); break; case factorylist::by_status: cmp = a->get_status() - b->get_status(); break; case factorylist::by_power: cmp = a->get_prodfactor_electric() - b->get_prodfactor_electric(); break; } if (cmp == 0) { cmp = STRICMP(a->get_name(), b->get_name()); } return reverse ? cmp > 0 : cmp < 0; } simutrans-124.3/src/simutrans/gui/factorylist_stats.h000066400000000000000000000023771474050137200231160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_FACTORYLIST_STATS_H #define GUI_FACTORYLIST_STATS_H #include "components/gui_colorbox.h" #include "components/gui_image.h" #include "components/gui_label.h" #include "components/gui_scrolled_list.h" #include "../simfab.h" class fabrik_t; namespace factorylist { enum sort_mode_t { by_name = 0, by_available, by_output, by_maxprod, by_status, by_power, SORT_MODES, // the last two are unused by_input, by_transit }; }; /** * Factory list stats display * Where factory stats are calculated for list dialog */ class factorylist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: fabrik_t *fab; gui_colorbox_t indicator; gui_image_t boost_electric, boost_passenger, boost_mail; gui_label_buf_t label; void update_label(); public: static sint16 sort_mode; static bool reverse; factorylist_stats_t(fabrik_t *); void draw( scr_coord pos) OVERRIDE; char const* get_text() const OVERRIDE { return fab->get_name(); } bool infowin_event(const event_t *) OVERRIDE; bool is_valid() const OVERRIDE; static bool compare(const gui_component_t *a, const gui_component_t *b ); }; #endif simutrans-124.3/src/simutrans/gui/goods_frame.cc000066400000000000000000000234671474050137200217630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "goods_frame.h" #include "components/gui_scrollpane.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../descriptor/goods_desc.h" #include "../dataobj/translator.h" #include "../simcolor.h" #include "simwin.h" #include "../world/simworld.h" sint32 goods_frame_t::selected_speed = 1; bool goods_frame_t::average_selection = true; goods_frame_t::sort_mode_t goods_frame_t::sortby = unsortiert; bool goods_frame_t::sortreverse = false; const char *goods_frame_t::sort_text[SORT_MODES] = { "gl_btn_unsort", "gl_btn_sort_name", "gl_btn_sort_revenue", "gl_btn_sort_bonus", "gl_btn_sort_catg" }; bool goods_frame_t::filter_goods = false; simline_t::linetype goods_frame_t::last_scheduletype = simline_t::trainline; goods_frame_t::goods_frame_t() : gui_frame_t( translator::translate("gl_title") ), speed_text( &speed_message), goods_stats(), scrolly(&goods_stats) { set_table_layout(1,0); // top line: combo, input, text add_table(3,1); { build_linetype_list(filter_goods); add_component(&scheduletype); scheduletype.add_listener( this ); speed.init(1, 1, 1, gui_numberinput_t::AUTOLINEAR, false); if (average_selection) { selected_speed = welt->get_average_speed(simline_t::linetype_to_waytype(last_scheduletype)); } set_linetype(last_scheduletype, selected_speed); add_component(&speed); speed.add_listener( this ); gui_label_buf_t *lb = new_component(SYSCOL_TEXT_HIGHLIGHT); lb->buf().printf(translator::translate("100 km/h = %i tiles/month"), welt->speed_to_tiles_per_month(kmh_to_speed(100)) ); lb->update(); } end_table(); add_component(&speed_text); filter_goods_toggle.init(button_t::square_state, "Show only used"); filter_goods_toggle.set_tooltip(translator::translate("Only show goods which are currently handled by factories")); filter_goods_toggle.add_listener(this); filter_goods_toggle.pressed = filter_goods; add_component(&filter_goods_toggle); // sort mode sort_row = add_table(3,1); { new_component("hl_txt_sort"); sortedby.set_unsorted(); // do not sort for (size_t i = 0; i < lengthof(sort_text); i++) { sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); } sortedby.set_selection(sortby); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_state, ""); sorteddir.pressed = sortreverse; sorteddir.add_listener(this); add_component(&sorteddir); } end_table(); add_component(&scrolly); scrolly.set_maximize(true); sort_list(); reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(diagonal_resize); } void goods_frame_t::build_linetype_list(bool const show_used) { // build combobox list scheduletype.enable(); scheduletype.clear_elements(); size_t item_count = 0; for (int i = 1; i < simline_t::MAX_LINE_TYPE; i++) { simline_t::linetype const linetype = (simline_t::linetype)i; waytype_t const waytype = simline_t::linetype_to_waytype(linetype); sint32 const maximum_speed = vehicle_builder_t::get_fastest_vehicle_speed(waytype, welt->get_current_month(), welt->get_settings().get_use_timeline() && show_used, welt->get_settings().get_allow_buying_obsolete_vehicles()); if (!show_used || maximum_speed > 0) { scheduletype.new_component(simline_t::get_linetype_name(linetype), SYSCOL_TEXT); linetype_selection_map[item_count] = linetype; item_count+= 1; } } if (item_count == 0) { // no vehicles found, eg due to unsupported date or incomplete pakset if (show_used) { build_linetype_list(false); } scheduletype.disable(); } // select schedule type bool selected = false; for (size_t index = 0 ; index < item_count ; index++) { if (linetype_selection_map[index] == last_scheduletype) { scheduletype.set_selection((int)index); selected = true; break; } } if (!selected && item_count > 0) { scheduletype.set_selection(0); set_linetype(linetype_selection_map[0]); } } bool goods_frame_t::compare_goods(goods_desc_t const* const w1, goods_desc_t const* const w2) { int order = 0; switch (sortby) { case 0: // sort by number order = w1->get_index() - w2->get_index(); break; case 2: // sort by revenue { const sint16 relative_speed_change = (100*selected_speed)/welt->get_average_speed(simline_t::linetype_to_waytype(last_scheduletype)); const sint32 grundwert1281 = w1->get_value() * goods_frame_t::welt->get_settings().get_bonus_basefactor(); const sint32 grundwert1282 = w2->get_value() * goods_frame_t::welt->get_settings().get_bonus_basefactor(); const sint32 grundwert_bonus1 = w1->get_value()*(1000l+(relative_speed_change-100l)*w1->get_speed_bonus()); const sint32 grundwert_bonus2 = w2->get_value()*(1000l+(relative_speed_change-100l)*w2->get_speed_bonus()); const sint32 price1 = (grundwert1281>grundwert_bonus1 ? grundwert1281 : grundwert_bonus1); const sint32 price2 = (grundwert1282>grundwert_bonus2 ? grundwert1282 : grundwert_bonus2); order = price1-price2; } break; case 3: // sort by speed bonus order = w1->get_speed_bonus()-w2->get_speed_bonus(); break; case 4: // sort by catg_index order = w1->get_catg()-w2->get_catg(); break; default: ; // make compiler happy, order will be determined below anyway } if( order==0 ) { // sort by name if not sorted or not unique order = strcmp(translator::translate(w1->get_name()), translator::translate(w2->get_name())); } return sortreverse ? order > 0 : order < 0; } void goods_frame_t::set_linetype(simline_t::linetype const linetype, sint32 const speed_value) { waytype_t const waytype = simline_t::linetype_to_waytype(linetype); sint32 const average_speed = welt->get_average_speed(waytype); sint32 new_value = speed_value; if (new_value == 0) { double const relative_speed_change = speed.get_value() / (double)welt->get_average_speed(simline_t::linetype_to_waytype(last_scheduletype)); new_value = (sint32)(average_speed * relative_speed_change + 0.5); } sint32 const maximum_speed = vehicle_builder_t::get_fastest_vehicle_speed(waytype, welt->get_current_month(), welt->get_settings().get_use_timeline(), welt->get_settings().get_allow_buying_obsolete_vehicles()); if (maximum_speed > 0) { speed.enable(); speed.set_limits(1, maximum_speed); } else { speed.disable(); speed.set_limits(new_value, new_value); } speed.set_value(new_value); selected_speed = new_value; average_selection = new_value == average_speed; if (last_scheduletype != linetype) { for (size_t index = 0 ; index < simline_t::MAX_LINE_TYPE ; index++) { if (linetype_selection_map[index] == linetype) { scheduletype.set_selection((int)index); break; } } } last_scheduletype = linetype; } // creates the list and pass it to the child function good_stats, which does the display stuff ... void goods_frame_t::sort_list() { sint32 const average_speed = welt->get_average_speed(simline_t::linetype_to_waytype(last_scheduletype)); // update all strings speed_message.clear(); speed_message.printf(translator::translate("Bonus Speed: %i km/h"), average_speed ); speed_message.append("\n"); speed_message.printf(translator::translate("Bonus Multiplier: %i%%"), (int)(100.0 * 10.0 * (((double)selected_speed / (double)average_speed) - 1.0)) ); speed_message.append("\n"); if (!speed.enabled()) { speed_message.append(translator::translate("No vehicles are available for purchase.")); } if (speed_text.get_min_size().h > speed_text.get_size().h) { resize(scr_coord(0,0)); } // update buttons sortedby.set_selection(sortby); sorteddir.pressed = sortreverse; filter_goods_toggle.pressed = filter_goods; sort_row->set_size(sort_row->get_min_size()); // now prepare the sort // Fetch the list of goods produced by the factories that exist in the current game const vector_tpl &goods_in_game = welt->get_goods_list(); good_list.clear(); for(unsigned int i=0; iget_value()!=0 && (!filter_goods || goods_in_game.is_contained(wtyp)) ) { good_list.insert_ordered( wtyp, compare_goods ); } } goods_stats.update_goodslist( good_list, (100 * selected_speed) / average_speed); } /** * This method is called if an action is triggered */ bool goods_frame_t::action_triggered( gui_action_creator_t *comp,value_t p) { if(comp == &sortedby) { // sort by what sortby = (goods_frame_t::sort_mode_t)p.i; } else if(comp == &sorteddir) { // order sortreverse ^= 1; } else if(comp == &filter_goods_toggle) { filter_goods = !filter_goods; build_linetype_list(filter_goods); } else if(comp == &scheduletype) { set_linetype(linetype_selection_map[scheduletype.get_selection()]); } else if(comp == &speed) { set_linetype(last_scheduletype, speed.get_value()); } sort_list(); return true; } uint32 goods_frame_t::get_rdwr_id() { return magic_goodslist; } void goods_frame_t::rdwr( loadsave_t *file ) { // This used to be realitive speed in percentage but is now absolute speed in km/h. sint16 saved_speed = (sint16)std::min(selected_speed, (sint32)std::numeric_limits::max()); file->rdwr_short( saved_speed ); file->rdwr_bool( sortreverse ); file->rdwr_bool( filter_goods ); sint16 s = last_scheduletype; file->rdwr_short( s ); sint16 b = sortby; file->rdwr_short( b ); if( file->is_loading() ) { build_linetype_list(filter_goods); if(saved_speed < 1) { saved_speed = 1; } set_linetype((simline_t::linetype)s, saved_speed); sortby = (sort_mode_t)b; sort_list(); } } simutrans-124.3/src/simutrans/gui/goods_frame.h000066400000000000000000000066361474050137200216240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GOODS_FRAME_H #define GUI_GOODS_FRAME_H #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_numberinput.h" #include "components/gui_textarea.h" #include "components/gui_combobox.h" #include "components/gui_scrollpane.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "goods_stats.h" #include "../simline.h" #include "../utils/cbuffer.h" class goods_desc_t; /** * Shows statistics. Only goods so far. */ class goods_frame_t : public gui_frame_t, private action_listener_t { private: enum sort_mode_t { unsortiert = 0, nach_name = 1, nach_gewinn = 2, nach_bonus = 3, nach_catg = 4, SORT_MODES = 5 }; static const char *sort_text[SORT_MODES]; // Variables used for remembering last state of window when closed. // The last selected speed. static sint32 selected_speed; // If the last selected speed was the average speed so as to allow selected speed to follow average speed over time. static bool average_selection; /** * This variable defines by which column the table is sorted * Values: 0 = Unsorted (passengers and mail first) * 1 = Alphabetical * 2 = Revenue */ static sort_mode_t sortby; /** * This variable defines the sort order (ascending or descending) * Values: 1 = ascending, 2 = descending) */ static bool sortreverse; /** * This variable controls whether all goods, way types and speeds are displayed, or * just the ones relevant to the current game * Values: false = all goods, way types and maximum speed shown, true = goods with factories, way types with vehicles and current best speed shown. */ static bool filter_goods; static simline_t::linetype last_scheduletype; cbuffer_t speed_message; vector_tpl good_list; gui_combobox_t sortedby; button_t sorteddir; gui_numberinput_t speed; gui_combobox_t scheduletype; gui_textarea_t speed_text; gui_aligned_container_t *sort_row; button_t filter_goods_toggle; goods_stats_t goods_stats; gui_scrollpane_t scrolly; /* Array to map linetype combobox selection to linetypes. * Allows the combo box to be filtered or sorted. */ simline_t::linetype linetype_selection_map[simline_t::MAX_LINE_TYPE]; /* Builds the linetype combobox list. * When show_used is specified then only types which have at least 1 powered vehicle will be shown. */ void build_linetype_list(bool const show_used); // creates the list and pass it to the child function good_stats, which does the display stuff ... static bool compare_goods(goods_desc_t const* const w1, goods_desc_t const* const w2); /* Changes the currently set linetype. * Updates the selectable speed limit as well as automatically adjusts the value to keep the same bonus. * A non 0 speed_value will set the speed value while a 0 value will automatically adjust. */ void set_linetype(simline_t::linetype const linetype, sint32 const speed_value = 0); void sort_list(); public: goods_frame_t(); // yes we can reload uint32 get_rdwr_id() OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "goods_filter.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/goods_stats.cc000066400000000000000000000042211474050137200220120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "goods_stats.h" #include "../simcolor.h" #include "../world/simworld.h" #include "../builder/goods_manager.h" #include "../descriptor/goods_desc.h" #include "../dataobj/translator.h" #include "components/gui_button.h" #include "components/gui_colorbox.h" #include "components/gui_label.h" karte_ptr_t goods_stats_t::welt; void goods_stats_t::update_goodslist(vector_tplgoods, int bonus) { scr_size size = get_size(); remove_all(); set_table_layout(6,0); new_component(); new_component("Name") ->set_align(gui_label_t::left); new_component("Revenue/unit/100 tiles")->set_align(gui_label_t::right); new_component("Speed Bonus") ->set_align(gui_label_t::right); new_component("Category") ->set_align(gui_label_t::left); new_component("Weight/unit") ->set_align(gui_label_t::right); for(const goods_desc_t* wtyp : goods) { new_component(wtyp->get_color())->set_max_size(scr_size(D_INDICATOR_WIDTH, D_INDICATOR_HEIGHT)); new_component(wtyp->get_name()); const sint32 grundwert128 = (sint32)wtyp->get_value() * welt->get_settings().get_bonus_basefactor(); // bonus price will be always at least this const sint32 grundwert_bonus = (sint32)wtyp->get_value()*(1000l+(bonus-100l)*wtyp->get_speed_bonus()); const sint32 price = (grundwert128>grundwert_bonus ? grundwert128 : grundwert_bonus); gui_label_buf_t *lb = new_component(SYSCOL_TEXT, gui_label_t::right); lb->buf().append_money(price/3000.0); lb->update(); lb = new_component(SYSCOL_TEXT, gui_label_t::right); lb->buf().printf("%d%%", wtyp->get_speed_bonus()); lb->update(); new_component(wtyp->get_catg_name()); lb = new_component(SYSCOL_TEXT, gui_label_t::right); lb->buf().printf("%dKg", wtyp->get_weight_per_unit()); lb->update(); } scr_size min_size = get_min_size(); set_size(scr_size(max(size.w, min_size.w), min_size.h) ); } simutrans-124.3/src/simutrans/gui/goods_stats.h000066400000000000000000000007671474050137200216670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GOODS_STATS_H #define GUI_GOODS_STATS_H #include "../simtypes.h" #include "components/gui_aligned_container.h" template class vector_tpl; class goods_desc_t; class goods_stats_t : public gui_aligned_container_t { static karte_ptr_t welt; public: goods_stats_t() {} // update list and resize void update_goodslist(vector_tpl, int bonus); }; #endif simutrans-124.3/src/simutrans/gui/ground_info.cc000066400000000000000000000030531474050137200217740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../display/simgraph.h" #include "../display/viewport.h" #include "../world/simworld.h" #include "../dataobj/translator.h" #include "ground_info.h" grund_info_t::grund_info_t(const grund_t* _gr) : base_infowin_t("",NULL), gr(_gr), lview(_gr->get_pos(), scr_size(max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width() * 7) / 8))) { fill_buffer(); set_embedded(&lview); textarea.set_width(textarea.get_size().w + get_base_tile_raster_width() - 64); recalc_size(); } void grund_info_t::fill_buffer() { const cbuffer_t old_buf(buf); buf.clear(); gr->info(buf); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void grund_info_t::draw(scr_coord pos, scr_size size) { scr_size old_t_size = textarea.get_size(); fill_buffer(); // update for owner and name change set_dirty(); const obj_t *const d = gr->obj_bei(0); if ( d!=NULL ) { set_owner( d->get_owner() ); } gui_frame_t::set_name(translator::translate(gr->get_name())); gui_frame_t::draw(pos, size); set_embedded(&lview); if (old_t_size != textarea.get_size()) { recalc_size(); } } koord3d grund_info_t::get_weltpos(bool) { return gr->get_pos(); } bool grund_info_t::is_weltpos() { return ( welt->get_viewport()->is_on_center( gr->get_pos() ) ); } void grund_info_t::map_rotate90( sint16 new_ysize ) { lview.map_rotate90(new_ysize); } simutrans-124.3/src/simutrans/gui/ground_info.h000066400000000000000000000011271474050137200216360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GROUND_INFO_H #define GUI_GROUND_INFO_H #include "gui_frame.h" #include "components/gui_location_view.h" #include "obj_info.h" class grund_t; class grund_info_t : public base_infowin_t { protected: const grund_t* gr; location_view_t lview; public: grund_info_t(const grund_t* _gr); koord3d get_weltpos(bool) OVERRIDE; bool is_weltpos() OVERRIDE; void fill_buffer(); void draw(scr_coord pos, scr_size size) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/groundobj_edit.cc000066400000000000000000000130011474050137200224530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * The trees builder */ #include #include "../player/finance.h" // convert_money #include "../world/simworld.h" #include "../tool/simtool.h" #include "../tool/simmenu.h" #include "../dataobj/translator.h" #include "../descriptor/image.h" #include "../descriptor/ground_desc.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "groundobj_edit.h" // new tool definition tool_plant_groundobj_t groundobj_edit_frame_t::groundobj_tool; cbuffer_t groundobj_edit_frame_t::param_str; bool groundobj_edit_frame_t::sortreverse = false; static bool compare_groundobj_desc(const groundobj_desc_t* a, const groundobj_desc_t* b) { int diff = strcmp( a->get_name(), b->get_name() ); return groundobj_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_groundobj_desc_name(const groundobj_desc_t* a, const groundobj_desc_t* b) { int diff = strcmp( translator::translate(a->get_name()), translator::translate(b->get_name()) ); if(diff ==0) { diff = strcmp( a->get_name(), b->get_name() ); } return groundobj_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } static bool compare_groundobj_desc_cost(const groundobj_desc_t* a, const groundobj_desc_t* b) { int diff = a->get_price() - b->get_price(); if(diff ==0) { diff = strcmp( a->get_name(), b->get_name() ); } return groundobj_edit_frame_t::sortreverse ? diff > 0 : diff < 0; } groundobj_edit_frame_t::groundobj_edit_frame_t(player_t* player_) : extend_edit_gui_t(translator::translate("groundobj builder"), player_), groundobj_list(16) { cont_timeline.set_visible(false); cb_sortedby.new_component(gui_sorting_item_t::BY_REMOVAL); desc = NULL; groundobj_tool.set_default_param(NULL); fill_list(); // since we do not have a building image, we have to add the image again ourselves ... cont_scrolly.remove_all(); cont_scrolly.set_table_layout(2, 0); cont_scrolly.set_margin(scr_size(0, D_V_SPACE), scr_size(0, D_V_SPACE)); // add object description cont_scrolly.add_component(&info_text, 2); // add object image cont_scrolly.add_component(&groundobj_image); cont_scrolly.new_component(true, false); cont_scrolly.new_component_span(false, true, 2); } // fill the current groundobj_list void groundobj_edit_frame_t::fill_list() { groundobj_list.clear(); const uint8 sortedby = get_sortedby(); sortreverse = sort_order.pressed; for(groundobj_desc_t const* const i : groundobj_t::get_all_desc()) { if ( i && (i->get_allowed_climate_bits() & get_climate()) ) { switch(sortedby) { case gui_sorting_item_t::BY_NAME_TRANSLATED: groundobj_list.insert_ordered( i, compare_groundobj_desc_name ); break; case gui_sorting_item_t::BY_REMOVAL: groundobj_list.insert_ordered( i, compare_groundobj_desc_cost ); break; default: groundobj_list.insert_ordered( i, compare_groundobj_desc ); } } } // now build scrolled list scl.clear_elements(); scl.set_selection(-1); for(groundobj_desc_t const* const i : groundobj_list) { char const* const name = sortedby==gui_sorting_item_t::BY_NAME_OBJECT ? i->get_name() : translator::translate(i->get_name()); scl.new_component(name, SYSCOL_TEXT); if (i == desc) { scl.set_selection(scl.get_count()-1); } } // always update current selection (since the tool may depend on it) change_item_info( scl.get_selection() ); } void groundobj_edit_frame_t::change_item_info(sint32 entry) { buf.clear(); if(entry>=0 && entry<(sint32)groundobj_list.get_count()) { desc = groundobj_list[entry]; buf.append(translator::translate(desc->get_name())); buf.append("\n\n"); // climates buf.append( translator::translate("allowed climates:\n") ); uint16 cl = desc->get_allowed_climate_bits(); if(cl==0) { buf.append( translator::translate("None") ); buf.append("\n"); } else { for(uint16 i=0; i<=arctic_climate; i++ ) { if(cl & (1<get_seasons(); if( seasons > 1){ buf.printf( "\n%s\n", translator::translate("Has Snow")); buf.printf( "%s %i\n", translator::translate("Seasons"), desc->get_seasons()-1 ); } if(desc->get_phases() > 2){ buf.printf( "\n%s\n", translator::translate("Has slope graphics")); } if(desc->can_build_trees_here()){ buf.printf( "\n%s\n", translator::translate("Can be overgrown") ); } buf.printf("\n%s ", translator::translate("cost for removal")); buf.append_money( convert_money( desc->get_price() ) ); buf.append("\n"); if (char const* const maker = desc->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); buf.append("\n"); } groundobj_image.set_image(desc->get_image_id( seasons>2 ? 2 : 0, 0 ), true); param_str.clear(); param_str.printf( "%i%i,%s", bt_climates.pressed, bt_timeline.pressed, desc->get_name() ); groundobj_tool.set_default_param(param_str); groundobj_tool.cursor = tool_t::general_tool[TOOL_PLANT_GROUNDOBJ]->cursor; welt->set_tool( &groundobj_tool, player ); } else if(welt->get_tool(player->get_player_nr())==&groundobj_tool) { desc = NULL; groundobj_image.set_image(IMG_EMPTY, true); welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); } info_text.recalc_size(); reset_min_windowsize(); } simutrans-124.3/src/simutrans/gui/groundobj_edit.h000066400000000000000000000021041474050137200223170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GROUNDOBJ_EDIT_H #define GUI_GROUNDOBJ_EDIT_H #include "extend_edit.h" #include "components/gui_image.h" class groundobj_desc_t; class tool_plant_groundobj_t; /* * The groundobj builder */ class groundobj_edit_frame_t : public extend_edit_gui_t { private: static tool_plant_groundobj_t groundobj_tool; static cbuffer_t param_str; const groundobj_desc_t *desc; gui_image_t groundobj_image; vector_tplgroundobj_list; void fill_list() OVERRIDE; void change_item_info( sint32 i ) OVERRIDE; public: groundobj_edit_frame_t(player_t* player_); static bool sortreverse; /** * in top-level windows the name is displayed in titlebar * @return the non-translated component name */ const char* get_name() const { return "groundobj builder"; } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char* get_help_filename() const OVERRIDE { return "groundobj_build.txt"; } }; #endif simutrans-124.3/src/simutrans/gui/gui_frame.cc000066400000000000000000000126661474050137200214330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "gui_frame.h" #include "../simcolor.h" #include "../dataobj/environment.h" #include "../display/simgraph.h" #include "simwin.h" #include "../world/simworld.h" #include "../player/simplay.h" #include "../descriptor/reader/obj_reader.h" #include "../descriptor/skin_desc.h" #include "../simskin.h" karte_ptr_t gui_frame_t::welt; // Insert the container gui_frame_t::gui_frame_t(char const* const name, player_t const* const player) { this->name = name; windowsize = scr_size(200, 100); min_windowsize = scr_size(0,0); owner = player; set_resizemode(no_resize); //25-may-02 markus weber added opaque = true; dirty = true; // set default margin and spacing gui_aligned_container_t::set_margin_from_theme(); gui_aligned_container_t::set_spacing_from_theme(); // initialize even if we cannot call has_title() here gui_aligned_container_t::set_pos(scr_coord(0, D_TITLEBAR_HEIGHT)); } /** * Set the window size */ void gui_frame_t::set_windowsize(scr_size new_windowsize) { gui_aligned_container_t::set_pos(scr_coord(0, has_title()*D_TITLEBAR_HEIGHT)); if( new_windowsize != windowsize ) { // mark old size dirty scr_coord const& pos = win_get_pos(this); mark_rect_dirty_wc( pos.x, pos.y, pos.x+windowsize.w, pos.y+windowsize.h ); // minimum size //25-may-02 markus weber added new_windowsize.clip_lefttop(min_windowsize); windowsize = new_windowsize; dirty = true; // TODO respect gui_aligned_container_t::get_max_size() } // recompute always, to react on resize(scr_coord(0,0)) if (gui_aligned_container_t::is_table()) { gui_aligned_container_t::set_size(get_client_windowsize()); } } void gui_frame_t::reset_min_windowsize() { gui_aligned_container_t::set_pos(scr_coord(0, has_title()*D_TITLEBAR_HEIGHT)); if (gui_aligned_container_t::is_table()) { const bool at_min_size = windowsize == min_windowsize; const scr_size csize = gui_aligned_container_t::get_min_size(); const scr_coord pos = gui_aligned_container_t::get_pos(); const scr_size new_min_windowsize(csize.w + pos.x, csize.h + pos.y); if (at_min_size) { set_windowsize(new_min_windowsize); } else { scr_size wsize = windowsize; wsize.clip_lefttop(new_min_windowsize); set_windowsize(wsize); } set_min_windowsize( new_min_windowsize ); } } /** * get color information for the window title * -borders and -body background */ FLAGGED_PIXVAL gui_frame_t::get_titlecolor() const { return owner ? PLAYER_FLAG|color_idx_to_rgb(owner->get_player_color1()+env_t::gui_player_color_dark) : env_t::default_window_title_color; } /** * Events are notified to GUI components via this method */ bool gui_frame_t::infowin_event(const event_t *ev) { // %DB0 printf( "\nMessage: gui_frame_t::infowin_event( event_t const * ev ) : Fenster|Window %p : Event is %d", (void*)this, ev->ev_class ); if (ev->ev_class==EVENT_SYSTEM && ev->ev_code == SYSTEM_THEME_CHANGED) { if (gui_aligned_container_t::is_table()) { reset_min_windowsize(); } return true; } if(IS_WINDOW_RESIZE(ev)) { scr_coord delta ( resize_mode & horizontal_resize ? ev->mouse_pos.x - ev->click_pos.x : 0, resize_mode & vertical_resize ? ev->mouse_pos.y - ev->click_pos.y : 0); resize(delta); return true; // don't pass to children! } else if(IS_WINDOW_MAKE_MIN_SIZE(ev)) { set_windowsize( get_min_windowsize() ) ; resize( scr_coord(0,0) ) ; return true; // don't pass to children! } else if(ev->ev_class==INFOWIN && (ev->ev_code==WIN_CLOSE || ev->ev_code==WIN_OPEN || ev->ev_code==WIN_TOP)) { dirty = true; gui_aligned_container_t::clear_dirty(); } event_t ev2 = *ev; ev2.move_origin(scr_coord(0, (int)has_title()*D_TITLEBAR_HEIGHT)); return gui_aligned_container_t::infowin_event(&ev2); } /** * resize window in response to a resize event */ void gui_frame_t::resize(const scr_coord delta) { dirty = true; scr_size new_size = windowsize + delta; // resize window to the minimum size new_size.clip_lefttop(min_windowsize); scr_coord size_change = new_size - windowsize; // resize window set_windowsize(new_size); // change drag start change_drag_start(size_change); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void gui_frame_t::draw(scr_coord pos, scr_size size) { scr_size titlebar_size(0, ( has_title()*D_TITLEBAR_HEIGHT )); // draw background if( opaque ) { display_img_stretch( gui_theme_t::windowback, scr_rect( pos + titlebar_size, size - titlebar_size ) ); if( dirty ) { mark_rect_dirty_wc(pos.x, pos.y, pos.x + size.w, pos.y + titlebar_size.h ); } } else { if( dirty ) { mark_rect_dirty_wc(pos.x, pos.y, pos.x + size.w, pos.y + size.h + titlebar_size.h ); } display_blend_wh_rgb( pos.x+1, pos.y+titlebar_size.h, size.w-2, size.h-titlebar_size.h, color_transparent, percent_transparent ); } dirty = false; PUSH_CLIP_FIT(pos.x+1, pos.y+titlebar_size.h+1, size.w-2, size.h-titlebar_size.h-2); gui_aligned_container_t::draw(pos); POP_CLIP(); // for shadows of the windows if( gui_theme_t::gui_drop_shadows ) { display_blend_wh_rgb( pos.x+size.w, pos.y+1, 2, size.h, color_idx_to_rgb(COL_BLACK), 50 ); display_blend_wh_rgb( pos.x+1, pos.y+size.h, size.w, 2, color_idx_to_rgb(COL_BLACK), 50 ); } } uint32 gui_frame_t::get_rdwr_id() { return magic_reserved; } simutrans-124.3/src/simutrans/gui/gui_frame.h000066400000000000000000000126251474050137200212700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GUI_FRAME_H #define GUI_GUI_FRAME_H #include "../display/scr_coord.h" #include "../display/simgraph.h" #include "../simcolor.h" #include "../dataobj/koord3d.h" #include "components/gui_aligned_container.h" #include "components/gui_button.h" #include "gui_theme.h" class loadsave_t; class karte_ptr_t; class player_t; /** * A Class for window with Component. * Unlike other Window Classes in Simutrans, this is * a true component-oriented window that all actions * delegates to its component. */ class gui_frame_t : protected gui_aligned_container_t { public: /** * Resize modes */ enum resize_modes { no_resize = 0, vertical_resize = 1, horizontal_resize = 2, diagonal_resize = 3 }; private: const char *name; scr_size windowsize; ///< Size of the whole window (possibly with title bar) scr_size min_windowsize; ///< min size of the whole window resize_modes resize_mode; const player_t *owner; // set true for total redraw bool dirty:1; bool opaque:1; uint8 percent_transparent; PIXVAL color_transparent; using gui_aligned_container_t::draw; using gui_aligned_container_t::set_size; protected: void set_dirty() { dirty=true; } void unset_dirty() { dirty=false; } /** * resize window in response to a resize event */ virtual void resize(const scr_coord delta); void set_owner( const player_t *player ) { owner = player; } void set_transparent( uint8 percent, PIXVAL col ) { opaque = percent==0; percent_transparent = percent; color_transparent = col; } static karte_ptr_t welt; public: /** * @param name Window title * @param player owner for color */ gui_frame_t(const char *name, const player_t *player=NULL); virtual ~gui_frame_t() {} /** * The name is displayed in the titlebar * @return the non-translated name of the Component */ const char *get_name() const { return name; } /** * sets the Name (Window title) */ void set_name(const char *name) { this->name=name; } /** * This returns an unique id (different from magic_reserved), if the dialogue can be saved. */ virtual uint32 get_rdwr_id(); virtual void rdwr( loadsave_t * ) {} /** * get color information for the window title * -borders and -body background */ virtual FLAGGED_PIXVAL get_titlecolor() const; /** * @return gets the window sizes */ scr_size get_windowsize() const { return windowsize; } /** * Sets the window sizes */ virtual void set_windowsize(scr_size size); protected: /** * Set minimum size of the window */ void set_min_windowsize(scr_size new_size) { min_windowsize = new_size; } /** * Set minimum window size to minimum size of container. */ void reset_min_windowsize(); public: /** * Get minimum size of the window */ scr_size get_min_windowsize() { return min_windowsize; } /** * Max Kielland 2013: Client size auto calculation with title bar and margins. * @return the usable width and height of the window */ scr_size get_client_windowsize() const { return windowsize - scr_size(0, ( has_title()*D_TITLEBAR_HEIGHT ) ); } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ virtual const char * get_help_filename() const {return NULL;} /** * Does this window need a next button in the title bar? * @return true if such a button is needed */ virtual bool has_next() const {return false;} /** * Does this window need a prev button in the title bar? * @return true if such a button is needed */ virtual bool has_prev() const {return has_next();} /** * Does this window need a sticky in the title bar? * @return true if such a button is needed */ virtual bool has_sticky() const { return true; } /** * Does this window need its title to be shown? * @return if false title and all gadgets will be not drawn */ virtual bool has_title() const { return true; } // position of a connected thing on the map // The calling parameter is only true when actually clicking the gadget virtual koord3d get_weltpos( bool /*set*/ ) { return koord3d::invalid; } // returns true, when the window show the current object already virtual bool is_weltpos() { return false; } bool is_dirty() const { return dirty; } /** * Set resize mode */ void set_resizemode(resize_modes mode) { resize_mode = mode; } /** * Get resize mode */ resize_modes get_resizemode() const { return resize_mode; } /** * Returns true, if inside window area. */ virtual bool is_hit(int x, int y) { scr_size size = get_windowsize(); return ( x>=0 && y>=0 && xx+image->w,image->y+image->h); } } /** * Lazy button image number init */ void gui_theme_t::init_gui_from_images() { // Calculate posbutton size if( skinverwaltung_t::divider == NULL ) { // usually there should be a default theme which would provided missing images even for outdated themes dbg->fatal( "gui_theme_t::init_gui_themes", "Wrong theme loaded" ); } init_size_from_image( skinverwaltung_t::posbutton->get_image( SKIN_BUTTON_POS ), gui_pos_button_size ); init_size_from_image( skinverwaltung_t::check_button->get_image( SKIN_BUTTON_CHECKBOX ), gui_checkbox_size ); for( int i=0; i<3; i++ ) { pos_button_img[i] = skinverwaltung_t::posbutton->get_image_id( SKIN_BUTTON_POS+i ); check_button_img[i] = skinverwaltung_t::check_button->get_image_id( SKIN_BUTTON_CHECKBOX+i ); } // Normal buttons (colorful ones) scr_coord_val y = gui_button_size.h; scr_size k; init_size_from_image( skinverwaltung_t::button->get_image( SKIN_BUTTON_SIDE_LEFT ), k ); y = max( y, k.h ); init_size_from_image( skinverwaltung_t::button->get_image( SKIN_BUTTON_SIDE_RIGHT ), k ); y = max( y, k.h ); init_size_from_image( skinverwaltung_t::button->get_image( SKIN_BUTTON_BODY ), k ); y = max( y, k.h ); for( int i=0; i<3; i++ ) { for( int j=0; j<9; j++ ) { button_tiles[i][j%3][j/3] = skinverwaltung_t::button->get_image_id( i*9+j ); } } image_id has_second_mask = 0xFFFF; for( int i=0; i<2; i++ ) { has_second_mask = 0xFFFF; for( int j=0; j<9; j++ ) { button_color_tiles[i][j%3][j/3] = skinverwaltung_t::button->get_image_id( i*9+j+27 ); has_second_mask &= button_color_tiles[i][j%3][j/3]; } } if( has_second_mask == 0xFFFF ) { // has no second mask => copy first for( int j=0; j<9; j++ ) { button_color_tiles[1][j%3][j/3] = button_color_tiles[0][j%3][j/3]; } } // Round buttons for( int i=0; i<3; i++ ) { for( int j=0; j<9; j++ ) { round_button_tiles[i][j%3][j/3] = skinverwaltung_t::round_button->get_image_id( i*9+j ); } } // background for editfields, listbuttons, and windows for( int j=0; j<9; j++ ) { editfield[j%3][j/3] = skinverwaltung_t::editfield->get_image_id( j ); listbox[j%3][j/3] = skinverwaltung_t::listbox->get_image_id( j ); windowback[j%3][j/3] = skinverwaltung_t::back->get_image_id( j ); } // Divider (vspace will be added later on) init_size_from_image( skinverwaltung_t::divider->get_image(1), gui_divider_size ); for( int i=0; i<3; i++ ) { divider[i][0] = skinverwaltung_t::divider->get_image_id( i ); divider[i][1] = IMG_EMPTY; divider[i][2] = IMG_EMPTY; } // Calculate arrow size init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_BUTTON_ARROW_LEFT ), gui_arrow_left_size ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_BUTTON_ARROW_RIGHT ), gui_arrow_right_size ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_BUTTON_ARROW_UP ), gui_arrow_up_size ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_BUTTON_ARROW_DOWN ), gui_arrow_down_size ); for( int i=0; i<3; i++ ) { arrow_button_left_img[i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_BUTTON_ARROW_LEFT+i ); arrow_button_right_img[i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_BUTTON_ARROW_RIGHT+i ); arrow_button_up_img[i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_BUTTON_ARROW_UP+i ); arrow_button_down_img[i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_BUTTON_ARROW_DOWN+i ); } if( gui_theme_t::gui_arrow_right_size != gui_theme_t::gui_arrow_left_size ) { dbg->warning( "gui_theme_t::themes_init()", "Size of left and right arrows differ" ); } if( gui_theme_t::gui_arrow_up_size != gui_theme_t::gui_arrow_down_size ) { dbg->warning( "gui_theme_t::themes_init()", "Size of up and down arrows differ" ); } // now init this button dependent size here too gui_edit_size = scr_size(92,max(LINESPACE+2, max(D_ARROW_LEFT_HEIGHT, D_ARROW_RIGHT_HEIGHT) )); // init horizontal scrollbar buttons for( int i=0; i<3; i++ ) { h_scroll_back_tiles[i][0] = skinverwaltung_t::scrollbar->get_image_id( SKIN_SCROLLBAR_H_BACKGROUND_LEFT+i ); h_scroll_back_tiles[i][1] = IMG_EMPTY; h_scroll_back_tiles[i][2] = IMG_EMPTY; h_scroll_knob_tiles[i][0] = skinverwaltung_t::scrollbar->get_image_id( SKIN_SCROLLBAR_H_KNOB_LEFT+i ); h_scroll_knob_tiles[i][1] = IMG_EMPTY; h_scroll_knob_tiles[i][2] = IMG_EMPTY; } // init vertical scrollbar buttons for( int i=0; i<3; i++ ) { v_scroll_back_tiles[0][i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_SCROLLBAR_V_BACKGROUND_TOP+i ); v_scroll_back_tiles[1][i] = IMG_EMPTY; v_scroll_back_tiles[2][i] = IMG_EMPTY; v_scroll_knob_tiles[0][i] = skinverwaltung_t::scrollbar->get_image_id( SKIN_SCROLLBAR_V_KNOB_TOP+i ); v_scroll_knob_tiles[1][i] = IMG_EMPTY; v_scroll_knob_tiles[2][i] = IMG_EMPTY; } // Calculate V scrollbar size { scr_size back, front; init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_V_BACKGROUND ), back ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_V_KNOB_BODY ), front ); gui_scrollbar_size.w = max(front.w, back.w); // Calculate H scrollbar size init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_H_BACKGROUND ), back ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_H_KNOB_BODY ), front ); gui_scrollbar_size.h = max(front.h, back.h); // calculate minimum width init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_H_KNOB_LEFT ), back ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_H_KNOB_RIGHT ), front ); gui_min_scrollbar_size.w = back.w + front.w; // calculate minimum height init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_V_KNOB_TOP ), back ); init_size_from_image( skinverwaltung_t::scrollbar->get_image( SKIN_SCROLLBAR_V_KNOB_BOTTOM ), front ); gui_min_scrollbar_size.h = back.h + front.h; } // gadgets gui_dragger_size = gui_scrollbar_size; if (skinverwaltung_t::gadget) { init_size_from_image( skinverwaltung_t::gadget->get_image( SKIN_GADGET_CLOSE ), gui_gadget_size ); } } /** * Reads theme configuration data, still not final * * Note, there will be a theme manager later on and * each gui object will find their own parameters by * themselves after registering its class to the theme * manager. This will be done as the last step in * the chain when loading a theme. */ bool gui_theme_t::themes_init(const char *file_name, bool init_fonts, bool init_tools ) { tabfile_t themesconf; // first take user data, then user global data if( !themesconf.open(file_name) ) { dbg->warning("simwin.cc themes_init()", "Can't read themes from %s", file_name ); return false; } // define a default even when stuff is missing from the table init_gui_defaults(); tabfileobj_t contents; themesconf.read(contents); // theme name to find out current theme std::string theme_name = contents.get( "name" ); // reload current font if requested size differs and we are allowed to do so uint8 new_size = contents.get_int("font_size", env_t::fontsize ); if( init_fonts && new_size!=0 && LINESPACE!=new_size ) { if( display_load_font( env_t::fontname.c_str() ) ) { env_t::fontsize = new_size; } } // first get the images ( to be able to overload default sizes) const std::string buttonpak = contents.get("themeimages"); if( buttonpak.length()>0 ) { std::string path; char *pathname = strdup(file_name); if( char *s = strrchr( pathname, '/' ) ) { *s = 0; } else if( char *s = strrchr( pathname, '\\' ) ) { *s = 0; } dr_chdir( pathname ); pakset_manager_t::load_pak_file(buttonpak); gui_theme_t::init_gui_from_images(); free(pathname); dr_chdir(env_t::user_dir); } // first the stuff for the dialogues gui_theme_t::gui_titlebar_height = (uint32)contents.get_int("gui_titlebar_height", gui_theme_t::gui_titlebar_height ); gui_theme_t::gui_frame_left = (uint32)contents.get_int("gui_frame_left", gui_theme_t::gui_frame_left ); gui_theme_t::gui_frame_top = (uint32)contents.get_int("gui_frame_top", gui_theme_t::gui_frame_top ); gui_theme_t::gui_frame_right = (uint32)contents.get_int("gui_frame_right", gui_theme_t::gui_frame_right ); gui_theme_t::gui_frame_bottom = (uint32)contents.get_int("gui_frame_bottom", gui_theme_t::gui_frame_bottom ); gui_theme_t::gui_hspace = (uint32)contents.get_int("gui_hspace", gui_theme_t::gui_hspace ); gui_theme_t::gui_vspace = (uint32)contents.get_int("gui_vspace", gui_theme_t::gui_vspace ); gui_theme_t::gui_filelist_vspace = (uint32)contents.get_int("gui_filelist_vspace", gui_theme_t::gui_filelist_vspace ); // the divider needs the vspace added to it for know gui_divider_size.h += gui_vspace*2; gui_theme_t::gui_divider_size.h = contents.get_int("gui_divider_vsize", gui_theme_t::gui_divider_size.h ); gui_theme_t::gui_button_size.w = (uint32)contents.get_int("gui_button_width", gui_theme_t::gui_button_size.w ); gui_theme_t::gui_button_size.h = (uint32)contents.get_int("gui_button_height", gui_theme_t::gui_button_size.h ); gui_theme_t::gui_edit_size.h = (uint32)contents.get_int("gui_edit_height", gui_theme_t::gui_edit_size.h ); gui_theme_t::gui_checkbox_size.w = (uint32)contents.get_int("gui_checkbox_width", gui_theme_t::gui_checkbox_size.w ); gui_theme_t::gui_checkbox_size.h = (uint32)contents.get_int("gui_checkbox_height", gui_theme_t::gui_checkbox_size.h ); gui_theme_t::gui_gadget_size.w = (uint32)contents.get_int("gui_gadget_width", gui_theme_t::gui_gadget_size.w ); gui_theme_t::gui_gadget_size.h = (uint32)contents.get_int("gui_gadget_height", gui_theme_t::gui_gadget_size.h ); // make them fit at least the font height gui_theme_t::gui_titlebar_height = max( LINESPACE+2, gui_theme_t::gui_titlebar_height ); gui_theme_t::gui_button_size.h = max( LINESPACE+2, gui_theme_t::gui_button_size.h ); gui_theme_t::gui_edit_size.h = max( LINESPACE+2, gui_theme_t::gui_edit_size.h ); // since the arrows are used in scrollbars, the need similar sizes gui_theme_t::gui_arrow_left_size.w = (uint32)contents.get_int("gui_horizontal_arrow_width", gui_theme_t::gui_arrow_left_size.w ); gui_theme_t::gui_arrow_left_size.h = (uint32)contents.get_int("gui_horizontal_arrow_height", gui_theme_t::gui_arrow_left_size.h ); gui_theme_t::gui_arrow_right_size = gui_theme_t::gui_arrow_left_size; gui_theme_t::gui_arrow_up_size.w = (uint32)contents.get_int("gui_vertical_arrow_width", gui_theme_t::gui_arrow_up_size.w ); gui_theme_t::gui_arrow_up_size.h = (uint32)contents.get_int("gui_vertical_arrow_height", gui_theme_t::gui_arrow_up_size.h ); gui_theme_t::gui_arrow_down_size = gui_theme_t::gui_arrow_up_size; // since scrollbar must have a certain size gui_theme_t::gui_scrollbar_size.w = max( gui_min_scrollbar_size.w, (uint32)contents.get_int("gui_scrollbar_width", gui_theme_t::gui_scrollbar_size.w ) ); gui_theme_t::gui_scrollbar_size.h = max( gui_min_scrollbar_size.h, (uint32)contents.get_int("gui_scrollbar_height", gui_theme_t::gui_scrollbar_size.h ) ); // dragger size must be as large as scrollbar size if (skinverwaltung_t::gadget) { init_size_from_image( skinverwaltung_t::gadget->get_image( SKIN_WINDOW_RESIZE), gui_dragger_size ); gui_dragger_size.clip_lefttop(scr_coord(gui_scrollbar_size.w, gui_scrollbar_size.h)); } // in practice, posbutton min height better is LINESPACE gui_theme_t::gui_pos_button_size.w = (uint32)contents.get_int("gui_posbutton_width", gui_theme_t::gui_pos_button_size.w ); gui_theme_t::gui_pos_button_size.h = (uint32)contents.get_int("gui_posbutton_height", gui_theme_t::gui_pos_button_size.h ); // read ../dataobj/tabfile.h for clarification of this area vector_tpl color_button_text_offsets = contents.get_ints("gui_color_button_text_offset"); if( color_button_text_offsets.get_count() > 2 ) { gui_theme_t::gui_color_button_text_offset = scr_size(color_button_text_offsets[0], color_button_text_offsets[1]); gui_theme_t::gui_color_button_text_offset_right = scr_coord(color_button_text_offsets[2], 0); } vector_tpl button_text_offsets = contents.get_ints("gui_button_text_offset"); if( button_text_offsets.get_count() > 2 ) { gui_theme_t::gui_button_text_offset = scr_size(button_text_offsets[0], button_text_offsets[1]); gui_theme_t::gui_button_text_offset_right = scr_coord(button_text_offsets[2], 0); } // maybe not the best place, rather use simwin for the static defines? gui_theme_t::gui_color_text = (PIXVAL)contents.get_color("gui_color_text", SYSCOL_TEXT); gui_theme_t::gui_color_text_highlight = (PIXVAL)contents.get_color("gui_color_text_highlight", SYSCOL_TEXT_HIGHLIGHT); gui_theme_t::gui_color_text_shadow = (PIXVAL)contents.get_color("gui_color_text_shadow", SYSCOL_TEXT_SHADOW); gui_theme_t::gui_color_text_title = (PIXVAL)contents.get_color("gui_color_text_title", SYSCOL_TEXT_TITLE); gui_theme_t::gui_color_text_strong = (PIXVAL)contents.get_color("gui_color_text_strong", SYSCOL_TEXT_STRONG); gui_theme_t::gui_color_text_minus = (PIXVAL)contents.get_color("gui_color_text_minus", MONEY_MINUS); gui_theme_t::gui_color_text_plus = (PIXVAL)contents.get_color("gui_color_text_plus", MONEY_PLUS); gui_theme_t::gui_color_text_unused = (PIXVAL)contents.get_color("gui_color_text_unused", SYSCOL_TEXT_UNUSED); gui_theme_t::gui_color_edit_text = (PIXVAL)contents.get_color("gui_color_edit_text", SYSCOL_EDIT_TEXT); gui_theme_t::gui_color_edit_text_selected = (PIXVAL)contents.get_color("gui_color_edit_text_selected", SYSCOL_EDIT_TEXT_SELECTED); gui_theme_t::gui_color_edit_text_disabled = (PIXVAL)contents.get_color("gui_color_edit_text_disabled", SYSCOL_EDIT_TEXT_DISABLED); gui_theme_t::gui_color_edit_background_selected = (PIXVAL)contents.get_color("gui_color_edit_background_selected", SYSCOL_EDIT_BACKGROUND_SELECTED); gui_theme_t::gui_color_edit_beam = (PIXVAL)contents.get_color("gui_color_edit_beam", SYSCOL_CURSOR_BEAM); gui_theme_t::gui_color_chart_background = (PIXVAL)contents.get_color("gui_color_chart_background", SYSCOL_CHART_BACKGROUND); gui_theme_t::gui_color_chart_lines_zero = (PIXVAL)contents.get_color("gui_color_chart_lines_zero", SYSCOL_CHART_LINES_ZERO); gui_theme_t::gui_color_chart_lines_odd = (PIXVAL)contents.get_color("gui_color_chart_lines_odd", SYSCOL_CHART_LINES_ODD); gui_theme_t::gui_color_chart_lines_even = (PIXVAL)contents.get_color("gui_color_chart_lines_even", SYSCOL_CHART_LINES_EVEN); gui_theme_t::gui_color_list_text_selected_focus = (PIXVAL)contents.get_color("gui_color_list_text_selected_focus", SYSCOL_LIST_TEXT_SELECTED_FOCUS); gui_theme_t::gui_color_list_text_selected_nofocus = (PIXVAL)contents.get_color("gui_color_list_text_selected_nofocus", SYSCOL_LIST_TEXT_SELECTED_NOFOCUS); gui_theme_t::gui_color_list_background_selected_f = (PIXVAL)contents.get_color("gui_color_list_background_selected_focus", SYSCOL_LIST_BACKGROUND_SELECTED_F); gui_theme_t::gui_color_list_background_selected_nf = (PIXVAL)contents.get_color("gui_color_list_background_selected_nofocus", SYSCOL_LIST_BACKGROUND_SELECTED_NF); gui_theme_t::gui_color_button_text = (PIXVAL)contents.get_color("gui_color_button_text", SYSCOL_BUTTON_TEXT); gui_theme_t::gui_color_button_text_disabled = (PIXVAL)contents.get_color("gui_color_button_text_disabled", SYSCOL_BUTTON_TEXT_DISABLED); gui_theme_t::gui_color_button_text_selected = (PIXVAL)contents.get_color("gui_color_button_text_selected", SYSCOL_BUTTON_TEXT_SELECTED); gui_theme_t::gui_color_colored_button_text = (PIXVAL)contents.get_color("gui_color_colored_button_text", SYSCOL_COLORED_BUTTON_TEXT); gui_theme_t::gui_color_colored_button_text_selected = (PIXVAL)contents.get_color("gui_color_colored_button_text_selected", SYSCOL_COLORED_BUTTON_TEXT_SELECTED); gui_theme_t::gui_color_checkbox_text = (PIXVAL)contents.get_color("gui_color_checkbox_text", SYSCOL_CHECKBOX_TEXT); gui_theme_t::gui_color_checkbox_text_disabled = (PIXVAL)contents.get_color("gui_color_checkbox_text_disabled", SYSCOL_CHECKBOX_TEXT_DISABLED); gui_theme_t::gui_color_ticker_background = (PIXVAL)contents.get_color("gui_color_ticker_background", SYSCOL_TICKER_BACKGROUND); gui_theme_t::gui_color_ticker_divider = (PIXVAL)contents.get_color("gui_color_ticker_divider", SYSCOL_TICKER_DIVIDER); gui_theme_t::gui_color_statusbar_text = (PIXVAL)contents.get_color("gui_color_statusbar_text", SYSCOL_STATUSBAR_TEXT); gui_theme_t::gui_color_statusbar_background = (PIXVAL)contents.get_color("gui_color_statusbar_background", SYSCOL_STATUSBAR_BACKGROUND); gui_theme_t::gui_color_statusbar_divider = (PIXVAL)contents.get_color("gui_color_statusbar_divider", SYSCOL_STATUSBAR_DIVIDER); gui_theme_t::gui_highlight_color = (PIXVAL)contents.get_color("gui_highlight_color", SYSCOL_HIGHLIGHT); gui_theme_t::gui_shadow_color = (PIXVAL)contents.get_color("gui_shadow_color", SYSCOL_SHADOW); gui_theme_t::gui_color_loadingbar_inner = (PIXVAL)contents.get_color("gui_color_loadingbar_inner", SYSCOL_LOADINGBAR_INNER); gui_theme_t::gui_color_loadingbar_progress = (PIXVAL)contents.get_color("gui_color_loadingbar_progress", SYSCOL_LOADINGBAR_PROGRESS); gui_theme_t::gui_color_obsolete = (PIXVAL)contents.get_color("gui_color_obsolete", SYSCOL_OBSOLETE); gui_theme_t::gui_color_empty = (PIXVAL)contents.get_color("gui_color_empty", SYSCOL_EMPTY); gui_theme_t::gui_color_chat_window_network_transparency = (PIXVAL)contents.get_color("gui_color_chat_window_network_transparency", gui_color_chat_window_network_transparency); gui_theme_t::gui_color_image_transparency = (PIXVAL)contents.get_color("gui_color_image_transparency", SYSCOL_IMAGE_TRANSPARENCY); gui_theme_t::gui_color_object_highlight = (PIXVAL)contents.get_color("gui_color_object_highlight", SYSCOL_OBJECT_HIGHLIGHT); gui_theme_t::gui_waitingbar_width = (uint32)contents.get_int("gui_waitingbar_width", gui_theme_t::gui_waitingbar_width); // those two may be rather an own control later on? gui_theme_t::gui_indicator_size = contents.get_scr_size("gui_indicator_size", gui_theme_t::gui_indicator_size ); gui_tab_panel_t::header_vsize = (uint32)contents.get_int("gui_tab_header_vsize", gui_tab_panel_t::header_vsize ); // stuff in env_t but rather GUI env_t::window_buttons_right = contents.get_int("window_buttons_right", env_t::window_buttons_right ); env_t::left_to_right_graphs = contents.get_int("left_to_right_graphs", env_t::left_to_right_graphs ); env_t::window_frame_active = contents.get_int("window_frame_active", env_t::window_frame_active ); env_t::second_open_closes_win = contents.get_int("second_open_closes_win", env_t::second_open_closes_win ); env_t::remember_window_positions = contents.get_int("remember_window_positions", env_t::remember_window_positions ); env_t::window_snap_distance = contents.get_int("window_snap_distance", env_t::window_snap_distance ); gui_theme_t::gui_drop_shadows = contents.get_int("gui_drop_shadows", gui_theme_t::gui_drop_shadows ); env_t::bottom_window_darkness = contents.get_int("bottom_window_darkness", env_t::bottom_window_darkness ); env_t::menupos = contents.get_int("menubar_position", env_t::menupos); env_t::gui_player_color_bright = contents.get_int("gui_player_color_bright", env_t::gui_player_color_bright ); env_t::gui_player_color_dark = contents.get_int("gui_player_color_dark", env_t::gui_player_color_dark ); env_t::default_window_title_color = contents.get_color("default_window_title_color", env_t::default_window_title_color, &env_t::default_window_title_color_rgb ); env_t::front_window_text_color = contents.get_color("front_window_text_color", env_t::front_window_text_color, &env_t::front_window_text_color_rgb ); env_t::bottom_window_text_color = contents.get_color("bottom_window_text_color", env_t::bottom_window_text_color, &env_t::bottom_window_text_color_rgb ); env_t::cursor_overlay_color = contents.get_color("cursor_overlay_color", env_t::cursor_overlay_color, &env_t::cursor_overlay_color_rgb ); env_t::tooltip_color = contents.get_color("tooltip_background_color", env_t::tooltip_color, &env_t::tooltip_color_rgb ); env_t::tooltip_textcolor = contents.get_color("tooltip_text_color", env_t::tooltip_textcolor, &env_t::tooltip_textcolor_rgb ); env_t::show_tooltips = contents.get_int("show_tooltips", env_t::show_tooltips ); env_t::tooltip_delay = contents.get_int("tooltip_delay", env_t::tooltip_delay ); env_t::tooltip_duration = contents.get_int("tooltip_duration", env_t::tooltip_duration ); env_t::toolbar_max_width = contents.get_int("toolbar_max_width", env_t::toolbar_max_width ); env_t::toolbar_max_height = contents.get_int("toolbar_max_height", env_t::toolbar_max_height ); // default iconsize scaling (must be read before the images) env_t::iconscaling = contents.get_int("icon_scaling", env_t::iconscaling); if (skinverwaltung_t::tool_icons_general) { env_t::iconsize = display_get_best_matching_size(skinverwaltung_t::tool_icons_general->get_image_id(0), env_t::iconscaling); } env_t::chat_window_transparency = 100 - contents.get_int("gui_chat_window_network_transparency", 100 - env_t::chat_window_transparency); // needs to be changed after resize events too gui_buttons_per_row = max(2, min(4, display_get_width() / (D_BUTTON_WIDTH + D_H_SPACE + D_MARGIN_LEFT))); if( toolbar_last_used_t::last_used_tools && init_tools ) { // only re-init if already inited tool_t::update_toolbars(); } env_t::default_theme = file_name; return true; } simutrans-124.3/src/simutrans/gui/gui_theme.h000066400000000000000000000365441474050137200213060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_GUI_THEME_H #define GUI_GUI_THEME_H #include "../dataobj/koord.h" #include "../simcolor.h" #include "../display/simgraph.h" class image_t; /* * The following gives positioning aids for elements in dialogues * Only those, LINESPACE, and dimensions of elements itself must be * exclusively used to calculate positions in dialogues to have a * scalable interface * * Max Kielland: * Added more defines for theme testing. * These is going to be moved into the theme handling later. */ #define D_BUTTONS_PER_ROW (gui_theme_t::gui_buttons_per_row) #define D_BUTTON_SIZE (gui_theme_t::gui_button_size ) #define D_BUTTON_WIDTH (gui_theme_t::gui_button_size.w) #define D_BUTTON_HEIGHT (gui_theme_t::gui_button_size.h) #define D_BUTTON_PADDINGS_X (gui_theme_t::gui_button_text_offset.w + gui_theme_t::gui_button_text_offset_right.x) #define D_FILTER_BUTTON_SIZE (gui_theme_t::gui_color_button_size ) #define D_FILTER_BUTTON_WIDTH (gui_theme_t::gui_color_button_size.w) #define D_FILTER_BUTTON_HEIGHT (gui_theme_t::gui_color_button_size.h) #define D_CHECKBOX_SIZE (gui_theme_t::gui_checkbox_size ) #define D_CHECKBOX_WIDTH (gui_theme_t::gui_checkbox_size.w) #define D_CHECKBOX_HEIGHT (gui_theme_t::gui_checkbox_size.h) #define D_POS_BUTTON_SIZE (gui_theme_t::gui_pos_button_size ) #define D_POS_BUTTON_WIDTH (gui_theme_t::gui_pos_button_size.w) #define D_POS_BUTTON_HEIGHT (gui_theme_t::gui_pos_button_size.h) #define D_ARROW_LEFT_SIZE (gui_theme_t::gui_arrow_left_size ) #define D_ARROW_LEFT_WIDTH (gui_theme_t::gui_arrow_left_size.w) #define D_ARROW_LEFT_HEIGHT (gui_theme_t::gui_arrow_left_size.h) #define D_ARROW_RIGHT_SIZE (gui_theme_t::gui_arrow_right_size ) #define D_ARROW_RIGHT_WIDTH (gui_theme_t::gui_arrow_right_size.w) #define D_ARROW_RIGHT_HEIGHT (gui_theme_t::gui_arrow_right_size.h) #define D_ARROW_UP_SIZE (gui_theme_t::gui_arrow_up_size ) #define D_ARROW_UP_WIDTH (gui_theme_t::gui_arrow_up_size.w) #define D_ARROW_UP_HEIGHT (gui_theme_t::gui_arrow_up_size.h) #define D_ARROW_DOWN_SIZE (gui_theme_t::gui_arrow_down_size ) #define D_ARROW_DOWN_WIDTH (gui_theme_t::gui_arrow_down_size.w) #define D_ARROW_DOWN_HEIGHT (gui_theme_t::gui_arrow_down_size.h) #define D_SCROLLBAR_SIZE (gui_theme_t::gui_scrollbar_size ) #define D_SCROLLBAR_HEIGHT (gui_theme_t::gui_scrollbar_size.h) #define D_SCROLLBAR_WIDTH (gui_theme_t::gui_scrollbar_size.w) #define D_SCROLL_MIN_SIZE (gui_theme_t::gui_min_scrollbar_size ) #define D_SCROLL_MIN_WIDTH (gui_theme_t::gui_min_scrollbar_size.w) #define D_SCROLL_MIN_HEIGHT (gui_theme_t::gui_min_scrollbar_size.h) #define D_GADGET_SIZE (gui_theme_t::gui_gadget_size ) #define D_GADGET_WIDTH (gui_theme_t::gui_gadget_size.w) #define D_GADGET_HEIGHT (gui_theme_t::gui_gadget_size.h) #define D_DRAGGER_SIZE (gui_theme_t::gui_dragger_size ) #define D_DRAGGER_WIDTH (gui_theme_t::gui_dragger_size.w) #define D_DRAGGER_HEIGHT (gui_theme_t::gui_dragger_size.h) #define D_INDICATOR_BOX_SIZE (gui_theme_t::gui_indicator_size ) #define D_INDICATOR_BOX_HEIGHT (gui_theme_t::gui_indicator_size.h) #define D_INDICATOR_BOX_WIDTH (gui_theme_t::gui_indicator_size.w) #define D_INDICATOR_SIZE (gui_theme_t::gui_indicator_size ) #define D_INDICATOR_WIDTH (gui_theme_t::gui_indicator_size.w) #define D_INDICATOR_HEIGHT (gui_theme_t::gui_indicator_size.h) #define D_LABEL_SIZE (gui_theme_t::gui_label_size ) #define D_LABEL_WIDTH (gui_theme_t::gui_label_size.w) #define D_LABEL_HEIGHT (gui_theme_t::gui_label_size.h) #define D_EDIT_SIZE (gui_theme_t::gui_edit_size ) #define D_EDIT_WIDTH (gui_theme_t::gui_edit_size.w) #define D_EDIT_HEIGHT (gui_theme_t::gui_edit_size.h) #define D_FOCUS_OFFSET (gui_theme_t::gui_focus_offset ) #define D_FOCUS_OFFSET_H (gui_theme_t::gui_focus_offset.x) #define D_FOCUS_OFFSET_V (gui_theme_t::gui_focus_offset.y) #define D_TITLEBAR_HEIGHT (gui_theme_t::gui_titlebar_height) #define D_DIVIDER_HEIGHT (gui_theme_t::gui_divider_size.h) #define D_STATUSBAR_HEIGHT (max(16,LINESPACE)) // statusbar bottom of screen #define D_TAB_HEADER_HEIGHT (gui_tab_panel_t::header_vsize) // Tab page params (replace with real values from the skin images) // Dialog borders #define D_MARGIN_LEFT (gui_theme_t::gui_frame_left) #define D_MARGIN_TOP (gui_theme_t::gui_frame_top) #define D_MARGIN_RIGHT (gui_theme_t::gui_frame_right) #define D_MARGIN_BOTTOM (gui_theme_t::gui_frame_bottom) // Dialogue border helpers #define D_MARGINS_X (D_MARGIN_LEFT + D_MARGIN_RIGHT) #define D_MARGINS_Y (D_MARGIN_TOP + D_MARGIN_BOTTOM) // space between two elements #define D_H_SPACE (gui_theme_t::gui_hspace) #define D_V_SPACE (gui_theme_t::gui_vspace) // bars of goods waiting in stations #define D_WAITINGBAR_WIDTH (gui_theme_t::gui_waitingbar_width) #if 0 // Button grid helpers #define BUTTON1_X (D_MARGIN_LEFT) #define BUTTON2_X (D_MARGIN_LEFT+1*(D_BUTTON_WIDTH+D_H_SPACE)) #define BUTTON3_X (D_MARGIN_LEFT+2*(D_BUTTON_WIDTH+D_H_SPACE)) #define BUTTON4_X (D_MARGIN_LEFT+3*(D_BUTTON_WIDTH+D_H_SPACE)) #define BUTTON_X(col) ( (col) * (D_BUTTON_WIDTH + D_H_SPACE) ) #define BUTTON_Y(row) ( (row) * (D_BUTTON_HEIGHT + D_V_SPACE) ) #endif // The width of a typical dialogue (either list/covoi/factory) and initial width when it makes sense #define D_DEFAULT_WIDTH (D_MARGINS_X + D_BUTTONS_PER_ROW*D_BUTTON_WIDTH + (D_BUTTONS_PER_ROW-1)*D_H_SPACE) #define D_DEFAULT_HEIGHT (max(56, get_base_tile_raster_width() * 7 / 8) + 208 + D_SCROLLBAR_HEIGHT) // Max Kielland: align helper, returns the offset to apply to N1 for a center alignment around N2 #define D_GET_CENTER_ALIGN_OFFSET(N1,N2) ((N2-N1)>>1) #define D_GET_FAR_ALIGN_OFFSET(N1,N2) (N2-N1) #define D_FILELIST_V_SPACE (gui_theme_t::gui_filelist_vspace) #define TOOLTIP_MOUSE_OFFSET_X (16) #define TOOLTIP_MOUSE_OFFSET_Y (12) #define TOOLTIP_MOUSE_OFFSET (scr_coord{ TOOLTIP_MOUSE_OFFSET_X, TOOLTIP_MOUSE_OFFSET_Y }) // these define the offset of images in their definitions enum { SKIN_WINDOW_BACKGROUND=0, // gadget (window GUI buttons) SKIN_GADGET_CLOSE=0, SKIN_GADGET_HELP, SKIN_GADGET_MINIMIZE, SKIN_BUTTON_PREVIOUS, SKIN_BUTTON_NEXT, SKIN_GADGET_NOTPINNED, SKIN_GADGET_PINNED, SKIN_WINDOW_RESIZE, SKIN_GADGET_GOTOPOS, // SKIN_GADGET_BUTTON, SKIN_GADGET_COUNT, // maximum number, NOT AN IMAGE // scrollbars horizontal SKIN_BUTTON_ARROW_LEFT = 0, SKIN_BUTTON_ARROW_LEFT_PRESSED, SKIN_BUTTON_ARROW_LEFT_DISABLED, SKIN_BUTTON_ARROW_RIGHT, SKIN_BUTTON_ARROW_RIGHT_PRESSED, SKIN_BUTTON_ARROW_RIGHT_DISABLED, SKIN_SCROLLBAR_H_BACKGROUND_LEFT, SKIN_SCROLLBAR_H_BACKGROUND, SKIN_SCROLLBAR_H_BACKGROUND_RIGHT, SKIN_SCROLLBAR_H_KNOB_LEFT, SKIN_SCROLLBAR_H_KNOB_BODY, SKIN_SCROLLBAR_H_KNOB_RIGHT, // and vertical SKIN_BUTTON_ARROW_UP, SKIN_BUTTON_ARROW_UP_PRESSED, SKIN_BUTTON_ARROW_UP_DISABLED, SKIN_BUTTON_ARROW_DOWN, SKIN_BUTTON_ARROW_DOWN_PRESSED, SKIN_BUTTON_ARROW_DOWN_DISABLED, SKIN_SCROLLBAR_V_BACKGROUND_TOP, SKIN_SCROLLBAR_V_BACKGROUND, SKIN_SCROLLBAR_V_BACKGROUND_BOTTOM, SKIN_SCROLLBAR_V_KNOB_TOP, SKIN_SCROLLBAR_V_KNOB_BODY, SKIN_SCROLLBAR_V_KNOB_BOTTOM, // squarebutton SKIN_BUTTON_CHECKBOX = 0, SKIN_BUTTON_CHECKBOX_PRESSED, SKIN_BUTTON_CHECKBOX_DISABLED, // posbutton SKIN_BUTTON_POS = 0, SKIN_BUTTON_POS_PRESSED, SKIN_BUTTON_POS_DISABLED, // normal buttons and round buttons SKIN_BUTTON_SIDE_LEFT = 0, SKIN_BUTTON_BODY, SKIN_BUTTON_SIDE_RIGHT, SKIN_BUTTON_SIDE_LEFT_PRESSED, SKIN_BUTTON_BODY_PRESSED, SKIN_BUTTON_SIDE_RIGHT_PRESSED, SKIN_BUTTON_SIDE_RIGHT_DISABLED, SKIN_BUTTON_BODY_DISABLED, SKIN_BUTTON_SIDE_LEFT_DISABLED, SKIN_BUTTON_COLOR_MASK_LEFT, SKIN_BUTTON_COLOR_MASK_BODY, SKIN_BUTTON_COLOR_MASK_RIGHT }; class gui_theme_t { public: /// @name system colours used by gui components /// @{ static PIXVAL gui_color_text; //@< Color to draw standard text static PIXVAL gui_color_text_highlight; //@< Color to draw highlighted text (tabs, finance window headlines, ware list bonus text, fps info in video options, it and em tags) static PIXVAL gui_color_text_title; //@< Color to draw title text (banner, h1 and a tags) static PIXVAL gui_color_text_shadow; //@< Color to draw text shadow static PIXVAL gui_color_text_strong; //@< Color to draw strong text (strong tags) static PIXVAL gui_color_text_minus; //@< Color to draw negative values static PIXVAL gui_color_text_plus; //@< Color to draw positive values static PIXVAL gui_color_text_unused; //@< Color to draw unused items static PIXVAL gui_color_edit_text; //@< Color to draw text in edit areas static PIXVAL gui_color_edit_text_selected; //@< Color to draw selected text in edit areas static PIXVAL gui_color_edit_text_disabled; //@< Color to draw disabled text in edit areas static PIXVAL gui_color_edit_background_selected; //@< Color to draw background of selected text in edit areas static PIXVAL gui_color_edit_beam; //@< Color to draw the cursor beam static PIXVAL gui_color_chart_background; //@< Color to draw background of charts static PIXVAL gui_color_chart_lines_zero; //@< Color to draw in-chart horizontal zero line static PIXVAL gui_color_chart_lines_odd; //@< Color to draw in-chart vertical odd lines and text static PIXVAL gui_color_chart_lines_even; //@< Color to draw in-chart vertical even lines and text static PIXVAL gui_color_list_text_selected_focus; //@< Colour to draw the selected element text in list when window has focus static PIXVAL gui_color_list_text_selected_nofocus; //@< Colour to draw the selected element text in list when window is not in focus static PIXVAL gui_color_list_background_selected_f; //@< Colour to draw the selected element background in list when window has focus static PIXVAL gui_color_list_background_selected_nf; //@< Colour to draw the selected element background in list when window is not in focus static PIXVAL gui_color_button_text; //@< Color to draw text in normal buttons static PIXVAL gui_color_button_text_disabled; //@< Color to draw text in disabled buttons static PIXVAL gui_color_button_text_selected; //@< Color to draw text in pressed normal buttons static PIXVAL gui_color_colored_button_text; //@< Color to draw text in colored buttons static PIXVAL gui_color_colored_button_text_selected; //@< Color to draw text in pressed colored buttons static PIXVAL gui_color_checkbox_text; //@< Color to draw text in checkboxes static PIXVAL gui_color_checkbox_text_disabled; //@< Color to draw text in disabled checkboxes static PIXVAL gui_color_ticker_background; //@< Color to draw ticker background static PIXVAL gui_color_ticker_divider; //@< Color to draw ticker divider static PIXVAL gui_color_statusbar_text; //@< Color to draw text in statusbar static PIXVAL gui_color_statusbar_background; //@< Color to draw statusbar background static PIXVAL gui_color_statusbar_divider; //@< Color to draw statusbar divider static PIXVAL gui_highlight_color; //@< Color to draw highlight dividers (tabs) static PIXVAL gui_shadow_color; //@< Color to draw shadowed dividers (tabs) static PIXVAL gui_color_loadingbar_inner; static PIXVAL gui_color_loadingbar_progress; static PIXVAL gui_color_obsolete; //@< Color for obsolete convois/server entries static PIXVAL gui_color_empty; //@< Color for empty entries static PIXVAL gui_color_chat_window_network_transparency; //@< Color if chat window is transparent in network mode static PIXVAL gui_color_image_transparency; //@< Transparency color for some icons/images static PIXVAL gui_color_object_highlight; //@< Color (Red) to mark objects on the map /// @} /// @name GUI element sizes used by gui components /// @{ static sint16 gui_buttons_per_row; // how many buttons in a default dialog static scr_size gui_divider_size; static scr_size gui_button_size; static scr_size gui_color_button_text_offset; // extra offset for the text (in case of asymmetric or buttons with color on the left) static scr_size gui_button_text_offset; // extra offset for the text (in case of asymmetric or buttons with checkmark on the left) static scr_size gui_color_button_size; static scr_size gui_checkbox_size; static scr_size gui_pos_button_size; static scr_size gui_arrow_left_size; static scr_size gui_arrow_right_size; static scr_size gui_arrow_up_size; static scr_size gui_arrow_down_size; static scr_size gui_scrollbar_size; static scr_size gui_min_scrollbar_size; // minimum width and height of a scrollbar slider static scr_size gui_label_size; static scr_size gui_edit_size; static scr_size gui_indicator_size; static scr_size gui_gadget_size; static scr_size gui_dragger_size; static scr_coord gui_focus_offset; static scr_coord gui_color_button_text_offset_right; // extra right offset for the text (in case of asymmetric or buttons with color on the right) static scr_coord gui_button_text_offset_right; // extra right offset for the text (in case of asymmetric or buttons with checkmark on the right) static scr_coord_val gui_titlebar_height; static scr_coord_val gui_frame_left; static scr_coord_val gui_frame_top; static scr_coord_val gui_frame_right; static scr_coord_val gui_frame_bottom; static scr_coord_val gui_hspace; static scr_coord_val gui_vspace; static scr_coord_val gui_waitingbar_width; // one special entries, since there are lot of lists with files/fonts/paks/... where less spacing could fit more entires on the screen static scr_coord_val gui_filelist_vspace; /// @} // those are the 3x3 images which are used for stretching static stretch_map_t button_tiles[3]; static stretch_map_t button_color_tiles[2]; static stretch_map_t round_button_tiles[3]; static stretch_map_t h_scroll_back_tiles; static stretch_map_t h_scroll_knob_tiles; static stretch_map_t v_scroll_back_tiles; static stretch_map_t v_scroll_knob_tiles; static stretch_map_t divider; static stretch_map_t editfield; static stretch_map_t listbox; static stretch_map_t windowback; // those are the normal, selected and disabled simple buttons static image_id arrow_button_left_img[3]; static image_id arrow_button_right_img[3]; static image_id arrow_button_up_img[3]; static image_id arrow_button_down_img[3]; static image_id check_button_img[3]; static image_id pos_button_img[3]; static bool gui_drop_shadows; public: // default dimensions and colors static void init_gui_defaults(); // assings k with the dimension of this image static void init_size_from_image( const image_t *pic, scr_size &k ); // init the skin dimensions form file static void init_gui_from_images(); /** * Reads theme configuration data, still not final * searches a theme.tab inside the specified folder */ static bool themes_init(const char *dir_name,bool init_font,bool init_tools); }; #endif simutrans-124.3/src/simutrans/gui/halt_info.cc000066400000000000000000000744731474050137200214440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "halt_info.h" #include "components/gui_button_to_chart.h" #include "../world/simworld.h" #include "../simware.h" #include "../simcolor.h" #include "../simconvoi.h" #include "../simfab.h" #include "../simintr.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "../simline.h" #include "../freight_list_sorter.h" #include "../dataobj/schedule.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../player/simplay.h" #include "../vehicle/vehicle.h" #include "../utils/simstring.h" #include "../utils/unicode.h" #include "../descriptor/skin_desc.h" #define CHART_HEIGHT (100) /** * Window with destination information for a stop */ class gui_departure_board_t : public gui_aligned_container_t { // helper class to compute departure board class dest_info_t { public: bool compare( const dest_info_t &other ) const; halthandle_t halt; sint32 delta_ticks; convoihandle_t cnv; dest_info_t() : delta_ticks(0) {} dest_info_t( halthandle_t h, sint32 d_t, convoihandle_t c) : halt(h), delta_ticks(d_t), cnv(c) {} bool operator == (const dest_info_t &other) const { return ( this->cnv==other.cnv ); } }; static bool compare_hi(const dest_info_t &a, const dest_info_t &b) { return a.delta_ticks <= b.delta_ticks; } static karte_ptr_t welt; vector_tpl destinations; vector_tpl origins; static button_t absolute_times; uint32 calc_ticks_until_arrival( convoihandle_t cnv ); void insert_image(convoihandle_t cnv); public: // if nothing changed, this is the next refresh to recalculate the content of the departure board sint8 next_refresh; gui_departure_board_t() : gui_aligned_container_t() { next_refresh = -1; set_table_layout(3,0); add_component( &absolute_times ); absolute_times.init( button_t::square_automatic, "Absolute times" ); } void update_departures(halthandle_t halt); scr_size get_max_size() const OVERRIDE { return get_min_size(); } }; button_t gui_departure_board_t::absolute_times; // all connections class gui_halt_detail_t : public gui_aligned_container_t { /** * Button to open line window */ class gui_line_button_t : public button_t, public action_listener_t { static karte_ptr_t welt; linehandle_t line; public: gui_line_button_t(linehandle_t line) : button_t() { this->line = line; init(button_t::posbutton, NULL); add_listener(this); } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE { player_t *player = welt->get_active_player(); if( player == line->get_owner() ) { player->simlinemgmt.show_lineinfo(player, line, 3); } return true; } void draw(scr_coord offset) OVERRIDE { if (line->get_owner() == welt->get_active_player()) { button_t::draw(offset); } } }; /** * Button to open convoi window */ class gui_convoi_button_t : public button_t, public action_listener_t { convoihandle_t convoi; public: gui_convoi_button_t(convoihandle_t convoi) : button_t() { this->convoi = convoi; init(button_t::posbutton, NULL); add_listener(this); } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE { convoi->open_info_window(); return true; } }; private: static bool compare_connection(haltestelle_t::connection_t const& a, haltestelle_t::connection_t const& b) { return strcmp(a.halt->get_name(), b.halt->get_name()) <=0; } static bool compare_line (linehandle_t a, linehandle_t b) { return a->get_linetype() == b->get_linetype() ? strcmp(a->get_name(), b->get_name()) <= 0 : strcmp(a->get_linetype_name(a->get_linetype()), b->get_linetype_name(b->get_linetype())) <= 0; } uint32 cached_line_count; uint32 cached_convoy_count; void insert_empty_row() { new_component(" "); new_component(); } void insert_show_nothing() { new_component(); new_component("keine"); } public: uint8 destination_counter; // last destination counter of the halt; if mismatch to current, then redraw destinations gui_halt_detail_t(halthandle_t h) : gui_aligned_container_t() { destination_counter = 0xFF; cached_line_count = 0xFFFFFFFFul; cached_convoy_count = 0xFFFFFFFFul; update_connections(h); } // will update if schedule or connection changed void update_connections(halthandle_t h); scr_size get_max_size() const OVERRIDE { return get_min_size(); } }; karte_ptr_t gui_departure_board_t::welt; karte_ptr_t gui_halt_detail_t::gui_line_button_t::welt; static const char *sort_text[4] = { "Zielort", "via", "via Menge", "Menge" }; const char cost_type[MAX_HALT_COST][64] = { "Happy", "Unhappy", "No Route", "hl_btn_sort_waiting", "Arrived", "Departed", "Convoys", "Walked" }; const uint8 index_of_haltinfo[MAX_HALT_COST] = { HALT_HAPPY, HALT_UNHAPPY, HALT_NOROUTE, HALT_WAITING, HALT_ARRIVED, HALT_DEPARTED, HALT_CONVOIS_ARRIVED, HALT_WALKED }; const uint8 cost_type_color[MAX_HALT_COST] = { COL_HAPPY, COL_UNHAPPY, COL_NO_ROUTE, COL_WAITING, COL_ARRIVED, COL_DEPARTED, COL_CONVOI_COUNT, COL_LILAC }; struct type_symbol_t { haltestelle_t::stationtyp type; const skin_desc_t **desc; }; const type_symbol_t symbols[] = { { haltestelle_t::railstation, &skinverwaltung_t::zughaltsymbol }, { haltestelle_t::loadingbay, &skinverwaltung_t::autohaltsymbol }, { haltestelle_t::busstop, &skinverwaltung_t::bushaltsymbol }, { haltestelle_t::dock, &skinverwaltung_t::schiffshaltsymbol }, { haltestelle_t::airstop, &skinverwaltung_t::airhaltsymbol }, { haltestelle_t::monorailstop, &skinverwaltung_t::monorailhaltsymbol }, { haltestelle_t::tramstop, &skinverwaltung_t::tramhaltsymbol }, { haltestelle_t::maglevstop, &skinverwaltung_t::maglevhaltsymbol }, { haltestelle_t::narrowgaugestop, &skinverwaltung_t::narrowgaugehaltsymbol } }; // helper class gui_halt_type_images_t::gui_halt_type_images_t(halthandle_t h) { halt = h; set_table_layout(lengthof(symbols), 1); set_alignment(ALIGN_LEFT | ALIGN_CENTER_V); assert( lengthof(img_transport) == lengthof(symbols) ); // indicator for supplied transport modes haltestelle_t::stationtyp const halttype = halt->get_station_type(); for(uint i=0; i < lengthof(symbols); i++) { if ( *symbols[i].desc ) { add_component(img_transport + i); img_transport[i].set_image( (*symbols[i].desc)->get_image_id(0)); img_transport[i].enable_offset_removal(true); img_transport[i].set_visible( (halttype & symbols[i].type) != 0); } } } void gui_halt_type_images_t::draw(scr_coord offset) { haltestelle_t::stationtyp const halttype = halt->get_station_type(); for(uint i=0; i < lengthof(symbols); i++) { img_transport[i].set_visible( (halttype & symbols[i].type) != 0); } gui_aligned_container_t::draw(offset); } // main class halt_info_t::halt_info_t(halthandle_t halt) : gui_frame_t("", NULL), departure_board( new gui_departure_board_t()), halt_detail( new gui_halt_detail_t(halt)), text_freight(&freight_info), scrolly_freight(&container_freight, true, true), scrolly_departure(departure_board, true, true), scrolly_details(halt_detail, true, true), view(koord3d::invalid, scr_size(max(64, get_base_tile_raster_width()), max(56, get_base_tile_raster_width() * 7 / 8))) { if (halt.is_bound()) { init(halt); } } void halt_info_t::init(halthandle_t halt) { this->halt = halt; set_name(halt->get_name()); set_owner(halt->get_owner() ); halt->set_sortby( env_t::default_sortmode ); set_table_layout(1,0); // top part add_table(2,1)->set_alignment(ALIGN_CENTER_H); { container_top = add_table(1,0); { // input name tstrncpy(edit_name, halt->get_name(), lengthof(edit_name)); input.set_text(edit_name, lengthof(edit_name)); input.set_notify_all_changes_delay(500); // since each letter triggers a tool input.add_listener(this); add_component(&input, 2); // status images add_table(5,1)->set_alignment(ALIGN_CENTER_V); { add_component(&indicator_color); // indicator for enabled freight type img_enable[0].set_image(skinverwaltung_t::passengers->get_image_id(0)); img_enable[1].set_image(skinverwaltung_t::mail->get_image_id(0)); img_enable[2].set_image(skinverwaltung_t::goods->get_image_id(0)); for(uint i=0; i<3; i++) { add_component(img_enable + i); img_enable[i].enable_offset_removal(true); } img_types = new_component(halt); } end_table(); // capacities add_table(6,1); { add_component(&lb_capacity[0]); if (welt->get_settings().is_separate_halt_capacities()) { new_component(skinverwaltung_t::passengers->get_image_id(0), 0, ALIGN_NONE, true); add_component(&lb_capacity[1]); new_component(skinverwaltung_t::mail->get_image_id(0), 0, ALIGN_NONE, true); add_component(&lb_capacity[2]); new_component(skinverwaltung_t::goods->get_image_id(0), 0, ALIGN_NONE, true); } } end_table(); // happy / unhappy / no route add_table(6,1); { add_component(&lb_happy[0]); if (skinverwaltung_t::happy && skinverwaltung_t::unhappy && skinverwaltung_t::no_route) { new_component(skinverwaltung_t::happy->get_image_id(0), 0, ALIGN_NONE, true); add_component(&lb_happy[1]); new_component(skinverwaltung_t::unhappy->get_image_id(0), 0, ALIGN_NONE, true); add_component(&lb_happy[2]); new_component(skinverwaltung_t::no_route->get_image_id(0), 0, ALIGN_NONE, true); } } end_table(); } end_table(); add_component(&view); view.set_location(halt->get_basis_pos3d()); } end_table(); // tabs: waiting, departure, chart add_component(&switch_mode); switch_mode.add_listener(this); switch_mode.add_tab(&scrolly_freight, translator::translate("Hier warten/lagern:")); // list of waiting cargo // sort mode container_freight.set_table_layout(1,0); container_freight.add_table(2,1); container_freight.new_component("Sort waiting list by"); // added sort_button sort_button.init(button_t::roundbox, sort_text[env_t::default_sortmode]); sort_button.set_tooltip("Sort waiting list by"); sort_button.add_listener(this); container_freight.add_component(&sort_button); container_freight.end_table(); container_freight.add_component(&text_freight); // departure board switch_mode.add_tab(&scrolly_departure, translator::translate("Departure board")); departure_board->update_departures(halt); departure_board->set_size( departure_board->get_min_size() ); // connection info switch_mode.add_tab(&scrolly_details, translator::translate("Connections")); halt_detail->update_connections(halt); halt_detail->set_size( halt_detail->get_min_size() ); // chart switch_mode.add_tab(&container_chart, translator::translate("Chart")); container_chart.set_table_layout(D_BUTTONS_PER_ROW,0); container_chart.set_force_equal_columns(true); chart.set_min_size(scr_size(0, CHART_HEIGHT)); chart.set_dimension(12, 10000); chart.set_background(SYSCOL_CHART_BACKGROUND); container_chart.add_component(&chart, D_BUTTONS_PER_ROW); for (int cost = 0; costget_finance_history(), MAX_HALT_COST, index_of_haltinfo[cost], MAX_MONTHS, 0, false, true, 0); button_t *b = container_chart.new_component(); b->init(button_t::box_state_automatic | button_t::flexible, cost_type[cost]); b->background_color = color_idx_to_rgb(cost_type_color[cost]); b->pressed = false; button_to_chart.append(b, &chart, curve); } update_components(); set_resizemode(diagonal_resize); reset_min_windowsize(); set_windowsize(get_min_windowsize()); } halt_info_t::~halt_info_t() { if( halt.is_bound() && strcmp(halt->get_name(),edit_name) && edit_name[0] ) { // text changed => call tool cbuffer_t buf; buf.printf( "h%u,%s", halt.get_id(), edit_name ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); welt->set_tool( tool, halt->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } delete departure_board; delete halt_detail; } koord3d halt_info_t::get_weltpos(bool) { return halt->get_basis_pos3d(); } bool halt_info_t::is_weltpos() { return ( welt->get_viewport()->is_on_center(get_weltpos(false))); } void halt_info_t::update_components() { indicator_color.set_color(halt->get_status_farbe()); lb_capacity[0].buf().printf("%s: %u", translator::translate("Storage capacity"), halt->get_capacity(0)); lb_capacity[0].update(); lb_capacity[1].buf().printf(" %u", halt->get_capacity(1)); lb_capacity[1].update(); lb_capacity[2].buf().printf(" %u", halt->get_capacity(2)); lb_capacity[2].update(); if (skinverwaltung_t::happy && skinverwaltung_t::unhappy && skinverwaltung_t::no_route) { lb_happy[0].buf().printf("%s: %u", translator::translate("Passagiere"), halt->get_pax_happy()); lb_happy[0].update(); lb_happy[1].buf().printf(" %u", halt->get_pax_unhappy()); lb_happy[1].update(); lb_happy[2].buf().printf(" %u", halt->get_pax_no_route()); lb_happy[2].update(); } else { if( has_character( 0x263A ) ) { utf8 happy[4], unhappy[4]; happy[ utf16_to_utf8( 0x263A, happy ) ] = 0; unhappy[ utf16_to_utf8( 0x2639, unhappy ) ] = 0; lb_happy[0].buf().printf(translator::translate("Passengers %d %s, %d %s, %d no route"), halt->get_pax_happy(), happy, halt->get_pax_unhappy(), unhappy, halt->get_pax_no_route()); } else if( has_character( 30 ) ) { lb_happy[0].buf().printf(translator::translate("Passengers %d %c, %d %c, %d no route"), halt->get_pax_happy(), 30, halt->get_pax_unhappy(), 31, halt->get_pax_no_route()); } else { lb_happy[0].buf().printf(translator::translate("Passengers %d %c, %d %c, %d no route"), halt->get_pax_happy(), '+', halt->get_pax_unhappy(), '-', halt->get_pax_no_route()); } lb_happy[0].update(); } img_enable[0].set_visible(halt->get_pax_enabled()); img_enable[1].set_visible(halt->get_mail_enabled()); img_enable[2].set_visible(halt->get_ware_enabled()); container_top->set_size( container_top->get_size()); // buffer update now only when needed by halt itself => dedicated buffer for this int old_len = freight_info.len(); halt->get_freight_info(freight_info); if( old_len != freight_info.len() ) { text_freight.recalc_size(); container_freight.set_size(container_freight.get_min_size()); } if (switch_mode.get_aktives_tab() == &scrolly_departure) { departure_board->update_departures(halt); } if (switch_mode.get_aktives_tab() == &scrolly_details) { halt_detail->update_connections(halt); } set_dirty(); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void halt_info_t::draw(scr_coord pos, scr_size size) { assert(halt.is_bound()); update_components(); gui_frame_t::draw(pos, size); } void gui_halt_detail_t::update_connections( halthandle_t halt ) { if( !halt.is_bound() ) { // first call, or invalid handle remove_all(); return; } if( halt->get_reconnect_counter()==destination_counter && halt->registered_lines.get_count()==cached_line_count && halt->registered_convoys.get_count()==cached_convoy_count ) { // all current, so do nothing return; } // update connections from here remove_all(); const slist_tpl & fab_list = halt->get_fab_list(); slist_tpl nimmt_an; set_table_layout(2,0); new_component_span("Fabrikanschluss", 2); if (!fab_list.empty()) { for(fabrik_t* const fab : fab_list) { const koord3d pos = fab->get_pos(); // target button ... button_t *pb = new_component(); pb->init( button_t::posbutton_automatic, NULL); pb->set_targetpos3d( pos ); // .. name gui_label_buf_t *lb = new_component(); lb->buf().printf("%s (%d, %d)\n", translator::translate(fab->get_name()), pos.x, pos.y); lb->update(); for(ware_production_t const& i : fab->get_input()) { goods_desc_t const* const ware = i.get_typ(); if(!nimmt_an.is_contained(ware)) { nimmt_an.append(ware); } } } } else { insert_show_nothing(); } insert_empty_row(); new_component_span("Angenommene Waren", 2); if (!nimmt_an.empty() && halt->get_ware_enabled()) { for(uint32 i=0; i(); new_component(ware->get_name()); } } } else { insert_show_nothing(); } insert_empty_row(); // add lines that serve this stop new_component_span("Lines serving this stop", 2); if( !halt->registered_lines.empty() ) { simline_t::linetype previous_linetype = simline_t::MAX_LINE_TYPE; vector_tpl sorted_lines; for(linehandle_t l : halt->registered_lines) { if( l.is_bound() ) { sorted_lines.insert_unique_ordered( l, gui_halt_detail_t::compare_line ); } } for(linehandle_t line : sorted_lines) { // Linetype if it is the first if( line->get_linetype() != previous_linetype ) { previous_linetype = line->get_linetype(); new_component_span(simline_t::get_linetype_name(previous_linetype),2); } new_component(line); // Line labels with color of player gui_label_buf_t *lb = new_component(PLAYER_FLAG | color_idx_to_rgb(line->get_owner()->get_player_color1()+env_t::gui_player_color_dark) ); lb->buf().append( line->get_name() ); lb->update(); } } else { insert_show_nothing(); } insert_empty_row(); // add lineless convoys which serve this stop new_component_span("Lineless convoys serving this stop", 2); if( !halt->registered_convoys.empty() ) { for( uint32 i=0; iregistered_convoys.get_count(); ++i ) { convoihandle_t cnv = halt->registered_convoys[i]; // Convoy buttons new_component(cnv); // Line labels with color of player gui_label_buf_t *lb = new_component(PLAYER_FLAG | color_idx_to_rgb(cnv->get_owner()->get_player_color1()+env_t::gui_player_color_dark) ); lb->buf().append( cnv->get_name() ); lb->update(); } } else { insert_show_nothing(); } insert_empty_row(); new_component_span("Direkt erreichbare Haltestellen", 2); bool has_stops = false; for (uint i=0; i const& connections = halt->get_connections(i); if( !connections.empty() ) { gui_label_buf_t *lb = new_component_span(2); lb->buf().append(" \xC2\xB7"); const goods_desc_t* info = goods_manager_t::get_info_catg_index(i); // If it is a special freight, we display the name of the good, otherwise the name of the category. lb->buf().append(translator::translate(info->get_catg()==0 ? info->get_name() : info->get_catg_name() ) ); #if MSG_LEVEL>=4 if( halt->is_transfer(i) ) { lb->buf().append("*"); } #endif lb->buf().append(":\n"); lb->update(); vector_tpl sorted; for(haltestelle_t::connection_t const& conn : connections) { if( conn.halt.is_bound() ) { sorted.insert_unique_ordered(conn, gui_halt_detail_t::compare_connection); } } for(haltestelle_t::connection_t const& conn : sorted) { has_stops = true; button_t *pb = new_component(); pb->init( button_t::posbutton_automatic, NULL); pb->set_targetpos3d( conn.halt->get_basis_pos3d() ); gui_label_buf_t *lb = new_component(); lb->buf().printf("%s <%u>", conn.halt->get_name(), conn.weight); lb->update(); } } } if (!has_stops) { insert_show_nothing(); } // ok, we have now this counter for pending updates destination_counter = halt->get_reconnect_counter(); cached_line_count = halt->registered_lines.get_count(); cached_convoy_count = halt->registered_convoys.get_count(); set_size( get_min_size() ); } // a sophisticated guess of a convois arrival time, taking into account the braking too and the current convoi state uint32 gui_departure_board_t::calc_ticks_until_arrival( convoihandle_t cnv ) { /* calculate the time needed: * tiles << (8+12) / (kmh_to_speed(max_kmh) = ticks */ uint32 delta_t = 0; sint32 delta_tiles = cnv->get_route()->get_count() - cnv->front()->get_route_index(); uint32 kmh_average = (cnv->get_average_kmh()*900 ) / 1024u; // last braking tile if( delta_tiles > 1 && kmh_average > 25 ) { delta_tiles --; delta_t += 3276; // ( (1 << (8+12)) / kmh_to_speed(25) ); } // second last braking tile if( delta_tiles > 1 && kmh_average > 50 ) { delta_tiles --; delta_t += 1638; // ( (1 << (8+12)) / kmh_to_speed(50) ); } // third last braking tile if( delta_tiles > 1 && kmh_average > 100 ) { delta_tiles --; delta_t += 819; // ( (1 << (8+12)) / kmh_to_speed(100) ); } // waiting at signal? if( cnv->get_state() != convoi_t::DRIVING ) { // extra time for acceleration delta_t += kmh_average * 25; } delta_t += ( ((sint64)delta_tiles << (8+12) ) / kmh_to_speed( kmh_average ) ); return delta_t; } // refreshes the departure string void gui_departure_board_t::update_departures(halthandle_t halt) { if (!halt.is_bound()) { return; } if (--next_refresh >= 0) { return; } vector_tpl old_origins(origins); destinations.clear(); origins.clear(); const uint32 cur_ticks = welt->get_ticks() % welt->ticks_per_world_month; static uint32 last_ticks = 0; if( last_ticks > cur_ticks ) { // new month has started => invalidate average buffer old_origins.clear(); } last_ticks = cur_ticks; // iterate over all convoys stopping here for(convoihandle_t cnv : halt->get_loading_convois() ) { if( !cnv.is_bound() || cnv->get_state()!=convoi_t::LOADING ) { continue; } halthandle_t next_halt = cnv->get_schedule()->get_next_halt(cnv->get_owner(),halt); if( next_halt.is_bound() ) { uint32 delta_ticks = 0; if( cnv->get_schedule()->get_current_entry().get_absolute_departures() ) { // absolute schedule delta_ticks = cnv->get_departure_ticks(); } else if( cnv->get_schedule()->get_current_entry().waiting_time > 0 ) { // waiting for load with max time delta_ticks = cnv->get_arrival_ticks() + cnv->get_schedule()->get_current_entry().get_waiting_ticks(); } // avoid overflow when departure time has passed but convoi is still loading etc. uint32 ct = welt->get_ticks(); if (ct > delta_ticks) { delta_ticks = 0; } else { delta_ticks -= ct; } dest_info_t next( next_halt, delta_ticks, cnv ); destinations.append_unique( next ); if( grund_t *gr = welt->lookup( cnv->get_vehicle(0)->last_stop_pos ) ) { if( gr->get_halt().is_bound() && gr->get_halt() != halt ) { dest_info_t prev( gr->get_halt(), 0, cnv ); origins.append_unique( prev ); } } } } // now exactly the same for convoys en route; the only change is that we estimate their arrival time too for(linehandle_t line : halt->registered_lines ) { for( uint j = 0; j < line->count_convoys(); j++ ) { convoihandle_t cnv = line->get_convoy(j); if( cnv.is_bound() && ( cnv->get_state() == convoi_t::DRIVING || cnv->is_waiting() ) && haltestelle_t::get_halt( cnv->get_schedule()->get_current_entry().pos, cnv->get_owner() ) == halt ) { halthandle_t prev_halt = haltestelle_t::get_halt( cnv->front()->last_stop_pos, cnv->get_owner() ); sint32 delta_t = calc_ticks_until_arrival( cnv ); if( prev_halt.is_bound() ) { dest_info_t prev( prev_halt, delta_t, cnv ); // smooth times a little for(dest_info_t &elem : old_origins ) { if( elem.cnv == cnv ) { delta_t = ( delta_t + 3*elem.delta_ticks ) / 4; prev.delta_ticks = delta_t; break; } } origins.insert_ordered( prev, compare_hi ); } halthandle_t next_halt = cnv->get_schedule()->get_next_halt(cnv->get_owner(),halt); if( next_halt.is_bound() ) { if( cnv->get_schedule()->get_current_entry().get_absolute_departures() ) { delta_t = cnv->get_departure_ticks( welt->get_ticks()+delta_t )-welt->get_ticks(); } else if( cnv->get_schedule()->get_current_entry().waiting_time > 0 ) { // waiting for load with max time delta_t += cnv->get_schedule()->get_current_entry().get_waiting_ticks(); } else { delta_t += 2000; } dest_info_t next( next_halt, delta_t+2000, cnv ); destinations.insert_ordered( next, compare_hi ); } } } } for(convoihandle_t cnv : halt->registered_convoys ) { if( cnv.is_bound() && ( cnv->get_state() == convoi_t::DRIVING || cnv->is_waiting() ) && haltestelle_t::get_halt( cnv->get_schedule()->get_current_entry().pos, cnv->get_owner() ) == halt ) { halthandle_t prev_halt = haltestelle_t::get_halt( cnv->front()->last_stop_pos, cnv->get_owner() ); sint32 delta_t = cur_ticks + calc_ticks_until_arrival( cnv ); if( prev_halt.is_bound() ) { dest_info_t prev( prev_halt, delta_t, cnv ); // smooth times a little for(dest_info_t &elem : old_origins ) { if( elem.cnv == cnv ) { delta_t = ( delta_t + 3*elem.delta_ticks ) / 4; prev.delta_ticks = delta_t; break; } } origins.insert_ordered( prev, compare_hi ); } halthandle_t next_halt = cnv->get_schedule()->get_next_halt(cnv->get_owner(),halt); if( next_halt.is_bound() ) { dest_info_t next( next_halt, delta_t+2000, cnv ); destinations.insert_ordered( next, compare_hi ); } } } // fill the board remove_all(); add_component( &absolute_times,3 ); slist_tpl exclude; if( destinations.get_count()>0 ) { new_component_span("Departures to\n", 3); for(dest_info_t hi : destinations ) { if( freight_list_sorter_t::by_via_sum != env_t::default_sortmode || !exclude.is_contained( hi.halt ) ) { gui_label_buf_t *lb = new_component(SYSCOL_TEXT, gui_label_t::right); if( hi.delta_ticks == 0 ) { lb->buf().append( translator::translate( "now" ) ); } else { if( absolute_times.pressed ) { lb->buf().printf( "%s", tick_to_string( welt->get_ticks()+hi.delta_ticks, true ) ); } else { lb->buf().printf( "%s", difftick_to_string( hi.delta_ticks, true ) ); } } lb->update(); insert_image(hi.cnv); new_component(hi.halt->get_name() ); exclude.append( hi.halt ); } } } exclude.clear(); if( origins.get_count()>0 ) { new_component_span("Arrivals from\n", 3); for(dest_info_t hi : origins ) { if( freight_list_sorter_t::by_via_sum != env_t::default_sortmode || !exclude.is_contained( hi.halt ) ) { gui_label_buf_t *lb = new_component(SYSCOL_TEXT, gui_label_t::right); if( hi.delta_ticks == 0 ) { lb->buf().append( translator::translate( "now" ) ); } else { if( absolute_times.pressed ) { lb->buf().printf( "%s", tick_to_string( welt->get_ticks()+hi.delta_ticks, true ) ); } else { lb->buf().printf( "%s", difftick_to_string( hi.delta_ticks, true ) ); } } lb->update(); insert_image(hi.cnv); new_component(hi.halt->get_name() ); exclude.append( hi.halt ); } } } set_size( get_min_size() ); next_refresh = 5; } void gui_departure_board_t::insert_image(convoihandle_t cnv) { gui_image_t *im = NULL; switch(cnv->front()->get_waytype()) { case road_wt: { if (cnv->front()->get_cargo_type() == goods_manager_t::passengers) { im = new_component(skinverwaltung_t::bushaltsymbol->get_image_id(0)); } else { im = new_component(skinverwaltung_t::autohaltsymbol->get_image_id(0)); } break; } case track_wt: { if (cnv->front()->get_desc()->get_waytype() == tram_wt) { im = new_component(skinverwaltung_t::tramhaltsymbol->get_image_id(0)); } else { im = new_component(skinverwaltung_t::zughaltsymbol->get_image_id(0)); } break; } case water_wt: im = new_component(skinverwaltung_t::schiffshaltsymbol->get_image_id(0)); break; case air_wt: im = new_component(skinverwaltung_t::airhaltsymbol->get_image_id(0)); break; case monorail_wt: im = new_component(skinverwaltung_t::monorailhaltsymbol->get_image_id(0)); break; case maglev_wt: im = new_component(skinverwaltung_t::maglevhaltsymbol->get_image_id(0)); break; case narrowgauge_wt: im = new_component(skinverwaltung_t::narrowgaugehaltsymbol->get_image_id(0)); break; default: new_component(); break; } if (im) { im->enable_offset_removal(true); } } /** * This method is called if an action is triggered */ bool halt_info_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if (comp == &sort_button) { env_t::default_sortmode = ((int)(halt->get_sortby())+1)%4; halt->set_sortby((freight_list_sorter_t::sort_mode_t) env_t::default_sortmode); sort_button.set_text(sort_text[env_t::default_sortmode]); } else if( comp == &input ) { if (strcmp(halt->get_name(), edit_name)) { // text changed => call tool cbuffer_t buf; buf.printf( "h%u,%s", halt.get_id(), edit_name ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); welt->set_tool( tool, halt->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } } else if (comp == &switch_mode) { departure_board->next_refresh = -1; } return true; } void halt_info_t::map_rotate90( sint16 new_ysize ) { view.map_rotate90(new_ysize); } void halt_info_t::rdwr(loadsave_t *file) { // window size scr_size size = get_windowsize(); size.rdwr( file ); // halt koord3d halt_pos; if( file->is_saving() ) { halt_pos = halt->get_basis_pos3d(); } halt_pos.rdwr( file ); if( file->is_loading() ) { halt = welt->lookup( halt_pos )->get_halt(); if (halt.is_bound()) { init(halt); win_set_magic(this, magic_halt_info+halt.get_id()); reset_min_windowsize(); set_windowsize(size); } } // sort file->rdwr_byte( env_t::default_sortmode ); scrolly_freight.rdwr(file); scrolly_departure.rdwr(file); switch_mode.rdwr(file); // button-to-chart array button_to_chart.rdwr(file); if (!halt.is_bound()) { destroy_win( this ); } } simutrans-124.3/src/simutrans/gui/halt_info.h000066400000000000000000000054611474050137200212750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HALT_INFO_H #define GUI_HALT_INFO_H #include "gui_frame.h" #include "components/gui_label.h" #include "components/gui_scrollpane.h" #include "components/gui_textarea.h" #include "components/gui_textinput.h" #include "components/gui_button.h" #include "components/gui_button_to_chart.h" #include "components/gui_location_view.h" #include "components/gui_tab_panel.h" #include "components/action_listener.h" #include "components/gui_chart.h" #include "components/gui_image.h" #include "components/gui_colorbox.h" #include "../utils/cbuffer.h" #include "../simhalt.h" #include "simwin.h" class gui_departure_board_t; class gui_halt_detail_t; /** * Helper class to show type symbols (train, bus, etc) */ class gui_halt_type_images_t : public gui_aligned_container_t { halthandle_t halt; gui_image_t img_transport[9]; public: gui_halt_type_images_t(halthandle_t h); void draw(scr_coord offset) OVERRIDE; }; /** * Main class: the station info window. * Window with destination information for a stop */ class halt_info_t : public gui_frame_t, private action_listener_t { private: gui_aligned_container_t *container_top; gui_label_buf_t lb_capacity[3], lb_happy[3]; gui_colorbox_t indicator_color; gui_image_t img_enable[3]; gui_halt_type_images_t *img_types; /** * Buffer for freight info text string. */ cbuffer_t freight_info; // departure stuff (departure and arrival times display) gui_departure_board_t *departure_board; // halt connections plane gui_halt_detail_t *halt_detail; // other UI definitions gui_aligned_container_t container_freight, container_chart; gui_textarea_t text_freight; gui_scrollpane_t scrolly_freight, scrolly_departure, scrolly_details; gui_textinput_t input; gui_chart_t chart; location_view_t view; button_t sort_button; gui_button_to_chart_array_t button_to_chart; gui_tab_panel_t switch_mode; halthandle_t halt; char edit_name[256]; void update_components(); void init(halthandle_t halt); public: halt_info_t(halthandle_t halt = halthandle_t()); virtual ~halt_info_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "station.txt";} /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; koord3d get_weltpos(bool) OVERRIDE; bool is_weltpos() OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_halt_info+halt.get_id(); } }; #endif simutrans-124.3/src/simutrans/gui/halt_list_filter_frame.cc000066400000000000000000000134741474050137200241750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "halt_list_filter_frame.h" #include "../simcolor.h" #include "../descriptor/goods_desc.h" #include "../builder/goods_manager.h" #include "../dataobj/translator.h" const char *halt_list_filter_frame_t::filter_buttons_text[FILTER_BUTTONS] = { "hlf_chk_spezial_filter", "hlf_chk_waren_annahme", "hlf_chk_waren_abgabe", "hlf_chk_overflow", "hlf_chk_keine_verb" }; halt_list_frame_t::filter_flag_t halt_list_filter_frame_t::filter_buttons_types[FILTER_BUTTONS] = { halt_list_frame_t::spezial_filter, halt_list_frame_t::ware_an_filter, halt_list_frame_t::ware_ab_filter, halt_list_frame_t::ueberfuellt_filter, halt_list_frame_t::ohneverb_filter }; halt_list_filter_frame_t::halt_list_filter_frame_t(player_t *player, halt_list_frame_t *main_frame) : gui_frame_t( translator::translate("hlf_title"), player), ware_scrolly_ab(&ware_cont_ab), ware_scrolly_an(&ware_cont_an) { this->main_frame = main_frame; // init buttons for( int i=0; i(); special_filter.add_component(filter_buttons + 3); special_filter.new_component(); special_filter.add_component(filter_buttons + 4); } // second columns: accepted cargo types accepts_filter.set_table_layout(1,0); { accepts_filter.add_component(filter_buttons + 1); accepts_filter.add_table(3,0); { ware_alle_an.init(button_t::roundbox, "hlf_btn_alle"); ware_alle_an.add_listener(this); accepts_filter.add_component(&ware_alle_an); ware_keine_an.init(button_t::roundbox, "hlf_btn_keine"); ware_keine_an.add_listener(this); accepts_filter.add_component(&ware_keine_an); ware_invers_an.init(button_t::roundbox, "hlf_btn_invers"); ware_invers_an.add_listener(this); accepts_filter.add_component(&ware_invers_an); } accepts_filter.end_table(); ware_scrolly_an.set_scroll_amount_y(D_BUTTON_HEIGHT); accepts_filter.add_component(&ware_scrolly_an); ware_cont_an.set_table_layout(2,0); for( int i=0; i(this, (const goods_desc_t*)NULL, ware); item->init(button_t::square, translator::translate(ware->get_name())); } } } // second columns: outgoing cargo types sends_filter.set_table_layout(1,0); { sends_filter.add_component(filter_buttons + 2); sends_filter.add_table(3,0); { ware_alle_ab.init(button_t::roundbox, "hlf_btn_alle"); ware_alle_ab.add_listener(this); sends_filter.add_component(&ware_alle_ab); ware_keine_ab.init(button_t::roundbox, "hlf_btn_keine"); ware_keine_ab.add_listener(this); sends_filter.add_component(&ware_keine_ab); ware_invers_ab.init(button_t::roundbox, "hlf_btn_invers"); ware_invers_ab.add_listener(this); sends_filter.add_component(&ware_invers_ab); } sends_filter.end_table(); ware_scrolly_ab.set_scroll_amount_y(D_BUTTON_HEIGHT); sends_filter.add_component(&ware_scrolly_ab); ware_cont_ab.set_table_layout(2,0); for( int i=0; i(this, ware, (const goods_desc_t*)NULL); item->init(button_t::square, translator::translate(ware->get_name())); } } } set_resizemode(diagonal_resize); reset_min_windowsize(); } halt_list_filter_frame_t::~halt_list_filter_frame_t() { main_frame->filter_frame_closed(); } /** * This method is called if an action is triggered */ bool halt_list_filter_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { for (int i = 0; i < FILTER_BUTTONS; i++) { if (comp == filter_buttons + i) { main_frame->set_filter(filter_buttons_types[i], !main_frame->get_filter(filter_buttons_types[i])); main_frame->sort_list(); return true; } } if (comp == &ware_alle_ab) { main_frame->set_alle_ware_filter_ab(1); main_frame->sort_list(); return true; } if (comp == &ware_keine_ab) { main_frame->set_alle_ware_filter_ab(0); main_frame->sort_list(); return true; } if (comp == &ware_invers_ab) { main_frame->set_alle_ware_filter_ab(-1); main_frame->sort_list(); return true; } if (comp == &ware_alle_an) { main_frame->set_alle_ware_filter_an(1); main_frame->sort_list(); return true; } if (comp == &ware_keine_an) { main_frame->set_alle_ware_filter_an(0); main_frame->sort_list(); return true; } if (comp == &ware_invers_an) { main_frame->set_alle_ware_filter_an(-1); main_frame->sort_list(); return true; } if (comp == &name_filter_input) { main_frame->sort_list(); return true; } return false; } void halt_list_filter_frame_t::ware_item_triggered(const goods_desc_t *ware_ab, const goods_desc_t *ware_an) { if (ware_ab) { main_frame->set_ware_filter_ab(ware_ab, -1); } if (ware_an) { main_frame->set_ware_filter_an(ware_an, -1); } main_frame->sort_list(); } void halt_list_filter_frame_t::draw(scr_coord pos, scr_size size) { for(int i = 0; i < FILTER_BUTTONS; i++) { filter_buttons[i].pressed = main_frame->get_filter(filter_buttons_types[i]); } gui_frame_t::draw(pos, size); } simutrans-124.3/src/simutrans/gui/halt_list_filter_frame.h000066400000000000000000000070611474050137200240320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HALT_LIST_FILTER_FRAME_H #define GUI_HALT_LIST_FILTER_FRAME_H #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_aligned_container.h" #include "components/gui_button.h" #include "components/gui_label.h" #include "components/gui_scrollpane.h" #include "components/gui_tab_panel.h" #include "components/gui_textinput.h" #include "halt_list_frame.h" class player_t; /** * Stations/stops list filter dialog * Displays filter settings for the halt list */ class halt_list_filter_frame_t : public gui_frame_t , private action_listener_t { private: /** * Helper class for the entries of the scrollable list of goods. * Needed since a button_t does not know its parent. */ class ware_item_t : public button_t { const goods_desc_t *ware_ab; const goods_desc_t *ware_an; halt_list_filter_frame_t *parent; public: ware_item_t(halt_list_filter_frame_t *parent, const goods_desc_t *ware_ab, const goods_desc_t *ware_an) { this->ware_ab = ware_ab; this->ware_an = ware_an; this->parent = parent; } bool infowin_event(event_t const* const ev) OVERRIDE { bool swallow = button_t::infowin_event( ev ); if( swallow && IS_LEFTRELEASE(ev) ) { // only handle, if we are hit! parent->ware_item_triggered( ware_ab, ware_an ); } return swallow; } void draw(scr_coord offset) OVERRIDE { if(ware_ab) { pressed = parent->get_ware_filter_ab(ware_ab); } if(ware_an) { pressed = parent->get_ware_filter_an(ware_an); } button_t::draw(offset); } }; /** * As long we do not have resource scripts, we display make * some tables for the main attributes of each button. */ enum { FILTER_BUTTONS = 5 }; static halt_list_frame_t::filter_flag_t filter_buttons_types[FILTER_BUTTONS]; static const char *filter_buttons_text[FILTER_BUTTONS]; /** * We are bound to this window. All filter states are stored in main_frame. */ halt_list_frame_t *main_frame; /** * All gui elements of this dialog: */ button_t filter_buttons[FILTER_BUTTONS]; gui_aligned_container_t special_filter, accepts_filter, sends_filter; gui_tab_panel_t tabs; gui_textinput_t name_filter_input; button_t typ_filter_enable; button_t ware_alle_ab; button_t ware_keine_ab; button_t ware_invers_ab; gui_aligned_container_t ware_cont_ab; gui_scrollpane_t ware_scrolly_ab; button_t ware_alle_an; button_t ware_keine_an; button_t ware_invers_an; gui_aligned_container_t ware_cont_an; gui_scrollpane_t ware_scrolly_an; public: halt_list_filter_frame_t(player_t *player, halt_list_frame_t *main_frame); ~halt_list_filter_frame_t(); /** * Propagate function from main_frame for ware_item_t */ bool get_ware_filter_ab(const goods_desc_t *ware) const { return main_frame->get_ware_filter_ab(ware); } bool get_ware_filter_an(const goods_desc_t *ware) const { return main_frame->get_ware_filter_an(ware); } /** * Handler for ware_item_t event. */ void ware_item_triggered(const goods_desc_t *ware_ab, const goods_desc_t *ware_an); /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "haltlist_filter.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/halt_list_frame.cc000066400000000000000000000304421474050137200226220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "halt_list_frame.h" #include "halt_list_filter_frame.h" #include "../player/simplay.h" #include "../simhalt.h" #include "../simware.h" #include "../simfab.h" #include "../utils/unicode.h" #include "simwin.h" #include "../descriptor/skin_desc.h" #include "../builder/goods_manager.h" #include "../dataobj/translator.h" #include "../utils/cbuffer.h" /** * Scrolled list of halt_list_stats_ts. * Filters (by setting visibility) and sorts. */ class gui_scrolled_halt_list_t : public gui_scrolled_list_t { public: gui_scrolled_halt_list_t() : gui_scrolled_list_t(gui_scrolled_list_t::windowskin, compare) {} void sort() { gui_scrolled_list_t::sort(0); } static bool compare(const gui_component_t *aa, const gui_component_t *bb) { const halt_list_stats_t *a = dynamic_cast(aa); const halt_list_stats_t *b = dynamic_cast(bb); return halt_list_frame_t::compare_halts(a->get_halt(), b->get_halt()); } }; /** * All filter and sort settings are static, so the old settings are * used when the window is reopened. */ /** * This variable defines by which column the table is sorted */ halt_list_frame_t::sort_mode_t halt_list_frame_t::sortby = nach_name; /** * This variable defines the sort order (ascending or descending) * Values: 1 = ascending, 2 = descending) */ bool halt_list_frame_t::sortreverse = false; /** * Default filter: no Oil rigs! */ uint8 halt_list_frame_t::filter_flags = 0; char halt_list_frame_t::name_filter[256] = ""; slist_tpl halt_list_frame_t::waren_filter_ab; slist_tpl halt_list_frame_t::waren_filter_an; const char *halt_list_frame_t::sort_text[SORT_MODES] = { "hl_btn_sort_name", "hl_btn_sort_waiting", "hl_btn_sort_type" }; /** * This function compares two stations * * @return halt1 < halt2 */ bool halt_list_frame_t::compare_halts(halthandle_t const halt1, halthandle_t const halt2) { int order; /*********************************** * Compare station 1 and station 2 ***********************************/ switch (sortby) { default: case nach_name: // sort by station name order = 0; break; case nach_wartend: // sort by waiting goods order = (int)(halt1->get_finance_history( 0, HALT_WAITING ) - halt2->get_finance_history( 0, HALT_WAITING )); break; case nach_typ: // sort by station type order = halt1->get_station_type() - halt2->get_station_type(); break; } /** * use name as an additional sort, to make sort more stable. */ if(order == 0) { order = strcmp(halt1->get_name(), halt2->get_name()); } /*********************************** * Consider sorting order ***********************************/ return sortreverse ? order > 0 : order < 0; } halt_list_frame_t::halt_list_frame_t() : gui_frame_t( translator::translate("hl_title"), welt->get_active_player()) { m_player = welt->get_active_player(); filter_frame = NULL; set_table_layout(1, 0); add_table(4, 2); { new_component("Filter:", 2); name_filter_input.set_text(name_filter, lengthof(name_filter)); add_component(&name_filter_input); filter_details.init(button_t::roundbox, "cl_btn_filter_settings"); filter_details.add_listener(this); add_component(&filter_details); new_component(); new_component_span("hl_txt_sort", 1); sortedby.set_unsorted(); // do not sort for (size_t i = 0; i < lengthof(sort_text); i++) { sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); } sortedby.set_selection(get_sortierung()); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_state, NULL); sorteddir.add_listener(this); sorteddir.pressed = get_reverse(); add_component(&sorteddir); new_component(); } end_table(); scrolly = new gui_scrolled_halt_list_t(); scrolly->set_maximize(true); scrolly->set_checkered(true); tabs.init_tabs(scrolly); tabs.add_listener(this); add_component(&tabs); sort_list(); set_resizemode(diagonal_resize); set_resizemode(diagonal_resize); reset_min_windowsize(); } halt_list_frame_t::~halt_list_frame_t() { if(filter_frame) { destroy_win(filter_frame); } } static bool passes_filter_special(haltestelle_t const& s) { if (!halt_list_frame_t::get_filter(halt_list_frame_t::spezial_filter)) return true; if (halt_list_frame_t::get_filter(halt_list_frame_t::ueberfuellt_filter)) { PIXVAL const color = s.get_status_farbe(); if (color == color_idx_to_rgb(COL_RED) || color == color_idx_to_rgb(COL_ORANGE)) { return true; // overcrowded } } if (halt_list_frame_t::get_filter(halt_list_frame_t::ohneverb_filter)) { for (uint8 i = 0; i < goods_manager_t::get_max_catg_index(); ++i) { if (!s.get_connections(i).empty()) return false; // only display stations with NO connection } return true; } return false; } static bool passes_filter_out(haltestelle_t const& s) { if (!halt_list_frame_t::get_filter(halt_list_frame_t::ware_ab_filter)) return true; /* * Die Unterkriterien werden gebildet aus: * - die Ware wird produziert (pax/post_enabled bzw. fabrik vorhanden) * - es existiert eine Zugverbindung mit dieser Ware (!ziele[...].empty()) */ for (uint32 i = 0; i != goods_manager_t::get_count(); ++i) { goods_desc_t const* const ware = goods_manager_t::get_info(i); if (!halt_list_frame_t::get_ware_filter_ab(ware)) continue; if (ware == goods_manager_t::passengers) { if (s.get_pax_enabled()) return true; } else if (ware == goods_manager_t::mail) { if (s.get_mail_enabled()) return true; } else if (ware != goods_manager_t::none) { // Sigh - a doubly nested loop per halt // Fortunately the number of factories and their number of outputs // is limited (usually 1-2 factories and 0-1 outputs per factory) for(fabrik_t* const f : s.get_fab_list()) { for(ware_production_t const& j : f->get_output()) { if (j.get_typ() == ware) return true; } } } } return false; } static bool passes_filter_in(haltestelle_t const& s) { if (!halt_list_frame_t::get_filter(halt_list_frame_t::ware_an_filter)) return true; /* * Die Unterkriterien werden gebildet aus: * - die Ware wird verbraucht (pax/post_enabled bzw. fabrik vorhanden) * - es existiert eine Zugverbindung mit dieser Ware (!ziele[...].empty()) */ for (uint32 i = 0; i != goods_manager_t::get_count(); ++i) { goods_desc_t const* const ware = goods_manager_t::get_info(i); if (!halt_list_frame_t::get_ware_filter_an(ware)) continue; if (ware == goods_manager_t::passengers) { if (s.get_pax_enabled()) return true; } else if (ware == goods_manager_t::mail) { if (s.get_mail_enabled()) return true; } else if (ware != goods_manager_t::none) { // Sigh - a doubly nested loop per halt // Fortunately the number of factories and their number of outputs // is limited (usually 1-2 factories and 0-1 outputs per factory) for(fabrik_t* const f : s.get_fab_list()) { for(ware_production_t const& j : f->get_input()) { if (j.get_typ() == ware) return true; } } } } return false; } /** * Check all filters for one halt. * returns true, if it is not filtered away. */ static bool passes_filter(haltestelle_t const& s) { if (!passes_filter_special(s)) return false; if (!passes_filter_out(s)) return false; if (!passes_filter_in(s)) return false; return true; } /** * This function refreshes the station-list */ void halt_list_frame_t::sort_list() { last_world_stops = haltestelle_t::get_alle_haltestellen().get_count(); // count of stations haltestelle_t::stationtyp current_type = tabs.get_active_tab_stationtype(); scrolly->clear_elements(); for(halthandle_t const halt : haltestelle_t::get_alle_haltestellen()) { if (halt->get_owner() != m_player) { continue; } if (name_filter[0] != 0 && !utf8caseutf8(halt->get_name(), name_filter)) { // not the right name continue; } if (current_type != 0 && (halt->get_station_type() & current_type) == 0) { continue; } if( passes_filter(*halt.get_rep()) ) { scrolly->new_component(halt); } } scrolly->sort(); scrolly->set_size(scr_size(get_windowsize().w, scrolly->get_size().h)); } bool halt_list_frame_t::infowin_event(const event_t *ev) { if(ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE) { if(filter_frame) { filter_frame->infowin_event(ev); } } return gui_frame_t::infowin_event(ev); } /** * This method is called if an action is triggered */ bool halt_list_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if ( comp == &sortedby ) { set_sortierung((sort_mode_t)((get_sortierung() + 1) % SORT_MODES)); sort_list(); } else if (comp == &tabs) { sort_list(); } else if (comp == &sorteddir) { set_reverse(!get_reverse()); sorteddir.pressed = get_reverse(); sort_list(); } else if ( comp == &filter_details ) { if (filter_frame) { destroy_win(filter_frame); } else { filter_frame = new halt_list_filter_frame_t(m_player, this); create_win(filter_frame, w_info, magic_haltlist_filter); } } return true; } void halt_list_frame_t::draw(scr_coord pos, scr_size size) { filter_details.pressed = filter_frame != NULL; if( last_world_stops != haltestelle_t::get_alle_haltestellen().get_count() || strcmp(last_name_filter, name_filter) ) { // some deleted/ added => resort strcpy(last_name_filter, name_filter); sort_list(); } gui_frame_t::draw(pos, size); } void halt_list_frame_t::set_ware_filter_ab(const goods_desc_t *ware, int mode) { if(ware != goods_manager_t::none) { if(get_ware_filter_ab(ware)) { if(mode != 1) { waren_filter_ab.remove(ware); } } else { if(mode != 0) { waren_filter_ab.append(ware); } } } } void halt_list_frame_t::set_ware_filter_an(const goods_desc_t *ware, int mode) { if(ware != goods_manager_t::none) { if(get_ware_filter_an(ware)) { if(mode != 1) { waren_filter_an.remove(ware); } } else { if(mode != 0) { waren_filter_an.append(ware); } } } } void halt_list_frame_t::set_alle_ware_filter_ab(int mode) { if(mode == 0) { waren_filter_ab.clear(); } else { for(unsigned int i = 0; iget_player_nr(); sint16 sort_mode = sortby; file->rdwr_byte(player_nr); size.rdwr(file); tabs.rdwr(file); scrolly->rdwr(file); file->rdwr_str(name_filter, lengthof(name_filter)); file->rdwr_short(sort_mode); file->rdwr_bool(sortreverse); file->rdwr_byte(filter_flags); if (file->is_saving()) { uint8 good_nr = waren_filter_ab.get_count(); file->rdwr_byte(good_nr); if (good_nr > 0) { for(const goods_desc_t* const i : waren_filter_ab) { char* name = const_cast(i->get_name()); file->rdwr_str(name, 256); } } good_nr = waren_filter_an.get_count(); file->rdwr_byte(good_nr); if (good_nr > 0) { for(const goods_desc_t* const i : waren_filter_an) { char* name = const_cast(i->get_name()); file->rdwr_str(name, 256); } } } else { // restore warenfilter uint8 good_nr; file->rdwr_byte(good_nr); if (good_nr > 0) { waren_filter_ab.clear(); for (sint16 i = 0; i < good_nr; i++) { char name[256]; file->rdwr_str(name, lengthof(name)); if (const goods_desc_t* gd = goods_manager_t::get_info(name)) { waren_filter_ab.append(gd); } } } file->rdwr_byte(good_nr); if (good_nr > 0) { waren_filter_an.clear(); for (sint16 i = 0; i < good_nr; i++) { char name[256]; file->rdwr_str(name, lengthof(name)); if (const goods_desc_t* gd = goods_manager_t::get_info(name)) { waren_filter_an.append(gd); } } } sortby = (sort_mode_t)sort_mode; m_player = welt->get_player(player_nr); set_owner(m_player); win_set_magic(this, magic_halt_list + player_nr); sort_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/halt_list_frame.h000066400000000000000000000071001474050137200224570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HALT_LIST_FRAME_H #define GUI_HALT_LIST_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "../simhalt.h" #include "halt_list_stats.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_textinput.h" #include "components/gui_waytype_tab_panel.h" #include "../tpl/vector_tpl.h" class player_t; class goods_desc_t; class gui_scrolled_halt_list_t; /** * Displays a scrollable list of all stations of a player */ class halt_list_frame_t : public gui_frame_t , private action_listener_t { public: enum sort_mode_t { nach_name, nach_wartend, nach_typ, SORT_MODES }; enum filter_flag_t { spezial_filter = 1 << 1, ware_ab_filter = 1 << 2, ware_an_filter = 1 << 3, ueberfuellt_filter = 1 << 4, ohneverb_filter = 1 << 5 }; private: player_t *m_player; static const char *sort_text[SORT_MODES]; uint32 last_world_stops; /* * All gui elements of this dialog: */ gui_combobox_t sortedby; button_t sorteddir; button_t filter_details; gui_scrolled_halt_list_t *scrolly; static char name_filter[256]; char last_name_filter[256]; gui_textinput_t name_filter_input; gui_waytype_tab_panel_t tabs; /* * Child window, if open */ gui_frame_t *filter_frame; /* * All filter settings are static, so they are not reset each * time the window closes. */ static sort_mode_t sortby; static bool sortreverse; static uint8 filter_flags; static slist_tpl waren_filter_ab; static slist_tpl waren_filter_an; public: static bool compare_halts(halthandle_t, halthandle_t); halt_list_frame_t(); ~halt_list_frame_t(); /** * The filter frame tells us when it is closed. */ void filter_frame_closed() { filter_frame = NULL; } // must be handled, because we could not use scrollpanel bool infowin_event(event_t const*) OVERRIDE; /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; /// sort & filter halts in list void sort_list(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "haltlist.txt"; } static sort_mode_t get_sortierung() { return sortby; } static void set_sortierung(sort_mode_t sm) { sortby = sm; } static bool get_reverse() { return sortreverse; } static void set_reverse(bool reverse) { sortreverse = reverse; } static bool get_filter(filter_flag_t filter) { return (filter_flags & filter) != 0; } static void set_filter(filter_flag_t filter, bool on) { filter_flags = on ? (filter_flags | filter) : (filter_flags & ~filter); } static bool get_ware_filter_ab(const goods_desc_t *ware) { return waren_filter_ab.is_contained(ware); } static void set_ware_filter_ab(const goods_desc_t *ware, int mode); static void set_alle_ware_filter_ab(int mode); static bool get_ware_filter_an(const goods_desc_t *ware) { return waren_filter_an.is_contained(ware); } static void set_ware_filter_an(const goods_desc_t *ware, int mode); static void set_alle_ware_filter_an(int mode); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void map_rotate90( sint16 ) OVERRIDE { sort_list(); } void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_halt_list; } }; #endif simutrans-124.3/src/simutrans/gui/halt_list_stats.cc000066400000000000000000000060101474050137200226600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "halt_list_stats.h" #include "../simhalt.h" #include "../simskin.h" #include "../simcolor.h" #include "../tool/simtool.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../player/simplay.h" #include "../world/simworld.h" #include "../display/simimg.h" #include "../dataobj/translator.h" #include "../descriptor/skin_desc.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "gui_frame.h" #include "halt_info.h" // gui_halt_type_images_t static karte_ptr_t welt; /** * Events are notified to GUI components via this method */ bool halt_list_stats_t::infowin_event(const event_t *ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if( !swallowed && halt.is_bound() ) { if(IS_LEFTRELEASE(ev)) { if ((event_get_last_control_shift() ^ tool_t::control_invert) == 2) { welt->get_viewport()->change_world_position(halt->get_basis_pos3d()); } else { halt->open_info_window(); } return true; } if( IS_RIGHTRELEASE(ev) ) { welt->get_viewport()->change_world_position(halt->get_basis_pos3d()); return true; } } return swallowed; } halt_list_stats_t::halt_list_stats_t(halthandle_t h) { halt = h; set_table_layout(2,2); set_spacing(scr_size(D_H_SPACE, 0)); gotopos.set_typ(button_t::posbutton_automatic); gotopos.set_targetpos3d(halt->get_basis_pos3d()); add_component(&gotopos); add_table(2,1); { add_component(&label_name); label_name.buf().append(halt->get_name()); label_name.update(); img_types = new_component(halt); } end_table(); // second row, skip posbutton new_component(); add_table(4,1); { add_component(&img_enabled[0]); img_enabled[0].set_image(skinverwaltung_t::passengers->get_image_id(0), true); add_component(&img_enabled[1]); img_enabled[1].set_image(skinverwaltung_t::mail->get_image_id(0), true); add_component(&img_enabled[2]); img_enabled[2].set_image(skinverwaltung_t::goods->get_image_id(0), true); img_enabled[0].set_rigid(true); img_enabled[1].set_rigid(true); img_enabled[2].set_rigid(true); add_component(&label_cargo); halt->get_short_freight_info( label_cargo.buf() ); label_cargo.update(); } end_table(); } const char* halt_list_stats_t::get_text() const { return halt->get_name(); } /** * Draw the component */ void halt_list_stats_t::draw(scr_coord offset) { gotopos.set_targetpos3d(halt->get_basis_pos3d()); // since roation may have changed the target pos img_enabled[0].set_visible(halt->get_pax_enabled()); img_enabled[1].set_visible(halt->get_mail_enabled()); img_enabled[2].set_visible(halt->get_ware_enabled()); label_name.buf().append(halt->get_name()); label_name.update(); label_name.set_color(halt->get_status_farbe()); label_name.set_shadow(SYSCOL_TEXT,true); halt->get_short_freight_info( label_cargo.buf() ); label_cargo.update(); set_size(get_size()); gui_aligned_container_t::draw(offset); } simutrans-124.3/src/simutrans/gui/halt_list_stats.h000066400000000000000000000024721474050137200225320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HALT_LIST_STATS_H #define GUI_HALT_LIST_STATS_H #include "components/gui_component.h" #include "components/gui_aligned_container.h" #include "components/gui_colorbox.h" #include "components/gui_button.h" #include "components/gui_image.h" #include "components/gui_label.h" #include "components/gui_scrolled_list.h" #include "../halthandle.h" class gui_halt_type_images_t; class halt_list_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: halthandle_t halt; public: gui_label_buf_t label_name, label_cargo; gui_image_t img_enabled[3]; gui_halt_type_images_t *img_types; gui_colorbox_t indicator; button_t gotopos; public: halt_list_stats_t(halthandle_t halt_); bool infowin_event(event_t const*) OVERRIDE; /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; void update_label(); const char* get_text() const OVERRIDE; bool is_valid() const OVERRIDE { return halt.is_bound(); } halthandle_t get_halt() const { return halt; } scr_size get_min_size() const OVERRIDE { return gui_aligned_container_t::get_min_size() + scr_size(D_H_SPACE, D_V_SPACE); } scr_size get_max_size() const OVERRIDE { return get_min_size(); } }; #endif simutrans-124.3/src/simutrans/gui/headquarter_info.cc000066400000000000000000000036331474050137200230070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "headquarter_info.h" #include "simwin.h" #include "../tool/simmenu.h" #include "../world/simworld.h" #include "../obj/gebaeude.h" #include "../player/simplay.h" headquarter_info_t::headquarter_info_t(player_t* player) : base_infowin_t(player->get_name(), player), headquarter_view(koord3d::invalid, scr_size( max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width()*7)/8) ) ) { this->player = player; set_embedded(&headquarter_view); upgrade.init(button_t::roundbox, "upgrade HQ"); upgrade.add_listener(this); add_component(&upgrade); update(); recalc_size(); } void headquarter_info_t::update() { // possibly update hq position const koord p2d = player->get_headquarter_pos(); if (p2d != koord::invalid) { // update hq position grund_t *gr = welt->lookup_kartenboden(p2d); koord3d pos = gr->get_pos(); headquarter_view.set_location(pos); gebaeude_t* hq = gr->find(); if (hq) { buf.clear(); hq->info(buf); } } else { set_embedded(NULL); } // check for possible upgrades const char * c = tool_t::general_tool[TOOL_HEADQUARTER]->get_tooltip(player); if(c) { // only true, if the headquarter can be built/updated headquarter_tooltip.clear(); headquarter_tooltip.append(c); upgrade.set_tooltip(headquarter_tooltip); upgrade.enable(); } else { upgrade.disable(); upgrade.set_tooltip(NULL); } reset_min_windowsize(); } void headquarter_info_t::draw(scr_coord pos, scr_size size) { update(); if (get_embedded() == NULL) { // no headquarter anymore, destroy window destroy_win(this); return; } base_infowin_t::draw(pos, size); } bool headquarter_info_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if( comp == &upgrade ) { welt->set_tool( tool_t::general_tool[TOOL_HEADQUARTER], player ); } return true; } simutrans-124.3/src/simutrans/gui/headquarter_info.h000066400000000000000000000013711474050137200226460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HEADQUARTER_INFO_H #define GUI_HEADQUARTER_INFO_H #include "base_info.h" #include "components/gui_button.h" #include "components/action_listener.h" #include "components/gui_location_view.h" #include "../utils/cbuffer.h" class gebaeude_t; class player_t; class headquarter_info_t : public base_infowin_t, private action_listener_t { button_t upgrade; cbuffer_t headquarter_tooltip; player_t *player; location_view_t headquarter_view; void update(); public: headquarter_info_t(player_t* player); void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t *comp, value_t extra) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/help_frame.cc000066400000000000000000000451201474050137200215660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simmem.h" #include "simwin.h" #include "../tool/simmenu.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../simticker.h" // TICKER_HEIGHT #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../utils/unicode.h" #include "../player/simplay.h" #include "tool_selector.h" #include "help_frame.h" #define DIALOG_MIN_WIDTH (100) help_frame_t::help_frame_t() : gui_frame_t( translator::translate("Help") ) { // info windows do not show general text generaltext.set_visible( false ); set_text("Unnamed

No text set

"); set_table_layout(1,0); helptext.add_listener(this); add_component(&helptext); set_resizemode(diagonal_resize); reset_min_windowsize(); set_windowsize( scr_size( D_MARGIN_LEFT + (D_SCROLLBAR_WIDTH<<1) + DIALOG_MIN_WIDTH + D_MARGIN_RIGHT, D_TITLEBAR_HEIGHT + D_MARGIN_TOP + (D_SCROLLBAR_HEIGHT<<1) + D_MARGIN_BOTTOM) ); } help_frame_t::help_frame_t(char const* const filename) : gui_frame_t( translator::translate("Help") ) { set_table_layout(2,0); set_alignment(ALIGN_TOP | ALIGN_LEFT); set_margin(scr_size(0,D_MARGIN_TOP), scr_size(0,0)); add_component(&generaltext); generaltext.add_listener(this); add_component(&helptext); helptext.add_listener(this); // we now exclusive build out index on the fly slist_tpl already_there; cbuffer_t index_txt; cbuffer_t introduction; cbuffer_t usage; cbuffer_t toolbars; cbuffer_t game_start; cbuffer_t how_to_play; cbuffer_t others; add_helpfile( introduction, NULL, "simutrans.txt", true, 0 ); // main usage section { // get title of keyboard help ... std::string kbtitle = extract_title( translator::translate( "Keyboard Help\n

Keyboard Help

\n" ) ); assert( !kbtitle.empty() ); usage.printf( "%s
\n", kbtitle.c_str() ); } add_helpfile( usage, NULL, "mouse.txt", true, 0 ); add_helpfile( usage, NULL, "window.txt", true, 0 ); // enumerate toolbars bool special = false; add_helpfile( toolbars, NULL, "mainmenu.txt", false, 0 ); for(toolbar_t * iter : tool_t::toolbar_tool ) { if( strstart(iter->get_tool_selector()->get_help_filename(),"list.txt" ) ) { continue; } add_helpfile( toolbars, translator::translate(iter->get_tool_selector()->get_internal_name()), iter->get_tool_selector()->get_help_filename(), false, 0 ); if( strstart(iter->get_tool_selector()->get_help_filename(),"railtools.txt" ) ) { add_helpfile( toolbars, NULL, "bridges.txt", true, 1 ); add_helpfile( toolbars, NULL, "signals.txt", true, 1 ); add_helpfile( toolbars, "set signal spacing", "signal_spacing.txt", false, 1 ); } if( strstart(iter->get_tool_selector()->get_help_filename(),"roadtools.txt" ) ) { add_helpfile( toolbars, NULL, "privatesign_info.txt", false, 1 ); add_helpfile( toolbars, NULL, "trafficlight_info.txt", false, 1 ); } if( !special && ( strstart(iter->get_tool_selector()->get_help_filename(),"special.txt" ) || strstart(iter->get_tool_selector()->get_help_filename(),"edittools.txt" ) ) ) { special = true; add_helpfile( toolbars, "baum builder", "baum_build.txt", false, 1 ); add_helpfile( toolbars, "citybuilding builder", "citybuilding_build.txt", false, 1 ); add_helpfile( toolbars, "curiosity builder", "curiosity_build.txt", false, 1 ); add_helpfile( toolbars, "factorybuilder", "factory_build.txt", false, 1 ); } } add_helpfile( toolbars, NULL, "inspection_tool.txt", true, 0 ); add_helpfile( toolbars, NULL, "removal_tool.txt", true, 0 ); add_helpfile( toolbars, "LISTTOOLS", "list.txt", false, 0 ); add_helpfile( toolbars, NULL, "citylist_filter.txt", false, 1 ); add_helpfile( toolbars, NULL, "convoi.txt", false, 1 ); add_helpfile( toolbars, NULL, "convoi_filter.txt", false, 2 ); add_helpfile( toolbars, NULL, "curiositylist_filter.txt", false, 1 ); add_helpfile( toolbars, NULL, "factorylist_filter.txt", false, 1 ); add_helpfile( toolbars, NULL, "goods_filter.txt", false, 1 ); add_helpfile( toolbars, NULL, "haltlist.txt", false, 1 ); add_helpfile( toolbars, NULL, "haltlist_filter.txt", false, 2 ); add_helpfile( toolbars, NULL, "labellist_filter.txt", false, 1 ); add_helpfile( game_start, "Neue Welt", "new_world.txt", false, 0 ); add_helpfile( game_start, "Lade Relief", "load_relief.txt", false, 1 ); add_helpfile( game_start, "Climate Control", "climates.txt", false, 1 ); add_helpfile( game_start, "Setting", "settings.txt", false, 1 ); add_helpfile( game_start, "Load game", "load.txt", false, 0 ); add_helpfile( game_start, "Load scenario", "scenario.txt", false, 0 ); add_helpfile( game_start, "join game", "server.txt", false, 0 ); add_helpfile( game_start, "Speichern", "save.txt", false, 0 ); add_helpfile( how_to_play, "Reliefkarte", "map.txt", false, 0 ); add_helpfile( how_to_play, "enlarge map", "enlarge_map.txt", false, 1 ); add_helpfile( how_to_play, NULL, "underground.txt", true, 0 ); add_helpfile( how_to_play, NULL, "citywindow.txt", true, 0 ); add_helpfile( how_to_play, NULL, "depot.txt", false, 0 ); add_helpfile( how_to_play, NULL, "convoiinfo.txt", false, 0 ); add_helpfile( how_to_play, NULL, "convoidetail.txt", false, 1 ); add_helpfile( how_to_play, "Line Management", "linemanagement.txt", false, 0 ); add_helpfile( how_to_play, "Fahrplan", "schedule.txt", false, 1 ); add_helpfile( how_to_play, NULL, "station.txt", false, 0 ); add_helpfile( how_to_play, NULL, "station_details.txt", false, 1 ); add_helpfile( how_to_play, NULL, "industry_info.txt", false, 0 ); add_helpfile( how_to_play, "Spielerliste", "players.txt", false, 0 ); add_helpfile( how_to_play, "Finanzen", "finances.txt", false, 1 ); add_helpfile( how_to_play, "Farbe", "color.txt", false, 1 ); // add_helpfile( how_to_play, "Scenario", "scenario.txt", false, 1 ); add_helpfile( how_to_play, "Enter Password", "password.txt", false, 1 ); add_helpfile( others, "Einstellungen aendern", "options.txt", false, 0 ); add_helpfile( others, "Display settings", "display.txt", false, 0 ); add_helpfile( others, "Mailbox", "mailbox.txt", false, 0 ); add_helpfile( others, "Sound settings", "sound.txt", false, 0 ); add_helpfile( others, "Sprachen", "language.txt", false, 0 ); index_txt.printf( translator::translate("

Index

*: only english

General

%s

Usage

%s

Tools

%s

Start

%s

How to play

%s

Others:

%s"), (const char *)introduction, (const char *)usage, (const char *)toolbars, (const char *)game_start, (const char *)how_to_play, (const char *)others ); generaltext.set_text( index_txt ); set_helpfile( filename, true ); set_resizemode(diagonal_resize); reset_min_windowsize(); set_windowsize(scr_size(200, D_DEFAULT_HEIGHT)); } // opens or tops main helpfile void help_frame_t::open_help_on( const char *helpfilename ) { if( help_frame_t *gui = (help_frame_t *)win_get_magic( magic_mainhelp ) ) { top_win( gui ); gui->set_helpfile( helpfilename, false ); } else { create_win( new help_frame_t( helpfilename ), w_info, magic_mainhelp ); } } // just loads a whole help file as one chunk static char *load_text(char const* const filename ) { std::string file_prefix= std::string("text") + PATH_SEPARATOR; std::string fullname = file_prefix + translator::get_lang()->iso + PATH_SEPARATOR + filename; dr_chdir(env_t::base_dir); FILE* file = dr_fopen(fullname.c_str(), "rb"); if (!file) { //Check for the 'base' language(ie en from en_gb) file = dr_fopen((file_prefix + translator::get_lang()->iso_base + PATH_SEPARATOR + filename).c_str(), "rb"); } if (!file) { // check fallback english file = dr_fopen((file_prefix + PATH_SEPARATOR + "en" + PATH_SEPARATOR + filename).c_str(), "rb"); } if (!file) { // no help file found then sarch [pakset]/text/[lang]/ file = dr_fopen((env_t::pak_dir + file_prefix + translator::get_lang()->iso + PATH_SEPARATOR + filename).c_str(), "rb"); } if (!file) { // no help file found then sarch [pakset]/text/[lang (bese)]/ file = dr_fopen((env_t::pak_dir + file_prefix + translator::get_lang()->iso_base + PATH_SEPARATOR + filename).c_str(), "rb"); } if (!file) { // no help file found then sarch [pakset]/text/en/ file = dr_fopen((env_t::pak_dir + file_prefix + "en" + PATH_SEPARATOR + filename).c_str(), "rb"); } // go back to load/save dir dr_chdir( env_t::user_dir ); if(file) { fseek(file,0,SEEK_END); long len = ftell(file); char *buf = NULL; if( len>0 ) { buf = MALLOCN(char, len + 1); fseek( file, 0, SEEK_SET ); len = fread( buf, 1, len, file); buf[len] = '\0'; fclose( file ); } // now we may need to translate the text ... if( len>0 ) { bool is_latin = strchr( buf, 0xF6 )!=NULL; // "o-umlaut, is forbidden for unicode if( !is_latin && translator::get_lang()->is_latin2_based ) { is_latin |= strchr( buf, 0xF8 )!=NULL; // "o-umlaut, is forbidden for unicode } if( !is_latin && translator::get_lang()->is_latin2_based ) { is_latin |= strchr( buf, 0xFE )!=NULL; // "o-umlaut, is forbidden for unicode } if( !is_latin && translator::get_lang()->is_latin2_based ) { is_latin |= strchr( buf, 0xFA )!=NULL; // "o-umlaut, is forbidden for unicode } if( !is_latin && translator::get_lang()->is_latin2_based ) { is_latin |= strchr( buf, 0xF3 )!=NULL; // "o-umlaut, is forbidden for unicode } if( !is_latin && translator::get_lang()->is_latin2_based ) { is_latin |= strchr( buf, 0xF1 )!=NULL; // "o-umlaut, is forbidden for unicode } if( is_latin ) { // we need to translate charwise ... utf8 *buf2 = MALLOCN(utf8, len*2 + 1); //assume the worst utf8 *src = (utf8 *)buf, *dest = buf2; if( translator::get_lang()->is_latin2_based ) { do { dest += utf16_to_utf8( latin2_to_unicode(*src), dest ); } while( *src++ ); *dest = 0; } else { do { dest += utf16_to_utf8( *src, dest ); } while( *src++ ); *dest = 0; } free( buf ); buf = (char *)buf2; } } return buf; } return NULL; } void help_frame_t::set_text(const char * buf, bool resize_frame ) { helptext.set_text(buf); if( resize_frame ) { // try to get the following sizes // y<400 or, if not possible, x<620 helptext.set_size(scr_size(220, 0)); int last_y = 0; scr_coord curr = helptext.get_preferred_size(); for( int i = 0; i<10 && curr.y>400 && curr.y!=last_y; i++ ) { helptext.set_size(scr_size(260+i*40, 0)); last_y = curr.y; curr = helptext.get_preferred_size(); } helptext.set_size(helptext.get_preferred_size()); if( generaltext.is_visible() ) { generaltext.set_pos( scr_coord(D_MARGIN_LEFT, D_MARGIN_TOP) ); generaltext.set_size( scr_size( min(180,display_get_width()/3), 0 ) ); int generalwidth = min( display_get_width()/3, generaltext.get_preferred_size().w ); generaltext.set_size( scr_size( generalwidth, helptext.get_size().h ) ); generaltext.set_size( generaltext.get_preferred_size() ); } else { generaltext.set_size( scr_size(D_MARGIN_LEFT, D_MARGIN_TOP) ); } // calculate sizes (might not a help but info window, which do not have general text) scr_coord_val size_x = helptext.get_size().w + D_MARGIN_LEFT + D_MARGIN_RIGHT + D_SCROLLBAR_WIDTH; scr_coord_val size_y = helptext.get_size().h + D_TITLEBAR_HEIGHT + D_MARGIN_TOP + D_MARGIN_BOTTOM + D_SCROLLBAR_HEIGHT; if( generaltext.is_visible() ) { size_x += generaltext.get_size().w + D_SCROLLBAR_WIDTH + D_H_SPACE; } // set window size if( size_x > display_get_width()-32 ) { size_x = display_get_width()-32; } const scr_coord_val h = display_get_height() - D_TITLEBAR_HEIGHT - win_get_statusbar_height() - TICKER_HEIGHT; if( size_y>h) { size_y = h; } set_windowsize( scr_size( size_x, size_y ) ); } // generate title title = ""; if( generaltext.is_visible() ) { title = translator::translate( "Help" ); title += " - "; } title += helptext.get_title(); set_name( title.c_str() ); resize( scr_coord(0,0) ); set_dirty(); } // show the help to one topic void help_frame_t::set_helpfile(const char *filename, bool resize_frame ) { // the key help texts are built automagically if (strcmp(filename, "keys.txt") == 0) { cbuffer_t buf; buf.append( translator::translate( "Keyboard Help\n

Keyboard Help

\n" ) ); player_t *player = welt->get_active_player(); const char *trad_str = translator::translate( "%s - %s
\n" ); for(tool_t* const i : tool_t::char_to_tool) { cbuffer_t c; char str[16]; if( i->command_flags & SIM_MOD_CTRL ) { c.append( translator::translate( "[CTRL]" ) ); c.append( " + " ); } if( i->command_flags & SIM_MOD_SHIFT ) { c.append( translator::translate( "[SHIFT]" ) ); c.append( " + " ); } switch (uint16 const key = i->command_key) { case '<': c.append( "<" ); break; case '>': c.append( ">" ); break; case 27: c.append( translator::translate( "[ESCAPE]" ) ); break; case 127: c.append( translator::translate( "[DELETE]" ) ); break; case SIM_KEY_HOME: c.append( translator::translate( "[HOME]" ) ); break; case SIM_KEY_END: c.append( translator::translate( "[END]" ) ); break; case SIM_KEY_SCROLLLOCK: c.append( translator::translate( "[SCROLLLOCK]" ) ); break; default: if (key <= 26) { c.printf("%c", '@' + key); } else if (key < 256) { c.printf("%c", key); } else if (key < SIM_KEY_F15) { c.printf("F%i", key - SIM_KEY_F1 + 1); } else { // try unicode str[utf16_to_utf8(key, (utf8*)str)] = '\0'; c.append( str ); } break; } buf.printf(trad_str, c.get_str(), i->get_tooltip(player)); } set_text( buf, resize_frame ); } else if( strcmp( filename, "general.txt" )!=0 ) { // and the actual help text (if not identical) if( char *buf = load_text( filename ) ) { set_text( buf, resize_frame ); free(buf); } else {{ cbuffer_t buf; buf.printf("%s%s", translator::translate("Error"), translator::translate("Help text not found")); set_text(buf, resize_frame ); }} } else { // default text when opening general help if( char *buf = load_text( "about.txt" ) ) { set_text( buf, resize_frame ); free(buf); } else if( char *buf = load_text( "simutrans.txt" ) ) { set_text( buf, resize_frame ); free(buf); } else { set_text( "", resize_frame ); } } } FILE *help_frame_t::has_helpfile( char const* const filename, int &mode ) { mode = native; std::string file_prefix = std::string("text") + PATH_SEPARATOR; std::string fullname = file_prefix + translator::get_lang()->iso + PATH_SEPARATOR + filename; dr_chdir(env_t::base_dir); FILE* file = dr_fopen(fullname.c_str(), "rb"); if( !file && strcmp(translator::get_lang()->iso,translator::get_lang()->iso_base) ) { //Check for the 'base' language(ie en from en_gb) file = dr_fopen( (file_prefix + translator::get_lang()->iso_base + PATH_SEPARATOR + filename).c_str(), "rb" ); } if( !file ) { // check fallback english file = dr_fopen((file_prefix + "en/" + filename).c_str(), "rb"); mode = english; } // go back to load/save dir dr_chdir( env_t::user_dir ); // success? if( !file ) { mode = missing; } return file; } // extracts the title and ASCII from a string std::string help_frame_t::extract_title( const char *htmllines ) { const uint8 *start = (const uint8 *)strstr( htmllines, "" ); const uint8 *end = (const uint8 *)strstr( htmllines, "" ); bool convert_to_utf = false; uint8 title_form_html[1024]; if( start && end && (size_t)(end-start)=32 ) { // convert to UTF if needed if( !convert_to_utf && *c >= 0x80 ) { size_t len; utf8_decoder_t::decode(c, len); convert_to_utf = (len <= 1); } if (convert_to_utf) { if (translator::get_lang()->is_latin2_based) { dest += utf16_to_utf8(latin2_to_unicode(*c), dest); } else { dest += utf16_to_utf8(*c, dest); } c++; } else { size_t len; utf32 cc = utf8_decoder_t::decode(c, len); dest += utf16_to_utf8(cc, dest); c += len; } } else { // avoid double spaces if( dest!=title_form_html && dest[-1]!=' ' ) { *dest++ = ' '; } c++; } } *dest = 0; return (const char *)title_form_html; } return ""; } void help_frame_t::add_helpfile( cbuffer_t §ion, const char *titlename, const char *filename, bool only_native, int indent_level ) { if( strempty(filename) ) { return; } int mode; FILE *file = has_helpfile( filename, mode ); if( ( only_native && mode!=native ) || mode==missing ) { return; } std::string filetitle; // just in case as temporary storage ... if( titlename == NULL && file ) { // get the title from the helpfile char htmlline[1024]; if (fread( htmlline, lengthof(htmlline)-1, 1, file ) == 1) { filetitle = extract_title( htmlline ); if( filetitle.empty() ) { // no idea how to generate the right name ... titlename = filename; } else { titlename = filetitle.c_str(); } } else { titlename = filename; } } else { titlename = translator::translate( titlename ); } // now build the entry if( mode != missing ) { while( indent_level-- > 0 ) { section.append( "+" ); } if( mode == native ) { section.printf( "%s
\n", filename, titlename ); } else if( mode == english ) { section.printf( "%s%s
\n", filename, "*", titlename ); } fclose( file ); } } /** * Called upon link activation * @param extra the name of the help file */ bool help_frame_t::action_triggered( gui_action_creator_t *, value_t extra) { top_win( this ); set_helpfile( (const char *)(extra.p), false ); return true; } void help_frame_t::resize(const scr_coord delta) { gui_frame_t::resize(delta); scr_coord_val generalwidth = 0; if( generaltext.is_visible() ) { // do not use more than 1/3 for the general infomations generalwidth = min( get_windowsize().w/3, generaltext.get_preferred_size().w ) + D_SCROLLBAR_WIDTH; generaltext.set_size( scr_size( generalwidth, get_client_windowsize().h - D_MARGIN_BOTTOM) ); generalwidth += D_H_SPACE; helptext.set_pos( generaltext.get_pos() + scr_size( generalwidth, 0 ) ); } helptext.set_size( get_client_windowsize() - scr_size( generalwidth, 0) -scr_size(0,D_MARGIN_BOTTOM) ); } simutrans-124.3/src/simutrans/gui/help_frame.h000066400000000000000000000022171474050137200214300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_HELP_FRAME_H #define GUI_HELP_FRAME_H #include #include "gui_frame.h" #include "components/gui_flowtext.h" #include "components/action_listener.h" class cbuffer_t; class help_frame_t : public gui_frame_t, action_listener_t { private: enum { missing, native, english }; gui_flowtext_t generaltext, helptext; std::string title; // show the help to one topic void set_helpfile(const char *filename, bool resize_frame ); help_frame_t(char const* filename); void add_helpfile( cbuffer_t §ion, const char *titlename, const char *filename, bool only_native, int indent_level ); std::string extract_title( const char *htmllines ); static FILE *has_helpfile( char const* const filename, int &mode ); public: help_frame_t(); static void open_help_on( const char *helpfilename ); void set_text(const char * text, bool resize = true ); /** * resize window in response to a resize event */ void resize(const scr_coord delta) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/jump_frame.cc000066400000000000000000000026331474050137200216130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../obj/zeiger.h" #include "jump_frame.h" #include "components/gui_divider.h" #include "../dataobj/translator.h" jump_frame_t::jump_frame_t() : gui_frame_t( translator::translate("Jump to") ) { set_table_layout(1,0); // Input box for new name sprintf(buf, "%i,%i", welt->get_viewport()->get_world_position().x, welt->get_viewport()->get_world_position().y ); input.set_text(buf, 62); input.add_listener(this); add_component(&input); new_component(); jumpbutton.init( button_t::roundbox, "Jump to"); jumpbutton.add_listener(this); add_component(&jumpbutton); set_focus(&input); reset_min_windowsize(); set_windowsize(get_min_windowsize()); } /** * This method is called if an action is triggered */ bool jump_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if(comp == &input || comp == &jumpbutton) { // OK- Button or Enter-Key pressed //--------------------------------------- koord my_pos; sscanf(buf, "%hd,%hd", &my_pos.x, &my_pos.y); if(welt->is_within_limits(my_pos)) { koord3d k( my_pos, welt->min_hgt( my_pos ) ); welt->get_viewport()->change_world_position(k); welt->get_zeiger()->change_pos( k ); } } return true; } simutrans-124.3/src/simutrans/gui/jump_frame.h000066400000000000000000000012671474050137200214570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_JUMP_FRAME_H #define GUI_JUMP_FRAME_H #include "components/action_listener.h" #include "gui_frame.h" #include "components/gui_textinput.h" #include "components/gui_button.h" class jump_frame_t : public gui_frame_t, action_listener_t { char buf[64]; gui_textinput_t input; button_t jumpbutton; public: jump_frame_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "jump_frame.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/kennfarbe.cc000066400000000000000000000077351474050137200214310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "kennfarbe.h" #include "../world/simworld.h" #include "../simskin.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../player/simplay.h" #include "components/gui_label.h" #include "components/gui_image.h" #include "../tool/simmenu.h" /** * Buttons forced to be square ... */ class choose_color_button_t : public button_t { scr_coord_val w; public: choose_color_button_t() : button_t() { w = max(D_BUTTON_HEIGHT, display_get_char_width('X') + D_BUTTON_PADDINGS_X); } scr_size get_min_size() const OVERRIDE { return scr_size(w, D_BUTTON_HEIGHT); } }; farbengui_t::farbengui_t(player_t *player_) : gui_frame_t( translator::translate("Farbe"), player_ ), txt(&buf) { player = player_; buf.clear(); buf.append(translator::translate("COLOR_CHOOSE\n")); set_table_layout(1,0); add_table(2,1); // Info text txt.recalc_size(); add_component( &txt ); // Picture new_component(skinverwaltung_t::color_options->get_image_id(0), player->get_player_nr(), ALIGN_NONE, true); end_table(); // Player's primary color label new_component("Your primary color:"); // Get all colors (except the current player's) uint32 used_colors1 = 0; uint32 used_colors2 = 0; for( int i=0; iget_player_nr() && welt->get_player(i) ) { used_colors1 |= 1 << (welt->get_player(i)->get_player_color1() / 8); used_colors2 |= 1 << (welt->get_player(i)->get_player_color2() / 8); } } add_table(14,2); // Primary color buttons for(unsigned i=0; i<28; i++) { player_color_1[i] = new_component(); player_color_1[i]->init( button_t::box_state, (used_colors1 & (1<background_color = color_idx_to_rgb(i*8+4); player_color_1[i]->add_listener(this); } player_color_1[player->get_player_color1()/8]->pressed = true; end_table(); // Player's secondary color label new_component("Your secondary color:"); add_table(14,2); // Secondary color buttons for(unsigned i=0; i<28; i++) { player_color_2[i] = new_component(); player_color_2[i]->init( button_t::box_state, (used_colors2 & (1<background_color = color_idx_to_rgb(i*8+4); player_color_2[i]->add_listener(this); } player_color_2[player->get_player_color2()/8]->pressed = true; end_table(); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool farbengui_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { for(unsigned i=0; i<28; i++) { // new player 1 color? if(comp==player_color_1[i]) { for(unsigned j=0; j<28; j++) { player_color_1[j]->pressed = false; } player_color_1[i]->pressed = true; //env_t::default_settings.set_default_player_color(player->get_player_nr(), player->get_player_color1(), player->get_player_color2()); // re-colour a player cbuffer_t buf; buf.printf( "1%u,%i", player->get_player_nr(), i*8); tool_t *w = create_tool( TOOL_RECOLOUR_TOOL | SIMPLE_TOOL ); w->set_default_param( buf ); world()->set_tool( w, player ); // since init always returns false, it is save to delete immediately delete w; return true; } // new player color 2? if(comp==player_color_2[i]) { for(unsigned j=0; j<28; j++) { player_color_2[j]->pressed = false; } player_color_2[i]->pressed = true; //env_t::default_settings.set_default_player_color(player->get_player_nr(), player->get_player_color1(), player->get_player_color2()); // re-colour a player cbuffer_t buf; buf.printf( "2%u,%i", player->get_player_nr(), i*8); tool_t *w = create_tool( TOOL_RECOLOUR_TOOL | SIMPLE_TOOL ); w->set_default_param( buf ); world()->set_tool( w, player ); // since init always returns false, it is save to delete immediately delete w; return true; } } return false; } simutrans-124.3/src/simutrans/gui/kennfarbe.h000066400000000000000000000016531474050137200212640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_KENNFARBE_H #define GUI_KENNFARBE_H #include "../utils/cbuffer.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_textarea.h" #include "components/gui_button.h" class choose_color_button_t; /** * Company colors window * Dialog to set the player's color */ class farbengui_t : public gui_frame_t, action_listener_t { private: player_t *player; cbuffer_t buf; gui_textarea_t txt; choose_color_button_t* player_color_1[28]; choose_color_button_t* player_color_2[28]; public: farbengui_t(player_t *player_); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "color.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/label_info.cc000066400000000000000000000037501474050137200215610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "label_info.h" #include "components/gui_label.h" #include "../world/simworld.h" #include "simwin.h" #include "../tool/simmenu.h" #include "../obj/label.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" label_info_t::label_info_t(label_t* l) : gui_frame_t( translator::translate("Marker"), l->get_owner()), view(l->get_pos(), scr_size( max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width()*7)/8) )) { label = l; set_table_layout(1,0); // input add_component(&input); input.add_listener(this); add_table(3,0)->set_alignment(ALIGN_TOP); // left: player name new_component(label->get_owner() ? label->get_owner()->get_name() : "" ); new_component(); // right column: view add_component( &view ); end_table(); grund_t *gr = welt->lookup(l->get_pos()); if(gr->get_text()) { tstrncpy(edit_name, gr->get_text(), lengthof(edit_name)); } else { edit_name[0] = '\0'; } // text input input.set_text(edit_name, lengthof(edit_name)); set_focus(&input); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool label_info_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if(comp == &input && welt->get_active_player()==label->get_owner()) { // check owner to change text grund_t *gd = welt->lookup(label->get_pos()); if( strcmp(gd->get_text(),edit_name) ) { // text changed => call tool cbuffer_t buf; buf.printf( "m%s,%s", label->get_pos().get_str(), edit_name ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); welt->set_tool( tool, label->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } destroy_win(this); } return true; } void label_info_t::map_rotate90( sint16 new_ysize ) { view.map_rotate90(new_ysize); } simutrans-124.3/src/simutrans/gui/label_info.h000066400000000000000000000013041474050137200214140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LABEL_INFO_H #define GUI_LABEL_INFO_H #include "gui_frame.h" #include "components/gui_textinput.h" #include "components/gui_location_view.h" #include "components/action_listener.h" class label_t; /** * Label creation/edition window */ class label_info_t : public gui_frame_t, private action_listener_t { private: label_t *label; gui_textinput_t input; location_view_t view; char edit_name[256]; public: label_info_t(label_t* l); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // rotated map need new info ... void map_rotate90( sint16 ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/labellist_frame.cc000066400000000000000000000076201474050137200226140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "labellist_frame.h" #include "labellist_stats.h" #include "../dataobj/translator.h" #include "../obj/label.h" #include "../world/simworld.h" #include "../utils/unicode.h" char labellist_frame_t::name_filter[256]; static const char *sort_text[labellist::SORT_MODES] = { "hl_btn_sort_name", "koord", "player" }; labellist_frame_t::labellist_frame_t() : gui_frame_t(translator::translate("labellist_title")), scrolly(gui_scrolled_list_t::windowskin, labellist_stats_t::compare) { set_table_layout(3,0); new_component("Filter:"); name_filter_input.set_text(name_filter, lengthof(name_filter)); name_filter_input.set_notify_all_changes_delay(0); name_filter_input.add_listener(this); add_component(&name_filter_input); new_component(); filter.init( button_t::square_automatic, "Active player only"); filter.pressed = labellist_stats_t::filter; add_component(&filter, 2); filter.add_listener( this ); new_component(); new_component("hl_txt_sort"); sortedby.set_unsorted(); // do not sort for (size_t i = 0; i < lengthof(sort_text); i++) { sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT); } sortedby.set_selection(labellist_stats_t::sortby); sortedby.add_listener(this); add_component(&sortedby); sorteddir.init(button_t::sortarrow_state, NULL); sorteddir.add_listener(this); sorteddir.pressed = labellist_stats_t::sortreverse; add_component(&sorteddir); scrolly.set_maximize(true); scrolly.set_checkered(true); add_component(&scrolly,3); fill_list(); reset_min_windowsize(); set_resizemode(diagonal_resize); } void labellist_frame_t::fill_list() { label_count = welt->get_label_list().get_count(); scrolly.clear_elements(); for(koord const& pos : welt->get_label_list()) { label_t* label = welt->lookup_kartenboden(pos)->find(); const char* name = welt->lookup_kartenboden(pos)->get_text(); // some old version games don't have label nor name. // Check them to avoid crashes. if(label && name && (!labellist_stats_t::filter || (label && (label->get_owner() == welt->get_active_player())))) { if( name_filter[0] == 0 || utf8caseutf8(name, name_filter) ) { scrolly.new_component(pos); } } } scrolly.sort(0); reset_min_windowsize(); } uint32 labellist_frame_t::count_label() { uint32 labelcount = 0; for(koord const& pos : welt->get_label_list()) { label_t* label = welt->lookup_kartenboden(pos)->find(); const char* name = welt->lookup_kartenboden(pos)->get_text(); // some old version games don't have label nor name. if(label && name && (!labellist_stats_t::filter || (label && (label->get_owner() == welt->get_active_player())))) { labelcount++; } } return labelcount; } bool labellist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) { if(comp == &sortedby) { labellist_stats_t::sortby = (labellist::sort_mode_t)v.i; scrolly.sort(0); } else if(comp == &sorteddir) { labellist_stats_t::sortreverse = !labellist_stats_t::sortreverse; sorteddir.pressed = labellist_stats_t::sortreverse; scrolly.sort(0); } else if (comp == &name_filter_input) { fill_list(); } else if (comp == &filter) { labellist_stats_t::filter = !labellist_stats_t::filter; fill_list(); } return true; } void labellist_frame_t::rdwr(loadsave_t* file) { scr_size size = get_windowsize(); sint16 sort_mode = labellist_stats_t::sortby; size.rdwr(file); scrolly.rdwr(file); file->rdwr_str(name_filter, lengthof(name_filter)); file->rdwr_short(sort_mode); file->rdwr_bool(labellist_stats_t::sortreverse); file->rdwr_bool(labellist_stats_t::filter); if (file->is_loading()) { labellist_stats_t::sortby = (labellist::sort_mode_t)sort_mode; fill_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/labellist_frame.h000066400000000000000000000020461474050137200224530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LABELLIST_FRAME_H #define GUI_LABELLIST_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_scrolled_list.h" #include "components/gui_textinput.h" /** * label list window */ class labellist_frame_t : public gui_frame_t, private action_listener_t { private: gui_combobox_t sortedby; button_t sorteddir; button_t filter; gui_scrolled_list_t scrolly; static char name_filter[256]; gui_textinput_t name_filter_input; uint32 label_count; public: labellist_frame_t(); const char *get_help_filename() const OVERRIDE {return "labellist_filter.txt"; } bool action_triggered( gui_action_creator_t *comp,value_t /* */) OVERRIDE; uint32 count_label(); void fill_list(); void map_rotate90( sint16 ) OVERRIDE { fill_list(); } void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_labellist; } }; #endif simutrans-124.3/src/simutrans/gui/labellist_stats.cc000066400000000000000000000066611474050137200226640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "labellist_stats.h" #include "components/gui_button.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../player/simplay.h" #include "../obj/label.h" #include "../utils/cbuffer.h" #include "../dataobj/environment.h" labellist::sort_mode_t labellist_stats_t::sortby = labellist::by_name; bool labellist_stats_t::sortreverse = false; bool labellist_stats_t::filter = false; static karte_ptr_t welt; bool labellist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb) { const labellist_stats_t* a = dynamic_cast(aa); const labellist_stats_t* b = dynamic_cast(bb); int cmp = 0; switch (sortby) { default: NOT_REACHED case labellist::by_name: { cmp = 0; break; } case labellist::by_koord: cmp = a->label_pos.x - b->label_pos.x; if(cmp==0) { cmp = a->label_pos.y - b->label_pos.y; } break; case labellist::by_player: { if(!filter) { const label_t* a_l = a->get_label(); const label_t* b_l = b->get_label(); if(a_l && b_l) { cmp = a_l->get_owner_nr() - b_l->get_owner_nr(); } } break; } } if(cmp==0) { const char* a_name = a->get_text(); const char* b_name = b->get_text(); cmp = strcmp(a_name, b_name); } return sortreverse ? cmp > 0 : cmp < 0; } labellist_stats_t::labellist_stats_t(koord label_pos) { this->label_pos = label_pos; set_table_layout(2,1); button_t *b = new_component(); b->set_typ(button_t::posbutton_automatic); b->set_targetpos(label_pos); add_component(&label); label.buf().printf("(%s) %s", label_pos.get_str(), get_text()); label.update(); if (const label_t *lb = get_label()) { if (lb->get_owner()) { label.set_color(PLAYER_FLAG | color_idx_to_rgb(lb->get_owner()->get_player_color1() + env_t::gui_player_color_dark)); } else { label.set_color(env_t::default_window_title_color); } } } const label_t* labellist_stats_t::get_label() const { if (grund_t *gr = welt->lookup_kartenboden(label_pos)) { return gr->find(); } return NULL; } void labellist_stats_t::map_rotate90( sint16 y_size ) { label_pos.rotate90(y_size); } bool labellist_stats_t::is_valid() const { return get_label() != NULL; } const char* labellist_stats_t::get_text() const { if (grund_t *gr = welt->lookup_kartenboden(label_pos)) { return gr->get_text(); } return ""; } /** * Events are notified to GUI components via this method */ bool labellist_stats_t::infowin_event(const event_t * ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if (!swallowed) { if (grund_t* gr = welt->lookup_kartenboden(label_pos)) { // either open dialog or goto (with control or right click) if (IS_LEFTRELEASE(ev)) { if ((event_get_last_control_shift() ^ tool_t::control_invert) == 2) { world()->get_viewport()->change_world_position(gr->get_pos()); } else { if (label_t* lb = gr->find()) { lb->show_info(); } } return true; } if (IS_RIGHTRELEASE(ev)) { world()->get_viewport()->change_world_position(gr->get_pos()); return true; } } } return swallowed; } /** * Draw the component */ void labellist_stats_t::draw(scr_coord offset) { label.buf().printf("(%s) %s", label_pos.get_str(), get_text()); gui_aligned_container_t::draw(offset); } simutrans-124.3/src/simutrans/gui/labellist_stats.h000066400000000000000000000020021474050137200225070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LABELLIST_STATS_H #define GUI_LABELLIST_STATS_H #include "components/gui_aligned_container.h" #include "components/gui_label.h" #include "components/gui_scrolled_list.h" namespace labellist { enum sort_mode_t { by_name = 0, by_koord, by_player, SORT_MODES }; }; class label_t; class labellist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: koord label_pos; gui_label_buf_t label; const label_t* get_label() const; public: static labellist::sort_mode_t sortby; static bool sortreverse, filter; static bool compare(const gui_component_t *a, const gui_component_t *b ); labellist_stats_t(koord label_pos); bool infowin_event(event_t const*) OVERRIDE; /** * Draw the component */ void draw(scr_coord offset) OVERRIDE; void map_rotate90( sint16 ); bool is_valid() const OVERRIDE; const char* get_text() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/line_item.cc000066400000000000000000000104611474050137200214310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simwin.h" #include "line_item.h" #include "../simline.h" #include "../dataobj/schedule.h" #include "../tool/simmenu.h" #include "../world/simworld.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" const char* line_scrollitem_t::get_text() const { return line->get_name(); } PIXVAL line_scrollitem_t::get_color() const { return line->get_state_color(); } void line_scrollitem_t::set_text(char const* const t) { if( t && t[0] && strcmp(t, line->get_name())) { // text changed => call tool cbuffer_t buf; buf.printf( "l%u,%s", line.get_id(), t ); tool_t *tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tool->set_default_param( buf ); karte_ptr_t welt; welt->set_tool( tool, line->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } } void line_scrollitem_t::draw( scr_coord offset ) { bool old_selected = selected; if (select_mode == SELECT_WIN) { selected = win_get_magic( (ptrdiff_t)line.get_rep() ); } static char infotext[256]; if( getroffen( get_mouse_pos() - offset ) ) { char convoi_tmp[128]; const char * convoicount; // update convoi info switch( line->count_convoys() ) { case 0: convoicount = translator::translate( "no convois" ); break; case 1: convoicount = translator::translate( "1 convoi" ); break; default: sprintf( convoi_tmp, translator::translate( "%d convois" ), line->count_convoys() ); convoicount = convoi_tmp; break; } char profit_str[64]; money_to_string( profit_str, line->get_finance_history( 0, LINE_PROFIT )/100.0, true ); sprintf( infotext, "%s, %s %s", convoicount, translator::translate( "Gewinn" ), profit_str ); win_set_tooltip( get_mouse_pos() + TOOLTIP_MOUSE_OFFSET, infotext); } gui_scrolled_list_t::const_text_scrollitem_t::draw( offset ); selected = old_selected; } // static helper function for sorting lineintems line_scrollitem_t::sort_modes_t line_scrollitem_t::sort_mode = line_scrollitem_t::SORT_BY_NAME; bool line_scrollitem_t::sort_reverse; bool line_scrollitem_t::compare(const gui_component_t *aa, const gui_component_t *bb) { const line_scrollitem_t *a = dynamic_cast(aa); const line_scrollitem_t *b = dynamic_cast(bb); // for sorting in reverse order: exchange a,b if (sort_reverse) { std::swap(a,b); } // good luck with mixed lists assert(a != NULL && b != NULL); (void)(a==b); if( sort_mode != SORT_BY_NAME ) { switch( sort_mode ) { case SORT_BY_NAME: // default break; case SORT_BY_ID: return a->get_line().get_id() < b->get_line().get_id(); case SORT_BY_PROFIT: return a->get_line()->get_finance_history(1, LINE_PROFIT ) - b->get_line()->get_finance_history(1, LINE_PROFIT ) < 0; case SORT_BY_REVENUE: return a->get_line()->get_finance_history(1, LINE_REVENUE ) - b->get_line()->get_finance_history(1, LINE_REVENUE ) < 0; case SORT_BY_TRANSPORTED: return a->get_line()->get_finance_history(1, LINE_TRANSPORTED_GOODS) - b->get_line()->get_finance_history(1, LINE_TRANSPORTED_GOODS) < 0; case SORT_BY_CONVOIS: return a->get_line()->get_finance_history(1, LINE_CONVOIS) - b->get_line()->get_finance_history(1, LINE_CONVOIS) < 0; case SORT_BY_DISTANCE: // normalizing to the number of convoys to get the fastest ones ... return a->get_line()->get_finance_history(1, LINE_DISTANCE)/max(1,a->get_line()->get_finance_history(1, LINE_CONVOIS)) - b->get_line()->get_finance_history(1, LINE_DISTANCE)/max(1,b->get_line()->get_finance_history(1, LINE_CONVOIS)) < 0; default: break; } // default sorting ... } // first: try to sort by number const char *atxt = a->get_text(); int aint = 0; // isdigit produces with UTF8 assertions ... if( atxt[0]>='0' && atxt[0]<='9' ) { aint = atoi( atxt ); } else if( atxt[0]=='(' && atxt[1]>='0' && atxt[1]<='9' ) { aint = atoi( atxt+1 ); } const char *btxt = b->get_text(); int bint = 0; if( btxt[0]>='0' && btxt[0]<='9' ) { bint = atoi( btxt ); } else if( btxt[0]=='(' && btxt[1]>='0' && btxt[1]<='9' ) { bint = atoi( btxt+1 ); } if( aint!=bint ) { return aint - bint < 0; } // otherwise: sort by name return strcmp(atxt, btxt) < 0; } simutrans-124.3/src/simutrans/gui/line_item.h000066400000000000000000000030311474050137200212660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LINE_ITEM_H #define GUI_LINE_ITEM_H #include "components/gui_scrolled_list.h" #include "../linehandle.h" /** * Container for list entries - consisting of text and color */ class line_scrollitem_t : public gui_scrolled_list_t::const_text_scrollitem_t { public: // helper to sort enum sort_modes_t { SORT_BY_NAME = 0, SORT_BY_ID, SORT_BY_PROFIT, SORT_BY_REVENUE, SORT_BY_TRANSPORTED, SORT_BY_CONVOIS, SORT_BY_DISTANCE, MAX_SORT_MODES }; // selection mode enum select_modes_t { SELECT_ITEM, ///< show selected: if item is selected in list to apply line for convoy SELECT_WIN, ///< show selected: if line window is open }; static sort_modes_t sort_mode; static bool sort_reverse; // to update selected status void draw( scr_coord offset ) OVERRIDE; // normal items line_scrollitem_t( linehandle_t l, select_modes_t sm = SELECT_ITEM) : gui_scrolled_list_t::const_text_scrollitem_t( NULL, color_idx_to_rgb(COL_ORANGE) ), select_mode(sm) { line = l; } PIXVAL get_color() const OVERRIDE; linehandle_t get_line() const { return line; } char const* get_text() const OVERRIDE; void set_text(char const*) OVERRIDE; bool is_valid() const OVERRIDE { return line.is_bound(); } // can be used to indicate invalid entries bool is_editable() const OVERRIDE { return true; } static bool compare(const gui_component_t *a, const gui_component_t *b ); private: linehandle_t line; select_modes_t select_mode; }; #endif simutrans-124.3/src/simutrans/gui/line_management_gui.cc000066400000000000000000000362531474050137200234620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simwin.h" #include "minimap.h" #include "components/gui_convoiinfo.h" #include "../dataobj/schedule.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../vehicle/vehicle.h" #include "../convoihandle.h" #include "../simconvoi.h" #include "../obj/depot.h" #include "../simhalt.h" #include "../simline.h" #include "../tool/simmenu.h" #include "../player/simplay.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "halt_list_stats.h" #include "line_management_gui.h" #define CHART_HEIGHT (100) static const char *cost_type[MAX_LINE_COST] = { "Free Capacity", "Transported", "Revenue", "Operation", "Road toll", "Profit", "Convoys", "Distance", "Maxspeed" }; static const uint8 cost_type_color[MAX_LINE_COST] = { COL_FREE_CAPACITY, COL_TRANSPORTED, COL_REVENUE, COL_OPERATION, COL_TOLL, COL_PROFIT, COL_CONVOI_COUNT, COL_DISTANCE, COL_MAXSPEED }; static uint8 idx2cost[MAX_LINE_COST] = { LINE_CAPACITY, LINE_TRANSPORTED_GOODS, LINE_REVENUE, LINE_OPERATIONS, LINE_WAYTOLL, LINE_PROFIT, LINE_CONVOIS, LINE_DISTANCE, LINE_MAXSPEED, }; static const bool cost_type_money[ MAX_LINE_COST ] = { false, false, true, true, true, true, false, false, false }; // which buttons as defualt in statistic static bool cost_type_default[MAX_LINE_COST] = { 0,0,0,0,0,0,0,0,0 }; // statistics as first default to open static int default_opening_tab = 1; line_management_gui_t::line_management_gui_t( linehandle_t line_, player_t* player_, int active_tab) : gui_frame_t( translator::translate( "Fahrplan" ), player_ ), scrolly_convois( gui_scrolled_list_t::windowskin ), scrolly_halts( gui_scrolled_list_t::windowskin ), loading_info( &loading_text ) { is_saving_gui = false; set_table_layout( 3, 0 ); set_alignment(ALIGN_TOP); line = line_; player = player_; scrolly_convois.set_checkered(true); scrolly_halts.set_checkered(true); // line name inp_name.add_listener( this ); add_component( &inp_name, 3 ); lb_convoi_count.set_text( "no convois" ); add_component( &lb_convoi_count, 3 ); capacity_bar.add_color_value( &load, color_idx_to_rgb( COL_GREEN ) ); add_component( &capacity_bar, 2 ); new_component(); add_component( &lb_profit_value ); add_component( &loading_info, 2 ); loading_text.printf( translator::translate("Capacity: %s\nLoad: %d (%d%%)"), 0, 0, 0); // tab panel: connections, chart panels, details add_component( &switch_mode, 3 ); switch_mode.add_listener( this ); switch_mode.add_tab( &container_schedule, translator::translate( "Fahrplan" ) ); container_schedule.set_table_layout( 1, 0 ); container_schedule.add_component( &scd ); scd.add_listener( this ); switch_mode.add_tab( &container_stats, translator::translate( "Chart" ) ); container_stats.set_table_layout( D_BUTTONS_PER_ROW, 0 ); container_stats.set_force_equal_columns(true); chart.set_dimension( 12, 10000 ); chart.set_background( SYSCOL_CHART_BACKGROUND ); chart.set_min_size( scr_size( 0, CHART_HEIGHT ) ); container_stats.add_component( &chart, D_BUTTONS_PER_ROW); switch_mode.add_tab( &container_convois, translator::translate( "cl_title" ) ); container_convois.set_table_layout( 1, 0 ); container_convois.add_table( D_BUTTONS_PER_ROW, 0 )->set_force_equal_columns(D_BUTTONS_PER_ROW>=4); bt_delete_line.init( button_t::roundbox | button_t::flexible, "Delete Line" ); bt_delete_line.set_tooltip( "Delete the selected line (if without associated convois)." ); bt_delete_line.add_listener( this ); bt_delete_line.disable(); container_convois.add_component( &bt_delete_line ); bt_withdraw_line.init( button_t::roundbox_state | button_t::flexible, "Withdraw All" ); bt_withdraw_line.set_tooltip( "Convoi is sold when all wagons are empty." ); bt_withdraw_line.add_listener( this ); container_convois.add_component( &bt_withdraw_line ); bt_find_convois.init( button_t::roundbox | button_t::flexible, "Find matching convois" ); bt_find_convois.set_tooltip( "Add convois with similar schedule to this line." ); bt_find_convois.add_listener( this ); container_convois.add_component( &bt_find_convois ); container_convois.end_table(); container_convois.add_component(&scrolly_convois); switch_mode.add_tab(&container_halts, translator::translate("hl_title")); container_halts.set_table_layout(1,0); scrolly_halts.set_maximize( true ); container_halts.add_component(&scrolly_halts); if (active_tab < 0) { active_tab = default_opening_tab; } switch_mode.set_active_tab_index(active_tab); if (line.is_bound() ) { init(true); } old_convoi_count = old_halt_count = 0; set_resizemode(diagonal_resize); reset_min_windowsize(); set_windowsize(get_windowsize()); } void line_management_gui_t::init(bool not_rdwr) { if( line.is_bound() ) { // title set_name(line->get_name() ); // schedule scd.init(not_rdwr?line->get_schedule():scd.get_schedule(), player, convoihandle_t(), linehandle_t(),true); // we use local buffer to prevent sudden death on line deletion tstrncpy(old_line_name, line->get_name(), sizeof(old_line_name)); tstrncpy(line_name, line->get_name(), sizeof(line_name)); inp_name.set_text(line_name, sizeof(line_name)); bt_delete_line.enable(); bt_withdraw_line.pressed = line->get_withdraw(); // init_chart if( chart.get_curve_count() == 0 ) { for( int cost = 0; cost < MAX_LINE_COST; cost++ ) { uint16 curve = chart.add_curve( color_idx_to_rgb( cost_type_color[ cost ] ), line->get_finance_history(), MAX_LINE_COST, idx2cost[cost], MAX_MONTHS, cost_type_money[ cost ], cost_type_default[cost], true, cost_type_money[ cost ] * 2 ); button_t *b = container_stats.new_component(); b->init( button_t::box_state_automatic | button_t::flexible, cost_type[ cost ] ); b->background_color = color_idx_to_rgb( cost_type_color[ cost ] ); b->pressed = cost_type_default[cost]; b->add_listener( this ); button_to_chart.append( b, &chart, curve ); } old_convoi_count = -1; // recalc! } // start editing scd.highlight_schedule(switch_mode.get_aktives_tab() == &container_schedule); if (line->count_convoys() > 0) { minimap_t::get_instance()->set_selected_cnv(line->get_convoy(0)); } } } void line_management_gui_t::draw(scr_coord pos, scr_size size) { if( line.is_bound() ) { player_t *ap = welt->get_active_player(); bool is_change_allowed = player == ap && !welt->get_active_player()->is_locked(); bool has_changed = false; // then we need to recalc sizes ... if (!is_change_allowed) { bt_delete_line.enable(false); } bt_withdraw_line.enable(is_change_allowed); bt_find_convois.enable(is_change_allowed); if( line->count_convoys() != old_convoi_count ) { old_convoi_count = line->count_convoys(); // update convoi info switch( old_convoi_count ) { case 0: lb_convoi_count.set_text( "no convois" ); break; case 1: lb_convoi_count.set_text( "1 convoi" ); break; default: lb_convoi_count_text.clear(); lb_convoi_count_text.printf( translator::translate( "%d convois" ), old_convoi_count ); lb_convoi_count.set_text( lb_convoi_count_text ); break; } bt_withdraw_line.enable(is_change_allowed && old_convoi_count != 0 ); // fill convoi container scrolly_convois.clear_elements(); for( uint32 i = 0; i < line->count_convoys(); i++ ) { convoihandle_t cnv = line->get_convoy( i ); scrolly_convois.new_component( cnv ); } has_changed = true; if( old_convoi_count>0 ) { scrolly_convois.set_maximize( true ); } } capacity = 0; load = 0; for( uint32 i = 0; i < line->count_convoys(); i++ ) { convoihandle_t cnv = line->get_convoy( i ); for (unsigned i = 0; iget_vehicle_count(); i++) { capacity += cnv->get_vehicle(i)->get_cargo_max(); load += cnv->get_vehicle( i )->get_total_cargo(); } } capacity_bar.set_base( capacity ); // we check if cap is zero, since theoretically a // conv can consist of only 1 vehicle, which has no cap (eg. locomotive) // and we do not like to divide by zero, do we? sint32 loadfactor = 0; if (capacity > 0) { loadfactor = (load * 100) / capacity; } char ctmp[ 20 ]; number_to_string(ctmp, capacity, 2); loading_text.clear(); loading_text.printf( translator::translate("Capacity: %s\nLoad: %d (%d%%)"), ctmp, load, loadfactor ); char profit_str[64]; money_to_string( profit_str, line->get_finance_history( 0, LINE_PROFIT )/100.0, true ); lb_profit_value_text.clear(); lb_profit_value_text.printf( "%s %s", translator::translate("Gewinn"), profit_str ); lb_profit_value.set_text_pointer( lb_profit_value_text ); lb_profit_value.set_color( line->get_finance_history( 0, LINE_PROFIT ) >= 0 ? MONEY_PLUS : MONEY_MINUS ); if( line->get_schedule()->get_count() != old_halt_count ) { // update halt info old_halt_count = line->get_schedule()->get_count(); // fill haltestellen container with info of stops of the line scrolly_halts.clear_elements(); for(schedule_entry_t const& i : line->get_schedule()->entries) { halthandle_t const halt = haltestelle_t::get_halt(i.pos, player); if( halt.is_bound() ) { scrolly_halts.new_component(halt); } } has_changed = true; } if( has_changed ) { reset_min_windowsize(); } bt_withdraw_line.enable( is_change_allowed ); if( strcmp( get_name(), line->get_name() ) ) { set_name( line->get_name() ); welt->set_dirty(); } } else { destroy_win( this ); } gui_frame_t::draw(pos,size); } void line_management_gui_t::rdwr(loadsave_t *file) { sint32 cont_xoff, cont_yoff; sint32 halt_xoff, halt_yoff; uint8 player_nr; is_saving_gui = file->is_saving(); if( file->is_saving() ) { cont_xoff = scrolly_convois.get_scroll_x(); cont_yoff = scrolly_convois.get_scroll_y(); halt_xoff = scrolly_halts.get_scroll_x(); halt_yoff = scrolly_halts.get_scroll_y(); player_nr = player->get_player_nr(); } scr_size size = get_windowsize(); size.rdwr( file ); file->rdwr_long( cont_xoff ); file->rdwr_long( cont_yoff ); file->rdwr_long( halt_xoff ); file->rdwr_long( halt_yoff ); file->rdwr_byte( player_nr ); file->rdwr_str( old_line_name, lengthof( old_line_name ) ); file->rdwr_str( line_name, lengthof( line_name ) ); simline_t::rdwr_linehandle_t(file, line); scd.rdwr( file ); if( file->is_loading() ) { player = welt->get_player( player_nr ); gui_frame_t::set_owner(player); if( line.is_bound() ) { set_windowsize(size); set_windowsize( size ); win_set_magic(this, (ptrdiff_t)line.get_rep()); scrolly_convois.set_scroll_position( cont_xoff, cont_yoff ); scrolly_halts.set_scroll_position( halt_xoff, halt_yoff ); init(false); } else { line = linehandle_t(); destroy_win( this ); dbg->error( "line_management_gui_t::rdwr", "Could not restore schedule window for line id %i", line.get_id() ); } } switch_mode.rdwr( file ); button_to_chart.rdwr( file ); } void line_management_gui_t::apply_schedule() { if( scd.has_pending_changes() && line.is_bound() && (player == welt->get_active_player() || welt->get_active_player()->is_public_service()) ) { // update line schedule via tool! tool_t *tool = create_tool( TOOL_CHANGE_LINE | SIMPLE_TOOL ); cbuffer_t buf; buf.printf( "g,%i,", line.get_id() ); scd.get_schedule()->sprintf_schedule( buf ); tool->set_default_param( buf ); world()->set_tool( tool, line->get_owner() ); // since init always returns false, it is safe to delete immediately delete tool; } } bool line_management_gui_t::action_triggered( gui_action_creator_t *comp, value_t v ) { if(line->count_convoys()>0) { minimap_t::get_instance()->set_selected_cnv(line->get_convoy(0)); } if( comp == &scd ) { if( !v.p ) { // revert scd.init( line->get_schedule(), player, convoihandle_t(), line ); reset_min_windowsize(); } return true; } else if( comp == &switch_mode ) { bool edit_schedule = switch_mode.get_aktives_tab() == &container_schedule; if( edit_schedule ) { scd.init( line->get_schedule(), player, convoihandle_t(), line ); scd.highlight_schedule( true ); reset_min_windowsize(); } else { default_opening_tab = v.i; scd.highlight_schedule( false ); apply_schedule(); } } else if( comp == &inp_name ) { rename_line(); } else if( comp == &bt_delete_line ) { if( line.is_bound() ) { tool_t *tmp_tool = create_tool( TOOL_CHANGE_LINE | SIMPLE_TOOL ); cbuffer_t buf; buf.printf( "d,%i", line.get_id() ); tmp_tool->set_default_param(buf); welt->set_tool( tmp_tool, player ); // since init always returns false, it is safe to delete immediately delete tmp_tool; depot_t::update_all_win(); } } else if( comp == &bt_withdraw_line ) { bt_withdraw_line.pressed ^= 1; if ( line.is_bound() ) { tool_t *tmp_tool = create_tool( TOOL_CHANGE_LINE | SIMPLE_TOOL ); cbuffer_t buf; buf.printf( "w,%i,%i", line.get_id(), bt_withdraw_line.pressed ); tmp_tool->set_default_param(buf); welt->set_tool( tmp_tool, player ); // since init always returns false, it is safe to delete immediately delete tmp_tool; } } else if( comp == &bt_find_convois ) { for(convoihandle_t cnv : welt->convoys()) { if( cnv->get_owner()==player ) { if( !cnv->get_line().is_bound() ) { if( line->get_schedule()->matches( welt, cnv->get_schedule() ) ) { // same schedule, and no line =< add to line char id[16]; sprintf(id, "%i,%i", line.get_id(), cnv->get_schedule()->get_current_stop()); cnv->call_convoi_tool('l', id); } } } } } else { const vector_tpl &l = button_to_chart.list(); for( uint32 i = 0; iget_button() ) { cost_type_default[i] = l[i]->get_button()->pressed; break; } } } return false; } void line_management_gui_t::rename_line() { if( line.is_bound() ) { const char *t = inp_name.get_text(); // only change if old name and current name are the same // otherwise some unintended undo if renaming would occur if( t && t[0] && strcmp(t, line->get_name()) && strcmp(old_line_name, line->get_name())==0 ) { // text changed => call tool cbuffer_t buf; buf.printf( "l%u,%s", line.get_id(), t ); tool_t *tmp_tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tmp_tool->set_default_param( buf ); welt->set_tool( tmp_tool, line->get_owner() ); // since init always returns false, it is safe to delete immediately delete tmp_tool; // do not trigger this command again tstrncpy(old_line_name, t, sizeof(old_line_name)); } } } bool line_management_gui_t::infowin_event( const event_t *ev ) { if( ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE ) { if( switch_mode.get_aktives_tab() == &container_schedule && !is_saving_gui ) { apply_schedule(); } scd.highlight_schedule( false ); minimap_t::get_instance()->set_selected_cnv(convoihandle_t()); } if( ev->ev_class == INFOWIN && ev->ev_code == WIN_TOP ) { if( switch_mode.get_aktives_tab() == &container_schedule ) { scd.highlight_schedule( true ); } if (line->count_convoys() > 0) { minimap_t::get_instance()->set_selected_cnv(line->get_convoy(0)); } } is_saving_gui = false; return gui_frame_t::infowin_event( ev ); } simutrans-124.3/src/simutrans/gui/line_management_gui.h000066400000000000000000000044141474050137200233160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LINE_MANAGEMENT_GUI_H #define GUI_LINE_MANAGEMENT_GUI_H #include "simwin.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_button_to_chart.h" #include "components/gui_chart.h" #include "components/gui_label.h" #include "components/gui_schedule.h" #include "components/gui_scrolled_list.h" #include "components/gui_speedbar.h" #include "components/gui_tab_panel.h" #include "components/gui_textarea.h" #include "components/gui_textinput.h" #include "../linehandle.h" class player_t; class loadsave_t; class line_management_gui_t : public gui_frame_t, public action_listener_t { linehandle_t line; gui_textinput_t inp_name; gui_label_t lb_convoi_count; cbuffer_t lb_convoi_count_text; gui_speedbar_t capacity_bar; cbuffer_t lb_profit_value_text; gui_label_t lb_profit_value; button_t bt_delete_line; gui_tab_panel_t switch_mode; gui_schedule_t scd; gui_chart_t chart; gui_button_to_chart_array_t button_to_chart; button_t bt_withdraw_line, bt_find_convois; gui_scrolled_list_t scrolly_convois, scrolly_halts; gui_aligned_container_t container_schedule, container_stats, container_convois, container_halts; cbuffer_t loading_text; gui_textarea_t loading_info; player_t *player; // so even japanese can have long enough names ... char line_name[512], old_line_name[512]; // rename selected line // checks if possible / necessary void rename_line(); uint32 old_convoi_count, old_halt_count; sint32 capacity, load; // only true if the window is closing due to finishign a game. The changes will not apply! bool is_saving_gui; void init(bool); void apply_schedule(); public: line_management_gui_t(linehandle_t line = linehandle_t(), player_t* player_ = NULL, int active_tab=0 ); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void draw(scr_coord pos, scr_size size) OVERRIDE; // stuff for UI saving void rdwr( loadsave_t *file ) OVERRIDE; const char *get_help_filename() const OVERRIDE { return "linedetails.txt"; } bool infowin_event( const event_t *ev ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_line_schedule_rdwr_dummy; } }; #endif simutrans-124.3/src/simutrans/gui/load_relief_frame.cc000066400000000000000000000104151474050137200231020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../world/simworld.h" #include "load_relief_frame.h" #include "welt.h" #include "simwin.h" #include "../dataobj/translator.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/height_map_loader.h" #include "components/gui_scrolled_list.h" static const char *load_mode_texts[env_t::NUM_HEIGHT_CONV_MODES] = { "legacy (small heights)", "legacy (large heights)", "linear", "clamp" }; class load_relief_mode_scrollitem_t : public gui_scrolled_list_t::const_text_scrollitem_t { public: load_relief_mode_scrollitem_t(env_t::height_conversion_mode mode) : gui_scrolled_list_t::const_text_scrollitem_t(translator::translate(load_mode_texts[(int)mode]), SYSCOL_TEXT), mode(mode) {} env_t::height_conversion_mode get_mode() const { return mode; } private: env_t::height_conversion_mode mode; }; /** * Action, started on button pressing */ bool load_relief_frame_t::item_action(const char *fullpath) { sets->heightfield = fullpath; if (gui_frame_t *new_world_gui = win_get_magic( magic_welt_gui_t )) { const gui_scrolled_list_t::scrollitem_t *selected = load_mode.get_selected_item(); if (selected) { env_t::height_conv_mode = static_cast(selected)->get_mode(); } static_cast(new_world_gui)->update_preview(true); } return false; } load_relief_frame_t::load_relief_frame_t(settings_t* const sets) : savegame_frame_t( NULL, false, "maps/", true ) { gui_aligned_container_t *table = bottom_left_frame.add_table(2, 1); load_mode_label.init(translator::translate("Load mode:"), scr_coord(0, 0)); load_mode_label.set_visible(true); table->add_component( &load_mode_label ); load_mode.init(scr_coord(0, 0)); load_mode.new_component(env_t::HEIGHT_CONV_LEGACY_SMALL); load_mode.new_component(env_t::HEIGHT_CONV_LEGACY_LARGE); load_mode.new_component(env_t::HEIGHT_CONV_LINEAR); load_mode.new_component(env_t::HEIGHT_CONV_CLAMP); load_mode.set_selection(env_t::HEIGHT_CONV_LINEAR); load_mode.add_listener(this); table->add_component( &load_mode ); bottom_left_frame.end_table(); const std::string extra_path = env_t::pak_dir + "maps/"; this->add_path(extra_path.c_str()); set_name(translator::translate("Lade Relief")); this->sets = sets; sets->heightfield = ""; } const char *load_relief_frame_t::get_info(const char *fullpath) { static char size[64]; sint16 w, h; sint8 *h_field = NULL; const sint8 min_h = world()->get_settings().get_minimumheight(); const sint8 max_h = world()->get_settings().get_maximumheight(); const gui_scrolled_list_t::scrollitem_t *selected = load_mode.get_selected_item(); env_t::height_conversion_mode new_mode = env_t::height_conv_mode; if (selected) { new_mode = static_cast(selected)->get_mode(); } height_map_loader_t hml(min_h, max_h, new_mode); if(hml.get_height_data_from_file(fullpath, (sint8)sets->get_groundwater(), h_field, w, h, true )) { sprintf( size, "%i x %i", w, h ); env_t::height_conv_mode = new_mode; return size; } return ""; } bool load_relief_frame_t::check_file( const char *fullpath, const char * ) { const sint8 min_h = world()->get_settings().get_minimumheight(); const sint8 max_h = world()->get_settings().get_maximumheight(); const gui_scrolled_list_t::scrollitem_t *selected = load_mode.get_selected_item(); env_t::height_conversion_mode new_mode = env_t::height_conv_mode; if (selected) { new_mode = static_cast(selected)->get_mode(); } height_map_loader_t hml(min_h, max_h, env_t::height_conv_mode); sint16 w, h; sint8 *h_field = NULL; if(hml.get_height_data_from_file(fullpath, (sint8)sets->get_groundwater(), h_field, w, h, true )) { env_t::height_conv_mode = new_mode; return w>0 && h>0; } return false; } bool load_relief_frame_t::action_triggered(gui_action_creator_t* comp, value_t extra) { if (comp == &load_mode) { return item_action(sets->heightfield.c_str()); } else { return savegame_frame_t::action_triggered(comp, extra); } } simutrans-124.3/src/simutrans/gui/load_relief_frame.h000066400000000000000000000015741474050137200227520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LOAD_RELIEF_FRAME_H #define GUI_LOAD_RELIEF_FRAME_H #include "components/gui_combobox.h" #include "savegame_frame.h" class settings_t; class load_relief_frame_t : public savegame_frame_t { private: settings_t* sets; gui_label_t load_mode_label; gui_combobox_t load_mode; protected: bool item_action(const char *fullpath) OVERRIDE; const char *get_info(const char *fullpath) OVERRIDE; bool check_file(const char *fullpath, const char *suffix) OVERRIDE; public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE { return "load_relief.txt"; } load_relief_frame_t(settings_t*); bool action_triggered(gui_action_creator_t *comp, value_t extra) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/loadfont_frame.cc000066400000000000000000000152411474050137200224450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include #include #include #include "loadfont_frame.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../simversion.h" #include "../pathes.h" #include "../utils/unicode.h" #include "../utils/searchfolder.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "gui_theme.h" #include "../utils/simstring.h" // static, since we keep them over reloading std::string loadfont_frame_t::old_fontname; uint8 loadfont_frame_t::old_linespace; bool loadfont_frame_t::use_unicode=true; bool loadfont_frame_t::is_resizable_font (const char *fontname) { const char *start_extension = strrchr(fontname, '.' ); return start_extension && STRICMP( start_extension, ".fnt" ) && STRICMP( start_extension, ".bdf" ); } /** * Action that's started with a button click */ bool loadfont_frame_t::item_action(const char *filename) { fontsize.enable( is_resizable_font(filename) ); win_load_font(filename, env_t::fontsize); return false; } bool loadfont_frame_t::ok_action(const char *filename) { item_action(filename); old_fontname.clear(); return true; } bool loadfont_frame_t::cancel_action(const char *) { win_load_font(old_fontname.c_str(), old_linespace); old_fontname.clear(); return true; } loadfont_frame_t::loadfont_frame_t() : savegame_frame_t(NULL,false,NULL,false) { set_name(translator::translate("Select display font")); use_unicode = true; // only try matching fonts top_frame.remove_component(&input); fontsize.init( env_t::fontsize, 6, 40, gui_numberinput_t::AUTOLINEAR, false ); fontsize.add_listener(this); fontsize.enable( is_resizable_font(env_t::fontname.c_str()) ); fnlabel.set_text( "font size" ); top_frame.add_component(&fontsize); unicode_only.init( button_t::square_automatic, "Only full Unicode fonts"); unicode_only.pressed = use_unicode; unicode_only.add_listener(this); top_frame.add_component(&unicode_only, 2); } const char *loadfont_frame_t::get_info(const char *fname) { return fname; } bool loadfont_frame_t::compare_items ( const dir_entry_t & entry, const char *info, const char *) { return (STRICMP(entry.info, info) > 0); } /** * CHECK FILE * Check if a file name qualifies to be added to the item list. */ bool loadfont_frame_t::check_file(const char *filename, const char *) { FILE *test = dr_fopen( filename, "r" ); if( test == NULL ) { return false; } fclose(test); // just match textension for buildin fonts const char *start_extension = strrchr(filename, '.' ); // we only show matching fonts for this language const utf8 *new_world = (const utf8 *)translator::translate("Beenden"); size_t len; utf16 testfor_this_character = utf8_decoder_t::decode(new_world, len); // no support for windows fon files, so we skip them to speed things up if( start_extension && !STRICMP( start_extension, ".fon" ) ) { return false; } #if COLOUR_DEPTH != 0 if( ft_library ) { // if we can open this font, it is probably ok ... FT_Face face; if( !FT_New_Face( ft_library, filename, 0, &face ) ) { // can load (no error returned) bool ok = false; if( FT_Get_Char_Index( face, '}' )!=0 && (STRICMP(face->style_name,"Regular")==0 || STRICMP(face->style_name,"Bold")==0) ) { // ok, we have at least charecter 126, and it is a regular font, so it is probably a valid font) ok = !use_unicode; if( FT_Get_Char_Index(face, testfor_this_character)!=0 ) { // the char NAMA does exist ok = true; // in pricipal we must also check if it can be rendered ... } } FT_Done_Face(face); return ok; } // next check for extension, might be still a valid font } #endif return false; } // parses the directory, using freetype lib, in installed void loadfont_frame_t::fill_list() { add_path( ((std::string)env_t::base_dir+"font/").c_str() ); #if COLOUR_DEPTH != 0 // ok, we can handle TTF fonts ft_library = NULL; if( FT_Init_FreeType(&ft_library) != FT_Err_Ok ) { ft_library = NULL; } else { const char *addpath; searchfolder_t subfolders; for( int i=0; ( addpath = dr_query_fontpath(i) ); i++ ) { add_path( addpath ); subfolders.search(addpath, "", searchfolder_t::SF_ONLYDIRS | searchfolder_t::SF_PREPEND_PATH, 4); for( const char * folder : subfolders ){ add_path( ((std::string) folder + PATH_SEPARATOR).c_str() ); } } } #endif if( old_fontname.empty() ) { old_fontname = env_t::fontname; old_linespace = env_t::fontsize; } // do the search ... savegame_frame_t::fill_list(); // mark current fonts for(dir_entry_t const& i : entries) { if (i.type == LI_HEADER) { continue; } i.button->set_typ(button_t::roundbox_state | button_t::flexible); #if COLOUR_DEPTH == 0 } #else // Use internal name instead the cutted file name if( ft_library ) { FT_Face face; if( FT_New_Face( ft_library, i.info, 0, &face )==FT_Err_Ok ) { if ( face->family_name ) { const size_t len = strlen(face->family_name) + 1 + (face->style_name ? strlen(face->style_name) + 1 : 0); char *name = new char[len]; strcpy( name, face->family_name ); if (face->style_name) { strcat( name, " "); strcat( name, face->style_name ); } delete [] const_cast(i.button->get_text()); i.button->set_text(name); i.button->pressed = strstr( env_t::fontname.c_str(), i.info ) != NULL; } FT_Done_Face( face ); } } } FT_Done_FreeType( ft_library ); ft_library = NULL; #endif // force new resize after we have rearranged the gui resize(scr_coord(0,0)); } void loadfont_frame_t::draw(scr_coord pos, scr_size size) { // mark current fonts for(dir_entry_t const& i : entries) { if (i.type == LI_HEADER) { continue; } i.button->pressed = strstr( env_t::fontname.c_str(), i.info ); } savegame_frame_t::draw(pos, size); } void loadfont_frame_t::rdwr( loadsave_t *file ) { file->rdwr_bool( unicode_only.pressed ); scr_size size = get_windowsize(); size.rdwr( file ); if( file->is_loading() ) { set_windowsize( size ); resize( scr_coord(0,0) ); } } bool loadfont_frame_t::action_triggered(gui_action_creator_t *component, value_t v) { if( &unicode_only==component ) { // send event, this will reload window event_t *ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event( ev ); use_unicode = unicode_only.pressed; return false; } if( &fontsize==component ) { win_load_font(env_t::fontname.c_str(), fontsize.get_value()); fontsize.set_limits(6, 40); return false; } return savegame_frame_t::action_triggered(component,v); } simutrans-124.3/src/simutrans/gui/loadfont_frame.h000066400000000000000000000034571474050137200223150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LOADFONT_FRAME_H #define GUI_LOADFONT_FRAME_H #if COLOUR_DEPTH != 0 #include "gui_theme.h" #include "../sys/simsys.h" #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_TRUETYPE_TABLES_H #endif #include "simwin.h" #include "savegame_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_numberinput.h" #include "../tpl/stringhashtable_tpl.h" #include class loadfont_frame_t : public savegame_frame_t { private: #if COLOUR_DEPTH != 0 FT_Library ft_library; #endif static bool use_unicode; protected: static std::string old_fontname; static uint8 old_linespace; button_t unicode_only; gui_numberinput_t fontsize; bool is_resizable_font (const char *fontname); /** * Action that's started with a button click */ bool item_action (const char *filename) OVERRIDE; bool ok_action (const char *fullpath) OVERRIDE; bool cancel_action(const char *) OVERRIDE; // returns extra file info const char *get_info(const char *fname) OVERRIDE; // sort with respect to info, which is date bool compare_items ( const dir_entry_t & entry, const char *info, const char *) OVERRIDE; bool check_file( const char *filename, const char *suffix ) OVERRIDE; void fill_list() OVERRIDE; public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE { return "load_font.txt"; } loadfont_frame_t(); void draw(scr_coord pos, scr_size size) OVERRIDE; uint32 get_rdwr_id( void ) OVERRIDE { return magic_font; } void rdwr( loadsave_t *file ) OVERRIDE; bool action_triggered(gui_action_creator_t *, value_t v) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/loadsave_frame.cc000066400000000000000000000060071474050137200224350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include #include "loadsave_frame.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../simversion.h" #include "../pathes.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/sve_cache.h" #include "../network/network.h" #include "../network/network_cmd.h" #include "../network/network_cmd_ingame.h" #include "../network/network_socket_list.h" #include "../utils/simstring.h" /** * Action that's started with a button click */ bool loadsave_frame_t::item_action(const char *filename) { if(do_load) { welt->switch_server( easy_server.pressed, true ); long start_load = dr_time(); if( !welt->load(filename) ) { welt->switch_server( false, true ); } else { if (env_t::server) { welt->announce_server(karte_t::SERVER_ANNOUNCE_HELLO); } welt->type_of_generation = karte_t::LOADED_WORLD; } DBG_MESSAGE( "loadsave_frame_t::item_action", "load world %li ms", dr_time() - start_load ); } else { // saving a game if( env_t::server || socket_list_t::get_playing_clients() > 0 ) { network_reset_server(); #if 0 // TODO: saving without kicking all clients off ... // we have connected clients, so we do a sync const uint32 new_map_counter = welt->generate_new_map_counter(); nwc_sync_t *nw_sync = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), -1, new_map_counter); network_send_all(nw_sync, false); // and now we need to copy the servergame to the map ... #endif } long start_save = dr_time(); welt->save( filename, false, env_t::savegame_version_str, false ); DBG_MESSAGE( "loadsave_frame_t::item_action", "save world %li ms", dr_time() - start_save ); welt->set_dirty(); welt->reset_timer(); } return true; } bool loadsave_frame_t::ok_action(const char *filename) { return item_action(filename); } loadsave_frame_t::loadsave_frame_t(bool do_load, bool back_to_menu) : savegame_frame_t(".sve",false,"save/",true, back_to_menu) { this->do_load = do_load; if(do_load) { set_name(translator::translate("Laden")); easy_server.init( button_t::square_automatic, "Start this as a server"); bottom_left_frame.add_component(&easy_server); } else { set_filename(welt->get_settings().get_filename()); set_name(translator::translate("Save")); } sve_cache_t::load_cache(); } const char *loadsave_frame_t::get_info(const char *fname) { return sve_cache_t::get_info(fname); } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *loadsave_frame_t::get_help_filename() const { return do_load ? "load.txt" : "save.txt"; } loadsave_frame_t::~loadsave_frame_t() { // save hashtable sve_cache_t::write_cache(); } bool loadsave_frame_t::compare_items ( const dir_entry_t & entry, const char *info, const char *) { return (strcmp(entry.label->get_text_pointer(), info) < 0); } simutrans-124.3/src/simutrans/gui/loadsave_frame.h000066400000000000000000000021421474050137200222730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LOADSAVE_FRAME_H #define GUI_LOADSAVE_FRAME_H #include #include "savegame_frame.h" #include "../tpl/stringhashtable_tpl.h" #include class loadsave_t; class sve_info_t; class loadsave_frame_t : public savegame_frame_t { private: bool do_load; button_t easy_server; // only active on loading savegames protected: /** * Action that's started with a button click */ bool item_action (const char *filename) OVERRIDE; bool ok_action (const char *fullpath) OVERRIDE; // returns extra file info const char *get_info(const char *fname) OVERRIDE; // sort with respect to info, which is date bool compare_items ( const dir_entry_t & entry, const char *info, const char *) OVERRIDE; public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE; loadsave_frame_t(bool do_load, bool back_to_menu = false); /** * save hashtable to xml file */ ~loadsave_frame_t(); }; #endif simutrans-124.3/src/simutrans/gui/loadsoundfont_frame.cc000066400000000000000000000064331474050137200235210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include #include "loadsoundfont_frame.h" #include "../pathes.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../music/music.h" #include "../simsound.h" #include "gui_theme.h" #include "../utils/simstring.h" // static, since we keep them over reloading std::string loadsoundfont_frame_t::old_soundfontname; /** * Action that's started with a button click */ bool loadsoundfont_frame_t::item_action(const char *filename) { if( dr_load_sf( filename ) && midi_get_mute() ) { midi_set_mute( false ); midi_play( env_t::shuffle_midi ? -1 : 0 ); } return false; } bool loadsoundfont_frame_t::ok_action(const char *filename) { item_action( filename ); old_soundfontname.clear(); return true; } bool loadsoundfont_frame_t::cancel_action(const char *) { dr_load_sf( old_soundfontname.c_str() ); old_soundfontname.clear(); return true; } loadsoundfont_frame_t::loadsoundfont_frame_t() : savegame_frame_t(NULL,false,NULL,false) { set_name( translator::translate("Select soundfont") ); fnlabel.set_text("Soundfonts are located in the music directory."); top_frame.remove_component( &input ); } const char *loadsoundfont_frame_t::get_info(const char *sfname) { return sfname; } bool loadsoundfont_frame_t::compare_items ( const dir_entry_t & entry, const char *info, const char *) { return (STRICMP(entry.info, info) > 0); } /** * CHECK FILE * Check if a file name qualifies to be added to the item list. */ bool loadsoundfont_frame_t::check_file(const char *filename, const char *) { FILE *test = fopen( filename, "r" ); if( test == NULL ) { return false; } fclose( test ); // just match extension for building soundfonts const char *start_extension = strrchr(filename, '.' ); if( start_extension && ( !STRICMP( start_extension, ".sf2" ) || !STRICMP( start_extension, ".sf3" ) ) ) { return true; } return false; } // parses the directory void loadsoundfont_frame_t::fill_list() { add_path( ((std::string)env_t::base_dir + "music/").c_str() ); add_path( "/usr/share/soundfonts/" ); add_path( "/usr/share/sounds/sf2/" ); if( old_soundfontname.empty() ) { old_soundfontname = env_t::soundfont_filename; } // do the search ... savegame_frame_t::fill_list(); // mark current fonts for(dir_entry_t const& i : entries ) { if( i.type == LI_HEADER ) { continue; } i.button->set_typ( button_t::roundbox_state | button_t::flexible ); } // force new resize after we have rearranged the gui resize( scr_coord(0,0) ); } void loadsoundfont_frame_t::draw(scr_coord pos, scr_size size) { // mark current fonts for(dir_entry_t const& i : entries) { if( i.type == LI_HEADER ) { continue; } i.button->pressed = strstr( env_t::soundfont_filename.c_str(), i.info ); } savegame_frame_t::draw( pos, size ); } void loadsoundfont_frame_t::rdwr( loadsave_t *file ) { scr_size size = get_windowsize(); size.rdwr( file ); if( file->is_loading() ) { set_windowsize( size ); resize( scr_coord(0,0) ); } } bool loadsoundfont_frame_t::action_triggered(gui_action_creator_t *component, value_t v) { return savegame_frame_t::action_triggered( component, v ); } simutrans-124.3/src/simutrans/gui/loadsoundfont_frame.h000066400000000000000000000026361474050137200233640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_LOADSOUNDFONT_FRAME_H #define GUI_LOADSOUNDFONT_FRAME_H #include "simwin.h" #include "savegame_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "../tpl/stringhashtable_tpl.h" #include class loadsoundfont_frame_t : public savegame_frame_t { protected: static std::string old_soundfontname; /** * Action that's started with a button click */ bool item_action (const char *filename) OVERRIDE; bool ok_action (const char *fullpath) OVERRIDE; bool cancel_action(const char *) OVERRIDE; // returns extra file info const char *get_info(const char *fname) OVERRIDE; // sort with respect to info, which is date bool compare_items ( const dir_entry_t & entry, const char *info, const char *) OVERRIDE; bool check_file( const char *filename, const char *suffix ) OVERRIDE; void fill_list() OVERRIDE; public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE { return "load_soundfont.txt"; } loadsoundfont_frame_t(); void draw(scr_coord pos, scr_size size) OVERRIDE; uint32 get_rdwr_id( void ) OVERRIDE { return magic_soundfont; } void rdwr( loadsave_t *file ) OVERRIDE; bool action_triggered(gui_action_creator_t *, value_t v) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/map_frame.cc000066400000000000000000000667521474050137200214310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "minimap.h" #include "map_frame.h" #include "simwin.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../simcolor.h" #include "../builder/fabrikbauer.h" #include "../builder/goods_manager.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../dataobj/koord.h" #include "../dataobj/loadsave.h" #include "../descriptor/factory_desc.h" #include "../simfab.h" #include "../player/finance.h" static koord old_ij=koord::invalid; karte_ptr_t map_frame_t::welt; scr_size map_frame_t::window_size; bool map_frame_t::legend_visible=false; bool map_frame_t::network_option_visible = false; bool map_frame_t::scale_visible=false; bool map_frame_t::directory_visible=false; bool map_frame_t::filter_factory_list=true; bool map_frame_t::zoomed = true; // we track our position onscreen scr_coord map_frame_t::screenpos; /** * Entries in factory legend: show color indicator + name */ class legend_entry_t : public gui_component_t { gui_label_t label; PIXVAL color; public: legend_entry_t(const char* text, PIXVAL c) : label(text), color(c) {} scr_size get_min_size() const OVERRIDE { return label.get_min_size() + scr_size(D_INDICATOR_BOX_WIDTH + D_H_SPACE, 0); } scr_size get_max_size() const OVERRIDE { return scr_size( scr_size::inf.w, label.get_max_size().h ); } void draw(scr_coord offset) OVERRIDE { scr_coord pos = get_pos() + offset; display_fillbox_wh_clip_rgb( pos.x, pos.y+D_GET_CENTER_ALIGN_OFFSET(D_INDICATOR_BOX_HEIGHT,LINESPACE), D_INDICATOR_BOX_WIDTH, D_INDICATOR_BOX_HEIGHT, color, false ); label.draw( pos+scr_size(D_INDICATOR_BOX_WIDTH+D_H_SPACE,0) ); } }; /** * Show scale of severity-MAX_SEVERITY_COLORS */ class gui_scale_t : public gui_component_t { public: void draw(scr_coord offset) OVERRIDE { scr_coord pos = get_pos() + offset; double bar_width = (double)get_size().w/(double)MAX_SEVERITY_COLORS; // color bar for( int i=0; ichange_zoom_factor(magnify)) { map_frame_t::zoomed = true; // recalculate scroll bar width scrolly.set_size(scrolly.get_size()); // invalidate old offsets old_ij = koord::invalid; return true; } return false; } map_frame_t::map_frame_t() : gui_frame_t( translator::translate("Reliefkarte") ), karte(minimap_t::get_instance()), scrolly(karte) { // init statics old_ij = koord::invalid; zoomed = false; karte->init(); karte->set_display_mode( ( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode ); // show all players by default karte->player_showed_on_map = -1; // init map scrolly.set_maximize(true); scrolly.set_min_width(D_DEFAULT_WIDTH - D_MARGIN_LEFT - D_MARGIN_RIGHT); // map the current position visible const koord ij = welt->get_viewport()->get_world_position(); const scr_size size = karte->get_size(); const scr_size s_size = scrolly.get_size(); const scr_size win_size = size - s_size; // this is the visible area scrolly.set_scroll_position( clamp(ij.x-win_size.w/2, 0, size.w), clamp(ij.y-win_size.h/2, 0, size.h) ); scrolly.set_focusable( true ); scrolly.set_scrollbar_mode(scrollbar_t::show_always); set_table_layout(1,0); // first row of controls add_table(D_BUTTONS_PER_ROW,0); { // first row of controls b_show_network_option.init(button_t::roundbox_state, "Show networks"); b_show_network_option.set_tooltip("Shows buttons on network overlay."); b_show_network_option.set_size(D_BUTTON_SIZE); b_show_network_option.add_listener(this); add_component(&b_show_network_option); // selections button b_show_legend.init(button_t::roundbox_state, "Show legend"); b_show_legend.set_tooltip("Shows buttons on special topics."); b_show_legend.add_listener(this); add_component(&b_show_legend); // industry list button b_show_directory.init(button_t::roundbox_state, "Show industry"); b_show_directory.set_tooltip("Shows a listing with all industries on the map."); b_show_directory.add_listener(this); add_component(&b_show_directory); // scale button b_show_scale.init(button_t::roundbox_state, "Show map scale"); b_show_scale.set_tooltip("Shows the color code for several selections."); b_show_scale.add_listener(this); add_component(&b_show_scale); } end_table(); // second row of controls if (D_BUTTONS_PER_ROW >= 4) { zoom_row = add_table(0, 1); { // zoom levels label new_component("map zoom"); // zoom levels arrow left zoom_buttons[0].init(button_t::repeatarrowleft, NULL); zoom_buttons[0].add_listener(this); add_component(zoom_buttons + 0); // zoom level value label sint16 zoom_in, zoom_out; minimap_t::get_instance()->get_zoom_factors(zoom_out, zoom_in); zoom_value_label.buf().printf("%i:%i", zoom_in, zoom_out); zoom_value_label.update(); add_component(&zoom_value_label); // zoom levels arrow right zoom_buttons[1].init(button_t::repeatarrowright, NULL); zoom_buttons[1].add_listener(this); add_component(zoom_buttons + 1); } } else { // narrow screen zoom_row = add_table(0, 1); { // zoom levels label new_component("map zoom"); // zoom levels arrow left zoom_buttons[0].init(button_t::repeatarrowleft, NULL); zoom_buttons[0].add_listener(this); add_component(zoom_buttons + 0); // zoom level value label sint16 zoom_in, zoom_out; minimap_t::get_instance()->get_zoom_factors(zoom_out, zoom_in); zoom_value_label.buf().printf("%i:%i", zoom_in, zoom_out); zoom_value_label.update(); add_component(&zoom_value_label); // zoom levels arrow right zoom_buttons[1].init(button_t::repeatarrowright, NULL); zoom_buttons[1].add_listener(this); add_component(zoom_buttons + 1); new_component(); } end_table(); add_table(0,1); } { // rotate map 45 degrees (isometric view) b_rotate45.init( button_t::square_state, "isometric map"); b_rotate45.set_tooltip("Similar view as the main window"); b_rotate45.add_listener(this); b_rotate45.pressed = karte->is_isometric(); add_component(&b_rotate45); // show contour c_show_outlines.new_component( translator::translate( "Show contour" ), SYSCOL_TEXT ); c_show_outlines.new_component( translator::translate( "Show climates" ), SYSCOL_TEXT ); c_show_outlines.new_component( translator::translate( "Show outline" ), SYSCOL_TEXT ); c_show_outlines.add_listener( this ); if( (env_t::default_mapmode & minimap_t::MAP_CLIMATES) != 0 ) { c_show_outlines.set_selection( 1 ); } else if( (env_t::default_mapmode & minimap_t::MAP_HIDE_CONTOUR) != 0 ) { c_show_outlines.set_selection( 2 ); } else { c_show_outlines.set_selection( 0 ); } add_component(&c_show_outlines); new_component(); } end_table(); // networks filter container network_filter_container.set_visible(false); add_component(&network_filter_container); if (D_BUTTONS_PER_ROW == 4) { network_filter_container.set_table_layout(0, 1); } else { network_filter_container.set_table_layout(1, 0); } network_filter_container.add_table(0, 1); // insert selections: show networks, in filter container b_overlay_networks.init(button_t::square_state, "Networks"); b_overlay_networks.set_tooltip("Overlay schedules/network"); b_overlay_networks.add_listener(this); b_overlay_networks.pressed = (env_t::default_mapmode & minimap_t::MAP_LINES)!=0; network_filter_container.add_component( &b_overlay_networks ); // player combo for network overlay viewed_player_c.new_component(translator::translate("All"), SYSCOL_TEXT); viewable_players[ 0 ] = -1; for( int np = 0, count = 1; np < MAX_PLAYER_COUNT; np++ ) { if( welt->get_player( np ) && welt->get_player( np )->get_finance()->has_convoi()) { viewed_player_c.new_component(welt->get_player( np )->get_name(), color_idx_to_rgb(welt->get_player( np )->get_player_color1()+env_t::gui_player_color_dark)); viewable_players[ count++ ] = np; } } viewed_player_c.set_selection(0); viewed_player_c.set_focusable( true ); viewed_player_c.add_listener( this ); network_filter_container.add_component(&viewed_player_c); network_filter_container.end_table(); // freight combo for network overlay network_filter_container.add_table(0, 1); { viewable_freight_types.append(NULL); freight_type_c.new_component( translator::translate("All"), SYSCOL_TEXT) ; viewable_freight_types.append(goods_manager_t::passengers); freight_type_c.new_component( translator::translate("Passagiere"), SYSCOL_TEXT) ; viewable_freight_types.append(goods_manager_t::mail); freight_type_c.new_component( translator::translate("Post"), SYSCOL_TEXT) ; viewable_freight_types.append(goods_manager_t::none); // for all freight ... freight_type_c.new_component( translator::translate("Fracht"), SYSCOL_TEXT) ; for( int i = 0; i < goods_manager_t::get_max_catg_index(); i++ ) { const goods_desc_t *freight_type = goods_manager_t::get_info_catg(i); const int index = freight_type->get_catg_index(); if( index == goods_manager_t::INDEX_NONE || freight_type->get_catg()==0 ) { continue; } freight_type_c.new_component(translator::translate(freight_type->get_catg_name()), SYSCOL_TEXT); viewable_freight_types.append(freight_type); } for( int i=0; i < goods_manager_t::get_count(); i++ ) { const goods_desc_t *ware = goods_manager_t::get_info(i); if( ware->get_catg() == 0 && ware->get_index() > 2 ) { // Special freight: Each good is special viewable_freight_types.append(ware); freight_type_c.new_component( translator::translate(ware->get_name()), SYSCOL_TEXT) ; } } } freight_type_c.set_selection(0); minimap_t::get_instance()->freight_type_group_index_showed_on_map = NULL; freight_type_c.set_focusable( true ); freight_type_c.add_listener( this ); network_filter_container.add_component(&freight_type_c); // mode of transport combo for network overlay for (int i = 0; i < simline_t::MAX_LINE_TYPE; i++) { transport_type_c.new_component(simline_t::get_linetype_name((simline_t::linetype)i), SYSCOL_TEXT); } transport_type_c.set_selection(0); minimap_t::get_instance()->transport_type_showed_on_map = simline_t::line; transport_type_c.set_focusable( true ); transport_type_c.add_listener( this ); network_filter_container.add_component(&transport_type_c); b_overlay_networks_load_factor.init(button_t::square_state, "Free Capacity"); b_overlay_networks_load_factor.set_tooltip("Color according to transport capacity left"); b_overlay_networks_load_factor.add_listener(this); b_overlay_networks_load_factor.pressed = 0; minimap_t::get_instance()->show_network_load_factor = 0; network_filter_container.add_component( &b_overlay_networks_load_factor ); network_filter_container.end_table(); // filter container filter_container.set_visible(false); add_component(&filter_container); filter_container.set_table_layout(1, 0); int w = network_filter_container.get_min_size().w; const int FILTER_BUTTONS_PER_ROW = max(3, min(5, max(display_get_width(),w) / (D_BUTTON_WIDTH + D_H_SPACE + D_MARGIN_LEFT))); filter_container.add_table(FILTER_BUTTONS_PER_ROW,0)->set_force_equal_columns(true); // insert filter buttons in legend container for (int index=0; index("min"); scale_container.new_component(); scale_container.new_component("max"); // map scrolly scrolly.set_show_scroll_x(true); scrolly.set_scroll_discrete_y(false); add_component(&scrolly); // restore window size and options show_hide_legend( legend_visible ); show_hide_network_option( network_option_visible ); show_hide_scale( scale_visible ); show_hide_directory( directory_visible ); reset_min_windowsize(); set_windowsize( window_size ); set_resizemode(diagonal_resize); } void map_frame_t::update_buttons() { for( int i=0; iget_supplier_count() == 0; const bool b_producer_only = b->get_supplier_count() == 0; const bool a_consumer_only = a->get_product_count() == 0; const bool b_consumer_only = b->get_product_count() == 0; if (a_producer_only != b_producer_only) { return a_producer_only; // producers to the front } else if (a_consumer_only != b_consumer_only) { return !a_consumer_only; // consumers to the end } else { // both of same type, sort by name return strcmp(translator::translate(a->get_name()), translator::translate(b->get_name())) < 0; } } void map_frame_t::update_factory_legend() { directory_container.remove_all(); directory_container.add_component( &b_filter_factory_list, 4 ); if( directory_visible ) { vector_tpl factory_types; // generate list of factory types if( filter_factory_list ) { for(fabrik_t* const f : welt->get_fab_list()) { if( f->get_desc()->get_distribution_weight() > 0 ) { factory_types.insert_unique_ordered(f->get_desc(), compare_factories); } } } else { for(auto i : factory_builder_t::get_factory_table()) { factory_desc_t const* const d = i.value; if (d->get_distribution_weight() > 0) { factory_types.insert_unique_ordered(d, compare_factories); } } } // now sort // add corresponding legend entries for(const factory_desc_t* f : factory_types) { directory_container.new_component(f->get_name(), f->get_color()); } } } void map_frame_t::show_hide_legend(const bool show) { filter_container.set_visible(show); b_show_legend.pressed = show; legend_visible = show; reset_min_windowsize(); } void map_frame_t::show_hide_network_option(const bool show) { network_filter_container.set_visible(show); b_show_network_option.pressed = show; network_option_visible = show; reset_min_windowsize(); } void map_frame_t::show_hide_scale(const bool show) { scale_container.set_visible(show); b_show_scale.pressed = show; scale_visible = show; reset_min_windowsize(); } void map_frame_t::show_hide_directory(const bool show) { directory_container.set_visible(show); b_show_directory.pressed = show; b_filter_factory_list.pressed = filter_factory_list; directory_visible = show; update_factory_legend(); reset_min_windowsize(); } bool map_frame_t::action_triggered( gui_action_creator_t *comp, value_t v ) { if( comp == &b_show_legend ) { show_hide_legend( !b_show_legend.pressed ); } else if(comp==&b_show_network_option) { show_hide_network_option( !b_show_network_option.pressed ); } else if( comp == &b_show_scale ) { show_hide_scale( !b_show_scale.pressed ); } else if( comp == &b_show_directory ) { show_hide_directory( !b_show_directory.pressed ); } else if( comp == &c_show_outlines ) { env_t::default_mapmode &= ~(minimap_t::MAP_CLIMATES | minimap_t::MAP_HIDE_CONTOUR); if( v.i == 2 ) { env_t::default_mapmode |= minimap_t::MAP_HIDE_CONTOUR; } else if( v.i == 1 ) { env_t::default_mapmode |= minimap_t::MAP_CLIMATES; } minimap_t::get_instance()->set_display_mode( (minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode ); } else if ( comp == &b_filter_factory_list ) { filter_factory_list = !filter_factory_list; show_hide_directory( b_show_directory.pressed ); } else if (comp == zoom_buttons+0 || comp == zoom_buttons+1) { // zoom in/out zoomed |= zoom(comp != zoom_buttons); } else if( comp == &b_rotate45 ) { // rotated/straight map minimap_t::get_instance()->toggle_isometric(); minimap_t::get_instance()->calc_map_size(); b_rotate45.pressed = minimap_t::get_instance()->is_isometric(); scrolly.set_size( scrolly.get_size() ); zoomed = true; old_ij = koord::invalid; } else if( comp == &b_overlay_networks ) { b_overlay_networks.pressed ^= 1; if( b_overlay_networks.pressed ) { env_t::default_mapmode |= minimap_t::MAP_LINES; } else { env_t::default_mapmode &= ~minimap_t::MAP_LINES; } minimap_t::get_instance()->set_display_mode( ( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode ); minimap_t::get_instance()->invalidate_map_lines_cache(); } else if ( comp == &viewed_player_c ) { minimap_t::get_instance()->player_showed_on_map = viewable_players[viewed_player_c.get_selection()]; minimap_t::get_instance()->invalidate_map_lines_cache(); } else if ( comp == &transport_type_c ) { minimap_t::get_instance()->transport_type_showed_on_map = transport_type_c.get_selection(); minimap_t::get_instance()->invalidate_map_lines_cache(); } else if ( comp == &freight_type_c ) { minimap_t::get_instance()->freight_type_group_index_showed_on_map = viewable_freight_types[freight_type_c.get_selection()]; minimap_t::get_instance()->invalidate_map_lines_cache(); } else if ( comp == &b_overlay_networks_load_factor ) { minimap_t::get_instance()->show_network_load_factor = !minimap_t::get_instance()->show_network_load_factor; b_overlay_networks_load_factor.pressed = !b_overlay_networks_load_factor.pressed; minimap_t::get_instance()->invalidate_map_lines_cache(); } else { for( int i=0; iset_display_mode( (minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode ); update_buttons(); } return true; } /** * Report events to the GUI-components */ bool map_frame_t::infowin_event(const event_t *ev) { event_t ev2 = *ev; ev2.move_origin(scrolly.get_pos() + scr_coord(0, D_TITLEBAR_HEIGHT)); if(ev->ev_class == INFOWIN) { if(ev->ev_code == WIN_OPEN) { minimap_t::get_instance()->set_xy_offset_size( scr_coord(0,0), scr_size(0,0) ); } else if(ev->ev_code == WIN_CLOSE) { minimap_t::get_instance()->is_visible = false; } } // center map with rightdobuleclick if (IS_RIGHTDBLCLK(ev)) { // zoom minimap to fit window while (karte->change_zoom_factor(true)) {} if (scrolly.get_client().w < karte->get_size().w || scrolly.get_client().h < karte->get_size().h) { // zoom out until no longer fits while (karte->change_zoom_factor(false) && (scrolly.get_client().w < karte->get_size().w || scrolly.get_client().h < karte->get_size().h)) {} } map_frame_t::zoomed = true; scrolly.set_size(scrolly.get_size()); // invalidate old offsets old_ij = koord::invalid; return true; } scr_size karte_sz = karte->get_size(); bool swallowed = gui_frame_t::infowin_event(ev); if (karte_sz != karte->get_size()) { // minimap was zoomed map_frame_t::zoomed = true; scrolly.set_size(scrolly.get_size()); old_ij = koord::invalid; } return swallowed; } /** * size window in response and save it in static size */ void map_frame_t::set_windowsize(scr_size size) { gui_frame_t::set_windowsize( size ); window_size = get_windowsize(); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void map_frame_t::draw(scr_coord pos, scr_size size) { // update our stored screen position screenpos = pos; minimap_t::get_instance()->set_xy_offset_size( scr_coord(scrolly.get_scroll_x(), scrolly.get_scroll_y()), scrolly.get_client().get_size() ); // first: check if cursor within map screen size koord ij = welt->get_viewport()->get_world_position(); if(welt->is_within_limits(ij)) { scr_coord center = minimap_t::get_instance()->map_to_screen_coord(ij); // only re-center if zoomed or world position has changed and its outside visible area const scr_size size = scrolly.get_size(); if(zoomed || ( old_ij != ij && ( scrolly.get_scroll_x()>center.x || scrolly.get_scroll_x()+size.w<=center.x || scrolly.get_scroll_y()>center.y || scrolly.get_scroll_y()+size.h<=center.y ) ) ) { // re-center cursor by scrolling scrolly.set_scroll_position( max(0,center.x-(size.w/2)), max(0,center.y-(size.h/2)) ); zoomed = false; // update zoom factors and zoom label sint16 zoom_in, zoom_out; minimap_t::get_instance()->get_zoom_factors(zoom_out, zoom_in); zoom_value_label.buf().printf("%i:%i", zoom_in, zoom_out); zoom_value_label.update(); zoom_row->set_size(zoom_row->get_size()); } // remember world position, we do not want to have surprises when scrolling later on old_ij = ij; } // draw all child controls gui_frame_t::draw(pos, size); // may add compass if( skinverwaltung_t::compass_map && env_t::compass_map_position!=0 ) { const uint16 isometric_img_offset = minimap_t::get_instance()->is_isometric() ? 4 : 0; display_img_aligned( skinverwaltung_t::compass_map->get_image_id( isometric_img_offset+welt->get_settings().get_rotation() ), scrolly.get_client()+pos+scr_coord(4,4+D_TITLEBAR_HEIGHT)-scr_size(8,8), env_t::compass_map_position, false ); } } void map_frame_t::rdwr( loadsave_t *file ) { file->rdwr_bool( legend_visible ); file->rdwr_bool( scale_visible ); file->rdwr_bool( directory_visible ); file->rdwr_long( env_t::default_mapmode ); file->rdwr_bool( b_overlay_networks_load_factor.pressed ); minimap_t::get_instance()->rdwr(file); window_size.rdwr(file); scrolly.rdwr(file); viewed_player_c.rdwr(file); transport_type_c.rdwr(file); freight_type_c.rdwr(file); if( file->is_version_atleast(123, 2) ) { file->rdwr_bool( network_option_visible ); } if( file->is_loading() ) { set_windowsize( window_size ); // notify minimap of new settings minimap_t::get_instance()->calc_map_size(); scrolly.set_size( scrolly.get_size() ); minimap_t::get_instance()->set_display_mode(( minimap_t::MAP_DISPLAY_MODE)env_t::default_mapmode); update_buttons(); show_hide_directory(directory_visible); show_hide_legend(legend_visible); show_hide_network_option(network_option_visible); show_hide_scale(scale_visible); b_overlay_networks.pressed = (env_t::default_mapmode & minimap_t::MAP_LINES)!=0; minimap_t::get_instance()->player_showed_on_map = viewable_players[viewed_player_c.get_selection()]; minimap_t::get_instance()->transport_type_showed_on_map = transport_type_c.get_selection(); minimap_t::get_instance()->freight_type_group_index_showed_on_map = viewable_freight_types[freight_type_c.get_selection()]; minimap_t::get_instance()->show_network_load_factor = b_overlay_networks_load_factor.pressed; minimap_t::get_instance()->invalidate_map_lines_cache(); } } simutrans-124.3/src/simutrans/gui/map_frame.h000066400000000000000000000056521474050137200212630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MAP_FRAME_H #define GUI_MAP_FRAME_H #include "gui_frame.h" #include "simwin.h" #include "components/gui_scrollpane.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_label.h" #include "../descriptor/factory_desc.h" #include "../tpl/stringhashtable_tpl.h" #include "../player/simplay.h" #include "../simline.h" class karte_ptr_t; class minimap_t; #define MAP_MAX_BUTTONS (22) /** * Minimap window */ class map_frame_t : public gui_frame_t, public action_listener_t { private: static karte_ptr_t welt; minimap_t* karte; /** * This is kind of hack: we know there can only be one map frame * at a time, and we want to save the current size for the next object * so we use a static variable here. */ static scr_size window_size; static bool legend_visible; static bool network_option_visible; static bool scale_visible; static bool directory_visible; static bool filter_factory_list; int viewable_players[MAX_PLAYER_COUNT+1]; vector_tpl viewable_freight_types; gui_aligned_container_t filter_container, network_filter_container, scale_container, directory_container, *zoom_row; gui_scrollpane_t scrolly; button_t filter_buttons[MAP_MAX_BUTTONS]; button_t zoom_buttons[2]; button_t b_rotate45; button_t b_show_legend; button_t b_show_network_option; button_t b_show_scale; gui_combobox_t c_show_outlines; button_t b_show_directory; button_t b_overlay_networks; button_t b_overlay_networks_load_factor; button_t b_filter_factory_list; gui_label_buf_t zoom_value_label; gui_combobox_t viewed_player_c; gui_combobox_t transport_type_c; gui_combobox_t freight_type_c; void update_buttons(); void update_factory_legend(); void show_hide_legend(const bool show); void show_hide_network_option(const bool show); void show_hide_scale(const bool show); void show_hide_directory(const bool show); static bool zoomed; // if true, zoom label will be updated on next redraw bool zoom(bool magnify); public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "map.txt";} static scr_coord screenpos; /** * Constructor. Adds all necessary Subcomponents. */ map_frame_t(); void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_reliefmap; } bool infowin_event(event_t const*) OVERRIDE; /** * Sets the window sizes */ void set_windowsize(scr_size size) OVERRIDE; /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/message_frame.cc000066400000000000000000000120741474050137200222640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simwin.h" #include "message_frame.h" #include "message_option.h" #include "message_stats.h" #include "chat_frame.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "../simmesg.h" #include "../sys/simsys.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../network/network_cmd_ingame.h" #include "../player/simplay.h" #define MAX_MESG_TABS (8) static sint32 categories[MAX_MESG_TABS] = { (1 << message_t::chat), // obsolete!! (1 << message_t::scenario), (1 << message_t::problems), (1 << message_t::traffic_jams) | (1 << message_t::warnings), (1 << message_t::full), (1 << message_t::city) | (1 << message_t::industry), (1 << message_t::ai), (1 << message_t::general) | (1 << message_t::new_vehicle) }; static char const* const tab_strings[]= { "Chat_msg", // obsolete!! "Scenario_msg", "Problems_msg", "Warnings_msg", "Station_msg", "Town_msg", "Company_msg", "Game_msg" }; message_frame_t::message_frame_t() : gui_frame_t( translator::translate("Mailbox") ), scrolly(gui_scrolled_list_t::windowskin, message_stats_t::compare) { last_count = 0; message_type = -1; set_table_layout(1,0); add_table(0,1); { option_bt.init(button_t::roundbox, translator::translate("Optionen")); option_bt.add_listener(this); add_component(&option_bt); copy_bt.init(button_t::roundbox, translator::translate("Copy to clipboard")); copy_bt.add_listener(this); add_component(©_bt); if (env_t::networkmode || !welt->get_chat_message()->get_list().empty()) { open_chat_bt.init(button_t::roundbox, translator::translate("Chat")); open_chat_bt.set_size(D_BUTTON_SIZE); open_chat_bt.add_listener(this); add_component(&open_chat_bt); } new_component(); } end_table(); // add tabs for classifying messages tabs.add_tab( &scrolly, translator::translate("All") ); tab_categories.append( -1 ); if (welt->get_scenario()->is_scripted()) { tabs.add_tab( &scrolly, translator::translate(tab_strings[1]) ); tab_categories.append( categories[1] ); } for( int i=2; iget_message()->get_list() ) { scrolly.new_component(i, id++); } last_count = welt->get_message()->get_list().get_count(); // trigger filtering sint32 t = message_type; message_type = -1; // filter & sort filter_list(t); scrolly.set_size( scrolly.get_size()); } void message_frame_t::filter_list(sint32 type) { if (type != message_type) { for(int i=0, end=scrolly.get_count(); i(scrolly.get_element(i)); // message type filtering controls visibility if (a) { a->set_visible(type == -1 || a->get_msg()->get_type_shifted() & type); } } message_type = type; } scrolly.sort(0); scrolly.set_size( scrolly.get_size()); } bool message_frame_t::action_triggered( gui_action_creator_t *comp, value_t v ) { if( comp==&option_bt ) { create_win({ 320, 200 }, new message_option_t(), w_info, magic_message_options ); } if( comp==&open_chat_bt ) { create_win({ 0, 200 }, new chat_frame_t(), w_info, magic_chatframe); } else if( comp==©_bt ) { cbuffer_t clipboard; const sint32 message_type = tab_categories[ tabs.get_active_tab_index() ]; int count = 20; // just copy the last 20 for(message_node_t* const i : welt->get_message()->get_list() ) { if( i->get_type_shifted() & message_type ) { // add them to clipboard char msg_no_break[ 258 ]; for( int j = 0; j < 256; j++ ) { msg_no_break[ j ] = i->msg[ j ] == '\n' ? ' ' : i->msg[ j ]; if( msg_no_break[ j ] == 0 ) { msg_no_break[ j++ ] = '\n'; msg_no_break[ j ] = 0; break; } } clipboard.append( msg_no_break ); if( count-- < 0 ) { break; } } } // copy, if there was anything ... if( clipboard.len() > 0 ) { dr_copy( clipboard, clipboard.len() ); } } else if( comp==&tabs ) { // filter messages by type where necessary filter_list(tab_categories[v.i]); } return true; } void message_frame_t::draw(scr_coord pos, scr_size size) { if( welt->get_message()->get_list().get_count() != last_count ) { fill_list(); } gui_frame_t::draw(pos, size); } void message_frame_t::rdwr(loadsave_t *file) { // window size scr_size size = get_windowsize(); size.rdwr( file ); scrolly.rdwr(file); tabs.rdwr(file); if (file->is_version_less(124, 1)) { char dummy[256] = { 0 }; file->rdwr_str(dummy, lengthof(dummy)); } if( file->is_loading() ) { fill_list(); reset_min_windowsize(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/message_frame.h000066400000000000000000000025041474050137200221230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MESSAGE_FRAME_H #define GUI_MESSAGE_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_scrolled_list.h" #include "components/gui_tab_panel.h" #include "components/action_listener.h" /** * All messages since the start of the program */ class message_frame_t : public gui_frame_t, private action_listener_t { private: gui_scrolled_list_t scrolly; gui_tab_panel_t tabs; // tab panel for filtering messages button_t option_bt, copy_bt, open_chat_bt; vector_tpl tab_categories; uint32 last_count; // of messages in list sint32 message_type; // message type for filtering; -1 indicates no filtering void fill_list(); void filter_list(sint32 type); public: message_frame_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "mailbox.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr(loadsave_t *) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_messageframe; } void draw(scr_coord pos, scr_size size) OVERRIDE; void map_rotate90(sint16 /*new_ysize*/) OVERRIDE { fill_list(); } }; #endif simutrans-124.3/src/simutrans/gui/message_option.cc000066400000000000000000000054251474050137200225040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simmesg.h" #include "../simskin.h" #include "../world/simworld.h" #include "../descriptor/skin_desc.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "message_option.h" #include "components/gui_image.h" message_option_t::message_option_t() : gui_frame_t( translator::translate("Mailbox Options") ) { set_table_layout(5,0); // first row images new_component_span(2); if (skinverwaltung_t::message_options->get_count() >=3 ) { // three single images for(int i=0; i<3; i++) { new_component(skinverwaltung_t::message_options->get_image_id(i), 0, 0, true); } } else { // one monolithic image new_component_span(skinverwaltung_t::message_options->get_image_id(0), 0, 0, true, 3); } // The text is unfortunately a single text, which we have to chop into pieces. const unsigned char *p = (const unsigned char *)translator::translate( "MessageOptionsText" ); welt->get_message()->get_message_flags( &ticker_msg, &window_msg, &auto_msg, &ignore_msg ); for( int i = 0; i < message_t::MAX_MESSAGE_TYPE; i++ ) { option_texts[i][0] = 0; } for( int i=0; i>i)&1)==0; buttons[i*4].add_listener(this); add_component( buttons+i*4 ); // copy the next line of the option text while( *p < ' ' && *p ) { p++; } for( int j=0; *p>=' '; p++ ) { if( j < MAX_MESSAGE_OPTION_TEXTLEN-1 ) { option_texts[i][j++] = *p; option_texts[i][j] = 0; } } text_lbl[i].set_text( option_texts[i] ); add_component( text_lbl+i ); buttons[i*4+1].set_typ(button_t::square_state); buttons[i*4+1].pressed = (ticker_msg>>i)&1; buttons[i*4+1].add_listener(this); add_component( buttons+i*4+1 ); buttons[i*4+2].set_typ(button_t::square_state); buttons[i*4+2].pressed = (auto_msg>>i)&1; buttons[i*4+2].add_listener(this); add_component( buttons+i*4+2 ); buttons[i*4+3].set_typ(button_t::square_state); buttons[i*4+3].pressed = (window_msg>>i)&1; buttons[i*4+3].add_listener(this); add_component( buttons+i*4+3 ); } reset_min_windowsize(); } bool message_option_t::action_triggered( gui_action_creator_t *comp, value_t ) { ((button_t*)comp)->pressed ^= 1; for( int i=0; iget_message()->set_message_flags( ticker_msg, window_msg, auto_msg, ignore_msg ); return true; } simutrans-124.3/src/simutrans/gui/message_option.h000066400000000000000000000017201474050137200223400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MESSAGE_OPTION_H #define GUI_MESSAGE_OPTION_H #include "../simmesg.h" #include "simwin.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_label.h" #include "../utils/cbuffer.h" #define MAX_MESSAGE_OPTION_TEXTLEN (64) class message_option_t : public gui_frame_t, private action_listener_t { private: button_t buttons[4*message_t::MAX_MESSAGE_TYPE]; gui_label_t text_lbl[message_t::MAX_MESSAGE_TYPE]; sint32 ticker_msg, window_msg, auto_msg, ignore_msg; char option_texts[message_t::MAX_MESSAGE_TYPE][MAX_MESSAGE_OPTION_TEXTLEN]; public: message_option_t(); const char * get_help_filename() const OVERRIDE {return "mailbox.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_message_options; } }; #endif simutrans-124.3/src/simutrans/gui/message_stats.cc000066400000000000000000000036571474050137200223370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "message_stats.h" #include "components/gui_button.h" #include "components/gui_label.h" #include "messagebox.h" #include "simwin.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" static karte_ptr_t welt; message_stats_t::message_stats_t(const message_node_t *m, uint32 sid) : msg(m), sortid(sid) { set_table_layout(2,1); // pos-button, visible or not button_t *b = new_component(); b->set_typ(button_t::posbutton_automatic); if (msg->pos!=koord3d::invalid) { b->set_targetpos3d(msg->pos); } else { b->set_visible(false); b->set_rigid(true); } // text buffer gui_label_buf_t *label = new_component(msg->get_player_color(welt)); // now fill buffer, first the date label->buf().printf( "(%s) ", translator::get_short_date( msg->time/12, msg->time%12 ) ); // then the text (without line break) for(int j=0; ; j++) { char c = msg->msg[j]; if (c==0) { break; } label->buf().printf("%c", c == '\n' ? ' ': c); } label->update(); } bool message_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb ) { const message_stats_t* a = dynamic_cast(aa); const message_stats_t* b = dynamic_cast(bb); assert(a && b); return a->sortid < b->sortid; } /** * Click on message => go to position */ bool message_stats_t::infowin_event(const event_t * ev) { bool swallowed = gui_aligned_container_t::infowin_event(ev); if( !swallowed && IS_LEFTRELEASE(ev) ) { msg->open_msg_window(false /* open as normal not autoclose */); swallowed = true; } else if( !swallowed && IS_RIGHTRELEASE(ev) && msg->pos!=koord3d::invalid ) { welt->get_viewport()->change_world_position( msg->pos ); swallowed = true; } return swallowed; } simutrans-124.3/src/simutrans/gui/message_stats.h000066400000000000000000000014571474050137200221750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MESSAGE_STATS_H #define GUI_MESSAGE_STATS_H #include "components/gui_aligned_container.h" #include "components/gui_scrolled_list.h" #include "../simmesg.h" /** * Message display */ class message_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t { private: const message_node_t *msg; uint32 sortid; // sortid reflects the order in message_t public: message_stats_t(const message_node_t *m, uint32 sid); const message_node_t* get_msg() const { return msg; } char const* get_text() const OVERRIDE { return msg->msg; } bool infowin_event(const event_t * ev) OVERRIDE; static bool compare(const gui_component_t *a, const gui_component_t *b ); }; #endif simutrans-124.3/src/simutrans/gui/messagebox.cc000066400000000000000000000044641474050137200216270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../world/simworld.h" #include "../display/simgraph.h" #include "../simskin.h" #include "../descriptor/skin_desc.h" #include "../dataobj/translator.h" #include "messagebox.h" #include "../sys/simsys.h" news_window::news_window(const char* text, FLAGGED_PIXVAL title_color) : base_infowin_t( translator::translate("Meldung" ) ), color(title_color) { buf.clear(); buf.append(translator::translate(text)); textarea.set_size(scr_size(textarea.get_size().w + 1, 0)); recalc_size(); } fatal_news::fatal_news(const char* text) : news_window(text, env_t::default_window_title_color) { copy_to_clipboard.init(button_t::roundbox, "Copy to clipboard"); copy_to_clipboard.add_listener( this ); copy_to_clipboard.set_focusable(false); add_component(©_to_clipboard); textarea.set_width(display_get_width()/2); recalc_size(); } bool fatal_news::action_triggered(gui_action_creator_t *comp, value_t) { if (comp == ©_to_clipboard) { dr_copy(buf, buf.len()); return false; } return true; } news_img::news_img(const char* text) : news_window(text, env_t::default_window_title_color), image() { init(skinverwaltung_t::meldungsymbol->get_image_id(0)); } news_img::news_img(const char* text, image_id id, FLAGGED_PIXVAL color) : news_window(text, color), image() { init(id); } /** * just puts the image in top-right corner * only cembedded.d from constructor * @param id id of image */ void news_img::init(image_id id) { if( id!=IMG_EMPTY ) { image.set_image(id, true); image.enable_offset_removal(true); image.set_size(image.get_min_size()); textarea.set_size(scr_size(textarea.get_size().w + image.get_size().w + D_H_SPACE + 1,0)); set_embedded(&image); } } news_loc::news_loc(const char* text, koord3d k, FLAGGED_PIXVAL color) : news_window(text, color), view(k, scr_size( max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width()*7)/8) )) { textarea.set_size(scr_size(textarea.get_size().w + view.get_size().w + D_H_SPACE + 1, 0)); set_embedded(&view); } // returns position of the location shown in the subwindow koord3d news_loc::get_weltpos(bool) { return view.get_location(); } void news_loc::map_rotate90( sint16 new_ysize ) { view.map_rotate90(new_ysize); } simutrans-124.3/src/simutrans/gui/messagebox.h000066400000000000000000000026771474050137200214750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MESSAGEBOX_H #define GUI_MESSAGEBOX_H #include "base_info.h" #include "components/gui_location_view.h" #include "components/gui_image.h" #include "../simcolor.h" #include "../dataobj/environment.h" /** * A class for Message/news window. */ class news_window : public base_infowin_t { public: FLAGGED_PIXVAL get_titlecolor() const OVERRIDE { return color; } protected: news_window(const char* text, FLAGGED_PIXVAL color); private: FLAGGED_PIXVAL color; }; /** * Displays fatal error message. */ class fatal_news : public news_window, private action_listener_t { button_t copy_to_clipboard; public: fatal_news(const char* text); private: bool action_triggered(gui_action_creator_t *comp, value_t extra) OVERRIDE; }; /** * Shows a news window with an image */ class news_img : public news_window { public: news_img(const char* text); news_img(const char* text, image_id image, FLAGGED_PIXVAL color = env_t::default_window_title_color); private: void init(image_id image); gui_image_t image; }; /** * Shows a news window with a view on some location */ class news_loc : public news_window { public: news_loc(const char* text, koord3d k, FLAGGED_PIXVAL color = env_t::default_window_title_color); void map_rotate90( sint16 new_ysize ) OVERRIDE; koord3d get_weltpos(bool) OVERRIDE; private: location_view_t view; }; #endif simutrans-124.3/src/simutrans/gui/minimap.cc000066400000000000000000001612051474050137200211210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simevent.h" #include "../simcolor.h" #include "../simconvoi.h" #include "../vehicle/vehicle.h" #include "../world/simworld.h" #include "../obj/depot.h" #include "../simhalt.h" #include "../simskin.h" #include "../ground/grund.h" #include "../tool/simtool.h" #include "../simfab.h" #include "../world/simcity.h" #include "fabrik_info.h" #include "simwin.h" #include "minimap.h" #include "../dataobj/translator.h" #include "../dataobj/settings.h" #include "../dataobj/schedule.h" #include "../dataobj/powernet.h" #include "../dataobj/ribi.h" #include "../dataobj/loadsave.h" #include "../obj/way/schiene.h" #include "../obj/leitung2.h" #include "../utils/cbuffer.h" #include "../display/scr_coord.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../utils/simrandom.h" #include "../player/simplay.h" #include "../tpl/inthashtable_tpl.h" #include "../tpl/slist_tpl.h" #include sint32 minimap_t::max_cargo=0; sint32 minimap_t::max_passed=0; static sint32 max_waiting_change = 1; static sint32 max_tourist_ziele = 1; static sint32 max_waiting = 1; static sint32 max_origin = 1; static sint32 max_transfer = 1; static sint32 max_service = 1; static sint32 max_building_level = 0; minimap_t * minimap_t::single_instance = NULL; karte_ptr_t minimap_t::world; minimap_t::MAP_DISPLAY_MODE minimap_t::mode = MAP_TOWN; minimap_t::MAP_DISPLAY_MODE minimap_t::last_mode = MAP_TOWN; bool minimap_t::is_visible = false; #define MAX_MAP_TYPE_LAND 31 #define MAX_MAP_TYPE_WATER 5 // color for the land static const uint8 map_type_color[MAX_MAP_TYPE_WATER+MAX_MAP_TYPE_LAND] = { // water level 97, 99, 19, 21, 23, // terrain level 160, 161, 162, 163, 164, 165, 166, 167, 205, 206, 207, 172, 174, 159, COL_LIGHT_ORANGE, COL_TOLL, 156, 154, 115, 114, 113, 112, 216, 217, 218, 219, 220, COL_LILAC, 222, 223, 224 }; const uint8 minimap_t::severity_color[MAX_SEVERITY_COLORS] = { 106, 2, 85, 86, 29, 30, COL_YELLOW, 71, 39, COL_OPERATION }; minimap_t::line_segment_t::line_segment_t(koord s, uint8 so, koord e, uint8 eo, schedule_t* sched, player_t* p, uint8 cc, bool diagonal) { schedule = sched; waytype = sched->get_waytype(); player = p; colorcount = cc; start_diagonal = diagonal; if( s.xsimilar( other.schedule, player ); } // Ordering based on first start then end coordinate bool minimap_t::LineSegmentOrdering::operator()(const minimap_t::line_segment_t& a, const minimap_t::line_segment_t& b) const { if( a.start.x == b.start.x ) { // same start ... return a.end.x < b.end.x; } return a.start.x < b.start.x; } static uint8 colore_idx = 0; static inthashtable_tpl< int, slist_tpl > waypoint_hash; // add the schedule to the map (if there is a valid one) void minimap_t::add_to_schedule_cache( convoihandle_t cnv, bool with_waypoints ) { // make sure this is valid! if( !cnv.is_bound() ) { return; } schedule_t *schedule = cnv->get_schedule(); if( !show_network_load_factor ) { colore_idx += 8; if( colore_idx >= 208 ) { colore_idx = (colore_idx % 8) + 1; if( colore_idx == 7 ) { colore_idx = 0; } } } else { //TODO: extract common part from with schedule_list_gui_t::display() int capacity = 0, load = 0; // total capacity and load of line (=sum of all conv's cap/load) if(cnv->get_line().is_bound()) { for( uint i = 0; i < cnv->get_line()->count_convoys(); i++ ) { convoihandle_t const cnv_in_line = cnv->get_line()->get_convoy(i); // we do not want to count the capacity of depot convois if( !cnv_in_line->in_depot() ) { for( unsigned j = 0; j < cnv_in_line->get_vehicle_count(); j++ ) { capacity += cnv_in_line->get_vehicle(j)->get_cargo_max(); load += cnv_in_line->get_vehicle(j)->get_total_cargo(); } } } } else { // we do not want to count the capacity of depot convois if(!cnv->in_depot()) { for(unsigned j = 0; j < cnv->get_vehicle_count(); j++) { capacity += cnv->get_vehicle(j)->get_cargo_max(); load += cnv->get_vehicle(j)->get_total_cargo(); } } } // we check if cap is zero, since theoretically a // conv can consist of only 1 vehicle, which has no cap (eg. locomotive) // and we do not like to divide by zero, do we? if(capacity > 0) { const uint32 load_idx = clamp(load * MAX_SEVERITY_COLORS / capacity, 0, MAX_SEVERITY_COLORS-1); colore_idx = severity_color[MAX_SEVERITY_COLORS-1 - load_idx]; } else { colore_idx = severity_color[MAX_SEVERITY_COLORS-1]; } } // ok, add this schedule to map // from here on we have a valid convoi int stops = 0; uint8 old_offset = 0, first_offset = 0, temp_offset = 0; koord old_stop, first_stop, temp_stop; bool last_diagonal = false; const bool add_schedule = schedule->get_waytype() != air_wt; for(schedule_entry_t cur : schedule->entries ) { //cycle on stops //try to read station's coordinates if there's a station at this schedule stop halthandle_t station = haltestelle_t::get_halt( cur.pos, cnv->get_owner() ); if( station.is_bound() ) { stop_cache.append_unique( station ); temp_stop = station->get_basis_pos(); stops ++; } else if( with_waypoints ) { temp_stop = cur.pos.get_2d(); stops ++; } else { continue; } const int key = temp_stop.x + temp_stop.y*world->get_size().x; waypoint_hash.put( key ); // now get the offset slist_tpl*pt_list = waypoint_hash.access(key); if( add_schedule ) { // init key if( !pt_list->is_contained( schedule ) ) { // not known => append temp_offset = pt_list->get_count(); } else { // how many times we reached here? temp_offset = pt_list->index_of( schedule ); } } else { temp_offset = 0; } if( stops>1 ) { last_diagonal ^= true; if( (temp_stop.x-old_stop.x)*(temp_stop.y-old_stop.y) == 0 ) { last_diagonal = false; } if( !schedule_cache.insert_unique_ordered( line_segment_t( temp_stop, temp_offset, old_stop, old_offset, schedule, cnv->get_owner(), colore_idx, last_diagonal ), LineSegmentOrdering() ) && add_schedule ) { // append if added and not yet there if( !pt_list->is_contained( schedule ) ) { pt_list->append( schedule ); } if( stops == 2 ) { // append first stop too, when this is called for the first time const int key = first_stop.x + first_stop.y*world->get_size().x; waypoint_hash.put( key ); slist_tpl*pt_list = waypoint_hash.access(key); if( !pt_list->is_contained( schedule ) ) { pt_list->append( schedule ); } } } old_stop = temp_stop; old_offset = temp_offset; } else { first_stop = temp_stop; first_offset = temp_offset; old_stop = temp_stop; old_offset = temp_offset; } } if( stops > 2 ) { // connect to start last_diagonal ^= true; schedule_cache.insert_unique_ordered( line_segment_t( first_stop, first_offset, old_stop, old_offset, schedule, cnv->get_owner(), colore_idx, last_diagonal ), LineSegmentOrdering() ); } } // some routines for the minimap with schedules static uint32 number_to_radius( uint32 n ) { return log2( n>>5 ); } static void display_airport( const scr_coord_val xx, const scr_coord_val yy, const FLAGGED_PIXVAL color ) { int x = xx + 5; int y = yy - 11; if ( y < 0 ) { y = 0; } const char symbol[] = { 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', '.', '.', '.', 'X', 'X', 'X', '.', '.', '.', 'X', 'X', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', '.', '.', 'X', '.', '.', '.', 'X', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', '.', '.', '.', 'X', 'X', 'X', '.', '.', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' }; for ( int i = 0; i < 11; i++ ) { for ( int j = 0; j < 11; j++ ) { if ( symbol[i + j * 11] == 'X' ) { display_vline_wh_clip_rgb( x + i, y + j, 1, color, true ); } } } } static void display_harbor( const scr_coord_val xx, const scr_coord_val yy, const FLAGGED_PIXVAL color ) { int x = xx + 5; int y = yy - 11 + 13; //to not overwrite airline symbol if ( y < 0 ) { y = 0; } const char symbol[] = { 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', '.', '.', 'X', 'X', 'X', '.', '.', '.', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', 'X', 'X', '.', '.', '.', 'X', 'X', 'X', '.', '.', '.', 'X', 'X', '.', '.', '.', '.', 'X', '.', '.', '.', '.', 'X', 'X', 'X', 'X', '.', '.', 'X', '.', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', 'X', '.', 'X', 'X', 'X', 'X', 'X', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', '.', 'X', 'X', '.', '.', 'X', 'X', 'X', 'X', 'X', '.', '.', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' }; for ( int i = 0; i < 11; i++ ) { for ( int j = 0; j < 11; j++ ) { if ( symbol[i + j * 11] == 'X' ) { display_vline_wh_clip_rgb( x + i, y + j, 1, color, true ); } } } } // those will be replaced by pak images later ...! static void display_thick_line( scr_coord_val x1, scr_coord_val y1, scr_coord_val x2, scr_coord_val y2, PIXVAL col, bool dotting, short dot_full, short dot_empty, short thickness ) { double delta_x = abs( x1 - x2 ); double delta_y = abs( y1 - y2 ); if( delta_x == 0.0 || delta_y/delta_x > 2.0 ) { // mostly vertical x1 -= thickness/2; x2 -= thickness/2; for( int i = 0; i < thickness; i++ ) { if ( !dotting ) { display_direct_line_rgb( x1 + i, y1, x2 + i, y2, col ); } else { display_direct_line_dotted_rgb( x1 + i, y1, x2 + i, y2, dot_full, dot_empty, col ); } } } else if( delta_y == 0.0 || delta_x/delta_y > 2.0 ) { // mostly horizontal y1 -= thickness/2; y2 -= thickness/2; for( int i = 0; i < thickness; i++ ) { if ( !dotting ) { display_direct_line_rgb( x1, y1 + i, x2, y2 + i, col ); } else { display_direct_line_dotted_rgb( x1, y1 + i, x2, y2 + i, dot_full, dot_empty, col ); } } } else { // diagonal int y_multiplier = (x1-x2)/(y1-y2) < 0 ? +1 : -1; thickness = (thickness*7)/8; x1 -= thickness/2; x2 -= thickness/2; y1 -= thickness*y_multiplier/2; y2 -= thickness*y_multiplier/2; for( int i = 0; i < thickness; i++ ) { if ( !dotting ) { display_direct_line_rgb( x1+i, y1+i*y_multiplier, x2+i, y2+i*y_multiplier, col ); display_direct_line_rgb( x1+i+1, y1+i*y_multiplier, x2+i+1, y2+i*y_multiplier, col ); } else { display_direct_line_dotted_rgb( x1 + i, y1 + i*y_multiplier, x2 + i, y2 + i*y_multiplier, dot_full, dot_empty, col ); display_direct_line_dotted_rgb( x1 + i + 1, y1 + i*y_multiplier, x2 + i + 1, y2 + i*y_multiplier, dot_full, dot_empty, col ); } } } } static void line_segment_draw( waytype_t type, scr_coord start, const uint8 start_offset, scr_coord end, const uint8 end_offset, bool start_diagonal, const PIXVAL colore ) { // airplanes are different, so we must check for them first if( type == air_wt ) { // ignore offset for airplanes draw_bezier_rgb( start.x, start.y, end.x, end.y, 50, 50, 50, 50, colore, 5, 5 ); draw_bezier_rgb( start.x + 1, start.y + 1, end.x + 1, end.y + 1, 50, 50, 50, 50, colore, 5, 5 ); } else { // determine line style uint8 thickness = 3; bool dotted = false; switch( type ) { case monorail_wt: case maglev_wt: thickness = 5; break; case track_wt: thickness = 4; break; case road_wt: thickness = 2; break; case tram_wt: case narrowgauge_wt: thickness = 3; break; default: thickness = 3; dotted = true; } // move to the correct locations start.x += 3*start_offset; start.y += 3*start_offset; end.x += 3*end_offset; end.y += 3*end_offset; scr_coord delta = end-start; // Reduce diagonal line overlap: Genereally respect the requested start_diagonal. // In case of NW to SE lines, ignore the requested diagonal, if either start or end of the line has index 0 if(sgn(delta.x) * sgn(delta.y) == 1){ if(end_offset){ start_diagonal = true; } if(start_offset){ start_diagonal = false; } } // We always start straight, then diagonal. If the other way round is desired, simply swap start and end. if(start_diagonal ){ delta = delta*-1; const scr_coord tmp = start; start=end; end=tmp; } const int d = min(abs(delta.x),abs(delta.y));//pick absolute of smallest component const scr_coord diag = scr_coord(d*sgn(delta.x),d*sgn(delta.y)); const scr_coord mid=end-diag; if(start!=mid) { display_thick_line(start.x, start.y, mid.x, mid.y, colore, dotted, 5, 3, thickness); } if(mid!=end) { display_thick_line(mid.x, mid.y, end.x, end.y, colore, dotted, 5, 3, thickness); } } } // converts map (karte) koordinates to screen koordinates scr_coord minimap_t::map_to_screen_coord(const koord &k) const { assert(zoom_in ==1 || zoom_out ==1 ); scr_coord_val x = (scr_coord_val)k.x * zoom_in; scr_coord_val y = (scr_coord_val)k.y * zoom_in; if(isometric) { // 45 rotate view scr_coord_val xrot = (scr_coord_val)world->get_size().y * zoom_in + x - y - 1; y = ( x + y )/2; x = xrot; } return scr_coord(x/zoom_out, y/zoom_out); } // and re-transform koord minimap_t::screen_to_map_coord(const scr_coord &c) const { sint32 x = ((sint32)c.x*zoom_out)/zoom_in; sint32 y = ((sint32)c.y*zoom_out)/zoom_in; if(isometric) { y *= 2; x = (x + y - world->get_size().y)/2; y = y - x; } return koord(x,y); } bool minimap_t::change_zoom_factor(bool magnify) { bool zoomed = false; if( magnify ) { // zoom in if( zoom_out > 1 ) { zoom_out--; zoomed = true; } else { // check here for maximum zoom-out, otherwise there will be integer overflows // with large maps as we calculate with sint16 coordinates ... const int max_zoom_in = min( INT_MAX / (2*world->get_size_max()), 16); if( zoom_in < max_zoom_in ) { zoom_in++; zoomed = true; } } } else { // zoom out if( zoom_in > 1 ) { zoom_in--; zoomed = true; } else if( zoom_out < 16 ) { zoom_out++; zoomed = true; } } if( zoomed ){ // recalc map size calc_map_size(); } return zoomed; } PIXVAL minimap_t::calc_severity_color(sint32 amount, sint32 max_value) { if(max_value!=0) { // color array goes from light blue to red const sint32 severity = ((sint64)amount * MAX_SEVERITY_COLORS) / ((sint64)max_value + 1); return color_idx_to_rgb( minimap_t::severity_color[ clamp( severity, 0, MAX_SEVERITY_COLORS-1 ) ]); } return color_idx_to_rgb( minimap_t::severity_color[0]); } PIXVAL minimap_t::calc_severity_color_log(sint32 amount, sint32 max_value) { if( max_value>1 ) { sint32 severity; if( amount <= 0x003FFFFF ) { severity = log2( (uint32)( (amount << MAX_SEVERITY_COLORS) / (max_value+1) ) ); } else { severity = (uint32)( log( (double)amount*(double)(1<get_width() && 0<=y && (uint16)y < map_data->get_height() ) { map_data->at( x, y ) = color; } } void minimap_t::set_map_color(koord k_, const PIXVAL color) { // if map is in normal mode, set new color for map // otherwise do nothing // result: convois will not "paint over" special maps if ( map_data==NULL || !world->is_within_limits(k_)) { return; } scr_coord c = map_to_screen_coord(k_); c -= cur_off; if( isometric ) { // since isometric is distorted const sint32 xw = zoom_out>=2 ? 1 : 2*zoom_in; // increase size at zoom_in 2, 5, 9, 11 const scr_coord_val mid_y = ((xw+1) / 5) + (xw / 18); // center line for( int x=0; x 0 ) { scr_coord_val left = 2, right = xw-2 + ((xw>>1)&1); for( scr_coord_val y_offset = 1; y_offset <= mid_y; y_offset++ ) { for( int x=left; xget_width(); x++ ) { for( sint32 y = max(0,c.y); y < zoom_in+c.y && (uint32)y < map_data->get_height(); y++ ) { map_data->at(x, y) = color; } } } } /** * calculates ground color for position relative to water height * @param hoehe height of the tile * @param groundwater water height */ PIXVAL minimap_t::calc_height_color(const sint16 hoehe, const sint16 groundwater) { sint16 relative_index; if( hoehe>groundwater ) { // adjust index for world_maximum_height relative_index = (hoehe-groundwater)*MAX_MAP_TYPE_LAND/world->get_settings().get_maximumheight(); if( (hoehe-groundwater)*MAX_MAP_TYPE_LAND%world->get_settings().get_maximumheight()!=0 ) { // to avoid relative_index==0 relative_index += 1; } } else { relative_index = hoehe-groundwater; } return color_idx_to_rgb(map_type_color[clamp( relative_index+MAX_MAP_TYPE_WATER-1, 0, MAX_MAP_TYPE_WATER+MAX_MAP_TYPE_LAND-1 )]); } /** * Calculates the minimap color of a ground tile */ PIXVAL minimap_t::calc_ground_color(const grund_t *gr) { PIXVAL color = color_idx_to_rgb(COL_BLACK); #ifdef DEBUG_ROUTES /* for debug purposes only ...*/ if(gr->get_flag(grund_t::marked)) { color = color_idx_to_rgb(COL_PURPLE); } else #endif if(gr->get_halt().is_bound()) { color = COL_HALT; } else { switch(gr->get_typ()) { case grund_t::brueckenboden: color = color_idx_to_rgb(MN_GREY3); break; case grund_t::tunnelboden: color = color_idx_to_rgb(COL_BROWN); break; case grund_t::monorailboden: color = COL_MONORAIL; break; case grund_t::fundament: { // object at zero is either factory or house (or attraction ... ) gebaeude_t *gb = gr->find(); fabrik_t *fab = gb ? gb->get_fabrik() : NULL; if(fab==NULL) { color = color_idx_to_rgb(COL_GREY3); } else { color = fab->get_color(); } } break; case grund_t::wasser: { // object at zero is either factory or boat gebaeude_t *gb = gr->find(); fabrik_t *fab = gb ? gb->get_fabrik() : NULL; if(fab==NULL) { sint16 height = corner_sw(gr->get_grund_hang()); if( mode&MAP_HIDE_CONTOUR ) { color = color_idx_to_rgb(map_type_color[1]); // second deep water color } else { color = calc_height_color( world->lookup_hgt( gr->get_pos().get_2d() ) + height, world->get_water_hgt( gr->get_pos().get_2d() ) ); } //color = color_idx_to_rgb(COL_BLUE); // water with boat? } else { color = fab->get_color(); } } break; // normal ground ... default: if(gr->hat_wege()) { switch(gr->get_weg_nr(0)->get_waytype()) { case road_wt: color = COL_ROAD; break; case tram_wt: case track_wt: color = COL_RAIL; break; case water_wt: color = COL_CANAL; break; case air_wt: color = COL_RUNWAY; break; case monorail_wt: default: // all other ways light red ... color = color_idx_to_rgb(135); break; } } else { const leitung_t* lt = gr->find(); if(lt!=NULL) { color = COL_POWERLINE; } else { if( mode&MAP_HIDE_CONTOUR ) { color = color_idx_to_rgb(map_type_color[MAX_MAP_TYPE_WATER+2]); // lowest land color } else if( mode&MAP_CLIMATES ) { static uint8 climate_color[ 8 ] = { 0, COL_YELLOW, COL_LIGHT_GREEN, COL_GREEN, COL_DARK_GREEN, COL_DARK_YELLOW, COL_BROWN, COL_GREY4 }; color = color_idx_to_rgb( climate_color[ world->get_climate(gr->get_pos().get_2d()) ] ); } else { sint16 height = corner_sw(gr->get_grund_hang()); if( gr->get_hoehe() > world->get_groundwater() ) { color = calc_height_color( gr->get_hoehe() + height, world->get_groundwater() ); } else { color = calc_height_color( gr->get_hoehe() + height, gr->get_hoehe() + height - 1); } } } } break; } } return color; } bool minimap_t::calc_map_pixel(const grund_t *gr) { if (!gr) { return false; } const koord k = gr->get_pos().get_2d(); if(mode != MAP_PAX_DEST && gr->get_convoi_vehicle()) { set_map_color(k, COL_VEHICLE); return true; } switch (mode & ~MAP_MODE_FLAGS) { case MAP_PASSENGER: case MAP_MAIL: return false; // show usage case MAP_FREIGHT: // need to init the maximum? if (max_cargo == 0) { max_cargo = 1; calc_map(); return true; } else if (gr->hat_wege()) { // now calc again ... sint32 cargo = 0; // maximum two ways for one ground const weg_t* w = gr->get_weg_nr(0); if (w) { cargo = w->get_statistics(WAY_STAT_GOODS); const weg_t* w = gr->get_weg_nr(1); if (w) { cargo += w->get_statistics(WAY_STAT_GOODS); } if (cargo > max_cargo) { max_cargo = cargo; } set_map_color(k, calc_severity_color_log(cargo, max_cargo)); return true; } } break; // show traffic (=convois/month) case MAP_TRAFFIC: // need to init the maximum? if (max_passed == 0) { max_passed = 1; calc_map(); } else if (gr->hat_wege()) { // now calc again ... sint32 passed = 0; // maximum two ways for one ground const weg_t* w = gr->get_weg_nr(0); if (w) { passed = w->get_statistics(WAY_STAT_CONVOIS); if (weg_t* w = gr->get_weg_nr(1)) { passed += w->get_statistics(WAY_STAT_CONVOIS); } if (passed > max_passed) { max_passed = passed; } set_map_color(k, calc_severity_color_log(passed, max_passed)); return true; } } break; // show tracks: white: no electricity, red: electricity, yellow: signal case MAP_TRACKS: // show track if (gr->hat_weg(track_wt)) { const schiene_t* sch = (const schiene_t*)(gr->get_weg(track_wt)); // show signals if (sch->has_sign() || sch->has_signal()) { set_map_color(k, color_idx_to_rgb(COL_YELLOW)); return true; } else if (sch->is_electrified()) { set_map_color(k, color_idx_to_rgb(COL_RED)); return true; } else { set_map_color(k, color_idx_to_rgb(COL_WHITE)); return true; } } break; // show max speed (if there) case MAX_SPEEDLIMIT: if (gr->get_max_speed()) { set_map_color(k, calc_severity_color(gr->get_max_speed(), 450)); return true; } break; // find power lines case MAP_POWERLINES: if (const leitung_t* lt = gr->find()) { const sint32 saturated_demand = std::min(lt->get_net()->get_demand(), INT32_MAX); const sint32 saturated_supply = std::min(lt->get_net()->get_supply(), INT32_MAX); set_map_color(k, calc_severity_color(saturated_demand, saturated_supply)); return true; } break; case MAP_FOREST: if (gr->obj_count() > 1 && gr->obj_bei(gr->obj_count() - 1)->get_typ() == obj_t::baum) { set_map_color(k, color_idx_to_rgb(COL_GREEN)); return true; } break; case MAP_OWNER: // show ownership if (gr->is_halt()) { set_map_color(k, color_idx_to_rgb(gr->get_halt()->get_owner()->get_player_color1() + 3)); return true; } else if (weg_t* weg = gr->get_weg_nr(0)) { set_map_color(k, weg->get_owner() == NULL ? color_idx_to_rgb(COL_ORANGE) : color_idx_to_rgb(weg->get_owner()->get_player_color1() + 3)); return true; } if (gebaeude_t* gb = gr->find()) { if (gb->get_owner() != NULL) { set_map_color(k, color_idx_to_rgb(gb->get_owner()->get_player_color1() + 3)); return true; } } break; case MAP_LEVEL: if (max_building_level == 0) { // init maximum max_building_level = 1; calc_map(); return true; } else if (gr->get_typ() == grund_t::fundament) { if (gebaeude_t* gb = gr->find()) { if (gb->is_city_building()) { sint32 level = gb->get_tile()->get_desc()->get_level(); if (level > max_building_level) { max_building_level = level; } set_map_color(k, calc_severity_color(level, max_building_level)); return true; } } } break; default: return false; } return false; } void minimap_t::calc_map_pixel(const koord k) { // no pixels visible, so noting to calculate if(!is_visible) { return; } // always use to uppermost ground const planquadrat_t *plan=world->access(k); if(plan==NULL || plan->get_boden_count()==0) { return; } switch (mode & ~MAP_MODE_FLAGS) { // show passenger coverage // display coverage case MAP_PASSENGER: for (int i = 0; i < plan->get_haltlist_count(); i++) { halthandle_t halt = plan->get_haltlist()[i]; if (halt->get_pax_enabled() && !halt->get_pax_connections().empty()) { set_map_color(k, color_idx_to_rgb(halt->get_owner()->get_player_color1() + 3)); return; } } break; // show mail coverage // display coverage case MAP_MAIL: for (int i = 0; i < plan->get_haltlist_count(); i++) { halthandle_t halt = plan->get_haltlist()[i]; if (halt->get_mail_enabled() && !halt->get_mail_connections().empty()) { set_map_color(k, color_idx_to_rgb(halt->get_owner()->get_player_color1() + 3)); return; } } break; } if(grund_t::underground_mode == grund_t::ugm_all) { const grund_t* last_tunnel = 0; for (uint8 i = 1; i < plan->get_boden_count(); i++) { const grund_t* gr = plan->get_boden_bei(i); if (gr->get_typ()==grund_t::tunnelboden) { if (calc_map_pixel(gr)) { return; } last_tunnel = gr; } } if(last_tunnel) { set_map_color(k, calc_ground_color(last_tunnel)); } else { set_map_color(k, color_idx_to_rgb(COL_BLACK)); } } else if(grund_t::underground_mode == grund_t::ugm_level) { for (uint8 i = 0; i < plan->get_boden_count(); i++) { const grund_t* gr = plan->get_boden_bei(i); if ((gr->get_hoehe() == grund_t::underground_level || (i==0 && gr->get_hoehe() == grund_t::underground_level)) && calc_map_pixel(gr)) { return; } } grund_t* gr = plan->get_boden_in_hoehe(grund_t::underground_level); if (!gr) { gr = plan->get_kartenboden(); } if (gr->get_hoehe() <= grund_t::underground_level) { set_map_color(k, calc_ground_color(gr)); } else { set_map_color(k, color_idx_to_rgb(COL_BLACK)); } } else { for (uint8 i = 0; i < plan->get_boden_count(); i++) { const grund_t* gr = plan->get_boden_bei(i); if (calc_map_pixel(gr)) { return; } } // Nothing special => calculate ground color based on last index set_map_color(k, calc_ground_color(plan->get_boden_bei(plan->get_boden_count() - 1))); } } scr_size minimap_t::get_min_size() const { return get_max_size(); //scr_size(0,0); } scr_size minimap_t::get_max_size() const { scr_coord size = map_to_screen_coord( koord( world->get_size().x, 0 ) ); scr_coord down = map_to_screen_coord( koord( world->get_size().x, world->get_size().y ) ); size.y = down.y; if( isometric ) { size.x += zoom_in*2; } return scr_size(size.x, size.y); } void minimap_t::calc_map_size() { set_size( get_max_size() ); // of the gui_component to adjust scroll bars needs_redraw = true; } void minimap_t::calc_map() { // only use bitmap size like screen size scr_size minimap_size ( min( get_size().w, new_size.w ), min( get_size().h, new_size.h ) ); // actually the following line should reduce new/deletes, but does not work properly if( map_data==NULL || (sint16) map_data->get_width()!=minimap_size.w || (sint16) map_data->get_height()!=minimap_size.h ) { delete map_data; map_data = new array2d_tpl ( minimap_size.w,minimap_size.h); } cur_off = new_off; cur_size = new_size; needs_redraw = false; is_visible = true; // redraw the map if( !isometric ) { koord k; koord start_off = koord( (cur_off.x*zoom_out)/zoom_in, (cur_off.y*zoom_out)/zoom_in ); koord end_off = start_off+koord( ( map_data->get_width()*zoom_out)/zoom_in+1, ( map_data->get_height()*zoom_out)/zoom_in+1 ); for( k.y=start_off.y; k.yinit( color_idx_to_rgb(COL_BLACK) ); } koord k; for( k.y=0; k.y < world->get_size().y; k.y++ ) { for( k.x=0; k.x < world->get_size().x; k.x++ ) { calc_map_pixel(k); } } } } minimap_t::minimap_t() { map_data = NULL; zoom_in = 1; zoom_out = 1; isometric = false; show_network_load_factor = false; mode = MAP_TOWN; selected_city = NULL; cur_off = new_off = scr_coord(0,0); cur_size = new_size = scr_size(0,0); needs_redraw = true; transport_type_showed_on_map = simline_t::line; } minimap_t::~minimap_t() { delete map_data; } minimap_t *minimap_t::get_instance() { if(single_instance == NULL) { single_instance = new minimap_t(); } return single_instance; } void minimap_t::init() { delete map_data; map_data = NULL; needs_redraw = true; is_visible = false; calc_map_size(); max_building_level = max_cargo = max_passed = 0; max_tourist_ziele = max_waiting = max_origin = max_transfer = max_service = 1; last_schedule_counter = world->get_schedule_counter()-1; set_selected_cnv(convoihandle_t()); } void minimap_t::set_display_mode(MAP_DISPLAY_MODE new_mode) { mode = new_mode; needs_redraw = true; } void minimap_t::new_month() { needs_redraw = true; } void minimap_t::invalidate_map_lines_cache() { last_schedule_counter = world->get_schedule_counter() - 1; needs_redraw = true; } // these two are the only gui_container specific routines // handle event bool minimap_t::infowin_event(const event_t *ev) { const koord k = screen_to_map_coord(ev->mouse_pos); // get factory under mouse cursor last_world_pos = k; if (IS_WHEELDOWN(ev) || IS_WHEELUP(ev)) { change_zoom_factor(IS_WHEELUP(ev)); return true; } // recenter if(IS_LEFTRELEASE(ev) || ((IS_LEFTCLICK(ev) || IS_LEFTDRAG(ev)) && !env_t::leftdrag_in_minimap)) { world->get_viewport()->set_follow_convoi( convoihandle_t() ); const sint8 min_hgt = world->is_within_grid_limits(k) ? world->min_hgt(k) : 0; world->get_viewport()->change_world_position(koord3d(k,min_hgt)); return true; } return false; } // helper function for finding nearby factory const fabrik_t* minimap_t::get_factory_near( const koord, bool enlarge ) const { const fabrik_t *fab = fabrik_t::get_fab(last_world_pos); for( int i=0; i<4 && fab==NULL; i++ ) { fab = fabrik_t::get_fab( last_world_pos+koord::nesw[i] ); } if( enlarge ) { for( int i=0; i<4 && fab==NULL; i++ ) { fab = fabrik_t::get_fab( last_world_pos+koord::nesw[i]*2 ); } } return fab; } // helper function for redraw: factory connections const fabrik_t* minimap_t::draw_factory_connections(const fabrik_t* const fab, bool supplier_link, const scr_coord pos) const { if(fab) { PIXVAL color = supplier_link ? color_idx_to_rgb(COL_RED) : color_idx_to_rgb(COL_WHITE); scr_coord fabpos = map_to_screen_coord( fab->get_pos().get_2d() ) + pos; const vector_tpl& consumer = supplier_link ? fab->get_suppliers() : fab->get_consumer(); for(koord lieferziel : consumer) { const fabrik_t * fab2 = fabrik_t::get_fab(lieferziel); if (fab2) { const scr_coord end = map_to_screen_coord( lieferziel ) + pos; display_direct_line_rgb(fabpos.x, fabpos.y, end.x, end.y, color); display_fillbox_wh_clip_rgb(end.x, end.y, 3, 3, ((world->get_ticks() >> 10) & 1) == 0 ? color_idx_to_rgb(COL_RED) : color_idx_to_rgb(COL_WHITE), true); scr_coord boxpos = end + scr_coord(10, 0); const char * name = translator::translate(fab2->get_name()); int name_width = proportional_string_width(name)+(LINESPACE/2); boxpos.x = clamp( boxpos.x, pos.x, pos.x+get_size().w-name_width ); display_ddd_proportional_clip(boxpos.x, boxpos.y, color_idx_to_rgb(5), color_idx_to_rgb(COL_WHITE), name, true); } } } return fab; } // show the schedule on the minimap void minimap_t::set_selected_cnv( convoihandle_t c ) { current_cnv = c; schedule_cache.clear(); stop_cache.clear(); colore_idx = 0; add_to_schedule_cache( current_cnv, true ); last_schedule_counter = world->get_schedule_counter()-1; } // draw the map (and the overlays!) void minimap_t::draw(scr_coord pos) { // sanity check, needed for overlarge maps if( (new_off.x|new_off.y)<0 ) { new_off = cur_off; } if( (new_size.w|new_size.h)<0 ) { new_size = cur_size; } if( last_mode != mode ) { // only needing update, if last mode was also not about halts or background rendering ... needs_redraw = (mode^last_mode) & (~MAP_MODE_FLAGS | MAP_CLIMATES | MAP_HIDE_CONTOUR); if( (mode & MAP_LINES) == 0 || (mode^last_mode) & MAP_MODE_HALT_FLAGS ) { // rebuilt stop_cache needed stop_cache.clear(); if( (mode & MAP_LINES) && (last_mode & MAP_LINES) && current_cnv.is_bound() ) { schedule_cache.clear(); add_to_schedule_cache(current_cnv, true); needs_redraw = true; } } if( (mode & MAP_LINES) && (last_mode & MAP_LINES) == 0 && current_cnv.is_bound() ) { schedule_cache.clear(); add_to_schedule_cache(current_cnv, true); needs_redraw = true; } if( (mode^last_mode) & (MAP_PASSENGER|MAP_MAIL|MAP_FREIGHT|MAP_LINES) || (mode&MAP_LINES && stop_cache.empty()) ) { // rebuilt line display last_schedule_counter = world->get_schedule_counter()-1; } last_mode = mode; } if( needs_redraw || cur_off!=new_off || cur_size!=new_size ) { calc_map(); needs_redraw = false; } if( map_data==NULL) { return; } if( mode & MAP_PAX_DEST && selected_city!=NULL ) { const uint32 current_pax_destinations = selected_city->get_pax_destinations_new_change(); if( pax_destinations_last_change > current_pax_destinations ) { // new month started. calc_map(); } else if( pax_destinations_last_change < current_pax_destinations ) { // new pax_dest in city. const sparse_tpl *pax_dests = selected_city->get_pax_destinations_new(); koord pos, min, max; PIXVAL color; for( uint16 i = 0; i < pax_dests->get_data_count(); i++ ) { pax_dests->get_nonzero( i, pos, color ); min = koord((pos.x*world->get_size().x)/PAX_DESTINATIONS_SIZE, (pos.y*world->get_size().y)/PAX_DESTINATIONS_SIZE); max = koord(((pos.x+1)*world->get_size().x)/PAX_DESTINATIONS_SIZE, ((pos.y+1)*world->get_size().y)/PAX_DESTINATIONS_SIZE); pos = min; do { do { set_map_color(pos, color); pos.y++; } while(pos.y < max.y); pos.x++; } while (pos.x < max.x); } } pax_destinations_last_change = selected_city->get_pax_destinations_new_change(); } if( (uint16)cur_size.w > map_data->get_width() ) { display_fillbox_wh_clip_rgb( pos.x+new_off.x+map_data->get_width(), new_off.y+pos.y, 32767, map_data->get_height(), color_idx_to_rgb(COL_BLACK), true); } if( (uint16)cur_size.h > map_data->get_height() ) { display_fillbox_wh_clip_rgb( pos.x+new_off.x, pos.y+new_off.y+map_data->get_height(), 32767, 32767, color_idx_to_rgb(COL_BLACK), true); } display_array_wh( cur_off.x+pos.x, new_off.y+pos.y, map_data->get_width(), map_data->get_height(), map_data->to_array()); if( !current_cnv.is_bound() && mode & MAP_LINES ) { vector_tpl linee; if( last_schedule_counter != world->get_schedule_counter() ) { // rebuild cache last_schedule_counter = world->get_schedule_counter(); schedule_cache.clear(); stop_cache.clear(); waypoint_hash.clear(); colore_idx = 0; for( int np = 0; np < MAX_PLAYER_COUNT; np++ ) { if( player_showed_on_map != -1 && player_showed_on_map != np ) { continue; } //cycle on players if( world->get_player( np ) && world->get_player( np )->simlinemgmt.get_line_count() > 0 ) { world->get_player( np )->simlinemgmt.get_lines( simline_t::line, &linee ); for( uint32 j = 0; j < linee.get_count(); j++ ) { //cycle on lines if( transport_type_showed_on_map != simline_t::line && linee[j]->get_linetype() != transport_type_showed_on_map ) { continue; } if( !is_matching_freight_catg( linee[j]->get_goods_catg_index() ) ) { continue; } // ware matches; now find at least a running convoi on this line ... convoihandle_t cnv; for( uint32 k = 0; k < linee[j]->count_convoys(); k++ ) { convoihandle_t test_cnv = linee[j]->get_convoy(k); if( test_cnv.is_bound() ) { int state = test_cnv->get_state(); if( state != convoi_t::INITIAL && state != convoi_t::ENTERING_DEPOT && state != convoi_t::SELF_DESTRUCT ) { cnv = test_cnv; break; } } } if( !cnv.is_bound() ) { continue; } int state = cnv->get_state(); if( state != convoi_t::INITIAL && state != convoi_t::ENTERING_DEPOT && state != convoi_t::SELF_DESTRUCT ) { add_to_schedule_cache( cnv, false ); } } } } // now add all unbound convois player_t * required_vehicle_owner = NULL; if (player_showed_on_map != -1) { required_vehicle_owner = world->get_player(player_showed_on_map); } for(convoihandle_t cnv : world->convoys() ) { if( !cnv.is_bound() || cnv->get_line().is_bound() ) { // not there or already part of a line continue; } if( required_vehicle_owner!= NULL && required_vehicle_owner != cnv->get_owner() ) { continue; } if( transport_type_showed_on_map != simline_t::line ) { if( transport_type_showed_on_map != simline_t::waytype_to_linetype(cnv->front()->get_waytype()) ) { continue; } } int state = cnv->get_state(); if( state != convoi_t::INITIAL && state != convoi_t::ENTERING_DEPOT && state != convoi_t::SELF_DESTRUCT ) { if( !is_matching_freight_catg(cnv->get_goods_catg_index()) ) { continue; } add_to_schedule_cache( cnv, false ); } } } /************ ATTENTION: The schedule pointers schedule in the line segments ****************** ************ are invalid after this point! ******************/ } //end MAP_LINES bool showing_schedule = false; if( mode & MAP_LINES ) { showing_schedule = !schedule_cache.empty(); } else { schedule_cache.clear(); colore_idx = 0; last_schedule_counter = world->get_schedule_counter()-1; } // since the schedule whitens out the background, we have to draw it first int offset = 1; koord last_start(0,0), last_end(0,0); bool diagonal = false; if( showing_schedule ) { // lighten background if( isometric ) { // isometric => lighten in three parts scr_coord p1 = map_to_screen_coord( koord(0,0) ); scr_coord p2 = map_to_screen_coord( koord( world->get_size().x, 0 ) ); scr_coord p3 = map_to_screen_coord( koord( world->get_size().x, world->get_size().y ) ); scr_coord p4 = map_to_screen_coord( koord( 0, world->get_size().y ) ); // top and bottom part const int toplines = min( p4.y, p2.y ); for( scr_coord_val y = 0; y < toplines; y++ ) { display_blend_wh_rgb( pos.x+p1.x-2*y, pos.y+y, 4*y+4, 1, color_idx_to_rgb(COL_WHITE), 75 ); display_blend_wh_rgb( pos.x+p3.x-2*y, pos.y+p3.y-y-1, 4*y+4, 1, color_idx_to_rgb(COL_WHITE), 75 ); } // center area if( p1.x < p3.x ) { for( scr_coord_val y = toplines; y < p3.y-toplines; y++ ) { display_blend_wh_rgb( pos.x+(y-toplines)*2, pos.y+y, 4*toplines+4, 1, color_idx_to_rgb(COL_WHITE), 75 ); } } else { for( scr_coord_val y = toplines; y < p3.y-toplines; y++ ) { display_blend_wh_rgb( pos.x+(y-toplines)*2, pos.y+p3.y-y-1, 4*toplines+4, 1, color_idx_to_rgb(COL_WHITE), 75 ); } } } else { // easier with rectangular maps ... display_blend_wh_rgb( cur_off.x+pos.x, cur_off.y+pos.y, map_data->get_width(), map_data->get_height(), color_idx_to_rgb(COL_WHITE), 75 ); } scr_coord k1,k2; // DISPLAY STATIONS AND AIRPORTS: moved here so station spots are not overwritten by lines drawn for(line_segment_t seg : schedule_cache ) { uint8 color = seg.colorcount; if( (event_get_last_control_shift() ^ tool_t::control_invert)==2 || current_cnv.is_bound() ) { // on control / single convoi use only player colors static uint8 last_color = color; color = seg.player->get_player_color1()+1; // all lines same thickness if same color if( color == last_color ) { offset = 0; } last_color = color; } if( seg.start != last_start || seg.end != last_end ) { last_start = seg.start; k1 = map_to_screen_coord( seg.start ); k1 += pos; last_end = seg.end; k2 = map_to_screen_coord( seg.end ); k2 += pos; // use same diagonal for all parallel segments diagonal = seg.start_diagonal; } // and finally draw ... line_segment_draw( seg.waytype, k1, seg.start_offset*offset, k2, seg.end_offset*offset, diagonal, color_idx_to_rgb(color) ); } } // display station information here (even without overlay) halthandle_t display_station; // only fill cache if needed if( mode & MAP_MODE_HALT_FLAGS && stop_cache.empty() ) { if( mode & MAP_ORIGIN ) { for(halthandle_t halt : haltestelle_t::get_alle_haltestellen() ) { if( halt->get_pax_enabled() || halt->get_mail_enabled() ) { stop_cache.append( halt ); } } } else if( mode & MAP_TRANSFER ) { for(halthandle_t halt : haltestelle_t::get_alle_haltestellen() ) { for (int catg = goods_manager_t::INDEX_PAS; catg != goods_manager_t::get_max_catg_index(); ++catg) { if (catg != goods_manager_t::INDEX_NONE && halt->is_transfer(catg)) { stop_cache.append(halt); break; } } } } else if( mode&MAP_STATUS || mode&MAP_SERVICE || mode&MAP_WAITING || mode&MAP_WAITCHANGE ) { for(halthandle_t halt : haltestelle_t::get_alle_haltestellen() ) { stop_cache.append( halt ); } } } // now draw stop cache // if needed to get new values sint32 new_max_waiting_change = 1; for(halthandle_t station : stop_cache ) { if( !station.is_bound() ) { // maybe deleted in the meanwhile continue; } int radius = 0; PIXVAL color; int diagonal_dist = 0; scr_coord temp_stop = map_to_screen_coord( station->get_basis_pos() ); temp_stop = temp_stop + pos; if( mode & MAP_STATUS ) { color = station->get_status_farbe(); radius = number_to_radius( station->get_capacity(0) ); } else if( mode & MAP_SERVICE ) { const sint32 service = (sint32)station->get_finance_history( 1, HALT_CONVOIS_ARRIVED ); if( service > max_service ) { max_service = service; } color = calc_severity_color_log( service, max_service ); radius = log2( (uint32)( (service << 7) / max_service ) ); } else if( mode & MAP_WAITING ) { const sint32 waiting = (sint32)station->get_finance_history( 0, HALT_WAITING ); if( waiting > max_waiting ) { max_waiting = waiting; } color = calc_severity_color_log( waiting, max_waiting ); radius = number_to_radius( waiting ); } else if( mode & MAP_WAITCHANGE ) { const sint32 waiting_diff = (sint32)(station->get_finance_history( 0, HALT_WAITING ) - station->get_finance_history( 1, HALT_WAITING )); if( waiting_diff > new_max_waiting_change ) { new_max_waiting_change = waiting_diff; } if( waiting_diff < -new_max_waiting_change ) { new_max_waiting_change = -waiting_diff; } const sint32 span = max(new_max_waiting_change,max_waiting_change); const sint32 diff = waiting_diff + span; color = calc_severity_color( diff, span*2 ) ; radius = number_to_radius( abs(waiting_diff) ); } else if( mode & MAP_ORIGIN ) { if( !station->get_pax_enabled() && !station->get_mail_enabled() ) { continue; } const sint32 pax_origin = (sint32)(station->get_finance_history( 1, HALT_HAPPY ) + station->get_finance_history( 1, HALT_UNHAPPY ) + station->get_finance_history( 1, HALT_NOROUTE )); if( pax_origin > max_origin ) { max_origin = pax_origin; } color = calc_severity_color_log( pax_origin, max_origin ); radius = number_to_radius( pax_origin ); } else if( mode & MAP_TRANSFER ) { const sint32 transfer = (sint32)(station->get_finance_history( 1, HALT_ARRIVED ) + station->get_finance_history( 1, HALT_DEPARTED )); if( transfer > max_transfer ) { max_transfer = transfer; } color = calc_severity_color_log( transfer, max_transfer ); radius = number_to_radius( transfer ); } else { const int stype = station->get_station_type(); color = color_idx_to_rgb(station->get_owner()->get_player_color1()+3); // invalid=0, loadingbay=1, railstation = 2, dock = 4, busstop = 8, airstop = 16, monorailstop = 32, tramstop = 64, maglevstop=128, narrowgaugestop=256 if( stype > 0 ) { radius = 1; if( stype & ~(haltestelle_t::loadingbay | haltestelle_t::busstop | haltestelle_t::tramstop) ) { radius = 3; } } // with control, show only circles if((event_get_last_control_shift() ^ tool_t::control_invert)==2) { // else elongate them ... const int key = station->get_basis_pos().x + station->get_basis_pos().y * world->get_size().x; diagonal_dist = waypoint_hash.get( key ).get_count(); if( diagonal_dist ) { diagonal_dist--; } diagonal_dist = (diagonal_dist*3)-1; } // show the mode of transport of the station if( skinverwaltung_t::station_type ) { int icon = 0; for( int type=0; type<9; type++ ) { if( (stype>>type)&1 ) { image_id img = skinverwaltung_t::station_type->get_image_id(type); if( img!=IMG_EMPTY ) { display_color_img( img, temp_stop.x+diagonal_dist+4+(icon/2)*12, temp_stop.y+diagonal_dist+4+(icon&1)*12, station->get_owner()->get_player_nr(), false, false ); icon++; } } } } else { if( stype & haltestelle_t::airstop ) { display_airport( temp_stop.x+diagonal_dist, temp_stop.y+diagonal_dist, color ); } if( stype & haltestelle_t::dock ) { display_harbor( temp_stop.x+diagonal_dist, temp_stop.y+diagonal_dist, color ); } } } // avoid too small circles when zoomed out if( zoom_in > 1 ) { radius ++; } int out_radius = (radius == 0) ? 1 : radius; display_filled_circle_rgb( temp_stop.x, temp_stop.y, radius, color ); display_circle_rgb( temp_stop.x, temp_stop.y, out_radius, color_idx_to_rgb(COL_BLACK) ); if( diagonal_dist>0 ) { display_filled_circle_rgb( temp_stop.x+diagonal_dist, temp_stop.y+diagonal_dist, radius, color ); display_circle_rgb( temp_stop.x+diagonal_dist, temp_stop.y+diagonal_dist, out_radius, color_idx_to_rgb(COL_BLACK) ); for( int i=1; i < diagonal_dist; i++ ) { display_filled_circle_rgb( temp_stop.x+i, temp_stop.y+i, radius, color ); } out_radius = sqrt_i32( 2*out_radius+1 ); display_direct_line_rgb( temp_stop.x+out_radius, temp_stop.y-out_radius, temp_stop.x+out_radius+diagonal_dist, temp_stop.y-out_radius+diagonal_dist, color_idx_to_rgb(COL_BLACK) ); display_direct_line_rgb( temp_stop.x-out_radius, temp_stop.y+out_radius, temp_stop.x-out_radius+diagonal_dist, temp_stop.y+out_radius+diagonal_dist, color_idx_to_rgb(COL_BLACK) ); } if( koord_distance( last_world_pos, station->get_basis_pos() ) <= 2 ) { // draw stop name with an index if close to mouse display_station = station; } } if( display_station.is_bound() ) { scr_coord temp_stop = map_to_screen_coord( display_station->get_basis_pos() ); temp_stop = temp_stop + pos; display_ddd_proportional_clip( temp_stop.x + 10, temp_stop.y + 7, color_idx_to_rgb(display_station->get_owner()->get_player_color1()+3), color_idx_to_rgb(COL_WHITE), display_station->get_name(), false ); } max_waiting_change = new_max_waiting_change; // update waiting tendencies // if we do not do this here, vehicles would erase the town names // ADD: if CRTL key is pressed, temporary show the name if( mode & MAP_TOWN ) { const weighted_vector_tpl& staedte = world->get_cities(); const PIXVAL col = color_idx_to_rgb(showing_schedule ? COL_BLACK : COL_WHITE); for(stadt_t* const stadt : staedte ) { const char * name = stadt->get_name(); scr_coord p = map_to_screen_coord( stadt->get_pos() ); p += pos; display_proportional_clip_rgb( p.x, p.y, name, ALIGN_LEFT, col, true ); } } // draw city limit if( mode & MAP_CITYLIMIT ) { const PIXVAL col = color_idx_to_rgb(showing_schedule ? COL_DARK_BROWN : COL_ORANGE); // for all cities for(stadt_t* const stadt : world->get_cities() ) { koord k[4]; k[0] = stadt->get_linksoben(); // top left k[2] = stadt->get_rechtsunten(); // bottom right k[1] = koord(k[0].x, k[2].y); // bottom left k[3] = koord(k[2].x, k[0].y); // top right k[0] += koord(0, -1); // top left k[2] += koord(1, 0); // bottom right k[3] += koord(1, -1); // top right // calculate and draw the rotated coordinates scr_coord c[4]; for(uint i=0; iget_attractions() ) { if( gb->get_first_tile() == gb ) { scr_coord gb_pos = map_to_screen_coord( gb->get_pos().get_2d() ); gb_pos = gb_pos + pos; int const pax = gb->get_passagier_level(); if( max_tourist_ziele < pax ) { max_tourist_ziele = pax; } PIXVAL color = calc_severity_color_log(gb->get_passagier_level(), max_tourist_ziele); int radius = max( (number_to_radius( pax*4 )*zoom_in)/zoom_out, 1 ); display_filled_circle_rgb( gb_pos.x, gb_pos.y, radius, color ); display_circle_rgb( gb_pos.x, gb_pos.y, radius, color_idx_to_rgb(COL_BLACK) ); } // otherwise larger attraction will be shown more often ... } } if( mode & MAP_FACTORIES ) { for(fabrik_t* const f : world->get_fab_list() ) { // find top-left tile position koord3d fab_tl_pos = f->get_pos(); if (grund_t *gr = world->lookup(f->get_pos())) { if (gebaeude_t* gb = gr->find()) { fab_tl_pos = gb->get_pos() - gb->get_tile()->get_offset(); } } scr_coord fab_pos = map_to_screen_coord( fab_tl_pos.get_2d() ); fab_pos = fab_pos + pos; koord size = f->get_desc()->get_building()->get_size(f->get_rotate()); sint16 x_size = max( 5, size.x*zoom_in ); sint16 y_size = max( 5, size.y*zoom_in ); display_fillbox_wh_clip_rgb( fab_pos.x-1, fab_pos.y-1, x_size+2, y_size+2, color_idx_to_rgb(COL_BLACK), false ); display_fillbox_wh_clip_rgb( fab_pos.x, fab_pos.y, x_size, y_size, f->get_color(), false ); } } if( mode & MAP_DEPOT ) { for(depot_t* const d : depot_t::get_depot_list() ) { if( d->get_owner() == world->get_active_player() ) { scr_coord depot_pos = map_to_screen_coord( d->get_pos().get_2d() ); depot_pos = depot_pos + pos; // offset of one to avoid static uint8 depot_typ_to_color[19]={ COL_ORANGE, COL_YELLOW, COL_RED, 0, 0, 0, 0, 0, 0, COL_PURPLE, COL_DARK_RED, COL_DARK_ORANGE, 0, 0, 0, 0, 0, 0, COL_LIGHT_RED }; display_filled_circle_rgb( depot_pos.x, depot_pos.y, 4, color_idx_to_rgb(depot_typ_to_color[d->get_typ() - obj_t::bahndepot]) ); display_circle_rgb( depot_pos.x, depot_pos.y, 4, color_idx_to_rgb(COL_BLACK) ); } } } // zoom/resize "selection box" in map // this must be rotated by 45 degree (sin45=cos45=0,5*sqrt(2)=0.707...) const sint16 raster=get_tile_raster_width(); // calculate and draw the rotated coordinates koord ij = world->get_viewport()->get_world_position(); const koord diff = koord( display_get_width()/(2*raster), display_get_height()/raster ); koord view[4]; scr_coord test[4]; // default coordinates - may be off if screen shows high mountains view[0] = ij + koord( -diff.y+diff.x, -diff.y-diff.x ); view[1] = ij + koord( -diff.y-diff.x, -diff.y+diff.x ); view[2] = ij + koord( diff.y-diff.x, diff.y+diff.x ); view[3] = ij + koord( diff.y+diff.x, diff.y-diff.x ); // try to find tile under the four corners of the screen test[0] = scr_coord(display_get_width(),0); test[1] = scr_coord(0,0); test[2] = scr_coord(0,display_get_height()); test[3] = scr_coord(display_get_width(),display_get_height()); for(int i=0; i<4; i++) { sint32 dummy1, dummy2; if (grund_t *gr = world->get_viewport()->get_ground_on_screen_coordinate( test[i], dummy1, dummy2 ) ) { view[i] = gr->get_pos().get_2d(); } } scr_coord c[4]; // translate to coordinates in the minimap for( int i=0; i<4; i++ ) { c[i] = map_to_screen_coord( view[i] ) + pos; } for( int i=0; i<4; i++ ) { display_direct_line_rgb( c[i].x, c[i].y, c[(i+1)%4].x, c[(i+1)%4].y, color_idx_to_rgb(showing_schedule?COL_RED:COL_YELLOW)); } if( !showing_schedule ) { // Add factory name tooltips and draw factory connections, if on a factory const fabrik_t* const fab = get_factory_near(last_world_pos, (mode & MAP_FACTORIES)); if(fab) { if (mode & MAP_FACTORIES) { draw_factory_connections(fab,event_get_last_control_shift() & 1, pos); } scr_coord fabpos = map_to_screen_coord( fab->get_pos().get_2d() ); scr_coord boxpos = fabpos + scr_coord(10, 0); const char * name = translator::translate(fab->get_name()); int name_width = proportional_string_width(name)+(LINESPACE/2); boxpos.x = clamp( boxpos.x, 0, 0+get_size().w-name_width ); boxpos += pos; display_ddd_proportional_clip(boxpos.x, boxpos.y, color_idx_to_rgb(10), color_idx_to_rgb(COL_WHITE), name, true); } for (int i = win_get_open_count() - 1; i >= 0; i--) { gui_frame_t *g = win_get_index(i); if(g->get_rdwr_id()== magic_factory_info) { // is a factory info window const fabrik_t * const fab = dynamic_cast(g)->get_factory(); draw_factory_connections(fab, true, pos); draw_factory_connections(fab, false, pos); break; // only show top window } } } if (current_cnv.is_bound()) { scr_coord_val offset = zoom_in / zoom_out /2; scr_coord_val wd = max( zoom_in/zoom_out, 1) * 2 + 1; // to have it always odd for( int i = 0; i < current_cnv->get_vehicle_count(); i++ ) { const scr_coord veh_pos = map_to_screen_coord(current_cnv->get_vehicle(i)->get_pos().get_2d()) + pos; display_fillbox_wh_clip_rgb(veh_pos.x-(wd/2)+offset, veh_pos.y-(wd/2)+offset, wd, wd, color_idx_to_rgb(COL_MAGENTA), true); } } } void minimap_t::set_selected_city( const stadt_t* _city ) { if( selected_city != _city ) { selected_city = _city; if( _city ) { pax_destinations_last_change = _city->get_pax_destinations_new_change(); } calc_map(); } } void minimap_t::rdwr(loadsave_t *file) { file->rdwr_short(zoom_out); file->rdwr_short(zoom_in); file->rdwr_bool(isometric); } bool minimap_t::is_matching_freight_catg(const minivec_tpl &goods_catg_index) { // does this line/convoi has a matching freight if( freight_type_group_index_showed_on_map == goods_manager_t::passengers ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_PAS); } else if( freight_type_group_index_showed_on_map == goods_manager_t::mail ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_MAIL); } else if( freight_type_group_index_showed_on_map == goods_manager_t::none ) { // all freights but not pax or mail for( uint8 i = 0; i < goods_catg_index.get_count(); i++ ) { if( goods_catg_index[i] > goods_manager_t::INDEX_NONE ) { return true; } } return false; } else if( freight_type_group_index_showed_on_map != NULL ) { for( uint8 i = 0; i < goods_catg_index.get_count(); i++ ) { if( goods_catg_index[i] == freight_type_group_index_showed_on_map->get_catg_index() ) { return true; } } return false; } // NULL show all but obey modes if( mode & MAP_PASSENGER ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_PAS); } else if( mode & MAP_MAIL ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_MAIL); } else if( mode & MAP_FREIGHT ) { // all freights but not pax or mail for( uint8 i = 0; i < goods_catg_index.get_count(); i++ ) { if( goods_catg_index[i]>2 ) { return true; } } return false; } // all true return true; } simutrans-124.3/src/simutrans/gui/minimap.h000066400000000000000000000145521474050137200207650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_MINIMAP_H #define GUI_MINIMAP_H #include "components/gui_component.h" #include "../halthandle.h" #include "../simline.h" #include "../convoihandle.h" #include "../dataobj/schedule.h" #include "../tpl/array2d_tpl.h" #include "../tpl/vector_tpl.h" class karte_ptr_t; class fabrik_t; class grund_t; class stadt_t; class player_t; class schedule_t; class loadsave_t; class goods_desc_t; #define MAX_SEVERITY_COLORS 10 /** * This class is used to render the actual minimap. * Implemented as singleton. */ class minimap_t : public gui_component_t { public: enum MAP_DISPLAY_MODE { PLAIN = 0, MAP_TOWN = 1 << 0, MAP_PASSENGER = 1 << 1, MAP_MAIL = 1 << 2, MAP_FREIGHT = 1 << 3, MAP_STATUS = 1 << 4, MAP_SERVICE = 1 << 5, MAP_TRAFFIC = 1 << 6, MAP_ORIGIN = 1 << 7, MAP_TRANSFER = 1 << 8, MAP_WAITING = 1 << 9, MAP_TRACKS = 1 << 10, MAX_SPEEDLIMIT = 1 << 11, MAP_POWERLINES = 1 << 12, MAP_TOURIST = 1 << 13, MAP_FACTORIES = 1 << 14, MAP_DEPOT = 1 << 15, MAP_FOREST = 1 << 16, MAP_CITYLIMIT = 1 << 17, MAP_PAX_DEST = 1 << 18, MAP_OWNER = 1 << 19, MAP_LINES = 1 << 20, MAP_LEVEL = 1 << 21, MAP_WAITCHANGE = 1 << 22, MAP_HIDE_CONTOUR = 1 << 23, MAP_CLIMATES = 1 << 24, MAP_MODE_HALT_FLAGS = (MAP_STATUS|MAP_SERVICE|MAP_ORIGIN|MAP_TRANSFER|MAP_WAITING|MAP_WAITCHANGE), MAP_MODE_FLAGS = (MAP_TOWN|MAP_CITYLIMIT|MAP_STATUS|MAP_SERVICE|MAP_WAITING|MAP_WAITCHANGE|MAP_TRANSFER|MAP_LINES|MAP_FACTORIES|MAP_ORIGIN|MAP_DEPOT|MAP_TOURIST|MAP_PAX_DEST|MAP_HIDE_CONTOUR|MAP_CLIMATES) }; private: static karte_ptr_t world; minimap_t(); static minimap_t *single_instance; /// the terrain map array2d_tpl *map_data; void set_map_color_clip( sint16 x, sint16 y, PIXVAL color ); /// all stuff connected with schedule display class line_segment_t { public: koord start, end; schedule_t *schedule; player_t *player; waytype_t waytype; uint8 colorcount; uint8 start_offset; uint8 end_offset; bool start_diagonal; line_segment_t() {} line_segment_t( koord s, uint8 so, koord e, uint8 eo, schedule_t *sched, player_t *p, uint8 cc, bool diagonal ); bool operator==(const line_segment_t & other) const; }; /// Ordering based on first start then end coordinate class LineSegmentOrdering { public: bool operator()(const minimap_t::line_segment_t& a, const minimap_t::line_segment_t& b) const; }; vector_tpl schedule_cache; convoihandle_t current_cnv; uint8 last_schedule_counter; vector_tpl stop_cache; /// adds a schedule to cache void add_to_schedule_cache( convoihandle_t cnv, bool with_waypoints ); /** * 0: normal * everything else: special map */ static MAP_DISPLAY_MODE mode; static MAP_DISPLAY_MODE last_mode; static const uint8 severity_color[MAX_SEVERITY_COLORS]; koord screen_to_map_coord(const scr_coord&) const; /// for passenger destination display const stadt_t *selected_city; uint32 pax_destinations_last_change; koord last_world_pos; /** * current and new offset and size (to avoid drawing invisible parts) * * gui_component_t::size is always equal to max_size. * * These are size and offset of visible part of map. * We only show and compute this. */ scr_coord cur_off, new_off; scr_size cur_size, new_size; /// true, if full redraw is needed bool needs_redraw; const fabrik_t* get_factory_near(koord pos, bool large_area) const; const fabrik_t* draw_factory_connections(const fabrik_t* const fab, bool supplier_link, const scr_coord pos) const; static sint32 max_cargo; static sint32 max_passed; /// the zoom factors sint16 zoom_out, zoom_in; /// if true, draw the map with 45 degree rotation bool isometric; bool is_matching_freight_catg(const minivec_tpl &goods_catg_index); /// nonstatic, if we have someday many maps ... void set_map_color(koord k, PIXVAL color); public: scr_coord map_to_screen_coord(const koord &k) const; void toggle_isometric() { isometric = !isometric; } bool is_isometric() const { return isometric; } static bool is_visible; bool show_network_load_factor; int player_showed_on_map; int transport_type_showed_on_map; const goods_desc_t *freight_type_group_index_showed_on_map; /** * returns a color based on an amount (high amount/scale -> color shifts from green to red) */ static PIXVAL calc_severity_color(sint32 amount, sint32 scale); /** * returns a color based on an amount (high amount/scale -> color shifts from green to red) * but using log scale */ static PIXVAL calc_severity_color_log(sint32 amount, sint32 scale); /** * returns a color based on the current height */ static PIXVAL calc_height_color(const sint16 height, const sint16 groundwater); /// needed for town passenger map static PIXVAL calc_ground_color (const grund_t *gr); /// we are single instance ... static minimap_t *get_instance(); // HACK! since we cannot set cleanly the current offset/size, we use this helper function void set_xy_offset_size( scr_coord off, scr_size size ) { new_off = off; new_size = size; } /// update color with render mode (but few are ignored ... ) void calc_map_pixel(const koord k); /// update color with render mode (but for that kind of ground) // true for bool calc_map_pixel(const grund_t *gr); void calc_map(); /// calculates the current size of the map (but do not change anything else) void calc_map_size(); ~minimap_t(); void init(); void set_display_mode(MAP_DISPLAY_MODE new_mode); MAP_DISPLAY_MODE get_display_mode() const { return mode; } /// updates the map (if needed) void new_month(); void invalidate_map_lines_cache(); bool infowin_event(event_t const*) OVERRIDE; void draw(scr_coord pos) OVERRIDE; void set_selected_cnv( convoihandle_t c ); void set_selected_city( const stadt_t* _city ); bool is_city_selected(const stadt_t* city) const { return selected_city == city; } /** * @returns true if zoom factors changed */ bool change_zoom_factor(bool magnify); void get_zoom_factors(sint16 &zoom_out_, sint16 &zoom_in_) const { zoom_in_ = zoom_in; zoom_out_ = zoom_out; } void rdwr(loadsave_t *file); scr_size get_min_size() const OVERRIDE; scr_size get_max_size() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/money_frame.cc000066400000000000000000000442311474050137200217670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "money_frame.h" #include "ai_option.h" #include "headquarter_info.h" #include "simwin.h" #include "../world/simworld.h" #include "../player/ai_scripted.h" #include "../simdebug.h" #include "../display/simgraph.h" #include "../simcolor.h" #include "../utils/simstring.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/scenario.h" #include "../dataobj/loadsave.h" #include "components/gui_button_to_chart.h" // for headquarter construction only ... #include "../tool/simmenu.h" // remembers last settings static vector_tpl bFilterStates; #define BUTTONSPACE max(D_BUTTON_HEIGHT, LINESPACE) static const char *cost_type_name[MAX_PLAYER_COST_BUTTON] = { "Transported", "Revenue", "Operation", "Maintenance", "Road toll", "Ops Profit", "New Vehicles", "Construction_Btn", "Gross Profit", "Cash", "Assets", "Margin (%%)", "Net Wealth" }; static const uint8 cost_type_color[MAX_PLAYER_COST_BUTTON] = { COL_TRANSPORTED, COL_REVENUE, COL_OPERATION, COL_MAINTENANCE, COL_TOLL, COL_OPS_PROFIT, COL_NEW_VEHICLES, COL_CONSTRUCTION, COL_PROFIT, COL_CASH, COL_VEHICLE_ASSETS, COL_MARGIN, COL_WEALTH }; static const uint8 cost_type[3*MAX_PLAYER_COST_BUTTON] = { ATV_TRANSPORTED, TT_ALL, gui_chart_t::STANDARD, // all transported goods ATV_REVENUE_TRANSPORT, TT_ALL, gui_chart_t::MONEY, // Income ATV_RUNNING_COST, TT_ALL, gui_chart_t::MONEY, // Vehicle running costs ATV_INFRASTRUCTURE_MAINTENANCE, TT_ALL, gui_chart_t::MONEY, // Upkeep ATV_WAY_TOLL, TT_ALL, gui_chart_t::MONEY, ATV_OPERATING_PROFIT, TT_ALL, gui_chart_t::MONEY, ATV_NEW_VEHICLE, TT_ALL, gui_chart_t::MONEY, // New vehicles ATV_CONSTRUCTION_COST, TT_ALL, gui_chart_t::MONEY, // Construction ATV_PROFIT, TT_ALL, gui_chart_t::MONEY, ATC_CASH, TT_MAX, gui_chart_t::MONEY, // Cash ATV_NON_FINANCIAL_ASSETS, TT_ALL, gui_chart_t::MONEY, // value of all vehicles and buildings ATV_PROFIT_MARGIN, TT_ALL, gui_chart_t::PERCENT, ATC_NETWEALTH, TT_MAX, gui_chart_t::MONEY, // Total Cash + Assets }; static const sint8 cell_to_buttons[] = { 0, -1, -1, -1, -1, 1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, 5, -1, -1, 9, -1, 6, -1, -1, 10, -1, 7, -1, -1, 11, -1, 8, -1, -1, 12, -1 }; // money label types: tt, atv, current/previous, type static const uint16 label_type[] = { TT_ALL, ATV_TRANSPORTED, 0, gui_chart_t::STANDARD, TT_ALL, ATV_TRANSPORTED, 1, gui_chart_t::STANDARD, TT_ALL, ATV_REVENUE_TRANSPORT, 0, gui_chart_t::MONEY, TT_ALL, ATV_REVENUE_TRANSPORT, 1, gui_chart_t::MONEY, TT_ALL, ATV_RUNNING_COST, 0, gui_chart_t::MONEY, TT_ALL, ATV_RUNNING_COST, 1, gui_chart_t::MONEY, TT_ALL, ATV_INFRASTRUCTURE_MAINTENANCE, 0, gui_chart_t::MONEY, TT_ALL, ATV_INFRASTRUCTURE_MAINTENANCE, 1, gui_chart_t::MONEY, TT_ALL, ATV_WAY_TOLL, 0, gui_chart_t::MONEY, TT_ALL, ATV_WAY_TOLL, 1, gui_chart_t::MONEY, TT_ALL, ATV_OPERATING_PROFIT, 0, gui_chart_t::MONEY, TT_ALL, ATV_OPERATING_PROFIT, 1, gui_chart_t::MONEY, TT_ALL, ATV_NEW_VEHICLE, 0, gui_chart_t::MONEY, TT_ALL, ATV_NEW_VEHICLE, 1, gui_chart_t::MONEY, TT_ALL, ATV_CONSTRUCTION_COST, 0, gui_chart_t::MONEY, TT_ALL, ATV_CONSTRUCTION_COST, 1, gui_chart_t::MONEY, TT_ALL, ATV_PROFIT, 0, gui_chart_t::MONEY, TT_ALL, ATV_PROFIT, 1, gui_chart_t::MONEY, TT_MAX, ATC_CASH, 0, gui_chart_t::MONEY, TT_ALL, ATV_NON_FINANCIAL_ASSETS, 0, gui_chart_t::MONEY, TT_ALL, ATV_PROFIT_MARGIN, 0, gui_chart_t::PERCENT, TT_MAX, ATC_NETWEALTH, 0, gui_chart_t::MONEY }; static const sint8 cell_to_moneylabel[] = { -1, 0, 1, -1, -1, -1, 2, 3, -1, -1, -1, 4, 5, -1, -1, -1, 6, 7, -1, -1, -1, 8, 9, -1, -1, -1, 10, 11, -1, 18, -1, 12, 13, -1, 19, -1, 14, 15, -1, 20, -1, 16, 17, -1, 21, }; /// Helper method to query data from players statistics sint64 money_frame_t::get_statistics_value(int tt, uint8 type, int yearmonth, bool monthly) { const finance_t* finance = player->get_finance(); if (tt == TT_MAX) { return monthly ? finance->get_history_com_month(yearmonth, type) : finance->get_history_com_year( yearmonth, type); } else { assert(0 <= tt && tt < TT_MAX); return monthly ? finance->get_history_veh_month((transport_type)tt, yearmonth, type) : finance->get_history_veh_year( (transport_type)tt, yearmonth, type); } } class money_frame_label_t : public gui_label_buf_t { uint8 transport_type; uint8 type; uint8 label_type; uint8 index; bool monthly; public: money_frame_label_t(uint8 tt, uint8 t, uint8 lt, uint8 i, bool mon) : gui_label_buf_t(lt == gui_chart_t::STANDARD ? SYSCOL_TEXT : MONEY_PLUS, lt != gui_chart_t::MONEY ? gui_label_t::right : gui_label_t::money_right) , transport_type(tt), type(t), label_type(lt), index(i), monthly(mon) { } void update(money_frame_t *mf) { uint8 tt = transport_type == TT_ALL ? mf->transport_type_option : transport_type; sint64 value = mf->get_statistics_value(tt, type, index, monthly ? 1 : 0); PIXVAL color = value >= 0 ? (value > 0 ? MONEY_PLUS : SYSCOL_TEXT_UNUSED) : MONEY_MINUS; switch (label_type) { case gui_chart_t::MONEY: buf().append_money(value / 100.0); break; case gui_chart_t::PERCENT: buf().append(value / 100.0, 2); buf().append("%"); break; default: buf().append(value * 1.0, 0); } gui_label_buf_t::update(); set_color(color); } }; void money_frame_t::fill_chart_tables() { // fill tables for chart curves for (int i = 0; iget_finance()->get_maintenance_with_bits((transport_type)ttoption) != 0) { return false; } // search for any non-zero values for (int i = 0; iget_player(0)!=player) { money_frame_title.printf(translator::translate("Finances of %s"), translator::translate(player->get_name()) ); set_name(money_frame_title); } this->player = player; set_table_layout(1,0); // bankruptcy notice add_component(&warn); warn.set_visible(false); // scenario name if(player->get_player_nr()!=1 && welt->get_scenario()->active()) { add_table(3,1); new_component("Scenario_", SYSCOL_TEXT_HIGHLIGHT); add_component(&scenario_desc); add_component(&scenario_completion); end_table(); } // select transport type gui_aligned_container_t *top = add_table(4,1); { new_component("Show finances for transport type"); transport_type_c.set_focusable( false ); for(int i=0, count=0; i(translator::translate(finance_t::transport_type_values[i]), SYSCOL_TEXT); transport_types[ count++ ] = i; } } add_component(&transport_type_c); transport_type_c.add_listener( this ); transport_type_c.set_selection(0); top->set_focus( &transport_type_c ); set_focus(top); new_component(); // headquarter/ai settings button/ai info string if (player->get_ai_id() != player_t::HUMAN && player->get_ai_id() != player_t::AI_SCRIPTED) { headquarter.init(button_t::roundbox, "Configure AI"); headquarter.add_listener(this); headquarter.set_tooltip("Configure AI setttings"); add_component(&headquarter); } else if (player->get_ai_id() == player_t::HUMAN) { koord pos = player->get_headquarter_pos(); headquarter.set_text(pos != koord::invalid ? "show HQ" : "build HQ"); headquarter.set_tooltip(NULL); if (pos == koord::invalid) { if (player == welt->get_active_player()) { // reuse tooltip from tool_headquarter_t const char* c = tool_t::general_tool[TOOL_HEADQUARTER]->get_tooltip(player); if (c) { // only true, if the headquarter can be built/updated headquarter_tooltip.clear(); headquarter_tooltip.append(c); headquarter.set_tooltip(headquarter_tooltip); } } } headquarter.add_listener(this); add_component(&headquarter); } else { new_component(dynamic_cast(player)->get_ai_name()); } } end_table(); // tab panels // tab (month/year) year_month_tabs.add_tab( &container_year, translator::translate("Years")); year_month_tabs.add_tab( &container_month, translator::translate("Months")); year_month_tabs.add_listener(this); add_component(&year_month_tabs); // fill both containers gui_aligned_container_t *current = &container_year; gui_chart_t *current_chart = &chart; // .. put the same buttons in both containers button_t* buttons[MAX_PLAYER_COST_BUTTON]; for(uint8 i = 0; i < 2 ; i++) { uint8 k = 0; current->set_table_layout(1,0); current->add_table(5,10); // first row: some labels current->new_component(); current->new_component(i==0 ? "This Year" : "This Month", SYSCOL_TEXT_HIGHLIGHT); current->new_component(i==0 ? "Last Year" : "Last Month", SYSCOL_TEXT_HIGHLIGHT); current->new_component(); current->new_component(); // all other rows: mix of buttons and money-labels for(uint8 r = 0; r < 9; r++) { for(uint8 c = 0; c < 5; c++, k++) { sint8 cost = cell_to_buttons[k]; sint8 l = cell_to_moneylabel[k]; // button + chart line if (cost >=0 ) { // add chart line const int curve_type = cost_type[3*cost+2]; const int curve_precision = curve_type == gui_chart_t::STANDARD ? 0 : 2; sint16 curve = i == 0 ? chart.add_curve( color_idx_to_rgb(cost_type_color[cost]), *chart_table_year, MAX_PLAYER_COST_BUTTON, cost, MAX_PLAYER_HISTORY_YEARS, curve_type, false, true, curve_precision) : mchart.add_curve( color_idx_to_rgb(cost_type_color[cost]), *chart_table_month, MAX_PLAYER_COST_BUTTON, cost, MAX_PLAYER_HISTORY_MONTHS, curve_type, false, true, curve_precision); // add button button_t *b; if (i == 0) { b = current->new_component(); b->init(button_t::box_state_automatic | button_t::flexible, cost_type_name[cost]); b->background_color = color_idx_to_rgb(cost_type_color[cost]); b->pressed = false; buttons[cost] = b; } else { b = buttons[cost]; current->add_component(b); } button_to_chart.append(b, current_chart, curve); } else if (l >= 0) { // money_frame_label_t(uint8 tt, uint8 t, uint8 lt, uint8 i, bool mon) money_labels.append( current->new_component(label_type[4*l], label_type[4*l+1], label_type[4*l+3], label_type[4*l+2], i==1) ); } else { if (r >= 2 && r<=4 && c == 4) { switch(r) { case 2: current->new_component("This Month", SYSCOL_TEXT_HIGHLIGHT); break; case 3: current->add_component(&maintenance_money); break; case 4: current->new_component("This Year", SYSCOL_TEXT_HIGHLIGHT); } } else { current->new_component(); } } } } current->end_table(); current->add_component(current_chart); current = &container_month; current_chart = &mchart; } // recover button states if (bFilterStates.get_count() > 0) { for(uint8 i = 0; iget_button()->pressed = bFilterStates[i] > 0; button_to_chart[i]->update(); } } chart.set_min_size(scr_size(0 ,8*BUTTONSPACE)); chart.set_dimension(MAX_PLAYER_HISTORY_YEARS, 10000); chart.set_seed(welt->get_last_year()); chart.set_background(SYSCOL_CHART_BACKGROUND); mchart.set_min_size(scr_size(0,8*BUTTONSPACE)); mchart.set_dimension(MAX_PLAYER_HISTORY_MONTHS, 10000); mchart.set_seed(0); mchart.set_background(SYSCOL_CHART_BACKGROUND); update_labels(); reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(diagonal_resize); } money_frame_t::~money_frame_t() { bFilterStates.clear(); // save button states for(gui_button_to_chart_t* b2c : button_to_chart.list()) { bFilterStates.append( b2c->get_button()->pressed ? 1 : 0); } } void money_frame_t::update_labels() { for(money_frame_label_t* lb : money_labels) { lb->update(this); } // scenario if(player->get_player_nr()!=1 && welt->get_scenario()->active()) { // the text are updated asynchron from the scenario scenario_desc.buf().append( welt->get_scenario()->description_text ); scenario_desc.buf().append( ":" ); scenario_desc.update(); sint32 percent = welt->get_scenario()->get_completion(player->get_player_nr()); if (percent >= 0) { scenario_completion.buf().printf(translator::translate("Scenario complete: %i%%"), percent ); } else { scenario_completion.buf().printf(translator::translate("Scenario lost!")); } scenario_completion.update(); } if (player->get_ai_id() == player_t::HUMAN) { koord pos = player->get_headquarter_pos(); headquarter.set_text(pos != koord::invalid ? "show HQ" : "build HQ"); headquarter.set_tooltip(NULL); if (pos == koord::invalid) { if (player == welt->get_active_player()) { // reuse tooltip from tool_headquarter_t if (const char* c = tool_t::general_tool[TOOL_HEADQUARTER]->get_tooltip(player)) { // only true, if the headquarter can be built/updated headquarter_tooltip.clear(); headquarter_tooltip.append(c); headquarter.set_tooltip(headquarter_tooltip); } } } headquarter.enable(player == welt->get_active_player()); } // current maintenance double maintenance = player->get_finance()->get_maintenance_with_bits((transport_type)transport_type_option) / 100.0; maintenance_money.append_money(-maintenance); maintenance_money.update(); // bankruptcy warning bool visible = warn.is_visible(); if(player->get_finance()->get_history_com_year(0, ATC_NETWEALTH)<0) { warn.set_color( MONEY_MINUS ); warn.buf().append( translator::translate("Company bankrupt") ); warn.set_visible(true); } else if( player->get_finance()->get_history_com_year(0, ATC_NETWEALTH)*10 < welt->get_settings().get_starting_money(welt->get_current_month()/12) ){ warn.set_color( MONEY_MINUS ); warn.buf().append( translator::translate("Net wealth near zero") ); warn.set_visible(true); } else if( player->get_account_overdrawn() ) { warn.set_color( SYSCOL_TEXT_STRONG ); warn.buf().printf(translator::translate("On loan since %i month(s)"), player->get_account_overdrawn() ); warn.set_visible(true); } else { warn.set_visible(false); } warn.update(); if (visible != warn.is_visible()) { resize(scr_size(0,0)); } } void money_frame_t::set_windowsize(scr_size size) { gui_frame_t::set_windowsize(size); // recompute the active container if (year_month_tabs.get_active_tab_index() == 0) { container_year.set_size( container_year.get_size() ); } else { container_month.set_size( container_month.get_size() ); } } void money_frame_t::draw(scr_coord pos, scr_size size) { player->get_finance()->calc_finance_history(); fill_chart_tables(); update_labels(); // update chart seed chart.set_seed(welt->get_last_year()); gui_frame_t::draw(pos, size); } bool money_frame_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if( comp == &headquarter ) { if( player->get_ai_id()!=player_t::HUMAN ) { create_win( new ai_option_t(player), w_info, magic_ai_options_t+player->get_player_nr() ); } else { if (player->get_headquarter_pos() == koord::invalid) { welt->set_tool( tool_t::general_tool[TOOL_HEADQUARTER], player ); } else { // open dedicated HQ window create_win( new headquarter_info_t(player), w_info, magic_headquarter+player->get_player_nr() ); } } return true; } if (comp == &year_month_tabs) { if (year_month_tabs.get_active_tab_index() == 0) { container_year.set_size( container_year.get_size() ); } else { container_month.set_size( container_month.get_size() ); } } if( comp == &transport_type_c) { const sint32 tmp = transport_type_c.get_selection(); if((0 <= tmp) && (tmp < (sint32)transport_type_c.count_elements())) { transport_type_option = transport_types[tmp]; } return true; } return false; } bool money_frame_t::infowin_event(const event_t *ev) { bool swallowed = gui_frame_t::infowin_event(ev); set_focus( &transport_type_c ); return swallowed; } uint32 money_frame_t::get_rdwr_id() { return magic_finances_t+player->get_player_nr(); } void money_frame_t::rdwr( loadsave_t *file ) { // button-to-chart array button_to_chart.rdwr(file); year_month_tabs.rdwr(file); file->rdwr_short(transport_type_option); if (file->is_loading()) { for(uint32 i=0; i money_labels; void update_labels(); void fill_chart_tables(); bool is_chart_table_zero(int ttoption); public: /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "finances.txt";} /** * Constructor. Adds all necessary Subcomponents. */ money_frame_t(player_t *player); ~money_frame_t(); /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; /** * Set window size and adjust component sizes and/or positions accordingly */ void set_windowsize(scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; bool infowin_event(const event_t *ev) OVERRIDE; // saving/restore stuff uint32 get_rdwr_id() OVERRIDE; void rdwr( loadsave_t *file ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/obj_info.cc000066400000000000000000000022141474050137200212460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../display/simgraph.h" #include "../display/viewport.h" #include "../world/simworld.h" #include "../dataobj/translator.h" #include "obj_info.h" obj_infowin_t::obj_infowin_t(const obj_t* obj) : base_infowin_t(translator::translate( obj->get_name() ), obj->get_owner()), view(obj, scr_size( max(64, get_base_tile_raster_width()), max(56, (get_base_tile_raster_width()*7)/8) )) { fill_buffer(); //textarea.set_width( textarea.get_size().w + get_base_tile_raster_width() - 64); set_embedded(&view); } void obj_infowin_t::fill_buffer() { buf.clear(); get_obj()->info(buf); } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void obj_infowin_t::draw(scr_coord pos, scr_size size) { const cbuffer_t old_buf(buf); fill_buffer(); if( strcmp( buf, old_buf ) ) { recalc_size(); } base_infowin_t::draw( pos, size ); } bool obj_infowin_t::is_weltpos() { return ( welt->get_viewport()->is_on_center(get_obj()->get_pos())); } simutrans-124.3/src/simutrans/gui/obj_info.h000066400000000000000000000015601474050137200211130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_OBJ_INFO_H #define GUI_OBJ_INFO_H #include "../simdebug.h" #include "../obj/simobj.h" #include "base_info.h" #include "components/gui_obj_view.h" /** * An adapter class to display info windows for things (objects) */ class obj_infowin_t : public base_infowin_t { protected: obj_view_t view; public: obj_infowin_t(const obj_t* obj); obj_t const* get_obj() const { return view.get_obj(); } koord3d get_weltpos(bool) OVERRIDE { return get_obj()->get_pos(); } bool is_weltpos() OVERRIDE; // refill buffer void fill_buffer(); /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/optionen.cc000066400000000000000000000066051474050137200213240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_divider.h" #include "components/action_listener.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "simwin.h" #include "optionen.h" #include "display_settings.h" #include "sprachen.h" #include "player_frame.h" #include "kennfarbe.h" #include "sound_frame.h" #include "scenario_info.h" #include "banner.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../sys/simsys.h" enum BUTTONS { BUTTON_LANGUAGE = 0, BUTTON_PLAYERS, BUTTON_DISPLAY, BUTTON_PLAYER_COLORS, BUTTON_SOUND, BUTTON_SAVE_GAME, BUTTON_SCENARIO_INFO, BUTTON_MENU, BUTTON_QUIT }; static char const *const option_buttons_text[] = { "Sprache", "Spieler(mz)", "Display settings", "Farbe", "Sound", "Save", "Scenario", "Return to menu", "Beenden" }; optionen_gui_t::optionen_gui_t() : gui_frame_t( translator::translate("Einstellungen aendern")) { assert( lengthof(option_buttons)==lengthof(option_buttons_text) ); assert( lengthof(option_buttons)==BUTTON_QUIT+1 ); set_table_layout(2,0); set_force_equal_columns(true); for( uint i=0; iget_scenario()->active() ) { option_buttons[BUTTON_SCENARIO_INFO].disable(); } // Squeeze in divider new_component(); add_component(option_buttons + i); new_component_span(2); } else add_component(option_buttons + i); } reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(gui_frame_t::horizontal_resize); } /** * This method is called if an action is triggered */ bool optionen_gui_t::action_triggered( gui_action_creator_t *comp,value_t /* */) { if( comp == option_buttons + BUTTON_LANGUAGE ) { create_win(new sprachengui_t(), w_info, magic_sprachengui_t); } else if( comp == option_buttons + BUTTON_PLAYER_COLORS ) { create_win(new farbengui_t(welt->get_active_player()), w_info, magic_farbengui_t); } else if( comp == option_buttons + BUTTON_DISPLAY ) { create_win(new color_gui_t(), w_info, magic_color_gui_t); } else if( comp == option_buttons + BUTTON_SOUND ) { create_win(new sound_frame_t(), w_info, magic_sound_kontroll_t); } else if( comp == option_buttons + BUTTON_PLAYERS ) { create_win(new ki_kontroll_t(), w_info, magic_ki_kontroll_t); } else if( comp == option_buttons + BUTTON_SCENARIO_INFO ) { create_win(new scenario_info_t(), w_info, magic_scenario_info); } else if( comp == option_buttons + BUTTON_SAVE_GAME ) { destroy_win(this); tool_t *tmp_tool = create_tool( DIALOG_SAVE | DIALOGE_TOOL ); welt->set_tool( tmp_tool, welt->get_active_player() ); // since init always returns false, it is safe to delete immediately delete tmp_tool; } else if (comp == option_buttons + BUTTON_MENU) { // return to menu banner_t::show_banner(); } else if( comp == option_buttons + BUTTON_QUIT ) { // we call the proper tool for quitting welt->set_tool(tool_t::simple_tool[TOOL_QUIT], NULL); } else { // not our? return false; } return true; } simutrans-124.3/src/simutrans/gui/optionen.h000066400000000000000000000015051474050137200211600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_OPTIONEN_H #define GUI_OPTIONEN_H #include "simwin.h" #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" /* * Settings in the game * * Dialog for game options/Main menu */ class optionen_gui_t : public gui_frame_t, action_listener_t { private: button_t option_buttons[9]; public: optionen_gui_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "options.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr(loadsave_t *) OVERRIDE {} uint32 get_rdwr_id() OVERRIDE { return magic_optionen_gui_t; } }; #endif simutrans-124.3/src/simutrans/gui/pakinstaller.cc000066400000000000000000000053721474050137200221620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../utils/cbuffer.h" #include "pakinstaller.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../dataobj/pakset_downloader.h" #include "../simloadingscreen.h" #include "../../paksetinfo.h" bool pakinstaller_t::finish_install; pakinstaller_t::pakinstaller_t() : gui_frame_t(translator::translate("Install graphics")), paks(gui_scrolled_list_t::listskin), obsolete_paks(gui_scrolled_list_t::listskin) { finish_install = false; set_table_layout(2, 0); new_component_span( "Select one or more graphics to install (Ctrl+click):", 2 ); for (int i = 0; i < OBSOLETE_FROM; i++) { if (pak_can_download(pakinfo + i)) { paklist.append(pakinfo + i); paks.new_component(pakinfo[i].name, SYSCOL_TEXT); paks.get_element(paks.get_count()-1)->selected = pak_need_update(pakinfo + i); } } paks.enable_multiple_selection(); scr_coord_val paks_h = paks.get_max_size().h; add_component(&paks,2); new_component_span( "The following graphics are unmaintained:", 2 ); for (int i = OBSOLETE_FROM; i < PAKSET_COUNT; i++) { if (pak_can_download(pakinfo + i)) { paklist.append(pakinfo + i); obsolete_paks.new_component(pakinfo[i].name, SYSCOL_TEXT_SHADOW); obsolete_paks.get_element(obsolete_paks.get_count()-1)->selected = pak_need_update(pakinfo + i); } } obsolete_paks.enable_multiple_selection(); scr_coord_val obsolete_paks_h = obsolete_paks.get_max_size().h; add_component(&obsolete_paks,2); bool is_world = world(); install.init(button_t::roundbox_state | button_t::flexible, "Install"); add_component(&install,is_world+1); install.add_listener(this); if( !is_world ) { cancel.init( button_t::roundbox_state | button_t::flexible, "Cancel" ); cancel.add_listener( this ); add_component( &cancel ); } reset_min_windowsize(); set_windowsize(get_min_windowsize()+scr_size(0,paks_h-paks.get_size().h + obsolete_paks_h- obsolete_paks.get_size().h)); } // compile list of paks to be installed by pakset_downloader bool pakinstaller_t::action_triggered(gui_action_creator_t *comp, value_t) { if (comp == &cancel) { finish_install = true; return false; } // now install dr_mkdir( env_t::install_dir ); dr_chdir( env_t::install_dir ); vector_tplinstall_paks; for (sint32 i : paks.get_selections()) { install_paks.append(paklist[i]); } for (sint32 i : obsolete_paks.get_selections()) { install_paks.append(paklist[i+paks.get_count()]); } pak_download(install_paks); finish_install = true; return false; } simutrans-124.3/src/simutrans/gui/pakinstaller.h000066400000000000000000000013451474050137200220200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PAKINSTALLER_H #define GUI_PAKINSTALLER_H #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_label.h" #include "components/gui_scrolled_list.h" #include "components/gui_button.h" #include "simwin.h" #include "../dataobj/pakset_downloader.h" class pakinstaller_t : public gui_frame_t, private action_listener_t { private: gui_scrolled_list_t paks; gui_scrolled_list_t obsolete_paks; button_t install, cancel; vector_tpl paklist; public: static bool finish_install; pakinstaller_t(); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/pakselector.cc000066400000000000000000000077521474050137200220110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "pakselector.h" #include "pakinstaller.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../sys/simsys.h" #include "../pathes.h" pakselector_t::pakselector_t() : savegame_frame_t( NULL, true, NULL, true ), notice_label(¬ice_buffer) { // if true, we would call the installler afterwards pakinstaller_t::finish_install = false; // remove unnecessary buttons top_frame.remove_component( &input ); savebutton.set_visible(false); cancelbutton.set_visible(false); // don't show list item labels label_enabled = false; fnlabel.set_text( "Choose one graphics set for playing:" ); notice_buffer.printf("%s", "To avoid seeing this dialogue define a path by:\n" " - adding 'pak_file_path = pak/' to your simuconf.tab\n" " - using '-objects pakxyz/' on the command line" ); notice_label.recalc_size(); add_component(¬ice_label); installbutton.init( button_t::roundbox, "Install" ); installbutton.add_listener( &ps ); add_component(&installbutton); resize(scr_coord(0,0)); add_path( env_t::base_dir ); if( strcmp(env_t::base_dir,env_t::install_dir) ) { add_path( env_t::install_dir ); } dr_chdir( env_t::user_dir ); if( !dr_chdir(USER_PAK_PATH) ) { char dummy[PATH_MAX]; dr_getcwd(dummy, lengthof(dummy) - 2); strcat(dummy, PATH_SEPARATOR); if( strcmp(env_t::install_dir, dummy) ) { add_path(dummy); } } } /** * what to do after loading */ bool pakselector_t::item_action(const char *fullpath) { env_t::pak_dir = fullpath; env_t::pak_dir += PATH_SEPARATOR; env_t::pak_name = (str_get_filename(fullpath, true)+PATH_SEPARATOR); env_t::default_settings.set_with_private_paks( false ); return true; } bool pakselector_t::del_action(const char *fullpath) { // cannot delete set => use this for selection env_t::pak_dir = fullpath; env_t::pak_dir += PATH_SEPARATOR; env_t::pak_name = str_get_filename(fullpath, true)+PATH_SEPARATOR; env_t::default_settings.set_with_private_paks( true ); return true; } const char *pakselector_t::get_info(const char *) { return ""; } /** * This method returns true if filename is what we want and false if not. * A PAK directory is considered valid if the file ground.outside.pak exists. */ bool pakselector_t::check_file(const char *filename, const char *) { cbuffer_t buf; buf.printf("%s/ground.Outside.pak", filename); // if we can open the file, it is valid. if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } // the file was not found or couldn't be opened. return false; } void pakselector_t::fill_list() { cbuffer_t path; // do the search ... savegame_frame_t::fill_list(); // do not sort or the path names are in the wrong positions // entries.sort(dir_entry_t::compare); for(dir_entry_t &i : entries) { if (i.type == LI_HEADER) { continue; } // look for addon directory path.clear(); path.printf("%saddons/%s", env_t::user_dir, i.button->get_text()); // reuse delete button as load-with-addons button delete i.del; i.del = new button_t(); i.del->init(button_t::roundbox, "Load with addons"); // if we can't change directory to /addon // Hide the addon button if( dr_chdir( path ) != 0 ) { i.del->disable(); // if list contains only one header, one pakset entry without addons // store path to pakset temporary, reset later if more choices available // if env_t::pak_dir is non-empty then simmain.cc will close the window immediately env_t::pak_name = (std::string)i.button->get_text() + PATH_SEPARATOR; env_t::pak_dir = (std::string)i.info + PATH_SEPARATOR; } } dr_chdir( env_t::base_dir ); if(entries.get_count() > this->num_sections+1) { // empty path as more than one pakset is present, user has to choose env_t::pak_dir.clear(); env_t::pak_name.clear(); } } bool pakselector_install_action_t::action_triggered( gui_action_creator_t*, value_t) { pakinstaller_t::finish_install = true; return true; } simutrans-124.3/src/simutrans/gui/pakselector.h000066400000000000000000000021671474050137200216460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PAKSELECTOR_H #define GUI_PAKSELECTOR_H #include "savegame_frame.h" #include "components/gui_textarea.h" #include "../utils/cbuffer.h" class pakselector_install_action_t : public action_listener_t { bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; class pakselector_t : public savegame_frame_t { protected: cbuffer_t notice_buffer; gui_textarea_t notice_label; button_t installbutton; pakselector_install_action_t ps; const char *get_info ( const char *filename ) OVERRIDE; bool check_file ( const char *filename, const char *suffix ) OVERRIDE; bool item_action ( const char *fullpath ) OVERRIDE; bool del_action ( const char *fullpath ) OVERRIDE; void fill_list ( void ) OVERRIDE; public: pakselector_t(); const char *get_help_filename ( void ) const OVERRIDE { return ""; } bool has_title ( void ) const OVERRIDE { return false; } bool has_pak ( void ) const { return !entries.empty(); } }; #endif simutrans-124.3/src/simutrans/gui/password_frame.cc000066400000000000000000000064571474050137200225120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../tool/simmenu.h" #include "simwin.h" #include "../world/simworld.h" #include "../player/simplay.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../network/network_cmd_ingame.h" #include "../utils/cbuffer.h" #include "../utils/sha1.h" #include "../utils/simstring.h" #include "password_frame.h" #include "player_frame.h" password_frame_t::password_frame_t( player_t *player ) : gui_frame_t( translator::translate("Enter Password"), player ) { set_table_layout(2,0); this->player = player; if( !player->is_locked() || (welt->get_active_player_nr()==PLAYER_PUBLIC_NR && !welt->get_public_player()->is_locked()) ) { // allow to change name name tstrncpy( player_name_str, player->get_name(), lengthof(player_name_str) ); player_name.set_text(player_name_str, lengthof(player_name_str)); player_name.add_listener(this); add_component(&player_name, 2); } else { const_player_name.set_text( player->get_name() ); add_component(&const_player_name, 2); } fnlabel.set_text( "Password" ); // so we have a width now add_component(&fnlabel); // Input box for password ibuf[0] = 0; password.set_text(ibuf, lengthof(ibuf) ); password.add_listener(this); add_component( &password ); set_focus( &password ); reset_min_windowsize(); set_windowsize(get_min_windowsize() ); } /** * This method is called if an action is triggered */ bool password_frame_t::action_triggered( gui_action_creator_t *comp, value_t p ) { if(comp == &password && (ibuf[0]!=0 || p.i == 1)) { if (player->is_unlock_pending()) { // unlock already pending, do not do everything twice return true; } // Enter-Key pressed // test for matching password to unlock size_t len = strlen( password.get_text() ); pwd_hash_t hash; // remove hash to re-open slot if password is empty if(len>0) { SHA1 sha1; sha1.Input( password.get_text(), len ); sha1.Result(hash); } // store the hash welt->store_player_password_hash( player->get_player_nr(), hash ); if( env_t::networkmode) { player->unlock(!player->is_locked(), true); // send hash to server: it will unlock player or change password nwc_auth_player_t *nwc = new nwc_auth_player_t(player->get_player_nr(), hash); network_send_server(nwc); } else { /* if current active player is player 1 and this is unlocked, he may reset passwords * otherwise you need the valid previous password */ if( !player->is_locked() || (welt->get_active_player_nr()==PLAYER_PUBLIC_NR && !welt->get_public_player()->is_locked()) ) { // set password player->access_password_hash() = hash; player->unlock(true, false); } else { player->check_unlock(hash); } } } if( comp == &player_name ) { // rename a player cbuffer_t buf; buf.printf( "p%u,%s", player->get_player_nr(), player_name.get_text() ); tool_t *tmp_tool = create_tool( TOOL_RENAME | SIMPLE_TOOL ); tmp_tool->set_default_param( buf ); welt->set_tool( tmp_tool, player ); // since init always returns false, it is safe to delete immediately delete tmp_tool; } if( p.i==1 ) { // destroy window after enter is pressed destroy_win(this); } return true; } simutrans-124.3/src/simutrans/gui/password_frame.h000066400000000000000000000014241474050137200223410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PASSWORD_FRAME_H #define GUI_PASSWORD_FRAME_H #include "components/action_listener.h" #include "gui_frame.h" #include "components/gui_container.h" #include "components/gui_textinput.h" #include "components/gui_label.h" class password_frame_t : public gui_frame_t, action_listener_t { private: char ibuf[256], player_name_str[256]; protected: player_t *player; gui_textinput_t player_name; gui_hidden_textinput_t password; gui_label_t fnlabel, const_player_name; public: password_frame_t( player_t *player ); const char * get_help_filename() const OVERRIDE {return "password.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/player_frame.cc000066400000000000000000000267241474050137200221430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../simcolor.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "../network/network_cmd_ingame.h" #include "../dataobj/environment.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "simwin.h" #include "../utils/simstring.h" #include "../player/ai_scripted.h" #include "money_frame.h" // for the finances #include "password_frame.h" // for the password #include "ai_selector.h" #include "player_frame.h" class password_button_t : public button_t { public: password_button_t() : button_t() { init(button_t::box, ""); } scr_size get_min_size() const OVERRIDE { return scr_size(D_BUTTON_HEIGHT,D_BUTTON_HEIGHT); } }; ki_kontroll_t::ki_kontroll_t() : gui_frame_t( translator::translate("Spielerliste") ) { set_table_layout(5,0); for(int i=0; iget_player(i); // activate player buttons // .. not available for the two first players (first human and second public) if( i >= 2 ) { // AI button (small square) player_active[i-2].init(button_t::square_state, ""); player_active[i-2].add_listener(this); player_active[i-2].set_rigid(true); add_component( player_active+(i-2) ); } else { new_component(); } // Player select button (arrow) player_change_to[i].init(button_t::arrowright_state, ""); player_change_to[i].add_listener(this); player_change_to[i].set_rigid(true); add_component(player_change_to+i); // Prepare finances button player_get_finances[i].init( button_t::box | button_t::flexible, ""); player_get_finances[i].background_color = PLAYER_FLAG | color_idx_to_rgb((player ? player->get_player_color1():i*8)+env_t::gui_player_color_bright); player_get_finances[i].add_listener(this); // Player type selector, Combobox player_select[i].set_focusable( false ); // add table that contains these two buttons, only one of them will be visible add_table(1,0); // When adding new players, activate the interface player_select[i].set_selection(welt->get_settings().get_player_type(i)); player_select[i].add_listener(this); add_component( player_get_finances+i ); add_component( player_select+i ); if( player != NULL ) { player_get_finances[i].set_text( player->get_name() ); player_select[i].set_visible(false); } else { player_get_finances[i].set_visible(false); } end_table(); // password/locked button player_lock[i] = new_component(); player_lock[i]->background_color = color_idx_to_rgb((player && player->is_locked()) ? (player->is_unlock_pending() ? COL_YELLOW : COL_RED) : COL_GREEN); player_lock[i]->add_listener(this); player_lock[i]->set_rigid(true); // Income label ai_income[i] = new_component(MONEY_PLUS, gui_label_t::money_right); ai_income[i]->set_rigid(true); } // freeplay mode freeplay.init( button_t::square_state, "freeplay mode"); freeplay.add_listener(this); freeplay.pressed = welt->get_settings().is_freeplay(); add_component( &freeplay, 5 ); update_data(); // calls reset_min_windowsize set_windowsize(get_min_windowsize()); } /** * This method is called if an action is triggered */ bool ki_kontroll_t::action_triggered( gui_action_creator_t *comp,value_t p ) { // Free play button? if( comp == &freeplay ) { welt->call_change_player_tool(karte_t::toggle_freeplay, 255, 0); return true; } // Check the GUI list of buttons for(int i=0; i=2 && comp == (player_active+i-2) ) { // switch AI on/off if( welt->get_player(i)==NULL ) { // create new AI welt->call_change_player_tool(karte_t::new_player, i, player_select[i].get_selection()); // if scripted ai without script -> open script selector window ai_scripted_t *ai = dynamic_cast(welt->get_player(i)); if (ai && !ai->has_script() && (!env_t::networkmode || env_t::server)) { create_win( new ai_selector_t(i), w_info, magic_finances_t + i ); } } else { // If turning on again, reload script if (!env_t::networkmode && !welt->get_player(i)->is_active()) { if (ai_scripted_t *ai = dynamic_cast(welt->get_player(i))) { ai->reload_script(); } } // Current AI on/off welt->call_change_player_tool(karte_t::toggle_player_active, i, !welt->get_player(i)->is_active()); } break; } // Finance button pressed if( comp == (player_get_finances+i) ) { // get finances player_get_finances[i].pressed = false; // if scripted ai without script -> open script selector window ai_scripted_t *ai = dynamic_cast(welt->get_player(i)); if (ai && !ai->has_script() && (!env_t::networkmode || env_t::server)) { create_win( new ai_selector_t(i), w_info, magic_finances_t + i ); } else { create_win( new money_frame_t(welt->get_player(i)), w_info, magic_finances_t + i ); } break; } // Changed active player if( comp == (player_change_to+i) ) { // make active player player_t *const prevplayer = welt->get_active_player(); welt->switch_active_player(i,false); // unlocked public service player can change into any company in multiplayer games player_t *const player = welt->get_active_player(); if( env_t::networkmode && prevplayer == welt->get_public_player() && !prevplayer->is_locked() && player->is_locked() ) { player->unlock(false, true); // send unlock command nwc_auth_player_t *nwc = new nwc_auth_player_t(); nwc->player_nr = player->get_player_nr(); network_send_server(nwc); } break; } // Change player name and/or password if( comp == (player_lock[i]) && welt->get_player(i) ) { if (!welt->get_player(i)->is_unlock_pending()) { // set password create_win(new password_frame_t(welt->get_player(i)), w_info, magic_pwd_t + i ); player_lock[i]->pressed = false; } } // New player assigned in an empty slot if( comp == (player_select+i) ) { // make active player if( p.i0 ) { player_active[i-2].set_visible(true); welt->get_settings().set_player_type(i, (uint8)p.i); } else { player_active[i-2].set_visible(false); player_select[i].set_selection(0); welt->get_settings().set_player_type(i, 0); } break; } } return true; } void ki_kontroll_t::update_data() { // switching active player allowed? bool player_change_allowed = welt->get_settings().get_allow_player_change() || !welt->get_public_player()->is_locked(); // activate player etc allowed? bool player_tools_allowed = true; // check also scenario rules if (welt->get_scenario()->is_scripted()) { player_tools_allowed = welt->get_scenario()->is_tool_allowed(NULL, TOOL_SWITCH_PLAYER | SIMPLE_TOOL); player_change_allowed &= player_tools_allowed; } freeplay.enable(); if (welt->get_public_player()->is_locked() || !welt->get_settings().get_allow_player_change() || !player_tools_allowed) { freeplay.disable(); } for(int i=0; iget_player(i) ) { player_select[i].set_visible(false); player_get_finances[i].set_visible(true); player_change_to[i].set_visible(player_change_allowed); player_lock[i]->set_visible(player_tools_allowed); // scripted ai without script get different button without color ai_scripted_t *ai = dynamic_cast(player); if (ai && !ai->has_script() && (!env_t::networkmode || env_t::server)) { player_get_finances[i].set_typ(button_t::roundbox | button_t::flexible); player_get_finances[i].set_text("Load Scripted AI"); } else { player_get_finances[i].set_typ(button_t::box | button_t::flexible); player_get_finances[i].set_text(player->get_name()); } // always update locking status player_get_finances[i].background_color = PLAYER_FLAG | color_idx_to_rgb(player->get_player_color1()+env_t::gui_player_color_bright); player_lock[i]->background_color = color_idx_to_rgb(player->is_locked() ? (player->is_unlock_pending() ? COL_YELLOW : COL_RED) : COL_GREEN); // human players cannot be deactivated if (i>1) { player_active[i-2].set_visible( player->get_ai_id()!=player_t::HUMAN && player_tools_allowed); } ai_income[i]->set_visible(true); } else { // inactive player => button needs removal? player_get_finances[i].set_visible(false); player_change_to[i].set_visible(false); player_select[i].set_visible(player_tools_allowed); player_lock[i]->set_visible(false); if (i>1) { player_active[i-2].set_visible(0 < player_select[i].get_selection() && player_select[i].get_selection() < player_t::MAX_AI); } // Create combobox list data int select = player_select[i].get_selection(); player_select[i].clear_elements(); player_select[i].new_component( translator::translate("slot empty"), SYSCOL_TEXT ) ; player_select[i].new_component( translator::translate("Manual (Human)"), SYSCOL_TEXT ) ; if( !welt->get_public_player()->is_locked() || !env_t::networkmode ) { player_select[i].new_component( translator::translate("Goods AI"), SYSCOL_TEXT ) ; player_select[i].new_component( translator::translate("Passenger AI"), SYSCOL_TEXT ) ; if (!env_t::networkmode || env_t::server) { // only server can start scripted players player_select[i].new_component( translator::translate("Scripted AI's"), SYSCOL_TEXT ) ; } } player_select[i].set_selection(select); assert( player_t::MAX_AI==5 ); ai_income[i]->set_visible(false); } } update_income(); reset_min_windowsize(); } void ki_kontroll_t::update_income() { // Update finance for(int i=0; ibuf().clear(); player_t *player = welt->get_player(i); if( player != NULL ) { if (i != 1 && !welt->get_settings().is_freeplay() && player->get_finance()->get_history_com_year(0, ATC_NETWEALTH) < 0) { ai_income[i]->set_color( MONEY_MINUS ); ai_income[i]->buf().append(translator::translate("Company bankrupt")); ai_income[i]->set_align(gui_label_t::left); } else { double account=player->get_account_balance_as_double(); char str[128]; money_to_string(str, account ); ai_income[i]->buf().append(str); ai_income[i]->set_color( account>=0.0 ? MONEY_PLUS : MONEY_MINUS ); ai_income[i]->set_align(gui_label_t::money_right); } } ai_income[i]->update(); } } /** * Draw the component */ void ki_kontroll_t::draw(scr_coord pos, scr_size size) { // Update free play freeplay.pressed = welt->get_settings().is_freeplay(); if (welt->get_public_player()->is_locked() || !welt->get_settings().get_allow_player_change()) { freeplay.disable(); } else { freeplay.enable(); } // Update finance update_income(); // Update buttons for(int i=0; iget_player(i); player_change_to[i].pressed = false; if(i>=2) { player_active[i-2].pressed = player !=NULL && player->is_active(); } player_lock[i]->background_color = color_idx_to_rgb(player && player->is_locked() ? (player->is_unlock_pending() ? COL_YELLOW : COL_RED) : COL_GREEN); } player_change_to[welt->get_active_player_nr()].pressed = true; // All controls updated, draw them... gui_frame_t::draw(pos, size); } simutrans-124.3/src/simutrans/gui/player_frame.h000066400000000000000000000034321474050137200217740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PLAYER_FRAME_H #define GUI_PLAYER_FRAME_H #include "../simconst.h" #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "simwin.h" /** * Menu for the player list */ class ki_kontroll_t : public gui_frame_t, private action_listener_t { private: gui_label_buf_t *ai_income[MAX_PLAYER_COUNT-1]; // Income labels button_t player_active[MAX_PLAYER_COUNT-2-1], // AI on/off button player_get_finances[MAX_PLAYER_COUNT-1], // Finance buttons player_change_to[MAX_PLAYER_COUNT-1], // Set active player button *player_lock[MAX_PLAYER_COUNT-1], // Set name & password button freeplay; gui_combobox_t player_select[MAX_PLAYER_COUNT-1]; void update_income(); public: ki_kontroll_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "players.txt";} /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; /** * Updates the dialogue window after changes to players states * called from tool_change_player_t::init * necessary for network games to keep dialogues synchronous */ void update_data(); // since no information are needed to be saved to restore this, returning magic is enough uint32 get_rdwr_id() OVERRIDE { return magic_ki_kontroll_t; } }; #endif simutrans-124.3/src/simutrans/gui/player_ranking_frame.cc000066400000000000000000000422631474050137200236500ustar00rootroot00000000000000/* * This file is part of the Simutrans-Extended project under the Artistic License. * (see LICENSE.txt) */ #include "../macros.h" #include "../simcolor.h" #include "../world/simworld.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../builder/wegbauer.h" #include "simwin.h" #include "money_frame.h" // for the finances #include "player_ranking_frame.h" uint8 player_ranking_frame_t::transport_type_option = TT_ALL; // Text should match that of the finance dialog static const char* cost_type_name[player_ranking_frame_t::MAX_PLAYER_RANKING_CHARTS] = { "Revenue", "Ops Profit", "Margin (%%)", "Passagiere", "Post", "Goods", "Cash", "Net Wealth", "Convoys", // "Vehicles", // "Stops" // "way_distances" // Way kilometrage // "travel_distance" }; static const uint8 cost_type[player_ranking_frame_t::MAX_PLAYER_RANKING_CHARTS] = { gui_chart_t::MONEY, gui_chart_t::MONEY, gui_chart_t::PERCENT, gui_chart_t::STANDARD, gui_chart_t::STANDARD, gui_chart_t::STANDARD, gui_chart_t::MONEY, gui_chart_t::MONEY, gui_chart_t::STANDARD }; static const uint8 cost_type_color[player_ranking_frame_t::MAX_PLAYER_RANKING_CHARTS] = { COL_REVENUE, COL_PROFIT, COL_MARGIN, COL_LIGHT_PURPLE, COL_TRANSPORTED, COL_BROWN, COL_CASH, COL_WEALTH, COL_NEW_VEHICLES }; // is_atv=1, ATV:vehicle finance record, ATC:common finance record static const uint8 history_type_idx[player_ranking_frame_t::MAX_PLAYER_RANKING_CHARTS * 2] = { 1,ATV_REVENUE, 1,ATV_OPERATING_PROFIT, 1,ATV_PROFIT_MARGIN, 1,ATV_TRANSPORTED_PASSENGER, 1,ATV_TRANSPORTED_MAIL, 1,ATV_TRANSPORTED_GOOD, 0,ATC_CASH, 0,ATC_NETWEALTH, 0,ATC_ALL_CONVOIS, // 1,ATV_VEHICLES, // 0,ATC_HALTS }; sint16 years_back = 1; static int compare_atv(uint8 player_nr_a, uint8 player_nr_b, uint8 atv_index) { sint64 comp = 0; // otherwise values may overflow player_t* a_player = world()->get_player(player_nr_a); player_t* b_player = world()->get_player(player_nr_b); if (a_player && b_player) { comp = b_player->get_finance()->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, years_back, atv_index) - a_player->get_finance()->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, years_back, atv_index); if (comp == 0 && years_back > 0) { // tie breaker: next year comp = b_player->get_finance()->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, years_back - 1, atv_index) - a_player->get_finance()->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, years_back - 1, atv_index); } } // if at least one if defined, it must go the the head of the list else if(a_player) { return true; } else if (b_player) { return false; } if (comp == 0) { comp = player_nr_b - player_nr_a; } return comp>0; // sort just test for larger than 0 } static int compare_atc(uint8 player_nr_a, uint8 player_nr_b, uint8 atc_index) { sint64 comp = 0; player_t* a_player = world()->get_player(player_nr_a); player_t* b_player = world()->get_player(player_nr_b); if (a_player && b_player) { comp = b_player->get_finance()->get_history_com_year(years_back, atc_index) - a_player->get_finance()->get_history_com_year(years_back, atc_index); if (comp == 0 && years_back > 0) { comp = b_player->get_finance()->get_history_com_year(years_back - 1, atc_index) - a_player->get_finance()->get_history_com_year(years_back - 1, atc_index); } } // if at least one if defined, it must go the the head of the list else if (a_player) { return true; } else if (b_player) { return false; } if (comp == 0) { comp = player_nr_b - player_nr_a; } return comp>0; } static int compare_revenue(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_REVENUE); } static int compare_profit(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_OPERATING_PROFIT); } static int compare_transport_pax(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_TRANSPORTED_PASSENGER); } static int compare_transport_mail(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_TRANSPORTED_MAIL); } static int compare_transport_goods(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_TRANSPORTED_GOOD); } static int compare_margin(player_button_t* const& a, player_button_t* const& b) { return compare_atv(a->get_player_nr(), b->get_player_nr(), ATV_PROFIT_MARGIN); } static int compare_cash(player_button_t* const& a, player_button_t* const& b) { return compare_atc(a->get_player_nr(), b->get_player_nr(), ATC_CASH); } static int compare_netwealth(player_button_t* const& a, player_button_t* const& b) { return compare_atc(a->get_player_nr(), b->get_player_nr(), ATC_NETWEALTH); } static int compare_convois(player_button_t* const& a, player_button_t* const& b) { return compare_atc(a->get_player_nr(), b->get_player_nr(), ATC_ALL_CONVOIS); } /* static int compare_halts(player_button_t* const& a, player_button_t* const& b) { return compare_atc(a->get_player_nr(), b->get_player_nr(), ATC_HALTS); } */ player_button_t::player_button_t(uint8 player_nr_) { player_nr = player_nr_; init(button_t::box_state | button_t::flexible, NULL, scr_coord(0, 0), D_BUTTON_SIZE); set_tooltip("Click to open the finance dialog."); update(); } void player_button_t::update() { player_t* player = world()->get_player(player_nr); if (player) { set_text(player->get_name()); background_color = color_idx_to_rgb(player->get_player_color1() + env_t::gui_player_color_bright); enable(); set_visible(true); } else { set_visible(false); disable(); } } player_ranking_frame_t::player_ranking_frame_t(uint8 selected_player_nr) : gui_frame_t(translator::translate("Player ranking")), scrolly(&cont_players, true, true) { selected_player = selected_player_nr; last_year = 0; // update on first drawing count = 0; set_table_layout(1, 0); add_table(2, 1)->set_alignment(ALIGN_TOP); { add_component(&chart); sint32 years_back = clamp(welt->get_last_year() - welt->get_settings().get_starting_year(), 2, MAX_PLAYER_HISTORY_YEARS); chart.set_dimension(years_back, 10000); chart.set_seed(welt->get_last_year()); chart.set_background(SYSCOL_CHART_BACKGROUND); for (int np = 0; np < MAX_PLAYER_COUNT; np++) { if (np == PLAYER_PUBLIC_NR) continue; if (welt->get_player(np)) { player_button_t* b = new player_button_t(np); b->add_listener(this); if (np == selected_player) { b->pressed = true; } buttons.append(b); } } add_table(2, 2); { years_back_c.new_component(translator::translate("This Year"), SYSCOL_TEXT); years_back_c.new_component(translator::translate("Last Year"), SYSCOL_TEXT); years_back_c.add_listener(this); years_back_c.set_selection(0); add_component(&years_back_c); for (int i = 0, count = 0; i < TT_OTHER; ++i) { transport_type_c.new_component(translator::translate(finance_t::transport_type_values[i]), SYSCOL_TEXT); transport_types[count++] = i; } transport_type_c.add_listener(this); transport_type_c.set_selection(0); transport_type_c.set_rigid(true); add_component(&transport_type_c); scrolly.set_maximize(true); scrolly.set_size_corner(false); add_component(&scrolly, 2); } end_table(); } end_table(); add_table(4, 0)->set_force_equal_columns(true); { for (uint8 i = 0; i < MAX_PLAYER_RANKING_CHARTS; i++) { bt_charts[i].init(button_t::roundbox_state | button_t::flexible, cost_type_name[i]); bt_charts[i].background_color = color_idx_to_rgb(cost_type_color[i]); if (i == selected_item) bt_charts[i].pressed = true; bt_charts[i].add_listener(this); add_component(&bt_charts[i]); } } end_table(); update_chart(true); set_windowsize(get_min_windowsize()); set_resizemode(diagonal_resize); } player_ranking_frame_t::~player_ranking_frame_t() { while (!buttons.empty()) { player_button_t* b = buttons.remove_first(); cont_players.remove_component(b); delete b; } } static int (*compare_function[player_ranking_frame_t::MAX_PLAYER_RANKING_CHARTS])(player_button_t* const& a, player_button_t* const& b) = { compare_revenue,//ATV_REVENUE, compare_profit,//ATV_OPERATING_PROFIT, compare_margin,//ATV_PROFIT_MARGIN, compare_transport_pax,//ATV_TRANSPORTED_PASSENGER, compare_transport_mail,//ATV_TRANSPORTED_MAIL, compare_transport_goods,//ATV_TRANSPORTED_GOOD, compare_cash,//ATC_CASH, compare_netwealth,//ATC_NETWEALTH, compare_convois//ATC_ALL_CONVOIS, // 1,ATV_VEHICLES, // 0,ATC_HALTS }; bool player_ranking_frame_t::is_chart_table_zero(uint8 player_nr) const { // search for any non-zero values if (player_t* player = welt->get_player(player_nr)) { const finance_t* finance = player->get_finance(); const bool is_atv = history_type_idx[selected_item * 2]; for (int y = 0; y < MAX_PLAYER_HISTORY_MONTHS; y++) { sint64 val = is_atv ? finance->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, y, history_type_idx[selected_item * 2 + 1]) : finance->get_history_com_year(y, history_type_idx[selected_item * 2 + 1]); if (val) return false; } } return true; } /** * This method is called if an action is triggered */ bool player_ranking_frame_t::action_triggered(gui_action_creator_t* comp, value_t v) { // Check the GUI list of buttons // player filter for (auto bt : buttons) { if (comp == bt) { if (player_t* p = welt->get_player(bt->get_player_nr())) { create_win(new money_frame_t(p), w_info, magic_finances_t + p->get_player_nr()); } return true; } } // chart selector for (uint8 i = 0; i < MAX_PLAYER_RANKING_CHARTS; i++) { if (comp == &bt_charts[i]) { if (bt_charts[i].pressed) { // nothing to do return true; } selected_item = i; update_chart(true); return true; } } if (comp == &years_back_c) { update_chart(true); return true; } if (comp == &transport_type_c) { if (v.i > 0) { transport_type_option = (uint8)v.i; transport_type_option = transport_types[v.i]; update_chart(true); } else { transport_type_option = TT_ALL; } return true; } return true; } void player_ranking_frame_t::update_chart(bool full_update) { if (years_back == 0) { // first update player finances if in the current year for (int np = 0; np < MAX_PLAYER_COUNT - 1; np++) { if (player_t* player = welt->get_player(np)) { player->get_finance()->calc_finance_history(); } } } // check if we have to upgrade to full update if (!full_update) { // check order full_update |= buttons.sort(compare_function[selected_item]); // check if the number of entries changed uint8 new_count = 0; for (uint i = 0; i < buttons.get_count(); i++) { const uint8 player_nr = buttons.at(i)->get_player_nr(); // Exclude players who are not in the competition if (player_nr == PLAYER_PUBLIC_NR || is_chart_table_zero(player_nr)) { continue; } new_count++; } full_update |= count != new_count; } // deselect chart buttons for (uint8 i = 0; i < MAX_PLAYER_RANKING_CHARTS; i++) { bt_charts[i].pressed = i == selected_item; } // rebuilt list if (full_update) { cont_players.remove_all(); cont_players.set_table_layout(3, 0); cont_players.set_alignment(ALIGN_CENTER_H); cont_players.set_margin(scr_size(0, 0), scr_size(D_SCROLLBAR_WIDTH + D_H_SPACE, D_SCROLLBAR_HEIGHT)); count = 0; for (uint i = 0; i < buttons.get_count(); i++) { const uint8 player_nr = buttons.at(i)->get_player_nr(); // Exclude players who are not in the competition if (player_nr == PLAYER_PUBLIC_NR || is_chart_table_zero(player_nr)) { continue; } count++; switch (count) { case 1: cont_players.new_component("1", color_idx_to_rgb(COL_YELLOW), gui_label_t::centered); break; case 2: cont_players.new_component("2", 0, gui_label_t::centered); break; case 3: cont_players.new_component("3", 0, gui_label_t::centered); break; default: gui_label_buf_t* lb = cont_players.new_component(SYSCOL_TEXT, gui_label_t::centered); lb->buf().printf("%u", count); lb->update(); lb->set_min_width(lb->get_min_size().w); break; } if (player_nr != selected_player) { buttons.at(i)->pressed = false; } cont_players.add_component(buttons.at(i)); cont_players.add_component(&lb_player_val[i]); } cont_players.new_component_span(1,1,3); } const bool is_atv = history_type_idx[selected_item * 2]; sint32 chart_years_back = clamp(welt->get_last_year() - welt->get_settings().get_starting_year(), 2, MAX_PLAYER_HISTORY_YEARS); if (full_update) { chart.set_dimension(chart_years_back, 10000); // need to clear the chart once to update the suffix and digit chart.remove_curves(); for (int np = 0; np < MAX_PLAYER_COUNT - 1; np++) { if (np == PLAYER_PUBLIC_NR) continue; if (player_t* player = welt->get_player(np)) { if (is_chart_table_zero(np)) { continue; } // create chart const int curve_type = (int)cost_type[selected_item]; const int curve_precision = (curve_type == gui_chart_t::STANDARD) ? 0 : (curve_type == gui_chart_t::MONEY || curve_type == gui_chart_t::PERCENT) ? 2 : 1; // gui_chart_t::chart_marker_t marker = (np==selected_player) ? gui_chart_t::square : gui_chart_t::none; chart.add_curve(color_idx_to_rgb(player->get_player_color1() + 3), *p_chart_table, MAX_PLAYER_COUNT - 1, np, chart_years_back, curve_type, true, false, curve_precision, NULL); } } for (int np = 0; np < MAX_PLAYER_COUNT - 1; np++) { if (player_t* player = welt->get_player(np)) { // update chart records for (int y = 0; y < chart_years_back; y++) { const finance_t* finance = player->get_finance(); p_chart_table[y][np] = is_atv ? finance->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, y, history_type_idx[selected_item * 2 + 1]) : finance->get_history_com_year(y, history_type_idx[selected_item * 2 + 1]); } chart.show_curve(np); } } } // update labels years_back = clamp(years_back_c.get_selection(), 0, chart_years_back); scr_size cont_min_sz = cont_players.get_min_size(); for (uint i = 0; i < buttons.get_count(); i++) { const uint8 player_nr = buttons.at(i)->get_player_nr(); // Exclude players who are not in the competition if (player_nr == PLAYER_PUBLIC_NR || is_chart_table_zero(player_nr)) { continue; } if (player_nr != selected_player) { buttons.at(i)->pressed = false; } const finance_t* finance = welt->get_player(player_nr)->get_finance(); PIXVAL color = SYSCOL_TEXT; sint64 value = is_atv ? finance->get_history_veh_year((transport_type)player_ranking_frame_t::transport_type_option, years_back, history_type_idx[selected_item * 2 + 1]) : finance->get_history_com_year(years_back, history_type_idx[selected_item * 2 + 1]); switch (cost_type[selected_item]) { case gui_chart_t::MONEY: lb_player_val[i].buf().append_money(value / 100.0); color = value >= 0 ? (value > 0 ? MONEY_PLUS : SYSCOL_TEXT_UNUSED) : MONEY_MINUS; break; case gui_chart_t::PERCENT: lb_player_val[i].buf().append(value / 100.0, 2); lb_player_val[i].buf().append("%"); color = value >= 0 ? (value > 0 ? MONEY_PLUS : SYSCOL_TEXT_UNUSED) : MONEY_MINUS; break; case gui_chart_t::STANDARD: default: lb_player_val[i].buf().append(value, 0); break; } lb_player_val[i].set_color(color); lb_player_val[i].set_align(gui_label_t::right); lb_player_val[i].update(); } transport_type_c.set_visible(is_atv); scrolly.set_visible(count > 0); if (full_update || cont_min_sz!=cont_players.get_min_size()) { resize(scr_size(0, 0)); reset_min_windowsize(); } } void player_ranking_frame_t::draw(scr_coord pos, scr_size size) { if (last_year != world()->get_last_year()) { // new year has started: last_year = world()->get_last_year(); sint32 years_back = clamp(last_year - welt->get_settings().get_starting_year(), 2, MAX_PLAYER_HISTORY_YEARS); // rebuilt year list sint32 sel = years_back_c.get_selection(); years_back_c.clear_elements(); years_back_c.new_component(translator::translate("This Year"), SYSCOL_TEXT); years_back_c.new_component(translator::translate("Last Year"), SYSCOL_TEXT); for (int i = 1; i < years_back; i++) { sprintf(years_back_s[i - 1], "%i", last_year - i - 1); years_back_c.new_component(years_back_s[i - 1], SYSCOL_TEXT); } chart.set_seed(last_year); years_back_c.set_selection(sel <= 0 ? 0 : (sel == 1 ? 1 : sel + 1)); update_chart(true); } else { update_chart(false); } gui_frame_t::draw(pos, size); } void player_ranking_frame_t::rdwr(loadsave_t* file) { transport_type_c.rdwr(file); years_back_c.rdwr(file); file->rdwr_byte(selected_item); if (file->is_loading()) { last_year = world()->get_last_year(); chart.set_seed(last_year); update_chart(true); } scrolly.rdwr(file); } simutrans-124.3/src/simutrans/gui/player_ranking_frame.h000066400000000000000000000043261474050137200235100ustar00rootroot00000000000000/* * This file is part of the Simutrans-Extended project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PLAYER_RANKING_GUI_H #define GUI_PLAYER_RANKING_GUI_H #include "gui_frame.h" #include "../player/finance.h" #include "components/gui_label.h" #include "components/gui_chart.h" #include "components/gui_button.h" #include "components/action_listener.h" #include "simwin.h" #include "../tpl/vector_tpl.h" #include "../utils/cbuffer.h" class player_button_t : public button_t { uint8 player_nr; public: player_button_t(uint8 player_nr); // set color and name void update(); uint8 get_player_nr() const { return player_nr; } }; /** * Menu for the player list */ class player_ranking_frame_t : public gui_frame_t, private action_listener_t { public: enum { PR_REVENUE, PR_PROFIT, PR_MARGIN, PR_TRANSPORT_PAX, PR_TRANSPORT_MAIL, PR_TRANSPORT_GOODS, PR_CASH, PR_NETWEALTH, PR_CONVOIS, // PR_VEHICLES, // PR_HALTS, MAX_PLAYER_RANKING_CHARTS }; static uint8 transport_type_option; private: sint16 last_year; gui_chart_t chart; gui_aligned_container_t cont_players; gui_scrollpane_t scrolly; button_t bt_charts[MAX_PLAYER_RANKING_CHARTS]; char years_back_s[MAX_PLAYER_HISTORY_YEARS][5]; gui_combobox_t years_back_c, transport_type_c; uint16 transport_types[TT_OTHER]; gui_label_buf_t lb_player_val[MAX_PLAYER_COUNT-1]; sint64 p_chart_table[MAX_PLAYER_HISTORY_YEARS][MAX_PLAYER_COUNT-1]; slist_tpl buttons; uint8 selected_item= PR_REVENUE; uint8 selected_player; uint8 count; bool is_chart_table_zero(uint8 player_nr) const; public: player_ranking_frame_t(uint8 selected_player_nr=255); ~player_ranking_frame_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "player_ranking.txt"; } void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void update_chart(bool full_update); // since no information are needed to be saved to restore this, returning magic is enough uint32 get_rdwr_id() OVERRIDE { return magic_player_ranking; } void rdwr(loadsave_t* file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/privatesign_info.cc000066400000000000000000000042141474050137200230310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "privatesign_info.h" #include "components/gui_label.h" #include "../obj/roadsign.h" #include "../player/simplay.h" #include "../tool/simmenu.h" #include "../world/simworld.h" privatesign_info_t::privatesign_info_t(roadsign_t* s) : obj_infowin_t(s), sign(s) { uint16 mask = sign->get_player_mask(); for( int i=0; iget_player(i) ) { players[i].init( button_t::square_state, welt->get_player(i)->get_name()); players[i].add_listener( this ); } else { players[i].init( button_t::square_state, ""); players[i].disable(); } players[i].pressed = mask & (1<get_desc()->get_copyright()) { gui_label_buf_t* lb = new_component(); lb->buf().printf(translator::translate("Constructed by %s"), maker); lb->update(); } recalc_size(); } /** * This method is called if an action is triggered * * Returns true, if action is done and no more * components should be triggered. */ bool privatesign_info_t::action_triggered( gui_action_creator_t *comp, value_t /* */) { if( welt->get_active_player() == sign->get_owner() ) { char param[256]; for( int i=0; iget_player_mask(); mask ^= (1 << i); // change active player mask for this private sign if( i<8 ) { sprintf( param, "%s,2,%u", sign->get_pos().get_str(), mask & 0x00FF ); } else { sprintf( param, "%s,0,%u", sign->get_pos().get_str(), mask >> 8 ); } tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT]->set_default_param( param ); welt->set_tool( tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT], welt->get_active_player() ); players[i].pressed = (mask >> i)&1; } } } return true; } // notify for an external update void privatesign_info_t::update_data() { uint16 mask = sign->get_player_mask(); for( int i=0; i> i)&1; } } simutrans-124.3/src/simutrans/gui/privatesign_info.h000066400000000000000000000015651474050137200227010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_PRIVATESIGN_INFO_H #define GUI_PRIVATESIGN_INFO_H #include "../simconst.h" #include "obj_info.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_container.h" class roadsign_t; /** * Info window for factories */ class privatesign_info_t : public obj_infowin_t, public action_listener_t { private: roadsign_t* sign; button_t players[PLAYER_UNOWNED]; public: privatesign_info_t(roadsign_t* s); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "privatesign_info.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // called, after external change void update_data(); }; #endif simutrans-124.3/src/simutrans/gui/savegame_frame.cc000066400000000000000000000417401474050137200224320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "savegame_frame.h" #include "../pathes.h" #include "../sys/simsys.h" #include "../simdebug.h" #include "simwin.h" #include "../utils/simstring.h" #include "../utils/searchfolder.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "banner.h" #define L_DEFAULT_ROWS (12) // Number of file entries to show as default #define L_SHORTENED_SIZE (48) /** * Small helper class for tiny 'X' delete buttons */ class del_button_t : public button_t { scr_coord_val w; public: del_button_t() : button_t() { init(button_t::roundbox, "X"); w = max(D_BUTTON_HEIGHT, display_get_char_width('X') + D_BUTTON_PADDINGS_X); } scr_size get_min_size() const OVERRIDE { return scr_size(w, D_BUTTON_HEIGHT); } }; /** * @param suffix Optional file pattern to populate the file list. * Example ".sve" or "sve" * Default value is NULL to disregard extension. * @param only_directories Populate the file list with only directories. This is * optional with a default value of false. * @param path Optional search path. If null next call to add_path() * defines the deefault path. Default value is NULL. * @param delete_enabled Show (true) or hide (false) the delete buttons. * This is an optional parameter with a default value of true. * @param back_to_menu */ savegame_frame_t::savegame_frame_t(const char *suffix, bool only_directories, const char *path, const bool delete_enabled, bool back_to_menu) : gui_frame_t( translator::translate("Load/Save") ), suffix(suffix), in_action(false), only_directories(only_directories), searchpath_defined(false), input(), fnlabel("Filename"), scrolly(&button_frame, true), num_sections(0), delete_enabled(delete_enabled) { is_back_to_menu = back_to_menu; set_table_layout(1,0); label_enabled = true; // Filename input top_frame.set_table_layout(2,0); add_component(&top_frame); { top_frame.add_component(&fnlabel); tstrncpy(ibuf, "", lengthof(ibuf)); input.set_text(ibuf, 128); top_frame.add_component(&input); } // Needs to be scrollable, size is adjusted in set_windowsize() scrolly.set_scroll_amount_y(D_BUTTON_HEIGHT + D_FOCUS_OFFSET_V); scrolly.set_size_corner(false); add_component(&scrolly); scrolly.set_maximize(true); // Controls below will be sized and positioned in set_windowsize() new_component(); add_component(&bottom_left_frame); bottom_left_frame.set_table_layout(1,0); add_table(3, 1)->set_force_equal_columns(true); { new_component(); savebutton.init(button_t::roundbox | button_t::flexible, "Ok"); savebutton.add_listener(this); add_component(&savebutton); cancelbutton.init(button_t::roundbox | button_t::flexible, "Cancel"); cancelbutton.add_listener(this); add_component(&cancelbutton); } end_table(); top_frame.set_focus( &input ); set_focus(&top_frame); if(this->suffix == NULL) { this->suffix = ""; } if(path != NULL) { this->add_path(path); // needed? dr_mkdir(path); } set_resizemode(diagonal_resize); } /** * Free all list items. */ savegame_frame_t::~savegame_frame_t() { for(dir_entry_t const& i : entries) { if(i.button) { delete [] const_cast(i.button->get_text()); delete i.button; } if(i.label) { char *tooltip = const_cast(i.label->get_tooltip_pointer()); delete [] tooltip; delete [] const_cast(i.label->get_text_pointer()); delete i.label; } delete i.del; delete [] i.info; } this->paths.clear(); } /** * Adds a section entry to the list... * * @param name Section name?!? */ void savegame_frame_t::add_section(std::string &name){ const char *prefix_label = translator::translate("Files from:"); size_t prefix_len = strlen(prefix_label); // NOTE: These char buffers will be freed on the destructor // +2 because of the space in printf and the ending \0 char *label_text = new char [L_SHORTENED_SIZE+prefix_len+2]; char *path_expanded = new char[FILENAME_MAX]; const size_t data_dir_len = strlen(env_t::base_dir); if( name[0]=='/' || name[0]=='\\' || name[1]==':' || strncmp(name.c_str(),env_t::base_dir,data_dir_len) == 0 ) { // starts with data_dir or an absolute path tstrncpy(path_expanded, name.c_str(), FILENAME_MAX); } else { // user_dir path size_t name_len = strlen(name.c_str()); size_t user_dir_len = strlen(env_t::user_dir); if ( name_len+user_dir_len > FILENAME_MAX-1 ) { // shouldn't happen, but I'll control anyway strcpy(path_expanded,"** ERROR ** Path too long"); } else { sprintf(path_expanded,"%s%s", env_t::user_dir, name.c_str()); } } cleanup_path(path_expanded); char shortened_path[L_SHORTENED_SIZE+1]; shorten_path(shortened_path,path_expanded,L_SHORTENED_SIZE); sprintf(label_text,"%s %s", prefix_label , shortened_path); gui_label_t* l = new gui_label_t(NULL, SYSCOL_TEXT_HIGHLIGHT); l->set_text_pointer(label_text); l->set_tooltip(path_expanded); this->entries.append(dir_entry_t(NULL, NULL, l, LI_HEADER, NULL)); this->num_sections++; } /** * Adds a path to the list of path included in the file search. * Several paths can be added one at a time. All added paths will * be searched by fill_list(). * * @param path A nul terminated path to include in the search. */ void savegame_frame_t::add_path(const char * path) { if (!this->searchpath_defined) { sprintf(this->searchpath, "%s", path); this->searchpath_defined = true; } this->paths.append(path); } /** * Populates the item list with matching file names. Each matching file * is first checked (check_file) and then added (add_file). */ void savegame_frame_t::fill_list( void ) { const char *suffixnodot; searchfolder_t sf; char *fullname; bool not_cutting_extension = (suffix==NULL || suffix[0]!='.'); if( suffix == NULL ){ suffixnodot = NULL; } else { suffixnodot = (suffix[0] == '.') ?suffix+1 : suffix; } // for each path, we search. for(std::string &path : paths){ const char *path_c = path.c_str(); const size_t path_c_len = strlen(path_c); const searchfolder_t::search_flags_t search_flags = this->only_directories ? searchfolder_t::SF_ONLYDIRS : searchfolder_t::SF_NONE; sf.search(path, std::string(suffixnodot), search_flags, false); bool section_added = false; // Add the entries that pass the check for(const char* const &name : sf) { fullname = new char [path_c_len+strlen(name)+1]; sprintf(fullname,"%s%s",path_c,name); if( check_file(fullname, suffix) ){ if(!section_added) { add_section(path); section_added = true; } add_file(fullname, name, get_info(fullname), not_cutting_extension); } else { // NOTE: we just free "fullname" memory when add_file is not called. That memory will be // freed in the class destructor. This way we save the cost of re-allocate/copy it inside there delete [] fullname; } } } } /** * All items has been inserted in the list. * On return resize() is called and all item's GYU members are positioned and resized. * Therefore it is no use to set the button's and label's width or any items y position. * The only control keeping its size is the delete button. */ void savegame_frame_t::list_filled( void ) { uint cols = (delete_enabled ? 1 : 0) + 1 + (label_enabled ? 1 : 0); button_frame.set_table_layout(1,0); button_frame.add_table(cols,0)->set_spacing(scr_size(D_H_SPACE,D_FILELIST_V_SPACE)); // less vertical spacing between entries to see more of them on screen button_t *pressed_button = NULL; for(dir_entry_t const& i : entries) { button_t* const delete_button = i.del; button_t* const action_button = i.button; gui_label_t* const label = i.label; if(i.type == LI_HEADER) { if(this->num_sections < 2) { // If just 1 section added, we won't print the header label->set_visible(false); continue; } button_frame.add_component(label, cols); } else { if (dr_cantrash()) { delete_button->set_tooltip("Send this file to the system trash bin. SHIFT+CLICK to permanently delete."); } else { delete_button->set_tooltip("Delete this file."); } delete_button->add_listener(this); action_button->add_listener(this); if (delete_enabled) { button_frame.add_component(delete_button); } button_frame.add_component(action_button); if (label_enabled) { button_frame.add_component(label); } if (pressed_button == NULL && action_button->pressed) { pressed_button = action_button; } } } button_frame.end_table(); const scr_coord_val row_height = max( D_LABEL_HEIGHT, D_BUTTON_HEIGHT ) + D_V_SPACE; reset_min_windowsize(); scr_size size = get_min_size() + scr_size(0, min(entries.get_count(), L_DEFAULT_ROWS) * row_height); // TODO do something smarter here size.w = max(size.w, button_frame.get_min_size().w + D_SCROLLBAR_WIDTH); set_windowsize(size); if (pressed_button) { scrolly.set_scroll_position(0, max(0, pressed_button->get_pos().y - 2 * D_BUTTON_HEIGHT) ); } } /** * Check if a file name qualifies to be added to he item list. * * @param filename The found file name * @param suffix Suffix pattern to match. If this is NULL * all filenames qualifies. * * @retval true The filename qualified and will be added. * @retval false This file doesn't qualify, don't add. */ bool savegame_frame_t::check_file(const char *filename, const char *suffix) { // assume truth, if there is no pattern to compare return suffix==NULL || suffix[0]==0 || (strncmp(filename+strlen(filename)-4, suffix, 4)== 0); } /** * Create and add a list item from the given parameters. The button is set * to the filename, the label to the string returned by get_info(). * * @param fullpath The full path to associate with this item. * @param filename The file name to assign the action button (i.button). * @param info Information to set in the label. * @param no_cutting_suffix Keep the suffix (true) in the file name. */ void savegame_frame_t::add_file(const char *fullpath, const char *filename, const char *info, const bool no_cutting_suffix) { button_t *button = new button_t(); char *name = new char[strlen(filename)+10]; char *text = new char[strlen(info)+1]; strcpy(text, info); strcpy(name, filename); if(!no_cutting_suffix) { name[strlen(name)-4] = '\0'; } button->set_typ( button_t::roundbox | button_t::flexible); button->set_no_translate(true); button->set_text(name); // to avoid translation std::string const compare_to = !env_t::pak_name.empty() ? env_t::pak_name.substr(0, env_t::pak_name.size() - 1) + " -" : std::string(); // sort descending with respect to compare_items slist_tpl::iterator i = entries.begin(); slist_tpl::iterator end = entries.end(); // This needs optimizing, advance to the last section, since inserts come always to the last section, we could just update last one on last_section slist_tpl::iterator lastfound; while(i != end) { if(i->type == LI_HEADER) { lastfound = i; } i++; } i = ++lastfound; // END of optimizing if(!strstart(info, compare_to.c_str())) { // skip current ones while(i != end) { // extract pakname in same format than in savegames ... if(!strstart(i->label->get_text_pointer(), compare_to.c_str())) { break; } ++i; } // now sort with respect to label on button or info text (ie date) while(i != end) { if( compare_items(*i, text, name ) ) { break; } ++i; } } else { // Insert to our games (or in front if none) while(i != end) { if(i->type == LI_HEADER) { ++i; continue; } if(compare_items( *i, text, name ) ) { break; } // not our savegame any more => insert if(!strstart(i->label->get_text_pointer(), compare_to.c_str())) { break; } ++i; } } gui_label_t* l = new gui_label_t(NULL); l->set_text_pointer(text); entries.insert(i, dir_entry_t(button, new del_button_t(), l, LI_ENTRY, fullpath)); } /** * This dialogue's message event handler. The enter key is dispateched as * an action button click event. The WIN_OPEN event starts to fill the file * list if it is empty. * * @param event The received event message. * * @retval true Stop event propagation. * @retval false Continue event propagation. */ bool savegame_frame_t::infowin_event(const event_t *event) { if(event->ev_class == INFOWIN && event->ev_code == WIN_OPEN && entries.empty()) { // before no virtual functions can be used ... fill_list(); // Notify of the end list_filled(); } if( event->ev_class == EVENT_KEYBOARD && event->ev_code == 13 ) { action_triggered(&input, (long)0); return true; // swallowed } return gui_frame_t::infowin_event(event); } /** * Click event handler and dispatcher. This function is called * every time a button is clicked and the corresponding handler * is called from here. * * @param component The component that was clicked. * * @retval true This function always returns true to stop * the event propagation. */ bool savegame_frame_t::action_triggered(gui_action_creator_t *component, value_t ) { char buf[PATH_MAX] = {}; if(component==&input || component==&savebutton) { // Save/Load Button or Enter-Key pressed //--------------------------------------- if(strstart(ibuf, "net:")) { tstrncpy(buf, ibuf, lengthof(buf)); } else { if(searchpath_defined) { tstrncpy(buf, searchpath, lengthof(buf)); } else { buf[0] = 0; } strcat(buf, ibuf); if(suffix) { strcat(buf, suffix); } } ok_action(buf); destroy_win(this); } else if(component == &cancelbutton) { // Cancel-button pressed //---------------------------- cancel_action(buf); if(is_back_to_menu) { banner_t::show_banner(); } destroy_win(this); } else { // File in list selected //-------------------------- for(dir_entry_t const& i : entries) { if(in_action){ break; } if(component==i.button || component==i.del) { in_action = true; bool const action_btn = component == i.button; if(action_btn) { if(item_action(i.info)) { destroy_win(this); } } else { if(del_action(i.info)) { destroy_win(this); } else { // do not delete components // simply hide them i.button->set_visible(false); i.del->set_visible(false); i.label->set_visible(false); resize(scr_coord(0, 0)); } } in_action = false; break; } } } return true; } /** * Generic delete button click handler. This will delete the * item from the storage media. If the system supports a * trash bin, the file is moved over there instead of being deleted. * A shift + Delete always deletes the file imediatly * * @param fullpath Full path to the file being deleted. * * @retval false This function always return false to prevent the * dialogue from being closed. */ bool savegame_frame_t::del_action(const char *fullpath) { if (!dr_cantrash() || event_get_last_control_shift() & 1) { // shift pressed, delete without trash bin dr_remove(fullpath); return false; } dr_movetotrash(fullpath); return false; } /** * Sets the current filename in the input box * * @param file_name A nul terminated string to assign the edit control. */ void savegame_frame_t::set_filename(const char *file_name) { size_t len = strlen(file_name); if(len>=4 && len-SAVE_PATH_X_LEN-3<128) { if(strstart(file_name, SAVE_PATH_X)) { tstrncpy(ibuf, file_name+SAVE_PATH_X_LEN, len-SAVE_PATH_X_LEN-3 ); } else { tstrncpy(ibuf, file_name, len-3); } input.set_text(ibuf, 128); } } /** * ONLY WIN32 * Translates all / into \ in a given path string. If a drive * letter is present it is translated to upper case * * @param path A pointer to the path string. This string is modified. */ void savegame_frame_t::cleanup_path(char *path) { #ifdef _WIN32 char *p = path; while (*(p++) != '\0'){ if(*p == '/') { *p='\\'; } } if ( strlen(path)>2 && path[1]==':' ) { path[0] = (char) toupper(path[0]); } #else (void)path; #endif } /** * Outputs a truncated path by replacing the middle portion with "..." * * @param dest Destination string. * @param source Nul terminated source string to parse. * @param max_size Truncate the string to this number of characters. */ void savegame_frame_t::shorten_path(char *dest,const char *source,const size_t max_size) { assert (max_size > 2); const size_t orig_size = strlen(source); if ( orig_size <= max_size ) { strcpy(dest,source); return; } const int half = max_size/2; const int odd = max_size%2; strncpy(dest,source,half-1); memcpy(&dest[half-1],"...",sizeof(char) * 3); strcpy(&dest[half+2],&source[orig_size-half+2-odd]); } bool savegame_frame_t::compare_items ( const dir_entry_t & entry, const char *, const char *name ) { return (strcmp(name, entry.button->get_text()) < 0); } simutrans-124.3/src/simutrans/gui/savegame_frame.h000066400000000000000000000132271474050137200222730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SAVEGAME_FRAME_H #define GUI_SAVEGAME_FRAME_H #include #include #include "../utils/simstring.h" #include "gui_frame.h" #include "../tpl/slist_tpl.h" #include "../tpl/vector_tpl.h" #include "components/action_listener.h" #include "components/gui_container.h" #include "components/gui_scrollpane.h" #include "components/gui_textinput.h" #include "components/gui_divider.h" #include "components/gui_label.h" #include "components/gui_button.h" class loadfont_frame_t; /** * Base class from which all GUI dialogs to load/save generics can inherit from * @note When I refer to a "qualified" path I mean it can contain sub-directories or even fully qualified path. i.e. : "save/a.sve" or "c:\simutrans\scenario\file.nut" */ class savegame_frame_t : public gui_frame_t, public action_listener_t { friend class loadfont_frame_t; private: vector_tpl paths; //@< Paths in which this dialog will search for const char *suffix; //@< Extension of the files this dialog will use, can be NULL Can include or not the "." at start, will work on both cases char ibuf[PATH_MAX]; //@< Input buffer for the text input component char searchpath[PATH_MAX]; //@< Default search path bool in_action; //@< To avoid double mouse action bool only_directories; //@< Search for directories (used in pak_selector) bool searchpath_defined; //@< Is default path defined? bool is_back_to_menu; //@< Open the banner menu on cancel void add_section(std::string &name); protected: /** * Entries in list can be actual file entries or * headers, that have a different look. */ enum dirlist_item_t { LI_HEADER, //@< This is a header list item. LI_ENTRY //@< This is a data list item. }; /** * A list item. * Max Kielland: Shouldn't this be an ADT and then have * each derivate to define their own item class? This would also * take care of differences, sorting and freeing resources. */ struct dir_entry_t { dir_entry_t(button_t* button_, button_t* del_, gui_label_t* label_, dirlist_item_t type_ = LI_ENTRY, const char *info_=NULL) : del(del_), button(button_), label(label_), type(type_), info(info_) {} button_t *del; //@< Delete button placed in the first column. button_t *button; //@< Action button placed in the second column. gui_label_t *label; //@< Label placed in the third column. dirlist_item_t type; //@< Item type, data or header. const char *info; //@< A qualified path (might be relative) to the file, not just the name static int compare (const dir_entry_t & l, const dir_entry_t &r) { if (( NULL == l.info ) && ( NULL != r.info )) { return -1; } if (( NULL == r.info ) && ( NULL != l.info )) { return 1; } if (( NULL != l.info ) && ( NULL != r.info )) { return strcmp ( l.info, r.info ); } return 0; } }; // Standard GUI controls in dialogue gui_textinput_t input; //@< Filename input field button_t savebutton; //@< Save button button_t cancelbutton; //@< Cancel button gui_label_t fnlabel; //@< Static file name label gui_aligned_container_t top_frame, //@< Contains input field bottom_left_frame, //@< container for elements on the left of the last row button_frame; //@< Gui container for all items gui_scrollpane_t scrolly; //@< Scroll panel for the GUI container slist_tpl entries; //@< Internal list representing the file listing uint32 num_sections; //@< Internal counter representing the number of sections added to the list bool delete_enabled; //@< Show the first column of delete buttons. bool label_enabled; //@< Show the third column of labels. void add_file ( const char *path, const char *filename, const char *pak, const bool no_cutting_suffix ); void add_path ( const char *path ); void set_filename ( const char *file_name ); void set_extension( const char *ext ) { suffix = ext; } void cleanup_path ( char *path ); void shorten_path ( char *dest, const char *source, const size_t max_size ); void list_filled ( void ); virtual void fill_list ( void ); // compare item to another with info and filename virtual bool compare_items ( const dir_entry_t & entry, const char *info, const char *filename ); // Virtual callback function that will be executed when the user clicks ok, virtual bool cancel_action ( const char * /*fullpath*/ ) { return true; } // Callback for cancel button click virtual bool del_action ( const char * fullpath ); // Callback for delete button click virtual bool ok_action ( const char * /*fullpath*/ ) { return true; } // Callback for ok button click virtual bool check_file ( const char *filename, const char *suffix ); // Pure virtual functions virtual const char *get_info ( const char *fname ) = 0; virtual bool item_action ( const char *fullpath ) = 0; public: savegame_frame_t(const char *suffix, bool only_directorie, const char *path, const bool delete_enabled = true, const bool back_to_menu = false ); // savegame_frame_t(const char *suffix = NULL, bool only_directories = false, const char *path = NULL, const bool delete_enabled = true); virtual ~savegame_frame_t(); bool action_triggered ( gui_action_creator_t*, value_t ) OVERRIDE; bool infowin_event ( event_t const* ) OVERRIDE; sint16 get_entries_count () { return entries.get_count(); } ; }; #endif simutrans-124.3/src/simutrans/gui/scenario_frame.cc000066400000000000000000000041431474050137200224410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../sys/simsys.h" #include "scenario_frame.h" #include "scenario_info.h" #include "messagebox.h" #include "simwin.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "../dataobj/environment.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../network/network.h" #include "../network/network_cmd.h" #include "../utils/cbuffer.h" scenario_frame_t::scenario_frame_t() : savegame_frame_t(NULL, true, NULL, false, true) { static cbuffer_t pakset_scenario; static cbuffer_t addons_scenario; pakset_scenario.clear(); pakset_scenario.printf("%sscenario/", env_t::pak_dir.c_str()); addons_scenario.clear(); addons_scenario.printf("addons/%sscenario/", env_t::pak_name.c_str()); if (env_t::default_settings.get_with_private_paks()) { this->add_path(addons_scenario); } this->add_path(pakset_scenario); easy_server.init( button_t::square_automatic, "Start this as a server"); bottom_left_frame.add_component(&easy_server); set_name(translator::translate("Load scenario")); set_focus(NULL); } void scenario_frame_t::load_scenario(const char *fullpath, bool is_easy_server) { cbuffer_t param; param.printf("%i,%s", is_easy_server, fullpath); tool_t::simple_tool[TOOL_LOAD_SCENARIO]->set_default_param(param); welt->set_tool(tool_t::simple_tool[TOOL_LOAD_SCENARIO], NULL); tool_t::simple_tool[TOOL_LOAD_SCENARIO]->set_default_param(0); } /** * Action, started after button pressing. */ bool scenario_frame_t::item_action(const char *fullpath) { scenario_frame_t::load_scenario(fullpath, easy_server.pressed); return true; } const char *scenario_frame_t::get_info(const char *filename) { static char info[PATH_MAX]; sprintf(info,"%s",str_get_filename(filename, false).c_str()); return info; } bool scenario_frame_t::check_file( const char *filename, const char * ) { char buf[PATH_MAX]; sprintf( buf, "%s/scenario.nut", filename ); if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } return false; } simutrans-124.3/src/simutrans/gui/scenario_frame.h000066400000000000000000000020051474050137200222760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SCENARIO_FRAME_H #define GUI_SCENARIO_FRAME_H #include "savegame_frame.h" #include "../utils/cbuffer.h" class scenario_frame_t : public savegame_frame_t { private: cbuffer_t path; button_t easy_server; protected: /** * Action that's started by the press of a button. */ bool item_action(const char *fullpath) OVERRIDE; /** * Action, started after X-Button pressing */ bool del_action(const char *f) OVERRIDE { return item_action(f); } // returns extra file info const char *get_info(const char *fname) OVERRIDE; public: // true, if valid bool check_file( const char *filename, const char *suffix ) OVERRIDE; /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "scenario.txt"; } void load_scenario(const char *fullpath, bool is_easy_server = false); scenario_frame_t(); }; #endif simutrans-124.3/src/simutrans/gui/scenario_info.cc000066400000000000000000000127671474050137200223150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "scenario_info.h" #include "../world/simworld.h" #include "../tool/simtool.h" #include "../display/viewport.h" #include "../obj/zeiger.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../utils/simstring.h" static dynamic_string* tab2dyn[scenario_t::SCRIPT_DEBUG + 1]; bool scenario_info_t::update_dynamic_texts(gui_flowtext_t *flow, dynamic_string *text, scr_size size, bool init) { if (text->has_changed() || init) { flow->set_text( *text ); text->clear_changed(); flow->set_size( size ); set_dirty(); return true; } return false; } uint16 scenario_info_t::get_tab_index(const char* which) { const char *shorts[] = { "info", "goal", "rules", "result", "about", "debug" }; for (uint i = 0; iget_scenario(); tabs.add_tab(&info, translator::translate("Scenario Info")); tab2dyn[i++] = &(scen->info_text); tabs.add_tab(&goal, translator::translate("Scenario Goal")); tab2dyn[i++] = &(scen->goal_text); tabs.add_tab(&rule, translator::translate("Scenario Rules")); tab2dyn[i++] = &(scen->rule_text); tabs.add_tab(&result, translator::translate("Scenario Result")); tab2dyn[i++] = &(scen->result_text); tabs.add_tab(&about, translator::translate("About scenario")); tab2dyn[i++] = &(scen->about_text); tabs.add_tab(&debug_msg, translator::translate("Scenario Debug")); tab2dyn[i++] = &(scen->debug_text); // cannot update text => possibly opened from sync_step hash_text = 0; // fetch possible error message const char *err_text = welt->get_scenario()->get_error_text(); if (err_text) { tabs.add_tab(&error, translator::translate("Scenario Error Log")); error.set_text( err_text ); } add_component(&tabs); tabs.add_listener(this); scr_coord pane_pos(D_MARGIN_LEFT, D_MARGIN_TOP); gui_flowtext_t *texts[] = { &info, &goal, &rule, &result, &about, &error, &debug_msg}; for(uint32 i=0; iset_pos(pane_pos); texts[i]->add_listener(this); } set_resizemode(diagonal_resize); scr_size ms(min(display_get_width() / 2, 500), min(display_get_height() / 2, 300)); set_min_windowsize(ms); set_windowsize(ms); } /** * fetches actualized texts and resizes flow text element */ void scenario_info_t::update_scenario_texts() { // we only update the current tab ... scenario_t *scen = welt->get_scenario(); scr_size border_size = get_client_windowsize() - info.get_pos() - scr_size(D_MARGIN_RIGHT + D_SCROLLBAR_WIDTH, D_MARGIN_BOTTOM + D_SCROLLBAR_HEIGHT); int active = tabs.get_active_tab_index(); gui_flowtext_t* ft = dynamic_cast(tabs.get_aktives_tab()); // since we do not update the scroll position if the top text did not changed uint32 new_hash_text = string_to_hash(*tab2dyn[active], 64); int x = ft->get_scroll_x(); int y = ft->get_scroll_y(); bool changed = update_dynamic_texts(ft, tab2dyn[active], border_size, hash_text==0); const char* d = scen->debug_text; debug_msg.set_visible(d && *d); if (changed || new_hash_text != hash_text) { set_windowsize(get_windowsize()); } if (new_hash_text == hash_text) { // first 256 bytes the same => keep scroll position ft->set_scroll_position(x, y); } hash_text = new_hash_text; } void scenario_info_t::draw(scr_coord pos, scr_size size) { update_scenario_texts(); gui_frame_t::draw(pos, size); } bool scenario_info_t::action_triggered( gui_action_creator_t *comp, value_t v) { if ( comp == &tabs ) { set_dirty(); hash_text = 0; // forces redraw } if ( comp == &info || comp == &goal || comp == &rule || comp == &result || comp == &about || comp == &debug_msg ) { // parse hyperlink const char *link = (const char*)v.p; if (link && *link) { if (link[0]=='(') { // jump to coordinate int x=-1, y=-1, z=-1; // try 3d coordinates first int n = sscanf(link, "(%i,%i,%i)", &x, &y, &z); if (n < 3) { // now try 2d n = sscanf(link, "(%i,%i)", &x, &y); } if (n >= 2) { // at least 2d coordinates supplied koord k(x,y); welt->get_scenario()->koord_sq2w( k ); if (welt->is_within_limits(k)) { koord3d p(k,z); if (n < 3) { // take z coordinate from ground p = welt->lookup_kartenboden(k)->get_pos(); } welt->get_viewport()->change_world_position( p ); welt->get_zeiger()->change_pos( p ); const char* err = welt->get_scenario()->jump_to_link_executed(p); if (err) { open_error_msg_win(err); } } } } else if (const char* func = strstart(link, "script:") ) { const char* err = welt->get_scenario()->eval_string(func); if (err && strcmp(err, "suspended") != 0) { dbg->warning("scenario_info_t::action_triggered", "error `%s' when evaluating: %s", err, func); } } else { open_tab(link); } } } return true; } void scenario_info_t::open_tab(const char* which) { tabs.set_active_tab_index(get_tab_index(which)); hash_text = 0; resize(scr_coord(0,0)); set_dirty(); } void scenario_info_t::rdwr( loadsave_t *file ) { // window size scr_size size = get_windowsize(); size.rdwr( file ); tabs.rdwr(file); if( file->is_loading() ) { reset_min_windowsize(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/scenario_info.h000066400000000000000000000023341474050137200221440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SCENARIO_INFO_H #define GUI_SCENARIO_INFO_H #include "gui_frame.h" #include "simwin.h" #include "components/gui_flowtext.h" #include "components/gui_tab_panel.h" class dynamic_string; /** * All messages since the start of the program */ class scenario_info_t : public gui_frame_t, private action_listener_t { private: gui_tab_panel_t tabs; gui_flowtext_t info, goal, rule, result, about, error, debug_msg; uint32 hash_text; bool update_dynamic_texts(gui_flowtext_t *flow, dynamic_string *text, scr_size size, bool init); uint16 get_tab_index(const char* which); public: scenario_info_t(); /** * This method is called if an action is triggered * * Returns true, if action is done and no more * components should be triggered. */ bool action_triggered( gui_action_creator_t *comp, value_t extra) OVERRIDE; void draw(scr_coord pos, scr_size size) OVERRIDE; void update_scenario_texts(); void open_tab(const char* which); int get_open_tab() { return tabs.get_active_tab_index(); } uint32 get_rdwr_id() OVERRIDE { return magic_scenario_info; } void rdwr( loadsave_t *file ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/schedule_list.cc000066400000000000000000000333221474050137200223140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "messagebox.h" #include "schedule_list.h" #include "line_management_gui.h" #include "components/gui_convoiinfo.h" #include "line_item.h" #include "simwin.h" #include "../simcolor.h" #include "../obj/depot.h" #include "../simhalt.h" #include "../world/simworld.h" #include "../simevent.h" #include "../display/simgraph.h" #include "../simskin.h" #include "../simconvoi.h" #include "../vehicle/vehicle.h" #include "../simlinemgmt.h" #include "../tool/simmenu.h" #include "../utils/simstring.h" #include "../player/simplay.h" #include "../builder/vehikelbauer.h" #include "../dataobj/schedule.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../obj/way/kanal.h" #include "../obj/way/maglev.h" #include "../obj/way/monorail.h" #include "../obj/way/narrowgauge.h" #include "../obj/way/runway.h" #include "../obj/way/schiene.h" #include "../obj/way/strasse.h" #include "../utils/unicode.h" #include "minimap.h" #define MAX_SORT_IDX (5) static uint8 idx_to_sort_mode[MAX_SORT_IDX] = { line_scrollitem_t::SORT_BY_NAME, line_scrollitem_t::SORT_BY_PROFIT, line_scrollitem_t::SORT_BY_REVENUE, line_scrollitem_t::SORT_BY_TRANSPORTED, line_scrollitem_t::SORT_BY_CONVOIS }; static const char *idx_to_sort_text[MAX_SORT_IDX] = { "Name", "Profit", "Revenue", "Transported", "Number of convois" }; /// selected tab per player static uint8 selected_tab[MAX_PLAYER_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /// selected line per tab (static) linehandle_t schedule_list_gui_t::selected_line[MAX_PLAYER_COUNT][simline_t::MAX_LINE_TYPE]; schedule_list_gui_t::schedule_list_gui_t(player_t *player_) : gui_frame_t( translator::translate("Line Management"), player_), player(player_), scl(gui_scrolled_list_t::listskin, line_scrollitem_t::compare) { schedule_filter[0] = 0; old_schedule_filter[0] = 0; current_sort_mode = 0; line_scrollitem_t::sort_reverse = false; // add components // first column: scrolled list of all lines set_table_layout(1,0); add_table(4,0); { // below line list: line filter new_component("Filter:"); inp_filter.set_text( schedule_filter, lengthof( schedule_filter ) ); inp_filter.add_listener( this ); add_component( &inp_filter, 2 ); new_component(); // freight type filter new_component(); viewable_freight_types.append(NULL); freight_type_c.new_component(translator::translate("All"), SYSCOL_TEXT); viewable_freight_types.append(goods_manager_t::passengers); freight_type_c.new_component(translator::translate("Passagiere"), SYSCOL_TEXT); viewable_freight_types.append(goods_manager_t::mail); freight_type_c.new_component(translator::translate("Post"), SYSCOL_TEXT); viewable_freight_types.append(goods_manager_t::none); // for all freight ... freight_type_c.new_component(translator::translate("Fracht"), SYSCOL_TEXT); for (int i = 0; i < goods_manager_t::get_max_catg_index(); i++) { const goods_desc_t* freight_type = goods_manager_t::get_info_catg(i); const int index = freight_type->get_catg_index(); if (index == goods_manager_t::INDEX_NONE || freight_type->get_catg() == 0) { continue; } freight_type_c.new_component(translator::translate(freight_type->get_catg_name()), SYSCOL_TEXT); viewable_freight_types.append(freight_type); } for (int i = 0; i < goods_manager_t::get_count(); i++) { const goods_desc_t* ware = goods_manager_t::get_info(i); if (ware->get_catg() == 0 && ware->get_index() > 2) { // Special freight: Each good is special viewable_freight_types.append(ware); freight_type_c.new_component(translator::translate(ware->get_name()), SYSCOL_TEXT); } } freight_type_c.set_selection(0); freight_type_c.set_focusable(true); freight_type_c.add_listener(this); add_component(&freight_type_c, 2); new_component(); // sort by what new_component("hl_txt_sort"); for( int i=0; i( translator::translate(idx_to_sort_text[i]), SYSCOL_TEXT) ; } sort_type_c.set_selection(current_sort_mode); sort_type_c.set_focusable( true ); sort_type_c.add_listener( this ); add_component(&sort_type_c); sorteddir.init(button_t::sortarrow_state, NULL); sorteddir.add_listener(this); sorteddir.pressed = line_scrollitem_t::sort_reverse; add_component(&sorteddir); new_component(); } end_table(); add_table(3, 1); { // line control buttons bt_new_line.init(button_t::roundbox, "New Line"); bt_new_line.add_listener(this); add_component(&bt_new_line); bt_delete_line.init(button_t::roundbox, "Delete Line"); bt_delete_line.set_tooltip("Delete the selected line (if without associated convois)."); bt_delete_line.add_listener(this); add_component( &bt_delete_line ); bt_single_line.init( button_t::square_automatic | button_t::flexible, "Single GUI" ); bt_single_line.set_tooltip( "Closes topmost line window when new line selected." ); bt_single_line.add_listener( this ); bt_single_line.pressed = env_t::single_line_gui; add_component( &bt_single_line ); new_component(); } end_table(); // init scrolled list scl.add_listener(this); // tab panel tabs.init_tabs(&scl); tabs.add_listener(this); add_component(&tabs); // recover last selected line tabs.set_active_tab_waytype(simline_t::linetype_to_waytype((simline_t::linetype)selected_tab[player->get_player_nr()])); build_line_list((simline_t::linetype)selected_tab[player->get_player_nr()]); set_resizemode(diagonal_resize); reset_min_windowsize(); } bool schedule_list_gui_t::action_triggered( gui_action_creator_t *comp, value_t v ) { if( comp == &bt_new_line ) { // create typed line assert( tabs.get_active_tab_index() > 0 ); // update line schedule via tool! tool_t *tmp_tool = create_tool( TOOL_CHANGE_LINE | SIMPLE_TOOL ); cbuffer_t buf; int type = simline_t::waytype_to_linetype(tabs.get_active_tab_waytype()); buf.printf( "c,0,%i,0,0|%i|", type, type ); tmp_tool->set_default_param(buf); welt->set_tool( tmp_tool, player ); // since init always returns false, it is safe to delete immediately delete tmp_tool; depot_t::update_all_win(); } else if( comp == &bt_delete_line ) { vector_tpl sel = scl.get_selections(); for(sint32 i : sel) { linehandle_t line = ((line_scrollitem_t*)scl.get_element(i))->get_line(); if (line->count_convoys()==0) { // delete this line via tool tool_t* tmp_tool = create_tool(TOOL_CHANGE_LINE | SIMPLE_TOOL); cbuffer_t buf; buf.printf("d,%i", line.get_id()); tmp_tool->set_default_param(buf); welt->set_tool(tmp_tool, player); // since init always returns false, it is safe to delete immediately delete tmp_tool; } } depot_t::update_all_win(); } else if( comp == &bt_single_line ) { env_t::single_line_gui ^= 1; bt_single_line.pressed = env_t::single_line_gui; } else if( comp == &tabs ) { int const tab = tabs.get_active_tab_index(); uint8 old_selected_tab = selected_tab[player->get_player_nr()]; selected_tab[player->get_player_nr()] = simline_t::waytype_to_linetype(tabs.get_active_tab_waytype()); if( old_selected_tab == simline_t::line && selected_line[player->get_player_nr()][0].is_bound() && selected_line[player->get_player_nr()][0]->get_linetype() == selected_tab[player->get_player_nr()] ) { // switching from general to same waytype tab while line is seletced => use current line instead selected_line[player->get_player_nr()][selected_tab[player->get_player_nr()]] = selected_line[player->get_player_nr()][0]; } build_line_list((simline_t::linetype)selected_tab[player->get_player_nr()]); if( tab>0 ) { bt_new_line.enable(); } else { bt_new_line.disable(); } } else if( comp == &scl ) { if( line_scrollitem_t *li=(line_scrollitem_t *)scl.get_element(v.i) ) { line = li->get_line(); gui_frame_t *line_info = win_get_magic( (ptrdiff_t)line.get_rep() ); // try to open to the right scr_coord sc = win_get_pos( this ); scr_coord lc = sc; lc.x += get_windowsize().w; if( lc.x > display_get_width() ) { lc.x = max( 0, display_get_width() - 100 ); } if( line_info ) { // close if open destroy_win( line_info ); } else { if( bt_single_line.pressed && win_get_open_count()>=2 ) { // close second topmost line window for( int i = win_get_open_count()-1; i>=0; i-- ) { if( gui_frame_t* gui = win_get_index( i ) ) { if( gui->get_rdwr_id()==magic_line_schedule_rdwr_dummy ) { destroy_win( gui ); break; } } } } create_win( lc, new line_management_gui_t(line, player, -1), w_info, (ptrdiff_t)line.get_rep() ); } } scl.set_selection( -1 ); } else if( comp == &inp_filter ) { if( strcmp(old_schedule_filter,schedule_filter) ) { build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); strcpy(old_schedule_filter,schedule_filter); } } else if( comp == &freight_type_c ) { build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); } else if (comp == &sorteddir) { line_scrollitem_t::sort_reverse = !line_scrollitem_t::sort_reverse; sorteddir.pressed = line_scrollitem_t::sort_reverse; build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); } else if( comp == &sort_type_c ) { build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); } return true; } void schedule_list_gui_t::draw(scr_coord pos, scr_size size) { // deativate buttons, if not curretn player const bool activate = player == welt->get_active_player() || welt->get_active_player()==welt->get_player( 1 ); bt_new_line.enable( activate && tabs.get_active_tab_index() > 0); bt_delete_line.enable(activate); // if search string changed, update line selection if( old_line_count != player->simlinemgmt.get_line_count() || strcmp( old_schedule_filter, schedule_filter ) ) { old_line_count = player->simlinemgmt.get_line_count(); build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); strcpy( old_schedule_filter, schedule_filter ); } vector_tpl sel = scl.get_selections(); bool can_delete = sel.get_count() > 0 && activate; if (can_delete) { for(sint32 i : sel) { linehandle_t line = ((line_scrollitem_t*)scl.get_element(i))->get_line(); if (line->count_convoys() > 0) { can_delete = false; break; } } } bt_delete_line.enable(can_delete); gui_frame_t::draw(pos, size); } void schedule_list_gui_t::build_line_list(simline_t::linetype filter) { vector_tpllines; sint32 sel = -1; scl.clear_elements(); player->simlinemgmt.get_lines(filter, &lines); for(linehandle_t const l : lines) { // search name if( !*schedule_filter || utf8caseutf8(l->get_name(), schedule_filter) ) { // match good category if( is_matching_freight_catg( l->get_goods_catg_index() ) ) { scl.new_component(l, line_scrollitem_t::SELECT_WIN); } if( line == l ) { sel = scl.get_count() - 1; } } } scl.set_selection( sel ); current_sort_mode = idx_to_sort_mode[ sort_type_c.get_selection() ]; line_scrollitem_t::sort_mode = (line_scrollitem_t::sort_modes_t)current_sort_mode; scl.sort( 0 ); scl.set_size(scl.get_size()); old_line_count = player->simlinemgmt.get_line_count(); } uint32 schedule_list_gui_t::get_rdwr_id() { return magic_line_management_t+player->get_player_nr(); } void schedule_list_gui_t::rdwr( loadsave_t *file ) { scr_size size; if( file->is_saving() ) { size = get_windowsize(); } size.rdwr( file ); tabs.rdwr( file ); simline_t::rdwr_linehandle_t(file, line); scl.rdwr(file); sort_type_c.rdwr(file); freight_type_c.rdwr(file); file->rdwr_str(schedule_filter, lengthof(schedule_filter)); file->rdwr_bool(line_scrollitem_t::sort_reverse); // open dialogue if( file->is_loading() ) { current_sort_mode = idx_to_sort_mode[sort_type_c.get_selection()]; line_scrollitem_t::sort_mode = (line_scrollitem_t::sort_modes_t)current_sort_mode; build_line_list(simline_t::waytype_to_linetype(tabs.get_active_tab_waytype())); set_windowsize(size); // that would be the proper way to restore windows, would keep the simwin side cleaner) ... // win_set_magic(magic_line_management_t + player->get_player_nr()) } } // borrowed code from minimap bool schedule_list_gui_t::is_matching_freight_catg(const minivec_tpl &goods_catg_index) { const goods_desc_t *line_freight_type_group_index = viewable_freight_types[ freight_type_c.get_selection() ]; // does this line/convoi has a matching freight if( line_freight_type_group_index == goods_manager_t::passengers ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_PAS); } else if( line_freight_type_group_index == goods_manager_t::mail ) { return goods_catg_index.is_contained(goods_manager_t::INDEX_MAIL); } else if( line_freight_type_group_index == goods_manager_t::none ) { // all freights but not pax or mail for( uint8 i = 0; i < goods_catg_index.get_count(); i++ ) { if( goods_catg_index[i] > goods_manager_t::INDEX_NONE ) { return true; } } return false; } else if( line_freight_type_group_index != NULL ) { for( uint8 i = 0; i < goods_catg_index.get_count(); i++ ) { if( goods_catg_index[i] == line_freight_type_group_index->get_catg_index() ) { return true; } } return false; } // all true return true; } simutrans-124.3/src/simutrans/gui/schedule_list.h000066400000000000000000000034011474050137200221510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SCHEDULE_LIST_H #define GUI_SCHEDULE_LIST_H #include "gui_frame.h" #include "components/gui_combobox.h" #include "components/gui_textinput.h" #include "components/gui_scrolled_list.h" #include "components/gui_convoiinfo.h" #include "components/gui_waytype_tab_panel.h" #include "../tpl/vector_tpl.h" #include "../tpl/minivec_tpl.h" #include "../simline.h" #include "../descriptor/goods_desc.h" class player_t; /** * Window displaying information about all schedules and lines. */ class schedule_list_gui_t : public gui_frame_t, public action_listener_t { private: player_t *player; button_t bt_new_line, bt_delete_line, bt_single_line; gui_scrolled_list_t scl; gui_textinput_t inp_filter; button_t filterButtons[MAX_LINE_COST]; gui_waytype_tab_panel_t tabs; gui_combobox_t freight_type_c, sort_type_c; button_t sorteddir; uint32 old_line_count; // to filter for line names char schedule_filter[256], old_schedule_filter[256]; vector_tpl viewable_freight_types; bool is_matching_freight_catg( const minivec_tpl &goods_catg_index ); uint8 current_sort_mode; void build_line_list(simline_t::linetype filter); // last active line linehandle_t line; public: /// last selected line per tab static linehandle_t selected_line[MAX_PLAYER_COUNT][simline_t::MAX_LINE_TYPE]; schedule_list_gui_t(player_t* player_); const char* get_help_filename() const OVERRIDE { return "linemanagement.txt"; } void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // following: rdwr stuff void rdwr( loadsave_t *file ) OVERRIDE; uint32 get_rdwr_id() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/script_generator_frame.cc000066400000000000000000000024111474050137200242040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "script_generator_frame.h" #include "../tool/simtool.h" #include "../sys/simsys.h" script_generator_frame_t::script_generator_frame_t(tool_generate_script_t* tl, const char *_p, cbuffer_t &cmd, koord a) : savegame_frame_t("", false, _p, true) { this->tool = tl; command = cmd; area = a; set_name(translator::translate("Save generated script")); } /** * Action, started after button pressing. */ bool script_generator_frame_t::item_action(const char *fullpath) { tool->save_script(fullpath,command,area); return true; } bool script_generator_frame_t::ok_action(const char *fullpath) { tool->save_script(fullpath,command,area); return true; } bool script_generator_frame_t::del_action(const char* fullpath) { dr_chdir(fullpath); dr_remove("description.tab"); dr_remove("tool.nut"); dr_remove("script-exec-0.log"); dr_chdir(".."); const char* p = strrchr(fullpath, *PATH_SEPARATOR); if (!p) { p = strrchr(fullpath, '/'); } if (p) { return dr_remove(p + 1); } return false; } const char *script_generator_frame_t::get_info(const char *) { return ""; } bool script_generator_frame_t::check_file( const char *f, const char * ) { return *f; } simutrans-124.3/src/simutrans/gui/script_generator_frame.h000066400000000000000000000021651474050137200240540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SCRIPT_GENERATOR_INFO_H #define GUI_SCRIPT_GENERATOR_INFO_H #include "savegame_frame.h" #include "../utils/cbuffer.h" #include "../tool/simtool.h" class script_generator_frame_t : public savegame_frame_t { private: tool_generate_script_t* tool; cbuffer_t command; koord area; protected: /** * Action that's started by the press of a button. */ bool item_action(const char *fullpath) OVERRIDE; bool ok_action(const char* fullpath) OVERRIDE; bool del_action(const char* fullpath) OVERRIDE; /** * Returns extra file info: title of tool from description.tab */ const char *get_info(const char *path) OVERRIDE; // true, if valid bool check_file( const char *filename, const char *suffix ) OVERRIDE; public: script_generator_frame_t(tool_generate_script_t*, const char *path, cbuffer_t &cmd, koord area); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "script_generator.txt"; } }; #endif simutrans-124.3/src/simutrans/gui/script_tool_frame.cc000066400000000000000000000047321474050137200232030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "script_tool_frame.h" #include "../script/script_tool_manager.h" #include "../dataobj/environment.h" #include "../dataobj/tabfile.h" #include "../dataobj/translator.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../tool/simtool-scripted.h" #include "../sys/simsys.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" script_tool_frame_t::~script_tool_frame_t() { clear_ptr_vector(infos); } script_tool_frame_t::script_tool_frame_t() : savegame_frame_t(NULL, true, NULL, false) { static cbuffer_t pakset_script_tool; static cbuffer_t addons_script_tool; static cbuffer_t user_addons_script_tool; pakset_script_tool.clear(); pakset_script_tool.printf("%stool%s", env_t::pak_dir.c_str(), PATH_SEPARATOR); addons_script_tool.clear(); addons_script_tool.printf("%saddons%s%stool%s", env_t::install_dir, PATH_SEPARATOR, env_t::pak_name.c_str(), PATH_SEPARATOR); user_addons_script_tool.clear(); user_addons_script_tool.printf("%saddons%s%stool%s", env_t::user_dir, PATH_SEPARATOR, env_t::pak_name.c_str(), PATH_SEPARATOR); if (env_t::default_settings.get_with_private_paks()) { this->add_path(addons_script_tool); } this->add_path(user_addons_script_tool); // always add user addons this->add_path(pakset_script_tool); set_name(translator::translate("Load script tool")); set_focus(NULL); } /** * Action, started after button pressing. */ bool script_tool_frame_t::item_action(const char *fullpath) { const scripted_tool_info_t* info = script_tool_manager_t::get_script_info(fullpath); bool is_one_click = info->is_one_click; delete info; tool_t* tool = script_tool_manager_t::load_tool(fullpath, tool_t::general_tool[is_one_click ? TOOL_EXEC_SCRIPT : TOOL_EXEC_TWO_CLICK_SCRIPT]); assert(tool); const char* p = strrchr(fullpath, *PATH_SEPARATOR); static plainstring last_default_param; last_default_param = p ? p + 1 : fullpath; tool->set_default_param(last_default_param); welt->set_tool(tool, welt->get_active_player()); return true; } // calls tool manager to read description.tab const char *script_tool_frame_t::get_info(const char *path) { const scripted_tool_info_t* info = script_tool_manager_t::get_script_info(path); infos.append(info); return info->title.c_str(); } bool script_tool_frame_t::check_file( const char *filename, const char * ) { return script_tool_manager_t::check_file(filename); } simutrans-124.3/src/simutrans/gui/script_tool_frame.h000066400000000000000000000017411474050137200230420ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SCRIPT_TOOL_FRAME_H #define GUI_SCRIPT_TOOL_FRAME_H #include "savegame_frame.h" #include "../tpl/vector_tpl.h" struct scripted_tool_info_t; class script_tool_frame_t : public savegame_frame_t { private: // pointers to info structures vector_tpl infos; protected: /** * Action that's started by the press of a button. */ bool item_action(const char *fullpath) OVERRIDE; /** * Returns extra file info: title of tool from description.tab */ const char *get_info(const char *path) OVERRIDE; // true, if valid bool check_file( const char *filename, const char *suffix ) OVERRIDE; public: script_tool_frame_t(); ~script_tool_frame_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE { return "script_tool.txt"; } }; #endif simutrans-124.3/src/simutrans/gui/server_frame.cc000066400000000000000000000406531474050137200221520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../world/simworld.h" #include "../simcolor.h" #include "../display/simgraph.h" #include "simwin.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "../utils/csv.h" #include "../simversion.h" #include "../dataobj/translator.h" #include "../network/network.h" #include "../network/network_file_transfer.h" #include "../network/network_cmd_ingame.h" #include "../network/network_cmp_pakset.h" #include "../dataobj/environment.h" #include "../network/pakset_info.h" #include "../player/simplay.h" #include "server_frame.h" #include "messagebox.h" #include "chat_frame.h" #include "help_frame.h" #include "components/gui_divider.h" static char nick_buf[256]; char server_frame_t::newserver_name[2048] = ""; class gui_minimap_t : public gui_component_t { gameinfo_t *gi; public: gui_minimap_t() { gi = NULL; } void set_gameinfo(gameinfo_t *gi) { this->gi = gi; } void draw( scr_coord offset ) OVERRIDE { if (gi) { scr_coord p = get_pos() + offset; scr_size mapsize( gi->get_map()->get_width(), gi->get_map()->get_height() ); // 3D border around the map graphic display_ddd_box_clip_rgb(p.x, p.y, mapsize.w + 2, mapsize.h + 2, color_idx_to_rgb(MN_GREY0), color_idx_to_rgb(MN_GREY4) ); display_array_wh( p.x + 1, p.y + 1, mapsize.w, mapsize.h, gi->get_map()->to_array() ); } } scr_size get_min_size() const OVERRIDE { return gi ? scr_size(gi->get_map()->get_width()+2, gi->get_map()->get_height()+2) : scr_size(0,0); } scr_size get_max_size() const OVERRIDE { return get_min_size(); } }; server_frame_t::server_frame_t() : gui_frame_t( translator::translate("Game info") ), gi(welt), custom_valid(false), serverlist( gui_scrolled_list_t::listskin, gui_scrolled_list_t::scrollitem_t::compare ), game_text(&buf) { map = new gui_minimap_t(); update_info(); map->set_gameinfo(&gi); set_table_layout(3,0); // When in network mode, display only local map info (and nickname changer) // When not in network mode, display server picker if ( !env_t::networkmode ) { new_component_span("Select a server to join:",2); join.init(button_t::roundbox | button_t::flexible, "join game"); join.disable(); join.add_listener(this); add_component(&join); // Server listing serverlist.set_selection( 0 ); add_component( &serverlist, 3 ); serverlist.add_listener(this); // Show mismatched checkbox show_mismatched.init( button_t::square_state | button_t::flexible, "Show mismatched"); show_mismatched.set_tooltip( "Show servers where game version or pakset does not match your client" ); show_mismatched.add_listener( this ); add_component( &show_mismatched ); // Show offline checkbox show_offline.init( button_t::square_state | button_t::flexible, "Show offline"); show_offline.set_tooltip( "Show servers that are offline" ); show_offline.add_listener( this ); add_component( &show_offline, 2 ); new_component_span(3); new_component_span("Or enter a server manually:", 2); add.init(button_t::roundbox | button_t::flexible, "Query server"); add.add_listener(this); add_component(&add); // Add server input/button addinput.set_text( newserver_name, sizeof( newserver_name ) ); addinput.add_listener( this ); add_component( &addinput, 3 ); new_component_span(3); } if(!env_t::networkmode) { add_component(&revision); find_mismatch.init(button_t::roundbox | button_t::flexible, "find mismatch"); find_mismatch.add_listener(this); add_component(&find_mismatch,2); } else { add_component(&revision, 3); } show_mismatched.pressed = gi.get_game_engine_revision() == 0; add_component( &pak_version, 3 ); #if MSG_LEVEL>=4 add_component( &pakset_checksum, 3 ); #endif new_component_span(3); add_table(2, 1, 3); { add_component(map); add_table(3,2); { add_component(&label_size); new_component(); add_component( &date ); add_component(&game_text,3); } end_table(); } end_table(); new_component_span(3); add_table(2, 1, 3); { new_component("Nickname:" ); nick.add_listener(this); nick.set_text( nick_buf, lengthof( nick_buf ) ); tstrncpy( nick_buf, env_t::nickname.c_str(), min( lengthof( nick_buf ), env_t::nickname.length() + 1 ) ); add_component(&nick); } end_table(); if ( !env_t::networkmode ) { // only update serverlist, when not already in network mode // otherwise desync to current game may happen update_serverlist(); } set_resizemode( diagonal_resize ); reset_min_windowsize(); } void server_frame_t::update_error (const char* errortext) { buf.clear(); buf.printf("%s", errortext ); map->set_gameinfo(NULL); date.buf().clear(); label_size.buf().clear(); revision.buf().clear(); pak_version.set_text( "" ); join.disable(); find_mismatch.disable(); } PIXVAL server_frame_t::update_info() { map->set_gameinfo(&gi); // Compare with current world to determine status gameinfo_t current( welt ); bool engine_match = false; bool pakset_match = false; // Zero means do not know => assume match if( current.get_game_engine_revision() == 0 || gi.get_game_engine_revision() == 0 || current.get_game_engine_revision() == gi.get_game_engine_revision() ) { engine_match = true; } if( gi.get_pakset_checksum() == current.get_pakset_checksum() ) { pakset_match = true; find_mismatch.disable(); } else { find_mismatch.enable(); } // State of join button if( (serverlist.get_selection() >= 0 || custom_valid) && pakset_match && engine_match ) { join.enable(); } else { join.disable(); } label_size.buf().printf("%ux%u\n", gi.get_size_x(), gi.get_size_y()); label_size.update(); // Update all text fields char temp[32]; buf.clear(); if ( gi.get_clients() != 255 ) { uint8 player = 0, locked = 0; for ( uint8 i = 0; i < MAX_PLAYER_COUNT; i++ ) { if ( gi.get_player_type(i)&~player_t::PASSWORD_PROTECTED ) { player ++; if ( gi.get_player_type(i)&player_t::PASSWORD_PROTECTED ) { locked ++; } } } buf.printf( translator::translate("%u Player (%u locked)\n"), player, locked ); buf.printf( translator::translate("%u Client(s)\n"), (unsigned)gi.get_clients() ); } buf.printf( "%s %u\n", translator::translate("Towns"), gi.get_city_count() ); number_to_string( temp, gi.get_citizen_count(), 0 ); buf.printf( "%s %s\n", translator::translate("citicens"), temp ); buf.printf( "%s %u\n", translator::translate("Factories"), gi.get_industries() ); buf.printf( "%s %u\n", translator::translate("Convoys"), gi.get_convoi_count() ); buf.printf( "%s %u\n", translator::translate("Stops"), gi.get_halt_count() ); revision.buf().printf( "%s %u", translator::translate( "Revision:" ), gi.get_game_engine_revision() ); revision.set_color( engine_match ? SYSCOL_TEXT : MONEY_MINUS ); revision.update(); pak_version.set_text( gi.get_pak_name() ); pak_version.set_color( pakset_match ? SYSCOL_TEXT : SYSCOL_OBSOLETE ); #if MSG_LEVEL>=4 pakset_checksum.buf().printf("%s %s",translator::translate( "Pakset checksum:" ), gi.get_pakset_checksum().get_str(8)); pakset_checksum.update(); pakset_checksum.set_color( pakset_match ? SYSCOL_TEXT : SYSCOL_TEXT_STRONG ); #endif date.buf().printf("%s", translator::get_date(gi.get_current_year(), gi.get_current_month())); date.update(); set_dirty(); resize(scr_size(0,0)); return pakset_match && engine_match ? SYSCOL_TEXT : SYSCOL_OBSOLETE; } bool server_frame_t::update_serverlist () { // Based on current dialog settings, should we show mismatched servers or not uint revision = 0; const char* pakset = NULL; gameinfo_t current( welt ); if( !show_mismatched.pressed ) { revision = current.get_game_engine_revision(); pakset = current.get_pak_name(); } // Download game listing from listings server into memory cbuffer_t buf; const char *err = NULL; if ((err = network_http_get(ANNOUNCE_SERVER1, ANNOUNCE_LIST_URL, buf))) { dbg->warning("server_frame_t::update_serverlist", "Could not download server list from %s: %s", ANNOUNCE_SERVER1, err); #ifdef ANNOUNCE_SERVER2 if ((err = network_http_get(ANNOUNCE_SERVER2, ANNOUNCE_LIST_URL, buf))) { dbg->warning("server_frame_t::update_serverlist", "Could not download server list from %s: %s", ANNOUNCE_SERVER2, err); #ifdef ANNOUNCE_SERVER3 if ((err = network_http_get(ANNOUNCE_SERVER3, ANNOUNCE_LIST_URL, buf))) { dbg->error("server_frame_t::update_serverlist", "Could not download server list from %s: %s", ANNOUNCE_SERVER3, err); return false; } #else return false; #endif } #else return false; #endif } // Parse listing into CSV_t object CSV_t csvdata( buf.get_str() ); int ret; dbg->message( "server_frame_t::update_serverlist", "CSV_t: %s", csvdata.get_str() ); // For each listing entry, determine if it matches the version supplied to this function do { // First field is display name of server cbuffer_t servername; ret = csvdata.get_next_field( servername ); dbg->message( "server_frame_t::update_serverlist", "servername: %s", servername.get_str() ); // Skip invalid lines if( ret <= 0 ) { continue; } // Second field is dns name of server cbuffer_t serverdns; ret = csvdata.get_next_field( serverdns ); dbg->message( "server_frame_t::update_serverlist", "serverdns: %s", serverdns.get_str() ); if( ret <= 0 ) { continue; } cbuffer_t serverdns2; // Strip default port if( strcmp(serverdns.get_str() + serverdns.len() - 6, ":13353") == 0 ) { dbg->message( "server_frame_t::update_serverlist", "stripping default port from entry %s", serverdns.get_str() ); serverdns2.append( serverdns.get_str(), strlen( serverdns.get_str() ) - 6 ); serverdns = serverdns2; serverdns2.clear(); } // Third field is server revision (use for filtering) cbuffer_t serverrevision; ret = csvdata.get_next_field( serverrevision ); dbg->message( "server_frame_t::update_serverlist", "serverrevision: %s", serverrevision.get_str() ); if( ret <= 0 ) { continue; } uint32 serverrev = atol( serverrevision.get_str() ); if( revision != 0 && revision != serverrev ) { // do not add mismatched servers dbg->warning( "server_frame_t::update_serverlist", "revision %i does not match our revision (%i), skipping", serverrev, revision ); continue; } // Fourth field is server pakset (use for filtering) cbuffer_t serverpakset; ret = csvdata.get_next_field( serverpakset ); dbg->message( "server_frame_t::update_serverlist", "serverpakset: %s", serverpakset.get_str() ); if( ret <= 0 ) { continue; } // now check pakset match if ( pakset != NULL ) { if (!strstart(serverpakset.get_str(), pakset)) { dbg->warning( "server_frame_t::update_serverlist", "pakset '%s' does not match our pakset ('%s'), skipping", serverpakset.get_str(), pakset ); continue; } } // Fifth field is server online/offline status (use for colour-coding) cbuffer_t serverstatus; ret = csvdata.get_next_field( serverstatus ); dbg->message( "server_frame_t::update_serverlist", "serverstatus: %s", serverstatus.get_str() ); uint32 status = 0; if( ret > 0 ) { status = atol( serverstatus.get_str() ); // sixth field on new list the alt dns, if there is one ret = csvdata.get_next_field(serverdns2); dbg->message("server_frame_t::update_serverlist", "altdns: %s", serverdns2.get_str()); } // Only show offline servers if the checkbox is set if( status == 1 || show_offline.pressed ) { PIXVAL color = status == 1 ? SYSCOL_EMPTY : MONEY_MINUS; if( pakset && !strstart( serverpakset.get_str(), pakset ) ) { color = SYSCOL_OBSOLETE; } serverlist.new_component( servername, serverdns, serverdns2, status, color ); dbg->message( "server_frame_t::update_serverlist", "Appended %s (%s) to list", servername.get_str(), serverdns.get_str() ); } } while( csvdata.next_line() ); // Set no default selection serverlist.set_selection( -1 ); serverlist.set_size(serverlist.get_size()); set_dirty(); resize(scr_size(0, 0)); return true; } bool server_frame_t::infowin_event (const event_t *ev) { return gui_frame_t::infowin_event( ev ); } bool server_frame_t::action_triggered (gui_action_creator_t *comp, value_t p) { // Selection has changed if( &serverlist == comp ) { if( p.i <= -1 ) { join.disable(); gi = gameinfo_t(welt); update_info(); } else { join.disable(); server_scrollitem_t *item = (server_scrollitem_t*)serverlist.get_element( p.i ); if( item->online() ) { display_show_load_pointer(1); const char *err = network_gameinfo( ((server_scrollitem_t*)serverlist.get_element( p.i ))->get_dns(), &gi ); if( err && *((server_scrollitem_t*)serverlist.get_element(p.i))->get_altdns() ) { item->set_color(MONEY_MINUS); update_error(err); err = network_gameinfo(((server_scrollitem_t*)serverlist.get_element(p.i))->get_altdns(), &gi); } if( err == NULL ) { item->set_color( update_info() ); } else { item->set_color( MONEY_MINUS ); update_error( err ); } display_show_load_pointer(0); } else { item->set_color( MONEY_MINUS ); update_error( "Cannot connect to offline server!" ); } } } else if ( &add == comp || &addinput ==comp ) { if ( newserver_name[0] != '\0' ) { join.disable(); dbg->warning("action_triggered()", "newserver_name: %s", newserver_name); display_show_load_pointer(1); const char *err = network_gameinfo( newserver_name, &gi ); if ( err == NULL ) { custom_valid = true; update_info(); } else { custom_valid = false; join.disable(); update_error( "Server did not respond!" ); } display_show_load_pointer(0); serverlist.set_selection( -1 ); } } else if ( &show_mismatched == comp ) { show_mismatched.pressed ^= 1; serverlist.clear_elements(); update_serverlist(); } else if ( &show_offline == comp ) { show_offline.pressed ^= 1; serverlist.clear_elements(); update_serverlist(); } else if ( &nick == comp ) { char* nickname = nick.get_text(); if ( env_t::networkmode ) { // Only try and change the nick with server if we're in network mode if ( env_t::nickname != nickname ) { env_t::nickname = nickname; nwc_nick_t* nwc = new nwc_nick_t( nickname ); network_send_server( nwc ); } } else { world()->get_chat_message()->rename_client(env_t::nickname.c_str(), nickname); env_t::nickname = nickname; } } else if ( &join == comp ) { char* nickname = nick.get_text(); if ( strlen( nickname ) == 0 ) { // forbid joining? } env_t::nickname = nickname; std::string filename = "net:"; // Prefer serverlist entry if one is selected if ( serverlist.get_selection() >= 0 ) { display_show_load_pointer(1); filename += ((server_scrollitem_t*)serverlist.get_selected_item())->get_dns(); destroy_win( this ); welt->load( filename.c_str() ); welt->type_of_generation = karte_t::CLIENT_WORLD; display_show_load_pointer(0); } // If we have a valid custom server entry, connect to that else if ( custom_valid ) { display_show_load_pointer(1); filename += newserver_name; destroy_win( this ); welt->load( filename.c_str() ); welt->type_of_generation = karte_t::CLIENT_WORLD; display_show_load_pointer(0); } else { dbg->error( "server_frame_t::action_triggered()", "join pressed without valid selection or custom server entry" ); join.disable(); } } else if ( &find_mismatch == comp ) { if ( gui_frame_t *info = win_get_magic(magic_pakset_info_t) ) { top_win( info ); } else { std::string msg; if ( serverlist.get_selection() >= 0 ) { network_compare_pakset_with_server( ((server_scrollitem_t*)serverlist.get_selected_item())->get_dns(), msg ); } else if ( custom_valid ) { network_compare_pakset_with_server( newserver_name, msg ); } else { dbg->error( "server_frame_t::action_triggered()", "find_mismatch pressed without valid selection or custom server entry" ); find_mismatch.disable(); } if ( !msg.empty() ) { help_frame_t *win = new help_frame_t(); win->set_text( msg.c_str() ); create_win( win, w_info, magic_pakset_info_t ); } } } return true; } void server_frame_t::draw (scr_coord pos, scr_size size) { // update nickname if necessary if ( get_focus() != &nick && env_t::nickname != nick_buf ) { tstrncpy( nick_buf, env_t::nickname.c_str(), min( lengthof( nick_buf ), env_t::nickname.length() + 1 ) ); } gui_frame_t::draw( pos, size ); } simutrans-124.3/src/simutrans/gui/server_frame.h000066400000000000000000000063501474050137200220100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SERVER_FRAME_H #define GUI_SERVER_FRAME_H #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_combobox.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "components/gui_textarea.h" #include "components/gui_textinput.h" #include "../dataobj/gameinfo.h" #include "../utils/cbuffer.h" class gui_minimap_t; /** * When connected to a network server, this dialog shows game information * When not connected, it provides the mechanism for joining a remote game */ class server_frame_t : public gui_frame_t, private action_listener_t { private: gameinfo_t gi; cbuffer_t buf; bool custom_valid; // Custom server entry is valid gui_textinput_t addinput, nick; static char newserver_name[2048]; gui_scrolled_list_t serverlist; button_t add, join, find_mismatch; button_t show_mismatched, show_offline; gui_label_t pak_version; gui_label_buf_t revision, date, label_size; #if MSG_LEVEL>=4 gui_label_buf_t pakset_checksum; #endif gui_minimap_t *map; gui_textarea_t game_text; /** * Server items to add to the listing panel * Stores dnsname (for connection) and servername (for display in list) * Also stores online/offline status of the server for filtering * Adds get_dns() method to retrieve dnsname */ class server_scrollitem_t : public gui_scrolled_list_t::const_text_scrollitem_t { private: cbuffer_t servername; cbuffer_t serverdns; cbuffer_t server_altdns; bool status; public: server_scrollitem_t (const cbuffer_t& name, const cbuffer_t& dns, const cbuffer_t& altdns, bool status, PIXVAL col) : gui_scrolled_list_t::const_text_scrollitem_t( NULL, col ), servername( name ), serverdns( dns ), server_altdns(altdns), status( status ) { servername.append( " (" ); servername.append( serverdns.get_str() ); if ( server_altdns.len() > 0 ) { servername.append(" or "); servername.append(server_altdns.get_str()); } servername.append(")"); } char const* get_text () const OVERRIDE { return servername.get_str(); } char const* get_dns() const { return serverdns.get_str(); } char const* get_altdns() const { return server_altdns.get_str(); } void set_text (char const* newtext) OVERRIDE { servername.clear(); servername.append( newtext ); serverdns.clear(); serverdns.append( newtext ); } bool online () { return status; } }; /** * Update UI fields with data from the current state of gameinfo_t gi */ PIXVAL update_info(); /** * Update UI fields to show connection errors */ void update_error ( const char* ); /** * Update server listing (retrieve from listings server) * Display depends on the state of the show_mismatched and * show_offline checkboxes */ bool update_serverlist (); public: server_frame_t(); void draw(scr_coord pos, scr_size size) OVERRIDE; /** * Return name of file which contains associated help text for this window * @return Help file name, nor NULL if no help file exists */ const char *get_help_filename() const OVERRIDE {return "server.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; bool infowin_event(event_t const*) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/settings_frame.cc000066400000000000000000000124271474050137200225020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simcity.h" #include "../sys/simsys.h" #include "simwin.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../dataobj/tabfile.h" #include "settings_frame.h" #include "components/gui_label.h" #include "../world/simworld.h" #include "components/action_listener.h" using std::string; settings_frame_t::settings_frame_t(settings_t* const s) : gui_frame_t( translator::translate("Setting") ), sets(s), scrolly_general(&general, true, true), scrolly_display(&display, true, true), scrolly_economy(&economy, true, true), scrolly_routing(&routing, true, true), scrolly_costs(&costs, true, true), scrolly_climates(&climates, true, true) { set_table_layout(1,0); add_table(0,1); { new_component("Load settings from"); revert_to_simuconf.init( button_t::roundbox | button_t::flexible, "Simuconf.tab"); revert_to_simuconf.add_listener( this ); add_component( &revert_to_simuconf ); revert_to_default_sve.init( button_t::roundbox | button_t::flexible, "Default.sve"); revert_to_default_sve.add_listener( this ); add_component( &revert_to_default_sve); if (world()->type_of_generation != karte_t::AUTO_GENERATED && sets != &welt->get_settings()) { revert_to_last_save.init(button_t::roundbox | button_t::flexible, "Current game"); revert_to_last_save.add_listener(this); add_component(&revert_to_last_save); } } end_table(); general.init( sets ); display.init( sets ); economy.init( sets ); routing.init( sets ); costs.init( sets ); climates.init( sets ); scrolly_general.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_economy.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_routing.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_costs.set_scroll_amount_y(D_BUTTON_HEIGHT/2); scrolly_climates.set_scroll_amount_y(D_BUTTON_HEIGHT/2); tabs.add_tab(&scrolly_general, translator::translate("General")); tabs.add_tab(&scrolly_display, translator::translate("Display settings")); tabs.add_tab(&scrolly_economy, translator::translate("Economy")); tabs.add_tab(&scrolly_routing, translator::translate("Routing")); tabs.add_tab(&scrolly_costs, translator::translate("Costs")); tabs.add_tab(&scrolly_climates, translator::translate("Climate Control")); add_component(&tabs); reset_min_windowsize(); set_windowsize(get_min_windowsize() + general.get_min_size()); set_resizemode(diagonal_resize); } /* triggered, when button clicked; only single button registered, so the action is clear ... */ bool settings_frame_t::action_triggered( gui_action_creator_t *comp, value_t ) { // some things must stay the same when loading defaults std::string old_save = sets->get_filename(); sint32 old_number = sets->get_map_number(); uint8 old_rot = sets->get_rotation(); uint8 old_player_type[MAX_PLAYER_COUNT]; memcpy(old_player_type, sets->player_type, sizeof(old_player_type)); // now we can change values if( comp==&revert_to_simuconf ) { // reread from simucon.tab(s) the settings and apply them tabfile_t simuconf; env_t::init(); *sets = settings_t(); dr_chdir( env_t::base_dir ); if(simuconf.open("config/simuconf.tab")) { sets->parse_simuconf( simuconf ); sets->parse_colours( simuconf ); } stadt_t::cityrules_init(); dr_chdir( env_t::pak_dir.c_str() ); if(simuconf.open("config/simuconf.tab")) { sets->parse_simuconf( simuconf ); sets->parse_colours( simuconf ); } dr_chdir( env_t::user_dir ); if(simuconf.open("simuconf.tab")) { sets->parse_simuconf( simuconf ); sets->parse_colours( simuconf ); } simuconf.close(); // and update ... general.init( sets ); display.init( sets ); economy.init( sets ); routing.init( sets ); costs.init( sets ); climates.init( sets ); set_windowsize(get_windowsize()); } else if( comp==&revert_to_default_sve) { // load settings of last generated map dr_chdir( env_t::user_dir ); loadsave_t file; if( file.rd_open("default.sve") == loadsave_t::FILE_STATUS_OK ) { sets->rdwr(&file); sets->reset_after_global_settings_reload(); file.close(); } // and update ... general.init( sets ); display.init( sets ); economy.init( sets ); routing.init( sets ); costs.init( sets ); climates.init( sets ); set_windowsize(get_windowsize()); } else if (comp == &revert_to_last_save) { // setting of the current map *sets = env_t::default_settings; // and update ... general.init(sets); display.init(sets); economy.init(sets); routing.init(sets); costs.init(sets); climates.init(sets); set_windowsize(get_windowsize()); } // restore essential values sets->set_filename(old_save.c_str()); sets->map_number = old_number; sets->rotation = old_rot; memcpy(sets->player_type, old_player_type, sizeof(old_player_type)); return true; } bool settings_frame_t::infowin_event(const event_t *ev) { if( ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE ) { general.read( sets ); display.read( sets ); routing.read( sets ); economy.read( sets ); costs.read( sets ); climates.read( sets ); // only the rgb colours have been changed, the colours in system format must be updated env_t_rgb_to_system_colors(); } return gui_frame_t::infowin_event(ev); } simutrans-124.3/src/simutrans/gui/settings_frame.h000066400000000000000000000030151474050137200223350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SETTINGS_FRAME_H #define GUI_SETTINGS_FRAME_H #include "gui_frame.h" #include "components/gui_tab_panel.h" #include "components/gui_button.h" #include "components/gui_scrollpane.h" #include "settings_stats.h" #include "components/action_listener.h" class settings_t; /** * All messages since the start of the program */ class settings_frame_t : public gui_frame_t, action_listener_t { private: settings_t* sets; gui_tab_panel_t tabs; settings_general_stats_t general; gui_scrollpane_t scrolly_general; settings_display_stats_t display; gui_scrollpane_t scrolly_display; settings_economy_stats_t economy; gui_scrollpane_t scrolly_economy; settings_routing_stats_t routing; gui_scrollpane_t scrolly_routing; settings_costs_stats_t costs; gui_scrollpane_t scrolly_costs; settings_climates_stats_t climates; gui_scrollpane_t scrolly_climates; button_t revert_to_simuconf, revert_to_default_sve, revert_to_last_save; public: settings_frame_t(settings_t*); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "settings.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // does not work during new world dialogue bool has_sticky() const OVERRIDE { return false; } bool infowin_event(event_t const*) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/settings_stats.cc000066400000000000000000000744141474050137200225520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "welt.h" #include "simwin.h" #include "../simversion.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../player/finance.h" // MAX_PLAYER_HISTORY_YEARS #include "../vehicle/vehicle_base.h" #include "settings_stats.h" #include "components/gui_divider.h" /* stuff not set here .... INIT_NUM( "intercity_road_length", env_t::intercity_road_length); INIT_NUM( "diagonal_multiplier", pak_diagonal_multiplier); */ static char const* const version[] = { "0.99.17", "0.100.0", "0.101.0", "0.102.1", "0.102.2", "0.102.5", "0.110.0", "0.110.1", "0.111.0", "0.111.1", "0.111.2", "0.111.3", "0.111.4", "0.112.0", "0.112.2", "0.120.1", "0.120.2", "0.120.3", "0.120.4", "0.120.5", "122.0" }; bool settings_general_stats_t::action_triggered(gui_action_creator_t *comp, value_t v) { assert( comp==&savegame ); (void)comp; if( v.i==-1 ) { savegame.set_selection( 0 ); } return true; } /* Nearly automatic lists with controls: * BEWARE: The init exit pair MUST match in the same order or else!!! */ void settings_general_stats_t::init(settings_t const* const sets) { INIT_INIT // combobox for savegame version savegame.clear_elements(); for( uint32 i=0; i( version[i]+2, SYSCOL_TEXT ) ; if( strcmp(version[i],env_t::savegame_version_str)==0 ) { savegame.set_selection( i ); } } savegame.set_focusable( false ); add_component( &savegame ); savegame.add_listener( this ); INIT_LB( "savegame version" ); SEPERATOR INIT_BOOL( "drive_left", sets->is_drive_left() ); INIT_BOOL( "signals_on_left", sets->is_signals_left() ); SEPERATOR INIT_NUM( "autosave", env_t::autosave, 0, 12, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "fast_forward", env_t::max_acceleration, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_BOOL( "numbered_stations", sets->get_numbered_stations() ); INIT_NUM( "show_names", env_t::show_names, 0, 3, gui_numberinput_t::AUTOLINEAR, true ); SEPERATOR INIT_NUM( "bits_per_month", sets->get_bits_per_month(), 16, 24, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "use_timeline", sets->get_use_timeline(), 0, 3, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "starting_year", sets->get_starting_year(), 0, 2999, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "starting_month", sets->get_starting_month(), 0, 11, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "show_month", env_t::show_month, 0, 7, gui_numberinput_t::AUTOLINEAR, true ); SEPERATOR INIT_NUM( "random_grounds_probability", env_t::ground_object_probability, 0, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false ); INIT_NUM( "random_wildlife_probability", env_t::moving_object_probability, 0, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false ); SEPERATOR INIT_BOOL( "pedes_and_car_info", env_t::road_user_info ); INIT_BOOL( "tree_info", env_t::tree_info ); INIT_BOOL( "ground_info", env_t::ground_info ); INIT_BOOL( "townhall_info", env_t::townhall_info ); INIT_BOOL( "only_single_info", env_t::single_info ); SEPERATOR INIT_NUM( "compass_map_position", env_t::compass_map_position, 0, 16, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "compass_screen_position", env_t::compass_screen_position, 0, 16, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM( "world_maximum_height", sets->get_maximumheight(), 16, 127, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "world_minimum_height", sets->get_minimumheight(), -127, -12, gui_numberinput_t::AUTOLINEAR, false ); INIT_END clear_dirty(); } void settings_general_stats_t::read(settings_t* const sets) { READ_INIT int selected = savegame.get_selection(); if( 0 <= selected && (uint32)selected < lengthof(version) ) { env_t::savegame_version_str = version[ selected ]; } READ_BOOL_VALUE( sets->drive_on_left ); vehicle_base_t::set_overtaking_offsets( sets->drive_on_left ); READ_BOOL_VALUE( sets->signals_on_left ); READ_NUM_VALUE( env_t::autosave ); READ_NUM_VALUE( env_t::max_acceleration ); READ_BOOL_VALUE( sets->numbered_stations ); READ_NUM_VALUE( env_t::show_names ); READ_NUM_VALUE( sets->bits_per_month ); READ_NUM_VALUE( sets->use_timeline ); READ_NUM_VALUE_NEW( sets->starting_year ); READ_NUM_VALUE_NEW( sets->starting_month ); READ_NUM_VALUE( env_t::show_month ); READ_NUM_VALUE( env_t::ground_object_probability ); READ_NUM_VALUE( env_t::moving_object_probability ); READ_BOOL_VALUE( env_t::road_user_info ); READ_BOOL_VALUE( env_t::tree_info ); READ_BOOL_VALUE( env_t::ground_info ); READ_BOOL_VALUE( env_t::townhall_info ); READ_BOOL_VALUE( env_t::single_info ); READ_NUM_VALUE( env_t::compass_map_position ); READ_NUM_VALUE( env_t::compass_screen_position ); READ_NUM_VALUE( sets->world_maximum_height ); READ_NUM_VALUE( sets->world_minimum_height ); } void settings_display_stats_t::init(settings_t const* const) { INIT_INIT INIT_NUM( "frames_per_second",env_t::fps, env_t::min_fps, env_t::max_fps, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "fast_forward_frames_per_second", env_t::ff_fps, env_t::min_fps, env_t::max_fps, gui_numberinput_t::AUTOLINEAR, false); INIT_NUM( "simple_drawing_tile_size",env_t::simple_drawing_default, 2, 256, gui_numberinput_t::POWER2, false ); INIT_BOOL( "simple_drawing_fast_forward",env_t::simple_drawing_fast_forward ); INIT_NUM( "water_animation_ms", env_t::water_animation, 0, 1000, 25, false ); INIT_NUM( "follow_convoi_underground", env_t::follow_convoi_underground, 0, 2, 1, true ); SEPERATOR INIT_BOOL( "window_buttons_right", env_t::window_buttons_right ); INIT_BOOL( "window_frame_active", env_t::window_frame_active ); INIT_COLOR( "default_window_title_color", env_t::default_window_title_color_rgb, gui_numberinput_t::AUTOLINEAR ); INIT_COLOR( "front_window_text_color", env_t::front_window_text_color_rgb, gui_numberinput_t::AUTOLINEAR ); INIT_COLOR( "bottom_window_text_color", env_t::bottom_window_text_color_rgb, gui_numberinput_t::AUTOLINEAR ); INIT_NUM( "bottom_window_darkness", env_t::bottom_window_darkness, 0, 100, gui_numberinput_t::AUTOLINEAR, 0 ); SEPERATOR INIT_BOOL( "show_tooltips", env_t::show_tooltips ); INIT_COLOR( "tooltip_background_color", env_t::tooltip_color_rgb, 1 ); INIT_COLOR( "tooltip_text_color", env_t::tooltip_textcolor_rgb, 1 ); INIT_NUM( "tooltip_delay", env_t::tooltip_delay, 0, 10000, gui_numberinput_t::AUTOLINEAR, 0 ); INIT_NUM( "tooltip_duration", env_t::tooltip_duration, 0, 30000, gui_numberinput_t::AUTOLINEAR, 0 ); SEPERATOR INIT_COLOR( "cursor_overlay_color", env_t::cursor_overlay_color_rgb, gui_numberinput_t::AUTOLINEAR ); INIT_BOOL( "left_to_right_graphs", env_t::left_to_right_graphs ); SEPERATOR INIT_BOOL( "player_finance_display_account", env_t::player_finance_display_account ); INIT_END } void settings_display_stats_t::read(settings_t* const) { READ_INIT // all visual stuff READ_NUM_VALUE( env_t::fps ); READ_NUM_VALUE( env_t::ff_fps ); READ_NUM_VALUE( env_t::simple_drawing_default ); READ_BOOL_VALUE( env_t::simple_drawing_fast_forward ); READ_NUM_VALUE( env_t::water_animation ); READ_NUM_VALUE( env_t::follow_convoi_underground ); READ_BOOL_VALUE( env_t::window_buttons_right ); READ_BOOL_VALUE( env_t::window_frame_active ); READ_COL_VALUE( env_t::default_window_title_color_rgb ); READ_COL_VALUE( env_t::front_window_text_color_rgb ); READ_COL_VALUE( env_t::bottom_window_text_color_rgb ); READ_NUM_VALUE( env_t::bottom_window_darkness ); READ_BOOL_VALUE( env_t::show_tooltips ); READ_COL_VALUE( env_t::tooltip_color_rgb ); READ_COL_VALUE( env_t::tooltip_textcolor_rgb ); READ_NUM_VALUE( env_t::tooltip_delay ); READ_NUM_VALUE( env_t::tooltip_duration ); READ_COL_VALUE( env_t::cursor_overlay_color_rgb ); READ_BOOL_VALUE( env_t::left_to_right_graphs ); READ_BOOL_VALUE( env_t::player_finance_display_account ); } void settings_routing_stats_t::init(settings_t const* const sets) { INIT_INIT INIT_BOOL( "separate_halt_capacities", sets->is_separate_halt_capacities() ); INIT_BOOL( "avoid_overcrowding", sets->is_avoid_overcrowding() ); INIT_BOOL( "no_routing_over_overcrowded", sets->is_no_routing_over_overcrowding() ); INIT_NUM( "station_coverage", sets->get_station_coverage(), 1, 8, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "allow_merge_distant_halt", sets->get_allow_merge_distant_halt(), 0, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false ); SEPERATOR INIT_NUM( "max_route_steps", sets->get_max_route_steps(), 1, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false ); INIT_NUM( "max_choose_route_steps", sets->get_max_choose_route_steps(), 1, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false ); INIT_NUM( "max_hops", sets->get_max_hops(), 100, 65000, gui_numberinput_t::POWER2, false ); INIT_NUM( "max_transfers", sets->get_max_transfers(), 1, 100, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM( "way_straight", sets->way_count_straight, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_curve", sets->way_count_curve, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_double_curve", sets->way_count_double_curve, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_90_curve", sets->way_count_90_curve, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_slope", sets->way_count_slope, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_tunnel", sets->way_count_tunnel, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_max_bridge_len", sets->way_max_bridge_len, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "way_leaving_road", sets->way_count_leaving_way, 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_BOOL( "stop_halt_as_scheduled", sets->get_stop_halt_as_scheduled() ); INIT_END } void settings_routing_stats_t::read(settings_t* const sets) { READ_INIT // routing of goods READ_BOOL_VALUE( sets->separate_halt_capacities ); READ_BOOL_VALUE( sets->avoid_overcrowding ); READ_BOOL_VALUE( sets->no_routing_over_overcrowding ); READ_NUM_VALUE( sets->station_coverage_size ); READ_NUM_VALUE( sets->allow_merge_distant_halt ); READ_NUM_VALUE( sets->max_route_steps ); READ_NUM_VALUE( sets->max_choose_route_steps ); READ_NUM_VALUE( sets->max_hops ); READ_NUM_VALUE( sets->max_transfers ); // routing on ways READ_NUM_VALUE( sets->way_count_straight ); READ_NUM_VALUE( sets->way_count_curve ); READ_NUM_VALUE( sets->way_count_double_curve ); READ_NUM_VALUE( sets->way_count_90_curve ); READ_NUM_VALUE( sets->way_count_slope ); READ_NUM_VALUE( sets->way_count_tunnel ); READ_NUM_VALUE( sets->way_max_bridge_len ); READ_NUM_VALUE( sets->way_count_leaving_way ); READ_BOOL_VALUE( sets->stop_halt_as_scheduled ); } void settings_economy_stats_t::init(settings_t const* const sets) { INIT_INIT INIT_NUM( "remove_dummy_player_months", sets->get_remove_dummy_player_months(), 0, MAX_PLAYER_HISTORY_YEARS*12, 12, false ); INIT_NUM( "unprotect_abandoned_player_months", sets->get_unprotect_abandoned_player_months(), 0, MAX_PLAYER_HISTORY_YEARS*12, 12, false ); INIT_NUM( "ai_construction_speed", sets->get_default_ai_construction_speed(), 0, 1000000000, 1000, false ); SEPERATOR INIT_COST( "starting_money", sets->get_starting_money(sets->get_starting_year()), 1, 0x7FFFFFFFul, 10000, false ); INIT_NUM( "pay_for_total_distance", sets->get_pay_for_total_distance_mode(), 0, 2, gui_numberinput_t::AUTOLINEAR, true ); INIT_NUM( "bonus_basefactor", sets->get_bonus_basefactor(), 0, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_BOOL_NEW( "first_beginner", sets->get_beginner_mode() ); INIT_NUM( "beginner_price_factor", sets->get_beginner_price_factor(), 1, 25000, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_BOOL( "allow_buying_obsolete_vehicles", sets->get_allow_buying_obsolete_vehicles() ); INIT_NUM( "used_vehicle_reduction", sets->get_used_vehicle_reduction(), 1, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_rail_convoi_length", sets->get_max_rail_convoi_length(), 1, 254, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_road_convoi_length", sets->get_max_road_convoi_length(), 1, 254, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_ship_convoi_length", sets->get_max_ship_convoi_length(), 1, 254, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_air_convoi_length", sets->get_max_air_convoi_length(), 1, 254, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM( "toll_runningcost_percentage", sets->get_way_toll_runningcost_percentage(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "toll_waycost_percentage", sets->get_way_toll_waycost_percentage(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_BOOL("disable_make_way_public", sets->get_disable_make_way_public()); SEPERATOR INIT_NUM( "just_in_time", sets->get_just_in_time(), 0, 2, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "maximum_intransit_percentage", sets->get_factory_maximum_intransit_percentage(), 0, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_BOOL( "crossconnect_factories", sets->is_crossconnect_factories() ); INIT_NUM( "crossconnect_factories_percentage", sets->get_crossconnect_factor(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "industry_increase_every", sets->get_industry_increase_every(), 0, 100000, 100, false ); INIT_NUM( "min_factory_spacing", sets->get_min_factory_spacing(), 1, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_factory_spacing_percent", sets->get_max_factory_spacing_percent(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "max_factory_spacing", sets->get_max_factory_spacing(), 1, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "electric_promille", sets->get_electric_promille(), 0, 1000, gui_numberinput_t::AUTOLINEAR, false ); INIT_BOOL( "allow_underground_transformers", sets->get_allow_underground_transformers() ); INIT_NUM( "way_height_clearance", sets->get_way_height_clearance(), 1, 2, gui_numberinput_t::AUTOLINEAR, true ); SEPERATOR INIT_NUM( "passenger_factor", sets->get_passenger_factor(), 0, 16, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "minimum_city_distance", sets->get_minimum_city_distance(), 1, 20000, 10, false ); INIT_NUM( "special_building_distance", sets->get_special_building_distance(), 1, 150, 1, false ); INIT_NUM( "factory_worker_radius", sets->get_factory_worker_radius(), 0, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "factory_worker_minimum_towns", sets->get_factory_worker_minimum_towns(), 0, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "factory_worker_maximum_towns", sets->get_factory_worker_maximum_towns(), 0, 32767, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "factory_arrival_periods", sets->get_factory_arrival_periods(), 1, 16, gui_numberinput_t::AUTOLINEAR, false ); INIT_BOOL( "factory_enforce_demand", sets->get_factory_enforce_demand() ); INIT_NUM( "factory_worker_percentage", sets->get_factory_worker_percentage(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "tourist_percentage", sets->get_tourist_percentage(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM( "locality_factor[0].year", sets->locality_factor_per_year[0].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[0].factor", sets->locality_factor_per_year[0].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[1].year", sets->locality_factor_per_year[1].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[1].factor", sets->locality_factor_per_year[1].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[2].year", sets->locality_factor_per_year[2].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[2].factor", sets->locality_factor_per_year[2].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[3].year", sets->locality_factor_per_year[3].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[3].factor", sets->locality_factor_per_year[3].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[4].year", sets->locality_factor_per_year[4].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[4].factor", sets->locality_factor_per_year[4].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[5].year", sets->locality_factor_per_year[5].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[5].factor", sets->locality_factor_per_year[5].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[6].year", sets->locality_factor_per_year[6].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[6].factor", sets->locality_factor_per_year[6].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[7].year", sets->locality_factor_per_year[7].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[7].factor", sets->locality_factor_per_year[7].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[8].year", sets->locality_factor_per_year[8].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[8].factor", sets->locality_factor_per_year[8].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); INIT_NUM( "locality_factor[9].year", sets->locality_factor_per_year[9].year, 0, 2999, 10, false ); INIT_NUM( "locality_factor[9].factor", sets->locality_factor_per_year[9].factor, 1, 0x7FFFFFFFu, gui_numberinput_t::POWER2, false ); SEPERATOR INIT_NUM( "passenger_multiplier", sets->get_passenger_multiplier(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "mail_multiplier", sets->get_mail_multiplier(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM( "goods_multiplier", sets->get_goods_multiplier(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); // INIT_NUM( "electricity_multiplier", sets->get_electricity_multiplier(), 0, 10000, 10, false ); SEPERATOR INIT_NUM( "growthfactor_villages", sets->get_growthfactor_small(), 1, 10000, 10, false ); INIT_NUM( "growthfactor_cities", sets->get_growthfactor_medium(), 1, 10000, 10, false ); INIT_NUM( "growthfactor_capitals", sets->get_growthfactor_large(), 1, 10000, 10, false ); SEPERATOR INIT_BOOL( "random_pedestrians", env_t::random_pedestrians); INIT_BOOL( "stop_pedestrians", env_t::stop_pedestrians); INIT_NUM( "citycar_level", sets->get_traffic_level(), 0, 16, 1, false ); INIT_NUM( "default_citycar_life", sets->get_stadtauto_duration(), 1, 1200, 12, false ); INIT_END } void settings_economy_stats_t::read(settings_t* const sets) { READ_INIT sint64 start_money_temp; READ_NUM_VALUE( sets->remove_dummy_player_months ); READ_NUM_VALUE( sets->unprotect_abandoned_player_months ); READ_NUM_VALUE( sets->default_ai_construction_speed ); env_t::default_ai_construction_speed = sets->get_default_ai_construction_speed(); READ_COST_VALUE( start_money_temp ); if( sets->get_starting_money(sets->get_starting_year())!=start_money_temp ) { // because this will render the table based values invalid, we do this only when needed sets->starting_money = start_money_temp; } READ_NUM_VALUE( sets->pay_for_total_distance ); READ_NUM_VALUE( sets->bonus_basefactor ); READ_BOOL_VALUE_NEW( sets->beginner_mode ); READ_NUM_VALUE( sets->beginner_price_factor ); READ_BOOL_VALUE( sets->allow_buying_obsolete_vehicles ); READ_NUM_VALUE( sets->used_vehicle_reduction ); READ_NUM_VALUE( sets->max_rail_convoi_length ); READ_NUM_VALUE( sets->max_road_convoi_length ); READ_NUM_VALUE( sets->max_ship_convoi_length ); READ_NUM_VALUE( sets->max_air_convoi_length ); READ_NUM_VALUE( sets->way_toll_runningcost_percentage ); READ_NUM_VALUE( sets->way_toll_waycost_percentage ); READ_BOOL_VALUE(sets->disable_make_way_public); READ_NUM_VALUE( env_t::just_in_time ); sets->just_in_time = env_t::just_in_time; READ_NUM_VALUE( sets->factory_maximum_intransit_percentage ); READ_BOOL_VALUE( sets->crossconnect_factories ); READ_NUM_VALUE( sets->crossconnect_factor ); READ_NUM_VALUE( sets->industry_increase ); READ_NUM_VALUE( sets->min_factory_spacing ); READ_NUM_VALUE( sets->max_factory_spacing_percentage ); READ_NUM_VALUE( sets->max_factory_spacing ); READ_NUM_VALUE( sets->electric_promille ); READ_BOOL_VALUE( sets->allow_underground_transformers ); READ_NUM_VALUE( sets->way_height_clearance ); READ_NUM_VALUE( sets->passenger_factor ); READ_NUM_VALUE( sets->minimum_city_distance ); READ_NUM_VALUE( sets->special_building_distance ); READ_NUM_VALUE( sets->factory_worker_radius ); READ_NUM_VALUE( sets->factory_worker_minimum_towns ); READ_NUM_VALUE( sets->factory_worker_maximum_towns ); READ_NUM_VALUE( sets->factory_arrival_periods ); READ_BOOL_VALUE( sets->factory_enforce_demand ); READ_NUM_VALUE( sets->factory_worker_percentage ); READ_NUM_VALUE( sets->tourist_percentage ); for( int i=0; i<10; i++ ) { READ_NUM_VALUE( sets->locality_factor_per_year[i].year ); READ_NUM_VALUE( sets->locality_factor_per_year[i].factor ); } READ_NUM_VALUE( sets->passenger_multiplier ); READ_NUM_VALUE( sets->mail_multiplier ); READ_NUM_VALUE( sets->goods_multiplier ); // READ_NUM_VALUE( sets->set_electricity_multiplier ); READ_NUM_VALUE( sets->growthfactor_small ); READ_NUM_VALUE( sets->growthfactor_medium ); READ_NUM_VALUE( sets->growthfactor_large ); READ_BOOL_VALUE( env_t::random_pedestrians ); READ_BOOL_VALUE( env_t::stop_pedestrians ); READ_NUM( sets->set_traffic_level ); READ_NUM_VALUE( sets->stadtauto_duration ); } void settings_costs_stats_t::init(settings_t const* const sets) { INIT_INIT INIT_NUM( "maintenance_building", sets->maint_building, 1, 100000000, 100, false ); INIT_COST( "cost_multiply_dock", -sets->cst_multiply_dock, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_station", -sets->cst_multiply_station, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_roadstop", -sets->cst_multiply_roadstop, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_airterminal", -sets->cst_multiply_airterminal, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_post", -sets->cst_multiply_post, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_headquarter", -sets->cst_multiply_headquarter, 1, 100000000, 10, false ); INIT_COST( "cost_depot_air", -sets->cst_depot_air, 1, 100000000, 10, false ); INIT_COST( "cost_depot_rail", -sets->cst_depot_rail, 1, 100000000, 10, false ); INIT_COST( "cost_depot_road", -sets->cst_depot_road, 1, 100000000, 10, false ); INIT_COST( "cost_depot_ship", -sets->cst_depot_ship, 1, 100000000, 10, false ); INIT_COST( "cost_buy_land", -sets->cst_buy_land, 1, 100000000, 10, false ); INIT_COST( "cost_alter_land", -sets->cst_alter_land, 1, 100000000, 10, false ); INIT_COST( "cost_set_slope", -sets->cst_set_slope, 1, 100000000, 10, false ); INIT_COST( "cost_alter_climate", -sets->cst_alter_climate, 1, 100000000, 10, false ); INIT_COST( "cost_found_city", -sets->cst_found_city, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_found_industry", -sets->cst_multiply_found_industry, 1, 100000000, 10, false ); INIT_COST( "cost_remove_tree", -sets->cst_remove_tree, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_remove_haus", -sets->cst_multiply_remove_haus, 1, 100000000, 10, false ); INIT_COST( "cost_multiply_remove_field", -sets->cst_multiply_remove_field, 1, 100000000, 10, false ); INIT_COST( "cost_transformer", -sets->cst_transformer, 1, 100000000, 10, false ); INIT_COST( "cost_maintain_transformer", -sets->cst_maintain_transformer, 1, 100000000, 10, false ); INIT_NUM("cost_make_public_months", sets->cst_make_public_months, 0, 36000, gui_numberinput_t::AUTOLINEAR, false ); INIT_END } void settings_costs_stats_t::read(settings_t* const sets) { READ_INIT (void)booliter; READ_NUM_VALUE( sets->maint_building ); READ_COST_VALUE( sets->cst_multiply_dock )*(-1); READ_COST_VALUE( sets->cst_multiply_station )*(-1); READ_COST_VALUE( sets->cst_multiply_roadstop )*(-1); READ_COST_VALUE( sets->cst_multiply_airterminal )*(-1); READ_COST_VALUE( sets->cst_multiply_post )*(-1); READ_COST_VALUE( sets->cst_multiply_headquarter )*(-1); READ_COST_VALUE( sets->cst_depot_air )*(-1); READ_COST_VALUE( sets->cst_depot_rail )*(-1); READ_COST_VALUE( sets->cst_depot_road )*(-1); READ_COST_VALUE( sets->cst_depot_ship )*(-1); READ_COST_VALUE( sets->cst_buy_land )*(-1); READ_COST_VALUE( sets->cst_alter_land )*(-1); READ_COST_VALUE( sets->cst_set_slope )*(-1); READ_COST_VALUE( sets->cst_alter_climate )*(-1); READ_COST_VALUE( sets->cst_found_city )*(-1); READ_COST_VALUE( sets->cst_multiply_found_industry )*(-1); READ_COST_VALUE( sets->cst_remove_tree )*(-1); READ_COST_VALUE( sets->cst_multiply_remove_haus )*(-1); READ_COST_VALUE( sets->cst_multiply_remove_field )*(-1); READ_COST_VALUE( sets->cst_transformer )*(-1); READ_COST_VALUE( sets->cst_maintain_transformer )*(-1); READ_NUM_VALUE(sets->cst_make_public_months); } #include "../descriptor/ground_desc.h" static char const * const climate_generate_string[] = { "height based", "temperature-humidity based" }; static char const * const tree_generate_string[] = { "none", "random", "rainfall" }; void settings_climates_stats_t::init(settings_t* const sets) { int mountain_height_start = (int)sets->get_max_mountain_height(); int mountain_roughness_start = (int)(sets->get_map_roughness()*20.0 + 0.5)-8; local_sets = sets; INIT_INIT INIT_NUM_NEW( "height_map_conversion_version", env_t::pak_height_conversion_factor, 1, 2, 0, false ); SEPERATOR INIT_NUM_NEW( "Water level", sets->get_groundwater(), -20*(ground_desc_t::double_grounds?2:1), 20, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "Mountain height", mountain_height_start, 0, min(1000,100*(11-mountain_roughness_start)), 10, false ); INIT_NUM_NEW( "Map roughness", mountain_roughness_start, 0, min(10, 11-((mountain_height_start+99)/100)), gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM_NEW( "Wind direction", sets->wind_direction, 0, 3, 1, true ); // combobox for climate generator climate_generate.clear_elements(); for( uint32 i=0; i( climate_generate_string[i], SYSCOL_TEXT ) ; } climate_generate.set_selection( sets->get_climate_generator() ); climate_generate.set_focusable( false ); add_component( &climate_generate ); INIT_LB( "climate generator" ); add_table(3,0); { // other climate borders ... for( int i=desert_climate; i<=arctic_climate; i++ ) { INIT_NUM( ground_desc_t::get_climate_name_from_bit((climate)i), sets->get_climate_borders(i,0), sets->get_groundwater(), 127, gui_numberinput_t::AUTOLINEAR, false ); gui_numberinput_t *ni = new_component(); ni->init( sets->get_climate_borders(i,1), sets->get_groundwater(), 127, gui_numberinput_t::AUTOLINEAR, false ); numinp.append( ni ); } } end_table(); new_component(); INIT_NUM_NEW( "climate area percentage", sets->get_patch_size_percentage(), 0, 100, gui_numberinput_t::AUTOLINEAR, false ); SEPERATOR INIT_NUM_NEW( "lake_height", sets->get_lakeheight(), 0, 127, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "Number of rivers", sets->get_river_number(), 0, 1024, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "minimum length of rivers", sets->get_min_river_length(), 0, max(16,sets->get_max_river_length())-16, gui_numberinput_t::AUTOLINEAR, false ); INIT_NUM_NEW( "maximum length of rivers", sets->get_max_river_length(), sets->get_min_river_length()+16, 8196, gui_numberinput_t::AUTOLINEAR, false ); // add listener to all of them for(gui_numberinput_t* const n : numinp) { n->add_listener(this); } // the following are independent and thus need no listener SEPERATOR // combobox for trees generator tree_generate.clear_elements(); for( uint32 i=0; i( tree_generate_string[i], SYSCOL_TEXT ) ; } tree_generate.set_selection( sets->get_tree_distribution() ); tree_generate.set_focusable( false ); add_component( &tree_generate, 2); INIT_NUM_NEW( "forest_base_size", sets->get_forest_base_size(), 10, 255, 1, false ); INIT_NUM_NEW( "forest_map_size_divisor", sets->get_forest_map_size_divisor(), 2, 255, 1, false ); INIT_NUM_NEW( "forest_count_divisor", sets->get_forest_count_divisor(), 2, 255, 1, false ); INIT_NUM_NEW( "forest_inverse_spare_tree_density", sets->get_forest_inverse_spare_tree_density(), 33, 10000, 10, false ); INIT_NUM( "max_no_of_trees_on_square", sets->get_max_no_of_trees_on_square(), 1, 5, 1, true ); INIT_NUM_NEW( "tree_climates", sets->get_tree_climates(), 0, 255, 1, false ); INIT_NUM_NEW( "no_tree_climates", sets->get_no_tree_climates(), 0, 255, 1, false ); INIT_END } void settings_climates_stats_t::read(settings_t* const sets) { sets->climate_generator = (settings_t::climate_generate_t)max( 0, climate_generate.get_selection() ); sets->tree_distribution = ::clamp(tree_generate.get_selection(), (int)settings_t::TREE_DIST_NONE, (int)settings_t::TREE_DIST_COUNT-1 ); READ_INIT READ_NUM_VALUE_NEW( env_t::pak_height_conversion_factor ); READ_NUM_VALUE_NEW( sets->groundwater ); READ_NUM_VALUE_NEW( sets->max_mountain_height ); READ_NUM_VALUE_NEW( sets->wind_direction ); double n = 0; READ_NUM_VALUE_NEW( n ); if( new_world ) { sets->map_roughness = (n+8.0)/20.0; } // other climate borders ... for( int i=desert_climate; i<=arctic_climate; i++ ) { sint16 ch; READ_NUM_VALUE( ch ); sets->climate_borders[i][0] = ch; READ_NUM_VALUE( ch ); sets->climate_borders[i][1] = ch; } READ_NUM_VALUE_NEW( sets->patch_size_percentage ); READ_NUM_VALUE_NEW( sets->lake_height ); READ_NUM_VALUE_NEW( sets->river_number ); READ_NUM_VALUE_NEW( sets->min_river_length ); READ_NUM_VALUE_NEW( sets->max_river_length ); READ_NUM_VALUE_NEW( sets->forest_base_size ); READ_NUM_VALUE_NEW( sets->forest_map_size_divisor ); READ_NUM_VALUE_NEW( sets->forest_count_divisor ); READ_NUM_VALUE_NEW( sets->forest_inverse_spare_tree_density ); READ_NUM_VALUE( sets->max_no_of_trees_on_square ); READ_NUM_VALUE_NEW( sets->tree_climates ); READ_NUM_VALUE_NEW( sets->no_tree_climates ); (void)booliter; // silence warning } bool settings_climates_stats_t::action_triggered(gui_action_creator_t *comp, value_t) { welt_gui_t *welt_gui = dynamic_cast(win_get_magic( magic_welt_gui_t )); read( local_sets ); uint i = 0; for(gui_numberinput_t* const n : numinp) { if (n == comp && i < 3 && welt_gui) { // update world preview welt_gui->update_preview(); } i++; } return true; } simutrans-124.3/src/simutrans/gui/settings_stats.h000066400000000000000000000123771474050137200224140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SETTINGS_STATS_H #define GUI_SETTINGS_STATS_H #include #include "../tpl/vector_tpl.h" #include "../utils/cbuffer.h" #include "components/gui_container.h" #include "components/gui_component.h" #include "components/gui_numberinput.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "components/gui_combobox.h" class settings_t; /* With the following macros, elements could be added to the property lists. * ATTENTION: In the init and read procedures, the order of the items MUST be identical! */ // call this before any init is done ... #define INIT_INIT \ new_world = (win_get_magic( magic_welt_gui_t )!=NULL);\ numinp.clear(); \ button.clear(); \ remove_all(); \ set_table_layout(1,0); \ add_table(2,0); // at the end of init #define INIT_END \ end_table();\ set_size( get_min_size()); #define INIT_NUM(t,a,b,c,d,e) \ {\ gui_numberinput_t *ni = new_component();\ ni->init( (sint32)(a), (b), (c), (d), (e) );\ numinp.append( ni );\ gui_label_t *lb = new_component();\ lb->set_text_pointer(t);\ } #define INIT_NUM_NEW(t,a,b,c,d,e) if( new_world ) INIT_NUM( (t), (a), (b), (c), (d) , (e) ) #define INIT_COLOR(t,val,step) {\ gui_numberinput_t *ni = new_component();\ ni->init((sint32)((val).r << 16 | (val).g << 8 | (val).b), 0, 0x00FFFFFF, (step), 0);\ numinp.append(ni);\ gui_label_t *lb = new_component();\ lb->set_text_pointer(t);\ } #define INIT_COLOR_NEW(t,val,step) if (new_world) INIT_COLOR( (t), (val), (step) ) #define INIT_COST(t,a,b,c,d,e) \ {\ gui_numberinput_t *ni = new_component();\ ni->init( (sint32)( (a)/(sint64)100 ), (b), (c), (d), (e) );\ numinp.append( ni );\ gui_label_t *lb = new_component();\ lb->set_text_pointer(t);\ }\ #define INIT_COST_NEW(t,a,b,c,d,e) if( new_world ) INIT_COST( (t), (a), (b), (c), (d) , (e) ) #define INIT_LB(t) \ {\ gui_label_t *lb = new_component();\ lb->set_text_pointer(t);\ }\ #define INIT_LB_NEW(t) if( new_world ) INIT_LB( (t) ) #define INIT_BOOL(t,a) \ {\ button_t *bt = new_component_span(2);\ bt->init(button_t::square_automatic, (t));\ button.append( bt );\ bt->pressed = (a);\ }\ #define INIT_BOOL_NEW(t,a) if( new_world ) INIT_BOOL( (t), (a) ) #define SEPERATOR \ new_component_span(2); // call this before and READ_... #define READ_INIT \ slist_tpl::const_iterator numiter = numinp.begin(); \ slist_tpl::const_iterator booliter = button.begin(); #define READ_NUM(t) (t)((*numiter++)->get_value()) #define READ_NUM_NEW(t) if(new_world) { READ_NUM(t); } #define READ_COST(t) (t)((sint64)((*numiter++)->get_value()) * 100) #define READ_NUM_VALUE(t) (t) = (*numiter++)->get_value() #define READ_NUM_VALUE_NEW(t) if(new_world) { READ_NUM_VALUE(t); } #define READ_COL_VALUE(t) do { const uint32_t v = (*numiter++)->get_value(); (t).r = v >> 16; (t).g = v >> 8; (t).b = v; } while (false) #define READ_COL_VALUE_NEW(t) if (new_world) { READ_COL_VALUE(t); } #define READ_COST_VALUE(t) (t) = (sint64)((*numiter++)->get_value()) * 100 #define READ_COST_VALUE_NEW(t) if(new_world) { READ_COST_VALUE(t); } #define READ_BOOL(t) (t)((*booliter++)->pressed) #define READ_BOOL_NEW(t) if(new_world) { READ_BOOL(t); } #define READ_BOOL_VALUE(t) (t) = (*booliter++)->pressed #define READ_BOOL_VALUE_NEW(t) if(new_world) { READ_BOOL_VALUE(t); } /** * Settings for property lists */ class settings_stats_t { protected: bool new_world; // since the copy constructor will not copy the right action listener => pointer slist_tpl numinp; slist_tpl button; public: settings_stats_t() {} void init(settings_t const*); void read(settings_t const*); }; // the only task left are the respective init/reading routines class settings_general_stats_t : protected settings_stats_t, public gui_aligned_container_t, public action_listener_t { gui_combobox_t savegame; public: // needed for savegame combobox bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void init(settings_t const*); void read(settings_t*); }; class settings_display_stats_t : protected settings_stats_t, public gui_aligned_container_t { public: void init(settings_t const*); void read(settings_t*); }; class settings_routing_stats_t : protected settings_stats_t, public gui_aligned_container_t { public: void init(settings_t const*); void read(settings_t*); }; class settings_economy_stats_t : protected settings_stats_t, public gui_aligned_container_t { public: void init(settings_t const*); void read(settings_t*); }; class settings_costs_stats_t : protected settings_stats_t, public gui_aligned_container_t { public: void init(settings_t const*); void read(settings_t*); }; class settings_climates_stats_t : protected settings_stats_t, public gui_aligned_container_t, public action_listener_t { private: gui_combobox_t climate_generate; gui_combobox_t tree_generate; settings_t* local_sets; public: void init(settings_t*); void read(settings_t*); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/signal_info.cc000066400000000000000000000026331474050137200217560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "components/gui_label.h" #include "../obj/signal.h" #include "../player/simplay.h" #include "signal_info.h" #include "../tool/simmenu.h" #include "../world/simworld.h" signal_info_t::signal_info_t(signal_t *s) : obj_infowin_t(s), sig(s) { remove.init( button_t::roundbox, "remove signal"); remove.add_listener( this ); add_component( &remove ); // show author below the settings if( char const* const maker = sig->get_desc()->get_copyright() ) { gui_label_buf_t* lb = new_component(); lb->buf().printf(translator::translate("Constructed by %s"), maker); lb->update(); } recalc_size(); } bool signal_info_t::action_triggered( gui_action_creator_t *, value_t /* */) { bool suspended_execution=false; koord3d pos = sig->get_pos(); tool_t::general_tool[TOOL_REMOVE_SIGNAL]->set_default_param(NULL); const char *err = welt->call_work_api( tool_t::general_tool[TOOL_REMOVE_SIGNAL], welt->get_active_player(), pos, suspended_execution); if(!suspended_execution) { // play sound / error message welt->get_active_player()->tell_tool_result(tool_t::general_tool[TOOL_REMOVE_SIGNAL], pos, err); } return true; } void signal_info_t::draw( scr_coord pos, scr_size size ) { remove.enable( !sig->get_removal_error( welt->get_active_player() ) ); obj_infowin_t::draw( pos, size ); } simutrans-124.3/src/simutrans/gui/signal_info.h000066400000000000000000000013361474050137200216170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SIGNAL_INFO_H #define GUI_SIGNAL_INFO_H #include "../simconst.h" #include "obj_info.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_container.h" class signal_t; /** * Info window for factories */ class signal_info_t : public obj_infowin_t, public action_listener_t { private: button_t remove; signal_t *sig; public: signal_info_t(signal_t *s); const char *get_help_filename() const OVERRIDE {return "signal_info.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void draw( scr_coord pos, scr_size size ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/signal_spacing.cc000066400000000000000000000035111474050137200224430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "components/gui_numberinput.h" #include "signal_spacing.h" #include "../tool/simtool.h" uint8 signal_spacing_frame_t::signal_spacing = 2; bool signal_spacing_frame_t::remove = true; bool signal_spacing_frame_t::replace = true; signal_spacing_frame_t::signal_spacing_frame_t(player_t *player_, tool_build_roadsign_t* tool_) : gui_frame_t( translator::translate("set signal spacing") ), signal_label("signal spacing") { player = player_; tool = tool_; tool->get_values(player, signal_spacing, remove, replace); set_table_layout(3,0); add_component( &signal_label ); new_component(); signal_spacing_inp.add_listener(this); signal_spacing_inp.init(signal_spacing, 1, 50, 1, true, 3); add_component( &signal_spacing_inp ); remove_button.init( button_t::square_state, "remove interm. signals"); remove_button.add_listener(this); remove_button.pressed = remove; add_component( &remove_button, 3); replace_button.init( button_t::square_state, "replace other signals"); replace_button.add_listener(this); replace_button.pressed = replace; add_component( &replace_button, 3); reset_min_windowsize(); set_windowsize(get_min_windowsize() ); } bool signal_spacing_frame_t::action_triggered( gui_action_creator_t *comp, value_t) { if( comp == &signal_spacing_inp ) { signal_spacing = signal_spacing_inp.get_value(); } else if( comp == &remove_button ) { remove = !remove; remove_button.pressed = remove; } else if( comp == &replace_button ) { replace = !replace; replace_button.pressed = replace; } tool->set_values(player, signal_spacing, remove, replace); return true; } simutrans-124.3/src/simutrans/gui/signal_spacing.h000066400000000000000000000020461474050137200223070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SIGNAL_SPACING_H #define GUI_SIGNAL_SPACING_H #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_numberinput.h" #include "components/gui_label.h" class gui_numberinput_t; class button_t; class gui_label_t; class tool_build_roadsign_t; class player_t; /* * Dialogue to set the signal spacing, when CTRL+clicking a signal on toolbar * Used by tool_build_roadsign_t */ class signal_spacing_frame_t : public gui_frame_t, private action_listener_t { private: static uint8 signal_spacing; static bool remove, replace; player_t *player; tool_build_roadsign_t* tool; gui_numberinput_t signal_spacing_inp; gui_label_t signal_label; button_t remove_button, replace_button; public: signal_spacing_frame_t( player_t *, tool_build_roadsign_t * ); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; const char * get_help_filename() const OVERRIDE { return "signal_spacing.txt"; } }; #endif simutrans-124.3/src/simutrans/gui/simwin.cc000066400000000000000000002213721474050137200207770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simcolor.h" #include "../simevent.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "../sys/simsys.h" #include "../simticker.h" #include "simwin.h" #include "../simintr.h" #include "../simhalt.h" #include "../world/simworld.h" #include "../utils/simrandom.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" #include "../dataobj/tabfile.h" #include "../descriptor/skin_desc.h" #include "../obj/zeiger.h" #include "../player/simplay.h" #include "../tpl/inthashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "map_frame.h" #include "help_frame.h" #include "messagebox.h" #include "gui_frame.h" // needed to restore/save them #include "tool_selector.h" #include "player_frame.h" #include "money_frame.h" #include "halt_info.h" #include "convoi_detail.h" #include "convoi_frame.h" #include "convoi_info.h" #include "line_management_gui.h" #include "schedule_list.h" #include "city_info.h" #include "citylist_frame.h" #include "message_frame.h" #include "chat_frame.h" #include "message_option.h" #include "fabrik_info.h" #include "themeselector.h" #include "goods_frame.h" #include "loadfont_frame.h" #ifdef USE_FLUIDSYNTH_MIDI #include "loadsoundfont_frame.h" #endif #include "scenario_info.h" #include "depot_frame.h" #include "depotlist_frame.h" #include "halt_list_frame.h" #include "vehiclelist_frame.h" #include "curiositylist_frame.h" #include "factorylist_frame.h" #include "labellist_frame.h" #include "display_settings.h" #include "optionen.h" #include "player_ranking_frame.h" #include "../simversion.h" class inthashtable_tpl old_win_pos; // hash-table: magic number to windowsize class inthashtable_tpl saved_windowsizes; // true if there is little space for the status messages static bool status_show_compact = false; // I added a button to the map window to fix it's size to the best one. // This struct is the flow back to the object of the refactoring. class simwin_gadget_flags_t { public: simwin_gadget_flags_t( ) : title(true), close( false ), help( false ), prev( false ), size( false ), next( false ), sticky( false ), gotopos( false ) { } bool title:1; bool close:1; bool help:1; bool prev:1; bool size:1; bool next:1; bool sticky:1; bool gotopos:1; }; class simwin_t { public: scr_coord pos; // Window position uint32 dauer; // How long should the window stay open? uint8 wt; // the flags for the window type ptrdiff_t magic_number; // either magic number or this pointer (which is unique too) gui_frame_t *gui; uint16 gadget_state; // which buttons to hilite bool sticky; // true if window is sticky bool rollup; bool dirty; simwin_gadget_flags_t flags; // See Above. simwin_t() : flags() {} bool operator== (const simwin_t &) const; }; bool simwin_t::operator== (const simwin_t &other) const { return gui == other.gui; } #define MAX_WIN (64) static vector_tpl wins(MAX_WIN); static vector_tpl kill_list(MAX_WIN); static karte_t* wl = NULL; // Pointer to current world is set in win_set_world static int top_win(int win, bool keep_state ); static void display_win(int win); // tooltip data static scr_coord_val tooltip_xpos = 0; static scr_coord_val tooltip_ypos = 0; static const char * tooltip_text = 0; static std::string static_tooltip_text; // For timed tooltip with initial delay and finite visible duration. // Valid owners are required for timing. Invalid (NULL) owners disable timing. static const void * tooltip_owner = 0; // owner of the registered tooltip static const void * tooltip_group = 0; // group to which the owner belongs static uint32 tooltip_register_time = 0; // time at which a tooltip is initially registered static bool show_ticker=0; /* if we are inside the event handler, * the window handler has gui pointer as value, * to defer destruction if this window */ static void *inside_event_handling = NULL; // only this gui element can set a tooltip static void *tooltip_element = NULL; static bool destroy_framed_win(simwin_t *win); //========================================================================= // Helper Functions #define REVERSE_GADGETS (!env_t::window_buttons_right) /** * Display a window gadget */ static int display_gadget_box(sint8 code, int const x, int const y, PIXVAL lighter, PIXVAL darker, bool const pushed) { // If we have a skin, get gadget image data const image_t *img = NULL; if( skinverwaltung_t::gadget ) { // "x", "?", "=", "<<", ">>" img = skinverwaltung_t::gadget->get_image(code); } if(pushed) { // mark_rect_dirty_wc(x, y, D_GADGET_WIDTH, D_TITLEBAR_HEIGHT); display_fillbox_wh_clip_rgb(x, y, D_GADGET_WIDTH, D_TITLEBAR_HEIGHT, lighter, false); } // Do we have a gadget image? if( img != NULL ) { // Max Kielland: This center the gadget image and compensates for any left/top margins within the image to be backward compatible with older PAK sets. display_img_aligned(img->imageid, scr_rect(x, y, D_GADGET_WIDTH, D_TITLEBAR_HEIGHT), ALIGN_CENTER_H | ALIGN_CENTER_V, false); } else { const char *gadget_text = "#"; static const char *gadget_texts[5]={ "X", "?", "=", "<", ">" }; if( code <= SKIN_BUTTON_NEXT ) { gadget_text = gadget_texts[code]; } else if( code == SKIN_GADGET_GOTOPOS ) { gadget_text = "*"; } else if( code == SKIN_GADGET_NOTPINNED ) { gadget_text = "s"; } else if( code == SKIN_GADGET_PINNED ) { gadget_text = "S"; } display_proportional_rgb( x+4, y+4, gadget_text, ALIGN_LEFT, SYSCOL_TEXT, false ); } int side = x+REVERSE_GADGETS*D_GADGET_WIDTH-1; display_vline_wh_clip_rgb(side+1, y+1, D_TITLEBAR_HEIGHT-2, lighter, false); display_vline_wh_clip_rgb(side, y+1, D_TITLEBAR_HEIGHT-2, darker, false); // return width of gadget return D_GADGET_WIDTH; } static int display_gadget_boxes( simwin_gadget_flags_t* flags, int x, int y, PIXVAL lighter, PIXVAL darker, uint16 gadget_state, bool sticky_pushed, bool goto_pushed ) { int width = 0; const int k=(REVERSE_GADGETS?1:-1); // Only the close and sticky gadget can be pushed. if( flags->close ) { width += k*display_gadget_box( SKIN_GADGET_CLOSE, x + width, y, lighter, darker, gadget_state & (1<size ) { width += k*display_gadget_box( SKIN_GADGET_MINIMIZE, x + width, y, lighter, darker, gadget_state & (1<help ) { width += k*display_gadget_box( SKIN_GADGET_HELP, x + width, y, lighter, darker, gadget_state & (1<prev ) { width += k*display_gadget_box( SKIN_BUTTON_PREVIOUS, x + width, y, lighter, darker, gadget_state & (1<next ) { width += k*display_gadget_box( SKIN_BUTTON_NEXT, x + width, y, lighter, darker, gadget_state & (1<gotopos ) { width += k*display_gadget_box( SKIN_GADGET_GOTOPOS, x + width, y, lighter, darker, goto_pushed || (gadget_state & (1<sticky ) { width += k*display_gadget_box( sticky_pushed ? SKIN_GADGET_PINNED : SKIN_GADGET_NOTPINNED, x + width, y, lighter, darker, gadget_state & (1<close ) { if( offset >= 0 && offsetsize ) { if( offset >= 0 && offsethelp ) { if( offset >= 0 && offsetprev ) { if( offset >= 0 && offsetnext ) { if( offset >= 0 && offsetgotopos ) { if( offset >= 0 && offsetsticky ) { if( offset >= 0 && offsetget_image_id(SKIN_WINDOW_RESIZE)!=IMG_EMPTY ) { const image_t *dragger = skinverwaltung_t::gadget->get_image(SKIN_WINDOW_RESIZE); display_color_img( dragger->get_id(), pos.x-dragger->get_pic()->w, pos.y-dragger->get_pic()->h, 0, false, false); } else { int dragger_size = min(D_DRAGGER_WIDTH, D_DRAGGER_HEIGHT); for( int x=1; xmagic_number; } // reduce player-wise magic numbers and magic numbers derived from handles const ptrdiff_t magic_pl[] = { magic_finances_t, magic_convoi_list, magic_convoi_list_filter, magic_line_list, magic_halt_list, magic_line_management_t, magic_ai_options_t, magic_ai_selector, magic_pwd_t, magic_jump, magic_headquarter, magic_headquarter + MAX_PLAYER_COUNT, magic_none, magic_convoi_info, magic_halt_info, magic_toolbar, }; for (uint i=1; igui->get_rdwr_id(); if (id != magic_reserved) { return id; } // anything outside the magic number's ranges will be ignored if (magic <= magic_reserved || magic >= magic_max) { magic = magic_none; } return magic; } static void save_windowsize(simwin_t *win) { ptrdiff_t magic = guess_magic_number(win); if (magic != magic_none) { saved_windowsizes.set(magic, win->gui->get_windowsize() ); } } static scr_size get_stored_windowsize(simwin_t *win) { ptrdiff_t magic = guess_magic_number(win); if (magic != magic_none) { return saved_windowsizes.get(magic); } return scr_size(); } void rdwr_win_settings(loadsave_t *file) { if (file->is_loading()) { saved_windowsizes.clear(); ptrdiff_t magic; do { sint64 rd_magic; file->rdwr_longlong(rd_magic); magic = (ptrdiff_t)rd_magic; if (magic != magic_none) { scr_size s; file->rdwr_long(s.w); file->rdwr_long(s.h); // ignore stuff that will not be used anymore if (magic == guess_magic_number(NULL, magic)) { saved_windowsizes.put(magic, s); } } } while (magic != magic_none); } else { for(auto it : saved_windowsizes) { sint64 m = it.key; file->rdwr_longlong(m); file->rdwr_long(it.value.w); file->rdwr_long(it.value.h); } sint64 m = magic_none; file->rdwr_longlong(m); } } //========================================================================= // returns the window (if open) otherwise zero gui_frame_t *win_get_magic(ptrdiff_t magic) { if( magic!=-1 && magic!=0 ) { // there is at most one window with a positive magic number for(simwin_t const& i : wins ) { if( i.magic_number == magic ) { // if 'special' magic number, return it return i.gui; } } } return NULL; } // sets the magic of a gui_frame_t (needed during reload of windows) bool win_set_magic( gui_frame_t *gui, ptrdiff_t magic ) { if( magic!=-1 && magic!=0 ) { // there is at most one window with a positive magic number for(simwin_t &i : wins ) { if( i.gui == gui ) { i.magic_number = magic; return true; } } } return false; } /** * Returns top window */ gui_frame_t *win_get_top() { return wins.empty() ? 0 : wins.back().gui; } /** * returns the focused component of the top window */ gui_component_t *win_get_focus() { return wins.empty() ? 0 : wins.back().gui->get_focus(); } bool win_is_textinput() { if( gui_component_t *comp = win_get_focus() ) { return dynamic_cast(comp) || dynamic_cast(comp) || dynamic_cast(comp); } return false; } uint32 win_get_open_count() { return wins.get_count(); } gui_frame_t* win_get_index(uint32 i) { if (i < wins.get_count()) { return wins[i].gui; } return NULL; } // brings a window to front, if open bool top_win( const gui_frame_t *gui, bool keep_rollup ) { for( uint i=0; iis_version_atleast(120, 8) ) { if( file->is_saving() ) { for(simwin_t & i : wins) { uint32 id = i.gui->get_rdwr_id(); if( id!=magic_reserved ) { file->rdwr_long( id ); i.pos.rdwr(file); file->rdwr_byte(i.wt); file->rdwr_bool(i.sticky); file->rdwr_bool(i.rollup); i.gui->rdwr(file); } } uint32 end = magic_none; file->rdwr_long( end ); } else { // restore windows while(1) { uint32 id; file->rdwr_long(id); // create the matching gui_frame_t *w = NULL; switch(magic_numbers(id)) { // end of dialogues case magic_none: return; // actual dialogues to restore case magic_themes: w = new themeselector_t(); break; case magic_reliefmap: w = new map_frame_t(); break; case magic_ki_kontroll_t: w = new ki_kontroll_t(); break; case magic_line_schedule_rdwr_dummy: w = new line_management_gui_t(); break; case magic_city_info_t: w = new city_info_t(); break; case magic_messageframe: w = new message_frame_t(); break; case magic_message_options: w = new message_option_t(); break; case magic_chatframe: w = new chat_frame_t(); break; case magic_factory_info: w = new fabrik_info_t(); break; case magic_goodslist: w = new goods_frame_t(); break; case magic_font: w = new loadfont_frame_t(); break; #ifdef USE_FLUIDSYNTH_MIDI case magic_soundfont: w = new loadsoundfont_frame_t(); break; #endif case magic_scenario_info: w = new scenario_info_t(); break; case magic_depot: w = new depot_frame_t(); break; case magic_convoi_list: w = new convoi_frame_t(); break; case magic_depotlist: w = new depotlist_frame_t(); break; case magic_vehiclelist: w = new vehiclelist_frame_t(); break; case magic_halt_list: w = new halt_list_frame_t(); break; case magic_citylist_frame_t: w = new citylist_frame_t(); break; case magic_curiositylist: w = new curiositylist_frame_t(); break; case magic_factorylist: w = new factorylist_frame_t(); break; case magic_labellist: w = new labellist_frame_t(); break; case magic_color_gui_t: w = new color_gui_t(); break; case magic_optionen_gui_t: w = new optionen_gui_t(); break; case magic_player_ranking: w = new player_ranking_frame_t(); break; default: if( id>=magic_finances_t && idget_player(id-magic_finances_t) ); } else if( id>=magic_line_management_t && idget_player(id-magic_line_management_t) ); } else if( id>=magic_toolbar && idupdate(wl->get_active_player()); w = tool_t::toolbar_tool[id-magic_toolbar]->get_tool_selector(); } else if( id>=magic_convoi_info && id=magic_halt_info && iderror( "rdwr_all_win()", "No idea how to restore magic 0x%X", id ); return; } } /* sequence is now the same for all dialogues * restore coordinates * create window * read state * restore content * restore state - gui_frame_t::rdwr() might create its own window ->> want to restore state to that window */ scr_coord p; p.rdwr(file); uint8 win_type; file->rdwr_byte( win_type ); create_win( p, w, (wintype)win_type, id ); bool sticky, rollup; file->rdwr_bool( sticky ); file->rdwr_bool( rollup ); // now load the window uint32 count = wins.get_count(); w->rdwr( file ); // restore sticky / rollup status // ensure that the new status is to currently loaded window if (wins.get_count() >= count) { wins.back().sticky = sticky; wins.back().rollup = rollup; } } } } } scr_rect win_get_max_window_area() { scr_coord other_pos((env_t::menupos == MENU_LEFT) * env_t::iconsize.w, (env_t::menupos == MENU_TOP) * env_t::iconsize.h + (env_t::menupos == MENU_BOTTOM) * win_get_statusbar_height()); scr_size other_size(display_get_width() - other_pos.x - (env_t::menupos == MENU_RIGHT) * env_t::iconsize.w, display_get_height() - win_get_statusbar_height() - env_t::iconsize.h); if (show_ticker) { other_size.h -= TICKER_HEIGHT; if (env_t::menupos == MENU_BOTTOM) { other_pos.y += TICKER_HEIGHT; } } return scr_rect(other_pos, other_size); } /* tries to get a window on the screen * without titlebar hidden by any menubar/satus bar elements */ void win_clamp_xywh_position( gui_frame_t* gui, scr_coord &pos, scr_size wh, bool move_topleft ) { // reposition to keep on screen scr_rect screen = win_get_max_window_area(); scr_coord other_pos = screen.get_pos(); scr_size other_size = screen.get_size(); if (pos.y < other_pos.y) { // y alsways visible pos.y = other_pos.y; } if (move_topleft) { if (pos.x < other_pos.x) { pos.x = other_pos.x; } } // should we move to be fully on screen? if (move_topleft) { if (pos.x + wh.w > screen.x + screen.w) { pos.x = screen.x + screen.w - wh.w; } if (pos.y + wh.h > screen.y + screen.h) { pos.y = screen.y + screen.h - wh.h; } } if (gui) { if (wh.w > other_size.w || wh.h > other_size.h) { // window still to big => maybe we can resize it to fit the screen scr_size minsize = gui->get_min_windowsize(); if (minsize != wh) { bool resize = false; if (pos.x < other_pos.x && minsize.w < other_size.w) { // too wide pos.x = other_pos.x; minsize.w = other_size.w; resize = true; } if (pos.y < other_pos.y && minsize.h < other_size.h) { //too high pos.y = other_pos.y; minsize.h = other_size.h; resize = true; } if (resize) { gui->set_windowsize(minsize); } } else if (move_topleft) { // center on screen if (pos.x < other_pos.x) { pos.x = other_pos.x - (wh.w - other_size.w) / 2; } if (pos.y < other_pos.y) { pos.y = other_pos.y - (wh.h - other_size.h) / 2; } } // make sure some corner remains visible if (pos.x + wh.w < other_pos.x + D_MARGIN_LEFT) { pos.x = other_pos.x + D_MARGIN_LEFT - wh.w; } if (pos.x > other_pos.x + other_size.w - D_MARGIN_LEFT) { pos.x = other_pos.x + other_size.w - D_MARGIN_LEFT; } if (pos.y + D_TITLEBAR_HEIGHT > other_pos.y + other_size.h) { pos.y = other_pos.y + other_size.h - D_TITLEBAR_HEIGHT; } } } } int create_win(gui_frame_t* const gui, wintype const wt, ptrdiff_t const magic) { return create_win({ -1, -1 }, gui, wt, magic); } int create_win(scr_coord pos, gui_frame_t *const gui, wintype const wt, ptrdiff_t const magic) { assert(gui!=NULL && magic!=0); if( gui_frame_t *win = win_get_magic(magic) ) { if( env_t::second_open_closes_win ) { destroy_win( win ); if( !( wt & w_do_not_delete ) ) { delete gui; } } else { top_win( win ); } return -1; } if( pos.x==-1 && pos.y==-1 && env_t::remember_window_positions ) { // look for window in hash table if( scr_coord *k = old_win_pos.access(magic) ) { pos = *k; } } /* if there are too many handles (likely in large games) * we search for any error/news message at the bottom of the stack and delete it * => newer information might be more important ... * This is a stopgap to avoid simutrans to freeze due to many error etc windows */ if( wins.get_count()==MAX_WIN ) { // we try to remove one of the lowest news windows (magic_none) for( uint i=0; i(wins[i].gui)!=NULL ) { destroy_win( wins[i].gui ); break; } } } if( wins.get_count() < MAX_WIN ) { if (!wins.empty()) { // mark old dirty const scr_size size = wins.back().gui->get_windowsize(); mark_rect_dirty_wc( wins.back().pos.x - 1, wins.back().pos.y - 1, wins.back().pos.x + size.w + 2, wins.back().pos.y + size.h + 2 + D_TITLEBAR_HEIGHT ); // -1, +2 for env_t::window_frame_active } wins.append( simwin_t() ); simwin_t& win = wins.back(); // Make Sure Closes Aren't Forgotten. // Must Reset as the entries and thus flags are reused win.flags.close = true; win.flags.title = gui->has_title(); win.flags.help = ( gui->get_help_filename() != NULL ); win.flags.prev = gui->has_prev(); win.flags.next = gui->has_next(); win.flags.sticky = gui->has_sticky(); win.gui = gui; // take care of time delete windows ... win.wt = wt & w_time_delete ? w_info : wt; win.dauer = (wt&w_time_delete) ? MESG_WAIT : -1; win.magic_number = magic; win.gadget_state = 0; win.rollup = false; win.sticky = false; win.dirty = true; // Notify window to be shown assert(gui); event_t ev; ev.ev_class = INFOWIN; ev.ev_code = WIN_OPEN; ev.mouse_pos.x = 0; ev.mouse_pos.y = 0; ev.click_pos.x = 0; ev.click_pos.y = 0; ev.button_state = 0; void *old = inside_event_handling; inside_event_handling = gui; gui->infowin_event(&ev); inside_event_handling = old; // restore windowsize scr_size stored = get_stored_windowsize(&win); if (stored == scr_size()) { // not stored, take current stored = gui->get_windowsize(); } // use default width stored.clip_lefttop(scr_size(D_DEFAULT_WIDTH, D_DEFAULT_HEIGHT)); // clip to display size stored.clip_rightbottom( scr_size(display_get_width(), display_get_height() - env_t::iconsize.h - win_get_statusbar_height() ) ); if (stored != gui->get_windowsize()) { // send tailored resize event scr_size delta = stored - gui->get_windowsize(); event_t wev; wev.ev_class = WINDOW_RESIZE; wev.ev_code = 0; wev.mouse_pos.x = delta.w; wev.mouse_pos.y = delta.h; inside_event_handling = gui; gui->infowin_event(&wev); inside_event_handling = old; } // try to go next to mouse bar if (pos.x == -1) { pos.x = get_mouse_pos().x - gui->get_windowsize().w / 2; pos.y = get_mouse_pos().y - gui->get_windowsize().h - get_tile_raster_width()/4; } // make sure window is on screen win_clamp_xywh_position(gui, pos, gui->get_windowsize(), true); win.pos = pos; win.dirty = true; return wins.get_count(); } else { if( !( wt & w_do_not_delete ) ) { delete gui; } return -1; } } static int notify_top_win() { // mark new dirty scr_size size = wins.back().gui->get_windowsize(); mark_rect_dirty_wc( wins.back().pos.x - 1, wins.back().pos.y - 1, wins.back().pos.x + size.w + 2, wins.back().pos.y + size.h + 2 ); // -1, +2 for env_t::window_frame_active event_t ev; ev.ev_class = INFOWIN; ev.ev_code = WIN_TOP; ev.mouse_pos.x = 0; ev.mouse_pos.y = 0; ev.click_pos.x = 0; ev.click_pos.y = 0; ev.button_state = 0; void *old = inside_event_handling; inside_event_handling = wins.back().gui; wins.back().gui->infowin_event(&ev); inside_event_handling = old; return wins.get_count()-1; } int top_win(int win, bool keep_state ) { if( (uint32)win==wins.get_count()-1 ) { return win; } // already topped // mark old dirty scr_size size = wins.back().gui->get_windowsize(); mark_rect_dirty_wc( wins.back().pos.x - 1, wins.back().pos.y - 1, wins.back().pos.x + size.w + 2, wins.back().pos.y + size.h + 2 ); // -1, +2 for env_t::window_frame_active wins.back().dirty = true; simwin_t tmp = wins[win]; wins.remove_at(win); if( !keep_state ) { tmp.rollup = false; // make visible when topping } wins.append(tmp); return notify_top_win(); } static void save_win_position(const simwin_t &win) { if( win.magic_number < magic_max ) { if( scr_coord *k = old_win_pos.access(win.magic_number) ) { *k = win.pos; } else { old_win_pos.put( win.magic_number, win.pos ); } } } /* sometimes a window cannot destroyed while it is still handled; * in those cases it will added to kill list and it is only destructed * by this function */ static void process_kill_list() { bool needs_top = !kill_list.empty(); for(simwin_t & i : kill_list) { if (inside_event_handling != i.gui) { save_win_position(i); destroy_framed_win(&i); // we call this first, otherwise the focus may not be recognized wins.remove(i); } } kill_list.clear(); // top message always after destruction if( needs_top && wins.get_count()>1 ) { notify_top_win(); } } /** * Destroy a framed window */ static bool destroy_framed_win(simwin_t *wins) { bool r = true; // mark dirty const scr_size size = wins->gui->get_windowsize(); mark_rect_dirty_wc( wins->pos.x - 1, wins->pos.y - 1, wins->pos.x + size.w + 2, wins->pos.y + size.h + 2 ); // -1, +2 for env_t::window_frame_active // save windowsize for later save_windowsize(wins); // save pointer to gui window: might be modified in event handling, // or could be modified if wins points to value in kill_list and kill_list is modified! nasty surprise gui_frame_t* gui = wins->gui; if( gui ) { event_t ev; ev.ev_class = INFOWIN; ev.ev_code = WIN_CLOSE; ev.mouse_pos.x = 0; ev.mouse_pos.y = 0; ev.click_pos.x = 0; ev.click_pos.y = 0; ev.button_state = 0; void *old = inside_event_handling; inside_event_handling = gui; wins->gui->infowin_event(&ev); inside_event_handling = old; } if( (wins->wt&w_do_not_delete) == 0 ) { if( wins->gui == gui ) { // remove from kill list first, otherwise delete will be called again on that window for( uint32 j = 0; j < kill_list.get_count(); j++ ) { if( kill_list[j].gui == gui ) { kill_list.remove_at(j); break; } } delete gui; } else { // wins likely modified during event handling. Assume this was just a schedule window destroying itself, and top_win() therefore modifying wins. // return false to signal destroy_all_win() that wins was already modified. r = false; } } // set dirty flag to refill background if( wl ) { wl->set_background_dirty(); } tooltip_text = 0; return r; } bool destroy_win(const ptrdiff_t magic) { const gui_frame_t *gui = win_get_magic(magic); if(gui) { return destroy_win( gui ); } return false; } bool destroy_win(const gui_frame_t *gui) { for( uint i=0; i1 ) { notify_top_win(); } } return true; } } return false; } void destroy_all_win(bool destroy_sticky) { for( sint32 curWin = 0; curWin < (sint32)wins.get_count(); curWin++ ) { if( destroy_sticky || !wins[curWin].sticky ) { save_win_position(wins[curWin]); if( inside_event_handling == wins[curWin].gui ) { // only add this, if not already added kill_list.append_unique(wins[curWin]); // compact the window list wins.remove_at(curWin); curWin--; } else { if( destroy_framed_win(&wins[curWin]) ) { // compact the window list wins.remove_at(curWin); curWin--; } // else wins was already modified - assume by the schedule window closing itself during event handling } } } } void rollup_all_win() { bool all_rolldown_flag = true; // If any dialog is open, all rolldown will not be performed for ( sint32 curWin = 0; curWin < (sint32)wins.get_count(); curWin++ ) { if ( !wins[curWin].rollup ) { wins[curWin].rollup = true; gui_frame_t *gui = wins[curWin].gui; scr_size size = gui->get_windowsize(); mark_rect_dirty_wc( wins[curWin].pos.x, wins[curWin].pos.y, wins[curWin].pos.x+size.w, wins[curWin].pos.y+size.h ); all_rolldown_flag = false; } } if ( !all_rolldown_flag ) { wl->set_background_dirty(); } else if ( wins.get_count() ) { rolldown_all_win(); } } void rolldown_all_win() { for ( sint32 curWin = 0; curWin < (sint32)wins.get_count(); curWin++ ) { wins[curWin].rollup = false; gui_frame_t *gui = wins[curWin].gui; scr_size size = gui->get_windowsize(); mark_rect_dirty_wc( wins[curWin].pos.x, wins[curWin].pos.y, wins[curWin].pos.x+size.w, wins[curWin].pos.y+size.h ); } } void display_win(int win) { // ok, now process it gui_frame_t* comp = wins[win].gui; scr_size size = comp->get_windowsize(); // minimising flag if resize allowed wins[win].flags.size = (comp->get_resizemode() != 0); scr_coord pos = wins[win].pos; FLAGGED_PIXVAL title_color = (comp->get_titlecolor()&0xFFFF); FLAGGED_PIXVAL text_color = env_t::front_window_text_color; if( (unsigned)win!=wins.get_count()-1 ) { // not top => darker title_color = display_blend_colors(title_color, color_idx_to_rgb(COL_BLACK), env_t::bottom_window_darkness); text_color = env_t::bottom_window_text_color; } bool need_dragger = comp->get_resizemode() != gui_frame_t::no_resize; // HACK So draw will know if gadget is needed. wins[win].flags.help = ( comp->get_help_filename() != NULL ); if( wins[win].flags.title ) { win_draw_window_title(wins[win].pos, size, title_color, comp->get_name(), text_color, comp->get_weltpos(false), wins[win].gadget_state, wins[win].sticky, comp->is_weltpos(), wins[win].flags ); } if( wins[win].dirty ) { // not sure this is still a useful call mark_rect_dirty_wc( wins[win].pos.x, wins[win].pos.y, wins[win].pos.x+size.w+1, wins[win].pos.y+2 ); wins[win].dirty = false; } // mark top window, if requested if(env_t::window_frame_active && (unsigned)win==wins.get_count()-1) { if(!wins[win].rollup) { display_ddd_box_clip_rgb( wins[win].pos.x-1, wins[win].pos.y-1, size.w+2, size.h+2, title_color, title_color); } else { display_ddd_box_clip_rgb( wins[win].pos.x-1, wins[win].pos.y-1, size.w+2, D_TITLEBAR_HEIGHT + 2, title_color, title_color); } } if(!wins[win].rollup) { comp->draw(wins[win].pos, size); // draw dragger if(need_dragger) { win_draw_window_dragger( pos, size); } } } void display_all_win() { // first: empty kill list process_kill_list(); // check which window can set tooltip const sint16 x = get_mouse_pos().x; const sint16 y = get_mouse_pos().y; tooltip_element = NULL; for( uint32 i = wins.get_count(); i-- != 0; ) { if( (!wins[i].rollup && wins[i].gui->is_hit(x-wins[i].pos.x,y-wins[i].pos.y)) || (wins[i].rollup && x>=wins[i].pos.x && xget_windowsize().w && y>=wins[i].pos.y && ymap_rotate90(new_ysize); } } static void remove_old_win() { // Destroy (close) old window when life time expire for( int i=wins.get_count()-1; i>=0; i=min(i,(int)wins.get_count())-1 ) { if(wins[i].dauer > 0) { wins[i].dauer --; if(wins[i].dauer == 0) { destroy_win( wins[i].gui ); } } } } static inline void snap_check_distance( scr_coord_val *r, const scr_coord_val a, const scr_coord_val b ) { if( abs(a-b)<=env_t::window_snap_distance ) { *r = a; } } static void snap_check_win( const int win, scr_coord *r, const scr_coord from_pos, const scr_coord from_size, const scr_coord to_pos, const scr_coord to_size ) { bool resize; if( from_size==to_size && from_pos!=to_pos ) { // check if we're moving resize = false; } else if( from_size!=to_size && from_pos==from_pos ) { // or resizing the window resize = true; } else { return; // or nothing to do. } const int wins_count = wins.get_count(); for( int i=0; i<=wins_count; i++ ) { if( i==win ) { // Don't snap to self continue; } scr_coord other_pos; scr_coord other_size; if( i==wins_count ) { // Allow snap to screen edge other_pos.x = (env_t::menupos==MENU_LEFT)*env_t::iconsize.w; other_pos.y = (env_t::menupos==MENU_TOP)*env_t::iconsize.h + (env_t::menupos==MENU_BOTTOM)*win_get_statusbar_height(); other_size.x = display_get_width() - other_pos.x - (env_t::menupos==MENU_RIGHT)*env_t::iconsize.w; other_size.y = display_get_height()-win_get_statusbar_height()-env_t::iconsize.h; if( show_ticker ) { other_size.y -= TICKER_HEIGHT; } } else { // Snap to other window other_size = wins[i].gui->get_windowsize(); other_pos = wins[i].pos; if( wins[i].rollup ) { other_size.y = D_TITLEBAR_HEIGHT; } } // my bottom below other top and my top above other bottom ---- in same vertical band if( from_pos.y+from_size.y >= other_pos.y && from_pos.y <= other_pos.y+other_size.y ) { if( resize ) { // other right side and my new right side within snap snap_check_distance( &r->x, other_pos.x+other_size.x-from_pos.x, to_size.x ); // snap right - align right sides } else { // other right side and my new right side within snap snap_check_distance( &r->x, other_pos.x+other_size.x-from_size.x, to_pos.x ); // snap right - align right sides // other left side and my new left side within snap snap_check_distance( &r->x, other_pos.x, to_pos.x ); // snap left - align left sides } } // my new bottom below other top and my new top above other bottom ---- in same vertical band if( resize ) { if( from_pos.y+to_size.y>other_pos.y && from_pos.yx, other_pos.x-from_pos.x, to_size.x ); // snap right - align my right to other left } } else { if( to_pos.y+from_size.y>other_pos.y && to_pos.yx, other_pos.x-from_size.x, to_pos.x ); // snap right - align my right to other left // other right side and my new left within snap snap_check_distance( &r->x, other_pos.x+other_size.x, to_pos.x ); // snap left - align my left to other right } } // my right side right of other left side and my left side left of other right side ---- in same horizontal band if( from_pos.x+from_size.x>=other_pos.x && from_pos.x<=other_pos.x+other_size.x ) { if( resize ) { // other bottom and my new bottom within snap snap_check_distance( &r->y, other_pos.y+other_size.y-from_pos.y, to_size.y ); // snap down - align bottoms } else { // other bottom and my new bottom within snap snap_check_distance( &r->y, other_pos.y+other_size.y-from_size.y, to_pos.y ); // snap down - align bottoms // other top and my new top within snap snap_check_distance( &r->y, other_pos.y, to_pos.y ); // snap up - align tops } } // my new right side right of other left side and my new left side left of other right side ---- in same horizontal band if ( resize ) { if( from_pos.x+to_size.x>other_pos.x && from_pos.xy, other_pos.y-from_pos.y, to_size.y ); // snap down - align my bottom to other top } } else { if( to_pos.x+from_size.x>other_pos.x && to_pos.xy, other_pos.y-from_size.y, to_pos.y ); // snap down - align my bottom to other top // other bottom and my new top within snap snap_check_distance( &r->y, other_pos.y+other_size.y, to_pos.y ); // snap up - align my top to other bottom } } } } static void move_win(int win, event_t *ev) { const scr_coord mouse_from = ev->click_pos; const scr_coord mouse_to = ev->mouse_pos; const scr_coord from_pos = wins[win].pos; scr_coord from_size = scr_coord(wins[win].gui->get_windowsize().w,wins[win].gui->get_windowsize().h); if( wins[win].rollup ) { from_size.y = D_TITLEBAR_HEIGHT + 2; } scr_coord to_pos = wins[win].pos+(mouse_to-mouse_from); const scr_coord to_size = from_size; if( env_t::window_snap_distance>0 ) { snap_check_win( win, &to_pos, from_pos, from_size, to_pos, to_size ); } // CLIP(wert,min,max) win_clamp_xywh_position(wins[win].gui, to_pos, wins[win].gui->get_windowsize(), false); // delta is actual window movement. const scr_coord delta = to_pos - from_pos; wins[win].pos += delta; // need to mark all of old and new positions dirty. -1, +2 for env_t::window_frame_active mark_rect_dirty_wc( from_pos.x - 1, from_pos.y - 1, from_pos.x + from_size.x + 2, from_pos.y + from_size.y + 2 ); wins[win].dirty = true; // set dirty flag to refill background if(wl) { wl->set_background_dirty(); } change_drag_start( delta ); } static void resize_win(int win, event_t *ev) { event_t wev = *ev; wev.ev_class = WINDOW_RESIZE; wev.ev_code = 0; const scr_coord mouse_from = wev.click_pos; const scr_coord mouse_to = wev.mouse_pos; const scr_coord from_pos = wins[win].pos; const scr_coord from_size = scr_coord(wins[win].gui->get_windowsize().w,wins[win].gui->get_windowsize().h); const scr_coord to_pos = from_pos; scr_coord to_size = from_size+(mouse_to-mouse_from); if( env_t::window_snap_distance>0 ) { snap_check_win( win, &to_size, from_pos, from_size, to_pos, to_size ); } // since we may be smaller afterwards mark_rect_dirty_wc( from_pos.x - 1, from_pos.y - 1, from_pos.x + from_size.x + 2, from_pos.y + from_size.y + 2 ); // -1, +2 for env_t::window_frame_active // set dirty flag to refill background if(wl) { wl->set_background_dirty(); } // adjust event mouse scr_coord per snap wev.mouse_pos = wev.click_pos + to_size - from_size; wins[win].gui->infowin_event( &wev ); } // returns true, if gui is a open window handle static bool win_is_open(gui_frame_t *gui) { for(simwin_t const& i : wins) { if (i.gui == gui) { for(simwin_t const& j : kill_list) { if (j.gui == gui) { return false; } } return true; } } return false; } scr_coord const& win_get_pos(gui_frame_t const* const gui) { for( uint32 i = wins.get_count(); i-- != 0; ) { if( wins[i].gui == gui ) { return wins[i].pos; } } static scr_coord const bad(-1, -1); return bad; } void win_set_pos(gui_frame_t *gui, scr_coord new_pos) { for( uint32 i = wins.get_count(); i-- != 0; ) { if( wins[i].gui == gui ) { win_clamp_xywh_position(gui, new_pos, gui->get_windowsize(), true); wins[i].pos = new_pos; wins[i].dirty = true; return; } } } bool last_drag_is_caught = false; // since check_pos_win is processed before i.e. scrolling map // we do not want to catch the mouse, if we use it already void catch_dragging() { last_drag_is_caught = true; } /* * main window event handler */ bool check_pos_win(event_t *ev,bool modal) { static int is_resizing = -1; static int is_moving = -1; static bool is_dragging = false; bool swallowed = false; const int x = ev->ev_class==EVENT_MOVE?ev->mouse_pos.x:ev->click_pos.x; const int y = ev->ev_class==EVENT_MOVE?ev->mouse_pos.y:ev->click_pos.y; if( last_drag_is_caught ) { if( ev->ev_class == EVENT_DRAG ) { // somebody else drags already => do nothing return false; } if( ev->ev_class == EVENT_RELEASE ) { // we will handle dragging events again after this last_drag_is_caught = false; return false; } } // for the moment, no none events if (ev->ev_class == EVENT_NONE) { process_kill_list(); return false; } // we stop resizing once the user releases the button if( (is_resizing>=0 || is_moving>=0) && (IS_LEFTRELEASE(ev) || (ev->button_state&1)==0) ) { is_resizing = -1; is_moving = -1; if( IS_LEFTRELEASE(ev) ) { // should not proceed, otherwise the left release event will be fed to other components; // return true (i.e. event swallowed) to prevent propagation back to the main view return true; } } // disable any active tooltip upon mouse click by forcing expiration of tooltip duration if( ev->ev_class==EVENT_CLICK ) { tooltip_register_time = 0; } // click in main menu? scr_coord menuoffset((env_t::menupos == MENU_RIGHT) * (display_get_width() - env_t::iconsize.w), (env_t::menupos == MENU_BOTTOM) * (display_get_height() - env_t::iconsize.h) - D_TITLEBAR_HEIGHT); if (!tool_t::toolbar_tool.empty() && tool_t::toolbar_tool[0]->get_tool_selector() && (is_dragging || tool_t::toolbar_tool[0]->get_tool_selector()->is_hit(x-menuoffset.x, y-menuoffset.y)) && y > menuoffset.y+D_TITLEBAR_HEIGHT && (ev->ev_class >= EVENT_CLICK && ev->ev_class <= EVENT_DRAG) ) { // first finish dragging event_t wev = *ev; wev.move_origin(menuoffset); inside_event_handling = tool_t::toolbar_tool[0]; tool_t::toolbar_tool[0]->get_tool_selector()->infowin_event(&wev); inside_event_handling = NULL; if (!tool_t::toolbar_tool[0]->get_tool_selector()->is_hit(ev->mouse_pos.x, ev->mouse_pos.y)) { // find out if the toolbar should be move to another corner uint8 new_pos = 0; int mx = get_mouse_pos().x; // inclippe values needed int my = get_mouse_pos().y; if (my < env_t::iconsize.h) { new_pos = 1 << MENU_TOP; } if (my > display_get_height()- env_t::iconsize.h) { new_pos |= 1 << MENU_BOTTOM; } if (mx < env_t::iconsize.w) { new_pos |= 1 << MENU_LEFT; } if (mx > display_get_width() - env_t::iconsize.w) { new_pos |= 1 << MENU_RIGHT; } if (new_pos && new_pos!=(1<>= 1; rot++; } // single rotation only if (check_pos == 1 && rot!=env_t::menupos) { env_t::menupos = rot; world()->set_dirty(); // if no inside a modal from if (!modal) { // move all windows event_t* ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event(ev); } is_dragging = false; return true; } } } is_dragging = ev->ev_class != EVENT_RELEASE && ev->button_state>1; // swallow event return true; } // cursor event only go to top window (but not if rolled up) if( (ev->ev_class == EVENT_KEYBOARD || ev->ev_class == EVENT_STRING) && !wins.empty() ) { simwin_t &win = wins.back(); if( !win.rollup ) { inside_event_handling = win.gui; swallowed = win.gui->infowin_event(ev); } inside_event_handling = NULL; process_kill_list(); return swallowed; } // just move top window until button release if( is_moving>=0 && (unsigned)is_moving=0 && (unsigned)is_resizingev_class == EVENT_KEYBOARD || ev->ev_class == EVENT_STRING) && y > display_get_height()- win_get_statusbar_height() ) { // swallow event return true; } // swallow all other events in ticker (if there) if( !(ev->ev_class == EVENT_KEYBOARD || ev->ev_class == EVENT_STRING) && show_ticker && y > display_get_height()- win_get_statusbar_height() - TICKER_HEIGHT ) { if( IS_LEFTCLICK(ev) ) { ticker::process_click(x); } // swallow event return true; } // handle all the other events for( int i=wins.get_count()-1; i>=0 && !swallowed; i=min(i,(int)wins.get_count())-1 ) { if( wins[i].gui->is_hit( x-wins[i].pos.x, y-wins[i].pos.y ) ) { // all events in window are swallowed swallowed = true; inside_event_handling = wins[i].gui; // Top window first if( (int)wins.get_count()-1>i && IS_LEFTCLICK(ev) && (!wins[i].rollup || ev->click_pos.yget_help_filename() != NULL ); // Where Was It ? sint8 code = decode_gadget_boxes( ( & wins[i].flags ), wins[i].pos.x + (REVERSE_GADGETS?0:wins[i].gui->get_windowsize().w-D_GADGET_WIDTH), x ); if( code < SKIN_GADGET_COUNT ) { if( IS_LEFTCLICK(ev) ) { wins[i].gadget_state |= (1 << code); } else if( IS_LEFTRELEASE(ev) ) { wins[i].gadget_state &= ~(1 << code); if( ev->mouse_pos.y >= wins[i].pos.y && ev->mouse_pos.y < wins[i].pos.y+D_TITLEBAR_HEIGHT && decode_gadget_boxes( ( & wins[i].flags ), wins[i].pos.x + (REVERSE_GADGETS?0:wins[i].gui->get_windowsize().w-D_GADGET_WIDTH), ev->mouse_pos.x )==code ) { // do whatever needs to be done switch( code ) { case SKIN_GADGET_CLOSE : destroy_win(wins[i].gui); break; case SKIN_GADGET_MINIMIZE: // (Mathew Hounsell) ev->ev_class = WINDOW_MAKE_MIN_SIZE; ev->ev_code = 0; wl->set_background_dirty(); wins[i].gui->infowin_event( ev ); break; case SKIN_GADGET_HELP : help_frame_t::open_help_on( wins[i].gui->get_help_filename() ); break; case SKIN_BUTTON_PREVIOUS: ev->ev_class = WINDOW_CHOOSE_NEXT; ev->ev_code = PREV_WINDOW; // backward wins[i].gui->infowin_event( ev ); break; case SKIN_BUTTON_NEXT: ev->ev_class = WINDOW_CHOOSE_NEXT; ev->ev_code = NEXT_WINDOW; // forward wins[i].gui->infowin_event( ev ); break; case SKIN_GADGET_GOTOPOS: { // change position on map (or follow) koord3d k = wins[i].gui->get_weltpos(true); if( k!=koord3d::invalid ) { wl->get_viewport()->change_world_position( k ); wl->get_zeiger()->change_pos( k ); } } break; case SKIN_GADGET_NOTPINNED: wins[i].sticky = !wins[i].sticky; break; } } } } else { // Somewhere on the titlebar if (IS_LEFTDRAG(ev)) { i = top_win(i,false); move_win(i, ev); is_moving = i; } if(IS_RIGHTCLICK(ev) || IS_LEFTDBLCLK(ev) ) { wins[i].rollup ^= 1; gui_frame_t *gui = wins[i].gui; scr_size size = gui->get_windowsize(); mark_rect_dirty_wc( wins[i].pos.x, wins[i].pos.y, wins[i].pos.x+size.w, wins[i].pos.y+size.h ); if( wins[i].rollup ) { wl->set_background_dirty(); } } } // It has been handled so stop checking. break; } else { if(!wins[i].rollup) { // click in Window / Resize? //11-May-02 markus weber added scr_size size = wins[i].gui->get_windowsize(); // resizer hit ? const bool canresize = is_resizing>=0 || (ev->click_pos.x > wins[i].pos.x + size.w - D_DRAGGER_WIDTH && ev->click_pos.y > wins[i].pos.y + size.h - D_DRAGGER_HEIGHT); if((IS_LEFTCLICK(ev) || IS_LEFTDRAG(ev)) && canresize && wins[i].gui->get_resizemode()!=gui_frame_t::no_resize) { resize_win( i, ev ); is_resizing = i; } else { is_resizing = -1; // click in Window event_t wev = *ev; wev.move_origin(wins[i].pos); wins[i].gui->infowin_event( &wev ); } } else { swallowed = false; } } inside_event_handling = NULL; } } inside_event_handling = NULL; process_kill_list(); return swallowed; } void win_poll_event(event_t* const ev) { display_poll_event(ev); // main window resized if( ev->ev_class==EVENT_SYSTEM && ev->ev_code==SYSTEM_RESIZE ) { // main window resized simgraph_resize( ev->new_window_size ); gui_theme_t::gui_buttons_per_row = max(2, min(4, display_get_width() / (D_BUTTON_WIDTH + D_H_SPACE + D_MARGIN_LEFT))); ticker::redraw(); tool_t::update_toolbars(); for( uint i = 0; iget_min_windowsize(), true ); } wl->set_dirty(); wl->get_viewport()->metrics_updated(); ev->ev_class = IGNORE_EVENT; // now see how much of the status text fits the display scr_coord_val time_width = proportional_string_width(tick_to_string(wl->get_ticks())); scr_coord_val player_width = proportional_string_width(wl->get_active_player()->get_name()); char buffer[128]; if (env_t::player_finance_display_account) { money_to_string(buffer, (double)world()->get_active_player()->get_finance()->get_account_balance() / 100.0); } else { money_to_string(buffer, (double)world()->get_active_player()->get_finance()->get_netwealth() / 100.0); } scr_coord_val money_width = proportional_string_width(buffer); scr_coord_val position_width = proportional_string_width(wl->get_zeiger()->get_pos().get_str()); // if too long shorten radically status_show_compact = (time_width + player_width + money_width + position_width) * 1.2 > ev->new_window_size.w; } // save and reload all windows (currently only used when a new theme is applied) else if( ev->ev_class==EVENT_SYSTEM && ev->ev_code==SYSTEM_RELOAD_WINDOWS ) { dr_chdir( env_t::user_dir ); loadsave_t dlg; if( dlg.wr_open( "dlgpos.xml", loadsave_t::xml_zipped, 1, "temp", SERVER_SAVEGAME_VER_NR ) == loadsave_t::FILE_STATUS_OK ) { // save all rdwr_all_win( &dlg ); dlg.close(); destroy_all_win( true ); if( dlg.rd_open( "dlgpos.xml" ) == loadsave_t::FILE_STATUS_OK ) { // and reload them ... rdwr_all_win( &dlg ); } } wl->set_dirty(); ev->ev_class = IGNORE_EVENT; ticker::redraw(); } else if( ev->ev_class==EVENT_SYSTEM && ev->ev_code==SYSTEM_THEME_CHANGED ) { // called when font is changed ev->mouse_pos.x = ev->mouse_pos.y = ev->click_pos.x = ev->click_pos.y = 0; for(simwin_t const& i : wins) { i.gui->infowin_event(ev); } ev->ev_class = IGNORE_EVENT; ticker::redraw(); } } uint16 win_get_statusbar_height() { return max(LINESPACE + 2, 15); } // finally updates the display void win_display_flush(double konto) { const sint16 disp_width = display_get_width(); const sint16 disp_height = display_get_height(); // display main menu tool_selector_t *main_menu = tool_t::toolbar_tool[0]->get_tool_selector(); scr_coord menu_pos(0,0); scr_size menu_size(disp_width, env_t::iconsize.h); scr_rect clip_rr(0, env_t::iconsize.h, disp_width, disp_height - env_t::iconsize.h); switch (env_t::menupos) { case MENU_TOP: // pos default (see above) // size default // rect default break; case MENU_BOTTOM: menu_pos = scr_coord(0, disp_height - env_t::iconsize.h); // size default clip_rr.y = 0; break; case MENU_LEFT: // pos default (see above) menu_size = scr_size(env_t::iconsize.w, disp_height-win_get_statusbar_height()-show_ticker*TICKER_HEIGHT); clip_rr = scr_rect(env_t::iconsize.h, 0, disp_width - env_t::iconsize.w, disp_height); break; case MENU_RIGHT: menu_pos.x = disp_width - env_t::iconsize.w; menu_size = scr_size(env_t::iconsize.w, disp_height - win_get_statusbar_height()-show_ticker*TICKER_HEIGHT ); clip_rr = scr_rect(0, 0, disp_width - env_t::iconsize.w, disp_height); break; } display_set_clip_wh( menu_pos.x, menu_pos.y, menu_size.w, menu_size.h ); if( skinverwaltung_t::toolbar_background && skinverwaltung_t::toolbar_background->get_image_id(0) != IMG_EMPTY ) { const image_id back_img = skinverwaltung_t::toolbar_background->get_image_id(0); display_fit_img_to_width( back_img, env_t::iconsize.w ); stretch_map_t imag = { {IMG_EMPTY, IMG_EMPTY, IMG_EMPTY}, {IMG_EMPTY, back_img, IMG_EMPTY}, {IMG_EMPTY, IMG_EMPTY, IMG_EMPTY} }; display_img_stretch(imag, scr_rect(menu_pos, menu_size)); } else { display_fillbox_wh_rgb( menu_pos.x, menu_pos.y, menu_size.w, menu_size.h, color_idx_to_rgb(MN_GREY2), false ); } // .. extra logic to enable tooltips tooltip_element = main_menu->is_hit( get_mouse_pos().x-menu_pos.x, get_mouse_pos().y-menu_pos.y) ? main_menu : NULL; void *old_inside_event_handling = inside_event_handling; inside_event_handling = main_menu; menu_pos.y -= D_TITLEBAR_HEIGHT; main_menu->draw(menu_pos, menu_size); inside_event_handling = old_inside_event_handling; display_set_clip_wh(clip_rr.x, clip_rr.y, clip_rr.w, clip_rr.h); if(show_ticker || !ticker::empty()) { if (!show_ticker || wl->is_dirty()) { ticker::redraw(); } show_ticker = !ticker::empty(); ticker::draw(); } else { show_ticker = false; } if( skinverwaltung_t::compass_iso && env_t::compass_screen_position ) { display_img_aligned( skinverwaltung_t::compass_iso->get_image_id( wl->get_settings().get_rotation() ), scr_rect(D_MARGIN_LEFT, env_t::iconsize.h+D_MARGIN_TOP,disp_width-2*4,disp_height- env_t::iconsize.h -D_MARGIN_TOP-D_MARGIN_BOTTOM-win_get_statusbar_height()-(TICKER_HEIGHT)*show_ticker), env_t::compass_screen_position, false ); } { // clip windows to avoid drawing into menu, ticker, or status-bar PUSH_CLIP(clip_rr.x, clip_rr.y+(env_t::menupos==MENU_BOTTOM ? win_get_statusbar_height() + show_ticker*TICKER_HEIGHT:0), clip_rr.w, clip_rr.h - (TICKER_HEIGHT)*show_ticker - win_get_statusbar_height() ); display_all_win(); remove_old_win(); if(env_t::show_tooltips) { // check if there is a tooltip to display if( tooltip_text && *tooltip_text ) { // display tooltip when current owner is invalid or when it is within visible duration uint32 elapsed_time; if( !tooltip_owner || ((elapsed_time=dr_time()-tooltip_register_time)>env_t::tooltip_delay && elapsed_time<=env_t::tooltip_delay+env_t::tooltip_duration) ) { const sint16 width = proportional_string_width(tooltip_text)+(LINESPACE/2); scr_coord pos{ tooltip_xpos, tooltip_ypos }; win_clamp_xywh_position( NULL, pos, scr_size( width, (LINESPACE*9)/7 ), true ); display_ddd_proportional_clip( pos.x, pos.y, env_t::tooltip_color, env_t::tooltip_textcolor, tooltip_text, true); if(wl) { wl->set_background_dirty(); } } } else if(!static_tooltip_text.empty()) { const sint16 width = proportional_string_width(static_tooltip_text.c_str())+ (LINESPACE/2); scr_coord pos = get_mouse_pos(); win_clamp_xywh_position( NULL, pos, scr_size(width, (LINESPACE*9)/7), true); display_ddd_proportional_clip(pos.x, pos.y, env_t::tooltip_color, env_t::tooltip_textcolor, static_tooltip_text.c_str(), true); if(wl) { wl->set_background_dirty(); } } // reset owner and group if no tooltip has been registered if( !tooltip_text ) { tooltip_owner = 0; tooltip_group = 0; } // clear tooltip text to avoid sticky tooltips tooltip_text = 0; } POP_CLIP(); if(!wl) { // no infos during loading etc return; } } char const* time; if (status_show_compact && env_t::show_month >= env_t::DATE_FMT_JAPANESE && env_t::show_month <= env_t::DATE_FMT_GERMAN) { // omit season from the date string env_t::show_month += 3; time = tick_to_string(wl->get_ticks()); env_t::show_month -= 3; } else { time = tick_to_string(wl->get_ticks()); } // statusbar background scr_coord_val const status_bar_height = win_get_statusbar_height(); scr_coord_val const status_bar_y =env_t::menupos == MENU_BOTTOM ? 0 : disp_height - status_bar_height; scr_coord_val const status_bar_text_y = status_bar_y + (status_bar_height - LINESPACE) / 2; scr_coord_val const status_bar_icon_y = status_bar_y + (status_bar_height - 15) / 2; display_set_clip_wh( 0, 0, disp_width, disp_height ); display_fillbox_wh_rgb(0, status_bar_y - 1, disp_width, 1, SYSCOL_STATUSBAR_DIVIDER, false); display_fillbox_wh_rgb(0, env_t::menupos == MENU_BOTTOM ? status_bar_height : status_bar_y - 1, disp_width, 1, SYSCOL_STATUSBAR_DIVIDER, false); display_fillbox_wh_rgb(0, status_bar_y, disp_width, status_bar_height, SYSCOL_STATUSBAR_BACKGROUND, false); bool tooltip_check = env_t::menupos == MENU_BOTTOM ? get_mouse_pos().y < status_bar_height : get_mouse_pos().y > status_bar_y; if( tooltip_check ) { tooltip_xpos = get_mouse_pos().x; tooltip_ypos = env_t::menupos == MENU_BOTTOM ? status_bar_height + 10 + TICKER_HEIGHT * show_ticker : status_bar_y - 10 - TICKER_HEIGHT * show_ticker; } scr_coord_val left_border = 2; // season icon display_color_img( skinverwaltung_t::seasons_icons->get_image_id(wl->get_season()), left_border, status_bar_icon_y, 0, false, true ); if( tooltip_check && tooltip_xpos<14 ) { static char const* const seasons[] = { "q2", "q3", "q4", "q1" }; tooltip_text = translator::translate(seasons[wl->get_season()]); tooltip_check = false; } left_border += 14; scr_coord_val right_border = disp_width-4; // shown if timeline game if( wl->use_timeline() && skinverwaltung_t::timelinesymbol ) { right_border -= 14; display_color_img( skinverwaltung_t::timelinesymbol->get_image_id(0), right_border, status_bar_icon_y, 0, false, true ); if( tooltip_check && tooltip_xpos>=right_border ) { tooltip_text = translator::translate("timeline"); tooltip_check = false; } } // shown if connected if( env_t::networkmode && skinverwaltung_t::networksymbol ) { right_border -= 14; display_color_img( skinverwaltung_t::networksymbol->get_image_id(0), right_border, status_bar_icon_y, 0, false, true ); if( tooltip_check && tooltip_xpos>=right_border ) { tooltip_text = translator::translate("Connected with server"); tooltip_check = false; } } // put pause icon if( wl->is_paused() && skinverwaltung_t::pausesymbol ) { right_border -= 14; display_color_img( skinverwaltung_t::pausesymbol->get_image_id(0), right_border, status_bar_icon_y, 0, false, true ); if( tooltip_check && tooltip_xpos>=right_border ) { tooltip_text = translator::translate("GAME PAUSED"); tooltip_check = false; } } // put fast forward icon if( wl->is_fast_forward() && skinverwaltung_t::fastforwardsymbol ) { right_border -= 14; display_color_img( skinverwaltung_t::fastforwardsymbol->get_image_id(0), right_border, status_bar_icon_y, 0, false, true ); if( tooltip_check && tooltip_xpos>=right_border ) { tooltip_text = translator::translate("Fast forward"); tooltip_check = false; } } right_border -= 4; koord3d pos = wl->get_zeiger()->get_pos(); static cbuffer_t info; info.clear(); if( pos!=koord3d::invalid ) { info.printf( "(%s)", pos.get_str() ); } if( skinverwaltung_t::timelinesymbol==NULL ) { info.printf( " %s", translator::translate(wl->use_timeline()?"timeline":"no timeline") ); } if(wl->show_distance!=koord3d::invalid && wl->show_distance!=pos) { info.printf("-(%d,%d)", wl->show_distance.x-pos.x, wl->show_distance.y-pos.y ); } if( !env_t::networkmode ) { // time multiplier text if(wl->is_fast_forward()) { info.printf(" %s(T~%1.2f)", skinverwaltung_t::fastforwardsymbol?"":">> ", wl->get_simloops()/50.0 ); } else if(!wl->is_paused()) { if (wl->get_time_multiplier() != 16) { info.printf(" (T=%1.2f)", wl->get_time_multiplier() / 16.0); } } else if( skinverwaltung_t::pausesymbol==NULL ) { info.printf( " %s", translator::translate("GAME PAUSED") ); } } #ifdef DEBUG if( env_t::verbose_debug>1 ) { if( haltestelle_t::get_rerouting_status()==RECONNECTING ) { info.append( " +" ); } else if( haltestelle_t::get_rerouting_status()==REROUTING ) { info.append( " *" ); } if( skinverwaltung_t::compass_iso == NULL && wl->get_settings().get_rotation() ) { static const char *compass_dir[4] = { "North", "East", "South", "West" }; info.append( " " ); info.append( translator::translate( compass_dir[ 4-wl->get_settings().get_rotation() ] ) ); } } #endif left_border += 4 + display_proportional_rgb(left_border, status_bar_text_y, time, ALIGN_LEFT, SYSCOL_STATUSBAR_TEXT, true); right_border -= 4 + display_proportional_rgb(right_border, status_bar_text_y, info, ALIGN_RIGHT, SYSCOL_STATUSBAR_TEXT, true); /* Since the visual center jumps left and right with proportional fonts, we quantisze by 16 pixel */ left_border = (left_border + 15) & 0xFFFFFFF0ul; right_border = (right_border - 15) & 0xFFFFFFF0ul; if(wl->get_active_player()) { char buffer[256]; scr_coord_val textwidth_pl = 0; textwidth_pl = D_H_SPACE + proportional_string_width(wl->get_active_player()->get_name()); if (status_show_compact) { number_to_string_fit(buffer, konto, 0, 10); strcat(buffer, "$"); } else { money_to_string(buffer, konto); } scr_coord_val textwidth_mn = (proportional_string_width(buffer)+15) & 0xFFFFFFF0ul; if (textwidth_mn + textwidth_pl < right_border - left_border) { // everything fits left_border += ( (right_border - left_border) - (textwidth_mn + textwidth_pl) ) / 2; left_border += D_H_SPACE + display_proportional_rgb(left_border, status_bar_text_y, wl->get_active_player()->get_name(), ALIGN_LEFT, PLAYER_FLAG | color_idx_to_rgb(wl->get_active_player()->get_player_color1() + env_t::gui_player_color_dark), true); display_proportional_rgb(left_border, status_bar_text_y, buffer, ALIGN_LEFT, konto >= 0.0 ? MONEY_PLUS : MONEY_MINUS, true); } else { // no space => only money status_show_compact = true; // make sure the seasons are omitted next time scr_coord_val width_left = (right_border - left_border - textwidth_mn); if (width_left > 50) { scr_rect r(left_border, status_bar_text_y, width_left-D_H_SPACE, LINESPACE); display_proportional_ellipsis_rgb(r, wl->get_active_player()->get_name(), ALIGN_LEFT, PLAYER_FLAG | color_idx_to_rgb(wl->get_active_player()->get_player_color1() + env_t::gui_player_color_dark), true); left_border += width_left; // normal color display_proportional_rgb(left_border, status_bar_text_y, buffer, ALIGN_LEFT, konto >= 0.0 ? MONEY_PLUS : MONEY_MINUS, true); } else { // just money in player color, no player name if (width_left > 0) { left_border += (right_border - left_border - textwidth_mn) / 2; } else { // shortest possible money strong number_to_string_fit(buffer, konto, 0, 5); strcat(buffer, "$"); } display_proportional_rgb(left_border, status_bar_text_y, buffer, ALIGN_LEFT, konto >= 0.0 ? color_idx_to_rgb(wl->get_active_player()->get_player_color1() + env_t::gui_player_color_dark) : MONEY_MINUS, true); } } } } void win_set_world(karte_t *world) { wl = world; // remove all save window positions old_win_pos.clear(); } void win_redraw_world() { if(wl) { wl->set_dirty(); } } bool win_change_zoom_factor(bool magnify) { const bool result = magnify ? zoom_factor_up() : zoom_factor_down(); if(magnify && wl->is_step_mode_normal()) { wl->reset_timer(); } wl->get_viewport()->metrics_updated(); return result; } void win_load_font(const char *fname, uint8 fontsize) { bool force_reload = fontsize != env_t::fontsize; env_t::fontsize = fontsize; if (display_load_font(fname, force_reload) ) { // successfull gui_theme_t::themes_init( env_t::default_theme, false, false ); event_t *ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_THEME_CHANGED; queue_event( ev ); } else { // restore old font display_load_font(env_t::fontname.c_str(), true); } win_redraw_world(); } /** * Sets the tooltip to display. * Has to be called from within gui_frame_t::draw * * @param pos * @param text * @param group * @param owner : owner==NULL disables timing (initial delay and visible duration) */ void win_set_tooltip(scr_coord pos, const char *text, const void *const owner, const void *const group) { // check whether the right window will set the tooltip if(inside_event_handling != tooltip_element ) { return; } // must be set every time as win_display_flush() will reset them tooltip_text = text; // update ownership if changed if( owner!=tooltip_owner ) { tooltip_owner = owner; // update register time only if owner is valid if( owner ) { const uint32 current_time = dr_time(); if( group && group==tooltip_group ) { // case : same group const uint32 elapsed_time = current_time - tooltip_register_time; const uint32 threshold = env_t::tooltip_delay - (env_t::tooltip_delay>>2); // 3/4 of delay if( elapsed_time>threshold && elapsed_time<=env_t::tooltip_delay+env_t::tooltip_duration ) { // case : threshold was reached and duration not expired -> delay time is reduced to 1/4 tooltip_register_time = current_time - threshold; } else { // case : either before threshold or duration expired tooltip_register_time = current_time; } } else { // case : owner has no associated group or group is different -> simply reset to current time tooltip_group = group; tooltip_register_time = current_time; } } else { // no owner to associate with a group even if the group is valid tooltip_group = 0; } } if (text) { const scr_size tt_size = scr_size(proportional_string_width(text), LINESPACE + 2); win_clamp_xywh_position(NULL, pos, tt_size, true); pos.y += LINESPACE / 2 + 1; } tooltip_xpos = pos.x; tooltip_ypos = pos.y; } /** * Sets the tooltip to display. */ void win_set_static_tooltip(const char *text) { static_tooltip_text = text ? text : ""; } // shows a modal dialoge void modal_dialogue(gui_frame_t* gui, ptrdiff_t magic, karte_t* welt, bool (*quit)(), bool dismissible) { if (display_get_width() == 0) { dbg->error("modal_dialogue", "called without a display driver => nothing will be shown!"); env_t::quit_simutrans = true; // cannot handle this! return; } // switch off autosave sint32 old_autosave = env_t::autosave; env_t::autosave = 0; event_t ev; create_win(scr_coord(0,0), gui, w_info, magic); scr_coord pos{ (display_get_width() - gui->get_windowsize().w) / 2, (display_get_height() - gui->get_windowsize().h) / 2 }; win_clamp_xywh_position(gui, pos, gui->get_windowsize(), true); wins[wins[0].gui!=gui].pos = pos; if (welt) { welt->set_pause(false); welt->reset_interaction(); welt->reset_timer(); set_random_mode(MODAL_RANDOM); const uint32 ms_per_frame = 1000 / env_t::fps; const uint32 sync_steps_per_step = 5; // env_t::network_frames_per_step uint32 frame_start_time; uint32 sync_steps_until_step = sync_steps_per_step; while (gui && win_is_open(gui) && !env_t::quit_simutrans && !quit()) { frame_start_time = dr_time(); do { DBG_DEBUG4("modal_dialogue", "calling win_poll_event"); win_poll_event(&ev); if (ev.ev_class == EVENT_SYSTEM && ev.ev_code == SYSTEM_QUIT) { welt->stop(true); break; } win_clamp_xywh_position(NULL, ev.mouse_pos, scr_size(1, 1), false); win_clamp_xywh_position(NULL, ev.mouse_pos, scr_size(1, 1), false); if (ev.ev_class == EVENT_KEYBOARD && ev.ev_code == SIM_KEY_F1) { if (gui_frame_t* win = win_get_top()) { if (const char* helpfile = win->get_help_filename()) { help_frame_t::open_help_on(helpfile); continue; } } } if(dismissible && gui){ if ( (ev.ev_class == EVENT_KEYBOARD) || (ev.ev_class == EVENT_CLICK && !gui->is_hit(ev.click_pos.x - pos.x, ev.click_pos.y - pos.y)) ) { destroy_win(gui); gui = NULL; } } DBG_DEBUG4("modal_dialogue", "calling check_pos_win"); check_pos_win(&ev, true); } while( ev.ev_class != EVENT_NONE && dr_time()-frame_start_time < 50 ); const uint32 delta_t = (ms_per_frame * welt->get_time_multiplier()) / 16; DBG_DEBUG4("modal_dialogue", "calling welt->sync_step(%u)", delta_t); welt->sync_step(delta_t); welt->display(delta_t); if (--sync_steps_until_step == 0) { DBG_DEBUG4("modal_dialogue", "calling welt->step"); intr_disable(); welt->step(); intr_enable(); sync_steps_until_step = sync_steps_per_step; } const uint32 next_frame_start_time = frame_start_time + ms_per_frame; const uint32 now = dr_time(); if (now < next_frame_start_time) { dr_sleep(next_frame_start_time - now); } } clear_random_mode(MODAL_RANDOM); } else { display_show_pointer(true); display_show_load_pointer(0); display_fillbox_wh_rgb(0, 0, display_get_width(), display_get_height(), color_idx_to_rgb(COL_BLACK), true); while (gui && win_is_open(gui) && !env_t::quit_simutrans && !quit()) { // do not move, do not close it! // check for events again after waiting if (quit()) { break; } dr_prepare_flush(); gui->draw(win_get_pos(gui), gui->get_windowsize()); dr_flush(); // some backends (etc. SDL2) tend to flood the queue with events. Hence we need to process them all quickly uint32 frame_start_time = dr_time(); do { display_poll_event(&ev); if (ev.ev_class == EVENT_SYSTEM) { if (ev.ev_code == SYSTEM_RESIZE) { // main window resized simgraph_resize(ev.new_window_size); dr_prepare_flush(); display_fillbox_wh_rgb(0, 0, ev.new_window_size.w, ev.new_window_size.h, color_idx_to_rgb(COL_BLACK), true); gui->draw(win_get_pos(gui), gui->get_windowsize()); dr_flush(); } else if (ev.ev_code == SYSTEM_QUIT) { // no world yet => simple quit env_t::quit_simutrans = true; break; } } else { // other events check_pos_win(&ev,true); } // however, after 50ms we do a redraw ... } while (ev.ev_class != EVENT_NONE && dr_time() - frame_start_time < 50); // sleep the rest of the time uint32 end_time = dr_time(); if (end_time - frame_start_time < 50) { dr_sleep(50 - (end_time - frame_start_time)); } } display_show_load_pointer(1); dr_prepare_flush(); display_fillbox_wh_rgb(0, 0, display_get_width(), display_get_height(), color_idx_to_rgb(COL_BLACK), true); dr_flush(); } // just trigger not another following window => wait for button release if (IS_LEFTCLICK(&ev)) { do { display_poll_event(&ev); } while (!IS_LEFTRELEASE(&ev)); } // restore autosave env_t::autosave = old_autosave; } simutrans-124.3/src/simutrans/gui/simwin.h000066400000000000000000000145721474050137200206430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SIMWIN_H #define GUI_SIMWIN_H #include // for ptrdiff_t #include "../simtypes.h" #include "../simconst.h" #include "../display/scr_coord.h" /* * The function implements a WindowManager 'Object' * There's only one WindowManager */ class karte_t; class scr_coord; class loadsave_t; class gui_frame_t; class gui_component_t; struct event_t; /* Types for the window */ enum wintype { w_info = 1 << 0, // A info window w_do_not_delete = 1 << 1, // A window whose GUI object should not be deleted on close w_no_overlap = 1 << 2, // try to place it below a previous window with the same flag w_time_delete = 1 << 3 // deletion after MESG_WAIT has elapsed }; ENUM_BITSET(wintype) enum magic_numbers { magic_none = -1, magic_reserved = 0, // from here on, delete second 'new'-ed object in create_win magic_settings_frame_t, magic_sprachengui_t, magic_themes, magic_welt_gui_t, magic_climate, magic_reliefmap, magic_farbengui_t, magic_color_gui_t, magic_ki_kontroll_t, magic_optionen_gui_t, magic_sound_kontroll_t, magic_load_t, magic_load_scenario, magic_load_script, magic_save_t, magic_UNUSED_railtools, magic_UNUSED_monorailtools, magic_UNUSED_tramtools, // Dario: Tramway magic_UNUSED_roadtools, magic_UNUSED_shiptools, magic_UNUSED_airtools, magic_UNUSED_specialtools, magic_UNUSED_listtools, magic_UNUSED_edittools, magic_UNUSED_slopetools, magic_UNUSED_halt_list_t, magic_UNUSED_label_frame, magic_city_info_t, magic_citylist_frame_t, magic_mainhelp, // player dependent stuff => 16 times present magic_finances_t, magic_convoi_list = magic_finances_t + MAX_PLAYER_COUNT, magic_convoi_list_filter = magic_convoi_list + MAX_PLAYER_COUNT, magic_line_list = magic_convoi_list_filter + MAX_PLAYER_COUNT, magic_halt_list = magic_line_list + MAX_PLAYER_COUNT, magic_line_management_t = magic_halt_list + MAX_PLAYER_COUNT, magic_ai_options_t = magic_line_management_t + MAX_PLAYER_COUNT, magic_ai_selector = magic_ai_options_t + MAX_PLAYER_COUNT, magic_pwd_t = magic_ai_selector + MAX_PLAYER_COUNT, magic_jump = magic_pwd_t + MAX_PLAYER_COUNT, magic_headquarter = magic_jump + MAX_PLAYER_COUNT, // normal stuff magic_curiositylist, magic_factorylist, magic_goodslist, magic_messageframe, magic_message_options, magic_scenario_frame, magic_scenario_info, magic_edit_factory, magic_edit_attraction, magic_edit_house, magic_edit_tree, magic_bigger_map, magic_labellist, magic_station_building_select, magic_server_frame_t, magic_pakset_info_t, magic_line_schedule_rdwr_dummy, // only used to save/load line schedules magic_motd, magic_factory_info, // only used to load/save magic_font, magic_soundfont, // only with USE_FLUIDSYNTH_MIDI magic_edit_groundobj, // magic numbers with big jumps between them magic_convoi_info, magic_UNUSED_convoi_detail = magic_convoi_info + 0x10000, // unused range magic_halt_info = magic_UNUSED_convoi_detail + 0x10000, magic_UNUSED_halt_detail = magic_halt_info + 0x10000, // unused range magic_toolbar = magic_UNUSED_halt_detail + 0x10000, magic_script_error = magic_toolbar + 0x100, magic_haltlist_filter, magic_depot, // only used to load/save magic_depotlist = magic_depot + MAX_PLAYER_COUNT, magic_vehiclelist = magic_depotlist + MAX_PLAYER_COUNT, magic_pakinstall, magic_chatframe, magic_player_ranking, magic_script_generator, // only during saving magic_max }; // Holding time for auto-closing windows #define MESG_WAIT 80 // windows with a valid id can be saved and restored void rdwr_all_win(loadsave_t *file); // save windowsizes in settings void rdwr_win_settings(loadsave_t *file); // returns the client area and offset scr_rect win_get_max_window_area(); void win_clamp_xywh_position(gui_frame_t *gui, scr_coord &pos, bool move_to_full_view); int create_win(gui_frame_t *gui, wintype type, ptrdiff_t magic); int create_win(scr_coord pos, gui_frame_t *gui, wintype type, ptrdiff_t magic); // call to avoid the main menu getting mouse events while dragging void catch_dragging(); bool check_pos_win(event_t*,bool modal); scr_coord const& win_get_pos(gui_frame_t const*); void win_set_pos(gui_frame_t *window, scr_coord new_pos); gui_frame_t *win_get_top(); // returns the focused component of the top window gui_component_t *win_get_focus(); // true, if the focus is currently in a text field bool win_is_textinput(); uint32 win_get_open_count(); gui_frame_t* win_get_index(uint32 i); // returns the window (if open) otherwise zero gui_frame_t *win_get_magic(ptrdiff_t magic); // sets the magic of a gui_frame_t (needed during reload of windows) bool win_set_magic( gui_frame_t *gui, ptrdiff_t magic ); /** * Checks if a window is a top level window */ bool win_is_top(const gui_frame_t *ig); // return true if actually window was destroyed (or marked for destruction) bool destroy_win(const gui_frame_t *ig); bool destroy_win(const ptrdiff_t magic); void destroy_all_win(bool destroy_sticky); void rollup_all_win(); void rolldown_all_win(); bool top_win(const gui_frame_t *ig, bool keep_rollup=false ); void display_all_win(); void win_rotate90( sint16 new_size ); void win_display_flush(double konto); // draw the frame and all windows uint16 win_get_statusbar_height(); void win_poll_event(event_t*); bool win_change_zoom_factor(bool magnify); /** * Sets the world this window manager is attached to. */ void win_set_world(karte_t *world); /** * Forces the redraw of the world on next frame. */ void win_redraw_world(); /** * Loads new font. Notifies gui's, world. */ void win_load_font(const char *fname, uint8 fontsize); /** * Sets the tooltip to display. * @param owner : owner==NULL disables timing (initial delay and visible duration) */ void win_set_tooltip(scr_coord pos, const char *text, const void *const owner = NULL, const void *const group = NULL); /** * Sets a static tooltip that follows the mouse * *MUST* be explicitly unset! */ void win_set_static_tooltip(const char *text); // shows a modal dialoge (blocks other interaction) void modal_dialogue(gui_frame_t* gui, ptrdiff_t magic, karte_t* welt, bool (*quit)(), bool dismissible = false); #endif simutrans-124.3/src/simutrans/gui/sound_frame.cc000066400000000000000000000166251474050137200217760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * Dialog for sound settings */ #include "sound_frame.h" #include "../simsound.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "components/gui_divider.h" #ifdef USE_FLUIDSYNTH_MIDI #include "loadsoundfont_frame.h" #endif #define L_KNOB_SIZE (32) void sound_frame_t::update_song_name() { const int current_midi_index = get_current_midi(); std::string credits = ""; if( current_midi_index < 0 ) { song_name_label.buf().printf( translator::translate("Music playing disabled/not available") ); } #ifdef USE_FLUIDSYNTH_MIDI else if( strcmp( env_t::soundfont_filename.c_str(), "Error") == 0 ){ song_name_label.buf().printf( translator::translate("Soundfont not found. Please select a soundfont below.") ); } #endif else { midi_info_t current_midi = sound_get_midi_info( current_midi_index ); song_name_label.buf().printf("%d - %s", current_midi_index + 1, current_midi.title.c_str() ); if ( current_midi.composer != "-" ) { credits.append( translator::translate("Composed by") ); credits.append(" " + current_midi.composer + " "); if( current_midi.arranger != "-" ) { credits.append( translator::translate("and arranged by") ); credits.append( " " + current_midi.arranger ); } } } song_name_label.update(); song_name_label.set_size( song_name_label.get_min_size() ); song_credits_label.buf().printf(credits.c_str()); song_credits_label.update(); song_credits_label.set_size( song_credits_label.get_min_size() ); // Loadsoundfont dialog may unmute us, update mute status music_mute_button.pressed = midi_get_mute(); previous_song_button.enable( !music_mute_button.pressed ); next_song_button.enable( !music_mute_button.pressed ); } const char *specific_volume_names[ MAX_SOUND_TYPES ] = { "TOOL_SOUND", "TRAFFIC_SOUND", "AMBIENT_SOUND", "FACTORY_SOUND", "CROSSING_SOUND", "CASH_SOUND" }; sound_frame_t::sound_frame_t() : gui_frame_t( translator::translate("Sound settings") ), sound_volume_scrollbar(scrollbar_t::horizontal), music_volume_scrollbar(scrollbar_t::horizontal) { set_table_layout(1,0); sound_mute_button.init( button_t::square_state, "mute sound"); sound_mute_button.pressed = sound_get_mute(); sound_mute_button.add_listener( this ); add_component(&sound_mute_button); add_table(2,0); { // Sound volume label new_component( "Sound volume:" ); sound_volume_scrollbar.set_knob( L_KNOB_SIZE, 255 + L_KNOB_SIZE ); sound_volume_scrollbar.set_knob_offset( sound_get_global_volume() ); sound_volume_scrollbar.set_scroll_discrete( false ); sound_volume_scrollbar.add_listener( this ); add_component( &sound_volume_scrollbar ); new_component( "Sound range:" ); sound_range.set_value( env_t::sound_distance_scaling); sound_range.set_limits( 1, 32 ); sound_range.add_listener(this); // sound_range.set_tooltip( "Lower values mean more local sounds" ) add_component(&sound_range); for( int i = 0; i < MAX_SOUND_TYPES; i++ ) { new_component( specific_volume_names[i] ); specific_volume_scrollbar[ i ] = new scrollbar_t( scrollbar_t::horizontal ); specific_volume_scrollbar[i]->set_knob( L_KNOB_SIZE, 255 + L_KNOB_SIZE ); specific_volume_scrollbar[i]->set_knob_offset( sound_get_specific_volume((sound_type_t)i) ); specific_volume_scrollbar[i]->set_scroll_discrete( false ); specific_volume_scrollbar[i]->add_listener( this ); add_component( specific_volume_scrollbar[i] ); } } end_table(); new_component(); // Music music_mute_button.init( button_t::square_state, "disable midi"); music_mute_button.pressed = midi_get_mute(); music_mute_button.add_listener( this ); #ifdef USE_FLUIDSYNTH_MIDI if( strcmp( env_t::soundfont_filename.c_str(), "Error" ) == 0 ){ music_mute_button.enable( !music_mute_button.pressed ); } #endif add_component(&music_mute_button); shuffle_song_button.init( button_t::square_state, "shuffle midis" ); shuffle_song_button.pressed = sound_get_shuffle_midi(); shuffle_song_button.add_listener(this); add_component(&shuffle_song_button); add_table(2,0); { new_component( "Music volume:" ); music_volume_scrollbar.set_knob( L_KNOB_SIZE, 255 + L_KNOB_SIZE ); music_volume_scrollbar.set_knob_offset( sound_get_midi_volume() ); music_volume_scrollbar.set_scroll_discrete( false ); music_volume_scrollbar.add_listener( this ); add_component( &music_volume_scrollbar ); } end_table(); new_component(); // song selection new_component( "Currently playing:" ); add_table( 3, 1 ); { previous_song_button.set_typ( button_t::arrowleft ); previous_song_button.add_listener( this ); previous_song_button.enable( !music_mute_button.pressed ); add_component( &previous_song_button ); next_song_button.set_typ( button_t::arrowright ); next_song_button.add_listener( this ); next_song_button.enable( !music_mute_button.pressed ); add_component( &next_song_button ); add_component( &song_name_label ); update_song_name(); } end_table(); add_component( &song_credits_label ); new_component(); #ifdef USE_FLUIDSYNTH_MIDI // Soundfont selection soundfont_button.init( button_t::roundbox_state | button_t::flexible, "Select soundfont" ); soundfont_button.add_listener(this); add_component( &soundfont_button ); #endif set_resizemode(diagonal_resize); reset_min_windowsize(); } bool sound_frame_t::action_triggered( gui_action_creator_t *comp, value_t p) { if (comp == &next_song_button) { midi_stop(); midi_next_track(); check_midi(); update_song_name(); } else if (comp == &previous_song_button) { midi_stop(); midi_last_track(); check_midi(); update_song_name(); } else if (comp == &shuffle_song_button) { sound_set_shuffle_midi( !sound_get_shuffle_midi() ); shuffle_song_button.pressed = sound_get_shuffle_midi(); } else if (comp == &sound_mute_button) { sound_set_mute( !sound_mute_button.pressed ); sound_mute_button.pressed = sound_get_mute(); } else if (comp == &music_mute_button) { midi_set_mute( !music_mute_button.pressed ); music_mute_button.pressed = midi_get_mute(); previous_song_button.enable( !music_mute_button.pressed ); next_song_button.enable( !music_mute_button.pressed ); } else if (comp == &sound_volume_scrollbar) { sound_set_global_volume(p.i); } else if (comp == &music_volume_scrollbar) { sound_set_midi_volume(p.i); } else if (comp == &sound_range) { env_t::sound_distance_scaling = p.i; } #ifdef USE_FLUIDSYNTH_MIDI else if( comp == &soundfont_button ) { create_win( new loadsoundfont_frame_t(), w_info, magic_soundfont ); } #endif else { for( int i = 0; i < MAX_SOUND_TYPES; i++ ) { if( comp == specific_volume_scrollbar[ i ] ) { sound_set_specific_volume( p.i, (sound_type_t)i ); } } } return true; } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void sound_frame_t::draw(scr_coord pos, scr_size size) { // update song name label update_song_name(); #ifdef USE_FLUIDSYNTH_MIDI if( strcmp(env_t::soundfont_filename.c_str(), "Error") != 0 ){ music_mute_button.enable( true ); } #endif gui_frame_t::draw(pos, size); } // need to delete scroll bars sound_frame_t::~sound_frame_t() { for( int i = 0; i < MAX_SOUND_TYPES; i++ ) { delete specific_volume_scrollbar[ i ]; } } simutrans-124.3/src/simutrans/gui/sound_frame.h000066400000000000000000000023341474050137200216300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SOUND_FRAME_H #define GUI_SOUND_FRAME_H #include "gui_frame.h" #include "components/gui_scrollbar.h" #include "components/gui_label.h" #include "components/gui_button.h" #include "components/gui_numberinput.h" #include "components/action_listener.h" /** * Dialog for sound settings */ class sound_frame_t : public gui_frame_t, action_listener_t { private: scrollbar_t sound_volume_scrollbar; scrollbar_t music_volume_scrollbar; scrollbar_t *specific_volume_scrollbar[MAX_SOUND_TYPES+1]; gui_numberinput_t sound_range; button_t sound_mute_button; button_t music_mute_button; button_t next_song_button; button_t previous_song_button; button_t shuffle_song_button; #ifdef USE_FLUIDSYNTH_MIDI button_t soundfont_button; #endif gui_label_buf_t song_name_label; gui_label_buf_t song_credits_label; void update_song_name(); public: const char *get_help_filename() const OVERRIDE {return "sound.txt";} sound_frame_t(); virtual ~sound_frame_t(); // used for updating the song title void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/sprachen.cc000066400000000000000000000115341474050137200212710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../pathes.h" #include "../display/simimg.h" #include "../simskin.h" #include "../tool/simmenu.h" #include "../descriptor/skin_desc.h" #include "sprachen.h" #include "loadfont_frame.h" #include "simwin.h" #include "components/gui_image.h" #include "components/gui_divider.h" #include "../display/font.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../sys/simsys.h" #include "../utils/simstring.h" #include "../world/simworld.h" int sprachengui_t::cmp_language_button(sprachengui_t::language_button_t a, sprachengui_t::language_button_t b) { return strcmp( a.button->get_text(), b.button->get_text() )<0; } /** * Causes the required fonts for currently selected * language to be loaded */ void sprachengui_t::init_font_from_lang() { bool reload_font = !has_character( translator::get_lang()->highest_character ); // the real fonts for the current language std::string old_font = env_t::fontname; static const char *default_name = "PROP_FONT_FILE"; const char *prop_font_file = translator::translate(default_name); // fallback if entry is missing -> use latin-1 font if( prop_font_file == default_name ) { prop_font_file = "cyr.bdf"; } if( reload_font ) { // load large font dr_chdir( env_t::base_dir ); bool ok = false; char prop_font_file_name[4096]; tstrncpy( prop_font_file_name, prop_font_file, lengthof(prop_font_file_name) ); char *f = strtok( prop_font_file_name, ";" ); do { std::string fname = FONT_PATH_X; fname += prop_font_file_name; ok = display_load_font(fname.c_str()); f = strtok( NULL, ";" ); } while( !ok && f ); dr_chdir( env_t::user_dir ); } const char * p = translator::translate("SEP_THOUSAND"); char c = ','; if(*p != 'S') { c = *p; } set_thousand_sep(c); set_thousand_sep_exponent(atoi(translator::translate("SEP_THOUSAND_EXPONENT"))); p = translator::translate("SEP_FRACTION"); c = '.'; if(*p != 'S') { c = *p; } set_fraction_sep(c); const char *str = "LARGE_NUMBER_STRING"; p = translator::translate(str); double v = atof( translator::translate("LARGE_NUMBER_VALUE") ); if(p == str || v==0.0) { // fallback: will ignore it p = ""; v = 1e99; } set_large_amount(p,v); } sprachengui_t::sprachengui_t() : gui_frame_t( translator::translate("Sprachen") ), text_label(&buf), buttons(translator::get_language_count()) { set_table_layout(2,0); buf.clear(); buf.append(translator::translate("LANG_CHOOSE\n")); text_label.set_buf(&buf); // force recalculation of size add_component( &text_label ); if (skinverwaltung_t::flaggensymbol) { gui_image_t *flags = new_component(skinverwaltung_t::flaggensymbol->get_image_id(0)); flags->enable_offset_removal(true); } else { new_component(); } new_component_span(2); const translator::lang_info* lang = translator::get_langs(); dr_chdir( env_t::base_dir ); for (int i = 0; i < translator::get_language_count(); ++i, ++lang) { button_t* b = new button_t(); b->set_typ(button_t::square_state); b->set_text(lang->name); b->set_no_translate(true); // we do not check for a working font anymore b->add_listener(this); // press button int id = translator::get_language(lang->iso); if( translator::get_language() == id ) { b->pressed = true; } // insert ordered by language name language_button_t lb; lb.button = b; lb.id = id; buttons.insert_ordered(lb, sprachengui_t::cmp_language_button); } dr_chdir(env_t::user_dir); // insert buttons such that language appears columnswise const uint32 count = buttons.get_count(); const uint32 half = (count+1)/2; for(uint32 i=0; i < half; i++) { add_component(buttons[i].button); if (i+ half < count) { add_component(buttons[i+half].button); } } reset_min_windowsize(); set_windowsize(get_min_windowsize() ); } bool sprachengui_t::action_triggered( gui_action_creator_t *comp, value_t) { for(int i=0; ipressed = true; translator::set_language( buttons[i].id ); init_font_from_lang(); event_t* ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event( ev ); // check if we need another font ... { // we only show matching fonts for this language const utf8 *new_world = (const utf8 *)translator::translate("Beenden"); size_t len; if (!has_character(utf8_decoder_t::decode(new_world, len))) { // load a matching font ... create_win(new loadfont_frame_t(), w_info, magic_font); } } if (world()) { // must not update non-existent toolbars tool_t::update_toolbars(); } } else { b->pressed = false; } } return true; } simutrans-124.3/src/simutrans/gui/sprachen.h000066400000000000000000000021531474050137200211300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_SPRACHEN_H #define GUI_SPRACHEN_H #include "gui_frame.h" #include "components/action_listener.h" #include "components/gui_button.h" #include "components/gui_textarea.h" #include "../utils/cbuffer.h" #include "../tpl/vector_tpl.h" /** * Dialog for language change */ class sprachengui_t : public gui_frame_t, private action_listener_t { private: cbuffer_t buf; gui_textarea_t text_label; struct language_button_t { button_t* button; int id; }; vector_tpl buttons; static int cmp_language_button(sprachengui_t::language_button_t a, sprachengui_t::language_button_t b); public: /** * Causes the required fonts for currently selected * language to be loaded if true */ static void init_font_from_lang(); sprachengui_t(); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "language.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/station_building_select.cc000066400000000000000000000037011474050137200243600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * Building facing selector, when CTRL+Clicking over a building icon in menu */ #include "../world/simworld.h" #include "../tool/simtool.h" #include "simwin.h" #include "../utils/cbuffer.h" #include "station_building_select.h" #include "components/gui_label.h" #include "components/gui_building.h" #include "../descriptor/building_desc.h" static const char label_text[4][64] = { "sued", "ost", "nord", "west" }; tool_build_station_t station_building_select_t::tool=tool_build_station_t(); station_building_select_t::station_building_select_t(const building_desc_t *desc) : gui_frame_t( translator::translate("Choose direction") ) { this->desc = desc; set_table_layout(1,0); set_alignment(ALIGN_CENTER_H); gui_label_buf_t *lb = new_component(); lb->buf().printf( translator::translate("Width = %d, Height = %d"), desc->get_x(0), desc->get_y(0)); lb->update(); // the image array add_table(2,2); { for( sint16 i=0; iget_all_layouts(),4); i++ ) { add_table(1,0)->set_alignment(ALIGN_CENTER_H); { gui_building_t *g = new_component(desc, i); g->add_listener(this); actionbutton[i].init( button_t::roundbox | button_t::flexible, translator::translate(label_text[i]) ); actionbutton[i].add_listener(this); add_component(&actionbutton[i]); } end_table(); } } end_table(); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool station_building_select_t::action_triggered( gui_action_creator_t *comp, value_t v) { for(int i=0; i<4; i++) { if(comp == &actionbutton[i] || v.i == i) { static cbuffer_t default_str; default_str.clear(); default_str.printf("%s,%i", desc->get_name(), i ); tool.set_default_param(default_str); welt->set_tool( &tool, welt->get_active_player() ); destroy_win(this); } } return true; } simutrans-124.3/src/simutrans/gui/station_building_select.h000066400000000000000000000013311474050137200242170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_STATION_BUILDING_SELECT_H #define GUI_STATION_BUILDING_SELECT_H #include "components/action_listener.h" #include "gui_frame.h" #include "components/gui_button.h" class building_desc_t; class tool_build_station_t; /* * Building facing selector, when CTRL+Clicking over a building icon in menu */ class station_building_select_t : public gui_frame_t, action_listener_t { const building_desc_t *desc; button_t actionbutton[4]; static tool_build_station_t tool; public: station_building_select_t(const building_desc_t *desc); bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/themeselector.cc000066400000000000000000000062671474050137200223400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "themeselector.h" #include "simwin.h" #include "../sys/simsys.h" #include "../simevent.h" #include "gui_theme.h" #include "../utils/simstring.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/tabfile.h" std::string themeselector_t::undo = ""; themeselector_t::themeselector_t() : savegame_frame_t( ".tab", false, NULL, false ) { // remove unnecessary buttons top_frame.remove_component( &input ); delete_enabled = false; label_enabled = false; set_name( translator::translate( "Theme selector" ) ); fnlabel.set_text_pointer( translator::translate( "Select a theme for display" ) ); if( undo.empty() ) { undo = env_t::default_theme; set_windowsize(get_min_windowsize()); } } bool themeselector_t::check_file(const char *filename, const char *suffix) { return savegame_frame_t::check_file(filename,suffix); } // A theme button was pressed bool themeselector_t::item_action(const char *fullpath) { gui_theme_t::themes_init(fullpath,true,true); event_t *ev = new event_t(); ev->ev_class = EVENT_SYSTEM; ev->ev_code = SYSTEM_RELOAD_WINDOWS; queue_event( ev ); return false; } // Ok button was pressed bool themeselector_t::ok_action(const char *) { undo = ""; return true; } // Cancel button was pressed bool themeselector_t::cancel_action(const char *) { item_action(undo.c_str()); undo = ""; return true; } // returns the additional name of the file const char *themeselector_t::get_info(const char *fn ) { const char *info = ""; tabfile_t themesconf; if( themesconf.open(fn) ) { tabfileobj_t contents; // get trimmed theme name themesconf.read(contents); std::string name( contents.get( "name" ) ); info = strdup( trim( name ).c_str() ); } themesconf.close(); return info; } void themeselector_t::fill_list() { add_path( ((std::string)env_t::base_dir+"themes/").c_str() ); if( strncmp(env_t::user_dir, env_t::base_dir, PATH_MAX) != 0 ) { // not signle user add_path( ((std::string)env_t::user_dir+"themes/").c_str() ); } // do the search ... savegame_frame_t::fill_list(); for(dir_entry_t const& i : entries) { if (i.type == LI_HEADER) { continue; } delete[] i.button->get_text(); // free up default allocation. i.button->set_typ(button_t::roundbox_state | button_t::flexible); i.button->set_text(i.label->get_text_pointer()); i.button->pressed = !strcmp( env_t::default_theme.c_str(), i.info ); // mark current theme i.label->set_text_pointer( NULL ); // remove reference to prevent conflicts at delete[] // Get a new label buffer since the original is now owned by i.button. // i.label->set_text_pointer( strdup( get_filename(i.info).c_str() ) ); } if(entries.get_count() <= this->num_sections+1) { // less than two themes exist => we coudl close now ... } // force new resize after we have rearranged the gui resize(scr_coord(0,0)); } void themeselector_t::rdwr( loadsave_t *file ) { scr_size size = get_windowsize(); size.rdwr( file ); if( file->is_loading() ) { set_windowsize( size ); resize( scr_coord(0,0) ); } } simutrans-124.3/src/simutrans/gui/themeselector.h000066400000000000000000000020411474050137200221640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_THEMESELECTOR_H #define GUI_THEMESELECTOR_H #include "simwin.h" #include "savegame_frame.h" #include "components/gui_textarea.h" #include "../utils/cbuffer.h" /* * selection of paks at the start time */ class themeselector_t : public savegame_frame_t { protected: static std::string undo; // undo buffer bool item_action ( const char *fullpath ) OVERRIDE; bool ok_action ( const char *fullpath ) OVERRIDE; bool cancel_action ( const char *fullpath ) OVERRIDE; const char* get_info ( const char *fname ) OVERRIDE; bool check_file ( const char *filename, const char *suffix ) OVERRIDE; void fill_list ( void ) OVERRIDE; public: themeselector_t ( void ); const char* get_help_filename ( void ) const OVERRIDE { return NULL; } uint32 get_rdwr_id ( void ) OVERRIDE { return magic_themes; } void rdwr ( loadsave_t *file ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/tool_selector.cc000066400000000000000000000370311474050137200223430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../dataobj/environment.h" #include "../display/simimg.h" #include "../display/simgraph.h" #include "../player/simplay.h" #include "../utils/simstring.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "gui_frame.h" #include "simwin.h" #include "tool_selector.h" #define MIN_WIDTH (80) tool_selector_t::tool_selector_t(const char* title, const char *help_file, uint32 toolbar_id, bool allow_break) : gui_frame_t( translator::translate(title) ), tools(0) { set_table_layout(0,0); // we do our own positioning of icons (for now) this->toolbar_id = toolbar_id; this->allow_break = allow_break; this->help_file = help_file; this->tool_icon_disp_start = 0; this->tool_icon_disp_end = 0; this->title = title; has_prev_next = false; is_dragging = false; offset = scr_coord( 0, 0 ); set_windowsize( scr_size(max(env_t::iconsize.w,MIN_WIDTH), D_TITLEBAR_HEIGHT) ); dirty = true; } /** * Add a new tool with values and tooltip text. * tool_in must be created by new tool_t(copy_tool)! */ void tool_selector_t::add_tool_selector(tool_t *tool_in) { image_id tool_img = tool_in->get_icon(welt->get_active_player()); if( tool_img == IMG_EMPTY && tool_in!=tool_t::dummy ) { return; } // only for non-empty icons ... tools.append(tool_in); scr_rect screen = win_get_max_window_area(); int ww = max(3,(screen.w/env_t::iconsize.w)-2); // to avoid zero or negative ww on posix (no graphic) backends tool_icon_width = tools.get_count(); DBG_DEBUG4("tool_selector_t::add_tool()","ww=%i, tool_icon_width=%i",ww,tool_icon_width); if( allow_break && (ww0 && env_t::toolbar_max_width 0) { ww = min(ww, env_t::toolbar_max_width); } else if (env_t::toolbar_max_width < 0) { ww = min(3, ww - env_t::toolbar_max_width); } int rows = (tool_icon_width/ww)+((tool_icon_width % ww)>0); uint16 max_tool_icon_height = max(1, (screen.h - win_get_statusbar_height()) / env_t::iconsize.h); tool_icon_width = min(ww, tool_icon_width); tool_icon_height = min(rows, max_tool_icon_height); } else { tool_icon_height = 1; } if( env_t::toolbar_max_height > 0 ) { tool_icon_height = min(tool_icon_height, env_t::toolbar_max_height); } dirty = true; set_windowsize( scr_size( tool_icon_width*env_t::iconsize.w, tool_icon_height*env_t::iconsize.h+D_TITLEBAR_HEIGHT ) ); tool_icon_disp_start = 0; tool_icon_disp_end = min( tool_icon_disp_start+tool_icon_width*tool_icon_height, tools.get_count() ); has_prev_next = ((uint32)tool_icon_width*tool_icon_height < tools.get_count()); DBG_DEBUG4("tool_selector_t::add_tool()", "at position %i (width %i)", tools.get_count(), tool_icon_width); } // reset the tools to empty state void tool_selector_t::reset_tools() { tools.clear(); gui_frame_t::set_windowsize( scr_size(max(env_t::iconsize.w,MIN_WIDTH), D_TITLEBAR_HEIGHT) ); tool_icon_width = 0; tool_icon_disp_start = 0; tool_icon_disp_end = 0; offset = scr_coord( 0, 0 ); } bool tool_selector_t::is_hit(int x, int y) { int dx = (x-offset.x)/env_t::iconsize.w; int dy = (y-D_TITLEBAR_HEIGHT-offset.y)/env_t::iconsize.h; // either click in titlebar or on an icon if( x>=0 && y>=0 && ( (ymouse_pos.x - ev->click_pos.x, 0) : scr_coord(0, ev->mouse_pos.y - ev->click_pos.y)); int xy = tool_icon_width*tool_icon_height; if( tool_icon_height == 1 && tool_icon_disp_start + xy >= (int)tools.get_count() ) { // we have to take into account that the height is not a full icon tool_icon_disp_start = max(0, (int)tools.get_count() - xy); offset.x = -min(-offset.x, env_t::iconsize.w-(get_windowsize().w % env_t::iconsize.w)); } if( tool_icon_width == 1 && tool_icon_disp_start + xy >= (int)tools.get_count() ) { // we have to take into account that the height is not a full icon tool_icon_disp_start = max(0, (int)tools.get_count() - xy); offset.y = -min( -offset.y, (get_windowsize().h-D_TITLEBAR_HEIGHT) % env_t::iconsize.h); } if( tool_icon_disp_start == 0 && (offset.x > 0 || offset.y > 0) ) { offset.x = 0; offset.y = 0; } if (offset.x > 0) { // we must change the old offset, since the mouse starting point changed! old_offset.x -= env_t::iconsize.w; offset.x -= env_t::iconsize.w; tool_icon_disp_start--; } if (offset.x <= -env_t::iconsize.w) { old_offset.x += env_t::iconsize.w; offset.x += env_t::iconsize.w; tool_icon_disp_start++; } if (offset.y > 0) { // we must change the old offset, since the mouse starting point changed! old_offset.y -= env_t::iconsize.h; offset.y -= env_t::iconsize.h; tool_icon_disp_start--; } if (offset.y <= -env_t::iconsize.h) { old_offset.y += env_t::iconsize.h; offset.y += env_t::iconsize.h; tool_icon_disp_start++; } if( !IS_LEFTRELEASE(ev) && ev->button_state != 1 ) { is_dragging = false; } } // offsets sanity check while (offset.x < -env_t::iconsize.w) { offset.x += env_t::iconsize.w; } while (offset.x > 0) { offset.x -= env_t::iconsize.w; } while (offset.y < -env_t::iconsize.h) { offset.y += env_t::iconsize.h; } while (offset.y > 0) { offset.y -= env_t::iconsize.h; } if( tool_icon_disp_start > tool_icon_disp_end ) { tool_icon_disp_start = 0; offset.x = 0; offset.y = 0; } int xy = tool_icon_width*tool_icon_height; tool_icon_disp_end = (tool_icon_height == 1) ? min(tool_icon_disp_start+xy+(offset.x!=0), tools.get_count()) : min(tool_icon_disp_start + xy + (offset.y != 0), tools.get_count()); if(IS_LEFTRELEASE(ev) || IS_RIGHTRELEASE(ev)) { if( is_dragging ) { is_dragging = false; if( abs(old_offset.x - offset.x) > 2 || abs(old_offset.y - offset.y) > 2 || ev->click_pos.x-ev->mouse_pos.x != offset.x || ev->click_pos.x - ev->mouse_pos.y != offset.y ) { // we did dragg sucesfully before, so no tool selection! return true; } } // No dragging => Next check tooltips const int x = (ev->mouse_pos.x-offset.x) / env_t::iconsize.w; const int y = (ev->mouse_pos.y-offset.y-D_TITLEBAR_HEIGHT) / env_t::iconsize.h; const int wz_idx = x+(tool_icon_width*y)+tool_icon_disp_start; if( wz_idx>=0 && wz_idx < (int)tools.get_count() ) { // change tool tool_t *tool = tools[wz_idx].tool; if(IS_LEFTRELEASE(ev)) { if( env_t::reselect_closes_tool && tool && tool->is_selected() ) { // ->exit triggers tool_selector_t::infowin_event in the closing toolbar, // which resets active tool to query tool if( tool->exit( welt->get_active_player() ) ) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], welt->get_active_player() ); } } else { welt->set_tool( tool, welt->get_active_player() ); } } else { // right-click on toolbar icon closes toolbars and dialogues. Resets selectable simple and general tools to the query-tool if( tool && tool->is_selected() ) { // ->exit triggers tool_selector_t::infowin_event in the closing toolbar, // which resets active tool to query tool if( tool->exit(welt->get_active_player()) ) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], welt->get_active_player() ); } } } return true; } } // this resets to query-tool, when closing toolsbar - but only for selected general tools in the closing toolbar else if(ev->ev_class==INFOWIN && ev->ev_code==WIN_CLOSE) { for(tool_data_t const i : tools) { if (i.tool->is_selected() && i.tool->get_id() & GENERAL_TOOL) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], welt->get_active_player() ); break; } } } // reset title, language may have changed else if(ev->ev_class==INFOWIN && (ev->ev_code==WIN_TOP || ev->ev_code==WIN_OPEN) ) { set_name( translator::translate(title) ); } if(IS_WINDOW_CHOOSE_NEXT(ev)) { int xy = tool_icon_width*tool_icon_height; if(ev->ev_code==NEXT_WINDOW) { assert( xy >= tool_icon_width ); tool_icon_disp_start += xy; if( tool_icon_disp_start + xy > (int)tools.get_count() ) { tool_icon_disp_start = tools.get_count() - xy -1; } offset = scr_coord( 0, 0 ); } else { if( tool_icon_disp_start > xy ) { tool_icon_disp_start -= xy; } else { tool_icon_disp_start = 0; } offset = scr_coord( 0, 0 ); } tool_icon_disp_end = min(tool_icon_disp_start+xy, tools.get_count()); dirty = true; } return false; } void tool_selector_t::draw(scr_coord pos, scr_size sz) { player_t *player = welt->get_active_player(); if( toolbar_id == 0 ) { // checks for main menu (since it can change during changing layout) if(env_t::menupos==MENU_TOP || env_t::menupos == MENU_BOTTOM) { offset.y = 0; allow_break = false; tool_icon_width = (display_get_width() + env_t::iconsize.w - 1) / env_t::iconsize.w; tool_icon_height = 1; // only single row for title bar set_windowsize(sz); // check for too large values (after changing width etc.) if ( display_get_width() >= (int)tools.get_count() * env_t::iconsize.w ) { tool_icon_disp_start = 0; offset.x = 0; } else { scr_coord_val wx = (tools.get_count() - tool_icon_disp_start + 1) * env_t::iconsize.w + offset.x; if (wx < display_get_width()) { tool_icon_disp_start = tool_icon_disp_end < tool_icon_height ? 0 : tool_icon_disp_end - tool_icon_width; offset.x = display_get_width() - (tools.get_count() - tool_icon_disp_start) * env_t::iconsize.w; } } has_prev_next = (int)tools.get_count() * env_t::iconsize.w > sz.w; } else { offset.x = 0; allow_break = false; tool_icon_width = 1; // only single column for title bar scr_rect screen = win_get_max_window_area(); tool_icon_height = max(1,(screen.h - win_get_statusbar_height() + env_t::iconsize.h-1) / env_t::iconsize.h); set_windowsize(scr_size(env_t::iconsize.w, display_get_height() - win_get_statusbar_height())); if ( display_get_height() >= (int)tools.get_count() * env_t::iconsize.h ) { tool_icon_disp_start = 0; offset.y = 0; } else { scr_coord_val hx = (tools.get_count() - tool_icon_disp_start + 1) * env_t::iconsize.h + offset.y; if (hx < display_get_height()) { tool_icon_disp_end = tools.get_count(); tool_icon_disp_start = tool_icon_disp_end < tool_icon_height ? 0 : tool_icon_disp_end - tool_icon_height; offset.y = display_get_height() - (tools.get_count() - tool_icon_disp_start) * env_t::iconsize.h; } } has_prev_next = (int)tools.get_count() * env_t::iconsize.h > sz.h; } } for( uint i = tool_icon_disp_start; i < tool_icon_disp_end; i++ ) { const image_id icon_img = tools[i].tool->get_icon(player); #if COLOUR_DEPTH != 0 const scr_coord_val additional_xoffset = ( (i-tool_icon_disp_start)%(tool_icon_width+(offset.x!=0)) )*env_t::iconsize.w; const scr_coord_val additional_yoffset = D_TITLEBAR_HEIGHT+( (i-tool_icon_disp_start)/(tool_icon_width+(offset.x!=0)) )*env_t::iconsize.h; #else const scr_coord_val additional_xoffset = 0; const scr_coord_val additional_yoffset = 0; #endif const scr_coord draw_pos = pos + offset + scr_coord(additional_xoffset, additional_yoffset); const char *param = tools[i].tool->get_default_param(); // we don't draw in main menu as it is already made in simwin.cc // no background if separator starts with "-b" and has an icon defined if( toolbar_id>0 && !(strstart((param==NULL)? "" : param, "-b")) ) { if( skinverwaltung_t::toolbar_background && skinverwaltung_t::toolbar_background->get_image_id(toolbar_id) != IMG_EMPTY ) { const image_id back_img = skinverwaltung_t::toolbar_background->get_image_id(toolbar_id); display_fit_img_to_width( back_img, env_t::iconsize.w ); display_color_img( back_img, draw_pos.x, draw_pos.y, welt->get_active_player_nr(), false, true ); } else { display_fillbox_wh_clip_rgb( draw_pos.x, draw_pos.y, env_t::iconsize.w, env_t::iconsize.h, color_idx_to_rgb(MN_GREY2), false ); } } // if there's no image we simply skip, button will be transparent showing toolbar background if( icon_img != IMG_EMPTY ) { bool tool_dirty = dirty || (tools[i].tool->is_selected() ^ tools[i].selected); display_fit_img_to_width( icon_img, env_t::iconsize.w ); display_color_img(icon_img, draw_pos.x, draw_pos.y, player->get_player_nr(), false, tool_dirty); tools[i].tool->draw_after( draw_pos, tool_dirty); if (!tools[i].tool->enabled) { // grey out disbaled entries display_img_blend(icon_img, draw_pos.x, draw_pos.y, TRANSPARENT75_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_WHITE), false, tool_dirty); } // store whether tool was selected tools[i].selected = tools[i].tool->is_selected(); } } if( is_dragging ) { mark_rect_dirty_wc(pos.x, pos.y+D_TITLEBAR_HEIGHT, pos.x+sz.w, pos.y+sz.h+D_TITLEBAR_HEIGHT ); } else if( dirty && (tool_icon_disp_end-tool_icon_disp_start < tool_icon_width*tool_icon_height) ) { // mark empty space empty mark_rect_dirty_wc(pos.x, pos.y, pos.x + tool_icon_width*env_t::iconsize.w, pos.y + tool_icon_height*env_t::iconsize.h); } if( offset.x != 0 && tool_icon_disp_start > 0 ) { display_color_img(gui_theme_t::arrow_button_left_img[0], pos.x, pos.y + D_TITLEBAR_HEIGHT, 0, false, false); } if( offset.y != 0 && tool_icon_disp_start > 0 ) { display_color_img(gui_theme_t::arrow_button_up_img[0], pos.x, pos.y + D_TITLEBAR_HEIGHT, 0, false, false); } if( tool_icon_height == 1 && (tool_icon_disp_start+tool_icon_width < tools.get_count() || (-offset.x) < env_t::iconsize.w*tool_icon_width-get_windowsize().w) ) { display_color_img( gui_theme_t::arrow_button_right_img[0], pos.x+sz.w-D_ARROW_UP_WIDTH, pos.y+D_TITLEBAR_HEIGHT, 0, false, false ); } if( tool_icon_width == 1 && (tool_icon_disp_start+tool_icon_height < tools.get_count() || (-offset.y) < env_t::iconsize.h*tool_icon_height-get_windowsize().h) ) { display_color_img(gui_theme_t::arrow_button_down_img[0], pos.x+sz.w-D_ARROW_DOWN_WIDTH, pos.y+D_TITLEBAR_HEIGHT+sz.h-D_ARROW_DOWN_HEIGHT, 0, false, false); } if( !is_dragging ) { // tooltips? const scr_coord mouse_pos = get_mouse_pos(); if( is_hit(mouse_pos.x-pos.x, mouse_pos.y-pos.y) && (mouse_pos.y-pos.y > D_TITLEBAR_HEIGHT)) { const scr_coord_val xdiff = (mouse_pos.x - pos.x - offset.x) / env_t::iconsize.w; const scr_coord_val ydiff = (mouse_pos.y - pos.y - D_TITLEBAR_HEIGHT - offset.y) / env_t::iconsize.h; if( xdiff>=0 && xdiff=0 ) { const int tipnr = xdiff+(tool_icon_width*ydiff)+tool_icon_disp_start; if( tipnr < (int)tool_icon_disp_end ) { const char* tipstr = tools[tipnr].tool->get_tooltip(welt->get_active_player()); win_set_tooltip(mouse_pos + TOOLTIP_MOUSE_OFFSET, tipstr, tools[tipnr].tool, this); } } } } dirty = false; //as we do not call gui_frame_t::draw, we reset dirty flag explicitly unset_dirty(); } bool tool_selector_t::empty(player_t *player) const { for(tool_data_t w : tools) { if (w.tool->get_icon(player) != IMG_EMPTY) { return false; } } return true; } simutrans-124.3/src/simutrans/gui/tool_selector.h000066400000000000000000000046121474050137200222040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_TOOL_SELECTOR_H #define GUI_TOOL_SELECTOR_H #include "gui_frame.h" #include "../tpl/vector_tpl.h" #include "simwin.h" #include "../dataobj/environment.h" class tool_t; /** * This class defines all toolbar dialogues, floating bar of tools, i.e. the part the user will see */ class tool_selector_t : public gui_frame_t { private: struct tool_data_t { tool_data_t(tool_t* t=NULL) : tool(t), selected(false) {} tool_t* tool; ///< pointer to associated tool bool selected; ///< store whether tool was active during last call to tool_selector_t::draw }; /// tool definitions vector_tpl tools; // get current toolbar number for saving uint32 toolbar_id; /** * window width in toolboxes */ uint16 tool_icon_width; uint16 tool_icon_height; scr_coord offset, old_offset; uint16 tool_icon_disp_start; uint16 tool_icon_disp_end; bool has_prev_next, is_dragging; /** * Window title */ const char *title; /** * Name of the help file */ const char *help_file; // needs dirty redraw (only when changed) bool dirty; bool allow_break; public: tool_selector_t(const char *title, const char *help_file, uint32 toolbar_id, bool allow_break=true ); /** * Add a new tool with values and tooltip text. */ void add_tool_selector(tool_t *tool_in); // purges toolbar void reset_tools(); // untranslated title const char *get_internal_name() const {return title;} bool has_title() const OVERRIDE { return toolbar_id!=0; } const char *get_help_filename() const OVERRIDE {return help_file;} FLAGGED_PIXVAL get_titlecolor() const OVERRIDE { return env_t::default_window_title_color; } bool is_hit(int x, int y) OVERRIDE; /** * Does this window need a next button in the title bar? * @return true if such a button is needed */ bool has_next() const OVERRIDE {return has_prev_next;} bool infowin_event(event_t const*) OVERRIDE; /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; // since no information are needed to be saved to restore this, returning magic is enough uint32 get_rdwr_id() OVERRIDE { return magic_toolbar+toolbar_id; } bool empty(player_t *player) const; }; #endif simutrans-124.3/src/simutrans/gui/trafficlight_info.cc000066400000000000000000000044421474050137200231470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "trafficlight_info.h" #include "components/gui_label.h" #include "../obj/roadsign.h" // The rest of the dialog #include "../tool/simmenu.h" #include "../world/simworld.h" void trafficlight_info_t::update_data() { ns.set_value( roadsign->get_ticks_ns() ); ow.set_value( roadsign->get_ticks_ow() ); offset.set_value( roadsign->get_ticks_offset() ); yellow_ns.set_value( roadsign->get_ticks_yellow_ns() ); yellow_ow.set_value( roadsign->get_ticks_yellow_ow() ); } trafficlight_info_t::trafficlight_info_t(roadsign_t* s) : obj_infowin_t(s), roadsign(s) { add_table(3,1); { ns.set_limits( 1, 255 ); ns.wrap_mode( false ); ns.add_listener( this ); add_component( &ns ); ow.set_limits( 1, 255 ); ow.wrap_mode( false ); ow.add_listener( this ); add_component( &ow ); offset.set_limits( 0, 255 ); offset.wrap_mode( false ); offset.add_listener( this ); add_component( &offset ); } end_table(); add_table(2,1); { yellow_ns.set_limits( 1, 255 ); yellow_ns.wrap_mode( false ); yellow_ns.add_listener( this ); add_component( &yellow_ns ); yellow_ow.set_limits( 1, 255 ); yellow_ow.wrap_mode( false ); yellow_ow.add_listener( this ); add_component( &yellow_ow ); } end_table(); update_data(); // show author below the settings if (char const* const maker = roadsign->get_desc()->get_copyright()) { gui_label_buf_t* lb = new_component(); lb->buf().printf(translator::translate("Constructed by %s"), maker); lb->update(); } recalc_size(); } bool trafficlight_info_t::action_triggered( gui_action_creator_t *comp, value_t v) { char param[256]; int toolnr = 0; if(comp == &ns) { toolnr = 1; } else if(comp == &ow) { toolnr = 0; } else if(comp == &offset) { toolnr = 2; } else if(comp == &yellow_ns) { toolnr = 4; } else if(comp == &yellow_ow) { toolnr = 3; } else { dbg->fatal( "trafficlight_info_t","Wrong action triggered" ); } sprintf( param, "%s,%d,%i", roadsign->get_pos().get_str(), toolnr, (int)v.i ); tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT]->set_default_param( param ); welt->set_tool( tool_t::simple_tool[TOOL_CHANGE_TRAFFIC_LIGHT], welt->get_active_player() ); return true; } simutrans-124.3/src/simutrans/gui/trafficlight_info.h000066400000000000000000000016001474050137200230020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_TRAFFICLIGHT_INFO_H #define GUI_TRAFFICLIGHT_INFO_H #include "obj_info.h" #include "components/action_listener.h" #include "components/gui_numberinput.h" #include "components/gui_container.h" class roadsign_t; /** * Traffic light phase buttons */ class trafficlight_info_t : public obj_infowin_t, public action_listener_t { private: roadsign_t* roadsign; gui_numberinput_t ns, ow, offset, yellow_ns, yellow_ow; public: trafficlight_info_t(roadsign_t* s); /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char *get_help_filename() const OVERRIDE {return "trafficlight_info.txt";} bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; // called, after external change void update_data(); }; #endif simutrans-124.3/src/simutrans/gui/vehiclelist_frame.cc000066400000000000000000000265631474050137200231630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "gui_theme.h" #include "vehiclelist_frame.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../simskin.h" #include "../simintr.h" #include "../world/simworld.h" #include "../display/simgraph.h" #include "../dataobj/translator.h" #include "../descriptor/goods_desc.h" #include "../descriptor/intro_dates.h" #include "../descriptor/skin_desc.h" #include "../descriptor/vehicle_desc.h" #include "../utils/simstring.h" #include "../utils/unicode.h" int vehiclelist_stats_t::sort_mode = vehicle_builder_t::sb_intro_date; bool vehiclelist_stats_t::reverse = false; // for having uniform spaced columns int vehiclelist_stats_t::img_width = 100; vehiclelist_stats_t::vehiclelist_stats_t(const vehicle_desc_t *v) : details(&details_buf,0) { veh = v; // width of image scr_coord_val x, y, w, h; const image_id image = veh->get_image_id( ribi_t::dir_south, veh->get_freight_type() ); display_get_base_image_offset(image, &x, &y, &w, &h ); if( w > img_width ) { img_width = w + D_H_SPACE; } height = h; // name is the widest entry in column 1 name_width = proportional_string_width( translator::translate( veh->get_name(), world()->get_settings().get_name_language_id() ) ); if( veh->get_power() > 0 ) { char str[ 256 ]; sprintf( str, " (%s)", translator::translate( vehicle_builder_t::engine_type_names[ veh->get_engine_type() + 1 ] ) ); name_width += proportional_string_width( str ); } scr_coord_val name_h = LINESPACE; // column 1 part1.clear(); if( sint64 fix_cost = world()->scale_with_month_length( veh->get_maintenance() ) ) { char tmp[ 128 ]; money_to_string( tmp, veh->get_price() / 100.0, false ); part1.printf( translator::translate( "Cost: %8s (%.2f$/km %.2f$/m)\n" ), tmp, veh->get_running_cost() / 100.0, fix_cost / 100.0 ); } else { char tmp[ 128 ]; money_to_string( tmp, veh->get_price() / 100.0, false ); part1.printf( translator::translate( "Cost: %8s (%.2f$/km)\n" ), tmp, veh->get_running_cost() / 100.0 ); } if( veh->get_capacity() > 0 ) { // must translate as "Capacity: %3d%s %s\n" part1.printf( translator::translate( "Capacity: %d%s %s\n" ), veh->get_capacity(), translator::translate( veh->get_freight_type()->get_mass() ), veh->get_freight_type()->get_catg() == 0 ? translator::translate( veh->get_freight_type()->get_name() ) : translator::translate( veh->get_freight_type()->get_catg_name() ) ); part1.printf("%s%s\n", translator::translate("Loading time:"), difftick_to_string(veh->get_loading_time(), false)); } part1.printf( "%s %3d km/h\n", translator::translate( "Max. speed:" ), veh->get_topspeed() ); if( veh->get_power() > 0 ) { if( veh->get_gear() != 64 ) { part1.printf( "%s %4d kW (x%0.2f)\n", translator::translate( "Power:" ), veh->get_power(), veh->get_gear() / 64.0 ); } else { part1.printf( translator::translate( "Power: %4d kW\n" ), veh->get_power() ); } } int text1w, text1h; display_calc_proportional_multiline_string_len_width( text1w, text1h, part1); col1_width = text1w + D_H_SPACE; // column 2 part2.clear(); part2.printf( "%s %4.1ft\n", translator::translate( "Weight:" ), veh->get_weight() / 1000.0 ); part2.printf( "%s: %s - ", translator::translate( "Available" ), translator::get_short_date( veh->get_intro_year_month() / 12, veh->get_intro_year_month() % 12 ) ); if( veh->get_retire_year_month() != DEFAULT_RETIRE_DATE * 12 ) { part2.printf( "%s", translator::get_short_date( veh->get_retire_year_month() / 12, veh->get_retire_year_month() % 12 ) ); } if( char const* const copyright = veh->get_copyright() ) { part2.append( "\n" ); part2.printf( translator::translate( "Constructed by %s" ), copyright ); } int text2w, text2h; display_calc_proportional_multiline_string_len_width( text2w, text2h, part2); col2_width = text2w; // we need to find out manually, if we have extra text to show if (strlen(veh->get_name()) < 238) { char ei[256]; sprintf(ei, "obj_%s_details", veh->get_name()); const char* translated_ei = translator::translate(ei); if (ei != translated_ei) { details_buf.append(translated_ei); details.set_width(col1_width + col2_width); name_h += details.get_size().h; } } height = max( height, max( text1h, text2h ) + name_h )+D_V_SPACE; } void vehiclelist_stats_t::draw( scr_coord offset ) { uint32 month = world()->get_current_month(); offset += pos; offset.x += D_MARGIN_LEFT; offset.y += D_V_SPACE/2; scr_coord_val x, y, w, h; const image_id image = veh->get_image_id( ribi_t::dir_south, veh->get_freight_type() ); display_get_base_image_offset(image, &x, &y, &w, &h ); display_base_img(image, offset.x - x, offset.y - y, world()->get_active_player_nr(), false, true); // first name offset.x += img_width; int dx = display_proportional_rgb( offset.x, offset.y, translator::translate( veh->get_name(), world()->get_settings().get_name_language_id() ), ALIGN_LEFT|DT_CLIP, veh->is_future(month) ? SYSCOL_TEXT_HIGHLIGHT : (veh->is_available(month) ? SYSCOL_TEXT : gui_theme_t::gui_color_obsolete), false ); if( veh->get_power() > 0 ) { char str[ 256 ]; sprintf( str, " (%s)", translator::translate( vehicle_builder_t::engine_type_names[ veh->get_engine_type() + 1 ] ) ); display_proportional_rgb( offset.x+dx, offset.y, str, ALIGN_LEFT|DT_CLIP, SYSCOL_TEXT, false ); } // maybe there are detailed text to the vehicle? int yyy = offset.y + LINESPACE; if (details_buf.len()>0) { details.draw(scr_coord(offset.x, yyy)); yyy += details.get_size().h; } // now the rest in two columns display_multiline_text_rgb( offset.x, yyy, part1, SYSCOL_TEXT ); display_multiline_text_rgb( offset.x + col1_width, yyy, part2, SYSCOL_TEXT ); } const char *vehiclelist_stats_t::get_text() const { return translator::translate( veh->get_name() ); } bool vehiclelist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb) { bool result = vehicle_builder_t::compare_vehicles( dynamic_cast(aa)->veh, dynamic_cast(bb)->veh, (vehicle_builder_t::sort_mode_t)vehiclelist_stats_t::sort_mode ); return vehiclelist_stats_t::reverse ? !result : result; } vehiclelist_frame_t::vehiclelist_frame_t() : gui_frame_t( translator::translate("vh_title") ), scrolly(gui_scrolled_list_t::windowskin, vehiclelist_stats_t::compare) { name_filter[0] = 0; scrolly.set_cmp( vehiclelist_stats_t::compare ); scrolly.set_checkered(true); set_table_layout(3,0); new_component("Filter:"); name_filter_input.set_text(name_filter, lengthof(name_filter)); name_filter_input.set_notify_all_changes_delay(0); add_component(&name_filter_input,2); name_filter_input.add_listener(this); // next rows bt_obsolete.init(button_t::square_state, "Show obsolete"); bt_obsolete.add_listener(this); add_component(&bt_obsolete); bt_future.init(button_t::square_state, "Show future"); bt_future.add_listener(this); bt_future.pressed = true; add_component(&bt_future); ware_filter.clear_elements(); ware_filter.new_component(translator::translate("All"), SYSCOL_TEXT); idx_to_ware.append(NULL); for (int i = 0; i < goods_manager_t::get_count(); i++) { const goods_desc_t* ware = goods_manager_t::get_info(i); if (ware == goods_manager_t::none) { continue; } if (ware->get_catg() == 0) { ware_filter.new_component(translator::translate(ware->get_name()), SYSCOL_TEXT); idx_to_ware.append(ware); } } // now add other good categories for (int i = 1; i < goods_manager_t::get_max_catg_index(); i++) { const goods_desc_t* ware = goods_manager_t::get_info_catg(i); if (ware->get_catg() != 0) { ware_filter.new_component(translator::translate(ware->get_catg_name()), SYSCOL_TEXT); idx_to_ware.append(ware); } } ware_filter.set_selection(0); ware_filter.add_listener(this); add_component(&ware_filter); // second row new_component( "hl_txt_sort" ); sort_by.clear_elements(); for( int i = 0; i < vehicle_builder_t::sb_length; i++ ) { sort_by.new_component(translator::translate(vehicle_builder_t::vehicle_sort_by[i]), SYSCOL_TEXT); } sort_by.set_selection( vehiclelist_stats_t::sort_mode ); sort_by.add_listener( this ); add_component( &sort_by ); sorteddir.init( button_t::sortarrow_state, NULL ); sorteddir.pressed = vehiclelist_stats_t::reverse; sorteddir.add_listener( this ); add_component( &sorteddir ); tabs.init_tabs(&scrolly); tabs.add_listener(this); add_component(&tabs,3); fill_list(); set_resizemode(diagonal_resize); scrolly.set_maximize(true); reset_min_windowsize(); } /** * This method is called if an action is triggered */ bool vehiclelist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v) { if(comp == &sort_by) { vehiclelist_stats_t::sort_mode = max(0,v.i); fill_list(); } else if(comp == &ware_filter) { fill_list(); } else if(comp == &sorteddir) { vehiclelist_stats_t::reverse = !vehiclelist_stats_t::reverse; sorteddir.set_text( vehiclelist_stats_t::reverse ? "hl_btn_sort_desc" : "hl_btn_sort_asc"); scrolly.sort(0); sorteddir.pressed = vehiclelist_stats_t::reverse; } else if(comp == &bt_obsolete) { bt_obsolete.pressed ^= 1; fill_list(); } else if(comp == &bt_future) { bt_future.pressed ^= 1; fill_list(); } else if(comp == &tabs) { fill_list(); } else if(comp == &name_filter_input) { fill_list(); } return true; } void vehiclelist_frame_t::fill_list() { scrolly.clear_elements(); vehiclelist_stats_t::img_width = 32; // reset col1 width uint32 month = world()->get_current_month(); const goods_desc_t *ware = idx_to_ware[ max( 0, ware_filter.get_selection() ) ]; // adding all vehiles, i.e. iterate over all available waytypes for (uint32 i = 1; i < tabs.get_count(); i++) { if( tabs.get_active_tab_index()>0 && (sint32)i!=tabs.get_active_tab_index() ) { // wrong waytype continue; } for(vehicle_desc_t const* const veh : vehicle_builder_t::get_info(tabs.get_tab_waytype(i)) ) { if( bt_obsolete.pressed || !veh->is_retired( month ) ) { if( bt_future.pressed || !veh->is_future( month ) ) { if( name_filter[0]==0 || utf8caseutf8(translator::translate(veh->get_name()),name_filter) ) { if( ware ) { const goods_desc_t *vware = veh->get_freight_type(); if( (ware->get_catg_index() > 0 && vware->get_catg_index() == ware->get_catg_index()) || vware->get_index() == ware->get_index() ) { scrolly.new_component( veh ); } } else { scrolly.new_component( veh ); } } } } } } if( vehiclelist_stats_t::sort_mode != 0 ) { scrolly.sort(0); } else { scrolly.set_size( scrolly.get_size() ); } } void vehiclelist_frame_t::rdwr(loadsave_t* file) { scr_size size = get_windowsize(); size.rdwr(file); tabs.rdwr(file); scrolly.rdwr(file); ware_filter.rdwr(file); sort_by.rdwr(file); file->rdwr_bool(sorteddir.pressed); file->rdwr_bool(bt_obsolete.pressed); file->rdwr_bool(bt_future.pressed); if (file->is_version_atleast(123, 2)) { file->rdwr_str(name_filter, lengthof(name_filter)); } if (file->is_loading()) { vehiclelist_stats_t::reverse = sorteddir.pressed; vehiclelist_stats_t::sort_mode = sort_by.get_selection(); fill_list(); set_windowsize(size); } } simutrans-124.3/src/simutrans/gui/vehiclelist_frame.h000066400000000000000000000042261474050137200230150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_VEHICLELIST_FRAME_H #define GUI_VEHICLELIST_FRAME_H #include "simwin.h" #include "gui_frame.h" #include "components/gui_scrollpane.h" #include "components/gui_scrolled_list.h" #include "components/gui_label.h" #include "components/gui_image.h" #include "components/gui_waytype_tab_panel.h" #include "components/gui_combobox.h" #include "components/gui_textinput.h" #include "components/gui_fixedwidth_textarea.h" class vehicle_desc_t; class goods_desc_t; class vehiclelist_frame_t : public gui_frame_t, private action_listener_t { private: gui_textinput_t name_filter_input; button_t sorteddir, bt_obsolete, bt_future; gui_scrolled_list_t scrolly; gui_waytype_tab_panel_t tabs; gui_combobox_t sort_by, ware_filter; vector_tplidx_to_ware; char name_filter[256]; public: vehiclelist_frame_t(); void fill_list(); const char *get_help_filename() const OVERRIDE {return "vehiclelist.txt"; } bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; void rdwr(loadsave_t* file) OVERRIDE; uint32 get_rdwr_id() OVERRIDE { return magic_vehiclelist; } }; class vehiclelist_stats_t : public gui_scrolled_list_t::scrollitem_t { private: const vehicle_desc_t *veh; cbuffer_t part1, part2, details_buf; int name_width; int col1_width; int col2_width; int height; gui_fixedwidth_textarea_t details; public: static int sort_mode; static bool reverse; static int img_width; vehiclelist_stats_t(const vehicle_desc_t *); char const* get_text() const OVERRIDE; scr_size get_size() const OVERRIDE { return scr_size( D_MARGIN_LEFT+img_width+max(col1_width+col2_width,name_width)+D_MARGIN_RIGHT, height ); } scr_size get_min_size() const OVERRIDE { return scr_size( D_MARGIN_LEFT+img_width+max(col1_width+col2_width,name_width)+D_MARGIN_RIGHT, height ); } scr_size get_max_size() const OVERRIDE { return scr_size( D_MARGIN_LEFT+img_width+max(col1_width+col2_width,name_width)+D_MARGIN_RIGHT, height ); } static bool compare(const gui_component_t *a, const gui_component_t *b ); void draw( scr_coord offset ) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/gui/welt.cc000066400000000000000000000455471474050137200204540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "welt.h" #include "minimap.h" #include "../simdebug.h" #include "../world/simworld.h" #include "simwin.h" #include "../display/simimg.h" #include "../simmesg.h" #include "../simskin.h" #include "../simversion.h" #include "../builder/hausbauer.h" #include "../builder/wegbauer.h" #include "../descriptor/building_desc.h" #include "../dataobj/height_map_loader.h" #include "../dataobj/settings.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../dataobj/tabfile.h" // just for their structure size ... #include "../obj/way/schiene.h" #include "../obj/baum.h" #include "../world/simcity.h" #include "../vehicle/vehicle.h" #include "../player/simplay.h" #include "../simconvoi.h" #include "../simcolor.h" #include "../display/simgraph.h" #include "../sys/simsys.h" #include "../utils/simstring.h" #include "../utils/simrandom.h" #include "components/gui_divider.h" #include "banner.h" #include "sprachen.h" #include "climates.h" #include "settings_frame.h" #include "load_relief_frame.h" #include "messagebox.h" // Local adjustment #define L_PREVIEW_SIZE_MIN (16) welt_gui_t::welt_gui_t() : gui_frame_t( translator::translate("Neue Welt" ) ), map(0,0) { { // reread from simucon.tab(s) the settings and apply them tabfile_t simuconf; sets = new settings_t(); *sets = env_t::default_settings; dr_chdir(env_t::base_dir); if (simuconf.open("config/simuconf.tab")) { sets->parse_simuconf(simuconf); sets->parse_colours(simuconf); } stadt_t::cityrules_init(); dr_chdir(env_t::pak_dir.c_str()); if (simuconf.open("config/simuconf.tab")) { sets->parse_simuconf(simuconf); sets->parse_colours(simuconf); } dr_chdir(env_t::user_dir); if (simuconf.open("simuconf.tab")) { sets->parse_simuconf(simuconf); sets->parse_colours(simuconf); } simuconf.close(); } sets->beginner_mode = env_t::default_settings.get_beginner_mode(); city_density = ( sets->get_city_count() ) ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_city_count() : 0.0; industry_density = ( sets->get_factory_count() ) ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_factory_count() : 0.0; attraction_density = ( sets->get_tourist_attractions() ) ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_tourist_attractions() : 0.0; river_density = ( sets->get_river_number() ) ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_river_number() : 0.0; // find earliest start and end date ... uint16 game_start = 4999; uint16 game_ends = 0; // first check town halls for(building_desc_t const* const desc : *hausbauer_t::get_list(building_desc_t::townhall)) { uint16 intro_year = (desc->get_intro_year_month()+11)/12; if( intro_yearget_retire_year_month()+11)/12; if( retire_year>game_ends ) { game_ends = retire_year; } } // then streets game_start = max( game_start, (way_builder_t::get_earliest_way(road_wt)->get_intro_year_month()+11)/12 ); game_ends = min( game_ends, (way_builder_t::get_latest_way(road_wt)->get_retire_year_month()+11)/12 ); loaded_heightfield = load_heightfield = false; sets->heightfield = ""; //****************************************************************** // Component creation set_table_layout(1,0); // top part: preview, maps size add_table(3,1); { // input fields add_table(2,3); { new_component("2WORLD_CHOOSE"); inp_map_number.init( abs(sets->get_map_number()), 0, 0x7FFFFFFF, 1, true ); inp_map_number.add_listener( this ); add_component( &inp_map_number ); // Map size label size_label.init(); size_label.buf().printf(translator::translate("Size (%d MB):"), 99999); size_label.update(); size_label.set_min_width(size_label.get_min_size().w); // Make sure to not make the component size too small when the window is opened with a small map size that is increased afterwards add_component( &size_label ); // Map X size edit inp_x_size.init( sets->get_size_x(), 8, 32766, sets->get_size_x()>=512 ? 128 : 64, false ); inp_x_size.add_listener(this); add_component( &inp_x_size ); new_component(&size_label); // Map size Y edit inp_y_size.init( sets->get_size_y(), 8, 32766, sets->get_size_y()>=512 ? 128 : 64, false ); inp_y_size.add_listener(this); add_component( &inp_y_size ); } end_table(); new_component(); // Map preview (will be initialized in update_preview add_component( &map_preview ); } end_table(); // two buttons add_table(2,0)->set_force_equal_columns(true); { // Random map button random_map.init(button_t::roundbox | button_t::flexible, "Random map"); random_map.set_tooltip("chooses a random map"); random_map.add_listener( this ); add_component( &random_map ); // Load height map button load_map.init(button_t::roundbox | button_t::flexible, "Lade Relief"); load_map.set_tooltip("load height data from file"); load_map.add_listener( this ); add_component( &load_map ); } end_table(); // specify map parameters add_table(2,0); { // Number of towns new_component("5WORLD_CHOOSE"); inp_number_of_towns.add_listener(this); inp_number_of_towns.init(abs(sets->get_city_count()), 0, 999); add_component( &inp_number_of_towns ); // Town size new_component("Median Citizen per town"); inp_town_size.add_listener(this); inp_town_size.set_limits(0,999999); inp_town_size.set_increment_mode(50); inp_town_size.set_value( sets->get_mean_citizen_count() ); add_component( &inp_town_size ); // Intercity road length new_component("Intercity road len:"); inp_intercity_road_len.add_listener(this); inp_intercity_road_len.set_limits(0,9999); inp_intercity_road_len.set_value( env_t::intercity_road_length ); inp_intercity_road_len.set_increment_mode( env_t::intercity_road_length>=1000 ? 100 : 20 ); add_component( &inp_intercity_road_len ); // Factories new_component("No. of Factories"); inp_other_industries.add_listener(this); inp_other_industries.set_limits(0,999); inp_other_industries.set_value(abs(sets->get_factory_count()) ); add_component( &inp_other_industries ); // Tourist attr. new_component("Tourist attractions"); inp_tourist_attractions.add_listener(this); inp_tourist_attractions.set_limits(0,999); inp_tourist_attractions.set_value(abs(sets->get_tourist_attractions()) ); add_component( &inp_tourist_attractions ); // Use timeline checkbox use_intro_dates.init(button_t::square_state, "Use timeline start year"); use_intro_dates.pressed = sets->get_use_timeline()&1; use_intro_dates.add_listener( this ); add_component( &use_intro_dates ); // Timeline year edit inp_intro_date.add_listener(this); inp_intro_date.set_limits(game_start,game_ends); inp_intro_date.set_increment_mode(10); inp_intro_date.set_value(abs(sets->get_starting_year()) ); add_component( &inp_intro_date ); // Use beginner mode checkbox use_beginner_mode.init(button_t::square_state, "Use beginner mode"); use_beginner_mode.set_tooltip("Higher transport fees, crossconnect all factories"); use_beginner_mode.pressed = sets->get_beginner_mode(); use_beginner_mode.add_listener( this ); add_component( &use_beginner_mode ); } end_table(); new_component(); add_table(2,1)->set_force_equal_columns(true); { // Map settings button open_setting_gui.init(button_t::roundbox | button_t::flexible, "Setting"); open_setting_gui.pressed = win_get_magic( magic_settings_frame_t ); open_setting_gui.add_listener( this ); add_component( &open_setting_gui ); // Landscape settings button open_climate_gui.init(button_t::roundbox | button_t::flexible,"Climate Control"); open_climate_gui.pressed = win_get_magic( magic_climate ); open_climate_gui.add_listener( this ); add_component( &open_climate_gui ); } end_table(); new_component(); add_table(2,0)->set_force_equal_columns(true); { // start game start_game.init(button_t::roundbox | button_t::flexible, "Starte Spiel"); start_game.add_listener( this ); add_component( &start_game ); // return to menu return_menu.init(button_t::roundbox | button_t::flexible,"Return to menu"); return_menu.add_listener( this ); add_component( &return_menu ); } end_table(); update_preview(); update_memory(&size_label, sets); reset_min_windowsize(); set_windowsize(get_min_windowsize()); set_resizemode(gui_frame_t::diagonal_resize); } /** * Calculates preview from height map * @param filename name of heightfield file */ bool welt_gui_t::update_from_heightfield(const char *filename) { DBG_MESSAGE("welt_gui_t::update_from_heightfield()", "%s", filename); const sint8 min_h = env_t::default_settings.get_minimumheight(); const sint8 max_h = env_t::default_settings.get_maximumheight(); height_map_loader_t hml(min_h, max_h, env_t::height_conv_mode); sint16 w, h; sint8 *h_field=NULL; if(hml.get_height_data_from_file(filename, (sint8)sets->get_groundwater(), h_field, w, h, false )) { sets->set_size_x(w); sets->set_size_y(h); update_densities(); inp_x_size.set_value(sets->get_size_x()); inp_y_size.set_value(sets->get_size_y()); resize_preview(); const int mx = sets->get_size_x()/map_size.w; const int my = sets->get_size_y()/map_size.h; for( int y=0; yget_groundwater()-1 ); } } map_preview.set_map_data(&map); free(h_field); return true; } return false; } // sets the new values for the number input filed for the densities void welt_gui_t::update_densities() { if( city_density!=0.0 ) { inp_number_of_towns.set_value( max( 1, (sint32)(0.5+sqrt((double)sets->get_size_x()*sets->get_size_y())/city_density) ) ); sets->set_city_count( inp_number_of_towns.get_value() ); } if( industry_density!=0.0 ) { inp_other_industries.set_value( max( 1, (sint32)(0.5+sqrt((double)sets->get_size_x()*sets->get_size_y())/industry_density) ) ); sets->set_factory_count( inp_other_industries.get_value() ); } if( attraction_density!=0.0 ) { inp_tourist_attractions.set_value( max( 1, (sint32)(0.5+sqrt((double)sets->get_size_x()*sets->get_size_y())/attraction_density) ) ); sets->set_tourist_attractions( inp_tourist_attractions.get_value() ); } if( river_density!=0.0 ) { sets->river_number = max( 1, (sint32)(0.5+sqrt((double)sets->get_size_x()*sets->get_size_y())/river_density) ); if( climate_gui_t *climate_gui = (climate_gui_t *)win_get_magic( magic_climate ) ) { climate_gui->update_river_number( sets->get_river_number() ); } } } void welt_gui_t::update_memory(gui_label_buf_t *label, const settings_t* sets) { // Calculate map memory const uint sx = sets->get_size_x(); const uint sy = sets->get_size_y(); const uint64 memory = ( (uint64)sizeof(karte_t) + sizeof(player_t) * 8 + sizeof(convoi_t) * 1000 + (sizeof(schiene_t) + sizeof(vehicle_t)) * 10 * (sx + sy) + sizeof(stadt_t) * sets->get_city_count() + ( sizeof(grund_t) + sizeof(planquadrat_t) + sizeof(baum_t)*(sets->get_tree_distribution()!=settings_t::TREE_DIST_NONE) + /* only one since a lot will be water */ sizeof(void*)*2 ) * (uint64)sx * (uint64)sy ) / (1024ll * 1024ll); label->buf().printf(translator::translate("Size (%d MB):"), memory); label->update(); } /** * Calculate the new Map-Preview. Initialize the new RNG! */ void welt_gui_t::update_preview(bool load_heightfield) { if( loaded_heightfield || load_heightfield) { loaded_heightfield = true; update_from_heightfield(sets->heightfield.c_str()); } else { resize_preview(); setsimrand( 0xFFFFFFFF, sets->get_map_number() ); const int mx = sets->get_size_x()/map_size.w; const int my = sets->get_size_y()/map_size.h; for( int y=0; yget_groundwater()); } } sets->heightfield = ""; } map_preview.set_map_data(&map); } void welt_gui_t::resize_preview() { const float world_aspect = (float)sets->get_size_x() / (float)sets->get_size_y(); if( world_aspect > 1.0 ) { map_size.w = MAP_PREVIEW_SIZE_X-2; map_size.h = (sint16) max( (int)((float)map_size.w / world_aspect), L_PREVIEW_SIZE_MIN-2); } else { map_size.h = MAP_PREVIEW_SIZE_Y-2; map_size.w = (sint16) max( (int)((float)map_size.h * world_aspect), L_PREVIEW_SIZE_MIN-2); } map.resize( map_size.w, map_size.h ); } /** * This method is called if an action is triggered */ bool welt_gui_t::action_triggered( gui_action_creator_t *comp,value_t v) { if (!sets) { // new map has been already created => ignored late events return true; } // check for changed map (update preview for any event) int knr = inp_map_number.get_value(); // if(comp==&inp_map_number) { sets->heightfield = ""; loaded_heightfield = false; } else if(comp==&inp_x_size) { if( !loaded_heightfield ) { sets->set_size_x( v.i ); inp_x_size.set_increment_mode( v.i>=64 ? (v.i>=512 ? 128 : 64) : 8 ); inp_y_size.set_limits( 8, 32766 ); update_densities(); } else { inp_x_size.set_value(sets->get_size_x()); // can't change size with heightfield loaded } } else if(comp==&inp_y_size) { if( !loaded_heightfield ) { sets->set_size_y( v.i ); inp_y_size.set_increment_mode( v.i>=64 ? (v.i>=512 ? 128 : 64) : 8 ); inp_x_size.set_limits( 8, 32766 ); update_densities(); } else { inp_y_size.set_value(sets->get_size_y()); // can't change size with heightfield loaded } } else if(comp==&inp_number_of_towns) { sets->set_city_count( v.i ); city_density = sets->get_city_count() ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_city_count() : 0.0; } else if(comp==&inp_town_size) { sets->set_mean_citizen_count( v.i ); } else if(comp==&inp_intercity_road_len) { env_t::intercity_road_length = v.i; inp_intercity_road_len.set_increment_mode( v.i>=1000 ? 100 : 20 ); } else if(comp==&inp_other_industries) { sets->set_factory_count( v.i ); industry_density = sets->get_factory_count() ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_factory_count() : 0.0; } else if(comp==&inp_tourist_attractions) { sets->set_tourist_attractions( v.i ); attraction_density = sets->get_tourist_attractions() ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_tourist_attractions() : 0.0; } else if(comp==&inp_intro_date) { sets->set_starting_year( (sint16)(v.i) ); } else if(comp==&random_map) { knr = sim_async_rand(9999); inp_map_number.set_value(knr); sets->heightfield = ""; loaded_heightfield = false; } else if(comp==&load_map) { // load relief loaded_heightfield = false; sets->heightfield = ""; load_relief_frame_t* lrf = new load_relief_frame_t(sets); create_win(lrf, w_info, magic_load_t ); const scr_coord new_pos{ (display_get_width() - lrf->get_windowsize().w-10), env_t::iconsize.h }; win_set_pos(lrf, new_pos); knr = sets->get_map_number(); // otherwise using cancel would not show the normal generated map again } else if(comp==&use_intro_dates) { // 0,1 should force setting to new game as well. don't allow to change // 2,3 allow to change if(sets->get_use_timeline()&2) { // don't change bit1. bit1 affects loading saved game sets->set_use_timeline( sets->get_use_timeline()^1 ); use_intro_dates.pressed = sets->get_use_timeline()&1; } } else if(comp==&use_beginner_mode) { sets->beginner_mode = sets->get_beginner_mode()^1; use_beginner_mode.pressed = sets->get_beginner_mode(); } else if(comp==&open_setting_gui) { gui_frame_t *sg = win_get_magic( magic_settings_frame_t ); if( sg ) { destroy_win( sg ); open_setting_gui.pressed = false; } else { create_win({ 10, 40 }, new settings_frame_t(sets), w_info, magic_settings_frame_t ); open_setting_gui.pressed = true; } } else if(comp==&open_climate_gui) { gui_frame_t *climate_gui = win_get_magic( magic_climate ); if( climate_gui ) { destroy_win( climate_gui ); open_climate_gui.pressed = false; } else { climate_gui_t *cg = new climate_gui_t(sets); const scr_coord_val xoff = min(win_get_pos(this).x + this->size.w, display_get_width() - cg->get_windowsize().w ); const scr_coord_val yoff = win_get_pos(this).y; create_win({ xoff, yoff }, cg, w_info, magic_climate ); open_climate_gui.pressed = true; } } else if(comp==&start_game) { destroy_all_win(true); welt->get_message()->clear(); create_win({ 200, 100 }, new news_img("Erzeuge neue Karte.\n", skinverwaltung_t::neueweltsymbol->get_image_id(0)), w_info, magic_none); env_t::default_settings = *sets; delete sets; sets = NULL; if(loaded_heightfield) { welt->load_heightfield(&env_t::default_settings); } else { env_t::default_settings.heightfield = ""; welt->init( &env_t::default_settings, 0 ); } destroy_all_win(true); welt->step_month( env_t::default_settings.get_starting_month() ); welt->set_pause(false); // save setting ... loadsave_t file; if( file.wr_open("default.sve",loadsave_t::binary,0,"settings only",SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK ) { // save default setting env_t::default_settings.rdwr(&file); env_t::default_settings.reset_after_global_settings_reload(); file.close(); } welt->type_of_generation = karte_t::NEW_WORLD; } else if(comp==&return_menu) { destroy_all_win(true); banner_t::show_banner(); } if(knr>=0 && sets) { sets->map_number = knr; if(!loaded_heightfield) { update_preview(); } } return true; } void welt_gui_t::draw(scr_coord pos, scr_size size) { // Coordinates are relative to parent (TITLEHEIGHT **NOT** subtracted) cbuffer_t buf; // Update child controls before redraw if(!loaded_heightfield && sets->heightfield.size()!=0) { if(update_from_heightfield(sets->heightfield.c_str())) { loaded_heightfield = true; } else { loaded_heightfield = false; sets->heightfield = ""; } } // simulate toggle buttons open_setting_gui.pressed = win_get_magic( magic_settings_frame_t ); open_climate_gui.pressed = false; if( win_get_magic( magic_climate ) ) { open_climate_gui.pressed = true; // check if number was directly changed sint16 new_river_number = max( 1, (sint32)(0.5+sqrt((double)sets->get_size_x()*sets->get_size_y())/river_density) ); if( sets->get_river_number() != new_river_number ) { river_density = sets->get_river_number() ? sqrt((double)sets->get_size_x()*sets->get_size_y()) / sets->get_river_number() : 0.0; } } use_intro_dates.pressed = sets->get_use_timeline()&1; use_beginner_mode.pressed = sets->get_beginner_mode(); update_memory(&size_label, sets); // draw child controls gui_frame_t::draw(pos, size); } simutrans-124.3/src/simutrans/gui/welt.h000066400000000000000000000046631474050137200203100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef GUI_WELT_H #define GUI_WELT_H #include "gui_frame.h" #include "components/gui_button.h" #include "components/gui_label.h" #include "components/action_listener.h" #include "components/gui_textinput.h" #include "components/gui_numberinput.h" #include "components/gui_map_preview.h" #include "../tpl/array2d_tpl.h" class settings_t; /** * The dialog for new world generation */ class welt_gui_t : public gui_frame_t, private action_listener_t { settings_t *sets; /// Mini Map-Preview array2d_tpl map; scr_size map_size; bool load_heightfield; bool loaded_heightfield; double city_density; double industry_density; double attraction_density; double river_density; gui_map_preview_t map_preview; gui_numberinput_t inp_map_number, inp_x_size, inp_y_size; button_t random_map, load_map; gui_numberinput_t inp_number_of_towns, inp_town_size, inp_intercity_road_len, inp_other_industries, inp_tourist_attractions, inp_intro_date; gui_label_buf_t size_label; button_t use_intro_dates, use_beginner_mode, open_climate_gui, open_setting_gui, start_game, return_menu; /** * Calculates preview from height map * @param filename name of heightfield file */ bool update_from_heightfield(const char *filename); void resize_preview(); void update_densities(); public: welt_gui_t(); public: /** * Berechnet Preview-Karte neu. Inititialisiert RNG neu! * public, because also the climate dialog need it */ void update_preview(bool load_heightfield = false); void clear_loaded_heightfield() { loaded_heightfield =0; } bool get_loaded_heightfield() const { return loaded_heightfield; } /** * Set the window associated helptext * @return the filename for the helptext, or NULL */ const char * get_help_filename() const OVERRIDE {return "new_world.txt";} settings_t* get_sets() const { return sets; } // does not work during new world dialog bool has_sticky() const OVERRIDE { return false; } /** * Draw new component. The values to be passed refer to the window * i.e. It's the screen coordinates of the window where the * component is displayed. */ void draw(scr_coord pos, scr_size size) OVERRIDE; bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; static void update_memory(gui_label_buf_t *label, const settings_t* sets); }; #endif simutrans-124.3/src/simutrans/halthandle.h000066400000000000000000000004061474050137200206440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef HALTHANDLE_H #define HALTHANDLE_H #include "tpl/quickstone_tpl.h" class haltestelle_t; typedef quickstone_tpl halthandle_t; #endif simutrans-124.3/src/simutrans/io/000077500000000000000000000000001474050137200167765ustar00rootroot00000000000000simutrans-124.3/src/simutrans/io/classify_file.cc000066400000000000000000000173571474050137200221360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "classify_file.h" #include "rdwr/raw_file_rdwr_stream.h" #ifndef MAKEOBJ #include "rdwr/bzip2_file_rdwr_stream.h" #include "rdwr/zlib_file_rdwr_stream.h" #endif #ifdef USE_ZSTD #include "rdwr/zstd_file_rdwr_stream.h" #endif #include "../dataobj/loadsave.h" #include "../simdebug.h" #include "../simversion.h" #include "../sys/simsys.h" #include "../utils/simstring.h" #include "../macros.h" #include #ifdef MAKEOBJ #define dr_fopen fopen #endif bool classify_as_png(FILE *f, file_info_t *info); bool classify_as_bmp(FILE *f, file_info_t *info); bool classify_as_ppm(FILE *f, file_info_t *info); bool classify_as_zstd(FILE *f, file_info_t *info); bool classify_as_bzip2(FILE *f, file_info_t *info); bool classify_as_zip(FILE *f, file_info_t *info); bool classify_file_data(rdwr_stream_t *stream, file_info_t *info); file_info_t::file_info_t() : file_type(TYPE_RAW), version(INVALID_FILE_VERSION), header_size(0) { pak_extension[0] = 0; } file_info_t::file_info_t(file_type_t file_type, uint32 version) : file_type(file_type), version(version) { pak_extension[0] = 0; } file_classify_status_t classify_save_file(const char *path, file_info_t *info) { if (!info) { dbg->error("classify_file()", "Cannot classify file: info is NULL"); return FILE_CLASSIFY_INVALID_ARGS; } else if( !path || !*path ) { dbg->error("classify_file()", "Invalid path"); return FILE_CLASSIFY_INVALID_ARGS; } FILE *f = dr_fopen(path, "rb"); if (!f) { // Do not warn about this since we can also use this function to check whether a file exists return FILE_CLASSIFY_NOT_EXISTING; } #ifdef MAKEOBJ info->file_type = file_info_t::TYPE_RAW; info->version = INVALID_FILE_VERSION; info->header_size = 0; return FILE_CLASSIFY_OK; #else fseek(f, 0, SEEK_SET); if (classify_as_zstd(f, info)) { fclose(f); #if USE_ZSTD // otherwise we cannot read it zstd_file_rdwr_stream_t s(path, false, 0); if (!classify_file_data(&s, info)) { #else { #endif info->file_type = file_info_t::TYPE_ZSTD; info->version = INVALID_FILE_VERSION; info->header_size = 0; } return FILE_CLASSIFY_OK; } fseek(f, 0, SEEK_SET); if (classify_as_bzip2(f, info)) { fclose(f); bzip2_file_rdwr_stream_t s(path, false); if (!classify_file_data(&s, info)) { info->file_type = file_info_t::TYPE_RAW; info->version = INVALID_FILE_VERSION; info->header_size = 0; } return FILE_CLASSIFY_OK; } fseek(f, 0, SEEK_SET); if (classify_as_zip(f, info)) { fclose(f); zlib_file_rdwr_stream_t s(path, false, 0); if (!classify_file_data(&s, info)) { info->file_type = file_info_t::TYPE_RAW; info->version = INVALID_FILE_VERSION; info->header_size = 0; } return FILE_CLASSIFY_OK; } fseek(f, 0, SEEK_SET); raw_file_rdwr_stream_t s(f, false); if (!classify_file_data(&s, info)) { info->file_type = file_info_t::TYPE_RAW; info->version = INVALID_FILE_VERSION; info->header_size = 0; } return FILE_CLASSIFY_OK; #endif // MAKEOBJ } file_classify_status_t classify_image_file(const char *path, file_info_t *info) { if (!info) { dbg->error("classify_file()", "Cannot classify file: info is NULL"); return FILE_CLASSIFY_INVALID_ARGS; } else if( !path || !*path ) { dbg->error("classify_file()", "Invalid path"); return FILE_CLASSIFY_INVALID_ARGS; } FILE *f = dr_fopen(path, "rb"); if (!f) { // Do not warn about this since we can also use this function to check whether a file exists return FILE_CLASSIFY_NOT_EXISTING; } fseek(f, 0, SEEK_SET); if (classify_as_png(f, info)) { fclose(f); return FILE_CLASSIFY_OK; } fseek(f, 0, SEEK_SET); if (classify_as_bmp(f, info)) { fclose(f); return FILE_CLASSIFY_OK; } fseek(f, 0, SEEK_SET); if (classify_as_ppm(f, info)) { fclose(f); return FILE_CLASSIFY_OK; } info->file_type = file_info_t::TYPE_RAW; info->version = INVALID_FILE_VERSION; info->header_size = 0; return FILE_CLASSIFY_OK; } bool classify_as_png(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 8, f) != 8) { return false; } if (memcmp(buf, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) != 0) { return false; } info->file_type = file_info_t::TYPE_PNG; return true; } bool classify_as_bmp(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 2, f) != 2) { return false; } if (memcmp(buf, "BM", 2) != 0) { return false; } info->file_type = file_info_t::TYPE_BMP; return true; } bool classify_as_ppm(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 2, f) != 2) { return false; } if (memcmp(buf, "P6", 2) != 0) { return false; } info->file_type = file_info_t::TYPE_PPM; return true; } #ifndef MAKEOBJ bool classify_as_bzip2(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 2, f) != 2) { return false; } if( memcmp(buf, "BZ", 2) != 0) { return false; // not bzip2 compressed } info->file_type = file_info_t::TYPE_BZIP2; return true; } bool classify_as_zstd(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 2, f) != 2) { return false; } if( memcmp(buf, "ZD", 2) != 0) { return false; // not zstd compressed } info->file_type = file_info_t::TYPE_ZSTD; return true; } bool classify_as_zip(FILE *f, file_info_t *info) { char buf[80]; if (fread(buf, 1, 2, f) != 2) { return false; } if( memcmp(buf, "\x1f\x8b", 2) != 0 && buf[0] != 0x78 ) { return false; // not zlib/gzip compressed } info->file_type = file_info_t::TYPE_ZIPPED; return true; } bool classify_file_data(rdwr_stream_t *stream, file_info_t *info) { char buf[80]; MEMZERO(buf); if( stream->read( buf, sizeof( SAVEGAME_PREFIX ) ) != sizeof( SAVEGAME_PREFIX ) ) { info->version = INVALID_FILE_VERSION; return false; // file too short } info->header_size = sizeof(SAVEGAME_PREFIX); // get the rest of the string for( int i = sizeof( SAVEGAME_PREFIX ); i < 79; ) { char ch; stream->read(&ch, 1); info->header_size++; if( ch < ' ' ) { break; } buf[ i++ ] = (char)ch; buf[ i ] = 0; } if (strstart(buf, SAVEGAME_PREFIX)) { info->version = loadsave_t::int_version(buf + sizeof(SAVEGAME_PREFIX) - 1, info->pak_extension); if( info->version == 0 ) { info->version = INVALID_FILE_VERSION; return false; } } else if (strstart(buf, XML_SAVEGAME_PREFIX)) { info->file_type |= file_info_t::TYPE_XML; char ch; do { info->header_size++; stream->read(&ch, 1); } while (ch != '<'); stream->read(buf, sizeof(SAVEGAME_PREFIX) - 1); info->header_size += sizeof(SAVEGAME_PREFIX) -1; if (!strstart(buf, SAVEGAME_PREFIX)) { // not a simutrans XML file ... info->version = INVALID_FILE_VERSION; return false; } stream->read(buf, sizeof("version=\"") - 1); info->header_size += sizeof("version=\"") - 1; char str[256]; char *s = str; for (int i = 0; i < 255; i++) { char c; stream->read(&c, 1); info->header_size++; if (c=='\"') { break; } *s++ = c; } *s = 0; info->version = loadsave_t::int_version(str, info->pak_extension); if( info->version == 0 ) { info->version = INVALID_FILE_VERSION; info->header_size = 0; return false; } stream->read(buf, sizeof(" pak=\"") - 1); info->header_size += sizeof(" pak=\"") - 1; if (info->version > 0) { s = info->pak_extension; for (int i = 0; i < 63; i++) { char c; stream->read(&c, 1); info->header_size++; if (c=='\"') { break; } *s++ = c; } *s = 0; char c; do { info->header_size++; stream->read(&c, 1); } while (c != '>'); } } else { // not a Simutrans specific file info->version = INVALID_FILE_VERSION; info->header_size = 0; return false; } if(*info->pak_extension == 0) { strcpy( info->pak_extension, "(unknown)" ); } return true; } #endif simutrans-124.3/src/simutrans/io/classify_file.h000066400000000000000000000041521474050137200217650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_CLASSIFY_FILE_H #define IO_CLASSIFY_FILE_H #include "../simtypes.h" enum file_classify_status_t { FILE_CLASSIFY_OK = 0, FILE_CLASSIFY_INVALID_ARGS, FILE_CLASSIFY_NOT_EXISTING }; #define INVALID_FILE_VERSION 0xFFFFFFFFu /** * Holds information about file type, format and version. * Use @ref classify_save_file and @ref classify_image_file to classify * save files and image files, respectively. */ struct file_info_t { enum file_type_t { TYPE_RAW = 0, // either raw binary or text (dat etc) TYPE_ZIPPED, // zipped save TYPE_BZIP2, // bzip2 compressed save TYPE_ZSTD, // zstd compressed save TYPE_PNG, // PNG image TYPE_BMP, TYPE_PPM, TYPE_XML = 1u << 31, // Combined file formats TYPE_XML_ZIPPED = TYPE_XML | TYPE_ZIPPED, TYPE_XML_BZIP2 = TYPE_XML | TYPE_BZIP2, TYPE_XML_ZSTD = TYPE_XML | TYPE_ZSTD }; public: file_info_t(); explicit file_info_t(file_type_t file_type, uint32 version = INVALID_FILE_VERSION); public: file_type_t file_type; uint32 version; ///< Version of saved game. char pak_extension[64]; ///< Pak extension of saved game. size_t header_size; ///< Header size of saved game in bytes }; ENUM_BITSET(file_info_t::file_type_t); /** * Classify a save file. * @param path must a valid system name, either a short name for windows or UTF8 for other plattforms * @param info If successfully classified, holds information about file format and version. * Must not be NULL. * @returns FILE_CLASSIFY_OK iff successfully classified. */ file_classify_status_t classify_save_file(const char *path, file_info_t *info); /** * Classify an image file. * @param path must a valid system name, either a short name for windows or UTF8 for other plattforms * @param info If successfully classified, holds information about file format and version. * Must not be NULL. * @returns FILE_CLASSIFY_OK iff successfully classified. */ file_classify_status_t classify_image_file(const char *path, file_info_t *info); #endif simutrans-124.3/src/simutrans/io/raw_image.cc000066400000000000000000000037121474050137200212430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "raw_image.h" #include "classify_file.h" #include "../simmem.h" #include #include #include #include raw_image_t::raw_image_t() : data(NULL) , width(0) , height(0) , fmt(FMT_INVALID) , bpp(0) { } raw_image_t::raw_image_t(uint32 width, uint32 height, raw_image_t::format_t format) : data(NULL) , width(width) , height(height) , fmt(format) , bpp(bpp_for_format(format)) { data = MALLOCN(uint8, width * height * (bpp/CHAR_BIT)); } raw_image_t::raw_image_t(const raw_image_t& rhs) : data(NULL), width(rhs.width), height(rhs.height), fmt(rhs.fmt), bpp(rhs.bpp) { const size_t data_size = width * height * (bpp/CHAR_BIT); data = MALLOCN(uint8, data_size); memcpy(data, rhs.data, data_size); } raw_image_t::~raw_image_t() { if (data) { free(data); } } raw_image_t &raw_image_t::operator=(raw_image_t rhs) { swap(*this, rhs); return *this; } void raw_image_t::copy_from(const raw_image_t &rhs) { *this = rhs; } bool raw_image_t::read_from_file(const char *filename) { file_info_t finfo; const file_classify_status_t status = classify_image_file(filename, &finfo); if (status != FILE_CLASSIFY_OK) { return false; } switch (finfo.file_type) { case file_info_t::TYPE_PNG: return read_png(filename); case file_info_t::TYPE_BMP: return read_bmp(filename); case file_info_t::TYPE_PPM: return read_ppm(filename); default: return false; } } uint8 raw_image_t::bpp_for_format(raw_image_t::format_t format) { switch (format) { case FMT_INVALID: return 0; case FMT_GRAY8: return 8; case FMT_RGB888: return 24; case FMT_RGBA8888: return 32; default: assert(false); return 0; } } void swap(raw_image_t &lhs, raw_image_t &rhs) { using std::swap; swap(lhs.data, rhs.data); swap(lhs.width, rhs.width); swap(lhs.height, rhs.height); swap(lhs.fmt, rhs.fmt); swap(lhs.bpp, rhs.bpp); } simutrans-124.3/src/simutrans/io/raw_image.h000066400000000000000000000046251474050137200211110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RAW_IMAGE_H #define IO_RAW_IMAGE_H #include "../simtypes.h" #include #include /** * Class to store, read or write raw image data in various formats. * The data are stored without gaps, i.e. * @code * access_pixel(x, y+1) == access_pixel(x, y) + get_width() * (get_bpp()/CHAR_BIT) * @endcode * for 0 <= x < width and 0 <= y < height-1 */ class raw_image_t { public: enum format_t { FMT_INVALID = 0xFF, FMT_GRAY8 = 0, ///< 8 bpp grayscale FMT_RGBA8888, ///< 32 bpp RGBA; alpha == 0xFF is fully opaque FMT_RGB888 ///< 24 bpp RGB }; public: /// Constructs an empty invalid image. raw_image_t(); /// Allocates a writable image with the specified dimensions and format. raw_image_t(uint32 width, uint32 height, format_t format); ~raw_image_t(); friend void swap(raw_image_t &lhs, raw_image_t &rhs); private: /// Copy ctor; use copy_from for explicit copying raw_image_t(const raw_image_t &rhs); raw_image_t &operator=(raw_image_t rhs); public: format_t get_format() const { return (format_t)fmt; } uint8 get_bpp() const { return bpp; } uint32 get_width() const { return width; } uint32 get_height() const { return height; } /// Access the first byte of a pixel. The actual number of bytes per pixel and the order of color channels depends on the format. const uint8 *access_pixel(uint32 x, uint32 y) const { assert(fmt != FMT_INVALID); return data + (x + y*width) * (bpp/CHAR_BIT); } uint8 *access_pixel(uint32 x, uint32 y) { assert(fmt != FMT_INVALID); return data + (x + y*width) * (bpp/CHAR_BIT); } /// @returns the bits per pixel for @p format static uint8 bpp_for_format(format_t format); void copy_from(const raw_image_t &rhs); public: /// Read image from file. File format is detected automatically. /// @returns true on success bool read_from_file(const char *filename); /// @returns true on success bool write_png(const char *filename) const; bool write_bmp(const char *filename) const; bool write_ppm(const char *filename) const; private: bool read_bmp(const char *filename); bool read_ppm(const char *filename); bool read_png(const char *filename); bool read_png_data(FILE *file); private: uint8 *data; uint32 width; uint32 height; uint8 fmt; uint8 bpp; }; void swap(raw_image_t &lhs, raw_image_t &rhs); #endif simutrans-124.3/src/simutrans/io/raw_image_bmp.cc000066400000000000000000000301221474050137200220740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "raw_image.h" #include "../sys/simsys.h" #include "../simdebug.h" #include "../simmem.h" #include "../tpl/array_tpl.h" #include "rdwr/raw_file_rdwr_stream.h" #define BMPINFOHEADER_OFFSET (14) #ifdef MAKEOBJ #define dr_fopen fopen #endif #ifdef _MSC_VER #pragma pack(push, 1) #endif struct bitmap_file_header_t { uint8 magic[2]; uint32 file_size; uint16 reserved1; uint16 reserved2; uint32 image_data_offset; } GCC_PACKED; struct bitmap_info_header_t { uint32 header_size; sint32 width; sint32 height; uint16 num_color_planes; uint16 bpp; uint32 compression; uint32 image_size; uint32 horizontal_resolution; uint32 vertical_resolution; uint32 num_palette_colors; uint32 num_important_colors; } GCC_PACKED; #ifdef _MSC_VER #pragma pack(pop) #endif enum compression_method_t { BI_RGB = 0, BI_RLE8 = 1, BI_RLE4 = 2 }; static bool is_format_supported(uint16 bpp, uint32 compression) { if (compression == BI_RGB) { return bpp == 8 || bpp == 24; } else if (compression == BI_RLE8) { return bpp == 8; } else { return false; } } bool raw_image_t::read_bmp(const char *filename) { FILE *file = dr_fopen(filename, "rb"); bitmap_file_header_t bmp_header; if (fread(&bmp_header, sizeof(bitmap_file_header_t), 1, file) != 1) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } else if (bmp_header.magic[0] != 'B' || bmp_header.magic[1] != 'M') { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } const uint32 image_data_offset = endian(bmp_header.image_data_offset); bitmap_info_header_t bmpinfo_header; if (fseek(file, BMPINFOHEADER_OFFSET, SEEK_SET) != 0 || fread(&bmpinfo_header, sizeof(bitmap_info_header_t), 1, file) != 1) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } const uint32 bmpinfoheader_size = endian(bmpinfo_header.header_size); if (bmpinfo_header.header_size < sizeof(bitmap_info_header_t)) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } sint32 width = endian(bmpinfo_header.width); sint32 height = endian(bmpinfo_header.height); const uint16 bit_depth = endian(bmpinfo_header.bpp); const uint32 compression = endian(bmpinfo_header.compression); uint32 table = endian(bmpinfo_header.num_palette_colors); // We only allow the following image formats: // 8 bit: BI_RGB (uncompressed) // BI_RLE8 (8 bit RLE) // 24 bit: BI_RGB if( !is_format_supported(bit_depth, compression) ) { dbg->warning("raw_image_t::read_bmp", "Can only use 8 bit (RLE or normal) or 24 bit bitmaps!"); fclose(file); return false; } this->width = abs(width); this->height = abs(height); this->fmt = FMT_RGBA8888; this->bpp = 32; // now read the data and convert them on the fly data = REALLOC(data, uint8, abs(width) * abs(height) * (bpp / CHAR_BIT)); if (!data) { dbg->warning("raw_image_t::read_bmp", "Not enough memory"); fclose(file); return false; } if( bit_depth==8 ) { // convert color tables to height levels if( table==0 ) { table = 256; } const uint32 colortable_offset = BMPINFOHEADER_OFFSET + bmpinfoheader_size; if( fseek( file, colortable_offset, SEEK_SET ) != 0 ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } else if (table > 256) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } uint8 h_table[256 * 4]; for( uint32 i=0; iwarning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } h_table[4*i + 0] = R; h_table[4*i + 1] = G; h_table[4*i + 2] = B; h_table[4*i + 3] = 0xFF; } // now read the data if( fseek( file, image_data_offset, SEEK_SET ) != 0 ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } const bool mirror = (height<0); height = abs(height); width = abs(width); if( compression==0 ) { // uncompressed (usually mirrored, if h<0) const int padding = (4 - (width & 3)) & 3; // padding at end of line for( sint32 y=0; ywarning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } data[offset + x * (bpp/CHAR_BIT) + 0] = h_table[4*res + 0]; data[offset + x * (bpp/CHAR_BIT) + 1] = h_table[4*res + 1]; data[offset + x * (bpp/CHAR_BIT) + 2] = h_table[4*res + 2]; data[offset + x * (bpp/CHAR_BIT) + 3] = h_table[4*res + 3]; } if( padding != 0 ) { // ignore missing padding at end of file if (fseek(file, padding, SEEK_CUR)!=0 && y < height-1) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } } } } else { // compressed RLE (reverse y, since mirrored) sint32 x=0, y = mirror ? 0 : height-1; while( !feof(file) && (mirror ? (y < height) : (y >= 0))) { int res = fgetc(file); if( res == EOF ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } uint8 Count = res; res = fgetc(file); if( res == EOF ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } const uint8 ColorIndex = res; if( Count>0 ) { for( sint32 k=0; kwarning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } x += (uint8)xx; y = mirror ? y+(uint8)yy : y-(uint8)yy; } else { // uncompressed run Count = Flag; for( sint32 k=0; kwarning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } access_pixel(x, y)[0] = h_table[4 * (uint8)idx + 0]; access_pixel(x, y)[1] = h_table[4 * (uint8)idx + 1]; access_pixel(x, y)[2] = h_table[4 * (uint8)idx + 2]; access_pixel(x, y)[3] = h_table[4 * (uint8)idx + 3]; } // always even offset in file const long int pos = ftell(file); if( pos==-1L || (pos&1 && fseek(file, 1, SEEK_CUR)!=0) ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } } } } } } else { // uncompressed 24 bits const bool mirror = (height<0); height = abs(height); // Now read the data if( fseek( file, image_data_offset, SEEK_SET ) != 0 ) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } for( sint32 y=0; ywarning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } access_pixel(x, real_y)[0] = R; access_pixel(x, real_y)[1] = G; access_pixel(x, real_y)[2] = B; access_pixel(x, real_y)[3] = 0xFF; } // skip padding to 4 bytes at the end of each scanline const int padding = (4 - ((width*3) & 3)) & 3; if( padding != 0 && fseek( file, padding, SEEK_CUR ) != 0 ) { // Allow missing padding at end of file if (y != height-1) { dbg->warning("raw_image_t::read_bmp", "Malformed bmp file"); fclose(file); return false; } } } } fclose(file); return true; } bool raw_image_t::write_bmp(const char *filename) const { if (fmt == FMT_INVALID) { dbg->error("raw_image_t::write_bmp", "Invalid format"); return false; } else if (fmt == FMT_GRAY8) { dbg->error("raw_image_t::write_bmp", "Saving greyscale images is not implemented"); return false; } bitmap_file_header_t fheader; fheader.magic[0] = 'B'; fheader.magic[1] = 'M'; fheader.file_size = 0; // This is overwritten by the correct value below fheader.reserved1 = 0; fheader.reserved2 = 0; fheader.image_data_offset = 0; // This is overwritten by the correct value below bitmap_info_header_t iheader; iheader.header_size = sizeof(bitmap_info_header_t); iheader.width = endian(sint32(get_width())); iheader.height = endian(sint32(get_height())); iheader.num_color_planes = endian(uint16(1)); iheader.bpp = endian(uint16(bpp)); iheader.compression = endian(uint32(BI_RGB)); iheader.horizontal_resolution = 0; iheader.vertical_resolution = 0; iheader.num_palette_colors = 0; iheader.num_important_colors = 0; // size in bytes const uint32 pitch = ((get_width() * (bpp / CHAR_BIT)) + 3) & ~3; // align to 4 bytes const uint32 image_data_size = pitch * get_height(); const uint32 headers_size = uint32(sizeof(bitmap_file_header_t) + sizeof(bitmap_info_header_t)); const uint32 gap1_size = 2; // padding between headers_size and next multiple of 4 bytes fheader.image_data_offset = endian(uint32(headers_size + gap1_size)); fheader.file_size = endian(uint32(headers_size + gap1_size + image_data_size)); // now actually write the data FILE *f = dr_fopen(filename, "wb"); if (!f) { return false; } if (fwrite(&fheader, sizeof(bitmap_file_header_t), 1, f) != 1) { fclose(f); return false; } if (fwrite(&iheader, sizeof(bitmap_info_header_t), 1, f) != 1) { fclose(f); return false; } const uint8 zeroes[4] = { 0, 0, 0, 0 }; if (fwrite(zeroes, 1, gap1_size, f) != gap1_size) { fclose(f); return false; } // write row by row, add padding const uint32 row_size = get_width() * (bpp/CHAR_BIT); const uint32 padding = pitch - row_size; assert(padding < 4); array_tpl row_buffer(pitch); for (sint32 y = get_height()-1; y >= 0; --y) { const uint8 *row_start = access_pixel(0, y); const uint8 *row_end = row_start + row_size; array_tpl::iterator dst = row_buffer.begin(); switch (fmt) { case FMT_RGB888: { const uint8 *src = row_start; while (src < row_end) { const uint8 R = *src++; const uint8 G = *src++; const uint8 B = *src++; *dst++ = B; *dst++ = G; *dst++ = R; } for (uint32 i = 0; i < padding; ++i) { *dst++ = 0; } if (fwrite(row_buffer.begin(), 1, pitch, f) != pitch) { fclose(f); return false; } } continue; case FMT_RGBA8888: { const uint8 *src = row_start; while (src < row_end) { const uint8 R = *src++; const uint8 G = *src++; const uint8 B = *src++; const uint8 A = *src++; *dst++ = B; *dst++ = G; *dst++ = R; *dst++ = A; } assert(padding == 0); if (fwrite(row_buffer.begin(), 1, pitch, f) != pitch) { fclose(f); return false; } } continue; default: // we only write supported formats here assert(false); break; } } fclose(f); return true; } simutrans-124.3/src/simutrans/io/raw_image_png.cc000066400000000000000000000162101474050137200221040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "raw_image.h" #include #include #include #include #include #include // strerror #include "../simmem.h" #include "../simdebug.h" #ifdef MAKEOBJ #define dr_fopen fopen #else #include "../sys/simsys.h" #endif static std::string filename_; bool raw_image_t::read_png_data(FILE *file) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if (png_ptr == NULL) { dbg->error( "raw_image_t::read_png_data", "Could not create read struct"); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { dbg->error( "raw_image_t::read_png_data", "Could not create info struct"); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } #ifdef PNG_SETJMP_SUPPORTED if( setjmp(png_jmpbuf(png_ptr) )) { dbg->error( "raw_image_t::read_png_data", "Fatal error in %s.", filename_.c_str()); png_destroy_read_struct(&png_ptr, &info_ptr, (png_info**)0); return false; } #endif /* Set up the input control if you are using standard C streams */ png_init_io(png_ptr, file); /* The call to png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). REQUIRED */ png_read_info(png_ptr, info_ptr); //png_uint_32 is 64 bit on some architectures! png_uint_32 new_width; png_uint_32 new_height; int bit_depth; int color_type; if (!png_get_IHDR(png_ptr, info_ptr, &new_width, &new_height, &bit_depth, &color_type, 0, 0, 0)) { dbg->error("raw_image_t::read_png_data", "Failed to read IHDR from '%s'", filename_.c_str()); png_destroy_read_struct(&png_ptr, &info_ptr, (png_info**)0); return false; } /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* Expand paletted colors into true RGB triplets */ if( color_type == PNG_COLOR_TYPE_PALETTE ) { png_set_expand(png_ptr); // tRNS to alpha if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); } color_type = PNG_COLOR_TYPE_RGBA; } else if (color_type == PNG_COLOR_TYPE_RGB) { // add opaque alpha channel png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); color_type = PNG_COLOR_TYPE_RGBA; } else if (color_type == PNG_COLOR_TYPE_GA) { dbg->warning("raw_image_t::read_png_data", "Ignoring alpha channel for grayscale image '%s'", filename_.c_str()); png_set_strip_alpha(png_ptr); color_type = PNG_COLOR_TYPE_GRAY; } // update info - png_get_rowbytes might return incorrect values png_read_update_info( png_ptr, info_ptr); const size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_bytep *row_pointers = MALLOCN(png_bytep, new_height); row_pointers[0] = MALLOCN(png_byte, rowbytes * new_height); for (uint32 row = 1; row < new_height; row++) { row_pointers[row] = row_pointers[row - 1] + rowbytes; } /* Read the entire image in one go */ png_read_image(png_ptr, row_pointers); // we use fixed height here because block is of limited, fixed size // not fixed any more format_t new_fmt = FMT_INVALID; switch (color_type) { case PNG_COLOR_TYPE_RGBA: new_fmt = FMT_RGBA8888; break; case PNG_COLOR_TYPE_RGB: new_fmt = FMT_RGB888; break; case PNG_COLOR_TYPE_GRAY: new_fmt = FMT_GRAY8; break; } if (new_fmt == FMT_INVALID) { dbg->error("raw_image_t::read_png_data", "Unsupported PNG format"); png_destroy_read_struct(&png_ptr, &info_ptr, (png_info**)0); return false; } const uint8 new_bpp = raw_image_t::bpp_for_format(raw_image_t::format_t(new_fmt)); const size_t old_size = width * height * (bpp /CHAR_BIT); const size_t new_size = new_width * new_height * (new_bpp/CHAR_BIT); if (new_size == 0) { free(data); data = NULL; } else if (new_size > old_size) { data = REALLOC(data, uint8, new_size); } fmt = new_fmt; width = new_width; height = new_height; bpp = new_bpp; if (new_size > 0) { uint8 *dst = data; for (uint32 y = 0; y < height; y++) { for (uint32 x = 0; x < width * (bpp/CHAR_BIT); x++) { *dst++ = row_pointers[y][x]; } } } free(row_pointers[0]); free(row_pointers); /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); /* At this point you have read the entire image */ /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return true; } bool raw_image_t::read_png(const char *fname) { // remember the file name for better error messages. filename_ = fname; FILE* file = dr_fopen(fname, "rb"); if (file) { const bool ok = read_png_data(file); fclose(file); return ok; } else { dbg->warning( "raw_image_t::read_png", "Cannot open %s: %s", fname, strerror(errno) ); return false; } } bool raw_image_t::write_png(const char *file_name) const { // remember the file name for better error messages. filename_ = file_name; png_structp png_ptr = NULL; png_infop info_ptr = NULL; FILE *fp = dr_fopen(file_name, "wb"); if (!fp) { return false; } // init structures png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose( fp ); return false; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); fclose( fp ); return false; } #ifdef PNG_SETJMP_SUPPORTED if( setjmp( png_jmpbuf(png_ptr) ) ) { dbg->error( "raw_image_t::write_png", "fatal error"); png_destroy_write_struct(&png_ptr, &info_ptr); return false; } #endif // assign file png_init_io(png_ptr, fp); #if PNG_LIBPNG_VER_MAJOR<=1 && PNG_LIBPNG_VER_MINOR<5 /* set the zlib compression level */ png_set_compression_level( png_ptr, Z_BEST_COMPRESSION ); #endif // output header int color_type; switch (fmt) { case FMT_RGBA8888: color_type = PNG_COLOR_TYPE_RGBA; break; case FMT_RGB888: color_type = PNG_COLOR_TYPE_RGB; break; case FMT_GRAY8: color_type = PNG_COLOR_TYPE_GRAY; break; default: dbg->fatal( "raw_image_t::write_png", "Cannot write png file: Unupported source format" ); } png_set_IHDR( png_ptr, info_ptr, width, height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_write_info(png_ptr, info_ptr); switch (fmt) { case FMT_RGBA8888: case FMT_RGB888: case FMT_GRAY8: { for (uint32 y = 0; y < height; ++y) { // hack to compile with old libpng versions that take a png_bytep instead of a png_const_bytep const uint8 *row = access_pixel(0, y); png_write_row(png_ptr, const_cast(row)); } } break; default: dbg->error("raw_image_t::write_png", "Unsupported source format for writing png"); png_destroy_write_struct(&png_ptr, &info_ptr); fclose( fp ); return false; } // free all png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose( fp ); return true; } simutrans-124.3/src/simutrans/io/raw_image_ppm.cc000066400000000000000000000045501474050137200221200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "raw_image.h" #include "../simdebug.h" #include "../sys/simsys.h" #include "../simio.h" #include "../simmem.h" #ifdef MAKEOBJ #define dr_fopen fopen #else #include "../sys/simsys.h" #endif bool raw_image_t::read_ppm(const char *filename) { FILE *file = dr_fopen(filename, "rb"); // ppm format char buf[255]; const char *c = ""; sint32 param[3] = {0, 0, 0}; char id[2]; if (fread(id, sizeof(char), 2, file) != 2 || id[0]!='P' || id[1]!='6') { fclose(file); dbg->error("raw_image::read_ppm", "Malformed ppm file"); return false; } for( int index=0; index<3; ) { // the format is "P6[whitespace]width[whitespace]height[[whitespace bitdepth]]newline] // however, Photoshop is the first program that uses space for the first whitespace // so we cater for Photoshop too while( *c!=0 && *c<=32 ) { c++; } // usually, after P6 there comes a comment with the maker // but comments can be anywhere if( *c==0 ) { if( read_line(buf, sizeof(buf), file) == NULL ) { dbg->error("raw_image::read_ppm", "Malformed ppm file"); fclose(file); return false; } c = buf; continue; } param[index++] = atoi(c); while( *c>='0' && *c<='9' ) { c++; } } // now the data const sint32 w = param[0]; const sint32 h = param[1]; if (w <= 0 || h <= 0) { dbg->error("raw_image_t::read_ppm", "Heightfield has invalid image size (%dx%d)", w, h); fclose(file); return false; } if( param[2]!=255 ) { dbg->warning("raw_image_t::read_ppm", "Heightfield has wrong color depth (was %d, must be 255)", param[2]); } width = w; height = h; fmt = FMT_RGBA8888; bpp = 32; data = REALLOC(data, uint8, width * height * (bpp/CHAR_BIT)); for( sint16 y=0; yerror("raw_image_t::read_ppm", "Malformed ppm file"); return false; } *data++ = R; *data++ = G; *data++ = B; *data++ = 0xFF; } } fclose(file); return true; } bool raw_image_t::write_ppm(const char *) const { dbg->error("raw_image_t::write_ppm", "Not implemented"); return false; } simutrans-124.3/src/simutrans/io/rdwr/000077500000000000000000000000001474050137200177545ustar00rootroot00000000000000simutrans-124.3/src/simutrans/io/rdwr/adler32_stream.cc000066400000000000000000000013651474050137200230770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "adler32_stream.h" #include "../../simdebug.h" #include adler32_stream_t::adler32_stream_t() : rdwr_stream_t(true) { adler_checksum = adler32(0, NULL, 0); status = STATUS_OK; } size_t adler32_stream_t::read(void *, size_t) { dbg->fatal("adler32_stream_t::read", "Cannot reconstruct original message from checksum!"); return 0; } size_t adler32_stream_t::write(const void *buf, size_t len) { adler_checksum = adler32(adler_checksum, static_cast(buf), len); return len; } uint32 adler32_stream_t::get_hash() { const uint32 result = adler_checksum; adler_checksum = adler32(0, NULL, 0); return result; } simutrans-124.3/src/simutrans/io/rdwr/adler32_stream.h000066400000000000000000000012061474050137200227330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_ADLER32_STREAM_H #define IO_RDWR_ADLER32_STREAM_H #include "rdwr_stream.h" /// Computes the adler32 checksum over some data class adler32_stream_t : public rdwr_stream_t { public: adler32_stream_t(); public: /// @copydoc rdwr_stream_t::write size_t write(const void *buf, size_t len) OVERRIDE; /// @returns the adler32 checksum of all the data written since the last get_hash() uint32 get_hash(); private: /// DO NOT USE! size_t read(void *buf, size_t len) OVERRIDE; private: uint32 adler_checksum; }; #endif simutrans-124.3/src/simutrans/io/rdwr/bzip2_file_rdwr_stream.cc000066400000000000000000000034131474050137200247220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "bzip2_file_rdwr_stream.h" #include "../../sys/simsys.h" #include bzip2_file_rdwr_stream_t::bzip2_file_rdwr_stream_t(const std::string &filename, bool writing) : rdwr_stream_t(writing) { if (is_writing()) { fp = dr_fopen(filename.c_str(), "wb"); bzfp = BZ2_bzWriteOpen( &bse, fp, 9, 0, 30 /* default is 30 */ ); } else { fp = dr_fopen(filename.c_str(), "rb"); bzfp = BZ2_bzReadOpen( &bse, fp, 0, 0, NULL, 0 ); } status = STATUS_OK; if (fp==NULL) { status = STATUS_ERR_FILE_INACCESSIBLE; } if( bse!=BZ_OK ) { status = STATUS_ERR_WRITEFAILURE; } } bzip2_file_rdwr_stream_t::~bzip2_file_rdwr_stream_t() { if (is_writing()) { // BZLIB seems to eat the last byte if it is at an odd position // => we just write a dummy zero padding byte if (status == STATUS_OK) { write( "", 1 ); } BZ2_bzWriteClose( &bse, bzfp, 0, NULL, NULL ); } else { BZ2_bzReadClose( &bse, bzfp ); } if (fp) { fclose( fp ); } } size_t bzip2_file_rdwr_stream_t::read(void *buf, size_t len) { assert(!is_writing()); assert(bse == BZ_OK || bse == BZ_STREAM_END); assert(len < 0x7FFFFFFFU); const int bytes_read = (bse == BZ_OK) ? BZ2_bzRead(&bse, bzfp, buf, len) : 0; switch (bse) { case BZ_OK: status = STATUS_OK; return bytes_read; case BZ_STREAM_END: status = STATUS_EOF; return bytes_read; default: status = STATUS_ERR_CORRUPT; return 0; } } size_t bzip2_file_rdwr_stream_t::write(const void* buf, size_t len) { assert(is_writing()); assert(bse==BZ_OK); BZ2_bzWrite( &bse, bzfp, const_cast(buf), len); if (bse == BZ_OK) { return len; } else { status = STATUS_ERR_FULL; return 0; } } simutrans-124.3/src/simutrans/io/rdwr/bzip2_file_rdwr_stream.h000066400000000000000000000012611474050137200245630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_BZIP2_FILE_RDWR_STREAM_H #define IO_RDWR_BZIP2_FILE_RDWR_STREAM_H #include "rdwr_stream.h" #include /// Reads/writes data from/to a bzip2 compressed file. class bzip2_file_rdwr_stream_t : public rdwr_stream_t { public: bzip2_file_rdwr_stream_t(const std::string &filename, bool writing); ~bzip2_file_rdwr_stream_t(); public: /// @copydoc rdwr_stream_t::read size_t read(void *buf, size_t len) OVERRIDE; /// @copydoc rdwr_stream_t::write size_t write(const void *buf, size_t len) OVERRIDE; private: FILE *fp; BZFILE *bzfp; int bse; }; #endif simutrans-124.3/src/simutrans/io/rdwr/compare_file_rd_stream.cc000066400000000000000000000023071474050137200247520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "compare_file_rd_stream.h" #include #include compare_file_rd_stream_t::compare_file_rd_stream_t(rdwr_stream_t *s1, rdwr_stream_t* s2) : rdwr_stream_t(false) { assert(s1 && s1->is_reading() && s1->get_status() == STATUS_OK); assert(s2 && s2->is_reading() && s2->get_status() == STATUS_OK); stream1 = s1; stream2 = s2; status = STATUS_OK; our_buf = NULL; our_len = 0; } compare_file_rd_stream_t::~compare_file_rd_stream_t() { free(our_buf); } size_t compare_file_rd_stream_t::read(void *buf, size_t len) { if (len > our_len) { free(our_buf); our_buf = (char*)malloc(len); our_len = len; } assert(!is_writing()); size_t r1 = stream1->read(buf, len); size_t r2 = stream2->read(our_buf, len); bool ok = (r1 == r2) && memcmp(buf, our_buf, r1)==0; // dump if difference is found if (!ok) { printf("File 1: "); for(int i=0; i /// Compares two streams: reads from both, throws error if streams are different. class compare_file_rd_stream_t : public rdwr_stream_t { size_t our_len; char *our_buf; public: /// Takes two streams, does not take ownership compare_file_rd_stream_t(rdwr_stream_t *s1, rdwr_stream_t* s2); ~compare_file_rd_stream_t(); public: /// @copydoc rdwr_stream_t::read size_t read(void *buf, size_t len) OVERRIDE; // not implemented size_t write(const void *, size_t) OVERRIDE { return -1; } private: rdwr_stream_t *stream1, *stream2; }; #endif simutrans-124.3/src/simutrans/io/rdwr/raw_file_rdwr_stream.cc000066400000000000000000000027171474050137200244730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "raw_file_rdwr_stream.h" #include "../../sys/simsys.h" #include raw_file_rdwr_stream_t::raw_file_rdwr_stream_t(const std::string &filename, bool writing) : rdwr_stream_t(writing) { file = dr_fopen(filename.c_str(), writing ? "wb" : "rb"); if (!file) { status = STATUS_ERR_FILE_INACCESSIBLE; } else { status = STATUS_OK; } } raw_file_rdwr_stream_t::raw_file_rdwr_stream_t(FILE *f, bool writing) : rdwr_stream_t(writing), file(f) { if (!file) { status = STATUS_ERR_FILE_INACCESSIBLE; } else if (ferror(file)) { status = STATUS_ERR_CORRUPT; } else if (feof(file)) { status = STATUS_EOF; } else { status = STATUS_OK; } } raw_file_rdwr_stream_t::~raw_file_rdwr_stream_t() { if (file) { fflush(file); fclose(file); } } size_t raw_file_rdwr_stream_t::read(void *buf, size_t len) { assert(!is_writing()); const size_t bytes_read = fread(buf, 1, len, file); if (bytes_read == len) { status = STATUS_OK; return bytes_read; } else if (feof(file)) { status = STATUS_EOF; return bytes_read; } else { status = STATUS_ERR_CORRUPT; return 0; } } size_t raw_file_rdwr_stream_t::write(const void *buf, size_t len) { assert(is_writing()); const size_t bytes_written = fwrite(buf, 1, len, file); if (bytes_written == len) { status = STATUS_OK; } else { status = STATUS_ERR_FULL; } return bytes_written; } simutrans-124.3/src/simutrans/io/rdwr/raw_file_rdwr_stream.h000066400000000000000000000014461474050137200243330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_RAW_FILE_RDWR_STREAM_H #define IO_RDWR_RAW_FILE_RDWR_STREAM_H #include "rdwr_stream.h" #include /// Reads/writes raw data from/to a file. class raw_file_rdwr_stream_t : public rdwr_stream_t { public: raw_file_rdwr_stream_t(const std::string &filename, bool writing); /// Takes ownership of an already open file. /// @p writing must match the mode with which the file was opened. raw_file_rdwr_stream_t(FILE *f, bool writing); ~raw_file_rdwr_stream_t(); public: /// @copydoc rdwr_stream_t::read size_t read(void *buf, size_t len) OVERRIDE; /// @copydoc rdwr_stream_t::write size_t write(const void *buf, size_t len) OVERRIDE; private: FILE *file; }; #endif simutrans-124.3/src/simutrans/io/rdwr/rdwr_stream.cc000066400000000000000000000003521474050137200226140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "rdwr_stream.h" rdwr_stream_t::rdwr_stream_t(bool writing) : status(STATUS_ERR_NOT_INITIALIZED), writing(writing) { } simutrans-124.3/src/simutrans/io/rdwr/rdwr_stream.h000066400000000000000000000047441474050137200224670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_RDWR_STREAM_H #define IO_RDWR_RDWR_STREAM_H #include "../../simtypes.h" #include /// Either reads or writes data (but not both at the same time). class rdwr_stream_t { public: /// Note: On failure, this does not throw. Instead, call @ref get_status() to check if /// @ref read() or @ref write() can be called. Derived classes must update @ref status accordingly. rdwr_stream_t(bool writing); virtual ~rdwr_stream_t() {} public: enum status_t { STATUS_OK = 0, STATUS_EOF = 1, ///< (when reading) end of file/buffer reached // error codes STATUS_ERR_NOT_INITIALIZED = -1, ///< Not initialized STATUS_ERR_GENERIC_ERROR = -2, ///< Catch-all for unknown errors STATUS_ERR_FILE_INACCESSIBLE = -3, ///< File not found or wrong permissions on file or directory STATUS_ERR_FULL = -4, ///< (when writing) No space left in buffer or hard drive STATUS_ERR_WRITEFAILURE = -5, ///< Failed to produce a valid file for whatever reason STATUS_ERR_NO_VERSION = -6, STATUS_ERR_FUTURE_VERSION = -7, STATUS_ERR_OBSOLETE_VERSION = -8, ///< Version too old STATUS_ERR_CORRUPT = -9 ///< ex.: file malformed }; status_t get_status() const { return status; } bool is_writing() const { return writing; } bool is_reading() const { return !writing; } public: /// Read at most @p len bytes into @p buf; must not be called when writing. /// If this function fails, call @ref get_status() to get information about the type of error. /// /// @param buf Must not be NULL. /// @param len Must not be 0. /// /// @returns @p len, if successful. /// @returns The number of bytes successfully read, if end-of-data occurs. /// @returns Undefined (but not @p len), if an error occurred. virtual size_t read(void *buf, size_t len) = 0; /// Write at most @p len bytes from @p buf; must not be called when reading. /// If this function fails, call @ref get_status() to get information about the type of error. /// /// @param buf Must not be NULL. /// @param len Must not be 0. /// /// @returns @p len, if successful. /// @returns Undefined (but not @p len), if an error occurred. virtual size_t write(const void *buf, size_t len) = 0; protected: /// @warning This must be updated to the correct value when @p read() or @p write() or the constructor fails. status_t status; private: const bool writing; }; #endif simutrans-124.3/src/simutrans/io/rdwr/zlib_file_rdwr_stream.cc000066400000000000000000000060401474050137200246330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "zlib_file_rdwr_stream.h" #include "../../sys/simsys.h" #include "../../macros.h" #include "../../simdebug.h" #include #include zlib_file_rdwr_stream_t::zlib_file_rdwr_stream_t(const std::string &filename, bool writing, int compression) : rdwr_stream_t(writing) { // Should be 0 anyway, but make sure to only catch errors from zlib // zlib might not set errno appropriately in all error cases // (source: https://refspecs.linuxbase.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/zlib-gzopen-1.html) // so reset it to a known value. The value will be translated to GENERIC_ERROR by set_status_from_errno errno = 0; if (is_writing()) { compression = clamp( compression, 1, 9 ); char compr[4] = { 'w', 'b', (char)('0' + compression), 0 }; gzfp = dr_gzopen(filename.c_str(), compr); } else { gzfp = dr_gzopen(filename.c_str(), "rb"); } if (gzfp == Z_NULL) { set_status_from_errno(); } else { gzbuffer(gzfp, 65536); status = STATUS_OK; } } zlib_file_rdwr_stream_t::~zlib_file_rdwr_stream_t() { if (is_writing()) { gzflush(gzfp, Z_FINISH); } gzclose(gzfp); } size_t zlib_file_rdwr_stream_t::read(void *buf, size_t len) { assert(!is_writing()); const int bytes_read = gzread(gzfp, buf, len); if (bytes_read >= 0 && (size_t)bytes_read == len) { status = STATUS_OK; return bytes_read; } else if (bytes_read != -1) { // not error => eof reached status = STATUS_EOF; return bytes_read; } else { // error int errnum = 0; const char *errmsg = gzerror(gzfp, &errnum); if (!errmsg) errmsg = ""; dbg->error("zlib_file_rdwr_stream_t::read", "Error: %s", errmsg); status = STATUS_ERR_CORRUPT; return 0; } } size_t zlib_file_rdwr_stream_t::write(const void *buf, size_t len) { assert(is_writing()); assert(len > 0); const int bytes_written = gzwrite(gzfp, const_cast(buf), len); if (bytes_written <= 0) { // error occurred int errnum = Z_OK; gzerror(gzfp, &errnum); switch (errnum) { case Z_MEM_ERROR: status = STATUS_ERR_WRITEFAILURE; return 0; // memerror means the lib could not malloc 260k => something else must be very wrong case Z_STREAM_ERROR: status = STATUS_ERR_NOT_INITIALIZED; return 0; case Z_BUF_ERROR: status = STATUS_ERR_FULL; return 0; case Z_ERRNO: set_status_from_errno(); return 0; } status = STATUS_ERR_GENERIC_ERROR; return 0; } else { status = STATUS_OK; return bytes_written; } } void zlib_file_rdwr_stream_t::set_status_from_errno() { switch (errno) { case EPERM: case ENOENT: case EIO: case EBADF: case EACCES: case ENODEV: case EISDIR: case ELOOP: status = STATUS_ERR_FILE_INACCESSIBLE; break; case ENOMEM: // this can only fail if there is invalid chunk data in the lib status = STATUS_ERR_CORRUPT; break; case EFBIG: case ENOSPC: status = STATUS_ERR_FULL; break; default: status = STATUS_ERR_GENERIC_ERROR; break; } } simutrans-124.3/src/simutrans/io/rdwr/zlib_file_rdwr_stream.h000066400000000000000000000013351474050137200244770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_ZLIB_FILE_RDWR_STREAM_H #define IO_RDWR_ZLIB_FILE_RDWR_STREAM_H #include "rdwr_stream.h" #include /// Reads/writes data from/to a zlib/gzip (deflate) compressed file. class zlib_file_rdwr_stream_t : public rdwr_stream_t { public: zlib_file_rdwr_stream_t(const std::string &filename, bool writing, int compression); ~zlib_file_rdwr_stream_t(); public: /// @copydoc rdwr_stream_t::read size_t read(void *buf, size_t len) OVERRIDE; /// @copydoc rdwr_stream_t::write size_t write(const void *buf, size_t len) OVERRIDE; private: void set_status_from_errno(); private: gzFile gzfp; }; #endif simutrans-124.3/src/simutrans/io/rdwr/zstd_file_rdwr_stream.cc000066400000000000000000000121621474050137200246610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "zstd_file_rdwr_stream.h" #include "../../dataobj/environment.h" #include "../../simdebug.h" #include "../../simmem.h" #include #define ZSTD_FILE_BUF_SIZE (1 << 20) // 1MiB zstd_file_rdwr_stream_t::zstd_file_rdwr_stream_t(const std::string &filename, bool writing, int compression_level) : raw_file_rdwr_stream_t(filename, writing), zbuff(NULL) { if (status != STATUS_OK) { return; // Could not open file } if (writing) { // compressing compression_context = ZSTD_createCCtx(); if( compression_context == NULL ) { // zstd could not init status = STATUS_ERR_NOT_INITIALIZED; return; } #if ZSTD_VERSION_MAJOR<=1 && ZSTD_VERSION_MINOR<=3 ZSTD_initCStream( compression_context, compression_level ); #else size_t ret1 = ZSTD_CCtx_setParameter( compression_context, ZSTD_c_compressionLevel, compression_level ); if (ZSTD_isError(ret1)) { dbg->error("zstd_file_rdwr_stream_t::zstd_file_rdwr_stream_t", "Cannot set compression level: %s", ZSTD_getErrorName(ret1)); status = STATUS_ERR_NOT_INITIALIZED; return; } // const size_t ret2 = ZSTD_CCtx_setParameter( compression_context, ZSTD_c_checksumFlag, 1 ); // if (ZSTD_isError(ret2)) { // dbg->error("zstd_file_rdwr_stream_t::zstd_file_rdwr_stream_t", "Cannot enable file checksumming: %s", ZSTD_getErrorName(ret2)); // status = STATUS_ERR_NOT_INITIALIZED; // return; // } #ifdef MULTI_THREAD ret1 = ZSTD_CCtx_setParameter( compression_context, ZSTD_c_nbWorkers, env_t::num_threads ); if (ZSTD_isError(ret1)) { // since compression should continue anyway, do not stop! dbg->warning("zstd_file_rdwr_stream_t::zstd_file_rdwr_stream_t", "Cannot set workers: %s", ZSTD_getErrorName(ret1)); } #endif #endif // the additional magic for zstd if (raw_file_rdwr_stream_t::write("ZD", 2) != 2) { return; } } else { // decompressing decompression_context = ZSTD_createDCtx(); if (decompression_context == NULL) { status = STATUS_ERR_CORRUPT; return; } char buf[2]; if (raw_file_rdwr_stream_t::read(buf, 2) != 2) { status = STATUS_ERR_CORRUPT; return; } else if (buf[0] != 'Z' || buf[1] != 'D') { status = STATUS_ERR_CORRUPT; return; } } zbuff = xmalloc(ZSTD_FILE_BUF_SIZE); if (writing) { zin.src = NULL; zin.size = 0; zin.pos = 0; zout.dst = zbuff; zout.size = ZSTD_FILE_BUF_SIZE; zout.pos = 0; } else { zin.src = zbuff; zin.size = ZSTD_FILE_BUF_SIZE; zin.pos = ZSTD_FILE_BUF_SIZE; zout.dst = NULL; zout.size = 0; zout.pos = 0; } status = STATUS_OK; } zstd_file_rdwr_stream_t::~zstd_file_rdwr_stream_t() { if (is_writing()) { // write zero length dummy to indicate end of data zin.src = ""; zin.size = 0; zin.pos = 0; zout.dst = zbuff; zout.size = ZSTD_FILE_BUF_SIZE; zout.pos = 0; size_t ret; do { zout.pos = 0; ret = ZSTD_endStream( compression_context, &zout ); if (ZSTD_isError(ret)) { dbg->error("zstd_file_rdwr_stream_t::~zstd_file_rdwr_stream_t", "Error flushing stream: %s", ZSTD_getErrorName(ret)); } raw_file_rdwr_stream_t::write( zout.dst, zout.pos ); } while( ret>0 ); ZSTD_freeCCtx( compression_context ); } else { ZSTD_freeDCtx( decompression_context ); } free( zbuff ); } size_t zstd_file_rdwr_stream_t::read(void *buf, size_t len) { zout.dst = buf; zout.size = len; zout.pos = 0; do { // first decompress from remaining input buffer while( zin.pos < zin.size && zout.pos < zout.size ) { const size_t ret = ZSTD_decompressStream( decompression_context, &zout, &zin ); if (ZSTD_isError(ret)) { dbg->error("zstd_file_rdwr_stream_t::read", "Error during decompression: %s", ZSTD_getErrorName(ret)); status = STATUS_ERR_CORRUPT; return 0; } if( ret == 0 ) { zout.size = zout.pos; } } // not enough data to fill output buffer => read more data from file if( zout.pos < zout.size ) { const size_t bytes_read = raw_file_rdwr_stream_t::read(zbuff, ZSTD_FILE_BUF_SIZE); zin.pos = 0; zin.size = bytes_read; if (status != rdwr_stream_t::STATUS_OK && status != rdwr_stream_t::STATUS_EOF) { // an error occurred, status is already set to the appropriate value return 0; } // reset status since EOF is indicated by end of decompressed data, // not end of compressed data status = STATUS_OK; } } while( zin.pos < zin.size && zout.pos < zout.size ); if (zout.pos < len) { // end of decompressed data reached status = STATUS_EOF; } return zout.pos; } size_t zstd_file_rdwr_stream_t::write(const void *buf, size_t len) { // compress the next data zin.src = buf; zin.size = len; zin.pos = 0; while( zin.pos < zin.size ) { zout.pos = 0; const size_t ret = ZSTD_compressStream( compression_context, &zout, &zin ); if (ZSTD_isError(ret)) { dbg->error("zstd_file_rdwr_stream_t::write", "Error during compression: %s", ZSTD_getErrorName(ret)); status = STATUS_ERR_WRITEFAILURE; return 0; } if (raw_file_rdwr_stream_t::write( zout.dst, zout.pos ) != zout.pos) { status = STATUS_ERR_FULL; return 0; } } return zin.pos; } simutrans-124.3/src/simutrans/io/rdwr/zstd_file_rdwr_stream.h000066400000000000000000000017061474050137200245250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef IO_RDWR_ZSTD_FILE_RDWR_STREAM_H #define IO_RDWR_ZSTD_FILE_RDWR_STREAM_H #include "raw_file_rdwr_stream.h" #include #if !USE_ZSTD #pragma message( "warning: Cannot use zstd_file_rdwr_stream_t: zstd not enabled") #endif /// Reads/writes data data from/to a zstd compressed file. class zstd_file_rdwr_stream_t : public raw_file_rdwr_stream_t { public: zstd_file_rdwr_stream_t(const std::string &filename, bool writing, int compression); ~zstd_file_rdwr_stream_t(); public: /// @copydoc rdwr_stream_t::read size_t read(void *buf, size_t len) OVERRIDE; /// @copydoc rdwr_stream_t::write size_t write(const void *buf, size_t len) OVERRIDE; private: void *zbuff; // buffer for compressed data, i.e. file <-> zbuff ZSTD_inBuffer zin; ZSTD_outBuffer zout; ZSTD_CCtx *compression_context; ZSTD_DCtx *decompression_context; }; #endif simutrans-124.3/src/simutrans/linehandle.h000066400000000000000000000003761474050137200206510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef LINEHANDLE_H #define LINEHANDLE_H #include "tpl/quickstone_tpl.h" class simline_t; typedef quickstone_tpl linehandle_t; #endif simutrans-124.3/src/simutrans/macros.h000066400000000000000000000015611474050137200200270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef MACROS_H #define MACROS_H #include "simtypes.h" #include template static constexpr size_t lengthof(const T (&)[N]) { return N; } template static constexpr T *endof(T (&arr)[N]) { return arr + N; } #define QUOTEME_(x) #x #define QUOTEME(x) QUOTEME_(x) #define MEMZERON(ptr, n) memset((ptr), 0, sizeof(*(ptr)) * (n)) #define MEMZERO(obj) MEMZERON(&(obj), 1) // make sure, a value in within the borders template static inline T clamp(T v, T l, T u) { return v < l ? l : (v > u ? u :v); } namespace sim { template inline void swap(T& a, T& b) { T t = a; a = b; b = t; } // XXX Workaround for GCC 2.95 template static inline T up_cast(T x) { return x; } } #endif simutrans-124.3/src/simutrans/music/000077500000000000000000000000001474050137200175075ustar00rootroot00000000000000simutrans-124.3/src/simutrans/music/AVF_core-audio_midi.mm000066400000000000000000000034671474050137200236010ustar00rootroot00000000000000/* * Apple OSX Core Audio MIDI routine added by Leopard * * This file is part of the Simutrans project under the artistic licence. * */ #import "music.h" #include "../simdebug.h" #import #import #import static int nowPlaying = -1; // the number of the track currently being played static NSMutableArray* players; void dr_set_midi_volume(int const vol) { // Not supportd by AVMIDIPlayer } int dr_load_midi(char const* const filename) { NSURL* const url = [NSURL fileURLWithPath: [NSString stringWithUTF8String: filename]]; AVMIDIPlayer* const player = [[AVMIDIPlayer alloc] initWithContentsOfURL:url soundBankURL: nil error: nil]; if (player) { [player prepareToPlay]; [players addObject: player]; } return [players count] - 1; } void dr_play_midi(int const key) { // Play the file referenced by the supplied key. AVMIDIPlayer* const player = [players objectAtIndex: key]; double duration = [player duration]; double currentPosition = [player currentPosition]; if (currentPosition >= duration) { [player setCurrentPosition: 0.0]; } try { [player play: ^{}]; } catch (NSException *e) { dbg->warning("dr_play_midi()", "AVFoundation: Error playing midi"); } nowPlaying = key; } void dr_stop_midi() { if( nowPlaying!= -1 ) { // We assume the 'nowPlaying' key holds the most recently started track. AVMIDIPlayer* const player = [players objectAtIndex: nowPlaying]; [player stop]; } } sint32 dr_midi_pos() { if (nowPlaying == -1) { return -1; } float const rate = [[players objectAtIndex: nowPlaying] rate]; return rate > 0 ? 0 : -1; } void dr_destroy_midi() { if (nowPlaying != -1) { dr_stop_midi(); } } bool dr_init_midi() { players = [NSMutableArray arrayWithCapacity: MAX_MIDI]; return true; } simutrans-124.3/src/simutrans/music/core-audio_midi.mm000066400000000000000000000031461474050137200230770ustar00rootroot00000000000000/* * Apple OSX Core Audio MIDI routine added by Leopard * * This file is part of the Simutrans project under the artistic licence. * */ #import "music.h" #import #import #import static float defaultVolume = 0.5; // a nice default volume static int nowPlaying = -1; // the number of the track currently being played static NSMutableArray* movies; void dr_set_midi_volume(int const vol) { // We are given an integer from 0 - 255, we need a float between 0 and 1. defaultVolume = vol / 255.f; if (nowPlaying != -1) { [[movies objectAtIndex: nowPlaying] setVolume: defaultVolume]; } } int dr_load_midi(char const* const filename) { NSString* const s = [NSString stringWithUTF8String: filename]; QTMovie* const m = [QTMovie movieWithFile: s error: nil]; if (m) { [movies addObject: m]; } return [movies count] - 1; } void dr_play_midi(int const key) { // Play the file referenced by the supplied key. QTMovie* const m = [movies objectAtIndex: key]; [m setVolume:defaultVolume]; [m play]; nowPlaying = key; } void dr_stop_midi() { if( nowPlaying!= -1 ) { // We assume the 'nowPlaying' key holds the most recently started track. QTMovie* const m = [movies objectAtIndex: nowPlaying]; [m stop]; } } sint32 dr_midi_pos() { if (nowPlaying == -1) { return -1; } float const rate = [[movies objectAtIndex: nowPlaying] rate]; return rate > 0 ? 0 : -1; } void dr_destroy_midi() { if (nowPlaying != -1) { dr_stop_midi(); } } bool dr_init_midi() { movies = [NSMutableArray arrayWithCapacity: MAX_MIDI]; return true; } simutrans-124.3/src/simutrans/music/fluidsynth.cc000066400000000000000000000156171474050137200222210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../utils/plainstring.h" #include "../dataobj/environment.h" #include "music.h" #ifndef _WIN32 #if !defined __APPLE__ && !defined __ANDROID__ #include #else #include #endif #endif // fluidsynth music routine interfaces static int midi_number = -1; static plainstring midi_filenames[MAX_MIDI]; fluid_settings_t* settings; fluid_synth_t* synth; fluid_audio_driver_t* adriver; fluid_player_t* player; // Predefined list of paths to search for soundfonts static const char * default_sf_paths[] = { /* RedHat/Fedora/Arch path */ "/usr/share/soundfonts/", /* Debian/Ubuntu/OpenSUSE path */ "/usr/share/sounds/sf2/", NULL }; // Soundfonts included on linux distros or bundled with Simutrans static const char * default_sf_names[] = { "default.sf3", "default.sf2", "freepats-general-midi.sf2", "PCLite.sf2", "TimGM6mb.sf2", "FluidR3_GM.sf2", "FluidR3_GS.sf2", NULL }; #ifdef __ANDROID__ /* Fluidsynth on Android is too old and does not export some functions */ extern "C" int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan); #endif /** * sets midi playback volume */ void dr_set_midi_volume(int vol) { /* Allowed range of synth.gain is 0.0 to 10.0 */ /* fluidsynth's default gain is 0.2, to avoid possible clipping. * Set gain using Simutrans's volume, as a number between 0 * and 0.7 to balance with sound effects. */ if( fluid_settings_setnum( settings, "synth.gain", 0.7 * vol / 255.0 ) != FLUID_OK ) { dbg->warning("dr_set_midi_volume()", "FluidSynth: Could not set volume."); } } /** * Loads a MIDI file */ int dr_load_midi(const char *filename) { if( midi_number < MAX_MIDI - 1 ) { const int i = midi_number + 1; if( i >= 0 && i < MAX_MIDI && fluid_is_midifile( filename ) ) { midi_number = i; midi_filenames[i] = filename; } else { dbg->warning("dr_load_midi()", "FluidSynth: Failed to load MIDI %s.", filename ); } } return midi_number; } /** * Plays a MIDI file */ void dr_play_midi(int key) { if( dr_midi_pos() != -1 ) { dr_stop_midi(); } if( !(player = new_fluid_player( synth )) ) { dbg->warning("dr_play_midi()", "FluidSynth: MIDI player setup failed."); return; } if( fluid_player_add( player, midi_filenames[key] ) != FLUID_OK ) { dbg->warning("dr_play_midi()", "FluidSynth: %s MIDI file load failed.", midi_filenames[key].c_str() ); return; } if( fluid_player_play( player ) != FLUID_OK ) { dbg->warning("dr_play_midi()", "FluidSynth: MIDI player start failed."); return; } } /** * Stops playing MIDI file */ void dr_stop_midi(void) { if( !player ) { return; } fluid_player_stop( player ); if( fluid_player_join( player ) != FLUID_OK ) { dbg->warning("dr_stop_midi()", "FluidSynth: Player join failed."); } fluid_synth_all_notes_off( synth, -1 ); delete_fluid_player( player ); player = NULL; } /** * Returns the midi_pos variable <- doesn't actually do this * Simutrans only needs to know whether file has finished (so that it can start the next music) * Returns -1 if current music has finished, else 0 */ sint32 dr_midi_pos(void) { if( !player || fluid_player_get_status( player ) != FLUID_PLAYER_PLAYING ) { return -1; } return 0; } /** * Midi shutdown/cleanup */ void dr_destroy_midi(void) { dr_stop_midi(); delete_fluid_audio_driver(adriver); delete_fluid_synth(synth); delete_fluid_settings(settings); midi_number = -1; } /** * MIDI initialisation routines */ bool dr_load_sf(const char * filename){ static int previous_id = -1; if( synth && fluid_is_soundfont( filename ) ) { int next_id = fluid_synth_sfload( synth, filename, 1 ); if( next_id != FLUID_FAILED ) { if( previous_id != -1 ) { fluid_synth_sfunload( synth, previous_id, 1 ); } previous_id = next_id; env_t::soundfont_filename = filename; return true; } } return false; } #if FLUIDSYNTH_VERSION_MAJOR >= 2 static void fluid_log(int level, const char* message, void*) #else static void fluid_log(int level, char *message, void *) #endif { switch (level) { case FLUID_PANIC: dbg->fatal("FluidSynth", "%s", message); case FLUID_ERR: dbg->error("FluidSynth", "%s", message); break; case FLUID_WARN: dbg->warning("FluidSynth", "%s", message); break; case FLUID_INFO: dbg->message("FluidSynth", "%s", message); break; case FLUID_DBG: dbg->debug("FluidSynth", "%s", message); break; } } bool dr_init_midi() { fluid_set_log_function(FLUID_PANIC, fluid_log, NULL); fluid_set_log_function(FLUID_ERR, fluid_log, NULL); fluid_set_log_function(FLUID_WARN, fluid_log, NULL); fluid_set_log_function(FLUID_INFO, fluid_log, NULL); fluid_set_log_function(FLUID_DBG, fluid_log, NULL); #ifdef _WIN32 std::string fluidsynth_driver = "dsound"; #elif defined(__APPLE__) && __APPLE__ std::string fluidsynth_driver = "coreaudio"; #elif defined(__ANDROID__) && __ANDROID__ std::string fluidsynth_driver = "oboe"; #else std::string fluidsynth_driver = "sdl2"; if( !SDL_WasInit(SDL_INIT_AUDIO) ) { if( SDL_InitSubSystem( SDL_INIT_AUDIO ) != 0 ) { dbg->warning("dr_init_midi()", "FluidSynth: SDL_INIT_AUDIO failed."); return false; } } #endif if( !(settings = new_fluid_settings()) ) { dbg->warning("dr_init_midi()", "FluidSynth: MIDI settings failed."); return false; } fluid_settings_setint( settings, "synth.cpu-cores", env_t::num_threads ); fluid_settings_setstr( settings, "synth.midi-bank-select", "gm" ); if( fluid_settings_setstr( settings, "audio.driver", fluidsynth_driver.c_str() ) != FLUID_OK ) { dbg->warning("dr_init_midi()", "FluidSynth: Set MIDI driver %s failed.", fluidsynth_driver.c_str()); return false; } if( !(synth = new_fluid_synth( settings )) ) { dbg->warning("dr_init_midi()", "FluidSynth: Synth setup failed."); return false; } if( !(adriver = new_fluid_audio_driver( settings, synth )) ) { dbg->warning("dr_init_midi()", "FluidSynth: Audio driver setup failed."); return false; } // User defined font first if( dr_load_sf( env_t::soundfont_filename.c_str() ) || dr_load_sf( ((std::string)env_t::base_dir + "music/" + env_t::soundfont_filename).c_str() ) ) { return true; } // Bundled soundfonts second for( int i = 0; default_sf_names[i]; i++ ) { if( dr_load_sf( ((std::string)env_t::base_dir + "music/" + (std::string)default_sf_names[i] ).c_str() ) ) { return true; } } // System soundfonts at last for( int i = 0; default_sf_paths[i]; i++ ) { for( int j = 0; default_sf_names[j]; j++ ){ if( dr_load_sf( ((std::string)default_sf_paths[i] + (std::string)default_sf_names[j]).c_str() ) ) { return true; } } } env_t::soundfont_filename = "Error"; dbg->warning("dr_init_midi()", "FluidSynth: No soundfont was found."); return true; // MIDI system has been initialed even if no soundfont was loaded. A user can load a soundfont after. } simutrans-124.3/src/simutrans/music/music.h000066400000000000000000000015721474050137200210050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef MUSIC_MUSIC_H #define MUSIC_MUSIC_H #include "../simtypes.h" #define MAX_MIDI (128) /** * MIDI initialisation routine * false: leave midi alone */ bool dr_init_midi(); /** * sets midi playback volume * @param vol volume in range 0..255 */ void dr_set_midi_volume(int vol); /** * Loads a MIDI file */ int dr_load_midi(const char* filename); /** * Plays a MIDI file */ void dr_play_midi(int key); /** * Stops playing MIDI file */ void dr_stop_midi(); /** * @return -1 if current track has finished, 0 otherwise. */ sint32 dr_midi_pos(); /** * Midi shutdown/cleanup */ void dr_destroy_midi(); /** * Load a soundfont. Only available if we are using FluidSynth. */ #ifdef USE_FLUIDSYNTH_MIDI bool dr_load_sf(const char * filename); #endif #endif simutrans-124.3/src/simutrans/music/no_midi.cc000066400000000000000000000012631474050137200214360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "music.h" // Dummy midi routines - only provide interface, does nothing /** * sets midi playback volume */ void dr_set_midi_volume(int) { } /** * Loads a MIDI file */ int dr_load_midi(const char *) { return -1; } /** * Plays a MIDI file */ void dr_play_midi(int) { } /** * Stops playing MIDI file */ void dr_stop_midi(void) { } /** * Returns the midi_pos variable */ sint32 dr_midi_pos(void) { return 0; } /** * Midi shutdown/cleanup */ void dr_destroy_midi(void) { } /** * MIDI initialisation routines */ bool dr_init_midi(void) { return false; } simutrans-124.3/src/simutrans/music/sdl_midi.cc000066400000000000000000000042421474050137200216040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../simdebug.h" #include "../utils/plainstring.h" #include "music.h" // SDL_Mixer music routine interfaces static int midi_number = -1; static plainstring midi_filenames[MAX_MIDI]; //Mix_Music *music[MAX_MIDI]; Mix_Music *music = NULL; /** * sets midi playback volume */ void dr_set_midi_volume(int vol) { Mix_VolumeMusic((vol*MIX_MAX_VOLUME)/256); } /** * Loads a MIDI file */ int dr_load_midi(const char * filename) { if (midi_number < MAX_MIDI - 1) { const int i = midi_number + 1; if(i >= 0 && i < MAX_MIDI) { music = Mix_LoadMUS(filename); if(music) { midi_number = i; midi_filenames[i] = filename; } else { dbg->warning( "dr_load_midi()", "Failed to load MIDI %s because %s", filename, Mix_GetError() ); } Mix_FreeMusic(music); music = NULL; } } return midi_number; } /** * Plays a MIDI file */ void dr_play_midi(int key) { if(dr_midi_pos()!= -1) { dr_stop_midi(); } music = Mix_LoadMUS(midi_filenames[key]); Mix_PlayMusic(music, 1); } /** * Stops playing MIDI file */ void dr_stop_midi(void) { if(music) { Mix_HaltMusic(); Mix_FreeMusic(music); music = NULL; } } /** * Returns the midi_pos variable <- doesn't actually do this * Simutrans only needs to know whether file has finished (so that it can start the next music) * Returns -1 if current music has finished, else 0 */ sint32 dr_midi_pos(void) { if(Mix_PlayingMusic()== 0) { return -1; } else { return 0; } } /** * Midi shutdown/cleanup */ void dr_destroy_midi(void) { dr_stop_midi(); midi_number = -1; } /** * MIDI initialisation routines */ bool dr_init_midi(void) { // if audio not init if(!SDL_WasInit(SDL_INIT_AUDIO)) { // if audio subsys is ok if(SDL_InitSubSystem(SDL_INIT_AUDIO) != -1) { if(Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 1024)==-1) { //if OpenAudio returns error, dr_init_midi is false return false; } } else { //if SDL_InitSubSystem returns error, dr_init_midi is false return false; } } //if all is fine, return true return true; } simutrans-124.3/src/simutrans/music/w32_midi.cc000066400000000000000000000171671474050137200214470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include "../utils/plainstring.h" #include "music.h" #include "../simsound.h" #include "../simdebug.h" // native win32 midi playing routines static int midi_number = -1; static plainstring midi_filenames[MAX_MIDI]; static int OldMIDIVol[2] = {-1, -1}; #define __MIDI_VOL_SIMU 1 // 0-255 #define __MIDI_VOL_WIN32 2 // 0-65535 void __win32_set_midi_volume(int type, int left, int right); /** * sets midi playback volume */ void dr_set_midi_volume(int vol) { __win32_set_midi_volume(__MIDI_VOL_SIMU, vol, vol); } /** * Loads a MIDI file */ int dr_load_midi(const char *filename) { if(midi_number < MAX_MIDI-1) { const int i = midi_number + 1; if (i >= 0 && i < MAX_MIDI) { // MCI doesn't like relative paths // but we get absolute ones anyway // already absolute path midi_filenames[i] = filename; // need to make dos path separators for (char* j = midi_filenames[i]; *j != '\0'; ++j) { if (*j == '/') { *j = '\\'; } } midi_number = i; } } return midi_number; } /** * Plays a MIDI file * Key: The index of the MIDI file to be played */ void dr_play_midi(int key) { char str[200], retstr[200]; if (midi_number > 0) { if (key >= 0 && key <= midi_number) { sprintf(str, "open \"%s\" type sequencer alias SimuMIDI", midi_filenames[key].c_str()); dbg->debug("dr_play_midi(w32)", "MCI string: %s", str); if (mciSendStringA(str, NULL, 0, NULL) != 0) { dbg->warning("dr_play_midi(w32)", "Unable to load MIDI %d", key); } else if (mciSendStringA("play SimuMIDI", retstr, 200, NULL) != 0) { dbg->warning("dr_play_midi(w32)", "Unable to play MIDI %d - %s\n", key, retstr); } } else { dbg->warning("dr_play_midi(w32)", "Unable to play MIDI %d", key); } } } /** * Stops playing MIDI file */ void dr_stop_midi() { // stop_midi(); char retstr[200]; mciSendStringA("stop SimuMIDI", retstr, 200, NULL); mciSendStringA("close SimuMIDI", retstr, 200, NULL); } /** * Returns the midi_pos variable */ sint32 dr_midi_pos() { char retstr[200]; long length; mciSendStringA("set SimuMIDI time format milliseconds", retstr, 200, NULL); mciSendStringA("status SimuMIDI length", retstr, 200, NULL); length = atol(retstr); if (mciSendStringA("status SimuMIDI position", retstr, 200, NULL) == 0) { const long pos = atol(retstr); if (pos == length) { mciSendStringA("stop SimuMIDI", retstr, 200, NULL); // We must stop ourselves mciSendStringA("close SimuMIDI", retstr, 200, NULL); return (-1); } else { return pos; } } return 0; } /** * Midi shutdown/cleanup */ void dr_destroy_midi() { __win32_set_midi_volume(__MIDI_VOL_WIN32, OldMIDIVol[0], OldMIDIVol[1]); midi_number = -1; } /** * MIDI initialisation routines */ bool dr_init_midi() { #ifdef MIXER_VOLUME UINT nMIDIDevices; MIXERLINECONTROLS mlc; MIXERCONTROL MixControl; MIXERCONTROLDETAILS MixControlDetails; MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsUnsigned[2]; MIXERLINE MixerLine; HMIXER hMixer; MIXERCAPS DevCaps; // Reset MIDI volume nMIDIDevices = midiOutGetNumDevs(); if (nMIDIDevices == 0) return; mixerOpen(&hMixer, 0, 0, 0, MIXER_OBJECTF_MIDIOUT); mixerGetDevCaps((UINT) hMixer, &DevCaps, sizeof(DevCaps)); mixerClose(hMixer); MixerLine.cbStruct = sizeof(MixerLine); MixerLine.Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT; MixerLine.Target.wMid = DevCaps.wMid; MixerLine.Target.wPid = DevCaps.wPid; MixerLine.Target.vDriverVersion = DevCaps.vDriverVersion; strcpy(MixerLine.Target.szPname, DevCaps.szPname); mixerGetLineInfo(0, &MixerLine, MIXER_GETLINEINFOF_TARGETTYPE | MIXER_OBJECTF_MIDIOUT); mlc.cbStruct = sizeof(mlc); mlc.dwLineID = MixerLine.dwLineID; mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mlc.cControls = 1; mlc.cbmxctrl = sizeof(MixControl); mlc.pamxctrl = &MixControl; MixControl.cbStruct = sizeof(MixControl); MixControl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mixerGetLineControls(0, &mlc, MIXER_OBJECTF_MIDIOUT | MIXER_GETLINECONTROLSF_ONEBYTYPE); MixControlDetails.cbStruct = sizeof(MixControlDetails); MixControlDetails.dwControlID = MixControl.dwControlID; MixControlDetails.cChannels = MixerLine.cChannels; MixControlDetails.hwndOwner = NULL; MixControlDetails.cMultipleItems = 0; MixControlDetails.cbDetails = sizeof(MixControlDetailsUnsigned[0])*2; MixControlDetails.paDetails = &MixControlDetailsUnsigned[0]; mixerGetControlDetails(0, &MixControlDetails, MIXER_OBJECTF_MIDIOUT | MIXER_GETCONTROLDETAILSF_VALUE); OldMIDIVol[0] = MixControlDetailsUnsigned[0].dwValue; // Save the old volume OldMIDIVol[1] = MixControlDetailsUnsigned[0].dwValue; sound_set_midi_volume_var(OldMIDIVol[0] >> 8); // Set the MIDI volume mixerSetControlDetails(0, &MixControlDetails, MIXER_OBJECTF_MIDIOUT | MIXER_SETCONTROLDETAILSF_VALUE); #else if( midiOutGetNumDevs()== 0 ) { return false; } DWORD old_volume; midiOutGetVolume( 0, &old_volume ); OldMIDIVol[0] = old_volume>>24; OldMIDIVol[1] = (old_volume&0x0000FF00)>>8; #endif // assuming if we got here, all is set up to work properly return true; } #ifdef MIXER_VOLUME // Sets the MIDI volume - internal routine void __win32_set_midi_volume(int type, int left, int right) { UINT nMIDIDevices; MIXERLINECONTROLS mlc; MIXERCONTROL MixControl; MIXERCONTROLDETAILS MixControlDetails; MIXERCONTROLDETAILS_UNSIGNED MixControlDetailsUnsigned[2]; MIXERLINE MixerLine; HMIXER hMixer; MIXERCAPS DevCaps; nMIDIDevices = midiOutGetNumDevs(); if (nMIDIDevices == 0) { return; } mixerOpen(&hMixer, 0, 0, 0, MIXER_OBJECTF_MIDIOUT); mixerGetDevCaps((UINT) hMixer, &DevCaps, sizeof(DevCaps)); mixerClose(hMixer); MixerLine.cbStruct = sizeof(MixerLine); MixerLine.Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT; MixerLine.Target.wMid = DevCaps.wMid; MixerLine.Target.wPid = DevCaps.wPid; MixerLine.Target.vDriverVersion = DevCaps.vDriverVersion; strcpy(MixerLine.Target.szPname, DevCaps.szPname); mixerGetLineInfo(0, &MixerLine, MIXER_GETLINEINFOF_TARGETTYPE | MIXER_OBJECTF_MIDIOUT); mlc.cbStruct = sizeof(mlc); mlc.dwLineID = MixerLine.dwLineID; mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mlc.cControls = 1; mlc.cbmxctrl = sizeof(MixControl); mlc.pamxctrl = &MixControl; MixControl.cbStruct = sizeof(MixControl); MixControl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mixerGetLineControls(0, &mlc, MIXER_OBJECTF_MIDIOUT | MIXER_GETLINECONTROLSF_ONEBYTYPE); MixControlDetails.cbStruct = sizeof(MixControlDetails); MixControlDetails.dwControlID = MixControl.dwControlID; MixControlDetails.cChannels = MixerLine.cChannels; MixControlDetails.hwndOwner = NULL; MixControlDetails.cMultipleItems = 0; MixControlDetails.cbDetails = sizeof(MixControlDetailsUnsigned[0])*2; MixControlDetails.paDetails = &MixControlDetailsUnsigned[0]; mixerGetControlDetails(0, &MixControlDetails, MIXER_OBJECTF_MIDIOUT | MIXER_GETCONTROLDETAILSF_VALUE); if (type == __MIDI_VOL_SIMU) { MixControlDetailsUnsigned[0].dwValue = (left << 8); MixControlDetailsUnsigned[1].dwValue = (right << 8); } else { MixControlDetailsUnsigned[0].dwValue = left; MixControlDetailsUnsigned[1].dwValue = right; } mixerSetControlDetails(0, &MixControlDetails, MIXER_OBJECTF_MIDIOUT | MIXER_SETCONTROLDETAILSF_VALUE); // Phew, I'm glad that's over! What a horrible API... } #else // Sets the MIDI volume - internal routine void __win32_set_midi_volume(int , int left, int right) { // short version long vol = (left<<24)|(right<<8); if( midiOutGetNumDevs()== 0 ) { return; } midiOutSetVolume( 0, vol ); } #endif simutrans-124.3/src/simutrans/network/000077500000000000000000000000001474050137200200605ustar00rootroot00000000000000simutrans-124.3/src/simutrans/network/checksum.cc000066400000000000000000000050221474050137200221700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "checksum.h" #include #include #include "../simdebug.h" checksum_t::checksum_t() { sha = NULL; reset(); } checksum_t& checksum_t::operator=(const checksum_t& other) { assert(other.valid); valid = true; delete sha; sha = NULL; for(uint8 i=0; i<20; i++) { message_digest[i] = other.message_digest[i]; } return *this; } checksum_t::checksum_t(const checksum_t &other) { assert(other.valid); valid = true; sha = NULL; for(uint8 i=0; i<20; i++) { message_digest[i] = other.message_digest[i]; } } checksum_t::~checksum_t() { delete sha; } void checksum_t::reset() { if (sha == NULL) { sha = new SHA1(); } else { sha->Reset(); } valid = false; } bool checksum_t::operator== (checksum_t &other) { if (!valid) { finish(); } if (!other.valid) { other.finish(); } for(uint8 i=0; i<20; i++) { if (message_digest[i] != other.message_digest[i]) { return false; } } return true; } bool checksum_t::operator== (const checksum_t &other) const { assert(valid && other.valid); for(uint8 i=0; i<20; i++) { if (message_digest[i] != other.message_digest[i]) { return false; } } return true; } void checksum_t::input(bool data) { assert(sha); // save bool as (uint8)1 uint8 bool1 = data ? 1 : 0; input(bool1); } void checksum_t::input(uint8 data) { assert(sha); sha->Input((const char*)&data, sizeof(uint8)); } void checksum_t::input(sint8 data) { input((uint8)data); } void checksum_t::input(uint16 data) { uint16 little_endian = endian(data); assert(sha); sha->Input((const char*)&little_endian, sizeof(uint16)); } void checksum_t::input(sint16 data) { input((uint16)data); } void checksum_t::input(uint32 data) { uint32 little_endian = endian(data); assert(sha); sha->Input((const char*)&little_endian, sizeof(uint32)); } void checksum_t::input(sint32 data) { input((uint32)data); } void checksum_t::input(const char *data) { if (data==NULL) { data = "null"; } assert(sha); sha->Input(data, strlen(data)); } const char* checksum_t::get_str(const int maxlen) const { static char buf[41]; for(uint8 i=0; iinput(message_digest[i]); } } void checksum_t::finish() { if (!valid) { assert(sha); sha->Result(message_digest); valid = true; delete sha; sha = NULL; } } simutrans-124.3/src/simutrans/network/checksum.h000066400000000000000000000023461474050137200220400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_CHECKSUM_H #define NETWORK_CHECKSUM_H #include "../utils/sha1.h" class checksum_t { private: sha1_hash_t message_digest; bool valid:1; SHA1 *sha; public: checksum_t(); checksum_t& operator=(const checksum_t&); checksum_t(const checksum_t&); ~checksum_t(); /** * fetches the result */ void finish(); void reset(); bool operator== (checksum_t &); bool operator== (const checksum_t &) const; bool is_valid() const { return valid; } void input(bool data); void input(uint8 data); void input(sint8 data); void input(uint16 data); void input(sint16 data); void input(uint32 data); void input(sint32 data); void input(const char *data); const char* get_str(const int maxlen=20) const; // templated to be able to read/write from/to loadsave_t and packet_t template void rdwr(rdwr_able *file) { if(file->is_saving()) { if (!valid) { finish(); } } else { valid = true; delete sha; sha = 0; } for(uint8 i=0; i<20; i++) { file->rdwr_byte(message_digest[i]); } } /** * build checksum of checksums */ void calc_checksum(checksum_t *chk) const; }; #endif simutrans-124.3/src/simutrans/network/memory_rw.cc000066400000000000000000000051041474050137200224070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "memory_rw.h" #include #include #include "../simdebug.h" #include "../simmem.h" #include "../utils/plainstring.h" memory_rw_t::memory_rw_t( void *ptr, uint32 max, bool saving ) { this->saving = saving; this->ptr = (char *)ptr; index = 0; max_size = max; overflow = false; } void memory_rw_t::rdwr(void *data, uint32 len) { assert(data); if( len+index>max_size ) { len = max_size-index; overflow = true; } if(is_saving()) { memmove(ptr+index, data, len); } else { memmove(data, ptr+index, len); } index += len; } void memory_rw_t::rdwr_byte(sint8 &c) { rdwr(&c, sizeof(sint8)); } void memory_rw_t::rdwr_byte(uint8 &c) { rdwr(&c, sizeof(uint8)); } void memory_rw_t::rdwr_bool(bool &i) { uint8 b = i; rdwr_byte(b); i = b!=0; } void memory_rw_t::rdwr_short(sint16 &i) { #ifdef SIM_BIG_ENDIAN sint16 ii; if(is_saving()) { ii = endian(i); } rdwr(&ii, sizeof(sint16)); if(is_loading()) { i = endian(ii); } #else rdwr(&i, sizeof(sint16)); #endif } void memory_rw_t::rdwr_short(uint16 &i) { sint16 ii=i; rdwr_short(ii); i = (uint16)ii; } void memory_rw_t::rdwr_long(sint32 &l) { #ifdef SIM_BIG_ENDIAN sint32 ii; if(is_saving()) { ii = endian(l); } rdwr(&ii, sizeof(sint32)); if(is_loading()) { l = endian(ii); } #else rdwr(&l, sizeof(sint32)); #endif } void memory_rw_t::rdwr_long(uint32 &l) { sint32 ll=l; rdwr_long(ll); l = (uint32)ll; } void memory_rw_t::rdwr_longlong(sint64 &ll) { #ifdef SIM_BIG_ENDIAN sint64 ii; if(is_saving()) { ii = endian(ii); } rdwr(&ii, sizeof(sint64)); if(is_loading()) { ll = endian(ii); } #else rdwr(&ll, sizeof(sint64)); #endif } void memory_rw_t::rdwr_str(char *&s) { // string length uint16 len = 0; if(is_saving()) { len = s ? strlen(s) : 0; } rdwr_short(len); // now the string if (is_saving()) { if(len>0 && !overflow) { rdwr( s, len); } } else { free( (void *)s ); s = 0; if(len>0 && !overflow) { s = MALLOCN(char, len + 1); rdwr(s, len); s[len] = '\0'; } } } void memory_rw_t::rdwr_str(plainstring &s) { if(is_loading()) { char *t = NULL; rdwr_str(t); s = t; free(t); } else { char *t = s; rdwr_str(t); } } void memory_rw_t::append(const memory_rw_t &mem) { assert(saving && mem.saving); rdwr(mem.ptr, mem.get_current_index()); } void memory_rw_t::append_tail(const memory_rw_t &mem) { assert(saving && !mem.saving); rdwr(mem.ptr + mem.get_current_index(), mem.max_size - mem.get_current_index()); } simutrans-124.3/src/simutrans/network/memory_rw.h000066400000000000000000000031411474050137200222500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_MEMORY_RW_H #define NETWORK_MEMORY_RW_H /* This is a class to write data to memory in intel byte order * on every architecture */ #include "../simtypes.h" class plainstring; class memory_rw_t { private: // pointer to the buffer char *ptr; // actual read/write position uint32 index; // maximal buffer size uint32 max_size; bool saving:1; bool overflow:1; public: memory_rw_t( void *ptr, uint32 max, bool saving ); protected: void set_max_size( uint32 new_max_size ) { max_size = new_max_size; } void set_index(uint32 new_index) { index = new_index; } public: uint32 get_current_index() const { return index; } bool is_saving() const { return saving; } bool is_loading() const { return !saving; } bool is_overflow() const { return overflow; } void rdwr_byte(sint8 &c); void rdwr_byte(uint8 &c); void rdwr_short(sint16 &i); void rdwr_short(uint16 &i); void rdwr_long(sint32 &i); void rdwr_long(uint32 &i); void rdwr_longlong(sint64 &i); void rdwr_bool(bool &i); void rdwr_double(double &dbl); // s: pointer to a string allocated with malloc! void rdwr_str(char *&s); void rdwr_str(plainstring& s); /** * appends the contents of the other buffer from [0 .. index-1] * (only if saving) */ void append(const memory_rw_t &mem); /** * appends the contents of the other buffer from [index .. max_size-1] * (only if reading) */ void append_tail(const memory_rw_t &mem); private: // Low-Level Read / Write function void rdwr(void *data, uint32 len); }; #endif simutrans-124.3/src/simutrans/network/network.cc000066400000000000000000000757431474050137200221000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* basic network functionality, borrowed from OpenTTD */ #if defined(__amiga__) // warning: IPv6 will only work on Windows XP and up ... #define USE_IP4_ONLY #endif #include #include #include #include #include #include "network.h" #include "network_address.h" #include "network_packet.h" #include "network_socket_list.h" #include "network_cmd.h" #include "network_cmd_ingame.h" #include "network_cmp_pakset.h" #include "../simconst.h" #include "../simversion.h" #ifndef NETTOOL #include "../dataobj/environment.h" #endif #include "../utils/simstring.h" #include "../tpl/slist_tpl.h" static bool network_active = false; uint16 network_server_port = 0; // list of received commands static slist_tpl received_command_queue; // blacklist address_list_t blacklist; void clear_command_queue() { while(!received_command_queue.empty()) { network_command_t *nwc = received_command_queue.remove_first(); delete nwc; } } #if USE_WINSOCK #define RET_ERR_STR { DWORD errnr = WSAGetLastError(); if( errnr!=0 ) FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM,NULL,errnr,MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),err_str,sizeof(err_str),NULL); err = err_str; return INVALID_SOCKET; } #else #define RET_ERR_STR { err = err_str; return INVALID_SOCKET; } #include #endif // global client id static uint32 client_id; void network_set_client_id(uint32 id) { client_id = id; } uint32 network_get_client_id() { return client_id; } /** * Initializes the network core (as that is needed for some platforms * @return true if the core has been initialized, false otherwise */ static bool network_initialize() { if(!network_active) { socket_list_t::reset(); #if USE_WINSOCK /* Let's load the network in windows */ WSADATA wsa; if(int err = WSAStartup( MAKEWORD(2, 2), &wsa)) { dbg->warning("NetworkInitialize()","failed loading windows socket library with %i", err); return false; } #endif } network_active = true; return true; } /** * Open a socket connected to a remote address * In case of failure err is populated with a meaningful error * @return a valid socket or INVALID_SOCKET if the connection fails */ SOCKET network_open_address(char const* cp, char const*& err) { err = NULL; if (!network_initialize()) { err = "Cannot init network!"; return INVALID_SOCKET; } #ifdef USE_IP4_ONLY // Network load. Address format e.g.: "128.0.0.1:13353" char address[1024]; static char err_str[256]; uint16 port = 13353; const char *cp2 = strrchr(cp,':'); if(cp2!=NULL) { port=atoi(cp2+1); // Copy the address part tstrncpy(address,cp,cp2-cp>sizeof(address)-1?sizeof(address)-1:cp2-cp+1); cp = address; } struct sockaddr_in server_name; memset(&server_name,0,sizeof(server_name)); server_name.sin_family=AF_INET; #if USE_WINSOCK bool ok = true; server_name.sin_addr.s_addr = inet_addr(cp); // for windows we must first try to resolve the number if((int)server_name.sin_addr.s_addr==-1) { // Bad address ok = false; struct hostent *theHost; theHost = gethostbyname( cp ); // ... before resolving a name ... if(theHost) { server_name.sin_addr = *(struct in_addr *)theHost->h_addr_list[0]; ok = true; } } if(!ok) { #else /* inet_anon does not work on BeOS; but since gethostbyname() can * do this job on all other systems too, we use it only: * instead of if(inet_aton(cp,&server_name.sin_addr)==0) { // Bad address */ struct hostent *theHost; theHost = gethostbyname( cp ); if(theHost) { server_name.sin_addr = *(struct in_addr *)theHost->h_addr_list[0]; } else {// Bad address #endif sprintf( err_str, "Bad address %s", cp ); RET_ERR_STR; } server_name.sin_port=htons(port); SOCKET my_client_socket = socket(AF_INET,SOCK_STREAM,0); if(my_client_socket==INVALID_SOCKET) { err = "Cannot create socket"; return INVALID_SOCKET; } if (connect(my_client_socket, (struct sockaddr*)&server_name, sizeof(server_name)) == -1) { sprintf(err_str, "Could not connect to %s", cp); RET_ERR_STR; } #else // Address format e.g.: "example.com:13353", "128.0.0.1:13353" or "[::1]:80" // this should be replaced with a URI parser... static char err_str[256]; // scan address string for key features const char *cp2 = strrchr( cp, ':' ); const char *ipv6end = strrchr( cp, ']' ); const char *ipv6start = strchr( cp, '[' ); // extract port if available std::string cpport; if ( cp2 != NULL && cp2 > ipv6end ) { cpport = std::string(cp2 + 1); } else { cpport = std::string("13353"); cp2 = strrchr(cp, '\0'); } // remove brackets from IPv6 addresses const bool ipv6exists = ipv6start != NULL && ipv6end != NULL; const char *const start = ipv6exists ? ipv6start + 1 : cp; const char *const end = ipv6exists ? ipv6end : cp2; // extract address const size_t addresslen = size_t(end - start); std::string const cpaddress(start, addresslen); SOCKET my_client_socket = INVALID_SOCKET; bool connected = false; #ifdef NETTOOL // Nettool doesn't have env, so fake it vector_tpl ips; ips.append_unique("::"); ips.append_unique("0.0.0.0"); #else vector_tpl const& ips = env_t::listen; #endif // For each address in the list of listen addresses try and create a socket to transmit on // Use the first one which works for (uint i = 0; !connected && i != ips.get_count(); ++i) { std::string const& ip = ips[i]; int ret; // Set up remote addrinfo struct addrinfo *remote; struct addrinfo remote_hints; memset( &remote_hints, 0, sizeof( struct addrinfo ) ); remote_hints.ai_socktype = SOCK_STREAM; remote_hints.ai_family = PF_UNSPEC; // Test remote address to ensure it is valid // Fill out remote address structure if ( (ret = getaddrinfo(cpaddress.c_str(), cpport.c_str(), &remote_hints, &remote)) != 0) { sprintf( err_str, "Bad address %s", cp ); if( i+1==ips.get_count() ) { RET_ERR_STR; } // maybe it is an IPv4 only on the second interface .. continue; } // Set up local addrinfo struct addrinfo *local; struct addrinfo local_hints; memset( &local_hints, 0, sizeof( struct addrinfo ) ); local_hints.ai_socktype = SOCK_STREAM; local_hints.ai_family = PF_UNSPEC; // Insert listen address into local_hints struct to influence local address to bind to DBG_MESSAGE( "network_open_address()", "Preparing to bind address: %s", ip.c_str() ); if ( (ret = getaddrinfo( ip.c_str(), 0, &local_hints, &local )) != 0 ) { dbg->warning( "network_open_address()", "Failed to getaddrinfo for %s, error was: %s", ip.c_str(), gai_strerror(ret) ); #ifndef NETTOOL env_t::listen.remove_at( i ); #endif i --; continue; } // Now try and open a socket to communicate with our remote endpoint struct addrinfo *walk_local; for( walk_local = local; !connected && walk_local != NULL; walk_local = walk_local->ai_next ) { char ipstr_local[INET6_ADDRSTRLEN]; // Validate address + get string representation for logging if ( (ret = getnameinfo( (walk_local->ai_addr), (socklen_t)walk_local->ai_addrlen, ipstr_local, sizeof(ipstr_local), NULL, 0, NI_NUMERICHOST )) !=0 ) { dbg->warning( "network_open_address()", "Call to getnameinfo() failed with error: \"%s\"", gai_strerror(ret) ); continue; } DBG_MESSAGE( "network_open_address()", "Potential local address: %s", ipstr_local ); my_client_socket = socket( walk_local->ai_family, walk_local->ai_socktype, walk_local->ai_protocol ); if ( my_client_socket == INVALID_SOCKET ) { DBG_MESSAGE( "network_open_address()", "Could not create socket! Error: \"%s\"", strerror(GET_LAST_ERROR()) ); continue; } // Bind socket to local IP if ( bind( my_client_socket, walk_local->ai_addr, walk_local->ai_addrlen ) ) { DBG_MESSAGE( "network_open_address()", "Unable to bind socket to local IP address! Error: \"%s\"", strerror(GET_LAST_ERROR()) ); network_close_socket( my_client_socket ); my_client_socket = INVALID_SOCKET; continue; } // For each address in remote, try and connect struct addrinfo *walk_remote; for ( walk_remote = remote; !connected && walk_remote != NULL; walk_remote = walk_remote->ai_next ) { char ipstr_remote[INET6_ADDRSTRLEN]; // Validate remote address + get string representation for logging if ( (ret = getnameinfo( walk_remote->ai_addr, (socklen_t)walk_remote->ai_addrlen, ipstr_remote, sizeof(ipstr_remote), NULL, 0, NI_NUMERICHOST )) !=0 ) { dbg->warning( "network_open_address()", "Call to getnameinfo() failed with error: \"%s\"", gai_strerror(ret) ); continue; } DBG_MESSAGE( "network_open_address()", "Potential remote address: %s", ipstr_remote ); // put socked in non-blocking mode... #ifdef WIN32 u_long block = 1; if( ioctlsocket(my_client_socket, FIONBIO, &block) != 0 ) { my_client_socket = INVALID_SOCKET; DBG_MESSAGE("network_open_address()", "Failed to make unblocking socket."); continue; } #endif if (connect(my_client_socket, walk_remote->ai_addr, (socklen_t)walk_remote->ai_addrlen) != 0) { if( GET_LAST_ERROR() != EINPROGRESS) { // connection failed network_close_socket(my_client_socket); continue; } // connection pending fd_set setW, setE; FD_ZERO(&setW); FD_SET(my_client_socket, &setW); FD_ZERO(&setE); FD_SET(my_client_socket, &setE); timeval time_out; time_out.tv_sec = 2; // 2 seconds or joining a server would not make sense time_out.tv_usec = 0; int ret = select(my_client_socket+1, NULL, &setW, &setE, &time_out); if (ret <= 0) { // select() failed or connection timed out DBG_MESSAGE("network_open_address()", "Could not connect using this socket. select() Error: \"%s\"", strerror(GET_LAST_ERROR())); network_close_socket(my_client_socket); continue; } if( FD_ISSET(my_client_socket, &setE) ) { // connection failed DBG_MESSAGE("network_open_address()", "Could not connect FD_ISSET failed."); network_close_socket(my_client_socket); continue; } // connection successful // put socket in blocking mode... #ifdef WIN32 block = 0; bool blocking_mode = ioctlsocket(my_client_socket, FIONBIO, &block) == 0; if (!blocking_mode) { DBG_MESSAGE("network_open_address()", "Could not reset to non-blocking."); network_close_socket(my_client_socket); continue; } // linux non-blocking sockets seems to not work at all! #endif } connected = true; } // If no connection throw away this socket and try the next one if ( !connected ) { network_close_socket( my_client_socket ); my_client_socket = INVALID_SOCKET; } } freeaddrinfo( local ); freeaddrinfo( remote ); } if ( my_client_socket == INVALID_SOCKET ) { sprintf( err_str, "Could not connect to %s", cp ); RET_ERR_STR; } #endif return my_client_socket; } /** * Start up server on the port specified * Server will listen on all addresses specified in @p listen_addrs * @return true on success */ bool network_init_server( int port, const vector_tpl &listen_addrs ) { if ( port==0 ) { dbg->fatal( "network_init_server()", "Cannot host on port 0!" ); } // First activate network if ( !network_initialize() ) { dbg->fatal( "network_init_server()", "Failed to initialize network!" ); } socket_list_t::reset(); #ifdef USE_IP4_ONLY (void)listen_addrs; const SOCKET my = socket( PF_INET, SOCK_STREAM, 0 ); if ( my == INVALID_SOCKET ) { dbg->fatal( "network_init_server()", "Failed to open socket!" ); return false; } struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons( port ); name.sin_addr.s_addr = htonl( INADDR_ANY ); if ( bind( my, (struct sockaddr *)&name, sizeof( name ) ) == -1 ) { dbg->fatal( "network_init_server()", "Bind failed!" ); return false; } /* Max pending connections */ if ( listen( my, MAX_PLAYER_COUNT ) == -1 ) { dbg->fatal( "network_init_server()", "Listen failed for %i sockets!", MAX_PLAYER_COUNT ); return false; } socket_list_t::add_server( my ); #else // For each address in the list of listen addresses try and create a socket to listen on for(std::string const& ip : listen_addrs) { int ret; char port_nr[16]; sprintf( port_nr, "%u", port ); struct addrinfo *server; struct addrinfo hints; memset( &hints, 0, sizeof( struct addrinfo ) ); hints.ai_socktype = SOCK_STREAM; // Insert potential listen address into hints struct to influence local address to bind to DBG_MESSAGE( "network_init_server()", "Preparing to bind address: \"%s\"", ip.c_str() ); hints.ai_family = PF_UNSPEC; if ( (ret = getaddrinfo( ip.c_str(), port_nr, &hints, &server )) != 0 ) { dbg->fatal( "network_init_server()", "Call to getaddrinfo() failed for: \"%s\", error was: \"%s\" - check listen directive in simuconf.tab!", ip.c_str(), gai_strerror(ret) ); } else { dbg->message( "network_init_server()", "Attempting to bind listening sockets for: \"%s\"\n", ip.c_str() ); } SOCKET server_socket; struct addrinfo *walk; // Open a listen socket for each IP address specified by this entry in the listen list for ( walk = server; walk != NULL; walk = walk->ai_next ) { char ipstr[INET6_ADDRSTRLEN]; // Validate address + get string representation for logging if ( (ret = getnameinfo( walk->ai_addr, (socklen_t)walk->ai_addrlen, ipstr, sizeof(ipstr), NULL, 0, NI_NUMERICHOST )) != 0 ) { dbg->warning( "network_init_server()", "Call to getnameinfo() failed with error: \"%s\"", gai_strerror(ret) ); continue; } DBG_MESSAGE( "network_init_server()", "Potential bind address: %s", ipstr ); server_socket = socket( walk->ai_family, walk->ai_socktype, walk->ai_protocol ); if ( server_socket == INVALID_SOCKET ) { dbg->warning( "network_init_server()", "Could not create socket! Error: \"%s\"", strerror(GET_LAST_ERROR()) ); continue; } /* Disable IPv4-mapped IPv6 addresses for this IPv6 listen socket This ensures that we are using separate sockets for dual-stack, one for v4, one for v6 */ if ( walk->ai_family == AF_INET6 ) { int const on = 1; if ( setsockopt(server_socket, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&on), sizeof(on)) != 0 ) { dbg->warning( "network_init_server()", "Call to setsockopt(IPV6_V6ONLY) failed for: \"%s\", error was: \"%s\"", ip.c_str(), strerror(GET_LAST_ERROR()) ); network_close_socket( server_socket ); server_socket = INVALID_SOCKET; continue; } } // Enable reusing of local addresses int const enable = 1; if ( setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(enable)) != 0 ) { dbg->warning( "network_init_server()", "Call to setsockopt(SO_REUSEADDR) failed for: \"%s\", error was: \"%s\"", ip.c_str(), strerror(GET_LAST_ERROR()) ); } if ( bind( server_socket, walk->ai_addr, walk->ai_addrlen ) ) { /* Unable to bind a socket - abort execution as we are supposed to be a server on this interface */ dbg->fatal( "network_init_server()", "Unable to bind socket to IP address: \"%s\", error was: \"%s\"", ipstr, strerror(GET_LAST_ERROR()) ); } if ( listen( server_socket, 32 ) == -1 ) { /* Unable to listen on bound socket - abort execution as we are supposed to be a server on this interface */ dbg->fatal( "network_init_server()", "Unable to set socket to listen for incoming connections on: \"%s\"", ipstr ); } dbg->message( "network_init_server()", "Added valid listen socket for address: \"%s\"\n", ipstr); socket_list_t::add_server( server_socket ); } freeaddrinfo( server ); } // Fatal error if no server sockets could be opened, since we're supposed to be a server! if ( socket_list_t::get_server_sockets() == 0 ) { dbg->fatal( "network_init_server()", "Unable to add any server sockets!" ); } else { dbg->message("network_init_server", "Server started, added %d server sockets", socket_list_t::get_server_sockets()); } #endif network_server_port = port; client_id = 0; network_reset_server(); return true; } void network_set_socket_nodelay( SOCKET sock ) { #if (defined(TCP_NODELAY) || COLOUR_DEPTH == 0) // do not wait to join small (command) packets when sending (may cause 200ms delay!) // force this for dedicated servers int b = 1; setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b) ); #else #warning TCP_NODELAY not defined. Expect multiplayer problems. (void)sock; #endif } network_command_t* network_get_received_command() { if (!received_command_queue.empty()) { return received_command_queue.remove_first(); } return NULL; } /* do appropriate action for network games: * - server: accept connection to a new client * - all: receive commands and puts them to the received_command_queue */ network_command_t *network_check_activity(int timeout) { fd_set fds; FD_ZERO(&fds); socket_list_t::fill_set(&fds); // time out: MAC complains about too long timeouts struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000ul; int action = select( FD_SETSIZE, &fds, NULL, NULL, &tv ); if( action<=0 ) { // timeout: return command from the queue return network_get_received_command(); } // accept new connection socket_list_t::server_socket_iterator_t iter_s(&fds); while(iter_s.next()) { SOCKET accept_sock = iter_s.get_current(); if( accept_sock!=INVALID_SOCKET ) { struct sockaddr_in client_name; socklen_t size = sizeof(client_name); SOCKET s = accept(accept_sock, (struct sockaddr *)&client_name, &size); if( s!=INVALID_SOCKET ) { #if USE_WINSOCK uint32 ip = ntohl((uint32)client_name.sin_addr.S_un.S_addr); #else uint32 ip = ntohl((uint32)client_name.sin_addr.s_addr); #endif if (blacklist.contains(net_address_t( ip ))) { // refuse connection network_close_socket(s); continue; } #ifdef __BEOS__ char name[256]; sprintf(name, "%lh", client_name.sin_addr.s_addr ); #else const char *name = inet_ntoa(client_name.sin_addr); #endif dbg->message("check_activity()", "Accepted connection from: %s.", name); socket_list_t::add_client(s, ip); } } } // receive from clients socket_list_t::client_socket_iterator_t iter_c(&fds); while(iter_c.next()) { SOCKET sender = iter_c.get_current(); if (sender != INVALID_SOCKET && socket_list_t::has_client(sender)) { uint32 client_id = socket_list_t::get_client_id(sender); network_command_t *nwc = socket_list_t::get_client(client_id).receive_nwc(); if (nwc) { received_command_queue.append(nwc); dbg->warning( "network_check_activity()", "received cmd %s (id %d) from socket[%d]", nwc->get_name(), nwc->get_id(), sender ); } // errors are caught and treated in socket_info_t::receive_nwc } } return network_get_received_command(); } void network_process_send_queues(int timeout) { fd_set fds; FD_ZERO(&fds); socket_list_t::fill_set(&fds); // time out struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000ul; int action = select( FD_SETSIZE, NULL, &fds, NULL, &tv ); if( action<=0 ) { // timeout: return return; } // send to clients socket_list_t::client_socket_iterator_t iter_c(&fds); while(iter_c.next() && action>0) { SOCKET sock = iter_c.get_current(); if (sock != INVALID_SOCKET && socket_list_t::has_client(sock)) { uint32 client_id = socket_list_t::get_client_id(sock); socket_list_t::get_client(client_id).process_send_queue(); // errors are caught and treated in socket_info_t::process_send_queue } action --; } } bool network_check_server_connection() { if( !network_server_port ) { // I am client // If I am playing, playing_clients should be at least one. if( socket_list_t::get_playing_clients()==0 ) { return false; } fd_set fds_read, fds_write; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds_read); socket_list_t::fill_set(&fds_read); FD_ZERO(&fds_write); socket_list_t::fill_set(&fds_write); int action = select( FD_SETSIZE, &fds_read, &fds_write, NULL, &tv ); if( action < 0 ) { // error - connection lost return false; } } return true; } // send data to all PLAYING clients // nwc is invalid after the call void network_send_all(network_command_t* nwc, bool exclude_us, uint8 player_nr) { if (nwc) { nwc->prepare_to_send(); socket_list_t::send_all(nwc, true, player_nr); if( !exclude_us && network_server_port ) { // I am the server nwc->get_packet()->sent_by_server(); received_command_queue.append(nwc); } else { delete nwc; } } } // send data to server // nwc is invalid after the call void network_send_server(network_command_t* nwc ) { if (nwc) { nwc->prepare_to_send(); if( !network_server_port ) { // I am client socket_list_t::send_all(nwc, true); delete nwc; } else { // I am the server nwc->get_packet()->sent_by_server(); received_command_queue.append(nwc); } } } /** * send data to dest * * @param dest * @param buf the data * @param size length of buffer and number of bytes to be sent * @param count * @param timeout_ms * @return true if data was completely send, false if an error occurs and connection needs to be closed */ bool network_send_data( SOCKET dest, const char *buf, const uint16 size, uint16 &count, const int timeout_ms ) { count = 0; #if USE_WINSOCK == 0 // ignore SIGPIPE sent by send() function. signal(SIGPIPE, SIG_IGN); #endif while (count < size) { const int sent = send(dest, buf+count, size-count, 0); if (sent == -1) { const int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { dbg->warning("network_send_data", "Could not send to [%d]: \"%s\"", dest, strerror(err)); return false; } if (timeout_ms <= 0) { // no timeout, continue sending later return true; } else { // try again, test whether sending is possible fd_set fds; FD_ZERO(&fds); FD_SET(dest,&fds); struct timeval tv; tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000ul; // can we write? if( select( FD_SETSIZE, NULL, &fds, NULL, &tv )!=1 ) { dbg->warning("network_send_data", "Could not write to socket [%d]", dest); return false; } } continue; } if (sent == 0) { // connection closed dbg->warning("network_send_data", "Connection [%d] already closed (sent %hu of %hu)", dest, count, size ); return false; } count += sent; DBG_DEBUG4("network_send_data", "Sent %d bytes to socket[%d]; size=%d, left=%d", count, dest, size, size-count ); } #if USE_WINSOCK == 0 signal(SIGPIPE, SIG_DFL); #endif // we reach here only if data are sent completely return true; } /** * receive data from sender * * @param sender * @param dest the destination buffer * @param len length of destination buffer and number of bytes to be received * @param received number of received bytes is returned here * @param timeout_ms * @return true if connection is still valid, false if an error occurs and connection needs to be closed */ bool network_receive_data( SOCKET sender, void *dest, const uint16 len, uint16 &received, const int timeout_ms ) { received = 0; char *ptr = (char *)dest; do { fd_set fds; FD_ZERO(&fds); FD_SET(sender,&fds); struct timeval tv; tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000ul; // can we read? if( select( FD_SETSIZE, &fds, NULL, NULL, &tv )!=1 ) { return true; } // now receive const int res = recv( sender, ptr+received, len-received, 0 ); if (res == -1) { const int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { dbg->warning("network_receive_data", "Could not receive from [%d]: \"%s\"", sender, strerror(err)); return false; } // try again later return true; } if (res == 0) { // connection closed // output warning / throw fatal error depending on heavy mode setting #ifndef NETTOOL void (log_t::*outfn)(const char*, const char*, ...) = (env_t::network_heavy_mode == 2 ? &log_t::fatal : &log_t::warning); (dbg->*outfn)("network_receive_data", "Connection [%d] already closed", sender); #endif return false; } received += res; } while( received #include } #if MINIUPNPC_API_VERSION < 14 #define upnpDiscover(a,b,c,d,e,f,g) upnpDiscover(a,b,c,d,e,g) #define UPNP_LOCAL_PORT_ANY 0 #endif bool prepare_for_server( char *externalIPAddress, char *externalAltIPAddress, int port ) { char lanaddr[64] = "unset"; /* my ip address on the LAN */ int error = 0; const char *multicastif = 0; const char *minissdpdpath = 0; int localport = UPNP_LOCAL_PORT_ANY; int ipv6 = 0; // probably not needed for IPv6 ever ... unsigned char ttl = 2; (void)ttl; /* defaulting to 2 */ struct UPNPDev *devlist = 0; bool has_IP = false; if( (devlist = upnpDiscover( 2000, multicastif, minissdpdpath, localport, ipv6, ttl, &error )) ) { struct UPNPUrls urls; struct IGDdatas data; #if MINIUPNPC_API_VERSION <= 17 UPNP_GetValidIGD( devlist, &urls, &data, lanaddr, sizeof(lanaddr) ); #else char wanaddr[64] = "uset"; UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), wanaddr, sizeof(lanaddr)); #endif // we must know our IP address first if( UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress) == UPNPCOMMAND_SUCCESS ) { // this is our ID (at least the routes tells us this) char eport[19]; char *iport = eport; sprintf( eport, "%d", port ); // remove anz forwarding UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport, "TCP", NULL); // setting up tcp redirect forever (last parameter "0") if( UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, lanaddr, "simutrans", "TCP", 0, "0") == UPNPCOMMAND_SUCCESS ) { // ok, we have our ID and redirected a port to us has_IP = true; } else { dbg->warning( "prepare_for_server()", "Could not redirect port (but may be still ok" ); has_IP = true; } } FreeUPNPUrls(&urls); } freeUPNPDevlist(devlist); externalAltIPAddress[0] = 0; // use the same routine as later the announce routine, otherwise update with dynamic IP fails cbuffer_t myIPaddr, altIPaddr; if( get_external_IP( myIPaddr, altIPaddr ) ) { has_IP = true; strcpy( externalIPAddress, myIPaddr ); if( altIPaddr.len() ) { strcpy( externalAltIPAddress, altIPaddr ); } } return has_IP; } // removes the redirect (or do nothing) void remove_port_forwarding( int port ) { if( port <= 0 || env_t::easy_server != 1 ) { return; } char lanaddr[64] = "unset"; /* my ip address on the LAN */ char externalIPAddress[64]; int error = 0; const char *multicastif = 0; const char *minissdpdpath = 0; int localport = UPNP_LOCAL_PORT_ANY; int ipv6 = 0; // probably not needed for IPv6 ever ... unsigned char ttl = 2; (void)ttl; /* defaulting to 2 */ struct UPNPDev *devlist = 0; if( (devlist = upnpDiscover( 2000, multicastif, minissdpdpath, localport, ipv6, ttl, &error )) ) { struct UPNPUrls urls; struct IGDdatas data; #if MINIUPNPC_API_VERSION <= 17 UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); #else char wanaddr[64] = "uset"; UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), wanaddr, sizeof(lanaddr)); #endif // we must know our IP address first if( UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress) == UPNPCOMMAND_SUCCESS ) { // this is our ID (at least the routes tells us this) char eport[19]; sprintf( eport, "%d", port ); UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, eport, "TCP", NULL); } FreeUPNPUrls(&urls); } freeUPNPDevlist(devlist); } #else // or we just get only our IP and hope we are not behind a router ... bool prepare_for_server(char* externalIPAddress, char* externalAltIPAddress, int /*port*/) { externalAltIPAddress[0] = 0; // use the same routine as later the announce routine, otherwise update with dynamic IP fails cbuffer_t myIPaddr, altIPaddr; if (get_external_IP(myIPaddr, altIPaddr)) { strcpy(externalIPAddress, myIPaddr); if (altIPaddr.len()) { strcpy(externalAltIPAddress, altIPaddr); } return true; } return false; } void remove_port_forwarding( int ) { } #endif #endif // not NETTOOL simutrans-124.3/src/simutrans/network/network.h000066400000000000000000000104561474050137200217300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_H #define NETWORK_NETWORK_H #if defined(_WIN32) && !defined(__CYGWIN__) #define USE_WINSOCK 1 #else #define USE_WINSOCK 0 #endif // windows headers #if USE_WINSOCK // must be include before all simutrans stuff! # include //# include # include # ifndef IPV6_V6ONLY # define IPV6_V6ONLY (27) # endif # if WINVER<=0x0500 // compiling for Windows 2000 # define USE_IP4_ONLY # endif # define GET_LAST_ERROR() WSAGetLastError() # include # undef EINPROGRESS # define EINPROGRESS WSAEWOULDBLOCK #else // beos specific headers # ifdef __BEOS__ # include # include // non-beos / non-windows # else # include # include # include # include # include # include # include # include # endif # ifdef __HAIKU__ # include # endif // all non-windows # include # include // to keep compatibility to MS windows typedef int SOCKET; # define INVALID_SOCKET -1 # define GET_LAST_ERROR() (errno) #endif #include "../tpl/vector_tpl.h" #include "../simconst.h" #include "../simtypes.h" #include "../utils/cbuffer.h" // version of network protocol code #define NETWORK_VERSION (1) class network_command_t; class gameinfo_t; class karte_t; void network_close_socket( SOCKET sock ); void network_set_socket_nodelay( SOCKET sock ); // open a socket or give a decent error message SOCKET network_open_address(char const* cp, char const*& err); // if successful, starts a server on this port bool network_init_server( int port, const vector_tpl &listen_addrs ); /** * returns pointer to command or NULL */ network_command_t* network_get_received_command(); /** * do appropriate action for network games: * - server: accept connection to a new client * - all: receive commands and puts them to the received_command_queue * * @param timeout in milliseconds * @return pointer to first received command * more commands can be obtained by call to network_get_received_command */ network_command_t* network_check_activity(int timeout); /** * send data to dest: * if timeout_ms is positive: * try to send all data, return true if all data are sent otherwise false * if timeout_ms is not positive: * try to send as much as possible but return after one send attempt * return true if connection is still open and sending can be continued later * * @param buf the data * @param size length of buffer and number of bytes to be sent * @param[out] count number of bytes actually sent * @param timeout_ms time-out in milliseconds */ bool network_send_data( SOCKET dest, const char *buf, const uint16 size, uint16 &count, const int timeout_ms ); /** * receive data from sender * @param dest the destination buffer * @param len length of destination buffer and number of bytes to be received * @param received number of received bytes is returned here * @param timeout_ms time-out in milliseconds * @return true if connection is still valid, false if an error occurs and connection needs to be closed */ bool network_receive_data( SOCKET sender, void *dest, const uint16 len, uint16 &received, const int timeout_ms ); void network_process_send_queues(int timeout); // true, if I can write on the server connection bool network_check_server_connection(); /** * send command to all clients (even us). * if @p player_nr is valid, then send only to clients with this player unlocked * @note nwc is invalid after the call */ void network_send_all(network_command_t* nwc, bool exclude_us, uint8 player_nr = PLAYER_UNOWNED); // send data to server only // nwc is invalid after the call void network_send_server(network_command_t* nwc ); void network_reset_server(); void network_core_shutdown(); // get & set our id on the server uint32 network_get_client_id(); void network_set_client_id(uint32 id); bool get_external_IP( cbuffer_t &myIPaddr, cbuffer_t &alt_IP ); // trys to open port on router (if there) and get external IP bool prepare_for_server( char *externalIPAddress, char *alter_IP, int port ); // removes the redirect (or do nothing) void remove_port_forwarding( int port ); #endif simutrans-124.3/src/simutrans/network/network_address.cc000066400000000000000000000021171474050137200235660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_address.h" #include "network_packet.h" #include #include net_address_t::net_address_t(uint32 ip_, uint32 mask_) : ip(ip_), mask(mask_) { ipstr[0] = '\0'; init_ipstr(); } net_address_t::net_address_t(const char *text) { ipstr[0] = '\0'; uint32 offset = 0; ip = 0; mask = 0; for(sint8 j=24; j>=0; j-=8) { uint32 n = atoi(text); ip |= (n & 0xff) << j; mask |= 0xff << j; text = strchr(text+offset, '.'); if (text) { text++; } else { break; } } init_ipstr(); } void net_address_t::init_ipstr() { if ( ipstr[0] == '\0' ) { sprintf( ipstr, "%i.%i.%i.%i", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255 ); } } const char* net_address_t::get_str () const { return ipstr; } void address_list_t::rdwr(packet_t *packet) { uint32 count = get_count(); packet->rdwr_long(count); for(uint32 i=0; iis_loading()) { append(net_address_t()); } (*this)[i].rdwr(packet); } } simutrans-124.3/src/simutrans/network/network_address.h000066400000000000000000000025101474050137200234250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_ADDRESS_H #define NETWORK_NETWORK_ADDRESS_H #include "../simtypes.h" #include "../tpl/vector_tpl.h" class packet_t; class net_address_t { public: uint32 ip; uint32 mask; private: char ipstr[16]; /** * Generate human readable representation of this IP address */ void init_ipstr(); public: net_address_t(uint32 ip_=0, uint32 mask_ = 0xffffffff); net_address_t(const char *); bool matches(const net_address_t &other) const { return (other.ip & mask)==(ip & mask); } template void rdwr(F *packet) { packet->rdwr_long(ip); packet->rdwr_long(mask); if (packet->is_loading()) { ipstr[0] = '\0'; init_ipstr(); } } /** * Return human readable representation of this IP address */ const char* get_str () const; bool operator==(const net_address_t& other) const { return ip==other.ip && mask == other.mask; } uint32 get_ip() const { return ip; } }; class address_list_t : public vector_tpl { public: address_list_t() : vector_tpl(10) {} bool contains(const net_address_t &other) { for(net_address_t const& i : *this) { if (i.matches(other)) { return true; } } return false; } void rdwr(packet_t *packet); }; #endif simutrans-124.3/src/simutrans/network/network_cmd.cc000066400000000000000000000065221474050137200227100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_cmd.h" #include "network.h" #include "network_packet.h" #include "network_socket_list.h" #include // needed by world to kick clients if needed SOCKET network_command_t::get_sender() { return packet->get_sender(); } network_command_t::network_command_t(uint16 id_) { packet = new packet_t(); id = id_; our_client_id = (uint32)network_get_client_id(); ready = false; } // default constructor network_command_t::network_command_t() : packet(NULL), id(0), our_client_id(0), ready(false) {} bool network_command_t::receive(packet_t *p) { ready = true; delete packet; packet = p; id = p->get_id(); rdwr(); return (!packet->has_failed()); } network_command_t::~network_command_t() { delete packet; packet = NULL; } void network_command_t::rdwr() { if (packet->is_saving()) { packet->set_id(id); ready = true; } packet->rdwr_long(our_client_id); dbg->message("network_command_t::rdwr", "%s packet_id=%s, client_id=%u", packet->is_saving() ? "write" : "read", get_name(), our_client_id); } void network_command_t::prepare_to_send() { // saves the data to the packet if(!ready) { rdwr(); } } bool network_command_t::send(SOCKET s) { prepare_to_send(); packet->send(s, true); bool ok = packet->is_ready(); if (!ok) { dbg->warning("network_command_t::send", "Sending %s to [%d] failed", get_name(), s); } return ok; } packet_t* network_command_t::copy_packet() const { if (packet) { return new packet_t(*packet); } else { return NULL; } } void nwc_auth_player_t::rdwr() { network_command_t::rdwr(); for(uint32 i=0; i<20; i++) { packet->rdwr_byte( hash[i] ); } packet->rdwr_byte( player_nr ); packet->rdwr_short(player_unlocked); } nwc_service_t::~nwc_service_t() { delete socket_info; delete address_list; free(text); } extern address_list_t blacklist; void nwc_service_t::rdwr() { network_command_t::rdwr(); packet->rdwr_long(flag); packet->rdwr_long(number); switch(flag) { case SRVC_LOGIN_ADMIN: case SRVC_BAN_IP: case SRVC_UNBAN_IP: case SRVC_ADMIN_MSG: case SRVC_GET_COMPANY_LIST: case SRVC_GET_COMPANY_INFO: packet->rdwr_str(text); break; case SRVC_GET_CLIENT_LIST: if (packet->is_loading()) { socket_info = new vector_tpl(10); // read the list socket_list_t::rdwr(packet, socket_info); } else { // write the socket list socket_list_t::rdwr(packet); } break; case SRVC_GET_BLACK_LIST: if (packet->is_loading()) { address_list = new address_list_t(); address_list->rdwr(packet); } else { blacklist.rdwr(packet); } break; default: ; } } const char *network_command_t::id_to_string(uint16 id) { #define CASE_TO_STRING(c) case c: return #c switch (id) { CASE_TO_STRING(NWC_INVALID); CASE_TO_STRING(NWC_GAMEINFO); CASE_TO_STRING(NWC_NICK); CASE_TO_STRING(NWC_CHAT); CASE_TO_STRING(NWC_JOIN); CASE_TO_STRING(NWC_SYNC); CASE_TO_STRING(NWC_GAME); CASE_TO_STRING(NWC_READY); CASE_TO_STRING(NWC_TOOL); CASE_TO_STRING(NWC_CHECK); CASE_TO_STRING(NWC_PAKSETINFO); CASE_TO_STRING(NWC_SERVICE); CASE_TO_STRING(NWC_AUTH_PLAYER); CASE_TO_STRING(NWC_CHG_PLAYER); CASE_TO_STRING(NWC_SCENARIO); CASE_TO_STRING(NWC_SCENARIO_RULES); CASE_TO_STRING(NWC_STEP); } return ""; } simutrans-124.3/src/simutrans/network/network_cmd.h000066400000000000000000000070171474050137200225520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_CMD_H #define NETWORK_NETWORK_CMD_H #include "../simtypes.h" #include "../tpl/slist_tpl.h" #include "../tpl/vector_tpl.h" #include "network.h" #include "../utils/sha1_hash.h" class address_list_t; class karte_t; class packet_t; class socket_info_t; // actual commands enum { NWC_INVALID = 0, NWC_GAMEINFO, NWC_NICK, NWC_CHAT, NWC_JOIN, NWC_SYNC, NWC_GAME, NWC_READY, NWC_TOOL, NWC_CHECK, NWC_PAKSETINFO, NWC_SERVICE, NWC_AUTH_PLAYER, NWC_CHG_PLAYER, NWC_SCENARIO, NWC_SCENARIO_RULES, NWC_STEP, NWC_COUNT }; class network_command_t { protected: packet_t *packet; // always send: uint16 id; uint32 our_client_id; // ready for sending bool ready; public: network_command_t(uint16 id); network_command_t(); virtual ~network_command_t(); // receive: calls rdwr from packet // return true on success bool receive(packet_t *p); // calls rdwr if packet is empty void prepare_to_send(); /** * sends to a client * sends complete command-packet * @return whether send was successful */ bool send(SOCKET s); // write our data to the packet virtual void rdwr(); // executes the command // (see network_world_command_t::execute() ) // if returns true this can be deleted afterwards virtual bool execute(karte_t *) { return true;} uint16 get_id() { return id;} const char *get_name() const { return id_to_string(id); } SOCKET get_sender(); packet_t *get_packet() const { return packet; } /** * returns ptr to a copy of the packet */ packet_t *copy_packet() const; // creates an instance: // gets the nwc-id from the packet, and reads its data static network_command_t* read_from_packet(packet_t *p); static const char *id_to_string(uint16 id); }; /** * base class for any service commands */ class nwc_service_t : public network_command_t { public: uint32 flag; enum { SRVC_LOGIN_ADMIN = 0, SRVC_ANNOUNCE_SERVER = 1, SRVC_GET_CLIENT_LIST = 2, SRVC_KICK_CLIENT = 3, SRVC_BAN_CLIENT = 4, SRVC_GET_BLACK_LIST = 5, SRVC_BAN_IP = 6, SRVC_UNBAN_IP = 7, SRVC_ADMIN_MSG = 8, SRVC_SHUTDOWN = 9, SRVC_FORCE_SYNC = 10, SRVC_GET_COMPANY_LIST = 11, SRVC_GET_COMPANY_INFO = 12, SRVC_UNLOCK_COMPANY = 13, SRVC_REMOVE_COMPANY = 14, SRVC_LOCK_COMPANY = 15, SRVC_MAX }; uint32 number; char *text; vector_tpl *socket_info; address_list_t *address_list; nwc_service_t() : network_command_t(NWC_SERVICE), text(NULL), socket_info(NULL), address_list(NULL) { } ~nwc_service_t(); #ifndef NETTOOL bool execute(karte_t *) OVERRIDE; #endif void rdwr() OVERRIDE; }; /** * nwc_auth_player_t * @from-client: client sends password hash to unlock player / set player password * server sends nwc_auth_player_t to sender * @from-server: * information whether players are locked / unlocked */ class nwc_auth_player_t : public network_command_t { public: nwc_auth_player_t() : network_command_t(NWC_AUTH_PLAYER), hash(), player_unlocked(0), player_nr(255) { } nwc_auth_player_t(uint8 nr, const pwd_hash_t& hash_) : network_command_t(NWC_AUTH_PLAYER), hash(hash_), player_unlocked(0), player_nr(nr) { } #ifndef NETTOOL bool execute(karte_t *) OVERRIDE; #endif void rdwr() OVERRIDE; pwd_hash_t hash; uint16 player_unlocked; uint8 player_nr; /** * sets unlocked flags for playing at server */ static void init_player_lock_server(karte_t *); }; #endif simutrans-124.3/src/simutrans/network/network_cmd_ingame.cc000066400000000000000000001316001474050137200242240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_cmd_ingame.h" #include "network.h" #include "network_file_transfer.h" #include "network_packet.h" #include "network_socket_list.h" #include "network_cmp_pakset.h" #include "network_cmd_scenario.h" #include "../dataobj/loadsave.h" #include "../dataobj/gameinfo.h" #include "../dataobj/scenario.h" #include "../tool/simmenu.h" #include "../simversion.h" #include "../gui/simwin.h" #include "../simmesg.h" #include "../sys/simsys.h" #include "../dataobj/environment.h" #include "../player/simplay.h" #include "../gui/player_frame.h" #include "../utils/simrandom.h" #include "../utils/cbuffer.h" #include "../utils/csv.h" #include "../display/viewport.h" #include "../script/script.h" // callback for calls to tools network_command_t* network_command_t::read_from_packet(packet_t *p) { // check data if (p==NULL || p->has_failed() || !p->check_version()) { delete p; dbg->warning("network_command_t::read_from_packet", "error in packet"); return NULL; } network_command_t* nwc = NULL; switch (p->get_id()) { case NWC_GAMEINFO: nwc = new nwc_gameinfo_t(); break; case NWC_NICK: nwc = new nwc_nick_t(); break; case NWC_CHAT: nwc = new nwc_chat_t(); break; case NWC_JOIN: nwc = new nwc_join_t(); break; case NWC_SYNC: nwc = new nwc_sync_t(); break; case NWC_GAME: nwc = new nwc_game_t(); break; case NWC_READY: nwc = new nwc_ready_t(); break; case NWC_TOOL: nwc = new nwc_tool_t(); break; case NWC_CHECK: nwc = new nwc_check_t(); break; case NWC_PAKSETINFO: nwc = new nwc_pakset_info_t(); break; case NWC_SERVICE: nwc = new nwc_service_t(); break; case NWC_AUTH_PLAYER: nwc = new nwc_auth_player_t(); break; case NWC_CHG_PLAYER: nwc = new nwc_chg_player_t(); break; case NWC_SCENARIO: nwc = new nwc_scenario_t(); break; case NWC_SCENARIO_RULES: nwc = new nwc_scenario_rules_t(); break; case NWC_STEP: nwc = new nwc_step_t(); break; default: dbg->warning("network_command_t::read_from_socket", "received unknown packet id %d", p->get_id()); } if (nwc) { if (!nwc->receive(p) || p->has_failed()) { dbg->warning("network_command_t::read_from_packet", "error while reading cmd from packet"); delete nwc; nwc = NULL; } } return nwc; } void nwc_gameinfo_t::rdwr() { network_command_t::rdwr(); packet->rdwr_long(len); } // will send the gameinfo to the client bool nwc_gameinfo_t::execute(karte_t *welt) { if (env_t::server) { DBG_MESSAGE("nwc_gameinfo_t::execute", ""); // TODO: check whether we can send a file nwc_gameinfo_t nwgi; // init the rest of the packet SOCKET s = packet->get_sender(); loadsave_t fd; if( fd.wr_open( "serverinfo.sve", loadsave_t::xml_bzip2, 0, "info", SERVER_SAVEGAME_VER_NR ) == loadsave_t::FILE_STATUS_OK ) { gameinfo_t gi(welt); gi.rdwr( &fd ); fd.close(); // get gameinfo size FILE *fh = dr_fopen( "serverinfo.sve", "rb" ); fseek( fh, 0, SEEK_END ); nwgi.len = ftell( fh ); rewind( fh ); nwgi.rdwr(); if ( nwgi.send( s ) ) { // send gameinfo while( !feof(fh) ) { char buffer[1024]; int bytes_read = (int)fread( buffer, 1, sizeof(buffer), fh ); uint16 dummy; if( !network_send_data(s,buffer,bytes_read,dummy,250)) { dbg->warning( "nwc_gameinfo_t::execute", "Client closed connection during transfer" ); break; } } } else { dbg->warning( "nwc_gameinfo_t::execute", "send of NWC_GAMEINFO failed" ); } fclose( fh ); dr_remove("serverinfo.sve"); } socket_list_t::remove_client( s ); } else { len = 0; } return true; } void nwc_nick_t::rdwr() { network_command_t::rdwr(); packet->rdwr_str(nickname); if (packet->is_loading() && env_t::server && id == NWC_NICK) { const SOCKET sock = packet->get_sender(); const socket_info_t &client = socket_list_t::get_client(socket_list_t::get_client_id(sock)); if (client.state != socket_info_t::playing) { packet->failed(); } } } static bool nick_already_taken(const plainstring& nick,uint32 client_id) { // check for same nick for (uint32 i = 0; i < socket_list_t::get_count(); i++) { socket_info_t& info = socket_list_t::get_client(i); if ((info.state == socket_info_t::playing || i == 0) && i != client_id && nick == info.nickname.c_str()) { return true; } } return false; } /** * if server: checks whether nickname is taken and generates default nick */ bool nwc_nick_t::execute(karte_t *welt) { if(env_t::server) { uint32 client_id = socket_list_t::get_client_id(packet->get_sender()); if(nickname==NULL || nickname=="Admin" || nick_already_taken(nickname, client_id)) { goto generate_default_nick; } if (id == NWC_NICK) { // do not call this tool if called by nwc_join_t::execute nwc_nick_t::server_tools(welt, client_id, CHANGE_NICK, nickname); } return true; generate_default_nick: // nick exists already // generate default nick from city names const vector_tpl& city_names = translator::get_city_name_list(); do { nickname = city_names[sim_async_rand(city_names.get_count())]; } while (nick_already_taken(nickname, client_id)); return true; } else { env_t::nickname = nickname!=NULL ? nickname.c_str() : "(null)"; } return true; } void nwc_nick_t::server_tools(karte_t *welt, uint32 client_id, uint8 what, const char* nick) { if (!socket_list_t::is_valid_client_id(client_id)) { return; } socket_info_t &info = socket_list_t::get_client(client_id); cbuffer_t buf; buf.printf("%d,", chat_message_t::DO_NOT_SAVE_MSG); switch(what) { case WELCOME: { // welcome message buf.printf(translator::translate("Welcome, %s!", welt->get_settings().get_name_language_id()), info.nickname.c_str()); // Log chat message - please don't change order of fields CSV_t csv; csv.add_field( "connect" ); csv.add_field( client_id ); csv.add_field( info.address.get_str() ); csv.add_field( info.nickname.c_str() ); DBG_MESSAGE( "__ChatLog__", "%s", csv.get_str() ); break; } case CHANGE_NICK: { if (nick==NULL || info.nickname == nick) { return; } // change nickname buf.printf(translator::translate("%s now known as %s.", welt->get_settings().get_name_language_id()), info.nickname.c_str(), nick); welt->get_chat_message()->rename_client(info.nickname, nick); // record nickname change for(uint8 i=0; i 0) { // send new nickname back to client nwc_nick_t nwc(nick); nwc.send(info.socket); } else { // human at server env_t::nickname = nick; } break; } case FAREWELL: { buf.printf(translator::translate("%s has left.", welt->get_settings().get_name_language_id()), info.nickname.c_str()); // Log chat message - please don't change order of fields CSV_t csv; csv.add_field( "disconnect" ); csv.add_field( client_id ); csv.add_field( info.address.get_str() ); csv.add_field( info.nickname.c_str() ); DBG_MESSAGE( "__ChatLog__", "%s", csv.get_str() ); break; } default: return; } tool_t *tmp_tool = create_tool( TOOL_ADD_MESSAGE | GENERAL_TOOL ); tmp_tool->set_default_param( buf ); // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(NULL, tmp_tool, koord3d::invalid, 0, welt->get_map_counter(), false); network_send_server(nwc); // since init always returns false, it is safe to delete immediately delete tmp_tool; // now tell all clients the new nicks nwc_chat_t* nwchat = new nwc_chat_t(socket_list_t::get_all_nicks(), PLAYER_UNOWNED, -2, NULL, NULL, koord::invalid); network_send_server(nwchat); } void nwc_chat_t::rdwr() { network_command_t::rdwr(); packet->rdwr_str( message ); packet->rdwr_byte( player_nr ); packet->rdwr_str( clientname ); packet->rdwr_str( destination ); packet->rdwr_byte( channel_nr ); packet->rdwr_short(pos.x); packet->rdwr_short(pos.y); if (packet->is_loading() && env_t::server) { const SOCKET sock = packet->get_sender(); const socket_info_t &client = socket_list_t::get_client(socket_list_t::get_client_id(sock)); if (client.state != socket_info_t::playing) { packet->failed(); } } DBG_MESSAGE("nwc_chat_t::rdwr", "rdwr message=%s plnr=%d clientname=%s destination=%s", message.c_str(), player_nr, clientname.c_str(), destination.c_str()); } void nwc_chat_t::add_message(karte_t* welt) const { cbuffer_t buf; // Output which will be printed to chat window FLAGGED_PIXVAL color = player_nr < PLAYER_UNOWNED ? PLAYER_FLAG | player_nr : color_idx_to_rgb(COL_WHITE); uint16 flag = message_t::chat; if ( destination == NULL ) { if ( player_nr < PLAYER_UNOWNED && welt->get_player(player_nr)) { buf.printf( "%s <%s>: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), message.c_str() ); } else { buf.printf( "%s: %s", clientname.c_str(), message.c_str() ); } } else { // Whisper, do not store message in savegame flag |= message_t::PLAYER_MSG; if ( player_nr < PLAYER_UNOWNED && welt->get_player(player_nr)) { buf.printf( "%s <%s> --> %s: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), destination.c_str(), message.c_str() ); } else { buf.printf( "%s --> %s: %s", clientname.c_str(), destination.c_str(), message.c_str() ); } } welt->get_message()->add_message( buf.get_str(), koord3d::invalid, flag, color, IMG_EMPTY ); } bool nwc_chat_t::execute (karte_t* welt) { if ( message == NULL ) { dbg->warning("nwc_chat_t::execute", "null message"); return true; } // Relay message to all listening clients if ( env_t::server ) { uint32 client_id = socket_list_t::get_client_id( packet->get_sender() ); DBG_MESSAGE("nwc_chat_t::execute", "server, client id: %d", client_id); // Clients can only send messages as companies they have unlocked if ( player_nr < PLAYER_UNOWNED && !socket_list_t::get_client( client_id ).is_player_unlocked( player_nr ) ) { dbg->warning("nwc_chat_t::execute", "attempt to send message as locked company by client %d, redirecting to PLAYER_UNOWNED", client_id); player_nr = PLAYER_UNOWNED; } // Otherwise forward message as appropriate socket_info_t &info = socket_list_t::get_client( client_id ); nwc_chat_t* nwchat = new nwc_chat_t( message, player_nr, channel_nr, info.nickname.c_str(), destination, pos ); if ( destination == NULL || destination=="") { // Do not send messages to ourself (server) network_send_all( nwchat, true ); // Act on message (for display of messages on server, and to keep record of messages for new clients joining) welt->get_chat_message()->add_chat_message(message.c_str(), channel_nr, player_nr, info.nickname, destination, pos); // Log chat message - please don't change order of fields CSV_t csv; csv.add_field( "chat" ); csv.add_field( client_id ); csv.add_field( info.address.get_str() ); csv.add_field( info.nickname.c_str() ); csv.add_field( player_nr ); csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" ); csv.add_field( message.c_str() ); DBG_MESSAGE( "__ChatLog__", "%s", csv.get_str() ); } else { // Send to a specific client // Look up a client with a matching name, if none matches // send a message back saying that client doesn't exist // is it for us => no need to send further away if (destination == env_t::nickname.c_str()) { welt->get_chat_message()->add_chat_message(message.c_str(), channel_nr, player_nr, info.nickname, destination, pos); } // Check if destination nick exists for ( uint32 i = 0; i < socket_list_t::get_count(); i++ ) { socket_info_t& dest_info = socket_list_t::get_client(i); if ( (dest_info.state == socket_info_t::playing || i == 0 ) && i != client_id && destination == dest_info.nickname.c_str() ) { nwchat->send( dest_info.socket ); } } // TODO also send a copy back to sending client for logging delete nwchat; // Log chat message - please don't change order of fields CSV_t csv; csv.add_field( "private" ); csv.add_field( client_id ); csv.add_field( info.address.get_str() ); csv.add_field( info.nickname.c_str() ); csv.add_field( player_nr ); csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" ); csv.add_field( destination.c_str() ); csv.add_field( message.c_str() ); DBG_MESSAGE( "__ChatLog__", "%s", csv.get_str() ); } } else { welt->get_chat_message()->add_chat_message(message.c_str(), channel_nr, player_nr, clientname, destination, pos); } return true; } SOCKET nwc_join_t::pending_join_client = INVALID_SOCKET; void nwc_join_t::rdwr() { nwc_nick_t::rdwr(); packet->rdwr_long(client_id); packet->rdwr_byte(answer); } bool nwc_join_t::execute(karte_t *welt) { if(env_t::server) { DBG_MESSAGE("nwc_join_t::execute", ""); // TODO: check whether we can send a file nwc_join_t nwj; nwj.client_id = socket_list_t::get_client_id(packet->get_sender()); //save nickname if (socket_list_t::is_valid_client_id(nwj.client_id)) { // check nickname nwc_nick_t::execute(welt); nwj.nickname = nickname; socket_list_t::get_client(nwj.client_id).nickname = nickname; } // no other joining process active? nwj.answer = socket_list_t::get_client(nwj.client_id).is_active() && pending_join_client == INVALID_SOCKET ? 1 : 0; DBG_MESSAGE( "nwc_join_t::execute", "client_id=%i active=%i pending_join_client=%i active=%d", socket_list_t::get_client_id(packet->get_sender()), socket_list_t::get_client(nwj.client_id).is_active(), pending_join_client, nwj.answer ); nwj.rdwr(); if( nwj.send( packet->get_sender() ) ) { if( nwj.answer==1 ) { // now send sync command const uint32 new_map_counter = welt->generate_new_map_counter(); // since network_send_all() does not include non-playing clients -> send sync command separately to the joining client nwc_sync_t nw_sync(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter); nw_sync.rdwr(); if( nw_sync.send( packet->get_sender() ) ) { // now send sync command to the server and the remaining clients nwc_sync_t *nws = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter); network_send_all(nws, false); pending_join_client = packet->get_sender(); DBG_MESSAGE( "nwc_join_t::execute", "pending_join_client now %i", pending_join_client); // unpause world if (welt->is_paused()) { welt->set_pause(false); } } else { dbg->warning("nwc_join_t::execute", "send of NWC_SYNC to the joining client failed"); } } } else { dbg->warning( "nwc_join_t::execute", "send of NWC_JOIN failed" ); } } return true; } /** * saves the history of map counters * the current one is at index zero, the older ones behind */ #define MAX_MAP_COUNTERS (7) vector_tpl nwc_ready_t::all_map_counters(MAX_MAP_COUNTERS); void nwc_ready_t::append_map_counter(uint32 map_counter_) { if (all_map_counters.get_count() == MAX_MAP_COUNTERS) { all_map_counters.pop_back(); } all_map_counters.insert_at(0, map_counter_); } void nwc_ready_t::clear_map_counters() { all_map_counters.clear(); } bool nwc_ready_t::execute(karte_t *welt) { if( env_t::server ) { // compare checklist if( welt->is_checklist_available(sync_step) && checklist!=welt->get_checklist_at(sync_step) ) { // client has gone out of sync socket_list_t::remove_client( get_sender() ); cbuffer_t buf; welt->get_checklist_at(sync_step).print(buf, "server"); checklist.print(buf, "client"); dbg->warning("nwc_ready_t::execute", "disconnect client due to checklist mismatch : sync_step=%u %s", sync_step, buf.get_str()); return true; } // check the validity of the map counter for(uint32 const i : all_map_counters) { if (i == map_counter) { // unpause the sender by sending nwc_ready_t back nwc_ready_t nwc(sync_step, map_counter, checklist); if( !nwc.send( get_sender()) ) { dbg->warning("nwc_ready_t::execute", "send of NWC_READY failed"); } return true; } } // no matching map counter -> disconnect client socket_list_t::remove_client( get_sender() ); dbg->warning("nwc_ready_t::execute", "disconnect client id=%u due to invalid map counter", our_client_id); } else { dbg->warning("nwc_ready_t::execute", "set sync_step=%d where map_counter=%d", sync_step, map_counter); if( map_counter==welt->get_map_counter() ) { welt->network_game_set_pause(false, sync_step); welt->set_checklist_at(sync_step, checklist); } else { welt->network_disconnect(); dbg->warning("nwc_ready_t::execute", "disconnecting due to map counter mismatch"); } } return true; } void nwc_ready_t::rdwr() { network_command_t::rdwr(); packet->rdwr_long(sync_step); packet->rdwr_long(map_counter); checklist.rdwr(packet); } void nwc_game_t::rdwr() { network_command_t::rdwr(); packet->rdwr_long(len); if (packet->is_loading() && env_t::server) { packet->failed(); } } bool nwc_auth_player_t::execute(karte_t *welt) { DBG_MESSAGE("nwc_auth_player_t::execute","plnr = %d unlock = %d our_client_id = %d", player_nr, player_unlocked, our_client_id); if( env_t::server && !(our_client_id==0 && player_nr==255)) { // sent to server, and not sent to player playing on server if (socket_list_t::is_valid_client_id(our_client_id)) { // player activated for this client? or admin connection via nettool? socket_info_t &info = socket_list_t::get_client(our_client_id); if (info.is_player_unlocked(player_nr) || info.state == socket_info_t::admin) { DBG_MESSAGE("nwc_auth_player_t::execute","set pwd for plnr = %d", player_nr); // change password if (welt->get_player(player_nr)->access_password_hash() != hash) { welt->get_player(player_nr)->access_password_hash() = hash; // unlock all clients if new password is empty // otherwise lock all socket_list_t::unlock_player_all(player_nr, hash.empty(), our_client_id); } } else if (player_nr < PLAYER_UNOWNED) { // players with public service player access always pass password checks if( info.is_player_unlocked(1) ) { info.unlock_player(player_nr); } // check password else if (welt->get_player(player_nr)->access_password_hash() == hash) { DBG_MESSAGE("nwc_auth_player_t::execute","unlock plnr = %d at our_client_id = %d", player_nr, our_client_id); info.unlock_player(player_nr); } } // report back to client who sent the command if (our_client_id == 0) { // unlock player on the server and clear unlock_pending flag welt->get_player(player_nr)->unlock(info.is_player_unlocked(player_nr), false); } else { // send unlock-info to player on the client (to clear unlock_pending flag) nwc_auth_player_t nwc; nwc.player_unlocked = info.player_unlocked; nwc.send( get_sender()); } } } else { for(uint8 i=0; iget_player(i)) { player->unlock( player_unlocked & (1<update_data(); } return true; } void nwc_auth_player_t::init_player_lock_server(karte_t *welt) { uint16 player_unlocked = 0; for(uint8 i=0; iget_player(i); if (player == NULL || player->access_password_hash() == welt->get_player_password_hash(i) ) { player_unlocked |= 1<unlock( player_unlocked & (1<sync_step = sync_step; this->map_counter = map_counter; } void network_world_command_t::rdwr() { network_command_t::rdwr(); packet->rdwr_long(sync_step); packet->rdwr_long(map_counter); } bool network_world_command_t::execute(karte_t *welt) { DBG_MESSAGE("network_world_command_t::execute","do_command %d at sync_step %d world now at %d", get_id(), get_sync_step(), welt->get_sync_steps()); // want to execute something in the past? if (get_sync_step() < welt->get_sync_steps()) { if (!ignore_old_events()) { dbg->warning("network_world_command_t::execute", "wanted to execute(%d) in the past", get_id()); welt->network_disconnect(); } return true; // to delete cmd } if (map_counter != welt->get_map_counter()) { // command from another world // could happen if we are behind and still have to execute the next sync command dbg->warning("network_world_command_t::execute", "wanted to execute(%d) from another world (mpc=%d)", get_id(), map_counter); if (env_t::server) { return true; // to delete cmd } // map_counter has to be checked before calling do_command() } welt->command_queue_append(this); return false; } void nwc_sync_t::rdwr() { network_world_command_t::rdwr(); packet->rdwr_long(client_id); packet->rdwr_long(new_map_counter); if (packet->is_loading() && env_t::server) { packet->failed(); } } // save, load, pause, if server send game void nwc_sync_t::do_command(karte_t *welt) { dbg->warning("nwc_sync_t::do_command", "sync_steps %d", get_sync_step()); // save screen coordinates & offsets const koord ij = welt->get_viewport()->get_world_position(); const sint16 xoff = welt->get_viewport()->get_x_off(); const sint16 yoff = welt->get_viewport()->get_y_off(); // save active player const uint8 active_player = welt->get_active_player_nr(); // save lock state uint16 player_unlocked = 0; for(uint8 i=0; iget_player(i)) { if (!player->is_locked()) { player_unlocked |= 1<save( fn, true, SERVER_SAVEGAME_VER_NR, false ); uint32 old_sync_steps = welt->get_sync_steps(); welt->load( fn ); welt->type_of_generation = karte_t::CLIENT_WORLD; env_t::restore_UI = old_restore_UI; // pause clients, restore steps welt->network_game_set_pause( true, old_sync_steps); // apply new map counter welt->set_map_counter(new_map_counter); // tell server we are ready network_command_t *nwc = new nwc_ready_t( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) ); network_send_server(nwc); } else { char fn[256]; // first save password hashes sprintf( fn, "server%d-pwdhash.sve", env_t::server ); loadsave_t file; if( file.wr_open(fn, loadsave_t::zipped, 1, "hashes", SAVEGAME_VER_NR ) == loadsave_t::FILE_STATUS_OK ) { welt->rdwr_player_password_hashes( &file ); file.close(); } // remove passwords before transfer on the server and set default client mask // they will be restored in karte_t::laden uint16 unlocked_players = 0; for( int i=0; iget_player(i); if( player==NULL || player->access_password_hash().empty() ) { unlocked_players |= (1<access_password_hash().clear(); } } // save game sprintf( fn, "server%d-network.sve", env_t::server ); bool old_restore_UI = env_t::restore_UI; env_t::restore_UI = true; welt->save( fn, false, SERVER_SAVEGAME_VER_NR, false ); // ok, now sending game // this sends nwc_game_t const char *err = network_send_file( socket_list_t::get_socket(client_id), fn ); if (err) { dbg->warning("nwc_sync_t::do_command","send game failed with: %s", err); } uint32 old_sync_steps = welt->get_sync_steps(); welt->load( fn ); welt->type_of_generation = karte_t::LOADED_WORLD; env_t::restore_UI = old_restore_UI; // restore steps welt->network_game_set_pause( false, old_sync_steps); // apply new map counter welt->set_map_counter(new_map_counter); // unpause the client that received the game // we do not want to wait for him (maybe loading failed due to pakset-errors) SOCKET sock = socket_list_t::get_socket(client_id); if( sock != INVALID_SOCKET ) { nwc_ready_t nwc( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) ); if (nwc.send(sock)) { socket_list_t::change_state(client_id, socket_info_t::playing); if (socket_list_t::is_valid_client_id(client_id)) { socket_list_t::get_client(client_id).player_unlocked = unlocked_players; // send information about locked state nwc_auth_player_t nwc; nwc.player_unlocked = unlocked_players; nwc.send(sock); // welcome message nwc_nick_t::server_tools(welt, client_id, nwc_nick_t::WELCOME, NULL); } else { dbg->warning("nwc_sync_t::do_command(karte_t *welt)", "client_id %d became invalid during sync!", client_id); } } else { dbg->warning( "nwc_sync_t::do_command", "send of NWC_READY failed" ); } } nwc_join_t::pending_join_client = INVALID_SOCKET; } // restore screen coordinates & offsets welt->get_viewport()->change_world_position(ij, xoff, yoff); welt->switch_active_player(active_player,true); // restore lock state for(uint8 i=0; iget_player(i)) { player->unlock(player_unlocked & (1<rdwr_long(server_sync_step); if (packet->is_loading() && env_t::server) { // server does not receive nwc_check_t-commands packet->failed(); } } void network_broadcast_world_command_t::rdwr() { network_world_command_t::rdwr(); packet->rdwr_bool(exec); if (packet->is_loading() && env_t::server && exec) { // server does not receive exec-commands packet->failed(); } } bool network_broadcast_world_command_t::execute(karte_t *welt) { if (exec) { // append to command queue return network_world_command_t::execute(welt); } else if (env_t::server) { // check map_counter if (map_counter != welt->get_map_counter()) { // command from another world dbg->warning("network_broadcast_world_command_t::execute", "wanted to execute(%d) from another world", get_id()); return true; } // clone network_broadcast_world_command_t *nwc = clone(welt); if (nwc == NULL) { return true; } // next call to execute will put it in command queue nwc->exec = true; nwc->sync_step = welt->get_sync_steps() + 1; // broadcast network_send_all(nwc, false); // return true to delete this command only if clone() returned something new return true; } else { dbg->warning("network_broadcast_world_command_t::execute", "should not reach here!"); } return true; } nwc_chg_player_t::~nwc_chg_player_t() { delete pending_company_creator; } void nwc_chg_player_t::rdwr() { network_broadcast_world_command_t::rdwr(); packet->rdwr_byte(cmd); packet->rdwr_byte(player_nr); packet->rdwr_short(param); packet->rdwr_bool(scripted_call); } network_broadcast_world_command_t* nwc_chg_player_t::clone(karte_t *welt) { if (!socket_list_t::is_valid_client_id(our_client_id)) { return NULL; } socket_info_t const& info = socket_list_t::get_client(our_client_id); // scripts only run on server if (socket_list_t::get_client_id(packet->get_sender()) != 0) { // not sent by server, clear flag scripted_call = false; // only server can start scripted AI for now if (cmd == karte_t::new_player && param == player_t::AI_SCRIPTED) { return NULL; } } if (!welt->change_player_tool(cmd, player_nr, param, info.is_player_unlocked(1) || scripted_call, false)) { return NULL; } // now create the new command nwc_chg_player_t* nwc = new nwc_chg_player_t(get_sync_step(), get_map_counter(), cmd, player_nr, param); // .. and store company_creator if necessary if (cmd == karte_t::new_player) { nwc->pending_company_creator = new connection_info_t(info); dbg->warning("nwc_chg_player_t::clone", "pending_company_creator for %d is set to %s/%s", player_nr, info.address.get_str(), info.nickname.c_str()); } return nwc; } connection_info_t* nwc_chg_player_t::company_creator[PLAYER_UNOWNED] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; slist_tpl nwc_chg_player_t::company_active_clients[PLAYER_UNOWNED]; void nwc_chg_player_t::company_removed(uint8 player_nr) { // delete history delete company_creator[player_nr]; company_creator[player_nr] = NULL; company_active_clients[player_nr].clear(); } void nwc_chg_player_t::do_command(karte_t *welt) { welt->change_player_tool(cmd, player_nr, param, true, true); // store IP of client who created this company if (env_t::server && cmd == karte_t::new_player && player_nr < lengthof(company_creator)) { company_creator[player_nr] = pending_company_creator; if (pending_company_creator) { dbg->warning("nwc_chg_player_t::do_command", "company_creator for %d is set to %s/%s", player_nr, pending_company_creator->address.get_str(), pending_company_creator->nickname.c_str()); } pending_company_creator = NULL; // to prevent deletion in ~nwc_chg_player_t } // reset locked state if (cmd == karte_t::new_player || cmd == karte_t::delete_player) { socket_list_t::unlock_player_all(player_nr, true); } // update the window ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t); if (playerwin) { playerwin->update_data(); } } nwc_tool_t::nwc_tool_t() : network_broadcast_world_command_t(NWC_TOOL, 0, 0), init(false), custom_data(custom_data_buf, lengthof(custom_data_buf), true) { tool = NULL; } nwc_tool_t::nwc_tool_t(player_t *player, tool_t *tool_, koord3d pos_, uint32 sync_steps, uint32 map_counter, bool init_) : network_broadcast_world_command_t(NWC_TOOL, sync_steps, map_counter), custom_data(custom_data_buf, lengthof(custom_data_buf), true) { pos = pos_; player_nr = player ? player->get_player_nr() : -1; tool_id = tool_->get_id(); wt = tool_->get_waytype(); default_param = tool_->get_default_param(player); init = init_; tool_client_id = 0; flags = tool_->flags; karte_ptr_t welt; last_sync_step = welt->get_last_checklist_sync_step(); last_checklist = welt->get_last_checklist(); callback_id = tool_->callback_id; // write custom data of tool_ to our internal buffer if (player) { tool_->rdwr_custom_data(&custom_data); } tool = NULL; } nwc_tool_t::nwc_tool_t(const nwc_tool_t &nwt) : network_broadcast_world_command_t(NWC_TOOL, nwt.get_sync_step(), nwt.get_map_counter()), custom_data(custom_data_buf, lengthof(custom_data_buf), true) { pos = nwt.pos; player_nr = nwt.player_nr; tool_id = nwt.tool_id; wt = nwt.wt; default_param = nwt.default_param; init = nwt.init; tool_client_id = nwt.our_client_id; flags = nwt.flags; callback_id = nwt.callback_id; // copy custom data of tool to our internal buffer custom_data.append(nwt.custom_data); tool = NULL; } nwc_tool_t::~nwc_tool_t() { delete tool; } void nwc_tool_t::rdwr() { network_broadcast_world_command_t::rdwr(); packet->rdwr_long(last_sync_step); last_checklist.rdwr(packet); packet->rdwr_byte(player_nr); sint16 posx = pos.x; packet->rdwr_short(posx); pos.x = posx; sint16 posy = pos.y; packet->rdwr_short(posy); pos.y = posy; sint8 posz = pos.z; packet->rdwr_byte(posz); pos.z = posz; packet->rdwr_short(tool_id); packet->rdwr_short(wt); packet->rdwr_str(default_param); packet->rdwr_bool(init); packet->rdwr_long(tool_client_id); packet->rdwr_byte(flags); packet->rdwr_long(callback_id); // copy custom data of tool to/from packet if (packet->is_saving()) { // write to packet packet->append(custom_data); } else { // read from packet custom_data.append_tail(*packet); } DBG_MESSAGE("nwc_tool_t::rdwr", "rdwr id=%d client=%d plnr=%d pos=%s tool_id=%s defpar=%s init=%d flags=%d", id, tool_client_id, player_nr, pos.get_str(), tool_t::id_to_string(tool_id), default_param.c_str(), init, flags); } void nwc_tool_t::init_tool() { delete tool; // create new memory_rw_t that is in reading mode to read tool data memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false); if ( (tool = create_tool(tool_id)) ) { tool->set_default_param(default_param); tool->rdwr_custom_data(&new_custom_data); } } network_broadcast_world_command_t* nwc_tool_t::clone(karte_t *welt) { init_tool(); if (tool == NULL) { // invalid id return NULL; } // do not open dialog windows across network if ( init ? tool->is_init_keeps_game_state() : tool->is_work_keeps_game_state() ){ // no reason to send request over network return NULL; } // scenario scripts only run on server if (socket_list_t::get_client_id(packet->get_sender()) != 0) { // not sent by server, clear flag flags &= ~tool_t::WFL_NO_CHK; } // scripted calls do not need authentication check bool const needs_check = (flags & tool_t::WFL_NO_CHK) == 0; // check authentication and scenario rules if (needs_check) { scenario_t *scen = welt->get_scenario(); // check for map editor tools - they need unlocked public player // scenario should check itself if (!scen->is_scripted()) { switch( tool_id ) { case TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL: case TOOL_BUILD_HOUSE | GENERAL_TOOL: case TOOL_BUILD_LAND_CHAIN | GENERAL_TOOL: case TOOL_CITY_CHAIN | GENERAL_TOOL: case TOOL_BUILD_FACTORY | GENERAL_TOOL: case TOOL_LINK_FACTORY | GENERAL_TOOL: case TOOL_ADD_CITYCAR | GENERAL_TOOL: case TOOL_INCREASE_INDUSTRY | SIMPLE_TOOL: case TOOL_STEP_YEAR | SIMPLE_TOOL: case TOOL_FILL_TREES | SIMPLE_TOOL: player_nr = 1; default: ; } } // check whether player is authorized do this socket_info_t const& info = socket_list_t::get_client(our_client_id); if ( player_nr < PLAYER_UNOWNED && !info.is_player_unlocked(player_nr) ) { if (tool_id == (TOOL_ADD_MESSAGE | GENERAL_TOOL)) { player_nr = PLAYER_UNOWNED; } else { dbg->warning("nwc_tool_t::clone", "client %d not allowed to act as player %d", our_client_id, player_nr); return NULL; // indicate failure } } // log that this client acted as this player if ( player_nr < PLAYER_UNOWNED) { nwc_chg_player_t::company_active_clients[player_nr].append_unique( connection_info_t(info) ); } // do scenario checks here, send error message back if ( scen->is_scripted() ) { if (!scen->is_tool_allowed(welt->get_player(player_nr), tool_id, wt, default_param)) { dbg->warning("nwc_tool_t::clone", "tool_id=%s wt=%d param=%p, tool not allowed", tool_t::id_to_string(tool_id), wt, default_param.c_str()); // TODO return error message ? return NULL; } if (!init) { const char *err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, default_param, pos); if (err == NULL) { if (two_click_tool_t *two_ctool = dynamic_cast(tool)) { if (!two_ctool->is_first_click()) { err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, default_param, two_ctool->get_start_pos()); } } } if (err) { nwc_tool_t *nwt = new nwc_tool_t(*this); nwt->tool_id = TOOL_ERROR_MESSAGE | GENERAL_TOOL; nwt->default_param = err; nwt->last_sync_step = welt->get_last_checklist_sync_step(); nwt->last_checklist = welt->get_last_checklist(); dbg->warning("nwc_tool_t::clone", "send sync_steps=%d tool_id=%s error=%s", nwt->get_sync_step(), tool_t::id_to_string(tool_id), err); return nwt; } } } } // copy data, sets tool_client_id to sender client_id nwc_tool_t *nwt = new nwc_tool_t(*this); nwt->last_sync_step = welt->get_last_checklist_sync_step(); nwt->last_checklist = welt->get_last_checklist(); DBG_MESSAGE("nwc_tool_t::clone", "send sync_steps=%d tool_id=%s %s", nwt->get_sync_step(), tool_t::id_to_string(tool_id), init ? "init" : "work"); return nwt; } bool nwc_tool_t::ignore_old_events() const { // messages are allowed to arrive at any time (return true if message) return tool_id==(GENERAL_TOOL|TOOL_ADD_MESSAGE); } void nwc_tool_t::do_command(karte_t *welt) { if (tool == NULL) { init_tool(); } DBG_MESSAGE("nwc_tool_t::do_command", "steps %d tool_id %d %s", get_sync_step(), tool_id, init ? "init" : "work"); // commands are treated differently if they come from this client or not bool local = tool_client_id == network_get_client_id(); player_t *player = player_nr < PLAYER_UNOWNED ? welt->get_player(player_nr) : NULL; // before calling work initialize new tool assert(tool); bool init_successfull = true; if (!init) { // init command was not sent if tool->is_init_keeps_game_state() returned true tool->flags = 0; // init tool init_successfull = tool->init(player); } // read custom data (again, necessary for two_click_tool_t) { memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false); tool->rdwr_custom_data(&new_custom_data); } // set flags correctly if (local) { tool->flags = flags | tool_t::WFL_LOCAL; } else { tool->flags = flags & ~tool_t::WFL_LOCAL; } DBG_MESSAGE("nwc_tool_t::do_command","id=%d init=%d defpar=%s flag=%d",tool_id&0xFFF,init,(const char*)default_param,tool->flags); const char* err = NULL; bool res = false; // call INIT if( init ) { // we should be here only if tool->init() returns false // no need to change active tool of world res = tool->init(player); } // call WORK else if (init_successfull) { // remove preview tiles of active tool two_click_tool_t *active_tool = dynamic_cast(welt->get_tool(welt->get_active_player_nr())); if(active_tool && active_tool->remove_preview_necessary()) { active_tool->cleanup(); } err = tool->work( player, pos ); // only local players get the callback if (local && callback_id == 0 && player) { player->tell_tool_result(tool, pos, err); } if (err) { dbg->warning("nwc_tool_t::do_command","Tool %s failed with '%s'", tool->get_name(), err); } tool->exit(player); } else { err = "Init was not succesfull, returned false."; } // callback to script here if (local && callback_id != 0) { if (init) { suspended_scripts_t::tell_return_value(callback_id, res); } else { suspended_scripts_t::tell_return_value(callback_id, err); } } } extern address_list_t blacklist; bool nwc_service_t::execute(karte_t *welt) { if (flag>=SRVC_MAX || !env_t::server) { // wrong flag, no server return true; // to delete } // check whether admin connection is established const uint32 sender_id = socket_list_t::get_client_id(packet->get_sender()); const bool admin_logged_in = socket_list_t::get_client(sender_id).state == socket_info_t::admin; if (!admin_logged_in && (flag != SRVC_LOGIN_ADMIN && flag != SRVC_ANNOUNCE_SERVER) ) { return true; // to delete } switch(flag) { case SRVC_LOGIN_ADMIN: { nwc_service_t nws; nws.flag = SRVC_LOGIN_ADMIN; // check password bool ok = !env_t::server_admin_pw.empty() && env_t::server_admin_pw.compare(text)==0; if (ok) { socket_list_t::get_client(sender_id).state = socket_info_t::admin; } nws.number = ok ? sender_id : 0; nws.send(packet->get_sender()); break; } case SRVC_ANNOUNCE_SERVER: // Startup announce, to force full details resend welt->announce_server( karte_t::SERVER_ANNOUNCE_HELLO ); break; case SRVC_GET_CLIENT_LIST: { nwc_service_t nws; nws.flag = SRVC_GET_CLIENT_LIST; // send, socket list will be written in rdwr nws.send(packet->get_sender()); break; } case SRVC_KICK_CLIENT: case SRVC_BAN_CLIENT: { bool ban = flag == SRVC_BAN_CLIENT; uint32 client_id = number; net_address_t address; SOCKET kick = socket_list_t::get_socket(client_id); if (kick!=INVALID_SOCKET) { socket_info_t &info = socket_list_t::get_client(client_id); address.ip = info.address.ip; if (info.state == socket_info_t::playing) { socket_list_t::remove_client(info.socket); } } if (ban && address.ip) { fd_set fd; FD_ZERO(&fd); socket_list_t::fill_set(&fd); socket_list_t::client_socket_iterator_t iter(&fd); while(iter.next()) { SOCKET sock = iter.get_current(); socket_info_t& info = socket_list_t::get_client(socket_list_t::get_client_id(sock)); if (address.matches(info.address)) { socket_list_t::remove_client(sock); } } blacklist.append(address); } break; } case SRVC_GET_BLACK_LIST: { nwc_service_t nws; nws.flag = SRVC_GET_BLACK_LIST; // send, blacklist will be written in rdwr nws.send(packet->get_sender()); break; } case SRVC_BAN_IP: case SRVC_UNBAN_IP: { net_address_t address(text); if (address.ip) { if (flag==SRVC_BAN_IP) { blacklist.append(address); } else { blacklist.remove(address); } } break; } case SRVC_ADMIN_MSG: if (text) { // Send message to all clients as Public Service // with reserved username Admin nwc_chat_t* nwchat = new nwc_chat_t( text, 1, -1, "Admin" ); network_send_all( nwchat, false ); // Log chat message - please don't change order of fields CSV_t csv; csv.add_field( "adminmsg" ); csv.add_field( text ); dbg->warning( "__ChatLog__", "%s", csv.get_str() ); } break; case SRVC_SHUTDOWN: { welt->stop( true ); break; } case SRVC_FORCE_SYNC: { const uint32 new_map_counter = welt->generate_new_map_counter(); nwc_sync_t *nw_sync = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), -1, new_map_counter); if (welt->is_paused()) { if (socket_list_t::get_playing_clients() == 0) { // we can save directly without disturbing clients nw_sync->do_command(welt); } delete nw_sync; } else { // send sync command network_send_all(nw_sync, false); } break; } case SRVC_GET_COMPANY_LIST: case SRVC_GET_COMPANY_INFO: { bool detailed = flag == SRVC_GET_COMPANY_INFO && number < PLAYER_UNOWNED; uint8 min_index = detailed ? number : 0; uint8 max_index = detailed ? number+1 : PLAYER_UNOWNED; cbuffer_t buf; for (uint8 i=min_index; iget_player(i)) { buf.printf("Company #%d: %s\n", i, player->get_name()); buf.printf(" Password: %sset\n", player->access_password_hash().empty() ? "NOT " :""); // print creator information if (i < lengthof(nwc_chg_player_t::company_creator)) { if (connection_info_t const* creator = nwc_chg_player_t::company_creator[i]) { buf.printf(" founded by %s at %s\n", creator->nickname.c_str(), creator->address.get_str()); } } // print clients who have this player unlocked for(uint32 j = 0; j < socket_list_t::get_count(); j++) { socket_info_t const& info = socket_list_t::get_client(j); if (info.is_active() && info.is_player_unlocked(i)) { buf.printf(" unlocked for [%d] %s at %s\n", j, info.nickname.c_str(), info.address.get_str()); } } // print clients who played for this company uint32 j=0; for(connection_info_t &iter : nwc_chg_player_t::company_active_clients[i]) { if (!detailed && j > 3 && nwc_chg_player_t::company_active_clients[i].get_count() > 5) { buf.printf(" .. and %d more.\n", nwc_chg_player_t::company_active_clients[i].get_count()-j); break; } buf.printf(" played by %s at %s\n", iter.nickname.c_str(), iter.address.get_str()); j++; } } } nwc_service_t nws; nws.flag = flag; nws.text = strdup(buf); if (text && (strlen(text) > MAX_PACKET_LEN - 256)) { text[MAX_PACKET_LEN - 256] = 0; } nws.send(packet->get_sender()); break; } case SRVC_UNLOCK_COMPANY: { if (number >= PLAYER_UNOWNED) { break; // invalid number } uint8 player_nr = number; // empty password player_t *player = welt->get_player(player_nr); if (player) { player->access_password_hash().clear(); // unlock all clients socket_list_t::unlock_player_all(player_nr, true, packet->get_sender()); // unlock player on the server player->unlock(true, false); } break; } case SRVC_REMOVE_COMPANY: { if (number >= PLAYER_UNOWNED) { break; // invalid number } nwc_chg_player_t *nwc = new nwc_chg_player_t(welt->get_sync_steps(), welt->get_map_counter(), karte_t::delete_player, number); if (nwc->execute(welt)) { delete nwc; } break; } default: ; } return true; // to delete } simutrans-124.3/src/simutrans/network/network_cmd_ingame.h000066400000000000000000000303101474050137200240620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_CMD_INGAME_H #define NETWORK_NETWORK_CMD_INGAME_H #include "network_cmd.h" #include "memory_rw.h" #include "../world/simworld.h" #include "../tpl/slist_tpl.h" #include "../utils/plainstring.h" #include "../dataobj/koord3d.h" class connection_info_t; class packet_t; class player_t; class tool_t; /** * nwc_gameinfo_t * @from-client: client wants map info * server sends nwc_gameinfo_t to sender * @from-server: * @data len of gameinfo * client processes this in network_connect */ class nwc_gameinfo_t : public network_command_t { public: nwc_gameinfo_t() : network_command_t(NWC_GAMEINFO) { len = 0; } bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; uint32 client_id; uint32 len; }; /** * nwc_nick_t * @from-client: client sends new nickname, * server checks if nickname is already taken, * and generates a default one if this is the case * @from-server: server sends the checked nickname back to the client */ class nwc_nick_t : public network_command_t { public: nwc_nick_t(const char* nick=NULL) : network_command_t(NWC_NICK), nickname(nick) { } bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; plainstring nickname; enum { WELCOME, CHANGE_NICK, FAREWELL }; /** * Server-side nickname related stuff: * what = WELCOME .. new player joined: send welcome message * what = CHANGE_NICK .. change nickname: in socket_list per client, send new nick back to client, tell others as well * what = FAREWELL .. player has left: send message */ static void server_tools(karte_t *welt, uint32 client_id, uint8 what, const char* nick); private: nwc_nick_t(const nwc_nick_t&); nwc_nick_t& operator=(const nwc_nick_t&); }; /** * nwc_chat_t * @from-client: client sends chat message to server * server logs message and sends it to all clients * @from-server: server sends a chat message for display on the client */ class nwc_chat_t : public network_command_t { public: nwc_chat_t (const char* msg = NULL, sint8 pn = -1, sint8 ch= -1, const char* cn = NULL, const char* dn = NULL, koord pos_=koord::invalid) : network_command_t(NWC_CHAT) , message(msg) , player_nr(pn) , channel_nr(ch) , pos(pos_) , clientname(cn) , destination(dn) {} bool execute (karte_t * welt) OVERRIDE; void rdwr () OVERRIDE; void add_message(karte_t*) const; plainstring message; // Message text sint8 player_nr; // Company number message was sent as sint8 channel_nr; // Company channnel (-1 for public) koord pos; plainstring clientname; // Name of client message is from plainstring destination; // Client to send message to (NULL for all) private: nwc_chat_t(const nwc_chat_t&); nwc_chat_t& operator=(const nwc_chat_t&); }; /** * nwc_join_t * @from-client: client wants to join the server * server sends nwc_join_t to sender, nwc_sync_t to all clients * @from-server: * @data answer == 1 (if joining now is ok) * @data client_id * client ignores the following nwc_sync_t, waits for nwc_ready_t */ class nwc_join_t : public nwc_nick_t { public: nwc_join_t(const char* nick=NULL) : nwc_nick_t(nick), client_id(0), answer(0) { id = NWC_JOIN; } bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; uint32 client_id; uint8 answer; /** * this clients is in the process of joining */ static SOCKET pending_join_client; static bool is_pending() { return pending_join_client != INVALID_SOCKET; } private: nwc_join_t(const nwc_join_t&); nwc_join_t& operator=(const nwc_join_t&); }; /** * nwc_ready_t * @from-client: * @data sync_steps at which client will continue * client paused, waits for unpause * @from-server: * data is resent to client * map_counter to identify network_commands * unpause client */ class nwc_ready_t : public network_command_t { public: nwc_ready_t() : network_command_t(NWC_READY), sync_step(0), map_counter(0) { } nwc_ready_t(uint32 sync_step_, uint32 map_counter_, const checklist_t &checklist_) : network_command_t(NWC_READY), sync_step(sync_step_), map_counter(map_counter_), checklist(checklist_) { } bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; uint32 sync_step; uint32 map_counter; checklist_t checklist; static void append_map_counter(uint32 map_counter_); static void clear_map_counters(); private: static vector_tplall_map_counters; }; /** * nwc_game_t * @from-server: * @data len of savegame * client processes this in network_connect */ class nwc_game_t : public network_command_t { public: nwc_game_t(uint32 len_=0) : network_command_t(NWC_GAME), len(len_) {} void rdwr() OVERRIDE; uint32 len; }; /** * commands that have to be executed at a certain sync_step */ class network_world_command_t : public network_command_t { public: network_world_command_t() : network_command_t(), sync_step(0), map_counter(0) {} network_world_command_t(uint16 /*id*/, uint32 /*sync_step*/, uint32 /*map_counter*/); void rdwr() OVERRIDE; // put it to the command queue bool execute(karte_t *) OVERRIDE; // apply it to the world virtual void do_command(karte_t*) {} uint32 get_sync_step() const { return sync_step; } uint32 get_map_counter() const { return map_counter; } // ignore events that lie in the past? // if false: any cmd with sync_step < world->sync_step forces network disconnect virtual bool ignore_old_events() const { return false;} // for sorted data structures bool operator <= (network_world_command_t c) const { return sync_step <= c.sync_step; } static bool cmp(network_world_command_t *nwc1, network_world_command_t *nwc2) { return nwc1->get_sync_step() <= nwc2->get_sync_step(); } protected: uint32 sync_step; // when this has to be executed uint32 map_counter; // cmd comes from world at this stage }; /** * nwc_sync_t * @from-server: * @data client_id this client wants to receive the game * @data new_map_counter new map counter for the new world after game reloading * clients: pause game, save, load, wait for nwc_ready_t command to unpause * server: pause game, save, load, send game to client, send nwc_ready_t command to client */ class nwc_sync_t : public network_world_command_t { public: nwc_sync_t() : network_world_command_t(NWC_SYNC, 0, 0), client_id(0), new_map_counter(0) {} nwc_sync_t(uint32 sync_steps, uint32 map_counter, uint32 send_to_client, uint32 _new_map_counter) : network_world_command_t(NWC_SYNC, sync_steps, map_counter), client_id(send_to_client), new_map_counter(_new_map_counter) { } void rdwr() OVERRIDE; void do_command(karte_t*) OVERRIDE; uint32 get_new_map_counter() const { return new_map_counter; } private: uint32 client_id; // this client shall receive the game uint32 new_map_counter; // map counter to be applied to the new world after game reloading }; /** * nwc_check_t * @from-server: * @data checklist random seed and quickstone next check entries at previous sync_step * clients: check random seed, if check fails disconnect. * the check is done in karte_t::interactive */ class nwc_check_t : public network_world_command_t { public: nwc_check_t() : network_world_command_t(NWC_CHECK, 0, 0), server_sync_step(0) { } nwc_check_t(uint32 sync_steps, uint32 map_counter, const checklist_t &server_checklist_, uint32 server_sync_step_) : network_world_command_t(NWC_CHECK, sync_steps, map_counter), server_checklist(server_checklist_), server_sync_step(server_sync_step_) {} void rdwr() OVERRIDE; void do_command(karte_t*) OVERRIDE { } checklist_t server_checklist; uint32 server_sync_step; // no action required -> can be ignored if too old bool ignore_old_events() const OVERRIDE { return true; } }; /** * commands that need to be executed at a certain syncstep * the command will be cloned at the server and broadcasted to all clients */ class network_broadcast_world_command_t : public network_world_command_t { public: network_broadcast_world_command_t(uint16 id, uint32 sync_step=0, uint32 map_counter=0) : network_world_command_t(id, sync_step, map_counter), exec(false) { } void rdwr() OVERRIDE; bool execute(karte_t *) OVERRIDE; // clones the command to be broadcasted // all validity checks must be done here // it must return a new command // clone() must return NULL to indicate failure virtual network_broadcast_world_command_t* clone(karte_t *) = 0; bool is_from_initiator() const { return !exec; } private: // at server: true if command needs to be put in command queue // it will be cloned and broadcasted otherwise bool exec; }; /** * nwc_chg_player_t * commands that require special authentication checks: toggle freeplay, start AI player * @from-server: * @data cmd command to perform (see karte_t::change_player_tool) * @data player_nr affected player * @data param */ class nwc_chg_player_t : public network_broadcast_world_command_t { public: nwc_chg_player_t() : network_broadcast_world_command_t(NWC_CHG_PLAYER, 0, 0), pending_company_creator(NULL) { } nwc_chg_player_t(uint32 sync_steps, uint32 map_counter, uint8 cmd_=255, uint8 player_nr_=255, uint16 param_=0, bool scripted_call_=false) : network_broadcast_world_command_t(NWC_CHG_PLAYER, sync_steps, map_counter), cmd(cmd_), player_nr(player_nr_), param(param_), scripted_call(scripted_call_), pending_company_creator(NULL) {} ~nwc_chg_player_t(); void rdwr() OVERRIDE; void do_command(karte_t*) OVERRIDE; // do some special checks network_broadcast_world_command_t* clone(karte_t *) OVERRIDE; uint8 cmd; uint8 player_nr; uint16 param; bool scripted_call; connection_info_t* pending_company_creator; // this client want to create new company (not sent) /// store information about client that created a company static connection_info_t* company_creator[PLAYER_UNOWNED]; /// store information about clients that played with a company static slist_tpl company_active_clients[PLAYER_UNOWNED]; /// callback when company was removed static void company_removed(uint8 player_nr); private: nwc_chg_player_t(const nwc_chg_player_t&); nwc_chg_player_t& operator=(const nwc_chg_player_t&); }; /** * nwc_tool_t * @from-client: client sends tool init/work * @from-server: server sends nwc_tool_t to all clients with step when tool has to be executed * @data client_id (the client that launched the tool, sent by server) * @data player_nr * @data init (if true call init else work) * @data tool_id * @data pos * @data default_param * @data exec (if true executes, else server sends it to clients) */ class nwc_tool_t : public network_broadcast_world_command_t { public: // to detect desync we sent these infos always together (only valid for tools) checklist_t last_checklist; uint32 last_sync_step; nwc_tool_t(); nwc_tool_t(player_t *player, tool_t *tool, koord3d pos, uint32 sync_steps, uint32 map_counter, bool init); nwc_tool_t(const nwc_tool_t&); // messages are allowed to arrive at any time bool ignore_old_events() const OVERRIDE; virtual ~nwc_tool_t(); void rdwr() OVERRIDE; // clone performs authentication checks network_broadcast_world_command_t* clone(karte_t *) OVERRIDE; // really executes it, here exec should be true void do_command(karte_t*) OVERRIDE; void init_tool(); private: // transfered data plainstring default_param; uint32 tool_client_id; uint32 callback_id; uint16 tool_id; sint16 wt; // needed for scenario checks koord3d pos; uint8 flags; uint8 player_nr; bool init; uint8 custom_data_buf[256]; memory_rw_t custom_data; // tool that will be executed tool_t* tool; // compare default_param's (NULL pointers allowed) // @return true if default_param are equal static bool cmp_default_param(const char *d1, const char *d2); }; /** * nwc_step_t * @from-server: * @data contains the current sync_steps of the server * defining the maximum sync_steps a client can advance to. */ class nwc_step_t : public network_world_command_t { public: nwc_step_t() : network_world_command_t(NWC_STEP, 0, 0) { } nwc_step_t(uint32 sync_steps, uint32 map_counter) : network_world_command_t(NWC_STEP, sync_steps, map_counter) {} bool execute(karte_t *) OVERRIDE { return true;} }; #endif simutrans-124.3/src/simutrans/network/network_cmd_scenario.cc000066400000000000000000000062321474050137200245710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_cmd_scenario.h" #include "network_packet.h" #include "network_socket_list.h" #include "../world/simworld.h" #include "../dataobj/scenario.h" #include "../dataobj/environment.h" #include "../script/script.h" void nwc_scenario_t::init(script_vm_t *script) { script->register_callback(&nwc_scenario_t::record_result, "nwc_scenario_t_record_result"); } bool nwc_scenario_t::record_result(const char* function, plainstring result, uint32 client_id) { SOCKET sock = socket_list_t::get_socket(client_id); if (sock == INVALID_SOCKET) { return false; } nwc_scenario_t nwc; nwc.what = CALL_SCRIPT_ANSWER; nwc.function = function; nwc.result = result; nwc.send( sock ); return true; } void nwc_scenario_t::rdwr() { network_command_t::rdwr(); packet->rdwr_short(what); packet->rdwr_short(won); packet->rdwr_short(lost); packet->rdwr_str(function); packet->rdwr_str(result); } bool nwc_scenario_t::execute(karte_t *welt) { scenario_t *scen = welt->get_scenario(); if (scen == NULL || !scen->is_scripted()) { return true; } script_vm_t *script = scen->script; if (what == OPEN_SCEN_WIN) { // open window on server and clients scen->open_info_win(function); return true; } if (env_t::server) { switch (what) { case CALL_SCRIPT: case CALL_SCRIPT_ANSWER: { // register callback to send result back to client if script is delayed. script->prepare_callback("nwc_scenario_t_record_result", 2, function, (const char*)"", socket_list_t::get_client_id( packet->get_sender() ) ); plainstring res = dynamic_string::fetch_result(function, script, NULL, what==CALL_SCRIPT_ANSWER); // clear callback, in case function call was successfull script->clear_pending_callback(); nwc_scenario_t nwc; nwc.what = CALL_SCRIPT_ANSWER; nwc.function = function; nwc.result = res; nwc.send( packet->get_sender() ); break; } case UPDATE_WON_LOST: default: ; } } else { switch (what) { case CALL_SCRIPT_ANSWER: // store result, call listening string dynamic_string::record_result(function, result); break; case UPDATE_WON_LOST: scen->update_won_lost(won, lost); break; default: ; } } return true; } void nwc_scenario_rules_t::do_command(karte_t *welt) { scenario_t *scen = welt->get_scenario(); scen->intern_forbid(rule, player_nr, forbid); rule = NULL; // pointer is now invalid } void nwc_scenario_rules_t::rdwr() { network_broadcast_world_command_t::rdwr(); rule->rdwr(packet); packet->rdwr_bool(forbid); packet->rdwr_short(player_nr); } nwc_scenario_rules_t::nwc_scenario_rules_t(const nwc_scenario_rules_t& nwr) : network_broadcast_world_command_t(NWC_SCENARIO_RULES, nwr.get_sync_step(), nwr.get_map_counter()) { forbid = nwr.forbid; player_nr = nwr.player_nr; rule = new scenario_t::forbidden_t(*nwr.rule); } network_broadcast_world_command_t* nwc_scenario_rules_t::clone(karte_t *) { // scenario scripts only run on server if (socket_list_t::get_client_id(packet->get_sender()) != 0) { // not sent by server return NULL; } return new nwc_scenario_rules_t(*this); } simutrans-124.3/src/simutrans/network/network_cmd_scenario.h000066400000000000000000000043161474050137200244340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_CMD_SCENARIO_H #define NETWORK_NETWORK_CMD_SCENARIO_H #include "network_cmd.h" #include "network_cmd_ingame.h" #include "../dataobj/scenario.h" #include "../utils/plainstring.h" /** * nwc_scenario_t: * scenario script runs on server only, to communicate results this command is used */ class nwc_scenario_t : public network_command_t { public: nwc_scenario_t() : network_command_t(NWC_SCENARIO), what(UNKNOWN), won(0), lost(0), function(NULL), result(NULL) { } bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; enum { UNKNOWN, CALL_SCRIPT, /// client asks for an update CALL_SCRIPT_ANSWER, /// client wants string, server sends string UPDATE_WON_LOST, /// update win/lose flags of the scenario OPEN_SCEN_WIN /// open scenario info window }; uint16 what; uint16 won, lost; plainstring function; plainstring result; /// register the callback to the script engine static void init(script_vm_t *script); /** * Callback method: sends answer back to client. * * @param function result of this function is returned * @param result * @param client_id to send result to * @returns dummy boolean value */ static bool record_result(const char* function, plainstring result, uint32 client_id); private: nwc_scenario_t(const nwc_scenario_t&); nwc_scenario_t& operator=(const nwc_scenario_t&); }; /** * nwc_scenario_rules_t: * scenario script runs on server only, use this command to send new rules to client */ class nwc_scenario_rules_t : public network_broadcast_world_command_t { public: nwc_scenario_rules_t(uint32 sync_step=0, uint32 map_counter=0) : network_broadcast_world_command_t(NWC_SCENARIO_RULES, sync_step, map_counter), rule( new scenario_t::forbidden_t()), forbid(true) { } ~nwc_scenario_rules_t() { delete rule; } void do_command(karte_t *) OVERRIDE; void rdwr() OVERRIDE; network_broadcast_world_command_t* clone(karte_t *) OVERRIDE; scenario_t::forbidden_t *rule; bool forbid; uint16 player_nr; private: nwc_scenario_rules_t(const nwc_scenario_rules_t&); nwc_scenario_rules_t& operator=(const nwc_scenario_rules_t&); }; #endif simutrans-124.3/src/simutrans/network/network_cmp_pakset.cc000066400000000000000000000175771474050137200243070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_cmp_pakset.h" #include "network_packet.h" #include "network.h" #include "network_socket_list.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../utils/cbuffer.h" #include "../simloadingscreen.h" #include stringhashtable_tpl::iterator nwc_pakset_info_t::server_iterator; SOCKET nwc_pakset_info_t::server_receiver = INVALID_SOCKET; nwc_pakset_info_t::~nwc_pakset_info_t() { delete chk; free(name); } bool nwc_pakset_info_t::execute(karte_t *) { // server side of the communication // client side in network_compare_pakset_with_server if( env_t::server ) { nwc_pakset_info_t nwi; bool send = false; bool ready = false; switch(flag) { case CL_INIT: // client want pakset info { if (server_receiver!=INVALID_SOCKET && socket_list_t::has_client(server_receiver)) { // we are already talking to another client nwi.flag = SV_ERROR; nwi.send(packet->get_sender()); // ignore result of send, we don't want to talk to that client either break; } server_receiver = packet->get_sender(); // restart iterator server_iterator = pakset_info_t::info.begin(); nwi.flag = SV_PAKSET; nwi.chk = new checksum_t(*pakset_info_t::get_checksum()); nwi.name = strdup("pakset"); DBG_MESSAGE("nwc_pakset_info_t::execute", "send info about %s",nwi.name); send = true; break; } case CL_WANT_NEXT: // client received one info packet, wants next if (server_iterator != pakset_info_t::info.end()) { nwi.flag = SV_DATA; nwi.chk = new checksum_t(*server_iterator->value); nwi.name = strdup(server_iterator->key); DBG_MESSAGE("nwc_pakset_info_t::execute", "send info about %s",nwi.name); ++server_iterator; } else { nwi.flag = SV_LAST; ready = true; } send = true; break; case CL_QUIT: // client ends this negotiation server_receiver = INVALID_SOCKET; break; default: ; } if( send ) { if(socket_list_t::has_client(server_receiver)) { // send, if unsuccessful stop comparing if (!nwi.send(server_receiver)) { ready = true; } } else { // client disappeared server_receiver = INVALID_SOCKET; } } if( ready ) { // all information sent server_receiver = INVALID_SOCKET; } } return true; } void nwc_pakset_info_t::rdwr() { network_command_t::rdwr(); packet->rdwr_byte(flag); packet->rdwr_str(name); bool has_info = (chk!=NULL && chk->is_valid()) || packet->is_loading(); packet->rdwr_bool(has_info); if( has_info ) { if( packet->is_loading() ) { chk = new checksum_t(); } chk->rdwr(packet); } } static bool str_cmp(const char *a, const char *b) { return strcmp(a,b) < 0; } void network_compare_pakset_with_server(const char* cp, std::string &msg) { // open from network const char *err = NULL; SOCKET const my_client_socket = network_open_address(cp, err); if( err==NULL ) { socket_list_t::add_client(my_client_socket); // for network_check_activity // client side of comparison // server part in nwc_pakset_info_t::execute { // start nwc_pakset_info_t nwi(nwc_pakset_info_t::CL_INIT); if (!nwi.send(my_client_socket)) { dbg->warning("network_compare_pakset_with_server", "send of NWC_PAKSETINFO failed"); socket_list_t::remove_client(my_client_socket); return; } } // copy our info to addon // ie treat all our paks as if they were not present on the server stringhashtable_tpl addons; { for(auto const& i : pakset_info_t::get_info()) { addons.put(i.key, i.value); } } // we do a sorted verctor of names ... vector_tpl missing, different; // show progress bar const uint32 num_paks = addons.get_count()+1; uint32 progress = 0; #define MAX_WRONG_PAKS 10 uint16 wrong_paks = 0; if(num_paks>0) { loadingscreen_t ls(translator::translate("Comparing pak files ..."), num_paks ); // communication loop bool ready = false; do { nwc_pakset_info_t *nwi = NULL; // wait for nwc_pakset_info_t, ignore other commands for(uint8 i=0; i<5; i++) { network_command_t* nwc = network_check_activity(10000); if (nwc && nwc->get_id() == NWC_PAKSETINFO) { nwi = (nwc_pakset_info_t*)nwc; break; } delete nwc; } if (nwi == NULL) { dbg->warning("network_compare_pakset_with_server", "server did not answer"); nwc_pakset_info_t nwi_quit(nwc_pakset_info_t::CL_QUIT); if (!nwi_quit.send(my_client_socket)) { err = "send of NWC_PAKSETINFO failed"; } break; } switch(nwi->flag) { case nwc_pakset_info_t::SV_PAKSET: { if(pakset_info_t::get_pakset_checksum()==(*(nwi->chk))) { // found identical paksets } else { wrong_paks++; } progress++; // request new data nwc_pakset_info_t nwi_data(nwc_pakset_info_t::CL_WANT_NEXT); if(!nwi_data.send(my_client_socket)) { err = "send of NWC_PAKSETINFO failed"; ready = true; } break; } case nwc_pakset_info_t::SV_DATA: { checksum_t* chk = addons.remove(nwi->name); if(chk) { if((*chk)==(*(nwi->chk))) { // found identical desc's } else { different.insert_ordered( nwi->name, str_cmp ); nwi->clear(); wrong_paks++; } progress++; } else { missing.insert_ordered( nwi->name, str_cmp ); nwi->clear(); wrong_paks++; } nwc_pakset_info_t nwi_next; if (wrong_paks<=MAX_WRONG_PAKS) { // request new data nwi_next.flag = nwc_pakset_info_t::CL_WANT_NEXT; } else { nwi_next.flag = nwc_pakset_info_t::CL_QUIT; } if(!nwi_next.send(my_client_socket)) { err = "send of NWC_PAKSETINFO failed"; ready = true; } break; } case nwc_pakset_info_t::SV_LAST: case nwc_pakset_info_t::SV_ERROR: default: ready = true; } // update progress bar ls.set_progress(progress); delete nwi; } while (!ready && wrong_paks<=MAX_WRONG_PAKS); } // now report the result msg.append(""); msg.append(translator::translate("Pakset differences")); msg.append("\n"); if(wrong_paks<=MAX_WRONG_PAKS && !addons.empty()) { msg.append("

"); msg.append(translator::translate("Pak(s) not on server:")); msg.append("


\n"); for(auto const& i : addons) { dbg->warning("network_compare_pakset_with_server", "PAK NOT ON SERVER: %s", i.key); msg.append(translator::translate(i.key+3)); msg.append("
\n"); } msg.append("
\n"); } if (!different.empty()) { msg.append("

"); msg.append(translator::translate("Pak(s) different:")); msg.append("


\n"); for(const char * const& i : different) { dbg->warning("network_compare_pakset_with_server", "PAK DIFFERENT: %s", i); msg.append(translator::translate(i+3)); // the first three letters are the type ... msg.append("
\n"); } msg.append("
\n"); } if (!missing.empty()) { msg.append("

"); msg.append(translator::translate("Pak(s) missing on client:")); msg.append("


\n"); for(const char * const& i : missing) { dbg->warning("network_compare_pakset_with_server", "PAK MISSING: %s", i); msg.append(translator::translate(i+3)); // the first three letters are the type ... msg.append("
\n"); } } if (wrong_paks>MAX_WRONG_PAKS) { msg.append("
\n"); msg.append("
\n"); cbuffer_t buf; buf.printf(translator::translate("Only first %d differing paks reported. There are probably more."), wrong_paks); msg.append((const char*)buf); msg.append("
\n"); } socket_list_t::remove_client(my_client_socket); } if(err) { dbg->warning("network_compare_pakset_with_server", err); } } simutrans-124.3/src/simutrans/network/network_cmp_pakset.h000066400000000000000000000031161474050137200241310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_CMP_PAKSET_H #define NETWORK_NETWORK_CMP_PAKSET_H #include "network_cmd.h" #include "pakset_info.h" #include /** * Compare paksets on server and client * client side of communication * @param cp url of server * @param msg contains html-text of differences to be displayed in a help_frame window */ void network_compare_pakset_with_server(const char* cp, std::string &msg); /** * nwc_pakset_info_t * @from-client: client wants to get pakset info from server * @from-server: server sends pakset info back to client */ class nwc_pakset_info_t : public network_command_t { public: nwc_pakset_info_t(uint8 flag_=UNDEFINED) : network_command_t(NWC_PAKSETINFO), flag(flag_), name(NULL), chk(NULL) {} ~nwc_pakset_info_t(); bool execute(karte_t *) OVERRIDE; void rdwr() OVERRIDE; enum { CL_INIT = 0, // client want pakset info CL_WANT_NEXT = 1, // client received one info packet, wants next CL_QUIT = 2, // client ends this negotiation SV_ERROR = 10, // server busy etc SV_PAKSET = 11, // server sends pakset checksum SV_DATA = 12, // server sends data SV_LAST = 19, // server sends last info packet UNDEFINED = 255 }; uint8 flag; // name of and info about descriptor char *name; checksum_t *chk; void clear() { name = NULL; chk = NULL; } // for the communication of the server with the client static stringhashtable_tpl::iterator server_iterator; static SOCKET server_receiver; }; #endif simutrans-124.3/src/simutrans/network/network_file_transfer.cc000066400000000000000000000402671474050137200247740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_file_transfer.h" #include "../simdebug.h" #include "../simloadingscreen.h" #include "../sys/simsys.h" #include #include #include "../utils/cbuffer.h" #ifndef NETTOOL #include "../dataobj/translator.h" #else #define dr_remove remove #define dr_fopen fopen #endif #include "../simversion.h" /* * Functions required by both Simutrans and Nettool */ const char *network_receive_file(const SOCKET src_sock, const char *const save_as, sint32 const length, sint32 const timeout ) { // ok, we have a socket to connect dr_remove(save_as); DBG_MESSAGE("network_receive_file", "File size %i", length ); if(length>0) { #ifndef NETTOOL // no display, no translator available loadingscreen_t ls(translator::translate("Downloading"),length,true,true); #endif // good place to show a progress bar char rbuf[4096]; sint32 length_read = 0; if (FILE* const f = dr_fopen(save_as, "wb")) { while(length_read < length) { if( timeout > 0 ) { /** 10s for 4096 bytes: * As long as you are not connected with less than 1200 Baud that should be fine * otherwise upgrade your acoustic coupler to 56k ... */ fd_set fds; FD_ZERO(&fds); FD_SET(src_sock,&fds); struct timeval tv; // 10 s timeout tv.tv_sec = 10000 / 1000; tv.tv_usec = (10000 % 1000) * 1000ul; // can we read? if( select( FD_SETSIZE, &fds, NULL, NULL, &tv )!=1 ) { dbg->warning("network_receive_file", "Timeout during transfer: %s", strerror(errno) ); break; } } // ok, now here should be something new to read int i = recv(src_sock, rbuf, length_read + 4096 < length ? 4096 : length - length_read, 0); if (i > 0) { fwrite(rbuf, 1, i, f); length_read += i; #ifndef NETTOOL ls.set_progress(length_read); #endif } else { if (i < 0) { dbg->warning("network_receive_file", "recv failed with %i", i); } break; } } fclose(f); } if( length_read(nwc); if (nwgi==NULL) { err = "Protocol error (expected NWC_GAMEINFO)"; goto end; } if (nwgi->len==0) { err = "Server busy"; goto end; } len = nwgi->len; sprintf( filename, "client%i-network.sve", nwgi->len ); err = network_receive_file( my_client_socket, filename, len ); if (err == NULL) { // now into gameinfo const loadsave_t::file_status_t status = fd.rd_open( filename ); if( status == loadsave_t::FILE_STATUS_ERR_FUTURE_VERSION ) { err = "Server version too new"; } else if( status == loadsave_t::FILE_STATUS_ERR_NO_VERSION ) { err = "Unknown server version"; } else if( status != loadsave_t::FILE_STATUS_OK ) { err = "Server busy"; } else if( fd.is_version_less(120, 8) ) { // Querying gameinfo of older server versions may crash the client // See gameinfo_t::rdwr err = "Server version too old"; } else { *gi = gameinfo_t( &fd ); } fd.close(); } dr_remove( filename ); end: socket_list_t::remove_client( my_client_socket ); } network_close_socket( my_client_socket ); if(err) { dbg->warning("network_gameinfo", err); } return err; } // connect to address (cp), receive game, save to client%i-network.sve const char *network_connect(const char *cp, karte_t *world) { // open from network const char *err = NULL; SOCKET const my_client_socket = network_open_address(cp, err); if( err==NULL ) { // want to join { nwc_join_t nwc_join( env_t::nickname.c_str() ); nwc_join.rdwr(); if (!nwc_join.send(my_client_socket)) { err = "send of NWC_JOIN failed"; goto end; } } socket_list_t::reset(); socket_list_t::add_client(my_client_socket); // wait for join command (tolerate some wrong commands) network_command_t *nwc = NULL; for(uint8 i=0; i<5; i++) { nwc = network_check_activity(10000); if (nwc && nwc->get_id() == NWC_JOIN) break; } if (nwc==NULL) { err = "Server did not respond!"; goto end; } nwc_join_t *nwj = dynamic_cast(nwc); if (nwj==NULL) { err = "Protocol error (expected NWC_JOIN)"; goto end; } if (nwj->answer!=1) { err = "Server busy"; goto end; } // set nickname env_t::nickname = nwj->nickname.c_str(); network_set_client_id(nwj->client_id); // update map counter // wait for sync command (tolerate some wrong commands) for( uint8 i=0; i<5; ++i ) { nwc = network_check_activity(10000); if( nwc && nwc->get_id()==NWC_SYNC ) break; } if( nwc==NULL || nwc->get_id()!=NWC_SYNC ) { err = "Protocol error (expected NWC_SYNC)"; goto end; } world->set_map_counter( ((nwc_sync_t*)nwc)->get_new_map_counter() ); // receive nwc_game_t { #ifndef NETTOOL // no display, no translator available loadingscreen_t ls(translator::translate("Server preparing game ..."),300,true,true); #endif // wait for game command for 5 min (tolerate some wrong commands) to leave it enough time for saving for(int i=0; i<300; i++) { #ifndef NETTOOL // no display, no translator available ls.set_progress(i); #endif nwc = network_check_activity(1000); if (nwc && nwc->get_id() == NWC_GAME) { break; } } } if (nwc == NULL || nwc->get_id()!=NWC_GAME) { err = "Protocol error (expected NWC_GAME)"; goto end; } int len = ((nwc_game_t*)nwc)->len; // guaranteed individual file name ... char filename[256]; sprintf( filename, "client%i-network.sve", network_get_client_id() ); err = network_receive_file( my_client_socket, filename, len ); } end: if(err) { dbg->warning("network_connect", err); if (!socket_list_t::remove_client(my_client_socket)) { network_close_socket( my_client_socket ); } } else { const uint32 id = socket_list_t::get_client_id(my_client_socket); socket_list_t::change_state(id, socket_info_t::playing); } return err; } const char *network_send_file( const SOCKET dst_sock, const char *filename ) { FILE *fp = dr_fopen(filename,"rb"); if (fp == NULL) { dbg->warning("network_send_file", "could not open file %s", filename); return "Could not open file"; } char buffer[1024]; // find out length fseek(fp, 0, SEEK_END); long length = (long)ftell(fp); rewind(fp); uint32 bytes_sent = 0; // send size of file nwc_game_t nwc(length); if (dst_sock==INVALID_SOCKET || !nwc.send(dst_sock)) { goto error; } // good place to show a progress bar if(length>0) { loadingscreen_t ls( translator::translate("Transferring game ..."), length, true, true ); while( !feof(fp) ) { int bytes_read = (int)fread( buffer, 1, sizeof(buffer), fp ); uint16 dummy; if( !network_send_data(dst_sock, buffer, bytes_read, dummy, 250) ) { socket_list_t::remove_client(dst_sock); goto error; } bytes_sent += bytes_read; ls.set_progress( bytes_sent ); } } // ok, new client has savegame fclose(fp); return NULL; error: // an error occurred: close file fclose(fp); return "Client closed connection during transfer"; } /// POST a message (poststr) to an HTTP server at the specified address and relative path (name) /// Optionally: Receive response to file localname const char *network_http_post( const char *address, const char *name, const char *poststr, const char *localname ) { DBG_MESSAGE("network_http_post", address); // Open socket const char *err = NULL; SOCKET const my_client_socket = network_open_address(address, err); if (err==NULL) { #ifndef REVISION # define REVISION 0 #endif const char* format = "POST %s HTTP/1.1\r\n" "User-Agent: Simutrans/r%s\r\n" "Host: %s\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %d\r\n\r\n%s"; if ((strlen(format) + strlen(name) + strlen(address) + strlen(poststr) + strlen(QUOTEME(REVISION))) > 4060) { // We will get a buffer overwrite here if we continue dbg->fatal( "network_http_post", "Error: String too long (>4096)" ); } DBG_MESSAGE("network_http_post", "2"); char request[4096]; int const len = sprintf(request, format, name, QUOTEME(REVISION), address, strlen(poststr), poststr); uint16 dummy; if (!network_send_data(my_client_socket, request, len, dummy, 250)) { err = "Server did not respond!"; } DBG_MESSAGE("network_http_post", "3"); // Read the response header // line is max length of a header line // rbuf is a single char char line[1024], rbuf; unsigned int pos = 0; sint32 length = 0; // TODO better handling of error message from listing server // TODO while(1) { // Returns number of bytes received // Receive one char from socket into rbuf int i = recv( my_client_socket, &rbuf, 1, 0 ); if( i>0 ) { // If char is above 32 in ascii table + not going to overflow line[] // Note: This will truncate any header to 1023 chars! // Add char to line at the next position // This ignores non-printable chars, including the CR char if( rbuf>=32 && pos now data will follow break; } // NUL at the end of our constructed line string line[pos] = 0; // we only need the length tag // Compare string so far constructed against the header we // are seeking (e.g. Content-Length) DBG_MESSAGE("network_http_post", "received header: %s", line); if( STRNICMP("Content-Length:",line,15)==0 ) { length = atol( line+15 ); } // Begin again to parse the next line pos = 0; } } else { break; } } DBG_MESSAGE("network_http_post", "5"); // for a simple query, just pass an empty filename if( localname && *localname ) { err = network_receive_file( my_client_socket, localname, length ); } network_close_socket( my_client_socket ); } else { dbg->warning("network_http_post()", "failed with %s", err); } return err; } const char* network_http_get(const char* address, const char* name, cbuffer_t& local) { const int REQ_HEADER_LEN = 1024; // open from network const char* err = NULL; SOCKET const my_client_socket = network_open_address(address, err); if (err == NULL) { #ifndef REVISION # define REVISION 0 #endif const char* format = "GET %s HTTP/1.1\r\n" "User-Agent: Simutrans/r%s\r\n" "Host: %s\r\n\r\n"; if ((strlen(format) + strlen(name) + strlen(address) + strlen(QUOTEME(REVISION))) > (REQ_HEADER_LEN - 1)) { // We will get a buffer overwrite here if we continue return "Error: String too long"; } char request[REQ_HEADER_LEN]; int const len = sprintf(request, format, name, QUOTEME(REVISION), address); uint16 dummy; if (!network_send_data(my_client_socket, request, len, dummy, 250)) { err = "Server did not respond!"; } // Read the response header and parse arguments as needed char line[1024], rbuf; unsigned int pos = 0; sint32 length = 0; while (1) { // Receive one character at a time the HTTP headers int i = recv(my_client_socket, &rbuf, 1, 0); if (i > 0) { if (rbuf >= 32 && pos < sizeof(line) - 1) { line[pos++] = rbuf; } if (rbuf == 10) { if (pos == 0) { // this line was empty => now data will follow break; } line[pos] = 0; DBG_MESSAGE("network_http_get", "received header: %s", line); // Parse out the length tag to get length of content if (STRNICMP("Content-Length:", line, 15) == 0) { length = atol(line + 15); } pos = 0; } } else { break; } } // Make buffer to receive data into char* buffer = new char[length + 1]; uint16 bytesreceived = 0; if (!network_receive_data(my_client_socket, buffer, length, bytesreceived, 10000)) { err = "Error: network_receive_data failed!"; } else if (bytesreceived != length) { err = "Error: Bytes received does not match length!"; } else { buffer[length] = 0; local.append(buffer, length); } DBG_MESSAGE("network_http_get", "received data length: %i", local.len()); delete[] buffer; network_close_socket(my_client_socket); } return err; } const char *network_http_get_file( const char* address, const char* name, const char *filename ) { const int REQ_HEADER_LEN = 1024; // open from network const char *err = NULL; SOCKET const my_client_socket = network_open_address( address, err ); if ( err==NULL ) { #ifndef REVISION # define REVISION 0 #endif const char* format = "GET %s HTTP/1.1\r\n" "User-Agent: Simutrans/r%s\r\n" "Host: %s\r\n\r\n"; if ( (strlen( format ) + strlen( name ) + strlen( address ) + strlen( QUOTEME(REVISION)) ) > ( REQ_HEADER_LEN - 1 ) ) { // We will get a buffer overwrite here if we continue return "Error: String too long"; } char request[REQ_HEADER_LEN]; int const len = sprintf( request, format, name, QUOTEME(REVISION), address ); uint16 dummy; if ( !network_send_data( my_client_socket, request, len, dummy, 250 ) ) { err = "Server did not respond!"; } // Read the response header and parse arguments as needed char line[1024], rbuf; unsigned int pos = 0; sint32 length = 0; while(pos 0 ) { if ( rbuf >= 32 && pos < sizeof(line) - 1 ) { line[pos++] = rbuf; } if ( rbuf == 10 ) { if ( pos > 0 && line[pos-1]==10) { line[pos++] = 10; line[pos++] = 0; // this line was empty => now data will follow break; } line[pos++] = 10; } } else { break; } } DBG_DEBUG("network_http_get_file()", "%s", line); int http_code = atoi(strchr(line, ' ')); // if not sucessful maybe redirect if(http_code==302 || http_code==301) { network_close_socket(my_client_socket); char new_ip[1024]; char new_path[1024]; if(char *c= tstrcasestr(line,"\nLocation: http://")) { tstrncpy(new_ip, c + 18, lengthof(new_ip)); if(char *c = strchr(new_ip, '/')) { tstrncpy(new_path, c, lengthof(new_path)); strcpy( c, ":80"); *strchr(new_path, 10) = 0; return network_http_get_file(new_ip, new_path, filename); } } if (tstrcasestr(line, "\nLocation: https://")) { return "Cannot handle https."; } return "Unknown redirect."; } if (http_code == 200) { if (char *c=strstr(line,"Content-Length:")) { length = atol(c + 15); } DBG_MESSAGE("network_http_get", "received data length: %i", length); err = network_receive_file(my_client_socket, filename, length); } else { static char err_code[64]; sprintf(err_code,"Cannot handle https: Server returned %d", http_code); err = err_code; } network_close_socket( my_client_socket ); } return err; } #endif simutrans-124.3/src/simutrans/network/network_file_transfer.h000066400000000000000000000030211474050137200246210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_FILE_TRANSFER_H #define NETWORK_NETWORK_FILE_TRANSFER_H /** * Contains functions to send & receive files over network * .. and to connect to a running simutrans server */ #include "network.h" class cbuffer_t; class karte_t; class gameinfo_t; // connect to address (cp), receive gameinfo, close const char *network_gameinfo(const char *cp, gameinfo_t *gi); // connects to server at (cp), receives game, save to client%i-network.sve const char *network_connect(const char *cp, karte_t *world); /// Send file over network const char *network_send_file(const SOCKET dst_sock, const char *filename); /// Receive file (directly to disk) const char *network_receive_file(const SOCKET src_sock, const char *const save_as, const sint32 length, const sint32 timeout=10000); /** * Use HTTP POST request to submit poststr to an HTTP server * Any response is saved to the file given by localname (pass NULL to ignore response) * Connection is closed after request is completed */ const char *network_http_post ( const char *address, const char *name, const char *poststr, const char *localname ); /** * Use HTTP to retrieve a file into the cbuffer_t object provided */ const char *network_http_get ( const char *address, const char *name, cbuffer_t& local ); /** * Use HTTP to retrieve a file into the FILE */ const char* network_http_get_file( const char* address, const char* name, const char *filename ); #endif simutrans-124.3/src/simutrans/network/network_packet.cc000066400000000000000000000053731474050137200234170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "network_packet.h" #include "network_socket_list.h" void packet_t::rdwr_header() { rdwr_short( size ); rdwr_short( version ); rdwr_short( id ); if (version > NETWORK_VERSION) { error = true; } } packet_t::packet_t() : memory_rw_t(buf,MAX_PACKET_LEN,true), size(0), version(NETWORK_VERSION), id(0), sock(INVALID_SOCKET), error(false), ready(false), count(0) { set_index(HEADER_SIZE); } packet_t::packet_t(const packet_t &p) : memory_rw_t(buf,MAX_PACKET_LEN,true) { version = p.version; id = p.id; error = p.error; ready = p.ready; sock = INVALID_SOCKET; size = 0; count = 0; uint16 index = p.get_current_index(); for(uint16 i = 0; i MAX_PACKET_LEN) { dbg->warning("packet_t::recv", "packet from [%d] has wrong size (%d)", sock, size); error = true; return; } } else { return; } } if (count >= HEADER_SIZE) { received = 0; if (!network_receive_data(sock, buf + count, size - count, received, 0)) { error = true; return; } count += received; if (count == size) { set_max_size(size); ready = true; } } } void packet_t::send(SOCKET s, bool complete) { if (has_failed()) { return; } // header written ? if (size == 0) { size = get_current_index(); // write header at right place set_index(0); set_max_size(HEADER_SIZE); rdwr_header(); } uint16 sent; const int timeout_ms = complete ? 250 : 0; if ( !network_send_data(s, (const char*) buf+count, size-count, sent, timeout_ms) ) { dbg->warning("packet_t::send", "error while sending to [%d]", s); error = true; return; } count += sent; // ready ? if (count == size) { ready = true; dbg->message("packet_t::send", "sent %d bytes to socket[%d]; id=%d, size=%d", count, s, id, size); } else { dbg->message("packet_t::send", "sent %d bytes to socket[%d]; id=%d, size=%d, left=%d", count, s, id, size, size-count); } } void packet_t::sent_by_server() { sock = socket_list_t::get_socket(0); } simutrans-124.3/src/simutrans/network/network_packet.h000066400000000000000000000033471474050137200232600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_PACKET_H #define NETWORK_NETWORK_PACKET_H #include "../simtypes.h" #include "memory_rw.h" #include "network.h" #define MAX_PACKET_LEN (8192) // static const do not work on all compilers/architectures #define HEADER_SIZE (6) // the network sizes are given ... class packet_t : public memory_rw_t { private: // the buffer uint8 buf[MAX_PACKET_LEN]; // the header // [0] size uint16 size; // [2] version uint16 version; // [4] id uint16 id; // who sent this packet SOCKET sock; bool error:1; // ready for sending / fully received bool ready:1; // how much already sent / received uint16 count; void rdwr_header(); public: /** * constructor: packet is in saving-mode */ packet_t(); packet_t(const packet_t &p); /** * constructor: packet is in loading-mode * @param s socket from where the packet has to be received */ packet_t(SOCKET s); /** * start/continue sending * sets bools ready or error * * @param s * @param complete forces to send the complete packet */ void send(SOCKET s, bool complete); /** * start/continue receiving * sets bools ready or error */ void recv(); bool has_failed() const { return error || is_overflow();} void failed() { error = true; } bool is_ready() const { return ready; } // can we understand the received packet? bool check_version() const { return is_saving() || (version <= NETWORK_VERSION); } uint16 get_id() const { return id; } void set_id(uint16 id_) { id = id_; } SOCKET get_sender() { return sock; } /** * mark this packet as sent by the server * @see network_send_server */ void sent_by_server(); }; #endif simutrans-124.3/src/simutrans/network/network_socket_list.cc000066400000000000000000000227111474050137200244660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "network_socket_list.h" #include "network_cmd.h" #include "network_cmd_ingame.h" #include "network_packet.h" #ifndef NETTOOL #include "../dataobj/environment.h" #endif bool connection_info_t::operator==(const connection_info_t& other) const { return (address.get_ip() == other.address.get_ip()) && ( strcmp(nickname.c_str(), other.nickname.c_str())==0 ); } void socket_info_t::reset() { delete packet; packet = NULL; while(!send_queue.empty()) { packet_t *p = send_queue.remove_first(); delete p; } if (socket != INVALID_SOCKET) { network_close_socket(socket); } if (state != has_left) { state = inactive; } socket = INVALID_SOCKET; player_unlocked = 0; } network_command_t* socket_info_t::receive_nwc() { if (!is_active()) { return NULL; } if (packet == NULL) { packet = new packet_t(socket); } packet->recv(); if (packet->has_failed()) { // close this client (will delete packet) socket_list_t::remove_client(socket); } else if (packet->is_ready()) { // create command network_command_t *nwc = network_command_t::read_from_packet(packet); // the network_command takes care of deleting packet packet = NULL; return nwc; } return NULL; } void socket_info_t::process_send_queue() { while(!send_queue.empty()) { packet_t *p = send_queue.front(); p->send(socket, false); if (p->has_failed()) { // close this client, clear the send_queue socket_list_t::remove_client(socket); break; } else if (p->is_ready()) { // packet complete sent, remove from queue send_queue.remove_first(); delete p; // proceed with next packet } else { break; } } } void socket_info_t::send_queue_append(packet_t *p) { if (p) { if (!p->has_failed()) { send_queue.append(p); } else { delete p; } } } void socket_info_t::rdwr(packet_t *p) { address.rdwr(p); } /** * list: contains _all_ sockets * with the convention that all server_sockets are at indices 0..server_sockets-1 */ vector_tplsocket_list_t::list(20); uint32 socket_list_t::connected_clients; uint32 socket_list_t::playing_clients; /** * server: max number of server_sockets ever created * do not decrease! * client: number of server connections */ uint32 socket_list_t::server_sockets; /** * book-keeping for the number of connected / playing clients */ void socket_list_t::book_state_change(socket_info_t::connection_state_t state, sint8 incr) { switch (state) { case socket_info_t::connected: connected_clients += incr; break; case socket_info_t::playing: playing_clients += incr; break; // do not change case socket_info_t::inactive: case socket_info_t::server: default: break; } } void socket_list_t::change_state(uint32 id, socket_info_t::connection_state_t new_state) { book_state_change(list[id]->state, -1); list[id]->state = new_state; list[id]->player_unlocked = 0; book_state_change(list[id]->state, +1); } void socket_list_t::reset() { for(socket_info_t* const i : list) { i->reset(); } connected_clients = 0; playing_clients = 0; server_sockets = 0; } void socket_list_t::reset_clients() { for(uint32 j=server_sockets; jreset(); } connected_clients = 0; playing_clients = 0; } void socket_list_t::add_client( SOCKET sock, uint32 ip ) { dbg->message("socket_list_t::add_client", "add client socket[%d] at address %xd", sock, ip); uint32 i = list.get_count(); // check whether socket already added for( uint32 j=server_sockets; jsocket == sock && list[j]->state != socket_info_t::inactive ) { return; } if( list[j]->state == socket_info_t::inactive && i == list.get_count() ) { i = j; } } if( i == list.get_count() ) { list.append(new socket_info_t() ); } list[i]->socket = sock; list[i]->address = net_address_t(ip, 0); change_state( i, socket_info_t::connected ); network_set_socket_nodelay( sock ); } void socket_list_t::add_server( SOCKET sock ) { dbg->message("socket_list_t::add_server", "add server socket[%d]", sock); assert(connected_clients==0 && playing_clients==0); uint32 i = server_sockets; // check whether socket already added for(uint32 j=0; jsocket == sock && list[j]->state == socket_info_t::server) { return; } if (list[j]->state == socket_info_t::inactive && i == server_sockets) { i = j; } } if (i == server_sockets) { list.insert_at(server_sockets, new socket_info_t()); server_sockets++; } list[i]->socket = sock; change_state(i, socket_info_t::server); if (i==0) { #ifndef NETTOOL // set server nickname if (!env_t::nickname.empty()) { list[i]->nickname = env_t::nickname.c_str(); } else { list[i]->nickname = "Server#0"; env_t::nickname = list[i]->nickname.c_str(); } #endif } network_set_socket_nodelay( sock ); } bool socket_list_t::remove_client( SOCKET sock ) { dbg->message("socket_list_t::remove_client", "remove client socket[%d]", sock); for(uint32 j=0; jsocket == sock) { #ifdef NETTOOL if (list[j]->state == socket_info_t::playing) { #else if (env_t::server && list[j]->state == socket_info_t::playing) { #endif change_state(j, socket_info_t::has_left); } else { change_state(j, socket_info_t::inactive); } list[j]->reset(); network_close_socket(sock); return true; } } return false; } bool socket_list_t::has_client( SOCKET sock ) { return get_client_id(sock) < list.get_count(); } uint32 socket_list_t::get_client_id( SOCKET sock ){ for(uint32 j=0; jstate != socket_info_t::inactive && list[j]->socket == sock) { return j; } } return list.get_count(); } void socket_list_t::unlock_player_all(uint8 player_nr, bool unlock, uint32 except_client) { // nettool does not know about nwc_auth_player_t #ifndef NETTOOL for(uint32 i=0; istate == socket_info_t::playing) ) { uint16 old_player_unlocked = list[i]->player_unlocked; if (unlock) { list[i]->unlock_player(player_nr); } else { list[i]->lock_player(player_nr); } if (old_player_unlocked != list[i]->player_unlocked) { dbg->warning("socket_list_t::unlock_player_all", "old = %d new = %d id = %d", old_player_unlocked, list[i]->player_unlocked, i); // tell the player nwc_auth_player_t *nwc = new nwc_auth_player_t(); nwc->player_unlocked = list[i]->player_unlocked; if (i==0) { network_send_server(nwc); } else { nwc->send(list[i]->socket); delete nwc; } } } } #else (void) player_nr; (void) unlock; (void) except_client; #endif } void socket_list_t::send_all(network_command_t* nwc, bool only_playing_clients, uint8 player_nr) { if (nwc == NULL) { return; } for(uint32 i=server_sockets; iis_active() && list[i]->socket!=INVALID_SOCKET && (!only_playing_clients || list[i]->state == socket_info_t::playing || list[i]->state == socket_info_t::connected) && (player_nr >= PLAYER_UNOWNED || list[i]->is_player_unlocked(player_nr)) ) { packet_t *p = nwc->copy_packet(); list[i]->send_queue_append(p); } } } plainstring socket_list_t::get_all_nicks() { std::string nicks #if COLOUR_DEPTH>0 // only add server nick, if server has a gui = env_t::nickname #endif ; for (uint32 i = server_sockets; i < list.get_count(); i++) { if (list[i]->is_active() && list[i]->socket != INVALID_SOCKET && (list[i]->state == socket_info_t::playing || list[i]->state == socket_info_t::connected) ) { if (!nicks.empty()) { nicks += "\t"; } nicks += list[i]->nickname; } } return nicks.c_str(); } SOCKET socket_list_t::fill_set(fd_set *fds) { SOCKET s_max = 0; for(socket_info_t* const i : list) { if (i->state != socket_info_t::inactive && i->socket != INVALID_SOCKET) { SOCKET const s = i->socket; s_max = max( s, s_max ); FD_SET( s, fds ); } } return s_max+1; } SOCKET socket_list_t::fd_isset(fd_set *fds, bool use_server_sockets, uint32 *offset) { const uint32 begin = offset ? *offset : (use_server_sockets ? 0 : server_sockets); const uint32 end = use_server_sockets ? server_sockets : list.get_count(); for(uint32 i=begin; isocket; if (socket!=INVALID_SOCKET) { if( FD_ISSET(socket, fds) ) { if (offset) { *offset = i+1; } return socket; } } } if (offset) { *offset = end; } return INVALID_SOCKET; } socket_list_t::socket_iterator_t::socket_iterator_t(fd_set *fds) { index = 0; this->fds = fds; current = INVALID_SOCKET; } bool socket_list_t::server_socket_iterator_t::next() { current = socket_list_t::fd_isset(fds, true, &index); return current != INVALID_SOCKET; } bool socket_list_t::client_socket_iterator_t::next() { current = socket_list_t::fd_isset(fds, false, &index); return current != INVALID_SOCKET; } void socket_list_t::rdwr(packet_t *p, vector_tpl *list) { assert(p->is_saving() || list!=&socket_list_t::list); uint32 count = list->get_count(); p->rdwr_long(count); for(uint32 i=0; iis_loading()) { list->append(new socket_info_t()); } uint8 s = (*list)[i]->state; p->rdwr_byte(s); (*list)[i]->state = socket_info_t::connection_state_t(s); if ( s==socket_info_t::playing) { (*list)[i]->rdwr(p); } } } simutrans-124.3/src/simutrans/network/network_socket_list.h000066400000000000000000000143561474050137200243360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_NETWORK_SOCKET_LIST_H #define NETWORK_NETWORK_SOCKET_LIST_H #include "network.h" #include "network_address.h" #include "../simconst.h" #include "../tpl/slist_tpl.h" #include "../tpl/vector_tpl.h" #include "../utils/plainstring.h" class network_command_t; class packet_t; /** * Class to store pairs of (address, nickname) for logging and admin purposes. */ class connection_info_t { public: /// address of connection net_address_t address; /// client nickname plainstring nickname; connection_info_t() : address(), nickname() {} connection_info_t(const connection_info_t& other) : address(other.address), nickname(other.nickname) {} template void rdwr(F *packet) { address.rdwr(packet); packet->rdwr_str(nickname); } bool operator==(const connection_info_t& other) const; bool operator!=(const connection_info_t& other) const { return !(*this == other); } }; class socket_info_t : public connection_info_t { public: enum connection_state_t { inactive = 0, ///< client disconnected server = 1, ///< server socket connected = 2, ///< connection established but client does not participate in the game yet playing = 3, ///< client actively plays has_left = 4, ///< was playing but left admin = 5 ///< admin connection }; private: packet_t *packet; slist_tpl send_queue; public: connection_state_t state; SOCKET socket; uint16 player_unlocked; public: socket_info_t() : connection_info_t(), packet(0), send_queue(), state(inactive), socket(INVALID_SOCKET), player_unlocked(0) {} ~socket_info_t(); /** * marks all information as invalid * closes socket, deletes packet */ void reset(); bool is_active() const { return state != inactive; } /** * receive the next command: continues receiving the packet * if an error occurs while receiving the packet, (this) is reset * @return the command if packet is fully received */ network_command_t* receive_nwc(); /** * */ void process_send_queue(); void send_queue_append(packet_t *p); /** * rdwr client information to packet */ void rdwr(packet_t *p); /** * human players on this connection can play with in-game companies/players? */ bool is_player_unlocked(uint8 player_nr) const { return (player_nr < PLAYER_UNOWNED) && ((player_unlocked & 1<list; static uint32 connected_clients; static uint32 playing_clients; static uint32 server_sockets; public: static uint32 get_server_sockets() { return server_sockets; } static uint32 get_connected_clients() { return connected_clients; } static uint32 get_playing_clients() { return playing_clients; } /** * clears list, closes all sockets */ static void reset(); /** * clears and closes all client sockets */ static void reset_clients(); /** * adds server socket * assumes that no active client sockets are present */ static void add_server( SOCKET sock ); /** * server: adds client socket (ie connection to client) * client: adds client socket (ie connection to server) */ static void add_client( SOCKET sock, uint32 ip = 0 ); /** * @ returns true if socket is already in our list */ static bool has_client( SOCKET sock ); /** * @return true if client was found and removed */ static bool remove_client( SOCKET sock ); static uint32 get_client_id( SOCKET sock ); static bool is_valid_client_id( uint32 client_id ) { return client_id < list.get_count(); } uint32 static get_count() { return list.get_count(); } static SOCKET get_socket( uint32 client_id ) { return client_id < list.get_count() && list[client_id]->state != socket_info_t::inactive ? list[client_id]->socket : INVALID_SOCKET; } static socket_info_t& get_client(uint32 client_id ) { assert (client_id < list.get_count()); return *list[client_id]; } /** * unlocks/locks player for all clients, except client number except_client */ static void unlock_player_all(uint8 player_nr, bool unlock, uint32 except_client = list.get_count()); /** * send command to all clients * * @param nwc * @param only_playing_clients if true then send only to playing clients * @param player_nr if != PLAYER_UNOWNED then only send to clients with this player unlocked */ static void send_all(network_command_t* nwc, bool only_playing_clients, uint8 player_nr = PLAYER_UNOWNED); static plainstring get_all_nicks(); static void change_state(uint32 id, socket_info_t::connection_state_t new_state); /** * rdwr client-list information to packet */ static void rdwr(packet_t *p, vector_tpl *writeto=&list); private: static void book_state_change(socket_info_t::connection_state_t state, sint8 incr); public: // from now stuff to deal with fd_set's /** * @param fds * @param offset pointer to an offset * @return the first client whose bit is set in fd_set */ static SOCKET fd_isset(fd_set *fds, bool use_server_sockets, uint32 *offset=NULL); /** * fill set with all active sockets */ static SOCKET fill_set(fd_set *fds); /** * iterators to iterate through all sockets whose bits are set in fd_set */ class socket_iterator_t { protected: uint32 index; // index to the socket list fd_set *fds; // fds as modified by select(), be sure it gets not deleted while the iterator is alive SOCKET current; public: socket_iterator_t(fd_set *fds); SOCKET get_current() const { return current; } }; /** * .. iterate through server sockets */ class server_socket_iterator_t : public socket_iterator_t { public: server_socket_iterator_t(fd_set *fds) : socket_iterator_t(fds) {} bool next(); }; /** * .. and client sockets */ class client_socket_iterator_t : public socket_iterator_t { public: client_socket_iterator_t(fd_set *fds) : socket_iterator_t(fds) { index = server_sockets; } bool next(); }; }; #endif simutrans-124.3/src/simutrans/network/pakset_info.cc000066400000000000000000000033531474050137200226750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "pakset_info.h" #include "../simdebug.h" #include "../dataobj/translator.h" #include "../dataobj/pakset_manager.h" #include "../tpl/vector_tpl.h" #include "../utils/cbuffer.h" stringhashtable_tpl pakset_info_t::info; checksum_t pakset_info_t::general; void pakset_info_t::append(const char* name, const char* type, checksum_t *chk) { chk->finish(); static cbuffer_t buf; buf.clear(); buf.printf("%s:%s", type, name); checksum_t *old = info.set( strdup( (const char*)buf), chk ); if (old) { if (*chk == *old) { dbg->warning("pakset_info_t::append", "Object %s::%s is overlaid by identical object, using data of new object", type, name); } else { dbg->warning("pakset_info_t::append", "Object %s::%s is overlaid by different object, using data of new object", type, name); pakset_manager_t::doubled(type, name); } } delete old; } void pakset_info_t::debug() { #if MSG_LEVEL >= 4 for(auto const& i : info) { DBG_DEBUG4("pakset_info_t::debug", "%.30s -> sha1 = %s", i.key, i.value->get_str()); } #endif } /** * order all pak checksums by name */ struct entry_t { entry_t(const char* n=NULL, const checksum_t* i=NULL) : name(n), chk(i) {} const char* name; const checksum_t* chk; }; static bool entry_cmp(entry_t a, entry_t b) { return strcmp(a.name, b.name) < 0; } void pakset_info_t::calculate_checksum() { general.reset(); // first sort all the desc's vector_tpl sorted(info.get_count()); for(auto const& i : info) { sorted.insert_ordered(entry_t(i.key, i.value), entry_cmp); } // now loop for(entry_t const& i : sorted) { i.chk->calc_checksum(&general); } general.finish(); } simutrans-124.3/src/simutrans/network/pakset_info.h000066400000000000000000000020151474050137200225310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef NETWORK_PAKSET_INFO_H #define NETWORK_PAKSET_INFO_H #include "../tpl/stringhashtable_tpl.h" #include "../descriptor/objversion.h" #include "checksum.h" class pakset_info_t { /** * checksums of all desc's * since their names are unique we can index them by name */ static stringhashtable_tpl info; /** * pakset checksum */ static checksum_t general; public: static const checksum_t& get_pakset_checksum() { return general; } static const stringhashtable_tpl& get_info() { return info; } static void calculate_checksum(); static checksum_t* get_checksum() { return &general; } /** * Register object with given @p name and @p type. * Sends warning to pakset_manager_t for objects with same name, type but different checksum. */ static void append(const char* name, const char* type, checksum_t *chk); static void debug(); friend class nwc_pakset_info_t; }; #endif simutrans-124.3/src/simutrans/obj/000077500000000000000000000000001474050137200171415ustar00rootroot00000000000000simutrans-124.3/src/simutrans/obj/baum.cc000066400000000000000000000166421474050137200204050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "baum.h" #include "groundobj.h" #include "../ground/grund.h" #include "../dataobj/environment.h" #include "../dataobj/freelist.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../descriptor/tree_desc.h" #include "../display/simimg.h" #include "../player/simplay.h" #include "../simdebug.h" #include "../simtypes.h" #include "../world/simworld.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include #include #include FLAGGED_PIXVAL baum_t::outline_color = 0; freelist_tpl baum_t::fl; baum_t::baum_t(loadsave_t *file) : obj_t(), geburt(welt->get_current_month()), tree_id(0), season(0) { rdwr(file); } baum_t::baum_t(koord3d pos) : obj_t(pos), geburt(welt->get_current_month() - simrand(baum_t::AGE_LIMIT-1)), // generate aged trees, might underflow season(0) { tree_id = (uint8)tree_builder_t::random_tree_id_for_climate( welt->get_climate( pos.get_2d() ) ); calc_off( welt->lookup( get_pos())->get_grund_hang() ); calc_image(); } baum_t::baum_t(koord3d pos, uint8 type, uint16 age, slope_t::type slope ) : obj_t(pos), geburt(welt->get_current_month() - age), // might underflow tree_id(type), season(0) { calc_off( slope ); calc_image(); } baum_t::baum_t(koord3d pos, const tree_desc_t *desc) : obj_t(pos), geburt(welt->get_current_month()), tree_id(tree_builder_t::get_id_by_desc(desc)), season(0) { calc_off( welt->lookup( get_pos())->get_grund_hang() ); calc_image(); } void baum_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "baum_t" ); obj_t::rdwr(file); uint32 age = get_age() << 18; file->rdwr_long(age); // after loading, calculate anew age &= 0xFFF << 18; geburt = welt->get_current_month() - (age>>18); if(file->is_loading()) { char buf[128]; file->rdwr_str(buf, lengthof(buf)); const tree_desc_t *desc = tree_builder_t::get_desc_by_name( buf ); if( !desc ) { desc = tree_builder_t::get_desc_by_name( translator::compatibility_name(buf) ); } if( desc ) { tree_id = tree_builder_t::get_id_by_desc( desc ); } else { // not a tree tree_id = tree_builder_t::get_num_trees(); } } else { const char *c = get_desc()->get_name(); file->rdwr_str(c); } // z-offset if(file->is_version_atleast(111, 1)) { uint8 zoff_ = zoff; file->rdwr_byte(zoff_); zoff = zoff_; } else { // correct z-offset if(file->is_loading()) { // this will trigger recalculation of offset in finish_rd() // we cant call calc_off() since this->pos is still invalid set_xoff(-128); } } } void baum_t::finish_rd() { if(get_xoff()==-128) { calc_off(welt->lookup( get_pos())->get_grund_hang()); } } image_id baum_t::get_image() const { if( env_t::hide_trees ) { if( env_t::hide_with_transparency ) { // we need the real age for transparency or real image return IMG_EMPTY; } else { return tree_builder_t::get_tree_image(tree_id, 0, season); } } return tree_builder_t::get_tree_image(tree_id, get_age(), season); // return get_desc()->get_image_id( season, baum_alter ); } // image which transparent outline is used image_id baum_t::get_outline_image() const { return tree_builder_t::get_tree_image(tree_id, get_age(), season); // return get_desc()->get_image_id( season, baum_alter ); } // actually calculates only the season void baum_t::calc_image() { // summer autumn winter spring season = welt->get_season(); if( welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate ) { // snowy winter graphics season = 4; } else if(welt->get_snowline()<=get_pos().z+1 && season==0) { // snowline crossing in summer // so at least some weeks spring/autumn season = welt->get_last_month() <=5 ? 3 : 1; } } FLAGGED_PIXVAL baum_t::get_outline_colour() const { return outline_color; } void baum_t::recalc_outline_color() { outline_color = (env_t::hide_trees && env_t::hide_with_transparency) ? (TRANSPARENT25_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK)) : 0; } /* we should be as fast as possible, because trees are nearly the most common object on a map */ bool baum_t::check_season(const bool) { // take care of birth/death and seasons const uint16 age = get_age(); if( age >= baum_t::SPAWN_PERIOD_START && age < baum_t::SPAWN_PERIOD_START + baum_t::SPAWN_PERIOD_LENGTH ) { // only in this month a tree can span new trees // only 1-3 trees will be planted.... uint8 const c_plant_tree_max = 1 + simrand( welt->get_settings().get_max_no_of_trees_on_square() ); uint retries = 0; for( uint8 c_temp = 0; c_temp < c_plant_tree_max && retries < c_plant_tree_max; c_temp++ ) { if( !tree_builder_t::spawn_tree_near(this) ) { retries++; c_temp--; } } // we make the tree four months older to avoid second spawning geburt -= baum_t::SPAWN_PERIOD_LENGTH; } // tree will die after 704 months (i.e. 58 years 8 months) if( age >= baum_t::AGE_LIMIT ) { mark_image_dirty( get_image(), 0 ); return false; } // update seasonal image const uint8 old_season = season; calc_image(); if( season != old_season ) { mark_image_dirty( get_image(), 0 ); } return true; } void baum_t::rotate90() { // cant use obj_t::rotate90 to rotate offsets as it rotates them only if xoff!=0 sint8 old_yoff = get_yoff() + zoff; sint8 old_xoff = get_xoff(); // rotate position obj_t::rotate90(); // .. and the offsets set_xoff( -2 * old_yoff ); set_yoff( old_xoff/2 - zoff); } void baum_t::recalc_off() { // reconstruct position on tile const sint8 xoff = get_xoff() + 32; // = x+y const sint8 yoff = 2*(get_yoff() + zoff); // = y-x sint8 x = (xoff - yoff) / 2; sint8 y = (xoff + yoff) / 2; calc_off(welt->lookup( get_pos())->get_grund_hang(), x, y); } // calculates tree position on a tile // takes care of slopes void baum_t::calc_off(slope_t::type slope, sint8 x_, sint8 y_) { const sint16 random = (sint16)( get_pos().x + get_pos().y + get_pos().z + slope + tree_id + geburt ); // point on tile (imaginary origin at sw corner, x axis: north, y axis: east sint16 x = x_==-128 ? (random + tree_id) & 31 : x_; sint16 y = y_==-128 ? (random + geburt) & 31 : y_; // the last bit has to be the same y ^= x&1; // bilinear interpolation of tile height const uint32 zoff_ = ((corner_ne(slope) * x * y + corner_nw(slope) * x * (32-y) + corner_se(slope) * (32-x) * y + corner_sw(slope) * (32-x) * (32-y)) * TILE_HEIGHT_STEP) / (32*32); // now zoff between 0 and TILE_HEIGHT_STEP-1 zoff = zoff_ < (uint32)TILE_HEIGHT_STEP ? zoff_ : TILE_HEIGHT_STEP-1u; // xoff must be even set_xoff( x + y - 32 ); set_yoff( (y - x)/2 - zoff); } void baum_t::show_info() { if(env_t::tree_info) { obj_t::show_info(); } } void baum_t::info(cbuffer_t &buf) const { translator::get_obj_info(buf, get_desc()->get_name() ); const int age = (int)get_age(); buf.printf( translator::translate("%i years %i months old."), age/12, (age%12) ); if (char const* const maker = get_desc()->get_copyright()) { buf.append("\n\n"); buf.printf(translator::translate("Constructed by %s"), maker); } } void baum_t::cleanup(player_t *player) { player_t::book_construction_costs(player, welt->get_settings().cst_remove_tree, get_pos().get_2d(), ignore_wt); mark_image_dirty( get_image(), 0 ); } uint16 baum_t::get_age() const { return (welt->get_current_month() - (uint32)geburt) % (1<<12); } simutrans-124.3/src/simutrans/obj/baum.h000066400000000000000000000063741474050137200202500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_BAUM_H #define OBJ_BAUM_H #include "simobj.h" #include "../builder/tree_builder.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../tpl/freelist_tpl.h" #include "../descriptor/tree_desc.h" #include "../simcolor.h" #include "../dataobj/environment.h" #include /** * Simulated trees for Simutrans. */ class baum_t : public obj_t { friend class tree_builder_t; public: static const uint16 AGE_LIMIT = 704; // in months (58 years 8 months). Must be smaller than 4095. static const uint16 SPAWN_PERIOD_START = 512; static const uint16 SPAWN_PERIOD_LENGTH = 4; private: static FLAGGED_PIXVAL outline_color; /// month of birth uint16 geburt; /// type of tree (was 9 but for more compact saves now only 254 different tree types are allowed) uint8 tree_id; uint8 season:3; /// z-offset, max TILE_HEIGHT_STEP i.e. 4 bits uint8 zoff:4; // one bit free ;) static freelist_tpl fl; public: /// Only the load save constructor should be called outside. /// Otherwise I suggest use the plant tree function (@see tree_builder_t) baum_t(loadsave_t *file); baum_t(koord3d pos); /** * @param pos * @param type * @param age Must be smaller than 4095 * @param slope * */ baum_t(koord3d pos, uint8 type, uint16 age, slope_t::type slope ); baum_t(koord3d pos, const tree_desc_t *desc); void* operator new(size_t) { return fl.gimme_node(); } void operator delete(void* p) { return fl.putback_node(p); } public: /// @copydoc obj_t::get_name const char *get_name() const OVERRIDE { return "Baum"; } /// @copydoc obj_t::get_typ typ get_typ() const OVERRIDE { return baum; } /// @copydoc obj_t::rdwr /// @deprecated Only used for loading old saves that did save tree offsets void rdwr(loadsave_t *file) OVERRIDE; /// @copydoc obj_t::finish_rd void finish_rd() OVERRIDE; /// @copydoc obj_t::get_image image_id get_image() const OVERRIDE; /// @copydoc obj_t::get_outline_image image_id get_outline_image() const OVERRIDE; /// @copydoc obj_t::calc_image /// Calculates tree image dependent on tree age void calc_image() OVERRIDE; /// @copydoc obj_t::get_outline_colour /// hide trees eventually with transparency FLAGGED_PIXVAL get_outline_colour() const OVERRIDE; static void recalc_outline_color(); /// @copydoc obj_t::check_season bool check_season(const bool) OVERRIDE; /// @copydoc obj_t::rotate90 void rotate90() OVERRIDE; /// re-calculate z-offset if slope of the tile has changed void recalc_off(); /// @copydoc obj_t::show_info void show_info() OVERRIDE; /// @copydoc obj_t::info void info(cbuffer_t & buf) const OVERRIDE; /// @copydoc obj_t::cleanup void cleanup(player_t *player) OVERRIDE; public: const tree_desc_t *get_desc() const { return tree_builder_t::get_desc_by_id(tree_id); } void set_desc(const tree_desc_t *desc) { tree_id = tree_builder_t::get_id_by_desc(desc); } uint16 get_desc_id() const { return tree_id; } /// @returns age of the tree in months, between 0 and 4095 uint16 get_age() const; private: /// calculate offsets for new trees void calc_off(slope_t::type slope, sint8 x=-128, sint8 y=-128); }; #endif simutrans-124.3/src/simutrans/obj/bruecke.cc000066400000000000000000000224171474050137200210760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../world/simworld.h" #include "../simtypes.h" #include "simobj.h" #include "../ground/grund.h" #include "../player/simplay.h" #include "../display/simimg.h" #include "../builder/brueckenbauer.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "bruecke.h" bruecke_t::bruecke_t(loadsave_t* const file) : obj_no_info_t() { rdwr(file); } bruecke_t::bruecke_t(koord3d pos, player_t *player, const bridge_desc_t *desc, bridge_desc_t::img_t img) : obj_no_info_t(pos) { this->desc = desc; this->img = img; set_owner( player ); player_t::book_construction_costs( get_owner(), -desc->get_price(), get_pos().get_2d(), desc->get_waytype()); } // single height segments static bridge_desc_t::img_t single_img[24]= { bridge_desc_t::NS_Segment, bridge_desc_t::OW_Segment, bridge_desc_t::N_Start, bridge_desc_t::S_Start, bridge_desc_t::O_Start, bridge_desc_t::W_Start, bridge_desc_t::N_Ramp, bridge_desc_t::S_Ramp, bridge_desc_t::O_Ramp, bridge_desc_t::W_Ramp, bridge_desc_t::NS_Pillar, bridge_desc_t::OW_Pillar, bridge_desc_t::NS_Segment, bridge_desc_t::OW_Segment, bridge_desc_t::N_Start, bridge_desc_t::S_Start, bridge_desc_t::O_Start, bridge_desc_t::W_Start, bridge_desc_t::N_Ramp, bridge_desc_t::S_Ramp, bridge_desc_t::O_Ramp, bridge_desc_t::W_Ramp, bridge_desc_t::NS_Pillar, bridge_desc_t::OW_Pillar }; void bruecke_t::calc_image() { grund_t *gr=welt->lookup(get_pos()); if(gr) { // if we are on the bridge, put the image into the ground, so we can have two ways ... if( weg_t *weg0 = gr->get_weg_nr(0) ) { #ifdef MULTI_THREAD weg0->lock_mutex(); #endif // if on a slope then start of bridge - take the upper value const slope_t::type slope = gr->get_grund_hang(); bool is_snow = welt->get_climate( get_pos().get_2d() ) == arctic_climate || get_pos().z + slope_t::max_diff(slope) >= welt->get_snowline(); // handle cases where old bridges don't have correct images image_id display_image=desc->get_background( img, is_snow ); if( display_image==IMG_EMPTY && desc->get_foreground( img, is_snow )==IMG_EMPTY ) { display_image=desc->get_background( single_img[img], is_snow ); } weg0->set_image( display_image ); // must always set both offsets, because after roation the xoffset contains the yoffset weg0->set_yoff( -gr->get_weg_yoff() ); weg0->set_xoff( 0 ); weg0->set_foreground_image(IMG_EMPTY); weg0->set_flag(obj_t::dirty); #ifdef MULTI_THREAD weg0->unlock_mutex(); #endif if( weg_t *weg1 = gr->get_weg_nr(1) ) { #ifdef MULTI_THREAD weg1->lock_mutex(); #endif weg1->set_yoff( -gr->get_weg_yoff() ); weg1->set_xoff( 0 ); #ifdef MULTI_THREAD weg1->unlock_mutex(); #endif } } set_yoff( -gr->get_weg_yoff() ); set_xoff( 0 ); } } image_id bruecke_t::get_front_image() const { grund_t *gr=welt->lookup(get_pos()); // if on a slope then start of bridge - take the upper value const slope_t::type slope = gr->get_grund_hang(); bool is_snow = welt->get_climate( get_pos().get_2d() ) == arctic_climate || get_pos().z + slope_t::max_diff(slope) >= welt->get_snowline(); // handle cases where old bridges don't have correct images image_id display_image=desc->get_foreground( img, is_snow ); if( display_image==IMG_EMPTY && desc->get_background( img, is_snow )==IMG_EMPTY ) { display_image=desc->get_foreground( single_img[img], is_snow ); } return display_image; } void bruecke_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "bruecke_t" ); obj_t::rdwr(file); const char *s = NULL; if(file->is_saving()) { s = desc->get_name(); } file->rdwr_str(s); file->rdwr_enum(img); if(file->is_loading()) { if (!s) { dbg->fatal("bruecke_t::rdwr", "No bridge name for bridge at (%s)", get_pos().get_str()); } desc = bridge_builder_t::get_desc(s); if(desc==NULL) { desc = bridge_builder_t::get_desc(translator::compatibility_name(s)); } if(desc==NULL) { dbg->warning( "bruecke_t::rdwr", "Unknown bridge \"%s\" at (%s) will be replaced with best match!", s, get_pos().get_str() ); pakset_manager_t::add_missing_paks( s, MISSING_BRIDGE ); } free(const_cast(s)); if( file->is_version_less(112, 7) && env_t::pak_height_conversion_factor==2 ) { switch(img) { case bridge_desc_t::OW_Segment: img = bridge_desc_t::OW_Segment2; break; case bridge_desc_t::NS_Segment: img = bridge_desc_t::NS_Segment2; break; case bridge_desc_t::O_Start: img = bridge_desc_t::O_Start2; break; case bridge_desc_t::W_Start: img = bridge_desc_t::W_Start2; break; case bridge_desc_t::S_Start: img = bridge_desc_t::S_Start2; break; case bridge_desc_t::N_Start: img = bridge_desc_t::N_Start2; break; case bridge_desc_t::O_Ramp: img = bridge_desc_t::O_Ramp2; break; case bridge_desc_t::W_Ramp: img = bridge_desc_t::W_Ramp2; break; case bridge_desc_t::S_Ramp: img = bridge_desc_t::S_Ramp2; break; case bridge_desc_t::N_Ramp: img = bridge_desc_t::N_Ramp2; break; case bridge_desc_t::OW_Pillar: img = bridge_desc_t::OW_Pillar2; break; case bridge_desc_t::NS_Pillar: img = bridge_desc_t::NS_Pillar2; break; default: break; } } } } // correct speed and maintenance void bruecke_t::finish_rd() { grund_t *gr = welt->lookup(get_pos()); if(desc==NULL) { if( weg_t *weg = gr->get_weg_nr(0) ) { desc = bridge_builder_t::find_bridge( weg->get_waytype(), weg->get_max_speed(), welt->get_timeline_year_month() ); if(desc==NULL) { desc = bridge_builder_t::find_bridge( weg->get_waytype(), weg->get_max_speed(), 0 ); } if(desc==NULL) { dbg->fatal("bruecke_t::finish_rd()", "Unknown bridge for type %x at (%s)", weg->get_waytype(), get_pos().get_str() ); } } else { // assume this is a powerbridge, since otherwise there should be a way desc = bridge_builder_t::find_bridge( powerline_wt, 0, welt->get_timeline_year_month() ); if(desc==NULL) { desc = bridge_builder_t::find_bridge( powerline_wt, 0, 0 ); } if(desc==NULL) { dbg->fatal("bruecke_t::finish_rd()", "No powerline bridge to build bridge type at (%s)", get_pos().get_str() ); } } } player_t *player=get_owner(); // change maintenance if(desc->get_waytype()!=powerline_wt) { weg_t *weg = gr->get_weg(desc->get_waytype()); if(weg==NULL) { dbg->error("bruecke_t::finish_rd()","Bridge without way at(%s)!", gr->get_pos().get_str() ); weg = weg_t::alloc( desc->get_waytype() ); gr->neuen_weg_bauen( weg, 0, welt->get_public_player() ); } weg->set_max_speed(desc->get_topspeed()); // take ownership of way player_t::add_maintenance( weg->get_owner(), -weg->get_desc()->get_maintenance(), desc->get_finance_waytype()); weg->set_owner(player); } player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype()); // with double heights may need to correct image on load (not all desc have double images) // at present only start images have 2 height variants, others to follow... if( !gr->ist_karten_boden() ) { if( desc->get_waytype() != powerline_wt ) { //img = desc->get_simple( gr->get_weg_ribi_unmasked( desc->get_waytype() ) ); } } else { if( gr->get_grund_hang() == slope_t::flat ) { //img = desc->get_ramp( gr->get_weg_hang() ); } else { img = desc->get_start( gr->get_grund_hang() ); } } } // correct speed and maintenance void bruecke_t::cleanup( player_t *player2 ) { player_t *player = get_owner(); // change maintenance, reset max-speed and y-offset if( const grund_t *gr = welt->lookup(get_pos()) ) { if( weg_t *weg0 = gr->get_weg( desc->get_waytype() ) ) { weg0->set_max_speed( weg0->get_desc()->get_topspeed() ); player_t::add_maintenance( player, weg0->get_desc()->get_maintenance(), weg0->get_desc()->get_finance_waytype()); // reset offsets weg0->set_xoff(0); weg0->set_yoff(0); if( weg_t *weg1 = gr->get_weg_nr(1) ) { weg1->set_xoff(0); weg1->set_yoff(0); } } } player_t::add_maintenance( player, -desc->get_maintenance(), desc->get_finance_waytype() ); player_t::book_construction_costs( player2, -desc->get_price(), get_pos().get_2d(), desc->get_waytype() ); } // rotated segment names static bridge_desc_t::img_t rotate90_img[24]= { bridge_desc_t::OW_Segment, bridge_desc_t::NS_Segment, bridge_desc_t::O_Start, bridge_desc_t::W_Start, bridge_desc_t::S_Start, bridge_desc_t::N_Start, bridge_desc_t::O_Ramp, bridge_desc_t::W_Ramp, bridge_desc_t::S_Ramp, bridge_desc_t::N_Ramp, bridge_desc_t::OW_Pillar, bridge_desc_t::NS_Pillar, bridge_desc_t::OW_Segment2, bridge_desc_t::NS_Segment2, bridge_desc_t::O_Start2, bridge_desc_t::W_Start2, bridge_desc_t::S_Start2, bridge_desc_t::N_Start2, bridge_desc_t::O_Ramp2, bridge_desc_t::W_Ramp2, bridge_desc_t::S_Ramp2, bridge_desc_t::N_Ramp2, bridge_desc_t::OW_Pillar2, bridge_desc_t::NS_Pillar2 }; void bruecke_t::rotate90() { set_yoff(0); obj_t::rotate90(); // the rotated image parameter is just one in front/back img = rotate90_img[img]; } // returns NULL, if removal is allowed // players can remove public owned ways const char *bruecke_t::get_removal_error(const player_t *player) { if (get_owner_nr()==PLAYER_PUBLIC_NR) { return NULL; } else { return obj_t::get_removal_error(player); } } simutrans-124.3/src/simutrans/obj/bruecke.h000066400000000000000000000030201474050137200207250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_BRUECKE_H #define OBJ_BRUECKE_H class karte_t; #include "../descriptor/bridge_desc.h" #include "simobj.h" /** * Bridges (visible) */ class bruecke_t : public obj_no_info_t { private: const bridge_desc_t *desc; bridge_desc_t::img_t img; protected: void rdwr(loadsave_t *file) OVERRIDE; public: bruecke_t(loadsave_t *file); bruecke_t(koord3d pos, player_t *player, const bridge_desc_t *desc, bridge_desc_t::img_t img); const char *get_name() const OVERRIDE {return "Bruecke";} typ get_typ() const OVERRIDE { return bruecke; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE { return desc ? desc->get_waytype() : invalid_wt; } const bridge_desc_t *get_desc() const { return desc; } // we will always replace first way image image_id get_image() const OVERRIDE { return IMG_EMPTY; } image_id get_front_image() const OVERRIDE; void calc_image() OVERRIDE; /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool calc_only_season_change) OVERRIDE { if( !calc_only_season_change ) { calc_image(); } return true; } // depends on snowline only void finish_rd() OVERRIDE; void cleanup(player_t *player) OVERRIDE; void rotate90() OVERRIDE; /** * @return NULL wenn OK, ansonsten eine Fehlermeldung */ const char *get_removal_error(const player_t *player) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/crossing.cc000066400000000000000000000133261474050137200213040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../world/simworld.h" #include "simobj.h" #include "../display/simimg.h" #include "../descriptor/crossing_desc.h" #include "../ground/grund.h" #include "../obj/way/weg.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../utils/cbuffer.h" #include "../player/simplay.h" #include "crossing.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t crossing_logic_mutex; static recursive_mutex_maker_t crossing_lm_maker(crossing_logic_mutex); #endif crossing_t::crossing_t(loadsave_t* const file) : obj_no_info_t() { image = foreground_image = IMG_EMPTY; logic = NULL; rdwr(file); } crossing_t::crossing_t(player_t* const player, koord3d const pos, crossing_desc_t const* const desc, uint8 const ns) : obj_no_info_t(pos) { this->ns = ns; this->desc = desc; logic = NULL; state = crossing_logic_t::CROSSING_INVALID; image = foreground_image = IMG_EMPTY; set_owner( player ); } crossing_t::~crossing_t() { if(logic) { crossing_logic_t *old_logic = logic; logic = NULL; old_logic->remove(this); } } void crossing_t::rotate90() { obj_t::rotate90(); ns ^= 1; } // changed state: mark dirty void crossing_t::state_changed() { mark_image_dirty( image, 0 ); mark_image_dirty( foreground_image, 0 ); calc_image(); } /** * Dient zur Neuberechnung des Bildes */ void crossing_t::calc_image() { #ifdef MULTI_THREAD pthread_mutex_lock( &crossing_logic_mutex ); #endif if( logic ) { state = logic->get_state(); } #ifdef MULTI_THREAD pthread_mutex_unlock( &crossing_logic_mutex ); #endif const bool snow_image = get_pos().z >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate; // recalc image each step ... const image_t *a = desc->get_foreground( ns, state!=crossing_logic_t::CROSSING_CLOSED, snow_image ); if( a==NULL && snow_image ) { // no snow image? take normal one a = desc->get_foreground( ns, state!=crossing_logic_t::CROSSING_CLOSED, 0); } foreground_image = a ? a->get_id() : IMG_EMPTY; const image_t *b = desc->get_background( ns, state!=crossing_logic_t::CROSSING_CLOSED, snow_image ); if (b==NULL && snow_image) { // no snow image? take normal one b = desc->get_background( ns, state!=crossing_logic_t::CROSSING_CLOSED, 0); } image = b ? b->get_id() : IMG_EMPTY; } void crossing_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "crossing_t" ); obj_t::rdwr(file); // variables ... attention, logic now in crossing_logic_t state = logic==NULL ? crossing_logic_t::CROSSING_INVALID : logic->get_state(); file->rdwr_byte(state); state = clamp(state, 0, crossing_logic_t::NUM_CROSSING_STATES-1); file->rdwr_byte(ns); if(file->is_version_less(99, 16)) { uint32 ldummy=0; uint8 bdummy=0; file->rdwr_byte(bdummy); file->rdwr_long(ldummy); dbg->fatal("crossing_t::rdwr()","I should be never forced to load old style crossings!" ); } // which waytypes? uint8 w1, w2; sint32 speedlimit0 = 999; sint32 speedlimit1 = 999; if(file->is_saving()) { w1 = desc->get_waytype(0); w2 = desc->get_waytype(1); speedlimit0 = desc->get_maxspeed(0); speedlimit1 = desc->get_maxspeed(1); } file->rdwr_byte(w1); file->rdwr_byte(w2); if( file->is_version_atleast(110, 0) ) { file->rdwr_long( speedlimit0 ); } if( file->is_version_atleast(110, 1) ) { file->rdwr_long( speedlimit1 ); } if( file->is_loading() ) { desc = crossing_logic_t::get_crossing( (waytype_t)w1, (waytype_t)w2, speedlimit0, speedlimit1, welt->get_timeline_year_month()); if(desc==NULL) { dbg->warning("crossing_t::rdwr()","requested for waytypes %i and %i not available, try to load object without timeline", w1, w2 ); desc = crossing_logic_t::get_crossing( (waytype_t)w1, (waytype_t)w2, 0, 0, 0); } if(desc==NULL) { dbg->fatal("crossing_t::rdwr()","requested for waytypes %i and %i but nothing defined!", w1, w2 ); } crossing_logic_t::add( this, static_cast(state) ); } } void crossing_t::finish_rd() { grund_t *gr=welt->lookup(get_pos()); if(gr==NULL || !gr->hat_weg(desc->get_waytype(0)) || !gr->hat_weg(desc->get_waytype(1))) { dbg->error("crossing_t::finish_rd","way/ground missing at %i,%i => ignore", get_pos().x, get_pos().y ); } else { // try to find crossing that matches way max speed weg_t *w1=gr->get_weg(desc->get_waytype(0)); weg_t *w2=gr->get_weg(desc->get_waytype(1)); const crossing_desc_t *test = crossing_logic_t::get_crossing( desc->get_waytype(0), desc->get_waytype(1), w1->get_desc()->get_topspeed(), w2->get_desc()->get_topspeed(), welt->get_timeline_year_month()); if (test && test!=desc) { desc = test; } // after loading restore speedlimits w1->count_sign(); w2->count_sign(); ns = ribi_t::is_straight_ns(w2->get_ribi_unmasked()); #ifdef MULTI_THREAD pthread_mutex_lock( &crossing_logic_mutex ); #endif crossing_logic_t::add( this, static_cast(state) ); logic->recalc_state(); #ifdef MULTI_THREAD pthread_mutex_unlock( &crossing_logic_mutex ); #endif } } // returns NULL, if removal is allowed // players can remove public owned ways const char *crossing_t::get_removal_error(const player_t *player) { if (get_owner_nr()==PLAYER_PUBLIC_NR) { return NULL; } else { return obj_t::get_removal_error(player); } } void crossing_t::info(cbuffer_t & buf) const { buf.append(translator::translate(get_name())); buf.append("\n"); logic->info(buf); buf.append("\n"); if (char const* const maker = get_desc()->get_copyright()) { buf.printf(translator::translate("Constructed by %s"), maker); buf.append("\n\n"); } } simutrans-124.3/src/simutrans/obj/crossing.h000066400000000000000000000054321474050137200211450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_CROSSING_H #define OBJ_CROSSING_H #include "simobj.h" #include "../simtypes.h" #include "../display/simimg.h" #include "../descriptor/crossing_desc.h" #include "../dataobj/crossing_logic.h" class vehicle_base_t; /** * road sign for traffic (one way minimum speed, traffic lights) */ class crossing_t : public obj_no_info_t { protected: image_id foreground_image, image; uint8 ns; // direction uint8 state; // only needed for loading ... crossing_logic_t *logic; const crossing_desc_t *desc; public: typ get_typ() const OVERRIDE { return crossing; } const char* get_name() const OVERRIDE { return "Kreuzung"; } /** * waytype associated with this object * for crossings: return invalid_wt since they do not need a way * if the way is deleted the crossing will be deleted, too */ waytype_t get_waytype() const OVERRIDE { return invalid_wt; } crossing_t(loadsave_t *file); crossing_t(player_t *player, koord3d pos, const crossing_desc_t *desc, uint8 ns = 0); /** * crossing logic is removed here */ virtual ~crossing_t(); void rotate90() OVERRIDE; const crossing_desc_t *get_desc() const { return desc; } /** * @param[out] buf string (only used for debug at the moment) */ void info(cbuffer_t & buf) const OVERRIDE; /** * @return NULL when OK, otherwise an error message */ const char *get_removal_error(const player_t *player) OVERRIDE; // returns true, if the crossing can be passed by this vehicle bool request_crossing( const vehicle_base_t *v ) { return logic->request_crossing( v ); } // adds to crossing void add_to_crossing( const vehicle_base_t *v ) { return logic->add_to_crossing( v ); } // removes the vehicle from the crossing void release_crossing( const vehicle_base_t *v ) { return logic->release_crossing( v ); } crossing_logic_t::crossing_state_t get_state() { return logic->get_state(); } // called from the logic directly void state_changed(); uint8 get_dir() { return ns; } void set_logic( crossing_logic_t *l ) { logic = l; } crossing_logic_t *get_logic() { return logic; } /** * Dient zur Neuberechnung des Bildes */ void calc_image() OVERRIDE; /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool calc_only_season_change) OVERRIDE { if( !calc_only_season_change ) { calc_image(); } return true; } // depends on snowline only // changes the state of a traffic light image_id get_image() const OVERRIDE { return image; } /** * For the front image hiding vehicles */ image_id get_front_image() const OVERRIDE { return foreground_image; } void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/depot.cc000066400000000000000000000421771474050137200205760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simconvoi.h" #include "../gui/simwin.h" #include "../player/simplay.h" #include "../world/simworld.h" #include "../obj/depot.h" #include "../simline.h" #include "../simlinemgmt.h" #include "../tool/simmenu.h" #include "../gui/depotlist_frame.h" #include "../gui/depot_frame.h" #include "../gui/messagebox.h" #include "../gui/simwin.h" #include "../dataobj/schedule.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../builder/hausbauer.h" #include "gebaeude.h" #include "../builder/vehikelbauer.h" #include "../descriptor/building_desc.h" #include "../utils/cbuffer.h" #include "../vehicle/air_vehicle.h" #include "../vehicle/rail_vehicle.h" #include "../vehicle/road_vehicle.h" #include "../vehicle/water_vehicle.h" slist_tpl depot_t::all_depots; depot_t::depot_t(loadsave_t *file) : gebaeude_t() { rdwr(file); if(file->is_version_less(88, 2)) { set_yoff(0); } all_depots.append(this); selected_filter = VEHICLE_FILTER_RELEVANT; selected_sort_by = SORT_BY_DEFAULT; last_selected_line = linehandle_t(); command_pending = false; } depot_t::depot_t(koord3d pos, player_t *player, const building_tile_desc_t *t) : gebaeude_t(pos, player, t) { all_depots.append(this); selected_filter = VEHICLE_FILTER_RELEVANT; selected_sort_by = SORT_BY_DEFAULT; last_selected_line = linehandle_t(); command_pending = false; if (depotlist_frame_t* f = (depotlist_frame_t*)win_get_magic(magic_depotlist + player->get_player_nr())) { f->fill_list(); } } depot_t::~depot_t() { destroy_win((ptrdiff_t)this); all_depots.remove(this); } // finds the next/previous depot relative to the current position depot_t *depot_t::find_depot( koord3d start, const obj_t::typ depot_type, const player_t *player, bool forward) { depot_t *found = NULL; koord3d found_pos = forward ? koord3d(welt->get_size().x+1,welt->get_size().y+1,welt->get_groundwater()) : koord3d(-1,-1,-1); sint32 found_hash = forward ? 0x7FFFFFF : -1; sint32 start_hash = start.x + (8192 * start.y); for(depot_t* const d : all_depots) { if(d->get_typ()==depot_type && d->get_owner()==player) { // ok, the right type of depot const koord3d pos = d->get_pos(); if(pos==start) { // ignore the start point continue; } sint32 hash = (pos.x + (8192 * pos.y)); if(forward) { if(hash>start_hash || (hash==start_hash && pos.z>start.z)) { // found a suitable one if(hashfound_hash || (hash==found_hash && pos.z>found_pos.z)) { // which is closer ... found = d; found_pos = pos; found_hash = hash; } } } } } return found; } // again needed for server void depot_t::call_depot_tool( char tool, convoihandle_t cnv, const char *extra) { // call depot tool tool_t *tmp_tool = create_tool( TOOL_CHANGE_DEPOT | SIMPLE_TOOL ); cbuffer_t buf; buf.printf( "%c,%s,%hu", tool, get_pos().get_str(), cnv.get_id() ); if( extra ) { buf.append( "," ); buf.append( extra ); } tmp_tool->set_default_param(buf); welt->set_tool( tmp_tool, get_owner() ); // since init always returns false, it is safe to delete immediately delete tmp_tool; } /* this is called on two occasions: * first a convoy reaches the depot during its journey * second during loading a convoi is stored in a depot => only store it again */ void depot_t::convoi_arrived(convoihandle_t acnv, bool schedule_adjust) { if(schedule_adjust) { // here a regular convoi arrived for(unsigned i=0; iget_vehicle_count(); i++) { vehicle_t *v = acnv->get_vehicle(i); // reset vehicle data v->discard_cargo(); v->set_pos( koord3d::invalid ); v->set_leading( i==0 ); v->set_last( i+1==acnv->get_vehicle_count() ); } // Volker: remove depot from schedule schedule_t *schedule = acnv->get_schedule(); for( int i=0; iget_count(); i++ ) { // only if convoi found if(schedule->entries[i].pos==get_pos()) { schedule->set_current_stop( i ); schedule->remove(); acnv->set_schedule(schedule); break; } } } // this part stores the convoi in the depot convois.append(acnv); depot_frame_t *depot_frame = dynamic_cast(win_get_magic( (ptrdiff_t)this )); if(depot_frame) { depot_frame->action_triggered(NULL,(long int)0); } acnv->set_home_depot( get_pos() ); DBG_MESSAGE("depot_t::convoi_arrived()", "convoi %d, %p entered depot", acnv.get_id(), acnv.get_rep()); } void depot_t::show_info() { create_win( new depot_frame_t(this), w_info, (ptrdiff_t)this ); } vehicle_t* depot_t::buy_vehicle(const vehicle_desc_t* info) { DBG_DEBUG("depot_t::buy_vehicle()", info->get_name()); vehicle_t* veh = vehicle_builder_t::build(get_pos(), get_owner(), NULL, info ); DBG_DEBUG("depot_t::buy_vehicle()", "vehiclebauer %p", veh); vehicles.append(veh); DBG_DEBUG("depot_t::buy_vehicle()", "appended %i vehicle", vehicles.get_count()); return veh; } void depot_t::append_vehicle(convoihandle_t cnv, vehicle_t* veh, bool infront, bool local_execution) { /* create a new convoi, if necessary */ if (!cnv.is_bound()) { cnv = add_convoi( local_execution ); } veh->set_pos(get_pos()); cnv->add_vehicle(veh, infront); vehicles.remove(veh); } void depot_t::remove_vehicle(convoihandle_t cnv, int ipos) { vehicle_t* veh = cnv->remove_vehicle_at( ipos ); if( veh ) { vehicles.append( veh ); } } void depot_t::remove_vehicles_to_end(convoihandle_t cnv, int ipos) { while( vehicle_t* veh = cnv->remove_vehicle_at( ipos ) ) { vehicles.append( veh ); } } void depot_t::sell_vehicle(vehicle_t* veh) { vehicles.remove(veh); get_owner()->book_new_vehicle((sint64)veh->calc_sale_value(), get_pos().get_2d(), get_waytype() ); DBG_MESSAGE("depot_t::sell_vehicle()", "this=%p sells %p", this, veh); delete veh; } // returns the index of the oldest/newest vehicle in a list vehicle_t* depot_t::find_oldest_newest(const vehicle_desc_t* desc, bool old) { vehicle_t* found_veh = NULL; for(vehicle_t* const veh : vehicles ) { if( veh->get_desc() == desc ) { // joy of XOR, finally a line where I could use it! if( found_veh == NULL || old ^ (found_veh->get_purchase_time() > veh->get_purchase_time()) ) { found_veh = veh; } } } return found_veh; } convoihandle_t depot_t::add_convoi(bool local_execution) { convoi_t* new_cnv = new convoi_t(get_owner()); new_cnv->set_home_depot(get_pos()); convois.append(new_cnv->self); depot_frame_t *win = dynamic_cast(win_get_magic( (ptrdiff_t)this )); if( win && local_execution ) { win->activate_convoi( new_cnv->self ); } return new_cnv->self; } bool depot_t::check_obsolete_inventory(convoihandle_t cnv) { bool ok = true; slist_tpl veh_tmp_list; for( int i = 0; i < cnv->get_vehicle_count(); i++ ) { const vehicle_desc_t* const vb = cnv->get_vehicle(i)->get_desc(); if( vb ) { // search storage for matching vehicle vehicle_t* veh = NULL; for( slist_tpl::iterator i = vehicles.begin(); i != vehicles.end(); ++i ) { if( (*i)->get_desc() == vb ) { // found in storage, remove to temp list while searching for next vehicle veh = *i; vehicles.erase(i); veh_tmp_list.append( veh ); break; } } if( !veh ) { // need to buy new if( vb->is_retired( welt->get_timeline_year_month() ) ) { // is obsolete, return false ok = false; break; } } } } // put vehicles back into storage vehicles.append_list( veh_tmp_list ); return ok; } convoihandle_t depot_t::copy_convoi(convoihandle_t old_cnv, bool local_execution) { if( old_cnv.is_bound() && !convoihandle_t::is_exhausted() && old_cnv->get_vehicle_count() > 0 && get_waytype() == old_cnv->front()->get_desc()->get_waytype() ) { convoihandle_t new_cnv = add_convoi( false ); new_cnv->set_name(old_cnv->get_internal_name()); int vehicle_count = old_cnv->get_vehicle_count(); for (int i = 0; iget_vehicle(i)->get_desc(); if (info != NULL) { // search in depot for an existing vehicle of correct type vehicle_t* oldest_vehicle = get_oldest_vehicle(info); if (oldest_vehicle != NULL) { // append existing vehicle append_vehicle( new_cnv, oldest_vehicle, false, local_execution ); } else { // buy new vehicle vehicle_t* veh = vehicle_builder_t::build(get_pos(), get_owner(), NULL, info ); veh->set_pos(get_pos()); new_cnv->add_vehicle(veh, false); } } } if (old_cnv->get_line().is_bound()) { new_cnv->set_line(old_cnv->get_line()); new_cnv->get_schedule()->set_current_stop( old_cnv->get_schedule()->get_current_stop() ); } else { if (old_cnv->get_schedule() != NULL) { new_cnv->set_schedule(old_cnv->get_schedule()->copy()); } } // make this the current selected convoi depot_frame_t *win = dynamic_cast(win_get_magic( (ptrdiff_t)this )); if( win ) { if( local_execution ) { win->activate_convoi( new_cnv ); } else { win->update_data(); } } return new_cnv; } return convoihandle_t(); } bool depot_t::disassemble_convoi(convoihandle_t cnv, bool sell) { if( cnv.is_bound() ) { if( !sell ) { // store vehicles in depot while( vehicle_t* const v = cnv->remove_vehicle_at(0) ) { v->discard_cargo(); v->set_leading(false); v->set_last(false); vehicles.append(v); } } // remove from depot lists remove_convoi( cnv ); // and remove from welt cnv->self_destruct(); return true; } return false; } bool depot_t::disassemble_all_convois(bool sell) { uint32 i = 0; while( i < convois.get_count() ) { if( !disassemble_convoi( convois.at(i), sell ) ) { i++; } } return (convois.get_count() == 0); } bool depot_t::start_all_convoys() { uint32 i = 0; while( i < convois.get_count() ) { if( !start_convoi( convois.at(i), false ) ) { i++; } } return (convois.get_count() == 0); } // implementation in tool/simtool.cc bool scenario_check_convoy(karte_t *welt, player_t *player, convoihandle_t cnv, depot_t* depot, bool local); bool depot_t::start_convoi(convoihandle_t cnv, bool local_execution) { // close schedule window if not yet closed if(cnv.is_bound() && cnv->get_schedule()!=NULL) { if(!cnv->get_schedule()->is_editing_finished()) { // close the schedule window destroy_win((ptrdiff_t)cnv->get_schedule()); } } // convoi not in depot anymore, maybe user double-clicked on start-button if(!convois.is_contained(cnv)) { return false; } if (cnv.is_bound() && cnv->get_schedule() && !cnv->get_schedule()->empty()) { // if next schedule entry is this depot => advance to next entry const koord3d& cur_pos = cnv->get_schedule()->get_current_entry().pos; if (cur_pos == get_pos()) { cnv->get_schedule()->advance(); } // check if convoi is complete if(cnv->get_sum_power() == 0 || !cnv->pruefe_alle()) { if (local_execution) { create_win( new news_img("Diese Zusammenstellung kann nicht fahren!\n"), w_time_delete, magic_none); } } else if( !cnv->front()->calc_route(this->get_pos(), cur_pos, cnv->get_min_top_speed(), cnv->access_route()) ) { // no route to go ... if(local_execution) { static cbuffer_t buf; buf.clear(); buf.printf( translator::translate("Vehicle %s can't find a route!"), cnv->get_name() ); create_win( new news_img(buf), w_time_delete, magic_none); } } else if (!scenario_check_convoy(welt, get_owner(), cnv, this, local_execution) ) { // not allowed by scenario } else { // convoi can start now cnv->start(); // remove from depot lists remove_convoi( cnv ); return true; } } else { if (local_execution) { create_win( new news_img("Noch kein Fahrzeug\nmit Fahrplan\nvorhanden\n"), w_time_delete, magic_none); } if (!cnv.is_bound()) { dbg->warning("depot_t::start_convoi()","No convoi to start!"); } else if (!cnv->get_schedule()) { dbg->warning("depot_t::start_convoi()","No schedule for convoi."); } else if (!cnv->get_schedule()->is_editing_finished()) { dbg->warning("depot_t::start_convoi()","Schedule is incomplete/not finished"); } } return false; } void depot_t::remove_convoi( convoihandle_t cnv ) { depot_frame_t *win = dynamic_cast(win_get_magic( (ptrdiff_t)this )); if( win ) { // get currently selected convoi to restore selection if not removed int icnv = win->get_icnv(); convoihandle_t c = icnv > -1 ? get_convoi( icnv ) : convoihandle_t(); icnv = convois.index_of( cnv ); convois.remove( cnv ); if( c == cnv ) { // removing currently selected, select next in list or last instead c = !convois.empty() ? convois.at( min((uint32)icnv, convois.get_count() - 1) ) : convoihandle_t(); } win->activate_convoi( c ); } else { convois.remove( cnv ); } } // attention! this will not be used for railway depots! They will be loaded by hand ... void depot_t::rdwr(loadsave_t *file) { gebaeude_t::rdwr(file); rdwr_vehikel(vehicles, file); if (file->is_version_less(81, 33)) { // wagons are stored extra, just add them to vehicles assert(file->is_loading()); rdwr_vehikel(vehicles, file); } } void depot_t::rdwr_vehikel(slist_tpl &list, loadsave_t *file) { sint32 count; if(file->is_saving()) { count = list.get_count(); DBG_MESSAGE("depot_t::vehikel_laden()","saving %d vehicles",count); } file->rdwr_long(count); if(file->is_loading()) { // no house definition for this => use a normal hut ... if( this->get_tile()==NULL ) { dbg->error( "depot_t::rdwr()", "tile for depot not found!" ); set_tile( (*hausbauer_t::get_citybuilding_list( building_desc_t::city_res ))[0]->get_tile(0), true ); } DBG_MESSAGE("depot_t::vehikel_laden()","loading %d vehicles",count); for(int i=0; ird_obj_id(); vehicle_t *v = NULL; const bool first = false; const bool last = false; switch( typ ) { case old_automobil: case road_vehicle: v = new road_vehicle_t(file, first, last); break; case old_waggon: case rail_vehicle: v = new rail_vehicle_t(file, first, last); break; case old_schiff: case water_vehicle: v = new water_vehicle_t(file, first, last); break; case old_aircraft: case air_vehicle: v = new air_vehicle_t(file, first, last); break; case old_monorailwaggon: case monorail_vehicle: v = new monorail_vehicle_t(file, first, last); break; case maglev_vehicle: v = new maglev_vehicle_t(file, first, last); break; case narrowgauge_vehicle: v = new narrowgauge_vehicle_t(file, first, last); break; default: dbg->fatal("depot_t::vehikel_laden()","invalid vehicle type $%X", typ); } if(v->get_desc()) { DBG_MESSAGE("depot_t::vehikel_laden()","loaded %s", v->get_desc()->get_name()); list.append( v ); } else { dbg->error("depot_t::vehikel_laden()","vehicle has no desc => ignored"); } } } else { for(vehicle_t* const v : list) { file->wr_obj_id(v->get_typ()); v->rdwr_from_convoi(file); } } } /** * @return NULL when OK, otherwise an error message */ const char *depot_t::get_removal_error(const player_t *player) { if(player!=get_owner() && player!=welt->get_public_player()) { return "Das Feld gehoert\neinem anderen Spieler\n"; } if (!vehicles.empty()) { return "There are still vehicles\nstored in this depot!\n"; } for(convoihandle_t const c : convois) { if (c.is_bound() && c->get_vehicle_count() > 0) { return "There are still vehicles\nstored in this depot!\n"; } } return NULL; } slist_tpl const& depot_t::get_vehicle_type(uint8 sortkey) const { return vehicle_builder_t::get_info(get_waytype(), sortkey); } vehicle_t* depot_t::get_oldest_vehicle(const vehicle_desc_t* desc) { vehicle_t* oldest_veh = NULL; for(vehicle_t* const veh : get_vehicle_list()) { if (veh->get_desc() == desc) { if (oldest_veh == NULL || oldest_veh->get_purchase_time() > veh->get_purchase_time()) { oldest_veh = veh; } } } return oldest_veh; } void depot_t::update_win() { depot_frame_t *depot_frame = dynamic_cast(win_get_magic( (ptrdiff_t)this )); if(depot_frame) { depot_frame->build_vehicle_lists(); } } void depot_t::new_month() { // since vehicles may have become obsolete update_all_win(); } void depot_t::update_all_win() { for(depot_t* const d : all_depots) { d->update_win(); } } unsigned bahndepot_t::get_max_convoi_length() const { return welt->get_settings().get_max_rail_convoi_length(); } unsigned strassendepot_t::get_max_convoi_length() const { return welt->get_settings().get_max_road_convoi_length(); } unsigned schiffdepot_t::get_max_convoi_length() const { return welt->get_settings().get_max_ship_convoi_length(); } unsigned airdepot_t::get_max_convoi_length() const { return welt->get_settings().get_max_air_convoi_length(); } simutrans-124.3/src/simutrans/obj/depot.h000066400000000000000000000275751474050137200204450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_DEPOT_H #define OBJ_DEPOT_H #include "../tpl/slist_tpl.h" #include "gebaeude.h" #include "../convoihandle.h" #include "../simline.h" #define VEHICLE_FILTER_RELEVANT 1 #define VEHICLE_FILTER_GOODS_OFFSET 2 #define SORT_BY_DEFAULT 0 class karte_t; class vehicle_t; class depot_frame_t; class vehicle_desc_t; /** * In Depots werden Fahrzeuge gekauft, gewartet, verkauft und gelagert. */ class depot_t : public gebaeude_t { protected: /** * Reworked depot data! * * It can now contain any number of vehicles bought by the user (as before). * And it can hold any number of convois (before only one). * It is possible to have 0 convois in a depot, but an empty one shall be * automatically created, when necessary. * Convois are numbered 0...(n-1). * Vehicles are accessed by type. */ slist_tpl vehicles; slist_tpl convois; void rdwr_vehikel(slist_tpl &list, loadsave_t *file); static slist_tpl all_depots; public: // Last selected vehicle filter int selected_filter; // Last selected vehicle sort int selected_sort_by; // finds the next/previous depot relative to the current position static depot_t *find_depot( koord3d start, const obj_t::typ depot_type, const player_t *player, bool next); static const slist_tpl& get_depot_list() { return all_depots; } depot_t(loadsave_t *file); depot_t(koord3d pos, player_t *player, const building_tile_desc_t *t); virtual ~depot_t(); void call_depot_tool( char tool, convoihandle_t cnv, const char *extra ); virtual simline_t::linetype get_line_type() const = 0; void rdwr(loadsave_t *file) OVERRIDE; // text for the tabs is defaulted to the train names virtual const char * get_electrics_name() { return "Electrics_tab"; } virtual const char * get_passenger_name() { return "Pas_tab"; } virtual const char * get_zieher_name() { return "Lokomotive_tab"; } virtual const char * get_haenger_name() { return "Waggon_tab"; } vehicle_t* find_oldest_newest(const vehicle_desc_t* desc, bool old); /** * Access to convoi list. */ unsigned convoi_count() const { return convois.get_count(); } convoihandle_t get_convoi(unsigned int icnv) const { return icnv < convoi_count() ? convois.at(icnv) : convoihandle_t(); } convoihandle_t add_convoi(bool local_execution); slist_tpl const& get_convoy_list() { return convois; } // checks if cnv can be copied by using only stored vehicles and non-obsolete purchased vehicles bool check_obsolete_inventory(convoihandle_t cnv); /** * copies convoi and its schedule or line */ convoihandle_t copy_convoi(convoihandle_t old_cnv, bool local_execution); /** * Let convoi leave the depot. * If not possible, a message is displayed and the function returns false. * * @param cnv * @param local_execution if true, this method creates pop-ups in case of errors */ bool start_convoi(convoihandle_t cnv, bool local_execution); bool start_all_convoys(); /** * Destroy the convoi and put the vehicles in the vehicles list (sell==false), * or sell all immediately (sell==true). */ bool disassemble_convoi(convoihandle_t cnv, bool sell); bool disassemble_all_convois(bool sell); /** * Remove the convoi from the depot lists * updating depot gui frame as necessary */ void remove_convoi( convoihandle_t cnv ); /** * Remove vehicle from vehicle list and add it to the convoi. Two positions * are possible - in front or at the rear. */ void append_vehicle(convoihandle_t cnv, vehicle_t* veh, bool infront, bool local_execution); /** * Remove the vehicle at given position from the convoi and put it in the * vehicle list. */ void remove_vehicle(convoihandle_t cnv, int ipos); void remove_vehicles_to_end(convoihandle_t cnv, int ipos); /** * Access to vehicles not bound to a convoi. They are not ordered * in any way. */ slist_tpl const& get_vehicle_list() { return vehicles; } /** * A new vehicle is bought and added to the vehicle list. * The new vehicle in the list is returned. */ vehicle_t* buy_vehicle(const vehicle_desc_t* info); /** * Sell a vehicle from the vehicle list. */ void sell_vehicle(vehicle_t* veh); /** * Access to vehicle types which can be bought in the depot. */ slist_tpl const& get_vehicle_type(uint8 sortkey = SORT_BY_DEFAULT) const; /** * A convoi arrived at the depot and is added to the convoi list. * If schedule_adjust is true, the current depot is removed from schedule. */ void convoi_arrived(convoihandle_t cnv, bool schedule_adjust); /** * Parameters to determine layout and behaviour of the depot_frame_t. */ virtual int get_x_grid() const = 0; virtual int get_y_grid() const = 0; virtual int get_x_placement() const = 0; virtual int get_y_placement() const = 0; virtual unsigned get_max_convoi_length() const = 0; /** * Opens a new info window for that object. */ void show_info() OVERRIDE; /** * Can object be removed? * @return NULL when OK, otherwise an error message */ const char *get_removal_error(const player_t *player) OVERRIDE; /** * identifies the oldest vehicle of a certain type * @return NULL if no vehicle is found */ vehicle_t* get_oldest_vehicle(const vehicle_desc_t* desc); /** * Sets/gets the line that was selected the last time in the depot dialog */ void set_last_selected_line(const linehandle_t last_line) { last_selected_line=last_line; } linehandle_t get_last_selected_line() const { return last_selected_line; } /** * Will update all depot_frame_t (new vehicles!) */ static void update_all_win(); static void new_month(); /** * Update the depot_frame_t. */ void update_win(); private: linehandle_t last_selected_line; /** * Used to block new actions from depot frame gui when convois are being added to the depot. * Otherwise lag in multipler results in actions being performed on the wrong convoi. * Only works for a single client making changes in a depot at once. Multiple clients can still result in wrong convois being changed. */ bool command_pending; public: bool is_command_pending() const { return command_pending; } void clear_command_pending() { command_pending = false; } void set_command_pending() { command_pending = true; } }; /** * Depots for train vehicles. * @see depot_t * @see gebaeude_t */ class bahndepot_t : public depot_t { public: bahndepot_t(loadsave_t *file) : depot_t(file) {} bahndepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t) : depot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::trainline; } void rdwr_vehicles(loadsave_t *file) { depot_t::rdwr_vehikel(vehicles,file); } /** * Parameters to determine layout and behaviour of the depot_frame_t. */ int get_x_placement() const OVERRIDE {return -25; } int get_y_placement() const OVERRIDE {return -28; } int get_x_grid() const OVERRIDE { return 24; } int get_y_grid() const OVERRIDE { return 24; } unsigned get_max_convoi_length() const OVERRIDE; obj_t::typ get_typ() const OVERRIDE { return bahndepot; } const char *get_name() const OVERRIDE {return "Bahndepot"; } }; class tramdepot_t : public bahndepot_t { public: tramdepot_t(loadsave_t *file):bahndepot_t(file) {} tramdepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t): bahndepot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::tramline; } obj_t::typ get_typ() const OVERRIDE { return tramdepot; } const char *get_name() const OVERRIDE {return "Tramdepot"; } }; class monoraildepot_t : public bahndepot_t { public: monoraildepot_t(loadsave_t *file):bahndepot_t(file) {} monoraildepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t): bahndepot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::monorailline; } obj_t::typ get_typ() const OVERRIDE { return monoraildepot; } const char *get_name() const OVERRIDE {return "Monoraildepot"; } }; class maglevdepot_t : public bahndepot_t { public: maglevdepot_t(loadsave_t *file):bahndepot_t(file) {} maglevdepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t): bahndepot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::maglevline; } obj_t::typ get_typ() const OVERRIDE { return maglevdepot; } const char *get_name() const OVERRIDE {return "Maglevdepot"; } }; class narrowgaugedepot_t : public bahndepot_t { public: narrowgaugedepot_t(loadsave_t *file):bahndepot_t(file) {} narrowgaugedepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t): bahndepot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::narrowgaugeline; } obj_t::typ get_typ() const OVERRIDE { return narrowgaugedepot; } const char *get_name() const OVERRIDE {return "Narrowgaugedepot"; } }; /** * Depots for street vehicles * @see depot_t * @see gebaeude_t */ class strassendepot_t : public depot_t { protected: const char * get_passenger_name() OVERRIDE { return "Bus_tab"; } const char * get_electrics_name() OVERRIDE { return "TrolleyBus_tab"; } const char * get_zieher_name() OVERRIDE { return "LKW_tab"; } const char * get_haenger_name() OVERRIDE { return "Anhaenger_tab"; } public: strassendepot_t(loadsave_t *file) : depot_t(file) {} strassendepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t) : depot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::truckline; } /** * Parameters to determine layout and behaviour of the depot_frame_t. */ int get_x_placement() const OVERRIDE { return -20; } int get_y_placement() const OVERRIDE { return -25; } int get_x_grid() const OVERRIDE { return 24; } int get_y_grid() const OVERRIDE { return 24; } unsigned get_max_convoi_length() const OVERRIDE; obj_t::typ get_typ() const OVERRIDE { return strassendepot; } const char *get_name() const OVERRIDE {return "Strassendepot";} }; /** * Depots for ships * @see depot_t * @see gebaeude_t */ class schiffdepot_t : public depot_t { protected: const char * get_passenger_name() OVERRIDE { return "Ferry_tab"; } const char * get_zieher_name() OVERRIDE { return "Schiff_tab"; } const char * get_haenger_name() OVERRIDE { return "Schleppkahn_tab"; } public: schiffdepot_t(loadsave_t *file) : depot_t(file) {} schiffdepot_t(koord3d pos, player_t *player, const building_tile_desc_t *t) : depot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::shipline; } /** * Parameters to determine layout and behaviour of the depot_frame_t. */ int get_x_placement() const OVERRIDE { return -1; } int get_y_placement() const OVERRIDE { return -11; } int get_x_grid() const OVERRIDE { return 60; } int get_y_grid() const OVERRIDE { return 46; } unsigned get_max_convoi_length() const OVERRIDE; obj_t::typ get_typ() const OVERRIDE { return schiffdepot; } const char *get_name() const OVERRIDE {return "Schiffdepot";} }; /** * Depots for aircrafts */ class airdepot_t : public depot_t { protected: const char * get_zieher_name() OVERRIDE { return "aircraft_tab"; } const char * get_passenger_name() OVERRIDE { return "Flug_tab"; } public: airdepot_t(loadsave_t *file) : depot_t(file) {} airdepot_t(koord3d pos,player_t *player, const building_tile_desc_t *t) : depot_t(pos,player,t) {} simline_t::linetype get_line_type() const OVERRIDE { return simline_t::airline; } /** * Parameters to determine layout and behaviour of the depot_frame_t. */ int get_x_placement() const OVERRIDE {return -10; } int get_y_placement() const OVERRIDE {return -23; } int get_x_grid() const OVERRIDE { return 36; } int get_y_grid() const OVERRIDE { return 36; } unsigned get_max_convoi_length() const OVERRIDE; obj_t::typ get_typ() const OVERRIDE { return airdepot; } const char *get_name() const OVERRIDE {return "Hangar";} }; #endif simutrans-124.3/src/simutrans/obj/dummy.h000066400000000000000000000011521474050137200204440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_DUMMY_H #define OBJ_DUMMY_H #include "simobj.h" #include "../display/simimg.h" /** * A dummy type for old things, which are now ignored */ class dummy_obj_t : public obj_t { public: dummy_obj_t(loadsave_t* file) : obj_t() { rdwr(file); // do not remove from this position, since there will be nothing obj_t::set_flag(obj_t::not_on_map); } typ get_typ() const OVERRIDE { return obj_t::undefined; } image_id get_image() const OVERRIDE { return IMG_EMPTY; } }; #endif simutrans-124.3/src/simutrans/obj/field.cc000066400000000000000000000037621474050137200205430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "simobj.h" #include "../simfab.h" #include "../display/simimg.h" #include "../ground/grund.h" #include "../dataobj/loadsave.h" #include "../player/simplay.h" #include "field.h" field_t::field_t(koord3d p, player_t *player, const field_class_desc_t *desc, fabrik_t *fab) : obj_t() { this->desc = desc; this->fab = fab; set_owner( player ); p.z = welt->max_hgt(p.get_2d()); set_pos( p ); } field_t::~field_t() { // mark field image area as dirty for removal mark_image_dirty( get_image(), 0 ); fab->remove_field_at( get_pos().get_2d() ); } const char *field_t::get_removal_error(const player_t *) { // we allow removal, if there is less than return (fab->get_field_count() > fab->get_desc()->get_field_group()->get_min_fields()) ? NULL : "Not enough fields would remain."; } // remove costs void field_t::cleanup(player_t *player) { player_t::book_construction_costs(player, welt->get_settings().cst_multiply_remove_field, get_pos().get_2d(), ignore_wt); mark_image_dirty( get_image(), 0 ); } // return the right month graphic for factories image_id field_t::get_image() const { const skin_desc_t *s=desc->get_images(); uint16 count=s->get_count() - desc->has_snow_image(); if( desc->has_snow_image() && (get_pos().z >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate) ) { // last images will be shown above snowline return s->get_image_id(count); } else { // resolution 1/8th month (0..95) const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_ticks()>>(welt->ticks_per_world_month_shift-3))&7) + 1; const image_id image = s->get_image_id( (count*yearsteps-1)/96 ); if((count*yearsteps-1)%96open_info_window(); } simutrans-124.3/src/simutrans/obj/field.h000066400000000000000000000015641474050137200204030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_FIELD_H #define OBJ_FIELD_H #include "simobj.h" #include "../display/simimg.h" class field_class_desc_t; class fabrik_t; class field_t : public obj_t { fabrik_t *fab; const field_class_desc_t *desc; public: field_t(const koord3d pos, player_t *player, const field_class_desc_t *desc, fabrik_t *fab); virtual ~field_t(); const char* get_name() const OVERRIDE { return "Field"; } typ get_typ() const OVERRIDE { return obj_t::field; } image_id get_image() const OVERRIDE; /// @copydoc obj_t::show_info void show_info() OVERRIDE; /** * @return NULL when OK, otherwise an error message */ const char *get_removal_error(const player_t *) OVERRIDE; void cleanup(player_t *player) OVERRIDE; fabrik_t* get_factory() const { return fab; } }; #endif simutrans-124.3/src/simutrans/obj/gebaeude.cc000066400000000000000000000750401474050137200212170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include // repair multitile building which have lost thier orientation due to replacements // may not work properly with multithread builds //#define REPAIR_MULTITILE_BUILD #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t sync_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t add_to_city_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #include "../builder/hausbauer.h" #include "../gui/headquarter_info.h" #include "../world/simworld.h" #include "simobj.h" #include "../simfab.h" #include "../display/simimg.h" #include "../display/simgraph.h" #include "../simhalt.h" #include "../gui/simwin.h" #include "../world/simcity.h" #include "../player/simplay.h" #include "../simdebug.h" #include "../simintr.h" #include "../simskin.h" #include "../simachievements.h" #include "../ground/grund.h" #include "../descriptor/building_desc.h" #include "../descriptor/intro_dates.h" #include "../descriptor/ground_desc.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "../gui/obj_info.h" #include "gebaeude.h" /** * Initializes all variables with safe, usable values */ void gebaeude_t::init() { tile = NULL; anim_time = 0; sync = false; zeige_baugrube = false; is_factory = false; season = 0; background_animated = false; remove_ground = true; anim_frame = 0; // insta_zeit = 0; // init in set_tile() ptr.fab = NULL; } gebaeude_t::gebaeude_t() : obj_t() { init(); } gebaeude_t::gebaeude_t(loadsave_t *file) : obj_t() { init(); rdwr(file); if(file->is_version_less(88, 2)) { set_yoff(0); } if(tile && tile->get_phases()>1) { welt->sync_buildings.add( this ); sync = true; } } gebaeude_t::gebaeude_t(koord3d pos, player_t *player, const building_tile_desc_t *t) : obj_t(pos) { set_owner( player ); init(); if(t) { set_tile(t,true); // this will set init time etc. player_t::add_maintenance(get_owner(), tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype() ); } // get correct y offset for bridges grund_t *gr=welt->lookup(pos); if(gr && gr->get_weg_hang()!=gr->get_grund_hang()) { set_yoff( -gr->get_weg_yoff() ); } } /** * Destructor. Removes this from the list of sync objects if necessary. */ gebaeude_t::~gebaeude_t() { if(welt->is_destroying()) { return; // avoid book-keeping } if(get_stadt()) { ptr.stadt->remove_gebaeude_from_stadt(this); } if(sync) { sync = false; welt->sync_buildings.remove(this); } // tiles might be invalid, if no description is found during loading if(tile && tile->get_desc() && tile->get_desc()->is_attraction()) { welt->remove_attraction(this); } if(tile) { player_t::add_maintenance(get_owner(), -tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype()); } } void gebaeude_t::rotate90() { obj_t::rotate90(); // must or can rotate? const building_desc_t* const building_desc = tile->get_desc(); if (building_desc->get_all_layouts() > 1 || building_desc->get_x() * building_desc->get_y() > 1) { uint8 layout = tile->get_layout(); koord new_offset = tile->get_offset(); if(building_desc->get_type() == building_desc_t::unknown || building_desc->get_all_layouts()<=4) { layout = ((layout+3) % building_desc->get_all_layouts() & 3); } else if( building_desc->get_all_layouts()==8 && building_desc->get_type() >= building_desc_t::city_res ) { // eight layout city building layout = (layout & 4) + ((layout+3) & 3); } else { // 8 & 16 tile lyoutout for stations static uint8 layout_rotate[16] = { 1, 8, 5, 10, 3, 12, 7, 14, 9, 0, 13, 2, 11, 4, 15, 6 }; layout = layout_rotate[layout] % building_desc->get_all_layouts(); } // have to rotate the tiles :( if( !building_desc->can_rotate() && building_desc->get_all_layouts() == 1 ) { if ((welt->get_settings().get_rotation() & 1) == 0) { // rotate 180 degree new_offset = koord(building_desc->get_x() - 1 - new_offset.x, building_desc->get_y() - 1 - new_offset.y); } // do nothing here, since we cannot fix it properly } else { // rotate on ... new_offset = koord(building_desc->get_y(tile->get_layout()) - 1 - new_offset.y, new_offset.x); } // such a tile exist? if( building_desc->get_x(layout) > new_offset.x && building_desc->get_y(layout) > new_offset.y ) { const building_tile_desc_t* const new_tile = building_desc->get_tile(layout, new_offset.x, new_offset.y); // add new tile: but make them old (no construction) uint32 old_insta_zeit = insta_zeit; set_tile( new_tile, false ); insta_zeit = old_insta_zeit; if( building_desc->get_type() != building_desc_t::dock && !tile->has_image() ) { // may have a rotation, that is not recoverable if( !is_factory && new_offset!=koord(0,0) ) { welt->set_nosave_warning(); } if( is_factory ) { // there are factories with a broken tile // => this map rotation cannot be reloaded! welt->set_nosave(); } } } else { welt->set_nosave(); } } } /** sets the corresponding pointer to a factory */ void gebaeude_t::set_fab(fabrik_t *fd) { // sets the pointer in non-zero if(fd) { if(!is_factory && ptr.stadt!=NULL) { dbg->fatal("gebaeude_t::set_fab()","building already bound to city!"); } is_factory = true; ptr.fab = fd; } else if(is_factory) { ptr.fab = NULL; } } /** sets the corresponding city */ void gebaeude_t::set_stadt(stadt_t *s) { if(is_factory && ptr.fab!=NULL) { dbg->fatal("gebaeude_t::set_stadt()","building at (%s) already bound to factory!", get_pos().get_str() ); } // sets the pointer in non-zero is_factory = false; ptr.stadt = s; } /* make this building without construction */ void gebaeude_t::add_alter(uint32 a) { insta_zeit -= min(a,insta_zeit); } void gebaeude_t::set_tile( const building_tile_desc_t *new_tile, bool start_with_construction ) { insta_zeit = welt->get_ticks(); if(!zeige_baugrube && tile!=NULL) { // mark old tile dirty mark_images_dirty(); } zeige_baugrube = !new_tile->get_desc()->no_construction_pit() && start_with_construction; if(sync) { if( new_tile->get_phases()<=1 && !zeige_baugrube ) { // need to stop animation #ifdef MULTI_THREAD pthread_mutex_lock( &sync_mutex ); #endif welt->sync_buildings.remove(this); sync = false; anim_frame = 0; #ifdef MULTI_THREAD pthread_mutex_unlock( &sync_mutex ); #endif } } else if( (new_tile->get_phases()>1 && (!is_factory || get_fabrik()->is_currently_producing()) ) || zeige_baugrube ) { // needs now animation #ifdef MULTI_THREAD pthread_mutex_lock( &sync_mutex ); #endif anim_frame = sim_async_rand( new_tile->get_phases() ); anim_time = 0; welt->sync_buildings.add(this); sync = true; #ifdef MULTI_THREAD pthread_mutex_unlock( &sync_mutex ); #endif } tile = new_tile; remove_ground = tile->has_image() && !tile->get_desc()->needs_ground(); set_flag(obj_t::dirty); } sync_result gebaeude_t::sync_step(uint32 delta_t) { if( zeige_baugrube ) { // still under construction? if( welt->get_ticks() - insta_zeit > 5000 ) { set_flag( obj_t::dirty ); mark_image_dirty( get_image(), 0 ); zeige_baugrube = false; if( tile->get_phases() <= 1 ) { sync = false; return SYNC_REMOVE; } } } else { if( !is_factory || get_fabrik()->is_currently_producing() ) { // normal animated building anim_time += delta_t; if( anim_time > tile->get_desc()->get_animation_time() ) { anim_time -= tile->get_desc()->get_animation_time(); // old positions need redraw if( background_animated ) { set_flag( obj_t::dirty ); mark_images_dirty(); } else { // try foreground image_id image = tile->get_foreground( anim_frame, season ); mark_image_dirty( image, 0 ); } anim_frame++; if( anim_frame >= tile->get_phases() ) { anim_frame = 0; } if( !background_animated ) { // next phase must be marked dirty too ... image_id image = tile->get_foreground( anim_frame, season ); mark_image_dirty( image, 0 ); } } } } return SYNC_OK; } void gebaeude_t::calc_image() { grund_t *gr = welt->lookup( get_pos() ); // need no ground? if( remove_ground && gr->get_typ() == grund_t::fundament ) { gr->set_image( IMG_EMPTY ); } static uint8 effective_season[][5] = { {0,0,0,0,0}, {0,0,0,0,1}, {0,0,0,0,1}, {0,1,2,3,2}, {0,1,2,3,4} }; // season image lookup from [number of images] and [actual season/snow] if( (gr->ist_tunnel() && !gr->ist_karten_boden()) || tile->get_seasons() < 2 ) { season = 0; } else if( get_pos().z - (get_yoff() / TILE_HEIGHT_STEP) >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate ) { // snowy winter graphics season = effective_season[tile->get_seasons() - 1][4]; } else if( get_pos().z - (get_yoff() / TILE_HEIGHT_STEP) >= welt->get_snowline() - 1 && welt->get_season() == 0 ) { // snowline crossing in summer // so at least some weeks spring/autumn season = effective_season[tile->get_seasons() - 1][welt->get_last_month() <= 5 ? 3 : 1]; } else { season = effective_season[tile->get_seasons() - 1][welt->get_season()]; } background_animated = tile->is_background_animated( season ); } image_id gebaeude_t::get_image() const { if(env_t::hide_buildings!=0 && tile->has_image()) { // opaque houses if(is_city_building()) { return env_t::hide_with_transparency ? skinverwaltung_t::fussweg->get_image_id(0) : skinverwaltung_t::construction_site->get_image_id(0); } else if( (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING && tile->get_desc()->get_type() < building_desc_t::others)) { // hide with transparency or tile without information if(env_t::hide_with_transparency) { if(tile->get_desc()->get_type() == building_desc_t::factory && ptr.fab->get_desc()->get_placement() == factory_desc_t::Water) { // no ground tiles for water things return IMG_EMPTY; } return skinverwaltung_t::fussweg->get_image_id(0); } else { uint16 kind=skinverwaltung_t::construction_site->get_count()<=tile->get_desc()->get_type() ? skinverwaltung_t::construction_site->get_count()-1 : tile->get_desc()->get_type(); return skinverwaltung_t::construction_site->get_image_id( kind ); } } } if( zeige_baugrube ) { return skinverwaltung_t::construction_site->get_image_id(0); } else { return tile->get_background( anim_frame, 0, season ); } } image_id gebaeude_t::get_outline_image() const { if(env_t::hide_buildings!=0 && env_t::hide_with_transparency && !zeige_baugrube) { // opaque houses return tile->get_background( anim_frame, 0, season ); } return IMG_EMPTY; } /* gives outline colour and plots background tile if needed for transparent view */ FLAGGED_PIXVAL gebaeude_t::get_outline_colour() const { uint8 colours[] = { COL_BLACK, COL_YELLOW, COL_YELLOW, COL_PURPLE, COL_RED, COL_GREEN }; FLAGGED_PIXVAL disp_colour = 0; if(env_t::hide_buildings!=env_t::NOT_HIDE) { if(is_city_building()) { disp_colour = color_idx_to_rgb(colours[0]) | TRANSPARENT50_FLAG | OUTLINE_FLAG; } else if (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING && tile->get_desc()->get_type() < building_desc_t::others) { // special building disp_colour = color_idx_to_rgb(colours[tile->get_desc()->get_type()]) | TRANSPARENT50_FLAG | OUTLINE_FLAG; } } return disp_colour; } image_id gebaeude_t::get_image(int nr) const { if(zeige_baugrube || env_t::hide_buildings) { return IMG_EMPTY; } else { return tile->get_background( anim_frame, nr, season ); } } image_id gebaeude_t::get_front_image() const { if(zeige_baugrube) { return IMG_EMPTY; } if (env_t::hide_buildings != 0 && (is_city_building() || (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING && tile->get_desc()->get_type() < building_desc_t::others))) { return IMG_EMPTY; } else { // Show depots, station buildings etc. return tile->get_foreground( anim_frame, season ); } } /** * calculate the passenger level as function of the city size (if there) */ int gebaeude_t::get_passagier_level() const { koord dim = tile->get_desc()->get_size(); sint32 pax = tile->get_desc()->get_level(); if( !is_factory && ptr.stadt != NULL ) { // belongs to a city ... return ((pax + 6) >> 2) * welt->get_settings().get_passenger_factor() / 16; } return pax*dim.x*dim.y; } int gebaeude_t::get_mail_level() const { koord dim = tile->get_desc()->get_size(); sint32 mail = tile->get_desc()->get_mail_level(); if( !is_factory && ptr.stadt != NULL ) { return ((mail + 5) >> 2) * welt->get_settings().get_passenger_factor() / 16; } return mail*dim.x*dim.y; } /** * @return eigener Name oder Name der Fabrik falls Teil einer Fabrik */ const char *gebaeude_t::get_name() const { if(is_factory && ptr.fab) { return ptr.fab->get_name(); } switch(tile->get_desc()->get_type()) { case building_desc_t::attraction_city: return "Besonderes Gebaeude"; case building_desc_t::attraction_land: return "Sehenswuerdigkeit"; case building_desc_t::monument: return "Denkmal"; case building_desc_t::townhall: return "Rathaus"; default: break; } return "Gebaeude"; } /** * waytype associated with this object */ waytype_t gebaeude_t::get_waytype() const { const building_desc_t *desc = tile->get_desc(); waytype_t wt = invalid_wt; const building_desc_t::btype type = tile->get_desc()->get_type(); if (type == building_desc_t::depot || type == building_desc_t::generic_stop || type == building_desc_t::generic_extension) { wt = (waytype_t)desc->get_extra(); } return wt; } bool gebaeude_t::is_townhall() const { return tile->get_desc()->is_townhall(); } bool gebaeude_t::is_monument() const { return tile->get_desc()->get_type() == building_desc_t::monument; } bool gebaeude_t::is_headquarter() const { return tile->get_desc()->is_headquarters(); } bool gebaeude_t::is_city_building() const { return tile->get_desc()->is_city_building(); } uint32 gebaeude_t::get_tile_list( vector_tpl &list ) const { koord size = get_tile()->get_desc()->get_size( get_tile()->get_layout() ); const koord3d pos0 = get_pos() - get_tile()->get_offset(); // get origin koord k; list.clear(); // add all tiles for( k.y = 0; k.y < size.y; k.y++ ) { for( k.x = 0; k.x < size.x; k.x++ ) { if( grund_t* gr = welt->lookup( pos0+k ) ) { if( gebaeude_t* const add_gb = gr->find() ) { if( is_same_building( add_gb ) ) { list.append( gr ); } } } } } return list.get_count(); } void gebaeude_t::show_info() { if(get_fabrik()) { ptr.fab->open_info_window(); return; } const uint32 old_count = win_get_open_count(); const bool special = is_headquarter() || is_townhall(); if(is_headquarter()) { create_win( new headquarter_info_t(get_owner()), w_info, magic_headquarter+get_owner()->get_player_nr() ); } else if (is_townhall()) { ptr.stadt->open_info_window(); } if(!tile->get_desc()->no_info_window()) { if(!special || (env_t::townhall_info && old_count==win_get_open_count()) ) { // iterate over all places to check if there is already an open window gebaeude_t * first_tile = NULL; static vector_tpl gb_tiles; get_tile_list( gb_tiles ); for(grund_t* gr : gb_tiles ) { // no need for check, we jsut did before ... gebaeude_t* gb = gr->find(); if( win_get_magic( (ptrdiff_t)gb ) ) { // already open return; } if( first_tile==0 ) { first_tile = gb; } } // open info window for the first tile of our building (not relying on presence of (0,0) tile) first_tile->obj_t::show_info(); simachievements_t::check_query_ach(tile->get_desc()->get_name()); } } } // returns true, if there is a halt serving at least one tile bool gebaeude_t::is_within_players_network(const player_t* player) const { if( get_fabrik() ) { return ptr.fab->is_within_players_network( player ); } if( is_townhall() ) { ptr.stadt->is_within_players_network( player ); } // normal building: iterate over all tiles vector_tpl gb_tiles; get_tile_list( gb_tiles ); for(grund_t* gr : gb_tiles ) { // no need for check, we jsut did before ... if( const planquadrat_t* plan = welt->access( gr->get_pos().get_2d()) ) { if( plan->get_haltlist_count() > 0 ) { const halthandle_t* const halt_list = plan->get_haltlist(); for( int h = 0; h < plan->get_haltlist_count(); h++ ) { if( halt_list[h].is_bound() && (halt_list[h]->get_pax_enabled() || halt_list[h]->get_mail_enabled()) && halt_list[h]->has_available_network( player ) ) { return true; } } } } } return false; } bool gebaeude_t::is_same_building(const gebaeude_t* other) const { if (other) { const building_tile_desc_t* otile = other->get_tile(); // same descriptor and house tile if (get_tile()->get_desc() == otile->get_desc() && get_tile()->get_layout() == otile->get_layout() // same position of (0,0) tile && (get_pos() - get_tile()->get_offset() == other->get_pos() - otile->get_offset())) { return true; } } return false; } gebaeude_t* gebaeude_t::get_first_tile() { koord size = get_tile()->get_desc()->get_size( get_tile()->get_layout() ); const koord3d pos0 = get_pos() - get_tile()->get_offset(); // get origin koord k; // add all tiles for( k.y = 0; k.y < size.y; k.y++ ) { for( k.x = 0; k.x < size.x; k.x++ ) { if( grund_t* gr = welt->lookup( pos0+k ) ) { if( gebaeude_t* const add_gb = obj_cast(gr->first_no_way_obj()) ) { if( is_same_building( add_gb ) ) { return add_gb; } } } } } return this; } void gebaeude_t::info(cbuffer_t & buf) const { const char* name=tile->get_desc()->get_name(); if(is_factory && ptr.fab != NULL) { buf.append((char *)0); } else if(zeige_baugrube) { buf.append(translator::translate("Baustelle")); buf.append("\n"); } else if(name) { const char *trans_name = translator::translate(name); if(trans_name == name) { // no translaion here switch(tile->get_desc()->get_type()) { case building_desc_t::city_res: buf.append(translator::translate("residential house")); break; case building_desc_t::city_ind: buf.append(translator::translate("industrial building")); break; case building_desc_t::city_com: buf.append(translator::translate("shops and stores")); break; default: buf.append(name); break; } } else { // since the format changed, we remove all but double newlines char *text = new char[strlen(trans_name)+1]; char *dest = text; const char *src = trans_name; while( *src!=0 ) { *dest = *src; if(src[0]=='\n') { if(src[1]=='\n') { src ++; dest++; *dest = '\n'; } else { *dest = ' '; } } src ++; dest ++; } // remove double line breaks at the end *dest = 0; while( dest>text && *--dest=='\n' ) { *dest = 0; } buf.append(text); delete [] text; } buf.append( "\n\n" ); obj_t::info(buf); // append owner // belongs to which city? if( !is_factory && ptr.stadt != NULL ) { buf.printf(translator::translate("Town: %s\n"), ptr.stadt->get_name()); } if( !get_tile()->get_desc()->is_transport_building() ) { buf.printf("%s: %d\n", translator::translate("Passagierrate"), get_passagier_level()); buf.printf("%s: %d\n", translator::translate("Postrate"), get_mail_level()); } building_desc_t const& h = *tile->get_desc(); buf.printf("%s%u", translator::translate("\nBauzeit von"), h.get_intro_year_month() / 12); if (h.get_retire_year_month() != DEFAULT_RETIRE_DATE * 12) { buf.printf("%s%u", translator::translate("\nBauzeit bis"), h.get_retire_year_month() / 12); } buf.append("\n"); if(get_owner()==NULL) { const sint32 v = (sint32)( -welt->get_settings().cst_multiply_remove_haus * (tile->get_desc()->get_level() + 1) / 100 ); buf.printf("\n%s: %d$\n", translator::translate("Wert"), v); } if (char const* const maker = tile->get_desc()->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); } #ifdef DEBUG buf.append( "\n\nrotation " ); buf.append( tile->get_layout(), 0 ); buf.append( " best layout " ); buf.append( stadt_t::orient_city_building( get_pos().get_2d() - tile->get_offset(), tile->get_desc(), koord(3,3) ), 0 ); buf.append( "\n" ); #endif } } void gebaeude_t::rdwr(loadsave_t *file) { // do not save factory buildings => factory will reconstruct them assert(!is_factory); xml_tag_t d( file, "gebaeude_t" ); obj_t::rdwr(file); char buf[128]; short idx; if(file->is_saving()) { const char *s = tile->get_desc()->get_name(); file->rdwr_str(s); idx = tile->get_index(); } else { file->rdwr_str(buf, lengthof(buf)); } file->rdwr_short(idx); file->rdwr_long(insta_zeit); if(file->is_loading()) { tile = hausbauer_t::find_tile(buf, idx); if(tile==NULL) { // try with compatibility list first tile = hausbauer_t::find_tile(translator::compatibility_name(buf), idx); if(tile==NULL) { DBG_MESSAGE("gebaeude_t::rdwr()","neither %s nor %s, tile %i not found, try other replacement",translator::compatibility_name(buf),buf,idx); } else { DBG_MESSAGE("gebaeude_t::rdwr()","%s replaced by %s, tile %i",buf,translator::compatibility_name(buf),idx); } } if(tile==NULL) { // first check for special buildings if(strstr(buf,"TrainStop")!=NULL) { tile = hausbauer_t::find_tile("TrainStop", idx); } else if(strstr(buf,"BusStop")!=NULL) { tile = hausbauer_t::find_tile("BusStop", idx); } else if(strstr(buf,"ShipStop")!=NULL) { tile = hausbauer_t::find_tile("ShipStop", idx); } else if(strstr(buf,"PostOffice")!=NULL) { tile = hausbauer_t::find_tile("PostOffice", idx); } else if(strstr(buf,"StationBlg")!=NULL) { tile = hausbauer_t::find_tile("StationBlg", idx); } else { // try to find a fitting building int level=atoi(buf); building_desc_t::btype type = building_desc_t::unknown; if(level>0) { // May be an old 64er, so we can try some if(strncmp(buf+3,"WOHN",4)==0) { type = building_desc_t::city_res; } else if(strncmp(buf+3,"FAB",3)==0) { type = building_desc_t::city_ind; } else { type = building_desc_t::city_com; } level --; } else if(buf[3]=='_') { /* should have the form of RES/IND/COM_xx_level * xx is usually a number by can be anything without underscores */ level = atoi(strrchr( buf, '_' )+1); if(level>0) { switch(toupper(buf[0])) { case 'R': type = building_desc_t::city_res; break; case 'I': type = building_desc_t::city_ind; break; case 'C': type = building_desc_t::city_com; break; } } level --; } // we try to replace citybuildings with their matching counterparts // if none are matching, we try again without climates and timeline! switch(type) { case building_desc_t::city_res: { const building_desc_t *bdsc = hausbauer_t::get_residential( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) ); if(bdsc==NULL) { bdsc = hausbauer_t::get_residential(level,0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) ); } if( bdsc) { dbg->message("gebaeude_t::rwdr", "replace unknown building %s with residence level %i by %s",buf,level,bdsc->get_name()); tile = bdsc->get_tile(0); } } break; case building_desc_t::city_com: { // for replacement, ignore cluster and size const building_desc_t *bdsc = hausbauer_t::get_commercial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) ); if(bdsc==NULL) { bdsc = hausbauer_t::get_commercial(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) ); } if(bdsc) { dbg->message("gebaeude_t::rwdr", "replace unknown building %s with commercial level %i by %s",buf,level,bdsc->get_name()); tile = bdsc->get_tile(0); } } break; case building_desc_t::city_ind: { const building_desc_t *bdsc = hausbauer_t::get_industrial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) ); if(bdsc==NULL) { bdsc = hausbauer_t::get_industrial(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) ); if(bdsc==NULL) { bdsc = hausbauer_t::get_residential(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) ); } } if (bdsc) { dbg->message("gebaeude_t::rwdr", "replace unknown building %s with industry level %i by %s",buf,level,bdsc->get_name()); tile = bdsc->get_tile(0); } } break; default: dbg->warning("gebaeude_t::rwdr", "description %s for building at %d,%d not found (will be removed)!", buf, get_pos().x, get_pos().y); pakset_manager_t::add_missing_paks( buf, MISSING_BUILDING ); } } } // here we should have a valid tile pointer or nothing ... /* avoid double construction of monuments: * remove them from selection lists */ if (tile && tile->get_desc()->get_type() == building_desc_t::monument) { hausbauer_t::monument_erected(tile->get_desc()); } if (tile) { remove_ground = tile->has_image() && !tile->get_desc()->needs_ground(); } } if(file->is_version_less(99, 6)) { // ignore the sync flag uint8 dummy=sync; file->rdwr_byte(dummy); } // restore city pointer here if( file->is_version_atleast(99, 14) ) { sint32 city_index = -1; if( file->is_saving() && ptr.stadt!=NULL ) { city_index = welt->get_cities().index_of( ptr.stadt ); } file->rdwr_long(city_index); if( file->is_loading() && city_index!=-1 && (tile==NULL || tile->get_desc()==NULL || tile->get_desc()->is_connected_with_town()) ) { ptr.stadt = welt->get_cities()[city_index]; } } if(file->is_loading()) { anim_frame = 0; anim_time = 0; sync = false; // rebuild tourist attraction list if(tile && tile->get_desc()->is_attraction()) { welt->add_attraction( this ); } } } void gebaeude_t::finish_rd() { player_t::add_maintenance(get_owner(), tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype()); // citybuilding, but no town? if( tile->get_offset()==koord(0,0) ) { if( tile->get_desc()->is_connected_with_town() ) { stadt_t *city = (ptr.stadt==NULL) ? welt->find_nearest_city( get_pos().get_2d() ) : ptr.stadt; if(city) { #ifdef MULTI_THREAD pthread_mutex_lock( &add_to_city_mutex ); #endif city->add_gebaeude_to_stadt(this, true); #ifdef MULTI_THREAD pthread_mutex_unlock( &add_to_city_mutex ); #endif } } else if( !is_factory ) { ptr.stadt = NULL; } #ifdef REPAIR_MULTITILE_BUILD // check multitile buildings for lost tiles koord size = tile->get_desc()->get_size(0); const building_desc_t* desc = tile->get_desc(); if (size.x + size.y > 2) { // ATTENTION: So far does only work for symmetrical buildings if (grund_t* gr = welt->lookup_kartenboden(get_pos().get_2d() - size + koord(1, 1))) { if (gebaeude_t* gb = gr->find()) { if (gb->get_tile() == tile) { // found misalinged building here => correct its tiles for (sint16 dx = 0; dx < size.x; dx++) { for (sint16 dy = 0; dy < size.x; dy++) { if (grund_t* gbgr = welt->lookup(gr->get_pos() + koord(dx, dy))) { if (gebaeude_t* gb = gbgr->find()) { gb->set_tile(desc->get_tile(0, dx, dy), false); } } } } } } } } #endif } } void gebaeude_t::cleanup(player_t *player) { // DBG_MESSAGE("gebaeude_t::entferne()","gb %i"); // remove costs sint64 cost = welt->get_settings().cst_multiply_remove_haus; // tearing down halts is always single costs only if (!tile->get_desc()->is_transport_building()) { cost *= tile->get_desc()->get_level() + 1; } player_t::book_construction_costs(player, cost, get_pos().get_2d(), tile->get_desc()->get_finance_waytype()); // may need to update next buildings, in the case of start, middle, end buildings if(tile->get_desc()->get_all_layouts()>1 && !is_city_building()) { // realign surrounding buildings... uint32 layout = tile->get_layout(); // detect if we are connected at far (north/west) end grund_t * gr = welt->lookup( get_pos() ); if(gr) { sint8 offset = gr->get_weg_yoff()/TILE_HEIGHT_STEP; gr = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::east : koord::south), offset) ); if(!gr) { // check whether bridge end tile grund_t * gr_tmp = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::east : koord::south),offset - 1) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) { gr = gr_tmp; } } if(gr) { gebaeude_t* gb = gr->find(); if(gb && gb->get_tile()->get_desc()->get_all_layouts()>4u) { koord xy = gb->get_tile()->get_offset(); uint8 layoutbase = gb->get_tile()->get_layout(); if((layoutbase & 1u) == (layout & 1u)) { layoutbase |= 4u; // set far bit on neighbour gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false ); } } } // detect if near (south/east) end gr = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::west : koord::north), offset) ); if(!gr) { // check whether bridge end tile grund_t * gr_tmp = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::west : koord::north),offset - 1) ); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) { gr = gr_tmp; } } if(gr) { gebaeude_t* gb = gr->find(); if(gb && gb->get_tile()->get_desc()->get_all_layouts()>4) { koord xy = gb->get_tile()->get_offset(); uint8 layoutbase = gb->get_tile()->get_layout(); if((layoutbase & 1u) == (layout & 1u)) { layoutbase |= 2u; // set near bit on neighbour gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false ); } } } } } mark_images_dirty(); } void gebaeude_t::mark_images_dirty() const { // remove all traces from the screen image_id img; if( zeige_baugrube || (!env_t::hide_with_transparency && env_t::hide_buildings>(is_city_building() ? env_t::NOT_HIDE : env_t::SOME_HIDDEN_BUILDING)) ) { img = skinverwaltung_t::construction_site->get_image_id(0); } else { img = tile->get_background( anim_frame, 0, season ) ; } for( int i=0; img!=IMG_EMPTY; img=get_image(++i) ) { mark_image_dirty( img, -(i*get_tile_raster_width()) ); } } simutrans-124.3/src/simutrans/obj/gebaeude.h000066400000000000000000000075211474050137200210600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_GEBAEUDE_H #define OBJ_GEBAEUDE_H #include "simobj.h" #include "../simcolor.h" class building_tile_desc_t; class fabrik_t; class stadt_t; class grund_t; /** * Asynchronous or synchronous animations for buildings. */ class gebaeude_t : public obj_t { private: const building_tile_desc_t *tile; /** * Time control for animation progress. */ uint16 anim_time; /** * Is this a sync animated object? */ uint8 sync:1; /** * Boolean flag if a construction site or buildings image * shall be displayed. */ uint8 zeige_baugrube:1; /** * if true, this ptr union contains a factory pointer */ uint8 is_factory:1; uint8 season:3; uint8 background_animated:1; uint8 remove_ground:1; // true if ground image can go uint8 anim_frame; /** * Zeitpunkt an dem das Gebaeude Gebaut wurde */ uint32 insta_zeit; /** * either point to a factory or a city */ union { fabrik_t *fab; stadt_t *stadt; } ptr; /** * Initializes all variables with safe, usable values */ void init(); protected: gebaeude_t(); public: gebaeude_t(loadsave_t *file); gebaeude_t(koord3d pos,player_t *player, const building_tile_desc_t *t); virtual ~gebaeude_t(); void rotate90() OVERRIDE; void add_alter(uint32 a); void set_fab(fabrik_t *fd); void set_stadt(stadt_t *s); fabrik_t* get_fabrik() const { return is_factory ? ptr.fab : NULL; } stadt_t* get_stadt() const { return is_factory ? NULL : ptr.stadt; } obj_t::typ get_typ() const OVERRIDE { return obj_t::gebaeude; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE; image_id get_image() const OVERRIDE; image_id get_image(int nr) const OVERRIDE; image_id get_front_image() const OVERRIDE; void mark_images_dirty() const; image_id get_outline_image() const OVERRIDE; FLAGGED_PIXVAL get_outline_colour() const OVERRIDE; // caches image at height 0 void calc_image() OVERRIDE; /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool) OVERRIDE { calc_image(); return true; } /** * @return eigener Name oder Name der Fabrik falls Teil einer Fabrik */ const char *get_name() const OVERRIDE; bool is_townhall() const; bool is_headquarter() const; bool is_monument() const; bool is_city_building() const; /// fills vector with a list of all tiles with this building /// @return number of actual tiles uint32 get_tile_list( vector_tpl& list ) const; /// @copydoc obj_t::info void info(cbuffer_t & buf) const OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; /** * Play animations of animated buildings. * Count-down to replace construction site image by regular image. */ sync_result sync_step(uint32 delta_t); /** * @return Den level (die Ausbaustufe) des Gebaudes */ int get_passagier_level() const; int get_mail_level() const; void set_tile( const building_tile_desc_t *t, bool start_with_construction ); const building_tile_desc_t *get_tile() const { return tile; } bool is_within_players_network(const player_t* player) const; void show_info() OVERRIDE; void cleanup(player_t *player) OVERRIDE; /** * Called after the world is completely * add buildings to towns if needed * may repair broken buildings if REPAIR_MULTITILE_BUILD is set */ void finish_rd() OVERRIDE; // currently animated bool is_sync() const { return sync; } /** * @returns pointer to first tile of a multi-tile building. */ gebaeude_t* get_first_tile(); /** * @returns true if both building tiles are part of one (multi-tile) building. */ bool is_same_building(const gebaeude_t* other) const; }; template<> inline gebaeude_t* obj_cast(obj_t* const d) { return dynamic_cast(d); } #endif simutrans-124.3/src/simutrans/obj/groundobj.cc000066400000000000000000000172451474050137200214520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../world/simworld.h" #include "simobj.h" #include "../display/simimg.h" #include "../player/simplay.h" #include "../simtypes.h" #include "../ground/grund.h" #include "../descriptor/groundobj_desc.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "../utils/simrandom.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/freelist.h" #include "groundobj.h" /******************************** static routines for desc management ****************************************************************/ vector_tpl groundobj_t::groundobj_typen(0); weighted_vector_tpl* groundobj_t::groundobj_list_per_climate = NULL; stringhashtable_tpl groundobj_t::desc_table; bool compare_groundobj_desc(const groundobj_desc_t* a, const groundobj_desc_t* b) { return strcmp(a->get_name(), b->get_name())<0; } // total number of groundobj for a certain climate int groundobj_t::get_count(climate cl) { return groundobj_list_per_climate[cl].get_count(); } /** * groundobj planting function - it takes care of checking suitability of area */ bool groundobj_t::plant_groundobj_on_coordinate(koord pos, const groundobj_desc_t *desc, const bool check_climate) { // none there if( desc_table.empty() ) { return false; } grund_t *gr = welt->lookup_kartenboden(pos); if( gr ) { if( gr->ist_natur() && (!check_climate || desc->is_allowed_climate( welt->get_climate(pos) )) ) { if( gr->obj_count() > 0 ) { switch(gr->obj_bei(0)->get_typ()) { case obj_t::cloud: case obj_t::air_vehicle: case obj_t::leitung: case obj_t::label: case obj_t::zeiger: // ok to built here break; case obj_t::baum: if( desc->can_build_trees_here() ) { break; } /* FALLTHROUGH */ // leave these (and all other empty) default: return false; } } groundobj_t *g = new groundobj_t(gr->get_pos(), desc); //plants the groundobj gr->obj_add( g ); return true; //groundobj was planted - currently unused value is not checked } } return false; } bool groundobj_t::successfully_loaded() { groundobj_typen.reserve(desc_table.get_count()); for(auto const& i : desc_table) { groundobj_typen.insert_ordered(i.value, compare_groundobj_desc); } // iterate again to assign the index for(auto const& i : desc_table) { i.value->index = groundobj_typen.index_of(i.value); } if(desc_table.empty()) { groundobj_typen.append( NULL ); DBG_MESSAGE("groundobj_t", "No groundobj found - feature disabled"); } delete [] groundobj_list_per_climate; groundobj_list_per_climate = new weighted_vector_tpl[MAX_CLIMATES]; for( uint32 typ=0; typis_allowed_climate((climate)j) ) { groundobj_list_per_climate[j].append(typ, groundobj_typen[typ]->get_distribution_weight()); } } } return true; } bool groundobj_t::register_desc(groundobj_desc_t *desc) { assert(desc->get_speed()==0); // remove duplicates if(groundobj_desc_t *old = desc_table.remove( desc->get_name() ) ) { delete old; } desc_table.put(desc->get_name(), desc ); return true; } /** * also checks for distribution values */ const groundobj_desc_t *groundobj_t::random_groundobj_for_climate(climate_bits cl, slope_t::type slope ) { // none there if( desc_table.empty() ) { return NULL; } int weight = 0; for(groundobj_desc_t const* const i : groundobj_typen ) { if( i->is_allowed_climate_bits(cl) && (slope == slope_t::flat || (i->get_phases() >= slope && i->get_image_id(0,slope)!=IMG_EMPTY ) ) ) { weight += i->get_distribution_weight(); } } // now weight their distribution if( weight > 0 ) { const int w=simrand(weight); weight = 0; for(groundobj_desc_t const* const i : groundobj_typen) { if( i->is_allowed_climate_bits(cl) && (slope == slope_t::flat || (i->get_phases() >= slope && i->get_image_id(0,slope)!=IMG_EMPTY ) ) ) { weight += i->get_distribution_weight(); if(weight>=w) { return i; } } } } return NULL; } /******************************* end of static ******************************************/ uint16 groundobj_t::random_groundobj_for_climate_intern(climate cl) { // now weight their distribution weighted_vector_tpl const& g = groundobj_list_per_climate[cl]; return g.empty() ? 0xFFFF : pick_any_weighted(g); } // recalculates only the seasonal image void groundobj_t::calc_image() { const groundobj_desc_t *desc=get_desc(); const uint8 seasons = desc->get_seasons()-1; uint8 season = 0; // two possibilities switch(seasons) { // summer only case 0: season = 0; break; // summer, snow case 1: season = welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate; break; // summer, winter, snow case 2: season = (welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate) ? 2 : welt->get_season() == 1; break; default: if( welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate ) { season = seasons; } else { // resolution 1/8th month (0..95) const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_ticks()>>(welt->ticks_per_world_month_shift-3))&7) + 1; season = (seasons*yearsteps-1)/96; } break; } // check for slopes? uint16 phase = 0; if(desc->get_phases()>1) { phase = welt->lookup(get_pos())->get_grund_hang(); } image = get_desc()->get_image_id( season, phase ); } groundobj_t::groundobj_t(loadsave_t *file) : obj_t() { rdwr(file); } groundobj_t::groundobj_t(koord3d pos, const groundobj_desc_t *b ) : obj_t(pos) { groundobjtype = groundobj_typen.index_of(b); calc_image(); } bool groundobj_t::check_season(const bool) { const image_id old_image = get_image(); calc_image(); if( get_image() != old_image ) { mark_image_dirty( get_image(), 0 ); } return true; } void groundobj_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "groundobj_t" ); obj_t::rdwr(file); if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); groundobj_desc_t *desc = desc_table.get( bname ); if( desc==NULL ) { desc = desc_table.get( translator::compatibility_name( bname ) ); } if( desc==NULL ) { groundobjtype = simrand(groundobj_typen.get_count()); } else { groundobjtype = desc->get_index(); } // if not there, desc will be zero } } void groundobj_t::show_info() { if(env_t::tree_info) { obj_t::show_info(); } } void groundobj_t::info(cbuffer_t & buf) const { translator::get_obj_info(buf, get_desc()->get_name()); if (char const* const maker = get_desc()->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); } buf.append("\n"); buf.append(translator::translate("cost for removal")); char buffer[128]; money_to_string( buffer, get_desc()->get_price()/100.0 ); buf.append( buffer ); } void groundobj_t::cleanup(player_t *player) { player_t::book_construction_costs(player, -get_desc()->get_price(), get_pos().get_2d(), ignore_wt); mark_image_dirty( get_image(), 0 ); } void *groundobj_t::operator new(size_t /*s*/) { return freelist_t::gimme_node(sizeof(groundobj_t)); } void groundobj_t::operator delete(void *p) { freelist_t::putback_node(sizeof(groundobj_t),p); } simutrans-124.3/src/simutrans/obj/groundobj.h000066400000000000000000000047561474050137200213170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_GROUNDOBJ_H #define OBJ_GROUNDOBJ_H #include "simobj.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../descriptor/groundobj_desc.h" #include "../dataobj/environment.h" /** * Decorative objects, like rocks, ponds etc. */ class groundobj_t : public obj_t { private: /// type of object, index into groundobj_typen uint16 groundobjtype; /// the image, cached image_id image; /// table to lookup object based on name static stringhashtable_tpl desc_table; /// all such objects static vector_tpl groundobj_typen; static weighted_vector_tpl* groundobj_list_per_climate; static uint16 random_groundobj_for_climate_intern(climate cl); public: static bool register_desc(groundobj_desc_t *desc); static bool successfully_loaded(); static const groundobj_desc_t *random_groundobj_for_climate(climate_bits cl, slope_t::type slope ); groundobj_t(loadsave_t *file); groundobj_t(koord3d pos, const groundobj_desc_t *); void rdwr(loadsave_t *file) OVERRIDE; image_id get_image() const OVERRIDE { return image; } /// recalculates image depending on season and slope of ground void calc_image() OVERRIDE; /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool) OVERRIDE; const char *get_name() const OVERRIDE {return "Groundobj";} typ get_typ() const OVERRIDE { return groundobj; } void show_info() OVERRIDE; void info(cbuffer_t & buf) const OVERRIDE; void cleanup(player_t *player) OVERRIDE; const groundobj_desc_t* get_desc() const { return groundobj_typen[groundobjtype]; } static vector_tpl const& get_all_desc() { return groundobj_typen; } static const groundobj_desc_t *find_groundobj( const char *obj_name ) { return groundobj_typen.empty() ? NULL : desc_table.get(obj_name); } static bool plant_groundobj_on_coordinate(koord pos, const groundobj_desc_t *desc, const bool check_climate); static const groundobj_desc_t *random_groundobj_for_climate(climate cl) { uint16 b = random_groundobj_for_climate_intern(cl); return b!=0xFFFF ? groundobj_typen[b] : NULL; } void * operator new(size_t s); void operator delete(void *p); static int get_count() { return groundobj_typen.get_count()-1; } static int get_count(climate cl); }; #endif simutrans-124.3/src/simutrans/obj/label.cc000066400000000000000000000042651474050137200205360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "simobj.h" #include "../display/simimg.h" #include "../simskin.h" #include "../gui/simwin.h" #include "../simhalt.h" #include "../player/simplay.h" #include "../gui/label_info.h" #include "../descriptor/ground_desc.h" #include "../descriptor/skin_desc.h" #include "../dataobj/environment.h" #include "label.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t add_label_mutex = PTHREAD_MUTEX_INITIALIZER; #endif label_t::label_t(loadsave_t *file) : obj_t() { rdwr(file); } label_t::label_t(koord3d pos, player_t *player, const char *text) : obj_t(pos) { set_owner( player ); grund_t *gr=welt->lookup_kartenboden(pos.get_2d()); if(gr) { if (text) { gr->set_text(text); } player_t::book_construction_costs(player, welt->get_settings().cst_buy_land, pos.get_2d(), ignore_wt); welt->add_label(pos.get_2d()); } else { dbg->error("label_t", "cannot create label on empty ground at %s", pos.get_fullstr()); } } label_t::~label_t() { koord k = get_pos().get_2d(); welt->remove_label(k); grund_t *gr = welt->lookup_kartenboden(k); if(gr) { // do not remove name from halts if (!gr->is_halt() || gr->get_halt()->get_basis_pos3d()!=gr->get_pos()) { gr->set_text(NULL); } } else { dbg->error("label_t", "cannot remove label on empty ground at %s", get_pos().get_fullstr()); } } void label_t::finish_rd() { #ifdef MULTI_THREAD pthread_mutex_lock( &add_label_mutex ); #endif // only now coordinates are known welt->add_label(get_pos().get_2d()); // broken label? set text to "" grund_t *gr = welt->lookup_kartenboden(get_pos().get_2d()); if (!gr->get_flag(grund_t::has_text)) { gr->set_text(""); } #ifdef MULTI_THREAD pthread_mutex_unlock( &add_label_mutex ); #endif } image_id label_t::get_image() const { grund_t *gr=welt->lookup(get_pos()); return gr && gr->obj_bei(0) == sim::up_cast(this) ? skinverwaltung_t::belegtzeiger->get_image_id(0) : IMG_EMPTY; } void label_t::show_info() { label_t* l = this; create_win(new label_info_t(l), w_info, (ptrdiff_t)this ); } simutrans-124.3/src/simutrans/obj/label.h000066400000000000000000000011201474050137200203630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_LABEL_H #define OBJ_LABEL_H #include "simobj.h" #include "../display/simimg.h" /* * Object which shows the label that indicates that the ground is owned by somebody */ class label_t : public obj_t { public: label_t(loadsave_t *file); label_t(koord3d pos, player_t *player, const char *text); ~label_t(); void finish_rd() OVERRIDE; void show_info() OVERRIDE; typ get_typ() const OVERRIDE { return obj_t::label; } image_id get_image() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/leitung2.cc000066400000000000000000000467431474050137200212170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t verbinde_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t calc_image_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #include "leitung2.h" #include "../simdebug.h" #include "../world/simworld.h" #include "simobj.h" #include "../player/simplay.h" #include "../display/simimg.h" #include "../simfab.h" #include "../simskin.h" #include "../display/simgraph.h" #include "../utils/cbuffer.h" #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../dataobj/powernet.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "../ground/grund.h" #include "../builder/wegbauer.h" const uint32 POWER_TO_MW = 12; // use same precision as powernet const uint8 leitung_t::FRACTION_PRECISION = powernet_t::FRACTION_PRECISION; /** * returns possible directions for powerline on this tile */ ribi_t::ribi get_powerline_ribi(grund_t *gr) { slope_t::type slope = gr->get_weg_hang(); ribi_t::ribi ribi = (ribi_t::ribi)ribi_t::all; if (slope == slope_t::flat) { // respect possible directions for bridge and tunnel starts if (gr->ist_karten_boden() && (gr->ist_tunnel() || gr->ist_bruecke())) { ribi = ribi_t::doubles( ribi_type( gr->get_grund_hang() ) ); } } else { ribi = ribi_t::doubles( ribi_type(slope) ); } return ribi; } int leitung_t::gimme_neighbours(leitung_t **conn) { int count = 0; grund_t *gr_base = welt->lookup(get_pos()); ribi_t::ribi ribi = get_powerline_ribi(gr_base); for(int i=0; i<4; i++) { // get next connected tile (if there) grund_t *gr; conn[i] = NULL; if( (ribi & ribi_t::nesw[i]) && gr_base->get_neighbour( gr, invalid_wt, ribi_t::nesw[i] ) ) { leitung_t *lt = gr->get_leitung(); // check that we can connect to the other tile: correct slope, // both ground or both tunnel or both not tunnel bool const ok = (gr->ist_karten_boden() && gr_base->ist_karten_boden()) || (gr->ist_tunnel()==gr_base->ist_tunnel()); if( lt && (ribi_t::backward(ribi_t::nesw[i]) & get_powerline_ribi(gr)) && ok ) { const player_t *owner = get_owner(); const player_t *other = lt->get_owner(); const player_t *super = welt->get_public_player(); if (owner==other || owner==super || other==super) { conn[i] = lt; count++; } } } } return count; } fabrik_t *leitung_t::suche_fab_4(const koord pos) { for(int k=0; k<4; k++) { fabrik_t *fab = fabrik_t::get_fab( pos+koord::nesw[k] ); if(fab) { return fab; } } return NULL; } leitung_t::leitung_t(loadsave_t *file) : obj_t() { image = IMG_EMPTY; set_net(NULL); ribi = ribi_t::none; is_transformer = false; rdwr(file); } leitung_t::leitung_t(koord3d pos, player_t *player) : obj_t(pos) { image = IMG_EMPTY; set_net(NULL); set_owner( player ); set_desc(way_builder_t::leitung_desc); is_transformer = false; } leitung_t::~leitung_t() { if (welt->is_destroying()) { return; } grund_t *gr = welt->lookup(get_pos()); if(gr) { leitung_t *conn[4]; int neighbours = gimme_neighbours(conn); gr->obj_remove(this); set_flag( obj_t::not_on_map ); if(neighbours>1) { // only reconnect if two connections ... bool first = true; for(int i=0; i<4; i++) { if(conn[i]!=NULL) { if(!first) { // replace both nets powernet_t *new_net = new powernet_t(); conn[i]->replace(new_net); } first = false; } } } // recalc images for(int i=0; i<4; i++) { if(conn[i]!=NULL) { conn[i]->calc_neighbourhood(); } } if(neighbours==0) { delete net; } player_t::add_maintenance(get_owner(), -get_maintenance(), powerline_wt); } } void leitung_t::cleanup(player_t *player) { player_t::book_construction_costs(player, -desc->get_price()/2, get_pos().get_2d(), powerline_wt); mark_image_dirty( image, 0 ); } /** * called during map rotation */ void leitung_t::rotate90() { obj_t::rotate90(); ribi = ribi_t::rotate90( ribi ); } /** * replace networks connection * non-trivial to handle transformers correctly */ void leitung_t::replace(powernet_t* new_net) { if (get_net() != new_net) { // convert myself ... //DBG_MESSAGE("leitung_t::replace()","My net %p by %p at (%i,%i)",new_net,current,base_pos.x,base_pos.y); set_net(new_net); } leitung_t * conn[4]; if(gimme_neighbours(conn)>0) { for(int i=0; i<4; i++) { if(conn[i] && conn[i]->get_net()!=new_net) { conn[i]->replace(new_net); } } } } /** * Connect this piece of powerline to its neighbours * -> this can merge power networks */ void leitung_t::verbinde() { // first get my own ... powernet_t *new_net = get_net(); //DBG_MESSAGE("leitung_t::verbinde()","Searching net at (%i,%i)",get_pos().x,get_pos().x); leitung_t * conn[4]; if(gimme_neighbours(conn)>0) { for( uint8 i=0; i<4 && new_net==NULL; i++ ) { if(conn[i]) { new_net = conn[i]->get_net(); } } } //DBG_MESSAGE("leitung_t::verbinde()","Found net %p",new_net); // we are alone? if(get_net()==NULL) { if(new_net!=NULL) { replace(new_net); } else { // then we start a new net set_net(new powernet_t()); //DBG_MESSAGE("leitung_t::verbinde()","Creating new net %p",new_net); } } else if(new_net) { powernet_t *my_net = get_net(); for( uint8 i=0; i<4; i++ ) { if(conn[i] && conn[i]->get_net()!=new_net) { conn[i]->replace(new_net); } } if(my_net && my_net!=new_net) { delete my_net; } } } void leitung_t::calc_image() { is_crossing = false; const koord pos = get_pos().get_2d(); bool snow = get_pos().z >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate; grund_t *gr = welt->lookup(get_pos()); if(gr==NULL) { // no valid ground; usually happens during building ... return; } if(gr->ist_bruecke() || (gr->get_typ()==grund_t::tunnelboden && gr->ist_karten_boden())) { // don't display on a bridge or in a tunnel) set_image(IMG_EMPTY); return; } image_id old_image = get_image(); slope_t::type hang = gr->get_weg_hang(); if(hang != slope_t::flat) { set_image( desc->get_slope_image_id(hang, snow)); } else { if(gr->hat_wege()) { // crossing with road or rail weg_t* way = gr->get_weg_nr(0); if(ribi_t::is_straight_ew(way->get_ribi())) { set_image( desc->get_diagonal_image_id(ribi_t::north|ribi_t::east, snow)); } else { set_image( desc->get_diagonal_image_id(ribi_t::south|ribi_t::east, snow)); } is_crossing = true; } else { if(ribi_t::is_straight(ribi) && !ribi_t::is_single(ribi) && (pos.x+pos.y)&1) { // every second skip mast if(ribi_t::is_straight_ns(ribi)) { set_image( desc->get_diagonal_image_id(ribi_t::north|ribi_t::west, snow)); } else { set_image( desc->get_diagonal_image_id(ribi_t::south|ribi_t::west, snow)); } } else { set_image( desc->get_image_id(ribi, snow)); } } } if (old_image != get_image()) { mark_image_dirty(old_image,0); } } /** * Recalculates the images of all neighbouring * powerlines and the powerline itself */ void leitung_t::calc_neighbourhood() { leitung_t *conn[4]; ribi = ribi_t::none; if(gimme_neighbours(conn)>0) { for( uint8 i=0; i<4 ; i++ ) { if(conn[i] && conn[i]->get_net()==get_net()) { ribi |= ribi_t::nesw[i]; conn[i]->add_ribi(ribi_t::backward(ribi_t::nesw[i])); conn[i]->calc_image(); } } } set_flag( obj_t::dirty ); calc_image(); } void leitung_t::info(cbuffer_t & buf) const { translator::get_obj_info(buf, desc->get_name()); obj_t::info(buf); powernet_t * const net = get_net(); buf.printf(translator::translate("Net ID: %p"), net); buf.printf("\n"); //buf.printf(translator::translate("Capacity: %.0f MW"), (double)(net->get_max_capacity() >> POWER_TO_MW)); //buf.printf("\n"); buf.printf(translator::translate("Demand: %.0f MW"), (double)(net->get_demand() >> POWER_TO_MW)); buf.printf("\n"); buf.printf(translator::translate("Generation: %.0f MW"), (double)(net->get_supply() >> POWER_TO_MW)); buf.printf("\n"); buf.printf(translator::translate("Usage: %.0f %%"), (double)((100 * net->get_normal_demand()) >> powernet_t::FRACTION_PRECISION)); } void leitung_t::finish_rd() { #ifdef MULTI_THREAD pthread_mutex_lock( &verbinde_mutex ); verbinde(); pthread_mutex_unlock( &verbinde_mutex ); pthread_mutex_lock( &calc_image_mutex ); calc_neighbourhood(); pthread_mutex_unlock( &calc_image_mutex ); #else verbinde(); calc_neighbourhood(); #endif grund_t *gr = welt->lookup(get_pos()); assert(gr); (void)gr; player_t::add_maintenance(get_owner(), get_maintenance(), powerline_wt); } void leitung_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "leitung_t" ); obj_t::rdwr(file); // no longer save power net pointer as it is no longer used if( file->is_version_less(120, 4) ) { uint32 value = 0; file->rdwr_long(value); } if( file->is_loading() ) { set_net(NULL); } if(get_typ()==leitung) { /* ATTENTION: during loading thus MUST not be called from the constructor!!! * (Otherwise it will be always true! */ if(file->is_version_atleast(102, 3)) { if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); const way_desc_t *desc = way_builder_t::get_desc(bname); if(desc==NULL) { desc = way_builder_t::get_desc(translator::compatibility_name(bname)); if(desc==NULL) { pakset_manager_t::add_missing_paks( bname, MISSING_WAY ); desc = way_builder_t::leitung_desc; if (!desc) { dbg->fatal("leitung_t::rdwr", "Trying to load powerline but pakset has none!"); } } dbg->warning("leitung_t::rdwr()", "Unknown powerline %s replaced by %s", bname, desc->get_name() ); } set_desc(desc); } } else { if (file->is_loading()) { set_desc(way_builder_t::leitung_desc); } } } } // returns NULL, if removal is allowed // players can remove public owned powerlines const char *leitung_t::get_removal_error(const player_t *player) { if( get_owner_nr()==PLAYER_PUBLIC_NR && player ) { return NULL; } return obj_t::get_removal_error(player); } sint64 leitung_t::get_maintenance() const { if (!is_transformer) { return desc->get_maintenance(); } else { return -welt->get_settings().cst_maintain_transformer; } } /************************************ from here on pump (source) stuff ********************************************/ freelist_iter_tpl pumpe_t::pl; pumpe_t::pumpe_t(loadsave_t *file ) : leitung_t( koord3d::invalid, NULL ) { fab = NULL; power_supply = 0; is_transformer = true; rdwr( file ); } pumpe_t::pumpe_t(koord3d pos, player_t *player) : leitung_t(pos, player) { fab = NULL; power_supply = 0; is_transformer = true; player_t::book_construction_costs(player, welt->get_settings().cst_transformer, get_pos().get_2d(), powerline_wt); } pumpe_t::~pumpe_t() { if(fab) { fab->remove_transformer_connected(this); fab = NULL; } if( net != NULL ) { net->sub_supply(power_supply); } } sync_result pumpe_t::sync_step(uint32 delta_t) { if( fab == NULL ) { return SYNC_DELETE; } else if( delta_t == 0 ) { return SYNC_OK; } // resolve image uint16 winter_offset = 0; if( skinverwaltung_t::senke->get_count() > 3 && (get_pos().z >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate) ) { winter_offset = 2; } uint16 const image_offset = power_supply > 0 ? 1 : 0; image_id const new_image = skinverwaltung_t::pumpe->get_image_id(image_offset + winter_offset); // update image if( image != new_image ) { set_flag(obj_t::dirty); set_image(new_image); } return SYNC_OK; } void pumpe_t::set_net(powernet_t * p) { powernet_t * p_old = get_net(); if( p_old != NULL ) { p_old->sub_supply(power_supply); } leitung_t::set_net(p); if( p != NULL ) { p->add_supply(power_supply); } } void pumpe_t::set_power_supply(uint32 newsupply) { // update power network powernet_t *const p = get_net(); if( p != NULL ) { p->sub_supply(power_supply); p->add_supply(newsupply); } power_supply = newsupply; } sint32 pumpe_t::get_power_consumption() const { powernet_t const *const p = get_net(); return p->get_normal_demand(); } void pumpe_t::rdwr(loadsave_t * file) { xml_tag_t d( file, "pumpe_t" ); leitung_t::rdwr(file); // current power state if( file->is_version_atleast(120, 4) ) { file->rdwr_long(power_supply); } } void pumpe_t::finish_rd() { leitung_t::finish_rd(); assert(get_net()); if( fab==NULL ) { if(welt->lookup(get_pos())->ist_karten_boden()) { // on surface, check around fab = leitung_t::suche_fab_4(get_pos().get_2d()); } else { // underground, check directly above fab = fabrik_t::get_fab(get_pos().get_2d()); } if( fab ) { // only add when factory there fab->add_transformer_connected(this); } } #ifdef MULTI_THREAD pthread_mutex_lock( &calc_image_mutex ); set_image(skinverwaltung_t::pumpe->get_image_id(0)); is_crossing = false; pthread_mutex_unlock( &calc_image_mutex ); #else set_image(skinverwaltung_t::pumpe->get_image_id(0)); is_crossing = false; #endif } void pumpe_t::info(cbuffer_t & buf) const { translator::get_obj_info(buf, desc->get_name()); obj_t::info( buf ); buf.printf(translator::translate("Net ID: %p"), get_net()); buf.printf("\n"); buf.printf(translator::translate("Generation: %.0f MW"), (double)(power_supply >> POWER_TO_MW)); buf.printf("\n"); buf.printf(translator::translate("Usage: %.0f %%"), (double)((100 * get_net()->get_normal_demand()) >> powernet_t::FRACTION_PRECISION)); buf.printf("\n"); // pad for consistent dialog size } /************************************ Distriubtion Transformer Code ********************************************/ freelist_iter_tpl senke_t::sl; uint32 senke_t::payment_timer = 0; bool senke_t::payout = false; void senke_t::new_world() { payment_timer = 0; payout = false; } void senke_t::static_rdwr(loadsave_t *file) { if( file->is_version_atleast(120, 4) ) { file->rdwr_long(payment_timer); } } void senke_t::sync_handler(uint32 delta_t) { // payment period (could be tied to game setting) const uint32 pay_period = PRODUCTION_DELTA_T * 10; // 10 seconds // revenue payout timer payment_timer += delta_t; payout = payment_timer >= pay_period; payment_timer %= pay_period; sl.sync_step(delta_t); } senke_t::senke_t(loadsave_t *file) : leitung_t( koord3d::invalid, NULL ) { fab = NULL; delta_t_sum = 0; next_t = 0; power_demand = 0; energy_acc = 0; is_transformer = true; rdwr( file ); } senke_t::senke_t(koord3d pos, player_t *player) : leitung_t(pos, player) { fab = NULL; delta_t_sum = 0; next_t = 0; power_demand = 0; energy_acc = 0; is_transformer = true; player_t::book_construction_costs(player, welt->get_settings().cst_transformer, get_pos().get_2d(), powerline_wt); } senke_t::~senke_t() { // one last final income pay_revenue(); if(fab!=NULL) { fab->remove_transformer_connected(this); fab = NULL; } if( net != NULL ) { net->sub_demand(power_demand); } } void senke_t::pay_revenue() { // megajoules (megawatt seconds) per cent const uint64 mjpc = (1 << POWER_TO_MW) / CREDIT_PER_MWS; // should be tied to game setting // calculate payment in cent const sint64 payment = (sint64)(energy_acc / mjpc); // make payment if( payment > 0 ) { // enough has accumulated for a payment get_owner()->book_revenue( payment, get_pos().get_2d(), powerline_wt ); // remove payment from accumulator energy_acc %= mjpc; } } void senke_t::set_net(powernet_t * p) { powernet_t * p_old = get_net(); if( p_old != NULL ) { p_old->sub_demand(power_demand); } leitung_t::set_net(p); if( p != NULL ) { p->add_demand(power_demand); } } void senke_t::set_power_demand(uint32 newdemand) { // update power network powernet_t *const p = get_net(); if( p != NULL ) { p->sub_demand(power_demand); p->add_demand(newdemand); } power_demand = newdemand; } sint32 senke_t::get_power_satisfaction() const { powernet_t const *const p = get_net(); return p->get_normal_supply(); } sync_result senke_t::sync_step(uint32 delta_t) { if(fab==NULL) { return SYNC_DELETE; } // advance timers delta_t_sum += delta_t; next_t += delta_t; // change graphics at most 16 times a second if( next_t > PRODUCTION_DELTA_T / 16 ) { // enforce timer periods delta_t_sum %= PRODUCTION_DELTA_T; // 1 second next_t %= PRODUCTION_DELTA_T / 16; // 1/16 seconds // determine pwm period for image change uint32 pwm_period = 0; const sint32 satisfaction = get_net()->get_normal_supply(); if( satisfaction >= 1 << powernet_t::FRACTION_PRECISION ) { // always on pwm_period = PRODUCTION_DELTA_T; } else if( satisfaction >= ((7 << powernet_t::FRACTION_PRECISION) / 8) ) { // limit to at most 7/8 of a second pwm_period = 7 * PRODUCTION_DELTA_T / 8; } else if( satisfaction > ((1 << powernet_t::FRACTION_PRECISION) / 8) ) { // duty cycle based on power satisfaction pwm_period = (uint32)(((uint64)PRODUCTION_DELTA_T * (uint64)satisfaction) >> powernet_t::FRACTION_PRECISION); } else if( satisfaction > 0 ) { // limit to at least 1/8 of a second pwm_period = PRODUCTION_DELTA_T / 8; } // determine image with PWM logic const uint16 work_offset = (delta_t_sum < pwm_period) ? 1 : 0; // apply seasonal image offset uint16 winter_offset = 0; if( skinverwaltung_t::senke->get_count() > 3 && (get_pos().z >= welt->get_snowline() || welt->get_climate(get_pos().get_2d()) == arctic_climate) ) { winter_offset = 2; } // update displayed image image_id new_image = skinverwaltung_t::senke->get_image_id(work_offset + winter_offset); if( image != new_image ) { set_flag( obj_t::dirty ); set_image( new_image ); } } // energy metering logic energy_acc += ((uint64)power_demand * (uint64)get_net()->get_normal_supply() * (uint64)delta_t) / ((uint64)PRODUCTION_DELTA_T << powernet_t::FRACTION_PRECISION); if (payout) { pay_revenue(); } return SYNC_OK; } void senke_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "senke_t" ); leitung_t::rdwr(file); // current power state if( file->is_version_atleast(120, 4) ) { file->rdwr_longlong((sint64 &)energy_acc); file->rdwr_long(power_demand); } else if (file->is_loading()) { energy_acc = 0; power_demand = 0; } if (file->is_version_atleast(122, 1)) { file->rdwr_long(delta_t_sum); file->rdwr_long(next_t); } else if (file->is_loading()) { delta_t_sum = 0; next_t = 0; } } void senke_t::finish_rd() { leitung_t::finish_rd(); assert(get_net()); if( fab==NULL ) { if(welt->lookup(get_pos())->ist_karten_boden()) { // on surface, check around fab = leitung_t::suche_fab_4(get_pos().get_2d()); } else { // underground, check directly above fab = fabrik_t::get_fab(get_pos().get_2d()); } if( fab ) { fab->add_transformer_connected(this); } } #ifdef MULTI_THREAD pthread_mutex_lock( &calc_image_mutex ); #endif set_image(skinverwaltung_t::senke->get_image_id(0)); is_crossing = false; #ifdef MULTI_THREAD pthread_mutex_unlock( &calc_image_mutex ); #endif } void senke_t::info(cbuffer_t & buf) const { translator::get_obj_info(buf, desc->get_name()); obj_t::info(buf); buf.printf(translator::translate("Net ID: %p"), get_net()); buf.printf("\n"); buf.printf(translator::translate("Demand: %.0f MW"), (double)(power_demand >> POWER_TO_MW)); buf.printf("\n"); buf.printf(translator::translate("Supplied: %.0f %%"), (double)((100 * get_net()->get_normal_supply()) >> powernet_t::FRACTION_PRECISION)); buf.printf("\n"); // pad for consistent dialog size } simutrans-124.3/src/simutrans/obj/leitung2.h000066400000000000000000000145361474050137200210540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_LEITUNG2_H #define OBJ_LEITUNG2_H #include "../dataobj/koord3d.h" #include "../dataobj/ribi.h" #include "simobj.h" #include "../tpl/freelist_iter_tpl.h" // bitshift for converting internal power values to MW for display extern const uint32 POWER_TO_MW; #define CREDIT_PER_MWS 2 class powernet_t; class player_t; class fabrik_t; class way_desc_t; class leitung_t : public obj_t { protected: image_id image; // powerline over ways bool is_crossing:1; bool is_transformer:1; // direction of the next pylon ribi_t::ribi ribi:4; /** * We are part of this network */ powernet_t * net; const way_desc_t *desc; /** * Connect this piece of powerline to its neighbours * -> this can merge power networks */ void verbinde(); void replace(powernet_t* neu); void add_ribi(ribi_t::ribi r) { ribi |= r; } /** * Dient zur Neuberechnung des Bildes */ void calc_image() OVERRIDE; public: // number of fractional bits for network load values static const uint8 FRACTION_PRECISION; powernet_t* get_net() const { return net; } /** * Changes the currently registered power net. * Can be overwritten to modify the power net on change. */ virtual void set_net(powernet_t* p) { net = p; } const way_desc_t * get_desc() { return desc; } void set_desc(const way_desc_t *new_desc) { desc = new_desc; } int gimme_neighbours(leitung_t **conn); static fabrik_t * suche_fab_4(koord pos); leitung_t(loadsave_t *file); leitung_t(koord3d pos, player_t *player); virtual ~leitung_t(); // just book the costs for destruction void cleanup(player_t *) OVERRIDE; // for map rotation void rotate90() OVERRIDE; typ get_typ() const OVERRIDE { return leitung; } const char *get_name() const OVERRIDE {return "Leitung"; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE { return powerline_wt; } /// @copydoc obj_t::info void info(cbuffer_t & buf) const OVERRIDE; ribi_t::ribi get_ribi() const { return ribi; } inline void set_image( image_id b ) { image = b; } image_id get_image() const OVERRIDE {return is_crossing ? IMG_EMPTY : image;} image_id get_front_image() const OVERRIDE {return is_crossing ? image : IMG_EMPTY;} /** * Recalculates the images of all neighbouring * powerlines and the powerline itself */ void calc_neighbourhood(); void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; /** * @return NULL if OK, otherwise an error message */ const char *get_removal_error(const player_t *player) OVERRIDE; /** * @return maintenance of this object (powerline or transformer) */ sint64 get_maintenance() const; }; class pumpe_t : public leitung_t { private: fabrik_t *fab; // The power supplied through the transformer. uint32 power_supply; static freelist_iter_tpl pl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules public: pumpe_t(loadsave_t *file); pumpe_t(koord3d pos, player_t *player); ~pumpe_t(); void* operator new(size_t) { return pl.gimme_node(); } void operator delete(void* p) { return pl.putback_node(p); } static void sync_handler(uint32 delta_t) { pl.sync_step(delta_t); } sync_result sync_step(uint32 delta_t); void set_net(powernet_t* p) OVERRIDE; /** * Set the power supply of the transformer. */ void set_power_supply(uint32 newsupply); /** * Get the power supply of the transformer. */ uint32 get_power_supply() const {return power_supply;} /** * Get the normalized satisfaction value of the power consumed, updated every tick. * Return value is fixed point with FRACTION_PRECISION fractional bits. */ sint32 get_power_consumption() const; typ get_typ() const OVERRIDE { return pumpe; } const char *get_name() const OVERRIDE {return "Aufspanntransformator";} void info(cbuffer_t & buf) const OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; void calc_image() OVERRIDE {} // empty; otherwise it will change to leitung const fabrik_t* get_factory() const { return fab; } }; /* * Distribution transformers act as an interface between power networks and * and power consuming factories. */ class senke_t : public leitung_t { private: // Timer for global power payment. static uint32 payment_timer; fabrik_t *fab; // Pwm timer for duty cycling image. uint32 delta_t_sum; // Timer for recalculating image. uint32 next_t; // The power requested through the transformer. uint32 power_demand; // Energy accumulator (how much energy has been metered). uint64 energy_acc; void step(uint32 delta_t); // Pay out revenue for the energy metered. void pay_revenue(); static freelist_iter_tpl sl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules // true, needs payout static bool payout; public: static void new_world(); /** * Read and write static state. * This is used to make payments occur at the same time after load as after saving. */ static void static_rdwr(loadsave_t* file); senke_t(loadsave_t *file); senke_t(koord3d pos, player_t *player); ~senke_t(); void* operator new(size_t) { return sl.gimme_node(); } void operator delete(void* p) { return sl.putback_node(p); } static void sync_handler(uint32 delta_t); void set_net(powernet_t* p) OVERRIDE; typ get_typ() const OVERRIDE { return senke; } /** * Set the power demand of the transformer. */ void set_power_demand(uint32 newdemand); /** * Get the power demand of the transformer. */ uint32 get_power_demand() const {return power_demand;} /** * Get the normalized satisfaction value of the power demand, updated every tick. * Return value is fixed point with FRACTION_PRECISION fractional bits. */ sint32 get_power_satisfaction() const; /** * Used to alternate between displaying power on and power off images. * Frequency determined by the percentage of power supplied. * Gives players a visual indication of a power network with insufficient generation. */ sync_result sync_step(uint32 delta_t); const char *get_name() const OVERRIDE {return "Abspanntransformator";} void info(cbuffer_t & buf) const OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; void calc_image() OVERRIDE {} // empty; otherwise it will change to leitung const fabrik_t* get_factory() const { return fab; } }; #endif simutrans-124.3/src/simutrans/obj/pillar.cc000066400000000000000000000076301474050137200207410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "simobj.h" #include "../simmem.h" #include "../display/simimg.h" #include "../builder/brueckenbauer.h" #include "../descriptor/bridge_desc.h" #include "../ground/grund.h" #include "../dataobj/loadsave.h" #include "pillar.h" #include "bruecke.h" #include "../dataobj/environment.h" pillar_t::pillar_t(loadsave_t *file) : obj_t() { desc = NULL; asymmetric = false; rdwr(file); } pillar_t::pillar_t( koord3d pos, player_t *player, const bridge_desc_t *desc, bridge_desc_t::img_t img, int hoehe ) : obj_t( pos ) { this->desc = desc; this->dir = (uint8)img; set_yoff( -hoehe ); set_owner( player ); asymmetric = desc->has_pillar_asymmetric(); calc_image(); } void pillar_t::calc_image() { bool hide = false; int height = get_yoff(); if( grund_t *gr = welt->lookup(get_pos()) ) { slope_t::type slope = gr->get_grund_hang(); if( desc->has_pillar_asymmetric() ) { if( dir == bridge_desc_t::NS_Pillar ) { height += ( (corner_sw(slope) + corner_se(slope) ) * TILE_HEIGHT_STEP )/2; } else { height += ( ( corner_se(slope) + corner_ne(slope) ) * TILE_HEIGHT_STEP ) / 2; } if( height > 0 ) { hide = true; } } else { // on slope use mean height ... height += ( ( corner_se(slope) + corner_ne(slope) + corner_sw(slope) + corner_se(slope) ) * TILE_HEIGHT_STEP ) / 4; } } image = hide ? IMG_EMPTY : desc->get_background( (bridge_desc_t::img_t)dir, get_pos().z-height/TILE_HEIGHT_STEP >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate ); } /** * Einen Beschreibungsstring fuer das Objekt, der z.B. in einem * Beobachtungsfenster angezeigt wird. */ void pillar_t::show_info() { planquadrat_t *plan=welt->access(get_pos().get_2d()); for(unsigned i=0; iget_boden_count(); i++ ) { grund_t *bd=plan->get_boden_bei(i); if(bd->ist_bruecke()) { bruecke_t* br = bd->find(); if(br && br->get_desc()==desc) { br->show_info(); } } } } void pillar_t::rdwr(loadsave_t *file) { xml_tag_t p( file, "pillar_t" ); obj_t::rdwr(file); if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); file->rdwr_byte(dir); } else { char s[256]; file->rdwr_str(s, lengthof(s)); file->rdwr_byte(dir); desc = bridge_builder_t::get_desc(s); if(desc==0) { if(strstr(s,"ail")) { desc = bridge_builder_t::get_desc("ClassicRail"); dbg->warning("pillar_t::rdwr()","Unknown bridge %s replaced by ClassicRail",s); } else if(strstr(s,"oad")) { desc = bridge_builder_t::get_desc("ClassicRoad"); dbg->warning("pillar_t::rdwr()","Unknown bridge %s replaced by ClassicRoad",s); } } asymmetric = desc && desc->has_pillar_asymmetric(); if( file->is_version_less(112, 7) && env_t::pak_height_conversion_factor==2 ) { switch(dir) { case bridge_desc_t::OW_Pillar: dir = bridge_desc_t::OW_Pillar2; break; case bridge_desc_t::NS_Pillar: dir = bridge_desc_t::NS_Pillar2; break; } } } } void pillar_t::rotate90() { // since we may have a "3D" offset from the slope, we must remove it beofer rotation sint8 hoff = get_yoff(); set_yoff(0); obj_t::rotate90(); set_yoff(hoff); // may need to hide/show asymmetric pillars // this is done now in calc_image, which is called after karte_t::rotate anyway // we cannot decide this here, since welt->lookup(get_pos())->get_grund_hang() cannot be called // since we are in the middle of the rotation process // the rotated image parameter is just one in front/back switch(dir) { case bridge_desc_t::NS_Pillar: dir=bridge_desc_t::OW_Pillar ; break; case bridge_desc_t::OW_Pillar: dir=bridge_desc_t::NS_Pillar ; break; case bridge_desc_t::NS_Pillar2: dir=bridge_desc_t::OW_Pillar2 ; break; case bridge_desc_t::OW_Pillar2: dir=bridge_desc_t::NS_Pillar2 ; break; } } simutrans-124.3/src/simutrans/obj/pillar.h000066400000000000000000000024431474050137200206000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_PILLAR_H #define OBJ_PILLAR_H #include "simobj.h" #include "../descriptor/bridge_desc.h" class loadsave_t; class karte_t; /** * Bridge piece (visible) */ class pillar_t : public obj_t { const bridge_desc_t *desc; uint8 dir; bool asymmetric; image_id image; protected: void rdwr(loadsave_t *file) OVERRIDE; public: pillar_t(loadsave_t *file); pillar_t(koord3d pos, player_t *player, const bridge_desc_t *desc, bridge_desc_t::img_t img, int hoehe); const char* get_name() const OVERRIDE { return "Pillar"; } typ get_typ() const OVERRIDE { return obj_t::pillar; } const bridge_desc_t* get_desc() const { return desc; } image_id get_image() const OVERRIDE { return asymmetric ? IMG_EMPTY : image; } // asymmetric pillars are placed at the southern/eastern boundary of the tile // thus the images have to be displayed after vehicles image_id get_front_image() const OVERRIDE { return asymmetric ? image : IMG_EMPTY;} // needs to check for hiding asymmetric pillars void calc_image() OVERRIDE; /** * Einen Beschreibungsstring fuer das Objekt, der z.B. in einem * Beobachtungsfenster angezeigt wird. */ void show_info() OVERRIDE; void rotate90() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/roadsign.cc000066400000000000000000000505371474050137200212700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simunits.h" #include "../simdebug.h" #include "simobj.h" #include "../display/simimg.h" #include "../player/simplay.h" #include "../tool/simtool.h" #include "../world/simworld.h" #include "../descriptor/roadsign_desc.h" #include "../descriptor/skin_desc.h" #include "../ground/grund.h" #include "../obj/way/strasse.h" #include "../dataobj/loadsave.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "../gui/trafficlight_info.h" #include "../gui/privatesign_info.h" #include "../gui/tool_selector.h" #include "../tpl/stringhashtable_tpl.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "roadsign.h" freelist_tpl roadsign_t::rs; const roadsign_desc_t *roadsign_t::default_signal=NULL; stringhashtable_tpl roadsign_t::table; roadsign_t::roadsign_t(loadsave_t *file) : obj_t () { image = foreground_image = IMG_EMPTY; preview = false; rdwr(file); if(desc) { /* if more than one state, we will switch direction and phase for traffic lights * however also gate signs need indications */ automatic = (desc->get_count()>4 && desc->get_wtyp()==road_wt) || (desc->get_count()>2 && desc->is_private_way()); } else { automatic = false; } // some sve had rather strange entries in state if( !automatic || desc==NULL ) { state = 0; } // only traffic light need switches if( automatic ) { welt->sync_roadsigns.add(this); } } roadsign_t::roadsign_t(player_t *player, koord3d pos, ribi_t::ribi dir, const roadsign_desc_t *desc, bool preview) : obj_t(pos) { this->desc = desc; this->dir = dir; this->preview = preview; image = foreground_image = IMG_EMPTY; state = 0; ticks_ns = ticks_ow = 16; ticks_offset = 0; ticks_yellow_ns = ticks_yellow_ow = 2; set_owner( player ); if( desc->is_private_way() ) { // init ownership of private ways ticks_offset = ticks_ow = 0; if( player->get_player_nr() >= 8 ) { ticks_ow = 1 << (player->get_player_nr()-8); } else { ticks_offset = 1 << player->get_player_nr(); } } /* if more than one state, we will switch direction and phase for traffic lights * however also gate signs need indications */ automatic = (desc->get_count()>4 && desc->get_wtyp()==road_wt) || (desc->get_count()>2 && desc->is_private_way()); // only traffic light need switches if( automatic ) { welt->sync_roadsigns.add(this); } } roadsign_t::~roadsign_t() { if( desc ) { const grund_t *gr = welt->lookup(get_pos()); if(gr) { weg_t *weg = gr->get_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt); if(weg) { if (!preview) { if (desc->is_single_way() || desc->is_signal_type()) { // signal removed, remove direction mask weg->set_ribi_maske(ribi_t::none); } weg->clear_sign_flag(); } } else { dbg->error("roadsign_t::~roadsign_t()","roadsign_t %p was deleted but ground has no way of type %d!", this, desc->get_wtyp() ); } } } if(automatic) { welt->sync_roadsigns.remove(this); } } void roadsign_t::set_dir(ribi_t::ribi dir) { ribi_t::ribi olddir = this->dir; this->dir = dir; if (!preview) { weg_t *weg = welt->lookup(get_pos())->get_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt); if( desc->get_wtyp()!=track_wt && desc->get_wtyp()!=monorail_wt && desc->get_wtyp()!=maglev_wt && desc->get_wtyp()!=narrowgauge_wt ) { weg->count_sign(); } if(desc->is_single_way() || desc->is_signal_type()) { // set mask, if it is a single way ... weg->count_sign(); weg->set_ribi_maske(calc_mask()); DBG_MESSAGE("roadsign_t::set_dir()","ribi %i",dir); } } // force redraw mark_image_dirty(get_image(),0); // some more magic to get left side images right ... sint8 old_x = get_xoff(); set_xoff( after_xoffset ); mark_image_dirty(foreground_image,after_yoffset-get_yoff()); set_xoff( old_x ); image = IMG_EMPTY; foreground_image = IMG_EMPTY; calc_image(); if (preview) this->dir = olddir; } void roadsign_t::show_info() { if( desc->is_private_way() ) { create_win(new privatesign_info_t(this), w_info, (ptrdiff_t)this ); } else if( automatic ) { create_win(new trafficlight_info_t(this), w_info, (ptrdiff_t)this ); } else { obj_t::show_info(); } } void roadsign_t::info(cbuffer_t & buf) const { if( !desc->is_private_way() ) { buf.append(translator::translate("Roadsign")); buf.append("\n"); if(desc->is_single_way()) { buf.append(translator::translate("\nsingle way")); } if(desc->get_min_speed()!=0) { buf.printf("%s%d", translator::translate("\nminimum speed:"), speed_to_kmh(desc->get_min_speed())); } buf.printf("%s%u\n", translator::translate("\ndirection:"), dir); if( automatic ) { buf.append(translator::translate("\nSet phases:")); } if (!automatic) { if (char const* const maker = desc->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); } // extra treatment of trafficlights & private signs, author will be shown by those windows themselves } } } // could be still better aligned for drive_left settings ... void roadsign_t::calc_image() { set_flag(obj_t::dirty); // vertical offset of the signal positions const grund_t *gr=welt->lookup(get_pos()); if(gr==NULL) { return; } after_xoffset = 0; after_yoffset = 0; sint8 xoff = 0, yoff = 0; // left offsets defined, and image-on-the-left activated const bool left_offsets = desc->get_offset_left() && ( (desc->get_wtyp()==road_wt && welt->get_settings().is_drive_left() ) || (desc->get_wtyp()!=air_wt && desc->get_wtyp()!=road_wt && welt->get_settings().is_signals_left()) ); const slope_t::type full_hang = gr->get_weg_hang(); const sint8 hang_diff = slope_t::max_diff(full_hang); const ribi_t::ribi hang_dir = ribi_t::backward( ribi_type(full_hang) ); // private way have also closed/open states if( desc->is_private_way() ) { uint8 image = 1-(dir&1); if( (1<get_active_player_nr()) & get_player_mask() ) { // gate open image += 2; } set_image( desc->get_image_id(image) ); set_yoff( 0 ); if( hang_diff ) { set_yoff( -(TILE_HEIGHT_STEP*hang_diff)/2 ); } else { set_yoff( -gr->get_weg_yoff() ); } foreground_image = IMG_EMPTY; return; } if( hang_diff == 0 ) { yoff = -gr->get_weg_yoff(); after_yoffset = yoff; } else { // since the places were switched const ribi_t::ribi test_hang = left_offsets ? ribi_t::backward(hang_dir) : hang_dir; if(test_hang==ribi_t::east || test_hang==ribi_t::north) { yoff = -TILE_HEIGHT_STEP*hang_diff; after_yoffset = 0; } else { yoff = 0; after_yoffset = -TILE_HEIGHT_STEP*hang_diff; } } image_id tmp_image=IMG_EMPTY; if(!automatic) { assert( state==0 ); foreground_image = IMG_EMPTY; ribi_t::ribi temp_dir = dir; if( gr->get_typ()==grund_t::tunnelboden && gr->ist_karten_boden() && (grund_t::underground_mode==grund_t::ugm_none || (grund_t::underground_mode==grund_t::ugm_level && gr->get_hoehe()get_grund_hang()) ); if( tunnel_hang_dir==ribi_t::east || tunnel_hang_dir==ribi_t::north ) { temp_dir &= ~ribi_t::southwest; } else { temp_dir &= ~ribi_t::northeast; } } // signs for left side need other offsets and other front/back order if( left_offsets ) { const sint16 XOFF = 2*desc->get_offset_left(); const sint16 YOFF = desc->get_offset_left(); if(temp_dir&ribi_t::east) { tmp_image = desc->get_image_id(3); xoff += XOFF; yoff += -YOFF; } if(temp_dir&ribi_t::north) { if(tmp_image!=IMG_EMPTY) { foreground_image = desc->get_image_id(0); after_xoffset += -XOFF; after_yoffset += -YOFF; } else { tmp_image = desc->get_image_id(0); xoff += -XOFF; yoff += -YOFF; } } if(temp_dir&ribi_t::west) { foreground_image = desc->get_image_id(2); after_xoffset += -XOFF; after_yoffset += YOFF; } if(temp_dir&ribi_t::south) { if(foreground_image!=IMG_EMPTY) { tmp_image = desc->get_image_id(1); xoff += XOFF; yoff += YOFF; } else { foreground_image = desc->get_image_id(1); after_xoffset += XOFF; after_yoffset += YOFF; } } } else { if(temp_dir&ribi_t::east) { foreground_image = desc->get_image_id(3); } if(temp_dir&ribi_t::north) { if(foreground_image!=IMG_EMPTY) { tmp_image = desc->get_image_id(0); } else { foreground_image = desc->get_image_id(0); } } if(temp_dir&ribi_t::west) { tmp_image = desc->get_image_id(2); } if(temp_dir&ribi_t::south) { if(tmp_image!=IMG_EMPTY) { foreground_image = desc->get_image_id(1); } else { tmp_image = desc->get_image_id(1); } } } // some signs on roads must not have a background (but then they have only two rotations) if( desc->get_flags()&roadsign_desc_t::ONLY_BACKIMAGE ) { if(foreground_image!=IMG_EMPTY) { tmp_image = foreground_image; } foreground_image = IMG_EMPTY; } } else { // traffic light weg_t *str=gr->get_weg(road_wt); if(str) { const uint8 weg_dir = str->get_ribi_unmasked(); const uint8 direction = desc->get_count()>16 ? (state&2) + ((state+1) & 1) : (state+1) & 1; // other front/back images for left side ... if( left_offsets ) { const sint16 XOFF = 2*desc->get_offset_left(); const sint16 YOFF = desc->get_offset_left(); if(weg_dir&ribi_t::north) { if(weg_dir&ribi_t::east) { foreground_image = desc->get_image_id(6+direction*8); after_xoffset += 0; after_yoffset += 0; } else { foreground_image = desc->get_image_id(1+direction*8); after_xoffset += XOFF; after_yoffset += YOFF; } } else if(weg_dir&ribi_t::east) { foreground_image = desc->get_image_id(2+direction*8); after_xoffset += -XOFF; after_yoffset += YOFF; } if(weg_dir&ribi_t::west) { if(weg_dir&ribi_t::south) { tmp_image = desc->get_image_id(7+direction*8); xoff += 0; yoff += 0; } else { tmp_image = desc->get_image_id(3+direction*8); xoff += XOFF; yoff += -YOFF; } } else if(weg_dir&ribi_t::south) { tmp_image = desc->get_image_id(0+direction*8); xoff += -XOFF; yoff += -YOFF; } } else { // drive right ... if(weg_dir&ribi_t::south) { if(weg_dir&ribi_t::east) { foreground_image = desc->get_image_id(4+direction*8); } else { foreground_image = desc->get_image_id(0+direction*8); } } else if(weg_dir&ribi_t::east) { foreground_image = desc->get_image_id(2+direction*8); } if(weg_dir&ribi_t::west) { if(weg_dir&ribi_t::north) { tmp_image = desc->get_image_id(5+direction*8); } else { tmp_image = desc->get_image_id(3+direction*8); } } else if(weg_dir&ribi_t::north) { tmp_image = desc->get_image_id(1+direction*8); } } } } // set image and offsets set_image( tmp_image ); set_xoff( xoff ); set_yoff( yoff ); } // only used for traffic light: change the current state sync_result roadsign_t::sync_step(uint32 /*delta_t*/) { if( desc->is_private_way() ) { uint8 image = 1-(dir&1); if( (1<get_active_player_nr()) & get_player_mask() ) { // gate open image += 2; // force redraw mark_image_dirty(get_image(),0); } set_image( desc->get_image_id(image) ); } else { if (grund_t* gr = welt->lookup(get_pos())) { ribi_t::ribi r = gr->get_weg_ribi_unmasked(road_wt); if ( ribi_t::none==r || ribi_t::is_single(r) || (ribi_t::is_twoway(r) && !ribi_t::is_straight(r)) ) { // not at least a straight road => remove the lights return SYNC_DELETE; } } else { return SYNC_DELETE; } // Must not overflow if ticks_ns+ticks_ow+ticks_yellow_ns+ticks_yellow_ow=256 uint32 ticks = ((welt->get_ticks()>>10)+ticks_offset) % ((uint32)ticks_ns+(uint32)ticks_ow+(uint32)ticks_yellow_ns+(uint32)ticks_yellow_ow); uint8 new_state = 0; //traffic light transition: e-w dir -> yellow e-w -> n-s dir -> yellow n-s -> ... if( ticks < ticks_ow ) { new_state = 0; } else if( ticks < ticks_ow+ticks_yellow_ow ) { new_state = 2; } else if( ticks < (uint32)ticks_ow+ticks_yellow_ow+ticks_ns ) { new_state = 1; } else { new_state = 3; } if(state!=new_state) { state = new_state; switch(new_state) { case 0: dir = ribi_t::northsouth; break; case 1: dir = ribi_t::eastwest; break; default: // yellow state dir = ribi_t::none; break; } calc_image(); } } return SYNC_OK; } void roadsign_t::rotate90() { // only meaningful for traffic lights obj_t::rotate90(); if(automatic && !desc->is_private_way()) { state = (state&2/*whether yellow*/) + ((state+1)&1); if( ticks_offset >= ticks_ns ) { ticks_offset -= ticks_ns; } else { ticks_offset += ticks_ow; } uint8 temp = ticks_ns; ticks_ns = ticks_ow; ticks_ow = temp; temp = ticks_yellow_ns; ticks_yellow_ns = ticks_yellow_ow; ticks_yellow_ow = temp; trafficlight_info_t *const trafficlight_win = dynamic_cast( win_get_magic( (ptrdiff_t)this ) ); if( trafficlight_win ) { trafficlight_win->update_data(); } } dir = ribi_t::rotate90( dir ); } // to correct offset on slopes #ifdef MULTI_THREAD void roadsign_t::display_after(int xpos, int ypos, const sint8 clip_num ) const #else void roadsign_t::display_after(int xpos, int ypos, bool ) const #endif { if( foreground_image != IMG_EMPTY ) { const int raster_width = get_current_tile_raster_width(); xpos += tile_raster_scale_x( after_xoffset, raster_width ); ypos += tile_raster_scale_y( after_yoffset, raster_width ); // draw with owner if( get_owner_nr() != PLAYER_UNOWNED ) { if( obj_t::show_owner ) { display_blend( foreground_image, xpos, ypos, 0, color_idx_to_rgb(get_owner()->get_player_color1()+2) | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, get_flag(obj_t::dirty) CLIP_NUM_PAR); } else { display_color( foreground_image, xpos, ypos, get_owner_nr(), true, get_flag(obj_t::dirty) CLIP_NUM_PAR); } } else { display_normal( foreground_image, xpos, ypos, 0, true, get_flag(obj_t::dirty) CLIP_NUM_PAR); } } } void roadsign_t::rdwr(loadsave_t *file) { xml_tag_t r( file, "roadsign_t" ); obj_t::rdwr(file); uint8 dummy=0; if( file->is_version_less(102, 3) ) { file->rdwr_byte(dummy); if( file->is_loading() ) { ticks_ns = ticks_ow = 16; } } else { file->rdwr_byte(ticks_ns); file->rdwr_byte(ticks_ow); } if( file->is_version_atleast(110, 7) ) { file->rdwr_byte(ticks_offset); } else { if( file->is_loading() ) { ticks_offset = 0; } } if( file->is_version_atleast(122,2) ) { file->rdwr_byte(ticks_yellow_ns); file->rdwr_byte(ticks_yellow_ow); } else if( file->is_loading() ){ ticks_yellow_ns = ticks_yellow_ow = 2; } dummy = state; file->rdwr_byte(dummy); state = dummy; dummy = dir; file->rdwr_byte(dummy); dir = dummy; if(file->is_version_less(89, 0)) { dir = ribi_t::backward(dir); } if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); desc = roadsign_t::table.get(bname); if(desc==NULL) { desc = roadsign_t::table.get(translator::compatibility_name(bname)); if( desc==NULL ) { dbg->warning("roadsign_t::rwdr", "description %s for roadsign/signal at %d,%d not found! (may be ignored)", bname, get_pos().x, get_pos().y); pakset_manager_t::add_missing_paks( bname, MISSING_SIGN ); } else { dbg->warning("roadsign_t::rwdr", "roadsign/signal %s at %d,%d replaced by %s", bname, get_pos().x, get_pos().y, desc->get_name() ); } } // init ownership of private ways signs if( desc && desc->is_private_way() ) { if( file->is_version_less(124, 2) ) { // private sign mask now in ticks_ow and ticks_offset ticks_offset = ticks_ns; ticks_ns = 0xFF; } } } } void roadsign_t::cleanup(player_t *player) { player_t::book_construction_costs(player, -desc->get_price(), get_pos().get_2d(), get_waytype()); } void roadsign_t::finish_rd() { grund_t *gr=welt->lookup(get_pos()); if( gr==NULL || !gr->hat_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt) ) { dbg->error("roadsign_t::finish_rd","roadsing: way/ground missing at %i,%i => ignore", get_pos().x, get_pos().y ); } else { // after loading restore directions set_dir(dir); gr->get_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt)->count_sign(); } } // to sort compare_roadsign_desc for always the same menu order static bool compare_roadsign_desc(const roadsign_desc_t* a, const roadsign_desc_t* b) { int diff = a->get_wtyp() - b->get_wtyp(); if (diff == 0) { if(a->is_choose_sign()) { diff += 120; } if(b->is_choose_sign()) { diff -= 120; } diff += (int)(a->get_flags() & ~roadsign_desc_t::SIGN_SIGNAL) - (int)(b->get_flags() & ~roadsign_desc_t::SIGN_SIGNAL); } if (diff == 0) { /* Some type: sort by name */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } /* static stuff from here on ... */ bool roadsign_t::successfully_loaded() { if(table.empty()) { DBG_MESSAGE("roadsign_t", "No signs found - feature disabled"); } return true; } bool roadsign_t::register_desc(roadsign_desc_t *desc) { // avoid duplicates with same name if(const roadsign_desc_t *old_desc = table.remove(desc->get_name())) { tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); delete old_desc; } if( desc->get_cursor()->get_image_id(1)!=IMG_EMPTY ) { // add the tool tool_build_roadsign_t *tool = new tool_build_roadsign_t(); tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param(desc->get_name()); tool_t::general_tool.append( tool ); desc->set_builder( tool ); } else { desc->set_builder( NULL ); } roadsign_t::table.put(desc->get_name(), desc); if( desc->get_wtyp()==track_wt && desc->get_flags()==roadsign_desc_t::SIGN_SIGNAL ) { default_signal = desc; } return true; } /** * Fill menu with icons of given signals/roadsings from the list */ void roadsign_t::fill_menu(tool_selector_t *tool_selector, waytype_t wtyp, sint16 /*sound_ok*/) { // check if scenario forbids this if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_ROADSIGN | GENERAL_TOOL, wtyp)) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_ROADSIGN | GENERAL_TOOL, wtyp, 0); const uint16 time = welt->get_timeline_year_month(); vector_tplmatching; for(auto const& i : table) { roadsign_desc_t const* const desc = i.value; // only add items with a cursor if( desc->is_available(time) && desc->get_wtyp()==wtyp && desc->get_builder() ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_ROADSIGN | GENERAL_TOOL, wtyp, desc->get_name())) { matching.insert_ordered(desc, compare_roadsign_desc); } } } for(roadsign_desc_t const* const i : matching) { i->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_ROADSIGN | GENERAL_TOOL, wtyp, i->get_name()); tool_selector->add_tool_selector(i->get_builder()); } } /** * Finds a matching roadsign */ const roadsign_desc_t *roadsign_t::roadsign_search(roadsign_desc_t::types const flag, waytype_t const wt, uint16 const time) { for(auto const& i : table) { roadsign_desc_t const* const desc = i.value; if( desc->is_available(time) && desc->get_wtyp()==wt && desc->get_flags()==flag ) { return desc; } } return NULL; } const vector_tpl& roadsign_t::get_available_signs(const waytype_t wt) { static vector_tpl dummy; dummy.clear(); const uint16 time = welt->get_timeline_year_month(); for(auto const& i : table) { roadsign_desc_t const* const desc = i.value; if (desc->is_available(time) && desc->get_wtyp()==wt && desc->get_builder()) { dummy.append(desc); } } return dummy; } simutrans-124.3/src/simutrans/obj/roadsign.h000066400000000000000000000130531474050137200211220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_ROADSIGN_H #define OBJ_ROADSIGN_H #include "simobj.h" #include "../simtypes.h" #include "../descriptor/roadsign_desc.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/freelist_tpl.h" template class vector_tpl; class tool_selector_t; /** * road sign for traffic (one way minimum speed, traffic lights) */ class roadsign_t : public obj_t { protected: image_id image; image_id foreground_image; enum { SHOW_FONT = 1, SHOW_BACK = 2, SWITCH_AUTOMATIC = 16 }; uint8 state:2; // counter for steps ... uint8 dir:4; uint8 automatic:1; uint8 preview:1; uint8 ticks_ns; uint8 ticks_ow; uint8 ticks_yellow_ns, ticks_yellow_ow; uint8 ticks_offset; sint8 after_yoffset, after_xoffset; const roadsign_desc_t *desc; ribi_t::ribi calc_mask() const { return ribi_t::is_single(dir) ? dir : (ribi_t::ribi)ribi_t::none; } static freelist_tplrs; // if not declared static, it would consume 4 bytes due to empty class nonzero rules public: enum signalstate { STATE_RED = 0, STATE_GREEN = 1, STATE_YELLOW = 2 // next state is red }; /** * return direction or the state of the traffic light */ ribi_t::ribi get_dir() const { return dir; } /* * sets ribi mask of the sign * Caution: it will modify way ribis directly unless in preview mode! */ void set_dir(ribi_t::ribi dir); void set_state(signalstate z) {state = z; calc_image();} signalstate get_state() { return (signalstate)state; } typ get_typ() const OVERRIDE { return roadsign; } const char* get_name() const OVERRIDE { return "Roadsign"; } // assuming this is a private way sign uint16 get_player_mask() const { return (ticks_ow<<8)|ticks_offset; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE { return desc ? desc->get_wtyp() : invalid_wt; } roadsign_t(loadsave_t *file); roadsign_t(player_t *player, koord3d pos, ribi_t::ribi dir, const roadsign_desc_t* desc, bool preview = false); const roadsign_desc_t *get_desc() const {return desc;} void* operator new(size_t) { return rs.gimme_node(); } void operator delete(void* p) { return rs.putback_node(p); } /** * signale muessen bei der destruktion von der * Blockstrecke abgemeldet werden */ ~roadsign_t(); // since traffic lights need their own window void show_info() OVERRIDE; /// @copydoc obj_t::info void info(cbuffer_t & buf) const OVERRIDE; /** * Calculate actual image */ void calc_image() OVERRIDE; // true, if a free route choose point (these are always single way the avoid recalculation of long return routes) bool is_free_route(uint8 check_dir) const { return desc->is_choose_sign() && check_dir == dir; } // changes the state of a traffic light sync_result sync_step(uint32); // change the phases of the traffic lights uint8 get_ticks_ns() const { return ticks_ns; } void set_ticks_ns(uint8 ns) { ticks_ns = ns; // To prevent overflow in ticks_offset when rotating if (ticks_ow > 256-ticks_ns - ticks_yellow_ns - ticks_yellow_ow ) { ticks_ow = 256-ticks_ns-ticks_yellow_ns-ticks_yellow_ow; } } uint8 get_ticks_ow() const { return ticks_ow; } void set_ticks_ow(uint8 ow) { ticks_ow = ow; // To prevent overflow in ticks_offset when rotating if (ticks_ns > 256-ticks_ow - ticks_yellow_ns-ticks_yellow_ow ) { ticks_ns = 256-ticks_ow-ticks_yellow_ns-ticks_yellow_ow; } } uint8 get_ticks_yellow_ns() const { return ticks_yellow_ns; } void set_ticks_yellow_ns(uint8 yellow) { ticks_yellow_ns = yellow; // To prevent overflow in ticks_offset when rotating if (ticks_yellow_ns > 256-ticks_ns - ticks_ow - ticks_yellow_ow) { ticks_yellow_ns = 256-ticks_ns-ticks_ow-ticks_yellow_ow; } } uint8 get_ticks_yellow_ow() const { return ticks_yellow_ow; } void set_ticks_yellow_ow(uint8 yellow) { ticks_yellow_ow = yellow; // To prevent overflow in ticks_offset when rotating if (ticks_yellow_ow > 256-ticks_ns - ticks_ow - ticks_yellow_ns) { ticks_yellow_ow = 256-ticks_ns-ticks_ow-ticks_yellow_ns; } } uint8 get_ticks_offset() const { return ticks_offset; } void set_ticks_offset(uint8 offset) { ticks_offset = offset; } inline void set_image( image_id b ) { image = b; } image_id get_image() const OVERRIDE { return image; } /** * For the front image hiding vehicles */ image_id get_front_image() const OVERRIDE { return foreground_image; } /** * draw the part overlapping the vehicles * (needed to get the right offset even on hills) */ #ifdef MULTI_THREAD void display_after(int xpos, int ypos, const sint8 clip_num) const OVERRIDE; #else void display_after(int xpos, int ypos, bool dirty) const OVERRIDE; #endif void rdwr(loadsave_t *file) OVERRIDE; void rotate90() OVERRIDE; // subtracts cost void cleanup(player_t *player) OVERRIDE; void finish_rd() OVERRIDE; // static routines from here private: static stringhashtable_tpl table; protected: static const roadsign_desc_t *default_signal; public: static bool register_desc(roadsign_desc_t *desc); static bool successfully_loaded(); /** * Fill menu with icons of given stops from the list */ static void fill_menu(tool_selector_t *tool_selector, waytype_t wtyp, sint16 sound_ok); static const roadsign_desc_t *roadsign_search(roadsign_desc_t::types flag, const waytype_t wt, const uint16 time); static const roadsign_desc_t *find_desc(const char *name) { return table.get(name); } static const vector_tpl& get_available_signs(const waytype_t wt); }; #endif simutrans-124.3/src/simutrans/obj/signal.cc000066400000000000000000000113711474050137200207300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../simdebug.h" #include "../world/simworld.h" #include "simobj.h" #include "../obj/way/schiene.h" #include "../ground/grund.h" #include "../display/simimg.h" #include "../dataobj/ribi.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../gui/signal_info.h" #include "../gui/simwin.h" #include "../utils/cbuffer.h" #include "signal.h" signal_t::signal_t(loadsave_t *file) : roadsign_t(file) { if(desc==NULL) { desc = roadsign_t::default_signal; } state = STATE_RED; } void signal_t::info(cbuffer_t & buf) const { translator::get_obj_info(buf, desc->get_name()); obj_t::info(buf); buf.printf("%s%u", translator::translate("\ndirection:")+1, get_dir()); // copyright obmitted, signal dialog will show it } void signal_t::calc_image() { foreground_image = IMG_EMPTY; image_id image = IMG_EMPTY; after_xoffset = 0; after_yoffset = 0; sint8 xoff = 0, yoff = 0; const bool left_swap = welt->get_settings().is_signals_left() && desc->get_offset_left(); grund_t *gr = welt->lookup(get_pos()); if(gr) { const slope_t::type full_hang = gr->get_weg_hang(); const sint8 hang_diff = slope_t::max_diff(full_hang); const ribi_t::ribi hang_dir = ribi_t::backward( ribi_type(full_hang) ); set_flag(obj_t::dirty); weg_t *sch = gr->get_weg(desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt); if(sch) { uint16 offset=0; ribi_t::ribi dir = sch->get_ribi_unmasked() & (~calc_mask()); if(sch->is_electrified() && (desc->get_count()/8)>1) { offset = (desc->is_pre_signal() || desc->is_priority_signal()) ? 12 : 8; } // vertical offset of the signal positions if(full_hang==slope_t::flat) { yoff = -gr->get_weg_yoff(); after_yoffset = yoff; } else { const ribi_t::ribi test_hang = left_swap ? ribi_t::backward(hang_dir) : hang_dir; if(test_hang==ribi_t::east || test_hang==ribi_t::north) { yoff = -TILE_HEIGHT_STEP*hang_diff; after_yoffset = 0; } else { yoff = 0; after_yoffset = -TILE_HEIGHT_STEP*hang_diff; } } // and now calculate the images: // we need to hide the "second" image on tunnel entries ribi_t::ribi temp_dir = dir; if( gr->get_typ()==grund_t::tunnelboden && gr->ist_karten_boden() && (grund_t::underground_mode==grund_t::ugm_none || (grund_t::underground_mode==grund_t::ugm_level && gr->get_hoehe()get_grund_hang()) ); if( tunnel_hang_dir==ribi_t::east || tunnel_hang_dir==ribi_t::north ) { temp_dir &= ~ribi_t::southwest; } else { temp_dir &= ~ribi_t::northeast; } } // signs for left side need other offsets and other front/back order if( left_swap ) { const sint16 XOFF = 2*desc->get_offset_left(); const sint16 YOFF = desc->get_offset_left(); if(temp_dir&ribi_t::east) { image = desc->get_image_id(3+state*4+offset); xoff += XOFF; yoff += -YOFF; } if(temp_dir&ribi_t::north) { if(image!=IMG_EMPTY) { foreground_image = desc->get_image_id(0+state*4+offset); after_xoffset += -XOFF; after_yoffset += -YOFF; } else { image = desc->get_image_id(0+state*4+offset); xoff += -XOFF; yoff += -YOFF; } } if(temp_dir&ribi_t::west) { foreground_image = desc->get_image_id(2+state*4+offset); after_xoffset += -XOFF; after_yoffset += YOFF; } if(temp_dir&ribi_t::south) { if(foreground_image!=IMG_EMPTY) { image = desc->get_image_id(1+state*4+offset); xoff += XOFF; yoff += YOFF; } else { foreground_image = desc->get_image_id(1+state*4+offset); after_xoffset += XOFF; after_yoffset += YOFF; } } } else { if(temp_dir&ribi_t::east) { foreground_image = desc->get_image_id(3+state*4+offset); } if(temp_dir&ribi_t::north) { if(foreground_image==IMG_EMPTY) { foreground_image = desc->get_image_id(0+state*4+offset); } else { image = desc->get_image_id(0+state*4+offset); } } if(temp_dir&ribi_t::west) { image = desc->get_image_id(2+state*4+offset); } if(temp_dir&ribi_t::south) { if(image==IMG_EMPTY) { image = desc->get_image_id(1+state*4+offset); } else { foreground_image = desc->get_image_id(1+state*4+offset); } } } } } set_xoff( xoff ); set_yoff( yoff ); set_image(image); } void signal_t::show_info() { create_win( new signal_info_t( this ), w_info, (ptrdiff_t)this ); } simutrans-124.3/src/simutrans/obj/signal.h000066400000000000000000000015051474050137200205700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_SIGNAL_H #define OBJ_SIGNAL_H #include "roadsign.h" #include "simobj.h" /** * Signals for rail tracks. * * @see blockstrecke_t * @see blockmanager */ class signal_t : public roadsign_t { public: signal_t(loadsave_t *file); signal_t(player_t *player, koord3d pos, ribi_t::ribi dir,const roadsign_desc_t *desc, bool preview = false) : roadsign_t(player,pos,dir,desc,preview) { state = STATE_RED;} const roadsign_desc_t* get_desc() const { return desc; } /// @copydoc obj_t::info void info(cbuffer_t & buf) const OVERRIDE; typ get_typ() const OVERRIDE { return obj_t::signal; } const char *get_name() const OVERRIDE {return "Signal";} void show_info() OVERRIDE; void calc_image() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/simobj.cc000066400000000000000000000223141474050137200207350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simobj.h" #include "baum.h" #include "../ground/grund.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../display/simgraph.h" #include "../display/simimg.h" #include "../display/viewport.h" #include "../player/simplay.h" #include "../gui/obj_info.h" #include "../gui/simwin.h" #include "../vehicle/vehicle_base.h" #include "../simcolor.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include #include #include /** * Pointer to the world of this thing. Static to conserve space. * Change to instance variable once more than one world is available. */ karte_ptr_t obj_t::welt; bool obj_t::show_owner = false; void obj_t::init() { pos = koord3d::invalid; xoff = 0; yoff = 0; owner_n = PLAYER_UNOWNED; flags = no_flags; set_flag(dirty); } obj_t::obj_t() { init(); } obj_t::obj_t(koord3d pos) { init(); this->pos = pos; } // removes an object and tries to delete it also from the corresponding objlist obj_t::~obj_t() { destroy_win((ptrdiff_t)this); if(flags¬_on_map || !welt->is_within_limits(pos.get_2d())) { return; } // find object on the map and remove it grund_t *gr = welt->lookup(pos); if(!gr || !gr->obj_remove(this)) { // not found? => try harder at all map locations dbg->warning("obj_t::~obj_t()", "Could not remove %p from (%s)", (void *)this, pos.get_str()); // first: try different height ... gr = welt->access(pos.get_2d())->get_boden_von_obj(this); if(gr && gr->obj_remove(this)) { dbg->warning("obj_t::~obj_t()", "Removed %p from (%hi,%hi,%hhi), but it should have been on (%hi,%hi,%hhi)", (void *)this, gr->get_pos().x, gr->get_pos().y, gr->get_pos().z, pos.x, pos.y, pos.z); return; } // then search entire map koord k; for(k.y=0; k.yget_size().y; k.y++) { for(k.x=0; k.xget_size().x; k.x++) { grund_t *gr = welt->access(k)->get_boden_von_obj(this); if (gr && gr->obj_remove(this)) { dbg->warning("obj_t::~obj_t()", "Removed %p from (%hi,%hi,%hhi), but it should have been on (%hi,%hi,%hhi)", (void *)this, gr->get_pos().x, gr->get_pos().y, gr->get_pos().z, pos.x, pos.y, pos.z); return; } } } } } /** * sets owner of object */ void obj_t::set_owner(player_t *player) { int i = welt->sp2num(player); assert(i>=0); owner_n = (uint8)i; } player_t *obj_t::get_owner() const { return welt->get_player(owner_n); } /* the only general info we can give is the name * we want to format it nicely, * with two linebreaks at the end => thus the little extra effort */ void obj_t::info(cbuffer_t & buf) const { char translation[256]; char const* const owner = owner_n == 1 ? translator::translate("Eigenbesitz\n") : owner_n == PLAYER_UNOWNED ? "" : // was translator::translate("Kein Besitzer\n") : get_owner()->get_name(); tstrncpy(translation, owner, lengthof(translation)); // remove trailing linebreaks etc. rtrim(translation); buf.append( translation ); // only append linebreaks if not empty if(owner[0]>0) { buf.append( "\n\n" ); } } void obj_t::show_info() { create_win( new obj_infowin_t(this), w_info, (ptrdiff_t)this); } bool obj_t::has_managed_lifecycle() const { return false; } // returns NULL, if removal is allowed const char *obj_t::get_removal_error(const player_t *player) { if(owner_n==PLAYER_UNOWNED || welt->get_player(owner_n) == player || welt->get_public_player() == player) { return NULL; } else { return "Der Besitzer erlaubt das Entfernen nicht"; } } void obj_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "obj_t" ); if( file->is_version_less(101, 0) ) { pos.rdwr( file ); } sint8 byte = (sint8)(((sint16)16*(sint16)xoff)/OBJECT_OFFSET_STEPS); file->rdwr_byte(byte); xoff = (sint8)(((sint16)byte*OBJECT_OFFSET_STEPS)/16); byte = (sint8)(((sint16)16*(sint16)yoff)/OBJECT_OFFSET_STEPS); file->rdwr_byte(byte); yoff = (sint8)(((sint16)byte*OBJECT_OFFSET_STEPS)/16); byte = owner_n; file->rdwr_byte(byte); owner_n = byte; } /** * draw the object * the dirty-flag is reset from objlist_t::display_obj_fg, or objlist_t::display_overlay when multithreaded */ void obj_t::display(int xpos, int ypos CLIP_NUM_DEF) const { image_id image = get_image(); image_id const outline_image = get_outline_image(); if( image!=IMG_EMPTY || outline_image!=IMG_EMPTY ) { const int raster_width = get_current_tile_raster_width(); const bool is_dirty = get_flag(obj_t::dirty); if (vehicle_base_t const* const v = obj_cast(this)) { // vehicles need finer steps to appear smoother v->get_screen_offset( xpos, ypos, raster_width ); } xpos += tile_raster_scale_x(get_xoff(), raster_width); ypos += tile_raster_scale_y(get_yoff(), raster_width); const int start_ypos = ypos; for( int j=0; image!=IMG_EMPTY; ) { if( owner_n != PLAYER_UNOWNED ) { if( obj_t::show_owner ) { display_blend( image, xpos, ypos, owner_n, color_idx_to_rgb(welt->get_player(owner_n)->get_player_color1()+2) | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } else { display_color( image, xpos, ypos, owner_n, true, is_dirty CLIP_NUM_PAR); } } else { display_normal( image, xpos, ypos, 0, true, is_dirty CLIP_NUM_PAR); } // this obj has another image on top (e.g. skyscraper) ypos -= raster_width; image = get_image(++j); } if( outline_image != IMG_EMPTY ) { // transparency? const FLAGGED_PIXVAL transparent = get_outline_colour(); if( TRANSPARENT_FLAGS&transparent ) { // only transparent outline display_blend( get_outline_image(), xpos, start_ypos, owner_n, transparent, 0, is_dirty CLIP_NUM_PAR); } else if( obj_t::get_flag( highlight ) ) { // highlight this tile display_blend( get_image(), xpos, start_ypos, owner_n, SYSCOL_OBJECT_HIGHLIGHT | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } } else if( obj_t::get_flag( highlight ) ) { // highlight this tile display_blend( get_image(), xpos, start_ypos, owner_n, SYSCOL_OBJECT_HIGHLIGHT | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } } } // called during map rotation void obj_t::rotate90() { // most basic: rotate coordinate pos.rotate90( welt->get_size().y-1 ); sint8 new_dx = -2*yoff; yoff = xoff/2; xoff = new_dx; } #ifdef MULTI_THREAD void obj_t::display_after(int xpos, int ypos, const sint8 clip_num) const #else void obj_t::display_after(int xpos, int ypos, bool) const #endif { image_id image = get_front_image(); if( image != IMG_EMPTY ) { const int raster_width = get_current_tile_raster_width(); const bool is_dirty = get_flag( obj_t::dirty ); xpos += tile_raster_scale_x( get_xoff(), raster_width ); ypos += tile_raster_scale_y( get_yoff(), raster_width ); if( owner_n != PLAYER_UNOWNED ) { if( obj_t::show_owner ) { display_blend( image, xpos, ypos, owner_n, color_idx_to_rgb(welt->get_player(owner_n)->get_player_color1()+2) | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } else if( obj_t::get_flag( highlight ) ) { // highlight this tile display_blend( image, xpos, ypos, owner_n, SYSCOL_OBJECT_HIGHLIGHT | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } else { display_color( image, xpos, ypos, owner_n, true, is_dirty CLIP_NUM_PAR); } } else if( obj_t::get_flag( highlight ) ) { // highlight this tile display_blend( image, xpos, ypos, owner_n, SYSCOL_OBJECT_HIGHLIGHT | OUTLINE_FLAG | TRANSPARENT75_FLAG, 0, is_dirty CLIP_NUM_PAR); } else { display_normal( image, xpos, ypos, 0, true, is_dirty CLIP_NUM_PAR); } } } /* * when a vehicle moves or a cloud moves, it needs to mark the old spot as dirty (to copy to screen) * sometimes they have an extra offset, this is the yoff parameter */ void obj_t::mark_image_dirty(image_id image, sint16 yoff) const { if( image != IMG_EMPTY ) { const sint16 rasterweite = get_tile_raster_width(); int xpos=0, ypos=0; if( is_moving() ) { vehicle_base_t const* const v = obj_cast(this); // vehicles need finer steps to appear smoother v->get_screen_offset( xpos, ypos, get_tile_raster_width() ); } viewport_t *vp = welt->get_viewport(); scr_coord scr_pos = vp->get_screen_coord(get_pos(), koord(get_xoff(), get_yoff())); // xpos, ypos, yoff are already in pixel units, no scaling needed // mark the region after the image as dirty display_mark_img_dirty( image, scr_pos.x + xpos, scr_pos.y + ypos + yoff); // too close to border => set dirty to be sure (smoke, skyscrapers, birds, or the like) scr_coord_val xbild = 0, ybild = 0, wbild = 0, hbild = 0; display_get_image_offset( image, &xbild, &ybild, &wbild, &hbild ); const sint16 distance_to_border = 3 - (yoff+get_yoff()+ybild)/(rasterweite/4); if( pos.x <= distance_to_border || pos.y <= distance_to_border ) { // but only if the image is actually visible ... if( scr_pos.x+xbild+wbild >= 0 && xpos <= display_get_width() && scr_pos.y+ybild+hbild >= 0 && ypos+ybild < display_get_height() ) { welt->set_background_dirty(); } } } } simutrans-124.3/src/simutrans/obj/simobj.h000066400000000000000000000206041474050137200205770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_SIMOBJ_H #define OBJ_SIMOBJ_H #include "../simtypes.h" #include "../display/clip_num.h" #include "../display/simimg.h" #include "../simcolor.h" #include "../dataobj/koord3d.h" class cbuffer_t; class karte_ptr_t; class player_t; /** * Base class of all objects on the map, obj == thing * Since everything is a 'obj' on the map, we need to make this as compact and fast as possible. */ class obj_t { public: // flags enum flag_values { no_flags = 0, /// no special properties dirty = 1 << 0, /// mark image dirty when drawing not_on_map = 1 << 1, /// this object is not placed on any tile (e.g. vehicles in a depot) is_vehicle = 1 << 2, /// this object is a vehicle obviously highlight = 1 << 3 /// for drawing some highlighted outline }; // display only outline with player color on owner stuff static bool show_owner; private: obj_t(obj_t const&); obj_t& operator=(obj_t const&); /** * Coordinate of position */ koord3d pos; /** * x-offset of the object on the tile * used for drawing object image * if xoff and yoff are between 0 and OBJECT_OFFSET_STEPS-1 then * the top-left corner of the image is within tile boundaries */ sint8 xoff; /** * y-offset of the object on the tile */ sint8 yoff; /** * Owner of the object (1 - public player, 15 - unowned) */ uint8 owner_n:4; /** * @see flag_values */ uint8 flags:4; private: /** * Used by all constructors to initialize all vars with safe values * -> single source principle */ void init(); protected: obj_t(); // since we often need access during loading void set_owner_nr(uint8 value) { owner_n = value; } /** * Pointer to the world of this thing. Static to conserve space. * Change to instance variable once more than one world is available. */ static karte_ptr_t welt; public: // needed for drawing images sint8 get_owner_nr() const { return owner_n; } /** * sets owner of object */ void set_owner(player_t *player); /** * returns owner of object */ player_t *get_owner() const; /** * routines to set, clear, get bit flags */ inline void set_flag(flag_values flag) {flags |= flag;} inline void clear_flag(flag_values flag) {flags &= ~flag;} inline bool get_flag(flag_values flag) const {return ((flags & flag) != 0);} /// all the different types of objects enum typ { undefined=-1, obj=0, baum=1, zeiger=2, cloud=4, gebaeude=7, // animated buildings (6 not used any more) signal=8, bruecke=9, tunnel=10, bahndepot=12, strassendepot=13, schiffdepot = 14, leitung = 16, pumpe = 17, senke = 18, roadsign = 19, pillar = 20, airdepot = 21, monoraildepot=22, tramdepot=23, maglevdepot=24, wayobj = 25, way = 26, // since 99.04 ways are normal things and stored in the objliste_t! label = 27, // indicates ownership field = 28, crossing = 29, groundobj = 30, // lakes, stones narrowgaugedepot=31, // after this only moving stuff // reserved values for vehicles: 64 to 95 pedestrian=64, road_user=65, road_vehicle=66, rail_vehicle=67, monorail_vehicle=68, maglev_vehicle=69, narrowgauge_vehicle=70, water_vehicle=80, air_vehicle=81, movingobj=82, // other new objs (obsolete, only used during loading old games // lagerhaus = 24, (never really used) // gebaeude_alt=6, (very, very old? old_wolke=3, old_async_wolke=5, old_gebaeudefundament=11, // wall below buildings, not used any more old_raucher=15, // obsolete old_automobil=32, old_waggon=33, old_schiff=34, old_aircraft=35, old_monorailwaggon=36, old_verkehr=41, old_fussgaenger=42, old_choosesignal = 95, old_presignal = 96, old_roadsign = 97, old_pillar = 98, old_airdepot = 99, old_monoraildepot=100, old_tramdepot=101 }; inline sint8 get_xoff() const {return xoff;} inline sint8 get_yoff() const {return yoff;} // true for all moving objects inline bool is_moving() const { return flags&is_vehicle; } // while in principle, this should trigger the dirty, it takes just too much time to do it // TAKE CARE OF SET IT DIRTY YOURSELF!!! inline void set_xoff(sint8 xoff) {this->xoff = xoff; } inline void set_yoff(sint8 yoff) {this->yoff = yoff; } /** * Constructor to set position of object * This does *not* add the object to the tile */ obj_t(koord3d pos); /** * Destructor: removes object from tile, should close any inspection windows */ virtual ~obj_t(); /** * Routine for cleanup if object is removed (ie book maintenance, cost for removal) */ virtual void cleanup(player_t *) {} /** * @returns untranslated name of object */ virtual const char *get_name() const {return "Ding";} /** * @return object type * @see typ */ virtual typ get_typ() const = 0; /** * waytype associated with this object */ virtual waytype_t get_waytype() const { return invalid_wt; } /** * called whenever the snowline height changes * return false and the obj_t will be deleted */ virtual bool check_season(const bool) { return true; } /** * called during map rotation */ virtual void rotate90(); /** * Every object needs an image. * @return number of current image for that object */ virtual image_id get_image() const = 0; /** * give image for height > 0 (max. height currently 3) * IMG_EMPTY is no images */ virtual image_id get_image(int /*height*/) const {return IMG_EMPTY;} /** * this image is drawn after all get_image() on this tile * Currently only single height is supported for this feature */ virtual image_id get_front_image() const {return IMG_EMPTY;} /** * if a function returns a value here with TRANSPARENT_FLAGS set * then a transparent outline with the color from the lower 8 bit is drawn */ virtual FLAGGED_PIXVAL get_outline_colour() const {return 0;} /** * The image, that will be outlined */ virtual image_id get_outline_image() const { return IMG_EMPTY; } /** * Save and Load of object data in one routine */ virtual void rdwr(loadsave_t *file); /** * Called after the world is completely loaded from savegame */ virtual void finish_rd() {} /** * @return position */ inline koord3d get_pos() const {return pos;} /** * set position - you would not have guessed it :) */ inline void set_pos(koord3d k) { if(k!=pos) { set_flag(dirty); pos = k;} } /** * put description of object into the buffer * (used for certain windows) * @see simwin */ virtual void info(cbuffer_t & buf) const; /** * Opens a new info window for the object */ virtual void show_info(); /** * @return True if the object lifecycle is managed by another system so cannot be destroyed. * False if the object can be destroyed at any time. */ virtual bool has_managed_lifecycle() const; /// @return NULL if this obj can be removed by @p player, otherwise an error message virtual const char *get_removal_error(const player_t *player); /** * Draw background image of object * (everything that could be potentially behind vehicles) */ void display(int xpos, int ypos CLIP_NUM_DEF) const; /** * Draw foreground image * (everything that is in front of vehicles) */ #ifdef MULTI_THREAD virtual void display_after(int xpos, int ypos, const sint8 clip_num) const; #else virtual void display_after(int xpos, int ypos, bool is_global) const; #endif #ifdef MULTI_THREAD /** * Draw overlays * (convoi tooltips) */ virtual void display_overlay(int /*xpos*/, int /*ypos*/) const { return; } #endif /** * When a vehicle moves or a cloud moves, it needs to mark the old spot as dirty (to copy to screen). * This routine already takes position, and offsets (x_off, y_off) into account. * * @param image * @param yoff extra y-offset, in most cases 0, in pixels. */ void mark_image_dirty(image_id image, sint16 yoff) const; /** * Function for recalculating the image. */ virtual void calc_image() {} }; /** * Template to do casting of pointers based on obj_t::typ * as a replacement of the slower dynamic_cast<> */ template static T* obj_cast(obj_t*); template static inline T const* obj_cast(obj_t const* const d) { return obj_cast(const_cast(d)); } /** * Game objects that do not have description windows (for instance zeiger_t, wolke_t) */ class obj_no_info_t : public obj_t { public: obj_no_info_t(koord3d pos) : obj_t(pos) {} void show_info() OVERRIDE {} protected: obj_no_info_t() : obj_t() {} }; #endif simutrans-124.3/src/simutrans/obj/tunnel.cc000066400000000000000000000144001474050137200207540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../world/simworld.h" #include "simobj.h" #include "../player/simplay.h" #include "../ground/grund.h" #include "../display/simimg.h" #include "../builder/tunnelbauer.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/pakset_manager.h" #include "../descriptor/tunnel_desc.h" #include "leitung2.h" #include "../builder/wegbauer.h" #include "tunnel.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t tunnel_calc_image_mutex; static recursive_mutex_maker_t tunnel_cim_maker(tunnel_calc_image_mutex); #endif tunnel_t::tunnel_t(loadsave_t* const file) : obj_no_info_t() { desc = 0; rdwr(file); image = foreground_image = IMG_EMPTY; broad_type = 0; } tunnel_t::tunnel_t(koord3d pos, player_t *player, const tunnel_desc_t *desc) : obj_no_info_t(pos) { assert(desc); this->desc = desc; set_owner( player ); image = foreground_image = IMG_EMPTY; broad_type = 0; } waytype_t tunnel_t::get_waytype() const { return desc ? desc->get_waytype() : invalid_wt; } void tunnel_t::calc_image() { #ifdef MULTI_THREAD pthread_mutex_lock( &tunnel_calc_image_mutex ); #endif const grund_t *gr = welt->lookup(get_pos()); if( gr->ist_karten_boden() && desc ) { slope_t::type hang = gr->get_grund_hang(); broad_type = 0; if( desc->has_broad_portals() ) { ribi_t::ribi dir = ribi_t::rotate90( ribi_type( hang ) ); if( dir==0 ) { dbg->error( "tunnel_t::calc_image()", "pos=%s, dir=%i, hang=%i", get_pos().get_str(), dir, hang ); } else { const grund_t *gr_l = welt->lookup(get_pos() + dir); tunnel_t* tunnel_l = gr_l ? gr_l->find() : NULL; if( tunnel_l && tunnel_l->get_desc() == desc && gr_l->get_grund_hang() == hang ) { broad_type += 1; if( !(tunnel_l->get_broad_type() & 2) ) { tunnel_l->calc_image(); } } const grund_t *gr_r = welt->lookup(get_pos() - dir); tunnel_t* tunnel_r = gr_r ? gr_r->find() : NULL; if( tunnel_r && tunnel_r->get_desc() == desc && gr_r->get_grund_hang() == hang ) { broad_type += 2; if( !(tunnel_r->get_broad_type() & 1) ) { tunnel_r->calc_image(); } } } } if (weg_t* w = gr->get_weg_nr(0)) { w->set_image(desc->get_background_id(hang, get_pos().z >= welt->get_snowline() || welt->get_climate(get_pos().get_2d()) == arctic_climate, broad_type)); w->set_foreground_image(desc->get_foreground_id(hang, get_pos().z >= welt->get_snowline() || welt->get_climate(get_pos().get_2d()) == arctic_climate, broad_type)); if (weg_t* w = gr->get_weg_nr(1)) { if (corner_se(hang) > 0) { w->set_image(IMG_EMPTY); w->set_foreground_image(IMG_EMPTY); } else { w->set_images(weg_t::image_flat, w->get_ribi_unmasked(), false); } } set_image(IMG_EMPTY); set_foreground_image(IMG_EMPTY); } else { set_image(desc->get_background_id(hang, get_pos().z >= welt->get_snowline() || welt->get_climate(get_pos().get_2d()) == arctic_climate, broad_type)); set_foreground_image(desc->get_foreground_id(hang, get_pos().z >= welt->get_snowline() || welt->get_climate(get_pos().get_2d()) == arctic_climate, broad_type)); } } else { set_image( IMG_EMPTY ); set_foreground_image( IMG_EMPTY ); } #ifdef MULTI_THREAD pthread_mutex_unlock( &tunnel_calc_image_mutex ); #endif } void tunnel_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "tunnel_t" ); obj_t::rdwr(file); if( file->is_version_atleast(99, 1) ) { char buf[256]; if( file->is_loading() ) { file->rdwr_str(buf, lengthof(buf)); desc = tunnel_builder_t::get_desc(buf); if( desc==NULL ) { desc = tunnel_builder_t::get_desc(translator::compatibility_name(buf)); } if( desc==NULL ) { pakset_manager_t::add_missing_paks( buf, MISSING_WAY ); } } else { strcpy( buf, desc->get_name() ); file->rdwr_str(buf,0); } } } void tunnel_t::finish_rd() { const grund_t *gr = welt->lookup(get_pos()); player_t *player=get_owner(); if(desc==NULL) { // find a matching desc if (gr->get_weg_nr(0)==NULL) { // no way? underground powerline if (gr->get_leitung()) { desc = tunnel_builder_t::get_tunnel_desc(powerline_wt, 1, 0); } // no tunnel -> use dummy road tunnel if (desc==NULL) { desc = tunnel_builder_t::get_tunnel_desc(road_wt, 1, 0); } } else { desc = tunnel_builder_t::get_tunnel_desc(gr->get_weg_nr(0)->get_desc()->get_wtyp(), 450, 0); if( desc == NULL ) { dbg->error( "tunnel_t::finish_rd()", "Completely unknown tunnel for this waytype: Lets use a rail tunnel!" ); desc = tunnel_builder_t::get_tunnel_desc(track_wt, 1, 0); } } } if(player) { // change maintenance weg_t *weg = gr->get_weg(desc->get_waytype()); if(weg) { weg->set_max_speed(desc->get_topspeed()); player_t::add_maintenance( player, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); } player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype() ); } } // correct speed and maintenance void tunnel_t::cleanup( player_t *player2 ) { player_t *player = get_owner(); if(player) { // inside tunnel => do nothing but change maintenance const grund_t *gr = welt->lookup(get_pos()); if(gr) { weg_t *weg = gr->get_weg( desc->get_waytype() ); if(weg) { weg->set_max_speed( weg->get_desc()->get_topspeed() ); player_t::add_maintenance( player, weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype()); } player_t::add_maintenance( player, -desc->get_maintenance(), desc->get_finance_waytype() ); } } player_t::book_construction_costs(player2, -desc->get_price(), get_pos().get_2d(), desc->get_finance_waytype() ); } void tunnel_t::set_image( image_id b ) { mark_image_dirty( image, 0 ); mark_image_dirty( b, 0 ); image = b; } void tunnel_t::set_foreground_image( image_id b ) { mark_image_dirty( foreground_image, 0 ); mark_image_dirty( b, 0 ); foreground_image = b; } // returns NULL, if removal is allowed // players can remove public owned ways const char *tunnel_t::get_removal_error(const player_t *player) { if (get_owner_nr()==PLAYER_PUBLIC_NR) { return NULL; } else { return obj_t::get_removal_error(player); } } simutrans-124.3/src/simutrans/obj/tunnel.h000066400000000000000000000031541474050137200206220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_TUNNEL_H #define OBJ_TUNNEL_H #include "simobj.h" #include "../display/simimg.h" class tunnel_desc_t; class tunnel_t : public obj_no_info_t { private: const tunnel_desc_t *desc; image_id image; image_id foreground_image; uint8 broad_type; // Is this a broad tunnel mouth? public: tunnel_t(loadsave_t *file); tunnel_t(koord3d pos, player_t *player, const tunnel_desc_t *desc); const char *get_name() const OVERRIDE {return "Tunnelmuendung";} typ get_typ() const OVERRIDE { return tunnel; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE; void calc_image() OVERRIDE; /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool calc_only_season_change) OVERRIDE { if( !calc_only_season_change ) { calc_image(); } return true; } // depends on snowline only void set_image( image_id b ); void set_foreground_image( image_id b ); image_id get_image() const OVERRIDE {return image;} image_id get_front_image() const OVERRIDE { return foreground_image; } const tunnel_desc_t *get_desc() const { return desc; } void set_desc( const tunnel_desc_t *_desc ) { desc = _desc; } void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; void cleanup(player_t *player) OVERRIDE; uint8 get_broad_type() const { return broad_type; } /** * @return NULL when OK, otherwise an error message */ const char *get_removal_error(const player_t *player) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/000077500000000000000000000000001474050137200177415ustar00rootroot00000000000000simutrans-124.3/src/simutrans/obj/way/kanal.cc000066400000000000000000000027741474050137200213500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../world/simworld.h" #include "../../display/simimg.h" #include "../../descriptor/ground_desc.h" #include "../../descriptor/way_desc.h" #include "../../builder/wegbauer.h" #include "../../dataobj/translator.h" #include "../../dataobj/pakset_manager.h" #include "kanal.h" const way_desc_t *kanal_t::default_kanal=NULL; kanal_t::kanal_t(loadsave_t *file) : weg_t() { rdwr(file); } kanal_t::kanal_t() : weg_t() { set_desc(default_kanal); } void kanal_t::rdwr(loadsave_t *file) { weg_t::rdwr(file); if(file->is_version_less(87, 1)) { set_desc(default_kanal); return; } if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); const way_desc_t *desc = way_builder_t::get_desc(bname); int old_max_speed = get_max_speed(); if(desc==NULL) { desc = way_builder_t::get_desc(translator::compatibility_name(bname)); if(desc==NULL) { desc = default_kanal; if (desc == NULL) { dbg->fatal("kanal_t::rdwr", "Trying to load canal but pakset has no water ways!"); } pakset_manager_t::add_missing_paks( bname, MISSING_WAY ); } dbg->warning("kanal_t::rdwr()", "Unknown canal '%s' replaced by '%s' (old_max_speed %i)", bname, desc->get_name(), old_max_speed ); } set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } } } simutrans-124.3/src/simutrans/obj/way/kanal.h000066400000000000000000000010001474050137200211670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_KANAL_H #define OBJ_WAY_KANAL_H #include "weg.h" #include "../../dataobj/loadsave.h" #include "../../utils/cbuffer.h" /** * Ships can be created on docks */ class kanal_t : public weg_t { public: static const way_desc_t *default_kanal; kanal_t(loadsave_t *file); kanal_t(); waytype_t get_waytype() const OVERRIDE {return water_wt;} void rdwr(loadsave_t *file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/maglev.cc000066400000000000000000000017621474050137200215310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simtypes.h" #include "../../builder/wegbauer.h" #include "../../descriptor/way_desc.h" #include "maglev.h" const way_desc_t *maglev_t::default_maglev=NULL; /** * File loading constructor. */ maglev_t::maglev_t(loadsave_t *file) : schiene_t() { rdwr(file); } void maglev_t::rdwr(loadsave_t *file) { schiene_t::rdwr(file); if(get_desc()->get_wtyp()!=maglev_wt) { int old_max_speed = get_max_speed(); const way_desc_t *desc = way_builder_t::weg_search( maglev_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (systemtype_t)((get_desc()->get_styp()==type_elevated)*type_elevated) ); if (desc==NULL) { dbg->fatal("maglev_t::rwdr()", "No maglev way available"); } dbg->warning("maglev_t::rwdr()", "Unknown way replaced by maglev %s (old_max_speed %i)", desc->get_name(), old_max_speed ); set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } } } simutrans-124.3/src/simutrans/obj/way/maglev.h000066400000000000000000000010741474050137200213670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_MAGLEV_H #define OBJ_WAY_MAGLEV_H #include "schiene.h" /** * derived from schiene, because signals will behave similar */ class maglev_t : public schiene_t { public: static const way_desc_t *default_maglev; maglev_t() : schiene_t() { set_desc(default_maglev); } /** * File loading constructor. */ maglev_t(loadsave_t *file); waytype_t get_waytype() const OVERRIDE {return maglev_wt;} void rdwr(loadsave_t *file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/monorail.cc000066400000000000000000000017461474050137200221000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../simtypes.h" #include "../../builder/wegbauer.h" #include "../../descriptor/way_desc.h" #include "monorail.h" const way_desc_t *monorail_t::default_monorail=NULL; monorail_t::monorail_t(loadsave_t *file) : schiene_t() { rdwr(file); } void monorail_t::rdwr(loadsave_t *file) { schiene_t::rdwr(file); if(get_desc()->get_wtyp()!=monorail_wt) { int old_max_speed = get_max_speed(); const way_desc_t *desc = way_builder_t::weg_search( monorail_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (systemtype_t)((get_desc()->get_styp()==type_elevated)*type_elevated) ); if (desc==NULL) { dbg->fatal("monorail_t::rwdr()", "No monorail way available"); } dbg->warning("monorail_t::rwdr()", "Unknown way replaced by monorail %s (old_max_speed %i)", desc->get_name(), old_max_speed ); set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } } } simutrans-124.3/src/simutrans/obj/way/monorail.h000066400000000000000000000012311474050137200217270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_MONORAIL_H #define OBJ_WAY_MONORAIL_H #include "schiene.h" /** * Class for monorail tracks, derived from schiene. * Monorail trains can drive on this tracks. * Each track belongs to a section block */ class monorail_t : public schiene_t { public: static const way_desc_t *default_monorail; monorail_t() : schiene_t() { set_desc(default_monorail); } /** * File loading constructor. */ monorail_t(loadsave_t *file); waytype_t get_waytype() const OVERRIDE {return monorail_wt;} void rdwr(loadsave_t *file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/narrowgauge.cc000066400000000000000000000017561474050137200226020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../builder/wegbauer.h" #include "../../descriptor/way_desc.h" #include "narrowgauge.h" const way_desc_t *narrowgauge_t::default_narrowgauge=NULL; narrowgauge_t::narrowgauge_t(loadsave_t *file) : schiene_t() { rdwr(file); } void narrowgauge_t::rdwr(loadsave_t *file) { schiene_t::rdwr(file); if(get_desc()->get_wtyp()!=narrowgauge_wt) { int old_max_speed = get_max_speed(); const way_desc_t *desc = way_builder_t::weg_search( narrowgauge_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (systemtype_t)((get_desc()->get_styp()==type_elevated)*type_elevated) ); if (desc==NULL) { dbg->fatal("narrowgauge_t::rwdr()", "No narrowgauge way available"); } dbg->warning("narrowgauge_t::rwdr()", "Unknown way replaced by narrow gauge %s (old_max_speed %i)", desc->get_name(), old_max_speed ); set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } } } simutrans-124.3/src/simutrans/obj/way/narrowgauge.h000066400000000000000000000011441474050137200224330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_NARROWGAUGE_H #define OBJ_WAY_NARROWGAUGE_H #include "schiene.h" /** * derived from schiene, because signals will behave similar */ class narrowgauge_t : public schiene_t { public: static const way_desc_t *default_narrowgauge; narrowgauge_t() : schiene_t() { set_desc(default_narrowgauge); } /** * File loading constructor. */ narrowgauge_t(loadsave_t *file); waytype_t get_waytype() const OVERRIDE {return narrowgauge_wt;} void rdwr(loadsave_t *file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/runway.cc000066400000000000000000000031771474050137200216050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../../world/simworld.h" #include "../../builder/wegbauer.h" #include "../../descriptor/way_desc.h" #include "../../dataobj/loadsave.h" #include "../../dataobj/translator.h" #include "../../dataobj/pakset_manager.h" #include "../../utils/cbuffer.h" #include "runway.h" const way_desc_t *runway_t::default_runway=NULL; runway_t::runway_t() : schiene_t() { set_desc(default_runway); } runway_t::runway_t(loadsave_t *file) : schiene_t() { rdwr(file); } void runway_t::info(cbuffer_t & buf) const { schiene_t::info(buf); cbuffer_t reserved; if( get_desc()->get_styp()==type_runway ) { reserved.printf( "%s %i\n", translator::translate("waiting"), reservations.get_count() ); buf.append( reserved ); } } void runway_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "runway_t" ); weg_t::rdwr(file); if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); const way_desc_t *desc = way_builder_t::get_desc(bname); int old_max_speed=get_max_speed(); if(desc==NULL) { desc = way_builder_t::weg_search(air_wt,old_max_speed>0 ? old_max_speed : 20, 0, (systemtype_t)(old_max_speed>250) ); if(desc==NULL) { desc = default_runway; pakset_manager_t::add_missing_paks( bname, MISSING_WAY ); } dbg->warning("runway_t::rdwr()", "Unknown runway %s replaced by %s (old_max_speed %i)", bname, desc->get_name(), old_max_speed ); } if(old_max_speed>0) { set_max_speed(old_max_speed); } set_desc(desc); } } simutrans-124.3/src/simutrans/obj/way/runway.h000066400000000000000000000023541474050137200214430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_RUNWAY_H #define OBJ_WAY_RUNWAY_H #include "../../tpl/vector_tpl.h" #include "../../convoihandle.h" #include "schiene.h" /** * Class for aiport runaway in Simutrans. * system type==1 are for takeoff */ class runway_t : public schiene_t { private: vector_tpl reservations; public: static const way_desc_t *default_runway; runway_t(loadsave_t *file); runway_t(); inline waytype_t get_waytype() const OVERRIDE {return air_wt;} /** * @param[out] buf additional info is reservation! */ void info(cbuffer_t & buf) const OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; // the code below is only used for runways // the more reservations, the higher the cost for landing there. // Should quickly lead to equal usage of runways uint32 get_reservation_count() const { return reservations.get_count(); } void add_convoi_reservation( convoihandle_t cnv ) { reservations.append_unique(cnv); } void remove_convoi_reservation( convoihandle_t cnv ) { reservations.remove(cnv); } bool unreserve( convoihandle_t cnv ) OVERRIDE { reservations.remove(cnv); schiene_t::unreserve(cnv); return true; } }; #endif simutrans-124.3/src/simutrans/obj/way/schiene.cc000066400000000000000000000077311474050137200216760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../../simconvoi.h" #include "../../world/simworld.h" #include "../../vehicle/vehicle.h" #include "../../dataobj/loadsave.h" #include "../../dataobj/translator.h" #include "../../dataobj/pakset_manager.h" #include "../../utils/cbuffer.h" #include "../../descriptor/way_desc.h" #include "../../builder/wegbauer.h" #include "schiene.h" const way_desc_t *schiene_t::default_schiene=NULL; bool schiene_t::show_reservations = false; schiene_t::schiene_t() : weg_t() { reserved = convoihandle_t(); if (schiene_t::default_schiene) { set_desc(schiene_t::default_schiene); } else { dbg->fatal("schiene_t::schiene_t()", "No rail way available!"); } } schiene_t::schiene_t(loadsave_t *file) : weg_t() { reserved = convoihandle_t(); rdwr(file); } void schiene_t::cleanup(player_t *) { // removes reservation if(reserved.is_bound()) { set_ribi(ribi_t::none); reserved->suche_neue_route(); } } void schiene_t::info(cbuffer_t & buf) const { weg_t::info(buf); if(reserved.is_bound()) { const char* reserve_text = translator::translate("\nis reserved by:"); // ignore linebreak if (reserve_text[0] == '\n') { reserve_text++; } buf.append(reserve_text); buf.append(reserved->get_name()); buf.append("\n"); #ifdef DEBUG_PBS reserved->open_info_window(); #endif } } /** * true, if this rail can be reserved */ bool schiene_t::reserve(convoihandle_t c, ribi_t::ribi dir ) { if(can_reserve(c)) { reserved = c; /* for threeway and fourway switches we may need to alter graphic, if * direction is a diagonal (i.e. on the switching part) * and there are switching graphics */ if( ribi_t::is_threeway(get_ribi_unmasked()) && ribi_t::is_bend(dir) && get_desc()->has_switch_image() ) { mark_image_dirty( get_image(), 0 ); mark_image_dirty( get_front_image(), 0 ); set_switched(dir == ribi_t::northeast || dir == ribi_t::southwest); set_images(image_switch, get_ribi_unmasked(), is_snow(), has_switched() ); set_flag( obj_t::dirty ); } if(schiene_t::show_reservations) { set_flag( obj_t::dirty ); } return true; } // reserve anyway ... return false; } /** * releases previous reservation * only true, if there was something to release */ bool schiene_t::unreserve(convoihandle_t c) { // is this tile reserved by us? if(reserved.is_bound() && reserved==c) { reserved = convoihandle_t(); if(schiene_t::show_reservations) { set_flag( obj_t::dirty ); } return true; } return false; } void schiene_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "schiene_t" ); weg_t::rdwr(file); if(file->is_version_less(99, 8)) { sint32 blocknr=-1; file->rdwr_long(blocknr); } if(file->is_version_less(89, 0)) { uint8 dummy; file->rdwr_byte(dummy); set_electrify(dummy); } if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); int old_max_speed = get_max_speed(); const way_desc_t *desc = way_builder_t::get_desc(bname); if(desc==NULL) { int old_max_speed=get_max_speed(); desc = way_builder_t::get_desc(translator::compatibility_name(bname)); if(desc==NULL) { desc = default_schiene; if (!desc) { dbg->fatal("schiene_t::rdwr", "Trying to load train tracks but pakset has none!"); } pakset_manager_t::add_missing_paks( bname, MISSING_WAY ); } dbg->warning("schiene_t::rdwr()", "Unknown rail '%s' replaced by '%s' (old_max_speed %i)", bname, desc->get_name(), old_max_speed ); } set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } // DBG_MESSAGE("schiene_t::rdwr","track %s at (%s) max_speed %i", bname, get_pos().get_str(), old_max_speed); } } FLAGGED_PIXVAL schiene_t::get_outline_colour() const { if (!show_reservations || !reserved.is_bound()) { return 0; } return TRANSPARENT75_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_RED); } simutrans-124.3/src/simutrans/obj/way/schiene.h000066400000000000000000000040031474050137200215250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_SCHIENE_H #define OBJ_WAY_SCHIENE_H #include "weg.h" #include "../../convoihandle.h" class vehicle_t; /** * Class for Rails in Simutrans. * Trains can run over rails. * Every rail belongs to a section block */ class schiene_t : public weg_t { protected: /** * Bound when this block was successfully reserved by the convoi */ convoihandle_t reserved; public: static const way_desc_t *default_schiene; static bool show_reservations; /** * File loading constructor. */ schiene_t(loadsave_t *file); schiene_t(); waytype_t get_waytype() const OVERRIDE {return track_wt;} /** * @param[out] buf additional info is reservation! */ void info(cbuffer_t & buf) const OVERRIDE; /** * true, if this rail can be reserved */ bool can_reserve(convoihandle_t c) const { return !reserved.is_bound() || c==reserved; } /** * true, if this rail can be reserved */ bool is_reserved() const { return reserved.is_bound(); } /** * true, then this rail was reserved */ bool reserve(convoihandle_t c, ribi_t::ribi dir); /** * releases previous reservation */ virtual bool unreserve( convoihandle_t c); /** * releases previous reservation */ bool unreserve( vehicle_t *) { return unreserve(reserved); } /* called before deletion; * last chance to unreserve tiles ... */ void cleanup(player_t *player) OVERRIDE; /** * gets the related convoi */ convoihandle_t get_reserved_convoi() const {return reserved;} void rdwr(loadsave_t *file) OVERRIDE; /** * if a function return here a value with TRANSPARENT_FLAGS set * then a transparent outline with the color form the lower 8 Bit is drawn */ FLAGGED_PIXVAL get_outline_colour() const OVERRIDE; /* * to show reservations if needed */ image_id get_outline_image() const OVERRIDE { return weg_t::get_image(); } }; template<> inline schiene_t* obj_cast(obj_t* const d) { return dynamic_cast(d); } #endif simutrans-124.3/src/simutrans/obj/way/strasse.cc000066400000000000000000000030451474050137200217360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "strasse.h" #include "../../world/simworld.h" #include "../../dataobj/loadsave.h" #include "../../descriptor/way_desc.h" #include "../../builder/wegbauer.h" #include "../../dataobj/translator.h" #include "../../dataobj/pakset_manager.h" const way_desc_t *strasse_t::default_strasse=NULL; strasse_t::strasse_t(loadsave_t *file) : weg_t() { rdwr(file); } strasse_t::strasse_t() : weg_t() { set_gehweg(false); set_desc(default_strasse); } void strasse_t::rdwr(loadsave_t *file) { xml_tag_t s( file, "strasse_t" ); weg_t::rdwr(file); if(file->is_version_less(89, 0)) { bool gehweg; file->rdwr_bool(gehweg); set_gehweg(gehweg); } if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); const way_desc_t *desc = way_builder_t::get_desc(bname); int old_max_speed = get_max_speed(); if(desc==NULL) { desc = way_builder_t::get_desc(translator::compatibility_name(bname)); if(desc==NULL) { desc = default_strasse; pakset_manager_t::add_missing_paks( bname, MISSING_WAY ); } dbg->warning("strasse_t::rdwr()", "Unknown street %s replaced by %s (old_max_speed %i)", bname, desc->get_name(), old_max_speed ); } set_desc(desc); if(old_max_speed>0) { set_max_speed(old_max_speed); } if(hat_gehweg()) { set_max_speed(max(desc->get_topspeed(),weg_t::get_cityroad_speedlimit())); } } } simutrans-124.3/src/simutrans/obj/way/strasse.h000066400000000000000000000007631474050137200216040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_STRASSE_H #define OBJ_WAY_STRASSE_H #include "weg.h" /** * Cars are able to drive on roads. */ class strasse_t : public weg_t { public: static const way_desc_t *default_strasse; strasse_t(loadsave_t *file); strasse_t(); inline waytype_t get_waytype() const OVERRIDE {return road_wt;} //void set_gehweg(bool janein); void rdwr(loadsave_t *file) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/obj/way/weg.cc000066400000000000000000000374411474050137200210430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "weg.h" #include "schiene.h" #include "strasse.h" #include "monorail.h" #include "maglev.h" #include "narrowgauge.h" #include "kanal.h" #include "runway.h" #include "../gebaeude.h" #include "../../ground/grund.h" #include "../../world/simworld.h" #include "../../display/simimg.h" #include "../../simhalt.h" #include "../../obj/simobj.h" #include "../../player/simplay.h" #include "../../obj/roadsign.h" #include "../../obj/signal.h" #include "../../obj/crossing.h" #include "../../utils/cbuffer.h" #include "../../dataobj/environment.h" // TILE_HEIGHT_STEP #include "../../dataobj/translator.h" #include "../../dataobj/loadsave.h" #include "../../descriptor/way_desc.h" #include "../../descriptor/roadsign_desc.h" #include "../../tpl/slist_tpl.h" #ifdef MULTI_THREAD #include "../../utils/simthread.h" static pthread_mutex_t weg_calc_image_mutex; static recursive_mutex_maker_t weg_cim_maker(weg_calc_image_mutex); #endif /** * Alle instantiierten Wege */ slist_tpl alle_wege; uint16 weg_t::cityroad_speed = 50; /** * Get list of all ways */ const slist_tpl &weg_t::get_alle_wege() { return alle_wege; } void weg_t::set_cityroad_speedlimit(uint16 new_limit) { if (cityroad_speed != new_limit) { cityroad_speed = new_limit; for(weg_t *w : alle_wege) { if( w->hat_gehweg() && w->get_waytype() == road_wt ) { if (const way_desc_t* desc = w->get_desc()) { w->set_max_speed(max(desc->get_topspeed(), cityroad_speed)); } else { w->set_max_speed(cityroad_speed); } } } } } // returns a way with matching waytype weg_t* weg_t::alloc(waytype_t wt) { weg_t *weg = NULL; switch(wt) { case tram_wt: case track_wt: weg = new schiene_t(); break; case monorail_wt: weg = new monorail_t(); break; case maglev_wt: weg = new maglev_t(); break; case narrowgauge_wt: weg = new narrowgauge_t(); break; case road_wt: weg = new strasse_t(); break; case water_wt: weg = new kanal_t(); break; case air_wt: weg = new runway_t(); break; default: // keep compiler happy; should never reach here anyway assert(0); break; } return weg; } // returns a string with the "official name of the waytype" const char *weg_t::waytype_to_string(waytype_t wt) { switch(wt) { case tram_wt: return "tram_track"; case track_wt: return "track"; case monorail_wt: return "monorail_track"; case maglev_wt: return "maglev_track"; case narrowgauge_wt: return "narrowgauge_track"; case road_wt: return "road"; case water_wt: return "water"; case air_wt: return "air"; default: // keep compiler happy; should never reach here anyway break; } return "invalid waytype"; } void weg_t::set_desc(const way_desc_t *b) { desc = b; if( hat_gehweg() && desc->get_wtyp() == road_wt && desc->get_topspeed() > cityroad_speed ) { max_speed = cityroad_speed; } else { max_speed = desc->get_topspeed(); } } /** * initializes statistic array */ void weg_t::init_statistics() { for( int type=0; typeget_maintenance(), desc->get_finance_waytype() ); } } void weg_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "weg_t" ); // save owner if( file->is_version_atleast(99, 6) ) { sint8 spnum=get_owner_nr(); file->rdwr_byte(spnum); set_owner_nr(spnum); } // all connected directions uint8 dummy8 = ribi; file->rdwr_byte(dummy8); if( file->is_loading() ) { ribi = dummy8 & 15; // before: high bits was maske ribi_maske = 0; // maske will be restored by signal/roadsing } uint16 dummy16=max_speed; file->rdwr_short(dummy16); max_speed=dummy16; if( file->is_version_atleast(89, 0) ) { dummy8 = flags; file->rdwr_byte(dummy8); if( file->is_loading() ) { // all other flags are restored afterwards flags = dummy8 & HAS_SIDEWALK; } } for( int type=0; typerdwr_long(w); statistics[month][type] = (sint16)w; // DBG_DEBUG("weg_t::rdwr()", "statistics[%d][%d]=%d", month, type, statistics[month][type]); } } } void weg_t::info(cbuffer_t & buf) const { obj_t::info(buf); buf.printf("%s %u%s", translator::translate("Max. speed:"), max_speed, translator::translate("km/h\n")); buf.printf("%s%u", translator::translate("\nRibi (unmasked)"), get_ribi_unmasked()); buf.printf("%s%u\n", translator::translate("\nRibi (masked)"), get_ribi()); if(has_sign()) { buf.append(translator::translate("\nwith sign/signal\n")); } if(is_electrified()) { buf.append(translator::translate("\nelektrified")); } else { buf.append(translator::translate("\nnot elektrified")); } #if 1 buf.printf(translator::translate("convoi passed last\nmonth %i\n"), statistics[1][1]); #else // Debug - output stats buf.append("\n"); for (int type=0; typeget_copyright()) { buf.printf(translator::translate("Constructed by %s"), maker); buf.append("\n"); } } /** * called during map rotation */ void weg_t::rotate90() { obj_t::rotate90(); ribi = ribi_t::rotate90( ribi ); ribi_maske = ribi_t::rotate90( ribi_maske ); } /** * counts signals on this tile; * It would be enough for the signals to register and unregister themselves, but this is more secure ... */ void weg_t::count_sign() { // Either only sign or signal please ... flags &= ~(HAS_SIGN|HAS_SIGNAL|HAS_CROSSING); const grund_t *gr=welt->lookup(get_pos()); if(gr) { uint8 i = 1; // if there is a crossing, the start index is at least three ... if( gr->ist_uebergang() ) { max_speed = desc->get_topspeed(); // reset max_speed flags |= HAS_CROSSING; i = 3; const crossing_t* cr = gr->find(); const sint32 top_speed = cr->get_desc()->get_maxspeed( cr->get_desc()->get_waytype(0)==get_waytype() ? 0 : 1); max_speed = min(max_speed, top_speed); } // since way 0 is at least present here ... for( ; iobj_count(); i++ ) { obj_t *obj=gr->obj_bei(i); // sign for us? if( roadsign_t const* const sign = obj_cast(obj) ) { if( sign->get_desc()->get_wtyp() == get_desc()->get_wtyp() ) { // here is a sign ... flags |= HAS_SIGN; return; } } if( signal_t const* const signal = obj_cast(obj) ) { if( signal->get_desc()->get_wtyp() == get_desc()->get_wtyp() ) { // here is a signal ... flags |= HAS_SIGNAL; return; } } } } } void weg_t::set_images(image_type typ, uint8 ribi, bool snow, bool switch_nw) { switch(typ) { case image_flat: default: set_image( desc->get_image_id( ribi, snow ) ); set_foreground_image( desc->get_image_id( ribi, snow, true ) ); break; case image_slope: set_image( desc->get_slope_image_id( (slope_t::type)ribi, snow ) ); set_foreground_image( desc->get_slope_image_id( (slope_t::type)ribi, snow, true ) ); break; case image_switch: set_image( desc->get_switch_image_id(ribi, snow, switch_nw) ); set_foreground_image( desc->get_switch_image_id(ribi, snow, switch_nw, true) ); break; case image_diagonal: set_image( desc->get_diagonal_image_id(ribi, snow) ); set_foreground_image( desc->get_diagonal_image_id(ribi, snow, true) ); break; } } // much faster recalculation of season image bool weg_t::check_season(const bool calc_only_season_change) { if( calc_only_season_change ) { // nothing depends on season, only snowline return true; } // no way to calculate this or no image set (not visible, in tunnel mouth, etc) if( desc == NULL || image == IMG_EMPTY ) { return true; } grund_t *gr = welt->lookup( get_pos() ); if( gr->ist_bruecke() && gr->obj_bei(0) == this ) { // first way on a bridge (bruecke_t will set the image) return true; } // use snow image if above snowline and above ground bool snow = (gr->ist_karten_boden() || !gr->ist_tunnel()) && (get_pos().z + gr->get_weg_yoff()/TILE_HEIGHT_STEP >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate); bool old_snow = (flags&IS_SNOW) != 0; if( !(snow ^ old_snow) ) { // season is not changing ... return true; } // set snow flake flags &= ~IS_SNOW; if( snow ) { flags |= IS_SNOW; } slope_t::type hang = gr->get_weg_hang(); if( hang != slope_t::flat ) { set_images( image_slope, hang, snow ); return true; } if( is_diagonal() ) { set_images( image_diagonal, ribi, snow ); } else if( ribi_t::is_threeway( ribi ) && desc->get_waytype()!=road_wt ) { set_images(image_switch, ribi, snow, has_switched()); } else { // level track set_images( image_flat, ribi, snow ); if(foreground_image != IMG_EMPTY && ribi_t::is_straight(ribi)) { // on straight level tracks may be stations or depots => no foreground then if (gr->is_halt()) { // no foreground in stations set_foreground_image(IMG_EMPTY); } else { // check for any building on this tile for ( uint8 i = 1; i < gr->obj_count(); i++ ) { if (dynamic_cast(gr->obj_bei(i))) { // no foreground in depots set_foreground_image(IMG_EMPTY); break; } } } } } return true; } #ifdef MULTI_THREAD void weg_t::lock_mutex() { pthread_mutex_lock( &weg_calc_image_mutex ); } void weg_t::unlock_mutex() { pthread_mutex_unlock( &weg_calc_image_mutex ); } #endif void weg_t::calc_image() { #ifdef MULTI_THREAD pthread_mutex_lock( &weg_calc_image_mutex ); #endif grund_t *from = welt->lookup(get_pos()); grund_t *to; image_id old_image = image; if( from==NULL || desc==NULL ) { // no ground, in tunnel set_image(IMG_EMPTY); set_foreground_image(IMG_EMPTY); if( from==NULL ) { dbg->error( "weg_t::calc_image()", "Own way at %s not found!", get_pos().get_str() ); } #ifdef MULTI_THREAD pthread_mutex_unlock( &weg_calc_image_mutex ); #endif return; // otherwise crashing during enlargement } else if( from->ist_tunnel() && from->ist_karten_boden() && (grund_t::underground_mode==grund_t::ugm_none || (grund_t::underground_mode==grund_t::ugm_level && from->get_hoehe()ist_bruecke() && from->obj_bei(0)==this ) { // first way on a bridge (bruecke_t will set the image) #ifdef MULTI_THREAD pthread_mutex_unlock( &weg_calc_image_mutex ); #endif return; } else { // use snow image if above snowline and above ground bool snow = (from->ist_karten_boden() || !from->ist_tunnel()) && (get_pos().z + from->get_weg_yoff()/TILE_HEIGHT_STEP >= welt->get_snowline() || welt->get_climate( get_pos().get_2d() ) == arctic_climate ); flags &= ~IS_SNOW; if( snow ) { flags |= IS_SNOW; } slope_t::type hang = from->get_weg_hang(); if(hang != slope_t::flat) { // on slope set_images(image_slope, hang, snow); } else if (ribi_t::is_threeway(ribi)) { set_images(image_switch, ribi, snow, has_switched()); } else if (!ribi_t::is_twoway(ribi)) { set_images(image_flat, ribi, snow); // nide foreground in stations and depots if (foreground_image != IMG_EMPTY) { if (from->is_halt()) { // no foreground in stations set_foreground_image(IMG_EMPTY); } else if (ribi_t::is_single(ribi) && from->obj_count() > 1) { // check for any building on this tile for (uint8 i = 1; i < from->obj_count(); i++) { if (dynamic_cast(from->obj_bei(i))) { // no foreground in depots set_foreground_image(IMG_EMPTY); break; } } } } } // recursion to find out of diagonal else { static int recursion = 0; /* Communicate among different instances of this method */ // flat way set_images(image_flat, ribi, snow); // recalc image of neighbors also when this changed to non-diagonal if(recursion == 0) { recursion++; for(int r = 0; r < 4; r++) { if( from->get_neighbour(to, get_waytype(), ribi_t::nesw[r]) ) { // can fail on water tiles if( weg_t *w=to->get_weg(get_waytype()) ) { // and will only change the outcome, if it has a diagonal image ... if( w->get_desc()->has_diagonal_image() ) { w->calc_image(); } } } } recursion--; } // try diagonal image if( desc->has_diagonal_image() ) { check_diagonal(); // now apply diagonal image if(is_diagonal()) { if( desc->get_diagonal_image_id(ribi, snow) != IMG_EMPTY || desc->get_diagonal_image_id(ribi, snow, true) != IMG_EMPTY) { set_images(image_diagonal, ribi, snow); } } } // level track if (foreground_image != IMG_EMPTY) { if (from->is_halt()) { // no foreground in stations set_foreground_image(IMG_EMPTY); } else if (ribi_t::is_straight(ribi) && from->obj_count() > 1) { // check for any building on this tile for (uint8 i = 1; i < from->obj_count(); i++) { if (dynamic_cast(from->obj_bei(i))) { // no foreground in depots set_foreground_image(IMG_EMPTY); break; } } } } } } if( image!=old_image ) { mark_image_dirty(old_image, from->get_weg_yoff()); mark_image_dirty(image, from->get_weg_yoff()); } #ifdef MULTI_THREAD pthread_mutex_unlock( &weg_calc_image_mutex ); #endif } // checks, if this way qualifies as diagonal void weg_t::check_diagonal() { bool diagonal = false; flags &= ~IS_DIAGONAL; const ribi_t::ribi ribi = get_ribi_unmasked(); if( !ribi_t::is_bend(ribi) ) { // This is not a curve, it can't be a diagonal return; } grund_t *from = welt->lookup(get_pos()); grund_t *to; ribi_t::ribi r1 = ribi_t::none; ribi_t::ribi r2 = ribi_t::none; // get the ribis of the ways that connect to us // r1 will be 45 degree clockwise ribi (eg northeast->east), r2 will be anticlockwise ribi (eg northeast->north) if( from->get_neighbour(to, get_waytype(), ribi_t::rotate45(ribi)) ) { r1 = to->get_weg_ribi_unmasked(get_waytype()); } if( from->get_neighbour(to, get_waytype(), ribi_t::rotate45l(ribi)) ) { r2 = to->get_weg_ribi_unmasked(get_waytype()); } // diagonal if r1 or r2 are our reverse and neither one is 90 degree rotation of us diagonal = (r1 == ribi_t::backward(ribi) || r2 == ribi_t::backward(ribi)) && r1 != ribi_t::rotate90l(ribi) && r2 != ribi_t::rotate90(ribi); if( diagonal ) { flags |= IS_DIAGONAL; } } /** * new month */ void weg_t::new_month() { for (int type=0; type0; month--) { statistics[month][type] = statistics[month-1][type]; } statistics[0][type] = 0; } } // correct speed and maintenance void weg_t::finish_rd() { player_t *player = get_owner(); if( player && desc ) { player_t::add_maintenance( player, desc->get_maintenance(), desc->get_finance_waytype() ); } } // returns NULL, if removal is allowed // players can remove public owned ways const char *weg_t::get_removal_error(const player_t *player) { if( get_owner_nr()==PLAYER_PUBLIC_NR ) { return NULL; } return obj_t::get_removal_error(player); } simutrans-124.3/src/simutrans/obj/way/weg.h000066400000000000000000000174011474050137200206770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAY_WEG_H #define OBJ_WAY_WEG_H #include "../../display/simimg.h" #include "../../simtypes.h" #include "../../obj/simobj.h" #include "../../descriptor/way_desc.h" #include "../../dataobj/koord3d.h" class karte_t; class way_desc_t; class cbuffer_t; template class slist_tpl; // maximum number of months to store information #define MAX_WAY_STAT_MONTHS 2 // number of different statistics collected #define MAX_WAY_STATISTICS 2 enum way_statistics { WAY_STAT_GOODS = 0, ///< number of goods transported over this way WAY_STAT_CONVOIS = 1, ///< number of convois that passed this way WAY_STAT_MAX }; /** * Ways is the base class for all traffic routes. (roads, track, runway etc.) * Ways always "belong" to a ground. They have direction bits (ribis) as well as * a mask for ribis. * * A way always is of a single type (waytype_t). * Crossings are supported by the fact that a ground can have more than one way. */ class weg_t : public obj_no_info_t { public: /** * Get list of all ways */ static const slist_tpl & get_alle_wege(); enum { HAS_SIDEWALK = 1 << 0, // only roads HAS_SWITCHED = 1 << 0, // only rails IS_ELECTRIFIED = 1 << 1, HAS_SIGN = 1 << 2, HAS_SIGNAL = 1 << 3, HAS_WAYOBJ = 1 << 4, HAS_CROSSING = 1 << 5, IS_DIAGONAL = 1 << 6, // marker for diagonal image IS_SNOW = 1 << 7 // marker, if above snowline currently }; private: /** * array for statistical values * MAX_WAY_STAT_MONTHS: [0] = actual value; [1] = last month value * MAX_WAY_STATISTICS: see #define at top of file */ sint16 statistics[MAX_WAY_STAT_MONTHS][MAX_WAY_STATISTICS]; static uint16 cityroad_speed; /** * Way type description */ const way_desc_t * desc; /** * Direction bits (ribis) for the way. North is in the upper right corner of the monitor. * 1=North, 2=East, 4=South, 8=West */ uint8 ribi:4; /** * Mask for ribi (Richtungsbits => Direction Bits) */ uint8 ribi_maske:4; /** * flags like walkway, electrification, road sings */ uint8 flags; /** * max speed; could not be taken for desc, since other object may modify the speed */ uint16 max_speed; image_id image; image_id foreground_image; /** * Initializes all member variables */ void init(); /** * initializes statistic array */ void init_statistics(); protected: public: weg_t(loadsave_t*) : obj_no_info_t() { init(); } weg_t() : obj_no_info_t() { init(); } virtual ~weg_t(); #ifdef MULTI_THREAD void lock_mutex(); void unlock_mutex(); #endif /** * Actual image recalculation */ void calc_image() OVERRIDE; enum image_type { image_flat, image_slope, image_diagonal, image_switch }; /** * initializes both front and back images * switch images are set in schiene_t::reserve * needed by tunnel mouths */ void set_images(image_type typ, uint8 ribi, bool snow, bool switch_nw = false); /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool calc_only_season_change) OVERRIDE; void set_max_speed(sint32 s) { max_speed = s; } sint32 get_max_speed() const { return max_speed; } static void set_cityroad_speedlimit(uint16 new_limit); static uint16 get_cityroad_speedlimit() { return cityroad_speed; } /// @note Replaces max speed of the way by the max speed property of the descriptor. void set_desc(const way_desc_t *b); const way_desc_t *get_desc() const { return desc; } // returns a way with the matching type static weg_t *alloc(waytype_t wt); // returns a string with the "official name of the waytype" static const char *waytype_to_string(waytype_t wt); void rdwr(loadsave_t *file) OVERRIDE; /** * Info-text for this way */ void info(cbuffer_t & buf) const OVERRIDE; /** * @return NULL if OK, otherwise an error message */ const char *get_removal_error(const player_t *player) OVERRIDE; waytype_t get_waytype() const OVERRIDE = 0; /// @copydoc obj_t::get_typ typ get_typ() const OVERRIDE { return obj_t::way; } /** * Die Bezeichnung des Wegs */ const char *get_name() const OVERRIDE { return desc->get_name(); } /** * Add direction bits (ribi) for a way. * * @note After changing of ribi the image of the way is wrong. To correct this, * grund_t::calc_image needs to be called. This is not done here (Too expensive). */ void ribi_add(ribi_t::ribi ribi) { this->ribi |= (uint8)ribi;} /** * Remove direction bits (ribi) for a way. * * @note After changing of ribi the image of the way is wrong. To correct this, * grund_t::calc_image needs to be called. This is not done here (Too expensive). */ void ribi_rem(ribi_t::ribi ribi) { this->ribi &= (uint8)~ribi;} /** * Set direction bits (ribi) for the way. * * @note After changing of ribi the image of the way is wrong. To correct this, * grund_t::calc_image needs to be called. This is not done here (Too expensive). */ void set_ribi(ribi_t::ribi ribi) { this->ribi = (uint8)ribi;} /** * Get the unmasked direction bits (ribi) for the way (without signals or other ribi changer). */ ribi_t::ribi get_ribi_unmasked() const { return (ribi_t::ribi)ribi; } /** * Get the masked direction bits (ribi) for the way (with signals or other ribi changer). */ ribi_t::ribi get_ribi() const { return (ribi_t::ribi)(ribi & ~ribi_maske); } /** * For signals it is necessary to mask out certain ribi to prevent vehicles * from driving the wrong way (e.g. oneway roads) */ void set_ribi_maske(ribi_t::ribi ribi) { ribi_maske = (uint8)ribi; } ribi_t::ribi get_ribi_maske() const { return (ribi_t::ribi)ribi_maske; } /** * called during map rotation */ void rotate90() OVERRIDE; /** * book statistics - is called very often and therefore inline */ void book(int amount, way_statistics type) { statistics[0][type] += amount; } /** * return statistics value * always returns last month's value */ int get_statistics(int type) const { return statistics[1][type]; } sint64 get_stat(int month, int stat_type) const { assert(stat_type #include "../ground/grund.h" #include "../world/simworld.h" #include "../display/simimg.h" #include "simobj.h" #include "../player/simplay.h" #include "../tool/simtool.h" #include "../dataobj/loadsave.h" #include "../dataobj/ribi.h" #include "../dataobj/scenario.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "../descriptor/bridge_desc.h" #include "../descriptor/tunnel_desc.h" #include "../descriptor/way_obj_desc.h" #include "../gui/tool_selector.h" #include "../ground/grund.h" #include "../obj/way/weg.h" #include "../obj/way/strasse.h" #include "../tpl/stringhashtable_tpl.h" #include "../utils/simstring.h" #include "bruecke.h" #include "tunnel.h" #include "wayobj.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t wayobj_calc_image_mutex; static recursive_mutex_maker_t wayobj_cim_maker(wayobj_calc_image_mutex); #endif // the descriptions ... const way_obj_desc_t *wayobj_t::default_oberleitung=NULL; stringhashtable_tpl wayobj_t::table; wayobj_t::wayobj_t(loadsave_t* const file) : obj_no_info_t(), desc(NULL), diagonal(false), hang(slope_t::flat), nw(false), dir(dir_unknown) { rdwr(file); } wayobj_t::wayobj_t(koord3d const pos, player_t* const owner, ribi_t::ribi const d, way_obj_desc_t const* const b) : obj_no_info_t(pos), desc(b), diagonal(false), hang(slope_t::flat), nw(false), dir(d) { set_owner(owner); } wayobj_t::~wayobj_t() { if(!desc) { return; } if(get_owner()) { player_t::add_maintenance(get_owner(), -desc->get_maintenance(), get_waytype()); } if(desc->is_overhead_line()) { grund_t *gr=welt->lookup(get_pos()); weg_t *weg=NULL; if(gr) { const waytype_t wt = (desc->get_wtyp()==tram_wt) ? track_wt : desc->get_wtyp(); weg = gr->get_weg(wt); if(weg) { // Weg wieder freigeben, wenn das Signal nicht mehr da ist. weg->set_electrify(false); // restore old speed limit sint32 max_speed = weg->get_desc()->get_topspeed(); if (wt==road_wt && weg->hat_gehweg()) { max_speed = weg_t::get_cityroad_speedlimit(); } if(gr->get_typ()==grund_t::tunnelboden) { tunnel_t *t = gr->find(1); if(t) { max_speed = t->get_desc()->get_topspeed(); } } if(gr->get_typ()==grund_t::brueckenboden) { bruecke_t *b = gr->find(1); if(b) { max_speed = b->get_desc()->get_topspeed(); } } weg->set_max_speed(max_speed); } else { dbg->warning("wayobj_t::~wayobj_t()","ground was not a way!"); } } } mark_image_dirty( get_front_image(), 0 ); mark_image_dirty( get_image(), 0 ); grund_t *gr = welt->lookup( get_pos() ); if( gr ) { for( uint8 i = 0; i < 4; i++ ) { // Remove ribis from adjacent wayobj. if( ribi_t::nesw[i] & get_dir() ) { grund_t *next_gr; if( gr->get_neighbour( next_gr, desc->get_wtyp(), ribi_t::nesw[i] ) ) { wayobj_t *wo2 = next_gr->get_wayobj( desc->get_wtyp() ); if( wo2 ) { wo2->mark_image_dirty( wo2->get_front_image(), 0 ); wo2->mark_image_dirty( wo2->get_image(), 0 ); wo2->set_dir( wo2->get_dir() & ~ribi_t::backward(ribi_t::nesw[i]) ); wo2->mark_image_dirty( wo2->get_front_image(), 0 ); wo2->mark_image_dirty( wo2->get_image(), 0 ); wo2->set_flag(obj_t::dirty); } } } } } } void wayobj_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "wayobj_t" ); obj_t::rdwr(file); if(file->is_version_atleast(89, 0)) { uint8 ddir = dir; file->rdwr_byte(ddir); dir = ddir; if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); desc = wayobj_t::table.get(bname); if(desc==NULL) { desc = wayobj_t::table.get(translator::compatibility_name(bname)); if(desc==NULL) { if(strstr(bname,"atenary") || strstr(bname,"electri") || strstr(bname,"power") ) { desc = default_oberleitung; } } if(desc==NULL) { dbg->warning("wayobj_t::rwdr", "description %s for wayobj_t at %d,%d not found, will be removed!", bname, get_pos().x, get_pos().y ); pakset_manager_t::add_missing_paks( bname, MISSING_WAYOBJ ); } else { dbg->warning("wayobj_t::rwdr", "wayobj %s at %d,%d replaced by %s", bname, get_pos().x, get_pos().y, desc->get_name() ); } } } } else { desc = default_oberleitung; dir = dir_unknown; } } void wayobj_t::cleanup(player_t *player) { if(desc) { player_t::book_construction_costs(player, -desc->get_price(), get_pos().get_2d(), desc->get_wtyp()); } } // returns NULL, if removal is allowed // players can remove public owned wayobjs const char *wayobj_t::get_removal_error(const player_t *player) { if( get_owner_nr()==PLAYER_PUBLIC_NR ) { return NULL; } return obj_t::get_removal_error(player); } void wayobj_t::finish_rd() { // (re)set dir if(dir==dir_unknown) { const waytype_t wt = (desc->get_wtyp()==tram_wt) ? track_wt : desc->get_wtyp(); weg_t *w=welt->lookup(get_pos())->get_weg(wt); if(w) { dir = w->get_ribi_unmasked(); } else { dir = ribi_t::all; } } // electrify a way if we are a catenary if(desc->is_overhead_line()) { const waytype_t wt = (desc->get_wtyp()==tram_wt) ? track_wt : desc->get_wtyp(); weg_t *weg = welt->lookup(get_pos())->get_weg(wt); if (wt == decoration_wt) { weg_t *weg2 = welt->lookup(get_pos())->get_weg_nr(1); if (weg2) { weg2->set_electrify(true); if(weg2->get_max_speed()>desc->get_topspeed()) { weg2->set_max_speed(desc->get_topspeed()); } } } if(weg) { // Weg wieder freigeben, wenn das Signal nicht mehr da ist. weg->set_electrify(true); if(weg->get_max_speed()>desc->get_topspeed()) { weg->set_max_speed(desc->get_topspeed()); } } else { dbg->warning("wayobj_t::finish_rd()","ground was not a way!"); } } if(get_owner()) { player_t::add_maintenance(get_owner(), desc->get_maintenance(), desc->get_wtyp()); } } void wayobj_t::rotate90() { obj_t::rotate90(); dir = ribi_t::rotate90( dir); hang = slope_t::rotate90( hang ); } // helper function: gets the ribi on next tile ribi_t::ribi wayobj_t::find_next_ribi(const grund_t *start, ribi_t::ribi const dir, const waytype_t wt) const { grund_t *to; ribi_t::ribi r1 = ribi_t::none; if(start->get_neighbour(to,wt,dir)) { const wayobj_t* wo = to->get_wayobj( wt ); if(wo) { r1 = wo->get_dir(); } } return r1; } void wayobj_t::calc_image() { #ifdef MULTI_THREAD pthread_mutex_lock( &wayobj_calc_image_mutex ); #endif grund_t *gr = welt->lookup(get_pos()); diagonal = false; if(gr) { const waytype_t wt = (desc->get_wtyp()==tram_wt) ? track_wt : desc->get_wtyp(); weg_t *w=gr->get_weg(wt); if(!w) { dbg->error("wayobj_t::calc_image()","without way at (%s)", get_pos().get_str() ); // well, we are not on a way anymore? => delete us cleanup(get_owner()); delete this; gr->set_flag(grund_t::dirty); #ifdef MULTI_THREAD pthread_mutex_unlock( &wayobj_calc_image_mutex ); #endif return; } ribi_t::ribi sec_way_ribi_unmasked = 0; if(wt == decoration_wt) { if (weg_t *sec_w = gr->get_weg_nr(1)) { sec_way_ribi_unmasked = sec_w->get_ribi_unmasked(); } } set_yoff( -gr->get_weg_yoff() ); set_xoff( 0 ); dir &= (w->get_ribi_unmasked() | sec_way_ribi_unmasked); // if there is a slope, we are finished, only four choices here (so far) hang = gr->get_weg_hang(); if(hang!=slope_t::flat) { #ifdef MULTI_THREAD pthread_mutex_unlock( &wayobj_calc_image_mutex ); #endif return; } // find out whether using diagonals or straight lines if(ribi_t::is_bend(dir) && desc->has_diagonal_image()) { ribi_t::ribi r1 = ribi_t::none, r2 = ribi_t::none; // get the ribis of the ways that connect to us // r1 will be 45 degree clockwise ribi (eg northeast->east), r2 will be anticlockwise ribi (eg northeast->north) r1 = find_next_ribi( gr, ribi_t::rotate45(dir), wt ); r2 = find_next_ribi( gr, ribi_t::rotate45l(dir), wt ); // diagonal if r1 or r2 are our reverse and neither one is 90 degree rotation of us diagonal = (r1 == ribi_t::backward(dir) || r2 == ribi_t::backward(dir)) && r1 != ribi_t::rotate90l(dir) && r2 != ribi_t::rotate90(dir); if(diagonal) { // with this, we avoid calling us endlessly // HACK (originally by hajo?) static int rekursion = 0; if(rekursion == 0) { grund_t *to; rekursion++; for(int r = 0; r < 4; r++) { if(gr->get_neighbour(to, wt, ribi_t::nesw[r])) { wayobj_t* wo = to->get_wayobj( wt ); if(wo) { wo->calc_image(); } } } rekursion--; } image_id after = desc->get_front_diagonal_image_id(dir); image_id image = desc->get_back_diagonal_image_id(dir); if(image==IMG_EMPTY && after==IMG_EMPTY) { // no diagonals available diagonal = false; } } } } #ifdef MULTI_THREAD pthread_mutex_unlock( &wayobj_calc_image_mutex ); #endif } /******************** static stuff from here **********************/ /* better use this constrcutor for new wayobj; it will extend a matching obj or make an new one */ void wayobj_t::extend_wayobj(koord3d pos, player_t *owner, ribi_t::ribi dir, const way_obj_desc_t *desc, bool keep_existing_faster_way) { grund_t *gr=welt->lookup(pos); if(gr) { wayobj_t *existing_wayobj = gr->get_wayobj( desc->get_wtyp() ); if( existing_wayobj ) { if( ( existing_wayobj->get_desc()->get_topspeed() < desc->get_topspeed() || !keep_existing_faster_way) && player_t::check_owner(owner, existing_wayobj->get_owner()) && existing_wayobj->get_desc() != desc ) { // replace slower by faster if desired dir = dir | existing_wayobj->get_dir(); gr->set_flag(grund_t::dirty); delete existing_wayobj; } else { // extend this one instead existing_wayobj->set_dir(dir|existing_wayobj->get_dir()); existing_wayobj->mark_image_dirty( existing_wayobj->get_front_image(), 0 ); existing_wayobj->mark_image_dirty( existing_wayobj->get_image(), 0 ); existing_wayobj->set_flag(obj_t::dirty); return; } } // nothing found => make a new one wayobj_t *wo = new wayobj_t(pos,owner,dir,desc); gr->obj_add(wo); wo->finish_rd(); wo->calc_image(); wo->mark_image_dirty( wo->get_front_image(), 0 ); wo->set_flag(obj_t::dirty); player_t::book_construction_costs( owner, -desc->get_price(), pos.get_2d(), desc->get_wtyp()); for( uint8 i = 0; i < 4; i++ ) { // Extend wayobjects around the new one, that aren't already connected. if( ribi_t::nesw[i] & ~wo->get_dir() ) { grund_t *next_gr; if( gr->get_neighbour( next_gr, desc->get_wtyp(), ribi_t::nesw[i] ) ) { wayobj_t *wo2 = next_gr->get_wayobj( desc->get_wtyp() ); if( wo2 ) { wo2->set_dir( wo2->get_dir() | ribi_t::backward(ribi_t::nesw[i]) ); wo2->mark_image_dirty( wo2->get_front_image(), 0 ); wo->set_dir( wo->get_dir() | ribi_t::nesw[i] ); wo->mark_image_dirty( wo->get_front_image(), 0 ); } } } } } } // to sort wayobj for always the same menu order static bool compare_wayobj_desc(const way_obj_desc_t* a, const way_obj_desc_t* b) { int diff = a->get_wtyp() - b->get_wtyp(); if (diff == 0) { diff = a->get_topspeed() - b->get_topspeed(); } if (diff == 0) { /* Some speed: sort by name */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } bool wayobj_t::successfully_loaded() { if(table.empty()) { dbg->warning("wayobj_t::successfully_loaded()", "No obj found - may crash when loading catenary."); } way_obj_desc_t const* def = 0; for(auto const& i : table) { way_obj_desc_t const& b = *i.value; if (!b.is_overhead_line()) continue; if (b.get_wtyp() != track_wt) continue; if (def && def->get_topspeed() >= b.get_topspeed()) continue; def = &b; } default_oberleitung = def; return true; } bool wayobj_t::register_desc(way_obj_desc_t *desc) { // avoid duplicates with same name if( const way_obj_desc_t *old_desc = table.remove(desc->get_name()) ) { tool_t::general_tool.remove( old_desc->get_builder() ); delete old_desc->get_builder(); delete old_desc; } if( desc->get_cursor()->get_image_id(1)!=IMG_EMPTY ) { // only add images for wayobjexts with cursor ... tool_build_wayobj_t *tool = new tool_build_wayobj_t(); tool->set_icon( desc->get_cursor()->get_image_id(1) ); tool->cursor = desc->get_cursor()->get_image_id(0); tool->set_default_param(desc->get_name()); tool_t::general_tool.append( tool ); desc->set_builder( tool ); } else { desc->set_builder( NULL ); } table.put(desc->get_name(), desc); DBG_DEBUG( "wayobj_t::register_desc()","%s", desc->get_name() ); return true; } /** * Fill menu with icons of given wayobjects from the list */ void wayobj_t::fill_menu(tool_selector_t *tool_selector, waytype_t wtyp, sint16 /*sound_ok*/) { // check if scenario forbids this if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_WAYOBJ | GENERAL_TOOL, wtyp)) { return; } bool enable = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_WAYOBJ | GENERAL_TOOL, wtyp, 0 ); const uint16 time=welt->get_timeline_year_month(); vector_tplmatching; for(auto const& i : table) { way_obj_desc_t const* const desc = i.value; if( desc->is_available(time) ) { DBG_DEBUG("wayobj_t::fill_menu()", "try to add %s(%p)", desc->get_name(), desc); // only add items with a cursor if( desc->get_builder() && wtyp==desc->get_wtyp() ) { if (welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_WAYOBJ | GENERAL_TOOL, wtyp, desc->get_name())) { matching.append(desc); } } } } // sort the tools before adding to menu std::sort(matching.begin(), matching.end(), compare_wayobj_desc); for(way_obj_desc_t const* const i : matching) { i->get_builder()->enabled = enable && welt->get_scenario()->is_tool_enabled(welt->get_active_player(), TOOL_BUILD_WAYOBJ | GENERAL_TOOL, wtyp, i->get_name()); tool_selector->add_tool_selector(i->get_builder()); } } const way_obj_desc_t *wayobj_t::get_overhead_line(waytype_t wt, uint16 time) { for(auto const& i : table) { way_obj_desc_t const* const desc = i.value; if( desc->is_available(time) && desc->get_wtyp()==wt && desc->is_overhead_line() ) { return desc; } } return NULL; } const way_obj_desc_t* wayobj_t::find_desc(const char *str) { return wayobj_t::table.get(str); } simutrans-124.3/src/simutrans/obj/wayobj.h000066400000000000000000000060551474050137200206130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WAYOBJ_H #define OBJ_WAYOBJ_H #include "../simtypes.h" #include "../display/simimg.h" #include "simobj.h" #include "../dataobj/ribi.h" #include "../descriptor/way_obj_desc.h" #include "../tpl/stringhashtable_tpl.h" class player_t; class karte_t; class koord; class grund_t; class tool_selector_t; /* wayobj enable various functionality of ways, most prominent are overhead power lines */ class wayobj_t : public obj_no_info_t { private: const way_obj_desc_t *desc; uint8 diagonal:1; uint8 hang:7; // direction of this wayobj uint8 nw:1; uint8 dir:7; static const uint8 dir_unknown = 127; ribi_t::ribi find_next_ribi(const grund_t *start, const ribi_t::ribi dir, const waytype_t wt) const; public: wayobj_t(koord3d pos, player_t *owner, ribi_t::ribi dir, const way_obj_desc_t *desc); wayobj_t(loadsave_t *file); virtual ~wayobj_t(); const way_obj_desc_t *get_desc() const {return desc;} void rotate90() OVERRIDE; /** * the back image, drawn before vehicles */ image_id get_image() const OVERRIDE { return hang!=slope_t::flat ? desc->get_back_slope_image_id(hang) : (dir>16 ? desc->get_crossing_image_id(dir,nw,false) : (diagonal ? desc->get_back_diagonal_image_id(dir) : desc->get_back_image_id(dir)) ); } /** * the front image, drawn after everything else */ image_id get_front_image() const OVERRIDE { return hang!=slope_t::flat ? desc->get_front_slope_image_id(hang) : (dir>16 ? desc->get_crossing_image_id(dir,nw,true) : (diagonal ? desc->get_front_diagonal_image_id(dir) : desc->get_front_image_id(dir)) ); } typ get_typ() const OVERRIDE { return wayobj; } /** * waytype associated with this object */ waytype_t get_waytype() const OVERRIDE { return desc ? desc->get_wtyp() : invalid_wt; } void calc_image() OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; void cleanup(player_t *player) OVERRIDE; const char *get_removal_error(const player_t *player) OVERRIDE; void finish_rd() OVERRIDE; // specific for wayobj void set_dir(ribi_t::ribi d) { dir = d; calc_image(); } ribi_t::ribi get_dir() const { return dir; } /* the static routines */ private: static stringhashtable_tpl table; public: static const way_obj_desc_t *default_oberleitung; // use this constructor; it will extend a matching existing wayobj static void extend_wayobj(koord3d pos, player_t *owner, ribi_t::ribi dir, const way_obj_desc_t *desc, bool keep_existing_faster_way); static bool register_desc(way_obj_desc_t *desc); static bool successfully_loaded(); // search an object (currently only used by AI for catenary) static const way_obj_desc_t *get_overhead_line(waytype_t wt, uint16 time); static const way_obj_desc_t *find_desc(const char *); /** * Fill menu with icons of given stops from the list */ static void fill_menu(tool_selector_t *tool_selector, waytype_t wtyp, sint16 sound_ok); static const stringhashtable_tpl& get_list() { return table; } }; #endif simutrans-124.3/src/simutrans/obj/wolke.cc000066400000000000000000000076521474050137200206030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../world/simworld.h" #include "simobj.h" #include "../utils/simrandom.h" #include "wolke.h" #include "../dataobj/loadsave.h" #include "../descriptor/factory_desc.h" #include "../tpl/vector_tpl.h" vector_tplwolke_t::all_clouds(0); freelist_iter_tpl wolke_t::fl; bool wolke_t::register_desc(const skin_desc_t* desc) { // avoid duplicates with same name for(skin_desc_t const* & i : all_clouds) { if (strcmp(i->get_name(), desc->get_name()) == 0) { i = desc; return true; } } return all_clouds.append_unique( desc ); } wolke_t::wolke_t(koord3d pos, sint8 b_x_off, sint8 b_y_off, sint16 b_h_off, uint16 lt, uint16 ul, const skin_desc_t* desc ) : obj_no_info_t(pos) { cloud_nr = all_clouds.index_of(desc); base_y_off = b_h_off; set_xoff( b_x_off ); set_yoff( b_y_off ); insta_zeit = 0; lifetime = lt; uplift = ul; } wolke_t::~wolke_t() { mark_image_dirty( get_image(), calc_yoff() ); } wolke_t::wolke_t(loadsave_t* const file) : obj_no_info_t() { rdwr(file); } image_id wolke_t::get_front_image() const { const skin_desc_t *desc = all_clouds[cloud_nr]; return desc->get_image_id( (insta_zeit*desc->get_count())/(lifetime+1) ); } sint16 wolke_t::calc_yoff() const { return tile_raster_scale_y( base_y_off - (((long)insta_zeit * uplift * OBJECT_OFFSET_STEPS) >> 16), get_current_tile_raster_width() ); } void wolke_t::rdwr(loadsave_t *file) { // not saving clouds! (and loading only for compatibility) assert(file->is_loading()); obj_t::rdwr( file ); cloud_nr = 0; insta_zeit = 0; uint32 ldummy = 0; file->rdwr_long(ldummy); uint16 dummy = 0; file->rdwr_short(dummy); file->rdwr_short(dummy); // do not remove from this position, since there will be nothing obj_t::set_flag(obj_t::not_on_map); } sync_result wolke_t::sync_step(uint32 delta_t) { // we query the image twice, since it may have changed (there are sure more efficient ways for that ... const image_id old_img = get_front_image(); const sint16 old_yoff = calc_yoff(); insta_zeit += delta_t; if( insta_zeit >= lifetime ) { // delete wolke ... set_flag( obj_t::dirty ); mark_image_dirty( old_img, old_yoff ); insta_zeit = lifetime; return SYNC_DELETE; } const image_id new_img = get_front_image(); // move cloud up const sint16 new_yoff = calc_yoff(); if( new_img != old_img ) { // change cloud set_flag( obj_t::dirty ); mark_image_dirty( old_img, old_yoff ); } if( new_yoff != old_yoff ) { // move cloud set_flag( obj_t::dirty ); mark_image_dirty( old_img, old_yoff ); // wind effect set_xoff( get_xoff() - sim_async_rand(2)); } return SYNC_OK; } #ifdef MULTI_THREAD void wolke_t::display_after( int xpos, int ypos, const sint8 extra_param ) const #else void wolke_t::display_after( int xpos, int ypos, bool extra_param ) const #endif { obj_t::display_after( xpos, ypos + calc_yoff(), extra_param ); } // called during map rotation void wolke_t::rotate90() { // most basic: rotate coordinate obj_t::rotate90(); if( lifetime != DEFAULT_EXHAUSTSMOKE_TIME ) { // since factory smoke may come from the wrong tile, remove it on rotation insta_zeit = lifetime; } } /***************************** just for compatibility, the old raucher and smoke clouds *********************************/ raucher_t::raucher_t(loadsave_t *file) : obj_t() { assert(file->is_loading()); obj_t::rdwr( file ); const char *s = NULL; file->rdwr_str(s); free(const_cast(s)); // do not remove from this position, since there will be nothing obj_t::set_flag(obj_t::not_on_map); } async_wolke_t::async_wolke_t(loadsave_t *file) : obj_t() { // not saving clouds! assert(file->is_loading()); obj_t::rdwr( file ); uint32 dummy; file->rdwr_long(dummy); // do not remove from this position, since there will be nothing obj_t::set_flag(obj_t::not_on_map); } simutrans-124.3/src/simutrans/obj/wolke.h000066400000000000000000000046471474050137200204460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_WOLKE_H #define OBJ_WOLKE_H #include "simobj.h" #include "../descriptor/skin_desc.h" #include "../tpl/vector_tpl.h" #include "../display/simimg.h" #include "../tpl/freelist_iter_tpl.h" class karte_t; #define DEFAULT_EXHAUSTSMOKE_TIME (2497) /** * smoke clouds (formerly sync_wolke_t) */ class wolke_t : public obj_no_info_t { private: static vector_tplall_clouds; uint16 insta_zeit; // clouds vanish when insta_zeit>2500 => maximum 5 images ... sint16 base_y_off; // since sint8 may overflow wiht larger pak sizes uint16 lifetime; // since factories generate other smoke than uint16 uplift; uint8 cloud_nr; sint16 calc_yoff() const; // calculate the smoke height using uplift and insta_zeit static freelist_iter_tpl fl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules public: static bool register_desc(const skin_desc_t *desc); wolke_t(loadsave_t *file); wolke_t(koord3d pos, sint8 xoff, sint8 yoff, sint16 hoff, uint16 lifetime, uint16 uplift, const skin_desc_t *cloud ); ~wolke_t(); sync_result sync_step(uint32 delta_t); void* operator new(size_t) { return fl.gimme_node(); } void operator delete(void* p) { return fl.putback_node(p); } static void sync_handler(uint32 delta_t) { fl.sync_step(delta_t); } const char* get_name() const OVERRIDE { return "Wolke"; } typ get_typ() const OVERRIDE { return cloud; } image_id get_image() const OVERRIDE { return IMG_EMPTY; } image_id get_front_image() const OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; void rotate90() OVERRIDE; /** * Draw foreground image * (everything that is in front of vehicles) */ #ifdef MULTI_THREAD virtual void display_after( int xpos, int ypos, const sint8 clip_num ) const OVERRIDE; #else virtual void display_after( int xpos, int ypos, bool is_global ) const OVERRIDE; #endif }; /** * following two classes are just for compatibility for old save games */ class async_wolke_t : public obj_t { public: async_wolke_t(loadsave_t *file); typ get_typ() const OVERRIDE { return old_async_wolke; } image_id get_image() const OVERRIDE { return IMG_EMPTY; } }; class raucher_t : public obj_t { public: raucher_t(loadsave_t *file); typ get_typ() const OVERRIDE { return old_raucher; } image_id get_image() const OVERRIDE { return IMG_EMPTY; } }; #endif simutrans-124.3/src/simutrans/obj/zeiger.cc000066400000000000000000000051451474050137200207420ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file zeiger.cc object to mark tiles */ #include #include "../world/simworld.h" #include "simobj.h" #include "../simhalt.h" #include "../ground/grund.h" #include "../dataobj/environment.h" #include "zeiger.h" zeiger_t::zeiger_t(loadsave_t *file) : obj_no_info_t() { image = IMG_EMPTY; foreground_image = IMG_EMPTY; area = koord(0,0); offset = koord(0,0); rdwr(file); } zeiger_t::zeiger_t(koord3d pos, player_t *player) : obj_no_info_t(pos) { set_owner( player ); image = IMG_EMPTY; foreground_image = IMG_EMPTY; area = koord(0,0); offset = koord(0,0); } /** * We want to be able to highlight the current tile. * Unmarks area around old and marks area around new position. * Use this routine to change position. */ void zeiger_t::change_pos(koord3d k ) { if( k != get_pos() ) { // remove from old position // and clear mark grund_t *gr = welt->lookup( get_pos() ); if(gr==NULL) { gr = welt->lookup_kartenboden( get_pos().get_2d() ); } if(gr) { if( gr->get_halt().is_bound() ) { gr->get_halt()->mark_unmark_coverage( false ); } welt->mark_area( get_pos()- offset, area, false ); } if( get_pos().x >= welt->get_size().x-1 || get_pos().y >= welt->get_size().y-1 ) { // the raise and lower tool actually can go to size! welt->set_background_dirty(); // this removes crap form large cursors overlapping into the nirvana } mark_image_dirty( get_image(), 0 ); mark_image_dirty( get_front_image(), 0 ); set_flag( obj_t::dirty ); obj_t::set_pos( k ); if( get_yoff() == Z_PLAN ) { gr = welt->lookup( k ); if( gr == NULL ) { gr = welt->lookup_kartenboden( k.get_2d() ); } if(gr) { if( gr->get_halt().is_bound() && env_t::station_coverage_show ) { gr->get_halt()->mark_unmark_coverage( true ); } welt->mark_area( k-offset, area, true ); } } } } void zeiger_t::set_image( image_id b ) { // mark dirty mark_image_dirty( image, 0 ); mark_image_dirty( b, 0 ); image = b; } void zeiger_t::set_foreground_image( image_id b ) { // mark dirty mark_image_dirty( foreground_image, 0 ); mark_image_dirty( b, 0 ); foreground_image = b; } void zeiger_t::set_area(koord new_area, bool center, koord new_offset) { if (center) { new_offset = new_area/2; } if(new_area==area && new_offset==offset) { return; } welt->mark_area( get_pos()-offset, area, false ); area = new_area; offset = new_offset; welt->mark_area( get_pos()-offset, area, true ); } bool zeiger_t::has_managed_lifecycle() const { return true; } simutrans-124.3/src/simutrans/obj/zeiger.h000066400000000000000000000025341474050137200206030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OBJ_ZEIGER_H #define OBJ_ZEIGER_H #include "simobj.h" #include "../simtypes.h" #include "../display/simimg.h" /** @file zeiger.h object to mark tiles */ /** * These objects mark tiles for tools. It marks the current tile * pointed to by mouse pointer (and possibly an area around it). */ class zeiger_t : public obj_no_info_t { private: koord area, offset; /// images image_id image, foreground_image; public: zeiger_t(loadsave_t *file); zeiger_t(koord3d pos, player_t *player); void change_pos(koord3d k); const char *get_name() const OVERRIDE {return "Zeiger";} typ get_typ() const OVERRIDE { return zeiger; } /** * Set area to be marked around cursor * @param area size of marked area * @param center true if cursor is centered within marked area * @param offset if center==false then cursor is at position @p offset */ void set_area( koord area, bool center, koord offset = koord(0,0) ); /// set back image void set_image( image_id b ); /// get back image image_id get_image() const OVERRIDE {return image;} /// set front image void set_foreground_image( image_id b ); /// get front image image_id get_front_image() const OVERRIDE {return foreground_image;} bool has_managed_lifecycle() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/old_blockmanager.cc000066400000000000000000000152301474050137200221620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simdebug.h" #include "world/simworld.h" #include "player/simplay.h" #include "simmesg.h" #include "display/simimg.h" #include "obj/signal.h" #include "obj/tunnel.h" #include "ground/grund.h" #include "obj/way/schiene.h" #include "dataobj/loadsave.h" #include "dataobj/translator.h" #include "dataobj/environment.h" #include "tpl/slist_tpl.h" #include "old_blockmanager.h" // only needed for loading old games class oldsignal_t : public obj_t { protected: uint8 state; uint8 blockend; uint8 dir; obj_t::typ type; public: oldsignal_t(loadsave_t *file, obj_t::typ type); /** * return direction or the state of the traffic light */ ribi_t::ribi get_dir() const { return dir; } bool ist_blockiert() const {return blockend != 0;} obj_t::typ get_typ() const OVERRIDE { return type; } void rdwr(loadsave_t *file) OVERRIDE; image_id get_image() const OVERRIDE { return IMG_EMPTY; } }; static slist_tpl signale; //------------------------- old blockmanager ---------------------------- // only there to convert old games to 89.02 and higher // these two routines for compatibility oldsignal_t::oldsignal_t(loadsave_t *file, obj_t::typ type) : obj_t () { this->type = type; rdwr(file); } void oldsignal_t::rdwr(loadsave_t *file) { if(!file->is_loading()) { dbg->fatal("oldsignal_t::rdwr()","cannot be saved!"); } // loading from blockmanager! obj_t::rdwr(file); file->rdwr_byte(blockend); file->rdwr_byte(state); file->rdwr_byte(dir); } // now the old block reader void old_blockmanager_t::rdwr_block(karte_t *,loadsave_t *file) { sint32 count; short int typ = obj_t::signal; // load signal file->rdwr_long(count); for(int i=0; ird_obj_id(); oldsignal_t *sig = new oldsignal_t(file, (obj_t::typ)typ); DBG_MESSAGE("oldsignal_t()","on %i,%i with dir=%i blockend=%i",sig->get_pos().x,sig->get_pos().y,sig->get_dir(),sig->ist_blockiert()); signale.insert( sig ); } // counters if(file->is_version_less(88, 6)) { // old style sint32 dummy = 0; file->rdwr_long(dummy); file->rdwr_long(dummy); } else { sint16 dummy; file->rdwr_short(dummy); } } void old_blockmanager_t::rdwr(karte_t *welt, loadsave_t *file) { signale.clear(); if(file->is_version_atleast(89, 0)) { // nothing to do any more ... return; } assert(file->is_loading()); // this routine just reads the of signal positions // and converts them to the new type> sint32 count; file->rdwr_long(count); for(int i=0; ilookup(os1->get_pos()); grund_t *to=NULL; uint8 directions=0; waytype_t wt=gr->hat_weg(track_wt) ? track_wt : monorail_wt; if( gr->get_neighbour(to,wt,os1->get_dir()) ) { for(oldsignal_t* const s : signale) { if (s->get_pos() == to->get_pos()) { os2 = s; break; } } if(os2==NULL) { dbg->error("old_blockmanager_t::finish_rd()","old signal near (%i,%i) is unpaired!",gr->get_pos().x,gr->get_pos().y); welt->get_message()->add_message(translator::translate("Orphan signal during loading!"),os1->get_pos(),message_t::problems); } } else { dbg->error("old_blockmanager_t::finish_rd()","old signal near (%i,%i) is unpaired!",gr->get_pos().x,gr->get_pos().y); welt->get_message()->add_message(translator::translate("Orphan signal during loading!"),os1->get_pos(),message_t::problems); } // remove second signal from list if(os2) { signale.remove(os2); } // now we should have a pair of signals ... or something was very wrong grund_t* new_signal_gr = 0; roadsign_desc_t::types type = roadsign_desc_t::SIGN_SIGNAL; ribi_t::ribi dir = 0; // now find out about type and direction if(os2 && !os2->ist_blockiert()) { // built the signal here, if possible grund_t *tmp=to; to = gr; gr = tmp; if(os2->get_typ()==obj_t::old_presignal) { type = roadsign_desc_t::SIGN_PRE_SIGNAL; } else if(os2->get_typ()==obj_t::old_choosesignal) { type |= roadsign_desc_t::CHOOSE_SIGN; } dir = os2->get_dir(); directions = 1; } else { // gr is already the first choice // so we just have to determine the type if(os1->get_typ()==obj_t::old_presignal) { type = roadsign_desc_t::SIGN_PRE_SIGNAL; } else if(os1->get_typ()==obj_t::old_choosesignal) { type |= roadsign_desc_t::CHOOSE_SIGN; } } // take care of one way if(!os1->ist_blockiert()) { directions ++; dir |= os1->get_dir(); } // now check where we can built best if(gr->hat_weg(wt) && ribi_t::is_twoway(gr->get_weg(wt)->get_ribi_unmasked())) { new_signal_gr = gr; } if((new_signal_gr==NULL || !os1->ist_blockiert()) && to && to->hat_weg(wt) && ribi_t::is_twoway(to->get_weg(wt)->get_ribi_unmasked())) { new_signal_gr = to; } if(directions==2 && new_signal_gr) { dir = new_signal_gr->get_weg(wt)->get_ribi_unmasked(); } // found a suitable location, ribi, signal type => construct if(new_signal_gr && dir!=0) { const roadsign_desc_t *sb=roadsign_t::roadsign_search(type,wt,0); if(sb!=NULL) { signal_t *sig = new signal_t(new_signal_gr->get_weg(wt)->get_owner(),new_signal_gr->get_pos(),dir,sb); new_signal_gr->obj_add(sig); //DBG_MESSAGE("old_blockmanager::finish_rd()","signal restored at %i,%i with dir %i",gr->get_pos().x,gr->get_pos().y,dir); } else { dbg->error("old_blockmanager_t::finish_rd()","no roadsign for way %x with type %d found!",type,wt); sprintf(buf,err_text,os1->get_pos().x,os1->get_pos().y); welt->get_message()->add_message(buf,os1->get_pos(),message_t::problems); failure++; } } else { dbg->warning("old_blockmanager_t::finish_rd()","could not restore old signal near (%i,%i), dir=%i",gr->get_pos().x,gr->get_pos().y,dir); sprintf(buf,err_text,os1->get_pos().x,os1->get_pos().y); welt->get_message()->add_message(buf,os1->get_pos(),message_t::problems); failure ++; } os1->set_pos(koord3d::invalid); delete os1; if(os2) { os2->set_pos(koord3d::invalid); delete os2; } } if(failure) { dbg->warning("old_blockmanager_t::finish_rd()","failed on %d signal pairs.",failure); } } simutrans-124.3/src/simutrans/old_blockmanager.h000066400000000000000000000007541474050137200220310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef OLD_BLOCKMANAGER_H #define OLD_BLOCKMANAGER_H class karte_t; class loadsave_t; /** * Old class to manage track reservations. * Only needed to load very old savegames. */ class old_blockmanager_t { private: static void rdwr_block(karte_t *welt,loadsave_t *file); public: static void rdwr(karte_t *welt, loadsave_t *file); static void finish_rd(karte_t *welt); }; #endif simutrans-124.3/src/simutrans/pathes.h000066400000000000000000000014641474050137200200310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PATHES_H #define PATHES_H /** * This header defines all paths used be simutrans relative to the game directory. * * \parblock * two defines for all paths - if You want the root path, use: * #define _PATH "" * #define _PATH_X "" * else use * #define _PATH "somewhere" * #define _PATH_X _PATH "/" * \endparblock */ #define USER_PAK_PATH "simutrans" #define USER_PAK_PATH_X USER_PAK_PATH "/" #define FONT_PATH "font" #define FONT_PATH_X FONT_PATH "/" #define SAVE_PATH "save" #define SAVE_PATH_X SAVE_PATH "/" #define SAVE_PATH_X_LEN (sizeof(SAVE_PATH_X) - 1) #define SCREENSHOT_PATH "screenshot" #define SCREENSHOT_PATH_X SCREENSHOT_PATH "/" #endif simutrans-124.3/src/simutrans/player/000077500000000000000000000000001474050137200176635ustar00rootroot00000000000000simutrans-124.3/src/simutrans/player/ai.cc000066400000000000000000000414361474050137200205730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "finance.h" #include "ai.h" #include "../world/simcity.h" #include "../simconvoi.h" #include "../simhalt.h" #include "../simintr.h" #include "../tool/simmenu.h" #include "../simskin.h" #include "../simware.h" #include "../builder/brueckenbauer.h" #include "../builder/hausbauer.h" #include "../builder/tunnelbauer.h" #include "../builder/vehikelbauer.h" #include "../builder/wegbauer.h" #include "../descriptor/building_desc.h" #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" #include "../obj/zeiger.h" #include "../utils/cbuffer.h" #include "../vehicle/vehicle.h" /* The flesh for the place with road for headquarters searcher ... */ bool ai_building_place_with_road_finder::is_road_at(sint16 x, sint16 y) const { grund_t *bd = welt->lookup_kartenboden( koord(x,y) ); return bd && bd->hat_weg(road_wt); } bool ai_building_place_with_road_finder::is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const { if(building_placefinder_t::is_area_ok(pos, w, h, cl)) { // check to not built on a road int i, j; for(j=pos.x; jlookup_kartenboden(pos) ) { return haltestelle_t::get_halt( gr->get_pos(), this ); } return halthandle_t(); } /** * returns true, * if there is already a connection */ bool ai_t::is_connected( const koord start_pos, const koord dest_pos, const goods_desc_t *wtyp ) const { // Dario: Check if there's a stop near destination const planquadrat_t* start_plan = welt->access(start_pos); const halthandle_t* start_list = start_plan->get_haltlist(); const uint16 start_halt_count = start_plan->get_haltlist_count(); // now try to find a route // ok, they are not in walking distance ware_t ware(wtyp); ware.set_target_pos(dest_pos); ware.amount = 1; return (start_halt_count != 0) && (haltestelle_t::search_route( start_list, start_halt_count, false, ware ) != haltestelle_t::NO_ROUTE); } // calls a general tool just like a player work do bool ai_t::call_general_tool( int tool, koord k, const char *param ) { grund_t *gr = welt->lookup_kartenboden(k); koord3d pos = gr ? gr->get_pos() : koord3d::invalid; const char *old_param = tool_t::general_tool[tool]->get_default_param(); tool_t::general_tool[tool]->set_default_param(param); const char * err = tool_t::general_tool[tool]->work( this, pos ); if(err) { if(*err) { dbg->message("ai_t::call_general_tool()","failed for tool %i at (%s) because of \"%s\"", tool, pos.get_str(), err ); } else { dbg->message("ai_t::call_general_tool()","not successful for tool %i at (%s)", tool, pos.get_str() ); } } tool_t::general_tool[tool]->set_default_param(old_param); return err==0; } /* returns ok, of there is a suitable space found * only check into two directions, the ones given by dir */ bool ai_t::suche_platz(koord pos, koord &size, koord *dirs) { sint16 length = abs( size.x + size.y ); const grund_t *gr = welt->lookup_kartenboden(pos); if( gr==NULL ) { return false; } sint8 start_z = gr->get_hoehe(); int max_dir = length==0 ? 1 : 2; bool place_ok; // two rotations for( int dir=0; dirlookup_kartenboden( pos + (dirs[dir]*i) ); if( gr == NULL || gr->get_halt().is_bound() || !welt->can_flatten_tile(this, pos, start_z ) || !gr->ist_natur() || gr->kann_alle_obj_entfernen(this) != NULL || gr->get_hoehe() < welt->get_water_hgt( pos + (dirs[dir] * i) ) ) { // something is blocking construction, try next rotation place_ok = false; break; } } if( place_ok ) { // apparently we can build this rotation here size = dirs[dir]*length; return true; } } return false; } /** needed renovation due to different sized factories * also try "nicest" place first */ bool ai_t::suche_platz(koord &start, koord &size, koord target, koord off) { // distance of last found point int dist=0x7FFFFFFF; koord platz; int const cov = welt->get_settings().get_station_coverage(); int xpos = start.x; int ypos = start.y; koord dir[2]; if( abs(start.x-target.x)get_size().y, ypos + off.y + cov ); int maxx = min( welt->get_size().x, xpos + off.x + cov ); for (int y = max(0,ypos-cov); y < maxy; y++) { for (int x = max(0,xpos-cov); x < maxx; x++) { platz = koord(x,y); // no water tiles if( welt->lookup_kartenboden(platz)->get_hoehe() <= welt->get_water_hgt(platz) ) { continue; } // thus now check them int current_dist = koord_distance(platz,target); if( current_distlookup_kartenboden(pos); zeiger_t *z = gr->find(); delete z; } } } void ai_t::set_marker( koord place, koord size ) { koord pos; if(size.y<0) { place.y += size.y; size.y = -size.y; } if(size.x<0) { place.x += size.x; size.x = -size.x; } for( pos.y=place.y; pos.y<=place.y+size.y; pos.y++ ) { for( pos.x=place.x; pos.x<=place.x+size.x; pos.x++ ) { grund_t *gr = welt->lookup_kartenboden(pos); zeiger_t *z = new zeiger_t(gr->get_pos(), this); z->set_image( skinverwaltung_t::belegtzeiger->get_image_id(0) ); gr->obj_add( z ); } } } /* builds headquarters or upgrades one */ bool ai_t::built_update_headquarter() { // find next level const building_desc_t* desc = hausbauer_t::get_headquarters(get_headquarter_level(), welt->get_timeline_year_month()); // is the a suitable one? if(desc!=NULL) { // cost is negative! sint64 const cost = welt->get_settings().cst_multiply_headquarter * desc->get_level() * desc->get_x() * desc->get_y(); if( finance->get_account_balance()+cost > finance->get_starting_money() ) { // and enough money left ... koord place = get_headquarter_pos(); if(place!=koord::invalid) { // remove old hq grund_t *gr = welt->lookup_kartenboden(place); gebaeude_t *prev_hq = gr->find(); // other size? if( desc->get_size()!=prev_hq->get_tile()->get_desc()->get_size() ) { // needs new place place = koord::invalid; } else { // old positions false after rotation => correct it place = prev_hq->get_pos().get_2d() - prev_hq->get_tile()->get_offset(); } } // needs new place? if(place==koord::invalid) { stadt_t *st = NULL; for(halthandle_t const halt : haltestelle_t::get_alle_haltestellen()) { if( halt->get_owner()==this ) { st = welt->find_nearest_city(halt->get_basis_pos()); break; } } if(st) { bool is_rotate=desc->get_all_layouts()>1; place = ai_building_place_with_road_finder(welt).find_place(st->get_pos(), desc->get_x(), desc->get_y(), desc->get_allowed_climate_bits(), &is_rotate); } } const char *err="No suitable ground!"; if( place!=koord::invalid ) { err = tool_t::general_tool[TOOL_HEADQUARTER]->work( this, welt->lookup_kartenboden(place)->get_pos() ); // success if( err==NULL ) { return true; } } // failed if( place==koord::invalid || err!=NULL ) { dbg->warning( "ai_t::built_update_headquarter()", "HQ failed with : %s", translator::translate(err) ); } return false; } } return false; } /** * Find the last water tile using line algorithm * start MUST be on land! */ koord ai_t::find_shore(koord start, koord end) const { int x = start.x; int y = start.y; int xx = end.x; int yy = end.y; int i, steps; int xp, yp; int xs, ys; const int dx = xx - x; const int dy = yy - y; steps = (abs(dx) > abs(dy) ? abs(dx) : abs(dy)); if (steps == 0) steps = 1; xs = (dx << 16) / steps; ys = (dy << 16) / steps; xp = x << 16; yp = y << 16; koord last = start; for (i = 0; i <= steps; i++) { koord next(xp>>16,yp>>16); if(next!=last) { if(!welt->lookup_kartenboden(next)->is_water()) { last = next; } } xp += xs; yp += ys; } // should always find something, since it ends in water ... return last; } bool ai_t::find_harbour(koord &start, koord &size, koord target) { koord shore = find_shore(target,start); // distance of last found point int dist=0x7FFFFFFF; koord k; // now find a nice shore next to here for( k.y=max(1,shore.y-5); k.yget_size().y-2; k.y++ ) { for( k.x=max(1,shore.x-5); k.xget_size().x-2; k.x++ ) { grund_t *gr = welt->lookup_kartenboden(k); if( gr && gr->get_grund_hang() != 0 && slope_t::is_way( gr->get_grund_hang() ) && gr->ist_natur() && gr->get_hoehe() == welt->get_water_hgt(k) && !gr->is_halt() ) { koord zv = koord(gr->get_grund_hang()); if(welt->lookup_kartenboden(k-zv)->get_weg_ribi(water_wt)) { // next place is also water koord dir[2] = { zv, koord(zv.y,zv.x) }; koord platz = k+zv; int current_dist = koord_distance(k,target); if( current_distget_climate(platz1); climate c2 = welt->get_climate(platz2); if( !(welt->flatten_tile( this, platz1, welt->lookup_kartenboden(platz1)->get_hoehe() ) && welt->flatten_tile( this, platz2, welt->lookup_kartenboden(platz2)->get_hoehe() )) ) { // no flat land here?!? return false; } // ensure is land grund_t* bd = welt->lookup_kartenboden(platz1); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(platz1, bd->get_hoehe()-1); welt->access(platz1)->correct_water(); welt->set_climate(platz1, c1, true); } bd = welt->lookup_kartenboden(platz2); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(platz2, bd->get_hoehe()-1); welt->access(platz2)->correct_water(); welt->set_climate(platz2, c2, true); } // is there already a connection? // get a default vehicle vehicle_desc_t test_desc(road_wt, 25, vehicle_desc_t::diesel ); vehicle_t* test_driver = vehicle_builder_t::build(welt->lookup_kartenboden(platz1)->get_pos(), this, NULL, &test_desc); test_driver->set_flag( obj_t::not_on_map ); route_t verbindung; if( verbindung.calc_route(welt, welt->lookup_kartenboden(platz1)->get_pos(), welt->lookup_kartenboden(platz2)->get_pos(), test_driver, 0, 0) && verbindung.get_count() < 2u*koord_distance(platz1,platz2)) { DBG_MESSAGE("ai_passenger_t::create_simple_road_transport()","Already connection between %d,%d to %d,%d is only %i",platz1.x, platz1.y, platz2.x, platz2.y, verbindung.get_count() ); // found something with the nearly same length delete test_driver; return true; } delete test_driver; // no connection => built one! way_builder_t bauigel(this); bauigel.init_builder( way_builder_t::strasse, road_weg, tunnel_builder_t::get_tunnel_desc(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()) ); // we won't destroy cities (and save the money) bauigel.set_keep_existing_faster_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(10000); bauigel.calc_route(welt->lookup_kartenboden(platz1)->get_pos(),welt->lookup_kartenboden(platz2)->get_pos()); INT_CHECK("ai 501"); if( bauigel.calc_costs() > finance->get_netwealth() ) { // too expensive return false; } // now try route with terraforming way_builder_t baumaulwurf(this); baumaulwurf.init_builder( way_builder_t::strasse|way_builder_t::terraform_flag, road_weg, tunnel_builder_t::get_tunnel_desc(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()) ); baumaulwurf.set_keep_existing_faster_ways(true); baumaulwurf.set_keep_city_roads(true); baumaulwurf.set_maximum(10000); baumaulwurf.calc_route(welt->lookup_kartenboden(platz1)->get_pos(),welt->lookup_kartenboden(platz2)->get_pos()); // build with terraforming if shorter and enough money is available bool with_tf = (baumaulwurf.get_count() > 2) && (10*baumaulwurf.get_count() < 9*bauigel.get_count() || bauigel.get_count() <= 2); if( with_tf && baumaulwurf.calc_costs() > finance->get_netwealth() ) { // too expensive with_tf = false; } // now build with or without terraforming if (with_tf) { DBG_MESSAGE("ai_t::create_simple_road_transport()","building not so simple road from %d,%d to %d,%d",platz1.x, platz1.y, platz2.x, platz2.y); baumaulwurf.build(); return true; } else if(bauigel.get_count() > 2) { DBG_MESSAGE("ai_t::create_simple_road_transport()","building simple road from %d,%d to %d,%d",platz1.x, platz1.y, platz2.x, platz2.y); bauigel.build(); return true; } // beware: The stop position might have changes! DBG_MESSAGE("ai_t::create_simple_road_transport()","building simple road from %d,%d to %d,%d failed",platz1.x, platz1.y, platz2.x, platz2.y); return false; } /* create new AI */ ai_t::ai_t(uint8 nr) : player_t( nr ), road_transport(false), rail_transport(false), ship_transport(false), air_transport(false), construction_speed(env_t::default_ai_construction_speed) { } void ai_t::rdwr(loadsave_t *file) { player_t::rdwr(file); if( file->is_version_less(111, 1) ) { // do not know about ai_t return; } file->rdwr_long( construction_speed ); file->rdwr_bool( road_transport ); file->rdwr_bool( rail_transport ); file->rdwr_bool( air_transport ); file->rdwr_bool( ship_transport ); } const vehicle_desc_t *ai_t::vehicle_search(waytype_t typ, const uint32 target_power, const sint32 target_speed, const goods_desc_t * target_freight, bool include_electric) { bool obsolete_allowed = welt->get_settings().get_allow_buying_obsolete_vehicles(); return vehicle_builder_t::vehicle_search(typ, welt->get_timeline_year_month(), target_power, target_speed, target_freight, include_electric, !obsolete_allowed); } simutrans-124.3/src/simutrans/player/ai.h000066400000000000000000000056441474050137200204360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PLAYER_AI_H #define PLAYER_AI_H #include "simplay.h" #include "../world/building_placefinder.h" class karte_t; class vehicle_desc_t; class goods_desc_t; /** * Search for a free location using the function find_place(). */ class ai_building_place_with_road_finder : public building_placefinder_t { public: ai_building_place_with_road_finder(karte_t *welt) : building_placefinder_t(welt) {} bool is_road_at(sint16 x, sint16 y) const; bool is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const OVERRIDE; }; // AI helper functions class ai_t : public player_t { protected: // set the allowed modes of transport bool road_transport; bool rail_transport; bool ship_transport; bool air_transport; // the shorter the faster construction will occur sint32 construction_speed; public: ai_t(uint8 nr); bool has_road_transport() const { return road_transport; } virtual void set_road_transport( bool yesno ) { road_transport = yesno; } bool has_rail_transport() const { return rail_transport; } virtual void set_rail_transport( bool yesno ) { rail_transport = yesno; } bool has_ship_transport() const { return ship_transport; } virtual void set_ship_transport( bool yesno ) { ship_transport = yesno; } bool has_air_transport() const { return air_transport; } virtual void set_air_transport( bool yesno ) { air_transport = yesno; } sint32 get_construction_speed() const { return construction_speed; } virtual void set_construction_speed( sint32 newspeed ) { construction_speed = newspeed; } void rdwr(loadsave_t *file) OVERRIDE; // return true, if there is already a connection bool is_connected(const koord star_pos, const koord end_pos, const goods_desc_t *wtyp) const; // calls a general tool just like a human player work do bool call_general_tool( int tool, koord k, const char *param ); // find space for stations bool suche_platz(koord pos, koord &size, koord *dirs); bool suche_platz(koord &start, koord &size, koord target, koord off); // removes building markers void clean_marker( koord place, koord size ); void set_marker( koord place, koord size ); halthandle_t get_halt( const koord haltpos ) const; /** * Find the first water tile using line algorithm * start MUST be on land! */ koord find_shore(koord start, koord end) const; bool find_harbour(koord &start, koord &size, koord target); bool built_update_headquarter(); // builds a round between those two places or returns false bool create_simple_road_transport(koord platz1, koord size1, koord platz2, koord size2, const way_desc_t *road ); /// helper method to call vehicle_builder_t::vehicle_search and fill in time-line related parameters static const vehicle_desc_t *vehicle_search(waytype_t typ, const uint32 target_power, const sint32 target_speed, const goods_desc_t * target_freight, bool include_electric); }; #endif simutrans-124.3/src/simutrans/player/ai_goods.cc000066400000000000000000001463401474050137200217660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simconvoi.h" #include "../simfab.h" #include "../tool/simmenu.h" #include "../simtypes.h" #include "../tool/simtool.h" #include "../simunits.h" #include "finance.h" #include "simplay.h" #include "../simhalt.h" #include "../simintr.h" #include "../simline.h" #include "../simmesg.h" #include "../world/simworld.h" #include "../builder/brueckenbauer.h" #include "../builder/hausbauer.h" #include "../builder/tunnelbauer.h" #include "../builder/vehikelbauer.h" #include "../builder/wegbauer.h" #include "../dataobj/schedule.h" #include "../dataobj/loadsave.h" #include "../obj/wayobj.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../utils/cbuffer.h" #include "../vehicle/vehicle.h" #include "ai_goods.h" ai_goods_t::ai_goods_t(uint8 nr) : ai_t(nr), state(NR_INIT), root(NULL), start(NULL), ziel(NULL), freight(NULL), rail_vehicle(NULL), rail_engine(NULL), road_vehicle(NULL), ship_vehicle(NULL), rail_weg(NULL), road_weg(NULL), count_rail(0), count_road(0), count(0), next_construction_steps(welt->get_steps()+50) { road_transport = nr!=7; rail_transport = nr>2; ship_transport = true; air_transport = false; } /** * Methode fuer jaehrliche Aktionen */ void ai_goods_t::new_year() { player_t::new_year(); // AI will reconsider the oldest unbuiltable lines again uint remove = (uint)max(0,(int)forbidden_connections.get_count()-3); while( remove < forbidden_connections.get_count() ) { forbidden_connections.remove_first(); } } void ai_goods_t::rotate90( const sint16 y_size ) { player_t::rotate90( y_size ); // rotate places platz1.rotate90( y_size ); platz2.rotate90( y_size ); size1.rotate90( 0 ); size2.rotate90( 0 ); harbour.rotate90( y_size ); } /** * Activates/deactivates a player */ bool ai_goods_t::set_active(bool new_state) { // something to change? if(active!=new_state) { if(!new_state) { // deactivate AI active = false; state = NR_INIT; start = ziel = NULL; } else { // activate AI active = true; } } return active; } /* recursive lookup of a factory tree: * sets start and destination to the next needed supplier * start always with the first branch, if there are more goods */ bool ai_goods_t::get_factory_tree_lowest_missing( fabrik_t *fab ) { // now check for all products (should be changed later for the root) for( int i=0; iget_desc()->get_supplier_count(); i++ ) { const goods_desc_t *ware = fab->get_desc()->get_supplier(i)->get_input_type(); // find out how much is there const array_tpl& input = fab->get_input(); uint ware_nr; for( ware_nr=0; ware_nr input[ware_nr].max/4 ) { // already enough supplied to continue; } for(koord const& q : fab->get_suppliers()) { fabrik_t* const qfab = fabrik_t::get_fab(q); const factory_desc_t* const fd = qfab->get_desc(); for( uint qq = 0; qq < fd->get_product_count(); qq++ ) { if( fd->get_product(qq)->get_output_type() == ware && !is_forbidden(qfab, fab, ware) && !is_connected(q, fab->get_pos().get_2d(), ware) ) { // find out how much is there const array_tpl& output = qfab->get_output(); uint ware_nr; for(ware_nr=0; ware_nrget_suppliers().get_count()>0 && get_factory_tree_lowest_missing( qfab )) { return true; } } start = qfab; ziel = fab; freight = ware; return true; } } } // completely supplied??? } return false; } /* recursive lookup of a tree and how many factories must be at least connected * returns -1, if this tree is can't be completed */ int ai_goods_t::get_factory_tree_missing_count( fabrik_t *fab ) { int numbers=0; // how many missing? factory_desc_t const& d = *fab->get_desc(); // ok, this is a source ... if (d.is_producer_only()) { return 0; } // now check for all for (int i = 0; i < d.get_supplier_count(); ++i) { goods_desc_t const* const ware = d.get_supplier(i)->get_input_type(); bool complete = false; // found at least one factory for(koord const& q : fab->get_suppliers()) { fabrik_t* const qfab = fabrik_t::get_fab(q); if(!qfab) { dbg->error("fabrik_t::get_fab()","fab %s at %s does not find supplier at %s.", fab->get_name(), fab->get_pos().get_str(), q.get_str()); continue; } if( !is_forbidden( qfab, fab, ware ) ) { const factory_desc_t* const fd = qfab->get_desc(); for (uint qq = 0; qq < fd->get_product_count(); qq++) { if (fd->get_product(qq)->get_output_type() == ware ) { int n = get_factory_tree_missing_count( qfab ); if(n>=0) { complete = true; if (!is_connected(q, fab->get_pos().get_2d(), ware)) { numbers += 1; } numbers += n; } } } } } if(!complete) { return -1; } } return numbers; } void add_neighbourhood( vector_tpl &list, const uint16 size) { uint32 old_size = list.get_count(); koord test; for( uint32 i = 0; i < old_size; i++ ) { for( test.x = -size; test.x < size+1; test.x++ ) { for( test.y = -size; test.y < size+1; test.y++ ) { list.append_unique( list[i] + test ); } } } } bool ai_goods_t::suche_platz1_platz2(fabrik_t *qfab, fabrik_t *zfab, int length ) { clean_marker(platz1,size1); clean_marker(platz2,size2); koord start( qfab->get_pos().get_2d() ); koord start_size( length, 0 ); koord ziel( zfab->get_pos().get_2d() ); koord ziel_size( length, 0 ); bool ok = false; bool has_ziel = false; if(qfab->get_desc()->get_placement()!=factory_desc_t::Water) { if( length == 0 ) { vector_tpl tile_list[2]; uint16 const cov = welt->get_settings().get_station_coverage(); koord test; for( uint8 i = 0; i < 2; i++ ) { fabrik_t *fab = i==0 ? qfab : zfab; vector_tpl fab_tiles; fab->get_tile_list( fab_tiles ); add_neighbourhood( fab_tiles, cov ); vector_tpl one_more( fab_tiles ); add_neighbourhood( one_more, 1 ); // Any halts here? vector_tpl halts; for(koord const& j : one_more) { halthandle_t const halt = get_halt(j); if( halt.is_bound() && !halts.is_contained(halt->get_basis_pos()) ) { bool halt_connected = halt->get_fab_list().is_contained( fab ); for(haltestelle_t::tile_t const& i : halt->get_tiles() ) { koord const pos = i.grund->get_pos().get_2d(); if( halt_connected || fab_tiles.is_contained(pos) ) { halts.append_unique( pos ); } } } } add_neighbourhood( halts, 1 ); vector_tpl *next = &halts; for( uint8 k = 0; k < 2; k++ ) { // On which tiles we can start? for(koord const& j : *next) { grund_t const* const gr = welt->lookup_kartenboden(j); if( gr && gr->get_grund_hang() == slope_t::flat && !gr->hat_wege() && !gr->get_leitung() ) { tile_list[i].append_unique( gr->get_pos() ); } } if( !tile_list[i].empty() ) { // Skip, if found tiles beneath halts. break; } next = &fab_tiles; } } // Test which tiles are the best: way_builder_t bauigel(this); bauigel.init_builder( way_builder_t::strasse, road_weg, tunnel_builder_t::get_tunnel_desc(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,road_weg->get_topspeed(),welt->get_timeline_year_month()) ); // we won't destroy cities (and save the money) bauigel.set_keep_existing_faster_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(10000); bauigel.calc_route(tile_list[0], tile_list[1]); if( bauigel.get_count() > 2 ) { // Sometimes reverse route is the best, so we have to change the koords. koord3d_vector_t const& r = bauigel.get_route(); start = r.front().get_2d(); ziel = r.back().get_2d(); if( !tile_list[0].is_contained(r.front()) ) { sim::swap(start, ziel); } ok = true; has_ziel = true; } } if( !ok ) { ok = suche_platz(start, start_size, ziel, qfab->get_desc()->get_building()->get_size(qfab->get_rotate()) ); } } else { // water factory => find harbour location ok = find_harbour(start, start_size, ziel ); } if( ok && !has_ziel ) { // found a place, search for target ok = suche_platz(ziel, ziel_size, start, zfab->get_desc()->get_building()->get_size(zfab->get_rotate()) ); } INT_CHECK("simplay 1729"); if( !ok ) { // no suitable locations found DBG_MESSAGE( "ai_t::suche_platz1_platz2()", "no suitable locations found" ); } else { // save places platz1 = start; size1 = start_size; platz2 = ziel; size2 = ziel_size; DBG_MESSAGE( "ai_t::suche_platz1_platz2()", "platz1=%d,%d platz2=%d,%d", platz1.x, platz1.y, platz2.x, platz2.y ); // reserve space with marker set_marker( platz1, size1 ); set_marker( platz2, size2 ); } return ok; } /** * build docks and ships */ bool ai_goods_t::create_ship_transport_vehicle(fabrik_t *qfab, int vehicle_count) { // pak64 has barges ... const vehicle_desc_t *v_second = NULL; if(ship_vehicle->get_power()==0) { v_second = ship_vehicle; if(v_second->get_leader_count()==0 || v_second->get_leader(0)==NULL) { // pushed barge? if(ship_vehicle->get_trailer_count()>0 && ship_vehicle->get_trailer(0)!=NULL) { v_second = ship_vehicle->get_trailer(0); } else { return false; } } else { ship_vehicle = v_second->get_leader(0); } } DBG_MESSAGE( "ai_goods_t::create_ship_transport_vehicle()", "for %i ships", vehicle_count ); if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... return false; } // must remove marker grund_t* gr = welt->lookup_kartenboden(platz1); if (gr) { gr->obj_loesche_alle(this); } // try to built dock const building_desc_t* h = hausbauer_t::get_random_station(building_desc_t::dock, water_wt, welt->get_timeline_year_month(), haltestelle_t::WARE); if(h==NULL || !call_general_tool(TOOL_BUILD_STATION, platz1, h->get_name())) { return false; } // sea pos (and not on harbour ... ) halthandle_t halt = haltestelle_t::get_halt(gr->get_pos(),this); koord pos1 = platz1 - koord(gr->get_grund_hang())*h->get_size().y; koord best_pos = pos1; uint16 const cov = welt->get_settings().get_station_coverage(); for( int y = pos1.y - cov; y <= pos1.y + cov; ++y ) { for( int x = pos1.x - cov; x <= pos1.x + cov; ++x ) { koord p(x,y); grund_t *gr = welt->lookup_kartenboden(p); // check for water tile, do not start in depots if( gr->is_water() && halt == get_halt(p) && gr->get_depot()==NULL ) { if( koord_distance(best_pos,platz2)append( welt->lookup_kartenboden(best_pos), 0 ); schedule->append( welt->lookup(qfab->get_pos()), 100 ); schedule->set_current_stop( 1 ); schedule->finish_editing(); linehandle_t line=simlinemgmt.create_line(simline_t::shipline,this,schedule); delete schedule; // now create all vehicles as convois for(int i=0; i cannot do anything about this ... return i>0; } vehicle_t* v = vehicle_builder_t::build( qfab->get_pos(), this, NULL, ship_vehicle); convoi_t* cnv = new convoi_t(this); // give the new convoi name from first vehicle cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); // two part consist if(v_second!=NULL) { v = vehicle_builder_t::build( qfab->get_pos(), this, NULL, v_second ); cnv->add_vehicle( v ); } cnv->set_line(line); cnv->start(); } clean_marker(platz1,size1); clean_marker(platz2,size2); platz1 += koord(welt->lookup_kartenboden(platz1)->get_grund_hang()); return true; } void ai_goods_t::create_road_transport_vehikel(fabrik_t *qfab, int vehicle_count) { const building_desc_t* fh = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::WARE); // succeed in frachthof creation if(fh && call_general_tool(TOOL_BUILD_STATION, platz1, fh->get_name()) && call_general_tool(TOOL_BUILD_STATION, platz2, fh->get_name()) ) { koord3d pos1 = welt->lookup_kartenboden(platz1)->get_pos(); koord3d pos2 = welt->lookup_kartenboden(platz2)->get_pos(); int start_location=0; // sometimes, when factories are very close, we need exact calculation const koord3d& qpos = qfab->get_pos(); if ((qpos.x - platz1.x) * (qpos.x - platz1.x) + (qpos.y - platz1.y) * (qpos.y - platz1.y) > (qpos.x - platz2.x) * (qpos.x - platz2.x) + (qpos.y - platz2.y) * (qpos.y - platz2.y)) { start_location = 1; } // calculate vehicle start position koord3d startpos=(start_location==0)?pos1:pos2; ribi_t::ribi w_ribi = welt->lookup(startpos)->get_weg_ribi_unmasked(road_wt); // now start all vehicle one field before, so they load immediately startpos = welt->lookup_kartenboden(koord(startpos.get_2d())+koord(w_ribi))->get_pos(); // since 86.01 we use lines for road vehicles ... schedule_t *schedule=new truck_schedule_t(); schedule->append(welt->lookup(pos1), start_location == 0 ? 100 : 0); schedule->append(welt->lookup(pos2), start_location == 1 ? 100 : 0); schedule->set_current_stop( start_location ); schedule->finish_editing(); linehandle_t line=simlinemgmt.create_line(simline_t::truckline,this,schedule); delete schedule; // now create all vehicles as convois for(int i=0; i cannot do anything about this ... return; } vehicle_t* v = vehicle_builder_t::build(startpos, this, NULL, road_vehicle); convoi_t* cnv = new convoi_t(this); // give the new convoi name from first vehicle cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); cnv->set_line(line); cnv->start(); } } } void ai_goods_t::create_rail_transport_vehikel(const koord platz1, const koord platz2, int vehicle_count, int minimum_loading) { // now obeys timeline and use "more clever" scheme for vehicle selection schedule_t *schedule; if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... return; } convoi_t* cnv = new convoi_t(this); koord3d pos1= welt->lookup_kartenboden(platz1)->get_pos(); koord3d pos2 = welt->lookup_kartenboden(platz2)->get_pos(); // probably need to electrify the track? if( rail_engine->get_engine_type()==vehicle_desc_t::electric ) { // we need overhead wires const way_obj_desc_t *e = wayobj_t::get_overhead_line(track_wt, welt->get_timeline_year_month()); tool_build_wayobj_t tool; tool.set_default_param(e->get_name()); tool.init( this ); tool.work( this, welt->lookup_kartenboden(platz1)->get_pos() ); tool.work( this, welt->lookup_kartenboden(platz2)->get_pos() ); tool.exit( this ); } koord3d start_pos = welt->lookup_kartenboden(pos1.get_2d() + (abs(size1.x)>abs(size1.y) ? koord(size1.x,0) : koord(0,size1.y)))->get_pos(); vehicle_t* v = vehicle_builder_t::build( start_pos, this, NULL, rail_engine); // give the new convoi name from first vehicle cnv->set_name(rail_engine->get_name()); cnv->add_vehicle( v ); DBG_MESSAGE( "ai_goods_t::create_rail_transport_vehikel","for %i cars",vehicle_count); /* now we add cars: * check here also for introduction years */ for(int i = 0; i < vehicle_count; i++) { // use the vehicle we searched before vehicle_t* v = vehicle_builder_t::build(start_pos, this, NULL, rail_vehicle); cnv->add_vehicle( v ); } schedule = cnv->front()->generate_new_schedule(); schedule->set_current_stop( 0 ); schedule->append(welt->lookup(pos1), minimum_loading); schedule->append(welt->lookup(pos2), 0); schedule->finish_editing(); cnv->set_schedule(schedule); cnv->start(); } /** * build a station * Can fail even though check has been done before */ int ai_goods_t::baue_bahnhof(const koord* p, int vehicle_count) { int laenge = max(((rail_vehicle->get_length()*vehicle_count)+rail_engine->get_length()+CARUNITS_PER_TILE-1)/CARUNITS_PER_TILE,1); int baulaenge = 0; ribi_t::ribi ribi = welt->lookup_kartenboden(*p)->get_weg_ribi(track_wt); koord zv ( ribi ); koord t = *p; bool ok = true; for( int i=0; ilookup_kartenboden(t); ok &= (gr != NULL) && !gr->has_two_ways() && gr->get_weg_hang()==slope_t::flat; if(!ok) { break; } baulaenge ++; t += zv; } // too short if(baulaenge<=1) { return 0; } // to avoid broken stations, they will be always built next to an existing bool make_all_bahnhof=false; // find a freight train station const building_desc_t* desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, track_wt, welt->get_timeline_year_month(), haltestelle_t::WARE); if(desc==NULL) { // no freight station return 0; } koord pos; for( pos=t-zv; pos!=*p; pos-=zv ) { if( make_all_bahnhof || get_halt(pos+koord(-1,-1)).is_bound() || get_halt(pos+koord(-1, 1)).is_bound() || get_halt(pos+koord( 1,-1)).is_bound() || get_halt(pos+koord( 1, 1)).is_bound() ) { // start building, if next to an existing station make_all_bahnhof = true; call_general_tool( TOOL_BUILD_STATION, pos, desc->get_name() ); } INT_CHECK("simplay 753"); } // now add the other squares (going backwards) for( pos=*p; pos!=t; pos+=zv ) { if( !get_halt(pos).is_bound() ) { call_general_tool( TOOL_BUILD_STATION, pos, desc->get_name() ); } } laenge = min( vehicle_count, (baulaenge*CARUNITS_PER_TILE - rail_engine->get_length())/rail_vehicle->get_length() ); //DBG_MESSAGE("ai_goods_t::baue_bahnhof","Final station at (%i,%i) with %i tiles for %i cars",p->x,p->y,baulaenge,laenge); return laenge; } /** * built a very simple track with just the minimum effort * usually good enough, since it can use road crossings */ bool ai_goods_t::create_simple_rail_transport() { clean_marker(platz1,size1); clean_marker(platz2,size2); way_builder_t bauigel(this); bauigel.init_builder( way_builder_t::schiene|way_builder_t::bot_flag, rail_weg, tunnel_builder_t::get_tunnel_desc(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()) ); bauigel.set_keep_existing_ways(false); // for stations way_builder_t bauigel1(this); bauigel1.init_builder( way_builder_t::schiene|way_builder_t::bot_flag, rail_weg, tunnel_builder_t::get_tunnel_desc(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()) ); bauigel1.set_keep_existing_ways(false); way_builder_t bauigel2(this); bauigel2.init_builder( way_builder_t::schiene|way_builder_t::bot_flag, rail_weg, tunnel_builder_t::get_tunnel_desc(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()) ); bauigel2.set_keep_existing_ways(false); // first: make plain stations tiles as intended sint8 z1 = max( welt->get_water_hgt(platz1) + 1, welt->lookup_kartenboden(platz1)->get_hoehe() ); koord k = platz1; koord diff1( sgn(size1.x), sgn(size1.y) ); koord perpend( sgn(size1.y), sgn(size1.x) ); while(k!=size1+platz1) { climate c = welt->get_climate(k); if(!welt->flatten_tile( this, k, z1 )) { return false; } // ensure is land grund_t* bd = welt->lookup_kartenboden(k); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(k, bd->get_hoehe()-1); welt->access(k)->correct_water(); welt->set_climate(k, c, true); } k += diff1; } // make the second ones flat ... sint8 z2 = max( welt->get_water_hgt(platz2) + 1, welt->lookup_kartenboden(platz2)->get_hoehe() ); k = platz2; perpend = koord( sgn(size2.y), sgn(size2.x) ); koord diff2( sgn(size2.x), sgn(size2.y) ); while(k!=size2+platz2) { climate c = welt->get_climate(k); if(!welt->flatten_tile(this,k,z2)) { return false; } // ensure is land grund_t* bd = welt->lookup_kartenboden(k); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(k, bd->get_hoehe()-1); welt->access(k)->correct_water(); welt->set_climate(k, c, true); } k += diff2; } bauigel1.calc_route( koord3d(platz1,z1), koord3d(platz1+size1-diff1, z1)); bauigel2.calc_route( koord3d(platz2,z2), koord3d(platz2+size2-diff2, z2)); // build immediately, otherwise way-builder could get confused and connect way to a tile in the middle of the station bauigel1.build(); bauigel2.build(); vector_tpl starttiles, endtiles; // now calc the route starttiles.append(welt->lookup_kartenboden(platz1 + size1)->get_pos()); starttiles.append(welt->lookup_kartenboden(platz1 - diff1)->get_pos()); endtiles.append(welt->lookup_kartenboden(platz2 + size2)->get_pos()); endtiles.append(welt->lookup_kartenboden(platz2 - diff2)->get_pos()); bauigel.calc_route( starttiles, endtiles ); INT_CHECK("ai_goods 672"); // build only if enough cash available bool build_no_tf = (bauigel.get_count() > 4) && (bauigel.calc_costs() <= finance->get_netwealth()); // now try route with terraforming way_builder_t baumaulwurf(this); baumaulwurf.init_builder( way_builder_t::schiene|way_builder_t::bot_flag|way_builder_t::terraform_flag, rail_weg, tunnel_builder_t::get_tunnel_desc(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()) ); baumaulwurf.set_keep_existing_ways(false); baumaulwurf.calc_route( starttiles, endtiles ); // build with terraforming if shorter and enough money is available bool with_tf = (baumaulwurf.get_count() > 4) && (10*baumaulwurf.get_count() < 9*bauigel.get_count() || bauigel.get_count() <= 4); // too expensive ? with_tf = with_tf && (baumaulwurf.calc_costs() <= finance->get_netwealth()); // now build with or without terraforming if (with_tf) { baumaulwurf.build(); } else if (build_no_tf) { bauigel.build(); } // connect track to station if( with_tf || build_no_tf ) { DBG_MESSAGE("ai_goods_t::create_simple_rail_transport()","building simple track from %d,%d to %d,%d",platz1.x, platz1.y, platz2.x, platz2.y); // connect to track koord3d_vector_t const& r = with_tf ? baumaulwurf.get_route() : bauigel.get_route(); koord3d tile1 = r.front(); koord3d tile2 = r.back(); if (!starttiles.is_contained(tile1)) sim::swap(tile1, tile2); // No botflag, since we want to connect with the station. bauigel.init_builder( way_builder_t::schiene, rail_weg, tunnel_builder_t::get_tunnel_desc(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(track_wt,rail_engine->get_topspeed(),welt->get_timeline_year_month()) ); bauigel.calc_straight_route( koord3d(platz1,z1), tile1); bauigel.build(); bauigel.calc_straight_route( koord3d(platz2,z2), tile2); bauigel.build(); // If connection is built not at platz1/2, we must alter platz1/2, otherwise baue_bahnhof gets confused. if( tile1.get_2d() != platz1 + size1 ) { platz1 = platz1 + size1 - diff1; size1 = -size1; } if( tile2.get_2d() != platz2 + size2 ) { platz2 = platz2 + size2 - diff2; } return true; } else { // not ok: remove station ... k = platz1; while(k!=size1+platz1) { int cost = -welt->lookup_kartenboden(k)->weg_entfernen( track_wt, true ); book_construction_costs(this, cost, k, track_wt); k += diff1; } k = platz2; while(k!=size2+platz2) { int cost = -welt->lookup_kartenboden(k)->weg_entfernen( track_wt, true ); book_construction_costs(this, cost, k, track_wt); k += diff2; } } return false; } // the normal length procedure for freight AI void ai_goods_t::step() { // needed for schedule of stops ... player_t::step(); if(!active) { // I am off ... return; } // one route per month ... if( welt->get_steps() < next_construction_steps ) { return; } if( finance->get_netwealth() < (finance->get_starting_money()/8) ) { // nothing to do but to remove unneeded convois to gain some money state = CHECK_CONVOI; } switch(state) { case NR_INIT: state = NR_SAMMLE_ROUTEN; count = 0; built_update_headquarter(); if(root==NULL) { // find a tree root to complete weighted_vector_tpl start_fabs(20); for(fabrik_t* const fab : welt->get_fab_list() ) { // consumer and not completely overcrowded if( fab->get_desc()->is_consumer_only() && fab->get_status() != fabrik_t::STATUS_BAD ) { int missing = get_factory_tree_missing_count( fab ); if( missing>0 ) { start_fabs.append( fab, 100/(missing+1)+1 ); } } } if( !start_fabs.empty() ) { root = pick_any_weighted(start_fabs); } } // still nothing => we have to check convois ... if(root==NULL) { state = CHECK_CONVOI; } break; /* try to built a network: * last target also new target ... */ case NR_SAMMLE_ROUTEN: if( get_factory_tree_lowest_missing(root) ) { if( start->get_desc()->get_placement()!=factory_desc_t::Water || vehicle_search( water_wt, 0, 10, freight, false)!=NULL ) { DBG_MESSAGE("ai_goods_t::do_ki", "Consider route from %s (%i,%i) to %s (%i,%i)", start->get_name(), start->get_pos().x, start->get_pos().y, ziel->get_name(), ziel->get_pos().x, ziel->get_pos().y ); state = NR_BAUE_ROUTE1; } else { // add to impossible connections forbidden_connections.append( new fabconnection_t( start, ziel, freight ) ); state = CHECK_CONVOI; } } else { // did all I could do here ... root = NULL; state = CHECK_CONVOI; } break; // now we need so select the cheapest mean to get maximum profit case NR_BAUE_ROUTE1: { /* if we reached here, we decide to built a route; * the KI just chooses the way to run the operation at maximum profit (minimum loss). * The KI will built also a loosing route; this might be required by future versions to * be able to built a network! */ /* for the calculation we need: * a suitable car (and engine) * a suitable way */ uint32 dist = koord_distance( start->get_pos(), ziel->get_pos() ); // guess the "optimum" speed (usually a little too low) sint32 best_rail_speed = 80;// is ok enough for goods, was: min(60+freight->get_speed_bonus()*5, 140 ); sint32 best_road_speed = min(60+freight->get_speed_bonus()*5, 130 ); INT_CHECK("simplay 1265"); // is rail transport allowed? if(rail_transport) { // any rail car that transport this good (actually this weg_t the largest) rail_vehicle = vehicle_search( track_wt, 0, best_rail_speed, freight, true); } rail_engine = NULL; rail_weg = NULL; DBG_MESSAGE("do_ki()","rail vehicle %p",rail_vehicle); // is road transport allowed? if(road_transport) { // any road car that transport this good (actually this returns the largest) road_vehicle = vehicle_search( road_wt, 10, best_road_speed, freight, false); } road_weg = NULL; DBG_MESSAGE("do_ki()","road vehicle %p",road_vehicle); ship_vehicle = NULL; if(start->get_desc()->get_placement()==factory_desc_t::Water) { // largest ship available ship_vehicle = vehicle_search( water_wt, 0, 20, freight, false); } INT_CHECK("simplay 1265"); // properly calculate production const array_tpl& output = start->get_output(); uint start_ware=0; while( start_wareget_base_production(), ( start->get_base_production() * start->get_desc()->get_product(start_ware)->get_factor() )/256u - (uint32)(start->get_output()[start_ware].get_stat(1, FAB_GOODS_DELIVERED)) ); DBG_MESSAGE("do_ki()","check railway"); /* calculate number of cars for railroad */ count_rail=255; // no cars yet if( rail_vehicle!=NULL ) { // if our car is faster: well use slower speed to save money best_rail_speed = min(51, rail_vehicle->get_topspeed()); // for engine: guess number of cars count_rail = (prod*dist) / (rail_vehicle->get_capacity()*best_rail_speed)+1; // assume the engine weight 100 tons for power needed calculation int total_weight = count_rail*( rail_vehicle->get_capacity()*freight->get_weight_per_unit() + rail_vehicle->get_weight() ); // long power_needed = (long)(((best_rail_speed*best_rail_speed)/2500.0+1.0)*(100.0+count_rail*(rail_vehicle->get_weight()+rail_vehicle->get_capacity()*freight->get_weight_per_unit()*0.001))); rail_engine = vehicle_search( track_wt, total_weight/1000, best_rail_speed, NULL, wayobj_t::default_oberleitung!=NULL); if( rail_engine!=NULL ) { best_rail_speed = min(rail_engine->get_topspeed(),rail_vehicle->get_topspeed()); // find cheapest track with that speed (and no monorail/elevated/tram tracks, please) rail_weg = way_builder_t::weg_search( track_wt, best_rail_speed, welt->get_timeline_year_month(),type_flat ); if( rail_weg!=NULL ) { if( best_rail_speed>rail_weg->get_topspeed() ) { best_rail_speed = rail_weg->get_topspeed(); } // no train can have more than 15 cars count_rail = min( 22, (3*prod*dist) / (rail_vehicle->get_capacity()*best_rail_speed*2) ); // if engine too week, reduce number of cars if( count_rail*80*64>(int)(rail_engine->get_power()*rail_engine->get_gear()) ) { count_rail = rail_engine->get_power()*rail_engine->get_gear()/(80*64); } count_rail = ((count_rail+1)&0x0FE)+1; DBG_MESSAGE("ai_goods_t::do_ki()","Engine %s guess to need %d rail cars %s for route (%s)", rail_engine->get_name(), count_rail, rail_vehicle->get_name(), rail_weg->get_name() ); } } if( rail_engine==NULL || rail_weg==NULL ) { // no rail transport possible DBG_MESSAGE("ai_goods_t::do_ki()","No railway possible."); rail_vehicle = NULL; count_rail = 255; } } INT_CHECK("simplay 1265"); DBG_MESSAGE("do_ki()","check railway"); /* calculate number of cars for road; much easier */ count_road=255; // no cars yet if( road_vehicle!=NULL ) { best_road_speed = road_vehicle->get_topspeed(); // find cheapest road road_weg = way_builder_t::weg_search( road_wt, best_road_speed, welt->get_timeline_year_month(),type_flat ); if( road_weg!=NULL ) { if( best_road_speed>road_weg->get_topspeed() ) { best_road_speed = road_weg->get_topspeed(); } // minimum vehicle is 1, maximum vehicle is 48, more just result in congestion count_road = min( 254, (prod*dist) / (road_vehicle->get_capacity()*best_road_speed*2)+2 ); DBG_MESSAGE("ai_goods_t::do_ki()","guess to need %d road cars %s for route %s", count_road, road_vehicle->get_name(), road_weg->get_name() ); } else { // no roads there !?! DBG_MESSAGE("ai_goods_t::do_ki()","No roadway possible."); } } // find the cheapest transport ... // assume maximum cost int cost_rail=0x7FFFFFFF, cost_road=0x7FFFFFFF; int income_rail=0, income_road=0; // calculate cost for rail if( count_rail<255 ) { int freight_price = (freight->get_value()*rail_vehicle->get_capacity()*count_rail)/24*((8000+(best_rail_speed-80)*freight->get_speed_bonus())/1000); // calculated here, since the above number was based on production // only uneven number of cars bigger than 3 makes sense ... count_rail = max( 3, count_rail ); income_rail = (freight_price*best_rail_speed)/(2*dist+count_rail); cost_rail = rail_weg->get_maintenance() + (((count_rail+1)/2)*300)/dist + ((count_rail*rail_vehicle->get_running_cost()+rail_engine->get_running_cost())*best_rail_speed)/(2*dist+count_rail); DBG_MESSAGE("ai_goods_t::do_ki()","Netto credits per day for rail transport %.2f (income %.2f)",cost_rail/100.0, income_rail/100.0 ); cost_rail -= income_rail; } // and calculate cost for road if( count_road<255 ) { // for short distance: reduce number of cars // calculated here, since the above number was based on production count_road = clamp( (sint32)(dist*15)/best_road_speed, 2, count_road ); int freight_price = (freight->get_value()*road_vehicle->get_capacity()*count_road)/24*((8000+(best_road_speed-80)*freight->get_speed_bonus())/1000); cost_road = road_weg->get_maintenance() + 300/dist + (count_road*road_vehicle->get_running_cost()*best_road_speed)/(2*dist+5); income_road = (freight_price*best_road_speed)/(2*dist+5); DBG_MESSAGE("ai_goods_t::do_ki()","Netto credits per day and km for road transport %.2f (income %.2f)",cost_road/100.0, income_road/100.0 ); cost_road -= income_road; } // check location, if vehicles found if( min(count_road,count_rail)!=255 ) { // road or rail? int length = 1; if( cost_railget_length() + count_rail*rail_vehicle->get_length()+CARUNITS_PER_TILE-1)/CARUNITS_PER_TILE; if(suche_platz1_platz2(start, ziel, length)) { state = ship_vehicle ? NR_BAUE_WATER_ROUTE : NR_BAUE_SIMPLE_SCHIENEN_ROUTE; next_construction_steps += 10; } } // if state is still NR_BAUE_ROUTE1 then there are no suitable places if(state==NR_BAUE_ROUTE1 && (count_road != 255) && suche_platz1_platz2(start, ziel, 0)) { // rail was too expensive or not successful count_rail = 255; state = ship_vehicle ? NR_BAUE_WATER_ROUTE : NR_BAUE_STRASSEN_ROUTE; next_construction_steps += 10; } } // no success at all? if(state==NR_BAUE_ROUTE1) { // maybe this route is not builtable ... add to forbidden connections forbidden_connections.append( new fabconnection_t( start, ziel, freight ) ); ziel = NULL; // otherwise it may always try to built the same route! state = CHECK_CONVOI; } } break; // built a simple ship route case NR_BAUE_WATER_ROUTE: if(is_connected(start->get_pos().get_2d(), ziel->get_pos().get_2d(), freight)) { state = CHECK_CONVOI; } else { // properly calculate production const array_tpl& output = start->get_output(); uint start_ware=0; while( start_wareget_base_production(), (sint32)(start->get_base_production() * start->get_desc()->get_product(start_ware)->get_factor()) - (sint32)(start->get_output()[start_ware].get_stat(1, FAB_GOODS_DELIVERED)) ); if(prod<0) { // too much supplied last time?!? => retry state = CHECK_CONVOI; break; } // just remember the position, where the harbour will be built harbour=platz1; int ships_needed = 1 + (prod*koord_distance(harbour,start->get_pos().get_2d())) / (ship_vehicle->get_capacity()*max(20,ship_vehicle->get_topspeed())); if(create_ship_transport_vehicle(start,ships_needed)) { bool already_connected = false; const planquadrat_t* pl = welt->access(harbour); for( uint8 i=0; iget_boden_count(); i++ ) { if( pl->get_boden_bei(i)->get_halt()->get_fab_list().is_contained(ziel) ) { already_connected = true; } } if( already_connected ) { // so close, so we are already connected grund_t *gr = welt->lookup_kartenboden(platz2); if (gr) gr->obj_loesche_alle(this); state = (rail_vehicle && count_rail<255) ? NR_RAIL_SUCCESS : NR_ROAD_SUCCESS; } else { // else we need to built the second part of the route state = (rail_vehicle && count_rail<255) ? NR_BAUE_SIMPLE_SCHIENEN_ROUTE : NR_BAUE_STRASSEN_ROUTE; } } else { ship_vehicle = NULL; state = NR_BAUE_CLEAN_UP; } } break; // built a simple railroad case NR_BAUE_SIMPLE_SCHIENEN_ROUTE: if(is_connected(start->get_pos().get_2d(), ziel->get_pos().get_2d(), freight)) { state = ship_vehicle ? NR_BAUE_CLEAN_UP : CHECK_CONVOI; } else if(create_simple_rail_transport()) { sint16 org_count_rail = count_rail; count_rail = baue_bahnhof(&platz1, count_rail); if(count_rail>=3) { count_rail = baue_bahnhof(&platz2, count_rail); } if(count_rail>=3) { if(count_railget_topspeed()); // for engine: guess number of cars sint32 power_needed=(sint32)(((best_rail_speed*best_rail_speed)/2500.0+1.0)*(100.0+count_rail*( (rail_vehicle->get_weight()+rail_vehicle->get_capacity()*freight->get_weight_per_unit())*0.001 ))); const vehicle_desc_t *v=vehicle_search( track_wt, power_needed, best_rail_speed, NULL, false); if(v->get_running_cost()get_running_cost()) { rail_engine = v; } } create_rail_transport_vehikel( platz1, platz2, count_rail, 100 ); state = NR_RAIL_SUCCESS; } else { DBG_MESSAGE("ai_goods_t::step()","remove already constructed rail between %i,%i and %i,%i and try road",platz1.x,platz1.y,platz2.x,platz2.y); // no success: clean route char param[16]; sprintf( param, "%i", track_wt ); tool_wayremover_t tool; tool.set_default_param(param); tool.init( this ); tool.work( this, welt->lookup_kartenboden(platz1)->get_pos() ); tool.work( this, welt->lookup_kartenboden(platz2)->get_pos() ); tool.exit( this ); if( (count_road != 255) && suche_platz1_platz2(start, ziel, 0) ) { state = NR_BAUE_STRASSEN_ROUTE; } else { state = NR_BAUE_CLEAN_UP; } } } else { if( (count_road != 255) && suche_platz1_platz2(start, ziel, 0) ) { state = NR_BAUE_STRASSEN_ROUTE; } else { state = NR_BAUE_CLEAN_UP; } } break; // built a simple road (no bridges, no tunnels) case NR_BAUE_STRASSEN_ROUTE: if(is_connected(start->get_pos().get_2d(), ziel->get_pos().get_2d(), freight)) { state = ship_vehicle ? NR_BAUE_CLEAN_UP : CHECK_CONVOI; } else if(create_simple_road_transport(platz1,size1,platz2,size2,road_weg)) { create_road_transport_vehikel(start, count_road ); state = NR_ROAD_SUCCESS; } else { state = NR_BAUE_CLEAN_UP; } break; // remove marker etc. case NR_BAUE_CLEAN_UP: { if(start!=NULL && ziel!=NULL) { forbidden_connections.append( new fabconnection_t( start, ziel, freight ) ); } if(ship_vehicle) { // only here, if we could built ships but no connection halthandle_t start_halt = get_halt(harbour); if( start_halt.is_bound() && (start_halt->get_station_type()&haltestelle_t::dock)!=0 ) { // delete all ships on this line vector_tpl lines; simlinemgmt.get_lines( simline_t::shipline, &lines ); if(!lines.empty()) { linehandle_t line = lines.back(); schedule_t *schedule=line->get_schedule(); if(schedule->get_count()>1 && haltestelle_t::get_halt(schedule->entries[0].pos,this)==start_halt) { while(line->count_convoys()>0) { convoihandle_t cnv = line->get_convoy(0); cnv->self_destruct(); if(cnv.is_bound()) { cnv->step(); } } simlinemgmt.delete_line( line ); } } } // delete harbour call_general_tool( TOOL_REMOVER, harbour, NULL ); } harbour = koord::invalid; // otherwise it may always try to built the same route! ziel = NULL; // schilder aufraeumen clean_marker(platz1,size1); clean_marker(platz2,size2); state = CHECK_CONVOI; break; } // successful rail construction case NR_RAIL_SUCCESS: { // tell the player cbuffer_t buf; const koord3d& spos = start->get_pos(); const koord3d& zpos = ziel->get_pos(); buf.printf( translator::translate("%s\nopened a new railway\nbetween %s\nat (%i,%i) and\n%s at (%i,%i)."), get_name(), translator::translate(start->get_name()), spos.x, spos.y, translator::translate(ziel->get_name()), zpos.x, zpos.y); welt->get_message()->add_message(buf, spos, message_t::ai, PLAYER_FLAG|player_nr, rail_engine->get_base_image()); harbour = koord::invalid; state = CHECK_CONVOI; } break; // successful rail construction case NR_ROAD_SUCCESS: { // tell the player cbuffer_t buf; const koord3d& spos = start->get_pos(); const koord3d& zpos = ziel->get_pos(); buf.printf( translator::translate("%s\nnow operates\n%i trucks between\n%s at (%i,%i)\nand %s at (%i,%i)."), get_name(), count_road, translator::translate(start->get_name()), spos.x, spos.y, translator::translate(ziel->get_name()), zpos.x, zpos.y); welt->get_message()->add_message(buf, spos, message_t::ai, PLAYER_FLAG|player_nr, road_vehicle->get_base_image()); harbour = koord::invalid; state = CHECK_CONVOI; } break; // remove stuck vehicles (only from roads!) case CHECK_CONVOI: { next_construction_steps = welt->get_steps() + ((1+finance->get_account_overdrawn())>0)*simrand( ai_t::construction_speed ) + 25; for (size_t i = welt->convoys().get_count(); i-- != 0;) { convoihandle_t const cnv = welt->convoys()[i]; if(!cnv.is_bound() || cnv->get_owner()!=this) { continue; } if (cnv->front()->get_waytype() == water_wt) { // ships will be only deleted together with the connecting convoi continue; } sint64 gewinn = 0; for( int j=0; j<12; j++ ) { gewinn += cnv->get_finance_history( j, convoi_t::CONVOI_PROFIT ); } // apparently we got the totally wrong vehicle here ... // (but we will delete it only, if we need, because it may be needed for a chain) bool delete_this = (finance->get_account_overdrawn() > 0) && (gewinn < -cnv->calc_restwert()); // check for empty vehicles (likely stuck) that are making no plus and remove them ... // take care, that the vehicle is old enough ... if (!delete_this && (welt->get_current_month() - cnv->front()->get_purchase_time()) > 6 && gewinn <= 0) { sint64 goods=0; // no goods for six months? for( int i=0; i<6; i ++) { goods += cnv->get_finance_history( i, convoi_t::CONVOI_TRANSPORTED_GOODS ); } delete_this = (goods==0); } // well, then delete this (likely stuck somewhere) or insanely unneeded if(delete_this) { waytype_t const wt = cnv->front()->get_desc()->get_waytype(); linehandle_t line = cnv->get_line(); DBG_MESSAGE("ai_goods_t::do_ki()","%s retires convoi %s!", get_name(), cnv->get_name()); koord3d start_pos, end_pos; schedule_t *schedule = cnv->get_schedule(); if(schedule && schedule->get_count()>1) { start_pos = schedule->entries[0].pos; end_pos = schedule->entries[1].pos; } cnv->self_destruct(); if(cnv.is_bound()) { cnv->step(); // to really get rid of it } // last vehicle on that connection (no line => railroad) if( !line.is_bound() || line->count_convoys()==0 ) { // check if a connection boat must be removed halthandle_t start_halt = haltestelle_t::get_halt(start_pos,this); if(start_halt.is_bound() && (start_halt->get_station_type()&haltestelle_t::dock)!=0) { // delete all ships on this line vector_tpl lines; koord water_stop = koord::invalid; simlinemgmt.get_lines( simline_t::shipline, &lines ); for(linehandle_t const line : lines) { schedule_t *schedule=line->get_schedule(); if(schedule->get_count()>1 && haltestelle_t::get_halt(schedule->entries[0].pos,this)==start_halt) { water_stop = koord( (start_pos.x+schedule->entries[0].pos.x)/2, (start_pos.y+schedule->entries[0].pos.y)/2 ); while(line->count_convoys()>0) { convoihandle_t cnv = line->get_convoy(0); cnv->self_destruct(); if(cnv.is_bound()) { cnv->step(); } } simlinemgmt.delete_line( line ); } } // delete harbour call_general_tool( TOOL_REMOVER, water_stop, NULL ); } } if(wt==track_wt) { char param[16]; sprintf( param, "%i", track_wt ); tool_wayremover_t tool; tool.set_default_param(param); tool.init( this ); tool.work( this, start_pos ); tool.work( this, end_pos ); tool.exit( this ); } else { // last convoi => remove completely< if(line.is_bound() && line->count_convoys()==0) { simlinemgmt.delete_line( line ); char param[16]; sprintf( param, "%i", wt ); tool_wayremover_t tool; tool.set_default_param(param); tool.init( this ); tool.work( this, start_pos ); if(tool.work( this, end_pos )!=NULL) { // cannot remove all => likely some other convois there too // remove loading bays and road on start and end, if we cannot remove the whole way tool.work( this, start_pos ); tool.work( this, start_pos ); tool.work( this, end_pos ); tool.work( this, end_pos ); } tool.exit( this ); } } break; } } state = NR_INIT; } break; default: dbg->warning("ai_goods_t::step()","Illegal state!", state ); state = NR_INIT; } } void ai_goods_t::rdwr(loadsave_t *file) { if( file->is_version_less(102, 2) ) { // due to an error the player was never saved correctly player_t::rdwr(file); return; } xml_tag_t t( file, "ai_goods_t" ); ai_t::rdwr(file); // then check, if we have to do something or the game is too old ... if(file->is_version_less(101, 0)) { // ignore saving, reinit on loading if( file->is_loading() ) { state = NR_INIT; road_vehicle = NULL; road_weg = NULL; next_construction_steps = welt->get_steps()+simrand(400); root = start = ziel = NULL; } return; } // now save current state ... file->rdwr_enum(state); platz1.rdwr( file ); size1.rdwr( file ); platz2.rdwr( file ); size2.rdwr( file ); file->rdwr_long(count_rail); file->rdwr_long(count_road); file->rdwr_long(count); if( file->is_version_less(111, 1) ) { file->rdwr_bool(road_transport); file->rdwr_bool(rail_transport); file->rdwr_bool(ship_transport); air_transport = false; } if(file->is_saving()) { // save current pointers sint32 delta_steps = next_construction_steps-welt->get_steps(); file->rdwr_long(delta_steps); koord3d k3d = root ? root->get_pos() : koord3d::invalid; k3d.rdwr(file); k3d = start ? start->get_pos() : koord3d::invalid; k3d.rdwr(file); k3d = ziel ? ziel->get_pos() : koord3d::invalid; k3d.rdwr(file); // what freight? const char *s = freight ? freight->get_name() : NULL; file->rdwr_str( s ); // vehicles desc s = rail_engine ? rail_engine->get_name() : NULL; file->rdwr_str( s ); s = rail_vehicle ? rail_vehicle->get_name() : NULL; file->rdwr_str( s ); s = road_vehicle ? road_vehicle->get_name() : NULL; file->rdwr_str( s ); s = ship_vehicle ? ship_vehicle->get_name() : NULL; file->rdwr_str( s ); // ways s = rail_weg ? rail_weg->get_name() : NULL; file->rdwr_str( s ); s = road_weg ? road_weg->get_name() : NULL; file->rdwr_str( s ); } else { // since steps in loaded game == 0 file->rdwr_long(next_construction_steps); // reinit current pointers koord3d k3d; k3d.rdwr(file); root = fabrik_t::get_fab( k3d.get_2d() ); k3d.rdwr(file); start = fabrik_t::get_fab( k3d.get_2d() ); k3d.rdwr(file); ziel = fabrik_t::get_fab( k3d.get_2d() ); // freight? const char *temp=NULL; file->rdwr_str( temp ); freight = temp ? goods_manager_t::get_info(temp) : NULL; // vehicles file->rdwr_str( temp ); rail_engine = temp ? vehicle_builder_t::get_info(temp) : NULL; file->rdwr_str( temp ); rail_vehicle = temp ? vehicle_builder_t::get_info(temp) : NULL; file->rdwr_str( temp ); road_vehicle = temp ? vehicle_builder_t::get_info(temp) : NULL; file->rdwr_str( temp ); ship_vehicle = temp ? vehicle_builder_t::get_info(temp) : NULL; // ways file->rdwr_str( temp ); rail_weg = temp ? way_builder_t::get_desc(temp,0) : NULL; file->rdwr_str( temp ); road_weg = temp ? way_builder_t::get_desc(temp,0) : NULL; } // finally: forbidden connection list sint32 cnt = forbidden_connections.get_count(); file->rdwr_long(cnt); if(file->is_saving()) { for(fabconnection_t* const fc : forbidden_connections) { fc->rdwr(file); } } else { forbidden_connections.clear(); while( cnt-->0 ) { fabconnection_t *fc = new fabconnection_t(0,0,0); fc->rdwr(file); // Don't add if fab or ware no longer in the game. if( fc->fab1 && fc->fab2 && fc->ware ) { forbidden_connections.append(fc); } else { delete fc; } } } // save harbour position if( file->is_version_atleast(110, 1) ) { harbour.rdwr(file); } } bool ai_goods_t::is_forbidden( fabrik_t *fab1, fabrik_t *fab2, const goods_desc_t *w ) const { fabconnection_t fc(fab1, fab2, w); for(fabconnection_t* const test_fc : forbidden_connections) { if (fc == (*test_fc)) { return true; } } return false; } void ai_goods_t::fabconnection_t::rdwr(loadsave_t *file) { koord3d k3d; if(file->is_saving()) { k3d = fab1->get_pos(); k3d.rdwr(file); k3d = fab2->get_pos(); k3d.rdwr(file); const char *s = ware->get_name(); file->rdwr_str( s ); } else { koord3d pos1, pos2; pos1.rdwr(file); fab1 = fabrik_t::get_fab( pos1.get_2d() ); pos2.rdwr(file); fab2 = fabrik_t::get_fab( pos2.get_2d() ); const char *temp=NULL; file->rdwr_str( temp ); if (!temp) { dbg->fatal("ai_goods_t::fabconnection_t::rdwr", "No name for freight connection between %s and %s", pos1.get_fullstr(), pos2.get_fullstr()); } ware = goods_manager_t::get_info(temp); } } /** * Dealing with stuck or lost vehicles: * - delete lost ones * - ignore stuck ones */ void ai_goods_t::report_vehicle_problem(convoihandle_t cnv,const koord3d ziel) { if( cnv->get_state() == convoi_t::NO_ROUTE && this!=welt->get_active_player() ) { DBG_MESSAGE("ai_passenger_t::report_vehicle_problem","Vehicle %s can't find a route to (%i,%i)!", cnv->get_name(),ziel.x,ziel.y); cnv->self_destruct(); return; } player_t::report_vehicle_problem( cnv, ziel ); } /** * Tells the player that a fabrik_t is going to be deleted. * It could also tell, that a fab has been created, but by now the factory_builder_t does not. */ void ai_goods_t::notify_factory(notification_factory_t flag, const fabrik_t* fab) { switch(flag) { // factory is going to be deleted case notify_delete: if (start==fab || ziel==fab || root==fab) { root = NULL; start = NULL; ziel = NULL; // set new state if (state == NR_SAMMLE_ROUTEN || state == NR_BAUE_ROUTE1) { state = NR_INIT; } else if (state == NR_BAUE_SIMPLE_SCHIENEN_ROUTE || state == NR_BAUE_STRASSEN_ROUTE || state == NR_BAUE_WATER_ROUTE) { state = NR_BAUE_CLEAN_UP; } else if (state == NR_RAIL_SUCCESS || state == NR_ROAD_SUCCESS || state == NR_WATER_SUCCESS) { state = CHECK_CONVOI; } for( slist_tpl::iterator i=forbidden_connections.begin(); i!=forbidden_connections.end(); ) { fabconnection_t *fc = *i; if (fc->fab1 == fab || fc->fab2 == fab) { i = forbidden_connections.erase(i); delete fc; } else { ++i; } } } break; default: ; } } simutrans-124.3/src/simutrans/player/ai_goods.h000066400000000000000000000071741474050137200216310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PLAYER_AI_GOODS_H #define PLAYER_AI_GOODS_H #include "ai.h" /// Simple goods transport AI class ai_goods_t : public ai_t { private: enum state { NR_INIT, NR_SAMMLE_ROUTEN, NR_BAUE_ROUTE1, NR_BAUE_SIMPLE_SCHIENEN_ROUTE, NR_BAUE_STRASSEN_ROUTE, NR_BAUE_WATER_ROUTE, NR_BAUE_CLEAN_UP, NR_RAIL_SUCCESS, NR_ROAD_SUCCESS, NR_WATER_SUCCESS, CHECK_CONVOI }; // vars for the KI state state; /** * test more than one supplier and more than one good * * save last factory for building next supplier/consumer * */ fabrik_t *root; // actual route to be built between those fabrik_t *start; fabrik_t *ziel; const goods_desc_t *freight; // we will use this vehicle! const vehicle_desc_t *rail_vehicle; const vehicle_desc_t *rail_engine; const vehicle_desc_t *road_vehicle; const vehicle_desc_t *ship_vehicle; // and the convoi will run on this track: const way_desc_t *rail_weg; const way_desc_t *road_weg; sint32 count_rail; sint32 count_road; // multi-purpose counter sint32 count; // time to wait before next construction sint32 next_construction_steps; /* start and end stop position (and their size) */ koord platz1, size1, platz2, size2, harbour; // KI helper class class fabconnection_t{ friend class ai_goods_t; fabrik_t *fab1; fabrik_t *fab2; // koord1 must be always "smaller" than koord2 const goods_desc_t *ware; public: fabconnection_t( fabrik_t *k1=0, fabrik_t *k2=0, const goods_desc_t *w=0 ) : fab1(k1), fab2(k2), ware(w) {} void rdwr( loadsave_t *file ); bool operator != (const fabconnection_t & k) const { return fab1 != k.fab1 || fab2 != k.fab2 || ware != k.ware; } bool operator == (const fabconnection_t & k) const { return fab1 == k.fab1 && fab2 == k.fab2 && ware == k.ware; } // const bool operator < (const fabconnection_t & k) { return (abs(fab1.x)+abs(fab1.y)) - (abs(k.fab1.x)+abs(k.fab1.y)) < 0; } }; slist_tpl forbidden_connections; // return true, if this a route to avoid (i.e. we did a construction without success here ...) bool is_forbidden( fabrik_t *fab1, fabrik_t *fab2, const goods_desc_t *w ) const; /* recursive lookup of a factory tree: * sets start and destination to the next needed supplier * start always with the first branch, if there are more goods */ bool get_factory_tree_lowest_missing( fabrik_t *fab ); /* recursive lookup of a tree and how many factories must be at least connected * returns -1, if this tree is can't be completed */ int get_factory_tree_missing_count( fabrik_t *fab ); bool suche_platz1_platz2(fabrik_t *qfab, fabrik_t *zfab, int length); int baue_bahnhof(const koord* p, int vehicle_count); bool create_simple_rail_transport(); // create way and stops for these routes bool create_ship_transport_vehicle(fabrik_t *qfab, int vehicle_count); void create_road_transport_vehikel(fabrik_t *qfab, int vehicle_count); void create_rail_transport_vehikel(const koord pos1,const koord pos2, int vehicle_count, int minimum_loading); public: ai_goods_t(uint8 nr); // this type of AIs identifier uint8 get_ai_id() const OVERRIDE { return AI_GOODS; } // cannot do airfreight at the moment void set_air_transport( bool ) OVERRIDE { air_transport = false; } void rdwr(loadsave_t *file) OVERRIDE; void report_vehicle_problem(convoihandle_t cnv,const koord3d ziel) OVERRIDE; bool set_active( bool b ) OVERRIDE; void step() OVERRIDE; void new_year() OVERRIDE; void rotate90( const sint16 y_size ) OVERRIDE; void notify_factory(notification_factory_t flag, const fabrik_t*) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/player/ai_passenger.cc000066400000000000000000001521071474050137200226400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../world/simcity.h" #include "../simconvoi.h" #include "../simfab.h" #include "../simhalt.h" #include "../simline.h" #include "../tool/simmenu.h" #include "../simmesg.h" #include "../world/simworld.h" #include "../builder/brueckenbauer.h" #include "../builder/hausbauer.h" #include "../builder/tunnelbauer.h" #include "../builder/vehikelbauer.h" #include "../builder/wegbauer.h" #include "../dataobj/schedule.h" #include "../dataobj/loadsave.h" #include "../dataobj/marker.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../vehicle/vehicle.h" #include "ai_passenger.h" #include "finance.h" ai_passenger_t::ai_passenger_t(uint8 nr) : ai_t( nr ) { state = NR_INIT; road_vehicle = NULL; road_weg = NULL; next_construction_steps = welt->get_steps() + 50; road_transport = true; rail_transport = false; air_transport = true; ship_transport = true; start_stadt = end_stadt = NULL; ziel = NULL; end_attraction = NULL; } /** * Activates/deactivates a player */ bool ai_passenger_t::set_active(bool new_state) { // only activate, when there are buses available! if( new_state ) { new_state = NULL!=vehicle_search( road_wt, 50, 80, goods_manager_t::passengers, false); } return player_t::set_active( new_state ); } /** return the hub of a city (always the very first stop) or zero */ halthandle_t ai_passenger_t::get_our_hub( const stadt_t *s ) const { for(halthandle_t const halt : haltestelle_t::get_alle_haltestellen()) { if (halt->get_owner() == sim::up_cast(this)) { if( halt->get_pax_enabled() && (halt->get_station_type()&haltestelle_t::busstop)!=0 ) { koord h=halt->get_basis_pos(); if(h.x>=s->get_linksoben().x && h.y>=s->get_linksoben().y && h.x<=s->get_rechtsunten().x && h.y<=s->get_rechtsunten().y ) { return halt; } } } } return halthandle_t(); } koord ai_passenger_t::find_area_for_hub( const koord lo, const koord ru, const koord basis ) const { // no found found koord best_pos = koord::invalid; // "shortest" distance int dist = 999; for( sint16 x=lo.x; x<=ru.x; x++ ) { for( sint16 y=lo.y; y<=ru.y; y++ ) { const koord trypos(x,y); const grund_t * gr = welt->lookup_kartenboden(trypos); if(gr) { // flat, solid if( gr->get_typ()==grund_t::boden && gr->get_grund_hang()==slope_t::flat ) { const obj_t* obj = gr->obj_bei(0); int test_dist = koord_distance( trypos, basis ); if (!obj || !obj->get_owner() || obj->get_owner() == sim::up_cast(this)) { if( gr->is_halt() && check_owner( gr->get_halt()->get_owner(), this ) && gr->hat_weg(road_wt) ) { // ok, one halt belongs already to us ... (should not really happen!) but might be a public stop return trypos; } else if( test_disthat_weg(road_wt) && !gr->is_halt() ) { ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(road_wt); if( ribi_t::is_straight(ribi) || ribi_t::is_single(ribi) ) { best_pos = trypos; dist = test_dist; } } else if( test_dist+2ist_natur() ) { // also ok for a stop, but second choice // so we gave it a malus of 2 best_pos = trypos; dist = test_dist+2; } } } } } } DBG_MESSAGE("ai_passenger_t::find_area_for_hub()","suggest hub at (%i,%i)",best_pos.x,best_pos.y); return best_pos; } /** * tries to built a hub near the koordinate */ koord ai_passenger_t::find_place_for_hub( const stadt_t *s ) const { halthandle_t h = get_our_hub( s ); if(h.is_bound()) { return h->get_basis_pos(); } return find_area_for_hub( s->get_linksoben(), s->get_rechtsunten(), s->get_pos() ); } koord ai_passenger_t::find_harbour_pos(karte_t* welt, const stadt_t *s ) { koord bestpos = koord::invalid, k; sint32 bestdist = 999999; // try to find an airport place as close to the city as possible for( k.y=max(6,s->get_linksoben().y-10); k.y<=min(welt->get_size().y-3-6,s->get_rechtsunten().y+10); k.y++ ) { for( k.x=max(6,s->get_linksoben().x-25); k.x<=min(welt->get_size().x-3-6,s->get_rechtsunten().x+10); k.x++ ) { sint32 testdist = koord_distance( k, s->get_pos() ); if( testdistget_linksoben().x || k.y+2get_linksoben().y || k.x>=s->get_rechtsunten().x || k.y>=s->get_rechtsunten().y ) { // malus for out of town testdist += 5; } if( testdistlookup_kartenboden(k); slope_t::type hang = gr->get_grund_hang(); if( gr->ist_natur() && gr->get_hoehe() == welt->get_water_hgt(k) && slope_t::is_way(hang) && welt->is_water( k - koord(hang), koord(hang) * 4 + koord(1, 1) ) ) { // can built busstop here? koord bushalt = k+koord(hang); gr = welt->lookup_kartenboden(bushalt); if(gr && gr->ist_natur()) { bestpos = k; bestdist = testdist; } } } } } } return bestpos; } bool ai_passenger_t::create_water_transport_vehicle(const stadt_t* start_stadt, const koord target_pos) { const vehicle_desc_t *v_desc = vehicle_search(water_wt, 10, 40, goods_manager_t::passengers, false); if(v_desc==NULL ) { // no ship there return false; } if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... return false; } stadt_t *end_stadt = NULL; grund_t *ziel = welt->lookup_kartenboden(target_pos); gebaeude_t *gb = ziel->find(); if(gb && gb->is_townhall()) { end_stadt = gb->get_stadt(); } else if(!ziel->is_halt() || !ziel->is_water()) { // not townhall, not factory => we will not built this line for attractions! return false; } halthandle_t start_hub = get_our_hub( start_stadt ); halthandle_t start_connect_hub; koord start_harbour = koord::invalid; if(start_hub.is_bound()) { if( (start_hub->get_station_type()&haltestelle_t::dock)==0 ) { start_connect_hub = start_hub; start_hub = halthandle_t(); // is there already one harbour next to this one? for(haltestelle_t::connection_t const& i : start_connect_hub->get_pax_connections()) { halthandle_t const h = i.halt; if( h->get_station_type()&haltestelle_t::dock ) { start_hub = h; break; } } } else { start_harbour = start_hub->get_basis_pos(); } } // find an dock place if(!start_hub.is_bound()) { start_harbour = find_harbour_pos( welt, start_stadt ); } if(start_harbour==koord::invalid) { // sorry, no suitable place return false; } // same for end halthandle_t end_hub = end_stadt ? get_our_hub( end_stadt ) : ziel->get_halt(); halthandle_t end_connect_hub; koord end_harbour = koord::invalid; if(end_hub.is_bound()) { if( (end_hub->get_station_type()&haltestelle_t::dock)==0 ) { end_connect_hub = end_hub; end_hub = halthandle_t(); // is there already one harbour next to this one? for(haltestelle_t::connection_t const& i : end_connect_hub->get_pax_connections()) { halthandle_t const h = i.halt; if( h->get_station_type()&haltestelle_t::dock ) { start_hub = h; break; } } } else { end_harbour = end_hub->get_basis_pos(); } } if(!end_hub.is_bound() && end_stadt) { // find an dock place end_harbour = find_harbour_pos( welt, end_stadt ); } if(end_harbour==koord::invalid) { // sorry, no suitable place return false; } const koord start_dx(welt->lookup_kartenboden(start_harbour)->get_grund_hang()); const koord end_dx(welt->lookup_kartenboden(end_harbour)->get_grund_hang()); // now we must check, if these two seas are connected { // we use the free own vehicle_desc_t vehicle_desc_t remover_desc( water_wt, 500, vehicle_desc_t::diesel ); vehicle_t* test_driver = vehicle_builder_t::build( koord3d( start_harbour - start_dx, welt->get_water_hgt( start_harbour - start_dx ) ), this, NULL, &remover_desc ); test_driver->set_flag( obj_t::not_on_map ); route_t verbindung; bool connected = verbindung.calc_route( welt, koord3d( start_harbour - start_dx, welt->get_water_hgt( start_harbour - start_dx ) ), koord3d( end_harbour - end_dx, welt->get_water_hgt( end_harbour - end_dx ) ), test_driver, 0, 0 ); delete test_driver; if(!connected) { return false; } } // build the harbour if necessary if(!start_hub.is_bound()) { koord bushalt = start_harbour+start_dx; const koord town_road = find_place_for_hub( start_stadt ); // first: built street to harbour if(town_road!=bushalt) { way_builder_t bauigel(this); // no bridges => otherwise first tile might be bridge start ... bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), NULL ); bauigel.set_keep_existing_faster_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(10000); bauigel.calc_route( welt->lookup_kartenboden(bushalt)->get_pos(), welt->lookup_kartenboden(town_road)->get_pos() ); if(bauigel.get_count()-1 <= 1) { return false; } bauigel.build(); } } if(!end_hub.is_bound()) { koord bushalt = end_harbour+end_dx; const koord town_road = find_place_for_hub( end_stadt ); // first: built street to harbour if(town_road!=bushalt) { way_builder_t bauigel(this); // no bridges => otherwise first tile might be bridge start ... bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), NULL ); bauigel.set_keep_existing_faster_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(10000); bauigel.calc_route( welt->lookup_kartenboden(bushalt)->get_pos(), welt->lookup_kartenboden(town_road)->get_pos() ); if(bauigel.get_count()-1 <= 1) { return false; } bauigel.build(); } } // now built the stops ... (since the roads were ok!) if(!start_hub.is_bound()) { /* first we must built the bus stop, since this will be the default stop for all our buses * we want to keep the name of a dock, thus we will create it beforehand */ koord bushalt = start_harbour+start_dx; const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX ); // now built the bus stop if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) { return false; } // and change name to dock ... grund_t *gr = welt->lookup_kartenboden(bushalt); halthandle_t halt = gr ? gr->get_halt() : halthandle_t(); if (halt.is_bound()) { // it should be, but avoid crashes char* const name = halt->create_name(bushalt, "Dock"); halt->set_name( name ); free(name); } // finally built the dock const building_desc_t* dock_desc = hausbauer_t::get_random_station(building_desc_t::dock, water_wt, welt->get_timeline_year_month(), 0); welt->lookup_kartenboden(start_harbour)->obj_loesche_alle(this); call_general_tool( TOOL_BUILD_STATION, start_harbour, dock_desc->get_name() ); grund_t *harbour_gr = welt->lookup_kartenboden(start_harbour); start_hub = harbour_gr ? harbour_gr->get_halt() : halthandle_t(); // eventually we must built a hub in the next town start_connect_hub = get_our_hub( start_stadt ); if(!start_connect_hub.is_bound()) { koord sch = find_place_for_hub( start_stadt ); call_general_tool( TOOL_BUILD_STATION, sch, busstop_desc->get_name() ); start_connect_hub = get_our_hub( start_stadt ); assert( start_connect_hub.is_bound() ); } } if(!end_hub.is_bound()) { /* again we must built the bus stop first, since this will be the default stop for all our buses * we want to keep the name of a dock, thus we will create it beforehand */ koord bushalt = end_harbour+end_dx; const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX ); // now built the bus stop if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) { return false; } // and change name to dock ... grund_t *gr = welt->lookup_kartenboden(bushalt); halthandle_t halt = gr ? gr->get_halt() : halthandle_t(); if (halt.is_bound()) { // it should be, but avoid crashes char* const name = halt->create_name(bushalt, "Dock"); halt->set_name( name ); free(name); } // finally built the dock const building_desc_t* dock_desc = hausbauer_t::get_random_station(building_desc_t::dock, water_wt, welt->get_timeline_year_month(), 0 ); welt->lookup_kartenboden(end_harbour)->obj_loesche_alle(this); call_general_tool( TOOL_BUILD_STATION, end_harbour, dock_desc->get_name() ); grund_t *harbour_gr = welt->lookup_kartenboden(end_harbour); end_hub = harbour_gr ? harbour_gr->get_halt() : halthandle_t(); // eventually we must built a hub in the next town end_connect_hub = get_our_hub( end_stadt ); if(!end_connect_hub.is_bound()) { koord ech = find_place_for_hub( end_stadt ); call_general_tool( TOOL_BUILD_STATION, ech, busstop_desc->get_name() ); end_connect_hub = get_our_hub( end_stadt ); assert( end_connect_hub.is_bound() ); } } uint16 const cov = welt->get_settings().get_station_coverage(); // now we have harbour => find start position for ships koord pos1 = start_harbour-start_dx; koord start_pos = pos1; for (int y = pos1.y - cov; y <= pos1.y + cov; ++y) { for (int x = pos1.x - cov; x <= pos1.x + cov; ++x) { koord p(x,y); const planquadrat_t *plan = welt->access(p); if(plan) { grund_t *gr = plan->get_kartenboden(); if( gr->is_water() && !gr->get_halt().is_bound() ) { if(plan->get_haltlist_count()>=1 && plan->get_haltlist()[0]==start_hub && koord_distance(start_pos,end_harbour)>koord_distance(p,end_harbour)) { start_pos = p; } } } } } // now we have harbour => find start position for ships pos1 = end_harbour-end_dx; koord end_pos = pos1; for (int y = pos1.y - cov; y <= pos1.y + cov; ++y) { for (int x = pos1.x - cov; x <= pos1.x + cov; ++x) { koord p(x,y); const planquadrat_t *plan = welt->access(p); if(plan) { grund_t *gr = plan->get_kartenboden(); if( gr->is_water() && !gr->get_halt().is_bound() ) { if(plan->get_haltlist_count()>=1 && plan->get_haltlist()[0]==end_hub && koord_distance(end_pos,start_harbour)>koord_distance(p,start_harbour)) { end_pos = p; } } } } } // since 86.01 we use lines for vehicles ... schedule_t *schedule=new ship_schedule_t(); schedule->append( welt->lookup_kartenboden(start_pos), 0, 0 ); schedule->append( welt->lookup_kartenboden(end_pos), 90, 0 ); schedule->set_current_stop( 1 ); schedule->finish_editing(); linehandle_t line=simlinemgmt.create_line(simline_t::shipline,this,schedule); delete schedule; // now create one ship vehicle_t* v = vehicle_builder_t::build( koord3d( start_pos, welt->get_water_hgt( start_pos ) ), this, NULL, v_desc ); convoi_t* cnv = new convoi_t(this); cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); cnv->set_line(line); cnv->start(); // eventually build a shuttle bus ... if(start_connect_hub.is_bound() && start_connect_hub!=start_hub) { koord stops[2] = { start_harbour+start_dx, start_connect_hub->get_basis_pos() }; create_bus_transport_vehicle( stops[1], 1, stops, 2, false ); } // eventually build a airport shuttle bus ... if(end_connect_hub.is_bound() && end_connect_hub!=end_hub) { koord stops[2] = { end_harbour+end_dx, end_connect_hub->get_basis_pos() }; create_bus_transport_vehicle( stops[1], 1, stops, 2, false ); } return true; } halthandle_t ai_passenger_t::build_airport(const stadt_t* city, koord pos, int rotation) { // not too close to border? if(pos.x<6 || pos.y<6 || pos.x+3+6>=welt->get_size().x || pos.y+3+6>=welt->get_size().y ) { return halthandle_t(); } // ok, not prematurely doomed // can we built airports at all? const way_desc_t *taxi_desc = way_builder_t::weg_search( air_wt, 25, welt->get_timeline_year_month(), type_flat ); const way_desc_t *runway_desc = way_builder_t::weg_search( air_wt, 250, welt->get_timeline_year_month(), type_runway ); if(taxi_desc==NULL || runway_desc==NULL) { return halthandle_t(); } // first, check if at least one tile is within city limits const koord lo = city->get_linksoben(); koord size(3-1,3-1); // make sure pos is within city limits! if(pos.xget_basis_pos() : find_place_for_hub( city ); if( town_road==koord::invalid) { return halthandle_t(); } // ok, now we could built it => flatten the land sint8 h = max( welt->get_water_hgt(pos) + 1, welt->lookup_kartenboden(pos)->get_hoehe() ); const koord dx( size.x/2, size.y/2 ); for( sint16 i=0; i!=size.y+dx.y; i+=dx.y ) { for( sint16 j=0; j!=size.x+dx.x; j+=dx.x ) { climate c = welt->get_climate(pos+koord(j,i)); if(!welt->flatten_tile(this,pos+koord(j,i),h)) { return halthandle_t(); } // ensure is land grund_t* bd = welt->lookup_kartenboden(pos+koord(j,i)); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(pos+koord(j,i), bd->get_hoehe()-1); welt->access(pos+koord(j,i))->correct_water(); welt->set_climate(pos+koord(j,i), c, true); } } } // now taxiways way_builder_t bauigel(this); // 3x3 layout, first we make the taxiway cross koord center=pos+dx; bauigel.init_builder( way_builder_t::luft, taxi_desc, NULL, NULL ); bauigel.calc_straight_route( welt->lookup_kartenboden(center+koord::north)->get_pos(), welt->lookup_kartenboden(center+koord::south)->get_pos() ); assert(bauigel.get_count()-1 > 1); bauigel.build(); bauigel.init_builder( way_builder_t::luft, taxi_desc, NULL, NULL ); bauigel.calc_straight_route( welt->lookup_kartenboden(center+koord::west)->get_pos(), welt->lookup_kartenboden(center+koord::east)->get_pos() ); assert(bauigel.get_count()-1 > 1); bauigel.build(); // now try to connect one of the corners with a road koord bushalt = koord::invalid, runwaystart, runwayend; koord trypos[4] = { koord(0,0), koord(size.x,0), koord(0,size.y), koord(size.x,size.y) }; uint32 length=9999; rotation=-1; bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()) ); bauigel.set_keep_existing_faster_ways(true); bauigel.set_keep_city_roads(true); bauigel.set_maximum(10000); // find the closest one to town ... for( int i=0; i<4; i++ ) { bushalt = pos+trypos[i]; bauigel.calc_route(welt->lookup_kartenboden(bushalt)->get_pos(),welt->lookup_kartenboden(town_road)->get_pos()); // no road => try next if( bauigel.get_count() >= 2 && bauigel.get_count() < length+1 ) { rotation = i; length = bauigel.get_count()-1; } } if(rotation==-1) { // if we every get here that means no connection road => remove airport welt->lookup_kartenboden(center+koord::north)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::south)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::west)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::east)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center)->remove_everything_from_way( this, air_wt, ribi_t::all ); return halthandle_t(); } bushalt = pos+trypos[rotation]; bauigel.calc_route(welt->lookup_kartenboden(bushalt)->get_pos(),welt->lookup_kartenboden(town_road)->get_pos()); bauigel.build(); // now the busstop (our next hub ... ) const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX ); // get an airport name (even though the hub is the bus stop ... ) // now built the bus stop if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) { welt->lookup_kartenboden(center+koord::north)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::south)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::west)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center+koord::east)->remove_everything_from_way( this, air_wt, ribi_t::none ); welt->lookup_kartenboden(center)->remove_everything_from_way( this, air_wt, ribi_t::all ); return halthandle_t(); } // and change name to airport ... grund_t *gr = welt->lookup_kartenboden(bushalt); halthandle_t halt = gr ? gr->get_halt() : halthandle_t(); if (halt.is_bound()) { // it should be, but avoid crashes char* const name = halt->create_name(bushalt, "Airport"); halt->set_name( name ); free(name); } // built also runway now ... bauigel.init_builder( way_builder_t::luft, runway_desc, NULL, NULL ); bauigel.calc_straight_route( welt->lookup_kartenboden(pos+trypos[rotation==0?3:0])->get_pos(), welt->lookup_kartenboden(pos+trypos[1+(rotation&1)])->get_pos() ); assert(bauigel.get_count()-1 > 1); bauigel.build(); // now the airstops (only on single tiles, this will always work const building_desc_t* airstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, air_wt, welt->get_timeline_year_month(), 0 ); for( int i=0; i<4; i++ ) { if( koord_distance(center+koord::nesw[i],bushalt)==1 && ribi_t::is_single( welt->lookup_kartenboden(center+koord::nesw[i])->get_weg_ribi_unmasked(air_wt) ) ) { call_general_tool( TOOL_BUILD_STATION, center+koord::nesw[i], airstop_desc->get_name() ); } } // and now the one far away ... for( int i=0; i<4; i++ ) { if( koord_distance(center+koord::nesw[i],bushalt)>1 && ribi_t::is_single( welt->lookup_kartenboden(center+koord::nesw[i])->get_weg_ribi_unmasked(air_wt) ) ) { call_general_tool( TOOL_BUILD_STATION, center+koord::nesw[i], airstop_desc->get_name() ); } } // success return halt; } static koord find_airport_pos(karte_t* welt, const stadt_t *s ) { koord bestpos = koord::invalid, k; sint32 bestdist = 999999; // try to find an airport place as close to the city as possible for( k.y=max(6,s->get_linksoben().y-10); k.y<=min(welt->get_size().y-3-6,s->get_rechtsunten().y+10); k.y++ ) { for( k.x=max(6,s->get_linksoben().x-25); k.x<=min(welt->get_size().x-3-6,s->get_rechtsunten().x+10); k.x++ ) { sint32 testdist = koord_distance( k, s->get_pos() ); if( testdistget_linksoben().x || k.y+2get_linksoben().y || k.x>=s->get_rechtsunten().x || k.y>=s->get_rechtsunten().y ) { // malus for out of town testdist += 5; } if( testdistsquare_is_free( k, 3, 3, NULL, ALL_CLIMATES ) ) { bestpos = k; bestdist = testdist; } } } } return bestpos; } /** build airports and planes */ bool ai_passenger_t::create_air_transport_vehicle(const stadt_t *start_stadt, const stadt_t *end_stadt) { const vehicle_desc_t *v_desc = vehicle_search(air_wt, 10, 900, goods_manager_t::passengers, false); if(v_desc==NULL) { // no aircraft there return false; } if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... return false; } halthandle_t start_hub = get_our_hub( start_stadt ); halthandle_t start_connect_hub; koord start_airport; if(start_hub.is_bound()) { if( (start_hub->get_station_type()&haltestelle_t::airstop)==0 ) { start_connect_hub = start_hub; start_hub = halthandle_t(); // is there already one airport next to this town? for(haltestelle_t::connection_t const& i : start_connect_hub->get_pax_connections()) { halthandle_t const h = i.halt; if( h->get_station_type()&haltestelle_t::airstop ) { start_hub = h; break; } } } else { start_airport = start_hub->get_basis_pos(); } } // find an airport place if(!start_hub.is_bound()) { start_airport = find_airport_pos( welt, start_stadt ); if(start_airport==koord::invalid) { // sorry, no suitable place return false; } } // same for end halthandle_t end_hub = get_our_hub( end_stadt ); halthandle_t end_connect_hub; koord end_airport; if(end_hub.is_bound()) { if( (end_hub->get_station_type()&haltestelle_t::airstop)==0 ) { end_connect_hub = end_hub; end_hub = halthandle_t(); // is there already one airport next to this town? for(haltestelle_t::connection_t const& i : end_connect_hub->get_pax_connections()) { halthandle_t const h = i.halt; if( h->get_station_type()&haltestelle_t::airstop ) { start_hub = h; break; } } } else { end_airport = end_hub->get_basis_pos(); } } if(!end_hub.is_bound()) { // find an airport place end_airport = find_airport_pos( welt, end_stadt ); if(end_airport==koord::invalid) { // sorry, no suitable place return false; } } // eventually construct them if(start_airport!=koord::invalid && end_airport!=koord::invalid) { // build the airport if necessary if(!start_hub.is_bound()) { start_hub = build_airport(start_stadt, start_airport, true); if(!start_hub.is_bound()) { return false; } start_connect_hub = get_our_hub( start_stadt ); if(!start_connect_hub.is_bound()) { koord sch = find_place_for_hub( start_stadt ); // probably we must construct a city hub, since the airport is outside of the city limits const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX ); call_general_tool( TOOL_BUILD_STATION, sch, busstop_desc->get_name() ); start_connect_hub = get_our_hub( start_stadt ); assert( start_connect_hub.is_bound() ); } } if(!end_hub.is_bound()) { end_hub = build_airport(end_stadt, end_airport, true); if(!end_hub.is_bound()) { if (start_hub->get_pax_connections().empty()) { // remove airport busstop welt->lookup_kartenboden(start_hub->get_basis_pos())->remove_everything_from_way( this, road_wt, ribi_t::none ); koord center = start_hub->get_basis_pos() + koord( welt->lookup_kartenboden(start_hub->get_basis_pos())->get_weg_ribi_unmasked( air_wt ) ); // now the remaining taxi-/runways for( sint16 y=center.y-1; y<=center.y+1; y++ ) { for( sint16 x=center.x-1; x<=center.x+1; x++ ) { welt->lookup_kartenboden(koord(x,y))->remove_everything_from_way( this, air_wt, ribi_t::none ); } } } return false; } end_connect_hub = get_our_hub( end_stadt ); if(!end_connect_hub.is_bound()) { koord ech = find_place_for_hub( end_stadt ); // probably we must construct a city hub, since the airport is outside of the city limits const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX ); call_general_tool( TOOL_BUILD_STATION, ech, busstop_desc->get_name() ); end_connect_hub = get_our_hub( end_stadt ); assert( end_connect_hub.is_bound() ); } } } // now we have airports (albeit first tile is a bus stop) const grund_t *start = start_hub->find_matching_position(air_wt); const grund_t *end = end_hub->find_matching_position(air_wt); // since 86.01 we use lines for vehicles ... schedule_t *schedule=new airplane_schedule_t(); schedule->append( start, 0, 0 ); schedule->append( end, 90, 0 ); schedule->set_current_stop( 1 ); schedule->finish_editing(); linehandle_t line=simlinemgmt.create_line(simline_t::airline,this,schedule); delete schedule; // now create one plane vehicle_t* v = vehicle_builder_t::build( start->get_pos(), this, NULL, v_desc); convoi_t* cnv = new convoi_t(this); cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); cnv->set_line(line); cnv->start(); // eventually build a airport shuttle bus ... if(start_connect_hub.is_bound() && start_connect_hub!=start_hub) { koord stops[2] = { start_hub->get_basis_pos(), start_connect_hub->get_basis_pos() }; create_bus_transport_vehicle( stops[1], 1, stops, 2, false ); } // eventually build a airport shuttle bus ... if(end_connect_hub.is_bound() && end_connect_hub!=end_hub) { koord stops[2] = { end_hub->get_basis_pos(), end_connect_hub->get_basis_pos() }; create_bus_transport_vehicle( stops[1], 1, stops, 2, false ); } return true; } /** creates a more general road transport */ void ai_passenger_t::create_bus_transport_vehicle(koord startpos2d,int vehicle_count,koord *stops,int count,bool do_wait) { DBG_MESSAGE("ai_passenger_t::create_bus_transport_vehicle()","bus at (%i,%i)",startpos2d.x,startpos2d.y); // now start all vehicle one field before, so they load immediately koord3d startpos = welt->lookup_kartenboden(startpos2d)->get_pos(); // since 86.01 we use lines for road vehicles ... schedule_t *schedule=new truck_schedule_t(); // do not start at current stop => wont work ... for(int j=0; jappend(welt->lookup_kartenboden(stops[j]), j == 0 || !do_wait ? 0 : 10, j == 0 || !do_wait ? 0 : 6553 ); } schedule->set_current_stop( stops[0]==startpos2d ); schedule->finish_editing(); linehandle_t line=simlinemgmt.create_line(simline_t::truckline,this,schedule); delete schedule; // now create all vehicles as convois for(int i=0; i cannot do anything about this ... return; } convoi_t* cnv = new convoi_t(this); // give the new convoi name from first vehicle cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); cnv->set_line(line); cnv->start(); } } /* now we follow all adjacent streets recursively and mark them * if they below to this stop, then we continue */ void ai_passenger_t::walk_city(linehandle_t const line, grund_t* const start, int const limit) { //maximum number of stops reached? if(line->get_schedule()->get_count()>=limit) { return; } ribi_t::ribi ribi = start->get_weg_ribi(road_wt); for(int r=0; r<4; r++) { // a way in our direction? if( (ribi & ribi_t::nesw[r])==0 ) { continue; } // ok, if connected, not marked, and not owner by somebody else grund_t *to; if( start->get_neighbour(to, road_wt, ribi_t::nesw[r] ) && !marker->is_marked(to) && check_owner(to->obj_bei(0)->get_owner(),this) ) { // ok, here is a valid street tile marker->mark(to); // can built a station here if( ribi_t::is_straight(to->get_weg_ribi(road_wt)) ) { // find out how many tiles we have covered already int covered_tiles=0; int house_tiles=0; uint16 const cov = welt->get_settings().get_station_coverage(); for (sint16 y = to->get_pos().y - cov; y <= to->get_pos().y + cov + 1; ++y) { for (sint16 x = to->get_pos().x - cov; x <= to->get_pos().x + cov + 1; ++x) { const planquadrat_t *pl = welt->access(koord(x,y)); // check, if we have a passenger stop already here if(pl && pl->get_haltlist_count()>0) { const halthandle_t *hl=pl->get_haltlist(); for( uint8 own=0; ownget_haltlist_count(); own++ ) { if( hl[own]->is_enabled(goods_manager_t::INDEX_PAS) ) { // our stop => nothing to do #ifdef AUTOJOIN_PUBLIC // we leave also public stops alone if( hl[own]->get_owner()==this || hl[own]->get_owner()==welt->get_public_player() ) { #else if( hl[own]->get_owner()==this ) { #endif covered_tiles ++; break; } } } } // check for houses if(pl && pl->get_kartenboden()->get_typ()==grund_t::fundament) { house_tiles++; } } } // now decide, if we build here // just using the ration of covered tiles versus house tiles int const max_tiles = cov * 2 + 1; if( covered_tiles<(max_tiles*max_tiles)/3 && house_tiles>=3 ) { // ok, lets do it const building_desc_t* bs = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX); if( call_general_tool( TOOL_BUILD_STATION, to->get_pos().get_2d(), bs->get_name() ) ) { //add to line line->get_schedule()->append(to,0); // no need to register it yet; done automatically, when convois will be assigned } } // start road, but no houses anywhere => stop searching if(house_tiles==0) { return; } } // now do recursion walk_city( line, to, limit ); } } } /* tries to cover a city with bus stops that does not overlap much and cover as much as possible * returns the line created, if successful */ void ai_passenger_t::cover_city_with_bus_route(koord start_pos, int number_of_stops) { if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... return; } // nothing in lists marker = &marker_t::instance(welt->get_size().x, welt->get_size().y); // and init all stuff for recursion grund_t *start = welt->lookup_kartenboden(start_pos); linehandle_t line = simlinemgmt.create_line( simline_t::truckline,this, new truck_schedule_t() ); line->get_schedule()->append(start,0); // now create a line walk_city( line, start, number_of_stops ); line->get_schedule()->finish_editing(); road_vehicle = vehicle_search( road_wt, 1, 50, goods_manager_t::passengers, false); if( line->get_schedule()->get_count()>1 ) { // success: add a bus to the line vehicle_t* v = vehicle_builder_t::build(start->get_pos(), this, NULL, road_vehicle); convoi_t* cnv = new convoi_t(this); cnv->set_name(v->get_desc()->get_name()); cnv->add_vehicle( v ); cnv->set_line(line); cnv->start(); } else { simlinemgmt.delete_line( line ); } marker = NULL; } void ai_passenger_t::step() { // needed for schedule of stops ... player_t::step(); if(!active) { // I am off ... return; } // one route per month ... if( welt->get_steps() < next_construction_steps ) { return; } switch(state) { case NR_INIT: { // time to update hq? built_update_headquarter(); // assume fail state = CHECK_CONVOI; /* if we have this little money, we do nothing * The second condition may happen due to extensive replacement operations; * in such a case it is save enough to expand anyway. */ if(!(finance->get_account_balance()>0 || finance->has_money_or_assets()) ) { return; } const weighted_vector_tpl& staedte = welt->get_cities(); int count = staedte.get_count(); int offset = (count>1) ? simrand(count-1) : 0; // start with previous target const stadt_t* last_start_stadt = start_stadt; start_stadt = end_stadt; end_stadt = NULL; end_attraction = NULL; ziel = NULL; platz2 = koord::invalid; // if no previous town => find one if(start_stadt==NULL) { if (staedte.empty()) { return; } // larger start town preferred start_stadt = pick_any_weighted(staedte); offset = staedte.index_of(start_stadt); } DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using city %s for start",start_stadt->get_name()); const halthandle_t start_halt = get_our_hub(start_stadt); // find starting place if(!start_halt.is_bound()) { DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","new_hub"); } platz1 = start_halt.is_bound() ? start_halt->get_basis_pos() : find_place_for_hub( start_stadt ); if(platz1==koord::invalid) { return; } DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using place (%i,%i) for start",platz1.x,platz1.y); if(count==1 || simrand(3)==0) { DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","searching attraction"); // 25 % of all connections are tourist attractions const weighted_vector_tpl &attractions = welt->get_attractions(); // this way, we are sure, our factory is connected to this town ... const vector_tpl &fabriken = start_stadt->get_target_factories_for_pax().get_entries(); unsigned last_dist = 0xFFFFFFFF; bool ausflug=simrand(2)!=0; // holidays first ... int ziel_count=ausflug?attractions.get_count():fabriken.get_count(); for( int i=0; iget_mail_level() <= 25) { // not a good object to go to ... continue; } pos = a->get_pos().get_2d(); size = a->get_tile()->get_desc()->get_size(a->get_tile()->get_layout()); } else { const fabrik_t* f = fabriken[i].factory; const factory_desc_t *const desc = f->get_desc(); if (( desc->get_pax_demand()==65535 ? desc->get_pax_level() : desc->get_pax_demand() ) <= 10) { // not a good object to go to ... we want more action ... continue; } pos = f->get_pos().get_2d(); size = f->get_desc()->get_building()->get_size(f->get_rotate()); } const stadt_t *next_town = welt->find_nearest_city(pos); if(next_town==NULL || start_stadt==next_town) { // this is either a town already served (so we do not create a new hub) // or a lonely point somewhere // in any case we do not want to serve this location already uint16 const c = welt->get_settings().get_station_coverage(); koord const cov = koord(c, c); koord test_platz=find_area_for_hub(pos-cov,pos+size+cov,pos); if( !get_halt(test_platz).is_bound() ) { // not served dist = koord_distance(platz1,test_platz); if(dist+simrand(50)3) { // but closer than the others if(ausflug) { end_attraction = attractions[i]; } else { ziel = fabriken[i].factory; } last_dist = dist; platz2 = test_platz; } } } } // test for success if(platz2!=koord::invalid) { // found something state = NR_SAMMLE_ROUTEN; DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","decision: %s wants to built network between %s and %s",get_name(),start_stadt->get_name(),ausflug?end_attraction->get_tile()->get_desc()->get_name():ziel->get_name()); } } else { DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","searching town"); int last_dist = 9999999; // find a good route for( int i=0; iget_pos()); if( end_halt.is_bound() && is_connected(platz1,end_halt->get_basis_pos(),goods_manager_t::passengers) ) { // already connected continue; } // check if more close if( distget_name(),end_stadt->get_name()); } } } break; // so far only busses case NR_SAMMLE_ROUTEN: { // koord end_hub_pos = koord::invalid; DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","Find hub"); // also for target (if not tourist attraction!) if(end_stadt!=NULL) { DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","try to built connect to city %p", end_stadt ); // target is town halthandle_t h = get_our_hub(end_stadt); if(h.is_bound()) { end_hub_pos = h->get_basis_pos(); } else { end_hub_pos = find_place_for_hub( end_stadt ); } } else { // already found place end_hub_pos = platz2; } // was successful? if(end_hub_pos!=koord::invalid) { // ok, now we check the vehicle platz2 = end_hub_pos; DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","hub found -> NR_BAUE_ROUTE1"); state = NR_BAUE_ROUTE1; } else { // no success DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","no suitable hub found"); end_stadt = NULL; state = CHECK_CONVOI; } } break; // get a suitable vehicle case NR_BAUE_ROUTE1: // wait for construction semaphore { // we want the fastest we can get! road_vehicle = vehicle_search( road_wt, 50, 80, goods_manager_t::passengers, false); if(road_vehicle!=NULL) { // find the best => AI will never survive // road_weg = way_builder_t::weg_search( road_wt, road_vehicle->get_topspeed(), welt->get_timeline_year_month(),type_flat ); // find the really cheapest road road_weg = way_builder_t::weg_search( road_wt, 10, welt->get_timeline_year_month(), type_flat ); state = NR_BAUE_STRASSEN_ROUTE; DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using %s on %s",road_vehicle->get_name(),road_weg->get_name()); } else { // no success end_stadt = NULL; state = CHECK_CONVOI; } } break; // built a simple road (no bridges, no tunnels) case NR_BAUE_STRASSEN_ROUTE: { state = NR_BAUE_WATER_ROUTE; // assume failure if( !ai_t::road_transport ) { // no overland bus lines break; } const building_desc_t* bs = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX); if(bs && create_simple_road_transport(platz1, koord(1,1),platz2,koord(1,1),road_weg) ) { // since the road may have led to a crossing at the intended stop position ... bool ok = true; if( !get_halt(platz1).is_bound() ) { if( !call_general_tool( TOOL_BUILD_STATION, platz1, bs->get_name() ) ) { platz1 = find_area_for_hub( platz1-koord(2,2), platz1+koord(2,2), platz1 ); ok = call_general_tool( TOOL_BUILD_STATION, platz1, bs->get_name() ); } } if( ok ) { if( !get_halt(platz2).is_bound() ) { if( !call_general_tool( TOOL_BUILD_STATION, platz2, bs->get_name() ) ) { platz2 = find_area_for_hub( platz2-koord(2,2), platz2+koord(2,2), platz2 ); ok = call_general_tool( TOOL_BUILD_STATION, platz2, bs->get_name() ); } } } // still continue? if(ok) { koord list[2]={ platz1, platz2 }; // wait only, if target is not a hub but an attraction/factory create_bus_transport_vehicle(platz1,1,list,2,end_stadt==NULL); state = NR_SUCCESS; // tell the player cbuffer_t buf; if(end_attraction!=NULL) { platz1 = end_attraction->get_pos().get_2d(); buf.printf(translator::translate("%s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n"), get_name(), start_stadt->get_name(), make_single_line_string(translator::translate(end_attraction->get_tile()->get_desc()->get_name()),2), platz1.x, platz1.y ); end_stadt = start_stadt; } else if(ziel!=NULL) { platz1 = ziel->get_pos().get_2d(); buf.printf( translator::translate("%s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n"), get_name(), start_stadt->get_name(), make_single_line_string(translator::translate(ziel->get_name()),2), platz1.x, platz1.y ); end_stadt = start_stadt; } else { buf.printf( translator::translate("Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() ); // add two intown routes cover_city_with_bus_route(platz1, 6); cover_city_with_bus_route(platz2, 6); } welt->get_message()->add_message(buf, welt->lookup_kartenboden(platz1)->get_pos(), message_t::ai, PLAYER_FLAG | player_nr, road_vehicle->get_base_image()); } } } break; case NR_BAUE_WATER_ROUTE: if( !ai_t::ship_transport ) { // no overland bus lines state = NR_BAUE_AIRPORT_ROUTE; break; } if( end_attraction == NULL && ship_transport && create_water_transport_vehicle(start_stadt, end_stadt ? end_stadt->get_pos() : ziel->get_pos().get_2d())) { // add two intown routes cover_city_with_bus_route( get_our_hub(start_stadt)->get_basis_pos(), 6); if(end_stadt!=NULL) { cover_city_with_bus_route( get_our_hub(end_stadt)->get_basis_pos(), 6); } else { // start again with same town end_stadt = start_stadt; } cbuffer_t buf; buf.printf( translator::translate("Ferry service by\n%s\nnow between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() ); koord3d pos = welt->lookup_kartenboden(end_stadt->get_pos())->get_pos(); welt->get_message()->add_message(buf, pos, message_t::ai, PLAYER_FLAG | player_nr, road_vehicle->get_base_image()); state = NR_SUCCESS; } else { if( end_attraction==NULL && ziel==NULL ) { state = NR_BAUE_AIRPORT_ROUTE; } else { state = NR_BAUE_CLEAN_UP; } } break; // despite its name: try airplane case NR_BAUE_AIRPORT_ROUTE: // try airline (if we are wealthy enough) ... if( !air_transport || finance->get_history_com_month(1, ATC_CASH) < finance->get_starting_money() || !end_stadt || !create_air_transport_vehicle( start_stadt, end_stadt ) ) { state = NR_BAUE_CLEAN_UP; } else { // add two intown routes cover_city_with_bus_route( get_our_hub(start_stadt)->get_basis_pos(), 6); cover_city_with_bus_route( get_our_hub(end_stadt)->get_basis_pos(), 6); cbuffer_t buf; buf.printf( translator::translate("Airline service by\n%s\nnow between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() ); koord3d pos = welt->lookup_kartenboden(end_stadt->get_pos())->get_pos(); welt->get_message()->add_message(buf, pos, message_t::ai, PLAYER_FLAG | player_nr, road_vehicle->get_base_image()); state = NR_SUCCESS; } break; // remove marker etc. case NR_BAUE_CLEAN_UP: state = CHECK_CONVOI; end_stadt = NULL; // otherwise it may always try to built the same route! break; // successful construction case NR_SUCCESS: { state = CHECK_CONVOI; next_construction_steps = welt->get_steps() + simrand( construction_speed/16 ); } break; // add vehicles to crowded lines case CHECK_CONVOI: { // next time: do something different state = NR_INIT; next_construction_steps = welt->get_steps() + simrand( ai_t::construction_speed ) + 25; vector_tpl lines(0); simlinemgmt.get_lines( simline_t::line, &lines); const uint32 offset = simrand(lines.get_count()); for (uint32 i = 0; iget_linetype()!=simline_t::airline && line->get_linetype()!=simline_t::truckline) { continue; } // remove empty lines if(line->count_convoys()==0) { simlinemgmt.delete_line(line); break; } // avoid empty schedule ?!? assert(!line->get_schedule()->empty()); // made loss with this line if(line->get_finance_history(0,LINE_PROFIT)<0) { // try to update the vehicles if(welt->use_timeline() && line->count_convoys()>1) { // do not update unimportant lines with single vehicles slist_tpl obsolete; uint32 capacity = 0; for( uint i=0; icount_convoys(); i++ ) { convoihandle_t cnv = line->get_convoy(i); if(cnv->has_obsolete_vehicles()) { obsolete.append(cnv); capacity += cnv->front()->get_desc()->get_capacity(); } } if(capacity>0) { // now try to find new vehicle vehicle_t const& v = *line->get_convoy(0)->front(); waytype_t const wt = v.get_waytype(); vehicle_desc_t const* const v_desc = vehicle_builder_t::vehicle_search(wt, welt->get_current_month(), 50, welt->get_average_speed(wt), goods_manager_t::passengers, false, true); if (!v_desc->is_retired(welt->get_current_month()) && v_desc != v.get_desc()) { // there is a newer one ... for( uint32 new_capacity=0; capacity>new_capacity; new_capacity+=v_desc->get_capacity()) { if( convoihandle_t::is_exhausted() ) { // too many convois => cannot do anything about this ... break; } vehicle_t* v = vehicle_builder_t::build( line->get_schedule()->entries[0].pos, this, NULL, v_desc ); convoi_t* new_cnv = new convoi_t(this); new_cnv->set_name( v->get_desc()->get_name() ); new_cnv->add_vehicle( v ); new_cnv->set_line(line); new_cnv->start(); } // delete all old convois while(!obsolete.empty()) { obsolete.remove_first()->self_destruct(); } return; } } } } // next: check for stuck convois ... sint64 free_cap = line->get_finance_history(0,LINE_CAPACITY); sint64 used_cap = line->get_finance_history(0,LINE_TRANSPORTED_GOODS); if(free_cap+used_cap==0) { continue; } sint32 ratio = (sint32)((free_cap*100l)/(free_cap+used_cap)); // next: check for overflowing lines, i.e. running with 3/4 of the capacity if( ratio<10 && !convoihandle_t::is_exhausted() ) { // else add the first convoi again vehicle_t* const v = vehicle_builder_t::build(line->get_schedule()->entries[0].pos, this, NULL, line->get_convoy(0)->front()->get_desc()); convoi_t* new_cnv = new convoi_t(this); new_cnv->set_name( v->get_desc()->get_name() ); new_cnv->add_vehicle( v ); new_cnv->set_line( line ); // on waiting line, wait at alternating stations for load balancing if( line->get_schedule()->entries[1].minimum_loading==90 && line->get_linetype()!=simline_t::truckline && (line->count_convoys()&1)==0 ) { new_cnv->get_schedule()->entries[0].minimum_loading = 90; new_cnv->get_schedule()->entries[1].minimum_loading = 0; } new_cnv->start(); return; } // next: check for too many cars, i.e. running with too many cars if( ratio>40 && line->count_convoys()>1) { // remove one convoi line->get_convoy(0)->self_destruct(); return; } } } break; default: DBG_MESSAGE("ai_passenger_t::do_passenger_ki()", "Illegal state %d!", state ); end_stadt = NULL; state = NR_INIT; } } void ai_passenger_t::rdwr(loadsave_t *file) { if( file->is_version_less(102, 2) ) { // due to an error the player was never saved correctly player_t::rdwr(file); return; } xml_tag_t t( file, "ai_passenger_t" ); ai_t::rdwr(file); // then check, if we have to do something or the game is too old ... if(file->is_version_less(101, 0)) { // ignore saving, reinit on loading if( file->is_loading() ) { next_construction_steps = welt->get_steps()+simrand(ai_t::construction_speed); } return; } // now save current state ... file->rdwr_enum(state); if( file->is_version_less(111, 1) ) { file->rdwr_long(ai_t::construction_speed); file->rdwr_bool(air_transport); file->rdwr_bool(ship_transport); road_transport = true; rail_transport = false; } platz1.rdwr( file ); platz2.rdwr( file ); if(file->is_saving()) { // save current pointers sint32 delta_steps = next_construction_steps-welt->get_steps(); file->rdwr_long(delta_steps); koord k = start_stadt ? start_stadt->get_pos() : koord::invalid; k.rdwr(file); k = end_stadt ? end_stadt->get_pos() : koord::invalid; k.rdwr(file); koord3d k3d = end_attraction ? end_attraction->get_pos() : koord3d::invalid; k3d.rdwr(file); k3d = ziel ? ziel->get_pos() : koord3d::invalid; k3d.rdwr(file); } else { // since steps in loaded game == 0 file->rdwr_long(next_construction_steps); next_construction_steps += welt->get_steps(); // reinit current pointers koord k; k.rdwr(file); start_stadt = welt->find_nearest_city(k); k.rdwr(file); end_stadt = welt->find_nearest_city(k); koord3d k3d; k3d.rdwr(file); end_attraction = welt->lookup(k3d) ? welt->lookup(k3d)->find() : NULL; k3d.rdwr(file); ziel = fabrik_t::get_fab(k3d.get_2d() ); } if (file->is_version_atleast(122, 1)) { plainstring road_vehicle_name = road_vehicle ? road_vehicle->get_name() : ""; file->rdwr_str(road_vehicle_name); if (file->is_loading() && road_vehicle_name != "") { road_vehicle = vehicle_builder_t::get_info(road_vehicle_name); } } } /** * Dealing with stuck or lost vehicles: * - delete lost ones * - ignore stuck ones */ void ai_passenger_t::report_vehicle_problem(convoihandle_t cnv,const koord3d ziel) { if( cnv->get_state() == convoi_t::NO_ROUTE && this!=welt->get_active_player() ) { DBG_MESSAGE("ai_passenger_t::report_vehicle_problem","Vehicle %s can't find a route to (%i,%i)!", cnv->get_name(),ziel.x,ziel.y); cnv->self_destruct(); return; } player_t::report_vehicle_problem( cnv, ziel ); } void ai_passenger_t::finish_rd() { if (!road_vehicle) { dbg->warning("ai_passenger_t::finish_rd", "Default road vehicle could not be loaded, searching for one..."); road_vehicle = vehicle_search( road_wt, 50, 80, goods_manager_t::passengers, false); } if (road_vehicle == NULL) { // reset state end_stadt = NULL; state = CHECK_CONVOI; } } simutrans-124.3/src/simutrans/player/ai_passenger.h000066400000000000000000000046271474050137200225050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PLAYER_AI_PASSENGER_H #define PLAYER_AI_PASSENGER_H #include "ai.h" class marker_t; /// Simple passenger transport AI class ai_passenger_t : public ai_t { private: enum state { NR_INIT, NR_SAMMLE_ROUTEN, NR_BAUE_ROUTE1, NR_BAUE_AIRPORT_ROUTE, NR_BAUE_STRASSEN_ROUTE, NR_BAUE_WATER_ROUTE, NR_BAUE_CLEAN_UP, NR_SUCCESS, NR_WATER_SUCCESS, CHECK_CONVOI }; // vars for the KI state state; // we will use this vehicle! const vehicle_desc_t *road_vehicle; // and the convoi will run on this track: const way_desc_t *road_weg ; // time to wait before next construction sint32 next_construction_steps; /* start and end stop position (and their size) */ koord platz1, platz2; const stadt_t *start_stadt; const stadt_t *end_stadt; // target is town const gebaeude_t *end_attraction; fabrik_t *ziel; // marker field marker_t *marker; halthandle_t get_our_hub( const stadt_t *s ) const; koord find_area_for_hub( const koord lo, const koord ru, const koord basis ) const; koord find_place_for_hub( const stadt_t *s ) const; /** builds harbours and ferries */ koord find_harbour_pos(karte_t* welt, const stadt_t *s ); bool create_water_transport_vehicle(const stadt_t* start_stadt, const koord target_pos); // builds a simple 3x3 three stop airport with town connection road halthandle_t build_airport(const stadt_t* city, koord pos, int rotate); /** build airports and planes */ bool create_air_transport_vehicle(const stadt_t *start_stadt, const stadt_t *end_stadt); // helper function for bus stops intown void walk_city(linehandle_t line, grund_t* start, int limit); // tries to cover a city with bus stops that does not overlap much and cover as much as possible void cover_city_with_bus_route(koord start_pos, int number_of_stops); void create_bus_transport_vehicle(koord startpos,int vehicle_count,koord *stops,int count,bool do_wait); public: ai_passenger_t(uint8 nr); // this type of AIs identifier uint8 get_ai_id() const OVERRIDE { return AI_PASSENGER; } // cannot do rail void set_rail_transport( bool ) OVERRIDE { rail_transport = false; } void report_vehicle_problem(convoihandle_t cnv,const koord3d ziel) OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; void finish_rd() OVERRIDE; bool set_active( bool b ) OVERRIDE; void step() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/player/ai_scripted.cc000066400000000000000000000164711474050137200224710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "ai_scripted.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../gui/simwin.h" #include "../gui/player_frame.h" // scripting #include "../script/script.h" #include "../script/script_loader.h" #include "../script/api/api.h" // TODO ai debug window ai_scripted_t::ai_scripted_t(uint8 nr) : ai_t(nr) { script = NULL; set_name("The unknown AI player"); } ai_scripted_t::~ai_scripted_t() { delete script; script = NULL; } const char* ai_scripted_t::init( const char *ai_base, const char *ai_name_) { if (script) { return "AI already initialized"; } ai_name = ai_name_; // path to ai files cbuffer_t buf; buf.printf("%s%s/", ai_base, ai_name_); ai_path = buf; // ai script file buf.append("ai.nut"); if (!load_script( buf )) { dbg->warning("ai_scripted_t::init", "could not load script file %s", (const char*)buf); delete script; script = NULL; return "Loading ai script failed"; } // load translations translator::load_files_from_folder( ai_path.c_str(), "scenario" ); // set the standard name buf.clear(); buf.printf("player %i", player_nr-1); set_name(buf); // now call startup function uint8 dummy = 0; if (const char* err = script->call_function(script_vm_t::QUEUE, "start", dummy, get_player_nr())) { if (strcmp(err, "suspended")) { dbg->warning("ai_scripted_t::init", "error [%s] calling start", err); } } // update player window if (ki_kontroll_t *frame = dynamic_cast( win_get_magic(magic_ki_kontroll_t) ) ) { frame->update_data(); } return NULL; } bool ai_scripted_t::load_script(const char* filename) { cbuffer_t buf; buf.printf("script-ai-%d.log", player_nr); // start vm script = script_loader_t::start_vm("ai_base.nut", buf, ai_path.c_str(), false); if (script == NULL) { return false; } // set my player number script->set_my_player(get_player_nr()); // load ai definition if (const char* err = script->call_script(filename)) { if (strcmp(err, "suspended")) { dbg->error("ai_scripted_t::load_script", "error [%s] calling %s", err, filename); } return false; } return true; } const char* ai_scripted_t::reload_script() { if (script == NULL) { return NULL; } // save the script to string plainstring str; script->call_function(script_vm_t::FORCEX, "save", str); // save old vm instance script_vm_t *old_script = script; script = NULL; // ai script file cbuffer_t buf; buf.printf("%sai.nut", ai_path.c_str()); if (!load_script( buf )) { dbg->warning("ai_scripted_t::reload_script", "could not reload script file %s", (const char*)buf); delete script; script = old_script; return "Reloading ai script failed"; } // restore persistent data const char* err = script->eval_string(str); if (err) { dbg->warning("ai_scripted_t::reload_script", "error [%s] evaluating persistent ai data", err); return "Reloading ai script data failed"; } // resume uint8 dummy = 0; script->call_function(script_vm_t::QUEUE, "resume_game", dummy, get_player_nr()); return NULL; } void ai_scripted_t::step() { if(!active) { return; } if (script) { script->call_function(script_vm_t::QUEUE, "step"); } } bool ai_scripted_t::new_month() { bool res = ai_t::new_month(); if (res && script) { script->call_function(script_vm_t::QUEUE, "new_month"); } return res; } void ai_scripted_t::new_year() { ai_t::new_year(); if (script) { script->call_function(script_vm_t::QUEUE, "new_year"); } } void repair_table_keys(plainstring &str) { // iterate linewise // replace [0\t]*([0-9][.*]) = by ["\1"]= // replace [0\t]*(".*") = by [\1]= char *p = str; char *line = p; // start of line char *equal = NULL; // place of equality sign char *first_digit = NULL; // first digit in line while (*p) { if (*p == '=') { if (first_digit && first_digit > line && equal == NULL) { // match /" =/ if (line+2 < p && *(p-2) == '"') { *(p-1) = ']'; } else { *(p-1) = '"'; *(p ) = ']'; *(p+1) = '='; } equal = p; } } else if (*p == '\n') { line = p; equal = NULL; first_digit = NULL; } else if('0' <= *p && *p <= '9') { if (first_digit == NULL && p >= line+2) { *(p-2) = '['; *(p-1) = '"'; first_digit = p; } } else if (first_digit == NULL && *p != ' ' && *p != '\t') { if (*p == '"' && line+1 < p ) { // " *(p-1) = '['; first_digit = p+1; } else { first_digit = line; } } // some keys contained broken umlauts if (equal == NULL && *p < 0) { *p = '_'; } p++; } } void ai_scripted_t::rdwr(loadsave_t *file) { ai_t::rdwr(file); script_api::coordinate_transform_t::rdwr(file); file->rdwr_str(ai_name); if (file->is_loading()) { // ai saved, but no script was assigned if (ai_name == NULL || *ai_name == 0) { script = NULL; return; } // load persistent data plainstring str; file->rdwr_str(str); dbg->message("ai_scripted_t::rdwr", "loaded persistent ai data: %s", str.c_str()); if (env_t::networkmode && !env_t::server) { // scripted players run on server only, for now at least delete script; script = NULL; return; } // DO NOT READ ANYTHING FROM file AFTER THIS POINT // load script cbuffer_t script_filename; // try addon directory first bool rdwr_error = true; if (env_t::default_settings.get_with_private_paks()) { ai_path = ( std::string("addons/ai/") + ai_name.c_str() + "/").c_str(); script_filename.printf("%sai.nut", ai_path.c_str()); rdwr_error = !load_script(script_filename); } // failed, try ai from data directory if (rdwr_error) { ai_path = ( std::string(env_t::base_dir) + "/ai/" + ai_name.c_str() + "/").c_str(); script_filename.clear(); script_filename.printf("%sai.nut", ai_path.c_str()); rdwr_error = !load_script(script_filename); } if (!rdwr_error) { // restore persistent data const char* err = script->eval_string(str); if (err && strcmp(err, "Error compiling string buffer")==0) { // sqai produced invalid table keys up to r9007 (and later as well... ) repair_table_keys(str); dbg->warning("ai_scripted_t::rdwr", "repaired persistent ai data: %s", str.c_str()); // close error message destroy_win(magic_script_error); // and try again err = script->eval_string(str); } if (err) { dbg->warning("ai_scripted_t::rdwr", "error [%s] evaluating persistent ai data for script '%s'", err, ai_name.c_str()); rdwr_error = true; } } else { dbg->warning("ai_scripted_t::rdwr", "could not load script file %s", (const char*)script_filename); } if (rdwr_error) { delete script; script = NULL; } } else { plainstring str(""); if (script) { script->call_function(script_vm_t::FORCEX, "save", str); dbg->warning("ai_scripted_t::rdwr", "write persistent ai data: %s", str.c_str()); } if (ai_name && *ai_name) { // valid name, save even if script is NULL file->rdwr_str(str); } } } void ai_scripted_t::finish_rd() { ai_t::finish_rd(); if (script) { uint8 dummy = 0; if (const char* err = script->call_function(script_vm_t::QUEUE, "resume_game", dummy, get_player_nr())) { if (strcmp(err, "suspended")) { dbg->warning("ai_scripted_t::finish_rd", "error [%s] calling resume_game", err); } } } } simutrans-124.3/src/simutrans/player/ai_scripted.h000066400000000000000000000030721474050137200223240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PLAYER_AI_SCRIPTED_H #define PLAYER_AI_SCRIPTED_H #include "ai.h" #include "../utils/plainstring.h" class script_vm_t; /// Squirrel Script AI class ai_scripted_t : public ai_t { /// name of ai, files are searched in ai/ai_name/... /// e.g. my_ai plainstring ai_name; /// path to ai directory (relative to env_t::user_dir) /// e.g. ai/my_ai/ plainstring ai_path; /** * loads ai file with the given name * @param filename name ai script file (including .nut extension) */ bool load_script(const char* filename); /// pointer to virtual machine script_vm_t *script; public: ai_scripted_t(uint8 nr); ~ai_scripted_t(); /** * Initializes scripted ai */ const char* init( const char *ai_base, const char *ai_name); /** * Reloads script * @returns error message */ const char* reload_script(); bool has_script() const { return script; } uint8 get_ai_id() const OVERRIDE { return AI_SCRIPTED; } const char* get_ai_name() const { return ai_name; } void step() OVERRIDE; /** * Called monthly by simworld.cc during simulation * @returns false if player has to be removed (bankrupt/inactive) */ bool new_month() OVERRIDE; /** * Called yearly by simworld.cc during simulation */ void new_year() OVERRIDE; /** * Stores/loads the player state * @param file where the data will be saved/loaded */ void rdwr(loadsave_t *file) OVERRIDE; /** * Called after game is fully loaded; */ void finish_rd() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/player/finance.cc000066400000000000000000001006651474050137200216050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../world/simworld.h" #include "../descriptor/building_desc.h" #include "../dataobj/loadsave.h" #include "../dataobj/scenario.h" #include "simplay.h" #include "finance.h" /** * initialize finance history arrays */ finance_t::finance_t(player_t *, karte_t * _world) : world(_world) { account_balance = world->get_settings().get_starting_money(world->get_last_year()); starting_money = account_balance; account_overdrawn = 0; for (int year=0; year= ATV_REVENUE )) { veh_month[TT_ALL][0][j] += veh_month[tt][0][j]; } } } for( int j=0; j< ATV_MAX; ++j ) { veh_year[TT_ALL][0][j] =0; for( int tt=1; tt= ATV_REVENUE )) { veh_year[TT_ALL][0][j] += veh_year[tt][0][j]; } } } // recalc margin for TT_ALL veh_month[TT_ALL][0][ATV_PROFIT_MARGIN] = calc_margin(veh_month[TT_ALL][0][ATV_OPERATING_PROFIT], veh_month[TT_ALL][0][ATV_REVENUE]); veh_year[TT_ALL][0][ATV_PROFIT_MARGIN] = calc_margin(veh_year[TT_ALL][0][ATV_OPERATING_PROFIT], veh_year[TT_ALL][0][ATV_REVENUE]); // undistinguishable by type of transport com_month[0][ATC_CASH] = account_balance; com_year [0][ATC_CASH] = account_balance; com_month[0][ATC_NETWEALTH] = veh_month[TT_ALL][0][ATV_NON_FINANCIAL_ASSETS] + account_balance; com_year [0][ATC_NETWEALTH] = veh_year[TT_ALL][0][ATV_NON_FINANCIAL_ASSETS] + account_balance; } sint64 finance_t::get_maintenance_with_bits(transport_type tt) const { assert(ttscale_with_month_length(maintenance[tt]); } sint64 finance_t::get_vehicle_maintenance_with_bits(transport_type tt) const { assert(ttscale_with_month_length(vehicle_maintenance[tt]); } bool finance_t::is_bancrupted() const { return ( get_netwealth() <=0 && veh_year[TT_ALL][0][ATV_INFRASTRUCTURE_MAINTENANCE] == 0 && maintenance[TT_ALL] == 0 && com_year[0][ATC_ALL_CONVOIS] == 0 ); } void finance_t::new_month() { calc_finance_history(); roll_history_month(); if(world->get_last_month()==0) { roll_history_year(); } // subtract maintenance for(int i=0; iis_version_less(112, 5) ) { rdwr_compatibility(file); return; } /* following lines enables FORWARD compatibility / you will be still able to load future versions of games with: * longer history * more transport_types * and new items in ATC_ or ATV_ */ sint8 max_years = MAX_PLAYER_HISTORY_YEARS; sint8 max_months = MAX_PLAYER_HISTORY_MONTHS; sint8 max_tt = TT_MAX; sint8 max_atc = ATC_MAX; sint8 max_atv = ATV_MAX; // used for reading longer history sint64 dummy = 0; // calc finance history for TT_ALL to save it correctly if( ! file->is_loading() ) { calc_finance_history(); } file->rdwr_longlong(account_balance); file->rdwr_long(account_overdrawn); file->rdwr_longlong(starting_money); file->rdwr_byte( max_years ); file->rdwr_byte( max_months ); file->rdwr_byte( max_tt ); // tt = transport type file->rdwr_byte( max_atc ); // atc = accounting type common file->rdwr_byte( max_atv ); // atv = accounting type vehicles for(int year = 0; year < max_years ; ++year ) { for( int cost_type = 0; cost_type < max_atc ; ++cost_type ) { if( ( year < MAX_PLAYER_HISTORY_YEARS ) && ( cost_type < ATC_MAX ) ) { file->rdwr_longlong( com_year[year][cost_type] ); } else { file->rdwr_longlong( dummy ); } } } for(int month = 0; month < max_months; ++month) { for( int cost_type = 0; cost_type < max_atc; ++cost_type ) { if( ( month < MAX_PLAYER_HISTORY_MONTHS ) && ( cost_type < ATC_MAX ) ) { file->rdwr_longlong( com_month[month][cost_type] ); } else { file->rdwr_longlong( dummy ); } } } for(int tt=0; tt < max_tt; ++tt){ for( int year = 0; year < max_years; ++year ) { for( int cost_type = 0; cost_type < max_atv; ++cost_type ) { if( ( tt < TT_MAX ) && ( year < MAX_PLAYER_HISTORY_YEARS ) && ( cost_type < ATV_MAX ) ) { file->rdwr_longlong( veh_year[tt][year][cost_type] ); } else { file->rdwr_longlong( dummy ); } } } } for(int tt=0; tt < max_tt; ++tt){ for( int month = 0; month < max_months; ++month ) { for( int cost_type = 0; cost_type < max_atv; ++cost_type ) { if( ( tt < TT_MAX ) && ( month < MAX_PLAYER_HISTORY_MONTHS ) && ( cost_type < ATV_MAX ) ) { file->rdwr_longlong( veh_month[tt][month][cost_type] ); } else { file->rdwr_longlong( dummy ); } } } } } void finance_t::roll_history_month() { // undistinguishable for (int i=MAX_PLAYER_HISTORY_MONTHS-1; i>0; i--) { for(int accounting_type=0; accounting_type0; i--) { for(int accounting_type=0; accounting_type0; i--) { for(int accounting_type=0; accounting_type0; i--) { for(int accounting_type=0; accounting_type 0 ){ veh_month[TT_OTHER][i][ATV_TOLL_RECEIVED] = finance_history_month[i][COST_WAY_TOLLS]; veh_month[TT_ALL ][i][ATV_TOLL_RECEIVED] = finance_history_month[i][COST_WAY_TOLLS]; } else{ veh_month[TT_OTHER][i][ATV_TOLL_PAID] = finance_history_month[i][COST_WAY_TOLLS]; veh_month[TT_ALL ][i][ATV_TOLL_PAID] = finance_history_month[i][COST_WAY_TOLLS]; } veh_month[TT_OTHER][i][ATV_WAY_TOLL] = finance_history_month[i][COST_WAY_TOLLS]; veh_month[TT_ALL ][i][ATV_WAY_TOLL] = finance_history_month[i][COST_WAY_TOLLS]; } } void finance_t::import_from_cost_year( const sint64 finance_history_year[][OLD_MAX_PLAYER_COST]) { for(int i=0; i 0 ){ veh_year[TT_OTHER][i][ATV_TOLL_RECEIVED] = finance_history_year[i][COST_WAY_TOLLS]; veh_year[TT_ALL ][i][ATV_TOLL_RECEIVED] = finance_history_year[i][COST_WAY_TOLLS]; } else{ veh_year[TT_OTHER][i][ATV_TOLL_PAID] = finance_history_year[i][COST_WAY_TOLLS]; veh_year[TT_ALL ][i][ATV_TOLL_PAID] = finance_history_year[i][COST_WAY_TOLLS]; } veh_year[TT_OTHER][i][ATV_WAY_TOLL] = finance_history_year[i][COST_WAY_TOLLS]; veh_year[TT_ALL ][i][ATV_WAY_TOLL] = finance_history_year[i][COST_WAY_TOLLS]; } } void finance_t::rdwr_compatibility(loadsave_t *file) { sint64 finance_history_year[OLD_MAX_PLAYER_HISTORY_YEARS][OLD_MAX_PLAYER_COST]; sint64 finance_history_month[OLD_MAX_PLAYER_HISTORY_MONTHS][OLD_MAX_PLAYER_COST]; for (int year=0; yearis_version_less(112, 5) ) && ( ! file->is_loading() ) ) { // for saving of game in old format export_to_cost_month( finance_history_month ); export_to_cost_year( finance_history_year ); } if (file->is_version_less(84, 8)) { // not so old save game for (int year = 0;yearis_version_less(84, 7)) { // a cost_type has has been added. For old savegames we only have 9 cost_types, now we have 10. // for old savegames only load 9 types and calculate the 10th; for new savegames load all 10 values if (cost_type < 9) { file->rdwr_longlong(finance_history_year[year][cost_type]); } } else { if (cost_type < 10) { file->rdwr_longlong(finance_history_year[year][cost_type]); } } } } } else if (file->is_version_less(86, 0)) { for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type]); } } // in 84008 monthly finance history was introduced for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } } else if (file->is_version_less(99, 11)) { // powerline category missing for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type]); } } for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } } else if (file->is_version_less(99, 17)) { // without detailed goo statistics for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type]); } } for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } } else if( file->is_version_less(102, 3) ) { // saved everything for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type]); } } for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } } else if( file->is_version_less(110, 7) ) { // only save what is needed for(int year = 0; yearCOST_MARGIN ) { file->rdwr_longlong(finance_history_year[year][cost_type]); } } } for (int month = 0;monthCOST_MARGIN ) { file->rdwr_longlong(finance_history_month[month][cost_type]); } } } } else if ( file->is_version_less(112, 5) ) { // savegame version: now with toll for(int year = 0; yearCOST_MARGIN ) { file->rdwr_longlong(finance_history_year[year][cost_type]); } } } for (int month = 0;monthCOST_MARGIN ) { file->rdwr_longlong(finance_history_month[month][cost_type]); } } } } if( file->is_version_atleast(102, 3) ) { file->rdwr_longlong(starting_money); } // we have to pay maintenance at the beginning of a month if(file->is_version_less(99, 18) && file->is_loading()) { finance_history_month[0][COST_MAINTENANCE] -= finance_history_month[1][COST_MAINTENANCE]; finance_history_year [0][COST_MAINTENANCE] -= finance_history_month[1][COST_MAINTENANCE]; set_account_balance(get_account_balance() - finance_history_month[1][COST_MAINTENANCE]); } if(file->is_loading()) { /* prior versions calculated margin incorrectly. * we also save only some values and recalculate all dependent ones * (remember: negative costs are just saved as negative numbers!) */ for( int year=0; year #include "../simtypes.h" /// for compatibility with old versions #define OLD_MAX_PLAYER_COST (19) /// number of years to keep history #define MAX_PLAYER_HISTORY_YEARS (25) /// number of months to keep history #define MAX_PLAYER_HISTORY_MONTHS (25) /** * Type of transport used in accounting statistics. * waytype_t was not used because of values assigned to air_wt and powerline_wt. * There are also buildings like railway station that can be distinguished * by transport_type and can not be distinguished by waytype_t. */ enum transport_type { TT_ALL=0, TT_ROAD, TT_RAILWAY, TT_SHIP, TT_MONORAIL, TT_MAGLEV, TT_TRAM, TT_NARROWGAUGE, TT_AIR, TT_OTHER, ///< everything else that can not be differentiated (e.g. houses), not powerlines TT_MAX_VEH = TT_OTHER, TT_POWERLINE, TT_MAX }; /** * ATC = accounting type common (common means data common for all transport types). * * Supersedes COST_ types, that CAN NOT be distinguished by type of transport- * - the data are concerning to whole company */ enum accounting_type_common { ATC_CASH = 0, ///< Cash ATC_NETWEALTH, ///< Total Cash + Assets ATC_ALL_CONVOIS, ///< Convoy count ATC_SCENARIO_COMPLETED, ///< Scenario success (only useful if there is one ... ) ATC_MAX }; /** * ATV = accounting type vehicles. * Supersedes COST_ types, that CAN be distinguished by type of transport. */ enum accounting_type_vehicles { ATV_REVENUE_PASSENGER = 0, ///< Revenue from passenger transport ATV_REVENUE_MAIL, ///< Revenue from mail transport ATV_REVENUE_GOOD, ///< Revenue from good transport ATV_REVENUE_TRANSPORT, ///< Operating profit = passenger + mail + goods = was: COST_INCOME ATV_TOLL_RECEIVED, ///< Toll paid to you by another player ATV_REVENUE, ///< Operating profit = revenue_transport + toll = passenger + mail+ goods + toll_received ATV_RUNNING_COST, ///< Distance based running costs, was: COST_VEHICLE_RUN ATV_VEHICLE_MAINTENANCE, ///< Monthly vehicle maintenance. Unused. ATV_INFRASTRUCTURE_MAINTENANCE, ///< Infrastructure maintenance (roads, railway, ...), was: COST_MAINTENANCE ATV_TOLL_PAID, ///< Toll paid by you to another player ATV_EXPENDITURE, ///< Total expenditure = RUNNING_COSTS+VEHICLE_MAINTENANCE+INFRACTRUCTURE_MAINTENANCE+TOLL_PAID ATV_OPERATING_PROFIT, ///< ATV_REVENUE - ATV_EXPENDITURE, was: COST_OPERATING_PROFIT ATV_NEW_VEHICLE, ///< New vehicles ATV_CONSTRUCTION_COST, ///< Construction cost, COST_CONSTRUCTION mapped here ATV_PROFIT, ///< ATV_OPERATING_PROFIT - (CONSTRUCTION_COST + NEW_VEHICLE), was: COST_PROFIT ATV_WAY_TOLL, ///< = ATV_TOLL_PAID + ATV_TOLL_RECEIVED, was: COST_WAY_TOLLS ATV_NON_FINANCIAL_ASSETS, ///< Value of vehicles owned by your company, was: COST_ASSETS ATV_PROFIT_MARGIN, ///< ATV_OPERATING_PROFIT / ATV_REVENUE, was: COST_MARGIN ATV_TRANSPORTED_PASSENGER, ///< Number of transported passengers ATV_TRANSPORTED_MAIL, ///< Number of transported mail ATV_TRANSPORTED_GOOD, ///< Number of transported goods ATV_TRANSPORTED, ///< Total number of transported cargo, was COST_ALL_TRANSPORTED ATV_DELIVERED_PASSENGER, ///< Number of delivered passengers, was: COST_TRANSPORTED_PAS ATV_DELIVERED_MAIL, ///< Number of delivered mail, was: COST_TRANSPORTED_MAIL ATV_DELIVERED_GOOD, ///< Number of delivered goods, was: COST_TRANSPORTED_GOOD ATV_DELIVERED, ///< Total number of delivered cargo ATV_MAX }; class loadsave_t; class karte_t; class player_t; class scenario_t; /** * Encapsulate margin calculation (Operating_Profit / Income) */ inline sint64 calc_margin(sint64 operating_profit, sint64 proceeds) { if (proceeds == 0) { return 0; } return (10000 * operating_profit) / proceeds; } /** * convert to displayed value */ inline sint64 convert_money(sint64 value) { return (value + 50) / 100; } /** * Class to encapsulate all company related statistics. */ class finance_t { karte_t * world; /** * Amount of money, previously known as "konto" */ sint64 account_balance; /** * Shows how many months you have been in red numbers. */ sint32 account_overdrawn; /** * Remember the starting money, used e.g. in scenarios. */ sint64 starting_money; /** * Contains values having relation with whole company but not with particular * type of transport (com - common). */ sint64 com_year[MAX_PLAYER_HISTORY_YEARS][ATC_MAX]; /** * Monthly finance history, data not distinguishable by transport type. */ sint64 com_month[MAX_PLAYER_HISTORY_MONTHS][ATC_MAX]; /** * Finance history having relation with particular type of service */ sint64 veh_year[TT_MAX][MAX_PLAYER_HISTORY_YEARS][ATV_MAX]; sint64 veh_month[TT_MAX][MAX_PLAYER_HISTORY_MONTHS][ATV_MAX]; /** * Monthly maintenance cost */ sint64 maintenance[TT_MAX]; /** * Monthly vehicle maintenance cost per transport type. */ sint64 vehicle_maintenance[TT_MAX]; public: finance_t(player_t * _player, karte_t * _world); /** * Adds construction cost to finance stats. * @param amount sum of money * @param wt way type, e.g. tram_wt */ inline void book_construction_costs(const sint64 amount, const waytype_t wt) { transport_type tt = translate_waytype_to_tt(wt); veh_year[tt][0][ATV_CONSTRUCTION_COST] += amount; veh_month[tt][0][ATV_CONSTRUCTION_COST] += amount; account_balance += amount; } /** * Adds count to number of convois in statistics. */ inline void book_convoi_number( const int count ) { com_year[0][ATC_ALL_CONVOIS] += count; com_month[0][ATC_ALL_CONVOIS] += count; } /** * Adds maintenance into/from finance stats. * @param change monthly maintenance cost difference * @param wt - waytype for accounting purposes */ inline sint64 book_maintenance(sint64 change, waytype_t const wt) { transport_type tt = translate_waytype_to_tt(wt); maintenance[tt] += change; maintenance[TT_ALL] += change; return maintenance[tt]; } /** * Account purchase of new vehicle: Subtracts money, increases assets. * @param amount money paid for vehicle (negative) * @param wt - waytype of vehicle */ inline void book_new_vehicle(const sint64 amount, const waytype_t wt) { const transport_type tt = translate_waytype_to_tt(wt); veh_year[ tt][0][ATV_NEW_VEHICLE] += amount; veh_month[tt][0][ATV_NEW_VEHICLE] += amount; update_assets(-amount, wt); account_balance += amount; } /** * Accounts income from transport of passenger, mail, or, goods. * @param amount earned money * @param wt waytype of vehicle * @param index 0 = passenger, 1 = mail, 2 = goods */ inline void book_revenue(const sint64 amount, const waytype_t wt, sint32 index) { const transport_type tt = translate_waytype_to_tt(wt); index = ((0 <= index) && (index <= 2)? index : 2); veh_year[tt][0][ATV_REVENUE_PASSENGER+index] += amount; veh_month[tt][0][ATV_REVENUE_PASSENGER+index] += amount; account_balance += amount; } /** * Accounts distance-based running costs * @param amount sum of money * @param wt way type */ inline void book_running_costs(const sint64 amount, const waytype_t wt) { const transport_type tt = translate_waytype_to_tt(wt); veh_year[tt][0][ATV_RUNNING_COST] += amount; veh_month[tt][0][ATV_RUNNING_COST] += amount; account_balance += amount; } /** * Account toll we have paid to any other company. * @param amount sum of money * @param wt way type */ inline void book_toll_paid(const sint64 amount, const waytype_t wt) { const transport_type tt = translate_waytype_to_tt(wt); veh_year[tt][0][ATV_TOLL_PAID] += amount; veh_month[tt][0][ATV_TOLL_PAID] += amount; account_balance += amount; } /** * Account toll we have received from another company. * @param amount sum of money * @param wt way type */ inline void book_toll_received(const sint64 amount, const waytype_t wt) { const transport_type tt = translate_waytype_to_tt(wt); veh_year[tt][0][ATV_TOLL_RECEIVED] += amount; veh_month[tt][0][ATV_TOLL_RECEIVED] += amount; account_balance += amount; } /** * Makes stats of amount of transported passenger, mail and goods * @param amount sum of money * @param wt way type * @param index 0 = passenger, 1 = mail, 2 = goods */ inline void book_transported(const sint64 amount, const waytype_t wt, int index) { const transport_type tt = translate_waytype_to_tt(wt); // there are: passenger, mail, goods if( (index < 0) || (index > 2)){ index = 2; } veh_year[ tt][0][ATV_TRANSPORTED_PASSENGER+index] += amount; veh_month[tt][0][ATV_TRANSPORTED_PASSENGER+index] += amount; } /** * Makes stats of amount of delivered passenger, mail and goods * @param amount sum of money * @param wt way type * @param index 0 = passenger, 1 = mail, 2 = goods */ inline void book_delivered(const sint64 amount, const waytype_t wt, int index) { const transport_type tt = translate_waytype_to_tt(wt); // there are: passenger, mail, goods if( (index < 0) || (index > 2)){ index = 2; } veh_year[ tt][0][ATV_DELIVERED_PASSENGER+index] += amount; veh_month[tt][0][ATV_DELIVERED_PASSENGER+index] += amount; } /** * Calculates the finance history for player. * This method has to be called before reading any variables besides account_balance! */ void calc_finance_history(); /** * @returns amount of money on account (also known as konto) */ inline sint64 get_account_balance() { return account_balance; } /** * Books amount of money to account (also known as konto) */ void book_account(sint64 amount) { account_balance += amount; com_month[0][ATC_CASH] = account_balance; com_year [0][ATC_CASH] = account_balance; com_month[0][ATC_NETWEALTH] += amount; com_year [0][ATC_NETWEALTH] += amount; // BUG profit is not adjusted when calling this method } /** * Returns the finance history (indistinguishable part) for player. * Call calc_finance_history before use! * @param year 0 .. current year, 1 .. last year, etc * @param type one of accounting_type_common */ sint64 get_history_com_year(int year, int type) const { return com_year[year][type]; } sint64 get_history_com_month(int month, int type) const { return com_month[month][type]; } /** * Returns the finance history (distinguishable by type of transport) for player. * Call calc_finance_history before use! * @param tt one of transport_type * @param year 0 .. current year, 1 .. last year, etc * @param type one of accounting_type_vehicles */ sint64 get_history_veh_year(transport_type tt, int year, int type) const { return veh_year[tt][year][type]; } sint64 get_history_veh_month(transport_type tt, int month, int type) const { return veh_month[tt][month][type]; } /** * @return how much month we have been in red numbers (= we had negative account balance) */ sint32 get_account_overdrawn() const { return account_overdrawn; } /** * @returns maintenance * @param tt transport type (Truck, Ship Aircraft, ...) */ sint64 get_maintenance(transport_type tt=TT_ALL) const { assert(tt 0); } /** * returns TRUE if net wealth > 0 (but this of course requires that we keep netwealth up to date!) */ bool has_money_or_assets() const { return ( get_netwealth() > 0 ); } /** * increases number of month for which the company is in red numbers */ void increase_account_overdrawn() { account_overdrawn++; } /** * returns true if company is bankrupt */ bool is_bancrupted() const; /** * Called at beginning of new month. */ void new_month(); /** * rolls the finance history for player (needed when new_year() or new_month()) triggered */ void roll_history_year(); void roll_history_month(); /** * loads or saves finance statistic */ void rdwr(loadsave_t *file); /// loads statistics of old versions void rdwr_compatibility(loadsave_t *file); /** * Sets account balance. This method enables to load old game format. * Do NOT use it in any other places! */ void set_account_balance(sint64 amount) { account_balance = amount; } void set_assets(const sint64 (&assets)[TT_MAX]); /** * Sets number of months for that the account balance is below zero. This method enables to load old game format. * Do NOT use it in any other places for any other purpose! */ void set_account_overdrawn(sint32 num) { account_overdrawn = num; } void set_starting_money(sint64 amount) { starting_money = amount; } /** * Translates waytype_t to transport_type */ static transport_type translate_waytype_to_tt(waytype_t wt); // to tranlate back to strings for finances GUI static const char* transport_type_values[TT_MAX]; void update_assets(sint64 delta, waytype_t wt); private: /** * Translates finance statistics from new format to old one. * Used for saving data in old format */ void export_to_cost_month(sint64 finance_history_month[][OLD_MAX_PLAYER_COST]); void export_to_cost_year( sint64 finance_history_year[][OLD_MAX_PLAYER_COST]); /** * Translates finance statistics from old format to new one. * Used for loading data from old format */ void import_from_cost_month(const sint64 finance_history_month[][OLD_MAX_PLAYER_COST]); void import_from_cost_year( const sint64 finance_history_year[][OLD_MAX_PLAYER_COST]); }; #endif simutrans-124.3/src/simutrans/player/simplay.cc000066400000000000000000000640211474050137200216530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simconvoi.h" #include "../simdebug.h" #include "../obj/depot.h" #include "../simhalt.h" #include "../simintr.h" #include "../simline.h" #include "../simmesg.h" #include "../simsound.h" #include "../simticker.h" #include "../tool/simtool.h" #include "../gui/simwin.h" #include "../world/simworld.h" #include "../display/viewport.h" #include "../builder/brueckenbauer.h" #include "../builder/hausbauer.h" #include "../builder/tunnelbauer.h" #include "../descriptor/tunnel_desc.h" #include "../descriptor/way_desc.h" #include "../ground/grund.h" #include "../dataobj/settings.h" #include "../dataobj/scenario.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../network/network_socket_list.h" #include "../obj/bruecke.h" #include "../obj/gebaeude.h" #include "../obj/leitung2.h" #include "../obj/tunnel.h" #include "../gui/messagebox.h" #include "../gui/player_frame.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" #include "../vehicle/air_vehicle.h" #include "simplay.h" #include "finance.h" karte_ptr_t player_t::welt; #ifdef MULTI_THREAD #include "../utils/simthread.h" static pthread_mutex_t load_mutex = PTHREAD_MUTEX_INITIALIZER; #endif player_t::player_t(uint8 nr) : finance(new finance_t(this, welt)), player_age(0), player_color_1(0), player_color_2(0), player_nr(nr), active(false), locked(false), unlock_pending(false), simlinemgmt(), undo_type(invalid_wt), headquarter_level(0), headquarter_pos(koord::invalid) { welt->get_settings().set_player_color_to_default(this); // we have different AI, try to find out our type: sprintf(player_name_buf,"player %i",player_nr-1); } player_t::~player_t() { while( !messages.empty() ) { delete messages.remove_first(); } destroy_win(magic_finances_t + get_player_nr()); delete finance; finance = NULL; } void player_t::book_construction_costs(player_t * const player, const sint64 amount, const koord k, const waytype_t wt) { if(player!=NULL) { player->finance->book_construction_costs(amount, wt); if(k != koord::invalid) { player->add_money_message(amount, k); } } } sint64 player_t::add_maintenance(sint64 change, waytype_t const wt) { #ifdef MULTI_THREAD pthread_mutex_lock( &load_mutex ); #endif const sint64 tmp = finance->book_maintenance(change, wt); #ifdef MULTI_THREAD pthread_mutex_unlock( &load_mutex ); #endif return tmp; } void player_t::add_money_message(const sint64 amount, const koord pos) { if(amount != 0 && player_nr != 1) { if( koord_distance(welt->get_viewport()->get_world_position(),pos)<2*(uint32)(display_get_width()/get_tile_raster_width())+3 ) { // only display, if near the screen ... add_message(amount, pos); // and same for sound too ... if( amount>=10000 && !welt->is_fast_forward() ) { welt->play_sound_area_clipped(pos, SFX_CASH, CASH_SOUND ); } } } } void player_t::book_new_vehicle(const sint64 amount, const koord k, const waytype_t wt) { finance->book_new_vehicle(amount, wt); add_money_message(amount, k); } void player_t::book_revenue(const sint64 amount, const koord k, const waytype_t wt, sint32 index) { finance->book_revenue(amount, wt, index); add_money_message(amount, k); } void player_t::book_running_costs(const sint64 amount, const waytype_t wt) { finance->book_running_costs(amount, wt); } void player_t::book_toll_paid(const sint64 amount, const waytype_t wt) { finance->book_toll_paid(amount, wt); } void player_t::book_toll_received(const sint64 amount, const waytype_t wt) { finance->book_toll_received(amount, wt); } void player_t::book_transported(const sint64 amount, const waytype_t wt, int index) { finance->book_transported(amount, wt, index); } void player_t::book_delivered(const sint64 amount, const waytype_t wt, int index) { finance->book_delivered(amount, wt, index); } const char* player_t::get_name() const { return translator::translate(player_name_buf); } void player_t::set_name(const char *new_name) { tstrncpy( player_name_buf, new_name, lengthof(player_name_buf) ); // update player window if (ki_kontroll_t *frame = dynamic_cast( win_get_magic(magic_ki_kontroll_t) ) ) { frame->update_data(); } } player_t::income_message_t::income_message_t( sint64 betrag, koord p ) { money_to_string(str, betrag/100.0); alter = 127; pos = p; amount = betrag; } void *player_t::income_message_t::operator new(size_t /*s*/) { return freelist_t::gimme_node(sizeof(player_t::income_message_t)); } void player_t::income_message_t::operator delete(void *p) { freelist_t::putback_node(sizeof(player_t::income_message_t),p); } void player_t::display_messages() { const viewport_t *vp = welt->get_viewport(); for(income_message_t* const m : messages) { const scr_coord scr_pos = vp->get_screen_coord(koord3d(m->pos,welt->lookup_hgt(m->pos)),koord(0,m->alter >> 4)) + scr_coord((get_tile_raster_width()-display_calc_proportional_string_len_width(m->str, 0x7FFF))/2,0); display_shadow_proportional_rgb( scr_pos.x, scr_pos.y, PLAYER_FLAG|color_idx_to_rgb(player_color_1+3), color_idx_to_rgb(COL_BLACK), m->str, true); if( m->pos.x < 3 || m->pos.y < 3 ) { // very close to border => renew background welt->set_background_dirty(); } } } void player_t::age_messages(uint32 /*delta_t*/) { for(slist_tpl::iterator iter = messages.begin(); iter != messages.end(); ) { income_message_t *m = *iter; m->alter -= 5; if(m->alter<-80) { iter = messages.erase(iter); delete m; } else { ++iter; } } } void player_t::add_message(sint64 betrag, koord k) { if( !messages.empty() && messages.back()->pos==k && messages.back()->alter==127 ) { // last message exactly at same place, not aged messages.back()->amount += betrag; money_to_string(messages.back()->str, messages.back()->amount/100.0); } else { // otherwise new message income_message_t *m = new income_message_t(betrag,k); messages.append( m ); } } void player_t::set_player_color(uint8 col1, uint8 col2) { player_color_1 = col1; player_color_2 = col2; display_set_player_color_scheme( player_nr, col1, col2 ); // update player window if (ki_kontroll_t* frame = dynamic_cast(win_get_magic(magic_ki_kontroll_t))) { frame->update_data(); } } void player_t::step() { } bool player_t::new_month() { // since the messages must remain on the screen longer ... static cbuffer_t buf; finance->new_month(); // new month has started => recalculate vehicle value calc_assets(); finance->calc_finance_history(); // Bankrupt ? if( finance->get_account_balance() < 0 ) { finance->increase_account_overdrawn(); if( !welt->get_settings().is_freeplay() && player_nr != 1 ) { if( welt->get_active_player_nr()==player_nr && !env_t::networkmode ) { if( finance->get_netwealth() < 0 ) { destroy_all_win(true); create_win({ display_get_width()/2-128, 40 }, new news_img("Bankrott:\n\nDu bist bankrott.\n"), w_info, magic_none); ticker::add_msg( translator::translate("Bankrott:\n\nDu bist bankrott.\n"), koord3d::invalid, PLAYER_FLAG | player_nr ); welt->stop(false); } else if( finance->get_netwealth()*10 < welt->get_settings().get_starting_money(welt->get_current_month()/12) ){ // tell the player (problem!) welt->get_message()->add_message( translator::translate("Net wealth less than 10%% of starting capital!"), koord3d::invalid, message_t::problems, PLAYER_FLAG | player_nr, IMG_EMPTY ); } else { // tell the player (just warning) buf.clear(); buf.printf( translator::translate("On loan since %i month(s)"), finance->get_account_overdrawn() ); welt->get_message()->add_message( buf, koord3d::invalid, message_t::ai, PLAYER_FLAG | player_nr, IMG_EMPTY ); } } // no assets => nothing to go bankrupt about again else if( finance->get_maintenance(TT_ALL) != 0 || finance->has_convoi() ) { // for AI, we only declare bankrupt, if total assets are below zero if( finance->get_netwealth() < 0 ) { return false; } // tell the current player (even during networkgames) if( welt->get_active_player_nr()==player_nr ) { if( finance->get_netwealth()*10 < welt->get_settings().get_starting_money(welt->get_current_month()/12) ){ // net wealth nearly spent (problem!) welt->get_message()->add_message( translator::translate("Net wealth near zero"), koord3d::invalid, message_t::problems, PLAYER_FLAG | player_nr, IMG_EMPTY ); } else { // just minus in account (just tell) buf.clear(); buf.printf( translator::translate("On loan since %i month(s)"), finance->get_account_overdrawn() ); welt->get_message()->add_message( buf, koord3d::invalid, message_t::ai, PLAYER_FLAG | player_nr, IMG_EMPTY ); } } } } } else { finance->set_account_overdrawn( 0 ); } if( env_t::networkmode && player_nr>1 && !active ) { // find out dummy companies (i.e. no vehicle running within x months) if( welt->get_settings().get_remove_dummy_player_months() && player_age >= welt->get_settings().get_remove_dummy_player_months() ) { bool no_cnv = true; const uint16 months = min( MAX_PLAYER_HISTORY_MONTHS, welt->get_settings().get_remove_dummy_player_months() ); for( uint16 m=0; mget_history_com_month(m, ATC_ALL_CONVOIS) ==0; } const uint16 years = max( MAX_PLAYER_HISTORY_YEARS, (welt->get_settings().get_remove_dummy_player_months() - 1) / 12 ); for( uint16 y=0; yget_history_com_year(y, ATC_ALL_CONVOIS)==0; } // never run a convoi => dummy if( no_cnv ) { return false; // remove immediately } } // find out abandoned companies (no activity within x months) if( welt->get_settings().get_unprotect_abandoned_player_months() && player_age >= welt->get_settings().get_unprotect_abandoned_player_months() ) { bool abandoned = true; const uint16 months = min( MAX_PLAYER_HISTORY_MONTHS, welt->get_settings().get_unprotect_abandoned_player_months() ); for( uint16 m = 0; m < months && abandoned; m++ ) { abandoned &= finance->get_history_veh_month(TT_ALL, m, ATV_NEW_VEHICLE)==0 && finance->get_history_veh_month(TT_ALL, m, ATV_CONSTRUCTION_COST)==0; } const uint16 years = min( MAX_PLAYER_HISTORY_YEARS, (welt->get_settings().get_unprotect_abandoned_player_months() - 1) / 12); for( uint16 y = 0; y < years && abandoned; y++ ) { abandoned &= finance->get_history_veh_year(TT_ALL, y, ATV_NEW_VEHICLE)==0 && finance->get_history_veh_year(TT_ALL, y, ATV_CONSTRUCTION_COST)==0; } // never changed convoi, never built => abandoned if( abandoned ) { if (env_t::server) { // server: unlock this player for all clients socket_list_t::unlock_player_all(player_nr, true); } // clients: local unlock pwd_hash.clear(); locked = false; unlock_pending = false; } } } // update line info simlinemgmt.new_month(); // subtract maintenance after bankruptcy check finance->book_account( -finance->get_maintenance_with_bits(TT_ALL) ); // company gets older ... player_age ++; return true; // still active } void player_t::calc_assets() { sint64 assets[TT_MAX]; for(int i=0; i < TT_MAX; ++i){ assets[i] = 0; } // all convois for(convoihandle_t const cnv : welt->convoys()) { if( cnv->get_owner() == this ) { sint64 restwert = cnv->calc_restwert(); assets[TT_ALL] += restwert; assets[finance->translate_waytype_to_tt(cnv->front()->get_desc()->get_waytype())] += restwert; } } // all vehicles stored in depot not part of a convoi for(depot_t* const depot : depot_t::get_depot_list()) { if( depot->get_owner_nr() == player_nr ) { for(vehicle_t* const veh : depot->get_vehicle_list()) { sint64 restwert = veh->calc_sale_value(); assets[TT_ALL] += restwert; assets[finance->translate_waytype_to_tt(veh->get_desc()->get_waytype())] += restwert; } } } finance->set_assets(assets); } void player_t::update_assets(sint64 const delta, const waytype_t wt) { finance->update_assets(delta, wt); } sint32 player_t::get_scenario_completion() const { return finance->get_scenario_completed(); } void player_t::set_scenario_completion(sint32 percent) { finance->set_scenario_completed(percent); } bool player_t::check_owner( const player_t *owner, const player_t *test ) { return owner == test || owner == NULL || test == welt->get_public_player(); } void player_t::ai_bankrupt() { player_t *const psplayer = welt->get_public_player(); DBG_MESSAGE("player_t::ai_bankrupt()","Removing convois"); for (size_t i = welt->convoys().get_count(); i-- != 0;) { convoihandle_t const cnv = welt->convoys()[i]; if(cnv->get_owner()!=this) { continue; } linehandle_t line = cnv->get_line(); cnv->self_destruct(); // convois not in depots must step to really get rid of them if( cnv.is_bound() && cnv->get_state() != convoi_t::INITIAL ) { cnv->step(); } // last vehicle on that connection (no line => railroad) if( !line.is_bound() || line->count_convoys()==0 ) { simlinemgmt.delete_line( line ); } } // remove headquarters pos headquarter_pos = koord::invalid; // remove all stops // first generate list of our stops slist_tpl halt_list; for(halthandle_t const halt : haltestelle_t::get_alle_haltestellen()) { if( halt->get_owner()==this ) { halt_list.append(halt); } } // ... and destroy them while (!halt_list.empty()) { halthandle_t h = halt_list.remove_first(); haltestelle_t::destroy( h ); } // transfer all ways in public stops belonging to me to no one for(halthandle_t const halt : haltestelle_t::get_alle_haltestellen()) { if( halt->get_owner()==welt->get_public_player() ) { // only concerns public stops tiles for(haltestelle_t::tile_t const& i : halt->get_tiles()) { grund_t const* const gr = i.grund; for( uint8 wnr=0; wnr<2; wnr++ ) { weg_t *w = gr->get_weg_nr(wnr); // make public if( w && w->get_owner()==this ) { // tunnels and bridges are handled later? (logic needs to be checked for correct maintenance costs) if (!gr->ist_bruecke() && !gr->ist_tunnel()) { sint32 const costs = w->get_desc()->get_maintenance(); waytype_t const wt = w->get_desc()->get_finance_waytype(); player_t::add_maintenance(this, -costs, wt); player_t::add_maintenance(psplayer, costs, wt); } w->set_owner(psplayer); } } } } } // deactivate active tool (remove dummy grounds) welt->set_tool(tool_t::general_tool[TOOL_QUERY], this); // next remove all ways, depot etc, that are not road or channels for( int y=0; yget_size().y; y++ ) { for( int x=0; xget_size().x; x++ ) { planquadrat_t *plan = welt->access(x,y); for (size_t b = plan->get_boden_count(); b-- != 0;) { grund_t *gr = plan->get_boden_bei(b); // remove tunnel and bridges first if( gr->obj_count()>0 && gr->obj_bei(0)->get_owner()==this && (gr->ist_bruecke() || gr->ist_tunnel()) ) { koord3d pos = gr->get_pos(); waytype_t wt = gr->hat_wege() ? gr->get_weg_nr(0)->get_waytype() : powerline_wt; if (gr->ist_bruecke()) { bridge_builder_t::remove( this, pos, wt ); // fails if powerline bridge somehow connected to powerline bridge of another player } else { tunnel_builder_t::remove( this, pos, wt, true ); } // maybe there are some objects left (station on bridge head etc) gr = plan->get_boden_in_hoehe(pos.z); if (gr == NULL) { continue; } } for (uint8 i = gr->obj_count(); i-- != 0;) { obj_t *obj = gr->obj_bei(i); if(obj->get_owner()==this) { sint32 costs = 0; waytype_t wt = ignore_wt; switch(obj->get_typ()) { case obj_t::roadsign: case obj_t::signal: case obj_t::airdepot: case obj_t::bahndepot: case obj_t::monoraildepot: case obj_t::tramdepot: case obj_t::strassendepot: case obj_t::schiffdepot: case obj_t::senke: case obj_t::pumpe: case obj_t::wayobj: case obj_t::label: obj->cleanup(this); delete obj; break; case obj_t::leitung: // do not remove powerline from bridges if(gr->ist_bruecke()) { costs = ((leitung_t*)obj)->get_desc()->get_maintenance(); add_maintenance(-costs, powerline_wt); psplayer->add_maintenance(costs, powerline_wt); obj->set_owner(psplayer); } else { obj->cleanup(this); delete obj; } break; case obj_t::gebaeude: hausbauer_t::remove( this, (gebaeude_t *)obj ); gr = plan->get_boden_bei(b); // fundament has now been replaced by normal ground break; case obj_t::way: { weg_t *w=(weg_t *)obj; // tunnels and bridges made public if (gr->ist_bruecke() || gr->ist_tunnel()) { w->set_owner(psplayer); } // roads and water ways also made public else if(w->get_waytype()==road_wt || w->get_waytype()==water_wt) { costs = w->get_desc()->get_maintenance(); wt = w->get_waytype(); add_maintenance(-costs, wt); psplayer->add_maintenance(costs, wt); w->set_owner(psplayer); } else { gr->weg_entfernen( w->get_waytype(), true ); } break; } case obj_t::bruecke: costs = ((bruecke_t*)obj)->get_desc()->get_maintenance(); wt = obj->get_waytype(); add_maintenance(-costs, wt); psplayer->add_maintenance(costs, wt); obj->set_owner(psplayer); break; case obj_t::tunnel: costs = ((tunnel_t*)obj)->get_desc()->get_maintenance(); wt = ((tunnel_t*)obj)->get_desc()->get_finance_waytype(); add_maintenance(-costs, wt); psplayer->add_maintenance(costs, wt); obj->set_owner(psplayer); break; default: obj->set_owner(psplayer); } } } // remove empty tiles (elevated ways) if (!gr->ist_karten_boden() && gr->obj_count()==0) { plan->boden_entfernen(gr); } } } } active = false; // make account negative if (finance->get_account_balance() > 0) { finance->book_account( -finance->get_account_balance() -1 ); } cbuffer_t buf; buf.printf( translator::translate("%s\nwas liquidated."), get_name() ); welt->get_message()->add_message( buf, koord3d::invalid, message_t::ai, PLAYER_FLAG|player_nr ); } void player_t::rdwr(loadsave_t *file) { xml_tag_t sss( file, "spieler_t" ); if(file->is_version_less(112, 5)) { sint64 konto = finance->get_account_balance(); file->rdwr_longlong(konto); finance->set_account_balance(konto); sint32 account_overdrawn = finance->get_account_overdrawn(); file->rdwr_long(account_overdrawn); finance->set_account_overdrawn( account_overdrawn ); } if(file->is_version_less(101, 0)) { // ignore steps sint32 ldummy=0; file->rdwr_long(ldummy); } if(file->is_version_less(99, 9)) { sint32 farbe; file->rdwr_long(farbe); player_color_1 = (uint8)farbe*2; player_color_2 = player_color_1+24; } else { file->rdwr_byte(player_color_1); file->rdwr_byte(player_color_2); } sint32 halt_count=0; if(file->is_version_less(99, 8)) { file->rdwr_long(halt_count); } if(file->is_version_less(112, 3)) { sint32 haltcount = 0; file->rdwr_long(haltcount); } // save all the financial statistics finance->rdwr( file ); file->rdwr_bool(active); // state is not saved anymore if(file->is_version_less(99, 14)) { sint32 ldummy=0; file->rdwr_long(ldummy); file->rdwr_long(ldummy); } // the AI stuff is now saved directly by the different AI if( file->is_version_less(101, 0)) { sint32 ldummy = -1; file->rdwr_long(ldummy); file->rdwr_long(ldummy); file->rdwr_long(ldummy); file->rdwr_long(ldummy); koord k(-1,-1); k.rdwr( file ); k.rdwr( file ); } if(file->is_loading()) { // halt_count will be zero for newer savegames DBG_DEBUG("player_t::rdwr()","player %i: loading %i halts.",welt->sp2num( this ),halt_count); for(int i=0; iis_version_less(86, 4)) { headquarter_level = 0; headquarter_pos = koord::invalid; } else { file->rdwr_long(headquarter_level); headquarter_pos.rdwr( file ); if(file->is_loading()) { if(headquarter_level<0) { headquarter_pos = koord::invalid; headquarter_level = 0; } } } // line management if(file->is_version_atleast(88, 3)) { simlinemgmt.rdwr(file,this); } if(file->is_version_atleast(102, 3)) { // password hash for( int i=0; i<20; i++ ) { file->rdwr_byte(pwd_hash[i]); } if( file->is_loading() ) { // disallow all actions, if password set (might be unlocked by password gui ) locked = !pwd_hash.empty(); } } // save the name too if( file->is_version_atleast(102, 4) ) { file->rdwr_str( player_name_buf, lengthof(player_name_buf) ); } // save age if( file->is_version_atleast(112, 2) ) { file->rdwr_short( player_age ); } } void player_t::finish_rd() { simlinemgmt.finish_rd(); display_set_player_color_scheme( player_nr, player_color_1, player_color_2 ); // recalculate vehicle value calc_assets(); finance->calc_finance_history(); } void player_t::rotate90( const sint16 y_size ) { simlinemgmt.rotate90( y_size ); headquarter_pos.rotate90( y_size ); } void player_t::report_vehicle_problem(convoihandle_t cnv,const koord3d position) { switch(cnv->get_state()) { case convoi_t::NO_ROUTE: DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s can't find a route to (%i,%i)!", cnv->get_name(),position.x,position.y); { cbuffer_t buf; buf.printf( translator::translate("Vehicle %s can't find a route!"), cnv->get_name()); welt->get_message()->add_message( (const char *)buf, cnv->get_pos(), message_t::problems, PLAYER_FLAG | player_nr, cnv->front()->get_base_image()); } break; case convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH: case convoi_t::CAN_START_ONE_MONTH: case convoi_t::CAN_START_TWO_MONTHS: DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s stuck!", cnv->get_name(),position.x,position.y); { cbuffer_t buf; buf.printf( translator::translate("Vehicle %s is stucked!"), cnv->get_name()); welt->get_message()->add_message( (const char *)buf, cnv->get_pos(), message_t::warnings, PLAYER_FLAG | player_nr, cnv->front()->get_base_image()); } break; default: DBG_MESSAGE("player_t::report_vehicle_problem","Vehicle %s, state %i!", cnv->get_name(), cnv->get_state()); } (void)position; } void player_t::init_undo( waytype_t wtype, unsigned short max ) { // only human player // allow for UNDO for real player DBG_MESSAGE("player_t::int_undo()","undo tiles %i",max); last_built.clear(); last_built.reserve(max+1); if(max>0) { undo_type = wtype; } } void player_t::add_undo(koord3d k) { if(last_built.get_capacity()>0) { //DBG_DEBUG("player_t::add_undo()","tile at (%i,%i)",k.x,k.y); last_built.append(k); } } sint64 player_t::undo() { if (last_built.empty()) { // nothing to UNDO return false; } // check, if we can still do undo for(koord3d const& i : last_built) { grund_t* const gr = welt->lookup(i); if(gr==NULL || gr->get_typ()!=grund_t::boden) { // well, something was built here ... so no undo last_built.clear(); return false; } // we allow ways, unimportant stuff but no vehicles, signals, wayobjs etc if(gr->obj_count()>0) { for( unsigned i=0; iobj_count(); i++ ) { switch(gr->obj_bei(i)->get_typ()) { // these are allowed case obj_t::zeiger: case obj_t::cloud: case obj_t::leitung: case obj_t::pillar: case obj_t::way: case obj_t::label: case obj_t::crossing: case obj_t::pedestrian: case obj_t::road_user: case obj_t::movingobj: break; // special case airplane // they can be everywhere, so we allow for everything but runway undo case obj_t::air_vehicle: { if(undo_type!=air_wt) { break; } const air_vehicle_t* aircraft = obj_cast(gr->obj_bei(i)); // flying aircrafts are ok if(!aircraft->is_on_ground()) { break; } } /* FALLTHROUGH */ // all other are forbidden => no undo any more default: last_built.clear(); return false; } } } } // ok, now remove everything last built sint64 cost=0; for(koord3d const& i : last_built) { grund_t* const gr = welt->lookup(i); if( undo_type != powerline_wt ) { cost += gr->weg_entfernen(undo_type,true); } else { if (leitung_t* lt = gr->get_leitung()) { cost += lt->get_desc()->get_price(); lt->cleanup(NULL); delete lt; } } } last_built.clear(); return cost; } void player_t::tell_tool_result(tool_t *tool, koord3d, const char *err) { /* tools can return three kinds of messages * NULL = success * "" = failure, but just do not try again * "bla" error message, which should be shown */ if (welt->get_active_player()==this) { if(err==NULL) { if(tool->ok_sound!=NO_SOUND) { sound_play(tool->ok_sound,255,TOOL_SOUND); } } else if(*err!=0) { // something went really wrong sound_play( SFX_FAILURE, 255, TOOL_SOUND ); // look for coordinate in error message // syntax: either @x,y or (x,y) open_error_msg_win(err); } } } void player_t::book_convoi_number(int count) { finance->book_convoi_number(count); } double player_t::get_account_balance_as_double() const { return finance->get_account_balance() / 100.0; } int player_t::get_account_overdrawn() const { return finance->get_account_overdrawn(); } bool player_t::has_money_or_assets() const { return finance->has_money_or_assets(); } bool player_t::can_afford(sint64 cost) const { return welt->get_settings().is_freeplay() || is_public_service() || get_finance()->get_netwealth() >= -cost; } bool player_t::is_public_service() const { return get_player_nr() == PLAYER_PUBLIC_NR; } simutrans-124.3/src/simutrans/player/simplay.h000066400000000000000000000227061474050137200215210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef PLAYER_SIMPLAY_H #define PLAYER_SIMPLAY_H #include "../utils/sha1_hash.h" #include "../simtypes.h" #include "../simlinemgmt.h" #include "../halthandle.h" #include "../convoihandle.h" #include "../dataobj/koord.h" #include "../tpl/slist_tpl.h" #include "../tpl/vector_tpl.h" class karte_ptr_t; class fabrik_t; class koord3d; class tool_t; class finance_t; #define PLAYER_HUMAN_NR (0) #define PLAYER_PUBLIC_NR (1) /** * Class to hold information about one player/company. AI players are derived from this class. */ class player_t { public: enum { EMPTY = 0, HUMAN = 1, AI_GOODS = 2, AI_PASSENGER = 3, AI_SCRIPTED = 4, MAX_AI, PASSWORD_PROTECTED = 128 }; protected: char player_name_buf[256]; /* "new" finance history */ finance_t *finance; /** * Die Welt in der gespielt wird. */ static karte_ptr_t welt; // when was the company founded uint16 player_age; /** * Floating massages for all players here */ class income_message_t { public: char str[33]; koord pos; sint64 amount; sint8 alter; income_message_t() { str[0]=0; alter=127; pos=koord::invalid; amount=0; } income_message_t( sint64 betrag, koord pos ); void * operator new(size_t s); void operator delete(void *p); }; slist_tpl messages; /** * Creates new income message entry or merges with existing one if the * most recent one is at the same coordinate */ void add_message(sint64 amount, koord k); /** * Displays amount of money when koordinates are on screen */ void add_money_message(sint64 amount, koord k); /** * Colors of the player */ uint8 player_color_1, player_color_2; /** * Player number; only player 0 can do interaction */ uint8 player_nr; /** * Adds some amount to the maintenance costs. * * @param change the change * @param wt * @return the new maintenance costs */ sint64 add_maintenance(sint64 change, waytype_t const wt=ignore_wt); /** * Is this player an AI player? */ bool active; /** * Are this player allowed to do any changes? */ bool locked; bool unlock_pending; // contains the password hash for local games pwd_hash_t pwd_hash; public: /** * Sums up "count" with number of convois in statistics, * supersedes buche( count, COST_ALL_CONVOIS). */ void book_convoi_number(int count); /** * Adds construction costs to accounting statistics. * * @param player * @param amount How much does it cost * @param k * @param wt type of transport */ static void book_construction_costs(player_t * const player, const sint64 amount, const koord k, const waytype_t wt=ignore_wt); /** * Accounts bought/sold vehicles. * * @param price money used for purchase of vehicle, * negative value = vehicle bought, * positive value = vehicle sold * @param k * @param wt type of transport for accounting purpose */ void book_new_vehicle(const sint64 price, const koord k, const waytype_t wt=ignore_wt); /** * Adds income to accounting statistics. * * @param amount earned money * @param k * @param wt transport type used in accounting statistics * @param cathegory parameter * 0 ... passenger * 1 ... mail * 2 ... good (and powerlines revenue) */ void book_revenue(const sint64 amount, const koord k, const waytype_t wt=ignore_wt, sint32 cathegory=2); /** * Adds running costs to accounting statistics. * @param amount How much does it cost * @param wt type of transport used for accounting statistics */ void book_running_costs(const sint64 amount, const waytype_t wt=ignore_wt); /** * Books toll paid by our company to someone else. * @param amount money paid to our company * @param wt type of transport used for accounting statistics */ void book_toll_paid(const sint64 amount, const waytype_t wt=ignore_wt); /** * Books toll paid to our company by someone else. * @param amount money paid for usage of our roads,railway,channels, ... ; positive sign * @param wt type of transport used for accounting statistics */ void book_toll_received(const sint64 amount, waytype_t wt=ignore_wt); /** * Add amount of transported passenger, mail, goods to accounting statistics. * @param amount sum of money * @param wt way type * @param index 0 = passenger, 1 = mail, 2 = goods */ void book_transported(const sint64 amount, const waytype_t wt=ignore_wt, int index=2); /** * Add amount of delivered passenger, mail, goods to accounting statistics. * @param amount sum of money * @param wt way type * @param index 0 = passenger, 1 = mail, 2 = goods */ void book_delivered(const sint64 amount, const waytype_t wt=ignore_wt, int index=2); bool has_money_or_assets() const; /** * Test if the player has sufficient funds for an action. * Returns true if the player has the funds or does not need to. * @param cost the amount of funds that want to be added to the balance */ bool can_afford(sint64 cost) const; finance_t * get_finance() const { return finance; } virtual bool set_active( bool b ) { return active = b; } bool is_active() const { return active; } bool is_locked() const { return locked; } bool is_unlock_pending() const { return unlock_pending; } void unlock(bool unlock_, bool unlock_pending_=false) { locked = !unlock_; unlock_pending = unlock_pending_; } void check_unlock( const pwd_hash_t& hash ) { locked = (pwd_hash != hash); } // some routine needs this for direct manipulation pwd_hash_t& access_password_hash() { return pwd_hash; } // this type of AIs identifier virtual uint8 get_ai_id() const { return HUMAN; } simlinemgmt_t simlinemgmt; /// Age messages (move them upwards) void age_messages(uint32 delta_t); /// Handles player colors uint8 get_player_color1() const { return player_color_1; } uint8 get_player_color2() const { return player_color_2; } void set_player_color(uint8 col1, uint8 col2); /** * @return the name of the player; "player -1" sits in front of the screen */ const char* get_name() const; void set_name(const char *); sint8 get_player_nr() const {return player_nr; } /** * Test if this player is a public service player. * @return true if the player is a public service player, otherwise false. */ bool is_public_service() const; /** * return true, if the owner is none, myself or player(1), i.e. the ownership can be taken by player test */ static bool check_owner( const player_t *owner, const player_t *test ); /** * @param player_nr Number assigned to this player - it's an ID. */ player_t(uint8 player_nr ); virtual ~player_t(); static inline sint64 add_maintenance(player_t *player, sint64 const change, waytype_t const wt=ignore_wt) { if(player) { return player->add_maintenance(change, wt); } return 0; } /** * Cached value of scenario completion percentage. * To get correct values for clients call scenario_t::get_completion instead. */ sint32 get_scenario_completion() const; void set_scenario_completion(sint32 percent); /** * @return Account balance as a double (floating point) value */ double get_account_balance_as_double() const; /** * @return true when account balance is overdrawn */ int get_account_overdrawn() const; /** * Displays messages from the queue of the player on the screen * Show income messages */ void display_messages(); /** * Called often by simworld.cc during simulation * @note Any action goes here (only need for AI at the moment) */ virtual void step(); /** * Called monthly by simworld.cc during simulation * @returns false if player has to be removed (bankrupt/inactive) */ virtual bool new_month(); /** * Called yearly by simworld.cc during simulation */ virtual void new_year() {} /** * Stores/loads the player state * @param file where the data will be saved/loaded */ virtual void rdwr(loadsave_t *file); /* * Called after game is fully loaded; */ virtual void finish_rd(); virtual void rotate90( const sint16 y_size ); /** * Calculates the assets of the player */ void calc_assets(); /** * Updates the assets value of the player */ void update_assets(sint64 const delta, const waytype_t wt = ignore_wt); /** * Report the player one of his vehicles has a problem */ virtual void report_vehicle_problem(convoihandle_t cnv,const koord3d position); /** * Tells the player the result of tool-work commands. * If player is active then play sound, popup error msg etc. */ void tell_tool_result(tool_t *tool, koord3d pos, const char *err); /** * Tells the player that the factory * is going to be deleted (flag==0) */ enum notification_factory_t { notify_delete // notified immediately before object is deleted (and before nulled in the slist_tpl<>)! }; virtual void notify_factory(notification_factory_t, const fabrik_t*) {} private: /// undo information vector_tpl last_built; waytype_t undo_type; public: /** * Function for UNDO */ void init_undo(waytype_t t, unsigned short max ); /** * Function for UNDO */ void add_undo(koord3d k); /** * Function for UNDO */ sint64 undo(); private: // headquarters stuff sint32 headquarter_level; koord headquarter_pos; public: void add_headquarter(short hq_level, koord hq_pos) { headquarter_level = hq_level; headquarter_pos = hq_pos; } koord get_headquarter_pos() const { return headquarter_pos; } short get_headquarter_level() const { return headquarter_level; } void ai_bankrupt(); }; #endif simutrans-124.3/src/simutrans/script/000077500000000000000000000000001474050137200176735ustar00rootroot00000000000000simutrans-124.3/src/simutrans/script/api/000077500000000000000000000000001474050137200204445ustar00rootroot00000000000000simutrans-124.3/src/simutrans/script/api/api.h000066400000000000000000000020501474050137200213630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_API_H #define SCRIPT_API_API_H /** @file api.h declarations of export functions. */ #include "../../../squirrel/squirrel.h" #include "api_command.h" void export_city(HSQUIRRELVM vm); void export_control(HSQUIRRELVM vm); void export_convoy(HSQUIRRELVM vm); void export_factory(HSQUIRRELVM vm); void export_goods_desc(HSQUIRRELVM vm); void export_gui(HSQUIRRELVM vm, bool scenario); void export_halt(HSQUIRRELVM vm); void export_line(HSQUIRRELVM vm); void export_map_objects(HSQUIRRELVM vm); void export_player(HSQUIRRELVM vm, bool scenario); void export_scenario(HSQUIRRELVM vm); void export_settings(HSQUIRRELVM vm); void export_schedule(HSQUIRRELVM vm); void export_simple(HSQUIRRELVM vm); void export_string_methods(HSQUIRRELVM vm); // api_scenario.cc void export_tiles(HSQUIRRELVM vm); void export_world(HSQUIRRELVM vm, bool scenario); void export_pathfinding(HSQUIRRELVM vm); void export_global_constants(HSQUIRRELVM vm); #endif simutrans-124.3/src/simutrans/script/api/api_base.h000066400000000000000000000041601474050137200223610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ // This file should not be compiled. It wont compile either. /** @file api_base.h documents base classes that are defined elsewhere. */ #ifdef DOXYGEN /** * Translatable text. * * Class takes raw string. It can do variable substitution. * * When transferred to simutrans: * -# the translation of the string will be fetched * -# variables will be substituted * * Translated strings will be taken from tab-files inside the scenario_name/ directory. * * Usage: * @code * local text = ttext("You have {N} trains running.") * text.N = 20; * // if returned to simutrans, the output will be "You have 20 trains running." * @endcode */ class ttext { // begin_class("ttext", 0) /** * Constructor. * @param text raw string to be translated. * @typemask (string) */ register_function(vm,, "constructor"); /** * Does translation and variable substitution. * @returns Translated string with all variables replaced by their values. * @typemask string() */ register_function("to_string"); }; // end_class /** * Loads text from a file. * * It does variable substitution as ttext. */ class ttextfile : public ttext { // begin_class("ttextfile", "ttext") /** * Constructor. Text is taken from a file. * * The file is searched in the following paths: * -# scenario_name/iso/ .. iso is language ISO abbreviation * -# scenario_name/en/ .. fall-back: English version * -# scenario_name/ * * @param file filename * @typemask (string) */ register_function(vm,, "constructor"); }; // end_class /** * Class that implements an extended get-method. * * If child class has method * @code * function get_something() * @endcode * then function result can be accessed by * @code * local result = some_instance.something * @endcode * as if the class has a member variable. * * * Example: * * @code * local player = player_x(0) * local cash1 = player.get_cash()[0] * local cash2 = player.cash[0] * // now cash1 == cash2 * @endcode */ class extend_get { // begin_class("extend_get", 0) }; // end_class #endif simutrans-124.3/src/simutrans/script/api/api_city.cc000066400000000000000000000210561474050137200225600ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_city.cc exports city related functions. */ #include "get_next.h" #include "../api_class.h" #include "../api_function.h" #include "../../world/simcity.h" #include "../../tool/simmenu.h" #include "../../world/simworld.h" #include "../../dataobj/scenario.h" using namespace script_api; vector_tpl const& get_city_stat(stadt_t* city, bool monthly, sint32 INDEX) { static vector_tpl v; v.clear(); if (city && 0<=INDEX && INDEXget_finance_history_month(i, INDEX) ); } else { v.append( city->get_finance_history_year(i, INDEX) ); } } } return v; } SQInteger world_get_next_city(HSQUIRRELVM vm) { return generic_get_next(vm, welt->get_cities().get_count()); } namespace script_api { declare_fake_param(city_list_t, "city_list_x"); } stadt_t* world_get_city_by_index(city_list_t, uint32 index) { return index < welt->get_cities().get_count() ? welt->get_cities()[index] : NULL; } call_tool_init set_citygrowth(stadt_t *city, bool allow) { cbuffer_t buf; buf.printf("g%hi,%hi,%hi", city->get_pos().x, city->get_pos().y, (short)allow ); return call_tool_init(TOOL_CHANGE_CITY | SIMPLE_TOOL, (const char*)buf, 0, welt->get_public_player()); } call_tool_init city_set_name(stadt_t* city, const char* name) { return command_rename(welt->get_public_player(), 't', welt->get_cities().index_of(city), name); } call_tool_work city_change_size(stadt_t *city, sint32 delta) { cbuffer_t buf; buf.printf("%i", delta); grund_t *gr = welt->lookup_kartenboden(city->get_pos()); if (gr) { return call_tool_work(TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL, (const char*)buf, 0, welt->get_public_player(), gr->get_pos()); } else { return "Invalid coordinate."; } } void export_city(HSQUIRRELVM vm) { /** * Implements iterator to iterate through the list of all cities on the map. * * Usage: * @code * local list = city_list_x() * foreach(city in list) { * ... // city is an instance of the city_x class * } * @endcode */ begin_class(vm, "city_list_x", 0); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, world_get_next_city, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_method(vm, &world_get_city_by_index, "_get", true); end_class(vm); /** * Class to access cities. */ begin_class(vm, "city_x", "coord,extend_get,ingame_object"); /** * Constructor. * @param x x-coordinate * @param y y-coordinate * @typemask (integer,integer) */ // actually defined in simutrans/script/script_base.nut // register_function(..., "constructor", ...); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Return name of city * @returns name */ register_method(vm, &stadt_t::get_name, "get_name"); /** * Change city name. * @ingroup rename_func */ register_method(vm, &city_set_name, "set_name", true); /** * Get monthly statistics of number of citizens. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_citizens", freevariable(true, HIST_CITIZENS), true); /** * Get monthly statistics of number of city growth. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_growth", freevariable(true, HIST_GROWTH), true ); /** * Get monthly statistics of number of buildings. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_buildings", freevariable(true, HIST_BUILDING), true ); /** * Get monthly statistics of number of citycars started. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_citycars", freevariable(true, HIST_CITYCARS), true ); /** * Get monthly statistics of number of transported passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_transported_pax", freevariable(true, HIST_PAS_TRANSPORTED), true ); /** * Get monthly statistics of number of generated passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_generated_pax", freevariable(true, HIST_PAS_GENERATED), true ); /** * Get monthly statistics of number of transported mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_transported_mail", freevariable(true, HIST_MAIL_TRANSPORTED), true ); /** * Get monthly statistics of number of generated mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_city_stat, "get_generated_mail", freevariable(true, HIST_MAIL_GENERATED), true ); /** * Get per year statistics of number of citizens. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_citizens", freevariable(false, HIST_CITIZENS), true ); /** * Get per year statistics of number of city growth. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_growth", freevariable(false, HIST_GROWTH), true ); /** * Get per year statistics of number of buildings. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_buildings", freevariable(false, HIST_BUILDING), true ); /** * Get per year statistics of number of citycars started. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_citycars", freevariable(false, HIST_CITYCARS), true ); /** * Get per year statistics of number of transported passengers. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_transported_pax", freevariable(false, HIST_PAS_TRANSPORTED), true ); /** * Get per year statistics of number of generated passengers. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_generated_pax", freevariable(false, HIST_PAS_GENERATED), true ); /** * Get per year statistics of number of transported mail. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_transported_mail", freevariable(false, HIST_MAIL_TRANSPORTED), true ); /** * Get per year statistics of number of generated mail. * @returns array, index [0] corresponds to current year */ register_method_fv(vm, &get_city_stat, "get_year_generated_mail", freevariable(false, HIST_MAIL_GENERATED), true ); /** * Check city growth allowance. * @returns whether city growth is enabled for this city */ register_method(vm, &stadt_t::get_citygrowth, "get_citygrowth_enabled"); /** * Position of town-hall. * @returns town-hall position */ register_method(vm, &stadt_t::get_pos, "get_pos"); /** * City limits. * * City area is between get_pos_nw().x and get_pos_se().x, and get_pos_nw().y and get_pos_se().y. * * It is @b not guaranteed that get_pos_nw().x <= get_pos_se().x or get_pos_nw().y <= get_pos_se().y holds! * @returns coordinate of one corner of city limit */ register_method(vm, &stadt_t::get_linksoben, "get_pos_nw"); /** * City limits. * * City area is between get_pos_nw().x and get_pos_se().x, and get_pos_nw().y and get_pos_se().y. * * It is @b not guaranteed that get_pos_nw().x <= get_pos_se().x or get_pos_nw().y <= get_pos_se().y holds! * @returns coordinate of another corner of city limit */ register_method(vm, &stadt_t::get_rechtsunten, "get_pos_se"); /** * Change city size. City will immediately grow. * @param delta City size will change by this number. * @ingroup game_cmd */ register_method(vm, city_change_size, "change_size", true); /** * Enable or disable city growth. * @ingroup game_cmd */ register_method(vm, &set_citygrowth, "set_citygrowth_enabled", true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_command.cc000066400000000000000000000477071474050137200232410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_command.cc exports the command_x class, which encodes the tools to manipulate a game */ #include "api_command.h" #include "api_obj_desc_base.h" #include "api_simple.h" #include "../api_param.h" #include "../api_class.h" #include "../api_function.h" #include "../../tool/simmenu.h" #include "../../tool/simtool.h" #include "../../world/simworld.h" #include "../../dataobj/environment.h" #include "../../script/script.h" #include "../../descriptor/bridge_desc.h" #include "../../descriptor/building_desc.h" #include "../../descriptor/roadsign_desc.h" #include "../../descriptor/way_obj_desc.h" #include // auto_ptr using namespace script_api; SQInteger command_constructor(HSQUIRRELVM vm) { // create tool uint16 id = param::get(vm, 2); if (id & GENERAL_TOOL) { // we do not want scripts to open dialogues or quitting the game etc if (id == (TOOL_EXEC_TWO_CLICK_SCRIPT | GENERAL_TOOL)) { // do not create & attach instance, will be done separately return 0; } else { if (tool_t *tool = create_tool(id)) { my_tool_t* mtool = new my_tool_t(tool); attach_instance(vm, 1, mtool); return 0; } } } return sq_raise_error(vm, "Invalid tool called (%d / 0x%x)", id & 0xfff, id); } SQInteger param::push(HSQUIRRELVM vm, call_tool_init v) { if (v.error) { return sq_raise_error(vm, *v.error ? v.error : "Strange error occurred"); } // create tool, if necessary, delete on exit std::unique_ptr our_tool; tool_t *tool = v.tool; if (tool == NULL) { our_tool.reset(v.create_tool()); tool = our_tool.get(); } if (tool == NULL) { return sq_raise_error(vm, "Called null tool"); } // set correct flags tool->flags &= (tool_t::WFL_SHIFT | tool_t:: WFL_CTRL); tool->flags |= tool_t::WFL_SCRIPT; // get player parameter player_t *player = get_my_player(vm); if (player == NULL) { player = v.player; // must be scenario - set flag tool->flags |= tool_t::WFL_NO_CHK; } #if 0 // sanity check if (player == NULL) { return sq_raise_error(vm, "Called tool with player == null"); } #endif // check if calling suspendable tools is blocked if (!v.no_block) { if (const char* blocker = env_t::networkmode ? sq_get_suspend_blocker(vm) : NULL) { return sq_raise_error(vm, "Cannot call this tool from within `%s'.", blocker); } } // register this tool call for callback with this id uint32 callback_id = suspended_scripts_t::get_unique_key(tool); tool->callback_id = callback_id; // HACK call karte_t::set_tool bool suspended; welt->set_tool_api(tool, player, suspended); // in networkmode, call is suspended if (suspended && !v.no_block) { // register for wakeup suspended_scripts_t::register_suspended_script(callback_id, vm); // suspend vm for now, after wakeup it returns to the script return sq_suspendvm(vm); } else { bool res = true; return param::push(vm, res); } } call_tool_init script_api::command_rename(player_t *owner, char what, koord3d pos, const char* name) { // build param string (see tool_rename_t::init) cbuffer_t buf; buf.printf( "%c%s,%s", what, pos.get_str(), name); // empty name? trigger error by setting id to zero uint16 tool_id = name ? TOOL_RENAME | SIMPLE_TOOL : 0; return call_tool_init(tool_id, (const char*)buf, 0, owner); } call_tool_init script_api::command_rename(player_t *owner, char what, uint32 id, const char* name) { // build param string (see tool_rename_t::init) cbuffer_t buf; buf.printf( "%c%u,%s", what, id, name); // empty name? trigger error by setting id to zero uint16 tool_id = name ? TOOL_RENAME | SIMPLE_TOOL : 0; return call_tool_init(tool_id, (const char*)buf, 0, owner); } SQInteger command_work(HSQUIRRELVM vm) { tool_t *tool = param::get(vm, 1); player_t *player = param::get(vm, 2); koord3d pos1 = param::get(vm, 3); SQInteger top = sq_gettop(vm); // top >=3 /* three possible calling conventions: * (1) tool.work(pl, pos) * (2) tool.work(pl, pos, param) * (3) tool.work(pl, pos, pos2, param) */ const char* default_param = top>3 ? param::get(vm, top) : NULL; koord3d pos2 = top>4 ? param::get(vm, 4) : koord3d::invalid; bool twoclick = top>4; // save & set default_param my_tool_t *mtool = get_attached_instance(vm, 1, param::tag()); if (mtool == NULL) { return sq_raise_error(vm, "Called from an instance different to tool_x"); } plainstring &pdefault_param = mtool->default_param; pdefault_param = default_param; // copy tool->set_default_param( (const char*)pdefault_param ); // .. and set param if (!twoclick) { return param::push(vm, call_tool_work(tool, player, pos1)); } else { return param::push(vm, call_tool_work(tool, player, pos1, pos2)); } } tool_t * call_tool_base_t::create_tool() { tool_t *tool = ::create_tool(tool_id); if (tool) { tool->set_default_param(default_param); tool->flags = flags; } return tool; } SQInteger param::push(HSQUIRRELVM vm, call_tool_work v) { if (v.error) { return sq_raise_error(vm, *v.error ? v.error : "Strange error occurred"); } // create tool, if necessary, delete on exit std::unique_ptr our_tool; tool_t *tool = v.tool; if (tool == NULL) { our_tool.reset(v.create_tool()); tool = our_tool.get(); } if (tool == NULL) { return sq_raise_error(vm, "Called null tool"); } // set correct flags tool->flags &= (tool_t::WFL_SHIFT | tool_t:: WFL_CTRL); tool->flags |= tool_t::WFL_SCRIPT; // get player parameter player_t *player = get_my_player(vm); if (player == NULL) { player = v.player; // must be scenario - set flag tool->flags |= tool_t::WFL_NO_CHK; } #if 0 // sanity check if (player == NULL) { return sq_raise_error(vm, "Called tool with player == null"); } #endif uint8 flags = tool->flags; // might be reset by init() // call init before work (but check network safety) if (!tool->is_init_keeps_game_state()) { return sq_raise_error(vm, "Initializing tool has side effects"); } if (!tool->init(player)) { return sq_raise_error(vm, "Error during initializing tool"); } // set flags tool->flags = flags; // test work if (tool->is_work_keeps_game_state() || (!v.twoclick && tool->is_work_here_keeps_game_state(player, v.start))) { return sq_raise_error(vm, "Tool has no effects"); } // two-click tool if (v.twoclick) { if (dynamic_cast(tool)==NULL) { return sq_raise_error(vm, "Cannot call this tool with two coordinates"); } if (!tool->is_work_here_keeps_game_state(player, v.start)) { return sq_raise_error(vm, "First click has side effects"); } } // check if calling suspendable tools is blocked if (!v.no_block) { if (const char* blocker = env_t::networkmode ? sq_get_suspend_blocker(vm) : NULL) { return sq_raise_error(vm, "Cannot call this tool from within `%s'.", blocker); } } bool suspended = false; const char* err = NULL; // first click of two_click_tool_t if (v.twoclick) { err = welt->call_work_api(tool, player, v.start, suspended); assert(!suspended); } // call the work that has effects if (err == NULL) { // register this tool call for callback with this id uint32 callback_id = suspended_scripts_t::get_unique_key(tool); tool->callback_id = callback_id; err = welt->call_work_api(tool, player, v.twoclick ? v.end : v.start, suspended); if (suspended && !v.no_block) { // register for wakeup suspended_scripts_t::register_suspended_script(callback_id, vm); // suspend vm for now, after wakeup it returns to the script return sq_suspendvm(vm); } } // return error message or NULL if tool was called return param::push(vm, err); } uint8 get_flags(tool_t *tool) { return tool->flags & (tool_t::WFL_SHIFT | tool_t:: WFL_CTRL); } void set_flags(tool_t *tool, uint8 flags) { tool->flags = flags & (tool_t::WFL_SHIFT | tool_t:: WFL_CTRL); } void* script_api::param::tag() { return (void*)param::get; } const char* is_available(const obj_desc_timelined_t* desc) { return desc->is_available(welt->get_timeline_year_month()) ? NULL : "Object not available (retired or future)."; } call_tool_work build_way(player_t* pl, koord3d start, koord3d end, const way_desc_t* way, bool straight, bool keep_city_roads) { if (way == NULL) { return call_tool_work("No way provided"); } if (const char* err = is_available(way)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_WAY | GENERAL_TOOL, way->get_name(), (straight ? 2 : 0) + (keep_city_roads ? 1 : 0), pl, start, end); } call_tool_work build_wayobj(player_t* pl, koord3d start, koord3d end, const way_obj_desc_t* wayobj) { if (wayobj == NULL) { return call_tool_work("No wayobj provided"); } if (const char* err = is_available(wayobj)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_WAYOBJ | GENERAL_TOOL, wayobj->get_name(), 0, pl, start, end); } typedef call_tool_work(*bsr_type)(player_t*, koord3d, const building_desc_t*, sint16); call_tool_work build_station_rotation(player_t* pl, koord3d pos, const building_desc_t* building, sint16 rot) { // rotation: SENW -> 0123, see station_building_select_t if (building == NULL || !building->is_transport_building()) { return call_tool_work("No building provided"); } if (const char* err = is_available(building)) { return call_tool_work(err); } static cbuffer_t buf; buf.clear(); if (rot >= 0) { buf.printf("%s,%i", building->get_name(), rot); } else { buf.printf("%s", building->get_name()); } return call_tool_work(TOOL_BUILD_STATION | GENERAL_TOOL, buf, 0, pl, pos); } SQInteger command_build_station(HSQUIRRELVM vm) { /* possible calling conventions: * * build_station(player, pos, desc) - top == 4 * build_station(player, pos, desc, layout ) - top == 5 */ if (sq_gettop(vm) == 4) { // layout parameter missing, push default value sq_pushinteger(vm, -1); } return embed_call_t::call_function(vm, build_station_rotation, false); } call_tool_work build_depot(player_t* pl, koord3d pos, const building_desc_t* building) { if (building == NULL || !building->is_depot()) { return call_tool_work("No depot provided"); } if (const char* err = is_available(building)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_DEPOT | GENERAL_TOOL, building->get_name(), 0, pl, pos); } call_tool_work build_bridge(player_t* pl, koord3d start, koord3d end, const bridge_desc_t* bridge) { if (bridge == NULL) { return call_tool_work("No bridge provided"); } if (const char* err = is_available(bridge)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_BRIDGE | GENERAL_TOOL, bridge->get_name(), 2, pl, start, end); } call_tool_work build_bridge_at(player_t* pl, koord3d start, const bridge_desc_t* bridge) { if (bridge == NULL) { return call_tool_work("No bridge provided"); } if (const char* err = is_available(bridge)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_BRIDGE | GENERAL_TOOL, bridge->get_name(), 0, pl, start); } call_tool_work set_slope(player_t* pl, koord3d start, my_slope_t slope) { // communicate per default_param static char buf[8]; sprintf(buf, "%2d", (uint8)slope); static tool_setslope_t tool; // we do not want our slopes translated to double-height (even for single-height paksets), they are already in the double-height system tool.old_slope_compatibility_mode = false; tool.set_default_param(buf); return call_tool_work(&tool, pl, start); } call_tool_work restore_slope(player_t* pl, koord3d start) { return call_tool_work(TOOL_RESTORESLOPE | GENERAL_TOOL, "", 0, pl, start); } const char* can_set_slope(player_t* pl, koord3d pos, my_slope_t slope) { return tool_setslope_t::tool_set_slope_work(pl, pos, slope, false /* compatibility */, true /* check */); } sint64 set_slope_get_price(my_slope_t slope) { return slope == RESTORE_SLOPE ? -welt->get_settings().cst_alter_land : -welt->get_settings().cst_set_slope; } call_tool_work build_sign_at(player_t* pl, koord3d start, const roadsign_desc_t* sign) { if (sign == NULL) { return call_tool_work("No sign provided"); } if (const char* err = is_available(sign)) { return call_tool_work(err); } return call_tool_work(TOOL_BUILD_ROADSIGN | GENERAL_TOOL, sign->get_name(), 0, pl, start); } call_tool_work change_climate_at(player_t* pl, koord3d start, int climate) { if (climate < water_climate || climate >= MAX_CLIMATES) { return call_tool_work("Invalid climate number provided"); } // communicate per default_param static cbuffer_t param; param.clear(); param.printf("%d", climate); return call_tool_work(TOOL_SET_CLIMATE | GENERAL_TOOL, param, 0, pl, start, start); } call_tool_work lower_raise(player_t* pl, koord3d pos, bool lower) { // need to transform coordinate to grid coordinates switch(coordinate_transform_t::get_rotation()) { case 1: pos += koord(1,0); break; case 2: pos += koord(1,1); break; case 3: pos += koord(0,1); break; default:; } return call_tool_work((lower ? TOOL_LOWER_LAND : TOOL_RAISE_LAND) | GENERAL_TOOL, NULL, 0, pl, pos); } void export_commands(HSQUIRRELVM vm) { /** * Proof-of-concept to make tools available to scripts. * * The default_param is not checked. Use at own risk. * @ingroup game_cmd */ create_class(vm, "command_x"); /** * Constructor to obtain a tool. * @param id id of the tool * @typemask command_x(tool_ids) */ register_function(vm, command_constructor, "constructor", 2, "xi"); // set type tag to custom getter sq_settypetag(vm, -1, param::tag()); /** * @returns flags set for this tool */ register_method(vm, &get_flags, "get_flags", true); /** * Sets flags for this tool. * Simulates pressing shift or ctrl while clicking with mouse. * @param flags bitmap, 1 = shift pressed, 2 = ctrl pressed */ register_method(vm, &set_flags, "set_flags", true); /** * Does the dirty work. * @note In network games script will be suspended until the command is executed. * @param pl player to pay for the work * @param pos coordinate, where something should happen * @returns null upon success, an error string otherwise * @typemask string(player_x,coord3d) */ register_function(vm, command_work, "work", -3, "x t|x|y t|x|y"); #ifdef DOXYGEN // command_work works with different numbers of parameters. // Their documentation is included here. /** * Does the dirty work. * @note In network games script will be suspended until the command is executed. * @param pl player to pay for the work * @param pos coordinate, where something should happen * @param param magic parameter string * @returns null upon success, an error string otherwise * @typemask string(player_x,coord3d,string) */ register_function(vm,, "work"); const char* work(player_x player, coord3d pos, string param); /** * Does the dirty work. * Needs two positions for start and end of the work, for e.g., road building. * @note In network games script will be suspended until the command is executed. * @param pl player to pay for the work * @param start coordinate, where work begins * @param end coordinate, where work ends * @param param magic parameter string * @returns null upon success, an error string otherwise * @typemask string(player_x,coord3d,coord3d,string) */ register_function(vm,, "work"); #endif /** * Build a way. * @param pl player to pay for the work * @param start coordinate, where work begins * @param end coordinate, where work ends * @param way type of way to be built * @param straight force building of straight ways, similar as building way with control key pressed */ STATIC register_method_fv(vm, build_way, "build_way", freevariable(false), false, true); /** * Build a road. * @param pl player to pay for the work * @param start coordinate, where work begins * @param end coordinate, where work ends * @param way type of way to be built * @param straight force building of straight ways, similar as building way with control key pressed * @param keep_city_roads if true city roads will not be replaced */ STATIC register_method(vm, build_way, "build_road", false, true); /** * Build a depot. * @param pl player to pay for the work * @param pos position to place the depot * @param depot type of depot to be built */ STATIC register_method(vm, build_depot, "build_depot", false, true); /** * Build a station or station extension building. * @param pl player to pay for the work * @param pos position to place the depot * @param station type of station to be built * @param layout (optional parameter) rotation of building (only used for flat docks and extensions, ribi are not allowed and must be converted!) */ STATIC register_function(vm, command_build_station, "build_station", -4 /* at least 4 parameters */, func_signature_t::get_typemask(false).c_str(), false /* static */); log_squirrel_type(func_signature_t::get_squirrel_class(false), "build_station", func_signature_t::get_squirrel_type(false, 0)); /** * Build a bridge. * Similar to drag-and-build of bridges in-game. * @param pl player to pay for the work * @param start coordinate, where bridge begins * @param end coordinate, where bridge ends * @param bridge type of bridge to be built */ STATIC register_method(vm, build_bridge, "build_bridge", false, true); /** * Build a bridge. * Similar to one click with mouse on suitable start tile: program will figure out bridge span itself. * @param pl player to pay for the work * @param start coordinate, where bridge begins, the end point will be automatically determined * @param bridge type of bridge to be built */ STATIC register_method(vm, build_bridge_at, "build_bridge_at", false, true); /** * Modify the slope of one tile. * @param pl player to pay for the work * @param pos position of tile * @param slope new slope, can also be one of @ref slope::all_up_slope or @ref slope::all_down_slope. */ STATIC register_method(vm, set_slope, "set_slope", false, true); /** * Restore natural slope of one tile. * @param pl player to pay for the work * @param pos position of tile */ STATIC register_method(vm, restore_slope, "restore_slope", false, true); /** * Checks whether player @p pl can do this terraforming. * @param pl player * @param pos position * @param slope new slope, can also be one of @ref slope::all_up_slope or @ref slope::all_down_slope * @returns null (if allowed) or an error message otherwise */ STATIC register_method(vm, can_set_slope, "can_set_slope", false, true); /** * Costs of using @ref set_slope. * @returns cost */ STATIC register_method(vm, set_slope_get_price, "slope_get_price", false, true); /** * Build signal / road-sign. If such a sign already exists then change its direction. * @param pl player to pay for the work * @param pos position of tile * @param sign type of road-sign or signal to be built */ STATIC register_method(vm, build_sign_at, "build_sign_at", false, true); /** * Build way-object. * @param pl player to pay for the work * @param start coordinate, where work begins * @param end coordinate, where work ends * @param wayobj type of wayobj to be built */ STATIC register_method(vm, build_wayobj, "build_wayobj", false, true); /** * Change climate of tile * @param pl player to pay for the work * @param pos coordinate of tile * @param climate new climate, possible values see @ref climates */ STATIC register_method(vm, change_climate_at, "change_climate_at", false, true); /** * Lower grid point * @param pl player to pay for the work * @param pos coordinate of tile, grid point in nw corner will be lowered */ STATIC register_method_fv(vm, lower_raise, "grid_lower", freevariable(true), false, true); /** * Raise grid point * @param pl player to pay for the work * @param pos coordinate of tile, grid point in nw corner will be lowered */ STATIC register_method_fv(vm, lower_raise, "grid_raise", freevariable(false), false, true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_command.h000066400000000000000000000106641474050137200230730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_API_COMMAND_H #define SCRIPT_API_API_COMMAND_H #include "../api_param.h" #include "../../dataobj/koord3d.h" #include "../../utils/plainstring.h" void export_commands(HSQUIRRELVM vm); class koord3d; class player_t; class tool_t; namespace script_api { /** * Class to hold pointer to tool_t and to manage its default_param string. */ struct my_tool_t { tool_t *tool; plainstring default_param; my_tool_t(tool_t *tool_) : tool(tool_) { } }; /* * Return types for tool calls: * - call_tool_init * - call_tool_work * * Their param<>::push methods actually call work/init and suspend. * * To implement a tool, make a method returning call_tool_work: * * call_tool_work call_x_tool(parameters..) * { * .... * return call_tool_work(tool, player, koord3d) * } * * call_tool_init call_x_tool(parameters..) * { * .... * return call_tool_init(tool, player) * } */ class call_tool_base_t { protected: // tool to be called, can be NULL tool_t *tool; // create tool with this id, default_param, and flags if tool == NULL uint16 tool_id; plainstring default_param; uint8 flags; player_t *player; // error message when calling, returned by push const char* error; // if true, calls to tools that were not immediately executed will not suspend the vm // but rather return null (as if the tool was successfully executed) bool no_block; public: call_tool_base_t(tool_t* t, player_t* pl) : tool(t), tool_id(0), default_param(NULL), flags(0), player(pl), error(NULL), no_block(false) { } call_tool_base_t(uint16 id, const char* dp, uint8 f, player_t* pl) : tool(NULL), tool_id(id), default_param(dp), flags(f), player(pl), error(NULL), no_block(false) { } call_tool_base_t(const char* err) : tool(NULL), tool_id(0), default_param(NULL), flags(0), player(NULL), error(err), no_block(false) { } tool_t * create_tool(); }; class call_tool_init : public call_tool_base_t { friend struct param; public: call_tool_init(tool_t* t, player_t* pl) : call_tool_base_t(t, pl) { } call_tool_init(uint16 id, const char* dp, uint8 f, player_t* pl) : call_tool_base_t(id, dp, f, pl) { } call_tool_init(const char* err) : call_tool_base_t(err) { } }; class call_tool_work : public call_tool_base_t { // parameters to call the work methods koord3d start; koord3d end; bool twoclick; friend struct param; public: call_tool_work(tool_t* t, player_t* pl, koord3d pos1) : call_tool_base_t(t, pl), start(pos1), end(koord3d::invalid), twoclick(false) { } call_tool_work(tool_t* t, player_t* pl, koord3d pos1, koord3d pos2) : call_tool_base_t(t, pl), start(pos1), end(pos2), twoclick(true) { } call_tool_work(uint16 id, const char* dp, uint8 f, player_t* pl, koord3d pos1) : call_tool_base_t(id, dp, f, pl), start(pos1), end(koord3d::invalid), twoclick(false) { } call_tool_work(uint16 id, const char* dp, uint8 f, player_t* pl, koord3d pos1, koord3d pos2) : call_tool_base_t(id, dp, f, pl), start(pos1), end(pos2), twoclick(true) { } call_tool_work(const char* err) : call_tool_base_t(err), start(koord3d::invalid), end(koord3d::invalid), twoclick(false) { } call_tool_work set_no_block(bool nb) { no_block = nb; return *this; } }; template<> struct param { /** * Pretends to be a push method. BUT, actually, * Calls tool->init (or sends to server & suspends the script). * Returns error string at the end of the day. */ static SQInteger push(HSQUIRRELVM vm, call_tool_init v); // returns nothing sensible static const char* squirrel_type() { return "void"; } }; template<> struct param { /** * Pretends to be a push method. BUT, actually, * Calls tool->work (or sends to server & suspends the script). * Returns error string at the end of the day. */ static SQInteger push(HSQUIRRELVM vm, call_tool_work v); // returns strings static const char* squirrel_type() { return param::squirrel_type(); } }; /** * Helper functions to rename objects. * @param what indicates type (see tool_rename_t::init) */ call_tool_init command_rename(player_t *owner, char what, koord3d pos, const char* name); call_tool_init command_rename(player_t *owner, char what, uint32 id, const char* name); }; #endif simutrans-124.3/src/simutrans/script/api/api_const.cc000066400000000000000000000252571474050137200227450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_const.cc exports constants */ #include "../api_param.h" #include "../../obj/simobj.h" #include "../../tool/simmenu.h" #include "../../simunits.h" using namespace script_api; #define begin_enum(name) sq_pushconsttable(vm); #define end_enum() sq_setconsttable(vm); #define enum_slot create_slot void export_global_constants(HSQUIRRELVM vm) { /** * Constants to identify tools, ie actions a player can perform to * alter the state of the game. */ begin_enum("tool_ids"); /// remover tool enum_slot(vm, "tool_remover", TOOL_REMOVER | GENERAL_TOOL); /// raise land tool enum_slot(vm, "tool_raise_land", TOOL_RAISE_LAND | GENERAL_TOOL); /// lower land tool enum_slot(vm, "tool_lower_land", TOOL_LOWER_LAND | GENERAL_TOOL); /// artificial slope enum_slot(vm, "tool_setslope", TOOL_SETSLOPE | GENERAL_TOOL); /// restore natural slope enum_slot(vm, "tool_restoreslope", TOOL_RESTORESLOPE | GENERAL_TOOL); /// set marker enum_slot(vm, "tool_set_marker", TOOL_MARKER | GENERAL_TOOL); /// clear block reservation enum_slot(vm, "tool_clear_reservation", TOOL_CLEAR_RESERVATION | GENERAL_TOOL); /// build transformer enum_slot(vm, "tool_build_transformer", TOOL_TRANSFORMER | GENERAL_TOOL); /// add city enum_slot(vm, "tool_add_city", TOOL_ADD_CITY | GENERAL_TOOL); /// change city size enum_slot(vm, "tool_change_city_size", TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL); /// plant a tree enum_slot(vm, "tool_plant_tree", TOOL_PLANT_TREE | GENERAL_TOOL); // not needed? enum__slot(vm, "tool_schedule_add", TOOL_SCHEDULE_ADD | GENERAL_TOOL); // not needed? enum__slot(vm, "tool_schedule_ins", TOOL_SCHEDULE_INS | GENERAL_TOOL); /// build groundobj/movingobj enum_slot(vm, "tool_build_groundobj", TOOL_PLANT_GROUNDOBJ | GENERAL_TOOL); /// build ways enum_slot(vm, "tool_build_way", TOOL_BUILD_WAY | GENERAL_TOOL); /// build bridges enum_slot(vm, "tool_build_bridge", TOOL_BUILD_BRIDGE | GENERAL_TOOL); /// build tunnel enum_slot(vm, "tool_build_tunnel", TOOL_BUILD_TUNNEL | GENERAL_TOOL); /// remove way enum_slot(vm, "tool_remove_way", TOOL_WAYREMOVER | GENERAL_TOOL); /// build overhead wires enum_slot(vm, "tool_build_wayobj", TOOL_BUILD_WAYOBJ | GENERAL_TOOL); /// build stations enum_slot(vm, "tool_build_station", TOOL_BUILD_STATION | GENERAL_TOOL); /// build signals and road signs enum_slot(vm, "tool_build_roadsign", TOOL_BUILD_ROADSIGN | GENERAL_TOOL); /// build depot enum_slot(vm, "tool_build_depot", TOOL_BUILD_DEPOT | GENERAL_TOOL); /// build city houses enum_slot(vm, "tool_build_house", TOOL_BUILD_HOUSE | GENERAL_TOOL); /// create industry chain with end consumer not in cities enum_slot(vm, "tool_land_chain", TOOL_BUILD_LAND_CHAIN | GENERAL_TOOL); /// create industry chain with end consumer in cities enum_slot(vm, "tool_city_chain", TOOL_CITY_CHAIN | GENERAL_TOOL); /// build a factory enum_slot(vm, "tool_build_factory", TOOL_BUILD_FACTORY | GENERAL_TOOL); /// link factories enum_slot(vm, "tool_link_factory", TOOL_LINK_FACTORY | GENERAL_TOOL); /// build headquarters enum_slot(vm, "tool_headquarter", TOOL_HEADQUARTER | GENERAL_TOOL); /// lock map: switching players not allowed anymore enum_slot(vm, "tool_lock_game", TOOL_LOCK_GAME | GENERAL_TOOL); /// add city car enum_slot(vm, "tool_add_citycar", TOOL_ADD_CITYCAR | GENERAL_TOOL); /// create forest enum_slot(vm, "tool_forest", TOOL_FOREST | GENERAL_TOOL); /// move stop tool enum_slot(vm, "tool_stop_mover", TOOL_STOP_MOVER | GENERAL_TOOL); /// make stop public enum_slot(vm, "tool_make_stop_public", TOOL_MAKE_STOP_PUBLIC | GENERAL_TOOL); /// remove way objects like overheadwires enum_slot(vm, "tool_remove_wayobj", TOOL_REMOVE_WAYOBJ | GENERAL_TOOL); // not needed? enum__slot(vm, "tool_sliced_and_underground_view", TOOL_SLICED_AND_UNDERGROUND_VIEW | GENERAL_TOOL); /// buy a house enum_slot(vm, "tool_buy_house", TOOL_BUY_HOUSE | GENERAL_TOOL); /// build city road with pavement enum_slot(vm, "tool_build_cityroad", TOOL_BUILD_CITYROAD | GENERAL_TOOL); /// alter water height enum_slot(vm, "tool_change_water_height", TOOL_CHANGE_WATER_HEIGHT | GENERAL_TOOL); /// change climate of tiles enum_slot(vm, "tool_set_climate", TOOL_SET_CLIMATE | GENERAL_TOOL); /// rotate a building enum_slot(vm, "tool_rotate_building", TOOL_ROTATE_BUILDING | GENERAL_TOOL); /// merge two stops enum_slot(vm, "tool_merge_stop", TOOL_MERGE_STOP | GENERAL_TOOL); /// scripted tool (one-click) enum_slot(vm, "tool_exec_script", TOOL_EXEC_SCRIPT | GENERAL_TOOL); /// scripted tool (two-click) enum_slot(vm, "tool_exec_two_click_script", TOOL_EXEC_TWO_CLICK_SCRIPT | GENERAL_TOOL); /// change owner of nth object on tile enum_slot(vm, "tool_set_owner", TOOL_SET_OWNER | GENERAL_TOOL); // simple tools /// increase industry density enum_slot(vm, "tool_increase_industry", TOOL_INCREASE_INDUSTRY | SIMPLE_TOOL); /// switch player enum_slot(vm, "tool_switch_player", TOOL_SWITCH_PLAYER | SIMPLE_TOOL); /// step year forward enum_slot(vm, "tool_step_year", TOOL_STEP_YEAR | SIMPLE_TOOL); /// fill area with trees enum_slot(vm, "tool_fill_trees", TOOL_FILL_TREES | SIMPLE_TOOL); /// set traffic level enum_slot(vm, "tool_set_traffic_level", TOOL_TRAFFIC_LEVEL | SIMPLE_TOOL); // tools to open certain windows /// open factory editor window enum_slot(vm, "dialog_edit_factory", DIALOG_EDIT_FACTORY | DIALOGE_TOOL); /// open tourist attraction editor window enum_slot(vm, "dialog_edit_attraction", DIALOG_EDIT_ATTRACTION | DIALOGE_TOOL); /// open house editor window enum_slot(vm, "dialog_edit_house", DIALOG_EDIT_HOUSE | DIALOGE_TOOL); /// open tree editor window enum_slot(vm, "dialog_edit_tree", DIALOG_EDIT_TREE | DIALOGE_TOOL); /// open map enlargement window enum_slot(vm, "dialog_enlarge_map", DIALOG_ENLARGE_MAP | DIALOGE_TOOL); end_enum(); /** * Flags for scripted tools. */ begin_enum("tool_flags"); enum_slot(vm, "shift_pressed", tool_t::WFL_SHIFT); enum_slot(vm, "ctrl_pressed", tool_t::WFL_CTRL); end_enum(); /** * Constants for different way types. */ begin_enum("way_types"); /// catch all value: used to forbid tools for all waytypes enum_slot(vm, "wt_all", ignore_wt); /// road enum_slot(vm, "wt_road", road_wt); /// rail enum_slot(vm, "wt_rail", track_wt); /// water enum_slot(vm, "wt_water", water_wt); /// monorail enum_slot(vm, "wt_monorail", monorail_wt); /// maglev enum_slot(vm, "wt_maglev", maglev_wt); /// trams enum_slot(vm, "wt_tram", tram_wt); /// narrow gauge enum_slot(vm, "wt_narrowgauge", narrowgauge_wt); /// aircrafts and airports enum_slot(vm, "wt_air", air_wt); /// powerlines enum_slot(vm, "wt_power", powerline_wt); /// decomartion for unspecifed wayobj enum_slot(vm, "wt_decoration", decoration_wt); /// invalid enum_slot(vm, "wt_invalid", invalid_wt); end_enum(); /** * Constants for different system types of ways. * System type could take also other values than the ones defined here. */ begin_enum("way_system_types"); /// flat ways enum_slot(vm, "st_flat", type_flat); /// elevated ways enum_slot(vm, "st_elevated", type_elevated); /// runway (for wt_air), equal to st_elevated enum_slot(vm, "st_runway", type_runway); /// tram tracks (here way type has to be wt_tram) enum_slot(vm, "st_tram", type_tram); end_enum(); // players begin_enum(""); /// constant to forbid/allow tools for all players (except public player) enum_slot(vm, "player_all", PLAYER_UNOWNED); end_enum(); /** * Types of map objects. */ begin_enum("map_objects"); /// tree enum_slot(vm, "mo_tree", obj_t::baum); /// pointer (bulldozers etc) enum_slot(vm, "mo_pointer", obj_t::zeiger); /// cloud and smoke enum_slot(vm, "mo_cloud", obj_t::cloud); /// building (houses, halts, factories ...) enum_slot(vm, "mo_building", obj_t::gebaeude); /// signal enum_slot(vm, "mo_signal", obj_t::signal); /// bridge enum_slot(vm, "mo_bridge", obj_t::bruecke); /// tunnel enum_slot(vm, "mo_tunnel", obj_t::tunnel); /// depot: rail enum_slot(vm, "mo_depot_rail", obj_t::bahndepot); /// depot: road enum_slot(vm, "mo_depot_road", obj_t::strassendepot); /// depot: ship enum_slot(vm, "mo_depot_water", obj_t::schiffdepot); /// powerline enum_slot(vm, "mo_powerline", obj_t::leitung); /// transformer at powerplant enum_slot(vm, "mo_transformer_s", obj_t::pumpe); /// transformer at factory enum_slot(vm, "mo_transformer_c", obj_t::senke); /// road-sign enum_slot(vm, "mo_roadsign", obj_t::roadsign); /// bridge pillar enum_slot(vm, "mo_pillar", obj_t::pillar); /// depot: airplanes enum_slot(vm, "mo_depot_air", obj_t::airdepot); /// depot: monorail enum_slot(vm, "mo_depot_monorail", obj_t::monoraildepot); /// depot: tram enum_slot(vm, "mo_depot_tram", obj_t::tramdepot); /// depot: maglev enum_slot(vm, "mo_depot_maglev", obj_t::maglevdepot); /// way object (overhead wires) enum_slot(vm, "mo_wayobj", obj_t::wayobj); /// way enum_slot(vm, "mo_way", obj_t::way); /// text label enum_slot(vm, "mo_label", obj_t::label); /// field enum_slot(vm, "mo_field", obj_t::field); /// crossing enum_slot(vm, "mo_crossing", obj_t::crossing); /// decorative objects (rocks, lakes ...) enum_slot(vm, "mo_groundobj", obj_t::groundobj); /// depot: narrowgauge enum_slot(vm, "mo_depot_narrowgauge", obj_t::narrowgaugedepot); /// pedestrian enum_slot(vm, "mo_pedestrian", obj_t::pedestrian); /// city car - not player owned enum_slot(vm, "mo_city_car", obj_t::road_user); /// road vehicle enum_slot(vm, "mo_car", obj_t::road_vehicle); /// rail vehicle enum_slot(vm, "mo_train", obj_t::rail_vehicle); /// monorail vehicle enum_slot(vm, "mo_monorail", obj_t::monorail_vehicle); /// maglev vehicle enum_slot(vm, "mo_maglev", obj_t::maglev_vehicle); /// narrowgauge vehicle enum_slot(vm, "mo_narrowgauge", obj_t::narrowgauge_vehicle); /// ship enum_slot(vm, "mo_ship", obj_t::water_vehicle); /// airplane enum_slot(vm, "mo_airplane", obj_t::air_vehicle); /// moving object (sheep ...) enum_slot(vm, "mo_moving_object", obj_t::movingobj); end_enum(); /** * Internal units. */ begin_enum("units"); /// The length of one side of a tile in car units. @see vehicle_desc_x::get_length enum_slot(vm, "CARUNITS_PER_TILE", (uint32)CARUNITS_PER_TILE); end_enum(); /** * Climate zones. Their naming may differ from the graphical representation and * translation in some paksets. */ begin_enum("climates"); enum_slot(vm, "cl_water", water_climate); enum_slot(vm, "cl_desert", desert_climate); enum_slot(vm, "cl_tropic", tropic_climate); enum_slot(vm, "cl_mediterran", mediterran_climate); enum_slot(vm, "cl_temperate", temperate_climate); enum_slot(vm, "cl_tundra", tundra_climate); enum_slot(vm, "cl_rocky", rocky_climate); enum_slot(vm, "cl_arctic", arctic_climate); end_enum(); } simutrans-124.3/src/simutrans/script/api/api_control.cc000066400000000000000000000045601474050137200232710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_control.cc script control and debug functions. */ #include "../api_function.h" #include "../api_class.h" #include "../script.h" #include "../../../squirrel/sq_extensions.h" #include "../../tool/simtool.h" namespace script_api { bool pause_game() { tool_pause_t t; if (!t.is_selected()) { t.init(NULL); } return t.is_selected(); } bool is_game_paused() { tool_pause_t t; return t.is_selected(); } }; using namespace script_api; SQInteger sleep(HSQUIRRELVM vm) { if (const char* blocker = sq_get_suspend_blocker(vm)) { return sq_raise_error(vm, "Cannot call sleep from within `%s'.", blocker); } return sq_suspendvm(vm); } SQInteger set_pause_on_error(HSQUIRRELVM vm) { if (script_vm_t *script = (script_vm_t*)sq_getforeignptr(vm)) { bool poe = param::get(vm, 2); script->pause_on_error = poe; } return SQ_OK; } void export_control(HSQUIRRELVM vm) { // in global scope /** * Suspends execution of the script. Upon resume, the script * will have full count of opcodes to spent for fragile code, * i.e. writing into @ref persistent. * @typemask void() */ register_function(vm, sleep, "sleep", 1, "."); /** * @returns total amount of opcodes executed by vm */ register_function(vm, sq_get_ops_total, "get_ops_total"); /** * @returns amount of remaining opcodes until vm will be suspended */ register_function(vm, sq_get_ops_remaing, "get_ops_remaining"); begin_class(vm, "debug"); /** * Pauses game. Does not work in network games. Use with care. * @returns true when successful. */ STATIC register_method(vm, &pause_game, "pause", false, true); /** * Checks whether game is paused. * Note that scripts only run for unpaused games. * This can only be used in functions that are called by user actions (e.g., is_*_allowed). * @returns true when successful. */ STATIC register_method(vm, &is_game_paused, "is_paused", false, true); /** * Scripts can pause the game in case of error. Toggle this behavior by parameter @p p. * Does not work in network games. Use with care. * @param p true if script should make the game pause in case of error */ STATIC register_function(vm, set_pause_on_error, "set_pause_on_error", true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_convoy.cc000066400000000000000000000304551474050137200231300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_convoy.cc exports convoy related functions. */ #include "get_next.h" #include "api_obj_desc_base.h" #include "../api_class.h" #include "../api_function.h" #include "../../simconvoi.h" #include "../../simhalt.h" #include "../../simline.h" #include "../../world/simworld.h" #include "../../display/viewport.h" #include "../../vehicle/vehicle.h" // for convoy tools #include "../../tool/simmenu.h" #include "../../dataobj/schedule.h" using namespace script_api; waytype_t get_convoy_wt(convoi_t const *cnv) { if (cnv && cnv->get_vehicle_count() > 0) { return cnv->front()->get_waytype(); } return invalid_wt; } vector_tpl const& get_convoy_stat(convoi_t* cnv, sint32 INDEX) { static vector_tpl v; v.clear(); if (cnv && 0<=INDEX && INDEXget_stat_converted(i, INDEX)); } } return v; } vector_tpl const& convoi_get_vehicles(convoi_t* cnv) { static vector_tpl v; v.clear(); if (cnv) { for(uint16 i=0; iget_vehicle_count(); i++) { v.append(cnv->get_vehicle(i)->get_desc()); } } return v; } sint32 convoy_get_kmh(convoi_t const* cnv) { return cnv ? speed_to_kmh(cnv->get_akt_speed()) : -1; } vector_tpl const* generic_get_convoy_list(HSQUIRRELVM vm, SQInteger index) { uint16 id; bool use_world; if (SQ_SUCCEEDED(get_slot(vm, "halt_id", id, index))) { halthandle_t halt; halt.set_id(id); if (halt.is_bound()) { return &halt->registered_convoys; } } if (SQ_SUCCEEDED(get_slot(vm, "line_id", id, index))) { linehandle_t line; line.set_id(id); if (line.is_bound()) { return &line->get_convoys(); } } if (SQ_SUCCEEDED(get_slot(vm, "use_world", use_world, index)) && use_world) { return &welt->convoys(); } sq_raise_error(vm, "Invalid convoy list."); return NULL; } SQInteger generic_get_convoy_count(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_convoy_list(vm, 1); return list ? param::push(vm, list->get_count()) : SQ_ERROR; } SQInteger generic_get_next_convoy(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_convoy_list(vm, 1); return list ? generic_get_next(vm, list->get_count()) : SQ_ERROR; } SQInteger generic_get_convoy_by_index(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_convoy_list(vm, 1); sint32 index = param::get(vm, 2); convoihandle_t cnv; if (list) { cnv = (0<=index && (uint32)index < list->get_count()) ? (*list)[index] : convoihandle_t(); return push_instance(vm, "convoy_x", cnv.is_bound() ? cnv.get_id() : 0); } return SQ_ERROR; } uint32 calc_max_kmh(uint32 power, uint32 weight, sint32 speed_limit) { return speed_to_kmh(convoi_t::calc_max_speed(power, weight, kmh_to_speed(speed_limit)) ); } uint32 kmh_to_tiles_per_month(uint32 kmh) { return welt->speed_to_tiles_per_month( kmh_to_speed(kmh)); } call_tool_init convoy_set_name(convoi_t *cnv, const char* name) { return command_rename(cnv->get_owner(), 'c', cnv->self.get_id(), name); } call_tool_init convoy_set_line(convoi_t *cnv, player_t *player, linehandle_t line) { if (!line.is_bound()) { return "Invalid line handle provided"; } // see depot_frame_t::apply_line() and convoi_t::call_convoi_tool() cbuffer_t buf; buf.printf("%c,%u,%i", 'l', cnv->self.get_id(), line->get_handle().get_id()); return call_tool_init(TOOL_CHANGE_CONVOI | SIMPLE_TOOL, buf, 0, player); } call_tool_init convoy_generic_tool(convoi_t *cnv, player_t *player, uint8 cnvtool) { char c = (char)cnvtool; if (strchr("wx", c) == NULL) { return "Invalid convoy tool called"; } // see convoi_t::call_convoi_tool() cbuffer_t buf; buf.printf("%c,%u", c, cnv->self.get_id()); return call_tool_init(TOOL_CHANGE_CONVOI | SIMPLE_TOOL, buf, 0, player); } bool convoy_is_schedule_editor_open(convoi_t *cnv) { return cnv->get_state() == convoi_t::EDIT_SCHEDULE; } sint32 convoy_is_followed(convoi_t const *cnv) { return cnv ? world()->get_viewport()->get_follow_convoi().get_id() == cnv->self.get_id() : false; } bool convoy_is_loading(convoi_t const *cnv) { return cnv->get_state() == convoi_t::LOADING; } call_tool_init convoy_change_schedule(convoi_t *cnv, player_t *player, schedule_t *sched) { if (sched) { cbuffer_t buf; // make a copy, and perform validation on it schedule_t *copy = sched->copy(); copy->make_valid(); if (copy->get_count() >= 2) { // build param string (see convoi_info_t::apply_schedule and convoi_t::call_convoi_tool()) buf.printf("g,%u,", cnv->self.get_id()); copy->sprintf_schedule(buf); } else { return "Invalid schedule provided: less than two entries remained after removing doubles"; } delete copy; return call_tool_init(TOOL_CHANGE_CONVOI | SIMPLE_TOOL, buf, 0, player); } return "Invalid schedule provided"; } void export_convoy(HSQUIRRELVM vm) { /** * Implements iterator to iterate through lists of convoys. * * Usage: * @code * local list = world.get_convoy_list_x() * foreach(cnv in list) { * ... // cnv is an instance of the convoy_x class * } * @endcode * * @see world::get_convoy_list, halt_x::get_convoy_list, line_x::get_convoy_list */ begin_class(vm, "convoy_list_x", 0); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, generic_get_next_convoy, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. * @typemask convoy_x() */ register_function(vm, generic_get_convoy_by_index, "_get", 2, "xi"); /** * Returns number of convoys in the list. * @typemask integer() */ register_function(vm, generic_get_convoy_count, "get_count", 1, "x"); end_class(vm); /** * Class to access a convoy. * Player vehicles are convoys, which themselves consist of individual vehicles (trucks, trailers, ...). */ begin_class(vm, "convoy_x", "extend_get,ingame_object"); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Does convoy needs electrified ways? * @returns true if this is the case */ register_method(vm, &convoi_t::needs_electrification, "needs_electrification"); /** * Name of convoy. * @returns name */ register_method(vm, &convoi_t::get_name, "get_name"); /** * Sets convoy name. * @ingroup rename_func */ register_method(vm, &convoy_set_name, "set_name", true); /** * Position of convoy. * @returns pos */ register_method(vm, &convoi_t::get_pos, "get_pos"); /** * Owner of convoy. * @returns owner, which is instance of player_x */ register_method(vm, &convoi_t::get_owner, "get_owner"); /** * Returns array of goods categories that can be transported by this convoy. * @returns array */ register_method(vm, &convoi_t::get_goods_catg_index, "get_goods_catg_index"); /** * Returns waytype of convoy. * @returns waytype * @see way_types */ register_method(vm, &get_convoy_wt, "get_waytype", true); /** * Schedule of this convoy. */ register_method(vm, &convoi_t::get_schedule, "get_schedule"); /** * Get monthly statistics of capacity. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_capacity", freevariable(convoi_t::CONVOI_CAPACITY), true); /** * Get monthly statistics of number of transported goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_transported_goods", freevariable(convoi_t::CONVOI_TRANSPORTED_GOODS), true ); /** * Get monthly statistics of revenue. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_revenue", freevariable(convoi_t::CONVOI_REVENUE), true ); /** * Get monthly statistics of running costs. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_cost", freevariable(convoi_t::CONVOI_OPERATIONS), true ); /** * Get monthly statistics of profit. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_profit", freevariable(convoi_t::CONVOI_PROFIT), true ); /** * Get monthly statistics of traveled distance. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_traveled_distance", freevariable(convoi_t::CONVOI_DISTANCE), true ); /** * Get monthly statistics of income/loss due to way tolls. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_convoy_stat, "get_way_tolls", freevariable(convoi_t::CONVOI_WAYTOLL), true ); /** * @returns lifetime traveled distance of this convoy */ register_method(vm, &convoi_t::get_total_distance_traveled, "get_distance_traveled_total"); /** * @returns the line the convoy belongs to, null if there is no line */ register_method(vm, &convoi_t::get_line, "get_line"); /** * Assigns the convoy to the given line. * @param player * @param line * @ingroup game_cmd */ register_method(vm, convoy_set_line, "set_line", true); /** * @returns returns an array containing the vehicle_desc_x 's of the vehicles of this convoy */ register_method(vm, convoi_get_vehicles, "get_vehicles", true); /** * @returns current speed of convoy */ register_method(vm, convoy_get_kmh, "get_speed", true); /** * @returns get current loading limit: waiting for full load gives 100 */ register_method(vm, &convoi_t::get_loading_limit, "get_loading_limit"); /** * @returns get current loading level */ register_method(vm, &convoi_t::get_loading_level, "get_loading_level"); /** * @returns gets location of home depot */ register_method(vm, &convoi_t::get_home_depot, "get_home_depot"); /** * @returns whether convoi has obsolete vehicles */ register_method(vm, &convoi_t::has_obsolete_vehicles, "has_obsolete_vehicles"); /** * Toggle the flag 'withdraw convoy' * @ingroup game_cmd */ register_method_fv(vm, convoy_generic_tool, "toggle_withdraw", freevariable('w'), true ); /** * @returns the flag 'withdraw convoy' */ register_method(vm, &convoi_t::get_withdraw, "is_withdrawn"); /** * @returns true if convoy is in depot */ register_method(vm, &convoi_t::in_depot, "is_in_depot"); /** * @returns true if convoy is currently waiting (for way clearance) */ register_method(vm, &convoi_t::is_waiting, "is_waiting"); /** * @returns true if convoy is currently being followed */ register_method(vm, convoy_is_followed, "is_followed", true); /** * @returns true if convoy is currently loading or unloading at a stop */ register_method(vm, convoy_is_loading, "is_loading", true); /** * Destroy the convoy. * The convoy will be marked for destroying, it will be destroyed when the simulation continues. * Call @ref sleep to be sure that the convoy is destroyed before script continues. * @ingroup game_cmd */ register_method_fv(vm, convoy_generic_tool, "destroy", freevariable('x'), true); /** * @returns returns true if the schedule of the convoy is currently being edited. */ register_method(vm, convoy_is_schedule_editor_open, "is_schedule_editor_open", true); /** * @returns returns the number of station tiles covered by the convoy. */ register_method(vm, &convoi_t::get_tile_length, "get_tile_length"); /** * Change schedule of convoy. * Schedule should not contain doubled entries and more than two entries. * This might make the convoy lose its line. * @ingroup game_cmd */ register_method(vm, convoy_change_schedule, "change_schedule", true); #define STATIC /** * Static method to compute the potential max speed of a convoy * with the given parameters. * @param power total power of convoy * @param weight weight of convoy * @param speed_limit speed limit induced by convoy's vehicles * @returns max speed */ STATIC register_method(vm, &calc_max_kmh, "calc_max_speed"); /** * Static method to convert speed (from km per hour) to tiles per month. * @param speed * @returns tile per month */ STATIC register_method(vm, &kmh_to_tiles_per_month, "speed_to_tiles_per_month"); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_doc.h000066400000000000000000000325221474050137200222170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file api_doc.h Just contains pages of exciting documentation */ /** * @mainpage * * Simutrans offers to possibility to add scripted scenarios and computer-controlled players. * * @tableofcontents * * Scripting language * ------------------ * * The scripts have to be written in squirrel. The manual can be found at Squirrel main page. * As squirrels like to crack nuts, understandably the script files get the extension '.nut'. * * @section s_scenarios Scripted scenarios * * See also @ref scen_skel and @ref scen_only. * * @subsection sec_howto How to create a scenario. * * You first need an @e idea - a vision what a scenario may look like. Then you have * to cast this idea into a @e savegame. That is, create the world in which your scenario will live. * You are the ruler of this toy universe, you are in charge of the rules, which go into the @e script. * * * @subsection sec_ex Example scenario scripts * * There are several commented examples. * -# @ref page_script_mill * -# @ref page_script_pharm * * @subsection sec_dir Recommended directory structure * * The scenario plays in a savegame. This savegame is tied to the pak-set you are using (e.g. pak64, pak128.Britain). * Hence, the scenario files have to go into a sub-folder of the pak-set. * The pak-set is found in a directory named pak-something, which is in the same directory, where the program * itself is located or under user-directory/addons/. * * Your scenario file goes into the folder * * * pak-something/scenario/myscenario/ * * * The scenario script must be in the file * * * pak-something/scenario/myscenario/scenario.nut * * * Translation files go into the scenario sub-directory with the same name as your file (just without extension) * * * pak-something/scenario/myscenario/ * * * If you need more complex texts, these go into sub-directories named after the language, in which they are written. * * * pak-something/scenario/myscenario/en/ <- English files go here. * * pak-something/scenario/myscenario/de/ <- German files go here. * * * Scenarios can also be put into the addons folder: * * * addons/pak-something/scenario/myscenario/ * * * * @section s_ai_player Scripted AI players * * See also @ref ai_skel. * * @subsection sec_dir Recommended directory structure * * Your script file goes into the folder * * * ai/myai/ * * * The main script file must be * * * ai/myai/ai.nut * * * The ai scripts can also be put into * * * addons/ai/myai/ * * * @section s_scripted_tools Scripted tools * * See also @ref tool_skel and @ref tool_only. * * @subsection sec_dir_tools Recommended directory structure * * The script file (tool.nut) as well as the configuration file (description.tab) go into * * * pak-something/tool/mytool/ * * * Related pak-files have to be placed in * * * pak-something/ * * * directly. * * @subsection sec_description_tab The file description.tab * * This is a plain text file with the following entries:
* * title=Name of tool to be shown in tool selection dialog
* type=one_click or two_click
* tooltip=Tooltip for the icon in the toolbar
* restart=Set to 1 if the virtual machine has to be restarted after each call to the work functions.
* menu=Parameter that can be used to load tools with menuconf.tab
* icon=Name of cursor object (loaded from some pak-file), used images: 0 = cursor, 1 = icon, 2 = marker image
*
* * @section s_general_advice General scripting advice * * Check out the sections on the Modules page. * See also @ref pitfalls. * * @subsection sec_data_types Squirrel data types * * Squirrel has some built-in data types: among them integer, string, tables, and arrays. These are * widely used throughout this documentation in the function declarations. * * If tables or arrays carry template parameters, this indicates the expected type of elements of the array or table. * See factory_x::input for an example. * * @subsection sec_coord Coordinates * * All coordinates in the script are with respect to the initial rotation of the map. If a player rotates * a map, then all coordinates are translated to the original rotation. * This affects the classes @ref coord and @ref coord3d as well as any functions that expect coordinates as input, as * for instance factory_x::factory_x or rules::forbid_way_tool_rect. * * @subsection sec_network Network play * * A lot of stuff is possible for network play. There are some limitations of course. These are due to the fact, that * the scripts are solely run on the server, the client does not need to have the script available at all. * This implies for instance that all scenario texts are translated to the server's language. * * @subsection sec_err Logging and error handling * If simutrans is started with '-debug 2', all errors and warnings are logged to standard output (i.e. terminal). * If simutrans is started in addition with '-log', all the output is written to the file script.log. In particular, * everything that is print-ed by the script, goes into this file. * * In case of error, an error window pops up showing the call stack and the values of local variables. * You can then repair your script, and restart the scenario via New Game - Scenario. You do not need to restart * simutrans to reload your script. * * @subsection sec_rdwr Load-Save support * Such support is available of course. If a running scenario is saved, the information about the scenario is saved within the * savegame. Upon loading, the scenario is resumed, by calling the function ::resume_game. * * You can save data in the savegame. In order to do so, you have to keep these data in the global table ::persistent. * This table is saved and loaded. * * */ /** * @example millionaire/scenario.nut * This example is commented in detail at the page @ref page_script_mill. */ /** * @page page_script_mill A simple example script * * Let us inspect a sample script file. We will have a look into the pak64 Millionaire scenario. * The objective of this scenario is to get rich as fast as possible. * * @dontinclude millionaire/scenario.nut * As first the savegame is specified: * @skipline map.file * Then we provide some meta-information about the ::scenario * @skipline scenario * @skipline scenario * @skipline scenario * Rules and goals are not that special. The texts returned in this functions * will be shown in the scenario info window. String constants with leading * '@' can span multiple lines. * @until } * @until } * @until } * The method presenting the result text is a little bit more advanced. If the * player has enough cash, he has won the scenario. * @until } * The get_cash() method accesses the player's bank account via player_x.cash, which * is equivalent to calling player_x.get_cash(). * @until } * Last but not least, the function that computes the actual progress in the scenario. * If it returns a negative value, the player has lost. If the return value is larger than 100, * this is equivalent to winning the scenario. * @until } */ /** * @example pharmacy-max/scenario.nut * This example is used to explain translatable texts at the page @ref page_script_pharm. */ /** * @page page_script_pharm A script showing translatable texts. * * Let us inspect another scenario script file. We will have a look into the pak64 Pharmacy-max scenario. * The objective is to get the pharmacy selling as much medicine as possible. * * We will learn how to make the translation of the script's output possible. * * @dontinclude pharmacy-max/scenario.nut * We do not care about the meta information, and jump right into the @ref get_rule_text method. * @skip get_rule_text * @until } * This function does not return a plain string, it sends the string into an instance of @ref ttext. * When the simutrans program now fetches the text, it will magically translate it. * This magic works only if there are translation files present. * * These files must be placed in a directory with the same name as the scenario, in our case at * * pharmacy-max/ * * The translation files itself are plain text files with the naming convention iso.tab, where @em iso * refers to the ISO abbreviation of the language (en, de, cz etc). * * These text files have a simple line-oriented structure. Lets look into de.tab: * * @code * You can build everything you like. The sky (and your bank account) is the limit. * Alles ist erlaubt. Der Himmel (und das Bankkonto) ist die Grenze. * @endcode * * The first line is the string as it appears in the script, it will be mapped to the string in the following line. * A German user thus will read 'Alles ist erlaubt. Der Himmel (und das Bankkonto) ist die Grenze.'. * * Similarly, the methods @ref get_info_text and @ref get_goal_text are implemented. * Some interesting stuff however happens in @ref get_result_text : * @skip get_result_text * @until } * Do you see the strange {med} string in the text? Here, you can see variable substitution in action: * @until text.med * That means the text now gets to know the precise value of {med}. * * When this text is transferred to simutrans (or when text.to_string() is called) the following happens: * -# First the translation of the string is searched, which can contain this {med} as well. * -# Then the occurrences of {med} are replaced by the concrete number. * The user will then hear 'The pharmacy sold 11 units of medicine per month.'. * * Now a second string is created, which features some html-like tags. * @until } * Both of the strings are translated by means of calls to ttext::to_string and the result is returned. * * That's it. The remaining parts of this script are plain routine. */ /** * @page pitfalls Common pitfalls * * @subsection pitfall_pass_by_reference Tables, arrays, strings, classes, instances etc are passed by reference * * @code * local a = {} // create an empty table * local b = a // b refers to the same table as a * a.x <- 1 // b.x is now also 1 * b.x <- 2 // a.x is changed to 2 * @endcode * * * @subsection nocalls_in_global_scope Do not call API-functions in global scope in the script * * @code * local start_time = settings.get_start_time() // this call is executed BEFORE the savegame is loaded -> undefined * * local factory_coalmine = null // we can create the variable ... * function start() * { * factory_coalmine = factory_x(40, 78) // ... but we can initialize it safely only in a function * } * @endcode * */ /** * @defgroup scen_skel Scenario interface * * The following methods are vital for the functioning of a scripted scenario. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup scen_only Scenario only functions * * These classes and methods are only available for scripted scenarios. * */ /** * @defgroup ai_skel AI interface * * The following methods are vital for the functioning of a scripted AI. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup ai_only AI only functions * * These classes and methods are only available for scripted AI players. * */ /** * @defgroup tool_skel Tool interface * * The following methods are vital for the functioning of scripted tools. * They will be called from simutrans to interact with the script. You should consider * implementing them. * */ /** * @defgroup tool_only Tool only functions * * These classes and methods are only available for scripted scenarios. * */ /** * @defgroup game_cmd Functions to alter the state of the game and map * * The player parameter in these functions represents the player that executes the command * and pays for it. If the call is from an AI player then the parameter is set to player_x::self, * and it will be checked whether the * player is permitted to execute the command. Calls from scenario always pass this check. * * In network games, the script is suspended until the command is executed, which is transparent to the script. * Hence such commands cannot be called from within functions that should return immediately, see @ref quick_return_func. */ /** * @defgroup rename_func Functions to rename something in the game * @ingroup game_cmd * * In AI mode, renaming works only if the object is owned by the script's player. */ /** * @defgroup quick_return_func Functions that should return quickly. * * These functions are intended to quickly return a result. In network games, it is not * allowed to call any map-altering tools from within such a function, see the section on @ref game_cmd. */ /** * @page page_sqstdlib Available functions from the squirrel standard lib * * - Math Library, see http://squirrel-lang.org/squirreldoc/stdlib/stdmathlib.html#squirrel-api * - String Library, see http://squirrel-lang.org/squirreldoc/stdlib/stdstringlib.html#squirrel-api * - System Library: functions clock, time, date, see http://squirrel-lang.org/squirreldoc/stdlib/stdsystemlib.html#squirrel-api * */ simutrans-124.3/src/simutrans/script/api/api_factory.cc000066400000000000000000000344051474050137200232610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_factory.cc exports factory related functions. */ #include "get_next.h" #include "api_obj_desc_base.h" #include "../api_class.h" #include "../api_function.h" #include "../../dataobj/scenario.h" #include "../../simfab.h" #include "../../descriptor/factory_desc.h" using namespace script_api; SQInteger exp_factory_constructor(HSQUIRRELVM vm) { sint16 x = param::get(vm, 2); sint16 y = param::get(vm, 3); // set coordinates set_slot(vm, "x", x, 1); set_slot(vm, "y", y, 1); // transform coordinates koord pos(x,y); coordinate_transform_t::koord_sq2w(pos); fabrik_t *fab = fabrik_t::get_fab(pos); if (!fab) { return sq_raise_error(vm, "No factory found at (%s)", pos.get_str()); } const factory_desc_t *desc = fab->get_desc(); // create input/output tables for (int io=0; io<2; io++) { sq_pushstring(vm, io==0 ? "input" : "output", -1); sq_newtable(vm); const array_tpl &prodslot = io==0 ? fab->get_input() :fab->get_output(); for(uint32 p=0; p < prodslot.get_count(); p++) { // create slots 'good name' <- {x,y,name} //'factory_production' sq_pushstring(vm, prodslot[p].get_typ()->get_name(), -1); // create instance of factory_production_x if(!SQ_SUCCEEDED(push_instance(vm, "factory_production_x", x, y, prodslot[p].get_typ()->get_name(), p + (io > 0 ? fab->get_input().get_count() : 0)))) { // create empty table sq_newtable(vm); } sint64 factor = io == 0 ? desc->get_supplier(p)->get_consumption() : desc->get_product(p)->get_factor(); // set max value - see fabrik_t::info_prod set_slot(vm, "max_storage", convert_goods( (sint64)prodslot[p].max * factor), -1); // production/consumption scaling set_slot(vm, "scaling", factor, -1); // put class into table sq_newslot(vm, -3, false); } sq_set(vm, 1); } return 0; // dummy return type } vector_tpl const& get_factory_stat(fabrik_t *fab, sint32 INDEX) { static vector_tpl v; v.clear(); if (fab && 0<=INDEX && INDEXget_stat_converted(i, INDEX)); } } return v; } vector_tpl const& get_factory_production_stat(const ware_production_t *prod_slot, sint32 INDEX) { static vector_tpl v; v.clear(); if (prod_slot && 0<=INDEX && INDEXget_stat_converted(i, INDEX)); } } return v; } uint32 get_production_factor(const factory_product_desc_t *desc) { return desc ? ( (1<< (DEFAULT_PRODUCTION_FACTOR_BITS-1)) + (uint32)desc->get_factor() * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS : 0; } uint32 get_consumption_factor(const factory_supplier_desc_t *desc) { return desc ? ( (1<< (DEFAULT_PRODUCTION_FACTOR_BITS-1)) + (uint32)desc->get_consumption() * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS : 0; } vector_tpl const& factory_get_tile_list(fabrik_t *fab) { static vector_tpl list; fab->get_tile_list(list); static vector_tpl tile_list; tile_list.clear(); for(koord k : list) { tile_list.append(welt->lookup_kartenboden(k)); } return tile_list; } vector_tpl const& factory_get_fields_list(fabrik_t *fab) { static vector_tpl list; fab->get_fields_list(list); return list; } vector_tpl const& square_get_halt_list(planquadrat_t *plan); // api_tiles.cc vector_tpl const& factory_get_halt_list(fabrik_t *fab) { planquadrat_t *plan = welt->access(fab->get_pos().get_2d()); return square_get_halt_list(plan); } leitung_t* factory_get_transformer( fabrik_t* fab ) { return fab->get_transformers().empty() ? NULL :fab->get_transformers().front(); } call_tool_init factory_set_name(fabrik_t *fab, const char* name) { return command_rename(welt->get_public_player(), 'f', fab->get_pos(), name); } const char* fabrik_get_raw_name(fabrik_t *fab) { return fab->get_desc()->get_name(); } SQInteger ware_production_get_production(HSQUIRRELVM vm) { fabrik_t* fab = param::get(vm, 1); sint64 prod = 0; if (fab) { sint64 scaling = 0; if (SQ_SUCCEEDED(get_slot(vm, "scaling", scaling, 1))) { // see fabrik_t::step prod = (scaling * welt->scale_with_month_length(fab->get_base_production()) * DEFAULT_PRODUCTION_FACTOR ) >> (8+8); } } return param::push(vm, prod); } SQInteger world_get_next_factory(HSQUIRRELVM vm) { return generic_get_next(vm, welt->get_fab_list().get_count()); } SQInteger world_get_factory_by_index(HSQUIRRELVM vm) { uint32 index = param::get(vm, -1); fabrik_t *fab = welt->get_fab(index); return param::push(vm, fab); } SQInteger world_get_factory_count(HSQUIRRELVM vm) { return param::push(vm, welt->get_fab_list().get_count()); } void export_factory(HSQUIRRELVM vm) { /** * Implements iterator to iterate through the list of all factories on the map. * * Usage: * @code * local list = factory_list_x() * foreach(factory in list) { * ... // factory is an instance of the factory_x class * } * @endcode */ begin_class(vm, "factory_list_x", 0); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, world_get_next_factory, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, world_get_factory_by_index, "_get", 2, "xi"); /** * Returns number of factories in the list. * @typemask integer() */ register_function(vm, world_get_factory_count, "get_count", 1, "x"); end_class(vm); /** * Class to access information about factories. * Identified by coordinate. */ begin_class(vm, "factory_x", "coord,extend_get,ingame_object"); /** * Constructor. * @param x x-coordinate * @param y y-coordinate * @typemask (integer,integer) */ register_function(vm, exp_factory_constructor, "constructor", 3, "xii"); #ifdef SQAPI_DOC // document members /** * Table containing input/consumption slots. * Entries can be retrieved by raw name of the good (as defined in the associated pak-file). * * Entries are of type factory_production_x. * * To print a list of all available goods names use this example: * @code * foreach(key,value in input) { * // print raw name of the good * print("Input slot key: " + key) * // print current storage * print("Input slot storage: " + value.get_storage()[0]) * } * @endcode * To catch the output of this example see @ref sec_err. */ table input; /** * Table containing output/production slots. * Entries can be retrieved by raw name of the good (as defined in the associated pak-file). * * Entries are of type factory_production_x. * * For an example to retrieve the list of goods, see factory_x::input. */ table output; #endif /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Get list of consumers of this factory. * @returns array of coordinates of consumers */ register_method(vm, &fabrik_t::get_consumer, "get_consumers"); /** * Get list of consumers of this factory. * @returns array of coordinates of suppliers */ register_method(vm, &fabrik_t::get_suppliers, "get_suppliers"); /** * Get (translated or custom) name of factory. * @returns name */ register_method(vm, &fabrik_t::get_name, "get_name"); /** * Get untranslated name of factory. * @returns name */ register_method(vm, &fabrik_get_raw_name, "get_raw_name", true); /** * Change name. * @ingroup rename_func */ register_method(vm, &factory_set_name, "set_name", true); /** * Get monthly statistics of production. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_production", freevariable(FAB_PRODUCTION), true); /** * Get monthly statistics of power consumption/production. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_power", freevariable(FAB_POWER), true); /** * Get monthly statistics of production boost due to electric power supply. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_boost_electric", freevariable(FAB_BOOST_ELECTRIC), true); /** * Get monthly statistics of production boost due to arrived passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_boost_pax", freevariable(FAB_BOOST_PAX), true); /** * Get monthly statistics of production boost due to arrived mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_boost_mail", freevariable(FAB_BOOST_MAIL), true); /** * Get monthly statistics of generated passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_pax_generated", freevariable(FAB_PAX_GENERATED), true); /** * Get monthly statistics of departed passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_pax_departed", freevariable(FAB_PAX_DEPARTED), true); /** * Get monthly statistics of arrived passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_pax_arrived", freevariable(FAB_PAX_ARRIVED), true); /** * Get monthly statistics of generated mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_mail_generated", freevariable(FAB_MAIL_GENERATED), true); /** * Get monthly statistics of departed mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_mail_departed", freevariable(FAB_MAIL_DEPARTED), true); /** * Get monthly statistics of arrived mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_stat, "get_mail_arrived", freevariable(FAB_MAIL_ARRIVED), true); /** * Get list of all tiles occupied by buildings belonging to this factory. * @returns array of tile_x objects */ register_method(vm, &factory_get_tile_list, "get_tile_list", true); /** * Get list of all tiles occupied by fields belonging to this factory. * @returns array of tile_x objects */ register_method(vm, &factory_get_fields_list, "get_fields_list", true); /** * Get list of all halts that serve this this factory. * @returns array of tile_x objects */ register_method(vm, &factory_get_halt_list, "get_halt_list", true); /** * Checks whether a transformer is connected. * @returns name */ register_method(vm, &fabrik_t::is_transformer_connected, "is_transformer_connected"); /** * Get connected transformer (if any). * @returns transformer */ register_method(vm, factory_get_transformer, "get_transformer", true); /** * @returns number of fields belonging to this factory */ register_method(vm, &fabrik_t::get_field_count, "get_field_count"); /** * @returns minimum number of fields required */ register_method(vm, &fabrik_t::get_min_field_count, "get_min_field_count"); /** * @returns factory descriptor */ register_method(vm, &fabrik_t::get_desc, "get_desc"); // pop class end_class(vm); /** * Class to access storage slots of factories. * Are automatically instantiated by factory_x constructor. */ begin_class(vm, "factory_production_x", "extend_get"); #ifdef SQAPI_DOC // document members /** * Maximum storage of this slot. */ integer max_storage; #endif /** * Get monthly statistics of storage. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_storage", freevariable(FAB_GOODS_STORAGE), true); /** * Get monthly statistics of received goods (for input slots). * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_received", freevariable(FAB_GOODS_RECEIVED), true); /** * Get monthly statistics of consumed goods (for input slots). * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_consumed", freevariable(FAB_GOODS_CONSUMED), true); /** * Get monthly statistics of in-transit goods (for input slots). * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_in_transit",freevariable(FAB_GOODS_TRANSIT), true); /** * Get monthly statistics of delivered goods (for output slots). * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_delivered", freevariable(FAB_GOODS_DELIVERED), true); /** * Get monthly statistics of produced goods (for output slots). * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_factory_production_stat, "get_produced", freevariable(FAB_GOODS_PRODUCED), true); /** * Returns base maximum production of this good per month. * Does not take any productivity boost into account. * @typemask integer() */ register_function(vm, &ware_production_get_production, "get_base_production", 1, "x"); /** * Returns base maximum consumption of this good per month. * Does not take any productivity boost into account. * @typemask integer() */ register_function(vm, &ware_production_get_production, "get_base_consumption", 1, "x"); /** * Returns number of consumed units of this good for the production of 100 units of generic outputs unit. * Does not take any productivity boost into account. * @typemask integer() */ register_method(vm, &get_consumption_factor, "get_consumption_factor", 1, "x"); /** * Returns number of produced units of this good due to the production of 100 units of generic outputs unit. * Does not take any productivity boost into account. * @typemask integer() */ register_method(vm, &get_production_factor, "get_production_factor", 1, "x"); // pop class end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_gui.cc000066400000000000000000000111171474050137200223710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_gui.cc exports gui-related functions. */ #include "../api_class.h" #include "../api_function.h" #include "api_simple.h" #include "../../simmesg.h" #include "../../tool/simmenu.h" #include "../../world/simworld.h" #include "../../dataobj/scenario.h" #include "../../player/simplay.h" #include "../../dataobj/environment.h" #include "../../network/network.h" #include "../../network/network_cmd_scenario.h" using namespace script_api; call_tool_work add_scenario_message_at(const char* text, my_koord3d pos) { // build param string (see tool_add_message_t::init) cbuffer_t buf; buf.printf("%d,%s", message_t::scenario, text); return call_tool_work(TOOL_ADD_MESSAGE | GENERAL_TOOL, (const char*)buf, 0, welt->get_active_player(), pos).set_no_block(true); } call_tool_work add_ai_message_at(player_t *player, const char* text, my_koord3d pos) { // build param string (see tool_add_message_t::init) cbuffer_t buf; buf.printf("%d,%s", message_t::ai, text); return call_tool_work(TOOL_ADD_MESSAGE | GENERAL_TOOL, (const char*)buf, 0, player, pos).set_no_block(true); } call_tool_work add_scenario_message(player_t* player, const char* text) { // build param string (see tool_add_message_t::init) cbuffer_t buf; buf.printf("%d,%s", message_t::scenario, text); return call_tool_work(TOOL_ADD_MESSAGE | GENERAL_TOOL, (const char*)buf, 0, player ? player : welt->get_active_player(), koord3d::invalid).set_no_block(true); } void open_info_win_client(const char* tab, uint8 player_nr) { if (env_t::server) { // void network_send_all(network_command_t* nwc, bool exclude_us ) nwc_scenario_t *nwc = new nwc_scenario_t(); nwc->what = nwc_scenario_t::OPEN_SCEN_WIN; nwc->function = tab; network_send_all(nwc, false, player_nr); } else { welt->get_scenario()->open_info_win(tab); } } void open_info_win_at(const char* tab) { open_info_win_client(tab, PLAYER_UNOWNED); } void open_info_win() { open_info_win_client("", PLAYER_UNOWNED); } void export_gui(HSQUIRRELVM vm, bool scenario) { /** * Table with methods to access gui functions. */ begin_class(vm, "gui", 0); if (scenario) { /** * Opens scenario info window and shows 'info' tab. * In network mode, opens window on all clients and server. * @note Only available in scenario mode. */ STATIC register_method(vm, open_info_win, "open_info_win", true); /** * Opens scenario info window with specific tab open. * In network mode, opens window on all clients and server. * @param tab possible values are "info", "goal", "rules", "result", "about", "debug" * @note Only available in scenario mode. */ STATIC register_method(vm, open_info_win_at, "open_info_win_at"); /** * Opens scenario info window for certain clients (and the server), * with specific tab open. * @param tab possible values are "info", "goal", "rules", "result", "about", "debug" * @param player_nr opens scenario info window on all clients that have this player unlocked. * @note Window is always opened on server. */ STATIC register_method(vm, open_info_win_client, "open_info_win_client"); /** * Adds message to the players mailboxes. * Will be shown in ticker or as pop-up window depending on players preferences. * Message window has small view of world. * * @param text Text to be shown. Has to be a translated string or a translatable string. * @param position Position of the view on the map. Clicking on the message will center viewport at this position. * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &add_scenario_message_at, "add_message_at"); /** * Adds message to the players mailboxes. * Will be shown in ticker or as pop-up window depending on players preferences. * * @param text Text to be shown. Has to be a translated string or a translatable string. * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &add_scenario_message, "add_message"); } else { /** * Adds message to the players mailboxes. * Will be shown in ticker or as pop-up window depending on players preferences. * Message window has small view of world. * * @param player sending this message * @param text Text to be shown. Has to be a translated string or a translatable string. * @param position Position of the view on the map. Clicking on the message will center viewport at this position. * @ingroup ai_only */ STATIC register_method(vm, &add_ai_message_at, "add_message_at"); } end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_halt.cc000066400000000000000000000226471474050137200225470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_halt.cc exports halt/station related functions. */ #include "get_next.h" #include "api_obj_desc_base.h" #include "../api_class.h" #include "../api_function.h" #include "../../simhalt.h" #include "../../world/simworld.h" halthandle_t get_halt_from_koord3d(koord3d pos, const player_t *player ); // api_schedule.cc, interfaces haltestelle_t::get_halt namespace script_api { declare_specialized_param(haltestelle_t::tile_t, "t|x|y", "tile_x"); declare_specialized_param(haltestelle_t::connection_t, "t|x|y", "halt_x"); SQInteger param::push(HSQUIRRELVM vm, haltestelle_t::tile_t const& v) { return param::push(vm, v.grund); } SQInteger param::push(HSQUIRRELVM vm, haltestelle_t::connection_t const& v) { return param::push(vm, v.halt); } }; using namespace script_api; vector_tpl const& get_halt_stat(const haltestelle_t *halt, sint32 INDEX) { static vector_tpl v; v.clear(); if (halt && 0<=INDEX && INDEXget_finance_history(i, INDEX) ); } } return v; } bool is_rerouting_finished() { return haltestelle_t::get_rerouting_status() == 0 && haltestelle_t::get_reconnect_counter() == world()->get_schedule_counter(); } SQInteger world_get_next_halt(HSQUIRRELVM vm) { return generic_get_next(vm, haltestelle_t::get_alle_haltestellen().get_count()); } SQInteger world_get_halt_by_index(HSQUIRRELVM vm) { sint32 index = param::get(vm, -1); const vector_tpl& list = haltestelle_t::get_alle_haltestellen(); halthandle_t halt = (0<=index && (uint32)index::push(vm, halt); } SQInteger halt_export_convoy_list(HSQUIRRELVM vm) { halthandle_t halt = param::get(vm, 1); if (halt.is_bound()) { push_instance(vm, "convoy_list_x"); set_slot(vm, "halt_id", halt.get_id()); return 1; } else { sq_raise_error(vm, "Invalid halt id %d", halt.get_id()); return SQ_ERROR; } } call_tool_init halt_set_name(halthandle_t halt, const char* name) { if (!halt.is_bound()) { return "Invalid halt provided"; } return command_rename(halt->get_owner(), 'h', halt.get_id(), name); } SQInteger halt_export_line_list(HSQUIRRELVM vm) { halthandle_t halt = param::get(vm, 1); if (halt.is_bound()) { push_instance(vm, "line_list_x"); set_slot(vm, "halt_id", halt.get_id()); return 1; } else { sq_raise_error(vm, "Invalid halt id %d", halt.get_id()); return SQ_ERROR; } } uint32 halt_get_capacity(const haltestelle_t *halt, const goods_desc_t *desc) { // passenger has index 0, mail 1, everything else >=2 return halt && desc ? halt->get_capacity(min( desc->get_catg_index(), 2 )) : 0; } // 0: not connected // 1: connected // -1: undecided sint8 is_halt_connected(const haltestelle_t *a, halthandle_t b, const goods_desc_t *desc) { if (desc == 0 || a == NULL || !b.is_bound()) { return 0; } return a->is_connected(b, desc->get_catg_index()); } // compare two halts to find out if they are the same SQInteger halt_compare(halthandle_t a, halthandle_t b) { return (SQInteger)a.get_id() - (SQInteger)b.get_id(); } vector_tpl const& halt_get_connections(const haltestelle_t *halt, const goods_desc_t* freight) { static vector_tpl dummy; dummy.clear(); return freight ? halt->get_connections(freight->get_catg_index()) : dummy; } void export_halt(HSQUIRRELVM vm) { /** * Implements iterator to iterate through the list of all halts on the map. * * Usage: * @code * local list = halt_list_x() * foreach(halt in list) { * ... // halt is an instance of the halt_x class * } * @endcode */ create_class(vm, "halt_list_x"); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, world_get_next_halt, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. * @typemask halt_x() */ register_function(vm, world_get_halt_by_index, "_get", 2, "xi"); end_class(vm); /** * Class to access halts / stations / bus stops. */ begin_class(vm, "halt_x", "extend_get,ingame_object"); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Station name. * @returns name */ register_method(vm, &haltestelle_t::get_name, "get_name"); /** * Sets station name. * @ingroup rename_func */ register_method(vm, &halt_set_name, "set_name", true); /** * Station owner. * @returns owner */ register_method(vm, &haltestelle_t::get_owner, "get_owner"); /** * compare classes using metamethods * @param halt the other halt * @returns difference in the unique id of the halthandle */ register_method(vm, &halt_compare, "_cmp", true); /** * Quick check if there is connection for certain freight to the other halt. * @param halt the other halt * @param freight_type freight type * @return 0 - not connected, 1 - connected, -1 - undecided (call this method again later) */ register_method(vm, &is_halt_connected, "is_connected", true); /** * Does this station accept this type of good? * @param freight_type freight type * @returns the answer to this question */ register_method(vm, &haltestelle_t::is_enabled, "accepts_good", false); /** * Get monthly statistics of number of arrived goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_arrived", freevariable(HALT_ARRIVED), true); /** * Get monthly statistics of number of departed goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_departed", freevariable(HALT_DEPARTED), true); /** * Get monthly statistics of number of waiting goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_waiting", freevariable(HALT_WAITING), true); /** * Get monthly statistics of number of happy passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_happy", freevariable(HALT_HAPPY), true); /** * Get monthly statistics of number of unhappy passengers. * * These passengers could not start their journey as station was crowded. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_unhappy", freevariable(HALT_UNHAPPY), true); /** * Get monthly statistics of number of passengers with no-route. * * These passengers could not start their journey as they find no route to their destination. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_noroute", freevariable(HALT_NOROUTE), true); /** * Get monthly statistics of number of convoys that stopped at this station. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_convoys", freevariable(HALT_CONVOIS_ARRIVED), true); /** * Get monthly statistics of number of passengers that could walk to their destination. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_halt_stat, "get_walked", freevariable(HALT_WALKED), true); /** * Exports list of convoys that stop at this halt. * @typemask convoy_list_x() */ register_function(vm, &halt_export_convoy_list, "get_convoy_list", 1, param::typemask()); /** * Exports list of lines that serve this halt. * @typemask line_list_x() */ register_function(vm, &halt_export_line_list, "get_line_list", 1, param::typemask()); /** * Get list of tiles belonging to this station. */ register_method(vm, &haltestelle_t::get_tiles, "get_tile_list"); /** * Get list of factories connected to this station. */ register_method(vm, &haltestelle_t::get_fab_list, "get_factory_list"); /** * Returns amount of @p freight at this halt that is going to @p target * @param freight freight type * @param target coordinate of target */ register_method(vm, &haltestelle_t::get_ware_fuer_zielpos, "get_freight_to_dest"); /** * Returns amount of @p freight at this halt that scheduled to @p stop * @param freight freight type * @param stop next transfer stop */ register_method(vm, &haltestelle_t::get_ware_fuer_zwischenziel, "get_freight_to_halt"); /** * Returns capacity of this halt for the given @p freight * @param freight freight type */ register_method(vm, &halt_get_capacity, "get_capacity", true); /** * Returns list of connected halts for the specific @p freight type. * @param freight freight type */ register_method(vm, &halt_get_connections, "get_connections", true); /** * Returns halt at given position. * @param pos coordinate * @param pl player that wants to use halt here * @return halt instance */ STATIC register_method(vm, &get_halt_from_koord3d, "get_halt", false, true); /** * Checks if the rerouting of halts is finsihed * @return true if all reconnections are finished */ STATIC register_method(vm, &is_rerouting_finished, "is_rerouting_finished", false, true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_include.cc000066400000000000000000000040061474050137200232270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "../api_function.h" #include "../../../squirrel/sqstdio.h" // for loadfile #include "../../../squirrel/sq_extensions.h" // for sq_call_restricted #include "../../sys/simsys.h" #include "../../dataobj/environment.h" /** @file api_include.cc exports include. */ using namespace script_api; SQInteger include_aux(HSQUIRRELVM vm) { const char* filename = param::get(vm, 2); const char* include_path = param::get(vm, 3); if (filename == NULL) { return sq_raise_error(vm, "Include got filename"); } // path to scenario files cbuffer_t buf; buf.printf("%s%s%s.nut", include_path, PATH_SEPARATOR, filename); struct stat dummy; if (dr_stat(buf,&dummy)) { // file does not exist, try other path buf.clear(); buf.printf("%sscript%s%s.nut", env_t::base_dir, PATH_SEPARATOR, filename); } // load script if (!SQ_SUCCEEDED(sqstd_loadfile(vm, (const char*)buf, true))) { return sq_raise_error(vm, "Reading / compiling script %s failed", filename); } // call it sq_pushroottable(vm); if (!SQ_SUCCEEDED(sq_call_restricted(vm, 1, SQFalse, SQTrue, 100000))) { sq_pop(vm, 1); // pop script return sq_raise_error(vm, "Call script %s failed", filename); } if (sq_getvmstate(vm) == SQ_VMSTATE_SUSPENDED) { return sq_raise_error(vm, "Calling scriptfile %s took too long", filename); } sq_pop(vm, 1); // pop script return SQ_OK; } void export_include(HSQUIRRELVM vm, const char* include_path) { sq_pushroottable(vm); /** * Includes the given file. * The file will be included in global scope. * Inclusion happens when the include-command gets executed. * No compile time inclusion! * @param filename name of file to be included (relative to scenario directory, without .nut extension) * @typemask void(string) */ register_function_fv(vm, &include_aux, "include", 2, ".s", freevariable(include_path)); sq_pop(vm, 1); // root table } simutrans-124.3/src/simutrans/script/api/api_line.cc000066400000000000000000000201411474050137200225310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_line.cc exports line related functions. */ #include "get_next.h" #include "api_obj_desc_base.h" #include "../api_class.h" #include "../api_function.h" #include "../../simhalt.h" #include "../../simline.h" #include "../../world/simworld.h" #include "../../player/simplay.h" // for manipulation of lines #include "../../tool/simmenu.h" #include "../../dataobj/schedule.h" // template<> schedule_t* script_api::param::get(HSQUIRRELVM, SQInteger); using namespace script_api; vector_tpl const& get_line_stat(simline_t *line, sint32 INDEX) { static vector_tpl v; v.clear(); if (line && 0<=INDEX && INDEXget_stat_converted(i, INDEX) ); } } return v; } waytype_t line_way_type(simline_t *line) { if (line) { switch (line->get_linetype()) { case simline_t::truckline: return road_wt; case simline_t::trainline: return track_wt; case simline_t::shipline: return water_wt; case simline_t::monorailline: return monorail_wt; case simline_t::maglevline: return maglev_wt; case simline_t::narrowgaugeline: return narrowgauge_wt; case simline_t::airline: return air_wt; case simline_t::tramline: return tram_wt; default: ; } } return invalid_wt; } call_tool_init line_change_schedule(simline_t* line, player_t *player, schedule_t *sched) { if (sched) { cbuffer_t buf; // make a copy, and perform validation on it schedule_t *copy = sched->copy(); copy->make_valid(); if (copy->get_count() >= 2) { // build param string (see line_management_gui_t::apply_schedule) buf.printf( "g,%i,", line->get_handle().get_id() ); copy->sprintf_schedule( buf ); } else { return "Invalid schedule provided: less than two entries remained after removing doubles"; } delete copy; return call_tool_init(TOOL_CHANGE_LINE | SIMPLE_TOOL, buf, 0, player); } return "Invalid schedule provided"; } call_tool_init line_delete(simline_t* line, player_t *player) { if (line->count_convoys() == 0) { cbuffer_t buf; buf.printf( "d,%i", line->get_handle().get_id() ); return call_tool_init(TOOL_CHANGE_LINE | SIMPLE_TOOL, buf, 0, player); } return "Cannot delete lines with associated convoys"; } SQInteger line_export_convoy_list(HSQUIRRELVM vm) { linehandle_t line = param::get(vm, 1); if (line.is_bound()) { push_instance(vm, "convoy_list_x"); set_slot(vm, "line_id", line.get_id()); return 1; } sq_raise_error(vm, "Invalid line handle provided"); return SQ_ERROR; } call_tool_init line_set_name(simline_t* line, const char* name) { return command_rename(line->get_owner(), 'l', line->get_handle().get_id(), name); } vector_tpl const* generic_get_line_list(HSQUIRRELVM vm, SQInteger index) { uint16 id; if (SQ_SUCCEEDED(get_slot(vm, "halt_id", id, index))) { halthandle_t halt; halt.set_id(id); if (halt.is_bound()) { return &halt->registered_lines; } } if (SQ_SUCCEEDED(get_slot(vm, "player_id", id, index)) && id < PLAYER_UNOWNED) { if (player_t *player = welt->get_player(id)) { return &player->simlinemgmt.get_line_list(); } } sq_raise_error(vm, "Invalid line list."); return NULL; } SQInteger generic_get_next_line(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_line_list(vm, 1); return list ? generic_get_next(vm, list->get_count()) : SQ_ERROR; } SQInteger generic_get_line_by_index(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_line_list(vm, 1); sint32 index = param::get(vm, 2); linehandle_t line; if (list) { line = (0<=index && (uint32)index < list->get_count()) ? (*list)[index] : linehandle_t(); return push_instance(vm, "line_x", line.is_bound() ? line.get_id() : 0); } return SQ_ERROR; } SQInteger generic_get_line_count(HSQUIRRELVM vm) { vector_tpl const* list = generic_get_line_list(vm, 1); return param::push(vm, list ? list->get_count() : 0); } void export_line(HSQUIRRELVM vm) { /** * Implements iterator to iterate through lists of lines. * * Usage: * @code * local list = player_x(0).get_line_list() * foreach(line in list) { * ... // line is an instance of the line_x class * } * @endcode * * @see player_x::get_line_list, halt_x::get_line_list */ begin_class(vm, "line_list_x", 0); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, generic_get_next_line, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. * @typemask line_x() */ register_function(vm, generic_get_line_by_index, "_get", 2, "xi"); /** * Returns number of lines in the list. * @typemask integer() */ register_function(vm, generic_get_line_count, "get_count", 1, "x"); end_class(vm); /** * Class to access lines. */ begin_class(vm, "line_x", "extend_get,ingame_object"); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Line name. * @returns name */ register_method(vm, &simline_t::get_name, "get_name"); /** * Sets line name. * @ingroup rename_func * @typemask void(string) */ register_method(vm, &line_set_name, "set_name", true); /** * Line owner. * @returns owner */ register_method(vm, &simline_t::get_owner, "get_owner"); /** * Schedule of this line. */ register_method(vm, &simline_t::get_schedule, "get_schedule"); /** * Returns array of goods categories that can be transported by this convoy. * @returns array */ register_method(vm, &simline_t::get_goods_catg_index, "get_goods_catg_index"); /** * Get monthly statistics of capacity. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_capacity", freevariable(LINE_CAPACITY), true); /** * Get monthly statistics of number of transported goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_transported_goods", freevariable(LINE_TRANSPORTED_GOODS), true ); /** * Get monthly statistics of number of convoys in this line. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_convoy_count", freevariable(LINE_CONVOIS), true ); /** * Get monthly statistics of revenue. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_revenue", freevariable(LINE_REVENUE), true ); /** * Get monthly statistics of running costs. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_cost", freevariable(LINE_OPERATIONS), true ); /** * Get monthly statistics of profit. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_profit", freevariable(LINE_PROFIT), true ); /** * Get monthly statistics of traveled distance. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_traveled_distance", freevariable(LINE_DISTANCE), true ); /** * Get monthly statistics of income/loss due to way tolls. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_line_stat, "get_way_tolls", freevariable(LINE_WAYTOLL), true ); /** * Exports list of convoys belonging to this line. * @typemask convoy_list_x() */ register_function(vm, &line_export_convoy_list, "get_convoy_list", 1, param::typemask()); /** * @return waytype of the line */ register_method(vm, &line_way_type, "get_waytype", true); /** * Change schedule of line. * Schedule should not contain doubled entries and more than two entries. * @ingroup game_cmd */ register_method(vm, line_change_schedule, "change_schedule", true); /** * Delete line * @ingroup game_cmd */ register_method(vm, line_delete, "destroy", true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_map_objects.cc000066400000000000000000000567161474050137200241110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_map_objects.cc exports all map-objects. */ #include "api_obj_desc_base.h" #include "api_simple.h" #include "../api_class.h" #include "../api_function.h" #include "../../obj/simobj.h" #include "../../obj/depot.h" #include "../../world/simworld.h" #include "../../ground/grund.h" #include "../../dataobj/scenario.h" #include "../../descriptor/ground_desc.h" #include "../../obj/baum.h" #include "../../obj/bruecke.h" #include "../../obj/gebaeude.h" #include "../../obj/field.h" #include "../../obj/label.h" #include "../../obj/leitung2.h" #include "../../obj/roadsign.h" #include "../../obj/signal.h" #include "../../obj/tunnel.h" #include "../../obj/wayobj.h" #include "../../player/simplay.h" // for depot tools #include "../../simconvoi.h" #include "../../tool/simmenu.h" #include "../../descriptor/building_desc.h" #include "../../descriptor/vehicle_desc.h" using namespace script_api; // use pointers to obj_t_tag[ ] to tag the obj_t classes static uint8 obj_t_tag[256]; /* * template struct to bind obj_t::typ to obj_t classes */ template struct bind_code; /* * Class to templatify access of obj_t objects */ template struct access_objs { /* * Access object: check whether object is still on this tile. */ static D* get_by_pos(HSQUIRRELVM vm, SQInteger index) { SQUserPointer tag = obj_t_tag + bind_code::objtype; SQUserPointer p = NULL; if (SQ_SUCCEEDED(sq_getinstanceup(vm, index, &p, tag)) && p) { D *obj = static_cast(p); koord3d pos = param::get(vm, index); grund_t *gr = welt->lookup(pos); if (gr && gr->obj_ist_da(obj)) { return obj; } else { // object or tile disappeared: clear userpointer sq_setinstanceup(vm, index, NULL); } sq_raise_error(vm, "Object of type %s vanished from (%s).", param::squirrel_type(), pos.get_str()); } else { sq_raise_error(vm, "Object is not of type %s.", param::squirrel_type); } return NULL; } /* * Create instance: call constructor with coordinates. */ static SQInteger push_with_pos(HSQUIRRELVM vm, D* const& obj) { if (obj == NULL) { sq_pushnull(vm); return 1; } koord pos = obj->get_pos().get_2d(); coordinate_transform_t::koord_w2sq(pos); sint16 x = pos.x; sint16 y = pos.y; sint8 z = obj->get_pos().z; if (bind_code::objtype == obj_t::obj) { // generic object, object type as fourth parameter if (!SQ_SUCCEEDED(push_instance(vm, script_api::param::squirrel_type(), x, y, z, obj->get_typ()))) { return SQ_ERROR; } } else if (bind_code::objtype != obj->get_typ()) { // obj is instance of derived class return script_api::param::push(vm, obj); } else { // specific object with its own constructor, type already preset as default parameter if (!SQ_SUCCEEDED(push_instance(vm, script_api::param::squirrel_type(), x, y, z))) { return SQ_ERROR; } } sq_setinstanceup(vm, -1, obj); return 1; } }; SQInteger exp_obj_pos_constructor(HSQUIRRELVM vm) // parameters: sint16 x, sint16 y, sint8 z, obj_t::typ type { // get coordinates sint16 x = param::get(vm, 2); sint16 y = param::get(vm, 3); sint8 z = param::get(vm, 4); // set coordinates set_slot(vm, "x", x, 1); set_slot(vm, "y", y, 1); koord pos(x,y); coordinate_transform_t::koord_sq2w(pos); // find tile - some objects have larger z-coordinate (e.g., on foundations) grund_t *gr = welt->lookup(koord3d(pos, z)); for(uint8 i=1, end = ground_desc_t::double_grounds ? 2 : 1; gr == NULL && i<=end; i++) { gr = welt->lookup(koord3d(pos, z-i)); } // find object and set instance up if (gr) { // correct z-coordinate set_slot(vm, "z", gr->get_pos().z, 1); // search for object obj_t::typ type = (obj_t::typ)param::get(vm, 5); obj_t *obj = NULL; if (type == obj_t::roadsign || type == obj_t::signal) { // special treatment of signals/roadsigns obj = gr->suche_obj(obj_t::roadsign); if (obj == NULL) { obj = gr->suche_obj(obj_t::signal); } } else if (type == obj_t::pumpe || type == obj_t::senke) { obj = gr->suche_obj(obj_t::pumpe); if (obj == NULL) { obj = gr->suche_obj(obj_t::senke); } } else if (type != obj_t::old_airdepot) { // special treatment of depots obj = gr->suche_obj(type); } else { obj = gr->get_depot(); } if (obj) { sq_setinstanceup(vm, 1, obj); return SQ_OK; } } return sq_raise_error(vm, "No object of requested type on tile (or no tile at this position)"); } template<> struct bind_code { static const uint8 objtype = obj_t::obj; }; // macro to implement get and push for obj_t's with position #define getpush_obj_pos(D, type) \ D* script_api::param::get(HSQUIRRELVM vm, SQInteger index) \ { \ return access_objs::get_by_pos(vm, index); \ } \ SQInteger script_api::param::push(HSQUIRRELVM vm, D* const& obj) \ { \ return access_objs::push_with_pos(vm, obj); \ } \ template<> struct bind_code { static const uint8 objtype = type; }; // implementation of get and push by macros getpush_obj_pos(baum_t, obj_t::baum); getpush_obj_pos(gebaeude_t, obj_t::gebaeude); getpush_obj_pos(label_t, obj_t::label); getpush_obj_pos(weg_t, obj_t::way); getpush_obj_pos(leitung_t, obj_t::leitung); getpush_obj_pos(field_t, obj_t::field); getpush_obj_pos(wayobj_t, obj_t::wayobj); getpush_obj_pos(bruecke_t, obj_t::bruecke); getpush_obj_pos(tunnel_t, obj_t::tunnel); namespace script_api { // each depot has its own class declare_specialized_param(depot_t*, "t|x|y", "depot_x"); declare_specialized_param(airdepot_t*, "t|x|y", "depot_x"); declare_specialized_param(narrowgaugedepot_t*, "t|x|y", "depot_x"); declare_specialized_param(bahndepot_t*, "t|x|y", "depot_x"); declare_specialized_param(strassendepot_t*, "t|x|y", "depot_x"); declare_specialized_param(schiffdepot_t*, "t|x|y", "depot_x"); declare_specialized_param(monoraildepot_t*, "t|x|y", "depot_x"); declare_specialized_param(tramdepot_t*, "t|x|y", "depot_x"); declare_specialized_param(maglevdepot_t*, "t|x|y", "depot_x"); // map roadsign_t and signal_t to the same class declare_specialized_param(roadsign_t*, "t|x|y", "sign_x"); declare_specialized_param(signal_t*, "t|x|y", "sign_x"); // map all to one transformer class declare_specialized_param(pumpe_t*, "t|x|y", "transformer_x"); declare_specialized_param(senke_t*, "t|x|y", "transformer_x"); }; // base depot class, use old_airdepot as identifier here getpush_obj_pos(depot_t, obj_t::old_airdepot); // now all the derived classes getpush_obj_pos(airdepot_t, obj_t::airdepot); getpush_obj_pos(narrowgaugedepot_t, obj_t::narrowgaugedepot); getpush_obj_pos(bahndepot_t, obj_t::bahndepot); getpush_obj_pos(strassendepot_t, obj_t::strassendepot); getpush_obj_pos(schiffdepot_t, obj_t::schiffdepot); getpush_obj_pos(monoraildepot_t, obj_t::monoraildepot); getpush_obj_pos(tramdepot_t, obj_t::tramdepot); getpush_obj_pos(maglevdepot_t, obj_t::maglevdepot); // roadsigns/signals getpush_obj_pos(roadsign_t, obj_t::roadsign); getpush_obj_pos(signal_t, obj_t::signal); // powerlines getpush_obj_pos(pumpe_t, obj_t::pumpe); getpush_obj_pos(senke_t, obj_t::senke); #define case_resolve_obj(D) \ case bind_code::objtype: \ return script_api::param::push(vm, (D*)obj); // we have to resolve instances of derived classes here... SQInteger script_api::param::push(HSQUIRRELVM vm, obj_t* const& obj) { if (obj == NULL) { sq_pushnull(vm); return 1; } obj_t::typ type = obj->get_typ(); switch(type) { case_resolve_obj(baum_t); case_resolve_obj(gebaeude_t); case_resolve_obj(label_t); case_resolve_obj(weg_t); case_resolve_obj(roadsign_t); case_resolve_obj(signal_t); case_resolve_obj(field_t); case_resolve_obj(airdepot_t); case_resolve_obj(narrowgaugedepot_t); case_resolve_obj(bahndepot_t); case_resolve_obj(strassendepot_t); case_resolve_obj(schiffdepot_t); case_resolve_obj(monoraildepot_t); case_resolve_obj(tramdepot_t); case_resolve_obj(maglevdepot_t); case_resolve_obj(leitung_t); case_resolve_obj(pumpe_t); case_resolve_obj(senke_t); case_resolve_obj(wayobj_t); case_resolve_obj(bruecke_t); case_resolve_obj(tunnel_t); default: return access_objs::push_with_pos(vm, obj); } } obj_t* script_api::param::get(HSQUIRRELVM vm, SQInteger index) { return access_objs::get_by_pos(vm, index); } // return way ribis, have to implement a wrapper, to correctly rotate ribi static SQInteger get_way_ribi(HSQUIRRELVM vm) { weg_t *w = param::get(vm, 1); bool masked = param::get(vm, 2); ribi_t::ribi ribi = w ? (masked ? w->get_ribi() : w->get_ribi_unmasked() ) : 0; return param::push(vm, ribi); } template static SQInteger map_obj_to_string(HSQUIRRELVM vm) // parameters: obj { static cbuffer_t buf; buf.clear(); koord3d pos = script_api::param::get(vm, 1); D* obj = script_api::param::get(vm, 1); buf.printf("%s@%s", script_api::param::squirrel_type(), pos.get_str()); if (obj == NULL) { buf.append(" [invalid]"); } sq_pushstring(vm, (const char*)buf, -1); return 1; } // create class template static void begin_obj_class(HSQUIRRELVM vm, const char* name, const char* base = NULL) { SQInteger res = create_class(vm, name, base); if( !SQ_SUCCEEDED(res) ) { // base class not found: maybe script_base.nut is not up-to-date dbg->error( "begin_obj_class()", "Create class failed for %s. Base class %s missing. Please update simutrans (or just script/script_base.nut)!", name, base ); sq_raise_error(vm, "Create class failed for %s. Base class %s missing. Please update simutrans (or just script/script_base.nut)!", name, base); } uint8 objtype = bind_code::objtype; // store typetag to identify pointers sq_settypetag(vm, -1, obj_t_tag + objtype); // export constructor register_function_fv(vm, exp_obj_pos_constructor, "constructor", 4, "xiiii", freevariable(objtype)); // export _tostring method register_function(vm, map_obj_to_string, "_tostring", 1, "x"); // now functions can be registered } // mark objects static void mark_object(obj_t* obj) { obj->set_flag(obj_t::highlight); obj->set_flag(obj_t::dirty); } static void unmark_object(obj_t* obj) { obj->clear_flag(obj_t::highlight); obj->set_flag(obj_t::dirty); } static bool object_is_marked(obj_t* obj) { return obj->get_flag(obj_t::highlight); } // markers / labels static call_tool_work create_marker(koord pos, player_t* player, const char* text) { if (text == NULL) { return "Cannot create label with text == null"; } return call_tool_work(TOOL_MARKER | GENERAL_TOOL, text, 0, player, koord3d(pos, 0)); } static call_tool_init label_set_text(label_t *l, const char* text) { return command_rename(l->get_owner(), 'm', l->get_pos(), text); } static const char* label_get_text(label_t* l) { if (l) { if (grund_t *gr = welt->lookup(l->get_pos())) { return gr->get_text(); } } return NULL; } // roadsign static bool roadsign_can_pass(const roadsign_t* rs, player_t* player) { return player && rs->get_desc()->is_private_way() ? (rs->get_player_mask() & (1<get_player_nr()))!=0 : true; } // depot static call_tool_init depot_append_vehicle(depot_t *depot, player_t *player, convoihandle_t cnv, const vehicle_desc_t *desc) { if (desc == NULL) { return "Invalid vehicle_desc_x provided"; } // see depot_frame_t::image_from_storage_list: tool = 'a' // see depot_t::call_depot_tool for command string composition cbuffer_t buf; buf.printf( "%c,%s,%hu,%s", 'a', depot->get_pos().get_str(), cnv.get_id(), desc->get_name()); return call_tool_init(TOOL_CHANGE_DEPOT | SIMPLE_TOOL, buf, 0, player); } static call_tool_init depot_start_convoy(depot_t *depot, player_t *player, convoihandle_t cnv) { // see depot_frame_t::action_triggered: tool = 'b' // see depot_t::call_depot_tool for command string composition cbuffer_t buf; if (cnv.is_bound()) { buf.printf( "%c,%s,%hu", 'b', depot->get_pos().get_str(), cnv->self.get_id()); } else { buf.printf( "%c,%s,%hu", 'B', depot->get_pos().get_str(), 0); } return call_tool_init(TOOL_CHANGE_DEPOT | SIMPLE_TOOL, buf, 0, player); } static vector_tpl const& depot_get_convoy_list(depot_t *depot) { static vector_tpl list; list.clear(); if (depot==NULL) { return list; } // fill list slist_tpl const& slist = depot->get_convoy_list(); for(slist_tpl::const_iterator i = slist.begin(), end = slist.end(); i!=end; ++i) { list.append(*i); } return list; } static vector_tpl const& get_depot_list(player_t *player, waytype_t wt) { static vector_tpl list; list.clear(); // do the conversion of waytype_t to depot-type by linetype simline_t::linetype line_type = simline_t::waytype_to_linetype(wt); if (player == NULL || line_type == simline_t::MAX_LINE_TYPE) { return list; } // fill list const slist_tpl &depot_list = depot_t::get_depot_list(); for(depot_t* d : depot_list) { if(d->get_line_type()==line_type && d->get_owner()==player) { list.append(d); } } return list; } static const fabrik_t* transformer_get_factory(leitung_t *lt) { if (pumpe_t *p = dynamic_cast(lt)) { return p->get_factory(); } if (senke_t *s = dynamic_cast(lt)) { return s->get_factory(); } return NULL; } static bool leitung_is_connected(leitung_t* lt1, leitung_t* lt2) { return lt2 != NULL && lt1->get_net() == lt2->get_net(); } static bool field_is_deletable(field_t* f) { return f->get_removal_error( welt->get_public_player() ) == NULL; } static vector_tpl const& get_way_stat(weg_t* weg, sint32 INDEX) { static vector_tpl v; v.clear(); if (weg && 0<=INDEX && INDEXget_stat(i, INDEX) ); } } return v; } static vector_tpl const& get_tile_list( gebaeude_t *gb ) { static vector_tpl list; gb->get_tile_list( list ); return list; } void export_map_objects(HSQUIRRELVM vm) { /** * Class to access objects on the map * These classes cannot modify anything. */ begin_class(vm, "map_object_x", "coord3d,extend_get,ingame_object"); uint8 objtype = bind_code::objtype; sq_settypetag(vm, -1, obj_t_tag + objtype); /** * Constructor. Implemented by derived classes. * Fails if no object of precisely the requested type is on the tile. * If there is more than one object of this type on the tile then it will return the first. * @param x * @param y * @param z * @param type of the map object * @typemask void(integer,integer,integer,map_objects) */ register_function(vm, exp_obj_pos_constructor, "constructor", 5, "xiiii"); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * @returns owner of the object. */ register_method(vm, &obj_t::get_owner, "get_owner"); /** * @returns raw name. */ register_method(vm, &obj_t::get_name, "get_name"); /** * @returns way type, can be @ref wt_invalid. */ register_method(vm, &obj_t::get_waytype, "get_waytype"); /** * @returns position. */ register_method(vm, &obj_t::get_pos, "get_pos"); /** * Checks whether player can remove this object. * @returns error message or null if object can be removed. */ register_method(vm, &obj_t::get_removal_error, "is_removable"); /** * @returns type of object. */ register_method(vm, &obj_t::get_typ, "get_type"); /** * Marks the object for highlighting. Use with care. */ register_method(vm, &mark_object, "mark", true); /** * Unmarks the object for highlighting. */ register_method(vm, &unmark_object, "unmark", true); /** * @returns whether object is highlighted. */ register_method(vm, &object_is_marked, "is_marked", true); end_class(vm); /** * Trees on the map. */ begin_obj_class(vm, "tree_x", "map_object_x"); /** * @returns age of tree in months. */ register_method(vm, &baum_t::get_age, "get_age"); /** * @returns object descriptor. */ register_method(vm, &baum_t::get_desc, "get_desc"); end_class(vm); /** * Buildings. */ begin_obj_class(vm, "building_x", "map_object_x"); /** * @returns factory if building belongs to one, otherwise null */ register_method(vm, &gebaeude_t::get_fabrik, "get_factory"); /** * @returns city if building belongs to one, otherwise null */ register_method(vm, &gebaeude_t::get_stadt, "get_city"); /** * @returns whether building is townhall */ register_method(vm, &gebaeude_t::is_townhall, "is_townhall"); /** * @returns whether building is headquarters */ register_method(vm, &gebaeude_t::is_headquarter, "is_headquarter"); /** * @returns whether building is a monument */ register_method(vm, &gebaeude_t::is_monument, "is_monument"); /** * Passenger level controls how many passengers will be generated by this building. * @returns passenger level */ register_method(vm, &gebaeude_t::get_passagier_level, "get_passenger_level"); /** * Mail level controls how many mail will be generated by this building. * @returns mail level */ register_method(vm, &gebaeude_t::get_mail_level, "get_mail_level"); /** * @returns object descriptor. */ register_method(vm, &gebaeude_t::get_tile, "get_desc"); /** * @returns coord for all tiles */ register_method( vm, &get_tile_list, "get_tile_list", true ); /** * @returns true if both building tiles are part of one (multi-tile) building */ register_method(vm, &gebaeude_t::is_same_building, "is_same_building"); end_class(vm); /** * Class to access depots. * Main purpose is the manipulation of convoys in depots. */ begin_obj_class(vm, "depot_x", "building_x"); /** * Append a car to the convoy in this depot. If the convoy does not exist, a new one is created first. * @param pl player owns the convoy * @param cnv the convoy * @param desc decriptor of the vehicle * @ingroup game_cmd */ register_method(vm, depot_append_vehicle, "append_vehicle", true); /** * Start the convoy in this depot. * @ingroup game_cmd */ register_method(vm, depot_start_convoy, "start_convoy", true); /** * Start all convoys in this depot. * @ingroup game_cmd */ register_method_fv(vm, depot_start_convoy, "start_all_convoys", freevariable(convoihandle_t()), true); /** * @returns list of convoys sitting in this depot */ register_method(vm, &depot_get_convoy_list, "get_convoy_list", true); /** * List of all depots of player @p pl of way-type @p wt * @param pl * @param wt * @returns depot list of player */ STATIC register_method(vm, &get_depot_list, "get_depot_list", false, true); end_class(vm); /** * Ways. */ begin_obj_class(vm, "way_x", "map_object_x"); /** * @return if this way has sidewalk - only meaningful for roads */ register_method(vm, &weg_t::hat_gehweg, "has_sidewalk"); /** * @return whether way is electrified by some way-object */ register_method(vm, &weg_t::is_electrified, "is_electrified"); /** * @return whether there is a road-sign associated to the way on the tile */ register_method(vm, &weg_t::has_sign, "has_sign"); /** * @return whether there is a signal associated to the way on the tile */ register_method(vm, &weg_t::has_signal, "has_signal"); /** * @return whether there is a way-object associated to the way on the tile */ register_method(vm, &weg_t::has_wayobj, "has_wayobj"); /** * @return whether there is a crossing associated to the way on the tile */ register_method(vm, &weg_t::is_crossing, "is_crossing"); /** * Return directions of this way. One-way signs are ignored here. * @returns direction * @typemask dir() */ register_function_fv(vm, &get_way_ribi, "get_dirs", 1, "x", freevariable(false) ); /** * Return directions of this way. Some signs restrict available directions. * @returns direction * @typemask dir() */ register_function_fv(vm, &get_way_ribi, "get_dirs_masked", 1, "x", freevariable(true) ); /** * @returns object descriptor. */ register_method(vm, &weg_t::get_desc, "get_desc"); /** * Returns maximal allowed speed on this way. * Takes limits from crossings, overhead-wires, bridges, etc, into account. * @returns max speed in kmh. */ register_method(vm, &weg_t::get_max_speed, "get_max_speed"); /** * Get monthly statistics of goods transported on this way. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_way_stat, "get_transported_goods", freevariable(WAY_STAT_GOODS), true); /** * Get monthly statistics of convoys that used this way. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_way_stat, "get_convoys_passed", freevariable(WAY_STAT_CONVOIS), true); end_class(vm); /** * Labels. */ begin_obj_class(vm, "label_x", "map_object_x"); /** * Creates a new marker. * @param pos position * @param pl owner * @param text text * @ingroup game_cmd */ STATIC register_method(vm, &create_marker, "create", false, true); /** * Set text of marker. * @param text text * @ingroup rename_func */ register_method(vm, &label_set_text, "set_text", true); /** * Get text of marker. * @see tile_x::get_text */ register_method(vm, &label_get_text, "get_text", true); end_class(vm); /** * Roadsigns and railway signals. */ begin_obj_class(vm, "sign_x", "map_object_x"); /** * @returns object descriptor. */ register_method(vm, &roadsign_t::get_desc, "get_desc"); /** * Test whether @p player 's vehicles can pass private-way sign. * Returns true if this is not a private-way sign. * @param player */ register_method(vm, &roadsign_can_pass, "can_pass", true); end_class(vm); /** * Powerlines. * (Including transformers. Can be differentiated by @ref obj_x::get_type. */ begin_obj_class(vm, "powerline_x", "map_object_x"); /** * Checkes whether powerline (or transformer) is connected to @p pl are connected. * @param pl other powerline/transformer */ register_method(vm, &leitung_is_connected, "is_connected", true); end_class(vm); /** * Transformers. * Sink and source can be differentiated by @ref obj_x::get_type. */ begin_obj_class(vm, "transformer_x", "powerline_x"); /** * Get factory connected to this transformer. */ register_method(vm, &transformer_get_factory, "get_factory", true); end_class(vm); /** * Fields */ begin_obj_class(vm, "field_x", "map_object_x"); /** * Fields can only be deleted if enough are present. * @see factory_x::get_field_count, factory_x::get_min_field_count * @return whether this one can be deleted */ register_method(vm, &field_is_deletable, "is_deletable", true); /** * @returns factory this field belongs to * @see factory_x::get_field_count, factory_x::get_min_field_count */ register_method(vm, &field_t::get_factory, "get_factory"); end_class(vm); /** * Way-objects: overhead-wires, fences, etc. Only one such object can exist on a tile. */ begin_obj_class(vm, "wayobj_x", "map_object_x"); /** * @returns object descriptor. */ register_method(vm, &wayobj_t::get_desc, "get_desc"); end_class(vm); /** * Bridges: bridge objects of bridge ramps and tiles */ begin_obj_class(vm, "bridge_x", "map_object_x"); /** * @returns object descriptor. */ register_method(vm, &bruecke_t::get_desc, "get_desc"); end_class(vm); /** * Tunnels */ begin_obj_class(vm, "tunnel_x", "map_object_x"); /** * @returns object descriptor. */ register_method(vm, &tunnel_t::get_desc, "get_desc"); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_obj_desc.cc000066400000000000000000000643321474050137200233640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_obj_desc.cc exports goods descriptors - *_desc_t. */ #include "api_obj_desc_base.h" #include "api_simple.h" #include "export_desc.h" #include "get_next.h" #include "../api_class.h" #include "../api_function.h" #include "../../descriptor/bridge_desc.h" #include "../../descriptor/building_desc.h" #include "../../descriptor/vehicle_desc.h" #include "../../descriptor/goods_desc.h" #include "../../descriptor/roadsign_desc.h" #include "../../descriptor/way_obj_desc.h" #include "../../descriptor/factory_desc.h" #include "../../builder/brueckenbauer.h" #include "../../builder/hausbauer.h" #include "../../builder/fabrikbauer.h" #include "../../builder/tunnelbauer.h" #include "../../builder/vehikelbauer.h" #include "../../builder/goods_manager.h" #include "../../builder/wegbauer.h" #include "../../obj/roadsign.h" #include "../../obj/wayobj.h" #include "../../simhalt.h" #include "../../simware.h" #include "../../world/simworld.h" #define begin_enum(name) #define end_enum() #define enum_slot create_slot using namespace script_api; SQInteger get_next_ware_desc(HSQUIRRELVM vm) { return generic_get_next(vm, goods_manager_t::get_count()); } SQInteger get_goods_desc_index(HSQUIRRELVM vm) { uint32 index = param::get(vm, -1); const char* name = "None"; // fall-back if (index < goods_manager_t::get_count()) { name = goods_manager_t::get_info(index)->get_name(); } return push_instance(vm, "good_desc_x", name); } bool are_equal(const obj_named_desc_t* a, const obj_named_desc_t* b) { return (a==b); } sint64 get_scaled_maintenance(const obj_desc_transport_related_t* desc) { return desc ? welt->scale_with_month_length(desc->get_maintenance()) : 0; } sint64 get_scaled_maintenance_vehicle(const vehicle_desc_t* desc) { return desc ? welt->scale_with_month_length(desc->vehicle_desc_t::get_maintenance()) : 0; } sint64 get_scaled_maintenance_building(const building_desc_t* desc) { return desc ? welt->scale_with_month_length(desc->get_maintenance(welt)) : 0; } bool building_enables(const building_desc_t* desc, uint8 which) { return desc ? desc->get_enabled() & which : 0; } SQInteger building_get_size(HSQUIRRELVM vm) { const building_desc_t* desc = param::get(vm, 1); uint8 rotation = param::get(vm, 2); if (desc) { koord size = desc->get_size(rotation); // no automatic coordinate transform please return push_instance(vm, "coord", size.x, size.y); } return -1; } mytime_t get_intro_retire(const obj_desc_timelined_t* desc, bool intro) { return (uint32)(desc ? ( intro ? desc->get_intro_year_month() : desc->get_retire_year_month() ) : 1); } bool is_obsolete_future(const obj_desc_timelined_t* desc, mytime_t time, uint8 what) { if (desc) { switch(what) { case 0: return desc->is_future(time.raw); case 1: return desc->is_retired(time.raw); case 2: return desc->is_available(time.raw); default: ; } } return false; } const vector_tpl& get_building_list(building_desc_t::btype type) { const vector_tpl* p = hausbauer_t::get_list(type); static const vector_tpl dummy; return p ? *p : dummy; } const vector_tpl& get_available_stations(building_desc_t::btype type, waytype_t wt, const goods_desc_t *freight) { static vector_tpl dummy; dummy.clear(); switch(type) { case building_desc_t::depot: case building_desc_t::generic_stop: case building_desc_t::generic_extension: case building_desc_t::dock: case building_desc_t::flat_dock: break; default: return dummy; } const vector_tpl* p = hausbauer_t::get_list(type); // translate freight to enables-flags uint8 enables = 0; if (freight && type != building_desc_t::depot) { switch(freight->get_catg_index()) { case goods_manager_t::INDEX_PAS: enables = haltestelle_t::PAX; break; case goods_manager_t::INDEX_MAIL: enables = haltestelle_t::POST; break; default: enables = haltestelle_t::WARE; } } // use wt_all (which is equal to invalid_wt, see api_const.cc) to get buildings for all waytypes bool accept_all_wt = wt == invalid_wt || wt == ignore_wt; uint16 time = welt->get_timeline_year_month(); for(building_desc_t const* const desc : *p) { if( desc->get_type()==type && (accept_all_wt || desc->get_extra()==(uint32)wt) && (enables==0 || (desc->get_enabled()&enables)!=0) && desc->get_builder() && desc->is_available(time)) { dummy.append(desc); } } return dummy; } sint64 building_get_cost(const building_desc_t* desc) { return desc->get_price(welt) * desc->get_x() * desc->get_y(); } bool building_is_terminus(const building_desc_t *desc) { return desc && desc->get_type() == building_desc_t::generic_stop && desc->get_all_layouts() == 4; } bool can_be_first(const vehicle_desc_t *desc) { return desc->can_follow(NULL); } bool can_be_last(const vehicle_desc_t *desc) { return desc->can_lead(NULL); } bool is_coupling_allowed(const vehicle_desc_t *desc1, const vehicle_desc_t *desc2) { return desc1 && desc2 && desc1->can_lead(desc2) && desc2->can_follow(desc1); } const vector_tpl& get_predecessors(const vehicle_desc_t *desc) { static vector_tpl dummy; dummy.clear(); for(int i=0; iget_leader_count(); i++) { if (desc->get_leader(i)) { dummy.append(desc->get_leader(i)); } } return dummy; } const vector_tpl& get_successors(const vehicle_desc_t *desc) { static vector_tpl dummy; dummy.clear(); for(int i=0; iget_trailer_count(); i++) { if (desc->get_trailer(i)) { dummy.append(desc->get_trailer(i)); } } return dummy; } const vector_tpl& get_available_vehicles(waytype_t wt) { static vector_tpl dummy; bool use_obsolete = welt->get_settings().get_allow_buying_obsolete_vehicles(); uint16 time = welt->get_timeline_year_month(); dummy.clear(); slist_tpl const& list = vehicle_builder_t::get_info(wt); for(vehicle_desc_t const* const i : list) { if (!i->is_retired(time) || use_obsolete) { if (!i->is_future(time)) { dummy.append(i); } } } return dummy; } uint32 get_power(const vehicle_desc_t *desc) { return desc->get_power() * desc->get_gear(); } bool vehicle_needs_electrification(const vehicle_desc_t *desc) { return desc->get_power() && (desc->get_engine_type()==vehicle_desc_t::electric); } // export of building_desc_t::btype only here namespace script_api { declare_enum_param(building_desc_t::btype, uint16, "building_desc_x::building_type"); }; bool is_traffic_light(const roadsign_desc_t *d) { return !d->is_signal_type() && d->is_traffic_light(); } sint64 tree_get_price() { return -welt->get_settings().cst_remove_tree; } const vector_tpl& get_available_wayobjs(waytype_t wt) { static vector_tpl dummy; uint16 time = welt->get_timeline_year_month(); dummy.clear(); for(auto i : wayobj_t::get_list()) { const way_obj_desc_t* desc = i.value; if (desc->get_waytype()==wt && desc->is_available(time) && desc->get_builder()) { dummy.append(desc); } } return dummy; } #ifdef DOXYGEN /** * Description of input/output slots */ struct factory_slot_information_x { // begin_class("factory_slot_information_x") good_desc_x good; ///< type of produced/consumed good integer capacity; ///< capacity to store the good integer factor; ///< production/consumption factor }; // end_class #endif SQInteger get_factory_outputs(HSQUIRRELVM vm) { const factory_desc_t *desc = param::get(vm, -1); sq_newarray(vm, 0); if (desc) { for(uint16 i=0; iget_product_count(); i++) { const factory_product_desc_t *fp = desc->get_product(i); sq_newtable(vm); create_slot(vm, "good", fp->get_output_type()); create_slot(vm, "capacity", fp->get_capacity()); create_slot(vm, "factor", fp->get_factor()); sq_arrayappend(vm, -2); } } return 1; } SQInteger get_factory_inputs(HSQUIRRELVM vm) { const factory_desc_t *desc = param::get(vm, -1); sq_newarray(vm, 0); if (desc) { for(uint16 i=0; iget_supplier_count(); i++) { const factory_supplier_desc_t *fp = desc->get_supplier(i); sq_newtable(vm); create_slot(vm, "good", fp->get_input_type()); create_slot(vm, "capacity", fp->get_capacity()); create_slot(vm, "factor", fp->get_consumption()); sq_arrayappend(vm, -2); } } return 1; } void export_goods_desc(HSQUIRRELVM vm) { /** * Base class of all object descriptors. */ create_class(vm, "obj_desc_x", "extend_get"); /** * @return raw (untranslated) name * @typemask string() */ register_method(vm, &obj_named_desc_t::get_name, "get_name"); /** * Checks if two object descriptor are equal. * @param other * @return true if this==other */ register_method(vm, &are_equal, "is_equal", true); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") end_class(vm); /** * Base class of object descriptors with intro / retire dates. */ create_class(vm, "obj_desc_time_x", "obj_desc_x"); /** * @return introduction date of this object */ register_method_fv(vm, &get_intro_retire, "get_intro_date", freevariable(true), true); /** * @return retirement date of this object */ register_method_fv(vm, &get_intro_retire, "get_retire_date", freevariable(false), true); /** * @param time to test (0 means no timeline game) * @return true if not available as intro date is in future */ register_method_fv(vm, &is_obsolete_future, "is_future", freevariable(0), true); /** * @param time to test (0 means no timeline game) * @return true if not available as retirement date already passed */ register_method_fv(vm, &is_obsolete_future, "is_retired", freevariable(1), true); /** * @param time to test (0 means no timeline game) * @return true if available: introduction and retirement date checked */ register_method_fv(vm, &is_obsolete_future, "is_available", freevariable(2), true); end_class(vm); /** * Base class of object descriptors for transport related stuff. */ create_class(vm, "obj_desc_transport_x", "obj_desc_time_x"); /** * @returns monthly maintenance cost [in 1/100 credits] of one object of this type. */ register_local_method(vm, &get_scaled_maintenance, "get_maintenance"); /** * @returns cost [in 1/100 credits] to buy or build one piece or tile of this thing. */ register_method(vm, &obj_desc_transport_related_t::get_price, "get_cost"); /** * @returns way type, can be @ref wt_invalid. */ register_method(vm, &obj_desc_transport_related_t::get_waytype, "get_waytype"); /** * @returns top speed: maximal possible or allowed speed, in km/h. */ register_method(vm, &obj_desc_transport_related_t::get_topspeed, "get_topspeed"); end_class(vm); /** * Vehicle descriptors */ begin_desc_class(vm, "vehicle_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * @returns true if this vehicle can lead a convoy */ register_method(vm, &can_be_first, "can_be_first", true); /** * @returns true if this vehicle can be the last of a convoy */ register_method(vm, &can_be_last, "can_be_last", true); /** * @returns list of possible successors, if list is empty then all are allowed (if @ref can_be_last returns true, or no successors are allowed if @ref can_be_last is false). */ register_method(vm, &get_successors, "get_successors", true); /** * @returns list of possible predecessors, if list is empty then all are allowed (if @ref can_be_first returns true, or no predecessors are allowed if @ref can_be_first is false). */ register_method(vm, &get_predecessors, "get_predecessors", true); /** * @returns a list of all available vehicles at the current in-game-time */ STATIC register_method(vm, &get_available_vehicles, "get_available_vehicles", false, true); /** * Power of the vehicle. This value can be used in convoy_x::calc_max_speed. * It returns (power of vehicle in kW) * (gear value) * 64, where power and gear are as shown in-game. * @returns the total power of the vehicle (takes power and gear from pak-files into account) */ register_method(vm, &get_power, "get_power", true); /** * @returns true if this vehicle needs electrification (and is powered) */ register_method(vm, &vehicle_needs_electrification, "needs_electrification", true); /** * @returns freight that can be transported (or null) */ register_method(vm, &vehicle_desc_t::get_freight_type, "get_freight"); /** * @returns capacity */ register_method(vm, &vehicle_desc_t::get_capacity, "get_capacity"); /** * @returns running cost in 1/100 credits per tile */ register_method(vm, &vehicle_desc_t::get_running_cost, "get_running_cost"); /** * @returns fixed cost in 1/100 credits per month */ register_method(vm, &get_scaled_maintenance_vehicle, "get_maintenance", true); /** * @returns weight of the empty vehicle */ register_method(vm, &vehicle_desc_t::get_weight, "get_weight"); // in kg /** * @returns lengths in @ref units::CARUNITS_PER_TILE */ register_method(vm, &vehicle_desc_t::get_length, "get_length"); // in CAR_UNITS_PER_TILE /** * Checks if the coupling of @p first and @p second is possible in this order. * @param first * @param second * @returns true if coupling is possible */ STATIC register_method(vm, is_coupling_allowed, "is_coupling_allowed", false, true); end_class(vm); /** * Object descriptors for trees. */ begin_desc_class(vm, "tree_desc_x", "obj_desc_x", (GETDESCFUNC)param::getfunc()); /** * Returns price to fell one tree. * @returns price (should be positive) */ STATIC register_method(vm, tree_get_price, "get_price", false, true); end_class(vm); /** * Object descriptors for buildings: houses, attractions, stations and extensions, depots, harbours. */ begin_desc_class(vm, "building_desc_x", "obj_desc_time_x", (GETDESCFUNC)param::getfunc()); /** * @returns whether building is an attraction */ register_method(vm, &building_desc_t::is_attraction, "is_attraction"); /** * @param rotation * @return size of building in the given @p rotation * @typemask coord(integer) */ register_function(vm, building_get_size, "get_size", 2, "x i"); /** * @return monthly maintenance cost */ register_method(vm, &get_scaled_maintenance_building, "get_maintenance", true); /** * Price to build this building, takes size, level, and type into account. * @return price [in 1/100 credits] to build this building */ register_method(vm, &building_get_cost, "get_cost", true); /** * @return capacity */ register_method(vm, &building_desc_t::get_capacity, "get_capacity"); /** * @return whether station building can be built underground */ register_method(vm, &building_desc_t::can_be_built_underground, "can_be_built_underground"); /** * @return whether station building can be built above ground */ register_method(vm, &building_desc_t::can_be_built_aboveground, "can_be_built_aboveground"); /** * @return whether this station building can handle passengers */ register_method_fv(vm, &building_enables, "enables_pax", freevariable(1), true); /** * @return whether this station building can handle mail */ register_method_fv(vm, &building_enables, "enables_mail", freevariable(2), true); /** * @return whether this station building can handle freight */ register_method_fv(vm, &building_enables, "enables_freight", freevariable(4), true); /// building types begin_enum("building_type") /// tourist attraction to be built in cities enum_slot(vm, "attraction_city", (uint8)building_desc_t::attraction_city, true); /// tourist attraction to be built outside cities enum_slot(vm, "attraction_land", (uint8)building_desc_t::attraction_land, true); /// monument, built only once per map enum_slot(vm, "monument", (uint8)building_desc_t::monument, true); /// factory enum_slot(vm, "factory", (uint8)building_desc_t::factory, true); /// townhall enum_slot(vm, "townhall", (uint8)building_desc_t::townhall, true); /// company headquarters enum_slot(vm, "headquarter", (uint8)building_desc_t::headquarters, true); /// harbour enum_slot(vm, "harbour", (uint8)building_desc_t::dock, true); /// harbour without a slope (buildable on flat ground beaches) enum_slot(vm, "flat_harbour", (uint8)building_desc_t::flat_dock, true); /// depot enum_slot(vm, "depot", (uint8)building_desc_t::depot, true); /// station enum_slot(vm, "station", (uint8)building_desc_t::generic_stop, true); /// station extension enum_slot(vm, "station_extension", (uint8)building_desc_t::generic_extension, true); /// city building: residential enum_slot(vm, "city_res", (uint8)building_desc_t::city_res, true); /// city building: commercial enum_slot(vm, "city_com", (uint8)building_desc_t::city_com, true); /// city building: industrial enum_slot(vm, "city_ind", (uint8)building_desc_t::city_ind, true); end_enum(); /** * @returns building type */ register_method(vm, &building_desc_t::get_type, "get_type"); /** * @returns way type, can be @ref wt_invalid. */ register_method(vm, &building_desc_t::get_finance_waytype, "get_waytype"); /** * @returns headquarter level (or -1 if building is not headquarter) */ register_method(vm, &building_desc_t::get_headquarters_level, "get_headquarter_level"); /** * Returns an array with all buildings of the given type. * @warning If @p type is one of building_desc_x::harbour, building_desc_x::depot, building_desc_x::station, building_desc_x::station_extension then always the same list is generated. * You have to filter out e.g. station buildings yourself. */ STATIC register_method(vm, &get_building_list, "get_building_list", false, true); /** * Returns an array of available station/extension/depot buildings. * Entries are of type @ref building_desc_x. * @param type building type from @ref building_desc_x::building_type * @param wt waytype (can be wt_all to ignore waytype of desc) * @param freight station should accept this freight (if equal to {}, i.e., empty table, then return all buildings) * @returns the list */ STATIC register_method(vm, &get_available_stations, "get_available_stations", false, true); /** * @returns true if this is a station building that can be used as terminus */ register_method(vm, &building_is_terminus, "is_terminus", true); end_class(vm); /** * Object descriptors for factories. */ begin_desc_class(vm, "factory_desc_x", "obj_desc_x", (GETDESCFUNC)param::getfunc()); /** * @returns name */ register_method(vm, &factory_desc_t::get_name, "get_name"); /** * Descriptor of associated building. */ register_method(vm, &factory_desc_t::get_building, "get_building_desc"); /** * @returns true if this factory produces electricity */ register_method(vm, &factory_desc_t::is_electricity_producer, "is_electricity_producer"); /** * Initial production of a factory is get_productivity_base() + rand( get_productivity_range() ). * @returns base production */ register_method(vm, &factory_desc_t::get_productivity, "get_productivity_base"); /** * @returns base production variable range */ register_method(vm, &factory_desc_t::get_range, "get_productivity_range"); /** * Returns array with information about input goods * @typemask array () */ register_function(vm, get_factory_inputs, "get_inputs", 1, "t|x|y"); /** * Returns array with information about input goods * @typemask array () */ register_function(vm, get_factory_outputs, "get_outputs", 1, "t|x|y"); /** * Returns table with all factory types. * The factory names are used as table keys. */ register_method(vm, &factory_builder_t::get_factory_table, "get_list", 1); end_class(vm); /** * Object descriptors for ways. */ begin_desc_class(vm, "way_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * @returns true if this way can be build on the steeper (double) slopes. */ register_method(vm, &way_desc_t::has_double_slopes, "has_double_slopes"); /** * @returns system type of the way, see @ref way_system_types. */ register_method(vm, &way_desc_t::get_styp, "get_system_type"); /** * Generates a list of all ways available for building. * @param wt waytype * @param st system type of way * @returns the list */ STATIC register_method(vm, way_builder_t::get_way_list, "get_available_ways", false, true); end_class(vm); /** * Object descriptors for tunnels. */ begin_desc_class(vm, "tunnel_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * Returns a list with available tunnel types. */ STATIC register_method(vm, tunnel_builder_t::get_available_tunnels, "get_available_tunnels", false, true); end_class(vm); /** * Object descriptors for bridges. */ begin_desc_class(vm, "bridge_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * @return true if this bridge can raise two level from flat terrain */ register_method(vm, &bridge_desc_t::has_double_ramp, "has_double_ramp"); /** * @return true if this bridge can start or end on a double slope */ register_method(vm, &bridge_desc_t::has_double_start, "has_double_start"); /** * @return maximal bridge length in tiles */ register_method(vm, &bridge_desc_t::get_max_length, "get_max_length"); /** * @return maximal bridge height */ register_method(vm, &bridge_desc_t::get_max_height, "get_max_height"); /** * Returns a bridge with the given name */ STATIC register_method(vm, bridge_builder_t::get_desc, "get_desc", false, true); /** * Returns a list with available bridge types. */ STATIC register_method(vm, bridge_builder_t::get_available_bridges, "get_available_bridges", false, true); end_class(vm); /** * Implements iterator to iterate through the list of all good types. * * Usage: * @code * local list = good_desc_list_x() * foreach(good_desc in list) { * ... // good_desc is an instance of the good_desc_x class * } * @endcode */ create_class(vm, "good_desc_list_x", 0); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, get_next_ware_desc, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops. Do not call them directly. */ register_function(vm, get_goods_desc_index, "_get", 2, "xi"); end_class(vm); /** * Descriptor of goods and freight types. */ begin_desc_class(vm, "good_desc_x", "obj_desc_x", (GETDESCFUNC)param::getfunc()); // dummy entry to create documentation of constructor /** * Constructor. * @param name raw name of the freight type. * @typemask (string) */ // register_function( .., "constructor", .. ) create_slot(vm, "passenger", goods_manager_t::passengers, true); create_slot(vm, "mail", goods_manager_t::mail, true); #ifdef DOXYGEN static good_desc_x passenger; ///< descriptor for passenger static good_desc_x mail; ///< descriptor for mail #endif /** * @return freight category. 0=Passengers, 1=Mail, 2=None, >=3 anything else */ register_method(vm, &goods_desc_t::get_catg_index, "get_catg_index"); /** * Checks if this good can be interchanged with the other, in terms of * transportability. */ register_method(vm, &goods_desc_t::is_interchangeable, "is_interchangeable"); /** * @returns weight of one unit of this freight */ register_method(vm, &goods_desc_t::get_weight_per_unit, "get_weight_per_unit"); // in kg /** * @returns metric unit name */ register_method(vm, &goods_desc_t::get_mass, "get_metric"); /** * Calculates transport revenue per tile and freight unit. * Takes speedbonus into account. * Value contains an additional factor of 3000. Don't ask. * Divide by 3000 *after* calculating revenue for a loaded convoy. * @param wt waytype of vehicle * @param speedkmh actual achieved speed in km/h * @returns revenue */ register_method(vm, &ware_t::calc_revenue, "calc_revenue", true); end_class(vm); /** * Descriptor of roadsigns and signals. */ begin_desc_class(vm, "sign_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * @returns true if sign is one-way sign */ register_method(vm, &roadsign_desc_t::is_single_way, "is_one_way"); /** * @returns true if sign is private-way sign */ register_method(vm, &roadsign_desc_t::is_private_way, "is_private_way"); /** * @returns true if sign is traffic light */ register_method(vm, &is_traffic_light, "is_traffic_light", true); /** * @returns true if sign is choose sign */ register_method(vm, &roadsign_desc_t::is_choose_sign, "is_choose_sign"); /** * @returns true if sign is signal */ register_method(vm, &roadsign_desc_t::is_simple_signal, "is_signal"); /** * @returns true if sign is pre signal (distant signal) */ register_method(vm, &roadsign_desc_t::is_pre_signal, "is_pre_signal"); /** * @returns true if sign is priority signal */ register_method(vm, &roadsign_desc_t::is_priority_signal, "is_priority_signal"); /** * @returns true if sign is long-block signal */ register_method(vm, &roadsign_desc_t::is_longblock_signal, "is_longblock_signal"); /** * @returns true if sign is end-of-choose sign */ register_method(vm, &roadsign_desc_t::is_end_choose_signal, "is_end_choose_signal"); /** * Returns a list with available sign types. * @param wt waytype */ STATIC register_method(vm, roadsign_t::get_available_signs, "get_available_signs", false, true); end_class(vm); /** * Descriptor of way-objects. */ begin_desc_class(vm, "wayobj_desc_x", "obj_desc_transport_x", (GETDESCFUNC)param::getfunc()); /** * @returns true for over-head lines. */ register_method(vm, &way_obj_desc_t::is_overhead_line, "is_overhead_line"); /** * Returns a list with available wayobj-types. * @param wt waytype */ STATIC register_method(vm, get_available_wayobjs, "get_available_wayobjs", false, true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_obj_desc_base.cc000066400000000000000000000050321474050137200243460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api_obj_desc_base.h" #include "../../builder/brueckenbauer.h" #include "../../builder/fabrikbauer.h" #include "../../builder/hausbauer.h" #include "../../builder/tunnelbauer.h" #include "../../builder/vehikelbauer.h" #include "../../builder/goods_manager.h" #include "../../builder/wegbauer.h" #include "../../descriptor/bridge_desc.h" #include "../../descriptor/tunnel_desc.h" #include "../../descriptor/vehicle_desc.h" #include "../../descriptor/goods_desc.h" #include "../../descriptor/way_desc.h" #include "../../descriptor/way_obj_desc.h" #include "../../obj/baum.h" #include "../../obj/roadsign.h" #include "../../obj/wayobj.h" #include "../../../squirrel/sq_extensions.h" using namespace script_api; static const way_desc_t *my_get_desc(const char *name) { return way_builder_t::get_desc(name); } implement_desc_param(tree_desc_t, "tree_desc_x", &tree_builder_t::find_tree); implement_desc_param(building_desc_t, "building_desc_x", &hausbauer_t::get_desc); implement_desc_param(goods_desc_t, "good_desc_x", (const goods_desc_t* (*)(const char*))(&goods_manager_t::get_info) ); implement_desc_param(way_desc_t, "way_desc_x", &my_get_desc); implement_desc_param(vehicle_desc_t, "vehicle_desc_x", &vehicle_builder_t::get_info); implement_desc_param(tunnel_desc_t, "tunnel_desc_x", &tunnel_builder_t::get_desc); implement_desc_param(bridge_desc_t, "bridge_desc_x", &bridge_builder_t::get_desc); implement_desc_param(roadsign_desc_t, "sign_desc_x", &roadsign_t::find_desc); implement_desc_param(way_obj_desc_t, "wayobj_desc_x", &wayobj_t::find_desc); implement_desc_param(factory_desc_t, "factory_desc_x", &factory_builder_t::get_desc); /** * Macro to get the implementation of get method based on unique tag. */ #define implement_class_with_tag(class) \ /* tag: points to itself */ \ static void *class ## _tag = &class ## _tag; \ \ const class* param::get(HSQUIRRELVM vm, SQInteger index) \ { \ return (const class*)get_instanceup(vm, index, tag(), squirrel_type()); \ } \ \ void* param::tag() \ { \ return class ## _tag; \ } // use the macro to obtain the interface of some abstract classes implement_class_with_tag(obj_named_desc_t); implement_class_with_tag(obj_desc_timelined_t); implement_class_with_tag(obj_desc_transport_related_t); SQInteger param::push(HSQUIRRELVM vm, const building_tile_desc_t* b) { return param::push(vm, b ? b->get_desc() : NULL); } simutrans-124.3/src/simutrans/script/api/api_obj_desc_base.h000066400000000000000000000053541474050137200242170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_API_OBJ_DESC_BASE_H #define SCRIPT_API_API_OBJ_DESC_BASE_H /** @file api_obj_desc_base.h templates for transfer of desc-pointers */ #include "../api_param.h" #include "../api_class.h" class obj_named_desc_t; class obj_desc_timelined_t; class obj_desc_transport_related_t; class tree_desc_t; class bridge_desc_t; class building_desc_t; class building_tile_desc_t; class factory_desc_t; class goods_desc_t; class roadsign_desc_t; class tunnel_desc_t; class vehicle_desc_t; class way_desc_t; class way_obj_desc_t; namespace script_api { #define declare_desc_param(T, sqtype) \ template<> \ struct param { \ \ typedef const T* (*GETFUNC)(const char*);\ \ static GETFUNC getfunc(); \ \ declare_types("t|x|y", sqtype); \ \ static void* tag() \ { \ return (void*)(getfunc()); \ } \ static const T* get(HSQUIRRELVM vm, SQInteger index); \ \ static SQInteger push(HSQUIRRELVM vm, const T* b); \ }; \ template<> \ struct param { \ \ declare_types("t|x|y", sqtype); \ }; #define implement_desc_param(T, sqtype, func) \ param::GETFUNC param::getfunc() \ { \ return func; \ } \ const T* param::get(HSQUIRRELVM vm, SQInteger index) \ { \ return (const T*)get_instanceup(vm, index, tag(), sqtype); \ } \ SQInteger param::push(HSQUIRRELVM vm, const T* b) \ { \ if (b) { \ return push_instance_up(vm, b); \ } \ else { \ sq_pushnull(vm); return 1; \ } \ } declare_specialized_param(const obj_named_desc_t*, "t|x|y", "obj_desc_x"); declare_param_mask(obj_named_desc_t*, "t|x|y", "obj_desc_x"); declare_specialized_param(const obj_desc_timelined_t*, "t|x|y", "obj_desc_time_x"); declare_param_mask(obj_desc_timelined_t*, "t|x|y", "obj_desc_time_x"); declare_specialized_param(const obj_desc_transport_related_t*, "t|x|y", "obj_desc_transport_x"); declare_param_mask(obj_desc_transport_related_t*, "t|x|y", "obj_desc_transport_x"); declare_desc_param(tree_desc_t, "tree_desc_x"); declare_desc_param(goods_desc_t, "good_desc_x"); declare_desc_param(building_desc_t, "building_desc_x"); declare_desc_param(way_desc_t, "way_desc_x"); declare_desc_param(vehicle_desc_t, "vehicle_desc_x"); declare_desc_param(tunnel_desc_t, "tunnel_desc_x"); declare_desc_param(bridge_desc_t, "bridge_desc_x"); declare_desc_param(roadsign_desc_t, "sign_desc_x"); declare_desc_param(way_obj_desc_t, "wayobj_desc_x"); declare_desc_param(factory_desc_t, "factory_desc_x"); // only push the building_desc_t-pointer declare_desc_param(building_tile_desc_t, "building_desc_x"); }; #endif simutrans-124.3/src/simutrans/script/api/api_pathfinding.cc000066400000000000000000000143041474050137200241010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_pathfinding.cc exports heap structure and construction helpers. */ #include "api_obj_desc_base.h" #include "api_simple.h" #include "../api_class.h" #include "../api_function.h" #include "../../builder/brueckenbauer.h" #include "../../builder/wegbauer.h" #include "../../descriptor/bridge_desc.h" #include "../../descriptor/way_desc.h" #include "../../tpl/binary_heap_tpl.h" #include "../../world/simworld.h" using namespace script_api; struct heap_node_t { sint32 weight; sint32 value; heap_node_t(sint32 w, sint32 v) : weight(w), value(v) {} // dereferencing to be used in binary_heap_tpl inline sint32 operator * () const { return weight; } }; typedef binary_heap_tpl simple_heap_t; namespace script_api{ declare_specialized_param(heap_node_t, "t|x|y", "simple_heap_x::node_x"); declare_specialized_param(simple_heap_t*, "t|x|y", "simple_heap_x"); }; SQInteger heap_constructor(HSQUIRRELVM vm) { simple_heap_t* heap = new simple_heap_t(); attach_instance(vm, 1, heap); return SQ_OK; } void* script_api::param::tag() { return (void*)&heap_constructor; } simple_heap_t* script_api::param::get(HSQUIRRELVM vm, SQInteger index) { simple_heap_t *heap = get_attached_instance(vm, index, param::tag()); return heap; } SQInteger param::push(HSQUIRRELVM vm, heap_node_t const& v) { sq_newtable(vm); create_slot(vm, "weight", v.weight); create_slot(vm, "value", v.value); return 1; } void simple_heap_insert(simple_heap_t *heap, sint32 weight, sint32 value) { heap->insert( heap_node_t(weight, value) ); } SQInteger simple_heap_pop(HSQUIRRELVM vm) // instance { simple_heap_t *heap = param::get(vm, 1); if (heap) { if (!heap->empty()) { return param::push(vm, heap->pop()); } else { return sq_raise_error(vm, "Called pop() on empty heap"); } } else { return sq_raise_error(vm, "Not a heap instance"); // should not happen } } SQInteger way_builder_constructor(HSQUIRRELVM vm) // instance, player { // get player parameter player_t *player = get_my_player(vm); if (player == NULL) { player = param::get(vm, 2); } if (player == NULL) { return SQ_ERROR; } way_builder_t* bob = new way_builder_t(player); bob->set_keep_existing_faster_ways(true); bob->set_keep_city_roads(true); attach_instance(vm, 1, bob); return SQ_OK; } void way_builder_set_build_types(way_builder_t *bob, const way_desc_t *way) { if (way) { bob->init_builder( (way_builder_t::bautyp_t)way->get_waytype(), way, NULL /*tunnel*/, NULL /*bridge*/); } } bool way_builder_is_allowed_step(way_builder_t *bob, grund_t *from, grund_t *to) { if (from == NULL || to == NULL) { return false; } sint32 costs = 0; return bob->is_allowed_step(from, to, &costs); } koord3d bridge_builder_find_end_pos(player_t *player, koord3d pos, my_ribi_t mribi, const bridge_desc_t *bridge, uint32 min_length) { const char* err; sint8 height; ribi_t::ribi ribi(mribi); if (player == NULL || bridge == NULL) { return koord3d::invalid; } grund_t *from = welt->lookup(pos); if (from == NULL || !bridge_builder_t::can_place_ramp(player, from, bridge->get_wtyp(), ribi_t::backward(ribi))) { return koord3d::invalid; } return bridge_builder_t::find_end_pos(player, pos, ribi, bridge, err, height, false, min_length, false); } void export_pathfinding(HSQUIRRELVM vm) { /** * Exports a binary heap structure with * with simple nodes. */ create_class(vm, "simple_heap_x", 0); /** * Constructor */ register_function(vm, heap_constructor, "constructor", 1, "x"); sq_settypetag(vm, -1, param::tag()); /// Clears the heap. register_method(vm, &simple_heap_t::clear, "clear"); /// @returns number of nodes in heap register_method(vm, &simple_heap_t::get_count, "len"); /// @returns true when heap is empty register_method(vm, &simple_heap_t::empty, "is_empty"); /** * Inserts a node into the heap. * @param weight heap is sorted with respect to weight * @param value the data to be stored */ register_method(vm, simple_heap_insert, "insert", true); /** * Pops the top node of the heap. * Raises error if heap is empty. * @returns top node */ register_function(vm, simple_heap_pop, "pop", 1, "x"); #ifdef SQAPI_DOC /** * Helper node class. */ class node_x { int weight; ///< heap is sorted with respect to weight int value; ///< the data to be stored } #endif end_class(vm); /** * Class with helper methods for way planning. */ create_class(vm, "way_planner_x", 0); /** * Constructor * @param pl player that wants to plan, for ai scripts is set to ai player_x::self * @typemask way_planner_x(player_x) */ register_function(vm, way_builder_constructor, "constructor", 2, "xx"); sq_settypetag(vm, -1, param::tag()); /** * Sets way descriptor, which is needed for @ref is_allowed_step. * @param way descriptor of way to be planned. */ register_method(vm, way_builder_set_build_types, "set_build_types", true); /** * Checks if player can build way from @p from to @p to. * @param from from here * @param to to here, @p from and @p to must be adjacent. */ register_method(vm, way_builder_is_allowed_step, "is_allowed_step", true); end_class(vm); /** * Class with helper methods for bridge planning. */ create_class(vm, "bridge_planner_x", 0); /** * Find suitable end tile for bridge starting at @p pos going into direction @p dir. * @param pl who wants to build a bridge * @param pos start tile for bridge * @param dir direction * @param bridge bridge descriptor * @param min_length bridge should have this minimal length * @returns coordinate of end tile or an invalid coordinate */ STATIC register_method(vm, bridge_builder_find_end_pos, "find_end", false, true); end_class(vm); } void* script_api::param::tag() { return (void*)&way_builder_constructor; } way_builder_t* script_api::param::get(HSQUIRRELVM vm, SQInteger index) { way_builder_t *bob = get_attached_instance(vm, index, param::tag()); return bob; } simutrans-124.3/src/simutrans/script/api/api_player.cc000066400000000000000000000254251474050137200231100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_player.cc exports player/company related functions. */ #include "../api_class.h" #include "../api_function.h" #include "../../player/simplay.h" #include "../../player/finance.h" // for creation of lines #include "../../simline.h" #include "../../tool/simmenu.h" #include "../../world/simworld.h" using namespace script_api; vector_tpl const& get_player_stat(player_t *player, sint32 INDEX, sint32 TTYPE, bool monthly) { static vector_tpl v; v.clear(); bool atv = false; if (TTYPE<0 || TTYPE>=TT_MAX) { if (INDEX<0 || INDEX>ATC_MAX) { return v; } } else { if (INDEX<0 || INDEX>ATV_MAX) { return v; } atv = true; } if (player) { finance_t *finance = player->get_finance(); // calculate current month finance->calc_finance_history(); uint16 maxi = monthly ? MAX_PLAYER_HISTORY_MONTHS : MAX_PLAYER_HISTORY_YEARS; for(uint16 i = 0; i < maxi; i++) { sint64 m = atv ? ( monthly ? finance->get_history_veh_month((transport_type)TTYPE, i, INDEX) : finance->get_history_veh_year((transport_type)TTYPE, i, INDEX) ) : ( monthly ? finance->get_history_com_month(i, INDEX) : finance->get_history_com_year(i, INDEX) ); if (atv) { if (INDEX != ATV_TRANSPORTED_PASSENGER && INDEX != ATV_TRANSPORTED_MAIL && INDEX != ATV_TRANSPORTED_GOOD && INDEX !=ATV_TRANSPORTED) { m = convert_money(m); } } else { if (INDEX != ATC_ALL_CONVOIS) { m = convert_money(m); } } v.append(m); } } return v; } // export of finance_t only here namespace script_api { declare_specialized_param(finance_t*, param::typemask(), param::squirrel_type()); finance_t* param::get(HSQUIRRELVM vm, SQInteger index) { player_t *player = param::get(vm, index); return player ? player->get_finance() : NULL; } }; // also export transport_type - to get correct parameters namespace script_api { declare_specialized_param(transport_type, "i", "integer"); transport_type param::get(HSQUIRRELVM vm, SQInteger index) { return (transport_type) min(param::get(vm, index), TT_MAX-1); } }; SQInteger player_export_line_list(HSQUIRRELVM vm) { if (player_t* player = param::get(vm, 1)) { push_instance(vm, "line_list_x"); set_slot(vm, "player_id", player->get_player_nr()); return 1; } return SQ_ERROR; } call_tool_init player_create_line(player_t *player, waytype_t wt) { simline_t::linetype lt = simline_t::waytype_to_linetype(wt); if (lt == simline_t::MAX_LINE_TYPE) { return "Invalid waytype provided"; } // build param string (see schedule_list_gui_t::action_triggered) cbuffer_t buf; buf.printf( "c,0,%i,0,0|%i|", lt, lt); return call_tool_init(TOOL_CHANGE_LINE | SIMPLE_TOOL, buf, 0, player); } call_tool_init player_book_account(player_t *player, sint32 delta) { // build param string (see tool_change_player_t) cbuffer_t buf; buf.printf( "$,%i,%i", player->get_player_nr(), delta); return call_tool_init(TOOL_CHANGE_PLAYER | SIMPLE_TOOL, buf, 0, welt->get_public_player()); } SQInteger player_get_my_player(HSQUIRRELVM vm) { return script_api::param::push(vm, get_my_player(vm) ); } call_tool_init player_set_name(player_t *player, const char* name) { return script_api::command_rename(player, 'p', player->get_player_nr(), name); } void export_player(HSQUIRRELVM vm, bool scenario) { /** * Class to access player statistics. * Here, a player refers to one transport company, not to an individual playing simutrans. */ begin_class(vm, "player_x", "extend_get,ingame_object"); /** * Constructor. * @param nr player number, 0 = standard player, 1 = public player * @typemask (integer) */ // actually defined in simutrans/script/script_base.nut // register_function(..., "constructor", ...); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") if (!scenario) { /** * @returns player associated with the AI. * @ingroup ai_only * @typemask player_x() * @note Only available in AI mode. */ STATIC register_function(vm, &player_get_my_player, "self", 0, "", true); } /** * Return headquarters level. * @returns level, level is zero if no headquarters was built */ register_method(vm, &player_t::get_headquarter_level, "get_headquarter_level"); /** * Return headquarters position. * @returns coordinate, (-1,-1) if no headquarters was built */ register_method(vm, &player_t::get_headquarter_pos, "get_headquarter_pos"); /** * Return name of company. * @returns name */ register_method(vm, &player_t::get_name, "get_name"); /** * Sets name of company. * @param name the new name * @ingroup rename_func */ register_method(vm, &player_set_name, "set_name", true); /** * Get monthly statistics of construction costs. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_construction", freevariable(ATV_CONSTRUCTION_COST, TT_ALL, true), true); /** * Get monthly statistics of vehicle running costs. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_vehicle_maint", freevariable(ATV_RUNNING_COST, TT_ALL, true), true); /** * Get monthly statistics of costs for vehicle purchase. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_new_vehicles", freevariable(ATV_NEW_VEHICLE, TT_ALL, true), true); /** * Get monthly statistics of income. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_income", freevariable(ATV_REVENUE_TRANSPORT, TT_ALL, true), true); /** * Get monthly statistics of infrastructure maintenance. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_maintenance", freevariable(ATV_INFRASTRUCTURE_MAINTENANCE, TT_ALL, true), true); /** * Get monthly statistics of assets. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_assets", freevariable(ATV_NON_FINANCIAL_ASSETS, TT_ALL, true), true); /** * Get monthly statistics of cash. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_cash", freevariable(ATC_CASH, -1, true), true); /** * Get monthly statistics of net wealth. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_net_wealth", freevariable(ATC_NETWEALTH, -1, true), true); /** * Get monthly statistics of profit. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_profit", freevariable(ATV_PROFIT, TT_ALL, true), true); /** * Get monthly statistics of operating profit. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_operating_profit", freevariable(ATV_OPERATING_PROFIT, TT_ALL, true), true); /** * Get monthly statistics of margin. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_margin", freevariable(ATV_PROFIT_MARGIN, -1, true), true); /** * Get monthly statistics of all transported goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_transported", freevariable(ATV_TRANSPORTED, TT_ALL, true), true); /** * Get monthly statistics of income from powerlines. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_powerline", freevariable(ATV_REVENUE, TT_POWERLINE, true), true); /** * Get monthly statistics of transported passengers. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_transported_pax", freevariable(ATV_TRANSPORTED_PASSENGER, TT_ALL, true), true); /** * Get monthly statistics of transported mail. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_transported_mail", freevariable(ATV_TRANSPORTED_MAIL, TT_ALL, true), true); /** * Get monthly statistics of transported goods. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_transported_goods", freevariable(ATV_TRANSPORTED_GOOD, TT_ALL, true), true); /** * Get monthly statistics of number of convoys. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_convoys", freevariable(ATC_ALL_CONVOIS, -1, true), true); /** * Get monthly statistics of income/loss due to way tolls. * @returns array, index [0] corresponds to current month */ register_method_fv(vm, &get_player_stat, "get_way_tolls", freevariable(ATV_WAY_TOLL, TT_ALL, true), true); if (scenario) { /** * Change bank account of player by given amount @p delta. * @param delta * @ingroup scen_only */ register_method(vm, player_book_account, "book_cash", true); } /** * Returns the current account balance. */ register_method(vm, &player_t::get_account_balance_as_double, "get_current_cash"); /** * Returns the current net worth [in 1/100 cr]. */ register_method(vm, &finance_t::get_netwealth, "get_current_net_wealth"); /** * Returns the current maintenance [in 1/100 cr]. */ register_method_fv(vm, &finance_t::get_maintenance_with_bits, "get_current_maintenance", freevariable(TT_ALL)); /** * Returns whether the player (still) exists in the game. * * @deprecated Only available for api versions less than 120.1, see @ref get_api_version. * @typemask bool() */ // register_method(vm,, "is_active", true); implemented in scenario_compat.nut /** * Exports list of lines of this player. * @typemask line_list_x() */ register_function(vm, &player_export_line_list, "get_line_list", 1, param::typemask()); /** * Creates a new line for the player of the given way type. * @param wt way type * @ingroup game_cmd */ register_method(vm, &player_create_line, "create_line", true); /** * Returns player type: 1 = human, 2,3 = old c++ AI, 4 = scripted AI */ register_method(vm, &player_t::get_ai_id, "get_type"); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_scenario.cc000066400000000000000000000273001474050137200234110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_scenario.cc exports scenario related functions. */ #include "../api_class.h" #include "../api_function.h" #include "../../dataobj/koord.h" #include "../../dataobj/koord3d.h" #include "../../dataobj/scenario.h" #include "../../dataobj/translator.h" #include "../../utils/simstring.h" #include "../../simintr.h" using namespace script_api; static char buf[40]; static plainstring double_to_string(double f, sint32 decimals) { number_to_string(buf, f, decimals); return buf; } static plainstring integer_to_string(sint64 f) { number_to_string(buf, f, 0); return buf; } static plainstring money_to_string_intern(sint64 m) { money_to_string(buf, m, false); return buf; } static plainstring difftick_to_string_intern(sint32 f ) { return difftick_to_string( f, false ); } static plainstring koord_to_string_intern(koord k) { return k.get_str(); } static plainstring koord3d_to_string_intern(koord3d k) { return k.get_str(); } void export_string_methods(HSQUIRRELVM vm) { /** * Helper method to translate strings, needed to identify the correct overloaded function * @param text string to translate * @returns translation of given string */ register_method(vm, &translator::translate, "translate"); /** * Pretty-print floating point numbers, use language specific separator for powers of thousands. * @param value number to print * @param decimals how many decimals should be printed * @returns a nice string */ register_method(vm, &double_to_string, "double_to_string"); /** * Pretty-print integers, use language specific separator for powers of thousands. * @param value number to print * @returns a nice string */ register_method(vm, &integer_to_string, "integer_to_string"); /** * Pretty-print money values, use language specific separator for powers of thousands. * @param value number to print * @returns a nice string with trailing dollar-sign */ register_method(vm, &money_to_string_intern, "money_to_string"); /** * Print coordinates, does automatic rotation. * @param c coordinate * @returns a nice string */ register_method(vm, &koord_to_string_intern, "coord_to_string"); /** * Print coordinates, does automatic rotation. * @param c coordinate * @returns a nice string */ register_method(vm, &koord3d_to_string_intern, "coord3d_to_string"); /** * Get name of given month. * @param month number between 0 (january) and 11 (december) * @returns month name in language of server */ register_method(vm, &translator::get_month_name, "get_month_name"); /** * Translates difference of ticks to string which could even have months in it. * @param difftick_to_string_intern ticks in simutrans units * @returns time difference using the current local setting */ register_method(vm, &difftick_to_string_intern, "difftick_to_string"); } void export_scenario(HSQUIRRELVM vm) { /** * Helper method to load scenario-related translation files. * Tries to load files in the following order relative to pakxx/scenario: * -# scenario-name/iso/filename * -# scenario-name/en/filename * -# scenario-name/filename * * Here, iso refers to iso-abbreviation of currently active language. * * The content of the files is cached. The cache is cleared upon reloading of savegame. * @param file name of txt-file * @return content of loaded file * @note Only available in scenario mode. * @ingroup scen_only */ register_method(vm, &scenario_t::load_language_file, "load_language_file"); /** * Table with methods to forbid and allow tools. * * Tools that are set to forbidden using the forbid_* methods can be allowed * again by calls to the respective allow_* method with exact the same parameters. * * @note Only available in scenario mode. * @ingroup scen_only */ begin_class(vm, "rules", 0); /** * Forbid an internal tool. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::forbid_tool, "forbid_tool"); /** * Forbid an internal tool with certain waytype. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or null (to catch all) * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::forbid_way_tool, "forbid_way_tool"); /** * Forbid an internal tool with certain waytype within rectangular region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or null (to catch all) * @param pos_nw coordinate of north-western corner of rectangle * @param pos_se coordinate of south-eastern corner of rectangle * @param err error message presented to user when trying to apply this tool, see also @ref is_work_allowed_here * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::forbid_way_tool_rect, "forbid_way_tool_rect"); /** * Forbid an internal tool with certain waytype within cubic region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or null (to catch all) * @param pos_nw 3d-coordinate of north-western corner of cube * @param pos_se 3d-coordinate of south-eastern corner of cube * @param err error message presented to user when trying to apply this tool, see also @ref is_work_allowed_here * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::forbid_way_tool_cube, "forbid_way_tool_cube"); /** * Allow again an internal tool. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_forbid_tool, "clear_forbid_tool"); /** * clear fule with certain waytype. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or 0 (to catch all) * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_forbid_way_tool, "clear_forbid_way_tool"); /** * clear rule with certain waytype within rectangular region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or 0 (to catch all) * @param pos_nw coordinate of north-western corner of rectangle * @param pos_se coordinate of south-eastern corner of rectangle * @param allow clear either allo (true) or forbid (false) rule * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_way_tool_rect, "clear_way_tool_rect"); /** * clear rule with certain waytype within cubic region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or 0 (to catch all) * @param pos_nw 3d-coordinate of north-western corner of cube * @param pos_se 3d-coordinate of south-eastern corner of cube * @param allow clear either allo (true) or forbid (false) rule * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_way_tool_cube, "clear_way_tool_cube"); /** * Clear all forbidding rules, effectively allowing all tools again that were forbidden using functions of the table @ref rules. * * Only effects tools forbidden by rules::forbid_tool, rules::forbid_way_tool, rules::forbid_way_tool_cube, rules::forbid_way_tool_rect. * The result of ::is_tool_allowed and ::is_work_allowed_here is not influenced. * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_rules, "clear"); /** * Clear all forbidding rules for a selec player * * Only effects tools forbidden by rules::forbid_tool, rules::forbid_way_tool, rules::forbid_way_tool_cube, rules::forbid_way_tool_rect. * The result of ::is_tool_allowed and ::is_work_allowed_here is not influenced. * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::clear_player_rules, "clear_player"); /** * Allow tool with certain waytype within rectangular region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or 0 (to catch all) * @param pos_nw coordinate of north-western corner of rectangle * @param pos_se coordinate of south-eastern corner of rectangle * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::allow_way_tool_rect, "allow_way_tool_rect"); /** * Allow tool with certain waytype within cubic region on the map. * * @param player_nr number of player this rule applies to, * if this is set to player_all then this acts for all players except public player * @param tool_id id of tool * @param wt waytype * @param default_paramter object name or 0 (to catch all) * @param pos_nw 3d-coordinate of north-western corner of cube * @param pos_se 3d-coordinate of south-eastern corner of cube * @see tool_ids way_types player_all * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::allow_way_tool_cube, "allow_way_tool_cube"); /** * Signals that toolbars and active tools need to be checked against scenario rules again. * * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::gui_needs_update, "gui_needs_update"); end_class(vm); /** * Table with methods help debugging. * @note Only available in scenario mode. * @ingroup scen_only */ begin_class(vm, "debug", 0); /** * @returns text containing all active rules, can be used in @ref get_debug_text * @note Only available in scenario mode. * @ingroup scen_only */ STATIC register_method(vm, &scenario_t::get_forbidden_text, "get_forbidden_text"); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_schedule.cc000066400000000000000000000145661474050137200234140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_schedule.cc exports schedule structure and related functions. */ #include "../api_class.h" #include "../api_function.h" #include "../../dataobj/schedule.h" #include "../../simhalt.h" #include "../../simintr.h" #include "../../world/simworld.h" using namespace script_api; SQInteger schedule_entry_constructor(HSQUIRRELVM vm) // instance, coord3d, load, wait { koord3d pos = param::get(vm, 2); // world coordinates uint8 load = param::get(vm, 3); uint16 wait = param::get(vm, 4); // transform coordinates to squirrel coordinates koord k(pos.get_2d()); coordinate_transform_t::koord_w2sq(k); // propagate error SQInteger res = pos != koord3d::invalid ? SQ_OK : SQ_ERROR; if (SQ_SUCCEEDED(res)) { res = set_slot(vm, "x", k.x, 1); } if (SQ_SUCCEEDED(res)) { res = set_slot(vm, "y", k.y, 1); } if (SQ_SUCCEEDED(res)) { res = set_slot(vm, "z", pos.z, 1); } if (SQ_SUCCEEDED(res)) { res = set_slot(vm, "wait", wait, 1); } if (SQ_SUCCEEDED(res)) { res = set_slot(vm, "load", load, 1); } return res; } halthandle_t get_halt_from_koord3d(koord3d pos, const player_t *player ) { if( player == NULL ) { return halthandle_t(); } return haltestelle_t::get_halt(pos, player); } SQInteger waiting_time_to_string(HSQUIRRELVM vm) { schedule_entry_t entry(koord3d::invalid, 0, 0); get_slot(vm, "wait", entry.waiting_time, -1); plainstring str = difftick_to_string(entry.get_waiting_ticks(), false); return param::push(vm, str); } SQInteger schedule_constructor(HSQUIRRELVM vm) // instance, wt, entries = [], current = 0 { waytype_t wt = param::get(vm, 2); SQInteger res = set_slot(vm, "waytype", wt, 1); if (SQ_SUCCEEDED(res)) { sq_pushstring(vm, "entries", -1); // entries parameter if (sq_gettop(vm) >= 3) { sq_push(vm, 3); } else { // not provided, push empty array sq_newarray(vm, 4); } res = sq_set(vm, 1); } if (SQ_SUCCEEDED(res)) { uint8 current = 0; if (sq_gettop(vm) >= 4) { current = param::get(vm, 4); } res = set_slot(vm, "current", current, 1); } if (SQ_SUCCEEDED(res)) { // attach a schedule instance // the c++ schedule_t instance will be refilled everytime when transfered to the c++ side of things. schedule_t* sched = NULL; switch(wt) { case road_wt: sched = new truck_schedule_t(); break; case track_wt: sched = new train_schedule_t(); break; case water_wt: sched = new ship_schedule_t(); break; case air_wt: sched = new airplane_schedule_t(); break; case monorail_wt: sched = new monorail_schedule_t(); break; case tram_wt: sched = new tram_schedule_t(); break; case maglev_wt: sched = new maglev_schedule_t(); break; case narrowgauge_wt: sched = new narrowgauge_schedule_t(); break; default: sq_raise_error(vm, "Invalid waytype %d", wt); return SQ_ERROR; } attach_instance(vm, 1, sched); } return res; } // read entry at index, append to schedule void append_entry(HSQUIRRELVM vm, SQInteger index, schedule_t* sched) { koord3d pos = param::get(vm, index); uint8 minimum_loading = 0; get_slot(vm, "load", minimum_loading, index); uint16 waiting_time_shift = 0; get_slot(vm, "wait", waiting_time_shift, index); grund_t *gr = welt->lookup(pos); if (gr) { sched->append(gr, minimum_loading, waiting_time_shift); } } schedule_t* script_api::param::get(HSQUIRRELVM vm, SQInteger index) { // get waytype waytype_t wt = invalid_wt; get_slot(vm, "waytype", wt, index); // get instance pointer schedule_t* sched = get_attached_instance(vm, index, param::tag()); if (sched) { // check waytype if (wt != sched->get_waytype()) { sq_raise_error(vm, "Waytype mismatch in schedule"); return NULL; } sched->entries.clear(); // now read the entries sq_pushstring(vm, "entries", -1); SQInteger new_index = index > 0 ? index : index-1; if (SQ_SUCCEEDED(sq_get(vm, new_index))) { // now entries array at the top of the stack // foreach loop sq_pushnull(vm); while(SQ_SUCCEEDED(sq_next(vm, -2))) { append_entry(vm, -1, sched); sq_pop(vm, 2); } sq_pop(vm, 1); } // current stop uint8 current = 0; get_slot(vm, "current", current, index); sched->set_current_stop(current); } return sched; } void* script_api::param::tag() { return (void*)&script_api::param::get; } void export_schedule(HSQUIRRELVM vm) { /** * Schedule entries */ begin_class(vm, "schedule_entry_x", "coord3d"); #ifdef SQAPI_DOC // document members /** * Minimum loading percentage. */ integer load; /** * Waiting time setting. */ integer wait; #endif /** * Constructor * @param pos coordinate of entry * @param wait waiting time * @param load minimum loading */ register_function(vm, schedule_entry_constructor, "constructor"); /** * Returns halt at this entry position. * @param pl player that wants to use halt here * @return halt instance * @typemask halt_x(player_x) */ register_method(vm, &get_halt_from_koord3d, "get_halt", true); /** * Returns waiting time formatted as string. * @typemask string() */ register_function(vm, waiting_time_to_string, "waiting_time_to_string", 1, "x" ); end_class(vm); /** * Class holding the schedule */ create_class(vm, "schedule_x"); /** * Constructor. * Parameters @p entries and @p current are optional. * @param wt way type * @param entries array of entries of the new schedule (default = []) * @param current current stop of schedule (default = 0) * * @typemask command_x(way_types, array< schedule_entry_x >, integer) */ register_function(vm, schedule_constructor, "constructor", 3, "xi."); sq_settypetag(vm, -1, param::tag()); #ifdef SQAPI_DOC // document members /** * The list of schedule targets. */ array< schedule_entry_x > entries; /** * Waytype of schedule. */ way_types waytype; /** * Current stop of schedule: * default first stop (schedule of line) * or next stop of convoy (schedule of convoy). * * In order to change this value for a convoy * call @ref convoy_x::change_schedule. */ integer current; #else create_slot(vm, "entries", 0); create_slot(vm, "waytype", 0); create_slot(vm, "current", 0); #endif end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_settings.cc000066400000000000000000000121411474050137200234430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_settings.cc exports game settings functions. */ #include "api_command.h" #include "api_simple.h" #include "../api_class.h" #include "../api_function.h" #include "../../dataobj/settings.h" #include "../../descriptor/ground_desc.h" #include "../../ground/grund.h" #include "../../tool/simmenu.h" #include "../../world/simworld.h" using namespace script_api; mytime_t get_start_time(settings_t* settings) { uint32 yearmonth = 12*( max( settings->get_starting_year(),0) ) + max( settings->get_starting_month(),0); return yearmonth; } call_tool_init set_traffic_level(settings_t*, sint16 rate) { cbuffer_t buf; buf.printf("%i", rate); return call_tool_init(TOOL_TRAFFIC_LEVEL | SIMPLE_TOOL, buf, 0, welt->get_public_player()); } sint8 get_underground_view_level() { return grund_t::underground_level; } bool has_double_slopes() { return ground_desc_t::double_grounds; } void export_settings(HSQUIRRELVM vm) { /** * Table with methods to access game settings. */ begin_class(vm, "settings", 0); /** * New industries will be spawned if cities grow to over 2^n times this setting. * @returns number */ register_method(vm, &settings_t::get_industry_increase_every, "get_industry_increase_every"); /** * New industries will be spawned if cities grow to over 2^n times @p count. * Set to zero to prevent new industries to be spawned. * @param count * @warning cannot be used in network games. */ register_method(vm, &settings_t::set_industry_increase_every, "set_industry_increase_every"); /** * Get traffic level. */ register_method(vm, &settings_t::get_traffic_level, "get_traffic_level"); /** * Set traffic level. The higher the level the more city cars will be created. * @param rate new traffic level, must be between 0 and 16 */ register_method(vm, &set_traffic_level, "set_traffic_level", true); /** * Returns starting time of the game. * @returns table { "year" = .., "month" = .. } */ register_local_method(vm, get_start_time, "get_start_time"); /// @returns station coverage register_method(vm, &settings_t::get_station_coverage, "get_station_coverage"); /// @returns passenger factors influences passenger generation in cities register_method(vm, &settings_t::get_passenger_factor, "get_passenger_factor"); /// @returns maximum distance of city to factory for supplying workers register_method(vm, &settings_t::get_factory_worker_radius, "get_factory_worker_radius"); /// @returns minimum number of cities to supply workers for a factory register_method(vm, &settings_t::get_factory_worker_minimum_towns, "get_factory_worker_minimum_towns"); /// @returns maximum number of cities to supply workers for a factory register_method(vm, &settings_t::get_factory_worker_maximum_towns, "get_factory_worker_maximum_towns"); /// @returns freight will not enter convoy if next transfer halt is overcrowded register_method(vm, &settings_t::is_avoid_overcrowding, "avoid_overcrowding"); /// @returns freight will not start when best route goes through overcrowded halt register_method(vm, &settings_t::is_no_routing_over_overcrowding, "no_routing_over_overcrowding"); /// @returns true if halt capacity is separated between passengers, mail, freight register_method(vm, &settings_t::is_separate_halt_capacities, "separate_halt_capacities"); /// @returns true if it is allowed to buy obsolete vehicles register_method(vm, &settings_t::get_allow_buying_obsolete_vehicles, "obsolete_vehicles_allowed"); /// @returns max number of vehicles of road convois register_method(vm, &settings_t::get_max_road_convoi_length, "get_max_road_convoi_length"); /// @returns max number of vehicles of rail convois register_method(vm, &settings_t::get_max_rail_convoi_length, "get_max_rail_convoi_length"); /// @returns max number of vehicles of ship convois register_method(vm, &settings_t::get_max_ship_convoi_length, "get_max_ship_convoi_length"); /// @returns max number of vehicles of air convois register_method(vm, &settings_t::get_max_air_convoi_length, "get_max_air_convoi_length"); /// @returns true, if drive-on-left is on register_method(vm, &settings_t::is_drive_left, "get_drive_on_left"); /// @returns minimal z-distance between tiles with ways (possible values = 1,2) register_method(vm, &settings_t::get_way_height_clearance, "get_way_height_clearance"); /// @returns whether paksets support two different slope heights register_method(vm, &has_double_slopes, "has_double_slopes", true); /** * Three modes of transfer payment: * 0 = pay for travelled Manhattan distance * 1 = pay for distance difference to next transfer stop * 2 = pay for distance to destination */ register_method(vm, &settings_t::get_pay_for_total_distance_mode, "get_pay_for_total_distance_mode"); /** * Returns current view mode and underground view level. * Possible return values: * -128 == full underground view * +127 == normal view * other values == sliced view at the given value */ register_method(vm, &get_underground_view_level, "get_underground_view_level", true); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_simple.cc000066400000000000000000000241041474050137200230760ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_simple.cc exports simple data types. */ #include "api_simple.h" #include "../api_class.h" #include "../api_function.h" #include "../../dataobj/ribi.h" #include "../../world/simworld.h" #include "../../dataobj/scenario.h" using namespace script_api; #ifdef DOXYGEN /** * Struct to hold information about time as month-year. * If used as argument to functions then only the value of @ref raw matters. * If filled by an api-call the year and month will be set, too. * Relation: raw = 12*month + year. * @see world::get_time obj_desc_time_x */ class time_x { // begin_class("time_x") public: #ifdef SQAPI_DOC // document members integer raw; ///< raw integer value of date integer year; ///< year integer month; ///< month in 0..11 #endif }; // end_class /** * Struct to get precise information about time. * @see world::get_time */ class time_ticks_x : public time_x { // begin_class("time_ticks_x", "time_x") public: #ifdef SQAPI_DOC // document members integer ticks; ///< current time in ticks integer ticks_per_month; ///< length of one in-game month in ticks integer next_month_ticks; ///< new month will start at this time #endif }; // end_class #endif // pushes table = { raw = , year = , month = } SQInteger param::push(HSQUIRRELVM vm, mytime_t const& v) { sq_newtableex(vm, 6); create_slot(vm, "raw", v.raw); create_slot(vm, "year", v.raw/12); create_slot(vm, "month", v.raw%12); return 1; } SQInteger param::push(HSQUIRRELVM vm, mytime_ticks_t const& v) { param::push(vm, v); create_slot(vm, "ticks", v.ticks); create_slot(vm, "ticks_per_month", v.ticks_per_month); create_slot(vm, "next_month_ticks", v.next_month_ticks); return 1; } SQInteger param::push(HSQUIRRELVM vm, mytool_data_t const& v) { sq_newtableex(vm, 6); create_slot(vm, "start_pos", v.start_pos); create_slot(vm, "is_drag_tool", v.is_drag_tool); create_slot(vm, "is_ctrl", v.is_ctrl); create_slot(vm, "is_shift", v.is_shift); return 1; } mytime_t param::get(HSQUIRRELVM vm, SQInteger index) { // 0 has special meaning of 'no-timeline' SQInteger i=1; if (!SQ_SUCCEEDED(sq_getinteger(vm, index, &i))) { get_slot(vm, "raw", i, index); } return (uint16) (i >= 0 ? i : 1); } #define map_ribi_any(f,type) \ type export_## f(my_ribi_t r) \ { \ return ribi_t::f(r); \ } // export the ribi functions map_ribi_any(is_single, bool); map_ribi_any(is_twoway, bool); map_ribi_any(is_threeway, bool); map_ribi_any(is_bend, bool); map_ribi_any(is_straight, bool); map_ribi_any(doubles, my_ribi_t); map_ribi_any(backward, my_ribi_t); my_slope_t ribi_to_slope(my_ribi_t ribi) { return slope_type((ribi_t::ribi)ribi); } my_ribi_t slope_to_ribi(my_slope_t slope) { return ribi_type((slope_t::type)slope); } template SQInteger coord_to_ribi(HSQUIRRELVM vm) { // get coordinate vector without transformation sint16 x=-1, y=-1; get_slot(vm, "x", x, idx); get_slot(vm, "y", y, idx); koord k(x,y); // and do not transform ribi either uint8 ribi = ribi_type(k); return param::push(vm, ribi); } SQInteger ribi_to_coord(HSQUIRRELVM vm) { const uint8 ribi = param::get(vm, 2); if ((ribi & ~(uint8)ribi_t::all) != 0) { return sq_raise_error(vm, "Invalid dir %hhu (valid values are 0..15)", ribi); } koord k( (ribi_t::ribi)ribi ); return push_instance(vm, "coord", k.x, k.y); } void export_simple(HSQUIRRELVM vm) { /** * Class that holds 2d coordinates. * All functions that use this as input parameters will accept every data structure that contains members x and y. * * Coordinates always refer to the original rotation in @ref map.file. * They will be rotated if transferred between the game engine and squirrel. */ begin_class(vm, "coord"); #ifdef SQAPI_DOC // document members /// x-coordinate integer x; /// y-coordinate integer y; // operators are defined in script_base.nut coord(int x, int y); coord operator + (coord other); coord operator - (coord other); coord operator - (); coord operator * (integer fac); coord operator / (integer fac); /** * Converts coordinate to string containing the coordinates in the current rotation of the map. * * Cannot be used in links in scenario texts. Use @ref href instead. */ string _tostring(); /** * Generates text to generate links to coordinates in scenario texts. * @param text text to be shown in the link * @returns a-tag with link in href * @see get_rule_text */ string href(string text); #endif /** * Helper function to convert direction vector to dir type. * @typemask dir() */ register_function(vm, coord_to_ribi<1>, "to_dir", 1, "t|x|y"); end_class(vm); /** * Class that holds 3d coordinates. * All functions that use this as input parameters will accept every data structure that contains members x, y, and z. * * Coordinates always refer to the original rotation in @ref map.file. * They will be rotated if transferred between the game engine and squirrel. */ begin_class(vm, "coord3d", "coord"); #ifdef SQAPI_DOC // document members /// x-coordinate integer x; /// y-coordinate integer y; /// z-coordinate - height integer z; // operators are defined in script_base.nut coord(int x, int y, int z); coord3d operator + (coord3d other); coord3d operator - (coord other); coord3d operator + (coord3d other); coord3d operator - (coord other); coord3d operator - (); coord3d operator * (integer fac); coord3d operator / (integer fac); /** * Converts coordinate to string containing the coordinates in the current rotation of the map. * * Cannot be used in links in scenario texts. Use @ref href instead. */ string _tostring(); /** * Generates text to generate links to coordinates in scenario texts. * @param text text to be shown in the link * @returns a-tag with link in href * @see get_rule_text */ string href(string text); #endif end_class(vm); /** * Helper function to convert direction vector to dir type. * @param dir * @typemask dir(coord) */ register_function(vm, coord_to_ribi<2>, "coord_to_dir", 2, "x t|x|y"); /** * Class holding static methods to work with directions. * Directions are just bit-encoded integers. */ begin_class(vm, "dir"); #ifdef SQAPI_DOC // document members /** @name Named directions. */ //@{ static const dir none; static const dir north; static const dir east; static const dir northeast; static const dir south; static const dir northsouth; static const dir southeast; static const dir northsoutheast; static const dir west; static const dir northwest; static const dir eastwest; static const dir northeastwest; static const dir southwest; static const dir northsouthwest; static const dir southeastwest; static const dir all; //@} #endif /** * @param d direction to test * @return whether direction is single direction, i.e. just one of n/s/e/w */ STATIC register_method(vm, &export_is_single, "is_single", false, true); /** * @param d direction to test * @return whether direction is double direction, e.g. n+e, n+s. */ STATIC register_method(vm, &export_is_twoway, "is_twoway", false, true); /** * @param d direction to test * @return whether direction is triple direction, e.g. n+s+e or n+s+e+w. */ STATIC register_method(vm, &export_is_threeway, "is_threeway", false, true); /** * @param d direction to test * @return whether direction is curve, e.g. n+e, s+w. */ STATIC register_method(vm, &export_is_bend, "is_curve", false, true); /** * @param d direction to test * @return whether direction is straight and has no curves in it, e.g. n+s, w. */ STATIC register_method(vm, &export_is_straight, "is_straight", false, true); /** * @param d direction * @return complements direction to complete straight, i.e. w -> w+e, but n+w -> 0. */ STATIC register_method(vm, &export_doubles, "double", false, true); /** * @param d direction to test * @return backward direction, e.g. w -> e, n+w -> s+e, n+w+s -> e. */ STATIC register_method(vm, &export_backward, "backward", false, true); /** * Converts direction to slope: direction goes upward on slope. * @param d direction */ STATIC register_method(vm, &ribi_to_slope, "to_slope", false, true); /** * Helper function to convert direction vector to dir type. * @typemask coord(dir) */ STATIC register_function(vm, ribi_to_coord, "to_coord", 2, ".i", true); end_class(vm); /** * Class holding static methods to work with slopes. * Slopes are just integers. */ begin_class(vm, "slope"); #ifdef SQAPI_DOC // document members /** @name Named slopes. */ //@{ static const slope flat; static const slope north; ///< North slope static const slope west; ///< West slope static const slope east; ///< East slope static const slope south; ///< South slope static const slope northwest; ///< NW corner static const slope northeast; ///< NE corner static const slope southeast; ///< SE corner static const slope southwest; ///< SW corner static const slope raised; ///< special meaning: used as slope of bridgeheads static const slope all_up_slope = 82; ///< used for terraforming tools static const slope all_down_slope = 83; ///< used for terraforming tools //@} #endif /** * Converts slope to dir: direction goes upward on slope. * If slope cannot be walked on, it returns @ref dir::none. * @param s slope */ STATIC register_method(vm, &slope_to_ribi, "to_dir", false, true); end_class(vm); #ifdef SQAPI_DOC /** * Classes to access in-game objects. * Creating an instance of such classes will not create an object in the game. * Instead, these classes contain data to access the in-game object. * If the in-game object disappears, then any access to it via these classes will fail. * Use the method @r ingame_object::is_valid to check whether the in-game object is still alive. */ class ingame_object { /** * @returns true if in-game object can still be accessed. */ bool is_valid(); } #endif } simutrans-124.3/src/simutrans/script/api/api_simple.h000066400000000000000000000027721474050137200227470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_API_SIMPLE_H #define SCRIPT_API_API_SIMPLE_H #include "../../../squirrel/squirrel.h" #include "../../dataobj/ribi.h" #include "../../dataobj/koord3d.h" /** @file api_simple.h Helper functions to export simple datatypes: ribi & friends */ /** * Use own type for ribis and slopes */ struct my_ribi_t { uint8 data; my_ribi_t(ribi_t::ribi r) : data(r) { } operator ribi_t::ribi() const { return data; } }; struct my_slope_t { uint8 data; my_slope_t(slope_t::type r) : data(r) { } operator slope_t::type() const { return data; } }; /** * Coordinate that accepts either 2d or 3d coordinates. * Converts to kartenboden/ground when supplied with 2d coordinates. */ struct my_koord3d { koord3d data; my_koord3d(koord3d k) : data(k) { } operator koord3d() const { return data; } }; namespace script_api { struct mytime_t { uint32 raw; mytime_t(uint32 r_) : raw(r_) {} }; struct mytime_ticks_t : public mytime_t { uint32 ticks; uint32 ticks_per_month; uint32 next_month_ticks; mytime_ticks_t(uint32 r, uint32 t, uint32 tpm, uint32 nmt) : mytime_t(r), ticks(t), ticks_per_month(tpm), next_month_ticks(nmt) {} }; struct mytool_data_t { koord3d start_pos; bool is_drag_tool; bool is_ctrl; bool is_shift; mytool_data_t(koord3d pos, bool drag, bool ctrl, bool shift) : start_pos(pos), is_drag_tool(drag), is_ctrl(ctrl), is_shift(shift) {} }; }; #endif simutrans-124.3/src/simutrans/script/api/api_skeleton.cc000066400000000000000000000266661474050137200234500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file api_skeleton.cc Documents the necessary functions to be implemented by a script */ // It is in a C++ file to be processed by Doxygen filters to get function typemasks right #ifdef DOXYGEN /** * This function is called when the scenario starts. Do all the initializations here, * as you cannot initialize global variables with non-built-in squirrel types. * @typemask void() * @ingroup scen_skel */ register_function("start"); /** * This function is called when the AI starts. Do all the initializations here, * as you cannot initialize global variables with non-built-in squirrel types. * * @param pl_num the number of the AI player. Call player_x(pl_num) to obtain * a corresponding player_x instance. Definitely store this value! * * @typemask void(int) * @ingroup ai_skel */ register_function("start"); /** * This function is called when a savegame with active scenario is loaded. * Do all the initializations and post-processing here. * @typemask void() * @ingroup scen_skel * @ingroup quick_return_func */ register_function("resume_game"); /** * This function is called when a savegame with active AI player is loaded. * Do all the initializations and post-processing here. * * @param pl_num the number of the AI player. Call player_x(pl_num) to obtain * a corresponding player_x instance. Definitely store this value! * @typemask void(int) * @ingroup ai_skel */ register_function("resume_game"); /** * The heartbeat of the AI player. Here, all AI-related calculations and work can be done. * * @typemask void() * @ingroup ai_skel */ register_function("step"); /** * Called at the beginning of a new month. * Statistics of the last (complete) month is now in position [1] of any statistics array. * @typemask void() * @ingroup scen_skel * @ingroup ai_skel */ register_function("new_month") /** * Called at the beginning of a new year. * Statistics of the last (complete) year is now in position [1] of any statistics array. * @typemask void() * @ingroup scen_skel * @ingroup ai_skel */ register_function("new_year") /** * Called before starting the scenario. * Should return filename of the savegame to be used for this scenario. * If it returns "" the scenario is started with the currently running world. * By default returns the string @ref map.file. * @returns filename or "" * @typemask string() * @ingroup scen_skel * @ingroup quick_return_func */ register_function("get_map_file") /** * Text shown in the 'About' tab in the scenario info window. * * There is a default implementation, which returns concatenation * of #scenario author, version, short_description. * Html-like tags can be used, see @ref get_rule_text. * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_about_text"); /** * Text shown in the 'Rules' tab in the scenario info window. * Must return quickly and must not modify the map! Calling tools is forbidden! * * Text can contain several html-like tags: * - \, \: line break * - \, \, \, \: text between start and end tag will be colored. It's a matter of taste, of course. * - \: insert hyper link, text between start and end tag will be colored blue. * - link to another tab of scenario info window: href="tabname", where tabname is one of: info, goal, rules, result, about * - link to position on the map: href="(x,y)" or href="(x,y,z)", click on link will jump to the map position * - call scripted method: href="script:bla(1)" will call bla(1). The characters \>, ', \" are not allowed in the string and will produce weird results. * The called method must return quickly and must not modify the map! Calling tools is forbidden! * * @code *

Here is an example.

*
* Do not build anything at the position
near Cologne. * The mayor of Berlin seems to be frustrated with your airport building capabilities. *
* Your results can be found in the results tab. * @endcode * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_rule_text"); /** * Text shown in the 'Goal' tab in the scenario info window. * * Html-like tags can be used, see @ref get_rule_text. * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_goal_text"); /** * Text shown in the 'Info' tab in the scenario info window. * * Html-like tags can be used, see @ref get_rule_text. * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_info_text"); /** * Text shown in the 'Result' tab in the scenario info window. * * Html-like tags can be used, see @ref get_rule_text. * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_result_text"); /** * Text shown in the 'Debug' tab in the scenario info window. * If the method returns null then the 'Debug'-tab will not be shown. * * Html-like tags can be used, see @ref get_rule_text. * * @param pl player number of active player * @typemask string(integer) * @ingroup scen_skel */ register_function("get_debug_text"); /** * Returns string containing the version of the api * that the scenario supports. * By default returns the string @ref scenario.api. * * If it returns "*" then this indicates that the scenario works in the most current api version. * Currently "112.3" and "120.1" are supported. * * @typemask string() * @ingroup scen_skel * @ingroup quick_return_func */ register_function("get_api_version"); /** * Core function of a scenario: It returns the completion percentage for the * specified player. * * If it returns a negative value the respective player has lost. This state will not be changed * even if the function later returns positive values again. * * If it returns a value >= 100 then the respective player has won. This state will not be changed * even if the function later returns lower values again. * * @param pl player number of active player * @typemask integer(integer) * @ingroup scen_skel */ register_function("is_scenario_completed"); /** * Function is called when toolbars are filled with icons or when a tool should be activated. * * There is a default implementation, which forbids map-editing tools. * * @attention Results are not transfered over network, use the functions provided in #rules in this case. * * @param pl player number * @param tool_id see @ref tool_ids * @param wt waytype of tool * @param name is parameter (string) i.e. description for way tools * @returns true if tool is allowed. * @typemask bool(integer,integer,way_types) * @ingroup scen_skel * @ingroup quick_return_func */ register_function("is_tool_allowed"); /** * Called when user clicks on a tile to build or remove something. * * This function is network-aware: * Error messages are sent back over network to clients. * * The error message can contain a coordinate, which is used to show a location on the map. * In order to show the right place, use @ref coord_to_string. The must be enclosed in parentheses * or prefixed with @ . * @code return "You cannot do this. The guy living at (" + coord_to_string({x=47, y=11}) + ") does not like you!" @endcode * * @attention Does not work with waybuilding and all tools that need path-finding, use the functions provided in #rules in this case. * * @param pl player number * @param tool_id see @ref tool_ids * @param name is parameter (string) i.e. description for way tools * @param pos coordinate * * @return null if allowed, an error message otherwise * @typemask string(integer,integer,coord3d) * @ingroup scen_skel * @ingroup quick_return_func */ register_function("is_work_allowed_here"); /** * Called when user changed a schedule (closes schedule window). * * @warning Function will NOT be called in network games. * * @param pl player number * @param schedule the schedule * * @return null if allowed, an error message otherwise * @typemask string(integer,schedule_x) * @ingroup scen_skel * @ingroup quick_return_func */ register_function("is_schedule_allowed"); /** * Called when user wants to start convoy. * * @warning Function will NOT be called in network games. * * @param pl player number * @param convoy convoy to start * @param depot convoy is in this depot * * @return null if allowed, an error message otherwise * @typemask string(integer,convoy_x,depot_x) * @ingroup scen_skel * @ingroup quick_return_func */ register_function("is_convoy_allowed"); /** * Called when player click link in scenario windows. * * @param pos coordinate go to in link * * @return null if allowed, an error message otherwise * @typemask string(coord3d) * @ingroup scen_skel * @ingroup quick_return_func */ register_function("jump_to_link_executed"); /** * Initializes the tool. * @returns true upon success. * * @param pl player instance to use this tool. * @ingroup tool_skel * @ingroup quick_return_func * @typemask bool(player_x) */ register_function("init"); /** * Exits the tool. Do cleanup here. * @returns true upon success. * * @param pl player instance to use this tool. * @ingroup tool_skel * @ingroup quick_return_func * @typemask bool(player_x) */ register_function("exit"); /** * Does the work (for tools of one-click type). * @returns null upon success, an error message otherwise. * * @param pl player instance to use this tool. * @param pos tile clicked by user, here the work should be done. * @param keys state of ctrl/shift keys. * @ingroup tool_skel * @typemask string(player_x, coord3d, int) */ register_function("work"); /** * Does the work (for tools of two-click type). * @returns null upon success, an error message otherwise. * * @param pl player instance to use this tool. * @param start first tile clicked by user. * @param end second tile clicked by user. * @param keys state of ctrl/shift keys. * @ingroup tool_skel * @typemask string(player_x, coord3d, coord3d, int) */ register_function("do_work"); /** * Mark tiles for working (for tools of two-click type). * Call @ref mark_tile from here. * * @param pl player instance to use this tool. * @param start first tile clicked by user. * @param end second tile clicked by user. * @param keys state of ctrl/shift keys. * @ingroup tool_skel * @typemask void(player_x, coord3d, coord3d, int) */ register_function("mark_tiles"); /** * Place marker image of scripted tool at @p pos. * Marker images will be deleted automatically. * @returns true if succesfull * * @param pos position to be marked * @ingroup tool_only * @typemask bool(coord3d) */ // see tool/simtool.scripted.cc register_function("mark_tile"); /** * Can the tool start/end on @p pos? If it is the second click, @p start is the position of the first click. * Possible return values: * 0 = no * 1 = This tool can work on this tile (with single click) * 2 = On this tile can dragging start/end * 3 = Both (1 and 2) * * @param pl player instance to use this tool. * @param pos position to test * @param start first tile clicked by user * @ingroup tool_skel * @ingroup quick_return_func * @typemask void(player_x, coord3d, coord3d) */ register_function("is_valid_pos"); #endif simutrans-124.3/src/simutrans/script/api/api_skeleton.h000066400000000000000000000033131474050137200232720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file api_skeleton.h Documents the global variables in a scenario script */ #ifdef SQAPI_DOC // document global structs struct { /// Short description of scenario, is shown for example in finance window. string short_description; /// Author(s) of the scenario and/or scripts. string author; /// Version of script. string version; /** * Script requires this version of api. * Corresponds to release numbers (e.g. 112.3). * Set it to "*" to support nightly versions. * If this string is not set, the default "112.3" will be used. * * @see get_api_version */ /// Required version of api. string api; } /** * Meta information about the scenario. */ scenario; struct { /** * Name of savegame. The scenario starts with the world saved there. * If file == "" then do not load a saved, attach * the scenario to the running world instead. * * @see get_map_file */ string file; } /** * Information about game map/world. */ map; /** * Only this table is saved and reloaded with an savegame. * Only plain data is saved: no classes / functions, no cyclic references. * * Instances of classes can be saved if * (1) the class implements the function _save that * (2) returns something which can reconstruct the instance, i.e. an constructor call, embedded in a string. * @code * * class my_class_with_save { * foo = 0 * * constructor(f) * { * foo = f; * } * function _save() * { * return "my_class_with_save("+ foo + ")" * } * } * @endcode * * @brief * Persistent data should go into this table. */ table persistent; #endif simutrans-124.3/src/simutrans/script/api/api_tiles.cc000066400000000000000000000272061474050137200227330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_tiles.cc exports tile related functions. */ #include "api_simple.h" #include "get_next.h" #include "../api_class.h" #include "../api_function.h" #include "../../tool/simmenu.h" #include "../../world/simworld.h" #include "../../ground/wasser.h" #include "../../obj/crossing.h" #include "../../simconvoi.h" #include "../../vehicle/vehicle.h" namespace script_api { declare_enum_param(grund_t::flag_values, uint8, "flags"); declare_specialized_param(depot_t*, "t|x|y", "depot_x"); }; using namespace script_api; SQInteger get_next_object(HSQUIRRELVM vm) { grund_t *gr = param::get(vm, 1); return generic_get_next(vm, gr ? gr->obj_count() : 0); } SQInteger get_object_index(HSQUIRRELVM vm) { grund_t *gr = param::get(vm, 1); uint8 index = param::get(vm, 2); obj_t *obj = NULL; if (gr && index < gr->obj_count()) { obj = gr->obj_bei(index); } return param::push(vm, obj); } SQInteger get_object_count(HSQUIRRELVM vm) { grund_t *gr = param::get(vm, 1); return param::push(vm, gr ? gr->obj_count() : 0); } call_tool_work tile_remove_object(grund_t* gr, player_t* player, obj_t::typ type) { cbuffer_t buf; buf.printf("%d", (int)type); return call_tool_work(TOOL_REMOVER | GENERAL_TOOL, (const char*)buf, 0, player, gr->get_pos()); } // return way ribis, have to implement a wrapper, to correctly rotate ribi static SQInteger get_way_ribi(HSQUIRRELVM vm) { grund_t *gr = param::get(vm, 1); waytype_t wt = param::get(vm, 2); bool masked = param::get(vm, 3); ribi_t::ribi ribi = gr ? (masked ? gr->get_weg_ribi(wt) : gr->get_weg_ribi_unmasked(wt) ) : 0; return param::push(vm, ribi); } static SQInteger get_canal_ribi(HSQUIRRELVM vm) { grund_t *gr = param::get(vm, 1); ribi_t::ribi ribi = gr && gr->is_water() ? ((wasser_t*)gr)->get_canal_ribi() : (ribi_t::ribi)0; return param::push(vm, ribi); } // we have to implement a wrapper, to correctly rotate ribi grund_t* get_neighbour(grund_t *gr, waytype_t wt, my_ribi_t ribi) { grund_t *to = NULL; if (gr && ribi_t::is_single(ribi)) { gr->get_neighbour(to, wt, ribi); } return to; } my_slope_t get_slope(grund_t *gr) { return gr->get_grund_hang(); } bool is_crossing(grund_t *gr) { return gr->find(); } halthandle_t get_first_halt_on_square(planquadrat_t* plan) { return plan->get_halt(NULL); } vector_tpl const& square_get_halt_list(planquadrat_t *plan) { static vector_tpl list; list.clear(); if (plan) { const halthandle_t* haltlist = plan->get_haltlist(); for(uint8 i=0, end = plan->get_haltlist_count(); i < end; i++) { list.append(haltlist[i]); } } return list; } vector_tpl const get_convoy_list(grund_t* gr) { static vector_tpl list; list.clear(); for( uint8 n = 0; nobj_count(); n++) { obj_t* obj = gr->obj_bei( n ); if( vehicle_t* veh = dynamic_cast(obj) ) { convoihandle_t cnv; if( veh->get_convoi() ) { list.append_unique( veh->get_convoi()->self ); } } } return list; } void export_tiles(HSQUIRRELVM vm) { /** * Class to access tiles on the map. * * There is the possibility to iterate through all objects on the tile: * @code * local tile = tile_x( ... ) * foreach(thing in tile) { * ... // thing is an instance of the map_object_x (or a derived) class * } * @endcode */ begin_class(vm, "tile_x", "coord3d,extend_get,ingame_object"); /** * Constructor. Returns tile at particular 3d coordinate. * If not tile is found, it returns the ground tile. * Raises error, if (@p x, @p y) coordinates are out-of-range. * @param x x-coordinate * @param y y-coordinate * @param z z-coordinate * @typemask (integer,integer,integer) */ // actually defined in simutrans/script/script_base.nut // register_function(..., "constructor", ...); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Search for a given object type on the tile. * @return some instance or null if not found */ register_method(vm, &grund_t::suche_obj, "find_object"); /** * Remove object of given type from the tile. * Type @p type must be one of the following: ::mo_label, ::mo_pedestrian, ::mo_city_car, ::mo_powerline, ::mo_transformer_s, * ::mo_transformer_c, ::mo_signal, ::mo_roadsign, ::mo_wayobj, ::mo_tunnel, ::mo_bridge, ::mo_field, ::mo_building, ::mo_depot_rail. * Setting @p type to ::mo_depot_rail deletes depots of every type. * @param pl player that pays for removal * @param type object type * @returns null upon success, an error message otherwise * @warning Does not work with all object types. * @ingroup game_cmd */ register_method(vm, &tile_remove_object, "remove_object", true); /** * Access halt at this tile. * @returns halt_x instance or null/false if no halt is present */ register_method(vm, &grund_t::get_halt, "get_halt"); /** * Queries tile type. * @returns true if tile is an ocean tile */ register_method(vm, &grund_t::is_water, "is_water"); /** * Queries tile type. * @returns true if tile is an bridge tile (including bridge starts) */ register_method(vm, &grund_t::ist_bruecke, "is_bridge"); /** * Queries tile type. * @returns true if tile is an tunnel tile (including tunnel mouths) */ register_method(vm, &grund_t::ist_tunnel, "is_tunnel"); /** * Queries tile type. * @returns true if tile is empty (no ways, buildings, powerlines, halts, not water tile) */ register_method(vm, &grund_t::ist_natur, "is_empty"); /** * Queries tile type. * @returns true if tile on ground (not bridge/elevated, not tunnel) */ register_method(vm, &grund_t::ist_karten_boden, "is_ground"); /** * Checks for crossing object. * @returns true if there is a crossing on the tile. */ register_method(vm, &is_crossing, "is_crossing", true); /** * Returns encoded slope of tile, zero means flat tile. * @returns slope */ register_method(vm, &get_slope, "get_slope", true); /** * Returns text of a sign on this tile (station sign, city name, label). * @returns text */ register_method(vm, &grund_t::get_text, "get_text"); /** * Queries ways on the tile. * @param wt waytype * @returns true if there is a way with the given waytype on the tile. */ register_method(vm, &grund_t::hat_weg, "has_way"); /** * Queries ways on the tile. * @returns true if there is at least one way on the tile */ register_method(vm, &grund_t::hat_wege, "has_ways"); /** * Queries ways on the tile. * @returns true if there is are two ways on the tile */ register_method(vm, &grund_t::has_two_ways, "has_two_ways"); /** * Returns way_x object on this tile of way type @p wt if present * @param wt waytype * @returns way object or null */ register_method(vm, &grund_t::get_weg, "get_way"); /** * Return directions in which ways on this tile go. One-way signs are ignored here. * @param wt waytype * @returns direction * @typemask dir(waytypes) */ register_function_fv(vm, &get_way_ribi, "get_way_dirs", 2, "xi", freevariable(false) ); /** * Return directions in which ways on this tile go. Some signs restrict available directions. * @param wt waytype * @returns direction * @typemask dir(waytypes) */ register_function_fv(vm, &get_way_ribi, "get_way_dirs_masked", 2, "xi", freevariable(true) ); /** * Return directions in which canals branch off from water tiles. * Used for jps pathfinding on water tiles. * @returns direction * @typemask dir() */ register_function(vm, &get_canal_ribi, "get_canal_ribi", 1, "x"); /** * Returns neighbour if one follows way in the given direction. * @param wt waytype, if equal to @ref wt_all then ways are ignored. * @param d direction * @return neighbour tile or null */ register_method(vm, &get_neighbour, "get_neighbour", true); /** * Returns depot_x object on this tile if any depot is present. * @returns depot object or null */ register_method(vm, &grund_t::get_depot, "get_depot"); /** * Checks whether player can delete all objects on the tile. * @param pl player * @return error message or null if player can delete everything */ register_method(vm, &grund_t::kann_alle_obj_entfernen, "can_remove_all_objects"); /** @name Functions to mark tiles. * Methods to mark, unmark, and check mark-status of tiles. * Mark flag can be reset by cursor movement. * @warning In network games, they only work on server. */ //@{ /// Check if tile is marked. register_method_fv(vm, &grund_t::get_flag, "is_marked", freevariable(grund_t::marked)); /// Unmark tile. register_method_fv(vm, &grund_t::clear_flag, "unmark", freevariable(grund_t::marked)); /// Mark tile. register_method_fv(vm, &grund_t::set_flag, "mark", freevariable(grund_t::marked)); //@} /** * @return convoy list by tile */ register_method(vm, &get_convoy_list, "get_convoys", true); #ifdef SQAPI_DOC // document members /** * List to iterate through all objects on this tile. * @code * t= tile_x(47,11) * foreach(obj in t.get_objects()) { * ... * } * @endcode */ tile_object_list_x get_objects(); #endif end_class(vm); /** * Class that holds an iterator through the list of objects on a particular tile. * * For an example see tile_x. */ begin_class(vm, "tile_object_list_x", "coord3d"); /** * Meta-method to be used in foreach loops to loop over all objects on the tile. Do not call it directly. */ register_function(vm, get_next_object, "_nexti", 2, "x o|i"); /** * Meta-method to be used in foreach loops to loop over all objects on the tile. Do not call it directly. */ register_function(vm, get_object_index, "_get", 2, "x i|s"); /** * Returns number of objects on the tile. * @typemask integer() */ register_function(vm, get_object_count, "get_count", 1, "x"); end_class(vm); /** * Class to map squares, which holds all the tiles on one particular coordinate. */ begin_class(vm, "square_x", "coord,extend_get,ingame_object"); /** * Constructor. Returns map square at particular 2d coordinate. * Raises error, if (@p x, @p y) coordinate are out-of-range. * @param x x-coordinate * @param y z-coordinate * @typemask (integer,integer) */ // actually defined in simutrans/script/script_base.nut // register_function(..., "constructor", ...); /** * @returns if object is still valid. */ export_is_valid(vm); //register_function("is_valid") /** * Access some halt at this square. * @deprecated Use square_x::get_player_halt or tile_x::get_halt instead! * @returns halt_x instance or null/false if no halt is present */ register_method(vm, &get_first_halt_on_square, "get_halt", true); /** * Access halt of this player at this map position. * @param pl potential owner of halt * @returns halt_x instance or null/false if no halt is present */ register_method(vm, &planquadrat_t::get_halt, "get_player_halt"); /** * Access tile at specified height. * @param z height * @returns tile_x or null/false if nothing found */ register_method(vm, &planquadrat_t::get_boden_in_hoehe, "get_tile_at_height"); /** * Access ground tile. * @returns tile_x instance */ register_method(vm, &planquadrat_t::get_kartenboden, "get_ground_tile"); /** * Returns list of stations that cover this tile. * @typemask array */ register_method(vm, &square_get_halt_list, "get_halt_list", true); /** * Returns climate of ground tile. */ register_method(vm, &planquadrat_t::get_climate, "get_climate"); end_class(vm); } simutrans-124.3/src/simutrans/script/api/api_world.cc000066400000000000000000000431671474050137200227460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api.h" /** @file api_world.cc exports world-map functions. */ #include "api_obj_desc_base.h" #include "api_simple.h" #include "get_next.h" #include "../api_class.h" #include "../api_function.h" #include "../../world/simworld.h" #include "../../simversion.h" #include "../../player/simplay.h" #include "../../obj/gebaeude.h" #include "../../obj/label.h" #include "../../descriptor/ground_desc.h" #include "../../simware.h" #include "../../builder/goods_manager.h" #include "../../simhalt.h" #include "../../simfab.h" using namespace script_api; mytime_ticks_t world_get_time(karte_t*) { return mytime_ticks_t(welt->get_current_month(), welt->get_ticks(), welt->scale_with_month_length(1<<18), welt->get_next_month_ticks()); } vector_tpl const& get_world_stat(karte_t* welt, bool monthly, sint32 INDEX) { static vector_tpl v; v.clear(); if (0<=INDEX && INDEXget_finance_history_month(i, INDEX) ); } else { v.append( welt->get_finance_history_year(i, INDEX) ); } } } return v; } bool world_remove_player(karte_t *welt, player_t *player) { if (player == NULL) { return false; } // first test bool ok = welt->change_player_tool(karte_t::delete_player, player->get_player_nr(), 0, true /*unlocked*/, false /*exec*/); if (!ok) { return false; } // now call - will not have immediate effect in network games welt->call_change_player_tool(karte_t::delete_player, player->get_player_nr(), 0, true /*scripted*/); return true; } uint32 world_generate_goods(karte_t *welt, koord from, koord to, const goods_desc_t *desc, uint32 count) { if (count == 0 || count >= 1<<23) { return 0; } planquadrat_t *fromplan = welt->access(from); planquadrat_t *toplan = welt->access(to); if (!fromplan || !toplan) { return haltestelle_t::NO_ROUTE; } else if (fromplan->get_haltlist_count() == 0) { // not reachable return haltestelle_t::NO_ROUTE; } ware_t good(desc); good.set_target_pos(to); good.amount = count; good.to_factory = fabrik_t::get_fab(to) != NULL; ware_t return_good(desc); const halthandle_t *haltlist = fromplan->get_haltlist(); const uint8 hl_count = fromplan->get_haltlist_count(); const bool no_route_over_overcrowded = welt->get_settings().is_no_routing_over_overcrowding(); assert(hl_count > 0); const int route_result = haltestelle_t::search_route(haltlist, hl_count, no_route_over_overcrowded, good, &return_good); switch (route_result) { case haltestelle_t::ROUTE_WALK: if (good.get_desc() == goods_manager_t::passengers) { haltlist[0]->add_pax_walked(count); } break; case haltestelle_t::ROUTE_OVERCROWDED: if (good.get_desc() == goods_manager_t::passengers) { haltlist[0]->add_pax_unhappy(count); } break; case haltestelle_t::NO_ROUTE: if (good.get_desc() == goods_manager_t::passengers) { haltlist[0]->add_pax_no_route(count); } break; case haltestelle_t::ROUTE_OK: { assert(route_result == haltestelle_t::ROUTE_OK); const halthandle_t start_halt = return_good.get_target_halt(); start_halt->starte_mit_route(good); if (good.get_desc() == goods_manager_t::passengers) { start_halt->add_pax_happy(good.amount); } else { start_halt->recalc_status(); } } break; } return route_result; } // returns index of attraction base tile with index > start uint32 get_next_attraction_base(uint32 start) { const weighted_vector_tpl& attractions = welt->get_attractions(); for(uint32 i = start+1; i < attractions.get_count(); i++) { gebaeude_t *gb = attractions[i]; if (gb != NULL && gb->get_first_tile() == gb) { return i; } } return attractions.get_count(); } SQInteger world_attraction_list_next(HSQUIRRELVM vm) { return generic_get_next_f(vm, welt->get_attractions().get_count(), get_next_attraction_base); } namespace script_api { declare_fake_param(attraction_list_t, "attraction_list_x"); declare_fake_param(label_list_t, "label_list_x"); } gebaeude_t* world_attraction_list_get(attraction_list_t, uint32 index) { const weighted_vector_tpl& attractions = welt->get_attractions(); return (index < attractions.get_count()) ? attractions[index] : NULL; } SQInteger world_get_attraction_list(HSQUIRRELVM vm) { return push_instance(vm, "attraction_list_x"); } SQInteger world_get_attraction_count(HSQUIRRELVM vm) { return param::push(vm, welt->get_attractions().get_count()); } SQInteger world_get_label_list(HSQUIRRELVM vm) { return push_instance(vm, "label_list_x"); } uint32 world_get_label_count(label_list_t) { return welt->get_label_list().get_count(); } SQInteger world_label_list_next(HSQUIRRELVM vm) { return generic_get_next(vm, welt->get_label_list().get_count()); } label_t* world_label_list_get(label_list_t, uint32 index) { auto list = welt->get_label_list(); if (index < list.get_count()) { koord k = list[index]; if (grund_t *gr = welt->lookup_kartenboden(k)) { return gr->find(); } } return NULL; } SQInteger world_get_convoy_list(HSQUIRRELVM vm) { push_instance(vm, "convoy_list_x"); set_slot(vm, "use_world", true); return 1; } SQInteger world_get_size(HSQUIRRELVM vm) { koord k = welt->get_size(); if (coordinate_transform_t::get_rotation() & 1) { return push_instance(vm, "coord", k.y, k.x); } else { return push_instance(vm, "coord", k.x, k.y); } } const char* get_pakset_name() { return ground_desc_t::outside->get_copyright(); } const char* get_version_number() { return VERSION_NUMBER; } void export_world(HSQUIRRELVM vm, bool scenario) { /** * Table with methods to access the world, the universe, and everything. */ begin_class(vm, "world", "extend_get"); /** * Checks whether given coordinate is valid. * @param k coordinate * @returns true if coordinate is valid */ STATIC register_method< bool(karte_t::*)(koord) const>(vm, &karte_t::is_within_limits, "is_coord_valid"); /** * Searches city next to the given coordinate. * @param k coordinate * @returns city if there is any */ STATIC register_method(vm, &karte_t::find_nearest_city, "find_nearest_city"); /** * Current season. * @returns season (0=winter, 1=spring, 2=summer, 3=autumn) */ STATIC register_method(vm, &karte_t::get_season, "get_season"); if (scenario) { /** * Removes player company: removes all assets. Use with care. * * If pl is the first player (nr == 0) it is restarted immediately. * Public player (nr == 1) cannot be removed. * * In network games, there will be a delay between the call to this function and the removal of the player. * * @param pl player to be removed * @ingroup scen_only * @returns whether operation was successful */ STATIC register_method(vm, &world_remove_player, "remove_player", true); /** * Generates goods (passengers, mail or freight) that want to travel from @p from to @p to. * Updates halt statistics (happy, unhappy, no route) for passengers if possible. * * @param from start position for good * @param to destination position for good * @param desc Good descriptor * @param count Number of goods to generate * @retval 0 No route to destination or start position not valid * @retval 1 Passengers/mail/freight successfully generated * @retval 2 Destination is within station catchment area * @retval 8 Route is overcrowded (if no_routing_over_overcrowded is enabled) * @ingroup scen_only */ STATIC register_method(vm, &world_generate_goods, "generate_goods", true); } /** * Returns player number @p pl. If player does not exist, returns null. * @param pl player number */ STATIC register_method(vm, &karte_t::get_player, "get_player", true); /** * @returns current in-game time. */ STATIC register_local_method(vm, world_get_time, "get_time"); /** * Get monthly statistics of total number of citizens. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_citizens", freevariable(true, karte_t::WORLD_CITIZENS), true ); /** * Get monthly statistics of total city growth. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_growth", freevariable(true, karte_t::WORLD_GROWTH), true ); /** * Get monthly statistics of total number of towns. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_towns", freevariable(true, karte_t::WORLD_TOWNS), true ); /** * Get monthly statistics of total number of factories. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_factories", freevariable(true, karte_t::WORLD_FACTORIES), true ); /** * Get monthly statistics of total number of convoys. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_convoys", freevariable(true, karte_t::WORLD_CONVOIS), true ); /** * Get monthly statistics of total number of citycars. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_citycars", freevariable(true, karte_t::WORLD_CITYCARS), true ); /** * Get monthly statistics of ratio transported to generated passengers. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_ratio_pax", freevariable(true, karte_t::WORLD_PAS_RATIO), true ); /** * Get monthly statistics of total number of generated passengers. * @returns array, index [0] corresponds to current month * @see city_x::get_generated_pax city_x::get_transported_pax */ STATIC register_method_fv(vm, &get_world_stat, "get_generated_pax", freevariable(true, karte_t::WORLD_PAS_GENERATED), true ); /** * Get monthly statistics of ratio transported to generated mail. * @returns array, index [0] corresponds to current month */ STATIC register_method_fv(vm, &get_world_stat, "get_ratio_mail", freevariable(true, karte_t::WORLD_MAIL_RATIO), true ); /** * Get monthly statistics of total number of generated mail. * @returns array, index [0] corresponds to current month * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_generated_mail", freevariable(true, karte_t::WORLD_MAIL_GENERATED), true ); /** * Get monthly statistics of ratio of factories that got supplied. * @returns array, index [0] corresponds to current month * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_ratio_goods", freevariable(true, karte_t::WORLD_GOODS_RATIO), true ); /** * Get monthly statistics of total number of transported goods. * @returns array, index [0] corresponds to current month * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_transported_goods", freevariable(true, karte_t::WORLD_TRANSPORTED_GOODS), true ); /** * Get per year statistics of total number of citizens. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_citizens", freevariable(false, karte_t::WORLD_CITIZENS), true ); /** * Get per year statistics of total city growth. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_growth", freevariable(false, karte_t::WORLD_GROWTH), true ); /** * Get per year statistics of total number of towns. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_towns", freevariable(false, karte_t::WORLD_TOWNS), true ); /** * Get per year statistics of total number of factories. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_factories", freevariable(false, karte_t::WORLD_FACTORIES), true ); /** * Get per year statistics of total number of convoys. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_convoys", freevariable(false, karte_t::WORLD_CONVOIS), true ); /** * Get per year statistics of total number of citycars. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_citycars", freevariable(false, karte_t::WORLD_CITYCARS), true ); /** * Get per year statistics of ratio transported to generated passengers. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_ratio_pax", freevariable(false, karte_t::WORLD_PAS_RATIO), true ); /** * Get per year statistics of total number of generated passengers. * @returns array, index [0] corresponds to current year * @see city_x::get_generated_pax city_x::get_transported_pax */ STATIC register_method_fv(vm, &get_world_stat, "get_year_generated_pax", freevariable(false, karte_t::WORLD_PAS_GENERATED), true ); /** * Get per year statistics of ratio transported to generated mail. * @returns array, index [0] corresponds to current year */ STATIC register_method_fv(vm, &get_world_stat, "get_year_ratio_mail", freevariable(false, karte_t::WORLD_MAIL_RATIO), true ); /** * Get per year statistics of total number of generated mail. * @returns array, index [0] corresponds to current year * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_year_generated_mail", freevariable(false, karte_t::WORLD_MAIL_GENERATED), true ); /** * Get per year statistics of ratio of factories that got supplied. * @returns array, index [0] corresponds to current year * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_year_ratio_goods", freevariable(false, karte_t::WORLD_GOODS_RATIO), true ); /** * Get per year statistics of total number of transported goods. * @returns array, index [0] corresponds to current year * @see city_x::get_generated_mail city_x::get_transported_mail */ STATIC register_method_fv(vm, &get_world_stat, "get_year_transported_goods", freevariable(false, karte_t::WORLD_TRANSPORTED_GOODS), true ); /** * @returns true if timeline play is active */ STATIC register_method(vm, &karte_t::use_timeline, "use_timeline"); /** * Returns iterator through the list of attractions on the map. * @returns iterator class. * @typemask attraction_list_x() */ STATIC register_function(vm, world_get_attraction_list, "get_attraction_list", 1, "."); /** * Returns iterator through the list of labels on the map. * @returns iterator class. * @typemask label_list_x() */ STATIC register_function(vm, world_get_label_list, "get_label_list", 1, "."); /** * Returns list of convoys on the map. * @returns convoy list * @typemask convoy_list_x() */ STATIC register_function(vm, world_get_convoy_list, "get_convoy_list", 1, "."); /** * Returns size of the map. * @typemask coord() */ STATIC register_function(vm, world_get_size, "get_size", 1, "."); end_class(vm); /** * Implements iterator to iterate through the list of all attractions on the map. * * Usage: * @code * local list = world.get_attraction_list() * // list is now of type attraction_list_x * foreach(att in list) { * ... // att is an instance of the building_x class * } * @endcode */ create_class(vm, "attraction_list_x"); /** * Meta-method to be used in foreach loops to loop over all attractions on the map. Do not call it directly. */ register_function(vm, world_attraction_list_next, "_nexti", 2, ". o|i"); /** * Meta-method to be used in foreach loops to loop over all attractions on the map. Do not call it directly. */ register_method(vm, world_attraction_list_get, "_get", true); /** * Returns number of attractions in the list. * @typemask integer() */ register_function(vm, world_get_attraction_count, "get_count", 1, "x"); end_class(vm); /** * Implements iterator to iterate through the list of all labels on the map. * * Usage: * @code * local list = world.get_label_list() * // list is now of type label_list_x * foreach(label in list) { * ... // label is an instance of the label_x class * } * @endcode */ create_class(vm, "label_list_x"); /** * Meta-method to be used in foreach loops to loop over all labels on the map. Do not call it directly. */ register_function(vm, world_label_list_next, "_nexti", 2, ". o|i"); /** * Meta-method to be used in foreach loops to loop over all labels on the map. Do not call it directly. */ register_method(vm, world_label_list_get, "_get", true); /** * Returns number of labels in the list. * @typemask integer() */ register_method(vm, world_get_label_count, "get_count", true); end_class(vm); /** * Returns pakset name as set in ground.outside.pak */ register_method(vm, get_pakset_name, "get_pakset_name"); /** * Returns simutrans version number */ register_method(vm, get_version_number, "get_version_number"); } simutrans-124.3/src/simutrans/script/api/changelog.h000066400000000000000000000173201474050137200225470ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /** @file changelog.h Documenting the timeline of api evolution */ /** @page changelog Changelog * * @section api-trunk Current trunk * * - Added @ref command_x::grid_lower, @ref command_x::grid_raise * - Added @ref settings::has_double_slopes, @ref settings::get_way_height_clearance * - Added @ref tile_x::is_crossing * - Added @ref world_x::generate_goods to generate passengers, mail or freight (scenario only) * - Added @ref change_climate_at * - Added @ref convoy_x::change_schedule * - Added tool_ids::tool_build_groundobj * - Changed building_desc_x::get_available_stations to accept wt_all * - Added @ref bridge_x, @ref tunnel_x * - Added @ref factory_x::get_fields_list, @ref world::get_label_list * - Added @ref schedule_x::current. * * @section api-123 Release 123.0 * * - Changed scripted tools: work, do_work, mark_tiles have additional parameter to send state of ctrl/shift keys * - Added @ref factory_desc_x * - Added @ref way_x::get_max_speed * - Added @ref wayobj_desc_x, @ref wayobj_x, @ref command_x::build_wayobj to work with way-objects * - Added @ref factory_x::get_raw_name * - Added @ref tree_desc_x::get_price, @ref command_x::slope_get_price * - Added @ref way_x::get_transported_goods, @ref way_x::get_convoys_passed * - Added @ref tile_x::get_way, @ref tile_x::get_depot * - Added @ref get_pakset_name, @ref player_x::get_type * * @section api-122 Release 122.0 * * - Feature: scripted tools * - Added @ref debug::pause, @ref debug::set_pause_on_error * - Added more tool ids * - Added @ref convoy_x::is_waiting, @ref convoy_x::is_loading * - Added @ref rules::gui_needs_update * - Added @ref convoy_x::get_tile_length * - Added @ref settings::get_pay_for_total_distance_mode, @ref settings::get_drive_on_left * - Added @ref halt_x::get_connections * - Added @ref command_x::can_set_slope * - Added @ref halt_x::get_halt * - Changed possible direction parameter of @ref command_x::build_station (useful for flat docks) * - Added @ref depot_x::get_depot_list * - Added @ref vehicle_desc_x::needs_electrification * - Added @ref command_x::build_road * - Added fields: @ref field_x * - Added powerlines: @ref powerline_x, @ref transformer_x, @ref factory_x::get_transformer, @ref factory_x::is_transformer_connected * * @section api-121 Release 121.0 * * - Added functions to mark tiles, see @ref tile_x::mark * - Added @ref convoy_x::is_schedule_editor_open * * @section api-120-3 Release 120.3 * * - Changed enable scenario scripts to open info window also on clients, see @ref gui::open_info_win_client * - Added sign_x::can_pass * - Added methods is_valid to check whether in-game object is still present, see @ref ingame_object * - Added tile_x::can_remove_all_objects * - Added @ref coord_to_dir, @ref coord.to_dir, @ref dir.to_coord * - Added @ref simple_heap_x, @ref way_planner_x, @ref bridge_planner_x * - Added map_object_x::is_marked * - Added gui::open_info_win_at * - Added ::is_convoy_allowed * - Added convoy_x::is_in_depot * - Added scriptable hyperlinks in scenario info window * - Added @ref slope * - Added functions to build stuff: command_x::build_way, command_x::build_depot, command_x::build_station, command_x::build_bridge, command_x::build_bridge_at, command_x::set_slope, command_x::restore_slope * - Added sign_x, sign_desc_x, command_x::build_sign_at * - Added line_x::destroy * * @section api-120-2-2 Release 120.2.2 * * - Added map_object_x::mark and unmark * * @section api-120-2 Release 120.2 * * - Feature: scripted AI players * - Feature: script calls can be suspended and waken up, less strict checks of 'script take too long' * - Feature: add commands to modify game state, see @ref game_cmd * - Added @ref climates, square_x::get_climate, world::get_size * - Added new classes command_x, vehicle_desc_x, tunnel_desc_x, bridge_desc_x * - Added tool_ids::tool_set_climate, tool_ids::tool_change_water_height * - Added string::toalnum (converts strings to strings that can be used as table keys) * - Changed gui::add_message to take additional player_x parameter * * @section api-120-1-2 Release 120.1.2 * * - Added label_x::get_text, tile_x::get_text * - Added factory_x::get_halt_list, halt_x::get_tile_list, halt_x::get_factory_list, square_x::get_halt_list * - Added world.get_player * - Removed player_x::is_active * * @section api-120-1 Release 120.1 * * - Added depot_x, depot_x::get_convoy_list * - Added line_x::get_waytype, tile_x::get_slope * - Added factory_production_x::get_base_production, factory_production_x::get_base_consumption, factory_x::get_tile_list * - Added coord::href, coord3d::href * - Added label_x, tile_x::remove_object * - Added ::get_debug_text, debug::get_forbidden_text * - Added operators and conversion to string to ::coord and ::coord3d classes * - Added ::coord_to_string, ::coord3d_to_string * - Added settings::get_station_coverage, settings::get_passenger_factor * - Added settings::get_factory_worker_radius, settings::get_factory_worker_minimum_towns, settings::get_factory_worker_maximum_towns * - Added settings::avoid_overcrowding, settings::no_routing_over_overcrowding, settings::separate_halt_capacities * * @section api-120-0-1 Release 120.0.1 * * - Added building_desc_x::get_building_list, building_desc_x::get_headquarter_level * - Added factory_production_x::get_in_transit * * @section api-120-0 Release 120.0 * * - Added line_x, line_list_x * - Deprecated get_convoy_list() * - Added world::get_convoy_list, halt_x::get_convoy_list * - Added @ref scenario.api to manage backward compatibility of scripts with the changing api * - Added ::include * - Changed return type of world::get_time to time_ticks_x * - Added building_x::is_same_building. * - Added attraction_list_x, world::get_attraction_list * - Added ::new_month, ::new_year * - Added halt_list_x * - Added possibility to attach scenario to an already running game, set map.file to "". * - Added building_desc_x::get_type, convoy_x::get_distance_traveled_total, obj_desc_time_x::is_available * - Added obj_desc_time_x, obj_desc_transport_x, building_desc_x, tree_desc_x, way_desc_x * - Added time_x * - Added @ref way_system_types * - Added square_x::get_player_halt * - Added way_x::get_dirs,way_x::get_dirs_masked * - Deprecated square_x::get_halt, use square_x::get_player_halt or tile_x::get_halt instead! * * @section api-112-3 Release 112.3 * * - Added good_desc_list_x * - Added tile_x::is_bridge, tile_x::is_empty, tile_x::is_ground, tile_x::is_tunnel, tile_x::is_water * - Added tile_x::has_way, tile_x::has_ways, tile_x::has_two_ways * - Added map_objects, map_object_x, building_x, tree_x, way_x * - Added iterator tile_x::objects to loop over all objects on the tile * - Added ::dir * - Added tile_x::get_way_dirs, tile_x::get_way_dirs_masked, tile_x::get_neighbour * * @section api-112-2 Release 112.2 * * - Added rules::forbid_way_tool_cube, rules::allow_way_tool_cube * - Added settings::get_start_time * - Added player_x::book_cash * - Added settings::get_traffic_level, settings::set_traffic_level, tool_set_traffic_level * - Added gui::add_message, gui::add_message_at * - Added hyperlinks to scenario window tabs and map positions are accepted in scenario info window * - Added ::double_to_string, ::integer_to_string, ::money_to_string, ::get_month_name * - Added factory_list_x * - Added factory_x::get_name * - Added halt_x::get_name, halt_x::get_owner, halt_x::accepts_good * - Added player_x::is_active, world::remove_player * - Added schedule_x, schedule_entry_x, ::is_schedule_allowed * - Added halt_x::is_connected * * @section api-112-1 Releases 112.0 and 112.1 * * Initial release and minor changes. * */ simutrans-124.3/src/simutrans/script/api/export.awk000066400000000000000000000110661474050137200224750ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Implements filter to automatically generate documentation of # the interface to squirrel. BEGIN { within_doxygen_comment = 0 within_class = "" param_count = 0 returns = "void" indent = "" within_apidoc = 0 mask = "" ai_only = 0 } # match beginning of SQAPI_DOC block /^#ifdef.*SQAPI_DOC/ { within_sqapi_doc = 1 } # match end of SQAPI_DOC block /^#(endif|else)/ { if (within_sqapi_doc == 1) { within_sqapi_doc = 0 param_count = 0 delete params delete ptypes mask = "" returns = "void" } } # ignore preprocessor directives /^#/ { next } /ingroup.*ai_only/ { ai_only = 1 } function split_params(string) { count = split(string, types, / *, */) for(i=1; i<=count;i++) { ptypes[i] = types[i]; } } /@typemask/ { match($0, "@typemask *(.*)\\((.*)\\)", data) returns = data[1] split_params(data[2]) next } # match beginning of doxgen comment block /\/\*\*/ { within_doxygen_comment = 1 } # print everything in a doxygen comment block # and everything in a SQAPI_DOC block { if (within_doxygen_comment==1) { print gensub( /^[[:space:]]*([ \\/])\\*/, indent "\\1", 1) } else if (within_sqapi_doc == 1) { print gensub( /^[[:space:]]*(.*)/, indent "\\1", 1) } } # match end of doxygen block /\*\// { within_doxygen_comment = 0 } # print doxygen brief commands, also //@ /\/\/[\/@]/ { if (within_doxygen_comment!=1 && within_sqapi_doc != 1) { print gensub( /^[[:space:]]*(\\.*)/, indent "\\1", 1) } } # beginning of class definition # begin_class("factory_x", "extend_get"); /(begin|create)_.*class/ { # ignore class name inside error messages as in 'dbg->error("create_class", "failed ..")' if ( /dbg->(message|warning|error|fatal)/ ) { next } # class with parent class if ( /_class[^"]*"([^"]*)"[^"]*"([^"]*)".*/ ) { match($0, /_class[^"]*"([^"]*)"[^"]*"([^"]*)".*/, data) if (mode == "sq") print "class " data[1] " extends " data[2] " {" else { print "class " data[1] " : public " data[2] " {" print "public:" } } # class without parent class else if ( /_class[^"]*"([^"]*)"/ ) { match($0, /_class[^"]*"([^"]*)"/, data) if (mode == "sq") print "class " data[1] " {" else { print "class " data[1] " {" print "public:" } } within_class = data[1] indent = "\t" param_count = 0 delete params delete ptypes } /end_.*class/ { if (mode == "sq") print "}" else print "};" within_class = "" indent = "" } # beginning of enum constant definition /begin_enum/ { match($0, /^[[:space:]]*begin_enum[^"]*"([^"]*)"/, data) if (mode == "sq") { #print "class " data[1] " {" } else { print "enum " data[1] " {" } indent = "\t" } # end of enum /end_enum/ { if (mode == "sq") { #print "class " data[1] " {" } else { print "};" } indent = "" } # @param names /@param/ { if (within_doxygen_comment==1) { param_count++ params[param_count] = $3 } } # now the actual methods # first string enclosed by ".." is method name /register_function/ || /register_method/ || /register_local_method/{ match($0, /"([^"]*)"/, data) method = data[1] if (ai_only == 1) { suffix = "ai" } else { suffix = "scenario" } # check for param types if (ai_only && ((within_class "::" method) in export_types_ai)) { mask = export_types_ai[(within_class "::" method)] } else if ((within_class "::" method) in export_types_scenario) { mask = export_types_scenario[(within_class "::" method)] } if (mask != "") { match(mask, " *(.*)\\((.*)\\)", data) returns = data[1] split_params(data[2]) for (t in ptypes) { if (!(t in params)) { params[t]="" param_count++ } } } # build the output fname = "" if ( /STATIC/ ) { fname = fname "static " } if (mode == "sq") { if (method != "constructor") { fname = fname "function " } fname = fname method "(" } else { if (method ~ /^_/) { print "private:" } if (method == "constructor") { fname = fname within_class "(" } else { fname = fname returns " " method "(" } } for (param = 1; param <= param_count; param++) { if (mode != "sq") { if (!(param in ptypes)) ptypes[param] = "any_x" fname = fname ptypes[param] } if (params[param] != "") { fname = fname " " params[param] } if (param < param_count) fname = fname ", " } fname = fname ");" print indent fname if ( (mode == "cpp") && (method ~ /^_/)) { print "public:" } param_count = 0 delete params delete ptypes mask = "" returns = "void" ai_only = 0 } # enum constants /enum_slot/ { match($0, /"([^"]*)"/, data) name = data[1] print indent name "," } simutrans-124.3/src/simutrans/script/api/export_desc.cc000066400000000000000000000023551474050137200232770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "export_desc.h" #include "../script.h" #include "../api_class.h" #include "../api_function.h" #include "../../tpl/vector_tpl.h" #include "../../utils/plainstring.h" using namespace script_api; static vector_tpl registered_desc_functions; SQInteger get_desc_pointer(HSQUIRRELVM vm) { void *tag = NULL; // get type tag of class sq_gettypetag(vm, 1, &tag); plainstring name = param::get(vm, 2); if (tag && registered_desc_functions.is_contained((GETDESCFUNC)tag) ) { // call method const void *desc = ((GETDESCFUNC)tag)(name.c_str()); // set userpointer of class instance sq_setinstanceup(vm, 1, const_cast(desc) ); return 0; } return -1; } void begin_desc_class(HSQUIRRELVM vm, const char* name, const char* base, GETDESCFUNC func) { SQInteger res = create_class(vm, name, base); assert( SQ_SUCCEEDED(res) ); (void)res; // store method to retrieve desc in typetag pointer sq_settypetag(vm, -1, (void*)func); registered_desc_functions.append_unique( func ); // register constructor register_function(vm, get_desc_pointer, "constructor", 2, "xs"); // now functions can be registered } simutrans-124.3/src/simutrans/script/api/export_desc.h000066400000000000000000000014421474050137200231350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_EXPORT_DESC_H #define SCRIPT_API_EXPORT_DESC_H #include "../../../squirrel/squirrel.h" /** @file export_desc.h Helper functions to export desc-classes */ /** * Creates class @p name in top of the stack. * * Defines constructor. Call has to be complemented by call to end_class. * @param name name of new class * @param parent name of base class (or NULL) * @param func function pointer to a function that retrieves pointer-to-desc by name */ void begin_desc_class(HSQUIRRELVM vm, const char* name, const char* parent, const void* (*func)(const char*)); /// Function signature to retrieve desc-pointer from name typedef const void* (*GETDESCFUNC)(const char*); #endif simutrans-124.3/src/simutrans/script/api/filter_cpp.sh000077500000000000000000000003521474050137200231320ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Filter for Doxygen input files gawk -f squirrel_types_scenario.awk -f squirrel_types_ai.awk -f export.awk -v mode=cpp $1 simutrans-124.3/src/simutrans/script/api/filter_sq.sh000077500000000000000000000003621474050137200227740ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Filter for Doxygen source code browsing gawk -f squirrel_types_scenario.awk -f squirrel_types_ai.awk -f export.awk -v mode=sq $1 simutrans-124.3/src/simutrans/script/api/get_next.cc000066400000000000000000000013341474050137200225710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "get_next.h" SQInteger generic_get_next_f(HSQUIRRELVM vm, uint32 count, uint32 F(uint32) ) { SQInteger index; if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &index))) { // now increase index if ( index >= 0 ) { // call the custom function uint32 new_index = F(index); if (new_index < count) { sq_pushinteger(vm, new_index); return 1; } } } else { if ( count>0 ) { sq_pushinteger(vm, 0); return 1; } } sq_pushnull(vm); return 1; } static uint32 inc(uint32 i) { return i+1; } SQInteger generic_get_next(HSQUIRRELVM vm, uint32 count) { return generic_get_next_f(vm, count, inc); } simutrans-124.3/src/simutrans/script/api/get_next.h000066400000000000000000000014501474050137200224320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_GET_NEXT_H #define SCRIPT_API_GET_NEXT_H #include "../../simtypes.h" #include "../../../squirrel/squirrel.h" /** * Implements custom function to realize foreach-iterators. * Can be used to export _nexti method. * Takes argument of _nexti from top of the stack. * Pushes null or the new index to the stack. * @pre assumed to be bound to _nexti meta method. * @param count total number of elements in iterated list */ SQInteger generic_get_next(HSQUIRRELVM vm, uint32 count); /** * Same as generic_get_next. * @param F custom function to increase index. Takes old index as parameter. */ SQInteger generic_get_next_f(HSQUIRRELVM vm, uint32 count, uint32 F(uint32) ); #endif simutrans-124.3/src/simutrans/script/api/squirrel_types_ai.awk000066400000000000000000000652121474050137200247210ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # file used to generate doxygen documentation of squirrel API # needs to be copied to trunk/script/api BEGIN { export_types_ai["city_list_x::_get"] = "city_x(integer)" export_types_ai["city_x::is_valid"] = "bool()" export_types_ai["city_x::get_name"] = "string()" export_types_ai["city_x::set_name"] = "void(string)" export_types_ai["city_x::get_citizens"] = "array()" export_types_ai["city_x::get_growth"] = "array()" export_types_ai["city_x::get_buildings"] = "array()" export_types_ai["city_x::get_citycars"] = "array()" export_types_ai["city_x::get_transported_pax"] = "array()" export_types_ai["city_x::get_generated_pax"] = "array()" export_types_ai["city_x::get_transported_mail"] = "array()" export_types_ai["city_x::get_generated_mail"] = "array()" export_types_ai["city_x::get_year_citizens"] = "array()" export_types_ai["city_x::get_year_growth"] = "array()" export_types_ai["city_x::get_year_buildings"] = "array()" export_types_ai["city_x::get_year_citycars"] = "array()" export_types_ai["city_x::get_year_transported_pax"] = "array()" export_types_ai["city_x::get_year_generated_pax"] = "array()" export_types_ai["city_x::get_year_transported_mail"] = "array()" export_types_ai["city_x::get_year_generated_mail"] = "array()" export_types_ai["city_x::get_citygrowth_enabled"] = "bool()" export_types_ai["city_x::get_pos"] = "coord()" export_types_ai["city_x::get_pos_nw"] = "coord()" export_types_ai["city_x::get_pos_se"] = "coord()" export_types_ai["city_x::change_size"] = "string(integer)" export_types_ai["city_x::set_citygrowth_enabled"] = "void(bool)" export_types_ai["::get_ops_total"] = "integer()" export_types_ai["::get_ops_remaining"] = "integer()" export_types_ai["debug::pause"] = "bool()" export_types_ai["debug::is_paused"] = "bool()" export_types_ai["debug::set_pause_on_error"] = "void(bool)" export_types_ai["convoy_x::is_valid"] = "bool()" export_types_ai["convoy_x::needs_electrification"] = "bool()" export_types_ai["convoy_x::get_name"] = "string()" export_types_ai["convoy_x::set_name"] = "void(string)" export_types_ai["convoy_x::get_pos"] = "coord3d()" export_types_ai["convoy_x::get_owner"] = "player_x()" export_types_ai["convoy_x::get_goods_catg_index"] = "array()" export_types_ai["convoy_x::get_waytype"] = "way_types()" export_types_ai["convoy_x::get_schedule"] = "schedule_x()" export_types_ai["convoy_x::get_capacity"] = "array()" export_types_ai["convoy_x::get_transported_goods"] = "array()" export_types_ai["convoy_x::get_revenue"] = "array()" export_types_ai["convoy_x::get_cost"] = "array()" export_types_ai["convoy_x::get_profit"] = "array()" export_types_ai["convoy_x::get_traveled_distance"] = "array()" export_types_ai["convoy_x::get_way_tolls"] = "array()" export_types_ai["convoy_x::get_distance_traveled_total"] = "integer()" export_types_ai["convoy_x::get_line"] = "line_x()" export_types_ai["convoy_x::set_line"] = "void(player_x, line_x)" export_types_ai["convoy_x::get_vehicles"] = "array()" export_types_ai["convoy_x::get_speed"] = "integer()" export_types_ai["convoy_x::get_loading_limit"] = "integer()" export_types_ai["convoy_x::get_loading_level"] = "integer()" export_types_ai["convoy_x::get_home_depot"] = "coord3d()" export_types_ai["convoy_x::has_obsolete_vehicles"] = "bool()" export_types_ai["convoy_x::toggle_withdraw"] = "void(player_x)" export_types_ai["convoy_x::is_withdrawn"] = "bool()" export_types_ai["convoy_x::is_in_depot"] = "bool()" export_types_ai["convoy_x::is_waiting"] = "bool()" export_types_ai["convoy_x::is_loading"] = "bool()" export_types_ai["convoy_x::destroy"] = "void(player_x)" export_types_ai["convoy_x::is_schedule_editor_open"] = "bool()" export_types_ai["convoy_x::get_tile_length"] = "integer()" export_types_ai["convoy_x::change_schedule"] = "void(player_x, schedule_x)" export_types_ai["convoy_x::calc_max_speed"] = "integer(integer, integer, integer)" export_types_ai["convoy_x::speed_to_tiles_per_month"] = "integer(integer)" export_types_ai["factory_x::is_valid"] = "bool()" export_types_ai["factory_x::get_consumers"] = "array()" export_types_ai["factory_x::get_suppliers"] = "array()" export_types_ai["factory_x::get_name"] = "string()" export_types_ai["factory_x::get_raw_name"] = "string()" export_types_ai["factory_x::set_name"] = "void(string)" export_types_ai["factory_x::get_production"] = "array()" export_types_ai["factory_x::get_power"] = "array()" export_types_ai["factory_x::get_boost_electric"] = "array()" export_types_ai["factory_x::get_boost_pax"] = "array()" export_types_ai["factory_x::get_boost_mail"] = "array()" export_types_ai["factory_x::get_pax_generated"] = "array()" export_types_ai["factory_x::get_pax_departed"] = "array()" export_types_ai["factory_x::get_pax_arrived"] = "array()" export_types_ai["factory_x::get_mail_generated"] = "array()" export_types_ai["factory_x::get_mail_departed"] = "array()" export_types_ai["factory_x::get_mail_arrived"] = "array()" export_types_ai["factory_x::get_tile_list"] = "array()" export_types_ai["factory_x::get_fields_list"] = "array()" export_types_ai["factory_x::get_halt_list"] = "array()" export_types_ai["factory_x::is_transformer_connected"] = "bool()" export_types_ai["factory_x::get_transformer"] = "powerline_x()" export_types_ai["factory_x::get_field_count"] = "integer()" export_types_ai["factory_x::get_min_field_count"] = "integer()" export_types_ai["factory_x::get_desc"] = "factory_desc_x()" export_types_ai["factory_production_x::get_storage"] = "array()" export_types_ai["factory_production_x::get_received"] = "array()" export_types_ai["factory_production_x::get_consumed"] = "array()" export_types_ai["factory_production_x::get_in_transit"] = "array()" export_types_ai["factory_production_x::get_delivered"] = "array()" export_types_ai["factory_production_x::get_produced"] = "array()" export_types_ai["factory_production_x::get_consumption_factor"] = "integer()" export_types_ai["factory_production_x::get_production_factor"] = "integer()" export_types_ai["obj_desc_x::get_name"] = "string()" export_types_ai["obj_desc_x::is_equal"] = "bool(obj_desc_x)" export_types_ai["obj_desc_x::is_valid"] = "bool()" export_types_ai["obj_desc_time_x::get_intro_date"] = "time_x()" export_types_ai["obj_desc_time_x::get_retire_date"] = "time_x()" export_types_ai["obj_desc_time_x::is_future"] = "bool(time_x)" export_types_ai["obj_desc_time_x::is_retired"] = "bool(time_x)" export_types_ai["obj_desc_time_x::is_available"] = "bool(time_x)" export_types_ai["obj_desc_transport_x::get_maintenance"] = "integer()" export_types_ai["obj_desc_transport_x::get_cost"] = "integer()" export_types_ai["obj_desc_transport_x::get_waytype"] = "way_types()" export_types_ai["obj_desc_transport_x::get_topspeed"] = "integer()" export_types_ai["vehicle_desc_x::can_be_first"] = "bool()" export_types_ai["vehicle_desc_x::can_be_last"] = "bool()" export_types_ai["vehicle_desc_x::get_successors"] = "array()" export_types_ai["vehicle_desc_x::get_predecessors"] = "array()" export_types_ai["vehicle_desc_x::get_available_vehicles"] = "array(way_types)" export_types_ai["vehicle_desc_x::get_power"] = "integer()" export_types_ai["vehicle_desc_x::needs_electrification"] = "bool()" export_types_ai["vehicle_desc_x::get_freight"] = "good_desc_x()" export_types_ai["vehicle_desc_x::get_capacity"] = "integer()" export_types_ai["vehicle_desc_x::get_running_cost"] = "integer()" export_types_ai["vehicle_desc_x::get_maintenance"] = "integer()" export_types_ai["vehicle_desc_x::get_weight"] = "integer()" export_types_ai["vehicle_desc_x::get_length"] = "integer()" export_types_ai["vehicle_desc_x::is_coupling_allowed"] = "bool(vehicle_desc_x, vehicle_desc_x)" export_types_ai["tree_desc_x::get_price"] = "integer()" export_types_ai["building_desc_x::is_attraction"] = "bool()" export_types_ai["building_desc_x::get_maintenance"] = "integer()" export_types_ai["building_desc_x::get_cost"] = "integer()" export_types_ai["building_desc_x::get_capacity"] = "integer()" export_types_ai["building_desc_x::can_be_built_underground"] = "bool()" export_types_ai["building_desc_x::can_be_built_aboveground"] = "bool()" export_types_ai["building_desc_x::enables_pax"] = "bool()" export_types_ai["building_desc_x::enables_mail"] = "bool()" export_types_ai["building_desc_x::enables_freight"] = "bool()" export_types_ai["building_desc_x::get_type"] = "building_desc_x::building_type()" export_types_ai["building_desc_x::get_waytype"] = "way_types()" export_types_ai["building_desc_x::get_headquarter_level"] = "integer()" export_types_ai["building_desc_x::get_building_list"] = "array(building_desc_x::building_type)" export_types_ai["building_desc_x::get_available_stations"] = "array(building_desc_x::building_type, way_types, good_desc_x)" export_types_ai["building_desc_x::is_terminus"] = "bool()" export_types_ai["factory_desc_x::get_name"] = "string()" export_types_ai["factory_desc_x::get_building_desc"] = "building_desc_x()" export_types_ai["factory_desc_x::is_electricity_producer"] = "bool()" export_types_ai["factory_desc_x::get_productivity_base"] = "integer()" export_types_ai["factory_desc_x::get_productivity_range"] = "integer()" export_types_ai["factory_desc_x::get_list"] = "table()" export_types_ai["way_desc_x::has_double_slopes"] = "bool()" export_types_ai["way_desc_x::get_system_type"] = "way_system_types()" export_types_ai["way_desc_x::get_available_ways"] = "array(way_types, way_system_types)" export_types_ai["tunnel_desc_x::get_available_tunnels"] = "array(way_types)" export_types_ai["bridge_desc_x::has_double_ramp"] = "bool()" export_types_ai["bridge_desc_x::has_double_start"] = "bool()" export_types_ai["bridge_desc_x::get_max_length"] = "integer()" export_types_ai["bridge_desc_x::get_max_height"] = "integer()" export_types_ai["bridge_desc_x::get_available_bridges"] = "array(way_types)" export_types_ai["good_desc_x::get_catg_index"] = "integer()" export_types_ai["good_desc_x::is_interchangeable"] = "bool(good_desc_x)" export_types_ai["good_desc_x::get_weight_per_unit"] = "integer()" export_types_ai["good_desc_x::get_metric"] = "string()" export_types_ai["good_desc_x::calc_revenue"] = "integer(way_types, integer)" export_types_ai["sign_desc_x::is_one_way"] = "bool()" export_types_ai["sign_desc_x::is_private_way"] = "bool()" export_types_ai["sign_desc_x::is_traffic_light"] = "bool()" export_types_ai["sign_desc_x::is_choose_sign"] = "bool()" export_types_ai["sign_desc_x::is_signal"] = "bool()" export_types_ai["sign_desc_x::is_pre_signal"] = "bool()" export_types_ai["sign_desc_x::is_priority_signal"] = "bool()" export_types_ai["sign_desc_x::is_longblock_signal"] = "bool()" export_types_ai["sign_desc_x::is_end_choose_signal"] = "bool()" export_types_ai["sign_desc_x::get_available_signs"] = "array(way_types)" export_types_ai["wayobj_desc_x::is_overhead_line"] = "bool()" export_types_ai["wayobj_desc_x::get_available_wayobjs"] = "array(way_types)" export_types_ai["gui::add_message_at"] = "string(player_x, string, coord3d)" export_types_ai["halt_x::is_valid"] = "bool()" export_types_ai["halt_x::get_name"] = "string()" export_types_ai["halt_x::set_name"] = "void(string)" export_types_ai["halt_x::get_owner"] = "player_x()" export_types_ai["halt_x::_cmp"] = "integer(halt_x)" export_types_ai["halt_x::is_connected"] = "integer(halt_x, good_desc_x)" export_types_ai["halt_x::accepts_good"] = "bool(good_desc_x)" export_types_ai["halt_x::get_arrived"] = "array()" export_types_ai["halt_x::get_departed"] = "array()" export_types_ai["halt_x::get_waiting"] = "array()" export_types_ai["halt_x::get_happy"] = "array()" export_types_ai["halt_x::get_unhappy"] = "array()" export_types_ai["halt_x::get_noroute"] = "array()" export_types_ai["halt_x::get_convoys"] = "array()" export_types_ai["halt_x::get_walked"] = "array()" export_types_ai["halt_x::get_tile_list"] = "array()" export_types_ai["halt_x::get_factory_list"] = "array()" export_types_ai["halt_x::get_freight_to_dest"] = "integer(good_desc_x, coord)" export_types_ai["halt_x::get_freight_to_halt"] = "integer(good_desc_x, halt_x)" export_types_ai["halt_x::get_capacity"] = "integer(good_desc_x)" export_types_ai["halt_x::get_connections"] = "array(good_desc_x)" export_types_ai["halt_x::get_halt"] = "halt_x(coord3d, player_x)" export_types_ai["line_x::is_valid"] = "bool()" export_types_ai["line_x::get_name"] = "string()" export_types_ai["line_x::set_name"] = "void(string)" export_types_ai["line_x::get_owner"] = "player_x()" export_types_ai["line_x::get_schedule"] = "schedule_x()" export_types_ai["line_x::get_goods_catg_index"] = "array()" export_types_ai["line_x::get_capacity"] = "array()" export_types_ai["line_x::get_transported_goods"] = "array()" export_types_ai["line_x::get_convoy_count"] = "array()" export_types_ai["line_x::get_revenue"] = "array()" export_types_ai["line_x::get_cost"] = "array()" export_types_ai["line_x::get_profit"] = "array()" export_types_ai["line_x::get_traveled_distance"] = "array()" export_types_ai["line_x::get_way_tolls"] = "array()" export_types_ai["line_x::get_waytype"] = "way_types()" export_types_ai["line_x::change_schedule"] = "void(player_x, schedule_x)" export_types_ai["line_x::destroy"] = "void(player_x)" export_types_ai["map_object_x::is_valid"] = "bool()" export_types_ai["map_object_x::get_owner"] = "player_x()" export_types_ai["map_object_x::get_name"] = "string()" export_types_ai["map_object_x::get_waytype"] = "way_types()" export_types_ai["map_object_x::get_pos"] = "coord3d()" export_types_ai["map_object_x::is_removable"] = "string(player_x)" export_types_ai["map_object_x::get_type"] = "map_objects()" export_types_ai["map_object_x::mark"] = "void()" export_types_ai["map_object_x::unmark"] = "void()" export_types_ai["map_object_x::is_marked"] = "bool()" export_types_ai["tree_x::get_age"] = "integer()" export_types_ai["tree_x::get_desc"] = "tree_desc_x()" export_types_ai["building_x::get_factory"] = "factory_x()" export_types_ai["building_x::get_city"] = "city_x()" export_types_ai["building_x::is_townhall"] = "bool()" export_types_ai["building_x::is_headquarter"] = "bool()" export_types_ai["building_x::is_monument"] = "bool()" export_types_ai["building_x::get_passenger_level"] = "integer()" export_types_ai["building_x::get_mail_level"] = "integer()" export_types_ai["building_x::get_desc"] = "building_desc_x()" export_types_ai["building_x::get_tile_list"] = "array()" export_types_ai["building_x::is_same_building"] = "bool(building_x)" export_types_ai["depot_x::append_vehicle"] = "void(player_x, convoy_x, vehicle_desc_x)" export_types_ai["depot_x::start_convoy"] = "void(player_x, convoy_x)" export_types_ai["depot_x::start_all_convoys"] = "void(player_x)" export_types_ai["depot_x::get_convoy_list"] = "array()" export_types_ai["depot_x::get_depot_list"] = "array(player_x, way_types)" export_types_ai["way_x::has_sidewalk"] = "bool()" export_types_ai["way_x::is_electrified"] = "bool()" export_types_ai["way_x::has_sign"] = "bool()" export_types_ai["way_x::has_signal"] = "bool()" export_types_ai["way_x::has_wayobj"] = "bool()" export_types_ai["way_x::is_crossing"] = "bool()" export_types_ai["way_x::get_desc"] = "way_desc_x()" export_types_ai["way_x::get_max_speed"] = "integer()" export_types_ai["way_x::get_transported_goods"] = "array()" export_types_ai["way_x::get_convoys_passed"] = "array()" export_types_ai["label_x::create"] = "string(coord, player_x, string)" export_types_ai["label_x::set_text"] = "void(string)" export_types_ai["label_x::get_text"] = "string()" export_types_ai["sign_x::get_desc"] = "sign_desc_x()" export_types_ai["sign_x::can_pass"] = "bool(player_x)" export_types_ai["powerline_x::is_connected"] = "bool(powerline_x)" export_types_ai["powerline_x::get_factory"] = "factory_x()" export_types_ai["field_x::is_deletable"] = "bool()" export_types_ai["field_x::get_factory"] = "factory_x()" export_types_ai["wayobj_x::get_desc"] = "wayobj_desc_x()" export_types_ai["bridge_x::get_desc"] = "bridge_desc_x()" export_types_ai["tunnel_x::get_desc"] = "tunnel_desc_x()" export_types_ai["player_x::is_valid"] = "bool()" export_types_ai["player_x::get_headquarter_level"] = "integer()" export_types_ai["player_x::get_headquarter_pos"] = "coord()" export_types_ai["player_x::get_name"] = "string()" export_types_ai["player_x::set_name"] = "void(string)" export_types_ai["player_x::get_construction"] = "array()" export_types_ai["player_x::get_vehicle_maint"] = "array()" export_types_ai["player_x::get_new_vehicles"] = "array()" export_types_ai["player_x::get_income"] = "array()" export_types_ai["player_x::get_maintenance"] = "array()" export_types_ai["player_x::get_assets"] = "array()" export_types_ai["player_x::get_cash"] = "array()" export_types_ai["player_x::get_net_wealth"] = "array()" export_types_ai["player_x::get_profit"] = "array()" export_types_ai["player_x::get_operating_profit"] = "array()" export_types_ai["player_x::get_margin"] = "array()" export_types_ai["player_x::get_transported"] = "array()" export_types_ai["player_x::get_powerline"] = "array()" export_types_ai["player_x::get_transported_pax"] = "array()" export_types_ai["player_x::get_transported_mail"] = "array()" export_types_ai["player_x::get_transported_goods"] = "array()" export_types_ai["player_x::get_convoys"] = "array()" export_types_ai["player_x::get_way_tolls"] = "array()" export_types_ai["player_x::get_current_cash"] = "float()" export_types_ai["player_x::get_current_net_wealth"] = "integer()" export_types_ai["player_x::get_current_maintenance"] = "integer()" export_types_ai["player_x::create_line"] = "void(way_types)" export_types_ai["player_x::get_type"] = "integer()" export_types_ai["schedule_entry_x::constructor"] = "void(coord3d, integer, integer)" export_types_ai["coord3d::get_halt"] = "halt_x(player_x)" export_types_ai["settings::get_industry_increase_every"] = "integer()" export_types_ai["settings::set_industry_increase_every"] = "void(integer)" export_types_ai["settings::get_traffic_level"] = "integer()" export_types_ai["settings::set_traffic_level"] = "void(integer)" export_types_ai["settings::get_start_time"] = "time_x()" export_types_ai["settings::get_station_coverage"] = "integer()" export_types_ai["settings::get_passenger_factor"] = "integer()" export_types_ai["settings::get_factory_worker_radius"] = "integer()" export_types_ai["settings::get_factory_worker_minimum_towns"] = "integer()" export_types_ai["settings::get_factory_worker_maximum_towns"] = "integer()" export_types_ai["settings::avoid_overcrowding"] = "bool()" export_types_ai["settings::no_routing_over_overcrowding"] = "bool()" export_types_ai["settings::separate_halt_capacities"] = "bool()" export_types_ai["settings::obsolete_vehicles_allowed"] = "bool()" export_types_ai["settings::get_max_road_convoi_length"] = "integer()" export_types_ai["settings::get_max_rail_convoi_length"] = "integer()" export_types_ai["settings::get_max_ship_convoi_length"] = "integer()" export_types_ai["settings::get_max_air_convoi_length"] = "integer()" export_types_ai["settings::get_drive_on_left"] = "bool()" export_types_ai["settings::get_way_height_clearance"] = "integer()" export_types_ai["settings::has_double_slopes"] = "bool()" export_types_ai["settings::get_pay_for_total_distance_mode"] = "integer()" export_types_ai["settings::get_underground_view_level"] = "integer()" export_types_ai["dir::is_single"] = "bool(dir)" export_types_ai["dir::is_twoway"] = "bool(dir)" export_types_ai["dir::is_threeway"] = "bool(dir)" export_types_ai["dir::is_curve"] = "bool(dir)" export_types_ai["dir::is_straight"] = "bool(dir)" export_types_ai["dir::double"] = "dir(dir)" export_types_ai["dir::backward"] = "dir(dir)" export_types_ai["dir::to_slope"] = "slope(dir)" export_types_ai["slope::to_dir"] = "dir(slope)" export_types_ai["::translate"] = "string(string)" export_types_ai["::double_to_string"] = "string(float, integer)" export_types_ai["::integer_to_string"] = "string(integer)" export_types_ai["::money_to_string"] = "string(integer)" export_types_ai["::coord_to_string"] = "string(coord)" export_types_ai["::coord3d_to_string"] = "string(coord3d)" export_types_ai["::get_month_name"] = "string(integer)" export_types_ai["::difftick_to_string"] = "string(integer)" export_types_ai["tile_x::is_valid"] = "bool()" export_types_ai["tile_x::find_object"] = "map_object_x(map_objects)" export_types_ai["tile_x::remove_object"] = "string(player_x, map_objects)" export_types_ai["tile_x::get_halt"] = "halt_x()" export_types_ai["tile_x::is_water"] = "bool()" export_types_ai["tile_x::is_bridge"] = "bool()" export_types_ai["tile_x::is_tunnel"] = "bool()" export_types_ai["tile_x::is_empty"] = "bool()" export_types_ai["tile_x::is_ground"] = "bool()" export_types_ai["tile_x::is_crossing"] = "bool()" export_types_ai["tile_x::get_slope"] = "slope()" export_types_ai["tile_x::get_text"] = "string()" export_types_ai["tile_x::has_way"] = "bool(way_types)" export_types_ai["tile_x::has_ways"] = "bool()" export_types_ai["tile_x::has_two_ways"] = "bool()" export_types_ai["tile_x::get_way"] = "way_x(way_types)" export_types_ai["tile_x::get_neighbour"] = "tile_x(way_types, dir)" export_types_ai["tile_x::get_depot"] = "depot_x()" export_types_ai["tile_x::can_remove_all_objects"] = "string(player_x)" export_types_ai["tile_x::is_marked"] = "bool()" export_types_ai["tile_x::unmark"] = "void()" export_types_ai["tile_x::mark"] = "void()" export_types_ai["tile_x::get_convoys"] = "array()" export_types_ai["square_x::is_valid"] = "bool()" export_types_ai["square_x::get_halt"] = "halt_x()" export_types_ai["square_x::get_player_halt"] = "halt_x(player_x)" export_types_ai["square_x::get_tile_at_height"] = "tile_x(integer)" export_types_ai["square_x::get_ground_tile"] = "tile_x()" export_types_ai["square_x::get_halt_list"] = "array()" export_types_ai["square_x::get_climate"] = "climates()" export_types_ai["world::is_coord_valid"] = "bool(coord)" export_types_ai["world::find_nearest_city"] = "city_x(coord)" export_types_ai["world::get_season"] = "integer()" export_types_ai["world::get_player"] = "player_x(integer)" export_types_ai["world::get_time"] = "time_ticks_x()" export_types_ai["world::get_citizens"] = "array()" export_types_ai["world::get_growth"] = "array()" export_types_ai["world::get_towns"] = "array()" export_types_ai["world::get_factories"] = "array()" export_types_ai["world::get_convoys"] = "array()" export_types_ai["world::get_citycars"] = "array()" export_types_ai["world::get_ratio_pax"] = "array()" export_types_ai["world::get_generated_pax"] = "array()" export_types_ai["world::get_ratio_mail"] = "array()" export_types_ai["world::get_generated_mail"] = "array()" export_types_ai["world::get_ratio_goods"] = "array()" export_types_ai["world::get_transported_goods"] = "array()" export_types_ai["world::get_year_citizens"] = "array()" export_types_ai["world::get_year_growth"] = "array()" export_types_ai["world::get_year_towns"] = "array()" export_types_ai["world::get_year_factories"] = "array()" export_types_ai["world::get_year_convoys"] = "array()" export_types_ai["world::get_year_citycars"] = "array()" export_types_ai["world::get_year_ratio_pax"] = "array()" export_types_ai["world::get_year_generated_pax"] = "array()" export_types_ai["world::get_year_ratio_mail"] = "array()" export_types_ai["world::get_year_generated_mail"] = "array()" export_types_ai["world::get_year_ratio_goods"] = "array()" export_types_ai["world::get_year_transported_goods"] = "array()" export_types_ai["world::use_timeline"] = "bool()" export_types_ai["attraction_list_x::_get"] = "building_x(integer)" export_types_ai["label_list_x::_get"] = "label_x(integer)" export_types_ai["label_list_x::get_count"] = "integer()" export_types_ai["::get_pakset_name"] = "string()" export_types_ai["::get_version_number"] = "string()" export_types_ai["simple_heap_x::clear"] = "void()" export_types_ai["simple_heap_x::len"] = "integer()" export_types_ai["simple_heap_x::is_empty"] = "bool()" export_types_ai["simple_heap_x::insert"] = "void(integer, integer)" export_types_ai["way_planner_x::set_build_types"] = "void(way_desc_x)" export_types_ai["way_planner_x::is_allowed_step"] = "bool(tile_x, tile_x)" export_types_ai["bridge_planner_x::find_end"] = "coord3d(player_x, coord3d, dir, bridge_desc_x, integer)" export_types_ai["command_x::get_flags"] = "integer()" export_types_ai["command_x::set_flags"] = "void(integer)" export_types_ai["command_x::build_way"] = "string(player_x, coord3d, coord3d, way_desc_x, bool)" export_types_ai["command_x::build_road"] = "string(player_x, coord3d, coord3d, way_desc_x, bool, bool)" export_types_ai["command_x::build_depot"] = "string(player_x, coord3d, building_desc_x)" export_types_ai["command_x::build_station"] = "string(player_x, coord3d, building_desc_x, dir)" export_types_ai["command_x::build_bridge"] = "string(player_x, coord3d, coord3d, bridge_desc_x)" export_types_ai["command_x::build_bridge_at"] = "string(player_x, coord3d, bridge_desc_x)" export_types_ai["command_x::set_slope"] = "string(player_x, coord3d, slope)" export_types_ai["command_x::restore_slope"] = "string(player_x, coord3d)" export_types_ai["command_x::can_set_slope"] = "string(player_x, coord3d, slope)" export_types_ai["command_x::slope_get_price"] = "integer(slope)" export_types_ai["command_x::build_sign_at"] = "string(player_x, coord3d, sign_desc_x)" export_types_ai["command_x::build_wayobj"] = "string(player_x, coord3d, coord3d, wayobj_desc_x)" export_types_ai["command_x::change_climate_at"] = "string(player_x, coord3d, integer)" export_types_ai["command_x::grid_lower"] = "string(player_x, coord3d)" export_types_ai["command_x::grid_raise"] = "string(player_x, coord3d)" } simutrans-124.3/src/simutrans/script/api/squirrel_types_scenario.awk000066400000000000000000000751011474050137200261310ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # file used to generate doxygen documentation of squirrel API # needs to be copied to trunk/script/api BEGIN { export_types_scenario["city_list_x::_get"] = "city_x(integer)" export_types_scenario["city_x::is_valid"] = "bool()" export_types_scenario["city_x::get_name"] = "string()" export_types_scenario["city_x::set_name"] = "void(string)" export_types_scenario["city_x::get_citizens"] = "array()" export_types_scenario["city_x::get_growth"] = "array()" export_types_scenario["city_x::get_buildings"] = "array()" export_types_scenario["city_x::get_citycars"] = "array()" export_types_scenario["city_x::get_transported_pax"] = "array()" export_types_scenario["city_x::get_generated_pax"] = "array()" export_types_scenario["city_x::get_transported_mail"] = "array()" export_types_scenario["city_x::get_generated_mail"] = "array()" export_types_scenario["city_x::get_year_citizens"] = "array()" export_types_scenario["city_x::get_year_growth"] = "array()" export_types_scenario["city_x::get_year_buildings"] = "array()" export_types_scenario["city_x::get_year_citycars"] = "array()" export_types_scenario["city_x::get_year_transported_pax"] = "array()" export_types_scenario["city_x::get_year_generated_pax"] = "array()" export_types_scenario["city_x::get_year_transported_mail"] = "array()" export_types_scenario["city_x::get_year_generated_mail"] = "array()" export_types_scenario["city_x::get_citygrowth_enabled"] = "bool()" export_types_scenario["city_x::get_pos"] = "coord()" export_types_scenario["city_x::get_pos_nw"] = "coord()" export_types_scenario["city_x::get_pos_se"] = "coord()" export_types_scenario["city_x::change_size"] = "string(integer)" export_types_scenario["city_x::set_citygrowth_enabled"] = "void(bool)" export_types_scenario["::get_ops_total"] = "integer()" export_types_scenario["::get_ops_remaining"] = "integer()" export_types_scenario["debug::pause"] = "bool()" export_types_scenario["debug::is_paused"] = "bool()" export_types_scenario["debug::set_pause_on_error"] = "void(bool)" export_types_scenario["convoy_x::is_valid"] = "bool()" export_types_scenario["convoy_x::needs_electrification"] = "bool()" export_types_scenario["convoy_x::get_name"] = "string()" export_types_scenario["convoy_x::set_name"] = "void(string)" export_types_scenario["convoy_x::get_pos"] = "coord3d()" export_types_scenario["convoy_x::get_owner"] = "player_x()" export_types_scenario["convoy_x::get_goods_catg_index"] = "array()" export_types_scenario["convoy_x::get_waytype"] = "way_types()" export_types_scenario["convoy_x::get_schedule"] = "schedule_x()" export_types_scenario["convoy_x::get_capacity"] = "array()" export_types_scenario["convoy_x::get_transported_goods"] = "array()" export_types_scenario["convoy_x::get_revenue"] = "array()" export_types_scenario["convoy_x::get_cost"] = "array()" export_types_scenario["convoy_x::get_profit"] = "array()" export_types_scenario["convoy_x::get_traveled_distance"] = "array()" export_types_scenario["convoy_x::get_way_tolls"] = "array()" export_types_scenario["convoy_x::get_distance_traveled_total"] = "integer()" export_types_scenario["convoy_x::get_line"] = "line_x()" export_types_scenario["convoy_x::set_line"] = "void(player_x, line_x)" export_types_scenario["convoy_x::get_vehicles"] = "array()" export_types_scenario["convoy_x::get_speed"] = "integer()" export_types_scenario["convoy_x::get_loading_limit"] = "integer()" export_types_scenario["convoy_x::get_loading_level"] = "integer()" export_types_scenario["convoy_x::get_home_depot"] = "coord3d()" export_types_scenario["convoy_x::has_obsolete_vehicles"] = "bool()" export_types_scenario["convoy_x::toggle_withdraw"] = "void(player_x)" export_types_scenario["convoy_x::is_withdrawn"] = "bool()" export_types_scenario["convoy_x::is_in_depot"] = "bool()" export_types_scenario["convoy_x::is_waiting"] = "bool()" export_types_scenario["convoy_x::is_loading"] = "bool()" export_types_scenario["convoy_x::destroy"] = "void(player_x)" export_types_scenario["convoy_x::is_schedule_editor_open"] = "bool()" export_types_scenario["convoy_x::get_tile_length"] = "integer()" export_types_scenario["convoy_x::change_schedule"] = "void(player_x, schedule_x)" export_types_scenario["convoy_x::calc_max_speed"] = "integer(integer, integer, integer)" export_types_scenario["convoy_x::speed_to_tiles_per_month"] = "integer(integer)" export_types_scenario["factory_x::is_valid"] = "bool()" export_types_scenario["factory_x::get_consumers"] = "array()" export_types_scenario["factory_x::get_suppliers"] = "array()" export_types_scenario["factory_x::get_name"] = "string()" export_types_scenario["factory_x::get_raw_name"] = "string()" export_types_scenario["factory_x::set_name"] = "void(string)" export_types_scenario["factory_x::get_production"] = "array()" export_types_scenario["factory_x::get_power"] = "array()" export_types_scenario["factory_x::get_boost_electric"] = "array()" export_types_scenario["factory_x::get_boost_pax"] = "array()" export_types_scenario["factory_x::get_boost_mail"] = "array()" export_types_scenario["factory_x::get_pax_generated"] = "array()" export_types_scenario["factory_x::get_pax_departed"] = "array()" export_types_scenario["factory_x::get_pax_arrived"] = "array()" export_types_scenario["factory_x::get_mail_generated"] = "array()" export_types_scenario["factory_x::get_mail_departed"] = "array()" export_types_scenario["factory_x::get_mail_arrived"] = "array()" export_types_scenario["factory_x::get_tile_list"] = "array()" export_types_scenario["factory_x::get_fields_list"] = "array()" export_types_scenario["factory_x::get_halt_list"] = "array()" export_types_scenario["factory_x::is_transformer_connected"] = "bool()" export_types_scenario["factory_x::get_transformer"] = "powerline_x()" export_types_scenario["factory_x::get_field_count"] = "integer()" export_types_scenario["factory_x::get_min_field_count"] = "integer()" export_types_scenario["factory_x::get_desc"] = "factory_desc_x()" export_types_scenario["factory_production_x::get_storage"] = "array()" export_types_scenario["factory_production_x::get_received"] = "array()" export_types_scenario["factory_production_x::get_consumed"] = "array()" export_types_scenario["factory_production_x::get_in_transit"] = "array()" export_types_scenario["factory_production_x::get_delivered"] = "array()" export_types_scenario["factory_production_x::get_produced"] = "array()" export_types_scenario["factory_production_x::get_consumption_factor"] = "integer()" export_types_scenario["factory_production_x::get_production_factor"] = "integer()" export_types_scenario["obj_desc_x::get_name"] = "string()" export_types_scenario["obj_desc_x::is_equal"] = "bool(obj_desc_x)" export_types_scenario["obj_desc_x::is_valid"] = "bool()" export_types_scenario["obj_desc_time_x::get_intro_date"] = "time_x()" export_types_scenario["obj_desc_time_x::get_retire_date"] = "time_x()" export_types_scenario["obj_desc_time_x::is_future"] = "bool(time_x)" export_types_scenario["obj_desc_time_x::is_retired"] = "bool(time_x)" export_types_scenario["obj_desc_time_x::is_available"] = "bool(time_x)" export_types_scenario["obj_desc_transport_x::get_maintenance"] = "integer()" export_types_scenario["obj_desc_transport_x::get_cost"] = "integer()" export_types_scenario["obj_desc_transport_x::get_waytype"] = "way_types()" export_types_scenario["obj_desc_transport_x::get_topspeed"] = "integer()" export_types_scenario["vehicle_desc_x::can_be_first"] = "bool()" export_types_scenario["vehicle_desc_x::can_be_last"] = "bool()" export_types_scenario["vehicle_desc_x::get_successors"] = "array()" export_types_scenario["vehicle_desc_x::get_predecessors"] = "array()" export_types_scenario["vehicle_desc_x::get_available_vehicles"] = "array(way_types)" export_types_scenario["vehicle_desc_x::get_power"] = "integer()" export_types_scenario["vehicle_desc_x::needs_electrification"] = "bool()" export_types_scenario["vehicle_desc_x::get_freight"] = "good_desc_x()" export_types_scenario["vehicle_desc_x::get_capacity"] = "integer()" export_types_scenario["vehicle_desc_x::get_running_cost"] = "integer()" export_types_scenario["vehicle_desc_x::get_maintenance"] = "integer()" export_types_scenario["vehicle_desc_x::get_weight"] = "integer()" export_types_scenario["vehicle_desc_x::get_length"] = "integer()" export_types_scenario["vehicle_desc_x::is_coupling_allowed"] = "bool(vehicle_desc_x, vehicle_desc_x)" export_types_scenario["tree_desc_x::get_price"] = "integer()" export_types_scenario["building_desc_x::is_attraction"] = "bool()" export_types_scenario["building_desc_x::get_maintenance"] = "integer()" export_types_scenario["building_desc_x::get_cost"] = "integer()" export_types_scenario["building_desc_x::get_capacity"] = "integer()" export_types_scenario["building_desc_x::can_be_built_underground"] = "bool()" export_types_scenario["building_desc_x::can_be_built_aboveground"] = "bool()" export_types_scenario["building_desc_x::enables_pax"] = "bool()" export_types_scenario["building_desc_x::enables_mail"] = "bool()" export_types_scenario["building_desc_x::enables_freight"] = "bool()" export_types_scenario["building_desc_x::get_type"] = "building_desc_x::building_type()" export_types_scenario["building_desc_x::get_waytype"] = "way_types()" export_types_scenario["building_desc_x::get_headquarter_level"] = "integer()" export_types_scenario["building_desc_x::get_building_list"] = "array(building_desc_x::building_type)" export_types_scenario["building_desc_x::get_available_stations"] = "array(building_desc_x::building_type, way_types, good_desc_x)" export_types_scenario["building_desc_x::is_terminus"] = "bool()" export_types_scenario["factory_desc_x::get_name"] = "string()" export_types_scenario["factory_desc_x::get_building_desc"] = "building_desc_x()" export_types_scenario["factory_desc_x::is_electricity_producer"] = "bool()" export_types_scenario["factory_desc_x::get_productivity_base"] = "integer()" export_types_scenario["factory_desc_x::get_productivity_range"] = "integer()" export_types_scenario["factory_desc_x::get_list"] = "table()" export_types_scenario["way_desc_x::has_double_slopes"] = "bool()" export_types_scenario["way_desc_x::get_system_type"] = "way_system_types()" export_types_scenario["way_desc_x::get_available_ways"] = "array(way_types, way_system_types)" export_types_scenario["tunnel_desc_x::get_available_tunnels"] = "array(way_types)" export_types_scenario["bridge_desc_x::has_double_ramp"] = "bool()" export_types_scenario["bridge_desc_x::has_double_start"] = "bool()" export_types_scenario["bridge_desc_x::get_max_length"] = "integer()" export_types_scenario["bridge_desc_x::get_max_height"] = "integer()" export_types_scenario["bridge_desc_x::get_available_bridges"] = "array(way_types)" export_types_scenario["good_desc_x::get_catg_index"] = "integer()" export_types_scenario["good_desc_x::is_interchangeable"] = "bool(good_desc_x)" export_types_scenario["good_desc_x::get_weight_per_unit"] = "integer()" export_types_scenario["good_desc_x::get_metric"] = "string()" export_types_scenario["good_desc_x::calc_revenue"] = "integer(way_types, integer)" export_types_scenario["sign_desc_x::is_one_way"] = "bool()" export_types_scenario["sign_desc_x::is_private_way"] = "bool()" export_types_scenario["sign_desc_x::is_traffic_light"] = "bool()" export_types_scenario["sign_desc_x::is_choose_sign"] = "bool()" export_types_scenario["sign_desc_x::is_signal"] = "bool()" export_types_scenario["sign_desc_x::is_pre_signal"] = "bool()" export_types_scenario["sign_desc_x::is_priority_signal"] = "bool()" export_types_scenario["sign_desc_x::is_longblock_signal"] = "bool()" export_types_scenario["sign_desc_x::is_end_choose_signal"] = "bool()" export_types_scenario["sign_desc_x::get_available_signs"] = "array(way_types)" export_types_scenario["wayobj_desc_x::is_overhead_line"] = "bool()" export_types_scenario["wayobj_desc_x::get_available_wayobjs"] = "array(way_types)" export_types_scenario["gui::open_info_win"] = "void()" export_types_scenario["gui::open_info_win_at"] = "void(string)" export_types_scenario["gui::open_info_win_client"] = "void(string, integer)" export_types_scenario["gui::add_message_at"] = "string(string, coord3d)" export_types_scenario["gui::add_message"] = "string(player_x, string)" export_types_scenario["halt_x::is_valid"] = "bool()" export_types_scenario["halt_x::get_name"] = "string()" export_types_scenario["halt_x::set_name"] = "void(string)" export_types_scenario["halt_x::get_owner"] = "player_x()" export_types_scenario["halt_x::_cmp"] = "integer(halt_x)" export_types_scenario["halt_x::is_connected"] = "integer(halt_x, good_desc_x)" export_types_scenario["halt_x::accepts_good"] = "bool(good_desc_x)" export_types_scenario["halt_x::get_arrived"] = "array()" export_types_scenario["halt_x::get_departed"] = "array()" export_types_scenario["halt_x::get_waiting"] = "array()" export_types_scenario["halt_x::get_happy"] = "array()" export_types_scenario["halt_x::get_unhappy"] = "array()" export_types_scenario["halt_x::get_noroute"] = "array()" export_types_scenario["halt_x::get_convoys"] = "array()" export_types_scenario["halt_x::get_walked"] = "array()" export_types_scenario["halt_x::get_tile_list"] = "array()" export_types_scenario["halt_x::get_factory_list"] = "array()" export_types_scenario["halt_x::get_freight_to_dest"] = "integer(good_desc_x, coord)" export_types_scenario["halt_x::get_freight_to_halt"] = "integer(good_desc_x, halt_x)" export_types_scenario["halt_x::get_capacity"] = "integer(good_desc_x)" export_types_scenario["halt_x::get_connections"] = "array(good_desc_x)" export_types_scenario["halt_x::get_halt"] = "halt_x(coord3d, player_x)" export_types_scenario["line_x::is_valid"] = "bool()" export_types_scenario["line_x::get_name"] = "string()" export_types_scenario["line_x::set_name"] = "void(string)" export_types_scenario["line_x::get_owner"] = "player_x()" export_types_scenario["line_x::get_schedule"] = "schedule_x()" export_types_scenario["line_x::get_goods_catg_index"] = "array()" export_types_scenario["line_x::get_capacity"] = "array()" export_types_scenario["line_x::get_transported_goods"] = "array()" export_types_scenario["line_x::get_convoy_count"] = "array()" export_types_scenario["line_x::get_revenue"] = "array()" export_types_scenario["line_x::get_cost"] = "array()" export_types_scenario["line_x::get_profit"] = "array()" export_types_scenario["line_x::get_traveled_distance"] = "array()" export_types_scenario["line_x::get_way_tolls"] = "array()" export_types_scenario["line_x::get_waytype"] = "way_types()" export_types_scenario["line_x::change_schedule"] = "void(player_x, schedule_x)" export_types_scenario["line_x::destroy"] = "void(player_x)" export_types_scenario["map_object_x::is_valid"] = "bool()" export_types_scenario["map_object_x::get_owner"] = "player_x()" export_types_scenario["map_object_x::get_name"] = "string()" export_types_scenario["map_object_x::get_waytype"] = "way_types()" export_types_scenario["map_object_x::get_pos"] = "coord3d()" export_types_scenario["map_object_x::is_removable"] = "string(player_x)" export_types_scenario["map_object_x::get_type"] = "map_objects()" export_types_scenario["map_object_x::mark"] = "void()" export_types_scenario["map_object_x::unmark"] = "void()" export_types_scenario["map_object_x::is_marked"] = "bool()" export_types_scenario["tree_x::get_age"] = "integer()" export_types_scenario["tree_x::get_desc"] = "tree_desc_x()" export_types_scenario["building_x::get_factory"] = "factory_x()" export_types_scenario["building_x::get_city"] = "city_x()" export_types_scenario["building_x::is_townhall"] = "bool()" export_types_scenario["building_x::is_headquarter"] = "bool()" export_types_scenario["building_x::is_monument"] = "bool()" export_types_scenario["building_x::get_passenger_level"] = "integer()" export_types_scenario["building_x::get_mail_level"] = "integer()" export_types_scenario["building_x::get_desc"] = "building_desc_x()" export_types_scenario["building_x::get_tile_list"] = "array()" export_types_scenario["building_x::is_same_building"] = "bool(building_x)" export_types_scenario["depot_x::append_vehicle"] = "void(player_x, convoy_x, vehicle_desc_x)" export_types_scenario["depot_x::start_convoy"] = "void(player_x, convoy_x)" export_types_scenario["depot_x::start_all_convoys"] = "void(player_x)" export_types_scenario["depot_x::get_convoy_list"] = "array()" export_types_scenario["depot_x::get_depot_list"] = "array(player_x, way_types)" export_types_scenario["way_x::has_sidewalk"] = "bool()" export_types_scenario["way_x::is_electrified"] = "bool()" export_types_scenario["way_x::has_sign"] = "bool()" export_types_scenario["way_x::has_signal"] = "bool()" export_types_scenario["way_x::has_wayobj"] = "bool()" export_types_scenario["way_x::is_crossing"] = "bool()" export_types_scenario["way_x::get_desc"] = "way_desc_x()" export_types_scenario["way_x::get_max_speed"] = "integer()" export_types_scenario["way_x::get_transported_goods"] = "array()" export_types_scenario["way_x::get_convoys_passed"] = "array()" export_types_scenario["label_x::create"] = "string(coord, player_x, string)" export_types_scenario["label_x::set_text"] = "void(string)" export_types_scenario["label_x::get_text"] = "string()" export_types_scenario["sign_x::get_desc"] = "sign_desc_x()" export_types_scenario["sign_x::can_pass"] = "bool(player_x)" export_types_scenario["powerline_x::is_connected"] = "bool(powerline_x)" export_types_scenario["powerline_x::get_factory"] = "factory_x()" export_types_scenario["field_x::is_deletable"] = "bool()" export_types_scenario["field_x::get_factory"] = "factory_x()" export_types_scenario["wayobj_x::get_desc"] = "wayobj_desc_x()" export_types_scenario["bridge_x::get_desc"] = "bridge_desc_x()" export_types_scenario["tunnel_x::get_desc"] = "tunnel_desc_x()" export_types_scenario["player_x::is_valid"] = "bool()" export_types_scenario["player_x::get_headquarter_level"] = "integer()" export_types_scenario["player_x::get_headquarter_pos"] = "coord()" export_types_scenario["player_x::get_name"] = "string()" export_types_scenario["player_x::set_name"] = "void(string)" export_types_scenario["player_x::get_construction"] = "array()" export_types_scenario["player_x::get_vehicle_maint"] = "array()" export_types_scenario["player_x::get_new_vehicles"] = "array()" export_types_scenario["player_x::get_income"] = "array()" export_types_scenario["player_x::get_maintenance"] = "array()" export_types_scenario["player_x::get_assets"] = "array()" export_types_scenario["player_x::get_cash"] = "array()" export_types_scenario["player_x::get_net_wealth"] = "array()" export_types_scenario["player_x::get_profit"] = "array()" export_types_scenario["player_x::get_operating_profit"] = "array()" export_types_scenario["player_x::get_margin"] = "array()" export_types_scenario["player_x::get_transported"] = "array()" export_types_scenario["player_x::get_powerline"] = "array()" export_types_scenario["player_x::get_transported_pax"] = "array()" export_types_scenario["player_x::get_transported_mail"] = "array()" export_types_scenario["player_x::get_transported_goods"] = "array()" export_types_scenario["player_x::get_convoys"] = "array()" export_types_scenario["player_x::get_way_tolls"] = "array()" export_types_scenario["player_x::book_cash"] = "void(integer)" export_types_scenario["player_x::get_current_cash"] = "float()" export_types_scenario["player_x::get_current_net_wealth"] = "integer()" export_types_scenario["player_x::get_current_maintenance"] = "integer()" export_types_scenario["player_x::create_line"] = "void(way_types)" export_types_scenario["player_x::get_type"] = "integer()" export_types_scenario["::load_language_file"] = "string(string)" export_types_scenario["rules::forbid_tool"] = "void(integer, integer)" export_types_scenario["rules::allow_tool"] = "void(integer, integer)" export_types_scenario["rules::forbid_way_tool"] = "void(integer, integer, way_types)" export_types_scenario["rules::allow_way_tool"] = "void(integer, integer, way_types)" export_types_scenario["rules::forbid_way_tool_rect"] = "void(integer, integer, way_types, coord, coord, string)" export_types_scenario["rules::allow_way_tool_rect"] = "void(integer, integer, way_types, coord, coord)" export_types_scenario["rules::forbid_way_tool_cube"] = "void(integer, integer, way_types, coord3d, coord3d, string)" export_types_scenario["rules::allow_way_tool_cube"] = "void(integer, integer, way_types, coord3d, coord3d)" export_types_scenario["rules::clear"] = "void()" export_types_scenario["rules::gui_needs_update"] = "void()" export_types_scenario["debug::get_forbidden_text"] = "string()" export_types_scenario["schedule_entry_x::constructor"] = "void(coord3d, integer, integer)" export_types_scenario["coord3d::get_halt"] = "halt_x(player_x)" export_types_scenario["settings::get_industry_increase_every"] = "integer()" export_types_scenario["settings::set_industry_increase_every"] = "void(integer)" export_types_scenario["settings::get_traffic_level"] = "integer()" export_types_scenario["settings::set_traffic_level"] = "void(integer)" export_types_scenario["settings::get_start_time"] = "time_x()" export_types_scenario["settings::get_station_coverage"] = "integer()" export_types_scenario["settings::get_passenger_factor"] = "integer()" export_types_scenario["settings::get_factory_worker_radius"] = "integer()" export_types_scenario["settings::get_factory_worker_minimum_towns"] = "integer()" export_types_scenario["settings::get_factory_worker_maximum_towns"] = "integer()" export_types_scenario["settings::avoid_overcrowding"] = "bool()" export_types_scenario["settings::no_routing_over_overcrowding"] = "bool()" export_types_scenario["settings::separate_halt_capacities"] = "bool()" export_types_scenario["settings::obsolete_vehicles_allowed"] = "bool()" export_types_scenario["settings::get_max_road_convoi_length"] = "integer()" export_types_scenario["settings::get_max_rail_convoi_length"] = "integer()" export_types_scenario["settings::get_max_ship_convoi_length"] = "integer()" export_types_scenario["settings::get_max_air_convoi_length"] = "integer()" export_types_scenario["settings::get_drive_on_left"] = "bool()" export_types_scenario["settings::get_way_height_clearance"] = "integer()" export_types_scenario["settings::has_double_slopes"] = "bool()" export_types_scenario["settings::get_pay_for_total_distance_mode"] = "integer()" export_types_scenario["settings::get_underground_view_level"] = "integer()" export_types_scenario["dir::is_single"] = "bool(dir)" export_types_scenario["dir::is_twoway"] = "bool(dir)" export_types_scenario["dir::is_threeway"] = "bool(dir)" export_types_scenario["dir::is_curve"] = "bool(dir)" export_types_scenario["dir::is_straight"] = "bool(dir)" export_types_scenario["dir::double"] = "dir(dir)" export_types_scenario["dir::backward"] = "dir(dir)" export_types_scenario["dir::to_slope"] = "slope(dir)" export_types_scenario["slope::to_dir"] = "dir(slope)" export_types_scenario["::translate"] = "string(string)" export_types_scenario["::double_to_string"] = "string(float, integer)" export_types_scenario["::integer_to_string"] = "string(integer)" export_types_scenario["::money_to_string"] = "string(integer)" export_types_scenario["::coord_to_string"] = "string(coord)" export_types_scenario["::coord3d_to_string"] = "string(coord3d)" export_types_scenario["::get_month_name"] = "string(integer)" export_types_scenario["::difftick_to_string"] = "string(integer)" export_types_scenario["tile_x::is_valid"] = "bool()" export_types_scenario["tile_x::find_object"] = "map_object_x(map_objects)" export_types_scenario["tile_x::remove_object"] = "string(player_x, map_objects)" export_types_scenario["tile_x::get_halt"] = "halt_x()" export_types_scenario["tile_x::is_water"] = "bool()" export_types_scenario["tile_x::is_bridge"] = "bool()" export_types_scenario["tile_x::is_tunnel"] = "bool()" export_types_scenario["tile_x::is_empty"] = "bool()" export_types_scenario["tile_x::is_ground"] = "bool()" export_types_scenario["tile_x::is_crossing"] = "bool()" export_types_scenario["tile_x::get_slope"] = "slope()" export_types_scenario["tile_x::get_text"] = "string()" export_types_scenario["tile_x::has_way"] = "bool(way_types)" export_types_scenario["tile_x::has_ways"] = "bool()" export_types_scenario["tile_x::has_two_ways"] = "bool()" export_types_scenario["tile_x::get_way"] = "way_x(way_types)" export_types_scenario["tile_x::get_neighbour"] = "tile_x(way_types, dir)" export_types_scenario["tile_x::get_depot"] = "depot_x()" export_types_scenario["tile_x::can_remove_all_objects"] = "string(player_x)" export_types_scenario["tile_x::is_marked"] = "bool()" export_types_scenario["tile_x::unmark"] = "void()" export_types_scenario["tile_x::mark"] = "void()" export_types_scenario["tile_x::get_convoys"] = "array()" export_types_scenario["square_x::is_valid"] = "bool()" export_types_scenario["square_x::get_halt"] = "halt_x()" export_types_scenario["square_x::get_player_halt"] = "halt_x(player_x)" export_types_scenario["square_x::get_tile_at_height"] = "tile_x(integer)" export_types_scenario["square_x::get_ground_tile"] = "tile_x()" export_types_scenario["square_x::get_halt_list"] = "array()" export_types_scenario["square_x::get_climate"] = "climates()" export_types_scenario["world::is_coord_valid"] = "bool(coord)" export_types_scenario["world::find_nearest_city"] = "city_x(coord)" export_types_scenario["world::get_season"] = "integer()" export_types_scenario["world::remove_player"] = "bool(player_x)" export_types_scenario["world::generate_goods"] = "integer(coord, coord, good_desc_x, integer)" export_types_scenario["world::get_player"] = "player_x(integer)" export_types_scenario["world::get_time"] = "time_ticks_x()" export_types_scenario["world::get_citizens"] = "array()" export_types_scenario["world::get_growth"] = "array()" export_types_scenario["world::get_towns"] = "array()" export_types_scenario["world::get_factories"] = "array()" export_types_scenario["world::get_convoys"] = "array()" export_types_scenario["world::get_citycars"] = "array()" export_types_scenario["world::get_ratio_pax"] = "array()" export_types_scenario["world::get_generated_pax"] = "array()" export_types_scenario["world::get_ratio_mail"] = "array()" export_types_scenario["world::get_generated_mail"] = "array()" export_types_scenario["world::get_ratio_goods"] = "array()" export_types_scenario["world::get_transported_goods"] = "array()" export_types_scenario["world::get_year_citizens"] = "array()" export_types_scenario["world::get_year_growth"] = "array()" export_types_scenario["world::get_year_towns"] = "array()" export_types_scenario["world::get_year_factories"] = "array()" export_types_scenario["world::get_year_convoys"] = "array()" export_types_scenario["world::get_year_citycars"] = "array()" export_types_scenario["world::get_year_ratio_pax"] = "array()" export_types_scenario["world::get_year_generated_pax"] = "array()" export_types_scenario["world::get_year_ratio_mail"] = "array()" export_types_scenario["world::get_year_generated_mail"] = "array()" export_types_scenario["world::get_year_ratio_goods"] = "array()" export_types_scenario["world::get_year_transported_goods"] = "array()" export_types_scenario["world::use_timeline"] = "bool()" export_types_scenario["attraction_list_x::_get"] = "building_x(integer)" export_types_scenario["label_list_x::_get"] = "label_x(integer)" export_types_scenario["label_list_x::get_count"] = "integer()" export_types_scenario["::get_pakset_name"] = "string()" export_types_scenario["::get_version_number"] = "string()" export_types_scenario["simple_heap_x::clear"] = "void()" export_types_scenario["simple_heap_x::len"] = "integer()" export_types_scenario["simple_heap_x::is_empty"] = "bool()" export_types_scenario["simple_heap_x::insert"] = "void(integer, integer)" export_types_scenario["way_planner_x::set_build_types"] = "void(way_desc_x)" export_types_scenario["way_planner_x::is_allowed_step"] = "bool(tile_x, tile_x)" export_types_scenario["bridge_planner_x::find_end"] = "coord3d(player_x, coord3d, dir, bridge_desc_x, integer)" export_types_scenario["command_x::get_flags"] = "integer()" export_types_scenario["command_x::set_flags"] = "void(integer)" export_types_scenario["command_x::build_way"] = "string(player_x, coord3d, coord3d, way_desc_x, bool)" export_types_scenario["command_x::build_road"] = "string(player_x, coord3d, coord3d, way_desc_x, bool, bool)" export_types_scenario["command_x::build_depot"] = "string(player_x, coord3d, building_desc_x)" export_types_scenario["command_x::build_station"] = "string(player_x, coord3d, building_desc_x, dir)" export_types_scenario["command_x::build_bridge"] = "string(player_x, coord3d, coord3d, bridge_desc_x)" export_types_scenario["command_x::build_bridge_at"] = "string(player_x, coord3d, bridge_desc_x)" export_types_scenario["command_x::set_slope"] = "string(player_x, coord3d, slope)" export_types_scenario["command_x::restore_slope"] = "string(player_x, coord3d)" export_types_scenario["command_x::can_set_slope"] = "string(player_x, coord3d, slope)" export_types_scenario["command_x::slope_get_price"] = "integer(slope)" export_types_scenario["command_x::build_sign_at"] = "string(player_x, coord3d, sign_desc_x)" export_types_scenario["command_x::build_wayobj"] = "string(player_x, coord3d, coord3d, wayobj_desc_x)" export_types_scenario["command_x::change_climate_at"] = "string(player_x, coord3d, integer)" export_types_scenario["command_x::grid_lower"] = "string(player_x, coord3d)" export_types_scenario["command_x::grid_raise"] = "string(player_x, coord3d)" } simutrans-124.3/src/simutrans/script/api_class.cc000066400000000000000000000041671474050137200221500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api_class.h" #include "api_function.h" /** * creates class, leaves it at the top of the stack * * @param vm */ SQInteger script_api::create_class(HSQUIRRELVM vm, const char* classname, const char* baseclass) { script_api::set_squirrel_type_class(classname); sq_pushroottable(vm); if (baseclass) { sq_pushstring(vm, baseclass, -1); if(!SQ_SUCCEEDED(sq_get(vm, -2))) { sq_raise_error(vm, "base class %s to derive %s from it not found", baseclass, classname); // sq error will not be reported most of the time, so report to dbg, too dbg->error("script_api::create_class", "base class '%s' to derive %s from it not found", baseclass, classname); // good luck with any script baseclass = NULL; } } sq_newclass(vm, baseclass!=NULL); sq_pushstring(vm, classname, -1); sq_push(vm, -2); // stack: root, class, classname, class sq_newslot(vm, -4, false); sq_remove(vm, -2); // remove root table return SQ_OK; } SQInteger script_api::begin_class(HSQUIRRELVM vm, const char* classname, const char* /* baseclasses - dummy */) { script_api::set_squirrel_type_class(classname); if(!SQ_SUCCEEDED(push_class(vm, classname))) { // push a dummy class on the stack to prevent failed assertions down the road sq_newclass(vm, false); return SQ_ERROR; } return SQ_OK; } void script_api::end_class(HSQUIRRELVM vm) { script_api::set_squirrel_type_class(""); sq_pop(vm,1); } /** * pushes class * * @param vm */ SQInteger script_api::push_class(HSQUIRRELVM vm, const char* classname) { sq_pushroottable(vm); sq_pushstring(vm, classname, -1); if(!SQ_SUCCEEDED(sq_get(vm, -2))) { sq_pop(vm, 1); return sq_raise_error(vm, "class %s not found", classname); } sq_remove(vm, -2); // remove root table return SQ_OK; } /** * pushes constructor of class: closure (the constructor) and environment (the class) * * @param vm */ SQInteger script_api::prepare_constructor(HSQUIRRELVM vm, const char* classname) { if (!SQ_SUCCEEDED(push_class(vm, classname))) { return SQ_ERROR; } sq_pushnull(vm); return SQ_OK; } simutrans-124.3/src/simutrans/script/api_class.h000066400000000000000000000133041474050137200220030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_CLASS_H #define SCRIPT_API_CLASS_H #include "api_param.h" #include "../../squirrel/squirrel.h" #include "../../squirrel/sq_extensions.h" // sq_call_restricted #include "../tpl/stringhashtable_tpl.h" #include /** @file api_class.h handling classes and instances */ namespace script_api { /** * Creates squirrel class on the stack. Inherits from @p baseclass. * Has to be complemented by call to end_class. * * @param vm * @param classname name of squirrel class * @param baseclass name of base class (or NULL) * @return SQ_OK or SQ_ERROR */ SQInteger create_class(HSQUIRRELVM vm, const char* classname, const char* baseclass = NULL); /** * Creates squirrel class on the stack. Inherits from @p baseclass. * Has to be complemented by call to end_class. * Assigns the tag from param::tag() to the class. * * @param vm * @tparam C assigns tag from C::tag() to the new class * @return SQ_OK or SQ_ERROR */ template SQInteger create_class(HSQUIRRELVM vm, const char* classname, const char* baseclass = NULL) { SQInteger res = create_class(vm, classname, baseclass); if (SQ_SUCCEEDED(res)) { sq_settypetag(vm, -1, param::tag()); } return res; } /** * Pushes class on stack. * Has to be complemented by call to end_class. * * @param vm * @param classname name of squirrel class, must exist prior to calling this function * @param baseclasses dummy string containing base classes - to create nice doxygen output * @return SQ_OK or SQ_ERROR */ SQInteger begin_class(HSQUIRRELVM vm, const char* classname, const char* baseclasses = NULL); /** * Pops class from stack. */ void end_class(HSQUIRRELVM vm); /** * Pushes the squirrel class onto the stack. * Has to be complemented by call to end_class. * * @param vm * @param classname name of squirrel class * @return SQ_OK or SQ_ERROR */ SQInteger push_class(HSQUIRRELVM vm, const char* classname); /** * Prepares call to class to instantiate. * Pushes class and dummy object. * * @param vm * @param classname name of squirrel class * @return SQ_OK or SQ_ERROR */ SQInteger prepare_constructor(HSQUIRRELVM vm, const char* classname); template SQInteger push_instance(HSQUIRRELVM vm, const char* classname, const As &... as) { // push constructor if (!SQ_SUCCEEDED(prepare_constructor(vm, classname)) ) { return -1; } // push parameters int nparam = push_param(vm, as...); if (!SQ_SUCCEEDED(nparam)) { return -1; } // call constructor bool ok = SQ_SUCCEEDED(sq_call_restricted(vm, nparam+1, true, false)); sq_remove(vm, ok ? -2 : -1); /* remove closure */ return ok ? 1 : -1; } /** * Create instance, set userpointer. * Does NOT call constructor. */ template inline SQInteger push_instance_up(HSQUIRRELVM vm, const C* ptr) { if (!SQ_SUCCEEDED(push_class(vm, param::squirrel_type()) )) { return -1; } sq_createinstance(vm, -1); sq_setinstanceup(vm, -1, (void*)const_cast(ptr)); sq_remove(vm, -2); // remove class return 1; } /** * Implementation of quickstone_tpl specialization */ template struct param< quickstone_tpl > { /** * Assumes that constructor of corresponding squirrel class * accepts one parameter (the id). * * @param vm * @return positive value for success, negative for failure */ static SQInteger push(HSQUIRRELVM vm, quickstone_tpl const& h) { if (h.is_bound()) { return push_instance(vm, param::squirrel_type(), h.get_id()); } else { sq_pushnull(vm); return 1; } } static const quickstone_tpl get(HSQUIRRELVM vm, SQInteger index) { uint16 id = 0; get_slot(vm, "id", id, index); quickstone_tpl h; if (id < quickstone_tpl::get_size()) { h.set_id(id); } else { sq_raise_error(vm, "Invalid id %d, too large", id); } return h; } static const char* squirrel_type() { return param::squirrel_type(); } static const char* typemask() { return param::typemask(); } }; /** * Implementation of stringhashtable_tpl specialization */ template struct param< stringhashtable_tpl > { /** * Creates table, uses string-keys as table keys. */ static SQInteger push(HSQUIRRELVM vm, stringhashtable_tpl const& v) { sq_newtable(vm); for(auto const&i : v) { create_slot(vm, i.key, i.value); } return 1; } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { static cbuffer_t buf; buf.clear(); buf.printf("table<%s>", param::squirrel_type() ); return buf; } }; // forward declaration template SQInteger command_release_hook(SQUserPointer up, SQInteger); /** * Stores pointer to C++ object as userpointer of squirrel class instance. * C++ object will be deleted when squirrel class instance gets released. */ template void attach_instance(HSQUIRRELVM vm, SQInteger index, C* o) { // set userpointer of class instance sq_setinstanceup(vm, index, o ); sq_setreleasehook(vm, index, command_release_hook); } /** * Retrieves pointer to stored C++ object. */ template C* get_attached_instance(HSQUIRRELVM vm, SQInteger index, SQUserPointer tag) { SQUserPointer up; if (SQ_SUCCEEDED(sq_getinstanceup(vm, index, &up, tag))) { return (C*)up; } return NULL; } /** * Releases memory allocated by attach_instance. * Do not call directly! */ template SQInteger command_release_hook(SQUserPointer up, SQInteger) { C* p = (C *)up; delete p; return 1; } }; // end of namespace #endif simutrans-124.3/src/simutrans/script/api_function.cc000066400000000000000000000035411474050137200226630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api_function.h" #include #include "../sys/simsys.h" #include "../dataobj/environment.h" /** * Auxiliary function to register function in table/class at stack top */ void script_api::register_function(HSQUIRRELVM vm, SQFUNCTION funcptr, const char *name, int nparamcheck, const char* typemask, bool staticmethod) { sq_pushstring(vm, name, -1); sq_newclosure(vm, funcptr, 0); //create a new function sq_setnativeclosurename(vm, -1, name); sq_setparamscheck(vm, nparamcheck, typemask); sq_newslot(vm, -3, staticmethod); } static FILE* file = NULL; static const char* suffix = NULL; void script_api::start_squirrel_type_logging(const char* s) { if (env_t::verbose_debug < 2) { return; } suffix = s; cbuffer_t buf; buf.printf("squirrel_types_%s.awk", suffix); file = dr_fopen(buf, "w"); if (file) { fprintf(file, "#\n"); fprintf(file, "# This file is part of the Simutrans project under the Artistic License.\n"); fprintf(file, "# (see LICENSE.txt)\n"); fprintf(file, "#\n"); fprintf(file, "# file used to generate doxygen documentation of squirrel API\n"); fprintf(file, "# needs to be copied to trunk/script/api\n"); fprintf(file, "BEGIN {\n"); } } void script_api::end_squirrel_type_logging() { if (file) { fprintf(file, "}\n"); fclose(file); file = NULL; suffix = NULL; } } static plainstring current_class; void script_api::set_squirrel_type_class(const char* classname) { current_class = classname; } void script_api::log_squirrel_type(std::string classname, const char* name, std::string squirrel_type) { if (file) { fprintf(file, "\texport_types_%s[\"%s::%s\"] = \"%s\"\n", suffix ? suffix : "", classname.empty() ? current_class.c_str() : classname.c_str(), name, squirrel_type.c_str() ); } } simutrans-124.3/src/simutrans/script/api_function.h000066400000000000000000000420261474050137200225260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_FUNCTION_H #define SCRIPT_API_FUNCTION_H #include "api_param.h" #include "../../squirrel/squirrel.h" #include #include #include #include // mark class members static in doxygen documentation of api #define STATIC /** @file api_function.h templates to export c++ function to and call from squirrel */ namespace script_api { // forward declarations template SQInteger generic_squirrel_callback(HSQUIRRELVM vm); template struct embed_call_t; template struct func_signature_t; /// @{ /// @name Function to log squirrel-side type of exported functions void start_squirrel_type_logging(const char* suffix); void end_squirrel_type_logging(); // sets current class name, does not work with nested classes void set_squirrel_type_class(const char* classname); void log_squirrel_type(std::string classname, const char* name, std::string squirrel_type); /// @} /** * Registers custom SQFUNCTION @p funcptr. * * @pre Assumes that there is a table/class at the top of the stack to * attach the function to it. * * @param funcptr function pointer to custom implementation * @param name name of the method as visible from squirrel * @param nparamcheck for squirrel parameter checking * @param typemask for squirrel parameter checking * @param staticmethod if true then register as static method */ void register_function(HSQUIRRELVM vm, SQFUNCTION funcptr, const char *name, int nparamcheck, const char* typemask, bool staticmethod = false); /** * Registers custom SQFUNCTION @p funcptr. * * Same as non-templated register_function. Typemask und paramcheck will be deduced from the template parameter. * * @param vm * @tparam F function pointer signature of c++ method * @param funcptr function pointer to custom implementation * @param name name of the method as visible from squirrel * @param staticmethod if true then register as static method */ template void register_function(HSQUIRRELVM vm, SQFUNCTION funcptr, const char *name, bool staticmethod = false) { std::string typemask = func_signature_t::get_typemask(false); int nparamcheck = func_signature_t::get_nparams(); register_function(vm, funcptr, name, nparamcheck, typemask.c_str(), staticmethod); log_squirrel_type(func_signature_t::get_squirrel_class(false), name, func_signature_t::get_squirrel_type(false, 0)); } /** * Registers custom SQFUNCTION @p funcptr with templated free variables (default parameters). * * @pre Assumes that there is a table/class at the top of the stack to * attach the function to it. * * @param vm * @tparam F type for free variables, @see freevariable * @param funcptr function pointer to custom implementation * @param name name of the method as visible from squirrel * @param nparamcheck for squirrel parameter checking * @param typemask for squirrel parameter checking * @param freevariables contains values of free variables * @param staticmethod if true then register as static method */ template void register_function_fv(HSQUIRRELVM vm, SQFUNCTION funcptr, const char *name, int nparamcheck, const char* typemask, F const& freevariables, bool staticmethod = false) { sq_pushstring(vm, name, -1); SQInteger count = freevariables.push(vm); sq_newclosure(vm, funcptr, count); //create a new function sq_setnativeclosurename(vm, -1, name); sq_setparamscheck(vm, nparamcheck, typemask); sq_newslot(vm, -3, staticmethod); } // auxiliary struct template struct function_info_t { F funcptr; // pointer to c++ function bool act_as_member; function_info_t(F f, bool d) : funcptr(f), act_as_member(d) {} }; /** * Registers native c++ method to be called from squirrel. * Squirrel calls generic_squirrel_callback, the pointer to the actual * c++ function is attached in form of userdata. * * @pre Assumes that there is a table/class at the top of the stack to * attach the function to it. * * @param vm * @tparam F function pointer signature of c++ method * @param funcptr pointer to the c++ method * @param name name of the method as visible from squirrel * @param act_as_member if true then a global (non-member) function can be called * as if it would be a member function of the class instance * provided as first argument * @param staticmethod if true then register as static method */ template void register_method(HSQUIRRELVM vm, F funcptr, const char* name, bool act_as_member = false, bool staticmethod = false) { sq_pushstring(vm, name, -1); // pointer to function info as free variable function_info_t fi(funcptr, act_as_member); SQUserPointer up = sq_newuserdata(vm, sizeof(function_info_t)); memcpy(up, &fi, sizeof(function_info_t)); // create function sq_newclosure(vm, generic_squirrel_callback, 1); // ..associate its name for debugging sq_setnativeclosurename(vm, -1, name); std::string typemask = func_signature_t::get_typemask(act_as_member); sq_setparamscheck(vm, func_signature_t::get_nparams() - act_as_member, typemask.c_str()); sq_newslot(vm, -3, staticmethod); log_squirrel_type(func_signature_t::get_squirrel_class(act_as_member), name, func_signature_t::get_squirrel_type(act_as_member, 0)); } /** * Registers native c++ method to be called from squirrel. * Squirrel calls generic_squirrel_callback, the pointer to the actual * c++ function is attached in form of userdata. * * @pre Assumes that there is a table/class at the top of the stack to * attach the function to it. * * @param vm * @tparam F function pointer signature of c++ method * @tparam V class to push default parameters as free variables * @param funcptr pointer to the c++ method * @param name name of the method as visible from squirrel * @param freevariables values of default parameters to the c++ function (not the squirrel function) * @param act_as_member if true then a global (non-member) function can be called * as if it would be a member function of the class instance * provided as first argument * @param staticmethod if true then register as static method */ template void register_method_fv(HSQUIRRELVM vm, F funcptr, const char* name, V const& freevariables, bool act_as_member = false, bool staticmethod = false) { sq_pushstring(vm, name, -1); // pointer to function info as free variable function_info_t fi(funcptr, act_as_member); SQUserPointer up = sq_newuserdata(vm, sizeof(function_info_t)); memcpy(up, &fi, sizeof(function_info_t)); // more free variables SQInteger count = freevariables.push(vm); // create function sq_newclosure(vm, generic_squirrel_callback, count+1); // ..associate its name for debugging sq_setnativeclosurename(vm, -1, name); std::string typemask = func_signature_t::get_typemask(act_as_member); sq_setparamscheck(vm, func_signature_t::get_nparams() - act_as_member - count, typemask.c_str()); sq_newslot(vm, -3, staticmethod); log_squirrel_type(func_signature_t::get_squirrel_class(act_as_member), name, func_signature_t::get_squirrel_type(act_as_member, count)); } /** * Registers native c++ method to be called from squirrel. * This allows to register a non-member function to be called as * member function of squirrel classes: The c++ class is provided as * first argument. * * @pre Assumes that there is a table/class at the top of the stack to * attach the function to it. * @see register_method * * @param vm * @tparam F function pointer signature of c++ method * @param funcptr pointer to the c++ method * @param name name of the method as visible from squirrel */ template void register_local_method(HSQUIRRELVM vm, F funcptr, const char* name) { register_method(vm, funcptr, name, true); } /** * The general purpose callback method to be called from squirrel. * @tparam F function pointer signature of c++ method */ template SQInteger generic_squirrel_callback(HSQUIRRELVM vm) { SQUserPointer up = NULL; // get pointer to function function_info_t fi(0,false); sq_getuserdata(vm, -1, &up, NULL); memcpy(&fi, up, sizeof(function_info_t)); // call the template that automatically fetches right number of parameters return embed_call_t::call_function(vm, fi.funcptr, fi.act_as_member); } /** * Template to split parameter lists */ template struct parameter_pack_t { using first = A1; using back = void (*)(As...); }; /** * Template to generate strings related to argument lists */ template struct parameter_list_t; template struct parameter_list_t< void (*)(As...) > { /// @returns get typemask of first @p nparams parameters only static std::string get_param_typemask() { std::string res = param::first>::typemask() + parameter_list_t::back >::get_param_typemask(); return res; } /// @returns type list of first @p nparams arguments (without parentheses) static std::string get_param_squirrel_type(int nparams) { if (nparams > 0) { std::string res = param::first>::squirrel_type(); std::string add = parameter_list_t< typename parameter_pack_t::back >::get_param_squirrel_type(nparams-1); return res + (add.empty() ? "" : ", " + add); } return ""; } }; // specialization for empty parameter list template<> struct parameter_list_t< void (*)() > { static std::string get_param_typemask() { return ""; } static std::string get_param_squirrel_type(int) { return ""; } }; /** * Templates to generate squirrel typemasks, * wrapped in a one-parameter template struct, * which is specialized per function-signature. */ template struct func_signature_t; /** * Non-member functions. * May act as member functions if @p act_as_member is true. */ template struct func_signature_t { /// @returns typemask taking into account class argument is taken from 0th or 1st parameter static std::string get_typemask(bool act_as_member) { return (act_as_member ? "" : "." ) + parameter_list_t::get_param_typemask(); } /// @returns number of parameters static int get_nparams() { return sizeof...(As) + 1; } /// @returns squirrel class name of class argument of F ("" if not a member function) static std::string get_squirrel_class(bool act_as_member) { if (act_as_member) { // type of first parameter - if there is none then "" return parameter_list_t::get_param_squirrel_type(1); } return ""; } /// @returns function signature if interpreted as squirrel function static std::string get_squirrel_type(bool act_as_member, int freevars) { std::string res = get_return_squirrel_type() + "("; // remaining number of parameters (including class name if act_as_member == true) int nparams = get_nparams() - freevars - 1; std::string params = parameter_list_t< void (*)(As...) >::get_param_squirrel_type(nparams); if (act_as_member) { // ignore class parameter size_t n = params.find(", "); if (n == std::string::npos || n+2 > params.size()) { // not found params = ""; } else { // drop first parameter params = params.substr(n+2); } } return res += params + ")"; } /// @return squirrel type of return value static std::string get_return_squirrel_type() { return param::squirrel_type(); // will resolve R = void } }; /** * Member functions */ template struct func_signature_t { // reduce it to the case of an non-member function with act_as_member == true using function = R (*)(C*,As...); static int get_nparams() { return func_signature_t::get_nparams() - 1; } static std::string get_typemask(bool) { return func_signature_t::get_typemask(true); } static std::string get_squirrel_class(bool) { return param::squirrel_type(); } static std::string get_squirrel_type(bool, int freevars) { return func_signature_t::get_squirrel_type(true, freevars); } }; template struct func_signature_t : public func_signature_t { }; /** * Class to check first parameters to be not NULL. * Actually do the check only for pointer types. */ template struct param_chk_t { static bool is_null(T) { return false; } }; template struct param_chk_t { static bool is_null(T* t) { return t == NULL; } }; /** * Classes to implement the actual calls. * Calls to function pointers and member functions are turned into std::function calls. */ template class call_std_function_t; // specialization for functions with at least one argument: we might have to check for null-pointers template class call_std_function_t< R(A1,As...) > { template static SQInteger call_function_helper(HSQUIRRELVM vm, std::function const& func, bool act_as_member, std::index_sequence) { A1 a1 = param::get(vm, 2-act_as_member); if (act_as_member && param_chk_t::is_null(a1)) { return -1; } // non-void return value return param::push(vm, func(a1, param::get(vm, is+2 /* index on stack */ +1 /* correct for A1 */ -act_as_member)...) ); // index on stack: at +1 `this` argument, then parameters starting from +2 // if act_as_member then `this` is first argument to function, results in offset -1 } public: static SQInteger call_function(HSQUIRRELVM vm, std::function const& func, bool act_as_member) { return call_function_helper(vm, func, act_as_member, std::index_sequence_for{}); } }; // specialization for void functions with at least one argument: we might have to check for null-pointers template class call_std_function_t< void(A1,As...) > { template static SQInteger call_function_helper(HSQUIRRELVM vm, std::function const& func, bool act_as_member, std::index_sequence) { A1 a1 = param::get(vm, 2-act_as_member); if (act_as_member && param_chk_t::is_null(a1)) { return -1; } // void function func(a1, param::get(vm, is+2 /* index on stack */ +1 /* correct for A1 */ -act_as_member)...); return 0; } public: static SQInteger call_function(HSQUIRRELVM vm, std::function const& func, bool act_as_member) { return call_function_helper(vm, func, act_as_member, std::index_sequence_for{}); } }; // functions with no parameters template class call_std_function_t< R() > { public: static SQInteger call_function(HSQUIRRELVM vm, std::function const& func, bool) { return param::push(vm, func()); } }; template<> class call_std_function_t< void() > { public: static SQInteger call_function(HSQUIRRELVM, std::function const& func, bool) { func(); return 0; } }; /** * Templates to call functions with automatically fetching the right parameters, * wrapped in a one-parameter template struct, * which is specialized per function-signature. */ template struct embed_call_t; // Non-member functions template struct embed_call_t { static SQInteger call_function(HSQUIRRELVM vm, R (*func_ptr)(As...), bool act_as_member) { std::function< R(As...)> func = func_ptr; return call_std_function_t< R(As...) >::call_function(vm, func, act_as_member); } }; // Non-const member functions template struct embed_call_t { static SQInteger call_function(HSQUIRRELVM vm, R (C::*member_func_ptr)(As...), bool) { std::function< R(C*,As...)> func = member_func_ptr; return call_std_function_t< R(C*,As...) >::call_function(vm, func, true); } }; // Const member functions template struct embed_call_t { static SQInteger call_function(HSQUIRRELVM vm, R (C::*member_func_ptr)(As...) const, bool) { std::function< R(const C*,As...)> func = member_func_ptr; return call_std_function_t< R(const C*,As...) >::call_function(vm, func, true); } }; /** * Exports function to check whether pointer to in-game object is not null */ template SQInteger is_ptr_valid(HSQUIRRELVM vm) { P ptr = param

::get(vm, 1); sq_pushbool(vm, ptr != NULL); return 1; } template void export_is_valid(HSQUIRRELVM vm) { register_function(vm, is_ptr_valid

, "is_valid", 1, param

::typemask()); log_squirrel_type(param

::squirrel_type(), "is_valid", "bool()"); } }; // end of namespace #endif simutrans-124.3/src/simutrans/script/api_param.cc000066400000000000000000000357411474050137200221450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "api_param.h" #include "api_class.h" #include "../world/simcity.h" #include "../simfab.h" #include "../builder/goods_manager.h" #include "../dataobj/schedule.h" #include "../dataobj/loadsave.h" #include "../dataobj/scenario.h" #include "../player/simplay.h" #include "../utils/plainstring.h" #include "api/api_command.h" // script_api::my_tool_t #include "api/api_simple.h" // my_ribi_t namespace script_api { karte_ptr_t welt; // rotation handling void rotate90() { coordinate_transform_t::rotate90(); } void new_world() { coordinate_transform_t::new_world(); } uint8 coordinate_transform_t::rotation = 4; void coordinate_transform_t::initialize() { if (rotation == 4) { rotation = welt->get_settings().get_rotation(); } } void coordinate_transform_t::rdwr(loadsave_t *file) { file->rdwr_byte(rotation); } void coordinate_transform_t::koord_w2sq(koord &k) { // do not transform koord::invalid if (k.x == -1 && k.y == -1) { return; } switch( rotation ) { // 0: do nothing case 1: k = koord(k.y, welt->get_size().x-1 - k.x); break; case 2: k = koord(welt->get_size().x-1 - k.x, welt->get_size().y-1 - k.y); break; case 3: k = koord(welt->get_size().y-1 - k.y, k.x); break; default: break; } } void coordinate_transform_t::koord_sq2w(koord &k) { // do not transform koord::invalid if (k.x == -1 && k.y == -1) { return; } switch( rotation ) { // 0: do nothing case 1: k = koord(welt->get_size().x-1 - k.y, k.x); break; case 2: k = koord(welt->get_size().x-1 - k.x, welt->get_size().y-1 - k.y); break; case 3: k = koord(k.y, welt->get_size().y-1 - k.x); break; default: break; } } void coordinate_transform_t::ribi_w2sq(ribi_t::ribi &r) { if (rotation) { r = ( ( (r << 4) | r) >> rotation) & 15; } } void coordinate_transform_t::ribi_sq2w(ribi_t::ribi &r) { if (rotation) { r = ( ( (r << 4) | r) << rotation) >> 4 & 15; } } void coordinate_transform_t::slope_w2sq(slope_t::type &s) { if (s < slope_t::max_number) { for(uint8 i=1; i <= 4-rotation; i++) { s = slope_t::rotate90(s); } } } void coordinate_transform_t::slope_sq2w(slope_t::type &s) { if (s < slope_t::max_number) { for(uint8 i=1; i <= rotation; i++) { s = slope_t::rotate90(s); } } } // integer arguments uint8 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return clamp(i, 0, 255); } SQInteger param::push(HSQUIRRELVM vm, uint8 const& v) { sq_pushinteger(vm, v); return 1; } sint8 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return clamp(i, -128, 127); } SQInteger param::push(HSQUIRRELVM vm, sint8 const& v) { sq_pushinteger(vm, v); return 1; } uint16 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return clamp(i, 0, 0xffff); } SQInteger param::push(HSQUIRRELVM vm, uint16 const& v) { sq_pushinteger(vm, v); return 1; } sint16 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return clamp(i, -32768, 0x7fff); } SQInteger param::push(HSQUIRRELVM vm, sint16 const& v) { sq_pushinteger(vm, v); return 1; } uint32 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return i>=0 ? i : 0; } SQInteger param::push(HSQUIRRELVM vm, uint32 const& v) { sq_pushinteger(vm, v); return 1; } sint32 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return i; } SQInteger param::push(HSQUIRRELVM vm, sint32 const& v) { sq_pushinteger(vm, v); return 1; } uint64 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return i>=0 ? i : 0; } SQInteger param::push(HSQUIRRELVM vm, uint64 const& v) { sq_pushinteger(vm, (SQInteger)v); return 1; } sint64 param::get(HSQUIRRELVM vm, SQInteger index) { SQInteger i = 0; sq_getinteger(vm, index, &i); return i; } SQInteger param::push(HSQUIRRELVM vm, sint64 const& v) { sq_pushinteger(vm, (SQInteger)v); return 1; } // floats double param::get(HSQUIRRELVM vm, SQInteger index) { SQFloat d = 0.0; sq_getfloat(vm, index, &d); return d; } SQInteger param::push(HSQUIRRELVM vm, double const& v) { sq_pushfloat(vm, (SQFloat)v); return 1; } // strings const char* param::get(HSQUIRRELVM vm, SQInteger index) { const char* str = NULL; if (!SQ_SUCCEEDED(sq_getstring(vm, index, &str))) { sq_raise_error(vm, "Supplied string parameter is null"); return NULL; } return str; } SQInteger param::push(HSQUIRRELVM vm, const char* const& v) { if (v) { sq_pushstring(vm, v, -1); } else { sq_pushnull(vm); } return 1; } plainstring param::get(HSQUIRRELVM vm, SQInteger index) { if (sq_gettype(vm, index) == OT_NULL) { return NULL; } plainstring ret; const char* str = NULL; if (!SQ_SUCCEEDED(sq_getstring(vm, index, &str))) { // try tostring if (SQ_SUCCEEDED(sq_tostring(vm, index))) { sq_getstring(vm, -1, &str); ret = str; sq_pop(vm, 1); } } else { ret = str; } return ret; } SQInteger param::push(HSQUIRRELVM vm, plainstring const& v) { return param::push(vm, v.c_str()); } // bool bool param::get(HSQUIRRELVM vm, SQInteger index) { SQBool b = false; sq_tobool(vm, index, &b); return b; } SQInteger param::push(HSQUIRRELVM vm, bool const& v) { sq_pushbool(vm, v); return 1; } // coordinates koord param::get(HSQUIRRELVM vm, SQInteger index) { sint16 x=-1, y=-1; get_slot(vm, "x", x, index); get_slot(vm, "y", y, index); koord k(x,y); if (k.x != -1 && k.y != -1) { // transform coordinates coordinate_transform_t::koord_sq2w(k); } else { k = koord::invalid; } return k; } SQInteger param::push(HSQUIRRELVM vm, koord const& v) { koord k(v); if (k.x != -1 && k.y != -1) { // transform coordinates coordinate_transform_t::koord_w2sq(k); } else { k = koord::invalid; } return push_instance(vm, "coord", k.x, k.y); } koord3d param::get(HSQUIRRELVM vm, SQInteger index) { sint8 z = -1; if (!SQ_SUCCEEDED(get_slot(vm, "z", z, index))) { return koord3d::invalid; } koord k = param::get(vm, index); return koord3d(k, z); } SQInteger param::push(HSQUIRRELVM vm, koord3d const& v) { koord k(v.get_2d()); if (k.x != -1 && k.y != -1) { // transform coordinates coordinate_transform_t::koord_w2sq(k); } else { k = koord::invalid; } return push_instance(vm, "coord3d", k.x, k.y, v.z); } my_koord3d param::get(HSQUIRRELVM vm, SQInteger index) { koord3d k3 = koord3d::invalid; sint8 z = 0; // dummy if (!SQ_SUCCEEDED(get_slot(vm, "z", z, index))) { // 2d, try kartenboden koord k = param::get(vm,index); if (grund_t *gr = welt->lookup_kartenboden(k)) { k3 = gr->get_pos(); } // else: return invalid } else { // 3d k3 = param::get(vm, index); } return k3; } // directions / ribis SQInteger param::push(HSQUIRRELVM vm, my_ribi_t const& v) { ribi_t::ribi ribi = v; coordinate_transform_t::ribi_w2sq(ribi); return param::push(vm, ribi); } my_ribi_t param::get(HSQUIRRELVM vm, SQInteger index) { ribi_t::ribi ribi = param::get(vm, index) & ribi_t::all; coordinate_transform_t::ribi_sq2w(ribi); return ribi; } // slopes SQInteger param::push(HSQUIRRELVM vm, my_slope_t const& v) { slope_t::type slope = v; coordinate_transform_t::slope_w2sq(slope); return param::push(vm, slope); } my_slope_t param::get(HSQUIRRELVM vm, SQInteger index) { slope_t::type slope = param::get(vm, index); coordinate_transform_t::slope_sq2w(slope); return slope; } // pointers to classes convoi_t* param::get(HSQUIRRELVM vm, SQInteger index) { convoihandle_t cnv = param::get(vm, index); if (!cnv.is_bound()) { sq_raise_error(vm, "Invalid convoi id %d", cnv.get_id()); } return cnv.get_rep(); } fabrik_t* param::get(HSQUIRRELVM vm, SQInteger index) { koord pos = param::get(vm, index); fabrik_t* fab = fabrik_t::get_fab(pos); if (fab==NULL) { sq_raise_error(vm, "no factory at position (%s)", pos.get_str()); } return fab; } const fabrik_t* param::get(HSQUIRRELVM vm, SQInteger index) { return param::get(vm, index); } SQInteger param::push(HSQUIRRELVM vm, const fabrik_t* const& fab) { if (fab == NULL) { sq_pushnull(vm); return 1; } koord pos(fab->get_pos().get_2d()); coordinate_transform_t::koord_w2sq(pos); return push_instance(vm, "factory_x", pos.x, pos.y); } SQInteger param::push(HSQUIRRELVM vm, fabrik_t* const& fab) { return param::push(vm, fab); } const ware_production_t* param::get(HSQUIRRELVM vm, SQInteger index) { fabrik_t* fab = param::get(vm, index); if (fab == NULL) { return NULL; } // obtain index into wareproduction_t arrays SQInteger i = -1; if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) { if (i>=0) { if ( (uint32)iget_input().get_count()) { return &fab->get_input()[i]; } else { i -= fab->get_input().get_count(); if ( (uint32)iget_output().get_count()) { return &fab->get_output()[i]; } } } } sq_raise_error(vm, "No production slot [%d] in factory at (%s)", i, fab->get_pos().get_str()); return NULL; } const factory_supplier_desc_t* param::get(HSQUIRRELVM vm, SQInteger index) { fabrik_t* fab = param::get(vm, index); if (fab == NULL) { return NULL; } // obtain index into wareproduction_t arrays SQInteger i = -1; if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) { if (i>=0 && (uint32)iget_input().get_count()) { const ware_production_t& in = fab->get_input()[i]; const factory_supplier_desc_t* desc = fab->get_desc()->get_supplier(i); // sanity check if (desc && desc->get_input_type() == in.get_typ()) { return desc; } } } sq_raise_error(vm, "No input slot [%d] in factory at (%s)", i, fab->get_pos().get_str()); return NULL; } const factory_product_desc_t* param::get(HSQUIRRELVM vm, SQInteger index) { fabrik_t* fab = param::get(vm, index); if (fab == NULL) { return NULL; } // obtain index into wareproduction_t arrays SQInteger i = -1; if (SQ_SUCCEEDED(get_slot(vm, "index", i, index))) { i -= fab->get_input().get_count(); if (i>=0 && (uint32)iget_output().get_count()) { const ware_production_t& out = fab->get_output()[i]; const factory_product_desc_t* desc = fab->get_desc()->get_product(i); // sanity check if (desc && desc->get_output_type() == out.get_typ()) { return desc; } } } sq_raise_error(vm, "No output slot [%d] in factory at (%s)", i, fab->get_pos().get_str()); return NULL; } player_t* param::get(HSQUIRRELVM vm, SQInteger index) { uint8 plnr = 0; get_slot(vm, "nr", plnr, index); if(plnr < 15) { return welt->get_player(plnr); } else { sq_raise_error(vm, "Invalid player index %d", plnr); return NULL; } } SQInteger param::push(HSQUIRRELVM vm, player_t* const& player) { return push_instance(vm, "player_x", player ? player->get_player_nr() : 16); } player_t* get_my_player(HSQUIRRELVM vm) { sq_pushregistrytable(vm); uint8 player_nr = PLAYER_UNOWNED; player_t *pl = NULL; if (SQ_SUCCEEDED(get_slot(vm, "my_player_nr", player_nr)) && player_nr < 15) { pl = welt->get_player(player_nr); } sq_poptop(vm); return pl; } const haltestelle_t* param::get(HSQUIRRELVM vm, SQInteger index) { halthandle_t halt = param::get(vm, index); if (!halt.is_bound()) { sq_raise_error(vm, "Invalid halt id %d", halt.get_id()); } return halt.get_rep(); } planquadrat_t* param::get(HSQUIRRELVM vm, SQInteger index) { koord pos = param::get(vm, index); planquadrat_t *plan = welt->access(pos); if (plan==NULL) { sq_raise_error(vm, "Coordinate out of range (%s)", pos.get_str()); } return plan; } grund_t* param::get(HSQUIRRELVM vm, SQInteger index) { koord3d pos = param::get(vm, index); grund_t *gr = welt->lookup(pos); if (gr==NULL) { gr = welt->lookup_kartenboden(pos.get_2d()); } if (gr==NULL) { sq_raise_error(vm, "Coordinate out of range (%s)", pos.get_str()); } return gr; } SQInteger param::push(HSQUIRRELVM vm, grund_t* const& v) { if (v) { koord k = v->get_pos().get_2d(); // transform coordinates coordinate_transform_t::koord_w2sq(k); return push_instance(vm, "tile_x", k.x, k.y, v->get_pos().z); } else { sq_pushnull(vm); return 1; } } scenario_t* param::get(HSQUIRRELVM, SQInteger) { return welt->get_scenario(); } SQInteger param::push(HSQUIRRELVM vm, schedule_entry_t const& v) { return push_instance(vm, "schedule_entry_x", v.pos, v.minimum_loading, v.waiting_time); } SQInteger param::push(HSQUIRRELVM vm, schedule_t* const& v) { return param::push(vm, v); } SQInteger param::push(HSQUIRRELVM vm, const schedule_t* const& v) { if (v) { return push_instance(vm, "schedule_x", v->get_waytype(), v->entries); } else { sq_pushnull(vm); return 1; } } settings_t* param::get(HSQUIRRELVM, SQInteger) { return &welt->get_settings(); } simline_t* param::get(HSQUIRRELVM vm, SQInteger index) { linehandle_t line = param::get(vm, index); if (!line.is_bound()) { sq_raise_error(vm, "Invalid line id %d", line.get_id()); } return line.get_rep(); } stadt_t* param::get(HSQUIRRELVM vm, SQInteger index) { koord pos = param::get(vm, index); return welt->find_nearest_city(pos); } SQInteger param::push(HSQUIRRELVM vm, stadt_t* const& v) { if (v) { koord k = v->get_pos(); // transform coordinates coordinate_transform_t::koord_w2sq(k); return push_instance(vm, "city_x", k.x, k.y); } else { sq_pushnull(vm); return 1; } } karte_t* param::get(HSQUIRRELVM, SQInteger) { return welt; } SQInteger param::push(HSQUIRRELVM vm, karte_t* const&) { sq_pushnull(vm); return 1; } tool_t* param::get(HSQUIRRELVM vm, SQInteger index) { my_tool_t *mtool = get_attached_instance(vm, index, param::tag()); if (mtool) { return mtool->tool; } return NULL; } }; simutrans-124.3/src/simutrans/script/api_param.h000066400000000000000000000403271474050137200220030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_API_PARAM_H #define SCRIPT_API_PARAM_H /** @file api_param.h templates for transfer of function call parameters */ #include "../../squirrel/squirrel.h" #include "../obj/simobj.h" #include "../simtypes.h" #include "../tpl/quickstone_tpl.h" #include "../utils/cbuffer.h" class baum_t; class bruecke_t; class convoi_t; class fabrik_t; class factory_supplier_desc_t; class factory_product_desc_t; class field_t; class gebaeude_t; class grund_t; class haltestelle_t; class karte_t; class karte_ptr_t; class koord; class koord3d; class label_t; class leitung_t; class loadsave_t; struct schedule_entry_t; struct my_ribi_t; struct my_slope_t; struct my_koord3d; class planquadrat_t; class plainstring; class scenario_t; class schedule_t; class settings_t; class simline_t; class player_t; class stadt_t; class tunnel_t; class tool_t; class ware_production_t; class weg_t; class wayobj_t; class way_builder_t; /** * @namespace script_api The namespace contains all functions necessary to communicate * between simutrans and squirrel: transfer parameters, export classes and functions. * * @brief API simutrans <-> squirrel */ namespace script_api { /// pointer to the world extern karte_ptr_t welt; // forward declaration struct mytime_t; struct mytime_ticks_t; struct mytool_data_t; /** * Templated interface to transfer variables from / to squirrel. */ template struct param { /** * Gets parameters for calls to c++ functions from stack. * @param index on stack * @return value of parameter */ #ifdef DOXYGEN static T get(HSQUIRRELVM vm, SQInteger index); #endif /** * Pushes parameters for calls to squirrel functions on stack. * @return positive value for success, negative for failure */ #ifdef DOXYGEN static SQInteger push(HSQUIRRELVM vm, T const& v); #endif /// typemask: this squirrel type needs to be provided when calling c++ function static const char* typemask() { return "."; } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { return "any_x"; } }; /** * Create slots in table/class on the stack: * it has the same effect as 'table.name <- value'. * * @tparam T type of the new value * @param name name of the slot to be created * @param value value to be set * @param static_ true if this should be a static class member * @param index of table/instance/etc on the stack * @returns positive value on success, negative on failure */ template SQInteger create_slot(HSQUIRRELVM vm, const char* name, T const& value, bool static_ = false, SQInteger index = -1) { sq_pushstring(vm, name, -1); if (SQ_SUCCEEDED(param::push(vm, value))) { SQInteger new_index = index > 0 ? index : index-2; return sq_newslot(vm, new_index, static_); } else { sq_pop(vm, 1); /* pop name */ return SQ_ERROR; } } /** * Sets value to existing variable in table, instance etc at index @p index. * @tparam T type of the new value * @param name name of the slot to be created * @param value value to be set * @param index of table/instance/etc on the stack * @returns positive value on success, negative on failure */ template SQInteger set_slot(HSQUIRRELVM vm, const char* name, T const& value, SQInteger index = -1) { sq_pushstring(vm, name, -1); if (SQ_SUCCEEDED(param::push(vm, value))) { SQInteger new_index = index > 0 ? index : index-2; return sq_set(vm, new_index); } else { sq_pop(vm, 1); /* pop name */ return SQ_ERROR; } } /** * Gets value to existing variable in table, instance etc at index @p index. * @tparam T type of the new value * @param name name of the slot to be created * @param value will be set upon success * @param index of table/instance/etc on the stack * @returns positive value on success, negative on failure */ template SQInteger get_slot(HSQUIRRELVM vm, const char* name, T& value, SQInteger index = -1) { sq_pushstring(vm, name, -1); SQInteger new_index = index > 0 ? index : index-1; if (SQ_SUCCEEDED(sq_get(vm, new_index))) { value = param::get(vm, -1); sq_pop(vm, 1); return SQ_OK; } return SQ_ERROR; } /** * partial specialization for 'const T*' types */ template struct param { /** * Gets parameters for calls to c++ functions from stack. * * @param vm * @param index on stack * @return value of parameter */ static const T* get(HSQUIRRELVM vm, SQInteger index) { return param::get(vm, index); } /** * Pushes parameters for calls to squirrel functions on stack. * * @param vm * @return positive value for success, negative for failure */ static SQInteger push(HSQUIRRELVM vm, const T* const& v) { return param::push(vm, v); } /// typemask: this squirrel type needs to be provided when calling c++ function static const char* typemask() { return param::typemask(); } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { return param::squirrel_type(); } }; /** * partial specialization for 'const T' types */ template struct param { /** * Gets parameters for calls to c++ functions from stack. * * @param vm * @param index on stack * @return value of parameter */ static const T get(HSQUIRRELVM vm, SQInteger index) { return param::get(vm, index); } /** * Pushes parameters for calls to squirrel functions on stack. * @return positive value for success, negative for failure */ static SQInteger push(HSQUIRRELVM vm, T const& v) { return param::push(vm, v); } /// typemask: this squirrel type needs to be provided when calling c++ function static const char* typemask() { return param::typemask(); } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { return param::squirrel_type(); } }; /** * partial specialization for 'const T&' types */ template struct param { /** * Pushes parameters for calls to squirrel functions on stack. * @return positive value for success, negative for failure */ static SQInteger push(HSQUIRRELVM vm, const T& v) { return param::push(vm, v); } /// typemask: this squirrel type needs to be provided when calling c++ function static const char* typemask() { return param::typemask(); } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { return param::squirrel_type(); } }; /** * partial specialization for container types */ template< template class vector, class T> struct param< vector > { /** * Pushes parameters for calls to squirrel functions on stack. * @return positive value for success, negative for failure */ static SQInteger push(HSQUIRRELVM vm, vector const& v) { sq_newarray(vm, 0); for(auto const&i : v) { if (SQ_SUCCEEDED(param::push(vm, i))) { sq_arrayappend(vm, -2); } else { // error sq_poptop(vm); return SQ_ERROR; } } return 1; } /// squirrel_type corresponding to the c++ type/class static const char* squirrel_type() { static cbuffer_t buf; buf.clear(); buf.printf("array<%s>", param::squirrel_type() ); return buf; } }; /** * partial specialization for *handle_t types */ // declared here, implementation in api_class.h, // which has to be included if necessary template struct param< quickstone_tpl >; /** * partial specialization for function pointers, * used in api_function.h */ template struct param { // return type of return value static const char* squirrel_type() { return param::squirrel_type(); } static const char* typemask() { return param::typemask(); } }; template<> struct param { static const char* squirrel_type() { return "void"; } static const char* typemask() { return ""; } }; #define declare_types(mask, sqtype) \ static const char* typemask() { return mask; } \ static const char* squirrel_type() \ { \ return sqtype; \ } /// macro to declare specialized param template #define declare_specialized_param(T, mask, sqtype) \ template<> struct param { \ static T get(HSQUIRRELVM vm, SQInteger index); \ static SQInteger push(HSQUIRRELVM vm, T const& v);\ static void* tag(); \ declare_types(mask, sqtype); \ }; /// macro to only define typemask for specialized param template /// if only 'const class*' is defined then parameter mask must be defined for 'class *' too. #define declare_param_mask(T, mask, sqtype) \ template<> struct param { \ declare_types(mask, sqtype) \ }; /// macro to declare fake types /// for documentation purposes #define declare_fake_param(T, sqtype) \ class T { public: T() {}; }; \ template<> struct param { \ static T get(HSQUIRRELVM, SQInteger) { return T(); } \ declare_types(".", sqtype); \ }; // macro to declare enums #define declare_enum_param(T, inttype, sqtype) \ template<> struct param { \ static T get(HSQUIRRELVM vm, SQInteger index) { return (T)param::get(vm, index); } \ static SQInteger push(HSQUIRRELVM vm, T const& v) { return param::push(vm, v); } \ declare_types("i", sqtype); \ }; // no typemask, as we call to_bool declare_specialized_param(bool, ".", "bool"); declare_specialized_param(uint8, "i", "integer"); declare_specialized_param(sint8, "i", "integer"); declare_specialized_param(uint16, "i", "integer"); declare_specialized_param(sint16, "i", "integer"); declare_specialized_param(uint32, "i", "integer"); declare_specialized_param(sint32, "i", "integer"); declare_specialized_param(uint64, "i", "integer"); declare_specialized_param(sint64, "i", "integer"); declare_enum_param(waytype_t, sint16, "way_types"); declare_enum_param(systemtype_t, uint8, "way_system_types"); declare_enum_param(obj_t::typ, uint8, "map_objects"); declare_enum_param(climate, uint8, "climates"); declare_specialized_param(my_ribi_t, "i", "dir"); declare_specialized_param(my_slope_t, "i", "slope"); declare_specialized_param(double, "i|f", "float"); declare_specialized_param(const char*, ".", "string"); // no string typemask, as we call to_string declare_specialized_param(plainstring, ".", "string"); declare_specialized_param(koord, "t|x|y", "coord"); declare_specialized_param(koord3d, "t|x|y", "coord3d"); declare_specialized_param(my_koord3d, "t|x|y", "coord3d"); declare_specialized_param(convoi_t*, "t|x|y", "convoy_x"); declare_specialized_param(fabrik_t*, "t|x|y", "factory_x"); declare_specialized_param(const fabrik_t*, "t|x|y", "factory_x"); declare_specialized_param(grund_t*, "t|x|y", "tile_x"); declare_specialized_param(const haltestelle_t*, "t|x|y", "halt_x"); declare_param_mask(haltestelle_t*, "t|x|y", "halt_x"); declare_specialized_param(karte_t*, ".", "world"); declare_specialized_param(planquadrat_t*, "t|x|y", "square_x"); declare_specialized_param(settings_t*, "t|x|y", "settings"); declare_specialized_param(schedule_t*, "t|x|y", "schedule_x"); declare_specialized_param(const schedule_t*, "t|x|y", "schedule_x"); declare_specialized_param(schedule_entry_t, "t|x|y", "schedule_entry_x"); declare_specialized_param(mytime_t, "i|t|x|y", "time_x"); declare_specialized_param(mytime_ticks_t, "i|t|x|y", "time_ticks_x"); declare_specialized_param(mytool_data_t, "i|t|x|y", "tool_data_x"); declare_specialized_param(scenario_t*, "t|x|y", ""); declare_specialized_param(simline_t*, "t|x|y", "line_x"); declare_specialized_param(player_t*, "t|x|y", "player_x"); declare_specialized_param(stadt_t*, "t|x|y", "city_x"); declare_specialized_param(const ware_production_t*, "t|x|y", "factory_production_x"); declare_specialized_param(const factory_supplier_desc_t*, "t|x|y", "factory_production_x"); declare_specialized_param(const factory_product_desc_t*, "t|x|y", "factory_production_x"); declare_param_mask(ware_production_t*, "t|x|y", "factory_production_x"); declare_specialized_param(tool_t*, "x", "command_x"); declare_specialized_param(way_builder_t*, "t|x|y", "way_planner_x"); // export of obj_t derived classes in api/map_objects.cc declare_specialized_param(obj_t*, "t|x|y", "map_object_x"); declare_specialized_param(baum_t*, "t|x|y", "tree_x"); declare_specialized_param(gebaeude_t*, "t|x|y", "building_x"); declare_specialized_param(label_t*, "t|x|y", "label_x"); declare_specialized_param(leitung_t*, "t|x|y", "powerline_x"); declare_specialized_param(weg_t*, "t|x|y", "way_x"); declare_specialized_param(field_t*, "t|x|y", "field_x"); declare_specialized_param(wayobj_t*, "t|x|y", "wayobj_x"); declare_specialized_param(bruecke_t*, "t|x|y", "bridge_x"); declare_specialized_param(tunnel_t*, "t|x|y", "tunnel_x"); /** * Returns the player associated to the script * (or NULL for scenarios) */ player_t* get_my_player(HSQUIRRELVM vm); // trivial specialization for zero arguments inline SQInteger push_param(HSQUIRRELVM) { return 0; } /** * Pushes (recursively) all arguments on the stack. * First argument is pushed first. * @returns number of arguments (or SQ_ERROR) */ template SQInteger push_param(HSQUIRRELVM vm, const A1 & a1, const As &... as) { // push first parameter if (SQ_SUCCEEDED(script_api::param::push(vm, a1))) { // push the other parameters int res = push_param(vm, as...); if (SQ_SUCCEEDED(res)) { return res+1; } else { // error: pop our parameter sq_poptop(vm); } } return -1; } /** * Templated interface to declare free variables for * c++ function calls */ template struct freevariable : freevariable { using base = freevariable; A1 arg1; freevariable(const A1 & a1, const As &... as) : base(as...), arg1(a1) {} /** * Pushes the free variables. Lifo. * @returns number of pushed parameters */ SQInteger push(HSQUIRRELVM vm) const { int res = base::push(vm); if (SQ_SUCCEEDED(res)) { // first parameter is pushed last if (SQ_SUCCEEDED(script_api::param::push(vm, arg1))) { return res+1; } else { sq_pop(vm, res); // pop other parameters in case of failure } } return -1; } }; template struct freevariable { A1 arg1; freevariable(const A1 & a1) : arg1(a1) {} /** * Pushes the free variables * @returns number of pushed parameters */ SQInteger push(HSQUIRRELVM vm) const { return push_param(vm, arg1); } }; /** * Static class to handle the translation of world coordinates (which are sensible to rotation) * to script coordinates (that are independent of rotation). */ class coordinate_transform_t { private: /// Stores how many times initial map was rotated. /// Scripts do not take care of rotated maps. /// Coordinates will be translated between in-game coordinates and script coordinates. /// First v.m. to be started sets this value static uint8 rotation; public: /// called if a new world is initialized static void new_world() { rotation=4; /*invalid*/ } /// inits rotation from karte_t::settings static void initialize(); /// keep track of rotation static void rotate90() { if (rotation<4) rotation = (rotation+1)&3; } /// read/save rotation to stay consistent after saving & loading static void rdwr(loadsave_t*); /** * rotate actual world coordinates back, * coordinates after transform are like in the * scenario's original savegame */ static void koord_w2sq(koord &); /** * rotate original coordinates to actual world coordinates */ static void koord_sq2w(koord &); /** * rotate actual world coordinates direction to original direction */ static void ribi_w2sq(ribi_t::ribi &r); /** * rotate original direction to actual world coordinates direction */ static void ribi_sq2w(ribi_t::ribi &r); /** * rotate actual slope to original slope */ static void slope_w2sq(slope_t::type &s); /** * rotate original slope to actual slope */ static void slope_sq2w(slope_t::type &s); static uint8 get_rotation() { return rotation; } }; /// called by karte_t directly void rotate90(); /// called by karte_t directly void new_world(); }; // end of namespace #endif simutrans-124.3/src/simutrans/script/dynamic_string.cc000066400000000000000000000160721474050137200232220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "dynamic_string.h" #include "script.h" #include "../sys/simsys.h" #include "../world/simworld.h" #include "../network/network.h" #include "../network/network_cmd_scenario.h" #include "../dataobj/environment.h" #include "../dataobj/loadsave.h" #include "../player/simplay.h" #include "../tpl/plainstringhashtable_tpl.h" #include "../utils/cbuffer.h" #include "../utils/simstring.h" uint32 dynamic_string::CACHE_TIME = 1000; // 10s struct cached_string_t { plainstring result; uint32 time; dynamic_string *listener; cached_string_t(const char* str, uint32 t, dynamic_string *l) : result(str), time(t), listener(l) {} cached_string_t(loadsave_t* file) { time = dr_time() - 10000; listener = NULL; rdwr(file); } void rdwr(loadsave_t* file) { file->rdwr_str(result); } }; static plainstringhashtable_tpl cached_results; cached_string_t* get_cached_result(const char* function, uint32 cache_time) { cached_string_t *entry = cached_results.get(function); if (entry) { if (dr_time() - entry->time > cache_time) { entry = NULL; } } return entry; } dynamic_string::~dynamic_string() { for(auto &iter : cached_results) { if (iter.value->listener == this) { iter.value->listener = NULL; } } } void dynamic_string::init(script_vm_t *script) { while(!cached_results.empty()) { delete cached_results.remove_first(); } script->register_callback(&dynamic_string::record_result, "dynamicstring_record_result"); } void dynamic_string::rdwr_cache(loadsave_t *file) { uint32 count = cached_results.get_count(); file->rdwr_long(count); if (file->is_loading()) { // clear list while(!cached_results.empty()) { delete cached_results.remove_first(); } for(uint32 i=0; irdwr_str(key); cached_results.set(key, new cached_string_t(file)); } } else { for(auto &iter : cached_results) { file->rdwr_str(iter.key); iter.value->rdwr(file); } } } void dynamic_string::update(script_vm_t *script, player_t *player, bool force_update) { cbuffer_t buf; buf.printf("%s(%d)", method, player ? player->get_player_nr() : PLAYER_UNOWNED); const char* function = (const char*)buf; plainstring s; if (script) { cached_string_t *entry = NULL; if (!force_update) { entry = get_cached_result(function, CACHE_TIME); } if (entry) { // valid cache entry s = entry->result.c_str(); } else { script->prepare_callback("dynamicstring_record_result", 2, (const char*)buf, (const char*)""); // call script; if QUEUE, it may continue to run another script in the background which alters then the map const char* err = script->call_function(script_vm_t::QUEUE, method, s, (uint8)(player ? player->get_player_nr() : PLAYER_UNOWNED)); if (!script_vm_t::is_call_suspended(err)) { if ( s != (const char*)str) { changed = true; str = s; } } else { // activate listener cached_string_t *entry = cached_results.get((const char*)buf); if (entry == NULL) { cached_results.set((const char*)buf, new cached_string_t(NULL, dr_time(), this)); } else { entry->listener = this; // return cached value for now; will be changed after callback returns s = entry->result.c_str(); } } script->clear_pending_callback(); // .. and store result record_result(function, s); } } else { if (env_t::networkmode && !env_t::server) { s = dynamic_string::fetch_result( function, NULL, this, force_update); if ( s == NULL) { s = "Waiting for server response..."; } } } if ( s != (const char*)str) { str = s; changed = true; } } const char* dynamic_string::fetch_result(const char* function, script_vm_t *script, dynamic_string *listener, bool force_update) { //dbg->warning("dynamic_string::fetch_result", "function = '%s'", function); cached_string_t *entry = cached_results.get(function); bool const needs_update = entry == NULL || force_update || (dr_time() - entry->time > CACHE_TIME); if (needs_update) { if (script) { // suspended calls have to be caught by script callbacks plainstring str; if(call_script(function, script, str)) { record_result(function, str); } } else { if (entry == NULL) { cached_string_t *old = cached_results.set(function, new cached_string_t(NULL, dr_time(), listener)); assert(old == NULL); (void)old; } // send request nwc_scenario_t *nwc = new nwc_scenario_t(); nwc->function = function; nwc->what = nwc_scenario_t::CALL_SCRIPT_ANSWER; network_send_server(nwc); } // entry maybe invalid now, fetch again entry = cached_results.get(function); } return entry ? entry->result.c_str() : NULL; } bool dynamic_string::record_result(const char* function, plainstring result) { cached_string_t *new_entry = new cached_string_t(result, dr_time(), NULL); cached_string_t *entry = cached_results.set(function, new_entry); if (entry == NULL) { return false; } if (dynamic_string *dyn = entry->listener) { new_entry->listener = dyn; if (dyn->str != (const char*) result) { dyn->str = result; dyn->changed = true; } } delete entry; return true; } /// Struct for checking number of parameters struct method_param_t { const char* name; int nparam; }; /// Static table with script methods that can be called static const method_param_t scenario_methods[] = { { "is_scenario_completed", 1 }, { "get_info_text", 1 }, { "get_goal_text", 1 }, { "get_rule_text", 1 }, { "get_result_text", 1 }, { "get_about_text", 1 }, { "get_short_description", 1} }; void get_scenario_completion(plainstring &res, int player_nr) { cbuffer_t buf; sint32 percent = script_api::welt->get_scenario()->get_completion(player_nr); buf.printf("%d", percent); res = (const char*)buf; } bool dynamic_string::call_script(const char* function, script_vm_t* script, plainstring& str) { int nparams = -1; size_t n = strcspn(function, "("); char *method = new char[n+1]; tstrncpy(method, function, n+1); // check method name for(uint i=0; i< lengthof(scenario_methods); i++) { if (strcmp(method, scenario_methods[i].name)==0) { nparams = scenario_methods[i].nparam; break; } } if (nparams == -1) { // unknown method delete [] method; return false; } // scan for params int params[] = {0, 0, 0, 0}; assert( nparams+1 < (int)lengthof(params) ); const char* p = function+n; if (*p) p++; bool ok = true; for(int i=0; icall_function(script_vm_t::QUEUE, method, str); break; case 1: if ( strcmp(method, "is_scenario_completed")==0 ) { get_scenario_completion(str, params[0]); } else { err = script->call_function(script_vm_t::QUEUE, method, str, params[0]); } break; default: assert(0); } if (script_vm_t::is_call_suspended(err)) { ok = false; } } // cleanup delete [] method; return ok; } simutrans-124.3/src/simutrans/script/dynamic_string.h000066400000000000000000000055721474050137200230670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_DYNAMIC_STRING_H #define SCRIPT_DYNAMIC_STRING_H /** @file dynamic_string.h strings that can be asynchronously changed by scripts */ #include "../utils/plainstring.h" class script_vm_t; class player_t; class loadsave_t; /** * Class of strings to hold result of text-returning script functions. * * Can communicate with server to update scenario text on clients, which * do not know the script. Used in scenario_t and scenario_info_t. * * Results will be cached, frequent calls to update() will only update * the text if some time threshold is exceeded. */ class dynamic_string { private: /// holds result of script function plainstring str; /// true if text changed since last call to clear_changed() bool changed; /// script method to be called to retrieve text const char* method; public: // time between updates to strings static uint32 CACHE_TIME; dynamic_string(const char *method_) : str(NULL), changed(false), method(method_) { } ~dynamic_string(); /** * Update the string, calls fetch_result(). * * @param script the scripting engine, if script == NULL then this needs server communication * @param player * @param force_update will force to update even if cache is still valid */ void update(script_vm_t *script, player_t *player, bool force_update=false); operator const plainstring& () const { return str; } operator const char* () const { return (const char*)str; } bool has_changed() const { return changed; } void clear_changed() { changed = false; } /** * At client: fetch result from server. * At server: call script to get immediate result. * * Results will be stored into a hashtable, fetch requests will be send only if * some time threshold is exceeded (or force_update is true). * * @param function script function incl arguments to be called * @param script * @param listener will be updated should the result change in future * @param force_update force an update, do not use cached string * @returns string or NULL if nothing available (yet) */ static const char* fetch_result(const char* function, script_vm_t *script, dynamic_string *listener=NULL, bool force_update=false); /** * Clear internal cache. Registers callback method. */ static void init(script_vm_t *script); /** * Cache result of script at server, * immediately update the listening dynamic_string. * @returns dummy value */ static bool record_result(const char* function, plainstring result); static void rdwr_cache(loadsave_t *file); private: /** * Calls a script * * @param function is the full function call including integer parameters * @param script * @param result * @returns true if call was successfull */ static bool call_script(const char* function, script_vm_t* script, plainstring& result); }; #endif simutrans-124.3/src/simutrans/script/export_objs.cc000066400000000000000000000016201474050137200225370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "export_objs.h" #include #include "api_function.h" #include "api_class.h" #include "api/api.h" void register_export_function(HSQUIRRELVM vm, bool scenario) { script_api::start_squirrel_type_logging(scenario ? "scenario" : "ai"); sq_pushroottable(vm); export_city(vm); export_control(vm); export_convoy(vm); export_factory(vm); export_goods_desc(vm); export_gui(vm, scenario); export_halt(vm); export_line(vm); export_map_objects(vm); export_player(vm, scenario); if (scenario) { export_scenario(vm); } export_schedule(vm); export_settings(vm); export_simple(vm); export_string_methods(vm); export_tiles(vm); export_world(vm, scenario); export_pathfinding(vm); export_commands(vm); sq_pop(vm, 1); // root table script_api::end_squirrel_type_logging(); } simutrans-124.3/src/simutrans/script/export_objs.h000066400000000000000000000006221474050137200224020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_EXPORT_OBJS_H #define SCRIPT_EXPORT_OBJS_H #include "../../squirrel/squirrel.h" /** * Registers the complete export interface. * * @param vm * @param scenario true if exporting is for scenario scripting */ void register_export_function(HSQUIRRELVM vm, bool scenario); #endif simutrans-124.3/src/simutrans/script/script.cc000066400000000000000000000521451474050137200215150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "script.h" #include #include #include "../../squirrel/sqstdaux.h" // for error handlers #include "../../squirrel/sqstdio.h" // for loadfile #include "../../squirrel/sqstdstring.h" // export for scripts #include "../../squirrel/sqstdmath.h" // export for scripts #include "../../squirrel/sqstdsystem.h" // export for scripts #include "../../squirrel/sq_extensions.h" // for sq_call_restricted #include "../utils/log.h" #include "../tpl/inthashtable_tpl.h" #include "../tpl/vector_tpl.h" // for error popups #include "../gui/help_frame.h" #include "../gui/simwin.h" #include "../utils/cbuffer.h" #include "../utils/plainstring.h" namespace script_api { bool pause_game(); // api_control.cc } // debug: store stack pointer #define BEGIN_STACK_WATCH(v) int stack_top = sq_gettop(v); // debug: compare stack pointer with expected stack pointer, raise warning if failure #define END_STACK_WATCH(v, delta) if ( (stack_top+(delta)) != sq_gettop(v)) { dbg->warning( __FUNCTION__, "(%d) stack in %d expected %d out %d", __LINE__,stack_top,stack_top+(delta),sq_gettop(v)); } void script_vm_t::printfunc(HSQUIRRELVM vm, const SQChar *s, ...) { va_list vl; va_start(vl, s); if (script_vm_t *script = (script_vm_t*)sq_getforeignptr(vm)) { script->log->vmessage("Script", "Print", s, vl); } va_end(vl); } void script_vm_t::errorfunc(HSQUIRRELVM vm, const SQChar *s_, ...) { char *s = strdup(s_); char *s_dup = s; // remove these linebreaks while (s && *s=='\n') s++; while (s && s[strlen(s)-1]=='\n') s[strlen(s)-1]=0; // get failed script script_vm_t *script = (script_vm_t*)sq_getforeignptr(vm); if (script) { va_list vl; va_start(vl, s_); script->log->vmessage("Script", "Error", s, vl); va_end(vl); } // only one error message at a time - hopefully // collect into static buffer static cbuffer_t buf; if (strcmp(s, "")==0) { // start of error message buf.clear(); buf.printf("An error occurred within a script!
\n"); } else if (strcmp(s, "
")==0) { // end of error message help_frame_t *win = dynamic_cast(win_get_magic(magic_script_error)); if (win == NULL) { win = new help_frame_t(); create_win( win, w_info, magic_script_error); } win->set_text(buf); win->set_name("Script error occurred"); if (script) { script->set_error(buf); // pause game if (script->pause_on_error) { script_api::pause_game(); } } } else { va_list vl; va_start(vl, s_); buf.vprintf(s, vl); va_end(vl); buf.append("
"); } free(s_dup); } void export_include(HSQUIRRELVM vm, const char* include_path); // api_include.cc // virtual machine script_vm_t::script_vm_t(const char* include_path_, const char* log_name) { pause_on_error = false; vm = sq_open(1024); sqstd_seterrorhandlers(vm); sq_setprintfunc(vm, printfunc, errorfunc); register_vm(vm); log = new log_t(log_name, true, true, true, "script engine started.\n"); // store ptr to us in vm sq_setforeignptr(vm, this); // create thread, and put it into registry-table sq_pushregistrytable(vm); sq_pushstring(vm, "thread", -1); thread = sq_newthread(vm, 1024); sq_newslot(vm, -3, false); register_vm(thread); // create queue array sq_pushstring(vm, "queue", -1); sq_newarray(vm, 0); sq_newslot(vm, -3, false); // create queued-callbacks array sq_pushstring(vm, "queued_callbacks", -1); sq_newarray(vm, 0); sq_newslot(vm, -3, false); // pop registry sq_pop(vm, 1); // store ptr to us in vm sq_setforeignptr(vm, this); sq_setforeignptr(thread, this); error_msg = NULL; include_path = include_path_; // register libraries sq_pushroottable(vm); sqstd_register_stringlib(vm); sqstd_register_mathlib(vm); sqstd_register_systemlib(vm); sq_pop(vm, 1); // export include command export_include(vm, include_path); // initialize coordinate and rotation handling script_api::coordinate_transform_t::initialize(); } script_vm_t::~script_vm_t() { unregister_vm(thread); unregister_vm(vm); // remove from suspended calls list suspended_scripts_t::remove_vm(thread); suspended_scripts_t::remove_vm(vm); // close vm, also closes thread sq_close(vm); delete log; } const char* script_vm_t::call_script(const char* filename) { // load script if (!SQ_SUCCEEDED(sqstd_loadfile(vm, filename, true))) { return "Reading / compiling script failed"; } // call it sq_pushroottable(vm); if (!SQ_SUCCEEDED(sq_call_restricted(vm, 1, SQFalse, SQTrue, 100000))) { sq_pop(vm, 1); // pop script return "Call script failed"; } if (sq_getvmstate(vm) == SQ_VMSTATE_SUSPENDED) { set_error("Calling scriptfile took too long"); return get_error(); } sq_pop(vm, 1); // pop script return NULL; } const char* script_vm_t::eval_string(const char* squirrel_string) { if (squirrel_string == NULL) { return NULL; } HSQUIRRELVM &job = thread; // log string printfunc(job, "String to compile:\n%s\n<<<\n", squirrel_string); // compile string if (!SQ_SUCCEEDED(sq_compilebuffer(job, squirrel_string, strlen(squirrel_string), "userdefinedstringmethod", true))) { set_error("Error compiling string buffer"); return get_error(); } // execute sq_pushroottable(job); // stack: closure, root table (1st param) return intern_finish_call(job, QUEUE, 1, true); } bool script_vm_t::is_call_suspended(const char* err) { return (err != NULL) && ( strcmp(err, "suspended") == 0); } const char* script_vm_t::intern_prepare_call(HSQUIRRELVM &job, call_type_t ct, const char* function) { const char* err = NULL; switch (ct) { case FORCE: case FORCEX: job = vm; // block calls to suspendable functions sq_block_suspend(job, function); break; case TRY: if (sq_getvmstate(thread) == SQ_VMSTATE_SUSPENDED) { return "suspended"; } // fall through case QUEUE: job = thread; break; } dbg->message("script_vm_t::intern_prepare_call", "ct=%d function=%s stack=%d", ct, function, sq_gettop(job)); sq_pushroottable(job); sq_pushstring(job, function, -1); // fetch function from root if (SQ_SUCCEEDED(sq_get(job,-2))) { sq_remove(job, -2); // root table sq_pushroottable(job); } else { err = "Function not found"; sq_poptop(job); // array, root table } return err; // stack: closure, root table (1st param) } const char* script_vm_t::intern_finish_call(HSQUIRRELVM job, call_type_t ct, int nparams, bool retvalue) { BEGIN_STACK_WATCH(job); // stack: closure, nparams*objects const char* err = NULL; // only call the closure if vm is idle (maybe in RUN state) bool suspended = sq_getvmstate(job) != SQ_VMSTATE_IDLE; // check queue, if not empty resume first job in queue if (!suspended && ct != FORCE && ct != FORCEX) { sq_pushregistrytable(job); sq_pushstring(job, "queue", -1); sq_get(job, -2); // stack: registry, queue if (sq_getsize(job, -1) > 0) { suspended = true; } sq_pop(job, 2); } // queue function call? if (suspended && ct == QUEUE) { intern_queue_call(job, nparams, retvalue); err = "suspended"; // stack: clean } if (suspended && ct != FORCE && ct != FORCEX) { intern_resume_call(job); } if (!suspended || ct == FORCE || ct == FORCEX) { // set active callback if call could be suspended if (ct == QUEUE) { intern_make_pending_callback_active(); } // mark as not queued sq_pushregistrytable(job); script_api::create_slot(job, "was_queued", false); sq_poptop(job); END_STACK_WATCH(job,0); err = intern_call_function(job, ct, nparams, retvalue); } return err; } /** * Calls function. If it was a queued call, also calls callbacks. * Stack(job): expects closure, nparam*objects, on exit: return value (or clean stack if failure). * @returns NULL on success, error message or "suspended" otherwise. */ const char* script_vm_t::intern_call_function(HSQUIRRELVM job, call_type_t ct, int nparams, bool retvalue) { BEGIN_STACK_WATCH(job); dbg->message("script_vm_t::intern_call_function", "start: stack=%d nparams=%d ret=%d", sq_gettop(job), nparams, retvalue); const char* err = NULL; uint32 opcodes = ct == FORCEX ? 100000 : 10000; // call the script if (!SQ_SUCCEEDED(sq_call_restricted(job, nparams, retvalue, ct == FORCE || ct == FORCEX, opcodes))) { err = "Call function failed"; retvalue = false; } // call not suspended if (sq_getvmstate(job) != SQ_VMSTATE_SUSPENDED) { // remove closure sq_remove(job, retvalue ? -2 : -1); if (ct == QUEUE && retvalue) { sq_pushregistrytable(job); // notify call backs only if call was queued bool notify = false; script_api::get_slot(job, "was_queued", notify, -1); sq_pop(job, 1); if (notify) { intern_call_callbacks(job); } } END_STACK_WATCH(job, -nparams-1 + retvalue); } else { // call suspended: pop dummy return value if (retvalue) { sq_poptop(job); } // throw error in FORCEd mode if (ct == FORCE || ct == FORCEX) { // not allowed for ct == FORCE sq_raise_error(job, "cannot suspend call to %s", sq_get_suspend_blocker(job)); // wake up to throw error sq_wakeupvm(job, false, retvalue, true /*raise_error*/, true /* throw error*/); retvalue = false; // pop closure and params sq_pop(job, nparams+1); } else { // save retvalue flag, number of parameters sq_pushregistrytable(job); script_api::create_slot(job, "retvalue", retvalue); script_api::create_slot(job, "nparams", nparams); sq_poptop(job); } err = "suspended"; } if (ct == FORCE || ct == FORCEX) { END_STACK_WATCH(job, -nparams-1 + retvalue); sq_block_suspend(job, NULL); } dbg->message("script_vm_t::intern_call_function", "stack=%d err=%s", sq_gettop(job)-retvalue, err); return err; } void script_vm_t::intern_resume_call(HSQUIRRELVM job) { BEGIN_STACK_WATCH(job); // stack: clean // get retvalue flag sq_pushregistrytable(job); bool retvalue = false; script_api::get_slot(job, "retvalue", retvalue, -1); int nparams = 0; script_api::get_slot(job, "nparams", nparams, -1); bool wait = false; script_api::get_slot(job, "wait_external", wait, -1); sq_pop(job, 1); END_STACK_WATCH(job, 0); if (wait) { dbg->message("script_vm_t::intern_resume_call", "waits for external call to be able to proceed"); return; } if (!sq_canresumevm(job)) { // vm waits for return value to suspended call dbg->message("script_vm_t::intern_resume_call", "waiting for return value"); return; } // vm suspended, but not from call to our methods if (nparams < 0) { retvalue = false; } // resume v.m. if (!SQ_SUCCEEDED(sq_resumevm(job, retvalue, 10000))) { retvalue = false; } // if finished, clear stack if (sq_getvmstate(job) != SQ_VMSTATE_SUSPENDED) { if (nparams >=0 ) { BEGIN_STACK_WATCH(job); // remove closure & args for(int i=0; imessage("script_vm_t::intern_resume_call", "in between stack=%d", sq_gettop(job)); END_STACK_WATCH(job, -1-nparams-retvalue); } else { // brute force clean stack sq_settop(job, 0); } // make nparams invalid sq_pushregistrytable(job); script_api::create_slot(job, "nparams", -1); sq_poptop(job); // proceed with next call in queue if (intern_prepare_queued(job, nparams, retvalue)) { const char* err = intern_call_function(job, QUEUE, nparams, retvalue); if (err == NULL && retvalue) { // remove return value: call was queued thus remove return value from stack sq_poptop(job); } } } else { if (retvalue) { sq_poptop(job); } } dbg->message("script_vm_t::intern_resume_call", "stack=%d", sq_gettop(job)); } /** * Stack(job): expects closure, nparams*objects, clean on exit. * Put call into registry.queue, callback into registry.queued_callbacks. * Cleans registry.pending_callback. * @param nparams number of parameter of the queued call * @param retvalue whether the call would return something */ void script_vm_t::intern_queue_call(HSQUIRRELVM job, int nparams, bool retvalue) { BEGIN_STACK_WATCH(job); // stack: closure, nparams*objects // queue call: put closure and parameters in array script_api::param::push(job, retvalue); sq_newarray(job, 0); // to hold parameters for queued calls // stack: closure, nparams*objects, retvalue, array for(int i=nparams+2; i>0; i--) { sq_push(job, -2); sq_arrayappend(job, -2); sq_remove(job, -2); } // stack: array sq_pushregistrytable(job); sq_pushstring(job, "queue", -1); sq_get(job, -2); // stack: array, registry, queue // search queue whether our call is already there sint32 size = sq_getsize(job, -1); bool equal = false; for(sint32 i=0; (imessage("script_vm_t::intern_queue_call", "NOT QUEUED stack=%d", sq_gettop(job)); } sq_pop(job, 3); END_STACK_WATCH(job, -nparams-1); dbg->message("script_vm_t::intern_queue_call", "stack=%d", sq_gettop(job)); // stack: clean } /** * Removes queue(0) and puts it on stack. * Activates callback by intern_make_queued_callback_active(). * Stack(job): on success - closure, nparams*objects, on failure - unchanged. * @param nparams number of parameters of the call on the stack * @param retvalue whether queued call returns something * @returns true if a new queued call is on the stack */ bool script_vm_t::intern_prepare_queued(HSQUIRRELVM job, int &nparams, bool &retvalue) { BEGIN_STACK_WATCH(job); // queued calls sq_pushregistrytable(job); sq_pushstring(job, "queue", -1); sq_get(job, -2); sq_pushinteger(job, 0); if (SQ_SUCCEEDED(sq_get(job, -2))) { // there are suspended jobs // stack: registry, queue, array[ retvalue nparams*objects closure] nparams = -2; while( SQ_SUCCEEDED(sq_arraypop(job, -3-nparams, true))) { nparams++; } retvalue = script_api::param::get(job, -1); sq_poptop(job); intern_make_queued_callback_active(); // stack: registry, queue, array, closure, nparams*objects END_STACK_WATCH(job, nparams+4); // mark this call as queued sq_pushstring(job, "was_queued", -1); script_api::param::push(job, true); sq_createslot(job, -6-nparams); // cleanup sq_remove(job, -2-nparams); sq_arrayremove(job, -2-nparams, 0); sq_remove(job, -2-nparams); sq_remove(job, -2-nparams); // stack: closure, nparams*objects dbg->message("script_vm_t::intern_prepare_queued", "stack=%d nparams=%d ret=%d", sq_gettop(job), nparams, retvalue); END_STACK_WATCH(job, nparams+1); return true; } else { // no suspended jobs: clean stack sq_pop(job, 2); } END_STACK_WATCH(job, 0); return false; } /** * Prepare function call. * Stack(vm): pushes registry, nret, closure, root. */ bool script_vm_t::intern_prepare_pending_callback(const char* function, sint32 nret) { BEGIN_STACK_WATCH(vm); sq_pushregistrytable(vm); script_api::param::push(vm, nret+1); // +1 to account for root table sq_pushstring(vm, function, -1); bool ok = SQ_SUCCEEDED(sq_get(vm, -3)); if (ok) { // stack: registry, nret, closure, root sq_pushroottable(vm); } else { // stack: clear sq_pop(vm, 2); } END_STACK_WATCH(vm, ok ? 4 : 0); return ok; } /** * Sets registry.pending_callback. * Stack(vm): expects registry, nret, closure, nparams*objects; clears upon exit. */ void script_vm_t::intern_store_pending_callback(sint32 nparams) { BEGIN_STACK_WATCH(vm); // stack: registry, nret, closure, nparams*objects // put closure and parameters in array sq_newarray(vm, 0); // stack: registry, nret, closure, nparams*objects, array for(int i=0; ipending_callback ] sq_createslot(vm, -3); } else { // stack: registry, "..", array[] sq_poptop(vm); // delete active_callbacks slot sq_deleteslot(vm, -2, false); } sq_poptop(vm); END_STACK_WATCH(vm,0); } /** * * * Stack(job): return value, unchanged */ void script_vm_t::intern_call_callbacks(HSQUIRRELVM job) { BEGIN_STACK_WATCH(job); sq_pushregistrytable(job); sq_pushstring(job, "active_callbacks", -1); if (SQ_SUCCEEDED( sq_deleteslot(job, -2, true) ) ) { BEGIN_STACK_WATCH(job); if (SQ_SUCCEEDED( sq_arraypop(job, -1, true))) { if (SQ_SUCCEEDED(sq_arraypop(job, -1, true))) { sint32 nret = script_api::param::get(job, -1); sq_poptop(job); BEGIN_STACK_WATCH(job); // stack: retval, registry, active_cb, active_cb[end]=array[ nparams*objects closure] int nparams = -1; while( SQ_SUCCEEDED(sq_arraypop(job, -2-nparams, true))) { nparams++; // replace parameter by return value if (nret > 0 && nret == nparams) { sq_poptop(job); sq_push(job, -4-nparams); } } // stack: retval, registry, active_cb, active_cb[end], closure, nparams*objects sq_call_restricted(job, nparams, false, true, 100); // remove closure and finished callback sq_pop(job, 1); END_STACK_WATCH(job,0); } sq_poptop(job); } END_STACK_WATCH(job,0); sq_poptop(job); } sq_poptop(job); END_STACK_WATCH(job,0); } void script_vm_t::set_my_player(uint8 player_nr) { sq_pushregistrytable(vm); script_api::create_slot(vm, "my_player_nr", player_nr); sq_poptop(vm); } /* -------- management of suspended scripts that wait for return value ----------- */ inthashtable_tpl suspended_scripts_t::suspended_scripts; uint32 suspended_scripts_t::get_unique_key(void* ptr) { uint32 key = (uint32)(size_t)ptr; while (key == 0 || suspended_scripts.get(key)) { key ++; } return key; } void suspended_scripts_t::register_suspended_script(uint32 key, HSQUIRRELVM vm) { suspended_scripts.set(key, vm); // mark vm to wait for external call to allow for wake-up sq_pushregistrytable(vm); bool wait = true; script_api::create_slot(vm, "wait_external", wait); sq_poptop(vm); } HSQUIRRELVM suspended_scripts_t::remove_suspended_script(uint32 key) { return suspended_scripts.remove(key); } void suspended_scripts_t::remove_vm(HSQUIRRELVM vm) { inthashtable_tpl::iterator iter=suspended_scripts.begin(), end=suspended_scripts.end(); for(; iter != end; ) { if ( (*iter).value == vm) { iter = suspended_scripts.erase(iter); } else { ++iter; } } } simutrans-124.3/src/simutrans/script/script.h000066400000000000000000000166341474050137200213620ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_SCRIPT_H #define SCRIPT_SCRIPT_H /** @file script.h handles the virtual machine, interface to squirrel */ #include "api_function.h" #include "api_param.h" #include "../simtypes.h" #include "../../squirrel/squirrel.h" #include "../utils/plainstring.h" #include class log_t; template class inthashtable_tpl; void sq_setwakeupretvalue(HSQUIRRELVM v); //sq_extensions /** * Class providing interface to squirrel's virtual machine. * * Logs output to script.log. * Opens error window in case of script errors. */ class script_vm_t { public: script_vm_t(const char* include_path, const char* log_name); ~script_vm_t(); /** * loads file, calls script * @returns error msg (or NULL if succeeded) */ const char* call_script(const char* filename); /** * compiles and executes given string * @returns error msg (or NULL if succeeded) */ const char* eval_string(const char* squirrel_string); bool uses_vm(HSQUIRRELVM other) const { return vm == other || thread == other; } const HSQUIRRELVM& get_vm() const { return vm; } const char* get_error() const { return error_msg.c_str(); } /** * The script can only act as a certain player. * @param player_nr the number of the player (PLAYER_UNOWNED for scenarios) */ void set_my_player(uint8 player_nr); /// priority of function call enum call_type_t { FORCE, ///< function has to return, raise error if not FORCEX, ///< function has to return, raise error if not, give more opcodes QUEUE, ///< function call can be queued, return value can be propagated by call back TRY ///< function call will not be queued, if virtual machine is suspended just return }; /** * @param err error string returned by call_script * @return whether the call was suspended */ static bool is_call_suspended(const char* err); /** * calls scripted function * @param function function name of squirrel function * @returns error msg (or NULL if succeeded) */ const char* call_function(call_type_t ct, const char* function) { // choose correct vm, push function HSQUIRRELVM job; const char* err = intern_prepare_call(job, ct, function); if (err) { return err; } // now call return intern_finish_call(job, ct, 1, false); } /** * calls scripted function * * @tparam R type of return value * @tparam As types of arguments * @param function function name of squirrel function * @param as any number of arguments passed to squirrel function * @param ret return value of script function is stored here * @returns error msg (or NULL if succeeded), if call was suspended ret is invalid */ template const char* call_function(call_type_t ct, const char* function, R& ret, const As &... as) { // choose correct vm, push function HSQUIRRELVM job; const char* err = intern_prepare_call(job, ct, function); if (err) { return err; } // push parameters int nparam = script_api::push_param(job, as...); if (!SQ_SUCCEEDED(nparam)) { return "error pushing argument"; } // now call err = intern_finish_call(job, ct, nparam+1, true); if (err == NULL) { ret = script_api::param::get(job, -1); sq_poptop(job); } return err; } /** * Registers a c++ function to be available as callback. * A callback is called when a function call got suspended, resumed, and returned something. * @tparam F function signature * @param funcptr function pointer * @param name register callback under this name */ template void register_callback(F funcptr, const char* name) { sq_pushregistrytable(vm); script_api::register_method(vm, funcptr, name); sq_poptop(vm); } /** * Prepares a callback call. * @param function name of function to be called as callback * @param nret the nret-th parameter will be replaced by return value of suspended function. */ template void prepare_callback(const char* function, int nret, const As &... as) { if (intern_prepare_pending_callback(function, nret)) { int nparam = script_api::push_param(vm, as...); assert(SQ_SUCCEEDED(nparam)); // FIXME intern_store_pending_callback(nparam+1); } } /** * Clears pending callback initialized by prepare_callback. */ void clear_pending_callback(); private: /// virtual machine running everything HSQUIRRELVM vm; /// thread in the virtual machine, used to run functions that can be suspended HSQUIRRELVM thread; /// our log file log_t* log; plainstring error_msg; /// path to files to #include plainstring include_path; public: bool pause_on_error; private: /// @{ /// @name Helper functions to call, suspend, queue calls to scripted functions /// prepare function call, used in templated call_function(), sets job to vm that should run function const char* intern_prepare_call(HSQUIRRELVM &job, call_type_t ct, const char* function); /// actually call function, used in templated call_function(), /// does also: resume suspended call, queue current call const char* intern_finish_call(HSQUIRRELVM job, call_type_t ct, int nparams, bool retvalue); /// queues current call static void intern_queue_call(HSQUIRRELVM job, int nparams, bool retvalue); /// resumes a suspended call. calls callbacks. void intern_resume_call(HSQUIRRELVM job); /// calls function. If it was a queued call, also calls callbacks. static const char* intern_call_function(HSQUIRRELVM job, call_type_t ct, int nparams, bool retvalue); /// pops an queued call and puts it on the stack, also activates corresponding callbacks bool intern_prepare_queued(HSQUIRRELVM job, int &nparams, bool &retvalue); /// prepare function call to callback, used in templated prepare_callback() bool intern_prepare_pending_callback(const char* function, sint32 nret); /// saves the callback call (with arguments), used in templated prepare_callback() void intern_store_pending_callback(sint32 nparams); /// pops callback from queued callbacks, and makes it active void intern_make_queued_callback_active(); /// takes pending callback, and makes it active void intern_make_pending_callback_active(); /// calls all active callbacks static void intern_call_callbacks(HSQUIRRELVM job); /// @} /// custom error handler for compile and runtime errors of squirrel scripts static void errorfunc(HSQUIRRELVM vm, const SQChar *s_,...); /// set error message, used in errorhandlers void set_error(const char* error) { error_msg = error; } /// custom print handler static void printfunc(HSQUIRRELVM, const SQChar *s, ...); }; /** * Class to manage all vm's that are suspended and waiting for the return of * a call to a tool. */ class suspended_scripts_t { private: static inthashtable_tpl suspended_scripts; static HSQUIRRELVM remove_suspended_script(uint32 key); public: // generates key from a pointer static uint32 get_unique_key(void* key); static void register_suspended_script(uint32 key, HSQUIRRELVM vm); // remove any reference to given vm static void remove_vm(HSQUIRRELVM vm); template static void tell_return_value(uint32 key, R& ret) { HSQUIRRELVM vm = remove_suspended_script(key); if (vm) { script_api::param::push(vm, ret); sq_setwakeupretvalue(vm); // this vm can be woken up now sq_pushregistrytable(vm); bool wait = false; script_api::create_slot(vm, "wait_external", wait); sq_poptop(vm); } } }; #endif simutrans-124.3/src/simutrans/script/script_loader.cc000066400000000000000000000041041474050137200230330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "script_loader.h" #include "script.h" #include "api/api.h" #include "export_objs.h" #include "../dataobj/environment.h" #include "../utils/cbuffer.h" bool script_loader_t::load_base_script(script_vm_t *script, const char* base) { cbuffer_t buf; buf.printf("%sscript/%s", env_t::base_dir, base); if (const char* err = script->call_script(buf)) { // should not happen dbg->error("load_base_script", "error [%s] calling %s", err, (const char*)buf); return false; } return true; } script_vm_t* script_loader_t::start_vm(const char* base_file_name, const char* logfile_name, const char* include_path, bool is_scenario) { script_vm_t* script = new script_vm_t(include_path, logfile_name); // load global stuff // constants must be known compile time export_global_constants(script->get_vm()); // load scripting base definitions bool ok = load_base_script(script, "script_base.nut"); // load specific base definitions ok = ok && load_base_script(script, base_file_name); // register api functions if (ok) { register_export_function(script->get_vm(), is_scenario); if (script->get_error()) { dbg->error("start_vm", "error [%s] calling register_export_function", script->get_error()); ok = false; } } if (ok) { return script; } else { delete script; return NULL; } } void script_loader_t::load_compatibility_script(script_vm_t *script) { // check api version plainstring api_version; if (const char* err = script->call_function(script_vm_t::FORCE, "get_api_version", api_version)) { dbg->warning("scenario_t::init", "error [%s] calling get_api_version", err); api_version = "120.1"; } if (api_version != "*") { // load scenario compatibility script if (load_base_script(script, "script_compat.nut")) { plainstring dummy; // call compatibility function if (const char* err = script->call_function(script_vm_t::FORCE, "compat", dummy, api_version) ) { dbg->warning("scenario_t::init", "error [%s] calling compat", err); } } } } simutrans-124.3/src/simutrans/script/script_loader.h000066400000000000000000000014061474050137200226770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_SCRIPT_LOADER_H #define SCRIPT_SCRIPT_LOADER_H class script_vm_t; struct script_loader_t { /** * Starts vm, loads the scripting interface, loads script/[base_file_name]. * @returns vm or NULL in case of error */ static script_vm_t* start_vm(const char* base_file_name, const char* logfile_name, const char* include_path, bool is_scenario); /** * Loads base script files: env_t::base_dir/script/script_base.nut and env_t::base_dir/script/[base]. */ static bool load_base_script(script_vm_t *vm, const char* base); /** * loads necessary compatibility scripts */ static void load_compatibility_script(script_vm_t *script); }; #endif simutrans-124.3/src/simutrans/script/script_tool_manager.cc000066400000000000000000000073451474050137200242460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "script_tool_manager.h" #include "../dataobj/tabfile.h" #include "../simdebug.h" #include "../tool/simtool-scripted.h" #include "../simskin.h" #include "../descriptor/skin_desc.h" #include "../sys/simsys.h" #include "../gui/tool_selector.h" #include "../utils/cbuffer.h" #include "../utils/searchfolder.h" vector_tpl script_tool_manager_t::one_click_script_tools; vector_tpl script_tool_manager_t::two_click_script_tools; bool script_tool_manager_t::check_file( const char *path ) { cbuffer_t buf; buf.printf("%s/tool.nut", path ); if (FILE* const f = dr_fopen(buf, "r")) { fclose(f); return true; } return false; } const scripted_tool_info_t* script_tool_manager_t::get_script_info(const char* path) { scripted_tool_info_t* info = new scripted_tool_info_t(); info->path = path; // read description.tab cbuffer_t buf; buf.printf("%s/description.tab", path); tabfile_t file; if ( file.open(buf) ) { tabfileobj_t contents; file.read( contents ); info->title = translator::translate(contents.get_string("title", path)); info->menu_arg = contents.get_string("menu", ""); info->tooltip = translator::translate(contents.get_string("tooltip", "")); info->cursor_area = contents.get_koord("cursor_area", koord(1,1)); info->cursor_offset = contents.get_koord("cursor_offset", koord(0,0)); if( info->cursor_area.x<1 || info->cursor_area.y<1 ) { dbg->warning("script_tool_manager_t::get_script_info()", "The cursor area of scripted tool %s must have at least 1 tile length. Sanitized to (1,1).", info->title.c_str()); info->cursor_area = koord(1,1); } const char* skin_name = contents.get_string("icon", ""); info->desc = skinverwaltung_t::get_extra(skin_name, strlen(skin_name), skinverwaltung_t::cursor); info->restart = contents.get_int("restart", false); info->is_one_click = !( strcmp(contents.get_string("type", "one_click"), "two_click")==0 ); } else { // no description.tab, use default values info->title = path; } return info; } tool_t* script_tool_manager_t::load_tool(char const* path, tool_t* tool) { if (!check_file(path)) { return tool; } const scripted_tool_info_t* info = get_script_info(path); if (tool) { // reinitialize existing tool exec_script_base_t* esb = dynamic_cast(tool); assert(esb); esb->set_info(info); esb->init_images(tool); } else { // create new tool if (info->is_one_click) { tool = new tool_exec_script_t(info); } else { tool = new tool_exec_two_click_script_t(info); } } return tool; } void script_tool_manager_t::load_scripts(char const* path) { searchfolder_t find; find.search(path, "", searchfolder_t::SF_ONLYDIRS); for(const char* const &name : find) { cbuffer_t fullname; fullname.printf("%s%s",path,name); tool_t *tool = load_tool(fullname); if (tool_exec_script_t* ot = dynamic_cast(tool)) { one_click_script_tools.append(ot); } else if (tool_exec_two_click_script_t* tt = dynamic_cast(tool)) { two_click_script_tools.append(tt); } } } void script_tool_manager_t::fill_menu(tool_selector_t* tool_selector, char const* arg, sint16 /*sound_ok*/) { for(uint32 i=0; iget_menu_arg(), arg)==0 ) { tool_selector->add_tool_selector(tool); } } for(uint32 i=0; iget_menu_arg(), arg)==0 ) { tool_selector->add_tool_selector(tool); } } } simutrans-124.3/src/simutrans/script/script_tool_manager.h000066400000000000000000000027101474050137200240770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCRIPT_SCRIPT_TOOL_MANAGER_H #define SCRIPT_SCRIPT_TOOL_MANAGER_H #include "../tpl/vector_tpl.h" class exec_script_base_t; struct scripted_tool_info_t; class tool_t; class tool_selector_t; class tool_exec_script_t; class tool_exec_two_click_script_t; /** * There's no need to construct an instance since everything is static here. */ class script_tool_manager_t { private: /// All one-click script tools static vector_tpl one_click_script_tools; /// All two-click script tools static vector_tpl two_click_script_tools; public: /// Looks for tool.nut in path static bool check_file(char const* path); /** * Reads description.tab at path. * If no description is found, use default values. * @returns filled info structure. */ static const scripted_tool_info_t* get_script_info(const char* path); /** * Loads tool from path. * If @p tool is not NULL it is reinitialized with the scripted tool. * @returns tool */ static tool_t* load_tool(char const* path, tool_t* tool = NULL); /** * Reads all tools from directory @p path. */ static void load_scripts(char const* path); /** * Fills toolbar with scripted tools. * Select only tools with menu entry equal to @p arg. */ static void fill_menu(tool_selector_t* tool_selector, char const* arg, sint16 sound_ok); }; #endif simutrans-124.3/src/simutrans/scrolltext.h000066400000000000000000000064741474050137200207560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SCROLLTEXT_H #define SCROLLTEXT_H /* first part is left, second part right side */ "","", "","", "","", "","", "","", "","", "","", "Current Team:","", " Markus Pristovsek","developer", " Roboron", "developer, Steam, Android, flatpack", " Daniel Wachsmuth", "developer", " ceeac", "developer", " TurfIt", "developer", "","", "Additional Programming:","", "","", " Hj. Malthaner","founder, Ironbite", " Volker Meyer","big patches", " Hendrik Siegeln","ex-developer", " Niels Roest","GUI", " Markus Weber","GUI changes", " Owen Rudge","MIDI, patches", " Tomas Kubes","patches", " Rainer Bertram","patches", " Andreas Röver","patches", " Tilman Raatz","patches", " Pasi Ruhanen","BeOS, SDL", " Mat Hounsell","GUI", " Kieron Green","skinned grounds, climates", " z9999","patches", " Gerd Wachsmuth", "patches", " Knightly", "ex-developer", " Markohs", "3D branch, ex-developer", " Christoph Mallon", "ex-developer, SVN", " Frank Penz", "Scripting AI", " Yona-TYT", "Tutorials", " Ranran","GUI-patches, chat", "","", "Graphic Paks:","", "","", " Peter J. Dobrovka","", " Tomas Kubes","pak128", " Vladimir Slavik", "pak128", " Frank Penz","pak.german", " Yoshihiro Shishido","pak128.japan", " Sven Osada","pak96.comic", " The Hood", "pak128.britain", " Flemmbrav", "pak192.comic", " Leartin", "pak192.comic", " Makie", "pak128.german", "","", "and many more", "", "", "", "", "", "Graphics:","", "","", " Flor Wauters","", " Georg 'MHz' Moers","", " Hansjörg Malthaner","", " James Starr","", " Manfred Tomaschitz","", " Oskari 'TPI' Saarekas","", " Patrick Nesbitt","", " Peter J. Dobrovka","", " Rick 'Trikky' McGreal","", " Sergiu Croitor","", " Seth C. Triggs","", " Tomas Kubes","", " Guillermo 'raven' Mateo","", " Alexander Brose","", "","", "and many more","", "","", "","", "Translation:","", "","", " Alberto Beccaria","Italian", " George Dragon","Hungarian", " Hansjörg Malthaner","German", " Marcal Guardiola","Spanish", " Niels Roest","Dutch", " Pasi Ruhanen","Finnish", " Rémi Denis-Courmont","French", " Ferencz Szekely","Hungary & Romanian", " Alex Revo","Russian", " Roman Schwörer","French & German", " Yannis Kaskamanid", "Greek", " Igor Eliezer", "Portuguese", " Joan-Josep Bargues", "Catalan", " Susanna Björverud", "Swedish", " Xavier Paz", "Spanish", " Wim Vreeswijk", "Dutch", " Paul Color", "Swedish", " Ignas Brasiskis", "Lithuanian", "","", "and many more","", "","", "","", "Additional Thanks go to:","", "","", " Bernhard Mecl","", "","the very first Simutrans beta tester", " Bram Schoenmakers","", "","the most critical tester", " Gerhard Hafner","", "","for providing tons of railway information", " Marcus Haupt","", "","for lots of help with tricky problems", " Vern Moorhouse", "", "","for some valuable technical hints", " Isaac Eiland-Hall","", "","hosting simutrans.com", " Dirk Burkholz","", "","hosting german forum until his dead", " Frank Penz", "", "", "Simutranslator, Wiki, and more", " Christoph Mallon", "", "", "long time hosting the SVN", " werniman", "", "", "long time hosting the nightly builds", " makie", "", "", "hosting of the simutranslator", "","", "", "", " And many thanks to all testers and","", " players, and all who supported the","", " project!","", "","", "","", "","", "","", "","", "","", "","", 0 #endif simutrans-124.3/src/simutrans/simachenum.h000066400000000000000000000005241474050137200206720ustar00rootroot00000000000000// IMPORTANT! CHANGE THIS ON NEW ACHIEVEMENTS ADDITION #define NUM_ACHIEVEMENTS 4 // Why a macro for this? Check steam/achievements.cc #define ACHIEVEMENTS \ X(ACH_LOAD_PAK192_COMIC) \ X(ACH_QUERY_DICTACTOR) \ X(ACH_PROD_INK) \ X(ACH_TOOL_REMOVE_BUSY_BRIDGE) #define X(id) id, enum simachievements_enum { ACHIEVEMENTS }; #undef Xsimutrans-124.3/src/simutrans/simachievements.cc000066400000000000000000000046511474050137200220700ustar00rootroot00000000000000#include "simachievements.h" #include "./dataobj/environment.h" #include "./simdebug.h" #include "./simfab.h" #include "./utils/simstring.h" #ifdef STEAM_BUILT #include "../steam/steam.h" #endif void simachievements_t::check_pakset_ach() { std::string pak_name = env_t::pak_name; pak_name.erase(pak_name.length() - 1); if ( STRICMP(pak_name.c_str(), "pak192.comic") == 0 ) { set_achievement(ACH_LOAD_PAK192_COMIC); } } void simachievements_t::check_query_ach(const char* object_name) { std::string pak_name = env_t::pak_name; pak_name.erase(pak_name.length() - 1); if ( (STRICMP(pak_name.c_str(), "pak128") == 0) && strstr(object_name, "rmax_dictator_statue") ) { set_achievement(ACH_QUERY_DICTACTOR); } } /** * Given a factory and a name, checks if the factory has the given name * If so, checks if the provided product meets the production target requirement (given as a percentage of maximum production) * @returns true if the yearly production is greater than the target production */ bool check_yearly_production(fabrik_t* fab, const char* name, uint32 product_index, double target_percent = 0.70) { if ( strcmp(fab->get_name(), name) != 0 || product_index >= fab->get_output().get_count() ) { return false; } sint64 yearly_production = 0; sint32 target_production = fab->get_current_production() * 12 * target_percent; for (int i = 0; i < MAX_MONTH; i++) { yearly_production += convert_goods(fab->get_output()[product_index].get_stats()[i * MAX_FAB_GOODS_STAT + FAB_GOODS_PRODUCED]); } // dbg->message("check_state_ach()", "TARGET PROD: %s", std::to_string(target_production).c_str()); // dbg->message("check_state_ach()", "PROD: %s", std::to_string(yearly_production).c_str()); return yearly_production >= target_production; } void simachievements_t::check_state_ach(karte_t* world) { if ( env_t::networkmode ) return; // We don't allow these kind of achievements in multiplayer games std::string pak_name = env_t::pak_name; pak_name.erase(pak_name.length() - 1); for ( fabrik_t* fab : world->get_fab_list() ) { if ( STRICMP(pak_name.c_str(), "pak192.comic") == 0 ) { if ( check_yearly_production(fab, "squid", 0) ) { set_achievement(ACH_PROD_INK); } } } } void simachievements_t::set_achievement(simachievements_enum ach) { dbg->message("simachievements_t::set_achievement()", "Unlocking achievement %d", ach); #ifdef STEAM_BUILT steam_t::get_instance()->get_achievements()->set_achievement(ach); #endif }simutrans-124.3/src/simutrans/simachievements.h000066400000000000000000000014251474050137200217260ustar00rootroot00000000000000#include "./simachenum.h" #include "./world/simworld.h" /** * Manages the achievement system. This currently only works for Steam achievements. * TODO: It would be cool to have our own achievement system! */ class simachievements_t { private: public: // Check achievements for loading the current pakset static void check_pakset_ach(); // Check achievements for querying a specific object static void check_query_ach(const char* object_name); // Check achievements that depend on game state static void check_state_ach(karte_t* world); // Set the given achievement. No check is made, use after the condition is fullfilled! static void set_achievement(simachievements_enum ach); // TODO: A function to set achievement from script tools (for scenarios, tutorial, etc...) };simutrans-124.3/src/simutrans/simcolor.h000066400000000000000000000161141474050137200203720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMCOLOR_H #define SIMCOLOR_H #include "simtypes.h" #define LIGHT_COUNT (15) #define SPECIAL_COLOR_COUNT (224) // this is a player color => use different table for conversion #define PLAYER_FLAG (0x800000) #define TRANSPARENT_FLAGS (0x780000) #define TRANSPARENT25_FLAG (0x200000) #define TRANSPARENT50_FLAG (0x400000) #define TRANSPARENT75_FLAG (0x600000) #define OUTLINE_FLAG (0x080000) // pixels stored in system type (uint16) typedef unsigned short PIXVAL; // PIXVAL with above flags (eg. transparent) (uint32) typedef unsigned int FLAGGED_PIXVAL; // Menu colours (they don't change between day and night) #define MN_GREY0 229 #define MN_GREY1 230 #define MN_GREY2 231 #define MN_GREY3 232 #define MN_GREY4 233 // fixed colors #define COL_BLACK 240 #define COL_WHITE 215 #define COL_RED 131 #define COL_DARK_RED 128 #define COL_LIGHT_RED 134 #define COL_YELLOW 171 #define COL_DARK_YELLOW 168 #define COL_LIGHT_YELLOW 175 #define COL_LEMON_YELLOW 31 #define COL_BLUE 147 #define COL_DARK_BLUE 144 #define COL_SOFT_BLUE 100 #define COL_LIGHT_BLUE 103 #define COL_GREEN 140 #define COL_DARK_GREEN 136 #define COL_LIGHT_GREEN 143 #define COL_ORANGE 155 #define COL_DARK_ORANGE 153 #define COL_LIGHT_ORANGE 158 #define COL_BRIGHT_ORANGE 133 #define COL_LILAC 221 #define COL_MAGENTA 63 #define COL_PURPLE 76 #define COL_DARK_PURPLE 73 #define COL_LIGHT_PURPLE 79 #define COL_TURQUOISE 53 #define COL_LIGHT_TURQUOISE 55 #define COL_DARK_TURQUOISE 50 #define COL_LIGHT_BROWN 191 #define COL_BROWN 189 #define COL_DARK_BROWN 178 // message colors #define CITY_KI color_idx_to_rgb(209) #define NEW_VEHICLE color_idx_to_rgb(COL_PURPLE) // by niels #define COL_GREY1 208 #define COL_GREY2 210 #define COL_GREY3 212 #define COL_GREY4 11 #define COL_GREY5 213 #define COL_GREY6 15 // Way colours for the map #define COL_ROAD color_idx_to_rgb(COL_GREY1) #define COL_RAIL color_idx_to_rgb(185) #define COL_CANAL color_idx_to_rgb(23) #define COL_MONORAIL color_idx_to_rgb(COL_ORANGE) #define COL_RUNWAY color_idx_to_rgb(28) #define COL_POWERLINE color_idx_to_rgb(COL_LIGHT_TURQUOISE) #define COL_HALT color_idx_to_rgb(COL_RED) #define COL_BUILDING color_idx_to_rgb(COL_GREY3) #define COL_VEHICLE color_idx_to_rgb(COL_YELLOW) // used in many dialogues graphs #define COL_REVENUE 142 #define COL_OPERATION 132 #define COL_MAINTENANCE COL_LIGHT_RED #define COL_TOLL 157 #define COL_POWERLINES 46 #define COL_OPS_PROFIT 87 #define COL_NEW_VEHICLES COL_LIGHT_PURPLE #define COL_CONSTRUCTION 110 #define COL_PROFIT 6 #define COL_TRANSPORTED COL_YELLOW #define COL_MAXSPEED COL_TURQUOISE #define COL_CASH 52 #define COL_VEHICLE_ASSETS COL_MAGENTA #define COL_MARGIN COL_LIGHT_YELLOW #define COL_WEALTH 95 #define COL_CONVOI_COUNT COL_LIGHT_TURQUOISE #define COL_FREE_CAPACITY COL_TOLL #define COL_DISTANCE COL_OPS_PROFIT #define COL_CITIZENS COL_WHITE #define COL_GROWTH 122 #define COL_HAPPY COL_WHITE #define COL_UNHAPPY COL_RED #define COL_NO_ROUTE COL_BLUE #define COL_WAITING COL_YELLOW #define COL_ARRIVED COL_DARK_ORANGE #define COL_DEPARTED COL_DARK_YELLOW #define SYSCOL_TEXT gui_theme_t::gui_color_text #define SYSCOL_TEXT_HIGHLIGHT gui_theme_t::gui_color_text_highlight #define SYSCOL_TEXT_SHADOW gui_theme_t::gui_color_text_shadow #define SYSCOL_TEXT_TITLE gui_theme_t::gui_color_text_title #define SYSCOL_TEXT_STRONG gui_theme_t::gui_color_text_strong #define MONEY_MINUS gui_theme_t::gui_color_text_minus #define MONEY_PLUS gui_theme_t::gui_color_text_plus #define SYSCOL_TEXT_UNUSED gui_theme_t::gui_color_text_unused #define SYSCOL_EDIT_TEXT gui_theme_t::gui_color_edit_text #define SYSCOL_EDIT_TEXT_SELECTED gui_theme_t::gui_color_edit_text_selected #define SYSCOL_EDIT_TEXT_DISABLED gui_theme_t::gui_color_edit_text_disabled #define SYSCOL_EDIT_BACKGROUND_SELECTED gui_theme_t::gui_color_edit_background_selected #define SYSCOL_CURSOR_BEAM gui_theme_t::gui_color_edit_beam #define SYSCOL_CHART_BACKGROUND gui_theme_t::gui_color_chart_background #define SYSCOL_CHART_LINES_ZERO gui_theme_t::gui_color_chart_lines_zero #define SYSCOL_CHART_LINES_ODD gui_theme_t::gui_color_chart_lines_odd #define SYSCOL_CHART_LINES_EVEN gui_theme_t::gui_color_chart_lines_even #define SYSCOL_LIST_TEXT_SELECTED_FOCUS gui_theme_t::gui_color_list_text_selected_focus #define SYSCOL_LIST_TEXT_SELECTED_NOFOCUS gui_theme_t::gui_color_list_text_selected_nofocus #define SYSCOL_LIST_BACKGROUND_SELECTED_F gui_theme_t::gui_color_list_background_selected_f #define SYSCOL_LIST_BACKGROUND_SELECTED_NF gui_theme_t::gui_color_list_background_selected_nf #define SYSCOL_BUTTON_TEXT gui_theme_t::gui_color_button_text #define SYSCOL_BUTTON_TEXT_DISABLED gui_theme_t::gui_color_button_text_disabled #define SYSCOL_BUTTON_TEXT_SELECTED gui_theme_t::gui_color_button_text_selected #define SYSCOL_COLORED_BUTTON_TEXT gui_theme_t::gui_color_colored_button_text #define SYSCOL_COLORED_BUTTON_TEXT_SELECTED gui_theme_t::gui_color_colored_button_text_selected #define SYSCOL_CHECKBOX_TEXT gui_theme_t::gui_color_checkbox_text #define SYSCOL_CHECKBOX_TEXT_DISABLED gui_theme_t::gui_color_checkbox_text_disabled #define SYSCOL_TICKER_BACKGROUND gui_theme_t::gui_color_ticker_background #define SYSCOL_TICKER_DIVIDER gui_theme_t::gui_color_ticker_divider #define SYSCOL_STATUSBAR_TEXT gui_theme_t::gui_color_statusbar_text #define SYSCOL_STATUSBAR_BACKGROUND gui_theme_t::gui_color_statusbar_background #define SYSCOL_STATUSBAR_DIVIDER gui_theme_t::gui_color_statusbar_divider #define SYSCOL_HIGHLIGHT gui_theme_t::gui_highlight_color #define SYSCOL_SHADOW gui_theme_t::gui_shadow_color #define SYSCOL_LOADINGBAR_INNER gui_theme_t::gui_color_loadingbar_inner #define SYSCOL_LOADINGBAR_PROGRESS gui_theme_t::gui_color_loadingbar_progress #define SYSCOL_OBSOLETE gui_theme_t::gui_color_obsolete #define SYSCOL_EMPTY gui_theme_t::gui_color_empty #define SYSCOL_IMAGE_TRANSPARENCY gui_theme_t::gui_color_image_transparency #define SYSCOL_OBJECT_HIGHLIGHT gui_theme_t::gui_color_object_highlight struct rgb888_t { uint8 r, g, b; }; #endif simutrans-124.3/src/simutrans/simconst.h000066400000000000000000000065351474050137200204100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMCONST_H #define SIMCONST_H /* * all defines that can change the compiling */ // color depth (default assumes RGB565), undefine only for rgb555 builds! //#define RGB555 // some clients had no goof IP6 support (or maybe useful for debugging) //#define USE_IP4_ONLY // server can try a lookup of the own name (may get wrong one if more than one IP for this host) //#define LOOKUP_OWN_IP_NAME // number of player #define MAX_PLAYER_COUNT (16) #define PLAYER_UNOWNED (15) /* Flag for non Intel byte order * SET THIS IN YOUR COMPILER COMMAND LINE! */ //#define SIM_BIG_ENDIAN /* crossconnect industry and half heights like openTTD */ //#define OTTD_LIKE /* construct automatic bridges also as active player */ //#define AUTOMATIC_BRIDGES /* construct automatic tunnels also as active player */ //#define AUTOMATIC_TUNNELS /* citycars have a destination; if they could get near, they dissolve */ //#define DESTINATION_CITYCARS /* need to emulate the mouse pointer with a graphic */ //#define USE_SOFTPOINTER /* Use assembly imepmentation of routines if available * Some routines, eg for drawing, can have assembly implementations for certaint platforms that may perform better */ #define USE_ASSEMBLER /* Use low level C/C++ implementations of routines * Some routines, eg for drawing, can have low level C++ implementations that might perform better on certain platforms */ #define LOW_LEVEL // define this for automatically joining stations next to a public stop with it //#define AUTOJOIN_PUBLIC // allow minspeed and private way signs on waterways (imho pointless) //#define ENABLE_WATERWAY_SIGNS // Maximum number of threads #define MAX_THREADS (12) // Use own routines for downloading paks and installing (requires libzip and libcurl) //#define USE_OWN_PAKINSTALL // if defined, if overrides the packing of the structures and allows for 255 ground pre planquadrat_t (default 15) // DO NOT USE THIS UNLESS YOU REALLY NEED IT!!! //#define MAX_PLAN_SIZE 255 /*********************** Useful things for debugging ... ********************/ /* will highlight marked areas and convoi will leave traces */ //#define DEBUG_ROUTES /* shows which tiles are drawn as dings (used in ground/grund.cc) */ //#define SHOW_FORE_GRUND /* shows with block needed update and which not */ //#define DEBUG_FLUSH_BUFFER /* inserts debugging code into freelist_tpl/freelist_iter_tpl to aid with finding memory corruptions */ //#define DEBUG_FREELIST /* define USE_VALGRIND_MEMCHECK to make valgrind aware of the freelist memory pool */ //#define USE_VALGRIND_MEMCHECK /**************************** automatic stuff ********************************/ // inclination types // constants used in tools tool_setslope / tool_restoreslope_t #define ALL_UP_SLOPE (82) #define ALL_DOWN_SLOPE (83) #define RESTORE_SLOPE (84) #define ALL_UP_SLOPE_SINGLE (16) #define ALL_DOWN_SLOPE_SINGLE (17) #define RESTORE_SLOPE_SINGLE (18) // 16 internal pixels per tile, for purposes of object visual offsets. #define OBJECT_OFFSET_STEPS (16) // These must be changed (along with lots of other code) if OBJECT_OFFSET_STEPS is changed. #define tile_raster_scale_x(v, rw) (((v)*(rw)) >> 6) #define tile_raster_scale_y(v, rh) (((v)*(rh)) >> 6) // offsets for mouse pointer #define Z_PLAN (4) #define Z_GRID (0) #endif simutrans-124.3/src/simutrans/simconvoi.cc000066400000000000000000003415701474050137200207160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simdebug.h" #include "simunits.h" #include "world/simworld.h" #include "simware.h" #include "player/finance.h" // convert_money #include "player/simplay.h" #include "simconvoi.h" #include "simhalt.h" #include "obj/depot.h" #include "gui/simwin.h" #include "tool/simmenu.h" #include "simcolor.h" #include "simmesg.h" #include "simintr.h" #include "simlinemgmt.h" #include "simline.h" #include "freight_list_sorter.h" #include "gui/minimap.h" #include "gui/convoi_info.h" #include "gui/depot_frame.h" #include "gui/messagebox.h" #include "gui/convoi_detail.h" #include "ground/grund.h" #include "obj/way/schiene.h" // for railblocks #include "descriptor/citycar_desc.h" #include "descriptor/roadsign_desc.h" #include "descriptor/vehicle_desc.h" #include "dataobj/schedule.h" #include "dataobj/route.h" #include "dataobj/loadsave.h" #include "dataobj/translator.h" #include "dataobj/environment.h" #include "display/viewport.h" #include "obj/crossing.h" #include "obj/roadsign.h" #include "obj/wayobj.h" #include "utils/simrandom.h" #include "utils/simstring.h" #include "utils/cbuffer.h" #include "vehicle/air_vehicle.h" #include "vehicle/overtaker.h" #include "vehicle/rail_vehicle.h" #include "vehicle/road_vehicle.h" #include "vehicle/simroadtraffic.h" #include "vehicle/water_vehicle.h" /* * Waiting time for loading (ms) */ #define WTT_LOADING 2000 karte_ptr_t convoi_t::welt; /* * Debugging helper - translate state value to human readable name */ static const char * state_names[convoi_t::MAX_STATES] = { "INITIAL", "EDIT_SCHEDULE", "ROUTING_1", "", "", "NO_ROUTE", "DRIVING", "LOADING", "WAITING_FOR_CLEARANCE", "WAITING_FOR_CLEARANCE_ONE_MONTH", "CAN_START", "CAN_START_ONE_MONTH", "SELF_DESTRUCT", "WAITING_FOR_CLEARANCE_TWO_MONTHS", "CAN_START_TWO_MONTHS", "LEAVING_DEPOT", "ENTERING_DEPOT" }; /** * Calculates speed of slowest vehicle in the given array */ static int calc_min_top_speed(const array_tpl& fahr, uint8 vehicle_count) { int min_top_speed = SPEED_UNLIMITED; for(uint8 i=0; iget_desc()->get_topspeed() ) ); } return min_top_speed; } void convoi_t::init(player_t *player) { owner = player; is_electric = false; sum_gesamtweight = sum_weight = 0; sum_running_costs = sum_fixed_costs = sum_gear_and_power = previous_delta_v = 0; sum_power = 0; min_top_speed = SPEED_UNLIMITED; speedbonus_kmh = SPEED_UNLIMITED; // speed_to_kmh() not needed schedule = NULL; schedule_target = koord3d::invalid; line = linehandle_t(); vehicle_count = 0; steps_driven = -1; withdraw = false; has_obsolete = false; no_load = false; wait_lock = 0; arrived_time = 0; jahresgewinn = 0; total_distance_traveled = 0; distance_since_last_stop = 0; sum_speed_limit = 0; maxspeed_average_count = 0; next_reservation_index = 0; alte_richtung = ribi_t::none; next_wolke = 0; state = INITIAL; unloading_state = false; *name_and_id = 0; name_offset = 0; freight_info_resort = true; freight_info_order = 0; loading_level = 0; loading_limit = 0; speed_limit = SPEED_UNLIMITED; max_record_speed = 0; brake_speed_soll = SPEED_UNLIMITED; akt_speed_soll = 0; // target speed akt_speed = 0; // current speed sp_soll = 0; next_stop_index = 65535; last_load_tick = 0; line_update_pending = linehandle_t(); home_depot = koord3d::invalid; recalc_data_front = true; recalc_data = true; recalc_speed_limit = true; } convoi_t::convoi_t(loadsave_t* file) : fahr(default_vehicle_length, NULL) { self = convoihandle_t(); init(0); rdwr(file); } convoi_t::convoi_t(player_t* player) : fahr(default_vehicle_length, NULL) { self = convoihandle_t(this); player->book_convoi_number(1); init(player); set_name( "Unnamed" ); welt->add_convoi( self ); init_financial_history(); } convoi_t::~convoi_t() { owner->book_convoi_number( -1); assert(self.is_bound()); assert(vehicle_count==0); // close windows destroy_win( magic_convoi_info+self.get_id() ); DBG_MESSAGE("convoi_t::~convoi_t()", "destroying %d, %p", self.get_id(), this); // stop following if(welt->get_viewport()->get_follow_convoi()==self) { welt->get_viewport()->set_follow_convoi( convoihandle_t() ); } welt->sync.remove( this ); welt->rem_convoi( self ); // if lineless convoy -> unregister from stops if( !line.is_bound() ) { unregister_stops(); } // force asynchronous recalculation if(schedule) { if(!schedule->is_editing_finished()) { destroy_win((ptrdiff_t)schedule); } if (!schedule->empty() && !line.is_bound()) { welt->set_schedule_counter(); } delete schedule; } // deregister from line (again) unset_line(); self.detach(); } // waypoint: no stop, resp. for airplanes in air (i.e. no air strip below) bool convoi_t::is_waypoint( koord3d ziel ) const { if( fahr[0]->get_waytype() == air_wt ) { // separate logic for airplanes, since the can have waypoints over stops etc. grund_t *gr = welt->lookup_kartenboden(ziel.get_2d()); if( gr == NULL || gr->get_weg(air_wt) == NULL ) { // during flight always a waypoint return true; } else if( gr->get_depot() ) { // but a depot is not a waypoint return false; } // so we are on a taxiway/runway here ... } if (grund_t* gr = welt->lookup(ziel)) { if (depot_t* dp = gr->get_depot()) { // don't stop in other peoples depot return !(dp->get_owner() == get_owner() && fahr[0] && dp->get_waytype() == fahr[0]->get_waytype()); } } return !haltestelle_t::get_halt(ziel,get_owner()).is_bound(); } /** * unreserves the whole remaining route */ void convoi_t::unreserve_route() { // need a route, vehicles, and vehicles must belong to this convoi // (otherwise crash during loading when fahr[0]->convoi is not initialized yet if( !route.empty() && vehicle_count>0 && fahr[0]->get_convoi() == this ) { rail_vehicle_t* lok = dynamic_cast(fahr[0]); if (lok) { // free all reserved blocks route_t::index_t dummy; lok->block_reserver(get_route(), back()->get_route_index(), dummy, dummy, 100000, false, true); } } } /** * reserves route until next_reservation_index */ void convoi_t::reserve_route() { if( !route.empty() && vehicle_count>0 && (is_waiting() || state==DRIVING || state==LEAVING_DEPOT) ) { for( route_t::index_t idx = back()->get_route_index(); idx < next_reservation_index /*&& idx < route.get_count()*/; idx++ ) { if( grund_t *gr = welt->lookup( route.at(idx) ) ) { if( schiene_t *sch = (schiene_t *)gr->get_weg( front()->get_waytype() ) ) { sch->reserve( self, ribi_type( route.at(max(1u,idx)-1u), route.at(min(route.get_count()-1u,idx+1u)) ) ); } } } } } /** * Sets route_index of all vehicles to startindex. * Puts all vehicles on tile at this position in the route. * Convoy stills needs to be pushed that the convoy is right on track. * @returns length of convoy minus last vehicle */ uint32 convoi_t::move_to(route_t::index_t const start_index) { steps_driven = -1; koord3d k = route.at(start_index); grund_t* gr = welt->lookup(k); uint32 train_length = 0; for (unsigned i = 0; i != vehicle_count; ++i) { vehicle_t& v = *fahr[i]; if( grund_t const* gr = welt->lookup(v.get_pos()) ) { v.mark_image_dirty(v.get_image(), 0); v.leave_tile(); // maybe unreserve this if( schiene_t* const rails = obj_cast(gr->get_weg(v.get_waytype())) ) { rails->unreserve(&v); } } // propagate new index to vehicle, will set all movement related variables, in particular pos v.initialise_journey(start_index, true); // now put vehicle on the tile if (gr) { v.enter_tile(gr); } if (i != vehicle_count - 1U) { train_length += v.get_desc()->get_length(); } } return train_length; } void convoi_t::finish_rd() { if(schedule==NULL) { if( state!=INITIAL ) { grund_t *gr = welt->lookup(home_depot); if(gr && gr->get_depot()) { dbg->warning( "convoi_t::finish_rd()","No schedule during loading convoi %i: State will be initial!", self.get_id() ); for( uint8 i=0; iset_pos(home_depot); } state = INITIAL; } else { dbg->error( "convoi_t::finish_rd()","No schedule during loading convoi %i: Convoi will be destroyed!", self.get_id() ); for( uint8 i=0; iset_pos(koord3d::invalid); } destroy(); return; } } // anyway reassign convoi pointer ... for( uint8 i=0; iset_convoi(this); if( state!=INITIAL && welt->lookup(v->get_pos()) ) { // mark vehicle as used v->set_driven(); } } return; } else { // restore next schedule target for non-stop waypoint handling const koord3d ziel = schedule->get_current_entry().pos; if( vehicle_count>0 && is_waypoint(ziel) ) { schedule_target = ziel; } } bool realign_position = false; if( vehicle_count>0 ) { DBG_MESSAGE("convoi_t::finish_rd()","state=%s, next_stop_index=%d", state_names[state], next_stop_index ); // only realign convois not leaving depot to avoid jumps through signals if( steps_driven!=-1 ) { for( uint8 i=0; iset_leading( i==0 ); v->set_last( i+1==vehicle_count ); v->calc_height(); // this sets the convoi and will renew the block reservation, if needed! v->set_convoi(this); } } else { // test also for realignment sint16 step_pos = 0; koord3d drive_pos; uint8 const diagonal_vehicle_steps_per_tile = (uint8)(130560U / welt->get_settings().get_pak_diagonal_multiplier()); for( uint8 i=0; iset_leading( i==0 ); v->set_last( i+1==vehicle_count ); v->calc_height(); // this sets the convoi and will renew the block reservation, if needed! v->set_convoi(this); // wrong alignment here => must relocate if(v->need_realignment()) { // diagonal => convoi must restart realign_position |= ribi_t::is_bend(v->get_direction()) && (state==DRIVING || is_waiting()); } // if version is 99.17 or lower, some convois are broken, i.e. had too large gaps between vehicles if( !realign_position && state!=INITIAL && state!=LEAVING_DEPOT ) { if( i==0 ) { step_pos = v->get_steps(); } else { if( drive_pos!=v->get_pos() ) { // with long vehicles on diagonals, vehicles need not to be on consecutive tiles // do some guessing here uint32 dist = koord_distance(drive_pos, v->get_pos()); if (dist>1) { step_pos += (dist-1) * diagonal_vehicle_steps_per_tile; } step_pos += ribi_t::is_bend(v->get_direction()) ? diagonal_vehicle_steps_per_tile : VEHICLE_STEPS_PER_TILE; } dbg->message("convoi_t::finish_rd()", "v: pos(%s) steps(%d) len=%d ribi=%d prev (%s) step(%d)", v->get_pos().get_str(), v->get_steps(), v->get_desc()->get_length()*16, v->get_direction(), drive_pos.get_2d().get_str(), step_pos); if( abs( v->get_steps() - step_pos )>15 ) { // not where it should be => realign realign_position = true; dbg->warning( "convoi_t::finish_rd()", "convoi (%s) is broken => realign", get_name() ); } } step_pos -= v->get_desc()->get_length_in_steps(); drive_pos = v->get_pos(); } } } DBG_MESSAGE("convoi_t::finish_rd()","next_stop_index=%d", next_stop_index ); linehandle_t new_line = line; if( !new_line.is_bound() ) { // if there is a line with id=0 in the savegame try to assign cnv to this line new_line = get_owner()->simlinemgmt.get_line_with_id_zero(); } if( new_line.is_bound() ) { if ( !schedule->matches( welt, new_line->get_schedule() ) ) { // 101 version produced broken line ids => we have to find our line the hard way ... vector_tpl lines; get_owner()->simlinemgmt.get_lines(schedule->get_type(), &lines); new_line = linehandle_t(); for(linehandle_t const l : lines) { if( schedule->matches( welt, l->get_schedule() ) ) { // if a line is assigned, set line! new_line = l; break; } } } // now the line should match our schedule or else ... if(new_line.is_bound()) { line = new_line; line->add_convoy(self); DBG_DEBUG("convoi_t::finish_rd()","%s registers for %d", name_and_id, line.get_id()); } else { line = linehandle_t(); } } } else { // no vehicles in this convoi?!? dbg->error( "convoi_t::finish_rd()","No vehicles in Convoi %i: will be destroyed!", self.get_id() ); destroy(); return; } // put convoi again right on track? if(realign_position && vehicle_count>1) { // display just a warning dbg->warning("convoi_t::finish_rd()","cnv %i is currently too long.",self.get_id()); if (route.empty()) { // realigning needs a route state = NO_ROUTE; owner->report_vehicle_problem( self, koord3d::invalid ); dbg->error( "convoi_t::finish_rd()", "No valid route, but needs realignment at (%s)!", fahr[0]->get_pos().get_str() ); } else { // since start may have been changed route_t::index_t start_index = max(1,fahr[vehicle_count-1]->get_route_index())-1; if (start_index >= route.get_count()) { dbg->error( "convoi_t::finish_rd()", "Routeindex of last vehicle of (%s) too large (%hu > %hu)!", get_name(), start_index, route.get_count() ); start_index = 0; } uint32 train_length = move_to(start_index) + 1; const koord3d last_start = fahr[0]->get_pos(); // now advance all convoi until it is completely on the track fahr[0]->set_leading(false); // switches off signal checks ... for(unsigned i=0; iset_smoke_enabled(false); fahr[i]->do_drive( (VEHICLE_STEPS_PER_CARUNIT*train_length)<get_desc()->get_length(); v->set_smoke_enabled(true); // eventually reserve this again grund_t *gr=welt->lookup(v->get_pos()); // airplanes may have no ground ... if (schiene_t* const sch0 = obj_cast(gr->get_weg(fahr[i]->get_waytype()))) { sch0->reserve(self,ribi_t::none); } } fahr[0]->set_leading(true); if( state != INITIAL && state != EDIT_SCHEDULE && fahr[0]->get_pos() != last_start ) { state = WAITING_FOR_CLEARANCE; } } } if( state==LOADING ) { // the fully the shorter => register again as older convoi wait_lock = max(0, 2000-loading_level*20); if (distance_since_last_stop > 0) { calc_gewinn(); } } // when saving with open window, this can happen if( state==EDIT_SCHEDULE ) { if (env_t::networkmode) { wait_lock = 30000; // 30s to drive on, if the client in question had left } schedule->finish_editing(); } // remove wrong freight check_freight(); // some convois had wrong old direction in them if( stateget_direction(); } // if lineless convoy -> register itself with stops if( !line.is_bound() ) { register_stops(); } calc_speedbonus_kmh(); } // since now convoi states go via tool_t void convoi_t::call_convoi_tool( const char function, const char *extra ) const { tool_t *tmp_tool = create_tool( TOOL_CHANGE_CONVOI | SIMPLE_TOOL ); cbuffer_t param; param.printf("%c,%u", function, self.get_id()); if( extra && *extra ) { param.printf(",%s", extra); } tmp_tool->set_default_param(param); welt->set_tool( tmp_tool, get_owner() ); // since init always returns false, it is safe to delete immediately delete tmp_tool; } void convoi_t::rotate90( const sint16 y_size ) { record_pos.rotate90( y_size ); home_depot.rotate90( y_size ); route.rotate90( y_size ); if( schedule_target!=koord3d::invalid ) { schedule_target.rotate90( y_size ); } if(schedule) { schedule->rotate90( y_size ); } for( int i=0; irotate90_freight_destinations( y_size ); } // eventually correct freight destinations (and remove all stale freight) check_freight(); } /** * Return the convoi position. * @return Convoi position */ koord3d convoi_t::get_pos() const { if(vehicle_count > 0 && fahr[0]) { return state==INITIAL ? home_depot : fahr[0]->get_pos(); } else { return koord3d::invalid; } } /** * Sets the name. Creates a copy of name. */ void convoi_t::set_name(const char *name, bool with_new_id) { if( with_new_id ) { char buf[128]; name_offset = sprintf(buf,"(%i) ",self.get_id() ); tstrncpy(buf + name_offset, translator::translate(name, welt->get_settings().get_name_language_id()), lengthof(buf) - name_offset); tstrncpy(name_and_id, buf, lengthof(name_and_id)); } else { char buf[128]; // check if there is a id in the name string name_offset = sprintf(buf,"(%i) ",self.get_id() ); if( strlen(name) < name_offset || strncmp(buf,name,name_offset)!=0) { name_offset = 0; } tstrncpy(buf+name_offset, name+name_offset, sizeof(buf)-name_offset); tstrncpy(name_and_id, buf, lengthof(name_and_id)); } // now tell the windows that we were renamed convoi_info_t *info = dynamic_cast(win_get_magic( magic_convoi_info+self.get_id())); if (info) { info->update_data(); } if( in_depot() ) { const grund_t *const ground = welt->lookup( get_home_depot() ); if( ground ) { const depot_t *const depot = ground->get_depot(); if( depot ) { depot_frame_t *const frame = dynamic_cast( win_get_magic( (ptrdiff_t)depot ) ); if( frame ) { frame->update_data(); } } } } } // length of convoi (16 is one tile) uint32 convoi_t::get_length() const { uint32 len = 0; for( uint8 i=0; iget_desc()->get_length(); } return len; } /** * convoi add their running cost for traveling one tile */ void convoi_t::add_running_cost( const weg_t *weg ) { jahresgewinn += sum_running_costs; if( weg && weg->get_owner()!=get_owner() && weg->get_owner()!=NULL ) { // running on non-public way costs toll (since running costs are positive => invert) sint32 toll = -(sum_running_costs*welt->get_settings().get_way_toll_runningcost_percentage())/100l; if( welt->get_settings().get_way_toll_waycost_percentage() ) { if( weg->is_electrified() && needs_electrification() ) { // toll for using electricity grund_t *gr = welt->lookup(weg->get_pos()); for( int i=1; iobj_count(); i++ ) { obj_t *d=gr->obj_bei(i); if( wayobj_t const* const wo = obj_cast(d) ) { if( wo->get_waytype()==weg->get_waytype() ) { toll += (wo->get_desc()->get_maintenance()*welt->get_settings().get_way_toll_waycost_percentage())/100l; break; } } } } // now add normal way toll be maintenance toll += (weg->get_desc()->get_maintenance()*welt->get_settings().get_way_toll_waycost_percentage())/100l; } weg->get_owner()->book_toll_received( toll, get_schedule()->get_waytype() ); get_owner()->book_toll_paid( -toll, get_schedule()->get_waytype() ); book( -toll, CONVOI_WAYTOLL); book( -toll, CONVOI_PROFIT); } get_owner()->book_running_costs( sum_running_costs, get_schedule()->get_waytype()); book( sum_running_costs, CONVOI_OPERATIONS ); book( sum_running_costs, CONVOI_PROFIT ); total_distance_traveled ++; distance_since_last_stop++; sum_speed_limit += speed_to_kmh( min( min_top_speed, speed_limit )); book( 1, CONVOI_DISTANCE ); } /** * Returns residual power given power, weight, and current speed. * @param speed (in internal speed unit) * @param total_power sum of power times gear (see calculation of sum_gear_and_power) * @param friction_weight weight including friction of the convoy * @param total_weight weight of the convoy * @returns residual power */ static inline sint32 res_power(sint64 speed, sint32 total_power, sint64 friction_weight, sint64 total_weight) { sint32 res = total_power - (sint32)( ( (sint64)speed * ( (friction_weight * (sint64)speed ) / 3125ll + 1ll) ) / 2048ll + (total_weight * 64ll) / 1000ll); return res; } /* Calculates (and sets) new akt_speed * needed for driving, entering and leaving a depot) */ void convoi_t::calc_acceleration(uint32 delta_t) { if( !recalc_data && !recalc_speed_limit && !recalc_data_front && ( (sum_friction_weight == sum_gesamtweight && akt_speed_soll <= akt_speed && akt_speed_soll+24 >= akt_speed) || (sum_friction_weight > sum_gesamtweight && akt_speed_soll == akt_speed) ) ) { // at max speed => go with max speed and finish calculation here // at slopes/curves, only do this if there is absolutely now change akt_speed = akt_speed_soll; return; } // only compute this if a vehicle in the convoi hopped if( recalc_data || recalc_speed_limit ) { // calculate total friction and lowest speed limit const vehicle_t* v = front(); speed_limit = min( min_top_speed, v->get_speed_limit() ); if (recalc_data) { sum_gesamtweight = v->get_total_weight(); sum_friction_weight = v->get_frictionfactor() * sum_gesamtweight; } for( unsigned i=1; iget_speed_limit() ); if (recalc_data) { int total_vehicle_weight = v->get_total_weight(); sum_friction_weight += v->get_frictionfactor() * total_vehicle_weight; sum_gesamtweight += total_vehicle_weight; } } recalc_data = recalc_speed_limit = false; akt_speed_soll = min( speed_limit, brake_speed_soll ); } if( recalc_data_front ) { // brake at the end of stations/in front of signals and crossings const uint32 tiles_left = 1 + get_next_stop_index() - front()->get_route_index(); brake_speed_soll = SPEED_UNLIMITED; if( tiles_left < 4 ) { static sint32 brake_speed_countdown[4] = { kmh_to_speed(25), kmh_to_speed(50), kmh_to_speed(100), kmh_to_speed(200) }; brake_speed_soll = brake_speed_countdown[tiles_left]; } akt_speed_soll = min( speed_limit, brake_speed_soll ); recalc_data_front = false; } // more pleasant and a little more "physical" model // try to simulate quadratic friction if(sum_gesamtweight != 0) { /* * The parameter consist of two parts (optimized for good looking): * - every vehicle in a convoi has a the friction of its weight * - the dynamic friction is calculated that way, that v^2*weight*frictionfactor = 200 kW * This means that if a vehicle is loaded heavier and/or travels faster, less * power for acceleration is available. * since delta_t can have any value, we have to scale the step size by this value. * However, there is a quadratic friction term => if delta_t is too large the calculation may get weird results * * but for integer, we have to use the order below and calculate actually 64*deccel, like the sum_gear_and_power * since akt_speed=10/128 km/h and we want 64*200kW=(100km/h)^2*100t, we must multiply by (128*2)/100 * But since the acceleration was too fast, we just decelerate 4x more => >>6 instead >>8 */ //sint32 deccel = ( ( (akt_speed*sum_friction_weight)>>6 )*(akt_speed>>2) ) / 25 + (sum_gesamtweight*64); // this order is needed to prevent overflows! //sint32 deccel = (sint32)( ( (sint64)akt_speed * (sint64)sum_friction_weight * (sint64)akt_speed ) / (25ll*256ll) + sum_gesamtweight * 64ll) / 1000ll; // intermediate still overflows so sint64 //sint32 deccel = (sint32)( ( (sint64)akt_speed * ( (sum_friction_weight * (sint64)akt_speed ) / 3125ll + 1ll) ) / 2048ll + (sum_gesamtweight * 64ll) / 1000ll); // note: result can overflow sint32 and double so we use sint64. Planes are ok. //sint32 delta_v = (sint32)( ( (double)( (akt_speed>akt_speed_soll?0l:sum_gear_and_power) - deccel)*(double)delta_t)/(double)sum_gesamtweight); sint64 residual_power = res_power(akt_speed, akt_speed>akt_speed_soll? 0l : sum_gear_and_power, sum_friction_weight, sum_gesamtweight); // we normalize delta_t to 1/64th and check for speed limit */ //sint32 delta_v = ( ( (akt_speed>akt_speed_soll?0l:sum_gear_and_power) - deccel) * delta_t)/sum_gesamtweight; sint64 delta_v = ( residual_power * (sint64)delta_t * 1000ll) / (sint64)sum_gesamtweight; // we need more accurate arithmetic, so we store the previous value delta_v += previous_delta_v; previous_delta_v = (uint16) (delta_v & 0x00000FFFll); // and finally calculate new speed akt_speed = max(akt_speed_soll>>4, akt_speed+(sint32)(delta_v>>12l) ); } else { // very old vehicle ... akt_speed += 16; } // obey speed maximum with additional const brake ... if(akt_speed > akt_speed_soll) { if (akt_speed > akt_speed_soll + 24) { akt_speed -= 24; if(akt_speed > akt_speed_soll+kmh_to_speed(20)) { akt_speed = akt_speed_soll+kmh_to_speed(20); } } else { akt_speed = akt_speed_soll; } } // new record? if(akt_speed > max_record_speed) { max_record_speed = akt_speed; record_pos = fahr[0]->get_pos(); } } /** * Calculates maximal possible speed. * Uses iterative technique to take care of integer arithmetic. */ sint32 convoi_t::calc_max_speed(uint64 total_power, uint64 total_weight, sint32 speed_limit) { // precision is 0.5 km/h const sint32 tol = kmh_to_speed(1)/2; // bisection to find max speed sint32 pl,pr,pm; sint64 sl,sr,sm; // test speed_limit sr = speed_limit; pr = res_power(sr, (sint32)total_power, total_weight, total_weight); if (pr >= 0) { return (sint32)sr; // convoy can travel at speed given by speed_limit } sl = 1; pl = res_power(sl, (sint32)total_power, total_weight, total_weight); if (pl <= 0) { return 0; // no power to move at all } // bisection algorithm to find speed for which residual power is zero while (sr - sl > tol) { sm = (sl + sr)/2; if (sm == sl) break; pm = res_power(sm, (sint32)total_power, total_weight, total_weight); if (((sint64)pl)*pm <= 0) { pr = pm; sr = sm; } else { pl = pm; sl = sm; } } return (sint32)sl; } int convoi_t::get_vehicle_at_length(uint16 length) { int current_length = 0; for( int i=0; iget_desc()->get_length(); if(length 0) { return SYNC_OK; } switch(state) { case INITIAL: // in depot, should not be in sync list, remove return SYNC_REMOVE; case EDIT_SCHEDULE: case ROUTING_1: case DUMMY4: case DUMMY5: case NO_ROUTE: case CAN_START: case CAN_START_ONE_MONTH: case CAN_START_TWO_MONTHS: // this is an async task, see step() break; case ENTERING_DEPOT: break; case LEAVING_DEPOT: { // ok, so we will accelerate akt_speed_soll = max( akt_speed_soll, kmh_to_speed(30) ); calc_acceleration(delta_t); sp_soll += (akt_speed*delta_t); // now actually move the units while(sp_soll>>12) { // Attempt to move one step. uint32 sp_hat = fahr[0]->do_drive(1<0 ) { steps_driven++; } int v_nr = get_vehicle_at_length(steps_driven>>4); // stop when depot reached if (state==INITIAL) { return SYNC_REMOVE; } if (state==ROUTING_1) { break; } if( v_nr==vehicle_count ) { // all are moving steps_driven = -1; state = DRIVING; return SYNC_OK; } else if( sp_hat==0 ) { // something went wrong. wait for next sync_step() return SYNC_OK; } // now only the right numbers for(int i=1; i<=v_nr; i++) { fahr[i]->do_drive(sp_hat); } sp_soll -= sp_hat; } // smoke for the engines next_wolke += delta_t; if(next_wolke>500) { next_wolke = 0; for(int i=0; imake_smoke(); } } } break; // LEAVING_DEPOT case DRIVING: { calc_acceleration(delta_t); // now actually move the units sp_soll += (akt_speed*delta_t); uint32 sp_hat = fahr[0]->do_drive(sp_soll); // stop when depot reached ... if(state==INITIAL) { return SYNC_REMOVE; } // now move the rest (so all vehicles are moving synchronously) for(unsigned i=1; ido_drive(sp_hat); } // maybe we have been stopped by something => avoid wide jumps sp_soll = (sp_soll-sp_hat) & 0x0FFF; // smoke for the engines next_wolke += delta_t; if(next_wolke>500) { next_wolke = 0; for(int i=0; imake_smoke(); } } } break; // DRIVING case LOADING: // loading is an async task, see laden() break; case WAITING_FOR_CLEARANCE: case WAITING_FOR_CLEARANCE_ONE_MONTH: case WAITING_FOR_CLEARANCE_TWO_MONTHS: // waiting is asynchronous => fixed waiting order and route search break; case SELF_DESTRUCT: // see step, since destruction during a screen update may give strange effects break; default: dbg->fatal("convoi_t::sync_step()", "Wrong state %d!\n", state); } return SYNC_OK; } /** * Berechne route von Start- zu Zielkoordinate */ bool convoi_t::drive_to() { if( vehicle_count>0 ) { // unreserve all tiles that are covered by the train but do not contain one of the wagons, // otherwise repositioning of the train drive_to may lead to stray reserved tiles if (dynamic_cast(fahr[0])!=NULL && vehicle_count > 1) { // route-index points to next position in route // it is completely off when convoi leaves depot route_t::index_t index0 = min(fahr[0]->get_route_index()-1, route.get_count()); for(uint8 i=1; iget_route_index(); for(route_t::index_t j = index1; jlookup(route.at(j)); if (schiene_t *track = (schiene_t *)gr->get_weg( front()->get_waytype() ) ) { track->unreserve(self); } } index0 = min(index1-1, route.get_count()); } } koord3d start = fahr[0]->get_pos(); koord3d ziel = schedule->get_current_entry().pos; // avoid stopping mid-halt if( start==ziel ) { halthandle_t halt = haltestelle_t::get_halt(ziel,get_owner()); if( halt.is_bound() && route.is_contained(start) ) { for( uint32 i=route.index_of(start); ilookup(route.at(i)); if( gr && gr->get_halt()==halt ) { ziel = gr->get_pos(); } else { break; } } } } if( !fahr[0]->calc_route( start, ziel, speed_to_kmh(min_top_speed), &route ) ) { if( state != NO_ROUTE ) { state = NO_ROUTE; get_owner()->report_vehicle_problem( self, ziel ); } // wait 25s before next attempt wait_lock = 25000; } else { bool route_ok = true; const uint8 current_stop = schedule->get_current_stop(); if( fahr[0]->get_waytype() != water_wt ) { air_vehicle_t *const plane = dynamic_cast(fahr[0]); uint32 takeoff = 0, search = 0, landing = 0; air_vehicle_t::flight_state plane_state = air_vehicle_t::taxiing; if( plane ) { // due to the complex state system of aircrafts, we have to save index and state plane->get_event_index( plane_state, takeoff, search, landing ); } // set next schedule target position if next is a waypoint if( is_waypoint(ziel) ) { schedule_target = ziel; } // continue route search until the destination is a station while( is_waypoint(ziel) ) { start = ziel; schedule->advance(); ziel = schedule->get_current_entry().pos; if( schedule->get_current_stop() == current_stop ) { // looped around without finding a halt => entire schedule is waypoints. break; } route_t next_segment; if( !fahr[0]->calc_route( start, ziel, speed_to_kmh(min_top_speed), &next_segment ) ) { // do we still have a valid route to proceed => then go until there if( route.get_count()>1 ) { break; } // we are stuck on our first routing attempt => give up if( state != NO_ROUTE ) { state = NO_ROUTE; get_owner()->report_vehicle_problem( self, ziel ); } // wait 25s before next attempt wait_lock = 25000; route_ok = false; break; } else { bool looped = false; if( fahr[0]->get_waytype() != air_wt ) { // check if the route circles back on itself (only check the first tile, should be enough) looped = route.is_contained(next_segment.at(1)); #if 0 // this will forbid an eight figure, which might be clever to avoid a problem of reserving one own track for( unsigned i = 1; iget_event_index( dummy1, new_takeoff, new_search, new_landing ); if( takeoff == 0x7FFFFFFF && new_takeoff != 0x7FFFFFFF ) { takeoff = new_takeoff + count_offset; } if( landing == 0x7FFFFFFF && new_landing != 0x7FFFFFFF ) { landing = new_landing + count_offset; } if( search == 0x7FFFFFFF && new_search != 0x7FFFFFFF ) { search = new_search + count_offset; } } } } } if( plane ) { // due to the complex state system of aircrafts, we have to restore index and state plane->set_event_index( plane_state, takeoff, search, landing ); } } schedule->set_current_stop(current_stop); if( route_ok ) { vorfahren(); return true; } } } return false; } /** * Ein Fahrzeug hat ein Problem erkannt und erzwingt die * Berechnung einer neuen Route */ void convoi_t::suche_neue_route() { state = ROUTING_1; wait_lock = 0; } /** * Asynchrne step methode des Convois */ void convoi_t::step() { if( wait_lock > 0 ) { return; } // moved check to here, as this will apply the same update // logic/constraints convois have for manual schedule manipulation if (line_update_pending.is_bound()) { check_pending_updates(); } if( state==LOADING ) { // handled seperately, since otherwise departures are delayed laden(); } switch(state) { case LOADING: // handled above break; case DUMMY4: case DUMMY5: break; case EDIT_SCHEDULE: // schedule window closed? if(schedule!=NULL && schedule->is_editing_finished()) { set_schedule(schedule); schedule_target = koord3d::invalid; if( schedule->empty() ) { // no entry => no route ... state = NO_ROUTE; owner->report_vehicle_problem( self, koord3d::invalid ); } else { // Schedule changed at station // this station? then complete loading task else drive on halthandle_t h = haltestelle_t::get_halt( get_pos(), get_owner() ); if( h.is_bound() && h==haltestelle_t::get_halt( schedule->get_current_entry().pos, get_owner() ) ) { if (route.get_count() > 0) { koord3d const& pos = route.back(); if (h == haltestelle_t::get_halt(pos, get_owner())) { state = get_pos() == pos ? LOADING : DRIVING; break; } } else { if( drive_to() ) { state = DRIVING; break; } } } if( schedule->get_current_entry().pos==get_pos() ) { // position in depot: waiting grund_t *gr = welt->lookup(schedule->get_current_entry().pos); if( gr && gr->get_depot() ) { betrete_depot( gr->get_depot() ); } else { state = ROUTING_1; } } else { // go to next state = ROUTING_1; } } } break; case ROUTING_1: { vehicle_t* v = fahr[0]; if( schedule->empty() ) { state = NO_ROUTE; owner->report_vehicle_problem( self, koord3d::invalid ); } else { // check first, if we are already there: assert( schedule->get_current_stop()get_count() ); if( v->get_pos()==schedule->get_current_entry().pos ) { schedule->advance(); } // now calculate a new route drive_to(); // finally, was there a record last time? if(max_record_speed>welt->get_record_speed(fahr[0]->get_waytype())) { welt->notify_record(self, max_record_speed, record_pos); } } } break; case NO_ROUTE: // stuck vehicles if (schedule->empty()) { // no entries => no route ... } else { // now calculate a new route drive_to(); } break; case CAN_START: case CAN_START_ONE_MONTH: case CAN_START_TWO_MONTHS: { vehicle_t* v = fahr[0]; sint32 restart_speed = -1; if( v->can_enter_tile( restart_speed, 0 ) ) { // can reserve new block => drive on state = (steps_driven>=0) ? LEAVING_DEPOT : DRIVING; if(haltestelle_t::get_halt(v->get_pos(),owner).is_bound()) { v->play_sound(); } } else if( steps_driven==0 ) { // on rail depot tile, do not reserve this if( grund_t *gr = welt->lookup(fahr[0]->get_pos()) ) { if (schiene_t* const sch0 = obj_cast(gr->get_weg(fahr[0]->get_waytype()))) { sch0->unreserve(fahr[0]); } } } if(restart_speed>=0) { akt_speed = restart_speed; } if(state==CAN_START || state==CAN_START_ONE_MONTH) { set_tiles_overtaking( 0 ); } } break; case WAITING_FOR_CLEARANCE_ONE_MONTH: case WAITING_FOR_CLEARANCE_TWO_MONTHS: case WAITING_FOR_CLEARANCE: { sint32 restart_speed = -1; if( fahr[0]->can_enter_tile( restart_speed, 0 ) ) { state = (steps_driven>=0) ? LEAVING_DEPOT : DRIVING; } if(restart_speed>=0) { akt_speed = restart_speed; } if(state!=DRIVING) { set_tiles_overtaking( 0 ); } } break; // must be here; may otherwise confuse window management case SELF_DESTRUCT: welt->set_dirty(); destroy(); return; // must not continue method after deleting this object default: /* keeps compiler silent*/ break; } // calculate new waiting time switch( state ) { // handled by routine case LOADING: break; // immediate action needed case SELF_DESTRUCT: case LEAVING_DEPOT: case ENTERING_DEPOT: case DRIVING: case DUMMY4: case DUMMY5: wait_lock = 0; break; // just waiting for action here case INITIAL: welt->sync.remove(this); // FALLTHROUGH case EDIT_SCHEDULE: case NO_ROUTE: wait_lock = max( wait_lock, 25000 ); break; // Same as waiting for free way case ROUTING_1: // immediate start required if (wait_lock == 0) break; // FALLTHROUGH case CAN_START: case WAITING_FOR_CLEARANCE: // unless a longer wait is requested if (wait_lock > 2500) { break; } // FALLTHROUGH // waiting for free way, not too heavy, not to slow case CAN_START_ONE_MONTH: case WAITING_FOR_CLEARANCE_ONE_MONTH: case CAN_START_TWO_MONTHS: case WAITING_FOR_CLEARANCE_TWO_MONTHS: // to avoid having a convoi stuck at a heavy traffic intersection/signal, the waiting time is randomized wait_lock = simrand(5000)+1; break; default: ; } } void convoi_t::new_year() { jahresgewinn = 0; } void convoi_t::new_month() { // should not happen: leftover convoi without vehicles ... if(vehicle_count==0) { DBG_DEBUG("convoi_t::new_month()","no vehicles => self destruct!"); self_destruct(); return; } // update statistics of average speed if( maxspeed_average_count==0 ) { financial_history[0][CONVOI_MAXSPEED] = distance_since_last_stop>0 ? get_speedbonus_kmh() : 0; } maxspeed_average_count = 0; // everything normal: update histroy for (int j = 0; j0; k--) { financial_history[k][j] = financial_history[k-1][j]; } financial_history[0][j] = 0; } // remind every new month again if( state==NO_ROUTE ) { get_owner()->report_vehicle_problem( self, get_pos() ); } // check for traffic jam if(state==WAITING_FOR_CLEARANCE) { state = WAITING_FOR_CLEARANCE_ONE_MONTH; // check, if now free ... // might also reset the state! sint32 restart_speed = -1; if( fahr[0]->can_enter_tile( restart_speed, 0 ) ) { state = DRIVING; } if(restart_speed>=0) { akt_speed = restart_speed; } } else if(state==WAITING_FOR_CLEARANCE_ONE_MONTH) { // make sure, not another vehicle with same line is loading in front bool notify = true; // check, if we are not waiting for load if( line.is_bound() && loading_level==0 ) { for( uint i=0; i < line->count_convoys(); i++ ) { convoihandle_t cnv = line->get_convoy(i); if( cnv.is_bound() && cnv->get_state()==LOADING && cnv->get_loading_level() < cnv->get_loading_limit() ) { // convoi on this line is waiting for load => assume we are waiting behind notify = false; break; } } } if( notify ) { get_owner()->report_vehicle_problem( self, koord3d::invalid ); } state = WAITING_FOR_CLEARANCE_TWO_MONTHS; } // check for traffic jam if(state==CAN_START) { state = CAN_START_ONE_MONTH; } else if(state==CAN_START_ONE_MONTH || state==CAN_START_TWO_MONTHS ) { get_owner()->report_vehicle_problem( self, koord3d::invalid ); state = CAN_START_TWO_MONTHS; } // check for obsolete vehicles in the convoi if(!has_obsolete && welt->use_timeline()) { // convoi has obsolete vehicles? const int month_now = welt->get_timeline_year_month(); has_obsolete = false; for(unsigned j=0; jget_desc()->is_retired(month_now)) { has_obsolete = true; break; } } } // book fixed cost as running cost book( sum_fixed_costs, CONVOI_OPERATIONS ); book( sum_fixed_costs, CONVOI_PROFIT ); // since convois can be in the depot, the waytypewithout schedule is determined from the vechile (if there) // one can argue that convois in depots should not cost money ... waytype_t wtyp = ignore_wt; if( schedule_t* s = get_schedule() ) { wtyp = s->get_waytype(); } else if( !fahr.empty() ) { wtyp = fahr[0]->get_waytype(); } get_owner()->book_running_costs( sum_fixed_costs, wtyp ); jahresgewinn += sum_fixed_costs; } void convoi_t::betrete_depot(depot_t *dep) { // first remove reservation, if train is still on track unreserve_route(); // remove vehicles from world data structure for(unsigned i=0; ilookup(v->get_pos()); if(gr) { // remove from blockstrecke v->set_last(true); v->leave_tile(); v->set_flag( obj_t::not_on_map ); } } dep->convoi_arrived(self, get_schedule()); destroy_win( magic_convoi_info+self.get_id() ); maxspeed_average_count = 0; state = INITIAL; } void convoi_t::start() { if( state == EDIT_SCHEDULE && schedule && schedule->is_editing_finished() ) { // go to defined starting state wait_lock = 0; step(); } if(state == INITIAL || state == ROUTING_1) { // set home depot to location of depot convoi is leaving if(route.empty()) { home_depot = fahr[0]->get_pos(); } else { home_depot = route.front(); fahr[0]->set_pos( home_depot ); } // put the convoi on the depot ground, to get automatic rotation // (vorfahren() will remove it anyway again.) grund_t *gr = welt->lookup( home_depot ); assert(gr); gr->obj_add( fahr[0] ); // put into sync list welt->sync.add(this); alte_richtung = ribi_t::none; no_load = false; state = ROUTING_1; // recalc weight and image // also for any vehicle entered a depot, set_letztes is true! => reset it correctly sint64 restwert_delta = 0; for(unsigned i=0; iset_leading( false ); fahr[i]->set_last( false ); restwert_delta -= fahr[i]->calc_sale_value(); fahr[i]->set_driven(); restwert_delta += fahr[i]->calc_sale_value(); fahr[i]->clear_flag( obj_t::not_on_map ); } fahr[0]->set_leading( true ); fahr[vehicle_count-1]->set_last( true ); // do not show the vehicle - it will be wrong positioned -vorfahren() will correct this fahr[0]->set_image(IMG_EMPTY); // update finances for used vehicle reduction when first driven owner->update_assets( restwert_delta, get_schedule()->get_waytype()); // calc state for convoi calc_loading(); calc_speedbonus_kmh(); maxspeed_average_count = 0; if(line.is_bound()) { // might have changed the vehicles in this car ... line->recalc_catg_index(); } else { welt->set_schedule_counter(); } wait_lock = 0; DBG_MESSAGE("convoi_t::start()","Convoi %s wechselt von INITIAL nach ROUTING_1", name_and_id); } else { dbg->warning("convoi_t::start()","called with state=%s\n",state_names[state]); } } /* called, when at a destination * can be waypoint, depot or a stop * called from the first vehicle_t of a convoi */ void convoi_t::ziel_erreicht() { const vehicle_t* v = fahr[0]; alte_richtung = v->get_direction(); // check, what is at destination! const grund_t *gr = welt->lookup(v->get_pos()); depot_t *dp = gr->get_depot(); if(dp) { // ok, we are entering a depot cbuffer_t buf; // we still book the money for the trip; however, the freight will be deleted (by the vehicle in the depot itself) calc_gewinn(); akt_speed = 0; buf.printf( translator::translate("%s has entered a depot."), get_name() ); welt->get_message()->add_message(buf, v->get_pos(),message_t::warnings, PLAYER_FLAG|get_owner()->get_player_nr(), IMG_EMPTY); betrete_depot(dp); } else { // no depot reached, check for stop! halthandle_t halt = haltestelle_t::get_halt(schedule->get_current_entry().pos,owner); if( halt.is_bound() && gr->get_weg_ribi(v->get_waytype())!=0 ) { // seems to be a stop, so book the money for the trip calc_gewinn(); akt_speed = 0; halt->book(1, HALT_CONVOIS_ARRIVED); state = LOADING; arrived_time = welt->get_ticks(); last_load_tick = arrived_time; } else { // Neither depot nor station: waypoint schedule->advance(); state = ROUTING_1; } } wait_lock = 0; } /** * Wartet bis Fahrzeug 0 freie Fahrt meldet */ void convoi_t::warten_bis_weg_frei(sint32 restart_speed) { if(!is_waiting()) { state = WAITING_FOR_CLEARANCE; wait_lock = 0; } if(restart_speed>=0) { // langsam anfahren akt_speed = restart_speed; } } bool convoi_t::add_vehicle(vehicle_t *v, bool infront) { DBG_MESSAGE("convoi_t::add_vehicle()","at pos %i of %i total vehicles.",vehicle_count,fahr.get_count()); // extend array if requested if(vehicle_count == fahr.get_count()) { fahr.resize(vehicle_count+1,NULL); DBG_MESSAGE("convoi_t::add_vehicle()","extend array_tpl to %i totals.",fahr.get_count()); } // now append if (vehicle_count < fahr.get_count()) { v->set_convoi(this); if(infront) { for(unsigned i = vehicle_count; i > 0; i--) { fahr[i] = fahr[i - 1]; } fahr[0] = v; } else { fahr[vehicle_count] = v; } vehicle_count ++; const vehicle_desc_t *info = v->get_desc(); if(info->get_power()) { is_electric |= info->get_engine_type()==vehicle_desc_t::electric; } sum_power += info->get_power(); sum_gear_and_power += info->get_power()*info->get_gear(); sum_weight += info->get_weight(); sum_running_costs -= info->get_running_cost(); sum_fixed_costs -= welt->scale_with_month_length( info->get_fixed_cost() ); min_top_speed = min( min_top_speed, kmh_to_speed( v->get_desc()->get_topspeed() ) ); sum_gesamtweight = sum_weight; calc_loading(); freight_info_resort = true; // Add good_catg_index: if(v->get_cargo_max() != 0) { const goods_desc_t *ware=v->get_cargo_type(); if(ware!=goods_manager_t::none ) { goods_catg_index.append_unique( ware->get_catg_index() ); } } // check for obsolete if(!has_obsolete && welt->use_timeline()) { has_obsolete = info->is_retired( welt->get_timeline_year_month() ); } } else { return false; } // der convoi hat jetzt ein neues ende set_erstes_letztes(); DBG_MESSAGE("convoi_t::add_vehicle()","now %i of %i total vehicles.",vehicle_count,fahr.get_count()); return true; } vehicle_t *convoi_t::remove_vehicle_at(uint16 i) { vehicle_t *v = NULL; if(iset_convoi(NULL); --vehicle_count; fahr[vehicle_count] = NULL; const vehicle_desc_t *info = v->get_desc(); sum_power -= info->get_power(); sum_gear_and_power -= info->get_power()*info->get_gear(); sum_weight -= info->get_weight(); sum_running_costs += info->get_running_cost(); sum_fixed_costs += welt->scale_with_month_length( info->get_fixed_cost() ); } sum_gesamtweight = sum_weight; calc_loading(); freight_info_resort = true; // der convoi hat jetzt ein neues ende if(vehicle_count > 0) { set_erstes_letztes(); } // calculate new minimum top speed min_top_speed = calc_min_top_speed(fahr, vehicle_count); // check for obsolete if(has_obsolete) { has_obsolete = false; const int month_now = welt->get_timeline_year_month(); for(unsigned i=0; iget_desc()->is_retired(month_now); } } recalc_catg_index(); // still requires electrifications? if(is_electric) { is_electric = false; for(unsigned i=0; iget_desc()->get_power()) { is_electric |= fahr[i]->get_desc()->get_engine_type()==vehicle_desc_t::electric; } } } } return v; } // recalc what good this convoy is moving void convoi_t::recalc_catg_index() { goods_catg_index.clear(); for( uint8 i = 0; i < get_vehicle_count(); i++ ) { // Only consider vehicles that really transport something // this helps against routing errors through passenger // trains pulling only freight wagons if(get_vehicle(i)->get_cargo_max() == 0) { continue; } const goods_desc_t *ware=get_vehicle(i)->get_cargo_type(); if(ware!=goods_manager_t::none ) { goods_catg_index.append_unique( ware->get_catg_index() ); } } /* since during composition of convois all kinds of composition could happen, * we do not enforce schedule recalculation here; it will be done anyway all times when leaving the INTI state ... */ } void convoi_t::set_erstes_letztes() { // vehicle_count muss korrekt init sein if(vehicle_count>0) { fahr[0]->set_leading(true); for(unsigned i=1; iset_leading(false); fahr[i - 1]->set_last(false); } fahr[vehicle_count - 1]->set_last(true); } else { dbg->warning("convoi_t::set_erstes_letzes()", "called with vehicle_count==0!"); } } // remove wrong freight when schedule changes etc. void convoi_t::check_freight() { for(unsigned i=0; iremove_stale_cargo(); } calc_loading(); freight_info_resort = true; } bool convoi_t::set_schedule(schedule_t * f) { if( state==SELF_DESTRUCT ) { return false; } DBG_DEBUG("convoi_t::set_schedule()", "new=%p, old=%p", f, schedule); assert(f != NULL); // happens to be identical? if(schedule!=f) { // now check, we we have been bond to a line we are about to lose: bool changed = false; if( line.is_bound() ) { if( !f->matches( welt, line->get_schedule() ) ) { // change from line to individual schedule // -> unset line now and register stops from new schedule later changed = true; unset_line(); } } else { if( !f->matches( welt, schedule ) ) { // merely change schedule and do not involve line // -> unregister stops from old schedule now and register stops from new schedule later changed = true; unregister_stops(); } } #ifdef BAD_IDEA // destroy a possibly open schedule window if( schedule && !schedule->is_editing_finished() ) { destroy_win((ptrdiff_t)schedule); delete schedule; } #endif schedule = f; if( changed ) { // if line is unset or schedule is changed // -> register stops from new schedule register_stops(); welt->set_schedule_counter(); // must trigger refresh } } // remove wrong freight check_freight(); // ok, now we have a schedule if(state != INITIAL) { state = EDIT_SCHEDULE; } // to avoid jumping trains alte_richtung = fahr[0]->get_direction(); wait_lock = 0; return true; } schedule_t *convoi_t::create_schedule() { if(schedule == NULL) { const vehicle_t* v = fahr[0]; if (v != NULL) { schedule = v->generate_new_schedule(); schedule->finish_editing(); } } return schedule; } /* checks, if we go in the same direction; * true: convoy prepared * false: must recalculate position * on all error we better use the normal starting procedure ... */ bool convoi_t::can_go_alte_richtung() { // invalid route? nothing to test, must start new if(route.empty()) { return false; } // going backwards? then recalculate all ribi_t::ribi neue_richtung_rwr = ribi_t::backward(fahr[0]->calc_direction(route.front(), route.at(min(2, route.get_count() - 1)))); // DBG_MESSAGE("convoi_t::go_alte_richtung()","neu=%i,rwr_neu=%i,alt=%i",neue_richtung_rwr,ribi_t::backward(neue_richtung_rwr),alte_richtung); if(neue_richtung_rwr&alte_richtung) { akt_speed = 8; return false; } // now get the actual length and the tile length uint16 convoi_length = 15; uint16 tile_length = 24; unsigned i; // for visual C++ const vehicle_t* pred = NULL; for(i=0; ilookup(v->get_pos()); // not last vehicle? // the length of last vehicle does not matter when it comes to positioning of vehicles if ( i+1 < vehicle_count) { convoi_length += v->get_desc()->get_length(); } if(gr==NULL || (pred!=NULL && (abs(v->get_pos().x-pred->get_pos().x)>=2 || abs(v->get_pos().y-pred->get_pos().y)>=2)) ) { // ending here is an error! // this is an already broken train => restart dbg->warning("convoi_t::go_alte_richtung()","broken convoy (id %i) found => fixing!",self.get_id()); akt_speed = 8; return false; } // now check, if ribi is straight and train is not ribi_t::ribi weg_ribi = gr->get_weg_ribi_unmasked(v->get_waytype()); if(ribi_t::is_straight(weg_ribi) && (weg_ribi|v->get_direction())!=weg_ribi) { dbg->warning("convoi_t::go_alte_richtung()","convoy with wrong vehicle directions (id %i) found => fixing!",self.get_id()); akt_speed = 8; return false; } if( pred && pred->get_pos()!=v->get_pos() ) { tile_length += (ribi_t::is_straight(welt->lookup(pred->get_pos())->get_weg_ribi_unmasked(pred->get_waytype())) ? 16 : 8192/vehicle_t::get_diagonal_multiplier())*koord_distance(pred->get_pos(),v->get_pos()); } pred = v; } // check if convoi is way too short (even for diagonal tracks) tile_length += (ribi_t::is_straight(welt->lookup(fahr[vehicle_count-1]->get_pos())->get_weg_ribi_unmasked(fahr[vehicle_count-1]->get_waytype())) ? 16 : 8192/vehicle_t::get_diagonal_multiplier()); if( convoi_length>tile_length ) { dbg->warning("convoi_t::go_alte_richtung()","convoy too short (id %i) => fixing!",self.get_id()); akt_speed = 8; return false; } uint16 length = min((convoi_length/16u)+4u,route.get_count()); // maximum length in tiles to check // we just check, whether we go back (i.e. route tiles other than zero have convoi vehicles on them) for( int index=1; indexlookup(route.at(index)); // now check, if we are already here ... for(unsigned i=0; iobj_ist_da(fahr[i])) { // we are turning around => start slowly and rebuilt train akt_speed = 8; return false; } } } //DBG_MESSAGE("convoi_t::go_alte_richtung()","alte=%d, neu_rwr=%d",alte_richtung,neue_richtung_rwr); // we continue our journey; however later cars need also a correct route entry // eventually we need to add their positions to the convois route koord3d pos = fahr[0]->get_pos(); assert(pos == route.front()); if(welt->lookup(pos)->get_depot()) { return false; } else { for(i=0; iget_pos() && route.at(1) != v->get_pos()) { route.insert(v->get_pos()); } } } // since we need the route for every vehicle of this convoi, // we must set the current route index (instead assuming 1) length = min((convoi_length/8u),route.get_count()-1); // maximum length in tiles to check bool ok=false; for(i=0; iget_pos(); for( route_t::index_t idx = 0; idx<=length; idx++ ) { if(route.at(idx)==vehicle_start_pos) { // set route index, no recalculations necessary v->initialise_journey(idx, false ); ok = true; // check direction uint8 richtung = v->get_direction(); uint8 neu_richtung = v->calc_direction( route.at(max(idx-1,0)), v->get_pos_next()); // we need to move to this place ... if(neu_richtung!=richtung && (i!=0 || vehicle_count==1 || ribi_t::is_bend(neu_richtung)) ) { // 90 deg bend! return false; } break; } } // too short?!? (rather broken then!) if(!ok) { return false; } } return true; } // put the convoi on its way void convoi_t::vorfahren() { // init speed settings sp_soll = 0; set_tiles_overtaking( 0 ); recalc_data_front = true; recalc_data = true; koord3d k0 = route.front(); grund_t *gr = welt->lookup(k0); bool at_dest = false; if(gr && gr->get_depot()) { // start in depot for(unsigned i=0; ilookup(v->get_pos()); if(gr) { gr->obj_remove(v); if(gr->ist_uebergang()) { crossing_t *cr = gr->find(2); cr->release_crossing(v); } // eventually unreserve this if( schiene_t* const sch0 = obj_cast(gr->get_weg(fahr[i]->get_waytype())) ) { sch0->unreserve(v); } } v->initialise_journey(0, true); // set at new position gr = welt->lookup(v->get_pos()); assert(gr); v->enter_tile(gr); } // just advances the first vehicle vehicle_t* v0 = fahr[0]; v0->set_leading(false); // switches off signal checks ... v0->set_smoke_enabled(false); steps_driven = 0; // drive half a tile: for(int i=0; ido_drive( (VEHICLE_STEPS_PER_TILE/2)<set_smoke_enabled(true); v0->set_leading(true); // switches on signal checks to reserve the next route // until all other are on the track state = CAN_START; } else { // still leaving depot (steps_driven!=0) or going in other direction or misalignment? if( steps_driven>0 || !can_go_alte_richtung() ) { // start route from the beginning at index 0, place everything on start uint32 train_length = move_to(0); // move one train length to the start position ... // in north/west direction, we leave the vehicle away to start as much back as possible ribi_t::ribi neue_richtung = fahr[0]->get_direction(); if(neue_richtung==ribi_t::south || neue_richtung==ribi_t::east) { // drive the convoi to the same position, but do not hop into next tile! if( train_length%16==0 ) { // any space we need => just add train_length += fahr[vehicle_count-1]->get_desc()->get_length(); } else { // limit train to front of tile train_length += min( (train_length%CARUNITS_PER_TILE)-1, fahr[vehicle_count-1]->get_desc()->get_length() ); } } else { train_length += 1; } train_length = max(1,train_length); // now advance all convoi until it is completely on the track fahr[0]->set_leading(fahr[0]->get_waytype()==air_wt); // switches off signal checks ... uint32 dist = (VEHICLE_STEPS_PER_CARUNIT*train_length) << YARDS_PER_VEHICLE_STEP_SHIFT; for(unsigned i=0; iset_smoke_enabled(false); uint32 const driven = fahr[i]->do_drive( dist ); if (i==0 && driven < dist) { // we are already at our destination at_dest = true; } // this gives the length in carunits, 1/CARUNITS_PER_TILE of a full tile => all cars closely coupled! v->set_smoke_enabled(true); uint32 const vlen = (VEHICLE_STEPS_PER_CARUNIT*v->get_desc()->get_length()) << YARDS_PER_VEHICLE_STEP_SHIFT; if (vlen > dist) { break; } dist = driven - vlen; } fahr[0]->set_leading(true); } if (!at_dest) { state = CAN_START; // to advance more smoothly sint32 restart_speed = -1; if( fahr[0]->can_enter_tile( restart_speed, 0 ) ) { // can reserve new block => drive on if(haltestelle_t::get_halt(k0,owner).is_bound()) { fahr[0]->play_sound(); } state = DRIVING; } } else { ziel_erreicht(); } } // finally reserve route (if needed) if( fahr[0]->get_waytype()!=air_wt && !at_dest ) { // do not pre-reserve for airplanes for(unsigned i=0; i(welt->lookup(v.get_pos())->get_weg(v.get_waytype()))) { sch0->reserve(self,ribi_t::none); } else { break; } } } wait_lock = 0; INT_CHECK("simconvoi 711"); } void convoi_t::rdwr_convoihandle_t(loadsave_t *file, convoihandle_t &cnv) { if( file->is_version_atleast(112, 3) ) { uint16 id = (file->is_saving() && cnv.is_bound()) ? cnv.get_id() : 0; file->rdwr_short( id ); if (file->is_loading()) { cnv.set_id( id ); } } } void convoi_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "convoi_t" ); sint32 dummy; sint32 owner_n = welt->sp2num(owner); if(file->is_saving()) { if( file->is_version_less(101, 0) ) { file->wr_obj_id("Convoi"); // the matching read is in karte_t::laden(loadsave*)... } } // do the update, otherwise we might lose the line after save & reload if(file->is_saving() && line_update_pending.is_bound()) { check_pending_updates(); } simline_t::rdwr_linehandle_t(file, line); // we want persistent convoihandles so we can keep dialogues open in network games if( file->is_loading() ) { if( file->is_version_less(112, 3) ) { self = convoihandle_t( this ); } else { uint16 id; file->rdwr_short( id ); self = convoihandle_t( this, id ); } } else if( file->is_version_atleast(112, 3) ) { uint16 id = self.get_id(); file->rdwr_short( id ); } dummy = vehicle_count; file->rdwr_long(dummy); vehicle_count = (uint8)dummy; if(file->is_version_less(99, 14)) { // was anz_ready file->rdwr_long(dummy); } sint32 wl = wait_lock; file->rdwr_long(wl); wait_lock = clamp(wl, 0, 0xFFFF); bool dummy_bool=false; file->rdwr_bool(dummy_bool); file->rdwr_long(owner_n); file->rdwr_long(akt_speed); file->rdwr_long(akt_speed_soll); file->rdwr_long(sp_soll); file->rdwr_enum(state); file->rdwr_enum(alte_richtung); // read the yearly income (which has since then become a 64 bit value) // will be recalculated later directly from the history if(file->is_version_less(89, 4)) { file->rdwr_long(dummy); } route.rdwr(file); if(file->is_loading()) { // extend array if requested (only needed for trains) if(vehicle_count > fahr.get_count()) { fahr.resize(vehicle_count, NULL); } owner = welt->get_player_or_create( owner_n ); // sanity check for values ... plus correction if(sp_soll < 0) { sp_soll = 0; } } file->rdwr_str(name_and_id + name_offset, lengthof(name_and_id) - name_offset); if(file->is_loading()) { set_name(name_and_id+name_offset); // will add id automatically } koord3d dummy_pos; if(file->is_saving()) { for(unsigned i=0; iwr_obj_id( fahr[i]->get_typ() ); fahr[i]->rdwr_from_convoi(file); } } else { bool override_monorail = false; is_electric = false; for( uint8 i=0; ird_obj_id(); vehicle_t *v = 0; const bool first = (i==0); const bool last = (i==vehicle_count-1u); if(override_monorail) { // ignore type for ancient monorails v = new monorail_vehicle_t(file, first, last); } else { switch(typ) { case obj_t::old_automobil: case obj_t::road_vehicle: v = new road_vehicle_t(file, first, last); break; case obj_t::old_waggon: case obj_t::rail_vehicle: v = new rail_vehicle_t(file, first, last); break; case obj_t::old_schiff: case obj_t::water_vehicle: v = new water_vehicle_t(file, first, last); break; case obj_t::old_aircraft: case obj_t::air_vehicle: v = new air_vehicle_t(file, first, last); break; case obj_t::old_monorailwaggon: case obj_t::monorail_vehicle: v = new monorail_vehicle_t(file, first, last); break; case obj_t::maglev_vehicle: v = new maglev_vehicle_t(file, first, last); break; case obj_t::narrowgauge_vehicle: v = new narrowgauge_vehicle_t(file, first, last); break; default: dbg->fatal("convoi_t::convoi_t()","Can't load vehicle type %d", typ); } } // no matching vehicle found? if(v->get_desc()==NULL) { // will create orphan object, but better than crashing at deletion ... dbg->error("convoi_t::convoi_t()","Can't load vehicle and no replacement found!"); i --; vehicle_count --; continue; } // in very old games, monorail was a railway // so we need to convert this // freight will be lost, but game will be loadable if(i==0 && v->get_desc()->get_waytype()==monorail_wt && v->get_typ()==obj_t::rail_vehicle) { override_monorail = true; vehicle_t *v_neu = new monorail_vehicle_t( v->get_pos(), v->get_desc(), v->get_owner(), NULL ); v->discard_cargo(); delete v; v = v_neu; } if(file->is_version_less(99, 4)) { dummy_pos.rdwr(file); } const vehicle_desc_t *info = v->get_desc(); assert(info); // if we load a game from a file which was saved from a // game with a different vehicle.tab, there might be no vehicle // info if(info) { sum_power += info->get_power(); sum_gear_and_power += info->get_power()*info->get_gear(); sum_weight += info->get_weight(); sum_running_costs -= info->get_running_cost(); sum_fixed_costs -= welt->scale_with_month_length( info->get_fixed_cost() ); is_electric |= info->get_engine_type()==vehicle_desc_t::electric; has_obsolete |= welt->use_timeline() && info->is_retired( welt->get_timeline_year_month() ); // we do not add maintenance here, the fixed costs are booked as running costs } // some versions save vehicles after leaving depot with koord3d::invalid if(v->get_pos()==koord3d::invalid) { state = INITIAL; } if(state!=INITIAL) { grund_t *gr; gr = welt->lookup(v->get_pos()); if(!gr) { gr = welt->lookup_kartenboden(v->get_pos().get_2d()); if(gr) { dbg->error("convoi_t::rdwr()", "invalid position %s for vehicle %s in state %d (setting to %i,%i,%i)", v->get_pos().get_str(), v->get_name(), state, gr->get_pos().x, gr->get_pos().y, gr->get_pos().z ); v->set_pos( gr->get_pos() ); } else { dbg->fatal("convoi_t::rdwr()", "invalid position %s for vehicle %s in state %d", v->get_pos().get_str(), v->get_name(), state); } state = INITIAL; } // add to blockstrecke if(v->get_waytype()==track_wt || v->get_waytype()==monorail_wt || v->get_waytype()==maglev_wt || v->get_waytype()==narrowgauge_wt) { schiene_t* sch = (schiene_t*)gr->get_weg(v->get_waytype()); if(sch) { sch->reserve(self,ribi_t::none); } // add to crossing if(gr->ist_uebergang()) { gr->find()->add_to_crossing(v); } } if( gr->obj_count()>253 ) { dbg->warning( "convoi_t::rdwr()", "cannot put vehicle on ground at (%s)", gr->get_pos().get_str() ); } gr->obj_add(v); v->clear_flag(obj_t::not_on_map); } else { v->set_flag(obj_t::not_on_map); } // add to convoi fahr[i] = v; } sum_gesamtweight = sum_weight; } bool has_schedule = (schedule != NULL); file->rdwr_bool(has_schedule); if(has_schedule) { //DBG_MESSAGE("convoi_t::rdwr()","convoi has a schedule, state %s!",state_names[state]); const vehicle_t* v = fahr[0]; if(file->is_loading() && v) { schedule = v->generate_new_schedule(); } // hack to load corrupted games -> there is a schedule // but no vehicle so we can't determine the exact type of // schedule needed. This hack is safe because convois // without vehicles get deleted right after loading. // Since generic schedules are not allowed, we use a train_schedule_t if(schedule == 0) { schedule = new train_schedule_t(); } // now read the schedule, we have one for sure here schedule->rdwr( file ); } if(file->is_loading()) { next_wolke = 0; calc_loading(); } // calculate new minimum top speed min_top_speed = calc_min_top_speed(fahr, vehicle_count); // since sp_ist became obsolete, sp_soll is used modulo 65536 sp_soll &= 65535; if(file->is_version_less(88, 4)) { // load statistics int j; for (j = 0; j<3; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (j = 2; j<5; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][CONVOI_DISTANCE] = 0; financial_history[k][CONVOI_MAXSPEED] = 0; financial_history[k][CONVOI_WAYTOLL] = 0; } } else if( file->is_version_less(102, 3) ){ // load statistics for (int j = 0; j<5; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][CONVOI_DISTANCE] = 0; financial_history[k][CONVOI_MAXSPEED] = 0; financial_history[k][CONVOI_WAYTOLL] = 0; } } else if( file->is_version_less(111, 1) ){ // load statistics for (int j = 0; j<6; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][CONVOI_MAXSPEED] = 0; financial_history[k][CONVOI_WAYTOLL] = 0; } } else if( file->is_version_less(112, 8) ){ // load statistics for (int j = 0; j<7; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][CONVOI_WAYTOLL] = 0; } } else { // load statistics for (int j = 0; jrdwr_longlong(financial_history[k][j]); } } } // the convoi odometer if( file->is_version_atleast(102, 3) ){ file->rdwr_longlong( total_distance_traveled); } // since it was saved as an signed int // we recalc it anyhow if(file->is_loading()) { jahresgewinn = 0; for(int i=welt->get_last_month()%12; i>=0; i-- ) { jahresgewinn += financial_history[i][CONVOI_PROFIT]; } } // save/restore pending line updates if(file->is_version_atleast(84, 9) && file->is_version_less(99, 13)) { file->rdwr_long(dummy); // ignore } if(file->is_loading()) { line_update_pending = linehandle_t(); } if(file->is_version_atleast(84, 10)) { home_depot.rdwr(file); } // Old versions recorded last_stop_pos in convoi, not in vehicle koord3d last_stop_pos_convoi = koord3d(0,0,0); if (vehicle_count !=0) { last_stop_pos_convoi = fahr[0]->last_stop_pos; } if(file->is_version_atleast(87, 1)) { last_stop_pos_convoi.rdwr(file); } else { last_stop_pos_convoi = !route.empty() ? route.front() : vehicle_count != 0 ? fahr[0]->get_pos() : koord3d(0, 0, 0); } // for leaving the depot routine if(file->is_version_less(99, 14)) { steps_driven = -1; } else { file->rdwr_short(steps_driven); } // waiting time left ... if(file->is_version_atleast(99, 17)) { if(file->is_saving()) { if( has_schedule && schedule->get_current_entry().waiting_time > 0 ) { uint32 diff_ticks = arrived_time + schedule->get_current_entry().get_waiting_ticks() - welt->get_ticks(); file->rdwr_long(diff_ticks); } else { uint32 diff_ticks = 0xFFFFFFFFu; // write old WAIT_INFINITE value for backwards compatibility file->rdwr_long(diff_ticks); } } else { uint32 diff_ticks = 0; file->rdwr_long(diff_ticks); arrived_time = has_schedule ? welt->get_ticks() - schedule->get_current_entry().get_waiting_ticks() + diff_ticks : 0; } } // since 99015, the last stop will be maintained by the vehicles themselves if(file->is_version_less(99, 15)) { for(unsigned i=0; ilast_stop_pos = last_stop_pos_convoi; } } // overtaking status if(file->is_version_less(100, 1)) { set_tiles_overtaking( 0 ); } else { file->rdwr_byte(tiles_overtaking); set_tiles_overtaking( tiles_overtaking ); } // no_load, withdraw if(file->is_version_less(102, 1)) { no_load = false; withdraw = false; } else { bool value = no_load; file->rdwr_bool(value); no_load = value; value = withdraw; file->rdwr_bool(value); withdraw = value; } if(file->is_version_atleast(111, 1)) { file->rdwr_long( distance_since_last_stop ); file->rdwr_long( sum_speed_limit ); } if( file->is_version_atleast(111, 2) ) { file->rdwr_long( maxspeed_average_count ); } if( file->is_version_atleast(111, 3) ) { file->rdwr_short( next_stop_index ); file->rdwr_short( next_reservation_index ); } if( file->is_loading() ) { reserve_route(); recalc_catg_index(); unloading_state = false; } } void convoi_t::open_info_window() { if( in_depot() ) { // if ownership matches, we can try to open the depot dialog if( get_owner()==welt->get_active_player() ) { grund_t *const ground = welt->lookup( get_home_depot() ); if( ground ) { depot_t *const depot = ground->get_depot(); if( depot ) { depot->show_info(); // try to activate this particular convoy in the depot depot_frame_t *const frame = dynamic_cast( win_get_magic( (ptrdiff_t)depot ) ); if( frame ) { frame->activate_convoi(self); } } } } } else { if( env_t::verbose_debug >= log_t::LEVEL_ERROR ) { dump(); } create_win( new convoi_info_t(self), w_info, magic_convoi_info+self.get_id() ); } } void convoi_t::info(cbuffer_t & buf) const { const vehicle_t* v = fahr[0]; if (v != NULL) { char tmp[128]; buf.printf("\n %d/%dkm/h (%1.2f$/km)\n", speed_to_kmh(min_top_speed), v->get_desc()->get_topspeed(), get_running_cost() / 100.0); buf.printf(" %s: %ikW\n", translator::translate("Leistung"), sum_power); buf.printf(" %s: %ld (%ld) t\n", translator::translate("Gewicht"), (long)sum_weight, (long)(sum_gesamtweight - sum_weight)); buf.printf(" %s: ", translator::translate("Gewinn")); money_to_string(tmp, (double)jahresgewinn); buf.append(tmp); buf.append("\n"); } } // sort order of convoi void convoi_t::set_sortby(uint8 sort_order) { freight_info_order = sort_order; freight_info_resort = true; } // caches the last info; resorts only when needed void convoi_t::get_freight_info(cbuffer_t & buf) { if(freight_info_resort) { freight_info_resort = false; // rebuilt the list with goods ... vector_tpl total_fracht; size_t const n = goods_manager_t::get_count(); ALLOCA(uint32, max_loaded_waren, n); MEMZERON(max_loaded_waren, n); for( uint32 i = 0; i != vehicle_count; ++i ) { const vehicle_t* v = fahr[i]; // first add to capacity indicator const goods_desc_t* ware_desc = v->get_desc()->get_freight_type(); const uint16 menge = v->get_desc()->get_capacity(); if(menge>0 && ware_desc!=goods_manager_t::none) { max_loaded_waren[ware_desc->get_index()] += menge; } // then add the actual load for(ware_t ware : v->get_cargo()) { for(ware_t & tmp : total_fracht) { // could this be joined with existing freight? // for pax: join according next stop // for all others we *must* use target coordinates if( ware.same_destination(tmp) ) { tmp.amount += ware.amount; ware.amount = 0; break; } } // if != 0 we could not join it to existing => load it if(ware.amount != 0) { total_fracht.append(ware); } } INT_CHECK("simconvoi 2643"); } buf.clear(); // apend info on total capacity slist_tpl capacity; for (uint16 i = 0; i != n; ++i) { if(max_loaded_waren[i]>0 && i!=goods_manager_t::INDEX_NONE) { ware_t ware(goods_manager_t::get_info(i)); ware.amount = max_loaded_waren[i]; // append to category? slist_tpl::iterator j = capacity.begin(); slist_tpl::iterator end = capacity.end(); while (j != end && j->get_desc()->get_catg_index() < ware.get_desc()->get_catg_index()) ++j; if (j != end && j->get_desc()->get_catg_index() == ware.get_desc()->get_catg_index()) { j->amount += max_loaded_waren[i]; } else { // not yet there capacity.insert(j, ware); } } } // show new info freight_list_sorter_t::sort_freight(total_fracht, buf, (freight_list_sorter_t::sort_mode_t)freight_info_order, &capacity, "loaded"); } } void convoi_t::open_schedule_window( bool show ) { DBG_MESSAGE("convoi_t::open_schedule_window()","Id = %hu, State = %d, Lock = %d", self.get_id(), (int)state, wait_lock); // manipulation of schedule not allowed while: // - just starting // - a line update is pending if( (state==EDIT_SCHEDULE || line_update_pending.is_bound()) && get_owner()==welt->get_active_player() ) { if (show) { create_win( new news_img("Not allowed!\nThe convoi's schedule can\nnot be changed currently.\nTry again later!"), w_time_delete, magic_none ); } return; } if(state==DRIVING) { // book the current value of goods calc_gewinn(); } akt_speed = 0; // stop the train ... if(state!=INITIAL) { state = EDIT_SCHEDULE; } wait_lock = 25000; alte_richtung = fahr[0]->get_direction(); ptrdiff_t magic = (ptrdiff_t)(magic_convoi_info + self.get_id()); if( show ) { // Open schedule dialog if( convoi_info_t *info = dynamic_cast(win_get_magic( magic )) ) { info->change_schedule(); top_win(info); } else { create_schedule(); create_win( new convoi_info_t(self,true), w_info, magic ); } // TODO: what happens if no client opens the window?? } schedule->start_editing(); } /** * Check validity of convoi with respect to vehicle constraints */ bool convoi_t::pruefe_alle() { bool ok = vehicle_count == 0 || fahr[0]->get_desc()->can_follow(NULL); unsigned i; const vehicle_t* pred = fahr[0]; for(i = 1; ok && i < vehicle_count; i++) { const vehicle_t* v = fahr[i]; ok = pred->get_desc()->can_lead(v->get_desc()) && v->get_desc()->can_follow(pred->get_desc()); pred = v; } if(ok) { ok = pred->get_desc()->can_lead(NULL); } return ok; } /** * Kontrolliert Be- und Entladen * * minimum_loading is now stored in the object (not returned) */ void convoi_t::laden() { if( state == EDIT_SCHEDULE ) { return; } // just wait a little longer if this is a non-bound halt wait_lock = (WTT_LOADING*2)+(self.get_id())%1024; // find station (ours or public) halthandle_t halt = haltestelle_t::get_halt(schedule->get_current_entry().pos,owner); if( halt.is_bound() ) { // queue for (un)loading, does (un)loading once per step halt->request_loading( self ); } } /** * calculate income for last hop */ void convoi_t::calc_gewinn() { sint64 gewinn = 0; for(unsigned i=0; icalc_revenue(v->last_stop_pos, v->get_pos() ); // get_schedule is needed as v->get_waytype() returns track_wt for trams (instead of tram_wt owner->book_revenue(tmp, fahr[0]->get_pos().get_2d(), get_schedule()->get_waytype(), v->get_cargo_type()->get_index() ); v->last_stop_pos = v->get_pos(); } // update statistics of average speed if( distance_since_last_stop ) { financial_history[0][CONVOI_MAXSPEED] *= maxspeed_average_count; financial_history[0][CONVOI_MAXSPEED] += get_speedbonus_kmh(); maxspeed_average_count ++; financial_history[0][CONVOI_MAXSPEED] /= maxspeed_average_count; } distance_since_last_stop = 0; sum_speed_limit = 0; if(gewinn) { jahresgewinn += gewinn; book(gewinn, CONVOI_PROFIT); book(gewinn, CONVOI_REVENUE); } } uint32 convoi_t::get_departure_ticks(uint32 ticks_at_arrival) const { // we need to make it this complicated, otherwise times versus the end of a month could be missed uint32 arrived_month_tick = ticks_at_arrival & ~(welt->ticks_per_world_month - 1); uint32 arrived_ticks = ticks_at_arrival - arrived_month_tick; uint32 delta = schedule->get_current_entry().get_absolute_departures(); uint32 departure_ticks = schedule->get_current_entry().get_waiting_ticks(); // there could be more than one departure per month => find the next one for( uint i = 0; iticks_per_world_month/delta)); if( next_depature_slot > arrived_ticks ) { return arrived_month_tick+next_depature_slot; } } // nothing there => depart slot is first one in next month return arrived_month_tick+welt->ticks_per_world_month+departure_ticks; } /** * convoi an haltestelle anhalten * * minimum_loading is now stored in the object (not returned) */ void convoi_t::hat_gehalten(halthandle_t halt) { // now find out station length uint16 vehicles_loading = 0; if (fahr[0]->get_desc()->get_waytype() == water_wt) { // harbour and river stop load any size vehicles_loading = vehicle_count; } else if (vehicle_count == 1 && CARUNITS_PER_TILE >= fahr[0]->get_desc()->get_length()) { vehicles_loading = 1; // one vehicle, which fits into one tile } else { // difference between actual station length and vehicle lenghts sint16 station_length = -fahr[vehicles_loading]->get_desc()->get_length(); // iterate through tiles in straight line and look for station koord zv = koord(ribi_t::backward(fahr[0]->get_direction())); koord3d pos = fahr[0]->get_pos(); grund_t* gr = welt->lookup(pos); // start on bridge? pos.z += gr->get_weg_yoff() / TILE_HEIGHT_STEP; do { // advance one station tile station_length += CARUNITS_PER_TILE; while (station_length >= 0) { vehicles_loading++; if (vehicles_loading < vehicle_count) { station_length -= fahr[vehicles_loading]->get_desc()->get_length(); } else { // all vehicles fit into station goto station_tile_search_ready; } } // search for next station tile pos += zv; gr = welt->lookup(pos); if (gr == NULL) { gr = welt->lookup(pos - koord3d(0, 0, 1)); if (gr == NULL) { gr = welt->lookup(pos - koord3d(0, 0, 2)); } if (gr && (pos.z != gr->get_hoehe() + gr->get_weg_yoff() / TILE_HEIGHT_STEP)) { // not end/start of bridge break; } } } while (gr && gr->get_halt() == halt); // finished station_tile_search_ready:; } // next stop in schedule will be a depot bool next_depot = false; // check if there is a convoi infront of us bool all_served_this_stop = true; // prepare a list of all destination halts in the schedule vector_tpl destination_halts(schedule->get_count()); if (!no_load) { const uint8 count = schedule->get_count(); bool first_entry = true; for (uint8 i = 1; i < count; i++) { const uint8 wrap_i = (i + schedule->get_current_stop()) % count; const halthandle_t plan_halt = haltestelle_t::get_halt(schedule->entries[wrap_i].pos, owner); if (plan_halt == halt) { // we will come later here again ... // the following halt is the same => there will never be a halt to serve all_served_this_stop &= first_entry; break; } else if (!plan_halt.is_bound()) { if (grund_t* gr = welt->lookup(schedule->entries[wrap_i].pos)) { if (gr->get_depot()) { // on our way to depot => there will never be a halt to serve all_served_this_stop &= !first_entry; next_depot = first_entry; // otherwise do not load for stops after a depot break; } } continue; } for (uint8 const idx : goods_catg_index) { if (!halt->get_halt_served_this_step()[idx].is_contained(plan_halt)) { // if overcroding mode, do add overcrowded steps if (!welt->get_settings().is_avoid_overcrowding() || !plan_halt->is_overcrowded(idx)) { // not somebody loaded before us in the queue destination_halts.append(plan_halt); all_served_this_stop = false; break; } } first_entry = false; } } } // only load vehicles in station // don't load when vehicle is being withdrawn bool changed_loading_level = false; unloading_state = true; uint32 time = 0; // min time for loading/unloading uint32 current_tick = welt->get_ticks(); if (last_load_tick == 0) { // first stop here, so no time passed yet last_load_tick = current_tick; } const uint32 loading_ms = current_tick - last_load_tick; last_load_tick = current_tick; // cargo type of previous vehicle that could not be filled const goods_desc_t* cargo_type_prev = NULL; bool wants_more = false; for (unsigned i = 0; i < vehicles_loading; i++) { vehicle_t* v = fahr[i]; // has no freight ... if (fahr[i]->get_cargo_max() == 0) { continue; } uint32 min_loading_step_time = v->get_desc()->get_loading_time() / v->get_cargo_max() + 1; time = max(time, min_loading_step_time); uint16 max_amount = next_depot ? 32767 : (v->get_cargo_max() * loading_ms) / ((uint32)v->get_desc()->get_loading_time() + 1) + 1; uint16 amount = v->unload_cargo(halt, next_depot, max_amount); if (amount > 0) { // could unload something, so we are open for new stuff cargo_type_prev = NULL; } if (!all_served_this_stop && max_amount > amount && v->get_total_cargo() < v->get_cargo_max()) { // load if: not unloaded something first or not filled and not forbidden (no_load or next is depot) or that stop has been served already if (cargo_type_prev == NULL || !cargo_type_prev->is_interchangeable(v->get_cargo_type())) { // load amount += v->load_cargo(halt, destination_halts, max_amount - amount); unloading_state &= amount == 0; } if (v->get_total_cargo() < v->get_cargo_max() && amount < max_amount) { // not full, but running out of goods cargo_type_prev = v->get_cargo_type(); } } if (amount) { v->mark_image_dirty(v->get_image(), 0); v->calc_image(); changed_loading_level = true; } wants_more |= (amount == max_amount) && (v->get_total_cargo() < v->get_cargo_max()); } freight_info_resort |= changed_loading_level; if (changed_loading_level) { halt->recalc_status(); } // any unloading/loading went on? if (changed_loading_level) { calc_loading(); } else { // nothing to unload or load: waiting for cargo unloading_state = false; } loading_limit = schedule->get_current_entry().minimum_loading; if(!no_load || wants_more) { // only check for further waiting, in not no_load is set assert(time > 0 || !wants_more); // time == 0 => wants_more == false, can only happen if all vehicles in station have no transport capacity (i.e., locomotives) wait_lock = min(time, 0xFFFF); // check if departure time is reached if (schedule->get_current_entry().get_absolute_departures()) { sint32 ticks_until_departure = get_departure_ticks() - welt->get_ticks(); if (ticks_until_departure <= 0) { // depart if nothing to load (wants_more==false) if (wants_more) { return; } } else { // else continue loading (even if full) until departure time reached if (wait_lock == 0) { // no loading time imposed, make sure we do not wait too long if the departure is imminent wait_lock = min(WTT_LOADING, ticks_until_departure); } return; } } else { // check for maximum load if (wants_more) { return; } if(loading_level < loading_limit) { // not reached maximum load: do we have to wait more? if (schedule->get_current_entry().waiting_time > 0) { if ((welt->get_ticks() - arrived_time) < schedule->get_current_entry().get_waiting_ticks()) { // continue waiting return; } } else { return; } } } } // loading is finished => maybe drive on if (withdraw && (loading_level == 0 || goods_catg_index.empty())) { // destroy when empty self_destruct(); return; } calc_speedbonus_kmh(); // add available capacity after loading(!) to statistics for (unsigned i = 0; iget_cargo_max()-get_vehicle(i)->get_total_cargo(), CONVOI_CAPACITY); } // Advance schedule schedule->advance(); state = ROUTING_1; loading_limit = 0; INT_CHECK("convoi_t::hat_gehalten"); } sint64 convoi_t::calc_restwert() const { sint64 result = 0; for(uint i=0; icalc_sale_value(); } return result; } /** * Calculate loading_level and loading_limit. This depends on current state (loading or not). */ void convoi_t::calc_loading() { int fracht_max = 0; int fracht_menge = 0; for(unsigned i=0; iget_cargo_max(); fracht_menge += v->get_total_cargo(); } loading_level = fracht_max > 0 ? (fracht_menge*100)/fracht_max : 100; loading_limit = 0; // will be set correctly from hat_gehalten() routine // since weight has changed recalc_data=true; } void convoi_t::calc_speedbonus_kmh() { // init with default const sint32 cnv_min_top_kmh = speed_to_kmh( min_top_speed ); speedbonus_kmh = cnv_min_top_kmh; // flying aircraft have 0 friction --> speed not limited by power, so just use top_speed if( front()!=NULL && front()->get_waytype() != air_wt ) { sint32 total_max_weight = 0; sint32 total_weight = 0; for( unsigned i=0; iget_desc(); total_max_weight += desc->get_weight(); total_weight += fahr[i]->get_total_weight(); // convoi_t::sum_gesamweight may not be updated yet when this method is called... if( desc->get_freight_type() == goods_manager_t::none ) { ; // nothing } else if( desc->get_freight_type()->get_catg() == 0 ) { // use full weight for passengers, mail, and special goods total_max_weight += desc->get_freight_type()->get_weight_per_unit() * desc->get_capacity(); } else { // use actual weight for regular goods total_max_weight += fahr[i]->get_cargo_weight(); } } // very old vehicles have zero weight ... if( total_weight>0 ) { speedbonus_kmh = speed_to_kmh( calc_max_speed(sum_gear_and_power, total_max_weight, min_top_speed) ); // convoi overtakers use current actual weight for achievable speed if( front()->get_overtaker() ) { max_power_speed = calc_max_speed(sum_gear_and_power, total_weight, min_top_speed); } } } } // return the current bonus speed sint32 convoi_t::get_speedbonus_kmh() const { if( distance_since_last_stop > 0 && front()!=NULL && front()->get_waytype() != air_wt ) { return min( speedbonus_kmh, (sint32)(sum_speed_limit / distance_since_last_stop) ); } return speedbonus_kmh; } // return the current bonus speed uint32 convoi_t::get_average_kmh() const { if( distance_since_last_stop > 0 ) { return sum_speed_limit / distance_since_last_stop; } return speedbonus_kmh; } /** * Schedule convois for self destruction. Will be executed * upon next sync step */ void convoi_t::self_destruct() { line_update_pending = linehandle_t(); // does not bother to add it to a new line anyway ... // convois in depot are not contained in the map array! if(state==INITIAL) { destroy(); } else { state = SELF_DESTRUCT; wait_lock = 0; } } /** * Helper method to remove convois from the map that cannot * removed normally (i.e. by sending to a depot) anymore. * This is a workaround for bugs in the game. */ void convoi_t::destroy() { // can be only done here, with a valid convoihandle ... if(fahr[0]) { fahr[0]->set_convoi(NULL); } if( state == INITIAL ) { // in depot => not on map for( uint8 i = vehicle_count; i-- != 0; ) { fahr[i]->set_flag( obj_t::not_on_map ); } } state = SELF_DESTRUCT; if(schedule!=NULL && !schedule->is_editing_finished()) { destroy_win((ptrdiff_t)schedule); } if( line.is_bound() ) { // needs to be done here to remove correctly ware catg from lines unset_line(); delete schedule; schedule = NULL; } // pay the current value owner->book_new_vehicle( calc_restwert(), get_pos().get_2d(), fahr[0] ? fahr[0]->get_desc()->get_waytype() : ignore_wt ); for( uint8 i = vehicle_count; i-- != 0; ) { if( !fahr[i]->get_flag( obj_t::not_on_map ) ) { // remove from rails/roads/crossings grund_t *gr = welt->lookup(fahr[i]->get_pos()); fahr[i]->set_last( true ); fahr[i]->leave_tile(); if( gr && gr->ist_uebergang() ) { gr->find()->release_crossing(fahr[i]); } fahr[i]->set_flag( obj_t::not_on_map ); } // no need to substract maintenance, since it is booked as running costs fahr[i]->discard_cargo(); fahr[i]->cleanup(owner); delete fahr[i]; } vehicle_count = 0; delete this; } /** * Debug info nach stderr */ void convoi_t::dump() const { dbg->debug("convoi::dump()", "\nvehicle_count = %d\n" "wait_lock = %d\n" "owner_n = %d\n" "akt_speed = %d\n" "akt_speed_soll = %d\n" "sp_soll = %d\n" "state = %d\n" "statename = %s\n" "alte_richtung = %d\n" "jahresgewinn = %ld\n" // %lld crashes mingw now, cast gewinn to long ... "name = '%s'\n" "line_id = '%d'\n" "schedule = '%p'", (int)vehicle_count, (int)wait_lock, (int)welt->sp2num(owner), (int)akt_speed, (int)akt_speed_soll, (int)sp_soll, (int)state, (const char *)(state_names[state]), (int)alte_richtung, (long)(jahresgewinn/100), (const char *)name_and_id, line.is_bound() ? line.get_id() : 0, (const void *)schedule ); } void convoi_t::book(sint64 amount, int cost_type) { assert( cost_typebook( amount, simline_t::convoi_to_line_catgory(cost_type) ); } } void convoi_t::init_financial_history() { for (int j = 0; jget_desc()->get_price(); } return purchase_cost; } /** * set line * since convoys must operate on a copy of the route's schedule, we apply a fresh copy */ void convoi_t::set_line(linehandle_t org_line) { // to remove a convoi from a line, call unset_line() if(!org_line.is_bound()) { unset_line(); } if( line.is_bound() ) { unset_line(); } else { // originally a lineless convoy -> unregister itself from stops as it now belongs to a line unregister_stops(); // must trigger refresh if old schedule was not empty if (schedule && !schedule->empty()) { welt->set_schedule_counter(); } } line_update_pending = org_line; check_pending_updates(); } /** * unset line * removes convoy from route without destroying its schedule * => no need to recalculate connections! */ void convoi_t::unset_line() { if( line.is_bound() ) { DBG_DEBUG("convoi_t::unset_line()", "removing old destinations from line=%d, schedule=%p",line.get_id(),schedule); line->remove_convoy(self); line = linehandle_t(); line_update_pending = linehandle_t(); } } void convoi_t::set_update_line(linehandle_t l) { line_update_pending = l; if (state == EDIT_SCHEDULE) { // save, since it is in a step only mode check_pending_updates(); } } // matches two halts; if the pos is not identical, maybe the halt still is the same bool convoi_t::matches_halt( const koord3d pos1, const koord3d pos2 ) { halthandle_t halt1 = haltestelle_t::get_halt(pos1, owner ); return pos1==pos2 || (halt1.is_bound() && halt1==haltestelle_t::get_halt( pos2, owner )); } // updates a line schedule and tries to find the best next station to go void convoi_t::check_pending_updates() { if( line_update_pending.is_bound() ) { // create dummy schedule if( schedule==NULL ) { schedule = create_schedule(); } schedule_t* new_schedule = line_update_pending->get_schedule(); int current_stop = schedule->get_current_stop(); // save current position of schedule bool is_same = false; bool is_depot = false; koord3d current = koord3d::invalid, depot = koord3d::invalid; if (schedule->empty() || new_schedule->empty()) { // was no entry or is no entry => goto 1st stop current_stop = 0; } else { // something to check for ... current = schedule->get_current_entry().pos; if( current_stopget_count() && current==new_schedule->entries[current_stop].pos ) { // next pos is the same => keep the convoi state is_same = true; } else { // check depot first (must also keept this state) is_depot = (welt->lookup(current) && welt->lookup(current)->get_depot() != NULL); if(is_depot) { // depot => current_stop+1 (depot will be restore later before this) depot = current; schedule->remove(); current = schedule->get_current_entry().pos; } /* there could be only one entry that matches best: * we try first same sequence as in old schedule; * if not found, we try for same nextnext station * (To detect also places, where only the platform * changed, we also compare the halthandle) */ const koord3d next = schedule->entries[(current_stop+1)%schedule->get_count()].pos; const koord3d nextnext = schedule->entries[(current_stop+2)%schedule->get_count()].pos; const koord3d nextnextnext = schedule->entries[(current_stop+3)%schedule->get_count()].pos; int how_good_matching = 0; const uint8 new_count = new_schedule->get_count(); for( uint8 i=0; ientries[i].pos)*3 + matches_halt(next,new_schedule->entries[(i+1)%new_count].pos)*4 + matches_halt(nextnext,new_schedule->entries[(i+2)%new_count].pos)*2 + matches_halt(nextnextnext,new_schedule->entries[(i+3)%new_count].pos); if( quality>how_good_matching ) { // better match than previous: but depending of distance, the next number will be different if( matches_halt(current,new_schedule->entries[i].pos) ) { current_stop = i; } else if( matches_halt(next,new_schedule->entries[(i+1)%new_count].pos) ) { current_stop = i+1; } else if( matches_halt(nextnext,new_schedule->entries[(i+2)%new_count].pos) ) { current_stop = i+2; } else if( matches_halt(nextnextnext,new_schedule->entries[(i+3)%new_count].pos) ) { current_stop = i+3; } current_stop %= new_count; how_good_matching = quality; } } if(how_good_matching==0) { // nothing matches => take the one from the line current_stop = new_schedule->get_current_stop(); } // if we go to same, then we do not need route recalculation ... is_same = matches_halt(current,new_schedule->entries[current_stop].pos); } } // we may need to update the line and connection tables if( !line.is_bound() ) { line_update_pending->add_convoy(self); } line = line_update_pending; line_update_pending = linehandle_t(); // destroy old schedule and all related windows if(!schedule->is_editing_finished()) { schedule->copy_from( new_schedule ); schedule->set_current_stop(current_stop); // set new schedule current position to best match schedule->start_editing(); } else { schedule->copy_from( new_schedule ); schedule->set_current_stop(current_stop); // set new schedule current position to one before best match } if(is_depot) { // next was depot. restore it schedule->insert(welt->lookup(depot)); schedule->set_current_stop( (schedule->get_current_stop()+schedule->get_count()-1)%schedule->get_count() ); } if (state == EDIT_SCHEDULE) { if (convoi_info_t* info = dynamic_cast(win_get_magic(magic_convoi_info + self.get_id()))) { info->update_schedule(); } } if (state != INITIAL) { // remove wrong freight check_freight(); if(is_same || is_depot) { /* same destination * We are already there => keep current state */ } else { // need re-routing state = EDIT_SCHEDULE; } // make this change immediately if( state!=LOADING ) { wait_lock = 0; } } } } /** * Register the convoy with the stops in the schedule */ void convoi_t::register_stops() { if( schedule ) { for(schedule_entry_t const& i : schedule->entries) { halthandle_t const halt = haltestelle_t::get_halt(i.pos, get_owner()); if( halt.is_bound() ) { halt->add_convoy(self); } } } } /** * Unregister the convoy from the stops in the schedule */ void convoi_t::unregister_stops() { if( schedule ) { for(schedule_entry_t const& i : schedule->entries) { halthandle_t const halt = haltestelle_t::get_halt(i.pos, get_owner()); if( halt.is_bound() ) { halt->remove_convoy(self); } } } } // set next stop before breaking will occur (or route search etc.) // currently only used for tracks void convoi_t::set_next_stop_index(route_t::index_t n) { // stop at station or signals, not at waypoints if( n==route_t::INVALID_INDEX ) { // find out if stop or waypoint, waypoint: do not brake at waypoints grund_t const* const gr = welt->lookup(route.back()); if( gr && gr->is_halt() ) { n = route.get_count()-1-1; // extra -1 to brake 1 tile earlier when entering station } } next_stop_index = n+1; } /* including this route_index, the route was reserved the last time * currently only used for tracks */ void convoi_t::set_next_reservation_index(route_t::index_t n) { // stop at station or signals, not at waypoints if( n==route_t::INVALID_INDEX ) { n = route.get_count()-1; } next_reservation_index = n; } /* * the current state saved as color * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete) */ PIXVAL convoi_t::get_status_color() const { if(state==INITIAL) { // in depot/under assembly return SYSCOL_TEXT_HIGHLIGHT; } else if (state == WAITING_FOR_CLEARANCE_ONE_MONTH || state == CAN_START_ONE_MONTH || get_state() == NO_ROUTE) { // stuck or no route return color_idx_to_rgb(COL_ORANGE); } else if(financial_history[0][CONVOI_PROFIT]+financial_history[1][CONVOI_PROFIT]<0) { // ok, not performing best return MONEY_MINUS; } else if((financial_history[0][CONVOI_OPERATIONS]|financial_history[1][CONVOI_OPERATIONS])==0) { // nothing moved return SYSCOL_TEXT_UNUSED; } else if(has_obsolete) { return SYSCOL_OBSOLETE; } // normal state return SYSCOL_TEXT; } // returns station tiles needed for this convoi uint16 convoi_t::get_tile_length() const { uint16 carunits=0; for(uint8 i=0; iget_desc()->get_length(); } // the last vehicle counts differently in stations and for reserving track // (1) add 8 = 127/256 tile to account for the driving in stations in north/west direction // see at the end of vehicle_t::hop() // carunits += max(CARUNITS_PER_TILE/2, fahr[vehicle_count-1]->get_desc()->get_length()); // (2) for length of convoi for loading in stations the length of the last vehicle matters // see convoi_t::hat_gehalten carunits += fahr[vehicle_count-1]->get_desc()->get_length(); uint16 tiles = (carunits + CARUNITS_PER_TILE - 1) / CARUNITS_PER_TILE; return tiles; } // if withdraw and empty, then self destruct void convoi_t::set_withdraw(bool new_withdraw) { withdraw = new_withdraw; if( withdraw && (loading_level==0 || goods_catg_index.empty())) { // test if convoi in depot and not driving grund_t *gr = welt->lookup( get_pos()); if( gr && gr->get_depot() && state == INITIAL ) { #if 1 // do not touch line bound convois in depots withdraw = false; no_load = false; #else // disassemble also line bound convois in depots gr->get_depot()->disassemble_convoi(self, true); #endif } else { self_destruct(); } } } /** * conditions for a city car to overtake another overtaker. * The city car is not overtaking/being overtaken. */ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) { if(fahr[0]->get_waytype()!=road_wt) { return false; } if (!other_overtaker->can_be_overtaken()) { return false; } if( other_speed == 0 ) { /* overtaking a loading convoi * => we can do a lazy check, since halts are always straight */ grund_t *gr = welt->lookup(get_pos()); if( gr==NULL ) { // should never happen, since there is a vehicle in front of us ... return false; } weg_t *str = gr->get_weg(road_wt); if( str==0 ) { // also this is not possible, since a car loads in front of is!?! return false; } route_t::index_t idx = fahr[0]->get_route_index(); const sint32 tiles = other_speed == 0 ? 2 : (steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) + get_tile_length() + 1; if( tiles > 0 && idx+(uint32)tiles >= route.get_count() ) { // needs more space than there return false; } for( sint32 i=0; ilookup( route.at( idx+i ) ); if( gr==NULL ) { return false; } weg_t *str = gr->get_weg(road_wt); if( str==0 ) { return false; } // not overtaking on railroad crossings or normal crossings ... if( str->is_crossing() ) { return false; } if( ribi_t::is_threeway(str->get_ribi()) ) { return false; } // Check for other vehicles on the next tile const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j)) ) { // check for other traffic on the road const overtaker_t *ov = v->get_overtaker(); if(ov) { if(this!=ov && other_overtaker!=ov) { return false; } } else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { return false; } } } } set_tiles_overtaking( tiles ); return true; } int diff_speed = akt_speed - other_speed; if( diff_speed < kmh_to_speed(5) ) { return false; } // Number of tiles overtaking will take int n_tiles = 0; // Distance it takes overtaking (unit: vehicle_steps) = my_speed * time_overtaking // time_overtaking = tiles_to_overtake/diff_speed // tiles_to_overtake = convoi_length + current pos within tile + (pos_other_convoi within tile + length of other convoi) - one tile sint32 distance = akt_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed; sint32 time_overtaking = 0; // Conditions for overtaking: // Flat tiles, with no stops, no crossings, no signs, no change of road speed limit // First phase: no traffic except me and my overtaken car in the dangerous zone route_t::index_t route_index = fahr[0]->get_route_index()+1; koord3d pos = fahr[0]->get_pos(); koord3d pos_prev = route_index > 2 ? route.at(route_index-2) : pos; koord3d pos_next; while( distance > 0 ) { if( route_index >= route.get_count() ) { return false; } pos_next = route.at(route_index++); grund_t *gr = welt->lookup(pos); // no ground, or slope => about if( gr==NULL || gr->get_weg_hang()!=slope_t::flat ) { return false; } weg_t *str = gr->get_weg(road_wt); if( str==NULL ) { return false; } // the only roadsign we must account for are choose points and traffic lights if( str->has_sign() ) { const roadsign_t *rs = gr->find(1); if(rs) { const roadsign_desc_t *rb = rs->get_desc(); if(rb->is_choose_sign() || rb->is_traffic_light() ) { // because we may need to stop here ... return false; } } } // not overtaking on railroad crossings or on normal crossings ... if( str->is_crossing() || ribi_t::is_threeway(str->get_ribi()) ) { return false; } // street gets too slow (TODO: should be able to be correctly accounted for) if( akt_speed > kmh_to_speed(str->get_max_speed()) ) { return false; } int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); distance -= d; time_overtaking += d; // Check for other vehicles const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j))) { // check for other traffic on the road const overtaker_t *ov = v->get_overtaker(); if(ov) { if(this!=ov && other_overtaker!=ov) { return false; } } else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { // sheeps etc. return false; } } } n_tiles++; pos_prev = pos; pos = pos_next; } // Second phase: only facing traffic is forbidden // the original routine was checking using the maximum road speed. // However, we can tolerate slower vehicles if they are closer // Furthermore, if we reach the end of the route for a vehcile as fast as us, // we simply assume it to be ok too sint32 overtaking_distance = time_overtaking; distance = 0; // distance to needed traveled to crash int us from this point time_overtaking = (time_overtaking << 16)/akt_speed; while( time_overtaking > 0 ) { if( route_index >= route.get_count() ) { return distance>=time_overtaking; // we assume ok, if there is enough distance when we would face ourselves } pos_next = route.at(route_index++); grund_t *gr= welt->lookup(pos); if( gr==NULL ) { // will cause a route search, but is ok break; } weg_t *str = gr->get_weg(road_wt); if( str==NULL ) { break; } // cannot check for oncoming traffic over crossings if( ribi_t::is_threeway(str->get_ribi()) ) { return false; } if( ribi_t::is_straight(str->get_ribi()) ) { time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed()); distance -= VEHICLE_STEPS_PER_TILE; } else { time_overtaking -= (vehicle_base_t::get_diagonal_vehicle_steps_per_tile()<<16) / kmh_to_speed(str->get_max_speed()); distance -= vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); } // Check for other vehicles in facing direction ribi_t::ribi their_direction = ribi_t::backward( fahr[0]->calc_direction(pos_prev, pos_next) ); const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j)); if( v && v->get_direction() == their_direction && v->get_overtaker() ) { // tolerated distance us>them: total_distance*akt_speed > current_distance*other_speed if( road_vehicle_t const* const car = obj_cast(v) ) { convoi_t* const ocnv = car->get_convoi(); if( ocnv && ocnv->get_max_power_speed()*distance > akt_speed*overtaking_distance ) { return false; } } else if( private_car_t* const caut = obj_cast(v) ) { if( caut->get_desc()->get_topspeed()*distance > akt_speed*overtaking_distance ) { return false; } } } } pos_prev = pos; pos = pos_next; } set_tiles_overtaking( 1+n_tiles ); other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed ); return true; } sint64 convoi_t::get_stat_converted(int month, int cost_type) const { sint64 value = financial_history[month][cost_type]; switch(cost_type) { case CONVOI_REVENUE: case CONVOI_OPERATIONS: case CONVOI_PROFIT: case CONVOI_WAYTOLL: value = convert_money(value); break; default: ; } return value; } const char* convoi_t::send_to_depot(bool local) { // iterate over all depots and try to find shortest route route_t *shortest_route = new route_t(); route_t *route = new route_t(); koord3d home = koord3d::invalid; vehicle_t *v = front(); for(depot_t* const depot : depot_t::get_depot_list()) { if (depot->get_waytype() != v->get_desc()->get_waytype() || depot->get_owner() != get_owner()) { continue; } koord3d pos = depot->get_pos(); if(!shortest_route->empty() && koord_distance(pos, get_pos()) >= shortest_route->get_count()-1) { // the current route is already shorter, no need to search further continue; } if (v->calc_route(get_pos(), pos, 50, route)) { // do not care about speed if( route->get_count() < shortest_route->get_count() || shortest_route->empty() ) { // just swap the pointers sim::swap(shortest_route, route); home = pos; } } } delete route; DBG_MESSAGE("shortest route has ", "%i hops", shortest_route->get_count()-1); if (local) { if (convoi_info_t *info = dynamic_cast(win_get_magic( magic_convoi_info+self.get_id()))) { info->route_search_finished(); } } // if route to a depot has been found, update the convoi's schedule const char *txt; if( !shortest_route->empty() ) { schedule_t *schedule = get_schedule()->copy(); schedule->insert(welt->lookup(home)); schedule->set_current_stop( (schedule->get_current_stop()+schedule->get_count()-1)%schedule->get_count() ); set_schedule(schedule); txt = "Convoi has been sent\nto the nearest depot\nof appropriate type.\n"; } else { txt = "Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually."; } delete shortest_route; return txt; } simutrans-124.3/src/simutrans/simconvoi.h000066400000000000000000000467071474050137200205640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMCONVOI_H #define SIMCONVOI_H #include "simtypes.h" #include "simunits.h" #include "simcolor.h" #include "linehandle.h" #include "dataobj/route.h" #include "vehicle/overtaker.h" #include "tpl/array_tpl.h" #include "tpl/minivec_tpl.h" #include "convoihandle.h" #include "halthandle.h" #define MAX_MONTHS 12 // Max history class weg_t; class depot_t; class karte_ptr_t; class player_t; class vehicle_t; class vehicle_desc_t; class schedule_t; class cbuffer_t; /** * Base class for all vehicle consists. Convoys can be referenced by handles, see halthandle_t. */ class convoi_t : public overtaker_t { public: enum { CONVOI_CAPACITY = 0, // the amount of ware that could be transported, theoretically CONVOI_TRANSPORTED_GOODS, // the amount of ware that has been transported CONVOI_REVENUE, // the income this CONVOI generated CONVOI_OPERATIONS, // the cost of operations this CONVOI generated CONVOI_PROFIT, // total profit of this convoi CONVOI_DISTANCE, // total distance traveled this month CONVOI_MAXSPEED, // average max. possible speed CONVOI_WAYTOLL, MAX_CONVOI_COST // Total number of cost items }; /** Constants */ enum { default_vehicle_length = 4 }; enum states : uint8 { INITIAL, EDIT_SCHEDULE, ROUTING_1, DUMMY4, DUMMY5, NO_ROUTE, DRIVING, LOADING, WAITING_FOR_CLEARANCE, WAITING_FOR_CLEARANCE_ONE_MONTH, CAN_START, CAN_START_ONE_MONTH, SELF_DESTRUCT, WAITING_FOR_CLEARANCE_TWO_MONTHS, CAN_START_TWO_MONTHS, LEAVING_DEPOT, ENTERING_DEPOT, MAX_STATES }; private: /// Current map static karte_ptr_t welt; /* The data is laid out such that the most important variables for sync_step and step are * concentrated at the beginning of the structure. * All computations are for 64bit builds. * * We start with a 16 bytes header from data of overtaker_t :( */ /** * The convoi is not processed every sync step for various actions * (like waiting before signals, loading etc.) Such action will only * continue after a waiting time larger than wait_lock milliseconds */ uint16 wait_lock; /// holds id of line with pending update, or -1 if no pending update linehandle_t line_update_pending; /** * The convoi is gradually loaded for each vehicle, i.e. there is a constant loading speed. * Hence the tick value */ uint32 last_load_tick; // 24 bytes uint16 unloading_state : 1; ///< if state == LOADING, this is true while unloading uint16 recalc_data_front : 1; ///< true, when front vehicle has to recalculate braking uint16 recalc_data : 1; ///< true, when convoy has to recalculate weights and speed limits uint16 recalc_speed_limit : 1; ///< true, when convoy has to recalculate speed limits uint16 previous_delta_v :12; ///< 12 bit! // Stores the previous delta_v value; otherwise these digits are lost during calculation and vehicle do not accelerate uint8 withdraw : 1; ///< the convoi is being withdrawn from service uint8 no_load : 1; ///< nothing will be loaded onto this convoi uint8 freight_info_resort : 1; ///< the convoi caches its freight info; it is only recalculation after loading or resorting uint8 has_obsolete : 1; ///< true, if at least one vehicle of a convoi is obsolete uint8 is_electric : 1; ///< true, if there is at least one engine that requires catenary // 3 bits free states state; /** * Overall performance with Gear. * Used in movement calculations. */ sint32 sum_gear_and_power; // 32 bytes /** * sum_weight: unloaded weight of all vehicles * sum_gesamtweight: total weight of all vehicles * Not stored, but calculated from individual weights * when loading/driving. */ sint64 sum_gesamtweight; sint64 sum_friction_weight; // 48 bytes sint32 akt_speed_soll; ///< target speed sint32 akt_speed; ///< current speed sint32 min_top_speed; ///< Lowest top speed of all vehicles. Doesn't get saved, but calculated from the vehicles data sint32 sp_soll; ///< steps to go // 64 bytes // needed for speed control/calculation sint32 brake_speed_soll; // brake target speed sint32 speed_limit; sint32 max_record_speed; // current convois fastest speed ever /// Number of steps the current convoi did already (only needed for leaving/entering depot) sint16 steps_driven; /** * this gives the index of the next signal or the end of the route * convois will slow down before it, if this is not a waypoint or the cannot pass * The slowdown is done by the vehicle routines */ route_t::index_t next_stop_index; // 80 bytes /// loading_level was minimum_loading before. Actual percentage loaded for loadable vehicles (station length!). /// needed as int, since used by the gui sint32 loading_level; /// At which loading level is the train allowed to start? 0 during driving. /// needed as int, since used by the gui sint32 loading_limit; // things for the world record koord3d record_pos; /// Number of vehicles in this convoi. uint8 vehicle_count; // 96 bytes /// The vehicles of this convoi array_tpl fahr; /** * Route of this convoi - a sequence of coordinates. Actually * the path of the first vehicle */ route_t route; // 128 bytes /// a list of all catg_index, which can be transported by this convoy. minivec_tpl goods_catg_index; /// assigned line linehandle_t line; /// Time when convoi arrived at the current stop /// Used to calculate when it should depart due to the 'month wait time' uint32 arrived_time; // 144 bytes /// All vehicle-schedule pointers point here schedule_t *schedule; /// Convoi owner player_t *owner; // 160 bytes koord3d schedule_target; /// the convoi caches its freight info; it is only recalculation after loading or resorting uint8 freight_info_order; /// this give the index until which the route has been reserved. /// It is used for restoring reservations after loading a game. route_t::index_t next_reservation_index; /// caches the running costs sint32 sum_running_costs; sint32 sum_fixed_costs; uint32 next_wolke; // time to next smoke /// Overall performance. /// Not used in movement code. uint32 sum_power; /// sum_weight: unloaded weight of all vehicles sint64 sum_weight; // 192 bytes /// accumulated profit over a year sint64 jahresgewinn; /* the odometer */ sint64 total_distance_traveled; uint32 distance_since_last_stop; // number of tiles entered since last stop uint32 sum_speed_limit; // sum of the speed limits encountered since the last stop sint32 speedbonus_kmh; // speed used for speedbonus calculation in km/h sint32 maxspeed_average_count; // just a simple count to average for statistics // 224 bytes /** * the koordinate of the home depot of this convoi * the last depot visited is considered being the home depot */ koord3d home_depot; ribi_t::ribi alte_richtung; /** * Name of the convoi. * @see set_name */ uint8 name_offset; char name_and_id[128]; /// struct holds new financial history for convoi sint64 financial_history[MAX_MONTHS][MAX_CONVOI_COST]; private: /** * Initialize all variables with default values. * Each constructor must call this method first! */ void init(player_t *player); /** * Calculate route from Start to Target Coordinate */ bool drive_to(); /** * Setup vehicles for moving in same direction than before * if the direction is the same as before */ bool can_go_alte_richtung(); /** * remove all track reservations (trains only) */ void unreserve_route(); // reserve route until next_reservation_index void reserve_route(); /** * Mark first and last vehicle. */ void set_erstes_letztes(); // returns the index of the vehicle at position length (16=1 tile) int get_vehicle_at_length(uint16); /** * calculate income for last hop * only used for entering depot or recalculating routes when a schedule window is opened */ void calc_gewinn(); /** * Recalculates loading level and limit. * While driving loading_limit will be set to 0. */ void calc_loading(); /* Calculates (and sets) akt_speed * needed for driving, entering and leaving a depot) */ void calc_acceleration(uint32 delta_t); /** * initialize the financial history */ void init_financial_history(); // matches two halts; if the pos is not identical, maybe the halt still is bool matches_halt( const koord3d pos1, const koord3d pos2 ); /** * Register the convoy with the stops in the schedule */ void register_stops(); /** * Unregister the convoy from the stops in the schedule */ void unregister_stops(); uint32 move_to(route_t::index_t start_index); public: uint32 get_arrival_ticks() const { return arrived_time; } uint32 get_departure_ticks(uint32) const; uint32 get_departure_ticks() const { return get_departure_ticks(arrived_time); } /** * Convoi haelt an Haltestelle und setzt quote fuer Fracht */ void hat_gehalten(halthandle_t halt); const route_t* get_route() const { return &route; } route_t* access_route() { return &route; } const koord3d get_schedule_target() const { return schedule_target; } void set_schedule_target( koord3d t ) { schedule_target = t; } /** * get line */ linehandle_t get_line() const {return line;} /* true, if electrification needed for this convoi */ bool needs_electrification() const { return is_electric; } /** * set line */ void set_line(linehandle_t ); /** * unset line -> remove cnv from line */ void unset_line(); void set_update_line(linehandle_t l); // updates a line schedule and tries to find the best next station to go void check_pending_updates(); // true if this is a waypoint bool is_waypoint( koord3d ) const; /* changes the state of a convoi via tool_t; mandatory for networkmode! * for list of commands and parameter see tool_t::tool_change_convoi_t */ void call_convoi_tool( const char function, const char *extra ) const; /** * set state: only use by tool_t::tool_change_convoi_t */ void set_state( uint16 new_state ) { assert(new_state=WAITING_FOR_CLEARANCE && state<=CAN_START_TWO_MONTHS) && state!=SELF_DESTRUCT; } bool is_unloading() { return state==LOADING && unloading_state; } /** * reset state to no error message */ void reset_waiting() { state=WAITING_FOR_CLEARANCE; } /** * The handle for ourselves. In Anlehnung an 'this' aber mit * allen checks beim Zugriff. */ convoihandle_t self; /** * The profit in this year */ const sint64 & get_jahresgewinn() const {return jahresgewinn;} const sint64 & get_total_distance_traveled() const { return total_distance_traveled; } /** * @return the total monthly fix cost for all vehicles in convoi */ sint64 get_fixed_cost() const { return -sum_fixed_costs; } /** * returns the total running cost for all vehicles in convoi */ sint32 get_running_cost() const { return -sum_running_costs; } /** * returns the total new purchase cost for all vehicles in convoy */ sint64 get_purchase_cost() const; /** * Constructor for loading from file, */ convoi_t(loadsave_t *file); convoi_t(player_t* player); virtual ~convoi_t(); /** * Load or save this convoi data */ void rdwr(loadsave_t *file); /** * method to load/save convoihandle_t */ static void rdwr_convoihandle_t(loadsave_t *file, convoihandle_t &cnv); void finish_rd(); void rotate90( const sint16 y_size ); /** * Called if a vehicle enters a depot */ void betrete_depot(depot_t *dep); /** * Return the internal name of the convois * @return Name of the convois */ const char *get_internal_name() const {return name_and_id+name_offset;} /** * Allows editing ... * @return Name of the Convois */ char *access_internal_name() {return name_and_id+name_offset;} /** * Return the name of the convois * @return Name of the convois */ const char *get_name() const {return name_and_id;} /** * Sets the name. Copies name into this->name and translates it. */ void set_name(const char *name, bool with_new_id = true); /** * Return the position of the convois. * @return Position of the convois */ koord3d get_pos() const; /** * @return current speed, this might be different from topspeed * actual currently set speed. */ const sint32& get_akt_speed() const { return akt_speed; } /** * @return total power of this convoi */ const uint32 & get_sum_power() const {return sum_power;} const sint32 & get_min_top_speed() const {return min_top_speed;} const sint32 & get_speed_limit() const {return speed_limit;} void set_speed_limit(sint32 s) { speed_limit = s;} /// @returns weight of the convoy's vehicles (excluding freight) const sint64 & get_sum_weight() const {return sum_weight;} /// @returns weight of convoy including freight const sint64 & get_sum_gesamtweight() const {return sum_gesamtweight;} /// changes sum_friction_weight, called when vehicle changed tile and friction changes as well. void update_friction_weight(sint64 delta_friction_weight) { sum_friction_weight += delta_friction_weight; } /// @returns theoretical max speed of a convoy with given @p total_power and @p total_weight static sint32 calc_max_speed(uint64 total_power, uint64 total_weight, sint32 speed_limit); uint32 get_length() const; /** * @return length of convoi in the correct units for movement */ uint32 get_length_in_steps() const { return get_length() * VEHICLE_STEPS_PER_CARUNIT; } /** * Add the costs for travelling one tile */ void add_running_cost( const weg_t *weg ); /** * moving the vehicles of a convoi and acceleration/deceleration * all other stuff => convoi_t::step() */ sync_result sync_step(uint32 delta_t); /** * All things like route search or loading, that may take a little */ void step(); /** * sets a new convoi in route */ void start(); void ziel_erreicht(); ///< Called, when the first vehicle reaches the target /** * When a vehicle has detected a problem * force calculate a new route */ void suche_neue_route(); /** * Wait until vehicle 0 reports free route * will be called during a hop_check, if the road/track is blocked */ void warten_bis_weg_frei(sint32 restart_speed); /** * @return Vehicle count */ uint8 get_vehicle_count() const { return vehicle_count; } /** * @return Vehicle at position i */ vehicle_t* get_vehicle(uint16 i) const { return fahr[i]; } vehicle_t* front() const { return fahr[0]; } vehicle_t* back() const { return fahr[vehicle_count - 1]; } /** * Adds a vehicle at the start or end of the convoi. */ bool add_vehicle(vehicle_t *v, bool infront = false); /** * Removes vehicles at position i */ vehicle_t * remove_vehicle_at(unsigned short i); const minivec_tpl &get_goods_catg_index() const { return goods_catg_index; } // recalculates the good transported by this convoy and (in case of changes) will start schedule recalculation void recalc_catg_index(); /** * Sets a schedule */ bool set_schedule(schedule_t *f); schedule_t* get_schedule() const { return schedule; } /** * Creates a new schedule if there isn't one already. */ schedule_t * create_schedule(); // remove wrong freight when schedule changes etc. void check_freight(); /** * @return Owner of this convoi */ player_t * get_owner() const { return owner; } /** * Opens an information window * @see simwin */ void open_info_window(); /** * @param[out] buf a description string for the object, der z.B. in einem * Beobachtungsfenster angezeigt wird. * @see simwin */ void info(cbuffer_t & buf) const; /** * @param[out] buf Filled with freight description */ void get_freight_info(cbuffer_t & buf); void set_sortby(uint8 order); uint8 get_sortby() const { return freight_info_order; } /** * Opens the schedule window * @see simwin */ void open_schedule_window( bool show ); /** * pruefe ob Beschraenkungen fuer alle Fahrzeuge erfuellt sind */ bool pruefe_alle(); /** * Control loading and unloading */ void laden(); /** * Setup vehicles before starting to move */ void vorfahren(); /** * Calculate the total value of the convoi as the sum of all vehicle values. */ sint64 calc_restwert() const; /** * Check if this convoi has entered a depot. */ bool in_depot() const { return state == INITIAL; } /** * loading_level was minimum_loading before. Actual percentage loaded of loadable * vehicles. */ const sint32 &get_loading_level() const { return loading_level; } /** * At which loading level is the train allowed to start? 0 during driving. */ const sint32 &get_loading_limit() const { return loading_limit; } /** * Schedule convois for self destruction. Will be executed * upon next sync step */ void self_destruct(); /** * Helper method to remove convois from the map that cannot * removed normally (i.e. by sending to a depot) anymore. * This is a workaround for bugs in the game. */ void destroy(); /** * Debug info to stderr */ void dump() const; /** * book a certain amount into the convois financial history * is called from vehicle during un/load */ void book(sint64 amount, int cost_type); /** * return a pointer to the financial history */ sint64* get_finance_history() { return *financial_history; } /** * return a specified element from the financial history */ sint64 get_finance_history(int month, int cost_type) const { return financial_history[month][cost_type]; } sint64 get_stat_converted(int month, int cost_type) const; /** * only purpose currently is to roll financial history */ void new_month(); /** * Method for yearly action */ void new_year(); void set_home_depot(koord3d hd) { home_depot = hd; } koord3d get_home_depot() { return home_depot; } /** * Sends convoi to nearest depot. * Has to be called synchronously on all clients in networkmode! * @returns success message */ const char* send_to_depot(bool local); /** * this give the index of the next signal or the end of the route * convois will slow down before it, if this is not a waypoint or the cannot pass * The slowdown is done by the vehicle routines */ route_t::index_t get_next_stop_index() const { return next_stop_index; } void set_next_stop_index(route_t::index_t n); /* including this route_index, the route was reserved the last time * currently only used for tracks */ route_t::index_t get_next_reservation_index() { return next_reservation_index; } void set_next_reservation_index(route_t::index_t n); /* the current state of the convoi */ PIXVAL get_status_color() const; // returns station tiles needed for this convoi uint16 get_tile_length() const; bool has_obsolete_vehicles() const { return has_obsolete; } bool get_withdraw() const { return withdraw; } void set_withdraw(bool new_withdraw); bool get_no_load() const { return no_load; } void set_no_load(bool new_no_load) { no_load = new_no_load; } void must_recalc_data() { recalc_data = true; } void must_recalc_data_front() { recalc_data_front = true; } void must_recalc_speed_limit() { recalc_speed_limit = true; } // calculates the speed used for the speedbonus base, and the max achievable speed at current power/weight for overtakers void calc_speedbonus_kmh(); sint32 get_speedbonus_kmh() const; // just a guess of the speed uint32 get_average_kmh() const; // Overtaking for convois bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/simdebug.cc000066400000000000000000000013061474050137200204750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "simdebug.h" #include "utils/log.h" /** * The log for all messages */ log_t *dbg = NULL; /** * Inits logging facility. */ void init_logging(const char* logname, bool force_flush, bool log_debug, const char* greeting, const char* syslogtag ) { dbg = new log_t( logname, force_flush, log_debug, true, greeting, syslogtag ); } #if (MSG_LEVEL >= 1) #ifdef _MSC_VER int __cdecl _purecall() #else extern "C" NORETURN void __cxa_pure_virtual() #endif { dbg->fatal("unknown", "pure virtual function call"); #ifdef _MSC_VER return -1; #endif } #endif simutrans-124.3/src/simutrans/simdebug.h000066400000000000000000000023611474050137200203410ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMDEBUG_H #define SIMDEBUG_H // do not check assertions //#define NDEBUG 1 // check assertions //#undef NDEBUG //#define NDEBUG #include #include "utils/log.h" /** * Logger instance, this is a globally exported object. */ extern log_t *dbg; /** * Inits logging facility. */ void init_logging(const char *logname, bool force_flush, bool log_debug, const char *greeting, const char* syslogtag ); #define DO_EXPAND(VAL) VAL ## 1 #define EXPAND(VAL) DO_EXPAND(VAL) #if !defined(MSG_LEVEL) || (EXPAND(MSG_LEVEL) == 1) #undef MSG_LEVEL #if defined(DEBUG) #define MSG_LEVEL 4 #else #define MSG_LEVEL 0 #endif #endif #undef DO_EXPAND #undef EXPAND #if MSG_LEVEL >= 4 #define DBG_DEBUG4 dbg->debug #define DBG_MESSAGE dbg->message #define DBG_DEBUG dbg->message #elif MSG_LEVEL >= 3 #define DBG_DEBUG4(i,...) ; #define DBG_MESSAGE dbg->message #define DBG_DEBUG dbg->message #elif MSG_LEVEL >= 1 #define DBG_DEBUG4(i,...) ; #define DBG_MESSAGE(i,...) ; #define DBG_DEBUG dbg->message #else // nothing to debug -> then ignore #define DBG_DEBUG4(i,...) ; #define DBG_MESSAGE(i,...) ; #define DBG_DEBUG(i,...) ; #endif #endif simutrans-124.3/src/simutrans/simevent.cc000066400000000000000000000165631474050137200205430ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simevent.h" #include "sys/simsys.h" #include "tpl/slist_tpl.h" // system-independent event handling routines static int cx = -1; // coordinates of last mouse click event static int cy = -1; // initialised to "nowhere" static bool is_dragging = false; static int control_shift_state = 0; // none pressed static event_t meta_event(EVENT_NONE); // for storing meta-events like double-clicks and triple-clicks static event_class_t last_meta_class = EVENT_NONE; static slist_tpl queued_events; event_t::event_t(event_class_t event_class) : ev_class(event_class), ev_code(0), mouse_pos(0,0), click_pos(0,0), button_state(0), ev_key_mod(SIM_MOD_NONE) { } void event_t::move_origin(scr_coord delta) { mouse_pos -= delta; click_pos -= delta; } int event_get_last_control_shift() { // shift = 1 // ctrl = 2 return control_shift_state & 0x03; } event_class_t last_meta_event_get_class() { return last_meta_class; } /** * each drag event contains the origin of the first click. * if the window is being dragged, it is convenient to change this * so the origin keeps pointing to the window top bar. * Mainly to prevent copied, double code. */ void change_drag_start(scr_coord offset) { cx += offset.x; cy += offset.y; } // since finger events work with absolute coordinates void set_click_xy(scr_coord_val x, scr_coord_val y) { cx = x; cy = y; } static void fill_event(event_t* const ev) { // variables for detecting double-clicks and triple-clicks const uint32 interval = 400; static unsigned int prev_ev_class = EVENT_NONE; static uint16 prev_ev_code = 0; static uint32 prev_ev_time = 0; static uint8 repeat_count = 0; // number of consecutive sequences of click-release // for autorepeat buttons we track button state, press time and a repeat time static int pressed_buttons = 0; // assume: at startup no button pressed (needed for some backends) ev->ev_class = EVENT_NONE; static scr_coord last_mpos; ev->mouse_pos.x = sys_event.mx; ev->mouse_pos.y = sys_event.my; ev->click_pos.x = cx; ev->click_pos.y = cy; // always put key mod code into event ev->ev_key_mod = sys_event.key_mod; control_shift_state = sys_event.key_mod; switch (sys_event.type) { case SIM_NOEVENT: case SIM_IGNORE_EVENT: break; case SIM_KEYBOARD: ev->ev_class = EVENT_KEYBOARD; ev->ev_code = sys_event.code; break; case SIM_STRING: ev->ev_class = EVENT_STRING; ev->ev_ptr = sys_event.ptr; break; case SIM_MOUSE_BUTTONS: // press only acknowledged when no buttons are pressed pressed_buttons = sys_event.mb; switch (sys_event.code) { case SIM_MOUSE_LEFTBUTTON: ev->ev_class = EVENT_CLICK; pressed_buttons |= MOUSE_LEFTBUTTON; ev->ev_code = MOUSE_LEFTBUTTON; ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; is_dragging = true; break; case SIM_MOUSE_RIGHTBUTTON: ev->ev_class = EVENT_CLICK; pressed_buttons |= MOUSE_RIGHTBUTTON; ev->ev_code = MOUSE_RIGHTBUTTON; ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; is_dragging = true; break; case SIM_MOUSE_MIDBUTTON: ev->ev_class = EVENT_CLICK; pressed_buttons |= MOUSE_MIDBUTTON; ev->ev_code = MOUSE_MIDBUTTON; ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; is_dragging = true; break; case SIM_MOUSE_WHEELUP: ev->ev_class = EVENT_CLICK; ev->ev_code = MOUSE_WHEELUP; ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; break; case SIM_MOUSE_WHEELDOWN: ev->ev_class = EVENT_CLICK; ev->ev_code = MOUSE_WHEELDOWN; ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; break; case SIM_MOUSE_LEFTUP: ev->ev_class = EVENT_RELEASE; ev->ev_code = MOUSE_LEFTBUTTON; pressed_buttons &= ~MOUSE_LEFTBUTTON; is_dragging = false; break; case SIM_MOUSE_RIGHTUP: ev->ev_class = EVENT_RELEASE; ev->ev_code = MOUSE_RIGHTBUTTON; pressed_buttons &= ~MOUSE_RIGHTBUTTON; is_dragging = false; break; case SIM_MOUSE_MIDUP: ev->ev_class = EVENT_RELEASE; ev->ev_code = MOUSE_MIDBUTTON; pressed_buttons &= ~MOUSE_MIDBUTTON; is_dragging = false; break; } break; case SIM_MOUSE_MOVE: if (last_mpos == ev->mouse_pos) { ev->ev_class = EVENT_NONE; ev->ev_code = 0; break; } if (sys_event.mb) { // drag ev->ev_class = EVENT_DRAG; ev->ev_code = sys_event.mb; if( !is_dragging) { // we just start dragging, since the click was not delivered it seems ev->click_pos.x = cx = sys_event.mx; ev->click_pos.y = cy = sys_event.my; is_dragging = true; } } else { // move ev->ev_class = EVENT_MOVE; ev->ev_code = 0; is_dragging = false; } break; case SIM_SYSTEM: ev->ev_class = EVENT_SYSTEM; ev->ev_code = sys_event.code; ev->new_window_size = scr_size(sys_event.new_window_size_w, sys_event.new_window_size_h); break; } // check for double-clicks and triple-clicks const uint32 curr_time = dr_time(); if( ev->ev_class==EVENT_CLICK ) { if( prev_ev_class==EVENT_RELEASE && prev_ev_code==ev->ev_code && curr_time-prev_ev_time<=interval ) { // case : a mouse click which forms an unbroken sequence with the previous clicks and releases prev_ev_class = EVENT_CLICK; prev_ev_time = curr_time; } else { // case : initial click or broken click-release sequence -> prepare for the start of a new sequence prev_ev_class = EVENT_CLICK; prev_ev_code = ev->ev_code; prev_ev_time = curr_time; repeat_count = 0; } } else if( ev->ev_class==EVENT_RELEASE && prev_ev_class==EVENT_CLICK && prev_ev_code==ev->ev_code && curr_time-prev_ev_time<=interval ) { // case : a mouse release which forms an unbroken sequence with the previous clicks and releases prev_ev_class = EVENT_RELEASE; prev_ev_time = curr_time; ++repeat_count; // create meta-events where necessary if( repeat_count==2 ) { // case : double-click meta_event = *ev; meta_event.ev_class = EVENT_DOUBLE_CLICK; } else if( repeat_count==3 ) { // case : triple-click meta_event = *ev; meta_event.ev_class = EVENT_TRIPLE_CLICK; repeat_count = 0; // reset -> start over again } } else if( ev->ev_class!=EVENT_NONE && prev_ev_class!=EVENT_NONE ) { // case : broken click-release sequence -> simply reset prev_ev_class = EVENT_NONE; prev_ev_code = 0; prev_ev_time = 0; repeat_count = 0; } ev->button_state = pressed_buttons; last_mpos = ev->mouse_pos; } void display_poll_event(event_t* const ev) { if( !queued_events.empty() ) { // We have a queued (injected programatically) event, return it. event_t *elem = queued_events.remove_first(); *ev = *elem; delete elem; } else if( meta_event.ev_class!=EVENT_NONE ) { // if there is any pending meta-event, consume it instead of fetching a new event from the system *ev = meta_event; last_meta_class = meta_event.ev_class; meta_event.ev_class = EVENT_NONE; } else { last_meta_class = EVENT_NONE; GetEvents(); fill_event(ev); // prepare for next event sys_event.type = SIM_NOEVENT; sys_event.code = 0; } } void queue_event(event_t *events) { queued_events.append(events); } simutrans-124.3/src/simutrans/simevent.h000066400000000000000000000164201474050137200203750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMEVENT_H #define SIMEVENT_H #include "display/scr_coord.h" /* Messageverarbeitung */ /* Event Classes */ enum event_class_t { EVENT_NONE = 0, EVENT_KEYBOARD = 1, EVENT_STRING = 2, ///< instead of a single character a ev_ptr points to an utf8 string EVENT_CLICK = 3, EVENT_DOUBLE_CLICK = 4, ///< 2 consecutive sequences of click-release EVENT_TRIPLE_CLICK = 5, ///< 3 consecutive sequences of click-release EVENT_RELEASE = 6, EVENT_MOVE = 7, EVENT_DRAG = 8, INFOWIN = 10, ///< window event, i.e. WIN_OPEN, WIN_CLOSE WINDOW_RESIZE = 11, WINDOW_MAKE_MIN_SIZE = 12, WINDOW_CHOOSE_NEXT = 13, EVENT_SYSTEM = 254, IGNORE_EVENT = 255 }; /* Event Codes */ #define MOUSE_LEFTBUTTON 1 #define MOUSE_RIGHTBUTTON 2 #define MOUSE_MIDBUTTON 4 #define MOUSE_WHEELUP 8 #define MOUSE_WHEELDOWN 16 #define WIN_OPEN 1 #define WIN_CLOSE 2 #define WIN_TOP 3 #define WIN_UNTOP 4 // losing focus #define NEXT_WINDOW 1 #define PREV_WINDOW 2 #define SYSTEM_QUIT 1 #define SYSTEM_RESIZE 2 #define SYSTEM_RELOAD_WINDOWS 3 #define SYSTEM_THEME_CHANGED 4 /* normal keys have range 0-255, special key follow above 255 */ /* other would be better for true unicode support :( */ /* control keys */ #define SIM_KEY_BACKSPACE 8 #define SIM_KEY_TAB 9 #define SIM_KEY_ENTER 13 #define SIM_KEY_ESCAPE 27 #define SIM_KEY_SPACE 32 #define SIM_KEY_DELETE 127 #define SIM_KEY_PAUSE 279 /* arrow (direction) keys */ enum { SIM_KEY_NUMPAD_BASE = 280, // 0 on keypad SIM_KEY_DOWNLEFT, SIM_KEY_DOWN, SIM_KEY_DOWNRIGHT, SIM_KEY_LEFT, SIM_KEY_CENTER, SIM_KEY_RIGHT, SIM_KEY_UPLEFT, SIM_KEY_UP, SIM_KEY_UPRIGHT }; /* other navigation keys */ #define SIM_KEY_HOME 275 #define SIM_KEY_END 276 #define SIM_KEY_PGUP 277 #define SIM_KEY_PGDN 278 #define SIM_KEY_SCROLLLOCK 279 /* Function keys */ #define SIM_KEY_F1 256 #define SIM_KEY_F2 257 #define SIM_KEY_F3 258 #define SIM_KEY_F4 259 #define SIM_KEY_F5 260 #define SIM_KEY_F6 261 #define SIM_KEY_F7 262 #define SIM_KEY_F8 263 #define SIM_KEY_F9 264 #define SIM_KEY_F10 265 #define SIM_KEY_F11 266 #define SIM_KEY_F12 267 #define SIM_KEY_F13 268 #define SIM_KEY_F14 269 #define SIM_KEY_F15 270 #define SIM_MOD_NONE 0 #define SIM_MOD_SHIFT (1u << 0) #define SIM_MOD_CTRL (1u << 1) /* macros */ #define IS_MOUSE(ev) ((ev)->ev_class >= EVENT_CLICK && (ev)->ev_class <= EVENT_DRAG) #define IS_LEFTCLICK(ev) ((ev)->ev_class == EVENT_CLICK && (ev)->ev_code == MOUSE_LEFTBUTTON) #define IS_LEFTRELEASE(ev) ((ev)->ev_class == EVENT_RELEASE && (ev)->ev_code == MOUSE_LEFTBUTTON) #define IS_LEFTDRAG(ev) ((ev)->ev_class == EVENT_DRAG && (ev)->ev_code == MOUSE_LEFTBUTTON) #define IS_LEFTDBLCLK(ev) ((ev)->ev_class == EVENT_DOUBLE_CLICK && (ev)->ev_code == MOUSE_LEFTBUTTON) #define IS_LEFTTPLCLK(ev) ((ev)->ev_class == EVENT_TRIPLE_CLICK && (ev)->ev_code == MOUSE_LEFTBUTTON) #define IS_RIGHTCLICK(ev) ((ev)->ev_class == EVENT_CLICK && (ev)->ev_code == MOUSE_RIGHTBUTTON) #define IS_RIGHTRELEASE(ev) ((ev)->ev_class == EVENT_RELEASE && (ev)->ev_code == MOUSE_RIGHTBUTTON) #define IS_RIGHTDRAG(ev) ((ev)->ev_class == EVENT_DRAG && (ev)->ev_code == MOUSE_RIGHTBUTTON) #define IS_RIGHTDBLCLK(ev) ((ev)->ev_class == EVENT_DOUBLE_CLICK && (ev)->ev_code == MOUSE_RIGHTBUTTON) #define IS_RIGHTTPLCLK(ev) ((ev)->ev_class == EVENT_TRIPLE_CLICK && (ev)->ev_code == MOUSE_RIGHTBUTTON) #define IS_WHEELUP(ev) ((ev)->ev_class == EVENT_CLICK && (ev)->ev_code == MOUSE_WHEELUP) #define IS_WHEELDOWN(ev) ((ev)->ev_class == EVENT_CLICK && (ev)->ev_code == MOUSE_WHEELDOWN) #define IS_WINDOW_RESIZE(ev) ((ev)->ev_class == WINDOW_RESIZE) #define IS_WINDOW_MAKE_MIN_SIZE(ev) ((ev)->ev_class == WINDOW_MAKE_MIN_SIZE) #define IS_WINDOW_CHOOSE_NEXT(ev) ((ev)->ev_class == WINDOW_CHOOSE_NEXT) // This macro is to determine if the event should be also handled by children of containers. #define DOES_WINDOW_CHILDREN_NEED(ev) ((ev)->ev_class == INFOWIN || (ev)->ev_class == WINDOW_RESIZE || (ev)->ev_class == WINDOW_MAKE_MIN_SIZE ) #define IS_WINDOW_TOP(ev) ((ev)->ev_class == INFOWIN || (ev)->ev_code == WIN_TOP) #define IS_LEFT_BUTTON_PRESSED(ev) ((ev)->button_state&1) #define IS_RIGHT_BUTTON_PRESSED(ev) (((ev)->button_state&2)>>1) #define IS_MIDDLE_BUTTON_PRESSED(ev) (((ev)->button_state&4)>>2) #define IS_SHIFT_PRESSED(ev) (((ev)->ev_key_mod&SIM_MOD_SHIFT) != 0) #define IS_CONTROL_PRESSED(ev) (((ev)->ev_key_mod&SIM_MOD_CTRL ) != 0) /** * Slight explanation of event_t structure: * ev_class and ev_code speak for itself. * ev_class = EVENT_NONE: nothing defined * ev_class = EVENT_KEYBOARD: code = key pressed (released key is ignored) * ev_class = EVENT_CLICK: mouse_pos/click_pos point to mouse click place, * code = pressed mouse button * ev_class = EVENT_RELEASE: click_pos points to mouse click place, * mouse_pos points to mouse release place, * code = mouse release button * ev_class = EVENT_MOVE: click_pos is last click place, mouse_pos is to. * ev_class = EVENT_DRAG: click_pos is last click place, mouse_pos is to, * code = mouse button * ev_class = EVENT_REPEAT: code = button pressed */ struct event_t { public: event_t(event_class_t event_class = EVENT_NONE); public: /** * Move event origin. Useful when transferring events to sub-components. * @param delta position of new origin relative to the old origin. */ void move_origin(scr_coord delta); public: event_class_t ev_class; union { unsigned int ev_code; void *ev_ptr; }; // Mouse position scr_coord mouse_pos; /// position of last mouse click scr_coord click_pos; /// new window size for SYSTEM_RESIZE scr_size new_window_size; /// current mouse button state int button_state; /// mod key (SHIFT; ALT; CTRL; etc) pressed while event as triggered unsigned int ev_key_mod; }; /// Return one event. Does *not* wait. void display_poll_event(event_t *event); void change_drag_start(scr_coord offset); void set_click_xy(scr_coord_val x, scr_coord_val y); int event_get_last_control_shift(); event_class_t last_meta_event_get_class(); /// Get mouse pointer position. Implementation in simsys.cc scr_coord get_mouse_pos(); /// Adds new events to be processed. void queue_event(event_t *event); #endif simutrans-124.3/src/simutrans/simfab.cc000066400000000000000000003270551474050137200201530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include "simdebug.h" #include "display/simimg.h" #include "simcolor.h" #include "ground/grund.h" #include "ground/boden.h" #include "ground/fundament.h" #include "simfab.h" #include "world/simcity.h" #include "simhalt.h" #include "simware.h" #include "world/simworld.h" #include "descriptor/building_desc.h" #include "descriptor/goods_desc.h" #include "descriptor/sound_desc.h" #include "player/simplay.h" #include "simintr.h" #include "obj/wolke.h" #include "obj/gebaeude.h" #include "obj/field.h" #include "obj/leitung2.h" #include "dataobj/settings.h" #include "dataobj/environment.h" #include "dataobj/translator.h" #include "dataobj/loadsave.h" #include "dataobj/pakset_manager.h" #include "descriptor/factory_desc.h" #include "builder/hausbauer.h" #include "builder/goods_manager.h" #include "builder/fabrikbauer.h" #include "gui/fabrik_info.h" #include "utils/simrandom.h" #include "utils/cbuffer.h" #include "gui/simwin.h" #include "display/simgraph.h" // Fabrik_t static const int FAB_MAX_INPUT = 15000; // Half a display unit (0.5). static const sint64 FAB_DISPLAY_UNIT_HALF = ((sint64)1 << (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS - 1)); // Half a production factor unit (0.5). static const sint32 FAB_PRODFACT_UNIT_HALF = ((sint32)1 << (DEFAULT_PRODUCTION_FACTOR_BITS - 1)); karte_ptr_t fabrik_t::welt; /** * Convert internal values to displayed values */ sint64 convert_goods(sint64 value) { return ((value + FAB_DISPLAY_UNIT_HALF) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS) ); } sint64 convert_power(sint64 value) { return ( value >> POWER_TO_MW ); } sint64 convert_boost(sint64 value) { return ( (value * 100 + (DEFAULT_PRODUCTION_FACTOR>>1)) >> DEFAULT_PRODUCTION_FACTOR_BITS ); } /** * Ordering based on relative distance to a fixed point `origin'. */ class RelativeDistanceOrdering { private: const koord m_origin; public: RelativeDistanceOrdering(const koord& origin) : m_origin(origin) { /* nothing */ } /** * Returns true if `a' is closer to the origin than `b', otherwise false. */ bool operator()(const koord& a, const koord& b) const { return koord_distance(m_origin, a) < koord_distance(m_origin, b); } }; /** * Produce a scaled production amount from a production amount and work factor. */ sint32 work_scale_production(sint64 prod, sint64 work){ // compute scaled production, rounding up return ((prod * work) + (1 << WORK_BITS) - 1) >> WORK_BITS; } /** * Produce a work factor from a production amount and scaled production amount. */ sint32 work_from_production(sint64 prod, sint64 scaled){ // compute work, rounding up return prod ? ((scaled << WORK_BITS) + prod - 1) / prod : 0; } void ware_production_t::init_stats() { for( int m=0; m0 ) { set_stat( weighted_sum_storage / aggregate_weight, FAB_GOODS_STORAGE ); } for( int s=0; s0; --m ) { statistics[m][s] = statistics[m-1][s]; } if( s==FAB_GOODS_TRANSIT ) { // keep the current amount in transit statistics[0][s] = statistics[1][s]; } else { statistics[0][s] = 0; } } weighted_sum_storage = 0; // restore current storage level set_stat( (sint64)menge * (sint64)factor, FAB_GOODS_STORAGE ); } void ware_production_t::rdwr(loadsave_t *file) { if( file->is_loading() ) { init_stats(); } // we use a temporary variable to save/load old data correctly sint64 statistics_buf[MAX_MONTH][MAX_FAB_GOODS_STAT]; memcpy( statistics_buf, statistics, sizeof(statistics_buf) ); if( file->is_saving() && file->is_version_less(120, 1) ) { for( int m=0; m> DEFAULT_PRODUCTION_FACTOR_BITS); statistics_buf[m][2] = (statistics[m][2] >> DEFAULT_PRODUCTION_FACTOR_BITS); } } if( file->is_version_atleast(112, 1) ) { for( int s=0; srdwr_longlong( statistics_buf[m][s] ); } } file->rdwr_longlong( weighted_sum_storage ); } else if( file->is_version_atleast(110, 5) ) { // save/load statistics for( int s=0; s<3; ++s ) { for( int m=0; mrdwr_longlong( statistics_buf[m][s] ); } } file->rdwr_longlong( weighted_sum_storage ); } if( file->is_loading() ) { memcpy( statistics, statistics_buf, sizeof(statistics_buf) ); // Apply correction for output production graphs which have had their precision changed for factory normalization. // Also apply a fix for corrupted in-transit values caused by a logical error. if(file->is_version_less(120, 1)){ for( int m=0; mis_version_atleast(122, 1)) { file->rdwr_long(index_offset); } else if (file->is_loading()) { index_offset = 0; } } void ware_production_t::book_weighted_sum_storage(uint32 factor, sint64 delta_time) { const sint64 amount = (sint64)menge * (sint64)factor; weighted_sum_storage += amount * delta_time; set_stat( amount, FAB_GOODS_STORAGE ); } sint32 ware_production_t::calculate_output_production_rate() const { return fabrik_t::calculate_work_rate_ramp(menge, min_shipment * OUTPUT_SCALE_RAMPDOWN_MULTIPLYER, max); } sint32 ware_production_t::calculate_demand_production_rate() const { return fabrik_t::calculate_work_rate_ramp(demand_buffer, max / 2, max); } void fabrik_t::arrival_statistics_t::init() { for( uint32 s=0; sis_version_atleast(110, 5) ) { if( file->is_loading() ) { aggregate_arrival = 0; for( uint32 s=0; srdwr_short( slots[s] ); aggregate_arrival += slots[s]; } scaled_demand = 0; } else { for( uint32 s=0; srdwr_short( slots[s] ); } } file->rdwr_short( current_slot ); file->rdwr_short( active_slots ); } else if( file->is_loading() ) { init(); } } sint32 fabrik_t::arrival_statistics_t::advance_slot() { sint32 result = 0; // advance to the next slot ++current_slot; if( current_slot>=SLOT_COUNT ) { current_slot = 0; } // handle expiration of past arrivals and reset slot to 0 if( slots[current_slot]>0 ) { aggregate_arrival -= slots[current_slot]; slots[current_slot] = 0; if( aggregate_arrival==0 ) { // reset slot count to 0 as all previous arrivals have expired active_slots = 0; } result |= ARRIVALS_CHANGED; } // count the number of slots covered since aggregate arrival last increased from 0 to +ve if( active_slots>0 && active_slots start counting slots active_slots = 1; } // increment current slot and aggregate arrival slots[current_slot] += amount; aggregate_arrival += amount; } void fabrik_t::update_transit( const ware_t *ware, bool add ) { if( ware->index > goods_manager_t::INDEX_NONE ) { // only for freights fabrik_t *fab = get_fab( ware->get_target_pos() ); if( fab ) { fab->update_transit_intern( ware, add ); } } } void fabrik_t::apply_transit( const ware_t *ware ) { if( ware->index > goods_manager_t::INDEX_NONE ) { // only for freights fabrik_t *fab = get_fab( ware->get_target_pos() ); if( fab ) { for( uint32 input = 0; input < fab->input.get_count(); input++ ){ ware_production_t& w = fab->input[input]; if( w.get_typ()->get_index() == ware->index ) { // It is now in transit. w.book_stat((sint64)ware->amount, FAB_GOODS_TRANSIT ); // If using JIT2, must decrement demand buffers, activating if required. if( welt->get_settings().get_just_in_time() >= 2 ){ const uint32 prod_factor = fab->desc->get_supplier(input)->get_consumption(); const sint32 prod_delta = (sint32)((((sint64)(ware->amount) << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); const sint32 demand = w.demand_buffer; w.demand_buffer -= prod_delta; if( demand >= w.max && w.demand_buffer < w.max ) { fab->inactive_demands --; } } // ours is on its way, no need to handle the other return; } } } } } // just for simplicity ... void fabrik_t::update_transit_intern( const ware_t *ware, bool add ) { for(ware_production_t &w : input ) { if( w.get_typ()->get_index() == ware->index ) { w.book_stat(add ? (sint64)ware->amount : -(sint64)ware->amount, FAB_GOODS_TRANSIT ); return; } } } void fabrik_t::init_stats() { for( int m=0; mget_supplier(in)->get_consumption(), delta_time); } for( uint32 out = 0; out < output.get_count(); out++ ){ output[out].book_weighted_sum_storage(desc->get_product(out)->get_factor(), delta_time); } // production level const sint32 current_prod = get_current_production(); weighted_sum_production += current_prod * delta_time; set_stat( current_prod, FAB_PRODUCTION ); // electricity, pax and mail boosts weighted_sum_boost_electric += prodfactor_electric * delta_time; set_stat( prodfactor_electric, FAB_BOOST_ELECTRIC ); weighted_sum_boost_pax += prodfactor_pax * delta_time; weighted_sum_boost_mail += prodfactor_mail * delta_time; // power produced or consumed sint64 power = get_power(); weighted_sum_power += power * delta_time; set_stat( power, FAB_POWER ); } void fabrik_t::update_scaled_electric_demand() { if( desc->get_electric_demand()==65535 ) { // demand not specified in pak, use old fixed demands scaled_electric_demand = prodbase * PRODUCTION_DELTA_T; if( desc->is_electricity_producer() ) { scaled_electric_demand *= 4; } return; } const sint64 prod = desc->get_productivity(); scaled_electric_demand = (uint32)( (( (sint64)(desc->get_electric_demand()) * (sint64)prodbase + (prod >> 1) ) / prod) << POWER_TO_MW ); if( scaled_electric_demand == 0 ) { prodfactor_electric = 0; } } void fabrik_t::update_scaled_pax_demand() { // first, scaling based on current production base const sint64 prod = desc->get_productivity(); const sint64 desc_pax_demand = ( desc->get_pax_demand()==65535 ? desc->get_pax_level() : desc->get_pax_demand() ); // formula : desc_pax_demand * (current_production_base / desc_production_base); (prod >> 1) is for rounding const uint32 pax_demand = (uint32)( ( desc_pax_demand * (sint64)prodbase + (prod >> 1) ) / prod ); // then, scaling based on month length scaled_pax_demand = (uint32)welt->scale_with_month_length(pax_demand); if( scaled_pax_demand == 0 && desc_pax_demand > 0 ) { scaled_pax_demand = 1; // since desc pax demand > 0 -> ensure no less than 1 } // pax demand for fixed period length arrival_stats_pax.set_scaled_demand( pax_demand ); } void fabrik_t::update_scaled_mail_demand() { // first, scaling based on current production base const sint64 prod = desc->get_productivity(); const sint64 desc_mail_demand = ( desc->get_mail_demand()==65535 ? (desc->get_pax_level()>>2) : desc->get_mail_demand() ); // formula : desc_mail_demand * (current_production_base / desc_production_base); (prod >> 1) is for rounding const uint32 mail_demand = (uint32)( ( desc_mail_demand * (sint64)prodbase + (prod >> 1) ) / prod ); // then, scaling based on month length scaled_mail_demand = (uint32)welt->scale_with_month_length(mail_demand); if( scaled_mail_demand == 0 && desc_mail_demand > 0 ) { scaled_mail_demand = 1; // since desc mail demand > 0 -> ensure no less than 1 } // mail demand for fixed period length arrival_stats_mail.set_scaled_demand( mail_demand ); } void fabrik_t::update_prodfactor_pax() { // calculate pax boost based on arrival data and demand of the fixed-length period const uint32 periods = welt->get_settings().get_factory_arrival_periods(); const uint32 slots = arrival_stats_pax.get_active_slots(); const uint32 pax_demand = ( periods==1 || slots*periods<=(uint32)SLOT_COUNT ? arrival_stats_pax.get_scaled_demand() : ( slots==(uint32)SLOT_COUNT ? arrival_stats_pax.get_scaled_demand() * periods : (arrival_stats_pax.get_scaled_demand() * periods * slots) >> SLOT_BITS ) ); const uint32 pax_arrived = arrival_stats_pax.get_aggregate_arrival(); if( pax_demand==0 || pax_arrived==0 || desc->get_pax_boost()==0 ) { prodfactor_pax = 0; } else if( pax_arrived>=pax_demand ) { // maximum boost prodfactor_pax = desc->get_pax_boost(); } else { // pro-rata boost : (pax_arrived / pax_demand) * desc_pax_boost; (pax_demand >> 1) is for rounding prodfactor_pax = (sint32)( ( (sint64)pax_arrived * (sint64)(desc->get_pax_boost()) + (sint64)(pax_demand >> 1) ) / (sint64)pax_demand ); } set_stat(prodfactor_pax, FAB_BOOST_PAX); } void fabrik_t::update_prodfactor_mail() { // calculate mail boost based on arrival data and demand of the fixed-length period const uint32 periods = welt->get_settings().get_factory_arrival_periods(); const uint32 slots = arrival_stats_mail.get_active_slots(); const uint32 mail_demand = ( periods==1 || slots*periods<=(uint32)SLOT_COUNT ? arrival_stats_mail.get_scaled_demand() : ( slots==(uint32)SLOT_COUNT ? arrival_stats_mail.get_scaled_demand() * periods : (arrival_stats_mail.get_scaled_demand() * periods * slots) >> SLOT_BITS ) ); const uint32 mail_arrived = arrival_stats_mail.get_aggregate_arrival(); if( mail_demand==0 || mail_arrived==0 || desc->get_mail_boost()==0 ) { prodfactor_mail = 0; } else if( mail_arrived>=mail_demand ) { // maximum boost prodfactor_mail = desc->get_mail_boost(); } else { // pro-rata boost : (mail_arrived / mail_demand) * desc_mail_boost; (mail_demand >> 1) is for rounding prodfactor_mail = (sint32)( ( (sint64)mail_arrived * (sint64)(desc->get_mail_boost()) + (sint64)(mail_demand >> 1) ) / (sint64)mail_demand ); } set_stat(prodfactor_mail, FAB_BOOST_MAIL); } void fabrik_t::recalc_demands_at_target_cities() { if (!welt->get_settings().get_factory_enforce_demand()) { // demand not enforced -> no splitting of demands for(stadt_t* const c : target_cities) { c->access_target_factories_for_pax().update_factory( this, scaled_pax_demand << DEMAND_BITS); c->access_target_factories_for_mail().update_factory(this, scaled_mail_demand << DEMAND_BITS); } return; } if (target_cities.empty()) { // nothing to do return; } else if( target_cities.get_count()==1 ) { // only 1 target city -> no need to apportion pax/mail demand target_cities[0]->access_target_factories_for_pax().update_factory(this, (scaled_pax_demand << DEMAND_BITS)); target_cities[0]->access_target_factories_for_mail().update_factory(this, (scaled_mail_demand << DEMAND_BITS)); } else { // more than 1 target cities -> need to apportion pax/mail demand among the cities static vector_tpl weights(8); weights.clear(); uint32 sum_of_weights = 0; // first, calculate the weights for( uint32 c=0; cget_einwohner(), shortest_distance( get_pos().get_2d(), target_cities[c]->get_center() ) ) ); sum_of_weights += weights[c]; } // finally, apportion the pax/mail demand; formula : demand * (city_weight / aggregate_city_weight); (sum_of_weights >> 1) is for rounding for( uint32 c=0; c> 1) ) / (sint64)sum_of_weights); target_cities[c]->access_target_factories_for_pax().update_factory(this, pax_amount); const uint32 mail_amount = (uint32)(( (sint64)(scaled_mail_demand << DEMAND_BITS) * (sint64)weights[c] + (sint64)(sum_of_weights >> 1) ) / (sint64)sum_of_weights); target_cities[c]->access_target_factories_for_mail().update_factory(this, mail_amount); } } } void fabrik_t::recalc_storage_capacities() { if( desc->get_field_group() ) { // with fields -> calculate based on capacities contributed by fields const uint32 ware_types = input.get_count() + output.get_count(); if( ware_types>0 ) { // calculate total storage capacity contributed by fields const field_group_desc_t *const field_group = desc->get_field_group(); sint32 field_capacities = 0; for(field_data_t const& f : fields) { field_capacities += field_group->get_field_class(f.field_class_index)->get_storage_capacity(); } const sint32 share = (sint32)( ( (sint64)field_capacities << precision_bits ) / (sint64)ware_types ); // first, for input goods for(ware_production_t & g : input) { for( int b=0; bget_supplier_count(); ++b ) { const factory_supplier_desc_t *const input = desc->get_supplier(b); if (g.get_typ() == input->get_input_type()) { // Inputs are now normalized to factory production. uint32 prod_factor = input->get_consumption(); g.max = (sint32)((((sint64)((input->get_capacity() << precision_bits) + share) << DEFAULT_PRODUCTION_FACTOR_BITS) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); } } } // then, for output goods for(ware_production_t & g : output) { for( uint b=0; bget_product_count(); ++b ) { const factory_product_desc_t *const output = desc->get_product(b); if (g.get_typ() == output->get_output_type()) { // Outputs are now normalized to factory production. uint32 prod_factor = output->get_factor(); g.max = (sint32)((((sint64)((output->get_capacity() << precision_bits) + share) << DEFAULT_PRODUCTION_FACTOR_BITS) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); } } } } } else { // without fields -> scaling based on prodbase // first, for input goods for(ware_production_t & g : input) { for( int b=0; bget_supplier_count(); ++b ) { const factory_supplier_desc_t *const input = desc->get_supplier(b); if (g.get_typ() == input->get_input_type()) { // Inputs are now normalized to factory production. uint32 prod_factor = input->get_consumption(); g.max = (sint32)(((((sint64)input->get_capacity() * (sint64)prodbase) << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / ((sint64)desc->get_productivity() * (sint64)prod_factor)); } } } // then, for output goods for(ware_production_t & g : output) { for( uint b=0; bget_product_count(); ++b ) { const factory_product_desc_t *const output = desc->get_product(b); if (g.get_typ() == output->get_output_type()) { // Outputs are now normalized to factory production. uint32 prod_factor = output->get_factor(); g.max = (sint32)(((((sint64)output->get_capacity() * (sint64)prodbase) << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / ((sint64)desc->get_productivity() * (sint64)prod_factor)); } } } } // Now that the maximum is known, work out the recommended shipment size for outputs in normalized units. for( uint32 out = 0; out < output.get_count(); out++ ){ const uint32 prod_factor = desc->get_product(out)->get_factor(); // Determine the maximum number of whole units the out can store. const uint32 unit_size = (uint32)(((sint64)output[out].max * (sint64)prod_factor) >> ( precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS )); // Determine the number of units to ship. Prefer 10 units although in future a more dynamic choice may be appropiate. uint32 shipment_size; // Maximum shipment size. if( unit_size >= SHIPMENT_MAX_SIZE * SHIPMENT_NUM_MIN ) { shipment_size = SHIPMENT_MAX_SIZE; } // Dynamic shipment size. else if( unit_size > SHIPMENT_NUM_MIN ) { shipment_size = unit_size / SHIPMENT_NUM_MIN; } // Minimum shipment size. else { shipment_size = 1; } // Now convert it into the prefered shipment size. Always round up to prevent "off by 1" error. output[out].min_shipment = (sint32)((((sint64)shipment_size << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); } if( welt->get_settings().get_just_in_time() >= 2 ) { rebuild_inactive_cache(); } } void fabrik_t::add_target_city(stadt_t *const city) { if( target_cities.append_unique(city) ) { recalc_demands_at_target_cities(); } } void fabrik_t::remove_target_city(stadt_t *const city) { if( target_cities.is_contained(city) ) { target_cities.remove(city); city->access_target_factories_for_pax().remove_factory(this); city->access_target_factories_for_mail().remove_factory(this); recalc_demands_at_target_cities(); } } void fabrik_t::clear_target_cities() { for(stadt_t* const c : target_cities) { c->access_target_factories_for_pax().remove_factory(this); c->access_target_factories_for_mail().remove_factory(this); } target_cities.clear(); } void fabrik_t::set_base_production(sint32 p) { prodbase = p; recalc_storage_capacities(); update_scaled_electric_demand(); update_scaled_pax_demand(); update_scaled_mail_demand(); update_prodfactor_pax(); update_prodfactor_mail(); recalc_demands_at_target_cities(); } fabrik_t *fabrik_t::get_fab(const koord &pos) { const grund_t *gr = welt->lookup_kartenboden(pos); if(gr) { gebaeude_t *gb = gr->find(); if(gb) { return gb->get_fabrik(); } } return NULL; } void fabrik_t::link_halt(halthandle_t halt) { welt->access(pos.get_2d())->add_to_haltlist(halt); } void fabrik_t::unlink_halt(halthandle_t halt) { planquadrat_t *plan=welt->access(pos.get_2d()); if(plan) { plan->remove_from_haltlist(halt); } } // returns true, if there is a freight halt serving us bool fabrik_t::is_within_players_network( const player_t* player ) const { if( const planquadrat_t *plan = welt->access( pos.get_2d() ) ) { if( plan->get_haltlist_count() > 0 ) { const halthandle_t *const halt_list = plan->get_haltlist(); for( int h = 0; h < plan->get_haltlist_count(); h++ ) { halthandle_t halt = halt_list[h]; if( halt.is_bound() && halt->is_enabled(haltestelle_t::WARE) && halt->has_available_network(player) ) { return true; } } } } return false; } void fabrik_t::add_consumer(koord ziel) { if( !consumer.is_contained(ziel) ) { consumer.insert_ordered( ziel, RelativeDistanceOrdering(pos.get_2d()) ); // now tell factory too fabrik_t * fab = fabrik_t::get_fab(ziel); if (fab) { fab->add_supplier(get_pos().get_2d()); } } } void fabrik_t::remove_consumer(koord ziel) { consumer.remove(ziel); } fabrik_t::fabrik_t(loadsave_t* file) { owner = NULL; prodfactor_electric = 0; consumer_active_last_month = 0; pos = koord3d::invalid; transformers.clear(); rdwr(file); if( desc == NULL ) { dbg->warning( "fabrik_t::fabrik_t()", "No pak-file for factory at (%s) - will not be built!", pos_origin.get_str() ); return; } else if( !welt->is_within_limits(pos_origin.get_2d()) ) { dbg->warning( "fabrik_t::fabrik_t()", "%s is not a valid position! (Will not be built!)", pos_origin.get_str() ); desc = NULL; // to get rid of this broken factory later... } else { build(rotate, false, false); // now get rid of construction image for( sint16 y=0; yget_building()->get_y(rotate); y++ ) { for( sint16 x=0; xget_building()->get_x(rotate); x++ ) { gebaeude_t *gb = welt->lookup_kartenboden( pos_origin.get_2d()+koord(x,y) )->find(); if( gb ) { gb->add_alter(10000); } } } } last_sound_ms = welt->get_ticks(); } fabrik_t::fabrik_t(koord3d pos_, player_t* owner, const factory_desc_t* factory_desc, sint32 initial_prod_base) : desc(factory_desc), pos(pos_) { this->pos.z = welt->max_hgt(pos.get_2d()); pos_origin = pos; this->owner = owner; prodfactor_electric = 0; prodfactor_pax = 0; prodfactor_mail = 0; if (initial_prod_base < 0) { prodbase = desc->get_productivity() + simrand(desc->get_range()); } else { prodbase = initial_prod_base; } delta_t_sum = 0; delta_amount = 0; delta_amount_remainder = 0; activity_count = 0; currently_requiring_power = false; currently_producing = false; total_input = total_transit = total_output = 0; status = STATUS_NOTHING; consumer_active_last_month = 0; // create input information input.resize( factory_desc->get_supplier_count() ); for( int g=0; gget_supplier_count(); ++g ) { const factory_supplier_desc_t *const supp = factory_desc->get_supplier(g); input[g].set_typ( supp->get_input_type() ); } // create output information output.resize( factory_desc->get_product_count() ); for( uint g=0; gget_product_count(); ++g ) { const factory_product_desc_t *const product = factory_desc->get_product(g); output[g].set_typ( product->get_output_type() ); } recalc_storage_capacities(); if( welt->get_settings().get_just_in_time() >= 2 ){ inactive_inputs = inactive_outputs = inactive_demands = 0; if( input.empty() ){ // All sources start out with maximum product. for( uint32 out = 0; out < output.get_count(); out++ ){ output[out].menge = output[out].max; inactive_outputs ++; } } else { for( uint32 out = 0; out < output.get_count(); out++ ){ output[out].menge = 0; } // A consumer of sorts so output and input starts out empty but with a full demand buffer. for( uint32 in = 0; in < input.get_count(); in++ ){ input[in].menge = 0; input[in].demand_buffer = input[in].max; inactive_inputs++; inactive_demands++; } } } else { if( input.empty() ) { for(ware_production_t & g : output ) { if( g.max > 0 ) { // if source then start with full storage, so that AI will build line(s) immediately g.menge = g.max - 1; } } } } last_sound_ms = welt->get_ticks(); init_stats(); arrival_stats_pax.init(); arrival_stats_mail.init(); delta_slot = 0; times_expanded = 0; update_scaled_electric_demand(); update_scaled_pax_demand(); update_scaled_mail_demand(); } fabrik_t::~fabrik_t() { while(!fields.empty()) { planquadrat_t *plan = welt->access( fields.back().location ); // if destructor is called when world is destroyed, plan is already invalid if (plan) { grund_t *gr = plan->get_kartenboden(); if (field_t* f = gr->find()) { delete f; // implicitly removes the field from fields plan->boden_ersetzen( gr, new boden_t(gr->get_pos(), slope_t::flat ) ); plan->get_kartenboden()->calc_image(); continue; } } fields.pop_back(); } // destroy chart window, if present destroy_win((ptrdiff_t)this); } void fabrik_t::build(sint32 rotate, bool build_fields, bool force_initial_prodbase) { this->rotate = rotate; pos_origin = welt->lookup_kartenboden(pos_origin.get_2d())->get_pos(); gebaeude_t *gb = hausbauer_t::build(owner, pos_origin.get_2d(), rotate, desc->get_building(), this); pos = gb->get_pos(); pos_origin.z = pos.z; if(desc->get_field_group()) { // if there are fields if( !fields.empty() ) { for( uint16 i=0; ilookup_kartenboden(k); if( gr->ist_natur() ) { // first make foundation below grund_t *gr2 = new fundament_t(gr->get_pos(), gr->get_grund_hang()); welt->access(k)->boden_ersetzen(gr, gr2); gr2->obj_add( new field_t(gr2->get_pos(), owner, desc->get_field_group()->get_field_class( fields[i].field_class_index ), this ) ); } else { // there was already a building at this position => do not restore! fields.remove_at(i); i--; } } } else if( build_fields ) { // make sure not to exceed initial prodbase too much sint32 org_prodbase = prodbase; // we will start with a minimum number and try to get closer to start_fields const uint16 spawn_fields = desc->get_field_group()->get_min_fields() + simrand( desc->get_field_group()->get_start_fields()-desc->get_field_group()->get_min_fields() ); while( fields.get_count() < spawn_fields && add_random_field(10000u) ) { if (fields.get_count() > desc->get_field_group()->get_min_fields() && prodbase >= 2*org_prodbase) { // too much productivity, no more fields needed break; } } sint32 field_prod = prodbase - org_prodbase; // adjust prodbase if (force_initial_prodbase) { set_base_production( max(field_prod, org_prodbase) ); } } } else { fields.clear(); } /// Determine control logic if( welt->get_settings().get_just_in_time() >= 2 ) { // Does it both consume and produce? if( !output.empty() && !input.empty() ) { control_type = CL_FACT_MANY; } // Does it produce? else if( !output.empty() ) { control_type = CL_PROD_MANY; } // Does it consume? else if( !input.empty() ) { control_type = CL_CONS_MANY; } // No I/O? else { control_type = desc->is_electricity_producer() ? CL_ELEC_PROD : CL_NONE; } } else{ // Classic logic. if( !output.empty() && !input.empty() ) { control_type = CL_FACT_CLASSIC; } else if( !output.empty() ) { control_type = CL_PROD_CLASSIC; } else if( !input.empty() ) { control_type = CL_CONS_CLASSIC; } else { control_type = CL_ELEC_CLASSIC; } } // Boost logic determines what factors boost factory production. if( welt->get_settings().get_just_in_time() >= 2 ) { if( !desc->is_electricity_producer() && desc->get_electric_demand() > 0 ) { boost_type = BL_POWER; } else if( desc->get_pax_demand() || desc->get_mail_demand() ) { boost_type = BL_PAXM; } else { boost_type = BL_NONE; } } else { boost_type = BL_CLASSIC; } if( welt->get_settings().get_just_in_time() >= 2 ) { if( input.empty() ) { demand_type = DL_NONE; } else if( output.empty() ) { demand_type = DL_ASYNC; } else { demand_type = DL_SYNC; } } else { demand_type = input.empty() ? DL_NONE : DL_OLD; } } /* field generation code */ bool fabrik_t::add_random_field(uint16 probability) { // has fields, and not yet too many? const field_group_desc_t *fd = desc->get_field_group(); if(fd==NULL || fd->get_max_fields() <= fields.get_count()) { return false; } // we are lucky and are allowed to generate a field if( simrand(10000)>=probability ) { return false; } // we start closest to the factory, and check for valid tiles as we move out uint8 radius = 1; // pick a coordinate to use - create a list of valid locations and choose a random one slist_tpl build_locations; do { for(sint32 xoff = -radius; xoff < radius + get_desc()->get_building()->get_size().x ; xoff++) { for(sint32 yoff =-radius ; yoff < radius + get_desc()->get_building()->get_size().y; yoff++) { // if we can build on this tile then add it to the list grund_t *gr = welt->lookup_kartenboden(pos.get_2d()+koord(xoff,yoff)); if (gr != NULL && gr->get_typ() == grund_t::boden && get_desc()->get_building()->is_allowed_climate(welt->get_climate(pos.get_2d()+koord(xoff,yoff))) && gr->get_grund_hang() == slope_t::flat && gr->ist_natur() && (gr->find() || gr->kann_alle_obj_entfernen(NULL) == NULL)) { // only on same height => climate will match! build_locations.append(gr); assert(gr->find() == NULL); } // skip inside of rectangle (already checked earlier) if(radius > 1 && yoff == -radius && (xoff > -radius && xoff < radius + get_desc()->get_building()->get_size().x - 1)) { yoff = radius + get_desc()->get_building()->get_size().y - 2; } } } if (build_locations.empty()) { radius++; } } while (radius < 10 && build_locations.empty()); // built on one of the positions if (!build_locations.empty()) { grund_t *gr = build_locations.at(simrand(build_locations.get_count())); leitung_t* lt = gr->find(); if(lt) { gr->obj_remove(lt); } gr->obj_loesche_alle(NULL); // first make foundation below const koord k = gr->get_pos().get_2d(); field_data_t new_field(k); assert(!fields.is_contained(new_field)); // fetch a random field class desc based on spawn weights const weighted_vector_tpl &field_class_indices = fd->get_field_class_indices(); new_field.field_class_index = pick_any_weighted(field_class_indices); const field_class_desc_t *const field_class = fd->get_field_class( new_field.field_class_index ); fields.append(new_field); grund_t *gr2 = new fundament_t(gr->get_pos(), gr->get_grund_hang()); welt->access(k)->boden_ersetzen(gr, gr2); gr2->obj_add( new field_t(gr2->get_pos(), owner, field_class, this ) ); // adjust production base and storage capacities set_base_production( prodbase + field_class->get_field_production() ); if(lt) { gr2->obj_add( lt ); } gr2->calc_image(); return true; } return false; } void fabrik_t::remove_field_at(koord pos) { field_data_t field(pos); assert(fields.is_contained( field )); field = fields[ fields.index_of(field) ]; const field_class_desc_t *const field_class = desc->get_field_group()->get_field_class( field.field_class_index ); fields.remove(field); // revert the field's effect on production base and storage capacities set_base_production( prodbase - field_class->get_field_production() ); } vector_tpl &fabrik_t::sind_da_welche(koord min_pos, koord max_pos) { static vector_tpl factory_list(16); factory_list.clear(); for(int y=min_pos.y; y<=max_pos.y; y++) { for(int x=min_pos.x; x<=max_pos.x; x++) { fabrik_t *fab=get_fab(koord(x,y)); if(fab) { if (factory_list.append_unique(fab)) { //DBG_MESSAGE("fabrik_t::sind_da_welche()","appended factory %s at (%i,%i)",gr->first_obj()->get_fabrik()->get_desc()->get_name(),x,y); } } } } return factory_list; } /** * if name==NULL translate desc factory name in game language */ char const* fabrik_t::get_name() const { return name ? name.c_str() : translator::translate(desc->get_name(), welt->get_settings().get_name_language_id()); } void fabrik_t::set_name(const char *new_name) { if(new_name==NULL || strcmp(new_name, translator::translate(desc->get_name(), welt->get_settings().get_name_language_id()))==0) { // new name is equal to name given by descriptor/translation -> set name to NULL name = NULL; } else { name = new_name; } fabrik_info_t *win = dynamic_cast(win_get_magic((ptrdiff_t)this)); if (win) { win->update_info(); } } void fabrik_t::rdwr(loadsave_t *file) { xml_tag_t f( file, "fabrik_t" ); sint32 i; sint32 owner_n; sint32 input_count; sint32 output_count; sint32 anz_lieferziele; if( file->is_saving() ) { input_count = input.get_count(); output_count = output.get_count(); anz_lieferziele = consumer.get_count(); const char *s = desc->get_name(); file->rdwr_str(s); } else { char s[256]; file->rdwr_str(s, lengthof(s)); DBG_DEBUG("fabrik_t::rdwr()","loading factory '%s'",s); desc = factory_builder_t::get_desc(s); if( desc==NULL ) { // maybe it was only renamed? desc = factory_builder_t::get_desc(translator::compatibility_name(s)); } if( desc==NULL ) { dbg->warning( "fabrik_t::rdwr()", "Pak-file for factory '%s' missing!", s ); // we continue loading even if desc==NULL pakset_manager_t::add_missing_paks( s, MISSING_FACTORY ); } } pos_origin.rdwr(file); // pos will be assigned after call to hausbauer_t::build file->rdwr_byte(rotate); if (file->is_version_atleast(122, 1)) { file->rdwr_long(delta_t_sum); file->rdwr_long(delta_amount); file->rdwr_long(delta_amount_remainder); file->rdwr_long(prodfactor_electric); file->rdwr_bool(currently_requiring_power); file->rdwr_long(total_input); file->rdwr_long(total_transit); file->rdwr_long(total_output); file->rdwr_byte(status); } else if (file->is_loading()) { delta_t_sum = 0; delta_amount = 0; delta_amount_remainder = 0; prodfactor_electric = 0; currently_requiring_power = false; total_input = 0; total_transit = 0; total_output = 0; status = STATUS_NOTHING; } // now rebuild information for received goods file->rdwr_long(input_count); if( file->is_loading() ) { input.resize( input_count ); } bool mismatch = false; for( i=0; iis_saving() ) { ware_name = ware.get_typ()->get_name(); if( file->is_version_less(120, 1) ) { // correct for older saves menge = (sint32)(((sint64)ware.menge * (sint64)desc->get_supplier(i)->get_consumption() ) >> DEFAULT_PRODUCTION_FACTOR_BITS); } } file->rdwr_str(ware_name); file->rdwr_long(menge); if( file->is_version_less(110, 5) ) { // max storage is only loaded/saved for older versions file->rdwr_long(ware.max); } // JIT2 needs to store input demand buffer if( welt->get_settings().get_just_in_time() >= 2 && file->is_version_atleast(120, 1) ){ file->rdwr_long(ware.demand_buffer); } ware.rdwr( file ); if( file->is_loading() ) { if (!ware_name) { dbg->fatal("fabrik_t::rdwr", "Invalid ware at input slot %d of factory at %s", i, pos.get_fullstr()); } ware.set_typ( goods_manager_t::get_info(ware_name) ); // Maximum in-transit is always 0 on load. if( welt->get_settings().get_just_in_time() < 2 ) { ware.max_transit = 0; } if( !desc || !desc->get_supplier(i) ) { if (desc) { dbg->warning( "fabrik_t::rdwr()", "Factory at %s requested producer for %s but has none!", pos_origin.get_fullstr(), ware_name); } ware.menge = 0; } else { // Inputs used to be with respect to actual units of production. They now are normalized with respect to factory production so require conversion. const uint32 prod_factor = desc ? desc->get_supplier(i)->get_consumption() : 1; if( file->is_version_less(120, 1) ) { ware.menge = (sint32)(((sint64)menge << DEFAULT_PRODUCTION_FACTOR_BITS) / (sint64)prod_factor); } else { ware.menge = menge; } // repair files that have 'insane' values const sint32 max = (sint32)((((sint64)FAB_MAX_INPUT << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); if( ware.menge < 0 ) { ware.menge = 0; } if( ware.menge > max ) { ware.menge = max; } if (ware.get_typ() != desc->get_supplier(i)->get_input_type()) { mismatch = true; dbg->warning("fabrik_t::rdwr", "Factory at %s: producer[%d] mismatch in savegame=%s/%s, in pak=%s", pos_origin.get_fullstr(), i, ware_name, ware.get_typ()->get_name(), desc->get_supplier(i)->get_input_type()->get_name()); } } free(const_cast(ware_name)); } } if( desc && input_count != desc->get_supplier_count() ) { dbg->warning("fabrik_t::rdwr", "Mismatch of input slot count for factory %s at %s: savegame = %d, pak = %d", get_name(), pos_origin.get_fullstr(), input_count, desc->get_supplier_count()); // resize input to match the descriptor input.resize( desc->get_supplier_count() ); mismatch = true; } if (mismatch) { array_tpl dummy; dummy.resize(desc->get_supplier_count()); for(uint16 i=0; iget_supplier_count(); i++) { dummy[i] = input[i]; } for(uint16 i=0; iget_supplier_count(); i++) { // search for matching type bool missing = true; const goods_desc_t* goods = desc->get_supplier(i)->get_input_type(); for(uint16 j=0; jget_supplier_count() && missing; j++) { if (dummy[j].get_typ() == goods) { input[i] = dummy[j]; dummy[j].set_typ(NULL); missing = false; } } if (missing) { input[i].set_typ(goods); } } } // now rebuilt information for produced goods file->rdwr_long(output_count); if( file->is_loading() ) { output.resize( output_count ); } mismatch = false; for( i=0; iis_saving() ) { ware_name = ware.get_typ()->get_name(); // correct scaling for older saves if( file->is_version_less(120, 1) ){ menge = (sint32)(((sint64)ware.menge * desc->get_product(i)->get_factor() ) >> DEFAULT_PRODUCTION_FACTOR_BITS); } } file->rdwr_str(ware_name); file->rdwr_long(menge); if( file->is_version_less(110, 5) ) { // max storage is only loaded/saved for older versions file->rdwr_long(ware.max); // obsolete variables -> statistics already contain records on goods delivered sint32 abgabe_sum = (sint32)(ware.get_stat(0, FAB_GOODS_DELIVERED)); sint32 abgabe_letzt = (sint32)(ware.get_stat(1, FAB_GOODS_DELIVERED)); file->rdwr_long(abgabe_sum); file->rdwr_long(abgabe_letzt); } ware.rdwr( file ); if( file->is_loading() ) { if (ware_name && goods_manager_t::get_info(ware_name)) { ware.set_typ( goods_manager_t::get_info(ware_name)); } else { dbg->fatal("fabrik_t::rdwr", "Invalid ware %s at output slot %d of factory at %s", ware_name ? ware_name : "", i, pos.get_fullstr()); } if( !desc || !desc->get_product(i) ) { if (desc) { dbg->warning( "fabrik_t::rdwr()", "Factory at %s requested consumer for %s but has none!", pos_origin.get_fullstr(), ware_name ); } ware.menge = 0; } else { // Outputs used to be with respect to actual units of production. They now are normalized with respect to factory production so require conversion. if( file->is_version_less(120, 1) ){ const uint32 prod_factor = desc ? desc->get_product(i)->get_factor() : 1; ware.menge = (sint32)(((sint64)menge << DEFAULT_PRODUCTION_FACTOR_BITS) / (sint64)prod_factor); } else { ware.menge = menge; } // repair files that have 'insane' values if( ware.menge < 0 ) { ware.menge = 0; } if (ware.get_typ() != desc->get_product(i)->get_output_type()) { mismatch = true; dbg->warning("fabrik_t::rdwr", "Factory at %s: consumer[%d] mismatch in savegame=%s/%s, in pak=%s", pos_origin.get_fullstr(), i, ware_name, ware.get_typ()->get_name(), desc->get_product(i)->get_output_type()->get_name()); } } free(const_cast(ware_name)); } } if( desc && output_count != desc->get_product_count()) { dbg->warning("fabrik_t::rdwr", "Mismatch of output slot count for factory %s at %s: savegame = %d, pak = %d", get_name(), pos_origin.get_fullstr(), output_count, desc->get_product_count()); // resize output to match the descriptor output.resize( desc->get_product_count() ); mismatch = true; } if (mismatch) { array_tpl dummy; dummy.resize(desc->get_product_count()); for(uint16 i=0; iget_product_count(); i++) { dummy[i] = output[i]; } for(uint16 i=0; iget_product_count(); i++) { // search for matching type bool missing = true; const goods_desc_t* goods = desc->get_product(i)->get_output_type(); for(uint16 j=0; jget_product_count() && missing; j++) { if (dummy[j].get_typ() == goods) { output[i] = dummy[j]; dummy[j].set_typ(NULL); missing = false; } } if (missing) { output[i].set_typ(goods); } } } // restore other information owner_n = welt->sp2num(owner); file->rdwr_long(owner_n); file->rdwr_long(prodbase); if( file->is_version_less(110, 5) ) { // prodfactor saving no longer required sint32 adjusted_value = (prodfactor_electric / 16) + 16; file->rdwr_long(adjusted_value); } // no longer save power at factories if( file->is_version_atleast(99, 17) && file->is_version_less(120, 4) ) { sint32 power = 0; file->rdwr_long(power); } if( file->is_version_atleast(120, 1) && file->is_version_less(120, 4) ) { sint32 power_demand = 0; file->rdwr_long(power_demand); } // owner stuff if( file->is_loading() ) { // take care of old files if( file->is_version_less(86, 1) ) { koord k = desc ? desc->get_building()->get_size() : koord(1,1); DBG_DEBUG("fabrik_t::rdwr()","correction of production by %i",k.x*k.y); // since we step from 86.01 per factory, not per tile! prodbase *= k.x*k.y*2; } // restore factory owner // Due to a omission in Volkers changes, there might be savegames // in which factories were saved without an owner. In this case // set the owner to the default of player 1 if(owner_n == -1) { // Use default owner = welt->get_public_player(); } else { // Restore owner pointer owner = welt->get_player(owner_n); } } file->rdwr_long(anz_lieferziele); // connect/save consumer for(int i=0; iis_loading()) { consumer.append(koord::invalid); } consumer[i].rdwr(file); } if( file->is_version_atleast(112, 2) ) { file->rdwr_long( consumer_active_last_month ); } // suppliers / consumers will be recalculated in finish_rd if (file->is_loading() && welt->get_settings().is_crossconnect_factories()) { consumer.clear(); } // information on fields ... if( file->is_version_atleast(99, 10) ) { if( file->is_saving() ) { uint16 nr=fields.get_count(); file->rdwr_short(nr); if( file->is_version_atleast(102, 3) ) { // each field stores location and a field class index for( uint16 i=0 ; irdwr_short(idx); } } else { // each field only stores location for( uint16 i=0 ; irdwr_short(nr); fields.reserve(nr); if( file->is_version_atleast(102, 3) ) { // each field stores location and a field class index for( uint16 i=0 ; irdwr_short(idx); if( desc && desc->get_field_group() ) { // set class index to 0 if it is out of range, if there fields at all fields.append( field_data_t(k, idx >= desc->get_field_group()->get_field_class_count() ? 0 : idx ) ); } } } else { // each field only stores location for( uint16 i=0 ; iget_field_group() ) { // oald add fields if there are any defined fields.append( field_data_t(k, 0) ); } } } } } // restore city pointer here if( file->is_version_atleast(99, 14) ) { sint32 nr = target_cities.get_count(); file->rdwr_long(nr); for( int i=0; iis_saving()) { city_index = welt->get_cities().index_of( target_cities[i] ); } file->rdwr_long(city_index); if( file->is_loading() ) { // will also update factory information target_cities.append( welt->get_cities()[city_index] ); } } } else if( file->is_loading() ) { // will be handled by the city after reloading target_cities.clear(); } if( file->is_version_atleast(110, 5) ) { file->rdwr_short(times_expanded); // statistics for( int s=0; srdwr_longlong( statistics[m][s] ); } } file->rdwr_longlong( weighted_sum_production ); file->rdwr_longlong( weighted_sum_boost_electric ); file->rdwr_longlong( weighted_sum_boost_pax ); file->rdwr_longlong( weighted_sum_boost_mail ); file->rdwr_longlong( weighted_sum_power ); file->rdwr_longlong( aggregate_weight ); file->rdwr_long( delta_slot ); } else if( file->is_loading() ) { times_expanded = 0; init_stats(); delta_slot = 0; } arrival_stats_pax.rdwr( file ); arrival_stats_mail.rdwr( file ); if( file->is_version_atleast(110, 7) ) { file->rdwr_byte(activity_count); } else if( file->is_loading() ) { activity_count = 0; } // save name if( file->is_version_atleast(110, 7) ) { if( file->is_saving() && !name ) { char const* fullname = desc->get_name(); file->rdwr_str(fullname); } else { file->rdwr_str(name); if( file->is_loading() && desc != NULL && name == desc->get_name() ) { // equal to desc name name = 0; } } } } /** * let the chimney smoke, if there is something to produce */ void fabrik_t::smoke() { const smoke_desc_t *rada = desc->get_smoke(); if(rada) { const uint8 rot = (4-rotate)%desc->get_building()->get_all_layouts(); grund_t *gr = welt->lookup_kartenboden(pos_origin.get_2d()+desc->get_smoketile( rot )); const koord offset = ( desc->get_smokeoffset(rot)*OBJECT_OFFSET_STEPS)/16; wolke_t *smoke = new wolke_t(gr->get_pos(), offset.x, 0, offset.y, desc->get_smokelifetime(), desc->get_smokeuplift(), rada->get_images() ); gr->obj_add(smoke); } // maybe sound? if( desc->get_sound()!=NO_SOUND && welt->get_ticks()>last_sound_ms+desc->get_sound_interval_ms() ) { last_sound_ms = welt->get_ticks(); welt->play_sound_area_clipped( get_pos().get_2d(), desc->get_sound(), FACTORY_SOUND ); } } uint32 fabrik_t::scale_output_production(const uint32 product, uint32 menge) const { // prorate production based upon amount of product in storage // but allow full production rate for storage amounts less than twice the minimum shipment size. const uint32 maxi = output[product].max; const uint32 actu = output[product].menge; if( actu= (uint32)(2 * output[product].min_shipment) ) { if( menge>(0x7FFFFFFFu/maxi) ) { // avoid overflow menge = (((maxi-actu)>>5)*(menge>>5))/(maxi>>10); } else { // and that is the simple formula menge = (menge*(maxi-actu)) / maxi; } } } else { // overfull? No production menge = 0; } return menge; } /************** TODO: properly handle more than one transformer! *******************************/ void fabrik_t::set_power_supply(uint32 supply) { if( transformers.empty() ) { return; } pumpe_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return; } trans->set_power_supply(supply); } uint32 fabrik_t::get_power_supply() const { if( transformers.empty() ) { return 0; } pumpe_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return 0; } return trans->get_power_supply(); } sint32 fabrik_t::get_power_consumption() const { if( transformers.empty() ) { return 0; } pumpe_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return 0; } return trans->get_power_consumption(); } void fabrik_t::set_power_demand(uint32 demand) { if( transformers.empty() ) { return; } senke_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return; } trans->set_power_demand(demand); } uint32 fabrik_t::get_power_demand() const { if( transformers.empty() ) { return 0; } senke_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return 0; } return trans->get_power_demand(); } sint32 fabrik_t::get_power_satisfaction() const { if( transformers.empty() ) { return 0; } senke_t *const trans = dynamic_cast(transformers.front()); if( trans == NULL ) { return 0; } return trans->get_power_satisfaction(); } sint64 fabrik_t::get_power() const { if( desc->is_electricity_producer() ) { return ((sint64)get_power_supply() * (sint64)get_power_consumption()) >> leitung_t::FRACTION_PRECISION; } else { return -(((sint64)get_power_demand() * (sint64)get_power_satisfaction() + (((sint64)1 << leitung_t::FRACTION_PRECISION) - 1)) >> leitung_t::FRACTION_PRECISION); } } sint32 fabrik_t::get_input_stock(const goods_desc_t *typ) { sint32 menge = -1; for(ware_production_t const& i : input) { if (typ == i.get_typ()) { menge = i.menge >> precision_bits; break; } } return menge; } sint32 fabrik_t::get_output_stock(const goods_desc_t *typ) { sint32 menge = -1; for(ware_production_t const& i : output) { if (typ == i.get_typ()) { menge = i.menge >> precision_bits; break; } } return menge; } sint32 fabrik_t::liefere_an(const goods_desc_t *typ, sint32 menge) { if( typ==goods_manager_t::passengers ) { // book pax arrival and recalculate pax boost book_stat(menge, FAB_PAX_ARRIVED); arrival_stats_pax.book_arrival(menge); update_prodfactor_pax(); return menge; } else if( typ==goods_manager_t::mail ) { // book mail arrival and recalculate mail boost book_stat(menge, FAB_MAIL_ARRIVED); arrival_stats_mail.book_arrival(menge); update_prodfactor_mail(); return menge; } else { // case : freight for( uint32 in = 0; in < input.get_count(); in++ ){ ware_production_t& ware = input[in]; if( ware.get_typ() == typ ) { ware.book_stat( -menge, FAB_GOODS_TRANSIT ); // Resolve how much normalized production arrived, rounding up (since we rounded up when we removed it). const uint32 prod_factor = desc->get_supplier(in)->get_consumption(); const sint32 prod_delta = (sint32)((((sint64)menge << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); // Activate inactive inputs. if( ware.menge <= 0 ) { inactive_inputs --; } ware.menge += prod_delta; if( welt->get_settings().get_just_in_time() >= 2 ){ // In JIT2 it is illegal to exceed input storage limit. All production that does so is discarded. if( ware.menge > ware.max ){ const sint32 prod_comp = ware.menge - ware.max; ware.menge = ware.max; // Apply demand penalty. Reactivate inactive demands. sint32 demand_old = ware.demand_buffer; ware.demand_buffer-= prod_comp; if( demand_old >= ware.max && ware.demand_buffer < ware.max ) inactive_demands-= 1; // Resolve how many goods we actually used (rounding to nearest) menge -= (sint32)(((sint64)prod_comp * (sint64)prod_factor + (1 << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits - 1))) >> (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)); } } else{ // avoid overflow const sint32 max = (sint32)((((sint64)FAB_MAX_INPUT << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); if( ware.menge >= max ) { menge -= (sint32)(((sint64)menge * (sint64)(ware.menge - max) + (sint64)(prod_delta >> 1)) / (sint64)prod_delta); ware.menge = max - 1; } } ware.book_stat(menge, FAB_GOODS_RECEIVED); return menge; } } } // ware "typ" wird hier nicht verbraucht return -1; } sint8 fabrik_t::is_needed(const goods_desc_t *typ) const { for(ware_production_t const& i : input) { if( i.get_typ() == typ ) { // Ordering logic is done in ticks. This means that every supplier is given a chance to fulfill an order (which they do so fairly). return i.placing_orders; } } return -1; // not needed here } bool fabrik_t::is_active_consumer( koord k ) const { if ( consumer.is_contained(k) ) { return 0 < ( ( 1 << consumer.index_of(k) ) & consumer_active_last_month ); } return false; } sint32 fabrik_t::get_jit2_power_boost() const { if (!is_transformer_connected()) { return 0; } const sint32 power_satisfaction = get_power_satisfaction(); if( power_satisfaction >= ((sint32)1 << leitung_t::FRACTION_PRECISION) ) { // all demand fulfilled return (sint32)desc->get_electric_boost(); } else { // calculate bonus, rounding down return (sint32)(((sint64)desc->get_electric_boost() * (sint64)power_satisfaction) >> leitung_t::FRACTION_PRECISION); } } void fabrik_t::step(uint32 delta_t) { // Only do something if advancing in time. if( delta_t==0 ) { return; } /// Declare production control variables. // The production effort of the factory. sint32 prod; // Actual production effort done. sint32 work = 0; // Desired production effort of factory. sint32 want = 0; /// Boost logic. // Solve boosts. switch( boost_type ) { case BL_CLASSIC: { // JIT1 implementation for power bonus. if( !desc->is_electricity_producer() && scaled_electric_demand > 0 ) { // one may be thinking of linking this to actual production only prodfactor_electric = (sint32)(((sint64)desc->get_electric_boost() * (sint64)get_power_satisfaction() + (sint64)((sint64)1 << (leitung_t::FRACTION_PRECISION - 1))) >> leitung_t::FRACTION_PRECISION); } break; } case BL_POWER: { // get desired power boost amount sint32 const prodfactor_want = get_jit2_power_boost(); // calculate maximum change delta from change rate scaled by time const sint32 prodfactor_change = max(BOOST_POWER_CHANGE_RATE * delta_t / PRODUCTION_DELTA_T, 1); // limit rate of change of electricity boost (improve stability) const sint32 prodfactor_delta = prodfactor_want - prodfactor_electric; if( prodfactor_delta > prodfactor_change ) { // limit increase rate prodfactor_electric += prodfactor_change; } // limit decrease rate, off because of possible exploit // else if( prodfactor_delta < -prodfactor_change ) { // prodfactor_electric -= prodfactor_change; // } else { // no limit prodfactor_electric = prodfactor_want; } break; } default: { // No boost amounts to solve. break; } }; // Compute boost amount. const sint32 boost = get_prodfactor(); /// Compute base production. { // Calculate actual production. A remainder is used for extra precision. const uint32 remainder_bits = (PRODUCTION_DELTA_T_BITS + DEFAULT_PRODUCTION_FACTOR_BITS + DEFAULT_PRODUCTION_FACTOR_BITS - fabrik_t::precision_bits); const uint64 want_prod_long = (uint64)prodbase * (uint64)boost * (uint64)delta_t + (uint64)delta_amount_remainder; prod = (uint32)(want_prod_long >> remainder_bits); delta_amount_remainder = (uint32)(want_prod_long & ((1 << remainder_bits) - 1 )); } /// Perform the control logic. { // Common logic locals go here. // Amount of production change. sint32 prod_delta; // The amount of production available. sint32 prod_comp; // The amount of consumption available. sint32 cons_comp = 0; switch( control_type ) { case CL_PROD_CLASSIC: { // Classic producer logic. currently_requiring_power = false; currently_producing = false; // produces something for( uint32 product = 0; product < output.get_count(); product++ ) { // source producer const uint32 menge_out = scale_output_production( product, prod ); if( menge_out > 0 ) { const sint32 p = (sint32)menge_out; // compute work factor const sint32 work_fact = work_from_production(prod, p); // work done is work done of maximum output if( work_fact > work ) { work = work_fact; } // produce if( output[product].menge < output[product].max ) { // to find out, if storage changed delta_amount += p; output[product].menge += p; output[product].book_stat((sint64)p * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); // if less than 3/4 filled we neary always consume power currently_requiring_power |= (output[product].menge*4 < output[product].max*3); currently_producing = true; } else { output[product].book_stat((sint64)(output[product].max - 1 - output[product].menge) * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); output[product].menge = output[product].max - 1; } } } break; } case CL_PROD_MANY: { // A producer with many outputs. if( inactive_outputs == output.get_count() ) { break; } currently_requiring_power = false; for( uint32 product = 0; product < output.get_count(); product++ ) { prod_comp = output[product].max - output[product].menge; // Ignore inactive outputs. if( prod_comp <= 0 ) { continue; } // get desired work factor const sint32 work_fact = output[product].calculate_output_production_rate(); // compute desired production prod_delta = work_scale_production(prod, work_fact); // Cannot produce more than can be stored. if( prod_delta > prod_comp ) { prod_delta = prod_comp; } currently_requiring_power = (prod_delta>0); delta_amount += prod_delta; output[product].menge += prod_delta; output[product].book_stat((sint64)prod_delta * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); work += work_fact; } currently_producing = currently_requiring_power; // normalize work with respect to output number work /= output.get_count(); break; } case CL_FACT_CLASSIC: { // Classic factory logic, work and want determined by the maximum output production rate. currently_requiring_power = false; currently_producing = false; // ok, calulate maximum allowed consumption. { sint32 min_menge = input[0].menge; sint32 consumed_menge = 0; for( uint32 index = 1; index < input.get_count(); index++ ) { if( input[index].menge < min_menge ) { min_menge = input[index].menge; } } // produces something for( uint32 product = 0; product < output.get_count(); product++ ) { // calculate production const sint32 p_menge = (sint32)scale_output_production( product, prod ); // Want the maximum production rate, this is so correct amount is ordered. if( p_menge > want ) { want = p_menge; } const sint32 menge_out = p_menge < min_menge ? p_menge : min_menge; // production smaller than possible due to consumption if( menge_out > consumed_menge ) { consumed_menge = menge_out; } if( menge_out > 0 ) { const sint32 p = menge_out; // produce if( output[product].menge < output[product].max ) { // to find out, if storage changed delta_amount += p; output[product].menge += p; output[product].book_stat((sint64)p * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); // if less than 3/4 filled we neary always consume power currently_requiring_power |= (output[product].menge*4 < output[product].max*3); currently_producing = true; } else { output[product].book_stat((sint64)(output[product].max - 1 - output[product].menge) * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); output[product].menge = output[product].max - 1; } } } // and finally consume stock for( uint32 index = 0; index < input.get_count(); index++ ) { const uint32 v = consumed_menge; if( (uint32)input[index].menge > v + 1 ) { input[index].menge -= v; input[index].book_stat((sint64)v * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); } else { input[index].book_stat((sint64)input[index].menge * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); input[index].menge = 0; } } // work done is consumption rate work = work_from_production(prod, consumed_menge); } break; } case CL_FACT_MANY: { // Logic for a factory with many outputs. Work and want are based on weighted output rate so is more complicated. currently_requiring_power = false; currently_producing = false; if( inactive_outputs == output.get_count() ) { break; } { const bool no_input = inactive_inputs > 0; // Determine minimum input in form of production from all outputs. This limits production. // Determine minimum demand work rate from all inputs. This limits production rate. sint32 demand_work_limt = input[0].calculate_demand_production_rate(); cons_comp = input[0].menge; for( uint32 index = 1; index < input.get_count(); index++ ) { if( input[index].menge < cons_comp ) { cons_comp = input[index].menge; } sint32 const work_limit = input[index].calculate_demand_production_rate(); if( work_limit < demand_work_limt ) { demand_work_limt = work_limit; } } cons_comp *= output.get_count(); for( uint32 product = 0; product < output.get_count(); product++ ) { prod_comp = output[product].max - output[product].menge; // Ignore inactive outputs. if( prod_comp <= 0 ) { continue; } // get desired work factor const sint32 work_fact = min(output[product].calculate_output_production_rate(), demand_work_limt); // compute desired production prod_delta = work_scale_production(prod, work_fact); // limit to maximum storage if( prod_delta > prod_comp ) { prod_delta = prod_comp; } // credit desired production for want want += prod_delta; // skip producing anything if no input if( no_input ) { continue; } // enforce input limits on production if( prod_delta > cons_comp ) { // not enough input prod_delta = cons_comp; cons_comp = 0; } else { // enough input cons_comp -= prod_delta; } // register inactive outputs if( prod_delta == prod_comp ) { inactive_outputs++; if( inactive_outputs == output.get_count() ) { currently_requiring_power = false; } } // credit output work done work += prod_delta; currently_requiring_power = true; currently_producing = true; // Produce output delta_amount += prod_delta; output[product].menge += prod_delta; output[product].book_stat((sint64)prod_delta * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED); } // normalize want with respect to output number want /= output.get_count(); // skip consuming anything if no input if( no_input ) { break; } // compute work done const sint32 consumed = work / output.get_count(); work = work_from_production(prod, consumed); // consume inputs for( uint32 index = 0; index < input.get_count(); index++ ) { input[index].menge -= consumed; input[index].book_stat((sint64)consumed * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); // register inactive inputs if( input[index].menge <= 0 ) { currently_requiring_power = false; input[index].menge = 0; inactive_inputs ++; } } } break; } case CL_CONS_CLASSIC: { uint32 power = 0; // Classic consumer logic. currently_requiring_power = false; currently_producing = false; if( desc->is_electricity_producer() ) { // power station => start with no production power = 0; } // Always want to consume at rate of prod. want = prod; // finally consume stock for( uint32 index = 0; index < input.get_count(); index++ ) { const uint32 v = prod; if( (uint32)input[index].menge > v + 1 ) { input[index].menge -= v; input[index].book_stat((sint64)v * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); currently_requiring_power = true; currently_producing = true; if( desc->is_electricity_producer() ) { // power station => produce power power += (uint32)( ((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS ); } work += 1 << WORK_BITS; // to find out, if storage changed delta_amount += v; } else { if( desc->is_electricity_producer() ) { // power station => produce power power += (uint32)( (((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS) * input[index].menge / (v + 1) ); } delta_amount += input[index].menge; work += work_from_production(prod, input[index].menge); input[index].book_stat((sint64)input[index].menge * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); input[index].menge = 0; } } // normalize work with respect to input number work /= input.get_count(); set_power_supply(power); break; } case CL_CONS_MANY: { // Consumer logic for many inputs. Work done is based on the average consumption of all inputs. currently_requiring_power = false; currently_producing = false; // always consume prod want = prod; // Do nothing if we cannot consume anything. if( inactive_inputs == input.get_count() ) { break; } for( uint32 index = 0; index < input.get_count(); index++ ) { // Only process active inputs; if( input[index].menge <= 0 ) { continue; } currently_requiring_power = true; currently_producing = true; sint32 const consumption_prod = work_scale_production(prod, input[index].calculate_demand_production_rate()); // limit consumption to minimum of production or storage prod_delta = input[index].menge > consumption_prod ? consumption_prod : input[index].menge; // add to work done work += prod_delta; // consume input delta_amount += prod_delta; input[index].menge -= prod_delta; input[index].book_stat((sint64)prod_delta * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED); // register inactive input if( input[index].menge <= 0 ) { inactive_inputs++; if( inactive_inputs == input.get_count() ) { currently_requiring_power = false; } } } // normalise and convert work into work factor work = work_from_production(prod, work / input.get_count()); if( desc->is_electricity_producer() ) { // compute power production uint64 pp = ((uint64)scaled_electric_demand * (uint64)boost * (uint64)work) >> (DEFAULT_PRODUCTION_FACTOR_BITS + WORK_BITS); set_power_supply((uint32)pp); } break; } case CL_ELEC_PROD: { // A simple no input electricity producer, like a solar array. // always maximum work currently_requiring_power = true; currently_producing = true; work = 1 << WORK_BITS; delta_amount += prod; // compute power production uint64 pp = ((uint64)scaled_electric_demand * (uint64)boost) >> DEFAULT_PRODUCTION_FACTOR_BITS; set_power_supply((uint32)pp); break; } case CL_ELEC_CLASSIC: { // Classic no input power producer. currently_requiring_power = false; work = 1 << WORK_BITS; // power station? => produce power if( desc->is_electricity_producer() ) { currently_requiring_power = true; currently_producing = true; set_power_supply((uint32)( ((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS )); } break; } case CL_NONE: default: { currently_producing = false; currently_requiring_power = false; // None always produces maximum for whatever reason. Also default. work = 1 << WORK_BITS; break; } } } /// Ordering logic. switch( demand_type ) { case DL_SYNC: { // Synchronous ordering. All buffers are filled the same amount in parallel based on desired work factor. if( want == 0 || inactive_demands > 0 ) { // No ordering if any are overfull or there is no want. break; } for( uint32 index = 0; index < input.get_count(); index++ ) { input[index].demand_buffer += want; // register inactive demand buffer if( input[index].demand_buffer >= input[index].max ) { inactive_demands++; } } break; } case DL_ASYNC: { // Asynchronous ordering. Each buffer tries to order scaled back by the demand work factor. if( want == 0 || inactive_demands == input.get_count() ) { // No ordering if all are overfull or no want. break; } for( uint32 index = 0; index < input.get_count(); index++ ) { // Skip inactive demand buffers. if( input[index].demand_buffer >= input[index].max ) { continue; } input[index].demand_buffer += max(work_scale_production(want, input[index].calculate_demand_production_rate()), 1); // register inactive demand buffer if( input[index].demand_buffer >= input[index].max ) { inactive_demands++; } } break; } default: { // Nothing to order. break; } } /// Book the weighted sums for statistics. book_weighted_sums( delta_t ); /// Power ordering logic. switch( boost_type ) { case BL_CLASSIC: { // draw a fixed amount of power when working sufficiently, otherwise draw no power if( !desc->is_electricity_producer() ) { if( currently_requiring_power ) { set_power_demand(scaled_electric_demand); } else { set_power_demand(0); } } break; } case BL_POWER: { // compute power demand uint64 pd = ((uint64)scaled_electric_demand * (uint64)boost * (uint64)work) >> (DEFAULT_PRODUCTION_FACTOR_BITS + WORK_BITS); set_power_demand((uint32)pd); break; } default: { // No power is ordered. break; } }; /// Periodic tasks. delta_t_sum += delta_t; if( delta_t_sum > PRODUCTION_DELTA_T ) { delta_t_sum = delta_t_sum % PRODUCTION_DELTA_T; // distribute, if min shipment waiting. for( uint32 product = 0; product < output.get_count(); product++ ) { // either more than ten or nearly full (if there are less than ten output) if( output[product].menge >= output[product].min_shipment ) { verteile_waren( product ); INT_CHECK("simfab 636"); } } // Order required inputs. for( uint32 index = 0; index < input.get_count(); index++ ) { switch( demand_type ) { case DL_SYNC: case DL_ASYNC: { // Orders based on demand buffer. input[index].placing_orders = (input[index].demand_buffer > 0); break; } case DL_OLD: { // Orders based on storage and maximum transit. input[index].placing_orders = (input[index].menge < input[index].max && (input[index].max_transit == 0 || input[index].get_in_transit() < input[index].max_transit) ); break; } default: { // Unknown order logic? break; } } } recalc_factory_status(); // rescale delta_amount here: all products should be produced at least once // (if consumer only: all supplements should be consumed once) const uint32 min_change = output.empty() ? input.get_count() : output.get_count(); if( (delta_amount >> fabrik_t::precision_bits) > min_change ) { // we produced some real quantity => smoke smoke(); // chance to expand every 256 rounds of activities, after which activity count will return to 0 (overflow behaviour) if( (++activity_count)==0 ) { if( desc->get_field_group() ) { if( fields.get_count()get_field_group()->get_max_fields() ) { // spawn new field with given probability add_random_field(desc->get_field_group()->get_probability()); } } else { if( times_expanded < desc->get_expand_times() ) { if( simrand(10000) < desc->get_expand_probability() ) { set_base_production( prodbase + desc->get_expand_minimum() + simrand( desc->get_expand_range() ) ); ++times_expanded; } } } } INT_CHECK("simfab 558"); // reset for next cycle delta_amount = 0; } } /// advance arrival slot at calculated interval and recalculate boost where necessary delta_slot += delta_t; const sint32 periods = welt->get_settings().get_factory_arrival_periods(); const sint32 slot_interval = (1 << (PERIOD_BITS - SLOT_BITS)) * periods; while( delta_slot>slot_interval ) { delta_slot -= slot_interval; const sint32 pax_result = arrival_stats_pax.advance_slot(); if( pax_result&ARRIVALS_CHANGED || (periods>1 && pax_result&ACTIVE_SLOTS_INCREASED && arrival_stats_pax.get_active_slots()*periods>SLOT_COUNT ) ) { update_prodfactor_pax(); } const sint32 mail_result = arrival_stats_mail.advance_slot(); if( mail_result&ARRIVALS_CHANGED || (periods>1 && mail_result&ACTIVE_SLOTS_INCREASED && arrival_stats_mail.get_active_slots()*periods>SLOT_COUNT ) ) { update_prodfactor_mail(); } } } class distribute_ware_t { public: ware_t ware; /// goods to be routed to consumer halthandle_t halt; /// potential start halt sint32 space_left; /// free space at halt sint32 amount_waiting; /// waiting goods at halt for same destination as ware private: sint32 ratio_free_space; /// ratio of free space at halt (=0 for overflowing station) public: distribute_ware_t( halthandle_t h, sint32 l, sint32 t, sint32 a, ware_t w ) { halt = h; space_left = l; amount_waiting = a; ware = w; // ensure overfull stations compare equal allowing tie breaker clause (amount waiting) sint32 space_total = t > 0 ? t : 1; ratio_free_space = space_left > 0 ? ((sint64)space_left << fabrik_t::precision_bits) / space_total : 0; } distribute_ware_t() {} static bool compare(const distribute_ware_t &dw1, const distribute_ware_t &dw2) { return (dw1.ratio_free_space > dw2.ratio_free_space) || (dw1.ratio_free_space == dw2.ratio_free_space && dw1.amount_waiting <= dw2.amount_waiting); } }; /** * distribute stuff to all best destination */ void fabrik_t::verteile_waren(const uint32 product) { // wohin liefern ? if( consumer.empty() ) { return; } // not connected? const planquadrat_t *plan = welt->access(pos.get_2d()); if( plan == NULL ) { dbg->fatal("fabrik_t::verteile_waren", "%s has not distribution target", get_name() ); } if( plan->get_haltlist_count() == 0 ) { return; } static vector_tpl dist_list(16); dist_list.clear(); // to distribute to all target equally, we use this counter, for the source hald, and target factory, to try first output[product].index_offset++; /* distribute goods to factory * that has not an overflowing input storage * also prevent stops from overflowing, if possible * Since we can called with menge>max/2 are at least 10 are there, we must first limit the amount we distribute */ // We already know the distribution amount. However it has to be converted from factory units into real units. const uint32 prod_factor = desc->get_product(product)->get_factor(); sint32 menge = (sint32)(((sint64)output[product].min_shipment * (sint64)(prod_factor)) >> (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)); // ok, first generate list of possible destinations const halthandle_t *haltlist = plan->get_haltlist(); for( unsigned i=0; iget_haltlist_count(); i++ ) { halthandle_t halt = haltlist[(i + output[product].index_offset) % plan->get_haltlist_count()]; if( !halt->get_ware_enabled() ) { continue; } for( uint32 n=0; nis_needed(output[product].get_typ()); if( needed>=0 ) { ware_t ware(output[product].get_typ()); ware.amount = menge; ware.to_factory = 1; ware.set_target_pos( lieferziel ); unsigned w; // find the index in the target factory for( w = 0; w < ziel_fab->get_input().get_count() && ziel_fab->get_input()[w].get_typ() != ware.get_desc(); w++ ) { // empty } // if only overflown factories found => deliver to first // else deliver to non-overflown factory if( !(welt->get_settings().get_just_in_time() != 0) ) { // without production stop when target overflowing, distribute to least overflow target const sint32 fab_left = ziel_fab->get_input()[w].max - ziel_fab->get_input()[w].menge; dist_list.insert_ordered( distribute_ware_t( halt, fab_left, ziel_fab->get_input()[w].max, (sint32)halt->get_ware_fuer_zielpos(output[product].get_typ(),ware.get_target_pos()), ware ), distribute_ware_t::compare ); } else if( needed > 0 ) { // we are not overflowing: Station can only store up to a maximum amount of goods per square const sint32 halt_left = (sint32)halt->get_capacity(2) - (sint32)halt->get_ware_summe(ware.get_desc()); dist_list.insert_ordered( distribute_ware_t( halt, halt_left, halt->get_capacity(2), (sint32)halt->get_ware_fuer_zielpos(output[product].get_typ(),ware.get_target_pos()), ware ), distribute_ware_t::compare ); } } } } } // Auswertung der Ergebnisse if( !dist_list.empty() ) { distribute_ware_t *best = NULL; for(distribute_ware_t & i : dist_list) { // now search route int const result = haltestelle_t::search_route(&i.halt, 1U, welt->get_settings().is_no_routing_over_overcrowding(), i.ware); if( result == haltestelle_t::ROUTE_OK || result == haltestelle_t::ROUTE_WALK ) { // we can deliver to this destination best = &i; break; } } if( best == NULL ) { return; // no route for any destination } halthandle_t &best_halt = best->halt; ware_t &best_ware = best->ware; // now process found route const sint32 space_left = (welt->get_settings().get_just_in_time() != 0 ) ? best->space_left : (sint32)best_halt->get_capacity(2) - (sint32)best_halt->get_ware_summe(best_ware.get_desc()); menge = min( menge, 9 + space_left ); // ensure amount is not negative ... if( menge<0 ) { menge = 0; } // since it is assigned here to an unsigned variable! best_ware.amount = menge; if( space_left<0 ) { // find, what is most waiting here from us ware_t most_waiting(output[product].get_typ()); most_waiting.amount = 0; for(koord const& n : consumer) { uint32 const amount = best_halt->get_ware_fuer_zielpos(output[product].get_typ(), n); if( amount > most_waiting.amount ) { most_waiting.set_target_pos(n); most_waiting.amount = amount; } } // we will reroute some goods if( best->amount_waiting==0 && most_waiting.amount>0 ) { // remove something from the most waiting goods if( best_halt->recall_ware( most_waiting, min((sint32)(most_waiting.amount/2), 1 - space_left) ) ) { best_ware.amount += most_waiting.amount; } else { // overcrowded with other stuff (not from us) return; } // refund JIT2 demand buffers for rerouted goods if( welt->get_settings().get_just_in_time() >= 2 ) { // locate destination factory fabrik_t *fab = get_fab( most_waiting.get_target_pos() ); if( fab ) { for( uint32 input = 0; input < fab->input.get_count(); input++ ) { ware_production_t& w = fab->input[input]; if ( w.get_typ()->get_index() == most_waiting.get_index() ) { // correct ware to refund found // refund demand buffers, deactivating if required const uint32 prod_factor = fab->desc->get_supplier(input)->get_consumption(); const sint32 prod_delta = (sint32)((((sint64)(most_waiting.amount) << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); const sint32 demand = w.demand_buffer; w.demand_buffer += prod_delta; if( demand < w.max && w.demand_buffer >= w.max ) { fab->inactive_demands++; } // refund successful break; } } } } } else { return; } } // Since menge might have been mutated, it must be converted back. This might introduce some error with some prod factors which is always rounded up. const sint32 prod_delta = (sint32)((((sint64)menge << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor); // If the output is inactive, reactivate it if( output[product].menge == output[product].max && prod_delta > 0 ) inactive_outputs-= 1; output[product].menge -= prod_delta; best_halt->starte_mit_route(best_ware); best_halt->recalc_status(); fabrik_t::apply_transit( &best_ware ); // add as active destination consumer_active_last_month |= (1 << consumer.index_of(best_ware.get_target_pos())); output[product].book_stat(best_ware.amount, FAB_GOODS_DELIVERED); } } void fabrik_t::new_month() { // calculate weighted averages if( aggregate_weight > 0 ) { set_stat( weighted_sum_production / aggregate_weight, FAB_PRODUCTION ); set_stat( weighted_sum_boost_electric / aggregate_weight, FAB_BOOST_ELECTRIC ); set_stat( weighted_sum_boost_pax / aggregate_weight, FAB_BOOST_PAX ); set_stat( weighted_sum_boost_mail / aggregate_weight, FAB_BOOST_MAIL ); set_stat( weighted_sum_power / aggregate_weight, FAB_POWER ); } // update statistics for input and output goods for( uint32 in = 0; in < input.get_count(); in++ ){ input[in].roll_stats( desc->get_supplier(in)->get_consumption(), aggregate_weight ); } for( uint32 out = 0; out < output.get_count(); out++ ){ output[out].roll_stats( desc->get_product(out)->get_factor(), aggregate_weight ); } consumer_active_last_month = 0; // advance statistics a month for( int s = 0; s < MAX_FAB_STAT; ++s ) { for( int m = MAX_MONTH - 1; m > 0; --m ) { statistics[m][s] = statistics[m-1][s]; } statistics[0][s] = 0; } weighted_sum_production = 0; weighted_sum_boost_electric = 0; weighted_sum_boost_pax = 0; weighted_sum_boost_mail = 0; weighted_sum_power = 0; aggregate_weight = 0; // restore the current values set_stat( get_current_production(), FAB_PRODUCTION ); set_stat( prodfactor_electric, FAB_BOOST_ELECTRIC ); set_stat( prodfactor_pax, FAB_BOOST_PAX ); set_stat( prodfactor_mail, FAB_BOOST_MAIL ); set_stat( get_power(), FAB_POWER ); // since target cities' population may be increased -> re-apportion pax/mail demand recalc_demands_at_target_cities(); } // static ! uint8 fabrik_t::status_to_color[5] = {COL_RED, COL_ORANGE, COL_GREEN, COL_YELLOW, COL_WHITE }; //#define FL_WARE_NULL 1 #define FL_WARE_ALLENULL 2 #define FL_WARE_LIMIT 4 #define FL_WARE_ALLELIMIT 8 #define FL_WARE_UEBER75 16 #define FL_WARE_ALLEUEBER75 32 #define FL_WARE_FEHLT_WAS 64 /* returns the status of the current factory, as well as output */ void fabrik_t::recalc_factory_status() { uint64 warenlager; char status_ein; char status_aus; int haltcount=welt->access(pos.get_2d())->get_haltlist_count(); // set bits for input warenlager = 0; total_transit = 0; status_ein = FL_WARE_ALLELIMIT; uint32 i = 0; for(ware_production_t const& j : input ) { if( j.menge >= j.max ) { status_ein |= FL_WARE_LIMIT; } else { status_ein &= ~FL_WARE_ALLELIMIT; } warenlager+= (uint64)j.menge * (uint64)(desc->get_supplier(i++)->get_consumption()); total_transit += j.get_in_transit(); if( (j.menge >> fabrik_t::precision_bits) == 0 ) { status_ein |= FL_WARE_FEHLT_WAS; } } warenlager >>= fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS; if( warenlager==0 ) { status_ein |= FL_WARE_ALLENULL; } total_input = (uint32)warenlager; // one ware missing, but producing if( status_ein & FL_WARE_FEHLT_WAS && !output.empty() && haltcount > 0 ) { status = STATUS_BAD; return; } // set bits for output warenlager = 0; status_aus = FL_WARE_ALLEUEBER75|FL_WARE_ALLENULL; i = 0; for(ware_production_t const& j : output ) { if( j.menge > 0 ) { status_aus &= ~FL_WARE_ALLENULL; if( j.menge >= 0.75 * j.max ) { status_aus |= FL_WARE_UEBER75; } else { status_aus &= ~FL_WARE_ALLEUEBER75; } warenlager += (uint64)j.menge * (uint64)(desc->get_product(i)->get_factor()); status_aus &= ~FL_WARE_ALLENULL; } else { // menge = 0 status_aus &= ~FL_WARE_ALLEUEBER75; } } warenlager >>= fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS; total_output = (uint32)warenlager; // now calculate status bar if( input.empty() ) { // does not consume anything, should just produce if( output.empty() ) { // does also not produce anything status = STATUS_NOTHING; } else if( status_aus&FL_WARE_ALLEUEBER75 || status_aus&FL_WARE_UEBER75 ) { status = STATUS_INACTIVE; // not connected? if(haltcount>0) { if(status_aus&FL_WARE_ALLEUEBER75) { status = STATUS_BAD; // connect => needs better service } else { status = STATUS_MEDIUM; // connect => needs better service for at least one product } } } else { status = STATUS_GOOD; } } else if( output.empty() ) { // nothing to produce if(status_ein&FL_WARE_ALLELIMIT) { // we assume not served status = STATUS_BAD; } else if(status_ein&FL_WARE_LIMIT) { // served, but still one at limit status = STATUS_MEDIUM; } else if(status_ein&FL_WARE_ALLENULL) { status = STATUS_INACTIVE; // assume not served if(haltcount>0) { // there is a halt => needs better service status = STATUS_BAD; } } else { status = STATUS_GOOD; } } else { // produces and consumes if((status_ein&FL_WARE_ALLELIMIT)!=0 && (status_aus&FL_WARE_ALLEUEBER75)!=0) { status = STATUS_BAD; } else if((status_ein&FL_WARE_ALLELIMIT)!=0 || (status_aus&FL_WARE_ALLEUEBER75)!=0) { status = STATUS_MEDIUM; } else if((status_ein&FL_WARE_ALLENULL)!=0 && (status_aus&FL_WARE_ALLENULL)!=0) { // not producing status = STATUS_INACTIVE; } else if(haltcount>0 && ((status_ein&FL_WARE_ALLENULL)!=0 || (status_aus&FL_WARE_ALLENULL)!=0)) { // not producing but out of supply status = STATUS_MEDIUM; } else { status = STATUS_GOOD; } } } void fabrik_t::open_info_window() { gebaeude_t *gb = welt->lookup(pos)->find(); create_win(new fabrik_info_t(this, gb), w_info, (ptrdiff_t)this ); } void fabrik_t::info_prod(cbuffer_t& buf) const { buf.clear(); buf.append( translator::translate("Durchsatz") ); buf.append(get_current_production(), 0); buf.append( translator::translate("units/day") ); buf.append("\n"); buf.printf(translator::translate("Produces: %.1f units/minute"), get_production_per_second() * 60.0 ); if (!output.empty()) { buf.append("\n\n"); buf.append(translator::translate("Produktion")); for (uint32 index = 0; index < output.get_count(); index++) { goods_desc_t const *const type = output[index].get_typ(); sint64 const pfactor = (sint64)desc->get_product(index)->get_factor(); buf.append("\n - "); if( welt->get_settings().get_just_in_time() >= 2 ) { double const pfraction = (double)pfactor / (double)DEFAULT_PRODUCTION_FACTOR; double const storage_unit = (double)(1 << fabrik_t::precision_bits); buf.printf(translator::translate("%s %.0f%% : %.0f/%.0f @ %.1f%%"), translator::translate(type->get_name()), pfraction * 100.0, (double)output[index].menge * pfraction / storage_unit, (double)output[index].max * pfraction / storage_unit, (double)output[index].calculate_output_production_rate() * 100.0 / (double)(1 << 16) ); } else { buf.printf("%s %u/%u%s", translator::translate(type->get_name()), (uint32) convert_goods( (sint64)output[index].menge * pfactor), (uint32) convert_goods( (sint64)output[index].max * pfactor), translator::translate(type->get_mass()) ); if(type->get_catg() != 0) { buf.append(", "); buf.append(translator::translate(type->get_catg_name())); } buf.printf(", %u%%", (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS)); } } } if (!input.empty()) { buf.append("\n\n"); buf.append(translator::translate("Verbrauch")); for (uint32 index = 0; index < input.get_count(); index++) { sint64 const pfactor = (sint64)desc->get_supplier(index)->get_consumption(); const char *cat_name = ""; const char *cat_seperator = ""; if( input[index].get_typ()->get_catg() > 0 ) { cat_name = translator::translate(input[index].get_typ()->get_catg_name()); cat_seperator = ", "; } buf.append("\n - "); if( welt->get_settings().get_just_in_time() >= 2 ) { double const pfraction = (double)pfactor / (double)DEFAULT_PRODUCTION_FACTOR; double const storage_unit = (double)(1 << fabrik_t::precision_bits); buf.printf(translator::translate("%s %.0f%% : %.0f+%u/%.0f%s, %s%s%.1f%%"), translator::translate(input[index].get_typ()->get_name()), pfraction * 100.0, (double)input[index].menge * pfraction / storage_unit, (uint32)input[index].get_in_transit(), (double)input[index].max * pfraction / storage_unit, translator::translate(input[index].get_typ()->get_mass()), cat_name, cat_seperator, (double)input[index].calculate_demand_production_rate() * 100.0 / (double)(1 << 16) ); } else if( welt->get_settings().get_factory_maximum_intransit_percentage() ) { buf.printf("%s %u/%i(%i)/%u%s, %s%s%u%%", translator::translate(input[index].get_typ()->get_name()), (uint32) convert_goods( (sint64)input[index].menge * pfactor), input[index].get_in_transit(), input[index].max_transit, (uint32) convert_goods( (sint64)input[index].max * pfactor), translator::translate(input[index].get_typ()->get_mass()), cat_name, cat_seperator, (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS) ); } else { buf.printf("%s %u/%i/%u%s, %s%s%u%%", translator::translate(input[index].get_typ()->get_name()), (uint32) convert_goods( (sint64)input[index].menge * pfactor), input[index].get_in_transit(), (uint32) convert_goods( (sint64)input[index].max * pfactor), translator::translate(input[index].get_typ()->get_mass()), cat_name, cat_seperator, (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS) ); } } } } void fabrik_t::info_conn(cbuffer_t& buf) const { buf.clear(); const planquadrat_t *plan = welt->access(get_pos().get_2d()); if(plan && plan->get_haltlist_count()>0) { buf.append(translator::translate("Connected stops")); for( uint i=0; iget_haltlist_count(); i++ ) { buf.printf("\n - %s", plan->get_haltlist()[i]->get_name() ); } } } void fabrik_t::finish_rd() { // adjust production base to be at least as large as fields productivity uint32 prodbase_adjust = 1; const field_group_desc_t *fd = desc->get_field_group(); if(fd) { for(uint32 i=0; iget_field_class( fields[i].field_class_index ); if (fc) { prodbase_adjust += fc->get_field_production(); } } } // set production, update all production related numbers set_base_production( max(prodbase, prodbase_adjust) ); // now we have a valid storage limit if( welt->get_settings().is_crossconnect_factories() ) { for(fabrik_t* const fab : welt->get_fab_list() ) { fab->add_supplier(this); } } else { // add as supplier to target(s) for(uint32 i=0; iadd_supplier(pos.get_2d()); consumer[i] = fab2->get_pos().get_2d(); } else { // remove this ... dbg->warning( "fabrik_t::finish_rd()", "No factory at expected position %s!", consumer[i].get_str() ); consumer.remove_at(i); i--; } } } // Now rebuild input/output activity information. if( welt->get_settings().get_just_in_time() >= 2 ){ inactive_inputs = inactive_outputs = inactive_demands = 0; for( uint32 in = 0; in < input.get_count(); in++ ){ if( input[in].menge > input[in].max ) { input[in].menge = input[in].max; } input[in].placing_orders = (input[in].demand_buffer > 0); // Also do a sanity check. People might try and force their saves to JIT2 mode via reloading so we need to catch any massive values. if( welt->get_settings().get_just_in_time() >= 2 && welt->get_settings().get_factory_maximum_intransit_percentage() != 0 ){ const sint32 demand_minmax = (sint32)((sint64)input[in].max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() / (sint64)100); if( input[in].demand_buffer < (-demand_minmax) ) { input[in].demand_buffer = -demand_minmax; } else if( input[in].demand_buffer > (input[in].max + demand_minmax) ) { input[in].demand_buffer = input[in].max; } } } for( uint32 out = 0 ; out < output.get_count() ; out++ ){ if( output[out].menge >= output[out].max ) { output[out].menge = output[out].max; } } rebuild_inactive_cache(); } else { // Classic order logic. for( uint32 in = 0; in < input.get_count(); in++ ){ input[in].placing_orders = (input[in].menge < input[in].max && input[in].get_in_transit() < input[in].max_transit); } } // set initial power boost if ( boost_type == BL_POWER ) { prodfactor_electric = get_jit2_power_boost(); } } void fabrik_t::rotate90( const sint16 y_size ) { rotate = (rotate+3)%desc->get_building()->get_all_layouts(); pos_origin.rotate90( y_size ); pos_origin.x -= desc->get_building()->get_x(rotate)-1; pos.rotate90( y_size ); for(koord & i : consumer) { i.rotate90(y_size); } for(koord & i : suppliers) { i.rotate90(y_size); } for(field_data_t & i : fields) { i.location.rotate90(y_size); } } void fabrik_t::add_supplier(koord ziel) { // Updated maximum in-transit. Only used for classic support. if( welt->get_settings().get_factory_maximum_intransit_percentage() && !suppliers.is_contained(ziel) && welt->get_settings().get_just_in_time() < 2 ) { if( fabrik_t *fab = get_fab( ziel ) ) { for( uint32 i=0; i < fab->get_output().get_count(); i++ ) { const ware_production_t &w_out = fab->get_output()[i]; // now update transit limits for(ware_production_t &w : input ) { if( w_out.get_typ() == w.get_typ() ) { #ifdef TRANSIT_DISTANCE sint64 distance = koord_distance( fab->get_pos(), get_pos() ); // calculate next mean by the following formula: average + (next - average)/(n+1) w.count_suppliers ++; sint64 next = 1 + ( distance * welt->get_settings().get_factory_maximum_intransit_percentage() * (w.max >> fabrik_t::precision_bits) ) / 131072; w.max_transit += (next - w.max_transit)/(w.count_suppliers); #else const sint32 max_storage = (sint32)(1 + ( ((sint64)w_out.max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() ) >> fabrik_t::precision_bits) / 100); const sint32 old_max_transit = w.max_transit; w.max_transit += max_storage; if( w.max_transit < old_max_transit ) { // we have overflown, so we use the max value w.max_transit = 0x7fffffff; } #endif break; } } } // since there could be more than one good, we have to iterate over all of them } } suppliers.insert_unique_ordered( ziel, RelativeDistanceOrdering(pos.get_2d()) ); } void fabrik_t::remove_supplier(koord pos) { suppliers.remove(pos); // Updated maximum in-transit. Only used for classic support. if( welt->get_settings().get_factory_maximum_intransit_percentage() && welt->get_settings().get_just_in_time() < 2 ) { // set to zero for(ware_production_t &w : input ) { w.max_transit = 0; } // unfourtunately we have to bite the bullet and recalc the values from scratch ... for(koord ziel : suppliers ) { if( fabrik_t *fab = get_fab( ziel ) ) { for( uint32 i=0; i < fab->get_output().get_count(); i++ ) { const ware_production_t &w_out = fab->get_output()[i]; // now update transit limits for(ware_production_t &w : input ) { if( w_out.get_typ() == w.get_typ() ) { #ifdef TRANSIT_DISTANCE sint64 distance = koord_distance( fab->get_pos(), get_pos() ); // calculate next mean by the following formula: average + (next - average)/(n+1) w.count_suppliers ++; sint64 next = 1 + ( distance * welt->get_settings().get_factory_maximum_intransit_percentage() * (w.max >> fabrik_t::precision_bits) ) / 131072; w.max_transit += (next - w.max_transit)/(w.count_suppliers); #else const sint32 max_storage = (sint32)(1 + ( ((sint64)w_out.max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() ) >> fabrik_t::precision_bits) / 100); const sint32 old_max_transit = w.max_transit; w.max_transit += max_storage; if( w.max_transit < old_max_transit ) { // we have overflown, so we use the max value w.max_transit = 0x7fffffff; } #endif break; } } } // since there could be more than one good, we have to iterate over all of them } } } } /** crossconnect everything possible */ void fabrik_t::add_all_suppliers() { for(int i=0; i < desc->get_supplier_count(); i++) { const factory_supplier_desc_t *supplier = desc->get_supplier(i); const goods_desc_t *ware = supplier->get_input_type(); for(fabrik_t* const fab : welt->get_fab_list()) { // connect to an existing one, if this is an producer if(fab!=this && fab->get_output_stock(ware) > -1) { // add us to this factory // will also add to our suppliers list fab->add_consumer(pos.get_2d()); } } } } /* adds a new supplier to this factory * fails if no matching goods are there */ bool fabrik_t::add_supplier(fabrik_t* fab) { for(int i=0; i < desc->get_supplier_count(); i++) { const factory_supplier_desc_t *supplier = desc->get_supplier(i); const goods_desc_t *ware = supplier->get_input_type(); // connect to an existing one, if this is an producer if( fab!=this && fab->get_output_stock(ware) > -1 ) { // add us to this factory fab->add_consumer(pos.get_2d()); return true; } } return false; } void fabrik_t::get_tile_list( vector_tpl &tile_list ) const { gebaeude_t *gb = welt->lookup( pos )->find(); koord size = get_desc()->get_building()->get_size( gb->get_tile()->get_layout() ); const koord3d pos0 = gb->get_pos() - gb->get_tile()->get_offset(); // get origin koord k; tile_list.clear(); // add all tiles for( k.y = 0; k.y < size.y; k.y++ ) { for( k.x = 0; k.x < size.x; k.x++ ) { if( grund_t* gr = welt->lookup( pos0+k ) ) { if( gebaeude_t* const add_gb = obj_cast(gr->first_no_way_obj()) ) { if( add_gb->get_fabrik()==this ) { tile_list.append( (pos0+k).get_2d() ); } } } } } } void fabrik_t::get_fields_list( vector_tpl &fields_list ) const { fields_list.clear(); if(desc->get_field_group()) { // if there are fields for(auto fd : fields) { const koord k = fd.location; grund_t *gr=welt->lookup_kartenboden(k); fields_list.append( gr ); } } } // Returns a list of goods produced by this factory. The caller must delete // the list when done slist_tpl *fabrik_t::get_produced_goods() const { slist_tpl *goods = new slist_tpl(); for(ware_production_t const& i : output) { goods->append(i.get_typ()); } return goods; } void fabrik_t::rebuild_inactive_cache() { inactive_inputs = inactive_outputs = inactive_demands = 0; for( uint32 i = 0; i < input.get_count(); i++ ){ if( input[i].menge <= 0 ) { inactive_inputs++; } if( input[i].demand_buffer >= input[i].max ) { inactive_demands++; } } for( uint32 i = 0 ; i < output.get_count() ; i++ ){ if( output[i].menge >= output[i].max ) { inactive_outputs++; } } } double fabrik_t::get_production_per_second() const { return (double)prodbase * (double)get_prodfactor() / (double)DEFAULT_PRODUCTION_FACTOR / (double)DEFAULT_PRODUCTION_FACTOR; } sint32 fabrik_t::calculate_work_rate_ramp(sint32 const amount, sint32 const minimum, sint32 const maximum, uint32 const precision) { sint32 production_rate; if( minimum >= maximum || minimum >= amount ) { // full production production_rate = 1 << precision; } else if( amount < maximum ) { // reduction production production_rate = (sint32)(((sint64)(maximum - amount) << precision) / (sint64)(maximum - minimum)); // apply work factor minimum limit if( production_rate < WORK_SCALE_MINIMUM_FRACTION ){ production_rate = WORK_SCALE_MINIMUM_FRACTION; } } else { // no production production_rate = 0; } return production_rate; } /** * Draws some nice colored bars giving some status information */ void fabrik_t::display_status(sint16 xpos, sint16 ypos) { const sint16 count = input.get_count()+output.get_count(); ypos += -D_WAITINGBAR_WIDTH - LINESPACE/6; xpos -= (count * D_WAITINGBAR_WIDTH - get_tile_raster_width()) / 2; if( input.get_count() ) { if( currently_producing ) { display_ddd_box_clip_rgb(xpos-2, ypos-1, D_WAITINGBAR_WIDTH*input.get_count()+4, 6, color_idx_to_rgb(10), color_idx_to_rgb(12)); } display_fillbox_wh_clip_rgb(xpos-1, ypos, D_WAITINGBAR_WIDTH*input.get_count()+2, 4, color_idx_to_rgb(150), true); for(uint32 i=0; i < input.get_count(); i++) { ware_production_t const& goods = input[i]; if (!desc->get_supplier(i)) { continue; } const sint64 pfactor = (sint64)desc->get_supplier(i)->get_consumption(); const uint32 storage_capacity = (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)goods.max * pfactor) >> (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)); if (storage_capacity) { const uint32 stock_quantity = (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)goods.menge * pfactor) >> (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)); const PIXVAL goods_color = goods.get_typ()->get_color(); const uint16 v = min(25, (uint16)(25 * stock_quantity / storage_capacity)) + 2; if (currently_producing) { display_fillbox_wh_clip_rgb(xpos, ypos - v - 1, 1, v, color_idx_to_rgb(COL_GREY4), true); display_fillbox_wh_clip_rgb(xpos + 1, ypos - v - 1, D_WAITINGBAR_WIDTH - 2, v, goods_color, true); display_fillbox_wh_clip_rgb(xpos + D_WAITINGBAR_WIDTH - 1, ypos - v - 1, 1, v, color_idx_to_rgb(COL_GREY1), true); } else { display_blend_wh_rgb(xpos + 1, ypos - v - 1, D_WAITINGBAR_WIDTH - 2, v, goods_color, 60); mark_rect_dirty_wc(xpos + 1, ypos - v - 1, xpos + D_WAITINGBAR_WIDTH - 1, ypos - 1); } } xpos += D_WAITINGBAR_WIDTH; } xpos += 4; } if( output.get_count() ) { if( currently_producing ) { display_ddd_box_clip_rgb(xpos-2, ypos-1, D_WAITINGBAR_WIDTH*output.get_count()+4, 6, color_idx_to_rgb(10), color_idx_to_rgb(12)); } display_fillbox_wh_clip_rgb(xpos-1, ypos, D_WAITINGBAR_WIDTH*output.get_count()+2, 4, color_idx_to_rgb(COL_ORANGE), true); for(uint32 i=0; i < output.get_count(); i++) { ware_production_t const& goods = output[i]; const sint64 pfactor = (sint64)desc->get_product(i)->get_factor(); const uint32 storage_capacity = (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)goods.max * pfactor) >> (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)); if (storage_capacity) { const uint32 stock_quantity = (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)goods.menge * pfactor) >> (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)); const PIXVAL goods_color = goods.get_typ()->get_color(); const uint16 v = min(25, (uint16)(25 * stock_quantity / storage_capacity)) + 2; // the blended bars are too faint for me if (currently_producing) { display_fillbox_wh_clip_rgb(xpos, ypos - v - 1, 1, v, color_idx_to_rgb(COL_GREY4), true); display_fillbox_wh_clip_rgb(xpos + 1, ypos - v - 1, D_WAITINGBAR_WIDTH - 2, v, goods_color, true); display_fillbox_wh_clip_rgb(xpos + D_WAITINGBAR_WIDTH - 1, ypos - v - 1, 1, v, color_idx_to_rgb(COL_GREY1), true); } else { display_blend_wh_rgb(xpos + 1, ypos - v - 1, D_WAITINGBAR_WIDTH - 2, v, goods_color, 60); mark_rect_dirty_wc(xpos + 1, ypos - v - 1, xpos + D_WAITINGBAR_WIDTH - 1, ypos - 1); } } xpos += D_WAITINGBAR_WIDTH; } } } simutrans-124.3/src/simutrans/simfab.h000066400000000000000000000533451474050137200200130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMFAB_H #define SIMFAB_H #include "dataobj/koord3d.h" #include "dataobj/translator.h" #include "tpl/slist_tpl.h" #include "tpl/vector_tpl.h" #include "tpl/array_tpl.h" #include "descriptor/factory_desc.h" #include "halthandle.h" #include "world/simworld.h" #include "utils/plainstring.h" class player_t; class stadt_t; class ware_t; class leitung_t; /** * Factory statistics */ #define MAX_MONTH (12) #define FAB_PRODUCTION (0) #define FAB_POWER (1) #define FAB_BOOST_ELECTRIC (2) #define FAB_BOOST_PAX (3) #define FAB_BOOST_MAIL (4) #define FAB_PAX_GENERATED (5) #define FAB_PAX_DEPARTED (6) #define FAB_PAX_ARRIVED (7) #define FAB_MAIL_GENERATED (8) #define FAB_MAIL_DEPARTED (9) #define FAB_MAIL_ARRIVED (10) #define MAX_FAB_STAT (11) // reference lines #define FAB_REF_MAX_BOOST_ELECTRIC (0) #define FAB_REF_MAX_BOOST_PAX (1) #define FAB_REF_MAX_BOOST_MAIL (2) #define FAB_REF_DEMAND_ELECTRIC (3) #define FAB_REF_DEMAND_PAX (4) #define FAB_REF_DEMAND_MAIL (5) #define MAX_FAB_REF_LINE (6) // statistics for goods #define MAX_FAB_GOODS_STAT (4) // common to both input and output goods #define FAB_GOODS_STORAGE (0) // input goods #define FAB_GOODS_RECEIVED (1) #define FAB_GOODS_CONSUMED (2) #define FAB_GOODS_TRANSIT (3) // output goods #define FAB_GOODS_DELIVERED (1) #define FAB_GOODS_PRODUCED (2) // production happens in every second #define PRODUCTION_DELTA_T_BITS (10) #define PRODUCTION_DELTA_T (1 << PRODUCTION_DELTA_T_BITS) // default production factor #define DEFAULT_PRODUCTION_FACTOR_BITS (8) #define DEFAULT_PRODUCTION_FACTOR (1 << DEFAULT_PRODUCTION_FACTOR_BITS) // precision of apportioned demand (i.e. weights of factories at target cities) #define DEMAND_BITS (4) /** * JIT2 output scale constants. */ // The fixed point precision for work done fraction. static const uint32 WORK_BITS = 16; // The minimum allowed production rate for a factory. This is to limit the time outputs take to fill completly (so factories idle sooner). // Fixed point form range must be between 0.0 and 1.0. static const sint32 WORK_SCALE_MINIMUM_FRACTION = (5 << WORK_BITS) / 100; // ~5%, 1/20 of the full production rate. // The number of times minimum_shipment must be in current storage before rampdown starts. // Must be at least 2 to allow for full production as shipment is not instant. static const sint32 OUTPUT_SCALE_RAMPDOWN_MULTIPLYER = 2; // Two shipments must be ready. // The maximum rate at which power boost change change per second. // This limit is required to help stiffen overloaded networks to combat oscilations caused by feedback. static const sint32 BOOST_POWER_CHANGE_RATE = (5 << DEFAULT_PRODUCTION_FACTOR_BITS) / 100; // ~5% /** * Shipment size constants. */ // The maximum shipment size in whole units. // Must be greater than 0. static const uint32 SHIPMENT_MAX_SIZE = 10; // Traditional value. // The minimum number of whole shipments a facotry can store. // Must be greater than 0 to prevent division by 0. static const uint32 SHIPMENT_NUM_MIN = 4; // Quarters should allow reasonably fair distribution. /** * Convert internal values to displayed values */ sint64 convert_goods(sint64 value); sint64 convert_power(sint64 value); sint64 convert_boost(sint64 value); class ware_production_t { private: const goods_desc_t *type; // statistics for each goods sint64 statistics[MAX_MONTH][MAX_FAB_GOODS_STAT]; sint64 weighted_sum_storage; /// clears statistics, transit, and weighted_sum_storage void init_stats(); public: ware_production_t() : type(NULL), menge(0), max(0)/*, transit(statistics[0][FAB_GOODS_TRANSIT])*/, max_transit(0), placing_orders(false), index_offset(0) { #ifdef TRANSIT_DISTANCE count_suppliers = 0; #endif init_stats(); } const goods_desc_t* get_typ() const { return type; } void set_typ(const goods_desc_t *t) { type=t; } // functions for manipulating goods statistics void roll_stats(uint32 factor, sint64 aggregate_weight); void rdwr(loadsave_t *file); const sint64* get_stats() const { return *statistics; } void book_stat(sint64 value, int stat_type) { assert(stat_type consumer; uint32 consumer_active_last_month; /** * suppliers to this factory */ vector_tpl suppliers; /** * fields of this factory (only for farms etc.) */ struct field_data_t { koord location; uint16 field_class_index; field_data_t() : field_class_index(0) {} explicit field_data_t(const koord loc) : location(loc), field_class_index(0) {} field_data_t(const koord loc, const uint16 class_index) : location(loc), field_class_index(class_index) {} bool operator==(const field_data_t &other) const { return location==other.location; } }; vector_tpl fields; /** * Distribute products to connected stops */ void verteile_waren(const uint32 product); // List of target cities vector_tpl target_cities; player_t *owner; static karte_ptr_t welt; const factory_desc_t *desc; /** * Is construction site rotated? */ uint8 rotate; /** * production base amount */ sint32 prodbase; /** * multipliers for the production base amount */ sint32 prodfactor_electric; sint32 prodfactor_pax; sint32 prodfactor_mail; array_tpl input; ///< array for input/consumed goods array_tpl output; ///< array for output/produced goods /// Accumulated time since last production uint32 delta_t_sum; uint32 delta_amount; // production remainder when scaled to PRODUCTION_DELTA_T. added back next step to eliminate cumulative error uint32 delta_amount_remainder; // number of rounds where there is active production or consumption uint8 activity_count; // The adjacent connected transformer, if any. vector_tpltransformers; // true, if the factory did produce enough in the last step to require power bool currently_requiring_power; // there is input or output and we do something with it ... bool currently_producing; uint32 last_sound_ms; uint32 total_input, total_transit, total_output; uint8 status; /** * Inactive caches, used to speed up logic when dealing with inputs and outputs. */ uint8 inactive_outputs; uint8 inactive_inputs; uint8 inactive_demands; /// Position of a building of the factory. koord3d pos; /// Position of the nw-corner tile of the factory. koord3d pos_origin; /** * Number of times the factory has expanded so far * Only for factories without fields */ uint16 times_expanded; /** * Electricity amount scaled with prodbase */ uint32 scaled_electric_demand; /** * Pax/mail demand scaled with prodbase and month length */ uint32 scaled_pax_demand; uint32 scaled_mail_demand; /** * Update scaled electricity amount */ void update_scaled_electric_demand(); /** * Update scaled pax/mail demand */ void update_scaled_pax_demand(); void update_scaled_mail_demand(); /** * Update production multipliers for pax and mail */ void update_prodfactor_pax(); void update_prodfactor_mail(); /** * Re-calculate the pax/mail demands of factory at target cities */ void recalc_demands_at_target_cities(); /** * Recalculate storage capacities based on prodbase or capacities contributed by fields */ void recalc_storage_capacities(); /** * Class for collecting arrival data and calculating pax/mail boost with fixed period length */ #define PERIOD_BITS (18) // determines period length on which boost calculation is based #define SLOT_BITS (6) // determines the number of time slots available #define SLOT_COUNT (1<& get_consumer() const { return consumer; } bool is_active_consumer( koord k ) const; const vector_tpl& get_suppliers() const { return suppliers; } /** * Functions for manipulating the list of connected cities */ void add_target_city(stadt_t *const city); void remove_target_city(stadt_t *const city); void clear_target_cities(); const vector_tpl& get_target_cities() const { return target_cities; } void add_consumer(koord ziel); void remove_consumer(koord pos); /** * adds a supplier */ void add_supplier(koord pos); void remove_supplier(koord pos); /** * @return counts amount of ware of typ * -1 not produced/used here * 0>= actual amount */ sint32 get_input_stock(const goods_desc_t *ware); sint32 get_output_stock(const goods_desc_t *ware); // true, if there was production requiring power in the last step bool is_currently_producing() const { return currently_requiring_power; } /** * True if a transformer is connected to this factory. */ bool is_transformer_connected() const { return !transformers.empty(); } vector_tpl const &get_transformers() { return transformers; } /** * Connect transformer to this factory. */ void add_transformer_connected(leitung_t *transformer) { transformers.append_unique(transformer); } void remove_transformer_connected( leitung_t* transformer ) { transformers.remove( transformer ); } /** * @return 1 wenn consumption, * 0 wenn Produktionsstopp, * -1 wenn Ware nicht verarbeitet wird */ sint8 is_needed(const goods_desc_t *) const; sint32 liefere_an(const goods_desc_t *, sint32 menge); /** * Calculate the JIT2 logic power boost amount using the currently attached transformer. */ sint32 get_jit2_power_boost() const; void step(uint32 delta_t); // factory muss auch arbeiten void new_month(); char const* get_name() const; void set_name( const char *name ); PIXVAL get_color() const { return desc->get_color(); } player_t *get_owner() const { grund_t const* const p = welt->lookup(pos); return p ? p->first_no_way_obj()->get_owner() : 0; } void open_info_window(); // infostring on production void info_prod(cbuffer_t& buf) const; // infostring on targets/sources void info_conn(cbuffer_t& buf) const; void rdwr(loadsave_t *file); /* * Fills the vector with the koords of the tiles. */ void get_tile_list( vector_tpl &tile_list ) const; /* * Fills the vector with the tiles of the fields. */ void get_fields_list( vector_tpl &fields_list ) const; /// @returns a vector of factories within a rectangle static vector_tpl & sind_da_welche(koord min, koord max); // hier die methoden zum parametrisieren der Fabrik /// Builds buildings (gebaeude_t) for the factory. void build(sint32 rotate, bool build_fields, bool force_initial_prodbase); uint8 get_rotate() const { return rotate; } void set_rotate( uint8 r ) { rotate = r; } /* field generation code * spawns a field for sure if probability>=1000 */ bool add_random_field(uint16 probability); void remove_field_at(koord pos); uint32 get_field_count() const { return fields.get_count(); } uint32 get_min_field_count() const { const field_group_desc_t *fg = get_desc()->get_field_group(); return fg ? fg->get_min_fields() : 0; } /** * total and current procduction/storage values */ const array_tpl& get_input() const { return input; } const array_tpl& get_output() const { return output; } /** * Production multipliers */ sint32 get_prodfactor_electric() const { return prodfactor_electric; } sint32 get_prodfactor_pax() const { return prodfactor_pax; } sint32 get_prodfactor_mail() const { return prodfactor_mail; } sint32 get_prodfactor() const { return DEFAULT_PRODUCTION_FACTOR + prodfactor_electric + prodfactor_pax + prodfactor_mail; } /* does not takes month length into account */ sint32 get_base_production() const { return prodbase; } void set_base_production(sint32 p); sint32 get_current_production() const { return (sint32)welt->scale_with_month_length( ((sint64)prodbase * (sint64)get_prodfactor())>>8 ); } /* returns the status of the current factory, as well as output */ enum { STATUS_BAD, STATUS_MEDIUM, STATUS_GOOD, STATUS_INACTIVE, STATUS_NOTHING }; static uint8 status_to_color[5]; uint8 get_status() const { return status; } uint32 get_total_in() const { return total_input; } uint32 get_total_transit() const { return total_transit; } uint32 get_total_out() const { return total_output; } /** * Draws some nice colored bars giving some status information */ void display_status(sint16 xpos, sint16 ypos); /** * Crossconnects all factories */ void add_all_suppliers(); /* adds a new supplier to this factory * fails if no matching goods are there */ bool add_supplier(fabrik_t* fab); /** * Return the scaled electricity amount and pax/mail demand */ uint32 get_scaled_electric_demand() const { return scaled_electric_demand; } uint32 get_scaled_pax_demand() const { return scaled_pax_demand; } uint32 get_scaled_mail_demand() const { return scaled_mail_demand; } bool is_end_consumer() const { return (output.empty() && !desc->is_electricity_producer()); } // Returns a list of goods produced by this factory. slist_tpl *get_produced_goods() const; // Rebuild the factory inactive caches. void rebuild_inactive_cache(); double get_production_per_second() const; /* Calculate work rate using a ramp function. * amount: The current amount. * minimum: Minimum amount before work rate starts ramp down. * maximum: Maximum before production stops. * (opt) precision: Work rate fixed point fractional precision. * returns: Work rate in fixed point form. */ static sint32 calculate_work_rate_ramp(sint32 const amount, sint32 const minimum, sint32 const maximum, uint32 const precision = WORK_BITS); }; #endif simutrans-124.3/src/simutrans/simhalt.cc000066400000000000000000003121331474050137200203420ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "freight_list_sorter.h" #include "world/simcity.h" #include "simcolor.h" #include "simconvoi.h" #include "simdebug.h" #include "simfab.h" #include "simhalt.h" #include "simintr.h" #include "simline.h" #include "simmem.h" #include "simmesg.h" #include "world/simplan.h" #include "player/simplay.h" #include "gui/simwin.h" #include "world/simworld.h" #include "simware.h" #include "builder/hausbauer.h" #include "builder/goods_manager.h" #include "descriptor/goods_desc.h" #include "descriptor/tunnel_desc.h" #include "ground/boden.h" #include "ground/grund.h" #include "ground/wasser.h" #include "obj/way/strasse.h" #include "dataobj/settings.h" #include "dataobj/schedule.h" #include "dataobj/loadsave.h" #include "dataobj/translator.h" #include "dataobj/environment.h" #include "obj/gebaeude.h" #include "obj/label.h" #include "obj/tunnel.h" #include "obj/wayobj.h" #include "gui/halt_info.h" #include "gui/minimap.h" #include "utils/simrandom.h" #include "utils/simstring.h" #include "tpl/binary_heap_tpl.h" #include "vehicle/vehicle.h" #include "vehicle/pedestrian.h" karte_ptr_t haltestelle_t::welt; vector_tpl haltestelle_t::alle_haltestellen; stringhashtable_tpl haltestelle_t::all_names; // hash table only used during loading inthashtable_tpl *haltestelle_t::all_koords = NULL; // since size_x*size_y < 0x1000000, we have just to shift the high bits #define get_halt_key(k,width) ( ((k).x*(width)+(k).y) /*+ ((k).z << 25)*/ ) uint8 haltestelle_t::status_step = 0; uint8 haltestelle_t::reconnect_counter = 0; static vector_tplstale_convois; static vector_tplstale_lines; void haltestelle_t::reset_routing() { reconnect_counter = welt->get_schedule_counter()-1; } void haltestelle_t::step_all() { // tell all stale convois to reroute their goods if( !stale_convois.empty() ) { convoihandle_t cnv = stale_convois.pop_back(); if( cnv.is_bound() ) { cnv->check_freight(); } } // same for stale lines if( !stale_lines.empty() ) { linehandle_t line = stale_lines.pop_back(); if( line.is_bound() ) { line->check_freight(); } } static uint32 next_halt_to_step=0; if (alle_haltestellen.empty()) { next_halt_to_step = 0; status_step = 0; return; } // reset served stops of all halts for (auto halt : alle_haltestellen) { for (int i = 0; i < goods_manager_t::get_max_catg_index(); i++) { halt->halt_served_this_step[i].clear(); } } // currently no reconnection/rerouting in progress? if (status_step == 0) { // than maybe start a reconnection (we start only when finished to avoid an eternal reconenction loop without ever rerouting) const uint8 schedule_counter = welt->get_schedule_counter(); if (reconnect_counter != schedule_counter) { // start with reconnection, re-routing will happen after complete reconnection status_step = RECONNECTING; reconnect_counter = schedule_counter; } else { // nothing to step if there is no rerouting/reconnection return; } } // we iterate in charges sint16 units_remaining = 1024; while (units_remaining > 0 && next_halt_to_step < alle_haltestellen.get_count()) { halthandle_t halt = alle_haltestellen[next_halt_to_step++]; halt->step(status_step, units_remaining); } // finished iteration, so we can proceed to next step if(next_halt_to_step >= alle_haltestellen.get_count()) { next_halt_to_step = 0; if( status_step == RECONNECTING ) { // reconnecting finished, compute connected components in one sweep rebuild_connected_components(); // reroute in next call status_step = REROUTING; } else if( status_step == REROUTING ) { // rerouting finished status_step = 0; } } } void haltestelle_t::start_load_game() { all_koords = new inthashtable_tpl; } void haltestelle_t::end_load_game() { delete all_koords; all_koords = NULL; } /** * return an index to a halt; it is only used for old games * by default create a new halt if none found */ halthandle_t haltestelle_t::get_halt_koord_index(koord k) { if(!welt->is_within_limits(k)) { return halthandle_t(); } // check in hashtable halthandle_t h; const sint32 n = get_halt_key(koord3d(k,-128), welt->get_size().y); assert(all_koords); h = all_koords->get( n ); if( !h.is_bound() ) { // No halts found => create one h = haltestelle_t::create(k, NULL ); all_koords->set( n, h ); } return h; } /* we allow only for a single stop per grund * this will only return something if this stop belongs to same player or is public, or is a dock (when on water) */ halthandle_t haltestelle_t::get_halt(const koord3d pos, const player_t *player ) { const grund_t *gr = welt->lookup(pos); if(gr) { if(gr->get_halt().is_bound() && player_t::check_owner(player,gr->get_halt()->get_owner()) ) { return gr->get_halt(); } // no halt? => we do the water check if(gr->is_water()) { // may catch bus stops close to water ... const planquadrat_t *plan = welt->access(pos.get_2d()); const uint8 cnt = plan->get_haltlist_count(); // first check for own stop for( uint8 i=0; iget_haltlist()[i]; if( halt->get_owner()==player && halt->get_station_type()&dock ) { return halt; } } // then for public stop for( uint8 i=0; iget_haltlist()[i]; if( halt->get_owner()==welt->get_public_player() && halt->get_station_type()&dock ) { return halt; } } // so: nothing found } } return halthandle_t(); } koord haltestelle_t::get_basis_pos() const { return get_basis_pos3d().get_2d(); } koord3d haltestelle_t::get_basis_pos3d() const { if (tiles.empty()) { return koord3d::invalid; } //assert(tiles.front().grund->get_pos().get_2d() == init_pos); return tiles.front().grund->get_pos(); } // returns tile closest to this coordinate grund_t *haltestelle_t::get_ground_closest_to( const koord here ) const { uint32 distance = 0x7FFFFFFFu; grund_t *closest = NULL; for(tile_t const& i : tiles) { uint32 dist = shortest_distance( i.grund->get_pos().get_2d(), here ); if( dist < distance ) { distance = dist; closest = i.grund; if( distance == 0 ) { break; } } } return closest; } /** * return the closest square that belongs to this halt */ koord haltestelle_t::get_next_pos( koord start ) const { if( grund_t *gr=get_ground_closest_to(start) ) { return gr->get_pos().get_2d(); } return koord::invalid; } /* Calculate and set basis position of this station * It is the avarage of all tiles' coordinate weighed by level of the building */ void haltestelle_t::recalc_basis_pos() { sint64 cent_x, cent_y; cent_x = cent_y = 0; uint64 level_sum; level_sum = 0; for(tile_t const& i : tiles) { if( gebaeude_t* const gb = i.grund->find() ) { uint32 lv; lv = gb->get_tile()->get_desc()->get_level() + 1; cent_x += gb->get_pos().get_2d().x * lv; cent_y += gb->get_pos().get_2d().y * lv; level_sum += lv; } } koord cent; cent = koord((sint16)(cent_x/level_sum),(sint16)(cent_y/level_sum)); // save old name plainstring name = get_name(); // clear name at old place (and the book-keeping) set_name(NULL); if ( level_sum > 0 ) { grund_t *new_center = get_ground_closest_to( cent ); if( new_center != tiles.front().grund && new_center->get_text()==NULL ) { // move to new center, if there is not yet a name on it tiles.remove( new_center ); tiles.insert( new_center ); init_pos = new_center->get_pos().get_2d(); } } // .. and set name again (and do all the book-keeping) set_name(name); return; } /** * Station factory method. Returns handles instead of pointers. */ halthandle_t haltestelle_t::create(koord pos, player_t *player) { haltestelle_t * p = new haltestelle_t(pos, player); return p->self; } /** * removes a ground tile from a station */ bool haltestelle_t::remove(player_t *player, koord3d pos) { grund_t *bd = welt->lookup(pos); // wrong ground? if(bd==NULL) { dbg->error("haltestelle_t::remove()","illegal ground at %d,%d,%d", pos.x, pos.y, pos.z); return false; } halthandle_t halt = bd->get_halt(); if(!halt.is_bound()) { dbg->error("haltestelle_t::remove()","no halt at %d,%d,%d", pos.x, pos.y, pos.z); return false; } DBG_MESSAGE("haltestelle_t::remove()","removing segment from %d,%d,%d", pos.x, pos.y, pos.z); // otherwise there will be marked tiles left ... halt->mark_unmark_coverage(false); // only try to remove connected buildings, when still in list to avoid infinite loops if( halt->rem_grund(bd) ) { // remove station building? gebaeude_t* gb = bd->find(); if(gb) { DBG_MESSAGE("haltestelle_t::remove()", "removing building" ); hausbauer_t::remove( player, gb ); bd = NULL; // no need to recalc image // removing the building could have destroyed this halt already if (!halt.is_bound()){ return true; } } } if(!halt->existiert_in_welt()) { DBG_DEBUG("haltestelle_t::remove()","remove last"); // all deleted? DBG_DEBUG("haltestelle_t::remove()","destroy"); haltestelle_t::destroy( halt ); } else { halt->recalc_basis_pos(); } // if building was removed this is false! if(bd) { bd->calc_image(); minimap_t::get_instance()->calc_map_pixel(pos.get_2d()); } return true; } /** * Station factory method. Returns handles instead of pointers. */ halthandle_t haltestelle_t::create(loadsave_t *file) { haltestelle_t *p = new haltestelle_t(file); return p->self; } /** * Station destruction method. */ void haltestelle_t::destroy(halthandle_t const halt) { delete halt.get_rep(); } /** * Station destruction method. * Da destroy() alle_haltestellen modifiziert kann kein Iterator benutzt * werden! */ void haltestelle_t::destroy_all() { while (!alle_haltestellen.empty()) { halthandle_t halt = alle_haltestellen.back(); destroy(halt); } delete all_koords; all_koords = NULL; status_step = 0; } haltestelle_t::haltestelle_t(loadsave_t* file) { last_loading_step = welt->get_steps(); cargo = (vector_tpl **)calloc( goods_manager_t::get_max_catg_index(), sizeof(vector_tpl *) ); all_links = new link_t[ goods_manager_t::get_max_catg_index() ]; halt_served_this_step = new vector_tpl[goods_manager_t::get_max_catg_index()]; status_color = SYSCOL_TEXT_UNUSED; last_status_color = color_idx_to_rgb(COL_PURPLE); last_bar_count = 0; reconnect_counter = welt->get_schedule_counter()-1; enables = NOT_ENABLED; sortierung = freight_list_sorter_t::by_name; resort_freight_info = true; rdwr(file); markers[ self.get_id() ] = current_marker; alle_haltestellen.append(self); } haltestelle_t::haltestelle_t(koord k, player_t* player) { self = halthandle_t(this); assert( !alle_haltestellen.is_contained(self) ); alle_haltestellen.append(self); markers[ self.get_id() ] = current_marker; last_loading_step = welt->get_steps(); this->init_pos = k; owner = player; enables = NOT_ENABLED; // force total re-routing reconnect_counter = welt->get_schedule_counter()-1; last_catg_index = 255; cargo = (vector_tpl **)calloc( goods_manager_t::get_max_catg_index(), sizeof(vector_tpl *) ); all_links = new link_t[ goods_manager_t::get_max_catg_index() ]; halt_served_this_step = new vector_tpl[goods_manager_t::get_max_catg_index()]; status_color = SYSCOL_TEXT_UNUSED; last_status_color = color_idx_to_rgb(COL_PURPLE); last_bar_count = 0; sortierung = freight_list_sorter_t::by_name; init_financial_history(); } haltestelle_t::~haltestelle_t() { assert(self.is_bound()); // first: remove halt from all lists int i=0; while(alle_haltestellen.is_contained(self)) { alle_haltestellen.remove(self); i++; } if (i != 1) { dbg->error("haltestelle_t::~haltestelle_t()", "handle %i found %i times in haltlist!", self.get_id(), i ); } // free name set_name(NULL); // remove from ground and planquadrat (tile) haltlists koord ul(32767,32767); koord lr(0,0); while( !tiles.empty() ) { grund_t *gr = tiles.remove_first().grund; koord pos = gr->get_pos().get_2d(); gr->set_halt( halthandle_t() ); // bounding box for adjustments ul.clip_max(pos); lr.clip_min(pos); } // remove from all haltlists uint16 const cov = welt->get_settings().get_station_coverage(); ul.x = max(0, ul.x - cov); ul.y = max(0, ul.y - cov); lr.x = min(welt->get_size().x, lr.x + 1 + cov); lr.y = min(welt->get_size().y, lr.y + 1 + cov); for( int y=ul.y; yaccess(x,y); if(plan->get_haltlist_count()>0) { plan->remove_from_haltlist(self); } } } destroy_win( magic_halt_info + self.get_id() ); // finally detach handle // before it is needed for clearing up the planqudrat and tiles self.detach(); for(unsigned i=0; i& warray = *cargo[i]; for (size_t j = warray.get_count(); j-- != 0;) { ware_t& ware = warray[j]; if(ware.amount>0) { ware.rotate90(y_size); } else { // empty => remove warray.remove_at(j); } } } } // re-linking factories verbinde_fabriken(); } const char* haltestelle_t::get_name() const { const char *name = "Unknown"; if (tiles.empty()) { name = "Unnamed"; } else { grund_t* bd = welt->lookup(get_basis_pos3d()); if(bd && bd->get_flag(grund_t::has_text)) { name = bd->get_text(); } } return name; } /** * Sets the name. Creates a copy of name. */ void haltestelle_t::set_name(const char *new_name) { grund_t *gr = welt->lookup(get_basis_pos3d()); if(gr) { if (gr->get_flag(grund_t::has_text)) { const char* old_name = gr->get_text(); halthandle_t h = all_names.remove(old_name); if(h!=self) { DBG_MESSAGE("haltestelle_t::set_name()","removing name %s already used!",gr->get_text()); } } if (label_t *lb=gr->find()) { delete lb; // very old games had labels for names } gr->set_text(new_name); if(new_name && all_names.set(gr->get_text(),self).is_bound() ) { DBG_MESSAGE("haltestelle_t::set_name()","name %s already used!",new_name); } halt_info_t *const info_frame = dynamic_cast( win_get_magic( magic_halt_info + self.get_id() ) ); if( info_frame ) { info_frame->set_name( get_name() ); } } } // returns the number of % in a printf string .... static int count_printf_param( const char *str ) { int count = 0; while( *str!=0 ) { if( *str=='%' ) { str++; if( *str!='%' ) { count++; } } str ++; } return count; } // creates stops with unique! names char* haltestelle_t::create_name(koord const k, char const* const typ) { int const lang = welt->get_settings().get_name_language_id(); stadt_t *stadt = welt->find_nearest_city(k); const char *stop = translator::translate(typ,lang); cbuffer_t buf; // this fails only, if there are no towns at all! if(stadt==NULL) { for( uint32 i=1; i<65536; i++ ) { // get a default name buf.printf( translator::translate("land stop %i %s",lang), i, stop ); if( !all_names.get(buf).is_bound() ) { return strdup(buf); } buf.clear(); } return strdup("Unnamed"); } // now we have a city const char *city_name = stadt->get_name(); sint16 li_gr = stadt->get_linksoben().x - 2; sint16 re_gr = stadt->get_rechtsunten().x + 2; sint16 ob_gr = stadt->get_linksoben().y - 2; sint16 un_gr = stadt->get_rechtsunten().y + 2; // strings for intown / outside of town const bool inside = (li_gr < k.x && re_gr > k.x && ob_gr < k.y && un_gr > k.y); const bool suburb = !inside && (li_gr - 6 < k.x && re_gr + 6 > k.x && ob_gr - 6 < k.y && un_gr + 6 > k.y); if (!welt->get_settings().get_numbered_stations()) { static const koord next_building[24] = { koord( 0, -1), // north koord( 1, 0), // east koord( 0, 1), // south koord(-1, 0), // west koord( 1, -1), // northeast koord( 1, 1), // southeast koord(-1, 1), // southwest koord(-1, -1), // northwest koord( 0, -2), // double nswo koord( 2, 0), koord( 0, 2), koord(-2, 0), koord( 1, -2), // all the remaining 3s koord( 2, -1), koord( 2, 1), koord( 1, 2), koord(-1, 2), koord(-2, 1), koord(-2, -1), koord(-1, -2), koord( 2, -2), // and now all buildings with distance 4 koord( 2, 2), koord(-2, 2), koord(-2, -2) }; // standard names: // order: factory, attraction, direction, normal name // first we try a factory name // is there a translation for factory defined? const char *fab_base_text = "%s factory %s %s"; const char *fab_base = translator::translate(fab_base_text,lang); if( fab_base_text != fab_base ) { slist_tplfabs; if (self.is_bound()) { // first factories (so with same distance, they have priority) int this_distance = 999; for(fabrik_t* const f : get_fab_list()) { int distance = koord_distance(f->get_pos().get_2d(), k); if( distance < this_distance ) { fabs.insert(f); this_distance = distance; } else { fabs.append(f); } } } else { // since the distance are presorted, we can just append for a good choice ... for( int test=0; test<24; test++ ) { fabrik_t *fab = fabrik_t::get_fab(k+next_building[test]); if(fab && fabs.is_contained(fab)) { fabs.append(fab); } } } // are there fabs? for(fabrik_t* const f : fabs) { // with factories buf.printf(fab_base, city_name, f->get_name(), stop); if( !all_names.get(buf).is_bound() ) { return strdup(buf); } buf.clear(); } } // no fabs or all names used up already // is there a translation for buildings defined? const char *building_base_text = "%s building %s %s"; const char *building_base = translator::translate(building_base_text,lang); if( building_base_text != building_base ) { // check for other special building (townhall, monument, tourist attraction) for (int i=0; i<24; i++) { grund_t *gr = welt->lookup_kartenboden( next_building[i] + k); if(gr==NULL || gr->get_typ()!=grund_t::fundament) { // no building here continue; } // since closes coordinates are tested first, we do not need to not sort this const char *building_name = NULL; const gebaeude_t* gb = gr->find(); if(gb==NULL) { // field may have foundations but no building continue; } // now we have a building here if (gb->is_monument()) { building_name = translator::translate(gb->get_name(),lang); } else if (gb->is_townhall() || gb->get_tile()->get_desc()->get_type() == building_desc_t::attraction_land || // land attraction gb->get_tile()->get_desc()->get_type() == building_desc_t::attraction_city) { // town attraction building_name = make_single_line_string(translator::translate(gb->get_tile()->get_desc()->get_name(),lang), 2); } else { // normal town house => not suitable for naming continue; } // now we have a name: try it buf.printf( building_base, city_name, building_name, stop ); if( !all_names.get(buf).is_bound() ) { return strdup(buf); } buf.clear(); } } // if there are street names, use them if( inside || suburb ) { const vector_tpl& street_names( translator::get_street_name_list() ); // make sure we do only ONE random call regardless of how many names are available (to avoid desyncs in network games) if( const uint32 count = street_names.get_count() ) { uint32 idx = simrand( count ); static const uint32 some_primes[] = { 19, 31, 109, 199, 409, 571, 631, 829, 1489, 1999, 2341, 2971, 3529, 4621, 4789, 7039, 7669, 8779, 9721 }; // find prime that does not divide count uint32 offset = 1; for(uint8 i=0; i then try the normal naming scheme ... char numbername[10]; if(inside) { strcpy( numbername, "0center" ); } else if(suburb) { // close to the city we use a different scheme, with suburbs strcpy( numbername, "0suburb" ); } else { strcpy( numbername, "0extern" ); } const char *dirname = NULL; static const char *diagonal_name[4] = { "nordwest", "nordost", "suedost", "suedwest" }; static const char *direction_name[4] = { "nord", "ost", "sued", "west" }; uint8 const rot = welt->get_settings().get_rotation(); if (k.y < ob_gr || (inside && k.y*3 < (un_gr+ob_gr+ob_gr)) ) { if (k.x < li_gr) { dirname = diagonal_name[(4 - rot) % 4]; } else if (k.x > re_gr) { dirname = diagonal_name[(5 - rot) % 4]; } else { dirname = direction_name[(4 - rot) % 4]; } } else if (k.y > un_gr || (inside && k.y*3 > (un_gr+un_gr+ob_gr)) ) { if (k.x < li_gr) { dirname = diagonal_name[(3 - rot) % 4]; } else if (k.x > re_gr) { dirname = diagonal_name[(6 - rot) % 4]; } else { dirname = direction_name[(6 - rot) % 4]; } } else { if (k.x <= stadt->get_pos().x) { dirname = direction_name[(3 - rot) % 4]; } else { dirname = direction_name[(5 - rot) % 4]; } } dirname = translator::translate(dirname,lang); // Try everything to get a unique name while(true) { // well now try them all from "0..." over "9..." to "A..." to "Z..." for( int i=0; i<10+26; i++ ) { numbername[0] = i<10 ? '0'+i : 'A'+i-10; const char *base_name = translator::translate(numbername,lang); if(base_name==numbername) { // not translated ... try next continue; } // allow for names without direction uint8 count_s = count_printf_param( base_name ); if(count_s==3) { if (cbuffer_t::check_and_repair_format_strings("%s %s %s", base_name) ) { // ok, try this name, if free ... buf.printf( base_name, city_name, dirname, stop ); } } else { if (cbuffer_t::check_and_repair_format_strings("%s %s", base_name) ) { // ok, try this name, if free ... buf.printf( base_name, city_name, stop ); } } if( buf.len()>0 && !all_names.get(buf).is_bound() ) { return strdup(buf); } buf.clear(); } // here we did not find a suitable name ... // ok, no suitable city names, try the suburb ones ... if( strcmp(numbername+1,"center")==0 ) { strcpy( numbername, "0suburb" ); } // ok, no suitable suburb names, try the external ones (if not inside city) ... else if( strcmp(numbername+1,"suburb")==0 && !inside ) { strcpy( numbername, "0extern" ); } else { // no suitable unique name found at all ... break; } } } /* so far we did not found a matching station name * as a last resort, we will try numbered names * (or the user requested this anyway) */ // strings for intown / outside of town const char *base_name = translator::translate( inside ? "%s city %d %s" : "%s land %d %s", lang); // finally: is there a stop with this name already? for( uint32 i=1; i<65536; i++ ) { buf.printf( base_name, city_name, i, stop ); if( !all_names.get(buf).is_bound() ) { return strdup(buf); } buf.clear(); } // emergency measure: But before we should run out of handles anyway ... assert(0); return strdup("Unnamed"); } // add convoi to loading void haltestelle_t::request_loading( convoihandle_t cnv ) { loading_here.append_unique( cnv ); if( last_loading_step != welt->get_steps() ) { last_loading_step = welt->get_steps(); // now iterate over all convois for (uint32 i = 0; iget_state() == convoi_t::LOADING) { // now we load into convoi c->hat_gehalten(self); } if (c.is_bound() && c->get_state() == convoi_t::LOADING) { ++i; } else { loading_here.remove_at(i); } } } } bool haltestelle_t::has_available_network(const player_t* player, uint8 catg_index) const { if(!player_t::check_owner( player, owner )) { return false; } if( catg_index != goods_manager_t::INDEX_NONE && !is_enabled(catg_index) ) { return false; } // Check if there is a player's line for(linehandle_t const l : registered_lines) { if( l->get_owner() == player && l->count_convoys()>0 ) { if( catg_index == goods_manager_t::INDEX_NONE ) { return true; } else if( l->get_goods_catg_index().is_contained(catg_index)) { return true; } } } // Check lineless convoys for(convoihandle_t cnv : registered_convoys ) { if( cnv->get_owner() == player && cnv->get_state() != convoi_t::INITIAL ) { if( catg_index == goods_manager_t::INDEX_NONE ) { return true; } else if( cnv->get_goods_catg_index().is_contained(catg_index) ) { return true; } } }; return false; } // steps is currently only called during reconnectiong and reoruting // any change need to change step_all() bool haltestelle_t::step(uint8 what, sint16 &units_remaining) { switch(what) { case RECONNECTING: units_remaining -= (rebuild_connections()/256)+2; break; case REROUTING: reroute_goods(units_remaining); recalc_status(); break; default: dbg->fatal("haltestelle_t::step()","Unknown step mode %i",what); break; } return true; } /** * Called every month */ void haltestelle_t::new_month() { if( welt->get_active_player()==owner && status_color==color_idx_to_rgb(COL_RED) ) { cbuffer_t buf; buf.printf( translator::translate("%s\nis crowded."), get_name() ); welt->get_message()->add_message(buf, get_basis_pos3d(),message_t::full|message_t::EXPIRE_AFTER_ONE_MONTH_MSG, PLAYER_FLAG|owner->get_player_nr(), IMG_EMPTY ); enables &= (PAX|POST|WARE); } // roll financial history for (int j = 0; j0; k--) { financial_history[k][j] = financial_history[k-1][j]; } financial_history[0][j] = 0; } // number of waiting should be constant ... financial_history[0][HALT_WAITING] = financial_history[1][HALT_WAITING]; } /** * Called after schedule calculation of all stations is finished * will distribute the goods to changed routes (if there are any) */ void haltestelle_t::reroute_goods(sint16 &units_remaining) { if( last_catg_index==255 ) { last_catg_index = 0; } for( ; last_catg_index * warray = cargo[last_catg_index]; vector_tpl * new_warray = new vector_tpl(warray->get_count()); for (size_t j = warray->get_count(); j-- != 0;) { ware_t & ware = (*warray)[j]; if(ware.amount==0) { continue; } // since also the factory halt list is added to the ground, we can use just this ... if( welt->access(ware.get_target_pos())->is_connected(self) ) { // we are already there! if( ware.to_factory ) { liefere_an_fabrik(ware); } continue; } // add to new array new_warray->append( ware ); } // delete, if nothing connects here if( new_warray->empty() ) { if( all_links[last_catg_index].connections.empty() ) { // no connections from here => delete delete new_warray; new_warray = NULL; } } // replace the array delete cargo[last_catg_index]; cargo[last_catg_index] = new_warray; // if something left // re-route goods to adapt to changes in world layout, // remove all goods whose destination was removed from the map if (cargo[last_catg_index] && !cargo[last_catg_index]->empty()) { vector_tpl &warray = *cargo[last_catg_index]; uint32 last_goods_index = 0; units_remaining -= warray.get_count(); while( last_goods_indexget_desc()->get_placement() != factory_desc_t::Water || (station_type & dock) > 0 ) { // do no link to oil rigs via stations ... fab_list.insert(fab); return true; } } return false; } void haltestelle_t::verbinde_fabriken() { // unlink all for(fabrik_t* const f : fab_list) { f->unlink_halt(self); } fab_list.clear(); // then reconnect for(tile_t const& i : tiles) { koord const p = i.grund->get_pos().get_2d(); uint16 const cov = welt->get_settings().get_station_coverage(); for(fabrik_t* const fab : fabrik_t::sind_da_welche(p - koord(cov, cov), p + koord(cov, cov))) { if (connect_factory(fab)) { // also connect the factory to this halt fab->link_halt(self); } } } } /* * removes factory to a halt */ void haltestelle_t::remove_fabriken(fabrik_t *fab) { fab_list.remove(fab); } /** * Rebuilds the list of connections to directly reachable halts * Returns the number of stops considered */ #define WEIGHT_WAIT (8) #define WEIGHT_HALT (1) // the minimum weight of a connection from a transfer halt #define WEIGHT_MIN (WEIGHT_WAIT+WEIGHT_HALT) sint32 haltestelle_t::rebuild_connections() { // halts which either immediately precede or succeed self halt in serving schedules static vector_tpl consecutive_halts[256]; // halts which either immediately precede or succeed self halt in currently processed schedule static vector_tpl consecutive_halts_schedule[256]; // remember max number of consecutive halts for one schedule uint8 max_consecutive_halts_schedule[256]; MEMZERON(max_consecutive_halts_schedule, goods_manager_t::get_max_catg_index()); // previous halt supporting the ware categories of the serving line static halthandle_t previous_halt[256]; // first, remove all old entries for( uint8 i=0; i *goods_catg_index; minivec_tpl supported_catg_index(32); /* * In the first loops: * lines==true => search for lines * After this: * lines==false => search for single convoys without lines */ bool lines = true; uint32 current_index = 0; while( lines || current_index < registered_convoys.get_count() ) { // Now, collect the "schedule", "owner" and "add_catg_index" from line resp. convoy. if( lines ) { if( current_index >= registered_lines.get_count() ) { // We have looped over all lines. lines = false; current_index = 0; // start over for registered lineless convoys continue; } const linehandle_t line = registered_lines[current_index]; ++current_index; owner = line->get_owner(); schedule = line->get_schedule(); goods_catg_index = &line->get_goods_catg_index(); } else { const convoihandle_t cnv = registered_convoys[current_index]; ++current_index; owner = cnv->get_owner(); schedule = cnv->get_schedule(); goods_catg_index = &cnv->get_goods_catg_index(); } // find the index from which to start processing uint8 start_index = 0; while( start_index < schedule->get_count() && get_halt( schedule->entries[start_index].pos, owner ) != self ) { ++start_index; } ++start_index; // the next index after self halt; it's okay to be out-of-range // determine goods category indices supported by this halt supported_catg_index.clear(); for(uint8 const catg_index : *goods_catg_index) { if( is_enabled(catg_index) ) { supported_catg_index.append(catg_index); previous_halt[catg_index] = self; consecutive_halts_schedule[catg_index].clear(); } } if( supported_catg_index.empty() ) { // this halt does not support the goods categories handled by the line/lineless convoy continue; } INT_CHECK("simhalt.cc 612"); // now we add the schedule to the connection array uint16 aggregate_weight = WEIGHT_WAIT; for( uint8 j=0; jget_count(); ++j ) { halthandle_t current_halt = get_halt(schedule->entries[(start_index+j)%schedule->get_count()].pos, owner ); if( !current_halt.is_bound() ) { // ignore way points continue; } if( current_halt == self ) { // check for consecutive halts which precede self halt for(uint8 const catg_index : supported_catg_index) { if( previous_halt[catg_index]!=self ) { consecutive_halts[catg_index].append_unique(previous_halt[catg_index]); consecutive_halts_schedule[catg_index].append_unique(previous_halt[catg_index]); previous_halt[catg_index] = self; } } // reset aggregate weight aggregate_weight = WEIGHT_WAIT; continue; } aggregate_weight += WEIGHT_HALT; for(uint8 const catg_index : supported_catg_index) { if( current_halt->is_enabled(catg_index) ) { // check for consecutive halts which succeed self halt if( previous_halt[catg_index] == self ) { consecutive_halts[catg_index].append_unique(current_halt); consecutive_halts_schedule[catg_index].append_unique(current_halt); } previous_halt[catg_index] = current_halt; // either add a new connection or update the weight of an existing connection where necessary connection_t *const existing_connection = all_links[catg_index].connections.insert_unique_ordered( connection_t( current_halt, aggregate_weight ), connection_t::compare ); if( existing_connection && aggregate_weightweight ) { existing_connection->weight = aggregate_weight; } } } } for(uint8 const catg_index : supported_catg_index) { if( consecutive_halts_schedule[catg_index].get_count() > max_consecutive_halts_schedule[catg_index] ) { max_consecutive_halts_schedule[catg_index] = consecutive_halts_schedule[catg_index].get_count(); } } connections_searched += schedule->get_count(); } for( uint8 i=0; i this is not transfer halt } else { all_links[i].is_transfer = true; } } } return connections_searched; } void haltestelle_t::rebuild_linked_connections() { vector_tpl all; // all halts connected to this halt for( uint8 i=0; i& connections = all_links[i].connections; for(connection_t &c : connections) { all.append_unique( c.halt ); } } for(halthandle_t h : all) { h->rebuild_connections(); } } void haltestelle_t::fill_connected_component(uint8 catg_idx, uint16 comp) { if (all_links[catg_idx].catg_connected_component != UNDECIDED_CONNECTED_COMPONENT) { // already connected return; } all_links[catg_idx].catg_connected_component = comp; for(connection_t &c : all_links[catg_idx].connections) { if (c.halt.is_bound()) { c.halt->fill_connected_component(catg_idx, comp); // cache the is_transfer value c.is_transfer = c.halt->is_transfer(catg_idx); } } } void haltestelle_t::rebuild_connected_components() { for(uint8 catg_idx = 0; catg_idxall_links[catg_idx].catg_connected_component == UNDECIDED_CONNECTED_COMPONENT) { // start recursion halt->fill_connected_component(catg_idx, halt.get_id()); } } } } sint8 haltestelle_t::is_connected(halthandle_t halt, uint8 catg_index) const { if (!halt.is_bound()) { return 0; // not connected } if (halt == self) { return 1; } const link_t& linka = all_links[catg_index]; const link_t& linkb = halt->all_links[catg_index]; if (linka.connections.empty() || linkb.connections.empty()) { return 0; // empty connections -> not connected } if (linka.catg_connected_component == UNDECIDED_CONNECTED_COMPONENT || linkb.catg_connected_component == UNDECIDED_CONNECTED_COMPONENT) { return -1; // undecided - try later } // now check whether both halts are in the same component return linka.catg_connected_component == linkb.catg_connected_component ? 1 : 0; } /** * Helper class that combines a vector_tpl * with WEIGHT_HEAP elements and a binary_heap_tpl. * If inserted node has weight less than WEIGHT_HEAP, * then node is inserted in one of the vectors. * If weight is larger, then node goes into the heap. * * WEIGHT_HEAP = 200 should be safe for even the largest games. */ template class bucket_heap_tpl { #define WEIGHT_HEAP (200) vector_tpl *buckets; ///< array of vectors binary_heap_tpl heap; ///< the heap uint16 min_weight; ///< current min_weight of nodes in the buckets uint32 node_count; ///< total count of nodes public: bucket_heap_tpl() : heap(128) { min_weight = WEIGHT_HEAP; node_count = 0; buckets = new vector_tpl [WEIGHT_HEAP]; } ~bucket_heap_tpl() { delete [] buckets; } void insert(const T item) { node_count++; uint16 weight = *item; if (weight < WEIGHT_HEAP) { if (weight < min_weight) { min_weight = weight; } buckets[weight].append(item); } else { heap.insert(item); } } T pop() { assert(!empty()); node_count--; if (min_weight < WEIGHT_HEAP) { T ret = buckets[min_weight].pop_back(); while(min_weight < WEIGHT_HEAP && buckets[min_weight].empty()) { min_weight++; } return ret; } else { return heap.pop(); } } void clear() { for(uint16 i=min_weight; i haltestelle_t::open_list; uint8 haltestelle_t::markers[65536]; uint8 haltestelle_t::current_marker = 0; /** * Data for resumable route search */ halthandle_t haltestelle_t::last_search_origin; uint8 haltestelle_t::last_search_ware_catg_idx = 255; /** * This routine tries to find a route for a good packet (ware) * it will be called for * - new goods (either from simcity.cc or simfab.cc) * - goods that transfer and cannot be joined with other goods * - during re-routing * Therefore this routine eats up most of the performance in * later games. So all changes should be done with this in mind! * * If no route is found, ziel and zwischenziel are unbound handles. * If next_to_ziel in not NULL, it will get the koordinate of the stop * previous to target. Can be used to create passengers/mail back the * same route back * * if USE_ROUTE_SLIST_TPL is defined, the list template will be used. * However, this is about 50% slower. * * @param start_halts * @param start_halt_count * @param no_routing_over_overcrowding * @param return_ware * @param[out] ware */ int haltestelle_t::search_route( const halthandle_t *const start_halts, const uint16 start_halt_count, const bool no_routing_over_overcrowding, ware_t &ware, ware_t *const return_ware ) { const uint8 ware_catg_idx = ware.get_desc()->get_catg_index(); const uint8 ware_idx = ware.get_desc()->get_index(); // since also the factory halt list is added to the ground, we can use just this ... const planquadrat_t *const plan = welt->access( ware.get_target_pos() ); const halthandle_t *const halt_list = plan->get_haltlist(); // but we can only use a subset of these static vector_tpl end_halts(16); end_halts.clear(); // target halts are in these connected components // we start from halts only in the same components static vector_tpl end_conn_comp(16); end_conn_comp.clear(); // if one target halt is undefined, we have to start search from all halts bool end_conn_comp_undefined = false; for( uint32 h=0; hget_haltlist_count(); ++h ) { halthandle_t halt = halt_list[h]; if( halt.is_bound() && halt->is_enabled(ware_catg_idx) ) { // check if this is present in the list of start halts for( uint16 s=0; s within walking distance ware.set_target_halt( start_halts[s] ); ware.set_via_halt( halthandle_t() ); if( return_ware ) { return_ware->set_target_halt( start_halts[s] ); return_ware->set_via_halt( halthandle_t() ); } return ROUTE_WALK; } } end_halts.append(halt); // check connected component of target halt uint16 endhalt_conn_comp = halt->all_links[ware_catg_idx].catg_connected_component; if (endhalt_conn_comp == UNDECIDED_CONNECTED_COMPONENT) { // undefined: all start halts are probably connected to this target end_conn_comp_undefined = true; } else { // store connected component if (!end_conn_comp_undefined) { end_conn_comp.append_unique( endhalt_conn_comp ); } } } } if( end_halts.empty() ) { // no end halt found ware.set_target_halt( halthandle_t() ); ware.set_via_halt( halthandle_t() ); if( return_ware ) { return_ware->set_target_halt( halthandle_t() ); return_ware->set_via_halt( halthandle_t() ); } return NO_ROUTE; } // invalidate search history last_search_origin = halthandle_t(); // set current marker ++current_marker; if( current_marker==0 ) { MEMZERON(markers, halthandle_t::get_size()); current_marker = 1u; } // initialisations for end halts => save some checking inside search loop for(halthandle_t const e : end_halts) { uint16 const halt_id = e.get_id(); halt_data[ halt_id ].best_weight = 65535u; halt_data[ halt_id ].destination = 1u; halt_data[ halt_id ].depth = 1u; // to distinct them from start halts markers[ halt_id ] = current_marker; } uint16 const max_transfers = welt->get_settings().get_max_transfers(); uint16 const max_hops = welt->get_settings().get_max_hops(); uint16 allocation_pointer = 0; uint16 best_destination_weight = 65535u; // best weight among all destinations open_list.clear(); uint32 overcrowded_nodes = 0; // initialise the origin node(s) for( ; allocation_pointerall_links[ware_catg_idx].catg_connected_component; if (!end_conn_comp_undefined && start_conn_comp != UNDECIDED_CONNECTED_COMPONENT && !end_conn_comp.is_contained( start_conn_comp )){ // this start halt will not lead to any target continue; } open_list.insert( route_node_t(start_halt, 0) ); halt_data_t & start_data = halt_data[ start_halt.get_id() ]; start_data.best_weight = 65535u; start_data.destination = 0; start_data.depth = 0; start_data.overcrowded = false; // start halt overcrowding is handled by routines calling this one start_data.transfer = halthandle_t(); markers[ start_halt.get_id() ] = current_marker; } // here the normal routing with overcrowded stops is done while (!open_list.empty()) { if( overcrowded_nodes == open_list.get_count() ) { // all unexplored routes go over overcrowded stations return ROUTE_OVERCROWDED; } // take node out of open list route_node_t current_node = open_list.pop(); // do not use aggregate_weight as it is _not_ the weight of the current_node // there might be a heuristic weight added const uint16 current_halt_id = current_node.halt.get_id(); halt_data_t & current_halt_data = halt_data[ current_halt_id ]; overcrowded_nodes -= current_halt_data.overcrowded; if( current_halt_data.destination ) { // destination found ware.set_target_halt( current_node.halt ); assert(current_halt_data.transfer.get_id() != 0); if( return_ware ) { // next transfer for the reverse route // if the end halt and its connections contain more than one transfer halt then // the transfer halt may not be the last transfer of the forward route // (the re-routing will happen in haltestelle_t::fetch_goods) return_ware->set_via_halt(current_halt_data.transfer); // count the connected transfer halts (including end halt) uint8 t = current_node.halt->is_transfer(ware_catg_idx); for(connection_t const& i : current_node.halt->all_links[ware_catg_idx].connections) { if (t > 1) { break; } t += i.halt.is_bound() && i.is_transfer; } return_ware->set_via_halt( t<=1 ? current_halt_data.transfer : halthandle_t()); } // find the next transfer halthandle_t transfer_halt = current_node.halt; while( halt_data[ transfer_halt.get_id() ].depth > 1 ) { transfer_halt = halt_data[ transfer_halt.get_id() ].transfer; } ware.set_via_halt(transfer_halt); if( return_ware ) { // return ware's destination halt is the start halt of the forward trip assert( halt_data[ transfer_halt.get_id() ].transfer.get_id() ); return_ware->set_target_halt( halt_data[ transfer_halt.get_id() ].transfer ); } return current_halt_data.overcrowded ? ROUTE_OVERCROWDED : ROUTE_OK; } // check if the current halt is already in closed list if( current_halt_data.best_weight==0 ) { // shortest path to the current halt has already been found earlier continue; } if( current_halt_data.depth > max_transfers ) { // maximum transfer limit is reached -> do not add reachable halts to open list continue; } for(connection_t const& current_conn : current_node.halt->all_links[ware_catg_idx].connections) { // halt may have been deleted or joined => test if still valid if( !current_conn.halt.is_bound() ) { // removal seems better though ... continue; } // since these are pre-calculated, they should be always pointing to a valid ground // (if not, we were just under construction, and will be fine after 16 steps) const uint16 reachable_halt_id = current_conn.halt.get_id(); if( markers[ reachable_halt_id ]!=current_marker ) { // Case : not processed before // indicate that this halt has been processed markers[ reachable_halt_id ] = current_marker; if( current_conn.halt.is_bound() && current_conn.is_transfer && allocation_pointeris_overcrowded( ware_idx ) ); halt_data[ reachable_halt_id ].best_weight = total_weight; halt_data[ reachable_halt_id ].destination = 0; halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u; halt_data[ reachable_halt_id ].transfer = current_node.halt; halt_data[ reachable_halt_id ].overcrowded = overcrowded_transfer; overcrowded_nodes += overcrowded_transfer; allocation_pointer++; // as the next halt is not a destination add WEIGHT_MIN open_list.insert( route_node_t(current_conn.halt, total_weight + WEIGHT_MIN) ); } else { // Case: non-optimal transfer halt -> put in closed list halt_data[ reachable_halt_id ].best_weight = 0; } } else { // Case: halt is removed / no transfer halt -> put in closed list halt_data[ reachable_halt_id ].best_weight = 0; } } // if not processed before else if( halt_data[ reachable_halt_id ].best_weight!=0 && halt_data[ reachable_halt_id ].depth>0) { // Case : processed before but not in closed list : that is, in open list // --> can only be destination halt or transfer halt // or start halt (filter the latter out with the condition depth>0) uint16 total_weight = current_halt_data.best_weight + current_conn.weight; if( total_weight create new node and update halt data const bool overcrowded_transfer = no_routing_over_overcrowding && ( current_halt_data.overcrowded || ( !halt_data[reachable_halt_id].destination && current_conn.halt->is_overcrowded( ware_idx ) ) ); halt_data[ reachable_halt_id ].best_weight = total_weight; // no need to update destination, as halt nature (as destination or transfer) will not change halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u; halt_data[ reachable_halt_id ].transfer = current_node.halt; halt_data[ reachable_halt_id ].overcrowded = overcrowded_transfer; overcrowded_nodes += overcrowded_transfer; if( halt_data[reachable_halt_id].destination ) { best_destination_weight = total_weight; } else { // as the next halt is not a destination add WEIGHT_MIN total_weight += WEIGHT_MIN; } allocation_pointer++; open_list.insert( route_node_t(current_conn.halt, total_weight) ); } } // else if not in closed list } // for each connection entry // indicate that the current halt is in closed list current_halt_data.best_weight = 0; } // if the loop ends, nothing was found ware.set_target_halt( halthandle_t() ); ware.set_via_halt( halthandle_t() ); if( return_ware ) { return_ware->set_target_halt( halthandle_t() ); return_ware->set_via_halt( halthandle_t() ); } return NO_ROUTE; } void haltestelle_t::search_route_resumable( ware_t &ware ) { const uint8 ware_catg_idx = ware.get_desc()->get_catg_index(); // continue search if start halt and good category did not change const bool resume_search = last_search_origin == self && ware_catg_idx == last_search_ware_catg_idx; if (!resume_search) { last_search_origin = self; last_search_ware_catg_idx = ware_catg_idx; open_list.clear(); // set current marker ++current_marker; if( current_marker==0 ) { MEMZERON(markers, halthandle_t::get_size()); current_marker = 1u; } } // remember destination nodes, to reset them before returning static vector_tpl dest_indices(16); dest_indices.clear(); uint16 best_destination_weight = 65535u; // reset next transfer and destination halt to null -> if they remain null after search, no route can be found ware.set_target_halt( halthandle_t() ); ware.set_via_halt( halthandle_t() ); // find suitable destination halts for the ware packet's target position const planquadrat_t *const plan = welt->access( ware.get_target_pos() ); const halthandle_t *const halt_list = plan->get_haltlist(); // check halt list for presence of current halt for( uint8 h = 0; hget_haltlist_count(); ++h ) { if (halt_list[h] == self) { // a destination halt is the same as the current halt -> no route searching is necessary ware.set_target_halt( self ); return; } } // check explored connection if (resume_search) { for( uint8 h=0; hget_haltlist_count(); ++h ) { const halthandle_t halt = halt_list[h]; if (markers[ halt.get_id() ]==current_marker && halt_data[ halt.get_id() ].best_weight < best_destination_weight && halt.is_bound()) { best_destination_weight = halt_data[ halt.get_id() ].best_weight; ware.set_target_halt( halt ); ware.set_via_halt( halt_data[ halt.get_id() ].transfer ); } } // for all halts with halt_data.weight < explored_weight one of the best routes is found const uint16 explored_weight = open_list.empty() ? 65535u : open_list.front().aggregate_weight; if (best_destination_weight <= explored_weight && best_destination_weight < 65535u) { // we explored best route to this destination in last run // (any other not yet explored connection will have larger weight) // no need to search route for this ware return; } } // we start in this connected component uint16 const conn_comp = all_links[ ware_catg_idx ].catg_connected_component; // find suitable destination halt(s), if any for( uint8 h=0; hget_haltlist_count(); ++h ) { const halthandle_t halt = halt_list[h]; if( halt.is_bound() && halt->is_enabled(ware_catg_idx) ) { // test for connected component uint16 const dest_comp = halt->all_links[ ware_catg_idx ].catg_connected_component; if (dest_comp != UNDECIDED_CONNECTED_COMPONENT && conn_comp != UNDECIDED_CONNECTED_COMPONENT && conn_comp != dest_comp) { continue; } // initialisations for destination halts => save some checking inside search loop if( markers[ halt.get_id() ]!=current_marker ) { // first time -> initialise marker and all halt data markers[ halt.get_id() ] = current_marker; halt_data[ halt.get_id() ].best_weight = 65535u; halt_data[ halt.get_id() ].destination = true; } else { // initialised before -> only update destination bit set halt_data[ halt.get_id() ].destination = true; } dest_indices.append(halt.get_id()); } } if( dest_indices.empty() ) { // no destination halt found or current halt is the same as (all) the destination halt(s) return; } uint16 const max_transfers = welt->get_settings().get_max_transfers(); uint16 const max_hops = welt->get_settings().get_max_hops(); static uint16 allocation_pointer; if (!resume_search) { // initialise the origin node allocation_pointer = 1u; open_list.insert( route_node_t(self, 0) ); halt_data_t & start_data = halt_data[ self.get_id() ]; start_data.best_weight = 0; start_data.destination = 0; start_data.depth = 0; start_data.transfer = halthandle_t(); markers[ self.get_id() ] = current_marker; } while( !open_list.empty() ) { if (best_destination_weight <= open_list.front().aggregate_weight) { // best route to destination found already break; } route_node_t current_node = open_list.pop(); const uint16 current_halt_id = current_node.halt.get_id(); const uint16 current_weight = current_node.aggregate_weight; halt_data_t & current_halt_data = halt_data[ current_halt_id ]; // check if the current halt is already in closed list (or removed) if( !current_node.halt.is_bound() ) { continue; } else if( current_halt_data.best_weight < current_weight) { // shortest path to the current halt has already been found earlier // assert(markers[ current_halt_id ]==current_marker); continue; } else { // no need to update weight, as it is already the right one // assert(current_halt_data.best_weight == current_weight); } if( current_halt_data.destination ) { // destination found ware.set_target_halt( current_node.halt ); ware.set_via_halt( current_halt_data.transfer ); // update best_destination_weight to leave loop due to first check above best_destination_weight = current_weight; // if this destination halt is not a transfer halt -> do not proceed to process its reachable halt(s) if( !current_node.halt->is_transfer(ware_catg_idx) ) { continue; } } // not start halt, not transfer halt -> do not expand further if( current_halt_data.depth > 0 && !current_node.halt->is_transfer(ware_catg_idx) ) { continue; } if( current_halt_data.depth > max_transfers ) { // maximum transfer limit is reached -> do not add reachable halts to open list continue; } for(connection_t const& current_conn : current_node.halt->all_links[ware_catg_idx].connections) { const uint16 reachable_halt_id = current_conn.halt.get_id(); const uint16 total_weight = current_weight + current_conn.weight; if( !current_conn.halt.is_bound() ) { // Case: halt removed -> make sure we never visit it again markers[ reachable_halt_id ] = current_marker; halt_data[ reachable_halt_id ].best_weight = 0; } else if( markers[ reachable_halt_id ]!=current_marker ) { // Case : not processed before and not destination // indicate that this halt has been processed markers[ reachable_halt_id ] = current_marker; // update data halt_data[ reachable_halt_id ].best_weight = total_weight; halt_data[ reachable_halt_id ].destination = false; // reset necessary if this was set by search_route halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u; halt_data[ reachable_halt_id ].transfer = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt; if( current_conn.is_transfer && allocation_pointer need to check whether we can reach it with smaller weight if( total_weight update halt data halt_data[ reachable_halt_id ].best_weight = total_weight; halt_data[ reachable_halt_id ].transfer = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt; // for transfer/destination nodes create new node if ( (halt_data[ reachable_halt_id ].destination || current_conn.is_transfer ) && allocation_pointer reset marker --markers[i]; } } } /** * Found route and station uncrowded */ void haltestelle_t::add_pax_happy(int n) { book(n, HALT_HAPPY); recalc_status(); } /** * Station in walking distance */ void haltestelle_t::add_pax_walked(int n) { book(n, HALT_WALKED); } /** * Station crowded */ void haltestelle_t::add_pax_unhappy(int n) { book(n, HALT_UNHAPPY); recalc_status(); } /** * Found no route */ void haltestelle_t::add_pax_no_route(int n) { book(n, HALT_NOROUTE); } void haltestelle_t::liefere_an_fabrik(const ware_t& ware) const { fabrik_t *const factory = fabrik_t::get_fab(ware.get_target_pos() ); if( factory ) { factory->liefere_an(ware.get_desc(), ware.amount); } } /* retrieves a ware packet for any destination in the list * needed, if the factory in question wants to remove something */ bool haltestelle_t::recall_ware( ware_t& w, uint32 menge ) { w.amount = 0; vector_tpl *warray = cargo[w.get_desc()->get_catg_index()]; if(warray!=NULL) { for(ware_t & tmp : *warray) { // skip empty entries if(tmp.amount==0 || w.get_index()!=tmp.get_index() || w.get_target_pos()!=tmp.get_target_pos()) { continue; } // not too much? if(tmp.amount > menge) { // not all can be loaded tmp.amount -= menge; w.amount = menge; } else { // leave an empty entry => joining will more often work w.amount = tmp.amount; tmp.amount = 0; } book(w.amount, HALT_ARRIVED); fabrik_t::update_transit( &w, false ); resort_freight_info = true; return true; } } // nothing to take out return false; } void haltestelle_t::fetch_goods( slist_tpl &load, const goods_desc_t *good_category, uint32 requested_amount, const vector_tpl& destination_halts) { // first iterate over the next stop, then over the ware // might be a little slower, but ensures that passengers to nearest stop are served first // this allows for separate high speed and normal service vector_tpl *warray = cargo[good_category->get_catg_index()]; if( warray && !warray->empty() ) { for( uint32 i=0; i < destination_halts.get_count(); i++ ) { halthandle_t plan_halt = destination_halts[i]; // mark this stop as served, even if I do not load to avoid stealing transfer freight by later processed convois halt_served_this_step[good_category->get_catg_index()].append_unique(plan_halt); // The random offset will ensure that all goods have an equal chance to be loaded. uint32 offset = simrand(warray->get_count()); for( uint32 i=0; iget_count(); i++ ) { ware_t &tmp = (*warray)[ i+offset ]; // prevent overflow (faster than division) if( i+offset+1>=warray->get_count() ) { offset -= warray->get_count(); } // skip empty entries if(tmp.amount==0) { continue; } // goods without route -> returning passengers/mail if( !tmp.get_via_halt().is_bound() ) { search_route_resumable(tmp); if (!tmp.get_target_halt().is_bound()) { // no route anymore tmp.amount = 0; continue; } } // compatible car and right target stop? if( tmp.get_via_halt()==plan_halt ) { if( plan_halt->is_overcrowded( tmp.get_index() ) ) { if (welt->get_settings().is_avoid_overcrowding() && tmp.get_target_halt() != plan_halt) { // do not go for transfer to overcrowded transfer stop continue; } } // not too much? ware_t neu(tmp); if( tmp.amount > requested_amount ) { // not all can be loaded neu.amount = requested_amount; tmp.amount -= requested_amount; requested_amount = 0; } else { requested_amount -= tmp.amount; // leave an empty entry => joining will more often work tmp.amount = 0; } load.insert(neu); book(neu.amount, HALT_DEPARTED); resort_freight_info = true; if (requested_amount==0) { return; } } } // nothing there to load } } } uint32 haltestelle_t::get_ware_summe(const goods_desc_t *wtyp) const { int sum = 0; const vector_tpl * warray = cargo[wtyp->get_catg_index()]; if(warray!=NULL) { for(ware_t const& i : *warray) { if (wtyp->get_index() == i.get_index()) { sum += i.amount; } } } return sum; } uint32 haltestelle_t::get_ware_fuer_zielpos(const goods_desc_t *wtyp, const koord zielpos) const { const vector_tpl * warray = cargo[wtyp->get_catg_index()]; if(warray!=NULL) { for(ware_t const& ware : *warray) { if(wtyp->get_index()==ware.get_index() && ware.get_target_pos()==zielpos) { return ware.amount; } } } return 0; } uint32 haltestelle_t::get_ware_fuer_zwischenziel(const goods_desc_t *wtyp, const halthandle_t zwischenziel) const { uint32 sum = 0; const vector_tpl * warray = cargo[wtyp->get_catg_index()]; if(warray!=NULL) { for(unsigned i=0; iget_count(); i++ ) { const ware_t &ware = (*warray)[i]; if(wtyp->get_index()==ware.get_index() && ware.get_via_halt()==zwischenziel) { sum += ware.amount; } } } return sum; } bool haltestelle_t::vereinige_waren(const ware_t &ware) { // pruefen ob die ware mit bereits wartender ware vereinigt werden kann vector_tpl * warray = cargo[ware.get_desc()->get_catg_index()]; if(warray!=NULL) { for(ware_t & tmp : *warray) { // join packets with same destination if(ware.same_destination(tmp)) { if( ware.get_via_halt().is_bound() && ware.get_via_halt()!=self ) { // update route if there is newer route tmp.set_via_halt( ware.get_via_halt() ); } tmp.amount += ware.amount; resort_freight_info = true; return true; } } } return false; } // put the ware into the internal storage // take care of all allocation necessary void haltestelle_t::add_ware_to_halt(ware_t ware) { // now we have to add the ware to the stop vector_tpl * warray = cargo[ware.get_desc()->get_catg_index()]; if(warray==NULL) { // this type was not stored here before ... warray = new vector_tpl(4); cargo[ware.get_desc()->get_catg_index()] = warray; } // the ware will be put into the first entry with menge==0 resort_freight_info = true; for(ware_t & i : *warray) { if (i.amount == 0) { i = ware; return; } } // here, if no free entries found warray->append(ware); } /* same as liefere an, but there will be no route calculated, * since it hase be calculated just before * (execption: route contains us as intermediate stop) */ uint32 haltestelle_t::starte_mit_route(ware_t ware) { if(ware.get_target_halt()==self) { if( ware.to_factory ) { // muss an factory geliefert werden liefere_an_fabrik(ware); } // already there: finished (may be happen with overlapping areas and returning passengers) return ware.amount; } // no valid next stops? Or we are the next stop? if(ware.get_via_halt()==self) { dbg->error("haltestelle_t::starte_mit_route()","route cannot contain us as first transfer stop => recalc route!"); if( search_route( &self, 1u, false, ware )==NO_ROUTE ) { // no route found? dbg->error("haltestelle_t::starte_mit_route()","no route found!"); return ware.amount; } } // passt das zu bereits wartender ware ? if(vereinige_waren(ware)) { // dann sind wir schon fertig; return ware.amount; } // add to internal storage add_ware_to_halt(ware); return ware.amount; } uint32 haltestelle_t::liefere_an(ware_t ware) { // no valid next stops? if(!ware.get_target_halt().is_bound() || !ware.get_via_halt().is_bound()) { // write a log entry and discard the goods dbg->warning("haltestelle_t::liefere_an()","%d %s delivered to %s have no longer a route to their destination!", ware.amount, translator::translate(ware.get_name()), get_name() ); return ware.amount; } // did we arrived? if( welt->access(ware.get_target_pos())->is_connected(self) ) { if( ware.to_factory ) { // muss an factory geliefert werden liefere_an_fabrik(ware); } else if( ware.is_passenger() ) { // arriving passenger may create pedestrians if(env_t::stop_pedestrians) { int menge = ware.amount; for(tile_t const& i : tiles ) { if (menge <= 0) { break; } if( (station_type & (loadingbay | busstop)) == 0 || i.grund->get_weg(road_wt) ) { // if the station has road tiles, then start passenger generation there to speed things up menge = pedestrian_t::generate_pedestrians_near(i.grund, menge); } } } } return ware.amount; } // do we have already something going in this direction here? if( vereinige_waren(ware) ) { return ware.amount; } // not near enough => we need to do a re-routing halthandle_t old_target = ware.get_target_halt(); search_route_resumable(ware); if (!ware.get_target_halt().is_bound()) { // target halt no longer there => delete and remove from fab in transit fabrik_t::update_transit( &ware, false ); return ware.amount; } // try to join with existing freight only if target has changed if(old_target != ware.get_target_halt() && vereinige_waren(ware)) { return ware.amount; } // add to internal storage add_ware_to_halt(ware); return ware.amount; } /** * @param[out] buf Goods description text (buf) */ void haltestelle_t::get_freight_info(cbuffer_t & buf) { if(resort_freight_info) { // resort only inf absolutely needed ... resort_freight_info = false; buf.clear(); for(unsigned i=0; i * warray = cargo[i]; if(warray) { freight_list_sorter_t::sort_freight(*warray, buf, (freight_list_sorter_t::sort_mode_t)sortierung, NULL, "waiting"); } } } } void haltestelle_t::get_short_freight_info(cbuffer_t & buf) const { bool got_one = false; for(unsigned int i=0; i0) { if(got_one) { buf.append(", "); } int max = get_capacity( i>2?2:i ); buf.printf("%d(%d)%s %s", summe, max, translator::translate(wtyp->get_mass()), translator::translate(wtyp->get_name())); got_one = true; } } } if(got_one) { buf.append(" "); buf.append(translator::translate("waiting")); buf.append("\n"); } else { buf.append(translator::translate("no goods waiting")); buf.append("\n"); } } void haltestelle_t::open_info_window() { create_win( new halt_info_t(self), w_info, magic_halt_info + self.get_id() ); } sint64 haltestelle_t::calc_maintenance() const { sint64 maintenance = 0; for(tile_t const& i : tiles ) { if( gebaeude_t* const gb = i.grund->find() ) { maintenance += welt->get_settings().maint_building * gb->get_tile()->get_desc()->get_level(); } } return maintenance; } // changes this to a public transfer exchange stop void haltestelle_t::change_owner( player_t *player ) { // check if already public if( owner == player ) { return; } // process every tile of stop slist_tpl joining; for(tile_t const& i : tiles) { grund_t* const gr = i.grund; if( gebaeude_t* gb = gr->find() ) { // change ownership player_t *gbplayer =gb->get_owner(); gb->set_owner(player); gb->set_flag(obj_t::dirty); sint64 const monthly_costs = welt->get_settings().maint_building * gb->get_tile()->get_desc()->get_level(); waytype_t const costs_type = gb->get_waytype(); player_t::add_maintenance(gbplayer, -monthly_costs, costs_type); player_t::add_maintenance(player, monthly_costs, costs_type); // cost is computed as cst_make_public_months sint64 const cost = -welt->scale_with_month_length(monthly_costs * welt->get_settings().cst_make_public_months); player_t::book_construction_costs(gbplayer, cost, get_basis_pos(), costs_type); player_t::book_construction_costs(player, -cost, koord::invalid, costs_type); } // change way ownership bool has_been_announced = false; for( int j=0; j<2; j++ ) { if( weg_t *w=gr->get_weg_nr(j) ) { // change ownership of way... player_t *wplayer = w->get_owner(); if( owner==wplayer ) { w->set_owner( player ); w->set_flag(obj_t::dirty); sint32 cost = w->get_desc()->get_maintenance(); // of tunnel... if( tunnel_t *t=gr->find() ) { t->set_owner( player ); t->set_flag(obj_t::dirty); cost = t->get_desc()->get_maintenance(); } waytype_t const financetype = w->get_desc()->get_finance_waytype(); player_t::add_maintenance( wplayer, -cost, financetype); player_t::add_maintenance( player, cost, financetype); // multiplayer notification message if( owner != welt->get_public_player() && env_t::networkmode && !has_been_announced ) { cbuffer_t buf; buf.printf( translator::translate("(%s) now public way."), w->get_pos().get_str() ); welt->get_message()->add_message( buf, w->get_pos(), message_t::ai, PLAYER_FLAG|player->get_player_nr(), IMG_EMPTY ); has_been_announced = true; // one message is enough } cost = -welt->scale_with_month_length(cost * (player==welt->get_public_player())*welt->get_settings().cst_make_public_months ); player_t::book_construction_costs(wplayer, cost, koord::invalid, financetype); } } } // make way object public if any suitable for( uint8 i = 1; i < gr->obj_count(); i++ ) { if( wayobj_t *const wo = obj_cast(gr->obj_bei(i)) ) { player_t *woplayer = wo->get_owner(); if( owner==woplayer ) { sint32 const cost = wo->get_desc()->get_maintenance(); // change ownership wo->set_owner( player ); wo->set_flag(obj_t::dirty); waytype_t const financetype = wo->get_desc()->get_waytype(); player_t::add_maintenance( woplayer, -cost, financetype); player_t::add_maintenance( player, cost, financetype); player_t::book_construction_costs( woplayer, cost, koord::invalid, financetype); } } } } // now finally change owner owner = player; rebuild_connections(); rebuild_linked_connections(); rebuild_connected_components(); // tell the world of it ... if( player == welt->get_public_player() && env_t::networkmode ) { cbuffer_t buf; buf.printf( translator::translate("%s at (%i,%i) now public stop."), get_name(), get_basis_pos().x, get_basis_pos().y ); welt->get_message()->add_message( buf, get_basis_pos3d(), message_t::ai, PLAYER_FLAG|player->get_player_nr(), IMG_EMPTY ); } } // merge stop void haltestelle_t::merge_halt( halthandle_t halt_merged ) { if( halt_merged == self || !halt_merged.is_bound() ) { return; } halt_merged->change_owner( owner ); // take the name from the larger halt if (get_capacity(0) + get_capacity(1) + get_capacity(2) < halt_merged->get_capacity(0) + halt_merged->get_capacity(1) + halt_merged->get_capacity(2)) { // the other halt was bigger => keep the old name plainstring bigger_name = halt_merged->get_name(); halt_merged->set_name(" "); set_name(bigger_name); } // add statistics for( int month=0; monthfinancial_history[month][type]; halt_merged->financial_history[month][type] = 0; } } slist_tpl tiles_to_join; for(tile_t const& i : halt_merged->get_tiles()) { tiles_to_join.append(i); } while( !tiles_to_join.empty() ) { // ATTENTION: Anz convoi reservation to this tile will be lost! grund_t *gr = tiles_to_join.remove_first().grund; // transfer tiles to us halt_merged->rem_grund(gr); add_grund(gr); } assert(!halt_merged->existiert_in_welt()); // transfer goods halt_merged->transfer_goods(self); destroy(halt_merged); recalc_basis_pos(); // also rebuild our connections recalc_station_type(); rebuild_connections(); rebuild_linked_connections(); rebuild_connected_components(); } void haltestelle_t::transfer_goods(halthandle_t halt) { if (!self.is_bound() || !halt.is_bound()) { return; } // transfer goods to halt for(uint8 i=0; i * warray = cargo[i]; if (warray) { for(ware_t const& j : *warray) { halt->add_ware_to_halt(j); } delete cargo[i]; cargo[i] = NULL; } } } // private helper function for recalc_station_type() void haltestelle_t::add_to_station_type( grund_t *gr ) { // init in any case ... if( tiles.empty() ) { capacity[0] = 0; capacity[1] = 0; capacity[2] = 0; enables = 0; station_type = invalid; } const gebaeude_t* gb = gr->find(); const building_desc_t *desc=gb?gb->get_tile()->get_desc():NULL; if( gr->is_water() && gb ) { // may happen around oil rigs and so on station_type |= dock; // for water factories if(desc) { // enabled the matching types enables |= desc->get_enabled(); if (welt->get_settings().is_separate_halt_capacities()) { if(desc->get_enabled()&1) { capacity[0] += desc->get_capacity(); } if(desc->get_enabled()&2) { capacity[1] += desc->get_capacity(); } if(desc->get_enabled()&4) { capacity[2] += desc->get_capacity(); } } else { // no separate capacities: sum up all capacity[0] += desc->get_capacity(); capacity[2] = capacity[1] = capacity[0]; } } return; } if( desc==NULL ) { // no desc, but solid ground?!? dbg->error("haltestelle_t::get_station_type()","ground belongs to halt but no desc?"); return; } // there is only one loading bay ... switch (desc->get_type()) { case building_desc_t::dock: case building_desc_t::flat_dock: station_type |= dock; break; // two ways on ground can only happen for tram tracks on streets, there buses and trams can stop case building_desc_t::generic_stop: switch (desc->get_extra()) { case road_wt: station_type |= (desc->get_enabled()&3)!=0 ? busstop : loadingbay; if (gr->has_two_ways()) { // tram track on street station_type |= tramstop; } break; case water_wt: station_type |= dock; break; case air_wt: station_type |= airstop; break; case monorail_wt: station_type |= monorailstop; break; case track_wt: station_type |= railstation; break; case tram_wt: station_type |= tramstop; if (gr->has_two_ways()) { // tram track on street station_type |= (desc->get_enabled()&3)!=0 ? busstop : loadingbay; } break; case maglev_wt: station_type |= maglevstop; break; case narrowgauge_wt: station_type |= narrowgaugestop; break; default: ; } break; default: ; } // enabled the matching types enables |= desc->get_enabled(); if (welt->get_settings().is_separate_halt_capacities()) { if(desc->get_enabled()&1) { capacity[0] += desc->get_capacity(); } if(desc->get_enabled()&2) { capacity[1] += desc->get_capacity(); } if(desc->get_enabled()&4) { capacity[2] += desc->get_capacity(); } } else { // no separate capacities: sum up all capacity[0] += desc->get_capacity(); capacity[2] = capacity[1] = capacity[0]; } } /* * recalculated the station type(s) * since it iterates over all ground, this is better not done too often, because line management and station list * queries this information regularly; Thus, we do this, when adding new ground * This recalculates also the capacity from the building levels ... */ void haltestelle_t::recalc_station_type() { capacity[0] = 0; capacity[1] = 0; capacity[2] = 0; enables = 0; station_type = invalid; // iterate over all tiles for(tile_t const& i : tiles) { grund_t* const gr = i.grund; add_to_station_type( gr ); } // and set halt info again for(tile_t const& i : tiles) { i.grund->set_halt( self ); } recalc_status(); } // necessary to load pre0.99.13 savegames void warenziel_rdwr(loadsave_t *file) { koord ziel; ziel.rdwr(file); char tn[256]; file->rdwr_str(tn, lengthof(tn)); } void haltestelle_t::rdwr(loadsave_t *file) { xml_tag_t h( file, "haltestelle_t" ); sint32 owner_n; koord3d k; // will restore halthandle_t after loading if(file->is_version_atleast(110, 6)) { if(file->is_saving()) { uint16 halt_id = self.is_bound() ? self.get_id() : 0; file->rdwr_short(halt_id); } else { uint16 halt_id; file->rdwr_short(halt_id); self.set_id(halt_id); self = halthandle_t(this, halt_id); } } else { if (file->is_loading()) { self = halthandle_t(this); } } if(file->is_saving()) { owner_n = welt->sp2num( owner ); } if(file->is_version_less(99, 8)) { init_pos.rdwr( file ); } file->rdwr_long(owner_n); if(file->is_version_less(88, 6)) { bool dummy; file->rdwr_bool(dummy); // pax file->rdwr_bool(dummy); // mail file->rdwr_bool(dummy); // ware } if(file->is_loading()) { owner = welt->get_player_or_create(owner_n); k.rdwr( file ); while(k!=koord3d::invalid) { grund_t *gr = welt->lookup(k); if(!gr) { dbg->error("haltestelle_t::rdwr()", "invalid position %s", k.get_str() ); gr = welt->lookup_kartenboden(k.get_2d()); dbg->error("haltestelle_t::rdwr()", "setting to %s", gr->get_pos().get_str() ); } // during loading and saving halts will be referred by their base position // so we may already be defined ... if(gr->get_halt().is_bound()) { dbg->warning( "haltestelle_t::rdwr()", "bound to ground twice at (%i,%i)!", k.x, k.y ); } // now check, if there is a building -> we allow no longer ground without building! const gebaeude_t* gb = gr->find(); const building_desc_t *desc=gb?gb->get_tile()->get_desc():NULL; if(desc) { add_grund( gr, false /*do not relink factories now*/ ); // verbinde_fabriken will be called in finish_rd } else { dbg->warning("haltestelle_t::rdwr()", "will no longer add ground without building at %s!", k.get_str() ); } k.rdwr( file ); } } else { for(tile_t const& i : tiles) { k = i.grund->get_pos(); k.rdwr( file ); } k = koord3d::invalid; k.rdwr( file ); } init_pos = tiles.empty() ? koord::invalid : tiles.front().grund->get_pos().get_2d(); if(file->is_saving()) { const char *s; for(unsigned i=0; i *warray = cargo[i]; if(warray) { s = "y"; // needs to be non-empty file->rdwr_str(s); if( file->is_version_less(112, 3) ) { uint16 count = warray->get_count(); file->rdwr_short(count); } else { uint32 count = warray->get_count(); file->rdwr_long(count); } for(ware_t & ware : *warray) { ware.rdwr(file); } } } s = ""; file->rdwr_str(s); } else { // restoring all goods in the station char s[256]; file->rdwr_str(s, lengthof(s)); while(*s) { uint32 count; if( file->is_version_less(112, 3) ) { uint16 scount; file->rdwr_short(scount); count = scount; } else { file->rdwr_long(count); } if(count>0) { for( uint32 i = 0; i < count; i++ ) { // add to internal storage (use this function, since the old categories were different) ware_t ware(file); if( ware.get_desc() && ware.amount>0 && welt->is_within_limits(ware.get_target_pos()) ) { add_ware_to_halt(ware); // restore in-transit information fabrik_t::update_transit( &ware, true ); } else if( ware.amount>0 ) { if( ware.get_desc() ) { dbg->error( "haltestelle_t::rdwr()", "%i of %s to %s ignored!", ware.amount, ware.get_name(), ware.get_target_pos().get_str() ); } else { dbg->error( "haltestelle_t::rdwr()", "%i of unknown to %s ignored!", ware.amount, ware.get_target_pos().get_str() ); } } } } file->rdwr_str(s, lengthof(s)); } // old games save the list with stations // however, we have to rebuilt them anyway for the new format if(file->is_version_less(99, 13)) { uint16 count; file->rdwr_short(count); for(int i=0; iis_version_atleast(111, 1) ) { for (int j = 0; jrdwr_longlong(financial_history[k][j]); } } } else { // old history did not know about walked pax for (int j = 0; j<7; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][HALT_WALKED] = 0; } } } void haltestelle_t::finish_rd() { verbinde_fabriken(); stale_convois.clear(); stale_lines.clear(); // fix good destination coordinates for(unsigned i=0; i * warray = cargo[i]; for(ware_t & j : *warray) { j.finish_rd(welt); } // merge identical entries (should only happen with old games) for(unsigned j=0; jget_count(); j++) { if( (*warray)[j].amount==0 ) { continue; } for(unsigned k=j+1; kget_count(); k++) { if( (*warray)[k].amount>0 && (*warray)[j].same_destination( (*warray)[k] ) ) { (*warray)[j].amount += (*warray)[k].amount; (*warray)[k].amount = 0; } } } } } // handle name for old stations which don't exist in kartenboden // also recover from stations without tiles (from broken savegames) grund_t* bd = welt->lookup(get_basis_pos3d()); if(bd!=NULL) { // what kind of station here? recalc_station_type(); if( !bd->get_flag(grund_t::has_text) ) { // restore label and bridges grund_t* bd_old = welt->lookup_kartenboden(get_basis_pos()); if(bd_old) { // transfer name (if there) const char *name = bd->get_text(); if(name) { set_name( name ); bd_old->set_text( NULL ); } else { set_name( "Unknown" ); } } } else { const char *current_name = bd->get_text(); if( all_names.get(current_name).is_bound() && fabrik_t::get_fab(get_basis_pos())==NULL ) { // try to get a new name ... const char *new_name; if( station_type & airstop ) { new_name = create_name( get_basis_pos(), "Airport" ); } else if( station_type & dock ) { new_name = create_name( get_basis_pos(), "Dock" ); } else if( station_type & (railstation|monorailstop|maglevstop|narrowgaugestop) ) { new_name = create_name( get_basis_pos(), "BF" ); } else { new_name = create_name( get_basis_pos(), "H" ); } dbg->warning("haltestelle_t::set_name()","name already used: \'%s\' -> \'%s\'", current_name, new_name ); bd->set_text( new_name ); current_name = new_name; } all_names.set( current_name, self ); } } recalc_status(); reconnect_counter = welt->get_schedule_counter()-1; last_search_origin = halthandle_t(); } void haltestelle_t::book(sint64 amount, int cost_type) { assert(cost_type <= MAX_HALT_COST); financial_history[0][cost_type] += amount; } void haltestelle_t::init_financial_history() { for (int j = 0; j 0 ? COL_GREEN : COL_YELLOW); // since the status is ordered ... uint8 status_bits = 0; MEMZERO(overcrowded); uint64 total_sum = 0; if(get_pax_enabled()) { const uint32 max_ware = get_capacity(0); total_sum += get_ware_summe(goods_manager_t::passengers); if(total_sum>max_ware) { overcrowded[0] |= 1; } if(get_pax_unhappy() > 40 ) { status_bits = (total_sum>max_ware+200 || (total_sum>max_ware && get_pax_unhappy()>200)) ? 2 : 1; } else if(total_sum>max_ware) { status_bits = total_sum>max_ware+200 ? 2 : 1; } } if(get_mail_enabled()) { const uint32 max_ware = get_capacity(1); const uint32 mail = get_ware_summe(goods_manager_t::mail); total_sum += mail; if(mail>max_ware) { status_bits |= mail>max_ware+200 ? 2 : 1; overcrowded[0] |= 2; } } // now for all goods if(status_color!=color_idx_to_rgb(COL_RED) && get_ware_enabled()) { const uint8 count = goods_manager_t::get_count(); const uint32 max_ware = get_capacity(2); for( uint32 i = 3; i < count; i++ ) { goods_desc_t const* const wtyp = goods_manager_t::get_info(i); const uint32 ware_sum = get_ware_summe(wtyp); total_sum += ware_sum; if(ware_sum>max_ware) { status_bits |= ware_sum > max_ware + 32 ? 2 : 1; // for now report only serious overcrowding on transfer stops overcrowded[wtyp->get_index()/8] |= 1<<(wtyp->get_index()%8); } } } // take the worst color for status if( status_bits ) { status_color = color_idx_to_rgb(status_bits&2 ? COL_RED : COL_ORANGE); } else { status_color = color_idx_to_rgb((financial_history[0][HALT_WAITING]+financial_history[0][HALT_DEPARTED] == 0) ? COL_YELLOW : COL_GREEN); } financial_history[0][HALT_WAITING] = total_sum; } /** * Draws some nice colored bars giving some status information */ void haltestelle_t::display_status(sint16 xpos, sint16 ypos) { // ignore freight that cannot reach to this station sint16 count = 0; for( uint16 i = 0; i < goods_manager_t::get_count(); i++ ) { if( i == 2 ) { continue; // ignore freight none } if( gibt_ab( goods_manager_t::get_info(i) ) ) { count++; } } ypos += -D_WAITINGBAR_WIDTH - LINESPACE/6; if( count != last_bar_count ) { // bars will shift x positions, mark entire station bar region dirty scr_coord_val max_bar_height = 0; for( sint16 i = 0; i < last_bar_count; i++ ) { if( last_bar_height[i] > max_bar_height ) { max_bar_height = last_bar_height[i]; } } const scr_coord_val x = xpos - (last_bar_count * D_WAITINGBAR_WIDTH - get_tile_raster_width()) / 2; mark_rect_dirty_wc( x - 1 - D_WAITINGBAR_WIDTH, ypos, x + last_bar_count * D_WAITINGBAR_WIDTH + 12 - 2, ypos - 11 ); // reset bar heights for new count last_bar_height.clear(); last_bar_height.reserve( count ); for( sint16 i = 0; i < count; i++ ) { last_bar_height.append(0); } last_bar_count = count; } xpos -= (count * D_WAITINGBAR_WIDTH - get_tile_raster_width()) / 2; const int x = xpos; sint16 bar_height_index = 0; uint32 max_capacity; for( uint8 i = 0; i < goods_manager_t::get_count(); i++ ) { if( i == 2 ) { continue; // ignore freight none } const goods_desc_t *wtyp = goods_manager_t::get_info(i); if( gibt_ab( wtyp ) ) { if( i < 2 ) { max_capacity = get_capacity(i); } else { max_capacity = get_capacity(2); } const uint32 sum = get_ware_summe( wtyp ); uint32 v = min( sum, max_capacity ); if( max_capacity > 512 ) { v = 2 + (v * 128) / max_capacity; } else { v = (v / 4) + 2; } display_fillbox_wh_clip_rgb( xpos, ypos - v - 1, 1, v, color_idx_to_rgb( COL_GREY4 ), false ); display_fillbox_wh_clip_rgb( xpos + 1, ypos - v - 1, D_WAITINGBAR_WIDTH - 2, v, wtyp->get_color(), false ); display_fillbox_wh_clip_rgb( xpos + D_WAITINGBAR_WIDTH - 1, ypos - v - 1, 1, v, color_idx_to_rgb( COL_GREY1 ), false ); // show up arrow for capped values if( sum > max_capacity ) { display_fillbox_wh_clip_rgb( xpos + (D_WAITINGBAR_WIDTH / 2) - 1, ypos - v - 6, 2, 4, color_idx_to_rgb( COL_WHITE ), false ); display_fillbox_wh_clip_rgb( xpos + (D_WAITINGBAR_WIDTH / 2) - 2, ypos - v - 5, 4, 1, color_idx_to_rgb( COL_WHITE ), false ); v += 5; // for marking dirty } if( last_bar_height[bar_height_index] != (scr_coord_val)v ) { if( (scr_coord_val)v > last_bar_height[bar_height_index] ) { // bar will be longer, mark new height dirty mark_rect_dirty_wc( xpos, ypos - v - 1, xpos + D_WAITINGBAR_WIDTH, ypos - 1 ); } else { // bar will be shorter, mark old height dirty mark_rect_dirty_wc( xpos, ypos - last_bar_height[ bar_height_index ] - 1, xpos + D_WAITINGBAR_WIDTH, ypos - 1 ); } last_bar_height[bar_height_index] = v; } bar_height_index++; xpos += D_WAITINGBAR_WIDTH; } } // status color box below bool dirty = false; if( get_status_farbe() != last_status_color ) { last_status_color = get_status_farbe(); dirty = true; } display_fillbox_wh_clip_rgb( x - 1 - 4, ypos, count * D_WAITINGBAR_WIDTH + 12 - 2, D_WAITINGBAR_WIDTH, get_status_farbe(), dirty ); } bool haltestelle_t::add_grund(grund_t *gr, bool relink_factories) { assert(gr!=NULL); // new halt? if( tiles.is_contained(gr) ) { return false; } koord pos = gr->get_pos().get_2d(); add_to_station_type( gr ); gr->set_halt( self ); tiles.append( gr ); // add to hashtable if (all_koords) { sint32 n = get_halt_key( gr->get_pos(), welt->get_size().y ); all_koords->set( n, self ); } // appends this to the ground // after that, the surrounding ground will know of this station bool insert_unsorted = !relink_factories; uint16 const cov = welt->get_settings().get_station_coverage(); for (int y = -cov; y <= cov; y++) { for (int x = -cov; x <= cov; x++) { koord p=pos+koord(x,y); planquadrat_t *plan = welt->access(p); if(plan) { plan->add_to_haltlist( self, insert_unsorted); plan->get_kartenboden()->set_flag(grund_t::dirty); } } } // since suddenly other factories may be connect to us too if (relink_factories) { verbinde_fabriken(); } // check if we have to register line(s) and/or lineless convoy(s) which serve this halt vector_tpl check_line(0); // public halt: must iterate over all players lines / convoys bool public_halt = get_owner() == welt->get_public_player(); uint8 const pl_min = public_halt ? 0 : get_owner()->get_player_nr(); uint8 const pl_max = public_halt ? MAX_PLAYER_COUNT : get_owner()->get_player_nr()+1; // iterate over all lines (public halt: all lines, other: only player's lines) for( uint8 i=pl_min; iget_player(i) ) { player->simlinemgmt.get_lines(simline_t::line, &check_line); for(linehandle_t const j : check_line ) { // only add unknown lines if( !registered_lines.is_contained(j) && j->count_convoys() > 0 ) { for(schedule_entry_t const& k : j->get_schedule()->entries ) { if( get_halt(k.pos, player) == self ) { registered_lines.append(j); break; } } } } } } // iterate over all convoys for(convoihandle_t const cnv : welt->convoys()) { // only check lineless convoys which have matching ownership and which are not yet registered if( !cnv->get_line().is_bound() && (public_halt || cnv->get_owner()==get_owner()) && !registered_convoys.is_contained(cnv) ) { if( const schedule_t *const schedule = cnv->get_schedule() ) { for(schedule_entry_t const& k : schedule->entries) { if (get_halt(k.pos, cnv->get_owner()) == self) { registered_convoys.append(cnv); break; } } } } } // This entire loop is just for the assertion below. // Consider deleting the assertion --neroden bool grund_is_where_it_should_be = false; const planquadrat_t* plan = welt->access(pos); for( uint8 i=0; i < plan->get_boden_count(); i++ ) { const grund_t* found_gr = plan->get_boden_bei(i); if (found_gr == gr) { grund_is_where_it_should_be = true; break; } } if ( !grund_is_where_it_should_be || gr->get_halt() != self || !gr->is_halt() ) { dbg->error( "haltestelle_t::add_grund()", "no ground added to (%s)", gr->get_pos().get_str() ); } init_pos = tiles.front().grund->get_pos().get_2d(); welt->set_schedule_counter(); return true; } bool haltestelle_t::rem_grund(grund_t *gr) { // namen merken if(!gr) { return false; } slist_tpl::iterator i = std::find(tiles.begin(), tiles.end(), gr); if (i == tiles.end()) { // was not part of station => do nothing dbg->error("haltestelle_t::rem_grund()","removed illegal ground from halt"); return false; } // first tile => remove name from this tile ... char buf[256]; const char* station_name_to_transfer = NULL; if (i == tiles.begin() && i->grund->get_name()) { tstrncpy(buf, get_name(), lengthof(buf)); station_name_to_transfer = buf; set_name(NULL); } // now remove tile from list tiles.erase(i); welt->set_schedule_counter(); init_pos = tiles.empty() ? koord::invalid : tiles.front().grund->get_pos().get_2d(); // re-add name if (station_name_to_transfer != NULL && !tiles.empty()) { label_t *lb = tiles.front().grund->find(); delete lb; // very old version had labels for names set_name( station_name_to_transfer ); } bool remove_halt = true; planquadrat_t *pl = welt->access( gr->get_pos().get_2d() ); if(pl) { // no longer present on this level gr->set_halt(halthandle_t()); // still connected elsewhere? for(unsigned i=0; iget_boden_count(); i++ ) { if(pl->get_boden_bei(i)->get_halt()==self) { // still connected with other ground => do not remove from plan ... remove_halt = false; break; } } } if (remove_halt) { // otherwise remove from plan ... if (pl) { pl->get_kartenboden()->set_flag(grund_t::dirty); } uint16 const cov = welt->get_settings().get_station_coverage(); for (int y = -cov; y <= cov; y++) { for (int x = -cov; x <= cov; x++) { planquadrat_t *pl = welt->access( gr->get_pos().get_2d()+koord(x,y) ); if(pl) { pl->remove_from_haltlist(self); pl->get_kartenboden()->set_flag(grund_t::dirty); } } } // factory reach may have been changed ... verbinde_fabriken(); } // needs to be done, if this was a dock recalc_station_type(); // remove lines eventually for( size_t j = registered_lines.get_count(); j-- != 0; ) { bool ok = false; for(schedule_entry_t const& k : registered_lines[j]->get_schedule()->entries ) { if( get_halt(k.pos, registered_lines[j]->get_owner()) == self ) { ok = true; break; } } // need removal? if(!ok) { stale_lines.append_unique( registered_lines[j] ); registered_lines.remove_at(j); } } // remove registered lineless convoys as well for( size_t j = registered_convoys.get_count(); j-- != 0; ) { bool ok = false; for(schedule_entry_t const& k : registered_convoys[j]->get_schedule()->entries ) { if( get_halt(k.pos, registered_convoys[j]->get_owner()) == self ) { ok = true; break; } } // need removal? if( !ok ) { stale_convois.append_unique( registered_convoys[j] ); registered_convoys.remove_at(j); } } return true; } bool haltestelle_t::existiert_in_welt() const { return !tiles.empty(); } /* marks a coverage area */ void haltestelle_t::mark_unmark_coverage(const bool mark) const { // iterate over all tiles uint16 const cov = welt->get_settings().get_station_coverage(); koord const size(cov * 2 + 1, cov * 2 + 1); for(tile_t const& i : tiles) { welt->mark_area(i.grund->get_pos() - size / 2, size, mark); } } /* Find a tile where this type of vehicle could stop */ const grund_t *haltestelle_t::find_matching_position(const waytype_t w) const { // iterate over all tiles for(tile_t const& i : tiles) { if (i.grund->hat_weg(w)) { return i.grund; } } return NULL; } /* checks, if there is an unoccupied loading bay for this kind of thing */ bool haltestelle_t::find_free_position(const waytype_t w,convoihandle_t cnv,const obj_t::typ d) const { // iterate over all tiles for(tile_t const& i : tiles) { if (i.reservation == cnv || !i.reservation.is_bound()) { // not reserved grund_t* const gr = i.grund; assert(gr); // found a stop for this waytype but without object d ... if(gr->hat_weg(w) && gr->suche_obj(d)==NULL) { // not occupied return true; } } } return false; } /* reserves a position (caution: railblocks work differently! */ bool haltestelle_t::reserve_position(grund_t *gr,convoihandle_t cnv) { slist_tpl::iterator i = std::find(tiles.begin(), tiles.end(), gr); if (i != tiles.end()) { if (i->reservation == cnv) { //DBG_MESSAGE("haltestelle_t::reserve_position()","gr=%d,%d already reserved by cnv=%d",gr->get_pos().x,gr->get_pos().y,cnv.get_id()); return true; } // not reserved if (!i->reservation.is_bound()) { grund_t* gr = i->grund; if(gr) { // found a stop for this waytype but without object d ... vehicle_t const& v = *cnv->front(); if (gr->hat_weg(v.get_waytype()) && !gr->suche_obj(v.get_typ())) { // not occupied //DBG_MESSAGE("haltestelle_t::reserve_position()","success for gr=%i,%i cnv=%d",gr->get_pos().x,gr->get_pos().y,cnv.get_id()); i->reservation = cnv; return true; } } } } //DBG_MESSAGE("haltestelle_t::reserve_position()","failed for gr=%i,%i, cnv=%d",gr->get_pos().x,gr->get_pos().y,cnv.get_id()); return false; } /** frees a reserved position (caution: railblocks work differently! */ bool haltestelle_t::unreserve_position(grund_t *gr, convoihandle_t cnv) { slist_tpl::iterator i = std::find(tiles.begin(), tiles.end(), gr); if (i != tiles.end()) { if (i->reservation == cnv) { i->reservation = convoihandle_t(); return true; } } DBG_MESSAGE("haltestelle_t::unreserve_position()","failed for gr=%p",gr); return false; } /** can a convoi reserve this position? */ bool haltestelle_t::is_reservable(const grund_t *gr, convoihandle_t cnv) const { for(tile_t const& i : tiles) { if (gr == i.grund) { if (i.reservation == cnv) { DBG_MESSAGE("haltestelle_t::is_reservable()","gr=%d,%d already reserved by cnv=%d",gr->get_pos().x,gr->get_pos().y,cnv.get_id()); return true; } // not reserved if (!i.reservation.is_bound()) { // found a stop for this waytype but without object d ... vehicle_t const& v = *cnv->front(); if (gr->hat_weg(v.get_waytype()) && !gr->suche_obj(v.get_typ())) { // not occupied return true; } } return false; } } DBG_MESSAGE("haltestelle_t::reserve_position()","failed for gr=%i,%i, cnv=%d",gr->get_pos().x,gr->get_pos().y,cnv.get_id()); return false; } /* deletes factory references so map rotation won't segfault */ void haltestelle_t::release_factory_links() { for(fabrik_t* const f : fab_list) { f->unlink_halt(self); } fab_list.clear(); } /* check if the station given is covered by this station */ bool haltestelle_t::is_halt_covered(const halthandle_t &halt) const { uint16 const cov = welt->get_settings().get_station_coverage(); for(tile_t const& i : halt->get_tiles()) { if( gebaeude_t* const gb = i.grund->find() ) { if ( koord_distance( gb->get_pos().get_2d(), get_next_pos( gb->get_pos().get_2d() )) <= cov ) { return true; } } } return false; } simutrans-124.3/src/simutrans/simhalt.h000066400000000000000000000533271474050137200202130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMHALT_H #define SIMHALT_H #include "convoihandle.h" #include "linehandle.h" #include "halthandle.h" #include "obj/simobj.h" #include "display/simgraph.h" #include "simtypes.h" #include "builder/goods_manager.h" #include "descriptor/goods_desc.h" #include "dataobj/koord.h" #include "tpl/inthashtable_tpl.h" #include "tpl/slist_tpl.h" #include "tpl/vector_tpl.h" #include "tpl/array_tpl.h" #define RECONNECTING (1) #define REROUTING (2) #define MAX_HALT_COST 8 // Total number of cost items #define MAX_MONTHS 12 // Max history #define MAX_HALT_NON_MONEY_TYPES 7 // number of non money types in HALT's financial statistic #define HALT_ARRIVED 0 // the amount of ware that arrived here #define HALT_DEPARTED 1 // the amount of ware that has departed from here #define HALT_WAITING 2 // the amount of ware waiting #define HALT_HAPPY 3 // number of happy passengers #define HALT_UNHAPPY 4 // number of unhappy passengers #define HALT_NOROUTE 5 // number of no-route passengers #define HALT_CONVOIS_ARRIVED 6 // number of convois arrived this month #define HALT_WALKED 7 // could walk to destination class cbuffer_t; class grund_t; class fabrik_t; class karte_t; class karte_ptr_t; class koord3d; class loadsave_t; class schedule_t; class player_t; class ware_t; template class bucket_heap_tpl; // -------------------------- Haltestelle ---------------------------- /** * Haltestellen in Simutrans. Diese Klasse managed das Routing und Verladen * von Waren. Eine Haltestelle ist somit auch ein Warenumschlagplatz. * @see stadt_t * @see fabrik_t * @see convoi_t */ class haltestelle_t { public: enum station_flags { NOT_ENABLED = 0, PAX = 1 << 0, POST = 1 << 1, WARE = 1 << 2 }; // can be combined with or! enum stationtyp { invalid = 0, loadingbay = 1 << 0, railstation = 1 << 1, dock = 1 << 2, busstop = 1 << 3, airstop = 1 << 4, monorailstop = 1 << 5, tramstop = 1 << 6, maglevstop = 1 << 7, narrowgaugestop = 1 << 8 }; private: /// List of all halts in the game. static vector_tpl alle_haltestellen; /** * finds a stop by its name */ static stringhashtable_tpl all_names; /** * Finds a stop by coordinate. * only used during loading. */ static inthashtable_tpl *all_koords; vector_tpl* halt_served_this_step; /** * struct holds new financial history for line */ sint64 financial_history[MAX_MONTHS][MAX_HALT_COST]; /** * initialize the financial history */ void init_financial_history(); PIXVAL status_color, last_status_color; sint16 last_bar_count; vector_tpl last_bar_height; // caches the last height of the station bar for each good type drawn in display_status(). used for dirty tile management uint32 capacity[3]; // passenger, mail, goods uint8 overcrowded[256/8]; ///< bit field for each goods type (max 256) static uint8 status_step; // NONE or SCHEDULING or REROUTING vector_tpl loading_here; sint32 last_loading_step; koord init_pos; // for halt without grounds, created during game initialisation /** * Handle for ourselves. Can be used like the 'this' pointer */ halthandle_t self; public: /** * List of convois currently loading at this station. * May contain invalid handles! */ const vector_tpl &get_loading_convois() const { return loading_here; } /** * All destinations which received goods in this step. hat_gehalten will exclude them, to load the first convoi for those first */ const vector_tpl *get_halt_served_this_step() const { return halt_served_this_step; } // add convoi to loading queue void request_loading( convoihandle_t cnv ); /* recalculates the station bar */ void recalc_status(); /** * Handles changes of schedules and the resulting re-routing. */ static void step_all(); static uint8 get_rerouting_status() { return status_step; } /** * Resets reconnect_counter. * The next call to step_all() will start complete reconnecting. */ static void reset_routing(); /** * Returns an index to a halt at koord k * optionally limit to that owned by player sp * by default create a new halt if none found * Only used during loading. */ static halthandle_t get_halt_koord_index(koord k); /* * this will only return something if this stop belongs to same player or is public, or is a dock (when on water) */ static halthandle_t get_halt(const koord3d pos, const player_t *player ); static const vector_tpl& get_alle_haltestellen() { return alle_haltestellen; } /** * Station factory method. Returns handles instead of pointers. */ static halthandle_t create(koord pos, player_t *player); /** * Station factory method. Returns handles instead of pointers. */ static halthandle_t create(loadsave_t *file); /** * removes a ground tile from a station, deletes the building and, if last tile, also the halthandle */ static bool remove(player_t *player, koord3d pos); /** * Station destruction method. */ static void destroy(halthandle_t); /** * destroys all stations */ static void destroy_all(); /** * List of all tiles (grund_t) that belong to this halt. */ struct tile_t { tile_t(grund_t* grund_) : grund(grund_) {} bool operator ==(const tile_t& o) { return grund == o.grund; } bool operator !=(const tile_t& o) { return grund != o.grund; } grund_t* grund; convoihandle_t reservation; }; const slist_tpl &get_tiles() const { return tiles; } /** * directly reachable halt with its connection weight */ struct connection_t { /// directly reachable halt halthandle_t halt; /// best connection weight to reach this destination uint16 weight:15; /// is halt a transfer halt bool is_transfer:1; connection_t() : weight(0), is_transfer(false) { } connection_t(halthandle_t _halt, uint16 _weight=0) : halt(_halt), weight(_weight), is_transfer(false) { } bool operator == (const connection_t &other) const { return halt == other.halt; } bool operator != (const connection_t &other) const { return halt != other.halt; } static bool compare(const connection_t &a, const connection_t &b) { return a.halt.get_id() < b.halt.get_id(); } }; bool is_transfer(const uint8 catg) const { return all_links[catg].is_transfer; } private: slist_tpl tiles; /** * Stores information about link to cargo network of a certain category */ struct link_t { /// List of all directly reachable halts with their respective connection weights vector_tpl connections; /** * A transfer/interchange is a halt whereby ware can change line or lineless convoy. * Thus, if a halt is served by 2 or more schedules (of lines or lineless convoys) * for a particular ware type, it is a transfer/interchange for that ware type. * Route searching is accelerated by differentiating transfer and non-transfer halts. */ bool is_transfer; /** * Id of connected component in link graph. * Two halts are connected if and only if they belong to the same connected component. * Exception: if value == UNDECIDED_CONNECTED_COMPONENT, then we are in the middle of * recalculating the link graph. * * The id of the component has to be equal to the halt-id of one of its halts. * This ensures that we always have unique component ids. */ uint16 catg_connected_component; # define UNDECIDED_CONNECTED_COMPONENT (0xffff) link_t() { clear(); } void clear() { connections.clear(); is_transfer = false; catg_connected_component = UNDECIDED_CONNECTED_COMPONENT; } }; /// All links to networks of all freight categories, filled by rebuild_connected_components. link_t* all_links; /** * Fills in catg_connected_component values for all halts and all categories. * Uses depth-first search. */ static void rebuild_connected_components(); /** * Helper method: This halt (and all its connected neighbors) belong * to the same component. * Also sets connection_t::is_transfer. * @param catg category of cargo network * @param comp number of component */ void fill_connected_component(uint8 catg, uint16 comp); // Array with different categories that contains all waiting goods at this stop vector_tpl **cargo; /** * Liste der angeschlossenen Fabriken */ slist_tpl fab_list; player_t *owner; static karte_ptr_t welt; /** * What is that for a station (for the image) */ stationtyp station_type; // private helper function for recalc_station_type() void add_to_station_type( grund_t *gr ); /** * Reconnect and reroute if counter different from welt->get_schedule_counter() */ static uint8 reconnect_counter; // since we do partial routing, we remember the last offset uint8 last_catg_index; /* station flags (most what enabled) */ uint8 enables; /** * versucht die ware mit beriets wartender ware zusammenzufassen */ bool vereinige_waren(const ware_t &ware); // add the ware to the internal storage, called only internally void add_ware_to_halt(ware_t ware); /** * liefert wartende ware an eine Fabrik */ void liefere_an_fabrik(const ware_t& ware) const; /** * transfers all goods to given station */ void transfer_goods(halthandle_t halt); /** * parameter to ease sorting * sortierung is local and stores the sortorder for the individual station */ uint8 sortierung; bool resort_freight_info; haltestelle_t(loadsave_t *file); haltestelle_t(koord pos, player_t *player); ~haltestelle_t(); public: /** * Called after schedule calculation of all stations is finished * will distribute the goods to changed routes (if there are any) */ void reroute_goods(sint16 &units_remaining); /** * getter/setter for sortby */ uint8 get_sortby() { return sortierung; } void set_sortby(uint8 sm) { resort_freight_info =true; sortierung = sm; } /** * Calculates a status color for status bars */ PIXVAL get_status_farbe() const { return status_color; } /** * Draws some nice colored bars giving some status information */ void display_status(sint16 xpos, sint16 ypos); /** * sucht umliegende, erreichbare fabriken und baut daraus die * Fabrikliste auf. */ void verbinde_fabriken(); /** * Connects factory to this halt if not already connected and * reachability check for oil rigs passed. * No station coverage checked. * @returns true if succeeded */ bool connect_factory(fabrik_t *fab); void remove_fabriken(fabrik_t *fab); /** * Rebuilds the list of connections to reachable halts * returns the search number of connections */ sint32 rebuild_connections(); /** * Rebuilds connections of all halts connected to this halt. * Prepares deletion of this halt without losing connections and routed freight. */ void rebuild_linked_connections(); static uint8 get_reconnect_counter() { return reconnect_counter; } void rotate90( const sint16 y_size ); player_t *get_owner() const {return owner;} // just for info so far sint64 calc_maintenance() const; void merge_halt( halthandle_t halt_to_join ); void change_owner( player_t *player ); vector_tpl const& get_pax_connections() const { return all_links[goods_manager_t::INDEX_PAS].connections; } vector_tpl const& get_mail_connections() const { return all_links[goods_manager_t::INDEX_MAIL].connections; } // returns the matching warenziele (goods objectives/destinations) vector_tpl const& get_connections(uint8 const catg_index) const { return all_links[catg_index].connections; } /** * Checks if there is connection for certain freight to the other halt. * @param halt the other halt * @param catg_index freight category index * @return 0 - not connected, 1 - connected, -1 - undecided (call again later...) */ sint8 is_connected(halthandle_t halt, uint8 catg_index) const; bool has_available_network( const player_t* player, uint8 catg_index = goods_manager_t::INDEX_NONE ) const; const slist_tpl& get_fab_list() const { return fab_list; } /** * called regularly to update status and reroute stuff */ bool step(uint8 what, sint16 &units_remaining); /** * Called every month/every 24 game hours */ void new_month(); private: /* Node used during route search */ struct route_node_t { halthandle_t halt; uint16 aggregate_weight; route_node_t() : aggregate_weight(0) {} route_node_t(halthandle_t h, uint16 w) : halt(h), aggregate_weight(w) {} // dereferencing to be used in binary_heap_tpl inline uint16 operator * () const { return aggregate_weight; } }; // open_list needs access to route_node_t template friend class bucket_heap_tpl; /* Extra data for route search */ struct halt_data_t { // transfer halt: // in static function search_route(): previous transfer halt (to track back route) // in member function search_route_resumable(): first transfer halt to get there halthandle_t transfer; uint16 best_weight; uint16 depth:14; bool destination:1; bool overcrowded:1; }; // store the best weight so far for a halt, and indicate whether it is a destination static halt_data_t halt_data[65536]; // for efficient retrieval of the node with the smallest weight static bucket_heap_tpl open_list; /** * Markers used in route searching to avoid processing the same halt more than once */ static uint8 markers[65536]; static uint8 current_marker; /** * Remember last route search start and catg to resume search */ static halthandle_t last_search_origin; static uint8 last_search_ware_catg_idx; public: enum routing_result_flags { NO_ROUTE = 0, ROUTE_OK = 1, ROUTE_WALK = 2, ROUTE_OVERCROWDED = 8 }; /** * Kann die Ware nicht zum Ziel geroutet werden (keine Route), dann werden * Ziel und Zwischenziel auf koord::invalid gesetzt. * * @param ware die zu routende Ware * * for reverse routing, also the next to last stop can be added, if next_to_ziel!=NULL * * if avoid_overcrowding is set, a valid route in only found when there is no overflowing stop in between */ static int search_route( const halthandle_t *const start_halts, const uint16 start_halt_count, const bool no_routing_over_overcrowding, ware_t &ware, ware_t *const return_ware=NULL ); /** * A separate version of route searching code for re-calculating routes * Search is resumable, that is if called for the same halt and same goods category * it reuses search history from last search * It is faster than calling the above version on each packet, and is used for re-routing packets from the same halt. */ void search_route_resumable( ware_t &ware ); bool get_pax_enabled() const { return enables & PAX; } bool get_mail_enabled() const { return enables & POST; } bool get_ware_enabled() const { return enables & WARE; } // check, if we accepts this good // often called, thus inline ... bool is_enabled( const goods_desc_t *wtyp ) const { return is_enabled(wtyp->get_catg_index()); } // a separate version for checking with goods category index bool is_enabled( const uint8 catg_index ) const { if (catg_index == goods_manager_t::INDEX_PAS) { return enables&PAX; } else if(catg_index == goods_manager_t::INDEX_MAIL) { return enables&POST; } return enables&WARE; } /** * Found route and station uncrowded */ void add_pax_happy(int n); /** * Station in walking distance */ void add_pax_walked(int n); /** * Found no route */ void add_pax_no_route(int n); /** * Station crowded */ void add_pax_unhappy(int n); int get_pax_happy() const { return (int)financial_history[0][HALT_HAPPY]; } int get_pax_no_route() const { return (int)financial_history[0][HALT_NOROUTE]; } int get_pax_unhappy() const { return (int)financial_history[0][HALT_UNHAPPY]; } /** * Add tile to list of station tiles. * * @param gb * @param relink_factories if true call verbinde_fabriken, if not true take care of factory connections yourself */ bool add_grund(grund_t *gb, bool relink_factories = true); bool rem_grund(grund_t *gb); uint32 get_capacity(uint8 typ) const { return capacity[typ]; } bool existiert_in_welt() const; koord get_init_pos() const { return init_pos; } koord get_basis_pos() const; koord3d get_basis_pos3d() const; public: void recalc_basis_pos(); // returns ground closest to this coordinate grund_t *get_ground_closest_to( const koord here ) const; /** * return the closest square that belongs to this halt */ koord get_next_pos( koord start ) const; /// true, if this station is overcrowded for this ware bool is_overcrowded( const uint8 idx ) const { return (overcrowded[idx/8] & (1<<(idx%8)))!=0; } /// @returns total amount of the good waiting at this halt. uint32 get_ware_summe(const goods_desc_t *warentyp) const; /** * returns total number for a certain position (since more than one factory might connect to a stop) */ uint32 get_ware_fuer_zielpos(const goods_desc_t *warentyp, const koord zielpos) const; /** * total amount of freight with specified next hop */ uint32 get_ware_fuer_zwischenziel(const goods_desc_t *warentyp, const halthandle_t zwischenziel) const; /// true, if we accept/deliver this kind of good bool gibt_ab(const goods_desc_t *warentyp) const { return cargo[warentyp->get_catg_index()] != NULL; } /** * retrieves a ware packet for any destination in the list * needed, if the factory in question wants to remove something */ bool recall_ware( ware_t& w, uint32 menge ); /** * Fetches goods from this halt * * @param load Output parameter. Goods will be put into this list, the vehicle has to load them. * @param good_category Specifies the kind of good (or compatible goods) we are requesting to fetch from this stop. * @param requested_amount How many units of the cargo we can fetch. * @param destination_halts */ void fetch_goods( slist_tpl &load, const goods_desc_t *good_category, uint32 requested_amount, const vector_tpl& destination_halts); /** * Delivers goods (ware_t) to this halt. * if no route is found, the good will be removed. * @returns amount of goods */ uint32 liefere_an(ware_t ware); /** * Delivers goods (ware_t) to this halt. * Will not recalculate the route * This is used for inital passenger, since they already know a route * @returns amount of goods */ uint32 starte_mit_route(ware_t ware); const grund_t *find_matching_position(waytype_t wt) const; /** * checks, if there is an unoccupied loading bay for this kind of thing */ bool find_free_position(const waytype_t w ,convoihandle_t cnv,const obj_t::typ d) const; /** * reserves a position (caution: railblocks work differently! */ bool reserve_position(grund_t *gr,convoihandle_t cnv); /** * frees a reserved position (caution: railblocks work differently! */ bool unreserve_position(grund_t *gr, convoihandle_t cnv); /** true, if this can be reserved */ bool is_reservable(const grund_t *gr, convoihandle_t cnv) const; /** * @param[out] buf Goods description text */ void get_freight_info(cbuffer_t & buf); /** * @param[out] buf short list of the waiting goods (i.e. 110 Wood, 15 Coal) */ void get_short_freight_info(cbuffer_t & buf) const; /** * Opens an information window for this station. */ void open_info_window(); /** * @return the type of a station * (combination of: railstation, loading bay, dock) */ stationtyp get_station_type() const { return station_type; } void recalc_station_type(); /** * fragt den namen der Haltestelle ab. * Der Name ist der text des ersten Untergrundes der Haltestelle * @return der Name der Haltestelle. */ const char *get_name() const; void set_name(const char *name); // create an unique name: better to be called with valid handle, although it will work without char* create_name(koord k, char const* typ); void rdwr(loadsave_t *file); void finish_rd(); /** * Called before savegame will be loaded. * Creates all_koords table. */ static void start_load_game(); /** * Called after loading of savegame almost finished, * i.e. after finish_rd is finished. * Deletes all_koords table. */ static void end_load_game(); /** * called, if a line serves this stop */ void add_line(linehandle_t line) { registered_lines.append_unique(line); } /** * called, if a line removes this stop from it's schedule */ void remove_line(linehandle_t line) { registered_lines.remove(line); } /** * list of line ids that serve this stop */ vector_tpl registered_lines; /** * Register a lineless convoy which serves this stop */ void add_convoy(convoihandle_t convoy) { registered_convoys.append_unique(convoy); } /** * Unregister a lineless convoy */ void remove_convoy(convoihandle_t convoy) { registered_convoys.remove(convoy); } /** * A list of lineless convoys serving this stop */ vector_tpl registered_convoys; /** * book a certain amount into the halt's financial history */ void book(sint64 amount, int cost_type); /** * return a pointer to the financial history */ sint64* get_finance_history() { return *financial_history; } /** * return a specified element from the financial history */ sint64 get_finance_history(int month, int cost_type) const { return financial_history[month][cost_type]; } /** marks a coverage area */ void mark_unmark_coverage(const bool mark) const; /* * deletes factory references so map rotation won't segfault */ void release_factory_links(); /** * Initialise the markers to zero */ static void init_markers(); /* * check if it is in the station coverage */ bool is_halt_covered (const halthandle_t &halt) const; }; ENUM_BITSET(haltestelle_t::stationtyp) #endif simutrans-124.3/src/simutrans/siminteraction.cc000066400000000000000000000301501474050137200217250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "siminteraction.h" #include "simversion.h" #include "dataobj/environment.h" #include "gui/gui_frame.h" #include "gui/help_frame.h" #include "network/network_cmd_ingame.h" #include "dataobj/scenario.h" #include "simevent.h" #include "utils/simrandom.h" #include "tool/simmenu.h" #include "player/simplay.h" #include "simsound.h" #include "sys/simsys.h" #include "simticker.h" #include "gui/simwin.h" #include "world/simworld.h" #include "descriptor/sound_desc.h" #include "obj/zeiger.h" #include "display/viewport.h" karte_ptr_t interaction_t::world; void interaction_t::move_view( const event_t &ev ) { koord new_ij = viewport->get_world_position(); sint16 new_xoff = viewport->get_x_off() - (ev.mouse_pos.x - ev.click_pos.x) * env_t::scroll_multi; sint16 new_yoff = viewport->get_y_off() - (ev.mouse_pos.y - ev.click_pos.y) * env_t::scroll_multi; // this sets the new position and mark screen dirty // => with next refresh we will be at a new location viewport->change_world_position( new_ij, new_xoff, new_yoff ); // move the mouse pointer back to starting location => infinite mouse movement if ((ev.mouse_pos.x - ev.click_pos.x) != 0 || (ev.mouse_pos.y - ev.click_pos.y) != 0) { if(!env_t::scroll_infinite || !move_pointer(ev.click_pos.x, ev.click_pos.y)) { // fails in finger mode => we have to reset start ourselves change_drag_start(ev.mouse_pos - ev.click_pos); } } } void interaction_t::move_cursor( const event_t &ev ) { zeiger_t *zeiger = world->get_zeiger(); if(! zeiger ) { // No cursor to move, exit return; } static int mb_alt=0; tool_t *tool = world->get_tool(world->get_active_player_nr()); const koord3d pos = viewport->get_new_cursor_position(scr_coord(ev.mouse_pos.x,ev.mouse_pos.y), tool->is_grid_tool()); if( pos == koord3d::invalid ) { zeiger->change_pos(pos); return; } // move cursor const koord3d prev_pos = zeiger->get_pos(); if( (prev_pos != pos || ev.button_state != mb_alt) ) { mb_alt = ev.button_state; zeiger->change_pos(pos); if (!tool->move_has_effects()) { is_dragging = false; } else { tool->flags = (event_get_last_control_shift() ^ tool_t::control_invert) | tool_t::WFL_LOCAL; if(tool->check_pos( world->get_active_player(), zeiger->get_pos() )==NULL) { if( ev.button_state == 0 ) { is_dragging = false; } else if(ev.ev_class==EVENT_DRAG) { if(!is_dragging && prev_pos != koord3d::invalid && tool->check_pos( world->get_active_player(), prev_pos )==NULL) { is_dragging = true; } } if (is_dragging) { world->set_deferred_move_to(pos, tool->flags); } } tool->flags = 0; } if( (ev.button_state&7)==0 ) { // time, since mouse got here world->set_mouse_rest_time(dr_time()); world->set_sound_wait_time(AMBIENT_SOUND_INTERVALL); // 13s no movement: play sound } } } void interaction_t::interactive_event( const event_t &ev ) { if(ev.ev_class == EVENT_KEYBOARD) { DBG_MESSAGE("interaction_t::interactive_event()","Keyboard event with code %d '%c'", ev.ev_code, (ev.ev_code>=32 && ev.ev_code<=126) ? ev.ev_code : '?' ); switch(ev.ev_code) { // cursor movements case SIM_KEY_UPRIGHT: viewport->change_world_position(viewport->get_world_position() + koord::north); world->set_dirty(); break; case SIM_KEY_DOWNLEFT: viewport->change_world_position(viewport->get_world_position() + koord::south); world->set_dirty(); break; case SIM_KEY_UPLEFT: viewport->change_world_position(viewport->get_world_position() + koord::west); world->set_dirty(); break; case SIM_KEY_DOWNRIGHT: viewport->change_world_position(viewport->get_world_position() + koord::east); world->set_dirty(); break; case SIM_KEY_RIGHT: viewport->change_world_position(viewport->get_world_position() + koord(+1,-1)); world->set_dirty(); break; case SIM_KEY_DOWN: viewport->change_world_position(viewport->get_world_position() + koord(+1,+1)); world->set_dirty(); break; case SIM_KEY_UP: viewport->change_world_position(viewport->get_world_position() + koord(-1,-1)); world->set_dirty(); break; case SIM_KEY_LEFT: viewport->change_world_position(viewport->get_world_position() + koord(-1,+1)); world->set_dirty(); break; // closing windows case 27: case 127: if( !IS_CONTROL_PRESSED( &ev ) && !IS_SHIFT_PRESSED( &ev ) ) { // close topmost win destroy_win( win_get_top() ); } break; case SIM_KEY_F1: if( gui_frame_t *win = win_get_top() ) { if( const char *helpfile = win->get_help_filename() ) { help_frame_t::open_help_on( helpfile ); break; } } world->set_tool( tool_t::dialog_tool[DIALOG_HELP], world->get_active_player() ); break; // just ignore the key case 0: break; // distinguish between backspace and ctrl-H (both keycode==8), and enter and ctrl-M (both keycode==13) case 8: case 13: if( !IS_CONTROL_PRESSED(&ev) && !IS_SHIFT_PRESSED(&ev) ) { // Control is _not_ pressed => Backspace or Enter pressed. if( ev.ev_code == 8 ) { // Backspace sound_play(SFX_SELECT,255,TOOL_SOUND); destroy_all_win(false); } // Ignore Enter and Backspace but not Ctrl-H and Ctrl-M break; } /* FALLTHROUGH */ default: { bool ok=false; for(tool_t* const i : tool_t::char_to_tool) { if( i->command_key == ev.ev_code ) { if( i->command_flags == 0 || (ev.ev_key_mod & (SIM_MOD_SHIFT|SIM_MOD_CTRL)) == i->command_flags ) { world->set_tool(i, world->get_active_player()); ok = true; break; } } } #ifdef STEAM_BUILT // Block F12 from bringing up Keyboard Help (for Steam Screenshot) - but still allow F12 to be used if defined in pakset if (ev.ev_code==SIM_KEY_F12) { ok=true; } #endif if(!ok) { help_frame_t::open_help_on( "keys.txt" ); } } break; } } if( !is_dragging && IS_LEFTRELEASE(&ev) && ev.mouse_pos.y < display_get_height() -16 -(TICKER_HEIGHT*ticker::empty()) ) { DBG_MESSAGE("interaction_t::interactive_event(event_t &ev)", "calling a tool"); koord3d pos = world->get_zeiger()->get_pos(); if(world->is_within_grid_limits(pos.get_2d())) { bool suspended = false; // true if execution was suspended, i.e. sent to server tool_t *tool = world->get_tool(world->get_active_player_nr()); player_t *player = world->get_active_player(); tool->flags = event_get_last_control_shift() ^ tool_t::control_invert; // first check for visibility etc (needs already right flags) const char *err = tool->check_pos( player, pos ); if (err==NULL) { err = world->call_work_api(tool, player, pos, suspended); } if (!suspended) { // play sound / error message world->get_active_player()->tell_tool_result(tool, pos, err); // Check if we need to update pointer(zeiger) position. if( err == NULL && tool->update_pos_after_use() ) { // Cursor might need movement (screen has changed, we get a new one under the mouse pointer) const koord3d pos_new = viewport->get_new_cursor_position(scr_coord(ev.mouse_pos.x,ev.mouse_pos.y), tool->is_grid_tool()); world->get_zeiger()->set_pos(pos_new); } } tool->flags = 0; } } // mouse wheel scrolled -> rezoom if (ev.ev_class == EVENT_CLICK) { // first, we need to check cursor is valid, won't zoom otherwise const koord3d cursor_pos = world->get_zeiger()->get_pos(); if( cursor_pos == koord3d::invalid) { //ignore event return; } bool zoom_successful = false; // store old screen position of centered tile scr_coord s = viewport->get_screen_coord(cursor_pos, koord(0,0)); if(ev.ev_code==MOUSE_WHEELUP) { if(win_change_zoom_factor(true)) { zoom_successful = true; } } else if(ev.ev_code==MOUSE_WHEELDOWN) { if(win_change_zoom_factor(false)) { zoom_successful = true; } } // zoom can fail if we are max zoomed in/out, so: if (zoom_successful) { // calculate offsets such that tile under cursor is still on the same screen position viewport->change_world_position(cursor_pos, koord(0,0), s); //and move cursor to the new position under the mouse move_cursor(ev); world->set_dirty(); } } } bool interaction_t::process_event( event_t &ev ) { if(ev.ev_class==EVENT_SYSTEM && ev.ev_code==SYSTEM_QUIT) { // since we run in a sync_step, quitting may be needed to be delagated to a tool if( (LOAD_RANDOM | MAP_CREATE_RANDOM | MODAL_RANDOM) & get_random_mode() ) { // next sync step would take tool long world->stop(true); } else { // we call the proper tool for quitting world->set_tool(tool_t::simple_tool[TOOL_QUIT], NULL); } return true; } if(ev.ev_class==IGNORE_EVENT) { // ignore it return false; } DBG_DEBUG4("interaction_t::process_event", "calling check_pos_win"); if(check_pos_win(&ev,false)){ // The event is shallowed by the GUI, next. return false; } DBG_DEBUG4("interaction_t::process_event", "after check_pos_win"); // Handle map drag with right-click if(IS_RIGHTCLICK(&ev)) { display_show_pointer(false); } else if(IS_RIGHTRELEASE(&ev)) { display_show_pointer(true); } else if(IS_RIGHTDRAG(&ev)) { // unset following world->get_viewport()->set_follow_convoi( convoihandle_t() ); catch_dragging(); move_view(ev); } else if( IS_LEFTDRAG(&ev) && IS_LEFT_BUTTON_PRESSED(&ev) && (is_world_dragging || (!world->get_tool(world->get_active_player_nr())->move_has_effects() && !IS_CONTROL_PRESSED(&ev)) ) ) { /* ok, we have a general tool selected, and we have a left drag or left release event with an actual difference * => move the map, if we are beyond a threshold */ if( is_world_dragging || abs(ev.click_pos.x-ev.mouse_pos.x)+abs(ev.click_pos.y-ev.mouse_pos.y)>=max(1,(env_t::scroll_threshold* get_tile_raster_width())/get_base_tile_raster_width()) ) { if (!is_world_dragging) { display_show_pointer(false); is_world_dragging = true; } world->get_viewport()->set_follow_convoi(convoihandle_t()); catch_dragging(); move_view(ev); ev.ev_code = IGNORE_EVENT; } } if( !IS_LEFT_BUTTON_PRESSED(&ev) && is_world_dragging ) { // show the mouse and swallow this event if we were dragging before ev.ev_code = IGNORE_EVENT; display_show_pointer(true); is_world_dragging = false; } DBG_DEBUG4("interaction_t::process_event", "check if cursor needs movement"); if( (ev.ev_class==EVENT_DRAG && ev.ev_code==MOUSE_LEFTBUTTON) || (ev.button_state==0 && ev.ev_class==EVENT_MOVE) || ev.ev_class==EVENT_RELEASE) { move_cursor(ev); } DBG_DEBUG4("interaction_t::process_event", "calling interactive_event"); interactive_event(ev); DBG_DEBUG4("interaction_t::process_event", "end of event handling"); return false; } void interaction_t::check_events() { event_t ev; win_poll_event(&ev); event_t deferred_ev; deferred_ev.ev_class = EVENT_NONE; for( int swallow_dummies=0; swallow_dummies<4; swallow_dummies++ ) { /* there are always dummy events in the queue, usually less than 4 * => retry a few times until we get a useful event * Otherwise very laggy response at low fps */ if (ev.ev_class != EVENT_NONE) { DBG_DEBUG4("interaction_t::check_events", "event %d after %d dummies", ev.ev_class, swallow_dummies); swallow_dummies = 0; if (ev.ev_class == EVENT_DRAG) { // defer processing, since there might be many triggered at once // Otherwise mark tiles could be alled twice duing one step deferred_ev = ev; } else { // still one drag left in queue? if (deferred_ev.ev_class == EVENT_DRAG) { // do this first process_event(deferred_ev); deferred_ev.ev_class = EVENT_NONE; } if (process_event(ev)) { // We have been asked to stop processing, exit. return; } } } win_poll_event(&ev); } if (deferred_ev.ev_class == EVENT_DRAG) { // process pending drag events process_event(deferred_ev); deferred_ev.ev_class = EVENT_NONE; } } interaction_t::interaction_t(viewport_t *viewport) : viewport(viewport), is_dragging(false), is_world_dragging(false) { assert(viewport); } simutrans-124.3/src/simutrans/siminteraction.h000066400000000000000000000025371474050137200215770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMINTERACTION_H #define SIMINTERACTION_H class karte_ptr_t; class viewport_t; struct event_t; /** * User interaction class, it collects and processes all user and system events from the OS. * @brief Event manager of the game. * @see karte_t::interactive */ class interaction_t { private: /** * The associated world. */ static karte_ptr_t world; /** * Associated viewport of the world, this is a cached value. * @note Since a world in our project just has one viewport, we cache its value. */ viewport_t *viewport; bool is_dragging; bool is_world_dragging; private: /** * Processes a mouse event that's moving the camera. */ void move_view(const event_t &ev); /** * Processes a cursor movement event, related to the tool pointer in-map. * @see zeiger_t */ void move_cursor(const event_t &ev); /** * Processes a user event on the map, like a keyclick, or a mouse event. */ void interactive_event(const event_t &ev); /** * Processes a single event. * @return true if we need to stop processing events. */ bool process_event(event_t &ev); public: /** * Processes all the pending system events. * @brief Message Pump */ void check_events(); explicit interaction_t(viewport_t *viewport); }; #endif simutrans-124.3/src/simutrans/simintr.cc000066400000000000000000000163731474050137200203750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "simdebug.h" #include "sys/simsys.h" #include "simintr.h" #include "gui/simwin.h" #include "player/simplay.h" #include "player/finance.h" #include "dataobj/environment.h" #include "dataobj/translator.h" #include "world/simworld.h" #include "display/simview.h" #include "ground/wasser.h" static main_view_t *main_view = NULL; static uint32 last_time; static bool enabled = false; #define FRAME_TIME_MULTI (16) // pause between two frames static uint32 frame_time = 36*FRAME_TIME_MULTI; bool reduce_frame_time() { if( frame_time > 150*FRAME_TIME_MULTI ) { // < ~6.6fps frame_time -= 8; return true; } else if(frame_time > (FRAME_TIME_MULTI*1000)/env_t::max_fps) { frame_time -= 1; return true; } else { frame_time = (FRAME_TIME_MULTI*1000)/env_t::max_fps; return false; } } bool increase_frame_time() { if(frame_time > (FRAME_TIME_MULTI*1000)/5) { // < 5 fps return false; } else { frame_time ++; return true; } } uint32 get_frame_time() { return frame_time/FRAME_TIME_MULTI; } void set_frame_time(uint32 time) { frame_time = clamp( time, 1000/env_t::max_fps, 1000/env_t::min_fps )*FRAME_TIME_MULTI; } void intr_refresh_display(bool dirty) { wasser_t::prepare_for_refresh(); dr_prepare_flush(); main_view->display( dirty ); if( env_t::player_finance_display_account ) { win_display_flush( (double)world()->get_active_player()->get_finance()->get_account_balance()/100.0 ); } else { win_display_flush( (double)world()->get_active_player()->get_finance()->get_netwealth()/100.0 ); } // with a switch statement more types could be supported ... dr_flush(); } // debug version with caller information void interrupt_check(const char* caller_info) { DBG_DEBUG4("interrupt_check", "called from (%s)", caller_info); (void)caller_info; if( !enabled ) { return; } static uint32 last_ms = 0; if( !world()->is_fast_forward() || world()->get_ticks() != last_ms ) { const uint32 now = dr_time(); if((now-last_time)*FRAME_TIME_MULTI < frame_time) { return; } const sint32 diff = (( (sint32)now - (sint32)last_time)*world()->get_time_multiplier())/16; if( diff>0 ) { enabled = false; last_time = now; if (!world()->is_fast_forward()) { world()->sync_step( diff ); } world()->display(diff); // since pause maz have been activated in this sync_step enabled = !world()->is_paused(); } } last_ms = world()->get_ticks(); } void intr_set_view(main_view_t *view) { main_view = view; last_time = dr_time(); enabled = true; } void intr_set_last_time(uint32 time) { last_time = time; } void intr_disable() { enabled = false; } void intr_enable() { enabled = true; } char const *tick_to_string( uint32 ticks, bool only_DDMMHHMM ) { static sint32 tage_per_month[12]={31,28,31,30,31,30,31,31,30,31,30,31}; static char const* const seasons[] = { "q2", "q3", "q4", "q1" }; static char time [128]; time[0] = 0; if (world()== NULL) { return time; } sint32 month = world()->get_last_month(); sint32 year = world()->get_last_year(); // calculate right month first const uint32 ticks_this_month = ticks % world()->ticks_per_world_month; month += ticks_this_month / world()->ticks_per_world_month; while( month>11 ) { month -= 12; year ++; } while( month<0 ) { month += 12; year --; } uint32 tage, hours, minuten; if (env_t::show_month > env_t::DATE_FMT_MONTH) { tage = (((sint64)ticks_this_month*tage_per_month[month]) >> world()->ticks_per_world_month_shift) + 1; hours = (((sint64)ticks_this_month*tage_per_month[month]) >> (world()->ticks_per_world_month_shift-16)); minuten = (((hours*3) % 8192)*60)/8192; hours = ((hours*3) / 8192)%24; } else { tage = 0; hours = (ticks_this_month * 24) >> world()->ticks_per_world_month_shift; minuten = ((ticks_this_month * 24 * 60) >> world()->ticks_per_world_month_shift)%60; } //DBG_MESSAGE("env_t::show_month","%d",env_t::show_month); // since seasons 0 is always summer for backward compatibility char const* const date = only_DDMMHHMM ? translator::get_day_date(tage) : translator::get_date(year, month, tage, translator::translate(seasons[world()->get_season()])); switch (env_t::show_month) { case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: { uint32 hours_ = hours % 12; if (hours_ == 0) hours_ = 12; sprintf(time, "%s%2d:%02d%s", date, hours_, minuten, hours < 12 ? "am" : "pm"); break; } case env_t::DATE_FMT_SEASON: sprintf(time, "%s", date); break; default: sprintf(time, "%s%2d:%02dh", date, hours, minuten); break; } return time; } char const *difftick_to_string( sint32 ticks, bool round_to_quaters ) { static char time [128]; time[0] = 0; // World model might not be initalized if this is called while reading saved windows. if ( world() == NULL) { return time; } // suppress as much as possible, assuming this is an relative offset to the current month sint32 num_days = ( ticks * (env_t::show_month==env_t::DATE_FMT_MONTH? 1 : 31) ) >> world()->ticks_per_world_month_shift; char days[64]; days[0] = 0; if( num_days!=0 ) { sprintf( days, "%+i ", num_days ); } uint32 hours, minuten; if( env_t::show_month > env_t::DATE_FMT_MONTH ) { if( world()->ticks_per_world_month_shift>=16 ) { hours = (((sint64)ticks*31) >> (world()->ticks_per_world_month_shift-16)); } else { hours = (((sint64)ticks*31) << (16-world()->ticks_per_world_month_shift)); } } else { if( world()->ticks_per_world_month_shift>=16 ) { uint32 precision = round_to_quaters ? 0 : 15; hours = (ticks >> (world()->ticks_per_world_month_shift-16)) + precision; } else { uint32 precision = round_to_quaters ? 0 : 15 >> (16-world()->ticks_per_world_month_shift); hours = (((sint64)ticks) << (16-world()->ticks_per_world_month_shift)) + precision; } } minuten = (((hours * 3) % 8192) * 60) / 8192; hours = ((hours * 3) / 8192) % 24; // maybe round minutes if( round_to_quaters ) { int switchtick = world()->ticks_per_world_month_shift; if( env_t::show_month == env_t::DATE_FMT_MONTH ) { // since a month is then just three days instead of about 30 ... switchtick += 3; } if( switchtick <= 19 ) { minuten = ( (minuten + 30 ) / 60 ) * 60; hours += minuten /60; if( switchtick < 18 ) { // four hour intervals hours = (hours + 3 ) & 0xFFFFC; } else if( switchtick == 18 ) { // two hour intervals hours = (hours + 1 ) & 0xFFFFE; } } else if( switchtick == 20 ) { minuten = ( (minuten + 15) / 30 ) * 30; } else if( switchtick == 21 ) { minuten = ( (minuten + 7) / 15 ) * 15; } else if( switchtick == 22 ) { minuten = ( (minuten + 2) / 5 ) * 5; } } // take care of overflow hours += (minuten / 60); minuten %= 60; hours %= 24; switch(env_t::show_month) { case env_t::DATE_FMT_GERMAN: case env_t::DATE_FMT_GERMAN_NO_SEASON: case env_t::DATE_FMT_US: case env_t::DATE_FMT_US_NO_SEASON: sprintf(time, "%s%2d:%02dh", days, hours, minuten); break; case env_t::DATE_FMT_JAPANESE: case env_t::DATE_FMT_JAPANESE_NO_SEASON: sprintf(time, "%s%2d:%02dh", days, hours, minuten); break; case env_t::DATE_FMT_MONTH: sprintf(time, "%s%2d:%02dh", days, hours, minuten); break; } return time; } simutrans-124.3/src/simutrans/simintr.h000066400000000000000000000026661474050137200202370ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMINTR_H #define SIMINTR_H #include "macros.h" class karte_t; class main_view_t; /// Try to increase fps bool reduce_frame_time(); /// Try to decrease fps bool increase_frame_time(); uint32 get_frame_time(); void set_frame_time(uint32 ms); void intr_refresh_display(bool dirty); void intr_set_view(main_view_t *view); void intr_set_last_time(uint32 time); void intr_enable(); void intr_disable(); void interrupt_check(const char* caller_info = "0"); #if COLOUR_DEPTH == 0 && defined PROFILE // 0 bit graphic + profiling: no interrupt_check. #define INT_CHECK(info) #else #ifndef DEBUG // standard version #define INT_CHECK(info) do { interrupt_check(); } while(false) #else // debug version #define INT_CHECK(info) do { interrupt_check( __FILE__ ":" QUOTEME(__LINE__) ); } while(false) #endif #endif // returns a time string in the desired format // Returns an empty string if called before the world model defining time is initalized. // reutrns a shorter date (without season and year if second parameter true) char const *tick_to_string( uint32 ticks, bool omit_season_year=false ); // returns a time difference string in the desired format // assume the month has 31 days // round will reduce presion to qrater or less (depending on month length) char const *difftick_to_string( sint32 ticks, bool round ); #endif simutrans-124.3/src/simutrans/simio.cc000066400000000000000000000004111474050137200200120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include char *read_line(char *s, int size, FILE *file) { char *r; do { r = fgets(s, size, file); } while(r != NULL && *s == '#'); return r; } simutrans-124.3/src/simutrans/simio.h000066400000000000000000000004461474050137200176640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMIO_H #define SIMIO_H #include /** * Reads a line from a file. Skips lines starting with # * @see fgets */ char *read_line(char *s, int size, FILE *stream); #endif simutrans-124.3/src/simutrans/simline.cc000066400000000000000000000321771474050137200203500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simtypes.h" #include "simline.h" #include "simhalt.h" #include "world/simworld.h" #include "utils/simstring.h" #include "dataobj/schedule.h" #include "dataobj/translator.h" #include "dataobj/loadsave.h" #include "gui/gui_theme.h" #include "player/simplay.h" #include "player/finance.h" // convert_money #include "vehicle/vehicle.h" #include "simconvoi.h" #include "convoihandle.h" #include "simlinemgmt.h" #include "gui/simwin.h" #include "gui/gui_frame.h" uint8 convoi_to_line_catgory_[convoi_t::MAX_CONVOI_COST] = { LINE_CAPACITY, LINE_TRANSPORTED_GOODS, LINE_REVENUE, LINE_OPERATIONS, LINE_PROFIT, LINE_DISTANCE, LINE_MAXSPEED, LINE_WAYTOLL }; uint8 simline_t::convoi_to_line_catgory(uint8 cnv_cost) { assert(cnv_cost < convoi_t::MAX_CONVOI_COST); return convoi_to_line_catgory_[cnv_cost]; } karte_ptr_t simline_t::welt; simline_t::simline_t(player_t* player, linetype type) { self = linehandle_t(this); char printname[128]; sprintf(printname, "(%i) %s", self.get_id(), translator::translate("Line", welt->get_settings().get_name_language_id())); name = printname; init_financial_history(); this->type = type; this->schedule = NULL; this->player = player; withdraw = false; state_color = SYSCOL_TEXT; create_schedule(); } simline_t::simline_t(player_t* player, linetype type, loadsave_t *file) { // id will be read and assigned during rdwr self = linehandle_t(); this->type = type; this->schedule = NULL; this->player = player; withdraw = false; create_schedule(); rdwr(file); // now self has the right id but the this-pointer is not assigned to the quickstone handle yet // do this explicitly // some savegames have line_id=0, resolve that in finish_rd if (self.get_id()!=0) { self = linehandle_t(this, self.get_id()); } } simline_t::~simline_t() { DBG_DEBUG("simline_t::~simline_t()", "deleting schedule=%p", schedule); assert(count_convoys()==0); unregister_stops(); delete schedule; self.detach(); DBG_MESSAGE("simline_t::~simline_t()", "line %d (%p) destroyed", self.get_id(), this); } simline_t::linetype simline_t::waytype_to_linetype(const waytype_t wt) { switch (wt) { case road_wt: return simline_t::truckline; case track_wt: return simline_t::trainline; case water_wt: return simline_t::shipline; case monorail_wt: return simline_t::monorailline; case maglev_wt: return simline_t::maglevline; case tram_wt: return simline_t::tramline; case narrowgauge_wt: return simline_t::narrowgaugeline; case air_wt: return simline_t::airline; default: return simline_t::line; } } const char *simline_t::get_linetype_name(const simline_t::linetype lt) { static const char *lt2name[MAX_LINE_TYPE] = {"All", "Truck", "Train", "Ship", "Aircraft", "Monorail", "Tram", "Maglev", "Narrowgauge" }; return translator::translate( lt2name[lt] ); } waytype_t simline_t::linetype_to_waytype(const linetype lt) { static const waytype_t wt2lt[MAX_LINE_TYPE] = { invalid_wt, road_wt, track_wt, water_wt, air_wt, monorail_wt, tram_wt, maglev_wt, narrowgauge_wt }; return wt2lt[lt]; } void simline_t::set_schedule(schedule_t* schedule) { if (this->schedule) { unregister_stops(); delete this->schedule; } this->schedule = schedule; } void simline_t::set_name(const char *new_name) { name = new_name; /// Update window title if window is open gui_frame_t *line_info = win_get_magic((ptrdiff_t)self.get_rep()); if (line_info) { line_info->set_name(name); } } void simline_t::create_schedule() { switch(type) { case simline_t::truckline: set_schedule(new truck_schedule_t()); break; case simline_t::trainline: set_schedule(new train_schedule_t()); break; case simline_t::shipline: set_schedule(new ship_schedule_t()); break; case simline_t::airline: set_schedule(new airplane_schedule_t()); break; case simline_t::monorailline: set_schedule(new monorail_schedule_t()); break; case simline_t::tramline: set_schedule(new tram_schedule_t()); break; case simline_t::maglevline: set_schedule(new maglev_schedule_t()); break; case simline_t::narrowgaugeline: set_schedule(new narrowgauge_schedule_t()); break; default: dbg->fatal( "simline_t::create_schedule()", "Cannot create default schedule!" ); } } void simline_t::add_convoy(convoihandle_t cnv) { if (line_managed_convoys.empty() && self.is_bound()) { // first convoi -> ok, now we can announce this connection to the stations // unbound self can happen during loading if this line had line_id=0 register_stops(schedule); } // first convoi may change line type if (type == trainline && line_managed_convoys.empty() && cnv.is_bound()) { // check, if needed to convert to tram/monorail line if (vehicle_t const* const v = cnv->front()) { switch (v->get_desc()->get_waytype()) { case tram_wt: type = simline_t::tramline; break; // elevated monorail were saved with wrong coordinates for some versions. // We try to recover here case monorail_wt: type = simline_t::monorailline; break; default: break; } } } // only add convoy if not already member of line line_managed_convoys.append_unique(cnv); // what goods can this line transport? bool update_schedules = false; if( cnv->get_state()!=convoi_t::INITIAL ) { for(uint8 const catg_index : cnv->get_goods_catg_index()) { if( !goods_catg_index.is_contained( catg_index ) ) { goods_catg_index.append( catg_index, 1 ); update_schedules = true; } } } // will not hurt ... financial_history[0][LINE_CONVOIS] = count_convoys(); recalc_status(); // do we need to tell the world about our new schedule? if( update_schedules ) { welt->set_schedule_counter(); } } void simline_t::remove_convoy(convoihandle_t cnv) { if(line_managed_convoys.is_contained(cnv)) { line_managed_convoys.remove(cnv); recalc_catg_index(); financial_history[0][LINE_CONVOIS] = count_convoys(); recalc_status(); } if(line_managed_convoys.empty()) { unregister_stops(); } } // invalid line id prior to 110.0 #define INVALID_LINE_ID_OLD ((uint16)(-1)) // invalid line id from 110.0 on #define INVALID_LINE_ID ((uint16)(0)) void simline_t::rdwr_linehandle_t(loadsave_t *file, linehandle_t &line) { uint16 id; if (file->is_saving()) { id = line.is_bound() ? line.get_id() : (file->is_version_less(110, 0) ? INVALID_LINE_ID_OLD : INVALID_LINE_ID); } else { // to avoid undefined errors during loading id = 0; } if(file->is_version_less(88, 3)) { sint32 dummy=id; file->rdwr_long(dummy); id = (uint16)dummy; } else { file->rdwr_short(id); } if (file->is_loading()) { // invalid line_id's: 0 and 65535 if (id == INVALID_LINE_ID_OLD) { id = 0; } line.set_id(id); } } void simline_t::rdwr(loadsave_t *file) { xml_tag_t s( file, "simline_t" ); assert(schedule); file->rdwr_str(name); rdwr_linehandle_t(file, self); schedule->rdwr(file); //financial history if( file->is_version_less(102, 3) ) { for (int j = 0; j<6; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][LINE_DISTANCE] = 0; financial_history[k][LINE_MAXSPEED] = 0; financial_history[k][LINE_WAYTOLL] = 0; } } else if( file->is_version_less(111, 1) ) { for (int j = 0; j<7; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][LINE_MAXSPEED] = 0; financial_history[k][LINE_WAYTOLL] = 0; } } else if( file->is_version_less(112, 8) ) { for (int j = 0; j<8; j++) { for (size_t k = MAX_MONTHS; k-- != 0;) { file->rdwr_longlong(financial_history[k][j]); } } for (size_t k = MAX_MONTHS; k-- != 0;) { financial_history[k][LINE_WAYTOLL] = 0; } } else { for (int j = 0; jrdwr_longlong(financial_history[k][j]); } } } if(file->is_version_atleast(102, 2)) { file->rdwr_bool(withdraw); } // otherwise initialized to zero if loading ... financial_history[0][LINE_CONVOIS] = count_convoys(); } void simline_t::finish_rd() { if( !self.is_bound() ) { // get correct handle self = player->simlinemgmt.get_line_with_id_zero(); assert( self.get_rep() == this ); DBG_MESSAGE("simline_t::finish_rd", "assigned id=%d to line %s", self.get_id(), get_name()); } if (!line_managed_convoys.empty()) { register_stops(schedule); } recalc_status(); } void simline_t::register_stops(schedule_t * schedule) { DBG_DEBUG("simline_t::register_stops()", "%d schedule entries in schedule %p", schedule->get_count(),schedule); for(schedule_entry_t const& i : schedule->entries) { halthandle_t const halt = haltestelle_t::get_halt(i.pos, player); if(halt.is_bound()) { //DBG_DEBUG("simline_t::register_stops()", "halt not null"); halt->add_line(self); } else { DBG_DEBUG("simline_t::register_stops()", "halt null"); } } } void simline_t::unregister_stops() { unregister_stops(schedule); } void simline_t::unregister_stops(schedule_t * schedule) { for(schedule_entry_t const& i : schedule->entries) { halthandle_t const halt = haltestelle_t::get_halt(i.pos, player); if(halt.is_bound()) { halt->remove_line(self); } } } void simline_t::renew_stops() { if (!line_managed_convoys.empty()) { register_stops( schedule ); DBG_DEBUG("simline_t::renew_stops()", "Line id=%d, name='%s'", self.get_id(), name.c_str()); } } void simline_t::check_freight() { for(convoihandle_t const i : line_managed_convoys) { i->check_freight(); } } void simline_t::new_month() { recalc_status(); // then calculate maxspeed sint64 line_max_speed = 0, line_max_speed_count = 0; for(convoihandle_t const i : line_managed_convoys) { if (!i->in_depot()) { // since convoi stepped first, our history is in month 1 ... line_max_speed += i->get_finance_history(1, convoi_t::CONVOI_MAXSPEED); line_max_speed_count ++; } } // to avoid div by zero if( line_max_speed_count ) { line_max_speed /= line_max_speed_count; } financial_history[0][LINE_MAXSPEED] = line_max_speed; // now roll history for (int j = 0; j0; k--) { financial_history[k][j] = financial_history[k-1][j]; } financial_history[0][j] = 0; } financial_history[0][LINE_CONVOIS] = count_convoys(); } void simline_t::init_financial_history() { MEMZERO(financial_history); } /* * the current state saved as color * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete) */ void simline_t::recalc_status() { if(financial_history[0][LINE_CONVOIS]==0) { // no convois assigned to this line state_color = SYSCOL_EMPTY; withdraw = false; } else if(financial_history[0][LINE_PROFIT]<0) { // ok, not performing best state_color = MONEY_MINUS; } else if((financial_history[0][LINE_OPERATIONS]|financial_history[1][LINE_OPERATIONS])==0) { // nothing moved state_color = SYSCOL_TEXT_UNUSED; } else if(welt->use_timeline()) { // convois has obsolete vehicles? bool has_obsolete = false; for(convoihandle_t const i : line_managed_convoys) { has_obsolete = i->has_obsolete_vehicles(); if (has_obsolete) break; } // now we have to set it state_color = has_obsolete ? SYSCOL_OBSOLETE : SYSCOL_TEXT; } else { // normal state state_color = SYSCOL_TEXT; } } // recalc what good this line is moving void simline_t::recalc_catg_index() { // first copy old minivec_tpl old_goods_catg_index(goods_catg_index.get_count()); for(uint8 const i : goods_catg_index) { old_goods_catg_index.append(i); } goods_catg_index.clear(); withdraw = !line_managed_convoys.empty(); // then recreate current for(convoihandle_t const i : line_managed_convoys) { // what goods can this line transport? convoi_t const& cnv = *i; withdraw &= cnv.get_withdraw(); for(uint8 const catg_index : cnv.get_goods_catg_index()) { goods_catg_index.append_unique( catg_index ); } } // if different => schedule need recalculation if( goods_catg_index.get_count()!=old_goods_catg_index.get_count() ) { // surely changed welt->set_schedule_counter(); } else { // maybe changed => must test all entries for(uint8 const i : goods_catg_index) { if (!old_goods_catg_index.is_contained(i)) { // different => recalc welt->set_schedule_counter(); break; } } } } void simline_t::set_withdraw( bool yes_no ) { withdraw = yes_no && !line_managed_convoys.empty(); // convois in depots will be immediately destroyed, thus we go backwards for (size_t i = line_managed_convoys.get_count(); i-- != 0;) { line_managed_convoys[i]->set_no_load(yes_no); // must be first, since set withdraw might destroy convoi if in depot! line_managed_convoys[i]->set_withdraw(yes_no); } } sint64 simline_t::get_stat_converted(int month, int cost_type) const { sint64 value = financial_history[month][cost_type]; switch(cost_type) { case LINE_REVENUE: case LINE_OPERATIONS: case LINE_PROFIT: case LINE_WAYTOLL: value = convert_money(value); break; default: ; } return value; } simutrans-124.3/src/simutrans/simline.h000066400000000000000000000116521474050137200202050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMLINE_H #define SIMLINE_H #include "simtypes.h" #include "simcolor.h" #include "convoihandle.h" #include "linehandle.h" #include "tpl/minivec_tpl.h" #include "tpl/vector_tpl.h" #include "utils/plainstring.h" #define MAX_MONTHS 12 // Max history #define LINE_CAPACITY 0 // the amount of ware that could be transported, theoretically #define LINE_TRANSPORTED_GOODS 1 // the amount of ware that has been transported #define LINE_CONVOIS 2 // number of convois for this line #define LINE_REVENUE 3 // the income this line generated #define LINE_OPERATIONS 4 // the cost of operations this line generated #define LINE_PROFIT 5 // total profit of line #define LINE_DISTANCE 6 // distance covered by all convois #define LINE_MAXSPEED 7 // maximum speed for bonus calculation of all convois #define LINE_WAYTOLL 8 // way toll paid by vehicles of line #define MAX_LINE_COST 9 // Total number of cost items class karte_ptr_t; class loadsave_t; class player_t; class schedule_t; class simline_t { public: enum linetype { line = 0, truckline = 1, trainline = 2, shipline = 3, airline = 4, monorailline = 5, tramline = 6, maglevline = 7, narrowgaugeline = 8, MAX_LINE_TYPE }; protected: schedule_t * schedule; player_t *player; linetype type; bool withdraw; private: static karte_ptr_t welt; plainstring name; /** * Handle for ourselves. Can be used like the 'this' pointer * Initialized by constructors */ linehandle_t self; /** * the current state saved as color * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete) */ PIXVAL state_color; /** * a list of all convoys assigned to this line */ vector_tpl line_managed_convoys; /** * a list of all catg_index, which can be transported by this line. */ minivec_tpl goods_catg_index; /** * struct holds new financial history for line */ sint64 financial_history[MAX_MONTHS][MAX_LINE_COST]; /** * creates empty schedule with type depending on line-type */ void create_schedule(); void init_financial_history(); void recalc_status(); public: simline_t(player_t *player, linetype type); simline_t(player_t *player, linetype type, loadsave_t *file); ~simline_t(); linehandle_t get_handle() const { return self; } /** * add convoy to route */ void add_convoy(convoihandle_t cnv); /** * remove convoy from route */ void remove_convoy(convoihandle_t cnv); /** * get convoy */ convoihandle_t get_convoy(int i) const { return line_managed_convoys[i]; } /** * return number of manages convoys in this line */ uint32 count_convoys() const { return line_managed_convoys.get_count(); } vector_tpl const& get_convoys() const { return line_managed_convoys; } /** * returns the state of the line */ PIXVAL get_state_color() const { return state_color; } /** * return the schedule of the line */ schedule_t * get_schedule() const { return schedule; } void set_schedule(schedule_t* schedule); /** * get name of line */ char const* get_name() const { return name; } void set_name(const char *str); /* * load or save the line */ void rdwr(loadsave_t * file); /** * method to load/save linehandles */ static void rdwr_linehandle_t(loadsave_t *file, linehandle_t &line); /* * register line with stop */ void register_stops(schedule_t * schedule); void finish_rd(); /* * unregister line from stop */ void unregister_stops(schedule_t * schedule); void unregister_stops(); /* * renew line registration for stops */ void renew_stops(); // called after tiles are removed from stations to change the load of connected convois void check_freight(); sint64* get_finance_history() { return *financial_history; } sint64 get_finance_history(int month, int cost_type) const { return financial_history[month][cost_type]; } sint64 get_stat_converted(int month, int cost_type) const; void book(sint64 amount, int cost_type) { financial_history[0][cost_type] += amount; } static uint8 convoi_to_line_catgory(uint8 convoi_cost_type); void new_month(); linetype get_linetype() { return type; } static waytype_t linetype_to_waytype( const linetype lt ); static linetype waytype_to_linetype( const waytype_t wt ); static const char *get_linetype_name( const linetype lt ); const minivec_tpl &get_goods_catg_index() const { return goods_catg_index; } // recalculates the good transported by this line and (in case of changes) will start schedule recalculation void recalc_catg_index(); void set_withdraw( bool yes_no ); bool get_withdraw() const { return withdraw; } player_t *get_owner() const {return player;} }; #endif simutrans-124.3/src/simutrans/simlinemgmt.cc000066400000000000000000000126001474050137200212220ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simlinemgmt.h" #include "simline.h" #include "simconvoi.h" #include "gui/simwin.h" #include "world/simworld.h" #include "simtypes.h" #include "simintr.h" #include "dataobj/schedule.h" #include "dataobj/loadsave.h" #include "gui/line_management_gui.h" #include "player/simplay.h" simlinemgmt_t::~simlinemgmt_t() { destroy_win((ptrdiff_t)this); // and delete all lines ... while (!all_managed_lines.empty()) { linehandle_t line = all_managed_lines.back(); all_managed_lines.pop_back(); delete line.get_rep(); // detaching handled by line itself } } void simlinemgmt_t::add_line(linehandle_t new_line) { all_managed_lines.append(new_line); } void simlinemgmt_t::delete_line(linehandle_t line) { if (line.is_bound()) { while(line->count_convoys() ) { line->get_convoy(0)->set_line( linehandle_t() ); } all_managed_lines.remove(line); //destroy line object delete line.get_rep(); } } void simlinemgmt_t::update_line(linehandle_t line) { // when a line is updated, all managed convoys must get the new schedule! const int count = line->count_convoys(); for( int i = 0; iget_convoy(i); cnv->set_update_line(line); if( cnv->in_depot() ) { cnv->check_pending_updates(); // apply new schedule immediately for convoys in depot } } // finally de/register all stops line->renew_stops(); if( count>0 ) { world()->set_schedule_counter(); } } void simlinemgmt_t::rdwr(loadsave_t *file, player_t *player) { xml_tag_t l( file, "simlinemgmt_t" ); if(file->is_saving()) { // on old versions if( file->is_version_less(101, 0) ) { file->wr_obj_id("Linemanagement"); } // ensure that lines are saved in the same order on all clients sort_lines(); uint32 count = all_managed_lines.get_count(); file->rdwr_long(count); for(linehandle_t const i : all_managed_lines) { simline_t::linetype lt = i->get_linetype(); file->rdwr_enum(lt); i->rdwr(file); } } else { // on old versions if( file->is_version_less(101, 0) ) { char buf[80]; file->rd_obj_id(buf, 79); all_managed_lines.clear(); if(strcmp(buf, "Linemanagement")!=0) { dbg->fatal( "simlinemgmt_t::rdwr", "Broken Savegame" ); } } sint32 totalLines = 0; file->rdwr_long(totalLines); DBG_MESSAGE("simlinemgmt_t::rdwr()","number of lines=%i",totalLines); simline_t *unbound_line = NULL; for (int i = 0; irdwr_enum(lt); if(lt < simline_t::truckline || lt > simline_t::narrowgaugeline) { dbg->fatal( "simlinemgmt_t::rdwr()", "Cannot create default line!" ); } simline_t *line = new simline_t(player, lt, file); if (!line->get_handle().is_bound()) { // line id was saved as zero ... if (unbound_line) { dbg->fatal( "simlinemgmt_t::rdwr()", "More than one line with unbound id read" ); } else { unbound_line = line; } } else { add_line( line->get_handle() ); } } if( unbound_line ) { // linehandle will be corrected in simline_t::finish_rd line_with_id_zero = linehandle_t(unbound_line,true); add_line( line_with_id_zero ); } } } static bool compare_lines(linehandle_t const a, linehandle_t const b) { int diff = 0; char const* const na = a->get_name(); char const* const nb = b->get_name(); if (na[0] == '(' && nb[0] == '(') { diff = atoi(na + 1) - atoi(nb + 1); } if( diff==0 ) { diff = strcmp(na, nb); } if(diff==0) { diff = a.get_id() - b.get_id(); } return diff < 0; } void simlinemgmt_t::sort_lines() { std::sort(all_managed_lines.begin(), all_managed_lines.end(), compare_lines); } void simlinemgmt_t::finish_rd() { for(linehandle_t const i : all_managed_lines) { i->finish_rd(); } sort_lines(); } void simlinemgmt_t::rotate90( sint16 y_size ) { for(linehandle_t const i : all_managed_lines) { if (schedule_t* const schedule = i->get_schedule()) { schedule->rotate90( y_size ); } } } void simlinemgmt_t::new_month() { for(linehandle_t const i : all_managed_lines) { i->new_month(); } } linehandle_t simlinemgmt_t::create_line(int ltype, player_t * player) { if(ltype < simline_t::truckline || ltype > simline_t::narrowgaugeline) { dbg->fatal( "simlinemgmt_t::create_line()", "Cannot create default line!" ); } simline_t * line = new simline_t(player, (simline_t::linetype)ltype); add_line( line->get_handle() ); sort_lines(); return line->get_handle(); } linehandle_t simlinemgmt_t::create_line(int ltype, player_t * player, schedule_t * schedule) { linehandle_t line = create_line( ltype, player ); if(schedule) { line->get_schedule()->copy_from(schedule); } return line; } void simlinemgmt_t::get_lines(int type, vector_tpl* lines) const { lines->clear(); for(linehandle_t const line : all_managed_lines) { if (type == simline_t::line || line->get_linetype() == simline_t::line || line->get_linetype() == type) { lines->append(line); } } } void simlinemgmt_t::show_lineinfo(player_t *player, linehandle_t line, int which_tab) { if( line.is_bound() ) { gui_frame_t *line_info = win_get_magic( (ptrdiff_t)line.get_rep() ); if( line_info ) { top_win( line_info ); } else { create_win( new line_management_gui_t(line, player, which_tab), w_info, (ptrdiff_t)line.get_rep() ); } } } simutrans-124.3/src/simutrans/simlinemgmt.h000066400000000000000000000036171474050137200210740ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMLINEMGMT_H #define SIMLINEMGMT_H #include "linehandle.h" #include "simtypes.h" #include "tpl/vector_tpl.h" class loadsave_t; class schedule_t; class player_t; class schedule_list_gui_t; class simlinemgmt_t { public: ~simlinemgmt_t(); /** * add a line */ void add_line(linehandle_t new_line); /** * delete a line */ void delete_line(linehandle_t line); /** * update a line -> apply updated schedule to all convoys */ void update_line(linehandle_t line); /* * load or save the linemanagement */ void rdwr(loadsave_t * file, player_t * player); /* * sort the lines by name */ void sort_lines(); /* * will register all stops for all lines */ void register_all_stops(); /* * called after game is fully loaded; */ void finish_rd(); void rotate90( sint16 y_size ); void new_month(); /** * creates a line with an empty schedule */ linehandle_t create_line(int ltype, player_t * player); /** * Creates a line and sets its schedule */ linehandle_t create_line(int ltype, player_t * player, schedule_t * schedule); /** * If there was a line with id=0 map it to non-zero handle */ linehandle_t get_line_with_id_zero() const {return line_with_id_zero; } /* * fill the list with all lines of a certain type * type == simline_t::line will return all lines */ void get_lines(int type, vector_tpl* lines) const; uint32 get_line_count() const { return all_managed_lines.get_count(); } /** * Will open the line management window and offer information about the line */ void show_lineinfo(player_t *player, linehandle_t line, int which_tab ); vector_tpl const& get_line_list() const { return all_managed_lines; } private: vector_tpl all_managed_lines; linehandle_t line_with_id_zero; }; #endif simutrans-124.3/src/simutrans/simloadingscreen.cc000066400000000000000000000106741474050137200222340ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simloadingscreen.h" #include "sys/simsys.h" #include "descriptor/image.h" #include "descriptor/skin_desc.h" #include "simskin.h" #include "display/simgraph.h" #include "simevent.h" #include "dataobj/environment.h" #include "simticker.h" #include "gui/simwin.h" #include "gui/gui_theme.h" #include "tpl/slist_tpl.h" loadingscreen_t::loadingscreen_t( const char *w, uint32 max_p, bool logo, bool continueflag ) { what = w; info = NULL; progress = 0; max_progress = max_p; last_bar_len = -1; show_logo = logo; if( !is_display_init() || continueflag ) { return; } // darkens the current screen display_blend_wh_rgb(0, 0, display_get_width(), display_get_height(), color_idx_to_rgb(COL_BLACK), 50 ); mark_screen_dirty(); display_logo(); } // show the logo if requested and there void loadingscreen_t::display_logo() { if( show_logo && skinverwaltung_t::biglogosymbol ) { const image_t *image0 = skinverwaltung_t::biglogosymbol->get_image(0); const int w = image0->w; const int h = image0->h + image0->y; int x = display_get_width()/2-w; int y = display_get_height()/4-w; if(y<0) { y = 1; } display_color_img(skinverwaltung_t::biglogosymbol->get_image_id(0), x, y, 0, false, true); display_color_img(skinverwaltung_t::biglogosymbol->get_image_id(1), x+w, y, 0, false, true); display_color_img(skinverwaltung_t::biglogosymbol->get_image_id(2), x, y+h, 0, false, true); display_color_img(skinverwaltung_t::biglogosymbol->get_image_id(3), x+w, y+h, 0, false, true); } } // show everything but the logo void loadingscreen_t::display() { const int width = display_get_width(); const int half_width = width>>1; const int quarter_width = width>>2; const int half_height = display_get_height()>>1; scr_coord_val const bar_height = max(LINESPACE + 10, 20); scr_coord_val const bar_y = half_height - bar_height / 2 + 1; scr_coord_val const bar_text_y = half_height - LINESPACE / 2 + 1; const int bar_len = max_progress>0 ? (int) ( ((double)progress*(double)half_width)/(double)max_progress ) : 0; if( bar_len != last_bar_len ) { last_bar_len = bar_len; dr_prepare_flush(); if( info ) { display_proportional_rgb( half_width, bar_y - LINESPACE - 2, info, ALIGN_CENTER_H, color_idx_to_rgb(COL_WHITE), true ); } // outline display_ddd_box_rgb( quarter_width-2, bar_y, half_width+4, bar_height, color_idx_to_rgb(COL_GREY6), color_idx_to_rgb(COL_GREY4), true ); display_ddd_box_rgb( quarter_width-1, bar_y + 1, half_width+2, bar_height - 2, color_idx_to_rgb(COL_GREY4), color_idx_to_rgb(COL_GREY6), true ); // inner display_fillbox_wh_rgb( quarter_width, bar_y + 2, half_width, bar_height - 4, SYSCOL_LOADINGBAR_INNER, true); // progress display_fillbox_wh_rgb( quarter_width, bar_y + 4, bar_len, bar_height - 8, SYSCOL_LOADINGBAR_PROGRESS, true ); if( what ) { display_proportional_rgb( half_width, bar_text_y, what, ALIGN_CENTER_H, SYSCOL_TEXT_HIGHLIGHT, false ); } dr_flush(); } } void loadingscreen_t::set_progress( uint32 progress ) { if(!is_display_init() && (progress != this->progress || progress == 0) ) { return; } // first: handle events event_t *ev = new event_t; display_poll_event(ev); if( ev->ev_class == EVENT_SYSTEM ) { if( ev->ev_code == SYSTEM_RESIZE ) { // main window resized simgraph_resize( ev->new_window_size ); display_fillbox_wh_rgb( 0, 0, ev->mouse_pos.x, ev->mouse_pos.y, color_idx_to_rgb(COL_BLACK), true ); display_logo(); // queue the event anyway, so the viewport is correctly updated on world resume (screen will be resized again). queued_events.append(ev); } else if( ev->ev_code == SYSTEM_QUIT ) { // since the world is suspended (or may not even exists) when the loading screen is active // we can quit the quick way env_t::quit_simutrans = true; delete ev; } else { delete ev; } } else { if( ev->ev_class == EVENT_KEYBOARD ) { queued_events.append(ev); } else { delete ev; } } this->progress = progress; display(); if (progress > max_progress) { dbg->error("loadingscreen_t::set_progress", "too much progress: actual = %d max = %d", progress, max_progress); } } loadingscreen_t::~loadingscreen_t() { if(is_display_init()) { win_redraw_world(); mark_screen_dirty(); ticker::set_redraw_all(true); } while( !queued_events.empty() ) { queue_event( queued_events.remove_first() ); } } simutrans-124.3/src/simutrans/simloadingscreen.h000066400000000000000000000022051474050137200220650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMLOADINGSCREEN_H #define SIMLOADINGSCREEN_H #include "simtypes.h" #include "tpl/slist_tpl.h" struct event_t; /** * Implements the loading screen related routines, in the aim of centralize * all its code and make it more modular, as it was scattered across all code * before. * * @note The functions are safe on non-initialized displays, it won't try to write * on a not existent buffer. */ class loadingscreen_t { private: const char *what, *info; uint32 progress, max_progress; int last_bar_len; bool show_logo; slist_tpl queued_events; // show the logo if requested and there void display_logo(); // show everything but the logo void display(); public: loadingscreen_t( const char *what, uint32 max_progress, bool show_logo = false, bool continueflag = false ); ~loadingscreen_t(); void set_progress( uint32 progress ); void set_max( uint32 max ) { max_progress = max; } void set_info( const char *info ) { this->info = info; } void set_what( const char *what ) { this->what = what; } }; #endif simutrans-124.3/src/simutrans/simmain.cc000066400000000000000000001473551474050137200203520ustar00rootroot00000000000000/* This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #if defined(_M_X64) || defined(__x86_64__) #if __GNUC__ #warning "Simutrans is preferably compiled as 32 bit binary!" #endif #endif #if defined(_MSC_VER) && defined(DEBUG) // Console window on MSVC debug builds #pragma comment(linker, "/SUBSYSTEM:CONSOLE") #endif #include #include #include #include "pathes.h" #include "simmain.h" #include "world/simworld.h" #include "simware.h" #include "display/simview.h" #include "gui/simwin.h" #include "gui/gui_theme.h" #include "gui/messagebox.h" #include "simhalt.h" #include "display/simimg.h" #include "simcolor.h" #include "simskin.h" #include "simconst.h" #include "ground/boden.h" #include "ground/wasser.h" #include "world/simcity.h" #include "player/simplay.h" #include "simsound.h" #include "simintr.h" #include "simloadingscreen.h" #include "simticker.h" #include "simmesg.h" #include "tool/simmenu.h" #include "siminteraction.h" #include "simtypes.h" #include "simachievements.h" #include "sys/simsys.h" #include "display/simgraph.h" #include "simevent.h" #include "simversion.h" #include "gui/banner.h" #include "gui/pakselector.h" #include "gui/pakinstaller.h" #include "gui/welt.h" #include "gui/help_frame.h" #include "gui/sprachen.h" #include "gui/climates.h" #include "gui/messagebox.h" #include "gui/loadsave_frame.h" #include "gui/loadfont_frame.h" #include "gui/load_relief_frame.h" #include "gui/scenario_frame.h" #include "obj/baum.h" #include "obj/wolke.h" #include "utils/simstring.h" #include "utils/searchfolder.h" #include "io/rdwr/compare_file_rd_stream.h" #include "network/network.h" // must be before any "windows.h" is included via bzlib2.h ... #include "dataobj/loadsave.h" #include "dataobj/environment.h" #include "dataobj/tabfile.h" #include "dataobj/scenario.h" #include "dataobj/settings.h" #include "dataobj/translator.h" #include "network/pakset_info.h" #include "descriptor/reader/obj_reader.h" #include "descriptor/sound_desc.h" #include "descriptor/ground_desc.h" #include "music/music.h" #include "sound/sound.h" #include "utils/cbuffer.h" #include "utils/simrandom.h" #include "utils/unicode.h" #include "builder/vehikelbauer.h" #include "script/script_tool_manager.h" #include "vehicle/vehicle.h" #include "vehicle/simroadtraffic.h" #ifdef STEAM_BUILT #include "../steam/steam.h" #endif using std::string; #ifdef DEBUG /* diagnostic routine: * show the size of several internal structures */ static void show_sizes() { log_t::level_t old_level = env_t::verbose_debug; env_t::verbose_debug = log_t::LEVEL_MSG; DBG_MESSAGE("Debug", "size of structures"); DBG_MESSAGE("sizes", "size of pointer %i", sizeof(void*)); DBG_MESSAGE("sizes", "koord: %d", sizeof(koord)); DBG_MESSAGE("sizes", "koord3d: %d", sizeof(koord3d)); DBG_MESSAGE("sizes", "ribi_t::ribi: %d", sizeof(ribi_t::ribi)); DBG_MESSAGE("sizes", "halthandle_t: %d\n", sizeof(halthandle_t)); DBG_MESSAGE("sizes", "obj_t: %d", sizeof(obj_t)); DBG_MESSAGE("sizes", "gebaeude_t: %d", sizeof(gebaeude_t)); DBG_MESSAGE("sizes", "baum_t: %d", sizeof(baum_t)); DBG_MESSAGE("sizes", "wolke_t: %d", sizeof(wolke_t)); DBG_MESSAGE("sizes", "weg_t: %d", sizeof(weg_t)); DBG_MESSAGE("sizes", "private_car_t: %d\n", sizeof(private_car_t)); DBG_MESSAGE("sizes", "objlist_t: %d", sizeof(objlist_t)); DBG_MESSAGE("sizes", "grund_t: %d", sizeof(grund_t)); DBG_MESSAGE("sizes", "boden_t: %d", sizeof(boden_t)); DBG_MESSAGE("sizes", "wasser_t: %d", sizeof(wasser_t)); DBG_MESSAGE("sizes", "planquadrat_t: %d\n", sizeof(planquadrat_t)); DBG_MESSAGE("sizes", "planquadrat_t[100]: %d\n", sizeof(planquadrat_t[100])); DBG_MESSAGE("sizes", "ware_t: %d", sizeof(ware_t)); DBG_MESSAGE("sizes", "vehicle_t: %d", sizeof(vehicle_t)); DBG_MESSAGE("sizes", "haltestelle_t: %d\n", sizeof(haltestelle_t)); DBG_MESSAGE("sizes", "karte_t: %d", sizeof(karte_t)); DBG_MESSAGE("sizes", "player_t: %d\n", sizeof(player_t)); env_t::verbose_debug = old_level; } #endif #if defined DEBUG || defined PROFILE // render tests ... static void show_times(karte_t *welt, main_view_t *view) { intr_set_view(view); welt->set_fast_forward(true); intr_disable(); dbg->message( "show_times()", "simple profiling of drawing routines" ); int i; image_id img = ground_desc_t::outside->get_image(0,0); display_color_img(img, 120, 100, 1, 0, 1); uint32 ms = dr_time(); for (i = 0; i < 6000000; i++) { display_img_aux( img, 50, 50, 1, 0, true CLIP_NUM_DEFAULT); } dbg->message("show_times()", "display_img() %i iterations took %li ms", i, dr_time() - ms ); image_id player_img = skinverwaltung_t::color_options->get_image_id(0); ms = dr_time(); for (i = 0; i < 1000000; i++) { display_color_img( player_img, 120, 100, i%15, 0, 1); } dbg->message("show_times()", "display_color_img() with recolor %i iterations took %li ms", i, dr_time() - ms ); ms = dr_time(); for (i = 0; i < 100000; i++) { display_color_img( img, 120, 100, 0, 1, 1); display_color_img( player_img, 160, 150, 16, 1, 1); } dbg->message("show_times()", "display_color_img() 3x %i iterations took %li ms", i, dr_time() - ms ); #if !defined(MULTI_THREAD) ms = dr_time(); for (i = 0; i < 600000; i++) { dr_prepare_flush(); dr_flush(); } dbg->message("show_times()", "display_flush_buffer() %i iterations took %li ms", i, dr_time() - ms ); #endif ms = dr_time(); for (i = 0; i < 300000; i++) { display_text_proportional_len_clip_rgb(100, 120, "Dies ist ein kurzer Textetxt ...", 0, 0, false, -1); } dbg->message("show_times()", "display_text_proportional_len_clip_rgb() %i iterations took %li ms", i, dr_time() - ms ); ms = dr_time(); for (i = 0; i < 300000; i++) { display_fillbox_wh_rgb(100, 120, 300, 50, 0, false); } dbg->message("show_times()", "display_fillbox_wh_rgb() %i iterations took %li ms", i, dr_time() - ms ); ms = dr_time(); for (i = 0; i < 2000; i++) { view->display(true); } dbg->message("show_times()", "view->display(true) %i iterations took %li ms", i, dr_time() - ms ); ms = dr_time(); for (i = 0; i < 2000; i++) { view->display(true); win_display_flush(0.0); } dbg->message("show_times()", "view->display(true) and flush %i iterations took %li ms", i, dr_time() - ms ); ms = dr_time(); for (i = 0; i < 40000000/(int)weg_t::get_alle_wege().get_count(); i++) { for(weg_t * const w : weg_t::get_alle_wege() ) { grund_t *dummy; welt->lookup( w->get_pos() )->get_neighbour( dummy, invalid_wt, ribi_t::north ); } } dbg->message("show_times()", "grund_t::get_neighbour() %i iterations took %li ms", i*weg_t::get_alle_wege().get_count(), dr_time() - ms ); ms = dr_time(); for (i = 0; i < 1000; i++) { welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->sync_step(100); welt->display(1000); welt->step(); } dbg->message("show_times()", "welt->sync_step(200)*10/display(1000)/step %i iterations took %li ms", i, dr_time() - ms); ms = dr_time(); for (i = 0; i < 2000; i++) { welt->sync_step(200); welt->display(200); welt->step(); } dbg->message("show_times()", "welt->sync_step(200)/display(200)/step %i iterations took %li ms", i, dr_time() - ms ); } #endif // some routines for the modal display static bool never_quit() { return false; } static bool no_language() { return translator::get_language()!=-1; } static utf16 testfor_this_character = 0; static bool no_font() { return has_character(testfor_this_character); } #if COLOUR_DEPTH != 0 static bool empty_objfilename() { return !env_t::pak_name.empty() || pakinstaller_t::finish_install; } static bool finish_install() { return pakinstaller_t::finish_install; } #endif #if COLOUR_DEPTH != 0 /** * Show pak installer */ static void install_objfilename() { DBG_DEBUG("", "env_t::reload_and_save_on_quit=%d", env_t::reload_and_save_on_quit); #if !defined(USE_OWN_PAKINSTALL) && defined(_WIN32) dr_download_pakset( env_t::base_dir, strcmp( env_t::base_dir, env_t::user_dir)==0 ); // windows #else pakinstaller_t* sel = new pakinstaller_t(); // notify gui to load list of paksets event_t ev; ev.ev_class = INFOWIN; ev.ev_code = WIN_OPEN; sel->infowin_event(&ev); destroy_all_win(true); // since eventually the successful load message is still there .... modal_dialogue(sel, magic_none, NULL, finish_install); #endif } /** * Show pak selector */ static sint16 ask_objfilename() { pakselector_t* sel = new pakselector_t(); // notify gui to load list of paksets event_t ev; ev.ev_class = INFOWIN; ev.ev_code = WIN_OPEN; sel->infowin_event(&ev); sint16 entries = sel->get_entries_count(); if(sel->has_pak()) { destroy_all_win(true); // since eventually the successful load message is still there .... modal_dialogue( sel, magic_none, NULL, empty_objfilename ); } else { delete sel; } return entries; } #endif /** * Show language selector */ static void ask_language() { if( display_get_width()==0 ) { // only console available ... => choose english for the moment dbg->warning( "ask_language", "No language selected, will use english!" ); translator::set_language( "en" ); } else { sprachengui_t* sel = new sprachengui_t(); destroy_all_win(true); // since eventually the successful load message is still there .... modal_dialogue( sel, magic_none, NULL, no_language ); destroy_win( sel ); } } /** * This function will be set in the main function as the handler the runtime environment will * call in the case it lacks memory for new() */ NORETURN static void sim_new_handler() { dbg->fatal("sim_new_handler()", "OUT OF MEMORY"); } /// Helper class for retrieving command line arguments struct args_t { public: args_t(int argc, char **argv) : argc(argc), argv(argv) {} public: const char *gimme_arg(const char *arg, int off) const { for( int i = 1; i < argc; i++ ) { if(strcmp(argv[i], arg) == 0 && i < argc - off ) { return argv[i + off]; } } return NULL; } bool has_arg(const char *arg) const { return gimme_arg(arg, 0) != NULL; } private: int argc; char **argv; }; void print_help() { printf( "\n" "---------------------------------------\n" " Simutrans " VERSION_NUMBER "\n" " released " VERSION_DATE "\n" " developed\n" " by the Simutrans team.\n" "\n" " Send feedback and questions to:\n" " \n" "\n" " Based on Simutrans 0.84.21.2\n" " by Hansjörg Malthaner et. al.\n" "---------------------------------------\n" "command line parameters available: \n" " -addons loads also addons (with -objects)\n" " -async asynchronous images, only for SDL\n" " -borderless emulate fullscreen as borderless window\n" " -use_hw hardware double buffering, only for SDL\n" " -debug NUM enables debugging (1..5)\n" " -easyserver set up every for server (query own IP, port forwarding)\n" " -freeplay play with endless money\n" " -fullscreen starts simutrans in fullscreen mode\n" " -fps COUNT framerate (from 5 to 100)\n" " -h | -help | --help displays this help\n" " -lang CODE starts with specified language\n" " -load NAME loads savegame with name 'NAME' from Simutrans 'save' directory\n" " -log enables logging to file 'simu.log'\n" #ifdef SYSLOG " -syslog enable logging to syslog\n" " mutually exclusive with -log\n" " -tag TAG sets syslog tag (default 'simutrans')\n" #endif " -mute mute all sounds\n" " -noaddons does not load any addon (default)\n" " -nomidi turns off background music\n" " -nosound turns off ambient sounds\n" " -objects DIR_NAME/ load the pakset in specified directory\n" " -pause starts game with paused after loading\n" " a server will pause if there are no clients\n" " -res N starts in specified resolution: \n" " 1=640x480, 2=800x600, 3=1024x768, 4=1280x1024\n" " -scenario NAME Load scenario NAME\n" " -screensize WxH set screensize to width W and height H\n" " -server [PORT] starts program as server (for network game)\n" " without port specified uses 13353\n" " -announce Enable server announcements\n" " -autodpi Automatic screen scaling for high DPI screens\n" " -screen_scale N Manual screen scaling to N percent (0=off)\n" " Ignored when -autodpi is specified\n" " -server_dns FQDN/IP FQDN or IP address of server for announcements\n" " -server_name NAME Name of server for announcements\n" " -server_admin_pw PW password for server administration\n" " -heavy NUM enables heavy-mode debugging for network games. VERY SLOW!\n" " -set_basedir WD Use WD as directory containing all constant data.\n" " -set_installdir WD Use WD as directory for pakset download.\n" " -set_userdir WD Use WD as directory for local user data.\n" " -singleuser Save everything in data directory (portable version)\n" #ifdef DEBUG " -sizes Show current size of some structures\n" #endif " -startyear N start in year N\n" " -theme N user directory containing theme files\n" #ifdef MULTI_THREAD " -threads N use N threads if possible\n" #endif " -timeline enables timeline\n" #if defined DEBUG || defined PROFILE " -times does some simple profiling\n" #endif " -until YEAR.MONTH quits when MONTH of YEAR starts\n" ); } void setup_logging(const args_t &args) { const char *version = "Simutrans version " VERSION_NUMBER " from " VERSION_DATE #ifdef REVISION " r" QUOTEME(REVISION) #endif #ifdef GIT_HASH " hash " QUOTEME(GIT_HASH) #endif "\n"; #ifdef SYSLOG bool cli_syslog_enabled = args.has_arg("-syslog"); const char* cli_syslog_tag = args.gimme_arg("-tag", 1); #else bool cli_syslog_enabled = false; const char* cli_syslog_tag = NULL; #endif env_t::verbose_debug = log_t::LEVEL_FATAL; if( args.has_arg("-debug") ) { const char *s = args.gimme_arg("-debug", 1); log_t::level_t level = log_t::LEVEL_DEBUG; if(s!=NULL && s[0]>='0' && s[0]<='9' ) { level = (log_t::level_t)clamp(atoi(s), (int)log_t::LEVEL_FATAL, (int)log_t::LEVEL_DEBUG); } env_t::verbose_debug = level; } if ( cli_syslog_enabled ) { printf("syslog enabled\n"); if ( cli_syslog_tag ) { printf("Init logging with syslog tag: %s\n", cli_syslog_tag); init_logging( "syslog", true, true, version, cli_syslog_tag ); } else { printf("Init logging with default syslog tag\n"); init_logging( "syslog", true, true, version, "simutrans" ); } } else if (args.has_arg("-log")) { dr_chdir( env_t::user_dir ); char temp_log_name[256]; const char *logname = "simu.log"; if( args.has_arg("-server") ) { const char *p = args.gimme_arg("-server", 1); int portadress = p ? atoi( p ) : 13353; sprintf( temp_log_name, "simu-server%d.log", portadress==0 ? 13353 : portadress ); logname = temp_log_name; } init_logging( logname, true, true, version, NULL ); } else if (args.has_arg("-debug")) { init_logging( "stderr", true, true, version, NULL ); } else { init_logging(NULL, false, false, version, NULL); } } // search for this in all possible pakset locations for the directory chkdir and take the first match static bool set_pakdir( const char *chkdir ) { if( !chkdir || !*chkdir ) { return false; } char tmp[PATH_MAX]; dr_chdir( env_t::base_dir ); if( !dr_chdir( chkdir ) ) { dr_getcwd(tmp, lengthof(tmp)); env_t::pak_dir = tmp; env_t::pak_dir += PATH_SEPARATOR; return true; } dr_chdir( env_t::install_dir ); if( !dr_chdir( chkdir ) ) { dr_getcwd(tmp, lengthof(tmp)); env_t::pak_dir = tmp; env_t::pak_dir += PATH_SEPARATOR; return true; } dr_chdir( env_t::user_dir ); if(!dr_chdir( USER_PAK_PATH ) ) { if( !dr_chdir( chkdir ) ) { dr_getcwd(tmp, lengthof(tmp)); env_t::pak_dir = tmp; env_t::pak_dir += PATH_SEPARATOR; return true; } } return false; } int simu_main(int argc, char** argv) { std::set_new_handler(sim_new_handler); args_t args(argc, argv); #ifdef DEBUG if (args.has_arg("-debug")) { // debug init messages env_t::verbose_debug = log_t::LEVEL_DEBUG; init_logging("stderr", true, true, "Preinit", NULL); } #endif env_t::init(); // you really want help with this? if (args.has_arg("-h") || args.has_arg("-?") || args.has_arg("-help") || args.has_arg("--help")) { print_help(); return EXIT_SUCCESS; } // only the specified pak conf should override this! uint16 pak_diagonal_multiplier = env_t::default_settings.get_pak_diagonal_multiplier(); sint8 pak_tile_height = TILE_HEIGHT_STEP; sint8 pak_height_conversion_factor = env_t::pak_height_conversion_factor; if( !dr_set_basedir(args.gimme_arg( "-set_basedir", 1 ), argv[0]) ) { dr_fatal_notify("Absolutely no base installation found.\nPlease download/install the complete base set!"); return EXIT_FAILURE; } dr_chdir( env_t::base_dir ); // parsing config/simuconf.tab to find out single user install bool found_settings = false; bool found_simuconf = false; bool not_portable = !args.has_arg("-singleuser"); // only parse global config, if not force to portable by switch tabfile_t simuconf; char path_to_simuconf[24]; // was config/simuconf.tab sprintf( path_to_simuconf, "config%ssimuconf.tab", PATH_SEPARATOR ); if( simuconf.open( path_to_simuconf ) ) { tabfileobj_t contents; simuconf.read( contents ); // use different save directories not_portable = !(contents.get_int( "singleuser_install", !not_portable )==1 || !not_portable); found_simuconf = true; simuconf.close(); } if( !check_and_set_dir( args.gimme_arg( "-set_installdir", 1 ), "-set_installdir", env_t::install_dir ) ) { if( !check_and_set_dir( getenv( "SIMUTRANS_INSTALLDIR" ), "SIMUTRANS_INSTALLDIR", env_t::install_dir ) ) { if( !not_portable ) { // portable installation strcpy( env_t::install_dir, env_t::base_dir ); } else { strcpy( env_t::install_dir, dr_query_installdir() ); } } } if( !check_and_set_dir( args.gimme_arg( "-set_userdir", 1 ), "-set_userdir", env_t::user_dir ) ) { if( !check_and_set_dir( getenv( "SIMUTRANS_USERDIR" ), "SIMUTRANS_USERDIR", env_t::user_dir ) ) { if( !not_portable ) { strcpy( env_t::user_dir, env_t::base_dir ); } else { strcpy( env_t::user_dir, dr_query_homedir() ); } } } // create directory and subdirectories dr_mkdir(env_t::install_dir); dr_mkdir(env_t::user_dir); // set portable, if base dir and user dir were same not_portable &= strcmp( env_t::user_dir, env_t::base_dir )!=0; dr_chdir( env_t::user_dir ); dr_mkdir("maps"); dr_mkdir(SAVE_PATH); dr_mkdir(SCREENSHOT_PATH); setup_logging(args); // now read last setting (might be overwritten by the tab-files) { loadsave_t settings_file; if( settings_file.rd_open("settings.xml") == loadsave_t::FILE_STATUS_OK ) { if( settings_file.get_version_int()>loadsave_t::int_version(SAVEGAME_VER_NR, NULL ) ) { // too new => remove it settings_file.close(); } else { found_settings = true; env_t::rdwr(&settings_file); env_t::default_settings.rdwr(&settings_file); settings_file.close(); // reset to false (otherwise these settings will persist) env_t::default_settings.reset_after_global_settings_reload(); env_t::server_announce = 0; } } } sint16 disp_width = 0; sint16 disp_height = 0; sint16 fullscreen = WINDOWED; // continue parsing dr_chdir( env_t::base_dir ); if( found_simuconf ) { if(simuconf.open(path_to_simuconf)) { // we do not allow to change the global font name std::string old_fontname = env_t::fontname; std::string old_soundfont_filename = env_t::soundfont_filename; dbg->message("simu_main()", "Parsing %s%s", env_t::base_dir, path_to_simuconf); env_t::default_settings.parse_simuconf( simuconf, disp_width, disp_height, fullscreen, env_t::pak_name ); simuconf.close(); if( (old_soundfont_filename.length() > 0) && (strcmp( old_soundfont_filename.c_str(), "Error" ) != 0) ) { // We had a valid soundfont saved by the user, let's restore it env_t::soundfont_filename = old_soundfont_filename; } env_t::fontname = old_fontname; } } // a portable installation could have a personal simuconf.tab in the main dir of simutrans // otherwise it is in ~/simutrans/simuconf.tab env_t::pak_dir.clear(); env_t::pak_name.clear(); string obj_conf = string(env_t::user_dir) + "simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { dbg->message("simu_main()", "Parsing %s", obj_conf.c_str()); env_t::default_settings.parse_simuconf( simuconf, disp_width, disp_height, fullscreen, env_t::pak_name ); if( set_pakdir( env_t::pak_name.c_str() ) ) { env_t::pak_name += PATH_SEPARATOR; } simuconf.close(); } // env: override previous settings if( args.has_arg("-freeplay") ) { env_t::default_settings.set_freeplay( true ); } #ifdef __ANDROID__ // always save and reload on Android env_t::reload_and_save_on_quit = true; #elif defined(STEAM_BUILT) && STEAM_BUILT != 0 steam_t::get_instance()->install_workshop_items(); #endif // now set the desired objectfilename (override all previous settings) if( const char *fn = args.gimme_arg("-set_pakdir", 1) ) { if(!set_pakdir(fn)) { // try as absolute path char tmp[PATH_MAX]; if( check_and_set_dir( fn, "-set_pakdir", tmp, "config/menuconf.tab" ) ) { env_t::pak_dir = tmp; // to be done => extrat pak name!!! const char *last_pathsep=0; for( char *c=tmp; c[0]>0; c++ ) { if( *c==*PATH_SEPARATOR ) { if( c[1]==0 ) { c[0] = 0; break; } last_pathsep = c+1; } } if( last_pathsep ) { env_t::pak_name = last_pathsep; } } } else { env_t::pak_name = fn; env_t::pak_name += PATH_SEPARATOR; } } if( env_t::pak_dir.empty() ) { // old style (deprecated) if( const char* pak = args.gimme_arg( "-objects", 1 ) ) { if( set_pakdir( pak ) ) { env_t::pak_name = pak; if (env_t::pak_name.back() == '/') { env_t::pak_name.pop_back(); } env_t::pak_name += PATH_SEPARATOR; } } } if( env_t::pak_name.empty() ) { if( const char *filename = args.gimme_arg("-load", 1) ) { // try to get a pak file path from a savegame file // read pak_extension from file loadsave_t test; std::string fn = env_t::user_dir; fn += "save/"; fn += filename; if( test.rd_open(fn.c_str()) == loadsave_t::FILE_STATUS_OK ) { // add pak extension const char *pak = test.get_pak_extension(); if( strcmp(pak,"(unknown)")!=0 ) { if( set_pakdir( pak ) ) { env_t::pak_name = pak; env_t::pak_name += PATH_SEPARATOR; } } } } } dr_chdir( env_t::base_dir ); // starting a server? if( args.has_arg("-easyserver") ) { const char *p = args.gimme_arg("-easyserver", 1); int portadress = p ? atoi( p ) : 13353; if( portadress!=0 ) { env_t::server_port = portadress; } // will fail fatal on the opening routine ... dbg->message( "simu_main()", "Server started on port %i", env_t::server_port ); env_t::networkmode = network_init_server( env_t::server_port, env_t::listen ); // query IP and try to open ports on router char IP[256], altIP[256]; altIP[0] = 0; if( prepare_for_server( IP, altIP, env_t::server_port ) ) { // we have forwarded a port in router, so we can continue env_t::server_dns = IP; if( env_t::server_name.empty() ) { env_t::server_name = std::string("Server at ")+IP; } env_t::server_announce = 1; env_t::easy_server = 1; env_t::server_dns = IP; env_t::server_alt_dns = altIP; } } // starting a server? if( !env_t::server ) { if( args.has_arg("-server") ) { const char *p = args.gimme_arg("-server", 1); int portadress = p ? atoi( p ) : 13353; if( portadress!=0 ) { env_t::server_port = portadress; } // will fail fatal on the opening routine ... dbg->message( "simu_main()", "Server started on port %i", env_t::server_port ); env_t::networkmode = network_init_server( env_t::server_port, env_t::listen ); } else { // no announce for clients ... env_t::server_announce = 0; } } // enabling heavy-mode for debugging network games env_t::network_heavy_mode = 0; if( args.has_arg("-heavy") ) { int heavy = atoi(args.gimme_arg("-heavy", 1)); env_t::network_heavy_mode = clamp(heavy, 0, 2); } DBG_MESSAGE("simu_main()", "Version: " VERSION_NUMBER " Date: " VERSION_DATE); DBG_MESSAGE("simu_main()", "Debuglevel: %i", env_t::verbose_debug); DBG_MESSAGE("simu_main()", "base_dir: %s", env_t::base_dir); DBG_MESSAGE("simu_main()", "install_dir: %s", env_t::install_dir); DBG_MESSAGE("simu_main()", "user_dir: %s", env_t::user_dir); DBG_MESSAGE("simu_main()", "locale: %s", dr_get_locale_string()); #ifdef DEBUG if (args.has_arg("-sizes")) { // show the size of some structures ... show_sizes(); } #endif static const sint16 resolutions[][2] = { { 640, 480 }, { 800, 600 }, { 1024, 768 }, { 1280, 1024 }, { 704, 560 } // try to force window mode with allegro }; // likely only the program without graphics was downloaded if (args.has_arg("-res")) { const char* res_str = args.gimme_arg("-res", 1); const int res = *res_str - '1'; switch (res) { case 0: case 1: case 2: case 3: case 4: case 5: fullscreen = (res<=4); disp_width = resolutions[res][0]; disp_height = resolutions[res][1]; break; default: fprintf(stderr, "Invalid resolution, argument must be in 1..5\n" "1=640x480, 2=800x600, 3=1024x768, 4=1280x1024, 5=windowed\n" ); return EXIT_FAILURE; } } if ( !fullscreen ) { fullscreen = args.has_arg("-fullscreen") ? FULLSCREEN : WINDOWED; } if ( !fullscreen ) { fullscreen = args.has_arg("-borderless") ? BORDERLESS : WINDOWED; } if ( !fullscreen ) { fullscreen = env_t::fullscreen; } if(args.has_arg("-screensize")) { const char* res_str = args.gimme_arg("-screensize", 1); int n = 0; if (res_str != NULL) { n = sscanf(res_str, "%hdx%hd", &disp_width, &disp_height); } if (n != 2) { fprintf(stderr, "Invalid argument for -screensize option\n" "Argument must be of format like 800x600\n" ); return EXIT_FAILURE; } } int parameter[2]; parameter[0] = args.has_arg("-async"); parameter[1] = args.has_arg("-use_hw"); if (!dr_os_init(parameter)) { dr_fatal_notify("Failed to initialize backend.\n"); return EXIT_FAILURE; } if (args.has_arg("-autodpi")) { dr_set_screen_scale(-1); } else if (const char* scaling = args.gimme_arg("-screen_scale", 1)) { if (scaling[0] >= '0' && scaling[0] <= '9') { dr_set_screen_scale(atoi(scaling)); } } // Get optimal resolution. if (disp_width == 0 || disp_height == 0) { resolution const res = dr_query_screen_resolution(); if (fullscreen != WINDOWED) { disp_width = res.w; disp_height = res.h; } else { disp_width = min(704, res.w); disp_height = min(560, res.h); } } DBG_MESSAGE("simu_main()", "simgraph_init disp_width=%d, disp_height=%d, fullscreen=%d", disp_width, disp_height, fullscreen); if (!simgraph_init(scr_size(disp_width, disp_height), fullscreen)) { dbg->error("simu_main()", "Failed to initialize graphics system."); return EXIT_FAILURE; } DBG_MESSAGE("simu_main()", ".. results in disp_width=%d, disp_height=%d", display_get_width(), display_get_height()); // now that the graphics system has already started // the saved colours can be converted to the system format env_t_rgb_to_system_colors(); // parse colours now that the graphics system has started // default simuconf.tab if( found_simuconf ) { if(simuconf.open(path_to_simuconf)) { dbg->message("simu_main()", "Loading colours from %sconfig/simuconf.tab", env_t::base_dir); // we do not allow to change the global font name also from the pakset ... std::string old_fontname = env_t::fontname; env_t::default_settings.parse_colours( simuconf ); simuconf.close(); env_t::fontname = old_fontname; } } // a portable installation could have a personal simuconf.tab in the main dir of simutrans // otherwise it is in ~/simutrans/simuconf.tab obj_conf = string(env_t::user_dir) + "simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { dbg->message("simu_main()", "Parsing %s", obj_conf.c_str() ); env_t::default_settings.parse_colours( simuconf ); simuconf.close(); } // prepare skins first bool themes_ok = false; if (const char* themestr = args.gimme_arg("-theme", 1)) { dr_chdir(env_t::user_dir); dr_chdir("themes"); themes_ok = gui_theme_t::themes_init(themestr, true, false); if (!themes_ok) { dr_chdir(env_t::base_dir); dr_chdir("themes"); themes_ok = gui_theme_t::themes_init(themestr, true, false); } } // next try the last used theme skinverwaltung_t::save_all_skins(); // save empty to have the pakset default if( !themes_ok && env_t::default_theme.c_str()!=NULL ) { dr_chdir( env_t::user_dir ); dr_remove("settings_old.xml"); dr_rename("settings.xml", "settings_old.xml"); // or we are stuck on a broken theme forever dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme, true, false ); if( !themes_ok ) { dr_chdir( env_t::base_dir ); dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme, true, false ); } dr_rename("settings_old.xml", "settings.xml"); // or we are stuck on a broken theme forever } // specified themes not found => try default themes #if COLOUR_DEPTH != 0 if( !themes_ok ) { dr_chdir( env_t::base_dir ); dr_chdir( "themes" ); #ifndef __ANDROID__ themes_ok = gui_theme_t::themes_init("themes.tab",true,false); #else themes_ok = gui_theme_t::themes_init("theme-large.tab", true, false); #endif } if( !themes_ok ) { dbg->fatal( "simu_main()", "No GUI themes found! Please re-install!" ); } dr_chdir( env_t::base_dir ); // The loading screen needs to be initialized display_show_pointer(1); // if no object files given, we ask the user int retries=0; while( env_t::pak_name.empty() && retries < 2 ) { if( ask_objfilename() == 0 ) { retries++; } if( env_t::quit_simutrans ) { simgraph_exit(); return EXIT_SUCCESS; } else if (env_t::pak_name.empty()) { // try to download missing paks install_objfilename(); // all other } } #else // headless server dr_chdir( env_t::base_dir ); if( env_t::pak_name.empty() ) { dr_fatal_notify( "*** No pak set found ***\n" "\n" "Please install a pak set and select it using the '-objects'\n" "command line parameter or the 'pak_file_path' simuconf.tab entry."); simgraph_exit(); return EXIT_FAILURE; } #endif // check for valid pak path { FILE* const f = dr_fopen((env_t::pak_dir+"ground.Outside.pak").c_str(), "r"); if( !f ) { cbuffer_t errmsg; errmsg.printf( "The file 'ground.Outside.pak' was not found in\n" "'%s'.\n" "This file is required for a valid pak set (graphics).\n" "Please install and select a valid pak set.", env_t::pak_dir.c_str()); dr_fatal_notify(errmsg); simgraph_exit(); return EXIT_FAILURE; } fclose(f); } // now find the pak specific tab file ... obj_conf = env_t::pak_dir + "config" + PATH_SEPARATOR + "simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { env_t::default_settings.set_way_height_clearance( 0 ); uint8 show_month = env_t::env_t::show_month; dbg->message("simu_main()", "Parsing %s", obj_conf.c_str()); env_t::default_settings.parse_simuconf( simuconf ); env_t::default_settings.parse_colours( simuconf ); if (show_month != env_t::show_month) { dbg->warning("Parsing simuconf.tab", "Pakset %s defines show_month will be ignored!", env_t::pak_name.c_str()); } env_t::show_month = show_month; pak_diagonal_multiplier = env_t::default_settings.get_pak_diagonal_multiplier(); pak_height_conversion_factor = env_t::pak_height_conversion_factor; pak_tile_height = TILE_HEIGHT_STEP; if( env_t::default_settings.get_way_height_clearance() == 0 ) { // ok, set default as conversion factor env_t::default_settings.set_way_height_clearance( pak_height_conversion_factor ); } simuconf.close(); } // and parse again the user settings obj_conf = string(env_t::user_dir) + "simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { dbg->message("simu_main()", "Parsing %s", obj_conf.c_str()); env_t::default_settings.parse_simuconf( simuconf ); env_t::default_settings.parse_colours( simuconf ); simuconf.close(); } // load with private addons (now in addons/pak-name either in simutrans main dir or in userdir) if( args.gimme_arg("-objects", 1) || args.gimme_arg("-set_pakdir", 1) ) { if(args.has_arg("-addons")) { env_t::default_settings.set_with_private_paks( true ); } if(args.has_arg("-noaddons")) { env_t::default_settings.set_with_private_paks( false ); } } // parse ~/simutrans/pakxyz/config.tab" if( env_t::default_settings.get_with_private_paks() ) { obj_conf = string(env_t::user_dir) + "addons/" + env_t::pak_name + "config/simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { dbg->message("simu_main()", "Parsing %s", obj_conf.c_str()); env_t::default_settings.parse_simuconf( simuconf ); env_t::default_settings.parse_colours( simuconf ); simuconf.close(); } // and parse user settings again ... obj_conf = string(env_t::user_dir) + "simuconf.tab"; if (simuconf.open(obj_conf.c_str())) { dbg->message("simu_main()", "Parsing %s", obj_conf.c_str()); env_t::default_settings.parse_simuconf( simuconf ); env_t::default_settings.parse_colours( simuconf ); simuconf.close(); } } // now (re)set the correct length and other pak set only settings env_t::default_settings.set_pak_diagonal_multiplier( pak_diagonal_multiplier ); vehicle_base_t::set_diagonal_multiplier( pak_diagonal_multiplier, pak_diagonal_multiplier ); env_t::pak_height_conversion_factor = pak_height_conversion_factor; TILE_HEIGHT_STEP = pak_tile_height; convoihandle_t::init( 1024 ); linehandle_t::init( 1024 ); halthandle_t::init( 1024 ); #ifdef MULTI_THREAD // set number of threads if( const char *ref_str = args.gimme_arg("-threads", 1) ) { uint8 want_threads = atoi(ref_str); env_t::num_threads = clamp( want_threads, (uint8)1u, min(dr_get_max_threads(), MAX_THREADS) ); env_t::num_threads = min( env_t::num_threads, MAX_THREADS ); dbg->message("simu_main()","Requested %d threads.", env_t::num_threads ); } #else if( env_t::num_threads > 1 ) { env_t::num_threads = 1; dbg->message("simu_main()","Multithreading not enabled: threads = %d ignored.", env_t::num_threads ); } #endif // just check before loading objects if( !args.has_arg("-nosound") && dr_init_sound() ) { dbg->message("simu_main()","Reading compatibility sound data ..."); sound_desc_t::init(env_t::pak_dir); } else { sound_set_mute(true); } // Adam - Moved away loading from simu_main() and placed into translator for better modularization if( !translator::load() ) { // installation error: likely only program started dbg->fatal("simu_main()", "Unable to load any language files\n" "*** PLEASE INSTALL PROPER BASE FILES ***\n" "\n" "either run ./get_lang_files.sh\n" "\n" "or\n" "\n" "download a complete simutrans archive and put the text/ folder here." ); } // use requested language (if available) if( args.gimme_arg("-lang", 1) ) { const char *iso = args.gimme_arg("-lang", 1); if( strlen(iso)>=2 ) { translator::set_language( iso ); } if( translator::get_language()==-1 ) { dbg->fatal("simu_main()", "Illegal language definition \"%s\"", iso ); } env_t::language_iso = translator::get_lang()->iso_base; } else if( found_settings ) { translator::set_language( env_t::language_iso ); } // simgraph_init loads default fonts, now we need to load (if not set otherwise) // sprachengui_t::init_font_from_lang( strcmp(env_t::fontname.c_str(), FONT_PATH_X "prop.fnt")==0 ); dr_chdir(env_t::base_dir); dbg->message("simu_main()","Reading city configuration ..."); stadt_t::cityrules_init(); dbg->message("simu_main()","Reading speedbonus configuration ..."); vehicle_builder_t::speedbonus_init(); dbg->message("simu_main()","Reading menu configuration ..."); tool_t::init_menu(); // loading all objects in the pak skinverwaltung_t::restore_all_skins(); // restore empty skins to have the pakset default pakset_manager_t::load_pakset(env_t::default_settings.get_with_private_paks()); skinverwaltung_t::save_all_skins(); // save pakset default // load tool scripts dbg->message("simu_main()","Reading tool scripts ..."); dr_chdir( env_t::base_dir ); script_tool_manager_t::load_scripts((env_t::pak_dir + "tool/").c_str()); if( env_t::default_settings.get_with_private_paks() ) { dr_chdir( env_t::user_dir ); script_tool_manager_t::load_scripts(("addons/" + env_t::pak_name + "tool/").c_str()); } dbg->message("simu_main()","Reading menu configuration ..."); dr_chdir( env_t::base_dir ); if (!tool_t::read_menu(env_t::pak_dir + "config/menuconf.tab")) { // Fatal error while reading menuconf.tab, we cannot continue! dbg->fatal( "Could not read %sconfig/menuconf.tab.\n" "This file is required for a valid pak set (graphics).\n" "Please install and select a valid pak set.", env_t::pak_dir.c_str()); } #if COLOUR_DEPTH != 0 // reread theme dr_chdir( env_t::user_dir ); dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme, true, false ); if( !themes_ok ) { dr_chdir( env_t::base_dir ); dr_chdir( "themes" ); themes_ok = gui_theme_t::themes_init( env_t::default_theme, true, false ); } #endif dr_chdir( env_t::base_dir ); if( translator::get_language()==-1 ) { // try current language const char* loc = dr_get_locale(); if( loc==NULL || !translator::set_language( loc ) ) { loc = dr_get_locale_string(); if( loc==NULL || !translator::set_language( loc ) ) { ask_language(); } else { sprachengui_t::init_font_from_lang(); } } else { sprachengui_t::init_font_from_lang(); } } #if COLOUR_DEPTH != 0 // now find out if there is a valid font { const utf8 *new_world = (const utf8 *)translator::translate("Beenden"); size_t len; testfor_this_character = utf8_decoder_t::decode(new_world,len); if (!has_character(testfor_this_character)) { // not valid => show font selector loadfont_frame_t* sel = new loadfont_frame_t(); destroy_all_win(true); // since eventually the successful load message is still there .... modal_dialogue(sel, magic_none, NULL, no_font); destroy_win(sel); } } #endif bool new_world = true; std::string loadgame; bool pause_after_load = false; if( args.has_arg("-pause") ) { if( env_t::server ) { env_t::pause_server_no_clients = true; } else { pause_after_load = true; } } if( args.has_arg("-load") ) { cbuffer_t buf; dr_chdir( env_t::user_dir ); /** * Added automatic adding of extension */ const char *name = args.gimme_arg("-load", 1); if (strstart(name, "net:")) { buf.append( name ); } else { buf.printf( SAVE_PATH_X "%s", searchfolder_t::complete(name, "sve").c_str() ); } dbg->message("simu_main()", "Loading savegame \"%s\"", name ); loadgame = buf; new_world = false; } // compare two savegames if (!new_world && strstart(loadgame.c_str(), "net:")==NULL && args.has_arg("-compare")) { cbuffer_t buf; dr_chdir( env_t::user_dir ); const char *name = args.gimme_arg("-compare", 1); buf.printf( SAVE_PATH_X "%s", searchfolder_t::complete(name, "sve").c_str() ); // open both files loadsave_t file1, file2; if (file1.rd_open(loadgame.c_str()) == loadsave_t::FILE_STATUS_OK && file2.rd_open(buf) == loadsave_t::FILE_STATUS_OK) { karte_t *welt = new karte_t(); compare_loadsave_t compare(&file1, &file2); welt->load(&compare); delete welt; file1.close(); file2.close(); } } // recover last server game if( new_world && env_t::server ) { dr_chdir( env_t::user_dir ); loadsave_t file; static char servername[128]; sprintf( servername, "server%d-network.sve", env_t::server ); // try recover with the latest savegame if( file.rd_open(servername) == loadsave_t::FILE_STATUS_OK ) { // compare pakset (objfilename has trailing path separator, pak_extension not) if (strstart(env_t::pak_name.c_str(), file.get_pak_extension())) { // same pak directory - load this loadgame = servername; new_world = false; } file.close(); } } bool old_restore_UI = env_t::restore_UI; if( new_world && env_t::reload_and_save_on_quit ) { // construct from pak name an autosave if requested std::string pak_name( "autosave-" ); pak_name.append( env_t::pak_name ); pak_name.erase( pak_name.length()-1 ); pak_name.append( ".sve" ); dr_chdir( env_t::user_dir ); unlink( "temp-load.sve" ); if( dr_rename(pak_name.c_str(), "temp-load.sve") == 0 ) { loadgame = "temp-load.sve"; new_world = false; } else { // test if rejoin server game pak_name.erase(pak_name.length() - 3); pak_name.append("net"); if (dr_rename(pak_name.c_str(), "temp-load.sve") == 0) { if (FILE *f = dr_fopen("temp-load.sve", "r")) { char servername[2048]; fgets(servername, 2048, f); fclose(f); loadgame = servername; new_world = false; } } } env_t::restore_UI = true; } // still nothing to be loaded => search for demo games if( new_world ) { dr_chdir( env_t::base_dir ); const std::string path = env_t::pak_dir + "demo.sve"; // access did not work! if( FILE *const f = dr_fopen(path.c_str(), "rb") ) { // there is a demo game to load loadgame = path; fclose(f); DBG_MESSAGE("simu_main()","loadgame file found at %s",path.c_str()); } } if( args.has_arg("-timeline") ) { const char* ref_str = args.gimme_arg("-timeline", 1); if( ref_str != NULL ) { env_t::default_settings.set_use_timeline( atoi(ref_str) ); } } if( args.has_arg("-startyear") ) { const char * ref_str = args.gimme_arg("-startyear", 1); //1930 if( ref_str != NULL ) { env_t::default_settings.set_starting_year( clamp(atoi(ref_str),1,2999) ); } } // now always writing in user dir (which points to the data dir in multiuser mode) dr_chdir( env_t::user_dir ); // init midi before loading sounds if( dr_init_midi() ) { dbg->message("simu_main()","Reading midi data ..."); if( !midi_init( env_t::pak_dir.c_str() ) && !midi_init( env_t::user_dir ) && !midi_init( env_t::base_dir ) ) { midi_set_mute(true); dbg->message("simu_main()","Midi disabled ..."); } if(args.has_arg("-nomidi")) { midi_set_mute(true); } #ifdef USE_FLUIDSYNTH_MIDI // Audio is ok, but we failed to find a soundfont if( strcmp( env_t::soundfont_filename.c_str(), "Error" ) == 0 ) { midi_set_mute(true); } #endif } else { dbg->message("simu_main()","Midi disabled ..."); midi_set_mute(true); } if( args.has_arg("-mute") ) { sound_set_mute(true); midi_set_mute(true); } // restore previous sound settings ... sound_set_mute( env_t::global_mute_sound || sound_get_mute() ); midi_set_mute( env_t::mute_midi || midi_get_mute() ); sound_set_shuffle_midi( env_t::shuffle_midi!=0 ); sound_set_global_volume( env_t::global_volume ); sound_set_midi_volume( env_t::midi_volume ); if( !midi_get_mute() ) { // not muted => play random song midi_play( env_t::shuffle_midi ? -1 : 0 ); // reset volume after first play call else no/low sound or music with win32 and sdl sound_set_midi_volume( env_t::midi_volume ); } karte_t *welt = new karte_t(); main_view_t *view = new main_view_t(welt); welt->set_view( view ); interaction_t *eventmanager = new interaction_t(welt->get_viewport()); welt->set_eventmanager( eventmanager ); // some messages about old vehicle may appear ... welt->get_message()->set_message_flags(0, 0, 0, 0); // set the frame per second if( const char *ref_str = args.gimme_arg("-fps", 1) ) { const int want_refresh = atoi(ref_str); env_t::fps = clamp(want_refresh, (int)env_t::min_fps, (int)env_t::max_fps); } // query server stuff // Enable server announcements if( args.has_arg("-announce") ) { env_t::server_announce = 1; DBG_DEBUG( "simu_main()", "Server will be announced." ); } if( const char *ref_str = args.gimme_arg("-server_dns", 1) ) { env_t::server_dns = ref_str; DBG_DEBUG( "simu_main()", "Server IP set to '%s'.", ref_str ); } if( const char *ref_str = args.gimme_arg("-server_altdns", 1) ) { env_t::server_alt_dns = ref_str; DBG_DEBUG( "simu_main()", "Server IP set to '%s'.", ref_str ); } if( const char *ref_str = args.gimme_arg("-server_name", 1) ) { env_t::server_name = ref_str; DBG_DEBUG( "simu_main()", "Server name set to '%s'.", ref_str ); } if( const char *ref_str = args.gimme_arg("-server_admin_pw", 1) ) { env_t::server_admin_pw = ref_str; } if( env_t::server_dns.empty() && !env_t::server_alt_dns.empty() ) { dbg->warning( "simu_main()", "server_altdns but not server_dns set. Please use server_dns first!" ); env_t::server_dns = env_t::server_alt_dns; env_t::server_alt_dns.clear(); } dr_chdir(env_t::user_dir); // reset random counter to true randomness setsimrand(dr_time(), dr_time()); clear_random_mode( 7 ); // allow all scenario_t *scen = NULL; if( const char *scen_name = args.gimme_arg("-scenario", 1) ) { scen = new scenario_t(welt); intr_set_view(view); win_set_world(welt); const char *err = ""; if (env_t::default_settings.get_with_private_paks()) { // try addon directory first err = scen->init(("addons/" + env_t::pak_name + "scenario/").c_str(), scen_name, welt); } if (err) { // no addon scenario, look in pakset err = scen->init((env_t::pak_dir + "scenario/").c_str(), scen_name, welt); } if( err ) { dbg->error("simu_main()", "Could not load scenario %s%s: %s", env_t::pak_name.c_str(), scen_name, err); delete scen; scen = NULL; } else { new_world = false; } } if( scen == NULL && (loadgame=="" || !welt->load(loadgame.c_str())) ) { // create a default map DBG_MESSAGE("simu_main()", "Init with default map (failing will be a pak error!)"); // no autosave on initial map during the first six months loadgame = ""; new_world = true; sint32 old_autosave = env_t::autosave; env_t::autosave = false; settings_t sets; sets.copy_city_road( env_t::default_settings ); sets.set_default_climates(); sets.set_use_timeline( 1 ); sets.set_size(64,64); sets.set_city_count(1); sets.set_factory_count(3); sets.set_tourist_attractions(1); sets.set_traffic_level(7); welt->init(&sets,0); // start in June ... intr_set_view(view); win_set_world(welt); tool_t::toolbar_tool[0]->init(welt->get_active_player()); welt->set_fast_forward(true); welt->sync_step(5000); welt->step_month(5); welt->step(); welt->step(); env_t::autosave = old_autosave; } else { // override freeplay setting when provided on command line if( (args.has_arg("-freeplay")) ) { welt->get_settings().set_freeplay( true ); } if (scen == NULL) { // just init view (world was loaded from file) intr_set_view(view); win_set_world(welt); welt->type_of_generation = karte_t::RESTORED_WORLD; } tool_t::toolbar_tool[0]->init(welt->get_active_player()); if (env_t::networkmode) { // try to restore windows loadsave_t file; std::string name("autosave-"); name.append(env_t::pak_name); name.erase(name.length() - 1); name.append(".net.sve"); dr_remove("temp-load.sve"); // we load under tempary name if there was a crash => no reloading next time if (!dr_rename(name.c_str(),"temp-load.sve") && file.rd_open("temp-load.sve") == loadsave_t::FILE_STATUS_OK) { uint8 pn; intr_disable(); file.rdwr_byte(pn); welt->switch_active_player(pn, true); rdwr_all_win(&file); intr_enable(); } // rename back, so we could get the same windows after a desync (when using the commandline to join) dr_rename( "temp-load.sve", name.c_str() ); } } welt->set_fast_forward(false); baum_t::recalc_outline_color(); uint32 quit_month = 0x7FFFFFFFu; #if defined DEBUG || defined PROFILE // do a render test? if (args.has_arg("-times")) { show_times(welt, view); } #endif // finish after a certain month? (must be entered decimal, i.e. 12*year+month if( args.has_arg("-until") ) { const char *until = args.gimme_arg("-until", 1); int year = -1, month = -1; if ( sscanf(until, "%i.%i", &year, &month) == 2) { quit_month = month+year*12-1; } else { quit_month = atoi(until); } welt->set_fast_forward(true); } welt->reset_timer(); if( !env_t::networkmode && !env_t::server ) { #ifdef display_in_main view->display(true); intr_refresh_display(true); #endif intr_enable(); } else { intr_disable(); } #ifdef USE_SOFTPOINTER // give user a mouse to work with if (skinverwaltung_t::mouse_cursor != NULL) { // we must use our softpointer (only Allegro!) display_set_pointer(skinverwaltung_t::mouse_cursor->get_image_id(0)); } #endif display_show_pointer(true); display_show_load_pointer(0); welt->set_dirty(); // simgraph_init loads default fonts, now we need to load // the real fonts for the current language, if not set otherwise sprachengui_t::init_font_from_lang(); if( !(env_t::reload_and_save_on_quit && !new_world) ) { destroy_all_win(true); } env_t::restore_UI = old_restore_UI; if( !env_t::networkmode && !env_t::server && new_world ) { welt->get_message()->clear(); welt->get_chat_message()->clear(); } #ifdef USE_FLUIDSYNTH_MIDI if( strcmp( env_t::soundfont_filename.c_str(), "Error" ) == 0 ) { create_win({ 0,0 }, new news_img("No soundfont found!\n\nMusic won't play until you load a soundfont from the sound options menu."), w_info, magic_none ); } #endif simachievements_t::check_pakset_ach(); while( !env_t::quit_simutrans ) { // play next tune? check_midi(); #if COLOUR_DEPTH != 0 if( new_world ) { dbg->message("simu_main()", "Show banner ... " ); ticker::add_msg("Welcome to Simutrans", koord3d::invalid, PLAYER_FLAG | 1); modal_dialogue( new banner_t(), magic_none, welt, never_quit, true ); // only show new world, if no other dialogue is active ... new_world = win_get_open_count()==0; } #endif // to purge all previous old messages welt->get_message()->set_message_flags(env_t::message_flags[0], env_t::message_flags[1], env_t::message_flags[2], env_t::message_flags[3]); if (pakset_manager_t::needs_doubled_warning_message()) { welt->get_message()->add_message(pakset_manager_t::get_doubled_warning_message(), koord3d::invalid, message_t::general | message_t::DO_NOT_SAVE_MSG); } if( !env_t::networkmode && !env_t::server ) { welt->set_pause( pause_after_load ); pause_after_load = false; } dbg->message("simu_main()", "Running world, pause=%i, fast forward=%i ... ", welt->is_paused(), welt->is_fast_forward() ); loadgame = ""; // only first time // run the loop welt->interactive(quit_month); new_world = true; welt->get_message()->get_message_flags(&env_t::message_flags[0], &env_t::message_flags[1], &env_t::message_flags[2], &env_t::message_flags[3]); welt->set_fast_forward(false); welt->set_pause(false); setsimrand(dr_time(), dr_time()); dbg->message("simu_main()", "World finished ..." ); } intr_disable(); // save settings { dr_chdir( env_t::user_dir ); loadsave_t settings_file; if( settings_file.wr_open("settings.xml",loadsave_t::xml,0,"settings only/",SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK ) { env_t::rdwr(&settings_file); env_t::default_settings.rdwr(&settings_file); settings_file.close(); } } destroy_all_win( true ); tool_t::exit_menu(); delete welt; welt = NULL; delete view; view = NULL; delete eventmanager; eventmanager = NULL; remove_port_forwarding( env_t::server ); network_core_shutdown(); simgraph_exit(); close_midi(); #if 0 // free all list memories (not working, since there seems to be unitialized list still waiting for automated destruction) freelist_t::free_all_nodes(); #endif #ifdef STEAM_BUILT steam_t::get_instance()->shutdown(); #endif return EXIT_SUCCESS; } simutrans-124.3/src/simutrans/simmain.h000066400000000000000000000002731474050137200201770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMMAIN_H #define SIMMAIN_H int simu_main(int argc, char** argv); #endif simutrans-124.3/src/simutrans/simmem.cc000066400000000000000000000013431474050137200201660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include // since BeOS needs size_t from there ... #include #include "simmem.h" #include "simdebug.h" void* xmalloc(size_t const size) { void* const p = malloc(size); if (!p) { // use unified error handler instead, since BeOS need this as C style file! dbg->fatal("xmalloc()", "Could not alloc %li bytes.", (long)size ); } return p; } void* xrealloc(void* const ptr, size_t const size) { void* const p = realloc(ptr, size); if (!p) { // use unified error handler instead, since BeOS need this as C style file! dbg->fatal("realloc()", "Could not alloc %li bytes.", (long)size ); } return p; } simutrans-124.3/src/simutrans/simmem.h000066400000000000000000000014141474050137200200270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMMEM_H #define SIMMEM_H #include void* xmalloc(size_t size); // Throws std::bad_alloc on failure void* xrealloc(void * const ptr, size_t size); // Throws std::bad_alloc on failure #define MALLOC(type) ((type*)xmalloc(sizeof(type))) // Allocate an object of a certain type #define MALLOCN(type, n) ((type*)xmalloc(sizeof(type) * (n))) // Allocate n objects of a certain type #define MALLOCF(type, member, n) ((type*)xmalloc(offsetof(type, member) + sizeof(*((type*)0)->member) * (n))) #define REALLOC(ptr, type, n) (type*)xrealloc((void *)ptr, sizeof(type) * (n)) // Reallocate n objects of a certain type #endif simutrans-124.3/src/simutrans/simmesg.cc000066400000000000000000000316421474050137200203500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "macros.h" #include "simdebug.h" #include "simmesg.h" #include "simticker.h" #include "display/simgraph.h" #include "simcolor.h" #include "gui/chat_frame.h" #include "gui/simwin.h" #include "world/simworld.h" #include "dataobj/loadsave.h" #include "dataobj/translator.h" #include "dataobj/environment.h" #include "dataobj/pakset_manager.h" #include "network/network_socket_list.h" #include "player/simplay.h" #include "utils/simstring.h" #include "tpl/slist_tpl.h" #include "gui/messagebox.h" #include #include #include "simsound.h" #include "descriptor/sound_desc.h" #define MAX_SAVED_MESSAGES (2000) static karte_ptr_t welt; static vector_tplclients; uint32 message_node_t::get_type_shifted() const { return 1<<(type & message_t::MESSAGE_TYPE_MASK); } void message_node_t::rdwr(loadsave_t *file) { file->rdwr_str( msg, lengthof(msg) ); file->rdwr_long( type ); if (file->is_version_less(123, 2)) { // only 2d coordinates koord k = pos.get_2d(); k.rdwr(file); if (file->is_loading()) { pos = koord3d::invalid; if (k != koord::invalid) { // query ground tile (world is loaded at this point) if (grund_t *gr = welt->lookup_kartenboden(k)) { pos = gr->get_pos(); } } } } else { pos.rdwr(file); } if (file->is_version_less(120, 5)) { // color was 16bit, with 0x8000 indicating player colors uint16 c = color & PLAYER_FLAG ? 0x8000 + (color&(~PLAYER_FLAG)) : MN_GREY0; file->rdwr_short(c); color = c & 0x8000 ? PLAYER_FLAG + (c&(~0x8000)) : color_idx_to_rgb(c); } else { file->rdwr_long( color ); } file->rdwr_long( time ); if( file->is_loading() ) { image = IMG_EMPTY; } } PIXVAL message_node_t::get_player_color(karte_t *welt) const { // correct for player color FLAGGED_PIXVAL colorval = color; if( color&PLAYER_FLAG ) { player_t *player = welt->get_player(color&(~PLAYER_FLAG)); colorval = player ? PLAYER_FLAG+color_idx_to_rgb(player->get_player_color1()+env_t::gui_player_color_dark) : color_idx_to_rgb(MN_GREY0); } return (PIXVAL)colorval; } void message_node_t::open_msg_window(bool open_as_autoclose) const { // show window with the complete warning if (strcmp(msg, pakset_manager_t::get_doubled_warning_message()) == 0) { pakset_manager_t::open_doubled_warning_window(); return; } // message window again news_window* news; if( pos==koord3d::invalid ) { news = new news_img( msg, image, get_player_color(welt) ); } else { news = new news_loc( msg, pos, get_player_color(welt) ); } create_win(news, open_as_autoclose ? w_time_delete /* autoclose window */ : w_info /* normal window */, magic_none); } message_t::message_t() { ticker_flags = 0xFF7F; // everything on the ticker only win_flags = 0; auto_win_flags = 0; ignore_flags = 0; win_flags = 256+8; auto_win_flags = 128+512; } message_t::~message_t() { clear(); } void message_t::clear() { while (!list.empty()) { delete list.remove_first(); } ticker::clear_messages(); clients.clear(); clients.append(env_t::nickname.c_str()); } /* get flags for message routing */ void message_t::get_message_flags( sint32 *t, sint32 *w, sint32 *a, sint32 *i) { *t = ticker_flags; *w = win_flags; *a = auto_win_flags; *i = ignore_flags; } /* set flags for message routing */ void message_t::set_message_flags( sint32 t, sint32 w, sint32 a, sint32 i) { ticker_flags = t; win_flags = w; auto_win_flags = a; ignore_flags = i; } /** * Add a message to the message list * * @param text * @param pos position of the event * @param color message color * @param what_flags type of message * @param image image associated with message (will be ignored if pos!=koord3d::invalid) */ void message_t::add_message(const char *text, koord3d pos, uint16 what_flags, FLAGGED_PIXVAL color, image_id image ) { DBG_MESSAGE("message_t::add_msg()","%40s (at %i,%i,%i)", text, pos.x, pos.y, pos.z ); sint32 what_bit = 1<<(what_flags & MESSAGE_TYPE_MASK); if( what_bit&ignore_flags ) { // wants us to ignore this completely return; } /* we will not add traffic jam messages two times to the list * if it was within the last 20 messages * or within last months * and is not a general (BLACK) message */ if( what_bit == (1<get_current_month()-2; uint32 i = 0; for(message_node_t* const iter : list) { message_node_t const& n = *iter; if (n.time >= now && strcmp(n.msg, text) == 0 && (n.pos.x & 0xFFF0) == (pos.x & 0xFFF0) && // positions need not 100% match ... (n.pos.y & 0xFFF0) == (pos.y & 0xFFF0)) { // we had exactly this message already return; } if (++i == 20) break; } } // filter out AI messages for a similar area to recent activity messages if( what_bit == (1<msg, text, lengthof(n->msg)); n->type = what_flags; n->pos = pos; n->color = color; n->time = welt->get_current_month(); n->image = image; // should we send this message to a ticker? if( what_bit&ticker_flags ) { ticker::add_msg_node(*n); } // insert at the top list.insert(n); // if we are not current player, do not open windows if( (what_bit&(1<get_active_player_nr() != (color&(~PLAYER_FLAG)) ) { return; } // check if some window has focus gui_frame_t *old_top = win_get_top(); // should we open a window? if ( what_bit & (auto_win_flags | win_flags) ) { n->open_msg_window( (what_bit & win_flags)==0 ); } // restore focus if( old_top ) { top_win( old_top, true ); } } koord3d message_t::get_coord_from_text(const char* text) { koord3d pos(koord3d::invalid); const char *str = text; // scan until either @ or ( are found while( *(str += strcspn(str, "@(")) ) { str += 1; int x=-1, y=-1, z=0; int read_coords = sscanf(str, "%d,%d,%d", &x, &y, &z); if (read_coords >= 2 && welt->is_within_limits(x,y)) { if (read_coords == 3) { pos.x = x; pos.y = y; pos.z = z; } else { pos = welt->lookup_kartenboden(x,y)->get_pos(); } break; // success } } return pos; } void message_t::rotate90( sint16 size_w ) { for(message_node_t* const i : list) { i->pos.rotate90(size_w); } } void message_t::rdwr(loadsave_t* file) { uint16 msg_count; if (file->is_saving()) { msg_count = 0; vector_tplmsg_to_save; msg_to_save.reserve(list.get_count()); if (env_t::server) { // do not save local messages and expired messages uint32 current_time = world()->get_current_month(); for (message_node_t* const i : list) { if (i->type & DO_NOT_SAVE_MSG || (i->type & EXPIRE_AFTER_ONE_MONTH_MSG && current_time - i->time > 1)) { continue; } msg_to_save.append(i); } } else { // do not save discardable messages (like changing player) for (message_node_t* const i : list) { if (!(i->type & DO_NOT_SAVE_MSG)) { msg_to_save.append(i); } } } // save only the last MAX_SAVED_MESSAGES msg_count = (uint16)min(MAX_SAVED_MESSAGES, msg_to_save.get_count()); file->rdwr_short(msg_count); for (uint32 i = msg_to_save.get_count() - msg_count; i < msg_to_save.get_count(); i++) { msg_to_save[i]->rdwr(file); } } else { // loading clear(); file->rdwr_short(msg_count); if (file->is_version_less(124, 1)) { welt->get_chat_message()->clear(); } while ((msg_count--) > 0) { message_node_t* n = new message_node_t(); n->rdwr(file); // maybe add this rather to the chat if (file->is_version_less(124, 1)) { if (n->get_type_shifted() == (1 << message_t::chat)) { char name[256]; char msg_no_name[256]; sint8 player_nr = 0; if (char* c = strchr(n->msg, ']')) { *c = 0; strcpy(name, n->msg + 1); strcpy(msg_no_name, c + 1); } else { strcpy(name, "Unknown"); tstrncpy(msg_no_name, n->msg, 256); } if (n->color & PLAYER_FLAG) { player_t* player = welt->get_player(n->color & (~PLAYER_FLAG)); if (player) { player_nr = player->get_player_nr(); } } welt->get_chat_message()->convert_old_message(msg_no_name, name, player_nr, n->time, n->pos.get_2d()); continue; // remove the chat message } } list.append(n); } } } chat_message_t::~chat_message_t() { clear(); } void chat_message_t::clear() { while (!list.empty()) { delete list.remove_first(); } } void chat_message_t::convert_old_message(const char* text, const char* name, sint8 player_nr, sint32 time, koord pos) { chat_node* const n = new chat_node(); tstrncpy(n->msg, text, lengthof(n->msg)); n->flags = chat_message_t::NONE; n->pos = pos; n->player_nr = player_nr; n->channel_nr = -1; n->sender = name; n->destination = 0; n->time = time; n->local_time = 0; list.append(n); } void chat_message_t::add_chat_message(const char* text, sint8 channel, sint8 sender_nr, plainstring sender_nick, plainstring recipient, koord pos, uint8 flags) { cbuffer_t buf; // Output which will be printed to ticker // send this message to a ticker if public channel message if (channel >= -1) { // and not mine if (sender_nr >= 0 && sender_nr != PLAYER_UNOWNED) { // not mine? if(strcmp(sender_nick, env_t::nickname.c_str()) != 0){ bool company_msg = channel == world()->get_active_player_nr(); bool private_msg = recipient && strcmp(recipient, env_t::nickname.c_str()) == 0; bool show_message = channel == -1 // message for all? || company_msg // company message for us? || private_msg; // private chat for us? if(show_message) { buf.printf("%s: %s", sender_nick.c_str(), text); int type = message_t::chat_common + company_msg + private_msg*2; ticker::add_msg(buf, koord3d::invalid, PLAYER_FLAG|sender_nr, type ); env_t::chat_unread_public++; sound_play(sound_desc_t::message_sound, 255, TOOL_SOUND); } } } } else if (channel == -2) { // text contains the current nicks, separated by TAB clients.clear(); std::string temp = text; // strtok alters the string, so make a copy to be safe char* nick = strtok(const_cast(temp.data()), "\t"); while (nick) { clients.append(nick); nick = strtok(NULL, "\t"); } flags |= DO_NO_LOG_MSG|DO_NOT_SAVE_MSG; // not saving this message if (chat_frame_t* cf = (chat_frame_t*)win_get_magic(magic_chatframe)) { cf->fill_list(); } } if (!(flags & DO_NO_LOG_MSG)) { // we do not allow messages larger than 256 bytes chat_node* const n = new chat_node(); tstrncpy(n->msg, text, lengthof(n->msg)); n->flags = flags; n->pos = pos; n->player_nr = sender_nr; n->channel_nr = channel; n->sender = sender_nick; n->destination = recipient; n->time = world()->get_current_month(); time_t ltime; time(<ime); n->local_time = ltime; list.append(n); } } void chat_message_t::rename_client(plainstring old_name, plainstring new_name) { for (chat_node* i : list) { if (i->sender && strcmp(i->sender, old_name) == 0) { i->sender = new_name; } if (i->destination && strcmp(i->destination, old_name) == 0) { i->destination = new_name; } } } void chat_message_t::chat_node::rdwr(loadsave_t* file) { file->rdwr_str(msg, lengthof(msg)); file->rdwr_byte(flags); file->rdwr_byte(player_nr); file->rdwr_byte(channel_nr); file->rdwr_str(sender); file->rdwr_str(destination); file->rdwr_long(time); sint64 tmp = local_time; file->rdwr_longlong(tmp); local_time = tmp; pos.rdwr(file); } void chat_message_t::rotate90(sint16 size_w) { for (chat_node* const i : list) { i->pos.rotate90(size_w); } } void chat_message_t::rdwr(loadsave_t* file) { uint16 msg_count; if (file->is_saving()) { vector_tplmsg_to_save; msg_to_save.reserve(list.get_count()); // do not save discardable messages for (chat_node* const i : list) { if (!(i->flags & DO_NOT_SAVE_MSG)) { msg_to_save.append(i); } } // save only the last MAX_SAVED_MESSAGES msg_count = (uint16)min(MAX_SAVED_MESSAGES, msg_to_save.get_count()); file->rdwr_short(msg_count); for (uint32 i = msg_to_save.get_count() - msg_count; i < msg_to_save.get_count(); i++) { msg_to_save[i]->rdwr(file); } } else { // loading clear(); file->rdwr_short(msg_count); while ((msg_count--) > 0) { chat_node* n = new chat_node(); n->rdwr(file); list.append(n); } } } // return the number of connected clients const vector_tpl& chat_message_t::get_online_nicks() { return clients; } simutrans-124.3/src/simutrans/simmesg.h000066400000000000000000000070441474050137200202110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMMESG_H #define SIMMESG_H #include "simtypes.h" #include "gui/gui_theme.h" #include "display/simimg.h" #include "dataobj/koord.h" #include "dataobj/koord3d.h" #include "tpl/slist_tpl.h" #include "utils/plainstring.h" class karte_t; class karte_ptr_t; /** * class for a simple message * this way they are stored in a list */ struct message_node_t { char msg[256]; sint32 type; koord3d pos; FLAGGED_PIXVAL color; image_id image; sint32 time; void rdwr(loadsave_t *file); uint32 get_type_shifted() const; // { return 1<<(type & MESSAGE_TYPE_MASK); } PIXVAL get_player_color(karte_t*) const; void open_msg_window(bool open_as_autoclose) const; }; class message_t { public: enum msg_typ { general = 0, ai = 1, city = 2, problems = 3, industry = 4, chat = 5, new_vehicle = 6, full = 7, warnings = 8, traffic_jams = 9, scenario = 10, chat_common = 11, chat_company = 12, chat_private = 13, MAX_MESSAGE_TYPE, MESSAGE_TYPE_MASK = 0xf, EXPIRE_AFTER_ONE_MONTH_MSG = 1 << 13, DO_NOT_SAVE_MSG = 1 << 14, PLAYER_MSG = 1 << 15 }; void add_message( const char *text, koord3d pos, uint16 what, FLAGGED_PIXVAL color=SYSCOL_TEXT, image_id image=IMG_EMPTY ); /* determines, which message is displayed where */ void get_message_flags( sint32 *t, sint32 *w, sint32 *a, sint32 *i); void set_message_flags( sint32, sint32, sint32, sint32 ); message_t(); ~message_t(); private: // bitfields that contains the messages sint32 ticker_flags; sint32 win_flags; sint32 auto_win_flags; sint32 ignore_flags; slist_tpl list; public: const slist_tpl &get_list() const { return list; } void clear(); void rotate90( sint16 size_w ); void rdwr( loadsave_t *file ); /** * Returns first valid coordinate from text (or koord::invalid if none is found). * syntax: either @x,y or (x,y) */ static koord3d get_coord_from_text(const char* text); }; class chat_message_t { public: class chat_node { public: char msg[256]; uint8 flags; sint8 player_nr; sint8 channel_nr=-1; // player(company) number, -1 = public chat plainstring sender; // NULL = system message plainstring destination; // for whisper koord pos; sint32 time; // game date time_t local_time; void rdwr(loadsave_t* file); }; enum { NONE = 0, DO_NO_LOG_MSG = 1<<1, // send system message via tool, but not logged chat window, send only ticker DO_NOT_SAVE_MSG = 1<<2 // send system message via tool, logged but not saved // TODO: We can consider flags such as messages pinned to the top by an admin, messages that remain for a certain amount of time, etc. }; void add_chat_message(const char* text, sint8 channel=-1, sint8 sender_player_nr=1 /*PLAYER_PUBLIC_NR*/, plainstring sender=NULL, plainstring recipient=NULL, koord pos = koord::invalid, uint8 flags=chat_message_t::NONE); chat_message_t() {}; ~chat_message_t(); static const vector_tpl &get_online_nicks(); private: slist_tpl list; public: const slist_tpl& get_list() const { return list; } // for converting old log void convert_old_message(const char* text, const char* name, sint8 player_nr, sint32 time, koord pos); // call from nwc_nick_t void rename_client(plainstring old_name, plainstring new_name); void clear(); void rotate90(sint16 size_w); void rdwr(loadsave_t* file); }; #endif simutrans-124.3/src/simutrans/simskin.cc000066400000000000000000000252011474050137200203530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "descriptor/skin_desc.h" #include "descriptor/spezial_obj_tpl.h" #include "simskin.h" #include "tpl/slist_tpl.h" #include "tpl/vector_tpl.h" /* * Skins, mostly GUI elements */ // menus const skin_desc_t* skinverwaltung_t::tool_icons_general = NULL; const skin_desc_t* skinverwaltung_t::tool_icons_simple = NULL; const skin_desc_t* skinverwaltung_t::tool_icons_dialoge = NULL; const skin_desc_t* skinverwaltung_t::tool_icons_toolbars = NULL; const skin_desc_t* skinverwaltung_t::toolbar_background = NULL; /* Window skin images are menus too! */ const skin_desc_t* skinverwaltung_t::button = NULL; const skin_desc_t* skinverwaltung_t::round_button = NULL; const skin_desc_t* skinverwaltung_t::check_button = NULL; const skin_desc_t* skinverwaltung_t::posbutton = NULL; const skin_desc_t* skinverwaltung_t::back = NULL; const skin_desc_t* skinverwaltung_t::scrollbar = NULL; const skin_desc_t* skinverwaltung_t::divider = NULL; const skin_desc_t* skinverwaltung_t::editfield = NULL; const skin_desc_t* skinverwaltung_t::listbox = NULL; const skin_desc_t* skinverwaltung_t::gadget= NULL; // symbol images const skin_desc_t* skinverwaltung_t::biglogosymbol = NULL; const skin_desc_t* skinverwaltung_t::logosymbol = NULL; const skin_desc_t* skinverwaltung_t::neujahrsymbol = NULL; const skin_desc_t* skinverwaltung_t::neueweltsymbol = NULL; const skin_desc_t* skinverwaltung_t::flaggensymbol = NULL; const skin_desc_t* skinverwaltung_t::meldungsymbol = NULL; const skin_desc_t* skinverwaltung_t::zughaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::autohaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::schiffshaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::airhaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::monorailhaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::maglevhaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::narrowgaugehaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::bushaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::tramhaltsymbol = NULL; const skin_desc_t* skinverwaltung_t::networksymbol = NULL; const skin_desc_t* skinverwaltung_t::timelinesymbol = NULL; const skin_desc_t* skinverwaltung_t::fastforwardsymbol = NULL; const skin_desc_t* skinverwaltung_t::pausesymbol = NULL; const skin_desc_t* skinverwaltung_t::electricity = NULL; const skin_desc_t* skinverwaltung_t::intown = NULL; const skin_desc_t* skinverwaltung_t::passengers = NULL; const skin_desc_t* skinverwaltung_t::mail = NULL; const skin_desc_t* skinverwaltung_t::goods = NULL; const skin_desc_t* skinverwaltung_t::happy = NULL; const skin_desc_t* skinverwaltung_t::unhappy = NULL; const skin_desc_t* skinverwaltung_t::no_route = NULL; const skin_desc_t* skinverwaltung_t::station_type = NULL; const skin_desc_t* skinverwaltung_t::seasons_icons = NULL; const skin_desc_t* skinverwaltung_t::message_options = NULL; const skin_desc_t* skinverwaltung_t::color_options = NULL; const skin_desc_t* skinverwaltung_t::compass_iso = NULL; const skin_desc_t* skinverwaltung_t::compass_map = NULL; // compass for minimap // cursors const skin_desc_t* skinverwaltung_t::cursor_general = NULL; // new cursors const skin_desc_t* skinverwaltung_t::bauigelsymbol = NULL; const skin_desc_t* skinverwaltung_t::belegtzeiger = NULL; const skin_desc_t* skinverwaltung_t::mouse_cursor = NULL; // misc images const skin_desc_t* skinverwaltung_t::construction_site = NULL; const skin_desc_t* skinverwaltung_t::fussweg = NULL; const skin_desc_t* skinverwaltung_t::pumpe = NULL; const skin_desc_t* skinverwaltung_t::senke = NULL; const skin_desc_t* skinverwaltung_t::tunnel_texture = NULL; slist_tplskinverwaltung_t::extra_menu_obj; slist_tplskinverwaltung_t::extra_cursor_obj; static special_obj_tpl const misc_objekte[] = { { &skinverwaltung_t::senke, "PowerDest" }, { &skinverwaltung_t::pumpe, "PowerSource" }, { &skinverwaltung_t::construction_site, "Construction" }, { &skinverwaltung_t::fussweg, "Sidewalk" }, { &skinverwaltung_t::tunnel_texture, "TunnelTexture"}, { NULL, NULL } }; static special_obj_tpl const menu_objekte[] = { // new menu system { &skinverwaltung_t::button, "Button" }, { &skinverwaltung_t::round_button, "Roundbutton" }, { &skinverwaltung_t::check_button, "Checkbutton" }, { &skinverwaltung_t::posbutton, "Posbutton" }, { &skinverwaltung_t::scrollbar, "Scrollbar" }, { &skinverwaltung_t::divider, "Divider" }, { &skinverwaltung_t::editfield, "Editfield" }, { &skinverwaltung_t::listbox, "Listbox" }, { &skinverwaltung_t::back, "Back" }, { &skinverwaltung_t::gadget, "Gadget" }, { &skinverwaltung_t::tool_icons_general, "GeneralTools" }, { &skinverwaltung_t::tool_icons_simple, "SimpleTools" }, { &skinverwaltung_t::tool_icons_dialoge, "DialogeTools" }, { &skinverwaltung_t::tool_icons_toolbars,"BarTools" }, { NULL, NULL } }; static special_obj_tpl const symbol_objekte[] = { { &skinverwaltung_t::seasons_icons, "Seasons" }, { &skinverwaltung_t::message_options, "MessageOptions" }, { &skinverwaltung_t::color_options, "ColorOptions" }, { &skinverwaltung_t::logosymbol, "Logo" }, { &skinverwaltung_t::neujahrsymbol, "NewYear" }, { &skinverwaltung_t::neueweltsymbol, "NewWorld" }, { &skinverwaltung_t::flaggensymbol, "Flags" }, { &skinverwaltung_t::meldungsymbol, "Message" }, { &skinverwaltung_t::electricity, "Electricity" }, { &skinverwaltung_t::intown, "InTown" }, { &skinverwaltung_t::passengers, "Passagiere" }, { &skinverwaltung_t::mail, "Post" }, { &skinverwaltung_t::goods, "Waren" }, { NULL, NULL } }; static const skin_desc_t* restore_symbol_objekte[lengthof(symbol_objekte)]; // simutrans will work without those static special_obj_tpl const fakultative_objekte[] = { { &skinverwaltung_t::biglogosymbol, "BigLogo" }, { &skinverwaltung_t::mouse_cursor, "Mouse" }, { &skinverwaltung_t::zughaltsymbol, "TrainStop" }, { &skinverwaltung_t::autohaltsymbol, "CarStop" }, { &skinverwaltung_t::schiffshaltsymbol, "ShipStop" }, { &skinverwaltung_t::bushaltsymbol, "BusStop" }, { &skinverwaltung_t::airhaltsymbol, "AirStop" }, { &skinverwaltung_t::monorailhaltsymbol, "MonorailStop" }, { &skinverwaltung_t::maglevhaltsymbol, "MaglevStop" }, { &skinverwaltung_t::narrowgaugehaltsymbol,"NarrowgaugeStop"}, { &skinverwaltung_t::tramhaltsymbol, "TramStop" }, { &skinverwaltung_t::networksymbol, "networksym" }, { &skinverwaltung_t::timelinesymbol, "timelinesym" }, { &skinverwaltung_t::fastforwardsymbol, "fastforwardsym" }, { &skinverwaltung_t::pausesymbol, "pausesym" }, { &skinverwaltung_t::station_type, "station_type" }, { &skinverwaltung_t::toolbar_background, "ToolsBackground"}, { &skinverwaltung_t::compass_iso, "CompassIso" }, { &skinverwaltung_t::compass_map, "CompassMap" }, { &skinverwaltung_t::happy, "Happy" }, { &skinverwaltung_t::unhappy, "Unhappy" }, { &skinverwaltung_t::no_route, "NoRoute" }, { NULL, NULL } }; static const skin_desc_t *restore_fakultative_objekte[lengthof(fakultative_objekte)]; static special_obj_tpl const cursor_objekte[] = { // old cursors { &skinverwaltung_t::bauigelsymbol, "Builder" }, { &skinverwaltung_t::cursor_general, "GeneralTools" }, { &skinverwaltung_t::belegtzeiger, "Marked" }, { NULL, NULL } }; bool skinverwaltung_t::successfully_loaded(skintyp_t type) { special_obj_tpl const* sd; switch (type) { case menu: return true; // skins will be handled elsewhere case cursor: sd = cursor_objekte; break; case symbol: sd = symbol_objekte; break; case misc: sd = misc_objekte+2; // for compatibility: use sidewalk as tunneltexture if (tunnel_texture==NULL) { tunnel_texture = fussweg; } break; case nothing: return true; default: return false; } return ::successfully_loaded(sd); } bool skinverwaltung_t::register_desc(skintyp_t type, const skin_desc_t* desc) { special_obj_tpl const* sd; switch (type) { case menu: sd = menu_objekte; break; case cursor: sd = cursor_objekte; break; case symbol: sd = symbol_objekte; break; case misc: sd = misc_objekte; break; case nothing: return true; default: return false; } if( ::register_desc(sd, desc) ) { return true; } else if( type==cursor || type==symbol ) { if( ::register_desc( fakultative_objekte, desc ) ) { return true; } } // currently no misc objects allowed ... if( type==cursor || type==menu ) { if( type==cursor ) { extra_cursor_obj.insert( desc ); } else { extra_menu_obj.insert( desc ); } dbg->message( "skinverwaltung_t::register_desc()","Extra object %s added.", desc->get_name() ); } else { dbg->warning("skinverwaltung_t::register_desc()","Spurious object '%s' loaded (will not be referenced anyway)!", desc->get_name() ); } return true; } // return the extra_obj with this name const skin_desc_t *skinverwaltung_t::get_extra( const char *str, int len, skintyp_t type ) { if(!str || len == 0) { return NULL; } if( type!=menu && type!=cursor ) { // illegal type return NULL; } for(skin_desc_t const* const s : (type==menu ? skinverwaltung_t::extra_menu_obj : skinverwaltung_t::extra_cursor_obj)) { if ( strncmp(str, s->get_name(), len) == 0 ) { return s; } } return NULL; } void skinverwaltung_t::save_all_skins() { for (int i = 0; symbol_objekte[i].name != 0; i++) { restore_symbol_objekte[i] = *(symbol_objekte[i].desc); } for (int i = 0; fakultative_objekte[i].name != 0; i++) { restore_fakultative_objekte[i]= *(fakultative_objekte[i].desc); } } void skinverwaltung_t::restore_all_skins() { // only saving the original pak objects once for (int i = 0; symbol_objekte[i].name != 0; i++) { *symbol_objekte[i].desc = restore_symbol_objekte[i]; } for (int i = 0; fakultative_objekte[i].name != 0; i++) { *fakultative_objekte[i].desc = restore_fakultative_objekte[i]; } } simutrans-124.3/src/simutrans/simskin.h000066400000000000000000000126461474050137200202260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMSKIN_H #define SIMSKIN_H #include "simcolor.h" // For test purposes themes can be disabled or an alternative theme.tab file can be used. // -1 = No theme, use internal fallback // 0 = Normal use, read theme.tab // n>0 = Use alternative file named theme_n.tab template class slist_tpl; class skin_desc_t; class skinverwaltung_t { public: enum skintyp_t { nothing, menu, cursor, symbol, misc }; /// @name icons used in the toolbars /// @{ /// icon images for advanced tools (everything that involves clicking on the map) static const skin_desc_t *tool_icons_general; /// icon images for simple tools (eg pause, fast forward) static const skin_desc_t *tool_icons_simple; /// icon images for GUI tools (which open windows) static const skin_desc_t *tool_icons_dialoge; /// icon images for toolbars static const skin_desc_t *tool_icons_toolbars; /// icon to skin toolbar background static const skin_desc_t *toolbar_background; /// @} /** * Different GUI elements */ static const skin_desc_t* button; static const skin_desc_t* round_button; static const skin_desc_t* check_button; static const skin_desc_t* posbutton; static const skin_desc_t* back; static const skin_desc_t* scrollbar; static const skin_desc_t* divider; static const skin_desc_t* editfield; static const skin_desc_t* listbox; static const skin_desc_t* gadget; /// @name pictures used in the GUI /// @{ /// image shown in welcome screen @see banner.cc static const skin_desc_t *logosymbol; /// image shown when loading pakset static const skin_desc_t *biglogosymbol; /// image shown with 'happy new year' message static const skin_desc_t *neujahrsymbol; /// image shown when creating new world static const skin_desc_t *neueweltsymbol; /// image shown in language selection static const skin_desc_t *flaggensymbol; /// image shown in message boxes @see gui/messagebox.h static const skin_desc_t *meldungsymbol; /// image shown in message options window static const skin_desc_t *message_options; /// image shown in color selection window static const skin_desc_t *color_options; // isometric compass for main map (evt. minimap) static const skin_desc_t *compass_iso; // normal staight compass for minimap static const skin_desc_t *compass_map; /// @} /// @name icons used for the tabs in the line management window /// @{ static const skin_desc_t *zughaltsymbol; static const skin_desc_t *autohaltsymbol; static const skin_desc_t *schiffshaltsymbol; static const skin_desc_t *airhaltsymbol; static const skin_desc_t *monorailhaltsymbol; static const skin_desc_t *maglevhaltsymbol; static const skin_desc_t *narrowgaugehaltsymbol; static const skin_desc_t *bushaltsymbol; static const skin_desc_t *tramhaltsymbol; ///@} /// @name icons shown in status bar at the bottom of the screen /// @{ static const skin_desc_t *networksymbol; static const skin_desc_t *timelinesymbol; static const skin_desc_t *fastforwardsymbol; static const skin_desc_t *pausesymbol; static const skin_desc_t *seasons_icons; /// @} /// @name icons used to show which halt serves passengers / mail / freight /// @{ static const skin_desc_t *passengers; static const skin_desc_t *mail; static const skin_desc_t *goods; /// @} /// @name icons used to passenger evaluations happy / unhappy / no route /// @{ static const skin_desc_t *happy; static const skin_desc_t *unhappy; static const skin_desc_t *no_route; /// @} /// images shown in display of lines in mini-map static const skin_desc_t *station_type; /// image to indicate power supply of factories static const skin_desc_t *electricity; /// image to indicate that an attraction is inside a town (attraction list window) static const skin_desc_t *intown; /// @name cursors /// @{ /// cursors for tools static const skin_desc_t *cursor_general; /// for allegro: emulate mouse cursor static const skin_desc_t *mouse_cursor; /// symbol to mark tiles by AI players and text labels static const skin_desc_t *belegtzeiger; /// icon to mark start tiles for construction (ie the bulldozer image) static const skin_desc_t *bauigelsymbol; /// @} /// shown in hidden-buildings mode instead of buildings images static const skin_desc_t *construction_site; /// texture to be shown beneath city roads to indicate pavements static const skin_desc_t *fussweg; /// transformer image: supply static const skin_desc_t *pumpe; /// transformer image: consumer static const skin_desc_t *senke; /// texture to be shown beneath ways in tunnel static const skin_desc_t *tunnel_texture; static bool register_desc(skintyp_t type, const skin_desc_t *desc); static bool successfully_loaded(skintyp_t type); /** * retrieves objects with type=menu and given name * * @param str pointer to beginning of name string (not null-terminated) * @param len length of string * @param type * @return pointer to skin object or NULL if nothing found */ static const skin_desc_t *get_extra( const char *str, int len, skintyp_t type = menu ); // called after all paksets are loaded to restore icons overlaid by skin paks static void save_all_skins(); // restore pakset originals static void restore_all_skins(); private: /// holds objects from paks with type 'menu' and 'cursor' static slist_tplextra_menu_obj; static slist_tplextra_cursor_obj; }; #endif simutrans-124.3/src/simutrans/simsound.cc000066400000000000000000000121251474050137200205400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "macros.h" #include "music/music.h" #include "descriptor/sound_desc.h" #include "sound/sound.h" #include "simsound.h" #include "sys/simsys.h" #include "simio.h" #include "simdebug.h" #include "dataobj/environment.h" #include "utils/plainstring.h" #include "utils/simrandom.h" #include "utils/simstring.h" static bool new_midi = false; static struct midi_info_t midi_list[MAX_MIDI]; static int max_midi = -1; // number of MIDI files static int current_midi = -1; // init with error condition, reset during loading void sound_set_global_volume(int volume) { env_t::global_volume = volume; } void sound_set_specific_volume( int volume, sound_type_t t) { env_t::specific_volume[t] = volume; } int sound_get_global_volume() { return env_t::global_volume; } int sound_get_specific_volume( sound_type_t t ) { return env_t::specific_volume[t]; } void sound_set_mute(bool f) { env_t::global_mute_sound = f; } bool sound_get_mute() { return ( env_t::global_mute_sound ); } void sound_play(uint16 const idx, uint8 const v, sound_type_t t) { uint32 volume = v; if( idx != (uint16)NO_SOUND && !env_t::global_mute_sound ) { dr_play_sample(idx, ( (volume * env_t::global_volume * env_t::specific_volume[t] ) >> 16) ); } } bool sound_get_shuffle_midi() { return env_t::shuffle_midi; } void sound_set_shuffle_midi( bool shuffle ) { env_t::shuffle_midi = shuffle; } void sound_set_midi_volume(int volume) { if( !env_t::mute_midi && max_midi > -1 ) { dr_set_midi_volume(volume); } env_t::midi_volume = volume; } int sound_get_midi_volume() { return env_t::midi_volume; } /** * gets midi title */ struct midi_info_t sound_get_midi_info(int index) { if ( index >= 0 && index <= max_midi ) { return midi_list[index]; } return { "Invalid MIDI Index!", "-", "-" }; } /** * gets current midi number */ int get_current_midi() { return current_midi; } /** * Load MIDI files */ int midi_init(const char *directory) { // read a list of soundfiles std::string full_path = std::string(directory) + "music" + PATH_SEPARATOR + "music.tab"; if( FILE* const file = dr_fopen(full_path.c_str(), "rb") ) { while(!feof(file)) { char buf[256], title[256], composer[256], arranger[256]; size_t len; read_line(buf, sizeof(buf), file); read_line(title, sizeof(title), file); read_line(composer, sizeof(composer), file); read_line(arranger, sizeof(arranger), file); if( !feof(file) ) { clear_invalid_ending_chars(buf); len = strlen(buf); if( len > 1 ) { full_path = std::string(directory) + buf; dbg->message("midi_init()", " Reading MIDI file '%s' - %s", full_path.c_str(), title); max_midi = dr_load_midi(full_path.c_str()); if( max_midi >= 0 ) { midi_list[max_midi].title = (std::string) clear_invalid_ending_chars(title); midi_list[max_midi].composer = (std::string) clear_invalid_ending_chars(composer); midi_list[max_midi].arranger = (std::string) clear_invalid_ending_chars(arranger); } } } } fclose(file); } else { dbg->warning("midi_init()","can't open file '%s' for reading.", full_path.c_str() ); } if( max_midi >= 0 ) { current_midi = 0; } // success? return ( max_midi >= 0 ); } void midi_play(const int no) { if( no > max_midi ) { dbg->warning("midi_play()", "MIDI index %d too high (total loaded: %d)", no, max_midi); } else if( !midi_get_mute() ) { current_midi = (no < 0) ? sim_async_rand( max_midi ) : no; dr_play_midi( current_midi ); } } void midi_stop() { if( !midi_get_mute() ) { dr_stop_midi(); } } void midi_set_mute(bool on) { on |= ( max_midi == -1 ); if( on ) { if( !env_t::mute_midi ) { dr_stop_midi(); } env_t::mute_midi = true; } else { if( env_t::mute_midi ) { env_t::mute_midi = false; midi_play(current_midi); } dr_set_midi_volume(env_t::midi_volume); } } bool midi_get_mute() { return ( env_t::mute_midi || max_midi == -1 ); } /* * Check if need to play new MIDI * Max Kielland: * Made it possible to get next song * even if we are muted. */ void check_midi() { // Check for next sound if (new_midi || (!midi_get_mute() && dr_midi_pos() < 0)) { if( env_t::shuffle_midi && max_midi > 1 ) { // shuffle songs (must not use simrand()!) int new_song = sim_async_rand(max_midi); if( new_song >= current_midi ) { new_song ++; } current_midi = new_song; } else { current_midi++; if( current_midi > max_midi ) { current_midi = 0; } } // Are we in playing mode? if( false == midi_get_mute() ) { midi_play(current_midi); DBG_MESSAGE("check_midi()", "Playing MIDI %d", current_midi); } } new_midi = false; } /** * shuts down midi playing */ void close_midi() { if( max_midi > -1 ) { dr_destroy_midi(); } } void midi_next_track() { new_midi = true; } void midi_last_track() { if ( current_midi == 0 ) { current_midi = max_midi - 1; } else { current_midi = current_midi - 2; } new_midi = true; } simutrans-124.3/src/simutrans/simsound.h000066400000000000000000000033311474050137200204010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMSOUND_H #define SIMSOUND_H #include #include "simtypes.h" #include "utils/plainstring.h" /// sound can be selectively muted (but volume is not touched) void sound_set_mute(bool new_flag); bool sound_get_mute(); /// @param volume in range 0..255 void sound_set_global_volume(int volume); /// @returns volume in range 0..255 int sound_get_global_volume(); /// Sets volume for a specific type of sound. /// @param volume in range 0..255 /// @param t void sound_set_specific_volume( int volume, sound_type_t t ); /// @param t /// @returns volume in range 0..255 int sound_get_specific_volume( sound_type_t t ); /** * Play a sound. * * @param idx Index of the sound * @param volume in range 0..255 * @param t */ void sound_play(uint16 idx, uint8 volume, sound_type_t t ); /// shuffle enable/disable for midis bool sound_get_shuffle_midi(); void sound_set_shuffle_midi( bool shuffle ); /// @param volume in range 0..255 void sound_set_midi_volume(int volume); /// @returns volume in range 0..255 int sound_get_midi_volume(); struct midi_info_t { std::string title; std::string composer; std::string arranger; }; /// gets midi title struct midi_info_t sound_get_midi_info(int index); /** * gets curent midi number */ int get_current_midi(); // when muted, midi is not used void midi_set_mute(bool on); bool midi_get_mute(); /* MIDI routines */ extern int midi_init(const char *path); extern void midi_play(const int no); extern void check_midi(); /** * shuts down midi playing */ extern void close_midi(); extern void midi_next_track(); extern void midi_last_track(); extern void midi_stop(); #endif simutrans-124.3/src/simutrans/simticker.cc000066400000000000000000000134411474050137200206730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "dataobj/koord3d.h" #include "dataobj/environment.h" #include "simticker.h" #include "display/simgraph.h" #include "simcolor.h" #include "tpl/slist_tpl.h" #include "utils/simstring.h" #include "gui/gui_theme.h" #include "gui/simwin.h" #include "gui/chat_frame.h" #include "world/simworld.h" #include "simmesg.h" #include "display/viewport.h" #define X_DIST (2) // how much scrolling per update call? #define X_SPACING (18) // spacing between messages, in pixels static karte_ptr_t welt; uint16 win_get_statusbar_height(); // simwin.h struct node : public message_node_t { node() {} node(const message_node_t& msg) : message_node_t(msg), xpos(0), w(0) {} sint16 xpos; sint32 w; }; static slist_tpl list; static bool redraw_all = false; ///< true, if also trigger background need redraw static int next_pos; ///< Next x offset of new message. Always greater or equal to display_width static int dx_since_last_draw = 0; ///< Increased during update(); positive values move messages to the left bool ticker::empty() { return list.empty(); } void ticker::clear_messages() { list.clear(); set_redraw_all(true); } void ticker::set_redraw_all(bool redraw) { redraw_all = redraw; } void ticker::add_msg_node(const message_node_t& msg) { const int count = list.get_count(); if(count==0) { redraw_all = true; next_pos = display_get_width(); } const char* txt = msg.msg; // don't store more than 4 messages, it's useless. if(count >= 4) { return; } // Don't repeat messages else if (count == 0 || !strstart(list.back().msg, txt)) { node n(msg); int i=0; // copy message text // remove breaks for( int j=0; i<250 && txt[j]!=0; j++ ) { if( txt[j]=='\n' ) { if( i==0 || n.msg[i-1]==' ' ) { continue; } n.msg[i++] = ' '; } else { if( txt[j]==' ' && (i==0 || n.msg[i-1]==' ') ) { // avoid double or leading spaces continue; } n.msg[i++] = txt[j]; } } n.msg[i++] = 0; n.xpos = next_pos; n.w = proportional_string_width(n.msg); next_pos += n.w + X_SPACING; list.append(n); } } void ticker::add_msg(const char* txt, koord3d pos, FLAGGED_PIXVAL color, int type) { node n; tstrncpy(n.msg, txt, lengthof(n.msg)); n.pos = pos; n.color = color; // set to default values n.type = message_t::general; n.time = 0; n.image = IMG_EMPTY; n.type = type; add_msg_node(n); } void ticker::update() { const int dx = X_DIST; const int display_width = display_get_width(); for(node & n : list) { n.xpos -= dx; } dx_since_last_draw += dx; next_pos = std::max(next_pos - dx, display_width); // remove old news while (!list.empty() && list.front().xpos + list.front().w < 0) { list.remove_first(); } if (list.empty()) { set_redraw_all(true); } } void ticker::draw() { const int start_y = env_t::menupos == MENU_BOTTOM ? win_get_statusbar_height() : display_get_height() - TICKER_HEIGHT - win_get_statusbar_height(); if (redraw_all) { redraw(); return; } else if (list.empty()) { // ticker not visible // mark everything at the bottom as dirty to clear also tooltips and compass mark_rect_dirty_wc(0, env_t::menupos == MENU_BOTTOM ? 0 : start_y - 128, display_get_width(), start_y + 128 + TICKER_HEIGHT); return; } if (dx_since_last_draw <=0) { return; } const int width = display_get_width(); if (width <= 0) { return; } // do partial redraw display_scroll_band( start_y, dx_since_last_draw, TICKER_HEIGHT ); display_fillbox_wh_rgb(width-dx_since_last_draw, start_y, dx_since_last_draw, TICKER_HEIGHT, SYSCOL_TICKER_BACKGROUND, true); mark_rect_dirty_wc(0, start_y, width, start_y + TICKER_HEIGHT); // ok, ready for the text PUSH_CLIP( width-dx_since_last_draw, start_y, dx_since_last_draw, TICKER_HEIGHT ); for(node & n : list) { if (n.xpos < width) { display_proportional_clip_rgb(n.xpos, start_y + TICKER_V_SPACE, n.msg, ALIGN_LEFT, n.get_player_color(welt), true); } } POP_CLIP(); dx_since_last_draw = 0; } void ticker::redraw() { set_redraw_all(false); dx_since_last_draw = 0; const int start_y = env_t::menupos == MENU_BOTTOM ? win_get_statusbar_height() : display_get_height() - TICKER_HEIGHT - win_get_statusbar_height(); if (list.empty()) { // mark everything at the bottom as dirty to clear also tooltips and compass mark_rect_dirty_wc(0, env_t::menupos == MENU_BOTTOM ? 0 : start_y - 128, display_get_width(), start_y + 128 + TICKER_HEIGHT); world()->set_background_dirty(); return; } const int width = display_get_width(); // just draw the ticker in its colour ... (to be sure ... ) display_fillbox_wh_rgb(0, start_y, width, TICKER_HEIGHT, SYSCOL_TICKER_BACKGROUND, true); for(node & n : list) { if (n.xpos < width) { display_proportional_clip_rgb(n.xpos, start_y + TICKER_V_SPACE, n.msg, ALIGN_LEFT, n.color, true); } } } void ticker::process_click(int x) { node *clicked = NULL; if (list.empty()) { return; } clicked = &list.front(); if (list.get_count() > 1) { for(node & n : list) { if (n.xpos <= x && x < n.xpos + n.w ) { clicked = &n; break; } } } if ((clicked->type & message_t::MESSAGE_TYPE_MASK) >= message_t::chat_common && (clicked->type & message_t::MESSAGE_TYPE_MASK) <= message_t::chat_private) { chat_frame_t* si = (chat_frame_t*)win_get_magic(magic_chatframe); if (si == NULL) { si = new chat_frame_t(); create_win({ 0, 200 }, si, w_info, magic_chatframe); } si->activate_tab((clicked->type & message_t::MESSAGE_TYPE_MASK) - message_t::chat_common); } else if (clicked->pos != koord3d::invalid) { if(welt->is_within_limits(clicked->pos.get_2d())) { welt->get_viewport()->change_world_position(clicked->pos); } } else { clicked->open_msg_window(false); } } simutrans-124.3/src/simutrans/simticker.h000066400000000000000000000025331474050137200205350ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMTICKER_H #define SIMTICKER_H #include "simcolor.h" #include "display/simgraph.h" #define TICKER_V_SPACE (2) // Vertical offset of ticker text #define TICKER_HEIGHT (LINESPACE+2*TICKER_V_SPACE) class koord3d; struct message_node_t; /** * A very simple scrolling news ticker. */ namespace ticker { bool empty(); /** * Add a message to the message list * * @param txt * @param pos position of the event * @param color message color * @param type what kind of message */ void add_msg(const char* txt, koord3d pos, FLAGGED_PIXVAL color, sint32 type=0); /** * Add a message in message_node_t format */ void add_msg_node(const message_node_t& msg); /** * Remove all messages and mark for redraw */ void clear_messages(); /** * Update message positions and remove old messages */ void update(); /** * Redraw the ticker partially or fully (if set_redraw_all() was called) */ void draw(); /** * Set true if ticker has to be redrawn fully * @sa redraw */ void set_redraw_all(bool redraw); /** * Force a ticker redraw (e.g. after a window resize) */ void redraw(); /** * Process click into ticker bar: jump to coordinate or open message window. */ void process_click(int x); }; #endif simutrans-124.3/src/simutrans/simtypes.h000066400000000000000000000142721474050137200204230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMTYPES_H #define SIMTYPES_H #include #ifndef PATH_MAX #ifdef MAX_PATH #define PATH_MAX (MAX_PATH) #else #define PATH_MAX 1024 #endif #endif #if defined _MSC_VER # include # define ALLOCA(type, name, count) type* name = static_cast(alloca(sizeof(type) * (count))) #elif defined __clang__ # include # define ALLOCA(type, name, count) type* name = static_cast(alloca(sizeof(type) * (count))) #else # define ALLOCA(type, name, count) type name[count] #endif #if defined DEBUG # include # define NOT_REACHED abort(); #else # define NOT_REACHED #endif #define OVERRIDE override #include // intptr_t (standard) #include // ptrdiff_t, intptr_t (Microsoft) #define ENUM_BITSET(T) \ static inline T operator ~ (T a) { return (T)~(unsigned)a; } \ static inline T operator & (T a, T b) { return (T)((unsigned)a & (unsigned)b); } \ static inline T operator &= (T& a, T b) { return a = (T)((unsigned)a & (unsigned)b); } \ static inline T operator | (T a, T b) { return (T)((unsigned)a | (unsigned)b); } \ static inline T operator |= (T& a, T b) { return a = (T)((unsigned)a | (unsigned)b); } /* divers enums: * better defined here than scattered in thousand files ... */ enum climate { water_climate = 0, desert_climate, tropic_climate, mediterran_climate, temperate_climate, tundra_climate, rocky_climate, arctic_climate, MAX_CLIMATES }; enum climate_bits { water_climate_bit = 1 << water_climate, desert_climate_bit = 1 << desert_climate, tropic_climate_bit = 1 << tropic_climate, mediterran_climate_bit = 1 << mediterran_climate, temperate_climate_bit = 1 << temperate_climate, tundra_climate_bit = 1 << tundra_climate, rocky_climatebit = 1 << rocky_climate, arctic_climate_bit = 1 << arctic_climate, ALL_CLIMATES = (1 << MAX_CLIMATES) - 1, all_but_water_climate = ALL_CLIMATES & ~water_climate_bit, all_but_arctic_climate = ALL_CLIMATES & ~arctic_climate_bit }; enum sound_type_t { TOOL_SOUND = 0, TRAFFIC_SOUND = 1, AMBIENT_SOUND = 2, FACTORY_SOUND = 3, CROSSING_SOUND = 4, CASH_SOUND = 5, MAX_SOUND_TYPES, ALL_SOUND = 0xFF }; /** * Vordefinierte Wegtypen. */ enum waytype_t { invalid_wt = -1, ignore_wt = 0, // fixme: many places assume invalid_wt stands for building any_wt road_wt = 1, track_wt = 2, water_wt = 3, overheadlines_wt = 4, monorail_wt = 5, maglev_wt = 6, tram_wt = 7, narrowgauge_wt = 8, air_wt = 16, powerline_wt = 128, decoration_wt = 255 }; /** * System types for ways */ enum systemtype_t { type_flat = 0, ///< flat track type_elevated = 1, ///< flag for elevated ways type_runway = 1, ///< flag for runway (only aircrafts) type_tram = 7, ///< tram track (waytype = track_wt) type_river = 255, ///< flag for river type_all = 255 ///< special ? }; /// Result of calling sync_step for sync_step-able object enum sync_result { SYNC_OK, ///< object remains in list SYNC_REMOVE, ///< remove object from list SYNC_DELETE ///< delete object and remove from list }; // define machine independent types typedef unsigned int uint; typedef signed char sint8; typedef unsigned char uint8; typedef signed short sint16; typedef unsigned short uint16; #ifndef __BEOS__ typedef signed int sint32; #ifndef NO_UINT32_TYPES typedef unsigned int uint32; #endif #else // BeOS: int!=long (even though both 32 bit) typedef signed long sint32; #ifndef NO_UINT32_TYPES typedef unsigned long uint32; #endif #endif typedef signed long long sint64; #ifndef NO_UINT64_TYPES typedef unsigned long long uint64; #endif #ifdef _MSC_VER # define GCC_PACKED # define GCC_ALIGN(a) # define MSVC_ALIGN(a) __declspec(align(a)) # define NORETURN __declspec(noreturn) # pragma warning(disable: 4200 4311 4800 4996) #else # define GCC_PACKED __attribute__ ((__packed__)) # define GCC_ALIGN(a) __attribute__ ((aligned (a))) # define MSVC_ALIGN(a) # define NORETURN __attribute__ ((noreturn)) #endif template static inline int sgn(T x) { if (x < 0) return -1; if (x > 0) return 1; return 0; } static inline int min(const int a, const int b) { return a < b ? a : b; } static inline int max(const int a, const int b) { return a > b ? a : b; } // endian conversion routines static inline uint16 endian(uint16 v) { #ifdef SIM_BIG_ENDIAN v = (v << 8) | (v >> 8); // 0x0011 #endif return v; } static inline uint32 endian(uint32 v) { #ifdef SIM_BIG_ENDIAN v = (v << 16) | (v >> 16); // 0x22330011 v = ( (v << 8) & 0xFF00FF00 ) | ( (v >> 8) & 0x00FF00FF ); // 0x33221100 #endif return v; } static inline uint64 endian(uint64 v) { #ifdef SIM_BIG_ENDIAN v = (v << 32) | (v >> 32); // 0x4455667700112233 v = ( (v << 16) & 0xFFFF0000FFFF0000ULL ) | ( (v >> 16) & 0x0000FFFF0000FFFFULL ); // 0x6677445522330011 v = ( (v << 8) & 0xFF00FF00FF00FF00ULL ) | ( (v >> 8) & 0x00FF00FF00FF00FFULL ); // 0x7766554433221100 #endif return v; } static inline sint16 endian(sint16 const v) { return sint16(endian(uint16(v))); } static inline sint32 endian(sint32 const v) { return sint32(endian(uint32(v))); } static inline sint64 endian(sint64 const v) { return sint64(endian(uint64(v))); } /** * Sometimes we need to pass pointers as well as integers through a * standardized interface (i.e. via a function pointer). This union is used as * a helper type to avoid cast operations. This isn't very clean, but if used * with care it seems better than using "long" and casting to a pointer type. * In all cases it ensures that no bits are lost. */ union value_t { value_t() : p(0) {} value_t(long itg) : i(itg) {} value_t(const void* ptr) : p(ptr) {} const void* p; long i; }; // Unicode type large enough to hold every single possible Unicode code point. typedef uint32 utf32; typedef unsigned char utf8; typedef unsigned short utf16; #endif simutrans-124.3/src/simutrans/simunits.h000066400000000000000000000102121474050137200204070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMUNITS_H #define SIMUNITS_H /* * This file is designed to contain the unit conversion routines * which were previously scattered all over the Simutrans code. * * Some are still scattered all over the code. So this file also documents * where the other conversion routines are. * * I have tried to leave out stuff which should be internal to the display * and have no gameplay consequences. * * DISTANCE units: * 1 -- tiles * 2 -- "internal pixels" -- 16 per tile. Old steps per tile. * -- OBJECT_OFFSET_STEPS, located in simconst.h * -- important to the internal rendering engine * -- used for locating images such as trees within a tile * -- same value as carunits, but conceptually different.... * 3 -- "carunits" or vehicle length units -- same as old steps per tile * -- Length of trains & other vehicles (as specified in paks) * -- is measured in this unit. Currently this is very hard to alter. * 4 -- vehicle steps * -- trains can be on one of 2^8 = 256 locations along a tile horizontally (not * diagonally). * 5 -- "yards" -- tiny distance units used internally * -- 2^12 per vehicle steps, by definition * -- 2^16 per vehicle steps in older code * -- chosen to maximize precision of certain interfaces * 6 -- km -- 1/tile in standard * * TIME units: * 1 -- ticks -- referred to as ms or milliseconds in old code * 2 -- months -- determined by karte_t::ticks_per_world_month * -- you may also use karte_t::ticks_per_world_month_shift * 3 -- days -- derived from months * 4 -- years -- derived from months * 5 -- hours & minutes -- NOT derived from months, implied by vehicle speed * 6 -- actual real-time milliseconds -- only for game speed setting * -- no meaning in-game * * SPEED units: * 1 -- "internal" speed -- yards per tick. * -- this is multiplied by delta_t, which is in ticks (in convoi_t::sync_step) * -- to get distance travelled in yards (passed to vehikel_t:fahre_basis) * 2 -- km/h -- core setting here is VEHICLE_SPEED_FACTOR * 3 -- tiles per tick * 4 -- steps per tick * * ELECTRICITY units: * 1 -- "internal" units * 2 -- megawatts * This conversion still lives in dings/leitung2.h, not here */ /** * Distance units: conversion between "vehicle steps" and "yards" * In bitshift form */ #define YARDS_PER_VEHICLE_STEP_SHIFT (12) /** * Mask, applied to yards, to eliminate anything smaller than a vehicle step * Assumes yards are in uint32 variables.... derivative of YARDS_PER_VEHICLE_STEP_SHIFT * \def YARDS_VEHICLE_STEP_MASK (0xFFFFF000) */ #define YARDS_VEHICLE_STEP_MASK ~((1<> 6) /** * Converts km/h value to speed * this is speed * 1024 / 80 = speed * 64 / 5 */ #define kmh_to_speed(speed) (((speed) << 6) / VEHICLE_SPEED_FACTOR) /* * Converts speed (yards per tick) into tiles per month */ // Done in world/simworld.h: speed_to_tiles_per_month #endif simutrans-124.3/src/simutrans/simutrans.svg000066400000000000000000000051651474050137200211440ustar00rootroot00000000000000 simutrans-124.3/src/simutrans/simversion.h000066400000000000000000000053331474050137200207420ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMVERSION_H #define SIMVERSION_H #ifndef REVISION // include external generated revision file #include "revision.h" #endif #define SIM_BUILD_NIGHTLY 0 #define SIM_BUILD_RELEASE_CANDIDATE 1 #define SIM_BUILD_RELEASE 2 #define SIM_VERSION_MAJOR 124 #define SIM_VERSION_MINOR 3 #define SIM_VERSION_PATCH 0 #define SIM_VERSION_BUILD SIM_BUILD_RELEASE // Beware: SAVEGAME minor is often ahead of version minor when there were patches. // ==> These have no direct connection at all! #define SIM_SAVE_MINOR 2 #define SIM_SERVER_MINOR 2 // NOTE: increment before next release to enable save/load of new features #define MAKEOBJ_VERSION "60.7" #ifndef QUOTEME # define QUOTEME_(x) #x # define QUOTEME(x) QUOTEME_(x) #endif #if SIM_VERSION_PATCH != 0 # define SIM_VERSION_PATCH_STRING "." QUOTEME(SIM_VERSION_PATCH) #else # define SIM_VERSION_PATCH_STRING #endif #if SIM_VERSION_BUILD == SIM_BUILD_NIGHTLY # define SIM_VERSION_BUILD_STRING " Nightly" #elif SIM_VERSION_BUILD == SIM_BUILD_RELEASE_CANDIDATE # define SIM_VERSION_BUILD_STRING " Release Candidate" #elif SIM_VERSION_BUILD == SIM_BUILD_RELEASE # define SIM_VERSION_BUILD_STRING "" #else # error invalid SIM_VERSION_BUILD #endif #define VERSION_NUMBER QUOTEME(SIM_VERSION_MAJOR) "." QUOTEME(SIM_VERSION_MINOR) SIM_VERSION_PATCH_STRING SIM_VERSION_BUILD_STRING #define VERSION_DATE __DATE__ #define SAVEGAME_PREFIX "Simutrans " #define XML_SAVEGAME_PREFIX "" #define SAVEGAME_VER_NR "0." QUOTEME(SIM_VERSION_MAJOR) "." QUOTEME(SIM_SAVE_MINOR) #define SERVER_SAVEGAME_VER_NR "0." QUOTEME(SIM_VERSION_MAJOR) "." QUOTEME(SIM_SERVER_MINOR) #define RES_VERSION_NUMBER 0, SIM_VERSION_MAJOR, SIM_VERSION_MINOR, SIM_VERSION_PATCH #ifdef REVISION # define SIM_TITLE_REVISION_STRING " - r" QUOTEME(REVISION) #else # define SIM_TITLE_REVISION_STRING #endif # define SIM_TITLE SAVEGAME_PREFIX VERSION_NUMBER SIM_TITLE_REVISION_STRING /*********************** Settings related to network games ********************/ /* Server to announce status to (up to three alternative servers possible) */ #define ANNOUNCE_SERVER1 "servers.simutrans-forum.de:80" #define ANNOUNCE_SERVER2 "servers.simutrans.org:80" /* Relative URL of the announce function on server */ #define ANNOUNCE_URL "/announce" /* Relative URL of the list function on server */ #define ANNOUNCE_LIST_URL "/list?format=csv" /* url for obtaining the external IP for easz servers */ #define QUERY_ADDR_IP "simutrans-forum.de:80" #define QUERY_ADDR_IPv4_ONLY "ipv4.simutrans-forum.de:80" /* Relative URL of the IP function on server */ #define QUERY_ADDR_URL "/get_IP.php" #endif simutrans-124.3/src/simutrans/simware.cc000066400000000000000000000113041474050137200203440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "simmem.h" #include "simdebug.h" #include "simfab.h" #include "simhalt.h" #include "simtypes.h" #include "simware.h" #include "world/simworld.h" #include "dataobj/loadsave.h" #include "dataobj/koord.h" #include "descriptor/goods_desc.h" #include "builder/goods_manager.h" const goods_desc_t *ware_t::index_to_desc[256]; ware_t::ware_t() : target_halt() , via_halt() , target_pos(-1, -1) { amount = 0; index = 0; to_factory = 0; } ware_t::ware_t(const goods_desc_t *desc) : target_halt() , via_halt() , target_pos(-1, -1) { amount = 0; index = desc->get_index(); to_factory = 0; } ware_t::ware_t(loadsave_t *file) { rdwr(file); } void ware_t::rdwr(loadsave_t *file) { sint32 amt = amount; file->rdwr_long(amt); amount = amt; if(file->is_version_less(99, 8)) { sint32 max; file->rdwr_long(max); } if( file->is_version_atleast(110, 5) ) { uint8 factory_going = to_factory; file->rdwr_byte(factory_going); to_factory = factory_going; } else if( file->is_loading() ) { to_factory = 0; } uint8 catg = 0; if(file->is_version_atleast(88, 5)) { file->rdwr_byte(catg); } if(file->is_saving()) { const char *typ = NULL; typ = get_desc()->get_name(); file->rdwr_str(typ); } else { char typ[256]; file->rdwr_str(typ, lengthof(typ)); const goods_desc_t *type = goods_manager_t::get_info(typ); if(type==NULL) { dbg->warning("ware_t::rdwr()","unknown ware of catg %d!",catg); index = goods_manager_t::get_info_catg(catg)->get_index(); amount = 0; } else { index = type->get_index(); } } // convert coordinate to halt indices if(file->is_version_atleast(110, 6)) { // save halt id directly if(file->is_saving()) { uint16 halt_id = target_halt.is_bound() ? target_halt.get_id() : 0; file->rdwr_short(halt_id); halt_id = via_halt.is_bound() ? via_halt.get_id() : 0; file->rdwr_short(halt_id); } else { uint16 halt_id; file->rdwr_short(halt_id); target_halt.set_id(halt_id); file->rdwr_short(halt_id); via_halt.set_id(halt_id); } } else { // save halthandles via coordinates koord target_halt_pos = (file->is_saving() && target_halt.is_bound()) ? target_halt->get_basis_pos() : koord::invalid; koord via_halt_pos = (file->is_saving() && via_halt.is_bound()) ? via_halt->get_basis_pos() : koord::invalid; target_halt_pos.rdwr(file); via_halt_pos.rdwr(file); if (file->is_loading()) { target_halt = haltestelle_t::get_halt_koord_index(target_halt_pos); via_halt = haltestelle_t::get_halt_koord_index(via_halt_pos); } } target_pos.rdwr(file); // restore factory-flag if (file->is_loading() && file->is_version_less(110, 5)) { if (fabrik_t::get_fab(target_pos)) { to_factory = 1; } } } void ware_t::finish_rd(karte_t *welt) { if( welt->load_version<=111005 ) { // since some halt was referred by with several koordinates // this routine will correct it if(target_halt.is_bound()) { target_halt = haltestelle_t::get_halt_koord_index(target_halt->get_init_pos()); } if(via_halt.is_bound()) { via_halt = haltestelle_t::get_halt_koord_index(via_halt->get_init_pos()); } } update_factory_target(); } void ware_t::rotate90(sint16 y_size ) { target_pos.rotate90( y_size ); update_factory_target(); } void ware_t::update_factory_target() { if (to_factory) { // assert that target coordinates are unique for cargo going to the same factory // as new cargo will be generated with possibly new factory coordinates fabrik_t *fab = fabrik_t::get_fab(target_pos ); if (fab) { target_pos = fab->get_pos().get_2d(); } } } sint64 ware_t::calc_revenue(const goods_desc_t* desc, waytype_t wt, sint32 speedkmh) { static karte_ptr_t welt; const sint32 ref_kmh = welt->get_average_speed( wt ); const sint32 kmh_base = (100 * speedkmh) / ref_kmh - 100; const sint32 grundwert128 = welt->get_settings().get_bonus_basefactor(); // minimal bonus factor const sint32 grundwert_bonus = 1000+kmh_base*desc->get_speed_bonus(); // speed bonus factor // take the larger of both return desc->get_value() * (grundwert128 > grundwert_bonus ? grundwert128 : grundwert_bonus); } ware_t::goods_amount_t ware_t::add_goods(goods_amount_t const to_add) { const goods_amount_t limit = GOODS_AMOUNT_LIMIT - amount; if (to_add > limit) { amount = GOODS_AMOUNT_LIMIT; return to_add - limit; } amount += to_add; return 0; } ware_t::goods_amount_t ware_t::remove_goods(goods_amount_t const to_remove) { if (to_remove > amount) { goods_amount_t const remainder = to_remove - amount; amount = 0; return remainder; } amount -= to_remove; return 0; } simutrans-124.3/src/simutrans/simware.h000066400000000000000000000077571474050137200202270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SIMWARE_H #define SIMWARE_H #include "halthandle.h" #include "dataobj/koord.h" #include "descriptor/goods_desc.h" class goods_manager_t; class karte_t; class player_t; /// Class to handle goods packets (and their destinations) class ware_t { friend class goods_manager_t; private: /// private lookup table to speedup static const goods_desc_t *index_to_desc[256]; public: /// Type used to specify an amount of goods. Always positive. typedef uint32 goods_amount_t; /// Maximum number of goods per ware package. Limited by the bit field used. static goods_amount_t const GOODS_AMOUNT_LIMIT = (1 << 23) - 1; /// type of good, used as index into goods-types array uint32 index : 8; /// amount of goods goods_amount_t amount : 23; /// To indicate that the ware's destination is a factory/consumer store uint32 to_factory : 1; private: /// Final destination halt. halthandle_t target_halt; /// Halt where the packet has to leave the convoy. halthandle_t via_halt; /// Target position (factory, etc) koord target_pos; /// Update target (zielpos) for factory-going goods (after loading or rotating) void update_factory_target(); public: ware_t(); ware_t(const goods_desc_t *desc); ware_t(loadsave_t *file); public: const halthandle_t &get_target_halt() const { return target_halt; } void set_target_halt(const halthandle_t &halt) { target_halt = halt; } const halthandle_t &get_via_halt() const { return via_halt; } void set_via_halt(const halthandle_t &halt) { via_halt = halt; } koord get_target_pos() const { return target_pos; } void set_target_pos(const koord new_pos) { target_pos = new_pos; } /// @returns the non-translated name of the ware. const char *get_name() const { return get_desc()->get_name(); } const char *get_mass() const { return get_desc()->get_mass(); } uint8 get_catg() const { return get_desc()->get_catg(); } uint8 get_index() const { return index; } const goods_desc_t *get_desc() const { return index_to_desc[index]; } void rdwr(loadsave_t *file); void finish_rd(karte_t *welt); // find out the category ... bool is_passenger() const { return index==0; } bool is_mail() const { return index==1; } bool is_freight() const { return index>2; } bool operator==(const ware_t &other) const { return index == other.index && amount == other.amount && to_factory == other.to_factory && target_halt == other.target_halt && via_halt == other.via_halt && target_pos == other.target_pos; } bool operator!=(const ware_t &w) const { return !(*this == w); } /// Mail and passengers just care about target station /// Freight needs to obey coordinates (since more than one factory might by connected) inline bool same_destination(const ware_t &w) const { return index == w.index && target_halt == w.target_halt && to_factory == w.to_factory && (!to_factory || target_pos==w.target_pos); } /** * Adjust target coordinates. * Must be called after factories have been rotated! */ void rotate90( sint16 y_size ); /** * Calculates transport revenue per tile and freight unit. * Takes speedbonus into account! * @param desc the freight * @param wt waytype of vehicle * @param speedkmh actual achieved speed in km/h */ static sint64 calc_revenue(const goods_desc_t *desc, waytype_t wt, sint32 speedkmh); /// Adds the number of goods to this goods packet. /// @return Any excess goods that could not be added, eg due to logical limits. goods_amount_t add_goods(goods_amount_t const to_add); /// Removes the number of goods from this goods packet. /// @return Any excess goods that could not be removed, eg due to logical limits. goods_amount_t remove_goods(goods_amount_t const to_remove); /// @returns True if goods amount is maxed out so no more goods can be added to this packet bool is_goods_amount_maxed() const { return amount == GOODS_AMOUNT_LIMIT; } }; #endif simutrans-124.3/src/simutrans/sound/000077500000000000000000000000001474050137200175175ustar00rootroot00000000000000simutrans-124.3/src/simutrans/sound/AVF_core-audio_sound.mm000066400000000000000000000023551474050137200240120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * Apple OSX Core Audio MIDI routine added by Leopard */ #include "sound.h" #import #import #import #import static NSMutableArray* players_WAV; bool dr_init_sound() { printf("Sound system Initialise\n"); printf("Wave File database\n"); players_WAV = [NSMutableArray arrayWithCapacity: 128]; printf("Sound system Initialisation complete\n"); return true; } int dr_load_sample(char const* const filename) { NSURL* const url = [NSURL fileURLWithPath: [NSString stringWithUTF8String: filename]]; AVAudioPlayer* const player = [[AVAudioPlayer alloc] initWithContentsOfURL: url error: nil]; if (!player) { printf("** Warning, unable to open wav file %s\n", filename); return -1; } // Preload the file into memory. [player setVolume: 0]; [player play]; [players_WAV addObject: player]; int const i = [players_WAV count] - 1; printf("Load WAV (%d): %s\n", i, filename); return i; } void dr_play_sample(int const key, int const volume) { AVAudioPlayer* const m = [players_WAV objectAtIndex: key]; [m setVolume: volume / 255.f]; [m play]; } simutrans-124.3/src/simutrans/sound/core-audio_sound.mm000066400000000000000000000022071474050137200233120ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* * Apple OSX Core Audio MIDI routine added by Leopard */ #include "sound.h" #import #import #import #import static NSMutableArray* movies_WAV; bool dr_init_sound() { printf("Sound system Initialise\n"); printf("Wave File database\n"); movies_WAV = [NSMutableArray arrayWithCapacity: 128]; printf("Sound system Initialisation complete\n"); return true; } int dr_load_sample(char const* const filename) { NSString* const s = [NSString stringWithUTF8String: filename]; QTMovie* const m = [QTMovie movieWithFile: s error: nil]; if (!m) { printf("** Warning, unable to open wav file %s\n", filename); return -1; } // Preload the file into memory. [m setVolume: 0]; [m play]; [movies_WAV addObject: m]; int const i = [movies_WAV count] - 1; printf("Load WAV (%d): %s\n", i, filename); return i; } void dr_play_sample(int const key, int const volume) { QTMovie* const m = [movies_WAV objectAtIndex: key]; [m setVolume: volume / 255.f]; [m play]; } simutrans-124.3/src/simutrans/sound/no_sound.cc000066400000000000000000000007061474050137200216550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /// stub for no sound #include "sound.h" bool dr_init_sound(void) { return false; } /** * loads a sample * @return a handle for that sample or -1 on failure */ int dr_load_sample(const char *) { return -1; } /** * plays a sample * * @param key the key for the sample to be played * @param volume */ void dr_play_sample(int, int) { } simutrans-124.3/src/simutrans/sound/sdl2_sound.cc000066400000000000000000000124461474050137200221110ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /// sdl-sound without SDL_mixer.dll #if !defined __APPLE__ && !defined __ANDROID__ #include #else #include #endif #include "sound.h" #include "../simmem.h" #include "../simdebug.h" #include #include /// flag if sound module should be used /// -1: error during initialization /// 0: not initialized /// 1: successfully initialized static int use_sound = 0; /// defines the number of channels available #define NUM_AUDIO_CHANNELS 4 /// Used to indicate that a channel is empty #define NO_SAMPLE (0xFF) /// this structure contains the data for one sample struct sample { // the buffer containing the data for the sample, the format // must always be identical to the one of the system output // format Uint8 *audio_data; Uint32 audio_len; // number of samples in the audio data }; /// this list contains all the samples static sample samples[64]; /// all samples are stored chronologically there static int samplenumber = 0; /// this structure contains the information about one channel struct channel { Uint32 sample_pos; ///< the current position inside this sample Uint8 sample; ///< which sample is played, or NO_SAMPLE if there is none Uint8 volume; ///< the volume this channel should be played }; /// this array contains all the information of the currently played samples static channel channels[NUM_AUDIO_CHANNELS]; /// the format of the output audio channel in use /// all loaded waved need to be converted to this format static SDL_AudioSpec output_audio_format; static SDL_AudioDeviceID audio_device; void sdl_sound_callback(void *, Uint8 * stream, int len) { memset(stream, 0, len); // SDL2 requires the output stream to be fully written on every callback. // add all the sample that need to be played for( int c = 0; c < NUM_AUDIO_CHANNELS; c++ ) { if (channels[c].sample == NO_SAMPLE) { // only do something if the channel is used continue; } sample *smp = &samples[channels[c].sample]; // add sample if (len + channels[c].sample_pos >= smp->audio_len ) { // SDL_MixAudio(stream, smp->audio_data + channels[c].sample_pos, smp->audio_len - channels[c].sample_pos, channels[c].volume); channels[c].sample = NO_SAMPLE; } else { SDL_MixAudioFormat(stream, smp->audio_data + channels[c].sample_pos, output_audio_format.format, len, channels[c].volume); channels[c].sample_pos += len; } } } bool dr_init_sound() { // avoid init twice if (use_sound != 0) { return use_sound > 0; } // initialize SDL sound subsystem if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1) { dbg->error("dr_init_sound(SDL2)", "Could not initialize sound system. Muting."); use_sound = -1; return false; } // open an audio channel SDL_AudioSpec desired; desired.freq = 22050; desired.channels = 1; desired.format = AUDIO_S16SYS; desired.samples = 1024; desired.userdata = NULL; desired.callback = sdl_sound_callback; // allow any change as loaded .wav files are converted to output format upon loading audio_device = SDL_OpenAudioDevice( NULL, 0, &desired, &output_audio_format, SDL_AUDIO_ALLOW_ANY_CHANGE ); if( !audio_device ) { dbg->error("dr_init_sound(SDL2)", "Could not open required audio channel. Muting."); SDL_QuitSubSystem(SDL_INIT_AUDIO); use_sound = -1; return false; } // finished initializing for (int i = 0; i < NUM_AUDIO_CHANNELS; i++) { channels[i].sample = NO_SAMPLE; } // start playing sounds SDL_PauseAudioDevice(audio_device, 0); use_sound = 1; return true; } int dr_load_sample(const char *filename) { if(use_sound<=0 || samplenumber>=64) { return -1; } SDL_AudioSpec wav_spec; SDL_AudioCVT wav_cvt; Uint8 *wav_data; Uint32 wav_length; sample smp; // load the sample if (SDL_LoadWAV(filename, &wav_spec, &wav_data, &wav_length) == NULL) { dbg->warning("dr_load_sample", "Could not load wav: %s", SDL_GetError()); return -1; } /* convert the loaded wav to the internally used sound format */ if (SDL_BuildAudioCVT(&wav_cvt, wav_spec.format, wav_spec.channels, wav_spec.freq, output_audio_format.format, output_audio_format.channels, output_audio_format.freq) < 0) { dbg->error("dr_load_sample", "Could not create conversion structure"); SDL_FreeWAV(wav_data); return -1; } wav_cvt.buf = MALLOCN(Uint8, wav_length * wav_cvt.len_mult); wav_cvt.len = wav_length; memcpy(wav_cvt.buf, wav_data, wav_length); SDL_FreeWAV(wav_data); if (SDL_ConvertAudio(&wav_cvt) < 0) { dbg->error("dr_load_sample", "Could not convert wav to output format"); return -1; } // save the data smp.audio_data = wav_cvt.buf; smp.audio_len = wav_cvt.len_cvt; samples[samplenumber] = smp; dbg->message("dr_load_sample", "Loaded '%s' to sample %i.", filename, samplenumber); return samplenumber++; } /* * plays a sample * * @param sample_number the key for the sample to be played * @param volume */ void dr_play_sample(int sample_number, int volume) { if (use_sound <= 0 || sample_number == -1) { return; } // find an empty channel, and play for (int c = 0; c < NUM_AUDIO_CHANNELS; c++) { if (channels[c].sample == NO_SAMPLE) { channels[c].sample = sample_number; channels[c].sample_pos = 0; channels[c].volume = volume * SDL_MIX_MAXVOLUME >> 8; break; } } } simutrans-124.3/src/simutrans/sound/sdl_mixer_sound.cc000066400000000000000000000051601474050137200232260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ // Sound with SDL_mixer.dll (not changing the volume of other programs) #include #include #include #include "sound.h" #include "../simdebug.h" /* * flag if sound module should be used */ static int use_sound = 0; /* this list contains all the samples */ static Mix_Chunk *samples[64]; /* all samples are stored chronologically there */ static int samplenumber = 0; /** * Sound initialisation routine */ bool dr_init_sound() { int sound_ok = 0; if(use_sound!=0) { return true; // avoid init twice } use_sound = 1; // initialize SDL sound subsystem if (SDL_InitSubSystem(SDL_INIT_AUDIO) != -1) { // open an audio channel int freq = 22050; int channels = 1; unsigned short int format = AUDIO_S16SYS; int samples = 1024; if (Mix_OpenAudio(freq, format, channels, samples) != -1) { Mix_QuerySpec(&freq, &format, &channels); // check if we got the right audio format if (format == AUDIO_S16SYS) { // finished initializing sound_ok = 1; // allocate 16 mixing channels Mix_AllocateChannels(16); // start playing sounds Mix_ResumeMusic(); } else { dbg->error("dr_init_sound()","Open audio channel doesn't meet requirements. Muting"); Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); } } else { dbg->error("dr_init_sound()","Could not open required audio channel. Muting"); SDL_QuitSubSystem(SDL_INIT_AUDIO); } } else { dbg->error("dr_init_sound()","Could not initialize sound system. Muting"); } use_sound = sound_ok ? 1: -1; return sound_ok; } /* * loads a sample * * @param filename * @return a handle for that sample or -1 on failure */ int dr_load_sample(const char *filename) { if(use_sound>0 && samplenumber<64) { Mix_Chunk *smp; /* load the sample */ smp = Mix_LoadWAV(filename); if (smp == NULL) { dbg->warning("dr_load_sample()", "could not load wav (%s)", SDL_GetError()); return -1; } samples[samplenumber] = smp; dbg->message("dr_load_sample()", "Loaded %s to sample %i.", filename, samplenumber); return samplenumber++; } return -1; } /** * plays a sample * * @param sample_nummer the key for the sample to be played * @param volume */ void dr_play_sample(int sample_number, int volume) { // sound enabled and a valid sample if(use_sound>0 && sample_number != -1) { // sdl_mixer finds free channel, we then play at correct volume int play_channel = Mix_PlayChannel(-1, samples[sample_number], 0); Mix_Volume(play_channel,(volume*MIX_MAX_VOLUME)/256); } } simutrans-124.3/src/simutrans/sound/sdl_sound.cc000066400000000000000000000125321474050137200220230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /// sdl-sound without SDL_mixer.dll #include #include #include "sound.h" #include "../simmem.h" #include "../simdebug.h" #include /* * flag if sound module should be used */ static int use_sound = 0; /* * defines the number of channels available */ #define NUM_AUDIO_CHANNELS 4 /* * this structure contains the data for one sample */ struct sample { /* the buffer containing the data for the sample, the format * must always be identical to the one of the system output * format */ Uint8 *audio_data; Uint32 audio_len; /* number of samples in the audio data */ }; /* this list contains all the samples */ static sample samples[64]; /* all samples are stored chronologically there */ static int samplenumber = 0; /* this structure contains the information about one channel */ struct channel { Uint32 sample_pos; /* the current position inside this sample */ Uint8 sample; /* which sample is played, 255 for no sample */ Uint8 volume; /* the volume this channel should be played */ }; /* this array contains all the information of the currently played samples */ static channel channels[NUM_AUDIO_CHANNELS]; /* the format of the output audio channel in use * all loaded waved need to be converted to this format */ static SDL_AudioSpec output_audio_format; void sdl_sound_callback(void *, Uint8 * stream, int len) { memset(stream, 0, len); // SDL2 requires the output stream to be fully written on every callback. /* * add all the sample that need to be played */ for( int c = 0; c < NUM_AUDIO_CHANNELS; c++ ) { /* * only do something, if the channel is used */ if (channels[c].sample != 255) { sample * smp = &samples[channels[c].sample]; /* * add sample */ if (len + channels[c].sample_pos >= smp->audio_len ) { // SDL_MixAudio(stream, smp->audio_data + channels[c].sample_pos, smp->audio_len - channels[c].sample_pos, channels[c].volume); channels[c].sample = 255; } else { SDL_MixAudio(stream, smp->audio_data + channels[c].sample_pos, len, channels[c].volume); channels[c].sample_pos += len; } } } } /** * Sound initialisation routine */ bool dr_init_sound() { int sound_ok = 0; if(use_sound!=0) { return use_sound; // avoid init twice } use_sound = 1; // initialize SDL sound subsystem if (SDL_InitSubSystem(SDL_INIT_AUDIO) != -1) { // open an audio channel SDL_AudioSpec desired; desired.freq = 22050; desired.channels = 1; desired.format = AUDIO_S16SYS; desired.samples = 1024; desired.userdata = NULL; desired.callback = sdl_sound_callback; if (SDL_OpenAudio(&desired, &output_audio_format) != -1) { // check if we got the right audio format if (output_audio_format.format == AUDIO_S16SYS) { int i; // finished initializing sound_ok = 1; for (i = 0; i < NUM_AUDIO_CHANNELS; i++) channels[i].sample = 255; // start playing sounds SDL_PauseAudio(0); } else { dbg->error("dr_init_sound()", "Open audio channel doesn't meet requirements. Muting"); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); } } else { dbg->error("dr_init_sound()", "Could not open required audio channel. Muting"); SDL_QuitSubSystem(SDL_INIT_AUDIO); } } else { dbg->error("dr_init_sound()", "Could not initialize sound system. Muting"); } use_sound = sound_ok ? 1: -1; return sound_ok; } /** * loads a sample * * @param filename * @return a handle for that sample or -1 on failure */ int dr_load_sample(const char *filename) { if(use_sound>0 && samplenumber<64) { SDL_AudioSpec wav_spec; SDL_AudioCVT wav_cvt; Uint8 *wav_data; Uint32 wav_length; sample smp; /* load the sample */ if (SDL_LoadWAV(filename, &wav_spec, &wav_data, &wav_length) == NULL) { dbg->warning("dr_load_sample", "could not load wav (%s)", SDL_GetError()); return -1; } /* convert the loaded wav to the internally used sound format */ if (SDL_BuildAudioCVT(&wav_cvt, wav_spec.format, wav_spec.channels, wav_spec.freq, output_audio_format.format, output_audio_format.channels, output_audio_format.freq) < 0) { dbg->warning("dr_load_sample", "could not create conversion structure"); SDL_FreeWAV(wav_data); return -1; } wav_cvt.buf = MALLOCN(Uint8, wav_length * wav_cvt.len_mult); wav_cvt.len = wav_length; memcpy(wav_cvt.buf, wav_data, wav_length); SDL_FreeWAV(wav_data); if (SDL_ConvertAudio(&wav_cvt) < 0) { dbg->warning("dr_load_sample", "could not convert wav to output format"); return -1; } /* save the data */ smp.audio_data = wav_cvt.buf; smp.audio_len = wav_cvt.len_cvt; samples[samplenumber] = smp; dbg->message("dr_load_sample", "Loaded %s to sample %i.",filename,samplenumber); return samplenumber++; } return -1; } /* * plays a sample * * @param sample_number the key for the sample to be played * @param volume */ void dr_play_sample(int sample_number, int volume) { if(use_sound>0) { int c; if (sample_number == -1) { return; } /* find an empty channel, and play */ for (c = 0; c < NUM_AUDIO_CHANNELS; c++) { if (channels[c].sample == 255) { channels[c].sample = sample_number; channels[c].sample_pos = 0; channels[c].volume = volume * SDL_MIX_MAXVOLUME >> 8; break; } } } } simutrans-124.3/src/simutrans/sound/sound.h000066400000000000000000000007721474050137200210260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SOUND_SOUND_H #define SOUND_SOUND_H /** * Sound initialisation routine */ bool dr_init_sound(); /** * loads a sample * * @param filename * @return a handle for that sample or -1 on failure */ int dr_load_sample(const char* filename); /** * plays a sample * * @param key the handle for the sample to be played * @param volume */ void dr_play_sample(int key, int volume); #endif simutrans-124.3/src/simutrans/sound/win32_sound.cc000066400000000000000000000035111474050137200222000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "sound.h" #include "../sys/simsys.h" /* * flag if sound module should be used * with Win32 the number+1 of the device used */ static int use_sound = 0; /* this list contains all the samples */ static void *samples[64]; static int sample_number = 0; /** * Sound initialisation routine */ bool dr_init_sound() { use_sound = 1; return true; } /** * loads a single sample * * @param filename * @return a handle for that sample or -1 on failure */ int dr_load_sample(char const* filename) { if(use_sound && sample_number>=0 && sample_number<64) { if (FILE* const fIn = dr_fopen(filename, "rb")) { long len; fseek( fIn, 0, SEEK_END ); len = ftell( fIn ); if(len>0) { samples[sample_number] = GlobalLock( GlobalAlloc( GMEM_MOVEABLE, (len+4)&0x7FFFFFFCu ) ); rewind( fIn ); fread( samples[sample_number], len, 1, fIn ); fclose( fIn ); return sample_number++; } } } return -1; } /* * plays a sample * * @param sample_number the key for the sample to be played * @param volume */ void dr_play_sample(int sample_number, int volume) { if(use_sound!=0 && sample_number>=0 && sample_number<64 && volume>1) { static int oldvol = -1; volume = (volume<<8)-1; if(oldvol!=volume) { DWORD vol = (volume<<16)|volume; waveOutSetVolume( 0, vol ); oldvol = volume; } UINT flags = SND_MEMORY | SND_ASYNC | SND_NODEFAULT; // Terminate the current sound, if not already the requested one. static int last_sample_nr = -1; if( last_sample_nr == sample_number ) { flags |= SND_NOSTOP; } last_sample_nr = sample_number; sndPlaySound(static_cast(samples[sample_number]), flags); } } simutrans-124.3/src/simutrans/sound/win32_sound_xa.cc000066400000000000000000000120421474050137200226670ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ /* The code is mostly copied and slightly adapted straight from the microsoft documetnation. * There was no clear indicating of license, so public domain is assumed. */ #include #if defined (__GNUC__) #include #else #include #endif #include "../tpl/vector_tpl.h" vector_tpl wfs; vector_tpl bufs; static IXAudio2* pXAudio2 = NULL; static IXAudio2MasteringVoice* pMasterVoice = NULL; /** * Sound initialisation routine */ bool dr_init_sound() { if( XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR) < 0) { return false; } if( pXAudio2->CreateMasteringVoice(&pMasterVoice) < 0 ) { return false; } return true; } #ifdef SIM_BIG_ENDIAN #define fourccRIFF 'RIFF' #define fourccDATA 'data' #define fourccFMT 'fmt ' #define fourccWAVE 'WAVE' #define fourccXWMA 'XWMA' #define fourccDPDS 'dpds' #else #define fourccRIFF 'FFIR' #define fourccDATA 'atad' #define fourccFMT ' tmf' #define fourccWAVE 'EVAW' #define fourccXWMA 'AMWX' #define fourccDPDS 'sdpd' #endif HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD& dwChunkSize, DWORD& dwChunkDataPosition) { HRESULT hr = S_OK; if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) return HRESULT_FROM_WIN32(GetLastError()); DWORD dwChunkType; DWORD dwChunkDataSize; DWORD dwRIFFDataSize = 0; DWORD dwFileType; DWORD bytesRead = 0; DWORD dwOffset = 0; while (hr == S_OK) { DWORD dwRead; if (0 == ReadFile(hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL)) hr = HRESULT_FROM_WIN32(GetLastError()); if (0 == ReadFile(hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL)) hr = HRESULT_FROM_WIN32(GetLastError()); switch (dwChunkType) { case fourccRIFF: dwRIFFDataSize = dwChunkDataSize; dwChunkDataSize = 4; if (0 == ReadFile(hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL)) hr = HRESULT_FROM_WIN32(GetLastError()); break; default: if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, dwChunkDataSize, NULL, FILE_CURRENT)) return HRESULT_FROM_WIN32(GetLastError()); } dwOffset += sizeof(DWORD) * 2; if (dwChunkType == fourcc) { dwChunkSize = dwChunkDataSize; dwChunkDataPosition = dwOffset; return S_OK; } dwOffset += dwChunkDataSize; if (bytesRead >= dwRIFFDataSize) return S_FALSE; } return S_OK; } static HRESULT ReadChunkData(HANDLE hFile, void* buffer, DWORD buffersize, DWORD bufferoffset) { HRESULT hr = S_OK; if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, bufferoffset, NULL, FILE_BEGIN)) return HRESULT_FROM_WIN32(GetLastError()); DWORD dwRead; if (0 == ReadFile(hFile, buffer, buffersize, &dwRead, NULL)) hr = HRESULT_FROM_WIN32(GetLastError()); return hr; } /* * loads a single sample * * @param strFileName * @return a handle for that sample or -1 on failure */ int dr_load_sample(char const* strFileName) { WAVEFORMATEXTENSIBLE wfx = { 0 }; XAUDIO2_BUFFER buffer = { 0 }; // Open the file HANDLE hFile = CreateFileA(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == hFile) { return -1; } if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN)) { return -1; } DWORD dwChunkSize; DWORD dwChunkPosition; //check the file type, should be fourccWAVE or 'XWMA' FindChunk(hFile, fourccRIFF, dwChunkSize, dwChunkPosition); DWORD filetype; ReadChunkData(hFile, &filetype, sizeof(DWORD), dwChunkPosition); if (filetype != fourccWAVE) { return -1; } FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition); ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition); //fill out the audio data buffer with the contents of the fourccDATA chunk FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition); BYTE* pDataBuffer = new BYTE[dwChunkSize]; ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition); buffer.AudioBytes = dwChunkSize; //size of the audio buffer in bytes buffer.pAudioData = pDataBuffer; //buffer containing audio data buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer wfs.append(wfx); bufs.append(buffer); return wfs.get_count() - 1; } /* * plays a sample * * @param sample_number the key for the sample to be played * @param volume */ void dr_play_sample(int sample_number, int volume) { IXAudio2SourceVoice* pSourceVoice; if (pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&(wfs[sample_number]))<0 ||pSourceVoice->SubmitSourceBuffer(&(bufs[sample_number])) < 0) { return; } pSourceVoice->SetVolume(volume/256.0); pSourceVoice->Start(0); } simutrans-124.3/src/simutrans/sys/000077500000000000000000000000001474050137200172055ustar00rootroot00000000000000simutrans-124.3/src/simutrans/sys/clipboard_internal.cc000066400000000000000000000035501474050137200233520ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "simsys.h" #include "../utils/unicode.h" #define MAX_SIZE (4096) static char content[MAX_SIZE] = ""; static size_t content_length = 0; /** * Copy text to the clipboard * @param source : pointer to the start of the source text * @param length : number of character bytes to copy */ void dr_copy(const char *source, size_t length) { assert( length0 ) { *content_ptr++ = *source++; } } /** * Paste text from the clipboard * @param target : pointer to the insertion position in the target text * @param max_length : maximum number of character bytes which could be inserted * @return number of character bytes actually inserted -> for cursor advancing */ size_t dr_paste(char *target, size_t max_length) { // determine the number of bytes to be pasted if( content_length<=max_length ) { max_length = content_length; } else { // ensure that max_length aligns with logical character boundaries of clipboard content size_t tmp_length = 0; size_t byte_count; while( tmp_length+(byte_count=utf8_get_next_char(content+tmp_length,0u))<=max_length ) { tmp_length += byte_count; } max_length = tmp_length; } const size_t inserted_length = max_length; // move the text to free up space for inserting the clipboard content char *target_old_end = target + strlen(target); char *target_new_end = target_old_end + max_length; while( target_old_end>=target ) { *target_new_end-- = *target_old_end--; } // insert the clipboard content const char *content_ptr = content; while( (max_length--)>0 ) { *target++ = *content_ptr++; } // return the inserted length for cursor advancing return inserted_length; } simutrans-124.3/src/simutrans/sys/clipboard_s2.cc000066400000000000000000000026451474050137200220660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simsys.h" #include "../display/simgraph.h" #include "../simdebug.h" #include "../dataobj/translator.h" #include "../utils/unicode.h" #if !defined __APPLE__ && !defined __ANDROID__ #include #else #include #endif #include /** * Copy text to the clipboard * @param source : pointer to the start of the source text * @param length : number of character bytes to copy */ void dr_copy(const char *source, size_t length) { char *text = (char *)malloc( length+1 ); strncpy( text, source, length ); text[length] = 0; SDL_SetClipboardText( text ); free( text ); } /** * Paste text from the clipboard * @param target : pointer to the insertion position in the target text * @param max_length : maximum number of character bytes which could be inserted * @return number of character bytes actually inserted -> for cursor advancing */ size_t dr_paste(char *target, size_t max_length) { size_t insert_len = 0; if( SDL_HasClipboardText() ) { char *str = SDL_GetClipboardText(); // Insert string. size_t const str_len = strlen(str); insert_len = str_len <= max_length ? str_len : (size_t)utf8_get_prev_char((utf8 const *)str, max_length); memmove(target + insert_len, target, strlen(target) + 1); memcpy(target, str, insert_len); SDL_free( str ); } return insert_len; } simutrans-124.3/src/simutrans/sys/clipboard_w32.cc000066400000000000000000000041031474050137200221440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simsys.h" #include "../display/simgraph.h" #include "../simdebug.h" #include "../dataobj/translator.h" #include "../utils/unicode.h" #include #include /** * Copy text to the clipboard * @param source : pointer to the start of the source text * @param length : number of character bytes to copy */ void dr_copy(const char *source, size_t length) { if( OpenClipboard(NULL) ) { if( EmptyClipboard() ) { // Allocate clipboard space. int const len = (int)length; int const wsize = MultiByteToWideChar(CP_UTF8, 0, source, len, NULL, 0) + 1; HANDLE hglbCopy = GlobalAlloc(GMEM_MOVEABLE, wsize * sizeof(WCHAR)); LPWSTR const wstr = (LPWSTR)GlobalLock(hglbCopy); if (wstr != NULL) { // Convert string. NUL appended implicitly by 0ed memory. MultiByteToWideChar(CP_UTF8, 0, source, len, wstr, wsize); } GlobalUnlock(hglbCopy); SetClipboardData(CF_UNICODETEXT, hglbCopy); } CloseClipboard(); } } /** * Paste text from the clipboard * @param target : pointer to the insertion position in the target text * @param max_length : maximum number of character bytes which could be inserted * @return number of character bytes actually inserted -> for cursor advancing */ size_t dr_paste(char *target, size_t max_length) { size_t insert_len = 0; if( OpenClipboard(NULL) ) { LPWSTR const wstr = (LPWSTR)GetClipboardData(CF_UNICODETEXT); if( wstr != NULL ) { // Convert entire clipboard to UTF-8. int const size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); char *const str = new char[size]; WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, size, NULL, NULL); // Insert string. size_t const str_len = strlen(str); insert_len = str_len <= max_length ? str_len : (size_t)utf8_get_prev_char((utf8 const *)str, max_length); memmove(target + insert_len, target, strlen(target) + 1); memcpy(target, str, insert_len); delete[] str; } CloseClipboard(); } return insert_len; } simutrans-124.3/src/simutrans/sys/simsys.cc000066400000000000000000001073651474050137200210570ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include #ifdef __HAIKU__ #include #include #include #include #include #define NO_UINT32_TYPES #define NO_UINT64_TYPES #endif #include "../dataobj/environment.h" #include "../macros.h" #include "../simmain.h" #include "simsys.h" #include "../pathes.h" #include "../simevent.h" #include "../utils/simstring.h" #include "../simdebug.h" #include "../simevent.h" #include "../simversion.h" #ifdef _WIN32 # include # include # include # include # include # if !defined(__CYGWIN__) # include # else # include # endif # include "../simdebug.h" #else # include # include # if !defined __AMIGA__ && !defined __BEOS__ # include # endif # ifdef __ANDROID__ # include # endif #endif #ifdef USE_FONTCONFIG #include #endif #ifdef MULTI_THREAD #include #endif #ifdef _OPTIMIZED #define L_DEBUG_TEXT " (optimized)" #elif defined DEBUG # define L_DEBUG_TEXT " (debug)" #else # define L_DEBUG_TEXT #endif sys_event_t sys_event; #ifdef _WIN32 /** * Utility class to handle conversion of UTF-8 to UTF-16 for use by Windows APIs. * Constructs a UTF-16 view of the current contents of a UTF-8 C string. */ class U16View { private: LPCWSTR cu16str; public: /** * Constructs a UTF-16 view of a UTF-8 C string. */ U16View(char const *const u8str) { // Convert UTF-8 to UTF-16. int const size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8str, -1, NULL, 0); if(size == 0) { // It should never fail, since all file IO UTF8 comes either via keyborad input or filenames, i.e. a win32 api. // log may not even initialising at this point, so we just fail. dr_fatal_notify( "Unknown unicode character encountered!" ); exit(0); } LPWSTR const u16str = new WCHAR[size]; MultiByteToWideChar(CP_UTF8, 0, u8str, -1, u16str, size); cu16str = u16str; } /** * Copy constructor to allow safe movement. * Should also have move constructor to allow efficient movement but that requires C++11. */ U16View(U16View const& from) { LPWSTR const u16str = new WCHAR[wcslen(from.cu16str) + 1]; wcscpy(u16str, from.cu16str); cu16str = u16str; } ~U16View() { delete[] cu16str; } /** * Typecast operator to allow implicit use as a LPCWSTR. */ operator LPCWSTR() const { return cu16str; } }; #endif // Platform specific path separators. #ifdef _WIN32 char const PATH_SEPARATOR[] = "\\"; #else char const PATH_SEPARATOR[] = "/"; #endif scr_coord get_mouse_pos() { return { sys_event.mx, sys_event.my }; } uint8 dr_get_max_threads() { uint8 max_threads = 0; #ifdef MULTI_THREAD #if 0 // does not work when crosscompile with mingw! max_threads = std::thread::hardware_concurrency(); #endif if(max_threads==0) { #ifdef _WIN32 SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); max_threads = (uint8)sysinfo.dwNumberOfProcessors; #else max_threads = sysconf(_SC_NPROCESSORS_ONLN); #endif } #endif return max(max_threads,1); } // create a directory with all subdirectories needed int dr_mkdir(char const* const path) { if (path == 0 || path[0]==0) { // always succed on empty string (should never happen) return 0; } #ifdef _WIN32 const char* new_dir_with_path = path; // Perform operation needs absolute path if (path[1] != ':' && path[1] != '\\') { // so let get the absolute path char abs_buf[MAX_PATH]; dr_getcwd(abs_buf, MAX_PATH); if (strlen(abs_buf) + strlen(path) + 2 >= MAX_PATH) { return -1; } strcat(abs_buf, "\\"); strcat(abs_buf, path); new_dir_with_path = abs_buf; } int result = SHCreateDirectory(NULL, U16View(new_dir_with_path)) ? 0 : -1; // Translate error. if (result != ERROR_SUCCESS) { DWORD const error = GetLastError(); if (error == ERROR_ALREADY_EXISTS || error == ERROR_FILE_EXISTS) { errno = EEXIST; } else if (error == ERROR_PATH_NOT_FOUND) { errno = ENOENT; } } return result; #else // create also intermediate directories char tmp[PATH_MAX]; size_t len; snprintf(tmp, sizeof(tmp), "%s", path); // remove trailing director separator len = strnlen(tmp, sizeof(tmp)); if (tmp[len - 1] == *PATH_SEPARATOR) { tmp[len - 1] = 0; } // now walk the path for (char *p = tmp + 1; *p; p++ ) { if (*p == '/') { *p = '\0'; // mkdir mail fail if already existing, but we continue anyway mkdir(tmp, 0777); *p = '/'; } } return mkdir(path, 0777); #endif } bool dr_movetotrash(const char *path) { #ifdef _WIN32 // Convert to full path name to allow use of recycle bin. // Must be double null terminated for SHFILESTRUCT U16View const wpath(path); int const full_size = GetFullPathNameW(wpath, 0, NULL, NULL); wchar_t *const full_wpath = new wchar_t[full_size + 1]; GetFullPathNameW(wpath, full_size, full_wpath, NULL); full_wpath[full_size] = L'\0'; // Initalize file operation structure. SHFILEOPSTRUCTW FileOp; FileOp.hwnd = GetActiveWindow(); FileOp.wFunc = FO_DELETE; FileOp.pFrom = full_wpath; FileOp.pTo = NULL; FileOp.fFlags = FOF_ALLOWUNDO|FOF_NOCONFIRMATION; // Perform operation. int success = SHFileOperationW(&FileOp); delete[] full_wpath; BringWindowToTop(FileOp.hwnd); return success; #else return remove(path); #endif } bool dr_cantrash() { #ifdef _WIN32 return true; #else return false; #endif } int dr_remove(const char *path) { #ifdef _WIN32 // Perform operation. bool success = DeleteFileW(U16View(path)); // Translate error. if(!success) { DWORD error = GetLastError(); if(error == ERROR_FILE_NOT_FOUND) { errno = ENOENT; } else if(error == ERROR_ACCESS_DENIED) { errno = EACCES; } } // try to remove directory if this is a directory and empty ... success = RemoveDirectoryW(U16View(path)); return success ? 0 : -1; #else return remove(path); #endif } int dr_rename(const char *existing_utf8, const char *new_utf8) { #ifdef _WIN32 // Perform operation. bool success = MoveFileExW(U16View(existing_utf8), U16View(new_utf8), MOVEFILE_REPLACE_EXISTING); // Translate error. if(!success) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { errno = ENOENT; } else if(error == ERROR_ACCESS_DENIED) { errno = EACCES; } } return success ? 0 : -1; #else remove( new_utf8 ); return rename( existing_utf8, new_utf8 ); #endif } int dr_chdir(const char *path) { #ifdef _WIN32 // Perform operation. bool success = SetCurrentDirectoryW(U16View(path)); // Translate error. if(!success) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { errno = ENOENT; } else if(error == ERROR_ACCESS_DENIED) { errno = EACCES; } } return success ? 0 : -1; #else return chdir(path); #endif } char *dr_getcwd(char *buf, size_t size) { #ifdef _WIN32 DWORD wsize = GetCurrentDirectoryW(0, NULL); WCHAR *const wpath = new WCHAR[wsize]; DWORD success = GetCurrentDirectoryW(wsize, wpath); // Translate error. if(!success) { delete[] wpath; return NULL; } // Convert UTF-16 to UTF-8. int const convert_size = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buf, (int)size, NULL, NULL); delete[] wpath; if(convert_size == 0) { return NULL; } return buf; #else return getcwd(buf, size); #endif } FILE *dr_fopen (const char *filename, const char *mode) { #ifdef _WIN32 return _wfopen(U16View(filename), U16View(mode)); #else return fopen(filename, mode); #endif } gzFile dr_gzopen(const char *path, const char *mode) { #ifdef _WIN32 return gzopen_w(U16View(path), mode); #else return gzopen(path, mode); #endif } int dr_stat(const char *path, struct stat *buf) { #ifdef _WIN32 return _wstat(U16View(path), (struct _stat*)buf); #else return stat(path, buf); #endif } bool check_and_set_dir( const char *path, const char *info, char *result, const char *testfile) { if( path && *path ) { bool ok = !dr_chdir(path); // Attempt to create it (if we aren't testing for an existing directory containing a file). if(!ok && !testfile) { dr_mkdir(path); ok = !dr_chdir(path); } else if(testfile) { FILE* testf = fopen(testfile,"r"); ok = ok && testf; if(testf) { fclose(testf); } } if(!ok) { printf("WARNING: Objects not found in %s \"%s\"!\n", info, path); } else { dr_getcwd( result, PATH_MAX-1 ); strcat( result, PATH_SEPARATOR ); return true; } } return false; } /** * Simutrans has three directories: * base_dir: directory with default data (may be write protected) * install_dir: global writable directory where paksets are installed * user_dir: a user writable directory * * The directory will be determined in the following order * -set_XXXdir Path (command line option) * SIMUTRANS_XXXDIR (environment variable) * (in case of base_dir current path, then executable path) * (for user_dir and install_dir: machine dependent default directories) * * The pak_dir contains the complete path to the current pak, since it could be in different locations * */ bool dr_set_basedir(const char * base_dir_arg, char * executable_path) { bool found_basedir = false; #ifdef __ANDROID__ found_basedir = check_and_set_dir( SDL_AndroidGetInternalStoragePath(), "Android Internal Storage", env_t::base_dir, "config/simuconf.tab"); #else found_basedir = check_and_set_dir( base_dir_arg, "-set_basedir", env_t::base_dir, "config/simuconf.tab"); if( !found_basedir ) { found_basedir = check_and_set_dir( getenv("SIMUTRANS_BASEDIR"), "SIMUTRANS_BASEDIR", env_t::base_dir, "config/simuconf.tab"); if( !found_basedir ) { dr_getcwd(env_t::base_dir, lengthof(env_t::base_dir)); strcat( env_t::base_dir, PATH_SEPARATOR ); // test if base installation if (FILE* f = dr_fopen("config/simuconf.tab", "r")) { fclose(f); found_basedir = true; } else { char testpath[PATH_MAX]; tstrncpy(testpath, executable_path, lengthof(testpath)); char* c = strrchr(testpath, *PATH_SEPARATOR); if(c) { *c = 0; // remove program name found_basedir = check_and_set_dir(testpath, "program dir", env_t::base_dir, "config/simuconf.tab"); if(!found_basedir) { #ifdef __APPLE__ // Detect if the binary is started inside an application bundle // Change working dir from MacOS to Resources dir strcpy(env_t::base_dir, testpath); if( strstr(env_t::base_dir, ".app/Contents/MacOS") != NULL ) { while (env_t::base_dir[strlen(env_t::base_dir) - 1] != 's') { env_t::base_dir[strlen(env_t::base_dir) - 1] = 0; } strcat(env_t::base_dir, "/Resources/simutrans/"); found_basedir = true; } #else // Detect if simutrans has been installed by the system and try to locate the installation relative to the binary location char *c = strrchr(testpath, *PATH_SEPARATOR); if( c && strcmp(c+1,"bin")==0 ) { // replace bin with other paths strcpy( c+1, "share/simutrans/" ); found_basedir = check_and_set_dir(testpath, "program dir", env_t::base_dir, "config/simuconf.tab"); if (!found_basedir) { strcpy( c+1 , "share/games/simutrans/" ); found_basedir = check_and_set_dir(testpath, "share/games/simutrans", env_t::base_dir, "config/simuconf.tab"); } } #endif } } } } } #endif if (!found_basedir) { // try the installer dir next found_basedir = check_and_set_dir(dr_query_installdir(), "install_dir", env_t::base_dir, "config/simuconf.tab"); } return found_basedir; } char const *dr_query_homedir() { static char buffer[PATH_MAX + 24]; #if defined _WIN32 WCHAR whomedir[MAX_PATH]; if(FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, whomedir))) { DWORD len = sizeof(whomedir); HKEY hHomeDir; if(RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hHomeDir) != ERROR_SUCCESS) { return NULL; } LONG const status = RegQueryValueExW(hHomeDir, L"Personal", NULL, NULL, (LPBYTE)whomedir, &len); RegCloseKey(hHomeDir); if(status != ERROR_SUCCESS) { return NULL; } } // Convert UTF-16 to UTF-8. int const convert_size = WideCharToMultiByte(CP_UTF8, 0, whomedir, -1, buffer, sizeof(buffer), NULL, NULL); if(convert_size == 0) { return NULL; } // Append Simutrans folder. char const foldername[] = "Simutrans"; if(lengthof(buffer) < strlen(buffer) + strlen(foldername) + 2 * strlen(PATH_SEPARATOR) + 1){ return NULL; } strcat(buffer, PATH_SEPARATOR); strcat(buffer, foldername); #elif defined __APPLE__ int maxlen = PATH_MAX + 22; unsigned n = snprintf(buffer, maxlen, "%s/Library/Simutrans", getenv("HOME")); if (n >= maxlen) { return NULL; } #elif defined __HAIKU__ BPath userDir; find_directory(B_USER_DIRECTORY, &userDir); sprintf(buffer, "%s/simutrans", userDir.Path()); #elif defined __ANDROID__ buffer[0] = 0; int state = SDL_AndroidGetExternalStorageState(); if (state & SDL_ANDROID_EXTERNAL_STORAGE_WRITE) { const char* p = SDL_AndroidGetExternalStoragePath(); if (p) { strcpy(buffer, p); dr_mkdir("/sdcard/simutrans"); } } if (!*buffer) { dbg->warning("dr_query_homedir()", "SDL_AndroidGetExternalStoragePath() failed."); // no permission tstrncpy(buffer, SDL_GetPrefPath("Simutrans Team", "simutrans"), lengthof(buffer)); } #else int maxlen = PATH_MAX + 22; unsigned n; if( getenv("XDG_DATA_HOME") == NULL ) { n = snprintf(buffer, maxlen, "%s/simutrans", getenv("HOME")); } else { n = snprintf(buffer, maxlen, "%s/simutrans", getenv("XDG_DATA_HOME")); } if (n >= maxlen) { return NULL; } #endif strcat(buffer, PATH_SEPARATOR); return buffer; } char const *dr_query_installdir() { static char buffer[PATH_MAX + 24]; #if defined _WIN32 WCHAR whomedir[MAX_PATH]; if(FAILED(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, whomedir))) { return NULL; } // Convert UTF-16 to UTF-8. int const convert_size = WideCharToMultiByte(CP_UTF8, 0, whomedir, -1, buffer, sizeof(buffer), NULL, NULL); if(convert_size == 0) { return NULL; } // Append Simutrans folder. char const foldername[] = "Simutrans"; if(lengthof(buffer) < strlen(buffer) + strlen(foldername) + 2 * strlen(PATH_SEPARATOR) + 1){ return NULL; } strcat(buffer, PATH_SEPARATOR); strcat(buffer, foldername); #elif defined __APPLE__ int maxlen = PATH_MAX + 22; unsigned n = snprintf(buffer, maxlen, "%s/Library/Simutrans/paksets", getenv("HOME")); if (n >= maxlen) { return NULL; } #elif defined __HAIKU__ BPath userDir; find_directory(B_USER_DIRECTORY, &userDir); sprintf(buffer, "%s/simutrans/paksets", userDir.Path()); #elif defined __ANDROID__ tstrncpy(buffer,SDL_AndroidGetExternalStoragePath(),lengthof(buffer)); #else int maxlen = PATH_MAX + 22; unsigned n; if( getenv("XDG_DATA_HOME") == NULL ) { n = snprintf(buffer, maxlen, "%s/simutrans/paksets", getenv("HOME")); } else { n = snprintf(buffer, maxlen, "%s/simutrans/paksets", getenv("XDG_DATA_HOME")); } if (n >= maxlen) { return NULL; } #endif strcat(buffer, PATH_SEPARATOR); return buffer; } const char *dr_query_fontpath(int which) { #ifdef _WIN32 if (!which) { // Build full font file path static CHAR winDir[MAX_PATH]; GetWindowsDirectoryA(winDir, MAX_PATH); strcat(winDir, "\\Fonts\\"); return winDir; } return NULL; #else // linux has more than one path // sometimes there is the file "/etc/fonts/fonts.conf" and we can read it // however, since we cannot rely on it, we just try a few candiates // Apple only uses three locals, and Haiku has no standard ... const char *trypaths[] = { #ifdef __APPLE__ "~/Library/", "/Library/Fonts/", "/System/Library/Fonts/", #elif defined __HAIKU__ "/boot/system/non-packaged/data/fonts/", "/boot/home/config/non-packaged/data/fonts/", "~/config/non-packaged/data/fonts/", "/boot/system/data/fonts/ttfonts/", #else "~/.fonts/", "~/.local/share/fonts/", "/usr/share/fonts/", "/usr/X11R6/lib/X11/fonts/", "/usr/local/share/fonts/", #endif NULL }; if( trypaths[which] != NULL ) { static char fontpath[PATH_MAX]; if( trypaths[which][0] == '~' ) { // prepace with homedirectory snprintf( fontpath, PATH_MAX, "%s/%s", getenv("HOME"), trypaths[which]+2 ); } else { tstrncpy( fontpath, trypaths[which], PATH_MAX ); } return fontpath; } return NULL; #endif } std::string dr_get_system_font() { #if COLOUR_DEPTH != 0 #ifdef WIN32 #define DEFAULT_FONT "arial.ttf" NONCLIENTMETRICSW ncm; ncm.cbSize = sizeof(NONCLIENTMETRICSW); SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, 0); std::wstring wsFaceName = ncm.lfMessageFont.lfFaceName; LPCWSTR fontRegistryPath = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; HKEY hKey; LONG result; // Open Windows font registry key result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontRegistryPath, 0, KEY_READ, &hKey); if (result != ERROR_SUCCESS) { return DEFAULT_FONT; } DWORD maxValueNameSize, maxValueDataSize; result = RegQueryInfoKeyW(hKey, 0, 0, 0, 0, 0, 0, 0, &maxValueNameSize, &maxValueDataSize, 0, 0); if (result != ERROR_SUCCESS) { return DEFAULT_FONT; } DWORD valueIndex = 0; LPWSTR valueName = new WCHAR[maxValueNameSize]; LPBYTE valueData = new BYTE[maxValueDataSize]; DWORD valueNameSize, valueDataSize, valueType; std::wstring wsFontFile; // So far best matching font name std::wstring wsBestMatch; do { wsFontFile.clear(); valueDataSize = maxValueDataSize; valueNameSize = maxValueNameSize; result = RegEnumValueW(hKey, valueIndex, valueName, &valueNameSize, 0, &valueType, valueData, &valueDataSize); valueIndex++; if (result != ERROR_SUCCESS || valueType != REG_SZ) { continue; } std::wstring wsValueName(valueName, valueNameSize); // Found a match if (_wcsnicmp(wsFaceName.c_str(), wsValueName.c_str(), wsFaceName.length()) == 0) { // full match wsFontFile.assign((LPWSTR)valueData, valueDataSize/2); break; } // Sometimes the face name is a family name; then only a partial match will be possible if (wcsstr(wsValueName.c_str(), wsFaceName.c_str())) { wsBestMatch.assign((LPWSTR)valueData, valueDataSize/2); } } while (result != ERROR_NO_MORE_ITEMS); delete[] valueName; delete[] valueData; RegCloseKey(hKey); if (wsFontFile.empty()) { if (wsBestMatch.empty()) { dbg->warning("dr_get_system_font()", "%s not found!", std::string(wsFaceName.begin(), wsFaceName.end()).c_str()); return DEFAULT_FONT; } wsFontFile = wsBestMatch; dbg->warning("dr_get_system_font()", "Using %s for %s", std::string(wsFontFile.begin(), wsFontFile.end()).c_str(), std::string(wsFaceName.begin(), wsFaceName.end()).c_str()); } // Build full font file path CHAR winDir[MAX_PATH]; GetWindowsDirectoryA(winDir, MAX_PATH); strcat(winDir, "\\Fonts\\"); // luckily any TTF font in windows has an ASCII name ... DBG_MESSAGE("dr_get_system_font()", "Using %s", std::string(wsFontFile.begin(), wsFontFile.end()).c_str()); return (std::string)winDir + std::string(wsFontFile.begin(), wsFontFile.end()); #elif defined(ANDROID) return FONT_PATH_X "Roboto-Regular.ttf"; #elif defined(USE_FONTCONFIG) std::string fontFile = FONT_PATH_X "cyr.bdf"; FcInit(); FcConfig* config = FcInitLoadConfigAndFonts(); FcPattern* pat = FcNameParse((const FcChar8*)"Sans"); FcConfigSubstitute(config, pat, FcMatchPattern); FcDefaultSubstitute(pat); FcResult result; FcPattern* font = FcFontMatch(config, pat, &result); if (font) { FcChar8* file = NULL; if ( FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch ) { fontFile = (char*)file; } } FcPatternDestroy(font); FcPatternDestroy(pat); FcConfigDestroy(config); FcFini(); return fontFile; #else return FONT_PATH_X "cyr.bdf"; #endif #else return ""; #endif } /* this retrieves the 2 byte string for the default language * I hope AmigaOS uses something like Linux for this ... */ #ifdef _WIN32 struct id2str_t { uint16 id; const char *name; }; const char *dr_get_locale_string() { static id2str_t id2str[] = { { 0x0001, "ar" }, { 0x0002, "bg" }, { 0x0003, "ca" }, { 0x0004, "zh\0Hans" }, { 0x0005, "cs" }, { 0x0006, "da" }, { 0x0007, "de" }, { 0x0008, "el" }, { 0x0009, "en" }, { 0x000a, "es" }, { 0x000b, "fi" }, { 0x000c, "fr" }, { 0x000d, "he" }, { 0x000e, "hu" }, { 0x000f, "is" }, { 0x0010, "it" }, { 0x0011, "ja" }, { 0x0012, "ko" }, { 0x0013, "nl" }, { 0x0014, "no" }, { 0x0015, "pl" }, { 0x0016, "pt" }, { 0x0017, "rm" }, { 0x0018, "ro" }, { 0x0019, "ru" }, { 0x001a, "hr" }, { 0x001b, "sk" }, { 0x001c, "sq" }, { 0x001d, "sv" }, { 0x001e, "th" }, { 0x001f, "tr" }, { 0x0020, "ur" }, { 0x0021, "id" }, { 0x0022, "uk" }, { 0x0023, "be" }, { 0x0024, "sl" }, { 0x0025, "et" }, { 0x0026, "lv" }, { 0x0027, "lt" }, { 0x0028, "tg" }, { 0x0029, "fa" }, { 0x002a, "vi" }, { 0x002b, "hy" }, { 0x002c, "az" }, { 0x002d, "eu" }, { 0x002e, "hsb" }, { 0x002f, "mk" }, { 0x0030, "st" }, { 0x0031, "ts" }, { 0x0032, "tn" }, { 0x0033, "ve" }, { 0x0034, "xh" }, { 0x0035, "zu" }, { 0x0036, "af" }, { 0x0037, "ka" }, { 0x0038, "fo" }, { 0x0039, "hi" }, { 0x003a, "mt" }, { 0x003b, "se" }, { 0x003c, "ga" }, { 0x003d, "yi" }, { 0x003e, "ms" }, { 0x003f, "kk" }, { 0x0040, "ky" }, { 0x0041, "sw" }, { 0x0042, "tk" }, { 0x0043, "uz" }, { 0x0044, "tt" }, { 0x0045, "bn" }, { 0x0046, "pa" }, { 0x0047, "gu" }, { 0x0048, "or" }, { 0x0049, "ta" }, { 0x004a, "te" }, { 0x004b, "kn" }, { 0x004c, "ml" }, { 0x004d, "as" }, { 0x004e, "mr" }, { 0x004f, "sa" }, { 0x0050, "mn" }, { 0x0051, "bo" }, { 0x0052, "cy" }, { 0x0053, "km" }, { 0x0054, "lo" }, { 0x0055, "my" }, { 0x0056, "gl" }, { 0x0057, "kok" }, { 0x0058, "mni" }, { 0x0059, "sd" }, { 0x005a, "syr" }, { 0x005b, "si" }, { 0x005c, "chr" }, { 0x005d, "iu" }, { 0x005e, "am" }, { 0x005f, "tzm" }, { 0x0060, "ks" }, { 0x0061, "ne" }, { 0x0062, "fy" }, { 0x0063, "ps" }, { 0x0064, "fil" }, { 0x0065, "dv" }, { 0x0066, "bin" }, { 0x0067, "ff" }, { 0x0068, "ha" }, { 0x0069, "ibb" }, { 0x006a, "yo" }, { 0x006b, "quz" }, { 0x006c, "nso" }, { 0x006d, "ba" }, { 0x006e, "lb" }, { 0x006f, "kl" }, { 0x0070, "ig" }, { 0x0071, "kr" }, { 0x0072, "om" }, { 0x0073, "ti" }, { 0x0074, "gn" }, { 0x0075, "haw" }, { 0x0076, "la" }, { 0x0077, "so" }, { 0x0078, "ii" }, { 0x0079, "pap" }, { 0x007a, "arn" }, { 0x007c, "moh" }, { 0x007e, "br" }, { 0x0080, "ug" }, { 0x0081, "mi" }, { 0x0082, "oc" }, { 0x0083, "co" }, { 0x0084, "gsw" }, { 0x0085, "sah" }, { 0x0086, "qut" }, { 0x0087, "rw" }, { 0x0088, "wo" }, { 0x008c, "prs" }, { 0x0091, "gd" }, { 0x0092, "ku" }, { 0x0093, "quc" }, { 0x0401, "ar\0SA" }, { 0x0402, "bg\0BG" }, { 0x0403, "ca\0ES" }, { 0x0404, "zh\0TW" }, { 0x0405, "cs\0CZ" }, { 0x0406, "da\0DK" }, { 0x0407, "de\0DE" }, { 0x0408, "el\0GR" }, { 0x0409, "en\0US" }, { 0x040a, "es\0ES_tradnl" }, { 0x040b, "fi\0FI" }, { 0x040c, "fr\0FR" }, { 0x040d, "he\0IL" }, { 0x040e, "hu\0HU" }, { 0x040f, "is\0IS" }, { 0x0410, "it\0IT" }, { 0x0411, "ja\0JP" }, { 0x0412, "ko\0KR" }, { 0x0413, "nl\0NL" }, { 0x0414, "nb\0NO" }, { 0x0415, "pl\0PL" }, { 0x0416, "pt\0BR" }, { 0x0417, "rm\0CH" }, { 0x0418, "ro\0RO" }, { 0x0419, "ru\0RU" }, { 0x041a, "hr\0HR" }, { 0x041b, "sk\0SK" }, { 0x041c, "sq\0AL" }, { 0x041d, "sv\0SE" }, { 0x041e, "th\0TH" }, { 0x041f, "tr\0TR" }, { 0x0420, "ur\0PK" }, { 0x0421, "id\0ID" }, { 0x0422, "uk\0UA" }, { 0x0423, "be\0BY" }, { 0x0424, "sl\0SI" }, { 0x0425, "et\0EE" }, { 0x0426, "lv\0LV" }, { 0x0427, "lt\0LT" }, { 0x0428, "tg\0Cyrl\0TJ" }, { 0x0429, "fa\0IR" }, { 0x042a, "vi\0VN" }, { 0x042b, "hy\0AM" }, { 0x042c, "az\0Latn\0AZ" }, { 0x042d, "eu\0ES" }, { 0x042e, "hsb\0DE" }, { 0x042f, "mk\0MK" }, { 0x0430, "st\0ZA" }, { 0x0431, "ts\0ZA" }, { 0x0432, "tn\0ZA" }, { 0x0433, "ve\0ZA" }, { 0x0434, "xh\0ZA" }, { 0x0435, "zu\0ZA" }, { 0x0436, "af\0ZA" }, { 0x0437, "ka\0GE" }, { 0x0438, "fo\0FO" }, { 0x0439, "hi\0IN" }, { 0x043a, "mt\0MT" }, { 0x043b, "se\0NO" }, { 0x043d, "yi\0Hebr" }, { 0x043e, "ms\0MY" }, { 0x043f, "kk\0KZ" }, { 0x0440, "ky\0KG" }, { 0x0441, "sw\0KE" }, { 0x0442, "tk\0TM" }, { 0x0443, "uz\0Latn\0UZ" }, { 0x0444, "tt\0RU" }, { 0x0445, "bn\0IN" }, { 0x0446, "pa\0IN" }, { 0x0447, "gu\0IN" }, { 0x0448, "or\0IN" }, { 0x0449, "ta\0IN" }, { 0x044a, "te\0IN" }, { 0x044b, "kn\0IN" }, { 0x044c, "ml\0IN" }, { 0x044d, "as\0IN" }, { 0x044e, "mr\0IN" }, { 0x044f, "sa\0IN" }, { 0x0450, "mn\0MN" }, { 0x0451, "bo\0CN" }, { 0x0452, "cy\0GB" }, { 0x0453, "km\0KH" }, { 0x0454, "lo\0LA" }, { 0x0455, "my\0MM" }, { 0x0456, "gl\0ES" }, { 0x0457, "kok\0IN" }, { 0x0458, "mni\0IN" }, { 0x0459, "sd\0Deva\0IN" }, { 0x045a, "syr\0SY" }, { 0x045b, "si\0LK" }, { 0x045c, "chr\0Cher\0US" }, { 0x045d, "iu\0Cans\0CA" }, { 0x045e, "am\0ET" }, { 0x045f, "tzm\0Arab\0MA" }, { 0x0460, "ks\0Arab" }, { 0x0461, "ne\0NP" }, { 0x0462, "fy\0NL" }, { 0x0463, "ps\0AF" }, { 0x0464, "fil\0PH" }, { 0x0465, "dv\0MV" }, { 0x0466, "bin\0NG" }, { 0x0467, "fuv\0NG" }, { 0x0468, "ha\0Latn\0NG" }, { 0x0469, "ibb\0NG" }, { 0x046a, "yo\0NG" }, { 0x046b, "quz\0BO" }, { 0x046c, "nso\0ZA" }, { 0x046d, "ba\0RU" }, { 0x046e, "lb\0LU" }, { 0x046f, "kl\0GL" }, { 0x0470, "ig\0NG" }, { 0x0471, "kr\0NG" }, { 0x0472, "om\0Ethi\0ET" }, { 0x0473, "ti\0ET" }, { 0x0474, "gn\0PY" }, { 0x0475, "haw\0US" }, { 0x0476, "la\0Latn" }, { 0x0477, "so\0SO" }, { 0x0478, "ii\0CN" }, { 0x0479, "pap\0029" }, { 0x047a, "arn\0CL" }, { 0x047c, "moh\0CA" }, { 0x047e, "br\0FR" }, { 0x0480, "ug\0CN" }, { 0x0481, "mi\0NZ" }, { 0x0482, "oc\0FR" }, { 0x0483, "co\0FR" }, { 0x0484, "gsw\0FR" }, { 0x0485, "sah\0RU" }, { 0x0486, "qut\0GT" }, { 0x0487, "rw\0RW" }, { 0x0488, "wo\0SN" }, { 0x048c, "prs\0AF" }, { 0x048d, "plt\0MG" }, { 0x048e, "zh\0yue\0HK" }, { 0x048f, "tdd\0Tale\0CN" }, { 0x0490, "khb\0Talu\0CN" }, { 0x0491, "gd\0GB" }, { 0x0492, "ku\0Arab\0IQ" }, { 0x0493, "quc\0CO" }, { 0x0501, "qps\0ploc" }, { 0x05fe, "qps\0ploca" }, { 0x0801, "ar\0IQ" }, { 0x0803, "ca\0ES\0valencia" }, { 0x0804, "zh\0CN" }, { 0x0807, "de\0CH" }, { 0x0809, "en\0GB" }, { 0x080a, "es\0MX" }, { 0x080c, "fr\0BE" }, { 0x0810, "it\0CH" }, { 0x0811, "ja\0Ploc\0JP" }, { 0x0813, "nl\0BE" }, { 0x0814, "nn\0NO" }, { 0x0816, "pt\0PT" }, { 0x0818, "ro\0MO" }, { 0x0819, "ru\0MO" }, { 0x081a, "sr\0Latn\0CS" }, { 0x081d, "sv\0FI" }, { 0x0820, "ur\0IN" }, { 0x082c, "az\0Cyrl\0AZ" }, { 0x082e, "dsb\0DE" }, { 0x0832, "tn\0BW" }, { 0x083b, "se\0SE" }, { 0x083c, "ga\0IE" }, { 0x083e, "ms\0BN" }, { 0x0843, "uz\0Cyrl\0UZ" }, { 0x0845, "bn\0BD" }, { 0x0846, "pa\0Arab\0PK" }, { 0x0849, "ta\0LK" }, { 0x0850, "mn\0Mong\0CN" }, { 0x0851, "bo\0BT" }, { 0x0859, "sd\0Arab\0PK" }, { 0x085d, "iu\0Latn\0CA" }, { 0x085f, "tzm\0Latn\0DZ" }, { 0x0860, "ks\0Deva" }, { 0x0861, "ne\0IN" }, { 0x0867, "ff\0Latn\0SN" }, { 0x086b, "quz\0EC" }, { 0x0873, "ti\0ER" }, { 0x09ff, "qps\0plocm" }, { 0x0c01, "ar\0EG" }, { 0x0c04, "zh\0HK" }, { 0x0c07, "de\0AT" }, { 0x0c09, "en\0AU" }, { 0x0c0a, "es\0ES" }, { 0x0c0c, "fr\0CA" }, { 0x0c1a, "sr\0Cyrl\0CS" }, { 0x0c3b, "se\0FI" }, { 0x0c5f, "tmz\0MA" }, { 0x0c6b, "quz\0PE" }, { 0x1001, "ar\0LY" }, { 0x1004, "zh\0SG" }, { 0x1007, "de\0LU" }, { 0x1009, "en\0CA" }, { 0x100a, "es\0GT" }, { 0x100c, "fr\0CH" }, { 0x101a, "hr\0BA" }, { 0x103b, "smj\0NO" }, { 0x1401, "ar\0DZ" }, { 0x1404, "zh\0MO" }, { 0x1407, "de\0LI" }, { 0x1409, "en\0NZ" }, { 0x140a, "es\0CR" }, { 0x140c, "fr\0LU" }, { 0x141a, "bs\0Latn\0BA" }, { 0x143b, "smj\0SE" }, { 0x1801, "ar\0MA" }, { 0x1809, "en\0IE" }, { 0x180a, "es\0PA" }, { 0x180c, "fr\0MC" }, { 0x181a, "sr\0Latn\0BA" }, { 0x183b, "sma\0NO" }, { 0x1c01, "ar\0TN" }, { 0x1c09, "en\0ZA" }, { 0x1c0a, "es\0DO" }, { 0x1c1a, "sr\0Cyrl\0BA" }, { 0x1c3b, "sma\0SE" }, { 0x2001, "ar\0OM" }, { 0x2009, "en\0JM" }, { 0x200a, "es\0VE" }, { 0x200c, "fr\0RE" }, { 0x201a, "bs\0Cyrl\0BA" }, { 0x203b, "sms\0FI" }, { 0x2401, "ar\0YE" }, { 0x2409, "en\0029" }, { 0x240a, "es\0CO" }, { 0x240c, "fr\0CG" }, { 0x241a, "sr\0Latn\0RS" }, { 0x243b, "smn\0FI" }, { 0x2801, "ar\0SY" }, { 0x2809, "en\0BZ" }, { 0x280a, "es\0PE" }, { 0x280c, "fr\0SN" }, { 0x281a, "sr\0Cyrl\0RS" }, { 0x2c01, "ar\0JO" }, { 0x2c09, "en\0TT" }, { 0x2c0a, "es\0AR" }, { 0x2c0c, "fr\0CM" }, { 0x2c1a, "sr\0Latn\0ME" }, { 0x3001, "ar\0LB" }, { 0x3009, "en\0ZW" }, { 0x300a, "es\0EC" }, { 0x300c, "fr\0CI" }, { 0x301a, "sr\0Cyrl\0ME" }, { 0x3401, "ar\0KW" }, { 0x3409, "en\0PH" }, { 0x340a, "es\0CL" }, { 0x340c, "fr\0ML" }, { 0x3801, "ar\0AE" }, { 0x3809, "en\0ID" }, { 0x380a, "es\0UY" }, { 0x380c, "fr\0MA" }, { 0x3c01, "ar\0BH" }, { 0x3c09, "en\0HK" }, { 0x3c0a, "es\0PY" }, { 0x3c0c, "fr\0HT" }, { 0x4001, "ar\0QA" }, { 0x4009, "en\0IN" }, { 0x400a, "es\0BO" }, { 0x4401, "ar\0Ploc\0SA" }, { 0x4409, "en\0MY" }, { 0x440a, "es\0SV" }, { 0x4801, "ar\0145" }, { 0x4809, "en\0SG" }, { 0x480a, "es\0HN" }, { 0x4c09, "en\0AE" }, { 0x4c0a, "es\0NI" }, { 0x5009, "en\0BH" }, { 0x500a, "es\0PR" }, { 0x5409, "en\0EG" }, { 0x540a, "es\0US" }, { 0x5809, "en\0JO" }, { 0x5c09, "en\0KW" }, { 0x6009, "en\0TR" }, { 0x6409, "en\0YE" }, { 0x641a, "bs\0Cyrl" }, { 0x681a, "bs\0Latn" }, { 0x6c1a, "sr\0Cyrl" }, { 0x701a, "sr\0Latn" }, { 0x703b, "smn" }, { 0x742c, "az\0Cyrl" }, { 0x743b, "sms" }, { 0x7804, "zh" }, { 0x7814, "nn" }, { 0x781a, "bs" }, { 0x782c, "az\0Latn" }, { 0x783b, "sma" }, { 0x7843, "uz\0Cyrl" }, { 0x7850, "mn\0Cyrl" }, { 0x785d, "iu\0Cans" }, { 0x7c04, "zh\0Hant" }, { 0x7c14, "nb" }, { 0x7c1a, "sr" }, { 0x7c28, "tg\0Cyrl" }, { 0x7c2e, "dsb" }, { 0x7c3b, "smj" }, { 0x7c43, "uz\0Latn" }, { 0x7c46, "pa\0Arab" }, { 0x7c50, "mn\0Mong" }, { 0x7c59, "sd\0Arab" }, { 0x7c5c, "chr\0Cher" }, { 0x7c5d, "iu\0Latn" }, { 0x7c5f, "tzm\0Latn" }, { 0x7c67, "ff\0Latn" }, { 0x7c68, "ha\0Latn" }, { 0x7c92, "ku\0Arab" } }; const uint16 current_id = (0x000000FFFFul & GetThreadLocale()); for( size_t i=0; i #include const char *dr_get_locale_string() { static char code[4]; BMessage result; const char *str; code[0] = 0; if( B_OK == BLocaleRoster::Default()->GetPreferredLanguages( &result ) ) { result.FindString( (const char *)"language", &str ); for( int i=0; i const char *dr_get_locale_string() { static char code[4]; char *ptr; setlocale( LC_ALL, "" ); ptr = setlocale( LC_ALL, NULL ); code[0] = 0; for( int i=0; i<(int)lengthof(code)-1 && isalpha(ptr[i]); i++ ) { code[i] = tolower(ptr[i]); code[i+1] = 0; } setlocale( LC_ALL, "C" ); // or the number output may be broken return code[0] ? code : NULL; } #endif void dr_fatal_notify(char const* const msg) { fprintf(stderr, "dr_fatal_notify: ERROR: %s\n", msg); #ifdef _WIN32 MessageBoxA(0, msg, "Fatal Error", MB_ICONEXCLAMATION); #endif #ifdef __ANDROID__ dbg->error(__FUNCTION__, msg); #endif } /* * Open a program/starts a script to download pak sets from sourceforge * * @param data_dir : actual simutrans pakfile directory * @param portable * @return false, if nothing was downloaded */ bool dr_download_pakset( const char *data_dir, bool portable ) { #ifdef _WIN32 int old_fullscreen = dr_suspend_fullscreen(); U16View const wpath_to_program(data_dir); WCHAR wparam[1024]; swprintf(wparam, portable ? L"/P /D=%ls" : L"/D=%ls", wpath_to_program); SHELLEXECUTEINFOW shExInfo; shExInfo.cbSize = sizeof(shExInfo); shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExInfo.hwnd = 0; /* since the installer will run again a child process * using "runas" will make sure it is already privileged. * Otherwise the waiting for installation will fail! * (no idea how this works on XP though) */ // shExInfo.lpVerb = L"runas"; we do not need afmin rights any more shExInfo.lpVerb = L"open"; shExInfo.lpFile = L"download-paksets.exe"; shExInfo.lpParameters = wparam; shExInfo.lpDirectory = wpath_to_program; shExInfo.nShow = SW_SHOW; shExInfo.hInstApp = 0; if( ShellExecuteExW(&shExInfo) ) { WaitForSingleObject( shExInfo.hProcess, INFINITE ); CloseHandle( shExInfo.hProcess ); } dr_restore_fullscreen(old_fullscreen); return true; #else (void)portable; char command[2048]; dr_chdir( data_dir ); sprintf(command, "%s/get_pak.sh", data_dir); const int retval = system( command ); dbg->debug("dr_download_pakset", "Command '%s' returned %d", command, retval); return true; #endif } const char* get_version() { return "Version " VERSION_NUMBER " " VERSION_DATE #ifdef REVISION " r" QUOTEME(REVISION) #endif #ifdef GIT_HASH " hash " QUOTEME(GIT_HASH) #endif L_DEBUG_TEXT; } /** * Copy argv because some systems (e.g. Android) do not allow to write them */ char **copy_argv(int argc, char *argv[]) { char** new_argv = new char*[argc+1]; for(int i=0; i < argc; i++) { int len = strlen(argv[i]) + 1; new_argv[i] = new char[len]; strcpy(new_argv[i], argv[i]); } new_argv[argc] = NULL; return new_argv; } int sysmain(int const argc, char** const argv) { char ** argv_copy = copy_argv(argc,argv); sys_event.type = SIM_NOEVENT; sys_event.code = 0; #ifdef _WIN32 // Guess required buffer length, if too small then dynamically expand up to around 65536 characters. // It is unlikely this loop will ever run more than once in practice but is required to cover flaws with the API. size_t buffersize = MAX_PATH; WCHAR *wpathname; while(true) { wpathname = new WCHAR[buffersize]; DWORD result = GetModuleFileNameW(GetModuleHandleW(0), wpathname, buffersize); if(result < buffersize || buffersize >= 1 << 16) { break; } delete[] wpathname; buffersize<<= 1; } // Convert UTF-16 to UTF-8 int const pathnamesize = WideCharToMultiByte(CP_UTF8, 0, wpathname, -1, NULL, 0, NULL, NULL); char *const pathname = new char[pathnamesize]; WideCharToMultiByte(CP_UTF8, 0, wpathname, -1, pathname, pathnamesize, NULL, NULL); delete[] wpathname; argv_copy[0] = pathname; #elif !defined __BEOS__ # if defined __GLIBC__ && !defined __AMIGA__ /* glibc has a non-standard extension */ char* buffer2 = 0; # else char buffer2[PATH_MAX]; # endif # ifndef __AMIGA__ char buffer[PATH_MAX]; ssize_t const length = readlink("/proc/self/exe", buffer, lengthof(buffer) - 1); if (length != -1) { buffer[length] = '\0'; /* readlink() does not NUL-terminate */ argv_copy[0] = buffer; } else if (strchr(argv_copy[0], '/') == NULL) { // no /proc, no '/' in argv[0] => search PATH const char* path = getenv("PATH"); if (path != NULL) { size_t flen = strlen(argv_copy[0]); for (;;) { /* for each directory in PATH */ size_t dlen = strcspn(path, ":"); if (dlen > 0 && dlen + flen + 2 < lengthof(buffer)) { // buffer = dir '/' argv[0] '\0' memcpy(buffer, path, dlen); buffer[dlen] = '/'; memcpy(buffer + dlen + 1, argv_copy[0], flen + 1); if (access(buffer, X_OK) == 0) { argv_copy[0] = buffer; break; /* found it! */ } } if (path[dlen] == '\0') break; path += dlen + 1; /* skip ':' */ } } } # endif // no process file system => need to parse argv[0] /* should work on most unix or gnu systems */ argv_copy[0] = realpath(argv_copy[0], buffer2); #endif setlocale( LC_CTYPE, "" ); setlocale( LC_NUMERIC, "en_US.UTF-8" ); return simu_main(argc, argv_copy); #ifdef _WIN32 // Cleanup for dynamic allocation, probably unnescescary. delete[] pathname; #endif } simutrans-124.3/src/simutrans/sys/simsys.h000066400000000000000000000164731474050137200207200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef SYS_SIMSYS_H #define SYS_SIMSYS_H #include "../simtypes.h" #include "../display/scr_coord.h" #include "../simcolor.h" #ifndef NETTOOL #include #endif #include // Provide chdir(). #if defined(_WIN32) && !defined(__CYGWIN__) # include #else # include #endif enum sim_event_type_t : uint32 { SIM_NOEVENT = 0, SIM_MOUSE_BUTTONS = 1, SIM_KEYBOARD = 2, SIM_MOUSE_MOVE = 3, SIM_STRING = 4, SIM_SYSTEM = 254, SIM_IGNORE_EVENT = 255 }; /// Mouse actions enum sim_mouse_action_t : unsigned long { SIM_MOUSE_LEFTUP = 1, SIM_MOUSE_RIGHTUP = 2, SIM_MOUSE_MIDUP = 3, SIM_MOUSE_LEFTBUTTON = 4, SIM_MOUSE_RIGHTBUTTON = 5, SIM_MOUSE_MIDBUTTON = 6, SIM_MOUSE_MOVED = 7, SIM_MOUSE_WHEELUP = 8, SIM_MOUSE_WHEELDOWN = 9 }; struct sys_event_t { sim_event_type_t type; union { unsigned long code; void *ptr; }; // mouse position; negative coords are possible scr_coord_val mx; scr_coord_val my; uint16 mb; // Combination of MOUSE_* flags from simevent.h /// new window size for SYSTEM_RESIZE uint16 new_window_size_w; uint16 new_window_size_h; /// pressed modifiers, combination of SIM_MOD_* flags from simevent.h unsigned int key_mod; }; enum { WINDOWED, FULLSCREEN, BORDERLESS }; /// Global Variable for message processing extern sys_event_t sys_event; extern char const PATH_SEPARATOR[]; /// @param scale_percent /// Possible values: /// -1: auto (scale according to screen DPI setting) /// 0: off (default 1:1 scale) /// other: specific scaling, in percent /// < -1: invalid bool dr_set_screen_scale(sint16 scale_percent); /// @returns Relative size of the virtual display, in percent sint16 dr_get_screen_scale(); bool dr_os_init(int const* parameter); /* maximum size possible (if there) */ struct resolution { scr_coord_val w; scr_coord_val h; }; resolution dr_query_screen_resolution(); int dr_os_open(scr_size window_size, sint16 fullscreen); void dr_os_close(); // returns the locale; NULL if unknown const char *dr_get_locale_string(); // Functions the same as normal mkdir except path must be UTF-8 encoded and a default mode of 0777 is assumed. int dr_mkdir(char const* path); /** * Moves the specified file to the system's trash bin. * If trash is not available on the platform, removes file. * @param path UTF-8 path to the file to delete. * @return False on success. */ bool dr_movetotrash(const char *path); /** * Returns true if platform supports recycle bin, otherwise false. * Used to control which UI tooltip is shown for deletion. */ bool dr_cantrash(); // Functions the same as cstdio remove except path must be UTF-8 encoded. int dr_remove(const char *path); // rename a file and delete eventually existing file new_utf8 int dr_rename( const char *existing_utf8, const char *new_utf8 ); // Functions the same as chdir except path must be UTF-8 encoded. int dr_chdir(const char *path); // Functions the same as getcwd except path must be UTF-8 encoded. char *dr_getcwd(char *buf, size_t size); // Functions the same as fopen except filename must be UTF-8 encoded. FILE *dr_fopen(const char *filename, const char *mode); #ifndef NETTOOL // Functions the same as gzopen except path must be UTF-8 encoded. gzFile dr_gzopen(const char *path, const char *mode); #endif // Functions the same as stat except path must be UTF-8 encoded. int dr_stat(const char *path, struct stat *buf); /** * Check if the directory exists and if so set the result variable to it * If the directory doesn't exist previously, it will attempt to create it if testfile is not provided * @param path : Path to directory to check * @param info : String to provide extra log info * @param result : Variable to store the path to directory if it exists * @param testfile : Optional file to check for existence */ bool check_and_set_dir(const char *path, const char *info, char *result, const char *testfile=NULL); /** * Sets the base_dir * @param base_dir_arg : command line argument "-set_basedir" * @param executable_path : Path to executable (as stored in argv[0]) */ bool dr_set_basedir(const char *base_dir_arg, char *executable_path); /* query home directory */ char const* dr_query_homedir(); /* query install directory (all user writable) */ char const* dr_query_installdir(); unsigned short* dr_textur_init(); // returns the file path to a font file (or more than one, if used with number higher than zero) const char *dr_query_fontpath( int ); // return a default TTF (windows/android) or a BDF for now std::string dr_get_system_font(); void dr_textur(int xp, int yp, int w, int h); /* returns the actual width (might be larger than requested! */ int dr_textur_resize(unsigned short** textur, int w, int h); // needed for screen update void dr_prepare_flush(); // waits, if previous update not yet finished void dr_flush(); // copy to screen (eventually multithreaded) /** * Transform a 24 bit RGB color into the system format. * @return converted color value */ PIXVAL get_system_color(rgb888_t rgb); void show_pointer(int yesno); void set_pointer(int loading); bool move_pointer(int x, int y); scr_coord get_mouse_pos(); void ex_ord_update_mx_my(); void GetEvents(); uint8 dr_get_max_threads(); uint32 dr_time(); void dr_sleep(uint32 millisec); // error message in case of fatal events void dr_fatal_notify(char const* msg); /** * Copy text to the clipboard * @param source : pointer to the start of the source text * @param length : number of character bytes to copy */ void dr_copy(const char *source, size_t length); /** * Paste text from the clipboard * @param target : pointer to the insertion position in the target text * @param max_length : maximum number of character bytes which could be inserted * @return number of character bytes actually inserted -> for cursor advancing */ size_t dr_paste(char *target, size_t max_length); /** * Open a program/starts a script to download pak sets. * @param data_dir : The current simutrans data directory (usually the same as env_t::base_dir) * @param portable : true if local files to be save in simutransdir * @return false, if nothing was downloaded */ bool dr_download_pakset( const char *data_dir, bool portable ); /** * Shows the touch keyboard when using systems without a hardware keyboard. * Will be ignored if there is an hardware keyboard available. */ void dr_start_textinput(); /** * Hides the touch keyboard when using systems without a hardware keyboard. * Will be ignored it there is no on-display keyboard shown. */ void dr_stop_textinput(); /** * Inform the IME of a ideal place to open its popup. */ void dr_notify_input_pos(scr_coord pos); /// returns current two byte languange ID const char* dr_get_locale(); /// true, if there is a hardware fullcreen mode bool dr_has_fullscreen(); /** * @return * 0: if windowed * 1: if fullscreen * 2: if borderless fullscreen */ sint16 dr_get_fullscreen(); /** * Toggle between borderless and windowed mode * @return the fullscreen state after the toggle */ sint16 dr_toggle_borderless(); /* temparily minimizes window and restore it */ sint16 dr_suspend_fullscreen(); void dr_restore_fullscreen(sint16 old_fullscreen); const char* get_version(); int sysmain(int argc, char** argv); #endif simutrans-124.3/src/simutrans/sys/simsys_posix.cc000066400000000000000000000053701474050137200222720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifdef _WIN32 #include #endif #ifndef _MSC_VER #include #include #else // need timeGetTime #include #endif #include #include "simsys.h" #include "../macros.h" #include "../simdebug.h" #include "../simevent.h" static bool sigterm_received = false; #if COLOUR_DEPTH != 0 #error "Posix only compiles with color depth=0" #endif bool dr_set_screen_scale(sint16) { // no autoscaling as we have no display ... return false; } sint16 dr_get_screen_scale() { return 100; } bool dr_os_init(const int*) { // prepare for next event sys_event.type = SIM_NOEVENT; sys_event.code = 0; return true; } resolution dr_query_screen_resolution() { resolution const res = { 0, 0 }; return res; } // open the window int dr_os_open(int, int, sint16) { return 1; } void dr_os_close() { } // resizes screen int dr_textur_resize(unsigned short** const textur, int, int) { *textur = NULL; return 1; } unsigned short *dr_textur_init() { return NULL; } PIXVAL get_system_color(rgb888_t) { return 1; } void dr_prepare_flush() { } void dr_flush() { } void dr_textur(int, int, int, int) { } bool move_pointer(int, int) { return false; } void set_pointer(int) { } void GetEvents() { if( sigterm_received ) { sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_QUIT; } } void show_pointer(int) { } void ex_ord_update_mx_my() { } #ifndef _MSC_VER static timeval first; #endif uint32 dr_time() { #ifndef _MSC_VER timeval second; gettimeofday(&second,NULL); if (first.tv_usec > second.tv_usec) { // since those are often unsigned second.tv_usec += 1000000; second.tv_sec--; } return (second.tv_sec - first.tv_sec)*1000ul + (second.tv_usec - first.tv_usec)/1000ul; #else return timeGetTime(); #endif } void dr_sleep(uint32 msec) { /* // this would be 100% POSIX but is usually not very accurate ... if( msec>0 ) { struct timeval tv; tv.sec = 0; tv.usec = msec*1000; select(0, 0, 0, 0, &tv); } */ #ifdef _WIN32 Sleep( msec ); #else usleep( 1000u * msec ); #endif } void dr_start_textinput() { } void dr_stop_textinput() { } void dr_notify_input_pos(scr_coord pos) { } static void posix_sigterm(int) { DBG_MESSAGE("Received SIGTERM", "exiting..."); sigterm_received = 1; } const char* dr_get_locale() { return ""; } bool dr_has_fullscreen() { return false; } sint16 dr_get_fullscreen() { return 0; } sint16 dr_toggle_borderless() { return 0; } sint16 dr_suspend_fullscreen() { return 0; } void dr_restore_fullscreen(sint16) {} int main(int argc, char **argv) { signal( SIGTERM, posix_sigterm ); #ifndef _MSC_VER gettimeofday(&first,NULL); #endif return sysmain(argc, argv); } simutrans-124.3/src/simutrans/sys/simsys_s2.cc000066400000000000000000001103731474050137200214540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #if !defined __APPLE__ && !defined __ANDROID__ #include #else #include #endif #ifdef _WIN32 #include #endif #include #include #ifdef __CYGWIN__ extern int __argc; extern char **__argv; #endif #include "simsys.h" #include "../macros.h" #include "../simversion.h" #include "../simevent.h" #include "../display/simgraph.h" #include "../simdebug.h" #include "../dataobj/environment.h" #include "../gui/simwin.h" #include "../gui/components/gui_component.h" #include "../gui/components/gui_textinput.h" #include "../simintr.h" #include "../world/simworld.h" #include "../music/music.h" #include "../utils/unicode.h" // Maybe Linux is not fine too, had critical bugs... #if !defined(__linux__) #define USE_SDL_TEXTEDITING #else #endif // threshold for zooming in/out with multitouch #define DELTA_PINCH (0.033) static Uint8 hourglass_cursor[] = { 0x3F, 0xFE, // ************* 0x30, 0x06, // ** ** 0x3F, 0xFE, // ************* 0x10, 0x04, // * * 0x10, 0x04, // * * 0x12, 0xA4, // * * * * * 0x11, 0x44, // * * * * * 0x18, 0x8C, // ** * ** 0x0C, 0x18, // ** ** 0x06, 0xB0, // ** * ** 0x03, 0x60, // ** ** 0x03, 0x60, // **H** 0x06, 0x30, // ** * ** 0x0C, 0x98, // ** ** 0x18, 0x0C, // ** * ** 0x10, 0x84, // * * * 0x11, 0x44, // * * * * 0x12, 0xA4, // * * * * * 0x15, 0x54, // * * * * * * 0x3F, 0xFE, // ************* 0x30, 0x06, // ** ** 0x3F, 0xFE // ************* }; static Uint8 hourglass_cursor_mask[] = { 0x3F, 0xFE, // ************* 0x3F, 0xFE, // ************* 0x3F, 0xFE, // ************* 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x0F, 0xF8, // ********* 0x07, 0xF0, // ******* 0x03, 0xE0, // ***** 0x03, 0xE0, // **H** 0x07, 0xF0, // ******* 0x0F, 0xF8, // ********* 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x1F, 0xFC, // *********** 0x3F, 0xFE, // ************* 0x3F, 0xFE, // ************* 0x3F, 0xFE // ************* }; static Uint8 blank_cursor[] = { 0x0, 0x0, }; static SDL_Window *window; static SDL_Renderer *renderer; static SDL_Texture *screen_tx; static SDL_Surface *screen; static int sync_blit = 0; static int use_dirty_tiles = 1; static sint16 fullscreen = WINDOWED; static SDL_Cursor *arrow; static SDL_Cursor *hourglass; static SDL_Cursor *blank; // Number of fractional bits for screen scaling #define SCALE_SHIFT_X 5 #define SCALE_SHIFT_Y 5 #define SCALE_NEUTRAL_X (1 << SCALE_SHIFT_X) #define SCALE_NEUTRAL_Y (1 << SCALE_SHIFT_Y) // Multiplier when converting from texture to screen coords, fixed point format // Example: If x_scale==2*SCALE_NEUTRAL_X && y_scale==2*SCALE_NEUTRAL_Y, // then things on screen are 2*2 = 4 times as big by area sint32 x_scale = SCALE_NEUTRAL_X; sint32 y_scale = SCALE_NEUTRAL_Y; // When using -autodpi, attempt to scale things on screen to this DPI value #ifdef __ANDROID__ #define TARGET_DPI (192) #else #define TARGET_DPI (96) #endif // make sure we have at least so much pixel in y-direction #define MIN_SCALE_HEIGHT (640) // Most Android devices are underpowered to handle larger screens #define MAX_AUTOSCALE_WIDTH (1280) // screen -> texture coords #define SCREEN_TO_TEX_X(x) (((x) * SCALE_NEUTRAL_X) / x_scale) #define SCREEN_TO_TEX_Y(y) (((y) * SCALE_NEUTRAL_Y) / y_scale) // texture -> screen coords #define TEX_TO_SCREEN_X(x) (((x) * x_scale) / SCALE_NEUTRAL_X) #define TEX_TO_SCREEN_Y(y) (((y) * y_scale) / SCALE_NEUTRAL_Y) bool has_soft_keyboard = false; bool dr_set_screen_scale(sint16 scale_percent) { const sint32 old_x_scale = x_scale; const sint32 old_y_scale = y_scale; if (scale_percent == -1) { float hdpi, vdpi; SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(0, &mode); DBG_MESSAGE("dr_auto_scale", "screen resolution width=%d, height=%d", mode.w, mode.h); #if SDL_VERSION_ATLEAST(2,0,4) // auto scale only for high enough screens if (mode.h > 1.5 * MIN_SCALE_HEIGHT && SDL_GetDisplayDPI(0, NULL, &hdpi, &vdpi) == 0) { x_scale = ((sint64)hdpi * SCALE_NEUTRAL_X + 1) / TARGET_DPI; y_scale = ((sint64)vdpi * SCALE_NEUTRAL_Y + 1) / TARGET_DPI; DBG_MESSAGE("auto_dpi_scaling", "x=%i, y=%i", x_scale, y_scale); } #ifdef __ANDROID__ // most Android are underpowered to run more than 1280 pixel horizontal sint32 current_x = SCREEN_TO_TEX_X(mode.w); if (current_x > MAX_AUTOSCALE_WIDTH) { sint32 new_x_scale = ((sint64)mode.w * SCALE_NEUTRAL_X + 1) / MAX_AUTOSCALE_WIDTH; y_scale = (y_scale * new_x_scale) / x_scale; x_scale = new_x_scale; DBG_MESSAGE("new scaling (max 1280)", "x=%i, y=%i", x_scale, y_scale); } #endif // ensure minimum height sint32 current_y = SCREEN_TO_TEX_Y(mode.h); if (current_y < MIN_SCALE_HEIGHT) { DBG_MESSAGE("dr_auto_scale", "virtual height=%d < %d", current_y, MIN_SCALE_HEIGHT); x_scale = (x_scale * current_y) / MIN_SCALE_HEIGHT; y_scale = (y_scale * current_y) / MIN_SCALE_HEIGHT; DBG_MESSAGE("new scaling (min 640)", "x=%i, y=%i", x_scale, y_scale); } #else #pragma message "SDL version must be at least 2.0.4 to support autoscaling." // 1.5 scale up by default x_scale = (150*SCALE_NEUTRAL_X)/100; y_scale = (150*SCALE_NEUTRAL_Y)/100; #endif } else if (scale_percent == 0) { x_scale = SCALE_NEUTRAL_X; y_scale = SCALE_NEUTRAL_Y; } else { x_scale = (scale_percent*SCALE_NEUTRAL_X)/100; y_scale = (scale_percent*SCALE_NEUTRAL_Y)/100; } if (window && (x_scale != old_x_scale || y_scale != old_y_scale) ) { // force window resize int w, h; SDL_GetWindowSize(window, &w, &h); SDL_Event ev; ev.type = SDL_WINDOWEVENT; ev.window.event = SDL_WINDOWEVENT_SIZE_CHANGED; ev.window.data1 = w; ev.window.data2 = h; if (SDL_PushEvent(&ev) != 1) { return false; } } return true; } sint16 dr_get_screen_scale() { return (x_scale*100)/SCALE_NEUTRAL_X; } static int SDLCALL my_event_filter(void* /*userdata*/, SDL_Event* event) { DBG_DEBUG4("my_event_filter", "%i", event->type); switch (event->type) { case SDL_APP_DIDENTERBACKGROUND: intr_disable(); // save settings { dr_chdir(env_t::user_dir); loadsave_t settings_file; if (settings_file.wr_open("settings.xml", loadsave_t::xml, 0, "settings only/", SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK) { env_t::rdwr(&settings_file); env_t::default_settings.rdwr(&settings_file); settings_file.close(); } } dr_stop_midi(); return 0; case SDL_APP_TERMINATING: // quitting immediate, save settings and game without visual feedback intr_disable(); DBG_DEBUG("SDL_APP_TERMINATING", "env_t::reload_and_save_on_quit=%d", env_t::reload_and_save_on_quit); world()->stop(true); // save settings { dr_chdir(env_t::user_dir); loadsave_t settings_file; if (settings_file.wr_open("settings.xml", loadsave_t::xml, 0, "settings only/", SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK) { env_t::rdwr(&settings_file); env_t::default_settings.rdwr(&settings_file); settings_file.close(); } } // at this point there is no UI active anymore, and we have no time to die, so just exit and leeve the cleanup to the OS dr_stop_midi(); SDL_Quit(); dr_os_close(); exit(0); // we never reach here tough ... return 0; } return 1; // let all events be added to the queue since we always return 1. } /* * Hier sind die Basisfunktionen zur Initialisierung der * Schnittstelle untergebracht * -> init,open,close */ bool dr_os_init(const int* parameter) { if( SDL_Init( SDL_INIT_VIDEO ) != 0 ) { dbg->error("dr_os_init(SDL2)", "Could not initialize SDL: %s", SDL_GetError() ); return false; } SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); dbg->message("dr_os_init(SDL2)", "SDL Driver: %s", SDL_GetCurrentVideoDriver() ); // disable event types not interested in #ifndef USE_SDL_TEXTEDITING SDL_EventState( SDL_TEXTEDITING, SDL_DISABLE ); #endif SDL_EventState( SDL_FINGERDOWN, SDL_ENABLE ); SDL_EventState( SDL_FINGERUP, SDL_ENABLE ); SDL_EventState( SDL_FINGERMOTION, SDL_ENABLE ); SDL_EventState( SDL_DOLLARGESTURE, SDL_DISABLE ); SDL_EventState( SDL_DOLLARRECORD, SDL_DISABLE ); SDL_EventState( SDL_MULTIGESTURE, SDL_ENABLE ); SDL_EventState( SDL_CLIPBOARDUPDATE, SDL_DISABLE ); SDL_EventState( SDL_DROPFILE, SDL_DISABLE ); // termination event: save current map and settings SDL_SetEventFilter(my_event_filter, 0); has_soft_keyboard = SDL_HasScreenKeyboardSupport(); if (has_soft_keyboard && !env_t::hide_keyboard) { env_t::hide_keyboard = true; } if (!env_t::hide_keyboard) { SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); } sync_blit = parameter[0]; // hijack SDL1 -async flag for SDL2 vsync use_dirty_tiles = !parameter[1]; // hijack SDL1 -use_hw flag to turn off dirty tile updates (force fullscreen updates) // prepare for next event sys_event.type = SIM_NOEVENT; sys_event.code = 0; if (!env_t::hide_keyboard) { SDL_StartTextInput(); DBG_MESSAGE("SDL_StartTextInput", ""); } atexit( SDL_Quit ); // clean up on exit return true; } resolution dr_query_screen_resolution() { resolution res; SDL_DisplayMode mode; SDL_GetCurrentDisplayMode( 0, &mode ); DBG_MESSAGE("dr_query_screen_resolution(SDL2)", "screen resolution width=%d, height=%d", mode.w, mode.h ); res.w = SCREEN_TO_TEX_X(mode.w); res.h = SCREEN_TO_TEX_Y(mode.h); return res; } bool internal_create_surfaces(int tex_width, int tex_height) { // The pixel format needs to match the graphics code within simgraph16.cc. // Note that alpha is handled by simgraph16, not by SDL. const Uint32 pixel_format = SDL_PIXELFORMAT_RGB565; #ifdef MSG_LEVEL // List all render drivers and their supported pixel formats. const int num_rend = SDL_GetNumRenderDrivers(); std::string formatStrBuilder; for( int i = 0; i < num_rend; i++ ) { SDL_RendererInfo ri; SDL_GetRenderDriverInfo( i, &ri ); formatStrBuilder.clear(); for( Uint32 j = 0; j < ri.num_texture_formats; j++ ) { formatStrBuilder += ", "; formatStrBuilder += SDL_GetPixelFormatName(ri.texture_formats[j]); } DBG_DEBUG( "internal_create_surfaces(SDL2)", "Renderer: %s, Max_w: %d, Max_h: %d, Flags: %d, Formats: %d%s", ri.name, ri.max_texture_width, ri.max_texture_height, ri.flags, ri.num_texture_formats, formatStrBuilder.c_str() ); } #endif Uint32 flags = SDL_RENDERER_ACCELERATED; if( sync_blit ) { flags |= SDL_RENDERER_PRESENTVSYNC; } renderer = SDL_CreateRenderer( window, -1, flags ); if( renderer == NULL ) { dbg->warning( "internal_create_surfaces(SDL2)", "Couldn't create accelerated renderer: %s", SDL_GetError() ); flags &= ~SDL_RENDERER_ACCELERATED; flags |= SDL_RENDERER_SOFTWARE; renderer = SDL_CreateRenderer( window, -1, flags ); if( renderer == NULL ) { dbg->error( "internal_create_surfaces(SDL2)", "No suitable SDL2 renderer found!" ); return false; } dbg->warning( "internal_create_surfaces(SDL2)", "Using fallback software renderer instead of accelerated: Performance may be low!"); } SDL_RendererInfo ri; SDL_GetRendererInfo( renderer, &ri ); DBG_DEBUG( "internal_create_surfaces(SDL2)", "Using: Renderer: %s, Max_w: %d, Max_h: %d, Flags: %d, Formats: %d, %s", ri.name, ri.max_texture_width, ri.max_texture_height, ri.flags, ri.num_texture_formats, SDL_GetPixelFormatName(pixel_format) ); // Non-integer scaling -> enable bilinear filtering (must be done before texture creation) const bool integer_scaling = (x_scale & (SCALE_NEUTRAL_X - 1)) == 0 && (y_scale & (SCALE_NEUTRAL_Y - 1)) == 0; SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, integer_scaling ? "0" : "1" ); // 0=none, 1=bilinear, 2=anisotropic (DirectX only) screen_tx = SDL_CreateTexture( renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, tex_width, tex_height ); if( screen_tx == NULL ) { dbg->error( "internal_create_surfaces(SDL2)", "Couldn't create texture: %s", SDL_GetError() ); return false; } // Color component bitmasks for the RGB565 pixel format used by simgraph16.cc int bpp; Uint32 rmask, gmask, bmask, amask; if( !SDL_PixelFormatEnumToMasks( pixel_format, &bpp, &rmask, &gmask, &bmask, &amask ) ) { dbg->error( "internal_create_surfaces(SDL2)", "Pixel format error. Couldn't generate masks: %s", SDL_GetError() ); return false; } else if( bpp != COLOUR_DEPTH || amask != 0 ) { dbg->error( "internal_create_surfaces(SDL2)", "Pixel format error. Bpp got %d, needed %d. Amask got %d, needed 0.", bpp, COLOUR_DEPTH, amask ); return false; } screen = SDL_CreateRGBSurface( 0, tex_width, tex_height, bpp, rmask, gmask, bmask, amask ); if( screen == NULL ) { dbg->error( "internal_create_surfaces(SDL2)", "Couldn't get the window surface: %s", SDL_GetError() ); return false; } return true; } // open the window int dr_os_open(const scr_size window_size, sint16 fs) { // scale up resolution res = dr_query_screen_resolution(); const int tex_w = clamp( res.w, 1, SCREEN_TO_TEX_X(window_size.w) ); const int tex_h = clamp( res.h, 1, SCREEN_TO_TEX_Y(window_size.h) ); DBG_MESSAGE("dr_os_open()", "Screen requested %i,%i, available max %i,%i", tex_w, tex_h, res.w, res.h); fullscreen = fs ? BORDERLESS : WINDOWED; // SDL2 has no real fullscreen mode // some cards need those alignments // especially 64bit want a border of 8bytes const int tex_pitch = (tex_w + 15) & 0x7FF0; // SDL2 only works with borderless fullscreen (SDL_WINDOW_FULLSCREEN_DESKTOP) Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_RESIZABLE; flags |= SDL_WINDOW_ALLOW_HIGHDPI; // apparently needed for Apple retina displays #ifdef __ANDROID__ // needed for landscape apparently flags |= SDL_WINDOW_RESIZABLE; #endif window = SDL_CreateWindow( SIM_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_size.w, window_size.h, flags ); if( window == NULL ) { dbg->error("dr_os_open(SDL2)", "Could not open the window: %s", SDL_GetError() ); return 0; } if( !internal_create_surfaces( tex_pitch, tex_h ) ) { return 0; } DBG_MESSAGE("dr_os_open(SDL2)", "SDL realized screen size width=%d, height=%d (internal w=%d, h=%d)", window_size.w, window_size.h, screen->w, screen->h ); SDL_ShowCursor(0); arrow = SDL_GetCursor(); hourglass = SDL_CreateCursor( hourglass_cursor, hourglass_cursor_mask, 16, 22, 8, 11 ); blank = SDL_CreateCursor( blank_cursor, blank_cursor, 8, 2, 0, 0 ); SDL_ShowCursor(1); #if SDL_VERSION_ATLEAST(2, 0, 10) SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); // no mouse emulation for touch #endif assert(tex_pitch <= screen->pitch / (int)sizeof(PIXVAL)); assert(tex_h <= screen->h); assert(tex_w <= tex_pitch); display_set_actual_width( tex_w ); display_set_height( tex_h ); return tex_pitch; } // shut down SDL void dr_os_close() { SDL_FreeCursor( blank ); SDL_FreeCursor( hourglass ); SDL_DestroyRenderer( renderer ); SDL_DestroyWindow( window ); SDL_StopTextInput(); } // resizes screen int dr_textur_resize(unsigned short** const textur, int tex_w, int const tex_h) { // enforce multiple of 16 pixels, or there are likely mismatches const int tex_pitch = max((tex_w + 15) & 0x7FF0, 16); SDL_UnlockTexture( screen_tx ); if( tex_pitch != screen->w || tex_h != screen->h ) { // Recreate the SDL surfaces at the new resolution. // First free surface and then renderer. SDL_FreeSurface( screen ); screen = NULL; // This destroys texture as well. SDL_DestroyRenderer( renderer ); renderer = NULL; screen_tx = NULL; internal_create_surfaces( tex_pitch, tex_h ); if( screen ) { DBG_MESSAGE("dr_textur_resize(SDL2)", "SDL realized screen size width=%d, height=%d (internal w=%d, h=%d)", tex_w, tex_h, screen->w, screen->h ); } else { dbg->error("dr_textur_resize(SDL2)", "screen is NULL. Good luck!"); } fflush( NULL ); } *textur = dr_textur_init(); assert(tex_pitch <= screen->pitch / (int)sizeof(PIXVAL)); assert(tex_h <= screen->h); assert(tex_w <= tex_pitch); display_set_actual_width( tex_w ); return tex_pitch; } unsigned short *dr_textur_init() { // SDL_LockTexture modifies pixels, so copy it first void *pixels = screen->pixels; int pitch = screen->pitch; SDL_LockTexture( screen_tx, NULL, &pixels, &pitch ); return (unsigned short*)screen->pixels; } /** * Transform a 24 bit RGB color into the system format. * @return converted color value */ PIXVAL get_system_color(rgb888_t col) { SDL_PixelFormat *fmt = SDL_AllocFormat( SDL_PIXELFORMAT_RGB565 ); unsigned int ret = SDL_MapRGB(fmt, col.r, col.g, col.b); SDL_FreeFormat( fmt ); assert((ret & 0xFFFF0000u) == 0); return ret; } void dr_prepare_flush() { return; } void dr_flush() { display_flush_buffer(); if( !use_dirty_tiles ) { SDL_UpdateTexture( screen_tx, NULL, screen->pixels, screen->pitch ); } SDL_Rect rSrc = { 0, 0, display_get_width(), display_get_height() }; SDL_RenderCopy( renderer, screen_tx, &rSrc, NULL ); SDL_RenderPresent( renderer ); } void dr_textur(int xp, int yp, int w, int h) { if( use_dirty_tiles ) { SDL_Rect r; r.x = xp; r.y = yp; r.w = xp + w > screen->w ? screen->w - xp : w; r.h = yp + h > screen->h ? screen->h - yp : h; SDL_UpdateTexture( screen_tx, &r, (uint8 *)screen->pixels + yp * screen->pitch + xp * sizeof(PIXVAL), screen->pitch ); } } static bool in_finger_handling = false; // move cursor to the specified location bool move_pointer(int x, int y) { if (in_finger_handling) { return false; } SDL_WarpMouseInWindow( window, TEX_TO_SCREEN_X(x), TEX_TO_SCREEN_Y(y) ); return true; } // set the mouse cursor (pointer/load) void set_pointer(int loading) { SDL_SetCursor( loading ? hourglass : arrow ); } /* * Hier sind die Funktionen zur Messageverarbeitung */ static inline unsigned int ModifierKeys() { const SDL_Keymod mod = SDL_GetModState(); return ((mod & KMOD_SHIFT) ? SIM_MOD_SHIFT : SIM_MOD_NONE) | ((mod & KMOD_CTRL) ? SIM_MOD_CTRL : SIM_MOD_NONE) #ifdef __APPLE__ // Treat the Command key as a control key. | ((mod & KMOD_GUI) ? SIM_MOD_CTRL : SIM_MOD_NONE) #endif ; } static uint16 conv_mouse_buttons(Uint8 const state) { return (state & SDL_BUTTON_LMASK ? MOUSE_LEFTBUTTON : 0) | (state & SDL_BUTTON_MMASK ? MOUSE_MIDBUTTON : 0) | (state & SDL_BUTTON_RMASK ? MOUSE_RIGHTBUTTON : 0); } static void internal_GetEvents() { // Apparently Cocoa SDL posts key events that meant to be used by IM... // Ignoring SDL_KEYDOWN during preedit seems to work fine. static bool composition_is_underway = false; static bool ignore_previous_number = false; static int previous_multifinger_touch = 0; static SDL_FingerID FirstFingerId = 0; static double dLastDist = 0.0; static bool has_queued_finger_release = false; static bool has_queued_zero_mouse_move = false; static sint32 last_mx, last_my; // last finger down pos if (has_queued_finger_release) { // we need to send a finger release, which was not done yet has_queued_finger_release = false; sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTUP; sys_event.mb = 0; sys_event.mx = last_mx; sys_event.my = last_my; sys_event.key_mod = ModifierKeys(); DBG_MESSAGE("SDL_FINGERUP for queue", "SIM_MOUSE_LEFTUP at %i,%i", sys_event.mx, sys_event.my); return; } if (has_queued_zero_mouse_move) { // we need to send a finger release, which was not done yet has_queued_zero_mouse_move = false; sys_event.type = SIM_MOUSE_MOVE; sys_event.code = 0; sys_event.mb = 0; sys_event.mx = last_mx; sys_event.my = last_my; sys_event.key_mod = ModifierKeys(); DBG_MESSAGE("SDL_FINGERUP for queue", "SIM_MOUSE_MOVE at %i,%i", sys_event.mx, sys_event.my); return; } SDL_Event event; event.type = 1; if (SDL_PollEvent(&event) == 0) { return; } static char textinput[SDL_TEXTINPUTEVENT_TEXT_SIZE]; DBG_DEBUG("SDL_EVENT", "0x%X", event.type); if (in_finger_handling && event.type == SDL_FINGERMOTION) { // swallow the millons of fingermotion events do { } while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) == 1); } switch( event.type ) { case SDL_APP_DIDENTERFOREGROUND: dr_stop_textinput(); intr_enable(); //reenable midi break; case SDL_WINDOWEVENT: if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ) { sys_event.new_window_size_w = max(1, SCREEN_TO_TEX_X(event.window.data1)); sys_event.new_window_size_h = max(1, SCREEN_TO_TEX_Y(event.window.data2)); sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_RESIZE; } // Ignore other window events. break; case SDL_MOUSEBUTTONDOWN: dLastDist = 0.0; if (event.button.which != SDL_TOUCH_MOUSEID) { sys_event.type = SIM_MOUSE_BUTTONS; switch( event.button.button ) { case SDL_BUTTON_LEFT: sys_event.code = SIM_MOUSE_LEFTBUTTON; break; case SDL_BUTTON_MIDDLE: sys_event.code = SIM_MOUSE_MIDBUTTON; break; case SDL_BUTTON_RIGHT: sys_event.code = SIM_MOUSE_RIGHTBUTTON; break; case SDL_BUTTON_X1: sys_event.code = SIM_MOUSE_WHEELUP; break; case SDL_BUTTON_X2: sys_event.code = SIM_MOUSE_WHEELDOWN; break; } sys_event.mx = SCREEN_TO_TEX_X(event.button.x); sys_event.my = SCREEN_TO_TEX_Y(event.button.y); sys_event.mb = conv_mouse_buttons( SDL_GetMouseState(0, 0) ); sys_event.key_mod = ModifierKeys(); } break; case SDL_MOUSEBUTTONUP: if (!previous_multifinger_touch && !in_finger_handling) { // we try to only handle mouse events sys_event.type = SIM_MOUSE_BUTTONS; switch( event.button.button ) { case SDL_BUTTON_LEFT: sys_event.code = SIM_MOUSE_LEFTUP; break; case SDL_BUTTON_MIDDLE: sys_event.code = SIM_MOUSE_MIDUP; break; case SDL_BUTTON_RIGHT: sys_event.code = SIM_MOUSE_RIGHTUP; break; } sys_event.mx = SCREEN_TO_TEX_X(event.button.x); sys_event.my = SCREEN_TO_TEX_Y(event.button.y); sys_event.mb = conv_mouse_buttons( SDL_GetMouseState(0, 0) ); sys_event.key_mod = ModifierKeys(); previous_multifinger_touch = false; } break; case SDL_MOUSEWHEEL: sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = event.wheel.y > 0 ? SIM_MOUSE_WHEELUP : SIM_MOUSE_WHEELDOWN; sys_event.key_mod = ModifierKeys(); break; case SDL_MOUSEMOTION: if (!in_finger_handling) { sys_event.type = SIM_MOUSE_MOVE; sys_event.code = SIM_MOUSE_MOVED; sys_event.mx = SCREEN_TO_TEX_X(event.motion.x); sys_event.my = SCREEN_TO_TEX_Y(event.motion.y); sys_event.mb = conv_mouse_buttons( SDL_GetMouseState(0, 0) ); sys_event.key_mod = ModifierKeys(); } break; case SDL_FINGERDOWN: /* just reset scroll state, since another finger may touch down next * The button down events will be from fingr move and the coordinate will be set from mouse up: enough */ DBG_MESSAGE("SDL_FINGERDOWN", "fingerID=%x FirstFingerId=%x Finger %i", (int)event.tfinger.fingerId, (int)FirstFingerId, SDL_GetNumTouchFingers(event.tfinger.touchId)); if (!in_finger_handling) { dLastDist = 0.0; FirstFingerId = event.tfinger.fingerId; DBG_MESSAGE("SDL_FINGERDOWN", "FirstfingerID=%x", FirstFingerId); in_finger_handling = true; previous_multifinger_touch = 0; } else if (FirstFingerId != event.tfinger.fingerId) { previous_multifinger_touch = 2; } break; case SDL_FINGERMOTION: // move whatever if( screen && previous_multifinger_touch==0 && FirstFingerId==event.tfinger.fingerId) { if (dLastDist == 0.0) { // not yet a finger down event before => we send one dLastDist = 1e-99; sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTBUTTON; sys_event.mx = event.tfinger.x * display_get_width(); sys_event.my = event.tfinger.y * display_get_height(); previous_multifinger_touch = 0; DBG_MESSAGE("SDL_FINGERMOTION", "SIM_MOUSE_LEFTBUTTON at %i,%i", sys_event.mx, sys_event.my); } else { sys_event.type = SIM_MOUSE_MOVE; sys_event.code = SIM_MOUSE_MOVED; sys_event.mx = event.tfinger.x * display_get_width(); sys_event.my = event.tfinger.y * display_get_height(); DBG_MESSAGE("SDL_FINGERMOTION", "SIM_MOUSE_MOVED at %i,%i", sys_event.mx, sys_event.my); } sys_event.mb = MOUSE_LEFTBUTTON; sys_event.key_mod = ModifierKeys(); } in_finger_handling = true; break; case SDL_FINGERUP: if (screen && in_finger_handling) { if (FirstFingerId==event.tfinger.fingerId || SDL_GetNumTouchFingers(event.tfinger.touchId)==0) { if(!previous_multifinger_touch) { if (dLastDist == 0.0) { dLastDist = 1e-99; // return a press event sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTBUTTON; sys_event.mb = MOUSE_LEFTBUTTON; sys_event.key_mod = ModifierKeys(); last_mx = sys_event.mx = event.tfinger.x * display_get_width(); last_my = sys_event.my = event.tfinger.y * display_get_height(); // not yet moved -> set click origin or click will be at last position ... set_click_xy(sys_event.mx, sys_event.my); has_queued_finger_release = true; DBG_MESSAGE("SDL_FINGERUP", "SIM_MOUSE_LEFTDOWN+UP at %i,%i", sys_event.mx, sys_event.my); } else { sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTUP; sys_event.mb = 0; sys_event.mx = (event.tfinger.x + event.tfinger.dx) * display_get_width(); sys_event.my = (event.tfinger.y + event.tfinger.dy) * display_get_height(); sys_event.key_mod = ModifierKeys(); DBG_MESSAGE("SDL_FINGERUP", "SIM_MOUSE_LEFTUP at %i,%i", sys_event.mx, sys_event.my); } } else { DBG_MESSAGE("SDL_FINGERUP", "ignored at %i,%i because previous_multifinger_touch>0", sys_event.mx, sys_event.my); } previous_multifinger_touch = 0; in_finger_handling = 0; FirstFingerId = 0xFFFF; } else { DBG_MESSAGE("SDL_FINGERUP", "ignored at %i,%i beacuse FirstFingerId(%xd)!=event.tfinger.fingerId(%xd) && SDL_GetNumTouchFinger()=%d", sys_event.mx, sys_event.my,FirstFingerId, event.tfinger.fingerId,SDL_GetNumTouchFingers(event.tfinger.touchId)); } } break; case SDL_MULTIGESTURE: DBG_MESSAGE("SDL_FINGERUP", "Finger %i", SDL_GetNumTouchFingers(event.tfinger.touchId)); in_finger_handling = true; if( event.mgesture.numFingers == 2 ) { int num_events; do { dLastDist += event.mgesture.dDist; num_events = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MULTIGESTURE, SDL_MULTIGESTURE); } while (num_events == 1); // any multitouch is intepreted as pinch zoom if (dLastDist < -DELTA_PINCH) { sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_WHEELDOWN; sys_event.key_mod = ModifierKeys(); //dLastDist += DELTA_PINCH; dLastDist = 0; } else if (dLastDist > DELTA_PINCH) { sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_WHEELUP; sys_event.key_mod = ModifierKeys(); //dLastDist -= DELTA_PINCH; dLastDist = 0; } previous_multifinger_touch = 2; } else if (event.mgesture.numFingers == 3 && screen) { // any three finger touch is scrolling the map if (previous_multifinger_touch != 3) { // just started scrolling set_click_xy(SCREEN_TO_TEX_X(event.mgesture.x* screen->w), SCREEN_TO_TEX_Y(event.mgesture.y* screen->h)); } do { } while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_MULTIGESTURE, SDL_MULTIGESTURE) == 1); sys_event.type = SIM_MOUSE_MOVE; sys_event.code = SIM_MOUSE_MOVED; sys_event.mb = MOUSE_RIGHTBUTTON; sys_event.key_mod = ModifierKeys(); sys_event.mx = SCREEN_TO_TEX_X(event.mgesture.x * screen->w); sys_event.my = SCREEN_TO_TEX_Y(event.mgesture.y * screen->h); previous_multifinger_touch = 3; } break; case SDL_KEYDOWN: { // Hack: when 2 byte character composition is under way, we have to leave the key processing with the IME // BUT: if not, we have to do it ourselves, or the cursor or return will not be recognised if( composition_is_underway ) { if( gui_component_t *c = win_get_focus() ) { if( gui_textinput_t *tinp = dynamic_cast(c) ) { if( tinp->get_composition()[0] ) { // pending string, handled by IME break; } } } } unsigned long code; #ifdef _WIN32 // SDL doesn't set numlock state correctly on startup. Revert to win32 function as workaround. const bool key_numlock = ((GetKeyState( VK_NUMLOCK ) & 1) != 0); #else const bool key_numlock = (SDL_GetModState() & KMOD_NUM); #endif const bool numlock = key_numlock || (env_t::numpad_always_moves_map && !win_is_textinput()); sys_event.key_mod = ModifierKeys(); SDL_Keycode sym = event.key.keysym.sym; bool np = false; // to indicate we converted a numpad key switch( sym ) { case SDLK_BACKSPACE: code = SIM_KEY_BACKSPACE; break; case SDLK_TAB: code = SIM_KEY_TAB; break; case SDLK_RETURN: code = SIM_KEY_ENTER; break; case SDLK_ESCAPE: code = SIM_KEY_ESCAPE; break; case SDLK_AC_BACK: case SDLK_DELETE: code = SIM_KEY_DELETE; break; case SDLK_DOWN: code = SIM_KEY_DOWN; break; case SDLK_END: code = SIM_KEY_END; break; case SDLK_HOME: code = SIM_KEY_HOME; break; case SDLK_F1: code = SIM_KEY_F1; break; case SDLK_F2: code = SIM_KEY_F2; break; case SDLK_F3: code = SIM_KEY_F3; break; case SDLK_F4: code = SIM_KEY_F4; break; case SDLK_F5: code = SIM_KEY_F5; break; case SDLK_F6: code = SIM_KEY_F6; break; case SDLK_F7: code = SIM_KEY_F7; break; case SDLK_F8: code = SIM_KEY_F8; break; case SDLK_F9: code = SIM_KEY_F9; break; case SDLK_F10: code = SIM_KEY_F10; break; case SDLK_F11: code = SIM_KEY_F11; break; case SDLK_F12: code = SIM_KEY_F12; break; case SDLK_F13: code = SIM_KEY_F13; break; case SDLK_F14: code = SIM_KEY_F14; break; case SDLK_F15: code = SIM_KEY_F15; break; case SDLK_KP_0: np = true; code = (numlock ? '0' : (unsigned long)SIM_KEY_NUMPAD_BASE); break; case SDLK_KP_1: np = true; code = (numlock ? '1' : (unsigned long)SIM_KEY_DOWNLEFT); break; case SDLK_KP_2: np = true; code = (numlock ? '2' : (unsigned long)SIM_KEY_DOWN); break; case SDLK_KP_3: np = true; code = (numlock ? '3' : (unsigned long)SIM_KEY_DOWNRIGHT); break; case SDLK_KP_4: np = true; code = (numlock ? '4' : (unsigned long)SIM_KEY_LEFT); break; case SDLK_KP_5: np = true; code = (numlock ? '5' : (unsigned long)SIM_KEY_CENTER); break; case SDLK_KP_6: np = true; code = (numlock ? '6' : (unsigned long)SIM_KEY_RIGHT); break; case SDLK_KP_7: np = true; code = (numlock ? '7' : (unsigned long)SIM_KEY_UPLEFT); break; case SDLK_KP_8: np = true; code = (numlock ? '8' : (unsigned long)SIM_KEY_UP); break; case SDLK_KP_9: np = true; code = (numlock ? '9' : (unsigned long)SIM_KEY_UPRIGHT); break; case SDLK_KP_ENTER: code = SIM_KEY_ENTER; break; case SDLK_LEFT: code = SIM_KEY_LEFT; break; case SDLK_PAGEDOWN: code = '<'; break; case SDLK_PAGEUP: code = '>'; break; case SDLK_RIGHT: code = SIM_KEY_RIGHT; break; case SDLK_UP: code = SIM_KEY_UP; break; case SDLK_PAUSE: code = SIM_KEY_PAUSE; break; case SDLK_SCROLLLOCK: code = SIM_KEY_SCROLLLOCK; break; default: { // Handle CTRL-keys. SDL_TEXTINPUT event handles regular input if( (sys_event.key_mod & SIM_MOD_CTRL) && SDLK_a <= sym && sym <= SDLK_z ) { code = event.key.keysym.sym & 31; } else { code = 0; } break; } } ignore_previous_number = (np && key_numlock); sys_event.type = SIM_KEYBOARD; sys_event.code = code; break; } case SDL_TEXTINPUT: { size_t in_pos = 0; utf32 uc = utf8_decoder_t::decode((utf8 const*)event.text.text, in_pos); if( event.text.text[in_pos]==0 ) { // single character if( ignore_previous_number ) { ignore_previous_number = false; break; } sys_event.type = SIM_KEYBOARD; sys_event.code = (unsigned long)uc; } else { // string strcpy( textinput, event.text.text ); sys_event.type = SIM_STRING; sys_event.ptr = (void*)textinput; } sys_event.key_mod = ModifierKeys(); composition_is_underway = false; break; } #ifdef USE_SDL_TEXTEDITING case SDL_TEXTEDITING: { //printf( "SDL_TEXTEDITING {timestamp=%d, \"%s\", start=%d, length=%d}\n", event.edit.timestamp, event.edit.text, event.edit.start, event.edit.length ); strcpy( textinput, event.edit.text ); if( !textinput[0] ) { composition_is_underway = false; } int i = 0; int start = 0; for( ; i(c) ) { tinp->set_composition_status( textinput, start, end-start ); } } composition_is_underway = true; break; } #endif case SDL_KEYUP: { sys_event.type = SIM_KEYBOARD; sys_event.code = 0; break; } case SDL_QUIT: { sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_QUIT; break; } default: { sys_event.type = SIM_IGNORE_EVENT; sys_event.code = 0; break; } } } void GetEvents() { internal_GetEvents(); } void show_pointer(int yesno) { SDL_SetCursor( (yesno != 0) ? arrow : blank ); } void ex_ord_update_mx_my() { SDL_PumpEvents(); } uint32 dr_time() { return SDL_GetTicks(); } void dr_sleep(uint32 usec) { SDL_Delay( usec ); } void dr_start_textinput() { if( env_t::hide_keyboard ) { SDL_StartTextInput(); DBG_MESSAGE("SDL_StartTextInput", ""); } } void dr_stop_textinput() { if( env_t::hide_keyboard ) { SDL_StopTextInput(); DBG_MESSAGE("SDL_StoptTextInput", ""); } else { SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); } } void dr_notify_input_pos(scr_coord pos) { SDL_Rect rect = { TEX_TO_SCREEN_X(pos.x), TEX_TO_SCREEN_Y(pos.y + LINESPACE), 1, 1}; SDL_SetTextInputRect( &rect ); } const char* dr_get_locale() { #if SDL_VERSION_ATLEAST(2, 0, 14) static char LanguageCode[5] = ""; SDL_Locale *loc = SDL_GetPreferredLocales(); if( loc ) { strncpy( LanguageCode, loc->language, 2 ); LanguageCode[2] = 0; DBG_MESSAGE( "dr_get_locale()", "%2s", LanguageCode ); return LanguageCode; } #endif return NULL; } bool dr_has_fullscreen() { return false; } sint16 dr_get_fullscreen() { return fullscreen ? BORDERLESS : WINDOWED; } sint16 dr_toggle_borderless() { if ( fullscreen ) { SDL_SetWindowFullscreen(window, 0); SDL_SetWindowPosition(window, 10, 10); fullscreen = WINDOWED; } else { SDL_SetWindowPosition(window, 0, 0); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); fullscreen = BORDERLESS; } return fullscreen; } sint16 dr_suspend_fullscreen() { int was_fullscreen = fullscreen; if (fullscreen) { SDL_SetWindowFullscreen(window, 0); fullscreen = WINDOWED; } SDL_MinimizeWindow(window); return was_fullscreen; } void dr_restore_fullscreen(sint16 was_fullscreen) { SDL_RestoreWindow(window); if(was_fullscreen) { SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); fullscreen = BORDERLESS; } } #ifdef _MSC_VER // Needed for MS Visual C++ with /SUBSYSTEM:CONSOLE to work , if /SUBSYSTEM:WINDOWS this function is compiled but unreachable #undef main int main() { return WinMain(NULL,NULL,NULL,NULL); } #endif #ifdef _WIN32 int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) #else int main(int argc, char **argv) #endif { #ifdef _WIN32 int const argc = __argc; char** const argv = __argv; #endif return sysmain(argc, argv); } simutrans-124.3/src/simutrans/sys/simsys_w.cc000066400000000000000000000666231474050137200214060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef _WIN32 #error "Only Windows has GDI!" #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef __CYGWIN__ extern int __argc; extern char **__argv; #endif #include "simsys.h" #include "../macros.h" #include "../simconst.h" #include "../simdebug.h" #include "../simmem.h" #include "../simversion.h" #include "../simevent.h" #include "../dataobj/environment.h" #include "../display/simgraph.h" #include "../gui/simwin.h" #include "../gui/gui_frame.h" #include "../gui/components/gui_component.h" #include "../gui/components/gui_textinput.h" #include "../utils/unicode.h" // needed for wheel #ifndef WM_MOUSEWHEEL # define WM_MOUSEWHEEL 0x020A #endif #ifndef GET_WHEEL_DELTA_WPARAM # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) #endif /* * The class name used to configure the main window. */ static const LPCWSTR WINDOW_CLASS_NAME = L"Simu"; static volatile HWND hwnd; static sint16 fullscreen = WINDOWED; static bool is_not_top = false; static MSG msg; static RECT WindowSize = { 0, 0, 0, 0 }; static RECT MaxSize; static HINSTANCE hInstance; static BITMAPINFO* AllDib = NULL; static PIXVAL* AllDibData; volatile HDC hdc = NULL; #ifdef MULTI_THREAD HANDLE hFlushThread=0; CRITICAL_SECTION redraw_underway; // forward deceleration DWORD WINAPI dr_flush_screen(LPVOID lpParam); #endif static long x_scale = 32; static long y_scale = 32; // scale automatically bool dr_set_screen_scale(sint16 percent) { bool scale_ok = false; long old_scale_x = x_scale, old_scale_y= y_scale; HDC hdc = GetDC(NULL); if( percent == -1 && hdc ) { x_scale = (GetDeviceCaps(hdc, LOGPIXELSX)*32)/96; y_scale = (GetDeviceCaps(hdc, LOGPIXELSY)*32)/96; scale_ok = true; } else if (percent == 0) { x_scale = y_scale = 32; scale_ok = true; } else if (percent < 0) { dbg->error("dr_set_screen_scale(Win32)", "Invalid screen scaling %d (Must be >= -1)", percent); return false; } else { x_scale = (percent * 32) / 100; y_scale = (percent * 32) / 100; } ReleaseDC(NULL, hdc); if( (x_scale!=old_scale_x || y_scale!=old_scale_y) && hwnd) { // force window size update RECT TempRect; GetWindowRect(hwnd, &TempRect); const LRESULT res = PostMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELPARAM(TempRect.right - TempRect.left, TempRect.bottom - TempRect.top)); } return true; } sint16 dr_get_screen_scale() { return (x_scale * 100) / 32; } /* * Hier sind die Basisfunktionen zur Initialisierung der * Schnittstelle untergebracht * -> init,open,close */ bool dr_os_init(int const* /*parameter*/) { // prepare for next event sys_event.type = SIM_NOEVENT; sys_event.code = 0; return true; } resolution dr_query_screen_resolution() { resolution res; res.w = (GetSystemMetrics(SM_CXSCREEN)*32)/x_scale; res.h = (GetSystemMetrics(SM_CYSCREEN)*32)/y_scale; return res; } static void create_window(DWORD const ex_style, DWORD const style, int const x, int const y, int const w, int const h) { RECT r = { 0, 0, w, h }; AdjustWindowRectEx(&r, style, false, ex_style); // Convert UTF-8 to UTF-16. int const size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, SIM_TITLE, -1, NULL, 0); LPWSTR const wSIM_TITLE = new WCHAR[size]; MultiByteToWideChar(CP_UTF8, 0, SIM_TITLE, -1, wSIM_TITLE, size); hwnd = CreateWindowExW(ex_style, WINDOW_CLASS_NAME, wSIM_TITLE, style, x, y, r.right - r.left, r.bottom - r.top, 0, 0, hInstance, 0); delete[] wSIM_TITLE; ShowWindow(hwnd, SW_SHOW); SetTimer( hwnd, 0, 1111, NULL ); // HACK: so windows thinks we are not dead when processing a timer every 1111 ms ... } static DEVMODE settings; // open the window int dr_os_open(const scr_size window_size, sint16 fs) { MaxSize.right = ((window_size.w*x_scale)/32+15) & 0x7FF0; MaxSize.bottom = (window_size.h*y_scale)/32; fullscreen = fs; #ifdef MULTI_THREAD InitializeCriticalSection( &redraw_underway ); hFlushThread = CreateThread( NULL, 0, dr_flush_screen, 0, CREATE_SUSPENDED, NULL ); #endif MEMZERO(settings); // fake fullscreen if (fullscreen) { // try to force display mode and size settings.dmSize = sizeof(settings); settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; settings.dmBitsPerPel = COLOUR_DEPTH; settings.dmPelsWidth = MaxSize.right; settings.dmPelsHeight = MaxSize.bottom; settings.dmDisplayFrequency = 0; if( ChangeDisplaySettings(&settings, CDS_TEST)!=DISP_CHANGE_SUCCESSFUL ) { // evt. try again in 32 bit if( COLOUR_DEPTH<32 ) { settings.dmBitsPerPel = 32; } dbg->warning("dr_os_open(w32)", "Could not reduce color depth to 16 Bit in fullscreen." ); } if( ChangeDisplaySettings(&settings, CDS_TEST)!=DISP_CHANGE_SUCCESSFUL ) { ChangeDisplaySettings( NULL, 0 ); fullscreen = WINDOWED; } else { ChangeDisplaySettings(&settings, CDS_FULLSCREEN); } } if( fullscreen ) { create_window(WS_EX_TOPMOST, WS_POPUP, 0, 0, MaxSize.right, MaxSize.bottom); } else { create_window(0, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, MaxSize.right, MaxSize.bottom); } WindowSize.right = MaxSize.right; WindowSize.bottom = MaxSize.bottom; AllDib = MALLOCF(BITMAPINFO, bmiColors, 3); BITMAPINFOHEADER& header = AllDib->bmiHeader; header.biSize = sizeof(BITMAPINFOHEADER); header.biWidth = (window_size.w+15) & 0x7FF0; header.biHeight = window_size.h; header.biPlanes = 1; header.biBitCount = COLOUR_DEPTH; header.biCompression = BI_RGB; header.biSizeImage = 0; header.biXPelsPerMeter = 0; header.biYPelsPerMeter = 0; header.biClrUsed = 0; header.biClrImportant = 0; DWORD* const masks = (DWORD*)AllDib->bmiColors; #ifdef RGB555 masks[0] = 0x01; masks[1] = 0x02; masks[2] = 0x03; #else header.biCompression = BI_BITFIELDS; masks[0] = 0x0000F800; masks[1] = 0x000007E0; masks[2] = 0x0000001F; #endif MaxSize.right = header.biWidth; MaxSize.bottom = header.biHeight; return header.biWidth; } void dr_os_close() { #ifdef MULTI_THREAD if( hFlushThread ) { TerminateThread( hFlushThread, 0 ); LeaveCriticalSection( &redraw_underway ); DeleteCriticalSection( &redraw_underway ); } #endif if (hwnd != NULL) { DestroyWindow(hwnd); } free(AllDibData); AllDibData = NULL; free(AllDib); AllDib = NULL; if( fullscreen == FULLSCREEN ) { ChangeDisplaySettings(NULL, 0); } } // resizes screen int dr_textur_resize(unsigned short** const textur, int w, int const h) { #ifdef MULTI_THREAD EnterCriticalSection( &redraw_underway ); #endif // some cards need those alignments w = (w + 15) & 0x7FF0; if( w<=0 ) { w = 16; } int img_w = w; int img_h = h; if( w > MaxSize.right || h >= MaxSize.bottom ) { // since the query routines that return the desktop data do not take into account a change of resolution free(AllDibData); AllDibData = NULL; MaxSize.right = w; MaxSize.bottom = h; AllDibData = MALLOCN(PIXVAL, img_w * img_h); *textur = (unsigned short*)AllDibData; } AllDib->bmiHeader.biWidth = img_w; AllDib->bmiHeader.biHeight = img_h; WindowSize.right = w; WindowSize.bottom = h; #ifdef MULTI_THREAD LeaveCriticalSection( &redraw_underway ); #endif return w; } unsigned short *dr_textur_init() { size_t const n = AllDib->bmiHeader.biWidth * AllDib->bmiHeader.biHeight; AllDibData = MALLOCN(PIXVAL, n); // start with black MEMZERON(AllDibData, n); return (unsigned short*)AllDibData; } /** * Transform a 24 bit RGB color into the system format. * @return converted color value */ PIXVAL get_system_color(rgb888_t col) { #ifdef RGB555 return ((col.r & 0xF8) << 7) | ((col.g & 0xF8) << 2) | (col.b >> 3); // 15 Bit #else return ((col.r & 0xF8) << 8) | ((col.g & 0xFC) << 3) | (col.b >> 3); #endif } #ifdef MULTI_THREAD // multithreaded screen copy ... DWORD WINAPI dr_flush_screen(LPVOID /*lpParam*/) { while(1) { // wait for finish of thread EnterCriticalSection( &redraw_underway ); hdc = GetDC(hwnd); display_flush_buffer(); ReleaseDC(hwnd, hdc); hdc = NULL; LeaveCriticalSection( &redraw_underway ); // suspend myself after one update SuspendThread( hFlushThread ); } return 0; } #endif void dr_prepare_flush() { #ifdef MULTI_THREAD // now the thread is finished ... EnterCriticalSection( &redraw_underway ); #endif } void dr_flush() { #ifdef MULTI_THREAD // just let the thread do its work LeaveCriticalSection( &redraw_underway ); ResumeThread( hFlushThread ); #else assert(hdc==NULL); hdc = GetDC(hwnd); display_flush_buffer(); ReleaseDC(hwnd, hdc); hdc = NULL; #endif } void dr_textur(int xp, int yp, int w, int h) { if( x_scale==32 && y_scale==32 ) { // make really sure we are not beyond screen coordinates w = min( xp+w, AllDib->bmiHeader.biWidth ) - xp; h = min( yp+h, AllDib->bmiHeader.biHeight ) - yp; if( h>1 && w>0 ) { StretchDIBits(hdc, xp, yp, w, h, xp, yp+h+1, w, -h, AllDibData, AllDib, DIB_RGB_COLORS, SRCCOPY); } } else { // align on 32 border to avoid rounding errors w += (xp % 32); h += (yp % 32); w = (w+31) & 0xFFE0; h = (h+31) & 0xFFE0; xp &= 0xFFE0; yp &= 0xFFE0; int xscr = (xp/32)*x_scale; int yscr = (yp/32)*y_scale; // make really sure we are not beyond screen coordinates w = min( xp+w, AllDib->bmiHeader.biWidth ) - xp; h = min( yp+h, AllDib->bmiHeader.biHeight ) - yp; if( h>1 && w>0 ) { SetStretchBltMode( hdc, HALFTONE ); SetBrushOrgEx( hdc, 0, 0, NULL ); StretchDIBits(hdc, xscr, yscr, (w*x_scale)/32, (h*y_scale)/32, xp, yp+h+1, w, -h, AllDibData, AllDib, DIB_RGB_COLORS, SRCCOPY); } } } bool dr_has_fullscreen() { return true; } sint16 dr_get_fullscreen() { return fullscreen; } sint16 dr_toggle_borderless() { if (fullscreen == WINDOWED) { SetWindowLongPtr(hwnd, GWL_STYLE, WS_POPUP); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); fullscreen = BORDERLESS; } else if (fullscreen == BORDERLESS) { SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); SetWindowPos(hwnd, HWND_NOTOPMOST, 10, 10, GetSystemMetrics(SM_CXSCREEN)-20, GetSystemMetrics(SM_CYSCREEN)-20, SWP_SHOWWINDOW); fullscreen = WINDOWED; } return fullscreen; } sint16 dr_suspend_fullscreen() { int was_fullscreen = 0; if( hwnd && fullscreen ) { SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); was_fullscreen = fullscreen; fullscreen = WINDOWED; } else { ShowWindow(hwnd, SW_SHOWMINNOACTIVE); } return was_fullscreen; } void dr_restore_fullscreen(sint16 was_fullscreen) { if( hwnd && was_fullscreen ) { SetWindowLongPtr(hwnd, GWL_STYLE, WS_EX_TOPMOST); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW); was_fullscreen = fullscreen; } else { ShowWindow(hwnd, SW_RESTORE); } } // move cursor to the specified location bool move_pointer(int x, int y) { POINT pt = { ((long)x*x_scale+16)/32, ((long)y*y_scale+16)/32 }; ClientToScreen(hwnd, &pt); SetCursorPos(pt.x, pt.y); return true; } // set the mouse cursor (pointer/load) void set_pointer(int loading) { SetCursor(LoadCursor(NULL, loading != 0 ? IDC_WAIT : IDC_ARROW)); } /* * Hier sind die Funktionen zur Messageverarbeitung */ static inline unsigned int ModifierKeys() { return (GetKeyState(VK_SHIFT) < 0 ? 1 : 0) | (GetKeyState(VK_CONTROL) < 0 ? 2 : 0); // highest bit set or return value<0 -> key is pressed } /* Windows eventhandler: does most of the work */ LRESULT WINAPI WindowProc(HWND this_hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { bool update_mouse = false; // Used for IME handling. static utf8 *u8buf = NULL; static size_t u8bufsize; static int last_mb = 0; // last mouse button state switch (msg) { case WM_TIMER: // dummy timer even to keep windows thinking we are still active return 0; case WM_ACTIVATE: // may check, if we have to restore color depth if(fullscreen) { // avoid double calls static bool while_handling = false; if(while_handling) { break; } while_handling = true; if(LOWORD(wParam)!=WA_INACTIVE && is_not_top) { #ifdef MULTI_THREAD // no updating while deleting a window please ... EnterCriticalSection( &redraw_underway ); #endif // try to force display mode and size // should be always successful, since it worked as least once ... ChangeDisplaySettings(&settings, CDS_FULLSCREEN); is_not_top = false; // must reshow window, otherwise startbar will be topmost ... create_window(WS_EX_TOPMOST, WS_POPUP, 0, 0, MaxSize.right, MaxSize.bottom); DestroyWindow( this_hwnd ); while_handling = false; #ifdef MULTI_THREAD LeaveCriticalSection( &redraw_underway ); #endif return true; } else if(LOWORD(wParam)==WA_INACTIVE && !is_not_top) { // restore default CloseWindow( hwnd ); ChangeDisplaySettings( NULL, 0 ); is_not_top = true; } while_handling = false; } break; case WM_GETMINMAXINFO: if(fullscreen) { LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam; lpmmi->ptMaxPosition.x = 0; lpmmi->ptMaxPosition.y = 0; } break; case WM_LBUTTONDOWN: /* originally ButtonPress */ SetCapture(this_hwnd); sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTBUTTON; update_mouse = true; break; case WM_LBUTTONUP: /* originally ButtonRelease */ ReleaseCapture(); sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_LEFTUP; update_mouse = true; break; case WM_MBUTTONDOWN: /* because capture or release may not start with the expected button */ case WM_XBUTTONDOWN: SetCapture(this_hwnd); break; case WM_MBUTTONUP: /* because capture or release may not start with the expected button */ case WM_XBUTTONUP: ReleaseCapture(); break; case WM_RBUTTONDOWN: /* originally ButtonPress */ SetCapture(this_hwnd); sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_RIGHTBUTTON; update_mouse = true; break; case WM_RBUTTONUP: /* originally ButtonRelease */ ReleaseCapture(); sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = SIM_MOUSE_RIGHTUP; update_mouse = true; break; case WM_MOUSEMOVE: sys_event.type = SIM_MOUSE_MOVE; sys_event.code = SIM_MOUSE_MOVED; update_mouse = true; break; case WM_MOUSEWHEEL: sys_event.type = SIM_MOUSE_BUTTONS; sys_event.code = GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? SIM_MOUSE_WHEELUP : SIM_MOUSE_WHEELDOWN; sys_event.key_mod = ModifierKeys(); /* the returned coordinate in LPARAM are absolute coordinates, which will deeply confuse simutrans * we just reuse the coordinates we used the last time by not changing mx/my ... */ return 0; #ifdef WM_DPICHANGED case WM_DPICHANGED: { RECT *r = (LPRECT)lParam; x_scale = (LOWORD(wParam)*32)/96; y_scale = (HIWORD(wParam)*32)/96; SetWindowPos( hwnd, NULL, r->left, r->top, r->right-r->left, r->bottom-r->top, SWP_NOZORDER ); } break; #endif case WM_SIZE: // resize client area if(lParam!=0) { sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_RESIZE; sys_event.new_window_size_w = (LOWORD(lParam)*32)/x_scale; if (sys_event.new_window_size_w <= 0) { sys_event.new_window_size_w = 4; } sys_event.new_window_size_h = (HIWORD(lParam)*32)/y_scale; if (sys_event.new_window_size_h <= 1) { sys_event.new_window_size_h = 64; } } break; case WM_PAINT: { if (AllDib != NULL) { PAINTSTRUCT ps; HDC hdcp; hdcp = BeginPaint(hwnd, &ps); AllDib->bmiHeader.biHeight = (WindowSize.bottom*32)/y_scale; StretchDIBits(hdcp, 0, 0, WindowSize.right, WindowSize.bottom, 0, AllDib->bmiHeader.biHeight + 1, AllDib->bmiHeader.biWidth, -AllDib->bmiHeader.biHeight, AllDibData, AllDib, DIB_RGB_COLORS, SRCCOPY); EndPaint(this_hwnd, &ps); } break; } case WM_KEYDOWN: { /* originally KeyPress */ // check for not numlock! sys_event.type = SIM_KEYBOARD; sys_event.code = 0; sys_event.key_mod = ModifierKeys(); sint16 code = lParam >> 16; if( code >= 0x47 && code <= 0x52 && code != 0x4A && code != 0x4e ) { if( (GetKeyState( VK_NUMLOCK ) & 1) == 0 || (env_t::numpad_always_moves_map && !win_is_textinput()) ) { // numlock off? switch( code ) { case 0x47: code = SIM_KEY_UPLEFT; break; case 0x48: code = SIM_KEY_UP; break; case 0x49: code = SIM_KEY_UPRIGHT; break; case 0x4B: code = SIM_KEY_LEFT; break; case 0x4C: code = SIM_KEY_CENTER; break; case 0x4D: code = SIM_KEY_RIGHT; break; case 0x4F: code = SIM_KEY_DOWNLEFT; break; case 0x50: code = SIM_KEY_DOWN; break; case 0x51: code = SIM_KEY_DOWNRIGHT; break; case 0x52: code = SIM_KEY_NUMPAD_BASE; break; } if( code>=SIM_KEY_NUMPAD_BASE ) { // ok found something sys_event.code = code; break; } } } // do low level special stuff here switch (wParam) { case VK_SCROLL: sys_event.code = SIM_KEY_SCROLLLOCK; break; case VK_PAUSE: sys_event.code = SIM_KEY_PAUSE; break; case VK_LEFT: sys_event.code = SIM_KEY_LEFT; break; case VK_RIGHT: sys_event.code = SIM_KEY_RIGHT; break; case VK_UP: sys_event.code = SIM_KEY_UP; break; case VK_DOWN: sys_event.code = SIM_KEY_DOWN; break; case VK_PRIOR: sys_event.code = '>'; break; case VK_NEXT: sys_event.code = '<'; break; case VK_DELETE: sys_event.code = 127; break; case VK_HOME: sys_event.code = SIM_KEY_HOME; break; case VK_END: sys_event.code = SIM_KEY_END; break; } // check for F-Keys! if (sys_event.code == 0 && wParam >= VK_F1 && wParam <= VK_F15) { sys_event.code = wParam - VK_F1 + SIM_KEY_F1; //printf("WindowsEvent: Key %i, (state %i)\n", sys_event.code, sys_event.key_mod); } // some result? if (sys_event.code != 0) return 0; sys_event.type = SIM_NOEVENT; sys_event.code = 0; break; } case WM_CHAR: /* originally KeyPress */ { sint16 code = lParam >> 16; if( code >= 0x47 && code <= 0x52 && code != 0x4A && code != 0x4e ) { if( (GetKeyState( VK_NUMLOCK ) & 1) == 0 || (env_t::numpad_always_moves_map && !win_is_textinput()) ) { // numlock off? // we handled this numpad keys already above ... sys_event.type = SIM_NOEVENT; sys_event.code = 0; break; } } sys_event.type = SIM_KEYBOARD; sys_event.code = wParam; sys_event.key_mod = ModifierKeys(); break; } case WM_IME_SETCONTEXT: // attempt to avoid crash at windows 1809> just not call DefWinodwsProc seems to work for SDL2 ... // DefWindowProc( this_hwnd, msg, wParam, lParam&~ISC_SHOWUICOMPOSITIONWINDOW ); lParam = 0; return 0; case WM_IME_STARTCOMPOSITION: break; case WM_IME_REQUEST: if( wParam == IMR_QUERYCHARPOSITION ) { if( gui_component_t *c = win_get_focus() ) { if( gui_textinput_t *tinp = dynamic_cast(c) ) { IMECHARPOSITION *icp = (IMECHARPOSITION *)lParam; icp->cLineHeight = LINESPACE; scr_coord pos = tinp->get_pos(); scr_coord gui_xy = win_get_pos( win_get_top() ); LONG x = pos.x + gui_xy.x + tinp->get_current_cursor_x(); const char *composition = tinp->get_composition(); for( DWORD i=0; idwCharPos; ++i ) { if( !*composition ) { break; } unsigned char pixel_width; unsigned char unused; get_next_char_with_metrics( composition, unused, pixel_width ); x += pixel_width; } icp->pt.x = x; icp->pt.y = pos.y + gui_xy.y + D_TITLEBAR_HEIGHT; ClientToScreen( this_hwnd, &icp->pt ); icp->rcDocument.left = 0; icp->rcDocument.right = 0; icp->rcDocument.top = 0; icp->rcDocument.bottom = 0; //printf("IMECHARPOSITION {dwCharPos=%d, pt {x=%d, y=%d} }\n", icp->dwCharPos, icp->pt.x, icp->pt.y); return TRUE; } } break; } return DefWindowProcW( this_hwnd, msg, wParam, lParam ); case WM_IME_COMPOSITION: { HIMC immcx = 0; if( lParam & (GCS_RESULTSTR|GCS_COMPSTR) ) { immcx = ImmGetContext( this_hwnd ); } if( lParam & GCS_RESULTSTR ) { // Retrieve the composition result. size_t u16size = ImmGetCompositionStringW(immcx, GCS_RESULTSTR, NULL, 0); utf16 *u16buf = (utf16*)malloc(u16size + 2); size_t copied = ImmGetCompositionStringW(immcx, GCS_RESULTSTR, u16buf, u16size + 2); // clear old composition if( gui_component_t *c = win_get_focus() ) { if( gui_textinput_t *tinp = dynamic_cast(c) ) { tinp->set_composition_status( NULL, 0, 0 ); } } // add result if( u16size>2 ) { u16buf[copied/2] = 0; // Grow the buffer as needed. size_t u8size = u16size + u16size/2; if( !u8buf ) { u8bufsize = u8size + 1; u8buf = (utf8 *)malloc( u8bufsize ); } else if( u8size >= u8bufsize ) { u8bufsize = max( u8bufsize*2, u8size+1 ); free( u8buf ); u8buf = (utf8 *)malloc( u8bufsize ); } // Convert UTF-16 to UTF-8. utf16 *s = u16buf; int i = 0; while( *s ) { i += utf16_to_utf8( *s++, u8buf+i ); } u8buf[i] = 0; free( u16buf ); sys_event.type = SIM_STRING; sys_event.ptr = (void*)u8buf; } else { // single key sys_event.type = SIM_KEYBOARD; sys_event.code = u16buf[0]; } sys_event.key_mod = ModifierKeys(); } else if( lParam & (GCS_COMPSTR|GCS_COMPATTR) ) { if( gui_component_t *c = win_get_focus() ) { if( gui_textinput_t *tinp = dynamic_cast(c) ) { // Query current conversion status int num_attr = ImmGetCompositionStringW( immcx, GCS_COMPATTR, NULL, 0 ); if( num_attr <= 0 ) { // This shouldn't happen... just in case. break; } char *attrs = (char *)malloc( num_attr ); ImmGetCompositionStringW( immcx, GCS_COMPATTR, attrs, num_attr ); int start = 0; for( ; start < num_attr; ++start ) { if( attrs[start] == ATTR_TARGET_CONVERTED || attrs[start] == ATTR_TARGET_NOTCONVERTED ) { break; } } int end = start; for( ; end < num_attr; ++end ) { if( attrs[end] != ATTR_TARGET_CONVERTED && attrs[end] != ATTR_TARGET_NOTCONVERTED ) { break; } } free( attrs ); // Then retrieve the composition text size_t u16size = ImmGetCompositionStringW( immcx, GCS_COMPSTR, NULL, 0 ); utf16 *u16buf = (utf16 *)malloc( u16size+2 ); size_t copied = ImmGetCompositionStringW( immcx, GCS_COMPSTR, u16buf, u16size+2 ); u16buf[copied/2] = 0; // Grow the buffer as needed. size_t u8size = u16size + u16size/2; if( !u8buf ) { u8bufsize = u8size + 1; u8buf = (utf8 *)malloc( u8bufsize ); } else if( u8size >= u8bufsize ) { u8bufsize = max( u8bufsize*2, u8size+1 ); free( u8buf ); u8buf = (utf8 *)malloc( u8bufsize ); } // Convert UTF-16 to UTF-8. utf16 *s = u16buf; int offset = 0; int i = 0; int u8start = 0, u8end = 0; while( true ) { if( i == start ) u8start = offset; if( i == end ) u8end = offset; if( !*s ) { break; } offset += utf16_to_utf8( *s, u8buf + offset ); ++s; ++i; } u8buf[offset] = 0; free( u16buf ); tinp->set_composition_status( (char *)u8buf, u8start, u8end-u8start ); } } } if( immcx ) { ImmReleaseContext( this_hwnd, immcx ); } break; } case WM_IME_ENDCOMPOSITION: if( gui_component_t *c = win_get_focus() ) { if( gui_textinput_t *tinp = dynamic_cast(c) ) { tinp->set_composition_status( NULL, 0, 0 ); } } break; case WM_CLOSE: if (AllDibData != NULL) { sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_QUIT; } break; case WM_DESTROY: free( u8buf ); if( hwnd==this_hwnd || AllDibData == NULL ) { sys_event.type = SIM_SYSTEM; sys_event.code = SYSTEM_QUIT; if( AllDibData == NULL ) { PostQuitMessage(0); hwnd = NULL; } } break; default: return DefWindowProcW(this_hwnd, msg, wParam, lParam); } if( update_mouse ) { sys_event.key_mod = ModifierKeys(); sys_event.mb = last_mb = (wParam&3); sint16 x = LOWORD(lParam); sys_event.mx = (x * 32l)/x_scale; sint16 y = HIWORD(lParam); sys_event.my = (y * 32l)/y_scale; } return 0; } static void internal_GetEvents(bool const wait) { do { // wait for keybord/mouse event GetMessage(&msg, NULL, 0, 0); TranslateMessage(&msg); DispatchMessage(&msg); } while(wait && sys_event.type == SIM_NOEVENT); } void GetEvents() { if (sys_event.type==SIM_NOEVENT && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { internal_GetEvents(false); } } void show_pointer(int yesno) { static int state=true; if(state^yesno) { ShowCursor(yesno); state = yesno; } } void ex_ord_update_mx_my() { // evt. called before update } uint32 dr_time() { return timeGetTime(); } void dr_sleep(uint32 millisec) { Sleep(millisec); } void dr_start_textinput() { } void dr_stop_textinput() { HIMC immcx = ImmGetContext( hwnd ); ImmNotifyIME( immcx, NI_COMPOSITIONSTR, CPS_CANCEL, 0 ); ImmReleaseContext( hwnd, immcx ); } void dr_notify_input_pos(scr_coord pos) { const int x = (pos.x * x_scale)/32; const int y = (pos.y * y_scale)/32; COMPOSITIONFORM co; co.dwStyle = CFS_POINT; co.ptCurrentPos.x = (LONG)x; co.ptCurrentPos.y = (LONG)y; CANDIDATEFORM ca; ca.dwIndex = 0; ca.dwStyle = CFS_CANDIDATEPOS; ca.ptCurrentPos.x = (LONG)x; ca.ptCurrentPos.y = (LONG)y + D_TITLEBAR_HEIGHT; HIMC immcx = ImmGetContext( hwnd ); ImmSetCompositionWindow( immcx, &co ); ImmSetCandidateWindow( immcx, &ca ); ImmReleaseContext( hwnd, immcx ); } #ifdef _MSC_VER // Needed for MS Visual C++ with /SUBSYSTEM:CONSOLE to work , if /SUBSYSTEM:WINDOWS this function is compiled but unreachable int main() { HINSTANCE const hInstance = (HINSTANCE)GetModuleHandle(NULL); return WinMain(hInstance,NULL,NULL,NULL); } #endif const char* dr_get_locale() { static char LanguageCode[5]=""; GetLocaleInfoA( GetUserDefaultUILanguage(), LOCALE_SISO639LANGNAME, LanguageCode, lengthof( LanguageCode ) ); return LanguageCode; } int CALLBACK WinMain(HINSTANCE const hInstance, HINSTANCE, LPSTR, int) { WNDCLASSW wc; bool timer_is_set = false; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(100)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1); wc.lpszMenuName = NULL; wc.lpszClassName = WINDOW_CLASS_NAME; RegisterClassW(&wc); GetWindowRect(GetDesktopWindow(), &MaxSize); // maybe set timer to 1ms interval on Win2k upwards ... { OSVERSIONINFO osinfo; osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osinfo) && osinfo.dwPlatformId==VER_PLATFORM_WIN32_NT) { timeBeginPeriod(1); timer_is_set = true; } } int const res = sysmain(__argc, __argv); if( timer_is_set ) { timeEndPeriod(1); } #ifdef MULTI_THREAD if( hFlushThread ) { TerminateThread( hFlushThread, 0 ); } #endif return res; } simutrans-124.3/src/simutrans/tool/000077500000000000000000000000001474050137200173445ustar00rootroot00000000000000simutrans-124.3/src/simutrans/tool/simmenu.cc000066400000000000000000001367341474050137200213460ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../utils/unicode.h" #include "../simevent.h" #include "../world/simworld.h" #include "../gui/simwin.h" #include "../player/simplay.h" #include "../tool/simmenu.h" #include "../tool/simtool.h" #include "../tool/simtool-dialogs.h" #include "../tool/simtool-scripted.h" #include "../simskin.h" #include "../simsound.h" #include "../builder/hausbauer.h" #include "../builder/wegbauer.h" #include "../builder/brueckenbauer.h" #include "../builder/tunnelbauer.h" #include "../script/script_tool_manager.h" #include "../descriptor/building_desc.h" #include "../descriptor/bridge_desc.h" #include "../descriptor/tunnel_desc.h" #include "../ground/grund.h" #include "../obj/way/strasse.h" #include "../dataobj/environment.h" #include "../dataobj/tabfile.h" #include "../dataobj/scenario.h" #include "../obj/roadsign.h" #include "../obj/wayobj.h" #include "../obj/zeiger.h" #include "../gui/tool_selector.h" #include "../utils/simstring.h" #include "../network/memory_rw.h" karte_ptr_t tool_t::welt; // emulate control key by tool uint8 tool_t::control_invert = 0; // for key lookup; is always sorted during the game vector_tpltool_t::char_to_tool(0); // here are the default values, icons, cursor, sound definitions ... vector_tpltool_t::general_tool(GENERAL_TOOL_COUNT); vector_tpltool_t::simple_tool(SIMPLE_TOOL_COUNT); vector_tpltool_t::dialog_tool(DIALOGE_TOOL_COUNT); // the number of toolbars is not know yet vector_tpltool_t::toolbar_tool(0); char tool_t::toolstr[1024]; toolbar_last_used_t* toolbar_last_used_t::last_used_tools = NULL; const char* tool_t::id_to_string(uint16 id) { #define CASE_TO_STRING(entry) case entry: return #entry if (id & GENERAL_TOOL) { switch (id & ~GENERAL_TOOL) { CASE_TO_STRING(TOOL_QUERY); CASE_TO_STRING(TOOL_REMOVER); CASE_TO_STRING(TOOL_RAISE_LAND); CASE_TO_STRING(TOOL_LOWER_LAND); CASE_TO_STRING(TOOL_SETSLOPE); CASE_TO_STRING(TOOL_RESTORESLOPE); CASE_TO_STRING(TOOL_MARKER); CASE_TO_STRING(TOOL_CLEAR_RESERVATION); CASE_TO_STRING(TOOL_TRANSFORMER); CASE_TO_STRING(TOOL_ADD_CITY); CASE_TO_STRING(TOOL_CHANGE_CITY_SIZE); CASE_TO_STRING(TOOL_PLANT_TREE); CASE_TO_STRING(TOOL_SCHEDULE_ADD); CASE_TO_STRING(TOOL_SCHEDULE_INS); CASE_TO_STRING(TOOL_BUILD_WAY); CASE_TO_STRING(TOOL_BUILD_BRIDGE); CASE_TO_STRING(TOOL_BUILD_TUNNEL); CASE_TO_STRING(TOOL_WAYREMOVER); CASE_TO_STRING(TOOL_BUILD_WAYOBJ); CASE_TO_STRING(TOOL_BUILD_STATION); CASE_TO_STRING(TOOL_BUILD_ROADSIGN); CASE_TO_STRING(TOOL_BUILD_DEPOT); CASE_TO_STRING(TOOL_BUILD_HOUSE); CASE_TO_STRING(TOOL_BUILD_LAND_CHAIN); CASE_TO_STRING(TOOL_CITY_CHAIN); CASE_TO_STRING(TOOL_BUILD_FACTORY); CASE_TO_STRING(TOOL_LINK_FACTORY); CASE_TO_STRING(TOOL_HEADQUARTER); CASE_TO_STRING(TOOL_LOCK_GAME); CASE_TO_STRING(TOOL_ADD_CITYCAR); CASE_TO_STRING(TOOL_FOREST); CASE_TO_STRING(TOOL_STOP_MOVER); CASE_TO_STRING(TOOL_MAKE_STOP_PUBLIC); CASE_TO_STRING(TOOL_REMOVE_WAYOBJ); CASE_TO_STRING(TOOL_SLICED_AND_UNDERGROUND_VIEW); CASE_TO_STRING(TOOL_BUY_HOUSE); CASE_TO_STRING(TOOL_BUILD_CITYROAD); CASE_TO_STRING(TOOL_ERROR_MESSAGE); CASE_TO_STRING(TOOL_CHANGE_WATER_HEIGHT); CASE_TO_STRING(TOOL_SET_CLIMATE); CASE_TO_STRING(TOOL_ROTATE_BUILDING); CASE_TO_STRING(TOOL_MERGE_STOP); CASE_TO_STRING(TOOL_EXEC_SCRIPT); CASE_TO_STRING(TOOL_EXEC_TWO_CLICK_SCRIPT); CASE_TO_STRING(TOOL_PLANT_GROUNDOBJ); CASE_TO_STRING(TOOL_REMOVE_SIGNAL); CASE_TO_STRING(TOOL_GENERATE_SCRIPT); CASE_TO_STRING(TOOL_PIPETTE); CASE_TO_STRING(TOOL_SET_OWNER); } } else if (id & SIMPLE_TOOL) { switch (id & ~SIMPLE_TOOL) { CASE_TO_STRING(TOOL_PAUSE); CASE_TO_STRING(TOOL_FASTFORWARD); CASE_TO_STRING(TOOL_SCREENSHOT); CASE_TO_STRING(TOOL_INCREASE_INDUSTRY); CASE_TO_STRING(TOOL_UNDO); CASE_TO_STRING(TOOL_SWITCH_PLAYER); CASE_TO_STRING(TOOL_STEP_YEAR); CASE_TO_STRING(TOOL_CHANGE_GAME_SPEED); CASE_TO_STRING(TOOL_ZOOM_IN); CASE_TO_STRING(TOOL_ZOOM_OUT); CASE_TO_STRING(TOOL_SHOW_COVERAGE); CASE_TO_STRING(TOOL_SHOW_NAME); CASE_TO_STRING(TOOL_SHOW_GRID); CASE_TO_STRING(TOOL_SHOW_TREES); CASE_TO_STRING(TOOL_SHOW_HOUSES); CASE_TO_STRING(TOOL_SHOW_UNDERGROUND); CASE_TO_STRING(TOOL_ROTATE90); CASE_TO_STRING(TOOL_QUIT); CASE_TO_STRING(TOOL_FILL_TREES); CASE_TO_STRING(TOOL_DAYNIGHT_LEVEL); CASE_TO_STRING(TOOL_VEHICLE_TOOLTIPS); CASE_TO_STRING(TOOL_TOOGLE_PAX); CASE_TO_STRING(TOOL_TOOGLE_PEDESTRIANS); CASE_TO_STRING(TOOL_TRAFFIC_LEVEL); CASE_TO_STRING(TOOL_CHANGE_CONVOI); CASE_TO_STRING(TOOL_CHANGE_LINE); CASE_TO_STRING(TOOL_CHANGE_DEPOT); CASE_TO_STRING(TOOL_CHANGE_PLAYER); CASE_TO_STRING(TOOL_CHANGE_TRAFFIC_LIGHT); CASE_TO_STRING(TOOL_CHANGE_CITY); CASE_TO_STRING(TOOL_RENAME); CASE_TO_STRING(TOOL_TOGGLE_RESERVATION); CASE_TO_STRING(TOOL_VIEW_OWNER); CASE_TO_STRING(TOOL_HIDE_UNDER_CURSOR); CASE_TO_STRING(TOOL_MOVE_MAP); CASE_TO_STRING(TOOL_ROLLUP_ALL_WIN); CASE_TO_STRING(TOOL_RECOLOUR_TOOL); CASE_TO_STRING(TOOL_SHOW_FACTORY_STORAGE); CASE_TO_STRING(TOOL_TOGGLE_CONTROL); CASE_TO_STRING(TOOL_LOAD_SCENARIO); CASE_TO_STRING(TOOL_DAY_NIGHT_TOGGLE); CASE_TO_STRING(UNUSED_TOOL_ADD_MESSAGE); CASE_TO_STRING(UNUSED_WKZ_PWDHASH_TOOL); } } else if (id & DIALOGE_TOOL) { switch (id & ~DIALOGE_TOOL) { CASE_TO_STRING(DIALOG_HELP); CASE_TO_STRING(DIALOG_OPTIONS); CASE_TO_STRING(DIALOG_MINIMAP); CASE_TO_STRING(DIALOG_LINEOVERVIEW); CASE_TO_STRING(DIALOG_MESSAGES); CASE_TO_STRING(DIALOG_FINANCES); CASE_TO_STRING(DIALOG_PLAYERS); CASE_TO_STRING(DIALOG_DISPLAYOPTIONS); CASE_TO_STRING(DIALOG_SOUND); CASE_TO_STRING(DIALOG_LANGUAGE); CASE_TO_STRING(DIALOG_PLAYERCOLOR); CASE_TO_STRING(DIALOG_JUMP); CASE_TO_STRING(DIALOG_LOAD); CASE_TO_STRING(DIALOG_SAVE); CASE_TO_STRING(DIALOG_LIST_HALT); CASE_TO_STRING(DIALOG_LIST_CONVOI); CASE_TO_STRING(DIALOG_LIST_TOWN); CASE_TO_STRING(DIALOG_LIST_GOODS); CASE_TO_STRING(DIALOG_LIST_FACTORY); CASE_TO_STRING(DIALOG_LIST_CURIOSITY); CASE_TO_STRING(DIALOG_EDIT_FACTORY); CASE_TO_STRING(DIALOG_EDIT_ATTRACTION); CASE_TO_STRING(DIALOG_EDIT_HOUSE); CASE_TO_STRING(DIALOG_EDIT_TREE); CASE_TO_STRING(DIALOG_ENLARGE_MAP); CASE_TO_STRING(DIALOG_LIST_LABEL); CASE_TO_STRING(DIALOG_CLIMATES); CASE_TO_STRING(DIALOG_SETTINGS); CASE_TO_STRING(DIALOG_GAMEINFO); CASE_TO_STRING(DIALOG_THEMES); CASE_TO_STRING(DIALOG_SCENARIO); CASE_TO_STRING(DIALOG_SCENARIO_INFO); CASE_TO_STRING(DIALOG_LIST_DEPOT); CASE_TO_STRING(DIALOG_LIST_VEHICLE); CASE_TO_STRING(DIALOG_SCRIPT_TOOL); CASE_TO_STRING(DIALOG_EDIT_GROUNDOBJ); CASE_TO_STRING(DIALOG_CHAT); CASE_TO_STRING(DIALOG_PLAYER_RANKING); } } return ""; } // separator in toolbars class tool_dummy_t : public tool_t { public: tool_dummy_t() : tool_t(dummy_id) {} bool init(player_t*) OVERRIDE { return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; tool_t* tool_t::dummy = new tool_dummy_t(); tool_t* create_general_tool(int toolnr) { tool_t* tool = NULL; switch (toolnr) { case TOOL_QUERY: tool = new tool_query_t(); break; case TOOL_REMOVER: tool = new tool_remover_t(); break; case TOOL_RAISE_LAND: tool = new tool_raise_t(); break; case TOOL_LOWER_LAND: tool = new tool_lower_t(); break; case TOOL_SETSLOPE: tool = new tool_setslope_t(); break; case TOOL_RESTORESLOPE: tool = new tool_restoreslope_t(); break; case TOOL_MARKER: tool = new tool_marker_t(); break; case TOOL_CLEAR_RESERVATION: tool = new tool_clear_reservation_t(); break; case TOOL_TRANSFORMER: tool = new tool_transformer_t(); break; case TOOL_ADD_CITY: tool = new tool_add_city_t(); break; case TOOL_CHANGE_CITY_SIZE: tool = new tool_change_city_size_t(); break; case TOOL_PLANT_TREE: tool = new tool_plant_tree_t(); break; case TOOL_SCHEDULE_ADD: tool = new tool_schedule_add_t(); break; case TOOL_SCHEDULE_INS: tool = new tool_schedule_ins_t(); break; case TOOL_BUILD_WAY: tool = new tool_build_way_t(); break; case TOOL_BUILD_BRIDGE: tool = new tool_build_bridge_t(); break; case TOOL_BUILD_TUNNEL: tool = new tool_build_tunnel_t(); break; case TOOL_WAYREMOVER: tool = new tool_wayremover_t(); break; case TOOL_BUILD_WAYOBJ: tool = new tool_build_wayobj_t(); break; case TOOL_BUILD_STATION: tool = new tool_build_station_t(); break; case TOOL_BUILD_ROADSIGN: tool = new tool_build_roadsign_t(); break; case TOOL_BUILD_DEPOT: tool = new tool_build_depot_t(); break; case TOOL_BUILD_HOUSE: tool = new tool_build_house_t(); break; case TOOL_BUILD_LAND_CHAIN: tool = new tool_build_land_chain_t(); break; case TOOL_CITY_CHAIN: tool = new tool_city_chain_t(); break; case TOOL_BUILD_FACTORY: tool = new tool_build_factory_t(); break; case TOOL_LINK_FACTORY: tool = new tool_link_factory_t(); break; case TOOL_HEADQUARTER: tool = new tool_headquarter_t(); break; case TOOL_LOCK_GAME: tool = new tool_lock_game_t(); break; case TOOL_ADD_CITYCAR: tool = new tool_add_citycar_t(); break; case TOOL_FOREST: tool = new tool_forest_t(); break; case TOOL_STOP_MOVER: tool = new tool_stop_mover_t(); break; case TOOL_MAKE_STOP_PUBLIC: tool = new tool_make_stop_public_t(); break; case TOOL_REMOVE_WAYOBJ: tool = new tool_remove_wayobj_t(); break; case TOOL_SLICED_AND_UNDERGROUND_VIEW: tool = new tool_show_underground_t(); break; case TOOL_BUY_HOUSE: tool = new tool_buy_house_t(); break; case TOOL_BUILD_CITYROAD: tool = new tool_build_cityroad(); break; case TOOL_ERROR_MESSAGE: tool = new tool_error_message_t(); break; case TOOL_CHANGE_WATER_HEIGHT: tool = new tool_change_water_height_t(); break; case TOOL_SET_CLIMATE: tool = new tool_set_climate_t(); break; case TOOL_ROTATE_BUILDING: tool = new tool_rotate_building_t(); break; case TOOL_MERGE_STOP: tool = new tool_merge_stop_t(); break; case TOOL_EXEC_SCRIPT: tool = new tool_exec_script_t(); break; case TOOL_EXEC_TWO_CLICK_SCRIPT: tool = new tool_exec_two_click_script_t(); break; case TOOL_PLANT_GROUNDOBJ: tool = new tool_plant_groundobj_t(); break; case TOOL_ADD_MESSAGE: tool = new tool_add_message_t(); break; case TOOL_REMOVE_SIGNAL: tool = new tool_remove_signal_t(); break; case TOOL_GENERATE_SCRIPT: tool = new tool_generate_script_t(); break; case TOOL_PIPETTE: tool = new tool_pipette_t(); break; case TOOL_SET_OWNER: tool = new tool_change_owner_t(); break; default: dbg->error("create_general_tool()", "cannot satisfy request for general_tool[%i]!", toolnr); return NULL; } // check for right id (exception: TOOL_SLICED_AND_UNDERGROUND_VIEW) assert(tool->get_id() == (toolnr | GENERAL_TOOL) || toolnr == TOOL_SLICED_AND_UNDERGROUND_VIEW); return tool; } tool_t* create_simple_tool(int toolnr) { tool_t* tool = NULL; switch (toolnr) { case TOOL_PAUSE: tool = new tool_pause_t(); break; case TOOL_FASTFORWARD: tool = new tool_fastforward_t(); break; case TOOL_SCREENSHOT: tool = new tool_screenshot_t(); break; case TOOL_INCREASE_INDUSTRY: tool = new tool_increase_industry_t(); break; case TOOL_UNDO: tool = new tool_undo_t(); break; case TOOL_SWITCH_PLAYER: tool = new tool_switch_player_t(); break; case TOOL_STEP_YEAR: tool = new tool_step_year_t(); break; case TOOL_CHANGE_GAME_SPEED: tool = new tool_change_game_speed_t(); break; case TOOL_ZOOM_IN: tool = new tool_zoom_in_t(); break; case TOOL_ZOOM_OUT: tool = new tool_zoom_out_t(); break; case TOOL_SHOW_COVERAGE: tool = new tool_show_coverage_t(); break; case TOOL_SHOW_NAME: tool = new tool_show_name_t(); break; case TOOL_SHOW_GRID: tool = new tool_show_grid_t(); break; case TOOL_SHOW_TREES: tool = new tool_show_trees_t(); break; case TOOL_SHOW_HOUSES: tool = new tool_show_houses_t(); break; case TOOL_SHOW_UNDERGROUND: tool = new tool_show_underground_t(); break; case TOOL_ROTATE90: tool = new tool_rotate90_t(); break; case TOOL_QUIT: tool = new tool_quit_t(); break; case TOOL_FILL_TREES: tool = new tool_fill_trees_t(); break; case TOOL_DAYNIGHT_LEVEL: tool = new tool_daynight_level_t(); break; case TOOL_VEHICLE_TOOLTIPS: tool = new tool_vehicle_tooltips_t(); break; case TOOL_TOOGLE_PAX: tool = new tool_toggle_pax_station_t(); break; case TOOL_TOOGLE_PEDESTRIANS: tool = new tool_toggle_pedestrians_t(); break; case TOOL_TRAFFIC_LEVEL: tool = new tool_traffic_level_t(); break; case TOOL_CHANGE_CONVOI: tool = new tool_change_convoi_t(); break; case TOOL_CHANGE_LINE: tool = new tool_change_line_t(); break; case TOOL_CHANGE_DEPOT: tool = new tool_change_depot_t(); break; case TOOL_CHANGE_PLAYER: tool = new tool_change_player_t(); break; case TOOL_CHANGE_TRAFFIC_LIGHT: tool = new tool_change_traffic_light_t(); break; case TOOL_CHANGE_CITY: tool = new tool_change_city_t(); break; case TOOL_RENAME: tool = new tool_rename_t(); break; case TOOL_TOGGLE_RESERVATION: tool = new tool_toggle_reservation_t(); break; case TOOL_VIEW_OWNER: tool = new tool_view_owner_t(); break; case TOOL_HIDE_UNDER_CURSOR: tool = new tool_hide_under_cursor_t(); break; case TOOL_MOVE_MAP: tool = new tool_move_map_t(); break; case TOOL_ROLLUP_ALL_WIN: tool = new tool_rollup_all_win_t(); break; case TOOL_RECOLOUR_TOOL: tool = new tool_recolour_t(); break; case TOOL_SHOW_FACTORY_STORAGE: tool = new tool_show_factory_storage_t(); break; case TOOL_TOGGLE_CONTROL: tool = new tool_toggle_control_t(); break; case TOOL_LOAD_SCENARIO: tool = new tool_load_scenario_t(); break; case TOOL_DAY_NIGHT_TOGGLE: tool = new tool_day_night_toggle_t(); break; case UNUSED_TOOL_ADD_MESSAGE: // fall-through - intended!!!111elf case UNUSED_WKZ_PWDHASH_TOOL: dbg->warning("create_simple_tool()", "Deprecated tool [%i] requested", toolnr); return NULL; default: dbg->error("create_simple_tool()", "cannot satisfy request for simple_tool[%i]!", toolnr); return NULL; } assert(tool->get_id() == (toolnr | SIMPLE_TOOL)); return tool; } tool_t* create_dialog_tool(int toolnr) { tool_t* tool = NULL; switch (toolnr) { case DIALOG_HELP: tool = new dialog_help_t(); break; case DIALOG_OPTIONS: tool = new dialog_options_t(); break; case DIALOG_MINIMAP: tool = new dialog_minimap_t(); break; case DIALOG_LINEOVERVIEW: tool = new dialog_lines_t(); break; case DIALOG_MESSAGES: tool = new dialog_messages_t(); break; case DIALOG_FINANCES: tool = new dialog_finances_t(); break; case DIALOG_PLAYERS: tool = new dialog_players_t(); break; case DIALOG_DISPLAYOPTIONS: tool = new dialog_displayoptions_t(); break; case DIALOG_SOUND: tool = new dialog_sound_t(); break; case DIALOG_LANGUAGE: tool = new dialog_language_t(); break; case DIALOG_PLAYERCOLOR: tool = new dialog_playercolor_t(); break; case DIALOG_JUMP: tool = new dialog_jump_t(); break; case DIALOG_LOAD: tool = new dialog_load_t(); break; case DIALOG_SAVE: tool = new dialog_save_t(); break; case DIALOG_LIST_HALT: tool = new dialog_list_halt_t(); break; case DIALOG_LIST_CONVOI: tool = new dialog_list_convoi_t(); break; case DIALOG_LIST_TOWN: tool = new dialog_list_town_t(); break; case DIALOG_LIST_GOODS: tool = new dialog_list_goods_t(); break; case DIALOG_LIST_FACTORY: tool = new dialog_list_factory_t(); break; case DIALOG_LIST_CURIOSITY: tool = new dialog_list_curiosity_t(); break; case DIALOG_EDIT_FACTORY: tool = new dialog_edit_factory_t(); break; case DIALOG_EDIT_ATTRACTION: tool = new dialog_edit_attraction_t(); break; case DIALOG_EDIT_HOUSE: tool = new dialog_edit_house_t(); break; case DIALOG_EDIT_TREE: tool = new dialog_edit_tree_t(); break; case DIALOG_ENLARGE_MAP: tool = new dialog_enlarge_map_t(); break; case DIALOG_LIST_LABEL: tool = new dialog_list_label_t(); break; case DIALOG_CLIMATES: tool = new dialog_climates_t(); break; case DIALOG_SETTINGS: tool = new dialog_settings_t(); break; case DIALOG_GAMEINFO: tool = new dialog_gameinfo_t(); break; case DIALOG_THEMES: tool = new dialog_themes_t(); break; case DIALOG_SCENARIO: tool = new dialog_scenario_t(); break; case DIALOG_SCENARIO_INFO: tool = new dialog_scenario_info_t(); break; case DIALOG_LIST_DEPOT: tool = new dialog_list_depot_t(); break; case DIALOG_LIST_VEHICLE: tool = new dialog_list_vehicle_t(); break; case DIALOG_SCRIPT_TOOL: tool = new dialog_script_tool_t(); break; case DIALOG_EDIT_GROUNDOBJ: tool = new dialog_edit_groundobj_t(); break; case DIALOG_CHAT: tool = new dialog_chat_t(); break; case DIALOG_PLAYER_RANKING: tool = new dialog_player_ranking_t(); break; default: dbg->error("create_dialog_tool()", "cannot satisfy request for dialog_tool[%i]!", toolnr); return NULL; } assert(tool->get_id() == (toolnr | DIALOGE_TOOL)); return tool; } tool_t* create_tool(int toolnr) { tool_t* tool = NULL; if (toolnr & GENERAL_TOOL) { tool = create_general_tool(toolnr & 0xFFF); } else if (toolnr & SIMPLE_TOOL) { tool = create_simple_tool(toolnr & 0xFFF); } else if (toolnr & DIALOGE_TOOL) { tool = create_dialog_tool(toolnr & 0xFFF); } if (tool == NULL) { dbg->error("create_tool()", "cannot satisfy request for tool with id %i!", toolnr); } return tool; } /** * Returns desc and tool pointer corresponding to the * general toolid with name @p param_str. */ void general_tool_get_desc_builder(uint16 id, const char* param_str, const obj_desc_timelined_t*& desc, tool_t*& tool) { if (id & ((uint16)SIMPLE_TOOL | (uint16)DIALOGE_TOOL)) { return; } id = id & (~GENERAL_TOOL); const obj_desc_transport_infrastructure_t* desc1 = NULL; if (param_str) { switch (id) { case TOOL_BUILD_WAY: desc1 = way_builder_t::get_desc(param_str); break; case TOOL_BUILD_BRIDGE: desc1 = bridge_builder_t::get_desc(param_str); break; case TOOL_BUILD_TUNNEL: desc1 = tunnel_builder_t::get_desc(param_str); break; case TOOL_BUILD_ROADSIGN: desc1 = roadsign_t::find_desc(param_str); break; case TOOL_BUILD_WAYOBJ: desc1 = wayobj_t::find_desc(param_str); break; // The following 3's descriptions are registered by hausbauer_t. case TOOL_BUILD_DEPOT: case TOOL_BUILD_STATION: case TOOL_HEADQUARTER: { const building_desc_t* desc2 = hausbauer_t::get_desc(param_str); desc = desc2; tool = desc2 ? desc2->get_builder() : NULL; return; } default:; } } if (desc1) { desc = desc1; tool = desc1->get_builder(); } } /** * Set the defaults of a newly created general tool. */ void set_defaults_general_tool(tool_t* tool, const char* param_str) { if (tool == NULL) { return; } tool_t* copy_from = NULL; const obj_desc_timelined_t* desc = NULL; general_tool_get_desc_builder(tool->get_id(), param_str, desc, copy_from); if (copy_from) { *tool = *copy_from; } } /** * Checks whether a tool is available in the current timeline. * * Note that this function would return true on error. It is done so * if no description was found, the previous toolbar button logic * will still be applied - show buttons with icons regardless of * whether the objects they build are available or not. */ bool check_tool_availability(const tool_t* tool, uint16 time) { if (tool == NULL) { return true; } tool_t* dummy = NULL; const obj_desc_timelined_t* desc = NULL; general_tool_get_desc_builder(tool->get_id(), tool->get_default_param(), desc, dummy); return desc ? desc->is_available(time) : true; } static utf32 str_to_key(const char* str, uint8* modifier) { *modifier = 0; // default no modufier check if (str[1] == ',' || str[1] <= ' ') { return (uint8)*str; } else { // check for control char if (str[0] == '^') { if (str[1] == 0 || str[1] == '^') { return str[1]; } else { *modifier = 2; // only single character following =>make is 1..26 value if (isalpha(str[1])) { return tolower(str[1]) - 'a' + 1; } str++; } } // add shift as requested modifier? if (str[0] == '+') { if (str[1] == '+' || str[1] == 0) { return '+'; } *modifier = 1; str++; } // direct value (decimal) if (str[0] == '#') { return (str[1] == '#') ? str[1] : atoi(str + 1); } // check for utf8 if (127 < (uint8)*str) { size_t len = 0; utf32 const c = utf8_decoder_t::decode((utf8 const*)str, len); if (str[len] == ',') { return c; } } // Function key? if (str[0] == 'F') { uint8 function = atoi(str + 1); if (function > 0) { return SIM_KEY_F1 + function - 1; } } // COMMA if (strstart(str, "COMMA")) { return ','; } // Scroll lock if (strstart(str, "SCROLLLOCK")) { return SIM_KEY_SCROLLLOCK; } // break/pause key if (strstart(str, "PAUSE")) { return SIM_KEY_PAUSE; } // HOME if (strstart(str, "HOME")) { return SIM_KEY_HOME; } // END if (strstart(str, "END")) { return SIM_KEY_END; } // SPACE if (strstart(str, "SPACE")) { return SIM_KEY_SPACE; } // ENTER //if (strstart(str, "ENTER")) { // return SIM_KEY_ENTER //} // ESC if (strstart(str, "ESC")) { // but currently fixed binding! return SIM_KEY_ESCAPE; } if (strstart(str, "DELETE")) { // but currently fixed binding! return SIM_KEY_DELETE; } if (strstart(str, "BACKSPACE")) { // but currently fixed binding! return SIM_KEY_BACKSPACE; } // NUMPAD if (const char* c = strstart(str, "NUM_")) { return SIM_KEY_NUMPAD_BASE + atoi(c); } } // invalid key return 0xFFFF; } // just fills the default tables before other tools are added void tool_t::init_menu() { for (uint16 i = 0; i < GENERAL_TOOL_COUNT; i++) { tool_t* tool = create_general_tool(i); general_tool.append(tool); } for (uint16 i = 0; i < SIMPLE_TOOL_COUNT; i++) { // To squelch warning on startup if (i == UNUSED_TOOL_ADD_MESSAGE || i == UNUSED_WKZ_PWDHASH_TOOL) { simple_tool.append(NULL); continue; } tool_t* tool = create_simple_tool(i); simple_tool.append(tool); } for (uint16 i = 0; i < DIALOGE_TOOL_COUNT; i++) { tool_t* tool = create_dialog_tool(i); dialog_tool.append(tool); } } void tool_t::exit_menu() { clear_ptr_vector(general_tool); clear_ptr_vector(simple_tool); clear_ptr_vector(dialog_tool); } // for sorting: compare tool key static bool compare_tool(tool_t const* const a, tool_t const* const b) { uint16 const ac = a->command_key & ~32; uint16 const bc = b->command_key & ~32; return ac != bc ? ac < bc : a->command_key < b->command_key; } // read a tab file to add images, cursors and sound to the tools bool tool_t::read_menu(const std::string& menuconf_path) { char_to_tool.clear(); tabfile_t menuconf; // only use pak specific menus, since otherwise images may be missing if (!menuconf.open(menuconf_path.c_str())) { return false; } tabfileobj_t contents; menuconf.read(contents); // structure to hold information for iterating through different tool types struct tool_class_info_t { const char* type; uint16 count; vector_tpl& tools; const skin_desc_t* icons; const skin_desc_t* cursor; bool with_sound; }; tool_class_info_t info[] = { { "general_tool", GENERAL_TOOL_COUNT, general_tool, skinverwaltung_t::tool_icons_general, skinverwaltung_t::cursor_general, true }, { "simple_tool", SIMPLE_TOOL_COUNT, simple_tool, skinverwaltung_t::tool_icons_simple, NULL, false}, { "dialog_tool", DIALOGE_TOOL_COUNT, dialog_tool, skinverwaltung_t::tool_icons_dialoge, NULL, false } }; // first init all tools DBG_MESSAGE("tool_t::read_menu()", "Reading general menu"); for (uint16 t = 0; t < 3; t++) { for (uint16 i = 0; i < info[t].count; i++) { char id[256]; sprintf(id, "%s[%i]", info[t].type, i); const char* str = contents.get(id); /* Format of str: * for general tools: icon,cursor,sound,key * icon is image number in menu.GeneralTools, cursor image number in cursor.GeneralTools * for simple and dialog tools: icon,key * icon is image number in menu.SimpleTools and menu.DialogeTools * -1 will disable any of them */ tool_t* tool = info[t].tools[i]; if (!tool) { if (str && strcmp(str, "") != 0) { // this key is present in the tab file dbg->warning("tool_t::read_menu", "Ignoring deprecated %s[%i] (%s)", info[t].type, i, tool_t::id_to_string((1 << (t + 12)) | i)); } continue; } while (*str == ' ') { str++; } if (*str && *str != ',') { // ok, first comes icon uint16 icon = (uint16)atoi(str); if (icon == 0 && *str != '0') { // check, if file name ... int i = 0; while (str[i] != 0 && str[i] != ',') { i++; } const skin_desc_t* s = skinverwaltung_t::get_extra(str, i - 1); tool->icon = s ? s->get_image_id(0) : IMG_EMPTY; } else { if (icon >= info[t].icons->get_count()) { dbg->warning("tool_t::init_menu()", "wrong icon (%i) given for %s[%i]", icon, info[t].type, i); } tool->icon = info[t].icons->get_image_id(icon); } do { str++; } while (*str && *str != ','); } if (info[t].cursor) { if (*str == ',') { // next comes cursor str++; if (*str && *str != ',') { uint16 cursor = (uint16)atoi(str); if (cursor >= info[t].cursor->get_count()) { dbg->warning("tool_t::init_menu()", "wrong cursor (%i) given for %s[%i]", cursor, info[t].type, i); } tool->cursor = info[t].cursor->get_image_id(cursor); do { str++; } while (*str && *str != ','); } } } if (info[t].with_sound) { if (*str == ',') { // ok_sound str++; if (*str && *str != ',') { int sound = atoi(str); if (sound > 0) { tool->ok_sound = sound_desc_t::get_compatible_sound_id(sound); } do { str++; } while (*str && *str != ','); } } } if (*str == ',') { // key str++; while (*str == ' ') { str++; } if (*str >= ' ') { tool->command_key = str_to_key(str, &tool->command_flags); char_to_tool.append(tool); } } } } // now the toolbar tools DBG_MESSAGE("tool_t::read_menu()", "Reading toolbars"); toolbar_last_used_t::last_used_tools = new toolbar_last_used_t(TOOL_LAST_USED | TOOLBAR_TOOL, "Last used tools", "last_used.txt"); // first: add main menu toolbar_tool.reserve(skinverwaltung_t::tool_icons_toolbars->get_count()); toolbar_tool.append(new toolbar_t(TOOLBAR_TOOL, "", "")); for (uint16 i = 0; i < toolbar_tool.get_count(); i++) { char id[256]; for (int j = 0; ; j++) { /* str should now contain something like 1,2,-1 * first parameter is the image number in "GeneralTools" * next is the cursor in "GeneralTools" * final is the sound * -1 will disable any of them */ sprintf(id, "toolbar[%i][%i]", i, j); const char* str = contents.get(id); if (*str == 0) { // empty entry => toolbar finished ... break; } tool_t* addtool = NULL; /* first, parse the string; we could have up to four parameters */ const char* toolname = str; image_id icon = IMG_EMPTY; const char* key_str = NULL; const char* param_str = NULL; // in case of toolbars, it will also contain the tooltip // parse until next zero-level comma uint level = 0; while (*str) { if (*str == ')') { level++; } else if (*str == '(') { level--; } else if (*str == ',' && level == 0) { break; } str++; } // icon if (*str == ',') { str++; if (*str != ',') { // ok, first come icon while (*str == ' ') { str++; } icon = (uint16)atoi(str); if (icon == 0 && *str != '0') { // check, if file name ... int i = 0; while (str[i] != 0 && str[i] != ',') { i++; } const skin_desc_t* s = skinverwaltung_t::get_extra(str, i - 1); icon = s ? s->get_image_id(0) : IMG_EMPTY; } else { if (icon >= skinverwaltung_t::tool_icons_toolbars->get_count()) { dbg->warning("tool_t::read_menu()", "wrong icon (%i) given for toolbar_tool[%i][%i]", icon, i, j); icon = 0; } icon = skinverwaltung_t::tool_icons_toolbars->get_image_id(icon); } while (*str && *str != ',') { str++; } } } // key if (*str == ',') { str++; while (*str == ' ' && *str) { str++; } if (*str != ',' && *str) { key_str = str; } while (*str != ',' && *str) { str++; } } // parameter if (*str == ',') { str++; if (*str >= ' ') { param_str = str; } } bool create_tool = icon != IMG_EMPTY || key_str || param_str; if (char const* const c = strstart(toolname, "general_tool[")) { uint8 toolnr = atoi(c); if (toolnr < GENERAL_TOOL_COUNT) { if (create_tool) { // compatibility mode: tool_cityroad is used for tool_wegebau with defaultparam 'cityroad' if (toolnr == TOOL_BUILD_WAY && param_str && strcmp(param_str, "city_road") == 0) { toolnr = TOOL_BUILD_CITYROAD; dbg->warning("tool_t::read_menu()", "toolbar[%i][%i]: replaced way-builder(id=14) with default param=cityroad by cityroad builder(id=36)", i, j); } // now create tool addtool = create_general_tool(toolnr); // copy defaults *addtool = *(general_tool[toolnr]); set_defaults_general_tool(addtool, param_str); general_tool.append(addtool); } else { addtool = general_tool[toolnr]; } } else { dbg->warning("tool_t::read_menu()", "When parsing menuconf.tab: General tool id is not valid (%hhu >= %i). Tool ignored.", toolnr, (int)GENERAL_TOOL_COUNT); } } else if (char const* const c = strstart(toolname, "simple_tool[")) { uint8 const toolnr = atoi(c); if (toolnr < SIMPLE_TOOL_COUNT) { if (create_tool) { addtool = create_simple_tool(toolnr); *addtool = *(simple_tool[toolnr]); simple_tool.append(addtool); } else { addtool = simple_tool[toolnr]; } } else { dbg->warning("tool_t::read_menu()", "When parsing menuconf.tab: Simple tool id is not valid (%hhu >= %i). Tool ignored.", toolnr, (int)SIMPLE_TOOL_COUNT); } } else if (char const* const c = strstart(toolname, "dialog_tool[")) { uint8 const toolnr = atoi(c); if (toolnr < DIALOGE_TOOL_COUNT) { if (create_tool) { addtool = create_dialog_tool(toolnr); *addtool = *(dialog_tool[toolnr]); dialog_tool.append(addtool); } else { addtool = dialog_tool[toolnr]; } } else { dbg->warning("tool_t::read_menu()", "When parsing menuconf.tab: Dialog tool id is not valid (%hhu >= %i). Tool ignored.", toolnr, (int)DIALOGE_TOOL_COUNT); } } else if (char const* const c = strstart(toolname, "toolbar[")) { uint8 const toolnr = atoi(c); if (toolnr == 0) { if (strstr(c, "LAST_USED")) { toolbar_last_used_t::last_used_tools->icon = icon; addtool = toolbar_last_used_t::last_used_tools; } else { dbg->error("Error in menuconf: toolbar cannot call main toolbar", "%s", toolname); return false; } } if (toolbar_tool.get_count() == toolnr) { if (param_str == NULL) { param_str = "Unnamed toolbar"; dbg->warning("tool_t::read_menu()", "Missing title for toolbar[%hhu]", toolnr); } char* c = strdup(param_str); const char* title = c; c += strcspn(c, ","); if (*c != '\0') { *c++ = '\0'; } toolbar_t* const tb = new toolbar_t(toolbar_tool.get_count() | TOOLBAR_TOOL, title, c); toolbar_tool.append(tb); addtool = tb; } } else { // make a default tool to add the parameter here addtool = new tool_dummy_t(); addtool->default_param = strdup(toolname); addtool->command_key = 1; } if (addtool) { if (icon != IMG_EMPTY) { addtool->icon = icon; } if (key_str != NULL) { addtool->command_key = str_to_key(key_str, &(addtool->command_flags)); char_to_tool.append(addtool); } if (param_str != NULL && ((addtool->get_id() & TOOLBAR_TOOL) == 0)) { addtool->default_param = strdup(param_str); } toolbar_tool[i]->append(addtool); } } } toolbar_tool.append(toolbar_last_used_t::last_used_tools); // sort characters std::sort(char_to_tool.begin(), char_to_tool.end(), compare_tool); return true; } void tool_t::update_toolbars() { // renew toolbar // iterate twice, to get correct icons if a toolbar changes between empty and non-empty for (uint j = 0; j < 2; j++) { bool change = false; for (toolbar_t* const i : toolbar_tool) { bool old_icon_empty = i->get_icon(welt->get_active_player()) == IMG_EMPTY; i->update(welt->get_active_player()); change |= old_icon_empty ^ (i->get_icon(welt->get_active_player()) == IMG_EMPTY); } if (!change) { // no toolbar changes between empty and non-empty, no need to loop again break; } } } void tool_t::draw_after(scr_coord pos, bool dirty) const { // default action: grey corner if selected image_id id = get_icon(welt->get_active_player()); if (id != IMG_EMPTY && is_selected()) { display_img_blend(id, pos.x, pos.y, TRANSPARENT50_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK), false, dirty); } } bool tool_t::is_selected() const { return welt->get_tool(welt->get_active_player_nr()) == this; } const char* tool_t::check_pos(player_t*, koord3d pos) { grund_t* gr = welt->lookup(pos); return (gr && !gr->is_visible()) ? "" : NULL; } bool tool_t::check_valid_pos(koord k) const { if (is_grid_tool()) { return welt->is_within_grid_limits(k); } return welt->is_within_limits(k); }; /** * Initializes cursor object: image, y-offset, size of marked area, * has to be called after init(). * @param zeiger cursor object */ void tool_t::init_cursor(zeiger_t* zeiger) const { zeiger->set_image(cursor); zeiger->set_yoff(offset); zeiger->set_area(cursor_area, cursor_centered, cursor_offset); } const char* kartenboden_tool_t::check_pos(player_t*, koord3d pos) { grund_t* gr = welt->lookup_kartenboden(pos.get_2d()); return (gr && !gr->is_visible()) ? "" : NULL; } image_id toolbar_t::get_icon(player_t* player) const { // no image for edit tools => do not open if (icon == IMG_EMPTY || (player != NULL && strcmp(default_param, "EDITTOOLS") == 0 && player->get_player_nr() != PLAYER_PUBLIC_NR)) { return IMG_EMPTY; } // now have we a least one visible tool? if (tool_selector && !tool_selector->empty(player)) { return icon; } return IMG_EMPTY; } // simply true, if visible bool toolbar_t::is_selected() const { return win_get_magic(magic_toolbar + toolbar_tool.index_of(const_cast(this))); } // just returns sound info after bracket static sint16 get_sound(const char* c) { while (*c && *c != ')') { c++; } while (*c && *c != ',') { c++; } return (*c ? atoi(c + 1) - 2 : NO_SOUND); } // fills and displays a toolbar void toolbar_t::update(player_t* player) { const bool create = (tool_selector == NULL); if (create) { DBG_MESSAGE("toolbar_t::update()", "create toolbar %s", default_param); tool_selector = new tool_selector_t(default_param, helpfile, toolbar_tool.index_of(this), this != tool_t::toolbar_tool[0]); } else { DBG_MESSAGE("toolbar_t::update()", "update toolbar %s", default_param); } tool_selector->reset_tools(); // now (re)fill it for (tool_t* const w : tools) { // no way to call this tool? => then it is most likely a metatool if (w->command_key == 1 && w->get_icon(player) == IMG_EMPTY) { if (char const* const param = w->get_default_param()) { if (create) { DBG_DEBUG("toolbar_t::update()", "add metatool (param=%s)", param); } if (char const* c = strstart(param, "ways(")) { waytype_t way = (waytype_t)atoi(c); while (*c && *c != ',' && *c != ')') { c++; } systemtype_t subtype = (systemtype_t)(*c != 0 ? atoi(++c) : 0); way_builder_t::fill_menu(tool_selector, way, subtype, get_sound(c)); } else if (char const* const c = strstart(param, "bridges(")) { waytype_t const way = (waytype_t)atoi(c); bridge_builder_t::fill_menu(tool_selector, way, get_sound(c)); } else if (char const* const c = strstart(param, "tunnels(")) { waytype_t const way = (waytype_t)atoi(c); tunnel_builder_t::fill_menu(tool_selector, way, get_sound(c)); } else if (char const* const c = strstart(param, "signs(")) { waytype_t const way = (waytype_t)atoi(c); roadsign_t::fill_menu(tool_selector, way, get_sound(c)); } else if (char const* const c = strstart(param, "wayobjs(")) { waytype_t const way = (waytype_t)atoi(c); wayobj_t::fill_menu(tool_selector, way, get_sound(c)); } else if (char const* c = strstart(param, "buildings(")) { building_desc_t::btype const utype = (building_desc_t::btype)atoi(c); while (*c && *c != ',' && *c != ')') { c++; } waytype_t way = (waytype_t)(*c != 0 ? atoi(++c) : 0); hausbauer_t::fill_menu(tool_selector, utype, way, get_sound(c)); } else if (char const* const c = strstart(param, "scripts(")) { const char* end = strchr(c, '\0'); char buf[1000]; size_t len = end ? min(lengthof(buf) - 1, end - c) : lengthof(buf) - 1; tstrncpy(buf, c, len); script_tool_manager_t::fill_menu(tool_selector, buf, get_sound(c)); } else if (param[0] == '-') { // add dummy tool_t as seperator tool_selector->add_tool_selector(dummy); } } } else if (w->get_icon(player) != IMG_EMPTY) { // get the right city_road if (w->get_id() == (TOOL_BUILD_CITYROAD | GENERAL_TOOL)) { w->flags = 0; w->init(player); } if (create) { DBG_DEBUG("toolbar_t::update()", "add tool %i (param=%s)", w->get_id(), w->get_default_param()); } scenario_t* scen = welt->get_scenario(); if (scen->is_scripted() && !scen->is_tool_allowed(player, w->get_id(), w->get_waytype(), w->get_default_param())) { continue; } if (!check_tool_availability(w, welt->get_timeline_year_month())) { continue; } w->enabled = welt->get_scenario()->is_tool_enabled(welt->get_active_player(), w->get_id(), w->get_waytype(), w->get_default_param()); // now add it to the toolbar gui tool_selector->add_tool_selector(w); } } if ((strcmp(this->default_param, "EDITTOOLS") == 0 && player != welt->get_public_player())) { destroy_win(tool_selector); return; } } // fills and displays a toolbar bool toolbar_t::init(player_t* player) { update(player); bool close = (strcmp(this->default_param, "EDITTOOLS") == 0 && player != welt->get_public_player()); // show/create window if (close) { destroy_win(tool_selector); return false; } if (this != tool_t::toolbar_tool[0]) { if (env_t::single_toolbar_mode) { for (uint16 i = 1; i < toolbar_tool.get_count(); i++) { if (this != toolbar_tool[i]) { // make sure only one tool is visibile destroy_win(magic_toolbar + i); } } // open toolbar centered at top or bottom position (bottom, when menubar at bottom) scr_coord_val w = display_get_width() - (env_t::menupos == MENU_LEFT ? env_t::iconsize.w : 0) - (env_t::menupos == MENU_RIGHT ? env_t::iconsize.w : 0); scr_coord_val x = (w - tool_selector->get_windowsize().w) / 2 + (env_t::menupos == MENU_LEFT ? env_t::iconsize.w : 0); scr_coord_val y = (env_t::menupos == MENU_BOTTOM ? display_get_height() - tool_selector->get_windowsize().h - env_t::iconsize.h : 0); create_win({ x, y }, tool_selector, w_do_not_delete, magic_toolbar + toolbar_tool.index_of(this)); } else { // not main menu => open random create_win(tool_selector, w_info | w_do_not_delete | w_no_overlap, magic_toolbar + toolbar_tool.index_of(this)); } DBG_MESSAGE("toolbar_t::init()", "ID=%id", get_id()); } return false; } bool toolbar_t::exit(player_t*) { if (win_get_magic(magic_toolbar + toolbar_tool.index_of(this))) { destroy_win(tool_selector); } return false; } // from here on last used toolbar tools (for each player!) void toolbar_last_used_t::update(player_t* sp) { tools.clear(); if (sp) { for (slist_tpl::iterator iter = all_tools[sp->get_player_nr()].begin(); iter != all_tools[sp->get_player_nr()].end(); ++iter) { tools.append(*iter); } } toolbar_t::update(sp); } void toolbar_last_used_t::clear() { for (int i = 0; i < MAX_PLAYER_COUNT; i++) { all_tools[i].clear(); } tools.clear(); } // currently only needed for last used tools void toolbar_last_used_t::append(tool_t* t, player_t* sp) { static int exclude_from_adding[8] = { TOOL_SCHEDULE_ADD | GENERAL_TOOL, TOOL_SCHEDULE_INS | GENERAL_TOOL, TOOL_CHANGE_CONVOI | SIMPLE_TOOL, TOOL_CHANGE_LINE | SIMPLE_TOOL, TOOL_CHANGE_DEPOT | SIMPLE_TOOL, UNUSED_WKZ_PWDHASH_TOOL | SIMPLE_TOOL, TOOL_CHANGE_PLAYER | SIMPLE_TOOL, TOOL_RENAME | SIMPLE_TOOL }; if (!sp || t->get_icon(sp) == IMG_EMPTY) { return; } // do not add certain tools for (uint i = 0; i < lengthof(exclude_from_adding); i++) { if (t->get_id() == exclude_from_adding[i]) { return; } } slist_tpl& players_tools = all_tools[sp->get_player_nr()]; if (players_tools.is_contained(t)) { players_tools.remove(t); } else { while (players_tools.get_count() >= MAX_LAST_TOOLS) { players_tools.remove(players_tools.back()); } } players_tools.insert(t); // if current => update if (sp == world()->get_active_player()) { update(sp); } } bool two_click_tool_t::init(player_t*) { first_click_var = true; start = koord3d::invalid; if (is_local_execution()) { welt->show_distance = koord3d::invalid; } cleanup(true); return true; } void two_click_tool_t::rdwr_custom_data(memory_rw_t* packet) { packet->rdwr_bool(first_click_var); sint16 posx = start.x; packet->rdwr_short(posx); start.x = posx; sint16 posy = start.y; packet->rdwr_short(posy); start.y = posy; sint8 posz = start.z; packet->rdwr_byte(posz); start.z = posz; } bool two_click_tool_t::is_first_click() const { return first_click_var; } bool two_click_tool_t::is_work_here_keeps_game_state(player_t* player, koord3d pos) { if (!is_first_click()) { return false; } const char* error = ""; //default: nosound uint8 value = is_valid_pos(player, pos, error, koord3d::invalid); DBG_MESSAGE("two_click_tool_t::is_work_here_keeps_game_state", "Position %s valid=%d", pos.get_str(), value); if (value == 0) { // cannot work here at all -> safe return true; } // work directly if possible and ctrl is NOT pressed if ((value & 1) && !((value & 2) && is_ctrl_pressed())) { // would work here directly. return false; } else { // set starting position only return true; } } const char* two_click_tool_t::work(player_t* player, koord3d pos) { if (!is_first_click() && start_marker) { start = start_marker->get_pos(); // if map was rotated. } // remove marker cleanup(true); const char* error = NULL; uint8 value = is_valid_pos(player, pos, error, !is_first_click() ? start : koord3d::invalid); DBG_MESSAGE("two_click_tool_t::work", "Position %s valid=%d", pos.get_str(), value); if (value == 0) { if (error == NULL) { error = ""; // propagate errors } flags &= ~(WFL_SHIFT | WFL_CTRL); init(player); return error; } if (is_first_click()) { // work directly if possible and ctrl is NOT pressed if ((value & 1) && !((value & 2) && is_ctrl_pressed())) { // Work here directly. DBG_MESSAGE("two_click_tool_t::work", "Call tool at %s", pos.get_str()); error = do_work(player, pos, koord3d::invalid); } else { // set starting position. DBG_MESSAGE("two_click_tool_t::work", "Setting start to %s", pos.get_str()); start_at(pos); error = NULL; } } else { if (value & 2) { DBG_MESSAGE("two_click_tool_t::work", "Setting end to %s", pos.get_str()); error = do_work(player, start, pos); } flags &= ~(WFL_SHIFT | WFL_CTRL); init(player); // Do the cleanup stuff after(!) do_work (otherwise start==koord3d::invalid). } return error; } const char* two_click_tool_t::move(player_t* player, uint16 buttonstate, koord3d pos) { DBG_MESSAGE("two_click_tool_t::move", "Button: %d, Pos: %s", buttonstate, pos.get_str()); if (buttonstate == 0) { return ""; } if (start == pos) { init(player); } const char* error = NULL; if (start == koord3d::invalid) { // start dragging. cleanup(true); uint8 value = is_valid_pos(player, pos, error, koord3d::invalid); if (error || value == 0) { return error; } if (value & 2) { start_at(pos); } } else { // continue dragging. cleanup(false); if (start_marker) { start = start_marker->get_pos(); // if map was rotated. } uint8 value = is_valid_pos(player, pos, error, start); if (error || value == 0) { return error; } if (value & 2) { display_show_load_pointer(true); mark_tiles(player, start, pos); display_show_load_pointer(false); } } return ""; } void two_click_tool_t::start_at(koord3d& new_start) { first_click_var = false; start = new_start; if (is_local_execution()) { welt->show_distance = new_start; start_marker = new zeiger_t(start, NULL); start_marker->set_image(get_marker_image()); grund_t* gr = welt->lookup(start); if (gr) { gr->obj_add(start_marker); } } DBG_MESSAGE("two_click_tool_t::start_at", "Setting start to %s", start.get_str()); } void two_click_tool_t::cleanup(bool delete_start_marker) { // delete marker. if (start_marker != NULL && delete_start_marker) { start_marker->mark_image_dirty(start_marker->get_image(), 0); delete start_marker; start_marker = NULL; } // delete old route. while (!marked.empty()) { zeiger_t* z = marked.remove_first(); z->mark_image_dirty(z->get_image(), 0); z->mark_image_dirty(z->get_front_image(), 0); koord3d pos = z->get_pos(); grund_t* gr = welt->lookup(pos); delete z; // Remove dummy ground (placed by tool_build_tunnel_t and tool_build_way_t): if (gr && gr->is_dummy_ground()) { welt->access(pos.get_2d())->boden_entfernen(gr); delete gr; assert(!welt->lookup(pos)); } } // delete tooltip. win_set_static_tooltip(NULL); } image_id two_click_tool_t::get_marker_image() const { return skinverwaltung_t::bauigelsymbol->get_image_id(0); } simutrans-124.3/src/simutrans/tool/simmenu.h000066400000000000000000000320061474050137200211730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TOOL_SIMMENU_H #define TOOL_SIMMENU_H #include #include "../descriptor/sound_desc.h" #include "../dataobj/koord3d.h" #include "../dataobj/translator.h" #include "../simtypes.h" #include "../display/simimg.h" /// New configurable OOP tool system template class vector_tpl; template class slist_tpl; class scr_coord; class tool_selector_t; class player_t; class toolbar_t; class memory_rw_t; class karte_ptr_t; class zeiger_t; enum { // general tools TOOL_QUERY=0, TOOL_REMOVER, TOOL_RAISE_LAND, TOOL_LOWER_LAND, TOOL_SETSLOPE, TOOL_RESTORESLOPE, TOOL_MARKER, TOOL_CLEAR_RESERVATION, TOOL_TRANSFORMER, TOOL_ADD_CITY, TOOL_CHANGE_CITY_SIZE, TOOL_PLANT_TREE, TOOL_SCHEDULE_ADD, TOOL_SCHEDULE_INS, TOOL_BUILD_WAY, TOOL_BUILD_BRIDGE, TOOL_BUILD_TUNNEL, TOOL_WAYREMOVER, TOOL_BUILD_WAYOBJ, TOOL_BUILD_STATION, TOOL_BUILD_ROADSIGN, TOOL_BUILD_DEPOT, TOOL_BUILD_HOUSE, TOOL_BUILD_LAND_CHAIN, TOOL_CITY_CHAIN, TOOL_BUILD_FACTORY, TOOL_LINK_FACTORY, TOOL_HEADQUARTER, TOOL_LOCK_GAME, TOOL_ADD_CITYCAR, TOOL_FOREST, TOOL_STOP_MOVER, TOOL_MAKE_STOP_PUBLIC, TOOL_REMOVE_WAYOBJ, TOOL_SLICED_AND_UNDERGROUND_VIEW, TOOL_BUY_HOUSE, TOOL_BUILD_CITYROAD, TOOL_ERROR_MESSAGE, TOOL_CHANGE_WATER_HEIGHT, TOOL_SET_CLIMATE, TOOL_ROTATE_BUILDING, TOOL_MERGE_STOP, TOOL_EXEC_SCRIPT, TOOL_EXEC_TWO_CLICK_SCRIPT, TOOL_PLANT_GROUNDOBJ, TOOL_ADD_MESSAGE, TOOL_REMOVE_SIGNAL, TOOL_GENERATE_SCRIPT, TOOL_PIPETTE, TOOL_SET_OWNER, GENERAL_TOOL_COUNT, GENERAL_TOOL = 0x1000 }; enum { // simple one click tools TOOL_PAUSE = 0, TOOL_FASTFORWARD, TOOL_SCREENSHOT, TOOL_INCREASE_INDUSTRY, TOOL_UNDO, TOOL_SWITCH_PLAYER, TOOL_STEP_YEAR, TOOL_CHANGE_GAME_SPEED, TOOL_ZOOM_IN, TOOL_ZOOM_OUT, TOOL_SHOW_COVERAGE, TOOL_SHOW_NAME, TOOL_SHOW_GRID, TOOL_SHOW_TREES, TOOL_SHOW_HOUSES, TOOL_SHOW_UNDERGROUND, TOOL_ROTATE90, TOOL_QUIT, TOOL_FILL_TREES, TOOL_DAYNIGHT_LEVEL, TOOL_VEHICLE_TOOLTIPS, TOOL_TOOGLE_PAX, TOOL_TOOGLE_PEDESTRIANS, TOOL_TRAFFIC_LEVEL, TOOL_CHANGE_CONVOI, TOOL_CHANGE_LINE, TOOL_CHANGE_DEPOT, UNUSED_WKZ_PWDHASH_TOOL, TOOL_CHANGE_PLAYER, TOOL_CHANGE_TRAFFIC_LIGHT, TOOL_CHANGE_CITY, TOOL_RENAME, UNUSED_TOOL_ADD_MESSAGE, TOOL_TOGGLE_RESERVATION, TOOL_VIEW_OWNER, TOOL_HIDE_UNDER_CURSOR, TOOL_MOVE_MAP, TOOL_ROLLUP_ALL_WIN, TOOL_RECOLOUR_TOOL, TOOL_SHOW_FACTORY_STORAGE, TOOL_TOGGLE_CONTROL, TOOL_LOAD_SCENARIO, TOOL_DAY_NIGHT_TOGGLE, SIMPLE_TOOL_COUNT, SIMPLE_TOOL = 0x2000 }; enum { // dialogue tools DIALOG_HELP = 0, DIALOG_OPTIONS, DIALOG_MINIMAP, DIALOG_LINEOVERVIEW, DIALOG_MESSAGES, DIALOG_FINANCES, DIALOG_PLAYERS, DIALOG_DISPLAYOPTIONS, DIALOG_SOUND, DIALOG_LANGUAGE, DIALOG_PLAYERCOLOR, DIALOG_JUMP, DIALOG_LOAD, DIALOG_SAVE, DIALOG_LIST_HALT, DIALOG_LIST_CONVOI, DIALOG_LIST_TOWN, DIALOG_LIST_GOODS, DIALOG_LIST_FACTORY, DIALOG_LIST_CURIOSITY, DIALOG_EDIT_FACTORY, DIALOG_EDIT_ATTRACTION, DIALOG_EDIT_HOUSE, DIALOG_EDIT_TREE, DIALOG_ENLARGE_MAP, DIALOG_LIST_LABEL, DIALOG_CLIMATES, DIALOG_SETTINGS, DIALOG_GAMEINFO, DIALOG_THEMES, DIALOG_SCENARIO, DIALOG_SCENARIO_INFO, DIALOG_LIST_DEPOT, DIALOG_LIST_VEHICLE, DIALOG_SCRIPT_TOOL, DIALOG_EDIT_GROUNDOBJ, DIALOG_CHAT, DIALOG_PLAYER_RANKING, DIALOGE_TOOL_COUNT, DIALOGE_TOOL = 0x4000 }; enum { // toolbars TOOL_MAINMENU = 0, TOOL_LAST_USED = 1022, TOOLBAR_TOOL = 0x8000u }; class tool_t { protected: image_id icon; private: /* value to trigger this command (see documentation) */ uint16 id; protected: static karte_ptr_t welt; const char *default_param; public: uint16 get_id() const { return id; } const char *get_name() const { return id_to_string(id); } static const char *id_to_string(uint16 id); static tool_t *dummy; // for key lookup static vector_tplchar_to_tool; // true, if the control key should be inverted static uint8 control_invert; /// disabled icons are greyed out bool enabled; /// cursor centered at marked area? default: false bool cursor_centered; /// cursor image image_id cursor; /// cursor marks this area koord cursor_area; /// cursor offset within marked area (only effective if cursor_centered != false) koord cursor_offset; /// z-offset of cursor, possible values: Z_PLAN and Z_GRID sint8 offset; sint16 ok_sound; /// a script is waiting for a call-back uint32 callback_id; enum { WFL_SHIFT = 1 << 0, ///< shift-key was pressed when mouse-click happened WFL_CTRL = 1 << 1, ///< ctrl-key was pressed when mouse-click happened WFL_LOCAL = 1 << 2, ///< tool call was issued by local client (and will not be sent to server) WFL_SCRIPT = 1 << 3, ///< tool call was issued by script WFL_NO_CHK = 1 << 4 ///< tool call needs no password or scenario checks }; uint8 flags; // flags are set before init/work/move is called bool is_ctrl_pressed() const { return flags & WFL_CTRL; } bool is_shift_pressed() const { return flags & WFL_SHIFT; } bool is_local_execution() const { return flags & WFL_LOCAL; } bool is_scripted() const { return flags & WFL_SCRIPT; } bool no_check() const { return flags & WFL_NO_CHK; } bool can_use_gui() const { return is_local_execution() && !is_scripted(); } uint8 command_flags; // only shift and control uint16 command_key;// key to toggle action for this function static vector_tpl general_tool; static vector_tpl simple_tool; static vector_tpl dialog_tool; static vector_tpl toolbar_tool; static void update_toolbars(); // since only a single toolstr a time can be visible ... static char toolstr[1024]; static void init_menu(); static void exit_menu(); /// Read tool, toolbar configuration and tool shortcuts from @p menuconf /// @param menuconf Path to file to read static bool read_menu(const std::string &menuconf); static uint16 const dummy_id = 0xFFFFU; tool_t(uint16 const id) : id(id), cursor_area(1,1) { cursor = icon = IMG_EMPTY; ok_sound = NO_SOUND; offset = Z_PLAN; default_param = NULL; command_key = 0; cursor_centered = false; enabled = true; flags = 0; callback_id = 0; } virtual ~tool_t() {} virtual image_id get_icon(player_t *) const { return icon; } void set_icon(image_id i) { icon = i; } // returns default_param of this tool for player // if player==NULL returns default_param that was used to create the tool virtual const char* get_default_param(player_t* = NULL) const { return default_param; } void set_default_param(const char* str) { default_param = str; } // transfer additional information in networkgames virtual void rdwr_custom_data(memory_rw_t*) { } // this will draw the tool with some indication, if active virtual bool is_selected() const; // when true, local execution would do no harm virtual bool is_init_keeps_game_state() const { return false; } // if is_work_keeps_game_state()==false // and is_work_here_keeps_game_state(...)==false // then work-command is sent over network or must execute outside a sync_step virtual bool is_work_keeps_game_state() const { return false; } virtual bool is_work_here_keeps_game_state(player_t *, koord3d) { return false; } // will draw a dark frame, if selected virtual void draw_after(scr_coord pos, bool dirty) const; virtual const char *get_tooltip(const player_t *) const { return NULL; } /** * @return true if this tool operates over the grid, not the map tiles. */ virtual bool is_grid_tool() const {return false;} /** * Returning false on init will automatically invoke previous tool. * Returning true will select tool and will make it possible to call work. */ virtual bool init( player_t * ) { return true; } /// initializes cursor (icon, marked area) void init_cursor( zeiger_t * ) const; // returning true on exit will have tool_selector resets to query-tool on right-click virtual bool exit( player_t * ) { return true; } /* the return string can have different meanings: * NULL: ok * "": unspecified error * "blabla": errors message, will be handled and translated as appropriate * check: called before work (and move too?) koord3d already valid coordinate, checks visibility * work / move should depend on undergroundmode for not network safe tools */ virtual const char *check_pos( player_t *, koord3d ); virtual const char *work( player_t *, koord3d ) { return NULL; } virtual const char *move( player_t *, uint16 /* buttonstate */, koord3d ) { return ""; } /** * Should be overloaded if derived class implements move, * move will only be called, if this function returns true. */ virtual bool move_has_effects() const { return false;} /** * Returns whether the 2d koordinate passed it's a valid position for this tool to highlight a tile, * just takes into account is_grid_tool. It does not check if work is allowed there, that's check_pos() work. * @see check_pos * @return true is the coordinate it's found valid, false otherwise. */ bool check_valid_pos( koord k ) const; /** * Specifies if the cursor will need a position update after this tool takes effect (ie: changed the height of the tile) * @note only used on lower_raise tools atm. * @return true if the cursor has to be moved. */ virtual bool update_pos_after_use() const { return false; } virtual waytype_t get_waytype() const { return invalid_wt; } }; /* * Class for tools that work only on ground (kartenboden) */ class kartenboden_tool_t : public tool_t { public: kartenboden_tool_t(uint16 const id) : tool_t(id) {} char const* check_pos(player_t*, koord3d) OVERRIDE; }; /** * Class for tools needing two clicks (e.g. building ways). * Dragging is also possible. */ class two_click_tool_t : public tool_t { public: two_click_tool_t(uint16 const id) : tool_t(id) { MEMZERO(start_marker); first_click_var = true; } void rdwr_custom_data(memory_rw_t*) OVERRIDE; bool init(player_t*) OVERRIDE; bool exit(player_t* const player) OVERRIDE { return init(player); } char const* work(player_t*, koord3d) OVERRIDE; char const* move(player_t*, uint16 /* buttonstate */, koord3d) OVERRIDE; bool move_has_effects() const OVERRIDE { return true; } bool is_work_here_keeps_game_state(player_t *, koord3d) OVERRIDE; /** * @returns true if cleanup() needs to be called before another tool can be executed * necessary for all tools that create dummy tiles for preview */ virtual bool remove_preview_necessary() const { return false; } bool is_first_click() const; /** * Remove dummy grounds, remove start_marker if @p delete_start_marker is true. */ void cleanup(bool delete_start_marker = true); const koord3d& get_start_pos() const { return start; } private: /* * This routine should fill marked_tiles. */ virtual void mark_tiles( player_t *, const koord3d &start, const koord3d &end ) = 0; /* * This routine is called, if the real work should be done. * If the tool supports single clicks, end is sometimes == koord3d::invalid. * Returned string is passed by work/move. */ virtual const char *do_work( player_t *, const koord3d &start, const koord3d &end ) = 0; /* * Can the tool start/end on pos? If it is the second click, start is the position of the first click * 0 = no * 1 = This tool can work on this tile (with single click) * 2 = On this tile can dragging start/end * 3 = Both (1 and 2) * error will contain an error message (if this is != NULL, return value should be 0). */ virtual uint8 is_valid_pos( player_t *, const koord3d &pos, const char *&error, const koord3d &start ) = 0; virtual image_id get_marker_image() const; bool first_click_var; koord3d start; zeiger_t *start_marker; protected: virtual void start_at( koord3d &new_start ); slist_tpl< zeiger_t* > marked; }; /* toolbar are a new overclass */ class toolbar_t : public tool_t { protected: const char *helpfile; tool_selector_t *tool_selector; slist_tpltools; public: toolbar_t(uint16 const id, char const* const t, char const* const h) : tool_t(id) { default_param = t; helpfile = h; tool_selector = NULL; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate(default_param); } tool_selector_t *get_tool_selector() const { return tool_selector; } image_id get_icon(player_t*) const OVERRIDE; bool is_selected() const OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } // show this toolbar bool init(player_t*) OVERRIDE; // close this toolbar bool exit(player_t*) OVERRIDE; virtual void update(player_t *); // just refresh content void append(tool_t *tool) { tools.append(tool); } }; #define MAX_LAST_TOOLS (10) class toolbar_last_used_t : public toolbar_t { private: slist_tplall_tools[MAX_PLAYER_COUNT]; public: toolbar_last_used_t(uint16 const id, char const* const t, char const* const h) : toolbar_t(id,t,h) {} static toolbar_last_used_t *last_used_tools; void update(player_t *) OVERRIDE; // just refresh content void append(tool_t *, player_t *); void clear(); }; // create new instance of tool tool_t *create_tool(int toolnr); #endif simutrans-124.3/src/simutrans/tool/simtool-dialogs.h000066400000000000000000000736341474050137200226400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TOOL_SIMTOOL_DIALOGS_H #define TOOL_SIMTOOL_DIALOGS_H #include "../tool/simmenu.h" #include "../gui/simwin.h" #include "../dataobj/translator.h" #include "../dataobj/scenario.h" #include "../dataobj/environment.h" #include "../gui/baum_edit.h" #include "../gui/chat_frame.h" #include "../gui/citybuilding_edit.h" #include "../gui/citylist_frame.h" #include "../gui/climates.h" #include "../gui/convoi_frame.h" #include "../gui/curiosity_edit.h" #include "../gui/curiositylist_frame.h" #include "../gui/depotlist_frame.h" #include "../gui/display_settings.h" #include "../gui/enlarge_map_frame.h" #include "../gui/factory_edit.h" #include "../gui/factorylist_frame.h" #include "../gui/goods_frame.h" #include "../gui/groundobj_edit.h" #include "../gui/halt_list_frame.h" #include "../gui/help_frame.h" #include "../gui/jump_frame.h" #include "../gui/kennfarbe.h" #include "../gui/labellist_frame.h" #include "../gui/loadsave_frame.h" #include "../gui/map_frame.h" #include "../gui/message_frame.h" #include "../gui/messagebox.h" #include "../gui/money_frame.h" #include "../gui/optionen.h" #include "../gui/player_frame.h" #include "../gui/player_ranking_frame.h" #include "../gui/scenario_frame.h" #include "../gui/scenario_info.h" #include "../gui/schedule_list.h" #include "../gui/script_tool_frame.h" #include "../gui/server_frame.h" #include "../gui/settings_frame.h" #include "../gui/sound_frame.h" #include "../gui/sprachen.h" #include "../gui/themeselector.h" #include "../gui/vehiclelist_frame.h" #include "../obj/baum.h" #include "../obj/groundobj.h" #include "../sys/simsys.h" class player_t; /********************** dialog tools *****************************/ // general help class dialog_help_t : public tool_t { public: dialog_help_t() : tool_t(DIALOG_HELP | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Help"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_mainhelp); } bool init(player_t*) OVERRIDE{ help_frame_t::open_help_on("general.txt"); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_mainhelp); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open info/quit dialog class dialog_options_t : public tool_t { public: dialog_options_t() : tool_t(DIALOG_OPTIONS | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Einstellungen aendern"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_optionen_gui_t); } bool init(player_t*) OVERRIDE{ create_win({ -1, -1 }, new optionen_gui_t(), w_info, magic_optionen_gui_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_optionen_gui_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open minimap class dialog_minimap_t : public tool_t { public: dialog_minimap_t() : tool_t(DIALOG_MINIMAP | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Reliefkarte"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_reliefmap); } bool init(player_t*) OVERRIDE{ create_win(new map_frame_t(), w_info, magic_reliefmap); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_reliefmap); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open line management class dialog_lines_t : public tool_t { public: dialog_lines_t() : tool_t(DIALOG_LINEOVERVIEW | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Line Management"); } image_id get_icon(player_t* player) const OVERRIDE{ return !player || player->get_player_nr() == PLAYER_PUBLIC_NR ? IMG_EMPTY : icon; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_line_management_t + welt->get_active_player_nr()); } bool init(player_t* player) OVERRIDE{ if (!player->is_public_service()) { create_win(new schedule_list_gui_t(player), w_info, magic_line_management_t + player->get_player_nr()); } return false; } bool exit(player_t* const player) OVERRIDE{ destroy_win(win_get_magic(magic_line_management_t + player->get_player_nr())); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open messages class dialog_messages_t : public tool_t { public: dialog_messages_t() : tool_t(DIALOG_MESSAGES | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Mailbox"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_messageframe); } bool init(player_t*) OVERRIDE{ create_win(new message_frame_t(), w_info, magic_messageframe); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_messageframe); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open finance window class dialog_finances_t : public tool_t { public: dialog_finances_t() : tool_t(DIALOG_FINANCES | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Finanzen"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_finances_t + welt->get_active_player_nr()); } bool init(player_t* player) OVERRIDE{ create_win(new money_frame_t(player), w_info, magic_finances_t + player->get_player_nr()); return false; } bool exit(player_t* const player) OVERRIDE{ destroy_win(magic_finances_t + player->get_player_nr()); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open player dialog class dialog_players_t : public tool_t { public: dialog_players_t() : tool_t(DIALOG_PLAYERS | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Spielerliste"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_ki_kontroll_t); } bool init(player_t*) OVERRIDE{ create_win({ 272, 160 }, new ki_kontroll_t(), w_info, magic_ki_kontroll_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_ki_kontroll_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open display options class dialog_displayoptions_t : public tool_t { public: dialog_displayoptions_t() : tool_t(DIALOG_DISPLAYOPTIONS | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Display settings"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_color_gui_t); } bool init(player_t*) OVERRIDE{ create_win(new color_gui_t(), w_info, magic_color_gui_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_color_gui_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open sound dialog class dialog_sound_t : public tool_t { public: dialog_sound_t() : tool_t(DIALOG_SOUND | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Sound"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_sound_kontroll_t); } bool init(player_t*) OVERRIDE{ create_win(new sound_frame_t(), w_info, magic_sound_kontroll_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_sound_kontroll_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open language dialog class dialog_language_t : public tool_t { public: dialog_language_t() : tool_t(DIALOG_LANGUAGE | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Sprache"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_sprachengui_t); } bool init(player_t*) OVERRIDE{ create_win(new sprachengui_t(), w_info, magic_sprachengui_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_sprachengui_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open player color dialog class dialog_playercolor_t : public tool_t { public: dialog_playercolor_t() : tool_t(DIALOG_PLAYERCOLOR | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Farbe"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_farbengui_t); } bool init(player_t* player) OVERRIDE{ create_win(new farbengui_t(player), w_info, magic_farbengui_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_farbengui_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // jump to position dialog class dialog_jump_t : public tool_t { public: dialog_jump_t() : tool_t(DIALOG_JUMP | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Jump to"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_jump); } bool init(player_t*) OVERRIDE{ create_win(new jump_frame_t(), w_info, magic_jump); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_jump); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // load game dialog class dialog_load_t : public tool_t { public: dialog_load_t() : tool_t(DIALOG_LOAD | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Laden"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_load_t); } bool init(player_t*) OVERRIDE{ if( !env_t::server ) { dr_chdir(env_t::user_dir); create_win(new loadsave_frame_t(true), w_info, magic_load_t); } else { destroy_win(magic_save_t); create_win( new loadsave_frame_t(true), w_info, magic_load_t); const scr_coord pos = win_get_pos( win_get_magic(magic_load_t) ); create_win( pos + scr_coord{ 20, 20 }, new news_img("Loading a new game will end the current server session!"), w_no_overlap, magic_none); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_load_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } }; // save game dialog class dialog_save_t : public tool_t { public: dialog_save_t() : tool_t(DIALOG_SAVE | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Speichern"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_save_t); } bool init(player_t*) OVERRIDE{ dr_chdir(env_t::user_dir); create_win(new loadsave_frame_t(false), w_info, magic_save_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_save_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } }; // open scripted-tools dialog class dialog_script_tool_t : public tool_t { public: dialog_script_tool_t() : tool_t(DIALOG_SCRIPT_TOOL | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Load tool script"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_load_script); } bool init(player_t*) OVERRIDE{ destroy_win(magic_save_t); create_win( new script_tool_frame_t(), w_info, magic_load_script ); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_load_script); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } }; // open scenario dialog class dialog_scenario_t : public tool_t { public: dialog_scenario_t() : tool_t(DIALOG_SCENARIO | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Load scenario"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_load_scenario); } bool init(player_t*) OVERRIDE{ destroy_win(magic_save_t); if( !env_t::server ) { create_win( new scenario_frame_t(), w_info, magic_load_scenario ); } else { create_win( new scenario_frame_t(), w_info, magic_load_scenario ); const scr_coord pos = win_get_pos( win_get_magic(magic_load_scenario) ); create_win( pos + scr_coord{ 20, 20 }, new news_img("Loading a new game will end the current server session!"), w_no_overlap, magic_none); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_load_scenario); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } }; // open scenario info dialog class dialog_scenario_info_t : public tool_t { public: dialog_scenario_info_t() : tool_t(DIALOG_SCENARIO_INFO | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Scenario"); } image_id get_icon(player_t *) const OVERRIDE { return world()->get_scenario()->is_scripted() ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_scenario_info); } bool init(player_t*) OVERRIDE{ create_win( new scenario_info_t(), w_info, magic_scenario_info ); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_scenario_info); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of halt */ class dialog_list_halt_t : public tool_t { public: dialog_list_halt_t() : tool_t(DIALOG_LIST_HALT | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("hl_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_halt_list + welt->get_active_player_nr()); } bool init(player_t* player) OVERRIDE{ create_win(new halt_list_frame_t(), w_info, magic_halt_list + player->get_player_nr()); return false; } bool exit(player_t* player) OVERRIDE{ destroy_win(magic_halt_list + player->get_player_nr()); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of vehicle */ class dialog_list_convoi_t : public tool_t { public: dialog_list_convoi_t() : tool_t(DIALOG_LIST_CONVOI | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("cl_title"); } image_id get_icon(player_t*) const OVERRIDE{ return welt->get_active_player_nr() == PLAYER_PUBLIC_NR ? IMG_EMPTY : icon; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_convoi_list + welt->get_active_player_nr()); } bool init(player_t* player) OVERRIDE{ create_win(new convoi_frame_t(), w_info, magic_convoi_list + player->get_player_nr()); return false; } bool exit(player_t* const player) OVERRIDE{ destroy_win(magic_convoi_list + player->get_player_nr()); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of depots */ class dialog_list_depot_t : public tool_t { public: dialog_list_depot_t() : tool_t(DIALOG_LIST_DEPOT | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("dp_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_depotlist + welt->get_active_player_nr()); } image_id get_icon(player_t*) const OVERRIDE{ return welt->get_active_player_nr() == PLAYER_PUBLIC_NR ? IMG_EMPTY : icon; } bool init(player_t* player) OVERRIDE{ create_win(new depotlist_frame_t(player), w_info, magic_depotlist + player->get_player_nr()); return false; } bool exit(player_t* player) OVERRIDE{ destroy_win(magic_depotlist + player->get_player_nr()); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of vehicles */ class dialog_list_vehicle_t : public tool_t { public: dialog_list_vehicle_t() : tool_t(DIALOG_LIST_VEHICLE | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("vh_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_vehiclelist); } bool init(player_t*) OVERRIDE{ create_win(new vehiclelist_frame_t(), w_info, magic_vehiclelist); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_vehiclelist); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of towns */ class dialog_list_town_t : public tool_t { public: dialog_list_town_t() : tool_t(DIALOG_LIST_TOWN | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("tl_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_citylist_frame_t); } bool init(player_t*) OVERRIDE{ create_win(new citylist_frame_t(), w_info, magic_citylist_frame_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_citylist_frame_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of goods */ class dialog_list_goods_t : public tool_t { public: dialog_list_goods_t() : tool_t(DIALOG_LIST_GOODS | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("gl_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_goodslist); } bool init(player_t*) OVERRIDE{ create_win(new goods_frame_t(), w_info, magic_goodslist); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_goodslist); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of factories */ class dialog_list_factory_t : public tool_t { public: dialog_list_factory_t() : tool_t(DIALOG_LIST_FACTORY | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("fl_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_factorylist); } bool init(player_t*) OVERRIDE{ create_win(new factorylist_frame_t(), w_info, magic_factorylist); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_factorylist); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open the list of attraction */ class dialog_list_curiosity_t : public tool_t { public: dialog_list_curiosity_t() : tool_t(DIALOG_LIST_CURIOSITY | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("curlist_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_curiositylist); } bool init(player_t*) OVERRIDE{ create_win(new curiositylist_frame_t(), w_info, magic_curiositylist); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_curiositylist); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* factory building dialog */ class dialog_edit_factory_t : public tool_t { public: dialog_edit_factory_t() : tool_t(DIALOG_EDIT_FACTORY | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("factorybuilder"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_factory); } bool init(player_t* player) OVERRIDE{ if (!is_selected()) { create_win(new factory_edit_frame_t(player), w_info, magic_edit_factory); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_edit_factory); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* attraction building dialog */ class dialog_edit_attraction_t : public tool_t { public: dialog_edit_attraction_t() : tool_t(DIALOG_EDIT_ATTRACTION | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("curiosity builder"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_attraction); } bool init(player_t* player) OVERRIDE{ if (!is_selected()) { create_win(new curiosity_edit_frame_t(player), w_info, magic_edit_attraction); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_edit_attraction); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* house building dialog */ class dialog_edit_house_t : public tool_t { public: dialog_edit_house_t() : tool_t(DIALOG_EDIT_HOUSE | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("citybuilding builder"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_house); } bool init(player_t* player) OVERRIDE{ if (!is_selected()) { create_win(new citybuilding_edit_frame_t(player), w_info, magic_edit_house); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_edit_house); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* tree placing dialog */ class dialog_edit_tree_t : public tool_t { public: dialog_edit_tree_t() : tool_t(DIALOG_EDIT_TREE | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("baum builder"); } image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_tree); } bool init(player_t* player) OVERRIDE{ if( tree_builder_t::has_trees() && !is_selected() ) { create_win(new baum_edit_frame_t(player), w_info, magic_edit_tree); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_edit_tree); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* groundobj placing dialog */ class dialog_edit_groundobj_t : public tool_t { public: dialog_edit_groundobj_t() : tool_t(DIALOG_EDIT_GROUNDOBJ | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("groundobj builder"); } image_id get_icon(player_t *) const OVERRIDE { return groundobj_t::get_count() > 0 ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_edit_groundobj); } bool init(player_t* player) OVERRIDE{ if (!is_selected()) { create_win(new groundobj_edit_frame_t(player), w_info, magic_edit_groundobj); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_edit_groundobj); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // to increase map-size class dialog_enlarge_map_t : public tool_t{ public: dialog_enlarge_map_t() : tool_t(DIALOG_ENLARGE_MAP | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return env_t::networkmode ? translator::translate("deactivated in online mode") : translator::translate("enlarge map"); } image_id get_icon(player_t *) const OVERRIDE { return env_t::networkmode ? IMG_EMPTY : icon; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_bigger_map); } bool init(player_t*) OVERRIDE{ if (!env_t::networkmode) { destroy_all_win(true); create_win(new enlarge_map_frame_t(), w_info, magic_bigger_map); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_bigger_map); return false; } }; /* open the list of label */ class dialog_list_label_t : public tool_t { public: dialog_list_label_t() : tool_t(DIALOG_LIST_LABEL | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("labellist_title"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_labellist); } bool init(player_t*) OVERRIDE{ create_win(new labellist_frame_t(), w_info, magic_labellist); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_labellist); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open climate settings */ class dialog_climates_t : public tool_t { public: dialog_climates_t() : tool_t(DIALOG_CLIMATES | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return (!env_t::networkmode || env_t::server) ? translator::translate("Climate Control") : translator::translate("deactivated in online mode"); } image_id get_icon(player_t *) const OVERRIDE { return (!env_t::networkmode || env_t::server) ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_climate); } bool init(player_t*) OVERRIDE{ if (!env_t::networkmode || env_t::server) { create_win(new climate_gui_t(&welt->get_settings()), w_info, magic_climate); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_climate); return false; } }; /* open all game settings */ class dialog_settings_t : public tool_t { public: dialog_settings_t() : tool_t(DIALOG_SETTINGS | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return (!env_t::networkmode || env_t::server) ? translator::translate("Setting") : translator::translate("deactivated in online mode"); } image_id get_icon(player_t *) const OVERRIDE { return (!env_t::networkmode || env_t::server) ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE{ return win_get_magic(magic_settings_frame_t); } bool init(player_t*) OVERRIDE{ if (!env_t::networkmode || env_t::server) { create_win(new settings_frame_t(&welt->get_settings()), w_info, magic_settings_frame_t); } return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_settings_frame_t); return false; } }; /* server info and join dialog */ class dialog_gameinfo_t : public tool_t { public: dialog_gameinfo_t() : tool_t(DIALOG_GAMEINFO | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Game info"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_server_frame_t); } bool init(player_t*) OVERRIDE{ create_win(new server_frame_t(), w_info, magic_server_frame_t); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_server_frame_t); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; /* open themes selector settings */ class dialog_themes_t : public tool_t { public: dialog_themes_t() : tool_t(DIALOG_THEMES | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE{ return translator::translate("Select a theme for display"); } bool is_selected() const OVERRIDE{ return win_get_magic(magic_themes); } bool init(player_t*) OVERRIDE{ create_win(new themeselector_t(), w_info, magic_themes); return false; } bool exit(player_t*) OVERRIDE{ destroy_win(magic_themes); return false; } bool is_init_keeps_game_state() const OVERRIDE{ return true; } bool is_work_keeps_game_state() const OVERRIDE{ return true; } }; // open chat window class dialog_chat_t : public tool_t { public: dialog_chat_t() : tool_t(DIALOG_CHAT | DIALOGE_TOOL) {} image_id get_icon(player_t*) const OVERRIDE { return env_t::networkmode || !welt->get_chat_message()->get_list().empty() ? icon : IMG_EMPTY; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Chat"); } bool is_selected() const OVERRIDE { return win_get_magic(magic_chatframe); } bool init(player_t*) OVERRIDE { create_win(new chat_frame_t(), w_info, magic_chatframe); return false; } bool exit(player_t*) OVERRIDE { destroy_win(magic_chatframe); return false; } void draw_after(scr_coord pos, bool dirty) const OVERRIDE { if (icon != IMG_EMPTY) { if (is_selected()) { display_img_blend(icon, pos.x, pos.y, TRANSPARENT50_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK), false, dirty); } uint16 unread_count = env_t::chat_unread_public + env_t::chat_unread_company + env_t::chat_unread_whisper; if (unread_count > 99) { unread_count = 99; } if (unread_count) { char str[16]; sprintf(str, "%i", unread_count); scr_coord_val txt_width = proportional_string_width(str); scr_coord_val width = max(LINEASCENT, txt_width + 2); scr_coord_val xoff = env_t::iconsize.w - width - 1; scr_coord_val yoff = env_t::iconsize.h - LINESPACE - 1; display_filled_roundbox_clip(pos.x + xoff, pos.y + yoff, width, LINESPACE, color_idx_to_rgb(COL_RED + 1), dirty); display_proportional_rgb(pos.x + xoff + D_GET_CENTER_ALIGN_OFFSET(txt_width, width), pos.y + yoff + 1, str, ALIGN_LEFT, color_idx_to_rgb(COL_WHITE), dirty); } } } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; // open player ranking dialog class dialog_player_ranking_t : public tool_t { public: dialog_player_ranking_t() : tool_t(DIALOG_PLAYER_RANKING | DIALOGE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Player ranking"); } image_id get_icon(player_t*) const OVERRIDE { int nr = 0; for (int i = 0; i < MAX_PLAYER_COUNT; i++) { if (welt->get_player(i)) { nr++; } } return nr>2 ? icon : IMG_EMPTY; } bool is_selected() const OVERRIDE { return win_get_magic(magic_player_ranking); } bool init(player_t */*player*/) OVERRIDE { create_win(new player_ranking_frame_t(), w_info, magic_player_ranking); return false; } bool exit(player_t*) OVERRIDE { destroy_win(magic_player_ranking); return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; #endif simutrans-124.3/src/simutrans/tool/simtool-script-generator.cc000066400000000000000000000531371474050137200246400ustar00rootroot00000000000000 #include "simtool.h" #include "../tpl/vector_tpl.h" #include "../simhalt.h" #include "../dataobj/environment.h" #include "../dataobj/koord3d.h" #include "../descriptor/building_desc.h" #include "../descriptor/ground_desc.h" #include "../gui/messagebox.h" #include "../gui/script_generator_frame.h" #include "../gui/simwin.h" #include "../obj/wayobj.h" #include "../obj/bruecke.h" #include "../obj/depot.h" #include "../obj/gebaeude.h" #include "../obj/signal.h" #include "../obj/zeiger.h" #include "../sys/simsys.h" #include "../world/simcity.h" #include "../world/simworld.h" #include "../world/simplan.h" void tool_generate_script_t::mark_tiles(player_t*, const koord3d& start, const koord3d& end) { koord k1, k2; k1.x = start.x < end.x ? start.x : end.x; k1.y = start.y < end.y ? start.y : end.y; k2.x = start.x + end.x - k1.x; k2.y = start.y + end.y - k1.y; koord k; for (k.x = k1.x; k.x <= k2.x; k.x++) { for (k.y = k1.y; k.y <= k2.y; k.y++) { if (planquadrat_t* plan = welt->access(k.x, k.y)) { for (uint8 i = 0; i < plan->get_boden_count(); i++) { if (grund_t* gr = plan->get_boden_bei(i)) { if (gr->ist_karten_boden() || gr->get_pos().z > plan->get_boden_bei(0)->get_pos().z) { zeiger_t* marker = new zeiger_t(gr->get_pos(), NULL); const uint8 grund_hang = gr->get_grund_hang(); #if 0 // this would use the way slope, not the ground slope const uint8 weg_hang = gr->get_weg_hang(); const uint8 hang = max(corner_sw(grund_hang), corner_sw(weg_hang)) + 3 * max(corner_se(grund_hang), corner_se(weg_hang)) + 9 * max(corner_ne(grund_hang), corner_ne(weg_hang)) + 27 * max(corner_nw(grund_hang), corner_nw(weg_hang)); uint8 back_hang = (hang % 3) + 3 * ((uint8)(hang / 9)) + 27; #else uint8 back_hang = (grund_hang % 3) + 3 * ((uint8)(grund_hang / 9)) + 27; #endif marker->set_foreground_image(ground_desc_t::marker->get_image(grund_hang % 27)); marker->set_image(ground_desc_t::marker->get_image(back_hang)); marker->mark_image_dirty(marker->get_image(), 0); gr->obj_add(marker); marked.insert(marker); } } } } } } } static void write_owner_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { if (pl->is_public_service()) { if (const grund_t* gr = world()->lookup(pos)) { if (obj_t* obj = gr->obj_bei(0)) { if (obj->get_owner() != pl) { koord3d diff = pos - origin; buf.printf("\thm_set_owner_tl(%hu,[%d,%d,%d])\n", obj->get_owner_nr(), diff.x, diff.y, diff.z); } } } } } static void write_city_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { if (pl->is_public_service()) { if (const grund_t* gr = world()->lookup(pos)) { if (const gebaeude_t* gb = gr->find()) { if (gb->get_tile()->get_offset() == koord(0, 0)) { if (gb->is_townhall()) { koord3d diff = pos - origin; buf.printf("\thm_city_set_population_tl(%ld,[%d,%d,%d])\n", gb->get_stadt()->get_finance_history_month(0, HIST_CITIZENS), diff.x, diff.y, diff.z); } } } } } } static void write_townhall_at(player_t */*pl*/, cbuffer_t& buf, const koord3d pos, const koord3d origin) { if (const grund_t* gr = world()->lookup(pos)) { if (const gebaeude_t* gb = gr->find()) { if (gb->get_tile()->get_offset() == koord(0, 0)) { // we have a start tile here => more checks const building_desc_t* desc = gb->get_tile()->get_desc(); if (gb->is_townhall()) { koord3d diff = pos - origin; buf.printf("\thm_city_tl(0,\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, gb->get_tile()->get_layout()); } } } } } static void write_house_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { if (const grund_t* gr = world()->lookup(pos)) { if (const gebaeude_t* gb = gr->find()) { if (gb->get_tile()->get_offset() == koord(0, 0)) { // we have a start tile here => more checks const building_desc_t* desc = gb->get_tile()->get_desc(); if (!desc->is_transport_building()) { sint16 rotation = gb->get_tile()->get_layout(); if (pl->is_public_service()) { if (desc->is_headquarters()) { // skipping } else if (desc->is_factory()) { // koord3d diff = pos - origin; // buf.printf("\thm_factor_tl(0,\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, rotation); } else if (desc->is_attraction()) { koord3d diff = pos - origin; buf.printf("\thm_house_tl(\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, rotation); } else if (gb->is_townhall()) { // has been hopefully already written ... } else if (desc->is_connected_with_town()) { koord3d diff = pos - origin; buf.printf("\thm_house_tl(\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, rotation); } } else if (gb->get_owner() == pl) { koord3d diff = pos - origin; if (desc->is_headquarters()) { // headquarter has a level instead desc buf.printf("\thm_headquarter_tl(%d,[%d,%d,%d],%d)\n", pl->get_headquarter_level(), diff.x, diff.y, diff.z, rotation); } else { buf.printf("\thm_house_tl(\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, rotation); } } } } } } } static void write_depot_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { if (const grund_t* gr = world()->lookup(pos)) { if (const depot_t* obj = gr->get_depot()) { if (obj->get_owner() == pl) { const building_desc_t* desc = obj->get_tile()->get_desc(); koord3d diff = pos - origin; buf.printf("\thm_depot_tl(\"%s\",[%d,%d,%d],%d)\n", desc->get_name(), diff.x, diff.y, diff.z, desc->get_finance_waytype()); } } } } // taking all roadsigns for now static void write_sign_at(player_t* , cbuffer_t& buf, const koord3d pos, const koord3d origin) { const grund_t* gr = world()->lookup(pos); const weg_t* weg = gr ? gr->get_weg_nr(0) : NULL; if (!weg || (!weg->has_sign() && !weg->has_signal())) { return; } // now this tile should have a sign. roadsign_t* sign = NULL; if (signal_t* s = gr->find()) { sign = s; } else { // a sign should exists. sign = gr->find(); } if (sign) { // now this pos has a stop. uint8 cnt = 1; const ribi_t::ribi d = sign->get_dir(); const bool ow = sign->get_desc()->is_single_way(); if (!ribi_t::is_single(d)) { cnt = 1; } else if (ribi_t::is_straight(weg->get_ribi_unmasked())) { cnt = (d == ribi_t::north || d == ribi_t::east) ^ ow ? 2 : 3; } else if (ribi_t::is_bend(weg->get_ribi_unmasked())) { cnt = (d == ribi_t::north || d == ribi_t::south) ^ ow ? 2 : 3; } koord3d diff = pos - origin; buf.printf("\thm_sign_tl(\"%s\",%d,[%d,%d,%d],%d,%u)\n", sign->get_desc()->get_name(), cnt, diff.x, diff.y, diff.z, sign->get_desc()->get_waytype(), sign->get_desc()->is_traffic_light() ? 512 : sign->get_desc()->get_flags()); } } static void write_slope_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { const grund_t* gr = world()->lookup(pos); if (!gr || gr->is_water() || gr->ist_auf_bruecke() || gr->ist_im_tunnel()) { return; } if(!pl->is_public_service()) { // only save used tiles unless public service if (gr->ist_natur() && gr->get_typ()==grund_t::boden) { // do not touch return; } if (origin.z > pos.z && (gr->obj_count()==0 || gr->obj_bei(0)->get_owner() != pl)) { // do not save tiles below the start unless is mine return; } } const koord3d pb = pos - origin; sint8 diff = pb.z; while (diff != 0) { if (diff > 0) { // raise the land buf.printf("\thm_slope_tl(hm_slope.UP,[%d,%d,%d])\n", pb.x, pb.y, pb.z - diff); diff -= 1; } else { // lower the land buf.printf("\thm_slope_tl(hm_slope.DOWN,[%d,%d,%d])\n", pb.x, pb.y, pb.z - diff); diff += 1; } } // check slopes const slope_t::type slp = gr->get_grund_hang(); if (slp > 0) { buf.printf("\thm_slope_tl(%d,[%d,%d,%d])\n", slp, pb.x, pb.y, pb.z); } } static void write_ground_at(player_t* pl, cbuffer_t& buf, const koord3d pos, const koord3d origin) { const grund_t* gr = world()->lookup(pos); if (!gr || gr->is_water() || gr->ist_auf_bruecke() || gr->ist_im_tunnel()) { return; } if (!pl->is_public_service()) { // only save used tiles unless public service if (gr->ist_natur() && gr->get_typ() == grund_t::boden) { // do not touch return; } if (origin.z > pos.z && (gr->obj_count() == 0 || gr->obj_bei(0)->get_owner() != pl)) { // do not save tiles below the start unless is mine return; } } const koord3d pb = pos - origin; buf.printf("\thm_ground_tl(%d,[%d,%d,%d])\n", gr->get_grund_hang(), pb.x, pb.y, pb.z); } // we only write bridges inside the marked area (ignoring ownership) static void write_command_bridges(player_t*, cbuffer_t& buf, const koord start, const koord end, const koord3d origin) { vector_tpl all_bridgepos;; karte_t* welt = world(); for (sint16 x = start.x; x <= end.x; x++) { for (sint16 y = start.y; y <= end.y; y++) { if (grund_t* gr = welt->lookup_kartenboden(x, y)) { if (gr->ist_bruecke()) { koord3d bstart = gr->get_pos(); bruecke_t* br = gr->find(); assert(br); if (all_bridgepos.is_contained(bstart)) { // already handled continue; } all_bridgepos.append(bstart); // find end of bridge koord zv = (gr->get_grund_hang() != slope_t::flat) ? -koord(gr->get_grund_hang()) : koord(gr->get_weg_hang()); koord3d checkpos(zv,slope_t::max_diff(max(gr->get_weg_hang(),gr->get_grund_hang()))); checkpos += bstart; bstart -= origin; while(checkpos.x>=start.x && checkpos.y>=start.y && checkpos.x<=end.x && checkpos.y<=end.y) { gr = welt->lookup(checkpos); if (!gr) { // nothing here => must be the end gr = welt->lookup_kartenboden(checkpos.get_2d()); if (gr) { koord3d bend = gr->get_pos(); all_bridgepos.append(bend); bend -= origin; // write bridge building command buf.printf("\thm_bridge_tl(\"%s\",[%d,%d,%d],[%d,%d,%d],%d)\n", br->get_desc()->get_name(), bstart.x, bstart.y, bstart.z, bend.x, bend.y, bend.z, br->get_waytype()); } // or the end of the map ... break; } else if (!gr->ist_auf_bruecke()) { koord3d bend = gr->get_pos(); all_bridgepos.append(bend); bend -= origin; // write bridge building command buf.printf("\thm_bridge_tl(\"%s\",[%d,%d,%d],[%d,%d,%d],%d)\n", br->get_desc()->get_name(), bstart.x, bstart.y, bstart.z, bend.x, bend.y, bend.z, br->get_waytype()); break; } checkpos += zv; } } } } } } // since the building order is important, we build the station in the same tile order as the original // May be still fail if there have been connecting tiles that have been deleted ... static void write_command_halt(player_t* pl, cbuffer_t& buf, const koord start, const koord end, const koord3d origin) { vector_tpl all_halt; karte_t *welt = world(); for (sint16 x = start.x; x <= end.x; x++) { for (sint16 y = start.y; y <= end.y; y++) { if (planquadrat_t* plan = welt->access(x, y)) { for (uint8 i = 0; i < plan->get_boden_count(); i++) { halthandle_t h = plan->get_boden_bei(i)->get_halt(); if (h.is_bound() && (h->get_owner()==pl || h->get_owner()->get_player_nr()==PLAYER_PUBLIC_NR)) { all_halt.append_unique(h); } } } } } for (const halthandle_t &halt : all_halt) { for (const haltestelle_t::tile_t& t : halt->get_tiles()) { koord p = t.grund->get_pos().get_2d(); if (start.x <= p.x && p.x <= end.x && start.y <= p.y && p.y <= end.y) { if (const gebaeude_t* gb = t.grund->find()) { sint16 rotation = gb->get_tile()->get_layout(); if (gb->get_tile()->get_offset() == koord(0, 0)) { // only for left top tile save const building_desc_t* desc = gb->get_tile()->get_desc(); koord3d diff = t.grund->get_pos() - origin; buf.printf("\thm_station_tl(\"%s\",[%d,%d,%d],%d,%d)\n", desc->get_name(), diff.x, diff.y, diff.z, gb->get_waytype(), rotation); } } } } } } static void write_command(player_t *pl, cbuffer_t& buf, void (*func)(player_t*, cbuffer_t&, const koord3d, const koord3d), const koord start, const koord end, const koord3d origin) { karte_t* welt = world(); for (sint16 x = start.x; x <= end.x; x++) { for (sint16 y = start.y; y <= end.y; y++) { if (planquadrat_t* plan = welt->access(x, y)) { for (uint8 i = 0; i < plan->get_boden_count(); i++) { if (grund_t* gr = plan->get_boden_bei(i)) { if (!gr->ist_im_tunnel()) { func(pl, buf, plan->get_boden_bei(i)->get_pos(), origin); } } } } } } } // for functions which need concatenation class write_path_command_t { protected: struct { koord3d start; koord3d end; const char* desc_name; waytype_t way_type; sint16 system_type; } typedef script_cmd; vector_tpl commands; const player_t* player; cbuffer_t& buf; const char* cmd_str; koord start, end; koord3d origin; virtual void append_command(koord3d pos, const ribi_t::ribi(&dirs)[2]) = 0; virtual bool can_concatnate(script_cmd& a, script_cmd& b) = 0; public: write_path_command_t(player_t* pl, cbuffer_t& b, koord s, koord e, koord3d o) : player(pl), buf(b), start(s), end(e), origin(o) { }; void write() { for (sint8 z = -128; z < 127; z++) { // iterate for all height for (sint16 x = start.x; x <= end.x; x++) { for (sint16 y = start.y; y <= end.y; y++) { ribi_t::ribi dirs[2]; dirs[0] = x > start.x ? ribi_t::west : ribi_t::none; dirs[1] = y > start.y ? ribi_t::north : ribi_t::none; append_command(koord3d(x, y, z), dirs); } } } // concatenate the command while (!commands.empty()) { script_cmd cmd = commands.pop_back(); bool adjacent_found = true; while (adjacent_found) { adjacent_found = false; for (uint32 i = 0; i < commands.get_count(); i++) { if (!can_concatnate(commands[i], cmd)) { continue; } if (cmd.end == commands[i].start) { cmd.end = commands[i].end; adjacent_found = true; } else if (cmd.start == commands[i].end) { cmd.start = commands[i].start; adjacent_found = true; } if (adjacent_found) { commands.remove_at(i); break; } } } // all adjacent entries were concatenated. if (cmd.system_type >= 0) { buf.printf("\t%s(\"%s\",[%d,%d,%d],[%d,%d,%d],%d,%d)\n", cmd_str, cmd.desc_name, cmd.start.x, cmd.start.y, cmd.start.z, cmd.end.x, cmd.end.y, cmd.end.z, cmd.way_type, cmd.system_type); } else { buf.printf("\t%s(\"%s\",[%d,%d,%d],[%d,%d,%d],%d)\n", cmd_str, cmd.desc_name, cmd.start.x, cmd.start.y, cmd.start.z, cmd.end.x, cmd.end.y, cmd.end.z, cmd.way_type); } } } }; class write_way_command_t : public write_path_command_t { protected: bool first_pass; void append_command(koord3d pos, const ribi_t::ribi(&dirs)[2]) OVERRIDE { const grund_t* gr = world()->lookup(pos); if (!gr) { return; } bool weg_nr = 0; if (!first_pass && gr->get_weg_nr(1)) { weg_nr = 1; } const weg_t* weg0 = gr->get_weg_nr(weg_nr); if (!weg0) { return; } systemtype_t start_styp = weg0->get_desc()->get_styp(); koord3d pb = pos - origin; // relative base pos if (gr->get_typ() == grund_t::monorailboden) { pb.z -= world()->get_settings().get_way_height_clearance(); } for (uint8 i = 0; i < 2; i++) { if (dirs[i] == ribi_t::none) { continue; } grund_t* to = NULL; gr->get_neighbour(to, weg0->get_waytype(), dirs[i]); if (to) { const weg_t* to_weg = to->get_weg_nr(0); bool to_weg_nr = 0; if (to_weg->get_waytype() != weg0->get_waytype()) { to_weg = to->get_weg_nr(1); to_weg_nr = 1; if (to_weg->get_waytype() != weg0->get_waytype()) { continue; } } if (!to_weg_nr && !weg_nr) { // check system type (for airplanes etc.) if there is only one way if (start_styp == to_weg->get_desc()->get_styp()) { if (first_pass && start_styp != 0) { // we connect in this round only to other system types for one step continue; } if (!first_pass && start_styp == 0) { // we connect in this round only to other system types continue; } } else if (!first_pass) { continue; } } koord3d tp = to->get_pos() - origin; if (to->get_typ() == grund_t::monorailboden) { tp = tp - koord3d(0, 0, world()->get_settings().get_way_height_clearance()); } const way_desc_t* d = (weg0->get_desc()->get_styp()==0 && first_pass) ? weg0->get_desc() : to_weg->get_desc(); if (weg_nr > 0) { d = weg0->get_desc(); } if (to_weg_nr > 0) { d = to_weg->get_desc(); } commands.append(script_cmd{ pb, tp, d->get_name(), d->get_waytype(), (sint16)d->get_styp() }); } } } bool can_concatnate(script_cmd& a, script_cmd& b) OVERRIDE { return strcmp(a.desc_name, b.desc_name) == 0 && ribi_type(a.start, a.end) == ribi_type(b.start, b.end); } public: write_way_command_t(player_t* pl, cbuffer_t& b, koord s, koord e, koord3d o, bool fp) : write_path_command_t(pl, b, s, e, o) { cmd_str = "hm_way_tl"; first_pass = fp; } }; class write_wayobj_command_t : public write_path_command_t { protected: void append_command(koord3d pos, const ribi_t::ribi(&dirs)[2]) OVERRIDE { const grund_t* gr = world()->lookup(pos); const weg_t* weg0 = gr ? gr->get_weg_nr(0) : NULL; const wayobj_t* wayobj = weg0 ? gr->get_wayobj(weg0->get_waytype()) : NULL; if (!wayobj) { return; } const waytype_t type = weg0->get_waytype(); for (uint8 i = 0; i < 2; i++) { if (dirs[i] == ribi_t::none) { continue; } grund_t* to = NULL; gr->get_neighbour(to, type, dirs[i]); const wayobj_t* t_obj = to ? to->get_wayobj(type) : NULL; if (t_obj && t_obj->get_desc() == wayobj->get_desc()) { commands.append(script_cmd{ pos - origin, to->get_pos() - origin, wayobj->get_desc()->get_name(), wayobj->get_waytype(),-1 }); } } } bool can_concatnate(script_cmd& a, script_cmd& b) OVERRIDE { return strcmp(a.desc_name, b.desc_name) == 0; } public: write_wayobj_command_t(player_t *pl, cbuffer_t& b, koord s, koord e, koord3d o) : write_path_command_t(pl, b, s, e, o) { cmd_str = "hm_wayobj_tl"; } }; char const* tool_generate_script_t::do_work(player_t* pl, const koord3d& start, const koord3d& end) { koord3d e = end == koord3d::invalid ? start : end; koord k1 = koord(min(start.x, e.x), min(start.y, e.y)); koord k2 = koord(max(start.x, e.x), max(start.y, e.y)); koord area( k2.x-k1.x+1, k2.y-k1.y+1 ); cbuffer_t generated_script_buf; generated_script_buf.printf("// automated rebuild scrip with size (%d,%d)\n\n", area.x, area.y); // comment generated_script_buf.append("include(\"hm_toolkit_v3\")\n\nfunction hm_build() {\n"); // header int cmdlen = generated_script_buf.len(); koord3d begin(k1, start.z); if (pl->is_public_service()) { // ensure this is run by public service generated_script_buf.append("\tif(this.player.nr != 1) {\n\t\treturn \"Must be run as public player!\"\n\t}\n\n"); } write_command(pl, generated_script_buf, write_ground_at, k1, k2, begin); // write all used tiles if (pl->is_public_service()) { write_command(pl, generated_script_buf, write_townhall_at, k1, k2, begin); } write_command_bridges(pl, generated_script_buf, k1, k2, begin); write_way_command_t(pl, generated_script_buf, k1, k2, begin, true).write(); write_way_command_t(pl, generated_script_buf, k1, k2, begin, false).write(); write_wayobj_command_t(pl, generated_script_buf, k1, k2, begin).write(); write_command_halt(pl, generated_script_buf, k1, k2, begin); write_command(pl, generated_script_buf, write_depot_at, k1, k2, begin); write_command(pl, generated_script_buf, write_sign_at, k1, k2, begin); write_command(pl, generated_script_buf, write_house_at, k1, k2, begin); if (pl->is_public_service()) { write_command(pl, generated_script_buf, write_owner_at, k1, k2, begin); // write_command(pl, generated_script_buf, write_city_at, k1, k2, begin); } if (cmdlen == generated_script_buf.len()) { return NULL; } generated_script_buf.append("}\n"); // footer cbuffer_t dir_buf; dir_buf.printf("%saddons%s%stool%s", env_t::user_dir, PATH_SEPARATOR, env_t::pak_name.c_str(), PATH_SEPARATOR); dr_mkdir(dir_buf.get_str()); create_win(new script_generator_frame_t(this, dir_buf.get_str(), generated_script_buf, area ), w_info, magic_script_generator); if (can_use_gui() && pl == welt->get_active_player()) { welt->set_tool(general_tool[TOOL_QUERY], pl); } return NULL; } bool tool_generate_script_t::save_script(const char* fullpath, const char *command, koord area) const { dr_mkdir(fullpath); cbuffer_t fname; cbuffer_t short_name; if (const char* p = strrchr(fullpath, *PATH_SEPARATOR)) { short_name.append(p + 1); } fname.printf("%s%stool.nut",fullpath, PATH_SEPARATOR); if (FILE* file = dr_fopen(fname, "w")) { fprintf(file, "%s", command); fclose(file); fname.clear(); fname.printf("%s%sdescription.tab", fullpath, PATH_SEPARATOR); if ((file = dr_fopen(fname, "w"))) { fprintf(file, "title=Building %s\n", short_name.get_str()); fprintf(file, "cursor_area=%d,%d\n", area.x, area.y); fprintf(file, "type=one_click\ntooltip=Building %s created by Simutrans\nrestart=1\nicon=BuilderScript\n", short_name.get_str()); fclose(file); } create_win(new news_img("The generated script was saved!\n"), w_time_delete, magic_none); return true; } dbg->error("tool_generate_script_t::save_script()", "cannot save file %s", fullpath); create_win(new news_img("The script cannot be saved!\n"), w_time_delete, magic_none); return false; } simutrans-124.3/src/simutrans/tool/simtool-scripted.cc000066400000000000000000000256571474050137200231730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../tool/simtool-scripted.h" #include "../player/simplay.h" #include "../script/script_tool_manager.h" #include "../script/script.h" #include "../script/script_loader.h" #include "../script/api/api.h" #include "../script/api_class.h" #include "../script/api_param.h" #include "../simskin.h" #include "../world/simworld.h" #include "../obj/zeiger.h" #include "../sys/simsys.h" #include "../dataobj/environment.h" void export_scripted_tools(HSQUIRRELVM vm); // -- callback to receive error messages from work/do_work calls static bool exec_script_base_work_callback(exec_script_base_t *esb, player_t* player, const char* err) { tool_t *tool = esb ? dynamic_cast(esb) : NULL; if (tool && player) { player->tell_tool_result(tool, koord3d::invalid, err); } if (tool_exec_two_click_script_t* tct = dynamic_cast(esb)) { tct->waiting_for_do_work = false; // we cannot call init() here directly, because it may destroy the vm that called us tct->needs_call_to_init = true; } return true; } // -- transfer pointers to tools between squirrel and c++ namespace script_api { /** * Mechanic to transfer exec_script_base_t* pointers between squirrel and c++, * used for callbacks. */ declare_specialized_param(exec_script_base_t*, "x", "scripted_tool_t"); SQInteger param::push(HSQUIRRELVM vm, exec_script_base_t* const& v) { return push_instance_up(vm, v); } exec_script_base_t* param::get(HSQUIRRELVM vm, SQInteger index) { return get_attached_instance(vm, index, param::tag()); } void* param::tag() { return (void*)¶m::get; } /** * Mechanic to transfer tool_exec_two_click_script_t* pointers between squirrel and c++, * used for marking tiles in two-click tools. */ template<> struct param { static tool_exec_two_click_script_t* get(HSQUIRRELVM vm, SQInteger index) { tool_t* tool = param::get(vm, index); return tool ? dynamic_cast(tool) : NULL; } static SQInteger push(HSQUIRRELVM vm, tool_exec_two_click_script_t* const& tool) { SQInteger res = push_instance(vm, "command_x", (uint32)(TOOL_EXEC_TWO_CLICK_SCRIPT | GENERAL_TOOL) ); if (SQ_SUCCEEDED(res)) { my_tool_t* mtool = new my_tool_t(tool); attach_instance(vm, -1, mtool); } return res; } }; }; // -- basic script handling -- exec_script_base_t::~exec_script_base_t() { delete info; delete script; } void exec_script_base_t::set_info(const scripted_tool_info_t *i) { delete info; info = i; } bool exec_script_base_t::init_vm(player_t* player) { if (get_info() == NULL) { // tool probably read from menuconf.tab // path in default_param, initialize if (tool_t *tool = dynamic_cast(this)) { script_tool_manager_t::load_tool(tool->get_default_param(), tool); } } if( script==NULL || (info && info->restart) ) { load_script(info->path, player); } return script != NULL; } void exec_script_base_t::load_script(const char* path, player_t* player) { cbuffer_t buf; buf.printf("script-exec-%d.log", player->get_player_nr()); if( script ) { // if vm already exists, delete it. delete script; script = NULL; } // start vm dr_chdir(path); script = script_loader_t::start_vm("tool_base.nut", buf, ".", false); if (script == NULL) { return; } // set my player number script->set_my_player(player->get_player_nr()); // export tool-pointer handling export_scripted_tools(script->get_vm()); // callback script->register_callback(exec_script_base_work_callback, "exec_script_base_work_callback"); // call script to initialize it buf.clear(); buf.printf( "%s/tool.nut", path ); if (const char* err = script->call_script("tool.nut")) { if (strcmp(err, "suspended")) { dbg->error("tool_exec_script_t::load_script", "error [%s] calling %s/tool.nut", err, (const char*)path); delete script; script = NULL; return; } } dr_chdir(env_t::user_dir); // older versions did not support the flags parameter - correct with helper function if (const char* err = script->call_function(script_vm_t::QUEUE, "correct_missing_flags_argument")) { if (strcmp(err, "suspended")) { dbg->error("tool_exec_script_t::load_script", "error [%s] calling correct_missing_flags_argument", err); delete script; script = NULL; } } } void export_scripted_tools(HSQUIRRELVM vm) { script_api::create_class(vm, script_api::param::squirrel_type()); script_api::end_class(vm); } template const char* exec_script_base_t::call_function(script_vm_t::call_type_t ct, const char* function, player_t* player, R& ret, const As &... as) { if (!script) { dbg->warning("tool_exec_script_t::call_function", "script vm is not available."); return ""; } const char* err = script->call_function(ct, function, ret, player, as...); if (err && strcmp(err, "suspended")) { dbg->warning("tool_exec_script_t::call_function", "error calling %s: %s", function, err); } return err; } void exec_script_base_t::step(player_t* player) { if (script) { script->call_function(script_vm_t::QUEUE, "step"); if (tool_exec_two_click_script_t *tt = dynamic_cast(this)) { if (tt->needs_call_to_init) { tt->init(player); } } } } void exec_script_base_t::init_images(tool_t *tool) const { if (info && info->desc) { if (info->desc->get_image_id(0) != IMG_EMPTY) { tool->cursor = info->desc->get_image_id(0); } tool->set_icon(info->desc->get_image_id(1)); } } tool_exec_script_t::tool_exec_script_t(const scripted_tool_info_t *info) : tool_t(TOOL_EXEC_SCRIPT | GENERAL_TOOL), exec_script_base_t(info) { init_images(this); } bool tool_exec_script_t::init(player_t* player) { bool res = false; cursor_area = get_cursor_area(); cursor_offset = get_cursor_offset(); // rotate area and offset for(uint8 i=0; iget_settings().get_rotation(); i++) { koord old_area = cursor_area; koord old_offset = cursor_offset; cursor_area = koord(old_area.y, old_area.x); cursor_offset = koord(old_area.y-1-old_offset.y, old_offset.x); } return init_vm(player) && call_function(script_vm_t::FORCE, "init", player, res)== NULL && res; } bool tool_exec_script_t::exit(player_t* player) { bool res, res2 = false; // exit script res = call_function(script_vm_t::FORCE, "exit", player, res2) == NULL; // shut down vm delete script; script = NULL; return res && res2; } const char* tool_exec_script_t::work(player_t* player, koord3d pos) { static plainstring res; res = NULL; // callback script->prepare_callback("exec_script_base_work_callback", 3, (exec_script_base_t*)this, player, (const char*)""); // now call uint8 keys = flags & (tool_t::WFL_SHIFT | tool_t::WFL_CTRL); const char* err = call_function(script_vm_t::QUEUE, "work", player, res, pos, keys); if (err && strcmp(err, "suspended")==0) { // suspended } else { // no callback necessary script->clear_pending_callback(); } return res.c_str(); } tool_exec_two_click_script_t::tool_exec_two_click_script_t(const scripted_tool_info_t *info) : two_click_tool_t(TOOL_EXEC_TWO_CLICK_SCRIPT | GENERAL_TOOL), exec_script_base_t(info) { set_marker(IMG_EMPTY); waiting_for_do_work = false; needs_call_to_init = true; init_images(this); if (info && info->desc) { set_marker(info->desc->get_image(2) ? info->desc->get_image_id(2) : cursor); } } SQInteger script_mark_tile(HSQUIRRELVM vm); // see below bool tool_exec_two_click_script_t::init(player_t* player) { // remove marker images bool res = two_click_tool_t::init(player); if (waiting_for_do_work) { return res; } needs_call_to_init = false; res = res && init_vm(player); if (res) { HSQUIRRELVM vm = script->get_vm(); // put pointer to this tool into registry sq_pushregistrytable(vm); script_api::create_slot(vm, "my_two_click_tool", this); sq_poptop(vm); // export marker function sq_pushroottable(vm); script_api::register_function(vm, script_mark_tile, "mark_tile", 2, ". t|x|y", false /* static */); sq_poptop(vm); } return res && call_function(script_vm_t::FORCE, "init", player, res)== NULL && res; } bool tool_exec_two_click_script_t::exit(player_t* player) { bool res, res2 = false; // exit script res = two_click_tool_t::exit(player) && call_function(script_vm_t::FORCE, "exit", player, res2) == NULL; // shut down vm delete script; script = NULL; return res && res2; } const char* tool_exec_two_click_script_t::do_work(player_t* player, const koord3d &start, const koord3d &end) { if (waiting_for_do_work) { return ""; } static plainstring res; // callback script->prepare_callback("exec_script_base_work_callback", 3, (exec_script_base_t*)this, player, (const char*)""); // now call uint8 keys = flags & (tool_t::WFL_SHIFT | tool_t::WFL_CTRL); res = NULL; const char* err = call_function(script_vm_t::QUEUE, "do_work", player, res, start, end, keys); if (err && strcmp(err, "suspended")==0) { // suspended waiting_for_do_work = true; } else { // no callback necessary script->clear_pending_callback(); } return res.c_str(); } void tool_exec_two_click_script_t::mark_tiles(player_t* player, const koord3d &start, const koord3d &end) { if (waiting_for_do_work) { return; } bool dummy; // try to mark; if script is busy, do nothing uint8 keys = flags & (tool_t::WFL_SHIFT | tool_t::WFL_CTRL); call_function(script_vm_t::TRY, "mark_tiles", player, dummy, start, end, keys); } uint8 tool_exec_two_click_script_t::is_valid_pos(player_t* player, const koord3d &pos, const char *&error, const koord3d &start) { error = NULL; uint8 res = 2; // allow dragging const char* err = call_function(script_vm_t::FORCEX, "is_valid_pos", player, res, pos, start); // script error? signal 'start dragging is allowed here' if (err) { res = 2; // allow dragging } return res; } // mark_tile(pos) SQInteger script_mark_tile(HSQUIRRELVM vm) { koord3d pos = script_api::param::get(vm, 2); player_t* player = script_api::get_my_player(vm); // tool sq_pushregistrytable(vm); tool_exec_two_click_script_t* tool = NULL; if (!SQ_SUCCEEDED(script_api::get_slot(vm, "my_two_click_tool", tool)) || tool == NULL) { return SQ_ERROR; } sq_poptop(vm); // now call the method return script_api::param::push(vm, tool->mark_tile(player, pos) ); } bool tool_exec_two_click_script_t::mark_tile(player_t* player, const koord3d &pos) { grund_t *gr = welt->lookup(pos); if (gr) { zeiger_t *mark = new zeiger_t(pos, player ); gr->obj_add(mark); mark->set_image(get_marker_image()); marked.insert(mark); } return gr != NULL; } image_id tool_exec_two_click_script_t::get_marker_image() const { return marker != IMG_EMPTY ? marker : (cursor != IMG_EMPTY ? cursor : skinverwaltung_t::bauigelsymbol->get_image_id(0)); } simutrans-124.3/src/simutrans/tool/simtool-scripted.h000066400000000000000000000110731474050137200230200ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TOOL_SIMTOOL_SCRIPTED_H #define TOOL_SIMTOOL_SCRIPTED_H #include "../tool/simmenu.h" #include "../script/script.h" #include "../utils/plainstring.h" class script_vm_t; class skin_desc_t; /** * Information about scripted tools, extracted from description.tab. * - data from description.tab: * * plainstring path * plainstring title=tool for test 2 * bool type=one_click or two_click * bool restart=1 * plainstring menu=my_script * skin_desc_t* icon=one_click_test: cursor, icon, marker * * @ingroup squirrel-tool-api * */ struct scripted_tool_info_t { plainstring path; ///< path to files plainstring title; ///< name of tool (used for dialog) plainstring tooltip; plainstring menu_arg; ///< menu name, where this tool should appear (used in menuconf.tab) const skin_desc_t* desc; ///< skin object used for cursor (0), icon (1), and maybe marker (2) bool restart; ///< true, if script vm has to be restarted after work() bool is_one_click; ///< true, if tool is one-click (otherwise needs two clicks/coordinates to work) koord cursor_area; ///< size of cursor defined in tool_t koord cursor_offset; ///< cursor offset defined in tool_t /// sets default values scripted_tool_info_t() { desc = NULL; restart = true; is_one_click = true; cursor_area = koord(1,1); cursor_offset = koord(0,0); } }; class exec_script_base_t { private: /// information about tool, take ownership of pointer const scripted_tool_info_t *info; void load_script(const char* path, player_t* player); protected: /// the vm, will be initialized in init() script_vm_t *script; /// starts vm, sets our_player, returns true if successful bool init_vm(player_t* player); template const char* call_function(script_vm_t::call_type_t ct, const char* function, player_t* player, R& ret, const As &... as); public: exec_script_base_t(const scripted_tool_info_t *i) : info(i), script(NULL) {} virtual ~exec_script_base_t(); void set_info(const scripted_tool_info_t *i); const scripted_tool_info_t* get_info() const { return info; } void init_images(tool_t *tool) const; const char* get_menu_arg() const { return info ? info->menu_arg.c_str() : ""; } /// has to be called if the tool is active, to resume script if a work-command gets suspended void step(player_t* player); const char *get_tooltip(const player_t *) const { return info ? info->tooltip.c_str() : ""; } koord get_cursor_area() const { return info->cursor_area; } koord get_cursor_offset() const { return info->cursor_offset; } }; class tool_exec_script_t : public tool_t, public exec_script_base_t { protected: public: tool_exec_script_t(const scripted_tool_info_t *info = NULL); /// is network-safe, as calls to work-commands will be properly handled in network mode bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } bool init(player_t* player) OVERRIDE; bool exit(player_t* player) OVERRIDE; const char *work(player_t* player, koord3d pos) OVERRIDE; const char *get_tooltip(const player_t *pl) const OVERRIDE { return exec_script_base_t::get_tooltip(pl); } }; class tool_exec_two_click_script_t : public two_click_tool_t, public exec_script_base_t { image_id marker; public: tool_exec_two_click_script_t(const scripted_tool_info_t *info = NULL); /// is network-safe, as calls to work-commands will be properly handled in network mode bool is_work_keeps_game_state() const OVERRIDE { return true; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool init(player_t* player) OVERRIDE; bool exit(player_t* player) OVERRIDE; uint8 is_valid_pos(player_t* player, const koord3d &pos, const char *&error, const koord3d &start) OVERRIDE; const char *do_work(player_t* player, const koord3d &start, const koord3d &end) OVERRIDE; void mark_tiles(player_t* player, const koord3d &start, const koord3d &end) OVERRIDE; bool mark_tile(player_t* player, const koord3d &start); // two_click_tool_t calls init() after do_work(), // because it assumes all work is done. // We have to block this. bool waiting_for_do_work; // instead, init() will be called in step() // if necessary bool needs_call_to_init; void set_marker(image_id m) { marker = m; } virtual image_id get_marker_image() const OVERRIDE; const char *get_tooltip(const player_t *pl) const OVERRIDE { return exec_script_base_t::get_tooltip(pl); } }; #endif simutrans-124.3/src/simutrans/tool/simtool.cc000066400000000000000000007761371474050137200213660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "../simdebug.h" #include "../simevent.h" #include "../world/simcity.h" #include "../simmesg.h" #include "../simconvoi.h" #include "../gui/simwin.h" #include "../display/viewport.h" #include "../builder/fabrikbauer.h" #include "../builder/vehikelbauer.h" #include "../ground/grund.h" #include "../ground/wasser.h" #include "../obj/way/schiene.h" #include "../ground/tunnelboden.h" #include "../ground/monorailboden.h" #include "../obj/depot.h" #include "../simfab.h" #include "../display/simimg.h" #include "../simintr.h" #include "../simhalt.h" #include "../simskin.h" #include "../descriptor/ground_desc.h" #include "../descriptor/building_desc.h" #include "../descriptor/roadsign_desc.h" #include "../descriptor/tunnel_desc.h" #include "../vehicle/air_vehicle.h" #include "../vehicle/simroadtraffic.h" #include "../vehicle/pedestrian.h" #include "../gui/line_management_gui.h" #include "../gui/tool_selector.h" #include "../gui/station_building_select.h" #include "../gui/minimap.h" // to update map after construction of new industry #include "../gui/depot_frame.h" #include "../gui/player_frame.h" #include "../gui/scenario_info.h" #include "../gui/schedule_list.h" #include "../gui/signal_spacing.h" #include "../gui/city_info.h" #include "../gui/trafficlight_info.h" #include "../gui/privatesign_info.h" #include "../gui/messagebox.h" #include "../obj/zeiger.h" #include "../obj/bruecke.h" #include "../obj/tunnel.h" #include "../obj/groundobj.h" #include "../obj/signal.h" #include "../obj/crossing.h" #include "../obj/roadsign.h" #include "../obj/wayobj.h" #include "../obj/leitung2.h" #include "../obj/baum.h" #include "../obj/field.h" #include "../obj/label.h" #include "../dataobj/koord.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/schedule.h" #include "../dataobj/route.h" #include "../dataobj/scenario.h" #include "../network/network_cmd_ingame.h" // for dragging raise / lower tools #include "../builder/tunnelbauer.h" #include "../builder/brueckenbauer.h" #include "../builder/wegbauer.h" #include "../builder/hausbauer.h" #include "../descriptor/way_desc.h" #include "../descriptor/roadsign_desc.h" #include "../tpl/vector_tpl.h" #include "../network/memory_rw.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../tool/simtool.h" #include "../player/finance.h" #define is_scenario() welt->get_scenario()->is_scripted() #define CHECK_FUNDS() \ /* do not allow, if out of money */ \ if( !welt->get_settings().is_freeplay() && player->get_player_nr()!=1 && !player->has_money_or_assets() ) {\ return "Out of funds";\ }\ /****************************************** notification strings **************************************/ /** * Translated notification text identifiers used by tools are placed here. * This is because they are not simple well structured internal identifiers. * Instead they can be complex sentences intended to be read untranslated. * Using these constants assues a valid and correct text identifier is choosen. */ /** * Message returned when a player cannot afford to complete an action. */ static const char *const NOTICE_INSUFFICIENT_FUNDS = "Insufficient funds!"; /** * Message returned when a player tries to place trees when trees are disabled. */ static const char *const NOTICE_NO_TREES = "Trees disabled!"; /** * Message returned when valid terrain cannot be found for a tool to use. */ static const char *const NOTICE_UNSUITABLE_GROUND = "No suitable ground!"; /** * Message returned when a tool fails due to the target tile being occupied. */ static const char *const NOTICE_TILE_FULL = "Tile not empty."; /** * Message returned when a company tries to make a public way when public ways are disabled. */ static const char *const NOTICE_DISABLED_PUBLIC_WAY = "Not allowed to make publicly owned ways!"; /****************************************** static helper functions **************************************/ size_t strncopy_to_break( char *dest, const char *src, size_t n ) { const char *p = src; for( size_t i=0; ((uint8)*p)>=32 && iscale_with_month_length(maintenance) ) / 100.0); strcat(tool_t::toolstr, translator::translate("/month")); return tool_t::toolstr; } /** * Creates a tooltip from tip text and money value */ static char const* tooltip_with_price_maintenance_capacity(karte_t* const welt, char const* const tip, sint64 const price, sint64 const maintenance, uint32 const capacity, uint8 const enables) { int n = strncopy_to_break( tool_t::toolstr, translator::translate( tip ), 256 ); memcpy( tool_t::toolstr+n, ", ", 2 ); money_to_string(tool_t::toolstr+n+2, (double)price/-100.0); strcat( tool_t::toolstr, "+" ); n = strlen(tool_t::toolstr); money_to_string(tool_t::toolstr+n, (double)(welt->scale_with_month_length(maintenance) ) / 100.0); strcat(tool_t::toolstr, translator::translate("/month")); n = strlen(tool_t::toolstr); if((enables&7)!=0) { n += sprintf( tool_t::toolstr+n, ", %d", capacity ); if(enables&1) { n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Passagiere") ); } if(enables&2) { n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Post") ); } if(enables&4) { n += sprintf( tool_t::toolstr+n, " %s", translator::translate("Fracht") ); } } else if (!welt->get_settings().is_separate_halt_capacities()) { n += sprintf( tool_t::toolstr+n, ", %s %d", translator::translate("Storage capacity"), capacity ); } return tool_t::toolstr; } void open_error_msg_win(const char* error) { koord3d pos = message_t::get_coord_from_text(error); if (pos != koord3d::invalid) { create_win( new news_loc(error, pos), w_time_delete, magic_none); } else { create_win( new news_img(error), w_time_delete, magic_none); } } /** * sucht Haltestelle um Umkreis +1/-1 um (pos, b, h) * extended to search first in our direction */ static halthandle_t suche_nahe_haltestelle(player_t *player, karte_t *welt, koord3d pos, sint16 b=1, sint16 h=1) { koord k(pos.get_2d()); // any other ground with a valid stop here? halthandle_t my_halt; if( planquadrat_t* plan=welt->access(pos.get_2d()) ) { my_halt = plan->get_halt( player ); if( my_halt.is_bound() ) { return my_halt; } } grund_t *bd = welt->lookup(pos); if( bd==NULL ) { bd = welt->lookup_kartenboden(k); } // first we try to connect to a stop straight in our direction; otherwise our station may break during construction if( bd->hat_wege() ) { ribi_t::ribi ribi = bd->get_weg_nr(0)->get_ribi_unmasked(); for( int i=0; i<4; i++ ) { if( ribi_t::nesw[i] & ribi ) { if( planquadrat_t* plan=welt->access(k+koord::nesw[i]) ) { my_halt = plan->get_halt( player ); if( my_halt.is_bound() ) { return my_halt; } } } } } // now just search all neighbours for( sint16 y=-1; y<=h; y++ ) { for( sint16 x=-1; x<=b; (x==-1 && y>-1 && yaccess(k+koord(x,y)) ) { my_halt = plan->get_halt( player ); if( my_halt.is_bound() ) { return my_halt; } } } } #ifdef AUTOJOIN_PUBLIC // now search everything for public stops for( int i=0; i<8; i++ ) { if( planquadrat_t* plan=welt->access(k+koord::neighbours[i]) ) { my_halt = plan->get_halt( welt->get_public_player() ); if( my_halt.is_bound() ) { return my_halt; } } } #endif // here we reach only with a non-found station, i.e. a non-bounded handle return halthandle_t(); } // converts a 2d koord to a suitable ground pointer static grund_t *tool_intern_koord_to_weg_grund(player_t *player, karte_t *welt, koord3d pos, waytype_t wt) { // check for valid ground grund_t *gr=welt->lookup(pos); if (gr==NULL) { return NULL; } if( wt==powerline_wt && gr->get_leitung() ) { // check for ownership if(gr->get_leitung()->get_removal_error(player)!=NULL) { return NULL; } // ok else { return gr; } } // tram if(wt==tram_wt) { weg_t *way = gr->get_weg(track_wt); if (way && way->get_desc()->get_styp() == type_tram && way->get_removal_error(player)==NULL) { return gr; } else { return NULL; } } // has some rail or monorail? if( !gr->hat_weg(wt) ) { return NULL; } // check for ownership if(gr->get_weg(wt)->get_removal_error(player)!=NULL){ return NULL; } // ok, now we have a valid ground return gr; } /****************************************** now the actual tools **************************************/ const char *tool_query_t::work( player_t *, koord3d pos ) { grund_t *gr = welt->lookup(pos); minivec_tplinfo; if(gr) { // not single_info: show least important first minivec_tplconvois; const bool reverse = is_ctrl_pressed(); // iterate through different stages of importance const uint8 max_stages = 5; for(uint8 stage = 0; stage<5; stage++) { uint32 old_count = win_get_open_count(); switch (reverse ? max_stages-1-stage: stage) { case 0: // halts if( gr->get_halt().is_bound() ) { gr->get_halt()->open_info_window(); if (old_count < win_get_open_count()) { info.append(win_get_top()); } } break; case 1: // labels if( gr->get_flag(grund_t::marked) ) { if(label_t *lb = gr->find()) { lb->show_info(); if( old_count < win_get_open_count() ) { info.append(win_get_top()); } } } break; case 2: // convois for (uint8 n = gr->obj_count(); n-- != 0;) { obj_t* obj = gr->obj_bei(reverse ? gr->obj_count() - 1 - n : n); if (vehicle_t* veh = dynamic_cast(obj)) { convois.append_unique(veh->get_convoi()->self); } } for (uint8 n = 0; n < convois.get_count(); n++) { convois[n]->open_info_window(); if (old_count < win_get_open_count()) { if (env_t::single_info) { return NULL; } info.append(win_get_top()); } } break; case 3: // objects for (uint8 n = gr->obj_count(); n-- != 0;) { obj_t* obj = gr->obj_bei(reverse ? gr->obj_count() - 1 - n : n); if (dynamic_cast(obj)) { // already openend them continue; } if (obj && obj->get_typ() != obj_t::wayobj && obj->get_typ() != obj_t::pillar && obj->get_typ() != obj_t::label) { DBG_MESSAGE("tool_query_t()", "index %u", (unsigned)n); obj->show_info(); // did some new window open? if (old_count < win_get_open_count()) { if (env_t::single_info) { return NULL; } info.append(win_get_top()); } old_count = win_get_open_count(); // click may have closed a window, open a new one if possible } } break; case 4: default: // ground gr->open_info_window(); if (old_count < win_get_open_count()) { info.append(win_get_top()); } break; } if( env_t::single_info && !info.empty()) { return NULL; } if(stage==2 && !info.empty()) { // we have a station, label or convois => do not show roads until next click break; } } } if (info.get_count() == 2) { scr_coord pos = welt->get_viewport()->get_screen_coord(gr->get_pos()); // try to tile the windows win_set_pos(info[0], pos - scr_size(info[0]->get_windowsize().w,info[0]->get_windowsize().h/2)); win_set_pos(info[1], pos - scr_size(0, info[1]->get_windowsize().h/2)); } else if (info.get_count() > 2) { scr_coord pos = welt->get_viewport()->get_screen_coord(gr->get_pos()); // try to tile the windows win_set_pos(info[0], pos - info[0]->get_windowsize()); win_set_pos(info[1], pos - scr_size(0, info[1]->get_windowsize().h)); win_set_pos(info[2], pos - scr_size(info[2]->get_windowsize().w,0)); if (info.get_count() > 3) { win_set_pos(info[3], pos); } // the rest will sit on top of each other } return NULL; } /* delete things from a tile * citycars and pedestrian first and then go up to queue to more important objects */ bool tool_remover_t::tool_remover_intern(player_t *player, koord3d pos, sint8 type, const char *&msg) { DBG_MESSAGE("tool_remover_intern()","at (%s)", pos.get_str()); // check if there is something to remove from here ... grund_t *gr = welt->lookup(pos); if (!gr || gr->obj_count()==0) { msg = ""; return false; } // marker? if (type == obj_t::label || type == obj_t::undefined) { if (label_t* l = gr->find()) { msg = l->get_removal_error(player); if(msg==NULL) { delete l; return true; } else if( gr->obj_count()==1 || type == obj_t::label ) { // only complain if this is the last object on this tile ... return false; } msg = NULL; // not deletable: skip it } } // citycar? (we allow always) if (type == obj_t::road_user || type == obj_t::undefined) { if (private_car_t* citycar = gr->find()) { delete citycar; return true; } } // pedestrians only delete on demand! if (type == obj_t::pedestrian) { if (pedestrian_t* pedestrian = gr->find()) { delete pedestrian; return true; } } koord k(pos.get_2d()); // check powerline (can cross ground of another player) leitung_t* lt = gr->get_leitung(); // check whether powerline related stuff should be removed, and if there is any to remove if ( (type == obj_t::leitung || type == obj_t::pumpe || type == obj_t::senke || type == obj_t::undefined) && lt != NULL && lt->get_removal_error(player) == NULL) { if( gr->ist_bruecke() ) { bruecke_t* br = gr->find(); if( br == NULL ) { // no bridge? most likely transformer on a former bridge tile... grund_t *gr_new = new boden_t(pos, gr->get_grund_hang()); gr_new->take_obj_from( gr ); welt->access(k)->kartenboden_setzen( gr_new ); gr = gr_new; } else if( br->get_desc()->get_waytype() == powerline_wt ) { msg = bridge_builder_t::remove(player, gr->get_pos(), powerline_wt ); return msg == NULL; } } if(gr->ist_tunnel() && gr->ist_karten_boden()) { if (gr->find()->get_desc()->get_waytype()==powerline_wt) { msg = tunnel_builder_t::remove(player, gr->get_pos(), powerline_wt, is_ctrl_pressed() ); return msg == NULL; } } if( gr->ist_im_tunnel() ) { lt->cleanup(player); delete lt; // now everything gone? if( gr->obj_count() == 1 ) { // delete tunnel too tunnel_t *t = gr->find(); t->cleanup(player); delete t; } // unmark kartenboden (is marked during underground mode deletion) welt->lookup_kartenboden(k)->clear_flag(grund_t::marked); // remove upper or lower ground welt->access(k)->boden_entfernen(gr); delete gr; } else { lt->cleanup(player); delete lt; } return true; } // check for signal roadsign_t* rs = gr->find(); if (rs == NULL) rs = gr->find(); if ( (type == obj_t::signal || type == obj_t::roadsign || type == obj_t::undefined) && rs!=NULL) { msg = rs->get_removal_error(player); if(msg) { return false; } DBG_MESSAGE("tool_remover()", "removing roadsign at (%s)", pos.get_str()); weg_t *weg = gr->get_weg(rs->get_desc()->get_wtyp()); if( weg==NULL && rs->get_desc()->get_wtyp()==tram_wt ) { weg = gr->get_weg(track_wt); } rs->cleanup(player); delete rs; // no need to update way if there is none // may happen when public player builds a signal on a company track, // the company goes bankrupt and the public player tries to remove the signal if (weg) { weg->count_sign(); } return true; } // check stations halthandle_t halt = gr->get_halt(); DBG_MESSAGE("tool_remover()", "bound=%i",halt.is_bound()); if (gr->is_halt() && halt.is_bound() && fabrik_t::get_fab(k)==NULL && type == obj_t::undefined) { // halt and not a factory (oil rig etc.) const player_t* owner = halt->get_owner(); if( player_t::check_owner( owner, player ) ) { return haltestelle_t::remove(player, gr->get_pos()); } } // catenary or something like this wayobj_t* wo = gr->find(); if(wo && (type == obj_t::wayobj || type == obj_t::undefined)) { msg = wo->get_removal_error(player); if(msg) { return false; } wo->cleanup(player); delete wo; depot_t *dep = gr->get_depot(); if( dep ) { dep->update_win(); } return true; } DBG_MESSAGE("tool_remover()", "check tunnel/bridge"); // bridge? if(gr->ist_bruecke() && (type == obj_t::bruecke || type == obj_t::undefined)) { DBG_MESSAGE("tool_remover()", "removing bridge from %d,%d,%d",gr->get_pos().x, gr->get_pos().y, gr->get_pos().z); bruecke_t* br = gr->find(); msg = bridge_builder_t::remove(player, gr->get_pos(), br->get_desc()->get_waytype()); return msg == NULL; } // beginning/end of tunnel if(gr->ist_tunnel() && gr->ist_karten_boden() && (type == obj_t::tunnel || type == obj_t::undefined)) { DBG_MESSAGE("tool_remover()", "removing tunnel from %d,%d,%d",gr->get_pos().x, gr->get_pos().y, gr->get_pos().z); waytype_t wegtyp = gr->get_leitung() ? powerline_wt : gr->get_weg_nr(0)->get_waytype(); msg = tunnel_builder_t::remove(player, gr->get_pos(), wegtyp, is_ctrl_pressed()); return msg == NULL; } // fields field_t* f = gr->find(); if (f && (type == obj_t::field || type == obj_t::undefined)) { msg = f->get_removal_error(player); if(msg==NULL) { f->cleanup(player); delete f; // fields have foundations ... sint8 dummy; welt->access(k)->boden_ersetzen( gr, new boden_t(gr->get_pos(), welt->recalc_natural_slope(k,dummy) ) ); welt->lookup_kartenboden(k)->calc_image(); welt->lookup_kartenboden(k)->set_flag( grund_t::dirty ); } return msg == NULL; } // depots depot_t* dep = gr->get_depot(); if (dep && (type == obj_t::bahndepot || type == obj_t::undefined)) { // type == bahndepot to remove any type of depot msg = dep->get_removal_error(player); if(msg) { return false; } dep->cleanup(player); delete dep; return true; } // since buildings can have more than one tile, we must handle them together gebaeude_t* gb = gr->find(); if(gb != NULL && (type == obj_t::gebaeude || type == obj_t::undefined)) { gb = gb->get_first_tile(); msg = gb->get_removal_error(player); if(msg) { return false; } if(!gb->get_tile()->get_desc()->can_rotate() && welt->cannot_save()) { msg = "Not possible in this rotation!"; return false; } DBG_MESSAGE("tool_remover()", "removing building" ); // remove town? (when removing townhall) if(gb->is_townhall()) { stadt_t *stadt = welt->find_nearest_city(k); if(!welt->remove_city( stadt )) { msg = "Das Feld gehoert\neinem anderen Spieler\n"; return false; } } else { // townhall is also removed during town removal hausbauer_t::remove( player, gb ); } return true; } // if type is given, then last check and leave here. Below other stuff and ways gets removed. if (type != obj_t::undefined) { for (uint i = 0; i < gr->obj_count(); i++) { obj_t* obj = gr->obj_bei(i); if (obj->get_typ() == type && player_t::check_owner(obj->get_owner(),player)) { msg = obj->get_removal_error(player); if (msg) { return false; } delete obj; return true; } } msg = "Requested object not found."; return false; } // there is a powerline above this tile, but we do not own it // so we take it out and add it later again if(lt) { DBG_MESSAGE("tool_remover()", "took out powerline"); gr->obj_remove(lt); } // do not delete crossing, labels, pointer and flying airplanes, so we store them minivec_tplstuff_to_keep; if (obj_t* obj = gr->find()) { stuff_to_keep.append(obj); gr->obj_remove(obj); } if (obj_t* obj = gr->find()) { stuff_to_keep.append(obj); gr->obj_remove(obj); } if (obj_t* obj = gr->find()) { stuff_to_keep.append(obj); gr->obj_remove(obj); } while(obj_t* obj = gr->find()) { stuff_to_keep.append(obj); gr->obj_remove(obj); } // remove all other stuff (clouds, ...) bool return_ok = false; uint8 num_obj = gr->obj_count(); if(num_obj>0) { // cout all pedestrians and ignore them int num_pedestrians = 0; for (int i = 1; i < num_obj; i++) { if (gr->obj_bei(i)->get_typ() == obj_t::pedestrian) { num_pedestrians++; } } // only delete everything if there is more than pedestrians to delete if (num_obj > num_pedestrians) { msg = gr->kann_alle_obj_entfernen(player); return_ok = (msg == NULL && !(gr->get_typ() == grund_t::brueckenboden || gr->get_typ() == grund_t::tunnelboden) && gr->obj_loesche_alle(player)); DBG_MESSAGE("tool_remover()", "removing everything from %d,%d,%d", gr->get_pos().x, gr->get_pos().y, gr->get_pos().z); } } for (int i=0; i < stuff_to_keep.get_count(); i++) { gr->obj_add(stuff_to_keep[i]); } // could not delete everything if(msg) { if (lt) gr->obj_add(lt); return false; } if(return_ok) { // no sound msg = ""; if (lt) gr->obj_add(lt); return true; } // ok, now we remove every object that should be removed - one by one. // the following objects will be removed together DBG_MESSAGE("tool_remover()", "removing way"); waytype_t wt = ignore_wt; if(gr->get_typ()!=grund_t::tunnelboden || gr->has_two_ways()) { weg_t *w = gr->get_weg_nr(1); if(gr->get_typ()==grund_t::brueckenboden && w==NULL) { // do not delete the middle of a bridge if (lt) gr->obj_add(lt); return false; } if( w && w->get_waytype()==water_wt ) { // remove the other way first w = NULL; } if(w==NULL || w->get_removal_error(player)!=NULL) { w = gr->get_weg_nr(0); if(w==NULL) { if (lt) { gr->obj_add(lt); msg = lt->get_removal_error(player); return false; } else { // no way at all ... return true; } } if(const char *err = w->get_removal_error(player)){ msg = err; if (lt) gr->obj_add(lt); return false; } } wt = w->get_desc()->get_finance_waytype(); sint32 cost_sum = gr->weg_entfernen(w->get_waytype(), true); player_t::book_construction_costs(player, -cost_sum, k, wt); } else { // remove ways and tunnel if( weg_t *weg = gr->get_weg_nr(0) ) { gr->remove_everything_from_way(player, weg->get_waytype(), ribi_t::none); } // tunnel without way: delete anything else if( !gr->hat_wege() ) { gr->obj_loesche_alle(player); if (gr->get_typ() == boden_t::tunnelboden && gr->ist_karten_boden()) { grund_t* gr_new = new boden_t(gr->get_pos(), gr->get_grund_hang()); welt->access(gr_new->get_pos().get_2d())->kartenboden_setzen(gr_new); gr = gr_new; } } } if (lt) gr->obj_add(lt); // remove empty tile if( !gr->ist_karten_boden() && gr->obj_count()==0 ) { // unmark kartenboden (is marked during underground mode deletion) welt->lookup_kartenboden(k)->clear_flag(grund_t::marked); // remove upper or lower ground welt->access(k)->boden_entfernen(gr); delete gr; } return true; } const char *tool_remover_t::work( player_t *player, koord3d pos ) { DBG_MESSAGE("tool_remover()","at %d,%d", pos.x, pos.y); obj_t::typ type = obj_t::undefined; if (default_param) { int t = atoi(default_param); if (t != 0 && -1 <= t && t <= 200) { type = (obj_t::typ)t; } } const char *fail = NULL; if(!tool_remover_intern(player, pos, type, fail)) { return fail; } // must recalc neighbourhood for slopes etc. if(pos.x>1) { welt->lookup_kartenboden(pos.get_2d()+koord::west)->calc_image(); } if(pos.y>1) { welt->lookup_kartenboden(pos.get_2d()+koord::north)->calc_image(); } if(pos.xget_size().x-1) { welt->lookup_kartenboden(pos.get_2d()+koord::east)->calc_image(); } if(pos.yget_size().y-1) { welt->lookup_kartenboden(pos.get_2d()+koord::south)->calc_image(); } return NULL; } const char *tool_change_owner_t::work( player_t *pl, koord3d pos ) { grund_t *gr = welt->lookup(pos); minivec_tplinfo; if(gr) { int idx=0, new_pl_id; if(!default_param || !*default_param) { // needs default string with "new_player_id[,tile_index]" return ""; } else { new_pl_id = atoi(default_param); if (const char* c = strchr(default_param, 'r')) { idx = atoi(c+1); } } player_t* new_pl = welt->get_player(new_pl_id); if( obj_t *obj = gr->obj_bei(idx)) { if(obj->is_moving()) { // cannot change ownership of moving stuff return "Der Besitzer erlaubt das Entfernen nicht"; } if(player_t::check_owner(pl,obj->get_owner())) { // we may have mainenance waytype_t wt = obj->get_waytype(); sint64 maintenance = 0; if (bruecke_t* b = dynamic_cast(obj)) { maintenance = b->get_desc()->get_maintenance(); wt = b->get_desc()->get_finance_waytype(); } else if (gebaeude_t* g = dynamic_cast(obj)) { // incudes depots maintenance = g->get_tile()->get_desc()->get_maintenance(welt); } else if (tunnel_t* t = dynamic_cast(obj)) { maintenance = t->get_desc()->get_maintenance(); wt = t->get_desc()->get_finance_waytype(); } else if (weg_t* w = dynamic_cast(obj)) { maintenance = w->get_desc()->get_maintenance(); wt = w->get_desc()->get_finance_waytype(); } if(maintenance) { // transfer maintenance player_t::add_maintenance(obj->get_owner(), -maintenance, wt); player_t::add_maintenance(new_pl, maintenance, wt); } obj->set_owner(new_pl); return NULL; } return "Der Besitzer erlaubt das Entfernen nicht"; } return ""; } return "No suitable ground!"; } const char *tool_raise_lower_base_t::move( player_t *player, uint16 buttonstate, koord3d pos ) { CHECK_FUNDS(); const char *result = NULL; if( buttonstate==1 ) { char buf[16]; if(!is_dragging) { drag_height = get_drag_height(pos.get_2d()); } is_dragging = true; sprintf( buf, "%i", drag_height ); default_param = buf; if (env_t::networkmode) { // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false); network_send_server(nwc); } else { result = work( player, pos ); } default_param = NULL; } return result; } const char* tool_raise_lower_base_t::drag(player_t *player, koord k, sint16 height, int &n) { if( !welt->is_within_grid_limits(k) ) { return ""; } const char* err = NULL; // dragging may be going up or down! while( welt->lookup_hgt(k) < height && height <= welt->get_max_allowed_height() ) { int diff = welt->grid_raise( player, k, err ); if( diff == 0 ) { break; } n += diff; } // when going down need to check here we will not be going below sea level // cannot rely on check within lower as water height can be recalculated while( height >= welt->get_water_hgt(k) && welt->lookup_hgt(k) > height && height >= welt->get_min_allowed_height() ) { int diff = welt->grid_lower( player, k, err ); if( diff == 0 ) { break; } n += diff; } return err; //height == welt->lookup_hgt(k); } bool tool_raise_lower_base_t::check_dragging() { // reset dragging if( is_dragging && strempty(default_param) ) { is_dragging = false; return false; } return true; } sint16 tool_raise_t::get_drag_height(koord k) { const grund_t *gr = welt->lookup_kartenboden_gridcoords(k); return gr->get_hoehe(welt->get_corner_to_operate(k)) + 1; } const char *tool_raise_t::check_pos(player_t *, koord3d pos ) { // check for underground mode if( is_dragging && drag_height-1 > grund_t::underground_level ) { is_dragging = false; return ""; } if( !welt->is_within_grid_limits(pos.get_2d()) ) { return ""; } sint8 h = (sint8) get_drag_height(pos.get_2d()); if( h > grund_t::underground_level ) { return "Terraforming not possible\nhere in underground view"; } return NULL; } const char *tool_raise_t::work(player_t* player, koord3d pos ) { if (!check_dragging()) { return NULL; } const char* err = NULL; koord k = pos.get_2d(); CHECK_FUNDS(); if(welt->is_within_grid_limits(k)) { const sint8 hgt = (sint8) get_drag_height(k); if( hgt <= welt->get_max_allowed_height() ) { int n = 0; // tiles changed if( !strempty(default_param) ) { // called by dragging or by AI err = drag(player, k, atoi(default_param), n); } else { n = welt->grid_raise(player, k, err); } if(n>0) { player_t::book_construction_costs(player, welt->get_settings().cst_alter_land * n, k, ignore_wt); } return err == NULL ? (n ? NULL : "") : (*err == 0 ? NOTICE_TILE_FULL : err); } else { // no mountains higher than welt->get_maximumheight() ... return "Maximum tile height difference reached."; } } return "Zu nah am Kartenrand"; } sint16 tool_lower_t::get_drag_height(koord k) { const grund_t *gr = welt->lookup_kartenboden_gridcoords(k); return gr->get_hoehe(welt->get_corner_to_operate(k)) - 1; } const char *tool_lower_t::check_pos( player_t *, koord3d pos ) { // check for underground mode if (is_dragging && drag_height+1 > grund_t::underground_level) { is_dragging = false; return ""; } if (! welt->is_within_grid_limits(pos.get_2d())) { return ""; } sint8 h = (sint8) get_drag_height(pos.get_2d()); if (h > grund_t::underground_level) { return "Terraforming not possible\nhere in underground view"; } return NULL; } const char *tool_lower_t::work( player_t *player, koord3d pos ) { if (!check_dragging()) { return NULL; } const char* err = NULL; koord k = pos.get_2d(); CHECK_FUNDS(); if(welt->is_within_grid_limits(k)) { const sint8 hgt = (sint8) get_drag_height(k); if( hgt >= welt->get_water_hgt( k ) ) { int n = 0; // tiles changed if (!strempty(default_param)) { // called by dragging or by AI err = drag(player, k, atoi(default_param), n); } else { n = welt->grid_lower(player, k, err); } if(n>0) { player_t::book_construction_costs(player, welt->get_settings().cst_alter_land * n, k, ignore_wt); } return err == NULL ? (n ? NULL : "") : (*err == 0 ? NOTICE_TILE_FULL : err); } else { // below water level return ""; } } return "Zu nah am Kartenrand"; } const char *tool_setslope_t::check_pos( player_t *, koord3d pos) { grund_t *gr1 = welt->lookup(pos); if(gr1) { // check for underground mode if( grund_t::underground_mode == grund_t::ugm_all && !gr1->ist_tunnel() ) { return "Terraforming not possible\nhere in underground view"; } } else { return ""; } return NULL; } const char *tool_restoreslope_t::check_pos( player_t *, koord3d pos) { grund_t *gr1 = welt->lookup(pos); if(gr1) { // check for underground mode if( grund_t::underground_mode == grund_t::ugm_all && !gr1->ist_tunnel() ) { return "Terraforming not possible\nhere in underground view"; } } else { return ""; } return NULL; } void tool_setslope_t::rdwr_custom_data(memory_rw_t *packet) { tool_t::rdwr_custom_data(packet); packet->rdwr_bool(old_slope_compatibility_mode); } const char *tool_setslope_t::tool_set_slope_work( player_t *player, koord3d pos, int new_slope, bool old_slope_compatibility, bool just_check ) { if( !ground_desc_t::double_grounds && !old_slope_compatibility ) { // do not build double slopes if no graphics are available if (slope_t::max_diff(new_slope) > 1) { return ""; // invalid parameter } } if( !ground_desc_t::double_grounds && old_slope_compatibility ) { // translate old single slope parameter to new double slope if( 0 < new_slope && new_slope < ALL_UP_SLOPE_SINGLE ) { new_slope = slope_from_slope4(slope4_t(new_slope), 1); } else { switch( new_slope ) { case ALL_UP_SLOPE: case ALL_UP_SLOPE_SINGLE: new_slope = ALL_UP_SLOPE; break; case ALL_DOWN_SLOPE: case ALL_DOWN_SLOPE_SINGLE: new_slope = ALL_DOWN_SLOPE; break; case RESTORE_SLOPE: case RESTORE_SLOPE_SINGLE: new_slope = RESTORE_SLOPE; break; default: return ""; // invalid parameter } } } bool ok = false; grund_t *gr1 = welt->lookup(pos); if( gr1 ) { if( gr1->ist_im_tunnel() ) { switch( new_slope ) { case ALL_UP_SLOPE: case ALL_UP_SLOPE_SINGLE: case ALL_DOWN_SLOPE: case ALL_DOWN_SLOPE_SINGLE: case RESTORE_SLOPE: case RESTORE_SLOPE_SINGLE: break; default: return "Only up and down movement in the underground!"; // invalid parameter } } koord k(pos.get_2d()); sint8 water_hgt = welt->get_water_hgt( k ); const uint8 max_hdiff = ground_desc_t::double_grounds ? 2 : 1; if(new_slope==ALL_DOWN_SLOPE && pos.z-1get_min_allowed_height() ) { return "Maximum tile height difference reached."; } // at least a pixel away from the border? if( pos.z < water_hgt && !gr1->ist_tunnel() ) { return "Maximum tile height difference reached."; } if( new_slope==RESTORE_SLOPE && !(gr1->get_typ()==grund_t::boden || gr1->get_typ()==grund_t::wasser) ) { return NOTICE_UNSUITABLE_GROUND; } // finally: empty enough if( gr1->get_grund_hang()!=gr1->get_weg_hang() || gr1->get_halt().is_bound() || gr1->kann_alle_obj_entfernen(player) || gr1->find() || gr1->get_depot() || (gr1->get_leitung() && gr1->hat_wege()) || gr1->get_weg(air_wt) || gr1->find() || gr1->get_typ()==grund_t::brueckenboden) { return NOTICE_TILE_FULL; } if( !welt->is_within_limits(k+koord(1,1)) || !welt->is_within_limits(k+koord(-1,-1))) { return "Zu nah am Kartenrand"; } // slopes may affect the position and the total height! koord3d new_pos = pos; if( gr1->hat_wege() || gr1->get_leitung() ) { // check the resulting slope ribi_t::ribi ribis = 0; if( gr1->hat_wege()) { ribis |= gr1->get_weg_nr(0)->get_ribi_unmasked(); if( gr1->get_weg_nr(1) ) { ribis |= gr1->get_weg_nr(1)->get_ribi_unmasked(); } } if( gr1->get_leitung()) { ribis |= gr1->get_leitung()->get_ribi(); } if( new_slope==RESTORE_SLOPE || !ribi_t::is_single(ribis) || (new_slopeget_weg_hang()==slope_t::flat ) { new_slope = slope_type(ribis); } else if( gr1->get_weg_hang() == slope_type(ribis) ) { // check that way_desc supports such steep slopes if( (gr1->get_weg_nr(0) && !gr1->get_weg_nr(0)->get_desc()->has_double_slopes()) || (gr1->get_weg_nr(1) && !gr1->get_weg_nr(1)->get_desc()->has_double_slopes()) || (gr1->get_leitung() && !gr1->get_leitung()->get_desc()->has_double_slopes()) ) { return NOTICE_TILE_FULL; } new_slope = slope_type(ribis) * 2; } else if( gr1->get_weg_hang() == slope_type( ribi_t::backward(ribis) ) * 2 ) { new_pos.z++; if( welt->lookup(new_pos) ) { return NOTICE_TILE_FULL; } new_slope = slope_type( ribi_t::backward(ribis) ); } else if( gr1->get_weg_hang() != slope_type( ribi_t::backward(ribis) ) ) { return "Maximum tile height difference reached."; } } else if( new_slope==ALL_DOWN_SLOPE ) { if( gr1->get_grund_hang()==slope_type(ribis) ) { // do not lower tiles to sea if( pos.z == water_hgt && !gr1->ist_tunnel() ) { return NOTICE_TILE_FULL; } } else if( gr1->get_grund_hang() == slope_type(ribis) * 2 ) { if( pos.z == water_hgt && !gr1->ist_tunnel() ) { return NOTICE_TILE_FULL; } new_slope = slope_type(ribis); } else if( gr1->get_grund_hang() == slope_t::flat ) { new_slope = slope_type( ribi_t::backward(ribis) ); new_pos.z--; if( welt->lookup(new_pos) ) { return NOTICE_TILE_FULL; } } else if( gr1->get_grund_hang() == slope_type( ribi_t::backward(ribis) ) ) { // check that way_desc supports such steep slopes if( (gr1->get_weg_nr(0) && !gr1->get_weg_nr(0)->get_desc()->has_double_slopes()) || (gr1->get_weg_nr(1) && !gr1->get_weg_nr(1)->get_desc()->has_double_slopes()) || (gr1->get_leitung() && !gr1->get_leitung()->get_desc()->has_double_slopes()) ) { return NOTICE_TILE_FULL; } new_slope = slope_type( ribi_t::backward(ribis) ) * 2; new_pos.z--; if( welt->lookup(new_pos) ) { return NOTICE_TILE_FULL; } } else { return "Maximum tile height difference reached."; } } } if( new_slope == ALL_DOWN_SLOPE || new_slope == RESTORE_SLOPE ) { if( new_slope == RESTORE_SLOPE ) { // special action: set to natural slope sint8 min_hgt; new_slope = welt->recalc_natural_slope( k, min_hgt ); new_pos = koord3d( k, min_hgt ); DBG_MESSAGE("natural_slope","%i",new_slope); } else { new_slope = slope_t::flat; // is more intuitive: if there is a slope, first downgrade it if( gr1->get_grund_hang() == 0 ) { new_pos.z--; } } // now prevent being lowered below neighbouring water sint8 water_table = (water_hgt >= (gr1->get_hoehe() + (gr1->get_grund_hang() ? 1 : 0))) ? water_hgt : welt->get_groundwater() - 4; sint8 min_neighbour_height = gr1->get_hoehe(); for( sint16 i = 0 ; i < 8 ; i++ ) { const koord neighbour = k + koord::neighbours[i]; if( welt->is_within_grid_limits( neighbour ) ) { grund_t *gr2 = welt->lookup_kartenboden( neighbour ); const sint8 water_hgt_neighbour = welt->get_water_hgt( neighbour ); if( gr2 && (water_hgt_neighbour >= (gr2->get_hoehe() + (gr2->get_grund_hang() ? 1 : 0))) ) { water_table = max( water_table, water_hgt_neighbour ); } if( gr2 && gr2->get_hoehe() < min_neighbour_height ) { min_neighbour_height = gr2->get_hoehe(); } } } if( water_table>new_pos.z || (water_table == new_pos.z && min_neighbour_height < new_pos.z) ) { // do not lower tiles when it will be below water level return NOTICE_TILE_FULL; } welt->set_water_hgt_nocheck( k, water_table ); water_hgt = water_table; } else if( new_slope == ALL_UP_SLOPE ) { new_slope = slope_t::flat; new_pos.z++; } // already some ground here (tunnel, bridge, monorail?) if( new_pos.z != pos.z && welt->lookup(new_pos) != NULL ) { return NOTICE_TILE_FULL; } // check for grounds above / below if( new_pos.z >= pos.z ) { grund_t *gr2 = welt->lookup( new_pos + koord3d(0, 0, 1) ); if( !gr2 ) { gr2 = welt->lookup( new_pos + koord3d(0, 0, 2) ); } if( !gr2 && welt->get_settings().get_way_height_clearance()==2 && (gr1->hat_wege() || gr1->get_leitung()) ) { gr2 = welt->lookup( new_pos + koord3d(0, 0, 3) ); } // slope may alter amount of clearance required if( gr2 && gr2->get_pos().z - new_pos.z + slope_t::min_diff( gr2->get_weg_hang(), new_slope ) < welt->get_settings().get_way_height_clearance() ) { return NOTICE_TILE_FULL; } } if( new_pos.z <= pos.z ) { grund_t *gr2 = welt->lookup( new_pos + koord3d(0, 0, -1) ); if( !gr2 ) { gr2 = welt->lookup( new_pos + koord3d(0, 0, -2) ); } if( !gr2 && welt->get_settings().get_way_height_clearance()==2 ) { gr2 = welt->lookup( new_pos + koord3d(0, 0, -3) ); } // slope may alter amount of clearance required if( gr2 && new_pos.z - gr2->get_pos().z + slope_t::min_diff( new_slope, gr2->get_weg_hang() ) < welt->get_settings().get_way_height_clearance() ) { return NOTICE_TILE_FULL; } } // check, if action is valid ... const sint16 hgt=new_pos.z; // maximum difference check with tiles to north, south east and west const sint8 test_hgt = hgt+(new_slope!=0); if( gr1->get_typ()==grund_t::boden ) { for( sint16 i = 0 ; i < 4 ; i++ ) { const koord neighbour = k + koord::nesw[i]; const grund_t *gr_neighbour=welt->lookup_kartenboden(neighbour); if(gr_neighbour) { const sint16 gr_neighbour_hgt=gr_neighbour->get_hoehe() + (new_slope==ALL_DOWN_SLOPE && gr_neighbour->get_grund_hang()? 1 : 0); const sint8 diff_from_ground = abs(gr_neighbour_hgt-test_hgt); if( diff_from_ground > 2 * max_hdiff ) { return "Maximum tile height difference reached."; } } } } // ok, now we set the slope ... ok = (new_pos!=pos); bool slope_changed = new_slope!=gr1->get_grund_hang(); ok |= slope_changed; if(ok) { // check if clear if( gr1->kann_alle_obj_entfernen(player) ) { return NOTICE_TILE_FULL; } // check way ownership if(gr1->hat_wege()) { if(gr1->get_weg_nr(0)->get_removal_error(player)!=NULL) { return NOTICE_TILE_FULL; } if(gr1->has_two_ways() && gr1->get_weg_nr(1)->get_removal_error(player)!=NULL) { return NOTICE_TILE_FULL; } } // check funds settings_t const& s = welt->get_settings(); sint64 const cost = new_slope == RESTORE_SLOPE ? s.cst_alter_land : s.cst_set_slope; if( !player->can_afford(cost) ) { return NOTICE_INSUFFICIENT_FUNDS; } // one last check if ( gr1->is_water() && (new_pos.z > water_hgt || new_slope != 0) ) { // we have to build underwater hill first if( !welt->can_flatten_tile( player, k, water_hgt, false, true ) ) { return NOTICE_TILE_FULL; } } // all checks passed if (just_check) { return NULL; } // ok, it was a success if( !gr1->is_water() && new_slope == 0 && hgt == water_hgt && gr1->get_typ() != grund_t::tunnelboden ) { // now water gr1->obj_loesche_alle(player); welt->access(k)->kartenboden_setzen( new wasser_t(new_pos) ); gr1 = welt->lookup_kartenboden(k); } else if( gr1->is_water() && (new_pos.z > water_hgt || new_slope != 0) ) { // build underwater hill first if( !welt->flatten_tile( player, k, water_hgt, false, true ) ) { return NOTICE_TILE_FULL; } gr1->obj_loesche_alle(player); welt->access(k)->kartenboden_setzen( new boden_t(new_pos,new_slope) ); gr1 = welt->lookup_kartenboden(k); welt->set_water_hgt_nocheck(k, welt->get_groundwater()-4); } else { gr1->set_grund_hang(new_slope); gr1->set_pos(new_pos); gr1->clear_flag(grund_t::marked); gr1->set_flag(grund_t::dirty); // update new positions if changed if( new_pos!=pos ) { for( int i=0; iobj_count(); i++ ) { gr1->obj_bei(i)->set_pos( new_pos ); } } // correct tree offsets if slope has changed if( slope_changed ) { for( int i=0; iobj_count(); i++ ) { baum_t *tree = obj_cast(gr1->obj_bei(i)); if (tree) { tree->recalc_off(); } } } if( !gr1->ist_karten_boden() ) { gr1->calc_image(); } } // if there is a powerline here we need to treat it as newly built as it may connect to neighbours leitung_t *lt = gr1->get_leitung(); if( lt ) { // remove maintenance for existing powerline player_t::add_maintenance(lt->get_owner(), -lt->get_desc()->get_maintenance(), powerline_wt); lt->finish_rd(); } if( gr1->ist_karten_boden() ) { if( new_slope!=slope_t::flat ) { // no lakes on slopes ... groundobj_t *obj = gr1->find(); if( obj && obj->get_desc()->get_phases()!=16 ) { obj->cleanup(player); delete obj; } // connect canals to sea if( gr1->get_hoehe() == water_hgt && gr1->hat_weg(water_wt) ) { grund_t *sea = welt->lookup_kartenboden(k - koord( ribi_type(new_slope ) )); if (sea && sea->is_water()) { gr1->weg_erweitern(water_wt, ribi_t::backward(ribi_type(new_slope))); sea->calc_image(); } } } // recalc slope walls on neighbours for(int y=-1; y<=1; y++) { for(int x=-1; x<=1; x++) { grund_t *gr = welt->lookup_kartenboden(k+koord(x,y)); gr->calc_image(); } } // correct the grid height if( gr1->is_water() ) { sint8 grid_hgt = min( water_hgt, welt->lookup_hgt( k ) ); welt->set_grid_hgt_nocheck(k, grid_hgt ); } else { welt->set_grid_hgt_nocheck(k, gr1->get_hoehe()+ corner_nw(gr1->get_grund_hang()) ); } minimap_t::get_instance()->calc_map_pixel(k); welt->calc_climate( k, true ); } player_t::book_construction_costs(player, cost, k, ignore_wt); } // update limits if( welt->min_height > gr1->get_hoehe() ) { welt->min_height = gr1->get_hoehe(); } else if( welt->max_height < gr1->get_hoehe() ) { welt->max_height = gr1->get_hoehe(); } } return ok ? NULL : ""; } // set marker const char *tool_marker_t::work( player_t *player, koord3d pos ) { grund_t *gr = welt->lookup_kartenboden(pos.get_2d()); if (gr) { if(!gr->get_text()) { const obj_t* thing = gr->obj_bei(0); if(thing == NULL || thing->get_owner() == player || (player_t::check_owner(thing->get_owner(), player) && (thing->get_typ() != obj_t::gebaeude))) { gr->obj_add(new label_t(gr->get_pos(), player, default_param ? default_param : "\0")); if (can_use_gui()) { gr->find()->show_info(); } return NULL; } } } return "Das Feld gehoert\neinem anderen Spieler\n"; } // show/repair blocks bool tool_clear_reservation_t::init( player_t * ) { if (can_use_gui()) { schiene_t::show_reservations = true; welt->set_dirty(); } return true; } bool tool_clear_reservation_t::exit( player_t * ) { if (can_use_gui()) { schiene_t::show_reservations = false; welt->set_dirty(); } return true; } bool tool_clear_reservation_t::is_selected() const { if (welt->get_tool(welt->get_active_player_nr())==this) { return true; } return false; } const char *tool_clear_reservation_t::work( player_t *, koord3d pos ) { grund_t *gr = welt->lookup(pos); if(gr && gr->hat_wege()) { // first start route search of the convoi here for( uint8 i = 0; i < gr->obj_count(); i++ ) { uint8 typ = gr->obj_bei(i)->get_typ(); if( typ >= obj_t::road_vehicle && typ <= obj_t::air_vehicle ) { vehicle_t *veh = dynamic_cast(gr->obj_bei( i )); if( veh->get_convoi() ) { uint16 state = veh->get_convoi()->get_state(); if( state > convoi_t::EDIT_SCHEDULE ) { veh->get_convoi()->set_state(convoi_t::ROUTING_1); } } } } // then unreserve the current tile for(unsigned wnr=0; wnr<2; wnr++ ) { schiene_t const* const w = obj_cast(gr->get_weg_nr(wnr)); // is this a reserved track? if(w!=NULL && w->is_reserved()) { /* now we do a very crude procedure: * - we search all ways for reservations of this convoi and remove them * - we set the convoi state to ROUTING_1; it must reserve again its ways then */ const waytype_t waytype = w->get_waytype(); const convoihandle_t cnv = w->get_reserved_convoi(); if(cnv->get_state()==convoi_t::DRIVING) { // reset driving state cnv->suche_neue_route(); } for(weg_t* const w : weg_t::get_alle_wege()) { if (w->get_waytype() == waytype) { schiene_t* const sch = obj_cast(w); if (sch->get_reserved_convoi() == cnv) { vehicle_t& v = *cnv->front(); if (!gr->suche_obj(v.get_typ())) { // force free sch->unreserve(&v); } } } } } } } return NULL; } // transformer for electricity supply const char* tool_transformer_t::get_tooltip(const player_t *) const { settings_t const& s = welt->get_settings(); sprintf(toolstr, "%s, %ld$ (%ld$)", translator::translate("Build drain"), (long)(s.cst_transformer / -100), (long)(welt->scale_with_month_length(s.cst_maintain_transformer)) / -100); return toolstr; } image_id tool_transformer_t::get_icon(player_t*) const { return way_builder_t::waytype_available( powerline_wt, welt->get_timeline_year_month() ) ? icon : IMG_EMPTY; } bool tool_transformer_t::init( player_t *) { return way_builder_t::waytype_available( powerline_wt, welt->get_timeline_year_month() ); } const char *tool_transformer_t::check_pos( player_t *, koord3d pos ) { if(grund_t::underground_mode == grund_t::ugm_all && env_t::networkmode) { // clients cannot guess at which height transformer should be build return "Cannot built this station/building\nin underground mode here."; } if(grund_t::underground_mode == grund_t::ugm_level) { // only above or directly under surface // taking into account way clearance requirements grund_t *gr = welt->lookup_kartenboden(pos.get_2d()); return (gr->get_pos() == pos || gr->get_hoehe() == grund_t::underground_level + welt->get_settings().get_way_height_clearance()) ? NULL : ""; } return NULL; } const char *tool_transformer_t::work( player_t *player, koord3d pos ) { DBG_MESSAGE("tool_transformer_t()","called on %d,%d", pos.x, pos.y); koord k(pos.get_2d()); grund_t *gr = welt->lookup_kartenboden(k); if( !welt->get_settings().get_allow_underground_transformers() && pos.z!=gr->get_hoehe() ) { // no underground transformers allowed return "Cannot built this station/building\nin underground mode here."; } bool underground = false; fabrik_t *fab = NULL; // full underground mode: coordinate is on ground, adjust it to one level below ground // not possible in network mode! if (!env_t::networkmode && grund_t::underground_mode == grund_t::ugm_all) { pos = gr->get_pos() - koord3d( 0, 0, welt->get_settings().get_way_height_clearance() ); } // search for factory // must be independent of network mode if (gr->get_pos().z <= pos.z) { fab = leitung_t::suche_fab_4(k); } else if( gr->get_pos().z == pos.z+welt->get_settings().get_way_height_clearance() ) { fab = fabrik_t::get_fab( k); underground = true; } if( !fab ) { return "Transformer only next to factory!"; } if( fab->is_transformer_connected() ) { return "Only one transformer per factory!"; } // underground: first build tunnel tile at coordinate pos if(underground) { if(gr->is_water()) { return "Transformer only next to factory!"; } if(welt->lookup(pos)) { return NOTICE_TILE_FULL; } if( welt->get_settings().get_way_height_clearance()==2 && welt->lookup(pos + koord3d( 0, 0, 1 )) ) { return NOTICE_TILE_FULL; } const tunnel_desc_t *tunnel_desc = tunnel_builder_t::get_tunnel_desc(powerline_wt, 0, 0); if( tunnel_desc==NULL ) { return "Cannot built this station/building\nin underground mode here."; } tunnelboden_t* tunnel = new tunnelboden_t(pos, slope_t::flat); welt->access(k)->boden_hinzufuegen(tunnel); tunnel->obj_add(new tunnel_t(pos, player, tunnel_desc)); player_t::add_maintenance( player, tunnel_desc->get_maintenance(), tunnel_desc->get_finance_waytype() ); gr = tunnel; } else { // above ground: check for clear tile if(gr->get_grund_hang()!=0 || !gr->ist_natur()) { return "Transformer only on flat bare land!"; } // remove everything on that spot if(const char *fail = gr->kann_alle_obj_entfernen(player)) { return fail; } gr->obj_loesche_alle(player); } // transformer will be build on tile pointed to by gr // build source or drain depending on factory type if(fab->get_desc()->is_electricity_producer()) { pumpe_t *p = new pumpe_t(gr->get_pos(), player); gr->obj_add( p ); p->finish_rd(); } else { senke_t *s = new senke_t(gr->get_pos(), player); gr->obj_add(s); s->finish_rd(); } return NULL; // ok } /** * found a new city */ const char *tool_add_city_t::work( player_t *player, koord3d pos ) { // check funds const sint64 cost = welt->get_settings().cst_found_city; if( !player->can_afford(cost) ) { return NOTICE_INSUFFICIENT_FUNDS; } koord k(pos.get_2d()); grund_t *gr = welt->lookup_kartenboden(k); if (!gr) { return ""; } if(!gr->ist_natur() || gr->is_water() || gr->get_grund_hang() != slope_t::flat) { return "Cities can only be built on flat empty ground!"; } if (hausbauer_t::get_special(0, building_desc_t::townhall, welt->get_timeline_year_month(), false, welt->get_climate( k )) == NULL ) { return "No suitable townhall available for this climate!"; } gebaeude_t const* const gb = obj_cast(gr->first_no_way_obj()); if (gb && gb->is_townhall()) { dbg->warning("tool_add_city()", "Already a city here"); return NOTICE_TILE_FULL; } // always start with 1/10 citizens int citizens = (int)(welt->get_settings().get_mean_citizen_count() * 0.09); const building_desc_t* desc = NULL; sint16 rotation = -1; if (!strempty(default_param)) { char* building = strdup(default_param); citizens = atoi(building); char* p = strchr(building, ','); if (p) { p++; char* desc_name = p; if (p = strchr(p, ',')) { *p++ = 0; if (isdigit(*p)) { rotation = atoi(p); } } *p = 0; desc = hausbauer_t::get_desc(desc_name); } free(building); } stadt_t *stadt = welt->create_city(k, citizens, desc, rotation); if (!stadt) { return NOTICE_UNSUITABLE_GROUND; } stadt->finish_rd(); stadt->verbinde_fabriken(); player_t::book_construction_costs(player, cost, k, ignore_wt); minimap_t::get_instance()->calc_map(); return NULL; } // buy a house const char *tool_buy_house_t::work( player_t *player, koord3d pos) { if ( player == welt->get_public_player() ) { return ""; } grund_t* gr = welt->lookup_kartenboden(pos.get_2d()); if(!gr || gr->hat_wege() || gr->get_halt().is_bound()) { return ""; } // since buildings can have more than one tile, we must handle them together gebaeude_t* gb = gr->find(); if( gb==NULL ){ return ""; } gb = gb->get_first_tile(); if( !gb->is_city_building() || !player_t::check_owner(gb->get_owner(),player) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } if( gb->get_owner()==player ) { // I bought this already ... return ""; } player_t* old_owner = gb->get_owner(); const building_desc_t* bdsc = gb->get_tile()->get_desc(); vector_tpl gb_tiles; gb->get_tile_list( gb_tiles ); for(grund_t* gr : gb_tiles ) { gebaeude_t* gb_part = gr->find(); sint32 const maint = welt->get_settings().maint_building * bdsc->get_level(); player_t::add_maintenance( old_owner, -maint, gb_part->get_waytype() ); player_t::add_maintenance( player, +maint, gb_part->get_waytype() ); gb_part->set_owner( player ); player_t::book_construction_costs( player, -maint, gr->get_pos().get_2d(), gb_part->get_waytype() ); } return NULL; } /** * change city size */ bool tool_change_city_size_t::init( player_t * ) { int delta = 0; if (!default_param || sscanf(default_param, "%d", &delta) != 1) { return false; } cursor = delta > 0 ? tool_t::general_tool[TOOL_RAISE_LAND]->cursor : tool_t::general_tool[TOOL_LOWER_LAND]->cursor; return true; } const char *tool_change_city_size_t::work( player_t *, koord3d pos ) { stadt_t *city = welt->find_nearest_city(pos.get_2d()); if(city!=NULL) { const int delta = std::atoi(default_param); city->change_size( delta ); // update the links from other cities to this city for(stadt_t* const c : welt->get_cities()) { c->remove_target_city(city); c->add_target_city(city); } return NULL; } return ""; } /** * change climate */ const char *tool_set_climate_t::get_tooltip(player_t const*) const { char temp[1024]; sprintf( temp, translator::translate( "Set tile climate %s" ), translator::translate( ground_desc_t::get_climate_name_from_bit((climate)atoi(default_param)) ) ); return tooltip_with_price( temp, welt->get_settings().cst_alter_climate ); } uint8 tool_set_climate_t::is_valid_pos(player_t *player, const koord3d &, const char *& error, const koord3d &) { error = NULL; // no dragging in networkmode but for admin return env_t::networkmode && !player->is_public_service() ? 1 /*no dragging*/ : 2 /*dragging allowed*/; } void tool_set_climate_t::mark_tiles(player_t *, const koord3d &start, const koord3d &end) { koord k1, k2; k1.x = start.x < end.x ? start.x : end.x; k1.y = start.y < end.y ? start.y : end.y; k2.x = start.x + end.x - k1.x; k2.y = start.y + end.y - k1.y; koord k; for( k.x = k1.x; k.x <= k2.x; k.x++ ) { for( k.y = k1.y; k.y <= k2.y; k.y++ ) { grund_t *gr = welt->lookup_kartenboden( k ); zeiger_t *marker = new zeiger_t(gr->get_pos(), NULL ); const uint8 grund_hang = gr->get_grund_hang(); const uint8 weg_hang = gr->get_weg_hang(); const uint8 hang = max( corner_sw(grund_hang), corner_sw(weg_hang) ) + 3 * max( corner_se(grund_hang), corner_se(weg_hang) ) + 9 * max( corner_ne(grund_hang), corner_ne(weg_hang) ) + 27 * max( corner_nw(grund_hang), corner_nw(weg_hang) ); uint8 back_hang = (hang % 3) + 3 * ((uint8)(hang / 9)) + 27; marker->set_foreground_image( ground_desc_t::marker->get_image( grund_hang % 27 ) ); marker->set_image( ground_desc_t::marker->get_image( back_hang ) ); marker->mark_image_dirty( marker->get_image(), 0 ); gr->obj_add( marker ); marked.insert( marker ); } } } const char *tool_set_climate_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { int value = 0; if (!default_param || sscanf(default_param, "%d", &value) != 1) { return ""; } else if (value < water_climate || value >= MAX_CLIMATES) { return ""; } int n = 0; // tiles altered climate cl = (climate)value; koord k1, k2; if( end == koord3d::invalid ) { k1.x = k2.x = start.x; k1.y = k2.y = start.y; } else { k1.x = start.x < end.x ? start.x : end.x; k1.y = start.y < end.y ? start.y : end.y; k2.x = start.x + end.x - k1.x; k2.y = start.y + end.y - k1.y; } koord k; for( k.x = k1.x; k.x <= k2.x; k.x++ ) { for( k.y = k1.y; k.y <= k2.y; k.y++ ) { if( grund_t *gr=welt->lookup_kartenboden(k) ) { if( cl != water_climate ) { bool ok = true; if( gr->is_water() ) { const sint8 hgt = welt->lookup_hgt(k); ok = welt->get_water_hgt(k) == hgt && welt->is_plan_height_changeable( k.x, k.y ); // check s, se, e - these must not be deep water! for( int i = 3 ; i < 6 && ok ; i++ ) { koord k_neighbour(k + koord::neighbours[i]); if( welt->is_within_grid_limits(k_neighbour) ) { ok = welt->lookup_hgt(k_neighbour) >= hgt; } } if( ok ) { gr->obj_loesche_alle( NULL ); welt->set_water_hgt_nocheck( k, hgt - 1 ); welt->access(k)->correct_water(); } } if( ok ) { welt->set_climate( k, cl, true ); minimap_t::get_instance()->calc_map_pixel( k ); n ++; } } else if( !gr->is_water() && gr->get_grund_hang() == slope_t::flat && welt->is_plan_height_changeable( k.x, k.y ) ) { bool ok = true; for( int i = 0 ; i < 8; i++ ) { grund_t *gr2 = welt->lookup_kartenboden( k + koord::neighbours[i] ); if( gr2 && ok ) { ok = gr2->get_pos().z >= gr->get_pos().z; } } if( ok ) { gr->obj_loesche_alle( NULL ); welt->set_water_hgt_nocheck( k, gr->get_pos().z ); welt->access(k)->correct_water(); welt->set_climate( k, water_climate, true ); minimap_t::get_instance()->calc_map_pixel( k ); n ++; } } } } } if(n>0) { player_t::book_construction_costs(player, welt->get_settings().cst_alter_climate * n, k, ignore_wt); } return NULL; } /** * change water height */ bool tool_change_water_height_t::init( player_t *player ) { int delta = 0; if (!default_param || sscanf(default_param, "%d", &delta) != 1) { return false; } cursor = delta > 0 ? tool_t::general_tool[TOOL_RAISE_LAND]->cursor : tool_t::general_tool[TOOL_LOWER_LAND]->cursor; return !env_t::networkmode || player->is_public_service(); } const char *tool_change_water_height_t::work( player_t *, koord3d pos ) { if( pos == koord3d::invalid ) { return "Cannot alter water"; } // calculate new height to use: bool raising = atoi(default_param) > 0; koord k = pos.get_2d(); sint8 new_water_height; grund_t *gr = welt->lookup_kartenboden(k); if( gr->is_water() ) { // lower + control removes shallow water only. If this tile is deep water this will fail if( !raising && is_ctrl_pressed() && welt->min_hgt(k)!=gr->get_hoehe() ) { return "Cannot alter water"; } // if currently water, raise = +1, lower = -1 new_water_height = gr->get_hoehe() + (raising ? 1 : -1); } // if not water then raise = set water height to ground height, lower = error else if( raising ) { slope_t::type slope = gr->get_grund_hang(); new_water_height = gr->get_hoehe() + max( max( corner_sw(slope), corner_se(slope) ),max( corner_ne(slope), corner_nw(slope) ) ); } else { return "Cannot alter water"; } if( new_water_height < welt->get_groundwater() - 3 ) { return "Cannot alter water"; } sint8 test_height = max( new_water_height, gr->get_hoehe() ); // make a list of tiles to change // cannot use a recursive method as stack is not large enough! sint8 *from_dir = new sint8[welt->get_size().x * welt->get_size().y]; sint8 *stage = new sint8[welt->get_size().x * welt->get_size().y]; memset( from_dir, -1, sizeof(sint8) * welt->get_size().x * welt->get_size().y ); memset( stage, -1, sizeof(sint8) * welt->get_size().x * welt->get_size().y ); #define array_koord(px,py) (px + py * welt->get_size().x) stage[array_koord(k.x,k.y)]=0; do { // firstly we must be able to change ground height bool ok = welt->is_plan_height_changeable( k.x, k.y ) && k.x > 0 && k.y > 0 && k.x < welt->get_size().x - 1 && k.y < welt->get_size().y - 1; const planquadrat_t *plan = welt->access(k); // next there cannot be any grounds directly above this tile sint8 h = plan->get_kartenboden()->get_hoehe() + 1; while( ok && h < new_water_height + welt->get_settings().get_way_height_clearance() ) { if( plan->get_boden_in_hoehe(h) ) { ok = false; } h++; } if( !ok ) { delete [] from_dir; delete [] stage; return "Cannot alter water"; } // get neighbour corner heights sint8 neighbour_heights[8][4]; welt->get_neighbour_heights( k, neighbour_heights ); for( int i = stage[array_koord(k.x,k.y)]; i < 8; i++ ) { koord k_neighbour = k + koord::neighbours[i]; grund_t *gr2 = welt->lookup_kartenboden(k_neighbour); if( gr2 ) { sint8 neighbour_height = gr2->get_hoehe(); // move onto this tile if it hasn't been processed yet bool ok = stage[array_koord(k_neighbour.x, k_neighbour.y)] == -1; if( raising ) { // test whether points adjacent to current tile will be flooded // if control key modifier pressed, level ground will be left alone, but then need to check for spills // for neighbour i test corners adjacent to tile // nw (i = 0), test se (corner 1) // w (i = 1), test se (corner 1) and ne (corner 2) // sw (i = 2), test ne (corner 2) // s (i = 3), test ne (corner 2) and nw (corner 3) // se (i = 4), test nw (corner 3) // e (i = 5), test nw (corner 3) and sw (corner 0) // ne (i = 6), test sw (corner 0) // n (i = 7), test sw (corner 0) and se (corner 1) if( is_ctrl_pressed() ) { ok = ok && ( (gr2->get_grund_hang()!=slope_t::flat && welt->max_hgt(k_neighbour) <= test_height) || neighbour_heights[i][((i >> 1) + 1) & 3] < test_height || ( (i & 1) && neighbour_heights[i][((i >> 1) + 2) & 3] < test_height) ); } else { ok = ok && (neighbour_heights[i][((i >> 1) + 1) & 3] <= test_height || ( (i & 1) && neighbour_heights[i][((i >> 1) + 2) & 3] <= test_height)); } // move onto this tile unless it already has water at new level, or the land level is above new level ok = ok && welt->get_water_hgt(k_neighbour) < new_water_height; } else { if( is_ctrl_pressed() ) { ok = ok && welt->min_hgt(k_neighbour) == test_height; } else { ok = ok && neighbour_height <= test_height; } // move onto this tile unless it already has water at new level, or the land level is above new level ok = ok && welt->get_water_hgt(k_neighbour) > new_water_height; } if( ok ) { //move on to next tile from_dir[array_koord(k_neighbour.x,k_neighbour.y)] = i; stage[array_koord(k_neighbour.x,k_neighbour.y)] = 0; stage[array_koord(k.x,k.y)] = i; k = k_neighbour; break; } } //return back to previous tile if( i==7 ) { stage[array_koord(k.x,k.y)] = 8; if( from_dir[array_koord(k.x,k.y)] != -1 ) { k = k - koord::neighbours[from_dir[array_koord(k.x,k.y)]]; } } } } while( from_dir[array_koord(k.x,k.y)] != -1 || stage[array_koord(k.x,k.y)] < 7 ); delete [] from_dir; // loop over map to find marked tiles for( int y = 1; yget_size().y - 1; y++ ) { for( int x = 1; xget_size().x - 1; x++ ) { if( stage[array_koord(x,y)] > -1 ) { // calculate new height, slope and climate and set water height grund_t *gr2 =welt->lookup_kartenboden(x, y); // remove any objects on this tile gr2->obj_loesche_alle( NULL ); const sint8 h0 = gr2->get_hoehe(); const sint8 min_grid_hgt = welt->min_hgt( koord( x, y ) ); sint8 h0_nw, h0_ne, h0_se, h0_sw; if( gr2->is_water() ) { // water - maximum existing height can be is old water height no matter what surrounding grids are h0_nw = min(h0, welt->lookup_hgt(x, y)); h0_ne = min(h0, welt->lookup_hgt(x+1, y)); h0_se = min(h0, welt->lookup_hgt(x+1, y+1)); h0_sw = min(h0, welt->lookup_hgt(x, y+1)); } else if( h0 > min_grid_hgt ) { // if min grid height here is less than ground height it will be because we are partially water h0_nw = welt->lookup_hgt(x, y); h0_ne = welt->lookup_hgt(x+1, y); h0_se = welt->lookup_hgt(x+1, y+1); h0_sw = welt->lookup_hgt(x, y+1); if( !gr2->is_water() ) { // while this appears to be a single height slope actually it is a double height slope half underwater const sint8 water_hgt = welt->get_water_hgt(x, y); h0_nw >= water_hgt ? h0_nw = h0 + corner_nw( gr2->get_grund_hang() ) : 0; h0_ne >= water_hgt ? h0_ne = h0 + corner_ne( gr2->get_grund_hang() ) : 0; h0_se >= water_hgt ? h0_se = h0 + corner_se( gr2->get_grund_hang() ) : 0; h0_sw >= water_hgt ? h0_sw = h0 + corner_sw( gr2->get_grund_hang() ) : 0; } } else { // fully land h0_nw = h0 + corner_nw( gr2->get_grund_hang() ); h0_ne = h0 + corner_ne( gr2->get_grund_hang() ); h0_se = h0 + corner_se( gr2->get_grund_hang() ); h0_sw = h0 + corner_sw( gr2->get_grund_hang() ); } const sint8 hneu_nw = max( new_water_height, h0_nw ); const sint8 hneu_ne = max( new_water_height, h0_ne ); const sint8 hneu_se = max( new_water_height, h0_se ); const sint8 hneu_sw = max( new_water_height, h0_sw ); const sint8 hneu = min( min( hneu_nw, hneu_ne ), min( hneu_se, hneu_sw ) ); gr2->set_hoehe( hneu ); const uint8 sneu = (hneu_sw - hneu > 2 ? 2 : hneu_sw - hneu) + ((hneu_se - hneu > 2 ? 2 : hneu_se-hneu) * 3) + ((hneu_ne - hneu > 2 ? 2 : hneu_ne - hneu) * 9) + ((hneu_nw - hneu > 2 ? 2 : hneu_nw - hneu) * 27); gr2->set_grund_hang( sneu ); welt->set_water_hgt_nocheck(x, y, new_water_height ); welt->access(x, y)->correct_water(); welt->calc_climate( koord( x, y ), true ); } } } delete [] stage; return NULL; } char const* tool_plant_tree_t::move(player_t* const player, uint16 const b, koord3d const pos) { if (b==0) { return NULL; } if (env_t::networkmode) { // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false); network_send_server(nwc); return NULL; } else { return work( player, pos ); } } bool tool_plant_tree_t::init(player_t*) { if (!tree_builder_t::has_trees()) { return false; } else if (default_param == NULL || default_param[0] == 0) { return true; } char ignore_cl,random_age,dummy; if (std::sscanf(default_param, "%c%c,%c", &ignore_cl, &random_age, &dummy) != 3) { return false; } return (ignore_cl == '0' || ignore_cl == '1') && (random_age == '0' || random_age == '1'); } const char *tool_plant_tree_t::work( player_t *player, koord3d pos ) { koord k(pos.get_2d()); grund_t *gr = welt->lookup_kartenboden(k); if(gr) { // check if trees are allowed if( welt->get_settings().get_tree_distribution()==settings_t::TREE_DIST_NONE && !player->is_public_service() ) { return NOTICE_NO_TREES; } // check funds sint64 const cost = welt->get_settings().cst_remove_tree; if( !player->can_afford(cost) ) { return NOTICE_INSUFFICIENT_FUNDS; } const tree_desc_t *desc = NULL; bool check_climates = true; bool random_age = true; if(default_param==NULL || strlen(default_param)<5 ) { // just a random tree to the limit if( tree_builder_t::plant_tree_on_coordinate( k, welt->get_settings().get_max_no_of_trees_on_square(), 1 ) ) { player_t::book_construction_costs( player, cost, k, ignore_wt ); return NULL; } } else { // parse default_param: bbdesc_nr b=1 ignore climate b=1 random age check_climates = default_param[0]=='0'; random_age = default_param[1]=='1'; desc = tree_builder_t::find_tree( default_param+3 ); if( !desc ) { desc = tree_builder_t::random_tree_for_climate( welt->get_climate( k ) ); } if( desc && tree_builder_t::plant_tree_on_coordinate( k, desc, check_climates, random_age ) ) { player_t::book_construction_costs( player, cost, k, ignore_wt ); return NULL; } } return ""; } return NULL; } char const* tool_plant_groundobj_t::move(player_t* const player, uint16 const b, koord3d const pos) { if (b==0) { return NULL; } if (env_t::networkmode) { // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false); network_send_server(nwc); return NULL; } else { return work( player, pos ); } } bool tool_plant_groundobj_t::init(player_t *) { if (groundobj_t::get_count() == 0) { return false; } else if (strempty(default_param)) { return true; } else if (strlen(default_param) < 4) { return false; } return default_param[0] == '0' || default_param[0] == '1'; } const char *tool_plant_groundobj_t::work( player_t *player, koord3d pos ) { koord k(pos.get_2d()); grund_t *gr = welt->lookup_kartenboden(k); if(gr) { const groundobj_desc_t *desc = NULL; bool check_climates = true; if (strempty(default_param)) { desc = groundobj_t::random_groundobj_for_climate( welt->get_climate( k ) ); if (desc == NULL) { return NULL; } } else { check_climates = default_param[0]=='0'; desc = groundobj_t::find_groundobj(default_param+3); } // disable placing groundobj on slopes unless they have extra phases (=moving or for slopes) if( gr->get_grund_hang() != slope_t::flat && desc->get_phases() == 2 ) { return NULL; } // check funds sint64 const cost = -desc->get_price(); if( !player->can_afford(cost) ) { return NOTICE_INSUFFICIENT_FUNDS; } if(desc && groundobj_t::plant_groundobj_on_coordinate( k, desc, check_climates ) ) { player_t::book_construction_costs(player, cost, k, ignore_wt); return NULL; } return ""; } return NULL; } /** * the following routines add waypoints/halts to a schedule * because we do not like to stop at AIs stop, but we still want to force the truck to use AI roads * So if there is a halt, then it must be either public or ours! */ static const char *tool_schedule_insert_aux(karte_t *welt, player_t *player, koord3d pos, schedule_t *schedule, bool append) { if(schedule == NULL) { dbg->warning("tool_schedule_insert_aux()","Schedule is (null), doing nothing"); return 0; } grund_t *bd = welt->lookup(pos); if (bd) { // now just for error messages, we're assuming a valid ground // check for right way type if(!schedule->is_stop_allowed(bd)) { return schedule->get_error_msg(); } // stored in minivec, so we have to avoid adding too many if( schedule->entries.get_count()>=254 ) { return "Maximum 254 stops\nin a schedule!\n"; } // and check for ownership if( !bd->is_halt() ) { weg_t *w = bd->get_weg( schedule->get_waytype() ); if( w==NULL && schedule->get_waytype()==tram_wt ) { w = bd->get_weg( track_wt ); } if( w!=NULL && w->get_owner()!=welt->get_public_player() && !player_t::check_owner(w->get_owner(),player) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } if( bd->get_depot() && !player_t::check_owner( bd->get_depot()->get_owner(), player ) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } } if( bd->is_halt() && !player_t::check_owner( player, bd->get_halt()->get_owner()) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // ok, now we have a valid ground if(append) { schedule->append(bd); } else { schedule->insert(bd); } } return NULL; } const char *tool_schedule_add_t::work( player_t *player, koord3d pos ) { return tool_schedule_insert_aux( welt, player, pos, (schedule_t*)const_cast(default_param), true ); } const char *tool_schedule_ins_t::work( player_t *player, koord3d pos ) { return tool_schedule_insert_aux( welt, player, pos, (schedule_t*)const_cast(default_param), false ); } /* way construction */ const way_desc_t *tool_build_way_t::defaults[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const way_desc_t *tool_build_way_t::get_desc( uint16 timeline_year_month) const { const way_desc_t *desc = default_param ? way_builder_t::get_desc(default_param,0) :NULL; if( desc==NULL && default_param ) { waytype_t wt = (waytype_t)atoi(default_param); desc = defaults[wt&63]; if(desc==NULL || !desc->is_available(timeline_year_month)) { // search fastest way. if( wt == tram_wt || wt == powerline_wt ) { desc = way_builder_t::weg_search(wt, 0xffffffff, timeline_year_month, type_flat); } else if ( (road_wt <= wt && wt <= narrowgauge_wt) || wt == air_wt) { // this triggers an assertion if wt == powerline_wt weg_t *w = weg_t::alloc(wt); desc = w->get_desc(); delete w; } } } return desc; } image_id tool_build_way_t::get_icon(player_t *) const { const way_desc_t *desc = way_builder_t::get_desc(default_param,0); image_id image = icon; bool is_tram = false; if( desc ) { is_tram = (desc->get_wtyp()==tram_wt) || (desc->get_styp() == type_tram); if( image == IMG_EMPTY ) { image = desc->get_cursor()->get_image_id(1); } if( !desc->is_available( world()->get_timeline_year_month() ) ) { return IMG_EMPTY; } } if( grund_t::underground_mode==grund_t::ugm_all && !is_tram ) { return IMG_EMPTY; } return image; } const char* tool_build_way_t::get_tooltip(const player_t *) const { const way_desc_t *desc = get_desc(welt->get_timeline_year_month()); if (desc == NULL) { return ""; } tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() ); size_t n= strlen(toolstr); sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed() ); return toolstr; } // default ways are not initialized synchronously for different clients // always return the name of a way, never the string containing the waytype const char* tool_build_way_t::get_default_param(player_t *player) const { if (player==NULL) { return default_param; } if (desc) { return desc->get_name(); } else { if (default_param == NULL) { // no chance to guess anything sensible return NULL; } const way_desc_t* test_desc = get_desc(0); if (test_desc) { return test_desc->get_name(); } else { return default_param; } } } bool tool_build_way_t::is_selected() const { tool_t const* const tool = welt->get_tool(welt->get_active_player_nr()); if (tool->get_id() != get_id()) { return false; } tool_build_way_t const* const selected = dynamic_cast(tool); return (selected && selected->get_desc(welt->get_timeline_year_month()) == get_desc(welt->get_timeline_year_month())); } bool tool_build_way_t::init( player_t *player ) { two_click_tool_t::init( player ); if( ok_sound == NO_SOUND ) { ok_sound = SFX_CASH; } // now get current desc desc = get_desc( welt->get_timeline_year_month()); if( desc && desc->get_cursor()->get_image_id(0) != IMG_EMPTY ) { cursor = desc->get_cursor()->get_image_id(0); } if( desc && !desc->is_available(welt->get_timeline_year_month()) && player!=NULL && player!=welt->get_public_player() ) { // non available way => fail return false; } return desc!=NULL; } waytype_t tool_build_way_t::get_waytype() const { const way_desc_t *desc = get_desc( welt->get_timeline_year_month()); if (desc) { return desc->is_tram() ? tram_wt : desc->get_wtyp(); } return invalid_wt; } void tool_build_way_t::start_at( koord3d &new_start ) { if( is_shift_pressed() && (desc->get_styp() == type_elevated && desc->get_wtyp() != air_wt) ) { grund_t *gr=welt->lookup(new_start); if( gr->get_weg( desc->get_waytype() ) ) { new_start.z -= welt->get_settings().get_way_height_clearance(); } } // elevated ways with SHIFT will selected the current layer, when already on an elevated way two_click_tool_t::start_at( new_start ); } uint8 tool_build_way_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & ) { error = NULL; grund_t *gr=welt->lookup(pos); if( gr && slope_t::is_way(gr->get_weg_hang()) ) { // ignore tunnel tiles (except road tunnel for tram track building ..) if( gr->get_typ() == grund_t::tunnelboden && !gr->ist_karten_boden() && !(desc->is_tram() && gr->hat_weg(road_wt)) ) { return 0; } bool const elevated = desc->get_styp() == type_elevated && desc->get_wtyp() != air_wt; // ignore water if( desc->get_wtyp() != water_wt && gr->get_typ() == grund_t::wasser ) { if( !elevated || welt->lookup_hgt( pos.get_2d() ) < welt->get_water_hgt( pos.get_2d() ) ) { return 0; } // here either channel or elevated way over not too deep water } // elevated ways have to check tile above if( elevated ) { gr = welt->lookup( pos + koord3d( 0, 0, welt->get_settings().get_way_height_clearance() ) ); if( gr == NULL ) { return 2; } if( gr->get_typ() != grund_t::monorailboden ) { return 0; } } // test if way already exists on the way and if we are allowed to connect weg_t *way = gr->get_weg(desc->get_wtyp()); if( way ) { // allow to connect to any road if( desc->get_wtyp() == road_wt || desc->get_wtyp() == water_wt ) { return 2; } error = way->get_removal_error(player); return error==NULL ? 2 : 0; } // check for ownership but ignore moving things if(player!=NULL) { for(uint8 i=0; iobj_count(); i++) { obj_t* dt = gr->obj_bei(i); if (!dt->is_moving() && dt->get_removal_error(player)!=NULL && dt->get_typ()!=obj_t::label && (desc->get_wtyp() == powerline_wt || dt->get_typ()!=obj_t::leitung) ) { error = dt->get_removal_error(player); // "Das Feld gehoert\neinem anderen Spieler\n"; return 0; } } } } else { return 0; } return 2; } const char *tool_build_way_t::calc_route( way_builder_t &bauigel, const koord3d &start, const koord3d &end ) { // recalc type of construction way_builder_t::bautyp_t bautyp = (way_builder_t::bautyp_t)desc->get_wtyp(); if(desc->is_tram()) { bautyp = way_builder_t::schiene_tram; } // elevated track? if(desc->get_styp()==type_elevated && desc->get_wtyp()!=air_wt) { bautyp |= way_builder_t::elevated_flag; } bauigel.init_builder(bautyp, desc); if( is_ctrl_pressed() && !is_shift_pressed()) { bauigel.set_keep_existing_ways( false ); } else { bauigel.set_keep_existing_faster_ways( true ); } // if shift pressed, keep city roads if (is_shift_pressed() && desc->get_styp() == type_flat && desc->get_wtyp() == road_wt) { bauigel.set_keep_city_roads(true); } koord3d my_end = end; // ending point is applied that elevated ways with SHIFT selects the current layer, when already on an elevated way if( is_shift_pressed() && (desc->get_styp() == type_elevated && desc->get_wtyp() != air_wt) ) { grund_t *gr=welt->lookup(my_end); if( gr->get_weg( desc->get_waytype() ) ) { my_end.z -= welt->get_settings().get_way_height_clearance(); } } // Find out if this might be intended to become a parallel way bool assume_parallel = false; if (grund_t *gr=welt->lookup(start)) { if (weg_t *w=gr->get_weg(desc->get_wtyp())) { // we start on a way; but if it is an end, maybe continue building a parallel way if (ribi_t::is_single(w->get_ribi_unmasked())) { koord zv = (koord)(ribi_t::rotate90(w->get_ribi_unmasked())); if (grund_t* gr = welt->lookup(start + zv)) { // is there a parallel way? assume_parallel = gr->get_weg(desc->get_wtyp()); } if (grund_t* gr = welt->lookup(start - zv)) { // is there a parallel way? assume_parallel |= gr->get_weg(desc->get_wtyp())!=0; } } } else { // find out if there is a way close by koord3d delta_z(0, 0, (bautyp & way_builder_t::elevated_flag) != 0); for (int i = 0; i < 8; i++) { if (grund_t* gr = welt->lookup(start + koord::neighbours[i] + delta_z)) { if (gr->get_weg(desc->get_wtyp())) { assume_parallel = true; break; } } } } } if (assume_parallel) { bool assume_parallel2 = false; if (grund_t* gr = welt->lookup(my_end)) { if (!gr->get_weg(desc->get_wtyp())) { koord3d delta_z(0, 0, (bautyp & way_builder_t::elevated_flag) != 0); for (int i = 0; i < 8; i++) { if (grund_t* gr = welt->lookup(my_end + koord::neighbours[i] + delta_z)) { if (gr->get_weg(desc->get_wtyp())) { assume_parallel2 = true; break; } } } } } // both start and end are one tile from a way assume_parallel &= assume_parallel2; } bauigel.set_prefer_parallel(assume_parallel); // and continue as normal ... const char *err; if( is_ctrl_pressed() || (env_t::straight_way_without_control && !env_t::networkmode && !is_scripted()) ) { DBG_MESSAGE("tool_build_way_t()", "try straight route"); err = bauigel.calc_straight_route(start,my_end); } else { err = bauigel.calc_route(start,my_end); } DBG_MESSAGE("tool_build_way_t()", "builder found route with %d squares length.", bauigel.get_count()); return err; } const char *tool_build_way_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { way_builder_t bauigel(player); const char *err = calc_route( bauigel, start, end ); if( bauigel.get_route().get_count()>1 ) { welt->mute_sound(true); bauigel.build(); welt->mute_sound(false); // set default newly constructed type if (can_use_gui()) { if( desc->get_styp() == type_tram ) { defaults[ tram_wt ] = desc; } else { defaults[desc->get_wtyp()&63] = desc; } } return NULL; } return err ? err : ""; } void tool_build_way_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) { way_builder_t bauigel(player); const char *err = calc_route( bauigel, start, end ); bool keep_city_roads = is_shift_pressed() && desc->get_styp() == type_flat && desc->get_wtyp() == road_wt; uint8 offset = (desc->get_styp() == type_elevated && desc->get_wtyp() != air_wt) ? welt->get_settings().get_way_height_clearance() : 0; if( bauigel.get_count()>1 ) { // Set tooltip first (no dummygrounds, if bauigel.calc_casts() is called). win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", bauigel.calc_costs(), bauigel.get_count() ) ); // make dummy route from bauigel for( uint32 j=0; jlookup( pos ); if( !gr ) { gr = new monorailboden_t(pos, slope_t::flat); // should only be here when elevated/monorail, therefore will be at height offset above ground gr->set_grund_hang( welt->lookup( pos - koord3d( 0, 0, offset ) )->get_grund_hang() ); welt->access(pos.get_2d())->boden_hinzufuegen(gr); } if (gr->is_water()) { continue; } ribi_t::ribi zeige = gr->get_weg_ribi_unmasked(desc->get_wtyp()) | bauigel.get_route().get_ribi( j ); // do not replace city roads if requested if (keep_city_roads && gr->get_weg(road_wt) && gr->get_weg(road_wt)->hat_gehweg()) { continue; } zeiger_t *way = new zeiger_t(pos, player); if(gr->get_weg_hang()) { way->set_image( desc->get_slope_image_id(gr->get_weg_hang(),0) ); } else if(desc->get_wtyp()!=powerline_wt && ribi_t::is_bend(zeige) && desc->has_diagonal_image()) { way->set_image( desc->get_diagonal_image_id(zeige,0) ); } else { way->set_image( desc->get_image_id(zeige,0) ); } gr->obj_add( way ); way->set_yoff(-gr->get_weg_yoff() ); marked.insert( way ); way->mark_image_dirty( way->get_image(), 0 ); } } else if(err) { win_set_static_tooltip(translator::translate(err)); } } /* city road construction */ const way_desc_t *tool_build_cityroad::get_desc(uint16) const { return welt->get_city_road(); } const char *tool_build_cityroad::do_work( player_t *player, const koord3d &start, const koord3d &end ) { way_builder_t bauigel(player); bauigel.set_build_sidewalk(true); calc_route( bauigel, start, end ); if( bauigel.get_route().get_count()>1 ) { welt->mute_sound(true); bauigel.build(); welt->mute_sound(false); return NULL; } return ""; } /* bridge construction */ const char* tool_build_bridge_t::get_tooltip(const player_t *) const { const bridge_desc_t * desc = bridge_builder_t::get_desc(default_param); if (desc == NULL) { return ""; } tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() ); size_t n= strlen(toolstr); if(desc->get_waytype()!=powerline_wt) { n += sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed()); } if(desc->get_max_length()>0) { n += sprintf(toolstr+n, ", %dkm", desc->get_max_length()); } return toolstr; } waytype_t tool_build_bridge_t::get_waytype() const { const bridge_desc_t * desc = bridge_builder_t::get_desc(default_param); return desc ? desc->get_waytype() : invalid_wt; } bool tool_build_bridge_t::init( player_t *player ) { two_click_tool_t::init( player ); // now get current desc const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param); if( desc && !desc->is_available(welt->get_timeline_year_month()) && player!=NULL && player!=welt->get_public_player() ) { return false; } return desc!=NULL; } const char *tool_build_bridge_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param); if (end==koord3d::invalid) { return bridge_builder_t::build( player, start, desc ); } else { const koord zv(ribi_type(end-start)); sint8 bridge_height; const char *error; koord3d end2 = bridge_builder_t::find_end_pos(player, start, zv, desc, error, bridge_height, false, koord_distance(start, end), is_ctrl_pressed()); if (end2 != end) { return "End position is not valid"; // could only happen for scripts } bridge_builder_t::build_bridge( player, start, end, zv, bridge_height, desc, way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat)); return NULL; // all checks are performed before building. } } void tool_build_bridge_t::rdwr_custom_data(memory_rw_t *packet) { two_click_tool_t::rdwr_custom_data(packet); uint8 i = ribi; packet->rdwr_byte(i); ribi = (ribi_t::ribi)i; } void tool_build_bridge_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) { const ribi_t::ribi ribi_mark = ribi_type(end-start); const koord zv(ribi_mark); const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param); const char *error; sint8 bridge_height; koord3d end2 = bridge_builder_t::find_end_pos(player, start, zv, desc, error, bridge_height, false, koord_distance(start, end), is_ctrl_pressed()); assert(end2 == end); (void)end2; sint64 costs = 0; // start grund_t *gr = welt->lookup(start); // get initial height of bridge from start tile // flat -> height is 1 if conversion factor 1, 2 if conversion factor 2 // single height -> height is 1 // double height -> height is 2 const slope_t::type slope = gr->get_weg_hang(); uint8 max_height = slope ? slope_t::max_diff(slope) : bridge_height; zeiger_t *way = new zeiger_t(start, player ); const bridge_desc_t::img_t img0 = desc->get_end( slope, slope, slope_type(zv)*max_height ); gr->obj_add( way ); way->set_image( desc->get_background( img0, 0 ) ); way->set_foreground_image( desc->get_foreground( img0, 0 ) ); if( gr->get_grund_hang() != 0 ) { way->set_yoff( -TILE_HEIGHT_STEP * max_height ); } // eventually we have to remove trees on start tile if (desc->get_waytype() != powerline_wt) { for( uint8 i=0; iobj_count(); i++ ) { obj_t *obj = gr->obj_bei(i); switch(obj->get_typ()) { case obj_t::baum: costs -= welt->get_settings().cst_remove_tree; break; case obj_t::groundobj: costs += ((groundobj_t *)obj)->get_desc()->get_price(); break; default: break; } } } marked.insert( way ); way->mark_image_dirty( way->get_image(), 0 ); // loop koord3d pos( start + zv + koord3d( 0, 0, max_height ) ); while (pos.get_2d()!=end.get_2d()) { grund_t *gr = welt->lookup( pos ); if( !gr ) { gr = new monorailboden_t(pos, slope_t::flat); gr->set_grund_hang( slope_t::flat ); welt->access(pos.get_2d())->boden_hinzufuegen(gr); } zeiger_t *way = new zeiger_t(pos, player ); gr->obj_add( way ); grund_t *kb = welt->lookup_kartenboden(pos.get_2d()); sint16 height = pos.z - kb->get_pos().z; way->set_image(desc->get_background(desc->get_straight(ribi_mark,height-slope_t::max_diff(kb->get_grund_hang())),0)); way->set_foreground_image(desc->get_foreground(desc->get_straight(ribi_mark,height-slope_t::max_diff(kb->get_grund_hang())), 0)); marked.insert( way ); way->mark_image_dirty( way->get_image(), 0 ); pos = pos + zv; } costs += desc->get_price() * koord_distance(start, pos); // end gr = welt->lookup(end); // get initial height of bridge from start tile // flat -> height is 1 if conversion factor 1, 2 if conversion factor 2 // single height -> height is 1 // double height -> height is 2 const slope_t::type end_slope = gr->get_weg_hang(); const uint8 end_max_height = end_slope ? (is_one_high(end_slope) ? 1 : 2) : (pos.z-end.z); if( gr->ist_karten_boden() && end.z + end_max_height == start.z + max_height ) { zeiger_t *way = new zeiger_t(end, player ); const bridge_desc_t::img_t img1 = desc->get_end( end_slope, end_slope, end_slope?0:(pos.z-end.z)*slope_type(-zv) ); gr->obj_add( way ); way->set_image(desc->get_background(img1, 0)); way->set_foreground_image(desc->get_foreground(img1, 0)); if( gr->get_grund_hang() != 0 ) { way->set_yoff( -TILE_HEIGHT_STEP * end_max_height ); } marked.insert( way ); way->mark_image_dirty( way->get_image(), 0 ); costs += desc->get_price(); } else { if (desc->get_waytype() == powerline_wt ? !gr->find() : !gr->hat_weg(desc->get_waytype())) { const way_desc_t *way_desc = way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat); costs += way_desc->get_price(); } } // eventually we have to remove trees on end tile if (desc->get_waytype() != powerline_wt) { for( uint8 i=0; iobj_count(); i++ ) { obj_t *obj = gr->obj_bei(i); switch(obj->get_typ()) { case obj_t::baum: costs -= welt->get_settings().cst_remove_tree; break; case obj_t::groundobj: costs += ((groundobj_t *)obj)->get_desc()->get_price(); break; default: break; } } } win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", costs, koord_distance(start, pos)+1 ) ); } uint8 tool_build_bridge_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &start ) { const bridge_desc_t *desc = bridge_builder_t::get_desc(default_param); const waytype_t wt = desc->get_waytype(); error = NULL; grund_t *gr = welt->lookup(pos); if( gr==NULL || !bridge_builder_t::can_place_ramp( player, gr, wt, (is_first_click() ? 0 : ribi_type(pos-start)) ) ) { return 0; } if( is_first_click() ) { if( gr->ist_karten_boden() ) { // first click // check ribis, all other checks already done ribi_t::ribi rw = ribi_t::none; if (wt==powerline_wt) { if (gr->find()) { rw |= gr->find()->get_ribi(); } } else { // way types are checked, take all ribis for(int i=0;i<2;i++) { if (const weg_t *w = gr->get_weg_nr(i)) { rw |= w->get_ribi_unmasked(); } else break; } } // ribi from slope rw |= ribi_type(gr->get_grund_hang()); if( rw!=ribi_t::none && !ribi_t::is_single(rw) ) { return 0; } // determine possible directions ribi = ribi_t::backward(rw); return (ribi!=ribi_t::none ? 2 : 0) | (ribi_t::is_single(ribi) ? 1 : 0); } else { if( gr->get_weg_hang() ) { return 0; } if( gr->get_typ() != grund_t::monorailboden && gr->get_typ() != grund_t::tunnelboden ) { return 0; } if(!gr->get_weg_nr(0)) { return 0; } ribi = ~gr->get_weg_nr(0)->get_ribi_unmasked(); return 2; } } else { // second click // dragging in the right direction? ribi_t::ribi test = ribi_type(pos - start); if (!ribi_t::is_single(test) || ((test & (~ribi))!=0) ) { return 0; } // check whether we can build a bridge here const char *error = NULL; sint8 bridge_height; koord3d end = bridge_builder_t::find_end_pos(player, start, koord(test), desc, error, bridge_height, false, koord_distance(start, pos), is_ctrl_pressed()); if (end!=pos) { return 0; } return 2; } } /* more difficult, since this builds also underground ways */ const char* tool_build_tunnel_t::get_tooltip(const player_t *) const { const tunnel_desc_t * desc = tunnel_builder_t::get_desc(default_param); tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() ); size_t n= strlen(toolstr); if(desc->get_waytype()!=powerline_wt) { n += sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed()); } return toolstr; } waytype_t tool_build_tunnel_t::get_waytype() const { const tunnel_desc_t * desc = tunnel_builder_t::get_desc(default_param); return desc ? desc->get_waytype() : invalid_wt; } bool tool_build_tunnel_t::init( player_t *player ) { two_click_tool_t::init( player ); // now get current desc const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); if( desc && !desc->is_available(welt->get_timeline_year_month()) && player!=NULL && player!=welt->get_public_player() ) { return false; } return desc!=NULL; } const char *tool_build_tunnel_t::check_pos( player_t *player, koord3d pos) { if (grund_t::underground_mode == grund_t::ugm_all) { return NULL; } else { if( grund_t *gr=welt->lookup( pos ) ) { if( !gr->is_visible() ) { // not visible return ""; } if (gr->find()) { // there is tunnel present -> allow, no chance to guess building cost. return NULL; } if( gr->ist_karten_boden() ) { win_set_static_tooltip( translator::translate("No suitable ground!") ); slope_t::type sl = gr->get_grund_hang(); if( sl == slope_t::flat || !slope_t::is_way( sl ) ) { // cannot start a tunnel here, wrong slope return ""; } if( welt->get_settings().get_way_height_clearance() != slope_t::max_diff(sl) ) { win_set_static_tooltip( translator::translate("The gradient does not fit a tunnel") ); return ""; } const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); // first check for building portal only if( is_ctrl_pressed() ) { // estimate costs for tunnel portal win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", (-(sint64)desc->get_price())*2, 1 ) ); return NULL; } // Now check, if we can built a tunnel here and display costs koord3d end = tunnel_builder_t::find_end_pos(player,pos, koord(gr->get_grund_hang()), desc, true ); if( end == koord3d::invalid || end == pos ) { // no end found return ""; } // estimate costs for full tunnel win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", (-(sint64)desc->get_price())*koord_distance(pos,end), koord_distance(pos,end) ) ); return NULL; } } return two_click_tool_t::check_pos(player, pos); } } void tool_build_tunnel_t::calc_route( way_builder_t &bauigel, const koord3d &start, const koord3d &end) { const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); way_builder_t::bautyp_t bt = (way_builder_t::bautyp_t)(desc->get_waytype()); const way_desc_t *wb = desc->get_way_desc(); if(wb==NULL) { // ignore timeline to get consistent results wb = way_builder_t::weg_search( desc->get_waytype(), desc->get_topspeed(), 0, type_flat ); } bauigel.init_builder(bt | way_builder_t::tunnel_flag, wb, desc); bauigel.set_keep_existing_faster_ways( !is_ctrl_pressed() ); // wegbauer (way builder) tries to find route to 3d coordinate if no ground at end exists or is not kartenboden (map ground) bauigel.calc_straight_route(start,end); } const char *tool_build_tunnel_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { if( end == koord3d::invalid ) { // Build tunnel mouths if( grund_t *gr=welt->lookup( start ) ) { if( gr->ist_karten_boden() ) { const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); const char *err = NULL; // first check for building portal only if( is_ctrl_pressed() ) { // estimate costs for tunnel portal if( !player->can_afford((-(sint64)desc->get_price())*2) ) { return NOTICE_INSUFFICIENT_FUNDS; } } else { // Now check, if we can built a tunnel here and display costs koord3d end = tunnel_builder_t::find_end_pos(player, start, koord(gr->get_grund_hang()), desc, true, &err ); if( end == koord3d::invalid || end == start ) { // no end found return err; } if( !player->can_afford((-(sint64)desc->get_price())*koord_distance(start,end)) ) { return NOTICE_INSUFFICIENT_FUNDS; } } return tunnel_builder_t::build( player, start.get_2d(), desc, !is_ctrl_pressed() ); } } return "Tunnel must start on single way!"; } else { // Build tunnels way_builder_t bauigel(player); calc_route( bauigel, start, end ); welt->mute_sound(true); bauigel.build(); welt->mute_sound(false); welt->lookup_kartenboden(end.get_2d())->clear_flag(grund_t::marked); return NULL; } } uint8 tool_build_tunnel_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & ) { if( !is_first_click() ) { error = NULL; // All pos are valid for the second click! return 2; } // search for ground // start needs valid tile! grund_t *gr = welt->lookup(pos); if( gr ) { if( gr->hat_wege() ) { const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); // use the check_owner routine of way_builder_t (not player_t!), needs an instance weg_t *w = gr->get_weg_nr(0); if( w==NULL || w->get_desc()->get_wtyp()!=desc->get_waytype() ) { error = NOTICE_UNSUITABLE_GROUND; return 0; } way_builder_t bauigel(player); if(!bauigel.check_owner( w->get_owner(), player )) { error = "Das Feld gehoert\neinem anderen Spieler\n"; return 0; } } } else { error = NOTICE_UNSUITABLE_GROUND; return 0; } // if starting tile is tunnel .. build underground tracks error = NULL; if(gr->ist_tunnel()) { return 2; } // .. otherwise build tunnel mouths (and tunnel behind) else { return 1; } } void tool_build_tunnel_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) { way_builder_t bauigel(player); calc_route( bauigel, start, end ); const tunnel_desc_t *desc = tunnel_builder_t::get_desc(default_param); // now we search a matching way for the tunnels top speed const way_desc_t *wb = desc->get_way_desc(); if(wb==NULL) { // ignore timeline to get consistent results wb = way_builder_t::weg_search( desc->get_waytype(), desc->get_topspeed(), 0, type_flat ); } welt->lookup_kartenboden(end.get_2d())->clear_flag(grund_t::marked); if( bauigel.get_count()>1 ) { // Set tooltip first (no dummygrounds, if bauigel.calc_casts() is called). win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", -bauigel.calc_costs(), bauigel.get_count() ) ); // make dummy route from bauigel for( uint32 j=0; jlookup(pos); if( !gr ) { // We need to create a dummy ground. gr = new tunnelboden_t(pos, slope_t::flat); welt->access(pos.get_2d())->boden_hinzufuegen(gr); } ribi_t::ribi zeige = gr->get_weg_ribi_unmasked(wb->get_wtyp()) | bauigel.get_route().get_ribi( j ); zeiger_t *way = new zeiger_t(pos, player ); if(gr->get_weg_hang()) { way->set_image( wb->get_slope_image_id(gr->get_weg_hang(),0) ); } else if(wb->get_wtyp()!=powerline_wt && ribi_t::is_bend(zeige) && wb->has_diagonal_image()) { way->set_image( wb->get_diagonal_image_id(zeige,0) ); } else { way->set_image( wb->get_image_id(zeige,0) ); } gr->obj_add( way ); marked.insert( way ); way->mark_image_dirty( way->get_image(), 0 ); } welt->lookup(end)->set_flag(grund_t::marked); } } /* removes a way like a driving car ... */ char const* tool_wayremover_t::get_tooltip(player_t const*) const { switch(atoi(default_param)) { case road_wt: return translator::translate("remove roads"); case tram_wt: case track_wt: return translator::translate("remove tracks"); case maglev_wt: return translator::translate("remove maglev tracks"); case narrowgauge_wt: return translator::translate("remove narrowgauge tracks"); case monorail_wt: return translator::translate("remove monorails"); case water_wt: return translator::translate("remove channels"); case air_wt: return translator::translate("remove airstrips"); case powerline_wt: return translator::translate("remove powerlines"); } return NULL; } image_id tool_wayremover_t::get_icon(player_t *) const { if (default_param && way_builder_t::waytype_available((waytype_t)atoi(default_param), welt->get_timeline_year_month())) { return icon; } return IMG_EMPTY; } waytype_t tool_wayremover_t::get_waytype() const { return default_param ? (waytype_t)atoi(default_param) : invalid_wt; } class electron_t : public test_driver_t { bool check_next_tile(const grund_t* gr) const OVERRIDE { return gr->get_leitung()!=NULL; } ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_leitung()->get_ribi(); } waytype_t get_waytype() const OVERRIDE { return invalid_wt; } int get_cost(const grund_t *, const weg_t *, const sint32, ribi_t::ribi) const OVERRIDE { return 1; } bool is_target(const grund_t *,const grund_t *) const OVERRIDE { return false; } }; class way_checker_t : public test_driver_t { private: waytype_t wt; public: way_checker_t(waytype_t w) : wt(w) {} bool check_next_tile(const grund_t* gr) const OVERRIDE { return gr->hat_weg(wt); } ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi(wt); } waytype_t get_waytype() const OVERRIDE { return wt; } int get_cost(const grund_t*, const weg_t*, const sint32, ribi_t::ribi) const OVERRIDE { return 1; } bool is_target(const grund_t*, const grund_t*) const OVERRIDE { return false; } }; class scenario_checker_t : public test_driver_t { public: test_driver_t *other; scenario_t *scenario; uint16 id; player_t *player; ~scenario_checker_t() { delete other; } /** * checks for active scenario, * @returns scenario_checker_t if scenario active, the supplied test_driver otherwise */ static test_driver_t* apply(test_driver_t *test_driver, player_t *player, tool_t *tool) { karte_t *welt = world(); if (is_scenario()) { scenario_checker_t *td2 = new scenario_checker_t(); td2->other = test_driver; td2->scenario = welt->get_scenario(); td2->id = tool->get_id(); td2->player = player; return td2; } return test_driver; } private: bool check_next_tile(const grund_t* gr) const OVERRIDE { return other->check_next_tile(gr) && scenario->is_work_allowed_here(player, id, other->get_waytype(), 0, gr->get_pos())==NULL;} ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return other->get_ribi(gr); } waytype_t get_waytype() const OVERRIDE { return other->get_waytype(); } int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const OVERRIDE { return other->get_cost(gr, w, max_speed, from); } bool is_target(const grund_t *gr,const grund_t *gr2) const OVERRIDE { return other->is_target(gr,gr2); } }; void tool_wayremover_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) { route_t verbindung; bool can_built = calc_route( verbindung, player, start, end ); if( can_built ) { for(koord3d const& pos : verbindung.get_route()) { zeiger_t *marker = new zeiger_t(pos, NULL ); marker->set_image( cursor ); marker->mark_image_dirty( marker->get_image(), 0 ); marked.insert( marker ); welt->lookup(pos)->obj_add( marker ); } } } uint8 tool_wayremover_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d & ) { // search for starting ground waytype_t wt = get_waytype(); grund_t *gr=tool_intern_koord_to_weg_grund(player,welt,pos,wt); if(gr==NULL) { DBG_MESSAGE("tool_wayremover_t()", "no ground on %i,%i",pos.x, pos.y); // wrong ground or not this way here => exit return 0; } // do not remove ground from depot if(gr->get_depot()) { error = NOTICE_UNSUITABLE_GROUND; return 0; } if(is_scenario()) { error = welt->get_scenario()->is_work_allowed_here(player, get_id(), wt, 0, pos); if (error) { dbg->warning("tool_wayremover_t::is_within_limits()", error); return 0; } } error = NULL; return 2; } bool tool_wayremover_t::calc_route( route_t &verbindung, player_t *player, const koord3d &start, const koord3d &end ) { waytype_t wt = get_waytype(); if (wt == tram_wt) { wt = track_wt; } if( start == end ) { verbindung.clear(); grund_t *gr=welt->lookup(start); if( gr && (wt!=powerline_wt ? gr->get_weg(wt)!=NULL : gr->get_leitung()!=NULL) ) { verbindung.append( start ); } } else { // get a default vehicle test_driver_t* test_driver; if( wt!=powerline_wt ) { test_driver = new way_checker_t(wt); } else { test_driver = new electron_t(); } test_driver = scenario_checker_t::apply(test_driver, player, this); verbindung.calc_route(welt, start, end, test_driver, 0, 0); delete test_driver; } DBG_MESSAGE("tool_wayremover_t()","route with %d tile found",verbindung.get_count()); calc_route_error = NULL; bool can_delete = start == end || verbindung.get_count()>1; if( can_delete ) { // found a route => check if I can delete anything on it for(koord3d const& i : verbindung.get_route()) { if (!can_delete) break; grund_t const* const gr = welt->lookup(i); if( wt!=powerline_wt ) { // no way found if( gr==NULL || gr->get_weg(wt)==NULL ) { can_delete = false; break; } // check all if we want to delete the first on a no-ground tile bool check_all = !gr->ist_karten_boden() && gr->has_two_ways() && gr->get_weg_nr(0)->get_waytype()==wt; // we have to do a fine check for( uint i=0; iobj_count() && can_delete; i++ ) { obj_t *obj = gr->obj_bei(i); const uint8 type = obj->get_typ(); // ignore pillars, powerlines if (type == obj_t::pillar || type==obj_t::leitung) { continue; } // ignore flying aircraft if (type == obj_t::air_vehicle && !(static_cast(obj)->is_on_ground())) { continue; } const waytype_t obj_wt = obj->get_waytype(); // way-related things if (obj_wt != invalid_wt) { // check this thing if it has the same waytype or if we want to remove the whole bridge/tunnel tile // special case: stations - take care not to produce station without any way const bool lonely_station = type==obj_t::gebaeude && !gr->has_two_ways(); if (check_all || obj_wt == wt || lonely_station) { can_delete = (calc_route_error = obj->get_removal_error(player)) == NULL; } } // all other stuff else { can_delete = (calc_route_error = obj->get_removal_error(player)) == NULL; } } } else { // for powerline: only a ground and a powerline to remove if( gr==NULL || gr->get_leitung()==NULL || (calc_route_error = gr->get_leitung()->get_removal_error(player))!=NULL ) { can_delete = false; break; } } } } DBG_MESSAGE("tool_wayremover_t()", "route search returned %d", can_delete); return can_delete; } const char *tool_wayremover_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { waytype_t wt = get_waytype(); route_t verbindung; if( !calc_route( verbindung, player, start, end ) ) { DBG_MESSAGE("tool_wayremover_t()","no route found"); if (calc_route_error && *calc_route_error) { return calc_route_error; } else { return "Ways not connected"; } } bool can_delete = true; // assume success // if successful => delete everything for( uint32 i=0; ilookup(verbindung.at(i)); // ground can be missing after deleting a bridge ... if(gr && !gr->is_water()) { if(gr->ist_bruecke()) { if(gr->find()->get_desc()->get_waytype()==wt) { if( bridge_builder_t::is_start_of_bridge(gr) ) { const char *err = NULL; err = bridge_builder_t::remove(player,verbindung.at(i),wt); if(err) { return err; } gr = welt->lookup(verbindung.at(i)); if( !gr ) { // happens with bridges without ramps continue; } } else { // do not remove asphalt from a bridge ... continue; } } } // now the tricky part: delete just part of a way (or everything, if possible) // calculate remaining directions ribi_t::ribi rem = 15 ^ ( verbindung.get_route().get_ribi(i) ); // if start=end tile then delete every direction if( verbindung.get_count() <= 1 ) { rem = 0; } if( wt!=powerline_wt ) { if(!gr->get_flag(grund_t::is_kartenboden) && (gr->get_typ()==grund_t::tunnelboden || gr->get_typ()==grund_t::monorailboden) && gr->get_weg_nr(0)->get_waytype()==wt) { can_delete &= gr->remove_everything_from_way(player,wt,rem); if(can_delete && gr->get_weg(wt)==NULL) { if(gr->get_weg_nr(0)!=0) { gr->remove_everything_from_way(player,gr->get_weg_nr(0)->get_waytype(),ribi_t::none); } gr->obj_loesche_alle(player); gr->mark_image_dirty(); if (gr->is_visible() && gr->get_typ()==grund_t::tunnelboden && i>0) { // visibility test does not influence execution grund_t *bd = welt->access(verbindung.at(i-1).get_2d())->get_kartenboden(); bd->calc_image(); bd->set_flag(grund_t::dirty); } // delete tunnel ground too, if empty welt->access(gr->get_pos().get_2d())->boden_entfernen(gr); delete gr; } } else { can_delete &= gr->remove_everything_from_way(player,wt,rem); if (gr->get_typ() == grund_t::tunnelboden && !gr->hat_wege() ) { // tunnel portal has been removed grund_t* gr_new = new boden_t(gr->get_pos(), gr->get_grund_hang()); welt->access(gr->get_pos().get_2d())->kartenboden_setzen(gr_new); gr = gr_new; } } } else { leitung_t *lt = gr->get_leitung(); if( lt && (rem<->get_ribi())==0 ) { // remove only single connections lt->cleanup(player); delete lt; // delete tunnel ground too, if empty if (gr->get_typ()==grund_t::tunnelboden) { gr->obj_loesche_alle(player); gr->mark_image_dirty(); if (!gr->get_flag(grund_t::is_kartenboden)) { welt->access(gr->get_pos().get_2d())->boden_entfernen(gr); delete gr; } else { grund_t *gr_new = new boden_t(gr->get_pos(), gr->get_grund_hang()); welt->access(gr->get_pos().get_2d())->boden_ersetzen(gr, gr_new); gr_new->calc_image(); } } } // otherwise it is a crossing ... } } // ok, now everything removed ... } // return success return can_delete ? NULL : ""; } /* add catenary during construction */ const way_obj_desc_t *tool_build_wayobj_t::default_electric = NULL; const char* tool_build_wayobj_t::get_tooltip(const player_t *) const { if( build ) { const way_obj_desc_t *desc = get_desc(); if(desc) { tooltip_with_price_maintenance( welt, desc->get_name(), -desc->get_price(), desc->get_maintenance() ); size_t n= strlen(toolstr); if (desc->is_overhead_line()) { // only overheadlines impose topspeed sprintf(toolstr+n, ", %dkm/h", desc->get_topspeed()); } return toolstr; } return NULL; } else { waytype_t wt = (waytype_t)atoi( default_param ); sprintf( toolstr, translator::translate("Remove wayobj %s"), translator::translate(weg_t::waytype_to_string(wt)) ); return toolstr; } } const way_obj_desc_t *tool_build_wayobj_t::get_desc() const { const way_obj_desc_t *desc = default_param ? wayobj_t::find_desc(default_param) : NULL; if(desc==NULL) { desc = default_electric; if(desc==NULL) { desc = wayobj_t::get_overhead_line( track_wt, welt->get_timeline_year_month() ); } } return desc; } waytype_t tool_build_wayobj_t::get_waytype() const { if( build ) { const way_obj_desc_t *desc = get_desc(); return desc ? desc->get_wtyp() : invalid_wt; } else { sint16 wt; return (default_param && std::sscanf(default_param, "%hi", &wt) == 1) ? (waytype_t)wt : invalid_wt; } } bool tool_build_wayobj_t::is_selected() const { const tool_build_wayobj_t *selected = dynamic_cast(welt->get_tool(welt->get_active_player_nr())); return (selected && selected->build==build && selected->get_desc() == get_desc()); } bool tool_build_wayobj_t::init( player_t *player ) { two_click_tool_t::init( player ); if( build ) { desc = get_desc(); if( desc ) { cursor = desc->get_cursor()->get_image_id(0); wt = desc->get_wtyp(); default_electric = desc; } return desc!=NULL; } else { desc = NULL; wt = (waytype_t)atoi( default_param ); return wt != 0; } } bool tool_build_wayobj_t::calc_route( route_t &verbindung, player_t *player, const koord3d& start, const koord3d& to ) { waytype_t waytype = wt; if( waytype == decoration_wt ) { waytype = welt->lookup(start)->get_weg(wt)->get_waytype(); } // special treatment for deports, since track electrication cannot "drive" into tram depot if( waytype == track_wt ) { if( depot_t *dp = welt->lookup(start)->get_depot() ) { waytype = dp->get_waytype(); } else if( depot_t *dp = welt->lookup(to)->get_depot() ) { waytype = dp->get_waytype(); } } // get a default vehicle vehicle_desc_t remover_desc( waytype, 500, vehicle_desc_t::diesel ); vehicle_t* test_vehicle = vehicle_builder_t::build(start, player, NULL, &remover_desc); test_vehicle->set_flag( obj_t::not_on_map ); test_driver_t* test_driver = scenario_checker_t::apply(test_vehicle, player, this); bool can_built; if( start != to ) { can_built = verbindung.calc_route(welt, start, to, test_driver, 0, 0); } else { verbindung.clear(); verbindung.append( start ); can_built = true; } delete test_driver; return can_built; } uint8 tool_build_wayobj_t::is_valid_pos( player_t* player, const koord3d& pos, const char *&error, const koord3d & ) { // search for starting ground grund_t *gr=tool_intern_koord_to_weg_grund(player, welt, pos, wt ); if( gr == NULL ) { DBG_MESSAGE("tool_build_wayobj_t::is_within_limits()", "no ground on %s",pos.get_str()); // wrong ground or not this way here => exit return 0; } error = NULL; return 2; } void tool_build_wayobj_t::mark_tiles( player_t* player, const koord3d &start, const koord3d &end ) { route_t verbindung; bool can_built = calc_route( verbindung, player, start, end ); if( can_built ) { sint32 cost_estimate = 0; bool keep_existing_faster_ways = !is_ctrl_pressed(); for( uint32 j = 0; j < verbindung.get_count(); j++ ) { koord3d pos = verbindung.at(j); grund_t *gr = welt->lookup(pos); ribi_t::ribi show = verbindung.get_route().get_ribi(j); // Search a matching catenary on gr. wayobj_t *wayobj = gr->get_wayobj( wt ); if( build ) { cost_estimate += desc->get_price(); if( wayobj ) { show = show | wayobj->get_dir(); // Already a catenary here -> costs only, if new catenary is faster if( (wayobj->get_desc()->get_topspeed() >= desc->get_topspeed() && keep_existing_faster_ways) || wayobj->get_desc() == desc ) { cost_estimate -= desc->get_price(); } } } else if( wayobj ) { cost_estimate += wayobj->get_desc()->get_price(); } zeiger_t *way_obj = NULL; if( build ) { way_obj = new zeiger_t(pos, player ); if( gr->get_weg_hang() ) { way_obj->set_foreground_image( desc->get_front_slope_image_id(gr->get_weg_hang()) ); way_obj->set_image( desc->get_back_slope_image_id(gr->get_weg_hang()) ); } else if( ribi_t::is_bend(show) && desc->has_diagonal_image() ) { way_obj->set_foreground_image( desc->get_front_diagonal_image_id(show) ); way_obj->set_image( desc->get_back_diagonal_image_id(show) ); } else { way_obj->set_foreground_image( desc->get_front_image_id(show) ); way_obj->set_image( desc->get_back_image_id(show) ); } } else { if( gr->get_wayobj( wt ) ) { way_obj = new zeiger_t(pos, player ); way_obj->set_image( cursor ); //skinverwaltung_t::bauigelsymbol->get_image_id(0)); } } if( way_obj ) { way_obj->mark_image_dirty( way_obj->get_image(), 0 ); gr->obj_add( way_obj ); marked.insert( way_obj ); } } win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", -cost_estimate, verbindung.get_count() ) ); } } const char *tool_build_wayobj_t::do_work( player_t* player, const koord3d &start, const koord3d &end ) { route_t verbindung; bool can_built = calc_route( verbindung, player, start, end ); DBG_MESSAGE("tool_build_wayobj_t::work()","route search returned %d",can_built); const char *err = NULL; if(!can_built) { return "Ways not connected"; } bool keep_existing_faster_ways = !is_ctrl_pressed(); // build wayobj ... koord3d_vector_t const& r = verbindung.get_route(); for(uint32 i=0; ilookup(r[i]); for(int n=0; nobj_count(); n++ ) { obj_t *obj = gr->obj_bei(n); if( obj && obj->get_typ()==obj_t::wayobj ) { wayobj_t *wo = static_cast(obj); if( wo->get_waytype() == wt ) { // only remove matching waytype const char *err = wo->get_removal_error( player ); if( !err ) { wo->cleanup( player ); delete wo; } else { break; } } } } } } // Update depots (maybe remove electric tab?). Depots can only be on first and last tile. if( depot_t *dep = welt->lookup(r[0])->get_depot() ) { dep->update_win(); } if( depot_t *dep = welt->lookup(r.back())->get_depot() ) { dep->update_win(); } return err; } image_id tool_remove_wayobj_t::get_icon(player_t*) const { if (default_param && way_builder_t::waytype_available((waytype_t)atoi(default_param), welt->get_timeline_year_month())) { return icon; } return IMG_EMPTY; } /* build all kind of station extension buildings */ const char *tool_build_station_t::tool_station_building_aux(player_t *player, bool extend_public_halt, koord3d pos, const building_desc_t *desc, sint8 rotation ) { koord k = pos.get_2d(); // need kartenboden (map ground) if (welt->lookup_kartenboden(k)->get_hoehe() != pos.z) { return ""; } DBG_MESSAGE("tool_station_building_aux()", "building mail office/station building on square %d,%d", k.x, k.y); // Player player pays for the construction // but we try to extend stations of Player new_owner that may be the public player player_t *new_owner = extend_public_halt ? welt->get_public_player() : player; koord offsets; halthandle_t halt; const char *msg = NOTICE_TILE_FULL; if( rotation==-1 ) { //no predefined rotation int best_halt = 0; int any_halt = 0; // find valid rotations (since halt extensions are symmetric, we need to check only two) bool any_ok = false; for( int r=0; r<2; r++ ) { koord testsize = desc->get_size(r); for( sint8 j=3; j>=0; j-- ) { bool ok = true; koord offset(((j&1)^1)*(testsize.x-1),((j>>1)&1)*(testsize.y-1)); if(welt->square_is_free(k-offset, testsize.x, testsize.y, NULL, desc->get_allowed_climate_bits())) { // first we must check over/under halt halthandle_t last_halt; for( sint16 x=0; xaccess( k-offset+koord(x,y) ); if (pl) { for( uint8 i=0; i < pl->get_boden_count(); i++ ) { halthandle_t test_halt = pl->get_boden_bei(i)->get_halt(); if(test_halt.is_bound()) { if(!player_t::check_owner( new_owner, test_halt->get_owner())) { // there is another player's halt ok = false; msg = "Das Feld gehoert\neinem anderen Spieler\n"; } else if(!last_halt.is_bound()) { last_halt = test_halt; } else if(last_halt != test_halt) { // there are several halts ok = false; msg = "Several halts found."; } } } } } } if(!ok) { continue; } // well, at least this is theoretical possible here any_ok = true; if(rotation==-1) { // we can build it. reserve this one // This needs to build a building at under/over a halt. rotation = r; offsets = offset; } koord test_start = k-offset; // find all surrounding tiles with a stop // for following section of code arrays are arranged such that // 0 - facing north // 1 - facing west // 2 - facing south // 3 - facing east int neighbour_halts[4] = { 0, 0, 0, 0 }; int best_halts[4] = { 0, 0, 0, 0 }; // test also diagonal corners (that is why from -1 to size!) for( sint16 y=-1; y<=testsize.y; y++ ) { for( sint16 x=-1; x<=testsize.x; (x==-1 && y>-1 && yaccess( test_start+koord(x,y) ); if( pl ) { for( uint b=0; b < pl->get_boden_count(); b++ ) { grund_t *gr = pl->get_boden_bei(b); if( gr->is_halt() && gr->get_halt().is_bound() && new_owner == gr->get_halt()->get_owner() ) { halt = gr->get_halt(); gebaeude_t *gb = gr->find(); bool best = gr->hat_wege() && gb && gb->get_tile()->get_desc()->get_extra()==desc->get_extra(); // north if( y==-1 ) { neighbour_halts[0] ++; if( best ) { best_halts[0] ++; } } // west if( x==-1 ) { neighbour_halts[1] ++; if( best ) { best_halts[1] ++; } } // south if( y==testsize.y ) { neighbour_halts[2] ++; if( best ) { best_halts[2] ++; } } // east if( x==testsize.x ) { neighbour_halts[3] ++; if( best ) { best_halts[3] ++; } } } } } } } // now find out, if this offset/rotation is better ... (i.e. matches more fitting buildings) // for r=0 we check north and south, for r=1 we check east and west for( int i=r; i<4; i+=2 ) { if( best_halts[i]>best_halt || (best_halt==0 && neighbour_halts[i]>any_halt) ) { best_halt = best_halts[i]; any_halt = neighbour_halts[i]; rotation = i; offsets = offset; } } } } } // no suitable ground here ... if( !any_ok ) { return msg; } // check over/under halt again for( sint16 x=0; xget_x(rotation); x++ ) { for( sint16 y=0; yget_y(rotation); y++ ) { const planquadrat_t *pl = welt->access( k-offsets+koord(x,y) ); for( uint8 i=0; i < pl->get_boden_count(); i++ ) { halthandle_t test_halt = pl->get_boden_bei(i)->get_halt(); if( test_halt.is_bound() && player_t::check_owner( new_owner, test_halt->get_owner()) ) { halt = test_halt; break; } } } } // is there no halt to connect? if( !halt.is_bound() ) { return "Post muss neben\nHaltestelle\nliegen!\n"; } } else { // rotation was pre-selected; just search for stop now if (rotation < desc->get_all_layouts()) { dbg->warning("tool_station_building_aux()", "%s rotation larger than %d", this->default_param, desc->get_all_layouts()); rotation %= desc->get_all_layouts(); } koord testsize = desc->get_size(rotation); offsets = koord(0,0); if( !welt->square_is_free(k, testsize.x, testsize.y, NULL, desc->get_allowed_climate_bits()) ) { return NOTICE_TILE_FULL; } // check over/under halt for( sint16 x=0; xaccess(k+koord(x,y)); for( uint8 i=0; i < pl->get_boden_count(); i++ ) { halthandle_t test_halt = pl->get_boden_bei(i)->get_halt(); if(test_halt.is_bound()) { if(!player_t::check_owner( new_owner, test_halt->get_owner())) { return "Das Feld gehoert\neinem anderen Spieler\n"; } else if(!halt.is_bound()) { halt = test_halt; } else if(halt != test_halt) { return "Several halts found."; } } } } } if(!halt.is_bound()) { halt = suche_nahe_haltestelle(new_owner, welt, welt->lookup_kartenboden(k)->get_pos(), desc->get_x(rotation), desc->get_y(rotation) ); // is there no halt to connect? if( !halt.is_bound() ) { return "Post muss neben\nHaltestelle\nliegen!\n"; } } } if( rotation>desc->get_all_layouts() ) { rotation %= desc->get_all_layouts(); } hausbauer_t::build(halt->get_owner(), pos.get_2d()-offsets, rotation, desc, &halt); sint32 const factor = desc->get_x() * desc->get_y(); sint64 cost = -desc->get_price(welt) * factor; if( player!=halt->get_owner() && halt->get_owner()==welt->get_public_player() ) { // public stops are expensive! cost -= (desc->get_maintenance(welt) * factor * 60); } // difficult to distinguish correctly most suitable waytype player_t::book_construction_costs(player, cost, k, desc->get_finance_waytype()); halt->recalc_station_type(); return NULL; } /* build a dock either small or large */ const char *tool_build_station_t::tool_station_dock_aux(player_t *player, koord3d pos, const building_desc_t *desc) { // the cursor cannot be outside the map from here on koord k = pos.get_2d(); grund_t *gr = welt->lookup_kartenboden(k); if (gr->get_hoehe()!= pos.z) { return ""; } slope_t::type hang = gr->get_grund_hang(); // first get the size int len = desc->get_y()-1; koord dx(hang); koord last_k = k - dx*len; halthandle_t halt; // check, if we can build here ... if(!slope_t::is_single(hang)) { return "Dock must be built on single slope!"; } else { // iterate up to max(len,1) to ensure that there is at least one tile of water // in front of the dock for(int i=0; i<=max(len,1); i++ ) { if(!welt->is_within_limits(k-dx*i)) { // need at least a single tile to navigate ... return "Zu nah am Kartenrand"; } // search for nearby stops const planquadrat_t* pl = welt->access(k-dx*i); for( uint8 j=0; j < pl->get_boden_count(); j++ ) { halthandle_t test_halt = pl->get_boden_bei(j)->get_halt(); if(test_halt.is_bound()) { if(!player_t::check_owner( player, test_halt->get_owner())) { return "Das Feld gehoert\neinem anderen Spieler\n"; } else if(!halt.is_bound()) { halt = test_halt; } else if(halt != test_halt) { return "Several halts found."; } } } // check whether we can build something const grund_t *gr=welt->lookup_kartenboden(k-dx*i); if (gr->get_hoehe() != pos.z) { return NOTICE_UNSUITABLE_GROUND; } if (i <= len) { if (const char *msg = gr->kann_alle_obj_entfernen(player)) { return msg; } } if (i==0) { // start tile on slope near water if(gr->hat_wege() || gr->get_typ()!=grund_t::boden || gr->is_halt()) { return NOTICE_TILE_FULL; } } else { // all other tiles in water (allowing one-tile docks on rivers) if (!gr->is_water() && !(len==0 && i==1 && gr->hat_weg(water_wt))) { return NOTICE_UNSUITABLE_GROUND; } if (gr->find() || gr->get_depot() || gr->is_halt()) { return NOTICE_TILE_FULL; } } } } // remove everything from tile gr->obj_loesche_alle(player); koord bau_pos = k; int layout = 0; koord dx2; switch(hang) { case slope_t::south: case slope_t::south*2: layout = 0; dx2 = koord::west; break; case slope_t::east: case slope_t::east*2: layout = 1; dx2 = koord::north; break; case slope_t::north: case slope_t::north*2: layout = 2; dx2 = koord::west; bau_pos = last_k; break; case slope_t::west: case slope_t::west*2: layout = 3; dx2 = koord::north; bau_pos = last_k; break; } // handle 16 layouts bool change_layout = false; if(desc->get_all_layouts()==16) { if( layout<2 ) { layout = 15-layout; } else { layout = 9-layout; } change_layout = true; } // oriented buildings here - get neighbouring layouts const grund_t* gr_neigh = welt->lookup_kartenboden(k+dx2); // find out if middle end or start tile if(gr_neigh && gr_neigh->is_halt() && player_t::check_owner( player, gr_neigh->get_halt()->get_owner() )) { gebaeude_t *gb = gr_neigh->find(); if(gb && (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock || gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock) ) { if(change_layout) { layout -= 4; } if(gb->get_tile()->get_desc()->get_all_layouts()==16) { sint8 ly = gb->get_tile()->get_layout(); if(ly&0x02) { gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFD,0,0), false ); } } } } gr_neigh = welt->lookup_kartenboden(k-dx2); if(gr_neigh && gr_neigh->is_halt() && player_t::check_owner( player, gr_neigh->get_halt()->get_owner() )) { gebaeude_t *gb = gr_neigh->find(); if(gb && (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock || gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock) ) { if(change_layout) { layout -= 2; } if(gb->get_tile()->get_desc()->get_all_layouts()==16) { sint8 ly = gb->get_tile()->get_layout(); if(ly&0x04) { gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFB,0,0), false ); } } } } if(!halt.is_bound()) { halt = suche_nahe_haltestelle(player, welt, welt->lookup_kartenboden(k)->get_pos() ); } bool neu = !halt.is_bound(); if(neu) { if( gr && gr->get_halt().is_bound() ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // ok, really new stop on this tile then halt = haltestelle_t::create(k, player); } hausbauer_t::build(halt->get_owner(), bau_pos, layout, desc, &halt); sint64 costs = -desc->get_price(welt); if( player!=halt->get_owner() && player != welt->get_public_player() ) { // public stops are expensive! // (Except for the public player itself) costs -= (desc->get_maintenance(welt) * 60); } for( int i=0; i<=len; i++ ) { koord p=k-dx*i; player_t::book_construction_costs(player, costs, p, water_wt); } halt->recalc_station_type(); if( env_t::station_coverage_show && welt->get_zeiger()->get_pos().get_2d()==k ) { // since we are larger now ... halt->mark_unmark_coverage( true ); } if(neu) { char* const name = halt->create_name(k, "Dock"); halt->set_name( name ); free(name); } return NULL; } /* build a dock either small or large */ const char *tool_build_station_t::tool_station_flat_dock_aux(player_t *player, koord3d pos, const building_desc_t *desc, sint8 rotation) { // the cursor cannot be outside the map from here on const koord k = pos.get_2d(); grund_t *gr = welt->lookup_kartenboden(k); if (gr->get_hoehe()!= pos.z) { return ""; } // first get the size int len = desc->get_size().y-1; // check, if we can build here ... if( !gr->ist_natur() || gr->get_grund_hang() != slope_t::flat ) { return NOTICE_UNSUITABLE_GROUND; } // now find the direction // first: find the next water ribi_t::ribi water_dir = 0; uint8 total_dir = 0; for( uint8 i=0; i<4; i++ ) { if( grund_t *gr = welt->lookup_kartenboden(k+koord::nesw[i]) ) { if( gr->is_water() && gr->get_hoehe() == pos.z) { water_dir |= ribi_t::nesw[i]; total_dir ++; } } } // not surrounded by water => fail if( total_dir == 0 ) { return NOTICE_UNSUITABLE_GROUND; } // prefer layouts that reach an existing halt ribi_t::ribi halt_dir = 0; halthandle_t test_halt[4]; for( uint8 ii=0; ii<4; ii++ ) { if( (water_dir & ribi_t::nesw[ii]) == 0 ) { continue; } const koord dx = koord::nesw[ii]; const char *last_error = NULL; for(int i=0; i<=len; i++ ) { // check whether we can build something const grund_t *gr = welt->lookup_kartenboden(k+dx*i); if( !gr ) { // need at least a single tile to navigate ... last_error = "Zu nah am Kartenrand"; break; } if (gr->get_hoehe() != pos.z) { last_error = NOTICE_UNSUITABLE_GROUND; break; } // search for nearby stops const planquadrat_t* pl = welt->access(k+dx*i); for( uint8 j=0; j < pl->get_boden_count() && !test_halt[ii].is_bound(); j++ ) { halthandle_t halt = pl->get_boden_bei(j)->get_halt(); if (halt.is_bound() && player_t::check_owner( player, halt->get_owner()) ) { test_halt[ii] = halt; halt_dir |= ribi_t::nesw[ii]; } } if( (last_error = gr->kann_alle_obj_entfernen(player)) ) { break; } if (i>0) { // all other tiles in water if (!gr->is_water() || gr->find() || gr->get_depot() || gr->is_halt()) { last_error = NOTICE_TILE_FULL; } } } // error: then remove this direction if( last_error ) { water_dir &= ~ribi_t::nesw[ii]; if( --total_dir == 0 ) { // no duitable directions found return last_error; } } } // now we may have more than one dir left if (rotation == -1 && total_dir > 1 && !ribi_t::is_single(water_dir & halt_dir) ) { return "More than one possibility to build this dock found."; } // remove everything from tile gr->obj_loesche_alle(player); koord dx = koord::invalid; koord last_k; uint8 layout = 0; // building orientation halthandle_t halt; koord bau_pos = k; for( uint8 i=0; i<4; i++ ) { if( water_dir & ribi_t::nesw[i] ) { dx = koord::nesw[i]; halt = test_halt[i]; koord last_k = k + dx*len; // layout: north 2, west 3, south 0, east 1 static const uint8 nesw_to_layout[4] = { 2, 1, 0, 3 }; layout = nesw_to_layout[i]; if( layout>=2 ) { // reverse construction in these directions bau_pos = last_k; } if (rotation == layout) { // desired rotation works break; } if (rotation != -1) { // desired rotation not possible, try others if( --total_dir == 0 ) { return NOTICE_UNSUITABLE_GROUND; } } } } // handle 16 layouts bool change_layout = false; if(desc->get_all_layouts()==16) { if( layout<2 ) { layout = 15-layout; } else { layout = 9-layout; } change_layout = true; } // oriented buildings here - get neighbouring layouts koord dx2 = dx; dx2.rotate90(0); gr = welt->lookup_kartenboden(k+dx2); // find out if middle end or start tile if(gr && gr->is_halt() && player_t::check_owner( player, gr->get_halt()->get_owner() )) { gebaeude_t *gb = gr->find(); if(gb && (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock || gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock) ) { if(change_layout) { layout -= 4; } if(gb->get_tile()->get_desc()->get_all_layouts()==16) { sint8 ly = gb->get_tile()->get_layout(); if(ly&0x02) { gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFD,0,0), false ); } } } } gr = welt->lookup_kartenboden(k-dx2); if(gr && gr->is_halt() && player_t::check_owner( player, gr->get_halt()->get_owner() )) { gebaeude_t *gb = gr->find(); if(gb && (gb->get_tile()->get_desc()->get_type()==building_desc_t::dock || gb->get_tile()->get_desc()->get_type()==building_desc_t::flat_dock) ) { if(change_layout) { layout -= 2; } if(gb->get_tile()->get_desc()->get_all_layouts()==16) { sint8 ly = gb->get_tile()->get_layout(); if(ly&0x04) { gb->set_tile( gb->get_tile()->get_desc()->get_tile(ly&0xFB,0,0), false ); } } } } DBG_MESSAGE("tool_station_flat_dock_aux()","building dock from square (%d,%d) to (%d,%d) layout=%i", k.x, k.y, last_k.x, last_k.y, layout ); if(!halt.is_bound()) { halt = suche_nahe_haltestelle(player, welt, welt->lookup_kartenboden(k)->get_pos() ); } bool neu = !halt.is_bound(); if(neu) { if( gr && gr->get_halt().is_bound() ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // ok, really new stop on this tile then halt = haltestelle_t::create(k, player); } hausbauer_t::build(halt->get_owner(), bau_pos, layout, desc, &halt); sint64 costs = -desc->get_price(welt); if( player!=halt->get_owner() && player != welt->get_public_player() ) { // public stops are expensive! // (Except for the public player itself) costs -= (desc->get_maintenance(welt) * 60); } for( int i=0; i<=len; i++ ) { koord p=k-dx*i; player_t::book_construction_costs(player, costs, p, water_wt); } halt->recalc_station_type(); if( env_t::station_coverage_show && welt->get_zeiger()->get_pos().get_2d()==k ) { // since we are larger now ... halt->mark_unmark_coverage( true ); } if(neu) { char* const name = halt->create_name(k, "Dock"); halt->set_name( name ); free(name); } else { halt->recalc_basis_pos(); } return NULL; } // build all types of stops but sea harbours const char *tool_build_station_t::tool_station_aux(player_t *player, koord3d pos, const building_desc_t *desc, sint8 layout, waytype_t wegtype, const char *type_name ) { koord k = pos.get_2d(); DBG_MESSAGE("tool_station_aux()", "building %s on square %d,%d for waytype %x", desc->get_name(), k.x, k.y, wegtype); const char *p_error=(desc->get_all_layouts()==4) ? "No terminal station here!" : "No through station here!"; // underground is checked in work(); if underground only simple stations are allowed // get valid ground grund_t *bd = tool_intern_koord_to_weg_grund(player, welt, pos, wegtype); if( !bd || bd->get_weg_hang()!=slope_t::flat ) { // only flat tiles, only one stop per map square return "No suitable way on the ground!"; } if( bd->ist_tunnel() && bd->ist_karten_boden() ) { // do not build on tunnel entries return "No suitable way on the ground!"; } if( bd->get_depot() ) { // not on depots return NOTICE_UNSUITABLE_GROUND; } if( bd->hat_weg(air_wt) && bd->get_weg(air_wt)->get_desc()->get_styp()!=type_flat ) { return "Flugzeughalt muss auf\nRunway liegen!\n"; } if( layout <= -1 || layout > desc->get_all_layouts() ) { // find out orientation ... ribi_t::ribi ribi = ribi_t::none; if( desc->get_all_layouts()==2 || desc->get_all_layouts()==8 || desc->get_all_layouts()==16 ) { // through station if( bd->has_two_ways() ) { // a crossing or maybe just a tram track on a road ... ribi = bd->get_weg_nr(0)->get_ribi_unmasked() | bd->get_weg_nr(1)->get_ribi_unmasked(); } else if( bd->hat_wege() ) { ribi = bd->get_weg_nr(0)->get_ribi_unmasked(); } // not straight: sorry cannot build here ... if( !ribi_t::is_straight(ribi) ) { return p_error; } layout = (ribi & ribi_t::northsouth)?0 :1; } else if( desc->get_all_layouts()==4 ) { // terminal station if( bd->hat_wege() ) { ribi = bd->get_weg_nr(0)->get_ribi_unmasked(); } // sorry cannot build here ... (not a terminal tile) if( !ribi_t::is_single(ribi) ) { return p_error; } switch(ribi) { case ribi_t::south: layout = 0; break; case ribi_t::east: layout = 1; break; case ribi_t::north: layout = 2; break; case ribi_t::west: layout = 3; break; } } else { // something wrong with station number of layouts dbg->fatal( "tool_station_t::tool_station_aux", "%s has wrong number of layouts (must be 2,4,8,16!)", desc->get_name() ); } if( desc->get_all_layouts() == 8 || desc->get_all_layouts() == 16 ) { // through station - complex layout // bits // 1 = north south/east west (as simple layout) // 2 = use far end image \ can be combined // 3 = use near end image / to use both end image // 4 = platform face - 0 = far, 1 = near // bit 1 has already been set ribi_t::ribi next_own = ribi_t::none; sint8 offset = bd->get_hoehe()+bd->get_weg_yoff()/TILE_HEIGHT_STEP; grund_t *gr; sint32 neighbour_layout[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; for( unsigned i=0; i<4; i++ ) { // oriented buildings here - get neighbouring layouts gr = welt->lookup(koord3d(k+koord::nesw[i],offset)); if(!gr) { // check whether bridge end tile grund_t * gr_tmp = welt->lookup(koord3d(k+koord::nesw[i],offset-1)); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) { gr = gr_tmp; } else { grund_t * gr_tmp = welt->lookup(koord3d(k+koord::nesw[i],offset-2)); if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 2) { gr = gr_tmp; } } } if( gr && gr->get_halt().is_bound() ) { // check, if there is an oriented stop const gebaeude_t* gb = gr->find(); if(gb && gb->get_tile()->get_desc()->get_all_layouts()>4 && (gb->get_tile()->get_desc()->get_type()>building_desc_t::dock || gb->get_tile()->get_desc()->get_type()>building_desc_t::flat_dock) ) { next_own |= ribi_t::nesw[i]; neighbour_layout[ribi_t::nesw[i]] = gb->get_tile()->get_layout(); } } } // now for the details ribi_t::ribi senkrecht = ~ribi_t::doubles(ribi); ribi_t::ribi waagerecht = ribi_t::doubles(ribi); if(next_own!=ribi_t::none) { // oriented buildings here if(ribi_t::is_single(ribi & next_own)) { // only a single next neighbour on the same track layout |= neighbour_layout[ribi & next_own] & 8; } else if(ribi_t::is_straight(ribi & next_own)) { // two neighbours on the same track, use the north/west one layout |= neighbour_layout[ribi & next_own & ribi_t::northwest] & 8; } else if(ribi_t::is_single((~ribi) & waagerecht & next_own)) { // neighbour across break in track layout |= neighbour_layout[(~ribi) & waagerecht & next_own] & 8; } else { // no buildings left and right // oriented buildings left and right if(neighbour_layout[senkrecht & next_own & ribi_t::northwest] != -1) { // just rotate layout layout |= 8-(neighbour_layout[senkrecht & next_own & ribi_t::northwest]&8); } else { if(neighbour_layout[senkrecht & next_own & ribi_t::southeast] != -1) { layout |= 8-(neighbour_layout[senkrecht & next_own & ribi_t::southeast]&8); } } } } assert(layout >= 0); // avoid orientation on 8 tiled buildings layout &= (desc->get_all_layouts()-1); } } else { // obey predefined layout // todo: check way ribis } halthandle_t old_halt = bd->get_halt(); sint64 old_cost = 0; bool recalc_schedule = false; halthandle_t halt; if( old_halt.is_bound() ) { gebaeude_t* gb = bd->find(); const building_desc_t *old_desc = gb->get_tile()->get_desc(); if( old_desc == desc ) { // already has the same station return NULL; } if( old_desc->get_capacity() >= desc->get_capacity() && !is_ctrl_pressed() ) { return "Upgrade must have\na higher level"; } old_cost = old_desc->get_price(welt)*old_desc->get_x()*old_desc->get_y(); gb->cleanup( NULL ); delete gb; halt = old_halt; if( old_desc->get_enabled() != desc->get_enabled() ) { recalc_schedule = true; } } else { halt = suche_nahe_haltestelle(player,welt,bd->get_pos()); } // seems everything ok, lets build bool neu = !halt.is_bound(); if(neu) { if( bd->get_halt().is_bound() ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } halt = haltestelle_t::create(k, player); } hausbauer_t::build_station_extension_depot(halt->get_owner(), bd->get_pos(), layout, desc, &halt); halt->recalc_station_type(); if(neu) { char* const name = halt->create_name(k, type_name); halt->set_name(name); free(name); } else { halt->recalc_basis_pos(); } // cost to build new station sint64 cost = -desc->get_price(welt)*desc->get_x()*desc->get_y(); // discount for existing station cost += old_cost/2; if( player!=halt->get_owner() && player != welt->get_public_player() ) { // public stops are expensive! // (Except for the public player itself) cost -= (desc->get_maintenance(welt) * desc->get_x() * desc->get_y() * 60); } player_t::book_construction_costs(player, cost, k, wegtype); if( env_t::station_coverage_show && welt->get_zeiger()->get_pos().get_2d()==k ) { // since we are larger now ... halt->mark_unmark_coverage( true ); } // the new station (after upgrading) might accept different goods => needs new schedule if( recalc_schedule ) { welt->set_schedule_counter(); } return NULL; } // gives the description and sets the rotation value const building_desc_t *tool_build_station_t::get_desc( sint8 &rotation ) const { if (strempty(default_param)) { return NULL; } char *building = strdup( default_param ); const building_tile_desc_t *tdsc = NULL; rotation = -1; if( building ) { char *p = strrchr( building, ',' ); if( p ) { *p++ = 0; if (std::sscanf(p, "%hhd", &rotation) != 1 || rotation < -1 || rotation > 15) { free(building); return NULL; } } tdsc = hausbauer_t::find_tile(building, 0); free( building ); } return tdsc ? tdsc->get_desc() : NULL; } bool tool_build_station_t::init( player_t * ) { sint8 rotation = -1; const building_desc_t *bdsc = get_desc( rotation ); if( bdsc==NULL || bdsc->get_cursor()==NULL) { return false; } cursor = bdsc->get_cursor()->get_image_id(0); if( !can_use_gui() ) { // do not change cursor return true; } if( (bdsc->get_type()==building_desc_t::generic_extension || bdsc->get_type()==building_desc_t::flat_dock) && bdsc->get_all_layouts()>1 ) { if( is_ctrl_pressed() && rotation==-1 ) { // call station dialog instead destroy_win( magic_station_building_select ); create_win( new station_building_select_t(bdsc), w_info, magic_station_building_select); // we do not activate building yet; else uncomment the return statement return false; } else if( rotation>=0 ) { // rotation is already fixed cursor_area = koord( bdsc->get_x(rotation), bdsc->get_y(rotation) ); cursor_centered = false; cursor_offset = koord(0,0); if (bdsc->get_type()==building_desc_t::flat_dock && rotation >= 2 ) { cursor_offset = cursor_area - koord(1,1); } } else { goto set_area_cov; } } else { set_area_cov: uint16 const cov = welt->get_settings().get_station_coverage() * 2 + 1; cursor_area = koord(cov, cov); cursor_centered = true; cursor_offset = koord(0,0); } return true; } image_id tool_build_station_t::get_icon( player_t * ) const { sint8 dummy; const building_desc_t *desc=get_desc(dummy); if (desc == NULL) { return IMG_EMPTY; } if( grund_t::underground_mode==grund_t::ugm_all ) { // in underground mode, buildings will be done invisible above ground => disallow such confusion if( desc->get_type()!=building_desc_t::generic_stop || desc->get_extra()==air_wt) { return IMG_EMPTY; } if( desc->get_type()==building_desc_t::generic_stop && !desc->can_be_built_underground()) { return IMG_EMPTY; } } if( grund_t::underground_mode==grund_t::ugm_none ) { if( desc->get_type()==building_desc_t::generic_stop && !desc->can_be_built_aboveground()) { return IMG_EMPTY; } } return icon; } const char* tool_build_station_t::get_tooltip(const player_t *) const { sint8 dummy; building_desc_t const* desc = get_desc(dummy); if (desc == NULL) { return ""; } sint64 price = 0; sint64 maint = 0; uint32 cap = desc->get_capacity(); // This is always correct in the desc object. maint = desc->get_maintenance(welt); if( desc->get_type()==building_desc_t::generic_stop || desc->get_type()==building_desc_t::generic_extension || desc->get_type()==building_desc_t::dock || desc->get_type()==building_desc_t::flat_dock ) { price = -desc->get_price(welt); } else { return "Illegal description"; } if(desc->get_type()==building_desc_t::generic_extension || desc->get_type()==building_desc_t::dock || desc->get_type()==building_desc_t::flat_dock) { const sint16 size_multiplier = desc->get_size().x * desc->get_size().y; price *= size_multiplier; cap *= size_multiplier; maint *= size_multiplier; } return tooltip_with_price_maintenance_capacity(welt, desc->get_name(), price, maint, cap, desc->get_enabled()); } waytype_t tool_build_station_t::get_waytype() const { sint8 dummy; building_desc_t const* desc = get_desc(dummy); switch (desc ? desc->get_type() : building_desc_t::generic_extension) { case building_desc_t::generic_stop: return (waytype_t)desc->get_extra(); case building_desc_t::dock: case building_desc_t::flat_dock: return water_wt; case building_desc_t::generic_extension: default: return ignore_wt; } } const char *tool_build_station_t::check_pos( player_t*, koord3d pos ) { if( grund_t *gr = welt->lookup( pos ) ) { sint8 rotation; const building_desc_t *desc = get_desc(rotation); if(desc == NULL) { // tool is in bad state, eg due to invalid tool parameters DBG_DEBUG("tool_build_station_t::check_pos()", "Cannot resolve building descriptor, default_param=\"%s\".", default_param); return "ENGINE ERROR: Build station tool cannot resolve a building descriptor."; } if( grund_t *bd = welt->lookup_kartenboden( pos.get_2d() ) ) { const bool underground = bd->get_hoehe()>gr->get_hoehe(); if( underground ) { // in underground mode, buildings will be done invisible above ground => disallow such confusion if( desc->get_type()!=building_desc_t::generic_stop || desc->get_extra()==air_wt) { return "Cannot built this station/building\nin underground mode here."; } if( desc->get_type()==building_desc_t::generic_stop && !desc->can_be_built_underground()) { return "Cannot built this station/building\nin underground mode here."; } } else if( desc->get_type()==building_desc_t::generic_stop && !desc->can_be_built_aboveground()) { return "This station/building\ncan only be built underground."; } return NULL; } } // no ground here??? return "Missing ground (fatal!)"; } char const* tool_build_station_t::move(player_t* const player, uint16 const b, koord3d const pos) { if (b == 0) { return NULL; } if (env_t::networkmode) { // queue tool for network nwc_tool_t* nwc = new nwc_tool_t(player, this, pos, welt->get_steps(), welt->get_map_counter(), false); network_send_server(nwc); return NULL; } else { return work(player, pos); } } const char *tool_build_station_t::work( player_t *player, koord3d pos ) { const grund_t *gr = welt->lookup(pos); if(!gr) { return ""; } // ownership allowed? halthandle_t halt = gr->get_halt(); if(halt.is_bound() && !player_t::check_owner( player, halt->get_owner())) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // check underground / above ground if (const char* msg = check_pos(player, pos)) { return msg; } // remove old labels on station tiles if (label_t* l = gr->find()) { if (const char *msg = l->get_removal_error(player)) { return msg; } delete l; } sint8 rotation = 0; const building_desc_t *desc=get_desc(rotation); const char *msg = NULL; switch (desc->get_type()) { case building_desc_t::dock: msg = tool_build_station_t::tool_station_dock_aux(player, pos, desc ); break; case building_desc_t::flat_dock: msg = tool_build_station_t::tool_station_flat_dock_aux(player, pos, desc, rotation ); break; case building_desc_t::generic_extension: msg = tool_build_station_t::tool_station_building_aux(player, false, pos, desc, rotation ); if (msg) { // try to build near a public halt msg = tool_build_station_t::tool_station_building_aux(player, true, pos, desc, rotation ); } break; case building_desc_t::generic_stop: { switch(desc->get_extra()) { case road_wt: msg = tool_build_station_t::tool_station_aux(player, pos, desc, rotation, road_wt, "H"); break; case track_wt: case monorail_wt: case maglev_wt: case narrowgauge_wt: case tram_wt: msg = tool_build_station_t::tool_station_aux(player, pos, desc, rotation, (waytype_t)desc->get_extra(), "BF"); break; case water_wt: msg = tool_build_station_t::tool_station_aux(player, pos, desc, rotation, water_wt, "Dock"); break; case air_wt: msg = tool_build_station_t::tool_station_aux(player, pos, desc, rotation, air_wt, "Airport"); break; } break; } default: dbg->warning("tool_build_station_t::work()","tool called for illegal desc \"%s\"", default_param ); msg = "Illegal station tool"; } return msg; } const char *tool_rotate_building_t::work( player_t *player, koord3d pos ) { const grund_t *gr = welt->lookup(pos); if(!gr) { return ""; } if( gebaeude_t* gb = gr->find() ) { if( !player_t::check_owner( gb->get_owner(), player ) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // check for harbour (must not rotate) const building_desc_t *desc = gb->get_tile()->get_desc(); if( desc->get_all_layouts() == 1 ) { // non rotatable => finish return NULL; } if( desc->get_type() == building_desc_t::dock ) { // cannot rotate a harbour return "Cannot rotate this building!"; } if( desc->get_all_layouts()==2 && desc->get_x()!=desc->get_y() ) { // cannot rotate an asymmetric building with only two rotations return "Cannot rotate this building!"; } if( gr->hat_wege() ) { // this is almost certainly a station ... if( desc->get_all_layouts()<16 ) { // either symmetrical (==2, ==8) or freight loading station, so do not rotate! return "Cannot rotate this building!"; } int layout = gb->get_tile()->get_layout(); gb->set_tile( gb->get_tile()->get_desc()->get_tile( layout^8, 0, 0 ), false ); } else { // single and multitile buildings from here, include factories with holes etc. bool rotate180 = desc->get_x() != desc->get_y(); if( desc->get_x() != desc->get_y() && desc->get_all_layouts()==2 ) { // asymmetrical with only one rotation so do not rotate! return "Cannot rotate this building!"; } uint8 layout = gb->get_tile()->get_layout(); uint8 newlayout = (layout+1+rotate180) % desc->get_all_layouts(); vector_tpl gb_tiles; gb->get_tile_list( gb_tiles ); // first test if all tiles are present (check for holes) if( gb_tiles.get_count() < (uint32)desc->get_x( layout ) * (uint32)desc->get_y( layout ) ) { // there are holes ... return "Cannot rotate this building!"; } if( fabrik_t* fab = gb->get_fabrik() ) { fab->set_rotate( (fab->get_rotate() + 1) % fab->get_desc()->get_building()->get_all_layouts() ); } // ok, we can rotate it for(grund_t* gr : gb_tiles ) { gebaeude_t* gb_part = gr->find(); koord k = gr->get_pos().get_2d()-gb_tiles.front()->get_pos().get_2d(); const building_tile_desc_t* tile = desc->get_tile( newlayout, k.x, k.y ); gb_part->set_tile( tile, false ); } } } else if (gr->hat_wege()) { // roate switch graphics for (uint i=0; i < 2; i++) { if (weg_t* w =gr->get_weg_nr(i)) { if (w->get_waytype()!=road_wt && ribi_t::is_threeway(w->get_ribi_unmasked())) { bool sw = w->has_switched(); w->set_switched(!sw); w->set_images(weg_t::image_switch, w->get_ribi_unmasked(), w->is_snow(), !sw); gr->mark_image_dirty(); } } } } return NULL; } tool_build_roadsign_t::tool_build_roadsign_t() : two_click_tool_t(TOOL_BUILD_ROADSIGN | GENERAL_TOOL), desc(NULL) { } const char *tool_build_roadsign_t::get_tooltip(const player_t *) const { const roadsign_desc_t *desc = roadsign_t::find_desc(default_param); if(desc) { return tooltip_with_price( desc->get_name(), -desc->get_price() ); } return NULL; } bool tool_build_roadsign_t::init(player_t *player) { desc = roadsign_t::find_desc(default_param); // take default values from players settings current = signal[player->get_player_nr()]; if (is_ctrl_pressed() && can_use_gui()) { create_win(new signal_spacing_frame_t(player, this), w_info, (ptrdiff_t)this); } return two_click_tool_t::init(player) && desc!=NULL; } bool tool_build_roadsign_t::exit(player_t *player) { destroy_win((ptrdiff_t)this); return two_click_tool_t::exit(player); } void tool_build_roadsign_t::set_values(player_t *player, uint8 spacing, bool remove, bool replace) { signal_info_t &s = signal[player->get_player_nr()]; s.spacing = spacing; s.remove_intermediate = remove; s.replace_other = replace; current = s; } void tool_build_roadsign_t::get_values(player_t *player, uint8 &spacing, bool &remove, bool &replace) { const signal_info_t &s = signal[player->get_player_nr()]; spacing = s.spacing; remove = s.remove_intermediate; replace = s.replace_other; } void tool_build_roadsign_t::draw_after(scr_coord k, bool dirty) const { if( icon!=IMG_EMPTY && is_selected() ) { display_img_blend( icon, k.x, k.y, TRANSPARENT50_FLAG|OUTLINE_FLAG|color_idx_to_rgb(COL_BLACK), false, dirty ); char level_str[16]; sprintf(level_str, "%i", signal[welt->get_active_player_nr()].spacing); display_proportional_rgb( k.x+4, k.y+4, level_str, ALIGN_LEFT, color_idx_to_rgb(COL_YELLOW), true ); } } void tool_build_roadsign_t::rdwr_custom_data(memory_rw_t *packet) { two_click_tool_t::rdwr_custom_data(packet); packet->rdwr_byte(current.spacing); packet->rdwr_bool(current.remove_intermediate); packet->rdwr_bool(current.replace_other); } waytype_t tool_build_roadsign_t::get_waytype() const { return desc ? desc->get_wtyp() : invalid_wt; } void tool_build_roadsign_t::mark_tiles(player_t *player, const koord3d &start, const koord3d &end) { route_t route; if (!calc_route(route, player, start, end)) { return; } const bool single_ribi = desc->is_signal_type() || desc->is_single_way() || desc->is_choose_sign(); const signal_info_t &s = current; const uint8 signal_density = 2 * s.spacing; //< measured in half tiles (straight track count as 2, diagonal as 1, since sqrt(1/2) = 1/2 ;) uint8 next_signal = signal_density + 1; //< to place a sign asap sint32 cost = 0; directions.clear(); // dummy roadsign to get images for preview roadsign_t *dummy_rs = desc->is_signal_type() ? new signal_t(player, koord3d::invalid, ribi_t::none, desc, true) : new roadsign_t(player, koord3d::invalid, ribi_t::none, desc, true); dummy_rs->set_flag(obj_t::not_on_map); for( route_t::index_t i = 0; i < route.get_count(); i++ ) { grund_t *gr = welt->lookup( route.at(i) ); weg_t *weg = gr->get_weg(desc->get_wtyp()); ribi_t::ribi ribi = weg->get_ribi_unmasked(); // set full ribi when signal is on a crossing. if( single_ribi ) { if(i>0) { // take backward direction ribi = ribi_type(route.at(i), route.at(i-1)); } else { // clear one direction bit to get single direction for signal ribi &= ~ribi_type(route.at(i), route.at(i+1)); } } roadsign_t *rs = gr->find(); if (rs==NULL) { rs = gr->find(); } if (rs && rs->get_waytype() != desc->get_waytype()) { // do not delete signs from other ways continue; } // check owner .. other signals... const bool straight = (i == 0) || (i == route.get_count()-1) || ribi_t::is_straight(ribi_type(route.at(i-1), route.at(i+1))); next_signal += straight ? 2 : 1; if( next_signal >= signal_density ) { // can we place signal here? if (check_pos_intern(player, route.at(i))==NULL || (s.replace_other && rs && !rs->get_removal_error(player))) { zeiger_t *zeiger = new zeiger_t(gr->get_pos(), player ); marked.append(zeiger); zeiger->set_image( skinverwaltung_t::bauigelsymbol->get_image_id(0) ); gr->obj_add( zeiger ); directions.append(ribi /* !=0 -> place sign*/); next_signal = 0; dummy_rs->set_pos(gr->get_pos()); dummy_rs->set_dir(ribi); // calls calc_image() zeiger->set_foreground_image(dummy_rs->get_front_image()); zeiger->set_image(dummy_rs->get_image()); cost += rs ? (rs->get_desc()==desc ? 0 : desc->get_price()+rs->get_desc()->get_price()) : desc->get_price(); } } else if (s.remove_intermediate && rs && !rs->get_removal_error(player)) { zeiger_t *zeiger = new zeiger_t(gr->get_pos(), player ); marked.append(zeiger); zeiger->set_image( tool_t::general_tool[TOOL_REMOVER]->cursor ); gr->obj_add( zeiger ); directions.append(ribi_t::none /*remove sign*/); cost += rs->get_desc()->get_price(); } } delete dummy_rs; win_set_static_tooltip( tooltip_with_price_length("Building costs estimates", cost, route.get_count() ) ); } const char *tool_build_roadsign_t::do_work(player_t *player, const koord3d &start, const koord3d &end) { // read data from string desc = roadsign_t::find_desc(default_param); // single click -> place signal if (end == koord3d::invalid || start == end) { grund_t *gr = welt->lookup(start); return place_sign_intern( player, gr ); } // mark tiles to calculate positions of signals mark_tiles(player, start, end); // only search the marked tiles uint32 j=0; for (zeiger_t *const i : marked) { grund_t* const gr = welt->lookup(i->get_pos()); weg_t *weg = gr->get_weg(desc->get_wtyp()); ribi_t::ribi dir = directions[j++]; if (dir) { // try to place signal const char *error_text = place_sign_intern( player, gr ); if( error_text ) { if (signal[player->get_player_nr()].replace_other) { roadsign_t* rs = gr->find(); if(rs == NULL) rs = gr->find(); if( rs != NULL && rs->get_removal_error(player) == NULL ) { rs->cleanup(player); delete rs; error_text = place_sign_intern( player, gr ); } } } if( error_text ) { return error_text; } roadsign_t* rs = gr->find(); if(rs == NULL) rs = gr->find(); assert(rs); rs->set_dir(dir); } else { // Place no signal -> remove existing signal roadsign_t* rs = gr->find(); if(rs == NULL) rs = gr->find(); if( rs != NULL && rs->get_removal_error(player) == NULL ) { rs->cleanup(player); delete rs; }; } weg->count_sign(); gr->calc_image(); } cleanup(); directions.clear(); return NULL; } uint8 tool_build_roadsign_t::is_valid_pos(player_t *player, const koord3d &pos, const char *&error, const koord3d &start) { // first click if (start==koord3d::invalid) { error = check_pos_intern(player, pos); return (error==NULL ? 3 : 0); } // second click else { error = NULL; return 2; } } const char *tool_build_roadsign_t::check_pos_intern(player_t *player, koord3d pos) { static const char *error = "Hier kann kein\nSignal aufge-\nstellt werden!\n"; if (desc==NULL) { // read data from string desc = roadsign_t::find_desc(default_param); } if (desc==NULL) { return error; } // search for starting ground const grund_t *gr = tool_intern_koord_to_weg_grund(player, welt, pos, desc->get_wtyp()); if(!gr) { return error; } // do not replace roadsigns by signals and vice versa (e.g. on level crossings) if ((desc->is_signal_type() && gr->find()) || (!desc->is_signal_type() && gr->find())) { return error; } // get the sign direction const weg_t *weg = gr->get_weg( desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt); const ribi_t::ribi way_ribi = weg->get_ribi_unmasked(); // no signs on runways if( weg->get_waytype() == air_wt && weg->get_desc()->get_styp() == type_runway ) { return error; } // no signals on switches if( ribi_t::is_threeway(way_ribi) && desc->is_signal_type() ) { return error; } if( desc->is_private_way() && !ribi_t::is_straight(way_ribi) ) { // only on straight tiles return error; } const bool needs_two_ways = desc->is_single_way() || desc->is_signal_type(); const bool valid_signal_pos = (!needs_two_ways && !desc->is_traffic_light()) || ( needs_two_ways && ribi_t::is_twoway(way_ribi)) || (desc->is_traffic_light() && ribi_t::is_threeway(way_ribi)); if(!valid_signal_pos) { return error; } const roadsign_t *rs = desc->is_signal_type() ? gr->find() : gr->find(); if (rs && !player_t::check_owner(rs->get_owner(), player)) { return "Das Feld gehoert\neinem anderen Spieler\n"; } return NULL; } const char *tool_build_roadsign_t::place_sign_intern(player_t *player, grund_t *gr) { static const char *error = "Hier kann kein\nSignal aufge-\nstellt werden!\n"; // search for starting ground if(!gr) { return error; } // get the sign direction weg_t *weg = gr->get_weg( desc->get_wtyp()!=tram_wt ? desc->get_wtyp() : track_wt); roadsign_t *s = gr->find(); if(s==NULL) { s = gr->find(); } if(s && (!s->get_desc()->is_signal_type() && s->get_desc() != desc)) { // can only replace signals return error; } ribi_t::ribi dir = weg->get_ribi_unmasked(); const bool two_way = desc->is_single_way() || desc->is_signal_type(); const bool valid_sign_location = !(desc->is_traffic_light() || two_way) || (two_way && ribi_t::is_twoway(dir)) || (desc->is_traffic_light() && ribi_t::is_threeway(dir)); if(!valid_sign_location) { return error; } roadsign_t *rs = NULL; if (desc->is_signal_type()) { // if there is already a signal, we might need to inverse the direction rs = gr->find(); if (!rs) { // add a new signal at position zero! rs = new signal_t(player, gr->get_pos(), dir, desc); DBG_MESSAGE("tool_roadsign()", "new signal, dir is %i", dir); goto built_sign; } if( !player_t::check_owner( rs->get_owner(), player ) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } if (rs->get_desc() == desc) { // signals have three options ribi_t::ribi sig_dir = rs->get_dir(); uint8 i = 0; if (!ribi_t::is_twoway(sig_dir)) { // inverse first dir for (; i < 4; i++) { if ((dir & ribi_t::nesw[i]) == sig_dir) { i++; break; } } } // find the second dir ... for (; i < 4; i++) { if ((dir & ribi_t::nesw[i]) != 0) { dir = ribi_t::nesw[i]; } } // if nothing found, we have two ways again ... rs->set_dir(dir); } // different desc -> replace signal else if (rs->get_removal_error(player) == NULL) { ribi_t::ribi old_dir = rs->get_dir(); rs->cleanup(player); delete rs; rs = new signal_t(player, gr->get_pos(), dir, desc); rs->set_dir(old_dir); goto built_sign; } } else { // if there is already a sign, we might need to invert the direction rs = gr->find(); if (rs) { if( !player_t::check_owner( rs->get_owner(), player ) ) { return "Das Feld gehoert\neinem anderen Spieler\n"; } // reverse only if single way sign if (desc->is_single_way() || desc->is_choose_sign()) { dir = ~rs->get_dir() & weg->get_ribi_unmasked(); rs->set_dir(dir); DBG_MESSAGE("tool_roadsign()", "reverse ribi %i", dir); } } else { // add a new roadsign at position zero! // if single way, we need to reduce the allowed ribi to one if (desc->is_single_way() || desc->is_choose_sign()) { for( int i=0; i<4; i++ ) { if ((dir & ribi_t::nesw[i]) != 0) { dir = ribi_t::nesw[i]; break; } } } DBG_MESSAGE("tool_roadsign()", "new roadsign, dir is %i", dir); rs = new roadsign_t(player, gr->get_pos(), dir, desc); built_sign: gr->obj_add(rs); rs->finish_rd(); // to make them visible weg->count_sign(); player_t::book_construction_costs(player, -desc->get_price(), gr->get_pos().get_2d(), weg->get_waytype()); } } return NULL; } bool tool_build_roadsign_t::calc_route(route_t &route, player_t *player, const koord3d &from, const koord3d &to) { // get a default vehicle vehicle_desc_t rs_desc( desc->get_wtyp(), 500, vehicle_desc_t::diesel); vehicle_t *test_vehicle = vehicle_builder_t::build(from, player, NULL, &rs_desc); test_vehicle->set_flag(obj_t::not_on_map); test_driver_t *test_driver = scenario_checker_t::apply(test_vehicle, player, this); bool can_build = false; if( from != to ) { can_build = route.calc_route(welt, from, to, test_driver, 0, 0); // prevent building of many signals if start and to are adjacent // but the step start->to is now allowed if (can_build && koord_distance(from, to)==1 && route.get_count()>2) { grund_t *gr, *grto = welt->lookup(to); if( welt->lookup(from)->get_neighbour(gr, desc->get_wtyp(), ribi_type(to-from) ) && gr==grto) { can_build = false; } } } else { route.clear(); route.append(from); can_build = true; } delete test_driver; return can_build; } // build all types of depots const char* tool_build_depot_t::tool_depot_aux(player_t* player, koord3d pos, const building_desc_t* desc, waytype_t wegtype) { if (!welt->is_within_limits(pos.get_2d())) { return ""; } grund_t* bd = NULL; // special for the Seven Seas ... if (wegtype == water_wt) { bd = welt->lookup_kartenboden(pos.get_2d()); if (!bd->is_water()) { if (!bd->hat_weg(water_wt)) { return "Ship depots must be built on water!"; } bd = NULL; } } if (!bd) { bd = tool_intern_koord_to_weg_grund(player, welt, pos, wegtype); } if (!bd) { return "Depots must be built on flat dead-end way tiles!"; } else if (bd->has_two_ways() || bd->is_halt() || bd->get_depot() != NULL) { // avoid building over a stop or on a second way return "Tile not empty."; } // no depots on runways! if (desc->get_extra() == air_wt && bd->get_weg(air_wt)->get_desc()->get_styp() != type_flat) { return "Depots cannot be built on runways!"; } if (const char* errmsg = bd->kann_alle_obj_entfernen(player)) { return errmsg; } ribi_t::ribi ribi; if (bd->is_water()) { // assume one orientation with water ribi = ribi_t::south; } else { ribi = bd->get_weg_ribi_unmasked(wegtype); } int layout = 0; if (bd->get_weg_hang() != slope_t::flat) { return "Depots must be built on flat dead-end way tiles!"; } if (desc->get_all_layouts() == 4) { // classical four rotation depot if (!ribi_t::is_single(ribi)) { return "Depots must be built on flat dead-end way tiles!"; } switch (ribi) { //case ribi_t::south:layout = 0; break; case ribi_t::east: layout = 1; break; case ribi_t::north: layout = 2; break; case ribi_t::west: layout = 3; break; } } else if (desc->get_all_layouts() == 2) { // two rotation through depot if (!ribi_t::is_straight(ribi)) { return "Depots must be built on flat dead-end way tiles!"; } layout = ribi_t::is_straight_ew(ribi); } else { dbg->warning("tool_build_depot_t::tool_depot_aux()", "Broken depot name \"%s\"", desc->get_name()); } hausbauer_t::build_station_extension_depot(player, bd->get_pos(), layout, desc ); player_t::book_construction_costs(player, -desc->get_price(welt), pos.get_2d(), desc->get_finance_waytype()); if(can_use_gui() && player == welt->get_active_player()) { welt->set_tool( general_tool[TOOL_QUERY], player ); } return NULL; } image_id tool_build_depot_t::get_icon(player_t *player) const { if( player && !player->is_public_service() ) { const building_desc_t *desc = hausbauer_t::find_tile(default_param,0)->get_desc(); const uint16 time = welt->get_timeline_year_month(); if( desc && desc->is_available(time) ) { return desc->get_cursor()->get_image_id(1); } } return IMG_EMPTY; } bool tool_build_depot_t::init( player_t *player ) { if (default_param == NULL) { return false; } const building_tile_desc_t *tile_desc = hausbauer_t::find_tile(default_param, 0); building_desc_t const* desc = tile_desc ? tile_desc->get_desc() : NULL; if (desc == NULL || desc->get_cursor()==NULL) { return false; } // no depots for player 1 if(!player->is_public_service()) { cursor = desc->get_cursor()->get_image_id(0); return true; } return false; } const char* tool_build_depot_t::get_tooltip(const player_t *) const { settings_t const& settings = welt->get_settings(); building_desc_t const* desc = hausbauer_t::find_tile(default_param, 0)->get_desc(); if (desc == NULL) { return NULL; } char const* tip; switch (desc->get_extra()) { case road_wt: tip = "Build road depot"; break; case track_wt: tip = "Build train depot"; break; case monorail_wt: tip = "Build monorail depot"; break; case maglev_wt: tip = "Build maglev depot"; break; case narrowgauge_wt: tip = "Build narrowgauge depot"; break; case tram_wt: tip = "Build tram depot"; break; case water_wt: tip = "Build ship depot"; break; case air_wt: tip = "Build air depot"; break; default: return 0; } return tooltip_with_price_maintenance(welt, tip, -desc->get_price(welt), settings.maint_building * desc->get_level()); } waytype_t tool_build_depot_t::get_waytype() const { const building_desc_t *desc = hausbauer_t::find_tile(default_param,0)->get_desc(); return desc ? (waytype_t)desc->get_extra() : invalid_wt; } const char *tool_build_depot_t::work( player_t *player, koord3d pos ) { if(player==welt->get_public_player()) { // no depots for player 1 return 0; } building_desc_t const* const desc = hausbauer_t::find_tile(default_param,0)->get_desc(); switch(desc->get_extra()) { case road_wt: case track_wt: case water_wt: case air_wt: case maglev_wt: case narrowgauge_wt: return tool_build_depot_t::tool_depot_aux(player, pos, desc, (waytype_t)desc->get_extra()); case monorail_wt: { // since it needs also a foundation, this is slightly more complex ... char const* const err = tool_build_depot_t::tool_depot_aux(player, pos, desc, monorail_wt); if(err==NULL) { grund_t *bd = welt->lookup_kartenboden(pos.get_2d()); if(hausbauer_t::elevated_foundation_desc && pos.z-bd->get_pos().z==1 && bd->ist_natur()) { hausbauer_t::build(player, pos.get_2d(), 0, hausbauer_t::elevated_foundation_desc ); } } return err; } case tram_wt: return tool_build_depot_t::tool_depot_aux(player, pos, desc, track_wt); default: dbg->warning("tool_build_depot()","called with unknown desc %s",desc->get_name() ); return "Unknown depot object"; } return NULL; } /** * builds (random) tourist attraction and maybe adds it to the next city * the parameter string is a follow: * 1#theater * first letter: ignore climates * second letter: rotation (0,1,2,3,#=random) * finally building name */ bool tool_build_house_t::init( player_t * ) { if (default_param && strlen(default_param) < 3) { return false; } if (can_use_gui() && !strempty(default_param)) { const char *c = default_param+2; const building_tile_desc_t *tile = hausbauer_t::find_tile(c,0); if(tile!=NULL) { const int rotation = (default_param[1]-'0') % tile->get_desc()->get_all_layouts(); cursor_area = tile->get_desc()->get_size(rotation); } } return true; } const char *tool_build_house_t::work( player_t *player, koord3d pos ) { koord k(pos.get_2d()); const grund_t* gr = welt->lookup_kartenboden(k); if(gr==NULL) { return ""; } // Parsing parameter (if there) const building_desc_t *desc = NULL; if (!strempty(default_param)) { const char *c = default_param+2; const building_tile_desc_t *tile = hausbauer_t::find_tile(c,0); if(tile) { desc = tile->get_desc(); } } else { desc = hausbauer_t::get_random_attraction( welt->get_timeline_year_month(), false, welt->get_climate( k ) ); } if(desc==NULL) { return ""; } int rotation; if( !default_param || default_param[1]=='#' ) { rotation = simrand(desc->get_all_layouts()); } else if( default_param[1]=='A' ) { if( desc->get_type()!=building_desc_t::attraction_land && desc->get_type()!=building_desc_t::attraction_city ) { // auto rotation only valid for city buildings rotation = stadt_t::orient_city_building( k, desc, desc->get_size() ); if( rotation < 0 ) { return NOTICE_UNSUITABLE_GROUND; } } else { rotation = simrand(desc->get_all_layouts()); } } else { rotation = (default_param[1]-'0') % desc->get_all_layouts(); } koord size = desc->get_size(rotation); // process ignore climates switch climate_bits cl = (default_param && default_param[0]=='1') ? ALL_CLIMATES : desc->get_allowed_climate_bits(); bool hat_platz = welt->square_is_free( k, desc->get_x(rotation), desc->get_y(rotation), NULL, cl ); if(!hat_platz && size.y!=size.x && desc->get_all_layouts()>1 && (default_param==NULL || default_param[1]=='#' || default_param[1]=='A')) { // try other rotation too ... rotation = (rotation+1) % desc->get_all_layouts(); hat_platz = welt->square_is_free( k, desc->get_x(rotation), desc->get_y(rotation), NULL, cl ); } // Place found... if(hat_platz) { player_t *gb_player = desc->is_city_building() ? NULL : welt->get_public_player(); gebaeude_t *gb = hausbauer_t::build(gb_player, k, rotation, desc); if(gb) { // building successful if( desc->get_type()!=building_desc_t::attraction_land && desc->get_type()!=building_desc_t::attraction_city ) { stadt_t *city = welt->find_nearest_city( k ); if(city) { city->add_gebaeude_to_stadt(gb); } } player_t::book_construction_costs(player, -desc->get_price(welt) * size.x * size.y, k, gb->get_waytype()); return NULL; } } return NOTICE_UNSUITABLE_GROUND; } // show industry size in cursor (in known) bool tool_build_land_chain_t::init( player_t * ) { if (can_use_gui() && !strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } const factory_desc_t *fab = factory_builder_t::get_desc(c); if(fab==NULL) { // wrong tool! return false; } int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts(); cursor_area = fab->get_building()->get_size(rotation); } return true; } /* builds a (if param=NULL random) industry chain starting here * * the parameter string is a follow: * 1#34,oelfeld * first letter: ignore climates * second letter: rotation (0,1,2,3,#=random) * next number is production value * finally industry name */ const char *tool_build_land_chain_t::work( player_t *player, koord3d pos ) { const grund_t* gr = welt->lookup_kartenboden(pos.get_2d()); if(gr==NULL) { return ""; } const factory_desc_t *fab = NULL; if (!strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } fab = factory_builder_t::get_desc(c); } else { fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() ); } if(fab==NULL) { return ""; } int rotation = (default_param && default_param[1]!='#') ? (default_param[1]-'0') % fab->get_building()->get_all_layouts() : simrand(fab->get_building()->get_all_layouts()-1); koord size = fab->get_building()->get_size(rotation); // process ignore climates switch bool ignore_climates = default_param && default_param[0]=='1'; climate_bits cl = ignore_climates ? ALL_CLIMATES : fab->get_building()->get_allowed_climate_bits(); bool hat_platz = false; if(fab->get_placement()==factory_desc_t::Water) { // at sea hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) ); if(!hat_platz && size.y!=size.x && fab->get_building()->get_all_layouts()>1 && (default_param==NULL || default_param[1]=='#')) { // try other rotation too ... rotation = (rotation+1) % fab->get_building()->get_all_layouts(); hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) ); } } else { // and on solid ground hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl ); if(!hat_platz && size.y!=size.x && fab->get_building()->get_all_layouts()>1 && (default_param==NULL || default_param[1]=='#')) { // try other rotation too ... rotation = (rotation+1) % fab->get_building()->get_all_layouts(); hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl ); } } if(hat_platz) { // eventually adjust production sint32 initial_prod = -1; if (!strempty(default_param)) { initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) ); } koord3d build_pos = gr->get_pos(); int count = factory_builder_t::build_link(NULL, fab, initial_prod, rotation, &build_pos, welt->get_public_player(), 10000, ignore_climates); if(count>0) { // at least one factory has been built welt->get_viewport()->change_world_position( build_pos ); player_t::book_construction_costs(player, count * welt->get_settings().cst_multiply_found_industry, build_pos.get_2d(), ignore_wt); // crossconnect all? if (welt->get_settings().is_crossconnect_factories()) { for(fabrik_t* const f : welt->get_fab_list()) { f->add_all_suppliers(); } } return NULL; } } return NOTICE_UNSUITABLE_GROUND; } // show industry size in cursor (in known) bool tool_city_chain_t::init( player_t * ) { if (can_use_gui() && !strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } const factory_desc_t *fab = factory_builder_t::get_desc(c); if(fab==NULL) { // wrong tool! return false; } int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts(); cursor_area = fab->get_building()->get_size(rotation); } return true; } /* builds a industry chain in the next town * default_param see previous function */ const char *tool_city_chain_t::work( player_t *player, koord3d pos ) { const grund_t* gr = welt->lookup_kartenboden(pos.get_2d()); if(gr==NULL) { return ""; } const factory_desc_t *fab = NULL; if (!strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } fab = factory_builder_t::get_desc(c); } else { fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() ); } if(fab==NULL) { return ""; } // eventually adjust production sint32 initial_prod = -1; if (!strempty(default_param)) { initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) ); } // process ignore climates switch bool ignore_climates = default_param && default_param[0]=='1'; pos = gr->get_pos(); int count = factory_builder_t::build_link(NULL, fab, initial_prod, 0, &pos, welt->get_public_player(), 10000, ignore_climates); if(count>0) { // at least one factory has been built welt->get_viewport()->change_world_position( pos ); // crossconnect all? if (welt->get_settings().is_crossconnect_factories()) { for(fabrik_t* const f : welt->get_fab_list()) { f->add_all_suppliers(); } } // ain't going to be cheap player_t::book_construction_costs(player, count * welt->get_settings().cst_multiply_found_industry, pos.get_2d(), ignore_wt); return NULL; } return NOTICE_UNSUITABLE_GROUND; } // show industry size in cursor (must be known!) bool tool_build_factory_t::init( player_t * ) { if (can_use_gui() && !strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } const factory_desc_t *fab = factory_builder_t::get_desc(c); if(fab==NULL) { // wrong tool! return false; } int rotation = (default_param[1]-'0') % fab->get_building()->get_all_layouts(); cursor_area = fab->get_building()->get_size(rotation); return true; } return true; } /* builds an industry next to the cursor (default_param see above) */ const char *tool_build_factory_t::work( player_t *player, koord3d pos ) { const grund_t* gr = welt->lookup_kartenboden(pos.get_2d()); if(gr==NULL) { return ""; } const factory_desc_t *fab = NULL; if (!strempty(default_param)) { const char *c = default_param+2; while(*c && *c++!=',') { /* do nothing */ } fab = factory_builder_t::get_desc(c); } else { fab = factory_builder_t::get_random_consumer( false, (climate_bits)(1 << welt->get_climate( pos.get_2d() )), welt->get_timeline_year_month() ); } if(fab==NULL) { return ""; } int rotation = (default_param && default_param[1]!='#') ? (default_param[1]-'0') % fab->get_building()->get_all_layouts() : simrand(fab->get_building()->get_all_layouts()); koord size = fab->get_building()->get_size(rotation); // process ignore climates switch climate_bits cl = (default_param && default_param[0]=='1') ? ALL_CLIMATES : fab->get_building()->get_allowed_climate_bits(); bool hat_platz = false; if(fab->get_placement()==factory_desc_t::Water) { // at sea hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) ); if(!hat_platz && size.y!=size.x && fab->get_building()->get_all_layouts()>1 && (default_param==NULL || default_param[1]=='#')) { // try other rotation too ... rotation = (rotation+1) % fab->get_building()->get_all_layouts(); hat_platz = welt->is_water( pos.get_2d(), fab->get_building()->get_size(rotation) ); } } else { // and on solid ground hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl ); if(!hat_platz && size.y!=size.x && fab->get_building()->get_all_layouts()>1 && (default_param==NULL || default_param[1]=='#')) { // try other rotation too ... rotation = (rotation+1) % fab->get_building()->get_all_layouts(); hat_platz = welt->square_is_free( pos.get_2d(), fab->get_building()->get_x(rotation), fab->get_building()->get_y(rotation), NULL, cl ); } } if(hat_platz) { // eventually adjust production sint32 initial_prod = -1; if (!strempty(default_param)) { initial_prod = welt->inverse_scale_with_month_length( atol(default_param+2) ); } fabrik_t *f = factory_builder_t::build_factory(NULL, fab, initial_prod, rotation, gr->get_pos(), welt->get_public_player()); if(f) { // at least one factory has been built // === removed on player request === welt->get_viewport()->change_world_position( pos ); player_t::book_construction_costs(player, welt->get_settings().cst_multiply_found_industry, pos.get_2d(), ignore_wt); // crossconnect all? if (welt->get_settings().is_crossconnect_factories()) { for(fabrik_t* const f : welt->get_fab_list()) { f->add_all_suppliers(); } } return NULL; } } return NOTICE_UNSUITABLE_GROUND; } /** * link tool: links products of factory one with factory two (if possible) */ image_id tool_link_factory_t::get_marker_image() const { return cursor; } uint8 tool_link_factory_t::is_valid_pos( player_t *, const koord3d &pos, const char *&error, const koord3d & ) { fabrik_t *fab = fabrik_t::get_fab( pos.get_2d() ); if (fab == NULL) { error = ""; return 0; } return 2; } const char *tool_link_factory_t::do_work( player_t *, const koord3d &start, const koord3d &pos ) { fabrik_t *last_fab = fabrik_t::get_fab( start.get_2d() ); fabrik_t *fab = fabrik_t::get_fab( pos.get_2d() ); if(fab!=NULL && last_fab!=NULL && last_fab!=fab) { // It's a factory if(!is_ctrl_pressed()) { if(fab->add_supplier(last_fab) || last_fab->add_supplier(fab)) { //ok! they are connected return NULL; } } else { // remove connections fab->remove_supplier(last_fab->get_pos().get_2d()); fab->remove_consumer(last_fab->get_pos().get_2d()); last_fab->remove_supplier(fab->get_pos().get_2d()); last_fab->remove_consumer(fab->get_pos().get_2d()); return NULL; } } return ""; } const building_desc_t *tool_headquarter_t::next_level( const player_t *player ) const { return hausbauer_t::get_headquarters(player->get_headquarter_level(), welt->get_timeline_year_month()); } const char* tool_headquarter_t::get_tooltip(const player_t *player) const { static char my_toolstr[1024]; if (building_desc_t const* const desc = next_level(player)) { char old_toolstr[1024]; /* since there is one static toolstr for all tools uing tooltip_with_... * but we are also called every frame from finance window, we need to restore old content * or all tooltips generated before will only show our message */ tstrncpy(old_toolstr, tool_t::toolstr, 1024); settings_t const& s = welt->get_settings(); char const* const tip = player->get_headquarter_level() == 0 ? "build HQ" : "upgrade HQ"; sint64 const factor = desc->get_x() * desc->get_y(); strcpy( my_toolstr, tooltip_with_price_maintenance(welt, tip, -factor * desc->get_price(welt), factor * desc->get_level() * s.maint_building) ); tstrncpy(tool_t::toolstr, old_toolstr, 1024); return my_toolstr; } return NULL; } bool tool_headquarter_t::init( player_t *player ) { // do no use this, if there is no next level to build ... const building_desc_t *desc = next_level(player); if (desc) { if (can_use_gui()) { const int rotation = 0; cursor_area = desc->get_size(rotation); } return true; } return false; } const char *tool_headquarter_t::work( player_t *player, koord3d pos ) { bool ok=false; bool built = false; DBG_MESSAGE("tool_headquarter()", "building headquarters at (%d,%d)", pos.x, pos.y); const building_desc_t* desc = next_level(player); if(desc==NULL) { // no further headquarters level dbg->message( "tool_headquarter()", "Already at maximum level!" ); return ""; } // check funds koord size = desc->get_size(); sint64 const cost = -desc->get_price(welt) * size.x * size.y; if( !player->can_afford(cost) ) { return NOTICE_INSUFFICIENT_FUNDS; } koord k(pos.get_2d()); grund_t *gr = welt->lookup_kartenboden(k); if(gr) { gebaeude_t *hq = NULL; // check for current head quarter koord previous = player->get_headquarter_pos(); if(previous!=koord::invalid) { grund_t *gr_hq = welt->lookup_kartenboden(previous); gebaeude_t *prev_hq = gr_hq->find(); // check if upgrade should be built at same place as current one gebaeude_t *gb = gr->find(); if (gb && gb->get_owner()==player && prev_hq->get_tile()->get_desc()==gb->get_tile()->get_desc()) { const building_desc_t* prev_desc = prev_hq->get_tile()->get_desc(); // check if sizes fit uint8 prev_layout = prev_hq->get_tile()->get_layout(); uint8 layout = prev_layout % desc->get_all_layouts(); koord size = desc->get_size(layout); if (prev_desc->get_size(prev_layout) == size) { // check for same tile structure ok = true; for (sint16 x=0; xget_tile(prev_layout, x, y)==NULL)==(desc->get_tile(layout, x, y)==NULL); } } hq = gb; if( ok ) { // upgrade the tiles koord k_hq = k - gb->get_tile()->get_offset(); for( sint16 x = 0; x < size.x; x++ ) { for( sint16 y = 0; y < size.y; y++ ) { if( const building_tile_desc_t *tile = desc->get_tile(layout, x, y) ) { if( grund_t *gr2 = welt->lookup_kartenboden(k_hq + koord(x, y)) ) { if( gebaeude_t *gb = gr2->find() ) { if( gb && gb->get_owner() == player && prev_desc == gb->get_tile()->get_desc() ) { player_t::add_maintenance( player, -prev_desc->get_maintenance(welt), prev_desc->get_finance_waytype() ); gb->set_tile( tile, true ); gb->calc_image(); player_t::add_maintenance( player, desc->get_maintenance(welt), desc->get_finance_waytype() ); } } } } } } built = true; } } } // did not upgrade old one, need to remove it if( !built ) { // remove previous one hausbauer_t::remove( player, prev_hq ); // resize cursor init(player); } } // build new one if (!built) { int rotate = 0; if(welt->square_is_free(k, size.x, size.y, NULL, desc->get_allowed_climate_bits())) { ok = true; } if(!ok && desc->get_all_layouts()>1 && size.y != size.x && welt->square_is_free(k, size.y, size.x, NULL, desc->get_allowed_climate_bits())) { rotate = 1; ok = true; } if(ok) { // then built it hq = hausbauer_t::build(player, k, rotate, desc, NULL); stadt_t *city = welt->find_nearest_city( k ); if(city) { city->add_gebaeude_to_stadt( hq ); } built = true; } else { return NOTICE_UNSUITABLE_GROUND; } } if( built ) { // sometimes those are not correct after rotation ... player->add_headquarter( desc->get_extra() + 1, hq->get_pos().get_2d() - hq->get_tile()->get_offset() ); player_t::book_construction_costs(player, cost, k, ignore_wt); // tell the world of it ... cbuffer_t buf; buf.printf( translator::translate("%s s\nheadquarter now\nat (%i,%i)."), player->get_name(), pos.x, pos.y ); welt->get_message()->add_message( buf, hq->get_pos(), message_t::ai, PLAYER_FLAG|player->get_player_nr(), hq->get_tile()->get_background(0,0,0) ); // reset to query tool, since costly relocations should be avoided if(can_use_gui() && player == welt->get_active_player()) { welt->set_tool( tool_t::general_tool[TOOL_QUERY], player ); } return NULL; } } return ""; } const char *tool_lock_game_t::work( player_t *, koord3d ) { // tool can never be executed in network mode if (env_t::networkmode) { return ""; } // as the result depends on the local locked state of public player if (welt->get_public_player()->is_locked() || !welt->get_settings().get_allow_player_change()) { return "Only public player can lock games!"; } welt->clear_player_password_hashes(); if( !welt->get_public_player()->is_locked() ) { return "In order to lock the game, you have to protect the public player by password!"; } destroy_all_win( true ); welt->switch_active_player( 0, true ); welt->get_settings().set_allow_player_change(false); welt->set_tool( general_tool[TOOL_QUERY], welt->get_player(0) ); return NULL; } const char *tool_add_citycar_t::work( player_t *player, koord3d pos ) { if( private_car_t::list_empty() ) { // No citycar return ""; } grund_t *gr = tool_intern_koord_to_weg_grund( player, welt, pos, road_wt ); if( gr != NULL && ribi_t::is_twoway(gr->get_weg_ribi_unmasked(road_wt)) && gr->find() == NULL) { // add citycar private_car_t* vt = new private_car_t(gr, koord::invalid, default_param); gr->obj_add(vt); return NULL; } return ""; } uint8 tool_forest_t::is_valid_pos( player_t *, const koord3d &, const char *&, const koord3d & ) { // do really nothing ... return 2; } void tool_forest_t::mark_tiles( player_t *, const koord3d &start, const koord3d &end ) { koord k1, k2; k1.x = start.x < end.x ? start.x : end.x; k1.y = start.y < end.y ? start.y : end.y; k2.x = start.x + end.x - k1.x; k2.y = start.y + end.y - k1.y; koord k; for( k.x = k1.x; k.x <= k2.x; k.x++ ) { for( k.y = k1.y; k.y <= k2.y; k.y++ ) { grund_t *gr = welt->lookup_kartenboden( k ); zeiger_t *marker = new zeiger_t(gr->get_pos(), NULL ); const uint8 grund_hang = gr->get_grund_hang(); const uint8 weg_hang = gr->get_weg_hang(); const uint8 hang = max( corner_sw(grund_hang), corner_sw(weg_hang)) + 3 * max( corner_se(grund_hang), corner_se(weg_hang)) + 9 * max( corner_ne(grund_hang), corner_ne(weg_hang)) + 27 * max( corner_nw(grund_hang), corner_nw(weg_hang)); uint8 back_hang = (hang % 3) + 3 * ((uint8)(hang / 9)) + 27; marker->set_foreground_image( ground_desc_t::marker->get_image( grund_hang % 27 ) ); marker->set_image( ground_desc_t::marker->get_image( back_hang ) ); marker->mark_image_dirty( marker->get_image(), 0 ); gr->obj_add( marker ); marked.insert( marker ); } } } const char *tool_forest_t::do_work( player_t *player, const koord3d &start, const koord3d &end ) { koord wh, nw; wh.x = abs(end.x-start.x)+1; wh.y = abs(end.y-start.y)+1; nw.x = min(start.x, end.x)+(wh.x/2); nw.y = min(start.y, end.y)+(wh.y/2); sint64 costs = tree_builder_t::create_forest( nw, wh, 0, 0, welt->get_size().x, welt->get_size().y ); player_t::book_construction_costs(player, costs * welt->get_settings().cst_remove_tree, end.get_2d(), ignore_wt); return NULL; } image_id tool_stop_mover_t::get_marker_image() const { return cursor; } void tool_stop_mover_t::read_start_position(player_t *player, const koord3d &pos) { waytype[0] = invalid_wt; waytype[1] = invalid_wt; last_halt = halthandle_t(); grund_t *bd = welt->lookup(pos); if (bd==NULL) { return; } // now assign waytypes if(bd->is_water()) { waytype[0] = water_wt; } else { waytype[0] = bd->get_weg_nr(0)->get_waytype(); if(bd->get_weg_nr(1)) { waytype[1] = bd->get_weg_nr(1)->get_waytype(); } } // .. and halt last_halt = haltestelle_t::get_halt(pos,player); } uint8 tool_stop_mover_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &start) { grund_t *bd = welt->lookup(pos); if (bd==NULL) { error = ""; return 0; } // check halt ownership halthandle_t h = haltestelle_t::get_halt(pos,player); if( h.is_bound() && !player_t::check_owner( player, h->get_owner() ) ) { error = "Das Feld gehoert\neinem anderen Spieler\n"; return 0; } // check for halt on the tile if( h.is_bound() && !(bd->is_halt() || (h->get_station_type()&haltestelle_t::dock && bd->is_water()) ) ) { error = NOTICE_UNSUITABLE_GROUND; return 0; } if (start==koord3d::invalid) { // check for existing ways if (bd->is_water() || bd->hat_wege()) { return 2; } else { error = NOTICE_UNSUITABLE_GROUND; return 0; } } else { // read conditions at start point read_start_position(player, start); // check halts vs waypoints if(h.is_bound() ^ last_halt.is_bound()) { error = "Can only move from halt to halt or waypoint to waypoint."; return 0; } // check waytypes if( (waytype[0] == water_wt && bd->is_water()) || bd->hat_weg(waytype[0]) || bd->hat_weg(waytype[1]) ) { // ok return 2; } else { error = NOTICE_UNSUITABLE_GROUND; return 0; } } } const char *tool_stop_mover_t::do_work( player_t *player, const koord3d &last_pos, const koord3d &pos) { // read conditions at start point read_start_position(player, last_pos); // second click grund_t *bd = welt->lookup(pos); halthandle_t h = haltestelle_t::get_halt(pos,player); if (bd) { const halthandle_t new_halt = h; // depending on the waytype we simply build replacements lists // in the worst case we have to iterate over all tiles twice ... for( uint i=0; i<2; i++ ) { const waytype_t wt = waytype[i]; slist_tpl old_platform; if(bd->is_water()) { if(wt!=water_wt) { break; } } else if(!bd->hat_weg(wt)) { continue; } // platform, stop or just tile moving? const bool catch_all_halt = (wt==water_wt || wt==air_wt) && last_halt.is_bound(); if(!last_halt.is_bound()) { old_platform.append(last_pos); } else if(!catch_all_halt) { // builds a coordinate list if(wt==road_wt) { old_platform.append(last_pos); } else { // all connected tiles for start pos uint8 ribi = welt->lookup(last_pos)->get_weg_ribi_unmasked(wt); koord delta = ribi_t::is_straight_ns(ribi) ? koord(0,1) : koord(1,0); koord3d start_pos=last_pos; while(ribi&12) { koord3d test_pos = start_pos+delta; grund_t *gr = welt->lookup(test_pos); if(!gr || !gr->is_halt() || (ribi=gr->get_weg_ribi_unmasked(wt))==0) { break; } start_pos = test_pos; } // now add all of them while(ribi&3) { koord3d test_pos = start_pos-delta; grund_t *gr = welt->lookup(test_pos); old_platform.append(start_pos); if(!gr || !gr->is_halt() || (ribi=gr->get_weg_ribi_unmasked(wt))==0) { break; } start_pos = test_pos; } } } // first, check convoi without line for(convoihandle_t const cnv : welt->convoys()) { // check line and owner if(!cnv->get_line().is_bound() && cnv->get_owner()==player) { schedule_t *schedule = cnv->get_schedule(); // check waytype if(schedule && schedule->is_stop_allowed(bd)) { bool updated = false; for(schedule_entry_t & k : schedule->entries) { if ((catch_all_halt && haltestelle_t::get_halt( k.pos, cnv->get_owner()) == last_halt) || old_platform.is_contained(k.pos)) { k.pos = pos; updated = true; } } if(updated) { schedule->make_valid(); // remove lineless convoy from old stop if( last_halt.is_bound() ) { last_halt->remove_convoy(cnv); } // register lineless convoy at new stop if( new_halt.is_bound() ) { new_halt->add_convoy(cnv); } if( !schedule->is_editing_finished() ) { // schedule is not owned by schedule window ... // ... thus we can set this schedule cnv->set_schedule(schedule); // otherwise the schedule window will reset it } } } } } // next, check lines serving old_halt (no owner check needed for own lines ... vector_tpllines; player->simlinemgmt.get_lines(simline_t::line,&lines); for(linehandle_t const line : lines) { schedule_t *schedule = line->get_schedule(); // check waytype if(schedule->is_stop_allowed(bd)) { bool updated = false; for(schedule_entry_t & k : schedule->entries) { // ok! if ((catch_all_halt && haltestelle_t::get_halt( k.pos, line->get_owner()) == last_halt) || old_platform.is_contained(k.pos)) { k.pos = pos; updated = true; } } // update line if(updated) { schedule->make_valid(); // remove line from old stop is needed at here if(last_halt.is_bound()) { last_halt->remove_line(line); } player->simlinemgmt.update_line(line); } } } } // since factory connections may have changed welt->set_schedule_counter(); } return NULL; } char const* tool_daynight_level_t::get_tooltip(player_t const*) const { if (!strempty(default_param)) { if(default_param[0]=='+' || default_param[0]=='-') { sprintf(toolstr, "%s %s", translator::translate("1LIGHT_CHOOSE"), &default_param[0]); return toolstr; } else { return translator::translate("Toggle day/night view"); } } else { return ""; } } bool tool_daynight_level_t::init( player_t * ) { if(grund_t::underground_mode==grund_t::ugm_all || env_t::night_shift) { return false; } if (!strempty(default_param)) { if(default_param[0]=='+' && env_t::daynight_level > 0) { // '+': fade in one level env_t::daynight_level = env_t::daynight_level-1; } else if (default_param[0]=='-') { // '-': fade out one level env_t::daynight_level = env_t::daynight_level+1; } else { // number: toggle number/0. 4 or 5 is good for night const sint8 level = atoi(default_param); env_t::daynight_level = (env_t::daynight_level==0) ? level : 0; } } return false; } bool tool_rollup_all_win_t::init( player_t * ) { rollup_all_win(); return false; } /* make all tiles of this player a public stop * if this player is public, make all connected tiles a public stop */ bool tool_make_stop_public_t::init( player_t * ) { win_set_static_tooltip( NULL ); return true; } const char* tool_make_stop_public_t::get_tooltip(const player_t *) const { sprintf(toolstr, translator::translate("Make way or stop public (will join with neighbours), %i times maintainance"), welt->get_settings().cst_make_public_months); return toolstr; } const char *tool_make_stop_public_t::move( player_t *player, uint16, koord3d p ) { // queue tool for network if (env_t::networkmode) { nwc_tool_t *nwc = new nwc_tool_t(player, this, p, welt->get_steps(), welt->get_map_counter(), false); network_send_server(nwc); return NULL; } return work( player, p ); } const char *tool_make_stop_public_t::work( player_t *player, koord3d p ) { // target halt must exist halthandle_t halt = haltestelle_t::get_halt(p,player); if (!halt.is_bound() && player == welt->get_public_player()) { // public player can make halts of other players public grund_t *gr = welt->lookup(p); if (gr) { halt = gr->get_halt(); } } if( !halt.is_bound() ) { if(welt->get_settings().get_disable_make_way_public()) { return NOTICE_DISABLED_PUBLIC_WAY; } // not a halt to merge => just change way ownership if (grund_t* gr = welt->lookup(p)) { if (gr->get_typ() == grund_t::brueckenboden) { return NOTICE_UNSUITABLE_GROUND; } for (int j = 0; j < 2; j++) { if (weg_t* w = gr->get_weg_nr(j)) { // no public way with signs if (w->has_sign()) { return NOTICE_UNSUITABLE_GROUND; } } } bool has_been_announced = false; for (int j = 0; j < 2; j++) { if (weg_t* w = gr->get_weg_nr(j)) { // change ownership of way... player_t* wplayer = w->get_owner(); if (player == wplayer) { w->set_owner(welt->get_public_player()); w->set_flag(obj_t::dirty); sint32 cost = w->get_desc()->get_maintenance(); // of tunnel... if (tunnel_t* t = gr->find()) { t->set_owner(welt->get_public_player()); t->set_flag(obj_t::dirty); cost = t->get_desc()->get_maintenance(); } waytype_t const financetype = w->get_desc()->get_finance_waytype(); player_t::add_maintenance(wplayer, -cost, financetype); player_t::add_maintenance(welt->get_public_player(), cost, financetype); // multiplayer notification message if (env_t::networkmode && !has_been_announced) { cbuffer_t buf; buf.printf(translator::translate("(%s) now public way."), w->get_pos().get_str()); welt->get_message()->add_message(buf, w->get_pos(), message_t::ai, PLAYER_FLAG | player->get_player_nr(), IMG_EMPTY); has_been_announced = true; // one message is enough } cost = -welt->scale_with_month_length(cost * welt->get_settings().cst_make_public_months); player_t::book_construction_costs(wplayer, cost, koord::invalid, financetype); } } } // make way object public if any suitable for (uint8 i = 1; i < gr->obj_count(); i++) { if (wayobj_t* const wo = obj_cast(gr->obj_bei(i))) { player_t* woplayer = wo->get_owner(); if (player == woplayer) { sint32 const cost = wo->get_desc()->get_maintenance(); // change ownership wo->set_owner(welt->get_public_player()); wo->set_flag(obj_t::dirty); waytype_t const financetype = wo->get_desc()->get_waytype(); player_t::add_maintenance(woplayer, -cost, financetype); player_t::add_maintenance(welt->get_public_player(), cost, financetype); player_t::book_construction_costs(woplayer, cost, koord::invalid, financetype); } } } return 0; } // no ground found?!? return NOTICE_UNSUITABLE_GROUND; } // check funds sint64 workcost = -welt->scale_with_month_length(halt->calc_maintenance() * welt->get_settings().cst_make_public_months); // check waycost and some forbidden cases too for(haltestelle_t::tile_t const& i : halt->get_tiles()) { // make way public if any suitable for( int j=0; j<2; j++ ) { if( weg_t *w=i.grund->get_weg_nr(0) ) { if( player_t::check_owner( player, w->get_owner() ) && w->get_owner() ) { // no public ways? if( welt->get_settings().get_disable_make_way_public() ) { return NOTICE_DISABLED_PUBLIC_WAY; } // no public way with signs if( w->has_sign() ) { return NOTICE_UNSUITABLE_GROUND; } // compute maintainance cost sint32 cost = w->get_desc()->get_maintenance(); // tunnel cost overwrites way cost if( tunnel_t *t = i.grund->find() ) { cost = t->get_desc()->get_maintenance(); } workcost -= welt->scale_with_month_length(cost * welt->get_settings().cst_make_public_months); } } } } if( !player->can_afford(workcost) ) { return NOTICE_INSUFFICIENT_FUNDS; } // now find an adjacent stop vector_tplchecked_halts; checked_halts.append(halt); halthandle_t merge_to; for(haltestelle_t::tile_t const& i : halt->get_tiles()) { const koord pos = i.grund->get_pos().get_2d(); planquadrat_t *pl = welt->access( pos ); for( int i=0; iget_haltlist_count(); i++ ) { halthandle_t h = pl->get_haltlist()[i]; if( !checked_halts.is_contained(h) && h->get_owner()==welt->get_public_player() ) { koord testpos = h->get_ground_closest_to( pos )->get_pos().get_2d(); if( abs(pos.x-testpos.x) <= 1 && abs(pos.y-testpos.y) <= 1 ) { merge_to = h; break; } } } if( merge_to.is_bound() ) { break; } } // change ownership halt->change_owner( welt->get_public_player() ); halt->merge_halt( merge_to ); return NULL; } /* merge stop */ image_id tool_merge_stop_t::get_marker_image() const { return cursor; } uint8 tool_merge_stop_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &) { grund_t *bd = welt->lookup(pos); if (bd==NULL) { error = ""; return 0; } // check halt ownership halthandle_t h = haltestelle_t::get_halt(pos,player); if( h.is_bound() ) { // allow to merge two public stops too // so no need to check for ownership // check for halt on the tile if( bd->is_halt() || (h->get_station_type()&haltestelle_t::dock && bd->is_water()) ) { return 2; } } // not a halt at all ... error = NOTICE_UNSUITABLE_GROUND; return 0; } void tool_merge_stop_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) { // only seens when dragging halt_be_merged_from = haltestelle_t::get_halt(start,player); halt_be_merged_to = haltestelle_t::get_halt(end,player); sint64 workcost = 0; uint32 distance = 0x7FFFFFFFu; if( halt_be_merged_from == halt_be_merged_to ) { // same halt => do nothing win_set_static_tooltip( NULL ); } // check ownership if (!halt_be_merged_from->get_owner()->is_public_service() || halt_be_merged_from->get_owner() != halt_be_merged_to->get_owner()) { win_set_static_tooltip( "Das Feld gehoert\neinem anderen Spieler\n" ); return; } for(haltestelle_t::tile_t const& i : halt_be_merged_from->get_tiles()) { for(haltestelle_t::tile_t const& j : halt_be_merged_to->get_tiles()) { uint32 dist = koord_distance( i.grund->get_pos(), j.grund->get_pos() ); if( dist < distance ) { distance = dist; if( distance <= 1 ) { break; } } } if( distance <= 1 ) { break; } } if( distance < welt->get_settings().allow_merge_distant_halt ) { distance = clamp(distance,2u,33u)-2; workcost = welt->scale_with_month_length( (1<get_settings().cst_multiply_merge_halt ); win_set_static_tooltip( tooltip_with_price("Building costs estimates", workcost) ); } else { win_set_static_tooltip( "Too far away to merge stations!" ); } } const char *tool_merge_stop_t::do_work( player_t *player, const koord3d &last_pos, const koord3d &pos) { halt_be_merged_from = haltestelle_t::get_halt(pos,player); halt_be_merged_to = haltestelle_t::get_halt(last_pos,player); sint64 workcost = 0; uint32 distance = 0x7FFFFFFFu; if( halt_be_merged_from == halt_be_merged_to ) { // same halt => do nothing return NULL; } // check ownership if(!player->is_public_service() && halt_be_merged_from->get_owner() != halt_be_merged_to->get_owner()) { return "Das Feld gehoert\neinem anderen Spieler\n"; } for(haltestelle_t::tile_t const& i : halt_be_merged_from->get_tiles()) { for(haltestelle_t::tile_t const& j : halt_be_merged_to->get_tiles()) { uint32 dist = koord_distance( i.grund->get_pos(), j.grund->get_pos() ); if( dist < distance ) { distance = dist; if( distance <= 1 ) { break; } } } if( distance <= 1 ) { break; } } if( distance < welt->get_settings().allow_merge_distant_halt ) { distance = clamp(distance,2u,33u)-2; workcost = welt->scale_with_month_length( (1<get_settings().cst_multiply_merge_halt ); win_set_static_tooltip( tooltip_with_price("Building costs estimates", workcost) ); if( player != welt->get_public_player() && !player->can_afford(workcost) ) { return NOTICE_INSUFFICIENT_FUNDS; } } else { return "Too far away to merge stations!"; } // and now just do it ... halt_be_merged_to->merge_halt(halt_be_merged_from); player_t::book_construction_costs( player, workcost, halt_be_merged_to->get_basis_pos(), ignore_wt ); // nothing to do return NULL; } image_id tool_remove_signal_t::get_icon(player_t*) const { // do not show if there are no matching ways on the map if (default_param && way_builder_t::waytype_available((waytype_t)atoi(default_param), welt->get_timeline_year_month())) { return icon; } return IMG_EMPTY; } const char* tool_remove_signal_t::work( player_t* player, koord3d pos ) { if( grund_t *gr=welt->lookup(pos) ) { if( signal_t *rs=gr->find() ) { const char *msg = rs->get_removal_error(player); if(msg) { return msg; } DBG_MESSAGE("tool_remove_signal_t()", "removing roadsign at (%s)", pos.get_str()); weg_t *weg = gr->get_weg(rs->get_desc()->get_wtyp()); if( weg==NULL && rs->get_desc()->get_wtyp()==tram_wt ) { weg = gr->get_weg(track_wt); } rs->cleanup(player); delete rs; // no need to update way if there is none // may happen when public player builds a signal on a company track, // the company goes bankrupt and the public player tries to remove the signal if (weg) { weg->count_sign(); } return NULL; } } // fail silent return ""; } // only public plaYer can copy public objects const char* tool_pipette_t::allow_tool_check(const obj_t* obj, const obj_desc_timelined_t *desc, const player_t* pl) const { if (!pl->is_public_service()) { if (obj->get_owner() == NULL || obj->get_owner() != pl) { return "Not allowed to copy object."; } if (!desc->is_available(welt->get_timeline_year_month())) { return "Not allowed to copy object."; } } return NULL; } #define select_and_check(typ) \ if(typ *obj=gr->find()) {\ if (const char *err = allow_tool_check(obj, obj->get_desc(), pl)) {\ return err;\ }\ welt->set_tool(obj->get_desc()->get_builder(), pl);\ return NULL;\ } // create tool for object under the cursor const char *tool_pipette_t::work(player_t *pl, koord3d pos) { static cbuffer_t param_str; const grund_t *gr = welt->lookup(pos); if (!gr || gr->obj_count()==0) { return NULL; } select_and_check(tunnel_t) select_and_check(bruecke_t) if (gebaeude_t* gb = gr->find()) { if (const char *err = allow_tool_check(gb, gb->get_tile()->get_desc(), pl)) { return err; } const building_desc_t* desc = gb->get_tile()->get_desc(); if (!pl->is_public_service()) { // since we are not allowed to create public infrastructure as normal player, we must forbid this too if (desc->is_city_building() || desc->is_attraction() || desc->is_townhall() || desc->is_monument()) { return "Not allowed to copy object."; } } else { if (desc->is_depot() || desc->is_headquarters() || desc->is_townhall()) { return "Not allowed to copy object."; } } // here on factories, monuments, town halls, city buildings and more if (gb->get_fabrik()) { static tool_build_factory_t t = tool_build_factory_t(); param_str.clear(); param_str.printf("%i%i%i,%s", 1, // with climate gb->get_tile()->get_layout(), /*rotation*/ gb->get_fabrik()->get_base_production(), gb->get_fabrik()->get_desc()->get_name()); t.set_default_param(param_str); t.cursor = tool_t::general_tool[TOOL_BUILD_FACTORY]->cursor; welt->set_tool(&t, pl); return NULL; } else if (desc->is_attraction() || desc->is_city_building()) { static tool_build_house_t t = tool_build_house_t(); t.cursor = tool_t::general_tool[TOOL_BUILD_HOUSE]->cursor; param_str.clear(); param_str.printf("%d,%s", gb->get_tile()->get_layout(), /*rotation*/ gb->get_tile()->get_desc()->get_name()); t.set_default_param(param_str); welt->set_tool(&t, pl); return NULL; } else if (tool_t* t = gb->get_tile()->get_desc()->get_builder()) { welt->set_tool(t, pl); return NULL; } return "Not allowed to copy object."; } if (depot_t *depot=gr->get_depot()) { if (pl->is_public_service()) { return "Not allowed to copy object."; } tool_t* t = depot->get_tile()->get_desc()->get_builder(); welt->set_tool(t, pl); return NULL; } if (gr->get_weg_nr(0)) { // signals > wayobjs > ways select_and_check(signal_t); select_and_check(roadsign_t); select_and_check(wayobj_t); if (tool_t *way_builder = gr->get_weg_nr(0)->get_desc()->get_builder()) { if (const char* err = allow_tool_check(gr->get_weg_nr(0), gr->get_weg_nr(0)->get_desc(), pl)) { return err; } welt->set_tool(way_builder, pl); return NULL; } return "Not allowed to copy object."; // here on rivers and city roads } select_and_check(leitung_t); if (gr->find() || gr->find()) { // missing: check for ownership welt->set_tool(tool_t::general_tool[TOOL_TRANSFORMER], pl); return NULL; } if (baum_t* b = gr->find()) { static tool_plant_tree_t t; param_str.clear(); param_str.printf("%i%i,%s", 1, 0, b->get_desc()->get_name()); t.set_default_param(param_str); t.cursor = tool_t::general_tool[TOOL_PLANT_TREE]->cursor; welt->set_tool(&t, pl); } if (groundobj_t* b = gr->find()) { if (pl->is_public_service()) { static tool_plant_groundobj_t t; param_str.clear(); param_str.printf("%i%i,%s", 1, 0, b->get_desc()->get_name()); t.set_default_param(param_str); t.cursor = tool_t::general_tool[TOOL_PLANT_GROUNDOBJ]->cursor; welt->set_tool(&t, pl); } } return gr->obj_count()>0 ? "Not allowed to copy object." : NULL; } bool tool_show_trees_t::init( player_t* ) { env_t::hide_trees = !env_t::hide_trees; baum_t::recalc_outline_color(); welt->set_dirty(); return false; } sint8 tool_show_underground_t::save_underground_level = -128; bool tool_show_underground_t::init( player_t * ) { koord3d zpos = welt->get_zeiger()->get_pos(); // move zeiger (pointer) to invalid position -> unmark tiles welt->get_zeiger()->change_pos( koord3d::invalid); sint8 old_underground_level = grund_t::underground_level; // map needs update? bool ok = true; // need an extra click? bool needs_click = false; // default default-param = U for backward compatibility if (default_param == NULL) { default_param = strdup("U"); } // now check the default parameter switch(default_param[0]) { // toggle sliced view by toolbar - height taken from extra mouse click case 'C': if(grund_t::underground_mode==grund_t::ugm_level) { grund_t::set_underground_mode( grund_t::ugm_none, 0); } else if(grund_t::underground_mode==grund_t::ugm_none) { needs_click = true; ok = false; } else { ok = false; } break; // decrease slice level case 'D': if(grund_t::underground_mode==grund_t::ugm_level) { if( grund_t::underground_level > welt->min_height ) { grund_t::underground_level --; } } else { ok = false; } break; // increase slice level case 'I': if(grund_t::underground_mode==grund_t::ugm_level) { if( grund_t::underground_level < welt->max_height ) { grund_t::underground_level ++; } } else { ok = false; } break; // toggle sliced view by keyboard - height taken from cursor case 'K': if(grund_t::underground_mode==grund_t::ugm_level) { // switch to normal or full-underground grund_t::set_underground_mode( grund_t::ugm_none, 0); } else if(grund_t::underground_mode==grund_t::ugm_none) { grund_t::set_underground_mode( grund_t::ugm_level, zpos.z); } else { ok = false; } break; // switch between full underground or normal/sliced view case 'U': if (grund_t::underground_mode==grund_t::ugm_all) { // check if the old level is valid then switch back to sliced view if (-128error( "tool_show_underground_t::init()", "Unknown command string \"%s\"", default_param ); } // move zeiger (pointer) back welt->get_zeiger()->change_pos( zpos); if (ok) { save_underground_level = old_underground_level; // renew toolbar tool_t::update_toolbars(); // recalc all images on map welt->update_underground(); } return needs_click; } bool tool_show_underground_t::exit( player_t* ) { if( grund_t::underground_mode != grund_t::ugm_none ) { // reset no normal view on deselect grund_t::set_underground_mode( grund_t::ugm_none, 0 ); // renew toolbar tool_t::update_toolbars(); // recalc all images on map welt->update_underground(); } return false; } const char *tool_show_underground_t::work( player_t *player, koord3d pos) { koord3d zpos = welt->get_zeiger()->get_pos(); // move zeiger (pointer) to invalid position -> unmark tiles welt->get_zeiger()->change_pos( koord3d::invalid); save_underground_level = grund_t::underground_level; grund_t::set_underground_mode( grund_t::ugm_level, pos.z); // move zeiger (pointer) back welt->get_zeiger()->change_pos( zpos); // renew toolbar tool_t::update_toolbars(); // recalc all images on map welt->update_underground(); if(player == welt->get_active_player()) { welt->set_tool( general_tool[TOOL_QUERY], player ); } return NULL; } char const* tool_show_underground_t::get_tooltip(player_t const*) const { // no default-param == U for backward compatibility if( default_param == NULL ) { return translator::translate("underground mode"); } // now check the default parameter switch(default_param[0]) { // toggle sliced view by toolbar - height taken from extra mouse click case 'C': return translator::translate("sliced underground mode"); // decrease slice level case 'D': return translator::translate("decrease underground view level"); // increase slice level case 'I': return translator::translate("increase underground view level"); // toggle sliced view by keyboard - height taken from cursor case 'K': return translator::translate("sliced underground mode"); // switch between full underground or normal/sliced view case 'U': default: return translator::translate("underground mode"); } } bool tool_show_underground_t::is_selected() const { // default default-param = U for backward compatibility if( default_param == NULL ) { return grund_t::underground_mode==grund_t::ugm_all; } // now check the default parameter switch(default_param[0]) { // toggle sliced view by toolbar - height taken from extra mouse click case 'C': return grund_t::underground_mode==grund_t::ugm_level; // decrease slice level case 'D': return false; // increase slice level case 'I': return false; // toggle sliced view by keyboard - height taken from cursor case 'K': return grund_t::underground_mode==grund_t::ugm_level; // switch between full underground or normal/sliced view case 'U': return grund_t::underground_mode==grund_t::ugm_all; } return false; } void tool_show_underground_t::draw_after(scr_coord k, bool dirty) const { if( icon!=IMG_EMPTY && is_selected() ) { display_img_blend( icon, k.x, k.y, TRANSPARENT50_FLAG|OUTLINE_FLAG|color_idx_to_rgb(COL_BLACK), false, dirty ); // additionally show level in sliced mode if( default_param!=NULL && grund_t::underground_mode==grund_t::ugm_level ) { char level_str[16]; sprintf( level_str, "%i", grund_t::underground_level ); display_proportional_rgb( k.x+4, k.y+4, level_str, ALIGN_LEFT, color_idx_to_rgb(COL_YELLOW), true ); } } } void tool_rotate90_t::draw_after(scr_coord pos, bool dirty) const { if( !env_t::networkmode ) { if( skinverwaltung_t::compass_map ) { display_img_aligned( skinverwaltung_t::compass_map->get_image_id( welt->get_settings().get_rotation()+4 ), scr_rect(pos,env_t::iconsize), ALIGN_CENTER_V|ALIGN_CENTER_H, false ); } tool_t::draw_after( pos, dirty ); } } bool tool_rotate90_t::init( player_t * ) { if( !env_t::networkmode ) { welt->rotate90(); welt->update_map(); } return false; } bool tool_quit_t::init( player_t * ) { if (!strempty(default_param)) { // new world destroy_all_win(true); welt->stop(false); } else { // totally quit welt->stop(true); } if (env_t::networkmode) { welt->network_disconnect(); } return false; } bool tool_toggle_reservation_t::is_selected() const { if (tool_t* t = welt->get_tool(welt->get_active_player_nr())) { if (t->get_id() != (TOOL_CLEAR_RESERVATION | GENERAL_TOOL)) { return schiene_t::show_reservations; } } return false; } bool tool_screenshot_t::init( player_t * ) { bool ok; const scr_rect screen_area = scr_rect(0, 0, display_get_width(), display_get_height()); const gui_frame_t *topwin = win_get_top(); if( is_ctrl_pressed() && topwin != NULL ) { ok = display_snapshot( scr_rect(win_get_pos(topwin), topwin->get_windowsize()) ); } else { ok = display_snapshot( screen_area ); } if (ok) { create_win( new news_img("Screenshot\ngespeichert.\n"), w_time_delete, magic_none); } else { create_win( new news_img("Could not\ncreate screenshot!\n"), w_time_delete, magic_none); } return false; } bool tool_undo_t::init( player_t *player ) { if(!player->undo() && can_use_gui()) { create_win( new news_img("UNDO failed!"), w_time_delete, magic_none); } return false; } bool tool_increase_industry_t::init( player_t * ) { factory_builder_t::increase_industry_density( false ); return false; } bool tool_zoom_in_t::init( player_t * ) { win_change_zoom_factor(true); welt->set_dirty(); return false; } bool tool_zoom_out_t::init( player_t * ) { win_change_zoom_factor(false); welt->set_dirty(); return false; } /************************* internal tools, only need for networking ***************/ static bool scenario_check_schedule(karte_t *welt, player_t *player, schedule_t *schedule, bool local) { if (!is_scenario()) { return true; } const char* err = welt->get_scenario()->is_schedule_allowed(player, schedule); if (err) { if (*err && local) { open_error_msg_win(err); } return false; } return true; } bool scenario_check_convoy(karte_t *welt, player_t *player, convoihandle_t cnv, depot_t* depot, bool local) { if (!is_scenario()) { return true; } const char* err = welt->get_scenario()->is_convoy_allowed(player, cnv, depot); if (err) { if (*err && local) { open_error_msg_win(err); } return false; } return true; } /* Handles all action of convois in depots. Needs a default param: * [function],[convoi_id],addition stuff * following simple command exists: * 'x' : self destruct * 'f' : open the schedule window * 'g' : apply a schedule * 'n' : toggle 'no load' * 'w' : toggle withdraw * 's' : change state to [number] (and maybe set open schedule flag) * 'l' : apply new line [number] * 'd' : go to nearest depot */ bool tool_change_convoi_t::init( player_t *player ) { char tool=0; uint16 convoi_id = 0; // skip the rest of the command const char *p = default_param; while( *p && *p<=' ' ) { p++; } sscanf( p, "%c,%hi", &tool, &convoi_id ); // skip to the commands ... for( int z = 2; *p && z>0; p++ ) { if( *p==',' ) { z--; } } convoihandle_t cnv; cnv.set_id( convoi_id ); // double click on remove button will send two such commands // the first will delete the convoi, the second should not trigger an assertion // catch such commands here if( !cnv.is_bound()) { #if MSG_LEVEL>=4 if (can_use_gui()) { create_win( new news_img("Convoy already deleted!"), w_time_delete, magic_none); } #endif dbg->warning("tool_change_convoi_t::init", "no convoy with id=%d found", convoi_id); return false; } // ownership check for network games if (env_t::networkmode && !player_t::check_owner(cnv->get_owner(), player)) { return false; } // first letter is now the actual command switch( tool ) { case 'x': // self destruction ... if (cnv->get_state()==convoi_t::INITIAL) { // delete cnv in depot if (grund_t *gr = welt->lookup(cnv->get_pos())) { if (depot_t *dep = gr->get_depot()) { dep->disassemble_convoi(cnv, true); return false; } } } cnv->self_destruct(); return false; case 'f': // open schedule { // we open the window only when executed on the same client that triggered the tool // but the all clients must call the function anyway cnv->open_schedule_window( can_use_gui() ); } break; case 'g': // change schedule { schedule_t *schedule = cnv->create_schedule()->copy(); schedule->finish_editing(); if (schedule->sscanf_schedule( p ) && (no_check() || scenario_check_schedule(welt, player, schedule, can_use_gui())) ) { cnv->set_schedule( schedule ); } else { // could not read schedule, do not assign delete schedule; // but clear editing flag cnv->get_schedule()->finish_editing(); cnv->set_schedule( cnv->get_schedule() ); } } break; case 'l': // change line { // read out id and new current_stop index uint16 id=0, current_stop=0; int count=sscanf( p, "%hi,%hi", &id, ¤t_stop ); linehandle_t l; l.set_id( id ); if( l.is_bound() ) { // sanity check for right line-type (compare schedule types ..) schedule_t *schedule = cnv->create_schedule(); if( schedule && l->get_schedule() && schedule->get_type()!=l->get_schedule()->get_type() ) { dbg->warning("tool_change_convoi_t::init", "types of convoi and line do not match"); return false; } if( count==1 ) { // current_stop was not supplied -> take it from line schedule current_stop = l->get_schedule()->get_current_stop(); } cnv->set_line( l ); cnv->get_schedule()->set_current_stop((uint8)current_stop); cnv->get_schedule()->finish_editing(); } } break; case 'n': // change no_load cnv->set_no_load( !cnv->get_no_load() ); if( !cnv->get_no_load() ) { cnv->set_withdraw( false ); } break; case 's': // change state { int new_state = atoi(p); if( new_state>0 ) { cnv->set_state( new_state ); if( new_state==convoi_t::EDIT_SCHEDULE ) { cnv->get_schedule()->start_editing(); } } } break; case 'w': // change withdraw cnv->set_withdraw( !cnv->get_withdraw() ); cnv->set_no_load( cnv->get_withdraw() ); break; case 'd': // goto depot { const char* msg = cnv->send_to_depot(is_local_execution()); if (is_local_execution()) { create_win( new news_img(msg), w_time_delete, magic_none); } } } if( cnv->in_depot() && (tool=='g' || tool=='l') ) { const grund_t *const ground = welt->lookup( cnv->get_home_depot() ); if( ground ) { const depot_t *const depot = ground->get_depot(); if( depot ) { depot_frame_t *const frame = dynamic_cast( win_get_magic( (ptrdiff_t)depot ) ); if( frame ) { frame->update_data(); } } } } return false; // no related work tool ... } /* Handles all action of lines. Needs a default param: * [function],[line_id],addition stuff * following simple command exists: * 'g' : apply new schedule to line [schedule follows] */ bool tool_change_line_t::init( player_t *player ) { uint16 line_id = 0; // skip the rest of the command const char *p = default_param; while( *p && *p<=' ' ) { p++; } char tool=*p++; while( *p && *p++!=',' ) { } if( *p==0 ) { dbg->warning( "tool_change_line_t::init()", "too short command \"%s\"", default_param ); return false; } line_id = atoi(p); while( *p && *p++!=',' ) { } linehandle_t line; line.set_id( line_id ); // ownership check for network games if (line.is_bound() && env_t::networkmode && !player_t::check_owner(line->get_owner(), player)) { return false; } // first letter is now the actual command switch( tool ) { case 'c': // create line, next parameter line type and magic of schedule window (only right window gets updated) { int ltype = atoi(p); if(ltype < simline_t::truckline || ltype > simline_t::narrowgaugeline) { // invalid line type break; } line = player->simlinemgmt.create_line( ltype, player ); while( *p && *p++!=',' ) { } long t; sscanf( p, "%ld", &t ); while( *p && *p++!=',' ) { } line->get_schedule()->sscanf_schedule( p ); // check scenario conditions if (!no_check() && !scenario_check_schedule(welt, player, line->get_schedule(), can_use_gui())) { player->simlinemgmt.delete_line(line); break; } line->get_schedule()->finish_editing(); // just in case ... if( can_use_gui() ) { player->simlinemgmt.show_lineinfo( player, line, 0 ); } } break; case 'd': // delete line { if (line.is_bound()) { // close a schedule window, if still active gui_frame_t *w = win_get_magic( (ptrdiff_t)line.get_rep() ); if(w) { destroy_win( w ); } player->simlinemgmt.delete_line(line); } } break; case 'g': // change schedule { if (line.is_bound()) { schedule_t *schedule = line->get_schedule()->copy(); if (schedule->sscanf_schedule( p ) && (no_check() || scenario_check_schedule(welt, player, schedule, can_use_gui())) ) { schedule->finish_editing(); line->set_schedule( schedule ); line->get_owner()->simlinemgmt.update_line(line); } else { // could not read schedule, do not assign delete schedule; } } } break; case 't': // trims away convois on all lines of linetype with this default parameter { vector_tpl const& lines = player->simlinemgmt.get_line_list(); // what kind of lines to trim const simline_t::linetype linetype = (simline_t::linetype)atoi(p); while( *p && *p++!=',' ) { } // how much as target sint32 percentage = *p ? atoi(p) : 10; if( percentage == 0 ) { break; } for(linehandle_t line : lines) { if( line->get_linetype() == linetype && line->get_convoys().get_count() > 2 ) { // correct waytpe and more than one,n now some up usage for the last six months sint64 transported = 0, capacity = 0; for( int i=0; i<6; i++ ) { capacity += line->get_finance_history( i , LINE_CAPACITY ); transported += line->get_finance_history( i , LINE_TRANSPORTED_GOODS ); } // sanity check for non-moving lines if( capacity == 0 ) { continue; } if( (transported*100) / capacity < percentage ) { // less than 33 % usage => remove concois vector_tpl const& cnvs = line->get_convoys(); sint64 old_sum_capacity = 0; for(convoihandle_t cnv : cnvs) { for( int i=0; iget_vehicle_count(); i++ ) { old_sum_capacity += cnv->get_vehicle(i)->get_desc()->get_capacity(); } } /* now we have the total capacity. We will now remove convois until this capacity * is reduced by the ration suggested from transported = 1/3 of total capacity * x is the percentage of used capacity * Then is the new target sum_capacity = x*old_sum_capacity */ sint64 new_sum_capacity = (transported * 1000 * old_sum_capacity) / (capacity * percentage * 10); // first we remove the totally empty convois (nowbody will miss them) int destroyed = 0; const int initial = line->get_convoys().get_count(); const int max_left = (initial+2) / 2; for( int j=initial-1; j >= 0 && initial-destroyed > max_left && new_sum_capacity < old_sum_capacity; j-- ) { convoihandle_t cnv = line->get_convoy(j); if( cnv->get_state() == convoi_t::INITIAL || cnv->get_state() >= convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH ) { for( int i=0; iget_vehicle_count(); i++ ) { old_sum_capacity -= cnv->get_vehicle(i)->get_desc()->get_capacity(); } cnv->self_destruct(); destroyed ++; } } // not enough? Then remove from the end ... for( uint j=0; j < line->get_convoys().get_count() && initial-destroyed > max_left && new_sum_capacity < old_sum_capacity; j++ ) { convoihandle_t cnv = line->get_convoy(j); if( cnv->get_state() != convoi_t::SELF_DESTRUCT ) { for( int i=0; iget_vehicle_count(); i++ ) { old_sum_capacity -= cnv->get_vehicle(i)->get_desc()->get_capacity(); } cnv->self_destruct(); destroyed ++; } } // done if( destroyed ) { dbg->message( "tool_change_line_t::init", "trim line %s: Reduced from %d to %d convois", line->get_name(), initial, initial-destroyed ); } } } } } break; case 'u': // unite all lineless convois with similar schedules { array_tpl > cnvs(welt->convoys().get_count()); uint32 max_cnvs=0; for(convoihandle_t cnv : welt->convoys()) { // only check lineless convoys if( !cnv->get_line().is_bound() ) { bool found = false; // check, if already matches existing convois schedule for( uint32 i=0; iget_schedule()->matches( welt, cnv->get_schedule() ) ) { found = true; cnvs[i].append( cnv ); break; } } } // not added: then may be new line for this? if( !found ) { cnvs[max_cnvs++].append( cnv ); } } } // now we have an array of one or more lineless convois for( uint32 i=0; i new line if( cnvs[i].get_count()>1 ) { line = player->simlinemgmt.create_line( cnvs[i][0]->get_schedule()->get_type(), player, cnvs[i][0]->get_schedule() ); for(convoihandle_t cnv : cnvs[i] ) { line->add_convoy( cnv ); cnv->set_line( line ); } } } } break; case 'w': // change widthdraw { if (line.is_bound()) { line->set_withdraw( atoi(p) ); } } break; } return false; } /* Handles all action of convois in depots. Needs a default param: * [function],[depot_pos_3d],[convoi_id],addition stuff * following simple command exists: * 'l' : creates a new line (convoi_id might be invalid) (+printf'd initial schedule) * 'b' : starts the convoi * 'B' : starts all convoys * 'c' : copies this convoi * 'd' : disassembles convoi * 's' : sells convoi * 'a' : appends a vehicle (+vehikel_name) uses the oldest * 'i' : inserts a vehicle in front (+vehikel_name) uses the oldest * 's' : sells a vehicle (+vehikel_name) uses the newest * 'r' : removes a vehicle (+number in convoi) * 'R' : removes all vehicles including (+number in convoi) to end */ bool tool_change_depot_t::init( player_t *player ) { char tool=0; koord pos2d; sint8 z; uint16 convoi_id; // skip the rest of the command const char *p = default_param; while( *p && *p<=' ' ) { p++; } sscanf( p, "%c,%hi,%hi,%hhi,%hi", &tool, &pos2d.x, &pos2d.y, &z, &convoi_id ); koord3d pos(pos2d, z); // skip to the commands ... z = 5; while( *p && z>0 ) { if( *p==',' ) { z--; } p++; } grund_t *gr = welt->lookup(pos); depot_t *depot = gr ? gr->get_depot() : NULL; if( depot==NULL ){ dbg->warning("tool_change_depot_t::init", "no depot found at (%s)", pos.get_str()); return false; } if( !player_t::check_owner( depot->get_owner(), player) ) { dbg->warning("tool_change_depot_t::init", "depot at (%s) belongs to another player", pos.get_str()); return false; } convoihandle_t cnv; cnv.set_id( convoi_id ); // ok now do our stuff switch( tool ) { case 'l': { // create line schedule window linehandle_t selected_line = depot->get_owner()->simlinemgmt.create_line(depot->get_line_type(),depot->get_owner()); // no need to check schedule for scenario conditions, as schedule is only copied selected_line->get_schedule()->sscanf_schedule( p ); depot_frame_t *depot_frame = dynamic_cast(win_get_magic( (ptrdiff_t)depot )); if( can_use_gui() ) { player->simlinemgmt.show_lineinfo( player, selected_line, 0 ); } if( depot_frame ) { if( can_use_gui() ) { depot_frame->set_selected_line( selected_line ); depot_frame->apply_line(); } depot_frame->update_data(); } DBG_MESSAGE("depot_frame_t::new_line()","id=%d",selected_line.get_id() ); break; } case 'b': { // start a convoi from the depot if( cnv.is_bound() ) { depot->start_convoi(cnv, can_use_gui()); } break; } case 'B': { // start all convoys depot->start_all_convoys(); break; } case 'd': // disassemble convoi case 'v': { // sell convoi depot->disassemble_convoi( cnv, tool=='v' ); break; } case 'V': { // sell all convoys depot->disassemble_all_convois( tool=='V' ); break; } case 'c': { // copy this convoi if( cnv.is_bound() ) { if( convoihandle_t::is_exhausted() ) { if( can_use_gui() ) { create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none ); } return false; } depot->copy_convoi( cnv, can_use_gui() ); } break; } case 'a': // append a vehicle case 'i': // insert a vehicle in front case 's': // sells a vehicle case 'r': // removes a vehicle (assumes a valid depot) case 'R': { // removes all vehicles to end (assumes a valid depot) if( tool=='r' || tool=='R' ) { // test may fail after double-click on the button: // two remove cmds are sent, only the first will remove, the second should not trigger assertion failure if ( cnv.is_bound() ) { int start_nr = atoi(p); int nr = start_nr; // find end while(nrget_vehicle_count()) { const vehicle_desc_t *info = cnv->get_vehicle(nr)->get_desc(); nr ++; if(info->get_trailer_count()!=1) { break; } } // now remove the vehicles if( cnv->get_vehicle_count()==nr-start_nr || (tool=='R' && start_nr==0) ) { depot->disassemble_convoi(cnv, false); } else if( tool=='R' ) { depot->remove_vehicles_to_end( cnv, start_nr ); } else { for( int i=start_nr; iremove_vehicle(cnv, start_nr); } } } } else { // create and append it const vehicle_desc_t *info = vehicle_builder_t::get_info( p ); // we have a valid vehicle there => now check for details if( info ) { // we buy/sell all vehicles together! slist_tplnew_vehicle_info; const vehicle_desc_t *start_info = info; if(tool!='a') { // start of composition while( info->get_leader_count() == 1 && info->get_leader(0) != NULL && info->get_leader(0) != vehicle_desc_t::any_vehicle && !new_vehicle_info.is_contained(info->get_leader(0))) { info = info->get_leader(0); new_vehicle_info.insert(info); } info = start_info; } new_vehicle_info.append( info ); if (tool != 'i') { while(info->get_trailer_count() == 1 && info->get_trailer(0) != NULL && info->get_trailer(0) != vehicle_desc_t::any_vehicle && !new_vehicle_info.is_contained(info->get_trailer(0))) { info = info->get_trailer(0); new_vehicle_info.append(info); } } // now we have a valid composition together if( tool=='s' ) { while( new_vehicle_info.get_count() ) { // We sell the newest vehicle - gives most money back. vehicle_t* veh = depot->find_oldest_newest(new_vehicle_info.remove_first(), false); if(veh != NULL) { depot->sell_vehicle(veh); } } } else { // now check if we are allowed to buy this (we test only leading vehicle, so one can still buy hidden stuff) info = new_vehicle_info.front(); if (!info->is_available(welt->get_timeline_year_month())) { if (info->is_future(welt->get_timeline_year_month())) { // not allowed return false; } else if (!welt->get_settings().get_allow_buying_obsolete_vehicles()) { // only allow append/insert, if in depot do not create new obsolete vehicles if( !depot->find_oldest_newest(info, true) ) { // just fail silent return false; } } // obsolete vehicle found or buying of obsolete allowed } // append/insert into convoi; create one if needed depot->clear_command_pending(); if( !cnv.is_bound() ) { if( convoihandle_t::is_exhausted() ) { if( can_use_gui() ) { create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none); } return false; } // create a new convoi cnv = depot->add_convoi( can_use_gui() ); cnv->set_name( new_vehicle_info.front()->get_name() ); } // now we have a valid cnv if( cnv->get_vehicle_count()+new_vehicle_info.get_count() <= depot->get_max_convoi_length() ) { for( unsigned i=0; ifind_oldest_newest(vb, true); if( veh == NULL ) { // nothing there => we buy it veh = depot->buy_vehicle(vb); } depot->append_vehicle( cnv, veh, tool=='i', can_use_gui() ); } } } } } depot->update_win(); break; } } return false; } /* Handles all player stuff default_param: * [function],[player_id],[state] * following command exists: * 'a' : activate/deactivate player (depends on state) * 'c' : change player color * '$' : change bank account */ bool tool_change_player_t::init( player_t *player_in) { if( default_param==NULL ) { dbg->warning( "tool_change_player_t::init()", "nothing to do!" ); return false; } // skip the rest of the command const char *p = default_param; while( *p && *p<=' ' ) { p++; } char tool = 0; int id = 0; if (sscanf( p, "%c,%i", &tool, &id ) < 2) { return false; // invalid command } player_t *player = welt->get_player(id); // ok now do our stuff switch( tool ) { case 'c': // change player color // unused if( player && player==player_in ) { int c1, c2, dummy; sscanf( p, "%c,%i,%i,%i", &tool, &dummy, &c1, &c2 ); player->set_player_color( c1, c2 ); } break; case '$': // change bank account if( player && player_in==welt->get_public_player() ) { int delta; if (sscanf(p, "%c,%i,%i", &tool, &id, &delta) == 3) { player->get_finance()->book_account(delta); } } break; case 'a': // WAS: activate/deactivate AI case 'n': // WAS: new player with type state case 'f': // WAS: activate/deactivate freeplay dbg->error( "tool_change_player_t::init()", "deprecated command called" ); break; } // update the window ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t); if (playerwin) { playerwin->update_data(); } return false; } /* Sets traffic light phases via default_param: * [pos],[ns_flag],[ticks] */ bool tool_change_traffic_light_t::init( player_t *player ) { koord pos2d; sint8 z; uint16 ns, ticks; if( 5!=sscanf( default_param, "%hi,%hi,%hhi,%hu,%hu", &pos2d.x, &pos2d.y, &z, &ns, &ticks ) ) { return false; } koord3d pos(pos2d, z); if( grund_t *gr = welt->lookup(pos) ) { if( roadsign_t *rs = gr->find() ) { if( ( rs->get_desc()->is_traffic_light() || rs->get_desc()->is_private_way() ) && player_t::check_owner(rs->get_owner(),player) ) { if( ns == 1 ) { rs->set_ticks_ns( (uint8)ticks ); } else if( ns == 0 ) { rs->set_ticks_ow( (uint8)ticks ); } else if( ns == 2 ) { rs->set_ticks_offset( (uint8)ticks ); } else if( ns == 4 ) { rs->set_ticks_yellow_ns( (uint8)ticks ); } else if( ns == 3 ) { rs->set_ticks_yellow_ow( (uint8)ticks ); } // update the window if( rs->get_desc()->is_traffic_light() ) { trafficlight_info_t* trafficlight_win = (trafficlight_info_t*)win_get_magic((ptrdiff_t)rs); if (trafficlight_win) { trafficlight_win->update_data(); } } else { privatesign_info_t* trafficlight_win = (privatesign_info_t*)win_get_magic((ptrdiff_t)rs); if (trafficlight_win) { trafficlight_win->update_data(); } } } } } return false; } /** * change city: * g[x],[y],[allow_city_growth] */ bool tool_change_city_t::init( player_t *player ) { if (player != welt->get_public_player()) { return false; } koord k; sint16 allow_growth; if( 3!=sscanf( default_param, "g%hi,%hi,%hi", &k.x, &k.y, &allow_growth ) ) { return false; } grund_t *gr = welt->lookup_kartenboden(k); if (gr) { gebaeude_t *gb = gr->find(); if (gb) { stadt_t *st = gb->get_stadt(); if (st) { st->set_citygrowth_yesno(allow_growth); city_info_t *stinfo = dynamic_cast(win_get_magic((ptrdiff_t)st)); if (stinfo) { stinfo->update_data(); } } } } return false; } /* Handles renaming of ingame entities. Needs a default param: * [object='c|h|l|m|t|p|f'][id|pos],[name] * c=convoi, h=halt, l=line, m=marker, t=town, p=player, f=factory * in case of marker / factory, id is a pos3d string */ bool tool_rename_t::init(player_t *player) { uint16 id = 0; koord3d pos = koord3d::invalid; // skip the rest of the command const char *p = default_param; const char what = *p++; switch( what ) { case 'h': case 'l': case 'c': case 't': case 'p': id = atoi(p); while( *p>0 && *p++!=',' ) { } break; case 'm': case 'f': { koord pos2d; sint8 z; if( 3!=sscanf( p, "%hi,%hi,%hhi", &pos2d.x, &pos2d.y, &z ) ) { dbg->error( "tool_rename_t::init", "no position given for marker/factory! (%s)", default_param ); return false; } while( *p>0 && *p++!=',' ) { } while( *p>0 && *p++!=',' ) { } while( *p>0 && *p++!=',' ) { } pos = koord3d(pos2d, z); id = 0; break; } default: dbg->error( "tool_rename_t::init", "illegal request! (%s)", default_param ); return false; } // now for action ... switch( what ) { case 'h': { halthandle_t halt; halt.set_id( id ); if( halt.is_bound() && (!env_t::networkmode || player_t::check_owner(halt->get_owner(), player)) ) { halt->set_name( p ); return false; } break; } case 'l': { linehandle_t line; line.set_id( id ); if( line.is_bound() && (!env_t::networkmode || player_t::check_owner(line->get_owner(), player)) ) { line->set_name( p ); return false; } break; } case 'c': { convoihandle_t cnv; cnv.set_id( id ); if( cnv.is_bound() && (!env_t::networkmode || player_t::check_owner(cnv->get_owner(), player)) ) { // set name without ID cnv->set_name( p, false ); return false; } break; } case 't': { if( player == welt->get_public_player() && idget_cities().get_count() ) { welt->get_cities()[id]->set_name( p ); return false; } break; } case 'm': if( grund_t *gr = welt->lookup(pos) ) { label_t *label = gr->find(); if (label && (!env_t::networkmode || player_t::check_owner(label->get_owner(), player)) ) { gr->set_text(p); } return false; } break; case 'p': { player_t *other = welt->get_player((uint8)id); if( other && other == player ) { other->set_name(p); return false; } break; } case 'f': { if( player == welt->get_public_player()) { if( grund_t *gr = welt->lookup(pos) ) { if( gebaeude_t* gb = gr->find() ) { if ( fabrik_t *fab = gb->get_fabrik() ) { fab->set_name(p); return false; } } } } } } // we are only getting here, if we could not process this request dbg->warning( "tool_rename_t::init", "could not perform (%s)", default_param ); return false; } bool tool_recolour_t::init(player_t *) { // skip the rest of the command const char *p = default_param; const char what = *p++; switch( what ) { case '1': case '2': { const uint8 player_nr = atoi(p); player_t *target_pl = player_nr < 16 ? welt->get_player(player_nr) : NULL; if (target_pl) { while (*p>0 && *p++!=',') {} if (*p) { const uint8 new_colour = atoi(p); const uint8 col1 = what == '1' ? new_colour : target_pl->get_player_color1(); const uint8 col2 = what == '2' ? new_colour : target_pl->get_player_color2(); target_pl->set_player_color(col1, col2); return false; } } // fallthrough } default: dbg->error( "tool_recolour_t::init", "Illegal request for player colour change! (%s)", default_param ); return false; } } bool tool_load_scenario_t::init(player_t*) { if (strempty(default_param) || strlen(default_param)<3 || default_param[1]!=',' ) { // no valid scenario parameter return false; } bool easy_server = default_param[0] == '1'; // since loading a scenario may not init the world welt->switch_server(easy_server, true); scenario_t* scn = new scenario_t(welt); const char* err = scn->init(str_get_basename(default_param+2).c_str(), str_get_filename(default_param + 2,true).c_str(), welt); if (err == NULL) { // start the game welt->set_pause(false); // open scenario info window destroy_win(magic_scenario_info); create_win(new scenario_info_t(), w_info, magic_scenario_info); tool_t::update_toolbars(); if (env_t::server) { welt->announce_server(karte_t::SERVER_ANNOUNCE_HELLO); } } else { if (env_t::server) { welt->switch_server(false, true); } create_win(new news_img(err), w_info, magic_none); delete scn; } // do not call work(), it's a no-op anyway return false; } /* * Add a message to the message queue */ const char* tool_add_message_t::work(player_t* player, koord3d pos ) { if (default_param && *default_param ) { uint32 type = atoi(default_param); const char* text = strchr(default_param, ','); if ((type & message_t::MESSAGE_TYPE_MASK) >= message_t::MAX_MESSAGE_TYPE || text == NULL) { return ""; } welt->get_message()->add_message( text+1, pos, type, player == NULL || ( (type & message_t::PLAYER_MSG) != 0) ? color_idx_to_rgb(COL_BLACK) : PLAYER_FLAG|player->get_player_nr(), IMG_EMPTY ); } return NULL; } simutrans-124.3/src/simutrans/tool/simtool.h000066400000000000000000001461711474050137200212150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TOOL_SIMTOOL_H #define TOOL_SIMTOOL_H /// New OO tool system #include "../simtypes.h" #include "../world/simworld.h" #include "../tool/simmenu.h" #include "../obj/simobj.h" #include "../obj/way/schiene.h" #include "../obj/baum.h" #include "../obj/groundobj.h" #include "../dataobj/environment.h" #include "../dataobj/translator.h" #include "../display/viewport.h" #include "../player/simplay.h" class koord3d; class koord; class way_builder_t; class building_desc_t; class roadsign_desc_t; class way_desc_t; class route_t; class way_obj_desc_t; /****************************** helper functions: *****************************/ char *tooltip_with_price(const char * tip, sint64 price); char *tooltip_with_price_length(const char * tip, sint64 price, sint64 length); void open_error_msg_win(const char* error); /************************ general tool *******************************/ // query tile info: default tool class tool_query_t : public tool_t { public: tool_query_t() : tool_t(TOOL_QUERY | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Abfrage"); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; // remove uppermost object from tile class tool_remover_t : public tool_t { private: bool tool_remover_intern(player_t *player, koord3d pos, sint8 type, const char *&msg); public: tool_remover_t() : tool_t(TOOL_REMOVER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Abriss"); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; // alter land height tools class tool_raise_lower_base_t : public tool_t { protected: bool is_dragging; sint16 drag_height; const char* drag(player_t*, koord k, sint16 h, int &n); virtual sint16 get_drag_height(koord k) = 0; bool check_dragging(); public: tool_raise_lower_base_t(uint16 id) : tool_t(id | GENERAL_TOOL), is_dragging(false), drag_height(0) { offset = Z_GRID; } image_id get_icon(player_t*) const OVERRIDE { return grund_t::underground_mode==grund_t::ugm_all ? IMG_EMPTY : icon; } bool init(player_t*) OVERRIDE { is_dragging = false; return true; } bool exit(player_t*) OVERRIDE { is_dragging = false; return true; } /** * technically move is not network safe, however its implementation is: * it sends work commands over network itself */ char const* move(player_t*, uint16 /* buttonstate */, koord3d) OVERRIDE; bool move_has_effects() const OVERRIDE { return true; } bool is_init_keeps_game_state() const OVERRIDE { return true; } /** * work() is only called when not dragging * if work() is called with is_dragging==true then is_dragging is reset */ bool is_work_keeps_game_state() const OVERRIDE { return is_dragging;} /** * @return true if this tool operates over the grid, not the map tiles. */ bool is_grid_tool() const OVERRIDE {return true;} bool update_pos_after_use() const OVERRIDE { return true; } }; class tool_raise_t : public tool_raise_lower_base_t { public: tool_raise_t() : tool_raise_lower_base_t(TOOL_RAISE_LAND) {} char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Anheben", welt->get_settings().cst_alter_land); } char const* check_pos(player_t*, koord3d) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; sint16 get_drag_height(koord k) OVERRIDE; }; class tool_lower_t : public tool_raise_lower_base_t { public: tool_lower_t() : tool_raise_lower_base_t(TOOL_LOWER_LAND) {} char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Absenken", welt->get_settings().cst_alter_land); } char const* check_pos(player_t*, koord3d) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; sint16 get_drag_height(koord k) OVERRIDE; }; /* slope tool definitions */ class tool_setslope_t : public tool_t { public: tool_setslope_t() : tool_t(TOOL_SETSLOPE | GENERAL_TOOL), old_slope_compatibility_mode(true) {} // if true then slope by default_param will be translated to new double-height system // true by default, can be set to false (used for scripts) bool old_slope_compatibility_mode; /** * Create an artificial slope * * @param player the player doing the task * @param pos position where the slope will be generated * @param slope the slope type * @param old_slope_compatibility * @param just_check */ static const char *tool_set_slope_work( player_t *player, koord3d pos, int slope, bool old_slope_compatibility, bool just_check = false); void rdwr_custom_data(memory_rw_t*) OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Built artifical slopes", welt->get_settings().cst_set_slope); } bool is_init_keeps_game_state() const OVERRIDE { return true; } char const* check_pos(player_t*, koord3d) OVERRIDE; char const* work(player_t* const player, koord3d const k) OVERRIDE { return tool_set_slope_work(player, k, default_param ? atoi(default_param) : 0, old_slope_compatibility_mode); } bool init(player_t*) OVERRIDE { return default_param != NULL; } }; class tool_restoreslope_t : public tool_t { public: tool_restoreslope_t() : tool_t(TOOL_RESTORESLOPE | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Restore natural slope", welt->get_settings().cst_set_slope); } bool is_init_keeps_game_state() const OVERRIDE { return true; } char const* check_pos(player_t*, koord3d) OVERRIDE; char const* work(player_t* const player, koord3d const k) OVERRIDE { return tool_setslope_t::tool_set_slope_work(player, k, RESTORE_SLOPE, true); } }; class tool_marker_t : public kartenboden_tool_t { public: tool_marker_t() : kartenboden_tool_t(TOOL_MARKER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Marker", welt->get_settings().cst_buy_land); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_clear_reservation_t : public tool_t { public: tool_clear_reservation_t() : tool_t(TOOL_CLEAR_RESERVATION | GENERAL_TOOL) {} bool is_selected() const OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Clear block reservation"); } bool init(player_t*) OVERRIDE; bool exit(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_transformer_t : public kartenboden_tool_t { private: bool is_powerline_available() const; public: tool_transformer_t() : kartenboden_tool_t(TOOL_TRANSFORMER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; image_id get_icon(player_t*) const OVERRIDE; bool init(player_t*) OVERRIDE; char const* check_pos(player_t*, koord3d) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE { return powerline_wt; } }; // default_string (optional) population,townhallname,rotation class tool_add_city_t : public kartenboden_tool_t { public: tool_add_city_t() : kartenboden_tool_t(TOOL_ADD_CITY | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return tooltip_with_price("Found new city", welt->get_settings().cst_found_city); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; // buy a house to protect it from renovating class tool_buy_house_t : public kartenboden_tool_t { public: tool_buy_house_t() : kartenboden_tool_t(TOOL_BUY_HOUSE | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Haus kaufen"); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /************** the following tools need a valid default_param ************************/ // step size by default_param class tool_change_city_size_t : public tool_t { public: tool_change_city_size_t() : tool_t(TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( atoi(default_param)>=0 ? "Grow city" : "Shrink city" ); } bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; // height change by default_param class tool_change_water_height_t : public tool_t { public: tool_change_water_height_t() : tool_t(TOOL_CHANGE_WATER_HEIGHT | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( atoi(default_param)>=0 ? "Increase water height" : "Decrease water height" ); } bool init(player_t*) OVERRIDE; image_id get_icon(player_t *player) const OVERRIDE { return (!env_t::networkmode || player->is_public_service()) ? icon : IMG_EMPTY; } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; // height change by default_param class tool_set_climate_t : public two_click_tool_t { public: tool_set_climate_t() : two_click_tool_t(TOOL_SET_CLIMATE | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_plant_tree_t : public kartenboden_tool_t { public: tool_plant_tree_t() : kartenboden_tool_t(TOOL_PLANT_TREE | GENERAL_TOOL) {} image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::get_num_trees() > 0 ? icon : IMG_EMPTY; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( "Plant tree" ); } bool init(player_t*) OVERRIDE; char const* move(player_t* const player, uint16 const b, koord3d const k) OVERRIDE; bool move_has_effects() const OVERRIDE { return true; } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_plant_groundobj_t : public kartenboden_tool_t { public: tool_plant_groundobj_t() : kartenboden_tool_t(TOOL_PLANT_GROUNDOBJ | GENERAL_TOOL) {} image_id get_icon(player_t *) const OVERRIDE { return groundobj_t::get_count() > 0 ? icon : IMG_EMPTY; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( "Plant groundobj" ); } bool init(player_t*) OVERRIDE; char const* move(player_t* const player, uint16 const b, koord3d const k) OVERRIDE; bool move_has_effects() const OVERRIDE { return true; } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* only called directly from schedule => no tooltip! * default_param must point to a schedule! */ class tool_schedule_add_t : public tool_t { public: tool_schedule_add_t() : tool_t(TOOL_SCHEDULE_ADD | GENERAL_TOOL) {} char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } // bool is_work_keeps_game_state() const OVERRIDE { return true; } bool is_work_here_keeps_game_state(player_t*, koord3d) OVERRIDE { return true; } }; class tool_schedule_ins_t : public tool_t { public: tool_schedule_ins_t() : tool_t(TOOL_SCHEDULE_INS | GENERAL_TOOL) {} char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } // bool is_work_keeps_game_state() const OVERRIDE { return true; } bool is_work_here_keeps_game_state(player_t*, koord3d) OVERRIDE { return true; } }; class tool_build_way_t : public two_click_tool_t { private: static const way_desc_t *defaults[17]; // default ways for all types char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; protected: const way_desc_t *desc; virtual way_desc_t const* get_desc(uint16 timeline_year_month) const; const char *calc_route( way_builder_t &bauigel, const koord3d &, const koord3d & ); void start_at( koord3d &new_start ) OVERRIDE; public: tool_build_way_t(uint16 const id = TOOL_BUILD_WAY | GENERAL_TOOL) : two_click_tool_t(id), desc() {} image_id get_icon(player_t*) const OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE; char const* get_default_param(player_t*) const OVERRIDE; bool is_selected() const OVERRIDE; bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; // remove preview necessary while building elevated ways bool remove_preview_necessary() const OVERRIDE { return !is_first_click() && (desc && (desc->get_styp() == type_elevated && desc->get_wtyp() != air_wt)); } }; class tool_build_cityroad : public tool_build_way_t { private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; public: tool_build_cityroad() : tool_build_way_t(TOOL_BUILD_CITYROAD | GENERAL_TOOL) {} way_desc_t const* get_desc(uint16) const OVERRIDE; image_id get_icon(player_t* const player) const OVERRIDE { return tool_t::get_icon(player); } bool is_selected() const OVERRIDE { return tool_t::is_selected(); } bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE { return road_wt; } }; class tool_build_bridge_t : public two_click_tool_t { private: ribi_t::ribi ribi; char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; public: tool_build_bridge_t() : two_click_tool_t(TOOL_BUILD_BRIDGE | GENERAL_TOOL) {} image_id get_icon(player_t*) const OVERRIDE { return grund_t::underground_mode==grund_t::ugm_all ? IMG_EMPTY : icon; } char const* get_tooltip(player_t const*) const OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; bool remove_preview_necessary() const OVERRIDE { return !is_first_click(); } void rdwr_custom_data(memory_rw_t*) OVERRIDE; bool init(player_t*) OVERRIDE; }; class tool_build_tunnel_t : public two_click_tool_t { private: void calc_route( way_builder_t &bauigel, const koord3d &, const koord3d &); char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; public: tool_build_tunnel_t() : two_click_tool_t(TOOL_BUILD_TUNNEL | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; char const* check_pos(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; bool remove_preview_necessary() const OVERRIDE { return !is_first_click(); } bool init(player_t*) OVERRIDE; }; class tool_wayremover_t : public two_click_tool_t { private: bool calc_route( route_t &, player_t *, const koord3d& start, const koord3d &to ); char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; // error message to be returned by calc_route const char *calc_route_error; public: tool_wayremover_t() : two_click_tool_t(TOOL_WAYREMOVER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; image_id get_icon(player_t*) const OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; }; class tool_build_wayobj_t : public two_click_tool_t { protected: const bool build; private: static const way_obj_desc_t *default_electric; const way_obj_desc_t *desc; const way_obj_desc_t *get_desc() const; waytype_t wt; bool calc_route( route_t &, player_t *, const koord3d& start, const koord3d &to ); char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; public: tool_build_wayobj_t(uint16 const id = TOOL_BUILD_WAYOBJ | GENERAL_TOOL, bool b = true) : two_click_tool_t(id), build(b) {} char const* get_tooltip(player_t const*) const OVERRIDE; bool is_selected() const OVERRIDE; bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; }; class tool_remove_wayobj_t : public tool_build_wayobj_t { public: tool_remove_wayobj_t() : tool_build_wayobj_t(TOOL_REMOVE_WAYOBJ | GENERAL_TOOL, false) {} image_id get_icon(player_t*) const OVERRIDE; bool is_selected() const OVERRIDE { return tool_t::is_selected(); } bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_build_station_t : public tool_t { private: const char *tool_station_building_aux(player_t *, bool, koord3d, const building_desc_t *, sint8 rotation ); const char *tool_station_dock_aux(player_t *, koord3d, const building_desc_t * ); const char *tool_station_flat_dock_aux(player_t *, koord3d, const building_desc_t *, sint8 ); const char *tool_station_aux(player_t *, koord3d, const building_desc_t *, sint8, waytype_t, const char *halt_suffix ); const building_desc_t *get_desc( sint8 &rotation ) const; public: tool_build_station_t() : tool_t(TOOL_BUILD_STATION | GENERAL_TOOL) {} bool move_has_effects() const OVERRIDE { return true; } image_id get_icon(player_t*) const OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE; bool init(player_t*) OVERRIDE; char const* check_pos(player_t*, koord3d) OVERRIDE; char const* move(player_t* const player, uint16 const b, koord3d const pos) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; }; class tool_rotate_building_t : public tool_t { private: const char *tool_rotate_platform(koord3d); const char *tool_rotate_building(koord3d); public: tool_rotate_building_t() : tool_t(TOOL_ROTATE_BUILDING | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Rotate Building"); } char const* work(player_t *, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /// builds roadsigns and signals class tool_build_roadsign_t : public two_click_tool_t { struct signal_info_t { uint8 spacing = 2; // place signals every n tiles bool remove_intermediate = true; bool replace_other = true; }; const roadsign_desc_t* desc = NULL; /// default values for this tool per player signal_info_t signal[MAX_PLAYER_COUNT]; /// values that will be used to build signal_info_t current; /// save direction of new signs vector_tpl directions; public: tool_build_roadsign_t(); public: /// @copydoc tool_t::get_tooltip const char *get_tooltip(const player_t *player) const OVERRIDE; /// @copydoc tool_t::init bool init(player_t*) OVERRIDE; /// @copydoc tool_t::exit bool exit(player_t*) OVERRIDE; /// Called by the GUI (gui/signal_spacing.*) void set_values(player_t *player, uint8 spacing, bool remove, bool replace); void get_values(player_t *player, uint8 &spacing, bool &remove, bool &replace); bool is_init_keeps_game_state() const OVERRIDE { return true; } void draw_after(scr_coord, bool dirty) const OVERRIDE; void rdwr_custom_data(memory_rw_t*) OVERRIDE; waytype_t get_waytype() const OVERRIDE; private: /// @copydoc two_click_tool_t::mark_tiles void mark_tiles(player_t *player, const koord3d &start, const koord3d &end) OVERRIDE; /// @copydoc two_click_tool_t::do_work const char *do_work(player_t *player, const koord3d &start, const koord3d &end) OVERRIDE; /// @copydoc two_click_tool_t::is_valid_pos uint8 is_valid_pos(player_t *player, const koord3d &builder, char const *&error, const koord3d &start) OVERRIDE; const char *check_pos_intern(player_t *, koord3d); const char *place_sign_intern(player_t *player, grund_t *gr); bool calc_route(route_t &route, player_t *player, const koord3d &from, const koord3d &to); }; class tool_build_depot_t : public tool_t { private: const char *tool_depot_aux(player_t *player, koord3d pos, const building_desc_t *desc, waytype_t wegtype); public: tool_build_depot_t() : tool_t(TOOL_BUILD_DEPOT | GENERAL_TOOL) {} image_id get_icon(player_t*) const OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE; bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } waytype_t get_waytype() const OVERRIDE; }; /** * builds (random) tourist attraction (default_param==NULL) and maybe adds it to the next city * the parameter string is a follow (or NULL): * 1#theater * first letter: ignore climates * second letter: rotation (0,1,2,3,#=random) * finally building name */ class tool_build_house_t : public kartenboden_tool_t { public: tool_build_house_t() : kartenboden_tool_t(TOOL_BUILD_HOUSE | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Built random attraction"); } bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /** * builds an (if param=NULL random) industry chain starting here * * the parameter string is a follow (or NULL): * 1#34,oelfeld * first letter: ignore climates * second letter: rotation (0,1,2,3,#=random) * next number is production value * finally industry name * NULL means random chain! */ class tool_build_land_chain_t : public kartenboden_tool_t { public: tool_build_land_chain_t() : kartenboden_tool_t(TOOL_BUILD_LAND_CHAIN | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Build land consumer"); } bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_city_chain_t : public kartenboden_tool_t { public: tool_city_chain_t() : kartenboden_tool_t(TOOL_CITY_CHAIN | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Build city market"); } bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_build_factory_t : public kartenboden_tool_t { public: tool_build_factory_t() : kartenboden_tool_t(TOOL_BUILD_FACTORY | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Build city market"); } bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; class tool_link_factory_t : public two_click_tool_t { public: tool_link_factory_t() : two_click_tool_t(TOOL_LINK_FACTORY | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Connect factory"); } bool is_init_keeps_game_state() const OVERRIDE { return true; } private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE {} uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; image_id get_marker_image() const OVERRIDE; }; class tool_headquarter_t : public kartenboden_tool_t { private: const building_desc_t *next_level( const player_t *player ) const; public: tool_headquarter_t() : kartenboden_tool_t(TOOL_HEADQUARTER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; bool init(player_t*) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* protects map from further change (here because two clicks to confirm it!) */ class tool_lock_game_t : public tool_t { public: tool_lock_game_t() : tool_t(TOOL_LOCK_GAME | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return env_t::networkmode ? translator::translate("deactivated in online mode") : translator::translate("Lock game"); } image_id get_icon(player_t*) const OVERRIDE { return env_t::networkmode ? IMG_EMPTY : icon; } // deactivate in network mode bool init(player_t *) OVERRIDE { return !env_t::networkmode; } const char *work( player_t *, koord3d ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* add random citycar if no default is set; else add a certain city car */ class tool_add_citycar_t : public tool_t { public: tool_add_citycar_t() : tool_t(TOOL_ADD_CITYCAR | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Add random citycar"); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* make forest */ class tool_forest_t : public two_click_tool_t { public: tool_forest_t() : two_click_tool_t(TOOL_FOREST | GENERAL_TOOL) {} image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Add forest"); } bool init( player_t *player) OVERRIDE { return tree_builder_t::has_trees() && two_click_tool_t::init(player); } private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* stop moving tool */ class tool_stop_mover_t : public two_click_tool_t { private: waytype_t waytype[2]; halthandle_t last_halt; public: tool_stop_mover_t() : two_click_tool_t(TOOL_STOP_MOVER | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("replace stop"); } bool is_init_keeps_game_state() const OVERRIDE { return true; } private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE {} uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; image_id get_marker_image() const OVERRIDE; void read_start_position(player_t *player, const koord3d &pos); }; /* make all tiles of this player a public stop * if this player is public, make all connected tiles a public stop */ class tool_make_stop_public_t : public tool_t { public: tool_make_stop_public_t() : tool_t(TOOL_MAKE_STOP_PUBLIC | GENERAL_TOOL) {} bool init(player_t * ) OVERRIDE; bool exit(player_t *s ) OVERRIDE { return init(s); } char const* get_tooltip(player_t const*) const OVERRIDE; char const* move(player_t*, uint16 /* buttonstate */, koord3d) OVERRIDE; bool move_has_effects() const OVERRIDE { return true; } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; /* merge stop */ class tool_merge_stop_t : public two_click_tool_t { private: halthandle_t halt_be_merged_from; halthandle_t halt_be_merged_to; public: tool_merge_stop_t() : two_click_tool_t(TOOL_MERGE_STOP | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("merge stop"); } bool is_init_keeps_game_state() const OVERRIDE { return true; } private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; image_id get_marker_image() const OVERRIDE; }; // removes signal from tile class tool_remove_signal_t : public tool_t { public: tool_remove_signal_t() : tool_t(TOOL_REMOVE_SIGNAL | GENERAL_TOOL) {} image_id get_icon(player_t*) const OVERRIDE; char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("remove signal"); } char const* work(player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } }; // saves the infrostructure of an area as a building script class tool_generate_script_t : public two_click_tool_t { public: tool_generate_script_t() : two_click_tool_t(TOOL_GENERATE_SCRIPT | GENERAL_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("generate script"); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool save_script(const char *fullpath, const char *command, koord area) const; private: char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE { return 3; }; }; // Copies item under cursor into cursor class tool_pipette_t : public tool_t { public: tool_pipette_t() : tool_t(TOOL_PIPETTE | GENERAL_TOOL) {} public: const char *get_tooltip(const player_t *) const OVERRIDE { return translator::translate("Pipette"); } const char *work(player_t *, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } private: const char* allow_tool_check(const obj_t* obj, const obj_desc_timelined_t* desc, const player_t* pl) const; }; // internal tool: show error message at specific coordinate // used for scenario error messages send by server class tool_error_message_t : public tool_t { public: tool_error_message_t() : tool_t(TOOL_ERROR_MESSAGE | GENERAL_TOOL) {} bool init(player_t*) OVERRIDE { return true; } bool is_init_keeps_game_state() const OVERRIDE { return true; } char const* work(player_t*, koord3d) OVERRIDE { return default_param ? default_param : ""; } }; /********************* one click tools ****************************/ class tool_pause_t : public tool_t { public: tool_pause_t() : tool_t(TOOL_PAUSE | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return env_t::networkmode ? translator::translate("deactivated in online mode") : translator::translate("Pause"); } image_id get_icon(player_t*) const OVERRIDE { return env_t::networkmode ? IMG_EMPTY : icon; } bool is_selected() const OVERRIDE { return welt->is_paused(); } bool init( player_t * ) OVERRIDE { if( !env_t::networkmode ) { welt->set_fast_forward(0); welt->set_pause( welt->is_paused()^1 ); } return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return !env_t::networkmode; } bool is_work_keeps_game_state() const OVERRIDE { return !env_t::networkmode; } }; class tool_fastforward_t : public tool_t { public: tool_fastforward_t() : tool_t(TOOL_FASTFORWARD | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return env_t::networkmode ? translator::translate("deactivated in online mode") : translator::translate("Fast forward"); } image_id get_icon(player_t*) const OVERRIDE { return env_t::networkmode ? IMG_EMPTY : icon; } bool is_selected() const OVERRIDE { return welt->is_fast_forward(); } bool init( player_t * ) OVERRIDE { if( !env_t::networkmode ) { if( welt->is_fast_forward() && env_t::simple_drawing_fast_forward ) { welt->set_dirty(); } welt->set_pause(0); welt->set_fast_forward( welt->is_fast_forward()^1 ); } return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return !env_t::networkmode; } bool is_work_keeps_game_state() const OVERRIDE { return !env_t::networkmode; } }; class tool_screenshot_t : public tool_t { public: tool_screenshot_t() : tool_t(TOOL_SCREENSHOT | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Screenshot"); } bool init(player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; // builds next chain class tool_increase_industry_t : public tool_t { public: tool_increase_industry_t() : tool_t(TOOL_INCREASE_INDUSTRY | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Increase Industry density"); } bool init( player_t * ) OVERRIDE; }; /* undo building */ class tool_undo_t : public tool_t { public: tool_undo_t() : tool_t(TOOL_UNDO | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Undo last ways construction"); } bool init(player_t *player ) OVERRIDE; }; /* switch to next player */ class tool_switch_player_t : public tool_t { public: tool_switch_player_t() : tool_t(TOOL_SWITCH_PLAYER | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Change player"); } bool init( player_t * ) OVERRIDE { welt->switch_active_player( welt->get_active_player_nr()+1, true ); return false; } // since it is handled internally bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; // step one year forward class tool_step_year_t : public tool_t { public: tool_step_year_t() : tool_t(TOOL_STEP_YEAR | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Step timeline one year"); } bool init( player_t *player ) OVERRIDE { if( !env_t::networkmode || player->is_public_service() ) { // in networkmode only for public player welt->step_year(); } return false; } }; class tool_change_game_speed_t : public tool_t { public: tool_change_game_speed_t() : tool_t(TOOL_CHANGE_GAME_SPEED | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { int factor = atoi(default_param); return factor>0 ? translator::translate("Accelerate time") : translator::translate("Deccelerate time"); } bool init( player_t *player ) OVERRIDE { if( !env_t::networkmode || player->is_public_service() ) { // in networkmode only for public player welt->change_time_multiplier( atoi(default_param) ); } return false; } }; class tool_zoom_in_t : public tool_t { public: tool_zoom_in_t() : tool_t(TOOL_ZOOM_IN | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("zooming in"); } bool init( player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_zoom_out_t : public tool_t { public: tool_zoom_out_t() : tool_t(TOOL_ZOOM_OUT | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("zooming out"); } bool init( player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_coverage_t : public tool_t { public: tool_show_coverage_t() : tool_t(TOOL_SHOW_COVERAGE | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("show station coverage"); } bool is_selected() const OVERRIDE { return env_t::station_coverage_show; } bool init( player_t * ) OVERRIDE { env_t::station_coverage_show = !env_t::station_coverage_show; welt->set_dirty(); return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_factory_storage_t : public tool_t { public: tool_show_factory_storage_t() : tool_t(TOOL_SHOW_FACTORY_STORAGE | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("switch the industry storage display mode"); } bool init(player_t *) OVERRIDE { env_t::show_factory_storage_bar = (env_t::show_factory_storage_bar+1) % 4; welt->set_dirty(); return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_name_t : public tool_t { public: tool_show_name_t() : tool_t(TOOL_SHOW_NAME | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( (env_t::show_names>>2)==2 ? "hide station names" : (env_t::show_names&1) ? "show waiting bars" : "show station names"); } bool init( player_t * ) OVERRIDE { if( env_t::show_names>=11 ) { if( (env_t::show_names&3)==3 ) { env_t::show_names = 0; } else { env_t::show_names = 2; } } else if( env_t::show_names==2 ) { env_t::show_names = 3; } else if( env_t::show_names==0 ) { env_t::show_names = 1; } else { env_t::show_names += 4; } welt->set_dirty(); return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_grid_t : public tool_t { public: tool_show_grid_t() : tool_t(TOOL_SHOW_GRID | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("show grid"); } bool is_selected() const OVERRIDE { return grund_t::show_grid; } bool init( player_t * ) OVERRIDE { grund_t::toggle_grid(); welt->set_dirty(); return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_trees_t : public tool_t { public: tool_show_trees_t() : tool_t(TOOL_SHOW_TREES | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("hide trees"); } bool is_selected() const OVERRIDE {return env_t::hide_trees; } bool init( player_t * ) OVERRIDE; bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_houses_t : public tool_t { public: tool_show_houses_t() : tool_t(TOOL_SHOW_HOUSES | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( env_t::hide_buildings==0 ? "hide city building" : (env_t::hide_buildings==1) ? "hide all building" : "show all building"); } bool is_selected() const OVERRIDE { return env_t::hide_buildings>0; } bool init( player_t * ) OVERRIDE { env_t::hide_buildings ++; if(env_t::hide_buildings>env_t::ALL_HIDDEN_BUILDING) { env_t::hide_buildings = env_t::NOT_HIDE; } welt->set_dirty(); return false; } bool exit(player_t* s) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_show_underground_t : public tool_t { public: tool_show_underground_t() : tool_t(TOOL_SHOW_UNDERGROUND | SIMPLE_TOOL) {} static sint8 save_underground_level; char const* get_tooltip(player_t const*) const OVERRIDE; bool is_selected() const OVERRIDE; void draw_after(scr_coord, bool dirty) const OVERRIDE; bool init(player_t *) OVERRIDE; char const* work(player_t*, koord3d) OVERRIDE; bool exit(player_t *) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_toggle_control_t : public tool_t { public: tool_toggle_control_t() : tool_t(TOOL_TOGGLE_CONTROL | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Lock Control key"); } bool is_selected() const OVERRIDE { return tool_t::control_invert; } bool init(player_t*) OVERRIDE { tool_t::control_invert = WFL_CTRL; return false; } bool exit(player_t *) OVERRIDE { tool_t::control_invert = 0; return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_load_scenario_t : public tool_t { // internal tool to start a scenario // command i.filename // if i==1, start as easyserver public: tool_load_scenario_t() : tool_t(TOOL_LOAD_SCENARIO | SIMPLE_TOOL) { flags = WFL_LOCAL | WFL_NO_CHK; } bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } bool is_work_keeps_game_state() const OVERRIDE { return false; } }; class tool_rotate90_t : public tool_t { public: tool_rotate90_t() : tool_t(TOOL_ROTATE90 | SIMPLE_TOOL) {} image_id get_icon(player_t*) const OVERRIDE { return env_t::networkmode ? IMG_EMPTY : icon; } void draw_after(scr_coord pos, bool dirty) const OVERRIDE; /* may draw a compass on top */ char const* get_tooltip(player_t const*) const OVERRIDE { return env_t::networkmode ? translator::translate("deactivated in online mode") : translator::translate("Rotate map"); } bool init( player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } bool is_work_keeps_game_state() const OVERRIDE { return false; } }; class tool_quit_t : public tool_t { // default_parameter not empty: start new game public: tool_quit_t() : tool_t(TOOL_QUIT | SIMPLE_TOOL) { flags = WFL_LOCAL | WFL_NO_CHK; } char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate( (default_param && *default_param) ? "Neue Welt" : "Beenden"); } bool init( player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } bool is_work_keeps_game_state() const OVERRIDE { return false; } }; // step size by default_param class tool_fill_trees_t : public tool_t { public: tool_fill_trees_t() : tool_t(TOOL_FILL_TREES | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Fill trees"); } image_id get_icon(player_t *) const OVERRIDE { return tree_builder_t::has_trees() ? icon : IMG_EMPTY; } bool init(player_t * ) OVERRIDE { if( tree_builder_t::has_trees() && default_param ) { tree_builder_t::fill_trees( atoi(default_param), 0, 0, welt->get_size().x, welt->get_size().y ); } return false; } }; /* change day/night view manually */ class tool_daynight_level_t : public tool_t { public: tool_daynight_level_t() : tool_t(TOOL_DAYNIGHT_LEVEL | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE; bool init(player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_vehicle_tooltips_t : public tool_t { public: tool_vehicle_tooltips_t() : tool_t(TOOL_VEHICLE_TOOLTIPS | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Toggle vehicle tooltips"); } bool init( player_t * ) OVERRIDE { env_t::show_vehicle_states = (env_t::show_vehicle_states+1)%4; welt->set_dirty(); return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_toggle_pax_station_t : public tool_t { public: tool_toggle_pax_station_t() : tool_t(TOOL_TOOGLE_PAX | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("5LIGHT_CHOOSE"); } bool is_selected() const OVERRIDE { return env_t::stop_pedestrians; } bool init( player_t * ) OVERRIDE { env_t::stop_pedestrians = !env_t::stop_pedestrians; return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_toggle_pedestrians_t : public tool_t { public: tool_toggle_pedestrians_t() : tool_t(TOOL_TOOGLE_PEDESTRIANS | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("6LIGHT_CHOOSE"); } bool is_selected() const OVERRIDE { return env_t::random_pedestrians; } bool init( player_t * ) OVERRIDE { env_t::random_pedestrians = !env_t::random_pedestrians; return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_toggle_reservation_t : public tool_t { public: tool_toggle_reservation_t() : tool_t(TOOL_TOGGLE_RESERVATION | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("show/hide block reservations"); } bool is_selected() const OVERRIDE; bool init( player_t * ) OVERRIDE { schiene_t::show_reservations ^= 1; welt->set_dirty(); return false; } bool exit(player_t* s) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_view_owner_t : public tool_t { public: tool_view_owner_t() : tool_t(TOOL_VIEW_OWNER | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("show/hide object owner"); } bool is_selected() const OVERRIDE { return obj_t::show_owner; } bool init( player_t * ) OVERRIDE { obj_t::show_owner ^= 1; welt->set_dirty(); return false; } bool exit(player_t* s) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_hide_under_cursor_t : public tool_t { public: tool_hide_under_cursor_t() : tool_t(TOOL_HIDE_UNDER_CURSOR | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("hide objects under cursor"); } bool is_selected() const OVERRIDE { return env_t::hide_under_cursor; } bool init( player_t * ) OVERRIDE { env_t::hide_under_cursor = !env_t::hide_under_cursor && env_t::cursor_hide_range>0; welt->set_dirty(); return false; } bool exit(player_t *s ) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_move_map_t : public tool_t { public: tool_move_map_t() : tool_t(TOOL_MOVE_MAP | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Move the map"); } bool is_selected() const OVERRIDE { return false; } bool init( player_t * ) OVERRIDE { assert( default_param ); if( const char *c = strchr( default_param, '|' ) ) { koord delta( atoi( default_param ), atoi( c+1 ) ); welt->get_viewport()->change_world_position(welt->get_viewport()->get_world_position() + delta); welt->set_dirty(); } return false; } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; class tool_rollup_all_win_t : public tool_t { public: tool_rollup_all_win_t() : tool_t(TOOL_ROLLUP_ALL_WIN | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Hide/open all windows"); } bool is_selected() const OVERRIDE { return false; } bool init( player_t * ) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; // on off of night mode class tool_day_night_toggle_t : public tool_t { public: tool_day_night_toggle_t() : tool_t(TOOL_DAY_NIGHT_TOGGLE | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("8WORLD_CHOOSE"); } bool is_selected() const OVERRIDE { return env_t::night_shift; } bool init(player_t*) OVERRIDE { env_t::night_shift = !env_t::night_shift; welt->set_dirty(); return false; } bool exit(player_t* s) OVERRIDE { return init(s); } bool is_init_keeps_game_state() const OVERRIDE { return true; } bool is_work_keeps_game_state() const OVERRIDE { return true; } }; /******************************** Internal tools ***********/ /* internal simple tools needed for network synchronisation */ class tool_traffic_level_t : public tool_t { public: tool_traffic_level_t() : tool_t(TOOL_TRAFFIC_LEVEL | SIMPLE_TOOL) {} char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("6WORLD_CHOOSE"); } bool is_selected() const OVERRIDE { return false; } bool init( player_t * ) OVERRIDE { assert( default_param ); sint16 level = clamp(atoi(default_param), 0, 16); welt->get_settings().set_traffic_level(level); return false; } bool is_init_keeps_game_state() const OVERRIDE { return false; } }; class tool_change_convoi_t : public tool_t { public: tool_change_convoi_t() : tool_t(TOOL_CHANGE_CONVOI | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; class tool_change_line_t : public tool_t { public: tool_change_line_t() : tool_t(TOOL_CHANGE_LINE | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; class tool_change_depot_t : public tool_t { public: tool_change_depot_t() : tool_t(TOOL_CHANGE_DEPOT | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; // adds a new player of certain type to the map class tool_change_player_t : public tool_t { public: tool_change_player_t() : tool_t(TOOL_CHANGE_PLAYER | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; }; // change timing of traffic light class tool_change_traffic_light_t : public tool_t { public: tool_change_traffic_light_t() : tool_t(TOOL_CHANGE_TRAFFIC_LIGHT | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; // change city: (dis)allow growth class tool_change_city_t : public tool_t { public: tool_change_city_t() : tool_t(TOOL_CHANGE_CITY | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; // internal tool: rename stuff class tool_rename_t : public tool_t { public: tool_rename_t() : tool_t(TOOL_RENAME | SIMPLE_TOOL) {} bool init(player_t*) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return false; } }; // internal tool: change player colours class tool_recolour_t : public tool_t { public: tool_recolour_t() : tool_t(TOOL_RECOLOUR_TOOL | SIMPLE_TOOL) {} virtual bool init(player_t * ) OVERRIDE; virtual bool is_init_network_save() const { return false; } }; // internal tool: send message, with additional coordinate information class tool_add_message_t : public tool_t { public: tool_add_message_t() : tool_t(TOOL_ADD_MESSAGE | GENERAL_TOOL) {} const char *work( player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } // work is not safe, has to be send over network }; // internal tool: rename stuff class tool_change_owner_t : public tool_t { public: tool_change_owner_t() : tool_t(TOOL_SET_OWNER | GENERAL_TOOL) {} const char *work( player_t*, koord3d) OVERRIDE; bool is_init_keeps_game_state() const OVERRIDE { return true; } // work is not safe, has to be send over network }; #endif simutrans-124.3/src/simutrans/tpl/000077500000000000000000000000001474050137200171665ustar00rootroot00000000000000simutrans-124.3/src/simutrans/tpl/array2d_tpl.h000066400000000000000000000057341474050137200215730ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_ARRAY2D_TPL_H #define TPL_ARRAY2D_TPL_H #include #include #include "../dataobj/koord.h" #include "../simdebug.h" /** * A template class for bounds checked 2-dimensional arrays. * This is kept as simple as possible. Does not use exceptions * for error handling. */ template class array2d_tpl { private: T* data; unsigned w, h; public: array2d_tpl(unsigned _w, unsigned _h) : w(_w), h(_h) { data = new T[w*h]; } array2d_tpl(const array2d_tpl &other) { w = other.w; h = other.h; data = new T[w*h]; memcpy(data, other.data, sizeof(T)*w*h); } ~array2d_tpl() { delete [] data; } unsigned get_width() const { return w; } unsigned get_height() const { return h; } void clear() { delete [] data; data = 0; w = h = 0; } void init( T value ) { if(sizeof(T)==1) { memset( data, value, w*h ); } else { unsigned i=(w*h); while( i>0 ) { data[--i] = value; } } } // all informations in the array are lost void resize(unsigned resize_x, unsigned resize_y ) { if( w*h != resize_x*resize_y ) { T* new_data = new T[resize_x*resize_y]; delete [] data; data = new_data; } w = resize_x; h = resize_y; } void rotate90() { if( w*h > 0 ) { T *new_data = new T[w*h]; for( unsigned y=0; yfatal("array2d_tpl::at()","index out of bounds: (%d,%d) not in (0..%d, 0..%d)", x, y, w-1, h-1); } return data[y*w + x]; } T& at(koord k) { return at((unsigned)k.x, (unsigned)k.y); } /* * use this with care, you'll lose all checks! */ const T* to_array() const { return data; } array2d_tpl & operator = (const array2d_tpl &other) { if( this != &other ) {// protect against invalid self-assignment if( h != other.h && w != other.w ) { if( h*w!=0 ) { dbg->error("array2d_tpl::=()","source has different size!"); } } delete [] data; w = other.w; h = other.h; data = new T[w*h]; memcpy(data, other.data, sizeof(T)*w*h); } return *this; } }; #endif simutrans-124.3/src/simutrans/tpl/array_tpl.h000066400000000000000000000041721474050137200213400ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_ARRAY_TPL_H #define TPL_ARRAY_TPL_H #include #include "../simdebug.h" #include "../simtypes.h" /** * A template class for bounds checked 1-dimensional arrays. * This is kept as simple as possible. Does not use exceptions * for error handling. */ template class array_tpl { public: typedef const T* const_iterator; typedef T* iterator; typedef uint32 index; explicit array_tpl() : data(NULL), size(0) {} explicit array_tpl(index s) : data(new T[s]), size(s) {} explicit array_tpl(index s, const T& value) : data(new T[s]), size(s) { for (index i = 0; i < size; i++) { data[i] = value; } } ~array_tpl() { delete [] data; } index get_count() const { return size; } bool empty() const { return size == 0; } void clear() { delete [] data; data = 0; size = 0; } void resize(index resize) { if (size < resize) { // extend if needed T* new_data = new T[resize]; for (index i = 0; i < size; i++) { new_data[i] = data[i]; } delete [] data; data = new_data; } size = resize; } void resize(index resize, const T& value) { if (size < resize) { T* new_data = new T[resize]; index i; for (i = 0; i < size; i++) { new_data[i] = data[i]; } for (; i < resize; i++) { new_data[i] = value; } delete [] data; data = new_data; size = resize; } } T& operator [](index i) { if (i >= size) { dbg->fatal("array_tpl::[]", "index out of bounds: %d not in 0..%d, T=%s", i, size - 1, typeid(T).name()); } return data[i]; } const T& operator [](index i) const { if (i >= size) { dbg->fatal("array_tpl::[]", "index out of bounds: %d not in 0..%d, T=%s", i, size - 1, typeid(T).name()); } return data[i]; } iterator begin() { return data; } iterator end() { return data + size; } const_iterator begin() const { return data; } const_iterator end() const { return data + size; } private: array_tpl(const array_tpl&); array_tpl& operator=( array_tpl const& other ); T* data; index size; }; #endif simutrans-124.3/src/simutrans/tpl/binary_heap_tpl.h000066400000000000000000000053401474050137200225010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_BINARY_HEAP_TPL_H #define TPL_BINARY_HEAP_TPL_H #include "../simmem.h" #include "../simtypes.h" /** * my try on a binary heap template, * inspired by the pathfinder of OTTD written by kuDr * * For information about Binary Heap algorithm, * see: https://en.wikipedia.org/wiki/Binary_heap */ template class binary_heap_tpl { private: T *nodes; public: uint32 node_count; uint32 node_size; binary_heap_tpl(uint32 size = 4096) { nodes = MALLOCN(T, size); node_size = size; node_count = 0; } ~binary_heap_tpl() { free( nodes ); } /** * Inserts an element into the queue. * in such a way that the lowest is at the top of this tree in an array * parts inspired from OTTD */ void insert(const T item) { node_count ++; // need to enlarge? (must be 2^x) if(node_count==node_size) { T *tmp=nodes; node_size *= 2; nodes = MALLOCN(T, node_size); memcpy( nodes, tmp, sizeof(T)*(node_size/2) ); free( tmp ); } // now we have to move it to the right position int gap = node_count; for (int parent = gap/2; (parent>0) && (*item <= *nodes[parent]); ) { nodes[gap] = nodes[parent]; gap = parent; parent /= 2; } nodes[gap] = item; } /** * unfortunately, the removing is as much effort as the insertion ... */ T pop() { assert(!empty()); T result = nodes[1]; // at index 1 is the lowest one uint32 gap = 1; // this is the last one T item = nodes[node_count--]; // now we must maintain relation between parent and its children: // parent <= any child // from head down to the tail uint32 child = 2; // first child is at [parent * 2] // while children are valid while(child<=node_count) { // choose the smaller child if( child we are done break; } // if smaller child is smaller than parent, it will become new parent nodes[gap] = nodes[child]; gap = child; // where do we have our new children? child = gap * 2; } // move last item to the proper place if (node_count>0) { nodes[gap] = item; } return result; } /** * Recycles all nodes. Doesn't delete the objects. * Leaves the list empty. */ void clear() { node_count = 0; } uint32 get_count() const { return node_count; } bool empty() const { return node_count == 0; } const T& front() { assert(!empty()); return nodes[1]; } private: binary_heap_tpl(const binary_heap_tpl& other); binary_heap_tpl& operator=( binary_heap_tpl const& other ); }; #endif simutrans-124.3/src/simutrans/tpl/freelist_iter_tpl.h000066400000000000000000000152441474050137200230640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_FREELIST_ITER_TPL_H #define TPL_FREELIST_ITER_TPL_H #include "../simmem.h" #include "../simconst.h" #include #include #ifdef MULTI_THREADx #include "../utils/simthread.h" #endif // define USE_VALGRIND_MEMCHECK to make // valgrind aware of the freelist memory pool #ifdef USE_VALGRIND_MEMCHECK #include #endif /** * A template class for const sized memory pool * Must be a static member! Does not use exceptions */ template class freelist_iter_tpl { private: struct nodelist_node_t { #ifdef DEBUG_FREELIST char canary[4]; #endif nodelist_node_t* next; }; const char *canary_free = "\xAA\x55\xAA"; const char *canary_used = "\x55\xAA\x55"; #ifdef MULTI_THREADx pthread_mutex_t freelist_mutex = PTHREAD_MUTEX_INITIALIZER;; #endif // next free node (or NULL) nodelist_node_t* freelist; // number of currently allocated node size_t nodecount; // we aim for near 32 kB chunks, hoping that the system will allocate them on each page // and they fit the L1 cache static constexpr size_t NODE_SIZE = (sizeof(T) + sizeof(nodelist_node_t)-sizeof(nodelist_node_t *)); static constexpr size_t new_chuck_size = (32250*8) / (NODE_SIZE*8+1); struct chunklist_node_t { chunklist_node_t *chunk_next; // marking empty and allocated tiles for fast interation std::bitset<(32250*8) / (NODE_SIZE*8+1)> allocated_mask; }; // list of all allocated memory chunklist_node_t* chunk_list; void change_obj(char *p,bool b) { char *c_list = (char *)chunk_list; const size_t chunk_mem_size = sizeof(chunklist_node_t) + (NODE_SIZE * new_chuck_size); while (c_list && (p continue c_list = (char *)((chunklist_node_t *)c_list)->chunk_next; } // we have found us (or we crash on error) size_t index = ((p - c_list) - sizeof(chunklist_node_t)) / NODE_SIZE; assert(index < new_chuck_size); ((chunklist_node_t*)c_list)->allocated_mask.set(index, b); } // clears all list memories void free_all_nodes() { while (chunk_list) { chunklist_node_t* p = chunk_list; chunk_list = chunk_list->chunk_next; // now release memory #ifdef USE_VALGRIND_MEMCHECK VALGRIND_DESTROY_MEMPOOL(p); #endif free(p); } freelist = 0; chunk_list = 0; nodecount = 0; } public: freelist_iter_tpl() : freelist(0), nodecount(0), chunk_list(0) {} void sync_step(uint32 delta_t) { chunklist_node_t* c_list = chunk_list; while (c_list) { char *p = ((char *)c_list)+sizeof(chunklist_node_t); for (unsigned i = 0; i < new_chuck_size; i++) { if (c_list->allocated_mask.test(i)) { // is active object T *obj = (T *)&(((nodelist_node_t*)(p + (i * NODE_SIZE)))->next); if (sync_result result = obj->sync_step(delta_t)) { // remove from sync c_list->allocated_mask.set(i, false); // and maybe delete if (result == SYNC_DELETE) { delete obj; if (nodecount == 0) { return; // since even the main chunk list became invalid } } } } } c_list = c_list->chunk_next; } } // switch on off sync handling void add_sync(T* p) { change_obj((char*)p,true); }; void remove_sync(T* p) { change_obj((char*)p,false); }; size_t get_nodecout() const { return nodecount; } void *gimme_node() { #ifdef MULTI_THREADx pthread_mutex_lock(&freelist_mutex); #endif nodelist_node_t *tmp; if (freelist == NULL) { char* p = (char*)xmalloc(new_chuck_size*NODE_SIZE + sizeof(chunklist_node_t)); memset(p, 0, sizeof(chunklist_node_t)); // clear allocation bits and next pointer #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we still cannot access the pool p VALGRIND_MAKE_MEM_NOACCESS(p, new_chuck_size * sizeof(T) + sizeof(chunklist_node_t)); #endif // put the memory into the chunklist for free it chunklist_node_t* chunk = (chunklist_node_t *)p; #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we reserved space for one nodelist_node_t VALGRIND_CREATE_MEMPOOL(chunk, 0, false); VALGRIND_MEMPOOL_ALLOC(chunk, chunk, sizeof(*chunk)); VALGRIND_MAKE_MEM_DEFINED(chunk, sizeof(*chunk)); #endif chunk->chunk_next = chunk_list; chunk_list = chunk; p += sizeof(chunklist_node_t); // then enter nodes into nodelist for (size_t i = 0; i < new_chuck_size; i++) { nodelist_node_t* tmp = (nodelist_node_t*)(p + i * NODE_SIZE); #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we reserved space for one nodelist_node_t VALGRIND_CREATE_MEMPOOL(tmp, 0, false); VALGRIND_MEMPOOL_ALLOC(tmp, tmp, sizeof(*tmp)); VALGRIND_MAKE_MEM_UNDEFINED(tmp, sizeof(*tmp)); #endif #ifdef DEBUG_FREELIST tmp->canary[0] = canary_free[0]; tmp->canary[1] = canary_free[1]; tmp->canary[2] = canary_free[2]; tmp->canary[3] = sizeof(T); #endif tmp->next = freelist; freelist = tmp; } } // return first node of list tmp = freelist; freelist = tmp->next; change_obj((char *)(&(tmp->next)),true); #ifdef MULTI_THREADx pthread_mutex_unlock(&freelist_mutex); #endif #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we now have access to a chunk of size bytes VALGRIND_MEMPOOL_CHANGE(tmp, tmp, tmp, sizeof(T)); VALGRIND_MAKE_MEM_UNDEFINED(tmp, sizeof(T)); #endif #ifdef DEBUG_FREELIST assert(tmp->canary[0] == canary_free[0] && tmp->canary[1] == canary_free[1] && tmp->canary[2] == canary_free[2] && tmp->canary[3] == sizeof(T)); tmp->canary[0] = canary_used[0]; tmp->canary[1] = canary_used[1]; tmp->canary[2] = canary_used[2]; #endif nodecount++; return (void *)(&(tmp->next)); } void putback_node(void* p) { #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we keep access to a nodelist_node_t within the memory chunk VALGRIND_MEMPOOL_CHANGE(p, p, p, sizeof(nodelist_node_t)); VALGRIND_MAKE_MEM_NOACCESS(p, sizeof(T)); VALGRIND_MAKE_MEM_UNDEFINED(p, sizeof(nodelist_node_t)); #endif #ifdef MULTI_THREADx pthread_mutex_unlock(&freelist_mutex); #endif // putback to first node nodelist_node_t* tmp = (nodelist_node_t*)p; #ifdef DEBUG_FREELIST size_t min_size = sizeof(nodelist_node_t) - sizeof(void*); tmp = (nodelist_node_t*)((char*)p - min_size); assert(tmp->canary[0] == canary_used[0] && tmp->canary[1] == canary_used[1] && tmp->canary[2] == canary_used[2] && tmp->canary[3] == sizeof(T)); tmp->canary[0] = canary_free[0]; tmp->canary[1] = canary_free[1]; tmp->canary[2] = canary_free[2]; #endif tmp->next = freelist; freelist = tmp; change_obj((char *)p,0); nodecount--; if (nodecount == 0) { free_all_nodes(); } #ifdef MULTI_THREADx pthread_mutex_unlock(&freelist_mutex); #endif } }; #undef NODE_SIZE #endif simutrans-124.3/src/simutrans/tpl/freelist_tpl.h000066400000000000000000000121451474050137200220360ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_FREELIST_TPL_H #define TPL_FREELIST_TPL_H #include #include "../simmem.h" #include "../simdebug.h" #include "../simconst.h" #ifdef MULTI_THREAD #include "../utils/simthread.h" #endif // define USE_VALGRIND_MEMCHECK to make // valgrind aware of the freelist memory pool #ifdef USE_VALGRIND_MEMCHECK #include #endif /** * A template class for const sized memory pool * Must be a static member! Does not use exceptions */ class freelist_size_t { private: struct nodelist_node_t { #ifdef DEBUG_FREELIST char canary[4]; #endif nodelist_node_t* next; }; char canary_free[4] = "\xAA\x55\xAA"; char canary_used[4] = "\x55\xAA\x55"; size_t NODE_SIZE; size_t new_chuck_size; // next free node (or NULL) nodelist_node_t* freelist; // number of currently allocated node size_t nodecount; // list of all allocated memory nodelist_node_t* chunk_list; #ifdef MULTI_THREAD pthread_mutex_t freelist_mutex = PTHREAD_MUTEX_INITIALIZER;; #endif public: freelist_size_t(size_t size) : freelist(0), nodecount(0), chunk_list(0) { NODE_SIZE = (size + sizeof(nodelist_node_t) - sizeof(nodelist_node_t*)); new_chuck_size = ((32768 - sizeof(void*)) / NODE_SIZE); canary_free[3] = canary_used[3] = NODE_SIZE; } ~freelist_size_t() { free_all_nodes(); } void *gimme_node() { #ifdef MULTI_THREAD pthread_mutex_lock(&freelist_mutex); #endif nodelist_node_t *tmp; if (freelist == NULL) { char* p = (char*)xmalloc(new_chuck_size*NODE_SIZE + sizeof(nodelist_node_t)); #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we still cannot access the pool p VALGRIND_MAKE_MEM_NOACCESS(p, chunksize *sizeof(T) + sizeof(nodelist_node_t)); #endif // put the memory into the chunklist for free it nodelist_node_t* chunk = (nodelist_node_t *)p; #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we reserved space for one nodelist_node_t VALGRIND_CREATE_MEMPOOL(chunk, 0, false); VALGRIND_MEMPOOL_ALLOC(chunk, chunk, sizeof(*chunk)); VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(*chunk)); #endif chunk->next = chunk_list; chunk_list = chunk; p += sizeof(nodelist_node_t); // then enter nodes into nodelist for (size_t i = 0; i < new_chuck_size; i++) { nodelist_node_t* tmp = (nodelist_node_t*)(p + i*NODE_SIZE); #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we reserved space for one nodelist_node_t VALGRIND_CREATE_MEMPOOL(tmp, 0, false); VALGRIND_MEMPOOL_ALLOC(tmp, tmp, sizeof(*tmp)); VALGRIND_MAKE_MEM_UNDEFINED(tmp, sizeof(*tmp)); #endif #ifdef DEBUG_FREELIST tmp->canary[0] = canary_free[0]; tmp->canary[1] = canary_free[1]; tmp->canary[2] = canary_free[2]; tmp->canary[3] = canary_free[3]; #endif tmp->next = freelist; freelist = tmp; } } // return first node of list tmp = freelist; freelist = tmp->next; #ifdef DEBUG_FREELIST assert(tmp->canary[0] == canary_free[0] && tmp->canary[1] == canary_free[1] && tmp->canary[2] == canary_free[2] && tmp->canary[3] == canary_free[3]); tmp->canary[0] = canary_used[0]; tmp->canary[1] = canary_used[1]; tmp->canary[2] = canary_used[2]; #endif nodecount++; #ifdef MULTI_THREAD pthread_mutex_unlock(&freelist_mutex); #endif #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we now have access to a chunk of size bytes VALGRIND_MEMPOOL_CHANGE(tmp, tmp, tmp, sizeof(T)); VALGRIND_MAKE_MEM_UNDEFINED(tmp, sizeof(T)); #endif return (void *)(&(tmp->next)); } // clears all list memories void free_all_nodes() { while (chunk_list) { nodelist_node_t* p = chunk_list; chunk_list = chunk_list->next; // now release memory #ifdef USE_VALGRIND_MEMCHECK VALGRIND_DESTROY_MEMPOOL(p); #endif free(p); } freelist = 0; nodecount = 0; } void putback_node(void* p) { #ifdef USE_VALGRIND_MEMCHECK // tell valgrind that we keep access to a nodelist_node_t within the memory chunk VALGRIND_MEMPOOL_CHANGE(p, p, p, sizeof(nodelist_node_t)); VALGRIND_MAKE_MEM_NOACCESS(p, sizeof(T)); VALGRIND_MAKE_MEM_UNDEFINED(p, sizeof(nodelist_node_t)); #endif #ifdef MULTI_THREAD pthread_mutex_unlock(&freelist_mutex); #endif // putback to first node nodelist_node_t* tmp = (nodelist_node_t*)p; #ifdef DEBUG_FREELIST size_t min_size = sizeof(nodelist_node_t) - sizeof(void*); tmp = (nodelist_node_t*)((char*)p - min_size); assert(tmp->canary[0] == canary_used[0] && tmp->canary[1] == canary_used[1] && tmp->canary[2] == canary_used[2] && tmp->canary[3] == canary_used[3]); tmp->canary[0] = canary_free[0]; tmp->canary[1] = canary_free[1]; tmp->canary[2] = canary_free[2]; #endif tmp->next = freelist; freelist = tmp; nodecount--; if (nodecount == 0) { free_all_nodes(); } #ifdef MULTI_THREAD pthread_mutex_unlock(&freelist_mutex); #endif } }; template class freelist_tpl { private: freelist_size_t fli; public: freelist_tpl() : fli(sizeof(T)) {} T *gimme_node() { return (T *)fli.gimme_node(); } void putback_node(void* p) { return fli.putback_node(p); } void free_all_nodes() { fli.free_all_nodes(); } }; #endif simutrans-124.3/src/simutrans/tpl/hashtable_tpl.h000066400000000000000000000223261474050137200221560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_HASHTABLE_TPL_H #define TPL_HASHTABLE_TPL_H #include "slist_tpl.h" #include "../macros.h" #define STHT_BAGSIZE 101 #define STHT_BAG_COUNTER_T uint8 /* * Generic hashtable, which maps key_t to value_t. key_t depended functions * like the hash generation is implemented by the third template parameter * hash_t (see ifc/hash_tpl.h) */ template class hashtable_tpl { protected: struct node_t { public: key_t key; value_t value; int operator == (const node_t &x) const { return key == x.key; } }; // the entires in the lists are sorted according to their keys slist_tpl bags[STHT_BAGSIZE]; uint32 count; /* * assigning hashtables seems also not sound */ private: hashtable_tpl(const hashtable_tpl&); hashtable_tpl& operator=( hashtable_tpl const&); public: hashtable_tpl() { count = 0; } public: STHT_BAG_COUNTER_T get_hash(const key_t key) const { return (STHT_BAG_COUNTER_T)(hash_t::hash(key) % STHT_BAGSIZE); } class iterator { friend class hashtable_tpl; public: typedef std::forward_iterator_tag iterator_category; typedef node_t value_type; typedef ptrdiff_t difference_type; typedef node_t* pointer; typedef node_t& reference; iterator() : bag_i(), bag_end(), node_i() {} iterator(slist_tpl* const bag_i, slist_tpl* const bag_end, typename slist_tpl::iterator const& node_i) : bag_i(bag_i), bag_end(bag_end), node_i(node_i) {} pointer operator ->() const { return &*node_i; } reference operator *() const { return *node_i; } iterator& operator ++() { if (++node_i == bag_i->end()) { for (;;) { if (++bag_i == bag_end) { node_i = typename slist_tpl::iterator(); break; } if (!bag_i->empty()) { node_i = bag_i->begin(); break; } } } return *this; } bool operator ==(iterator const& o) const { return bag_i == o.bag_i && node_i == o.node_i; } bool operator !=(iterator const& o) const { return !(*this == o); } private: slist_tpl* bag_i; slist_tpl* bag_end; typename slist_tpl::iterator node_i; }; /* Erase element at pos * pos is invalid after this method * An iterator pointing to the successor of the erased element is returned */ iterator erase(iterator old) { iterator pos(old); pos.bag_end = old.bag_end; pos.bag_i = old.bag_i; pos.node_i = old.bag_i->erase( old.node_i ); if( pos.node_i == pos.bag_i->end() ) { for (;;) { if (++pos.bag_i == pos.bag_end) { pos.node_i = typename slist_tpl::iterator(); break; } if (!pos.bag_i->empty()) { pos.node_i = pos.bag_i->begin(); break; } } } count --; return pos; } class const_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef node_t value_type; typedef ptrdiff_t difference_type; typedef node_t const* pointer; typedef node_t const& reference; const_iterator() : bag_i(), bag_end(), node_i() {} const_iterator(slist_tpl const* const bag_i, slist_tpl const* const bag_end, typename slist_tpl::const_iterator const& node_i) : bag_i(bag_i), bag_end(bag_end), node_i(node_i) {} pointer operator ->() const { return &*node_i; } reference operator *() const { return *node_i; } const_iterator& operator ++() { if (++node_i == bag_i->end()) { for (;;) { if (++bag_i == bag_end) { node_i = typename slist_tpl::const_iterator(); break; } if (!bag_i->empty()) { node_i = bag_i->begin(); break; } } } return *this; } bool operator ==(const_iterator const& o) const { return bag_i == o.bag_i && node_i == o.node_i; } bool operator !=(const_iterator const& o) const { return !(*this == o); } private: slist_tpl const* bag_i; slist_tpl const* bag_end; typename slist_tpl::const_iterator node_i; }; iterator begin() { for (slist_tpl* i = bags; i != endof(bags); ++i) { if (!i->empty()) { return iterator(i, endof(bags), i->begin()); } } return end(); } iterator end() { return iterator(endof(bags), endof(bags), typename slist_tpl::iterator()); } const_iterator begin() const { for (slist_tpl const* i = bags; i != endof(bags); ++i) { if (!i->empty()) { return const_iterator(i, endof(bags), i->begin()); } } return end(); } const_iterator end() const { return const_iterator(endof(bags), endof(bags), typename slist_tpl::iterator()); } void clear() { for(STHT_BAG_COUNTER_T i=0; i faster retrieval (we only have to check half of the lists) const value_t &get(const key_t key) const { static value_t nix; for(auto const& node : bags[get_hash(key)]) { typename hash_t::diff_type diff = hash_t::comp(node.key, key); if( diff == 0 ) { return node.value; } if( diff > 0 ) { // not contained break; } } return nix; } // the elements are inserted with increasing key // => faster retrieval, but never ever change a key later!!! value_t *access(const key_t key) { slist_tpl& bag = bags[get_hash(key)]; for(auto & node : bag) { typename hash_t::diff_type diff = hash_t::comp(node.key, key); if( diff == 0 ) { return &node.value; } if( diff > 0 ) { // not contained break; } } return NULL; } /// Inserts a new value - failure if key exists in table bool put(const key_t key, value_t object) { slist_tpl& bag = bags[get_hash(key)]; /* Duplicate values are hard to debug, so better check here. * we also enter it sorted, saving lookout time for large lists ... */ for( typename slist_tpl::iterator iter = bag.begin(), end = bag.end(); iter != end; ++iter ) { typename hash_t::diff_type diff = hash_t::comp(iter->key, key); if( diff>0 ) { node_t n; n.key = key; n.value = object; bag.insert( iter, n ); count ++; return true; } if( diff == 0 ) { dbg->error( "hashtable_tpl::put", "Duplicate hash!" ); return false; } } // here only for empty lists or everything was smaller node_t n; n.key = key; n.value = object; bag.append( n ); count ++; return true; } // // Inserts a new instantiated value - failure, if key exists in table // mostly used with value_t = slist_tpl // bool put(const key_t key) { slist_tpl& bag = bags[get_hash(key)]; /* Duplicate values are hard to debug, so better check here. * we also enter it sorted, saving lookout time for large lists ... */ for( typename slist_tpl::iterator iter = bag.begin(), end = bag.end(); iter != end; ++iter ) { typename hash_t::diff_type diff = hash_t::comp(iter->key, key); if( diff>0 ) { iter = bag.insert( iter ); iter->key = key; count ++; return true; } if( diff == 0 ) { // already initialized return false; } } // here only for empty lists or everything was smaller bag.append(); bag.back().key = key; count ++; return true; } // // Insert or replace a value - if a value is replaced, the old value is // returned, otherwise a nullvalue. This may be useful if you need to delete it // afterwards. // value_t set(const key_t key, value_t object) { slist_tpl& bag = bags[get_hash(key)]; for( typename slist_tpl::iterator iter = bag.begin(), end = bag.end(); iter != end; ++iter ) { typename hash_t::diff_type diff = hash_t::comp(iter->key, key); if( diff == 0 ) { value_t value = iter->value; iter->value = object; return value; } if( diff > 0 ) { node_t node; node.key = key; node.value = object; bag.insert( iter, node ); count ++; return value_t(); } } // empty list or really last one ... node_t node; node.key = key; node.value = object; bag.append(node); count ++; return value_t(); } // Remove an entry - if the entry is not there, return a nullvalue // otherwise the value that was associated to the key. value_t remove(const key_t key) { slist_tpl& bag = bags[get_hash(key)]; for( typename slist_tpl::iterator iter = bag.begin(), end = bag.end(); iter != end; ++iter ) { typename hash_t::diff_type diff = hash_t::comp(iter->key, key); if( diff == 0 ) { value_t v = iter->value; bag.erase(iter); count --; return v; } if( diff > 0 ) { // not in list break; } } return value_t(); } value_t remove_first() { for(STHT_BAG_COUNTER_T i = 0; i < STHT_BAGSIZE; i++) { if( !bags[i].empty() ) { count --; return bags[i].remove_first().value; } } dbg->fatal( "hashtable_tpl::remove_first()", "Hashtable already empty!" ); return value_t(); } uint32 get_count() const { return count; } bool empty() const { return get_count()==0; } }; #endif simutrans-124.3/src/simutrans/tpl/inthashtable_tpl.h000066400000000000000000000024301474050137200226630ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_INTHASHTABLE_TPL_H #define TPL_INTHASHTABLE_TPL_H #include "hashtable_tpl.h" /** * Define type for differences of integers. * Default is int. * Obvious specializations for 64bit integers. */ template struct int_diff_type { typedef int diff_type; }; template<> struct int_diff_type { typedef sint64 diff_type; }; template<> struct int_diff_type { typedef sint64 diff_type; }; /** * Define the key characteristics for hashing integer types */ template class inthash_tpl { public: typedef typename int_diff_type::diff_type diff_type; static uint32 hash(const key_t key) { return (uint32)key; } static diff_type comp(key_t key1, key_t key2) { return key1 - key2; } }; /* * Ready to use class for hashing integer types. Note that key can be of any * integer type including enums. */ template class inthashtable_tpl : public hashtable_tpl > { public: inthashtable_tpl() : hashtable_tpl >() {} private: inthashtable_tpl(const inthashtable_tpl&); inthashtable_tpl& operator=( inthashtable_tpl const&); }; #endif simutrans-124.3/src/simutrans/tpl/minivec_tpl.h000066400000000000000000000073501474050137200216550ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_MINIVEC_TPL_H #define TPL_MINIVEC_TPL_H #include "../simdebug.h" #include "../simtypes.h" /** A template class for a simple vector type */ template class minivec_tpl { public: typedef const T* const_iterator; typedef T* iterator; minivec_tpl() : data(NULL), size(0), count(0) {} /** Construct a vector for cap elements */ explicit minivec_tpl(uint8 cap) : data(cap > 0 ? new T[cap] : NULL), size(cap), count(0) {} ~minivec_tpl() { delete [] data; } /** sets the vector to empty */ void clear() { count = 0; } /** * Resizes the maximum data that can be hold by this vector. * Existing entries are preserved, new_size must be big enough to hold them */ void resize(uint new_size) { if (new_size > 255) { dbg->fatal("minivec_tpl::resize()", "new size %u too large (>255).", new_size); } // not yet used, but resize may be called anyway if(size<=0) { size = new_size; data = new T[size]; return; } if (new_size <= size) return; // do nothing T* new_data = new T[new_size]; for (uint i = 0; i < count; i++) new_data[i] = data[i]; delete [] data; size = new_size; data = new_data; } /** * Checks if element elem is contained in vector. * Uses the == operator for comparison. */ bool is_contained(T elem) const { for (uint i = 0; i < count; i++) { if (data[i] == elem) return true; } return false; } /** * Appends the element at the end of the vector. * if out of space, extend it */ void append(T elem, uint8 extend = 1) { if (count >= size) { resize( count > 255-extend ? 255 : count+extend); } data[count++] = elem; } /** Checks if element is contained. Appends only new elements. */ bool append_unique(T elem) { if (is_contained(elem)) return false; append(elem); return true; } /** Removes element, if contained */ void remove(T elem) { uint i, j; for (i = j = 0; i < count; i++, j++) { if (data[i] == elem) { // skip this one j++; count--; } // maybe we copy too often ... if (j < size) { data[i] = data[j]; } } } /** Inserts data at a certain pos */ void insert_at(uint8 pos, T elem) { if (pos > count) { dbg->fatal("minivec_tpl::append()", "cannot insert at %i! Only %i elements.", pos, count); } if (pos < count) { if (count == size) resize(count + 1); for (uint i = count; i > pos; i--) data[i] = data[i - 1]; data[pos] = elem; count++; } else { append(elem, 1); } } /** Removes element at position */ bool remove_at(uint8 pos) { if (pos < count) { for (uint i = pos+1; i < count; i++) { data[i-1] = data[i]; } count--; return true; } return false; } T& operator [](uint8 i) { if (i >= count) dbg->fatal("minivec_tpl::[]", "index out of bounds: %i not in 0..%d", i, count - 1); return data[i]; } const T& operator [](uint8 i) const { if (i >= count) dbg->fatal("minivec_tpl::[]", "index out of bounds: %i not in 0..%d", i, count - 1); return data[i]; } T& back() { return data[count - 1]; } const T& back() const { return data[count - 1]; } iterator begin() { return data; } iterator end() { return data + count; } const_iterator begin() const { return data; } const_iterator end() const { return data + count; } /** Get the number of elements in the vector */ uint8 get_count() const { return count; } /** Get the capacity */ uint8 get_size() const { return size; } bool empty() const { return count == 0; } private: minivec_tpl(const minivec_tpl&); minivec_tpl& operator=( minivec_tpl const& other ); T* data; uint8 size; ///< Capacity uint8 count; ///< Number of elements in vector } GCC_PACKED; #endif simutrans-124.3/src/simutrans/tpl/plainstringhashtable_tpl.h000066400000000000000000000013371474050137200244300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_PLAINSTRINGHASHTABLE_TPL_H #define TPL_PLAINSTRINGHASHTABLE_TPL_H #include "stringhashtable_tpl.h" #include "../utils/plainstring.h" /** * Hashtable with plainstring keys. * * Keys will be copied when creating entries, * unlike stringhashtable_tpl */ template class plainstringhashtable_tpl : public hashtable_tpl { public: plainstringhashtable_tpl() : hashtable_tpl() {} private: plainstringhashtable_tpl(const plainstringhashtable_tpl&); plainstringhashtable_tpl& operator=( plainstringhashtable_tpl const&); }; #endif simutrans-124.3/src/simutrans/tpl/ptrhashtable_tpl.h000066400000000000000000000021721474050137200227010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_PTRHASHTABLE_TPL_H #define TPL_PTRHASHTABLE_TPL_H #include "hashtable_tpl.h" #include "../simtypes.h" /* * Define the key characteristics for hashing pointers. For hashing the * direct value is used. */ template class ptrhash_tpl { public: // define NO_INTPTR_T if it does not compile #ifndef NO_INTPTR_T typedef intptr_t cast_ptr_to_t; typedef intptr_t diff_type; #else typedef ptrdiff_t diff_type; typedef const char* cast_ptr_to_t; #endif static uint32 hash(const key_t key) { return (uint32)(size_t)key; } static diff_type comp(key_t key1, key_t key2) { return (cast_ptr_to_t)key1 - (cast_ptr_to_t)key2; } }; /** * Implements a hashtable with pointer keys */ template class ptrhashtable_tpl : public hashtable_tpl > { public: ptrhashtable_tpl() : hashtable_tpl >() {} private: ptrhashtable_tpl(const ptrhashtable_tpl&); ptrhashtable_tpl& operator=( ptrhashtable_tpl const&); }; #endif simutrans-124.3/src/simutrans/tpl/quickstone_tpl.h000066400000000000000000000133761474050137200224150ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_QUICKSTONE_TPL_H #define TPL_QUICKSTONE_TPL_H #include "../simtypes.h" #include "../simdebug.h" /** * An implementation of the tombstone pointer checking method. * It uses a table of pointers and indices into that table to * implement the tombstone system. Unlike real tombstones, this * template reuses entries from the tombstone table, but it tries * to leave freed tombstones untouched as long as possible, to * detect most of the dangling pointers. * * This templates goal is to be efficient and fairly safe. */ template class quickstone_tpl { private: /** * Array of pointers. The first entry is always NULL! */ static T ** data; /** * Next entry to check */ static uint16 next; /** * Size of tombstone table */ static uint16 size; /** * The index in the table for this handle. * (only this variable is actually saved, since the rest is static!) */ uint16 entry; private: /** * Retrieves next free tombstone index */ static uint16 find_next() { uint16 i; // scan rest of array for( i=next; ifatal("quickstone::find_next()","no free index found (size=%i)",size); return 0; //dummy for compiler } else if (size >= 32768) { // max out on handles, don't overflow uint16 newsize = 65535; } else { newsize = 2*size; } // Move data to new extended array T ** newdata = new T* [newsize]; memcpy( newdata, data, sizeof(T*)*size ); for( uint16 i=size; i0; i++ ) { if( data[i] == 0 ) { entry = i; data[entry] = p; return; } } enlarge(); // repeat for( i=size-1; i>0; i++ ) { if( data[i] == 0 ) { entry = i; data[entry] = p; return; } } dbg->fatal( "quickstone_tpl(bool)", "No more handles!\nShould have already failed with enlarge!" ); } // creates handle with id, fails if already taken quickstone_tpl(T* p, uint16 id) { if(p) { if( id == 0 ) { dbg->fatal("quickstone::quickstone_tpl(T*,uint16)","wants to assign non-null pointer to null index"); } while( id >= size ) { enlarge(); } if( data[id]!=NULL && data[id]!=p ) { dbg->fatal("quickstone::quickstone_tpl(T*,uint16)","slot (%d) already taken", id); } entry = id; data[entry] = p; } else { if( id!=0 ) { dbg->fatal("quickstone::quickstone_tpl(T*,uint16)","wants to assign null pointer to non-null index"); } // all NULL pointers are mapped to entry 0 entry = 0; } } // returns true, if no handles left static bool is_exhausted() { if( size==65535 ) { // scan array for( uint16 i = 1; i cannot extent return true; } // can extent in any case => ok return false; } inline bool is_bound() const { return data[entry] != 0; } /** * Removes the object from the tombstone table - this affects all * handles to the object! */ T* detach() { T* p = data[entry]; data[entry] = 0; return p; } /** * Danger - use with care. * Useful to hand the underlying pointer to subsystems * that don't know about quickstones - but take care that such pointers * are never ever deleted or that by some means detach() is called * upon deletion, i.e. from the ~T() destructor!!! */ T* get_rep() const { return data[entry]; } /** * @return the index into the tombstone table. May be used as * an ID for the referenced object. */ uint16 get_id() const { return entry; } /** * Sets the current id: Needed to recreate stuff via network. * ATTENTION: This may be harmful. DO not use unless really really needed! */ void set_id(uint16 e) { entry=e; } /** * Overloaded dereference operator. With this, quickstones can * be used as if they were pointers. */ T* operator->() const { return data[entry]; } T& operator *() const { return *data[entry]; } bool operator== (const quickstone_tpl &other) const { return entry == other.entry; } bool operator!= (const quickstone_tpl &other) const { return entry != other.entry; } static uint16 get_size() { return size; } /** * For checking the consistency of handle allocation * among the server and the clients in network mode */ static uint16 get_next_check() { return next; } }; template T** quickstone_tpl::data = 0; template uint16 quickstone_tpl::next = 1; template uint16 quickstone_tpl::size = 0; #endif simutrans-124.3/src/simutrans/tpl/slist_tpl.h000066400000000000000000000226351474050137200213640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_SLIST_TPL_H #define TPL_SLIST_TPL_H #include #include #include "../dataobj/freelist.h" #include "../simdebug.h" #include // for ptrdiff_t #ifdef _MSC_VER #pragma warning(disable:4786) #endif /** * A template class for a single linked list. Insert() and append() * work in fixed time. Maintains a list of free nodes to reduce calls * to new and delete. * * Must NOT be used with things with copy constructor like button_t or std::string!!! */ template class slist_tpl { private: struct node_t { node_t(const T& data_, node_t* next_) : next(next_), data(data_) {} node_t(node_t* next_) : next(next_), data() {} void* operator new(size_t) { return freelist_t::gimme_node(sizeof(node_t)); } void operator delete(void* p) { freelist_t::putback_node(sizeof(node_t), p); } node_t* next; T data; }; node_t *head; node_t *tail; uint32 node_count; public: class const_iterator; /** * Iterator class: can be used to erase nodes and to modify nodes * Usage: @see utils/for.h */ class iterator { public: typedef std::forward_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef value_type* pointer; typedef value_type& reference; iterator() : ptr(), pred() {} pointer operator ->() const { return &ptr->data; } reference operator *() const { return ptr->data; } iterator& operator ++() { pred = ptr; ptr = ptr->next; return *this; } iterator operator ++(int) { iterator const old = *this; ++*this; return old; } bool operator ==(iterator const& o) const { return ptr == o.ptr; } bool operator !=(iterator const& o) const { return ptr != o.ptr; } private: iterator(node_t* ptr_, node_t* pred_) : ptr(ptr_), pred(pred_) {} node_t* ptr; node_t* pred; private: friend class slist_tpl; friend class const_iterator; }; /** * Iterator class: neither nodes nor the list can be modified * Usage: @see utils/for.h */ class const_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T const* pointer; typedef T const& reference; const_iterator() : ptr() {} const_iterator(const iterator& o) : ptr(o.ptr) {} pointer operator ->() const { return &ptr->data; } reference operator *() const { return ptr->data; } const_iterator& operator ++() { ptr = ptr->next; return *this; } const_iterator operator ++(int) { const_iterator const old = *this; ++*this; return old; } bool operator ==(const_iterator const& o) const { return ptr == o.ptr; } bool operator !=(const_iterator const& o) const { return ptr != o.ptr; } private: explicit const_iterator(node_t* ptr_) : ptr(ptr_) {} const node_t* ptr; private: friend class slist_tpl; }; /** * Creates a new empty list. */ slist_tpl() { head = 0; // empty list tail = 0; node_count = 0; } ~slist_tpl() { clear(); } /** * Inserts an element at the beginning of the list. */ void insert(const T& data) { node_t* tmp = new node_t(data, head); head = tmp; if( tail == NULL ) { tail = tmp; } node_count++; } /** * Inserts an element initialized by standard constructor * at the beginning of the lists * (avoid the use of copy constructor) */ void insert() { node_t* tmp = new node_t(head); head = tmp; if( tail == NULL ) { tail = tmp; } node_count++; } /** * Appends an element to the end of the list. */ void append(const T& data) { if (tail == 0) { insert(data); } else { node_t* tmp = new node_t(data, 0); tail->next = tmp; tail = tmp; node_count++; } } /** * Append an zero/empty element * mostly used for T=slist_tpl<...> */ void append() { if (tail == 0) { insert(); } else { node_t* tmp = new node_t(0); tail->next = tmp; tail = tmp; node_count++; } } /** * Appends an element to the end of the list. */ void append_unique(const T& data) { if (tail == 0) { insert(data); } else if( !is_contained(data) ) { node_t* tmp = new node_t(data, 0); tail->next = tmp; tail = tmp; node_count++; } } /** * Appends the nodes of another list * empties other list * -> no memory allocation involved */ void append_list(slist_tpl& other) { if (tail) { tail->next = other.head; } else { head = other.head; } if (other.tail) { tail = other.tail; } node_count += other.node_count; // empty other list other.tail = NULL; other.head = NULL; other.node_count = 0; } /** * Checks if the given element is already contained in the list. */ bool is_contained(const T &data) const { node_t *p = head; while(p != 0 && p->data != data) { p = p->next; } return p != 0; // is NULL when not found } /** * Removes an element from the list */ bool remove(const T &data) { if (empty()) { //MESSAGE("slist_tpl::remove()", "data not in list!"); return false; } if(head->data == data) { node_t *tmp = head->next; delete head; head = tmp; if(head == NULL) { tail = NULL; } } else { node_t *p = head; while(p->next != 0 && !(p->next->data == data)) { p = p->next; } if(p->next == 0) { //MESSAGE("slist_tpl::remove()", "data not in list!"); return false; } node_t *tmp = p->next->next; delete p->next; p->next = tmp; if(tmp == 0) { tail = p; } } node_count--; return true; } /** * Retrieves the first element from the list. This element is * deleted from the list. Useful for some queuing tasks. */ T remove_first() { if (empty()) { dbg->fatal("slist_tpl::remove_first()","List of <%s> is empty",typeid(T).name()); } T tmp = head->data; node_t *p = head; head = head->next; delete p; node_count--; if(head == 0) { // list is empty now tail = 0; } return tmp; } /** * Recycles all nodes. * Leaves the list empty. */ void clear() { node_t* p = head; while (p != NULL) { node_t* tmp = p; p = p->next; delete tmp; } head = 0; tail = 0; node_count = 0; } uint32 get_count() const { return node_count; } bool empty() const { return head == 0; } T& at(uint32 pos) const { if (pos >= node_count) { dbg->fatal("slist_tpl::at()", "<%s> index %d is out of bounds", typeid(T).name(), pos); } node_t* p = head; while (pos--) { p = p->next; } return p->data; } T& front() const { return head->data; } T& back() const { return tail->data; } iterator begin() { return iterator(head, NULL); } iterator end() { return iterator(NULL, tail); } const_iterator begin() const { return const_iterator(head); } const_iterator end() const { return const_iterator(NULL); } /* Erase element at pos * pos is invalid after this method * An iterator pointing to the successor of the erased element is returned */ iterator erase(iterator pos) { node_t* pred = pos.pred; node_t* succ = pos.ptr->next; if (pred == NULL) { head = succ; } else { pred->next = succ; } if (succ == NULL) { tail = pred; } delete pos.ptr; --node_count; return iterator(succ, pred); } /* Add x before pos * pos is invalid after this method * An iterator pointing to the new element is returned */ iterator insert(iterator pos, const T& x) { node_t* tmp = new node_t(x, pos.ptr); if (pos.pred == NULL) { head = tmp; } else { pos.pred->next = tmp; } if (pos.ptr == NULL) { tail = tmp; } ++node_count; return iterator(tmp, pos.pred); } /* Add an empty node * pos is invalid after this method * An iterator pointing to the new element is returned */ iterator insert(iterator pos) { node_t* tmp = new node_t(pos.ptr); if (pos.pred == NULL) { head = tmp; } else { pos.pred->next = tmp; } if (pos.ptr == NULL) { tail = tmp; } ++node_count; return iterator(tmp, pos.pred); } int index_of(T data) const { node_t *t = head; int index = 0; while(t && t->data != data) { t = t->next; index++; } return t ? index : -1; } /** * sorts list using specified comparator * returns true if list was changed */ bool sort( int (*compare)(const T &l, const T &r) ) { if( NULL == head || head == tail ) { return false; } bool needed_work = false; for( uint i=1; i < node_count; ++i ) { int changes = 0; if( compare( head->data, head->next->data ) > 0 ) { node_t * tmp = head; head = head->next; tmp->next = head->next; head->next = tmp; ++changes; if( head == tail ) { tail = tail->next; break; } } for( node_t *node = head; node != tail && node->next != tail; node = node->next ) { if( compare( node->next->data, node->next->next->data ) > 0 ) { node_t * tmp = node->next; node->next = node->next->next; tmp->next = node->next->next; node->next->next = tmp; ++changes; if( node->next == tail ){ tail = tail->next; break; } } } if( changes == 0 ) { break; } needed_work = true; } return needed_work; } private: slist_tpl(const slist_tpl& slist_tpl); slist_tpl& operator=( slist_tpl const& other ); }; #endif simutrans-124.3/src/simutrans/tpl/sparse_tpl.h000066400000000000000000000116171474050137200215210ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_SPARSE_TPL_H #define TPL_SPARSE_TPL_H #include "../dataobj/koord.h" #include "../macros.h" #include "../simtypes.h" template class sparse_tpl; template void swap(sparse_tpl& a, sparse_tpl& b); /** * A template class for spares 2-dimensional arrays. * It's using Compressed Row Storage (CRS). * @see array2d_tpl */ template class sparse_tpl { private: koord size; T* data; uint16* col_ind; uint16* row_ptr; uint16 data_size; uint16 data_count; public: sparse_tpl( koord _size ) { size = _size; data_size = 0; data_count = 0; data = NULL; col_ind = NULL; row_ptr = new uint16[ size.y + 1]; for( uint16 i = 0; i < size.y + 1; i++ ) { row_ptr[i] = 0; } } ~sparse_tpl() { delete[] data; data = NULL; delete[] col_ind; col_ind = NULL; delete[] row_ptr; row_ptr = NULL; } void clear() { data_count = 0; for( uint16 i = 0; i < size.y + 1; i++ ) { row_ptr[i] = 0; } resize_data(0); } const koord& get_size() const { return size; } uint16 get_data_size() const { return data_size; } uint16 get_data_count() const { return data_count; } T get( koord pos ) const { if( pos.x >= 0 && pos.y >= 0 && pos.x < size.x && pos.y < size.y ) { return get_unsafe( pos ); } return 0; } T get( uint16 i, uint16 j ) const { return get(koord(i,j)); } /* * Access to the nonzero elements. Result is saved in pos and value! */ void get_nonzero( uint16 index, koord& pos, T& value ) const { if( index > data_count ) { pos = koord::invalid; value = 0; return; } value = data[index]; pos = koord(col_ind[index], 0); while( row_ptr[ pos.y+1 ] <= index ) { pos.y++; } } void set( koord pos, T value ) { if( pos.x >= 0 && pos.y >= 0 && pos.x < size.x && pos.y < size.y ) { set_unsafe( pos, value ); } } void set( uint16 i, uint16 j, T value ) { set(koord(i,j),value); } private: T get_unsafe( koord pos ) const { uint16 index = pos_to_index( pos ); if( index < row_ptr[pos.y+1] && col_ind[index] == pos.x ) { return data[index]; } else { return 0; } } void set_unsafe( koord pos, T value ) { uint16 index = pos_to_index( pos ); if( index < row_ptr[pos.y+1] && col_ind[index] == pos.x ) { if( value == 0 ) { move_data(index+1, data_count, -1); for( uint16 i = pos.y+1; i < size.y+1; i++ ){ row_ptr[i]--; } data_count--; } else { data[index] = value; } } else { if( value == 0 ) { // Don't add 0 to data! return; } if( data_count == data_size ) { resize_data(data_size==0 ? 1 : 2*data_size); } move_data(index, data_count, 1); data[index] = value; col_ind[index] = pos.x; for( uint16 i = pos.y+1; i < size.y+1; i++ ){ row_ptr[i]++; } data_count++; } } /* * Moves the elements data[start_index]..data[end_index-1] to * data[start_index+offset]..data[end_index-1+offset] */ void move_data(uint16 start_index, uint16 end_index, sint8 offset) { uint16 num = end_index - start_index; if( offset < 0 ) { for( uint16 i=0; i 0 ) { for( uint16 i=num ; i>0 ; i-- ){ data[start_index+i+offset-1] = data[start_index+i-1]; col_ind[start_index+i+offset-1] = col_ind[start_index+i-1]; } } } void resize_data( uint16 new_size ) { if( new_size < data_count || new_size == data_size ) { // new_size is too small or equal our current size. return; } T* new_data; uint16* new_col_ind; if( new_size > 0 ) { new_data = new T[new_size]; new_col_ind = new uint16[new_size]; } else { new_data = NULL; new_col_ind = NULL; } if( data_size > 0 ) { for( uint16 i = 0; i < data_count; i++ ) { new_data[i] = data[i]; new_col_ind[i] = col_ind[i]; } delete[] data; delete[] col_ind; } data_size = new_size; data = new_data; col_ind = new_col_ind; } /* * Returns an index i * - to the pos (if pos already in array) * - to the index, where pos can be inserted. */ uint16 pos_to_index( koord pos ) const { uint16 row_start = row_ptr[ pos.y ]; uint16 row_end = row_ptr[ pos.y + 1 ]; for( uint16 i = row_start; i < row_end; i++ ) { if( col_ind[i] >= pos.x ) { return i; } } return row_end; } private: friend void swap<>(sparse_tpl& a, sparse_tpl& b); sparse_tpl(const sparse_tpl& other); sparse_tpl& operator=( sparse_tpl const& other ); }; template void swap(sparse_tpl& a, sparse_tpl& b) { sim::swap(a.size, b.size); sim::swap(a.data, b.data); sim::swap(a.col_ind, b.col_ind); sim::swap(a.row_ptr, b.row_ptr); sim::swap(a.data_size, b.data_size); sim::swap(a.data_count, b.data_count); } #endif simutrans-124.3/src/simutrans/tpl/stringhashtable_tpl.h000066400000000000000000000021551474050137200234030ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_STRINGHASHTABLE_TPL_H #define TPL_STRINGHASHTABLE_TPL_H #include "hashtable_tpl.h" #include /* * a template class which implements a hashtable with string keys */ /* * Define the key characteristics for hashing "const char *". */ class stringhash_t { public: typedef int diff_type; static uint32 hash(const char *key) { uint32 hash = 0; #if 1 for( sint8 i=16; i*key[0]!=0; i-- ) { hash += (uint8)(*key++); } #else while (*key != '\0') { hash = hash * 33 + *key++; } #endif return hash; } static diff_type comp(const char *key1, const char *key2) { return strcmp(key1, key2); } }; /* * Ready to use class for hashing strings. */ template class stringhashtable_tpl : public hashtable_tpl { public: stringhashtable_tpl() : hashtable_tpl() {} private: stringhashtable_tpl(const stringhashtable_tpl&); stringhashtable_tpl& operator=( stringhashtable_tpl const&); }; #endif simutrans-124.3/src/simutrans/tpl/vector_tpl.h000066400000000000000000000142721474050137200215260ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_VECTOR_TPL_H #define TPL_VECTOR_TPL_H #include #include "../macros.h" #include "../simtypes.h" #include "../simdebug.h" template class vector_tpl; template inline void swap(vector_tpl& a, vector_tpl& b); /** A template class for a simple vector type */ template class vector_tpl { public: typedef const T *const_iterator; typedef T *iterator; /** Construct a vector for cap elements */ vector_tpl() : data(NULL), cap(0), count(0) {} explicit vector_tpl(const uint32 cap) : data(cap > 0 ? new T[cap] : NULL), cap(cap), count(0) {} vector_tpl(const vector_tpl& copy_from) : data( copy_from.cap > 0 ? new T[ copy_from.cap ] : 0 ), cap( copy_from.cap ), count( copy_from.count ) { for( uint32 i = 0; i < count; i++ ) { data[i] = copy_from.data[i]; } } ~vector_tpl() { delete[] data; } /** sets the vector to empty */ void clear() { count = 0; } /** * Increases the capacity of this vector to @p new_capacity. Existing entries are preserved. * If @p new_capacity is smaller than the current capacity, the vector is not modified. */ void reserve(uint32 new_capacity) { if (new_capacity <= cap) return; // do nothing T *new_data = new T[new_capacity]; if (cap>0) { for (uint32 i = 0; i < count; i++) { new_data[i] = data[i]; } delete [] data; } cap = new_capacity; data = new_data; } /** * Checks if element elem is contained in vector. * Uses the == operator for comparison. */ bool is_contained(const T& elem) const { for (uint32 i = 0; i < count; i++) { if (data[i] == elem) { return true; } } return false; } /** * Checks if element elem is contained in vector. * Uses the == operator for comparison. */ uint32 index_of(const T& elem) const { for (uint32 i = 0; i < count; i++) { if (data[i] == elem) { return i; } } assert(false); return 0xFFFFFFFFu; } void append(const T& elem) { if( count == cap ) { reserve(cap == 0 ? 1 : cap * 2); } data[count++] = elem; } /** * Checks if element is contained. Appends only new elements. * extend vector if necessary */ bool append_unique(const T& elem) { if (is_contained(elem)) { return false; } append(elem); return true; } /** insert data at a certain pos */ void insert_at(const uint32 pos, const T& elem) { if (pos < count) { if (count == cap) { reserve(cap == 0 ? 1 : cap * 2); } for (uint i = count; i > pos; i--) { data[i] = data[i - 1]; } data[pos] = elem; count++; } else { append(elem); } } /** * Insert `elem' with respect to ordering. */ template void insert_ordered(const T& elem, StrictWeakOrdering comp) { sint32 low = -1, high = count; while( high - low>1 ) { const sint32 mid = ((uint32) (low + high)) >> 1; T &mid_elem = data[mid]; if( comp(elem, mid_elem) ) { high = mid; } else { low = mid; } } insert_at(high, elem); } /** * Only insert `elem' if not already contained in this vector. * Respects the ordering and assumes the vector is ordered. * Returns NULL if insertion is successful; * otherwise return the address of the element in conflict */ template T* insert_unique_ordered(const T& elem, StrictWeakOrdering comp) { sint32 low = -1, high = count; while( high - low>1 ) { const sint32 mid = ((uint32) (low + high)) >> 1; T &mid_elem = data[mid]; if( elem==mid_elem ) { return &mid_elem; } else if( comp(elem, mid_elem) ) { high = mid; } else { low = mid; } } insert_at(high, elem); return NULL; } /** * Put the data at a certain position. * Possibly re-allocates vector (and hence creates default objects). * @param pos index * @param elem this element will be copied */ void store_at(const uint32 pos, const T& elem) { if (pos >= cap) { uint32 new_cap = cap == 0 ? 1 : cap * 2; while (pos >= new_cap) { new_cap *= 2; } reserve(new_cap); } data[pos] = elem; if (pos >= count) { count = pos + 1; } } /** removes element, if contained */ bool remove(const T& elem) { for (uint32 i = 0; i < count; i++) { if (data[i] == elem) { return remove_at(i); } } return false; } /** removes element at position */ bool remove_at(const uint32 pos) { assert(pos0); --count; return data[count]; } T& operator [](uint i) { if (i >= count) { dbg->fatal("vector_tpl::[]", "%s: index out of bounds: %i not in 0..%d", typeid(T).name(), i, count - 1); } return data[i]; } const T& operator [](uint i) const { if (i >= count) { dbg->fatal("vector_tpl::[]", "%s: index out of bounds: %i not in 0..%d", typeid(T).name(), i, count - 1); } return data[i]; } T& front() const { return data[0]; } T& back() const { return data[count - 1]; } iterator begin() { return data; } iterator end() { return data + count; } iterator erase(iterator i) { remove_at( i-data ); return i; } const_iterator begin() const { return data; } const_iterator end() const { return data + count; } /** Get the number of elements in the vector */ uint32 get_count() const { return count; } /** Get the capacity */ uint32 get_capacity() const { return cap; } bool empty() const { return count == 0; } private: T* data; uint32 cap; ///< Capacity uint32 count; ///< Number of elements in vector vector_tpl& operator=( vector_tpl const& other ) { vector_tpl tmp(other); swap(tmp, *this); return *this; } private: friend void swap<>(vector_tpl& a, vector_tpl& b); }; template void swap(vector_tpl& a, vector_tpl& b) { sim::swap(a.data, b.data); sim::swap(a.cap, b.cap); sim::swap(a.count, b.count); } /** * Clears vectors of the type vector_tpl * Deletes all objects pointed to by pointers in the vector */ template void clear_ptr_vector(vector_tpl& v) { for(auto const i : v) { delete i; } v.clear(); } #endif simutrans-124.3/src/simutrans/tpl/weighted_vector_tpl.h000066400000000000000000000226321474050137200234050ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef TPL_WEIGHTED_VECTOR_TPL_H #define TPL_WEIGHTED_VECTOR_TPL_H #include #include #include "../macros.h" #include "../simdebug.h" template class weighted_vector_tpl; template void swap(weighted_vector_tpl&, weighted_vector_tpl&); /** A template class for a simple vector type */ template class weighted_vector_tpl { private: struct nodestruct { T data; uint32 weight; }; public: class const_iterator; class iterator { public: typedef std::forward_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; typedef T const* pointer; typedef T const& reference; typedef T value_type; T& operator *() const { return ptr->data; } iterator& operator ++() { ++ptr; return *this; } bool operator !=(const iterator& o) { return ptr != o.ptr; } private: explicit iterator(nodestruct* ptr_) : ptr(ptr_) {} nodestruct* ptr; private: friend class weighted_vector_tpl; friend class const_iterator; }; class const_iterator { public: typedef std::forward_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; typedef T const* pointer; typedef T const& reference; typedef T value_type; const_iterator(const iterator& o) : ptr(o.ptr) {} const T& operator *() const { return ptr->data; } const_iterator& operator ++() { ++ptr; return *this; } bool operator !=(const const_iterator& o) { return ptr != o.ptr; } private: explicit const_iterator(nodestruct* ptr_) : ptr(ptr_) {} const nodestruct* ptr; private: friend class weighted_vector_tpl; }; weighted_vector_tpl() : nodes(NULL), size(0), count(0), total_weight(0) {} /** Construct a vector for size elements */ explicit weighted_vector_tpl(uint32 size) { this->size = size; nodes = (size > 0 ? new nodestruct[size] : NULL); count = 0; total_weight = 0; } ~weighted_vector_tpl() { delete [] nodes; } /** sets the vector to empty */ void clear() { count = 0; total_weight = 0; } /** * Resizes the maximum data that can be hold by this vector. * Existing entries are preserved, new_size must be big enough * to hold them. */ void resize(uint32 new_size) { if (new_size <= size) return; // do nothing nodestruct* new_nodes = new nodestruct[new_size]; for (uint32 i = 0; i < count; i++) new_nodes[i] = nodes[i]; delete [] nodes; size = new_size; nodes = new_nodes; } /** * Checks if element elem is contained in vector. * Uses the == operator for comparison. */ bool is_contained(T elem) const { for (uint32 i = 0; i < count; i++) { if (nodes[i].data == elem) return true; } return false; } /** * Checks if element elem is contained in vector. * Uses the == operator for comparison. */ template uint32 index_of(U elem) const { for (uint32 i = 0; i < count; i++) { if (nodes[i].data == elem) return i; } dbg->fatal("weighted_vector_tpl::index_of()", "not contained" ); } /** * Appends the element at the end of the vector. * Extend if necessary. */ bool append(T elem, uint32 weight) { #ifdef IGNORE_ZERO_WEIGHT if (weight == 0) { // ignore unused entries ... return false; } #endif if( count == size ) { resize(size == 0 ? 1 : size * 2); } nodes[count].data = elem; nodes[count].weight = total_weight; count++; total_weight += weight; return true; } /** * Checks if element is contained. Appends only new elements. */ bool append_unique(T elem, uint32 weight) { return is_contained(elem) || append(elem, weight); } /** inserts data at a certain pos */ bool insert_at(uint32 pos, T elem, uint32 weight) { #ifdef IGNORE_ZERO_WEIGHT if (weight == 0) { // ignore unused entries ... return false; } #endif if (pos < count) { if( count==size ) { resize(size == 0 ? 1 : size * 2); } for (uint32 i = count; i > pos; i--) { nodes[i].data = nodes[i - 1].data; nodes[i].weight = nodes[i - 1].weight + weight; } nodes[pos].data = elem; total_weight += weight; count++; return true; } else { return append(elem, weight); } } /** * Insert `elem' with respect to ordering. */ template void insert_ordered(const T& elem, uint32 weight, StrictWeakOrdering comp) { if( count==size ) { resize(size == 0 ? 1 : size * 2); } sint32 high = count, low = -1; while( high-low>1 ) { const sint32 mid = ((uint32)(high + low)) >> 1; if( comp(elem, nodes[mid].data) ) { high = mid; } else { low = mid; } } insert_at(high, elem, weight); } /** * Only insert `elem' if not already contained in this vector. * Respects the ordering and assumes the vector is ordered. * Returns NULL if insertion is successful; * Otherwise return the address of the element in conflict. */ template T* insert_unique_ordered(const T& elem, uint32 weight, StrictWeakOrdering comp) { if( count==size ) { resize(size == 0 ? 1 : size * 2); } sint32 high = count, low = -1; while( high-low>1 ) { const sint32 mid = ((uint32)(high + low)) >> 1; T &mid_elem = nodes[mid].data; if( elem==mid_elem ) { return &mid_elem; } else if( comp(elem, mid_elem) ) { high = mid; } else { low = mid; } } insert_at(high, elem, weight); return NULL; } /** * Update the weights of all elements. The new weight of each element is * retrieved from get_weight(). */ template void update_weights(U& get_weight) { uint32 sum = 0; for (nodestruct* i = nodes, * const end = i + count; i != end; ++i) { i->weight = sum; sum += get_weight(i->data); } total_weight = sum; } /** removes element, if contained */ bool remove(T elem) { for (uint32 i = 0; i < count; i++) { if (nodes[i].data == elem) return remove_at(i); } return false; } /** removes element at position */ bool remove_at(uint32 pos) { if (pos >= count) return false; // get the change in the weight; must check, if it isn't the last element const uint32 diff_weight = ( pos + 1 < count ? nodes[pos + 1].weight : total_weight ) - nodes[pos].weight; for (uint32 i = pos; i < count - 1; i++) { nodes[i].data = nodes[i + 1].data; nodes[i].weight = nodes[i + 1].weight - diff_weight; } count--; total_weight -= diff_weight; return true; } T& pop_back() { assert(count>0); --count; total_weight = nodes[count].weight; return nodes[count].data; } T& operator [](uint32 i) { if (i >= count) dbg->fatal("weighted_vector_tpl::get()", "index out of bounds: %i not in 0..%d", i, count - 1); return nodes[i].data; } const T& operator [](uint32 i) const { if (i >= count) dbg->fatal("weighted_vector_tpl::get()", "index out of bounds: %i not in 0..%d", i, count - 1); return nodes[i].data; } T& front() { return nodes[0].data; } /** returns the weight at a position */ uint32 weight_at(uint32 pos) const { return (pos < count) ? nodes[pos].weight : total_weight + 1; } /** Accesses the element at position i by weight */ T& at_weight(const uint32 target_weight) const { if (target_weight > total_weight) { dbg->fatal("weighted_vector_tpl::at_weight()", "weight out of bounds: %i not in 0..%d", target_weight, total_weight); } #if 0 // that is the main idea (but slower, the more entries are in the list) uint32 pos; uint32 current_weight = 0; for (pos = 0; pos < count - 1 && current_weight + nodes[pos + 1].weight < target_weight; pos++) { current_weight += nodes[pos + 1].weight; } #else // ... and that the much faster binary search uint32 diff = 1; sint8 counter = 0; // now make sure, diff is 2^n while (diff <= count) { diff <<= 1; counter++; } diff >>= 1; uint pos = diff; // now search while (counter-- > 0) { diff = (diff + 1) >> 1; if (pos < count && weight_at(pos) <= target_weight) { if (weight_at(pos + 1) > target_weight) break; pos += diff; } else { pos -= diff; } } #endif //DBG_DEBUG("at_weight()", "target_weight=%i found_weight=%i at pos %i", target_weight, weight_at(pos), pos); return nodes[pos].data; } /** Gets the number of elements in the vector */ uint32 get_count() const { return count; } /** Gets the capacity */ uint32 get_size() const { return size; } /** Gets the total weight */ uint32 get_sum_weight() const { return total_weight; } bool empty() const { return count == 0; } iterator begin() { return iterator(nodes); } iterator end() { return iterator(nodes + count); } const_iterator begin() const { return const_iterator(nodes); } const_iterator end() const { return const_iterator(nodes + count); } private: nodestruct* nodes; uint32 size; ///< Capacity uint32 count; ///< Number of elements in vector uint32 total_weight; ///< Sum of all weights weighted_vector_tpl(const weighted_vector_tpl& other); weighted_vector_tpl& operator=( weighted_vector_tpl const& other ); private: friend void swap<>(weighted_vector_tpl&, weighted_vector_tpl&); }; template void swap(weighted_vector_tpl& a, weighted_vector_tpl& b) { sim::swap(a.nodes, b.nodes); sim::swap(a.size, b.size); sim::swap(a.count, b.count); sim::swap(a.total_weight, b.total_weight); } #endif simutrans-124.3/src/simutrans/utils/000077500000000000000000000000001474050137200175275ustar00rootroot00000000000000simutrans-124.3/src/simutrans/utils/cbuffer.cc000066400000000000000000000325641474050137200214640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include #include "cbuffer.h" #include "simstring.h" #include "../macros.h" #include "../simdebug.h" #include "../simtypes.h" cbuffer_t::cbuffer_t() : capacity(256), size(0), buf(new char[capacity]) { buf[0] = '\0'; } cbuffer_t::~cbuffer_t() { free(); } void cbuffer_t::clear() { buf[0] = '\0'; size = 0; } cbuffer_t::cbuffer_t (const cbuffer_t& cbx) { copy( cbx ); } cbuffer_t::cbuffer_t(const char *txt) { capacity = (txt ? strlen(txt)+1 : 256); buf = new char[capacity]; size = 0; if (txt) { size = capacity-1; strcpy(buf, txt); } } cbuffer_t& cbuffer_t::operator= (const cbuffer_t& cbx) { if ( this != &cbx ) { free(); copy( cbx ); } return *this; } void cbuffer_t::copy (const cbuffer_t& cbx) { capacity = cbx.capacity; size = cbx.size; buf = new char[capacity]; memcpy( buf, cbx.buf, size + 1 ); } void cbuffer_t::free () { delete [] buf; } void cbuffer_t::append(const char * text) { size_t const n = strlen( text ); extend( n ); memcpy( buf + size, text, n + 1); size += n; } void cbuffer_t::append(const char* text, size_t maxchars) { size_t const n = min( strlen( text ), maxchars ); extend( n ); memcpy( buf + size, text, n ); size += n; buf[size] = '\0'; // Ensure buffer is null terminated } void cbuffer_t::append(double n,int decimals) { char tmp[128]; number_to_string( tmp, n, decimals ); append(tmp); } void cbuffer_t::append_money(double money) { char tmp[128]; money_to_string(tmp, money, true); append(tmp); } void cbuffer_t::rtrim() { // remove all trailing whichspaces, i.e. ASCII <= 32 while (size > 0 && buf[size - 1] <= ' ') { size--; } } const char* cbuffer_t::get_str() const { return buf; } /** * Checks the format specifier. * No flags, precision modifiers, n, * are allowed. * @param format points to percent sign * @param position positional parameter (if larger than zero) * @param mask format mask for checking ('?' in case of error) * @returns whether specifier is correct */ static bool check_format_specifier(const char*& format, int& position, char& mask) { mask = '?'; // skip % assert(*format == '%'); format++; // %[n$][flags][width][.precision][length]specifier int n = atoi(format); // skip numbers while(*format && ('0'<=*format && *format<='9') ) format++; // positional argument? position = *format == '$' ? n : -1; // skip $ if (*format == '$') format++; // no flags // skip numbers (width) while(*format && ('0'<=*format && *format<='9') ) format++; // skip . if (*format == '.') format++; // no precision modifiers allowed // skip numbers (precision) while(*format && ('0'<=*format && *format<='9') ) format++; // now the specifier static const char* all_types = "cdiouxXeEfFgGaAsp%"; // no n static const char* all_masks = "ciiiiiiffffffffsp%"; if (*format) { if (const char* type = strchr(all_types, *format)) { mask = *(all_masks + (type-all_types)); if (mask == '%') { // previous char has to be % as well if ( *(format-1) != '%') { mask = '?'; } } // skip specifier format++; } } return mask != '?'; } /** * Parses string @p format, and puts type identifiers into @p typemask. * If an error occurs, an error message is printed into @p error. * Checks for positional parameters: either all or no parameter have to be positional as eg %1$d. * If positional parameter %[n]$ is specified then all up to n have to be present in the string as well. * Treats all integer parameters %i %u %d etc the same. * Ignores positional width parameters as *[n]. * Positional parameters start with 1. * * @param format format string * @param typemask pointer to array of length @p max_params * @param max_params length of typemask * @param error receives error message */ static void get_format_mask(const char* format, char *typemask, int max_params, cbuffer_t &error) { MEMZERON(typemask, max_params); // count found parameters int found = 0; bool positional = false; while(format && *format) { // skip until percent sign while(*format && *format!='%') format++; if (*format == 0) { break; } int pos; char mask; if (check_format_specifier(format, pos, mask)) { // mixed positional / non-positional arguments? if (found>0 && (positional ^ (pos > 0) )) { goto err_mix_pos_nopos; } // has positional parameters? // allowed range 1 .. max_params if (found == 0) { positional = pos > 0; } if (pos > max_params) { error.printf("Positional parameter too large (pos = %d). ", pos); return; } if (mask != '%') { // ignore %% // no positional parameter // positional parameter is 1-based, indexing is 0-based int idx = pos > 0 ? pos-1 : found; // found valid format typemask[idx] = mask; found++; } } else { error.printf("Format specifier %d contains invalid characters. ", found); return; } } // check whether positional parameters are continuous if (positional) { for(uint16 i=0; i 0) { // broken master string ?! // cannot contain single % signs, use %% instead dbg->warning("cbuffer_t::check_format_strings", "Broken master string '%s': %s", master, (const char*) buf); return false; } // no format specifiers or only %%? Replace %% by %, otherwise leave translated alone. bool has_format = false; for(uint i=0; (master_tm[i]) && (i 0 && repaired_p) { // try to repair repair_format_string(translated, *repaired_p); // and check again buf.clear(); get_format_mask(*repaired_p, translated_tm, lengthof(translated_tm), buf); if (buf.len() == 0) { // acceptable now dbg->warning("cbuffer_t::check_format_strings", "Repaired broken translation string '%.15s' of '%s'.", translated, master); } } if (buf.len() > 0) { // broken translated string dbg->warning("cbuffer_t::check_format_strings", "Broken translation string '%.15s' of '%s': %s", translated, master, (const char*) buf); return false; } // check for consistency for(uint i=0; (translated_tm[i]) && (iwarning("cbuffer_t::check_format_strings", "Translation string '%.15s' has more parameters than master string '%s'", translated, master); return false; } else if (master_tm[i]!=translated_tm[i]) { // wrong type dbg->warning("cbuffer_t::check_format_strings", "Parameter %d in translation string '%.15s' of '%s' has to be of type '%%%c' instead of '%%%c', Typemasks: Master = %s vs Translated = %s", i+1, translated, master, master_tm[i], translated_tm[i], master_tm,translated_tm); return false; } } return true; } /* this is a vsnprintf which can always process positional parameters * like "%2$i: %1$s" * WARNING: posix specification as well as this function always assumes that * ALL parameter are either positional or not!!! * * When numbered argument specifications are used, specifying the Nth argument requires that all the * leading arguments, from the first to the (N-1)th, are specified in the format string. * * ATTENTION: no support for positional precision (which are not used in simutrans anyway! */ static int my_vsnprintf(char *buf, size_t n, const char* fmt, va_list ap ) { #if defined _MSC_FULL_VER && _MSC_FULL_VER >= 140050727 && !defined __WXWINCE__ // this MSC function can handle positional parameters since 2008 return _vsprintf_p(buf, n, fmt, ap); #else #if !defined(HAVE_UNIX98_PRINTF) // this function cannot handle positional parameters if( const char *c=strstr( fmt, "%1$" ) ) { // but they are requested here ... // our routine can only handle max. 9 parameters char pos[14]; static char format_string[256]; char *cfmt = format_string; static char buffer[16000]; // the longest possible buffer ... int count = 0; for( ; c && count<9; count++ ) { sprintf( pos, "%%%i$", count+1 ); c = strstr( fmt, pos ); if( c ) { // extend format string, using 1 as mark between strings if( count ) { *cfmt++ = '\01'; } *cfmt++ = '%'; // now find the end c += 3; int len = strspn( c, "+-0123456789 #.hlI" )+1; while( len-->0 ) { *cfmt++ = *c++; } } } *cfmt = 0; // now printf into buffer int result = vsnprintf( buffer, 16000, format_string, ap ); if( result<0 || result>=16000 ) { *buf = 0; return 0; } // check the length result += strlen(fmt); if( (size_t)result > n ) { // increase the size please ... return result; } // we have enough size: copy everything together *buf = 0; char *cbuf = buf; cfmt = const_cast(fmt); // cast is save, as the string is not modified while( *cfmt!=0 ) { while( *cfmt!='%' && *cfmt ) { *cbuf++ = *cfmt++; } if( *cfmt==0 ) { break; } // get the nth argument char *carg = buffer; int current = cfmt[1]-'1'; for( int j=0; j= capacity - size ) { unsigned int by_amount = min_free_space + 1 - (capacity - size); if( by_amount < capacity ) { // At least double the size of the buffer. by_amount = capacity; } unsigned int new_capacity = capacity + by_amount; char *new_buf = new char [new_capacity]; memcpy( new_buf, buf, capacity ); delete [] buf; buf = new_buf; capacity = new_capacity; } } // remove whitespace and unprinatable characters void cbuffer_t::trim() { while (size > 0) { const unsigned char c = buf[size - 1]; if (c >= 33) { break; } size--; } } simutrans-124.3/src/simutrans/utils/cbuffer.h000066400000000000000000000045011474050137200213140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_CBUFFER_H #define UTILS_CBUFFER_H #include #include /** * A character buffer. Main operation is 'append' */ class cbuffer_t { private: size_t capacity; /** * Number of characters without(!) trailing '\0' */ size_t size; char *buf; /** * Implementation for copy constructor and copy assignment operator */ void copy( const cbuffer_t& cbx ); /** * Implementation for destructor and copy assignment operator */ void free(); public: /** * Number of characters without(!) trailing '\0' */ int len() const { return size; } /** * Creates a new cbuffer with capacity cap */ cbuffer_t(); ~cbuffer_t(); /** * Copy constructor */ cbuffer_t(const cbuffer_t& cbx); cbuffer_t(const char *); /** * Copy assignment operator */ cbuffer_t& operator= (const cbuffer_t& cbx); /** * Clears the buffer */ void clear(); /** * Appends text. Buffer will be extended if it does not have enough capacity. */ void append(const char * text); /** * Appends text, at most n characters worth. Buffer will be extended if needed. * maxchars should NOT include the null at the end of the string! * (e.g. it should be equivalent to the output of strlen()) */ void append(const char* text, size_t maxchars); /** * Removes all trailing whitespaces */ void rtrim(); /** * Return contents of buffer */ const char* get_str() const; /** * Appends a number. Buffer will be extended if it does not have enough capacity. */ void append(double n, int precision); /** * appends formatted money string */ void append_money(double money); /* Append formatted text to the buffer */ void printf(const char *fmt, ...); void vprintf(const char *fmt, va_list args ); /* enlarge the buffer if needed (i.e. size+by_amount larger than capacity) */ void extend(unsigned int by_amount); // removes trailing whitespaces void trim(); /** * Automagic conversion to a const char* for backwards compatibility */ operator const char *() const {return buf;} /// checks whether format specifiers in @p translated match those in @p master static bool check_and_repair_format_strings(const char* master, const char* translated, char **repaired = NULL); }; #endif simutrans-124.3/src/simutrans/utils/checklist.cc000066400000000000000000000026201474050137200220070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "checklist.h" #include "../network/memory_rw.h" #include "../utils/cbuffer.h" checklist_t::checklist_t() : hash(0), random_seed(0), halt_entry(0), line_entry(0), convoy_entry(0) { } checklist_t::checklist_t(const uint32 &hash) : hash(hash), random_seed(0), halt_entry(0), line_entry(0), convoy_entry(0) { } checklist_t::checklist_t(uint32 _random_seed, uint16 _halt_entry, uint16 _line_entry, uint16 _convoy_entry) : hash(0), random_seed(_random_seed), halt_entry(_halt_entry), line_entry(_line_entry), convoy_entry(_convoy_entry) { } bool checklist_t::operator==(const checklist_t& other) const { return hash == other.hash && random_seed==other.random_seed && halt_entry==other.halt_entry && line_entry==other.line_entry && convoy_entry==other.convoy_entry; } bool checklist_t::operator!=(const checklist_t& other) const { return !(*this==other); } void checklist_t::rdwr(memory_rw_t *buffer) { buffer->rdwr_long(hash); buffer->rdwr_long(random_seed); buffer->rdwr_short(halt_entry); buffer->rdwr_short(line_entry); buffer->rdwr_short(convoy_entry); } void checklist_t::print(cbuffer_t &buffer, const char *entity) const { buffer.printf("%s=[adler32=%08x rand=%u halt=%u line=%u cnvy=%u] ", entity, hash, random_seed, halt_entry, line_entry, convoy_entry); } simutrans-124.3/src/simutrans/utils/checklist.h000066400000000000000000000013141474050137200216500ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_CHECKLIST_H #define UTILS_CHECKLIST_H #include "../simtypes.h" class memory_rw_t; class cbuffer_t; struct checklist_t { public: checklist_t(); explicit checklist_t(const uint32 &hash); checklist_t(uint32 _random_seed, uint16 _halt_entry, uint16 _line_entry, uint16 _convoy_entry); bool operator==(const checklist_t &other) const; bool operator!=(const checklist_t &other) const; void rdwr(memory_rw_t *buffer); void print(cbuffer_t &buffer, const char *entity) const; private: uint32 hash; uint32 random_seed; uint16 halt_entry; uint16 line_entry; uint16 convoy_entry; }; #endif simutrans-124.3/src/simutrans/utils/csv.cc000066400000000000000000000132021474050137200206270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include "csv.h" #include "simstring.h" #include "../macros.h" #include "../simtypes.h" CSV_t::CSV_t (const char *csvdata) : lines(1), offset(0), first_field(true) { const char* pos = csvdata; cbuffer_t tmp; int ret; do { // Puts the field pointed to by pos into the cbuffer_t tmp // (While ret is not failure case or end of file - check these!) tmp.clear(); ret = (int)decode( pos, tmp ); switch ( ret ) { case -1: new_line(); pos++; break; case -2: // finished break; case -4: case -5: case -9: // Encountered invalid data, stop parsing break; default: // Encode contents of tmp and add them to our contents pos += ret; add_field( tmp.get_str() ); } } while( ret > -2 ); } int CSV_t::get_next_field (cbuffer_t& buf) { // Sanity check - offset must be less than or equal to the length of contents string if ( strlen( contents.get_str() ) < offset ) { return -5; } // Start at contents + offset (position of next field) const char *pos = contents.get_str() + offset; // Decode into cbuffer_t int ret = (int)decode( pos, buf ); if ( ret >= 0 ) { // Return value is amount to increase offset by // (Number of characters consumed) offset += ret; } return ret; } bool CSV_t::next_line () { // Call get_next_field until EOL, then move forward to next field past newline int r; cbuffer_t tmp; while ( (r = get_next_field( tmp )) >= 0 ) {}; if ( r != -1 ) { // Return code from get_next_field() indicates that there are // no more lines, return false return false; } offset++; return true; } void CSV_t::reset () { offset = 0; } const char *CSV_t::get_str () const { return contents.get_str(); } int CSV_t::get_lines () const { return lines; } void CSV_t::add_field (int newfield) { char tmp[32]; sprintf( tmp, "%i", newfield ); add_field( tmp ); } void CSV_t::add_field (const char *newfield) { // Add comma if this isn't the first field on a line if ( !first_field ) { // If offset is pointing to the EOF character // (e.g. if offset == strlen(contents)) // then advance it by one to point at the start of // the new field // If we don't do this after a call to add_field() // the next call to get_next_field() would always // return an empty string, as offset would point to // the comma preceding the last field, rather than // the last field itself if ( offset == strlen( contents.get_str() ) ) { offset++; } contents.append( "," ); } // CSV encode string and add to buffer encode( newfield, contents ); first_field = false; } void CSV_t::new_line () { // Add newline to buffer contents.append( "\n" ); lines++; first_field = true; } int CSV_t::encode( const char *text, cbuffer_t& output ) { char *n; bool wrap = false; // not empty? if( *text ) { // If text contains a comma, quote, or a line break, needs to be wrapped in quote marks wrap = strpbrk( text, ",\"\r\n" )!=0; // If text has leading or trailing spaces, must be wrapped in quotes if( *text == ' ' || text[strlen( text )-1] == ' ' ) { wrap = true; } } int len = output.len(); if( wrap ) { char* cpy = strdup(text); char* tmp = cpy; output.append( "\"" ); // Replace all '"' with '""' while ( (n = strchr( tmp, '"' )) != NULL ) { *n = '\0'; output.append( tmp ); output.append( "\"\"" ); tmp = n + 1; } output.append( tmp ); output.append( "\"" ); tmp = NULL; free(cpy); } else { output.append( text ); } return output.len() - len; } int CSV_t::decode (const char *start, cbuffer_t& output) { const char *s = start; switch ( *s ) { case '"': { const char *c = s + 1; const char *n; // Start of quoted field, may contain commas and newlines while( 1 ) { n = strchr( c, '"' ); if( n == NULL || *n == '\0' ) { // No matching '"' - malformed field return -9; } switch( *(n + 1) ) { case '"': // Copy everything up to and including the first quote output.append( c, (n - c) + 1 ); c = n + 2; break; case ',': // Copy everything up to the quotes before the comma // Needs to be +1 since output.append puts a '\0' on the last position copied output.append( c, (n - c) ); // Move offset to character after ',' return (int)((n - s) + 2); case '\0': case '\n': case '\r': // Copy everything up to the quotes before the newline/null output.append( c, (n - c) ); // Move offset to last character return (int)((n - s) + 1); default: // Single '"' in the middle of a field - malformed field return -9; } } // one will never reach here ... assert(0); } case '\r': case '\n': return -1; case '\0': return -2; default: { const char *newline = strchr( s, '\n' ); const char *comma = strchr( s, ',' ); if( newline == NULL && comma == NULL ) { // Copy to '\0' + leave offset on '\0' char // Copy all to '\0' into buffer output.append( s, strlen( s ) ); // Offset to point at '\0' return (int)strlen( s ); } if( newline != NULL && (comma == NULL || newline < comma) ) { // Copy up to newline + leave offset on newline char output.append( s, (newline - s) ); return (int)(newline - s); } if( comma != NULL && (newline == NULL || comma < newline) ) { // Copy up to comma + leave offset at next char after output.append( s, (comma - s) ); return (int)((comma - s) + 1); } return -9; } } } simutrans-124.3/src/simutrans/utils/csv.h000066400000000000000000000065311474050137200205000ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_CSV_H #define UTILS_CSV_H #include "cbuffer.h" /* Provides functionality for building a buffer containing CSV encoded data. This is done in a very simple way, building up the block of data field-by-field and line-by-line - this is not intended as a way of representing data for editing! This class is NOT thread safe! Writing: Each string added will be CSV encoded and may contain commas, quotation marks and newlines. The end of a line of data should be indicated by calling the new_line() method. Each new field is added using the add_field() method. There is a constructor which takes a char array containing CSV formatted data to parse, which can then be read as normal. Reading: get_next_field(), next_line() and reset() are used to parse each field in order. Example: Create a new, blank, CSV_t Use the add_field() and add_line() functions to build up the data Then finally read its contents with get_str() Example: CSV_t csv(); csv.add_field("Field1 Header"); csv.add_field("Field2 Header"); csv.new_line(); csv.add_field("field1 data"); csv.add_field("field2, data"); printf(csv.get_str()); // Output would be: Field1 Header,Field2 Header field1 data,"field2, data" */ class CSV_t { // The raw data itself (stored encoded) cbuffer_t contents; // Count of number of lines of CSV data // Note: This is not the same as the number of newlines in the file // since CSV fields can contain encoded newlines int lines; // Offset into cbuffer for current item size_t offset; bool first_field; /* * Escape the input text so it is appropriate to make up a single CSV field * Writes output into the supplied cbuffer_t (appending to the end) * Return length of output string */ int encode( const char *, cbuffer_t& ); /* * Parse the next field from the CSV formatted data pointed to by field * Returns the number of characters consumed from input string * this may be more than the length of output, as it includes CSV formatting * stripped during decoding * Returns -1 for end of line (call next_line()) * Returns -2 for end of data * Returns -9 for corrupt input data (unable to parse any further) */ int decode( const char *, cbuffer_t& ); public: /* Constructors */ CSV_t() : lines(1), offset(0), first_field(true) {} CSV_t( const char * ); /* Methods for reading */ /* * Parse the next field of the current line * Returns -4 if contents are NULL * Returns -5 if offset exceeds contents size * Else returns either the error code output of decode() * or the length of the data consumed from the input string * Field is appended to the cbuffer_t supplied */ int get_next_field( cbuffer_t& ); /* * Move onto the next line * Return true on success, false if there are no more lines */ bool next_line(); /* * Reset parse position to start of data */ void reset(); /* * Return CSV formatted contents */ const char *get_str() const; /* * Return number of lines of CSV data */ int get_lines() const; /* Methods for writing */ /* * Add a field to the current line */ void add_field(const char *); /* * Add a field to the current line (number) */ void add_field(int); /* * Terminate a line of CSV data, and move to the next line */ void new_line(); }; #endif simutrans-124.3/src/simutrans/utils/fetchopt.cc000066400000000000000000000022731474050137200216560ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "fetchopt.h" Fetchopt_t::Fetchopt_t(int argc, char **argv, const char *optstring) { optarg = NULL; optind = 1; optstr = optstring; ac = argc; av = argv; pos = 1; } char *Fetchopt_t::get_optarg() { return optarg; } int Fetchopt_t::get_optind() { return optind; } int Fetchopt_t::next() { optarg = NULL; if (optind >= ac || av[optind][0] != '-') { return -1; } int optchar = av[optind][pos]; const char *offset = strchr(optstr, optchar); if (offset == NULL || optchar == ':') { // Invalid option return '?'; } if (*(offset+1) == ':') { // Option with argument if (av[optind][pos+1] == '\0') { // Use next argument for option's argument if (ac < optind+2) { // Missing argument return '?'; } else { optarg = av[optind+1]; optind += 2; } } else { // Use rest of current argument for option's argument optarg = av[optind]+pos+1; optind++; } pos = 1; return optchar; } else { // Simple option pos++; if (av[optind][pos] == '\0') { // Next argument pos = 1; optind++; } return optchar; } } simutrans-124.3/src/simutrans/utils/fetchopt.h000066400000000000000000000055261474050137200215240ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_FETCHOPT_H #define UTILS_FETCHOPT_H /** This class can be used to parse unix-style single character command line options. It is intended to provide a similar interface to the POSIX getopt() function. The constructor takes the number of arguments (typically the argc value), the array of arguments and an options string describing the options that should be searched for. The value of the options string is constructed from the single-character options flags you wish to search for. A colon ':' following the option indicates that the option should take an argument. It is an error if an option is indicated as having an argument and no argument is found. E.g. the options string "a:bc" indicates that three flags should be searched for: -a (which takes an argument), -b and -c (which do not). The next() method will return the character representing the next option found. When no further options are found it will return -1. If an error condition is encountered the character '?' is returned. The get_optarg() method returns the argument value of the current option (or NULL if the current option does not take an argument). When all option arguments have been parsed the value of get_optind() will be the index into the argv array of the next non-option argument. A return value of '?' indicates an error, program usage ought to be printed if this is encountered. Example: // Parsing the following command line: // mycommand -a override -bc somecommand Fetchopt_t fetchopt(argc, argv, "a:bc"); const char default_arg_a[] = "default"; char *arg_a = default_arg_a; bool flag_b = true; bool flag_c = false; int ch; while ((ch = fetchopt.next()) != -1) { switch (ch) { case 'a': arg_a = fetchopt.get_optarg(); break; case 'b': flag_b = false; break; case 'c': flag_c = true; break; case '?': case 'h': default: usage(); } } // Values will be: // arg_a = "override" // flag_b = false // flag_c i = true // fetchopt.get_optind() = 4 // argv[fetchopt.get_optind()] = "somecommand" */ class Fetchopt_t { const char *optstr; // Options definition string int ac; // argc char **av; // argv char *optarg; // Current option's argument string int optind; // Index of current option in argv int pos; // Position of option within current argument public: Fetchopt_t(int, char **, const char *optstring); char *get_optarg(); int get_optind(); int next(); }; #endif simutrans-124.3/src/simutrans/utils/int_math.h000066400000000000000000000017551474050137200215130ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_INT_MATH_H #define UTILS_INT_MATH_H #include "../simtypes.h" inline int log2(uint64 n) { #define S(k) do { if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; } } while(false) int i = -(n == 0); S(32); S(16); S(8); S(4); S(2); S(1); return i; #undef S } inline int log2(uint32 n) { #define S(k) do { if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; } } while (false) int i = -(n == 0); S(16); S(8); S(4); S(2); S(1); return i; #undef S } inline int log2(uint16 n) { #define S(k) do { if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; } } while(false) int i = -(n == 0); S(8); S(4); S(2); S(1); return i; #undef S } inline int log10(uint64 n) { #define S(k, m) do { if (n >= UINT64_C(m)) { i += k; n /= UINT64_C(m); } } while(false) int i = -(n == 0); S(16,10000000000000000); S(8,100000000); S(4,10000); S(2,100); S(1,10); return i; #undef S } #endif simutrans-124.3/src/simutrans/utils/log.cc000066400000000000000000000227561474050137200206330ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #ifdef SYSLOG #include #endif #include "log.h" #include "../simdebug.h" #include "../sys/simsys.h" #ifdef MAKEOBJ //debuglevel is global variable #define dr_fopen fopen #else #ifdef NETTOOL #define debuglevel (0) #define dr_fopen fopen #else #define debuglevel (env_t::verbose_debug) // for display ... #include "../gui/messagebox.h" #include "../display/simgraph.h" #include "../gui/simwin.h" #include "../dataobj/environment.h" #endif #endif #ifdef __ANDROID__ #include #include "cbuffer.h" #define LOG_TAG "com.simutrans" #endif /** * writes a debug message into the log. */ void log_t::debug(const char *who, const char *format, ...) { if(log_debug && debuglevel >= log_t::LEVEL_DEBUG) { va_list argptr; va_start(argptr, format); if( log ) { /* only log when a log */ fprintf(log ,"Debug: %s:\t",who); /* is already open */ vfprintf(log, format, argptr); fprintf(log,"\n"); if( force_flush ) { fflush(log); } } va_end(argptr); va_start(argptr, format); if( tee ) { /* only log when a log */ fprintf(tee, "Debug: %s:\t",who); /* is already open */ vfprintf(tee, format, argptr); fprintf(tee,"\n"); } va_end(argptr); #ifdef SYSLOG va_start( argptr, format ); if ( syslog ) { // Replace with dynamic memory allocation char buffer[4096]; sprintf( buffer, "Debug: %s\t%s", who, format ); vsyslog( LOG_DEBUG, buffer, argptr ); } va_end( argptr ); #endif #ifdef __ANDROID__ va_start(argptr, format); cbuffer_t buffer; buffer.printf("Debug: %s\t%s", who, format); __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, buffer, argptr); va_end( argptr ); #endif } } /** * writes a message into the log. */ void log_t::message(const char *who, const char *format, ...) { if(debuglevel >= log_t::LEVEL_MSG) { va_list argptr; va_start(argptr, format); if( log ) { /* only log when a log */ fprintf(log ,"Message: %s:\t",who); /* is already open */ vfprintf(log, format, argptr); fprintf(log,"\n"); if( force_flush ) { fflush(log); } } va_end(argptr); va_start(argptr, format); if( tee ) { /* only log when a log */ fprintf(tee, "Message: %s:\t",who); /* is already open */ vfprintf(tee, format, argptr); fprintf(tee,"\n"); } va_end(argptr); #ifdef SYSLOG va_start( argptr, format ); if ( syslog ) { // Replace with dynamic memory allocation char buffer[4096]; sprintf( buffer, "Message: %s\t%s", who, format ); vsyslog( LOG_INFO, buffer, argptr ); } va_end( argptr ); #endif #ifdef __ANDROID__ va_start(argptr, format); cbuffer_t buffer; buffer.printf("Message: %s\t%s", who, format); __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, buffer, argptr); va_end( argptr ); #endif } } /** * writes a warning into the log. */ void log_t::warning(const char *who, const char *format, ...) { if(debuglevel >= log_t::LEVEL_WARN) { va_list argptr; va_start(argptr, format); if( log ) { /* only log when a log */ fprintf(log ,"Warning: %s:\t",who); /* is already open */ vfprintf(log, format, argptr); fprintf(log,"\n"); if( force_flush ) { fflush(log); } } va_end(argptr); va_start(argptr, format); if( tee ) { /* only log when a log */ fprintf(tee, "Warning: %s:\t",who); /* is already open */ vfprintf(tee, format, argptr); fprintf(tee,"\n"); } va_end(argptr); #ifdef SYSLOG va_start( argptr, format ); if ( syslog ) { // Replace with dynamic memory allocation char buffer[4096]; sprintf( buffer, "Warning: %s\t%s", who, format ); vsyslog( LOG_WARNING, buffer, argptr ); } va_end( argptr ); #endif #ifdef __ANDROID__ va_start(argptr, format); cbuffer_t buffer; buffer.printf("Debug: %s\t%s", who, format); __android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, buffer, argptr); va_end( argptr ); #endif } } /** * writes an error into the log. */ void log_t::error(const char *who, const char *format, ...) { if(debuglevel >= log_t::LEVEL_ERROR) { va_list argptr; va_start(argptr, format); if( log ) { /* only log when a log */ fprintf(log ,"ERROR: %s:\t",who); /* is already open */ vfprintf(log, format, argptr); fprintf(log,"\n"); if( force_flush ) { fflush(log); } fprintf(log ,"For help with this error or to file a bug report please see the Simutrans forum:\n"); fprintf(log ,"https://forum.simutrans.com\n"); } va_end(argptr); va_start(argptr, format); if( tee ) { /* only log when a log */ fprintf(tee, "ERROR: %s:\t",who); /* is already open */ vfprintf(tee, format, argptr); fprintf(tee,"\n"); fprintf(tee ,"For help with this error or to file a bug report please see the Simutrans forum:\n"); fprintf(tee ,"https://forum.simutrans.com\n"); } va_end(argptr); #ifdef SYSLOG va_start( argptr, format ); if ( syslog ) { // Replace with dynamic memory allocation char buffer[4096]; sprintf( buffer, "ERROR: %s\t%s", who, format ); vsyslog( LOG_ERR, buffer, argptr ); } va_end( argptr ); #endif #ifdef __ANDROID__ va_start(argptr, format); cbuffer_t buffer; buffer.printf("ERROR: %s\t%s", who, format); __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, buffer, argptr); va_end( argptr ); #endif } } /** * writes an error into the log, aborts the program. */ void log_t::fatal(const char* who, const char* format, ...) { va_list argptr; va_start(argptr, format); static char formatbuffer[512]; sprintf(formatbuffer, "FATAL ERROR: %s - %s\n" "Aborting program execution ...\n" "\n" "For help with this error or to file a bug report please see the Simutrans forum at\n" "https://forum.simutrans.com\n", who, format); static char buffer[8192]; vsprintf(buffer, formatbuffer, argptr); va_end(argptr); custom_fatal(buffer); } void log_t::custom_fatal(char *buffer) { if( log ) { fputs( buffer, log ); if ( force_flush ) { fflush( log ); } } if( tee && log!=tee ) { fputs( buffer, tee ); } #ifdef SYSLOG if ( syslog ) { ::syslog( LOG_ERR, buffer ); } #endif if ( tee == NULL && log == NULL && tag == NULL ) { fputs( buffer, stderr ); } #if defined MAKEOBJ exit(EXIT_FAILURE); #elif defined NETTOOL // no display available puts( buffer ); exit(1); #else env_t::verbose_debug = log_t::LEVEL_FATAL; // no more window concerning messages if(is_display_init()) { // show notification destroy_all_win( true ); strcat( buffer, "PRESS ANY KEY\n" ); fatal_news* sel = new fatal_news(buffer); scr_coord xy( display_get_width()/2 - sel->get_windowsize().w/2, display_get_height()/2 - sel->get_windowsize().h/2 ); event_t ev; create_win( xy, sel, w_info, magic_none ); while(win_is_top(sel)) { // do not move, do not close it! dr_sleep(50); dr_prepare_flush(); sel->draw( xy, sel->get_windowsize() ); dr_flush(); display_poll_event(&ev); // main window resized check_pos_win(&ev,true); if(ev.ev_class==EVENT_KEYBOARD) { break; } } } else { // use OS means, if there dr_fatal_notify(buffer); } abort(); #endif } void log_t::vmessage(const char *what, const char *who, const char *format, va_list args ) { if(debuglevel >= LEVEL_ERROR) { va_list args2; va_copy(args2, args); if( log ) { /* only log when a log */ fprintf(log ,"%s: %s:\t", what, who); /* is already open */ vfprintf(log, format, args); fprintf(log,"\n"); if( force_flush ) { fflush(log); } } if( tee ) { /* only log when a log */ fprintf(tee,"%s: %s:\t", what, who); /* is already open */ vfprintf(tee, format, args2); fprintf(tee,"\n"); } va_end(args2); } } // create a logfile for log_debug=true log_t::log_t( const char *logfilename, bool force_flush, bool log_debug, bool log_console, const char *greeting, const char* syslogtag ) : log(NULL), tee(NULL), force_flush(force_flush), // if true will always flush when an entry is written to the log log_debug(log_debug), tag(NULL) #ifdef SYSLOG , syslog(false) #endif { if(logfilename == NULL) { log = NULL; /* not a log */ tee = NULL; } else if(strcmp(logfilename,"stdio") == 0) { log = stdout; tee = NULL; } else if(strcmp(logfilename,"stderr") == 0) { log = stderr; tee = NULL; #ifdef SYSLOG } else if( strcmp( logfilename, "syslog" ) == 0 ) { syslog = true; if ( syslogtag ) { tag = syslogtag; // Set up syslog openlog( tag, LOG_PID, LOG_DAEMON ); } log = NULL; tee = NULL; #endif } else { log = dr_fopen(logfilename,"wb"); if(log == NULL) { fprintf(stderr,"log_t::log_t: can't open file '%s' for writing\n", logfilename); } tee = stderr; } if (!log_console) { tee = NULL; } if( greeting ) { if( log ) { fputs( greeting, log ); // message("log_t::log_t","Starting logging to %s", logfilename); } if( tee ) { fputs( greeting, tee ); } #ifdef SYSLOG if ( syslog ) { ::syslog( LOG_NOTICE, greeting ); } #else (void)syslogtag; #endif } } void log_t::close() { message("log_t::~log_t","stop logging, closing log file"); if( log ) { fclose(log); log = NULL; } } // close all logs during cleanup log_t::~log_t() { if( log ) { close(); } } simutrans-124.3/src/simutrans/utils/log.h000066400000000000000000000037771474050137200204770ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_LOG_H #define UTILS_LOG_H #include #include #include #include "../simtypes.h" /** * Logging facility */ class log_t { public: enum level_t { LEVEL_FATAL = 0, LEVEL_ERROR = 1, LEVEL_WARN = 2, LEVEL_MSG = 3, LEVEL_DEBUG = 4 }; private: /** * Primary log file. */ FILE *log; /** * Secondary log file, currently fixed to stderr */ FILE * tee; bool force_flush; /** * Logging level - include debug messages ? */ bool log_debug; /** * Syslog tag */ const char* tag; #ifdef SYSLOG /** * Log to syslog? */ bool syslog; #endif public: /** * writes a debug message into the log. */ void debug(const char *who, const char *format, ...); /** * writes a message into the log. */ void message(const char *who, const char *format, ...); /** * writes a warning into the log. */ void warning(const char *who, const char *format, ...); /** * writes an error into the log. */ void error(const char *who, const char *format, ...); /** * writes an error into the log, aborts the program. */ void NORETURN fatal(const char* who, const char* format, ...); /** * writes an error into the log, aborts the program, use own messsgae. */ void NORETURN custom_fatal(char* error_str); /** * writes an error into the log, aborts the program. */ void NORETURN custom_fatal(const char* error_str); /** * writes to log using va_lists */ void vmessage(const char *what, const char *who, const char *format, va_list args ); void close(); /** * @param logname * @param fource_flush * @param log_debug * @param log_console * @param greeting * @param syslogtag only used with syslog */ log_t(const char* logname, bool force_flush, bool log_debug, bool log_console, const char* greeting, const char* syslogtag=NULL); ~log_t(); }; #if defined(MAKEOBJ) extern log_t::level_t debuglevel; #endif #endif simutrans-124.3/src/simutrans/utils/plainstring.h000066400000000000000000000026201474050137200222320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_PLAINSTRING_H #define UTILS_PLAINSTRING_H #include #include "../simtypes.h" class plainstring { public: plainstring() : str_(NULL) {} plainstring(char const* const s) : str_(copy_string(s)) {} plainstring(const plainstring &other) : str_(copy_string(other.c_str())) {} ~plainstring() { delete [] str_; } plainstring& operator =(char const* const o) { char* const s = copy_string(o); delete [] str_; str_ = s; return *this; } plainstring& operator =(plainstring const& o) { return *this = o.str_; } char const* c_str() const { return str_; } operator char const*() const { return str_; } operator char*() { return str_; } bool operator ==(const plainstring o) const { return *this==o.c_str(); } bool operator !=(const plainstring o) const { return !(*this == o.c_str()); } bool operator ==(char const* const o) const { return str_ && o ? std::strcmp(str_, o) == 0 : str_ == o; } bool operator !=(char const* const o) const { return !(*this == o); } private: static char* copy_string(char const* const s) { if (s) { size_t const n = std::strlen(s) + 1; return static_cast(std::memcpy(new char[n], s, n)); } else { return 0; } } char* str_; }; void free(plainstring const&) = delete; #endif simutrans-124.3/src/simutrans/utils/searchfolder.cc000066400000000000000000000154711474050137200225070ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #ifndef _WIN32 # include # include # include #else # ifndef NOMINMAX # define NOMINMAX # endif # include # include #endif #include "../simdebug.h" #include "../simmem.h" #include "../simtypes.h" #include "simstring.h" #include "searchfolder.h" /* * * Description: * If filepath ends with a slash, search for all files in the * directory having the given extension. * If filepath does not end with a slash and it also doesn't contain * a dot after the last slash, then append extension to filepath and * search for it. * Otherwise searches directly for filepath. * * No wildcards please! */ void searchfolder_t::add_entry(const std::string &path, const char *entry, const bool prepend) { const size_t entry_len = strlen(entry); char *c = MALLOCN(char, path.length() + entry_len + 1); if(prepend) { sprintf(c,"%s%s",path.c_str(),entry); } else{ sprintf(c,"%s",entry); } files.append(c); } void searchfolder_t::clear_list() { for(char* const i : files) { free(i); } files.clear(); } int searchfolder_t::search(const std::string &filepath, const std::string &extension, const search_flags_t search_flags, const int max_depth ) { clear_list(); return prepare_search(filepath, extension, search_flags, max_depth); } int searchfolder_t::prepare_search(const std::string &filepath, const std::string &extension, const search_flags_t search_flags, const int max_depth ) { std::string path(filepath); std::string name; std::string ext; #ifdef _WIN32 // since we assume hardcoded path are using / we need to correct this for windows for( uint i=0; i 0 ) ) { search_path(path + entry_name + '/', name, ext, search_flags, max_depth - 1); } } delete[] entry_name; } while(_wfindnext(hfind, &entry) == 0 ); _findclose(hfind); #else assert(path.empty() || path[path.length()-1] == '/'); lookfor = path + "."; if (DIR* const dir = opendir(lookfor.c_str())) { int dir_fd = dirfd(dir); if( dir_fd == -1 ) { goto close_dir; } lookfor = name + ext; while (dirent const* const entry = readdir(dir)) { if(entry->d_name[0]!='.' || (entry->d_name[1]!='.' && entry->d_name[1]!=0)) { bool is_dir = false; if( entry->d_type == DT_DIR ) { is_dir = true; } else if( entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK ) { struct stat st; if( fstatat(dir_fd, entry->d_name, &st, 0) == -1 ) { continue; } is_dir = S_ISDIR(st.st_mode); } if( is_dir && (search_flags&SF_NOADDONS) && !STRICMP(entry->d_name, "addons") ) { continue; } if (only_directories) { if( is_dir ) { add_entry(path, entry->d_name, prepend_path); } } else if (filename_matches_pattern(entry->d_name, lookfor.c_str())) { add_entry(path, entry->d_name, prepend_path); } if( is_dir && max_depth > 0 ) { search_path(path + entry->d_name + '/', name, ext, search_flags, max_depth - 1); } } } close_dir: closedir(dir); } #endif } #ifdef _WIN32 std::string searchfolder_t::complete(const std::string &filepath_raw, const std::string &extension) { std::string filepath(filepath_raw); // since we assume hardcoded path are using / we need to correct this for windows for( uint i=0; i #include "../tpl/vector_tpl.h" /** * Searches a disk folder for files matching certain restrictions. */ class searchfolder_t { public: enum search_flags_t : uint8 { SF_NONE = 0, SF_ONLYDIRS = 1 << 0, ///< Extra restriction, will only consider directory entries. If not specified, will search both file and directory entries. SF_PREPEND_PATH = 1 << 1, ///< Will force prepending the base path to the output on each entry. SF_NOADDONS = 1 << 2 ///< If set, subdrectories named "addons" will not be searched. }; public: ~searchfolder_t(); /** * Executes the requested file search. It will look in subdirectories recursively when a max_depth is given. * * @param filepath Base path to search in. * @param extension Extension of files to search for. Input a empty string to not enforce the restriction. * * @param only_directories Extra restriction, will only consider directory entries. * @param prepend_path Will force prepending the base path to the output on each entry. * * @param flags * @param max_depth Maximum depth of recursive search (0=search only the directory given by @p filepath). * @returns Number of files that matched the search parameters. */ int search(const std::string &filepath, const std::string &extension, search_flags_t flags = SF_PREPEND_PATH, const int max_depth = 0); /** * Appends the extension to the file name if it's not a directory * @param filepath Path to the file * @param extension File name extension to append if the conditions are meet */ static std::string complete(const std::string &filepath, const std::string &extension); /** * Function results will be accessible only in a const iterator fashion. */ typedef vector_tpl::const_iterator const_iterator; /** * Gets the first entry iterator. */ const_iterator begin() const { return files.begin(); } /** * Gets the last entry iterator. */ const_iterator end() const { return files.end(); } private: /** * Make the preparations for the search and then call search_path to do the actual search. * * @param filepath Base path to search in. (This path can have either / or \ as deliminator on windows. * @param extension Extension of files to search for. Input a empty string to not enforce the restriction. * * @param only_directories Extra restriction, will only consider directory entries. * @param prepend_path Will force prepending the base path to the output on each entry. * * @param search_flag * @param max_depth Maximum depth of recursive search. */ int prepare_search(const std::string &filepath, const std::string &extension, search_flags_t search_flags, const int max_depth = 0); /** * Real implementation of the search. It will call itself recursively to search in subdirectories when a max_depth is given. * * @param path Path to search in. (This path can have either / or \ as deliminator on windows. * @param name Name of file to search. It will be "*" if not searching for an specific file. * @param ext Extension of files to search for. * * @param only_directories Extra restriction, will only consider directory entries. * @param prepend_path Will force prepending the base path to the output on each entry. * * @param search_flag * @param max_depth Maximum depth of recursive search. */ void search_path(const std::string path, const std::string name, const std::string ext, search_flags_t search_flags, const int max_depth = 0 ); /** * We store the result of the search on this list */ vector_tpl files; /** * Adds one entry to the list. * @param path Qualified path to the directory of the entry. * @param entry Filename of the file to add. * @param prepend Add the full path to the file or just the file name. */ void add_entry(const std::string &path, const char *entry, const bool prepend ); /** * Checks if @p fn matches @p pattern, case insensitive. * @param pattern may start with an * as a wildcard that matches 0 or more characters. */ bool filename_matches_pattern(const char *fn, const char *pattern); /** * Clears the search results. */ void clear_list(); }; ENUM_BITSET(searchfolder_t::search_flags_t); #endif simutrans-124.3/src/simutrans/utils/sha1.cc000066400000000000000000000201741474050137200206760ustar00rootroot00000000000000/* * sha1.cpp * * Copyright (C) 1998, 2009 * Paul E. Jones * All Rights Reserved. * ***************************************************************************** * $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $ ***************************************************************************** * * Description: * This class implements the Secure Hashing Standard as defined * in FIPS PUB 180-1 published April 17, 1995. * * The Secure Hashing Standard, which uses the Secure Hashing * Algorithm (SHA), produces a 160-bit message digest for a * given data stream. In theory, it is highly improbable that * two messages will produce the same message digest. Therefore, * this algorithm can serve as a means of providing a "fingerprint" * for a message. * * Caveats: * SHA-1 is designed to work with messages less than 2^64 bits long. * Although SHA-1 allows a message digest to be generated for * messages of any number of bits less than 2^64, this implementation * only works with messages with a length that is a multiple of 8 * bits. * */ #include #include "sha1.h" /* * Reset * * Description: * This function will initialize the sha1 class member variables * in preparation for computing a new message digest. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ void SHA1::Reset() { Length_Low = 0; Length_High = 0; Message_Block_Index = 0; H[0] = 0x67452301; H[1] = 0xEFCDAB89; H[2] = 0x98BADCFE; H[3] = 0x10325476; H[4] = 0xC3D2E1F0; Computed = false; Corrupted = false; } /* * Result * * Description: * This function will return the 160-bit message digest into the * array provided. * * Parameters: * message_digest_array: [out] * This is an array of five uint32 integers which will be filled * with the message digest that has been computed. * * Returns: * True if successful, false if it failed. * * Comments: * */ bool SHA1::Result(sha1_hash_t &result_digest) { if (Corrupted) { return false; } if (!Computed) { PadMessage(); Computed = true; } #ifdef SIM_BIG_ENDIAN uint32 H_little_endian[5]; for(int i = 0; i < 5; i++) { H_little_endian[i] = endian( H[i] ); } result_digest = sha1_hash_t((const uint8 *)H_little_endian); #else result_digest = sha1_hash_t((const uint8 *)H); #endif return true; } /* * Input * * Description: * This function accepts an array of octets as the next portion of * the message. * * Parameters: * message_array: [in] * An array of characters representing the next portion of the * message. * * Returns: * Nothing. * * Comments: * */ void SHA1::Input( const char *message_array, uint32 length) { if (!length) { return; } if (Computed || Corrupted) { Corrupted = true; return; } while(length-- && !Corrupted) { Message_Block[Message_Block_Index++] = (*message_array & 0xFF); Length_Low += 8; Length_Low &= 0xFFFFFFFF; // Force it to 32 bits if (Length_Low == 0) { Length_High++; Length_High &= 0xFFFFFFFF; // Force it to 32 bits if (Length_High == 0) { Corrupted = true; // Message is too long } } if (Message_Block_Index == 64) { ProcessMessageBlock(); } message_array++; } } /* * Input * * Description: * This function accepts a single octets as the next message element. * * Parameters: * message_element: [in] * The next octet in the message. * * Returns: * Nothing. * * Comments: * */ void SHA1::Input(char message_element) { Input(&message_element, 1); } /* * ProcessMessageBlock * * Description: * This function will process the next 512 bits of the message * stored in the Message_Block array. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * Many of the variable names in this function, especially the single * character names, were used because those were the names used * in the publication. * */ void SHA1::ProcessMessageBlock() { const uint32 K[] = { // Constants defined for SHA-1 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; int t; // Loop counter uint32 temp; // Temporary word value uint32 W[80]; // Word sequence uint32 A, B, C, D, E; // Word buffers /* * Initialize the first 16 words in the array W */ for(t = 0; t < 16; t++) { W[t] = ((uint32) Message_Block[t * 4]) << 24; W[t] |= ((uint32) Message_Block[t * 4 + 1]) << 16; W[t] |= ((uint32) Message_Block[t * 4 + 2]) << 8; W[t] |= ((uint32) Message_Block[t * 4 + 3]); } for(t = 16; t < 80; t++) { W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); } A = H[0]; B = H[1]; C = H[2]; D = H[3]; E = H[4]; for(t = 0; t < 20; t++) { temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 20; t < 40; t++) { temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 40; t < 60; t++) { temp = CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } for(t = 60; t < 80; t++) { temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; temp &= 0xFFFFFFFF; E = D; D = C; C = CircularShift(30,B); B = A; A = temp; } H[0] = (H[0] + A) & 0xFFFFFFFF; H[1] = (H[1] + B) & 0xFFFFFFFF; H[2] = (H[2] + C) & 0xFFFFFFFF; H[3] = (H[3] + D) & 0xFFFFFFFF; H[4] = (H[4] + E) & 0xFFFFFFFF; Message_Block_Index = 0; } /* * PadMessage * * Description: * According to the standard, the message must be padded to an even * 512 bits. The first padding bit must be a '1'. The last 64 bits * represent the length of the original message. All bits in between * should be 0. This function will pad the message according to those * rules by filling the message_block array accordingly. It will also * call ProcessMessageBlock() appropriately. When it returns, it * can be assumed that the message digest has been computed. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * */ void SHA1::PadMessage() { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second block. */ if (Message_Block_Index > 55) { Message_Block[Message_Block_Index++] = 0x80; while(Message_Block_Index < 64) { Message_Block[Message_Block_Index++] = 0; } ProcessMessageBlock(); while(Message_Block_Index < 56) { Message_Block[Message_Block_Index++] = 0; } } else { Message_Block[Message_Block_Index++] = 0x80; while(Message_Block_Index < 56) { Message_Block[Message_Block_Index++] = 0; } } /* * Store the message length as the last 8 octets */ Message_Block[56] = (Length_High >> 24) & 0xFF; Message_Block[57] = (Length_High >> 16) & 0xFF; Message_Block[58] = (Length_High >> 8) & 0xFF; Message_Block[59] = (Length_High) & 0xFF; Message_Block[60] = (Length_Low >> 24) & 0xFF; Message_Block[61] = (Length_Low >> 16) & 0xFF; Message_Block[62] = (Length_Low >> 8) & 0xFF; Message_Block[63] = (Length_Low) & 0xFF; ProcessMessageBlock(); } /* * CircularShift * * Description: * This member function will perform a circular shifting operation. * * Parameters: * bits: [in] * The number of bits to shift (1-31) * word: [in] * The value to shift (assumes a 32-bit integer) * * Returns: * The shifted value. * * Comments: * */ uint32 SHA1::CircularShift(int bits, uint32 word) { return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits)); } simutrans-124.3/src/simutrans/utils/sha1.h000066400000000000000000000040251474050137200205350ustar00rootroot00000000000000/* * sha1.h * * Copyright (C) 1998, 2009 * Paul E. Jones * All Rights Reserved. * ***************************************************************************** * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ ***************************************************************************** * * Description: * This class implements the Secure Hashing Standard as defined * in FIPS PUB 180-1 published April 17, 1995. * * Many of the variable names in this class, especially the single * character names, were used because those were the names used * in the publication. * * Please read the file sha1.cpp for more information. * */ #ifndef UTILS_SHA1_H #define UTILS_SHA1_H #include "sha1_hash.h" class SHA1 { public: SHA1() { Reset(); } /* * Re-initialize the class */ void Reset(); /* * Returns the message digest */ bool Result(sha1_hash_t &result_digest); /* * Provide input to SHA1 */ void Input( const char *message_array, uint32 length); void Input( char message_element); private: /* * Process the next 512 bits of the message */ void ProcessMessageBlock(); /* * Pads the current message block to 512 bits */ void PadMessage(); /* * Performs a circular left shift operation */ inline unsigned CircularShift(int bits, unsigned word); uint32 H[5]; // Message digest buffers uint32 Length_Low; // Message length in bits uint32 Length_High; // Message length in bits uint8 Message_Block[64]; // 512-bit message blocks int Message_Block_Index; // Index into message block array bool Computed; // Is the digest computed? bool Corrupted; // Is the message digest corrupted? }; #endif simutrans-124.3/src/simutrans/utils/sha1_hash.cc000066400000000000000000000015711474050137200217010ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "sha1_hash.h" #include "sha1.h" #include "../macros.h" #include sha1_hash_t::sha1_hash_t() { clear(); } sha1_hash_t::sha1_hash_t(const uint8 *value) { memcpy(hash, value, 20); } void sha1_hash_t::clear() { MEMZERO(hash); } bool sha1_hash_t::empty() const { for (uint8 const* i = hash; i != endof(hash); ++i) { if (*i != 0) { return false; } } return true; } uint8 & sha1_hash_t::operator[](const size_t i) { assert(i < 20); return hash[i]; } const uint8 & sha1_hash_t::operator[](size_t i) const { assert(i < 20); return hash[i]; } bool sha1_hash_t::operator==(const sha1_hash_t &o) const { return memcmp(hash, o.hash, 20) == 0; } bool sha1_hash_t::operator!=(const sha1_hash_t& o) const { return memcmp(hash, o.hash, 20) != 0; } simutrans-124.3/src/simutrans/utils/sha1_hash.h000066400000000000000000000012751474050137200215440ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_SHA1_HASH_H #define UTILS_SHA1_HASH_H #include "../simtypes.h" /** * Stores the value of a SHA-1 message digest. */ class sha1_hash_t { public: /// @warning @p raw_value must be at least 20 bytes long sha1_hash_t(const uint8 *raw_value); /// Initializes hash to all zeroes sha1_hash_t(); public: void clear(); bool empty() const; uint8 &operator[](size_t i); const uint8 &operator[](size_t i) const; bool operator==(const sha1_hash_t &o) const; bool operator!=(const sha1_hash_t &o) const; private: uint8 hash[20]; }; typedef sha1_hash_t pwd_hash_t; #endif simutrans-124.3/src/simutrans/utils/simrandom.cc000066400000000000000000000215221474050137200220310ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "simrandom.h" #include "../sys/simsys.h" #include "../dataobj/loadsave.h" /* This is the mersenne random generator: More random and faster! */ /* Period parameters */ #define MERSENNE_TWISTER_N 624 #define M 397 #define MATRIX_A 0x9908b0dfUL /* constant vector a */ #define UPPER_MASK 0x80000000UL /* most significant w-r bits */ #define LOWER_MASK 0x7fffffffUL /* least significant r bits */ static uint32 mersenne_twister[MERSENNE_TWISTER_N]; // the array for the state vector static uint32 mersenne_twister_index = MERSENNE_TWISTER_N + 1; // mersenne_twister_index==N+1 means mersenne_twister[N] is not initialized static uint8 random_origin = 0; /* initializes mersenne_twister[N] with a seed */ static void init_genrand(uint32 s) { mersenne_twister[0]= s & 0xffffffffUL; for (mersenne_twister_index=1; mersenne_twister_index> 30)) + mersenne_twister_index); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mersenne_twister[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ mersenne_twister[mersenne_twister_index] &= 0xffffffffUL; /* for >32 bit machines */ } } /* generate N words at one time */ static void MTgenerate() { static uint32 mag01[2]={0x0UL, MATRIX_A}; uint32 y; int kk; if (mersenne_twister_index == MERSENNE_TWISTER_N+1) /* if init_genrand() has not been called, */ init_genrand(5489UL); /* a default initial seed is used */ for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; } for (;kk> 1) ^ mag01[y & 0x1UL]; } y = (mersenne_twister[MERSENNE_TWISTER_N-1]&UPPER_MASK)|(mersenne_twister[0]&LOWER_MASK); mersenne_twister[MERSENNE_TWISTER_N-1] = mersenne_twister[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mersenne_twister_index = 0; } /* returns current seed value */ uint32 get_random_seed() { if (mersenne_twister_index >= MERSENNE_TWISTER_N) { /* generate N words at one time */ MTgenerate(); } return mersenne_twister[mersenne_twister_index]; } /* generates a random number on [0,0xffffffff]-interval */ uint32 simrand_plain() { uint32 y; if (mersenne_twister_index >= MERSENNE_TWISTER_N) { /* generate N words at one time */ MTgenerate(); } y = mersenne_twister[mersenne_twister_index++]; /* Tempering */ y ^= (y >> 11); y ^= (y << 7) & 0x9d2c5680UL; y ^= (y << 15) & 0xefc60000UL; y ^= (y >> 18); return y; } /* generates a random number on [0,max-1]-interval */ uint32 simrand(const uint32 max) { assert( (random_origin&INTERACTIVE_RANDOM) == 0 ); if(max<=1) { // may rather assert this? return 0; } return simrand_plain() % max; } void simrand_rdwr(loadsave_t *file) { xml_tag_t t(file, "simrand"); // rdwr index file->rdwr_long(mersenne_twister_index); // rdwr state vector for (uint32 i=0; irdwr_long(mersenne_twister[i]); } } void clear_random_mode( uint16 mode ) { random_origin &= ~mode; } void set_random_mode( uint16 mode ) { random_origin |= mode; } uint16 get_random_mode() { return random_origin; } static uint32 async_rand_seed = 12345678 + (uint32)time( NULL ); // Do not use dr_time(). It returns 0 on program startup for some platforms (SDL). /* simpler simrand for anything not game critical (like UI) */ uint32 sim_async_rand( uint32 max ) { if( max==0 ) { return 0; } async_rand_seed *= 3141592621u; async_rand_seed ++; return (async_rand_seed >> 8) % max; } static uint32 noise_seed = 0; uint32 setsimrand(uint32 seed,uint32 ns) { uint32 old_noise_seed = noise_seed; if(seed!=0xFFFFFFFF) { init_genrand( seed ); async_rand_seed = seed + dr_time(); // dr_time() ok here. re comment ^^^. setsimrand not called immediately on program startup. random_origin = 0; } if(noise_seed!=0xFFFFFFFF) { noise_seed = ns*15731; } return old_noise_seed; } static double int_noise(const sint32 x, const sint32 y) { uint32 n = (uint32)x + (uint32)y*101U + noise_seed; n = (n<<13) ^ n; return 1.0 - (double)((n * (n * n * 15731U + 789221U) + 1376312589U) & 0x7fffffff) / 1073741824.0; } static float *map = 0; static sint32 map_w=0; void init_perlin_map( sint32 w, sint32 h ) { map_w = w+2; map = new float[map_w*(h+2)]; for( sint32 y=0; y> 12; // 1 / log_2(10) ~~ 1233 / 4096 } uint32 log2(uint32 n) { uint32 i = (n & 0xffff0000) ? 16 : 0; if( (n >>= i) & 0xff00 ) { i |= 8; n >>= 8; } if( n & 0xf0 ) { i |= 4; n >>= 4; } if( n & 0xC ) { i |= 2; n >>= 2; } return i | (n >> 1); } /* compute integer sqrt */ uint32 sqrt_i32(uint32 num) { // taken from https://en.wikipedia.org/wiki/Methods_of_computing_square_roots uint32 res = 0; uint32 bit = 1 << 30; // The second-to-top bit is set: 1<<14 for short // "bit" starts at the highest power of four <= the argument. while( bit > num ) { bit >>= 2; } while( bit != 0 ) { if( num >= res + bit ) { num -= res + bit; res = (res >> 1) + bit; } else { res >>= 1; } bit >>= 2; } return res; } /* compute integer sqrt */ uint64 sqrt_i64(uint64 num) { // taken from https://en.wikipedia.org/wiki/Methods_of_computing_square_roots uint64 res = 0; uint64 bit = (uint64)1 << 62; // The second-to-top bit is set: 1<<14 for short // "bit" starts at the highest power of four <= the argument. while( bit > num ) { bit >>= 2; } while( bit != 0 ) { if( num >= res + bit ) { num -= res + bit; res = (res >> 1) + bit; } else { res >>= 1; } bit >>= 2; } return res; } simutrans-124.3/src/simutrans/utils/simrandom.h000066400000000000000000000047751474050137200217060ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_SIMRANDOM_H #define UTILS_SIMRANDOM_H #include "../simtypes.h" #include class loadsave_t; uint32 get_random_seed(); uint32 setsimrand(uint32 seed, uint32 noise_seed); /* generates a random number on [0,max-1]-interval * without affecting the game state * Use this for UI etc. */ uint32 sim_async_rand(const uint32 max); /* generates a random number on [0,max-1]-interval */ uint32 simrand(const uint32 max); /* generates a random number on [0,0xFFFFFFFFu]-interval */ uint32 simrand_plain(); /// reads/writes the sate of the random number generator void simrand_rdwr(loadsave_t *file); double perlin_noise_2D(const double x, const double y, const double persistence); // for network debugging, i.e. finding hidden simrands in wrong places enum { INTERACTIVE_RANDOM = 1 << 0, STEP_RANDOM = 1 << 1, SYNC_STEP_RANDOM = 1 << 2, LOAD_RANDOM = 1 << 3, MAP_CREATE_RANDOM = 1 << 4, MODAL_RANDOM = 1 << 5 }; void set_random_mode( uint16 ); void clear_random_mode( uint16 ); uint16 get_random_mode(); // just more speed with those (generate a precalculated map, which needs only smoothing) void init_perlin_map( sint32 w, sint32 h ); void exit_perlin_map(); /* Randomly select an entry from the given array. */ template T const& pick_any(T const (&array)[N]) { return array[simrand(N)]; } /* Randomly select an entry from the given container. */ template class U> T const& pick_any(U const& container) { return container[simrand(container.get_count())]; } /* Randomly select an entry from the given array, not affecting game state. */ template T const& pick_any_async(T const (&array)[N]) { return array[sim_async_rand(N)]; } /* Randomly select an entry from the given weighted container. */ template class U> T const& pick_any_weighted(U const& container) { return container.at_weight(simrand(container.get_sum_weight())); } /* Randomly select an entry from the given weighted container, not affecting game state. */ template class U> T const& pick_any_weighted_async(U const& container) { return container.at_weight(sim_async_rand(container.get_sum_weight())); } // compute integer log10 uint32 log10( uint32 v ); uint32 log2( uint32 i ); // compute integer sqrt uint32 sqrt_i32(uint32 num); uint64 sqrt_i64(uint64 num); #endif simutrans-124.3/src/simutrans/utils/simstring.cc000066400000000000000000000220641474050137200220610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simstring.h" #include #include #include static char thousand_sep = ','; static char fraction_sep = '.'; static const char *large_number_string = "M"; static double large_number_factor = 1e99; // off static int thousand_sep_exponent = 3; /** * Set thousand separator, used in money_to_string and * number_to_string */ void set_thousand_sep(char c) { thousand_sep = c; } /** * Set thousand exponent (3=1000, 4=10000), used in money_to_string and * number_to_string */ void set_thousand_sep_exponent(int new_thousand_sep_exponent) { thousand_sep_exponent = new_thousand_sep_exponent>0 ? new_thousand_sep_exponent : 3; } /** * Set fraction separator, used in money_to_string and * number_to_string */ void set_fraction_sep(char c) { fraction_sep = c; } char get_fraction_sep() { return fraction_sep; } const char *get_large_money_string() { return large_number_string; } /** * Set large money abbreviation, used in money_to_string and * number_to_string */ void set_large_amount(const char *s, const double v) { large_number_string = s; large_number_factor = v; } /** * Formats a money value. Uses thousand separator. Two digits precision. * Concludes format with $ sign. Buffer must be large enough, no checks * are made! */ void money_to_string(char * p, double f, const bool show_decimal) { char tmp[128]; char *tp = tmp; int i,l; if( f>1000.0*large_number_factor ) { sprintf( tp, "%.1f", f/large_number_factor ); } else { sprintf( tp, "%.2f", f ); } // skip sign if(*tp == '-') { *p ++ = *tp++; } // format string l = (long)(size_t)(strchr(tp,'.') - tp); i = l % thousand_sep_exponent; if(i != 0) { memcpy(p, tp, i); p += i; *p++ = thousand_sep; } while(i < l) { for( int j=0; j1000.0*large_number_factor ) { // only decimals for smaller numbers; add large number string instead for( i=0; large_number_string[i]!=0; i++ ) { *p++ = large_number_string[i]; } } else if( show_decimal ) { i = l+1; // only decimals for smaller numbers *p++ = fraction_sep; // since it might be longer due to unicode characters while( tp[i]!=0 ) { *p++ = tp[i++]; } } *p++ = '$'; *p = 0; } int number_to_string(char * p, double f, int decimals ) { char tmp[128]; char *tp = tmp; long i,l; bool has_decimals; if( decimals>0 ) { sprintf(tp,"%.*f",decimals,f); has_decimals = true; } else { sprintf(tp,"%.0f", f); // some compilers produce trailing dots then ... has_decimals = strchr(tp,'.')!=NULL; } // skip sign if(*tp == '-') { *p ++ = *tp++; } // format string l = has_decimals ? (long)(size_t)(strchr(tp,'.') - tp) : strlen(tp); i = l % thousand_sep_exponent; if(i != 0) { memcpy(p, tp, i); p += i; *p++ = thousand_sep; } while(i < l) { for( int j=0; j 0 && len <= max_length+decimals+1 ) { tstrncpy( ret, result, len-(decimals) ); return; } // still not fitting: Then we have to really shorten the string number_to_string( result, f/large_number_factor, 2 ); len = strlen( result ); const int llen = strlen(large_number_string); // not fitting: then strip those remaining decimals if( len+llen > max_length ) { result[len-3] = 0; } strcat( result, large_number_string ); strcpy( ret, result ); } /// copies a n into a single line and maximum 128 characters char *make_single_line_string(const char *in,int number_of_lines) { static char buf[64]; int pos; // skip leading whitespaces while(*in=='\n' || *in==' ') { in++; } // start copying for(pos=0; pos<62 && *in!=0 && number_of_lines>0; ) { if((unsigned)(*in)>' ') { buf[pos++] = *in++; } else { // replace new lines by space while(*in=='\n' || *in==' ') { if(*in=='\n') { number_of_lines--; } in++; } buf[pos++] = ' '; } } // trim trailing spaces while(pos>0 && buf[pos-1]==' ') { pos--; } // end mark! buf[pos] = 0; return buf; } /** * Terminated, length limited string copy. Copies at most * n characters. Terminates dest string always by 0. * @return dest */ char *tstrncpy(char *dest, const char *src, size_t n) { if (dest == src) { // source and destination are the same // avoid copying overlapping memory regions return dest; } strncpy(dest, src, n); dest[n-1] = '\0'; return dest; } /** * strcasestr implementation. Search for a pattern in a given string, ignoring case. * @param str: String to search in * @param pattern: The pattern we are looking for. * @returns: A char pointer to the start of the pattern we are looking for in the given string, or NULL if not found. * Original code written by Clifford and shared at StackOverflow: https://stackoverflow.com/a/27304609 */ char *tstrcasestr(const char* str, const char* pattern) { const char* p1 = str; const char* p2 = pattern; const char* r = *p2 == 0 ? str : 0; while( *p1 != 0 && *p2 != 0 ) { if( tolower( (unsigned char)*p1 ) == tolower( (unsigned char)*p2 ) ) { if( r == 0 ) { r = p1; } p2++; } else { p2 = pattern; if( r != 0 ) { p1 = r + 1; } if( tolower( (unsigned char)*p1 ) == tolower( (unsigned char)*p2 ) ) { r = p1; p2++; } else { r = 0; } } p1++; } return *p2 == 0 ? const_cast(r) : NULL; } /** * Removes whitespace from the end of the string. * Modifies the argument! */ void rtrim(char * buf) { for (size_t l = strlen(buf); l-- != 0 && 0 < buf[l] && buf[l] <= 32;) { buf[l] = '\0'; } } /** * Hands back a pointer to the first non-whitespace character * of the argument. The argument must be 0 terminated */ const char * ltrim(const char *p) { while(*p != '\0' && *p > 0 && *p <= 32) { p ++; } return p; } /** * Trims a std::string by removing any beginning and ending space/tab characters. * (Move to simstring?) * @retval std::string The trimmed string. */ std::string trim(const std::string &str_) { std::string str(str_); // left trim std::string::size_type pos = str.find_first_not_of(" \t"); if( pos && pos != std::string::npos ) { str = str.substr(pos); } // right trim pos = str.find_last_not_of(" \t"); if( pos != str.length()-1 && pos != std::string::npos ) { str = str.erase(pos+1); } return str; } char const* strstart(char const* str, char const* start) { while (*start != '\0') { if (*str++ != *start++) return 0; } return str; } /** * Returns the file name without extension (optional) of a qualified filename * including path. * * @param fullpath A nul terminated string with a full qualified file name. * @param with_extension If true, the extension is removed from the filename. * * @retval std::string The filename without extension. */ std::string str_get_filename(const char* fullpath, const bool with_extension) { std::string path = fullpath; // Remove until last \ or / size_t last = path.find_last_of("\\/"); if (last != std::string::npos) { path = path.erase(0, last + 1); } // Remove extension if it's present, will remove from '.' till the end. if (!with_extension) { last = path.find_last_of("."); if (last != std::string::npos) { path = path.erase(last); } } return path; } /** * Returns the path portion of a qualified filename including path. * * @param fullpath A null terminated string with a full qualified file name. */ std::string str_get_basename(const char* fullpath) { std::string path = fullpath; size_t last = path.find_last_of("\\/"); if (last == std::string::npos) { return path; } return path.substr(0, last + 1); } /** * Removes ASCII control characters and the space character from the end of the string * See https://www.ascii-code.com/ * * @param string * @returns the string without control chars at the end */ char* clear_invalid_ending_chars(char* string) { static int MAX_ASCII_CHAR = 32; size_t len = strlen(string); while( len>0 && string[--len] <= MAX_ASCII_CHAR ) { string[len] = 0; } return string; } void str_to_lowercase(std::string& s) { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); } simutrans-124.3/src/simutrans/utils/simstring.h000066400000000000000000000100601474050137200217140ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_SIMSTRING_H #define UTILS_SIMSTRING_H #include #include #include #ifdef __HAIKU__ #include #endif #ifndef STRICMP #ifdef _MSC_VER #define STRICMP stricmp #define STRNICMP strnicmp #else #define STRICMP strcasecmp #define STRNICMP strncasecmp #endif #endif #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__) #endif /** * Set thousand separator, used in money_to_string and * number_to_string */ void set_thousand_sep(char c); #define MULTIPLIER 37 inline unsigned int string_to_hash(const char* p, size_t maxlen) { unsigned int hash = 0; if (p) { const char* start = p; for (; *p && (size_t)(p - start) < maxlen; p++) { hash = MULTIPLIER * hash + (unsigned char)*p; } } return hash; } inline unsigned int string_to_hash(const char* p) { unsigned int hash = 0; if (p) { for (; *p; p++) { hash = MULTIPLIER * hash + (unsigned char)*p; } } return hash; } #undef MULTIPLIER /** * Set fraction separator, used in money_to_string and * number_to_string */ void set_fraction_sep(char c); char get_fraction_sep(); const char *get_large_money_string(); /** * Set thousand exponent (3=1000, 4=10000), used in money_to_string and * number_to_string */ void set_thousand_sep_exponent(int new_thousand_sep_exponent); /** * Set abbreviation and the amount by which large money amounts will be shortened */ void set_large_amount( const char *, const double v ); /** * copies n lines of the source into a buffer * @return a temporary buffer with the result */ char *make_single_line_string(const char *in,int number_of_lines); /** * Formats a money value. Uses thousand separator. Two digits precision. * Concludes format with $ sign. Buffer must be large enough, no checks * are made! */ void money_to_string(char * buf, double f, const bool show_decimal = true); /** * Formats a number value. Uses thousand separator. Buffer must be large enough, * no checks are made! */ int number_to_string(char * buf, double f, int decimal_places ); /* tries to squeeze the number into this amount of given digits * BUT: too large number will still exceed the space */ void number_to_string_fit(char *ret, double f, int decimals, int max_length ); /** * Terminated, length limited string copy. Copies at most * n characters. Terminates dest string always by 0. * @return dest */ char *tstrncpy(char *dest, const char *src, size_t n); /** * strcasestr implementation. Search for a pattern in a given string, ignoring case. * @param str: String to search in * @param pattern: The pattern we are looking for. * @returns: A char pointer to the start of the pattern we are looking for in the given string, or NULL if not found. * Original code written by Clifford and shared at StackOverflow: https://stackoverflow.com/a/27304609 */ char* tstrcasestr(const char* str, const char* pattern); /** * Removes whitespace from the end of the string. * Modifies the argument! */ void rtrim(char *); /** * Hands back a pointer to the first non-whitespace character * of the argument. The argument must be 0 terminated. */ const char * ltrim(const char *); /** * Trim function for std::strings */ std::string trim (const std::string &str ); /** * Returns a pointer to the rest of str if str starts with start. */ char const* strstart(char const* str, char const* start); /** * Returns whether s is a null pointer or the empty string. */ static inline bool strempty(char const* const s) { return !s || s[0] == '\0'; } std::string str_get_filename(const char* fullpath, const bool with_extension); std::string str_get_basename(const char* fullpath); /** * Removes ASCII control characters (and the space character) from the end of the string * See https://www.ascii-code.com/ * * @param string * @returns string without control chars at the end */ char* clear_invalid_ending_chars(char* string); void str_to_lowercase(std::string& s); #endif simutrans-124.3/src/simutrans/utils/simthread.cc000066400000000000000000000036441474050137200220250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "simthread.h" #ifdef MULTI_THREAD // do not try to compile this file for non-multithreaded builds #ifndef _USE_POSIX_BARRIERS // implement barriers using other pthread primitives #include int simthread_barrier_init(simthread_barrier_t *barrier, const simthread_barrierattr_t */*attr*/, unsigned int count) { if( count == 0 ) { errno = EINVAL; return -1; } if( pthread_mutex_init( &barrier->mutex, 0 ) < 0 ) { return -1; } if( pthread_cond_init( &barrier->cond, 0 ) < 0 ) { pthread_mutex_destroy( &barrier->mutex ); return -1; } barrier->tripCount = count; barrier->count = 0; return 0; } int simthread_barrier_destroy(simthread_barrier_t *barrier) { pthread_cond_destroy( &barrier->cond ); pthread_mutex_destroy( &barrier->mutex ); return 0; } int simthread_barrier_wait(simthread_barrier_t *barrier) { pthread_mutex_lock( &barrier->mutex ); barrier->count++; if( barrier->count >= barrier->tripCount ) { barrier->count = 0; pthread_cond_broadcast( &barrier->cond ); pthread_mutex_unlock( &barrier->mutex ); return 1; } else { pthread_cond_wait( &barrier->cond, &barrier->mutex ); pthread_mutex_unlock( &barrier->mutex ); return 0; } } #endif #ifndef _SIMTHREAD_R_MUTEX_I #include "../simdebug.h" // initialize a recursive mutex by calling pthread_mutex_init() recursive_mutex_maker_t::recursive_mutex_maker_t(pthread_mutex_t &mutex) { pthread_mutexattr_t attr; if (pthread_mutexattr_init(&attr) != 0 || pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 || pthread_mutex_init(&mutex, &attr) != 0 || pthread_mutexattr_destroy(&attr) != 0) { // Can't call dbg->error(), because this constructor // may run before simu_main() calls init_logging(). dbg->fatal("recursive_mutex_maker_t","Can't make a recursive mutex!"); } } #endif #endif simutrans-124.3/src/simutrans/utils/simthread.h000066400000000000000000000045231474050137200216640ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_SIMTHREAD_H #define UTILS_SIMTHREAD_H #ifdef MULTI_THREAD #if !defined(__APPLE__) && ( !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 ) // On Posix systems, this enables barriers. // On OS X, barriers are not supported anyway, and defining this would // cause PTHREAD_RECURSIVE_MUTEX_INITIALIZER to not get defined. #define _XOPEN_SOURCE 600 #endif #ifndef _MSC_VER #include // _POSIX_BARRIERS macro // Visual C++ does not supply unistd.h #endif #if defined _MSC_VER && _MSC_VER >= 1900 // MSVC 2015 with Windows 10 SDK has struct timespec #define HAVE_STRUCT_TIMESPEC #endif #include #if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP // Linux glibc #define _SIMTHREAD_R_MUTEX_I PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP #elif defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER // Mac OS X #define _SIMTHREAD_R_MUTEX_I PTHREAD_RECURSIVE_MUTEX_INITIALIZER #endif struct recursive_mutex_maker_t { #ifdef _SIMTHREAD_R_MUTEX_I recursive_mutex_maker_t(pthread_mutex_t &mutex) { // initializer can only be used for initialization, not assignment pthread_mutex_t dummy = _SIMTHREAD_R_MUTEX_I; mutex = dummy; } #else recursive_mutex_maker_t(pthread_mutex_t &mutex); #endif }; // use our implementation if no posix barriers are available #if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS > 0) #define _USE_POSIX_BARRIERS #endif #ifdef _USE_POSIX_BARRIERS // redirect simthread functions to use supported pthread barriers typedef pthread_barrierattr_t simthread_barrierattr_t; typedef pthread_barrier_t simthread_barrier_t; #define simthread_barrier_init pthread_barrier_init #define simthread_barrier_destroy pthread_barrier_destroy #define simthread_barrier_wait pthread_barrier_wait #else // add barrier support using other pthread primitives typedef int simthread_barrierattr_t; typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; int count; int tripCount; } simthread_barrier_t; // needed because our signature doesn't match the one from simthread_barrier_init(3) int simthread_barrier_init(simthread_barrier_t *barrier, const simthread_barrierattr_t *attr, unsigned int count); int simthread_barrier_destroy(simthread_barrier_t *barrier); int simthread_barrier_wait(simthread_barrier_t *barrier); #endif #endif #endif simutrans-124.3/src/simutrans/utils/unicode.cc000066400000000000000000000155261474050137200214750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../utils/unicode.h" #include "../simtypes.h" #include utf32 const UNICODE_NUL = 0; utf8_decoder_t::utf8_decoder_t(utf8 const *const str) { utf8str = str; } utf32 utf8_decoder_t::decode(utf8 const *&buff) { size_t len = 0; utf32 const code_point = decode(buff, len); buff += len; return code_point; } utf32 utf8_decoder_t::decode(utf8 const *const buff, size_t &len) { // Implementation derived from RFC 3629. // Process character byte. size_t i = 0; len = 0; utf8 const character = buff[i++]; utf32 cp = 0; if( character <= 0x7F ) { // ASCII character. cp = character; len = 1; } else if( character < 0xC2 ) { // Invalid character. } else if( character <= 0xDF ) { // 2 byte character. cp = character & 0x1F; len = 2; } else if( character <= 0xEF ) { // 3 byte character. if( !((character == 0xE0 && buff[i] < 0xA0) || (character == 0xED && buff[i] > 0x9F)) ) { cp = character & 0xF; len = 3; } } else if( character <= 0xF4 ) { // 4 byte character. if( !((character == 0xF0 && buff[i] < 0x90) || (character == 0xF4 && buff[i] > 0x8F)) ) { cp = character & 0x7; len = 4; } } else { // Invalid character. } // Process tail bytes. for( ; i < len ; i++ ) { utf8 const tail = buff[i]; if( 0x80 <= tail && tail <= 0xBF ) { cp <<= 6; cp |= tail & 0x3F; } else { // Invalid tail. len = 0; } } if( len == 0 ) { // Replace invalid sequences with code point of the single decoded character (ISO-8859-1). len = 1; cp = character; } return cp; } bool utf8_decoder_t::has_next() const { return utf8str[0] != UNICODE_NUL; } utf32 utf8_decoder_t::next() { return has_next() ? decode(utf8str) : UNICODE_NUL; } utf8 const *utf8_decoder_t::get_position() { return utf8str; } size_t utf8_get_next_char(const utf8* text, size_t pos) { // go right one character // the bytes in a sequence have always the format 10xxxxxx, thus we use is_cont_char() // this will always work, even if we do not start on a sequence starting character do { pos++; } while (is_cont_char(text[pos])); return pos; } sint32 utf8_get_prev_char(const utf8* text, sint32 pos) { if (pos <= 0) { return 0; } // go left one character // the bytes in a sequence have always the format 10xxxxxx, thus we use is_cont_char() do { pos--; } while (pos>0 && is_cont_char(text[pos])); return pos; } size_t utf8_get_next_char(const char* text, size_t pos) { return utf8_get_next_char((const utf8*)text, pos); } sint32 utf8_get_prev_char(const char* text, sint32 pos) { return utf8_get_prev_char((const utf8*)text, pos); } int utf16_to_utf8(utf16 c, utf8* out) { if (c < 0x80) { out[0] = (utf8)c; return 1; } else if (c < 0x800) { out[0] = 0xC0 | (c >> 6); out[1] = 0x80 | (c >> 0 & 0x3F); return 2; } else /* if (c < 0x10000) */ { // Assume always a 3 byte sequence, since we do not support 4 byte UTF32 out[0] = 0xE0 | (c >> 12); out[1] = 0x80 | (c >> 6 & 0x3F); out[2] = 0x80 | (c >> 0 & 0x3F); return 3; } } // helper function to convert unicode into latin2 static utf16 latin2_to_unicode_lookup[96] = { 0x00A0, // char 0xA0 0x0104, // char 0xA1 0x02D8, // char 0xA2 0x0141, // char 0xA3 0x00A4, // char 0xA4 0x013D, // char 0xA5 0x015A, // char 0xA6 0x00A7, // char 0xA7 0x00A8, // char 0xA8 0x0160, // char 0xA9 0x015E, // char 0xAA 0x0164, // char 0xAB 0x0179, // char 0xAC 0x00AD, // char 0xAD 0x017D, // char 0xAE 0x017B, // char 0xAF 0x00B0, // char 0xB0 0x0105, // char 0xB1 0x02DB, // char 0xB2 0x0142, // char 0xB3 0x00B4, // char 0xB4 0x013E, // char 0xB5 0x015B, // char 0xB6 0x02C7, // char 0xB7 0x00B8, // char 0xB8 0x0161, // char 0xB9 0x015F, // char 0xBA 0x0165, // char 0xBB 0x017A, // char 0xBC 0x02DD, // char 0xBD 0x017E, // char 0xBE 0x017C, // char 0xBF 0x0154, // char 0xC0 0x00C1, // char 0xC1 0x00C2, // char 0xC2 0x0102, // char 0xC3 0x00C4, // char 0xC4 0x0139, // char 0xC5 0x0106, // char 0xC6 0x00C7, // char 0xC7 0x010C, // char 0xC8 0x00C9, // char 0xC9 0x0118, // char 0xCA 0x00CB, // char 0xCB 0x011A, // char 0xCC 0x00CD, // char 0xCD 0x00CE, // char 0xCE 0x010E, // char 0xCF 0x0110, // char 0xD0 0x0143, // char 0xD1 0x0147, // char 0xD2 0x00D3, // char 0xD3 0x00D4, // char 0xD4 0x0150, // char 0xD5 0x00D6, // char 0xD6 0x00D7, // char 0xD7 0x0158, // char 0xD8 0x016E, // char 0xD9 0x00DA, // char 0xDA 0x0170, // char 0xDB 0x00DC, // char 0xDC 0x00DD, // char 0xDD 0x0162, // char 0xDE 0x00DF, // char 0xDF 0x0155, // char 0xE0 0x00E1, // char 0xE1 0x00E2, // char 0xE2 0x0103, // char 0xE3 0x00E4, // char 0xE4 0x013A, // char 0xE5 0x0107, // char 0xE6 0x00E7, // char 0xE7 0x010D, // char 0xE8 0x00E9, // char 0xE9 0x0119, // char 0xEA 0x00EB, // char 0xEB 0x011B, // char 0xEC 0x00ED, // char 0xED 0x00EE, // char 0xEE 0x010F, // char 0xEF 0x0111, // char 0xF0 0x0144, // char 0xF1 0x0148, // char 0xF2 0x00F3, // char 0xF3 0x00F4, // char 0xF4 0x0151, // char 0xF5 0x00F6, // char 0xF6 0x00F7, // char 0xF7 0x0159, // char 0xF8 0x016F, // char 0xF9 0x00FA, // char 0xFA 0x0171, // char 0xFB 0x00FC, // char 0xFC 0x00FD, // char 0xFD 0x0163, // char 0xFE 0x02D9 // char 0xFF }; uint8 unicode_to_latin2( utf16 chr ) { for( utf8 i=0; i<96; i++ ) { if( latin2_to_unicode_lookup[i]==chr ) { return (i+0xA0); } } return 0; } utf16 latin2_to_unicode( uint8 chr ) { return chr >= 0xA0 ? latin2_to_unicode_lookup[chr-0xA0] : chr; } // inspired from Stackoverflow https://stackoverflow.com/questions/27303062/strstr-function-like-that-ignores-upper-or-lower-case // Handles somewhat umlaute as well (may depend a little on the locale though) const utf8 *utf8caseutf8(const utf8 *haystack_start, const utf8 *needle_start) { const utf8 *needle_p = needle_start; const utf8 *haystack_p = haystack_start; utf32 c = towlower( utf8_decoder_t::decode(needle_p )); needle_start = needle_p; if( c=='\0' ) { return haystack_start; } const utf8 *haystack_current = haystack_p; utf32 hs = utf8_decoder_t::decode( haystack_p ); while( hs != 0 ) { if( towlower( hs ) == c ) { const utf8 *haystack_next = haystack_p; while(true) { sint32 nc = utf8_decoder_t::decode( needle_p ); if( nc == 0 ) { return haystack_current; } hs = utf8_decoder_t::decode( haystack_p ); if( towlower( hs ) != towlower( nc ) ) { needle_p = needle_start; break; } } // advance one character haystack_p = haystack_next; } haystack_current = haystack_p; hs = utf8_decoder_t::decode( haystack_p ); } return NULL; } // defining it in the include did not work for whatever reason const char *utf8caseutf8( const char *haystack, const char *needle ) { return (const char *)utf8caseutf8( (const utf8 *)haystack, (const utf8 *)needle ); } simutrans-124.3/src/simutrans/utils/unicode.h000066400000000000000000000050241474050137200213270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef UTILS_UNICODE_H #define UTILS_UNICODE_H #include #include "../simtypes.h" extern utf32 const UNICODE_NUL; // the bytes in a sequence have always the format 10xxxxxx inline int is_cont_char(utf8 c) { return (c & 0xC0) == 0x80; } /** * UTF-8 string decoder that can be used to iterate through all code points. */ class utf8_decoder_t { private: // Pointer to UTF-8 formated C string. utf8 const *utf8str; public: // Constructs a UTF-8 decoder for the given C string. utf8_decoder_t(utf8 const *str); /** * Decodes a Unicode code point from the byte sequence pointed to by buff. * On return buff has been advanced to point at the beginning of the next Unicode code point. * Does not respect NUL terminator character, care should be taken to detect the emmited UNICODE_NUL when decoding C strings to avoid buffer over run errors. * Invalid Unicode sequences are intepreted using ISO-8859-1 and advance buff 1 byte. */ static utf32 decode(utf8 const *&buff); /** * Decodes a Unicode code point from the byte sequence pointed to by buff. * On return len contains the length of the Unicode character in bytes. * Does not respect NUL terminator character, care should be taken to detect the emmited UNICODE_NUL when decoding C strings to avoid buffer over run errors. * Invalid Unicode sequences are intepreted using ISO-8859-1 with a len of 1. */ static utf32 decode(utf8 const *const buff, size_t &len); /** * Returns true if there are more code points left to decode. * Returns false if at end of string. */ bool has_next() const; /** * Returns the next Unicode code point value in the string. * Returns UNICODE_NUL if has_next returns false. */ utf32 next(); /** * Returns the current position of the decoder. * This is a pointer to the next character. */ utf8 const *get_position(); }; // unicode save moving in strings size_t utf8_get_next_char(const utf8 *text, size_t pos); size_t utf8_get_next_char(const char* text, size_t pos); sint32 utf8_get_prev_char(const utf8 *text, sint32 pos); sint32 utf8_get_prev_char(const char* text, sint32 pos); int utf16_to_utf8(utf16 unicode, utf8 *out); // returns latin2 or 0 for error uint8 unicode_to_latin2( utf16 chr ); utf16 latin2_to_unicode( uint8 chr ); // caseless strstr with utf8 const utf8 *utf8caseutf8( const utf8 *haystack_start, const utf8 *needle_start ); const char *utf8caseutf8( const char *haystack, const char *needle ); #endif simutrans-124.3/src/simutrans/vehicle/000077500000000000000000000000001474050137200200065ustar00rootroot00000000000000simutrans-124.3/src/simutrans/vehicle/air_vehicle.cc000066400000000000000000000754341474050137200226040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "air_vehicle.h" #include "../obj/way/runway.h" #include "../simhalt.h" #include "../simconvoi.h" #include "../world/simworld.h" #include "../dataobj/environment.h" #include "../simware.h" #include "../builder/vehikelbauer.h" #include "../dataobj/schedule.h" // for flying things, everywhere is good ... // another function only called during route searching ribi_t::ribi air_vehicle_t::get_ribi(const grund_t *gr) const { switch(state) { case taxiing: case looking_for_parking: return gr->get_weg_ribi(air_wt); case taxiing_to_halt: { // we must invert all one way signs here, since we start from the target position here! weg_t *w = gr->get_weg(air_wt); if(w) { ribi_t::ribi r = w->get_ribi_unmasked(); if( ribi_t::ribi mask = w->get_ribi_maske() ) { r &= mask; } return r; } return ribi_t::none; } case landing: case departing: { ribi_t::ribi dir = gr->get_weg_ribi(air_wt); if(dir==0) { return ribi_t::all; } return dir; } case flying: case circling: return ribi_t::all; } return ribi_t::none; } // how expensive to go here (for way search) int air_vehicle_t::get_cost(const grund_t *, const weg_t *w, const sint32, ribi_t::ribi) const { // first favor faster ways int costs = 0; if(state==flying) { if(w==NULL) { costs += 1; } else { if(w->get_desc()->get_styp()==type_flat) { costs += 25; } } } else { // only, if not flying ... const runway_t *rw =(const runway_t *)w; // if we are on a runway, then take into account how many convois are already going there if( rw->get_desc()->get_styp()==1 ) { costs += rw->get_reservation_count()*9; // encourage detours even during take off } if(w->get_desc()->get_styp()==type_flat) { costs += 3; } else { costs += 2; } } return costs; } // whether the ground is drivable or not depends on the current state of the airplane bool air_vehicle_t::check_next_tile(const grund_t *bd) const { switch (state) { case taxiing: case taxiing_to_halt: case looking_for_parking: //DBG_MESSAGE("check_next_tile()","at %i,%i",bd->get_pos().x,bd->get_pos().y); return (bd->hat_weg(air_wt) && bd->get_weg(air_wt)->get_max_speed()>0); case landing: case departing: case flying: case circling: { //DBG_MESSAGE("air_vehicle_t::check_next_tile()","(cnv %i) in idx %i",cnv->self.get_id(),route_index ); // here a height check could avoid too high mountains return true; } } return false; } // this routine is called by find_route, to determined if we reached a destination bool air_vehicle_t::is_target(const grund_t *gr,const grund_t *) const { if(state!=looking_for_parking || !target_halt.is_bound()) { // search for the end of the runway const weg_t *w=gr->get_weg(air_wt); if(w && w->get_desc()->get_styp()==type_runway) { // ok here is a runway ribi_t::ribi ribi= w->get_ribi_unmasked(); if(ribi_t::is_single(ribi) && (ribi&approach_dir)!=0) { // pointing in our direction // here we should check for length, but we assume everything is ok return true; } } } else { // otherwise we just check, if we reached a free stop position of this halt if(gr->get_halt()==target_halt && target_halt->is_reservable(gr,cnv->self)) { return true; } } return false; } /* finds a free stop, calculates a route and reserve the position * else return false */ bool air_vehicle_t::find_route_to_stop_position() { if(target_halt.is_bound()) { //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","bound! (cnv %i)",cnv->self.get_id()); return true; // already searched with success } // check for skipping circle route_t *rt=cnv->access_route(); //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","can approach? (cnv %i)",cnv->self.get_id()); grund_t const* const last = welt->lookup(rt->back()); target_halt = last ? last->get_halt() : halthandle_t(); if(!target_halt.is_bound()) { return true; // no halt to search } // then: check if the search point is still on a runway (otherwise just proceed) grund_t const* const target = welt->lookup(rt->at(search_for_stop)); if(target==NULL || !target->hat_weg(air_wt)) { target_halt = halthandle_t(); block_reserver( search_for_stop, 0xFFFFu, false ); // unreserve all tiles DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","no runway found at (%s)",rt->at(search_for_stop).get_str()); return true; // no runway any more ... } // is our target occupied? // DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","state %i",state); if(!target_halt->find_free_position(air_wt,cnv->self,obj_t::air_vehicle) ) { target_halt = halthandle_t(); DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","no free position found!"); return false; } else { // calculate route to free position: // if we fail, we will wait in a step, much more simulation friendly // and the route finder is not re-entrant! if(!cnv->is_waiting()) { target_halt = halthandle_t(); return false; } // now search a route //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","some free: find route from index %i",suchen); route_t target_rt; flight_state prev_state = state; state = looking_for_parking; if(!target_rt.find_route( welt, rt->at(search_for_stop), this, 500, ribi_t::all, welt->get_settings().get_max_choose_route_steps() )) { DBG_MESSAGE("aircraft_t::find_route_to_stop_position()","found no route to free one"); // just make sure, that there is a route at all, otherwise start route search again for( uint32 i=search_for_stop; iget_count(); i++ ) { grund_t const* const target = welt->lookup( rt->at( i ) ); if( target == NULL || !target->hat_weg( air_wt ) ) { DBG_MESSAGE( "aircraft_t::find_route_to_stop_position()", "no runway found at (%s)", rt->at( search_for_stop ).get_str() ); get_convoi()->set_state(convoi_t::ROUTING_1); block_reserver( search_for_stop, 0xFFFFu, false ); // unreserve all tiles return false; // find new route } } // circle slowly another round ... target_halt = halthandle_t(); state = prev_state; return false; } state = prev_state; // now reserve our choice ... target_halt->reserve_position(welt->lookup(target_rt.back()), cnv->self); //DBG_MESSAGE("aircraft_t::find_route_to_stop_position()", "found free stop near %i,%i,%i", target_rt.back().x, target_rt.back().y, target_rt.back().z); rt->remove_koord_from(search_for_stop); rt->append( &target_rt ); return true; } } // main routine: searches the new route in up to three steps // must also take care of stops under traveling and the like bool air_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) { //DBG_MESSAGE("aircraft_t::calc_route()","search route from %i,%i,%i to %i,%i,%i",start.x,start.y,start.z,ziel.x,ziel.y,ziel.z); if(leading && cnv) { // free target reservation if( target_halt.is_bound() ) { if (grund_t* const target = welt->lookup(cnv->get_route()->back())) { target_halt->unreserve_position(target,cnv->self); } } // free runway reservation block_reserver( route_index, route->get_count(), false ); } target_halt = halthandle_t(); // no block reserved const weg_t *w=welt->lookup(start)->get_weg(air_wt); bool start_in_the_air = (w==NULL) || state==flying || flying_height>0; bool end_in_air=false; search_for_stop = takeoff = touchdown = 0x7ffffffful; if(!start_in_the_air) { // see, if we find a direct route: We are finished state = taxiing; if(route->calc_route( welt, start, ziel, this, max_speed, 0 )) { // ok, we can taxi to our location return true; } } if(start_in_the_air || (w->get_desc()->get_styp()==type_runway && ribi_t::is_single(w->get_ribi())) ) { // we start here, if we are in the air or at the end of a runway search_start = start; start_in_the_air = true; route->clear(); //DBG_MESSAGE("aircraft_t::calc_route()","start in air at %i,%i,%i",search_start.x,search_start.y,search_start.z); } else { // not found and we are not on the takeoff tile (where the route search will fail too) => we try to calculate a complete route, starting with the way to the runway // second: find start runway end state = taxiing; approach_dir = welt->get_settings().get_approach_dir(); // reverse DBG_MESSAGE("aircraft_t::calc_route()","search runway start near (%s)",start.get_str()); if(!route->find_route( welt, start, this, max_speed, ribi_t::all, 100 )) { DBG_MESSAGE("aircraft_t::calc_route()","failed"); return false; } // save the route search_start = route->back(); //DBG_MESSAGE("aircraft_t::calc_route()","start at ground (%s)",search_start.get_str()); } // second: find target runway end state = taxiing_to_halt; // only used for search approach_dir = ~welt->get_settings().get_approach_dir(); // reverse //DBG_MESSAGE("aircraft_t::calc_route()","search runway target near %i,%i,%i in corners %x",ziel.x,ziel.y,ziel.z); route_t end_route; if(!end_route.find_route( welt, ziel, this, max_speed, ribi_t::all, welt->get_settings().get_max_choose_route_steps() )) { // well, probably this is a waypoint if( grund_t *target = welt->lookup(ziel) ) { if( !target->get_weg(air_wt) ) { end_in_air = true; search_end = ziel; } else { // we have a taxiway/illegal runway here we cannot reach return false; // no route! } } else { // illegal coordinates? return false; } } else { // save target route search_end = end_route.back(); } //DBG_MESSAGE("aircraft_t::calc_route()","end at ground (%s)",search_end.get_str()); // create target route if(!start_in_the_air) { takeoff = route->get_count()-1; koord start_dir(welt->lookup(search_start)->get_weg_ribi(air_wt)); if(start_dir!=koord(0,0)) { // add the start ribi_t::ribi start_ribi = ribi_t::backward(ribi_type(start_dir)); const grund_t *gr=NULL; // add the start int endi = 1; int over = 3; // now add all runway + 3 ... do { if(!welt->is_within_limits(search_start.get_2d()+(start_dir*endi)) ) { break; } gr = welt->lookup_kartenboden(search_start.get_2d()+(start_dir*endi)); if(over<3 || (gr->get_weg_ribi(air_wt)&start_ribi)==0) { over --; } endi ++; route->append(gr->get_pos()); } while( over>0 ); // out of map if(gr==NULL) { dbg->error("aircraft_t::calc_route()","out of map!"); return false; } // need some extra step to avoid 180 deg turns if( start_dir.x!=0 && sgn(start_dir.x)!=sgn(search_end.x-search_start.x) ) { route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord(0,(search_end.y>search_start.y) ? 1 : -1 ) )->get_pos() ); route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord(0,(search_end.y>search_start.y) ? 2 : -2 ) )->get_pos() ); } else if( start_dir.y!=0 && sgn(start_dir.y)!=sgn(search_end.y-search_start.y) ) { route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord((search_end.x>search_start.x) ? 1 : -1 ,0) )->get_pos() ); route->append( welt->lookup_kartenboden(gr->get_pos().get_2d()+koord((search_end.x>search_start.x) ? 2 : -2 ,0) )->get_pos() ); } } else { // init with startpos dbg->error("aircraft_t::calc_route()","Invalid route calculation: start is on a single direction field ..."); } state = taxiing; flying_height = 0; target_height = (sint16)get_pos().z*TILE_HEIGHT_STEP; } else { // init with current pos (in air ... ) route->clear(); route->append( start ); state = flying; if(flying_height==0) { flying_height = 3*TILE_HEIGHT_STEP; } takeoff = 0; target_height = ((sint16)get_pos().z+3)*TILE_HEIGHT_STEP; } //DBG_MESSAGE("aircraft_t::calc_route()","take off ok"); koord3d landing_start=search_end; if(!end_in_air) { // now find way to start of landing pos ribi_t::ribi end_ribi = welt->lookup(search_end)->get_weg_ribi(air_wt); koord end_dir(end_ribi); end_ribi = ribi_t::backward(end_ribi); if(end_dir!=koord(0,0)) { // add the start const grund_t *gr; int endi = 1; int over = 3; // now add all runway + 3 ... do { if(!welt->is_within_limits(search_end.get_2d()+(end_dir*endi)) ) { break; } gr = welt->lookup_kartenboden(search_end.get_2d()+(end_dir*endi)); if(over<3 || (gr->get_weg_ribi(air_wt)&end_ribi)==0) { over --; } endi ++; landing_start = gr->get_pos(); } while( over>0 ); } } else { search_for_stop = touchdown = 0x7FFFFFFFul; } // just some straight routes ... if(!route->append_straight_route(welt,landing_start)) { // should never fail ... dbg->error( "aircraft_t::calc_route()", "No straight route found!" ); return false; } if(!end_in_air) { // find starting direction int offset = 0; switch(welt->lookup(search_end)->get_weg_ribi(air_wt)) { case ribi_t::north: offset = 0; break; case ribi_t::west: offset = 4; break; case ribi_t::south: offset = 8; break; case ribi_t::east: offset = 12; break; } // now make a curve koord circlepos=landing_start.get_2d(); static const koord circle_koord[16]={ koord(0,1), koord(0,1), koord(1,0), koord(0,1), koord(1,0), koord(1,0), koord(0,-1), koord(1,0), koord(0,-1), koord(0,-1), koord(-1,0), koord(0,-1), koord(-1,0), koord(-1,0), koord(0,1), koord(-1,0) }; // circle to the left for( int i=0; i<16; i++ ) { circlepos += circle_koord[(offset+i+16)%16]; if(welt->is_within_limits(circlepos)) { route->append( welt->lookup_kartenboden(circlepos)->get_pos() ); } else { // could only happen during loading old savegames; // in new versions it should not possible to build a runway here route->clear(); dbg->error("aircraft_t::calc_route()","airport too close to the edge! (Cannot go to %i,%i!)",circlepos.x,circlepos.y); return false; } } touchdown = route->get_count()+2; route->append_straight_route(welt,search_end); // now the route reach point (+1, since it will check before entering the tile ...) search_for_stop = route->get_count()-1; // now we just append the rest for( int i=end_route.get_count()-2; i>=0; i-- ) { route->append(end_route.at(i)); } } //DBG_MESSAGE("aircraft_t::calc_route()","departing=%i touchdown=%i suchen=%i total=%i state=%i",takeoff, touchdown, suchen, route->get_count()-1, state ); return true; } /* reserves runways (reserve true) or removes the reservation * finishes when reaching end tile or leaving the ground (end of runway) * @return true if the reservation is successful */ bool air_vehicle_t::block_reserver( uint32 start, uint32 end, bool reserve ) const { bool start_now = false; bool success = true; const route_t *route = cnv->get_route(); if(route->empty()) { return false; } for( uint32 i=start; success && iget_count(); i++) { grund_t *gr = welt->lookup(route->at(i)); runway_t *sch1 = gr ? (runway_t *)gr->get_weg(air_wt) : NULL; if( !sch1 ) { if(reserve) { if(!start_now) { // touched down here start = i; } else { // most likely left the ground here ... end = i; break; } } } else { // we un-reserve also nonexistent tiles! (may happen during deletion) if(reserve) { start_now = true; sch1->add_convoi_reservation(cnv->self); if( !sch1->reserve(cnv->self,ribi_t::none) ) { // unsuccessful => must un-reserve all success = false; end = i; break; } // end of runway? if( i > start && (ribi_t::is_single( sch1->get_ribi_unmasked() ) || sch1->get_desc()->get_styp() != type_runway) ) { end = i; break; } } else { // we always unreserve everything sch1->unreserve(cnv->self); } } } // un-reserve if not successful if( !success && reserve ) { for( uint32 i=start; ilookup(route->at(i)); if (gr) { runway_t* sch1 = (runway_t *)gr->get_weg(air_wt); if (sch1) { sch1->unreserve(cnv->self); } } } return false; } if( reserve && endget_count(); i++ ) { if( grund_t *gr = welt->lookup(route->at(i)) ) { if( runway_t* sch1 = (runway_t *)gr->get_weg(air_wt) ) { if( sch1->get_desc()->get_styp()!=type_runway ) { break; } sch1->add_convoi_reservation( cnv->self ); } } } } return success; } // handles all the decisions on the ground an in the air bool air_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8) { restart_speed = -1; assert(gr); if(gr->obj_count()>250) { // too many objects here return false; } if (!leading) { return true; } if( route_index < takeoff && route_index > 1 && takeoffget_route()->get_count()-1 ) { // check, if tile occupied by a plane on ground if( route_index > 1 ) { for( uint8 i = 1; iobj_count(); i++ ) { obj_t *obj = gr->obj_bei(i); // we drive through non leading vehicels for now ... if( obj->get_typ() == obj_t::air_vehicle && ((air_vehicle_t*)obj)->get_convoi()!=cnv ) { restart_speed = 0; return false; } } } // need to reserve runway? runway_t *rw = (runway_t *)gr->get_weg(air_wt); if(rw==NULL) { cnv->suche_neue_route(); return false; } // next tile a runway => then reserve if(rw->get_desc()->get_styp()==type_runway) { // try to reserve the runway if(!block_reserver(takeoff,takeoff+100,true)) { // runway already blocked ... restart_speed = 0; return false; } } return true; } if( state == taxiing ) { // enforce on ground for taxiing flying_height = 0; // we may need to unreserve the runway after leaving it if( route_index >= touchdown ) { runway_t *rw = (runway_t *)gr->get_weg(air_wt); // next tile a not runway => then unreserve if( rw == NULL || rw->get_desc()->get_styp() != type_runway || gr->is_halt() ) { block_reserver( touchdown, search_for_stop+1, false ); } } } if( route_index == takeoff && state == taxiing ) { // try to reserve the runway if not already done if(route_index==2 && !block_reserver(takeoff,takeoff+100,true)) { // runway blocked, wait at start of runway restart_speed = 0; return false; } // stop shortly at the end of the runway state = departing; restart_speed = 0; return false; } //DBG_MESSAGE("aircraft_t::can_enter_tile()","index %i<>%i",route_index,touchdown); // check for another circle ... if( route_index==(touchdown-3) ) { if( !block_reserver( touchdown, search_for_stop+1, true ) ) { route_index -= 16; return true; } state = landing; return true; } if( route_index==touchdown-16-3 && state!=circling ) { // just check, if the end of runway is free; we will wait there if( block_reserver( touchdown, search_for_stop+1, true ) ) { route_index += 16; // can land => set landing height state = landing; } else { // circle slowly next round state = circling; cnv->must_recalc_data(); if( leading ) { cnv->must_recalc_data_front(); } } } if(route_index==search_for_stop && state==landing && !target_halt.is_bound()) { // if we fail, we will wait in a step, much more simulation friendly // and the route finder is not re-entrant! if(!cnv->is_waiting()) { return false; } // nothing free here? if(find_route_to_stop_position()) { // stop reservation successful state = taxiing; return true; } restart_speed = 0; return false; } if(state==looking_for_parking) { state = taxiing; } if(state == taxiing && gr->is_halt() && gr->find()) { // the next step is a parking position. We do not enter, if occupied! restart_speed = 0; return false; } return true; } // this must also change the internal modes for the calculation void air_vehicle_t::enter_tile(grund_t* gr) { vehicle_t::enter_tile(gr); if( this->is_on_ground() ) { runway_t *w=(runway_t *)gr->get_weg(air_wt); if(w) { const int cargo = get_total_cargo(); w->book(cargo, WAY_STAT_GOODS); if (leading) { w->book(1, WAY_STAT_CONVOIS); } } } } air_vehicle_t::air_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t() { rdwr_from_convoi(file); if( file->is_loading() ) { static const vehicle_desc_t *last_desc = NULL; if(is_first) { last_desc = NULL; } // try to find a matching vehicle if(desc==NULL) { dbg->warning("aircraft_t::aircraft_t()", "try to find a fitting vehicle for %s.", !fracht.empty() ? fracht.front().get_name() : "passengers"); desc = vehicle_builder_t::get_best_matching(air_wt, 0, 101, 1000, 800, !fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers, true, last_desc, is_last ); if(desc) { calc_image(); } } // update last desc if( desc ) { last_desc = desc; } } } air_vehicle_t::air_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) : vehicle_t(pos, desc, player) { cnv = cn; state = taxiing; flying_height = 0; target_height = pos.z; } air_vehicle_t::~air_vehicle_t() { // mark aircraft (after_image) dirty, since we have no "real" image const int raster_width = get_current_tile_raster_width(); sint16 yoff = tile_raster_scale_y(-flying_height-get_hoff()-2, raster_width); mark_image_dirty( image, yoff); mark_image_dirty( image, 0 ); } void air_vehicle_t::set_convoi(convoi_t *c) { DBG_MESSAGE("aircraft_t::set_convoi()","%p",c); if(leading && (uintptr_t)cnv > 1) { // free stop reservation route_t const& r = *cnv->get_route(); if(target_halt.is_bound()) { target_halt->unreserve_position(welt->lookup(r.back()), cnv->self); target_halt = halthandle_t(); } if (!r.empty()) { // free runway reservation if(route_index>=takeoff && route_index=touchdown-1 && state!=taxiing) { block_reserver( touchdown, search_for_stop+1, false ); } } } // maybe need to restore state? if(c!=NULL) { bool target=(bool)cnv; vehicle_t::set_convoi(c); if(leading) { if(target) { // reinitialize the target halt grund_t* const target=welt->lookup(cnv->get_route()->back()); target_halt = target->get_halt(); if(target_halt.is_bound()) { target_halt->reserve_position(target,cnv->self); } } // restore reservation if( grund_t *gr = welt->lookup(get_pos()) ) { if( weg_t *weg = gr->get_weg(air_wt) ) { if( weg->get_desc()->get_styp()==type_runway ) { // but only if we are on a runway ... if( route_index>=takeoff && route_index=touchdown-1 && state!=taxiing ) { block_reserver( touchdown, search_for_stop+1, true ); } } } } } } else { vehicle_t::set_convoi(NULL); } } schedule_t *air_vehicle_t::generate_new_schedule() const { return new airplane_schedule_t(); } void air_vehicle_t::rdwr_from_convoi(loadsave_t *file) { xml_tag_t t( file, "aircraft_t" ); // initialize as vehicle_t::rdwr_from_convoi calls get_image() if (file->is_loading()) { state = taxiing; flying_height = 0; } vehicle_t::rdwr_from_convoi(file); file->rdwr_enum(state); file->rdwr_short(flying_height); flying_height &= ~(TILE_HEIGHT_STEP-1); file->rdwr_short(target_height); file->rdwr_long(search_for_stop); file->rdwr_long(touchdown); file->rdwr_long(takeoff); } void air_vehicle_t::hop(grund_t* gr) { sint32 new_speed_limit = SPEED_UNLIMITED; sint32 new_friction = 0; // take care of in-flight height ... const sint16 h_cur = (sint16)get_pos().z*TILE_HEIGHT_STEP; const sint16 h_next = (sint16)pos_next.z*TILE_HEIGHT_STEP; // just mimick vehicle in front of me if (cnv->get_vehicle(0)!=this) { // get number in convoi uint16 previous = 1; while (cnv->get_vehicle(previous) != this) { previous++; assert(previous < cnv->get_vehicle_count()); } previous--; // hop to next tile vehicle_t::hop(gr); air_vehicle_t* before_veh = dynamic_cast(cnv->get_vehicle(previous)); target_height = before_veh->get_target_height(); current_friction = before_veh->get_frictionfactor(); speed_limit = before_veh->get_speed_limit(); flying_height = before_veh->get_flyingheight() + before_veh->get_hoff() + 2; state = before_veh->get_flying_state(); route_index = before_veh->get_route_index(); // friction factors and speed limit may have changed // TODO use the same logic as in vehicle_t::hop cnv->must_recalc_data(); return; } switch(state) { case departing: { flying_height = 0; target_height = h_cur; new_friction = max( 1, 28/(1+(route_index-takeoff)*2) ); // 9 5 4 3 2 2 1 1... // take off, when a) end of runway or b) last tile of runway or c) fast enough weg_t *weg=welt->lookup(get_pos())->get_weg(air_wt); if( (weg==NULL || // end of runway (broken runway) weg->get_desc()->get_styp()!=type_runway || // end of runway (grass now ... ) (route_index>takeoff+1 && ribi_t::is_single(weg->get_ribi_unmasked())) ) || // single ribi at end of runway cnv->get_akt_speed()>kmh_to_speed(desc->get_topspeed())/3 // fast enough ) { state = flying; new_friction = 1; block_reserver( takeoff, touchdown-1, false ); flying_height = h_cur - h_next; target_height = h_cur+TILE_HEIGHT_STEP*3; } break; } case circling: { new_speed_limit = kmh_to_speed(desc->get_topspeed())/3; new_friction = 4; // do not change height any more while circling flying_height += h_cur; flying_height -= h_next; break; } case flying: { // since we are at a tile border, round up to the nearest value flying_height += h_cur; if (flying_height < target_height) { flying_height = (flying_height + TILE_HEIGHT_STEP) & ~(TILE_HEIGHT_STEP - 1); } else if (flying_height > target_height) { flying_height = (flying_height - TILE_HEIGHT_STEP); } flying_height -= h_next; // did we have to change our flight height? if (target_height - h_next > TILE_HEIGHT_STEP * 5) { // Move down target_height -= TILE_HEIGHT_STEP * 2; } else if (target_height - h_next < TILE_HEIGHT_STEP * 2) { // Move up target_height += TILE_HEIGHT_STEP * 2; } break; } case landing: { new_speed_limit = kmh_to_speed(desc->get_topspeed())/3; // ==approach speed new_friction = 8; flying_height += h_cur; if( flying_height < target_height ) { flying_height = (flying_height+TILE_HEIGHT_STEP) & ~(TILE_HEIGHT_STEP-1); } else if( flying_height > target_height ) { flying_height = (flying_height-TILE_HEIGHT_STEP); } if (route_index >= touchdown) { // come down, now! target_height = h_next; // touchdown! if (flying_height==h_next) { const sint32 taxi_speed = kmh_to_speed( min( 60, desc->get_topspeed()/4 ) ); if( cnv->get_akt_speed() <= taxi_speed ) { new_speed_limit = taxi_speed; new_friction = 16; } else { const sint32 runway_left = search_for_stop - route_index; new_speed_limit = min( new_speed_limit, runway_left*runway_left*taxi_speed ); // ...approach 540 240 60 60 const sint32 runway_left_fr = max( 0, 6-runway_left ); new_friction = max( new_friction, min( desc->get_topspeed()/12, 4 + 4*(runway_left_fr*runway_left_fr+1) )); // ...8 8 12 24 44 72 108 152 } } } else { // runway is on this height const sint16 runway_height = cnv->get_route()->at(touchdown).z*TILE_HEIGHT_STEP; // we are too low, ascent asap if (flying_height < runway_height + TILE_HEIGHT_STEP) { target_height = runway_height + TILE_HEIGHT_STEP; } // too high, descent else if (flying_height + h_next - h_cur > runway_height + (sint16)(touchdown-route_index-1)*TILE_HEIGHT_STEP) { target_height = runway_height + (touchdown-route_index-1)*TILE_HEIGHT_STEP; } } flying_height -= h_next; break; } default: { new_speed_limit = kmh_to_speed( min( 60, desc->get_topspeed()/4 ) ); new_friction = 16; flying_height = 0; target_height = h_next; break; } } // hop to next tile vehicle_t::hop(gr); speed_limit = new_speed_limit; current_friction = new_friction; // friction factors and speed limit may have changed // TODO use the same logic as in vehicle_t::hop cnv->must_recalc_data(); } // this routine will display the aircraft (if in flight) #ifdef MULTI_THREAD void air_vehicle_t::display_after(int xpos_org, int ypos_org, const sint8 clip_num) const #else void air_vehicle_t::display_after(int xpos_org, int ypos_org, bool is_global) const #endif { if( image != IMG_EMPTY && !is_on_ground() ) { int xpos = xpos_org, ypos = ypos_org; const int raster_width = get_current_tile_raster_width(); const sint16 z = get_pos().z; if( z + flying_height/TILE_HEIGHT_STEP - 1 > grund_t::underground_level ) { return; } const sint16 target = target_height - ((sint16)z*TILE_HEIGHT_STEP); sint16 current_flughohe = flying_height; if( current_flughohe < target ) { current_flughohe += (steps*TILE_HEIGHT_STEP) >> 8; } else if( current_flughohe > target ) { current_flughohe -= (steps*TILE_HEIGHT_STEP) >> 8; } sint16 hoff = get_hoff(); ypos += tile_raster_scale_y(get_yoff()-current_flughohe-hoff-2, raster_width); xpos += tile_raster_scale_x(get_xoff(), raster_width); get_screen_offset( xpos, ypos, raster_width ); display_swap_clip_wh(CLIP_NUM_VAR); // will be dirty // the aircraft!!! display_color( image, xpos, ypos, get_owner_nr(), true, true/*get_flag(obj_t::dirty)*/ CLIP_NUM_PAR); #ifndef MULTI_THREAD vehicle_t::display_after( xpos_org, ypos_org - tile_raster_scale_y( current_flughohe - hoff - 2, raster_width ), is_global ); #endif display_swap_clip_wh(CLIP_NUM_VAR); } #ifdef MULTI_THREAD } void air_vehicle_t::display_overlay(int xpos_org, int ypos_org) const { if( image != IMG_EMPTY && !is_on_ground() ) { const int raster_width = get_current_tile_raster_width(); const sint16 z = get_pos().z; if( z + flying_height/TILE_HEIGHT_STEP - 1 > grund_t::underground_level ) { return; } const sint16 target = target_height - ((sint16)z*TILE_HEIGHT_STEP); sint16 current_flughohe = flying_height; if( current_flughohe < target ) { current_flughohe += (steps*TILE_HEIGHT_STEP) >> 8; } else if( current_flughohe > target ) { current_flughohe -= (steps*TILE_HEIGHT_STEP) >> 8; } vehicle_t::display_overlay( xpos_org, ypos_org - tile_raster_scale_y( current_flughohe - get_hoff() - 2, raster_width ) ); } #endif else if( is_on_ground() ) { // show loading tooltips on ground #ifdef MULTI_THREAD vehicle_t::display_overlay( xpos_org, ypos_org ); #else vehicle_t::display_after( xpos_org, ypos_org, is_global ); #endif } } const char *air_vehicle_t::get_removal_error(const player_t *player) { return is_on_ground() ? vehicle_t::get_removal_error(player) : NULL; } simutrans-124.3/src/simutrans/vehicle/air_vehicle.h000066400000000000000000000101511474050137200224270ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_AIR_VEHICLE_H #define VEHICLE_AIR_VEHICLE_H #include "vehicle.h" /** * A class for aircrafts. Manages the look of the vehicles * and the navigability of tiles. * @see vehicle_t */ class air_vehicle_t : public vehicle_t { public: enum flight_state { taxiing = 0, departing = 1, flying = 2, landing = 3, looking_for_parking = 4, circling = 5, taxiing_to_halt = 6 }; private: // only used for is_target() (do not need saving) ribi_t::ribi approach_dir; // only used for route search and approach vectors of get_ribi() (do not need saving) koord3d search_start; koord3d search_end; flight_state state; // functions needed for the search without destination from find_route sint16 flying_height; sint16 target_height; uint32 search_for_stop, touchdown, takeoff; protected: // jumps to next tile and correct the height ... void hop(grund_t*) OVERRIDE; bool check_next_tile(const grund_t *bd) const OVERRIDE; void enter_tile(grund_t*) OVERRIDE; bool block_reserver( uint32 start, uint32 end, bool reserve ) const; // find a route and reserve the stop position bool find_route_to_stop_position(); public: air_vehicle_t(loadsave_t *file, bool is_first, bool is_last); air_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv); // start and schedule // to shift the events around properly void get_event_index( flight_state &state_, uint32 &takeoff_, uint32 &stopsearch_, uint32 &landing_ ) { state_ = state; takeoff_ = takeoff; stopsearch_ = search_for_stop; landing_ = touchdown; } void set_event_index( flight_state state_, uint32 takeoff_, uint32 stopsearch_, uint32 landing_ ) { state = state_; takeoff = takeoff_; search_for_stop = stopsearch_; touchdown = landing_; } // since we are drawing ourselves, we must mark ourselves dirty during deletion ~air_vehicle_t(); waytype_t get_waytype() const OVERRIDE { return air_wt; } // returns true for the way search to an unknown target. bool is_target(const grund_t *,const grund_t *) const OVERRIDE; // return valid direction ribi_t::ribi get_ribi(const grund_t* ) const OVERRIDE; // how expensive to go here (for way search) int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const OVERRIDE; bool can_enter_tile(const grund_t *gr_next, sint32 &restart_speed, uint8) OVERRIDE; void set_convoi(convoi_t *c) OVERRIDE; bool calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) OVERRIDE; typ get_typ() const OVERRIDE { return air_vehicle; } schedule_t *generate_new_schedule() const OVERRIDE; void rdwr_from_convoi(loadsave_t *file) OVERRIDE; int get_flyingheight() const {return flying_height-get_hoff()-2;} sint16 get_target_height() const { return target_height; } flight_state get_flying_state() const { return state; } // image: when flying empty, on ground the plane image_id get_image() const OVERRIDE {return !is_on_ground() ? IMG_EMPTY : image;} // image: when flying the shadow, on ground empty image_id get_outline_image() const OVERRIDE {return !is_on_ground() ? image : IMG_EMPTY;} // shadow has black color (when flying) FLAGGED_PIXVAL get_outline_colour() const OVERRIDE {return !is_on_ground() ? TRANSPARENT75_FLAG | OUTLINE_FLAG | color_idx_to_rgb(COL_BLACK) : 0;} #ifdef MULTI_THREAD // this draws the "real" aircrafts (when flying) void display_after(int xpos, int ypos, const sint8 clip_num) const OVERRIDE; // this routine will display a tooltip for lost, on depot order, and stuck vehicles void display_overlay(int xpos, int ypos) const OVERRIDE; #else // this draws the "real" aircrafts (when flying) void display_after(int xpos, int ypos, bool dirty) const OVERRIDE; #endif void calc_friction(const grund_t*) OVERRIDE {} bool is_on_ground() const { return flying_height==0 && !(state==circling || state==flying); } const char *get_removal_error(const player_t *player) OVERRIDE; bool is_flying() const OVERRIDE { return !is_on_ground(); } }; #endif simutrans-124.3/src/simutrans/vehicle/movingobj.cc000066400000000000000000000223641474050137200223160ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include "../simdebug.h" #include "../world/simworld.h" #include "../obj/simobj.h" #include "../display/simimg.h" #include "../player/simplay.h" #include "../simtypes.h" #include "../simunits.h" #include "../ground/grund.h" #include "../descriptor/groundobj_desc.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "../obj/baum.h" #include "movingobj.h" /******************************** static stuff: desc management ****************************************************************/ freelist_iter_tpl movingobj_t::fl; vector_tpl movingobj_t::movingobj_typen(0); stringhashtable_tpl movingobj_t::desc_table; bool compare_groundobj_desc(const groundobj_desc_t* a, const groundobj_desc_t* b); bool movingobj_t::successfully_loaded() { movingobj_typen.reserve(desc_table.get_count()); for(auto const& i : desc_table) { movingobj_typen.insert_ordered(i.value, compare_groundobj_desc); } // iterate again to assign the index for(auto const& i : desc_table) { i.value->index = movingobj_typen.index_of(i.value); } if(desc_table.empty()) { movingobj_typen.append( NULL ); DBG_MESSAGE("movingobj_t", "No movingobj found - feature disabled"); } return true; } bool movingobj_t::register_desc(groundobj_desc_t *desc) { // remove duplicates if (groundobj_desc_t *old = desc_table.remove( desc->get_name() ) ) { delete old; } desc_table.put(desc->get_name(), desc ); return true; } /** also checks for distribution values */ const groundobj_desc_t *movingobj_t::random_movingobj_for_climate(climate cl) { // none there if( desc_table.empty() ) { return NULL; } int weight = 0; for(groundobj_desc_t const* const i : movingobj_typen) { if (i->is_allowed_climate(cl) ) { weight += i->get_distribution_weight(); } } // now weight their distribution if (weight > 0) { const int w=simrand(weight); weight = 0; for(groundobj_desc_t const* const i : movingobj_typen) { if (i->is_allowed_climate(cl)) { weight += i->get_distribution_weight(); if(weight>=w) { return i; } } } } return NULL; } /******************************* end of static ******************************************/ // recalculates only the seasonal image void movingobj_t::calc_image() { const groundobj_desc_t *desc=get_desc(); const uint8 seasons = desc->get_seasons()-1; uint8 season = 0; switch( seasons ) { case 0: { // summer only season = 0; break; } case 1: { // summer, snow season = welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate; break; } case 2: { // summer, winter, snow season = welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate ? 2 : welt->get_season() == 1; break; } default: { if( welt->get_snowline() <= get_pos().z || welt->get_climate( get_pos().get_2d() ) == arctic_climate ) { season = seasons; } else { // resolution 1/8th month (0..95) const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_ticks()>>(welt->ticks_per_world_month_shift-3))&7) + 1; season = (seasons * yearsteps - 1) / 96; } break; } } set_image( get_desc()->get_image( season, ribi_t::get_dir(get_direction()) )->get_id() ); } movingobj_t::movingobj_t(loadsave_t *file) : vehicle_base_t() { rdwr(file); } movingobj_t::movingobj_t(koord3d pos, const groundobj_desc_t *b ) : vehicle_base_t(pos) { movingobjtype = movingobj_typen.index_of(b); weg_next = 0; timetochange = 0; // will do random direct change anyway during next step direction = calc_set_direction( koord3d(0,0,0), koord3d(koord::west,0) ); calc_image(); } bool movingobj_t::check_season(const bool) { const image_id old_image = get_image(); calc_image(); if( get_image() != old_image ) { mark_image_dirty( get_image(), 0 ); } return true; } void movingobj_t::rdwr(loadsave_t *file) { xml_tag_t d( file, "movingobj_t" ); vehicle_base_t::rdwr(file); file->rdwr_enum(direction); if (file->is_loading()) { // restore dxdy information dx = dxdy[ ribi_t::get_dir(direction)*2]; dy = dxdy[ ribi_t::get_dir(direction)*2+1]; } file->rdwr_byte(steps); file->rdwr_byte(steps_next); pos_next.rdwr(file); koord p = pos_next_next.get_2d(); p.rdwr(file); if(file->is_loading()) { pos_next_next = koord3d(p, 0); // z-coordinate will be restored in hop_check } file->rdwr_short(timetochange); if(file->is_saving()) { const char *s = get_desc()->get_name(); file->rdwr_str(s); } else { char bname[128]; file->rdwr_str(bname, lengthof(bname)); groundobj_desc_t *desc = desc_table.get(bname); if( desc_table.empty() || desc==NULL ) { movingobjtype = simrand(movingobj_typen.get_count()); } else { movingobjtype = (uint8)desc->get_index(); } // if not there, desc will be zero use_calc_height = true; } if (file->is_version_atleast(122, 1)) { file->rdwr_long(weg_next); } else if (file->is_loading()) { weg_next = 0; } } void movingobj_t::show_info() { if(env_t::tree_info) { obj_t::show_info(); } } void movingobj_t::info(cbuffer_t & buf) const { obj_t::info(buf); buf.append(translator::translate(get_desc()->get_name())); if (char const* const maker = get_desc()->get_copyright()) { buf.append("\n"); buf.printf(translator::translate("Constructed by %s"), maker); } buf.append("\n"); buf.append(translator::translate("cost for removal")); char buffer[128]; money_to_string( buffer, get_desc()->get_price()/100.0 ); buf.append( buffer ); } void movingobj_t::cleanup(player_t *player) { player_t::book_construction_costs(player, -get_desc()->get_price(), get_pos().get_2d(), ignore_wt); mark_image_dirty( get_image(), 0 ); } sync_result movingobj_t::sync_step(uint32 delta_t) { weg_next += get_desc()->get_speed() * delta_t; weg_next -= do_drive( weg_next ); return SYNC_OK; } /* essential to find out about next step * returns true, if we can go here * (identical to fahrer) */ bool movingobj_t::check_next_tile( const grund_t *gr ) const { if(gr==NULL) { // no ground => we cannot check further return false; } const groundobj_desc_t *desc = get_desc(); if( !desc->is_allowed_climate( welt->get_climate(gr->get_pos().get_2d()) ) ) { // not an allowed climate zone! return false; } if(desc->get_waytype()==road_wt) { // can cross roads if(gr->get_typ()!=grund_t::boden || !slope_t::is_way(gr->get_grund_hang())) { return false; } // only on roads, do not walk in cities if(gr->hat_wege() && (!gr->hat_weg(road_wt) || gr->get_weg(road_wt)->hat_gehweg())) { return false; } if(!desc->can_build_trees_here()) { return gr->find()==NULL; } } else if(desc->get_waytype()==air_wt) { // avoid towns to avoid flying through houses return gr->get_typ()==grund_t::boden || gr->get_typ()==grund_t::wasser; } else if(desc->get_waytype()==water_wt) { // floating object return gr->get_typ()==grund_t::wasser || gr->hat_weg(water_wt); } else if(desc->get_waytype()==ignore_wt) { // crosses nothing if(!gr->ist_natur() || !slope_t::is_way(gr->get_grund_hang())) { return false; } if(!desc->can_build_trees_here()) { return gr->find()==NULL; } } return true; } grund_t* movingobj_t::hop_check() { /* since we may be going diagonal without any road * determining the next koord is a little tricky: * If it is a diagonal, pos_next_next is calculated from current pos, * Else pos_next_next is a single step from pos_next. * otherwise objects would jump left/right on some diagonals */ if (timetochange != 0) { koord k(direction); if(k.x&k.y) { pos_next_next = get_pos() + k; } else { pos_next_next = pos_next + k; } grund_t *gr = welt->lookup_kartenboden(pos_next_next.get_2d()); if (check_next_tile(gr)) { pos_next_next = gr->get_pos(); } else { timetochange = 0; } } if (timetochange==0) { // direction change needed timetochange = simrand(speed_to_kmh(get_desc()->get_speed())/3); const koord pos=pos_next.get_2d(); const grund_t *to[4]; uint8 until=0; // find all tiles we can go for( int i=0; i<4; i++ ) { const grund_t *check = welt->lookup_kartenboden(pos+koord::nesw[i]); if(check_next_tile(check) && check->get_pos()!=get_pos()) { to[until++] = check; } } // if nothing found, return if(until==0) { pos_next_next = get_pos(); // (better would be destruction?) } else { // else prepare for direction change const grund_t *next = to[simrand(until)]; pos_next_next = next->get_pos(); } } else { timetochange--; } return welt->lookup(pos_next); } void movingobj_t::hop(grund_t* gr) { leave_tile(); if(pos_next.get_2d()==get_pos().get_2d()) { direction = ribi_t::backward(direction); dx = -dx; dy = -dy; calc_image(); } else { ribi_t::ribi old_dir = direction; direction = calc_set_direction( get_pos(), pos_next_next ); if(old_dir!=direction) { calc_image(); } } set_pos(pos_next); enter_tile(gr); // next position pos_next = pos_next_next; } simutrans-124.3/src/simutrans/vehicle/movingobj.h000066400000000000000000000044551474050137200221610ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_MOVINGOBJ_H #define VEHICLE_MOVINGOBJ_H #include "../tpl/stringhashtable_tpl.h" #include "../tpl/vector_tpl.h" #include "../tpl/freelist_iter_tpl.h" #include "../descriptor/groundobj_desc.h" #include "../simcolor.h" #include "vehicle_base.h" /** * moving stuff like sheep or birds */ class movingobj_t : public vehicle_base_t { private: /// distance to move uint32 weg_next; /// direction will change after this time uint16 timetochange; /// type of object, index into movingobj_typen uint8 movingobjtype; koord3d pos_next_next; /// static table to find desc by name static stringhashtable_tpl desc_table; /// static vector for fast lookup of desc static vector_tpl movingobj_typen; static freelist_iter_tpl fl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules protected: void rdwr(loadsave_t *file) OVERRIDE; void calc_image() OVERRIDE; public: static bool register_desc(groundobj_desc_t *desc); static bool successfully_loaded(); static const groundobj_desc_t *random_movingobj_for_climate(climate cl); movingobj_t(loadsave_t *file); movingobj_t(koord3d pos, const groundobj_desc_t *); sync_result sync_step(uint32 delta_t); static void sync_handler(uint32 delta_t) { fl.sync_step(delta_t); } void* operator new(size_t) { return fl.gimme_node(); } void operator delete(void* p) { return fl.putback_node(p); } // always free virtual bool check_next_tile(const grund_t *) const; grund_t* hop_check() OVERRIDE; void hop(grund_t* gr) OVERRIDE; waytype_t get_waytype() const OVERRIDE { return get_desc()->get_waytype(); } const char *get_name() const OVERRIDE {return "Movingobj";} typ get_typ() const OVERRIDE { return movingobj; } /** * Called whenever the season or snowline height changes * return false and the obj_t will be deleted */ bool check_season(const bool) OVERRIDE; void show_info() OVERRIDE; void info(cbuffer_t & buf) const OVERRIDE; void cleanup(player_t *player) OVERRIDE; const groundobj_desc_t* get_desc() const { return movingobj_typen[movingobjtype]; } bool is_flying() const OVERRIDE { return get_desc()->get_waytype()==air_wt; } }; #endif simutrans-124.3/src/simutrans/vehicle/overtaker.h000066400000000000000000000026521474050137200221660ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_OVERTAKER_H #define VEHICLE_OVERTAKER_H #include "../simtypes.h" #include "../simunits.h" /** * Class dealing with overtaking * It is the superclass of convois and city cars (private_car_t) */ class overtaker_t { protected: /* if >0, number of tiles for overtaking left * if <0, number of tiles that is prevented being overtaken * (other vehicle is overtaking us) */ sint8 tiles_overtaking; sint8 diff; sint32 max_power_speed; // max achievable speed at current power/weight public: overtaker_t():tiles_overtaking(0), diff(0), max_power_speed(SPEED_UNLIMITED) {} virtual ~overtaker_t() {} bool is_overtaking() const { return diff < 0; } bool is_overtaken() const { return diff > 0; } bool can_be_overtaken() const { return tiles_overtaking == 0; } void set_tiles_overtaking(sint8 v) { tiles_overtaking = v; diff = 0; if(tiles_overtaking>0) { diff --; } else if(tiles_overtaking<0) { diff ++; } } // change counter for overtaking void update_tiles_overtaking() { tiles_overtaking += diff; if(tiles_overtaking==0) { diff = 0; } } // since citycars and convois can react quite different virtual bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) = 0; sint32 get_max_power_speed() const { return max_power_speed; } }; #endif simutrans-124.3/src/simutrans/vehicle/pedestrian.cc000066400000000000000000000230321474050137200224530ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "pedestrian.h" #include "../simdebug.h" #include "../world/simworld.h" #include "../display/simimg.h" #include "../utils/simrandom.h" #include "../ground/grund.h" #include "../dataobj/loadsave.h" #include "../dataobj/translator.h" #include "../utils/cbuffer.h" #include "../descriptor/pedestrian_desc.h" #include freelist_iter_tpl pedestrian_t::fl; static uint32 const strecke[] = { 6000, 11000, 15000, 20000, 25000, 30000, 35000, 40000 }; static weighted_vector_tpl list_timeline; stringhashtable_tpl pedestrian_t::table; bool pedestrian_t::register_desc(const pedestrian_desc_t *desc) { if(const pedestrian_desc_t* old = table.remove(desc->get_name()) ) { delete old; } table.put(desc->get_name(), desc); return true; } bool pedestrian_t::successfully_loaded() { if (table.empty()) { DBG_MESSAGE("pedestrian_t", "No pedestrians found - feature disabled"); } return true; } static bool compare_pedestrian_desc(const pedestrian_desc_t* a, const pedestrian_desc_t* b) { int diff = a->get_intro_year_month() - b->get_intro_year_month(); if (diff == 0) { /* same Level - we introduce an artificial, but unique resort * on the induced name. */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } pedestrian_t::pedestrian_t(loadsave_t *file) : road_user_t() { animation_steps = 0; on_left = false; steps_offset = 0; rdwr(file); if(desc) { ped_offset = desc->get_offset(); } calc_disp_lane(); } void pedestrian_t::build_timeline_list(karte_t *welt) { // this list will contain all citycars list_timeline.clear(); vector_tpl temp_liste(0); if( !table.empty() ) { const int month_now = welt->get_current_month(); // check for every citycar, if still ok ... for(auto const& i : table) { pedestrian_desc_t const* const info = i.value; const int intro_month = info->get_intro_year_month(); const int retire_month = info->get_retire_year_month(); if (!welt->use_timeline() || (intro_month <= month_now && month_now < retire_month)) { temp_liste.insert_ordered( info, compare_pedestrian_desc ); } } } list_timeline.resize( temp_liste.get_count() ); for(pedestrian_desc_t const* const i : temp_liste) { list_timeline.append(i, i->get_distribution_weight()); } } bool pedestrian_t::list_empty() { return list_timeline.empty(); } pedestrian_t::pedestrian_t(grund_t *gr) : road_user_t(gr, sim_async_rand(65535)), desc(pick_any_weighted_async(list_timeline)) { animation_steps = 0; on_left = sim_async_rand(2) > 0; steps_offset = 0; time_to_life = pick_any_async(strecke); ped_offset = desc->get_offset(); calc_image(); calc_disp_lane(); } void pedestrian_t::calc_image() { set_image(desc->get_image_id(ribi_t::get_dir(get_direction()))); } image_id pedestrian_t::get_image() const { if (desc->get_steps_per_frame() > 0) { uint16 frame = ((animation_steps + steps) / desc->get_steps_per_frame()) % desc->get_animation_count(ribi_t::get_dir(direction)); return desc->get_image_id(ribi_t::get_dir(get_direction()), frame); } else { return image; } } void pedestrian_t::rdwr(loadsave_t *file) { xml_tag_t f( file, "fussgaenger_t" ); road_user_t::rdwr(file); if(!file->is_loading()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char s[256]; file->rdwr_str(s, lengthof(s)); desc = table.get(s); // unknown pedestrian => create random new one if(desc == NULL && !list_timeline.empty() ) { desc = pick_any_weighted_async(list_timeline); } } if(file->is_version_less(89, 4)) { time_to_life = pick_any_async(strecke); } if (file->is_version_atleast(120, 6)) { file->rdwr_short(steps_offset); file->rdwr_bool(on_left); } if (file->is_loading()) { calc_disp_lane(); } } void pedestrian_t::calc_disp_lane() { // walking in the back or the front disp_lane = on_left ? 0 : 4; if ((direction & ribi_t::south) || direction == ribi_t::west) disp_lane ^= 4; } void pedestrian_t::rotate90() { road_user_t::rotate90(); calc_disp_lane(); } // create a number (count) of pedestrians (if possible) void pedestrian_t::generate_pedestrians_at(grund_t *bd, int &count) { if (list_timeline.empty()) { return; } // allow also pedestrians on any road including crossings // the complex bus center in front of the station is almost empty ... if (bd->get_weg_ribi(road_wt)) { // we create maximal 4 pedestrians here for performance reasons for (int i = 0; i < 4 && count > 0; i++) { if (bd->obj_count() >= 120) { // tile too full return; } pedestrian_t* fg = new pedestrian_t(bd); if (fg->time_to_life > 0 && bd->obj_add(fg) != 0) { fg->calc_height(bd); uint32 separate_pedestrians = (bd->obj_count()*23) << YARDS_PER_VEHICLE_STEP_SHIFT; // walk a little fg->sync_step( (separate_pedestrians % (255 << YARDS_PER_VEHICLE_STEP_SHIFT))/128 ); count--; } else { // delete it, if we could not put it on the map fg->set_flag(obj_t::not_on_map); // do not try to delete it from sync-list fg->time_to_life = 0; return; // it is pointless to try for more here } } } } int pedestrian_t::generate_pedestrians_near(grund_t *gr, int count) { generate_pedestrians_at(gr, count); for (int i = 0; i < 4 && count>0; i++) { if (grund_t *gr_next = welt->lookup_kartenboden(gr->get_pos().get_2d() + koord::nesw[i])) { generate_pedestrians_at(gr_next, count); } } return count; } sync_result pedestrian_t::sync_step(uint32 delta_t) { time_to_life -= delta_t; if (time_to_life>0) { weg_next += 128*delta_t; weg_next -= do_drive( weg_next ); return time_to_life>0 ? SYNC_OK : SYNC_DELETE; } return SYNC_DELETE; } grund_t* pedestrian_t::hop_check() { grund_t *from = welt->lookup(pos_next); if(!from) { time_to_life = 0; return NULL; } // find the allowed directions const weg_t *weg = from->get_weg(road_wt); if(weg==NULL) { // no road anymore: destroy it time_to_life = 0; return NULL; } if (from->obj_count() >= 240) { time_to_life = 0; return NULL; // target tile full, just die } return from; } void pedestrian_t::hop(grund_t *gr) { const koord3d from = get_pos(); // hop leave_tile(); set_pos(gr->get_pos()); // no need to call enter_tile() // if this fails, the target tile is full, but this should already have been checked in hop_check const bool ok = gr->obj_add(this); assert(ok); (void)ok; // determine pos_next const weg_t *weg = gr->get_weg(road_wt); // new target grund_t *to = NULL; // current single direction ribi_t::ribi current_direction = ribi_type(from, get_pos()); // ribi opposite to current direction ribi_t::ribi reverse_direction = ribi_t::reverse_single( current_direction ); // all possible directions ribi_t::ribi ribi = weg->get_ribi_unmasked() & (~reverse_direction); // randomized offset const uint8 offset = (ribi > 0 && ribi_t::is_single(ribi)) ? 0 : sim_async_rand(4); ribi_t::ribi new_direction = ribi_t::none; for(uint r = 0; r < 4; r++) { new_direction = ribi_t::nesw[ (r+offset) & 3]; if( (ribi & new_direction)!=0 && gr->get_neighbour(to, road_wt, new_direction) ) { // this is our next target break; } } steps_offset = 0; if (to) { pos_next = to->get_pos(); if ( ribi_t::is_twoway(weg->get_ribi_unmasked()) || new_direction == current_direction ) { // going straight direction = calc_set_direction(from, pos_next); } else { ribi_t::ribi turn_ribi = on_left ? ribi_t::rotate90l(current_direction) : ribi_t::rotate90(current_direction); if (turn_ribi == new_direction) { // short diagonal (turn but do not cross street) direction = calc_set_direction(from, pos_next); steps_next = (ped_offset*181) / 128; // * sqrt(2) steps_offset = 0; } else { // do not cross street diagonally, change side on_left = !on_left; direction = calc_set_direction(get_pos(), pos_next); } } } else { // dead end, turn pos_next = from; direction = calc_set_direction(get_pos(), pos_next); steps_offset = VEHICLE_STEPS_PER_TILE - ped_offset; steps_next = ped_offset; on_left = !on_left; } calc_disp_lane(); // carry over remainder to next tile for continuous animation during straight movement uint16 steps_per_animation = desc->get_steps_per_frame() * desc->get_animation_count(ribi_t::get_dir(direction)); if (steps_per_animation > 0) { animation_steps = (animation_steps + steps_next + 1) % steps_per_animation; } else { animation_steps = 0; } calc_image(); } void pedestrian_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const { // vehicles needs finer steps to appear smoother sint32 display_steps = (uint32)(steps + steps_offset)*(uint16)raster_width; if( dx && dy ) { display_steps &= 0xFFFFFC00; } else { display_steps = (display_steps*diagonal_multiplier)>>10; } xoff += (display_steps*dx) >> 10; yoff += ((display_steps*dy) >> 10) + (get_hoff(raster_width))/(4*16); if (on_left) { sint32 left_off_steps = ( (VEHICLE_STEPS_PER_TILE - 2*ped_offset)*(uint16)raster_width ) & 0xFFFFFC00; if (dx*dy==0) { // diagonal left_off_steps /= 2; } // turn left (dx,dy) increments xoff += (left_off_steps*2*dy) >> 10; yoff -= (left_off_steps*dx) >> (10+1); } } void pedestrian_t::info(cbuffer_t & buf) const { char const* const owner = translator::translate("Kein Besitzer\n"); buf.append(owner); if (char const* const maker = get_desc()->get_copyright()) { buf.printf(translator::translate("Constructed by %s"), maker); } } simutrans-124.3/src/simutrans/vehicle/pedestrian.h000066400000000000000000000043631474050137200223230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_PEDESTRIAN_H #define VEHICLE_PEDESTRIAN_H #include "simroadtraffic.h" #include "../tpl/freelist_iter_tpl.h" class pedestrian_desc_t; class grund_t; /** * Pedestrians also are road users. * @see road_user_t */ class pedestrian_t : public road_user_t { private: static stringhashtable_tpl table; private: const pedestrian_desc_t *desc; uint16 animation_steps; uint16 steps_offset; uint16 ped_offset; bool on_left; bool list_empty(); static freelist_iter_tpl fl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules static void generate_pedestrians_at(grund_t *gr, int& count); protected: void rdwr(loadsave_t *file) OVERRIDE; void calc_image() OVERRIDE; /** * Creates pedestrian at position given by @p gr. * Does not add pedestrian to the tile! */ pedestrian_t(grund_t *gr); public: pedestrian_t(loadsave_t *file); static void sync_handler(uint32 delta_t) { fl.sync_step(delta_t); } const pedestrian_desc_t *get_desc() const { return desc; } const char *get_name() const OVERRIDE {return "Fussgaenger";} typ get_typ() const OVERRIDE { return pedestrian; } void info(cbuffer_t & buf) const OVERRIDE; sync_result sync_step(uint32 delta_t); ///@ returns true if pedestrian walks on the left side of the road bool is_on_left() const { return on_left; } void calc_disp_lane(); void rotate90() OVERRIDE; // overloaded to enable animations image_id get_image() const OVERRIDE; void get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const OVERRIDE; grund_t* hop_check() OVERRIDE; void hop(grund_t* gr) OVERRIDE; void* operator new(size_t) { return fl.gimme_node(); } void operator delete(void* p) { return fl.putback_node(p); } // class register functions static bool register_desc(const pedestrian_desc_t *desc); static bool successfully_loaded(); /** * Tries to generate some pedestrians on the square and the * adjacent squares. Return actual number of generated * pedestrians. */ static int generate_pedestrians_near(grund_t *gr, int count); static void build_timeline_list( karte_t *welt ); }; #endif simutrans-124.3/src/simutrans/vehicle/rail_vehicle.cc000066400000000000000000000676451474050137200227650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "rail_vehicle.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../simware.h" #include "../simconvoi.h" #include "../world/simworld.h" #include "../obj/way/schiene.h" #include "../obj/depot.h" #include "../obj/roadsign.h" #include "../obj/signal.h" #include "../dataobj/schedule.h" #include "../obj/crossing.h" /* from now on rail vehicles (and other vehicles using blocks) */ rail_vehicle_t::rail_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t() { vehicle_t::rdwr_from_convoi(file); if( file->is_loading() ) { static const vehicle_desc_t *last_desc = NULL; if(is_first) { last_desc = NULL; } // try to find a matching vehicle if(desc==NULL) { int power = (is_first || fracht.empty() || fracht.front() == goods_manager_t::none) ? 500 : 0; const goods_desc_t* w = fracht.empty() ? goods_manager_t::none : fracht.front().get_desc(); dbg->warning("rail_vehicle_t::rail_vehicle_t()","try to find a fitting vehicle for %s.", power>0 ? "engine": w->get_name() ); if(last_desc!=NULL && last_desc->can_follow(last_desc) && last_desc->get_freight_type()==w && (!is_last || last_desc->get_trailer(0)==NULL)) { // same as previously ... desc = last_desc; } else { // we have to search desc = vehicle_builder_t::get_best_matching(get_waytype(), 0, w!=goods_manager_t::none?5000:0, power, speed_to_kmh(speed_limit), w, false, last_desc, is_last ); } if(desc) { DBG_MESSAGE("rail_vehicle_t::rail_vehicle_t()","replaced by %s",desc->get_name()); calc_image(); } else { dbg->error("rail_vehicle_t::rail_vehicle_t()","no matching desc found for %s!",w->get_name()); } if (!fracht.empty() && fracht.front().amount == 0) { // this was only there to find a matching vehicle fracht.remove_first(); } } // update last desc if( desc ) { last_desc = desc; } } } rail_vehicle_t::rail_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) : vehicle_t(pos, desc, player) { cnv = cn; } rail_vehicle_t::~rail_vehicle_t() { if (cnv && leading) { route_t const& r = *cnv->get_route(); if (!r.empty() && route_index < r.get_count()) { // free all reserved blocks route_t::index_t dummy; block_reserver(&r, cnv->back()->get_route_index(), dummy, dummy, target_halt.is_bound() ? 100000 : 1, false, false); } } grund_t *gr = welt->lookup(get_pos()); if(gr) { schiene_t * sch = (schiene_t *)gr->get_weg(get_waytype()); if(sch) { sch->unreserve(this); } } } void rail_vehicle_t::set_convoi(convoi_t *c) { if(c!=cnv) { DBG_MESSAGE("rail_vehicle_t::set_convoi()","new=%p old=%p",c,cnv); if(leading) { if(cnv!=NULL && cnv!=(convoi_t *)1) { // free route from old convoi route_t const& r = *cnv->get_route(); if( !r.empty() && route_index + 1U < r.get_count() - 1 ) { route_t::index_t dummy; block_reserver(&r, cnv->back()->get_route_index(), dummy, dummy, 100000, false, false); target_halt = halthandle_t(); } } else if( c->get_next_reservation_index()==0 ) { assert(c!=NULL); // eventually search new route route_t const& r = *c->get_route(); if( (r.get_count()<=route_index || r.empty() || get_pos()==r.back()) && c->get_state()!=convoi_t::INITIAL && c->get_state()!=convoi_t::LOADING && c->get_state()!=convoi_t::SELF_DESTRUCT ) { check_for_finish = true; dbg->warning("rail_vehicle_t::set_convoi()", "convoi %i had a too high route index! (%i of max %i)", c->self.get_id(), route_index, r.get_count() - 1); } // set default next stop index c->set_next_stop_index( max(route_index,1)-1 ); // need to reserve new route? if( !check_for_finish && c->get_state()!=convoi_t::SELF_DESTRUCT && (c->get_state()==convoi_t::DRIVING || c->get_state()>=convoi_t::LEAVING_DEPOT) ) { sint32 num_index = cnv==(convoi_t *)1 ? 1001 : 0; // only during loadtype: cnv==1 indicates, that the convoi did reserve a stop route_t::index_t next_signal, next_crossing; cnv = c; if( block_reserver(&r, max(route_index,1)-1, next_signal, next_crossing, num_index, true, false) ) { c->set_next_stop_index( next_signal>next_crossing ? next_crossing : next_signal ); } } } } vehicle_t::set_convoi(c); } } // need to reset halt reservation (if there was one) bool rail_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) { if(leading && route_indexget_route()->get_count()) { // free all reserved blocks route_t::index_t dummy; block_reserver(cnv->get_route(), cnv->back()->get_route_index(), dummy, dummy, target_halt.is_bound() ? 100000 : 1, false, true); } cnv->set_next_reservation_index( 0 ); // nothing to reserve target_halt = halthandle_t(); // no block reserved // use length 8888 tiles to advance to the end of all stations const uint16 convoy_length = world()->get_settings().get_stop_halt_as_scheduled() ? cnv->get_tile_length() : 8888; return route->calc_route(welt, start, ziel, this, max_speed, convoy_length ); } bool rail_vehicle_t::check_next_tile(const grund_t *bd) const { schiene_t const* const sch = obj_cast(bd->get_weg(get_waytype())); if( !sch ) { return false; } // diesel and steam engines can use electrified track as well. // also allow driving on foreign tracks ... const bool needs_no_electric = !(cnv!=NULL ? cnv->needs_electrification() : desc->get_engine_type()==vehicle_desc_t::electric); if( (!needs_no_electric && !sch->is_electrified()) || sch->get_max_speed() == 0 ) { return false; } if (depot_t *depot = bd->get_depot()) { if (depot->get_waytype() != desc->get_waytype() || depot->get_owner() != get_owner()) { return false; } } // now check for special signs if(sch->has_sign()) { const roadsign_t* rs = bd->find(); if( rs->get_desc()->get_wtyp()==get_waytype() ) { if( cnv != NULL && rs->get_desc()->get_min_speed() > 0 && rs->get_desc()->get_min_speed() > cnv->get_min_top_speed() ) { // below speed limit return false; } if( rs->get_desc()->is_private_way() && (rs->get_player_mask() & (1<is_waiting() ) { // we are searching a stop here: // ok, we can go where we already are ... if(bd->get_pos()==get_pos()) { return true; } // we cannot pass an end of choose area if(sch->has_sign()) { const roadsign_t* rs = bd->find(); if( rs->get_desc()->get_wtyp()==get_waytype() ) { if( rs->get_desc()->get_flags() & roadsign_desc_t::END_OF_CHOOSE_AREA ) { return false; } } } // but we can only use empty blocks ... // now check, if we could enter here return sch->can_reserve(cnv->self); } return true; } // how expensive to go here (for way search) int rail_vehicle_t::get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const { // first favor faster ways if( w==NULL ) { // only occurs when deletion during way search return 999; } // add cost for going (with maximum speed, cost is 1) const sint32 max_tile_speed = w->get_max_speed(); int costs = (max_speed<=max_tile_speed) ? 1 : 4-(3*max_tile_speed)/max_speed; // effect of slope if( gr->get_weg_hang()!=0 ) { // check if the slope is upwards, relative to the previous tile // 25 hardcoded, see get_cost_upslope() costs += 25 * get_sloping_upwards( gr->get_weg_hang(), from ); } return costs; } // this routine is called by find_route, to determined if we reached a destination bool rail_vehicle_t::is_target(const grund_t *gr,const grund_t *prev_gr) const { const schiene_t * sch1 = (const schiene_t *) gr->get_weg(get_waytype()); // first check blocks, if we can go there if( sch1->can_reserve(cnv->self) ) { // just check, if we reached a free stop position of this halt if( gr->is_halt() && gr->get_halt()==target_halt ) { // now we must check the predecessor ... if( prev_gr!=NULL ) { const koord dir=gr->get_pos().get_2d()-prev_gr->get_pos().get_2d(); const ribi_t::ribi ribi = ribi_type(dir); if( gr->get_weg(get_waytype())->get_ribi_maske() & ribi ) { // signal/one way sign wrong direction return false; } grund_t *to; if( !gr->get_neighbour(to,get_waytype(),ribi) || !(to->get_halt()==target_halt) || (to->get_weg(get_waytype())->get_ribi_maske() & ribi_type(dir))!=0 ) { // end of stop: Is it long enough? // end of stop could be also signal! uint16 tiles = cnv->get_tile_length(); while( tiles>1 ) { if( gr->get_weg(get_waytype())->get_ribi_maske() & ribi || !gr->get_neighbour(to,get_waytype(),ribi_t::backward(ribi)) || !(to->get_halt()==target_halt) ) { return false; } gr = to; tiles --; } return true; } } } } return false; } bool rail_vehicle_t::is_longblock_signal_clear(signal_t *sig, route_t::index_t next_block, sint32 &restart_speed) { // longblock signal: first check, whether there is a signal coming up on the route => just like normal signal route_t::index_t next_signal, next_crossing; if( !block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false ) ) { // not even the "Normal" signal route part is free => no bother checking further on sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } if( next_signal != route_t::INVALID_INDEX ) { // success, and there is a signal before end of route => finished sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_crossing, next_signal ) ); return true; } // no signal before end_of_route => need to do route search in a step if( !cnv->is_waiting() ) { restart_speed = -1; return false; } // now we can use the route search array, since we are in step mode // (route until end is already reserved at this point!) uint8 schedule_index = cnv->get_schedule()->get_current_stop()+1; route_t target_rt; koord3d cur_pos = cnv->get_route()->back(); route_t::index_t dummy; route_t::index_t next_next_signal = route_t::INVALID_INDEX; if(schedule_index >= cnv->get_schedule()->get_count()) { schedule_index = 0; } while( schedule_index != cnv->get_schedule()->get_current_stop() ) { // now search // search for route bool success = target_rt.calc_route( welt, cur_pos, cnv->get_schedule()->entries[schedule_index].pos, this, speed_to_kmh(cnv->get_min_top_speed()), 8888 /*cnv->get_tile_length()*/ ); if( target_rt.is_contained(get_pos()) ) { // do not reserve route going through my current stop& break; } if( success ) { success = block_reserver( &target_rt, 1, next_next_signal, dummy, 0, true, false ); block_reserver( &target_rt, 1, dummy, dummy, 0, false, false ); } if( success ) { // ok, would be free if( next_next_signal finished // (however, if it is this signal, we need to renew reservation ... if( target_rt.at(next_next_signal) == cnv->get_route()->at( next_block ) ) { block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false ); } sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( min( next_crossing, next_signal ), cnv->get_route()->get_count()-1-1 ) ); return true; } } if( !success ) { block_reserver( cnv->get_route(), next_block+1, next_next_signal, dummy, 0, false, false ); sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } // prepare for next leg of schedule cur_pos = target_rt.back(); schedule_index ++; if(schedule_index >= cnv->get_schedule()->get_count()) { schedule_index = 0; } } if( cnv->get_next_stop_index()-1 <= route_index ) { cnv->set_next_stop_index( cnv->get_route()->get_count()-1 ); } return true; } bool rail_vehicle_t::is_choose_signal_clear(signal_t *sig, const route_t::index_t start_block, sint32 &restart_speed) { bool choose_ok = false; target_halt = halthandle_t(); route_t::index_t next_signal, next_crossing; grund_t const* const target = welt->lookup(cnv->get_route()->back()); if( cnv->get_schedule_target()!=koord3d::invalid ) { // destination is a waypoint! goto skip_choose; } if( target==NULL ) { cnv->suche_neue_route(); return false; } // first check, if we are not heading to a waypoint if( !target->get_halt().is_bound() ) { goto skip_choose; } // now we might choose something at least choose_ok = true; // check, if there is another choose signal or end_of_choose on the route for( uint32 idx=start_block+1; choose_ok && idxget_route()->get_count(); idx++ ) { grund_t *gr = welt->lookup(cnv->get_route()->at(idx)); if( gr==0 ) { choose_ok = false; break; } if( gr->get_halt()==target->get_halt() ) { target_halt = gr->get_halt(); break; } weg_t *way = gr->get_weg(get_waytype()); if( way==0 ) { choose_ok = false; break; } if( way->has_sign() ) { roadsign_t *rs = gr->find(1); if( rs && rs->get_desc()->get_wtyp()==get_waytype() ) { if( rs->get_desc()->get_flags() & roadsign_desc_t::END_OF_CHOOSE_AREA ) { // end of choose on route => not choosing here choose_ok = false; } } } if( way->has_signal() ) { signal_t *sig = gr->find(1); if( sig && sig->get_desc()->is_choose_sign() ) { // second choose signal on route => not choosing here choose_ok = false; } } } skip_choose: if( !choose_ok ) { // just act as normal signal if( block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 0, true, false ) ) { sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_crossing, next_signal ) ); return true; } // not free => wait here if directly in front sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } target_halt = target->get_halt(); if( !block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 100000, true, false ) ) { // no free route to target! // note: any old reservations should be invalid after the block reserver call. // => We can now start freshly all over if(!cnv->is_waiting()) { // we are driving and cannot search yet restart_speed = -1; target_halt = halthandle_t(); return false; } // now we are in a step and can use the route search array route_t target_rt; const int richtung = ribi_type(get_pos(), pos_next); // to avoid confusion at diagonals if( !target_rt.find_route( welt, cnv->get_route()->at(start_block), this, speed_to_kmh(cnv->get_min_top_speed()), richtung, welt->get_settings().get_max_choose_route_steps() ) ) { // nothing empty or not route with less than get_max_choose_route_steps() tiles target_halt = halthandle_t(); sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } else { // try to alloc the whole route cnv->access_route()->remove_koord_from(start_block); cnv->access_route()->append( &target_rt ); if( !block_reserver( cnv->get_route(), start_block+1, next_signal, next_crossing, 100000, true, false ) ) { dbg->error( "rail_vehicle_t::is_choose_signal_clear()", "could not reserved route after find_route!" ); target_halt = halthandle_t(); sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } } // reserved route to target } sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_crossing, next_signal ) ); return true; } bool rail_vehicle_t::is_pre_signal_clear(signal_t *sig, route_t::index_t next_block, sint32 &restart_speed) { // parse to next signal; if needed recurse, since we allow cascading route_t::index_t next_signal, next_crossing; if( block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false ) ) { if( next_signal == route_t::INVALID_INDEX || cnv->get_route()->at(next_signal) == cnv->get_route()->back() || is_signal_clear( next_signal, restart_speed ) ) { // ok, end of route => we can go sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_signal, next_crossing ) ); return true; } // when we reached here, the way is apparently not free => release reservation and set state to next free sig->set_state( roadsign_t::STATE_YELLOW ); block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, false, false ); restart_speed = 0; return false; } // if we end up here, there was not even the next block free sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } bool rail_vehicle_t::is_priority_signal_clear(signal_t *sig, route_t::index_t next_block, sint32 &restart_speed) { // parse to next signal; if needed recurse, since we allow cascading route_t::index_t next_signal, next_crossing; if( block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false ) ) { if( next_signal == route_t::INVALID_INDEX || cnv->get_route()->at(next_signal) == cnv->get_route()->back() || is_signal_clear( next_signal, restart_speed ) ) { // ok, end of route => we can go sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_signal, next_crossing ) ); return true; } // when we reached here, the way after the last signal is not free though the way before is => we can still go if( cnv->get_next_stop_index()<=next_signal+1 ) { // only show third aspect on last signal of cascade sig->set_state( roadsign_t::STATE_YELLOW ); } else { sig->set_state( roadsign_t::STATE_GREEN ); } cnv->set_next_stop_index( min( next_signal, next_crossing ) ); return false; } // if we end up here, there was not even the next block free sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } bool rail_vehicle_t::is_signal_clear(route_t::index_t next_block, sint32 &restart_speed) { // called, when there is a signal; will call other signal routines if needed grund_t *gr_next_block = welt->lookup(cnv->get_route()->at(next_block)); signal_t *sig = gr_next_block->find(); if( sig==NULL ) { dbg->error( "rail_vehicle_t::is_signal_clear()", "called at %s without a signal!", cnv->get_route()->at(next_block).get_str() ); return true; } // action depend on the next signal const roadsign_desc_t *sig_desc=sig->get_desc(); // simple signal: fail, if next block is not free if( sig_desc->is_simple_signal() ) { route_t::index_t next_signal, next_crossing; if( block_reserver( cnv->get_route(), next_block+1, next_signal, next_crossing, 0, true, false ) ) { sig->set_state( roadsign_t::STATE_GREEN ); cnv->set_next_stop_index( min( next_crossing, next_signal ) ); return true; } // not free => wait here if directly in front sig->set_state( roadsign_t::STATE_RED ); restart_speed = 0; return false; } if( sig_desc->is_pre_signal() ) { return is_pre_signal_clear( sig, next_block, restart_speed ); } if ( sig_desc->is_priority_signal() ) { return is_priority_signal_clear( sig, next_block, restart_speed ); } if( sig_desc->is_longblock_signal() ) { return is_longblock_signal_clear( sig, next_block, restart_speed ); } if( sig_desc->is_choose_sign() ) { return is_choose_signal_clear( sig, next_block, restart_speed ); } dbg->error( "rail_vehicle_t::is_signal_clear()", "felt through at signal at %s", cnv->get_route()->at(next_block).get_str() ); return false; } bool rail_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8) { assert(leading); route_t::index_t next_signal, next_crossing; if( cnv->get_state()==convoi_t::CAN_START || cnv->get_state()==convoi_t::CAN_START_ONE_MONTH || cnv->get_state()==convoi_t::CAN_START_TWO_MONTHS ) { // reserve first block at the start until the next signal grund_t *gr_current = welt->lookup( get_pos() ); weg_t *w = gr_current ? gr_current->get_weg(get_waytype()) : NULL; if( w==NULL || !(w->has_signal() || w->is_crossing()) ) { // free track => reserve up to next signal if( !block_reserver(cnv->get_route(), max(route_index,1)-1, next_signal, next_crossing, 0, true, false ) ) { restart_speed = 0; return false; } cnv->set_next_stop_index( next_crossingset_next_stop_index( max(route_index,1)-1 ); if( steps can drive to signal safely return true; } // we start with a signal/crossing => use stuff below ... } assert(gr); if(gr->obj_count()>250) { // too many objects here return false; } schiene_t *w = (schiene_t *)gr->get_weg(get_waytype()); if(w==NULL) { return false; } /* this should happen only before signals ... * but if it is already reserved, we can save lots of other checks later */ if( !w->can_reserve(cnv->self) ) { restart_speed = 0; return false; } // is there any signal/crossing to be reserved? route_t::index_t next_block = cnv->get_next_stop_index()-1; if( next_block >= cnv->get_route()->get_count() ) { // no obstacle in the way => drive on ... return true; } // signal disappeared, train passes the tile of former signal if( next_block+1 < route_index ) { // we need to reserve the next block even if there is no signal present anymore bool ok = block_reserver( cnv->get_route(), route_index, next_signal, next_crossing, 0, true, false ); if (ok) { cnv->set_next_stop_index( min( next_crossing, next_signal ) ); } return ok; // if reservation was not possible the train will wait on the track until block is free } if( next_block <= route_index+3 ) { koord3d block_pos=cnv->get_route()->at(next_block); grund_t *gr_next_block = welt->lookup(block_pos); const schiene_t *sch1 = gr_next_block ? (const schiene_t *)gr_next_block->get_weg(get_waytype()) : NULL; if(sch1==NULL) { // way (weg) not existent (likely destroyed) cnv->suche_neue_route(); return false; } // Is a crossing? // note: crossing and signal might exist on same tile // so first check crossing if( sch1->is_crossing() ) { if( crossing_t* cr = gr_next_block->find(2) ) { // ok, here is a draw/turnbridge ... bool ok = cr->request_crossing(this); if(!ok) { // cannot cross => wait here restart_speed = 0; return cnv->get_next_stop_index()>route_index+1; } else if( !sch1->has_signal() ) { // can reserve: find next place to do something and drive on if( block_pos == cnv->get_route()->back() ) { // is also last tile => go on ... cnv->set_next_stop_index( route_t::INVALID_INDEX ); return true; } else if( !block_reserver( cnv->get_route(), cnv->get_next_stop_index(), next_signal, next_crossing, 0, true, false ) ) { dbg->error( "rail_vehicle_t::can_enter_tile()", "block not free but was reserved!" ); return false; } cnv->set_next_stop_index( next_crossinghas_signal() ) { if( !is_signal_clear( next_block, restart_speed ) ) { // only return false, if we are directly in front of the signal return cnv->get_next_stop_index()>route_index; } } } return true; } /** * reserves or un-reserves all blocks and returns the handle to the next block (if there) * if count is larger than 1, (and defined) maximum MAX_CHOOSE_BLOCK_TILES tiles will be checked * (freeing or reserving a choose signal path) * if (!reserve && force_unreserve) then un-reserve everything till the end of the route * return the last checked block */ bool rail_vehicle_t::block_reserver(const route_t *route, route_t::index_t start_index, route_t::index_t &next_signal_index, route_t::index_t &next_crossing_index, int count, bool reserve, bool force_unreserve ) const { bool success=true; #ifdef MAX_CHOOSE_BLOCK_TILES int max_tiles=2*MAX_CHOOSE_BLOCK_TILES; // max tiles to check for choosesignals #endif slist_tpl signs; // switch all signals on their way too ... if(start_index>=route->get_count()) { cnv->set_next_reservation_index( max(route->get_count(),1)-1 ); return 0; } if(route->at(start_index)==get_pos() && reserve) { start_index++; } if( !reserve ) { cnv->set_next_reservation_index( start_index ); } // find next block segment en route route_t::index_t i = start_index; next_signal_index = route_t::INVALID_INDEX; next_crossing_index = route_t::INVALID_INDEX; bool unreserve_now = false; for ( ; success && count>=0 && iget_count(); i++) { koord3d pos = route->at(i); grund_t *gr = welt->lookup(pos); schiene_t * sch1 = gr ? (schiene_t *)gr->get_weg(get_waytype()) : NULL; if(sch1==NULL && reserve) { // reserve until the end of track break; } // we un-reserve also nonexistent tiles! (may happen during deletion) #ifdef MAX_CHOOSE_BLOCK_TILES max_tiles--; if(max_tiles<0 && count>1) { break; } #endif if(reserve) { if( sch1->has_signal() && iget_count()-1 ) { if(count) { signs.append(gr); } count --; next_signal_index = i; } if( !sch1->reserve( cnv->self, ribi_type( route->at(max(1u,i)-1u), route->at(min(route->get_count()-1u,i+1u)) ) ) ) { success = false; } if(next_crossing_index==route_t::INVALID_INDEX && sch1->is_crossing()) { next_crossing_index = i; } } else if(sch1) { if(!sch1->unreserve(cnv->self)) { if(unreserve_now) { // reached an reserved or free track => finished return false; } } else { // un-reserve from here (used during sale, since there might be reserved tiles not freed) unreserve_now = !force_unreserve; } if(sch1->has_signal()) { signal_t* signal = gr->find(); if(signal) { signal->set_state(roadsign_t::STATE_RED); } } if(sch1->is_crossing()) { gr->find()->release_crossing(this); } } } if(!reserve) { return false; } // here we go only with reserve //DBG_MESSAGE("block_reserver()","signals at %i, success=%d",next_signal_index,success); // free, in case of un-reserve or no success in reservation if(!success) { // free reservation for ( route_t::index_t j=start_index; jlookup( route->at(j))->get_weg(get_waytype()); sch1->unreserve(cnv->self); } cnv->set_next_reservation_index( start_index ); return false; } // ok, switch everything green ... for(grund_t* const g : signs) { if (signal_t* const signal = g->find()) { signal->set_state(roadsign_t::STATE_GREEN); } } cnv->set_next_reservation_index( i ); return true; } /* beware: we must un-reserve rail blocks... */ void rail_vehicle_t::leave_tile() { vehicle_t::leave_tile(); // fix counters if(last) { grund_t *gr = welt->lookup( get_pos() ); if(gr) { schiene_t *sch0 = (schiene_t *) gr->get_weg(get_waytype()); if(sch0) { sch0->unreserve(this); // tell next signal? // and switch to red if(sch0->has_signal()) { signal_t* sig = gr->find(); if(sig) { sig->set_state(roadsign_t::STATE_RED); } } } } } } void rail_vehicle_t::enter_tile(grund_t* gr) { vehicle_t::enter_tile(gr); if( schiene_t *sch0 = (schiene_t *) gr->get_weg(get_waytype()) ) { // way statistics const int cargo = get_total_cargo(); sch0->book(cargo, WAY_STAT_GOODS); if(leading) { sch0->book(1, WAY_STAT_CONVOIS); sch0->reserve( cnv->self, get_direction() ); } } } schedule_t * rail_vehicle_t::generate_new_schedule() const { return desc->get_waytype()==tram_wt ? new tram_schedule_t() : new train_schedule_t(); } schedule_t * monorail_vehicle_t::generate_new_schedule() const { return new monorail_schedule_t(); } schedule_t * maglev_vehicle_t::generate_new_schedule() const { return new maglev_schedule_t(); } schedule_t * narrowgauge_vehicle_t::generate_new_schedule() const { return new narrowgauge_schedule_t(); } simutrans-124.3/src/simutrans/vehicle/rail_vehicle.h000066400000000000000000000102731474050137200226100ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_RAIL_VEHICLE_H #define VEHICLE_RAIL_VEHICLE_H #include "vehicle.h" /** * A class for rail vehicles (trains). Manages the look of the vehicles * and the navigability of tiles. * @see vehicle_t */ class rail_vehicle_t : public vehicle_t { protected: bool check_next_tile(const grund_t *bd) const OVERRIDE; void enter_tile(grund_t*) OVERRIDE; bool is_signal_clear(route_t::index_t start_index, sint32 &restart_speed); bool is_pre_signal_clear(signal_t *sig, route_t::index_t start_index, sint32 &restart_speed); bool is_priority_signal_clear(signal_t *sig, route_t::index_t start_index, sint32 &restart_speed); bool is_longblock_signal_clear(signal_t *sig, route_t::index_t start_index, sint32 &restart_speed); bool is_choose_signal_clear(signal_t *sig, route_t::index_t start_index, sint32 &restart_speed); public: waytype_t get_waytype() const OVERRIDE { return track_wt; } // since we might need to un-reserve previously used blocks, we must do this before calculation a new route bool calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) OVERRIDE; // how expensive to go here (for way search) int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const OVERRIDE; uint32 get_cost_upslope() const OVERRIDE { return 25; } // returns true for the way search to an unknown target. bool is_target(const grund_t *,const grund_t *) const OVERRIDE; // handles all block stuff and route choosing ... bool can_enter_tile(const grund_t *gr_next, sint32 &restart_speed, uint8) OVERRIDE; // reserves or un-reserves all blocks and returns the handle to the next block (if there) // returns true on successful reservation bool block_reserver(const route_t *route, route_t::index_t start_index, route_t::index_t &next_signal, route_t::index_t &next_crossing, int signal_count, bool reserve, bool force_unreserve ) const; void leave_tile() OVERRIDE; typ get_typ() const OVERRIDE { return rail_vehicle; } rail_vehicle_t(loadsave_t *file, bool is_first, bool is_last); rail_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t *cnv); ~rail_vehicle_t(); void set_convoi(convoi_t *c) OVERRIDE; schedule_t * generate_new_schedule() const OVERRIDE; }; /** * very similar to normal railroad, so we can implement it here completely * @see vehicle_t */ class monorail_vehicle_t : public rail_vehicle_t { public: waytype_t get_waytype() const OVERRIDE { return monorail_wt; } // all handled by rail_vehicle_t monorail_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : rail_vehicle_t(file,is_first, is_last) {} monorail_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv) : rail_vehicle_t(pos, desc, player, cnv) {} typ get_typ() const OVERRIDE { return monorail_vehicle; } schedule_t * generate_new_schedule() const OVERRIDE; }; /** * very similar to normal railroad, so we can implement it here completely * @see vehicle_t */ class maglev_vehicle_t : public rail_vehicle_t { public: waytype_t get_waytype() const OVERRIDE { return maglev_wt; } // all handled by rail_vehicle_t maglev_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : rail_vehicle_t(file, is_first, is_last) {} maglev_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv) : rail_vehicle_t(pos, desc, player, cnv) {} typ get_typ() const OVERRIDE { return maglev_vehicle; } schedule_t * generate_new_schedule() const OVERRIDE; }; /** * very similar to normal railroad, so we can implement it here completely * @see vehicle_t */ class narrowgauge_vehicle_t : public rail_vehicle_t { public: waytype_t get_waytype() const OVERRIDE { return narrowgauge_wt; } // all handled by rail_vehicle_t narrowgauge_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : rail_vehicle_t(file, is_first, is_last) {} narrowgauge_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv) : rail_vehicle_t(pos, desc, player, cnv) {} typ get_typ() const OVERRIDE { return narrowgauge_vehicle; } schedule_t * generate_new_schedule() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/vehicle/road_vehicle.cc000066400000000000000000000472441474050137200227540ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "road_vehicle.h" #include "simroadtraffic.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../obj/way/strasse.h" #include "../dataobj/schedule.h" #include "../dataobj/translator.h" #include "../descriptor/citycar_desc.h" #include "../obj/crossing.h" #include "../obj/roadsign.h" #include "../player/simplay.h" #include "../simware.h" #include "../world/simworld.h" #include "../simconvoi.h" #include "../simhalt.h" #include "../simmesg.h" #include "../utils/cbuffer.h" road_vehicle_t::road_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) : vehicle_t(pos, desc, player) { cnv = cn; } road_vehicle_t::road_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t() { rdwr_from_convoi(file); if( file->is_loading() ) { static const vehicle_desc_t *last_desc = NULL; if(is_first) { last_desc = NULL; } // try to find a matching vehicle if(desc==NULL) { const goods_desc_t* w = (!fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers); dbg->warning("road_vehicle_t::road_vehicle_t()","try to find a fitting vehicle for %s.", w->get_name() ); desc = vehicle_builder_t::get_best_matching(road_wt, 0, (fracht.empty() ? 0 : 50), is_first?50:0, speed_to_kmh(speed_limit), w, true, last_desc, is_last ); if(desc) { DBG_MESSAGE("road_vehicle_t::road_vehicle_t()","replaced by %s",desc->get_name()); // still wrong load ... calc_image(); } if(!fracht.empty() && fracht.front().amount == 0) { // this was only there to find a matching vehicle fracht.remove_first(); } } if( desc ) { last_desc = desc; } calc_disp_lane(false); // we do not know right now, if we are overtaking ... } } void road_vehicle_t::rotate90() { vehicle_t::rotate90(); calc_disp_lane(cnv && cnv->is_overtaking()); } void road_vehicle_t::calc_disp_lane(bool is_overtaking) { disp_lane = welt->get_settings().is_drive_left() ? 1 : 3; ribi_t::ribi dir = get_direction(); /* disp_lane is valid for vehicles moving to the right side of the screen, must be mirrored if SE <= heading < NW, and also if overtaking as there are five "display lanes" in simutrans which determine their drawing order. */ bool heading_left = (dir & ribi_t::south) || dir == ribi_t::west; if (heading_left ^ is_overtaking) { disp_lane ^= 2; } } // need to reset halt reservation (if there was one) bool road_vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) { assert(cnv); // free target reservation if(leading && previous_direction!=ribi_t::none && cnv && target_halt.is_bound() ) { // now reserve our choice (beware: might be longer than one tile!) for( uint32 length=0; lengthget_tile_length() && length+1get_route()->get_count(); length++ ) { target_halt->unreserve_position( welt->lookup( cnv->get_route()->at( cnv->get_route()->get_count()-length-1) ), cnv->self ); } } target_halt = halthandle_t(); // no block reserved route_t::route_result_t r = route->calc_route(welt, start, ziel, this, max_speed, cnv->get_tile_length() ); if( r == route_t::valid_route_halt_too_short ) { cbuffer_t buf; buf.printf( translator::translate("Vehicle %s cannot choose because stop too short!"), cnv->get_name()); welt->get_message()->add_message( (const char *)buf, ziel, message_t::traffic_jams, PLAYER_FLAG | cnv->get_owner()->get_player_nr(), cnv->front()->get_base_image() ); } return r; } bool road_vehicle_t::check_next_tile(const grund_t *bd) const { strasse_t *str=(strasse_t *)bd->get_weg(road_wt); if(str==NULL || str->get_max_speed()==0) { return false; } bool electric = cnv!=NULL ? cnv->needs_electrification() : desc->get_engine_type()==vehicle_desc_t::electric; if(electric && !str->is_electrified()) { return false; } // check for signs if(str->has_sign()) { const roadsign_t* rs = bd->find(); if(rs!=NULL) { if( rs->get_desc()->get_min_speed()>0 && rs->get_desc()->get_min_speed()>kmh_to_speed(get_desc()->get_topspeed()) ) { return false; } if( rs->get_desc()->is_private_way() && (rs->get_player_mask() & (1<is_waiting() && rs->get_desc()->get_flags()&roadsign_desc_t::END_OF_CHOOSE_AREA) { return false; } } } return true; } // how expensive to go here (for way search) int road_vehicle_t::get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const { // first favor faster ways if(!w) { return 0xFFFF; } // max_speed? sint32 max_tile_speed = w->get_max_speed(); // add cost for going (with maximum speed, cost is 1) int costs = (max_speed<=max_tile_speed) ? 1 : 4-(3*max_tile_speed)/max_speed; // assume all traffic is not good ... (otherwise even smoke counts ... ) costs += (w->get_statistics(WAY_STAT_CONVOIS) > ( 2 << (welt->get_settings().get_bits_per_month()-16) ) ); // effect of slope if( gr->get_weg_hang()!=0 ) { // check if the slope is upwards, relative to the previous tile // 15 hardcoded, see get_cost_upslope() costs += 15 * get_sloping_upwards( gr->get_weg_hang(), from ); } return costs; } // this routine is called by find_route, to determined if we reached a destination bool road_vehicle_t::is_target(const grund_t *gr, const grund_t *prev_gr) const { // just check, if we reached a free stop position of this halt if(gr->is_halt() && gr->get_halt()==target_halt && target_halt->is_reservable(gr,cnv->self)) { // now we must check the predecessor => try to advance as much as possible if(prev_gr!=NULL) { const koord dir=gr->get_pos().get_2d()-prev_gr->get_pos().get_2d(); ribi_t::ribi ribi = ribi_type(dir); if( gr->get_weg(get_waytype())->get_ribi_maske() & ribi ) { // one way sign wrong direction return false; } grund_t *to; if( !gr->get_neighbour(to,road_wt,ribi) || !(to->get_halt()==target_halt) || (gr->get_weg(get_waytype())->get_ribi_maske() & ribi_type(dir))!=0 || !target_halt->is_reservable(to,cnv->self) ) { // end of stop: Is it long enough? uint16 tiles = cnv->get_tile_length(); while( tiles>1 ) { if( !gr->get_neighbour(to,get_waytype(),ribi_t::backward(ribi)) || !(to->get_halt()==target_halt) || !target_halt->is_reservable(to,cnv->self) ) { return false; } gr = to; tiles --; } return true; } // can advance more return false; } //DBG_MESSAGE("is_target()","success at %i,%i",gr->get_pos().x,gr->get_pos().y); // return true; } return false; } // to make smaller steps than the tile granularity, we have to use this trick void road_vehicle_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const { vehicle_base_t::get_screen_offset( xoff, yoff, raster_width ); if( welt->get_settings().is_drive_left() ) { const int drive_left_dir = ribi_t::get_dir(get_direction()); xoff += tile_raster_scale_x( driveleft_base_offsets[drive_left_dir][0], raster_width ); yoff += tile_raster_scale_y( driveleft_base_offsets[drive_left_dir][1], raster_width ); } // eventually shift position to take care of overtaking if(cnv) { if( cnv->is_overtaking() ) { xoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width); yoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width); } else if( cnv->is_overtaken() ) { xoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width)/5; yoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width)/5; } } } // chooses a route at a choose sign; returns true on success bool road_vehicle_t::choose_route(sint32 &restart_speed, ribi_t::ribi start_direction, uint16 index) { if( cnv->get_schedule_target()!=koord3d::invalid ) { // destination is a waypoint! return true; } // are we heading to a target? route_t *rt = cnv->access_route(); target_halt = haltestelle_t::get_halt( rt->back(), get_owner() ); if( target_halt.is_bound() ) { // since convois can long than one tile, check is more difficult bool can_go_there = true; bool original_route = (rt->back() == cnv->get_schedule()->get_current_entry().pos); for( uint32 length=0; can_go_there && lengthget_tile_length() && length+1get_count(); length++ ) { if( grund_t *gr = welt->lookup( rt->at( rt->get_count()-length-1) ) ) { if (gr->get_halt().is_bound()) { can_go_there &= target_halt->is_reservable( gr, cnv->self ); } else { // if this is the original stop, it is too short! can_go_there |= original_route; } } } if( can_go_there ) { // then reserve it ... for( uint32 length=0; lengthget_tile_length() && length+1get_count(); length++ ) { target_halt->reserve_position( welt->lookup( rt->at( rt->get_count()-length-1) ), cnv->self ); } } else { // cannot go there => need slot search // if we fail, we will wait in a step, much more simulation friendly if(!cnv->is_waiting()) { restart_speed = -1; target_halt = halthandle_t(); return false; } // check if there is a free position // this is much faster than waysearch if( !target_halt->find_free_position(road_wt,cnv->self,obj_t::road_vehicle )) { restart_speed = 0; target_halt = halthandle_t(); return false; } // now it make sense to search a route route_t target_rt; koord3d next3d = rt->at(index); if( !target_rt.find_route( welt, next3d, this, speed_to_kmh(cnv->get_min_top_speed()), start_direction, welt->get_settings().get_max_choose_route_steps() ) ) { // nothing empty or not route with less than 33 tiles target_halt = halthandle_t(); restart_speed = 0; return false; } // now reserve our choice (beware: might be longer than one tile!) for( uint32 length=0; lengthget_tile_length() && length+1reserve_position( welt->lookup( target_rt.at( target_rt.get_count()-length-1) ), cnv->self ); } rt->remove_koord_from( index ); rt->append( &target_rt ); } } return true; } bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8 second_check_count) { // check for traffic lights (only relevant for the first car in a convoi) if( leading ) { // no further check, when already entered a crossing (to allow leaving it) if( !second_check_count ) { if( const grund_t *gr_current = welt->lookup(get_pos()) ) { if( gr_current && gr_current->ist_uebergang() ) { return true; } } // always allow to leave traffic lights (avoid vehicles stuck on crossings directly after though) if( const grund_t *gr_current = welt->lookup(get_pos()) ) { if( const roadsign_t *rs = gr_current->find() ) { if( rs && rs->get_desc()->is_traffic_light() && !gr->ist_uebergang() ) { return true; } } } } assert(gr); const strasse_t *str = (strasse_t *)gr->get_weg(road_wt); if( !str || gr->obj_count() > 250 ) { // too many cars here or no street return false; } // first: check roadsigns const roadsign_t *rs = NULL; if( str->has_sign() ) { rs = gr->find(); route_t const& r = *cnv->get_route(); if( rs && (route_index + 1u < r.get_count()) ) { // since at the corner, our direction may be diagonal, we make it straight uint8 direction90 = ribi_type(get_pos(), pos_next); if( rs->get_desc()->is_traffic_light() && (rs->get_dir()&direction90) == 0 ) { // wait here restart_speed = 16; return false; } // check, if we reached a choose point else { // route position after road sign const koord pos_next_next = r.at(route_index + 1u).get_2d(); // since at the corner, our direction may be diagonal, we make it straight direction90 = ribi_type( pos_next, pos_next_next ); if( rs->is_free_route(direction90) && !target_halt.is_bound() ) { if( second_check_count ) { return false; } if( !choose_route( restart_speed, direction90, route_index ) ) { return false; } } } } } vehicle_base_t *obj = NULL; uint32 test_index = route_index + 1u; // way should be clear for overtaking: we checked previously if( !cnv->is_overtaking() ) { // calculate new direction route_t const& r = *cnv->get_route(); koord3d next = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next; ribi_t::ribi curr_direction = get_direction(); ribi_t::ribi curr_90direction = calc_direction(get_pos(), pos_next); ribi_t::ribi next_direction = calc_direction(get_pos(), next); ribi_t::ribi next_90direction = calc_direction(pos_next, next); obj = no_cars_blocking( gr, cnv, curr_direction, next_direction, next_90direction ); // do not block intersections const bool drives_on_left = welt->get_settings().is_drive_left(); bool int_block = ribi_t::is_threeway(str->get_ribi_unmasked()) && (((drives_on_left ? ribi_t::rotate90l(curr_90direction) : ribi_t::rotate90(curr_90direction)) & str->get_ribi_unmasked()) || curr_90direction != next_90direction || (rs && rs->get_desc()->is_traffic_light())); // check exit from crossings and intersections, allow to proceed after 4 consecutive while( !obj && (str->is_crossing() || int_block) && test_index < r.get_count() && test_index < route_index + 4u ) { if( str->is_crossing() ) { crossing_t* cr = gr->find(2); if( !cr->request_crossing(this) ) { restart_speed = 0; return false; } } // test next position gr = welt->lookup(r.at(test_index)); if( !gr ) { // way (weg) not existent (likely destroyed) if( !second_check_count ) { cnv->suche_neue_route(); } return false; } str = (strasse_t *)gr->get_weg(road_wt); if( !str || gr->obj_count() > 250 ) { // too many cars here or no street if( !second_check_count && !str) { cnv->suche_neue_route(); } return false; } // check cars curr_direction = next_direction; curr_90direction = next_90direction; if( test_index + 1u < r.get_count() ) { next = r.at(test_index + 1u); next_direction = calc_direction(r.at(test_index - 1u), next); next_90direction = calc_direction(r.at(test_index), next); obj = no_cars_blocking( gr, cnv, curr_direction, next_direction, next_90direction ); } else { next = r.at(test_index); next_90direction = calc_direction(r.at(test_index - 1u), next); if( curr_direction == next_90direction || !gr->is_halt() ) { // check cars but allow to enter intersection if we are turning even when a car is blocking the halt on the last tile of our route // preserves old bus terminal behaviour obj = no_cars_blocking( gr, cnv, curr_direction, next_90direction, ribi_t::none ); } } // check roadsigns if( str->has_sign() ) { rs = gr->find(); if( rs ) { // check, if we reached a choose point if( rs->is_free_route(curr_90direction) && !target_halt.is_bound() ) { if( second_check_count ) { return false; } if( !choose_route( restart_speed, curr_90direction, test_index ) ) { return false; } } } } else { rs = NULL; } // check for blocking intersection int_block = ribi_t::is_threeway(str->get_ribi_unmasked()) && (((drives_on_left ? ribi_t::rotate90l(curr_90direction) : ribi_t::rotate90(curr_90direction)) & str->get_ribi_unmasked()) || curr_90direction != next_90direction || (rs && rs->get_desc()->is_traffic_light())); test_index++; } if( obj && test_index > route_index + 1u && !str->is_crossing() && !int_block ) { // found a car blocking us after checking at least 1 intersection or crossing // and the car is in a place we could stop. So if it can move, assume it will, so we will too. // but check only upto 8 cars ahead to prevent infinite recursion on roundabouts. if( second_check_count >= 8 ) { return false; } if( road_vehicle_t const* const car = obj_cast(obj) ) { const convoi_t* const ocnv = car->get_convoi(); sint32 dummy; if( ocnv->front()->get_route_index() < ocnv->get_route()->get_count() && ocnv->front()->can_enter_tile( dummy, second_check_count + 1 ) ) { return true; } } } } // stuck message ... if( obj && !second_check_count ) { if( obj->is_stuck() ) { // end of traffic jam, but no stuck message, because previous vehicle is stuck too restart_speed = 0; cnv->set_tiles_overtaking(0); cnv->reset_waiting(); } else { if( test_index == route_index + 1u ) { // no intersections or crossings, we might be able to overtake this one ... overtaker_t *over = obj->get_overtaker(); if( over && !over->is_overtaken() ) { if( over->is_overtaking() ) { // otherwise we would stop every time being overtaken return true; } // not overtaking/being overtake: we need to make a more thought test! if( road_vehicle_t const* const car = obj_cast(obj) ) { convoi_t* const ocnv = car->get_convoi(); if( cnv->can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehicle(0)->get_steps()) ) { return true; } } else if( private_car_t* const caut = obj_cast(obj) ) { if( cnv->can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE) ) { return true; } } } } // we have to wait ... restart_speed = (cnv->get_akt_speed()*3)/4; cnv->set_tiles_overtaking(0); } } return obj==NULL; } return true; } overtaker_t* road_vehicle_t::get_overtaker() { return cnv; } void road_vehicle_t::enter_tile(grund_t* gr) { if (leading) { cnv->update_tiles_overtaking(); } calc_disp_lane(cnv && cnv->is_overtaking()); vehicle_t::enter_tile(gr); const int cargo = get_total_cargo(); weg_t *str = gr->get_weg(road_wt); if (str) { str->book(cargo, WAY_STAT_GOODS); if (leading) { str->book(1, WAY_STAT_CONVOIS); } } } schedule_t * road_vehicle_t::generate_new_schedule() const { return new truck_schedule_t(); } void road_vehicle_t::set_convoi(convoi_t *c) { DBG_MESSAGE("road_vehicle_t::set_convoi()","%p",c); if(c!=NULL) { bool target=(bool)cnv; // only during loadtype: cnv==1 indicates, that the convoi did reserve a stop vehicle_t::set_convoi(c); if(target && leading && c->get_route()->empty()) { // reinitialize the target halt const route_t *rt = cnv->get_route(); target_halt = haltestelle_t::get_halt( rt->back(), get_owner() ); if( target_halt.is_bound() ) { for( uint32 i=0; iget_tile_length() && i+1get_count(); i++ ) { target_halt->reserve_position( welt->lookup( rt->at(rt->get_count()-i-1) ), cnv->self ); } } } } else { if( cnv && leading && target_halt.is_bound() ) { // now reserve our choice (beware: might be longer than one tile!) for( uint32 length=0; lengthget_tile_length() && length+1get_route()->get_count(); length++ ) { target_halt->unreserve_position( welt->lookup( cnv->get_route()->at( cnv->get_route()->get_count()-length-1) ), cnv->self ); } target_halt = halthandle_t(); } cnv = NULL; } } simutrans-124.3/src/simutrans/vehicle/road_vehicle.h000066400000000000000000000035031474050137200226040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_ROAD_VEHICLE_H #define VEHICLE_ROAD_VEHICLE_H #include "vehicle.h" /** * A class for road vehicles. Manages the look of the vehicles * and the navigability of tiles. * @see vehicle_t */ class road_vehicle_t : public vehicle_t { private: // called internally only from can_enter_tile() // returns true on success bool choose_route(sint32 &restart_speed, ribi_t::ribi start_direction, uint16 index); protected: bool check_next_tile(const grund_t *bd) const OVERRIDE; public: void enter_tile(grund_t*) OVERRIDE; void rotate90() OVERRIDE; void calc_disp_lane(bool is_overtaking); waytype_t get_waytype() const OVERRIDE { return road_wt; } road_vehicle_t(loadsave_t *file, bool first, bool last); road_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv); // start and schedule void set_convoi(convoi_t *c) OVERRIDE; // how expensive to go here (for way search) int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const OVERRIDE; uint32 get_cost_upslope() const OVERRIDE { return 15; } bool calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) OVERRIDE; bool can_enter_tile(const grund_t *gr_next, sint32 &restart_speed, uint8 second_check_count) OVERRIDE; // returns true for the way search to an unknown target. bool is_target(const grund_t *,const grund_t *) const OVERRIDE; // since we must consider overtaking, we use this for offset calculation void get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const OVERRIDE; obj_t::typ get_typ() const OVERRIDE { return road_vehicle; } schedule_t * generate_new_schedule() const OVERRIDE; overtaker_t* get_overtaker() OVERRIDE; }; #endif simutrans-124.3/src/simutrans/vehicle/simroadtraffic.cc000066400000000000000000000754121474050137200233230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../display/simgraph.h" #include "../simmesg.h" #include "../world/simworld.h" #include "../utils/simrandom.h" #include "../display/simimg.h" #include "../simunits.h" #include "../simtypes.h" #include "../simconvoi.h" #include "simroadtraffic.h" #include "vehicle.h" #ifdef DESTINATION_CITYCARS // for final citycar destinations #include "simpeople.h" #endif #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../obj/crossing.h" #include "../obj/roadsign.h" #include "../ground/grund.h" #include "../obj/way/weg.h" #include "../descriptor/citycar_desc.h" #include "../descriptor/roadsign_desc.h" #include "../utils/cbuffer.h" #include "road_vehicle.h" /**********************************************************************************************************************/ /* Road users (private cars and pedestrians) basis class from here on */ road_user_t::road_user_t() : vehicle_base_t() { set_owner( welt->get_public_player() ); time_to_life = 0; weg_next = 0; } /** * Ensures that this object is removed correctly from the list * of sync step-able things! */ road_user_t::~road_user_t() { mark_image_dirty( get_image(), 0 ); } road_user_t::road_user_t(grund_t* bd, uint16 random) : vehicle_base_t(bd ? bd->get_pos() : koord3d::invalid) { assert(bd); ribi_t::ribi road_ribi = bd->get_weg_ribi(road_wt); weg_next = random; // randomized offset uint8 offset = random & 3; direction = ribi_t::nesw[offset]; grund_t *to = NULL; for(uint8 r = 0; r < 4; r++) { ribi_t::ribi ribi = ribi_t::nesw[ (r + offset) &3]; if( (ribi & road_ribi)!=0 && bd->get_neighbour(to, road_wt, ribi)) { direction = ribi; break; } } switch(direction) { case ribi_t::north: dx = 2; dy = -1; break; case ribi_t::south: dx = -2; dy = 1; break; case ribi_t::east: dx = 2; dy = 1; break; case ribi_t::west: dx = -2; dy = -1; break; } set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS ); set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 ); if(to) { pos_next = to->get_pos(); } else { pos_next = bd->get_pos(); // we have nowhere to go time_to_life = 0; } set_owner( welt->get_public_player() ); } /** * Open a new observation window for the object. */ void road_user_t::show_info() { if(env_t::road_user_info) { obj_t::show_info(); } } void road_user_t::rdwr(loadsave_t *file) { xml_tag_t t( file, "verkehrsteilnehmer_t" ); sint8 hoff = file->is_saving() ? get_hoff() : 0; // correct old offsets ... REMOVE after savegame increase ... if(file->is_version_less(99, 18) && file->is_saving()) { dx = dxdy[ ribi_t::get_dir(direction)*2 ]; dy = dxdy[ ribi_t::get_dir(direction)*2+1 ]; sint8 i = steps/16; set_xoff( get_xoff() + i*dx ); set_yoff( get_yoff() + i*dy + hoff ); } vehicle_base_t::rdwr(file); if(file->is_version_less(86, 6)) { sint32 l; file->rdwr_long(l); file->rdwr_long(l); file->rdwr_long(weg_next); file->rdwr_long(l); dx = (sint8)l; file->rdwr_long(l); dy = (sint8)l; file->rdwr_enum(direction); file->rdwr_long(l); hoff = (sint8)l; } else { if(file->is_version_less(99, 5)) { sint32 dummy32; file->rdwr_long(dummy32); } file->rdwr_long(weg_next); if(file->is_version_less(99, 18)) { file->rdwr_byte(dx); file->rdwr_byte(dy); } else { file->rdwr_byte(steps); file->rdwr_byte(steps_next); } file->rdwr_enum(direction); dx = dxdy[ ribi_t::get_dir(direction)*2]; dy = dxdy[ ribi_t::get_dir(direction)*2+1]; if(file->is_version_less(99, 5) || file->is_version_atleast(99, 17)) { sint16 dummy16 = ((16*(sint16)hoff)/OBJECT_OFFSET_STEPS); file->rdwr_short(dummy16); hoff = (sint8)((OBJECT_OFFSET_STEPS*(sint16)dummy16)/16); } else { file->rdwr_byte(hoff); } } pos_next.rdwr(file); // convert steps to position if(file->is_version_less(99, 18)) { sint8 ddx=get_xoff(), ddy=get_yoff()-hoff; sint8 i=0; while( !is_about_to_hop(ddx+dx*i,ddy+dy*i ) && i<16 ) { i++; } set_xoff( ddx-(16-i)*dx ); set_yoff( ddy-(16-i)*dy ); if(file->is_loading()) { if(dx && dy) { steps = min( VEHICLE_STEPS_PER_TILE - 1, VEHICLE_STEPS_PER_TILE - 1 - (i*16) ); steps_next = VEHICLE_STEPS_PER_TILE - 1; } else { steps = min( VEHICLE_STEPS_PER_TILE/2 - 1, VEHICLE_STEPS_PER_TILE / 2 -(i*16) ); steps_next = VEHICLE_STEPS_PER_TILE/2 ; } } } // the lifetime in ms if(file->is_version_atleast(89, 5)) { file->rdwr_long(time_to_life); } // there might be crashes if world is destroyed after loading // without a sync-step being performed if(file->is_loading() && time_to_life<=0) { time_to_life = 1; } // avoid endless growth of the values // this causes lockups near 2**32 weg_next &= 65535; } void road_user_t::finish_rd() { calc_height(NULL); calc_image(); } /**********************************************************************************************************************/ /* private_car_t (city cars) from here on */ freelist_iter_tpl private_car_t::fl; static weighted_vector_tpl liste_timeline; stringhashtable_tpl private_car_t::table; bool private_car_t::register_desc(const citycar_desc_t *desc) { if(const citycar_desc_t *old = table.remove(desc->get_name()) ) { delete old; } table.put(desc->get_name(), desc); return true; } bool private_car_t::successfully_loaded() { if(table.empty()) { DBG_MESSAGE("private_car_t", "No citycars found - feature disabled"); } return true; } static bool compare_stadtauto_desc(const citycar_desc_t* a, const citycar_desc_t* b) { int diff = a->get_intro_year_month() - b->get_intro_year_month(); if (diff == 0) { diff = a->get_topspeed() - b->get_topspeed(); } if (diff == 0) { /* same Level - we introduce an artificial, but unique resort * on the induced name. */ diff = strcmp(a->get_name(), b->get_name()); } return diff < 0; } void private_car_t::build_timeline_list(karte_t *welt) { // this list will contain all citycars liste_timeline.clear(); vector_tpl temp_liste(0); if( !table.empty() ) { const int month_now = welt->get_current_month(); //DBG_DEBUG("private_car_t::built_timeline_liste()","year=%i, month=%i", month_now/12, month_now%12+1); // check for every citycar, if still ok ... for(auto const& i : table) { citycar_desc_t const* const info = i.value; const int intro_month = info->get_intro_year_month(); const int retire_month = info->get_retire_year_month(); if (!welt->use_timeline() || (intro_month <= month_now && month_now < retire_month)) { temp_liste.insert_ordered( info, compare_stadtauto_desc ); } } } liste_timeline.resize( temp_liste.get_count() ); for(citycar_desc_t const* const i : temp_liste) { liste_timeline.append(i, i->get_distribution_weight()); } } bool private_car_t::list_empty() { return liste_timeline.empty(); } private_car_t::~private_car_t() { // first: release crossing grund_t *gr = welt->lookup(get_pos()); if(gr && gr->ist_uebergang()) { gr->find(2)->release_crossing(this); } welt->buche( -1, karte_t::WORLD_CITYCARS ); } private_car_t::private_car_t(loadsave_t *file) : road_user_t() { rdwr(file); ms_traffic_jam = 0; calc_disp_lane(); welt->buche( +1, karte_t::WORLD_CITYCARS ); } private_car_t::private_car_t(grund_t* gr, koord const target, const char* name) : road_user_t(gr, simrand(65535)) { desc = name ? table.get(name) : NULL; if (desc == NULL) { desc = liste_timeline.empty() ? 0 : pick_any_weighted(liste_timeline); } pos_next_next = koord3d::invalid; time_to_life = welt->get_settings().get_stadtauto_duration() << 20; // ignore welt->ticks_per_world_month_shift; current_speed = 48; ms_traffic_jam = 0; #ifdef DESTINATION_CITYCARS this->target = target; #else (void)target; #endif calc_image(); calc_disp_lane(); welt->buche( +1, karte_t::WORLD_CITYCARS ); } sync_result private_car_t::sync_step(uint32 delta_t) { time_to_life -= delta_t; if( time_to_life<=0 ) { return SYNC_DELETE; } if( current_speed==0 ) { // stuck in traffic jam uint32 old_ms_traffic_jam = ms_traffic_jam; ms_traffic_jam += delta_t; // check only every 1.024 s if stopped if( (ms_traffic_jam>>10) != (old_ms_traffic_jam>>10) ) { pos_next_next = koord3d::invalid; if( hop_check() ) { ms_traffic_jam = 0; current_speed = 48; } else { if( ms_traffic_jam > welt->ticks_per_world_month && old_ms_traffic_jam<=welt->ticks_per_world_month ) { // message after two month, reset waiting timer welt->get_message()->add_message( translator::translate("To heavy traffic\nresults in traffic jam.\n"), get_pos(), message_t::traffic_jams|message_t::EXPIRE_AFTER_ONE_MONTH_MSG, color_idx_to_rgb(COL_ORANGE) ); } } } weg_next = 0; } else { weg_next += current_speed*delta_t; const uint32 distance = do_drive( weg_next ); // hop_check could have set weg_next to zero, check for possible underflow here if (weg_next > distance) { weg_next -= distance; } else { weg_next = 0; } } return time_to_life>0 ? SYNC_OK : SYNC_DELETE; } void private_car_t::rdwr(loadsave_t *file) { xml_tag_t s( file, "stadtauto_t" ); road_user_t::rdwr(file); if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char s[256]; file->rdwr_str(s, lengthof(s)); desc = table.get(s); if( desc == 0 && !liste_timeline.empty() ) { dbg->warning("private_car_t::rdwr()", "Object '%s' not found in table, trying random stadtauto object type",s); desc = pick_any_weighted(liste_timeline); } if(desc == 0) { dbg->warning("private_car_t::rdwr()", "loading game with private cars, but no private car objects found in PAK files."); } else { set_image(desc->get_image_id(ribi_t::get_dir(get_direction()))); } } if(file->is_version_less(86, 2)) { time_to_life = simrand(1000000)+10000; } else if(file->is_version_less(89, 5)) { file->rdwr_long(time_to_life); time_to_life *= 10000; // converting from hops left to ms since start } if(file->is_version_less(86, 5)) { // default starting speed for old games if(file->is_loading()) { current_speed = 48; } } else { sint32 dummy32=current_speed; file->rdwr_long(dummy32); current_speed = dummy32; } if(file->is_version_less(99, 10)) { pos_next_next = koord3d::invalid; } else { pos_next_next.rdwr(file); } // overtaking status if(file->is_version_less(100, 1)) { set_tiles_overtaking( 0 ); } else { file->rdwr_byte(tiles_overtaking); set_tiles_overtaking( tiles_overtaking ); } } bool private_car_t::can_enter_tile(grund_t *gr) { if(gr->obj_count()>200) { // already too many things here return false; } // road still there? weg_t * str = gr->get_weg(road_wt); if(str==NULL) { time_to_life = 0; return false; } // calculate new direction // are we just turning around? const uint8 this_direction = get_direction(); bool frei = false; if( get_pos()==pos_next_next ) { // turning around => single check const uint8 next_direction = ribi_t::backward(this_direction); frei = (NULL == no_cars_blocking( gr, NULL, next_direction, next_direction, next_direction )); // do not block railroad crossing if(frei && str->is_crossing()) { const grund_t *gr = welt->lookup(get_pos()); frei = (NULL == no_cars_blocking( gr, NULL, next_direction, next_direction, next_direction )); } } else { // driving on: check for crossings etc. too const uint8 next_direction = this->calc_direction(get_pos(), pos_next_next); // do not block this crossing (if possible) if(ribi_t::is_threeway(str->get_ribi_unmasked())) { // but leaving from railroad crossing is more important grund_t *gr_here = welt->lookup(get_pos()); if( gr_here && gr_here->ist_uebergang() ) { return true; } grund_t *test = welt->lookup(pos_next_next); if( test ) { uint8 next_90direction = this->calc_direction(pos_next, pos_next_next); frei = (NULL == no_cars_blocking( gr, NULL, this_direction, next_direction, next_90direction )); if( frei ) { // check, if it can leave this crossings frei = (NULL == no_cars_blocking( test, NULL, next_direction, next_90direction, next_90direction )); } } // this fails with two crossings together; however, I see no easy way out here ... } else { // not a crossing => skip 90 degrees check! frei = true; // Overtaking vehicles shouldn't have anything blocking them if( !is_overtaking() ) { // not a crossing => skip 90 degrees check! vehicle_base_t *dt = no_cars_blocking( gr, NULL, this_direction, next_direction, next_direction ); if( dt ) { if(dt->is_stuck()) { // previous vehicle is stuck => end of traffic jam ... frei = false; } else { overtaker_t *over = dt->get_overtaker(); if(over) { if(!over->is_overtaking()) { // otherwise the overtaken car would stop for us ... if( road_vehicle_t const* const car = obj_cast(dt) ) { convoi_t* const ocnv = car->get_convoi(); if( ocnv==NULL || !can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehicle(0)->get_steps()) ) { frei = false; } } else if( private_car_t* const caut = obj_cast(dt) ) { if( !can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE) ) { frei = false; } } } } else { // movingobj ... block road totally frei = false; } } } } } // do not block railroad crossing if( frei && str->is_crossing() ) { // can we cross? crossing_t* cr = gr->find(2); if( cr && !cr->request_crossing(this)) { // approaching railway crossing: check if empty return false; } // no further check, when already entered a crossing (to allow leaving it) grund_t *gr_here = welt->lookup(get_pos()); if(gr_here && gr_here->ist_uebergang()) { return true; } // ok, now check for free exit koord dir = pos_next.get_2d()-get_pos().get_2d(); koord3d checkpos = pos_next+dir; uint8 number_reversed = 0; while( number_reversed<2 ) { const grund_t *test = welt->lookup(checkpos); if(!test) { // should not reach here! break; } const uint8 next_direction = ribi_type(dir); const uint8 nextnext_direction = ribi_type(dir); // test next field after way crossing if(no_cars_blocking( test, NULL, next_direction, nextnext_direction, nextnext_direction )) { return false; } // ok, left the crossing if(!test->find(2)) { // approaching railway crossing: check if empty crossing_t* cr = gr->find(2); return cr->request_crossing( this ); } else { // seems to be a dead-end. if( (test->get_weg_ribi(road_wt)&next_direction) == 0 ) { // will be going back pos_next_next=get_pos(); // check also opposite direction are free dir = -dir; number_reversed ++; } } checkpos += dir; } } } if(frei && current_speed==0) { ms_traffic_jam = 0; current_speed = 48; } if(!frei) { // not free => stop overtaking this->set_tiles_overtaking(0); } return frei; } void private_car_t::enter_tile(grund_t* gr) { #ifdef DESTINATION_CITYCARS if( target!=koord::invalid && koord_distance(pos_next.get_2d(),target)<10 ) { // delete it ... time_to_life = 0; // was generating pedestrians gere, but not possible with new sync system } #endif update_tiles_overtaking(); calc_disp_lane(); vehicle_base_t::enter_tile(gr); gr->get_weg(road_wt)->book(1, WAY_STAT_CONVOIS); } grund_t* private_car_t::hop_check() { grund_t *const from = welt->lookup(pos_next); if(from==NULL) { // nothing to go? => destroy ... time_to_life = 0; return NULL; } // find the allowed directions const weg_t *weg = from->get_weg(road_wt); if(weg==NULL) { // nothing to go? => destroy ... time_to_life = 0; return NULL; } // traffic light phase check (since this is on next tile, it will always be necessary!) const ribi_t::ribi direction90 = ribi_type(get_pos(), pos_next); if( weg->has_sign() ) { const roadsign_t* rs = from->find(); const roadsign_desc_t* rs_desc = rs->get_desc(); if( rs_desc->is_traffic_light() && (rs->get_dir()&direction90)==0 ) { // red traffic light, but we go on, if we are already on a traffic light bool go_on = false; if( const grund_t *gr_current = welt->lookup(get_pos()) ) { if( const roadsign_t *rs = gr_current->find() ) { go_on = rs && rs->get_desc()->is_traffic_light() && !from->ist_uebergang(); } } if( !go_on ) { direction = direction90; calc_image(); // wait here current_speed = 48; weg_next = 0; return NULL; } } } // next tile unknown => find next tile if(pos_next_next==koord3d::invalid) { // ok, nobody did delete the road in front of us // so we can check for valid directions ribi_t::ribi ribi = weg->get_ribi() & (~ribi_t::backward(direction90)); // cul de sac: return if(ribi==0) { pos_next_next = get_pos(); return can_enter_tile(from) ? from : NULL; } #ifdef DESTINATION_CITYCARS static weighted_vector_tpl posliste(4); posliste.clear(); const uint8 offset = ribi_t::is_single(ribi) ? 0 : simrand(4); for(uint8 r = 0; r < 4; r++) { if( get_pos().get_2d()==koord::nesw[r]+pos_next.get_2d() ) { continue; } #else const uint8 offset = ribi_t::is_single(ribi) ? 0 : simrand(4); for(uint8 i = 0; i < 4; i++) { const uint8 r = (i+offset)&3; #endif if( (ribi&ribi_t::nesw[r])!=0 ) { grund_t *to; if( from->get_neighbour(to, road_wt, ribi_t::nesw[r]) ) { // check, if this is just a single tile deep after a crossing weg_t *w = to->get_weg(road_wt); if( ribi_t::is_single(w->get_ribi()) && (w->get_ribi()&ribi_t::nesw[r])==0 && !ribi_t::is_single(ribi) ) { ribi &= ~ribi_t::nesw[r]; continue; } // check, if roadsign forbid next step ... if(w->has_sign()) { const roadsign_t* rs = to->find(); const roadsign_desc_t* rs_desc = rs->get_desc(); if(rs_desc->get_min_speed()>desc->get_topspeed() || (rs_desc->is_private_way() && (rs->get_player_mask()&2)==0) ) { // not allowed to go here ribi &= ~ribi_t::nesw[r]; continue; } } #ifdef DESTINATION_CITYCARS uint32 dist=koord_distance( to->get_pos().get_2d(), target ); posliste.append( to->get_pos(), dist*dist ); #else // ok, now check if we are allowed to go here (i.e. no cars blocking) pos_next_next = to->get_pos(); if(can_enter_tile(from)) { // ok, this direction is fine! ms_traffic_jam = 0; if(current_speed<48) { current_speed = 48; } return from; } else { pos_next_next = koord3d::invalid; } #endif } else { // not connected?!? => ribi likely wrong ribi &= ~ribi_t::nesw[r]; } } } #ifdef DESTINATION_CITYCARS if (!posliste.empty()) { pos_next_next = pick_any_weighted(posliste); } else { pos_next_next = get_pos(); } if(can_enter_tile(from)) { // ok, this direction is fine! ms_traffic_jam = 0; if(current_speed<48) { current_speed = 48; } return from; } #else // only stumps at single way crossing, all other blocked => turn around if(ribi==0) { pos_next_next = get_pos(); return can_enter_tile(from) ? from : NULL; } #endif } else { if(from && can_enter_tile(from)) { // ok, this direction is fine! ms_traffic_jam = 0; if(current_speed<48) { current_speed = 48; } return from; } } // no free tiles => assume traffic jam ... pos_next_next = koord3d::invalid; current_speed = 0; set_tiles_overtaking( 0 ); return NULL; } void private_car_t::hop(grund_t* to) { leave_tile(); if(pos_next_next==get_pos()) { direction = calc_set_direction( pos_next, pos_next_next ); steps_next = 0; // mark for starting at end of tile! } else { direction = calc_set_direction( get_pos(), pos_next_next ); } calc_image(); set_pos(pos_next); enter_tile(to); calc_current_speed(to); if(to->ist_uebergang()) { to->find(2)->add_to_crossing(this); } pos_next = pos_next_next; pos_next_next = koord3d::invalid; } void private_car_t::calc_image() { set_image(desc->get_image_id(ribi_t::get_dir(get_direction()))); } void private_car_t::calc_current_speed(grund_t* gr) { const weg_t * weg = gr->get_weg(road_wt); const sint32 max_speed = desc->get_topspeed(); const sint32 speed_limit = weg ? kmh_to_speed(weg->get_max_speed()) : max_speed; current_speed += max_speed>>2; if(current_speed > max_speed) { current_speed = max_speed; } if(current_speed > speed_limit) { current_speed = speed_limit; } } void private_car_t::info(cbuffer_t & buf) const { buf.printf(translator::translate("%s\nspeed %i\nmax_speed %i\ndx:%i dy:%i"), translator::translate(desc->get_name()), speed_to_kmh(current_speed), speed_to_kmh(desc->get_topspeed()), dx, dy); if (char const* const maker = desc->get_copyright()) { buf.printf(translator::translate("Constructed by %s"), maker); } } // to make smaller steps than the tile granularity, we have to use this trick void private_car_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const { vehicle_base_t::get_screen_offset( xoff, yoff, raster_width ); if( welt->get_settings().is_drive_left() ) { const int drive_left_dir = ribi_t::get_dir(get_direction()); xoff += tile_raster_scale_x( driveleft_base_offsets[drive_left_dir][0], raster_width ); yoff += tile_raster_scale_y( driveleft_base_offsets[drive_left_dir][1], raster_width ); } // eventually shift position to take care of overtaking if( is_overtaking() ) { xoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width); yoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width); } else if( is_overtaken() ) { xoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width)/5; yoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width)/5; } } void private_car_t::calc_disp_lane() { disp_lane = welt->get_settings().is_drive_left() ? 1 : 3; ribi_t::ribi dir = get_direction(); /* disp_lane is valid for vehicles moving to the right side of the screen, must be mirrored if SE <= heading < NW, and also if overtaking as there are five "display lanes" in simutrans which determine their drawing order. */ bool heading_left = (dir & ribi_t::south) || dir == ribi_t::west; if (heading_left ^ is_overtaking()) { disp_lane ^= 2; } } void private_car_t::rotate90() { road_user_t::rotate90(); calc_disp_lane(); } /** * conditions for a city car to overtake another overtaker. * The city car is not overtaking/being overtaken. */ bool private_car_t::can_overtake( overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) { if( !other_overtaker->can_be_overtaken() ) { return false; } if( other_speed == 0 ) { /* overtaking a loading convoi * => we can do a lazy check, since halts are always straight */ grund_t *gr = welt->lookup(get_pos()); if( gr==NULL ) { // should never happen, since there is a vehicle in front of us ... return false; } weg_t *str = gr->get_weg(road_wt); if( str==0 ) { // also this is not possible, since a car loads in front of is!?! return false; } const ribi_t::ribi direction = get_direction() & str->get_ribi(); koord3d check_pos = get_pos()+koord((ribi_t::ribi)(str->get_ribi()&direction)); for( int tiles=1+(steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT); tiles>=0; tiles-- ) { grund_t *gr = welt->lookup(check_pos); if( gr==NULL ) { return false; } weg_t *str = gr->get_weg(road_wt); if( str==0 ) { return false; } // not overtaking on railroad crossings ... if( str->is_crossing() ) { return false; } if( ribi_t::is_threeway(str->get_ribi()) ) { return false; } // Check for other vehicles on the next tile const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j)) ) { // check for other traffic on the road const overtaker_t *ov = v->get_overtaker(); if(ov) { if(this!=ov && other_overtaker!=ov) { return false; } } else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { return false; } } } check_pos += koord(direction); } set_tiles_overtaking( 3+(steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) ); return true; } sint32 diff_speed = (sint32)current_speed - other_speed; if( diff_speed < kmh_to_speed( 5 ) ) { // not fast enough to overtake return false; } // Number of tiles overtaking will take int n_tiles = 0; /* Distance it takes overtaking (unit: vehicle steps) = my_speed * time_overtaking * time_overtaking = tiles_to_overtake/diff_speed * tiles_to_overtake = convoi_length + pos_other_convoi * convoi_length for city cars? ==> a bit over half a tile (10) */ sint32 time_overtaking = 0; sint32 distance = current_speed*((10<<4)+steps_other)/diff_speed; // Conditions for overtaking: // Flat tiles, with no stops, no crossings, no signs, no change of road speed limit koord3d check_pos = get_pos(); koord pos_prev = check_pos.get_2d(); grund_t *gr = welt->lookup(check_pos); if( gr==NULL ) { return false; } weg_t *str = gr->get_weg(road_wt); if( str==0 ) { return false; } // we need 90 degree ribi ribi_t::ribi direction = get_direction(); direction = str->get_ribi() & direction; while( distance > 0 ) { // we allow stops and slopes, since empty stops and slopes cannot affect us // (citycars do not slow down on slopes!) // start of bridge is one level deeper if(gr->get_weg_yoff()>0) { check_pos.z ++; } // special signs if( str->has_sign() && str->get_ribi()==str->get_ribi_unmasked() ) { const roadsign_t *rs = gr->find(1); if(rs) { const roadsign_desc_t *rb = rs->get_desc(); if(rb->get_min_speed()>desc->get_topspeed() || rb->is_private_way() || rb->is_traffic_light() ) { // do not overtake when road is closed for cars, there is a traffic light or a too high min speed limit return false; } } } // not overtaking on railroad crossings ... if( str->is_crossing() ) { return false; } // street gets too slow (TODO: should be able to be correctly accounted for) if( current_speed > kmh_to_speed(str->get_max_speed()) ) { return false; } int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : diagonal_vehicle_steps_per_tile; distance -= d; time_overtaking += d; n_tiles++; /* Now we must check for next position: * crossings are ok, as long as we cannot exit there due to one way signs * much cheaper calculation: only go on in the direction of before (since no slopes allowed anyway ... ) */ grund_t *to = welt->lookup( check_pos + koord((ribi_t::ribi)(str->get_ribi()&direction)) ); if( ribi_t::is_threeway(str->get_ribi()) || to==NULL) { // check for entries/exits/bridges, if necessary ribi_t::ribi rib = str->get_ribi(); bool found_one = false; for( int r=0; r<4; r++ ) { if( (rib&ribi_t::nesw[r])==0 || check_pos.get_2d()+koord::nesw[r]==pos_prev) { continue; } if(gr->get_neighbour(to, road_wt, ribi_t::nesw[r])) { if(found_one) { // two directions to go: unexpected cars may occurs => abort return false; } found_one = true; } } } pos_prev = check_pos.get_2d(); // nowhere to go => nobody can come against us ... if(to==NULL || (str=to->get_weg(road_wt))==NULL) { return false; } // Check for other vehicles on the next tile const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j)) ) { // check for other traffic on the road const overtaker_t *ov = v->get_overtaker(); if(ov) { if(this!=ov && other_overtaker!=ov) { return false; } } else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { return false; } } } gr = to; check_pos = to->get_pos(); direction = ~ribi_type( check_pos, pos_prev ) & str->get_ribi(); } // Second phase: only facing traffic is forbidden // Since street speed can change, we do the calculation with time. // Each empty tile will subtract tile_dimension/max_street_speed. // If time is exhausted, we are guaranteed that no facing traffic will // invade the dangerous zone. time_overtaking = (time_overtaking << 16)/(sint32)current_speed; do { // we can allow crossings or traffic lights here, since they will stop also oncoming traffic if( ribi_t::is_straight(str->get_ribi()) ) { time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed()); } else { time_overtaking -= (diagonal_vehicle_steps_per_tile<<16) / kmh_to_speed(str->get_max_speed()); } // start of bridge is one level deeper if(gr->get_weg_yoff()>0) { check_pos.z ++; } // much cheaper calculation: only go on in the direction of before ... grund_t *to = welt->lookup( check_pos + koord((ribi_t::ribi)(str->get_ribi()&direction)) ); if( ribi_t::is_threeway(str->get_ribi()) || to==NULL ) { // check for crossings/bridges, if necessary bool found_one = false; for( int r=0; r<4; r++ ) { if(check_pos.get_2d()+koord::nesw[r]==pos_prev) { continue; } if(gr->get_neighbour(to, road_wt, ribi_t::nesw[r])) { if(found_one) { return false; } found_one = true; } } } koord pos_prev_prev = pos_prev; pos_prev = check_pos.get_2d(); // nowhere to go => nobody can come against us ... if(to==NULL || (str=to->get_weg(road_wt))==NULL) { break; } // Check for other vehicles in facing direction // now only I know direction on this tile ... ribi_t::ribi their_direction = ribi_t::backward(calc_direction( pos_prev_prev, to->get_pos())); const uint8 top = gr->obj_count(); for( uint8 j=1; j(gr->obj_bei(j)); if( v && v->get_direction() == their_direction ) { // check for car if(v->get_overtaker()) { return false; } } } gr = to; check_pos = to->get_pos(); direction = ~ribi_type( check_pos, pos_prev ) & str->get_ribi(); } while( time_overtaking > 0 ); set_tiles_overtaking( 1+n_tiles ); other_overtaker->set_tiles_overtaking( -1-(n_tiles/2) ); return true; } simutrans-124.3/src/simutrans/vehicle/simroadtraffic.h000066400000000000000000000075641474050137200231700ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_SIMROADTRAFFIC_H #define VEHICLE_SIMROADTRAFFIC_H #include "vehicle_base.h" #include "overtaker.h" #include "../tpl/stringhashtable_tpl.h" #include "../tpl/freelist_iter_tpl.h" class citycar_desc_t; class karte_t; /** * Base class for traffic participants with random movement * * Transport vehicles are defined in vehicle.h, because they greatly * differ from the vehicles defined herein for the individual traffic * (pedestrians, citycars, movingobj aka flock of sheep). */ class road_user_t : public vehicle_base_t { protected: /** * Distance count */ uint32 weg_next; /* ms until destruction */ sint32 time_to_life; protected: waytype_t get_waytype() const OVERRIDE { return road_wt; } road_user_t(); /** * Creates thing at position given by @p gr. * Does not add it to the tile! * * @param gr * @param random number to compute initial direction. */ road_user_t(grund_t* gr, uint16 random); public: virtual ~road_user_t(); const char *get_name() const OVERRIDE = 0; typ get_typ() const OVERRIDE = 0; /** * Open a new observation window for the object. */ void show_info() OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; // finalizes direction void finish_rd() OVERRIDE; // we allow to remove all cars etc. const char *get_removal_error(const player_t *) OVERRIDE { return NULL; } }; class private_car_t : public road_user_t, public overtaker_t { private: static stringhashtable_tpl table; const citycar_desc_t *desc; // time to life in blocks #ifdef DESTINATION_CITYCARS koord target; #endif koord3d pos_next_next; /** * Actual speed */ uint16 current_speed; uint32 ms_traffic_jam; grund_t* hop_check() OVERRIDE; void calc_disp_lane(); bool can_enter_tile(grund_t *gr); static freelist_iter_tpl fl; // if not declared static, it would consume 4 bytes due to empty class nonzero rules protected: void rdwr(loadsave_t *file) OVERRIDE; void calc_image() OVERRIDE; public: private_car_t(loadsave_t *file); /** * Creates citycar at position given by @p gr. * Does not add car to the tile! * If @p name == NULL then a random car is created. */ private_car_t(grund_t* gr, koord target, const char* name = NULL); virtual ~private_car_t(); sync_result sync_step(uint32 delta_t); void* operator new(size_t) { return fl.gimme_node(); } void operator delete(void* p) { return fl.putback_node(p); } static void sync_handler(uint32 delta_t) { fl.sync_step(delta_t); } void rotate90() OVERRIDE; const citycar_desc_t* get_desc() const { return desc; } void hop(grund_t *gr) OVERRIDE; void enter_tile(grund_t* gr) OVERRIDE; void calc_current_speed(grund_t*); uint16 get_current_speed() const {return current_speed;} const char *get_name() const OVERRIDE {return "Verkehrsteilnehmer";} typ get_typ() const OVERRIDE { return road_user; } /** * @param[out] buf a description string for the object * e.g. for the observation window/dialog * @see simwin */ void info(cbuffer_t & buf) const OVERRIDE; // true, if this vehicle did not moved for some time bool is_stuck() OVERRIDE { return current_speed==0;} /** this function builds the list of the allowed citycars * it should be called every month and in the beginning of a new game */ static void build_timeline_list(karte_t *welt); static bool list_empty(); static bool register_desc(const citycar_desc_t *desc); static bool successfully_loaded(); // since we must consider overtaking, we use this for offset calculation void get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const OVERRIDE; overtaker_t *get_overtaker() OVERRIDE { return this; } // Overtaking for city cars bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) OVERRIDE; }; #endif simutrans-124.3/src/simutrans/vehicle/simtestdriver.h000066400000000000000000000024241474050137200230650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_SIMTESTDRIVER_H #define VEHICLE_SIMTESTDRIVER_H #include "../simtypes.h" #include "../dataobj/ribi.h" class grund_t; class weg_t; /** * Interface to connect the vehicle with its route */ class test_driver_t { public: virtual ~test_driver_t() {} virtual bool check_next_tile(const grund_t* ) const = 0; /** * Determine the direction bits (ribi) for the applicable vehicle, * Depends of the ground type. */ virtual ribi_t::ribi get_ribi(const grund_t* ) const = 0; virtual waytype_t get_waytype() const = 0; /** * How expensive to go here (for way search). * @param gr tile to check * @param w way on the tile (can be NULL) * @param max_speed the maximum convoi speed as second parameter * @param from direction in which we enter the tile */ virtual int get_cost(const grund_t *gr, const weg_t *w, const sint32 max_speed, ribi_t::ribi from) const = 0; // returns true for the way search to an unknown target. // first is current ground, second is starting ground virtual bool is_target(const grund_t *,const grund_t *) const = 0; // return the cost of a single step upwards virtual uint32 get_cost_upslope() const { return 0; } }; #endif simutrans-124.3/src/simutrans/vehicle/vehicle.cc000066400000000000000000001042571474050137200217450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "vehicle.h" #include "../simintr.h" #include "../world/simworld.h" #include "../simware.h" #include "../simconvoi.h" #include "../simhalt.h" #include "../dataobj/translator.h" #include "../simfab.h" #include "../player/simplay.h" #include "../dataobj/schedule.h" #include "../gui/minimap.h" #include "../obj/crossing.h" #include "../obj/wolke.h" #include "../utils/cbuffer.h" #include "../dataobj/environment.h" #include "../dataobj/pakset_manager.h" #include "../builder/vehikelbauer.h" #include "../obj/zeiger.h" #include "../utils/simstring.h" #include void vehicle_t::rotate90() { vehicle_base_t::rotate90(); previous_direction = ribi_t::rotate90( previous_direction ); last_stop_pos.rotate90( welt->get_size().y-1 ); } void vehicle_t::rotate90_freight_destinations(const sint16 y_size) { // now rotate the freight for(ware_t & tmp : fracht) { tmp.rotate90(y_size ); } } void vehicle_t::set_convoi(convoi_t *c) { /* cnv can have three values: * NULL: not previously assigned * 1 (only during loading): convoi wants to reserve the whole route * other: previous convoi (in this case, currently always c==cnv) * * if c is NULL, then the vehicle is removed from the convoi * (the rail_vehicle_t::set_convoi etc. routines must then remove a * possibly pending reservation of stops/tracks) */ assert( c==NULL || cnv==NULL || cnv==(convoi_t *)1 || c==cnv); cnv = c; if(cnv) { // we need to re-establish the finish flag after loading if(leading) { route_t const& r = *cnv->get_route(); check_for_finish = r.empty() || route_index >= r.get_count() || get_pos() == r.at(route_index); } if( pos_next != koord3d::invalid ) { route_t const& r = *cnv->get_route(); if (!r.empty() && route_index < r.get_count() - 1) { grund_t const* const gr = welt->lookup(pos_next); if (!gr || !gr->get_weg(get_waytype())) { if (!(water_wt == get_waytype() && gr && gr->is_water())) { // ships on the open sea are valid pos_next = r.at(route_index + 1U); } } } } // just correct freight destinations for(ware_t & c : fracht) { c.finish_rd(welt); } } } /** * Unload freight to halt * @return sum of unloaded goods */ uint16 vehicle_t::unload_cargo(halthandle_t halt, bool unload_all, uint16 max_amount ) { uint16 sum_menge = 0, sum_delivered = 0, index = 0; if( !halt.is_bound() ) { return 0; } if( halt->is_enabled( get_cargo_type() ) ) { if( !fracht.empty() ) { for( slist_tpl::iterator i = fracht.begin(), end = fracht.end(); i != end && max_amount > 0; ) { ware_t& tmp = *i; halthandle_t end_halt = tmp.get_target_halt(); halthandle_t via_halt = tmp.get_via_halt(); // check if destination or transfer is still valid if( !end_halt.is_bound() || !via_halt.is_bound() ) { // target halt no longer there => delete and remove from fab in transit fabrik_t::update_transit( &tmp, false ); DBG_MESSAGE("vehicle_t::unload_freight()", "destination of %d %s is no longer reachable",tmp.amount,translator::translate(tmp.get_name())); total_freight -= tmp.amount; sum_weight -= tmp.amount * tmp.get_desc()->get_weight_per_unit(); i = fracht.erase( i ); } else if( end_halt == halt || via_halt == halt || unload_all ) { // here, only ordinary goods should be processed uint32 org_menge = tmp.amount; if (tmp.amount > max_amount) { tmp.amount = max_amount; } // since the max capacity of a vehicle is an uint16 uint16 menge = (uint16)halt->liefere_an(tmp); max_amount -= menge; sum_menge += menge; total_freight -= menge; sum_weight -= tmp.amount * tmp.get_desc()->get_weight_per_unit(); index = tmp.get_index(); if(end_halt==halt) { sum_delivered += menge; } // in case of partial unlaoding tmp.amount = org_menge-tmp.amount; if (tmp.amount == 0) { i = fracht.erase(i); } } else { ++i; } } } } if( sum_menge ) { // book transported goods get_owner()->book_transported( sum_menge, get_desc()->get_waytype(), index ); if( sum_delivered ) { // book delivered goods to destination get_owner()->book_delivered( sum_delivered, get_desc()->get_waytype(), index ); } // add delivered goods to statistics cnv->book( sum_menge, convoi_t::CONVOI_TRANSPORTED_GOODS ); // add delivered goods to halt's statistics halt->book( sum_menge, HALT_ARRIVED ); } return sum_menge; } /** * Load freight from halt * @return amount loaded */ uint16 vehicle_t::load_cargo(halthandle_t halt, const vector_tpl& destination_halts, uint16 max_amount ) { if( !halt.is_bound() || !halt->gibt_ab(desc->get_freight_type()) ) { return 0; } const uint16 total_freight_start = total_freight; const uint16 capacity_left = min(desc->get_capacity() - total_freight, max_amount); if (capacity_left > 0) { slist_tpl freight_add; halt->fetch_goods( freight_add, desc->get_freight_type(), capacity_left, destination_halts); if( freight_add.empty() ) { // now empty, but usually, we can get it here ... return 0; } for( slist_tpl::iterator iter_z = freight_add.begin(); iter_z != freight_add.end(); ) { ware_t &ware = *iter_z; total_freight += ware.amount; sum_weight += ware.amount * ware.get_desc()->get_weight_per_unit(); // could this be joined with existing freight? for(ware_t & tmp : fracht ) { // for pax: join according next stop // for all others we *must* use target coordinates if( ware.same_destination(tmp) ) { tmp.amount += ware.amount; ware.amount = 0; break; } } // if != 0 we could not join it to existing => load it if( ware.amount != 0 ) { ++iter_z; // we add list directly } else { iter_z = freight_add.erase(iter_z); } } if( !freight_add.empty() ) { fracht.append_list(freight_add); } } return total_freight - total_freight_start; } /** * Remove freight that no longer can reach it's destination * i.e. because of a changed schedule */ void vehicle_t::remove_stale_cargo() { DBG_DEBUG("vehicle_t::remove_stale_cargo()", "called"); // and now check every piece of ware on board, // if its target is somewhere on // the new schedule, if not -> remove slist_tpl kill_queue; total_freight = 0; if (!fracht.empty()) { for(ware_t & tmp : fracht) { bool found = false; if( tmp.get_via_halt().is_bound() ) { // the original halt exists, but does we still go there? for(schedule_entry_t const& i : cnv->get_schedule()->entries) { if( haltestelle_t::get_halt( i.pos, cnv->get_owner()) == tmp.get_via_halt() ) { found = true; break; } } } if( !found ) { // the target halt may have been joined or there is a closer one now, thus our original target is no longer valid const int offset = cnv->get_schedule()->get_current_stop(); const int max_count = cnv->get_schedule()->entries.get_count(); for( int i=0; iget_schedule()->entries[ (i+offset)%max_count ].pos, cnv->get_owner() ); if( halt.is_bound() ) { if( halt->is_enabled(tmp.get_index()) ) { // ok, lets change here, since goods are accepted here tmp.set_via_halt(halt); if (!tmp.get_target_halt().is_bound()) { // set target, to prevent that unload_freight drops cargo tmp.set_target_halt( halt ); } found = true; break; } } } } if( !found ) { kill_queue.insert(tmp); } else { // since we need to point at factory (0,0), we recheck this too koord k = tmp.get_target_pos(); fabrik_t *fab = fabrik_t::get_fab( k ); tmp.set_target_pos( fab ? fab->get_pos().get_2d() : k ); total_freight += tmp.amount; } } for(ware_t const& c : kill_queue) { fabrik_t::update_transit( &c, false ); fracht.remove(c); } } sum_weight = get_cargo_weight() + desc->get_weight(); } void vehicle_t::play_sound() const { if( desc->get_sound() >= 0 && !welt->is_fast_forward() ) { welt->play_sound_area_clipped(get_pos().get_2d(), desc->get_sound(), TRAFFIC_SOUND ); } } /** * Prepare vehicle for new ride. * Sets route_index, pos_next, steps_next. * If @p recalc is true this sets position and recalculates/resets movement parameters. */ void vehicle_t::initialise_journey(route_t::index_t start_route_index, bool recalc) { route_index = start_route_index+1; check_for_finish = false; use_calc_height = true; if(welt->is_within_limits(get_pos().get_2d())) { mark_image_dirty( get_image(), 0 ); } route_t const& r = *cnv->get_route(); if(!recalc) { // always set pos_next pos_next = r.at(route_index); assert(get_pos() == r.at(start_route_index)); } else { // set pos_next if (route_index < r.get_count()) { pos_next = r.at(route_index); } else { // already at end of route check_for_finish = true; } set_pos(r.at(start_route_index)); // recalc directions previous_direction = direction; direction = calc_set_direction( get_pos(), pos_next ); zoff_start = zoff_end = 0; steps = 0; set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS ); set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 ); calc_image(); } if ( ribi_t::is_single(direction) ) { steps_next = VEHICLE_STEPS_PER_TILE - 1; } else { steps_next = diagonal_vehicle_steps_per_tile - 1; } } vehicle_t::vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player) : vehicle_base_t(pos) { this->desc = desc; set_owner( player ); purchase_time = welt->get_current_month(); cnv = NULL; speed_limit = SPEED_UNLIMITED; route_index = 1; smoke = true; direction = ribi_t::none; current_friction = 4; total_freight = 0; sum_weight = desc->get_weight(); leading = last = false; check_for_finish = false; use_calc_height = true; has_driven = false; previous_direction = direction = ribi_t::none; target_halt = halthandle_t(); } vehicle_t::vehicle_t() : vehicle_base_t() { smoke = true; desc = NULL; cnv = NULL; route_index = 1; current_friction = 4; sum_weight = 10; total_freight = 0; leading = last = false; check_for_finish = false; use_calc_height = true; previous_direction = direction = ribi_t::none; } bool vehicle_t::calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route) { return route->calc_route(welt, start, ziel, this, max_speed, 0 ); } grund_t* vehicle_t::hop_check() { // the leading vehicle will do all the checks if(leading) { if(check_for_finish) { // so we are there yet? cnv->ziel_erreicht(); if(cnv->get_state()==convoi_t::INITIAL) { // to avoid crashes with airplanes use_calc_height = false; } return NULL; } // now check, if we can go here grund_t *bd = welt->lookup(pos_next); if(bd==NULL || !check_next_tile(bd) || cnv->get_route()->empty()) { // way (weg) not existent (likely destroyed) or no route ... cnv->suche_neue_route(); return NULL; } // check for one-way sign etc. const waytype_t wt = get_waytype(); if( air_wt != wt && route_index < cnv->get_route()->get_count()-1 ) { uint8 dir = get_ribi(bd); koord3d nextnext_pos = cnv->get_route()->at(route_index+1); if ( nextnext_pos == get_pos() ) { dbg->error("vehicle_t::hop_check", "route contains point (%s) twice for %s", nextnext_pos.get_str(), cnv->get_name()); } uint8 new_dir = ribi_type(nextnext_pos - pos_next); if((dir&new_dir)==0) { // new one way sign here? cnv->suche_neue_route(); return NULL; } // check for recently built bridges/tunnels or reverse branches (really slows down the game, so we do this only on slopes) if( bd->get_weg_hang() ) { grund_t *from; if( !bd->get_neighbour( from, get_waytype(), ribi_type( get_pos(), pos_next ) ) ) { // way likely destroyed or altered => reroute cnv->suche_neue_route(); return NULL; } } } sint32 restart_speed = -1; // can_enter_tile() wll compute restart_speed if( !can_enter_tile( bd, restart_speed, 0 ) ) { // stop convoi, when the way is not free cnv->warten_bis_weg_frei(restart_speed); // don't continue return NULL; } // we cache it here, hop() will use it to save calls to karte_t::lookup return bd; } else { // this is needed since in convoi_t::vorfahren the flag 'leading' is set to null if(check_for_finish) { return NULL; } } return welt->lookup(pos_next); } bool vehicle_t::can_enter_tile(sint32 &restart_speed, uint8 second_check_count) { grund_t *gr = welt->lookup( pos_next ); if( gr ) { return can_enter_tile( gr, restart_speed, second_check_count ); } else { if( !second_check_count ) { cnv->suche_neue_route(); } return false; } } void vehicle_t::leave_tile() { vehicle_base_t::leave_tile(); #ifndef DEBUG_ROUTES if(last && minimap_t::is_visible) { minimap_t::get_instance()->calc_map_pixel(get_pos().get_2d()); } #endif } /** this routine add a vehicle to a tile and will insert it in the correct sort order to prevent overlaps */ void vehicle_t::enter_tile(grund_t* gr) { vehicle_base_t::enter_tile(gr); if(leading && minimap_t::is_visible ) { minimap_t::get_instance()->calc_map_pixel( get_pos().get_2d() ); } } void vehicle_t::hop(grund_t* gr) { leave_tile(); koord3d pos_prev = get_pos(); set_pos( pos_next ); // next field if(route_indexget_route()->get_count()-1) { route_index ++; pos_next = cnv->get_route()->at(route_index); } else { route_index ++; check_for_finish = true; } previous_direction = direction; // check if arrived at waypoint, and update schedule to next destination // route search through the waypoint is already complete if( get_pos()==cnv->get_schedule_target() ) { if( route_index >= cnv->get_route()->get_count() ) { // we end up here after loading a game or when a waypoint is reached which crosses next itself cnv->set_schedule_target( koord3d::invalid ); } else { cnv->get_schedule()->advance(); const koord3d ziel = cnv->get_schedule()->get_current_entry().pos; cnv->set_schedule_target( cnv->is_waypoint(ziel) ? ziel : koord3d::invalid ); } } // this is a required hack for aircrafts! Aircrafts can turn on a single square, and this confuses the previous calculation! if(!check_for_finish && pos_prev==pos_next) { direction = calc_set_direction( get_pos(), pos_next); steps_next = 0; } else { if( pos_next!=get_pos() ) { direction = calc_set_direction( pos_prev, pos_next ); } else if( ( check_for_finish && welt->lookup(pos_next) && ribi_t::is_straight(welt->lookup(pos_next)->get_weg_ribi_unmasked(get_waytype())) ) || welt->lookup(pos_next)->is_halt()) { // allow diagonal stops at waypoints on diagonal tracks but avoid them on halts and at straight tracks... direction = calc_set_direction( pos_prev, pos_next ); } } // change image if direction changes if (previous_direction != direction) { calc_image(); } sint32 old_speed_limit = speed_limit; enter_tile(gr); const weg_t *weg = gr->get_weg(get_waytype()); if( weg ) { speed_limit = kmh_to_speed( weg->get_max_speed() ); if( weg->is_crossing() ) { gr->find(2)->add_to_crossing(this); } } else { speed_limit = SPEED_UNLIMITED; } if( leading ) { if( check_for_finish && (direction==ribi_t::north || direction==ribi_t::west) ) { steps_next = (steps_next/2)+1; } cnv->add_running_cost( weg ); cnv->must_recalc_data_front(); } // update friction and friction weight of convoy sint16 old_friction = current_friction; calc_friction(gr); if (old_friction != current_friction) { cnv->update_friction_weight( (current_friction-old_friction) * (sint64)sum_weight); } // if speed limit changed, then cnv must recalc if (speed_limit != old_speed_limit) { if (speed_limit < old_speed_limit) { if (speed_limit < cnv->get_speed_limit()) { // update cnv->set_speed_limit(speed_limit); } } else { if (old_speed_limit == cnv->get_speed_limit()) { // convoy's speed limit may be larger now cnv->must_recalc_speed_limit(); } } } } /** calculates the current friction coefficient based on the current track * flat, slope, curve ... */ void vehicle_t::calc_friction(const grund_t *gr) { // assume straight flat track current_friction = 1; // curve: higher friction if(previous_direction != direction) { current_friction = 8; } // or a hill? const slope_t::type hang = gr->get_weg_hang(); if( hang != slope_t::flat ) { const uint slope_height = is_one_high(hang) ? 1 : 2; if( ribi_type(hang) == direction ) { // hill up, since height offsets are negative: heavy decelerate current_friction += 15 * slope_height * slope_height; } else { // hill down: accelerate current_friction += -7 * slope_height * slope_height; } } } void vehicle_t::make_smoke() const { // does it smoke at all? if( smoke && desc->get_smoke() ) { // only produce smoke when heavily accelerating or steam engine if( cnv->get_akt_speed() < (sint32)((cnv->get_speed_limit() * 7u) >> 3) || desc->get_engine_type() == vehicle_desc_t::steam ) { grund_t* const gr = welt->lookup( get_pos() ); if( gr ) { wolke_t* const abgas = new wolke_t( get_pos(), get_xoff() + ((dx * (sint16)((uint16)steps * OBJECT_OFFSET_STEPS)) >> VEHICLE_STEPS_PER_TILE_SHIFT), get_yoff() + ((dy * (sint16)((uint16)steps * OBJECT_OFFSET_STEPS)) >> VEHICLE_STEPS_PER_TILE_SHIFT), get_hoff() - LEGACY_SMOKE_YOFFSET, DEFAULT_EXHAUSTSMOKE_TIME, DEFAULT_SMOKE_UPLIFT, desc->get_smoke() ); if( !gr->obj_add( abgas ) ) { abgas->set_flag( obj_t::not_on_map ); delete abgas; } } } } } /** * Payment is done per hop. It iterates all goods and calculates * the income for the last hop. This method must be called upon * every stop. * @return income total for last hop */ sint64 vehicle_t::calc_revenue(const koord3d& start, const koord3d& end) const { // may happen when waiting in station if (start == end || fracht.empty()) { return 0; } // cnv_kmh = lesser of min_top_speed, power limited top speed, and average way speed limits on trip, except aircraft which are not power limited and don't have speed limits sint32 cnv_kmh = cnv->get_speedbonus_kmh(); sint64 value = 0; // cache speedbonus price const goods_desc_t* last_freight = NULL; sint64 freight_revenue = 0; sint32 dist = 0; if( welt->get_settings().get_pay_for_total_distance_mode() == settings_t::TO_PREVIOUS ) { // pay distance traveled dist = koord_distance( start, end ); } for(ware_t const& ware : fracht) { if( ware.amount==0 ) { continue; } // which distance will be paid? switch(welt->get_settings().get_pay_for_total_distance_mode()) { case settings_t::TO_TRANSFER: { // pay distance traveled to next transfer stop // now only use the real gain in difference for the revenue (may as well be negative!) if (ware.get_via_halt().is_bound()) { const koord &zwpos = ware.get_via_halt()->get_basis_pos(); // cast of koord_distance to sint32 is necessary otherwise the r-value would be interpreted as unsigned, leading to overflows dist = (sint32)koord_distance( zwpos, start ) - (sint32)koord_distance( end, zwpos ); } else { dist = koord_distance( end, start ); } break; } case settings_t::TO_DESTINATION: { // pay only the distance, we get closer to our destination // now only use the real gain in difference for the revenue (may as well be negative!) const koord &zwpos = ware.get_target_pos(); // cast of koord_distance to sint32 is necessary otherwise the r-value would be interpreted as unsigned, leading to overflows dist = (sint32)koord_distance( zwpos, start ) - (sint32)koord_distance( end, zwpos ); break; } default: ; // no need to recompute } // calculate freight revenue incl. speed-bonus if (ware.get_desc() != last_freight) { freight_revenue = ware_t::calc_revenue(ware.get_desc(), get_desc()->get_waytype(), cnv_kmh); last_freight = ware.get_desc(); } const sint64 price = freight_revenue * (sint64)dist * (sint64)ware.amount; // sum up new price value += price; } // Rounded value, in cents return (value+1500ll)/3000ll; } const char *vehicle_t::get_cargo_mass() const { return get_cargo_type()->get_mass(); } /** * Calculate transported cargo total weight in KG */ uint32 vehicle_t::get_cargo_weight() const { uint32 weight = 0; for(ware_t const& c : fracht) { weight += c.amount * c.get_desc()->get_weight_per_unit(); } return weight; } void vehicle_t::get_cargo_info(cbuffer_t & buf) const { if (fracht.empty()) { buf.append(" "); buf.append(translator::translate("leer")); buf.append("\n"); } else { for(ware_t const& ware : fracht) { const char * name = "Error in Routing"; halthandle_t halt = ware.get_target_halt(); if(halt.is_bound()) { name = halt->get_name(); } buf.printf(" %u%s %s > %s\n", ware.amount, translator::translate(ware.get_mass()), translator::translate(ware.get_name()), name); } } } /** * Delete all vehicle load */ void vehicle_t::discard_cargo() { for(ware_t w : fracht ) { fabrik_t::update_transit( &w, false ); } fracht.clear(); sum_weight = desc->get_weight(); } void vehicle_t::calc_image() { image_id old_image=get_image(); if (fracht.empty()) { set_image(desc->get_image_id(ribi_t::get_dir(get_direction()),NULL)); } else { set_image(desc->get_image_id(ribi_t::get_dir(get_direction()), fracht.front().get_desc())); } if(old_image!=get_image()) { set_flag(obj_t::dirty); } } image_id vehicle_t::get_loaded_image() const { return desc->get_image_id(ribi_t::dir_south, fracht.empty() ? NULL : fracht.front().get_desc()); } // true, if this vehicle did not moved for some time bool vehicle_t::is_stuck() { return cnv==NULL || cnv->is_waiting(); } void vehicle_t::rdwr(loadsave_t *file) { // this is only called from objlist => we save nothing ... assert( file->is_saving() ); (void)file; } void vehicle_t::rdwr_from_convoi(loadsave_t *file) { xml_tag_t r( file, "vehikel_t" ); sint32 fracht_count = 0; if(file->is_saving()) { fracht_count = fracht.get_count(); // we try to have one freight count to guess the right freight // when no desc is given if(fracht_count==0 && desc->get_freight_type()!=goods_manager_t::none && desc->get_capacity()>0) { fracht_count = 1; } } obj_t::rdwr(file); // since obj_t does no longer save positions if( file->is_version_atleast(101, 0) ) { koord3d pos = get_pos(); pos.rdwr(file); set_pos(pos); } sint8 hoff = file->is_saving() ? get_hoff() : 0; if(file->is_version_less(86, 6)) { sint32 l; file->rdwr_long(purchase_time); file->rdwr_long(l); dx = (sint8)l; file->rdwr_long(l); dy = (sint8)l; file->rdwr_long(l); hoff = (sint8)(l*TILE_HEIGHT_STEP/16); file->rdwr_long(speed_limit); file->rdwr_enum(direction); file->rdwr_enum(previous_direction); file->rdwr_long(fracht_count); file->rdwr_long(l); route_index = (uint16)l; purchase_time = (purchase_time >> welt->ticks_per_world_month_shift) + welt->get_settings().get_starting_year(); DBG_MESSAGE("vehicle_t::rdwr_from_convoi()","bought at %i/%i.",(purchase_time%12)+1,purchase_time/12); } else { // changed several data types to save runtime memory file->rdwr_long(purchase_time); if(file->is_version_less(99, 18)) { file->rdwr_byte(dx); file->rdwr_byte(dy); } else { file->rdwr_byte(steps); file->rdwr_byte(steps_next); if(steps_next==old_diagonal_vehicle_steps_per_tile - 1 && file->is_loading()) { // reset diagonal length (convoi will be reset anyway, if game diagonal is different) steps_next = diagonal_vehicle_steps_per_tile - 1; } } sint16 dummy16 = ((16*(sint16)hoff)/TILE_HEIGHT_STEP); file->rdwr_short(dummy16); hoff = (sint8)((TILE_HEIGHT_STEP*(sint16)dummy16)/16); file->rdwr_long(speed_limit); file->rdwr_enum(direction); file->rdwr_enum(previous_direction); file->rdwr_long(fracht_count); file->rdwr_short(route_index); // restore dxdy information dx = dxdy[ ribi_t::get_dir(direction)*2]; dy = dxdy[ ribi_t::get_dir(direction)*2+1]; } // convert steps to position if(file->is_version_less(99, 18)) { sint8 ddx=get_xoff(), ddy=get_yoff()-hoff; sint8 i=1; dx = dxdy[ ribi_t::get_dir(direction)*2]; dy = dxdy[ ribi_t::get_dir(direction)*2+1]; while( !is_about_to_hop(ddx+dx*i,ddy+dy*i ) && i<16 ) { i++; } i--; set_xoff( ddx-(16-i)*dx ); set_yoff( ddy-(16-i)*dy ); if(file->is_loading()) { if(dx && dy) { steps = min( VEHICLE_STEPS_PER_TILE - 1, VEHICLE_STEPS_PER_TILE - 1-(i*16) ); steps_next = VEHICLE_STEPS_PER_TILE - 1; } else { // will be corrected anyway, if in a convoi steps = min( diagonal_vehicle_steps_per_tile - 1, diagonal_vehicle_steps_per_tile - 1-(uint8)(((uint16)i*(uint16)(diagonal_vehicle_steps_per_tile - 1))/8) ); steps_next = diagonal_vehicle_steps_per_tile - 1; } } } // information about the target halt if(file->is_version_atleast(88, 7)) { bool target_info; if(file->is_loading()) { file->rdwr_bool(target_info); cnv = (convoi_t *)target_info; // will be checked during convoi reassignment } else { target_info = target_halt.is_bound(); file->rdwr_bool(target_info); } } else { if(file->is_loading()) { cnv = NULL; // no reservation too } } if(file->is_version_less(112, 9)) { koord3d pos_prev(koord3d::invalid); pos_prev.rdwr(file); } if(file->is_version_less(99, 5)) { koord3d dummy; dummy.rdwr(file); // current pos (is already saved as ding => ignore) } pos_next.rdwr(file); if(file->is_saving()) { const char *s = desc->get_name(); file->rdwr_str(s); } else { char s[256]; file->rdwr_str(s, lengthof(s)); desc = vehicle_builder_t::get_info(s); if(desc==NULL) { desc = vehicle_builder_t::get_info(translator::compatibility_name(s)); } if(desc==NULL) { pakset_manager_t::add_missing_paks( s, MISSING_VEHICLE ); dbg->warning("vehicle_t::rdwr_from_convoi()","no vehicle pak for '%s' search for something similar", s); } } if(file->is_saving()) { if (fracht.empty() && fracht_count>0) { // create dummy freight for savegame compatibility ware_t ware( desc->get_freight_type() ); ware.amount = 0; ware.set_target_halt( halthandle_t() ); ware.set_via_halt( halthandle_t() ); ware.set_target_pos( get_pos().get_2d() ); ware.rdwr(file); } else { for(ware_t ware : fracht) { ware.rdwr(file); } } } else { for(int i=0; i0) && welt->is_within_limits(ware.get_target_pos()) && ware.get_desc() ) { // also add, of the desc is unknown to find matching replacement fracht.append(ware); #ifdef CACHE_TRANSIT if( file->is_version_less(112, 1) ) #endif // restore in-transit information fabrik_t::update_transit( &ware, true ); } else if( ware.amount>0 ) { if( ware.get_desc() ) { dbg->error( "vehicle_t::rdwr_from_convoi()", "%i of %s to %s ignored!", ware.amount, ware.get_name(), ware.get_target_pos().get_str() ); } else { dbg->error( "vehicle_t::rdwr_from_convoi()", "%i of unknown to %s ignored!", ware.amount, ware.get_target_pos().get_str() ); } } } } // skip first last info (the convoi will know this better than we!) if(file->is_version_less(88, 7)) { bool dummy = 0; file->rdwr_bool(dummy); file->rdwr_bool(dummy); } // koordinate of the last stop if(file->is_version_atleast(99, 15)) { // This used to be 2d, now it's 3d. if(file->is_version_less(112, 8)) { if(file->is_saving()) { koord last_stop_pos_2d = last_stop_pos.get_2d(); last_stop_pos_2d.rdwr(file); } else { // loading. Assume ground level stop (could be wrong, but how would we know?) koord last_stop_pos_2d = koord::invalid; last_stop_pos_2d.rdwr(file); const grund_t* gr = welt->lookup_kartenboden(last_stop_pos_2d); if (gr) { last_stop_pos = koord3d(last_stop_pos_2d, gr->get_hoehe()); } else { // no ground?!? last_stop_pos = koord3d::invalid; } } } else { // current version, 3d last_stop_pos.rdwr(file); } } if(file->is_loading()) { leading = last = false; // dummy, will be set by convoi afterwards if(desc) { calc_image(); // full weight after loading sum_weight = get_cargo_weight() + desc->get_weight(); } // recalc total freight total_freight = 0; for(ware_t const& c : fracht) { total_freight += c.amount; } } if( file->is_version_atleast(110, 0) ) { bool hd = has_driven; file->rdwr_bool( hd ); has_driven = hd; } else { if (file->is_loading()) { has_driven = false; } } } uint32 vehicle_t::calc_sale_value() const { // if already used, there is a general price reduction double value = (double)desc->get_price(); if( has_driven ) { value *= (1000 - welt->get_settings().get_used_vehicle_reduction()) / 1000.0; } // after 20 year, it has only half value return (uint32)( value * pow(0.997, (int)(welt->get_current_month() - get_purchase_time()))); } void vehicle_t::show_info() { if( cnv != NULL ) { cnv->open_info_window(); } else { dbg->warning("vehicle_t::show_info()","cnv is null, can't open convoi window!"); } } void vehicle_t::info(cbuffer_t & buf) const { if(cnv) { cnv->info(buf); } } const char *vehicle_t::get_removal_error(const player_t *) { return "Fahrzeuge koennen so nicht entfernt werden"; } vehicle_t::~vehicle_t() { // remove vehicle's marker from the minimap minimap_t::get_instance()->calc_map_pixel(get_pos().get_2d()); } #ifdef MULTI_THREAD void vehicle_t::display_overlay(int xpos, int ypos) const { if( cnv && leading ) { #else void vehicle_t::display_after(int xpos, int ypos, bool is_global) const { if( is_global && cnv && leading ) { #endif PIXVAL color = 0; // not used, but stop compiler warning about uninitialized char tooltip_text[1024]; tooltip_text[0] = 0; uint8 state = env_t::show_vehicle_states; if( state==1 || state==2 ) { // mouse over check bool mo_this_convoy = false; const koord3d mouse_pos = world()->get_zeiger()->get_pos(); if( mouse_pos == get_pos() ) { mo_this_convoy = true; } else if( grund_t* mo_gr = world()->lookup(mouse_pos) ) { if( vehicle_t* mo_veh = (vehicle_t *)mo_gr->get_convoi_vehicle() ) { mo_this_convoy = mo_veh->get_convoi() == get_convoi(); } } // only show when mouse over vehicle if( mo_this_convoy ) { state = 3; } else { state = 0; } } if( state != 3 ) { // nothing to show return; } // now find out what has happened switch(cnv->get_state()) { case convoi_t::WAITING_FOR_CLEARANCE_ONE_MONTH: case convoi_t::WAITING_FOR_CLEARANCE: case convoi_t::CAN_START: case convoi_t::CAN_START_ONE_MONTH: if( state>=3 ) { snprintf( tooltip_text, lengthof(tooltip_text), "%s (%s)", translator::translate("Waiting for clearance!"), cnv->get_schedule()->get_current_entry().pos.get_str() ); color = color_idx_to_rgb(COL_YELLOW); } break; case convoi_t::LOADING: if( state>=3 ) { if( cnv->is_unloading() ) { sprintf( tooltip_text, translator::translate( "Unloading (%i%%)!" ), cnv->get_loading_level() ); } else if( cnv->get_schedule()->get_current_entry().minimum_loading == 0 && cnv->get_schedule()->get_current_entry().waiting_time >0 ) { // is on a schedule sprintf(tooltip_text, translator::translate("Loading (%i%%) departure %s!"), cnv->get_loading_level(), tick_to_string(cnv->get_departure_ticks(),true)); } else if( cnv->get_loading_limit()==0 ){ sprintf( tooltip_text, translator::translate( "Loading (%i%%)!" ), cnv->get_loading_level(), cnv->get_loading_limit() ); } else { sprintf( tooltip_text, translator::translate( "Loading (%i->%i%%)!" ), cnv->get_loading_level(), cnv->get_loading_limit() ); } color = color_idx_to_rgb(COL_YELLOW); } break; case convoi_t::EDIT_SCHEDULE: // case convoi_t::ROUTING_1: if( state>=3 ) { tstrncpy( tooltip_text, translator::translate("Schedule changing!"), lengthof(tooltip_text) ); color = color_idx_to_rgb(COL_YELLOW); } break; case convoi_t::DRIVING: if( state>=3 ) { grund_t const* const gr = welt->lookup(cnv->get_route()->back()); if( gr && gr->get_depot() ) { tstrncpy( tooltip_text, translator::translate("go home"), lengthof(tooltip_text) ); color = color_idx_to_rgb(COL_GREEN); } else if( cnv->get_no_load() ) { tstrncpy( tooltip_text, translator::translate("no load"), lengthof(tooltip_text) ); color = color_idx_to_rgb(COL_GREEN); } } break; case convoi_t::LEAVING_DEPOT: if( state>=2 ) { tstrncpy( tooltip_text, translator::translate("Leaving depot!"), lengthof(tooltip_text) ); color = color_idx_to_rgb(COL_GREEN); } break; case convoi_t::WAITING_FOR_CLEARANCE_TWO_MONTHS: case convoi_t::CAN_START_TWO_MONTHS: snprintf( tooltip_text, lengthof(tooltip_text), "%s (%s)", translator::translate("clf_chk_stucked"), cnv->get_schedule()->get_current_entry().pos.get_str() ); color = color_idx_to_rgb(COL_ORANGE); break; case convoi_t::NO_ROUTE: tstrncpy( tooltip_text, translator::translate("clf_chk_noroute"), lengthof(tooltip_text) ); color = color_idx_to_rgb(COL_RED); break; } if( env_t::show_vehicle_states == 2 && !tooltip_text[ 0 ] ) { // show line name or simply convoi name color = color_idx_to_rgb( cnv->get_owner()->get_player_color1() + 7 ); if( cnv->get_line().is_bound() ) { snprintf( tooltip_text, lengthof( tooltip_text ), "%s - %s", cnv->get_line()->get_name(), cnv->get_name() ); } else { snprintf( tooltip_text, lengthof( tooltip_text ), "%s", cnv->get_name() ); } } // something to show? if( tooltip_text[0] ) { const int raster_width = get_current_tile_raster_width(); get_screen_offset( xpos, ypos, raster_width ); xpos += tile_raster_scale_x(get_xoff(), raster_width); ypos += tile_raster_scale_y(get_yoff(), raster_width)+14; if(ypos>LINESPACE+32 && ypos+LINESPACE fracht; // list of goods being transported const vehicle_desc_t *desc; convoi_t *cnv; // != NULL if the vehicle is part of a Convoi bool leading:1; // true, if vehicle is first vehicle of a convoi bool last:1; // true, if vehicle is last vehicle of a convoi bool smoke:1; bool check_for_finish:1; // true, if on the last tile bool has_driven:1; bool check_next_tile(const grund_t* ) const OVERRIDE {return false;} public: void calc_image() OVERRIDE; // the coordinates, where the vehicle was loaded the last time koord3d last_stop_pos; convoi_t *get_convoi() const { return cnv; } void rotate90() OVERRIDE; /** * Method checks whether next tile is free to move on. * Looks up next tile, and calls @ref can_enter_tile(const grund_t*, sint32&, uint8). */ bool can_enter_tile(sint32 &restart_speed, uint8 second_check_count); /** * Method checks whether next tile is free to move on. * * @param second_check_count * @param[out] gr_next next tile, must not be NULL * @param[out] restart_speed */ virtual bool can_enter_tile(const grund_t *gr_next, sint32 &restart_speed, uint8 second_check_count) = 0; void enter_tile(grund_t*) OVERRIDE; void leave_tile() OVERRIDE; waytype_t get_waytype() const OVERRIDE = 0; /** * Determine the direction bits for this kind of vehicle. */ ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi(get_waytype()); } sint32 get_purchase_time() const {return purchase_time;} void set_smoke_enabled(bool yesno ) { smoke = yesno;} virtual bool calc_route(koord3d start, koord3d ziel, sint32 max_speed, route_t* route); route_t::index_t get_route_index() const { return route_index; } /** * Get the base image. */ image_id get_base_image() const { return desc->get_base_image(); } /** * @return image with base direction and freight image taken from loaded cargo */ image_id get_loaded_image() const; /** * @return vehicle description object */ const vehicle_desc_t *get_desc() const {return desc; } /** * @return die running_cost in Cr/100Km */ int get_operating_cost() const { return desc->get_running_cost(); } /** * Play sound, when the vehicle is visible on screen */ void play_sound() const; /** * Prepare vehicle for new ride. * Sets route_index, pos_next, steps_next. * If @p recalc is true this sets position and recalculates/resets movement parameters. */ void initialise_journey( route_t::index_t start_route_index, bool recalc ); vehicle_t(); vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player); ~vehicle_t(); void make_smoke() const; void show_info() OVERRIDE; void info(cbuffer_t & buf) const OVERRIDE; /** * return friction constant: changes in hill and curves; may even negative downhill * */ inline sint16 get_frictionfactor() const { return current_friction; } /** * Return total weight including freight (in kg!) */ inline uint32 get_total_weight() const { return sum_weight; } // returns speedlimit of ways (and if convoi enters station etc) // the convoi takes care of the max_speed of the vehicle sint32 get_speed_limit() const { return speed_limit; } const slist_tpl & get_cargo() const { return fracht;} // list of goods being transported /** * Rotate freight target coordinates, has to be called after rotating factories. */ void rotate90_freight_destinations(const sint16 y_size); /** * Calculate the total quantity of goods moved */ uint16 get_total_cargo() const { return total_freight; } /** * Calculate transported cargo total weight in KG */ uint32 get_cargo_weight() const; /** * get the type of cargo this vehicle can transport */ const goods_desc_t* get_cargo_type() const { return desc->get_freight_type(); } /** * Get the maximum capacity */ uint16 get_cargo_max() const {return desc->get_capacity(); } const char * get_cargo_mass() const; /** * create an info text for the freight * e.g. to display in a info window */ void get_cargo_info(cbuffer_t & buf) const; /** * Delete all vehicle load */ void discard_cargo(); /** * Payment is done per hop. It iterates all goods and calculates * the income for the last hop. This method must be called upon * every stop. * @return income total for last hop */ sint64 calc_revenue(const koord3d& start, const koord3d& end) const; // sets or query begin and end of convois void set_leading(bool janein) {leading = janein;} bool is_leading() {return leading;} void set_last(bool janein) {last = janein;} bool is_last() {return last;} // marks the vehicle as really used void set_driven() { has_driven = true; } virtual void set_convoi(convoi_t *c); /** * Unload freight to halt * @return sum of unloaded goods */ uint16 unload_cargo(halthandle_t halt, bool all, uint16 max_amount ); /** * Load freight from halt * @return amount loaded */ uint16 load_cargo(halthandle_t halt, const vector_tpl& destination_halts, uint16 max_amount ); /** * Remove freight that no longer can reach it's destination * i.e. because of a changed schedule */ void remove_stale_cargo(); /** * Generate a matching schedule for the vehicle type */ virtual schedule_t *generate_new_schedule() const = 0; /// @copydoc obj_t::get_removal_error const char *get_removal_error(const player_t *player) OVERRIDE; void rdwr(loadsave_t *file) OVERRIDE; virtual void rdwr_from_convoi(loadsave_t *file); uint32 calc_sale_value() const; // true, if this vehicle did not moved for some time bool is_stuck() OVERRIDE; // this routine will display a tooltip for lost, on depot order, and stuck vehicles #ifdef MULTI_THREAD void display_overlay(int xpos, int ypos) const OVERRIDE; #else void display_after(int xpos, int ypos, bool dirty) const OVERRIDE; #endif }; template<> inline vehicle_t* obj_cast(obj_t* const d) { return dynamic_cast(d); } #endif simutrans-124.3/src/simutrans/vehicle/vehicle_base.cc000066400000000000000000000411441474050137200227320ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "vehicle_base.h" #include "road_vehicle.h" #include "simroadtraffic.h" #include "vehicle.h" #include "../dataobj/environment.h" #include "../simunits.h" #include "../world/simworld.h" #include "../obj/crossing.h" #include "../simconvoi.h" /* get dx and dy from dir (just to remind you) * any vehicle (including city cars and pedestrians) * will go this distance per sync step. * (however, the real dirs are only calculated during display, these are the old ones) */ sint8 vehicle_base_t::dxdy[ 8*2 ] = { -2, 1, // s -2, -1, // w -4, 0, // sw 0, 2, // se 2, -1, // n 2, 1, // e 4, 0, // ne 0, -2 // nw }; // Constants uint8 vehicle_base_t::old_diagonal_vehicle_steps_per_tile = 128; uint8 vehicle_base_t::diagonal_vehicle_steps_per_tile = 181; uint16 vehicle_base_t::diagonal_multiplier = 724; // set only once, before loading! void vehicle_base_t::set_diagonal_multiplier( uint32 multiplier, uint32 old_diagonal_multiplier ) { diagonal_multiplier = (uint16)multiplier; diagonal_vehicle_steps_per_tile = (uint8)(130560u/diagonal_multiplier) + 1; old_diagonal_vehicle_steps_per_tile = (uint8)(130560u/max(old_diagonal_multiplier, 1u)) + 1; } // if true, convoi, must restart! bool vehicle_base_t::need_realignment() const { return old_diagonal_vehicle_steps_per_tile!=diagonal_vehicle_steps_per_tile && ribi_t::is_bend(direction); } // [0]=xoff [1]=yoff sint8 vehicle_base_t::driveleft_base_offsets[8][2] = { { 12, 6 }, { -12, 6 }, { 0, 6 }, { 12, 0 }, { -12, -6 }, { 12, -6 }, { 0, -6 }, { -12, 0 } }; // [0]=xoff [1]=yoff sint8 vehicle_base_t::overtaking_base_offsets[8][2]; // recalc offsets for overtaking void vehicle_base_t::set_overtaking_offsets( bool driving_on_the_left ) { const sint8 sign = driving_on_the_left ? -1 : 1; // a tile has the internal size of const sint8 XOFF = 12; const sint8 YOFF = 6; overtaking_base_offsets[0][0] = sign * XOFF; overtaking_base_offsets[1][0] = -sign * XOFF; overtaking_base_offsets[2][0] = 0; overtaking_base_offsets[3][0] = sign * XOFF; overtaking_base_offsets[4][0] = -sign * XOFF; overtaking_base_offsets[5][0] = sign * XOFF; overtaking_base_offsets[6][0] = 0; overtaking_base_offsets[7][0] = sign * (-XOFF-YOFF); overtaking_base_offsets[0][1] = sign * YOFF; overtaking_base_offsets[1][1] = sign * YOFF; overtaking_base_offsets[2][1] = sign * YOFF; overtaking_base_offsets[3][1] = 0; overtaking_base_offsets[4][1] = -sign * YOFF; overtaking_base_offsets[5][1] = -sign * YOFF; overtaking_base_offsets[6][1] = -sign * YOFF; overtaking_base_offsets[7][1] = 0; } /** * Checks if this vehicle must change the square upon next move * THIS IS ONLY THERE FOR LOADING OLD SAVES! */ bool vehicle_base_t::is_about_to_hop( const sint8 neu_xoff, const sint8 neu_yoff ) const { const sint8 y_off_2 = 2*neu_yoff; const sint8 c_plus = y_off_2 + neu_xoff; const sint8 c_minus = y_off_2 - neu_xoff; return ! (c_plus < OBJECT_OFFSET_STEPS*2 && c_minus < OBJECT_OFFSET_STEPS*2 && c_plus > -OBJECT_OFFSET_STEPS*2 && c_minus > -OBJECT_OFFSET_STEPS*2); } vehicle_base_t::vehicle_base_t(): obj_t() { image = IMG_EMPTY; set_flag( obj_t::is_vehicle ); steps = 0; steps_next = VEHICLE_STEPS_PER_TILE - 1; use_calc_height = true; dx = 0; dy = 0; zoff_start = zoff_end = 0; disp_lane = 2; } vehicle_base_t::vehicle_base_t(koord3d pos): obj_t(pos) { image = IMG_EMPTY; set_flag( obj_t::is_vehicle ); pos_next = pos; steps = 0; steps_next = VEHICLE_STEPS_PER_TILE - 1; use_calc_height = true; dx = 0; dy = 0; zoff_start = zoff_end = 0; disp_lane = 2; } void vehicle_base_t::rotate90() { obj_t::rotate90(); // directions are counterclockwise to ribis! direction = ribi_t::rotate90( direction ); pos_next.rotate90( welt->get_size().y-1 ); // new offsets sint8 new_dx = -dy*2; dy = dx/2; dx = new_dx; } void vehicle_base_t::leave_tile() { // first: release crossing grund_t *gr = welt->lookup(get_pos()); if( gr && gr->ist_uebergang() ) { crossing_t *cr = gr->find(2); grund_t *gr2 = welt->lookup(pos_next); if( gr2==NULL || gr2==gr || !gr2->ist_uebergang() || cr->get_logic()!=gr2->find(2)->get_logic() ) { cr->release_crossing(this); } } // then remove from ground (or search whole map, if failed) if(!get_flag(not_on_map) && (gr==NULL || !gr->obj_remove(this)) ) { // was not removed (not found?) dbg->error("vehicle_base_t::leave_tile()", "%s %p could not be removed from (%s)", get_name(), (void *)this, get_pos().get_str()); DBG_MESSAGE("vehicle_base_t::leave_tile()", "checking all plan squares"); // check, whether it is on another height ... const planquadrat_t *pl = welt->access( get_pos().get_2d() ); if( pl ) { gr = pl->get_boden_von_obj(this); if( gr ) { gr->obj_remove(this); dbg->warning("vehicle_base_t::leave_tile()", "Removed %s %p from (%s)", get_name(), (void *)this, get_pos().get_str()); } return; } koord k; bool ok = false; for(k.y=0; k.yget_size().y; k.y++) { for(k.x=0; k.xget_size().x; k.x++) { grund_t *gr = welt->access( k )->get_boden_von_obj(this); if(gr && gr->obj_remove(this)) { dbg->warning("vehicle_base_t::leave_tile()", "Removed %s %p from (%s)", get_name(), (void *)this, k.get_str()); ok = true; } } } if(!ok) { dbg->error("vehicle_base_t::leave_tile()", "%s %p was not found on any map square!", get_name(), (void *)this); } } } void vehicle_base_t::enter_tile(grund_t* gr) { if(!gr) { dbg->error("vehicle_base_t::enter_tile()","'%s' new position (%i,%i,%i)!",get_name(), get_pos().x, get_pos().y, get_pos().z ); gr = welt->lookup_kartenboden(get_pos().get_2d()); set_pos( gr->get_pos() ); } gr->obj_add(this); } /* THE routine for moving vehicles * it will drive on as log as it can * @return the distance actually traveled */ uint32 vehicle_base_t::do_drive(uint32 distance) { uint32 steps_to_do = distance >> YARDS_PER_VEHICLE_STEP_SHIFT; if( steps_to_do == 0 ) { // ok, we will not move in this steps return 0; } // ok, so moving ... if( !get_flag(obj_t::dirty) ) { mark_image_dirty( image, 0 ); set_flag( obj_t::dirty ); } grund_t *gr = NULL; // if hopped, then this is new position uint32 steps_target = steps_to_do + steps; uint32 distance_travelled; // Return value if( steps_target > steps_next ) { // We are going far enough to hop. // We'll be adding steps_next+1 for each hop, as if we // started at the beginning of this tile, so for an accurate // count of steps done we must subtract the location we started with. sint32 steps_done = -steps; // Hop as many times as possible. while( steps_target > steps_next && (gr = hop_check()) ) { // now do the update for hopping steps_target -= steps_next+1; steps_done += steps_next+1; koord pos_prev(get_pos().get_2d()); hop(gr); use_calc_height = true; // set offsets set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS ); set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 ); if(dx*dy==0) { if(dx==0) { if(dy>0) { set_xoff( pos_prev.x!=get_pos().x ? -OBJECT_OFFSET_STEPS : OBJECT_OFFSET_STEPS ); } else { set_xoff( pos_prev.x!=get_pos().x ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS ); } } else { if(dx>0) { set_yoff( pos_prev.y!=get_pos().y ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 ); } else { set_yoff( pos_prev.y!=get_pos().y ? -OBJECT_OFFSET_STEPS/2 : OBJECT_OFFSET_STEPS/2 ); } } } } if( steps_next == 0 ) { // only needed for aircrafts, which can turn on the same tile // the indicate the turn with this here steps_next = VEHICLE_STEPS_PER_TILE - 1; steps_target = VEHICLE_STEPS_PER_TILE - 1; steps_done -= VEHICLE_STEPS_PER_TILE - 1; } // Update internal status, how far we got within the tile. if( steps_target <= steps_next ) { steps = steps_target; } else { // could not go as far as we wanted (hop_check failed) => stop at end of tile steps = steps_next; } steps_done += steps; distance_travelled = steps_done << YARDS_PER_VEHICLE_STEP_SHIFT; } else { // Just travel to target, it's on same tile steps = steps_target; distance_travelled = distance & YARDS_VEHICLE_STEP_MASK; // round down to nearest step } if(use_calc_height) { calc_height(gr); } // remaining steps return distance_travelled; } // to make smaller steps than the tile granularity, we have to use this trick void vehicle_base_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const { // vehicles needs finer steps to appear smoother sint32 display_steps = (uint32)steps*(uint16)raster_width; if(dx && dy) { display_steps &= 0xFFFFFC00; } else { display_steps = (display_steps*diagonal_multiplier)>>10; } xoff += (display_steps*dx) >> 10; yoff += ((display_steps*dy) >> 10) + (get_hoff(raster_width))/(4*16); } // calcs new direction and applies it to the vehicles ribi_t::ribi vehicle_base_t::calc_set_direction(const koord3d& start, const koord3d& ende) { ribi_t::ribi direction = ribi_t::none; const sint8 di = ende.x - start.x; const sint8 dj = ende.y - start.y; if(dj < 0 && di == 0) { direction = ribi_t::north; dx = 2; dy = -1; steps_next = VEHICLE_STEPS_PER_TILE - 1; } else if(dj > 0 && di == 0) { direction = ribi_t::south; dx = -2; dy = 1; steps_next = VEHICLE_STEPS_PER_TILE - 1; } else if(di < 0 && dj == 0) { direction = ribi_t::west; dx = -2; dy = -1; steps_next = VEHICLE_STEPS_PER_TILE - 1; } else if(di >0 && dj == 0) { direction = ribi_t::east; dx = 2; dy = 1; steps_next = VEHICLE_STEPS_PER_TILE - 1; } else if(di > 0 && dj > 0) { direction = ribi_t::southeast; dx = 0; dy = 2; steps_next = diagonal_vehicle_steps_per_tile - 1; } else if(di < 0 && dj < 0) { direction = ribi_t::northwest; dx = 0; dy = -2; steps_next = diagonal_vehicle_steps_per_tile - 1; } else if(di > 0 && dj < 0) { direction = ribi_t::northeast; dx = 4; dy = 0; steps_next = diagonal_vehicle_steps_per_tile - 1; } else { direction = ribi_t::southwest; dx = -4; dy = 0; steps_next = diagonal_vehicle_steps_per_tile - 1; } // we could artificially make diagonals shorter: but this would break existing game behaviour return direction; } // this routine calculates the new height // beware of bridges, tunnels, slopes, ... void vehicle_base_t::calc_height(grund_t *gr) { use_calc_height = false; // assume, we are only needed after next hop zoff_start = zoff_end = 0; // assume flat way if(gr==NULL) { gr = welt->lookup(get_pos()); } if(gr==NULL) { // slope changed below a moving thing?!? return; } else if( gr->ist_tunnel() && gr->ist_karten_boden() && !is_flying() ) { use_calc_height = true; // to avoid errors if underground mode is switched if( grund_t::underground_mode == grund_t::ugm_none || (grund_t::underground_mode == grund_t::ugm_level && gr->get_hoehe() < grund_t::underground_level) ) { // need hiding? One of the few uses of XOR: not half driven XOR exiting => not hide! ribi_t::ribi hang_ribi = ribi_type( gr->get_grund_hang() ); if((steps<(steps_next/2)) ^ ((hang_ribi&direction)!=0) ) { set_image(IMG_EMPTY); } else { calc_image(); } } } else { // force a valid image above ground, with special handling of tunnel entraces if( get_image()==IMG_EMPTY ) { if( !gr->ist_tunnel() && gr->ist_karten_boden() ) { calc_image(); } } // will not work great with ways, but is very short! slope_t::type hang = gr->get_weg_hang(); if( hang ) { const uint slope_height = is_one_high(hang) ? 1 : 2; ribi_t::ribi hang_ribi = ribi_type(hang); if( ribi_t::doubles(hang_ribi) == ribi_t::doubles(direction)) { zoff_start = hang_ribi & direction ? 2*slope_height : 0; // 0 .. 4 zoff_end = hang_ribi & ribi_t::backward(direction) ? 2*slope_height : 0; // 0 .. 4 } else { // only for shadows and movingobjs ... zoff_start = hang_ribi & direction ? slope_height+1 : 0; // 0 .. 3 zoff_end = hang_ribi & ribi_t::backward(direction) ? slope_height+1 : 0; // 0 .. 3 } } else { zoff_start = (gr->get_weg_yoff() * 2) / TILE_HEIGHT_STEP; zoff_end = zoff_start; } } } sint16 vehicle_base_t::get_hoff(const sint16 raster_width) const { sint16 h_start = -(sint8)TILE_HEIGHT_STEP * (sint8)zoff_start; sint16 h_end = -(sint8)TILE_HEIGHT_STEP * (sint8)zoff_end; return ((h_start*steps + h_end*(256-steps))*raster_width) >> 9; } /* true, if one could pass through this field * also used for citycars, thus defined here */ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convoi_t *cnv, const uint8 current_direction, const uint8 next_direction, const uint8 next_90direction ) { // Search vehicle for( uint8 pos=1; pos<(uint8)gr->obj_count(); pos++ ) { if( vehicle_base_t* const v = obj_cast(gr->obj_bei(pos)) ) { if( v->get_typ()==obj_t::pedestrian ) { continue; } // check for car uint8 other_direction=255; bool other_moving = false; if( road_vehicle_t const* const at = obj_cast(v) ) { // ignore ourself if( cnv == at->get_convoi() ) { continue; } other_direction = at->get_direction(); other_moving = at->get_convoi()->get_akt_speed() > kmh_to_speed(1); } // check for city car else if( v->get_waytype() == road_wt ) { other_direction = v->get_direction(); if( private_car_t const* const sa = obj_cast(v) ){ other_moving = sa->get_current_speed() > 1; } } // ok, there is another car ... if( other_direction != 255 ) { if( next_direction == other_direction && !ribi_t::is_threeway(gr->get_weg_ribi(road_wt)) ) { // cars going in the same direction and no crossing => that mean blocking ... return v; } const ribi_t::ribi other_90direction = (gr->get_pos().get_2d() == v->get_pos_next().get_2d()) ? other_direction : calc_direction(gr->get_pos(), v->get_pos_next()); if( other_90direction == next_90direction ) { // Want to exit in same as other ~50% of the time return v; } const bool drives_on_left = welt->get_settings().is_drive_left(); const bool across = next_direction == (drives_on_left ? ribi_t::rotate45l(next_90direction) : ribi_t::rotate45(next_90direction)); // turning across the opposite directions lane const bool other_across = other_direction == (drives_on_left ? ribi_t::rotate45l(other_90direction) : ribi_t::rotate45(other_90direction)); // other is turning across the opposite directions lane if( other_direction == next_direction && !(other_across || across) ) { // entering same straight waypoint as other ~18% return v; } const bool straight = next_direction == next_90direction; // driving straight const ribi_t::ribi current_90direction = straight ? ribi_t::backward(next_90direction) : (~(next_direction|ribi_t::backward(next_90direction)))&0x0F; const bool other_straight = other_direction == other_90direction; // other is driving straight const bool other_exit_same_side = current_90direction == other_90direction; // other is exiting same side as we're entering const bool other_exit_opposite_side = ribi_t::backward(current_90direction) == other_90direction; // other is exiting side across from where we're entering if( across && ((ribi_t::is_perpendicular(current_90direction,other_direction) && other_moving) || (other_across && other_exit_opposite_side) || ((other_across || other_straight) && other_exit_same_side && other_moving) ) ) { // other turning across in front of us from orth entry dir'n ~4% return v; } const bool headon = ribi_t::backward(current_direction) == other_direction; // we're meeting the other headon const bool other_exit_across = (drives_on_left ? ribi_t::rotate90l(next_90direction) : ribi_t::rotate90(next_90direction)) == other_90direction; // other is exiting by turning across the opposite directions lane if( straight && (ribi_t::is_perpendicular(current_90direction,other_direction) || (other_across && other_moving && (other_exit_across || (other_exit_same_side && !headon))) ) ) { // other turning across in front of us, but allow if other is stopped - duplicating historic behaviour ~2% return v; } else if( other_direction == current_direction && current_90direction == ribi_t::none ) { // entering same diagonal waypoint as other ~1% return v; } // else other car is not blocking ~25% } } } // way is free return NULL; } simutrans-124.3/src/simutrans/vehicle/vehicle_base.h000066400000000000000000000115351474050137200225750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_VEHICLE_BASE_H #define VEHICLE_VEHICLE_BASE_H #include "../obj/simobj.h" class convoi_t; class grund_t; class overtaker_t; /** * Base class for all moving things (vehicles, pedestrians, movingobj) */ class vehicle_base_t : public obj_t { protected: // offsets for different directions static sint8 dxdy[16]; // to make the length on diagonals configurable // Number of vehicle steps along a diagonal... // remember to subtract one when stepping down to 0 static uint8 diagonal_vehicle_steps_per_tile; static uint8 old_diagonal_vehicle_steps_per_tile; static uint16 diagonal_multiplier; // [0]=xoff [1]=yoff static sint8 driveleft_base_offsets[8][2]; static sint8 overtaking_base_offsets[8][2]; /** * Actual travel direction in screen coordinates */ ribi_t::ribi direction; // true on slope (make calc_height much faster) uint8 use_calc_height:1; /** * Thing is moving on this lane. * Possible values: * (Back) * 0 - sidewalk (going on the right side to w/sw/s) * 1 - road (going on the right side to w/sw/s) * 2 - middle (everything with waytype != road) * 3 - road (going on the right side to se/e/../nw) * 4 - sidewalk (going on the right side to se/e/../nw) * (Front) */ uint8 disp_lane:3; sint8 dx, dy; // number of steps in this tile (255 per tile) uint8 steps, steps_next; /** * Next position on our path */ koord3d pos_next; /** * Offsets for uphill/downhill. * Have to be multiplied with -TILE_HEIGHT_STEP/2. * To obtain real z-offset, interpolate using steps, steps_next. */ uint8 zoff_start:4, zoff_end:4; // cached image image_id image; /** * Vehicle movement: check whether this vehicle can enter the next tile (pos_next). * @returns NULL if check fails, otherwise pointer to the next tile */ virtual grund_t* hop_check() = 0; /** * Vehicle movement: change tiles, calls leave_tile and enter_tile. * @param gr pointer to ground of new position (never NULL) */ virtual void hop(grund_t* gr) = 0; void calc_image() OVERRIDE = 0; // check for road vehicle, if next tile is free vehicle_base_t *no_cars_blocking( const grund_t *gr, const convoi_t *cnv, const uint8 current_direction, const uint8 next_direction, const uint8 next_90direction ); // only needed for old way of moving vehicles to determine position at loading time bool is_about_to_hop( const sint8 neu_xoff, const sint8 neu_yoff ) const; public: // only called during load time: set some offsets static void set_diagonal_multiplier( uint32 multiplier, uint32 old_multiplier ); static uint16 get_diagonal_multiplier() { return diagonal_multiplier; } static uint8 get_diagonal_vehicle_steps_per_tile() { return diagonal_vehicle_steps_per_tile; } static void set_overtaking_offsets( bool driving_on_the_left ); // if true, this convoi needs to restart for correct alignment bool need_realignment() const; uint32 do_drive(uint32 dist); // basis movement code inline void set_image( image_id b ) { image = b; } image_id get_image() const OVERRIDE {return image;} sint16 get_hoff(const sint16 raster_width=1) const; uint8 get_steps() const {return steps;} uint8 get_disp_lane() const { return disp_lane; } // to make smaller steps than the tile granularity, we have to calculate our offsets ourselves! virtual void get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const; /** * Vehicle movement: calculates z-offset of vehicles on slopes, * handles vehicles that are invisible in tunnels. * @param gr vehicle is on this ground * @note has to be called after loading to initialize z-offsets */ void calc_height(grund_t *gr = NULL); void rotate90() OVERRIDE; template static ribi_t::ribi calc_direction(const K1& from, const K2& to) { return ribi_type(from, to); } ribi_t::ribi calc_set_direction(const koord3d& start, const koord3d& ende); ribi_t::ribi get_direction() const {return direction;} koord3d get_pos_next() const {return pos_next;} waytype_t get_waytype() const OVERRIDE = 0; // true, if this vehicle did not moved for some time virtual bool is_stuck() { return true; } /** * Vehicle movement: enter tile, add this to the ground. * @pre position (obj_t::pos) needs to be updated prior to calling this functions * @param gr pointer to ground (never NULL) */ virtual void enter_tile(grund_t *gr); /** * Vehicle movement: leave tile, release reserved crossing, remove vehicle from the ground. */ virtual void leave_tile(); virtual overtaker_t *get_overtaker() { return NULL; } vehicle_base_t(); vehicle_base_t(koord3d pos); virtual bool is_flying() const { return false; } }; template<> inline vehicle_base_t* obj_cast(obj_t* const d) { return d->is_moving() ? static_cast(d) : 0; } #endif simutrans-124.3/src/simutrans/vehicle/water_vehicle.cc000066400000000000000000000062671474050137200231510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "water_vehicle.h" #include "../simware.h" #include "../builder/goods_manager.h" #include "../builder/vehikelbauer.h" #include "../obj/crossing.h" #include "../dataobj/schedule.h" #include "../obj/roadsign.h" #include "../simconvoi.h" water_vehicle_t::water_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cn) : vehicle_t(pos, desc, player) { cnv = cn; } water_vehicle_t::water_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t() { vehicle_t::rdwr_from_convoi(file); if( file->is_loading() ) { static const vehicle_desc_t *last_desc = NULL; if(is_first) { last_desc = NULL; } // try to find a matching vehicle if(desc==NULL) { dbg->warning("water_vehicle_t::water_vehicle_t()", "try to find a fitting vehicle for %s.", !fracht.empty() ? fracht.front().get_name() : "passengers"); desc = vehicle_builder_t::get_best_matching(water_wt, 0, fracht.empty() ? 0 : 30, 100, 40, !fracht.empty() ? fracht.front().get_desc() : goods_manager_t::passengers, true, last_desc, is_last ); if(desc) { calc_image(); } } // update last desc if( desc ) { last_desc = desc; } } } void water_vehicle_t::enter_tile(grund_t* gr) { vehicle_t::enter_tile(gr); if( weg_t *ch = gr->get_weg(water_wt) ) { // we are in a channel, so book statistics ch->book(get_total_cargo(), WAY_STAT_GOODS); if (leading) { ch->book(1, WAY_STAT_CONVOIS); } } } bool water_vehicle_t::check_next_tile(const grund_t *bd) const { if( bd->is_water() ) { return true; } // channel can have more stuff to check const weg_t *w = bd->get_weg(water_wt); #ifdef ENABLE_WATERWAY_SIGNS if( w && w->has_sign() ) { const roadsign_t* rs = bd->find(); if( rs->get_desc()->get_wtyp()==get_waytype() ) { if( cnv !=NULL && rs->get_desc()->get_min_speed() > 0 && rs->get_desc()->get_min_speed() > cnv->get_min_top_speed() ) { // below speed limit return false; } if( rs->get_desc()->is_private_way() && (rs->get_player_mask() & (1<get_max_speed()>0); } /** Since slopes are handled different for ships */ void water_vehicle_t::calc_friction(const grund_t *gr) { // or a hill? if(gr->get_weg_hang()) { // hill up or down => in lock => decelerate current_friction = 16; } else { // flat track current_friction = 1; } if(previous_direction != direction) { // curve: higher friction current_friction *= 2; } } bool water_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, uint8) { restart_speed = -1; if(leading) { assert(gr); if( gr->obj_count()>251 ) { // too many ships already here .. return false; } weg_t *w = gr->get_weg(water_wt); if(w && w->is_crossing()) { // ok, here is a draw/turn-bridge ... crossing_t* cr = gr->find(); if(!cr->request_crossing(this)) { restart_speed = 0; return false; } } } return true; } schedule_t * water_vehicle_t::generate_new_schedule() const { return new ship_schedule_t(); } simutrans-124.3/src/simutrans/vehicle/water_vehicle.h000066400000000000000000000023341474050137200230020ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef VEHICLE_WATER_VEHICLE_H #define VEHICLE_WATER_VEHICLE_H #include "vehicle.h" /** * A class for naval vehicles. Manages the look of the vehicles * and the navigability of tiles. * @see vehicle_t */ class water_vehicle_t : public vehicle_t { protected: // how expensive to go here (for way search) int get_cost(const grund_t *, const weg_t*, const sint32, ribi_t::ribi) const OVERRIDE { return 1; } void calc_friction(const grund_t *gr) OVERRIDE; bool check_next_tile(const grund_t *bd) const OVERRIDE; void enter_tile(grund_t*) OVERRIDE; public: waytype_t get_waytype() const OVERRIDE { return water_wt; } bool can_enter_tile(const grund_t *gr_next, sint32 &restart_speed, uint8) OVERRIDE; // returns true for the way search to an unknown target. bool is_target(const grund_t *,const grund_t *) const OVERRIDE {return 0;} water_vehicle_t(loadsave_t *file, bool is_first, bool is_last); water_vehicle_t(koord3d pos, const vehicle_desc_t* desc, player_t* player, convoi_t* cnv); obj_t::typ get_typ() const OVERRIDE { return water_vehicle; } schedule_t * generate_new_schedule() const OVERRIDE; }; #endif simutrans-124.3/src/simutrans/world/000077500000000000000000000000001474050137200175165ustar00rootroot00000000000000simutrans-124.3/src/simutrans/world/building_placefinder.h000066400000000000000000000011701474050137200240170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_BUILDING_PLACEFINDER_H #define WORLD_BUILDING_PLACEFINDER_H #include "placefinder.h" #include "simworld.h" /** * building_placefinder_t: * * Search a free site for building using function find_place(). */ class building_placefinder_t : public placefinder_t { public: building_placefinder_t(karte_t *welt, sint16 radius = -1) : placefinder_t(welt, radius) {} bool is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const OVERRIDE { return welt->square_is_free(pos, w, h, NULL, cl); } }; #endif simutrans-124.3/src/simutrans/world/placefinder.cc000066400000000000000000000112361474050137200223040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include "simworld.h" #include "../simintr.h" #include "../simtypes.h" #include "placefinder.h" pos_list_t::pos_list_t(sint16 max_radius) { this->max_radius = max_radius + 1; columns = new sint16[this->max_radius]; restart(); } pos_list_t::~pos_list_t() { delete [] columns; } void pos_list_t::restart() { radius = 1; columns[0] = 0; row = 0; quadrant = 0; } sint16 pos_list_t::find_best_row() { sint16 best_dist = -1; sint16 best_row = -1; for(sint16 i = 0; i < radius; i++) { if(columns[i] < radius) { int dist = (int)i * i + columns[i] * columns[i]; if(best_dist == -1 || dist < best_dist) { best_dist = dist; best_row = i; } } } if(radius < max_radius && best_dist > radius * radius) { return -1; } else { return best_row; } } bool pos_list_t::get_next_pos(koord &k) { if(row != -1) { if(quadrant++ == 4) { quadrant = 1; columns[row]++; row = find_best_row(); if(row == -1) { if(radius < max_radius) { columns[radius++] = 0; } row = find_best_row(); } } } if(row != -1) { if(quadrant == 1 && !row) { quadrant += 2; // skip second 0, +/-y } if(quadrant % 2 == 1 && !columns[row]) { quadrant ++; // skip second +/-x, 0 } return get_pos(k); } return false; } bool pos_list_t::get_pos(koord &k) { if(row != -1) { switch(quadrant) { case 1: k = koord(row, columns[row]); return true; case 2: k = koord(row, (short)-columns[row]); return true; case 3: k = koord((short)-row, columns[row]); return true; case 4: k = koord(-row, -columns[row]); return true; } } return false; } pos_list_wh_t::pos_list_wh_t(sint16 max_radius, sint16 w, sint16 h) : pos_list_t(max_radius) { restart(w, h); } void pos_list_wh_t::restart(sint16 w, sint16 h) { this->w = w; this->h = h; dx = dy = 0; pos_list_t::restart(); } bool pos_list_wh_t::get_next_pos(koord &k) { get_pos(k); if(k.x == 0 && k.y == 0 && (dx > 0 || dy > 0)) { if(dx > 0) { dx--; } else if(dy > 0) { dy--; dx = w - 1; } k.x -= dx; k.y -= dy; } else if(dx > 0) { k.x -= --dx; if(k.y <= 0) { k.y -= h - 1; } } else if(dy > 0) { k.y -= --dy; if(k.x <= 0) { k.x -= w - 1; } } else { if(pos_list_t::get_next_pos(k)) { if(k.y == 0) { dy = h - 1; } if(k.x == 0) { dx = w - 1; } if(k.y <= 0) { k.y -= h - 1; } if(k.x <= 0) { k.x -= w - 1; } } else { return false; } } return true; } /* * Checks if all tiles are suitable for the building to be built * Includes boundary tiles around the building */ bool placefinder_t::is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const { if(!welt->is_within_limits(pos)) { return false; } koord k(w, h); while(k.y-- > 0) { k.x = w; while(k.x-- > 0) { if(!is_tile_ok(pos, k, cl)) { return false; } } } return true; } /* * Checks if the tile is part of the building or if it's a boundary tile * @return false, when tile is part of the building * @return true, when tile is the boundary tile of the building */ bool placefinder_t::is_boundary_tile(koord d) const { return d.x == 0 || d.x == w - 1 || d.y == 0 || d.y == h - 1; } /* * Checks if the tile is suitable for building, used by is_area_ok() * This function is replaced for building types that require rules */ bool placefinder_t::is_tile_ok(koord /*pos*/, koord /*d*/, climate_bits /*cl*/) const { return true; } koord placefinder_t::find_place(koord start, sint16 w, sint16 h, climate_bits cl, bool *r) { sint16 radius = max_radius > 0 ? max_radius : welt->get_size_max(); pos_list_wh_t results_straight(radius, w, h); this->w = w; this->h = h; koord rel1, rel2; if((r && *r) && w != h) { // // Here we also search for the rotated positions. // pos_list_wh_t results_rotated(radius, h, w); if(is_area_ok(start, w, h, cl)) { *r = false; return start; } if(is_area_ok(start, h, w, cl)) { *r = true; return start; } while(results_straight.get_next_pos(rel1) && results_rotated.get_next_pos(rel2)) { if(is_area_ok(start + rel1, w, h, cl)) { *r = false; return start + rel1; } if(is_area_ok(start + rel2, h, w, cl)) { *r = true; return start + rel2; } INT_CHECK("simcity 1313"); } } else { // // Search without rotated positions. // if(is_area_ok(start, w, h, cl)) { return start; } while(results_straight.get_next_pos(rel1)) { if(is_area_ok(start + rel1, w, h, cl)) { if(r) { *r = false; } return start + rel1; } INT_CHECK("simcity 1314"); } } return koord::invalid; } simutrans-124.3/src/simutrans/world/placefinder.h000066400000000000000000000033061474050137200221450ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_PLACEFINDER_H #define WORLD_PLACEFINDER_H #include "../dataobj/koord.h" class karte_t; /** * pos_list_t: * * Provides a list of all coordinates from (0, 0) sorted by distance in increasing * order with x and y in range [-max_xy; max_xy] except for (0, 0) itself. * (0, 0) is used as the end marker. */ class pos_list_t { sint16 max_radius; sint16 *columns; sint16 radius; sint16 row; sint16 quadrant; sint16 find_best_row(); public: /** * @param max_xy (Maximum value for x and y position) */ pos_list_t(sint16 max_xy); virtual ~pos_list_t(); void restart(); bool get_pos(koord &k); virtual bool get_next_pos(koord &k); }; /** * pos_list_wh_t: * * Extended version of pos_list_t. Provides surrounding positions * for a range of size h by w. * (0, 0) is used as the end marker again. */ class pos_list_wh_t : public pos_list_t { sint16 w; sint16 h; sint16 dx; sint16 dy; public: pos_list_wh_t(sint16 max_radius, sint16 w, sint16 h); void restart(sint16 w, sint16 h); void restart() { pos_list_t::restart(); } bool get_next_pos(koord &k) OVERRIDE; }; class placefinder_t { protected: karte_t *welt; sint16 w; sint16 h; sint16 max_radius; virtual bool is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const; virtual bool is_tile_ok(koord pos, koord d, climate_bits cl) const; bool is_boundary_tile(koord d) const; placefinder_t(karte_t *welt, sint16 _max_radius = - 1) { this->welt = welt; max_radius = _max_radius; } virtual ~placefinder_t() {} public: koord find_place(koord start, sint16 w, sint16 h, climate_bits cl, bool *r = NULL); }; #endif simutrans-124.3/src/simutrans/world/simcity.cc000066400000000000000000003747401474050137200215250ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include "../ground/grund.h" #include "../ground/boden.h" #include "../gui/simwin.h" #include "simworld.h" #include "../simware.h" #include "../player/simplay.h" #include "simplan.h" #include "../display/simimg.h" #include "../simhalt.h" #include "../simfab.h" #include "simcity.h" #include "../simmesg.h" #include "../simcolor.h" #include "../gui/minimap.h" #include "../gui/city_info.h" #include "../descriptor/building_desc.h" #include "../simintr.h" #include "../simdebug.h" #include "../obj/gebaeude.h" #include "../obj/way/strasse.h" #include "../vehicle/pedestrian.h" #include "../vehicle/simroadtraffic.h" #include "../dataobj/translator.h" #include "../dataobj/settings.h" #include "../dataobj/loadsave.h" #include "../dataobj/tabfile.h" #include "../dataobj/environment.h" #include "building_placefinder.h" #include "../builder/wegbauer.h" #include "../builder/brueckenbauer.h" #include "../builder/hausbauer.h" #include "../builder/fabrikbauer.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #define PACKET_SIZE (7) /** * This variable is used to control the fractional precision of growth to prevent loss when quantities are small. * Growth calculations use 64 bit signed integers. * Although this is actually scale factor, a power of two is recommended for optimization purposes. */ static sint64 const CITYGROWTH_PER_CITIZEN = 1ll << 32; // Q31.32 fractional form. karte_ptr_t stadt_t::welt; // one is enough ... /********************************* From here on cityrules stuff *****************************************/ /** * in this fixed interval, construction will happen * 21s = 21000 per house */ const uint32 stadt_t::city_growth_step = 21000; /** * this is the default factor to prefer clustering */ uint32 stadt_t::cluster_factor = 10; /* * chance to do renovation instead new building (in percent) */ static uint32 renovation_percentage = 12; /* * minimum ratio of city area to building area to allow expansion * the higher this value, the slower the city expansion if there are still "holes" */ static uint32 min_building_density = 25; // the following are the scores for the different building types static sint16 ind_start_score = 0; static sint16 com_start_score = -10; static sint16 res_start_score = 0; // order: res, com, ind static sint16 ind_neighbour_score[] = { -8, 0, 8 }; static sint16 com_neighbour_score[] = { 1, 8, 1 }; static sint16 res_neighbour_score[] = { 8, 0, -8 }; /** * Rule data structure * maximum 7x7 rules */ class rule_entry_t { public: uint8 x,y; char flag; rule_entry_t(uint8 x_=0, uint8 y_=0, char f_='.') : x(x_), y(y_), flag(f_) {} void rdwr(loadsave_t* file) { file->rdwr_byte(x); file->rdwr_byte(y); uint8 c = flag; file->rdwr_byte(c); flag = c; } }; class rule_t { public: sint16 chance; vector_tpl rule; rule_t(uint32 count=0) : chance(0), rule(count) {} void rdwr(loadsave_t* file) { file->rdwr_short(chance); if (file->is_loading()) { rule.clear(); } uint32 count = rule.get_count(); file->rdwr_long(count); for(uint32 i=0; iis_loading()) { rule.append(rule_entry_t()); } rule[i].rdwr(file); } } }; // house rules static vector_tpl house_rules; // and road rules static vector_tpl road_rules; /** * Symbols in rules: * S = not a road * s = is a road * n = is nature/empty * H = not a house * h = is a house * T = not a stop // added in 88.03.3 * t = is a stop // added in 88.03.3 * u = good slope for way * U = not a slope for ways * . = beliebig */ // here '.' is ignored, since it will not be tested anyway static char const* const allowed_chars_in_rule = "SsnHhTtUu"; /** * @param pos position to check * @param regel the rule to evaluate * @return true on match, false otherwise */ bool stadt_t::bewerte_loc(const koord pos, const rule_t ®el, int rotation) { //printf("Test for (%s) in rotation %d\n", pos.get_str(), rotation); koord k; for(rule_entry_t const& r : regel.rule) { uint8 x,y; switch (rotation) { default: case 0: x=r.x; y=r.y; break; case 90: x=r.y; y=6-r.x; break; case 180: x=6-r.x; y=6-r.y; break; case 270: x=6-r.y; y=r.x; break; } const koord k(pos.x+x-3, pos.y+y-3); const grund_t* gr = welt->lookup_kartenboden(k); if (gr == NULL) { // outside of the map => cannot apply this rule return false; } switch (r.flag) { case 's': // road? if (!gr->hat_weg(road_wt)) return false; break; case 'S': // not road? if (gr->hat_weg(road_wt)) return false; break; case 'h': // is house if (gr->get_typ() != grund_t::fundament || gr->obj_bei(0)->get_typ()!=obj_t::gebaeude) return false; break; case 'H': // no house if (gr->get_typ() == grund_t::fundament) return false; break; case 'n': // nature/empty if (!gr->ist_natur() || gr->kann_alle_obj_entfernen(NULL) != NULL) return false; break; case 'U': // unbuildable for road if (!slope_t::is_way(gr->get_grund_hang())) return false; break; case 'u': // road may be buildable if (slope_t::is_way(gr->get_grund_hang())) return false; break; case 't': // here is a stop/extension building if (!gr->is_halt()) return false; break; case 'T': // no stop if (gr->is_halt()) return false; break; default: ; // ignore } } return true; } /** * Check rule in all transformations at given position * @note but the rules should explicitly forbid building then?!? */ sint32 stadt_t::bewerte_pos(const koord pos, const rule_t ®el) { // will be called only a single time, so we can stop after a single match if(bewerte_loc(pos, regel, 0) || bewerte_loc(pos, regel, 90) || bewerte_loc(pos, regel, 180) || bewerte_loc(pos, regel, 270)) { return 1; } return 0; } void stadt_t::bewerte_strasse(koord k, sint32 rd, const rule_t ®el) { if (simrand(rd) == 0) { best_strasse.check(k, bewerte_pos(k, regel)); } } void stadt_t::bewerte_haus(koord k, sint32 rd, const rule_t ®el) { if (simrand(rd) == 0) { best_haus.check(k, bewerte_pos(k, regel)); } } /** * Reads city configuration data */ bool stadt_t::cityrules_init() { tabfile_t cityconf; // first take user data, then user global data const std::string user_dir=env_t::user_dir; if (!cityconf.open((user_dir+"cityrules.tab").c_str())) { if (!cityconf.open((user_dir+"addons/"+env_t::pak_name+"config/cityrules.tab").c_str())) { if (!cityconf.open((env_t::pak_dir+"config/cityrules.tab").c_str())) { dbg->fatal("stadt_t::init()", "Can't read cityrules.tab" ); } } } tabfileobj_t contents; cityconf.read(contents); char buf[128]; cluster_factor = (uint32)contents.get_int("cluster_factor", 10); renovation_percentage = (uint32)contents.get_int("renovation_percentage", 25); // to keep compatible with the typo, here both are ok min_building_density = (uint32)contents.get_int("minimum_building_desity", 25); min_building_density = (uint32)contents.get_int("minimum_building_density", min_building_density); // init the building value tables ind_start_score = contents.get_int("ind_start_score", 0); ind_neighbour_score[0] = contents.get_int("ind_near_res", -8); ind_neighbour_score[1] = contents.get_int("ind_near_com", 0); ind_neighbour_score[2] = contents.get_int("ind_near_ind", 8); com_start_score = contents.get_int("com_start_score", -10); com_neighbour_score[0] = contents.get_int("com_near_res", 1); com_neighbour_score[1] = contents.get_int("com_near_com", 8); com_neighbour_score[2] = contents.get_int("com_near_ind", 1); res_start_score = contents.get_int("res_start_score", 0); res_neighbour_score[0] = contents.get_int("res_near_res", 8); res_neighbour_score[1] = contents.get_int("res_near_com", 0); res_neighbour_score[2] = contents.get_int("res_near_ind", -8); uint32 num_house_rules = 0; for (;;) { sprintf(buf, "house_%d", num_house_rules + 1); if (contents.get_string(buf, 0)) { num_house_rules++; } else { break; } } DBG_MESSAGE("stadt_t::init()", "Read %d house building rules", num_house_rules); uint32 num_road_rules = 0; for (;;) { sprintf(buf, "road_%d", num_road_rules + 1); if (contents.get_string(buf, 0)) { num_road_rules++; } else { break; } } DBG_MESSAGE("stadt_t::init()", "Read %d road building rules", num_road_rules); clear_ptr_vector( house_rules ); for (uint32 i = 0; i < num_house_rules; i++) { house_rules.append(new rule_t()); sprintf(buf, "house_%d.chance", i + 1); house_rules[i]->chance = contents.get_int(buf, 0); sprintf(buf, "house_%d", i + 1); const char* rule = contents.get_string(buf, ""); // skip leading spaces (use . for padding) while (*rule == ' ') { rule++; } // find out rule size size_t size = 0; size_t maxlen = strlen(rule); while (size < maxlen && rule[size]!=' ') { size++; } if (size > 7 || maxlen < size * (size + 1) - 1 || (size & 1) == 0 || size <= 2 ) { dbg->fatal("stadt_t::cityrules_init()", "house rule %d has bad format!", i + 1); } // put rule into memory const uint8 offset = (7 - (uint8)size) / 2; for (uint y = 0; y < size; y++) { for (uint x = 0; x < size; x++) { const char flag = rule[x + y * (size + 1)]; // check for allowed characters; ignore '.'; // leave midpoint out, should be 'n', which is checked in build() anyway if ((x+offset!=3 || y+offset!=3) && (flag!=0 && strchr(allowed_chars_in_rule, flag))) { house_rules[i]->rule.append(rule_entry_t(x+offset,y+offset,flag)); } else { if ((x+offset!=3 || y+offset!=3) && flag!='.') { dbg->warning("stadt_t::cityrules_init()", "house rule %d entry (%d,%d) is '%c' and will be ignored", i + 1, x+offset, y+offset, flag); } } } } } clear_ptr_vector( road_rules ); for (uint32 i = 0; i < num_road_rules; i++) { road_rules.append(new rule_t()); sprintf(buf, "road_%d.chance", i + 1); road_rules[i]->chance = contents.get_int(buf, 0); sprintf(buf, "road_%d", i + 1); const char* rule = contents.get_string(buf, ""); // skip leading spaces (use . for padding) while (*rule == ' ') { rule++; } // find out rule size size_t size = 0; size_t maxlen = strlen(rule); while (size < maxlen && rule[size] != ' ') { size++; } if ( size > 7 || maxlen < size * (size + 1) - 1 || (size & 1) == 0 || size <= 2 ) { dbg->fatal("stadt_t::cityrules_init()", "road rule %d has bad format!", i + 1); } // put rule into memory const uint8 offset = (7 - (uint8)size) / 2; for (uint y = 0; y < size; y++) { for (uint x = 0; x < size; x++) { const char flag = rule[x + y * (size + 1)]; // check for allowed characters; ignore '.'; // leave midpoint out, should be 'n', which is checked in build() anyway if ((x+offset!=3 || y+offset!=3) && (flag!=0 && strchr(allowed_chars_in_rule, flag))) { road_rules[i]->rule.append(rule_entry_t(x+offset,y+offset,flag)); } else { if ((x+offset!=3 || y+offset!=3) && flag!='.') { dbg->warning("stadt_t::cityrules_init()", "road rule %d entry (%d,%d) is '%c' and will be ignored", i + 1, x+offset, y+offset, flag); } } } } } return true; } /** * Reads/writes city configuration data from/to a savegame * called from karte_t::speichern and karte_t::laden * only written for networkgames */ void stadt_t::cityrules_rdwr(loadsave_t *file) { if( file->is_version_atleast(112, 8) ) { file->rdwr_long( cluster_factor ); } file->rdwr_long(renovation_percentage); file->rdwr_long(min_building_density); file->rdwr_short(ind_start_score); file->rdwr_short(ind_neighbour_score[0]); file->rdwr_short(ind_neighbour_score[1]); file->rdwr_short(ind_neighbour_score[2]); file->rdwr_short(com_start_score); file->rdwr_short(com_neighbour_score[0]); file->rdwr_short(com_neighbour_score[1]); file->rdwr_short(com_neighbour_score[2]); file->rdwr_short(res_start_score); file->rdwr_short(res_neighbour_score[0]); file->rdwr_short(res_neighbour_score[1]); file->rdwr_short(res_neighbour_score[2]); // house rules if (file->is_loading()) { clear_ptr_vector( house_rules ); } uint32 count = house_rules.get_count(); file->rdwr_long(count); for(uint32 i=0; iis_loading()) { house_rules.append(new rule_t()); } house_rules[i]->rdwr(file); } // road rules if (file->is_loading()) { clear_ptr_vector( road_rules ); } count = road_rules.get_count(); file->rdwr_long(count); for(uint32 i=0; iis_loading()) { road_rules.append(new rule_t()); } road_rules[i]->rdwr(file); } } /** * Search a free place for a monument building * Im Gegensatz zum building_placefinder_t werden Strassen auf den Raendern * toleriert. */ class monument_placefinder_t : public placefinder_t { public: monument_placefinder_t(karte_t* welt, sint16 radius) : placefinder_t(welt, radius) {} bool is_tile_ok(koord pos, koord d, climate_bits cl) const OVERRIDE { const planquadrat_t* plan = welt->access(pos + d); // can't build here if (plan == NULL) { return false; } const grund_t* gr = plan->get_kartenboden(); if( ((1 << welt->get_climate( gr->get_pos().get_2d() )) & cl) == 0 ) { return false; } if (is_boundary_tile(d)) { return gr->get_grund_hang() == slope_t::flat && // Flat gr->get_typ() == grund_t::boden && // Boden -> no building (!gr->hat_wege() || gr->hat_weg(road_wt)) && // only roads gr->kann_alle_obj_entfernen(NULL) == NULL; // Irgendwas verbaut den Platz? } else { return gr->get_grund_hang() == slope_t::flat && gr->get_typ() == grund_t::boden && gr->ist_natur() && // No way here gr->kann_alle_obj_entfernen(NULL) == NULL; // Irgendwas verbaut den Platz? } } }; /** * townhall_placefinder_t: */ class townhall_placefinder_t : public placefinder_t { public: townhall_placefinder_t(karte_t* welt, uint8 dir_) : placefinder_t(welt), dir(dir_) {} bool is_tile_ok(koord pos, koord d, climate_bits cl) const OVERRIDE { const grund_t* gr = welt->lookup_kartenboden(pos + d); if (gr == NULL || gr->get_grund_hang() != slope_t::flat) { return false; } if( ((1 << welt->get_climate( gr->get_pos().get_2d() )) & cl) == 0 ) { return false; } if (d.x > 0 || d.y > 0) { if (welt->lookup_kartenboden(pos)->get_hoehe() != gr->get_hoehe()) { // height wrong! return false; } } if ( ((dir & ribi_t::south)!=0 && d.y == h - 1) || ((dir & ribi_t::west)!=0 && d.x == 0) || ((dir & ribi_t::north)!=0 && d.y == 0) || ((dir & ribi_t::east)!=0 && d.x == w - 1)) { // we want to build a road here: return gr->get_typ() == grund_t::boden && (!gr->hat_wege() || (gr->hat_weg(road_wt) && !gr->has_two_ways())) && // build only on roads, no other ways !gr->is_halt() && gr->kann_alle_obj_entfernen(NULL) == NULL; } else { // we want to build the townhall here: maybe replace existing buildings return ((gr->get_typ()==grund_t::boden && gr->ist_natur()) || gr->get_typ()==grund_t::fundament) && gr->kann_alle_obj_entfernen(NULL) == NULL; } } private: uint8 dir; }; static bool compare_gebaeude_pos(const gebaeude_t* a, const gebaeude_t* b) { const uint32 pos_a = (a->get_pos().y<<16)+a->get_pos().x; const uint32 pos_b = (b->get_pos().y<<16)+b->get_pos().x; return pos_a gb_tiles; if (gb != NULL) { uint16 level = gb->get_tile()->get_desc()->get_level()+1; gb->get_tile_list( gb_tiles ); for(grund_t* gr : gb_tiles ) { gebaeude_t* add_gb = gr->find(); if( ordered ) { buildings.insert_ordered( add_gb, level, compare_gebaeude_pos ); } else { buildings.append( add_gb, level ); } add_gb->set_stadt( this ); if( add_gb->get_tile()->get_desc()->is_townhall() ) { has_townhall = true; } } // no update of city limits // as has_low_density may depend on the order the buildings list is filled if (!ordered) { // check borders koord size = gb_tiles.back()->get_pos().get_2d()-gb_tiles.front()->get_pos().get_2d()+koord( 1, 1 ); pruefe_grenzen(pos, size); } } } // this function removes houses from the city house list void stadt_t::remove_gebaeude_from_stadt(gebaeude_t* gb) { buildings.remove(gb); gb->set_stadt(NULL); recalc_city_size(); } // just updates the weight count of this building (after a renovation) void stadt_t::update_gebaeude_from_stadt(gebaeude_t* gb) { buildings.remove(gb); buildings.append(gb, gb->get_tile()->get_desc()->get_level() + 1); } void stadt_t::pruefe_grenzen(koord /*k*/, koord /*size*/) { /* somehow we sometimes end up during growth with a high density * city that is not recognized as such (happens more frequently with pak64.japan) * Therefore, we just recalc the borders each time; building events * are few, and the penalty is not strong. * See version control for old code. */ recalc_city_size(); } // returns true, if there is a halt serving at least one building of the town. bool stadt_t::is_within_players_network(const player_t* player) const { vector_tpl halts; // Find all stations whose coverage affects this city for( weighted_vector_tpl::const_iterator i = buildings.begin(); i != buildings.end(); ++i ) { gebaeude_t* gb = *i; if( const planquadrat_t *plan = welt->access( gb->get_pos().get_2d() ) ) { if( plan->get_haltlist_count() > 0 ) { const halthandle_t *const halt_list = plan->get_haltlist(); for( int h = 0; h < plan->get_haltlist_count(); h++ ) { if( halt_list[h].is_bound() && (halt_list[h]->get_pax_enabled() || halt_list[h]->get_mail_enabled() ) && halt_list[h]->has_available_network(player) ) { return true; } } } } } return false; } // recalculate the spreading of a city // will be updated also after house deletion void stadt_t::recalc_city_size() { // WARNING: do not call this during multithreaded loading, // as has_low_density may depend on the order the buildings list is filled lo = pos; ur = pos; for(gebaeude_t* const i : buildings) { if (i->get_tile()->get_desc()->get_type() != building_desc_t::headquarters) { koord const& gb_pos = i->get_pos().get_2d(); koord const& gb_size = i->get_tile()->get_desc()->get_size(i->get_tile()->get_layout()); lo.clip_max(gb_pos); ur.clip_min(gb_pos + gb_size); } } has_low_density = (buildings.get_count()<10 || (buildings.get_count()*100l)/((ur.x-lo.x)*(ur.y-lo.y)+1) > min_building_density); if( has_low_density ) { // wider borders for faster growth of sparse small towns lo -= koord(2,2); ur += koord(2,2); } lo.clip_min(koord(0,0)); ur.clip_max(koord(welt->get_size().x-1,welt->get_size().y-1)); } void stadt_t::init_pax_destinations() { pax_destinations_old.clear(); pax_destinations_new.clear(); pax_destinations_new_change = 0; } void stadt_t::factory_entry_t::rdwr(loadsave_t *file) { if( file->is_version_atleast(110, 5) ) { koord factory_pos; if( file->is_saving() ) { factory_pos = factory->get_pos().get_2d(); } factory_pos.rdwr( file ); if( file->is_loading() ) { // position will be resolved back into fabrik_t* later factory_pos_x = factory_pos.x; factory_pos_y = factory_pos.y; } file->rdwr_long( demand ); file->rdwr_long( supply ); file->rdwr_long( remaining ); } } void stadt_t::factory_entry_t::resolve_factory() { factory = fabrik_t::get_fab( koord(factory_pos_x, factory_pos_y) ); } const stadt_t::factory_entry_t* stadt_t::factory_set_t::get_entry(const fabrik_t *const factory) const { for(factory_entry_t const& e : entries) { if (e.factory == factory) { return &e; } } return NULL; // not found } stadt_t::factory_entry_t* stadt_t::factory_set_t::get_random_entry() { if( total_remaining>0 ) { sint32 weight = simrand(total_remaining); for(factory_entry_t & entry : entries) { if( entry.remaining>0 ) { if( weight0 ) { average_generated += month_generated; ++months; } if( months>1 ) { average_generated /= months; } /* ratio formula -> ((supply * 100) / total) shifted by RATIO_BITS */ // we supply 1/8 more than demand const sint32 target_supply = (total_demand * SUPPLY_FACTOR + ((1<<(DEMAND_BITS+SUPPLY_BITS))-1)) >> (DEMAND_BITS+SUPPLY_BITS); if( total_demand==0 ) { // no demand -> zero ratio generation_ratio = 0; } else if( !welt->get_settings().get_factory_enforce_demand() || average_generated == 0 ) { // demand not enforced or no pax generation data from previous month(s) -> simply use default ratio generation_ratio = (uint32)default_percent << RATIO_BITS; } else { // ratio of target supply (plus allowances for rounding up) to previous months' average generated pax (less 6.25% or 1/16 allowance for fluctuation), capped by default ratio const sint64 default_ratio = (sint64)default_percent << RATIO_BITS; const sint64 supply_ratio = ((sint64)((target_supply+(sint32)entries.get_count())*100)<>4)+1); generation_ratio = (uint32)( default_ratioget_settings().get_factory_enforce_demand() && (generation_ratio >> RATIO_BITS) == (uint32)default_percent && average_generated > 0 && total_demand > 0 ) { const sint64 supply_promille = ( ( (average_generated << 10) * (sint64)default_percent ) / 100 ) / (sint64)target_supply; if( supply_promille < 1024 ) { // expected supply is really smaller than target supply for(factory_entry_t & entry : entries) { const sint32 new_supply = (sint32)( ( (sint64)entry.demand * SUPPLY_FACTOR * supply_promille + ((1<<(DEMAND_BITS+SUPPLY_BITS+10))-1) ) >> (DEMAND_BITS+SUPPLY_BITS+10) ); const sint32 delta_supply = new_supply - entry.supply; if( delta_supply==0 ) { continue; } else if( delta_supply>0 || (entry.remaining+delta_supply)>=0 ) { // adjust remaining figures by the change in supply total_remaining += delta_supply; entry.remaining += delta_supply; } else { // avoid deducting more than allowed total_remaining -= entry.remaining; entry.remaining = 0; } entry.supply = new_supply; } return; } } // expected supply is unknown or sufficient to meet target supply for(factory_entry_t & entry : entries) { const sint32 new_supply = ( entry.demand * SUPPLY_FACTOR + ((1<<(DEMAND_BITS+SUPPLY_BITS))-1) ) >> (DEMAND_BITS+SUPPLY_BITS); const sint32 delta_supply = new_supply - entry.supply; if( delta_supply==0 ) { continue; } else if( delta_supply>0 || (entry.remaining+delta_supply)>=0 ) { // adjust remaining figures by the change in supply total_remaining += delta_supply; entry.remaining += delta_supply; } else { // avoid deducting more than allowed total_remaining -= entry.remaining; entry.remaining = 0; } entry.supply = new_supply; } } void stadt_t::factory_set_t::new_month() { for(factory_entry_t & e : entries) { e.new_month(); } total_remaining = 0; total_generated = 0; ratio_stale = true; } void stadt_t::factory_set_t::rdwr(loadsave_t *file) { if( file->is_version_atleast(110, 5) ) { uint32 entry_count = entries.get_count(); file->rdwr_long(entry_count); if( file->is_loading() ) { entries.reserve( entry_count ); factory_entry_t entry; for( uint32 e=0; erdwr_long( total_generated ); } } void stadt_t::factory_set_t::resolve_factories() { uint32 remove_count = 0; for(factory_entry_t & e : entries) { e.resolve_factory(); if (!e.factory) { remove_count ++; } } for( uint32 e=0; eremove_factory( NULL ); } } stadt_t::~stadt_t() { // close info win destroy_win((ptrdiff_t)this); if( minimap_t::get_instance()->is_city_selected(this) ) { minimap_t::get_instance()->set_selected_city(NULL); } // only if there is still a world left to delete from if( welt->get_size().x > 1 ) { welt->lookup_kartenboden(pos)->set_text(NULL); if (!welt->is_destroying()) { // remove city info and houses while (!buildings.empty()) { gebaeude_t* const gb = buildings.pop_back(); assert( gb!=NULL && !buildings.is_contained(gb) ); if(gb->get_tile()->get_desc()->get_type()==building_desc_t::headquarters) { stadt_t *city = welt->find_nearest_city(gb->get_pos().get_2d()); gb->set_stadt( city ); if(city) { city->buildings.append(gb, gb->get_passagier_level()); } } else { gb->set_stadt( NULL ); hausbauer_t::remove(welt->get_public_player(),gb); } } // avoid the bookkeeping if world gets destroyed } } } static bool name_used(weighted_vector_tpl const& cities, char const* const name) { for(stadt_t* const i : cities) { if (strcmp(i->get_name(), name) == 0) { return true; } } return false; } stadt_t::stadt_t(player_t* player, koord pos, sint32 citizens, const building_desc_t* th, sint16 rotation) : buildings(16), pax_destinations_old(koord(PAX_DESTINATIONS_SIZE, PAX_DESTINATIONS_SIZE)), pax_destinations_new(koord(PAX_DESTINATIONS_SIZE, PAX_DESTINATIONS_SIZE)) { assert(welt->is_within_limits(pos)); step_count = 0; pax_destinations_new_change = 0; next_step = 0; step_interval = 1; next_growth_step = 0; has_low_density = false; has_townhall = false; stadtinfo_options = 3; // citizen and growth owner = player; this->pos = pos; last_center = koord::invalid; bev = 0; arb = 0; won = 0; lo = ur = pos; /* get a unique cityname */ char const* n = "simcity"; weighted_vector_tpl const& staedte = welt->get_cities(); const vector_tpl& city_names = translator::get_city_name_list(); // make sure we do only ONE random call regardless of how many names are available (to avoid desyncs in network games) if( const uint32 count = city_names.get_count() ) { uint32 idx = simrand( count ); static const uint32 some_primes[] = { 19, 31, 109, 199, 409, 571, 631, 829, 1489, 1999, 2341, 2971, 3529, 4621, 4789, 7039, 7669, 8779, 9721 }; // find prime that does not divide count uint32 offset = 1; for( uint8 i=0; i < lengthof(some_primes); i++ ) { if( count % some_primes[i] != 0 ) { offset = some_primes[i]; break; } } // as count % offset != 0 we are guaranteed to test all city names for(uint32 i=0; i0) { change_size( citizens, true ); } // fill with start citizen ... sint64 bew = get_einwohner(); for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { city_history_year[year][HIST_CITIZENS] = bew; } for (uint month = 0; month < MAX_CITY_HISTORY_MONTHS; month++) { city_history_month[month][HIST_CITIZENS] = bew; } // initialize history array for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { for (uint hist_type = 1; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_year[year][hist_type] = 0; } } for (uint month = 0; month < MAX_CITY_HISTORY_YEARS; month++) { for (uint hist_type = 1; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_month[month][hist_type] = 0; } } city_history_year[0][HIST_CITIZENS] = get_einwohner(); city_history_month[0][HIST_CITIZENS] = get_einwohner(); #ifdef DESTINATION_CITYCARS number_of_cars = 0; #endif } stadt_t::stadt_t(loadsave_t* file) : buildings(16), pax_destinations_old(koord(PAX_DESTINATIONS_SIZE, PAX_DESTINATIONS_SIZE)), pax_destinations_new(koord(PAX_DESTINATIONS_SIZE, PAX_DESTINATIONS_SIZE)) { step_count = 0; next_step = 0; step_interval = 1; next_growth_step = 0; has_low_density = false; has_townhall = false; unsupplied_city_growth = 0; stadtinfo_options = 3; rdwr(file); } void stadt_t::rdwr(loadsave_t* file) { sint32 owner_n; if (file->is_saving()) { owner_n = welt->sp2num(owner); } file->rdwr_str(name); pos.rdwr(file); uint32 lli = lo.x; uint32 lob = lo.y; uint32 lre = ur.x; uint32 lun = ur.y; file->rdwr_long(lli); file->rdwr_long(lob); file->rdwr_long(lre); file->rdwr_long(lun); lo.x = lli; lo.y = lob; ur.x = lre; ur.y = lun; file->rdwr_long(owner_n); file->rdwr_long(bev); file->rdwr_long(arb); file->rdwr_long(won); if( file->is_version_atleast(112, 9) ) { // Must record the partial (less than 1 citizen) growth factor // Otherwise we will get network desyncs // Also allows accumulation of small growth factors file->rdwr_longlong(unsupplied_city_growth); } else if( file->is_loading() ) { unsupplied_city_growth = 0; } // old values zentrum_namen_cnt : aussen_namen_cnt if(file->is_version_less(99, 18)) { sint32 dummy=0; file->rdwr_long(dummy); file->rdwr_long(dummy); } if (file->is_loading()) { owner = welt->get_player(owner_n); } if(file->is_loading()) { // initialize history array for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_year[year][hist_type] = 0; } } for (uint month = 0; month < MAX_CITY_HISTORY_MONTHS; month++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_month[month][hist_type] = 0; } } city_history_year[0][HIST_CITIZENS] = get_einwohner(); city_history_year[0][HIST_CITIZENS] = get_einwohner(); } // we probably need to load/save the city history if (file->is_version_less(86, 0)) { DBG_DEBUG("stadt_t::rdwr()", "is old version: No history!"); } else if(file->is_version_less(99, 16)) { // 86.00.0 introduced city history for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { for (uint hist_type = 0; hist_type < 2; hist_type++) { file->rdwr_longlong(city_history_year[year][hist_type]); } for (uint hist_type = 4; hist_type < 6; hist_type++) { file->rdwr_longlong(city_history_year[year][hist_type]); } } for (uint month = 0; month < MAX_CITY_HISTORY_MONTHS; month++) { for (uint hist_type = 0; hist_type < 2; hist_type++) { file->rdwr_longlong(city_history_month[month][hist_type]); } for (uint hist_type = 4; hist_type < 6; hist_type++) { file->rdwr_longlong(city_history_month[month][hist_type]); } } // not needed any more sint32 dummy = 0; file->rdwr_long(dummy); file->rdwr_long(dummy); file->rdwr_long(dummy); file->rdwr_long(dummy); } else if( file->is_version_less(120, 1) ) { // 99.17.0 extended city history for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { if( hist_type==HIST_PAS_WALKED || hist_type==HIST_MAIL_WALKED ) { continue; } file->rdwr_longlong(city_history_year[year][hist_type]); } } for (uint month = 0; month < MAX_CITY_HISTORY_MONTHS; month++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { if( hist_type==HIST_PAS_WALKED || hist_type==HIST_MAIL_WALKED ) { continue; } file->rdwr_longlong(city_history_month[month][hist_type]); } } // save button settings for this town file->rdwr_long( stadtinfo_options); } else { // 120,001 with walking (direct connections) recored seperately for (uint year = 0; year < MAX_CITY_HISTORY_YEARS; year++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { file->rdwr_longlong(city_history_year[year][hist_type]); } } for (uint month = 0; month < MAX_CITY_HISTORY_MONTHS; month++) { for (uint hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { file->rdwr_longlong(city_history_month[month][hist_type]); } } // save button settings for this town file->rdwr_long( stadtinfo_options); } // differential history if ( file->is_version_less(120, 1) ) { if ( file->is_loading() ) { // Initalize differential statistics assuming a differential of 0. city_growth_get_factors(city_growth_factor_previous, 0); } } else { // load/save differential statistics. for (uint32 i = 0; i < GROWTH_FACTOR_NUMBER; i++) { file->rdwr_longlong(city_growth_factor_previous[i].demand); file->rdwr_longlong(city_growth_factor_previous[i].supplied); } } if(file->is_version_atleast(99, 15) && file->is_version_less(99, 16)) { sint32 dummy = 0; file->rdwr_long(dummy); file->rdwr_long(dummy); } // since 102.2 there are static cities if(file->is_version_atleast(102, 2)) { file->rdwr_bool(allow_citygrowth); } else if( file->is_loading() ) { allow_citygrowth = true; } // save townhall road position if(file->is_version_atleast(102, 3)) { townhall_road.rdwr(file); } else if( file->is_loading() ) { townhall_road = koord::invalid; } // data related to target factories target_factories_pax.rdwr( file ); target_factories_mail.rdwr( file ); if (file->is_version_atleast(122, 1)) { file->rdwr_long(step_count); file->rdwr_long(next_step); file->rdwr_long(next_growth_step); } else if (file->is_loading()) { step_count = 0; next_step = 0; next_growth_step = 0; } if(file->is_loading()) { // Due to some bugs in the special buildings/town hall // placement code, li,re,ob,un could've gotten irregular values // If a game is loaded, the game might suffer from such an mistake // and we need to correct it here. DBG_MESSAGE("stadt_t::rdwr()", "borders (%i,%i) -> (%i,%i)", lo.x, lo.y, ur.x, ur.y); // recalculate borders recalc_city_size(); } } void stadt_t::finish_rd() { // there might be broken savegames if (!name) { set_name( "simcity" ); } if (!has_townhall) { dbg->warning("stadt_t::finish_rd()", "City %s has no valid townhall after loading the savegame, try to build a new one.", get_name()); check_bau_townhall(true,NULL,-1); } // new city => need to grow if (buildings.empty()) { step_grow_city(true); } // clear the minimaps init_pax_destinations(); // init step counter with meaningful value step_interval = (2 << 18u) / (buildings.get_count() * 4 + 1); if (step_interval < 1) { step_interval = 1; } if(townhall_road==koord::invalid) { // guess road tile based on current orientation gebaeude_t const* const gb = obj_cast(welt->lookup_kartenboden(pos)->first_no_way_obj()); if( gb && gb->is_townhall() ) { koord k(gb->get_tile()->get_desc()->get_size(gb->get_tile()->get_layout())); switch (gb->get_tile()->get_layout()) { default: case 0: townhall_road = pos + koord(0, k.y); break; case 1: townhall_road = pos + koord(k.x, 0); break; case 2: townhall_road = pos + koord(0, -1); break; case 3: townhall_road = pos + koord(-1, 0); break; } } } recalc_city_size(); // resolve target factories target_factories_pax.resolve_factories(); target_factories_mail.resolve_factories(); } void stadt_t::rotate90( const sint16 y_size ) { // rotate town origin pos.rotate90( y_size ); townhall_road.rotate90( y_size ); // rotate an rectangle lo.rotate90( y_size ); ur.rotate90( y_size ); sint16 lox = lo.x; lo.x = ur.x; ur.x = lox; // reset building search best_strasse.reset(pos); best_haus.reset(pos); // townhall position may be changed a little! sparse_tpl pax_destinations_temp(koord( PAX_DESTINATIONS_SIZE, PAX_DESTINATIONS_SIZE )); PIXVAL color; koord pos; for( uint16 i = 0; i < pax_destinations_new.get_data_count(); i++ ) { pax_destinations_new.get_nonzero(i, pos, color); assert( color != 0 ); pax_destinations_temp.set( PAX_DESTINATIONS_SIZE-1-pos.y, pos.x, color ); } swap( pax_destinations_temp, pax_destinations_new ); pax_destinations_temp.clear(); for( uint16 i = 0; i < pax_destinations_old.get_data_count(); i++ ) { pax_destinations_old.get_nonzero(i, pos, color); assert( color != 0 ); pax_destinations_temp.set( PAX_DESTINATIONS_SIZE-1-pos.y, pos.x, color ); } pax_destinations_new_change ++; swap( pax_destinations_temp, pax_destinations_old ); } void stadt_t::set_name(const char *new_name) { if (new_name == NULL) { return; } name = new_name; grund_t *gr = welt->lookup_kartenboden(pos); if(gr) { gr->set_text( new_name ); } city_info_t *win = dynamic_cast(win_get_magic((ptrdiff_t)this)); if (win) { win->update_data(); } } /* show city info dialogue */ void stadt_t::open_info_window() { create_win( new city_info_t(this), w_info, (ptrdiff_t)this ); } /* calculates the factories which belongs to certain cities */ void stadt_t::verbinde_fabriken() { DBG_MESSAGE("stadt_t::verbinde_fabriken()", "search factories near %s (center at %i,%i)", get_name(), pos.x, pos.y); assert( target_factories_pax.get_entries().empty() ); assert( target_factories_mail.get_entries().empty() ); for(fabrik_t* const fab : welt->get_fab_list()) { const uint32 count = fab->get_target_cities().get_count(); if( count < welt->get_settings().get_factory_worker_maximum_towns() && koord_distance(fab->get_pos(), pos) < welt->get_settings().get_factory_worker_radius() ) { fab->add_target_city(this); } } DBG_MESSAGE("stadt_t::verbinde_fabriken()", "is connected with %i/%i factories (total demand=%i/%i) for pax/mail.", target_factories_pax.get_entries().get_count(), target_factories_mail.get_entries().get_count(), target_factories_pax.total_demand, target_factories_mail.total_demand); } /* change size of city */ void stadt_t::change_size( sint64 delta_citizen, bool new_town) { DBG_MESSAGE("stadt_t::change_size()", "%i + %i", bev, delta_citizen); if( delta_citizen > 0 ) { unsupplied_city_growth += delta_citizen * CITYGROWTH_PER_CITIZEN; step_grow_city(new_town); } if( delta_citizen < 0 ) { if( bev > -delta_citizen ) { bev += (sint32)delta_citizen; } else { // remove_city(); bev = 1; } step_grow_city(new_town); } DBG_MESSAGE("stadt_t::change_size()", "%i+%i", bev, delta_citizen); } void stadt_t::step(uint32 delta_t) { // recalculate factory going ratios where necessary const sint16 factory_worker_percentage = welt->get_settings().get_factory_worker_percentage(); if( target_factories_pax.ratio_stale ) { target_factories_pax.recalc_generation_ratio( factory_worker_percentage, *city_history_month, MAX_CITY_HISTORY, HIST_PAS_GENERATED); } if( target_factories_mail.ratio_stale ) { target_factories_mail.recalc_generation_ratio( factory_worker_percentage, *city_history_month, MAX_CITY_HISTORY, HIST_MAIL_GENERATED); } // is it time for the next step? next_step += delta_t; next_growth_step += delta_t; step_interval = (1 << 21U) / (buildings.get_count() * welt->get_settings().get_passenger_factor() + 1); if (step_interval < 1) { step_interval = 1; } while(next_growth_step > stadt_t::city_growth_step) { calc_growth(); step_grow_city(); next_growth_step -= stadt_t::city_growth_step; } // create passenger rate proportional to town size while(next_step > step_interval) { step_passagiere(); step_count++; next_step -= step_interval; } // update history (might be changed do to construction/destroying of houses) city_history_month[0][HIST_CITIZENS] = get_einwohner(); // total number city_history_year[0][HIST_CITIZENS] = get_einwohner(); city_history_month[0][HIST_GROWTH] = city_history_month[0][HIST_CITIZENS]-city_history_month[1][HIST_CITIZENS]; // growth city_history_year[0][HIST_GROWTH] = city_history_year[0][HIST_CITIZENS]-city_history_year[1][HIST_CITIZENS]; city_history_month[0][HIST_BUILDING] = buildings.get_count(); city_history_year[0][HIST_BUILDING] = buildings.get_count(); } /* updates the city history */ void stadt_t::roll_history() { // roll months for (int i = MAX_CITY_HISTORY_MONTHS - 1; i > 0; i--) { for (int hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_month[i][hist_type] = city_history_month[i - 1][hist_type]; } } // init this month for (int hist_type = 1; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_month[0][hist_type] = 0; } city_history_month[0][HIST_CITIZENS] = get_einwohner(); city_history_month[0][HIST_BUILDING] = buildings.get_count(); city_history_month[0][HIST_GOODS_NEEDED] = 0; //need to roll year too? if (welt->get_last_month() == 0) { for (int i = MAX_CITY_HISTORY_YEARS - 1; i > 0; i--) { for (int hist_type = 0; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_year[i][hist_type] = city_history_year[i - 1][hist_type]; } } // init this year for (int hist_type = 1; hist_type < MAX_CITY_HISTORY; hist_type++) { city_history_year[0][hist_type] = 0; } city_history_year[0][HIST_CITIZENS] = get_einwohner(); city_history_year[0][HIST_BUILDING] = buildings.get_count(); city_history_year[0][HIST_GOODS_NEEDED] = 0; } } void stadt_t::city_growth_get_factors(city_growth_factor_t(&factors)[GROWTH_FACTOR_NUMBER], uint32 const month) const { // optimize view of history for convenience sint64 const (&h)[MAX_CITY_HISTORY] = city_history_month[month]; // go through each index one at a time uint32 index = 0; // passenger growth factors factors[index ].demand = h[HIST_PAS_GENERATED]; factors[index++].supplied = h[HIST_PAS_TRANSPORTED] + h[HIST_PAS_WALKED]; // mail growth factors factors[index ].demand = h[HIST_MAIL_GENERATED]; factors[index++].supplied = h[HIST_MAIL_TRANSPORTED] + h[HIST_MAIL_WALKED]; // goods growth factors factors[index ].demand = h[HIST_GOODS_NEEDED]; factors[index++].supplied = h[HIST_GOODS_RECEIVED]; assert(index == GROWTH_FACTOR_NUMBER); } sint32 stadt_t::city_growth_base(uint32 const rprec, uint32 const cprec) { // Resolve constant references. settings_t const & s = welt->get_settings(); sint32 const weight[GROWTH_FACTOR_NUMBER] = { s.get_passenger_multiplier(), s.get_mail_multiplier(), s.get_goods_multiplier() }; sint32 acc = 0; // The weighted satisfaction accululator. sint32 div = 0; // The weight dividend. sint32 total = 0; // The total weight. // initalize const growth array city_growth_factor_t growthfactors[GROWTH_FACTOR_NUMBER]; city_growth_get_factors(growthfactors, 0); // Loop through each growth factor and compute it. for( uint32 i = 0; i < GROWTH_FACTOR_NUMBER; i += 1 ) { // Resolve the weight. total += weight[i]; // Compute the differentials. sint64 const had = growthfactors[i].demand - city_growth_factor_previous[i].demand; sint64 const got = growthfactors[i].supplied - city_growth_factor_previous[i].supplied; city_growth_factor_previous[i].demand = growthfactors[i].demand; city_growth_factor_previous[i].supplied = growthfactors[i].supplied; // If we had anything to satisfy add it to weighting otherwise skip. if( had == 0 ) { continue; } // Compute fractional satisfaction. sint32 const frac = (sint32)((got << cprec) / had); // Add to weight and div. acc += frac * weight[i]; div += weight[i]; } // If there was not anything to satisfy then use last month averages. if ( div == 0 ) { // initalize growth factor array city_growth_factor_t prev_growthfactors[GROWTH_FACTOR_NUMBER]; city_growth_get_factors(prev_growthfactors, 1); for( uint32 i = 0; i < GROWTH_FACTOR_NUMBER; i += 1 ){ // Extract the values of growth. sint64 const had = prev_growthfactors[i].demand; sint64 const got = prev_growthfactors[i].supplied; // If we had anything to satisfy add it to weighting otherwise skip. if( had == 0 ) { continue; } // Compute fractional satisfaction. sint32 const frac = (sint32)((got << cprec) / had); // Add to weight and div. acc += frac * weight[i]; div += weight[i]; } } // Return computed result. If still no demand then assume no growth to prevent self-growing new hamlets. return div != 0 ? (total * (acc / div)) >> (cprec - rprec) : 0; } void stadt_t::city_growth_monthly(uint32 const month) { // initalize growth factor array city_growth_factor_t growthfactors[GROWTH_FACTOR_NUMBER]; city_growth_get_factors(growthfactors, month); // Perform roll over. for( uint32 i = 0; i < GROWTH_FACTOR_NUMBER; i += 1 ){ // Compute the differentials. sint64 const had = growthfactors[i].demand - city_growth_factor_previous[i].demand; sint64 const got = growthfactors[i].supplied - city_growth_factor_previous[i].supplied; city_growth_factor_previous[i].demand = -had; city_growth_factor_previous[i].supplied = -got; } } void stadt_t::new_month( bool recalc_destinations ) { swap( pax_destinations_old, pax_destinations_new ); pax_destinations_new.clear(); pax_destinations_new_change = 0; city_growth_monthly(0); roll_history(); target_factories_pax.new_month(); target_factories_mail.new_month(); const sint16 factory_worker_percentage = welt->get_settings().get_factory_worker_percentage(); // settings_t const& s = welt->get_settings(); target_factories_pax.recalc_generation_ratio( factory_worker_percentage, *city_history_month, MAX_CITY_HISTORY, HIST_PAS_GENERATED); target_factories_mail.recalc_generation_ratio( factory_worker_percentage, *city_history_month, MAX_CITY_HISTORY, HIST_MAIL_GENERATED); recalc_target_cities(); // center has moved => change attraction weights if( recalc_destinations || last_center != get_center() ) { last_center = get_center(); recalc_target_attractions(); } if( !private_car_t::list_empty() && welt->get_settings().get_traffic_level() > 0 ) { // spawn eventual citycars // the more transported, the less are spawned // the larger the city, the more spawned ... /* original implementation that is replaced by integer-only version below double pfactor = (double)(city_history_month[1][HIST_PAS_TRANSPORTED]) / (double)(city_history_month[1][HIST_PAS_GENERATED]+1); double mfactor = (double)(city_history_month[1][HIST_MAIL_TRANSPORTED]) / (double)(city_history_month[1][HIST_MAIL_GENERATED]+1); double gfactor = (double)(city_history_month[1][HIST_GOODS_RECEIVED]) / (double)(city_history_month[1][HIST_GOODS_NEEDED]+1); double factor = pfactor > mfactor ? (gfactor > pfactor ? gfactor : pfactor ) : mfactor; factor = (1.0-factor)*city_history_month[1][HIST_CITIZENS]; factor = log10( factor ); */ // placeholder for fractions # define decl_stat(name, i0, i1) sint64 name##_stat[2]; name##_stat[0] = city_history_month[1][i0]; name##_stat[1] = city_history_month[1][i1]+1; // defines and initializes local sint64[2] arrays decl_stat(pax, HIST_PAS_TRANSPORTED, HIST_PAS_GENERATED); decl_stat(mail, HIST_MAIL_TRANSPORTED, HIST_MAIL_GENERATED); decl_stat(good, HIST_GOODS_RECEIVED, HIST_GOODS_NEEDED); // true if s1[0] / s1[1] > s2[0] / s2[1] # define comp_stats(s1,s2) ( s1[0]*s2[1] > s2[0]*s1[1] ) // computes (1.0 - s[0]/s[1]) * city_history_month[1][HIST_CITIZENS] # define comp_factor(s) (city_history_month[1][HIST_CITIZENS] *( s[1]-s[0] )) / s[1] uint32 factor = (uint32)( comp_stats(pax_stat, mail_stat) ? (comp_stats(good_stat, pax_stat) ? comp_factor(good_stat) : comp_factor(pax_stat)) : comp_factor(mail_stat) ); factor = log10(factor); #ifndef DESTINATION_CITYCARS uint16 number_of_cars = simrand( factor * welt->get_settings().get_traffic_level() ) / 16; city_history_month[0][HIST_CITYCARS] = number_of_cars; city_history_year[0][HIST_CITYCARS] += number_of_cars; koord k; koord pos = get_zufallspunkt(); for (k.y = pos.y - 3; k.y < pos.y + 3; k.y++) { for (k.x = pos.x - 3; k.x < pos.x + 3; k.x++) { if(number_of_cars==0) { return; } if( grund_t* gr = welt->lookup_kartenboden(k) ) { if( weg_t* w = gr->get_weg(road_wt) ) { // do not spawn on privte roads or if there is already a car if( ribi_t::is_twoway(w->get_ribi_unmasked()) && player_t::check_owner(NULL,w->get_owner()) && gr->find() == NULL ) { private_car_t* vt = new private_car_t(gr, koord::invalid); gr->obj_add(vt); number_of_cars--; } } } } } // correct statistics for ungenerated cars city_history_month[0][HIST_CITYCARS] -= number_of_cars; city_history_year[0][HIST_CITYCARS] -= number_of_cars; #else city_history_month[0][HIST_CITYCARS] = 0; number_of_cars = simrand( factor * welt->get_settings().get_traffic_level() ) / 16; #endif } } void stadt_t::calc_growth() { // now iterate over all factories to get the ratio of producing version non-producing factories // we use the incoming storage as a measure and we will only look for end consumers (power stations, markets) for(factory_entry_t const& i : target_factories_pax.get_entries()) { fabrik_t *const fab = i.factory; if (fab->get_consumer().empty() && !fab->get_suppliers().empty()) { // consumer => check for it storage const factory_desc_t *const desc = fab->get_desc(); for( int i=0; iget_supplier_count(); i++ ) { city_history_month[0][HIST_GOODS_NEEDED] ++; city_history_year[0][HIST_GOODS_NEEDED] ++; if( fab->get_input_stock( desc->get_supplier(i)->get_input_type() )>0 ) { city_history_month[0][HIST_GOODS_RECEIVED] ++; city_history_year[0][HIST_GOODS_RECEIVED] ++; } } } } // maybe this town should stay static if( !allow_citygrowth ) { unsupplied_city_growth = 0; return; } // Compute base growth. sint32 const total_supply_percentage = city_growth_base(); // By construction, this is a percentage times 2^6 (Q25.6). // Although intended to be out of 100, it can be more or less. // We will divide it by 2^4=16 for traditional reasons, which means // it generates 2^2 (=4) or fewer people at 100%. // smaller towns should grow slower to have villages for a longer time sint32 const weight_factor = bev < 1000 ? welt->get_settings().get_growthfactor_small() : bev < 10000 ? welt->get_settings().get_growthfactor_medium() : welt->get_settings().get_growthfactor_large(); // now compute the growth for this step sint32 growth_factor = weight_factor > 0 ? total_supply_percentage / weight_factor : 0; // Scale up growth to have a larger fractional component. This allows small growth units to accumulate in the case of long months. sint64 new_unsupplied_city_growth = growth_factor * (CITYGROWTH_PER_CITIZEN / 16); // Growth is scaled down by month length. // The result is that ~ the same monthly growth will occur independent of month length. new_unsupplied_city_growth = welt->inverse_scale_with_month_length( new_unsupplied_city_growth ); // Add the computed growth to the growth accumulator. // Future growth scale factors can be applied here. unsupplied_city_growth += new_unsupplied_city_growth; } // does constructions ... void stadt_t::step_grow_city( bool new_town ) { // Try harder to build if this is a new town int num_tries = new_town ? 1000 : 30; // since we use internally a finer value ... const sint64 growth_steps = unsupplied_city_growth / CITYGROWTH_PER_CITIZEN; if( growth_steps > 0 ) { unsupplied_city_growth %= CITYGROWTH_PER_CITIZEN; } // let city grow in steps of 1 for( sint64 n = 0; n < growth_steps; n++ ) { bev++; for( int i = 0; i < num_tries && bev * 2 > won + arb + 100; i++ ) { build(); } check_bau_spezial(new_town); check_bau_townhall(new_town,NULL,-1); check_bau_factory(new_town); // add industry? (not during creation) INT_CHECK("simcity 275"); } } /* this creates passengers and mail for everything. It is therefore one of the CPU hogs of the machine * think trice, before adding here ... */ void stadt_t::step_passagiere() { // decide whether to generate passengers or mail const bool ispass = simrand(GENERATE_RATIO_PASS + GENERATE_RATIO_MAIL) < GENERATE_RATIO_PASS; const goods_desc_t *const wtyp = ispass ? goods_manager_t::passengers : goods_manager_t::mail; const uint32 history_type = ispass ? HIST_BASE_PASS : HIST_BASE_MAIL; factory_set_t &target_factories = ispass ? target_factories_pax : target_factories_mail; // restart at first building? if (step_count >= buildings.get_count()) { step_count = 0; } if (buildings.empty()) { return; } const gebaeude_t* gb = buildings[step_count]; // since now backtravels occur, we damp the numbers a little const uint32 num_pax = (ispass) ? (gb->get_tile()->get_desc()->get_level() + 6) >> 2 : (gb->get_tile()->get_desc()->get_mail_level() + 8) >> 3 ; // create pedestrians in the near area? if (env_t::random_pedestrians && ispass) { pedestrian_t::generate_pedestrians_near(welt->lookup_kartenboden(gb->get_pos().get_2d()), num_pax); } // suitable start search const koord origin_pos = gb->get_pos().get_2d(); const planquadrat_t *const plan = welt->access(origin_pos); const halthandle_t *const halt_list = plan->get_haltlist(); // suitable start search static vector_tpl start_halts(16); start_halts.clear(); for (uint h = 0; h < plan->get_haltlist_count(); h++) { halthandle_t halt = halt_list[h]; if( halt.is_bound() && halt->is_enabled(wtyp) && !halt->is_overcrowded(wtyp->get_index()) ) { start_halts.append(halt); } } // track number of generated passengers. city_history_year[0][history_type + HIST_OFFSET_GENERATED] += num_pax; city_history_month[0][history_type + HIST_OFFSET_GENERATED] += num_pax; // only continue, if this is a good start halt if( !start_halts.empty() ) { // Find passenger destination for( uint pax_routed=0, pax_left_to_do=0; pax_routed < num_pax; pax_routed += pax_left_to_do ) { // number of passengers that want to travel // for efficiency we try to route not every single pax, but packets. // If possible, we do 7 passengers at a time // the last packet might have less than 7 pax pax_left_to_do = min(PACKET_SIZE, num_pax - pax_routed); // search target for the passenger pax_return_type will_return; factory_entry_t *factory_entry = NULL; stadt_t *dest_city = NULL; const koord dest_pos = find_destination(target_factories, city_history_month[0][history_type + HIST_OFFSET_GENERATED], &will_return, factory_entry, dest_city); if( factory_entry ) { if (welt->get_settings().get_factory_enforce_demand()) { // ensure no more than remaining amount pax_left_to_do = min( pax_left_to_do, factory_entry->remaining ); factory_entry->remaining -= pax_left_to_do; target_factories.total_remaining -= pax_left_to_do; } target_factories.total_generated += pax_left_to_do; factory_entry->factory->book_stat(pax_left_to_do, ispass ? FAB_PAX_GENERATED : FAB_MAIL_GENERATED); } ware_t pax(wtyp); pax.set_target_pos(dest_pos); pax.amount = pax_left_to_do; pax.to_factory = ( factory_entry ? 1 : 0 ); ware_t return_pax(wtyp); // now, finally search a route; this consumes most of the time int const route_result = haltestelle_t::search_route( &start_halts[0], start_halts.get_count(), welt->get_settings().is_no_routing_over_overcrowding(), pax, &return_pax); halthandle_t start_halt = return_pax.get_target_halt(); if( route_result==haltestelle_t::ROUTE_OK ) { // so we have happy traveling passengers start_halt->starte_mit_route(pax); start_halt->add_pax_happy(pax.amount); // people were transported so are logged city_history_year[0][history_type + HIST_OFFSET_TRANSPORTED] += pax_left_to_do; city_history_month[0][history_type + HIST_OFFSET_TRANSPORTED] += pax_left_to_do; // destination logged merke_passagier_ziel(dest_pos, color_idx_to_rgb(COL_YELLOW)); } else if( route_result==haltestelle_t::ROUTE_WALK ) { if( factory_entry ) { // workers and mail delivered instantly to factory factory_entry->factory->liefere_an(wtyp, pax_left_to_do); } // log walked at stop start_halt->add_pax_walked(pax_left_to_do); // people who walk or deliver by hand logged as walking city_history_year[0][history_type + HIST_OFFSET_WALKED] += pax_left_to_do; city_history_month[0][history_type + HIST_OFFSET_WALKED] += pax_left_to_do; // probably not a good idea to mark them as player only cares about remote traffic //merke_passagier_ziel(dest_pos, color_idx_to_rgb(COL_YELLOW)); } else if( route_result==haltestelle_t::ROUTE_OVERCROWDED ) { // overcrowded routes cause unhappiness to be logged if( start_halt.is_bound() ) { start_halt->add_pax_unhappy(pax_left_to_do); } else { // all routes to goal are overcrowded -> register at first stop (closest) for(halthandle_t const s : start_halts) { s->add_pax_unhappy(pax_left_to_do); merke_passagier_ziel(dest_pos, color_idx_to_rgb(COL_ORANGE)); break; } } // destination logged merke_passagier_ziel(dest_pos, color_idx_to_rgb(COL_ORANGE)); } else if ( route_result == haltestelle_t::NO_ROUTE ) { // since there is no route from any start halt -> register no route at first halts (closest) for(halthandle_t const s : start_halts) { s->add_pax_no_route(pax_left_to_do); break; } merke_passagier_ziel(dest_pos, color_idx_to_rgb(COL_DARK_ORANGE)); #ifdef DESTINATION_CITYCARS //citycars with destination generate_private_cars( origin_pos, dest_pos ); #endif } // return passenger traffic if( will_return != no_return ) { // compute return amount uint32 pax_return = pax_left_to_do; // apply return modifiers if( will_return != city_return && wtyp == goods_manager_t::mail ) { // attractions and factories return more mail than they receive pax_return *= MAIL_RETURN_MULTIPLIER_PRODUCERS; } // log potential return passengers at destination city dest_city->city_history_year[0][history_type + HIST_OFFSET_GENERATED] += pax_return; dest_city->city_history_month[0][history_type + HIST_OFFSET_GENERATED] += pax_return; // factories generate return traffic if ( factory_entry ) { factory_entry->factory->book_stat(pax_return, (ispass ? FAB_PAX_GENERATED : FAB_MAIL_GENERATED)); } // route type specific logic if( route_result == haltestelle_t::ROUTE_OK ) { // send return packet halthandle_t return_halt = pax.get_target_halt(); if( !return_halt->is_overcrowded(wtyp->get_index()) ) { // stop can receive passengers // register departed pax/mail at factory if (factory_entry) { factory_entry->factory->book_stat(pax_return, ispass ? FAB_PAX_DEPARTED : FAB_MAIL_DEPARTED); } // setup ware packet return_pax.amount = pax_return; return_pax.set_target_pos(origin_pos); return_halt->starte_mit_route(return_pax); // log departed at stop return_halt->add_pax_happy(pax_return); // log departed at destination city dest_city->city_history_year[0][history_type + HIST_OFFSET_TRANSPORTED] += pax_return; dest_city->city_history_month[0][history_type + HIST_OFFSET_TRANSPORTED] += pax_return; } else { // stop is crowded return_halt->add_pax_unhappy(pax_return); } } else if( route_result == haltestelle_t::ROUTE_WALK ) { // walking can produce return flow as a result of commuters to industry, monuments or stupidly big stops // register departed pax/mail at factory if ( factory_entry ) { factory_entry->factory->book_stat(pax_return, ispass ? FAB_PAX_DEPARTED : FAB_MAIL_DEPARTED); } // log walked at stop (source and destination stops are the same) start_halt->add_pax_walked(pax_return); // log people who walk or deliver by hand dest_city->city_history_year[0][history_type + HIST_OFFSET_WALKED] += pax_return; dest_city->city_history_month[0][history_type + HIST_OFFSET_WALKED] += pax_return; } else if( route_result == haltestelle_t::ROUTE_OVERCROWDED ) { // overcrowded routes cause unhappiness to be logged if (pax.get_target_halt().is_bound()) { pax.get_target_halt()->add_pax_unhappy(pax_return); } else { // the unhappy passengers will be added to the first stops near destination (might be none) const planquadrat_t *const dest_plan = welt->access(dest_pos); const halthandle_t *const dest_halt_list = dest_plan->get_haltlist(); for (uint h = 0; h < dest_plan->get_haltlist_count(); h++) { halthandle_t halt = dest_halt_list[h]; if (halt->is_enabled(wtyp)) { halt->add_pax_unhappy(pax_return); break; } } } } else if (route_result == haltestelle_t::NO_ROUTE) { // passengers who cannot find a route will be added to the first stops near destination (might be none) const planquadrat_t *const dest_plan = welt->access(dest_pos); const halthandle_t *const dest_halt_list = dest_plan->get_haltlist(); for (uint h = 0; h < dest_plan->get_haltlist_count(); h++) { halthandle_t halt = dest_halt_list[h]; if (halt->is_enabled(wtyp)) { halt->add_pax_no_route(pax_return); break; } } } } INT_CHECK( "simcity 1579" ); } } else { // assume no free stop to start at all bool is_there_any_stop = false; // the unhappy passengers will be added to the first stop if any for( uint h=0; hget_haltlist_count(); h++ ) { halthandle_t halt = plan->get_haltlist()[h]; if( halt->is_enabled(wtyp) ) { halt->add_pax_unhappy(num_pax); is_there_any_stop = true; // only overcrowded break; } } // all passengers without suitable start: // fake one ride to get a proper display of destinations (although there may be more) ... pax_return_type will_return; factory_entry_t *factory_entry = NULL; stadt_t *dest_city = NULL; const koord ziel = find_destination(target_factories, city_history_month[0][history_type + HIST_OFFSET_GENERATED], &will_return, factory_entry, dest_city); if( factory_entry ) { // consider at most 1 packet's amount as factory-going sint32 amount = min(PACKET_SIZE, num_pax); if( welt->get_settings().get_factory_enforce_demand() ) { // ensure no more than remaining amount amount = min( amount, factory_entry->remaining ); factory_entry->remaining -= amount; target_factories.total_remaining -= amount; } target_factories.total_generated += amount; factory_entry->factory->book_stat( amount, ( ispass ? FAB_PAX_GENERATED : FAB_MAIL_GENERATED ) ); } // log reverse flow at destination city for accurate tally if( will_return != no_return ) { uint32 pax_return = num_pax; // apply return modifiers if( will_return != city_return && wtyp == goods_manager_t::mail ) { // attractions and factories return more mail than they receive pax_return *= MAIL_RETURN_MULTIPLIER_PRODUCERS; } // log potential return passengers at destination city dest_city->city_history_year[0][history_type + HIST_OFFSET_GENERATED] += pax_return; dest_city->city_history_month[0][history_type + HIST_OFFSET_GENERATED] += pax_return; // factories generate return traffic if ( factory_entry ) { factory_entry->factory->book_stat(pax_return, (ispass ? FAB_PAX_GENERATED : FAB_MAIL_GENERATED)); } // passengers with no route will be added to the first stops near destination (might be none) const planquadrat_t *const dest_plan = welt->access(ziel); const halthandle_t *const dest_halt_list = dest_plan->get_haltlist(); for (uint h = 0; h < dest_plan->get_haltlist_count(); h++) { halthandle_t halt = dest_halt_list[h]; if ( halt->is_enabled(wtyp) ) { if( is_there_any_stop ) { // "just" overcrowded halt->add_pax_unhappy(pax_return); } else { // no stops at all halt->add_pax_no_route(pax_return); } break; } } } #ifdef DESTINATION_CITYCARS //citycars with destination generate_private_cars( origin_pos, ziel ); #endif merke_passagier_ziel(ziel, color_idx_to_rgb(COL_ORANGE)); // we show unhappy instead no route for destination stop } } koord stadt_t::get_zufallspunkt() const { if(!buildings.empty()) { gebaeude_t* const gb = pick_any_weighted(buildings); koord k = gb->get_pos().get_2d(); if(!welt->is_within_limits(k)) { // this building should not be in this list, since it has been already deleted! dbg->error("stadt_t::get_zufallspunkt()", "illegal building in city list of %s: %p removing!", this->get_name(), gb); const_cast(this)->buildings.remove(gb); k = koord(0, 0); } return k; } // might happen on slow computers during creation of new cities or start of map return koord(0,0); } void stadt_t::add_target_city(stadt_t *const city) { target_cities.append( city, weight_by_distance( city->get_einwohner()+1, shortest_distance( get_center(), city->get_center() ) ) ); } void stadt_t::recalc_target_cities() { target_cities.clear(); for(stadt_t* const c : welt->get_cities()) { add_target_city(c); } } void stadt_t::add_target_attraction(gebaeude_t *const attraction) { assert( attraction != NULL ); target_attractions.append( attraction, weight_by_distance( attraction->get_passagier_level() << 4, shortest_distance( get_center(), attraction->get_pos().get_2d() ) ) ); } void stadt_t::recalc_target_attractions() { target_attractions.clear(); for(gebaeude_t* const a : welt->get_attractions()) { add_target_attraction(a); } } /* this function generates a random target for passenger/mail * changing this strongly affects selection of targets and thus game strategy */ koord stadt_t::find_destination(factory_set_t &target_factories, const sint64 generated, pax_return_type* will_return, factory_entry_t* &factory_entry, stadt_t* &dest_city) { // generate factory traffic when required if( target_factories.total_remaining>0 && (sint64)target_factories.generation_ratio>((sint64)(target_factories.total_generated*100)<factory->get_pos().get_2d(); } // chance to generate tourist traffic const sint16 rand = simrand(100 - (target_factories.generation_ratio >> RATIO_BITS)); if( rand < welt->get_settings().get_tourist_percentage() && target_attractions.get_sum_weight() > 0 ) { *will_return = tourist_return; // tourists will return gebaeude_t *const &attraction = pick_any_weighted(target_attractions); dest_city = attraction->get_stadt(); // unsure if return value always valid if (dest_city == NULL) { // if destination city was invalid assume this city is the source dest_city = this; } return attraction->get_pos().get_2d(); } // generate general traffic between buildings // since the locality is already taken into account for us, we just use the random weight stadt_t *const selected_city = pick_any_weighted( target_cities ); // no return trip if the destination is inside the same city *will_return = selected_city == this ? no_return : city_return; dest_city = selected_city; // find a random spot inside the selected city return selected_city->get_zufallspunkt(); } void stadt_t::merke_passagier_ziel(koord k, PIXVAL color) { const koord p = koord( ((k.x * PAX_DESTINATIONS_SIZE) / welt->get_size().x) & (PAX_DESTINATIONS_SIZE-1), ((k.y * PAX_DESTINATIONS_SIZE) / welt->get_size().y) & (PAX_DESTINATIONS_SIZE-1) ); pax_destinations_new_change ++; pax_destinations_new.set(p, color); } /** * building_place_with_road_finder: * Search a free place for a building using function suche_platz() (search place). * added: Minimum distance between monuments */ class building_place_with_road_finder: public building_placefinder_t { public: /// if false, this will the check 'do not build next other to special buildings' bool big_city; building_place_with_road_finder(karte_t* welt, sint16 radius, bool big) : building_placefinder_t(welt, radius), big_city(big) {} // get distance to next special building int find_dist_next_special(koord pos) const { const weighted_vector_tpl& attractions = welt->get_attractions(); int dist = welt->get_size().x * welt->get_size().y; for(gebaeude_t* const i : attractions ) { int const d = koord_distance(i->get_pos(), pos); if( d < dist ) { dist = d; } } for(stadt_t * const city : welt->get_cities() ) { int const d = koord_distance(city->get_pos(), pos); if( d < dist ) { dist = d; } } return dist; } bool is_area_ok(koord pos, sint16 w, sint16 h, climate_bits cl) const OVERRIDE { if( !building_placefinder_t::is_area_ok(pos, w, h, cl) ) { return false; } bool next_to_road = false; // not direct next to factories or townhalls for (sint16 x = -1; x < w; x++) { for (sint16 y = -1; y < h; y++) { grund_t *gr = welt->lookup_kartenboden(pos + koord(x,y)); if (!gr) { return false; } if ( 0 <= x && x < w-1 && 0 <= y && y < h-1 ) { // inside: nothing on top like elevated monorails? if( gr->get_leitung()!=NULL || welt->lookup(gr->get_pos()+koord3d(0,0,1) )!=NULL) { // something on top (monorail or powerlines) return false; } } else { // border: not direct next to special buildings if (big_city) { if( gebaeude_t *gb=gr->find() ) { const building_desc_t::btype utyp = gb->get_tile()->get_desc()->get_type(); if( building_desc_t::attraction_city <= utyp && utyp <= building_desc_t::headquarters) { return false; } } } // but near a road if possible if (!next_to_road) { next_to_road = gr->hat_weg(road_wt); } } } } if (!next_to_road) { return false; } // try to built a little away from previous ones if (big_city && find_dist_next_special(pos) < w + h + welt->get_settings().get_special_building_distance() ) { return false; } return true; } }; void stadt_t::check_bau_spezial(bool new_town) { // tourist attraction buildings const building_desc_t* desc = hausbauer_t::get_special( bev, building_desc_t::attraction_city, welt->get_timeline_year_month(), new_town, welt->get_climate(pos) ); if (desc != NULL) { if (simrand(100) < (uint)desc->get_distribution_weight()) { bool big_city = buildings.get_count() >= 10; bool is_rotate = desc->get_all_layouts() > 1; sint16 radius = koord_distance( get_rechtsunten(), get_linksoben() )/2 + 10; // find place koord best_pos = building_place_with_road_finder(welt, radius, big_city).find_place(pos, desc->get_x(), desc->get_y(), desc->get_allowed_climate_bits(), &is_rotate); if (best_pos != koord::invalid) { // then built it int rotate = 0; if (desc->get_all_layouts() > 1) { rotate = (simrand(20) & 2) + is_rotate; } gebaeude_t* monument = hausbauer_t::build( owner, best_pos, rotate, desc ); // tell the player, if not during initialization if (!new_town) { cbuffer_t buf; buf.printf( translator::translate("To attract more tourists\n%s built\na %s\nwith the aid of\n%i tax payers."), get_name(), make_single_line_string(translator::translate(desc->get_name()), 2), get_einwohner()); welt->get_message()->add_message(buf, monument->get_pos(), message_t::city, CITY_KI, desc->get_tile(0)->get_background(0, 0, 0)); } } } } if ((bev & 511) == 0) { // Build a monument desc = hausbauer_t::get_random_monument(welt->get_timeline_year_month()); if (desc) { koord total_size = koord(2 + desc->get_x(), 2 + desc->get_y()); sint16 radius = koord_distance( get_rechtsunten(), get_linksoben() )/2 + 10; koord best_pos(monument_placefinder_t(welt, radius).find_place(pos, total_size.x, total_size.y, desc->get_allowed_climate_bits())); if (best_pos != koord::invalid) { // check if borders around the monument are inside the map limits const bool pre_ok = welt->is_within_limits( koord(best_pos) - koord(1, 1) ) && \ welt->is_within_limits( koord(best_pos) + total_size + koord(1, 1) ); if (!pre_ok){ return; } bool ok=false; // We build the monument only if there is already at least one road for (int i = 0; i < total_size.x && !ok; i++) { ok = ok || welt->access(best_pos + koord(i, -1))->get_kartenboden()->hat_weg(road_wt) || welt->access(best_pos + koord(i, total_size.y))->get_kartenboden()->hat_weg(road_wt); } for (int i = 0; i < total_size.y && !ok; i++) { ok = ok || welt->access(best_pos + koord(total_size.x, i))->get_kartenboden()->hat_weg(road_wt) || welt->access(best_pos + koord(-1, i))->get_kartenboden()->hat_weg(road_wt); } if (ok) { // build roads around the monument sint16 h=welt->lookup_kartenboden(best_pos)->get_hoehe(); for (int i = 0; i < total_size.y; i++) { // only build in same height and not on slopes... const grund_t *gr = welt->lookup_kartenboden(best_pos + koord(0, i)); if(gr->get_hoehe()==h && gr->get_grund_hang()==0) { build_road(best_pos + koord(0, i), NULL, true); } gr = welt->lookup_kartenboden(best_pos + koord(total_size.x - 1, i)); if(gr->get_hoehe()==h && gr->get_grund_hang()==0) { build_road(best_pos + koord(total_size.x - 1, i), NULL, true); } } for (int i = 0; i < total_size.x; i++) { // only build in same height and not on slopes... const grund_t *gr = welt->lookup_kartenboden(best_pos + koord(i, 0)); if(gr->get_hoehe()==h && gr->get_grund_hang()==0) { build_road(best_pos + koord(i, 0), NULL, true); } gr = welt->lookup_kartenboden(best_pos + koord(i, total_size.y - 1)); if(gr->get_hoehe()==h && gr->get_grund_hang()==0) { build_road(best_pos + koord(i, total_size.y - 1), NULL, true); } } // and then build it const gebaeude_t* gb = hausbauer_t::build(owner, best_pos + koord(1, 1), 0, desc); hausbauer_t::monument_erected(desc); add_gebaeude_to_stadt(gb); // tell the player, if not during initialization if (!new_town) { cbuffer_t buf; buf.printf( translator::translate("With a big festival\n%s built\na new monument.\n%i citicens rejoiced."), get_name(), get_einwohner() ); welt->get_message()->add_message(buf, gb->get_pos() + koord3d(1, 1, 0), message_t::city, CITY_KI, desc->get_tile(0)->get_background(0, 0, 0)); } } } } } } void stadt_t::check_bau_townhall(bool new_town, const building_desc_t* desc, sint16 rotation) { if (desc == NULL) { desc = hausbauer_t::get_special(has_townhall ? bev : 0, building_desc_t::townhall, welt->get_timeline_year_month(), (bev == 0) || !has_townhall, welt->get_climate(pos)); } if(desc != NULL) { grund_t* gr = welt->lookup_kartenboden(pos); gebaeude_t* gb = obj_cast(gr->first_no_way_obj()); const bool neugruendung = !has_townhall || !gb || !gb->is_townhall(); bool umziehen = !neugruendung; koord alte_str(koord::invalid); koord best_pos(pos); koord k; int old_layout = rotation; DBG_MESSAGE("check_bau_townhall()", "bev=%d, new=%d name=%s", bev, neugruendung, name.c_str()); if( umziehen ) { const building_desc_t* desc_old = gb->get_tile()->get_desc(); if (desc_old->get_level() == desc->get_level()) { DBG_MESSAGE("check_bau_townhall()", "town hall already ok."); return; // Rathaus ist schon okay } old_layout = gb->get_tile()->get_layout(); const sint8 old_z = gb->get_pos().z; koord pos_alt = best_pos = gr->get_pos().get_2d() - gb->get_tile()->get_offset(); // guess layout for broken townhall's if(desc_old->get_x() != desc_old->get_y() && desc_old->get_all_layouts()==1) { // test all layouts koord corner_offset(desc_old->get_x()-1, desc_old->get_y()-1); for(uint8 test_layout = 0; test_layout<4; test_layout++) { // is there a part of our townhall in this corner grund_t *gr0 = welt->lookup_kartenboden(pos + corner_offset); gebaeude_t const* const gb0 = gr0 ? obj_cast(gr0->first_no_way_obj()) : 0; if (gb0 && gb0->is_townhall() && gb0->get_tile()->get_desc()==desc_old && gb0->get_stadt()==this) { old_layout = test_layout; pos_alt = best_pos = gr->get_pos().get_2d() + koord(test_layout%3!=0 ? corner_offset.x : 0, test_layout&2 ? corner_offset.y : 0); break; } corner_offset = koord(-corner_offset.y, corner_offset.x); } } koord groesse_alt = desc_old->get_size(old_layout); // do we need to move if( old_layout<=desc->get_all_layouts() && desc->get_x(old_layout) <= groesse_alt.x && desc->get_y(old_layout) <= groesse_alt.y ) { // no, the size is ok // still need to check whether the existing townhall is not broken in some way umziehen = false; for(k.y = 0; k.y < groesse_alt.y; k.y ++) { for(k.x = 0; k.x < groesse_alt.x; k.x ++) { // for buildings with holes the hole could be on a different height ->gr==NULL bool ok = false; if (grund_t *gr = welt->lookup_kartenboden(k + pos)) { if(gebaeude_t *gb_part = gr->find()) { // there may be buildings with holes, so we only remove our building! if(gb_part->get_tile() == desc_old->get_tile(old_layout, k.x, k.y)) { ok = true; } } } umziehen |= !ok; } } if (!umziehen) { // correct position if new townhall is smaller than old if( old_layout == 0 ) { best_pos.y -= desc->get_y(old_layout) - groesse_alt.y; } else if (old_layout == 1) { best_pos.x -= desc->get_x(old_layout) - groesse_alt.x; } } } // Needs bounds checks for the edge case where a townhall is at the very top of the map and the townhall road is demolished // (pos - whatever) could result in negative (or invalid) map coordinates given that pos can be zero and given that zero is a valid pos in the world if (umziehen) { // we need to built a new road, thus we will use the old as a starting point (if found) if (welt->is_within_limits(townhall_road) && welt->lookup_kartenboden(townhall_road)->hat_weg(road_wt)) { alte_str = townhall_road; } else { koord k = pos + (old_layout==0 ? koord(0, desc_old->get_y()) : koord(desc_old->get_x(),0) ); if (welt->is_within_limits(k) && welt->lookup_kartenboden(k)->hat_weg(road_wt)) { alte_str = k; } else { k = pos - (old_layout==0 ? koord(0, desc_old->get_y()) : koord(desc_old->get_x(),0) ); if (welt->is_within_limits(k) && welt->lookup_kartenboden(k)->hat_weg(road_wt)) { alte_str = k; } } } } // remove old townhall if( gb ) { DBG_MESSAGE("stadt_t::check_bau_townhall()", "delete townhall at (%s)", pos_alt.get_str()); hausbauer_t::remove(NULL, gb); } // replace old space by normal houses level 0 (must be 1x1!) if( umziehen ) { for (k.x = 0; k.x < groesse_alt.x; k.x++) { for (k.y = 0; k.y < groesse_alt.y; k.y++) { // we iterate over all tiles, since the townhalls are allowed sizes bigger than 1x1 const koord pos = pos_alt + k; gr = welt->lookup_kartenboden(pos); if (gr && gr->ist_natur() && gr->kann_alle_obj_entfernen(NULL) == NULL && ( gr->get_grund_hang() == slope_t::flat || welt->lookup(koord3d(k, welt->max_hgt(k))) == NULL ) ) { DBG_MESSAGE("stadt_t::check_bau_townhall()", "fill empty spot at (%s)", pos.get_str()); build_city_building(pos); } } } } else { // make tiles flat, hausbauer_t::remove could have set some natural slopes for( k.x = 0; k.x < desc->get_x(old_layout); k.x++ ) { for( k.y = 0; k.y < desc->get_y(old_layout); k.y++ ) { gr = welt->lookup_kartenboden(best_pos + k); if( gr && gr->ist_natur() ) { // make flat and use right height gr->set_grund_hang(slope_t::flat); gr->set_pos( koord3d( best_pos + k, old_z ) ); } } } } } // Now built the new townhall (remember old orientation) sint16 layout = old_layout; if (old_layout == -1 || neugruendung) { layout = simrand(desc->get_all_layouts()); } else { layout = old_layout % desc->get_all_layouts(); } // on which side should we place the road? uint8 dir = ribi_t::layout_to_ribi[layout & 3]; if (neugruendung || umziehen) { best_pos = townhall_placefinder_t(welt, dir).find_place(pos, desc->get_x(layout) + (dir & ribi_t::eastwest ? 1 : 0), desc->get_y(layout) + (dir & ribi_t::northsouth ? 1 : 0), desc->get_allowed_climate_bits()); } // check, if the was something found if(best_pos==koord::invalid) { dbg->error( "stadt_t::check_bau_townhall", "no better position found!" ); return; } gebaeude_t const* const new_gb = hausbauer_t::build(owner, best_pos, layout, desc); DBG_MESSAGE("new townhall", "use layout=%i", layout); add_gebaeude_to_stadt(new_gb); // sets has_townhall to true DBG_MESSAGE("stadt_t::check_bau_townhall()", "add townhall (bev=%i, ptr=%p)", buildings.get_sum_weight(),welt->lookup_kartenboden(best_pos)->first_no_way_obj()); // if not during initialization koord offset(dir == ribi_t::west, dir == ribi_t::north); if (!new_town) { cbuffer_t buf; buf.printf(translator::translate("%s wasted\nyour money with a\nnew townhall\nwhen it reached\n%i inhabitants."), name.c_str(), get_einwohner()); welt->get_message()->add_message(buf, new_gb->get_pos(), message_t::city, CITY_KI, desc->get_tile(layout, 0, 0)->get_background(0, 0, 0)); } else { welt->lookup_kartenboden(best_pos + offset)->set_text( name ); } if (neugruendung || umziehen) { // offset of building within searched place, start and end of road koord road0(0,0); koord road1(0,0); koord size = desc->get_size(layout); switch (dir) { case ribi_t::east: road0.x = road1.x = size.x; road0.y = -neugruendung; road1.y = size.y - umziehen; break; case ribi_t::west: road0.x = road1.x = -1; road0.y = -neugruendung; road1.y = size.y - umziehen; break; case ribi_t::north: road0.y = road1.y = -1; road0.x = -neugruendung; road1.x = size.x - umziehen; break; case ribi_t::south: default: road0.y = road1.y = size.y; road0.x = -neugruendung; road1.x = size.x - umziehen; break; } // make them one tile shorter, if not lookup gr = welt->lookup_kartenboden(best_pos + road0); if (!gr || !slope_t::is_way(gr->get_grund_hang())) { if (dir == ribi_t::east || dir == ribi_t::west) { road0.y ++; } else { road0.x ++; } } gr = welt->lookup_kartenboden(best_pos + road1); if (!gr || !slope_t::is_way(gr->get_grund_hang())) { if (dir == ribi_t::east || dir == ribi_t::west) { road0.y --; } else { road0.x --; } } // build the road in front of the townhall if (road0!=road1 && welt->lookup_kartenboden(best_pos + road0) && welt->lookup_kartenboden(best_pos + road1)) { way_builder_t bauigel(NULL); bauigel.init_builder(way_builder_t::strasse | way_builder_t::terraform_flag, welt->get_city_road(), NULL, NULL); bauigel.set_build_sidewalk(true); bauigel.calc_straight_route(welt->lookup_kartenboden(best_pos + road0)->get_pos(), welt->lookup_kartenboden(best_pos + road1)->get_pos()); bauigel.build(); } else { build_road(best_pos + road0, NULL, true); } townhall_road = best_pos + road0; } if (umziehen && alte_str != koord::invalid) { // Strasse vom ehemaligen Rathaus zum neuen verlegen. way_builder_t bauer(NULL); bauer.init_builder(way_builder_t::strasse | way_builder_t::terraform_flag, welt->get_city_road()); bauer.calc_route(welt->lookup_kartenboden(alte_str)->get_pos(), welt->lookup_kartenboden(townhall_road)->get_pos()); bauer.build(); } else if (neugruendung) { lo = best_pos+offset - koord(2, 2); ur = best_pos+offset + koord(desc->get_x(layout), desc->get_y(layout)) + koord(2, 2); } const koord new_pos = best_pos + offset; if( pos!=new_pos ) { // update position (where the name is) welt->lookup_kartenboden(pos)->set_text( NULL ); pos = new_pos; welt->lookup_kartenboden(pos)->set_text( name ); } } } /** * eventually adds a new industry * so with growing number of inhabitants the industry grows */ void stadt_t::check_bau_factory(bool new_town) { uint32 const inc = welt->get_settings().get_industry_increase_every(); if( !new_town && inc > 0 && bev % inc == 0 ) { uint32 const div = bev / inc; for( uint8 i = 0; i < 8; i++ ) { if( div == (1u<lookup_kartenboden(k)) { if (gebaeude_t const* const gb = obj_cast(gr->first_no_way_obj())) { t = gb->get_tile()->get_desc()->get_type(); } } int i = -1; switch(t) { case building_desc_t::city_res: i = 0; break; case building_desc_t::city_com: i = 1; break; case building_desc_t::city_ind: i = 2; break; default: ; } if (i >= 0) { ind_score += ind_neighbour_score[i]; com_score += com_neighbour_score[i]; res_score += res_neighbour_score[i]; } } } } // return the eight neighbors: // orthogonal before diagonal static koord const neighbors[] = { koord( 0, 1), koord( 1, 0), koord( 0, -1), koord(-1, 0), // now the diagonals koord( 1, 1), koord( 1, -1), koord(-1, 1), koord(-1, -1) }; static koord const area3x3[] = { koord( 0, 1), // 1x2 koord( 1, 0), // 2x1 koord( 1, 1), // 2x2 koord( 2, 0), // 3x1 koord( 2, 1), // 3x2 koord( 0, 2), // 1x3 koord( 1, 2), // 2x3 koord( 2, 2) // 3x3 }; // updates one surrounding road with current city road bool update_city_street(koord pos) { // !!! We should take the bulding size into consideration, missing!!! const way_desc_t* cr = world()->get_city_road(); for( int i=0; i<8; i++ ) { if( grund_t *gr = world()->lookup_kartenboden(pos+neighbors[i]) ) { if( weg_t* const weg = gr->get_weg(road_wt) ) { // Check if any changes are needed. if( !weg->hat_gehweg() || weg->get_desc() != cr ) { player_t *sp = weg->get_owner(); if( sp ){ player_t::add_maintenance(sp, -weg->get_desc()->get_maintenance(), road_wt); weg->set_owner(NULL); // make public } weg->set_gehweg(true); weg->set_desc(cr); gr->calc_image(); minimap_t::get_instance()->calc_map_pixel(pos+neighbors[i]); return true; // update only one road per renovation } } } } return false; } // return layout #define CHECK_NEIGHBOUR (128) static int const building_layout[] = { CHECK_NEIGHBOUR | 0, 0, 1, 4, 2, 0, 5, CHECK_NEIGHBOUR | 1, 3, 7, 1, CHECK_NEIGHBOUR | 0, 6, CHECK_NEIGHBOUR | 3, CHECK_NEIGHBOUR | 2, CHECK_NEIGHBOUR | 0 }; // calculates the "best" oreintation of a citybuilding int stadt_t::orient_city_building(const koord k, const building_desc_t *h, koord maxarea ) { /******************************************************* * these are the layout possible for city buildings ******************************************************** dims=1,1,1 +---+ |000| |0 0| |000| +---+ dims=1,1,2 +---+ |001| |1 1| |100| +---+ dims=1,1,4 +---+ |221| |3 1| |300| +---+ dims=1,1,8 +---+ |625| |3 1| |704| +---+ ********************************************************/ // we have something to built here ... if( h == NULL ) { return -1; } // old, highly sophisticated routines for 1x1 buildings if( h->get_x()*h->get_y()==1 ) { if( grund_t *gr = welt->lookup_kartenboden(k) ) { int rotation = 0; int max_layout = h->get_all_layouts()-1; if( max_layout ) { // check for pavement int streetdir = 0; for( int i = 0; i < 4; i++ ) { // Neighbors goes through these in 'preferred' order, orthogonal first gr = welt->lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_weg_hang() == gr->get_grund_hang() && gr->hat_weg(road_wt) ){ streetdir += (1 << i); } } // not completely unique layout, see if any of the neighbouring building gives a hint rotation = building_layout[streetdir] & ~CHECK_NEIGHBOUR; // for four rotation stop here ... if( max_layout<7 ) { return rotation & max_layout; } // now this is an eight roation building, so we must put in more effort bool unique_orientation = !(building_layout[streetdir] & CHECK_NEIGHBOUR); if( !unique_orientation ) { // no unique answer, check nearby buildings (more likely to fail) int gb_dir = 0; for( int i = 0; i < 4; i++ ) { // look for adjacent buildings gr = welt->lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_typ()==grund_t::fundament ){ if( gr->find() ) { gb_dir |= (1<lookup_kartenboden(k) ) { int rotation = -1; int max_layout = h->get_all_layouts()-1; if( max_layout ) { // we counting the streetiles, but asymmetric buildings will have an uneven number; we init with negative width int streetdir[4]; for( int i = 0; i < 4; i++ ) { streetdir[i] = -h->get_x(i&1); } int roads_found = 0; // now just counting street tiles north/south of the house ... sint16 extra_offset = h->get_y(0)-1; for( int offset = -1; offset <= h->get_x(0); offset++ ) { gr = welt->lookup_kartenboden(k + koord(offset,1+extra_offset) ); if( gr && gr->hat_weg(road_wt) ){ streetdir[0] ++; roads_found ++; } gr = welt->lookup_kartenboden(k + koord(offset,-1) ); if( gr && gr->hat_weg(road_wt) ){ streetdir[2] ++; roads_found ++; } } // ... and east/west for( int offset = -1; offset <= h->get_x(1); offset++ ) { // Neighbors goes through these in 'preferred' order, orthogonal first gr = welt->lookup_kartenboden(k + koord(1+extra_offset,offset) ); if( gr && gr->hat_weg(road_wt) ){ streetdir[1] ++; roads_found ++; } // Neighbors goes through these in 'preferred' order, orthogonal first gr = welt->lookup_kartenboden(k + koord(-1,offset) ); if( gr && gr->hat_weg(road_wt) ){ streetdir[3] ++; roads_found ++; } } // first, make sure we found some roads if( roads_found > 0 ) { // now find the two sides with most streets around int largest_dir_count = -9999, largest_2nd_count = -9999; int largest_dir = -1, largest_2nd_dir = -1; for( int i=0; i<4; i++ ) { if( streetdir[i] > largest_dir_count ) { largest_dir_count = streetdir[i]; largest_dir = i; } else if( streetdir[i] > largest_2nd_count ) { largest_2nd_dir = i; } } // so we have two adjacent corners with the most roads if( max_layout > 3 && ((largest_2nd_dir-largest_dir)==1 || (largest_2nd_dir-largest_dir)==3) ) { // corner cases: only roads on two sides if( streetdir[0]<0 && streetdir[1]<0 ) { rotation = 6; } else if( streetdir[1]<0 && streetdir[2]<0 ) { rotation = 7; } else if( streetdir[2]<0 && streetdir[3]<0 ) { rotation = 4; } else if( streetdir[3]<0 && streetdir[0]<0 ) { rotation = 5; } // some valid found? if( rotation >=0 && h->get_x(rotation) <= maxarea.x && h->get_y(rotation) <= maxarea.y ) { return rotation; } } // now we have to check right of it if( streetdir[(largest_dir+1)&3] == largest_dir_count ) { // but since we take the first, if the next two corner have the same street count, better rotate one further if( streetdir[(largest_dir+2)&3] == largest_dir_count ) { // both next corners same count rotation = largest_dir+1; } else { rotation = largest_dir; } rotation &= max_layout; } // and left of it else if( streetdir[(largest_dir+3)&3] == largest_dir_count ) { // but since we take the first, if the next two corner have the same street count, better rotate one further if( streetdir[(largest_dir+2)&3] == largest_dir_count ) { // both next corners same count rotation = largest_dir+3; } else { rotation = largest_dir; } rotation &= max_layout; } // this is the really only longest one else { rotation = largest_dir & max_layout; } // some valid found? if( rotation >= 0 && h->get_x(rotation) <= maxarea.x && h->get_y(rotation) <= maxarea.y ) { return rotation; } return -1; } // no roads or not fitting if( roads_found == 0 ) { bool even_ok = (maxarea.x <= h->get_x(0) && maxarea.y <= h->get_y(0)); bool odd_ok = (maxarea.x <= h->get_x(1) && maxarea.y <= h->get_y(1)); if( even_ok && odd_ok ) { // no roads at all and both rotations fit => random oreintation (but no corner) return simrand(4) % max_layout; } else if( even_ok ) { return (simrand(2)*2) % max_layout; } else if( odd_ok ) { return (simrand(2)*2+1) % max_layout; } // nothing fits, should not happen! assert(1); } // we have a preferred orientation, but it does not fit => gave up return -1; } // we landed here but maxlayout == 1, so we have only to test for fit if( maxarea.x <= h->get_x(0) && maxarea.y <= h->get_y(0) ) { return 0; } } return -1; } void stadt_t::build_city_building(const koord k) { grund_t* gr = welt->lookup_kartenboden(k); // Not building on ways (this was actually tested before be the cityrules), but you can construct manually if( !gr->ist_natur() ) { return; } // test ownership of all objects that can block construction for( uint8 i = 0; i < gr->obj_count(); i++ ) { obj_t *const obj = gr->obj_bei(i); if( obj->get_removal_error(NULL) != NULL && obj->get_typ() != obj_t::pillar ) { return; } } // Refuse to build on a slope, when there is a ground right on top of it (=> the house would sit on the bridge then!) if( gr->get_grund_hang() != slope_t::flat && welt->lookup(koord3d(k, welt->max_hgt(k))) != NULL ) { return; } // Divide unemployed by 4, because it counts towards commercial and industrial, // and both of those count 'double' for population relative to residential. int employment_wanted = get_unemployed() / 4; int housing_wanted = get_homeless(); int industrial_suitability, commercial_suitability, residential_suitability; bewerte_res_com_ind(k, industrial_suitability, commercial_suitability, residential_suitability ); const int sum_industrial = industrial_suitability + employment_wanted; const int sum_commercial = commercial_suitability + employment_wanted; const int sum_residential = residential_suitability + housing_wanted; // does the timeline allow this building? const uint16 current_month = welt->get_timeline_year_month(); const climate cl = welt->get_climate(k); // Run through orthogonal neighbors (only) looking for which cluster to build // This is a bitmap -- up to 32 clustering types are allowed. uint32 neighbor_building_clusters = 0; uint8 area_level=0; // used to calculate the maximum size sint8 zpos = gr->get_pos().z + slope_t::max_diff(gr->get_grund_hang()); for( int i = 0; i < 4; i++ ) { grund_t* gr = welt->lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_typ() == grund_t::fundament && gr->obj_bei(0)->get_typ() == obj_t::gebaeude ) { // We have a building as a neighbor... if( gebaeude_t const* const gb = obj_cast(gr->first_no_way_obj()) ) { // We really have a building as a neighbor... const building_desc_t* neighbor_building = gb->get_tile()->get_desc(); neighbor_building_clusters |= neighbor_building->get_clusters(); if( gb->get_pos().z == zpos && neighbor_building->get_x()*neighbor_building->get_y()==1 ) { // also in right height and citybuilding, and (1x1) (so we don not tear down existing larger building, even if we can do that) area_level |= (neighbor_building->is_city_building() << i); } } else if( gr->ist_natur() && gr->get_pos().z+slope_t::max_diff(gr->get_grund_hang())==zpos ) { // we can of course also build on nature area_level |= (1 << i); } } } // since the above test is only enough for 2x1 and 1x2, we must test more tiles, if we want larger koord maxsize=koord(1,1); switch( area_level&3 ) { case 3: if( hausbauer_t::get_largest_city_building_area() > 2 ) { // now test the remaining tiles for even laregr size for( area_level=2; area_level < lengthof(area3x3); area_level++ ) { grund_t* gr = welt->lookup_kartenboden(k + area3x3[area_level]); if( gr && gr->get_typ() == grund_t::fundament && gr->obj_bei(0)->get_typ() == obj_t::gebaeude ) { // We have a building as a neighbor... if( gebaeude_t const* const testgb = obj_cast(gr->first_no_way_obj()) ) { // We really have a building as a neighbor... const building_desc_t* neighbor_building = testgb->get_tile()->get_desc(); if( testgb->get_pos().z == zpos && neighbor_building->is_city_building() && neighbor_building->get_x()*neighbor_building->get_y()==1 ) { // also in right height and citybuilding maxsize = area3x3[area_level]+koord(1,1); continue; } } else if( gr->ist_natur() && gr->get_pos().z+slope_t::max_diff(gr->get_grund_hang())==zpos ) { // we can of course also build on nature maxsize = area3x3[area_level]+koord(1,1); continue; } } // we only reach here upon unsuitable ground break; } } break; case 2: maxsize = area3x3[1]+koord(1,1); break; case 1: maxsize = area3x3[0]+koord(1,1); break; default: break; } // Find a house to build const building_desc_t* h = NULL; if (sum_commercial > sum_industrial && sum_commercial >= sum_residential) { h = hausbauer_t::get_commercial(0, current_month, cl, neighbor_building_clusters, koord(1,1), maxsize); if (h != NULL) { arb += (h->get_level()+1) * 20; } } if (h == NULL && sum_industrial > sum_residential && sum_industrial >= sum_commercial) { h = hausbauer_t::get_industrial(0, current_month, cl, neighbor_building_clusters, koord(1,1), maxsize); if (h != NULL) { arb += (h->get_level()+1) * 20; } } if (h == NULL && sum_residential > sum_industrial && sum_residential >= sum_commercial) { h = hausbauer_t::get_residential(0, current_month, cl, neighbor_building_clusters, koord(1,1), maxsize); if (h != NULL) { // will be aligned next to a street won += (h->get_level()+1) * 10; } } // so we found at least one suitable building for this place int rotation = orient_city_building( k, h, maxsize ); if( rotation >= 0 ) { const gebaeude_t* gb = hausbauer_t::build(NULL, k, rotation, h); add_gebaeude_to_stadt(gb); } // to be extended for larger building ... update_city_street(k); } void stadt_t::renovate_city_building(gebaeude_t *gb) { const building_desc_t::btype alt_typ = gb->get_tile()->get_desc()->get_type(); if( !gb->is_city_building() ) { return; // only renovate res, com, ind } // Now we are sure that this is a city building const building_desc_t *gb_desc = gb->get_tile()->get_desc(); const int level = gb_desc->get_level(); if( welt->get_timeline_year_month() > gb_desc->no_renovation_month() ) { // this is a historic city building (as defined by the pak set author), so do not renovate return; } koord k = gb->get_pos().get_2d() - gb->get_tile()->get_offset(); // Divide unemployed by 4, because it counts towards commercial and industrial, // and both of those count 'double' for population relative to residential. const int employment_wanted = get_unemployed() / 4; const int housing_wanted = get_homeless() / 4; int industrial_suitability, commercial_suitability, residential_suitability; bewerte_res_com_ind(k, industrial_suitability, commercial_suitability, residential_suitability ); const int sum_industrial = industrial_suitability + employment_wanted; const int sum_commercial = commercial_suitability + employment_wanted; const int sum_residential = residential_suitability + housing_wanted; // does the timeline allow this building? const uint16 current_month = welt->get_timeline_year_month(); const climate cl = welt->get_climate( gb->get_pos().get_2d() ); // Run through orthogonal neighbors (only), and oneself looking for which cluster to build // This is a bitmap -- up to 32 clustering types are allowed. uint32 neighbor_building_clusters = gb->get_tile()->get_desc()->get_clusters(); sint8 zpos = gb->get_pos().z; koord minsize = gb->get_tile()->get_desc()->get_size(gb->get_tile()->get_layout()); // since we handle buildings larger than (1x1) we test all periphery koord lu = k - koord( 1, 1 ); koord rd = k + minsize; for( sint16 x = lu.x; x<=rd.x; x++ ) { for( sint16 y = lu.y; y<=rd.y; y++ ) { if( koord(x,y)!=k ) { if( grund_t *gr = welt->lookup_kartenboden(x,y) ) { if( gebaeude_t const* const testgb = gr->find() ) { if( testgb->get_tile()->get_desc() != gb->get_tile()->get_desc() && testgb->is_city_building() ) { // We really have a different building as a neighbor... const building_desc_t* neighbor_building = testgb->get_tile()->get_desc(); neighbor_building_clusters |= neighbor_building->get_clusters(); } } } } } } // now test the surrounding tiles for larger size koord maxsize=minsize; if( hausbauer_t::get_largest_city_building_area() > 1 ) { for( uint area_level=0; area_level < lengthof(area3x3); area_level++ ) { grund_t* gr = welt->lookup_kartenboden(k + area3x3[area_level]); if( gr && gr->get_typ() == grund_t::fundament && gr->obj_bei(0)->get_typ() == obj_t::gebaeude ) { // We have a building as a neighbor... if( gebaeude_t const* const testgb = obj_cast(gr->first_no_way_obj()) ) { // We really have a building here const building_desc_t* neighbor_building = testgb->get_tile()->get_desc(); if( neighbor_building->is_city_building() ) { if( gb->get_tile()->get_desc() == neighbor_building && testgb->get_tile()->get_offset() == area3x3[area_level] ) { // part of same building maxsize = area3x3[ area_level ] + koord( 1, 1 ); continue; } if( testgb->get_pos().z == zpos && neighbor_building->get_x()*neighbor_building->get_y() == 1 ) { // also in right height and citybuilding maxsize = area3x3[ area_level ] + koord( 1, 1 ); continue; } } } #if 0 /* since we only replace tiles, natur is not allowed for the moment, but could be easily changed */ else if( gr->ist_natur() && gr->get_pos().z+slope_t::max_diff(gr->get_grund_hang())==zpos ) { // we can of course also build on nature maxsize = area3x3[area_level]+koord(1,1); continue; } #endif } // we only reach here upon unsuitable ground break; } } building_desc_t::btype want_to_have = building_desc_t::unknown; int sum = 0; // try to build const building_desc_t* h = NULL; if (sum_commercial > sum_industrial && sum_commercial > sum_residential) { // we must check, if we can really update to higher level ... const int try_level = (alt_typ == building_desc_t::city_com ? level + 1 : level); h = hausbauer_t::get_commercial(try_level, current_month, cl, neighbor_building_clusters, minsize, maxsize ); if( h != NULL && h->get_level() >= try_level ) { want_to_have = building_desc_t::city_com; sum = sum_commercial; } } // check for industry, also if we wanted com, but there was no com good enough ... if( (sum_industrial > sum_commercial && sum_industrial > sum_residential) || (sum_commercial > sum_residential && want_to_have == building_desc_t::unknown) ) { // we must check, if we can really update to higher level ... const int try_level = (alt_typ == building_desc_t::city_ind ? level + 1 : level); h = hausbauer_t::get_industrial(try_level , current_month, cl, neighbor_building_clusters, minsize, maxsize ); if( h != NULL && h->get_level() >= try_level ) { want_to_have = building_desc_t::city_ind; sum = sum_industrial; } } // check for residence // (sum_wohnung>sum_industrie && sum_wohnung>sum_gewerbe if( want_to_have == building_desc_t::unknown ) { // we must check, if we can really update to higher level ... const int try_level = (alt_typ == building_desc_t::city_res ? level + 1 : level); h = hausbauer_t::get_residential(try_level, current_month, cl, neighbor_building_clusters, minsize, maxsize ); if( h != NULL && h->get_level() >= try_level ) { want_to_have = building_desc_t::city_res; sum = sum_residential; } else { h = NULL; } } if (alt_typ != want_to_have) { sum -= level * 10; } // good enough to renovate, and we found a building? if( sum > 0 && h != NULL ) { // DBG_MESSAGE("stadt_t::renovate_city_building()", "renovation at %i,%i (%i level) of typ %i to typ %i with desire %i", k.x, k.y, alt_typ, want_to_have, sum); // no renovation for now, if new is smaller assert( gb_desc->get_x()*gb_desc->get_y() <= h->get_x()*h->get_y() ); int rotation = 0; if( h->get_all_layouts()>1 ) { // only do this of symmetric of small enough building if( h->get_x()==h->get_y() || (h->get_x()get_x()lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_weg_hang() == gr->get_grund_hang() && gr->hat_weg(road_wt) ){ streetdir += (1 << i); } } // not completely unique layout, see if any of the neighbouring building gives a hint rotation = building_layout[streetdir] & ~CHECK_NEIGHBOUR; bool unique_orientation = !(building_layout[streetdir] & CHECK_NEIGHBOUR); // only streets in diagonal corners => make a house there in L direction if( !streetdir ) { int count = 0; for( int i = 4; i < 8; i++ ) { // Neighbors goes through these in 'preferred' order, orthogonal first grund_t *gr = welt->lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_weg_hang() == gr->get_grund_hang() && gr->hat_weg(road_wt) ) { rotation = i; count ++; } } unique_orientation = (count==1); } if( !unique_orientation ) { int max_layout = h->get_all_layouts()-1; for( int i = 0; i < 4; i++ ) { // Neighbors goes through these in 'preferred' order, orthogonal first grund_t *gr = welt->lookup_kartenboden(k + neighbors[i]); if( gr && gr->get_typ()==grund_t::fundament ){ if( gebaeude_t *gb = gr->find() ) { if( gb->get_tile()->get_desc()->get_all_layouts() > max_layout ) { // so take the roation of the next bilding with similar or more rotations rotation = gb->get_tile()->get_layout(); max_layout = gb->get_tile()->get_desc()->get_all_layouts(); if( h->get_clusters() == 0 && gb->get_tile()->get_desc() == h ) { // we only renovate, if there is not an identical building (unless its a cluster) return; } } } } } } } else { // asymmetric building rotation = (h->get_x(0)<=maxsize.x && h->get_y(0)<=maxsize.y) ? 0 : 1; } } // we only renovate, if there is not an identical building (unless its a cluster) if( !h->get_clusters() ) { for( int i = 0; i < 8; i++ ) { koord p = k; p.x += neighbors[i].x > 0 ? h->get_x( rotation ) : neighbors[i].x; p.y += neighbors[i].y > 0 ? h->get_y( rotation ) : neighbors[i].y; grund_t *gr = welt->lookup_kartenboden(p); if( gr && gr->get_typ() == grund_t::fundament ) { if( gebaeude_t *gb = gr->find() ) { if( gb->get_tile()->get_desc() == h ) { // same building => do not renovate return; } } } } } // ok now finally replace for( int x=0; xget_x(rotation); x++ ) { for( int y=0; yget_y(rotation); y++ ) { koord kpos = k+koord(x,y); grund_t *gr = welt->lookup_kartenboden(kpos); gebaeude_t *oldgb = gr->find(); switch(oldgb->get_tile()->get_desc()->get_type()) { case building_desc_t::city_res: won -= level * 10; break; case building_desc_t::city_com: arb -= level * 20; break; case building_desc_t::city_ind: arb -= level * 20; break; default: break; } // exchange building; try to face it to street in front oldgb->mark_images_dirty(); oldgb->set_tile( h->get_tile(rotation, x, y), true ); welt->lookup_kartenboden(kpos)->calc_image(); update_gebaeude_from_stadt(oldgb); update_city_street(kpos); switch(h->get_type()) { case building_desc_t::city_res: won += h->get_level() * 10; break; case building_desc_t::city_com: arb += h->get_level() * 20; break; case building_desc_t::city_ind: arb += h->get_level() * 20; break; default: break; } } } } } #ifdef DESTINATION_CITYCARS void stadt_t::generate_private_cars(koord pos, koord target) { if (!private_car_t::list_empty() && number_of_cars>0 ) { koord k; for (k.y = pos.y - 1; k.y <= pos.y + 1; k.y++) { for (k.x = pos.x - 1; k.x <= pos.x + 1; k.x++) { if( grund_t* gr = welt->lookup_kartenboden(k) ) { const weg_t* weg = gr->get_weg(road_wt); if (weg != NULL && ( weg->get_ribi_unmasked(road_wt) == ribi_t::northsouth || weg->get_ribi_unmasked(road_wt) == ribi_t::eastwest) && player_t::check_owner(NULL,w->get_owner() ) { // already a car here => avoid congestion if(gr->obj_bei(gr->get_top()-1)->is_moving()) { continue; } private_car_t* vt = new private_car_t(gr, target); gr->obj_add(vt); city_history_month[0][HIST_CITYCARS] ++; city_history_year[0][HIST_CITYCARS] ++; number_of_cars --; return; } } } } } } #endif /** * baut ein Stueck Strasse * @param k Bauposition */ bool stadt_t::build_road(const koord k, player_t* player_, bool forced) { grund_t* bd = welt->lookup_kartenboden(k); if (bd->get_typ() != grund_t::boden) { // not on water, monorails, foundations, tunnel or bridges return false; } // we must not built on water or runways etc. if( bd->hat_wege() && !bd->hat_weg(road_wt) && !bd->hat_weg(track_wt) ) { return false; } // somebody else's things on it? if( bd->kann_alle_obj_entfernen(NULL) ) { return false; } // If not able to build here, try to make artificial slope slope_t::type slope = bd->get_grund_hang(); if (!slope_t::is_way(slope)) { climate c = welt->get_climate(k); if (welt->can_flatten_tile(NULL, k, bd->get_hoehe()+1, true)) { welt->flatten_tile(NULL, k, bd->get_hoehe()+1, true); } else if( bd->get_hoehe() > welt->get_water_hgt(k) && welt->can_flatten_tile(NULL, k, bd->get_hoehe() ) ) { welt->flatten_tile(NULL, k, bd->get_hoehe()); } else { return false; } // kartenboden may have changed - also ensure is land bd = welt->lookup_kartenboden(k); if (bd->get_typ() == grund_t::wasser) { welt->set_water_hgt_nocheck(k, bd->get_hoehe()-1); welt->access(k)->correct_water(); welt->set_climate(k, c, true); bd = welt->lookup_kartenboden(k); } } // initially allow all possible directions ... ribi_t::ribi allowed_dir = (bd->get_grund_hang() != slope_t::flat ? ribi_t::doubles(ribi_type(bd->get_weg_hang())) : (ribi_t::ribi)ribi_t::all); // we have here a road: check for four corner stops const gebaeude_t* gb = bd->find(); if(gb) { // nothing to connect if(gb->get_tile()->get_desc()->get_all_layouts()==4) { // single way allowed_dir = ribi_t::layout_to_ribi[gb->get_tile()->get_layout()]; } else if(gb->get_tile()->get_desc()->get_all_layouts()) { // through way allowed_dir = ribi_t::doubles( ribi_t::layout_to_ribi[gb->get_tile()->get_layout() & 1] ); } else { dbg->error("stadt_t::build_road()", "building on road with not directions at %i,%i?!?", k.x, k.y ); } } // we must not built on water or runways etc. // only crossing or tramways allowed if( bd->hat_weg(track_wt) ) { weg_t* sch = bd->get_weg(track_wt); if (sch->get_desc()->get_styp() != type_tram) { // not a tramway ribi_t::ribi r = sch->get_ribi_unmasked(); if (!ribi_t::is_straight(r)) { // no building on crossings, curves, dead ends return false; } // just the other directions are allowed allowed_dir &= ~r; } } // determine now, in which directions we can connect to another road ribi_t::ribi connection_roads = ribi_t::none; // add ribi's to connection_roads if possible for (int r = 0; r < 4; r++) { if (ribi_t::nesw[r] & allowed_dir) { // now we have to check for several problems ... grund_t* bd2; if(bd->get_neighbour(bd2, invalid_wt, ribi_t::nesw[r])) { if(bd2->get_typ()==grund_t::fundament || bd2->get_typ()==grund_t::wasser) { // not connecting to a building of course ... } else if (!bd2->ist_karten_boden()) { // do not connect to elevated ways / bridges } else if (bd2->get_typ()==grund_t::tunnelboden && ribi_t::nesw[r]!=ribi_type(bd2->get_grund_hang())) { // not the correct slope } else if (bd2->get_typ()==grund_t::brueckenboden && (bd2->get_grund_hang()==slope_t::flat ? ribi_t::nesw[r]!=ribi_type(bd2->get_weg_hang()) : ribi_t::backward(ribi_t::nesw[r])!=ribi_type(bd2->get_grund_hang()))) { // not the correct slope } else if(bd2->hat_weg(road_wt)) { const gebaeude_t* gb = bd2->find(); if(gb) { uint8 layouts = gb->get_tile()->get_desc()->get_all_layouts(); // nothing to connect if(layouts==4) { // single way if(ribi_t::nesw[r]==ribi_t::backward(ribi_t::layout_to_ribi[gb->get_tile()->get_layout()])) { // allowed ... connection_roads |= ribi_t::nesw[r]; } } else if(layouts==2 || layouts==8 || layouts==16) { // through way if((ribi_t::doubles( ribi_t::layout_to_ribi[gb->get_tile()->get_layout() & 1] )&ribi_t::nesw[r])!=0) { // allowed ... connection_roads |= ribi_t::nesw[r]; } } else { dbg->error("stadt_t::build_road()", "building on road with not directions at %i,%i?!?", k.x, k.y ); } } else if(bd2->get_depot()) { // do not enter depots } else { // check slopes way_builder_t bauer( NULL ); bauer.init_builder( way_builder_t::strasse | way_builder_t::terraform_flag, welt->get_city_road() ); if( bauer.check_slope( bd, bd2 ) ) { // allowed ... connection_roads |= ribi_t::nesw[r]; } } } } } } // now add the ribis to the other ways (if there) for (int r = 0; r < 4; r++) { if (ribi_t::nesw[r] & connection_roads) { grund_t* bd2 = welt->lookup_kartenboden(k + koord::nesw[r]); weg_t* w2 = bd2->get_weg(road_wt); w2->ribi_add(ribi_t::backward(ribi_t::nesw[r])); bd2->calc_image(); bd2->set_flag( grund_t::dirty ); } } if (connection_roads != ribi_t::none || forced) { if (!bd->weg_erweitern(road_wt, connection_roads)) { strasse_t* weg = new strasse_t(); // city roads should not belong to any player => so we can ignore any construction costs ... weg->set_desc(welt->get_city_road()); weg->set_gehweg(true); bd->neuen_weg_bauen(weg, connection_roads, player_); bd->calc_image(); // otherwise the } // check to bridge a river if(ribi_t::is_single(connection_roads) && !bd->has_two_ways() ) { koord zv = koord(ribi_t::backward(connection_roads)); grund_t *bd_next = welt->lookup_kartenboden( k + zv ); if(bd_next && (bd_next->is_water() || (bd_next->hat_weg(water_wt) && bd_next->get_weg(water_wt)->get_desc()->get_styp()== type_river))) { // ok there is a river const bridge_desc_t *bridge = bridge_builder_t::find_bridge(road_wt, welt->get_city_road()->get_topspeed(), welt->get_timeline_year_month() ); if( bridge==NULL ) { // does not have a bridge available ... return false; } const char *err = NULL; sint8 bridge_height; koord3d end = bridge_builder_t::find_end_pos(NULL, bd->get_pos(), zv, bridge, err, bridge_height, false); if(err || koord_distance( k, end.get_2d())>3) { // try to find shortest possible end = bridge_builder_t::find_end_pos(NULL, bd->get_pos(), zv, bridge, err, bridge_height, true); } // if the river is nagigable, we need a two hight slope, so we have to start on a flat tile if( err && *err!=0 && strcmp(err,"Bridge is too long for this type!\n")!=0 && bd->get_weg_hang()!=slope_t::flat ) { slope_t::type old_slope = bd->get_grund_hang(); sint8 h_diff = slope_t::max_diff( old_slope ); // raise up the tile bd->set_grund_hang( slope_t::flat ); bd->set_hoehe( bd->get_hoehe() + h_diff ); // transfer objects to on new grund for( int i=0; iobj_count(); i++ ) { bd->obj_bei(i)->set_pos( bd->get_pos() ); } end = bridge_builder_t::find_end_pos(NULL, bd->get_pos(), zv, bridge, err, bridge_height, false); if(err || koord_distance( k, end.get_2d())>3) { // try to find shortest possible end = bridge_builder_t::find_end_pos(NULL, bd->get_pos(), zv, bridge, err, bridge_height, true); } // not successful: restore old slope if( (err && *err != 0) || end==koord3d::invalid || koord_distance( k, end.get_2d())>5 ) { bd->set_grund_hang( old_slope ); bd->set_hoehe( bd->get_hoehe() - h_diff ); // transfer objects to on new grund for( int i=0; iobj_count(); i++ ) { bd->obj_bei(i)->set_pos( bd->get_pos() ); } } else { // update slope graphics on tile and tile in front if( grund_t *bd_recalc = welt->lookup_kartenboden( k + koord( 0, 1 ) ) ) { bd_recalc->check_update_underground(); } if( grund_t *bd_recalc = welt->lookup_kartenboden( k + koord( 1, 0 ) ) ) { bd_recalc->check_update_underground(); } if( grund_t *bd_recalc = welt->lookup_kartenboden( k + koord( 1, 1 ) ) ) { bd_recalc->check_update_underground(); } bd->mark_image_dirty(); } } if((err==NULL||*err == 0) && koord_distance( k, end.get_2d())<=5 && welt->is_within_limits((end+zv).get_2d())) { bridge_builder_t::build_bridge(NULL, bd->get_pos(), end, zv, bridge_height, bridge, welt->get_city_road()); // try to build one connecting piece of road build_road( (end+zv).get_2d(), NULL, false); // try to build a house near the bridge end uint32 old_count = buildings.get_count(); for(uint8 i=0; iis_within_limits(c)) { build_city_building(end.get_2d()+zv+koord::neighbours[i]); } } } } } return true; } return false; } // will check a single random pos in the city, then build will be called void stadt_t::build() { const koord k(lo + koord::koord_random(ur.x - lo.x + 2,ur.y - lo.y + 2)-koord(1,1) ); // do not build on any border tile if( !welt->is_within_limits(k+koord(1,1)) || k.x<=0 || k.y<=0 ) { return; } grund_t *gr = welt->lookup_kartenboden(k); if(gr==NULL) { return; } // checks only make sense on empty ground if(gr->ist_natur()) { // since only a single location is checked, we can stop after we have found a positive rule best_strasse.reset(k); const uint32 num_road_rules = road_rules.get_count(); uint32 offset = simrand(num_road_rules); // start with random rule for (uint32 i = 0; i < num_road_rules && !best_strasse.found(); i++) { uint32 rule = ( i+offset ) % num_road_rules; bewerte_strasse(k, 8 + road_rules[rule]->chance, *road_rules[rule]); } // ok => then built road if (best_strasse.found()) { build_road(best_strasse.get_pos(), NULL, false); INT_CHECK("simcity 1156"); return; } // not good for road => test for house // since only a single location is checked, we can stop after we have found a positive rule best_haus.reset(k); const uint32 num_house_rules = house_rules.get_count(); offset = simrand(num_house_rules); // start with random rule for( uint32 i = 0; i < num_house_rules && !best_haus.found(); i++ ) { uint32 rule = ( i+offset ) % num_house_rules; bewerte_haus(k, 8 + house_rules[rule]->chance, *house_rules[rule]); } // one rule applied? if( best_haus.found() ) { build_city_building(best_haus.get_pos()); INT_CHECK("simcity 1163"); return; } } // renovation (only done when nothing matches a certain location if( !buildings.empty() && simrand(100) <= renovation_percentage ) { // try to find a public owned building for( uint8 i=0; i<4; i++ ) { gebaeude_t* const gb = pick_any(buildings); if( player_t::check_owner(gb->get_owner(),NULL) ) { renovate_city_building(gb); break; } } INT_CHECK("simcity 876"); } } // find suitable places for cities vector_tpl* stadt_t::random_place(const sint32 count, sint16 old_x, sint16 old_y) { int cl = 0; for (int i = 0; i < MAX_CLIMATES; i++) { if (hausbauer_t::get_special(0, building_desc_t::townhall, welt->get_timeline_year_month(), false, (climate)i)) { cl |= (1 << i); } } DBG_DEBUG("karte_t::init()", "get random places in climates %x", cl); // search at least places which are 5x5 squares large slist_tpl* list = welt->find_squares( 5, 5, (climate_bits)cl, old_x, old_y); DBG_DEBUG("karte_t::init()", "found %i places", list->get_count()); vector_tpl* result = new vector_tpl(count); // pre processed array: max 1 city from each square can be built // each entry represents a cell of minimum_city_distance/2 length and width const uint32 minimum_city_distance = welt->get_settings().get_minimum_city_distance(); const uint32 xmax = (2*welt->get_size().x)/minimum_city_distance+1; const uint32 ymax = (2*welt->get_size().y)/minimum_city_distance+1; array2d_tpl< vector_tpl > places(xmax, ymax); while (!list->empty()) { const koord k = list->remove_first(); places.at( (2*k.x)/minimum_city_distance, (2*k.y)/minimum_city_distance).append(k); } // weighted index vector into places array weighted_vector_tpl index_to_places(xmax*ymax); for(uint32 i=0; i const& p = places.at(i, j); if (!p.empty()) { index_to_places.append(koord(i,j), p.get_count()); } } } // post-processing array: // each entry represents a cell of minimum_city_distance length and width // to limit the search for neighboring cities const uint32 xmax2 = welt->get_size().x/minimum_city_distance+1; const uint32 ymax2 = welt->get_size().y/minimum_city_distance+1; array2d_tpl< vector_tpl > result_places(xmax2, ymax2); for (int i = 0; i < count; i++) { // check distances of all cities to their respective neighbours while (!index_to_places.empty()) { // find a random cell koord const ip = pick_any_weighted(index_to_places); // remove this cell from index list index_to_places.remove(ip); vector_tpl& p = places.at(ip); // get random place in the cell if (p.empty()) continue; uint32 const j = simrand(p.get_count()); koord const k = p[j]; const koord k2mcd = koord( k.x/minimum_city_distance, k.y/minimum_city_distance ); for (sint32 i = k2mcd.x - 1; i <= k2mcd.x + 1; ++i) { for (sint32 j = k2mcd.y - 1; j <= k2mcd.y + 1; ++j) { if (i>=0 && i<(sint32)xmax2 && j>=0 && j<(sint32)ymax2) { for(koord const& l : result_places.at(i, j)) { if (koord_distance(k, l) < minimum_city_distance) { goto too_close; } } } } } // all cities are far enough => ok, find next place result->append(k); result_places.at(k2mcd).append(k); break; too_close: // remove the place from the list p.remove_at(j); // re-insert in index list with new weight if (!p.empty()) { index_to_places.append(ip, p.get_count()); } // if we reached here, the city was not far enough => try again } if (index_to_places.empty() && i < count - 1) { dbg->warning("stadt_t::random_place()", "Not enough places found!"); break; } } delete list; return result; } simutrans-124.3/src/simutrans/world/simcity.h000066400000000000000000000437451474050137200213650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_SIMCITY_H #define WORLD_SIMCITY_H #include "../obj/simobj.h" #include "../obj/gebaeude.h" #include "../tpl/vector_tpl.h" #include "../tpl/weighted_vector_tpl.h" #include "../tpl/sparse_tpl.h" #include "../utils/plainstring.h" #include class building_desc_t; class karte_ptr_t; class player_t; class rule_t; #define MAX_CITY_HISTORY_YEARS (12) // number of years to keep history #define MAX_CITY_HISTORY_MONTHS (12) // number of months to keep history #define PAX_DESTINATIONS_SIZE (256) // size of the minimap (sparse array) enum city_cost { HIST_CITIZENS = 0, // total people HIST_GROWTH, // growth (just for convenience) HIST_BUILDING, // number of buildings HIST_CITYCARS, // number of citycars generated HIST_PAS_TRANSPORTED, // number of passengers who could start their journey HIST_PAS_WALKED, // direct transfer HIST_PAS_GENERATED, // total number generated HIST_MAIL_TRANSPORTED, // letters that could be sent HIST_MAIL_WALKED, // direct handover HIST_MAIL_GENERATED, // all letters generated HIST_GOODS_RECEIVED, // times all storages were not empty HIST_GOODS_NEEDED, // times storages checked HIST_POWER_RECEIVED, // power consumption (not used at the moment!) MAX_CITY_HISTORY // Total number of items in array }; // The base offset for passenger statistics. static const uint32 HIST_BASE_PASS = HIST_PAS_TRANSPORTED; // The base offset for mail statistics. static const uint32 HIST_BASE_MAIL = HIST_MAIL_TRANSPORTED; // The offset for transported statistic for passengers and mail. static const uint32 HIST_OFFSET_TRANSPORTED = 0; // The offset for walked statistic for passengers and mail. static const uint32 HIST_OFFSET_WALKED = 1; // The offset for generated statistic for passengers and mail. static const uint32 HIST_OFFSET_GENERATED = 2; // The number of growth factors kept track of. static const uint32 GROWTH_FACTOR_NUMBER = 3; // Mail return multiplier used by mail producers (attractions and factories). static const uint32 MAIL_RETURN_MULTIPLIER_PRODUCERS = 3; // Passenger generation ratio. This many parts to mail generation ratio parts. static const uint32 GENERATE_RATIO_PASS = 3; // Mail generation ratio. This many parts to passenger generation ratio parts. static const uint32 GENERATE_RATIO_MAIL = 1; /** * Die Objecte der Klasse stadt_t bilden die Staedte in Simu. Sie * wachsen automatisch. */ class stadt_t { /** * Kleine Hilfsklasse - speichert die beste Bewertung einer Position. */ class best_t { sint32 best_wert; koord best_pos; public: void reset(koord pos) { best_wert = 0; best_pos = pos; } void check(koord pos, sint32 wert) { if(wert > best_wert) { best_wert = wert; best_pos = pos; } } bool found() const { return best_wert > 0; } koord get_pos() const { return best_pos;} // sint32 get_wert() const { return best_wert; } }; public: /** * Reads city configuration data from config/cityrules.tab */ static bool cityrules_init(); /** * Reads/writes city configuration data from/to a savegame * called from settings_t::rdwr * only written for networkgames */ static void cityrules_rdwr(loadsave_t *file); static uint32 get_industry_increase(); static void set_industry_increase(uint32 ind_increase); static uint32 get_minimum_city_distance(); static void set_minimum_city_distance(uint32 s); static void set_cluster_factor( uint32 factor ) { stadt_t::cluster_factor = factor; } static uint32 get_cluster_factor() { return stadt_t::cluster_factor; } private: static karte_ptr_t welt; player_t *owner; plainstring name; weighted_vector_tpl buildings; sparse_tpl pax_destinations_old; sparse_tpl pax_destinations_new; // this counter will increment by one for every change => dialogs can question, if they need to update map uint32 pax_destinations_new_change; koord pos; // Gruendungsplanquadrat der City koord townhall_road; // road in front of townhall koord lo, ur; // max size of housing area koord last_center; bool has_low_density; // in this case extend borders by two bool allow_citygrowth; // town can be static and will grow (true by default) bool has_townhall; // this counter indicate which building will be processed next uint32 step_count; /** * step so every house is asked once per month * i.e. 262144/(number of houses) per step */ uint32 step_interval; /** * next passenger generation timer */ uint32 next_step; /** * in this fixed interval, construction will happen */ static const uint32 city_growth_step; /** * When to do growth next */ uint32 next_growth_step; static uint32 cluster_factor; // attribute for the population (Bevoelkerung) sint32 bev; // total population (bevoelkerung) sint32 arb; // with a job (arbeit) sint32 won; // with a residence (wohnung) /** * Un-supplied city growth needs * A value of 2^32 means 1 new resident */ sint64 unsupplied_city_growth; /** * City history * Current month stats are not appropiate to determine satisfaction for growth. */ sint64 city_history_year[MAX_CITY_HISTORY_YEARS][MAX_CITY_HISTORY]; sint64 city_history_month[MAX_CITY_HISTORY_MONTHS][MAX_CITY_HISTORY]; /* updates the city history */ void roll_history(); /* Members used to determine satisfaction for growth rate. * Satisfaction of this month cannot be used as it is an averaging filter for the entire month up to the present. * Instead the average over a number of growth ticks is used, defaulting to last month average if nothing is available. */ private: // The growth factor type in form of the amount demanded and what was received. struct city_growth_factor_t { // The wanted value. sint64 demand; // The received value. sint64 supplied; city_growth_factor_t() : demand(0), supplied(0){} }; // The previous values of the growth factors. Used to get delta between ticks and must be saved for determinism. city_growth_factor_t city_growth_factor_previous[GROWTH_FACTOR_NUMBER]; /* Method to generate comparable growth factor data. * This allows one to alter the logic which computes growth. * @param factors factor array. * @param month the month which is to be used for the growth factors. */ void city_growth_get_factors(city_growth_factor_t (&factors)[GROWTH_FACTOR_NUMBER], uint32 const month) const; /* Method to compute base growth using growth factors. * Logs differences in growth factors as well. * rprec : The returned fractional precision (out of sint32). * cprec : The computation fractional precision (out of sint32). */ sint32 city_growth_base(uint32 const rprec = 6, uint32 const cprec = 16); /* Method to roll previous growth factors at end of month, called before history rolls over. * Needed to prevent loss of data (not set to 0) and while keeping reasonable (no insane values). * month : The month index of what is now the "last month". */ void city_growth_monthly(uint32 const month); public: /** * Returns pointer to history for city */ sint64* get_city_history_year() { return *city_history_year; } sint64* get_city_history_month() { return *city_history_month; } const sint64* get_city_history_year() const { return *city_history_year; } const sint64* get_city_history_month() const { return *city_history_month; } uint32 stadtinfo_options; /* end of history related things */ private: sint32 best_haus_wert; sint32 best_strasse_wert; best_t best_haus; best_t best_strasse; public: /** * Classes for storing and manipulating target factories and their data */ struct factory_entry_t { union { fabrik_t *factory; struct { sint16 factory_pos_x; sint16 factory_pos_y; }; }; sint32 demand; // amount demanded by the factory; shifted by DEMAND_BITS sint32 supply; // amount that the city can supply sint32 remaining; // portion of supply which has not realised yet; remaining <= supply factory_entry_t() : factory(NULL), demand(0), supply(0), remaining(0) { } factory_entry_t(fabrik_t *_factory) : factory(_factory), demand(0), supply(0), remaining(0) { } factory_entry_t(fabrik_t *_factory, sint32 _demand) : factory(_factory), demand(_demand), supply(0), remaining(0) { } bool operator == (const factory_entry_t &other) const { return ( this->factory==other.factory ); } void new_month() { supply = 0; remaining = 0; } void rdwr(loadsave_t *file); void resolve_factory(); }; #define RATIO_BITS (25) struct factory_set_t { vector_tpl entries; sint32 total_demand; // shifted by DEMAND_BITS sint32 total_remaining; sint32 total_generated; uint32 generation_ratio; bool ratio_stale; factory_set_t() : total_demand(0), total_remaining(0), total_generated(0), generation_ratio(0), ratio_stale(true) { } const vector_tpl& get_entries() const { return entries; } const factory_entry_t* get_entry(const fabrik_t *const factory) const; factory_entry_t* get_random_entry(); void update_factory(fabrik_t *const factory, const sint32 demand); void remove_factory(fabrik_t *const factory); void recalc_generation_ratio(const sint32 default_percent, const sint64 *city_stats, const int stats_count, const int stat_type); void new_month(); void rdwr(loadsave_t *file); void resolve_factories(); }; private: /** * Data of target factories for pax/mail */ factory_set_t target_factories_pax; factory_set_t target_factories_mail; /** * Initialization of pax_destinations_old/new */ void init_pax_destinations(); /** * Recalculates city borders (after loading and deletion). * @warning Do not call this during multithreaded loading! */ void recalc_city_size(); // calculates the growth rate for next growth_interval using all the different indicators void calc_growth(); /** * Build new buildings when growing city */ void step_grow_city(bool new_town = false); enum pax_return_type { no_return, factory_return, tourist_return, city_return }; /** * verteilt die Passagiere auf die Haltestellen */ void step_passagiere(); /** * ein Passagierziel in die Zielkarte eintragen */ void merke_passagier_ziel(koord ziel, PIXVAL color); /** * baut Spezialgebaeude, z.B Stadion */ void check_bau_spezial(bool); /** * baut ein angemessenes Rathaus */ void check_bau_townhall(bool new_town, const building_desc_t* th, sint16 rotation); /** * constructs a new consumer */ void check_bau_factory(bool); // find out, what building matches best void bewerte_res_com_ind(const koord pos, int &ind, int &com, int &res); /** * Build/renovates a city building at Planquadrat (tile) x,y */ void build_city_building(koord pos); void renovate_city_building(gebaeude_t *gb); #ifdef DESTINATION_CITYCARS sint16 number_of_cars; // allowed number of cars to spawn per month void generate_private_cars(koord pos, koord target); #endif protected: /** * builds a piece of road * * @param k tile to build * @param player_ player * @param forced */ bool build_road(const koord k, player_t *player_, bool forced); private: void build(); /** * @param pos position to check * @param regel the rule to evaluate * @param rotation * @return true on match, false otherwise */ static bool bewerte_loc(koord pos, const rule_t ®el, int rotation); /** * Check rule in all transformations at given position */ static sint32 bewerte_pos(koord pos, const rule_t ®el); void bewerte_strasse(koord pos, sint32 rd, const rule_t ®el); void bewerte_haus(koord pos, sint32 rd, const rule_t ®el); /** * Updates city limits: tile at @p pos belongs to city. * @warning Do not call this during multithreaded loading! */ void pruefe_grenzen(koord pos, koord extend); public: bool is_within_players_network( const player_t* player ) const; /// Connects factories to this city. void verbinde_fabriken(); /** * Returns the data set associated with the pax/mail target factories */ const factory_set_t& get_target_factories_for_pax() const { return target_factories_pax; } const factory_set_t& get_target_factories_for_mail() const { return target_factories_mail; } factory_set_t& access_target_factories_for_pax() { return target_factories_pax; } factory_set_t& access_target_factories_for_mail() { return target_factories_mail; } // calculated the "best" orietation of city buildings, also used by editor, thus public static int orient_city_building(const koord k, const building_desc_t *h, koord maxarea ); // this function removes houses from the city house list // (called when removed by player, or by town) void remove_gebaeude_from_stadt(gebaeude_t *gb); /** * This function adds houses to the city house list. * * @param gb building * @param ordered true for multithreaded loading, will insert buidings ordered, will not update city limits */ void add_gebaeude_to_stadt(const gebaeude_t *gb, bool ordered=false); // changes the weight; must be called if there is a new definition (tile) for that house void update_gebaeude_from_stadt(gebaeude_t *gb); /** * Returns the finance history for cities */ sint64 get_finance_history_year(int year, int type) { return city_history_year[year][type]; } sint64 get_finance_history_month(int month, int type) { return city_history_month[month][type]; } // growth number (smoothed!) sint32 get_wachstum() const {return ((sint32)city_history_month[0][HIST_GROWTH]*5) + (sint32)(city_history_month[1][HIST_GROWTH]*4) + (sint32)city_history_month[2][HIST_GROWTH]; } /** * ermittelt die Einwohnerzahl der City */ sint32 get_einwohner() const {return (buildings.get_sum_weight()*6)+((2*bev-arb-won)>>1);} uint32 get_buildings() const { return buildings.get_count(); } sint32 get_unemployed() const { return bev - arb; } sint32 get_homeless() const { return bev - won; } const char *get_name() const { return name; } void set_name( const char *name ); /// @returns a random point within city borders. koord get_zufallspunkt() const; /// @returns passenger destination statistics for the last month const sparse_tpl* get_pax_destinations_old() const { return &pax_destinations_old; } /// @returns passenger destination statistics for the current month const sparse_tpl* get_pax_destinations_new() const { return &pax_destinations_new; } /* this counter will increment by one for every change * => dialogs can question, if they need to update map */ uint32 get_pax_destinations_new_change() const { return pax_destinations_new_change; } /** * Creates a new city on grid square (x,y) that belongs to player sp. * * * @param player The owner of the city * @param pos Planquadratkoordinate * @param citizens number of citizens * @param th townhall object * @param rotation */ stadt_t(player_t* player, koord pos, sint32 citizens, const building_desc_t* th = NULL, sint16 rotation = -1); /** * Erzeugt eine neue City nach Angaben aus der Datei file. * * @param file Zeiger auf die Datei mit den Citybaudaten. * @see stadt_t::speichern() */ stadt_t(loadsave_t *file); // closes window and that stuff ~stadt_t(); /** * Speichert die Daten der City in der Datei file so, dass daraus * die City wieder erzeugt werden kann. Die Gebaude und strassen der * City werden nicht mit der City gespeichert sondern mit den * Planquadraten auf denen sie stehen. * * @see stadt_t::stadt_t() * @see planquadrat_t */ void rdwr(loadsave_t *file); /** * Called when loading of savegame is finished to correctly init data. */ void finish_rd(); void rotate90( const sint16 y_size ); /* change size of city */ void change_size( sint64 delta_citizens, bool new_town = false ); // when ng is false, no town growth any more void set_citygrowth_yesno( bool ng ) { allow_citygrowth = ng; } bool get_citygrowth() const { return allow_citygrowth; } void step(uint32 delta_t); void new_month( bool recalc_destinations ); private: /** * List of target cities weighted by both city size and distance */ weighted_vector_tpl target_cities; /** * List of target attractions weighted by both passenger level and distance */ weighted_vector_tpl target_attractions; public: /** * Functions for manipulating the list of target cities */ void add_target_city(stadt_t *const city); void remove_target_city(stadt_t *const city) { target_cities.remove( city ); } void recalc_target_cities(); /** * Functions for manipulating the list of target attractions */ void add_target_attraction(gebaeude_t *const attraction); void remove_target_attraction(gebaeude_t *const attraction) { target_attractions.remove( attraction ); } void recalc_target_attractions(); /** * Search for a possible Passenger or Mail destination. * * @param target_factories the factory set to use (eg passenger or mail). * @param generated number of passengers already generated, used to fairly distribute to factories. * @param will_return set to the jounrey return type on return. * @param factory_entry set to the destination factory, if any. * @param dest_city set to the destination city for return flow use. */ koord find_destination(factory_set_t &target_factories, const sint64 generated, pax_return_type* will_return, factory_entry_t* &factory_entry, stadt_t* &dest_city); /** * Gibt die Gruendungsposition der City zurueck. * @return die Koordinaten des Gruendungsplanquadrates */ inline koord get_pos() const {return pos;} inline koord get_townhall_road() const {return townhall_road;} inline koord get_linksoben() const { return lo;} inline koord get_rechtsunten() const { return ur;} koord get_center() const { return lo/2 + ur/2; } /** * Generates an array of random coordinates suitable for creating cities. * Do not consider coordinates in (0,0) - (old_x, old_y) * (leave @p old_x and @p old_y 0 to generate cities on the whole map). * * @param count how many cities to generate * @param old_x * @param old_y */ static vector_tpl *random_place(sint32 count, sint16 old_x, sint16 old_y); void open_info_window(); }; #endif simutrans-124.3/src/simutrans/world/simplan.cc000066400000000000000000000602211474050137200214710ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "../simdebug.h" #include "../obj/simobj.h" #include "../simfab.h" #include "../display/simgraph.h" #include "../tool/simmenu.h" #include "simplan.h" #include "simworld.h" #include "../simhalt.h" #include "../player/simplay.h" #include "../simconst.h" #include "../macros.h" #include "../descriptor/ground_desc.h" #include "../ground/grund.h" #include "../ground/boden.h" #include "../ground/fundament.h" #include "../ground/wasser.h" #include "../ground/tunnelboden.h" #include "../ground/brueckenboden.h" #include "../ground/monorailboden.h" #include "../obj/gebaeude.h" #include "../dataobj/loadsave.h" #include "../dataobj/environment.h" #include "../gui/minimap.h" karte_ptr_t planquadrat_t::welt; void swap(planquadrat_t& a, planquadrat_t& b) { // since sim::swap down not work for bitfields, we brute force copy memory char tmp[sizeof(planquadrat_t)]; memcpy(tmp, &a, sizeof(planquadrat_t)); memcpy(&a, &b, sizeof(planquadrat_t)); memcpy(&b, tmp, sizeof(planquadrat_t)); } // deletes also all grounds in this array! planquadrat_t::~planquadrat_t() { if(ground_size==0) { // empty } else if(ground_size==1) { delete data.one; } else { while(ground_size>0) { ground_size --; delete data.some[ground_size]; data.some[ground_size] = 0; } delete [] data.some; } delete [] halt_list; halt_list_count = 0; // to avoid access to this tile ground_size = 0; data.one = NULL; } grund_t *planquadrat_t::get_boden_von_obj(obj_t *obj) const { if(ground_size==1) { if(data.one && data.one->obj_ist_da(obj)) { return data.one; } } else { for(uint8 i=0; iobj_ist_da(obj)) { return data.some[i]; } } } return NULL; } void planquadrat_t::boden_hinzufuegen(grund_t *bd) { assert(!bd->ist_karten_boden()); if(ground_size==0) { // completely empty data.one = bd; ground_size = 1; minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d()); return; } else if(ground_size==1) { // needs to convert to array // assert(data.one->get_hoehe()!=bd->get_hoehe()); if(data.one->get_hoehe()==bd->get_hoehe()) { DBG_MESSAGE("planquadrat_t::boden_hinzufuegen()","addition ground %s at (%i,%i,%i) will be ignored!",bd->get_name(),bd->get_pos().x,bd->get_pos().y,bd->get_pos().z); return; } grund_t **tmp = new grund_t *[2]; tmp[0] = data.one; tmp[1] = bd; data.some = tmp; ground_size = 2; minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d()); return; } else { // insert into array uint8 i; for(i=1; iget_hoehe()>=bd->get_hoehe()) { break; } } if(iget_hoehe()==bd->get_hoehe()) { DBG_MESSAGE("planquadrat_t::boden_hinzufuegen()","addition ground %s at (%i,%i,%i) will be ignored!",bd->get_name(),bd->get_pos().x,bd->get_pos().y,bd->get_pos().z); return; } bd->set_kartenboden(false); if (ground_size == MAX_PLAN_SIZE) { dbg->fatal("", "Maximum %d grounds at %s exhausted", MAX_PLAN_SIZE, data.some[0]->get_pos().get_2d().get_str()); } // extend array if needed grund_t **tmp = new grund_t *[ground_size+1]; for( uint8 j=0; jcalc_map_pixel(bd->get_pos().get_2d()); } } bool planquadrat_t::boden_entfernen(grund_t *bd) { assert(!bd->ist_karten_boden() && ground_size>0); if(ground_size==1) { ground_size = 0; data.one = NULL; return true; } else { for(uint8 i=0; iset_kartenboden(true); } if (!startup) { // water tiles need neighbor tiles, which might not be initialized at startup bd->calc_image(); } minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d()); } /** * replaces the map solid ground (or water) and deletes the old one */ void planquadrat_t::boden_ersetzen(grund_t *alt, grund_t *neu) { assert(alt!=NULL && neu!=NULL && !alt->is_halt() ); if(ground_size<=1) { assert(data.one==alt || ground_size==0); data.one = neu; ground_size = 1; neu->set_kartenboden(true); } else { for(uint8 i=0; iset_kartenboden(i==0); break; } } } // transfer text and delete if(alt) { if(alt->get_flag(grund_t::has_text)) { neu->set_flag(grund_t::has_text); alt->clear_flag(grund_t::has_text); } // transfer all objects while( alt->obj_count()>0 ) { neu->obj_add( alt->obj_remove_top() ); } // transfer way flags if(alt->get_flag(grund_t::has_way1)) { neu->set_flag(grund_t::has_way1); } if(alt->get_flag(grund_t::has_way2)) { neu->set_flag(grund_t::has_way2); } delete alt; } } void planquadrat_t::rdwr(loadsave_t *file, koord pos ) { xml_tag_t p( file, "planquadrat_t" ); if(file->is_saving()) { if(ground_size==1) { file->wr_obj_id(data.one->get_typ()); data.one->rdwr(file); } else { for(int i=0; iwr_obj_id(data.some[i]->get_typ()); data.some[i]->rdwr(file); } } file->wr_obj_id(-1); } else { grund_t *gr; sint8 hgt = welt->get_groundwater(); //DBG_DEBUG("planquadrat_t::rdwr()","Reading boden"); do { short gtyp = file->rd_obj_id(); switch(gtyp) { case -1: gr = NULL; break; case grund_t::boden: gr = new boden_t(file, pos); break; case grund_t::wasser: gr = new wasser_t(file, pos); break; case grund_t::fundament: gr = new fundament_t(file, pos); break; case grund_t::tunnelboden: gr = new tunnelboden_t(file, pos); break; case grund_t::brueckenboden: gr = new brueckenboden_t(file, pos); break; case grund_t::monorailboden: gr = new monorailboden_t(file, pos); break; default: gr = NULL; // keep compiler happy, fatal() never returns dbg->fatal("planquadrat_t::rdwr()","Error while loading game: Unknown ground type '%d'",gtyp); } // check if we have a matching building here, otherwise set to nothing if (gr && gtyp == grund_t::fundament && gr->find() == NULL) { koord3d pos = gr->get_pos(); // show normal ground here grund_t *neu = new boden_t(pos, 0); if(gr->get_flag(grund_t::has_text)) { neu->set_flag(grund_t::has_text); gr->clear_flag(grund_t::has_text); } // transfer all objects while( gr->obj_count()>0 ) { neu->obj_add( gr->obj_remove_top() ); } delete gr; gr = neu; //DBG_MESSAGE("planquadrat_t::rwdr", "unknown building (or prepare for factory) at %d,%d replaced by normal ground!", pos.x,pos.y); } // we should also check for ground below factories if(gr) { if(ground_size==0) { data.one = gr; ground_size = 1; gr->set_kartenboden(true); hgt = welt->lookup_hgt(pos); } else { boden_hinzufuegen(gr); // other ground must not change the grid height => reset it welt->set_grid_hgt_nocheck( pos, hgt ); } } } while(gr != NULL); // we must always have a kartenboden! if (get_kartenboden() == NULL) { dbg->fatal("planquadrat_t::rdwr", "No kartenboden found for tile at (%s)", pos.get_str()); } } } void planquadrat_t::check_season_snowline(const bool season_change, const bool snowline_change) { if( ground_size == 1 ) { data.one->check_season_snowline( season_change, snowline_change ); } else if( ground_size > 1 ) { for( uint8 i = 0; i < ground_size; i++ ) { data.some[i]->check_season_snowline( season_change, snowline_change ); } } } void planquadrat_t::correct_water() { grund_t *gr = get_kartenboden(); slope_t::type slope = gr->get_grund_hang(); sint8 max_height = gr->get_hoehe() + slope_t::max_diff( slope ); koord k = gr->get_pos().get_2d(); sint8 water_hgt = welt->get_water_hgt(k); if( gr && gr->get_typ() != grund_t::wasser && max_height <= water_hgt ) { // below water but ground => convert kartenboden_setzen( new wasser_t(koord3d( k, water_hgt ) ) ); } else if( gr && gr->get_typ() == grund_t::wasser && max_height > water_hgt ) { // water above ground => to ground kartenboden_setzen( new boden_t(gr->get_pos(), gr->get_disp_slope() ) ); } else if( gr && gr->get_typ() == grund_t::wasser && gr->get_hoehe() != water_hgt ) { // water at wrong height gr->set_hoehe( water_hgt ); } gr = get_kartenboden(); if( gr && gr->get_typ() != grund_t::wasser && gr->get_disp_height() < water_hgt && welt->max_hgt(k) > water_hgt ) { sint8 disp_hneu = water_hgt; sint8 disp_hn_sw = max( gr->get_hoehe() + corner_sw(slope), water_hgt ); sint8 disp_hn_se = max( gr->get_hoehe() + corner_se(slope), water_hgt ); sint8 disp_hn_ne = max( gr->get_hoehe() + corner_ne(slope), water_hgt ); sint8 disp_hn_nw = max( gr->get_hoehe() + corner_nw(slope), water_hgt ); const slope_t::type sneu = encode_corners(disp_hn_sw - disp_hneu, disp_hn_se - disp_hneu, disp_hn_ne - disp_hneu, disp_hn_nw - disp_hneu); gr->set_hoehe( disp_hneu ); gr->set_grund_hang( (slope_t::type)sneu ); } } void planquadrat_t::abgesenkt() { grund_t *gr = get_kartenboden(); if(gr) { const slope_t::type slope = gr->get_grund_hang(); gr->obj_loesche_alle(NULL); sint8 max_hgt = gr->get_hoehe() + (slope!=slope_t::flat ? 1 : 0); // only matters that not flat koord k(gr->get_pos().get_2d()); if( max_hgt <= welt->get_water_hgt( k ) && gr->get_typ() != grund_t::wasser ) { gr = new wasser_t(gr->get_pos()); kartenboden_setzen( gr ); // recalc water ribis of neighbors for(int r=0; r<4; r++) { grund_t *gr2 = welt->lookup_kartenboden(k + koord::nesw[r]); if (gr2 && gr2->is_water()) { gr2->calc_image(); } } } else { minimap_t::get_instance()->calc_map_pixel(k); } gr->set_grund_hang( slope ); } } void planquadrat_t::angehoben() { grund_t *gr = get_kartenboden(); if(gr) { const uint8 slope = gr->get_grund_hang(); gr->obj_loesche_alle(NULL); sint8 max_hgt = gr->get_hoehe() + (slope ? 1 : 0); // only matters that not flat koord k(gr->get_pos().get_2d()); if( max_hgt > welt->get_water_hgt( k ) && gr->get_typ() == grund_t::wasser ) { gr = new boden_t(gr->get_pos(), slope ); kartenboden_setzen( gr ); // recalc water ribis for(int r=0; r<4; r++) { grund_t *gr2 = welt->lookup_kartenboden(k + koord::nesw[r]); if( gr2 && gr2->is_water() ) { gr2->calc_image(); } } } else if( slope == 0 && gr->get_hoehe() == welt->get_water_hgt(k) && gr->get_typ() == grund_t::wasser ) { // water at zero level => make it land gr = new boden_t(gr->get_pos(), slope ); kartenboden_setzen( gr ); // recalc water ribis for(int r=0; r<4; r++) { grund_t *gr2 = welt->lookup_kartenboden(k + koord::nesw[r]); if( gr2 && gr2->is_water() ) { gr2->calc_image(); } } } else { minimap_t::get_instance()->calc_map_pixel(k); } } } void planquadrat_t::display_obj(const sint16 xpos, const sint16 ypos, const sint16 raster_tile_width, bool is_global, const sint8 hmin, const sint8 hmax CLIP_NUM_DEF) const { grund_t *gr0 = get_kartenboden(); if( gr0->get_flag( grund_t::dirty ) ) { gr0->set_all_obj_dirty(); // prevent artifacts with smart hide cursor } const sint8 h0 = gr0->get_disp_height(); uint8 i = 1; // tiles below ground drawing height (tunnels in full underground mode) if( hmin < h0 ) { for( ; i < ground_size; i++ ) { const grund_t* gr = data.some[i]; const sint8 h = gr->get_hoehe(); const sint8 htop = h + slope_t::max_diff( gr->get_grund_hang() ); // above ground if( h > h0 ) { break; } // not too low? if( htop >= hmin ) { const sint16 yypos = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width ); gr->display_boden( xpos, yypos, raster_tile_width CLIP_NUM_PAR ); gr->display_obj_all( xpos, yypos, raster_tile_width, is_global CLIP_NUM_PAR ); } } } //const bool kartenboden_dirty = gr->get_flag(grund_t::dirty); if( gr0->get_flag( grund_t::draw_as_obj ) || !gr0->is_karten_boden_visible() ) { gr0->display_boden( xpos, ypos, raster_tile_width CLIP_NUM_PAR ); } if( env_t::simple_drawing ) { // ignore trees going though bridges gr0->display_obj_all_quick_and_dirty( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR ); } else { // clip everything at the next tile above if( i < ground_size ) { clip_dimension p_cr = display_get_clip_wh( CLIP_NUM_VAR ); for( uint8 j = i; j < ground_size; j++ ) { const sint8 h = data.some[j]->get_hoehe(); const sint8 htop = h + slope_t::max_diff(data.some[j]->get_grund_hang()); // still underground if( h < h0 ) { continue; } // too high? if( h > hmax ) { break; } // not too low? if( htop >= hmin ) { // something on top: clip horizontally to prevent trees etc shining trough bridges const sint16 yh = ypos - tile_raster_scale_y( (h + corner_nw(data.some[j]->get_grund_hang()) - h0) * TILE_HEIGHT_STEP, raster_tile_width ) + ((3 * raster_tile_width) >> 2); if( yh >= p_cr.y ) { display_push_clip_wh(p_cr.x, yh, p_cr.w, p_cr.h + p_cr.y - yh CLIP_NUM_PAR ); } break; } } gr0->display_obj_all( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR ); display_pop_clip_wh(CLIP_NUM_VAR); } else { gr0->display_obj_all( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR ); } } // above ground drawing height for( ; i < ground_size; i++ ) { const grund_t* gr = data.some[i]; const sint8 h = gr->get_hoehe(); const sint8 htop = h + slope_t::max_diff( gr->get_grund_hang() ); // still underground if( h < h0 ) { if( grund_t::underground_mode != grund_t::ugm_level ) { continue; } // in level underground mode we show also the underground slope tiles one level down if( htop < h0 || data.some[0]->get_hoehe() == h0 ) { // but only if there is not just ground above and they would sine through continue; } } // too high? if( h > hmax ) { break; } // not too low? if( htop >= hmin ) { const sint16 yypos = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width ); gr->display_boden( xpos, yypos, raster_tile_width CLIP_NUM_PAR ); gr->display_obj_all( xpos, yypos, raster_tile_width, is_global CLIP_NUM_PAR ); } } } image_id overlay_img(grund_t *gr) { // only transparent outline image_id img; if( gr->get_typ()==grund_t::wasser ) { // water is always flat and does not return proper image_id img = ground_desc_t::outside->get_image(0); } else { img = gr->get_image(); if( img==IMG_EMPTY ) { // foundations or underground mode img = ground_desc_t::get_ground_tile( gr ); } } return img; } void planquadrat_t::display_overlay(const sint16 xpos, const sint16 ypos) const { grund_t *gr=get_kartenboden(); // building transformers - show outlines of factories /* // alternative method of finding selected tool - may be more useful in future but use simpler method for now tool_t *tool = welt->get_tool(welt->get_active_player_nr()); int tool_id = tool->get_id(); if(tool_id==(TOOL_TRANSFORMER|GENERAL_TOOL).... */ if( (grund_t::underground_mode == grund_t::ugm_all || (grund_t::underground_mode == grund_t::ugm_level && gr->get_hoehe() == grund_t::underground_level + welt->get_settings().get_way_height_clearance()) ) && gr->get_typ()==grund_t::fundament && tool_t::general_tool[TOOL_TRANSFORMER]->is_selected()) { gebaeude_t *gb = gr->find(); if(gb) { fabrik_t* fab=gb->get_fabrik(); if(fab) { FLAGGED_PIXVAL status = color_idx_to_rgb(COL_RED); if(fab->get_desc()->is_electricity_producer()) { status = color_idx_to_rgb(COL_LIGHT_BLUE); if(fab->is_transformer_connected()) { status = color_idx_to_rgb(COL_LIGHT_TURQUOISE); } } else { if(fab->is_transformer_connected()) { status = color_idx_to_rgb(COL_ORANGE); } if(fab->get_prodfactor_electric()>0) { status = color_idx_to_rgb(COL_GREEN); } } display_img_blend( overlay_img(gr), xpos, ypos, status | OUTLINE_FLAG | TRANSPARENT50_FLAG, 0, true); } } } // display station owner boxes if(env_t::station_coverage_show && halt_list_count>0) { if(env_t::use_transparency_station_coverage) { // only transparent outline image_id img = overlay_img(gr); for(int halt_count = 0; halt_count < halt_list_count; halt_count++) { const FLAGGED_PIXVAL transparent = PLAYER_FLAG | OUTLINE_FLAG | color_idx_to_rgb(halt_list[halt_count]->get_owner()->get_player_color1() + 4); display_img_blend( img, xpos, ypos, transparent | TRANSPARENT25_FLAG, 0, 0); } /* // unfortunately, too expensive for display // plot player outline colours - we always plot in order of players so that the order of the stations in halt_list // doesn't affect the colour displayed [since blend(col1,blend(col2,screen)) != blend(col2,blend(col1,screen))] for(int player_count = 0; player_countget_player(player_count); const FLAGGED_PIXVAL transparent = PLAYER_FLAG | OUTLINE_FLAG | color_idx_to_rgb(display_player->get_player_color1() * 4 + 4); for(int halt_count = 0; halt_count < halt_list_count; halt_count++) { if(halt_list[halt_count]->get_owner() == display_player) { display_img_blend( img, xpos, ypos, transparent | TRANSPARENT25_FLAG, 0, 0); } } } */ } else { const sint16 raster_tile_width = get_tile_raster_width(); // opaque boxes ( const sint16 r=raster_tile_width/8; const sint16 x=xpos+raster_tile_width/2-r; const sint16 y=ypos+(raster_tile_width*3)/4-r - (gr->get_grund_hang()? tile_raster_scale_y(8,raster_tile_width): 0); const bool kartenboden_dirty = gr->get_flag(grund_t::dirty); const sint16 off = (raster_tile_width>>5); // suitable start search for (size_t h = halt_list_count; h-- != 0;) { display_fillbox_wh_clip_rgb(x - h * off, y + h * off, r, r, PLAYER_FLAG | color_idx_to_rgb(halt_list[h]->get_owner()->get_player_color1() + 4), kartenboden_dirty); } } } gr->display_overlay( xpos, ypos ); if( ground_size > 1 ) { const sint16 raster_tile_width = get_tile_raster_width(); const sint8 h0 = gr->get_disp_height(); for( uint8 i = 1; i < ground_size; i++ ) { grund_t* gr = data.some[i]; const sint8 h = gr->get_disp_height(); const sint16 yypos = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width ); gr->display_overlay( xpos, yypos ); } } } /** * Finds halt belonging to a player * @param player owner of the halts we are interested in. */ halthandle_t planquadrat_t::get_halt(player_t *player) const { for( uint8 i=0; i < get_boden_count(); i++ ) { halthandle_t my_halt = get_boden_bei(i)->get_halt(); if( my_halt.is_bound() && (player == NULL || player == my_halt->get_owner()) ) { return my_halt; } } return halthandle_t(); } /** * The following haltlist routines takes at least 5 bytes of memory per tile but speed up passenger generation a lot */ // these functions are private helper functions for halt_list void planquadrat_t::halt_list_remove( halthandle_t halt ) { for( uint8 i=0; ihalt_list_count!!! void planquadrat_t::halt_list_insert_at( halthandle_t halt, uint8 pos ) { if (halt_list_count == MAX_PLAN_SIZE) { dbg->warning("planquadrat_t::halt_list_insert_at()", "Maximum %d haltlist at %s, kick out last", MAX_PLAN_SIZE, data.some[0]->get_pos().get_2d().get_str()); halt_list_count--; } // extend list? if((halt_list_count%4)==0) { // in the very rare cases of shrinking below 4 and growing again above 4, we do some unneccessary reallocation halthandle_t *tmp = new halthandle_t[halt_list_count+4]; if(halt_list!=NULL) { // now insert for( uint8 i=0; ipos; i-- ) { halt_list[i] = halt_list[i-1]; } halt_list[pos] = halt; halt_list_count ++; } void planquadrat_t::add_to_haltlist(halthandle_t halt, bool unsorted) { if(halt.is_bound()) { if (!unsorted) { // quick and dirty way to our 2d koodinates ... const koord pos = get_kartenboden()->get_pos().get_2d(); if( halt_list_count > 0 ) { // since only the first one gets all, we want the closest halt one to be first halt_list_remove(halt); uint32 dist = koord_distance(halt->get_next_pos(pos), pos); for(unsigned insert_pos=0; insert_posget_next_pos(pos), pos) > dist ) { halt_list_insert_at( halt, insert_pos ); return; } } // not found } // first just or just append to the end ... halt_list_insert_at( halt, halt_list_count ); } else { // insert only if not already present for(uint8 i = 0; i halts(halt_list_count); // sort with respect to distance to pos const koord pos = get_kartenboden()->get_pos().get_2d(); for(uint8 i = 0; iget_next_pos(pos), pos); halt_dist_node n(halt_list[i], dist); halts.insert_unique_ordered(n, halt_dist_node::comp); } // put back into halt_list for(uint8 i = 0; iget_pos().get_2d(); int const cov = welt->get_settings().get_station_coverage(); for (int y = -cov; y <= cov; y++) { for (int x = -cov; x <= cov; x++) { koord test_pos = pos+koord(x,y); const planquadrat_t *pl = welt->access(test_pos); if (pl) { for( uint i = 0; i < pl->get_boden_count(); i++ ) { if ( pl->get_boden_bei(i)->get_halt() == halt ) { // still connected // Reset distance computation add_to_haltlist(halt); } } } } } } /** * true, if this halt is reachable from here */ bool planquadrat_t::is_connected(halthandle_t halt) const { for( uint8 i=0; icheck_update_underground(); // update tunnel tiles for(unsigned int i=1; iist_tunnel()) { gr->check_update_underground(); } } } simutrans-124.3/src/simutrans/world/simplan.h000066400000000000000000000165241474050137200213420ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_SIMPLAN_H #define WORLD_SIMPLAN_H #include "../simconst.h" #include "../halthandle.h" #include "../ground/grund.h" #if !defined(MAX_PLAN_SIZE) #if defined(_M_X64) || defined(__x86_64__) #define MAX_PLAN_SIZE 15 #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) #define MAX_PLAN_SIZE 15 #else #define MAX_PLAN_SIZE 255 #endif #endif class karte_ptr_t; class grund_t; class obj_t; class planquadrat_t; void swap(planquadrat_t& a, planquadrat_t& b); /** * The map (karte_t) consists of map squares (planquadrat_t). * planquadrat_t objects consist of zero or more ground objects (grund_t). * As it is not that often accessed and wasting 6 bytes per field for 64 bit. * This is the only structure we pak and makes the sync_step even faster. * (I guess more cache hits.) * As I have no ARM machine to test if it dies with 32 bit ARM misalignment * no packing is done for ARM for now */ #if defined(__GNUC__) && MAX_PLAN_SIZE==15 class __attribute__((__packed__)) planquadrat_t #else class planquadrat_t #endif { static karte_ptr_t welt; private: /* list of stations that are reaching to this tile (saves lots of time for lookup) */ halthandle_t *halt_list; union DATA { grund_t ** some; // valid if capacity > 1 grund_t * one; // valid if capacity == 1 } data; #if MAX_PLAN_SIZE==15 uint8 ground_size:4; uint8 halt_list_count:4; uint8 climate_data:8; #else uint8 ground_size; uint8 halt_list_count; uint8 climate_data; #endif public: /** * Constructs a planquadrat (tile) with initial capacity of one ground */ planquadrat_t() { ground_size = 0; climate_data = 0; data.one = NULL; halt_list_count = 0; halt_list = NULL; } ~planquadrat_t(); private: planquadrat_t(planquadrat_t const&); planquadrat_t& operator=(planquadrat_t const&); friend void swap(planquadrat_t& a, planquadrat_t& b); public: /** * Setzen des "normalen" Bodens auf Kartenniveau */ void kartenboden_setzen(grund_t *bd, bool startup = false); /// Replaces old ground by new ground, deletes old ground. void boden_ersetzen(grund_t *old_ground, grund_t *new_ground); /// Adds a bridge, tunnel or monorail ground to this map square. void boden_hinzufuegen(grund_t *bd); /// Removes a bridge, tunnel or monorail ground from this map square. bool boden_entfernen(grund_t *bd); /** * Return either ground tile in this height or NULL if not existing * Inline, since called from karte_t::lookup() and thus extremely often * @return NULL if not ground in this height */ inline grund_t *get_boden_in_hoehe(const sint16 z) const { if(ground_size==1) { // must be valid ground at this point! if( data.one->get_hoehe() == z ) { return data.one; } } else { for( uint8 i = 0; i < ground_size; i++ ) { if( data.some[i]->get_hoehe() == z ) { return data.some[i]; } } } return NULL; } /** * returns normal ground (always first index) * @return not defined if no ground (must not happen!) */ inline grund_t *get_kartenboden() const { return (ground_size<=1) ? data.one : data.some[0]; } /** * find ground if thing is on this planquadrat (tile) * @return grund_t * with thing or NULL */ grund_t *get_boden_von_obj(obj_t *obj) const; /** * ground saved at index position idx (zero would be normal ground) * Since it is always called from loops or with other checks, no * range check is done => if only one ground, range is ignored! * @return ground at idx, undefined if ground_size==NULL */ inline grund_t *get_boden_bei(const unsigned idx) const { return (ground_size<=1 ? data.one : data.some[idx]); } /// @returns number of grounds on this map square. unsigned int get_boden_count() const { return ground_size; } /** * returns climate of plan (lowest 3 bits of climate byte) */ inline climate get_climate() const { return (climate)(climate_data & 7); } /** * sets plan climate */ void set_climate(climate cl) { climate_data = (climate_data & 0xf8) + (cl & 7); } /** * returns whether this is a transition to next climate (which will then use calculated image rather than overlay) */ inline bool get_climate_transition_flag() const { return (climate_data >> 3) & 1; } /** * set whether this is a transition to next climate (which will then use calculated image rather than overlay) */ void set_climate_transition_flag(bool flag) { climate_data = flag ? (climate_data | 0x08) : (climate_data & 0xf7); } /** * returns corners which transition to another climate * this has no meaning if tile is a slope with transition to next climate as these corners are fixed * therefore for this case to allow double heights 0 = first level transition, 1 = second level transition */ inline uint8 get_climate_corners() const { return (climate_data >> 4) & 15; } /** * sets climate transition corners * this has no meaning if tile is a slope with transition to next climate as these corners are fixed * therefore for this case to allow double heights 0 = first level transition, 1 = second level transition */ void set_climate_corners(uint8 corners) { climate_data = (climate_data & 0x0f) + (corners << 4); } /** * converts boden to correct type, land or water */ void correct_water(); /** * konvertiert Land zu Water wenn unter Grundwasserniveau abgesenkt */ void abgesenkt(); /** * Converts water to land when raised above the ground water level */ void angehoben(); /** * returns halthandle belonging to player if present */ halthandle_t get_halt(player_t *player) const; private: // these functions are private helper functions for halt_list corrections void halt_list_remove( halthandle_t halt ); void halt_list_insert_at( halthandle_t halt, uint8 pos ); public: /** * The following three functions takes about 4 bytes of memory per tile but speed up passenger generation * * @param halt * @param unsorted if true then halt list will be sorted later by call to sort_haltlist, see karte_t::plans_finish_rd. */ void add_to_haltlist(halthandle_t halt, bool unsorted = false); /** * removes the halt from a ground * however this function check, whether there is really no other part still reachable */ void remove_from_haltlist(halthandle_t halt); /** * sort list of connected halts, ascending wrt distance to this tile */ void sort_haltlist(); bool is_connected(halthandle_t halt) const; /** * returns the internal array of halts */ const halthandle_t *get_haltlist() const { return halt_list; } uint8 get_haltlist_count() const { return halt_list_count; } void rdwr(loadsave_t *file, koord pos ); /** * Updates season and/or snowline dependent graphics */ void check_season_snowline(const bool season_change, const bool snowline_change); void display_obj(const sint16 xpos, const sint16 ypos, const sint16 raster_tile_width, const bool is_global, const sint8 hmin, const sint8 hmax CLIP_NUM_DEF) const; void display_overlay(sint16 xpos, sint16 ypos) const; static void toggle_horizontal_clip(CLIP_NUM_DEF0); /** * @brief Update this square for underground view. * * Updates this square for underground view. This includes calculating * calculating new back will images as well as water depth texture. * * This method does not modify this square object, but does modify the * grounds it references. */ void update_underground() const; }; #endif simutrans-124.3/src/simutrans/world/simworld.cc000066400000000000000000006124021474050137200216720ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include #include #include #include "simcity.h" #include "../simcolor.h" #include "../simconvoi.h" #include "../simdebug.h" #include "../obj/depot.h" #include "../simfab.h" #include "../display/simgraph.h" #include "../display/viewport.h" #include "../simhalt.h" #include "../display/simimg.h" #include "../siminteraction.h" #include "../simintr.h" #include "../simlinemgmt.h" #include "../simloadingscreen.h" #include "../tool/simmenu.h" #include "../simmesg.h" #include "../simskin.h" #include "../simsound.h" #include "../simticker.h" #include "../simunits.h" #include "../simversion.h" #include "../display/simview.h" #include "../tool/simtool-scripted.h" #include "../gui/simwin.h" #include "simworld.h" #include "../sys/simsys.h" #include "../simachievements.h" #include "../tpl/vector_tpl.h" #include "../tpl/binary_heap_tpl.h" #include "../ground/boden.h" #include "../ground/wasser.h" #include "../old_blockmanager.h" #include "../vehicle/vehicle.h" #include "../vehicle/simroadtraffic.h" #include "../vehicle/pedestrian.h" #include "../vehicle/movingobj.h" #include "../obj/way/schiene.h" #include "../obj/zeiger.h" #include "../obj/baum.h" #include "../obj/signal.h" #include "../obj/roadsign.h" #include "../obj/wayobj.h" #include "../obj/groundobj.h" #include "../obj/gebaeude.h" #include "../obj/leitung2.h" #include "../obj/wolke.h" #include "../gui/password_frame.h" #include "../gui/messagebox.h" #include "../gui/help_frame.h" #include "../gui/minimap.h" #include "../gui/player_frame.h" #include "../gui/factorylist_frame.h" #include "../gui/curiositylist_frame.h" #include "../gui/labellist_frame.h" #include "../gui/vehiclelist_frame.h" #include "../network/network.h" #include "../network/network_file_transfer.h" #include "../network/network_socket_list.h" #include "../network/network_cmd_ingame.h" #include "../dataobj/height_map_loader.h" #include "../dataobj/ribi.h" #include "../dataobj/translator.h" #include "../dataobj/loadsave.h" #include "../dataobj/marker.h" #include "../dataobj/scenario.h" #include "../dataobj/settings.h" #include "../dataobj/environment.h" #include "../dataobj/powernet.h" #include "../dataobj/records.h" #include "../dataobj/pakset_manager.h" #include "../utils/cbuffer.h" #include "../utils/simrandom.h" #include "../utils/simstring.h" #include "../network/memory_rw.h" #include "../builder/brueckenbauer.h" #include "../builder/tunnelbauer.h" #include "../builder/fabrikbauer.h" #include "../builder/wegbauer.h" #include "../builder/hausbauer.h" #include "../builder/vehikelbauer.h" #include "../descriptor/ground_desc.h" #include "../descriptor/intro_dates.h" #include "../player/simplay.h" #include "../player/finance.h" #include "../player/ai_passenger.h" #include "../player/ai_goods.h" #include "../player/ai_scripted.h" #include "terraformer.h" #include "../io/rdwr/adler32_stream.h" #include "../pathes.h" #ifdef STEAM_BUILT #include "../../steam/steam.h" #endif // forward declaration - management of rotation for scripting namespace script_api { void rotate90(); void new_world(); }; static uint32 last_clients = -1; static uint8 last_active_player_nr = 0; static std::string last_network_game; karte_t* karte_t::world = NULL; #ifdef MULTI_THREAD #include "../utils/simthread.h" #include bool spawned_world_threads=false; // global job indicator array static simthread_barrier_t world_barrier_start; static simthread_barrier_t world_barrier_end; // to start a thread typedef struct{ karte_t *welt; int thread_num; sint16 x_step; sint16 x_world_max; sint16 y_min; sint16 y_max; sem_t* wait_for_previous; sem_t* signal_to_next; xy_loop_func function; bool keep_running; } world_thread_param_t; // now the parameters static world_thread_param_t world_thread_param[MAX_THREADS]; void *karte_t::world_xy_loop_thread(void *ptr) { world_thread_param_t *param = reinterpret_cast(ptr); bool keep_running = false; do { simthread_barrier_wait( &world_barrier_start ); // wait for all to start sint16 x_min = 0; sint16 x_max = param->x_step; while( x_min < param->x_world_max ) { // wait for predecessor to finish its block if( param->wait_for_previous ) { sem_wait( param->wait_for_previous ); } (param->welt->*(param->function))(x_min, x_max, param->y_min, param->y_max); // signal to next thread that we finished one block if( param->signal_to_next ) { sem_post( param->signal_to_next ); } x_min = x_max; x_max = min(x_max + param->x_step, param->x_world_max); } // the main thread writes to param->keep_running between world_barrier_end and world_barrier_start // so we have to copy the old value keep_running = param->keep_running; simthread_barrier_wait( &world_barrier_end ); // wait for all to finish } while (keep_running); return NULL; } #endif void karte_t::world_xy_loop(xy_loop_func function, uint8 flags) { const bool use_grids = (flags & GRIDS_FLAG) == GRIDS_FLAG; uint16 max_x = use_grids?(cached_grid_size.x+1):cached_grid_size.x; uint16 max_y = use_grids?(cached_grid_size.y+1):cached_grid_size.y; #ifdef MULTI_THREAD set_random_mode( INTERACTIVE_RANDOM ); // do not allow simrand() here! const bool sync_x_steps = (flags & SYNCX_FLAG) == SYNCX_FLAG; // semaphores to synchronize progress in x direction sem_t sems[MAX_THREADS-1]; for( int t = 0; t < env_t::num_threads; t++ ) { if( sync_x_steps && t < env_t::num_threads - 1 ) { sem_init(&sems[t], 0, 0); } world_thread_param[t].welt = this; world_thread_param[t].thread_num = t; world_thread_param[t].x_step = sync_x_steps ? min( 64, max_x / env_t::num_threads ) : max_x; world_thread_param[t].x_world_max = max_x; world_thread_param[t].y_min = (t * max_y) / env_t::num_threads; world_thread_param[t].y_max = ((t + 1) * max_y) / env_t::num_threads; world_thread_param[t].function = function; world_thread_param[t].wait_for_previous = sync_x_steps && t > 0 ? &sems[t-1] : NULL; world_thread_param[t].signal_to_next = sync_x_steps && t < env_t::num_threads - 1 ? &sems[t] : NULL; world_thread_param[t].keep_running = t < env_t::num_threads - 1; } if( !spawned_world_threads ) { // we can do the parallel display using posix threads ... pthread_t thread[MAX_THREADS]; /* Initialize and set thread detached attribute */ pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); // init barrier simthread_barrier_init( &world_barrier_start, NULL, env_t::num_threads ); simthread_barrier_init( &world_barrier_end, NULL, env_t::num_threads ); for( int t = 0; t < env_t::num_threads - 1; t++ ) { if( pthread_create( &thread[t], &attr, world_xy_loop_thread, (void *)&world_thread_param[t] ) ) { dbg->fatal( "karte_t::world_xy_loop()", "cannot multithread, error at thread #%i", t+1 ); } } spawned_world_threads = true; pthread_attr_destroy( &attr ); } // and start processing; the last we can run ourselves world_xy_loop_thread(&world_thread_param[env_t::num_threads-1]); // return from thread for( int t = 0; t < env_t::num_threads - 1; t++ ) { if( sync_x_steps ) { sem_destroy(&sems[t]); } } clear_random_mode( INTERACTIVE_RANDOM ); // do not allow simrand() here! #else // slow serial way of display (this->*function)( 0, max_x, 0, max_y ); #endif } void karte_t::recalc_season_snowline(bool set_pending) { static const sint8 mfactor[12] = { 99, 95, 80, 50, 25, 10, 0, 5, 20, 35, 65, 85 }; static const uint8 month_to_season[12] = { 2, 2, 2, 3, 3, 0, 0, 0, 0, 1, 1, 2 }; // calculate snowline with day precision // use linear interpolation const sint32 ticks_this_month = get_ticks() & (karte_t::ticks_per_world_month - 1); const sint32 factor = mfactor[last_month] + ( ( (mfactor[(last_month + 1) % 12] - mfactor[last_month]) * (ticks_this_month >> 12) ) >> (karte_t::ticks_per_world_month_shift - 12) ); // just remember them const uint8 old_season = season; const sint16 old_snowline = snowline; // and calculate new values season = month_to_season[last_month]; // (2+last_month/3)&3; // summer always zero if( old_season != season && set_pending ) { pending_season_change++; } const sint8 winterline = settings.get_winter_snowline(); const sint8 summerline = max(settings.get_climate_borders(arctic_climate,1),settings.get_climate_borders(arctic_climate,0)); snowline = summerline - (sint8)(((summerline-winterline)*factor)/100); if( old_snowline != snowline && set_pending ) { pending_snowline_change++; } } void karte_t::perlin_hoehe_loop( sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) { for( int y = y_min; y < y_max; y++ ) { for( int x = x_min; x < x_max; x++ ) { // loop all tiles koord k(x,y); sint16 const h = perlin_hoehe(&settings, k, koord(0, 0)); set_grid_hgt_nocheck( k, (sint8) h); } } } sint32 karte_t::perlin_hoehe(settings_t const* const sets, koord k, koord const size) { // replace the fixed values with your settings. Amplitude is the top highness of the mountains, // frequency is something like landscape 'roughness'; amplitude may not be greater than 160.0 !!! // please don't allow frequencies higher than 0.8, it'll break the AI's pathfinding. // Frequency values of 0.5 .. 0.7 seem to be ok, less is boring flat, more is too crumbled // the old defaults are given here: f=0.6, a=160.0 switch( sets->get_rotation() ) { // 0: do nothing case 1: k = koord(k.y,size.x-k.x); break; case 2: k = koord(size.x-k.x,size.y-k.y); break; case 3: k = koord(size.y-k.y,k.x); break; } // double perlin_noise_2D(double x, double y, double persistence); // return ((int)(perlin_noise_2D(x, y, 0.6)*160.0)) & 0xFFFFFFF0; k = k + koord(sets->get_origin_x(), sets->get_origin_y()); return ((int)(perlin_noise_2D(k.x, k.y, sets->get_map_roughness())*(double)sets->get_max_mountain_height())) / 16; } void karte_t::cleanup_grounds_loop( sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) { for( int y = y_min; y < y_max; y++ ) { for( int x = x_min; x < x_max; x++ ) { planquadrat_t *pl = access_nocheck(x,y); koord k(x,y); slope_t::type slope = calc_natural_slope(k); sint8 height = min_hgt_nocheck(k); sint8 water_hgt = get_water_hgt_nocheck(k); if( height < water_hgt) { const sint8 disp_hn_sw = max( height + corner_sw(slope), water_hgt ); const sint8 disp_hn_se = max( height + corner_se(slope), water_hgt ); const sint8 disp_hn_ne = max( height + corner_ne(slope), water_hgt ); const sint8 disp_hn_nw = max( height + corner_nw(slope), water_hgt ); height = water_hgt; slope = encode_corners(disp_hn_sw - height, disp_hn_se - height, disp_hn_ne - height, disp_hn_nw - height); } if( max_hgt_nocheck(k) <= water_hgt ) { // create water pl->kartenboden_setzen( new wasser_t(koord3d( k, height)), true /* do not calc_image for water tiles */ ); } else { // create ground pl->kartenboden_setzen( new boden_t(koord3d( k, height), slope ) ); } if( max_hgt_nocheck(k) > water_hgt ) { set_water_hgt_nocheck(k, groundwater-4); } } } } void karte_t::cleanup_karte( int xoff, int yoff ) { // we need a copy to smooth the map to a realistic level const sint32 grid_size = (get_size().x+1)*(sint32)(get_size().y+1); sint8 *grid_hgts_cpy = new sint8[grid_size]; memcpy( grid_hgts_cpy, grid_hgts, grid_size ); // the trick for smoothing is to raise each tile by one sint32 i,j; for(j=0; j<=get_size().y; j++) { for(i=j>=yoff?0:xoff; i<=get_size().x; i++) { raise_grid_to(i,j, grid_hgts_cpy[i+j*(get_size().x+1)] + 1); } } delete [] grid_hgts_cpy; // but to leave the map unchanged, we lower the height again for(j=0; j<=get_size().y; j++) { for(i=j>=yoff?0:xoff; i<=get_size().x; i++) { grid_hgts[i+j*(get_size().x+1)] --; } } if( xoff==0 && yoff==0 ) { // world_xy_loop(&karte_t::cleanup_grounds_loop, 0); cleanup_grounds_loop( 0, get_size().x, 0, get_size().y ); } else { cleanup_grounds_loop( 0, get_size().x, yoff, get_size().y ); cleanup_grounds_loop( xoff, get_size().x, 0, yoff ); } } void karte_t::destroy() { is_sound = false; // karte_t::play_sound_area_clipped needs valid zeiger (pointer/drawer) destroying = true; DBG_MESSAGE("karte_t::destroy()", "destroying world"); uint32 max_display_progress = 256+cities.get_count()*10 + haltestelle_t::get_alle_haltestellen().get_count() + convoi_array.get_count() + (cached_size.x*cached_size.y)*2; uint32 old_progress = 0; loadingscreen_t ls( translator::translate("Destroying map ..."), max_display_progress, true ); // rotate the map until it can be saved nosave_warning = false; if( nosave ) { max_display_progress += 256; for( int i=0; i<4 && nosave; i++ ) { DBG_MESSAGE("karte_t::destroy()", "rotating"); rotate90(); } old_progress += 256; ls.set_max( max_display_progress ); ls.set_progress( old_progress ); } if(nosave) { dbg->fatal( "karte_t::destroy()","Map cannot be cleanly destroyed in any rotation!" ); } goods_in_game.clear(); DBG_MESSAGE("karte_t::destroy()", "label clear"); labels.clear(); if(zeiger) { zeiger->set_pos(koord3d::invalid); delete zeiger; zeiger = NULL; } old_progress += 256; ls.set_progress( old_progress ); // removes all moving stuff from the sync_step sync.clear(); sync_buildings.clear(); sync_roadsigns.clear(); old_progress += cached_size.x*cached_size.y; ls.set_progress( old_progress ); DBG_MESSAGE("karte_t::destroy()", "sync list cleared"); // alle convois aufraeumen while (!convoi_array.empty()) { convoihandle_t cnv = convoi_array.back(); cnv->destroy(); old_progress ++; if( (old_progress&0x00FF) == 0 ) { ls.set_progress( old_progress ); } } convoi_array.clear(); DBG_MESSAGE("karte_t::destroy()", "convois destroyed"); // alle haltestellen aufraeumen old_progress += haltestelle_t::get_alle_haltestellen().get_count(); haltestelle_t::destroy_all(); DBG_MESSAGE("karte_t::destroy()", "stops destroyed"); ls.set_progress( old_progress ); // remove all target cities (we can skip recalculation anyway) for(fabrik_t* const f : fab_list) { f->clear_target_cities(); } // delete towns first (will also delete all their houses) // for the next game we need to remember the desired number ... sint32 const no_of_cities = settings.get_city_count(); for( uint32 i=0; !cities.empty(); i++ ) { remove_city(cities.front()); old_progress += 10; if( (i&0x00F) == 0 ) { ls.set_progress( old_progress ); } } settings.set_city_count(no_of_cities); DBG_MESSAGE("karte_t::destroy()", "towns destroyed"); ls.set_progress( old_progress ); // dinge aufraeumen cached_grid_size.x = cached_grid_size.y = 1; cached_size.x = cached_size.y = 0; delete [] plan; plan = NULL; DBG_MESSAGE("karte_t::destroy()", "planquadrat destroyed"); old_progress += (cached_size.x*cached_size.y)/2; ls.set_progress( old_progress ); // gitter aufraeumen delete [] grid_hgts; grid_hgts = NULL; delete [] water_hgts; water_hgts = NULL; // player cleanup for(int i=0; iget_einwohner() == 0) { delete new_city; return NULL; } settings.set_city_count(settings.get_city_count() + 1); cities.append(new_city, new_city->get_einwohner()); // add links between this city and other cities as well as attractions for(stadt_t *city : cities) { city->add_target_city(new_city); } new_city->recalc_target_cities(); new_city->recalc_target_attractions(); return new_city; } bool karte_t::remove_city(stadt_t *s) { if(s == NULL || cities.empty()) { // no town there to delete ... return false; } // reduce number of towns if(s->get_name()) { DBG_MESSAGE("karte_t::remove_city()", "%s", s->get_name()); } cities.remove(s); DBG_DEBUG4("karte_t::remove_city()", "reduce city to %i", settings.get_city_count() - 1); settings.set_city_count(settings.get_city_count() - 1); // remove links between this city and other cities for(stadt_t* const c : cities) { c->remove_target_city(s); } // remove all links from factories DBG_DEBUG4("karte_t::remove_city()", "fab_list %i", fab_list.get_count() ); for(fabrik_t* const f : fab_list) { f->remove_target_city(s); } // ok, we can delete this DBG_MESSAGE("karte_t::remove_city()", "delete" ); delete s; return true; } // just allocates space; void karte_t::init_tiles() { assert(plan==0); uint32 const x = get_size().x; uint32 const y = get_size().y; plan = new planquadrat_t[x * y]; grid_hgts = new sint8[(x + 1) * (y + 1)]; max_height = min_height = 0; MEMZERON(grid_hgts, (x + 1) * (y + 1)); water_hgts = new sint8[x * y]; MEMZERON(water_hgts, x * y); win_set_world( this ); minimap_t::get_instance()->init(); for(int i=0; iclear_speed_records(); // make timer loop invalid for( int i=0; i<32; i++ ) { last_frame_ms[i] = 0x7FFFFFFFu; last_step_nr[i] = 0xFFFFFFFFu; } last_frame_idx = 0; pending_season_change = 0; pending_snowline_change = 0; // init global history for (int year=0; yearwarning("karte_t::create_rivers()","There is no river defined!\n"); return; } // create a vector of the highest points vector_tpl lake_tiles; vector_tpl sea_tiles; weighted_vector_tpl mountain_tiles; sint8 last_height = 1; koord last_koord(0,0); const sint16 max_dist = cached_size.y+cached_size.x; // trunk of 16 will ensure that rivers are long enough apart ... for( sint16 y = 8; y < cached_size.y; y+=16 ) { for( sint16 x = 8; x < cached_size.x; x+=16 ) { koord k(x,y); grund_t *gr = lookup_kartenboden_nocheck(k); const sint8 h = gr->get_hoehe() - get_water_hgt_nocheck(k); if( gr->is_water() ) { // may be good to start a river here if( gr->get_hoehe() <= get_groundwater() ) { sea_tiles.append(k); } else { lake_tiles.append(k); } } else if( h>=last_height || koord_distance(last_koord,k)>simrand(max_dist) ) { // something worth to add here if( h>last_height ) { last_height = h; } last_koord = k; // using h*h as weight would give mountain sources more preferences // on the other hand most rivers do not string near summits ... mountain_tiles.append( k, h ); } } } vector_tpl water_tiles( sea_tiles.empty() ? lake_tiles : sea_tiles ); if (water_tiles.empty()) { dbg->message("karte_t::create_rivers()","There aren't any water tiles!\n"); return; } // now make rivers sint16 retrys = number*2; while( number > 0 && !mountain_tiles.empty() && retrys>0 ) { // start with random coordinates koord const start = pick_any_weighted(mountain_tiles); mountain_tiles.remove( start ); // build a list of matching targets vector_tpl valid_water_tiles; for( uint32 i=0; iget_pos(), lookup_kartenboden(start)->get_pos() ); if( riverbuilder.get_count() >= (uint32)settings.get_min_river_length() ) { // do not built too short rivers riverbuilder.build(); number --; retrys++; break; } } retrys--; } // we gave up => tell the user if( number>0 ) { dbg->warning( "karte_t::create_rivers()","Too many rivers requested! (%i not constructed)", number ); } } void karte_t::distribute_cities(int new_city_count, sint32 new_mean_citizen_count, sint16 old_x, sint16 old_y) { DBG_DEBUG("karte_t::distribute_cities()","prepare cities"); vector_tpl *pos = stadt_t::random_place(new_city_count, old_x, old_y); if( !pos->empty() ) { const sint32 old_city_count = cities.get_count(); new_city_count = pos->get_count(); DBG_DEBUG("karte_t::distribute_cities()", "Creating cities: %d", new_city_count); // if we could not generate enough positions ... settings.set_city_count(old_city_count); int old_progress = 16; loadingscreen_t ls( translator::translate( "distributing cities" ), 16 + 2 * (old_city_count + new_city_count) + 2 * new_city_count + (old_x == 0 ? settings.get_factory_count() : 0), true, true ); { // Loop only new cities: #ifdef DEBUG uint32 tbegin = dr_time(); #endif for( int i=0; iget_city_history_month())[HIST_CITIZENS] ); } } // center on first city if( old_x+old_y == 0 && cities.get_count()>0) { viewport->change_world_position( cities[0]->get_pos() ); } delete pos; #ifdef DEBUG dbg->message("karte_t::distribute_cities()","took %lu ms for all towns", dr_time()-tbegin ); #endif uint32 game_start = current_month; // townhalls available since? for(building_desc_t const* const desc : *hausbauer_t::get_list(building_desc_t::townhall)) { uint32 intro_year_month = desc->get_intro_year_month(); if( intro_year_monthget_intro_year_month() ); uint32 original_start_year = current_month; uint32 original_industry_growth = settings.get_industry_increase_every(); settings.set_industry_increase_every( 0 ); for( uint32 i=old_city_count; ifinish_rd(); // int citizens=(int)(new_mean_citizen_count*0.9); // citizens = citizens/10+simrand(2*citizens+1); const sint32 citizens = (2500l * new_mean_citizen_count) /(simrand(20000)+100); sint32 diff = (original_start_year-game_start)/2; sint32 growth = 32; sint32 current_bev = 1; /* grow gradually while aging * the difference to the current end year will be halved, * while the growth step is doubled */ current_month = game_start; bool not_updated = false; bool new_town = true; while( current_bev < citizens ) { growth = min( citizens-current_bev, growth*2 ); current_bev += growth; cities[i]->change_size( growth, new_town ); // Only "new" for the first change_size call new_town = false; if( current_bev > citizens/2 && not_updated ) { ls.set_progress( ++old_progress ); not_updated = true; } current_month += diff; diff >>= 1; } // the growth is slow, so update here the progress bar ls.set_progress( ++old_progress ); } current_month = original_start_year; settings.set_industry_increase_every( original_industry_growth ); msg->clear(); } finance_history_year[0][WORLD_TOWNS] = finance_history_month[0][WORLD_TOWNS] = cities.get_count(); finance_history_year[0][WORLD_CITIZENS] = finance_history_month[0][WORLD_CITIZENS] = last_month_bev; // connect some cities with roads way_desc_t const* desc = settings.get_intercity_road_type(get_timeline_year_month()); if(desc == 0) { // try some default (might happen with timeline ... ) desc = way_builder_t::weg_search(road_wt,80,get_timeline_year_month(),type_flat); } way_builder_t bauigel(get_public_player()); bauigel.init_builder(way_builder_t::strasse | way_builder_t::terraform_flag, desc, tunnel_builder_t::get_tunnel_desc(road_wt,15,get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,15,get_timeline_year_month()) ); bauigel.set_keep_existing_ways(true); bauigel.set_maximum(env_t::intercity_road_length); // **** intercity road construction int count = 0; sint32 const n_cities = settings.get_city_count(); int const max_count = n_cities * (n_cities - 1) / 2 - old_city_count * (old_city_count - 1) / 2; // something to do?? if( max_count > 0 ) { // print("Building intercity roads ...\n"); ls.set_max( 16 + 2 * (old_city_count + new_city_count) + 2 * new_city_count + (old_x == 0 ? settings.get_factory_count() : 0) ); // find townhall of city i and road in front of it vector_tpl k; for (int i = 0; i < settings.get_city_count(); ++i) { koord k1(cities[i]->get_townhall_road()); if (lookup_kartenboden(k1) && lookup_kartenboden(k1)->hat_weg(road_wt)) { k.append(lookup_kartenboden(k1)->get_pos()); } else { // look for a road near the townhall gebaeude_t const* const gb = obj_cast(lookup_kartenboden(cities[i]->get_pos())->first_no_way_obj()); bool ok = false; if( gb && gb->is_townhall() ) { koord k_check = cities[i]->get_pos() + koord(-1,-1); const koord size = gb->get_tile()->get_desc()->get_size(gb->get_tile()->get_layout()); koord inc(1,0); // scan all adjacent tiles, take the first that has a road for(sint32 i=0; i<2*size.x+2*size.y+4 && !ok; i++) { grund_t *gr = lookup_kartenboden(k_check); if (gr && gr->hat_weg(road_wt)) { k.append(gr->get_pos()); ok = true; } k_check = k_check + inc; if (i==size.x+1) { inc = koord(0,1); } else if (i==size.x+size.y+2) { inc = koord(-1,0); } else if (i==2*size.x+size.y+3) { inc = koord(0,-1); } } } if (!ok) { k.append( koord3d::invalid ); } } } // compute all distances uint8 conn_comp=1; // current connection component for phase 0 vector_tpl city_flag; // city already connected to the graph? >0 nr of connection component array2d_tpl city_dist(settings.get_city_count(), settings.get_city_count()); for (sint32 i = 0; i < settings.get_city_count(); ++i) { city_dist.at(i,i) = 0; for (sint32 j = i + 1; j < settings.get_city_count(); ++j) { city_dist.at(i,j) = koord_distance(k[i], k[j]); city_dist.at(j,i) = city_dist.at(i,j); // count unbuildable connections to new cities if( j>=old_city_count && city_dist.at(i,j) >= env_t::intercity_road_length ) { count++; } } city_flag.append( i < old_city_count ? conn_comp : 0 ); // progress bar stuff ls.set_progress( 16 + 2 * new_city_count + count * settings.get_city_count() * 2 / max_count ); } // mark first town as connected if (old_city_count==0) { city_flag[0]=conn_comp; } // get a default vehikel route_t verbindung; vehicle_t* test_driver; vehicle_desc_t test_drive_desc(road_wt, 500, vehicle_desc_t::diesel ); test_driver = vehicle_builder_t::build(koord3d(), get_public_player(), NULL, &test_drive_desc); test_driver->set_flag( obj_t::not_on_map ); bool ready=false; uint8 phase=0; // 0 - first phase: built minimum spanning tree (edge weights: city distance) // 1 - second phase: try to complete the graph, avoid edges that // == have similar length then already existing connection // == lead to triangles with an angle >90 deg while( phase < 2 ) { ready = true; koord conn = koord::invalid; sint32 best = env_t::intercity_road_length; if( phase == 0 ) { // loop over all unconnected cities for (int i = 0; i < settings.get_city_count(); ++i) { if( city_flag[i] == conn_comp ) { // loop over all connections to connected cities for (int j = old_city_count; j < settings.get_city_count(); ++j) { if( city_flag[j] == 0 ) { ready=false; if( city_dist.at(i,j) < best ) { best = city_dist.at(i,j); conn = koord(i,j); } } } } } // did we completed a connection component? if( !ready && best == env_t::intercity_road_length ) { // next component conn_comp++; // try the first not connected city ready = true; for( int i = old_city_count; i < settings.get_city_count(); ++i ) { if( city_flag[i] ==0 ) { city_flag[i] = conn_comp; ready = false; break; } } } } else { // loop over all unconnected cities for (int i = 0; i < settings.get_city_count(); ++i) { for (int j = max(old_city_count, i + 1); j < settings.get_city_count(); ++j) { if( city_dist.at(i,j) < best && city_flag[i] == city_flag[j] ) { bool ok = true; // is there a connection i..l..j ? forbid stumpfe winkel for (int l = 0; l < settings.get_city_count(); ++l) { if( city_flag[i] == city_flag[l] && city_dist.at(i,l) == env_t::intercity_road_length && city_dist.at(j,l) == env_t::intercity_road_length ) { // cosine < 0 ? koord3d d1 = k[i]-k[l]; koord3d d2 = k[j]-k[l]; if( d1.x*d2.x + d1.y*d2.y < 0 ) { city_dist.at(i,j) = env_t::intercity_road_length+1; city_dist.at(j,i) = env_t::intercity_road_length+1; ok = false; count ++; break; } } } if(ok) { ready = false; best = city_dist.at(i,j); conn = koord(i,j); } } } } } // valid connection? if( conn.x >= 0 ) { // is there a connection already const bool connected = ( phase==1 && verbindung.calc_route( this, k[conn.x], k[conn.y], test_driver, 0, 0 ) ); // build this connection? bool build = false; // set appropriate max length for way builder if( connected ) { if( 2*verbindung.get_count() > (uint32)city_dist.at(conn) ) { bauigel.set_maximum(verbindung.get_count() / 2); build = true; } } else { bauigel.set_maximum(env_t::intercity_road_length); build = true; } if( build ) { bauigel.calc_route(k[conn.x],k[conn.y]); } if( build && bauigel.get_count() >= 2 ) { bauigel.build(); if (phase==0) { city_flag[ conn.y ] = conn_comp; } // mark as built city_dist.at(conn) = env_t::intercity_road_length; city_dist.at(conn.y, conn.x) = env_t::intercity_road_length; count ++; } else { // do not try again city_dist.at(conn) = env_t::intercity_road_length+1; city_dist.at(conn.y, conn.x) = env_t::intercity_road_length+1; count ++; if( phase == 0 ) { // do not try to connect to this connected component again for( int i = 0; i < settings.get_city_count(); ++i ) { if( city_flag[i] == conn_comp && city_dist.at(i, conn.y) 0 ) { // add eyecandy like rocky, moles, flowers, ... koord k; sint32 queried = simrand(env_t::ground_object_probability*2-1); for( k.y=0; k.yget_typ()==grund_t::boden && !gr->hat_wege() ) { queried --; if( queried<0 ) { // test for beach bool neighbour_water = false; for(int i=0; i<8; i++) { if( is_within_limits(k + koord::neighbours[i]) && get_climate( k + koord::neighbours[i] ) == water_climate ) { neighbour_water = true; break; } } const climate_bits cl = neighbour_water ? water_climate_bit : (climate_bits)(1<get_grund_hang() ); queried = simrand(env_t::ground_object_probability*2-1); if(desc) { gr->obj_add( new groundobj_t( gr->get_pos(), desc ) ); } } } } } } } void karte_t::distribute_movingobjs(sint16 old_x, sint16 old_y) { DBG_DEBUG("karte_t::distribute_movingobj()","distributing movingobjs"); if( env_t::moving_object_probability > 0 ) { // add animals and so on (must be done after growing and all other objects, that could change ground coordinates) koord k; bool has_water = movingobj_t::random_movingobj_for_climate( water_climate )!=NULL; sint32 queried = simrand(env_t::moving_object_probability*2); // no need to test the borders, since they are mostly slopes anyway for(k.y=1; k.yobj_count()==0 && ( (gr->get_typ()==grund_t::boden && gr->get_grund_hang()==slope_t::flat) || (has_water && gr->is_water()) ) ) { queried --; if( queried<0 ) { const groundobj_desc_t *desc = movingobj_t::random_movingobj_for_climate( get_climate(k) ); if( desc && ( desc->get_waytype() != water_wt || gr->get_hoehe() <= get_water_hgt_nocheck(k) ) ) { if(desc->get_speed()!=0) { queried = simrand(env_t::moving_object_probability*2); gr->obj_add( new movingobj_t( gr->get_pos(), desc ) ); } } } } } } } } sint8 *humidity; void karte_t::init(settings_t* const sets, sint8 const* const h_field) { humidity = NULL; clear_random_mode( 7 ); mute_sound(true); if (env_t::networkmode) { if (env_t::server) { network_reset_server(); } else { network_core_shutdown(); } } step_mode = PAUSE_FLAG; intr_disable(); if(plan) { destroy(); } for( uint i=0; ichange_world_position( koord(0,0), 0, 0 ); settings = *sets; // names during creation time settings.set_name_language_iso(env_t::language_iso); settings.set_use_timeline(settings.get_use_timeline() & 1); ticks = 0; last_step_ticks = ticks; schedule_counter = 0; // ticks = 0x7FFFF800; // Testing the 31->32 bit step last_month = 0; last_year = settings.get_starting_year(); current_month = last_month + (last_year*12); set_ticks_per_world_month_shift(settings.get_bits_per_month()); next_month_ticks = karte_t::ticks_per_world_month; season=(2+last_month/3)&3; // summer always zero steps = 0; network_frame_count = 0; sync_steps = 0; sync_steps_barrier = sync_steps; map_counter = 0; recalc_average_speed(); // resets timeline koord::locality_factor = settings.get_locality_factor( last_year ); max_allowed_height = sets->get_maximumheight(); min_allowed_height = sets->get_minimumheight(); groundwater = (sint8)sets->get_groundwater(); init_height_to_climate(); snowline = sets->get_winter_snowline() + groundwater; if(sets->get_beginner_mode()) { goods_manager_t::set_multiplier(settings.get_beginner_price_factor()); settings.set_just_in_time( 0 ); } else { goods_manager_t::set_multiplier( 1000 ); } recalc_season_snowline(false); cities.clear(); DBG_DEBUG("karte_t::init()","hausbauer_t::new_world()"); // Call this before building cities hausbauer_t::new_world(); cached_grid_size.x = 0; cached_grid_size.y = 0; DBG_DEBUG("karte_t::init()","init_tiles"); init_tiles(); enlarge_map(&settings, h_field); script_api::new_world(); DBG_DEBUG("karte_t::init()","built timeline"); private_car_t::build_timeline_list(this); pedestrian_t::build_timeline_list(this); nosave_warning = nosave = false; dbg->message("karte_t::init()", "Creating factories ..."); factory_builder_t::new_world(); int consecutive_build_failures = 0; loadingscreen_t ls( translator::translate("distributing factories"), 16 + settings.get_city_count() * 4 + settings.get_factory_count(), true, true ); while( fab_list.get_count() < (uint32)settings.get_factory_count() ) { if( !factory_builder_t::increase_industry_density( false ) ) { if( ++consecutive_build_failures > 3 ) { // Industry chain building starts failing consecutively as map approaches full. break; } } else { consecutive_build_failures = 0; } ls.set_progress( 16 + settings.get_city_count() * 4 + min(fab_list.get_count(),settings.get_factory_count()) ); } settings.set_factory_count( fab_list.get_count() ); finance_history_year[0][WORLD_FACTORIES] = finance_history_month[0][WORLD_FACTORIES] = fab_list.get_count(); // tourist attractions factory_builder_t::distribute_attractions(settings.get_tourist_attractions()); dbg->message("karte_t::init()", "Preparing startup ..."); if(zeiger == NULL) { zeiger = new zeiger_t(koord3d::invalid, NULL ); } // finishes the line preparation and sets id 0 to invalid ... players[PLAYER_HUMAN_NR]->simlinemgmt.finish_rd(); set_tool( tool_t::general_tool[TOOL_QUERY], get_active_player() ); recalc_average_speed(); for (int i = 0; i < MAX_PLAYER_COUNT; i++) { if( players[i] ) { players[i]->set_active(true); } } active_player_nr = PLAYER_HUMAN_NR; active_player = players[PLAYER_HUMAN_NR]; tool_t::update_toolbars(); msg->clear(); chat_msg->clear(); set_dirty(); step_mode = PAUSE_FLAG; simloops = 60; reset_timer(); if(is_display_init()) { display_show_pointer(true); } mute_sound(false); } #define array_koord(px,py) (px + py * get_size().x) /* Lakes: * For each height from groundwater+1 to max_lake_height we loop over * all tiles in the map trying to increase water height to this value * To start with every tile in the map is checked - but when we fail for * a tile then it is excluded from subsequent checks */ sint8 *stage; sint8 *new_stage; sint8 *local_stage; sint8 *max_water_hgt; bool need_to_flood; bool global_lake_fill; sint8 h; void karte_t::create_lakes_loop( sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) { const uint16 size_x = get_size().x; const uint16 size_y = get_size().y; if( x_min < 1 ) x_min = 1; if( y_min < 1 ) y_min = 1; if( x_max > size_x-1 ) x_max = size_x-1; if( y_max > size_y-1 ) y_max = size_y-1; bool alternate_stage = false; // false = new data in new_stage, true = new data in stage sint8 *this_stage = stage; // local copy of pointer so we can swap round in thread sint8 *this_new_stage = new_stage; // local copy of pointer so we can swap round in thread for( uint16 y = y_min; y < y_max; y++ ) { for( uint16 x = x_min; x < x_max; x++ ) { uint32 offset = array_koord(x,y); if( h>max_water_hgt[offset] && max_water_hgt[offset]!=-126 && this_stage[offset]==-1 ) { koord k(x,y); if( global_lake_fill == true ) { memcpy( this_new_stage, this_stage, sizeof(sint8) * size_x * size_y ); } else { memcpy( this_new_stage + sizeof(sint8) * array_koord(0,y_min), this_stage + sizeof(sint8) * array_koord(0,y_min), sizeof(sint8) * size_x * (y_max-y_min) ); } bool success = false; if( global_lake_fill == true ) { success = can_flood_to_depth( k, h, this_new_stage, local_stage, 1, size_x-1, 1, size_y-1 ); } else { success = can_flood_to_depth( k, h, this_new_stage, local_stage, x_min, x_max, y_min, y_max ); } if( success ) { if( alternate_stage ) { this_new_stage = new_stage; this_stage = stage; } else { this_new_stage = stage; this_stage = new_stage; } alternate_stage = !alternate_stage; need_to_flood = true; } else { uint32 offset_end = array_koord(0,(global_lake_fill?size_y-1:y_max)); for( uint32 local_offset = array_koord(0,(global_lake_fill?1:y_min)); local_offset -1 ) { max_water_hgt[local_offset] = -126; } } } } } } // ensure global stage reflect local data if( alternate_stage ) { if( global_lake_fill == true ) { sint8 *tmp_stage = new_stage; new_stage = stage; stage = tmp_stage; } else { memcpy( stage + sizeof(sint8) * array_koord(0,y_min), new_stage + sizeof(sint8) * array_koord(0,y_min), sizeof(sint8) * size_x * (y_max-y_min) ); } } } void karte_t::create_lakes( int xoff, int yoff, sint8 max_lake_height ) { if( xoff > 0 || yoff > 0 ) { // too complicated to add lakes to an already existing world... return; } const uint16 size_x = get_size().x; const uint16 size_y = get_size().y; max_water_hgt = new sint8[size_x * size_y]; for( uint16 y = 0; y < size_y; y++ ) { for( uint16 x = 0; x < size_x; x++ ) { uint32 offset = array_koord(x,y); grund_t *gr = lookup_kartenboden_nocheck(x,y); sint8 hgt = gr->get_hoehe(); const sint8 water_hgt = water_hgts[offset]; // optimised <- get_water_hgt_nocheck(x, y); max_water_hgt[offset] = max(hgt, water_hgt); } } stage = new sint8[size_x * size_y]; new_stage = new sint8[size_x * size_y]; local_stage = new sint8[size_x * size_y]; for( h = groundwater+1; hcorrect_water(); } } void karte_t::create_beaches( int xoff, int yoff ) { const uint16 size_x = get_size().x; const uint16 size_y = get_size().y; // bays have wide beaches for( uint16 iy = 0; iy < size_y; iy++ ) { for( uint16 ix = (iy >= yoff - 19) ? 0 : max( xoff - 19, 0 ); ix < size_x; ix++ ) { grund_t *gr = lookup_kartenboden_nocheck(ix,iy); if( gr->is_water() && gr->get_hoehe()==groundwater && gr->kann_alle_obj_entfernen(NULL)==NULL) { koord k( ix, iy ); uint8 neighbour_water = 0; bool water[8] = {}; sint16 total_ground = 0; // check whether nearby tiles are water for( int i = 0; i < 8; i++ ) { if( grund_t *gr2 = lookup_kartenboden( k + koord::neighbours[i] ) ) { total_ground++; if( gr2->hat_weg( water_wt ) ) { // never ever make a beach near a river mound neighbour_water = 8; break; } if( gr2->is_water() ) { water[i] = 1; neighbour_water++; } } } // make a count of nearby tiles - where tiles on opposite (+-1 direction) sides are water these count much more so we don't block straits for( int i = 0; i < 8; i++ ) { if( water[i] ) { if( water[(i + 3) & 7] || water[(i + 4) & 7] || water[(i + 5) & 7] ) { neighbour_water++; } } } // if not much nearby water then turn into a beach if( neighbour_water < (3*total_ground)/4 ) { set_water_hgt_nocheck( k, gr->get_hoehe() - 1 ); raise_grid_to( ix, iy, gr->get_hoehe() ); raise_grid_to( ix + 1, iy, gr->get_hoehe() ); raise_grid_to( ix, iy + 1, gr->get_hoehe() ); raise_grid_to( ix + 1, iy + 1 , gr->get_hoehe() ); access_nocheck(k)->correct_water(); access_nocheck(k)->set_climate( desert_climate ); } } } } // headlands should not have beaches at all for( uint16 iy = 0; iy < size_y; iy++ ) { for( uint16 ix = (iy >= yoff - 19) ? 0 : max( xoff - 19, 0 ); ix < size_x; ix++ ) { koord k( ix, iy ); grund_t *gr = lookup_kartenboden_nocheck(k); if( !gr->is_water() && gr->get_pos().z == groundwater ) { uint8 neighbour_water = 0; for( int i = 0; i < 8; i++ ) { grund_t *gr2 = lookup_kartenboden( k + koord::neighbours[i] ); if( !gr2 || gr2->is_water() ) { neighbour_water++; } } // if a lot of water nearby we are a headland if( neighbour_water > 3 ) { access_nocheck(k)->set_climate( get_climate_at_height( groundwater + 1 ) ); } } } } // remove any isolated 1 tile beaches for( uint16 iy = 0; iy < size_y; iy++ ) { for( uint16 ix = (iy >= yoff - 19) ? 0 : max( xoff - 19, 0 ); ix < size_x; ix++ ) { koord k( ix, iy ); if( access_nocheck(k)->get_climate() == desert_climate ) { uint8 neighbour_beach = 0; //look up neighbouring climates climate neighbour_climate[8]; for( int i = 0; i < 8; i++ ) { koord k_neighbour = k + koord::neighbours[i]; if( !is_within_limits(k_neighbour) ) { k_neighbour = get_closest_coordinate(k_neighbour); } neighbour_climate[i] = get_climate( k_neighbour ); } // get transition climate - look for each corner in turn for( int i = 0; i < 4; i++ ) { climate transition_climate = (climate) max( max( neighbour_climate[(i * 2 + 1) & 7], neighbour_climate[(i * 2 + 3) & 7] ), neighbour_climate[(i * 2 + 2) & 7] ); climate min_climate = (climate) min( min( neighbour_climate[(i * 2 + 1) & 7], neighbour_climate[(i * 2 + 3) & 7] ), neighbour_climate[(i * 2 + 2) & 7] ); if( min_climate <= desert_climate && transition_climate == desert_climate ) { neighbour_beach++; } } if( neighbour_beach == 0 ) { access_nocheck(k)->set_climate( get_climate_at_height( groundwater + 1 ) ); } } } } } void karte_t::distribute_trees_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ) { // now distribute trees DBG_DEBUG("karte_t::init()","distributing trees"); switch (settings.get_tree_distribution()) { case settings_t::TREE_DIST_RAINFALL: if( humidity_map.get_height() != 0 ) { koord pos; for( pos.y=ytop; pos.yobj_count() == 0 && gr->get_typ() == grund_t::boden) { if(humidity_map.at(pos.x,pos.y)>75) { const uint32 tree_probability = (humidity_map.at(pos.x,pos.y) - 75)/5 + 38; uint8 number_to_plant = 0; uint8 const max_trees_here = min(get_settings().get_max_no_of_trees_on_square(), (tree_probability - 38 + 1) / 2); for (uint8 c2 = 0 ; c275) { // plant spare trees, (those with low preffered density) or in an entirely tree climate uint16 cl = 1 << get_climate(pos); settings_t const& s = get_settings(); if ((cl & s.get_no_tree_climates()) == 0 && ((cl & s.get_tree_climates()) != 0 || simrand(s.get_forest_inverse_spare_tree_density() * /*dichte*/3) < 100)) { tree_builder_t::plant_tree_on_coordinate(pos, 1, 1); } } } } } break; } // fall-through case settings_t::TREE_DIST_RANDOM: // no humidity data or on request tree_builder_t::distribute_trees(3, xtop, ytop, xbottom, ybottom ); break; case settings_t::TREE_DIST_NONE: // no trees break; case settings_t::TREE_DIST_COUNT: assert(false); // should not happen break; } } void karte_t::enlarge_map(settings_t const* sets, sint8 const* const h_field) { const koord new_size(sets->get_size_x(), sets->get_size_y()); if( cached_grid_size.y>0 && cached_grid_size.y!=new_size.y ) { // to keep the labels grund_t::enlarge_map( new_size.x, new_size.y ); } planquadrat_t *new_plan = new planquadrat_t[new_size.x*new_size.y]; sint8 *new_grid_hgts = new sint8[(new_size.x + 1) * (new_size.y + 1)]; sint8 *new_water_hgts = new sint8[new_size.x * new_size.y]; memset( new_grid_hgts, groundwater, sizeof(sint8) * (new_size.x + 1) * (new_size.y + 1) ); memset( new_water_hgts, groundwater, sizeof(sint8) * new_size.x * new_size.y ); const koord old_size = get_size(); const bool new_world = old_size.x == 0 && old_size.y == 0; settings.set_size_x(new_size.x); settings.set_size_y(new_size.y); cached_grid_size = new_size; cached_size_max = max(cached_grid_size.x,cached_grid_size.y); cached_size.x = cached_grid_size.x-1; cached_size.y = cached_grid_size.y-1; intr_disable(); const bool minimap_was_visible = minimap_t::is_visible; int max_display_progress; if( !new_world ) { mute_sound(true); minimap_t::is_visible = false; if(is_display_init()) { display_show_pointer(false); } // Copy old values: for (sint16 iy = 0; iyget_city_count()*2 + cities.get_count()*4; } else { max_display_progress = 16 + sets->get_city_count() * 4 + settings.get_factory_count(); } loadingscreen_t ls( translator::translate( new_world ? "Init map ..." : "enlarge map"), max_display_progress, true, true ); delete [] plan; plan = new_plan; delete [] grid_hgts; grid_hgts = new_grid_hgts; delete [] water_hgts; water_hgts = new_water_hgts; if( new_world ) { // init max and min with defaults max_height = groundwater; min_height = groundwater; } setsimrand(0xFFFFFFFF, settings.get_map_number()); clear_random_mode( 0xFFFF ); set_random_mode( MAP_CREATE_RANDOM ); if( new_world && !settings.heightfield.empty() ) { // init from file for(int y=0; yget_rotation()==0 && sets->get_origin_x()==0 && sets->get_origin_y()==0) { // otherwise negative offsets may occur, so we cache only non-rotated maps init_perlin_map(new_size.x,new_size.y); } if ( old_size.x > 0 && old_size.y > 0 ) { // loop only new tiles: for( sint16 y = 0; y<=new_size.y; y++ ) { for( sint16 x = (y>old_size.y) ? 0 : old_size.x+1; x<=new_size.x; x++ ) { koord k(x,y); sint16 const h = perlin_hoehe(&settings, k, koord(old_size.x, old_size.y)); set_grid_hgt_nocheck( k, (sint8) h); } ls.set_progress( (y*16)/new_size.y ); } } else { world_xy_loop(&karte_t::perlin_hoehe_loop, GRIDS_FLAG); ls.set_progress(2); } exit_perlin_map(); } /** @note First we'll copy the border heights to the adjacent tile. * The best way I could find is raising the first new grid point to * the same height the adjacent old grid point was and lowering to the * same height again. This doesn't preserve the old area 100%, but it respects it * somehow. * * This does not work for water tiles as for them get_hoehe will return the * z-coordinate of the water surface, not the height of the underwater * landscape. */ sint32 i; grund_t *gr; sint8 h; if (!new_world) { for(i=0; iis_water()) { h = gr->get_hoehe(slope4_t::corner_SW); raise_grid_to(i, old_size.y+1, h); lower_grid_to(i, old_size.y+1, h ); } } for(i=0; iis_water()) { h = gr->get_hoehe(slope4_t::corner_NE); raise_grid_to(old_size.x+1, i, h); lower_grid_to(old_size.y+1, i, h); } } gr = lookup_kartenboden_nocheck(old_size.x-1, old_size.y -1); if (!gr->is_water()) { h = gr->get_hoehe(slope4_t::corner_SE); raise_grid_to(old_size.x+1, old_size.y+1, h); lower_grid_to(old_size.x+1, old_size.y+1, h); } } // smooth the new part, reassign slopes on new part cleanup_karte( old_size.x, old_size.y ); if ( new_world ) { ls.set_progress(10); } // update height bounds for( sint16 iy = 0; iy < new_size.y; iy++ ) { for( sint16 ix = (iy >= old_size.y) ? 0 : max( old_size.x, 0 ); ix < new_size.x; ix++ ) { sint8 hgt = lookup_kartenboden_nocheck(ix, iy)->get_hoehe(); if (hgt < min_height) { min_height = hgt; } if (hgt > max_height) { max_height = hgt; } } } if ( new_world ) { ls.set_progress(12); } DBG_DEBUG("karte_t::distribute_groundobjs_cities()","distributing rivers"); if( sets->get_lakeheight() > get_groundwater() ) { create_lakes( old_size.x, old_size.y, sets->get_lakeheight() ); } // so at least some rivers end or start in lakes if( env_t::river_types > 0 && settings.get_river_number() > 0 ) { create_rivers( settings.get_river_number() ); } if ( new_world ) { ls.set_progress(13); } // set climates in new area if( new_world ) { calc_climate_map_region( 0, 0, new_size.x, new_size.y ); } else { calc_climate_map_region( 0, old_size.y, old_size.x, new_size.y ); calc_climate_map_region( old_size.x, 0, new_size.x, new_size.y ); } if ( new_world ) { ls.set_progress(14); } create_beaches( old_size.x, old_size.y ); if ( new_world ) { ls.set_progress(15); } if ( new_world ) { // new world -> calculate all transitions world_xy_loop(&karte_t::recalc_transitions_loop, 0); ls.set_progress(16); } else { // and calculate transitions in a 1 tile larger area for( sint16 iy = 0; iy < new_size.y; iy++ ) { for( sint16 ix = (iy >= old_size.y - 20) ? 0 : max( old_size.x - 20, 0 ); ix < new_size.x; ix++ ) { recalc_transitions( koord( ix, iy ) ); } } } // now recalc the images of the old map near the seam ... for( sint16 y = 0; y < old_size.y - 20; y++ ) { for( sint16 x = max( old_size.x - 20, 0 ); x < old_size.x; x++ ) { lookup_kartenboden_nocheck(x,y)->calc_image(); } } for( sint16 y = max( old_size.y - 20, 0 ); y < old_size.y; y++) { for( sint16 x = 0; x < old_size.x; x++ ) { lookup_kartenboden_nocheck(x,y)->calc_image(); } } distribute_cities( sets->get_city_count(), sets->get_mean_citizen_count(), old_size.x, old_size.y ); if( new_world ) { distribute_trees_region( 0, 0, new_size.x, new_size.y ); } else { distribute_trees_region( 0, old_size.y, old_size.x, new_size.y ); distribute_trees_region( old_size.x, 0, new_size.x, new_size.y ); } humidity_map.clear(); // eventual update origin switch( settings.get_rotation() ) { case 1: { settings.set_origin_y( settings.get_origin_y() - new_size.y + old_size.y ); break; } case 2: { settings.set_origin_x( settings.get_origin_x() - new_size.x + old_size.x ); settings.set_origin_y( settings.get_origin_y() - new_size.y + old_size.y ); break; } case 3: { settings.set_origin_x( settings.get_origin_x() - new_size.y + old_size.y ); break; } } distribute_groundobjs(old_size.x, old_size.y); distribute_movingobjs(old_size.x, old_size.y); // hausbauer_t::new_world(); <- this would reinit monuments! do not do this! factory_builder_t::new_world(); set_schedule_counter(); // Refresh the haltlist for the affected tiles / stations. // It is enough to check the tile just at the border ... uint16 const cov = settings.get_station_coverage(); if( old_size.y < new_size.y ) { for( sint16 y=0; yget_boden_count(); i++ ) { // update halt halthandle_t h = pl->get_boden_bei(i)->get_halt(); if( h.is_bound() ) { for( sint16 xp=max(0,x-cov); xpadd_to_haltlist(h); } } } } } } } if( old_size.x < new_size.x ) { for( sint16 y=max(0,old_size.y-cov); yget_boden_count(); i++ ) { // update halt halthandle_t h = pl->get_boden_bei(i)->get_halt(); if( h.is_bound() ) { for( sint16 xp=x; xpadd_to_haltlist(h); } } } } } } } clear_random_mode( MAP_CREATE_RANDOM ); if ( !new_world ) { if(is_display_init()) { display_show_pointer(true); } mute_sound(false); minimap_t::is_visible = minimap_was_visible; minimap_t::get_instance()->init(); minimap_t::get_instance()->calc_map(); minimap_t::get_instance()->set_display_mode( minimap_t::get_instance()->get_display_mode() ); set_dirty(); reset_timer(); } // update main menu tool_t::update_toolbars(); } karte_t::karte_t() : settings(env_t::default_settings), convoi_array(0), attractions(16), cities(0) { destroying = false; // length of day and other time stuff ticks_per_world_month_shift = 20; ticks_per_world_month = (1 << ticks_per_world_month_shift); last_step_ticks = 0; server_last_announce_time = 0; last_interaction = dr_time(); step_mode = PAUSE_FLAG; time_multiplier = 16; next_midi_time = next_step_time = next_misc_time = 0; fix_ratio_frame_time = 200; idle_time = 0; network_frame_count = 0; sync_steps = 0; sync_steps_barrier = sync_steps; for( uint i=0; imsg); // generate ground textures once ground_desc_t::init_ground_textures(this); // set single instance world = this; } karte_t::~karte_t() { is_sound = false; destroy(); // not deleting the tools of this map ... delete viewport; delete msg; delete records; // unset single instance if (world == this) { world = NULL; } } void karte_t::store_player_password_hash( uint8 player_nr, const pwd_hash_t& hash ) { player_password_hash[player_nr] = hash; } void karte_t::clear_player_password_hashes() { for(int i=0; icheck_unlock(player_password_hash[i]); } } } void karte_t::rdwr_player_password_hashes(loadsave_t *file) { pwd_hash_t dummy; for( int i=0; iaccess_password_hash() : &dummy; for( uint8 j=0; j<20; j++) { file->rdwr_byte( (*p)[j] ); } } } void karte_t::call_change_player_tool(uint8 cmd, uint8 player_nr, uint16 param, bool scripted_call) { if (env_t::networkmode) { nwc_chg_player_t *nwc = new nwc_chg_player_t(sync_steps, map_counter, cmd, player_nr, param, scripted_call); network_send_server(nwc); } else { clear_random_mode(INTERACTIVE_RANDOM); // beacue the AI will call random to check where it can run change_player_tool(cmd, player_nr, param, !get_public_player()->is_locked() || scripted_call, true); // update the window ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t); if (playerwin) { playerwin->update_data(); } } } bool karte_t::change_player_tool(uint8 cmd, uint8 player_nr, uint16 param, bool public_player_unlocked, bool exec) { switch(cmd) { case new_player: { // only public player can start AI if( (param != player_t::HUMAN && !public_player_unlocked) || param >= player_t::MAX_AI ) { return false; } // range check, player already existent? if( player_nr >= PLAYER_UNOWNED || get_player(player_nr) ) { return false; } if(exec) { init_new_player( player_nr, (uint8) param ); // activate/deactivate AI immediately player_t *player = get_player(player_nr); if (param != player_t::HUMAN && player) { player->set_active(true); } } return true; } case toggle_player_active: { // range check, player existent? if ( player_nr <=1 || player_nr >= PLAYER_UNOWNED || get_player(player_nr)==NULL ) { return false; } // only public player can (de)activate other players if ( !public_player_unlocked ) { return false; } if (exec) { player_t *player = get_player(player_nr); player->set_active(param != 0); } return true; } case toggle_freeplay: { // only public player can change freeplay mode if (!public_player_unlocked || !settings.get_allow_player_change()) { return false; } if (exec) { settings.set_freeplay( !settings.is_freeplay() ); } return true; } case delete_player: { // range check, player existent? if ( player_nr >= PLAYER_UNOWNED || get_player(player_nr)==NULL ) { return false; } if (exec) { remove_player(player_nr); } return true; } // unknown command: delete default: ; } return false; } void karte_t::set_tool_api( tool_t *tool_in, player_t *player, bool& suspended) { suspended = false; if( get_random_mode()&LOAD_RANDOM ) { dbg->warning("karte_t::set_tool", "Ignored tool %s during loading.", tool_in->get_name() ); return; } bool needs_check = !tool_in->no_check(); // check for scenario conditions if( needs_check && !scenario->is_tool_allowed(player, tool_in->get_id(), tool_in->get_waytype(), tool_in->get_default_param()) ) { return; } // check for password-protected players if( (!tool_in->is_init_keeps_game_state() || !tool_in->is_work_keeps_game_state()) && needs_check && !(tool_in->get_id() == (DIALOG_LOAD | DIALOGE_TOOL) || tool_in->get_id() == (TOOL_CHANGE_PLAYER | SIMPLE_TOOL) || tool_in->get_id()==(TOOL_ADD_MESSAGE | GENERAL_TOOL)) && player && player->is_locked() ) { // player is currently password protected => request unlock first create_win(new password_frame_t(player), w_info, magic_pwd_t + player->get_player_nr() ); return; } tool_in->flags |= (event_get_last_control_shift() ^ tool_t::control_invert); if(!env_t::networkmode || tool_in->is_local_execution() || tool_in->is_init_keeps_game_state() ) { if (tool_in->is_init_keeps_game_state() || (get_random_mode() & INTERACTIVE_RANDOM) == 0) { // network safe or not during sync_step: call directly local_set_tool(tool_in, player); } else { // queue tool for execution nwc_tool_t* nwc = new nwc_tool_t(player, tool_in, zeiger->get_pos(), 0, map_counter, true); command_queue_append(nwc); suspended = true; } } else { // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(player, tool_in, zeiger->get_pos(), steps, map_counter, true); network_send_server(nwc); suspended = true; } } // set a new tool on our client, calls init void karte_t::local_set_tool( tool_t *tool_in, player_t * player ) { tool_in->flags |= tool_t::WFL_LOCAL; // now call init bool init_result = tool_in->init(player); // for unsafe tools init() must return false assert(tool_in->is_init_keeps_game_state() || !init_result); if (player && init_result && !tool_in->is_scripted()) { set_dirty(); tool_t *sp_tool = selected_tool[player->get_player_nr()]; if(tool_in != sp_tool) { // reinit same tool => do not play sound twice sound_play(SFX_SELECT,255,TOOL_SOUND); // only exit, if it is not the same tool again ... sp_tool->flags |= tool_t::WFL_LOCAL; sp_tool->exit(player); sp_tool->flags =0; } if( player==active_player ) { // reset pointer koord3d zpos = zeiger->get_pos(); // remove marks zeiger->change_pos( koord3d::invalid ); // set new cursor properties tool_in->init_cursor(zeiger); // .. and mark again (if the position is acceptable for the tool) if( tool_in->check_valid_pos(zpos.get_2d())) { zeiger->change_pos( zpos ); } else { zeiger->change_pos( koord3d::invalid ); } } selected_tool[player->get_player_nr()] = tool_in; } tool_in->flags = 0; toolbar_last_used_t::last_used_tools->append( tool_in, player ); } planquadrat_t *rotate90_new_plan; sint8 *rotate90_new_water; void karte_t::rotate90_plans(sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max) { const int LOOP_BLOCK = 64; if( (loaded_rotation + settings.get_rotation()) & 1 ) { // 1 || 3 for( int yy = y_min; yy < y_max; yy += LOOP_BLOCK ) { for( int xx = x_min; xx < x_max; xx += LOOP_BLOCK ) { for( int y = yy; y < min(yy + LOOP_BLOCK, y_max); y++ ) { for( int x = xx; x < min(xx + LOOP_BLOCK, x_max); x++ ) { const int nr = x + (y * cached_grid_size.x); const int new_nr = (cached_size.y - y) + (x * cached_grid_size.y); // first rotate everything on the ground(s) for( uint i = 0; i < plan[nr].get_boden_count(); i++ ) { plan[nr].get_boden_bei(i)->rotate90(); } // rotate climate transitions rotate_transitions( koord( x, y ) ); // now: rotate all things on the map swap(rotate90_new_plan[new_nr], plan[nr]); } } } } } else { // first: rotate all things on the map for( int xx = x_min; xx < x_max; xx += LOOP_BLOCK ) { for( int yy = y_min; yy < y_max; yy += LOOP_BLOCK ) { for( int x = xx; x < min(xx + LOOP_BLOCK, x_max); x++ ) { for( int y=yy; y < min(yy + LOOP_BLOCK, y_max); y++ ) { // rotate climate transitions rotate_transitions( koord( x, y ) ); const int nr = x + (y * cached_grid_size.x); const int new_nr = (cached_size.y - y) + (x * cached_grid_size.y); swap(rotate90_new_plan[new_nr], plan[nr]); } } } } // now rotate everything on the ground(s) for( int xx = x_min; xx < x_max; xx += LOOP_BLOCK ) { for( int yy = y_min; yy < y_max; yy += LOOP_BLOCK ) { for( int x = xx; x < min(xx + LOOP_BLOCK, x_max); x++ ) { for( int y = yy; y < min(yy + LOOP_BLOCK, y_max); y++ ) { const int new_nr = (cached_size.y - y) + (x * cached_grid_size.y); for( uint i = 0; i < rotate90_new_plan[new_nr].get_boden_count(); i++ ) { rotate90_new_plan[new_nr].get_boden_bei(i)->rotate90(); } } } } } } // rotate water for( int xx = 0; xx < cached_grid_size.x; xx += LOOP_BLOCK ) { for( int yy = y_min; yy < y_max; yy += LOOP_BLOCK ) { for( int x = xx; x < min( xx + LOOP_BLOCK, cached_grid_size.x ); x++ ) { int nr = x + (yy * cached_grid_size.x); int new_nr = (cached_size.y - yy) + (x * cached_grid_size.y); for( int y = yy; y < min( yy + LOOP_BLOCK, y_max ); y++ ) { rotate90_new_water[new_nr] = water_hgts[nr]; nr += cached_grid_size.x; new_nr--; } } } } } void karte_t::rotate90() { DBG_MESSAGE( "karte_t::rotate90()", "called" ); // assume we can save this rotation nosave_warning = nosave = false; //announce current target rotation settings.rotate90(); // clear marked region zeiger->change_pos( koord3d::invalid ); // preprocessing, detach stops from factories to prevent crash for(halthandle_t const s : haltestelle_t::get_alle_haltestellen()) { s->release_factory_links(); } //rotate plans in parallel posix thread ... rotate90_new_plan = new planquadrat_t[cached_grid_size.y * cached_grid_size.x]; rotate90_new_water = new sint8[cached_grid_size.y * cached_grid_size.x]; world_xy_loop(&karte_t::rotate90_plans, 0); grund_t::finish_rotate90(); delete [] plan; plan = rotate90_new_plan; delete[] water_hgts; water_hgts = rotate90_new_water; climate_map.rotate90(); // rotate heightmap sint8* new_hgts = new sint8[(cached_grid_size.x + 1) * (cached_grid_size.y + 1)]; const int LOOP_BLOCK = 64; for (int yy = 0; yy <= cached_grid_size.y; yy += LOOP_BLOCK) { for (int xx = 0; xx <= cached_grid_size.x; xx += LOOP_BLOCK) { for (int x = xx; x <= min(xx + LOOP_BLOCK, cached_grid_size.x); x++) { for (int y = yy; y <= min(yy + LOOP_BLOCK, cached_grid_size.y); y++) { const int nr = x + (y * (cached_grid_size.x + 1)); const int new_nr = (cached_grid_size.y - y) + (x * (cached_grid_size.y + 1)); new_hgts[new_nr] = grid_hgts[nr]; } } } } delete[] grid_hgts; grid_hgts = new_hgts; // rotate borders sint16 xw = cached_size.x; cached_size.x = cached_size.y; cached_size.y = xw; int wx = cached_grid_size.x; cached_grid_size.x = cached_grid_size.y; cached_grid_size.y = wx; // now step all towns (to generate passengers) for (stadt_t* const i : cities) { i->rotate90(cached_size.x); } // fixed order factory, halts, convois for (fabrik_t* const f : fab_list) { f->rotate90(cached_size.x); } // after rotation of factories, rotate everything that holds freight: stations and convoys for (halthandle_t const s : haltestelle_t::get_alle_haltestellen()) { s->rotate90(cached_size.x); } for (convoihandle_t const i : convoi_array) { i->rotate90(cached_size.x); } for (int i = 0; i < MAX_PLAYER_COUNT; i++) { if (players[i]) { players[i]->rotate90(cached_size.x); } } // rotate label texts for (koord& l : labels) { l.rotate90(cached_size.x); } // rotate view viewport->rotate90(cached_size.x); // rotate messages msg->rotate90(cached_size.x); // rotate view in dialog windows win_rotate90(cached_size.x); if (cached_grid_size.x != cached_grid_size.y) { // the map must be reinit minimap_t::get_instance()->init(); } // rotate map search array factory_builder_t::new_world(); // update minimap if (minimap_t::is_visible) { minimap_t::get_instance()->set_display_mode(minimap_t::get_instance()->get_display_mode()); } get_scenario()->rotate90(cached_size.x); script_api::rotate90(); // finally recalculate schedules for goods in transit ... set_schedule_counter(); set_dirty(); } // -------- Verwaltung von Fabriken ----------------------------- bool karte_t::add_fab(fabrik_t* fab) { //DBG_MESSAGE("karte_t::add_fab()","fab = %p",fab); assert(fab != NULL); fab_list.insert(fab); goods_in_game.clear(); // Force rebuild of goods list if (factorylist_frame_t* f = (factorylist_frame_t*)win_get_magic(magic_factorylist)) { f->fill_list(); } return true; } // beware: must remove also links from stops and towns bool karte_t::rem_fab(fabrik_t *fab) { if(!fab_list.remove( fab )) { return false; } // Force rebuild of goods list goods_in_game.clear(); // now all the interwoven connections must be cleared koord k = fab->get_pos().get_2d(); planquadrat_t* plan = access(k); if(plan) { // we need a copy, since the verbinde fabriken is modifying the list halthandle_t list[16]; const uint8 count = plan->get_haltlist_count(); assert(count<16); assert((count == 0) || (plan->get_haltlist() != NULL)); if (count > 0) { memcpy( list, plan->get_haltlist(), count*sizeof(halthandle_t) ); for( uint8 i=0; iremove_from_haltlist( list[i] ); // then reconnect list[i]->verbinde_fabriken(); } } // remove all links from factories for(fabrik_t* const fab : fab_list) { fab->remove_consumer(k); fab->remove_supplier(k); } // remove all links to cities fab->clear_target_cities(); // finally delete it delete fab; // recalculate factory position map factory_builder_t::new_world(); } if (factorylist_frame_t* f = (factorylist_frame_t *)win_get_magic(magic_factorylist)) { f->fill_list(); } return true; } /*----------------------------------------------------------------------------------------------------------------------*/ /* same procedure for tourist attractions */ void karte_t::add_attraction(gebaeude_t *gb) { assert(gb != NULL); attractions.append( gb, gb->get_tile()->get_desc()->get_level() ); // add links between this attraction and all cities for(stadt_t* const c : cities) { c->add_target_attraction(gb); } if (curiositylist_frame_t *f = (curiositylist_frame_t*)win_get_magic(magic_curiositylist)) { f->fill_list(); } } void karte_t::remove_attraction(gebaeude_t *gb) { assert(gb != NULL); attractions.remove( gb ); // remove links between this attraction and all cities for(stadt_t* const c : cities) { c->remove_target_attraction(gb); } if (curiositylist_frame_t *f = (curiositylist_frame_t*)win_get_magic(magic_curiositylist)) { f->fill_list(); } } void karte_t::add_label(koord k) { labels.append_unique(k); if (labellist_frame_t* f = (labellist_frame_t*)win_get_magic(magic_labellist)) { f->fill_list(); } } void karte_t::remove_label(koord k) { labels.remove(k); if (labellist_frame_t* f = (labellist_frame_t*)win_get_magic(magic_labellist)) { f->fill_list(); } } // -------- Verwaltung von Staedten ----------------------------- stadt_t *karte_t::find_nearest_city(const koord k) const { uint32 min_dist = 99999999; bool contains = false; stadt_t *best = NULL; // within city limits if( is_within_limits(k) ) { for(stadt_t* const s : cities ) { if( k.x >= s->get_linksoben().x && k.y >= s->get_linksoben().y && k.x < s->get_rechtsunten().x && k.y < s->get_rechtsunten().y ) { const uint32 dist = koord_distance( k, s->get_center() ); if( !contains ) { // no city within limits => this is best best = s; min_dist = dist; } else if( dist < min_dist ) { best = s; min_dist = dist; } contains = true; } else if( !contains ) { // so far no cities found within its city limit const uint32 dist = koord_distance( k, s->get_center() ); if( dist < min_dist ) { best = s; min_dist = dist; } } } } return best; } /* * this routine is called before an image is displayed * it moves vehicles and pedestrians * only time consuming thing are done in step() * everything else is done here */ void karte_t::sync_step(uint32 delta_t) { set_random_mode( SYNC_STEP_RANDOM ); // only omitted, when called to display a new frame during fast forward // just for progress if( delta_t > 10000 ) { dbg->error( "karte_t::sync_step()", "delta_t (%u) too large, limiting to 10000", delta_t ); delta_t = 10000; } ticks += delta_t; /* animations do not require exact sync * foundations etc are added removed frequently during city growth */ sync_buildings.sync_step(delta_t); wolke_t::sync_handler(delta_t); pedestrian_t::sync_handler(delta_t); // the following sync_steps affect the game state sync_roadsigns.sync_step(delta_t); movingobj_t::sync_handler(delta_t); private_car_t::sync_handler(delta_t); senke_t::sync_handler(delta_t); sync.sync_step( delta_t ); ticker::update(); clear_random_mode( SYNC_STEP_RANDOM ); set_random_mode( INTERACTIVE_RANDOM ); eventmanager->check_events(); clear_random_mode( INTERACTIVE_RANDOM ); } void karte_t::display(uint32 delta_t) { set_random_mode( SYNC_STEP_RANDOM ); // only omitted in fast forward mode for the magic steps for(int x=0; xage_messages(delta_t); } } // change view due to following a convoi? convoihandle_t follow_convoi = viewport->get_follow_convoi(); if(follow_convoi.is_bound() && follow_convoi->get_vehicle_count()>0) { vehicle_t const& v = *follow_convoi->front(); koord3d const new_pos = v.get_pos(); if(new_pos!=koord3d::invalid) { const sint16 rw = get_tile_raster_width(); int new_xoff = 0; int new_yoff = 0; v.get_screen_offset( new_xoff, new_yoff, get_tile_raster_width() ); new_xoff -= tile_raster_scale_x(-v.get_xoff(), rw); new_yoff -= tile_raster_scale_y(-v.get_yoff(), rw) + tile_raster_scale_y(new_pos.z * TILE_HEIGHT_STEP, rw); viewport->change_world_position( new_pos.get_2d(), -new_xoff, -new_yoff ); // auto underground to follow convois if( env_t::follow_convoi_underground ) { grund_t *gr = lookup_kartenboden( new_pos.get_2d() ); bool redraw = false; if( new_pos.z < gr->get_hoehe() ) { redraw = (grund_t::underground_mode != grund_t::ugm_level) || (grund_t::underground_level != new_pos.z); grund_t::set_underground_mode( grund_t::ugm_level, new_pos.z ); } else { redraw = grund_t::underground_mode != grund_t::ugm_none; grund_t::set_underground_mode( grund_t::ugm_none, 0 ); } if( redraw ) { // recalc all images on map update_underground(); } } } } // display new frame with water animation intr_refresh_display( false ); update_frame_sleep_time(); clear_random_mode( SYNC_STEP_RANDOM ); } // does all the magic about frame timing void karte_t::update_frame_sleep_time() { // get average frame time uint32 frame_end_time = dr_time(); last_frame_ms[last_frame_idx] = frame_end_time; last_frame_idx = (last_frame_idx+1) % 32; sint32 ms_diff = (sint32)( frame_end_time - last_frame_ms[last_frame_idx] ); if(ms_diff > 0) { realFPS = (32000u*16) / ms_diff; } else { realFPS = env_t::fps*16; simloops = 60; } if( step_mode&PAUSE_FLAG ) { // calculate next frame start time based on last frame start // setting next_step_time = frame_end_time + 1000/env_t::fps would would sleep way too long next_step_time = std::max(frame_end_time, next_step_time + 1000 / env_t::fps); idle_time = 100; } else if( step_mode==FIX_RATIO) { simloops = realFPS/16; } else if(step_mode==NORMAL) { // calculate simloops uint16 last_step = (steps+31)%32; if(last_step_nr[last_step]>last_step_nr[steps%32]) { simloops = (10000*32l)/(last_step_nr[last_step]-last_step_nr[steps%32]); } // (de-)activate faster redraw env_t::simple_drawing = (env_t::simple_drawing_normal >= get_tile_raster_width()); // calculate and activate fast redraw .. if( realFPS > (env_t::fps*17/16) ) { // decrease fast tile zoom by one if( env_t::simple_drawing_normal > env_t::simple_drawing_default ) { env_t::simple_drawing_normal --; } } else if( realFPS < env_t::fps*16/2 ) { // activate simple redraw env_t::simple_drawing_normal = max( env_t::simple_drawing_normal, get_tile_raster_width()+1 ); } else if( realFPS < (env_t::fps*15) ) { // increase fast tile redraw by one if below current tile size if( env_t::simple_drawing_normal <= (get_tile_raster_width()*3)/2 ) { env_t::simple_drawing_normal ++; } } else if( idle_time > 0 ) { // decrease fast tile zoom by one if( env_t::simple_drawing_normal > env_t::simple_drawing_default ) { env_t::simple_drawing_normal --; } } env_t::simple_drawing = (env_t::simple_drawing_normal >= get_tile_raster_width()); // way too slow => try to increase time ... if( frame_end_time-last_interaction > 100 ) { if( frame_end_time-last_interaction > 500 ) { idle_time >>= 1; set_frame_time( 1+get_frame_time() ); // more than 1s since last zoom => check if zoom out is a way to improve it if( frame_end_time-last_interaction > 5000 && get_current_tile_raster_width() < 32 && realFPS <= 80 ) { zoom_factor_up(); viewport->metrics_updated(); set_dirty(); last_interaction = frame_end_time-1000; } } else { increase_frame_time(); increase_frame_time(); increase_frame_time(); increase_frame_time(); } } else { // change frame spacing ... (pause will be changed by step() directly) if(realFPS>(env_t::fps*17)) { increase_frame_time(); } else if(realFPSframe_intervall) { reduce_frame_time(); } else { increase_frame_time(); } // (de-)activate faster redraw env_t::simple_drawing = env_t::simple_drawing_fast_forward || (env_t::simple_drawing_normal >= get_tile_raster_width()); } } // add an amount to a subcategory void karte_t::buche(sint64 const betrag, player_cost const type) { assert(type < MAX_WORLD_COST); finance_history_year[0][type] += betrag; finance_history_month[0][type] += betrag; // to do: check for dependencies } inline sint32 get_population(stadt_t const* const c) { return c->get_einwohner(); } void karte_t::new_month() { bool need_locality_update = false; update_history(); // advance history ... last_month_bev = finance_history_month[ 0 ][ WORLD_CITIZENS ]; for( int hist = 0; hist < karte_t::MAX_WORLD_COST; hist++ ) { for( int y = MAX_WORLD_HISTORY_MONTHS - 1; y > 0; y-- ) { finance_history_month[ y ][ hist ] = finance_history_month[ y - 1 ][ hist ]; } } current_month++; last_month++; if( last_month > 11 ) { last_month = 0; // check for changed distance weight uint32 old_locality_factor = koord::locality_factor; koord::locality_factor = settings.get_locality_factor( last_year + 1 ); need_locality_update = (old_locality_factor != koord::locality_factor); if( current_month > DEFAULT_RETIRE_DATE * 12 ) { // switch off timeline after 2999, since everything retires settings.set_use_timeline( 0 ); dbg->warning( "karte_t::new_month()", "Timeline disabled after the year 2999" ); } } DBG_MESSAGE( "karte_t::new_month()", "Month (%d/%d) has started", (last_month % 12) + 1, last_month / 12 ); // this should be done before a map update, since the map may want an update of the way usage for(weg_t* const w : weg_t::get_alle_wege() ) { w->new_month(); } // recalc old settings (and maybe update the stops with the current values) minimap_t::get_instance()->new_month(); INT_CHECK( "simworld 1701" ); // DBG_MESSAGE("karte_t::new_month()","factories"); for(fabrik_t* const fab : fab_list) { fab->new_month(); } INT_CHECK("simworld 1278"); // DBG_MESSAGE("karte_t::new_month()","cities"); cities.update_weights(get_population); for(stadt_t* const i : cities) { i->new_month(need_locality_update); } INT_CHECK("simworld 1282"); // player for(uint i=0; i=2 && last_month == 0 && !settings.is_freeplay() ) { // remove all player (but first and second) who went bankrupt during last year if( players[i] != NULL && players[i]->get_finance()->is_bancrupted() ) { remove_player(i); } } if( players[i] != NULL ) { // if returns false -> remove player if (!players[i]->new_month()) { remove_player(i); } } } // DBG_MESSAGE("karte_t::new_month()","convois"); // call new month for convois, must be after player, because fixed costs are booked here and to connected lines for(convoihandle_t const cnv : convoi_array) { cnv->new_month(); } INT_CHECK("simworld 1701"); // update the window if( ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t) ) { playerwin->update_data(); } INT_CHECK("simworld 1289"); // DBG_MESSAGE("karte_t::new_month()","halts"); for(halthandle_t const s : haltestelle_t::get_alle_haltestellen()) { s->new_month(); INT_CHECK("simworld 1877"); } INT_CHECK("simworld 2522"); depot_t::new_month(); scenario->new_month(); // now switch year to get the right year for all timeline stuff ... if( last_month == 0 ) { new_year(); INT_CHECK("simworld 1299"); } way_builder_t::new_month(); INT_CHECK("simworld 1299"); recalc_average_speed(); INT_CHECK("simworld 1921"); // update toolbars (i.e. new waytypes tool_t::update_toolbars(); // no autosave in networkmode or when the new world dialogue is shown if( !env_t::networkmode && env_t::autosave>0 && last_month%env_t::autosave==0 && !win_get_magic(magic_welt_gui_t) ) { cbuffer_t buf; dr_chdir(env_t::user_dir); // make sure we are in the right directory buf.printf( SAVE_PATH_X "autosave%02i.sve", last_month+1 ); save( buf, true, env_t::savegame_version_str, true ); } } void karte_t::new_year() { last_year = current_month/12; // advance history ... for( int hist=0; hist0; y-- ) { finance_history_year[y][hist] = finance_history_year[y-1][hist]; } } DBG_MESSAGE("karte_t::new_year()","speedbonus for %d %i, %i, %i, %i, %i, %i, %i, %i", last_year, average_speed[0], average_speed[1], average_speed[2], average_speed[3], average_speed[4], average_speed[5], average_speed[6], average_speed[7] ); cbuffer_t buf; buf.printf( translator::translate("Year %i has started."), last_year ); msg->add_message(buf,koord3d::invalid,message_t::general,SYSCOL_TEXT,skinverwaltung_t::neujahrsymbol->get_image_id(0)); for(convoihandle_t const cnv : convoi_array) { cnv->new_year(); } for(int i=0; inew_year(); } } scenario->new_year(); } // recalculated speed bonus for different vehicles // and takes care of all timeline stuff void karte_t::recalc_average_speed() { // retire/allocate vehicles private_car_t::build_timeline_list(this); pedestrian_t::build_timeline_list(this); for(int i=road_wt; i<=narrowgauge_wt; i++) { const int typ = i==4 ? 3 : (i-1)&7; average_speed[typ] = vehicle_builder_t::get_speedbonus( this->get_timeline_year_month(), i==4 ? air_wt : (waytype_t)i ); } // DBG_MESSAGE("karte_t::recalc_average_speed()",""); if(use_timeline()) { for(int i=road_wt; i<=air_wt; i++) { const char *vehicle_type=NULL; switch(i) { case road_wt: vehicle_type = "road vehicle"; break; case track_wt: vehicle_type = "rail car"; break; case water_wt: vehicle_type = "water vehicle"; break; case monorail_wt: vehicle_type = "monorail vehicle"; break; case tram_wt: vehicle_type = "street car"; break; case air_wt: vehicle_type = "airplane"; break; case maglev_wt: vehicle_type = "maglev vehicle"; break; case narrowgauge_wt: vehicle_type = "narrowgauge vehicle"; break; default: // this is not a valid waytype continue; } vehicle_type = translator::translate( vehicle_type ); bool vehicle_changed = false; for(vehicle_desc_t const* const info : vehicle_builder_t::get_info((waytype_t)i)) { const uint16 intro_month = info->get_intro_year_month(); if(intro_month == current_month) { cbuffer_t buf; buf.printf( translator::translate("New %s now available:\n%s\n"), vehicle_type, translator::translate(info->get_name()) ); msg->add_message(buf,koord3d::invalid,message_t::new_vehicle,NEW_VEHICLE,info->get_base_image()); vehicle_changed = true; } const uint16 retire_month = info->get_retire_year_month(); if(retire_month == current_month) { cbuffer_t buf; buf.printf( translator::translate("Production of %s has been stopped:\n%s\n"), vehicle_type, translator::translate(info->get_name()) ); msg->add_message(buf,koord3d::invalid,message_t::new_vehicle,NEW_VEHICLE,info->get_base_image()); vehicle_changed = true; } } if (vehicle_changed) { if (vehiclelist_frame_t* f = (vehiclelist_frame_t*)win_get_magic(magic_vehiclelist)) { f->fill_list(); } } } // city road (try to use always a timeline) if (way_desc_t const* city_road_test = settings.get_city_road_type(current_month) ) { city_road = city_road_test; } else { DBG_MESSAGE("karte_t::new_month()","Month %d has started", last_month); city_road = way_builder_t::weg_search(road_wt,50,get_timeline_year_month(),type_flat); } weg_t::set_cityroad_speedlimit(settings.get_city_road_speed_limit(get_timeline_year_month() / 12)); } else { // defaults city_road = settings.get_city_road_type(0); if(city_road==NULL) { city_road = way_builder_t::weg_search(road_wt,50,0,type_flat); } weg_t::set_cityroad_speedlimit(50); } } // returns the current speed record sint32 karte_t::get_record_speed( waytype_t w ) const { return records->get_record_speed(w); } // sets the new speed record void karte_t::notify_record( convoihandle_t cnv, sint32 max_speed, koord3d k ) { records->notify_record(cnv, max_speed, k, current_month); } void karte_t::set_schedule_counter() { // do not call this from gui when playing in network mode! assert( (get_random_mode() & INTERACTIVE_RANDOM) == 0 ); schedule_counter++; } void karte_t::step() { DBG_DEBUG4("karte_t::step", "start step"); uint32 step_start_time = dr_time(); // calculate delta_t before handling overflow in ticks uint32 delta_t = ticks - last_step_ticks; // first: check for new month if(ticks > next_month_ticks) { if( next_month_ticks > next_month_ticks+karte_t::ticks_per_world_month ) { // avoid overflow here ... dbg->warning("karte_t::step()", "Ticks were overflowing => reset"); ticks %= karte_t::ticks_per_world_month; next_month_ticks %= karte_t::ticks_per_world_month; } next_month_ticks += karte_t::ticks_per_world_month; DBG_DEBUG4("karte_t::step", "calling new_month"); new_month(); } DBG_DEBUG4("karte_t::step", "time calculations"); if( step_mode==NORMAL ) { /* Try to maintain a decent pause, with a step every 170-250 ms (~5,5 simloops/s) * Also avoid too large or negative steps */ // needs plausibility check?!? if(delta_t>10000) { dbg->error( "karte_t::step()", "delta_t (%u) out of bounds!", delta_t ); last_step_ticks = ticks; next_step_time = step_start_time+10; return; } idle_time = 0; last_step_nr[steps%32] = ticks; next_step_time = step_start_time + (3200/get_time_multiplier()); } else if( step_mode==FAST_FORWARD ) { // fast forward first: get average simloops (i.e. calculate acceleration) last_step_nr[steps%32] = step_start_time; int last_5_simloops = simloops; if( last_step_nr[(steps+32-5)%32] < last_step_nr[steps%32] ) { // since 5 steps=1s last_5_simloops = (1000) / (last_step_nr[steps%32]-last_step_nr[(steps+32-5)%32]); } if( last_step_nr[(steps+1)%32] < last_step_nr[steps%32] ) { simloops = (10000*32) / (last_step_nr[steps%32]-last_step_nr[(steps+1)%32]); } // now try to approach the target speed if(last_5_simloops0) { idle_time --; } } else if(simloops>8u*env_t::max_acceleration) { if(idle_time + 10u < get_frame_time()) { idle_time ++; } } // cap it ... if( idle_time + 10u >= get_frame_time()) { idle_time = get_frame_time()-10; } next_step_time = step_start_time+idle_time; } else { // network mode } // now do the step ... last_step_ticks = ticks; steps ++; // to make sure the tick counter will be updated INT_CHECK("karte_t::step"); // check for pending seasons change const bool season_change = pending_season_change > 0; const bool snowline_change = pending_snowline_change > 0; if( season_change || snowline_change ) { DBG_DEBUG4("karte_t::step", "pending_season_change"); // process const uint32 end_count = min( cached_grid_size.x * cached_grid_size.y, tile_counter + max( 16384, cached_grid_size.x * cached_grid_size.y / 16 ) ); while( tile_counter < end_count ) { plan[tile_counter].check_season_snowline( season_change, snowline_change ); tile_counter++; if( (tile_counter & 0x3FF) == 0 ) { INT_CHECK("karte_t::step"); } } if( tile_counter >= (uint32)cached_grid_size.x * (uint32)cached_grid_size.y ) { if( season_change ) { pending_season_change--; } if( snowline_change ) { pending_snowline_change--; } tile_counter = 0; } } // to make sure the tick counter will be updated INT_CHECK("karte_t::step"); DBG_DEBUG4("karte_t::step", "step convois"); // since convois will be deleted during stepping, we need to step backwards for (size_t i = convoi_array.get_count(); i-- != 0;) { convoihandle_t cnv = convoi_array[i]; cnv->step(); if((i&15)==0) { INT_CHECK("simworld 1947"); } } // now step all towns (to generate passengers) DBG_DEBUG4("karte_t::step", "step cities"); sint64 bev=0; for(stadt_t* const i : cities) { i->step(delta_t); bev += i->get_finance_history_month(0, HIST_CITIZENS); } // the inhabitants stuff finance_history_month[0][WORLD_CITIZENS] = bev; DBG_DEBUG4("karte_t::step", "step factories"); for(fabrik_t* const f : fab_list) { f->step(delta_t); } finance_history_year[0][WORLD_FACTORIES] = finance_history_month[0][WORLD_FACTORIES] = fab_list.get_count(); // step powerlines - required order: powernet, pumpe then senke DBG_DEBUG4("karte_t::step", "step poweline stuff"); powernet_t::step_all(delta_t); pumpe_t::sync_handler(delta_t); // senke_t::step_all(delta_t); // not needed, handeld by sunc_step already DBG_DEBUG4("karte_t::step", "step players"); // then step all players for( int i=0; istep(); } } DBG_DEBUG4("karte_t::step", "step halts"); haltestelle_t::step_all(); // ok, next step INT_CHECK("simworld 1975"); recalc_season_snowline(true); // number of playing clients changed if( env_t::server && last_clients!=socket_list_t::get_playing_clients() ) { if( env_t::server_announce ) { // inform the master server announce_server( karte_t::SERVER_ANNOUNCE_HEARTBEAT ); } // check if player has left and send message for(uint32 i=0; i < socket_list_t::get_count(); i++) { socket_info_t& info = socket_list_t::get_client(i); if (info.state == socket_info_t::has_left) { nwc_nick_t::server_tools(this, i, nwc_nick_t::FAREWELL, NULL); info.state = socket_info_t::inactive; } } last_clients = socket_list_t::get_playing_clients(); // add message via tool cbuffer_t buf; buf.printf("%d,", chat_message_t::DO_NOT_SAVE_MSG | chat_message_t::DO_NO_LOG_MSG); buf.printf(translator::translate("Now %u clients connected.", settings.get_name_language_id()), last_clients); tool_t *tmp_tool = create_tool( TOOL_ADD_MESSAGE | GENERAL_TOOL ); tmp_tool->set_default_param( buf ); bool suspended; call_work_api(tmp_tool, get_active_player(), koord3d::invalid, suspended); // work is done (or command sent), it is safe to delete immediately delete tmp_tool; } if( get_scenario()->is_scripted() ) { get_scenario()->step(); } if (selected_tool[active_player_nr]) { if (exec_script_base_t* esb = dynamic_cast(selected_tool[active_player_nr])) { esb->step(get_active_player()); } } DBG_DEBUG4("karte_t::step", "end"); } // recalculates world statistics for older versions void karte_t::restore_history(bool restore_transported_only) { // update total transported, including passenger and mail for( int m=min(MAX_WORLD_HISTORY_MONTHS,MAX_PLAYER_HISTORY_MONTHS)-1; m>0; m-- ) { sint64 transported = 0; for( uint i=0; iget_finance()->calc_finance_history(); transported += players[i]->get_finance()->get_history_veh_month( TT_ALL, m, ATV_TRANSPORTED ); } } finance_history_month[m][WORLD_TRANSPORTED_GOODS] = max(transported, finance_history_month[m][WORLD_TRANSPORTED_GOODS]); } for( int y=min(MAX_WORLD_HISTORY_YEARS,MAX_CITY_HISTORY_YEARS)-1; y>0; y-- ) { sint64 transported_year = 0; for( uint i=0; iget_finance()->get_history_veh_year( TT_ALL, y, ATV_TRANSPORTED ); } } finance_history_year[y][WORLD_TRANSPORTED_GOODS] = max(transported_year, finance_history_year[y][WORLD_TRANSPORTED_GOODS]); } if (restore_transported_only) { return; } last_month_bev = -1; for( int m=12-1; m>0; m-- ) { // now step all towns (to generate passengers) sint64 bev=0; sint64 total_pas = 1, trans_pas = 0; sint64 total_mail = 1, trans_mail = 0; sint64 total_goods = 1, supplied_goods = 0; for(stadt_t* const i : cities) { bev += i->get_finance_history_month(m, HIST_CITIZENS); trans_pas += i->get_finance_history_month(m, HIST_PAS_TRANSPORTED); total_pas += i->get_finance_history_month(m, HIST_PAS_GENERATED); trans_mail += i->get_finance_history_month(m, HIST_MAIL_TRANSPORTED); total_mail += i->get_finance_history_month(m, HIST_MAIL_GENERATED); supplied_goods += i->get_finance_history_month(m, HIST_GOODS_RECEIVED); total_goods += i->get_finance_history_month(m, HIST_GOODS_NEEDED); } // the inhabitants stuff if(last_month_bev == -1) { last_month_bev = bev; } finance_history_month[m][WORLD_GROWTH] = bev-last_month_bev; finance_history_month[m][WORLD_CITIZENS] = bev; last_month_bev = bev; // transportation ratio and total number finance_history_month[m][WORLD_PAS_RATIO] = (10000*trans_pas)/total_pas; finance_history_month[m][WORLD_PAS_GENERATED] = total_pas-1; finance_history_month[m][WORLD_MAIL_RATIO] = (10000*trans_mail)/total_mail; finance_history_month[m][WORLD_MAIL_GENERATED] = total_mail-1; finance_history_month[m][WORLD_GOODS_RATIO] = (10000*supplied_goods)/total_goods; } sint64 bev_last_year = -1; for( int y=min(MAX_WORLD_HISTORY_YEARS,MAX_CITY_HISTORY_YEARS)-1; y>0; y-- ) { // now step all towns (to generate passengers) sint64 bev=0; sint64 total_pas_year = 1, trans_pas_year = 0; sint64 total_mail_year = 1, trans_mail_year = 0; sint64 total_goods_year = 1, supplied_goods_year = 0; for(stadt_t* const i : cities) { bev += i->get_finance_history_year(y, HIST_CITIZENS); trans_pas_year += i->get_finance_history_year(y, HIST_PAS_TRANSPORTED); total_pas_year += i->get_finance_history_year(y, HIST_PAS_GENERATED); trans_mail_year += i->get_finance_history_year(y, HIST_MAIL_TRANSPORTED); total_mail_year += i->get_finance_history_year(y, HIST_MAIL_GENERATED); supplied_goods_year += i->get_finance_history_year(y, HIST_GOODS_RECEIVED); total_goods_year += i->get_finance_history_year(y, HIST_GOODS_NEEDED); } // the inhabitants stuff if(bev_last_year == -1) { bev_last_year = bev; } finance_history_year[y][WORLD_GROWTH] = bev-bev_last_year; finance_history_year[y][WORLD_CITIZENS] = bev; bev_last_year = bev; // transportation ratio and total number finance_history_year[y][WORLD_PAS_RATIO] = (10000*trans_pas_year)/total_pas_year; finance_history_year[y][WORLD_PAS_GENERATED] = total_pas_year-1; finance_history_year[y][WORLD_MAIL_RATIO] = (10000*trans_mail_year)/total_mail_year; finance_history_year[y][WORLD_MAIL_GENERATED] = total_mail_year-1; finance_history_year[y][WORLD_GOODS_RATIO] = (10000*supplied_goods_year)/total_goods_year; } // fix current month/year update_history(); } void karte_t::update_history() { finance_history_year[0][WORLD_CONVOIS] = finance_history_month[0][WORLD_CONVOIS] = convoi_array.get_count(); finance_history_year[0][WORLD_FACTORIES] = finance_history_month[0][WORLD_FACTORIES] = fab_list.get_count(); // now step all towns (to generate passengers) sint64 bev=0; sint64 total_pas = 1, trans_pas = 0; sint64 total_mail = 1, trans_mail = 0; sint64 total_goods = 1, supplied_goods = 0; sint64 total_pas_year = 1, trans_pas_year = 0; sint64 total_mail_year = 1, trans_mail_year = 0; sint64 total_goods_year = 1, supplied_goods_year = 0; for(stadt_t* const i : cities) { bev += i->get_finance_history_month(0, HIST_CITIZENS); trans_pas += i->get_finance_history_month(0, HIST_PAS_TRANSPORTED); total_pas += i->get_finance_history_month(0, HIST_PAS_GENERATED); trans_mail += i->get_finance_history_month(0, HIST_MAIL_TRANSPORTED); total_mail += i->get_finance_history_month(0, HIST_MAIL_GENERATED); supplied_goods += i->get_finance_history_month(0, HIST_GOODS_RECEIVED); total_goods += i->get_finance_history_month(0, HIST_GOODS_NEEDED); trans_pas_year += i->get_finance_history_year( 0, HIST_PAS_TRANSPORTED); total_pas_year += i->get_finance_history_year( 0, HIST_PAS_GENERATED); trans_mail_year += i->get_finance_history_year( 0, HIST_MAIL_TRANSPORTED); total_mail_year += i->get_finance_history_year( 0, HIST_MAIL_GENERATED); supplied_goods_year += i->get_finance_history_year( 0, HIST_GOODS_RECEIVED); total_goods_year += i->get_finance_history_year( 0, HIST_GOODS_NEEDED); } finance_history_month[0][WORLD_GROWTH] = bev-last_month_bev; finance_history_year[0][WORLD_GROWTH] = bev - (finance_history_year[1][WORLD_CITIZENS]==0 ? finance_history_month[0][WORLD_CITIZENS] : finance_history_year[1][WORLD_CITIZENS]); // the inhabitants stuff finance_history_year[0][WORLD_TOWNS] = finance_history_month[0][WORLD_TOWNS] = cities.get_count(); finance_history_year[0][WORLD_CITIZENS] = finance_history_month[0][WORLD_CITIZENS] = bev; finance_history_month[0][WORLD_GROWTH] = bev-last_month_bev; finance_history_year[0][WORLD_GROWTH] = bev - (finance_history_year[1][WORLD_CITIZENS]==0 ? finance_history_month[0][WORLD_CITIZENS] : finance_history_year[1][WORLD_CITIZENS]); // transportation ratio and total number finance_history_month[0][WORLD_PAS_RATIO] = (10000*trans_pas)/total_pas; finance_history_month[0][WORLD_PAS_GENERATED] = total_pas-1; finance_history_month[0][WORLD_MAIL_RATIO] = (10000*trans_mail)/total_mail; finance_history_month[0][WORLD_MAIL_GENERATED] = total_mail-1; finance_history_month[0][WORLD_GOODS_RATIO] = (10000*supplied_goods)/total_goods; finance_history_year[0][WORLD_PAS_RATIO] = (10000*trans_pas_year)/total_pas_year; finance_history_year[0][WORLD_PAS_GENERATED] = total_pas_year-1; finance_history_year[0][WORLD_MAIL_RATIO] = (10000*trans_mail_year)/total_mail_year; finance_history_year[0][WORLD_MAIL_GENERATED] = total_mail_year-1; finance_history_year[0][WORLD_GOODS_RATIO] = (10000*supplied_goods_year)/total_goods_year; // update total transported, including passenger and mail sint64 transported = 0; sint64 transported_year = 0; for( uint i=0; iget_finance()->calc_finance_history(); transported += players[i]->get_finance()->get_history_veh_month( TT_ALL, 0, ATV_TRANSPORTED_GOOD ); transported_year += players[i]->get_finance()->get_history_veh_year( TT_ALL, 0, ATV_TRANSPORTED_GOOD ); } } finance_history_month[0][WORLD_TRANSPORTED_GOODS] = transported; finance_history_year[0][WORLD_TRANSPORTED_GOODS] = transported_year; } slist_tpl *karte_t::find_squares(sint16 w, sint16 h, climate_bits cl, sint16 old_x, sint16 old_y) const { slist_tpl * list = new slist_tpl(); koord start; int last_y = -1; DBG_DEBUG("karte_t::finde_plaetze()","for size (%i,%i) in map (%i,%i)",w,h,get_size().x,get_size().y ); for(start.x=0; start.xinsert(start); } else { // Optimiert fuer groessere Felder, hehe! // Die Idee: wenn bei 2x2 die untere Reihe nicht geht, koennen // wir gleich 2 tiefer weitermachen! start.y = last_y; } } } return list; } /** * Play a sound, but only if near enough. * Sounds are muted by distance and clipped completely if too far away. * * @param type */ bool karte_t::play_sound_area_clipped(koord const k, uint16 const idx, sound_type_t type ) const { if(is_sound && zeiger!=NULL) { const uint32 dist = koord_distance( k, zeiger->get_pos() ); if(dist < 100) { uint8 const volume = (uint8)((255U * env_t::sound_distance_scaling) / (env_t::sound_distance_scaling + dist*dist)); if (volume > 8) { sound_play(idx, volume, type ); } } return dist < 25; } return false; } void karte_t::save(const char *filename, bool autosave, const char *version_str, bool silent ) { dbg->message("karte_t::save", "%s game to '%s', version=%s, ticks=%u", autosave ? "Auto-saving" : "Saving", filename, version_str, ticks); loadsave_t file; std::string savename = filename; savename[savename.length()-1] = '_'; display_show_load_pointer( true ); const loadsave_t::mode_t mode = autosave ? loadsave_t::autosave_mode : loadsave_t::save_mode; const int save_level = autosave ? loadsave_t::autosave_level : loadsave_t::save_level; if( file.wr_open( savename.c_str(), mode, save_level, env_t::pak_name.c_str(), version_str ) != loadsave_t::FILE_STATUS_OK ) { create_win(new news_img("Kann Spielstand\nnicht speichern.\n"), w_info, magic_none); dbg->error("karte_t::save", "Cannot open file '%s' for writing! Check permissions!", savename.c_str()); } else { save(&file,silent); const char *save_err = file.close(); if(save_err) { static char err_str[512]; sprintf( err_str, translator::translate("Error during saving:\n%s"), save_err ); create_win( new news_img(err_str), w_time_delete, magic_none); } else { dr_rename( savename.c_str(), filename ); if(!silent) { create_win( new news_img("Spielstand wurde\ngespeichert!\n"), w_time_delete, magic_none); // update the filename, if no autosave settings.set_filename(filename); } } reset_interaction(); } display_show_load_pointer( false ); } void karte_t::save(loadsave_t *file,bool silent) { bool needs_redraw = false; loadingscreen_t *ls = NULL; DBG_MESSAGE("karte_t::save(loadsave_t *file)", "start"); if(!silent) { ls = new loadingscreen_t( translator::translate("Saving map ..."), get_size().y ); } // rotate the map until it can be saved completely for( int i=0; i<4 && nosave_warning; i++ ) { rotate90(); needs_redraw = true; } // seems not successful if(nosave_warning) { // but then we try to rotate until only warnings => some buildings may be broken, but factories should be fine for( int i=0; i<4 && nosave; i++ ) { rotate90(); needs_redraw = true; } if( nosave ) { dbg->error( "karte_t::save()", "Map cannot be saved in any rotation!" ); create_win( new news_img("Map may be not saveable in any rotation!"), w_info, magic_none); // still broken, but we try anyway to save it ... } } // only broken buildings => just warn if(nosave_warning) { dbg->error( "karte_t::save()","Some buildings may be broken by saving!" ); } /* If the current tool is a two_click_tool_t, call cleanup() in order to delete dummy grounds (tunnel + monorail preview) * THIS MUST NOT BE DONE IN NETWORK MODE! */ for( uint8 sp_nr=0; sp_nr(selected_tool[sp_nr])) { tool->cleanup(); } } file->set_buffered(true); rdwr_gamestate(file, ls); for(int i=0; iis_version_less(101, 0)) { if( i<8 ) { if( players[i] ) { players[i]->rdwr(file); } else { // simulate old ones ... player_t *player = new player_t( i ); player->rdwr(file); delete player; } } } else if( players[i] ) { players[i]->rdwr(file); } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved players"); // saving messages if( file->is_version_atleast(102, 5) ) { msg->rdwr(file); } DBG_MESSAGE("karte_t::save(loadsave_t *file)", "saved messages"); // centered on what? sint32 dummy = viewport->get_world_position().x; file->rdwr_long(dummy); dummy = viewport->get_world_position().y; file->rdwr_long(dummy); if(file->is_version_atleast(99, 18)) { // most recent version is 99018 for (int year = 0; yearrdwr_longlong(finance_history_year[year][cost_type]); } } for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } } // finally a possible scenario scenario->rdwr( file ); if( file->is_version_atleast(112, 8) ) { xml_tag_t t( file, "motd_t" ); dr_chdir( env_t::user_dir ); // maybe show message about server DBG_MESSAGE("karte_t::save(loadsave_t *file)", "motd filename %s", env_t::server_motd_filename.c_str() ); if( FILE *fmotd = dr_fopen( env_t::server_motd_filename.c_str(), "r" ) ) { struct stat st; stat( env_t::server_motd_filename.c_str(), &st ); sint32 len = min( 32760, st.st_size+1 ); char *motd = (char *)malloc( len ); if (fread( motd, len-1, 1, fmotd ) != 1) { len = 1; } fclose( fmotd ); motd[len-1] = 0; file->rdwr_str( motd, len ); free( motd ); } else { // no message plainstring motd(""); file->rdwr_str( motd ); } } if (file->is_version_atleast(124, 1)) { chat_msg->rdwr(file); } if (file->is_version_atleast(124, 2)) { records->rdwr(file); } file->rdwr_byte( active_player_nr ); // save all open windows (upon request) rdwr_all_win(file); file->set_buffered(false); if(needs_redraw) { update_map(); } if(!silent) { delete ls; } } void karte_t::switch_server( bool start_server, bool port_forwarding ) { if( !start_server ) { // end current server session if( env_t::server ) { // take down server announce_server(karte_t::SERVER_ANNOUNCE_GOODBYE); remove_port_forwarding( env_t::server ); } network_core_shutdown(); env_t::easy_server = 0; clear_random_mode( INTERACTIVE_RANDOM ); step_mode = NORMAL; reset_timer(); clear_command_queue(); last_active_player_nr = active_player_nr; if( port_forwarding && env_t::fps<=15 ) { env_t::fps = 25; } } else { // convert current game into server game if( env_t::server ) { // kick all clients out network_reset_server(); } else { // now start a server with defaults env_t::networkmode = network_init_server( env_t::server_port, env_t::listen ); if( env_t::networkmode ) { // query IP and try to open ports on router char IP[256], altIP[256]; if( port_forwarding && prepare_for_server( IP, altIP, env_t::server_port ) ) { // we have forwarded a port in router, so we can continue env_t::server_dns = IP; if( env_t::server_name.empty() ) { env_t::server_name = std::string("Server at ")+IP; } env_t::server_alt_dns = altIP; env_t::server_announce = 1; env_t::easy_server = 1; if( env_t::fps>15 ) { env_t::fps = 15; } } reset_timer(); clear_command_queue(); // meaningless to use a locked map; there are passwords now settings.set_allow_player_change(true); // language of map becomes server language settings.set_name_language_iso(translator::get_lang()->iso_base); nwc_auth_player_t::init_player_lock_server(this); last_active_player_nr = active_player_nr; } } } } // just the preliminaries, opens the file, checks the versions ... bool karte_t::load(const char *filename) { cbuffer_t name; bool ok = false; bool restore_player_nr = false; bool server_reload_pwd_hashes = false; mute_sound(true); display_show_load_pointer(true); loadsave_t file; // clear hash table with missing paks (may cause some small memory loss though) pakset_manager_t::clear_missing_paks(); dbg->message("karte_t::load", "Loading game from '%s'", filename); // reloading same game? Remember pos const koord oldpos = settings.get_filename()[0]>0 && strncmp(filename,settings.get_filename(),strlen(settings.get_filename()))==0 ? viewport->get_world_position() : koord::invalid; if( strstart(filename, "net:") ) { // probably finish network mode? if( env_t::networkmode ) { network_core_shutdown(); } dr_chdir( env_t::user_dir ); const char *err = network_connect(filename+4, this); if(err) { create_win( new news_img(err), w_info, magic_none ); display_show_load_pointer(false); step_mode = NORMAL; return false; } else { env_t::networkmode = true; name.printf( "client%i-network.sve", network_get_client_id() ); restore_player_nr = strcmp( last_network_game.c_str(), filename )==0; if( !restore_player_nr ) { last_network_game = filename; } } } else { // probably finish network mode first? if( env_t::networkmode ) { if( env_t::server ) { char fn[256]; sprintf( fn, "server%d-network.sve", env_t::server ); if( strcmp(filename, fn) != 0 ) { // stay in networkmode, but disconnect clients dbg->warning("karte_t::load", "Disconnecting all clients"); } else { // read password hashes from separate file // as they are not in the savegame to avoid sending them over network server_reload_pwd_hashes = true; } } else { // check, if reload during sync char fn[256]; sprintf( fn, "client%i-network.sve", network_get_client_id() ); if( strcmp(filename,fn)!=0 ) { // no sync => finish network mode dbg->warning("karte_t::load","finished network mode"); network_disconnect(); // closing the socket will tell the server, I am away too } } } name.append(filename); } if(file.rd_open(name) != loadsave_t::FILE_STATUS_OK) { if( file.get_version_int()==0 || file.get_version_int()>loadsave_t::int_version(SAVEGAME_VER_NR, NULL ) ) { dbg->warning("karte_t::load()", translator::translate("WRONGSAVE") ); create_win( new news_img("WRONGSAVE"), w_info, magic_none ); } else { dbg->warning("karte_t::load()", translator::translate("Kann Spielstand\nnicht laden.\n") ); create_win(new news_img("Kann Spielstand\nnicht laden.\n"), w_info, magic_none); } } else if(file.is_version_less(84, 6)) { // too old dbg->warning("karte_t::load()", translator::translate("WRONGSAVE") ); create_win(new news_img("WRONGSAVE"), w_info, magic_none); } else { DBG_MESSAGE("karte_t::load()","Savegame version is %u", file.get_version_int()); file.set_buffered(true); load(&file); if( env_t::server ) { // since the sync should have been the last command on the clients due to tcp, only clear command queue on the server clear_command_queue(); step_mode = FIX_RATIO; // meaningless to use a locked map; there are passwords now settings.set_allow_player_change(true); // language of map becomes server language settings.set_name_language_iso(translator::get_lang()->iso_base); if( server_reload_pwd_hashes ) { char fn[256]; sprintf( fn, "server%d-pwdhash.sve", env_t::server ); loadsave_t pwdfile; if( pwdfile.rd_open(fn) == loadsave_t::FILE_STATUS_OK ) { rdwr_player_password_hashes( &pwdfile ); // correct locking info nwc_auth_player_t::init_player_lock_server(this); pwdfile.close(); } } } else if( env_t::networkmode ) { step_mode = PAUSE_FLAG|FIX_RATIO; switch_active_player( last_active_player_nr, true ); if( is_within_limits(oldpos) ) { // go to position when last disconnected viewport->change_world_position( oldpos ); } } else { step_mode = NORMAL; // save current map settings only in non-networkmode env_t::default_settings = settings; } ok = true; file.close(); if( !scenario->rdwr_ok() ) { // error during loading of savegame of scenario const char* err = scenario->get_error_text(); if (err == NULL) { err = "Loading scenario failed."; } create_win( new news_img( err ), w_info, magic_none); delete scenario; scenario = new scenario_t(this); } else if( !env_t::networkmode || !env_t::restore_UI ) { // warning message about missing paks pakset_manager_t::warn_if_paks_missing(); // will not notify if we restore everything if( scenario->is_scripted() ) { scenario->open_info_win(); } create_win( new news_img("Spielstand wurde\ngeladen!\n"), w_time_delete, magic_none); } set_dirty(); reset_timer(); recalc_average_speed(); mute_sound(false); tool_t::update_toolbars(); toolbar_last_used_t::last_used_tools->clear(); set_tool( tool_t::general_tool[TOOL_QUERY], get_active_player() ); } settings.set_filename(filename); display_show_load_pointer(false); return ok; } #ifdef MULTI_THREAD static pthread_mutex_t height_mutex; static recursive_mutex_maker_t height_mutex_maker(height_mutex); #endif player_t* karte_t::get_player_or_create(uint8 n) { n &= 15; if (players[n]) { return players[n]; } dbg->error("get_player()", "No player %d in this game -> make a new one", n); init_new_player(n, player_t::HUMAN); return players[n]; } void karte_t::plans_finish_rd( sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) { sint8 min_h = 127, max_h = -128; for( int y = y_min; y < y_max; y++ ) { for( int x = x_min; x < x_max; x++ ) { planquadrat_t *plan = access_nocheck(x,y); plan->sort_haltlist(); const int boden_count = plan->get_boden_count(); for( int schicht = 0; schicht < boden_count; schicht++ ) { grund_t *gr = plan->get_boden_bei(schicht); if( min_h > gr->get_hoehe() ) { min_h = gr->get_hoehe(); } else if( max_h < gr->get_hoehe() ) { max_h = gr->get_hoehe(); } for( int n = 0; n < gr->obj_count(); n++ ) { obj_t *obj = gr->obj_bei(n); if(obj) { obj->finish_rd(); } } if( load_version<=111000 && gr->ist_natur() ) { gr->sort_trees(); } gr->calc_image(); } } } // update heights #ifdef MULTI_THREAD pthread_mutex_lock( &height_mutex ); if( min_height > min_h ) { min_height = min_h; } if( max_height < max_h ) { max_height = max_h; } pthread_mutex_unlock( &height_mutex ); #else min_height = min_h; max_height = max_h; #endif } void karte_t::load(loadsave_t *file) { intr_disable(); dbg->message("karte_t::load()", "Prepare for loading" ); for( uint8 sp_nr=0; sp_nr(selected_tool[sp_nr])) { tool->cleanup(); } } destroy_all_win(true); clear_random_mode(~LOAD_RANDOM); set_random_mode(LOAD_RANDOM); destroy(); loadingscreen_t ls(translator::translate("Loading map ..."), 1, true, true ); tile_counter = 0; simloops = 60; // jetzt geht das Laden los dbg->message("karte_t::load", "File version: %u", file->get_version_int()); rdwr_gamestate(file, &ls); // now the player can be loaded for(int i=0; irdwr(file); } ls.set_progress( (get_size().y*3)/2+128+8*i ); } DBG_MESSAGE("karte_t::rdwr_gamestate()", "players loaded"); // loading messages if( file->is_version_atleast(102, 5) ) { msg->rdwr(file); } else if( !env_t::networkmode ) { msg->clear(); chat_msg->clear(); } DBG_MESSAGE("karte_t::load()", "messages loaded"); // nachdem die welt jetzt geladen ist koennen die Blockstrecken neu // angelegt werden old_blockmanager_t::finish_rd(this); DBG_MESSAGE("karte_t::load()", "blocks loaded"); sint32 mi,mj; file->rdwr_long(mi); file->rdwr_long(mj); DBG_MESSAGE("karte_t::load()", "Setting view to %d,%d", mi,mj); viewport->change_world_position( koord3d(mi,mj,0) ); // right season for recalculations recalc_season_snowline(false); DBG_MESSAGE("karte_t::load()", "%d ways loaded",weg_t::get_alle_wege().get_count()); ls.set_progress( (get_size().y*3)/2+256 ); world_xy_loop(&karte_t::plans_finish_rd, SYNCX_FLAG); // update power nets with correct power powernet_t::step_all(1); if( file->is_version_less(112, 7) ) { // set transitions - has to be done after plans_finish_rd world_xy_loop(&karte_t::recalc_transitions_loop, 0); } ls.set_progress( (get_size().y*3)/2+256+get_size().y/8 ); DBG_MESSAGE("karte_t::load()", "laden_abschliesen for tiles finished" ); // must finish loading cities first before cleaning up factories weighted_vector_tpl new_cities(cities.get_count() + 1); for(stadt_t* const s : cities) { s->finish_rd(); s->recalc_target_cities(); new_cities.append(s, s->get_einwohner()); INT_CHECK("simworld 1278"); } swap(cities, new_cities); DBG_MESSAGE("karte_t::load()", "cities initialized"); ls.set_progress( (get_size().y*3)/2+256+get_size().y/4 ); DBG_MESSAGE("karte_t::load()", "clean up factories"); for(fabrik_t* const f : fab_list) { f->finish_rd(); } DBG_MESSAGE("karte_t::load()", "%d factories loaded", fab_list.get_count()); // old versions did not save factory connections if(file->is_version_less(99, 14)) { sint32 const temp_min = settings.get_factory_worker_minimum_towns(); sint32 const temp_max = settings.get_factory_worker_maximum_towns(); // this needs to avoid the first city to be connected to all town settings.set_factory_worker_minimum_towns(0); settings.set_factory_worker_maximum_towns(cities.get_count() + 1); for(stadt_t* const i : cities) { i->verbinde_fabriken(); } settings.set_factory_worker_minimum_towns(temp_min); settings.set_factory_worker_maximum_towns(temp_max); } ls.set_progress( (get_size().y*3)/2+256+get_size().y/3 ); // resolve dummy stops into real stops first ... for(halthandle_t const i : haltestelle_t::get_alle_haltestellen()) { if (i->get_owner() && i->existiert_in_welt()) { i->finish_rd(); } } // ... before removing dummy stops for( vector_tpl::const_iterator i=haltestelle_t::get_alle_haltestellen().begin(); i!=haltestelle_t::get_alle_haltestellen().end(); ) { halthandle_t const h = *i; if( !h->get_owner() || !h->existiert_in_welt() ) { // this stop was only needed for loading goods ... haltestelle_t::destroy(h); // remove from list } else { ++i; } } ls.set_progress( (get_size().y*3)/2+256+(get_size().y*3)/8 ); // adding lines and other stuff for convois for(unsigned i=0; ifinish_rd(); // was deleted during loading => use same position again if(!cnv.is_bound()) { i--; } } haltestelle_t::end_load_game(); // register all line stops and change line types, if needed for(int i=0; ifinish_rd(); } } #ifdef DEBUG uint32 dt = dr_time(); #endif // recalculate halt connections haltestelle_t::reset_routing(); do { haltestelle_t::step_all(); } while ( haltestelle_t::get_rerouting_status()==RECONNECTING ); #ifdef DEBUG dbg->message("karte_t::load()", "for all haltstellen_t took %ld ms", dr_time()-dt ); #endif #if 0 // reroute goods for benchmarking dt = dr_time(); for(halthandle_t const i : haltestelle_t::get_alle_haltestellen()) { sint16 dummy = 0x7FFF; i->reroute_goods(dummy); } DBG_MESSAGE("reroute_goods()","for all haltstellen_t took %ld ms", dr_time()-dt ); #endif // load history/create world history if(file->is_version_less(99, 18)) { restore_history(false); } else { for (int year = 0; yearrdwr_longlong(finance_history_year[year][cost_type]); } } for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type]); } } last_month_bev = finance_history_month[1][WORLD_CITIZENS]; if (file->is_version_atleast(112, 5) && file->is_version_less(120, 6)) { restore_history(true); } } // finally: do we run a scenario? if(file->is_version_atleast(99, 18)) { scenario->rdwr(file); } // restore locked state // network game this will be done in nwc_sync_t::do_command if( !env_t::networkmode ) { for( uint8 i=0; icheck_unlock( player_password_hash[i] ); } } } // initialize lock info for local server player // if call from sync command, lock info will be corrected there if( env_t::server ) { nwc_auth_player_t::init_player_lock_server(this); } // show message about server if( file->is_version_atleast(112, 8) ) { xml_tag_t t( file, "motd_t" ); char msg[32766]; file->rdwr_str( msg, 32766 ); if( *msg && !env_t::server ) { // if not empty ... help_frame_t *win = new help_frame_t(); win->set_text( msg ); create_win(win, w_info, magic_motd); } } if (file->is_version_atleast(124, 1)) { chat_msg->rdwr(file); } else { // maybe move messages into chat_messages? } if (file->is_version_atleast(124, 2)) { records->rdwr(file); } if( file->is_version_atleast(102, 4) ) { if( env_t::restore_UI ) { file->rdwr_byte( active_player_nr ); active_player = players[active_player_nr]; /* restore all open windows * otherwise it will be ignored * which is save, since it is the end of file */ rdwr_all_win( file ); } } file->set_buffered(false); clear_random_mode(LOAD_RANDOM); // loading finished, reset savegame version to current load_version = loadsave_t::int_version( env_t::savegame_version_str, NULL ); dbg->warning("karte_t::load()","loaded savegame from %i/%i, next month=%i, ticks=%i (per month=1<<%i)",last_month,last_year,next_month_ticks,ticks,karte_t::ticks_per_world_month_shift); } void karte_t::rdwr_gamestate(loadsave_t *file, loadingscreen_t *ls) { if (file->is_loading()) { // zum laden vorbereiten -> tabelle loeschen powernet_t::new_world(); senke_t::new_world(); script_api::new_world(); settings = env_t::default_settings; } else { // do not set value for empty player and correct existing players for( int i=0; ierror("karte_t::rdwr_gamestate()", "State %d of non-existing player %d correct to 0 (EMPTY)", settings.get_player_type(i), i); settings.set_player_type(i, player_t::EMPTY); } } else if(settings.get_player_type(i)-1>= player_t::MAX_AI-1) { dbg->error("karte_t::rdwr_gamestate()", "State %d of player %d correct to 1 (HUMAN)", settings.get_player_type(i), i); settings.set_player_type(i, player_t::HUMAN); } } } settings.rdwr(file); if (file->is_loading()) { // some functions (finish_rd) need to know what version was loaded load_version = file->get_version_int(); loaded_rotation = settings.get_rotation(); } if (file->is_version_atleast(122, 1)) { // rdwr the entire RNG sate simrand_rdwr(file); } if (file->is_loading()) { if( env_t::networkmode ) { // To have games synchronized, transfer random counter too // Superseded by simrand_rdwr in newer versions if (file->is_version_less(122, 1)) { setsimrand(settings.get_random_counter(), 0xFFFFFFFFu ); } translator::init_custom_names(settings.get_name_language_id()); } if( !env_t::networkmode || (env_t::server && socket_list_t::get_playing_clients()==0) ) { if (settings.get_allow_player_change() && env_t::default_settings.get_use_timeline() < 2) { // not locked => eventually switch off timeline settings, if explicitly stated settings.set_use_timeline(env_t::default_settings.get_use_timeline()); DBG_DEBUG("karte_t::rdwr_gamestate()", "timeline: reset to %i", env_t::default_settings.get_use_timeline() ); } } if (settings.get_beginner_mode()) { goods_manager_t::set_multiplier(settings.get_beginner_price_factor()); } else { goods_manager_t::set_multiplier( 1000 ); } max_allowed_height = settings.get_maximumheight(); min_allowed_height = settings.get_minimumheight(); groundwater = (sint8)(settings.get_groundwater()); min_height = max_height = groundwater; DBG_DEBUG("karte_t::rdwr_gamestate()","groundwater %i",groundwater); if( file->is_version_less(112, 7) ) { // r7930 fixed a bug in init_height_to_climate // recover old behavior to not mix up climate when loading old savegames groundwater = settings.get_climate_borders(0,0); init_height_to_climate(); groundwater = settings.get_groundwater(); } else { init_height_to_climate(); } // just an initialisation for the loading season = (2+last_month/3)&3; // summer always zero snowline = settings.get_winter_snowline() + groundwater; DBG_DEBUG("karte_t::rdwr_gamestate()", "settings loaded (size %i,%i) timeline=%i beginner=%i", settings.get_size_x(), settings.get_size_y(), settings.get_use_timeline(), settings.get_beginner_mode()); // wird gecached, um den Pointerzugriff zu sparen, da // die size _sehr_ oft referenziert wird cached_grid_size.x = settings.get_size_x(); cached_grid_size.y = settings.get_size_y(); cached_size_max = max(cached_grid_size.x,cached_grid_size.y); cached_size.x = cached_grid_size.x-1; cached_size.y = cached_grid_size.y-1; viewport->set_x_off(0); viewport->set_y_off(0); // Update minimap for new world minimap_t::get_instance()->init(); ls->set_max( get_size().y*2+256 ); init_tiles(); // reinit pointer with new pointer object and old values zeiger = new zeiger_t(koord3d::invalid, NULL ); hausbauer_t::new_world(); factory_builder_t::new_world(); DBG_DEBUG("karte_t::rdwr_gamestate()", "init felder ok"); } file->rdwr_long(ticks); file->rdwr_long(last_month); file->rdwr_long(last_year); if (file->is_loading()) { if(file->is_version_less(86, 6)) { last_year += env_t::default_settings.get_starting_year(); } if (last_year+1 >= INT32_MAX/12) { // prevent overflow dbg->fatal("karte_t::rdwr_gamestate", "Year out of range (%d >= %d)", last_year+1, INT_MAX/12); } // old game might have wrong month last_month %= 12; // set the current month count set_ticks_per_world_month_shift(settings.get_bits_per_month()); current_month = last_month + (last_year*12); season = (2+last_month/3)&3; // summer always zero next_month_ticks = ( (ticks >> karte_t::ticks_per_world_month_shift) + 1 ) << karte_t::ticks_per_world_month_shift; last_step_ticks = ticks; steps = 0; network_frame_count = 0; sync_steps = 0; sync_steps_barrier = sync_steps; step_mode = PAUSE_FLAG; DBG_MESSAGE("karte_t::rdwr_gamestate()","savegame loading at tick count %i",ticks); recalc_average_speed(); // resets timeline koord::locality_factor = settings.get_locality_factor( last_year ); // resets weight factor // recalc_average_speed may have opened message windows destroy_all_win(true); DBG_MESSAGE("karte_t::rdwr_gamestate()", "init player"); for(int i=0; iis_version_atleast(101, 0) ) { // since we have different kind of AIs delete players[i]; players[i] = NULL; init_new_player(i, settings.player_type[i]); } else if(i<8) { // get the old player ... if( players[i]==NULL ) { init_new_player( i, (i==3) ? player_t::AI_PASSENGER : player_t::AI_GOODS ); } settings.player_type[i] = players[i]->get_ai_id(); } } // so far, player 1 will be active (may change in future) active_player = players[PLAYER_HUMAN_NR]; active_player_nr = PLAYER_HUMAN_NR; } // rdwr tree ID mapping to restore tree IDs if (file->is_version_atleast(122, 2)) { DBG_MESSAGE("karte_t::rdwr_gamestate()", "rdwr tree IDs"); tree_builder_t::rdwr_tree_ids(file); } // rdwr static states senke_t::static_rdwr(file); // rdwr cityrules, speedbonus for network games if(file->is_version_atleast(102, 3)) { bool do_rdwr = env_t::networkmode; file->rdwr_bool(do_rdwr); if (do_rdwr) { stadt_t::cityrules_rdwr(file); if(file->is_version_atleast(102, 4)) { vehicle_builder_t::rdwr_speedbonus(file); } } } // rdwr cities if (file->is_loading()) { DBG_DEBUG("karte_t::rdwr_gamestate()", "init %i cities", settings.get_city_count()); cities.clear(); cities.resize(settings.get_city_count()); for (int i = 0; i < settings.get_city_count(); ++i) { stadt_t *s = new stadt_t(file); cities.append( s, s->get_einwohner()); } } else { for(stadt_t* const i : cities) { i->rdwr(file); if(!ls) { INT_CHECK("saving"); } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved cities ok"); } // import rail blocks from old saves if (file->is_loading()) { DBG_MESSAGE("karte_t::rdwr_gamestate()","loading blocks"); old_blockmanager_t::rdwr(this, file); } // rdwr tiles if (file->is_loading()) { DBG_MESSAGE("karte_t::rdwr_gamestate()","loading tiles"); for (int y = 0; y < get_size().y; y++) { for (int x = 0; x < get_size().x; x++) { plan[x+y*cached_grid_size.x].rdwr(file, koord(x,y) ); } if(file->is_eof()) { dbg->fatal("karte_t::rdwr_gamestate()","Savegame file mangled (too short)!"); } ls->set_progress( y/2 ); } } else { for(int j=0; jset_progress(j); } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved tiles"); } // rdwr terrain if (file->is_loading()) { if(file->is_version_less(99, 5)) { DBG_MESSAGE("karte_t::rdwr_gamestate()","loading grid for older versions"); for (int y = 0; y <= get_size().y; y++) { for (int x = 0; x <= get_size().x; x++) { sint32 hgt; file->rdwr_long(hgt); // old height step was 16! set_grid_hgt_nocheck(x, y, hgt/16 ); } } } else if( file->is_version_less(102, 2) ) { // hgt now bytes DBG_MESSAGE("karte_t::rdwr_gamestate()","loading grid for older versions"); for( sint32 i=0; i<(get_size().y+1)*(sint32)(get_size().x+1); i++ ) { file->rdwr_byte(grid_hgts[i]); } } if(file->is_version_less(88, 9)) { DBG_MESSAGE("karte_t::rdwr_gamestate()","loading slopes from older version"); // load slopes for older versions // now part of the grund_t structure for (int y = 0; y < get_size().y; y++) { for (int x = 0; x < get_size().x; x++) { sint8 slope; file->rdwr_byte(slope); // convert slopes from old single height saved game slope = slope_from_slope4(slope4_t(slope), env_t::pak_height_conversion_factor); access_nocheck(x, y)->get_kartenboden()->set_grund_hang(slope); } } } if(file->is_version_less(88, 1)) { // because from 88.01.4 on the foundations are handled differently for (int y = 0; y < get_size().y; y++) { for (int x = 0; x < get_size().x; x++) { koord k(x,y); grund_t *gr = access_nocheck(x, y)->get_kartenboden(); if( gr->get_typ()==grund_t::fundament ) { gr->set_hoehe( max_hgt_nocheck(k) ); gr->set_grund_hang( slope_t::flat ); // transfer object to on new grund for( int i=0; iobj_count(); i++ ) { gr->obj_bei(i)->set_pos( gr->get_pos() ); } } } } } } else { if( file->is_version_less(102, 2) ) { // not needed any more for(int j=0; j<(get_size().y+1)*(sint32)(get_size().x+1); j++) { file->rdwr_byte(grid_hgts[j]); } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved hgt"); } } // rdwr climate map if (file->is_loading()) { // init climates and default climate map DBG_MESSAGE("karte_t::rdwr_gamestate()", "init climates"); climate_map.resize( get_size().x, get_size().y ); if( file->is_version_atleast( 121, 1 ) ) { for( sint16 y = 0; y < get_size().y; y++ ) { for( sint16 x = 0; x < get_size().x; x++ ) { file->rdwr_byte( climate_map.at(x,y) ); } } } else if( file->is_version_less(112, 7) ) { // distribute climates calc_climate_map_region(0,0,get_size().x,get_size().y); } else { for( sint16 y = 0; y < get_size().y; y++ ) { for( sint16 x = 0; x < get_size().x; x++ ) { climate_map.at(x,y) = access(x,y)->get_climate(); if( climate_map.at( x, y ) > arctic_climate ) { dbg->warning( "karte_t::rdwr_gamestate()", "Wrong climate %i at (%i%i) set to temperate", climate_map.at( x, y ), x, y ); climate_map.at( x, y ) = temperate_climate; } } } } } else { // save default climate amp if( file->is_version_atleast( 121, 1 ) ) { for( sint16 y = 0; y < get_size().y; y++ ) { for( sint16 x = 0; x < get_size().x; x++ ) { file->rdwr_byte( climate_map.at(x,y) ); } } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved default climates"); } if (file->is_loading()) { // Update minimap for new world DBG_MESSAGE("karte_t::rdwr_gamestate()", "init minimap"); win_set_world( this ); minimap_t::get_instance()->init(); } // rdwr factories if (file->is_loading()) { // load factories sint32 fabs; file->rdwr_long(fabs); DBG_MESSAGE("karte_t::rdwr_gamestate()", "Prepare for %i factories", fabs); for(sint32 i = 0; i < fabs; i++) { // list in gleicher reihenfolge wie vor dem speichern wieder aufbauen fabrik_t *fab = new fabrik_t(file); if(fab->get_desc()) { fab_list.append( fab ); } else { dbg->error("karte_t::rdwr_gamestate()","Unknown factory skipped!"); delete fab; } if(i&7) { ls->set_progress( get_size().y/2+(128*i)/fabs ); } } } else { sint32 fabs = fab_list.get_count(); file->rdwr_long(fabs); for(fabrik_t* const f : fab_list) { f->rdwr(file); if(!ls) { INT_CHECK("saving"); } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved fabs"); } // import line management from old saves if (file->is_loading()) { // load linemanagement status (and lines) if (file->is_version_atleast(82, 4) && file->is_version_less(88, 3)) { DBG_MESSAGE("karte_t::rdwr_gamestate()", "load linemanagement"); get_player(0)->simlinemgmt.rdwr(file, get_player(0)); } // end load linemanagement } // rdwr stops if (file->is_loading()) { DBG_MESSAGE("karte_t::rdwr_gamestate()", "load stops"); // now load the stops // (the players will be load later and overwrite some values, // like the total number of stops build (for the numbered station feature) haltestelle_t::start_load_game(); if(file->is_version_atleast(99, 8)) { sint32 halt_count; file->rdwr_long(halt_count); DBG_MESSAGE("karte_t::rdwr_gamestate()","%d halts loaded",halt_count); for(int i=0; iexistiert_in_welt()) { dbg->warning("karte_t::rdwr_gamestate()", "could not restore stop near %i,%i", halt->get_init_pos().x, halt->get_init_pos().y ); } ls->set_progress( get_size().y/2+128+(get_size().y*i)/(2*halt_count) ); } } } else { sint32 haltcount=haltestelle_t::get_alle_haltestellen().get_count(); file->rdwr_long(haltcount); for(halthandle_t const s : haltestelle_t::get_alle_haltestellen()) { s->rdwr(file); } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved stops"); } // rdwr convois if (file->is_loading()) { DBG_MESSAGE("karte_t::rdwr_gamestate()", "load convois"); uint16 convoi_nr = 65535; uint16 max_convoi = 65535; if( file->is_version_atleast(101, 0) ) { file->rdwr_short(convoi_nr); max_convoi = convoi_nr; } char buf[80]; while( convoi_nr-->0 ) { if( file->is_version_less(101, 0) ) { file->rd_obj_id(buf, 79); if (strcmp(buf, "Ende Convois") == 0) { break; } } convoi_t *cnv = new convoi_t(file); convoi_array.append(cnv->self); if(cnv->in_depot()) { grund_t * gr = lookup(cnv->get_pos()); depot_t *dep = gr ? gr->get_depot() : 0; if(dep) { cnv->betrete_depot(dep); } else { dbg->error("karte_t::rdwr_gamestate()", "no depot for convoi, blocks may now be wrongly reserved!"); cnv->destroy(); } } else { sync.add( cnv ); } if( (convoi_array.get_count()&7) == 0 ) { ls->set_progress( get_size().y+(get_size().y*convoi_array.get_count())/(2*max_convoi)+128 ); } } DBG_MESSAGE("karte_t::rdwr_gamestate()", "%d convois/trains loaded", convoi_array.get_count()); } else { // save number of convois if( file->is_version_atleast(101, 0) ) { uint16 i=convoi_array.get_count(); file->rdwr_short(i); } for(convoihandle_t const cnv : convoi_array) { // one MUST NOT call INT_CHECK here or else the convoi will be broken during reloading! cnv->rdwr(file); } if( file->is_version_less(101, 0) ) { file->wr_obj_id("Ende Convois"); } if(!ls) { INT_CHECK("saving"); } DBG_MESSAGE("karte_t::rdwr_gamestate()", "saved %i convois",convoi_array.get_count()); } } // recalcs all ground tiles on the map void karte_t::update_map_intern(sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max) { if( (loaded_rotation + settings.get_rotation()) & 1 ) { // 1 || 3 // ~14% faster loop blocking rotations 1 and 3 const int LOOP_BLOCK = 128; for( int xx = x_min; xx < x_max; xx += LOOP_BLOCK ) { for( int yy = y_min; yy < y_max; yy += LOOP_BLOCK ) { for( int y = yy; y < min(yy + LOOP_BLOCK, y_max); y++ ) { for( int x = xx; x < min(xx + LOOP_BLOCK, x_max); x++ ) { const int nr = y * cached_grid_size.x + x; for( uint i = 0; i < plan[nr].get_boden_count(); i++ ) { plan[nr].get_boden_bei(i)->calc_image(); } } } } } } else { for( int y = y_min; y < y_max; y++ ) { for( int x = x_min; x < x_max; x++ ) { const int nr = y * cached_grid_size.x + x; for( uint i = 0; i < plan[nr].get_boden_count(); i++ ) { plan[nr].get_boden_bei(i)->calc_image(); } } } } } bool karte_t::can_flood_to_depth(koord k, sint8 new_water_height, sint8 *stage, sint8 *our_stage, sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) const { bool succeeded = true; if( k == koord::invalid ) { return false; } if( new_water_height < get_groundwater() - 3 ) { return false; } // make a list of tiles to change // cannot use a recursive method as stack is not large enough! sint8 *from_dir = new sint8[get_size().x * get_size().y]; bool local_stage = (our_stage==NULL); if( local_stage ) { our_stage = new sint8[get_size().x * get_size().y]; } memset( our_stage + sizeof(sint8) * array_koord(0,y_min), -1, sizeof(sint8) * get_size().x * (y_max-y_min) ); uint32 offset = array_koord(k.x,k.y); from_dir[offset]=-1; stage[offset]=0; our_stage[offset]=0; do { koord k_neighbour = k + koord::neighbours[our_stage[offset]]; if( k_neighbour.x < x_min || k_neighbour.x>=x_max) { succeeded = false; } else if( k_neighbour.y >= y_min && k_neighbour.y= new_water_height) { goto next_neighbour; } //move on to next tile from_dir[neighbour_offset] = our_stage[offset]; stage[neighbour_offset] = 0; our_stage[neighbour_offset] = 0; k = k_neighbour; offset = neighbour_offset; continue; } else if( succeeded && (global_lake_fill || k_neighbour.y < 1 || k_neighbour.y>=get_size().y-1) ) { // edge of map - we keep iterating so we can mark all connected tiles as failing succeeded = false; } next_neighbour: //return back to previous tile while( our_stage[offset]==7 ) { if( from_dir[offset] == -1 ) goto exit_iteration; // for natural maps only need to have checked one path out from original tile k = k - koord::neighbours[from_dir[offset]]; offset = array_koord(k.x,k.y); } our_stage[offset]++; } while( true ); exit_iteration: delete [] from_dir; if( local_stage ) { delete [] our_stage; } return succeeded; } void karte_t::flood_to_depth( sint8 new_water_height, sint8 *stage ) { const uint16 size_x = get_size().x; const uint16 size_y = get_size().y; uint32 offset_max = size_x*size_y; for( uint32 offset = 0; offset < offset_max; offset++ ) { if( stage[offset] == -1 ) { continue; } water_hgts[offset] = new_water_height; } } // recalcs all ground tiles on the map void karte_t::update_map() { DBG_MESSAGE( "karte_t::update_map()", "" ); world_xy_loop(&karte_t::update_map_intern, SYNCX_FLAG); set_dirty(); } void karte_t::update_underground() { DBG_MESSAGE( "karte_t::update_underground_map()", "" ); get_view()->clear_prepared(); world_view_t::invalidate_all(); set_dirty(); minimap_t::get_instance()->calc_map(); } void karte_t::prepare_tiles(rect_t const &new_area, rect_t const &old_area) { if (new_area == old_area) { // area already prepared return; } size_t const prepare_rects_capacity = rect_t::MAX_FRAGMENT_DIFFERENCE_COUNT; rect_t prepare_rects[prepare_rects_capacity]; size_t const prepare_rects_length = new_area.fragment_difference(old_area, prepare_rects, prepare_rects_capacity); // additional tiles to prepare for correct hiding behaviour sint16 const prefix_tiles_x = min(grund_t::MAXIMUM_HIDE_TEST_DISTANCE, new_area.origin.x); sint16 const prefix_tiles_y = min(grund_t::MAXIMUM_HIDE_TEST_DISTANCE, new_area.origin.y); for (size_t rect_index = 0 ; rect_index < prepare_rects_length ; rect_index++) { rect_t const &prepare_rect = prepare_rects[rect_index]; sint16 x_start = prepare_rect.origin.x; sint16 const x_end = x_start + prepare_rect.size.x; if (x_start == new_area.origin.x) { x_start-= prefix_tiles_x; } sint16 y_start = prepare_rect.origin.y; sint16 const y_end = y_start + prepare_rect.size.y; if (y_start == new_area.origin.y) { y_start-= prefix_tiles_y; } for (sint16 y = y_start ; y < y_end ; y++) { for (sint16 x = x_start ; x < x_end ; x++) { const planquadrat_t &tile = plan[y * cached_grid_size.x + x]; tile.update_underground(); } } } } // distributes climates in a rectangle void karte_t::calc_humidity_map_region( sint16 , sint16 , sint16 xbottom, sint16 ybottom ) { // always calculate the map for the entire map to have smooth transitions humidity_map.resize( xbottom, ybottom ); // some parameter to teaks: // artic height should relate to the gradient, like delta_h/artic_max_height ~ 1/16 change of humidity or temperature // also on smaller maps remoistering must be faster, since this parameter is kept with enlargement, it must be set externally const sint8 height_increase = min( 160 / settings.get_climate_borders(arctic_climate,1), 33 ); const ribi_t::ribi wind = settings.get_wind_dir(); if( wind == ribi_t::west || wind == ribi_t::east ) { const sint16 x0 = wind == ribi_t::west ? 0 : xbottom - 1; const sint16 xmax = wind == ribi_t::west ? xbottom : -1; const sint16 dx = wind == ribi_t::west ? 1 : -1; for( sint16 y = 0; y < ybottom; y++ ) { sint8 current_humidity = 50; // start value for each row for( sint16 x = x0; x < xmax; x+=dx ) { grund_t *gr = lookup_kartenboden(x,y); if( gr->is_water() || gr->hat_weg(water_wt) ) { // increase humidity over water and rivers current_humidity = current_humidity+settings.get_moisture_water(); if( gr->is_water() ) { climate_map.at( x, y ) = water_climate; } } else { sint8 gradient = lookup_hgt_nocheck( x+1, y )-lookup_hgt_nocheck( x, y ); current_humidity += settings.get_moisture() + gradient * height_increase; } current_humidity = clamp( current_humidity, 0, 100 ); humidity_map.at(x,y) = current_humidity; } } } else { const sint16 y0 = wind == ribi_t::north ? 0 : ybottom - 1; const sint16 ymax = wind == ribi_t::north ? ybottom : -1; const sint16 dy = wind == ribi_t::north ? 1 : -1; for( sint16 x = 0; x < xbottom; x++ ) { sint8 current_humidity = 50; // start value for each row for( sint16 y = y0; y < ymax; y+=dy ) { grund_t *gr = lookup_kartenboden(x,y); if( gr->is_water() || gr->hat_weg(water_wt) ) { // increase humidity over water and rivers current_humidity = current_humidity+settings.get_moisture_water(); if( gr->is_water() ) { climate_map.at( x, y ) = water_climate; } } else { sint8 gradient = lookup_hgt_nocheck( x+1, y )-lookup_hgt_nocheck( x, y ); current_humidity += settings.get_moisture() + gradient * height_increase; } current_humidity = clamp( current_humidity, 0, 100 ); humidity_map.at(x,y) = current_humidity; } } } } // distributes climates in a rectangle void karte_t::calc_climate_map_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ) { if( xtop == 0 && ytop == 0 ) { climate_map.clear(); } climate_map.resize( xbottom, ybottom, 0x7F ); switch(settings.get_climate_generator()) { case settings_t::HUMIDITY_BASED: { calc_humidity_map_region( xtop, ytop, xbottom, ybottom ); sint16 groundwater = settings.get_groundwater(); const sint16 winterline = settings.get_winter_snowline(); const sint16 summerline = settings.get_climate_borders( arctic_climate, 1 ); // annual mean temperature at summer snowline must be less than zero // assume annual mean temperature at winter snowline is 14 celcius const sint8 snowline_diff = summerline-winterline; const sint8 groundwater_temperature = 14+((winterline-groundwater)*14)/(snowline_diff!=0 ? snowline_diff:1); // first remove water all clear single tiles from effort // for the first passes, we only work on the grid, which is much faster for( sint16 y = 0; y < ybottom; y++ ) { for( sint16 x = 0; x < xbottom; x++ ) { if( climate_map.at(x,y)==0x7F ) { climate this_climate = arctic_climate; // fallthrough option sint8 hgt = lookup_hgt_nocheck(x,y) - groundwater; sint8 temperature = groundwater_temperature - (hgt-groundwater) - simrand(2); sint8 this_humidity = humidity_map.at(x,y) + simrand(5); if( temperature >= settings.get_climate_temperature_borders(0) ) { if( this_humidity > settings.get_tropic_humidity() ) { this_climate = tropic_climate; } else if( this_humidity > settings.get_desert_humidity() ) { this_climate = mediterran_climate; } else { this_climate = desert_climate; } } else if( temperature >= settings.get_climate_temperature_borders(1) ) { if( this_humidity > settings.get_desert_humidity() ) { this_climate = mediterran_climate; } else { this_climate = desert_climate; } } else if( temperature >= settings.get_climate_temperature_borders(2) ) { if( this_humidity > settings.get_desert_humidity() ) { this_climate = temperate_climate; } else { this_climate = mediterran_climate; } } else if( temperature >= settings.get_climate_temperature_borders(3) ) { if( this_humidity > settings.get_desert_humidity() ) { this_climate = tundra_climate; } else { this_climate = temperate_climate; } } else if( temperature >= settings.get_climate_temperature_borders(4) ) { this_climate = rocky_climate; } if( x >= xtop && y >= ytop ) { climate_map.at( x, y ) = this_climate; } } } } // smooth climates (this code needs a little cleanup, I think) const sint32 world_size = xbottom*(sint32)ybottom; climate *climate_smooth = new climate[world_size]; climate *climate_smooth_cpy = new climate[world_size]; for(uint16 y=0; y= 0; if( within_limits && climate_smooth_cpy[k_neighbour.x+k_neighbour.y*xbottom]!=water_climate ) { this_climate = climate_smooth_cpy[k_neighbour.x+k_neighbour.y*xbottom]; } else { this_climate = climate_smooth_cpy[x+y*xbottom]; } temp_climate += (i&1) ? (2 * (this_climate)) : (this_climate); } //if(s<8) temp_height += sets->get_map_roughness()*(simrand(8)); climate_smooth[x+y*xbottom]=(climate)((temp_climate)/16); } } } } for(uint16 y=ytop; y allowed( 8 ); { // find the next climateless tile for( sint16 y = ytop; y < ybottom; y++ ) { for( sint16 x = xtop; x < xbottom; x++ ) { if( climate_map.at( x, y ) > arctic_climate ) { // not assigned yet => start with a random allowed climate allowed.clear(); sint8 hgt = lookup_hgt_nocheck( x, y ); for( int cl=1; cl= settings.get_climate_borders( cl, 0 ) && hgt < settings.get_climate_borders( cl, 1 ) ) { allowed.append(cl); } } //assert( !allowed.empty() ); climate cl = !allowed.empty() ? (climate)pick_any(allowed) : temperate_climate; // now we do an ellipse with size wx and wy around the starting point const sint32 wx = 2+simrand( max_patchsize_x ); const sint32 wy = 2+simrand( max_patchsize_y ); for( sint16 j = 0; j < wx; j++) { for( sint16 i = 0; i < wy; i++) { const sint32 x_off = (j-(wx>>1)); const sint32 y_off = (i-(wy>>1)); if( x+x_off>=xtop && x+x_off=ytop && y+y_offarctic_climate ) { const uint64 distance = 1 + sqrt_i64( ((uint64)x_off*x_off*(wx*wx) + (uint64)y_off*y_off*(wy*wy))); const uint32 threshold = (uint32)( ( 8 * (uint32)((wx*wx)+(wy*wy)) ) / distance ); if( threshold > 40 ) { hgt = lookup_hgt_nocheck( x+x_off, y+y_off ); // find out if the climate is still allowed here if( hgt >= settings.get_climate_borders( cl, 0 ) && hgt <= settings.get_climate_borders( cl, 1 ) ) { climate_map.at( x+x_off, y+y_off ) = cl; } } } } } } } } } } break; case settings_t::MAP_BASED: { /* Essentially keep the climates from this map * we just have to set the tiles with water to water climate * and vice vers */ for( sint16 y = ytop; y < ybottom; y++ ) { for( sint16 x = xtop; x < xbottom; x++ ) { sint8 hgt = lookup_hgt_nocheck( x, y ); if( hgt < groundwater ) { climate_map.at( x, y ) = water_climate; } else if( climate_map.at( x, y )==water_climate ) { climate_map.at( x, y ) = height_to_climate[hgt-groundwater]; } } } } break; } assign_climate_map_region( xtop, ytop, xbottom, ybottom ); } void karte_t::assign_climate_map_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ) { for( sint16 y = ytop; y < ybottom; y++ ) { for( sint16 x = xtop; x < xbottom; x++ ) { if( planquadrat_t *pl = access( x, y ) ) { if( pl->get_kartenboden()->is_water() ) { // full water tile pl->set_climate( water_climate ); pl->set_climate_transition_flag(false); pl->set_climate_corners(0); climate_map.at( x, y ) = water_climate; } else { // test for beach tiles (if climate is not desert) bool beach = false; if( climate_map.at(x,y)!=desert_climate ) { grund_t *gr = pl->get_kartenboden(); if( gr->get_pos().z == groundwater ) { for( int i = 0; i < 8 && !beach; i++ ) { grund_t *gr2 = lookup_kartenboden( koord(x,y) + koord::neighbours[i] ); if( gr2 && gr2->is_water() ) { beach = true; } } } } // beach or only one climate uint8 cl = beach ? (uint8)desert_climate : climate_map.at(x,y); pl->set_climate( (climate)cl ); climate_map.at( x, y ) = cl; pl->set_climate_transition_flag(false); pl->set_climate_corners(0); } } } } } void karte_t::recalc_transitions_loop( sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max ) { for( int y = y_min; y < y_max; y++ ) { for( int x = x_min; x < x_max; x++ ) { recalc_transitions( koord( x, y ) ); } } } uint8 karte_t::sp2num(player_t *player) { if( player==NULL ) { return PLAYER_UNOWNED; } for(int i=0; ifatal( "karte_t::sp2num()", "called with an invalid player!" ); } void karte_t::load_heightfield(settings_t* const sets) { sint16 w, h; sint8 *h_field = NULL; const sint8 min_h = sets->get_minimumheight(); const sint8 max_h = sets->get_maximumheight(); height_map_loader_t hml(min_h, max_h, env_t::height_conv_mode); if(hml.get_height_data_from_file(sets->heightfield.c_str(), (sint8)(sets->get_groundwater()), h_field, w, h, false )) { sets->set_size(w,h); // create map init(sets,h_field); free(h_field); } else { dbg->error("karte_t::load_heightfield()","Cant open file '%s'", sets->heightfield.c_str()); create_win( new news_img("\nCan't open heightfield file.\n"), w_info, magic_none ); } } void karte_t::mark_area( const koord3d pos, const koord size, const bool mark ) const { for( sint16 y=pos.y; yset_flag(grund_t::marked); } else { gr->clear_flag(grund_t::marked); } gr->set_flag(grund_t::dirty); } } } } void karte_t::reset_timer() { // Reset timers uint32 last_tick_sync = dr_time(); mouse_rest_time = last_tick_sync; sound_wait_time = AMBIENT_SOUND_INTERVALL; intr_set_last_time(last_tick_sync); if( env_t::networkmode && (step_mode&PAUSE_FLAG)==0 ) { step_mode = FIX_RATIO; } last_interaction = last_tick_sync; last_step_ticks = ticks; // reinit simloop counter for( int i=0; i<32; i++ ) { last_step_nr[i] = steps; } if( step_mode&PAUSE_FLAG ) { intr_disable(); } else if(step_mode==FAST_FORWARD) { next_step_time = last_tick_sync+1; idle_time = 0; set_frame_time( 1000 / env_t::ff_fps ); time_multiplier = 16; intr_enable(); } else if(step_mode==FIX_RATIO) { last_frame_idx = 0; fix_ratio_frame_time = 1000 / clamp(settings.get_frames_per_second(), env_t::min_fps, env_t::max_fps); next_step_time = last_tick_sync + fix_ratio_frame_time; set_frame_time( fix_ratio_frame_time ); intr_disable(); // other stuff needed to synchronize tile_counter = 0; pending_season_change = 1; pending_snowline_change = 1; } else { // make timer loop invalid for( int i=0; i<32; i++ ) { last_frame_ms[i] = dr_time(); } last_frame_idx = 0; simloops = 60; set_frame_time( 1000/env_t::fps ); next_step_time = last_tick_sync+(3200/get_time_multiplier() ); intr_enable(); } DBG_MESSAGE("karte_t::reset_timer()","called, mode=$%X", step_mode); } void karte_t::reset_interaction() { last_interaction = dr_time(); } void karte_t::set_map_counter(uint32 new_map_counter) { map_counter = new_map_counter; if( env_t::server ) { nwc_ready_t::append_map_counter(map_counter); } } uint32 karte_t::generate_new_map_counter() const { return dr_time(); } // jump one year ahead // (not updating history!) void karte_t::step_year() { DBG_MESSAGE("karte_t::step_year()","called"); current_month += 12; last_year ++; reset_timer(); recalc_average_speed(); koord::locality_factor = settings.get_locality_factor( last_year ); for(stadt_t* const i : cities) { i->recalc_target_cities(); i->recalc_target_attractions(); } } // jump one or more months ahead // (updating history!) void karte_t::step_month( sint16 months ) { while( months-->0 ) { new_month(); } reset_timer(); } sint32 karte_t::get_time_multiplier() const { return step_mode==FAST_FORWARD ? env_t::max_acceleration : time_multiplier; } void karte_t::change_time_multiplier(sint32 delta) { if( step_mode == FAST_FORWARD ) { if( env_t::max_acceleration+delta > 2 ) { env_t::max_acceleration += delta; } } else { time_multiplier += delta; if(time_multiplier<=0) { time_multiplier = 1; } if(step_mode!=NORMAL) { step_mode = NORMAL; reset_timer(); } } } void karte_t::set_pause(bool p) { bool pause = step_mode&PAUSE_FLAG; if(p!=pause) { step_mode ^= PAUSE_FLAG; if(p) { intr_disable(); } else { reset_timer(); } } } void karte_t::set_fast_forward(bool ff) { if( !env_t::networkmode ) { if( ff ) { if( step_mode==NORMAL ) { step_mode = FAST_FORWARD; reset_timer(); } } else { if( step_mode==FAST_FORWARD ) { step_mode = NORMAL; reset_timer(); } } } } /* creates a new player with this type */ const char *karte_t::init_new_player(uint8 new_player_in, uint8 type) { if( new_player_in>=PLAYER_UNOWNED || get_player(new_player_in)!=NULL ) { return "Id invalid/already in use!"; } switch( type ) { case player_t::EMPTY: break; case player_t::HUMAN: players[new_player_in] = new player_t(new_player_in); break; case player_t::AI_GOODS: players[new_player_in] = new ai_goods_t(new_player_in); break; case player_t::AI_PASSENGER: players[new_player_in] = new ai_passenger_t(new_player_in); break; case player_t::AI_SCRIPTED: players[new_player_in] = new ai_scripted_t(new_player_in); break; default: return "Unknown AI type!"; } settings.set_player_type(new_player_in, type); return NULL; } void karte_t::remove_player(uint8 player_nr) { if ( player_nr!=PLAYER_PUBLIC_NR && player_nrai_bankrupt(); delete players[player_nr]; players[player_nr] = NULL; nwc_chg_player_t::company_removed(player_nr); // if default human, create new instace of it (to avoid crashes) if( player_nr == PLAYER_HUMAN_NR ) { players[0] = new player_t( PLAYER_HUMAN_NR ); } // if currently still active => reset to default human if( player_nr == active_player_nr ) { active_player_nr = PLAYER_HUMAN_NR; active_player = players[PLAYER_HUMAN_NR]; if( !env_t::server ) { const scr_coord pos{ display_get_width()/2-128, 40 }; create_win( pos, new news_img("Bankrott:\n\nDu bist bankrott.\n"), w_info, magic_none); } } } } /* goes to next active player */ void karte_t::switch_active_player(uint8 new_player, bool silent) { for( uint8 i=0; iget_pos(); // no cheating allowed? if (!settings.get_allow_player_change() && get_public_player()->is_locked()) { active_player_nr = PLAYER_HUMAN_NR; active_player = players[PLAYER_HUMAN_NR]; if(new_player!=PLAYER_HUMAN_NR) { create_win( new news_img("On this map, you are not\nallowed to change player!\n"), w_time_delete, magic_none); } } else { zeiger->change_pos( koord3d::invalid ); // unmark area // exit active tool to remove pointers (for two_click_tool_t's, stop mover, factory linker) if(selected_tool[active_player_nr]) { selected_tool[active_player_nr]->exit(active_player); } active_player_nr = new_player; active_player = players[new_player]; if( !silent ) { // tell the player cbuffer_t buf; buf.printf( translator::translate("Now active as %s.\n"), get_active_player()->get_name() ); msg->add_message(buf, koord3d::invalid, message_t::ai | message_t::DO_NOT_SAVE_MSG, PLAYER_FLAG|get_active_player()->get_player_nr(), IMG_EMPTY); } // update menu entries tool_t::update_toolbars(); set_dirty(); } // init tool again selected_tool[active_player_nr]->flags = 0; selected_tool[active_player_nr]->init(active_player); // update pointer image / area selected_tool[active_player_nr]->init_cursor(zeiger); // set position / mark area zeiger->change_pos( old_zeiger_pos ); } void karte_t::stop(bool exit_game) { finish_loop = true; if (exit_game) { env_t::quit_simutrans = true; DBG_DEBUG("ev=SYSTEM_QUIT", "env_t::reload_and_save_on_quit=%d", env_t::reload_and_save_on_quit); // we may be requested to save the game before exit if (env_t::server && env_t::server_save_game_on_quit) { // to ensure only one attempt is made env_t::server_save_game_on_quit = false; // following code quite similar to nwc_sync_t::do_coomand dr_chdir(env_t::user_dir); // first save password hashes char fn[256]; sprintf(fn, "server%d-pwdhash.sve", env_t::server); loadsave_t file; if (file.wr_open(fn, loadsave_t::zipped, 1, "hashes", SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK) { world->rdwr_player_password_hashes(&file); file.close(); } // remove passwords before transfer on the server and set default client mask // they will be restored in karte_t::load for (uint8 i = 0; i < PLAYER_UNOWNED; i++) { player_t *player = world->get_player(i); if (player && !player->access_password_hash().empty()) { player->access_password_hash().clear(); } } // save game sprintf(fn, "server%d-restore.sve", env_t::server); bool old_restore_UI = env_t::restore_UI; env_t::restore_UI = true; world->save(fn, false, SAVEGAME_VER_NR, false); env_t::restore_UI = old_restore_UI; } else if (env_t::reload_and_save_on_quit) { if (env_t::networkmode) { // construct from pak name an autosave if requested std::string pak_name("autosave-"); pak_name.append(env_t::pak_name); pak_name.erase(pak_name.length() - 1); pak_name.append(".net"); FILE *f = dr_fopen(pak_name.c_str(), "w"); fputs(settings.get_filename(), f); fclose(f); // save windows loadsave_t file; pak_name.append(".sve"); if (file.wr_open(pak_name.c_str(), loadsave_t::autosave_mode, loadsave_t::autosave_level, env_t::pak_name.c_str(), SAVEGAME_VER_NR) == loadsave_t::FILE_STATUS_OK) { // we could open for writing file.rdwr_byte(active_player_nr); // save all open windows rdwr_all_win(&file); } } else { // save current game, if not online bool old_restore_UI = env_t::restore_UI; env_t::restore_UI = true; // construct from pak name an autosave if requested std::string pak_name("autosave-"); pak_name.append(env_t::pak_name); pak_name.erase(pak_name.length() - 1); pak_name.append(".sve"); dr_chdir(env_t::user_dir); world->save(pak_name.c_str(), true, SAVEGAME_VER_NR, false); env_t::restore_UI = old_restore_UI; } } destroy_all_win(true); } } void karte_t::network_game_set_pause(bool pause_, uint32 syncsteps_) { if (env_t::networkmode) { time_multiplier = 16; // reset to normal speed sync_steps = syncsteps_; sync_steps_barrier = sync_steps; steps = sync_steps / settings.get_frames_per_step(); network_frame_count = sync_steps % settings.get_frames_per_step(); dbg->warning("karte_t::network_game_set_pause", "steps=%d sync_steps=%d pause=%d", steps, sync_steps, pause_); if (pause_) { if (!env_t::server) { reset_timer(); step_mode = PAUSE_FLAG|FIX_RATIO; } else { // TODO } } else { step_mode = FIX_RATIO; reset_timer(); if( !env_t::server ) { // allow server to run ahead the specified number of frames, plus an extra 50%. Better to catch up than be ahead. next_step_time = dr_time() + (settings.get_server_frames_ahead() + (uint32)env_t::additional_client_frames_behind) * fix_ratio_frame_time * 3 / 2; } } } else { set_pause(pause_); } } const char* karte_t::call_work_api(tool_t *tool, player_t *player, koord3d pos, bool &suspended) { suspended = false; const char *err = NULL; bool network_safe_tool = tool->is_work_keeps_game_state() || tool->is_work_here_keeps_game_state(player, pos); // do the check for allowed (always done locally) tool->flags |= tool_t::WFL_LOCAL; // first allowance by scenario if( (tool->flags & tool_t::WFL_NO_CHK) == 0 && get_scenario()->is_scripted() ) { if( !get_scenario()->is_tool_allowed(player, tool->get_id(), tool->get_waytype(), tool->get_default_param()) ) { err = "Forbidden by scenario"; } else { err = get_scenario()->is_work_allowed_here(player, tool->get_id(), tool->get_waytype(), tool->get_default_param(), pos); } } if (err == NULL) { if( !env_t::networkmode || network_safe_tool ) { if( network_safe_tool || (get_random_mode() & INTERACTIVE_RANDOM) == 0 ) { // call work if it would not affect game state or if the call is not during sync_step err = tool->work(player, pos); suspended = false; } else { // queue tool for execution (will be only done when NOT in networkmode!) nwc_tool_t* nwc = new nwc_tool_t(player, tool, pos, get_steps(), get_map_counter(), false); command_queue_append(nwc); // reset tool tool->init(player); suspended = true; } } else { // queue tool for network nwc_tool_t *nwc = new nwc_tool_t(player, tool, pos, get_steps(), get_map_counter(), false); network_send_server(nwc); suspended = true; // reset tool tool->init(player); } } return err; } static slist_tpl command_queue; static koord3d next_deferred_move_to = koord3d::invalid; static uint8 next_deferred_move_flags = 0; void karte_t::set_deferred_move_to(koord3d k, uint8 f) { next_deferred_move_to = k; next_deferred_move_flags = f; } void karte_t::command_queue_append(network_world_command_t* nwc) const { slist_tpl::iterator i = command_queue.begin(); slist_tpl::iterator end = command_queue.end(); while(i != end && network_world_command_t::cmp(*i, nwc)) { ++i; } command_queue.insert(i, nwc); } void karte_t::clear_command_queue() const { while (!command_queue.empty()) { delete command_queue.remove_first(); } } static void encode_URI(cbuffer_t& buf, char const* const text) { for (char const* i = text; *i != '\0'; ++i) { char const c = *i; if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '-' || c == '.' || c == '_' || c == '~') { char const two[] = { c, '\0' }; buf.append(two); } else { buf.printf("%%%02X", (unsigned char)c); } } } void karte_t::process_network_commands(sint32 *ms_difference) { // did we receive a new command? uint32 ms = dr_time(); sint32 time_to_next_step = (sint32)next_step_time - (sint32)ms; network_command_t *nwc = network_check_activity(clamp(time_to_next_step, 0, 5)); if( nwc==NULL && !network_check_server_connection() ) { dbg->warning("karte_t::process_network_commands", "lost connection to server"); network_disconnect(); return; } // process the received command while( nwc ) { // check timing uint16 const nwcid = nwc->get_id(); if( nwcid == NWC_CHECK || nwcid == NWC_STEP ) { // pull out server sync step const uint32 server_sync_step = nwcid == NWC_CHECK ? dynamic_cast(nwc)->server_sync_step : dynamic_cast(nwc)->get_sync_step(); // are we on time? *ms_difference = 0; const uint32 timems = dr_time(); const sint32 time_to_next = (sint32)next_step_time - (sint32)timems; // +'ve - still waiting for next, -'ve - lagging const sint64 frame_timediff = ((sint64)server_sync_step - sync_steps - settings.get_server_frames_ahead() - env_t::additional_client_frames_behind) * fix_ratio_frame_time; // +'ve - server is ahead, -'ve - client is ahead const sint64 timediff = time_to_next + frame_timediff; dbg->warning("NWC_CHECK", "time difference to server %lli", frame_timediff ); if( frame_timediff < (0 - (sint64)settings.get_server_frames_ahead() - (sint64)env_t::additional_client_frames_behind) * (sint64)fix_ratio_frame_time / 2 ) { // running way ahead - more than half margin, simply set next_step_time ahead to where it should be next_step_time = (sint64)timems - frame_timediff; } else if( frame_timediff < 0 ) { // running ahead if( time_to_next > -frame_timediff ) { // already waiting longer than how far we're ahead, so set wait time shorter to the time ahead. next_step_time = (sint64)timems - frame_timediff; } else if( nwcid == NWC_CHECK ) { // gentle slowing down *ms_difference = timediff; } } else if( frame_timediff > 0 ) { // running behind if( time_to_next > (sint32)fix_ratio_frame_time / 4 ) { // behind but we're still waiting for the next step time - get going. next_step_time = timems; *ms_difference = frame_timediff; } else if( nwcid == NWC_CHECK ) { // gentle catching up *ms_difference = timediff; } } if( sync_steps_barrier < server_sync_step ) { sync_steps_barrier = server_sync_step; } } // check random number generator states if( env_t::server && nwcid == NWC_TOOL ) { nwc_tool_t *nwt = dynamic_cast(nwc); if( nwt->is_from_initiator() ) { if( nwt->last_sync_step>sync_steps ) { dbg->warning("karte_t::process_network_commands", "client was too fast (skipping command)" ); delete nwc; nwc = NULL; } // out of sync => drop client (but we can only compare if nwt->last_sync_step is not too old) else if( is_checklist_available(nwt->last_sync_step) && LCHKLST(nwt->last_sync_step)!=nwt->last_checklist ) { // lost synchronisation -> server kicks client out actively cbuffer_t buf; LCHKLST(nwt->last_sync_step).print(buf, "server"); nwt->last_checklist.print(buf, "initiator"); dbg->warning("karte_t::process_network_commands", "kicking client due to checklist mismatch : sync_step=%u %s", nwt->last_sync_step, buf.get_str()); socket_list_t::remove_client( nwc->get_sender() ); delete nwc; nwc = NULL; } } } // execute command, append to command queue if necessary if(nwc && nwc->execute(this)) { // network_world_command_t's will be appended to command queue in execute // all others have to be deleted here delete nwc; } // fetch the next command nwc = network_get_received_command(); } uint32 next_command_step = get_next_command_step(); // send data ms = dr_time(); network_process_send_queues( next_step_time>ms ? min( next_step_time-ms, 5) : 0 ); // process enqueued network world commands while( !command_queue.empty() && (next_command_step<=sync_steps/* || step_mode&PAUSE_FLAG*/) ) { network_world_command_t *nwc = command_queue.remove_first(); if (nwc) { do_network_world_command(nwc); delete nwc; } next_command_step = get_next_command_step(); } } void karte_t::do_network_world_command(network_world_command_t *nwc) { // want to execute something in the past? if (nwc->get_sync_step()!=0 && nwc->get_sync_step() < sync_steps) { if (!nwc->ignore_old_events()) { dbg->warning("karte_t:::do_network_world_command", "wanted to do_command(%s) in the past", nwc->get_name()); network_disconnect(); } } // check map counter else if (nwc->get_map_counter() != map_counter) { dbg->warning("karte_t:::do_network_world_command", "wanted to do_command(%s) from another world", nwc->get_name()); } // check random counter? else if( nwc->get_id()==NWC_CHECK ) { nwc_check_t* nwcheck = (nwc_check_t*)nwc; // this was the random number at the previous sync step on the server const checklist_t &server_checklist = nwcheck->server_checklist; const uint32 server_sync_step = nwcheck->server_sync_step; cbuffer_t buf; server_checklist.print(buf, "server"); LCHKLST(server_sync_step).print(buf, "client"); dbg->warning("karte_t:::do_network_world_command", "sync_step=%u %s", server_sync_step, buf.get_str()); if( LCHKLST(server_sync_step)!=server_checklist ) { network_disconnect(); // output warning / throw fatal error depending on heavy mode setting void (log_t::*outfn)(const char*, const char*, ...) = (env_t::network_heavy_mode == 2 ? &log_t::fatal : &log_t::warning); (dbg->*outfn)("karte_t:::do_network_world_command", "Disconnected due to checklist mismatch" ); } } else { if( nwc->get_id()==NWC_TOOL ) { nwc_tool_t *nwt = dynamic_cast(nwc); if( is_checklist_available(nwt->last_sync_step) && LCHKLST(nwt->last_sync_step)!=nwt->last_checklist ) { // lost synchronisation ... cbuffer_t buf; nwt->last_checklist.print(buf, "server"); LCHKLST(nwt->last_sync_step).print(buf, "executor"); dbg->warning("karte_t:::do_network_world_command", "skipping command due to checklist mismatch : sync_step=%u %s", nwt->last_sync_step, buf.get_str()); if( !env_t::server ) { network_disconnect(); } return; } } nwc->do_command(this); } } uint32 karte_t::get_next_command_step() { // when execute next command? if( !command_queue.empty() ) { return command_queue.front()->get_sync_step(); } else { return 0xFFFFFFFFu; } } sint16 karte_t::get_sound_id(grund_t *gr) { if( gr->ist_natur() || gr->is_water() ) { // first, find out if climates overlap for shore const koord k = gr->get_pos().get_2d(); uint8 climate_corners = access(k)->get_climate_corners(); if (climate_corners && sound_desc_t::beach_sound!=NO_SOUND) { for (int i = 0; i < 8; i++) { koord k_neighbour = k + koord::neighbours[i]; if (!is_within_limits(k_neighbour)) { k_neighbour = get_closest_coordinate(k_neighbour); } if(water_climate == get_climate(k_neighbour)) { // one croner water => shore return sound_desc_t::beach_sound; } } } // try forest if ( sound_desc_t::forest_sound!=NO_SOUND && gr->obj_count() > 0 && gr->obj_bei(0)->get_typ() == obj_t::baum ) { return sound_desc_t::forest_sound; } if( gr->get_pos().z >= get_snowline() ) { return sound_desc_t::climate_sounds[ arctic_climate ]; } else { return sound_desc_t::climate_sounds[get_climate( k )]; } } return NO_SOUND; } static void heavy_rotate_saves(const char *prefix, uint32 sync_steps, uint32 num_to_keep) { dr_chdir(env_t::user_dir); dr_mkdir( SAVE_PATH_X "heavy"); cbuffer_t name; name.printf(SAVE_PATH_X "heavy/heavy-%s-%04d.sve", prefix, sync_steps); world()->save(name, false, SERVER_SAVEGAME_VER_NR, true); if (sync_steps >= num_to_keep) { cbuffer_t old_name; old_name.printf(SAVE_PATH_X "heavy/heavy-%s-%04d.sve", prefix, sync_steps - num_to_keep); dr_remove(old_name); } } bool karte_t::interactive(uint32 quit_month) { finish_loop = false; sync_steps = 0; sync_steps_barrier = sync_steps; next_deferred_move_to = koord3d::invalid; network_frame_count = 0; vector_tplhashes_ok; // bit set: this client can do something with this player if( !scenario->rdwr_ok() ) { // error during loading of savegame of scenario create_win( new news_img( scenario->get_error_text() ), w_info, magic_none); scenario->stop(); } // only needed for network if( env_t::networkmode ) { // clear the checklist history for( int i=0; iget_pos()); if( gr ) { sint16 id = get_sound_id(gr); if( id!=NO_SOUND ) { sound_play(id,255,AMBIENT_SOUND); } } sound_wait_time *= 2; } DBG_DEBUG4("karte_t::interactive", "end of sound"); } // events are now checked during each screen update for quicker feedback on scrolling etc. if (env_t::quit_simutrans){ break; } if (next_deferred_move_to != koord3d::invalid) { // some tool movement is expensive (like route search) and must be done outsied sync_step // to avoid calling a the non-reentrant route search twice tool_t *tool = selected_tool[active_player_nr]; const char* err = scenario->is_work_allowed_here(active_player, tool->get_id(), tool->get_waytype(), tool->get_default_param(), next_deferred_move_to); if (err == NULL) { koord3d target = next_deferred_move_to; next_deferred_move_to = koord3d::invalid; tool->flags = next_deferred_move_flags; tool->move(active_player, true, target); tool->flags = 0; } else if (two_click_tool_t *tct = dynamic_cast(tool)) { // remove preview images if (!tct->is_first_click()) { tct->cleanup(false); } } next_deferred_move_to = koord3d::invalid; next_deferred_move_flags = 0; } if( env_t::networkmode ) { process_network_commands(&ms_difference); } else { // we wait here for maximum 9ms // average is 5 ms, so we usually // are quite responsive DBG_DEBUG4("karte_t::interactive", "can I get some sleep?"); INT_CHECK( "karte_t::interactive()" ); const sint32 wait_time = (sint32)next_step_time - (sint32)dr_time(); if(wait_time>2) { dr_sleep(2); INT_CHECK("karte_t::interactive()"); } DBG_DEBUG4("karte_t::interactive", "end of sleep"); // process enqueued network world commands while (!command_queue.empty()) { network_world_command_t* nwc = command_queue.remove_first(); if (nwc) { nwc->do_command(this); delete nwc; } } INT_CHECK("karte_t::interactive()"); } uint32 time = dr_time(); if( (sint32)next_misc_time - (sint32)time <=0 ) { #ifdef STEAM_BUILT steam_t::get_instance()->update_ui(get_last_year(), convoys().get_count()); #endif simachievements_t::check_state_ach(this); next_misc_time = time + 5000; // every 5s } // check midi if next songs needs to be started if( (sint32)next_midi_time - (sint32)time <= 0 ) { DBG_DEBUG4("karte_t::interactive", "checkmidi"); check_midi(); next_midi_time = time + 1500; // check every 1.5 s if we need to start next song } // time for the next step? if( (sint32)next_step_time - (sint32)time <= 0 ) { if( step_mode&PAUSE_FLAG ) { // only update display display(0); idle_time = 100; eventmanager->check_events(); } else if( env_t::networkmode && !env_t::server && sync_steps >= sync_steps_barrier ) { display(0); next_step_time = time + fix_ratio_frame_time; } else { if( step_mode==FAST_FORWARD ) { sync_step( 100 ); set_random_mode( STEP_RANDOM ); step(); clear_random_mode( STEP_RANDOM ); } else if( step_mode==FIX_RATIO ) { if( env_t::server ) { next_step_time += fix_ratio_frame_time; } else { const sint32 lag_time = (sint32)time - (sint32)next_step_time; if( lag_time > 0 ) { ms_difference += lag_time; next_step_time = time; } const sint32 nst_diff = clamp( ms_difference, -fix_ratio_frame_time * 2, fix_ratio_frame_time * 8 ) / 10; // allows timerate between 83% and 500% of normal next_step_time += fix_ratio_frame_time - nst_diff; ms_difference -= nst_diff; } const uint32 delta_t = (fix_ratio_frame_time*time_multiplier)/16; sync_step( delta_t ); display( delta_t ); if (++network_frame_count == settings.get_frames_per_step()) { set_random_mode( STEP_RANDOM ); step(); clear_random_mode( STEP_RANDOM ); network_frame_count = 0; } sync_steps = steps * settings.get_frames_per_step() + network_frame_count; switch(env_t::network_heavy_mode) { case 0: default: LCHKLST(sync_steps) = checklist_t(get_random_seed(), halthandle_t::get_next_check(), linehandle_t::get_next_check(), convoihandle_t::get_next_check()); break; case 2: heavy_rotate_saves(env_t::server ? "server" : "client", sync_steps, 10); // fall-through case 1: LCHKLST(sync_steps) = checklist_t(get_gamestate_hash()); } // some server side tasks if( env_t::networkmode && env_t::server ) { // broadcast sync info regularly and when lagged const sint64 timelag = (sint32)dr_time() - (sint32)next_step_time; if( (network_frame_count == 0 && timelag > fix_ratio_frame_time * settings.get_server_frames_ahead() / 2) || (sync_steps % env_t::server_sync_steps_between_checks) == 0 ) { const sint64 time_per_step = fix_ratio_frame_time * settings.get_frames_per_step(); static sint64 previous_lag = 0; if( timelag > 1*time_per_step ) { // log when server is lagged more than one step, but only if it gets worse (don't spam log) if (timelag/time_per_step > previous_lag/time_per_step) { dbg->warning("karte_t::interactive", "Server lagging by %lli ms (%d steps)", timelag, (sint32)(timelag/time_per_step) ); } } previous_lag = timelag; nwc_check_t* nwc = new nwc_check_t(sync_steps + 1, map_counter, LCHKLST(sync_steps), sync_steps); network_send_all(nwc, true); } else { // broadcast sync_step nwc_step_t* nwcstep = new nwc_step_t(sync_steps, map_counter); network_send_all(nwcstep, true); } } // no clients -> pause game if ( env_t::networkmode && env_t::pause_server_no_clients && socket_list_t::get_playing_clients() == 0 && !nwc_join_t::is_pending() ) { set_pause(true); } } else { // normal ratio INT_CHECK( "karte_t::interactive()" ); set_random_mode( STEP_RANDOM ); step(); clear_random_mode( STEP_RANDOM ); uint32 cur_time = dr_time(); if (next_step_time > cur_time) { // slowly change idel time idle_time = ( (idle_time * 7) + (next_step_time - cur_time) ) / 8; } else { // but half if we are really far behind idle_time >>= 1; } INT_CHECK( "karte_t::interactive()" ); } } } // Interval-based server announcements if ( env_t::server && env_t::server_announce && env_t::server_announce_interval > 0 && dr_time() - server_last_announce_time >= (uint32)env_t::server_announce_interval * 1000 ) { announce_server( karte_t::SERVER_ANNOUNCE_HEARTBEAT ); } DBG_DEBUG4("karte_t::interactive", "point of loop return"); } while(!finish_loop && get_current_month()= quit_month ) { env_t::quit_simutrans = true; } // On quit announce server as being offline if( env_t::server && env_t::server_announce ) { announce_server( karte_t::SERVER_ANNOUNCE_GOODBYE ); } intr_enable(); display_show_pointer(true); return finish_loop; #undef LRAND } // Announce server to central listing server // Status is one of: // 0 - startup // 1 - interval // 2 - shutdown void karte_t::announce_server(server_announce_type_t status) { DBG_DEBUG( "announce_server()", "status: %i", (int)status ); // Announce game info to server, format is: // st=on&dns=server.com&port=13353&rev=1234&pak=pak128&name=some+name&time=3,1923&size=256,256&active=[0-16]&locked=[0-16]&clients=[0-16]&towns=15&citizens=3245&factories=33&convoys=56&stops=17 // (This is the data part of an HTTP POST) if( env_t::server && env_t::server_announce ) { // in easy_server mode, we assume the IP may change frequently and thus query it before each announce cbuffer_t ip_buf, altip_buf; if( env_t::easy_server && status!=SERVER_ANNOUNCE_GOODBYE && get_external_IP(ip_buf,altip_buf) ) { // update IP just in case if( status == SERVER_ANNOUNCE_HEARTBEAT && (env_t::server_dns.compare( ip_buf )!=0 || env_t::server_alt_dns.compare( altip_buf )!=0) ) { announce_server( SERVER_ANNOUNCE_GOODBYE ); status = SERVER_ANNOUNCE_HELLO; // since starting with new IP // if we had uPnP, we may need to drill another hole in the firewall again; the delay is no problem, since all clients will be lost anyway char IP[256], altIP[256]; prepare_for_server( IP, altIP, env_t::server_port ); } // now update DNS info env_t::server_dns = (const char *)ip_buf; env_t::server_alt_dns = (const char *)altip_buf; } // Always send dns and port as these are used as the unique identifier for the server cbuffer_t buf; buf.append( "&dns=" ); encode_URI( buf, env_t::server_dns.c_str() ); buf.append( "&alt_dns=" ); encode_URI( buf, env_t::server_alt_dns.c_str() ); buf.printf( "&port=%u", env_t::server ); // Always send announce interval to allow listing server to predict next announce buf.printf( "&aiv=%u", env_t::server_announce_interval ); // Always send status, either online or offline if ( status == SERVER_ANNOUNCE_HELLO || status == SERVER_ANNOUNCE_HEARTBEAT ) { buf.append( "&st=1" ); } else { buf.append( "&st=0" ); } #ifndef REVISION # define REVISION 0 #endif // Simple revision used for matching (integer) buf.printf( "&rev=%d", (int)atol( QUOTEME(REVISION) )); // Complex version string used for display buf.printf( "&ver=Simutrans %s (r%s) built %s", QUOTEME(VERSION_NUMBER), QUOTEME(REVISION), QUOTEME(VERSION_DATE) ); // Pakset version buf.append( "&pak=" ); // Announce pak set, ideally get this from the copyright field of ground.Outside.pak char const* const copyright = ground_desc_t::outside->get_copyright(); if (copyright && STRICMP("none", copyright) != 0) { // construct from outside object copyright string encode_URI( buf, copyright ); } else { // construct from pak name std::string pak_name = env_t::pak_name; pak_name.erase( pak_name.length() - 1 ); encode_URI( buf, pak_name.c_str() ); } // TODO - change this to be the start date of the current map buf.printf( "&start=%u,%u", settings.get_starting_month() + 1, settings.get_starting_year() ); // Add server name for listing buf.append( "&name=" ); encode_URI( buf, env_t::server_name.c_str() ); // Add server comments for listing buf.append( "&comments=" ); encode_URI( buf, env_t::server_comments.c_str() ); // Add server maintainer email for listing buf.append( "&email=" ); encode_URI( buf, env_t::server_email.c_str() ); // Add server pakset URL for listing buf.append( "&pakurl=" ); encode_URI( buf, env_t::server_pakurl.c_str() ); // Add server info URL for listing buf.append( "&infurl=" ); encode_URI( buf, env_t::server_infurl.c_str() ); // Now add the game data part uint8 active = 0, locked = 0; for( uint8 i=0; iget_ai_id()!=player_t::EMPTY ) { active ++; if( players[i]->is_locked() ) { locked ++; } } } buf.printf( "&time=%u,%u", (get_current_month() % 12) + 1, get_current_month() / 12 ); buf.printf( "&size=%u,%u", get_size().x, get_size().y ); buf.printf( "&active=%u", active ); buf.printf( "&locked=%u", locked ); buf.printf( "&clients=%u", socket_list_t::get_playing_clients() ); buf.printf( "&towns=%u", cities.get_count() ); buf.printf( "&citizens=%u", cities.get_sum_weight() ); buf.printf( "&factories=%u", fab_list.get_count() ); buf.printf( "&convoys=%u", convoys().get_count()); buf.printf( "&stops=%u", haltestelle_t::get_alle_haltestellen().get_count() ); if (network_http_post(ANNOUNCE_SERVER1, ANNOUNCE_URL, buf, NULL)) { #ifdef ANNOUNCE_SERVER2 if (network_http_post(ANNOUNCE_SERVER2, ANNOUNCE_URL, buf, NULL)) #ifdef ANNOUNCE_SERVER3 if (network_http_post(ANNOUNCE_SERVER3, ANNOUNCE_URL, buf, NULL)) #endif #endif dbg->warning("announce_server", "All announce servers down!"); } // Record time of this announce server_last_announce_time = dr_time(); } } void karte_t::network_disconnect() { // force disconnect dbg->warning("karte_t::network_disconnect()", "Lost synchronisation with server."); network_core_shutdown(); destroy_all_win(true); clear_random_mode( INTERACTIVE_RANDOM ); step_mode = NORMAL; reset_timer(); clear_command_queue(); create_win({ display_get_width()/2-128, 40 }, new news_img("Lost synchronisation\nwith server."), w_info, magic_none); ticker::add_msg( translator::translate("Lost synchronisation\nwith server."), koord3d::invalid, SYSCOL_TEXT ); last_active_player_nr = active_player_nr; finish_loop = true; // kick me out to main screen } static bool sort_ware_by_name(const goods_desc_t* a, const goods_desc_t* b) { int diff = strcmp(translator::translate(a->get_name()), translator::translate(b->get_name())); return diff < 0; } // Returns a list of goods produced by factories that exist in current game const vector_tpl &karte_t::get_goods_list() { if (goods_in_game.empty()) { // Goods list needs to be rebuilt // Reset last vehicle filter in all depots, in case goods list has changed for(depot_t* const d : depot_t::get_depot_list()) { d->selected_filter = VEHICLE_FILTER_RELEVANT; } for(fabrik_t* const factory : get_fab_list()) { slist_tpl* const produced_goods = factory->get_produced_goods(); for(goods_desc_t const* const good : *produced_goods) { goods_in_game.insert_unique_ordered(good, sort_ware_by_name); } delete produced_goods; } goods_in_game.insert_at(0, goods_manager_t::passengers); goods_in_game.insert_at(1, goods_manager_t::mail); } return goods_in_game; } player_t *karte_t::get_public_player() const { return get_player(PLAYER_PUBLIC_NR); } uint32 karte_t::get_gamestate_hash() { adler32_stream_t *stream = new adler32_stream_t; stream_loadsave_t ls(stream); rdwr_gamestate(&ls, NULL); return stream->get_hash(); } simutrans-124.3/src/simutrans/world/simworld.h000066400000000000000000000764741474050137200215510ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_SIMWORLD_H #define WORLD_SIMWORLD_H #include "../simconst.h" #include "../simtypes.h" #include "../simunits.h" #include "../convoihandle.h" #include "../halthandle.h" #include "../tpl/weighted_vector_tpl.h" #include "../tpl/array2d_tpl.h" #include "../tpl/vector_tpl.h" #include "../tpl/slist_tpl.h" #include "../dataobj/settings.h" #include "../dataobj/loadsave.h" #include "../dataobj/rect.h" #include "../utils/checklist.h" #include "../utils/sha1_hash.h" #include "simplan.h" #include "surface.h" #include "../simdebug.h" struct sound_info; class stadt_t; class fabrik_t; class gebaeude_t; class zeiger_t; class grund_t; class planquadrat_t; class main_view_t; class interaction_t; class tool_t; class scenario_t; class message_t; class chat_message_t; class way_desc_t; class network_world_command_t; class goods_desc_t; class memory_rw_t; class viewport_t; class records_t; class loadingscreen_t; class terraformer_t; class building_desc_t; /** * Threaded function caller. */ typedef void (karte_t::*xy_loop_func)(sint16, sint16, sint16, sint16); /** * The map is the central part of the simulation. It stores all data and objects. * @brief Stores all data and objects of the simulated world. */ class karte_t : public surface_t { friend karte_t* world(); // to access the single instance friend class karte_ptr_t; // to access the single instance static karte_t* world; ///< static single instance public: // kind of map enum { AUTO_GENERATED, SCENARIO_WORLD, NEW_WORLD, RESTORED_WORLD, CLIENT_WORLD, LOADED_WORLD } type_of_generation; /** * Height of a point of the map with "perlin noise". * Uses map roughness and mountain height from @p sets. */ static sint32 perlin_hoehe(settings_t const *sets, koord k, koord size); /** * Loops over tiles setting heights from perlin noise */ void perlin_hoehe_loop(sint16, sint16, sint16, sint16); enum player_cost { WORLD_CITIZENS = 0, ///< total people WORLD_GROWTH, ///< growth (just for convenience) WORLD_TOWNS, ///< number of all cities WORLD_FACTORIES, ///< number of all consuming only factories WORLD_CONVOIS, ///< total number of convois WORLD_CITYCARS, ///< number of citycars generated WORLD_PAS_RATIO, ///< percentage of passengers that started successful WORLD_PAS_GENERATED, ///< total number generated WORLD_MAIL_RATIO, ///< percentage of mail that started successful WORLD_MAIL_GENERATED, ///< all letters generated WORLD_GOODS_RATIO, ///< ratio of chain completeness WORLD_TRANSPORTED_GOODS, ///< all transported goods MAX_WORLD_COST }; #define MAX_WORLD_HISTORY_YEARS (12) // number of years to keep history #define MAX_WORLD_HISTORY_MONTHS (12) // number of months to keep history enum step_mode_t { NORMAL = 0, PAUSE_FLAG = 1 << 0, FAST_FORWARD = 1 << 1, FIX_RATIO = 1 << 2 }; private: /** * @name Map properties * Basic map properties are stored in this variables. * @{ */ /** * @brief Map settings are stored here. */ settings_t settings; /** @} */ /** * All cursor interaction goes via this function, it will call save_mouse_funk first with * init, then with the position and with exit, when another tool is selected without click * @see tool/simtool.cc for practical examples of such functions. */ tool_t *selected_tool[MAX_PLAYER_COUNT]; /** * Redraw whole map. */ bool dirty; /* * Redraw background. */ bool background_dirty; /** * True during destroying of the map. */ bool destroying; /** * The rotation of the map when first loaded. */ uint8 loaded_rotation; /** * The one and only camera looking at our world. */ viewport_t *viewport; /** * @name Mouse pointer and cursor management * @{ */ /** * @brief Map mouse cursor tool. */ zeiger_t *zeiger; /** @} */ /** * Time when last mouse moved to check for ambient sound events. */ uint32 mouse_rest_time; /** * Waiting time before next event. */ uint32 sound_wait_time; /** * Gets an ambient sound id appropriate for the given tile. * Returns NO_SOUND if no appropriate sound is found. */ sint16 get_sound_id(grund_t *gr); /** * If true, this map cannot be saved. */ bool nosave; bool nosave_warning; /** * Changes the season and/or snowline height */ void recalc_season_snowline(bool set_pending); /** * >0 means a season change is needed */ sint8 pending_season_change; sint8 pending_snowline_change; /** * Recalculates sleep time etc. */ void update_frame_sleep_time(); /** * Array containing the convois. */ vector_tpl convoi_array; /** * Array containing the factories. */ slist_tpl fab_list; /** * Stores a list of goods produced by factories currently in the game; */ vector_tpl goods_in_game; weighted_vector_tpl attractions; vector_tpl labels; /** * Stores the cities. */ weighted_vector_tpl cities; sint64 last_month_bev; /** * The recorded history so far. */ sint64 finance_history_year[MAX_WORLD_HISTORY_YEARS][MAX_WORLD_COST]; /** * The recorded history so far. */ sint64 finance_history_month[MAX_WORLD_HISTORY_MONTHS][MAX_WORLD_COST]; /** * World record speed manager. * Keeps track of the fastest vehicles in game. */ records_t *records; /** * Attached view to this world. */ main_view_t *view; /** * Event manager of this world. */ interaction_t *eventmanager; private: /** * The fractal generation of the map is not perfect. * cleanup_karte() eliminates errors. */ void cleanup_karte( int xoff, int yoff ); /** * @name Player management * Variables related to the player management in game. * @{ */ /** * The players of the game. * @note Standard human player has index 0, public player 1. */ player_t *players[MAX_PLAYER_COUNT]; /** * Active player. */ player_t *active_player; /** * Active player index. */ uint8 active_player_nr; /** * Locally stored password hashes, will be used after reconnect to a server. */ pwd_hash_t player_password_hash[MAX_PLAYER_COUNT]; /** @} */ /** * Counter for schedules. * If a new schedule is active, this counter will increment * stations check this counter and will reroute their goods if changed. */ uint8 schedule_counter; /** * @name Display timing and scheduling * These variables store system display timings in the past frames * and allow for adequate adjustments to adapt to the system performance * and available resources (also in network mode). * @{ */ /** * ms since creation. * @note The time is in ms (milliseconds) */ uint32 ticks; /** * Ticks counter at last steps. * @note The time is in ms (milliseconds) */ uint32 last_step_ticks; /** * From now on is next month. * @note The time is in ms (milliseconds) */ uint32 next_month_ticks; /// Default time stretching factor, 4 bits fractional part uint32 time_multiplier; /// @ref step_mode_t uint8 step_mode; /// @note variable used in interactive() uint32 sync_steps; // The maximum sync_steps that a client can safely advance to. uint32 sync_steps_barrier; #define LAST_CHECKLISTS_COUNT 64 /// @note variable used in interactive() checklist_t last_checklists[LAST_CHECKLISTS_COUNT]; #define LCHKLST(x) (last_checklists[(x) % LAST_CHECKLISTS_COUNT]) /// @note variable used in interactive() uint8 network_frame_count; /** * @note Variable used in interactive(). * @note Set in reset_timer(). */ sint32 fix_ratio_frame_time; /// Average number of calls to display() per second, 4 bits fractional part uint32 realFPS; /// Average number of calls to step() per second. /// Fractional factor of 10, so the real average number of steps is simloops/10 uint32 simloops; /// Index for last_frame_ms uint8 last_frame_idx; /// Real-world time when the last display() finished, indexed by @ref last_frame_idx uint32 last_frame_ms[32]; /// Time when the last step started, indexed by @ref steps counter (modulo array size) uint32 last_step_nr[32]; /** * ms, when the last time events were handled. * To calculate the fps and the simloops. */ uint32 last_interaction; /** * ms, when the next step is to be done. * To calculate the fps and the simloops. */ uint32 next_step_time; /** * ms, when the next check if we need to start next song */ uint32 next_midi_time; /** * Miscellaneus stuff that do not need to be updated frequently * Currently used for rich presence and achievements */ uint32 next_misc_time; /// To calculate the fps and the simloops. uint32 idle_time; /** @} */ /** * Current accumulated month number, counting January of year 0 as 0. * @note last_month + (last_year*12); */ sint32 current_month; /** * Last month 0..11 */ sint32 last_month; /** * Last year. */ sint32 last_year; /** * Number of steps since creation. */ sint32 steps; /** * Flag, that now no sound will play. */ bool is_sound; /** * Flag for ending simutrans (true -> end simutrans). */ bool finish_loop; /** * May change due to timeline. */ const way_desc_t *city_road; /** * What game objectives. */ scenario_t *scenario; /** * Holds all the text messages in the messagebox (chat, new vehicle etc). */ message_t *msg; chat_message_t* chat_msg; /** * Array indexed per way type. Used to determine the speedbonus. */ sint32 average_speed[8]; /** * Used to distribute the workload when changing seasons to several steps. */ uint32 tile_counter; /** * To identify different stages of the same game. */ uint32 map_counter; /** * Recalculated speed bonus for different vehicles. */ void recalc_average_speed(); /** * Monthly actions. */ void new_month(); /** * Yearly actions. */ void new_year(); /** * Internal saving method. */ void save(loadsave_t *file, bool silent); public: /** * Internal loading method. */ void load(loadsave_t *file); private: void rdwr_gamestate(loadsave_t *file, loadingscreen_t *ls); /** * Removes all objects, deletes all data structures and frees all accessible memory. */ void destroy(); /** * Restores history for older savegames. */ void restore_history(bool restore_transported_only); /** * Will create rivers. */ void create_rivers(sint16 number); /** * Will create lakes (multithreaded). */ void create_lakes_loop(sint16, sint16, sint16, sint16); /** * Will create lakes. */ void create_lakes( int xoff, int yoff, sint8 max_lake_height ); /** * Will create beaches. */ void create_beaches( int xoff, int yoff ); /** * Distribute groundobjs and cities on the map but not * in the rectangle from (0,0) till (old_x, old_y). * It's now an extra function so we don't need the code twice. */ void distribute_cities(int new_cities, sint32 new_mean_citizen_count, sint16 old_x, sint16 old_y ); void distribute_groundobjs(sint16 old_x, sint16 old_y); void distribute_movingobjs(sint16 old_x, sint16 old_y); /** * The last time when a server announce was performed (in ms). */ uint32 server_last_announce_time; enum { SYNCX_FLAG = 1 << 0, GRIDS_FLAG = 1 << 1 }; void world_xy_loop(xy_loop_func func, uint8 flags); static void *world_xy_loop_thread(void *); /** * Loops over plans after load. */ void plans_finish_rd(sint16, sint16, sint16, sint16); /** * Updates all images. */ void update_map_intern(sint16, sint16, sint16, sint16); bool can_flood_to_depth(koord k, sint8 new_water_height, sint8 *stage, sint8 *our_stage, sint16, sint16, sint16, sint16) const; void flood_to_depth(sint8 new_water_height, sint8 *stage); public: enum server_announce_type_t { SERVER_ANNOUNCE_HELLO = 0, ///< my server is now up SERVER_ANNOUNCE_HEARTBEAT = 1, ///< my server is still up SERVER_ANNOUNCE_GOODBYE = 2, ///< my server is now down }; /** * Announce server and current state to listserver. * @param status Specifies what information should be announced * or offline (the latter only in cases where it is shutting down) */ void announce_server(server_announce_type_t status); /** * Returns the messagebox message container. */ message_t *get_message() { return msg; } /** * Returns the messagebox message container. */ chat_message_t* get_chat_message() const { return chat_msg; } /** * Set to something useful, if there is a total distance != 0 to show in the bar below. */ koord3d show_distance; /** * Absolute month. */ inline uint32 get_last_month() const { return last_month; } /** * Returns last year. */ inline sint32 get_last_year() const { return last_year; } /** * dirty: redraw whole screen. */ void set_dirty() {dirty=true;} /** * dirty: redraw whole screen. */ void unset_dirty() {dirty=false;} /** * dirty: redraw whole screen. */ bool is_dirty() const {return dirty;} /** * background_dirty: redraw background. */ void set_background_dirty() { background_dirty = true; } /** * background_dirty: redraw whole screen. */ bool is_background_dirty() const { return background_dirty; } /** * background_dirty: redraw background. */ void unset_background_dirty() { background_dirty = false; } // do the internal accounting void buche(sint64 betrag, player_cost type); // calculates the various entries void update_history(); scenario_t *get_scenario() const { return scenario; } void set_scenario(scenario_t *s); /** * Returns the finance history for player. */ sint64 get_finance_history_year(int year, int type) const { return finance_history_year[year][type]; } /** * Returns the finance history for player. */ sint64 get_finance_history_month(int month, int type) const { return finance_history_month[month][type]; } /** * Returns pointer to finance history for player. */ const sint64* get_finance_history_year() const { return *finance_history_year; } /** * Returns pointer to finance history for player. */ const sint64* get_finance_history_month() const { return *finance_history_month; } /** * Recalcs all map images. */ void update_map(); /** * Recalcs images after change of underground mode. */ void update_underground(); /** * @brief Prepares an area of the map to be drawn. * * New area is the area that will be prepared. Old area is the area that was * already prepared. Only the difference between the two rects is prepared. */ void prepare_tiles(rect_t const& new_area, rect_t const& old_area); /** * @returns true if world gets destroyed */ bool is_destroying() const { return destroying; } /** * Gets the world view. */ main_view_t *get_view() const { return view; } /** * Gets the world viewport. */ viewport_t *get_viewport() const { return viewport; } /** * Sets the world view. */ void set_view(main_view_t *v) { view = v; } /** * Sets the world event manager. */ void set_eventmanager(interaction_t *em) { eventmanager = em; } settings_t const& get_settings() const { return settings; } settings_t& get_settings() { return settings; } /// returns current speed bonus sint32 get_average_speed(waytype_t typ) const { return average_speed[ (typ==16 ? 3 : (int)(typ-1)&7 ) ]; } /// speed record management sint32 get_record_speed( waytype_t w ) const; void notify_record( convoihandle_t cnv, sint32 max_speed, koord3d k ); /// time lapse mode ... bool is_paused() const { return step_mode&PAUSE_FLAG; } /// stops the game with interaction void set_pause( bool ); bool is_fast_forward() const { return step_mode == FAST_FORWARD; } void set_fast_forward(bool ff); bool is_step_mode_normal() const { return step_mode == NORMAL; } /** * (un)pause for network games. */ void network_game_set_pause(bool pause_, uint32 syncsteps_); /** * @return The active mouse cursor. */ zeiger_t * get_zeiger() const { return zeiger; } /** * Marks an area using the grund_t mark flag. */ void mark_area( const koord3d center, const koord radius, const bool mark ) const; /** * Player management here */ uint8 sp2num(player_t *player); player_t* get_player(uint8 n) const { return players[n&15]; } // return player or gives error and cerates player to recover broken savegames player_t* get_player_or_create(uint8 n); player_t* get_active_player() const { return active_player; } uint8 get_active_player_nr() const { return active_player_nr; } void switch_active_player(uint8 nr, bool silent); const char *init_new_player( uint8 nr, uint8 type ); void store_player_password_hash( uint8 player_nr, const pwd_hash_t& hash ); const pwd_hash_t& get_player_password_hash( uint8 player_nr ) const { return player_password_hash[player_nr]; } void clear_player_password_hashes(); void rdwr_player_password_hashes(loadsave_t *file); void remove_player(uint8 player_nr); /** * Get the default public service player. * @return the default public service player */ player_t *get_public_player() const; /** * Network safe initiation of new and deletion of players, change freeplay. * * @param cmd * @param player_nr * @param param Player type (human / C ai / script ai) of new players. * @param scripted_call */ void call_change_player_tool(uint8 cmd, uint8 player_nr, uint16 param, bool scripted_call=false); enum change_player_tool_cmds { new_player = 1, toggle_freeplay = 2, delete_player = 3, toggle_player_active = 4 }; /** * @param cmd * @param player_nr * @param param * @param public_player_unlocked * @param exec If false checks whether execution is allowed, if true executes tool. * @returns Whether execution is allowed. */ bool change_player_tool(uint8 cmd, uint8 player_nr, uint16 param, bool public_player_unlocked, bool exec); /** * If a schedule is changed, it will increment the schedule counter * every step the haltestelle will check and reroute the goods if needed. */ uint8 get_schedule_counter() const { return schedule_counter; } /** * If a schedule is changed, it will increment the schedule counter * every step the haltestelle will check and reroute the goods if needed. */ void set_schedule_counter(); /** * @note Often used, therefore found here. */ bool use_timeline() const { return settings.get_use_timeline(); } void reset_timer(); void reset_interaction(); void step_year(); /** * Jump one or more months ahead. * @note Updating history! */ void step_month( sint16 months=1 ); /** * @return Either 0 or the current year*12 + month */ uint16 get_timeline_year_month() const { return settings.get_use_timeline() ? current_month : 0; } /** * Number of ticks per day in bits. * @see ticks_per_world_month */ uint32 ticks_per_world_month_shift; /** * Number of ticks per MONTH! */ uint32 ticks_per_world_month; void set_ticks_per_world_month_shift(uint32 bits) {ticks_per_world_month_shift = bits; ticks_per_world_month = (1 << ticks_per_world_month_shift); } /** * Converts speed (yards per tick) into tiles per month * * A derived quantity: * speed * ticks_per_world_month / yards_per_tile * == speed << ticks_per_world_month_shift (pak-set dependent, 18 in old games) * >> yards_per_tile_shift (which is 12 + 8 = 20, see above) * This is hard to do with full generality, because shift operators * take positive numbers! */ uint32 speed_to_tiles_per_month(uint32 speed) const { const int left_shift = ticks_per_world_month_shift - YARDS_PER_TILE_SHIFT; if (left_shift >= 0) { return speed << left_shift; } else { const int right_shift = -left_shift; // round to nearest return (speed + (1<<(right_shift -1)) ) >> right_shift; } } /** * Scales value proportionally with month length. * Used to scale monthly maintenance costs and factory production. * @returns value << ( ticks_per_world_month_shift -18 ) */ sint64 scale_with_month_length(sint64 value) { const int left_shift = ticks_per_world_month_shift - 18; if(left_shift >= 0) { return value << left_shift; } else { return value >> (-left_shift); } } /** * Scales value inverse proportionally with month length. * Used to scale monthly maintenance costs, city growth, and factory production. * @returns value << ( 18 - ticks_per_world_month_shift ) */ sint64 inverse_scale_with_month_length(sint64 value) { const int left_shift = (int)ticks_per_world_month_shift-18; if( left_shift < 0 ) { return value << (-left_shift); } else { return value >> left_shift; } } sint32 get_time_multiplier() const; void change_time_multiplier( sint32 delta ); /** * @return 0=winter, 1=spring, 2=summer, 3=autumn * Here instead of in surface_t because this is required for the script API */ uint8 get_season() const { return season; } /** * Time since map creation or the last load in ms. */ uint32 get_ticks() const { return ticks; } uint32 get_next_month_ticks() const { return next_month_ticks; } /** * Absolute month (count start year zero). */ uint32 get_current_month() const { return current_month; } /** * current city road. * @note May change due to timeline. */ const way_desc_t* get_city_road() const { return city_road; } /** * Number of steps elapsed since the map was generated. */ sint32 get_steps() const { return steps; } /** * Idle time. Nur zur Anzeige verwenden! */ uint32 get_idle_time() const { return idle_time; } /** * Number of frames displayed in the last real time second. */ uint32 get_realFPS() const { return realFPS; } /** * Number of simulation loops in the last second. Can be very inaccurate! */ uint32 get_simloops() const { return simloops; } /** * Returns the current snowline height. */ sint8 get_snowline() const { return snowline; } void set_mouse_rest_time(uint32 new_val) { mouse_rest_time = new_val; } void set_sound_wait_time(uint32 new_val) { sound_wait_time = new_val; } public: /** * Set a new tool as current: calls local_set_tool or sends to server/queue (then suspend is true). */ void set_tool_api(tool_t* tool_in, player_t* player, bool& suspended); /** * Set a new tool as current without suspending parameter */ void set_tool(tool_t* tool_in, player_t* player) { bool b; set_tool_api(tool_in, player, b); } /** * Set a new tool on our client, calls init. */ void local_set_tool( tool_t *tool_in, player_t* player ); tool_t *get_tool(uint8 nr) const { return selected_tool[nr]; } /* since move can alter the map state * (e.g. route search for marking tiles) * we defer it to outside sync_step */ void set_deferred_move_to(koord3d pos, uint8 flags); /** * Calls the work method of the tool. * Takes network and scenarios into account. */ const char* call_work_api(tool_t *t, player_t *pl, koord3d pos, bool &suspended); /** * Initialize map. * * @param sets Game settings. * @param heights */ void init(settings_t *sets, sint8 const* heights); void init_tiles(); void enlarge_map(settings_t const*, sint8 const* h_field); karte_t(); ~karte_t(); /** * File version used when loading (or current if generated) * @note Useful for finish_rd */ uint32 load_version; public: // the convois are also handled each step => thus we keep track of them too void add_convoi(convoihandle_t); void rem_convoi(convoihandle_t); vector_tpl const& convoys() const { return convoi_array; } /** * To access the cities array. */ const weighted_vector_tpl& get_cities() const { return cities; } /// Try to add a new city at @p pos with @p citizens inhabitants. /// Returns NULL on failure. stadt_t *create_city(koord pos, sint32 citizens, const building_desc_t* th=NULL, sint16 rotation=-1); /// Removes town from map, houses will be left over. bool remove_city(stadt_t *s); /* tourist attraction list */ void add_attraction(gebaeude_t *gb); void remove_attraction(gebaeude_t *gb); const weighted_vector_tpl &get_attractions() const {return attractions; } void add_label(koord k); void remove_label(koord k); const vector_tpl& get_label_list() const { return labels; } bool add_fab(fabrik_t *fab); bool rem_fab(fabrik_t *fab); int get_fab_index(fabrik_t* fab) const { return fab_list.index_of(fab); } fabrik_t* get_fab(unsigned index) const { return index < fab_list.get_count() ? fab_list.at(index) : NULL; } const slist_tpl& get_fab_list() const { return fab_list; } /** * Returns a list of goods produced by factories that exist in current game. */ const vector_tpl &get_goods_list(); /** * Searches and returns the closest city * but prefers even farther cities if within their city limits */ stadt_t *find_nearest_city(koord k) const; bool cannot_save() const { return nosave; } void set_nosave() { nosave = true; nosave_warning = true; } void set_nosave_warning() { nosave_warning = true; } /// rotate plans by 90 degrees void rotate90_plans(sint16 x_min, sint16 x_max, sint16 y_min, sint16 y_max); /// rotate map view by 90 degrees void rotate90(); template class sync_list_t { friend class karte_t; vector_tpl list; ///< list of sync-steppable objects T *currently_deleting; ///< deleted durign sync_step, safeguard calls to remove bool sync_step_running; public: sync_list_t() : currently_deleting(NULL), sync_step_running(false) {} void add(T *obj) { assert(!sync_step_running); list.append(obj); } void remove(T *obj) { if(sync_step_running) { if (obj == currently_deleting) { return; } assert(false); } else { list.remove(obj); } } private: void sync_step(uint32 delta_t) { sync_step_running = true; currently_deleting = NULL; for(uint32 i=0; isync_step(delta_t)) { case SYNC_OK: break; case SYNC_DELETE: currently_deleting = ss; delete ss; currently_deleting = NULL; /* fall-through */ case SYNC_REMOVE: ss = list.pop_back(); if (i < list.get_count()) { list[i] = ss; } } } sync_step_running = false; } /// clears list, does not delete the objects void clear() { list.clear(); currently_deleting = NULL; sync_step_running = false; } }; sync_list_t sync; ///< vehicles sync_list_t sync_buildings; ///< animated buildings sync_list_t sync_roadsigns; ///< traffic lights /** * Synchronous stepping of objects like vehicles. */ void sync_step(uint32 delta_t); // advance also the timer void display(uint32 delta_t); /** * Tasks that are more time-consuming, like route search of vehicles and production of factories. */ void step(); public: /** * Calculates appropriate climate for a region using elliptic areas for each */ void calc_climate_map_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ); /** * Calculates appropriate climate for a region using elliptic areas for each */ void calc_humidity_map_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ); /** * assign climated from the climate map to a region */ void assign_climate_map_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ); /** * Since the trees follow humidity, we have to redistribute them only in the new region */ void distribute_trees_region( sint16 xtop, sint16 ytop, sint16 xbottom, sint16 ybottom ); /** * Loop recalculating transitions - suitable for multithreading */ void recalc_transitions_loop(sint16, sint16, sint16, sint16); /** * Loop cleans grounds so that they have correct boden and slope - suitable for multithreading */ void cleanup_grounds_loop(sint16, sint16, sint16, sint16); /** * @return A list of all buildable squares with size w, h. * @note Only used for town creation at the moment. */ slist_tpl * find_squares(sint16 w, sint16 h, climate_bits cl, sint16 old_x, sint16 old_y) const; /** * Plays the sound when the position is inside the visible region. * The sound plays lower when the position is outside the visible region. * @param k Position at which the event took place. * @param idx Index of the sound * @param t is the type of sound (for selective muting etc.) */ bool play_sound_area_clipped(koord k, uint16 idx, sound_type_t t) const; void mute_sound( bool state ) { is_sound = !state; } /* if start is true, the current map will be used as servergame * Does not announce a new map! */ void switch_server( bool start_server, bool port_forwarding ); /** * Saves the map to a file. * * @param filename name of the file to write. * @param autosave * @param version * @param silent */ void save(const char *filename, bool autosave, const char *version, bool silent); /** * Loads a map from a file. * @param filename name of the file to read. */ bool load(const char *filename); /** * Creates a map from a heightfield. * @param sets game settings. */ void load_heightfield(settings_t *sets); /** * Stops simulation and optionally closes the game. * @param exit_game If true, the game will also close. */ void stop(bool exit_game); /** * Main loop with event handling. * @return false to exit. */ bool interactive(uint32 quit_month); uint32 get_sync_steps() const { return sync_steps; } /** * Checks whether checklist is available, ie given sync_step is not too far into past. */ bool is_checklist_available(const uint32 sync_step) const { return sync_step + LAST_CHECKLISTS_COUNT > sync_steps; } const checklist_t& get_checklist_at(const uint32 sync_step) const { return LCHKLST(sync_step); } void set_checklist_at(const uint32 sync_step, const checklist_t &chklst) { LCHKLST(sync_step) = chklst; } const checklist_t& get_last_checklist() const { return LCHKLST(sync_steps); } uint32 get_last_checklist_sync_step() const { return sync_steps; } void command_queue_append(network_world_command_t*) const; void clear_command_queue() const; void network_disconnect(); /** * To identify the current map. */ uint32 get_map_counter() const { return map_counter; } void set_map_counter(uint32 new_map_counter); /** * Called by the server before sending the sync commands. */ uint32 generate_new_map_counter() const; /** * Generates hash of game state by streaming a save to a hash function */ uint32 get_gamestate_hash(); private: void process_network_commands(sint32* ms_difference); void do_network_world_command(network_world_command_t *nwc); uint32 get_next_command_step(); }; /** * Returns pointer to single instance of the world. */ inline karte_t *world() { return karte_t::world; } /** * Class to access the pointer to the world. * No need to initialize it. */ class karte_ptr_t { public: /// dereference operator: karte_ptr_t can be used as it would be karte_t* karte_t& operator*() { assert( karte_t::world ); return *karte_t::world; } const karte_t& operator*() const { assert( karte_t::world ); return *karte_t::world; } karte_ptr_t() {} /// dereference operator: karte_ptr_t can be used as it would be karte_t* karte_t* operator->() { assert( karte_t::world ); return karte_t::world; } const karte_t* operator->() const { assert( karte_t::world ); return karte_t::world; } /// cast to karte_t* operator karte_t* () const { return karte_t::world; } private: karte_ptr_t(const karte_ptr_t&); karte_ptr_t& operator=(const karte_ptr_t&); // no cast to bool please operator bool () const; }; #endif simutrans-124.3/src/simutrans/world/surface.cc000066400000000000000000000533611474050137200214650ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "surface.h" #include "simworld.h" #include "terraformer.h" #include "../descriptor/ground_desc.h" #include "../ground/grund.h" #include "../player/simplay.h" #define array_koord(px,py) (px + py * get_size().x) static sint8 median( sint8 a, sint8 b, sint8 c ) { #if 0 if( a==b || a==c ) { return a; } else if( b==c ) { return b; } else { // noting matches // return (3*128+1 + a+b+c)/3-128; return -128; } #elif 0 if( a<=b ) { return b<=c ? b : max(a,c); } else { return b>c ? b : min(a,c); } #else return (6*128+3 + a+a+b+b+c+c)/6-128; #endif } surface_t::surface_t() : climate_map(0, 0), humidity_map(0, 0) { } surface_t::~surface_t() { } koord surface_t::get_closest_coordinate(koord outside_pos) { outside_pos.clip_min(koord(0,0)); outside_pos.clip_max(koord(get_size().x-1,get_size().y-1)); return outside_pos; } bool surface_t::is_water(koord pos, koord dim) const { koord k; for( k.y = pos.y; k.y < pos.y + dim.y; k.y++ ) { for( k.x = pos.x; k.x < pos.x + dim.x; k.x++ ) { if( !is_within_grid_limits( k + koord(1, 1) ) || max_hgt(k) > get_water_hgt(k) ) { return false; } } } return true; } bool surface_t::square_is_free(koord pos, sint16 w, sint16 h, int *last_y, climate_bits cl) const { if(pos.x < 0 || pos.y < 0 || pos.x+w > get_size().x || pos.y+h > get_size().y) { return false; } grund_t *gr = lookup_kartenboden(pos); const sint16 platz_base_h = gr->get_hoehe(); // remember the base height of the first tile const sint16 platz_max_h = gr->get_hoehe() + slope_t::max_diff( gr->get_grund_hang() ); // remember the max height of the first tile koord k_check; for(k_check.x=pos.x; k_check.x=pos.y; k_check.y--) { const grund_t *gr = lookup_kartenboden(k_check); // we can built, if: max height all the same, everything removable and no buildings there slope_t::type slope = gr->get_grund_hang(); sint8 max_height = gr->get_hoehe() + slope_t::max_diff(slope); climate test_climate = get_climate(k_check); if( cl & (1 << water_climate) && test_climate != water_climate ) { bool neighbour_water = false; for(int i=0; i<8 && !neighbour_water; i++) { if( is_within_limits(k_check + koord::neighbours[i]) && get_climate( k_check + koord::neighbours[i] ) == water_climate ) { neighbour_water = true; } } if( neighbour_water ) { test_climate = water_climate; } } if( (platz_max_h != max_height && platz_base_h != gr->get_hoehe()) || !gr->ist_natur() || gr->kann_alle_obj_entfernen(NULL) != NULL || (cl & (1 << test_climate)) == 0 || ( slope && (lookup( gr->get_pos()+koord3d(0,0,1) ) || (slope_t::max_diff(slope)==2 && lookup( gr->get_pos()+koord3d(0,0,2) )) )) ) { if( last_y ) { *last_y = k_check.y; } return false; } } } return true; } sint8 surface_t::min_hgt_nocheck(const koord k) const { // more optimised version of min_hgt code const sint8 * p = &grid_hgts[k.x + k.y*(sint32)(cached_grid_size.x+1)]; const int h1 = *p; const int h2 = *(p+1); const int h3 = *(p+get_size().x+2); const int h4 = *(p+get_size().x+1); return min(min(h1,h2), min(h3,h4)); } sint8 surface_t::max_hgt_nocheck(const koord k) const { // more optimised version of max_hgt code const sint8 * p = &grid_hgts[k.x + k.y*(sint32)(cached_grid_size.x+1)]; const int h1 = *p; const int h2 = *(p+1); const int h3 = *(p+get_size().x+2); const int h4 = *(p+get_size().x+1); return max(max(h1,h2), max(h3,h4)); } sint8 surface_t::min_hgt(const koord k) const { const sint8 h1 = lookup_hgt(k); const sint8 h2 = lookup_hgt(k+koord(1, 0)); const sint8 h3 = lookup_hgt(k+koord(1, 1)); const sint8 h4 = lookup_hgt(k+koord(0, 1)); return min(min(h1,h2), min(h3,h4)); } sint8 surface_t::max_hgt(const koord k) const { const sint8 h1 = lookup_hgt(k); const sint8 h2 = lookup_hgt(k+koord(1, 0)); const sint8 h3 = lookup_hgt(k+koord(1, 1)); const sint8 h4 = lookup_hgt(k+koord(0, 1)); return max(max(h1,h2), max(h3,h4)); } void surface_t::get_height_slope_from_grid(koord k, sint8 &hgt, slope_t::type &slope) { if( (k.x | k.y | (cached_grid_size.x - k.x-1) | (cached_grid_size.y - k.y-1)) >= 0 ) { // inside map, so without further checks const sint8 h_n = lookup_hgt_nocheck(k.x, k.y); const sint8 h_w = lookup_hgt_nocheck(k.x, k.y+1); const sint8 h_s = lookup_hgt_nocheck(k.x+1, k.y+1); const sint8 h_e = lookup_hgt_nocheck(k.x+1, k.y); hgt = min(min(h_n, h_e), min(h_s, h_w)); slope = slope_t::northwest * min(h_n - hgt, 2); slope |= slope_t::northeast * min(h_e - hgt, 2); slope |= slope_t::southeast * min(h_s - hgt, 2); slope |= slope_t::southwest * min(h_w - hgt, 2); } } // fills array with neighbour heights void surface_t::get_neighbour_heights(const koord k, sint8 neighbour_height[8][4]) const { for( int i = 0; i < 8; i++ ) { // 0 = nw, 1 = w etc. planquadrat_t *pl2 = access( k + koord::neighbours[i] ); if( pl2 ) { grund_t *gr2 = pl2->get_kartenboden(); slope_t::type slope_corner = gr2->get_grund_hang(); for( int j = 0; j < 4; j++ ) { neighbour_height[i][j] = gr2->get_hoehe() + corner_sw(slope_corner); slope_corner /= slope_t::southeast; } } else { switch(i) { case 0: // nw neighbour_height[i][0] = groundwater; neighbour_height[i][1] = max( lookup_hgt( k+koord(0,0) ), get_water_hgt( k ) ); neighbour_height[i][2] = groundwater; neighbour_height[i][3] = groundwater; break; case 1: // w neighbour_height[i][0] = groundwater; neighbour_height[i][1] = max( lookup_hgt( k+koord(0,1) ), get_water_hgt( k ) ); neighbour_height[i][2] = max( lookup_hgt( k+koord(0,0) ), get_water_hgt( k ) ); neighbour_height[i][3] = groundwater; break; case 2: // sw neighbour_height[i][0] = groundwater; neighbour_height[i][1] = groundwater; neighbour_height[i][2] = max( lookup_hgt( k+koord(0,1) ), get_water_hgt( k ) ); neighbour_height[i][3] = groundwater; break; case 3: // s neighbour_height[i][0] = groundwater; neighbour_height[i][1] = groundwater; neighbour_height[i][2] = max( lookup_hgt( k+koord(1,1) ), get_water_hgt( k ) ); neighbour_height[i][3] = max( lookup_hgt( k+koord(0,1) ), get_water_hgt( k ) ); break; case 4: // se neighbour_height[i][0] = groundwater; neighbour_height[i][1] = groundwater; neighbour_height[i][2] = groundwater; neighbour_height[i][3] = max( lookup_hgt( k+koord(1,1) ), get_water_hgt( k ) ); break; case 5: // e neighbour_height[i][0] = max( lookup_hgt( k+koord(1,1) ), get_water_hgt( k ) ); neighbour_height[i][1] = groundwater; neighbour_height[i][2] = groundwater; neighbour_height[i][3] = max( lookup_hgt( k+koord(1,0) ), get_water_hgt( k ) ); break; case 6: // ne neighbour_height[i][0] = max( lookup_hgt( k+koord(1,0) ), get_water_hgt( k ) ); neighbour_height[i][1] = groundwater; neighbour_height[i][2] = groundwater; neighbour_height[i][3] = groundwater; break; case 7: // n neighbour_height[i][0] = max( lookup_hgt( k+koord(0,0) ), get_water_hgt( k ) ); neighbour_height[i][1] = max( lookup_hgt( k+koord(1,0) ), get_water_hgt( k ) ); neighbour_height[i][2] = groundwater; neighbour_height[i][3] = groundwater; break; } /*neighbour_height[i][0] = groundwater; neighbour_height[i][1] = groundwater; neighbour_height[i][2] = groundwater; neighbour_height[i][3] = groundwater;*/ } } } bool surface_t::is_plan_height_changeable(sint16 x, sint16 y) const { const planquadrat_t *plan = access(x,y); bool ok = true; if(plan != NULL) { grund_t *gr = plan->get_kartenboden(); ok = (gr->ist_natur() || gr->is_water()) && !gr->hat_wege() && !gr->is_halt(); for( int i=0; ok && iobj_count(); i++ ) { const obj_t *obj = gr->obj_bei(i); assert(obj != NULL); ok = obj->get_typ() == obj_t::baum || obj->get_typ() == obj_t::zeiger || obj->get_typ() == obj_t::cloud || obj->get_typ() == obj_t::groundobj; } } return ok; } int surface_t::grid_raise(const player_t *player, koord k, const char*&err) { int n = 0; if(is_within_grid_limits(k)) { const grund_t *gr = lookup_kartenboden_gridcoords(k); const slope4_t corner_to_raise = get_corner_to_operate(k); const sint16 x = gr->get_pos().x; const sint16 y = gr->get_pos().y; const sint8 hgt = gr->get_hoehe(corner_to_raise); sint8 hsw, hse, hne, hnw; if( !gr->is_water() ) { const sint8 f = ground_desc_t::double_grounds ? 2 : 1; const sint8 o = ground_desc_t::double_grounds ? 1 : 0; hsw = hgt - o + scorner_sw( corner_to_raise ) * f; hse = hgt - o + scorner_se( corner_to_raise ) * f; hne = hgt - o + scorner_ne( corner_to_raise ) * f; hnw = hgt - o + scorner_nw( corner_to_raise ) * f; } else { hsw = hse = hne = hnw = hgt; } terraformer_t digger(terraformer_t::raise, world()); digger.add_node(x, y, hsw, hse, hne, hnw); digger.generate_affected_tile_list(); err = digger.can_raise_all(player); if (err) { return 0; } n = digger.apply(); // force world full redraw, or background could be dirty. world()->set_dirty(); if( max_height < lookup_kartenboden_gridcoords(k)->get_hoehe() ) { max_height = lookup_kartenboden_gridcoords(k)->get_hoehe(); } } return (n+3)>>2; } int surface_t::grid_lower(const player_t *player, koord k, const char*&err) { int n = 0; if(is_within_grid_limits(k)) { const grund_t *gr = lookup_kartenboden_gridcoords(k); const slope4_t corner_to_lower = get_corner_to_operate(k); const sint16 x = gr->get_pos().x; const sint16 y = gr->get_pos().y; const sint8 hgt = gr->get_hoehe(corner_to_lower); const sint8 f = ground_desc_t::double_grounds ? 2 : 1; const sint8 o = ground_desc_t::double_grounds ? 1 : 0; const sint8 hsw = hgt + o - scorner_sw( corner_to_lower ) * f; const sint8 hse = hgt + o - scorner_se( corner_to_lower ) * f; const sint8 hne = hgt + o - scorner_ne( corner_to_lower ) * f; const sint8 hnw = hgt + o - scorner_nw( corner_to_lower ) * f; terraformer_t digger(terraformer_t::lower, world()); digger.add_node(x, y, hsw, hse, hne, hnw); digger.generate_affected_tile_list(); err = digger.can_lower_all(player); if (err) { return 0; } n = digger.apply(); err = NULL; // force world full redraw, or background could be dirty. world()->set_dirty(); if( min_height > min_hgt_nocheck( koord(x,y) ) ) { min_height = min_hgt_nocheck( koord(x,y) ); } } return (n+3)>>2; } // raise height in the hgt-array void surface_t::raise_grid_to(sint16 x, sint16 y, sint8 h) { if(is_within_grid_limits(x,y)) { const sint32 offset = x + y*(cached_grid_size.x+1); if( grid_hgts[offset] < h ) { grid_hgts[offset] = h; const sint8 hh = h - (ground_desc_t::double_grounds ? 2 : 1); // set new height of neighbor grid points raise_grid_to(x-1, y-1, hh); raise_grid_to(x , y-1, hh); raise_grid_to(x+1, y-1, hh); raise_grid_to(x-1, y , hh); raise_grid_to(x+1, y , hh); raise_grid_to(x-1, y+1, hh); raise_grid_to(x , y+1, hh); raise_grid_to(x+1, y+1, hh); } } } void surface_t::lower_grid_to(sint16 x, sint16 y, sint8 h) { if(is_within_grid_limits(x,y)) { const sint32 offset = x + y*(cached_grid_size.x+1); if( grid_hgts[offset] > h ) { grid_hgts[offset] = h; sint8 hh = h + 2; // set new height of neighbor grid points lower_grid_to(x-1, y-1, hh); lower_grid_to(x , y-1, hh); lower_grid_to(x+1, y-1, hh); lower_grid_to(x-1, y , hh); lower_grid_to(x+1, y , hh); lower_grid_to(x-1, y+1, hh); lower_grid_to(x , y+1, hh); lower_grid_to(x+1, y+1, hh); } } } bool surface_t::can_flatten_tile(player_t *player, koord k, sint8 hgt, bool keep_water, bool make_underwater_hill) { return flatten_tile(player, k, hgt, keep_water, make_underwater_hill, true /* just check */); } // make a flat level at this position (only used for AI at the moment) bool surface_t::flatten_tile(player_t *player, koord k, sint8 hgt, bool keep_water, bool make_underwater_hill, bool justcheck) { int n = 0; bool ok = true; const grund_t *gr = lookup_kartenboden(k); const slope_t::type slope = gr->get_grund_hang(); const sint8 old_hgt = make_underwater_hill && gr->is_water() ? min_hgt(k) : gr->get_hoehe(); const sint8 max_hgt = old_hgt + slope_t::max_diff(slope); if( max_hgt > hgt ) { terraformer_t digger(terraformer_t::lower, world()); digger.add_node(k.x, k.y, hgt, hgt, hgt, hgt); digger.generate_affected_tile_list(); ok = digger.can_lower_all(player) == NULL; if (ok && !justcheck) { n += digger.apply(); } } if( ok && old_hgt < hgt ) { terraformer_t digger(terraformer_t::raise, world()); digger.add_node(k.x, k.y, hgt, hgt, hgt, hgt); digger.generate_affected_tile_list(); ok = digger.can_raise_all(player, keep_water) == NULL; if (ok && !justcheck) { n += digger.apply(); } } // was changed => pay for it if(n>0) { n = (n+3) / 4; player_t::book_construction_costs(player, n * world()->get_settings().cst_alter_land, k, ignore_wt); } return ok; } slope_t::type surface_t::calc_natural_slope( const koord k ) const { if(!is_within_grid_limits(k.x, k.y)) { return slope_t::flat; } const sint8 *p = &grid_hgts[k.x + k.y*(sint32)(get_size().x+1)]; const int h1 = *p; const int h2 = *(p+1); const int h3 = *(p+get_size().x+2); const int h4 = *(p+get_size().x+1); const int mini = min(min(h1,h2), min(h3,h4)); const int d1=h1-mini; const int d2=h2-mini; const int d3=h3-mini; const int d4=h4-mini; return encode_corners(d4, d3, d2, d1); } slope_t::type surface_t::recalc_natural_slope( const koord k, sint8 &new_height ) const { grund_t *gr = lookup_kartenboden(k); if(!gr) { return slope_t::flat; } else { const sint8 max_hdiff = ground_desc_t::double_grounds ? 2 : 1; sint8 corner_height[4]; // get neighbour corner heights sint8 neighbour_height[8][4]; get_neighbour_heights( k, neighbour_height ); //check whether neighbours are foundations bool neighbour_fundament[8]; for( int i = 0; i < 8; i++ ) { grund_t *gr2 = lookup_kartenboden( k + koord::neighbours[i] ); neighbour_fundament[i] = (gr2 && gr2->get_typ() == grund_t::fundament); } for( uint8 i = 0; i < 4; i++ ) { // 0 = sw, 1 = se etc. // corner_sw (i=0): tests vs neighbour 1:w (corner 2 j=1),2:sw (corner 3) and 3:s (corner 4) // corner_se (i=1): tests vs neighbour 3:s (corner 3 j=2),4:se (corner 4) and 5:e (corner 1) // corner_ne (i=2): tests vs neighbour 5:e (corner 4 j=3),6:ne (corner 1) and 7:n (corner 2) // corner_nw (i=3): tests vs neighbour 7:n (corner 1 j=0),0:nw (corner 2) and 1:w (corner 3) sint16 median_height = 0; uint8 natural_corners = 0; for( int j = 1; j < 4; j++ ) { if( !neighbour_fundament[(i * 2 + j) & 7] ) { natural_corners++; median_height += neighbour_height[(i * 2 + j) & 7][(i + j) & 3]; } } switch( natural_corners ) { case 1: { corner_height[i] = (sint8)median_height; break; } case 2: { corner_height[i] = median_height >> 1; break; } default: { // take the average of all 3 corners (if no natural corners just use the artificial ones anyway) corner_height[i] = median( neighbour_height[(i * 2 + 1) & 7][(i + 1) & 3], neighbour_height[(i * 2 + 2) & 7][(i + 2) & 3], neighbour_height[(i * 2 + 3) & 7][(i + 3) & 3] ); break; } } } // new height of that tile ... sint8 min_height = min( min( corner_height[0], corner_height[1] ), min( corner_height[2], corner_height[3] ) ); sint8 max_height = max( max( corner_height[0], corner_height[1] ), max( corner_height[2], corner_height[3] ) ); /* check for an artificial slope on a steep sidewall */ bool not_ok = abs( max_height - min_height ) > max_hdiff || min_height == -128; sint8 old_height = gr->get_hoehe(); new_height = min_height; // now we must make clear, that there is no ground above/below the slope if( old_height!=new_height ) { not_ok |= lookup(koord3d(k,new_height))!=NULL; if( old_height > new_height ) { not_ok |= lookup(koord3d(k,old_height-1))!=NULL; } if( old_height < new_height ) { not_ok |= lookup(koord3d(k,old_height+1))!=NULL; } } if( not_ok ) { /* difference too high or ground above/below * we just keep it as it was ... */ new_height = old_height; return gr->get_grund_hang(); } const sint16 d1 = min( corner_height[0] - new_height, max_hdiff ); const sint16 d2 = min( corner_height[1] - new_height, max_hdiff ); const sint16 d3 = min( corner_height[2] - new_height, max_hdiff ); const sint16 d4 = min( corner_height[3] - new_height, max_hdiff ); return encode_corners(d1, d2, d3, d4); } } void surface_t::init_height_to_climate() { // mark unused as arctic memset( num_climates_at_height, 0, lengthof(num_climates_at_height) ); const settings_t &settings = world()->get_settings(); // now just add them, the later climates will win (we will do a fineer assessment later for( int cl=0; cl settings.get_climate_borders( arctic_climate, 1 ) ) { height_to_climate[ h ] = arctic_climate; } else { height_to_climate[ h ] = temperate_climate; } num_climates_at_height[ h ] = 1; } DBG_DEBUG( "init_height_to_climate()", "Height %i, climate %i, num_climates %i", h - groundwater, height_to_climate[ h ], num_climates_at_height[ h ] ); } } void surface_t::rotate_transitions(koord k) { planquadrat_t *pl = access(k); if( !pl ) { return; } uint8 climate_corners = pl->get_climate_corners(); if( climate_corners != 0 ) { climate_corners = (climate_corners >> 1) | ((climate_corners & 1) << 3); pl->set_climate_corners( climate_corners ); } } void surface_t::recalc_transitions(koord k) { planquadrat_t *pl = access(k); if( !pl ) { return; } grund_t *gr = pl->get_kartenboden(); if( !gr->is_water() ) { // get neighbour corner heights sint8 neighbour_height[8][4]; get_neighbour_heights( k, neighbour_height ); // look up neighbouring climates climate neighbour_climate[8]; for( int i = 0; i < 8; i++ ) { // 0 = nw, 1 = w etc. koord k_neighbour = k + koord::neighbours[i]; if( !is_within_limits(k_neighbour) ) { k_neighbour = get_closest_coordinate(k_neighbour); } neighbour_climate[i] = get_climate( k_neighbour ); } uint8 climate_corners = 0; climate climate0 = get_climate(k); slope_t::type slope_corner = gr->get_grund_hang(); for( uint8 i = 0; i < 4; i++ ) { // 0 = sw, 1 = se etc. // corner_sw (i=0): tests vs neighbour 1:w (corner 2 j=1),2:sw (corner 3) and 3:s (corner 4) // corner_se (i=1): tests vs neighbour 3:s (corner 3 j=2),4:se (corner 4) and 5:e (corner 1) // corner_ne (i=2): tests vs neighbour 5:e (corner 4 j=3),6:ne (corner 1) and 7:n (corner 2) // corner_nw (i=3): tests vs neighbour 7:n (corner 1 j=0),0:nw (corner 2) and 1:w (corner 3) sint8 corner_height = gr->get_hoehe() + corner_sw(slope_corner); climate transition_climate = water_climate; climate min_climate = arctic_climate; for( int j = 1; j < 4; j++ ) { if( corner_height == neighbour_height[(i * 2 + j) & 7][(i + j) & 3]) { climate climatej = neighbour_climate[(i * 2 + j) & 7]; climatej > transition_climate ? transition_climate = climatej : 0; climatej < min_climate ? min_climate = climatej : 0; } } if( min_climate == water_climate || transition_climate > climate0 ) { climate_corners |= 1 << i; } slope_corner /= slope_t::southeast; } pl->set_climate_transition_flag( climate_corners != 0 ); pl->set_climate_corners( climate_corners ); } gr->calc_image(); } void surface_t::calc_climate(koord k, bool recalc) { planquadrat_t *pl = access(k); if( !pl ) { return; } if( (unsigned)k.x >= climate_map.get_width() || (unsigned)k.y >= climate_map.get_height() ) { // not initialised yet (may happend during river creation) return; } grund_t *gr = pl->get_kartenboden(); if( gr ) { if( !gr->is_water() ) { bool beach = false; climate default_cl = (climate)climate_map.at( k.x, k.y ); if( gr->get_pos().z == groundwater ) { for( int i = 0; i < 8 && !beach; i++ ) { grund_t *gr2 = lookup_kartenboden( k + koord::neighbours[i] ); if( gr2 && gr2->is_water() ) { beach = true; } } } if( beach ) { pl->set_climate( desert_climate ); } else if( default_cl>water_climate && default_cl<=arctic_climate && world()->get_settings().get_climate_borders(default_cl,false)<=gr->get_pos().z && world()->get_settings().get_climate_borders(default_cl,true)>gr->get_pos().z ) { // if possible keep (or revert) to original climate pl->set_climate( default_cl ); } else { pl->set_climate( get_climate_at_height( max( gr->get_pos().z, groundwater + 1 ) ) ); } } else { pl->set_climate( water_climate ); } pl->set_climate_transition_flag(false); pl->set_climate_corners(0); } if( recalc ) { recalc_transitions(k); for( int i = 0; i < 8; i++ ) { recalc_transitions( k + koord::neighbours[i] ); } } } simutrans-124.3/src/simutrans/world/surface.h000066400000000000000000000402041474050137200213170ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_SURFACE_H #define WORLD_SURFACE_H #include "simplan.h" #include "../dataobj/koord.h" #include "../dataobj/koord3d.h" #include "../tpl/array2d_tpl.h" class grund_t; class player_t; /// Contains all in-game objects like terrain, buildings and vehicles. /// Provides low-level access to the in-game world (e.g. for terraforming or map height lookup) /// Most functions come in two variants: a normal one and a *_nocheck one. /// The *_nocheck variant should be used if the 2d coordinate is already known to be valid. class surface_t { protected: /** * For performance reasons we have the map grid size cached locally, comes from the environment (Einstellungen) * @brief Cached map grid size. * @note Valid grid coords are within (0..x,0..y) */ koord cached_grid_size; /** * For performance reasons we have the map size cached locally, comes from the environment (Einstellungen). * @brief Cached map tile size. * @note Valid tile coords are (0..x,0..y) * @note These values are one less than the size values of the grid. */ koord cached_size; /// @brief The maximum of cached_size.x and cached_size.y. /// Maximum size for waiting bars etc. sint16 cached_size_max; /// the maximum allowed world height. No tile/grid point can be higher than this limit. sint8 max_allowed_height; /// the minimum allowed world height. No tile/grid point can be lower than this limit. sint8 min_allowed_height; // @note min_allowed_height <= min_height <= groundwater < max_height <= max_allowed_height public: /// cache the current maximum and minimum height on the map sint8 max_height, min_height; protected: /// Water level height. sint8 groundwater; /// Current snow line height, changes between winter and summer snow line height. sint8 snowline; /// Current season. /// @note 0=winter, 1=spring, 2=summer, 3=autumn uint8 season; /** * @name Map data structures * These variables represent the simulated map. * @{ */ /** * Array containing all the map tiles. * @see cached_size */ planquadrat_t *plan = NULL; /** * Array representing the height of each point of the grid. * @see cached_grid_size */ sint8 *grid_hgts = NULL; /** * Array representing the height of water on each point of the grid. * @see cached_grid_size */ sint8 *water_hgts = NULL; /** @} */ /// Table for fast conversion from height to climate. uint8 height_to_climate[256] = {}; uint8 num_climates_at_height[256] = {}; /// Contains the intended climate for a tile /// (needed to restore tiles after height changes) array2d_tpl climate_map; /// Contains the intended climate for a tile /// (needed to restore tiles after height changes) array2d_tpl humidity_map; public: surface_t(); ~surface_t(); public: /// Returns the number of tiles of the map in x and y direction. /// @note Valid tile coords are within (0..x-1, 0..y-1) inline koord get_size() const { return cached_grid_size; } /// Maximum size for waiting bars etc. inline sint16 get_size_max() const { return cached_size_max; } /** * @return True if the specified coordinate is inside the world tiles(planquadrat_t) limits, false otherwise. * @param x,y Position * @note Inline because called very frequently! */ inline bool is_within_limits(sint16 x, sint16 y) const { // since negative values will make the whole result negative, we can use bitwise or // This is faster, since pentiums and other long pipeline processors do not like jumps // return x>=0 && y>=0 && cached_size.x>=x && cached_size.y>=y; return (x|y|(cached_size.x-x)|(cached_size.y-y))>=0; } /** * @return True if the specified coordinate is inside the world tiles(planquadrat_t) limits, false otherwise. * @param k Position * @note Inline because called very frequently! */ inline bool is_within_limits(koord k) const { return is_within_limits(k.x, k.y); } /** * @return True if the specified coordinate is inside the world height grid limits, false otherwise. * @param x,y Position * @note Inline because called very frequently! */ inline bool is_within_grid_limits(sint16 x, sint16 y) const { // Since negative values will make the whole result negative, we can use bitwise or // This is faster, since pentiums and other long pipeline processors do not like jumps // return x>=0 && y>=0 && cached_grid_size.x>=x && cached_grid_size.y>=y; return (x|y|(cached_grid_size.x-x)|(cached_grid_size.y-y))>=0; } /** * @return True if the specified coordinate is inside the world height grid limits, false otherwise. * @param k (x,y) coordinate. * @note Inline because called very frequently! */ inline bool is_within_grid_limits(const koord &k) const { return is_within_grid_limits(k.x, k.y); } /** * @return True if the specified coordinate is inside the world height grid limits, false otherwise. * @param x X coordinate. * @param y Y coordinate. * @note Inline because called very frequently! */ inline bool is_within_grid_limits(uint16 x, uint16 y) const { return (x<=(unsigned)cached_grid_size.x && y<=(unsigned)cached_grid_size.y); } /// @returns the closest coordinate to @p outside_pos that is within the world koord get_closest_coordinate(koord outside_pos); public: /** * @return grund an pos/hoehe * @note Inline because called very frequently! */ inline grund_t *lookup(const koord3d &pos) const { const planquadrat_t *plan = access(pos.x, pos.y); return plan ? plan->get_boden_in_hoehe(pos.z) : NULL; } /** * @return grund an pos/hoehe * @note Inline because called very frequently! * For speed no checks are performed that 2d coordinates are valid * (This function may still return NULL if there is no ground at pos.z) */ inline grund_t *lookup_nocheck(const koord3d &pos) const { return access_nocheck(pos.x, pos.y)->get_boden_in_hoehe(pos.z); } /** * This function takes grid coordinates as a parameter and a desired height (koord3d). * Will return the ground_t object that intersects with it in its northern corner if possible. * If that tile doesn't exist, returns the one that intersects with it in another corner. * * @param pos Grid coordinates to check for, the z points to the desired height. * @see lookup_kartenboden_gridcoords * @see corner_to_operate * @note Inline because called very frequently! */ inline grund_t *lookup_gridcoords(const koord3d &pos) const { if ( ( pos.x != cached_grid_size.x ) && ( pos.y != cached_grid_size.y ) ){ return lookup(koord3d(pos.x, pos.y, pos.z)); } if ( ( pos.x == cached_grid_size.x ) && ( pos.y == cached_grid_size.y ) ) { return lookup(koord3d(pos.x-1, pos.y-1, pos.z)); } else if ( pos.x == cached_grid_size.x ) { return lookup(koord3d(pos.x-1, pos.y, pos.z)); } return lookup(koord3d(pos.x, pos.y-1, pos.z)); } /** * This function takes 2D grid coordinates as a parameter, will return the ground_t object that * intersects with it in it's north corner if possible. If that tile doesn't exist, returns * the one that intersects with it in other corner. * @param pos Grid coordinates to check for. * @see corner_to_operate * @see lookup_gridcoords * @return The requested tile, or the immediately adjacent in case of lower border. * @note Inline because called very frequently! */ inline grund_t *lookup_kartenboden_gridcoords(const koord &pos) const { if ( ( pos.x != cached_grid_size.x ) && ( pos.y != cached_grid_size.y ) ){ return lookup_kartenboden(pos); } if ( ( pos.x == cached_grid_size.x ) && ( pos.y == cached_grid_size.y ) ) { return access(koord(pos.x-1, pos.y-1))->get_kartenboden(); } else if ( pos.x == cached_grid_size.x ) { return access(koord(pos.x-1, pos.y))->get_kartenboden(); } return access(koord(pos.x, pos.y-1))->get_kartenboden(); } public: /** * @return grund at the bottom (where house will be build) * @note Inline because called very frequently! - nocheck for more speed */ inline grund_t *lookup_kartenboden_nocheck(const sint16 x, const sint16 y) const { return plan[x+y*cached_grid_size.x].get_kartenboden(); } inline grund_t *lookup_kartenboden_nocheck(const koord &pos) const { return lookup_kartenboden_nocheck(pos.x, pos.y); } /** * @return grund at the bottom (where house will be build) * @note Inline because called very frequently! */ inline grund_t *lookup_kartenboden(const sint16 x, const sint16 y) const { return is_within_limits(x, y) ? plan[x+y*cached_grid_size.x].get_kartenboden() : NULL; } inline grund_t *lookup_kartenboden(const koord &pos) const { return lookup_kartenboden(pos.x, pos.y); } public: inline planquadrat_t *access_nocheck(sint16 x, sint16 y) const { return &plan[x + y*cached_grid_size.x]; } inline planquadrat_t *access_nocheck(koord k) const { return access_nocheck(k.x, k.y); } inline planquadrat_t *access(sint16 x, sint16 y) const { return is_within_limits(x, y) ? &plan[x + y*cached_grid_size.x] : NULL; } inline planquadrat_t *access(koord k) const { return access(k.x, k.y); } public: /** * @return Height at the grid point x,y - versions without checks for speed */ inline sint8 lookup_hgt_nocheck(sint16 x, sint16 y) const { return grid_hgts[x + y*(cached_grid_size.x+1)]; } inline sint8 lookup_hgt_nocheck(koord k) const { return lookup_hgt_nocheck(k.x, k.y); } /** * @return Height at the grid point x,y */ inline sint8 lookup_hgt(sint16 x, sint16 y) const { return is_within_grid_limits(x, y) ? grid_hgts[x + y*(cached_grid_size.x+1)] : groundwater; } inline sint8 lookup_hgt(koord k) const { return lookup_hgt(k.x, k.y); } /** * Sets grid height. * Never set grid_hgts manually, always use this method! */ void set_grid_hgt_nocheck(sint16 x, sint16 y, sint8 hgt) { grid_hgts[x + y*(uint32)(cached_grid_size.x+1)] = hgt; } inline void set_grid_hgt_nocheck(koord k, sint8 hgt) { set_grid_hgt_nocheck(k.x, k.y, hgt); } public: /// @return water height - versions without checks for speed inline sint8 get_water_hgt_nocheck(sint16 x, sint16 y) const { return water_hgts[x + y * (cached_grid_size.x)]; } inline sint8 get_water_hgt_nocheck(koord k) const { return get_water_hgt_nocheck(k.x, k.y); } /// @return water height inline sint8 get_water_hgt(sint16 x, sint16 y) const { return is_within_limits( x, y ) ? water_hgts[x + y * (cached_grid_size.x)] : groundwater; } inline sint8 get_water_hgt(koord k) const { return get_water_hgt(k.x, k.y); } /** * Sets water height. * * @param x,y tile position * @param hgt */ void set_water_hgt_nocheck(sint16 x, sint16 y, sint8 hgt) { water_hgts[x + y * cached_grid_size.x] = hgt; } inline void set_water_hgt_nocheck(koord k, sint8 hgt) { water_hgts[k.x + k.y * cached_grid_size.x] = hgt; } public: /** * Returns the current waterline height. */ sint8 get_groundwater() const { return groundwater; } /// @returns the minimum allowed height on the map. sint8 get_min_allowed_height() const { return min_allowed_height; } /// @returns the maximum allowed world height. sint8 get_max_allowed_height() const { return max_allowed_height; } public: /// @return true, wenn Platz an Stelle @p pos mit Groesse @p dim dim Water ist bool is_water(koord pos, koord dim) const; /// @return true, if square in place (i,j) with size w, h is constructible. bool square_is_free(koord k, sint16 w, sint16 h, int *last_y, climate_bits cl) const; public: /// @returns Minimum height of the planquadrat (tile) at @p k. /// For speed no checks performed that coordinates are valid sint8 min_hgt_nocheck(koord k) const; /// @return Maximum height of the planquadrats (tile) at @p k. /// For speed no checks performed that coordinates are valid sint8 max_hgt_nocheck(koord k) const; /// @return Minimum height of the planquadrat (tile) at @p k. sint8 min_hgt(koord k) const; /// @return Maximum height of the planquadrat (tile) at @p k. sint8 max_hgt(koord k) const; public: void get_height_slope_from_grid(koord k, sint8 &hgt, slope_t::type &slope); /** * Fills array with corner heights of neighbours */ void get_neighbour_heights(const koord k, sint8 neighbour_height[8][4]) const; // // Terraforming related // public: /** * Checks if the whole planquadrat (tile) at coordinates (@p x, @p y) height can * be changed ( for example, water height can't be changed ). */ bool is_plan_height_changeable(sint16 x, sint16 y) const; /** * Increases the height of the grid coordinate (@p x, @p y) by one. * * @param player player * @param pos Grid coordinate. * @param[out] err */ int grid_raise(const player_t *player, koord pos, const char *&err); /** * Decreases the height of the grid coordinate (@p x, @p y) by one. * * @param player player * @param pos Grid coordinate. * @param[out] err */ int grid_lower(const player_t *player, koord pos, const char *&err); /** * Raise grid point (@p x,@p y). Changes @ref grid_hgts only, used during map creation/enlargement. * @see clean_up */ void raise_grid_to(sint16 x, sint16 y, sint8 h); /** * Lower grid point (@p x,@p y). Changes @ref grid_hgts only, used during map creation/enlargement. * @see clean_up */ void lower_grid_to(sint16 x, sint16 y, sint8 h); // mostly used by AI: Ask to flatten a tile bool can_flatten_tile(player_t *player, koord k, sint8 hgt, bool keep_water=false, bool make_underwater_hill=false); bool flatten_tile(player_t *player, koord k, sint8 hgt, bool keep_water=false, bool make_underwater_hill=false, bool justcheck=false); public: /** * Returns the natural slope a a position using the grid. * @note No checking, and only using the grind for calculation. */ slope_t::type calc_natural_slope( const koord k ) const; /** * @return The natural slope at a position. * @note Uses the corner height for the best slope. */ slope_t::type recalc_natural_slope( const koord k, sint8 &new_height ) const; /** * @return The corner that needs to be raised/lowered on the given coordinates. * @param pos Grid coordinate to check. * @note Inline because called very frequently! * @note Will always return north-west except on border tiles. * @pre pos has to be a valid grid coordinate, undefined otherwise. */ inline slope4_t get_corner_to_operate(const koord &pos) const { // Normal tile if ( ( pos.x != cached_grid_size.x ) && ( pos.y != cached_grid_size.y ) ){ return slope4_t::corner_NW; } // Border on south-east if ( is_within_limits(pos.x-1, pos.y) ) { return(slope4_t::corner_NE); } // Border on south-west if ( is_within_limits(pos.x, pos.y-1) ) { return(slope4_t::corner_SW); } // Border on south return (slope4_t::corner_SE); } protected: /** * Initializes the height_to_climate field from settings. */ void init_height_to_climate(); /// Rotates climate and water transitions for a tile void rotate_transitions(koord k); public: /// Recalculate climate and water transitions for a tile void recalc_transitions(koord k); public: /** * Returns the climate for a given height, ruled by world creation settings. * Used to determine climate when terraforming, loading old games, etc. */ climate get_climate_at_height(sint16 height) const { const sint16 h=height-groundwater; if(h<0) { return water_climate; } else if( (uint)h >= lengthof(height_to_climate) ) { return arctic_climate; } return (climate)height_to_climate[h]; } /** * returns the current climate for a given koordinate */ inline climate get_climate(koord k) const { const planquadrat_t *plan = access(k); return plan ? plan->get_climate() : water_climate; } /** * sets the current climate for a given koordinate */ inline void set_climate(koord k, climate cl, bool recalc) { planquadrat_t *plan = access(k); if( plan ) { plan->set_climate(cl); if( recalc ) { recalc_transitions(k); for( int i = 0; i < 8; i++ ) { recalc_transitions( k + koord::neighbours[i] ); } } } } /// Calculates appropriate climate for a tile void calc_climate(koord k, bool recalc); private: /** * Dummy method, to generate compiler error if someone tries to call get_climate( int ), * as the int parameter will silently be cast to koord... */ climate get_climate(sint16) const = delete; }; #endif simutrans-124.3/src/simutrans/world/terraformer.cc000066400000000000000000000527571474050137200223750ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "terraformer.h" #include "../dataobj/scenario.h" #include "../descriptor/ground_desc.h" #include "../tool/simmenu.h" #include "simworld.h" terraformer_t::node_t::node_t() : x(-1), y(-1), changed(0) { } terraformer_t::node_t::node_t(sint16 x, sint16 y, sint8 hsw, sint8 hse, sint8 hne, sint8 hnw, uint8 c) : x(x), y(y), hsw(hsw), hse(hse), hne(hne), hnw(hnw), changed(c) { } bool terraformer_t::node_t::operator==(const terraformer_t::node_t &a) const { return (a.x==x) && (a.y==y); } terraformer_t::terraformer_t(operation_t op, karte_t *welt) : actual_flag(1), ready(false), op(op), welt(welt) { } bool terraformer_t::node_t::comp(const terraformer_t::node_t &a, const terraformer_t::node_t &b) { int diff = a.x - b.x; if (diff == 0) { diff = a.y - b.y; } return diff<0; } void terraformer_t::add_node(sint16 x, sint16 y, sint8 hsw, sint8 hse, sint8 hne, sint8 hnw) { if (!welt->is_within_limits(x,y)) { return; } const node_t test(x, y, hsw, hse, hne, hnw, actual_flag^3); node_t *other = list.insert_unique_ordered(test, node_t::comp); const sint8 factor = (op == terraformer_t::raise) ? +1 : -1; if (other) { if (factor*other->hsw < factor*test.hsw) { other->hsw = test.hsw; other->changed |= actual_flag ^ 3; ready = false; } if (factor*other->hse < factor*test.hse) { other->hse = test.hse; other->changed |= actual_flag ^ 3; ready = false; } if (factor*other->hne < factor*test.hne) { other->hne = test.hne; other->changed |= actual_flag ^ 3; ready = false; } if (factor*other->hnw < factor*test.hnw) { other->hnw = test.hnw; other->changed |= actual_flag ^ 3; ready = false; } } else { ready = false; } } void terraformer_t::generate_affected_tile_list() { while( !ready) { actual_flag ^= 3; // flip bits // clear new_flag bit for(node_t& i : list) { i.changed &= actual_flag; } // process nodes with actual_flag set ready = true; for(uint32 j=0; j < list.get_count(); j++) { node_t& i = list[j]; if (i.changed & actual_flag) { i.changed &= ~actual_flag; if (op == terraformer_t::raise) { prepare_raise(i); } else { prepare_lower(i); } } } } } const char *terraformer_t::can_raise_all(const player_t *player, bool keep_water) const { assert(op == terraformer_t::raise); assert(ready); for(node_t const& i : list) { if (const char *err = can_raise_tile_to(i, player, keep_water)) { return err; } } return NULL; } const char *terraformer_t::can_lower_all(const player_t *player) const { assert(op == terraformer_t::lower); assert(ready); for(node_t const& i : list) { if (const char *err = can_lower_tile_to(i, player)) { return err; } } return NULL; } int terraformer_t::apply() { assert(ready); int n = 0; if (op == terraformer_t::raise) { for(node_t const& i : list) { n += raise_to(i); } } else { for(node_t const& i : list) { n += lower_to(i); } } return n; } void terraformer_t::prepare_raise(const node_t node) { assert(welt->is_within_limits(node.x,node.y)); const grund_t *gr = welt->lookup_kartenboden_nocheck(node.x,node.y); const sint8 water_hgt = welt->get_water_hgt_nocheck(node.x,node.y); const sint8 h0 = gr->get_hoehe(); // old height const sint8 h0_sw = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x, node.y+1) ) : h0 + corner_sw( gr->get_grund_hang() ); const sint8 h0_se = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x+1,node.y+1) ) : h0 + corner_se( gr->get_grund_hang() ); const sint8 h0_ne = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x+1,node.y ) ) : h0 + corner_ne( gr->get_grund_hang() ); const sint8 h0_nw = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x, node.y ) ) : h0 + corner_nw( gr->get_grund_hang() ); // new height const sint8 hn_sw = max(node.hsw, h0_sw); const sint8 hn_se = max(node.hse, h0_se); const sint8 hn_ne = max(node.hne, h0_ne); const sint8 hn_nw = max(node.hnw, h0_nw); // nothing to do? if( !gr->is_water() && h0_sw >= node.hsw && h0_se >= node.hse && h0_ne >= node.hne && h0_nw >= node.hnw ) { return; } // calc new height and slope const sint8 hneu = min( min( hn_sw, hn_se ), min( hn_ne, hn_nw ) ); const sint8 hmaxneu = max( max( hn_sw, hn_se ), max( hn_ne, hn_nw ) ); const uint8 max_hdiff = ground_desc_t::double_grounds ? 2 : 1; const bool ok = (hmaxneu - hneu <= max_hdiff); // may fail on water tiles since lookup_hgt might be modified from previous raise_to calls if( !ok && !gr->is_water() ) { assert(false); } // sw if (h0_sw < node.hsw) { add_node( node.x - 1, node.y + 1, node.hsw - max_hdiff, node.hsw - max_hdiff, node.hsw, node.hsw - max_hdiff ); } // s if (h0_sw < node.hsw || h0_se < node.hse) { const sint8 hs = max( node.hse, node.hsw ) - max_hdiff; add_node( node.x, node.y + 1, hs, hs, node.hse, node.hsw ); } // se if (h0_se < node.hse) { add_node( node.x + 1, node.y + 1, node.hse - max_hdiff, node.hse - max_hdiff, node.hse - max_hdiff, node.hse ); } // e if (h0_se < node.hse || h0_ne < node.hne) { const sint8 he = max( node.hse, node.hne ) - max_hdiff; add_node( node.x + 1, node.y, node.hse, he, he, node.hne ); } // ne if (h0_ne < node.hne) { add_node( node.x + 1,node.y - 1, node.hne, node.hne - max_hdiff, node.hne - max_hdiff, node.hne - max_hdiff ); } // n if (h0_nw < node.hnw || h0_ne < node.hne) { const sint8 hn = max( node.hnw, node.hne ) - max_hdiff; add_node( node.x, node.y - 1, node.hnw, node.hne, hn, hn ); } // nw if (h0_nw < node.hnw) { add_node( node.x - 1, node.y - 1, node.hnw - max_hdiff, node.hnw, node.hnw - max_hdiff, node.hnw - max_hdiff ); } // w if (h0_sw < node.hsw || h0_nw < node.hnw) { const sint8 hw = max( node.hnw, node.hsw ) - max_hdiff; add_node( node.x - 1, node.y, hw, node.hsw, node.hnw, hw ); } } void terraformer_t::prepare_lower(const node_t node) { assert(welt->is_within_limits(node.x,node.y)); const grund_t *gr = welt->lookup_kartenboden_nocheck(node.x,node.y); const sint8 water_hgt = welt->get_water_hgt_nocheck(node.x,node.y); const sint8 h0 = gr->get_hoehe(); // which corners have to be raised? const sint8 h0_sw = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x, node.y+1) ) : h0 + corner_sw( gr->get_grund_hang() ); const sint8 h0_se = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x+1,node.y+1) ) : h0 + corner_se( gr->get_grund_hang() ); const sint8 h0_ne = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x, node.y+1) ) : h0 + corner_ne( gr->get_grund_hang() ); const sint8 h0_nw = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x, node.y ) ) : h0 + corner_nw( gr->get_grund_hang() ); const uint8 max_hdiff = ground_desc_t::double_grounds ? 2 : 1; // sw if (h0_sw > node.hsw) { add_node(node.x - 1, node.y + 1, node.hsw + max_hdiff, node.hsw + max_hdiff, node.hsw, node.hsw + max_hdiff); } // s if (h0_se > node.hse || h0_sw > node.hsw) { const sint8 hs = min( node.hse, node.hsw ) + max_hdiff; add_node( node.x, node.y + 1, hs, hs, node.hse, node.hsw); } // se if (h0_se > node.hse) { add_node( node.x + 1, node.y + 1, node.hse + max_hdiff, node.hse + max_hdiff, node.hse + max_hdiff, node.hse); } // e if (h0_se > node.hse || h0_ne > node.hne) { const sint8 he = max( node.hse, node.hne ) + max_hdiff; add_node( node.x + 1, node.y, node.hse, he, he, node.hne); } // ne if (h0_ne > node.hne) { add_node( node.x + 1, node.y - 1, node.hne, node.hne + max_hdiff, node.hne + max_hdiff, node.hne + max_hdiff); } // n if (h0_nw > node.hnw || h0_ne > node.hne) { const sint8 hn = min( node.hnw, node.hne ) + max_hdiff; add_node( node.x, node.y - 1, node.hnw, node.hne, hn, hn); } // nw if (h0_nw > node.hnw) { add_node( node.x - 1, node.y - 1, node.hnw + max_hdiff, node.hnw, node.hnw + max_hdiff, node.hnw + max_hdiff); } // w if (h0_nw > node.hnw || h0_sw > node.hsw) { const sint8 hw = min( node.hnw, node.hsw ) + max_hdiff; add_node( node.x - 1, node.y, hw, node.hsw, node.hnw, hw); } } const char *terraformer_t::can_raise_tile_to(const node_t &node, const player_t *player, bool keep_water) const { assert(welt->is_within_limits(node.x,node.y)); const grund_t *gr = welt->lookup_kartenboden_nocheck(node.x,node.y); const sint8 water_hgt = welt->get_water_hgt_nocheck(node.x,node.y); const sint8 max_hgt = max(max(node.hsw,node.hse),max(node.hne,node.hnw)); if( gr->is_water() && keep_water && max_hgt > water_hgt ) { return ""; } return can_raise_plan_to(player, node.x, node.y, max_hgt); } // lower plan // new heights for each corner given const char* terraformer_t::can_lower_tile_to(const node_t &node, const player_t *player) const { assert(welt->is_within_limits(node.x,node.y)); const sint8 hneu = min( min( node.hsw, node.hse ), min( node.hne, node.hnw ) ); if( hneu < welt->get_min_allowed_height() ) { return "Maximum tile height difference reached."; } // water heights // check if need to lower water height for higher neighbouring tiles for( sint16 i = 0 ; i < 8 ; i++ ) { const koord neighbour = koord( node.x, node.y ) + koord::neighbours[i]; if( welt->is_within_limits(neighbour) && welt->get_water_hgt_nocheck(neighbour) > hneu ) { if (!welt->is_plan_height_changeable( neighbour.x, neighbour.y )) { return ""; } } } return can_lower_plan_to(player, node.x, node.y, hneu ); } int terraformer_t::raise_to(const node_t &node) { assert(welt->is_within_limits(node.x,node.y)); int n = 0; grund_t *gr = welt->lookup_kartenboden_nocheck(node.x,node.y); const sint8 water_hgt = welt->get_water_hgt_nocheck(node.x,node.y); const sint8 h0 = gr->get_hoehe(); // old height const sint8 h0_sw = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x, node.y+1) ) : h0 + corner_sw( gr->get_grund_hang() ); const sint8 h0_se = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x+1, node.y+1) ) : h0 + corner_se( gr->get_grund_hang() ); const sint8 h0_ne = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x+1, node.y ) ) : h0 + corner_ne( gr->get_grund_hang() ); const sint8 h0_nw = gr->is_water() ? min(water_hgt, welt->lookup_hgt_nocheck(node.x, node.y ) ) : h0 + corner_nw( gr->get_grund_hang() ); // new height const sint8 hn_sw = max(node.hsw, h0_sw); const sint8 hn_se = max(node.hse, h0_se); const sint8 hn_ne = max(node.hne, h0_ne); const sint8 hn_nw = max(node.hnw, h0_nw); // nothing to do? if( !gr->is_water() && h0_sw >= node.hsw && h0_se >= node.hse && h0_ne >= node.hne && h0_nw >= node.hnw ) { return 0; } // calc new height and slope const sint8 hneu = min( min( hn_sw, hn_se ), min( hn_ne, hn_nw ) ); const sint8 hmaxneu = max( max( hn_sw, hn_se ), max( hn_ne, hn_nw ) ); const uint8 max_hdiff = ground_desc_t::double_grounds ? 2 : 1; const sint8 disp_hneu = max( hneu, water_hgt ); const sint8 disp_hn_sw = max( hn_sw, water_hgt ); const sint8 disp_hn_se = max( hn_se, water_hgt ); const sint8 disp_hn_ne = max( hn_ne, water_hgt ); const sint8 disp_hn_nw = max( hn_nw, water_hgt ); const slope_t::type sneu = encode_corners(disp_hn_sw - disp_hneu, disp_hn_se - disp_hneu, disp_hn_ne - disp_hneu, disp_hn_nw - disp_hneu); const bool ok = (hmaxneu - hneu <= max_hdiff); // may fail on water tiles since lookup_hgt might be modified from previous raise_to calls if (!ok && !gr->is_water()) { assert(false); } bool recalc_climate = gr-> is_water() || welt->get_settings().get_climate_generator() == settings_t::HEIGHT_BASED; // change height and slope, for water tiles only if they will become land if( !gr->is_water() || (hmaxneu > water_hgt || (hneu == water_hgt && hmaxneu == water_hgt) ) ) { gr->set_pos( koord3d( node.x, node.y, disp_hneu ) ); gr->set_grund_hang( sneu ); welt->access_nocheck(node.x,node.y)->angehoben(); welt->set_water_hgt_nocheck(node.x, node.y, welt->get_groundwater()-4); } // update north point in grid welt->set_grid_hgt_nocheck(node.x, node.y, hn_nw); if (recalc_climate) { welt->calc_climate(koord(node.x, node.y), true); } if ( node.x+1 == welt->get_size().x ) { // update eastern grid coordinates too if we are in the edge. welt->set_grid_hgt_nocheck(node.x+1, node.y, hn_ne); welt->set_grid_hgt_nocheck(node.x+1, node.y+1, hn_se); } if ( node.y+1 == welt->get_size().y ) { // update southern grid coordinates too if we are in the edge. welt->set_grid_hgt_nocheck(node.x, node.y+1, hn_sw); welt->set_grid_hgt_nocheck(node.x+1, node.y+1, hn_se); } n += hn_sw - h0_sw + hn_se - h0_se + hn_ne - h0_ne + hn_nw - h0_nw; welt->lookup_kartenboden_nocheck(node.x,node.y)->calc_image(); if ( (node.x+2) < welt->get_size().x ) { welt->lookup_kartenboden_nocheck(node.x+1,node.y)->calc_image(); } if ( (node.y+2) < welt->get_size().y ) { welt->lookup_kartenboden_nocheck(node.x,node.y+1)->calc_image(); } return n; } int terraformer_t::lower_to(const node_t &node) { assert(welt->is_within_limits(node.x,node.y)); int n = 0; grund_t *gr = welt->lookup_kartenboden_nocheck(node.x,node.y); sint8 water_hgt = welt->get_water_hgt_nocheck(node.x,node.y); const sint8 h0 = gr->get_hoehe(); // old height const sint8 h0_sw = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x, node.y+1) ) : h0 + corner_sw( gr->get_grund_hang() ); const sint8 h0_se = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x+1, node.y+1) ) : h0 + corner_se( gr->get_grund_hang() ); const sint8 h0_ne = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x+1, node.y ) ) : h0 + corner_ne( gr->get_grund_hang() ); const sint8 h0_nw = gr->is_water() ? min( water_hgt, welt->lookup_hgt_nocheck(node.x, node.y ) ) : h0 + corner_nw( gr->get_grund_hang() ); // new height const sint8 hn_sw = min(node.hsw, h0_sw); const sint8 hn_se = min(node.hse, h0_se); const sint8 hn_ne = min(node.hne, h0_ne); const sint8 hn_nw = min(node.hnw, h0_nw); // nothing to do? if( gr->is_water() ) { if( h0_nw <= node.hnw ) { return 0; } } else if( h0_sw <= node.hsw && h0_se <= node.hse && h0_ne <= node.hne && h0_nw <= node.hnw ) { return 0; } // calc new height and slope const sint8 hneu = min( min( hn_sw, hn_se ), min( hn_ne, hn_nw ) ); const sint8 hmaxneu = max( max( hn_sw, hn_se ), max( hn_ne, hn_nw ) ); if( hneu >= water_hgt ) { // calculate water table from surrounding tiles - start off with height on this tile sint8 water_table = water_hgt >= h0 ? water_hgt : welt->get_groundwater() - 4; /* * we test each corner in turn to see whether it is at the base height of the tile. * If it is we then mark the 3 surrounding tiles for that corner for checking. * Surrounding tiles are indicated by bits going anti-clockwise from * (binary) 00000001 for north-west through to (binary) 10000000 for north * as this is the order of directions used by koord::neighbours[] */ uint8 neighbour_flags = 0; if( hn_nw == hneu ) { neighbour_flags |= 0x83; } if( hn_ne == hneu ) { neighbour_flags |= 0xe0; } if( hn_se == hneu ) { neighbour_flags |= 0x38; } if( hn_sw == hneu ) { neighbour_flags |= 0x0e; } for( sint16 i = 0; i < 8 ; i++ ) { const koord neighbour = koord( node.x, node.y ) + koord::neighbours[i]; // here we look at the bit in neighbour_flags for this direction // we shift it i bits to the right and test the least significant bit if( welt->is_within_limits( neighbour ) && ((neighbour_flags >> i) & 1) ) { grund_t *gr2 = welt->lookup_kartenboden_nocheck( neighbour ); const sint8 water_hgt_neighbour = welt->get_water_hgt_nocheck( neighbour ); if( gr2 && (water_hgt_neighbour >= gr2->get_hoehe()) && water_hgt_neighbour <= hneu ) { water_table = max( water_table, water_hgt_neighbour ); } } } for( sint16 i = 0; i < 8 ; i++ ) { const koord neighbour = koord( node.x, node.y ) + koord::neighbours[i]; if( welt->is_within_limits( neighbour ) ) { grund_t *gr2 = welt->lookup_kartenboden_nocheck( neighbour ); if( gr2 && gr2->get_hoehe() < water_table ) { i = 8; water_table = welt->get_groundwater() - 4; } } } // only allow water table to be lowered (except for case of sea level) // this prevents severe (errors! if( water_table < welt->get_water_hgt_nocheck(node.x,node.y) ) { water_hgt = water_table; welt->set_water_hgt_nocheck(node.x, node.y, water_table ); } } // calc new height and slope const sint8 disp_hneu = max( hneu, water_hgt ); const sint8 disp_hn_sw = max( hn_sw, water_hgt ); const sint8 disp_hn_se = max( hn_se, water_hgt ); const sint8 disp_hn_ne = max( hn_ne, water_hgt ); const sint8 disp_hn_nw = max( hn_nw, water_hgt ); const slope_t::type sneu = encode_corners(disp_hn_sw - disp_hneu, disp_hn_se - disp_hneu, disp_hn_ne - disp_hneu, disp_hn_nw - disp_hneu); bool recalc_climate = welt->get_settings().get_climate_generator() == settings_t::HEIGHT_BASED; // change height and slope for land tiles only if( !gr->is_water() || (hmaxneu > water_hgt) ) { gr->set_pos( koord3d( node.x, node.y, disp_hneu ) ); gr->set_grund_hang( (slope_t::type)sneu ); welt->access_nocheck(node.x,node.y)->abgesenkt(); } // update north point in grid welt->set_grid_hgt_nocheck(node.x, node.y, hn_nw); if ( node.x+1 == welt->get_size().x ) { // update eastern grid coordinates too if we are in the edge. welt->set_grid_hgt_nocheck(node.x+1, node.y, hn_ne); welt->set_grid_hgt_nocheck(node.x+1, node.y+1, hn_se); } if ( node.y+1 == welt->get_size().y ) { // update southern grid coordinates too if we are in the edge. welt->set_grid_hgt_nocheck(node.x, node.y+1, hn_sw); welt->set_grid_hgt_nocheck(node.x+1, node.y+1, hn_se); } // water heights // lower water height for higher neighbouring tiles // find out how high water is for( sint16 i = 0; i < 8; i++ ) { const koord neighbour = koord( node.x, node.y ) + koord::neighbours[i]; if( welt->is_within_limits( neighbour ) ) { const sint8 water_hgt_neighbour = welt->get_water_hgt_nocheck( neighbour ); if(water_hgt_neighbour > hneu ) { if( welt->min_hgt_nocheck( neighbour ) < water_hgt_neighbour ) { // convert to flat ground before lowering water level welt->raise_grid_to( neighbour.x, neighbour.y, water_hgt_neighbour ); welt->raise_grid_to( neighbour.x + 1, neighbour.y, water_hgt_neighbour ); welt->raise_grid_to( neighbour.x, neighbour.y + 1, water_hgt_neighbour ); welt->raise_grid_to( neighbour.x + 1, neighbour.y + 1, water_hgt_neighbour ); } welt->set_water_hgt_nocheck( neighbour, hneu ); welt->access_nocheck(neighbour)->correct_water(); recalc_climate = true; } } } if (recalc_climate) { welt->calc_climate( koord( node.x, node.y ), false ); for( sint16 i = 0; i < 8; i++ ) { const koord neighbour = koord( node.x, node.y ) + koord::neighbours[i]; welt->calc_climate( neighbour, false ); } } // recalc landscape images - need to extend 2 in each direction for( sint16 j = node.y - 2; j <= node.y + 2; j++ ) { for( sint16 i = node.x - 2; i <= node.x + 2; i++ ) { if( welt->is_within_limits( i, j ) /*&& (i != x || j != y)*/ ) { welt->recalc_transitions( koord (i, j ) ); } } } n += h0_sw-hn_sw + h0_se-hn_se + h0_ne-hn_ne + h0_nw-hn_nw; welt->lookup_kartenboden_nocheck(node.x,node.y)->calc_image(); if( (node.x+2) < welt->get_size().x ) { welt->lookup_kartenboden_nocheck(node.x+1,node.y)->calc_image(); } if( (node.y+2) < welt->get_size().y ) { welt->lookup_kartenboden_nocheck(node.x,node.y+1)->calc_image(); } return n; } const char *terraformer_t::can_lower_plan_to(const player_t *player, sint16 x, sint16 y, sint8 h) const { const planquadrat_t *plan = welt->access(x,y); const settings_t &settings = welt->get_settings(); if( plan==NULL ) { return ""; } if( h < welt->get_groundwater() - 3 ) { return "Watertable reached"; } const sint8 hmax = plan->get_kartenboden()->get_hoehe(); if( (hmax == h || hmax == h - 1) && (plan->get_kartenboden()->get_grund_hang() == 0 || welt->is_plan_height_changeable( x, y )) ) { return NULL; } if( !welt->is_plan_height_changeable(x, y) ) { return ""; } // tunnel slope below? const grund_t *gr = plan->get_boden_in_hoehe( h - 1 ); if( !gr ) { gr = plan->get_boden_in_hoehe( h - 2 ); } if( !gr && settings.get_way_height_clearance()==2 ) { gr = plan->get_boden_in_hoehe( h - 3 ); } if( gr && h < gr->get_pos().z + slope_t::max_diff( gr->get_weg_hang() ) + settings.get_way_height_clearance() ) { return ""; } // tunnel below? while(h < hmax) { if(plan->get_boden_in_hoehe(h)) { return ""; } h ++; } // check allowance by scenario if (welt->get_scenario()->is_scripted()) { return welt->get_scenario()->is_work_allowed_here(player, TOOL_LOWER_LAND|GENERAL_TOOL, ignore_wt, 0, plan->get_kartenboden()->get_pos()); } return NULL; } const char *terraformer_t::can_raise_plan_to(const player_t *player, sint16 x, sint16 y, sint8 h) const { const planquadrat_t *plan = welt->access(x,y); if( plan == NULL || !welt->is_plan_height_changeable(x, y) ) { return ""; } // irgendwo eine Bruecke im Weg? const sint8 hmin = plan->get_kartenboden()->get_hoehe(); while(h > hmin) { if(plan->get_boden_in_hoehe(h)) { return ""; } h --; } // check allowance by scenario if (welt->get_scenario()->is_scripted()) { return welt->get_scenario()->is_work_allowed_here(player, TOOL_RAISE_LAND|GENERAL_TOOL, ignore_wt, 0, plan->get_kartenboden()->get_pos()); } return NULL; } simutrans-124.3/src/simutrans/world/terraformer.h000066400000000000000000000103731474050137200222230ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #ifndef WORLD_TERRAFORMER_H #define WORLD_TERRAFORMER_H #include "../simtypes.h" #include "../tpl/vector_tpl.h" class karte_t; class player_t; /** * Class to manage terraform operations. * Can be used for raise only or lower only operations, but not mixed. * * Usual order of calls: * 1. add_node() (can be repeated) * 2. generate_affected_tile_list() * 3. can_raise_all() / can_lower_all() * 4. apply() (to actually apply the changes to the terrain; optional) */ class terraformer_t { public: enum operation_t { lower = 0, raise = 1 }; private: /// Structure to save terraforming operations struct node_t { public: node_t(); node_t(sint16 x, sint16 y, sint8 hsw, sint8 hse, sint8 hne, sint8 hnw, uint8 c); public: /// compares position bool operator==(const node_t &a) const; /// compares position static bool comp(const node_t &a, const node_t &b); public: sint16 x; ///< x-coordinate sint16 y; ///< y-coordinate sint8 hsw, hse, hne, hnw; uint8 changed; }; public: terraformer_t(terraformer_t::operation_t op, karte_t *welt); public: /// Add tile to be raised/lowered. void add_node(sint16 x, sint16 y, sint8 hsw, sint8 hse, sint8 hne, sint8 hnw); /// Generate list of all tiles that will be affected. void generate_affected_tile_list(); /// Check whether raise operation would succeed const char *can_raise_all(const player_t *player, bool keep_water = false) const; /// Check whether lower operation would succeed const char *can_lower_all(const player_t *player) const; /// Do the raise/lower operations int apply(); private: /// Internal functions to be used with terraformer_t to propagate terrain changes to neighbouring tiles void prepare_raise(const node_t node); void prepare_lower(const node_t node); /** * Checks whether the heights of the corners of the tile at (@p x, @p y) can be raised. * If the desired height of a corner is lower than its current height, this corner is ignored. * * @param node * @param player player who wants to lower * @param keep_water returns false if water tiles would be raised above water * @returns NULL if raise_to operation can be performed, an error message otherwise */ const char *can_raise_tile_to(const node_t &node, const player_t *player, bool keep_water) const; /** * Checks whether the heights of the corners of the tile at (@p x, @p y) can be lowered. * If the desired height of a corner is higher than its current height, this corner is ignored. * * @param node * @param player player who wants to lower * @returns NULL if lower_to operation can be performed, an error message otherwise */ const char *can_lower_tile_to(const node_t &node, const player_t *player) const; /** * Raises heights of the corners of the tile at (@p x, @p y). * New heights for each corner given. * * @pre can_raise_to should be called before this method. * @see can_raise_to * @returns count of full raise operations (4 corners raised one level) * @note Clear tile, reset water/land type, calc minimap pixel. */ int raise_to(const node_t &node); /** * Lowers heights of the corners of the tile at (@p x, @p y). * New heights for each corner given. * @pre can_lower_to should be called before this method. * @see can_lower_to * @returns count of full lower operations (4 corners lowered one level) * @note Clear tile, reset water/land type, calc minimap pixel. */ int lower_to(const node_t &node); /** * Checks if the planquadrat (tile) at coordinate (x,y) * can be lowered at the specified height. */ const char *can_lower_plan_to(const player_t *player, sint16 x, sint16 y, sint8 h) const; /** * Checks if the planquadrat (tile) at coordinate (x,y) * can be raised at the specified height. */ const char *can_raise_plan_to(const player_t *player, sint16 x, sint16 y, sint8 h) const; private: vector_tpl list; ///< list of affected tiles uint8 actual_flag; ///< internal flag to iterate through list bool ready; ///< internal flag to signal that the affected tile list is updated operation_t op; ///< Raise or lower? karte_t *welt; }; #endif simutrans-124.3/src/squirrel/000077500000000000000000000000001474050137200162105ustar00rootroot00000000000000simutrans-124.3/src/squirrel/sq_extensions.cc000066400000000000000000000051341474050137200214240ustar00rootroot00000000000000#include "sq_extensions.h" #include "squirrel/sqpcheader.h" // for declarations... #include "squirrel/sqvm.h" // for Raise_Error_vl #include #include "../simutrans/tpl/ptrhashtable_tpl.h" // store data associate to vm's here struct my_vm_info_t { const char* suspend_blocker; /// if not null then no suspendable functions should be called }; static ptrhashtable_tpl vm_info; void register_vm(HSQUIRRELVM v) { vm_info.put(v); } void unregister_vm(HSQUIRRELVM v) { vm_info.remove(v); } void* get_instanceup(HSQUIRRELVM vm, SQInteger index, void* tag, const char* type) { void* ptr = NULL; if(SQ_SUCCEEDED(sq_getinstanceup(vm, index, &ptr, tag))) { return ptr; } else { sq_raise_error(vm, "Expected instance of class %s.", type ? type : ""); return NULL; } } SQRESULT sq_raise_error(HSQUIRRELVM vm, const SQChar *s, ...) { va_list vl; va_start(vl, s); vm->Raise_Error_vl(s, vl); va_end(vl); return SQ_ERROR; } SQRESULT sq_call_restricted(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool throw_if_no_ops, SQInteger ops) { if(v->_ops_remaining < 4*ops && sq_getvmstate(v)==SQ_VMSTATE_IDLE) { v->_ops_remaining += ops; } bool save_throw_if_no_ops = v->_throw_if_no_ops; v->_throw_if_no_ops = throw_if_no_ops; SQRESULT ret = sq_call(v, params, retval, true /*raise_error*/); v->_throw_if_no_ops = save_throw_if_no_ops; return ret; } SQRESULT sq_resumevm(HSQUIRRELVM v, SQBool retval, SQInteger ops) { if(v->_ops_remaining < 4*ops) { v->_ops_remaining += ops; } bool save_throw_if_no_ops = v->_throw_if_no_ops; v->_throw_if_no_ops = false; SQRESULT ret = sq_wakeupvm(v, false, retval, true /*raise_error*/, false); v->_throw_if_no_ops = save_throw_if_no_ops; return ret; } // see sq_wakeupvm void sq_setwakeupretvalue(HSQUIRRELVM v) { if(!v->_suspended) { return; } SQInteger target = v->_suspended_target; if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target) = v->GetUp(-1); //retval } v->Pop(); // make target invalid v->_suspended_target = -1; } bool sq_canresumevm(HSQUIRRELVM v) { // true if not suspended or not waiting for any return value return (!v->_suspended || v->_suspended_target==-1); } SQRESULT sq_get_ops_total(HSQUIRRELVM v) { sq_pushinteger(v, v->_ops_total); return 1; } SQRESULT sq_get_ops_remaing(HSQUIRRELVM v) { sq_pushinteger(v, v->_ops_remaining); return 1; } void sq_block_suspend(HSQUIRRELVM v, const char* f) { if (my_vm_info_t* i = vm_info.access(v)) { i->suspend_blocker = f; } } const char* sq_get_suspend_blocker(HSQUIRRELVM v) { return vm_info.get(v).suspend_blocker; } simutrans-124.3/src/squirrel/sq_extensions.h000066400000000000000000000036671474050137200212770ustar00rootroot00000000000000#ifndef _SQ_EXTENSIONS_ #define _SQ_EXTENSIONS_ #include "squirrel.h" /** * Extensions to the squirrel engine * for simutrans */ /** * Register vm to store internal information. */ void register_vm(HSQUIRRELVM v); /** * Should be called if vm closes. */ void unregister_vm(HSQUIRRELVM v); /** * Returns instance userpointer of instance, checks type tag. * @param index of instance in stack * @param tag type tag of class * @param type squirrel-side class name - used for error message * @returns userpointer or NULL in case of error (tag does not match) */ void* get_instanceup(HSQUIRRELVM vm, SQInteger index, void* tag, const char* type); /** * Raises error. * @param s is format string analogue to printf-interface * @returns SQ_ERROR (-1) */ SQRESULT sq_raise_error(HSQUIRRELVM vm, const SQChar *s, ...); /** * calls a function with limited number of opcodes. * returns and suspends vm if opcode limit is exceeded */ SQRESULT sq_call_restricted(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool throw_if_no_ops, SQInteger ops = 1000); /** * if @r is not null, then no suspendable functions should be called in this vm */ void sq_block_suspend(HSQUIRRELVM v, const char* f); /** * @returns the name of the suspend-blocking function */ const char* sq_get_suspend_blocker(HSQUIRRELVM v); /** * resumes suspended vm. * returns and suspends (again) vm if opcode limit is exceeded. */ SQRESULT sq_resumevm(HSQUIRRELVM v, SQBool retval, SQInteger ops = 1000); /** * pops return value from stack and sets it for the suspended script. */ void sq_setwakeupretvalue(HSQUIRRELVM v); /** * checks whether vm can be resumed. in particular if script waits for return value on wakeup. */ bool sq_canresumevm(HSQUIRRELVM v); /// @returns total amount of opcodes executed by vm SQRESULT sq_get_ops_total(HSQUIRRELVM v); /// @returns amount of remaining opcodes until vm will be suspended SQRESULT sq_get_ops_remaing(HSQUIRRELVM v); #endif simutrans-124.3/src/squirrel/sqconfig.h000066400000000000000000000062621474050137200202000ustar00rootroot00000000000000#ifdef _SQ64 #ifdef _MSC_VER typedef __int64 SQInteger; typedef unsigned __int64 SQUnsignedInteger; typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/ #else typedef long long SQInteger; typedef unsigned long long SQUnsignedInteger; typedef unsigned long long SQHash; /*should be the same size of a pointer*/ #endif typedef int SQInt32; typedef unsigned int SQUnsignedInteger32; #else typedef int SQInteger; typedef int SQInt32; /*must be 32 bits(also on 64bits processors)*/ typedef unsigned int SQUnsignedInteger32; /*must be 32 bits(also on 64bits processors)*/ typedef unsigned int SQUnsignedInteger; typedef unsigned int SQHash; /*should be the same size of a pointer*/ #endif #ifdef SQUSEDOUBLE typedef double SQFloat; #else typedef float SQFloat; #endif #if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64) #ifdef _MSC_VER typedef __int64 SQRawObjectVal; //must be 64bits #else typedef long long SQRawObjectVal; //must be 64bits #endif #define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; } #else typedef SQUnsignedInteger SQRawObjectVal; //is 32 bits on 32 bits builds and 64 bits otherwise #define SQ_OBJECT_RAWINIT() #endif #ifndef SQ_ALIGNMENT // SQ_ALIGNMENT shall be less than or equal to SQ_MALLOC alignments, and its value shall be power of 2. #if defined(SQUSEDOUBLE) || defined(_SQ64) #define SQ_ALIGNMENT 8 #else #define SQ_ALIGNMENT 4 #endif #endif typedef void* SQUserPointer; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; #ifdef SQUNICODE #include #include typedef wchar_t SQChar; #define scstrcmp wcscmp #ifdef _WIN32 #define scsprintf _snwprintf #else #define scsprintf swprintf #endif #define scstrlen wcslen #define scstrtod wcstod #ifdef _SQ64 #define scstrtol wcstoll #else #define scstrtol wcstol #endif #define scstrtoul wcstoul #define scvsprintf vswprintf #define scstrstr wcsstr #define scprintf wprintf #ifdef _WIN32 #define WCHAR_SIZE 2 #define WCHAR_SHIFT_MUL 1 #define MAX_CHAR 0xFFFF #else #define WCHAR_SIZE 4 #define WCHAR_SHIFT_MUL 2 #define MAX_CHAR 0xFFFFFFFF #endif #define _SC(a) L##a #define scisspace iswspace #define scisdigit iswdigit #define scisprint iswprint #define scisxdigit iswxdigit #define scisalpha iswalpha #define sciscntrl iswcntrl #define scisalnum iswalnum #define sq_rsl(l) ((l)< #include #include void sqstd_printcallstack(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { SQStackInfos si; SQInteger i; SQFloat f; const SQChar *s; SQInteger level=1; //1 is to skip this function that is level 0 const SQChar *name=0; SQInteger seq=0; pf(v,_SC("\nCALLSTACK\n")); while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) { const SQChar *fn=_SC("unknown"); const SQChar *src=_SC("unknown"); if(si.funcname)fn=si.funcname; if(si.source)src=si.source; pf(v,_SC("* FUNCTION [%s()]
* %s"), fn,src); if (si.line > 0) { pf(v,_SC("* line [%d]"),si.line); } pf(v,_SC("
\n")); pf(v,_SC("- - LOCALS\n")); seq=0; while((name = sq_getlocal(v,level,seq))) { seq++; switch(sq_gettype(v,-1)) { case OT_NULL: pf(v,_SC("- - - [%s] NULL\n"),name); break; case OT_INTEGER: sq_getinteger(v,-1,&i); pf(v,_SC("- - - [%s] %d\n"),name,i); break; case OT_FLOAT: sq_getfloat(v,-1,&f); pf(v,_SC("- - - [%s] %.14g\n"),name,f); break; case OT_USERPOINTER: pf(v,_SC("- - - [%s] USERPOINTER\n"),name); break; case OT_STRING: sq_getstring(v,-1,&s); pf(v,_SC("- - - [%s] \"%s\"\n"),name,s); break; case OT_TABLE: pf(v,_SC("- - - [%s] TABLE (%d entries)\n"),name, sq_getsize(v, -1)); break; case OT_ARRAY: pf(v,_SC("- - - [%s] ARRAY (%d entries)\n"),name, sq_getsize(v, -1)); break; case OT_CLOSURE: pf(v,_SC("- - - [%s] CLOSURE\n"),name); break; case OT_NATIVECLOSURE: pf(v,_SC("- - - [%s] NATIVECLOSURE\n"),name); break; case OT_GENERATOR: pf(v,_SC("- - - [%s] GENERATOR\n"),name); break; case OT_USERDATA: pf(v,_SC("- - - [%s] USERDATA\n"),name); break; case OT_THREAD: pf(v,_SC("- - - [%s] THREAD\n"),name); break; case OT_CLASS: pf(v,_SC("- - - [%s] CLASS\n"),name); break; case OT_INSTANCE: { // try to obtain class name sq_getclass(v, -1); sq_pushnull(v); if (SQ_SUCCEEDED(sq_getattributes(v, -2))) { // stack: instance, class, attributes sq_pushstring(v, "classname", -1); if (SQ_SUCCEEDED(sq_get(v, -2))) { const char* cn; if (SQ_SUCCEEDED(sq_getstring(v, -1, &cn))) { pf(v,_SC("- - - [%s] INSTANCE(%s)\n"),name, cn); sq_pop(v, 3); break; } } sq_poptop(v); } sq_poptop(v); pf(v,_SC("- - - [%s] INSTANCE\n"),name); break; } case OT_WEAKREF: pf(v,_SC("- - - [%s] WEAKREF\n"),name); break; case OT_BOOL:{ SQBool bval; sq_getbool(v,-1,&bval); pf(v,_SC("- - - [%s] %s\n"),name,bval == SQTrue ? _SC("true"):_SC("false")); } break; default: assert(0); break; } sq_pop(v,1); } level++; } } } static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { pf(v,_SC("")); const SQChar *sErr = 0; if(sq_gettop(v)>=1) { if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { pf(v,_SC("\nError: [%s]\n"),sErr); } else{ pf(v,_SC("\nError: [unknown]\n")); } sqstd_printcallstack(v); } pf(v,_SC("")); } return 0; } void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column) { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { pf(v,_SC("")); pf(v,_SC("%s line = (%d) column = (%d) : error %s\n"),sSource,line,column,sErr); pf(v,_SC("")); } } void sqstd_seterrorhandlers(HSQUIRRELVM v) { sq_setcompilererrorhandler(v,_sqstd_compiler_error); sq_newclosure(v,_sqstd_aux_printerror,0); sq_seterrorhandler(v); } SQRESULT sqstd_throwerrorf(HSQUIRRELVM v,const SQChar *err,...) { SQInteger n=256; va_list args; begin: va_start(args,err); SQChar *b=sq_getscratchpad(v,n); SQInteger r=scvsprintf(b,n,err,args); va_end(args); if (r>=n) { n=r+1;//required+null goto begin; } else if (r<0) { return sq_throwerror(v,_SC("@failed to generate formatted error message")); } else { return sq_throwerror(v,b); } } simutrans-124.3/src/squirrel/sqstdlib/sqstdblob.cc000066400000000000000000000146721474050137200223530ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include #include "../squirrel.h" #include "../sqstdio.h" #include #include "../sqstdblob.h" #include "sqstdstream.h" #include "sqstdblobimpl.h" #define SQSTD_BLOB_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000002)) //Blob #define SETUP_BLOB(v) \ SQBlob *self = NULL; \ { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \ return sq_throwerror(v,_SC("invalid type tag")); } \ if(!self || !self->IsValid()) \ return sq_throwerror(v,_SC("the blob is invalid")); static SQInteger _blob_resize(HSQUIRRELVM v) { SETUP_BLOB(v); SQInteger size; sq_getinteger(v,2,&size); if(!self->Resize(size)) return sq_throwerror(v,_SC("resize failed")); return 0; } static void __swap_dword(unsigned int *n) { *n=(unsigned int)(((*n&0xFF000000)>>24) | ((*n&0x00FF0000)>>8) | ((*n&0x0000FF00)<<8) | ((*n&0x000000FF)<<24)); } static void __swap_word(unsigned short *n) { *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00); } static SQInteger _blob_swap4(HSQUIRRELVM v) { SETUP_BLOB(v); SQInteger num=(self->Len()-(self->Len()%4))>>2; unsigned int *t=(unsigned int *)self->GetBuf(); for(SQInteger i = 0; i < num; i++) { __swap_dword(&t[i]); } return 0; } static SQInteger _blob_swap2(HSQUIRRELVM v) { SETUP_BLOB(v); SQInteger num=(self->Len()-(self->Len()%2))>>1; unsigned short *t = (unsigned short *)self->GetBuf(); for(SQInteger i = 0; i < num; i++) { __swap_word(&t[i]); } return 0; } static SQInteger _blob__set(HSQUIRRELVM v) { SETUP_BLOB(v); SQInteger idx,val; sq_getinteger(v,2,&idx); sq_getinteger(v,3,&val); if(idx < 0 || idx >= self->Len()) return sq_throwerror(v,_SC("index out of range")); ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val; sq_push(v,3); return 1; } static SQInteger _blob__get(HSQUIRRELVM v) { SETUP_BLOB(v); SQInteger idx; if ((sq_gettype(v, 2) & SQOBJECT_NUMERIC) == 0) { sq_pushnull(v); return sq_throwobject(v); } sq_getinteger(v,2,&idx); if(idx < 0 || idx >= self->Len()) return sq_throwerror(v,_SC("index out of range")); sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]); return 1; } static SQInteger _blob__nexti(HSQUIRRELVM v) { SETUP_BLOB(v); if(sq_gettype(v,2) == OT_NULL) { sq_pushinteger(v, 0); return 1; } SQInteger idx; if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) { if(idx+1 < self->Len()) { sq_pushinteger(v, idx+1); return 1; } sq_pushnull(v); return 1; } return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type")); } static SQInteger _blob__typeof(HSQUIRRELVM v) { sq_pushstring(v,_SC("blob"),-1); return 1; } static SQInteger _blob_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size)) { SQBlob *self = (SQBlob*)p; self->~SQBlob(); sq_free(self,sizeof(SQBlob)); return 1; } static SQInteger _blob_constructor(HSQUIRRELVM v) { SQInteger nparam = sq_gettop(v); SQInteger size = 0; if(nparam == 2) { sq_getinteger(v, 2, &size); } if(size < 0) return sq_throwerror(v, _SC("cannot create blob with negative size")); //SQBlob *b = new SQBlob(size); SQBlob *b = new (sq_malloc(sizeof(SQBlob)))SQBlob(size); if(SQ_FAILED(sq_setinstanceup(v,1,b))) { b->~SQBlob(); sq_free(b,sizeof(SQBlob)); return sq_throwerror(v, _SC("cannot create blob")); } sq_setreleasehook(v,1,_blob_releasehook); return 0; } static SQInteger _blob__cloned(HSQUIRRELVM v) { SQBlob *other = NULL; { if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) return SQ_ERROR; } //SQBlob *thisone = new SQBlob(other->Len()); SQBlob *thisone = new (sq_malloc(sizeof(SQBlob)))SQBlob(other->Len()); memcpy(thisone->GetBuf(),other->GetBuf(),thisone->Len()); if(SQ_FAILED(sq_setinstanceup(v,1,thisone))) { thisone->~SQBlob(); sq_free(thisone,sizeof(SQBlob)); return sq_throwerror(v, _SC("cannot clone blob")); } sq_setreleasehook(v,1,_blob_releasehook); return 0; } #define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck} static const SQRegFunction _blob_methods[] = { _DECL_BLOB_FUNC(constructor,-1,_SC("xn")), _DECL_BLOB_FUNC(resize,2,_SC("xn")), _DECL_BLOB_FUNC(swap2,1,_SC("x")), _DECL_BLOB_FUNC(swap4,1,_SC("x")), _DECL_BLOB_FUNC(_set,3,_SC("xnn")), _DECL_BLOB_FUNC(_get,2,_SC("x.")), _DECL_BLOB_FUNC(_typeof,1,_SC("x")), _DECL_BLOB_FUNC(_nexti,2,_SC("x")), _DECL_BLOB_FUNC(_cloned,2,_SC("xx")), {NULL,(SQFUNCTION)0,0,NULL} }; //GLOBAL FUNCTIONS static SQInteger _g_blob_swap2(HSQUIRRELVM v) { SQInteger i; sq_getinteger(v,2,&i); unsigned short s = (unsigned short)i; sq_pushinteger(v, ((s << 8) | ((s >> 8) & 0x00FFu)) & 0xFFFFu); return 1; } static SQInteger _g_blob_swap4(HSQUIRRELVM v) { SQInteger i; sq_getinteger(v,2,&i); unsigned int t4 = (unsigned int)i; __swap_dword(&t4); sq_pushinteger(v,(SQInteger)t4); return 1; } static SQInteger _g_blob_swapfloat(HSQUIRRELVM v) { SQFloat f; sq_getfloat(v,2,&f); __swap_dword((unsigned int *)&f); sq_pushfloat(v,f); return 1; } #define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck} static const SQRegFunction bloblib_funcs[]={ _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")), _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")), _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")), {NULL,(SQFUNCTION)0,0,NULL} }; SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr) { SQBlob *blob; if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) return -1; *ptr = blob->GetBuf(); return SQ_OK; } SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx) { SQBlob *blob; if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) return -1; return blob->Len(); } SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size) { SQInteger top = sq_gettop(v); sq_pushregistrytable(v); sq_pushstring(v,_SC("std_blob"),-1); if(SQ_SUCCEEDED(sq_get(v,-2))) { sq_remove(v,-2); //removes the registry sq_push(v,1); // push the this sq_pushinteger(v,size); //size SQBlob *blob = NULL; if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse)) && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) { sq_remove(v,-2); return blob->GetBuf(); } } sq_settop(v,top); return NULL; } SQRESULT sqstd_register_bloblib(HSQUIRRELVM v) { return declare_stream(v,_SC("blob"),(SQUserPointer)SQSTD_BLOB_TYPE_TAG,_SC("std_blob"),_blob_methods,bloblib_funcs); } simutrans-124.3/src/squirrel/sqstdlib/sqstdblobimpl.h000066400000000000000000000043671474050137200230770ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTD_BLOBIMPL_H_ #define _SQSTD_BLOBIMPL_H_ struct SQBlob : public SQStream { SQBlob(SQInteger size) { _size = size; _allocated = size; _buf = (unsigned char *)sq_malloc(size); memset(_buf, 0, _size); _ptr = 0; _owns = true; } virtual ~SQBlob() { sq_free(_buf, _allocated); } SQInteger Write(void *buffer, SQInteger size) { if(!CanAdvance(size)) { GrowBufOf(_ptr + size - _size); } memcpy(&_buf[_ptr], buffer, size); _ptr += size; return size; } SQInteger Read(void *buffer,SQInteger size) { SQInteger n = size; if(!CanAdvance(size)) { if((_size - _ptr) > 0) n = _size - _ptr; else return 0; } memcpy(buffer, &_buf[_ptr], n); _ptr += n; return n; } bool Resize(SQInteger n) { if(!_owns) return false; if(n != _allocated) { unsigned char *newbuf = (unsigned char *)sq_malloc(n); memset(newbuf,0,n); if(_size > n) memcpy(newbuf,_buf,n); else memcpy(newbuf,_buf,_size); sq_free(_buf,_allocated); _buf=newbuf; _allocated = n; if(_size > _allocated) _size = _allocated; if(_ptr > _allocated) _ptr = _allocated; } return true; } bool GrowBufOf(SQInteger n) { bool ret = true; if(_size + n > _allocated) { if(_size + n > _size * 2) ret = Resize(_size + n); else ret = Resize(_size * 2); } _size = _size + n; return ret; } bool CanAdvance(SQInteger n) { if(_ptr+n>_size)return false; return true; } SQInteger Seek(SQInteger offset, SQInteger origin) { switch(origin) { case SQ_SEEK_SET: if(offset > _size || offset < 0) return -1; _ptr = offset; break; case SQ_SEEK_CUR: if(_ptr + offset > _size || _ptr + offset < 0) return -1; _ptr += offset; break; case SQ_SEEK_END: if(_size + offset > _size || _size + offset < 0) return -1; _ptr = _size + offset; break; default: return -1; } return 0; } bool IsValid() { return _size == 0 || _buf?true:false; } bool EOS() { return _ptr == _size; } SQInteger Flush() { return 0; } SQInteger Tell() { return _ptr; } SQInteger Len() { return _size; } SQUserPointer GetBuf(){ return _buf; } private: SQInteger _size; SQInteger _allocated; SQInteger _ptr; unsigned char *_buf; bool _owns; }; #endif simutrans-124.3/src/squirrel/sqstdlib/sqstdio.cc000066400000000000000000000272621474050137200220430ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include #include #include "../squirrel.h" #include "../sqstdio.h" #include "sqstdstream.h" #include "../../simutrans/sys/simsys.h" #define SQSTD_FILE_TYPE_TAG ((SQUnsignedInteger)(SQSTD_STREAM_TYPE_TAG | 0x00000001)) //basic API SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode) { #ifndef SQUNICODE return (SQFILE)fopen(filename,mode); #else return (SQFILE)_wfopen(filename,mode); #endif } SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file) { SQInteger ret = (SQInteger)fread(buffer,size,count,(FILE *)file); return ret; } SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file) { return (SQInteger)fwrite(buffer,size,count,(FILE *)file); } SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin) { SQInteger realorigin; switch(origin) { case SQ_SEEK_CUR: realorigin = SEEK_CUR; break; case SQ_SEEK_END: realorigin = SEEK_END; break; case SQ_SEEK_SET: realorigin = SEEK_SET; break; default: return -1; //failed } return fseek((FILE *)file,(long)offset,(int)realorigin); } SQInteger sqstd_ftell(SQFILE file) { return ftell((FILE *)file); } SQInteger sqstd_fflush(SQFILE file) { return fflush((FILE *)file); } SQInteger sqstd_fclose(SQFILE file) { return fclose((FILE *)file); } SQInteger sqstd_feof(SQFILE file) { return feof((FILE *)file); } //File struct SQFile : public SQStream { SQFile() { _handle = NULL; _owns = false;} SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;} virtual ~SQFile() { Close(); } bool Open(const SQChar *filename ,const SQChar *mode) { Close(); if( (_handle = sqstd_fopen(filename,mode)) ) { _owns = true; return true; } return false; } void Close() { if(_handle && _owns) { sqstd_fclose(_handle); _handle = NULL; _owns = false; } } SQInteger Read(void *buffer,SQInteger size) { return sqstd_fread(buffer,1,size,_handle); } SQInteger Write(void *buffer,SQInteger size) { return sqstd_fwrite(buffer,1,size,_handle); } SQInteger Flush() { return sqstd_fflush(_handle); } SQInteger Tell() { return sqstd_ftell(_handle); } SQInteger Len() { SQInteger prevpos=Tell(); Seek(0,SQ_SEEK_END); SQInteger size=Tell(); Seek(prevpos,SQ_SEEK_SET); return size; } SQInteger Seek(SQInteger offset, SQInteger origin) { return sqstd_fseek(_handle,offset,origin); } bool IsValid() { return _handle?true:false; } bool EOS() { return Tell()==Len()?true:false;} SQFILE GetHandle() {return _handle;} private: SQFILE _handle; bool _owns; }; static SQInteger _file__typeof(HSQUIRRELVM v) { sq_pushstring(v,_SC("file"),-1); return 1; } static SQInteger _file_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size)) { SQFile *self = (SQFile*)p; self->~SQFile(); sq_free(self,sizeof(SQFile)); return 1; } static SQInteger _file_constructor(HSQUIRRELVM v) { const SQChar *filename,*mode; bool owns = true; SQFile *f; SQFILE newf; if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) { sq_getstring(v, 2, &filename); sq_getstring(v, 3, &mode); newf = sqstd_fopen(filename, mode); if(!newf) return sq_throwerror(v, _SC("cannot open file")); } else if(sq_gettype(v,2) == OT_USERPOINTER) { owns = !(sq_gettype(v,3) == OT_NULL); sq_getuserpointer(v,2,&newf); } else { return sq_throwerror(v,_SC("wrong parameter")); } f = new (sq_malloc(sizeof(SQFile)))SQFile(newf,owns); if(SQ_FAILED(sq_setinstanceup(v,1,f))) { f->~SQFile(); sq_free(f,sizeof(SQFile)); return sq_throwerror(v, _SC("cannot create blob with negative size")); } sq_setreleasehook(v,1,_file_releasehook); return 0; } static SQInteger _file_close(HSQUIRRELVM v) { SQFile *self = NULL; if(SQ_SUCCEEDED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_FILE_TYPE_TAG)) && self != NULL) { self->Close(); } return 0; } //bindings #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck} static const SQRegFunction _file_methods[] = { _DECL_FILE_FUNC(constructor,3,_SC("x")), _DECL_FILE_FUNC(_typeof,1,_SC("x")), _DECL_FILE_FUNC(close,1,_SC("x")), {NULL,(SQFUNCTION)0,0,NULL} }; SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own) { SQInteger top = sq_gettop(v); sq_pushregistrytable(v); sq_pushstring(v,_SC("std_file"),-1); if(SQ_SUCCEEDED(sq_get(v,-2))) { sq_remove(v,-2); //removes the registry sq_pushroottable(v); // push the this sq_pushuserpointer(v,file); //file if(own){ sq_pushinteger(v,1); //true } else{ sq_pushnull(v); //false } if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) { sq_remove(v,-2); return SQ_OK; } } sq_settop(v,top); return SQ_ERROR; } SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file) { SQFile *fileobj = NULL; if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) { *file = fileobj->GetHandle(); return SQ_OK; } return sq_throwerror(v,_SC("not a file")); } #define IO_BUFFER_SIZE 2048 struct IOBuffer { unsigned char buffer[IO_BUFFER_SIZE]; SQInteger size; SQInteger ptr; SQFILE file; }; SQInteger _read_byte(IOBuffer *iobuffer) { if(iobuffer->ptr < iobuffer->size) { SQInteger ret = iobuffer->buffer[iobuffer->ptr]; iobuffer->ptr++; return ret; } else { if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 ) { SQInteger ret = iobuffer->buffer[0]; iobuffer->ptr = 1; return ret; } } return 0; } SQInteger _read_two_bytes(IOBuffer *iobuffer) { if(iobuffer->ptr < iobuffer->size) { if(iobuffer->size < 2) return 0; SQInteger ret = *((const wchar_t*)&iobuffer->buffer[iobuffer->ptr]); iobuffer->ptr += 2; return ret; } else { if( (iobuffer->size = sqstd_fread(iobuffer->buffer,1,IO_BUFFER_SIZE,iobuffer->file )) > 0 ) { if(iobuffer->size < 2) return 0; SQInteger ret = *((const wchar_t*)&iobuffer->buffer[0]); iobuffer->ptr = 2; return ret; } } return 0; } static SQInteger _io_file_lexfeed_PLAIN(SQUserPointer iobuf) { IOBuffer *iobuffer = (IOBuffer *)iobuf; return _read_byte(iobuffer); } #ifdef SQUNICODE static SQInteger _io_file_lexfeed_UTF8(SQUserPointer iobuf) { IOBuffer *iobuffer = (IOBuffer *)iobuf; #define READ(iobuf) \ if((inchar = (unsigned char)_read_byte(iobuf)) == 0) \ return 0; static const SQInteger utf8_lengths[16] = { 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */ 0,0,0,0, /* 1000 to 1011 : not valid */ 2,2, /* 1100, 1101 : 2 bytes */ 3, /* 1110 : 3 bytes */ 4 /* 1111 :4 bytes */ }; static const unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07}; unsigned char inchar; SQInteger c = 0; READ(iobuffer); c = inchar; // if(c >= 0x80) { SQInteger tmp; SQInteger codelen = utf8_lengths[c>>4]; if(codelen == 0) return 0; //"invalid UTF-8 stream"; tmp = c&byte_masks[codelen]; for(SQInteger n = 0; n < codelen-1; n++) { tmp<<=6; READ(iobuffer); tmp |= inchar & 0x3F; } c = tmp; } return c; } #endif static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer iobuf) { SQInteger ret; IOBuffer *iobuffer = (IOBuffer *)iobuf; if( (ret = _read_two_bytes(iobuffer)) > 0 ) return ret; return 0; } static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer iobuf) { SQInteger c; IOBuffer *iobuffer = (IOBuffer *)iobuf; if( (c = _read_two_bytes(iobuffer)) > 0 ) { c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00); return c; } return 0; } SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size) { SQInteger ret; if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret; return -1; } SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size) { return sqstd_fwrite(p,1,size,(SQFILE)file); } SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror) { SQFILE file = sqstd_fopen(filename,_SC("rb")); SQInteger ret; unsigned short us; unsigned char uc; SQLEXREADFUNC func = _io_file_lexfeed_PLAIN; if(file){ ret = sqstd_fread(&us,1,2,file); if(ret != 2) { //probably an empty file us = 0; } if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE sqstd_fseek(file,0,SQ_SEEK_SET); if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) { sqstd_fclose(file); return SQ_OK; } } else { //SCRIPT switch(us) { //gotta swap the next 2 lines on BIG endian machines case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian; case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian; case 0xBBEF: if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) { sqstd_fclose(file); return sq_throwerror(v,_SC("io error")); } if(uc != 0xBF) { sqstd_fclose(file); return sq_throwerror(v,_SC("Unrecognized encoding")); } #ifdef SQUNICODE func = _io_file_lexfeed_UTF8; #else func = _io_file_lexfeed_PLAIN; #endif break;//UTF-8 ; default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii } IOBuffer buffer; buffer.ptr = 0; buffer.size = 0; buffer.file = file; if(SQ_SUCCEEDED(sq_compile(v,func,&buffer,filename,printerror))){ sqstd_fclose(file); return SQ_OK; } } sqstd_fclose(file); return SQ_ERROR; } return sq_throwerror(v,_SC("cannot open the file")); } SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror) { //at least one entry must exist in order for us to push it as the environment if(sq_gettop(v) == 0) return sq_throwerror(v,_SC("environment table expected")); if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) { sq_push(v,-2); if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) { sq_remove(v,retval?-2:-1); //removes the closure return 1; } sq_pop(v,1); //removes the closure } return SQ_ERROR; } SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename) { SQFILE file = sqstd_fopen(filename,_SC("wb+")); if(!file) return sq_throwerror(v,_SC("cannot open the file")); if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) { sqstd_fclose(file); return SQ_OK; } sqstd_fclose(file); return SQ_ERROR; //forward the error } SQInteger _g_io_loadfile(HSQUIRRELVM v) { const SQChar *filename; SQBool printerror = SQFalse; sq_getstring(v,2,&filename); if(sq_gettop(v) >= 3) { sq_getbool(v,3,&printerror); } if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) return 1; return SQ_ERROR; //propagates the error } SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v) { const SQChar *filename; sq_getstring(v,2,&filename); if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename))) return 1; return SQ_ERROR; //propagates the error } SQInteger _g_io_dofile(HSQUIRRELVM v) { const SQChar *filename; SQBool printerror = SQFalse; sq_getstring(v,2,&filename); if(sq_gettop(v) >= 3) { sq_getbool(v,3,&printerror); } sq_push(v,1); //repush the this if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror))) return 1; return SQ_ERROR; //propagates the error } #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck} static const SQRegFunction iolib_funcs[]={ _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")), _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")), _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")), {NULL,(SQFUNCTION)0,0,NULL} }; SQRESULT sqstd_register_iolib(HSQUIRRELVM v) { SQInteger top = sq_gettop(v); //create delegate declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs); sq_pushstring(v,_SC("stdout"),-1); sqstd_createfile(v,stdout,SQFalse); sq_newslot(v,-3,SQFalse); sq_pushstring(v,_SC("stdin"),-1); sqstd_createfile(v,stdin,SQFalse); sq_newslot(v,-3,SQFalse); sq_pushstring(v,_SC("stderr"),-1); sqstd_createfile(v,stderr,SQFalse); sq_newslot(v,-3,SQFalse); sq_settop(v,top); return SQ_OK; } simutrans-124.3/src/squirrel/sqstdlib/sqstdmath.cc000066400000000000000000000050641474050137200223610ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "../squirrel.h" #include #include #include "../sqstdmath.h" #define SINGLE_ARG_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ SQFloat f; \ sq_getfloat(v,2,&f); \ sq_pushfloat(v,(SQFloat)_funcname(f)); \ return 1; \ } #define TWO_ARGS_FUNC(_funcname) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ SQFloat p1,p2; \ sq_getfloat(v,2,&p1); \ sq_getfloat(v,3,&p2); \ sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ return 1; \ } static SQInteger math_srand(HSQUIRRELVM v) { SQInteger i; if(SQ_FAILED(sq_getinteger(v,2,&i))) return sq_throwerror(v,_SC("invalid param")); srand((unsigned int)i); return 0; } static SQInteger math_rand(HSQUIRRELVM v) { sq_pushinteger(v,rand()); return 1; } static SQInteger math_abs(HSQUIRRELVM v) { SQInteger n; sq_getinteger(v,2,&n); sq_pushinteger(v,(SQInteger)abs((int)n)); return 1; } SINGLE_ARG_FUNC(sqrt) SINGLE_ARG_FUNC(fabs) SINGLE_ARG_FUNC(sin) SINGLE_ARG_FUNC(cos) SINGLE_ARG_FUNC(asin) SINGLE_ARG_FUNC(acos) SINGLE_ARG_FUNC(log) SINGLE_ARG_FUNC(log10) SINGLE_ARG_FUNC(tan) SINGLE_ARG_FUNC(atan) TWO_ARGS_FUNC(atan2) TWO_ARGS_FUNC(pow) SINGLE_ARG_FUNC(floor) SINGLE_ARG_FUNC(ceil) SINGLE_ARG_FUNC(exp) #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name),math_##name,nparams,tycheck} static const SQRegFunction mathlib_funcs[] = { _DECL_FUNC(sqrt,2,_SC(".n")), _DECL_FUNC(sin,2,_SC(".n")), _DECL_FUNC(cos,2,_SC(".n")), _DECL_FUNC(asin,2,_SC(".n")), _DECL_FUNC(acos,2,_SC(".n")), _DECL_FUNC(log,2,_SC(".n")), _DECL_FUNC(log10,2,_SC(".n")), _DECL_FUNC(tan,2,_SC(".n")), _DECL_FUNC(atan,2,_SC(".n")), _DECL_FUNC(atan2,3,_SC(".nn")), _DECL_FUNC(pow,3,_SC(".nn")), _DECL_FUNC(floor,2,_SC(".n")), _DECL_FUNC(ceil,2,_SC(".n")), _DECL_FUNC(exp,2,_SC(".n")), _DECL_FUNC(srand,2,_SC(".n")), _DECL_FUNC(rand,1,NULL), _DECL_FUNC(fabs,2,_SC(".n")), _DECL_FUNC(abs,2,_SC(".n")), {NULL,(SQFUNCTION)0,0,NULL} }; #undef _DECL_FUNC #ifndef M_PI #define M_PI (3.14159265358979323846) #endif SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) { SQInteger i=0; while(mathlib_funcs[i].name!=0) { sq_pushstring(v,mathlib_funcs[i].name,-1); sq_newclosure(v,mathlib_funcs[i].f,0); sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); sq_newslot(v,-3,SQFalse); i++; } sq_pushstring(v,_SC("RAND_MAX"),-1); sq_pushinteger(v,RAND_MAX); sq_newslot(v,-3,SQFalse); sq_pushstring(v,_SC("PI"),-1); sq_pushfloat(v,(SQFloat)M_PI); sq_newslot(v,-3,SQFalse); return SQ_OK; } simutrans-124.3/src/squirrel/sqstdlib/sqstdrex.cc000066400000000000000000000435731474050137200222350ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "../squirrel.h" #include #include #include #include "../sqstdstring.h" #ifdef _DEBUG #include static const SQChar *g_nnames[] = { _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"), _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"), _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"), _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB"),_SC("OP_MB") }; #endif #define OP_GREEDY (MAX_CHAR+1) // * + ? {n} #define OP_OR (MAX_CHAR+2) #define OP_EXPR (MAX_CHAR+3) //parentesis () #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) #define OP_DOT (MAX_CHAR+5) #define OP_CLASS (MAX_CHAR+6) #define OP_CCLASS (MAX_CHAR+7) #define OP_NCLASS (MAX_CHAR+8) //negates class the [^ #define OP_RANGE (MAX_CHAR+9) #define OP_CHAR (MAX_CHAR+10) #define OP_EOL (MAX_CHAR+11) #define OP_BOL (MAX_CHAR+12) #define OP_WB (MAX_CHAR+13) #define OP_MB (MAX_CHAR+14) //match balanced #define SQREX_SYMBOL_ANY_CHAR ('.') #define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') #define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') #define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') #define SQREX_SYMBOL_BRANCH ('|') #define SQREX_SYMBOL_END_OF_STRING ('$') #define SQREX_SYMBOL_BEGINNING_OF_STRING ('^') #define SQREX_SYMBOL_ESCAPE_CHAR ('\\') typedef int SQRexNodeType; typedef struct tagSQRexNode{ SQRexNodeType type; SQInteger left; SQInteger right; SQInteger next; }SQRexNode; struct SQRex{ const SQChar *_eol; const SQChar *_bol; const SQChar *_p; SQInteger _first; SQInteger _op; SQRexNode *_nodes; SQInteger _nallocated; SQInteger _nsize; SQInteger _nsubexpr; SQRexMatch *_matches; SQInteger _currsubexp; void *_jmpbuf; const SQChar **_error; }; static SQInteger sqstd_rex_list(SQRex *exp); static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) { SQRexNode n; n.type = type; n.next = n.right = n.left = -1; if(type == OP_EXPR) n.right = exp->_nsubexpr++; if(exp->_nallocated < (exp->_nsize + 1)) { SQInteger oldsize = exp->_nallocated; exp->_nallocated *= 2; exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); } exp->_nodes[exp->_nsize++] = n; SQInteger newid = exp->_nsize - 1; return (SQInteger)newid; } static void sqstd_rex_error(SQRex *exp,const SQChar *error) { if(exp->_error) *exp->_error = error; longjmp(*((jmp_buf*)exp->_jmpbuf),-1); } static void sqstd_rex_expect(SQRex *exp, SQInteger n){ if((*exp->_p) != n) sqstd_rex_error(exp, _SC("expected paren")); exp->_p++; } static SQChar sqstd_rex_escapechar(SQRex *exp) { if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ exp->_p++; switch(*exp->_p) { case 'v': exp->_p++; return '\v'; case 'n': exp->_p++; return '\n'; case 't': exp->_p++; return '\t'; case 'r': exp->_p++; return '\r'; case 'f': exp->_p++; return '\f'; default: return (*exp->_p++); } } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,_SC("letter expected")); return (*exp->_p++); } static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) { SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); exp->_nodes[n].left = classid; return n; } static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) { SQChar t; if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { exp->_p++; switch(*exp->_p) { case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); case 'a': case 'A': case 'w': case 'W': case 's': case 'S': case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': case 'p': case 'P': case 'l': case 'u': { t = *exp->_p; exp->_p++; return sqstd_rex_charclass(exp,t); } case 'm': { SQChar cb, ce; //cb = character begin match ce = character end match cb = *++exp->_p; //skip 'm' ce = *++exp->_p; exp->_p++; //points to the next char to be parsed if ((!cb) || (!ce)) sqstd_rex_error(exp,_SC("balanced chars expected")); if ( cb == ce ) sqstd_rex_error(exp,_SC("open/close char can't be the same")); SQInteger node = sqstd_rex_newnode(exp,OP_MB); exp->_nodes[node].left = cb; exp->_nodes[node].right = ce; return node; } case 0: sqstd_rex_error(exp,_SC("letter expected for argument of escape sequence")); break; case 'b': case 'B': if(!isclass) { SQInteger node = sqstd_rex_newnode(exp,OP_WB); exp->_nodes[node].left = *exp->_p; exp->_p++; return node; } //else default default: t = *exp->_p; exp->_p++; return sqstd_rex_newnode(exp,t); } } else if(!scisprint(*exp->_p)) { sqstd_rex_error(exp,_SC("letter expected")); } t = *exp->_p; exp->_p++; return sqstd_rex_newnode(exp,t); } static SQInteger sqstd_rex_class(SQRex *exp) { SQInteger ret = -1; SQInteger first = -1,chain; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ ret = sqstd_rex_newnode(exp,OP_NCLASS); exp->_p++; }else ret = sqstd_rex_newnode(exp,OP_CLASS); if(*exp->_p == ']') sqstd_rex_error(exp,_SC("empty class")); chain = ret; while(*exp->_p != ']' && exp->_p != exp->_eol) { if(*exp->_p == '-' && first != -1){ SQInteger r; if(*exp->_p++ == ']') sqstd_rex_error(exp,_SC("unfinished range")); r = sqstd_rex_newnode(exp,OP_RANGE); if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,_SC("invalid range")); if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,_SC("cannot use character classes in ranges")); exp->_nodes[r].left = exp->_nodes[first].type; SQInteger t = sqstd_rex_escapechar(exp); exp->_nodes[r].right = t; exp->_nodes[chain].next = r; chain = r; first = -1; } else{ if(first!=-1){ SQInteger c = first; exp->_nodes[chain].next = c; chain = c; first = sqstd_rex_charnode(exp,SQTrue); } else{ first = sqstd_rex_charnode(exp,SQTrue); } } } if(first!=-1){ SQInteger c = first; exp->_nodes[chain].next = c; } /* hack? */ exp->_nodes[ret].left = exp->_nodes[ret].next; exp->_nodes[ret].next = -1; return ret; } static SQInteger sqstd_rex_parsenumber(SQRex *exp) { SQInteger ret = *exp->_p-'0'; SQInteger positions = 10; exp->_p++; while(isdigit(*exp->_p)) { ret = ret*10+(*exp->_p++-'0'); if(positions==1000000000) sqstd_rex_error(exp,_SC("overflow in numeric constant")); positions *= 10; }; return ret; } static SQInteger sqstd_rex_element(SQRex *exp) { SQInteger ret = -1; switch(*exp->_p) { case '(': { SQInteger expr; exp->_p++; if(*exp->_p =='?') { exp->_p++; sqstd_rex_expect(exp,':'); expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); } else expr = sqstd_rex_newnode(exp,OP_EXPR); SQInteger newn = sqstd_rex_list(exp); exp->_nodes[expr].left = newn; ret = expr; sqstd_rex_expect(exp,')'); } break; case '[': exp->_p++; ret = sqstd_rex_class(exp); sqstd_rex_expect(exp,']'); break; case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; default: ret = sqstd_rex_charnode(exp,SQFalse); break; } SQBool isgreedy = SQFalse; unsigned short p0 = 0, p1 = 0; switch(*exp->_p){ case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break; case '{': exp->_p++; if(!isdigit(*exp->_p)) sqstd_rex_error(exp,_SC("number expected")); p0 = (unsigned short)sqstd_rex_parsenumber(exp); /*******************************/ switch(*exp->_p) { case '}': p1 = p0; exp->_p++; break; case ',': exp->_p++; p1 = 0xFFFF; if(isdigit(*exp->_p)){ p1 = (unsigned short)sqstd_rex_parsenumber(exp); } sqstd_rex_expect(exp,'}'); break; default: sqstd_rex_error(exp,_SC(", or } expected")); } /*******************************/ isgreedy = SQTrue; break; } if(isgreedy) { SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); exp->_nodes[nnode].left = ret; exp->_nodes[nnode].right = ((p0)<<16)|p1; ret = nnode; } if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { SQInteger nnode = sqstd_rex_element(exp); exp->_nodes[ret].next = nnode; } return ret; } static SQInteger sqstd_rex_list(SQRex *exp) { SQInteger ret=-1,e; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { exp->_p++; ret = sqstd_rex_newnode(exp,OP_BOL); } e = sqstd_rex_element(exp); if(ret != -1) { exp->_nodes[ret].next = e; } else ret = e; if(*exp->_p == SQREX_SYMBOL_BRANCH) { SQInteger temp,tright; exp->_p++; temp = sqstd_rex_newnode(exp,OP_OR); exp->_nodes[temp].left = ret; tright = sqstd_rex_list(exp); exp->_nodes[temp].right = tright; ret = temp; } return ret; } static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) { switch(cclass) { case 'a': return isalpha(c)?SQTrue:SQFalse; case 'A': return !isalpha(c)?SQTrue:SQFalse; case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; case 's': return isspace(c)?SQTrue:SQFalse; case 'S': return !isspace(c)?SQTrue:SQFalse; case 'd': return isdigit(c)?SQTrue:SQFalse; case 'D': return !isdigit(c)?SQTrue:SQFalse; case 'x': return isxdigit(c)?SQTrue:SQFalse; case 'X': return !isxdigit(c)?SQTrue:SQFalse; case 'c': return iscntrl(c)?SQTrue:SQFalse; case 'C': return !iscntrl(c)?SQTrue:SQFalse; case 'p': return ispunct(c)?SQTrue:SQFalse; case 'P': return !ispunct(c)?SQTrue:SQFalse; case 'l': return islower(c)?SQTrue:SQFalse; case 'u': return isupper(c)?SQTrue:SQFalse; } return SQFalse; /*cannot happen*/ } static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQChar c) { do { switch(node->type) { case OP_RANGE: if(c >= node->left && c <= node->right) return SQTrue; break; case OP_CCLASS: if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; break; default: if(c == node->type)return SQTrue; } } while((node->next != -1) && (node = &exp->_nodes[node->next])); return SQFalse; } static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next) { SQRexNodeType type = node->type; switch(type) { case OP_GREEDY: { //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; SQRexNode *greedystop = NULL; SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; const SQChar *s=str, *good = str; if(node->next != -1) { greedystop = &exp->_nodes[node->next]; } else { greedystop = next; } while((nmaches == 0xFFFF || nmaches < p1)) { const SQChar *stop; if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) break; nmaches++; good=s; if(greedystop) { //checks that 0 matches satisfy the expression(if so skips) //if not would always stop(for instance if is a '?') if(greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) { SQRexNode *gnext = NULL; if(greedystop->next != -1) { gnext = &exp->_nodes[greedystop->next]; }else if(next && next->next != -1){ gnext = &exp->_nodes[next->next]; } stop = sqstd_rex_matchnode(exp,greedystop,s,gnext); if(stop) { //if satisfied stop it if(p0 == p1 && p0 == nmaches) break; else if(nmaches >= p0 && p1 == 0xFFFF) break; else if(nmaches >= p0 && nmaches <= p1) break; } } } if(s >= exp->_eol) break; } if(p0 == p1 && p0 == nmaches) return good; else if(nmaches >= p0 && p1 == 0xFFFF) return good; else if(nmaches >= p0 && nmaches <= p1) return good; return NULL; } case OP_OR: { const SQChar *asd = str; SQRexNode *temp=&exp->_nodes[node->left]; while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } asd = str; temp = &exp->_nodes[node->right]; while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } return NULL; break; } case OP_EXPR: case OP_NOCAPEXPR:{ SQRexNode *n = &exp->_nodes[node->left]; const SQChar *cur = str; SQInteger capture = -1; if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { capture = exp->_currsubexp; exp->_matches[capture].begin = cur; exp->_currsubexp++; } SQInteger tempcap = exp->_currsubexp; do { SQRexNode *subnext = NULL; if(n->next != -1) { subnext = &exp->_nodes[n->next]; }else { subnext = next; } if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) { if(capture != -1){ exp->_matches[capture].begin = 0; exp->_matches[capture].len = 0; } return NULL; } } while((n->next != -1) && (n = &exp->_nodes[n->next])); exp->_currsubexp = tempcap; if(capture != -1) exp->_matches[capture].len = cur - exp->_matches[capture].begin; return cur; } case OP_WB: if((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str-1))) || (!isspace(*str) && isspace(*(str+1))) || (isspace(*str) && !isspace(*(str+1))) ) { return (node->left == 'b')?str:NULL; } return (node->left == 'b')?NULL:str; case OP_BOL: if(str == exp->_bol) return str; return NULL; case OP_EOL: if(str == exp->_eol) return str; return NULL; case OP_DOT:{ if (str == exp->_eol) return NULL; str++; } return str; case OP_NCLASS: case OP_CLASS: if (str == exp->_eol) return NULL; if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { str++; return str; } return NULL; case OP_CCLASS: if (str == exp->_eol) return NULL; if(sqstd_rex_matchcclass(node->left,*str)) { str++; return str; } return NULL; case OP_MB: { SQInteger cb = node->left; //char that opens a balanced expression if(*str != cb) return NULL; // string doesnt start with open char SQInteger ce = node->right; //char that closes a balanced expression SQInteger cont = 1; const SQChar *streol = exp->_eol; while (++str < streol) { if (*str == ce) { if (--cont == 0) { return ++str; } } else if (*str == cb) cont++; } } return NULL; // string ends out of balance default: /* char */ if (str == exp->_eol) return NULL; if(*str != node->type) return NULL; str++; return str; } return NULL; } /* public api */ SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) { SQRex * volatile exp = (SQRex *)sq_malloc(sizeof(SQRex)); // "volatile" is needed for setjmp() exp->_eol = exp->_bol = NULL; exp->_p = pattern; exp->_nallocated = (SQInteger)scstrlen(pattern) * sizeof(SQChar); exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); exp->_nsize = 0; exp->_matches = 0; exp->_nsubexpr = 0; exp->_first = sqstd_rex_newnode(exp,OP_EXPR); exp->_error = error; exp->_jmpbuf = sq_malloc(sizeof(jmp_buf)); if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { SQInteger res = sqstd_rex_list(exp); exp->_nodes[exp->_first].left = res; if(*exp->_p!='\0') sqstd_rex_error(exp,_SC("unexpected character")); #ifdef _DEBUG { SQInteger nsize,i; SQRexNode *t; nsize = exp->_nsize; t = &exp->_nodes[0]; scprintf(_SC("\n")); for(i = 0;i < nsize; i++) { if(exp->_nodes[i].type>MAX_CHAR) scprintf(_SC("[%02d] %10s "), (SQInt32)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); else scprintf(_SC("[%02d] %10c "), (SQInt32)i,exp->_nodes[i].type); scprintf(_SC("left %02d right %02d next %02d\n"), (SQInt32)exp->_nodes[i].left, (SQInt32)exp->_nodes[i].right, (SQInt32)exp->_nodes[i].next); } scprintf(_SC("\n")); } #endif exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); } else{ sqstd_rex_free(exp); return NULL; } return exp; } void sqstd_rex_free(SQRex *exp) { if(exp) { if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); if(exp->_jmpbuf) sq_free(exp->_jmpbuf,sizeof(jmp_buf)); if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); sq_free(exp,sizeof(SQRex)); } } SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) { const SQChar* res = NULL; exp->_bol = text; exp->_eol = text + scstrlen(text); exp->_currsubexp = 0; res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL); if(res == NULL || res != exp->_eol) return SQFalse; return SQTrue; } SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) { const SQChar *cur = NULL; SQInteger node = exp->_first; if(text_begin >= text_end) return SQFalse; exp->_bol = text_begin; exp->_eol = text_end; do { cur = text_begin; while(node != -1) { exp->_currsubexp = 0; cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL); if(!cur) break; node = exp->_nodes[node].next; } text_begin++; } while(cur == NULL && text_begin != text_end); if(cur == NULL) return SQFalse; --text_begin; if(out_begin) *out_begin = text_begin; if(out_end) *out_end = cur; return SQTrue; } SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) { return sqstd_rex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end); } SQInteger sqstd_rex_getsubexpcount(SQRex* exp) { return exp->_nsubexpr; } SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) { if( n<0 || n >= exp->_nsubexpr) return SQFalse; *subexp = exp->_matches[n]; return SQTrue; } simutrans-124.3/src/squirrel/sqstdlib/sqstdstream.cc000066400000000000000000000162521474050137200227240ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include #include #include #include #include "../squirrel.h" #include "../sqstdio.h" #include "../sqstdblob.h" #include "sqstdstream.h" #include "sqstdblobimpl.h" #define SETUP_STREAM(v) \ SQStream *self = NULL; \ if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \ return sq_throwerror(v,_SC("invalid type tag")); \ if(!self || !self->IsValid()) \ return sq_throwerror(v,_SC("the stream is invalid")); SQInteger _stream_readblob(HSQUIRRELVM v) { SETUP_STREAM(v); SQUserPointer data,blobp; SQInteger size,res; sq_getinteger(v,2,&size); if(size > self->Len()) { size = self->Len(); } data = sq_getscratchpad(v,size); res = self->Read(data,size); if(res <= 0) return sq_throwerror(v,_SC("no data left to read")); blobp = sqstd_createblob(v,res); memcpy(blobp,data,res); return 1; } #define SAFE_READN(ptr,len) { \ if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \ } SQInteger _stream_readn(HSQUIRRELVM v) { SETUP_STREAM(v); SQInteger format; sq_getinteger(v, 2, &format); switch(format) { case 'l': { SQInteger i; SAFE_READN(&i, sizeof(i)); sq_pushinteger(v, i); } break; case 'i': { SQInt32 i; SAFE_READN(&i, sizeof(i)); sq_pushinteger(v, i); } break; case 's': { short s; SAFE_READN(&s, sizeof(short)); sq_pushinteger(v, s); } break; case 'w': { unsigned short w; SAFE_READN(&w, sizeof(unsigned short)); sq_pushinteger(v, w); } break; case 'c': { char c; SAFE_READN(&c, sizeof(char)); sq_pushinteger(v, c); } break; case 'b': { unsigned char c; SAFE_READN(&c, sizeof(unsigned char)); sq_pushinteger(v, c); } break; case 'f': { float f; SAFE_READN(&f, sizeof(float)); sq_pushfloat(v, f); } break; case 'd': { double d; SAFE_READN(&d, sizeof(double)); sq_pushfloat(v, (SQFloat)d); } break; default: return sq_throwerror(v, _SC("invalid format")); } return 1; } SQInteger _stream_writeblob(HSQUIRRELVM v) { SQUserPointer data; SQInteger size; SETUP_STREAM(v); if(SQ_FAILED(sqstd_getblob(v,2,&data))) return sq_throwerror(v,_SC("invalid parameter")); size = sqstd_getblobsize(v,2); if(self->Write(data,size) != size) return sq_throwerror(v,_SC("io error")); sq_pushinteger(v,size); return 1; } SQInteger _stream_writen(HSQUIRRELVM v) { SETUP_STREAM(v); SQInteger format, ti; SQFloat tf; sq_getinteger(v, 3, &format); switch(format) { case 'l': { SQInteger i; sq_getinteger(v, 2, &ti); i = ti; self->Write(&i, sizeof(SQInteger)); } break; case 'i': { SQInt32 i; sq_getinteger(v, 2, &ti); i = (SQInt32)ti; self->Write(&i, sizeof(SQInt32)); } break; case 's': { short s; sq_getinteger(v, 2, &ti); s = (short)ti; self->Write(&s, sizeof(short)); } break; case 'w': { unsigned short w; sq_getinteger(v, 2, &ti); w = (unsigned short)ti; self->Write(&w, sizeof(unsigned short)); } break; case 'c': { char c; sq_getinteger(v, 2, &ti); c = (char)ti; self->Write(&c, sizeof(char)); } break; case 'b': { unsigned char b; sq_getinteger(v, 2, &ti); b = (unsigned char)ti; self->Write(&b, sizeof(unsigned char)); } break; case 'f': { float f; sq_getfloat(v, 2, &tf); f = (float)tf; self->Write(&f, sizeof(float)); } break; case 'd': { double d; sq_getfloat(v, 2, &tf); d = tf; self->Write(&d, sizeof(double)); } break; default: return sq_throwerror(v, _SC("invalid format")); } return 0; } SQInteger _stream_seek(HSQUIRRELVM v) { SETUP_STREAM(v); SQInteger offset, origin = SQ_SEEK_SET; sq_getinteger(v, 2, &offset); if(sq_gettop(v) > 2) { SQInteger t; sq_getinteger(v, 3, &t); switch(t) { case 'b': origin = SQ_SEEK_SET; break; case 'c': origin = SQ_SEEK_CUR; break; case 'e': origin = SQ_SEEK_END; break; default: return sq_throwerror(v,_SC("invalid origin")); } } sq_pushinteger(v, self->Seek(offset, origin)); return 1; } SQInteger _stream_tell(HSQUIRRELVM v) { SETUP_STREAM(v); sq_pushinteger(v, self->Tell()); return 1; } SQInteger _stream_len(HSQUIRRELVM v) { SETUP_STREAM(v); sq_pushinteger(v, self->Len()); return 1; } SQInteger _stream_flush(HSQUIRRELVM v) { SETUP_STREAM(v); if(!self->Flush()) sq_pushinteger(v, 1); else sq_pushnull(v); return 1; } SQInteger _stream_eos(HSQUIRRELVM v) { SETUP_STREAM(v); if(self->EOS()) sq_pushinteger(v, 1); else sq_pushnull(v); return 1; } SQInteger _stream__cloned(HSQUIRRELVM v) { return sq_throwerror(v,_SC("this object cannot be cloned")); } static const SQRegFunction _stream_methods[] = { _DECL_STREAM_FUNC(readblob,2,_SC("xn")), _DECL_STREAM_FUNC(readn,2,_SC("xn")), _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")), _DECL_STREAM_FUNC(writen,3,_SC("xnn")), _DECL_STREAM_FUNC(seek,-2,_SC("xnn")), _DECL_STREAM_FUNC(tell,1,_SC("x")), _DECL_STREAM_FUNC(len,1,_SC("x")), _DECL_STREAM_FUNC(eos,1,_SC("x")), _DECL_STREAM_FUNC(flush,1,_SC("x")), _DECL_STREAM_FUNC(_cloned,0,NULL), {NULL,(SQFUNCTION)0,0,NULL} }; void init_streamclass(HSQUIRRELVM v) { sq_pushregistrytable(v); sq_pushstring(v,_SC("std_stream"),-1); if(SQ_FAILED(sq_get(v,-2))) { sq_pushstring(v,_SC("std_stream"),-1); sq_newclass(v,SQFalse); sq_settypetag(v,-1,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)); SQInteger i = 0; while(_stream_methods[i].name != 0) { const SQRegFunction &f = _stream_methods[i]; sq_pushstring(v,f.name,-1); sq_newclosure(v,f.f,0); sq_setparamscheck(v,f.nparamscheck,f.typemask); sq_newslot(v,-3,SQFalse); i++; } sq_newslot(v,-3,SQFalse); sq_pushroottable(v); sq_pushstring(v,_SC("stream"),-1); sq_pushstring(v,_SC("std_stream"),-1); sq_get(v,-4); sq_newslot(v,-3,SQFalse); sq_pop(v,1); } else { sq_pop(v,1); //result } sq_pop(v,1); } SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals) { if(sq_gettype(v,-1) != OT_TABLE) return sq_throwerror(v,_SC("table expected")); SQInteger top = sq_gettop(v); //create delegate init_streamclass(v); sq_pushregistrytable(v); sq_pushstring(v,reg_name,-1); sq_pushstring(v,_SC("std_stream"),-1); if(SQ_SUCCEEDED(sq_get(v,-3))) { sq_newclass(v,SQTrue); sq_settypetag(v,-1,typetag); SQInteger i = 0; while(methods[i].name != 0) { const SQRegFunction &f = methods[i]; sq_pushstring(v,f.name,-1); sq_newclosure(v,f.f,0); sq_setparamscheck(v,f.nparamscheck,f.typemask); sq_setnativeclosurename(v,-1,f.name); sq_newslot(v,-3,SQFalse); i++; } sq_newslot(v,-3,SQFalse); sq_pop(v,1); i = 0; while(globals[i].name!=0) { const SQRegFunction &f = globals[i]; sq_pushstring(v,f.name,-1); sq_newclosure(v,f.f,0); sq_setparamscheck(v,f.nparamscheck,f.typemask); sq_setnativeclosurename(v,-1,f.name); sq_newslot(v,-3,SQFalse); i++; } //register the class in the target table sq_pushstring(v,name,-1); sq_pushregistrytable(v); sq_pushstring(v,reg_name,-1); sq_get(v,-2); sq_remove(v,-2); sq_newslot(v,-3,SQFalse); sq_settop(v,top); return SQ_OK; } sq_settop(v,top); return SQ_ERROR; } simutrans-124.3/src/squirrel/sqstdlib/sqstdstream.h000066400000000000000000000013741474050137200225650ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTD_STREAM_H_ #define _SQSTD_STREAM_H_ SQInteger _stream_readblob(HSQUIRRELVM v); SQInteger _stream_readline(HSQUIRRELVM v); SQInteger _stream_readn(HSQUIRRELVM v); SQInteger _stream_writeblob(HSQUIRRELVM v); SQInteger _stream_writen(HSQUIRRELVM v); SQInteger _stream_seek(HSQUIRRELVM v); SQInteger _stream_tell(HSQUIRRELVM v); SQInteger _stream_len(HSQUIRRELVM v); SQInteger _stream_eos(HSQUIRRELVM v); SQInteger _stream_flush(HSQUIRRELVM v); #define _DECL_STREAM_FUNC(name,nparams,typecheck) {_SC(#name),_stream_##name,nparams,typecheck} SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals); #endif simutrans-124.3/src/squirrel/sqstdlib/sqstdstring.cc000066400000000000000000000315301474050137200227330ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "../squirrel.h" #include "../sqstdstring.h" #include #include #include #include #include #include #define MAX_FORMAT_LEN 20 #define MAX_WFORMAT_LEN 3 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) static SQUserPointer rex_typetag = NULL; static SQBool isfmtchr(SQChar ch) { switch(ch) { case '-': case '+': case ' ': case '#': case '0': return SQTrue; } return SQFalse; } static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width) { SQChar *dummy; SQChar swidth[MAX_WFORMAT_LEN]; SQInteger wc = 0; SQInteger start = n; fmt[0] = '%'; while (isfmtchr(src[n])) n++; while (scisdigit(src[n])) { swidth[wc] = src[n]; n++; wc++; if(wc>=MAX_WFORMAT_LEN) return sq_throwerror(v,_SC("width format too long")); } swidth[wc] = '\0'; if(wc > 0) { width = scstrtol(swidth,&dummy,10); } else width = 0; if (src[n] == '.') { n++; wc = 0; while (scisdigit(src[n])) { swidth[wc] = src[n]; n++; wc++; if(wc>=MAX_WFORMAT_LEN) return sq_throwerror(v,_SC("precision format too long")); } swidth[wc] = '\0'; if(wc > 0) { width += scstrtol(swidth,&dummy,10); } } if (n-start > MAX_FORMAT_LEN ) return sq_throwerror(v,_SC("format too long")); memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); fmt[(n-start)+2] = '\0'; return n; } SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output) { const SQChar *format; SQChar *dest; SQChar fmt[MAX_FORMAT_LEN]; const SQRESULT res = sq_getstring(v,nformatstringidx,&format); if (SQ_FAILED(res)) { return res; // propagate the error } SQInteger format_size = sq_getsize(v,nformatstringidx); SQInteger allocated = (format_size+2)*sizeof(SQChar); dest = sq_getscratchpad(v,allocated); SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0; //while(format[n] != '\0') while(n < format_size) { if(format[n] != '%') { assert(i < allocated); dest[i++] = format[n]; n++; } else if(format[n+1] == '%') { //handles %% dest[i++] = '%'; n += 2; } else { n++; if( nparam > sq_gettop(v) ) return sq_throwerror(v,_SC("not enough parameters for the given format string")); n = validate_format(v,fmt,format,n,w); if(n < 0) return -1; SQInteger addlen = 0; SQInteger valtype = 0; const SQChar *ts = NULL; SQInteger ti = 0; SQFloat tf = 0; switch(format[n]) { case 's': if(SQ_FAILED(sq_getstring(v,nparam,&ts))) return sq_throwerror(v,_SC("string expected for the specified format")); addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); valtype = 's'; break; case 'i': case 'd': case 'o': case 'u': case 'x': case 'X': #ifdef _SQ64 { size_t flen = scstrlen(fmt); SQInteger fpos = flen - 1; SQChar f = fmt[fpos]; const SQChar *prec = (const SQChar *)_PRINT_INT_PREC; while(*prec != _SC('\0')) { fmt[fpos++] = *prec++; } fmt[fpos++] = f; fmt[fpos++] = _SC('\0'); } #endif case 'c': if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) return sq_throwerror(v,_SC("integer expected for the specified format")); addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); valtype = 'i'; break; case 'f': case 'g': case 'G': case 'e': case 'E': if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) return sq_throwerror(v,_SC("float expected for the specified format")); addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); valtype = 'f'; break; default: return sq_throwerror(v,_SC("invalid format")); } n++; allocated += addlen + sizeof(SQChar); dest = sq_getscratchpad(v,allocated); switch(valtype) { case 's': i += scsprintf(&dest[i],allocated,fmt,ts); break; case 'i': i += scsprintf(&dest[i],allocated,fmt,ti); break; case 'f': i += scsprintf(&dest[i],allocated,fmt,tf); break; }; nparam ++; } } *outlen = i; dest[i] = '\0'; *output = dest; return SQ_OK; } void sqstd_pushstringf(HSQUIRRELVM v,const SQChar *s,...) { SQInteger n=256; va_list args; begin: va_start(args,s); SQChar *b=sq_getscratchpad(v,n); SQInteger r=scvsprintf(b,n,s,args); va_end(args); if (r>=n) { n=r+1;//required+null goto begin; } else if (r<0) { sq_pushnull(v); } else { sq_pushstring(v,b,r); } } static SQInteger _string_printf(HSQUIRRELVM v) { SQChar *dest = NULL; SQInteger length = 0; if(SQ_FAILED(sqstd_format(v,2,&length,&dest))) return -1; SQPRINTFUNCTION printfunc = sq_getprintfunc(v); if(printfunc) printfunc(v,_SC("%s"),dest); return 0; } static SQInteger _string_format(HSQUIRRELVM v) { SQChar *dest = NULL; SQInteger length = 0; if(SQ_FAILED(sqstd_format(v,2,&length,&dest))) return -1; sq_pushstring(v,dest,length); return 1; } static void __strip_l(const SQChar *str,const SQChar **start) { const SQChar *t = str; while(((*t) != '\0') && scisspace(*t)){ t++; } *start = t; } static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end) { if(len == 0) { *end = str; return; } const SQChar *t = &str[len-1]; while(t >= str && scisspace(*t)) { t--; } *end = t + 1; } static SQInteger _string_strip(HSQUIRRELVM v) { const SQChar *str,*start,*end; sq_getstring(v,2,&str); SQInteger len = sq_getsize(v,2); __strip_l(str,&start); __strip_r(str,len,&end); sq_pushstring(v,start,end - start); return 1; } static SQInteger _string_lstrip(HSQUIRRELVM v) { const SQChar *str,*start; sq_getstring(v,2,&str); __strip_l(str,&start); sq_pushstring(v,start,-1); return 1; } static SQInteger _string_rstrip(HSQUIRRELVM v) { const SQChar *str,*end; sq_getstring(v,2,&str); SQInteger len = sq_getsize(v,2); __strip_r(str,len,&end); sq_pushstring(v,str,end - str); return 1; } static SQInteger _string_split(HSQUIRRELVM v) { const SQChar *str,*seps; SQInteger sepsize; SQBool skipempty = SQFalse; sq_getstring(v,2,&str); sq_getstringandsize(v,3,&seps,&sepsize); if(sepsize == 0) return sq_throwerror(v,_SC("empty separators string")); if(sq_gettop(v)>3) { sq_getbool(v,4,&skipempty); } const SQChar *start = str; const SQChar *end = str; sq_newarray(v,0); while(*end != '\0') { SQChar cur = *end; for(SQInteger i = 0; i < sepsize; i++) { if(cur == seps[i]) { if(!skipempty || (end != start)) { sq_pushstring(v,start,end-start); sq_arrayappend(v,-2); } start = end + 1; break; } } end++; } if(end != start) { sq_pushstring(v,start,end-start); sq_arrayappend(v,-2); } return 1; } static SQInteger _string_escape(HSQUIRRELVM v) { const SQChar *str; SQChar *dest,*resstr; SQInteger size; sq_getstring(v,2,&str); size = sq_getsize(v,2); if(size == 0) { sq_push(v,2); return 1; } #ifdef SQUNICODE #if WCHAR_SIZE == 2 const SQChar *escpat = _SC("\\x%04x"); const SQInteger maxescsize = 6; #else //WCHAR_SIZE == 4 const SQChar *escpat = _SC("\\x%08x"); const SQInteger maxescsize = 10; #endif #else const SQChar *escpat = _SC("\\x%02x"); const SQInteger maxescsize = 4; #endif SQInteger destcharsize = (size * maxescsize); //assumes every char could be escaped resstr = dest = (SQChar *)sq_getscratchpad(v,destcharsize * sizeof(SQChar)); SQChar c; SQChar escch; SQInteger escaped = 0; for(int n = 0; n < size; n++){ c = *str++; escch = 0; if(scisprint(c) || c == 0) { switch(c) { case '\a': escch = 'a'; break; case '\b': escch = 'b'; break; case '\t': escch = 't'; break; case '\n': escch = 'n'; break; case '\v': escch = 'v'; break; case '\f': escch = 'f'; break; case '\r': escch = 'r'; break; case '\\': escch = '\\'; break; case '\"': escch = '\"'; break; case '\'': escch = '\''; break; case 0: escch = '0'; break; } if(escch) { *dest++ = '\\'; *dest++ = escch; escaped++; } else { *dest++ = c; } } else { dest += scsprintf(dest, destcharsize, escpat, c); escaped++; } } if(escaped) { sq_pushstring(v,resstr,dest - resstr); } else { sq_push(v,2); //nothing escaped } return 1; } static SQInteger _string_startswith(HSQUIRRELVM v) { const SQChar *str,*cmp; sq_getstring(v,2,&str); sq_getstring(v,3,&cmp); SQInteger len = sq_getsize(v,2); SQInteger cmplen = sq_getsize(v,3); SQBool ret = SQFalse; if(cmplen <= len) { ret = memcmp(str,cmp,sq_rsl(cmplen)) == 0 ? SQTrue : SQFalse; } sq_pushbool(v,ret); return 1; } static SQInteger _string_endswith(HSQUIRRELVM v) { const SQChar *str,*cmp; sq_getstring(v,2,&str); sq_getstring(v,3,&cmp); SQInteger len = sq_getsize(v,2); SQInteger cmplen = sq_getsize(v,3); SQBool ret = SQFalse; if(cmplen <= len) { ret = memcmp(&str[len - cmplen],cmp,sq_rsl(cmplen)) == 0 ? SQTrue : SQFalse; } sq_pushbool(v,ret); return 1; } #define SETUP_REX(v) \ SQRex *self = NULL; \ if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer *)&self,rex_typetag))) { \ return sq_throwerror(v,_SC("invalid type tag")); \ } static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size)) { SQRex *self = ((SQRex *)p); sqstd_rex_free(self); return 1; } static SQInteger _regexp_match(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str; sq_getstring(v,2,&str); if(sqstd_rex_match(self,str) == SQTrue) { sq_pushbool(v,SQTrue); return 1; } sq_pushbool(v,SQFalse); return 1; } static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) { sq_newtable(v); sq_pushstring(v,_SC("begin"),-1); sq_pushinteger(v,begin - str); sq_rawset(v,-3); sq_pushstring(v,_SC("end"),-1); sq_pushinteger(v,end - str); sq_rawset(v,-3); } static SQInteger _regexp_search(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str,*begin,*end; SQInteger start = 0; sq_getstring(v,2,&str); if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { _addrexmatch(v,str,begin,end); return 1; } return 0; } static SQInteger _regexp_capture(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str,*begin,*end; SQInteger start = 0; sq_getstring(v,2,&str); if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { SQInteger n = sqstd_rex_getsubexpcount(self); SQRexMatch match; sq_newarray(v,0); for(SQInteger i = 0;i < n; i++) { sqstd_rex_getsubexp(self,i,&match); if(match.len > 0) _addrexmatch(v,str,match.begin,match.begin+match.len); else _addrexmatch(v,str,str,str); //empty match sq_arrayappend(v,-2); } return 1; } return 0; } static SQInteger _regexp_subexpcount(HSQUIRRELVM v) { SETUP_REX(v); sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); return 1; } static SQInteger _regexp_constructor(HSQUIRRELVM v) { SQRex *self = NULL; if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, rex_typetag))) { return sq_throwerror(v, _SC("invalid type tag")); } if (self != NULL) { return sq_throwerror(v, _SC("invalid regexp object")); } const SQChar *error,*pattern; sq_getstring(v,2,&pattern); SQRex *rex = sqstd_rex_compile(pattern,&error); if(!rex) return sq_throwerror(v,error); sq_setinstanceup(v,1,rex); sq_setreleasehook(v,1,_rexobj_releasehook); return 0; } static SQInteger _regexp__typeof(HSQUIRRELVM v) { sq_pushstring(v,_SC("regexp"),-1); return 1; } #define _DECL_REX_FUNC(name,nparams,pmask) {_SC(#name),_regexp_##name,nparams,pmask} static const SQRegFunction rexobj_funcs[]={ _DECL_REX_FUNC(constructor,2,_SC(".s")), _DECL_REX_FUNC(search,-2,_SC("xsn")), _DECL_REX_FUNC(match,2,_SC("xs")), _DECL_REX_FUNC(capture,-2,_SC("xsn")), _DECL_REX_FUNC(subexpcount,1,_SC("x")), _DECL_REX_FUNC(_typeof,1,_SC("x")), {NULL,(SQFUNCTION)0,0,NULL} }; #undef _DECL_REX_FUNC #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_string_##name,nparams,pmask} static const SQRegFunction stringlib_funcs[]={ _DECL_FUNC(format,-2,_SC(".s")), _DECL_FUNC(printf,-2,_SC(".s")), _DECL_FUNC(strip,2,_SC(".s")), _DECL_FUNC(lstrip,2,_SC(".s")), _DECL_FUNC(rstrip,2,_SC(".s")), _DECL_FUNC(split,-3,_SC(".ssb")), _DECL_FUNC(escape,2,_SC(".s")), _DECL_FUNC(startswith,3,_SC(".ss")), _DECL_FUNC(endswith,3,_SC(".ss")), {NULL,(SQFUNCTION)0,0,NULL} }; #undef _DECL_FUNC SQInteger sqstd_register_stringlib(HSQUIRRELVM v) { sq_pushstring(v,_SC("regexp"),-1); sq_newclass(v,SQFalse); rex_typetag = (SQUserPointer)rexobj_funcs; sq_settypetag(v, -1, rex_typetag); SQInteger i = 0; while(rexobj_funcs[i].name != 0) { const SQRegFunction &f = rexobj_funcs[i]; sq_pushstring(v,f.name,-1); sq_newclosure(v,f.f,0); sq_setparamscheck(v,f.nparamscheck,f.typemask); sq_setnativeclosurename(v,-1,f.name); sq_newslot(v,-3,SQFalse); i++; } sq_newslot(v,-3,SQFalse); i = 0; while(stringlib_funcs[i].name!=0) { sq_pushstring(v,stringlib_funcs[i].name,-1); sq_newclosure(v,stringlib_funcs[i].f,0); sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); sq_newslot(v,-3,SQFalse); i++; } return 1; } simutrans-124.3/src/squirrel/sqstdlib/sqstdsystem.cc000066400000000000000000000065441474050137200227600ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "../squirrel.h" #include #include #include #include "../sqstdsystem.h" #ifdef SQUNICODE #include #define scgetenv _wgetenv #define scsystem _wsystem #define scasctime _wasctime #define scremove _wremove #define screname _wrename #else #define scgetenv getenv #define scsystem system #define scasctime asctime #define scremove remove #define screname rename #endif #ifdef IOS #include extern char **environ; #endif static SQInteger _system_getenv(HSQUIRRELVM v) { const SQChar *s; if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ sq_pushstring(v,scgetenv(s),-1); return 1; } return 0; } static SQInteger _system_system(HSQUIRRELVM v) { const SQChar *s; if(SQ_SUCCEEDED(sq_getstring(v,2,&s))){ #ifdef IOS pid_t pid; posix_spawn(&pid, s, NULL, NULL, NULL, environ); sq_pushinteger(v, 0); #else sq_pushinteger(v,scsystem(s)); #endif return 1; } return sq_throwerror(v,_SC("wrong param")); } static SQInteger _system_clock(HSQUIRRELVM v) { sq_pushfloat(v,((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC); return 1; } static SQInteger _system_time(HSQUIRRELVM v) { SQInteger t = (SQInteger)time(NULL); sq_pushinteger(v,t); return 1; } static SQInteger _system_remove(HSQUIRRELVM v) { const SQChar *s; sq_getstring(v,2,&s); if(scremove(s)==-1) return sq_throwerror(v,_SC("remove() failed")); return 0; } static SQInteger _system_rename(HSQUIRRELVM v) { const SQChar *oldn,*newn; sq_getstring(v,2,&oldn); sq_getstring(v,3,&newn); if(screname(oldn,newn)==-1) return sq_throwerror(v,_SC("rename() failed")); return 0; } static void _set_integer_slot(HSQUIRRELVM v,const SQChar *name,SQInteger val) { sq_pushstring(v,name,-1); sq_pushinteger(v,val); sq_rawset(v,-3); } static SQInteger _system_date(HSQUIRRELVM v) { time_t t; SQInteger it; SQInteger format = 'l'; if(sq_gettop(v) > 1) { sq_getinteger(v,2,&it); t = it; if(sq_gettop(v) > 2) { sq_getinteger(v,3,(SQInteger*)&format); } } else { time(&t); } tm *date; if(format == 'u') date = gmtime(&t); else date = localtime(&t); if(!date) return sq_throwerror(v,_SC("crt api failure")); sq_newtable(v); _set_integer_slot(v, _SC("sec"), date->tm_sec); _set_integer_slot(v, _SC("min"), date->tm_min); _set_integer_slot(v, _SC("hour"), date->tm_hour); _set_integer_slot(v, _SC("day"), date->tm_mday); _set_integer_slot(v, _SC("month"), date->tm_mon); _set_integer_slot(v, _SC("year"), date->tm_year+1900); _set_integer_slot(v, _SC("wday"), date->tm_wday); _set_integer_slot(v, _SC("yday"), date->tm_yday); return 1; } #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_system_##name,nparams,pmask} static const SQRegFunction systemlib_funcs[]={ _DECL_FUNC(getenv,2,_SC(".s")), _DECL_FUNC(system,2,_SC(".s")), _DECL_FUNC(clock,0,NULL), _DECL_FUNC(time,1,NULL), _DECL_FUNC(date,-1,_SC(".nn")), _DECL_FUNC(remove,2,_SC(".s")), _DECL_FUNC(rename,3,_SC(".ss")), {NULL,(SQFUNCTION)0,0,NULL} }; #undef _DECL_FUNC SQInteger sqstd_register_systemlib(HSQUIRRELVM v) { SQInteger i=0; while(systemlib_funcs[i].name!=0) { sq_pushstring(v,systemlib_funcs[i].name,-1); sq_newclosure(v,systemlib_funcs[i].f,0); sq_setparamscheck(v,systemlib_funcs[i].nparamscheck,systemlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,systemlib_funcs[i].name); sq_newslot(v,-3,SQFalse); i++; } return 1; } simutrans-124.3/src/squirrel/sqstdmath.h000066400000000000000000000003611474050137200203710ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTD_MATH_H_ #define _SQSTD_MATH_H_ #ifdef __cplusplus extern "C" { #endif SQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); #ifdef __cplusplus } /*extern "C"*/ #endif #endif simutrans-124.3/src/squirrel/sqstdstring.h000066400000000000000000000022341474050137200207470ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTD_STRING_H_ #define _SQSTD_STRING_H_ #ifdef __cplusplus extern "C" { #endif typedef unsigned int SQRexBool; typedef struct SQRex SQRex; typedef struct { const SQChar *begin; SQInteger len; } SQRexMatch; SQUIRREL_API SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); SQUIRREL_API void sqstd_rex_free(SQRex *exp); SQUIRREL_API SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); SQUIRREL_API SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); SQUIRREL_API SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); SQUIRREL_API SQInteger sqstd_rex_getsubexpcount(SQRex* exp); SQUIRREL_API SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp); SQUIRREL_API SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output); SQUIRREL_API void sqstd_pushstringf(HSQUIRRELVM v,const SQChar *s,...); SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); #ifdef __cplusplus } /*extern "C"*/ #endif #endif simutrans-124.3/src/squirrel/sqstdsystem.h000066400000000000000000000003761474050137200207720ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTD_SYSTEMLIB_H_ #define _SQSTD_SYSTEMLIB_H_ #ifdef __cplusplus extern "C" { #endif SQUIRREL_API SQInteger sqstd_register_systemlib(HSQUIRRELVM v); #ifdef __cplusplus } /*extern "C"*/ #endif #endif simutrans-124.3/src/squirrel/squirrel.h000066400000000000000000000434261474050137200202400ustar00rootroot00000000000000/* Copyright (c) 2003-2017 Alberto Demichelis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _SQUIRREL_H_ #define _SQUIRREL_H_ #ifdef _SQ_CONFIG_INCLUDE #include _SQ_CONFIG_INCLUDE #endif #ifdef __cplusplus extern "C" { #endif #ifndef SQUIRREL_API #define SQUIRREL_API extern #endif #if (defined(_WIN64) || defined(_LP64)) #ifndef _SQ64 #define _SQ64 #endif #endif #define SQTrue (1) #define SQFalse (0) struct SQVM; struct SQTable; struct SQArray; struct SQString; struct SQClosure; struct SQGenerator; struct SQNativeClosure; struct SQUserData; struct SQFunctionProto; struct SQRefCounted; struct SQClass; struct SQInstance; struct SQDelegable; struct SQOuter; #ifdef _UNICODE // #define SQUNICODE #endif #include "sqconfig.h" #define SQUIRREL_VERSION _SC("Squirrel 3.1 stable") #define SQUIRREL_COPYRIGHT _SC("Copyright (C) 2003-2017 Alberto Demichelis") #define SQUIRREL_AUTHOR _SC("Alberto Demichelis") #define SQUIRREL_VERSION_NUMBER 310 #define SQ_VMSTATE_IDLE 0 #define SQ_VMSTATE_RUNNING 1 #define SQ_VMSTATE_SUSPENDED 2 #define SQUIRREL_EOB 0 #define SQ_BYTECODE_STREAM_TAG 0xFAFA #define SQOBJECT_REF_COUNTED 0x08000000 #define SQOBJECT_NUMERIC 0x04000000 #define SQOBJECT_DELEGABLE 0x02000000 #define SQOBJECT_CANBEFALSE 0x01000000 #define SQ_MATCHTYPEMASKSTRING (-99999) #define _RT_MASK 0x00FFFFFF #define _RAW_TYPE(type) (type&_RT_MASK) #define _RT_NULL 0x00000001 #define _RT_INTEGER 0x00000002 #define _RT_FLOAT 0x00000004 #define _RT_BOOL 0x00000008 #define _RT_STRING 0x00000010 #define _RT_TABLE 0x00000020 #define _RT_ARRAY 0x00000040 #define _RT_USERDATA 0x00000080 #define _RT_CLOSURE 0x00000100 #define _RT_NATIVECLOSURE 0x00000200 #define _RT_GENERATOR 0x00000400 #define _RT_USERPOINTER 0x00000800 #define _RT_THREAD 0x00001000 #define _RT_FUNCPROTO 0x00002000 #define _RT_CLASS 0x00004000 #define _RT_INSTANCE 0x00008000 #define _RT_WEAKREF 0x00010000 #define _RT_OUTER 0x00020000 typedef enum tagSQObjectType{ OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), OT_USERPOINTER = _RT_USERPOINTER, OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_WEAKREF = (_RT_WEAKREF|SQOBJECT_REF_COUNTED), OT_OUTER = (_RT_OUTER|SQOBJECT_REF_COUNTED) //internal usage only }SQObjectType; #define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) typedef union tagSQObjectValue { struct SQTable *pTable; struct SQArray *pArray; struct SQClosure *pClosure; struct SQOuter *pOuter; struct SQGenerator *pGenerator; struct SQNativeClosure *pNativeClosure; struct SQString *pString; struct SQUserData *pUserData; SQInteger nInteger; SQFloat fFloat; SQUserPointer pUserPointer; struct SQFunctionProto *pFunctionProto; struct SQRefCounted *pRefCounted; struct SQDelegable *pDelegable; struct SQVM *pThread; struct SQClass *pClass; struct SQInstance *pInstance; struct SQWeakRef *pWeakRef; SQRawObjectVal raw; }SQObjectValue; typedef struct tagSQObject { SQObjectType _type; SQObjectValue _unVal; }SQObject; typedef struct tagSQMemberHandle{ SQBool _static; SQInteger _index; }SQMemberHandle; typedef struct tagSQStackInfos{ const SQChar* funcname; const SQChar* source; SQInteger line; }SQStackInfos; typedef struct SQVM* HSQUIRRELVM; typedef SQObject HSQOBJECT; typedef SQMemberHandle HSQMEMBERHANDLE; typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM); typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/); typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); typedef void (*SQDEBUGHOOK)(HSQUIRRELVM /*v*/, SQInteger /*type*/, const SQChar * /*sourcename*/, SQInteger /*line*/, const SQChar * /*funcname*/); typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger); typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger); typedef SQInteger (*SQLEXREADFUNC)(SQUserPointer); typedef struct tagSQRegFunction{ const SQChar *name; SQFUNCTION f; SQInteger nparamscheck; const SQChar *typemask; }SQRegFunction; typedef struct tagSQFunctionInfo { SQUserPointer funcid; const SQChar *name; const SQChar *source; SQInteger line; }SQFunctionInfo; /*vm*/ SQUIRREL_API HSQUIRRELVM sq_open(SQInteger initialstacksize); SQUIRREL_API HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize); SQUIRREL_API void sq_seterrorhandler(HSQUIRRELVM v); SQUIRREL_API void sq_close(HSQUIRRELVM v); SQUIRREL_API void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); SQUIRREL_API SQUserPointer sq_getforeignptr(HSQUIRRELVM v); SQUIRREL_API void sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p); SQUIRREL_API SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v); SQUIRREL_API void sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook); SQUIRREL_API SQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v); SQUIRREL_API void sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook); SQUIRREL_API SQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v); SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc); SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); SQUIRREL_API SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror); SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v); SQUIRREL_API SQInteger sq_getversion(); /*compiler*/ SQUIRREL_API SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); SQUIRREL_API SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror); SQUIRREL_API void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable); SQUIRREL_API void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable); SQUIRREL_API void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); /*stack operations*/ SQUIRREL_API void sq_push(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop); SQUIRREL_API void sq_poptop(HSQUIRRELVM v); SQUIRREL_API void sq_remove(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQInteger sq_gettop(HSQUIRRELVM v); SQUIRREL_API void sq_settop(HSQUIRRELVM v,SQInteger newtop); SQUIRREL_API SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize); SQUIRREL_API SQInteger sq_cmp(HSQUIRRELVM v); SQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx); /*object creation handling*/ SQUIRREL_API SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size); SQUIRREL_API void sq_newtable(HSQUIRRELVM v); SQUIRREL_API void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity); SQUIRREL_API void sq_newarray(HSQUIRRELVM v,SQInteger size); SQUIRREL_API void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars); SQUIRREL_API SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask); SQUIRREL_API SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_setclosureroot(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getclosureroot(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len); SQUIRREL_API void sq_pushfloat(HSQUIRRELVM v,SQFloat f); SQUIRREL_API void sq_pushinteger(HSQUIRRELVM v,SQInteger n); SQUIRREL_API void sq_pushbool(HSQUIRRELVM v,SQBool b); SQUIRREL_API void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); SQUIRREL_API void sq_pushnull(HSQUIRRELVM v); SQUIRREL_API void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread); SQUIRREL_API SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx); SQUIRREL_API SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b); SQUIRREL_API SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger *size); SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c); SQUIRREL_API SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i); SQUIRREL_API SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f); SQUIRREL_API SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b); SQUIRREL_API SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread); SQUIRREL_API SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p); SQUIRREL_API SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag); SQUIRREL_API SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag); SQUIRREL_API SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag); SQUIRREL_API void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook); SQUIRREL_API SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize); SQUIRREL_API SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi); SQUIRREL_API SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars); SQUIRREL_API SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name); SQUIRREL_API SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p); SQUIRREL_API SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag); SQUIRREL_API SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize); SQUIRREL_API SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); SQUIRREL_API SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API void sq_weakref(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t); SQUIRREL_API SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle); SQUIRREL_API SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle); SQUIRREL_API SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle); /*object manipulation*/ SQUIRREL_API void sq_pushroottable(HSQUIRRELVM v); SQUIRREL_API void sq_pushregistrytable(HSQUIRRELVM v); SQUIRREL_API void sq_pushconsttable(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_setroottable(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_setconsttable(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); SQUIRREL_API SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQUIRREL_API SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQUIRREL_API SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic); SQUIRREL_API SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic); SQUIRREL_API SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQUIRREL_API SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize); SQUIRREL_API SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx); SQUIRREL_API SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos); SQUIRREL_API SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); SQUIRREL_API SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx); SQUIRREL_API SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx); /*calls*/ SQUIRREL_API SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror); SQUIRREL_API SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); SQUIRREL_API const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); SQUIRREL_API SQRESULT sq_getcallee(HSQUIRRELVM v); SQUIRREL_API const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); SQUIRREL_API SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); SQUIRREL_API SQRESULT sq_throwobject(HSQUIRRELVM v); SQUIRREL_API void sq_reseterror(HSQUIRRELVM v); SQUIRREL_API void sq_getlasterror(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams); /*raw object handling*/ SQUIRREL_API SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po); SQUIRREL_API void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); SQUIRREL_API void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); SQUIRREL_API SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); SQUIRREL_API SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po); SQUIRREL_API void sq_resetobject(HSQOBJECT *po); SQUIRREL_API const SQChar *sq_objtostring(const HSQOBJECT *o); SQUIRREL_API SQBool sq_objtobool(const HSQOBJECT *o); SQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o); SQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o); SQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o); SQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag); SQUIRREL_API SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po); /*GC*/ SQUIRREL_API SQInteger sq_collectgarbage(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_resurrectunreachable(HSQUIRRELVM v); /*serialization*/ SQUIRREL_API SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); SQUIRREL_API SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); /*mem allocation*/ SQUIRREL_API void *sq_malloc(SQUnsignedInteger size); SQUIRREL_API void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize); SQUIRREL_API void sq_free(void *p,SQUnsignedInteger size); /*debug*/ SQUIRREL_API SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si); SQUIRREL_API void sq_setdebughook(HSQUIRRELVM v); SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook); /*UTILITY MACRO*/ #define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) #define sq_istable(o) ((o)._type==OT_TABLE) #define sq_isarray(o) ((o)._type==OT_ARRAY) #define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) #define sq_isclosure(o) ((o)._type==OT_CLOSURE) #define sq_isgenerator(o) ((o)._type==OT_GENERATOR) #define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) #define sq_isstring(o) ((o)._type==OT_STRING) #define sq_isinteger(o) ((o)._type==OT_INTEGER) #define sq_isfloat(o) ((o)._type==OT_FLOAT) #define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) #define sq_isuserdata(o) ((o)._type==OT_USERDATA) #define sq_isthread(o) ((o)._type==OT_THREAD) #define sq_isnull(o) ((o)._type==OT_NULL) #define sq_isclass(o) ((o)._type==OT_CLASS) #define sq_isinstance(o) ((o)._type==OT_INSTANCE) #define sq_isbool(o) ((o)._type==OT_BOOL) #define sq_isweakref(o) ((o)._type==OT_WEAKREF) #define sq_type(o) ((o)._type) /* deprecated */ #define sq_createslot(v,n) sq_newslot(v,n,SQFalse) #define SQ_OK (0) #define SQ_ERROR (-1) #define SQ_FAILED(res) (res<0) #define SQ_SUCCEEDED(res) (res>=0) #ifdef XX__GNUC__ # define SQ_UNUSED_ARG(x) __attribute__((unused)) x #else # define SQ_UNUSED_ARG(x) #endif #ifdef __cplusplus } /*extern "C"*/ #endif #endif simutrans-124.3/src/squirrel/squirrel/000077500000000000000000000000001474050137200200565ustar00rootroot00000000000000simutrans-124.3/src/squirrel/squirrel/sqapi.cc000066400000000000000000001137651474050137200215170ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "squserdata.h" #include "sqcompiler.h" #include "sqfuncstate.h" #include "sqclass.h" static bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) { *o = &stack_get(v,idx); if(sq_type(**o) != type){ SQObjectPtr oval = v->PrintObjVal(**o); v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval)); return false; } return true; } #define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } #define sq_aux_paramscheck(v,count) \ { \ if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\ } SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) { SQUnsignedInteger buf_size = 100 *sizeof(SQChar); scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, _SC("unexpected type %s"), IdType2Name(type)); return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); } HSQUIRRELVM sq_open(SQInteger initialstacksize) { SQSharedState *ss; SQVM *v; sq_new(ss, SQSharedState); ss->Init(); v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); new (v) SQVM(ss); ss->_root_vm = v; if(v->Init(NULL, initialstacksize)) { return v; } else { sq_delete(v, SQVM); return NULL; } return v; } HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize) { SQSharedState *ss; SQVM *v; ss=_ss(friendvm); v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); new (v) SQVM(ss); if(v->Init(friendvm, initialstacksize)) { friendvm->Push(v); return v; } else { sq_delete(v, SQVM); return NULL; } } SQInteger sq_getvmstate(HSQUIRRELVM v) { if(v->_suspended) return SQ_VMSTATE_SUSPENDED; else { if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING; else return SQ_VMSTATE_IDLE; } } void sq_seterrorhandler(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { v->_errorhandler = o; v->Pop(); } } void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook) { v->_debughook_native = hook; v->_debughook_closure.Null(); v->_debughook = hook?true:false; } void sq_setdebughook(HSQUIRRELVM v) { SQObject o = stack_get(v,-1); if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { v->_debughook_closure = o; v->_debughook_native = NULL; v->_debughook = !sq_isnull(o); v->Pop(); } } void sq_close(HSQUIRRELVM v) { SQSharedState *ss = _ss(v); _thread(ss->_root_vm)->Finalize(); sq_delete(ss, SQSharedState); } SQInteger sq_getversion() { return SQUIRREL_VERSION_NUMBER; } SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) { SQObjectPtr o; #ifndef NO_COMPILER if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { v->Push(SQClosure::Create(_ss(v), _funcproto(o), _table(v->_roottable)->GetWeakRef(OT_TABLE))); return SQ_OK; } return SQ_ERROR; #else return sq_throwerror(v,_SC("this is a no compiler build")); #endif } void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) { _ss(v)->_debuginfo = enable?true:false; } void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) { _ss(v)->_notifyallexceptions = enable?true:false; } void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) { if(!ISREFCOUNTED(sq_type(*po))) return; #ifdef NO_GARBAGE_COLLECTOR __AddRef(po->_type,po->_unVal); #else _ss(v)->_refs_table.AddRef(*po); #endif } SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po) { if(!ISREFCOUNTED(sq_type(*po))) return 0; #ifdef NO_GARBAGE_COLLECTOR return po->_unVal.pRefCounted->_uiRef; #else return _ss(v)->_refs_table.GetRefCount(*po); #endif } SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) { if(!ISREFCOUNTED(sq_type(*po))) return SQTrue; #ifdef NO_GARBAGE_COLLECTOR bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse; __Release(po->_type,po->_unVal); return ret; //the ret val doesn't work(and cannot be fixed) #else return _ss(v)->_refs_table.Release(*po); #endif } SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM SQ_UNUSED_ARG(v), const HSQOBJECT *po) { if (!ISREFCOUNTED(sq_type(*po))) return 0; return po->_unVal.pRefCounted->_uiRef; } const SQChar *sq_objtostring(const HSQOBJECT *o) { if(sq_type(*o) == OT_STRING) { return _stringval(*o); } return NULL; } SQInteger sq_objtointeger(const HSQOBJECT *o) { if(sq_isnumeric(*o)) { return tointeger(*o); } return 0; } SQFloat sq_objtofloat(const HSQOBJECT *o) { if(sq_isnumeric(*o)) { return tofloat(*o); } return 0; } SQBool sq_objtobool(const HSQOBJECT *o) { if(sq_isbool(*o)) { return _integer(*o); } return SQFalse; } SQUserPointer sq_objtouserpointer(const HSQOBJECT *o) { if(sq_isuserpointer(*o)) { return _userpointer(*o); } return 0; } void sq_pushnull(HSQUIRRELVM v) { v->PushNull(); } void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) { if(s) v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); else v->PushNull(); } void sq_pushinteger(HSQUIRRELVM v,SQInteger n) { v->Push(n); } void sq_pushbool(HSQUIRRELVM v,SQBool b) { v->Push(b?true:false); } void sq_pushfloat(HSQUIRRELVM v,SQFloat n) { v->Push(n); } void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) { v->Push(p); } void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread) { v->Push(thread); } SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) { SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT); v->Push(ud); return (SQUserPointer)sq_aligning(ud + 1); } void sq_newtable(HSQUIRRELVM v) { v->Push(SQTable::Create(_ss(v), 0)); } void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity) { v->Push(SQTable::Create(_ss(v), initialcapacity)); } void sq_newarray(HSQUIRRELVM v,SQInteger size) { v->Push(SQArray::Create(_ss(v), size)); } SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) { SQClass *baseclass = NULL; if(hasbase) { SQObjectPtr &base = stack_get(v,-1); if(sq_type(base) != OT_CLASS) return sq_throwerror(v,_SC("invalid base type")); baseclass = _class(base); } SQClass *newclass = SQClass::Create(_ss(v), baseclass); if(baseclass) v->Pop(); v->Push(newclass); return SQ_OK; } SQBool sq_instanceof(HSQUIRRELVM v) { SQObjectPtr &inst = stack_get(v,-1); SQObjectPtr &cl = stack_get(v,-2); if(sq_type(inst) != OT_INSTANCE || sq_type(cl) != OT_CLASS) return sq_throwerror(v,_SC("invalid param type")); return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse; } SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) { sq_aux_paramscheck(v,2); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); _array(*arr)->Append(v->GetUp(-1)); v->Pop(); return SQ_OK; } SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); if(_array(*arr)->Size() > 0) { if(pushval != 0){ v->Push(_array(*arr)->Top()); } _array(*arr)->Pop(); return SQ_OK; } return sq_throwerror(v, _SC("empty array")); } SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize) { sq_aux_paramscheck(v,1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); if(newsize >= 0) { _array(*arr)->Resize(newsize); return SQ_OK; } return sq_throwerror(v,_SC("negative size")); } SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx) { sq_aux_paramscheck(v, 1); SQObjectPtr *o; _GETSAFE_OBJ(v, idx, OT_ARRAY,o); SQArray *arr = _array(*o); if(arr->Size() > 0) { SQObjectPtr t; SQInteger size = arr->Size(); SQInteger n = size >> 1; size -= 1; for(SQInteger i = 0; i < n; i++) { t = arr->_values[i]; arr->_values[i] = arr->_values[size-i]; arr->_values[size-i] = t; } return SQ_OK; } return SQ_OK; } SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); } SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); v->Pop(); return ret; } void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) { SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars); nc->_nparamscheck = 0; for(SQUnsignedInteger i = 0; i < nfreevars; i++) { nc->_outervalues[i] = v->Top(); v->Pop(); } v->Push(SQObjectPtr(nc)); } SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQInteger *nparams,SQInteger *nfreevars) { SQObject o = stack_get(v, idx); if(sq_type(o) == OT_CLOSURE) { SQClosure *c = _closure(o); SQFunctionProto *proto = c->_function; *nparams = proto->_nparameters; *nfreevars = proto->_noutervalues; return SQ_OK; } else if(sq_type(o) == OT_NATIVECLOSURE) { SQNativeClosure *c = _nativeclosure(o); *nparams = c->_nparamscheck; *nfreevars = (SQInteger)c->_noutervalues; return SQ_OK; } return sq_throwerror(v,_SC("the object is not a closure")); } SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name) { SQObject o = stack_get(v, idx); if(sq_isnativeclosure(o)) { SQNativeClosure *nc = _nativeclosure(o); nc->_name = SQString::Create(_ss(v),name); return SQ_OK; } return sq_throwerror(v,_SC("the object is not a nativeclosure")); } SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask) { SQObject o = stack_get(v, -1); if(!sq_isnativeclosure(o)) return sq_throwerror(v, _SC("native closure expected")); SQNativeClosure *nc = _nativeclosure(o); nc->_nparamscheck = nparamscheck; if(typemask) { SQIntVec res; if(!CompileTypemask(res, typemask)) return sq_throwerror(v, _SC("invalid typemask")); nc->_typecheck.copy(res); } else { nc->_typecheck.resize(0); } if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { nc->_nparamscheck = nc->_typecheck.size(); } return SQ_OK; } SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); if(!sq_isnativeclosure(o) && !sq_isclosure(o)) return sq_throwerror(v,_SC("the target is not a closure")); SQObjectPtr &env = stack_get(v,-1); if(!sq_istable(env) && !sq_isarray(env) && !sq_isclass(env) && !sq_isinstance(env)) return sq_throwerror(v,_SC("invalid environment")); SQWeakRef *w = _refcounted(env)->GetWeakRef(sq_type(env)); SQObjectPtr ret; if(sq_isclosure(o)) { SQClosure *c = _closure(o)->Clone(); __ObjRelease(c->_env); c->_env = w; __ObjAddRef(c->_env); if(_closure(o)->_base) { c->_base = _closure(o)->_base; __ObjAddRef(c->_base); } ret = c; } else { //then must be a native closure SQNativeClosure *c = _nativeclosure(o)->Clone(); __ObjRelease(c->_env); c->_env = w; __ObjAddRef(c->_env); ret = c; } v->Pop(); v->Push(ret); return SQ_OK; } SQRESULT sq_getclosurename(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); if(!sq_isnativeclosure(o) && !sq_isclosure(o)) return sq_throwerror(v,_SC("the target is not a closure")); if(sq_isnativeclosure(o)) { v->Push(_nativeclosure(o)->_name); } else { //closure v->Push(_closure(o)->_function->_name); } return SQ_OK; } SQRESULT sq_setclosureroot(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &c = stack_get(v,idx); SQObject o = stack_get(v, -1); if(!sq_isclosure(c)) return sq_throwerror(v, _SC("closure expected")); if(sq_istable(o)) { _closure(c)->SetRoot(_table(o)->GetWeakRef(OT_TABLE)); v->Pop(); return SQ_OK; } return sq_throwerror(v, _SC("invalid type")); } SQRESULT sq_getclosureroot(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &c = stack_get(v,idx); if(!sq_isclosure(c)) return sq_throwerror(v, _SC("closure expected")); v->Push(_closure(c)->_root->_obj); return SQ_OK; } SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx) { SQObject &o=stack_get(v,idx); switch(sq_type(o)) { case OT_TABLE: _table(o)->Clear(); break; case OT_ARRAY: _array(o)->Resize(0); break; default: return sq_throwerror(v, _SC("clear only works on table and array")); break; } return SQ_OK; } void sq_pushroottable(HSQUIRRELVM v) { v->Push(v->_roottable); } void sq_pushregistrytable(HSQUIRRELVM v) { v->Push(_ss(v)->_registry); } void sq_pushconsttable(HSQUIRRELVM v) { v->Push(_ss(v)->_consts); } SQRESULT sq_setroottable(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_istable(o) || sq_isnull(o)) { v->_roottable = o; v->Pop(); return SQ_OK; } return sq_throwerror(v, _SC("invalid type")); } SQRESULT sq_setconsttable(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_istable(o)) { _ss(v)->_consts = o; v->Pop(); return SQ_OK; } return sq_throwerror(v, _SC("invalid type, expected table")); } void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) { v->_foreignptr = p; } SQUserPointer sq_getforeignptr(HSQUIRRELVM v) { return v->_foreignptr; } void sq_setsharedforeignptr(HSQUIRRELVM v,SQUserPointer p) { _ss(v)->_foreignptr = p; } SQUserPointer sq_getsharedforeignptr(HSQUIRRELVM v) { return _ss(v)->_foreignptr; } void sq_setvmreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook) { v->_releasehook = hook; } SQRELEASEHOOK sq_getvmreleasehook(HSQUIRRELVM v) { return v->_releasehook; } void sq_setsharedreleasehook(HSQUIRRELVM v,SQRELEASEHOOK hook) { _ss(v)->_releasehook = hook; } SQRELEASEHOOK sq_getsharedreleasehook(HSQUIRRELVM v) { return _ss(v)->_releasehook; } void sq_push(HSQUIRRELVM v,SQInteger idx) { v->Push(stack_get(v, idx)); } SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx) { return sq_type(stack_get(v, idx)); } SQRESULT sq_typeof(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); SQObjectPtr res; if(!v->TypeOf(o,res)) { return SQ_ERROR; } v->Push(res); return SQ_OK; } SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); SQObjectPtr res; if(!v->ToString(o,res)) { return SQ_ERROR; } v->Push(res); return SQ_OK; } void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) { SQObjectPtr &o = stack_get(v, idx); *b = SQVM::IsFalse(o)?SQFalse:SQTrue; } SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) { SQObjectPtr &o = stack_get(v, idx); if(sq_isnumeric(o)) { *i = tointeger(o); return SQ_OK; } if(sq_isbool(o)) { *i = SQVM::IsFalse(o)?SQFalse:SQTrue; return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f) { SQObjectPtr &o = stack_get(v, idx); if(sq_isnumeric(o)) { *f = tofloat(o); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b) { SQObjectPtr &o = stack_get(v, idx); if(sq_isbool(o)) { *b = _integer(o); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger *size) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_STRING,o); *c = _stringval(*o); *size = _string(*o)->_len; return SQ_OK; } SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_STRING,o); *c = _stringval(*o); return SQ_OK; } SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_THREAD,o); *thread = _thread(*o); return SQ_OK; } SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); v->PushNull(); if(!v->Clone(o, stack_get(v, -1))){ v->Pop(); return SQ_ERROR; } return SQ_OK; } SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); SQObjectType type = sq_type(o); switch(type) { case OT_STRING: return _string(o)->_len; case OT_TABLE: return _table(o)->CountUsed(); case OT_ARRAY: return _array(o)->Size(); case OT_USERDATA: return _userdata(o)->_size; case OT_INSTANCE: return _instance(o)->_class->_udsize; case OT_CLASS: return _class(o)->_udsize; default: return sq_aux_invalidtype(v, type); } } SQHash sq_gethash(HSQUIRRELVM v, SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); return HashObj(o); } SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_USERDATA,o); (*p) = _userdataval(*o); if(typetag) *typetag = _userdata(*o)->_typetag; return SQ_OK; } SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag) { SQObjectPtr &o = stack_get(v,idx); switch(sq_type(o)) { case OT_USERDATA: _userdata(o)->_typetag = typetag; break; case OT_CLASS: _class(o)->_typetag = typetag; break; default: return sq_throwerror(v,_SC("invalid object type")); } return SQ_OK; } SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag) { switch(sq_type(*o)) { case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break; case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break; case OT_CLASS: *typetag = _class(*o)->_typetag; break; default: return SQ_ERROR; } return SQ_OK; } SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag) { SQObjectPtr &o = stack_get(v,idx); if(SQ_FAILED(sq_getobjtypetag(&o,typetag))) return SQ_ERROR;// this is not an error it should be a bool but would break backward compatibility return SQ_OK; } SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); (*p) = _userpointer(*o); return SQ_OK; } SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p) { SQObjectPtr &o = stack_get(v,idx); if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); _instance(o)->_userpointer = p; return SQ_OK; } SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) { SQObjectPtr &o = stack_get(v,idx); if(sq_type(o) != OT_CLASS) return sq_throwerror(v,_SC("the object is not a class")); if(_class(o)->_locked) return sq_throwerror(v,_SC("the class is locked")); _class(o)->_udsize = udsize; return SQ_OK; } SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) { SQObjectPtr &o = stack_get(v,idx); if(sq_type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); (*p) = _instance(o)->_userpointer; if(typetag != 0) { SQClass *cl = _instance(o)->_class; do{ if(cl->_typetag == typetag) return SQ_OK; cl = cl->_base; }while(cl != NULL); return sq_throwerror(v,_SC("invalid type tag")); } return SQ_OK; } SQInteger sq_gettop(HSQUIRRELVM v) { return (v->_top) - v->_stackbase; } void sq_settop(HSQUIRRELVM v, SQInteger newtop) { SQInteger top = sq_gettop(v); if(top > newtop) sq_pop(v, top - newtop); else while(top++ < newtop) sq_pushnull(v); } void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop) { assert(v->_top >= nelemstopop); v->Pop(nelemstopop); } void sq_poptop(HSQUIRRELVM v) { assert(v->_top >= 1); v->Pop(); } void sq_remove(HSQUIRRELVM v, SQInteger idx) { v->Remove(idx); } SQInteger sq_cmp(HSQUIRRELVM v) { SQInteger res; v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); return res; } SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) { sq_aux_paramscheck(v, 3); SQObjectPtr &self = stack_get(v, idx); if(sq_type(self) == OT_TABLE || sq_type(self) == OT_CLASS) { SQObjectPtr &key = v->GetUp(-2); if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false); v->Pop(2); } return SQ_OK; } SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 2); SQObjectPtr *self; _GETSAFE_OBJ(v, idx, OT_TABLE,self); SQObjectPtr &key = v->GetUp(-1); if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); SQObjectPtr res; if(!v->DeleteSlot(*self, key, res)){ v->Pop(); return SQ_ERROR; } if(pushval) v->GetUp(-1) = res; else v->Pop(); return SQ_OK; } SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); if(v->Set(self, v->GetUp(-2), v->GetUp(-1),DONT_FALL_BACK)) { v->Pop(2); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &key = v->GetUp(-2); if(sq_type(key) == OT_NULL) { v->Pop(2); return sq_throwerror(v, _SC("null key")); } switch(sq_type(self)) { case OT_TABLE: _table(self)->NewSlot(key, v->GetUp(-1)); v->Pop(2); return SQ_OK; break; case OT_CLASS: _class(self)->NewSlot(_ss(v), key, v->GetUp(-1),false); v->Pop(2); return SQ_OK; break; case OT_INSTANCE: if(_instance(self)->Set(key, v->GetUp(-1))) { v->Pop(2); return SQ_OK; } break; case OT_ARRAY: if(v->Set(self, key, v->GetUp(-1),false)) { v->Pop(2); return SQ_OK; } break; default: v->Pop(2); return sq_throwerror(v, _SC("rawset works only on array/table/class and instance")); } v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; } SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic) { SQObjectPtr &self = stack_get(v, idx); if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes")); SQObjectPtr &key = v->GetUp(-3); if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null key")); if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false)) { v->Pop(3); return SQ_ERROR; } v->Pop(3); return SQ_OK; } SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic) { SQObjectPtr &self = stack_get(v, idx); if(sq_type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes")); SQObjectPtr &key = v->GetUp(-3); if(sq_type(key) == OT_NULL) return sq_throwerror(v, _SC("null key")); if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true)) { v->Pop(3); return SQ_ERROR; } v->Pop(3); return SQ_OK; } SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &mt = v->GetUp(-1); SQObjectType type = sq_type(self); switch(type) { case OT_TABLE: if(sq_type(mt) == OT_TABLE) { if(!_table(self)->SetDelegate(_table(mt))) { return sq_throwerror(v, _SC("delegate cycle")); } v->Pop(); } else if(sq_type(mt)==OT_NULL) { _table(self)->SetDelegate(NULL); v->Pop(); } else return sq_aux_invalidtype(v,type); break; case OT_USERDATA: if(sq_type(mt)==OT_TABLE) { _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } else if(sq_type(mt)==OT_NULL) { _userdata(self)->SetDelegate(NULL); v->Pop(); } else return sq_aux_invalidtype(v, type); break; default: return sq_aux_invalidtype(v, type); break; } return SQ_OK; } SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 2); SQObjectPtr *self; _GETSAFE_OBJ(v, idx, OT_TABLE,self); SQObjectPtr &key = v->GetUp(-1); SQObjectPtr t; if(_table(*self)->Get(key,t)) { _table(*self)->Remove(key); } if(pushval != 0) v->GetUp(-1) = t; else v->Pop(); return SQ_OK; } SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); switch(sq_type(self)){ case OT_TABLE: case OT_USERDATA: if(!_delegable(self)->_delegate){ v->PushNull(); break; } v->Push(SQObjectPtr(_delegable(self)->_delegate)); break; default: return sq_throwerror(v,_SC("wrong type")); break; } return SQ_OK; } SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); SQObjectPtr &obj = v->GetUp(-1); if(v->Get(self,obj,obj,false,DONT_FALL_BACK)) return SQ_OK; v->Pop(); return SQ_ERROR; } SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); SQObjectPtr &obj = v->GetUp(-1); switch(sq_type(self)) { case OT_TABLE: if(_table(self)->Get(obj,obj)) return SQ_OK; break; case OT_CLASS: if(_class(self)->Get(obj,obj)) return SQ_OK; break; case OT_INSTANCE: if(_instance(self)->Get(obj,obj)) return SQ_OK; break; case OT_ARRAY:{ if(sq_isnumeric(obj)){ if(_array(self)->Get(tointeger(obj),obj)) { return SQ_OK; } } else { v->Pop(); return sq_throwerror(v,_SC("invalid index type for an array")); } } break; default: v->Pop(); return sq_throwerror(v,_SC("rawget works only on array/table/instance and class")); } // modified: call Raise_IdxError v->Raise_IdxError(v->GetUp(-1)); v->Pop(); return SQ_ERROR; } SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) { *po=stack_get(v,idx); return SQ_OK; } const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx) { SQUnsignedInteger cstksize=v->_callsstacksize; SQUnsignedInteger lvl=(cstksize-level)-1; SQInteger stackbase=v->_stackbase; if(lvl_callsstack[(cstksize-i)-1]; stackbase-=ci._prevstkbase; } SQVM::CallInfo &ci=v->_callsstack[lvl]; if(sq_type(ci._closure)!=OT_CLOSURE) return NULL; SQClosure *c=_closure(ci._closure); SQFunctionProto *func=c->_function; if(func->_noutervalues > (SQInteger)idx) { v->Push(*_outer(c->_outervalues[idx])->_valptr); return _stringval(func->_outervalues[idx]._name); } idx -= func->_noutervalues; return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1); } return NULL; } void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) { v->Push(SQObjectPtr(obj)); } void sq_resetobject(HSQOBJECT *po) { po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; } SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) { v->_lasterror=SQString::Create(_ss(v),err); return SQ_ERROR; } SQRESULT sq_throwobject(HSQUIRRELVM v) { v->_lasterror = v->GetUp(-1); v->Pop(); return SQ_ERROR; } void sq_reseterror(HSQUIRRELVM v) { v->_lasterror.Null(); } void sq_getlasterror(HSQUIRRELVM v) { v->Push(v->_lasterror); } SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize) { if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { if(v->_nmetamethodscall) { return sq_throwerror(v,_SC("cannot resize stack while in a metamethod")); } v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); } return SQ_OK; } SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) { if (sq_type(v->GetUp(-1)) == OT_GENERATOR) { v->PushNull(); //retval if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, SQVM::ET_RESUME_GENERATOR)) {v->Raise_Error(v->_lasterror); return SQ_ERROR;} if(!retval) v->Pop(); return SQ_OK; } return sq_throwerror(v,_SC("only generators can be resumed")); } /* modified for our purposes to handle suspended scripts */ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror) { SQObjectPtr res; if(v->_suspended) { v->Pop(params);//pop closure and args return sq_throwerror(v,_SC("script took to long")); } // we can suspend call only when vm is not already running (thus when we are not called from squirrel) if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false, sq_getvmstate(v)==SQ_VMSTATE_IDLE)){ if(!v->_suspended) { v->Pop(params);//pop closure and args } if(retval){ v->Push(res); return SQ_OK; } return SQ_OK; } else { v->Pop(params); return SQ_ERROR; // sq_throwerror(v,_SC("call failed")); } } /* TODO check whether this works with our suspend logic; wont be missed SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams) { SQObjectPtr &res = v->GetUp(-(nparams + 1)); if (sq_type(res) != OT_CLOSURE) { return sq_throwerror(v, _SC("only closure can be tail called")); } SQClosure *clo = _closure(res); if (clo->_function->_bgenerator) { return sq_throwerror(v, _SC("generators cannot be tail called")); } SQInteger stackbase = (v->_top - nparams) - v->_stackbase; if (!v->TailCall(clo, stackbase, nparams)) { return SQ_ERROR; } return SQ_TAILCALL_FLAG; } */ SQRESULT sq_suspendvm(HSQUIRRELVM v) { return v->Suspend(); } SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror) { SQObjectPtr ret; if(!v->_suspended) return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); SQInteger target = v->_suspended_target; if(wakeupret) { if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval } v->Pop(); } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); } SQObjectPtr dummy; if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM, true /*can_suspend*/)) { return SQ_ERROR; } if(retval) v->Push(ret); return SQ_OK; } void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) { SQObjectPtr &ud=stack_get(v,idx); switch(sq_type(ud) ) { case OT_USERDATA: _userdata(ud)->_hook = hook; break; case OT_INSTANCE: _instance(ud)->_hook = hook; break; case OT_CLASS: _class(ud)->_hook = hook; break; default: return; } } SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &ud=stack_get(v,idx); switch(sq_type(ud) ) { case OT_USERDATA: return _userdata(ud)->_hook; break; case OT_INSTANCE: return _instance(ud)->_hook; break; case OT_CLASS: return _class(ud)->_hook; break; default: return NULL; } } void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) { _ss(v)->_compilererrorhandler = f; } SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); unsigned short tag = SQ_BYTECODE_STREAM_TAG; if(_closure(*o)->_function->_noutervalues) return sq_throwerror(v,_SC("a closure with free variables bound cannot be serialized")); if(w(up,&tag,2) != 2) return sq_throwerror(v,_SC("io error")); if(!_closure(*o)->Save(v,up,w)) return SQ_ERROR; return SQ_OK; } SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) { SQObjectPtr closure; unsigned short tag; if(r(up,&tag,2) != 2) return sq_throwerror(v,_SC("io error")); if(tag != SQ_BYTECODE_STREAM_TAG) return sq_throwerror(v,_SC("invalid stream")); if(!SQClosure::Load(v,up,r,closure)) return SQ_ERROR; v->Push(closure); return SQ_OK; } SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) { return _ss(v)->GetScratchPad(minsize); } SQRESULT sq_resurrectunreachable(HSQUIRRELVM v) { #ifndef NO_GARBAGE_COLLECTOR _ss(v)->ResurrectUnreachable(v); return SQ_OK; #else return sq_throwerror(v,_SC("sq_resurrectunreachable requires a garbage collector build")); #endif } SQInteger sq_collectgarbage(HSQUIRRELVM v) { #ifndef NO_GARBAGE_COLLECTOR return _ss(v)->CollectGarbage(v); #else return -1; #endif } SQRESULT sq_getcallee(HSQUIRRELVM v) { if(v->_callsstacksize > 1) { v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); return SQ_OK; } return sq_throwerror(v,_SC("no closure in the calls stack")); } const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) { SQObjectPtr &self=stack_get(v,idx); const SQChar *name = NULL; switch(sq_type(self)) { case OT_CLOSURE:{ SQClosure *clo = _closure(self); SQFunctionProto *fp = clo->_function; if(((SQUnsignedInteger)fp->_noutervalues) > nval) { v->Push(*(_outer(clo->_outervalues[nval])->_valptr)); SQOuterVar &ov = fp->_outervalues[nval]; name = _stringval(ov._name); } } break; case OT_NATIVECLOSURE:{ SQNativeClosure *clo = _nativeclosure(self); if(clo->_noutervalues > nval) { v->Push(clo->_outervalues[nval]); name = _SC("@NATIVE"); } } break; default: break; //shutup compiler } return name; } SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) { SQObjectPtr &self=stack_get(v,idx); switch(sq_type(self)) { case OT_CLOSURE:{ SQFunctionProto *fp = _closure(self)->_function; if(((SQUnsignedInteger)fp->_noutervalues) > nval){ *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1); } else return sq_throwerror(v,_SC("invalid free var index")); } break; case OT_NATIVECLOSURE: if(_nativeclosure(self)->_noutervalues > nval){ _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1); } else return sq_throwerror(v,_SC("invalid free var index")); break; default: return sq_aux_invalidtype(v, sq_type(self)); } v->Pop(); return SQ_OK; } SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); SQObjectPtr &key = stack_get(v,-2); SQObjectPtr &val = stack_get(v,-1); SQObjectPtr attrs; if(sq_type(key) == OT_NULL) { attrs = _class(*o)->_attributes; _class(*o)->_attributes = val; v->Pop(2); v->Push(attrs); return SQ_OK; }else if(_class(*o)->GetAttributes(key,attrs)) { _class(*o)->SetAttributes(key,val); v->Pop(2); v->Push(attrs); return SQ_OK; } return sq_throwerror(v,_SC("wrong index")); } SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); SQObjectPtr &key = stack_get(v,-1); SQObjectPtr attrs; if(sq_type(key) == OT_NULL) { attrs = _class(*o)->_attributes; v->Pop(); v->Push(attrs); return SQ_OK; } else if(_class(*o)->GetAttributes(key,attrs)) { v->Pop(); v->Push(attrs); return SQ_OK; } return sq_throwerror(v,_SC("wrong index")); } SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); SQObjectPtr &key = stack_get(v,-1); SQTable *m = _class(*o)->_members; SQObjectPtr val; if(m->Get(key,val)) { handle->_static = _isfield(val) ? SQFalse : SQTrue; handle->_index = _member_idx(val); v->Pop(); return SQ_OK; } return sq_throwerror(v,_SC("wrong index")); } SQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,const HSQMEMBERHANDLE *handle,SQObjectPtr *&val) { switch(sq_type(self)) { case OT_INSTANCE: { SQInstance *i = _instance(self); if(handle->_static) { SQClass *c = i->_class; val = &c->_methods[handle->_index].val; } else { val = &i->_values[handle->_index]; } } break; case OT_CLASS: { SQClass *c = _class(self); if(handle->_static) { val = &c->_methods[handle->_index].val; } else { val = &c->_defaultvalues[handle->_index].val; } } break; default: return sq_throwerror(v,_SC("wrong type(expected class or instance)")); } return SQ_OK; } SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle) { SQObjectPtr &self = stack_get(v,idx); SQObjectPtr *val = NULL; if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { return SQ_ERROR; } v->Push(_realval(*val)); return SQ_OK; } SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,const HSQMEMBERHANDLE *handle) { SQObjectPtr &self = stack_get(v,idx); SQObjectPtr &newval = stack_get(v,-1); SQObjectPtr *val = NULL; if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { return SQ_ERROR; } *val = newval; v->Pop(); return SQ_OK; } SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); if(_class(*o)->_base) v->Push(SQObjectPtr(_class(*o)->_base)); else v->PushNull(); return SQ_OK; } SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); v->Push(SQObjectPtr(_instance(*o)->_class)); return SQ_OK; } SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); v->Push(_class(*o)->CreateInstance()); return SQ_OK; } void sq_weakref(HSQUIRRELVM v,SQInteger idx) { SQObject &o=stack_get(v,idx); if(ISREFCOUNTED(sq_type(o))) { v->Push(_refcounted(o)->GetWeakRef(sq_type(o))); return; } v->Push(o); } SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); if(sq_type(o) != OT_WEAKREF) { return sq_throwerror(v,_SC("the object must be a weakref")); } v->Push(_weakref(o)->_obj); return SQ_OK; } SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) { SQSharedState *ss = _ss(v); switch(t) { case OT_TABLE: v->Push(ss->_table_default_delegate); break; case OT_ARRAY: v->Push(ss->_array_default_delegate); break; case OT_STRING: v->Push(ss->_string_default_delegate); break; case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; case OT_THREAD: v->Push(ss->_thread_default_delegate); break; case OT_CLASS: v->Push(ss->_class_default_delegate); break; case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; default: return sq_throwerror(v,_SC("the type doesn't have a default delegate")); } return SQ_OK; } SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; if(sq_type(o) == OT_GENERATOR) { return sq_throwerror(v,_SC("cannot iterate a generator")); } int faketojump; if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump)) return SQ_ERROR; if(faketojump != 666) { v->Push(realkey); v->Push(val); return SQ_OK; } return SQ_ERROR; } struct BufState{ const SQChar *buf; SQInteger ptr; SQInteger size; }; SQInteger buf_lexfeed(SQUserPointer file) { BufState *buf=(BufState*)file; if(buf->size<(buf->ptr+1)) return 0; return buf->buf[buf->ptr++]; } SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { BufState buf; buf.buf = s; buf.size = size; buf.ptr = 0; return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); } void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) { dest->Push(stack_get(src,idx)); } void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc) { _ss(v)->_printfunc = printfunc; _ss(v)->_errorfunc = errfunc; } SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) { return _ss(v)->_printfunc; } SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v) { return _ss(v)->_errorfunc; } void *sq_malloc(SQUnsignedInteger size) { return SQ_MALLOC(size); } void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize) { return SQ_REALLOC(p,oldsize,newsize); } void sq_free(void *p,SQUnsignedInteger size) { SQ_FREE(p,size); } simutrans-124.3/src/squirrel/squirrel/sqarray.h000066400000000000000000000047121474050137200217150ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQARRAY_H_ #define _SQARRAY_H_ struct SQArray : public CHAINABLE_OBJ { private: SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} ~SQArray() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } public: static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){ SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); new (newarray) SQArray(ss,nInitialSize); return newarray; } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); SQObjectType GetType() {return OT_ARRAY;} #endif void Finalize(){ _values.resize(0); } bool Get(const SQInteger nidx,SQObjectPtr &val) { if(nidx>=0 && nidx<(SQInteger)_values.size()){ SQObjectPtr &o = _values[nidx]; val = _realval(o); return true; } else return false; } bool Set(const SQInteger nidx,const SQObjectPtr &val) { if(nidx>=0 && nidx<(SQInteger)_values.size()){ _values[nidx]=val; return true; } else return false; } SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) { SQUnsignedInteger idx=TranslateIndex(refpos); while(idx<_values.size()){ //first found outkey=(SQInteger)idx; SQObjectPtr &o = _values[idx]; outval = _realval(o); //return idx for the next iteration return ++idx; } //nothing to iterate anymore return -1; } SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),0); anew->_values.copy(_values); return anew; } SQInteger Size() const {return _values.size();} void Resize(SQInteger size) { SQObjectPtr _null; Resize(size,_null); } void Resize(SQInteger size,SQObjectPtr &fill) { _values.resize(size,fill); ShrinkIfNeeded(); } void Reserve(SQInteger size) { _values.reserve(size); } void Append(const SQObject &o){_values.push_back(o);} void Extend(const SQArray *a); SQObjectPtr &Top(){return _values.top();} void Pop(){_values.pop_back(); ShrinkIfNeeded(); } bool Insert(SQInteger idx,const SQObject &val){ if(idx < 0 || idx > (SQInteger)_values.size()) return false; _values.insert(idx,val); return true; } void ShrinkIfNeeded() { if(_values.size() <= _values.capacity()>>2) //shrink the array _values.shrinktofit(); } bool Remove(SQInteger idx){ if(idx < 0 || idx >= (SQInteger)_values.size()) return false; _values.remove(idx); ShrinkIfNeeded(); return true; } void Release() { sq_delete(this,SQArray); } SQObjectPtrVec _values; }; #endif simutrans-124.3/src/squirrel/squirrel/sqbaselib.cc000066400000000000000000001044551474050137200223430ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqclass.h" #include #include #include static bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base) { SQChar *end; const SQChar *e = s; bool iseintbase = base > 13; //to fix error converting hexadecimals with e like 56f0791e bool isfloat = false; SQChar c; while((c = *e) != _SC('\0')) { if (c == _SC('.') || (!iseintbase && (c == _SC('E') || c == _SC('e')))) { //e and E is for scientific notation isfloat = true; break; } e++; } if(isfloat){ SQFloat r = SQFloat(scstrtod(s,&end)); if(s == end) return false; res = r; } else{ SQInteger r = SQInteger(scstrtol(s,&end,(int)base)); if(s == end) return false; res = r; } return true; } static SQInteger base_dummy(HSQUIRRELVM SQ_UNUSED_ARG(v)) { return 0; } #ifndef NO_GARBAGE_COLLECTOR static SQInteger base_collectgarbage(HSQUIRRELVM v) { sq_pushinteger(v, sq_collectgarbage(v)); return 1; } static SQInteger base_resurectureachable(HSQUIRRELVM v) { sq_resurrectunreachable(v); return 1; } #endif static SQInteger base_getroottable(HSQUIRRELVM v) { v->Push(v->_roottable); return 1; } static SQInteger base_getconsttable(HSQUIRRELVM v) { v->Push(_ss(v)->_consts); return 1; } static SQInteger base_setroottable(HSQUIRRELVM v) { SQObjectPtr o = v->_roottable; if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; v->Push(o); return 1; } static SQInteger base_setconsttable(HSQUIRRELVM v) { SQObjectPtr o = _ss(v)->_consts; if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR; v->Push(o); return 1; } static SQInteger base_seterrorhandler(HSQUIRRELVM v) { sq_seterrorhandler(v); return 0; } static SQInteger base_setdebughook(HSQUIRRELVM v) { sq_setdebughook(v); return 0; } static SQInteger base_enabledebuginfo(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,2); sq_enabledebuginfo(v,SQVM::IsFalse(o)?SQFalse:SQTrue); return 0; } static SQInteger __getcallstackinfos(HSQUIRRELVM v,SQInteger level) { SQStackInfos si; SQInteger seq = 0; const SQChar *name = NULL; if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) { const SQChar *fn = _SC("unknown"); const SQChar *src = _SC("unknown"); if(si.funcname)fn = si.funcname; if(si.source)src = si.source; sq_newtable(v); sq_pushstring(v, _SC("func"), -1); sq_pushstring(v, fn, -1); sq_newslot(v, -3, SQFalse); sq_pushstring(v, _SC("src"), -1); sq_pushstring(v, src, -1); sq_newslot(v, -3, SQFalse); sq_pushstring(v, _SC("line"), -1); sq_pushinteger(v, si.line); sq_newslot(v, -3, SQFalse); sq_pushstring(v, _SC("locals"), -1); sq_newtable(v); seq=0; while ((name = sq_getlocal(v, level, seq))) { sq_pushstring(v, name, -1); sq_push(v, -2); sq_newslot(v, -4, SQFalse); sq_pop(v, 1); seq++; } sq_newslot(v, -3, SQFalse); return 1; } return 0; } static SQInteger base_getstackinfos(HSQUIRRELVM v) { SQInteger level; sq_getinteger(v, -1, &level); return __getcallstackinfos(v,level); } static SQInteger base_assert(HSQUIRRELVM v) { if(SQVM::IsFalse(stack_get(v,2))){ SQInteger top = sq_gettop(v); if (top>2 && SQ_SUCCEEDED(sq_tostring(v,3))) { const SQChar *str = 0; if (SQ_SUCCEEDED(sq_getstring(v,-1,&str))) { return sq_throwerror(v, str); } } return sq_throwerror(v, _SC("assertion failed")); } return 0; } static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o) { SQInteger top = sq_gettop(v); sidx=0; eidx=0; o=stack_get(v,1); if(top>1){ SQObjectPtr &start=stack_get(v,2); if(sq_type(start)!=OT_NULL && sq_isnumeric(start)){ sidx=tointeger(start); } } if(top>2){ SQObjectPtr &end=stack_get(v,3); if(sq_isnumeric(end)){ eidx=tointeger(end); } } else { eidx = sq_getsize(v,1); } return 1; } static SQInteger base_print(HSQUIRRELVM v) { const SQChar *str; if(SQ_SUCCEEDED(sq_tostring(v,2))) { if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) { if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),str); return 0; } } return SQ_ERROR; } static SQInteger base_error(HSQUIRRELVM v) { const SQChar *str; if(SQ_SUCCEEDED(sq_tostring(v,2))) { if(SQ_SUCCEEDED(sq_getstring(v,-1,&str))) { if(_ss(v)->_errorfunc) _ss(v)->_errorfunc(v,_SC("%s"),str); return 0; } } return SQ_ERROR; } static SQInteger base_compilestring(HSQUIRRELVM v) { SQInteger nargs=sq_gettop(v); const SQChar *src=NULL,*name=_SC("unnamedbuffer"); SQInteger size; sq_getstring(v,2,&src); size=sq_getsize(v,2); if(nargs>2){ sq_getstring(v,3,&name); } if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse))) return 1; else return SQ_ERROR; } static SQInteger base_newthread(HSQUIRRELVM v) { SQObjectPtr &func = stack_get(v,2); SQInteger stksize = (_closure(func)->_function->_stacksize << 1) +2; HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); sq_move(newv,v,-2); return 1; } static SQInteger base_suspend(HSQUIRRELVM v) { return sq_suspendvm(v); } static SQInteger base_array(HSQUIRRELVM v) { SQArray *a; SQObject &size = stack_get(v,2); if(sq_gettop(v) > 2) { a = SQArray::Create(_ss(v),0); a->Resize(tointeger(size),stack_get(v,3)); } else { a = SQArray::Create(_ss(v),tointeger(size)); } v->Push(a); return 1; } static SQInteger base_type(HSQUIRRELVM v) { SQObjectPtr &o = stack_get(v,2); v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); return 1; } static SQInteger base_callee(HSQUIRRELVM v) { if(v->_callsstacksize > 1) { v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); return 1; } return sq_throwerror(v,_SC("no closure in the calls stack")); } static const SQRegFunction base_funcs[]={ //generic {_SC("seterrorhandler"),base_seterrorhandler,2, NULL}, {_SC("setdebughook"),base_setdebughook,2, NULL}, {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL}, {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")}, {_SC("getroottable"),base_getroottable,1, NULL}, {_SC("setroottable"),base_setroottable,2, NULL}, {_SC("getconsttable"),base_getconsttable,1, NULL}, {_SC("setconsttable"),base_setconsttable,2, NULL}, {_SC("assert"),base_assert,-2, NULL}, {_SC("print"),base_print,2, NULL}, {_SC("error"),base_error,2, NULL}, {_SC("compilestring"),base_compilestring,-2, _SC(".ss")}, {_SC("newthread"),base_newthread,2, _SC(".c")}, {_SC("suspend"),base_suspend,-1, NULL}, {_SC("array"),base_array,-2, _SC(".n")}, {_SC("type"),base_type,2, NULL}, {_SC("callee"),base_callee,0,NULL}, {_SC("dummy"),base_dummy,0,NULL}, #ifndef NO_GARBAGE_COLLECTOR {_SC("collectgarbage"),base_collectgarbage,0, NULL}, {_SC("resurrectunreachable"),base_resurectureachable,0, NULL}, #endif {NULL,(SQFUNCTION)0,0,NULL} }; void sq_base_register(HSQUIRRELVM v) { SQInteger i=0; sq_pushroottable(v); while(base_funcs[i].name!=0) { sq_pushstring(v,base_funcs[i].name,-1); sq_newclosure(v,base_funcs[i].f,0); sq_setnativeclosurename(v,-1,base_funcs[i].name); sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask); sq_newslot(v,-3, SQFalse); i++; } sq_pushstring(v,_SC("_versionnumber_"),-1); sq_pushinteger(v,SQUIRREL_VERSION_NUMBER); sq_newslot(v,-3, SQFalse); sq_pushstring(v,_SC("_version_"),-1); sq_pushstring(v,SQUIRREL_VERSION,-1); sq_newslot(v,-3, SQFalse); sq_pushstring(v,_SC("_charsize_"),-1); sq_pushinteger(v,sizeof(SQChar)); sq_newslot(v,-3, SQFalse); sq_pushstring(v,_SC("_intsize_"),-1); sq_pushinteger(v,sizeof(SQInteger)); sq_newslot(v,-3, SQFalse); sq_pushstring(v,_SC("_floatsize_"),-1); sq_pushinteger(v,sizeof(SQFloat)); sq_newslot(v,-3, SQFalse); sq_pop(v,1); } static SQInteger default_delegate_len(HSQUIRRELVM v) { v->Push(SQInteger(sq_getsize(v,1))); return 1; } static SQInteger default_delegate_tofloat(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,1); switch(sq_type(o)){ case OT_STRING:{ SQObjectPtr res; if(str2num(_stringval(o),res,10)){ v->Push(SQObjectPtr(tofloat(res))); break; }} return sq_throwerror(v, _SC("cannot convert the string")); break; case OT_INTEGER:case OT_FLOAT: v->Push(SQObjectPtr(tofloat(o))); break; case OT_BOOL: v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); break; default: v->PushNull(); break; } return 1; } static SQInteger default_delegate_tointeger(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,1); SQInteger base = 10; if(sq_gettop(v) > 1) { sq_getinteger(v,2,&base); } switch(sq_type(o)){ case OT_STRING:{ SQObjectPtr res; if(str2num(_stringval(o),res,base)){ v->Push(SQObjectPtr(tointeger(res))); break; }} return sq_throwerror(v, _SC("cannot convert the string")); break; case OT_INTEGER:case OT_FLOAT: v->Push(SQObjectPtr(tointeger(o))); break; case OT_BOOL: v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0)); break; default: v->PushNull(); break; } return 1; } static SQInteger default_delegate_tostring(HSQUIRRELVM v) { if(SQ_FAILED(sq_tostring(v,1))) return SQ_ERROR; return 1; } static SQInteger obj_delegate_weakref(HSQUIRRELVM v) { sq_weakref(v,1); return 1; } static SQInteger obj_clear(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_clear(v,-1)) ? 1 : SQ_ERROR; } static SQInteger number_delegate_tochar(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); SQChar c = (SQChar)tointeger(o); v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); return 1; } ///////////////////////////////////////////////////////////////// //TABLE DEFAULT DELEGATE static SQInteger table_rawdelete(HSQUIRRELVM v) { if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) return SQ_ERROR; return 1; } static SQInteger container_rawexists(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_rawget(v,-2))) { sq_pushbool(v,SQTrue); return 1; } sq_pushbool(v,SQFalse); return 1; } static SQInteger container_rawset(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_rawset(v,-3)) ? 1 : SQ_ERROR; } static SQInteger container_rawget(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; } static SQInteger table_setdelegate(HSQUIRRELVM v) { if(SQ_FAILED(sq_setdelegate(v,-2))) return SQ_ERROR; sq_push(v,-1); // -1 because sq_setdelegate pops 1 return 1; } static SQInteger table_getdelegate(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR; } static SQInteger table_filter(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); SQTable *tbl = _table(o); SQObjectPtr ret = SQTable::Create(_ss(v),0); SQObjectPtr itr, key, val; SQInteger nitr; while((nitr = tbl->Next(false, itr, key, val)) != -1) { itr = (SQInteger)nitr; v->Push(o); v->Push(key); v->Push(val); if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { return SQ_ERROR; } if(!SQVM::IsFalse(v->GetUp(-1))) { _table(ret)->NewSlot(key, val); } v->Pop(); } v->Push(ret); return 1; } #define TABLE_TO_ARRAY_FUNC(_funcname_,_valname_) static SQInteger _funcname_(HSQUIRRELVM v) \ { \ SQObject &o = stack_get(v, 1); \ SQTable *t = _table(o); \ SQObjectPtr itr, key, val; \ SQObjectPtr _null; \ SQInteger nitr, n = 0; \ SQInteger nitems = t->CountUsed(); \ SQArray *a = SQArray::Create(_ss(v), nitems); \ a->Resize(nitems, _null); \ if (nitems) { \ while ((nitr = t->Next(false, itr, key, val)) != -1) { \ itr = (SQInteger)nitr; \ a->Set(n, _valname_); \ n++; \ } \ } \ v->Push(a); \ return 1; \ } TABLE_TO_ARRAY_FUNC(table_keys, key) TABLE_TO_ARRAY_FUNC(table_values, val) const SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ {_SC("len"),default_delegate_len,1, _SC("t")}, {_SC("rawget"),container_rawget,2, _SC("t")}, {_SC("rawset"),container_rawset,3, _SC("t")}, {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, {_SC("rawin"),container_rawexists,2, _SC("t")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("clear"),obj_clear,1, _SC(".")}, {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")}, {_SC("getdelegate"),table_getdelegate,1, _SC(".")}, {_SC("filter"),table_filter,2, _SC("tc")}, {_SC("keys"),table_keys,1, _SC("t") }, {_SC("values"),table_values,1, _SC("t") }, {NULL,(SQFUNCTION)0,0,NULL} }; //ARRAY DEFAULT DELEGATE/////////////////////////////////////// static SQInteger array_append(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_arrayappend(v,-2)) ? 1 : SQ_ERROR; } static SQInteger array_extend(HSQUIRRELVM v) { _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); sq_pop(v,1); return 1; } static SQInteger array_reverse(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_arrayreverse(v,-1)) ? 1 : SQ_ERROR; } static SQInteger array_pop(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; } static SQInteger array_top(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); if(_array(o)->Size()>0){ v->Push(_array(o)->Top()); return 1; } else return sq_throwerror(v,_SC("top() on a empty array")); } static SQInteger array_insert(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); SQObject &idx=stack_get(v,2); SQObject &val=stack_get(v,3); if(!_array(o)->Insert(tointeger(idx),val)) return sq_throwerror(v,_SC("index out of range")); sq_pop(v,2); return 1; } static SQInteger array_remove(HSQUIRRELVM v) { SQObject &o = stack_get(v, 1); SQObject &idx = stack_get(v, 2); if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type")); SQObjectPtr val; if(_array(o)->Get(tointeger(idx), val)) { _array(o)->Remove(tointeger(idx)); v->Push(val); return 1; } return sq_throwerror(v, _SC("idx out of range")); } static SQInteger array_resize(HSQUIRRELVM v) { SQObject &o = stack_get(v, 1); SQObject &nsize = stack_get(v, 2); SQObjectPtr fill; if(sq_isnumeric(nsize)) { SQInteger sz = tointeger(nsize); if (sz<0) return sq_throwerror(v, _SC("resizing to negative length")); if(sq_gettop(v) > 2) fill = stack_get(v, 3); _array(o)->Resize(sz,fill); sq_settop(v, 1); return 1; } return sq_throwerror(v, _SC("size must be a number")); } static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) { SQObjectPtr temp; SQInteger size = src->Size(); SQObject &closure = stack_get(v, 2); v->Push(closure); SQInteger nArgs = 0; if(sq_type(closure) == OT_CLOSURE) { nArgs = _closure(closure)->_function->_nparameters; } else if (sq_type(closure) == OT_NATIVECLOSURE) { SQInteger nParamsCheck = _nativeclosure(closure)->_nparamscheck; if (nParamsCheck > 0) nArgs = nParamsCheck; else // push all params when there is no check or only minimal count set nArgs = 4; } for(SQInteger n = 0; n < size; n++) { src->Get(n,temp); v->Push(src); v->Push(temp); if (nArgs >= 3) v->Push(SQObjectPtr(n)); if (nArgs >= 4) v->Push(src); if(SQ_FAILED(sq_call(v,nArgs,SQTrue,SQFalse))) { return SQ_ERROR; } dest->Set(n,v->GetUp(-1)); v->Pop(); } v->Pop(); return 0; } static SQInteger array_map(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); SQInteger size = _array(o)->Size(); SQObjectPtr ret = SQArray::Create(_ss(v),size); if(SQ_FAILED(__map_array(_array(ret),_array(o),v))) return SQ_ERROR; v->Push(ret); return 1; } static SQInteger array_apply(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); if(SQ_FAILED(__map_array(_array(o),_array(o),v))) return SQ_ERROR; sq_pop(v,1); return 1; } static SQInteger array_reduce(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); SQArray *a = _array(o); SQInteger size = a->Size(); SQObjectPtr res; SQInteger iterStart; if (sq_gettop(v)>2) { res = stack_get(v,3); iterStart = 0; } else if (size==0) { return 0; } else { a->Get(0,res); iterStart = 1; } if (size > iterStart) { SQObjectPtr other; v->Push(stack_get(v,2)); for (SQInteger n = iterStart; n < size; n++) { a->Get(n,other); v->Push(o); v->Push(res); v->Push(other); if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { return SQ_ERROR; } res = v->GetUp(-1); v->Pop(); } v->Pop(); } v->Push(res); return 1; } static SQInteger array_filter(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); SQArray *a = _array(o); SQObjectPtr ret = SQArray::Create(_ss(v),0); SQInteger size = a->Size(); SQObjectPtr val; for(SQInteger n = 0; n < size; n++) { a->Get(n,val); v->Push(o); v->Push(n); v->Push(val); if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { return SQ_ERROR; } if(!SQVM::IsFalse(v->GetUp(-1))) { _array(ret)->Append(val); } v->Pop(); } v->Push(ret); return 1; } static SQInteger array_find(HSQUIRRELVM v) { SQObject &o = stack_get(v,1); SQObjectPtr &val = stack_get(v,2); SQArray *a = _array(o); SQInteger size = a->Size(); SQObjectPtr temp; for(SQInteger n = 0; n < size; n++) { bool res = false; a->Get(n,temp); if(SQVM::IsEqual(temp,val,res) && res) { v->Push(n); return 1; } } return 0; } static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) { if(func < 0) { if(!v->ObjCmp(a,b,ret)) return false; } else { SQInteger top = sq_gettop(v); sq_push(v, func); sq_pushroottable(v); v->Push(a); v->Push(b); SQObjectPtr *valptr = arr->_values._vals; SQUnsignedInteger precallsize = arr->_values.size(); if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { if(!sq_isstring( v->_lasterror)) v->Raise_Error(_SC("compare func failed")); return false; } if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { v->Raise_Error(_SC("numeric value expected as return value of the compare function")); return false; } if (precallsize != arr->_values.size() || valptr != arr->_values._vals) { v->Raise_Error(_SC("array resized during sort operation")); return false; } sq_settop(v, top); return true; } return true; } static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func) { SQInteger maxChild; SQInteger done = 0; SQInteger ret; SQInteger root2; while (((root2 = root * 2) <= bottom) && (!done)) { if (root2 == bottom) { maxChild = root2; } else { if(!_sort_compare(v,arr,arr->_values[root2],arr->_values[root2 + 1],func,ret)) return false; if (ret > 0) { maxChild = root2; } else { maxChild = root2 + 1; } } if(!_sort_compare(v,arr,arr->_values[root],arr->_values[maxChild],func,ret)) return false; if (ret < 0) { if (root == maxChild) { v->Raise_Error(_SC("inconsistent compare function")); return false; // We'd be swapping ourselve. The compare function is incorrect } _Swap(arr->_values[root],arr->_values[maxChild]); root = maxChild; } else { done = 1; } } return true; } static bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger SQ_UNUSED_ARG(l), SQInteger SQ_UNUSED_ARG(r),SQInteger func) { SQArray *a = _array(arr); SQInteger i; SQInteger array_size = a->Size(); for (i = (array_size / 2); i >= 0; i--) { if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false; } for (i = array_size-1; i >= 1; i--) { _Swap(a->_values[0],a->_values[i]); if(!_hsort_sift_down(v,a, 0, i-1,func)) return false; } return true; } static SQInteger array_sort(HSQUIRRELVM v) { SQInteger func = -1; SQObjectPtr &o = stack_get(v,1); if(_array(o)->Size() > 1) { if(sq_gettop(v) == 2) func = 2; if(!_hsort(v, o, 0, _array(o)->Size()-1, func)) return SQ_ERROR; } sq_settop(v,1); return 1; } static SQInteger array_slice(HSQUIRRELVM v) { SQInteger sidx,eidx; SQObjectPtr o; if(get_slice_params(v,sidx,eidx,o)==-1)return -1; SQInteger alen = _array(o)->Size(); if(sidx < 0)sidx = alen + sidx; if(eidx < 0)eidx = alen + eidx; if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes")); if(eidx > alen || sidx < 0)return sq_throwerror(v, _SC("slice out of range")); SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); SQObjectPtr t; SQInteger count=0; for(SQInteger i=sidx;iGet(i,t); arr->Set(count++,t); } v->Push(arr); return 1; } const SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ {_SC("len"),default_delegate_len,1, _SC("a")}, {_SC("append"),array_append,2, _SC("a")}, {_SC("extend"),array_extend,2, _SC("aa")}, {_SC("push"),array_append,2, _SC("a")}, {_SC("pop"),array_pop,1, _SC("a")}, {_SC("top"),array_top,1, _SC("a")}, {_SC("insert"),array_insert,3, _SC("an")}, {_SC("remove"),array_remove,2, _SC("an")}, {_SC("resize"),array_resize,-2, _SC("an")}, {_SC("reverse"),array_reverse,1, _SC("a")}, {_SC("sort"),array_sort,-1, _SC("ac")}, {_SC("slice"),array_slice,-1, _SC("ann")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("clear"),obj_clear,1, _SC(".")}, {_SC("map"),array_map,2, _SC("ac")}, {_SC("apply"),array_apply,2, _SC("ac")}, {_SC("reduce"),array_reduce,-2, _SC("ac.")}, {_SC("filter"),array_filter,2, _SC("ac")}, {_SC("find"),array_find,2, _SC("a.")}, {NULL,(SQFUNCTION)0,0,NULL} }; //STRING DEFAULT DELEGATE////////////////////////// static SQInteger string_slice(HSQUIRRELVM v) { SQInteger sidx,eidx; SQObjectPtr o; if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; SQInteger slen = _string(o)->_len; if(sidx < 0)sidx = slen + sidx; if(eidx < 0)eidx = slen + eidx; if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); if(eidx > slen || sidx < 0) return sq_throwerror(v, _SC("slice out of range")); v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); return 1; } static SQInteger string_find(HSQUIRRELVM v) { SQInteger top,start_idx=0; const SQChar *str,*substr,*ret; if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){ if(top>2)sq_getinteger(v,3,&start_idx); if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){ ret=scstrstr(&str[start_idx],substr); if(ret){ sq_pushinteger(v,(SQInteger)(ret-str)); return 1; } } return 0; } return sq_throwerror(v,_SC("invalid param")); } #define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ {\ SQInteger sidx,eidx; \ SQObjectPtr str; \ if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \ SQInteger slen = _string(str)->_len; \ if(sidx < 0)sidx = slen + sidx; \ if(eidx < 0)eidx = slen + eidx; \ if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); \ if(eidx > slen || sidx < 0) return sq_throwerror(v,_SC("slice out of range")); \ SQInteger len=_string(str)->_len; \ const SQChar *sthis=_stringval(str); \ SQChar *snew=(_ss(v)->GetScratchPad(sq_rsl(len))); \ memcpy(snew,sthis,sq_rsl(len));\ for(SQInteger i=sidx;iPush(SQString::Create(_ss(v),snew,len)); \ return 1; \ } static char toalnum(char c) { return isalnum(c) && c >=0 ? c : '_'; } STRING_TOFUNCZ(tolower) STRING_TOFUNCZ(toupper) STRING_TOFUNCZ(toalnum) const SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ {_SC("len"),default_delegate_len,1, _SC("s")}, {_SC("tointeger"),default_delegate_tointeger,-1, _SC("sn")}, {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("slice"),string_slice,-1, _SC("s n n")}, {_SC("find"),string_find,-2, _SC("s s n")}, {_SC("tolower"),string_tolower,-1, _SC("s n n")}, {_SC("toupper"),string_toupper,-1, _SC("s n n")}, {_SC("toalnum"),string_toalnum,1, _SC("s")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {NULL,(SQFUNCTION)0,0,NULL} }; //INTEGER DEFAULT DELEGATE////////////////////////// const SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {NULL,(SQFUNCTION)0,0,NULL} }; //CLOSURE DEFAULT DELEGATE////////////////////////// static SQInteger closure_pcall(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; } static SQInteger closure_call(HSQUIRRELVM v) { /* has to wait until sq_tailcall is enabled SQObjectPtr &c = stack_get(v, -1); if (sq_type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false)) { return sq_tailcall(v, sq_gettop(v) - 1); } */ return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR; } static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) { SQArray *aparams=_array(stack_get(v,2)); SQInteger nparams=aparams->Size(); v->Push(stack_get(v,1)); for(SQInteger i=0;iPush(aparams->_values[i]); return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR; } static SQInteger closure_acall(HSQUIRRELVM v) { return _closure_acall(v,SQTrue); } static SQInteger closure_pacall(HSQUIRRELVM v) { return _closure_acall(v,SQFalse); } static SQInteger closure_bindenv(HSQUIRRELVM v) { if(SQ_FAILED(sq_bindenv(v,1))) return SQ_ERROR; return 1; } static SQInteger closure_getroot(HSQUIRRELVM v) { if(SQ_FAILED(sq_getclosureroot(v,-1))) return SQ_ERROR; return 1; } static SQInteger closure_setroot(HSQUIRRELVM v) { if(SQ_FAILED(sq_setclosureroot(v,-2))) return SQ_ERROR; return 1; } static SQInteger closure_getinfos(HSQUIRRELVM v) { SQObject o = stack_get(v,1); SQTable *res = SQTable::Create(_ss(v),4); if(sq_type(o) == OT_CLOSURE) { SQFunctionProto *f = _closure(o)->_function; SQInteger nparams = f->_nparameters + (f->_varparams?1:0); SQObjectPtr params = SQArray::Create(_ss(v),nparams); SQObjectPtr defparams = SQArray::Create(_ss(v),f->_ndefaultparams); for(SQInteger n = 0; n_nparameters; n++) { _array(params)->Set((SQInteger)n,f->_parameters[n]); } for(SQInteger j = 0; j_ndefaultparams; j++) { _array(defparams)->Set((SQInteger)j,_closure(o)->_defaultparams[j]); } if(f->_varparams) { _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1)); } res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false); res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name); res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename); res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params); res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams); res->NewSlot(SQString::Create(_ss(v),_SC("defparams"),-1),defparams); } else { //OT_NATIVECLOSURE SQNativeClosure *nc = _nativeclosure(o); res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true); res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name); res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck); SQObjectPtr typecheck; if(nc->_typecheck.size() > 0) { typecheck = SQArray::Create(_ss(v), nc->_typecheck.size()); for(SQUnsignedInteger n = 0; n_typecheck.size(); n++) { _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); } } res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck); } v->Push(res); return 1; } const SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ {_SC("call"),closure_call,-1, _SC("c")}, {_SC("pcall"),closure_pcall,-1, _SC("c")}, {_SC("acall"),closure_acall,2, _SC("ca")}, {_SC("pacall"),closure_pacall,2, _SC("ca")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")}, {_SC("getinfos"),closure_getinfos,1, _SC("c")}, {_SC("getroot"),closure_getroot,1, _SC("c")}, {_SC("setroot"),closure_setroot,2, _SC("ct")}, {NULL,(SQFUNCTION)0,0,NULL} }; //GENERATOR DEFAULT DELEGATE static SQInteger generator_getstatus(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); switch(_generator(o)->_state){ case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break; case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break; case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break; } return 1; } const SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ {_SC("getstatus"),generator_getstatus,1, _SC("g")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {NULL,(SQFUNCTION)0,0,NULL} }; //THREAD DEFAULT DELEGATE static SQInteger thread_call(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(sq_type(o) == OT_THREAD) { SQInteger nparams = sq_gettop(v); _thread(o)->Push(_thread(o)->_roottable); for(SQInteger i = 2; i<(nparams+1); i++) sq_move(_thread(o),v,i); if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQTrue))) { sq_move(v,_thread(o),-1); sq_pop(_thread(o),1); return 1; } v->_lasterror = _thread(o)->_lasterror; return SQ_ERROR; } return sq_throwerror(v,_SC("wrong parameter")); } static SQInteger thread_wakeup(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(sq_type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger state = sq_getvmstate(thread); if(state != SQ_VMSTATE_SUSPENDED) { switch(state) { case SQ_VMSTATE_IDLE: return sq_throwerror(v,_SC("cannot wakeup a idle thread")); break; case SQ_VMSTATE_RUNNING: return sq_throwerror(v,_SC("cannot wakeup a running thread")); break; } } SQInteger wakeupret = sq_gettop(v)>1?SQTrue:SQFalse; if(wakeupret) { sq_move(thread,v,2); } if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) { sq_move(v,thread,-1); sq_pop(thread,1); //pop retval if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { sq_settop(thread,1); //pop roottable } return 1; } sq_settop(thread,1); v->_lasterror = thread->_lasterror; return SQ_ERROR; } return sq_throwerror(v,_SC("wrong parameter")); } static SQInteger thread_wakeupthrow(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(sq_type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger state = sq_getvmstate(thread); if(state != SQ_VMSTATE_SUSPENDED) { switch(state) { case SQ_VMSTATE_IDLE: return sq_throwerror(v,_SC("cannot wakeup a idle thread")); break; case SQ_VMSTATE_RUNNING: return sq_throwerror(v,_SC("cannot wakeup a running thread")); break; } } sq_move(thread,v,2); sq_throwobject(thread); SQBool rethrow_error = SQTrue; if(sq_gettop(v) > 2) { sq_getbool(v,3,&rethrow_error); } if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) { sq_move(v,thread,-1); sq_pop(thread,1); //pop retval if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { sq_settop(thread,1); //pop roottable } return 1; } sq_settop(thread,1); if(rethrow_error) { v->_lasterror = thread->_lasterror; return SQ_ERROR; } return SQ_OK; } return sq_throwerror(v,_SC("wrong parameter")); } static SQInteger thread_getstatus(HSQUIRRELVM v) { SQObjectPtr &o = stack_get(v,1); switch(sq_getvmstate(_thread(o))) { case SQ_VMSTATE_IDLE: sq_pushstring(v,_SC("idle"),-1); break; case SQ_VMSTATE_RUNNING: sq_pushstring(v,_SC("running"),-1); break; case SQ_VMSTATE_SUSPENDED: sq_pushstring(v,_SC("suspended"),-1); break; default: return sq_throwerror(v,_SC("internal VM error")); } return 1; } static SQInteger thread_getstackinfos(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(sq_type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger threadtop = sq_gettop(thread); SQInteger level; sq_getinteger(v,-1,&level); SQRESULT res = __getcallstackinfos(thread,level); if(SQ_FAILED(res)) { sq_settop(thread,threadtop); if(sq_type(thread->_lasterror) == OT_STRING) { sq_throwerror(v,_stringval(thread->_lasterror)); } else { sq_throwerror(v,_SC("unknown error")); } } if(res > 0) { //some result sq_move(v,thread,-1); sq_settop(thread,threadtop); return 1; } //no result sq_settop(thread,threadtop); return 0; } return sq_throwerror(v,_SC("wrong parameter")); } const SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { {_SC("call"), thread_call, -1, _SC("v")}, {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, {_SC("wakeupthrow"), thread_wakeupthrow, -2, _SC("v.b")}, {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")}, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {NULL,(SQFUNCTION)0,0,NULL} }; static SQInteger class_getattributes(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR; } static SQInteger class_setattributes(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR; } static SQInteger class_instance(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR; } static SQInteger class_getbase(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR; } static SQInteger class_newmember(HSQUIRRELVM v) { SQInteger top = sq_gettop(v); SQBool bstatic = SQFalse; if(top == 5) { sq_tobool(v,-1,&bstatic); sq_pop(v,1); } if(top < 4) { sq_pushnull(v); } return SQ_SUCCEEDED(sq_newmember(v,-4,bstatic))?1:SQ_ERROR; } static SQInteger class_rawnewmember(HSQUIRRELVM v) { SQInteger top = sq_gettop(v); SQBool bstatic = SQFalse; if(top == 5) { sq_tobool(v,-1,&bstatic); sq_pop(v,1); } if(top < 4) { sq_pushnull(v); } return SQ_SUCCEEDED(sq_rawnewmember(v,-4,bstatic))?1:SQ_ERROR; } const SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, {_SC("rawget"),container_rawget,2, _SC("y")}, {_SC("rawset"),container_rawset,3, _SC("y")}, {_SC("rawin"),container_rawexists,2, _SC("y")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("instance"),class_instance,1, _SC("y")}, {_SC("getbase"),class_getbase,1, _SC("y")}, {_SC("newmember"),class_newmember,-3, _SC("y")}, {_SC("rawnewmember"),class_rawnewmember,-3, _SC("y")}, {NULL,(SQFUNCTION)0,0,NULL} }; static SQInteger instance_getclass(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_getclass(v,1))) return 1; return SQ_ERROR; } const SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { {_SC("getclass"), instance_getclass, 1, _SC("x")}, {_SC("rawget"),container_rawget,2, _SC("x")}, {_SC("rawset"),container_rawset,3, _SC("x")}, {_SC("rawin"),container_rawexists,2, _SC("x")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {NULL,(SQFUNCTION)0,0,NULL} }; static SQInteger weakref_ref(HSQUIRRELVM v) { if(SQ_FAILED(sq_getweakrefval(v,1))) return SQ_ERROR; return 1; } const SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { {_SC("ref"),weakref_ref,1, _SC("r")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {NULL,(SQFUNCTION)0,0,NULL} }; simutrans-124.3/src/squirrel/squirrel/sqclass.cc000066400000000000000000000121611474050137200220370ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqtable.h" #include "sqclass.h" #include "sqfuncproto.h" #include "sqclosure.h" SQClass::SQClass(SQSharedState *ss,SQClass *base) { _base = base; _typetag = 0; _hook = NULL; _udsize = 0; _locked = false; _constructoridx = -1; if(_base) { _constructoridx = _base->_constructoridx; _udsize = _base->_udsize; _defaultvalues.copy(base->_defaultvalues); _methods.copy(base->_methods); _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST); __ObjAddRef(_base); } _members = base?base->_members->Clone() : SQTable::Create(ss,0); __ObjAddRef(_members); INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } void SQClass::Finalize() { _attributes.Null(); _NULL_SQOBJECT_VECTOR(_defaultvalues,_defaultvalues.size()); _methods.resize(0); _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST); __ObjRelease(_members); if(_base) { __ObjRelease(_base); } } SQClass::~SQClass() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); Finalize(); } bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { SQObjectPtr temp; bool belongs_to_static_table = sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE || bstatic; if(_locked && !belongs_to_static_table) return false; //the class already has an instance so cannot be modified if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value { _defaultvalues[_member_idx(temp)].val = val; return true; } if (_members->CountUsed() >= MEMBER_MAX_COUNT) { return false; } if(belongs_to_static_table) { SQInteger mmidx; if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) && (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { _metamethods[mmidx] = val; } else { SQObjectPtr theval = val; if(_base && sq_type(val) == OT_CLOSURE) { theval = _closure(val)->Clone(); _closure(theval)->_base = _base; __ObjAddRef(_base); //ref for the closure } if(sq_type(temp) == OT_NULL) { bool isconstructor; SQVM::IsEqual(ss->_constructoridx, key, isconstructor); if(isconstructor) { _constructoridx = (SQInteger)_methods.size(); } SQClassMember m; m.val = theval; _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); _methods.push_back(m); } else { _methods[_member_idx(temp)].val = theval; } } return true; } SQClassMember m; m.val = val; _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); _defaultvalues.push_back(m); return true; } SQInstance *SQClass::CreateInstance() { if(!_locked) Lock(); return SQInstance::Create(_opt_ss(this),this); } SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQObjectPtr oval; SQInteger idx = _members->Next(false,refpos,outkey,oval); if(idx != -1) { if(_ismethod(oval)) { outval = _methods[_member_idx(oval)].val; } else { SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; outval = _realval(o); } } return idx; } bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) { SQObjectPtr idx; if(_members->Get(key,idx)) { if(_isfield(idx)) _defaultvalues[_member_idx(idx)].attrs = val; else _methods[_member_idx(idx)].attrs = val; return true; } return false; } bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) { SQObjectPtr idx; if(_members->Get(key,idx)) { outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); return true; } return false; } /////////////////////////////////////////////////////////////////////// void SQInstance::Init(SQSharedState *ss) { _userpointer = NULL; _hook = NULL; __ObjAddRef(_class); _delegate = _class->_members; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) { _memsize = memsize; _class = c; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); } Init(ss); } SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) { _memsize = memsize; _class = i->_class; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(i->_values[n]); } Init(ss); } void SQInstance::Finalize() { SQUnsignedInteger nvalues = _class->_defaultvalues.size(); __ObjRelease(_class); _NULL_SQOBJECT_VECTOR(_values,nvalues); } SQInstance::~SQInstance() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); if(_class){ Finalize(); } //if _class is null it was already finalized by the GC } bool SQInstance::GetMetaMethod(SQVM* SQ_UNUSED_ARG(v),SQMetaMethod mm,SQObjectPtr &res) { if(sq_type(_class->_metamethods[mm]) != OT_NULL) { res = _class->_metamethods[mm]; return true; } return false; } bool SQInstance::InstanceOf(SQClass *trg) { SQClass *parent = _class; while(parent != NULL) { if(parent == trg) return true; parent = parent->_base; } return false; } simutrans-124.3/src/squirrel/squirrel/sqclass.h000066400000000000000000000105451474050137200217050ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQCLASS_H_ #define _SQCLASS_H_ struct SQInstance; struct SQClassMember { SQObjectPtr val; SQObjectPtr attrs; void Null() { val.Null(); attrs.Null(); } }; typedef sqvector SQClassMemberVec; #define MEMBER_TYPE_METHOD 0x01000000 #define MEMBER_TYPE_FIELD 0x02000000 #define MEMBER_MAX_COUNT 0x00FFFFFF #define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) #define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) #define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i)) #define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i)) #define _member_type(o) (_integer(o)&0xFF000000) #define _member_idx(o) (_integer(o)&0x00FFFFFF) struct SQClass : public CHAINABLE_OBJ { SQClass(SQSharedState *ss,SQClass *base); public: static SQClass* Create(SQSharedState *ss,SQClass *base) { SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); new (newclass) SQClass(ss, base); return newclass; } ~SQClass(); bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); bool Get(const SQObjectPtr &key,SQObjectPtr &val) { if(_members->Get(key,val)) { if(_isfield(val)) { SQObjectPtr &o = _defaultvalues[_member_idx(val)].val; val = _realval(o); } else { val = _methods[_member_idx(val)].val; } return true; } return false; } bool GetConstructor(SQObjectPtr &ctor) { if(_constructoridx != -1) { ctor = _methods[_constructoridx].val; return true; } return false; } bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); void Lock() { _locked = true; if(_base) _base->Lock(); } void Release() { if (_hook) { _hook(_typetag,0);} sq_delete(this, SQClass); } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); SQObjectType GetType() {return OT_CLASS;} #endif SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInstance *CreateInstance(); SQTable *_members; SQClass *_base; SQClassMemberVec _defaultvalues; SQClassMemberVec _methods; SQObjectPtr _metamethods[MT_LAST]; SQObjectPtr _attributes; SQUserPointer _typetag; SQRELEASEHOOK _hook; bool _locked; SQInteger _constructoridx; SQInteger _udsize; }; #define calcinstancesize(_theclass_) \ (_theclass_->_udsize + sq_aligning(sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0)))) struct SQInstance : public SQDelegable { void Init(SQSharedState *ss); SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize); SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize); public: static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { SQInteger size = calcinstancesize(theclass); SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); new (newinst) SQInstance(ss, theclass,size); if(theclass->_udsize) { newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); } return newinst; } SQInstance *Clone(SQSharedState *ss) { SQInteger size = calcinstancesize(_class); SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); new (newinst) SQInstance(ss, this,size); if(_class->_udsize) { newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); } return newinst; } ~SQInstance(); bool Get(const SQObjectPtr &key,SQObjectPtr &val) { if(_class->_members->Get(key,val)) { if(_isfield(val)) { SQObjectPtr &o = _values[_member_idx(val)]; val = _realval(o); } else { val = _class->_methods[_member_idx(val)].val; } return true; } return false; } bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { SQObjectPtr idx; if(_class->_members->Get(key,idx) && _isfield(idx)) { _values[_member_idx(idx)] = val; return true; } return false; } void Release() { _uiRef++; if (_hook) { _hook(_userpointer,0);} _uiRef--; if(_uiRef > 0) return; SQInteger size = _memsize; this->~SQInstance(); SQ_FREE(this, size); } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); SQObjectType GetType() {return OT_INSTANCE;} #endif bool InstanceOf(SQClass *trg); bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQClass *_class; SQUserPointer _userpointer; SQRELEASEHOOK _hook; SQInteger _memsize; SQObjectPtr _values[1]; }; #endif simutrans-124.3/src/squirrel/squirrel/sqclosure.h000066400000000000000000000137771474050137200222660ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQCLOSURE_H_ #define _SQCLOSURE_H_ #define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr))) struct SQFunctionProto; struct SQClass; struct SQClosure : public CHAINABLE_OBJ { private: SQClosure(SQSharedState *ss,SQFunctionProto *func){_function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL; _root=NULL;} public: static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func,SQWeakRef *root){ SQInteger size = _CALC_CLOSURE_SIZE(func); SQClosure *nc=(SQClosure*)SQ_MALLOC(size); new (nc) SQClosure(ss,func); nc->_outervalues = (SQObjectPtr *)(nc + 1); nc->_defaultparams = &nc->_outervalues[func->_noutervalues]; nc->_root = root; __ObjAddRef(nc->_root); _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues); _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams); return nc; } void Release(){ SQFunctionProto *f = _function; SQInteger size = _CALC_CLOSURE_SIZE(f); _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues); _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams); __ObjRelease(_function); this->~SQClosure(); sq_vm_free(this,size); } void SetRoot(SQWeakRef *r) { __ObjRelease(_root); _root = r; __ObjAddRef(_root); } SQClosure *Clone() { SQFunctionProto *f = _function; SQClosure * ret = SQClosure::Create(_opt_ss(this),f,_root); ret->_env = _env; if(ret->_env) __ObjAddRef(ret->_env); _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues); _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams); return ret; } ~SQClosure(); bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){ SQFunctionProto *f = _function; _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues); _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams); } SQObjectType GetType() {return OT_CLOSURE;} #endif SQWeakRef *_env; SQWeakRef *_root; SQClass *_base; SQFunctionProto *_function; SQObjectPtr *_outervalues; SQObjectPtr *_defaultparams; }; ////////////////////////////////////////////// struct SQOuter : public CHAINABLE_OBJ { private: SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } public: static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer) { SQOuter *nc = (SQOuter*)SQ_MALLOC(sizeof(SQOuter)); new (nc) SQOuter(ss, outer); return nc; } ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } void Release() { this->~SQOuter(); sq_vm_free(this,sizeof(SQOuter)); } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize() { _value.Null(); } SQObjectType GetType() {return OT_OUTER;} #endif SQObjectPtr *_valptr; /* pointer to value on stack, or _value below */ SQInteger _idx; /* idx in stack array, for relocation */ SQObjectPtr _value; /* value of outer after stack frame is closed */ SQOuter *_next; /* pointer to next outer when frame is open */ }; ////////////////////////////////////////////// struct SQGenerator : public CHAINABLE_OBJ { enum SQGeneratorState{eRunning,eSuspended,eDead}; private: SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} public: static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); new (nc) SQGenerator(ss,closure); return nc; } ~SQGenerator() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } void Kill(){ _state=eDead; _stack.resize(0); _closure.Null();} void Release(){ sq_delete(this,SQGenerator); } bool Yield(SQVM *v,SQInteger target); bool Resume(SQVM *v,SQObjectPtr &dest); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){_stack.resize(0);_closure.Null();} SQObjectType GetType() {return OT_GENERATOR;} #endif SQObjectPtr _closure; SQObjectPtrVec _stack; SQVM::CallInfo _ci; ExceptionsTraps _etraps; SQGeneratorState _state; }; #define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + (noutervalues*sizeof(SQObjectPtr))) struct SQNativeClosure : public CHAINABLE_OBJ { private: SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;} public: static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters) { SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters); SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(size); new (nc) SQNativeClosure(ss,func); nc->_outervalues = (SQObjectPtr *)(nc + 1); nc->_noutervalues = nouters; _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues); return nc; } SQNativeClosure *Clone() { SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues); ret->_env = _env; if(ret->_env) __ObjAddRef(ret->_env); ret->_name = _name; _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues); ret->_typecheck.copy(_typecheck); ret->_nparamscheck = _nparamscheck; return ret; } ~SQNativeClosure() { __ObjRelease(_env); REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } void Release(){ SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues); _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues); this->~SQNativeClosure(); sq_free(this,size); } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); } SQObjectType GetType() {return OT_NATIVECLOSURE;} #endif SQInteger _nparamscheck; SQIntVec _typecheck; SQObjectPtr *_outervalues; SQUnsignedInteger _noutervalues; SQWeakRef *_env; SQFUNCTION _function; SQObjectPtr _name; }; #endif simutrans-124.3/src/squirrel/squirrel/sqcompiler.cc000066400000000000000000001315411474050137200225500ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #ifndef NO_COMPILER #include #include #include "sqopcodes.h" #include "sqstring.h" #include "sqfuncproto.h" #include "sqcompiler.h" #include "sqfuncstate.h" #include "sqlexer.h" #include "sqvm.h" #include "sqtable.h" #define EXPR 1 #define OBJECT 2 #define BASE 3 #define LOCAL 4 #define OUTER 5 struct SQExpState { SQInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */ SQInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */ bool donot_get; /* signal not to deref the next value */ }; #define MAX_COMPILER_ERROR_LEN 256 struct SQScope { SQInteger outers; SQInteger stacksize; }; #define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \ _scope.outers = _fs->_outers; \ _scope.stacksize = _fs->GetStackSize(); #define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \ if(_fs->CountOuters(_scope.stacksize)) { \ _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ } \ } #define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \ _fs->SetStackSize(_scope.stacksize); \ } \ _scope = __oldscope__; \ } #define END_SCOPE() { SQInteger oldouters = _fs->_outers;\ if(_fs->GetStackSize() != _scope.stacksize) { \ _fs->SetStackSize(_scope.stacksize); \ if(oldouters != _fs->_outers) { \ _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ } \ } \ _scope = __oldscope__; \ } #define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \ SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \ _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} class SQCompiler { public: SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) { _vm=v; _lex.Init(_ss(v), rg, up,ThrowError,this); _sourcename = SQString::Create(_ss(v), sourcename); _lineinfo = lineinfo;_raiseerror = raiseerror; _scope.outers = 0; _scope.stacksize = 0; _compilererror[0] = _SC('\0'); } static void ThrowError(void *ud, const SQChar *s) { SQCompiler *c = (SQCompiler *)ud; c->Error(s); } void Error(const SQChar *s, ...) { va_list vl; va_start(vl, s); scvsprintf(_compilererror, MAX_COMPILER_ERROR_LEN, s, vl); va_end(vl); longjmp(_errorjmp,1); } void Lex(){ _token = _lex.Lex();} SQObject Expect(SQInteger tok) { if(_token != tok) { if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { //do nothing } else { const SQChar *etypename; if(tok > 255) { switch(tok) { case TK_IDENTIFIER: etypename = _SC("IDENTIFIER"); break; case TK_STRING_LITERAL: etypename = _SC("STRING_LITERAL"); break; case TK_INTEGER: etypename = _SC("INTEGER"); break; case TK_FLOAT: etypename = _SC("FLOAT"); break; default: etypename = _lex.Tok2Str(tok); } Error(_SC("expected '%s'"), etypename); } Error(_SC("expected '%c'"), tok); } } SQObjectPtr ret; switch(tok) { case TK_IDENTIFIER: ret = _fs->CreateString(_lex._svalue); break; case TK_STRING_LITERAL: ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); break; case TK_INTEGER: ret = SQObjectPtr(_lex._nvalue); break; case TK_FLOAT: ret = SQObjectPtr(_lex._fvalue); break; } Lex(); return ret; } bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); } void OptionalSemicolon() { if(_token == _SC(';')) { Lex(); return; } if(!IsEndOfStatement()) { Error(_SC("end of statement expected (; or lf)")); } } void MoveIfCurrentTargetIsLocal() { SQInteger trg = _fs->TopTarget(); if(_fs->IsLocal(trg)) { trg = _fs->PopTarget(); //pops the target and moves it _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); } } bool Compile(SQObjectPtr &o) { _debugline = 1; _debugop = 0; SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this); funcstate._name = SQString::Create(_ss(_vm), _SC("main")); _fs = &funcstate; _fs->AddParameter(_fs->CreateString(_SC("this"))); _fs->AddParameter(_fs->CreateString(_SC("vargv"))); _fs->_varparams = true; _fs->_sourcename = _sourcename; SQInteger stacksize = _fs->GetStackSize(); if(setjmp(_errorjmp) == 0) { Lex(); while(_token > 0){ Statement(); if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); } _fs->SetStackSize(stacksize); _fs->AddLineInfos(_lex._currentline, _lineinfo, true); _fs->AddInstruction(_OP_RETURN, 0xFF); _fs->SetStackSize(0); o =_fs->BuildProto(); #ifdef _DEBUG_DUMP _fs->Dump(_funcproto(o)); #endif } else { if(_raiseerror && _ss(_vm)->_compilererrorhandler) { _ss(_vm)->_compilererrorhandler(_vm, _compilererror, sq_type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"), _lex._currentline, _lex._currentcolumn); } _vm->_lasterror = SQString::Create(_ss(_vm), _compilererror, -1); return false; } return true; } void Statements() { while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) { Statement(); if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); } } void Statement(bool closeframe = true) { _fs->AddLineInfos(_lex._currentline, _lineinfo); switch(_token){ case _SC(';'): Lex(); break; case TK_IF: IfStatement(); break; case TK_WHILE: WhileStatement(); break; case TK_DO: DoWhileStatement(); break; case TK_FOR: ForStatement(); break; case TK_FOREACH: ForEachStatement(); break; case TK_SWITCH: SwitchStatement(); break; case TK_LOCAL: LocalDeclStatement(); break; case TK_RETURN: case TK_YIELD: { SQOpcode op; if(_token == TK_RETURN) { op = _OP_RETURN; } else { op = _OP_YIELD; _fs->_bgenerator = true; } Lex(); if(!IsEndOfStatement()) { SQInteger retexp = _fs->GetCurrentPos()+1; CommaExpr(); if(op == _OP_RETURN && _fs->_traps > 0) _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); _fs->_returnexp = retexp; _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize()); } else{ if(op == _OP_RETURN && _fs->_traps > 0) _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); _fs->_returnexp = -1; _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); } break;} case TK_BREAK: if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block")); if(_fs->_breaktargets.top() > 0){ _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); } RESOLVE_OUTERS(); _fs->AddInstruction(_OP_JMP, 0, -1234); _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); Lex(); break; case TK_CONTINUE: if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block")); if(_fs->_continuetargets.top() > 0) { _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); } RESOLVE_OUTERS(); _fs->AddInstruction(_OP_JMP, 0, -1234); _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); Lex(); break; case TK_FUNCTION: FunctionStatement(); break; case TK_CLASS: ClassStatement(); break; case TK_ENUM: EnumStatement(); break; case _SC('{'):{ BEGIN_SCOPE(); Lex(); Statements(); Expect(_SC('}')); if(closeframe) { END_SCOPE(); } else { END_SCOPE_NO_CLOSE(); } } break; case TK_TRY: TryCatchStatement(); break; case TK_THROW: Lex(); CommaExpr(); _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); break; case TK_CONST: { Lex(); SQObject id = Expect(TK_IDENTIFIER); Expect('='); SQObject val = ExpectScalar(); OptionalSemicolon(); SQTable *enums = _table(_ss(_vm)->_consts); SQObjectPtr strongid = id; enums->NewSlot(strongid,SQObjectPtr(val)); strongid.Null(); } break; default: CommaExpr(); _fs->DiscardTarget(); //_fs->PopTarget(); break; } _fs->SnoozeOpt(); } void EmitDerefOp(SQOpcode op) { SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); } void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0) { SQInteger p2 = _fs->PopTarget(); //src in OP_GET SQInteger p1 = _fs->PopTarget(); //key in OP_GET _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); } void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos) { /* Generate code depending on the expression type */ switch(etype) { case LOCAL:{ SQInteger p2 = _fs->PopTarget(); //src in OP_GET SQInteger p1 = _fs->PopTarget(); //key in OP_GET _fs->PushTarget(p1); //EmitCompArithLocal(tok, p1, p1, p2); _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0); _fs->SnoozeOpt(); } break; case OBJECT: case BASE: { SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger src = _fs->PopTarget(); /* _OP_COMPARITH mixes dest obj and source val in the arg1 */ _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok)); } break; case OUTER: { SQInteger val = _fs->TopTarget(); SQInteger tmp = _fs->PushTarget(); _fs->AddInstruction(_OP_GETOUTER, tmp, pos); _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0); _fs->PopTarget(); _fs->PopTarget(); _fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp); } break; } } void CommaExpr() { for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); } void Expression() { SQExpState es = _es; _es.etype = EXPR; _es.epos = -1; _es.donot_get = false; LogicalOrExp(); switch(_token) { case _SC('='): case TK_NEWSLOT: case TK_MINUSEQ: case TK_PLUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ:{ SQInteger op = _token; SQInteger ds = _es.etype; SQInteger pos = _es.epos; if(ds == EXPR) Error(_SC("can't assign expression")); else if(ds == BASE) Error(_SC("'base' cannot be modified")); Lex(); Expression(); switch(op){ case TK_NEWSLOT: if(ds == OBJECT || ds == BASE) EmitDerefOp(_OP_NEWSLOT); else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local Error(_SC("can't 'create' a local slot")); break; case _SC('='): //ASSIGN switch(ds) { case LOCAL: { SQInteger src = _fs->PopTarget(); SQInteger dst = _fs->TopTarget(); _fs->AddInstruction(_OP_MOVE, dst, src); } break; case OBJECT: case BASE: EmitDerefOp(_OP_SET); break; case OUTER: { SQInteger src = _fs->PopTarget(); SQInteger dst = _fs->PushTarget(); _fs->AddInstruction(_OP_SETOUTER, dst, pos, src); } } break; case TK_MINUSEQ: case TK_PLUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: EmitCompoundArith(op, ds, pos); break; } } break; case _SC('?'): { Lex(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); SQInteger jzpos = _fs->GetCurrentPos(); SQInteger trg = _fs->PushTarget(); Expression(); SQInteger first_exp = _fs->PopTarget(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); SQInteger endfirstexp = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_JMP, 0, 0); Expect(_SC(':')); SQInteger jmppos = _fs->GetCurrentPos(); Expression(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); _fs->SetInstructionParam(jzpos, 1, endfirstexp - jzpos + 1); _fs->SnoozeOpt(); } break; } _es = es; } template void INVOKE_EXP(T f) { SQExpState es = _es; _es.etype = EXPR; _es.epos = -1; _es.donot_get = false; (this->*f)(); _es = es; } template void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0) { Lex(); INVOKE_EXP(f); SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget(); _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); _es.etype = EXPR; } void LogicalOrExp() { LogicalAndExp(); for(;;) if(_token == TK_OR) { SQInteger first_exp = _fs->PopTarget(); SQInteger trg = _fs->PushTarget(); _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); SQInteger jpos = _fs->GetCurrentPos(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); Lex(); INVOKE_EXP(&SQCompiler::LogicalOrExp); _fs->SnoozeOpt(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SnoozeOpt(); _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); _es.etype = EXPR; break; }else return; } void LogicalAndExp() { BitwiseOrExp(); for(;;) switch(_token) { case TK_AND: { SQInteger first_exp = _fs->PopTarget(); SQInteger trg = _fs->PushTarget(); _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); SQInteger jpos = _fs->GetCurrentPos(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); Lex(); INVOKE_EXP(&SQCompiler::LogicalAndExp); _fs->SnoozeOpt(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SnoozeOpt(); _fs->SetInstructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); _es.etype = EXPR; break; } default: return; } } void BitwiseOrExp() { BitwiseXorExp(); for(;;) if(_token == _SC('|')) {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); }else return; } void BitwiseXorExp() { BitwiseAndExp(); for(;;) if(_token == _SC('^')) {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); }else return; } void BitwiseAndExp() { EqExp(); for(;;) if(_token == _SC('&')) {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND); }else return; } void EqExp() { CompExp(); for(;;) switch(_token) { case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break; case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break; case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break; default: return; } } void CompExp() { ShiftExp(); for(;;) switch(_token) { case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::ShiftExp); break; case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::ShiftExp); break; default: return; } } void ShiftExp() { PlusExp(); for(;;) switch(_token) { case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; default: return; } } SQOpcode ChooseArithOpByToken(SQInteger tok) { switch(tok) { case TK_PLUSEQ: case '+': return _OP_ADD; case TK_MINUSEQ: case '-': return _OP_SUB; case TK_MULEQ: case '*': return _OP_MUL; case TK_DIVEQ: case '/': return _OP_DIV; case TK_MODEQ: case '%': return _OP_MOD; default: assert(0); } return _OP_ADD; } SQInteger ChooseCompArithCharByToken(SQInteger tok) { SQInteger oper; switch(tok){ case TK_MINUSEQ: oper = '-'; break; case TK_PLUSEQ: oper = '+'; break; case TK_MULEQ: oper = '*'; break; case TK_DIVEQ: oper = '/'; break; case TK_MODEQ: oper = '%'; break; default: oper = 0; //shut up compiler assert(0); break; }; return oper; } void PlusExp() { MultExp(); for(;;) switch(_token) { case _SC('+'): case _SC('-'): BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break; default: return; } } void MultExp() { PrefixedExpr(); for(;;) switch(_token) { case _SC('*'): case _SC('/'): case _SC('%'): BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break; default: return; } } //if 'pos' != -1 the previous variable is a local variable void PrefixedExpr() { SQInteger pos = Factor(); for(;;) { switch(_token) { case _SC('.'): pos = -1; Lex(); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); if(_es.etype==BASE) { Emit2ArgsOP(_OP_GET); pos = _fs->TopTarget(); _es.etype = EXPR; _es.epos = pos; } else { if(NeedGet()) { Emit2ArgsOP(_OP_GET); } _es.etype = OBJECT; } break; case _SC('['): if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot break deref/or comma needed after [exp]=exp slot declaration")); Lex(); Expression(); Expect(_SC(']')); pos = -1; if(_es.etype==BASE) { Emit2ArgsOP(_OP_GET); pos = _fs->TopTarget(); _es.etype = EXPR; _es.epos = pos; } else { if(NeedGet()) { Emit2ArgsOP(_OP_GET); } _es.etype = OBJECT; } break; case TK_MINUSMINUS: case TK_PLUSPLUS: { if(IsEndOfStatement()) return; SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1; Lex(); switch(_es.etype) { case EXPR: Error(_SC("can't '++' or '--' an expression")); break; case OBJECT: case BASE: if(_es.donot_get == true) { Error(_SC("can't '++' or '--' an expression")); break; } //mmh dor this make sense? Emit2ArgsOP(_OP_PINC, diff); break; case LOCAL: { SQInteger src = _fs->PopTarget(); _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff); } break; case OUTER: { SQInteger tmp1 = _fs->PushTarget(); SQInteger tmp2 = _fs->PushTarget(); _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos); _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff); _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2); _fs->PopTarget(); } } } return; break; case _SC('('): switch(_es.etype) { case OBJECT: { SQInteger key = _fs->PopTarget(); /* location of the key */ SQInteger table = _fs->PopTarget(); /* location of the object */ SQInteger closure = _fs->PushTarget(); /* location for the closure */ SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */ _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); } break; case BASE: //Emit2ArgsOP(_OP_GET); _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); break; case OUTER: _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos); _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); break; default: _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); } _es.etype = EXPR; Lex(); FunctionCallArgs(); break; default: return; } } } SQInteger Factor() { //_es.etype = EXPR; switch(_token) { case TK_STRING_LITERAL: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); Lex(); break; case TK_BASE: Lex(); _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget()); _es.etype = BASE; _es.epos = _fs->TopTarget(); return (_es.epos); break; case TK_IDENTIFIER: case TK_CONSTRUCTOR: case TK_THIS:{ SQObject id; SQObject constant; switch(_token) { case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; case TK_THIS: id = _fs->CreateString(_SC("this"),4); break; case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor"),11); break; } SQInteger pos = -1; Lex(); if((pos = _fs->GetLocalVariable(id)) != -1) { /* Handle a local variable (includes 'this') */ _fs->PushTarget(pos); _es.etype = LOCAL; _es.epos = pos; } else if((pos = _fs->GetOuterVariable(id)) != -1) { /* Handle a free var */ if(NeedGet()) { _es.epos = _fs->PushTarget(); _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos); /* _es.etype = EXPR; already default value */ } else { _es.etype = OUTER; _es.epos = pos; } } else if(_fs->IsConstant(id, constant)) { /* Handle named constant */ SQObjectPtr constval; SQObject constid; if(sq_type(constant) == OT_TABLE) { Expect('.'); constid = Expect(TK_IDENTIFIER); if(!_table(constant)->Get(constid, constval)) { constval.Null(); Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid)); } } else { constval = constant; } _es.epos = _fs->PushTarget(); /* generate direct or literal function depending on size */ SQObjectType ctype = sq_type(constval); switch(ctype) { case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break; case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break; case OT_BOOL: _fs->AddInstruction(_OP_LOADBOOL, _es.epos, _integer(constval)); break; default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break; } _es.etype = EXPR; } else { /* Handle a non-local variable, aka a field. Push the 'this' pointer on * the virtual stack (always found in offset 0, so no instruction needs to * be generated), and push the key next. Generate an _OP_LOAD instruction * for the latter. If we are not using the variable as a dref expr, generate * the _OP_GET instruction. */ _fs->PushTarget(0); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(NeedGet()) { Emit2ArgsOP(_OP_GET); } _es.etype = OBJECT; } return _es.epos; } break; case TK_DOUBLE_COLON: // "::" _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget()); _es.etype = OBJECT; _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/ _es.epos = -1; return _es.epos; break; case TK_NULL: _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); Lex(); break; case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break; case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break; case TK_TRUE: case TK_FALSE: _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); Lex(); break; case _SC('['): { _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY); SQInteger apos = _fs->GetCurrentPos(),key = 0; Lex(); while(_token != _SC(']')) { Expression(); if(_token == _SC(',')) Lex(); SQInteger val = _fs->PopTarget(); SQInteger array = _fs->TopTarget(); _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK); key++; } _fs->SetInstructionParam(apos, 1, key); Lex(); } break; case _SC('{'): _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();ParseTableOrClass(_SC(','),_SC('}')); break; case TK_FUNCTION: FunctionExp(_token);break; case _SC('@'): FunctionExp(_token,true);break; case TK_CLASS: Lex(); ClassExp();break; case _SC('-'): Lex(); switch(_token) { case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break; case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break; default: UnaryOP(_OP_NEG); } break; case _SC('!'): Lex(); UnaryOP(_OP_NOT); break; case _SC('~'): Lex(); if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; } UnaryOP(_OP_BWNOT); break; case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break; case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break; case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break; case TK_RAWCALL: Lex(); Expect('('); FunctionCallArgs(true); break; case TK_MINUSMINUS : case TK_PLUSPLUS :PrefixIncDec(_token); break; case TK_DELETE : DeleteExpr(); break; case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); break; case TK___LINE__: EmitLoadConstInt(_lex._currentline,-1); Lex(); break; case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break; default: Error(_SC("expression expected")); } _es.etype = EXPR; return -1; } void EmitLoadConstInt(SQInteger value,SQInteger target) { if(target < 0) { target = _fs->PushTarget(); } if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits? _fs->AddInstruction(_OP_LOADINT, target,value); } else { _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); } } void EmitLoadConstFloat(SQFloat value,SQInteger target) { if(target < 0) { target = _fs->PushTarget(); } if(sizeof(SQFloat) == sizeof(SQInt32)) { _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value)); } else { _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); } } void UnaryOP(SQOpcode op) { PrefixedExpr(); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(op, _fs->PushTarget(), src); } bool NeedGet() { switch(_token) { case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: return false; case TK_PLUSPLUS: case TK_MINUSMINUS: if (!IsEndOfStatement()) { return false; } break; } return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('[')))); } void FunctionCallArgs(bool rawcall = false) { SQInteger nargs = 1;//this while(_token != _SC(')')) { Expression(); MoveIfCurrentTargetIsLocal(); nargs++; if(_token == _SC(',')){ Lex(); if(_token == ')') Error(_SC("expression expected, found ')'")); } } Lex(); if (rawcall) { if (nargs < 3) Error(_SC("rawcall requires at least 2 parameters (callee and this)")); nargs -= 2; //removes callee and this from count } for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget(); SQInteger stackbase = _fs->PopTarget(); SQInteger closure = _fs->PopTarget(); _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); #if 0 /* * disabled as it breaks existing scripts like * * local a = [] * local b = a.len() * // open some new block * { * local c = 0 * } * * see https://github.com/albertodemichelis/squirrel/issues/177 */ if (_token == '{') { SQInteger retval = _fs->TopTarget(); SQInteger nkeys = 0; Lex(); while (_token != '}') { switch (_token) { case _SC('['): Lex(); CommaExpr(); Expect(_SC(']')); Expect(_SC('=')); Expression(); break; default: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); Expect(_SC('=')); Expression(); break; } if (_token == ',') Lex(); nkeys++; SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); _fs->AddInstruction(_OP_SET, 0xFF, retval, key, val); } Lex(); } #endif } void ParseTableOrClass(SQInteger separator,SQInteger terminator) { SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0; while(_token != terminator) { bool hasattrs = false; bool isstatic = false; //check if is an attribute if(separator == ';') { if(_token == TK_ATTR_OPEN) { _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex(); ParseTableOrClass(',',TK_ATTR_CLOSE); hasattrs = true; } if(_token == TK_STATIC) { isstatic = true; Lex(); } } switch(_token) { case TK_FUNCTION: case TK_CONSTRUCTOR:{ SQInteger tk = _token; Lex(); SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor")); Expect(_SC('(')); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); CreateFunction(id); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); } break; case _SC('['): Lex(); CommaExpr(); Expect(_SC(']')); Expect(_SC('=')); Expression(); break; case TK_STRING_LITERAL: //JSON if(separator == ',') { //only works for tables _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL))); Expect(_SC(':')); Expression(); break; } default : _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); Expect(_SC('=')); Expression(); } if(_token == separator) Lex();//optional comma/semicolon nkeys++; SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger attrs = hasattrs ? _fs->PopTarget():-1; ((void)attrs); assert((hasattrs && (attrs == key-1)) || !hasattrs); unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); SQInteger table = _fs->TopTarget(); //<AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val); } else { _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember } } if(separator == _SC(',')) //hack recognizes a table from the separator _fs->SetInstructionParam(tpos, 1, nkeys); Lex(); } void LocalDeclStatement() { SQObject varname; Lex(); if( _token == TK_FUNCTION) { Lex(); varname = Expect(TK_IDENTIFIER); Expect(_SC('(')); CreateFunction(varname,false); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); _fs->PopTarget(); _fs->PushLocalVariable(varname); return; } do { varname = Expect(TK_IDENTIFIER); if(_token == _SC('=')) { Lex(); Expression(); SQInteger src = _fs->PopTarget(); SQInteger dest = _fs->PushTarget(); if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); } else{ _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); } _fs->PopTarget(); _fs->PushLocalVariable(varname); if(_token == _SC(',')) Lex(); else break; } while(1); } void IfBlock() { if (_token == _SC('{')) { BEGIN_SCOPE(); Lex(); Statements(); Expect(_SC('}')); if (true) { END_SCOPE(); } else { END_SCOPE_NO_CLOSE(); } } else { //BEGIN_SCOPE(); Statement(); if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); //END_SCOPE(); } } void IfStatement() { SQInteger jmppos; bool haselse = false; Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); SQInteger jnepos = _fs->GetCurrentPos(); IfBlock(); // /*static int n = 0; if (_token != _SC('}') && _token != TK_ELSE) { printf("IF %d-----------------------!!!!!!!!!\n", n); if (n == 5) { printf("asd"); } n++; //OptionalSemicolon(); }*/ SQInteger endifblock = _fs->GetCurrentPos(); if(_token == TK_ELSE){ haselse = true; //BEGIN_SCOPE(); _fs->AddInstruction(_OP_JMP); jmppos = _fs->GetCurrentPos(); Lex(); //Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon(); IfBlock(); //END_SCOPE(); _fs->SetInstructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); } _fs->SetInstructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); } void WhileStatement() { SQInteger jzpos, jmppos; jmppos = _fs->GetCurrentPos(); Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); BEGIN_BREAKBLE_BLOCK(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); BEGIN_SCOPE(); Statement(); END_SCOPE(); _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); END_BREAKBLE_BLOCK(jmppos); } void DoWhileStatement() { Lex(); SQInteger jmptrg = _fs->GetCurrentPos(); BEGIN_BREAKBLE_BLOCK() BEGIN_SCOPE(); Statement(); END_SCOPE(); Expect(TK_WHILE); SQInteger continuetrg = _fs->GetCurrentPos(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1); _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1); END_BREAKBLE_BLOCK(continuetrg); } void ForStatement() { Lex(); BEGIN_SCOPE(); Expect(_SC('(')); if(_token == TK_LOCAL) LocalDeclStatement(); else if(_token != _SC(';')){ CommaExpr(); _fs->PopTarget(); } Expect(_SC(';')); _fs->SnoozeOpt(); SQInteger jmppos = _fs->GetCurrentPos(); SQInteger jzpos = -1; if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } Expect(_SC(';')); _fs->SnoozeOpt(); SQInteger expstart = _fs->GetCurrentPos() + 1; if(_token != _SC(')')) { CommaExpr(); _fs->PopTarget(); } Expect(_SC(')')); _fs->SnoozeOpt(); SQInteger expend = _fs->GetCurrentPos(); SQInteger expsize = (expend - expstart) + 1; SQInstructionVec exp; if(expsize > 0) { for(SQInteger i = 0; i < expsize; i++) exp.push_back(_fs->GetInstruction(expstart + i)); _fs->PopInstructions(expsize); } BEGIN_BREAKBLE_BLOCK() Statement(); SQInteger continuetrg = _fs->GetCurrentPos(); if(expsize > 0) { for(SQInteger i = 0; i < expsize; i++) _fs->AddInstruction(exp[i]); } _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); if(jzpos> 0) _fs->SetInstructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); END_BREAKBLE_BLOCK(continuetrg); END_SCOPE(); } void ForEachStatement() { SQObject idxname, valname; Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER); if(_token == _SC(',')) { idxname = valname; Lex(); valname = Expect(TK_IDENTIFIER); } else{ idxname = _fs->CreateString(_SC("@INDEX@")); } Expect(TK_IN); //save the stack size BEGIN_SCOPE(); //put the table in the stack(evaluate the table expression) Expression(); Expect(_SC(')')); SQInteger container = _fs->TopTarget(); //push the index local var SQInteger indexpos = _fs->PushLocalVariable(idxname); _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); //push the value local var SQInteger valuepos = _fs->PushLocalVariable(valname); _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); //push reference index SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); SQInteger jmppos = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); SQInteger foreachpos = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); //generate the statement code BEGIN_BREAKBLE_BLOCK() Statement(); _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); _fs->SetInstructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); _fs->SetInstructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); END_BREAKBLE_BLOCK(foreachpos - 1); //restore the local variable stack(remove index,val and ref idx) _fs->PopTarget(); END_SCOPE(); } void SwitchStatement() { Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); Expect(_SC('{')); SQInteger expr = _fs->TopTarget(); bool bfirst = true; SQInteger tonextcondjmp = -1; SQInteger skipcondjmp = -1; SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); _fs->_breaktargets.push_back(0); while(_token == TK_CASE) { if(!bfirst) { _fs->AddInstruction(_OP_JMP, 0, 0); skipcondjmp = _fs->GetCurrentPos(); _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); } //condition Lex(); Expression(); Expect(_SC(':')); SQInteger trg = _fs->PopTarget(); SQInteger eqtarget = trg; bool local = _fs->IsLocal(trg); if(local) { eqtarget = _fs->PushTarget(); //we need to allocate a extra reg } _fs->AddInstruction(_OP_EQ, eqtarget, trg, expr); _fs->AddInstruction(_OP_JZ, eqtarget, 0); if(local) { _fs->PopTarget(); } //end condition if(skipcondjmp != -1) { _fs->SetInstructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); } tonextcondjmp = _fs->GetCurrentPos(); BEGIN_SCOPE(); Statements(); END_SCOPE(); bfirst = false; } if(tonextcondjmp != -1) _fs->SetInstructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); if(_token == TK_DEFAULT) { Lex(); Expect(_SC(':')); BEGIN_SCOPE(); Statements(); END_SCOPE(); } Expect(_SC('}')); _fs->PopTarget(); __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); _fs->_breaktargets.pop_back(); } void FunctionStatement() { SQObject id; Lex(); id = Expect(TK_IDENTIFIER); _fs->PushTarget(0); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); while(_token == TK_DOUBLE_COLON) { Lex(); id = Expect(TK_IDENTIFIER); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); } Expect(_SC('(')); CreateFunction(id); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); EmitDerefOp(_OP_NEWSLOT); _fs->PopTarget(); } void ClassStatement() { SQExpState es; Lex(); es = _es; _es.donot_get = true; PrefixedExpr(); if(_es.etype == EXPR) { Error(_SC("invalid class name")); } else if(_es.etype == OBJECT || _es.etype == BASE) { ClassExp(); EmitDerefOp(_OP_NEWSLOT); _fs->PopTarget(); } else { Error(_SC("cannot create a class in a local with the syntax(class )")); } _es = es; } SQObject ExpectScalar() { SQObject val; val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x switch(_token) { case TK_INTEGER: val._type = OT_INTEGER; val._unVal.nInteger = _lex._nvalue; break; case TK_FLOAT: val._type = OT_FLOAT; val._unVal.fFloat = _lex._fvalue; break; case TK_STRING_LITERAL: val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); break; case TK_TRUE: case TK_FALSE: val._type = OT_BOOL; val._unVal.nInteger = _token == TK_TRUE ? 1 : 0; break; case '-': Lex(); switch(_token) { case TK_INTEGER: val._type = OT_INTEGER; val._unVal.nInteger = -_lex._nvalue; break; case TK_FLOAT: val._type = OT_FLOAT; val._unVal.fFloat = -_lex._fvalue; break; default: Error(_SC("scalar expected : integer,float")); } break; default: Error(_SC("scalar expected : integer, float, or string")); } Lex(); return val; } void EnumStatement() { Lex(); SQObject id = Expect(TK_IDENTIFIER); Expect(_SC('{')); SQObject table = _fs->CreateTable(); SQInteger nval = 0; while(_token != _SC('}')) { SQObject key = Expect(TK_IDENTIFIER); SQObject val; if(_token == _SC('=')) { Lex(); val = ExpectScalar(); } else { val._type = OT_INTEGER; val._unVal.nInteger = nval++; } _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val)); if(_token == ',') Lex(); } SQTable *enums = _table(_ss(_vm)->_consts); SQObjectPtr strongid = id; enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table)); strongid.Null(); Lex(); } void TryCatchStatement() { SQObject exid; Lex(); _fs->AddInstruction(_OP_PUSHTRAP,0,0); _fs->_traps++; if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; SQInteger trappos = _fs->GetCurrentPos(); { BEGIN_SCOPE(); Statement(); END_SCOPE(); } _fs->_traps--; _fs->AddInstruction(_OP_POPTRAP, 1, 0); if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; _fs->AddInstruction(_OP_JMP, 0, 0); SQInteger jmppos = _fs->GetCurrentPos(); _fs->SetInstructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')')); { BEGIN_SCOPE(); SQInteger ex_target = _fs->PushLocalVariable(exid); _fs->SetInstructionParam(trappos, 0, ex_target); Statement(); _fs->SetInstructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); END_SCOPE(); } } void FunctionExp(SQInteger ftype,bool lambda = false) { Lex(); Expect(_SC('(')); SQObjectPtr dummy; CreateFunction(dummy,lambda); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); } void ClassExp() { SQInteger base = -1; SQInteger attrs = -1; if(_token == TK_EXTENDS) { Lex(); Expression(); base = _fs->TopTarget(); } if(_token == TK_ATTR_OPEN) { Lex(); _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); attrs = _fs->TopTarget(); } Expect(_SC('{')); if(attrs != -1) _fs->PopTarget(); if(base != -1) _fs->PopTarget(); _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS); ParseTableOrClass(_SC(';'),_SC('}')); } void DeleteExpr() { SQExpState es; Lex(); es = _es; _es.donot_get = true; PrefixedExpr(); if(_es.etype==EXPR) Error(_SC("can't delete an expression")); if(_es.etype==OBJECT || _es.etype==BASE) { Emit2ArgsOP(_OP_DELETE); } else { Error(_SC("cannot delete an (outer) local")); } _es = es; } void PrefixIncDec(SQInteger token) { SQExpState es; SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1; Lex(); es = _es; _es.donot_get = true; PrefixedExpr(); if(_es.etype==EXPR) { Error(_SC("can't '++' or '--' an expression")); } else if(_es.etype==OBJECT || _es.etype==BASE) { Emit2ArgsOP(_OP_INC, diff); } else if(_es.etype==LOCAL) { SQInteger src = _fs->TopTarget(); _fs->AddInstruction(_OP_INCL, src, src, 0, diff); } else if(_es.etype==OUTER) { SQInteger tmp = _fs->PushTarget(); _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos); _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff); _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp); } _es = es; } void CreateFunction(SQObject &name,bool lambda = false) { SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); funcstate->_name = name; SQObject paramname; funcstate->AddParameter(_fs->CreateString(_SC("this"))); funcstate->_sourcename = _sourcename; SQInteger defparams = 0; while(_token!=_SC(')')) { if(_token == TK_VARPARAMS) { if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters")); funcstate->AddParameter(_fs->CreateString(_SC("vargv"))); funcstate->_varparams = true; Lex(); if(_token != _SC(')')) Error(_SC("expected ')'")); break; } else { paramname = Expect(TK_IDENTIFIER); funcstate->AddParameter(paramname); if(_token == _SC('=')) { Lex(); Expression(); funcstate->AddDefaultParam(_fs->TopTarget()); defparams++; } else { if(defparams > 0) Error(_SC("expected '='")); } if(_token == _SC(',')) Lex(); else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); } } Expect(_SC(')')); for(SQInteger n = 0; n < defparams; n++) { _fs->PopTarget(); } SQFuncState *currchunk = _fs; _fs = funcstate; if(lambda) { Expression(); _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());} else { Statement(false); } funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); funcstate->AddInstruction(_OP_RETURN, -1); funcstate->SetStackSize(0); SQFunctionProto *func = funcstate->BuildProto(); #ifdef _DEBUG_DUMP funcstate->Dump(func); #endif _fs = currchunk; _fs->_functions.push_back(func); _fs->PopChildState(); } void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve) { while(ntoresolve > 0) { SQInteger pos = funcstate->_unresolvedbreaks.back(); funcstate->_unresolvedbreaks.pop_back(); //set the jmp instruction funcstate->SetInstructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); ntoresolve--; } } void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos) { while(ntoresolve > 0) { SQInteger pos = funcstate->_unresolvedcontinues.back(); funcstate->_unresolvedcontinues.pop_back(); //set the jmp instruction funcstate->SetInstructionParams(pos, 0, targetpos - pos, 0); ntoresolve--; } } private: SQInteger _token; SQFuncState *_fs; SQObjectPtr _sourcename; SQLexer _lex; bool _lineinfo; bool _raiseerror; SQInteger _debugline; SQInteger _debugop; SQExpState _es; SQScope _scope; SQChar _compilererror[MAX_COMPILER_ERROR_LEN]; jmp_buf _errorjmp; SQVM *_vm; }; bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) { SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); return p.Compile(out); } #endif simutrans-124.3/src/squirrel/squirrel/sqcompiler.h000066400000000000000000000034261474050137200224120ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQCOMPILER_H_ #define _SQCOMPILER_H_ struct SQVM; #define TK_IDENTIFIER 258 #define TK_STRING_LITERAL 259 #define TK_INTEGER 260 #define TK_FLOAT 261 #define TK_BASE 262 #define TK_DELETE 263 #define TK_EQ 264 #define TK_NE 265 #define TK_LE 266 #define TK_GE 267 #define TK_SWITCH 268 #define TK_ARROW 269 #define TK_AND 270 #define TK_OR 271 #define TK_IF 272 #define TK_ELSE 273 #define TK_WHILE 274 #define TK_BREAK 275 #define TK_FOR 276 #define TK_DO 277 #define TK_NULL 278 #define TK_FOREACH 279 #define TK_IN 280 #define TK_NEWSLOT 281 #define TK_MODULO 282 #define TK_LOCAL 283 #define TK_CLONE 284 #define TK_FUNCTION 285 #define TK_RETURN 286 #define TK_TYPEOF 287 #define TK_UMINUS 288 #define TK_PLUSEQ 289 #define TK_MINUSEQ 290 #define TK_CONTINUE 291 #define TK_YIELD 292 #define TK_TRY 293 #define TK_CATCH 294 #define TK_THROW 295 #define TK_SHIFTL 296 #define TK_SHIFTR 297 #define TK_RESUME 298 #define TK_DOUBLE_COLON 299 #define TK_CASE 300 #define TK_DEFAULT 301 #define TK_THIS 302 #define TK_PLUSPLUS 303 #define TK_MINUSMINUS 304 #define TK_3WAYSCMP 305 #define TK_USHIFTR 306 #define TK_CLASS 307 #define TK_EXTENDS 308 #define TK_CONSTRUCTOR 310 #define TK_INSTANCEOF 311 #define TK_VARPARAMS 312 #define TK___LINE__ 313 #define TK___FILE__ 314 #define TK_TRUE 315 #define TK_FALSE 316 #define TK_MULEQ 317 #define TK_DIVEQ 318 #define TK_MODEQ 319 #define TK_ATTR_OPEN 320 #define TK_ATTR_CLOSE 321 #define TK_STATIC 322 #define TK_ENUM 323 #define TK_CONST 324 #define TK_RAWCALL 325 typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); #endif simutrans-124.3/src/squirrel/squirrel/sqdebug.cc000066400000000000000000000072061474050137200220240ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include #include "sqvm.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqstring.h" SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi) { SQInteger cssize = v->_callsstacksize; if (cssize > level) { SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; if(sq_isclosure(ci._closure)) { SQClosure *c = _closure(ci._closure); SQFunctionProto *proto = c->_function; fi->funcid = proto; fi->name = sq_type(proto->_name) == OT_STRING?_stringval(proto->_name):_SC("unknown"); fi->source = sq_type(proto->_sourcename) == OT_STRING?_stringval(proto->_sourcename):_SC("unknown"); fi->line = proto->_lineinfos[0]._line; return SQ_OK; } } return sq_throwerror(v,_SC("the object is not a closure")); } SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) { SQInteger cssize = v->_callsstacksize; if (cssize > level) { memset(si, 0, sizeof(SQStackInfos)); SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; switch (sq_type(ci._closure)) { case OT_CLOSURE:{ SQFunctionProto *func = _closure(ci._closure)->_function; if (sq_type(func->_name) == OT_STRING) si->funcname = _stringval(func->_name); if (sq_type(func->_sourcename) == OT_STRING) si->source = _stringval(func->_sourcename); si->line = func->GetLine(ci._ip); } break; case OT_NATIVECLOSURE: si->source = _SC("NATIVE"); si->funcname = _SC("unknown"); if(sq_type(_nativeclosure(ci._closure)->_name) == OT_STRING) si->funcname = _stringval(_nativeclosure(ci._closure)->_name); si->line = -1; break; default: break; //shutup compiler } return SQ_OK; } return SQ_ERROR; } void SQVM::Raise_Error(const SQChar *s, ...) { va_list vl; va_start(vl, s); Raise_Error_vl(s, vl); va_end(vl); } void SQVM::Raise_Error_vl(const SQChar *s, va_list vl) { SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2); scvsprintf(_sp(sq_rsl(buffersize)),buffersize, s, vl); _lasterror = SQString::Create(_ss(this),_spval,-1); } void SQVM::Raise_Error(const SQObjectPtr &desc) { _lasterror = desc; } SQString *SQVM::PrintObjVal(const SQObjectPtr &o) { switch(sq_type(o)) { case OT_STRING: return _string(o); case OT_INTEGER: scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o)); return SQString::Create(_ss(this), _spval); break; case OT_FLOAT: scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)), sq_rsl(NUMBER_MAX_CHAR), _SC("%.14g"), _float(o)); return SQString::Create(_ss(this), _spval); break; default: return SQString::Create(_ss(this), GetTypeName(o)); } } void SQVM::Raise_IdxError(const SQObjectPtr &o) { SQObjectPtr oval = PrintObjVal(o); Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval)); } void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) { SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); Raise_Error(_SC("comparison between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2)); } void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type) { SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1); SQInteger found = 0; for(SQInteger i=0; i<16; i++) { SQInteger mask = ((SQInteger)1) << i; if(typemask & (mask)) { if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes); found ++; StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); } } Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); } simutrans-124.3/src/squirrel/squirrel/sqfuncproto.h000066400000000000000000000107101474050137200226110ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQFUNCTION_H_ #define _SQFUNCTION_H_ #include "sqopcodes.h" enum SQOuterType { otLOCAL = 0, otOUTER = 1 }; struct SQOuterVar { SQOuterVar(){} SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) { _name = name; _src=src; _type=t; } SQOuterType _type; SQObjectPtr _name; SQObjectPtr _src; }; struct SQLocalVarInfo { SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0){} SQObjectPtr _name; SQUnsignedInteger _start_op; SQUnsignedInteger _end_op; SQUnsignedInteger _pos; }; struct SQLineInfo { SQInteger _line;SQInteger _op; }; typedef sqvector SQOuterVarVec; typedef sqvector SQLocalVarInfoVec; typedef sqvector SQLineInfoVec; #define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \ +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \ +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \ +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \ +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger))) struct SQFunctionProto : public CHAINABLE_OBJ { private: SQFunctionProto(SQSharedState *ss); ~SQFunctionProto(); public: static SQFunctionProto *Create(SQSharedState *ss,SQInteger ninstructions, SQInteger nliterals,SQInteger nparameters, SQInteger nfunctions,SQInteger noutervalues, SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) { SQFunctionProto *f; //I compact the whole class and members in a single memory allocation f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams)); new (f) SQFunctionProto(ss); f->_ninstructions = ninstructions; f->_literals = (SQObjectPtr*)&f->_instructions[ninstructions]; f->_nliterals = nliterals; f->_parameters = (SQObjectPtr*)&f->_literals[nliterals]; f->_nparameters = nparameters; f->_functions = (SQObjectPtr*)&f->_parameters[nparameters]; f->_nfunctions = nfunctions; f->_outervalues = (SQOuterVar*)&f->_functions[nfunctions]; f->_noutervalues = noutervalues; f->_lineinfos = (SQLineInfo *)&f->_outervalues[noutervalues]; f->_nlineinfos = nlineinfos; f->_localvarinfos = (SQLocalVarInfo *)&f->_lineinfos[nlineinfos]; f->_nlocalvarinfos = nlocalvarinfos; f->_defaultparams = (SQInteger *)&f->_localvarinfos[nlocalvarinfos]; f->_ndefaultparams = ndefaultparams; _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals); _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters); _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions); _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues); //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos); return f; } void Release(){ _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams); this->~SQFunctionProto(); sq_vm_free(this,size); } const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); SQInteger GetLine(SQInstruction *curr); bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){ _NULL_SQOBJECT_VECTOR(_literals,_nliterals); } SQObjectType GetType() {return OT_FUNCPROTO;} #endif SQObjectPtr _sourcename; SQObjectPtr _name; SQInteger _stacksize; bool _bgenerator; SQInteger _varparams; SQInteger _nlocalvarinfos; SQLocalVarInfo *_localvarinfos; SQInteger _nlineinfos; SQLineInfo *_lineinfos; SQInteger _nliterals; SQObjectPtr *_literals; SQInteger _nparameters; SQObjectPtr *_parameters; SQInteger _nfunctions; SQObjectPtr *_functions; SQInteger _noutervalues; SQOuterVar *_outervalues; SQInteger _ndefaultparams; SQInteger *_defaultparams; SQInteger _ninstructions; SQInstruction _instructions[1]; }; #endif simutrans-124.3/src/squirrel/squirrel/sqfuncstate.cc000066400000000000000000000401611474050137200227270ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #ifndef NO_COMPILER #include "sqcompiler.h" #include "sqstring.h" #include "sqfuncproto.h" #include "sqtable.h" #include "sqopcodes.h" #include "sqfuncstate.h" #ifdef _DEBUG_DUMP SQInstructionDesc g_InstrDesc[]={ {_SC("_OP_LINE")}, {_SC("_OP_LOAD")}, {_SC("_OP_LOADINT")}, {_SC("_OP_LOADFLOAT")}, {_SC("_OP_DLOAD")}, {_SC("_OP_TAILCALL")}, {_SC("_OP_CALL")}, {_SC("_OP_PREPCALL")}, {_SC("_OP_PREPCALLK")}, {_SC("_OP_GETK")}, {_SC("_OP_MOVE")}, {_SC("_OP_NEWSLOT")}, {_SC("_OP_DELETE")}, {_SC("_OP_SET")}, {_SC("_OP_GET")}, {_SC("_OP_EQ")}, {_SC("_OP_NE")}, {_SC("_OP_ADD")}, {_SC("_OP_SUB")}, {_SC("_OP_MUL")}, {_SC("_OP_DIV")}, {_SC("_OP_MOD")}, {_SC("_OP_BITW")}, {_SC("_OP_RETURN")}, {_SC("_OP_LOADNULLS")}, {_SC("_OP_LOADROOT")}, {_SC("_OP_LOADBOOL")}, {_SC("_OP_DMOVE")}, {_SC("_OP_JMP")}, {_SC("_OP_JCMP")}, {_SC("_OP_JZ")}, {_SC("_OP_SETOUTER")}, {_SC("_OP_GETOUTER")}, {_SC("_OP_NEWOBJ")}, {_SC("_OP_APPENDARRAY")}, {_SC("_OP_COMPARITH")}, {_SC("_OP_INC")}, {_SC("_OP_INCL")}, {_SC("_OP_PINC")}, {_SC("_OP_PINCL")}, {_SC("_OP_CMP")}, {_SC("_OP_EXISTS")}, {_SC("_OP_INSTANCEOF")}, {_SC("_OP_AND")}, {_SC("_OP_OR")}, {_SC("_OP_NEG")}, {_SC("_OP_NOT")}, {_SC("_OP_BWNOT")}, {_SC("_OP_CLOSURE")}, {_SC("_OP_YIELD")}, {_SC("_OP_RESUME")}, {_SC("_OP_FOREACH")}, {_SC("_OP_POSTFOREACH")}, {_SC("_OP_CLONE")}, {_SC("_OP_TYPEOF")}, {_SC("_OP_PUSHTRAP")}, {_SC("_OP_POPTRAP")}, {_SC("_OP_THROW")}, {_SC("_OP_NEWSLOTA")}, {_SC("_OP_GETBASE")}, {_SC("_OP_CLOSE")}, }; #endif void DumpLiteral(SQObjectPtr &o) { switch(sq_type(o)){ case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; case OT_INTEGER: scprintf(_SC("{") _PRINT_INT_FMT _SC("}"),_integer(o));break; case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break; default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler } } SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) { _nliterals = 0; _literals = SQTable::Create(ss,0); _strings = SQTable::Create(ss,0); _sharedstate = ss; _lastline = 0; _optimization = true; _parent = parent; _stacksize = 0; _traps = 0; _returnexp = 0; _varparams = false; _errfunc = efunc; _errtarget = ed; _bgenerator = false; _outers = 0; _ss = ss; } void SQFuncState::Error(const SQChar *err) { _errfunc(_errtarget,err); } #ifdef _DEBUG_DUMP void SQFuncState::Dump(SQFunctionProto *func) { SQUnsignedInteger n=0,i; SQInteger si; scprintf(_SC("SQInstruction sizeof %d\n"),(SQInt32)sizeof(SQInstruction)); scprintf(_SC("SQObject sizeof %d\n"), (SQInt32)sizeof(SQObject)); scprintf(_SC("--------------------------------------------------------------------\n")); scprintf(_SC("*****FUNCTION [%s]\n"),sq_type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown")); scprintf(_SC("-----LITERALS\n")); SQObjectPtr refidx,key,val; SQInteger idx; SQObjectPtrVec templiterals; templiterals.resize(_nliterals); while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { refidx=idx; templiterals[_integer(val)]=key; } for(i=0;i>\n")); n=0; for(i=0;i<_parameters.size();i++){ scprintf(_SC("[%d] "), (SQInt32)n); DumpLiteral(_parameters[i]); scprintf(_SC("\n")); n++; } scprintf(_SC("-----LOCALS\n")); for(si=0;si_nlocalvarinfos;si++){ SQLocalVarInfo lvi=func->_localvarinfos[si]; scprintf(_SC("[%d] %s \t%d %d\n"), (SQInt32)lvi._pos,_stringval(lvi._name), (SQInt32)lvi._start_op, (SQInt32)lvi._end_op); n++; } scprintf(_SC("-----LINE INFO\n")); for(i=0;i<_lineinfos.size();i++){ SQLineInfo li=_lineinfos[i]; scprintf(_SC("op [%d] line [%d] \n"), (SQInt32)li._op, (SQInt32)li._line); n++; } scprintf(_SC("-----dump\n")); n=0; for(i=0;i<_instructions.size();i++){ SQInstruction &inst=_instructions[i]; if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ SQInteger lidx = inst._arg1; scprintf(_SC("[%03d] %15s %d "), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0); if(lidx >= 0xFFFFFFFF) scprintf(_SC("null")); else { SQInteger refidx; SQObjectPtr val,key,refo; while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { refo = refidx; } DumpLiteral(key); } if(inst.op != _OP_DLOAD) { scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3); } else { scprintf(_SC(" %d "),inst._arg2); lidx = inst._arg3; if(lidx >= 0xFFFFFFFF) scprintf(_SC("null")); else { SQInteger refidx; SQObjectPtr val,key,refo; while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { refo = refidx; } DumpLiteral(key); scprintf(_SC("\n")); } } } else if(inst.op==_OP_LOADFLOAT) { scprintf(_SC("[%03d] %15s %d %f %d %d\n"), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3); } /* else if(inst.op==_OP_ARITH){ scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); }*/ else { scprintf(_SC("[%03d] %15s %d %d %d %d\n"), (SQInt32)n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); } n++; } scprintf(_SC("-----\n")); scprintf(_SC("stack size[%d]\n"), (SQInt32)func->_stacksize); scprintf(_SC("--------------------------------------------------------------------\n\n")); } #endif SQInteger SQFuncState::GetNumericConstant(const SQInteger cons) { return GetConstant(SQObjectPtr(cons)); } SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) { return GetConstant(SQObjectPtr(cons)); } SQInteger SQFuncState::GetConstant(const SQObject &cons) { SQObjectPtr val; if(!_table(_literals)->Get(cons,val)) { val = _nliterals; _table(_literals)->NewSlot(cons,val); _nliterals++; if(_nliterals > MAX_LITERALS) { val.Null(); Error(_SC("internal compiler error: too many literals")); } } return _integer(val); } void SQFuncState::SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) { _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0); _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); } void SQFuncState::SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val) { switch(arg){ case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break; }; } SQInteger SQFuncState::AllocStackPos() { SQInteger npos=_vlocals.size(); _vlocals.push_back(SQLocalVarInfo()); if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) { if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals")); _stacksize=_vlocals.size(); } return npos; } SQInteger SQFuncState::PushTarget(SQInteger n) { if(n!=-1){ _targetstack.push_back(n); return n; } n=AllocStackPos(); _targetstack.push_back(n); return n; } SQInteger SQFuncState::GetUpTarget(SQInteger n){ return _targetstack[((_targetstack.size()-1)-n)]; } SQInteger SQFuncState::TopTarget(){ return _targetstack.back(); } SQInteger SQFuncState::PopTarget() { SQUnsignedInteger npos=_targetstack.back(); assert(npos < _vlocals.size()); SQLocalVarInfo &t = _vlocals[npos]; if(sq_type(t._name)==OT_NULL){ _vlocals.pop_back(); } _targetstack.pop_back(); return npos; } SQInteger SQFuncState::GetStackSize() { return _vlocals.size(); } SQInteger SQFuncState::CountOuters(SQInteger stacksize) { SQInteger outers = 0; SQInteger k = _vlocals.size() - 1; while(k >= stacksize) { SQLocalVarInfo &lvi = _vlocals[k]; k--; if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer outers++; } } return outers; } void SQFuncState::SetStackSize(SQInteger n) { SQInteger size=_vlocals.size(); while(size>n){ size--; SQLocalVarInfo lvi = _vlocals.back(); if(sq_type(lvi._name)!=OT_NULL){ if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer _outers--; } lvi._end_op = GetCurrentPos(); _localvarinfos.push_back(lvi); } _vlocals.pop_back(); } } bool SQFuncState::IsConstant(const SQObject &name,SQObject &e) { SQObjectPtr val; if(_table(_sharedstate->_consts)->Get(name,val)) { e = val; return true; } return false; } bool SQFuncState::IsLocal(SQUnsignedInteger stkpos) { if(stkpos>=_vlocals.size())return false; else if(sq_type(_vlocals[stkpos]._name)!=OT_NULL)return true; return false; } SQInteger SQFuncState::PushLocalVariable(const SQObject &name) { SQInteger pos=_vlocals.size(); SQLocalVarInfo lvi; lvi._name=name; lvi._start_op=GetCurrentPos()+1; lvi._pos=_vlocals.size(); _vlocals.push_back(lvi); if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); return pos; } SQInteger SQFuncState::GetLocalVariable(const SQObject &name) { SQInteger locals=_vlocals.size(); while(locals>=1){ SQLocalVarInfo &lvi = _vlocals[locals-1]; if(sq_type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){ return locals-1; } locals--; } return -1; } void SQFuncState::MarkLocalAsOuter(SQInteger pos) { SQLocalVarInfo &lvi = _vlocals[pos]; lvi._end_op = UINT_MINUS_ONE; _outers++; } SQInteger SQFuncState::GetOuterVariable(const SQObject &name) { SQInteger outers = _outervalues.size(); for(SQInteger i = 0; iGetLocalVariable(name); if(pos == -1) { pos = _parent->GetOuterVariable(name); if(pos != -1) { _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local return _outervalues.size() - 1; } } else { _parent->MarkLocalAsOuter(pos); _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local return _outervalues.size() - 1; } } return -1; } void SQFuncState::AddParameter(const SQObject &name) { PushLocalVariable(name); _parameters.push_back(name); } void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force) { if(_lastline!=line || force){ SQLineInfo li; li._line=line;li._op=(GetCurrentPos()+1); if(lineop)AddInstruction(_OP_LINE,0,line); if(_lastline!=line) { _lineinfos.push_back(li); } _lastline=line; } } void SQFuncState::DiscardTarget() { SQInteger discardedtarget = PopTarget(); SQInteger size = _instructions.size(); if(size > 0 && _optimization){ SQInstruction &pi = _instructions[size-1];//previous instruction switch(pi.op) { case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL: if(pi._arg0 == discardedtarget) { pi._arg0 = 0xFF; } } } } void SQFuncState::AddInstruction(SQInstruction &i) { SQInteger size = _instructions.size(); if(size > 0 && _optimization){ //simple optimizer SQInstruction &pi = _instructions[size-1];//previous instruction switch(i.op) { case _OP_JZ: if( pi.op == _OP_CMP && pi._arg1 < 0xFF) { pi.op = _OP_JCMP; pi._arg0 = (unsigned char)pi._arg1; pi._arg1 = i._arg1; return; } break; case _OP_SET: case _OP_NEWSLOT: if(i._arg0 == i._arg3) { i._arg0 = 0xFF; } break; case _OP_SETOUTER: if(i._arg0 == i._arg2) { i._arg0 = 0xFF; } break; case _OP_RETURN: if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { pi.op = _OP_TAILCALL; } else if(pi.op == _OP_CLOSE){ pi = i; return; } break; case _OP_GET: if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ pi._arg2 = (unsigned char)i._arg1; pi.op = _OP_GETK; pi._arg0 = i._arg0; return; } break; case _OP_PREPCALL: if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ pi.op = _OP_PREPCALLK; pi._arg0 = i._arg0; pi._arg2 = i._arg2; pi._arg3 = i._arg3; return; } break; case _OP_APPENDARRAY: { SQInteger aat = -1; switch(pi.op) { case _OP_LOAD: aat = AAT_LITERAL; break; case _OP_LOADINT: aat = AAT_INT; break; case _OP_LOADBOOL: aat = AAT_BOOL; break; case _OP_LOADFLOAT: aat = AAT_FLOAT; break; default: break; } if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ pi.op = _OP_APPENDARRAY; pi._arg0 = i._arg0; pi._arg2 = (unsigned char)aat; pi._arg3 = MAX_FUNC_STACKSIZE; return; } } break; case _OP_MOVE: switch(pi.op) { case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW: case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD: if(pi._arg0 == i._arg1) { pi._arg0 = i._arg0; _optimization = false; //_result_elimination = false; return; } } if(pi.op == _OP_MOVE) { pi.op = _OP_DMOVE; pi._arg2 = i._arg0; pi._arg3 = (unsigned char)i._arg1; return; } break; case _OP_LOAD: if(pi.op == _OP_LOAD && i._arg1 < 256) { pi.op = _OP_DLOAD; pi._arg2 = i._arg0; pi._arg3 = (unsigned char)i._arg1; return; } break; case _OP_EQ:case _OP_NE: if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) { pi.op = i.op; pi._arg0 = i._arg0; pi._arg2 = i._arg2; pi._arg3 = MAX_FUNC_STACKSIZE; return; } break; case _OP_LOADNULLS: if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { pi._arg1 = pi._arg1 + 1; pi.op = _OP_LOADNULLS; return; } break; case _OP_LINE: if(pi.op == _OP_LINE) { _instructions.pop_back(); _lineinfos.pop_back(); } break; } } _optimization = true; _instructions.push_back(i); } SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) { SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); _table(_strings)->NewSlot(ns,(SQInteger)1); return ns; } SQObject SQFuncState::CreateTable() { SQObjectPtr nt(SQTable::Create(_sharedstate,0)); _table(_strings)->NewSlot(nt,(SQInteger)1); return nt; } SQFunctionProto *SQFuncState::BuildProto() { SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(), _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); SQObjectPtr refidx,key,val; SQInteger idx; f->_stacksize = _stacksize; f->_sourcename = _sourcename; f->_bgenerator = _bgenerator; f->_name = _name; while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { f->_literals[_integer(val)]=key; refidx=idx; } for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl]; for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni]; for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd]; memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction)); f->_varparams = _varparams; return f; } SQFuncState *SQFuncState::PushChildState(SQSharedState *ss) { SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); new (child) SQFuncState(ss,this,_errfunc,_errtarget); _childstates.push_back(child); return child; } void SQFuncState::PopChildState() { SQFuncState *child = _childstates.back(); sq_delete(child,SQFuncState); _childstates.pop_back(); } SQFuncState::~SQFuncState() { while(_childstates.size() > 0) { PopChildState(); } } #endif simutrans-124.3/src/squirrel/squirrel/sqfuncstate.h000066400000000000000000000061461474050137200225760ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQFUNCSTATE_H_ #define _SQFUNCSTATE_H_ /////////////////////////////////// #include "squtils.h" struct SQFuncState { SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); ~SQFuncState(); #ifdef _DEBUG_DUMP void Dump(SQFunctionProto *func); #endif void Error(const SQChar *err); SQFuncState *PushChildState(SQSharedState *ss); void PopChildState(); void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} void AddInstruction(SQInstruction &i); void SetInstructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0); void SetInstructionParam(SQInteger pos,SQInteger arg,SQInteger val); SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];} void PopInstructions(SQInteger size){for(SQInteger i=0;i _childstates; SQInteger GetConstant(const SQObject &cons); private: CompilerErrorFunc _errfunc; void *_errtarget; SQSharedState *_ss; }; #endif simutrans-124.3/src/squirrel/squirrel/sqlexer.cc000066400000000000000000000327201474050137200220540ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include #include #include "sqtable.h" #include "sqstring.h" #include "sqcompiler.h" #include "sqlexer.h" #define CUR_CHAR (_currdata) #define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} #define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) #define NEXT() {Next();_currentcolumn++;} #define INIT_TEMP_STRING() { _longstr.resize(0);} #define APPEND_CHAR(c) { _longstr.push_back(c);} #define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));} #define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id)) SQLexer::SQLexer(){} SQLexer::~SQLexer() { _keywords->Release(); } void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) { _errfunc = efunc; _errtarget = ed; _sharedstate = ss; _keywords = SQTable::Create(ss, 37); ADD_KEYWORD(while, TK_WHILE); ADD_KEYWORD(do, TK_DO); ADD_KEYWORD(if, TK_IF); ADD_KEYWORD(else, TK_ELSE); ADD_KEYWORD(break, TK_BREAK); ADD_KEYWORD(continue, TK_CONTINUE); ADD_KEYWORD(return, TK_RETURN); ADD_KEYWORD(null, TK_NULL); ADD_KEYWORD(function, TK_FUNCTION); ADD_KEYWORD(local, TK_LOCAL); ADD_KEYWORD(for, TK_FOR); ADD_KEYWORD(foreach, TK_FOREACH); ADD_KEYWORD(in, TK_IN); ADD_KEYWORD(typeof, TK_TYPEOF); ADD_KEYWORD(base, TK_BASE); ADD_KEYWORD(delete, TK_DELETE); ADD_KEYWORD(try, TK_TRY); ADD_KEYWORD(catch, TK_CATCH); ADD_KEYWORD(throw, TK_THROW); ADD_KEYWORD(clone, TK_CLONE); ADD_KEYWORD(yield, TK_YIELD); ADD_KEYWORD(resume, TK_RESUME); ADD_KEYWORD(switch, TK_SWITCH); ADD_KEYWORD(case, TK_CASE); ADD_KEYWORD(default, TK_DEFAULT); ADD_KEYWORD(this, TK_THIS); ADD_KEYWORD(class,TK_CLASS); ADD_KEYWORD(extends,TK_EXTENDS); ADD_KEYWORD(constructor,TK_CONSTRUCTOR); ADD_KEYWORD(instanceof,TK_INSTANCEOF); ADD_KEYWORD(true,TK_TRUE); ADD_KEYWORD(false,TK_FALSE); ADD_KEYWORD(static,TK_STATIC); ADD_KEYWORD(enum,TK_ENUM); ADD_KEYWORD(const,TK_CONST); ADD_KEYWORD(__LINE__,TK___LINE__); ADD_KEYWORD(__FILE__,TK___FILE__); ADD_KEYWORD(rawcall, TK_RAWCALL); _readf = rg; _up = up; _lasttokenline = _currentline = 1; _currentcolumn = 0; _prevtoken = -1; _reached_eof = SQFalse; Next(); } void SQLexer::Error(const SQChar *err) { _errfunc(_errtarget,err); } void SQLexer::Next() { SQInteger t = _readf(_up); if(t > MAX_CHAR) Error(_SC("Invalid character")); if(t != 0) { _currdata = (LexChar)t; return; } _currdata = SQUIRREL_EOB; _reached_eof = SQTrue; } const SQChar *SQLexer::Tok2Str(SQInteger tok) { SQObjectPtr itr, key, val; SQInteger nitr; while((nitr = _keywords->Next(false,itr, key, val)) != -1) { itr = (SQInteger)nitr; if(((SQInteger)_integer(val)) == tok) return _stringval(key); } return NULL; } void SQLexer::LexBlockComment() { bool done = false; while(!done) { switch(CUR_CHAR) { case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue; case _SC('\n'): _currentline++; NEXT(); continue; case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment")); default: NEXT(); } } } void SQLexer::LexLineComment() { do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); } SQInteger SQLexer::Lex() { _lasttokenline = _currentline; while(CUR_CHAR != SQUIRREL_EOB) { switch(CUR_CHAR){ case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue; case _SC('\n'): _currentline++; _prevtoken=_curtoken; _curtoken=_SC('\n'); NEXT(); _currentcolumn=1; continue; case _SC('#'): LexLineComment(); continue; case _SC('/'): NEXT(); switch(CUR_CHAR){ case _SC('*'): NEXT(); LexBlockComment(); continue; case _SC('/'): LexLineComment(); continue; case _SC('='): NEXT(); RETURN_TOKEN(TK_DIVEQ); continue; case _SC('>'): NEXT(); RETURN_TOKEN(TK_ATTR_CLOSE); continue; default: RETURN_TOKEN('/'); } case _SC('='): NEXT(); if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') } else { NEXT(); RETURN_TOKEN(TK_EQ); } case _SC('<'): NEXT(); switch(CUR_CHAR) { case _SC('='): NEXT(); if(CUR_CHAR == _SC('>')) { NEXT(); RETURN_TOKEN(TK_3WAYSCMP); } RETURN_TOKEN(TK_LE) break; case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break; case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break; case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break; } RETURN_TOKEN('<'); case _SC('>'): NEXT(); if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);} else if(CUR_CHAR == _SC('>')){ NEXT(); if(CUR_CHAR == _SC('>')){ NEXT(); RETURN_TOKEN(TK_USHIFTR); } RETURN_TOKEN(TK_SHIFTR); } else { RETURN_TOKEN('>') } case _SC('!'): NEXT(); if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')} else { NEXT(); RETURN_TOKEN(TK_NE); } case _SC('@'): { SQInteger stype; NEXT(); if(CUR_CHAR != _SC('"')) { RETURN_TOKEN('@'); } if((stype=ReadString('"',true))!=-1) { RETURN_TOKEN(stype); } Error(_SC("error parsing the string")); } case _SC('"'): case _SC('\''): { SQInteger stype; if((stype=ReadString(CUR_CHAR,false))!=-1){ RETURN_TOKEN(stype); } Error(_SC("error parsing the string")); } case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'): case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'): {SQInteger ret = CUR_CHAR; NEXT(); RETURN_TOKEN(ret); } case _SC('.'): NEXT(); if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') } NEXT(); if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); } NEXT(); RETURN_TOKEN(TK_VARPARAMS); case _SC('&'): NEXT(); if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') } else { NEXT(); RETURN_TOKEN(TK_AND); } case _SC('|'): NEXT(); if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') } else { NEXT(); RETURN_TOKEN(TK_OR); } case _SC(':'): NEXT(); if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') } else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } case _SC('*'): NEXT(); if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);} else RETURN_TOKEN('*'); case _SC('%'): NEXT(); if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);} else RETURN_TOKEN('%'); case _SC('-'): NEXT(); if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} else RETURN_TOKEN('-'); case _SC('+'): NEXT(); if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} else RETURN_TOKEN('+'); case SQUIRREL_EOB: return 0; default:{ if (scisdigit(CUR_CHAR)) { SQInteger ret = ReadNumber(); RETURN_TOKEN(ret); } else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) { SQInteger t = ReadID(); RETURN_TOKEN(t); } else { SQInteger c = CUR_CHAR; if (sciscntrl((int)c)) Error(_SC("unexpected character(control)")); NEXT(); RETURN_TOKEN(c); } RETURN_TOKEN(0); } } } return 0; } SQInteger SQLexer::GetIDType(const SQChar *s,SQInteger len) { SQObjectPtr t; if(_keywords->GetStr(s,len, t)) { return SQInteger(_integer(t)); } return TK_IDENTIFIER; } #ifdef SQUNICODE #if WCHAR_SIZE == 2 SQInteger SQLexer::AddUTF16(SQUnsignedInteger ch) { if (ch >= 0x10000) { SQUnsignedInteger code = (ch - 0x10000); APPEND_CHAR((SQChar)(0xD800 | (code >> 10))); APPEND_CHAR((SQChar)(0xDC00 | (code & 0x3FF))); return 2; } else { APPEND_CHAR((SQChar)ch); return 1; } } #endif #else SQInteger SQLexer::AddUTF8(SQUnsignedInteger ch) { if (ch < 0x80) { APPEND_CHAR((char)ch); return 1; } if (ch < 0x800) { APPEND_CHAR((SQChar)((ch >> 6) | 0xC0)); APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80)); return 2; } if (ch < 0x10000) { APPEND_CHAR((SQChar)((ch >> 12) | 0xE0)); APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80)); APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80)); return 3; } if (ch < 0x110000) { APPEND_CHAR((SQChar)((ch >> 18) | 0xF0)); APPEND_CHAR((SQChar)(((ch >> 12) & 0x3F) | 0x80)); APPEND_CHAR((SQChar)(((ch >> 6) & 0x3F) | 0x80)); APPEND_CHAR((SQChar)((ch & 0x3F) | 0x80)); return 4; } return 0; } #endif SQInteger SQLexer::ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits) { NEXT(); if (!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected")); SQInteger n = 0; while (isxdigit(CUR_CHAR) && n < maxdigits) { dest[n] = CUR_CHAR; n++; NEXT(); } dest[n] = 0; return n; } SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim) { INIT_TEMP_STRING(); NEXT(); if(IS_EOB()) return -1; for(;;) { while(CUR_CHAR != ndelim) { SQInteger x = CUR_CHAR; switch (x) { case SQUIRREL_EOB: Error(_SC("unfinished string")); return -1; case _SC('\n'): if(!verbatim) Error(_SC("newline in a constant")); APPEND_CHAR(CUR_CHAR); NEXT(); _currentline++; break; case _SC('\\'): if(verbatim) { APPEND_CHAR('\\'); NEXT(); } else { NEXT(); switch(CUR_CHAR) { case _SC('x'): { const SQInteger maxdigits = sizeof(SQChar) * 2; SQChar temp[maxdigits + 1]; ProcessStringHexEscape(temp, maxdigits); SQChar *stemp; APPEND_CHAR((SQChar)scstrtoul(temp, &stemp, 16)); } break; case _SC('U'): case _SC('u'): { const SQInteger maxdigits = CUR_CHAR == 'u' ? 4 : 8; SQChar temp[8 + 1]; ProcessStringHexEscape(temp, maxdigits); SQChar *stemp; #ifdef SQUNICODE #if WCHAR_SIZE == 2 AddUTF16(scstrtoul(temp, &stemp, 16)); #else APPEND_CHAR((SQChar)scstrtoul(temp, &stemp, 16)); #endif #else AddUTF8(scstrtoul(temp, &stemp, 16)); #endif } break; case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break; case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break; case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break; case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break; case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break; case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break; case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break; case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break; case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break; case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break; case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break; default: Error(_SC("unrecognised escaper char")); break; } } break; default: APPEND_CHAR(CUR_CHAR); NEXT(); } } NEXT(); if(verbatim && CUR_CHAR == '"') { //double quotation APPEND_CHAR(CUR_CHAR); NEXT(); } else { break; } } TERMINATE_BUFFER(); SQInteger len = _longstr.size()-1; if(ndelim == _SC('\'')) { if(len == 0) Error(_SC("empty constant")); if(len > 1) Error(_SC("constant too long")); _nvalue = _longstr[0]; return TK_INTEGER; } _svalue = &_longstr[0]; return TK_STRING_LITERAL; } void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0'); else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); else { assert(0); } } } void LexInteger(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { *res = (*res)*10+((*s++)-'0'); } } SQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); } void LexOctal(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0'); else { assert(0); } } } SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } #define MAX_HEX_DIGITS (sizeof(SQInteger)*2) SQInteger SQLexer::ReadNumber() { #define TINT 1 #define TFLOAT 2 #define THEX 3 #define TSCIENTIFIC 4 #define TOCTAL 5 SQInteger type = TINT, firstchar = CUR_CHAR; SQChar *sTemp; INIT_TEMP_STRING(); NEXT(); if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) { if(scisodigit(CUR_CHAR)) { type = TOCTAL; while(scisodigit(CUR_CHAR)) { APPEND_CHAR(CUR_CHAR); NEXT(); } if(scisdigit(CUR_CHAR)) Error(_SC("invalid octal number")); } else { NEXT(); type = THEX; while(isxdigit(CUR_CHAR)) { APPEND_CHAR(CUR_CHAR); NEXT(); } if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number")); } } else { APPEND_CHAR((int)firstchar); while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { if(CUR_CHAR == _SC('.') || isexponent(CUR_CHAR)) type = TFLOAT; if(isexponent(CUR_CHAR)) { if(type != TFLOAT) Error(_SC("invalid numeric format")); type = TSCIENTIFIC; APPEND_CHAR(CUR_CHAR); NEXT(); if(CUR_CHAR == '+' || CUR_CHAR == '-'){ APPEND_CHAR(CUR_CHAR); NEXT(); } if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected")); } APPEND_CHAR(CUR_CHAR); NEXT(); } } TERMINATE_BUFFER(); switch(type) { case TSCIENTIFIC: case TFLOAT: _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); return TK_FLOAT; case TINT: LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; case THEX: LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; case TOCTAL: LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; } return 0; } SQInteger SQLexer::ReadID() { SQInteger res; INIT_TEMP_STRING(); do { APPEND_CHAR(CUR_CHAR); NEXT(); } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); TERMINATE_BUFFER(); res = GetIDType(&_longstr[0],_longstr.size() - 1); if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) { _svalue = &_longstr[0]; } return res; } simutrans-124.3/src/squirrel/squirrel/sqlexer.h000066400000000000000000000023441474050137200217150ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQLEXER_H_ #define _SQLEXER_H_ #ifdef SQUNICODE typedef SQChar LexChar; #else typedef unsigned char LexChar; #endif struct SQLexer { SQLexer(); ~SQLexer(); void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); void Error(const SQChar *err); SQInteger Lex(); const SQChar *Tok2Str(SQInteger tok); private: SQInteger GetIDType(const SQChar *s,SQInteger len); SQInteger ReadString(SQInteger ndelim,bool verbatim); SQInteger ReadNumber(); void LexBlockComment(); void LexLineComment(); SQInteger ReadID(); void Next(); #ifdef SQUNICODE #if WCHAR_SIZE == 2 SQInteger AddUTF16(SQUnsignedInteger ch); #endif #else SQInteger AddUTF8(SQUnsignedInteger ch); #endif SQInteger ProcessStringHexEscape(SQChar *dest, SQInteger maxdigits); SQInteger _curtoken; SQTable *_keywords; SQBool _reached_eof; public: SQInteger _prevtoken; SQInteger _currentline; SQInteger _lasttokenline; SQInteger _currentcolumn; const SQChar *_svalue; SQInteger _nvalue; SQFloat _fvalue; SQLEXREADFUNC _readf; SQUserPointer _up; LexChar _currdata; SQSharedState *_sharedstate; sqvector _longstr; CompilerErrorFunc _errfunc; void *_errtarget; }; #endif simutrans-124.3/src/squirrel/squirrel/sqmem.cc000066400000000000000000000005751474050137200215160ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #ifndef SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); } void *sq_vm_realloc(void *p, SQUnsignedInteger SQ_UNUSED_ARG(oldsize), SQUnsignedInteger size){ return realloc(p, size); } void sq_vm_free(void *p, SQUnsignedInteger SQ_UNUSED_ARG(size)){ free(p); } #endif simutrans-124.3/src/squirrel/squirrel/sqobject.cc000066400000000000000000000473711474050137200222130ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqarray.h" #include "sqtable.h" #include "squserdata.h" #include "sqfuncproto.h" #include "sqclass.h" #include "sqclosure.h" const SQChar *IdType2Name(SQObjectType type) { switch(_RAW_TYPE(type)) { case _RT_NULL:return _SC("null"); case _RT_INTEGER:return _SC("integer"); case _RT_FLOAT:return _SC("float"); case _RT_BOOL:return _SC("bool"); case _RT_STRING:return _SC("string"); case _RT_TABLE:return _SC("table"); case _RT_ARRAY:return _SC("array"); case _RT_GENERATOR:return _SC("generator"); case _RT_CLOSURE: case _RT_NATIVECLOSURE: return _SC("function"); case _RT_USERDATA: case _RT_USERPOINTER: return _SC("userdata"); case _RT_THREAD: return _SC("thread"); case _RT_FUNCPROTO: return _SC("function"); case _RT_CLASS: return _SC("class"); case _RT_INSTANCE: return _SC("instance"); case _RT_WEAKREF: return _SC("weakref"); case _RT_OUTER: return _SC("outer"); default: return NULL; } } const SQChar *GetTypeName(const SQObjectPtr &obj1) { return IdType2Name(sq_type(obj1)); } SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) { SQString *str=ADD_STRING(ss,s,len); return str; } void SQString::Release() { REMOVE_STRING(_sharedstate,this); } SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQInteger idx = (SQInteger)TranslateIndex(refpos); while(idx < _len){ outkey = (SQInteger)idx; outval = (SQInteger)((SQUnsignedInteger)_val[idx]); //return idx for the next iteration return ++idx; } //nothing to iterate anymore return -1; } SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) { switch(sq_type(idx)){ case OT_NULL: return 0; case OT_INTEGER: return (SQUnsignedInteger)_integer(idx); default: assert(0); break; } return 0; } SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type) { if(!_weakref) { sq_new(_weakref,SQWeakRef); #if defined(SQUSEDOUBLE) && !defined(_SQ64) _weakref->_obj._unVal.raw = 0; //clean the whole union on 32 bits with double #endif _weakref->_obj._type = type; _weakref->_obj._unVal.pRefCounted = this; } return _weakref; } SQRefCounted::~SQRefCounted() { if(_weakref) { _weakref->_obj._type = OT_NULL; _weakref->_obj._unVal.pRefCounted = NULL; } } void SQWeakRef::Release() { if(ISREFCOUNTED(_obj._type)) { _obj._unVal.pRefCounted->_weakref = NULL; } sq_delete(this,SQWeakRef); } bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(_delegate) { return _delegate->Get((*_ss(v)->_metamethods)[mm],res); } return false; } bool SQDelegable::SetDelegate(SQTable *mt) { SQTable *temp = mt; if(temp == this) return false; while (temp) { if (temp->_delegate == this) return false; //cycle detected temp = temp->_delegate; } if (mt) __ObjAddRef(mt); __ObjRelease(_delegate); _delegate = mt; return true; } bool SQGenerator::Yield(SQVM *v,SQInteger target) { if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;} if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; } SQInteger size = v->_top-v->_stackbase; _stack.resize(size); SQObject _this = v->_stack[v->_stackbase]; _stack._vals[0] = ISREFCOUNTED(sq_type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(sq_type(_this))) : _this; for(SQInteger n =1; n_stack[v->_stackbase+n]; } for(SQInteger j =0; j < size; j++) { v->_stack[v->_stackbase+j].Null(); } _ci = *v->ci; _ci._generator=NULL; for(SQInteger i=0;i<_ci._etraps;i++) { _etraps.push_back(v->_etraps.top()); v->_etraps.pop_back(); // store relative stack base and size in case of resume to other _top SQExceptionTrap &et = _etraps.back(); et._stackbase -= v->_stackbase; et._stacksize -= v->_stackbase; } _state=eSuspended; return true; } bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest) { if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; } if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; } SQInteger size = _stack.size(); SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]); assert(target>=0 && target<=255); SQInteger newbase = v->_top; if(!v->EnterFrame(v->_top, v->_top + size, false)) return false; v->ci->_generator = this; v->ci->_target = (SQInt32)target; v->ci->_closure = _ci._closure; v->ci->_ip = _ci._ip; v->ci->_literals = _ci._literals; v->ci->_ncalls = _ci._ncalls; v->ci->_etraps = _ci._etraps; v->ci->_root = _ci._root; for(SQInteger i=0;i<_ci._etraps;i++) { v->_etraps.push_back(_etraps.top()); _etraps.pop_back(); SQExceptionTrap &et = v->_etraps.back(); // restore absolute stack base and size et._stackbase += newbase; et._stacksize += newbase; } SQObject _this = _stack._vals[0]; v->_stack[v->_stackbase] = sq_type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this; for(SQInteger n = 1; n_stack[v->_stackbase+n] = _stack._vals[n]; _stack._vals[n].Null(); } _state=eRunning; if (v->_debughook) v->CallDebugHook(_SC('c')); return true; } void SQArray::Extend(const SQArray *a){ SQInteger xlen; if((xlen=a->Size())) for(SQInteger i=0;i_values[i]); } const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop) { SQUnsignedInteger nvars=_nlocalvarinfos; const SQChar *res=NULL; if(nvars>=nseq){ for(SQUnsignedInteger i=0;i=nop) { if(nseq==0){ vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); res=_stringval(_localvarinfos[i]._name); break; } nseq--; } } } return res; } SQInteger SQFunctionProto::GetLine(SQInstruction *curr) { SQInteger op = (SQInteger)(curr-_instructions); SQInteger line=_lineinfos[0]._line; SQInteger low = 0; SQInteger high = _nlineinfos - 1; SQInteger mid = 0; while(low <= high) { mid = low + ((high - low) >> 1); SQInteger curop = _lineinfos[mid]._op; if(curop > op) { high = mid - 1; } else if(curop < op) { if(mid < (_nlineinfos - 1) && _lineinfos[mid + 1]._op >= op) { break; } low = mid + 1; } else { //equal break; } } while(mid > 0 && _lineinfos[mid]._op >= op) mid--; line = _lineinfos[mid]._line; return line; } SQClosure::~SQClosure() { __ObjRelease(_root); __ObjRelease(_env); __ObjRelease(_base); REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } #define _CHECK_IO(exp) { if(!exp)return false; } bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size) { if(write(up,dest,size) != size) { v->Raise_Error(_SC("io error (write function failure)")); return false; } return true; } bool SafeRead(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size) { if(size && read(up,dest,size) != size) { v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated")); return false; } return true; } bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag) { return SafeWrite(v,write,up,&tag,sizeof(tag)); } bool CheckTag(HSQUIRRELVM v,SQREADFUNC read,SQUserPointer up,SQUnsignedInteger32 tag) { SQUnsignedInteger32 t; _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); if(t != tag){ v->Raise_Error(_SC("invalid or corrupted closure stream")); return false; } return true; } bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) { SQUnsignedInteger32 _type = (SQUnsignedInteger32)sq_type(o); _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type))); switch(sq_type(o)){ case OT_STRING: _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); _CHECK_IO(SafeWrite(v,write,up,_stringval(o),sq_rsl(_string(o)->_len))); break; case OT_BOOL: case OT_INTEGER: _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; case OT_FLOAT: _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; case OT_NULL: break; default: v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o)); return false; } return true; } bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) { SQUnsignedInteger32 _type; _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type))); SQObjectType t = (SQObjectType)_type; switch(t){ case OT_STRING:{ SQInteger len; _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(sq_rsl(len)),sq_rsl(len))); o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); } break; case OT_INTEGER:{ SQInteger i; _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; } case OT_BOOL:{ SQInteger i; _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o._type = OT_BOOL; o._unVal.nInteger = i; break; } case OT_FLOAT:{ SQFloat f; _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; } case OT_NULL: o.Null(); break; default: v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t)); return false; } return true; } bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) { _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger))); _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat))); _CHECK_IO(_function->Save(v,up,write)); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); return true; } bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) { _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger))); _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat))); SQObjectPtr func; _CHECK_IO(SQFunctionProto::Load(v,up,read,func)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); ret = SQClosure::Create(_ss(v),_funcproto(func),_table(v->_roottable)->GetWeakRef(OT_TABLE)); //FIXME: load an root for this closure return true; } SQFunctionProto::SQFunctionProto(SQSharedState *ss) { _stacksize=0; _bgenerator=false; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } SQFunctionProto::~SQFunctionProto() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) { SQInteger i,nliterals = _nliterals,nparameters = _nparameters; SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; SQInteger ndefaultparams = _ndefaultparams; _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(WriteObject(v,up,write,_sourcename)); _CHECK_IO(WriteObject(v,up,write,_name)); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals))); _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); for(i=0;iSave(v,up,write)); } _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); return true; } bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) { SQInteger i, nliterals,nparameters; SQInteger noutervalues ,nlocalvarinfos ; SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; SQObjectPtr sourcename, name; SQObjectPtr o; _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(ReadObject(v, up, read, sourcename)); _CHECK_IO(ReadObject(v, up, read, name)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals))); _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters, nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); SQObjectPtr proto = f; //gets a ref in case of failure f->_sourcename = sourcename; f->_name = name; _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0;i < nliterals; i++){ _CHECK_IO(ReadObject(v, up, read, o)); f->_literals[i] = o; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nparameters; i++){ _CHECK_IO(ReadObject(v, up, read, o)); f->_parameters[i] = o; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < noutervalues; i++){ SQUnsignedInteger type; SQObjectPtr name; _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger))); _CHECK_IO(ReadObject(v, up, read, o)); _CHECK_IO(ReadObject(v, up, read, name)); f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type); } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nlocalvarinfos; i++){ SQLocalVarInfo lvi; _CHECK_IO(ReadObject(v, up, read, lvi._name)); _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger))); _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger))); _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger))); f->_localvarinfos[i] = lvi; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nfunctions; i++){ _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); f->_functions[i] = o; } _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); ret = f; return true; } #ifndef NO_GARBAGE_COLLECTOR #define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ _uiRef|=MARK_FLAG; #define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ AddToChain(chain, this); } void SQVM::Mark(SQCollectable **chain) { START_MARK() SQSharedState::MarkObject(_lasterror,chain); SQSharedState::MarkObject(_errorhandler,chain); SQSharedState::MarkObject(_debughook_closure,chain); SQSharedState::MarkObject(_roottable, chain); SQSharedState::MarkObject(temp_reg, chain); for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); END_MARK() } void SQArray::Mark(SQCollectable **chain) { START_MARK() SQInteger len = _values.size(); for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); END_MARK() } void SQTable::Mark(SQCollectable **chain) { START_MARK() if(_delegate) _delegate->Mark(chain); SQInteger len = _numofnodes; for(SQInteger i = 0; i < len; i++){ SQSharedState::MarkObject(_nodes[i].key, chain); SQSharedState::MarkObject(_nodes[i].val, chain); } END_MARK() } void SQClass::Mark(SQCollectable **chain) { START_MARK() _members->Mark(chain); if(_base) _base->Mark(chain); SQSharedState::MarkObject(_attributes, chain); for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { SQSharedState::MarkObject(_defaultvalues[i].val, chain); SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); } for(SQUnsignedInteger j =0; j< _methods.size(); j++) { SQSharedState::MarkObject(_methods[j].val, chain); SQSharedState::MarkObject(_methods[j].attrs, chain); } for(SQUnsignedInteger k =0; k< MT_LAST; k++) { SQSharedState::MarkObject(_metamethods[k], chain); } END_MARK() } void SQInstance::Mark(SQCollectable **chain) { START_MARK() _class->Mark(chain); SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger i =0; i< nvalues; i++) { SQSharedState::MarkObject(_values[i], chain); } END_MARK() } void SQGenerator::Mark(SQCollectable **chain) { START_MARK() for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); SQSharedState::MarkObject(_closure, chain); END_MARK() } void SQFunctionProto::Mark(SQCollectable **chain) { START_MARK() for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain); for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain); END_MARK() } void SQClosure::Mark(SQCollectable **chain) { START_MARK() if(_base) _base->Mark(chain); SQFunctionProto *fp = _function; fp->Mark(chain); for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain); END_MARK() } void SQNativeClosure::Mark(SQCollectable **chain) { START_MARK() for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); END_MARK() } void SQOuter::Mark(SQCollectable **chain) { START_MARK() /* If the valptr points to a closed value, that value is alive */ if(_valptr == &_value) { SQSharedState::MarkObject(_value, chain); } END_MARK() } void SQUserData::Mark(SQCollectable **chain){ START_MARK() if(_delegate) _delegate->Mark(chain); END_MARK() } void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } #endif simutrans-124.3/src/squirrel/squirrel/sqobject.h000066400000000000000000000213461474050137200220470ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQOBJECT_H_ #define _SQOBJECT_H_ #include "squtils.h" #ifdef _SQ64 #define UINT_MINUS_ONE (0xFFFFFFFFFFFFFFFF) #else #define UINT_MINUS_ONE (0xFFFFFFFF) #endif #define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) #define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) #define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) struct SQSharedState; enum SQMetaMethod{ MT_ADD=0, MT_SUB=1, MT_MUL=2, MT_DIV=3, MT_UNM=4, MT_MODULO=5, MT_SET=6, MT_GET=7, MT_TYPEOF=8, MT_NEXTI=9, MT_CMP=10, MT_CALL=11, MT_CLONED=12, MT_NEWSLOT=13, MT_DELSLOT=14, MT_TOSTRING=15, MT_NEWMEMBER=16, MT_INHERITED=17, MT_LAST = 18 }; #define MM_ADD _SC("_add") #define MM_SUB _SC("_sub") #define MM_MUL _SC("_mul") #define MM_DIV _SC("_div") #define MM_UNM _SC("_unm") #define MM_MODULO _SC("_modulo") #define MM_SET _SC("_set") #define MM_GET _SC("_get") #define MM_TYPEOF _SC("_typeof") #define MM_NEXTI _SC("_nexti") #define MM_CMP _SC("_cmp") #define MM_CALL _SC("_call") #define MM_CLONED _SC("_cloned") #define MM_NEWSLOT _SC("_newslot") #define MM_DELSLOT _SC("_delslot") #define MM_TOSTRING _SC("_tostring") #define MM_NEWMEMBER _SC("_newmember") #define MM_INHERITED _SC("_inherited") #define _CONSTRUCT_VECTOR(type,size,ptr) { \ for(SQInteger n = 0; n < ((SQInteger)size); n++) { \ new (&ptr[n]) type(); \ } \ } #define _DESTRUCT_VECTOR(type,size,ptr) { \ for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \ ptr[nl].~type(); \ } \ } #define _COPY_VECTOR(dest,src,size) { \ for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ dest[_n_] = src[_n_]; \ } \ } #define _NULL_SQOBJECT_VECTOR(vec,size) { \ for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ vec[_n_].Null(); \ } \ } #define MINPOWER2 4 struct SQRefCounted { SQUnsignedInteger _uiRef; struct SQWeakRef *_weakref; SQRefCounted() { _uiRef = 0; _weakref = NULL; } virtual ~SQRefCounted(); SQWeakRef *GetWeakRef(SQObjectType type); virtual void Release()=0; }; struct SQWeakRef : SQRefCounted { void Release(); SQObject _obj; }; #define _realval(o) (sq_type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj) struct SQObjectPtr; #define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ { \ unval.pRefCounted->_uiRef++; \ } #define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0)) \ { \ unval.pRefCounted->Release(); \ } #define __ObjRelease(obj) { \ if((obj)) { \ (obj)->_uiRef--; \ if((obj)->_uiRef == 0) \ (obj)->Release(); \ (obj) = NULL; \ } \ } #define __ObjAddRef(obj) { \ (obj)->_uiRef++; \ } #define is_delegable(t) (sq_type(t)&SQOBJECT_DELEGABLE) #define raw_type(obj) _RAW_TYPE((obj)._type) #define _integer(obj) ((obj)._unVal.nInteger) #define _float(obj) ((obj)._unVal.fFloat) #define _string(obj) ((obj)._unVal.pString) #define _table(obj) ((obj)._unVal.pTable) #define _array(obj) ((obj)._unVal.pArray) #define _closure(obj) ((obj)._unVal.pClosure) #define _generator(obj) ((obj)._unVal.pGenerator) #define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) #define _userdata(obj) ((obj)._unVal.pUserData) #define _userpointer(obj) ((obj)._unVal.pUserPointer) #define _thread(obj) ((obj)._unVal.pThread) #define _funcproto(obj) ((obj)._unVal.pFunctionProto) #define _class(obj) ((obj)._unVal.pClass) #define _instance(obj) ((obj)._unVal.pInstance) #define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) #define _weakref(obj) ((obj)._unVal.pWeakRef) #define _outer(obj) ((obj)._unVal.pOuter) #define _refcounted(obj) ((obj)._unVal.pRefCounted) #define _rawval(obj) ((obj)._unVal.raw) #define _stringval(obj) (obj)._unVal.pString->_val #define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1)) #define tofloat(num) ((sq_type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) #define tointeger(num) ((sq_type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// #if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64) #define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT() #else #define SQ_REFOBJECT_INIT() #endif #define _REF_TYPE_DECL(type,_class,sym) \ SQObjectPtr(_class * x) \ { \ SQ_OBJECT_RAWINIT() \ _type=type; \ _unVal.sym = x; \ assert(_unVal.pTable); \ _unVal.pRefCounted->_uiRef++; \ } \ inline SQObjectPtr& operator=(_class *x) \ { \ SQObjectType tOldType; \ SQObjectValue unOldVal; \ tOldType=_type; \ unOldVal=_unVal; \ _type = type; \ SQ_REFOBJECT_INIT() \ _unVal.sym = x; \ _unVal.pRefCounted->_uiRef++; \ __Release(tOldType,unOldVal); \ return *this; \ } #define _SCALAR_TYPE_DECL(type,_class,sym) \ SQObjectPtr(_class x) \ { \ SQ_OBJECT_RAWINIT() \ _type=type; \ _unVal.sym = x; \ } \ inline SQObjectPtr& operator=(_class x) \ { \ __Release(_type,_unVal); \ _type = type; \ SQ_OBJECT_RAWINIT() \ _unVal.sym = x; \ return *this; \ } struct SQObjectPtr : public SQObject { SQObjectPtr() { SQ_OBJECT_RAWINIT() _type=OT_NULL; _unVal.pUserPointer=NULL; } SQObjectPtr(const SQObjectPtr &o) { _type = o._type; _unVal = o._unVal; __AddRef(_type,_unVal); } SQObjectPtr(const SQObject &o) { _type = o._type; _unVal = o._unVal; __AddRef(_type,_unVal); } _REF_TYPE_DECL(OT_TABLE,SQTable,pTable) _REF_TYPE_DECL(OT_CLASS,SQClass,pClass) _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance) _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray) _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure) _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure) _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter) _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator) _REF_TYPE_DECL(OT_STRING,SQString,pString) _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData) _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef) _REF_TYPE_DECL(OT_THREAD,SQVM,pThread) _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto) _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger) _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat) _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer) SQObjectPtr(bool bBool) { SQ_OBJECT_RAWINIT() _type = OT_BOOL; _unVal.nInteger = bBool?1:0; } inline SQObjectPtr& operator=(bool b) { __Release(_type,_unVal); SQ_OBJECT_RAWINIT() _type = OT_BOOL; _unVal.nInteger = b?1:0; return *this; } ~SQObjectPtr() { __Release(_type,_unVal); } inline SQObjectPtr& operator=(const SQObjectPtr& obj) { SQObjectType tOldType; SQObjectValue unOldVal; tOldType=_type; unOldVal=_unVal; _unVal = obj._unVal; _type = obj._type; __AddRef(_type,_unVal); __Release(tOldType,unOldVal); return *this; } inline SQObjectPtr& operator=(const SQObject& obj) { SQObjectType tOldType; SQObjectValue unOldVal; tOldType=_type; unOldVal=_unVal; _unVal = obj._unVal; _type = obj._type; __AddRef(_type,_unVal); __Release(tOldType,unOldVal); return *this; } inline void Null() { SQObjectType tOldType = _type; SQObjectValue unOldVal = _unVal; _type = OT_NULL; _unVal.raw = (SQRawObjectVal)NULL; __Release(tOldType ,unOldVal); } private: SQObjectPtr(const SQChar *){} //safety }; inline void _Swap(SQObject &a,SQObject &b) { SQObjectType tOldType = a._type; SQObjectValue unOldVal = a._unVal; a._type = b._type; a._unVal = b._unVal; b._type = tOldType; b._unVal = unOldVal; } ///////////////////////////////////////////////////////////////////////////////////// #ifndef NO_GARBAGE_COLLECTOR #define MARK_FLAG 0x80000000 struct SQCollectable : public SQRefCounted { SQCollectable *_next; SQCollectable *_prev; SQSharedState *_sharedstate; virtual SQObjectType GetType()=0; virtual void Release()=0; virtual void Mark(SQCollectable **chain)=0; void UnMark(); virtual void Finalize()=0; static void AddToChain(SQCollectable **chain,SQCollectable *c); static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); }; #define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) #define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} #define CHAINABLE_OBJ SQCollectable #define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} #else #define ADD_TO_CHAIN(chain,obj) ((void)0) #define REMOVE_FROM_CHAIN(chain,obj) ((void)0) #define CHAINABLE_OBJ SQRefCounted #define INIT_CHAIN() ((void)0) #endif struct SQDelegable : public CHAINABLE_OBJ { bool SetDelegate(SQTable *m); virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQTable *_delegate; }; SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); typedef sqvector SQObjectPtrVec; typedef sqvector SQIntVec; const SQChar *GetTypeName(const SQObjectPtr &obj1); const SQChar *IdType2Name(SQObjectType type); #endif simutrans-124.3/src/squirrel/squirrel/sqopcodes.h000066400000000000000000000046071474050137200222360ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQOPCODES_H_ #define _SQOPCODES_H_ #define MAX_FUNC_STACKSIZE 0xFF #define MAX_LITERALS ((SQInteger)0x7FFFFFFF) enum BitWiseOP { BW_AND = 0, BW_OR = 2, BW_XOR = 3, BW_SHIFTL = 4, BW_SHIFTR = 5, BW_USHIFTR = 6 }; enum CmpOP { CMP_G = 0, CMP_GE = 2, CMP_L = 3, CMP_LE = 4, CMP_3W = 5 }; enum NewObjectType { NOT_TABLE = 0, NOT_ARRAY = 1, NOT_CLASS = 2 }; enum AppendArrayType { AAT_STACK = 0, AAT_LITERAL = 1, AAT_INT = 2, AAT_FLOAT = 3, AAT_BOOL = 4 }; enum SQOpcode { _OP_LINE= 0x00, _OP_LOAD= 0x01, _OP_LOADINT= 0x02, _OP_LOADFLOAT= 0x03, _OP_DLOAD= 0x04, _OP_TAILCALL= 0x05, _OP_CALL= 0x06, _OP_PREPCALL= 0x07, _OP_PREPCALLK= 0x08, _OP_GETK= 0x09, _OP_MOVE= 0x0A, _OP_NEWSLOT= 0x0B, _OP_DELETE= 0x0C, _OP_SET= 0x0D, _OP_GET= 0x0E, _OP_EQ= 0x0F, _OP_NE= 0x10, _OP_ADD= 0x11, _OP_SUB= 0x12, _OP_MUL= 0x13, _OP_DIV= 0x14, _OP_MOD= 0x15, _OP_BITW= 0x16, _OP_RETURN= 0x17, _OP_LOADNULLS= 0x18, _OP_LOADROOT= 0x19, _OP_LOADBOOL= 0x1A, _OP_DMOVE= 0x1B, _OP_JMP= 0x1C, //_OP_JNZ= 0x1D, _OP_JCMP= 0x1D, _OP_JZ= 0x1E, _OP_SETOUTER= 0x1F, _OP_GETOUTER= 0x20, _OP_NEWOBJ= 0x21, _OP_APPENDARRAY= 0x22, _OP_COMPARITH= 0x23, _OP_INC= 0x24, _OP_INCL= 0x25, _OP_PINC= 0x26, _OP_PINCL= 0x27, _OP_CMP= 0x28, _OP_EXISTS= 0x29, _OP_INSTANCEOF= 0x2A, _OP_AND= 0x2B, _OP_OR= 0x2C, _OP_NEG= 0x2D, _OP_NOT= 0x2E, _OP_BWNOT= 0x2F, _OP_CLOSURE= 0x30, _OP_YIELD= 0x31, _OP_RESUME= 0x32, _OP_FOREACH= 0x33, _OP_POSTFOREACH= 0x34, _OP_CLONE= 0x35, _OP_TYPEOF= 0x36, _OP_PUSHTRAP= 0x37, _OP_POPTRAP= 0x38, _OP_THROW= 0x39, _OP_NEWSLOTA= 0x3A, _OP_GETBASE= 0x3B, _OP_CLOSE= 0x3C, }; struct SQInstructionDesc { const SQChar *name; }; struct SQInstruction { SQInstruction(){}; SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) { op = (unsigned char)_op; _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; } SQInt32 _arg1; unsigned char op; unsigned char _arg0; unsigned char _arg2; unsigned char _arg3; }; #include "squtils.h" typedef sqvector SQInstructionVec; #define NEW_SLOT_ATTRIBUTES_FLAG 0x01 #define NEW_SLOT_STATIC_FLAG 0x02 #endif simutrans-124.3/src/squirrel/squirrel/sqpcheader.h000066400000000000000000000005541474050137200223520ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQPCHEADER_H_ #define _SQPCHEADER_H_ #if defined(_MSC_VER) && defined(_DEBUG) #include #endif #include #include #include #include #include #include //squirrel stuff #include "../squirrel.h" #include "sqobject.h" #include "sqstate.h" #endif simutrans-124.3/src/squirrel/squirrel/sqstate.cc000066400000000000000000000364411474050137200220610ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqopcodes.h" #include "sqvm.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "squserdata.h" #include "sqclass.h" SQSharedState::SQSharedState() { _compilererrorhandler = NULL; _printfunc = NULL; _errorfunc = NULL; _debuginfo = false; _notifyallexceptions = false; _foreignptr = NULL; _releasehook = NULL; } #define newsysstring(s) { \ _systemstrings->push_back(SQString::Create(this,s)); \ } #define newmetamethod(s) { \ _metamethods->push_back(SQString::Create(this,s)); \ _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ } bool CompileTypemask(SQIntVec &res,const SQChar *typemask) { SQInteger i = 0; SQInteger mask = 0; while(typemask[i] != 0) { switch(typemask[i]){ case 'o': mask |= _RT_NULL; break; case 'i': mask |= _RT_INTEGER; break; case 'f': mask |= _RT_FLOAT; break; case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; case 's': mask |= _RT_STRING; break; case 't': mask |= _RT_TABLE; break; case 'a': mask |= _RT_ARRAY; break; case 'u': mask |= _RT_USERDATA; break; case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; case 'b': mask |= _RT_BOOL; break; case 'g': mask |= _RT_GENERATOR; break; case 'p': mask |= _RT_USERPOINTER; break; case 'v': mask |= _RT_THREAD; break; case 'x': mask |= _RT_INSTANCE; break; case 'y': mask |= _RT_CLASS; break; case 'r': mask |= _RT_WEAKREF; break; case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; case ' ': i++; continue; //ignores spaces default: return false; } i++; if(typemask[i] == '|') { i++; if(typemask[i] == 0) return false; continue; } res.push_back(mask); mask = 0; } return true; } SQTable *CreateDefaultDelegate(SQSharedState *ss,const SQRegFunction *funcz) { SQInteger i=0; SQTable *t=SQTable::Create(ss,0); while(funcz[i].name!=0){ SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0); nc->_nparamscheck = funcz[i].nparamscheck; nc->_name = SQString::Create(ss,funcz[i].name); if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) return NULL; t->NewSlot(SQString::Create(ss,funcz[i].name),nc); i++; } return t; } void SQSharedState::Init() { _scratchpad=NULL; _scratchpadsize=0; #ifndef NO_GARBAGE_COLLECTOR _gc_chain=NULL; #endif _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable)); new (_stringtable) SQStringTable(this); sq_new(_metamethods,SQObjectPtrVec); sq_new(_systemstrings,SQObjectPtrVec); sq_new(_types,SQObjectPtrVec); _metamethodsmap = SQTable::Create(this,MT_LAST-1); //adding type strings to avoid memory trashing //types names newsysstring(_SC("null")); newsysstring(_SC("table")); newsysstring(_SC("array")); newsysstring(_SC("closure")); newsysstring(_SC("string")); newsysstring(_SC("userdata")); newsysstring(_SC("integer")); newsysstring(_SC("float")); newsysstring(_SC("userpointer")); newsysstring(_SC("function")); newsysstring(_SC("generator")); newsysstring(_SC("thread")); newsysstring(_SC("class")); newsysstring(_SC("instance")); newsysstring(_SC("bool")); //meta methods newmetamethod(MM_ADD); newmetamethod(MM_SUB); newmetamethod(MM_MUL); newmetamethod(MM_DIV); newmetamethod(MM_UNM); newmetamethod(MM_MODULO); newmetamethod(MM_SET); newmetamethod(MM_GET); newmetamethod(MM_TYPEOF); newmetamethod(MM_NEXTI); newmetamethod(MM_CMP); newmetamethod(MM_CALL); newmetamethod(MM_CLONED); newmetamethod(MM_NEWSLOT); newmetamethod(MM_DELSLOT); newmetamethod(MM_TOSTRING); newmetamethod(MM_NEWMEMBER); newmetamethod(MM_INHERITED); _constructoridx = SQString::Create(this,_SC("constructor")); _registry = SQTable::Create(this,0); _consts = SQTable::Create(this,0); _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz); _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz); _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz); _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz); _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz); _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz); _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz); _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz); _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz); _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz); } SQSharedState::~SQSharedState() { if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; } _constructoridx.Null(); _table(_registry)->Finalize(); _table(_consts)->Finalize(); _table(_metamethodsmap)->Finalize(); _registry.Null(); _consts.Null(); _metamethodsmap.Null(); while(!_systemstrings->empty()) { _systemstrings->back().Null(); _systemstrings->pop_back(); } _thread(_root_vm)->Finalize(); _root_vm.Null(); _table_default_delegate.Null(); _array_default_delegate.Null(); _string_default_delegate.Null(); _number_default_delegate.Null(); _closure_default_delegate.Null(); _generator_default_delegate.Null(); _thread_default_delegate.Null(); _class_default_delegate.Null(); _instance_default_delegate.Null(); _weakref_default_delegate.Null(); _refs_table.Finalize(); #ifndef NO_GARBAGE_COLLECTOR SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; if(t) { t->_uiRef++; while(t) { t->Finalize(); nx = t->_next; if(nx) nx->_uiRef++; if(--t->_uiRef == 0) t->Release(); t = nx; } } assert(_gc_chain==NULL); //just to proove a theory while(_gc_chain){ _gc_chain->_uiRef++; _gc_chain->Release(); } #endif sq_delete(_types,SQObjectPtrVec); sq_delete(_systemstrings,SQObjectPtrVec); sq_delete(_metamethods,SQObjectPtrVec); sq_delete(_stringtable,SQStringTable); if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); } SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) { if(sq_type(name) != OT_STRING) return -1; SQObjectPtr ret; if(_table(_metamethodsmap)->Get(name,ret)) { return _integer(ret); } return -1; } #ifndef NO_GARBAGE_COLLECTOR void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) { switch(sq_type(o)){ case OT_TABLE:_table(o)->Mark(chain);break; case OT_ARRAY:_array(o)->Mark(chain);break; case OT_USERDATA:_userdata(o)->Mark(chain);break; case OT_CLOSURE:_closure(o)->Mark(chain);break; case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; case OT_GENERATOR:_generator(o)->Mark(chain);break; case OT_THREAD:_thread(o)->Mark(chain);break; case OT_CLASS:_class(o)->Mark(chain);break; case OT_INSTANCE:_instance(o)->Mark(chain);break; case OT_OUTER:_outer(o)->Mark(chain);break; case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break; default: break; //shutup compiler } } void SQSharedState::RunMark(SQVM* SQ_UNUSED_ARG(vm),SQCollectable **tchain) { SQVM *vms = _thread(_root_vm); vms->Mark(tchain); _refs_table.Mark(tchain); MarkObject(_registry,tchain); MarkObject(_consts,tchain); MarkObject(_metamethodsmap,tchain); MarkObject(_table_default_delegate,tchain); MarkObject(_array_default_delegate,tchain); MarkObject(_string_default_delegate,tchain); MarkObject(_number_default_delegate,tchain); MarkObject(_generator_default_delegate,tchain); MarkObject(_thread_default_delegate,tchain); MarkObject(_closure_default_delegate,tchain); MarkObject(_class_default_delegate,tchain); MarkObject(_instance_default_delegate,tchain); MarkObject(_weakref_default_delegate,tchain); } SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm) { SQInteger n=0; SQCollectable *tchain=NULL; RunMark(vm,&tchain); SQCollectable *resurrected = _gc_chain; SQCollectable *t = resurrected; _gc_chain = tchain; SQArray *ret = NULL; if(resurrected) { ret = SQArray::Create(this,0); SQCollectable *rlast = NULL; while(t) { rlast = t; SQObjectType type = t->GetType(); if(type != OT_FUNCPROTO && type != OT_OUTER) { SQObject sqo; sqo._type = type; sqo._unVal.pRefCounted = t; ret->Append(sqo); } t = t->_next; n++; } assert(rlast->_next == NULL); rlast->_next = _gc_chain; if(_gc_chain) { _gc_chain->_prev = rlast; } _gc_chain = resurrected; } t = _gc_chain; while(t) { t->UnMark(); t = t->_next; } if(ret) { SQObjectPtr temp = ret; vm->Push(temp); } else { vm->PushNull(); } return n; } SQInteger SQSharedState::CollectGarbage(SQVM *vm) { SQInteger n = 0; SQCollectable *tchain = NULL; RunMark(vm,&tchain); SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; if(t) { t->_uiRef++; while(t) { t->Finalize(); nx = t->_next; if(nx) nx->_uiRef++; if(--t->_uiRef == 0) t->Release(); t = nx; n++; } } t = tchain; while(t) { t->UnMark(); t = t->_next; } _gc_chain = tchain; return n; } #endif #ifndef NO_GARBAGE_COLLECTOR void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) { c->_prev = NULL; c->_next = *chain; if(*chain) (*chain)->_prev = c; *chain = c; } void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) { if(c->_prev) c->_prev->_next = c->_next; else *chain = c->_next; if(c->_next) c->_next->_prev = c->_prev; c->_next = NULL; c->_prev = NULL; } #endif SQChar* SQSharedState::GetScratchPad(SQInteger size) { SQInteger newsize; if(size>0) { if(_scratchpadsize < size) { newsize = size + (size>>1); _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); _scratchpadsize = newsize; }else if(_scratchpadsize >= (size<<5)) { newsize = _scratchpadsize >> 1; _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); _scratchpadsize = newsize; } } return _scratchpad; } RefTable::RefTable() { AllocNodes(4); } void RefTable::Finalize() { RefNode *nodes = _nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { nodes->obj.Null(); nodes++; } } RefTable::~RefTable() { SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); } #ifndef NO_GARBAGE_COLLECTOR void RefTable::Mark(SQCollectable **chain) { RefNode *nodes = (RefNode *)_nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { if(sq_type(nodes->obj) != OT_NULL) { SQSharedState::MarkObject(nodes->obj,chain); } nodes++; } } #endif void RefTable::AddRef(SQObject &obj) { SQHash mainpos; RefNode *prev; RefNode *ref = Get(obj,mainpos,&prev,true); ref->refs++; } SQUnsignedInteger RefTable::GetRefCount(SQObject &obj) { SQHash mainpos; RefNode *prev; RefNode *ref = Get(obj,mainpos,&prev,true); return ref->refs; } SQBool RefTable::Release(SQObject &obj) { SQHash mainpos; RefNode *prev; RefNode *ref = Get(obj,mainpos,&prev,false); if(ref) { if(--ref->refs == 0) { SQObjectPtr o = ref->obj; if(prev) { prev->next = ref->next; } else { _buckets[mainpos] = ref->next; } ref->next = _freelist; _freelist = ref; _slotused--; ref->obj.Null(); //<>test for shrink? return SQTrue; } } else { assert(0); } return SQFalse; } void RefTable::Resize(SQUnsignedInteger size) { RefNode **oldbucks = _buckets; RefNode *t = _nodes; SQUnsignedInteger oldnumofslots = _numofslots; AllocNodes(size); //rehash SQUnsignedInteger nfound = 0; for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { if(sq_type(t->obj) != OT_NULL) { //add back; assert(t->refs != 0); RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); nn->refs = t->refs; t->obj.Null(); nfound++; } t++; } assert(nfound == oldnumofslots); SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); } RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) { RefNode *t = _buckets[mainpos]; RefNode *newnode = _freelist; newnode->obj = obj; _buckets[mainpos] = newnode; _freelist = _freelist->next; newnode->next = t; assert(newnode->refs == 0); _slotused++; return newnode; } RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) { RefNode *ref; mainpos = ::HashObj(obj)&(_numofslots-1); *prev = NULL; for (ref = _buckets[mainpos]; ref; ) { if(_rawval(ref->obj) == _rawval(obj) && sq_type(ref->obj) == sq_type(obj)) break; *prev = ref; ref = ref->next; } if(ref == NULL && add) { if(_numofslots == _slotused) { assert(_freelist == 0); Resize(_numofslots*2); mainpos = ::HashObj(obj)&(_numofslots-1); } ref = Add(mainpos,obj); } return ref; } void RefTable::AllocNodes(SQUnsignedInteger size) { RefNode **bucks; RefNode *nodes; bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); nodes = (RefNode *)&bucks[size]; RefNode *temp = nodes; SQUnsignedInteger n; for(n = 0; n < size - 1; n++) { bucks[n] = NULL; temp->refs = 0; new (&temp->obj) SQObjectPtr; temp->next = temp+1; temp++; } bucks[n] = NULL; temp->refs = 0; new (&temp->obj) SQObjectPtr; temp->next = NULL; _freelist = nodes; _nodes = nodes; _buckets = bucks; _slotused = 0; _numofslots = size; } ////////////////////////////////////////////////////////////////////////// //SQStringTable /* * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) * http://www.lua.org/copyright.html#4 * http://www.lua.org/source/4.0.1/src_lstring.c.html */ SQStringTable::SQStringTable(SQSharedState *ss) { _sharedstate = ss; AllocNodes(4); _slotused = 0; } SQStringTable::~SQStringTable() { SQ_FREE(_strings,sizeof(SQString*)*_numofslots); _strings = NULL; } void SQStringTable::AllocNodes(SQInteger size) { _numofslots = size; _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); memset(_strings,0,sizeof(SQString*)*_numofslots); } SQString *SQStringTable::Add(const SQChar *news,SQInteger len) { if(len<0) len = (SQInteger)scstrlen(news); SQHash newhash = ::_hashstr(news,len); SQHash h = newhash&(_numofslots-1); SQString *s; for (s = _strings[h]; s; s = s->_next){ if(s->_len == len && (!memcmp(news,s->_val,sq_rsl(len)))) return s; //found } SQString *t = (SQString *)SQ_MALLOC(sq_rsl(len)+sizeof(SQString)); new (t) SQString; t->_sharedstate = _sharedstate; memcpy(t->_val,news,sq_rsl(len)); t->_val[len] = _SC('\0'); t->_len = len; t->_hash = newhash; t->_next = _strings[h]; _strings[h] = t; _slotused++; if (_slotused > _numofslots) /* too crowded? */ Resize(_numofslots*2); return t; } void SQStringTable::Resize(SQInteger size) { SQInteger oldsize=_numofslots; SQString **oldtable=_strings; AllocNodes(size); for (SQInteger i=0; i_next; SQHash h = p->_hash&(_numofslots-1); p->_next = _strings[h]; _strings[h] = p; p = next; } } SQ_FREE(oldtable,oldsize*sizeof(SQString*)); } void SQStringTable::Remove(SQString *bs) { SQString *s; SQString *prev=NULL; SQHash h = bs->_hash&(_numofslots - 1); for (s = _strings[h]; s; ){ if(s == bs){ if(prev) prev->_next = s->_next; else _strings[h] = s->_next; _slotused--; SQInteger slen = s->_len; s->~SQString(); SQ_FREE(s,sizeof(SQString) + sq_rsl(slen)); return; } prev = s; s = s->_next; } assert(0);//if this fail something is wrong } simutrans-124.3/src/squirrel/squirrel/sqstate.h000066400000000000000000000102571474050137200217200ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTATE_H_ #define _SQSTATE_H_ #include "squtils.h" #include "sqobject.h" struct SQString; struct SQTable; //max number of character for a printed number #define NUMBER_MAX_CHAR 50 struct SQStringTable { SQStringTable(SQSharedState*ss); ~SQStringTable(); SQString *Add(const SQChar *,SQInteger len); void Remove(SQString *); private: void Resize(SQInteger size); void AllocNodes(SQInteger size); SQString **_strings; SQUnsignedInteger _numofslots; SQUnsignedInteger _slotused; SQSharedState *_sharedstate; }; struct RefTable { struct RefNode { SQObjectPtr obj; SQUnsignedInteger refs; struct RefNode *next; }; RefTable(); ~RefTable(); void AddRef(SQObject &obj); SQBool Release(SQObject &obj); SQUnsignedInteger GetRefCount(SQObject &obj); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif void Finalize(); private: RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); RefNode *Add(SQHash mainpos,SQObject &obj); void Resize(SQUnsignedInteger size); void AllocNodes(SQUnsignedInteger size); SQUnsignedInteger _numofslots; SQUnsignedInteger _slotused; RefNode *_nodes; RefNode *_freelist; RefNode **_buckets; }; #define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) #define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) struct SQObjectPtr; struct SQSharedState { SQSharedState(); ~SQSharedState(); void Init(); public: SQChar* GetScratchPad(SQInteger size); SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); #ifndef NO_GARBAGE_COLLECTOR SQInteger CollectGarbage(SQVM *vm); void RunMark(SQVM *vm,SQCollectable **tchain); SQInteger ResurrectUnreachable(SQVM *vm); static void MarkObject(SQObjectPtr &o,SQCollectable **chain); #endif SQObjectPtrVec *_metamethods; SQObjectPtr _metamethodsmap; SQObjectPtrVec *_systemstrings; SQObjectPtrVec *_types; SQStringTable *_stringtable; RefTable _refs_table; SQObjectPtr _registry; SQObjectPtr _consts; SQObjectPtr _constructoridx; #ifndef NO_GARBAGE_COLLECTOR SQCollectable *_gc_chain; #endif SQObjectPtr _root_vm; SQObjectPtr _table_default_delegate; static const SQRegFunction _table_default_delegate_funcz[]; SQObjectPtr _array_default_delegate; static const SQRegFunction _array_default_delegate_funcz[]; SQObjectPtr _string_default_delegate; static const SQRegFunction _string_default_delegate_funcz[]; SQObjectPtr _number_default_delegate; static const SQRegFunction _number_default_delegate_funcz[]; SQObjectPtr _generator_default_delegate; static const SQRegFunction _generator_default_delegate_funcz[]; SQObjectPtr _closure_default_delegate; static const SQRegFunction _closure_default_delegate_funcz[]; SQObjectPtr _thread_default_delegate; static const SQRegFunction _thread_default_delegate_funcz[]; SQObjectPtr _class_default_delegate; static const SQRegFunction _class_default_delegate_funcz[]; SQObjectPtr _instance_default_delegate; static const SQRegFunction _instance_default_delegate_funcz[]; SQObjectPtr _weakref_default_delegate; static const SQRegFunction _weakref_default_delegate_funcz[]; SQCOMPILERERROR _compilererrorhandler; SQPRINTFUNCTION _printfunc; SQPRINTFUNCTION _errorfunc; bool _debuginfo; bool _notifyallexceptions; SQUserPointer _foreignptr; SQRELEASEHOOK _releasehook; private: SQChar *_scratchpad; SQInteger _scratchpadsize; }; #define _sp(s) (_sharedstate->GetScratchPad(s)) #define _spval (_sharedstate->GetScratchPad(-1)) #define _table_ddel _table(_sharedstate->_table_default_delegate) #define _array_ddel _table(_sharedstate->_array_default_delegate) #define _string_ddel _table(_sharedstate->_string_default_delegate) #define _number_ddel _table(_sharedstate->_number_default_delegate) #define _generator_ddel _table(_sharedstate->_generator_default_delegate) #define _closure_ddel _table(_sharedstate->_closure_default_delegate) #define _thread_ddel _table(_sharedstate->_thread_default_delegate) #define _class_ddel _table(_sharedstate->_class_default_delegate) #define _instance_ddel _table(_sharedstate->_instance_default_delegate) #define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) bool CompileTypemask(SQIntVec &res,const SQChar *typemask); #endif simutrans-124.3/src/squirrel/squirrel/sqstring.h000066400000000000000000000013541474050137200221040ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQSTRING_H_ #define _SQSTRING_H_ inline SQHash _hashstr (const SQChar *s, size_t l) { SQHash h = (SQHash)l; /* seed */ size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ for (; l>=step; l-=step) h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); return h; } struct SQString : public SQRefCounted { SQString(){} ~SQString(){} public: static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); void Release(); SQSharedState *_sharedstate; SQString *_next; //chain for the string table SQInteger _len; SQHash _hash; SQChar _val[1]; }; #endif simutrans-124.3/src/squirrel/squirrel/sqtable.cc000066400000000000000000000117171474050137200220270ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include "sqvm.h" #include "sqtable.h" #include "sqfuncproto.h" #include "sqclosure.h" SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) { SQInteger pow2size=MINPOWER2; while(nInitialSize>pow2size)pow2size=pow2size<<1; AllocNodes(pow2size); _usednodes = 0; _delegate = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); } void SQTable::Remove(const SQObjectPtr &key) { _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val.Null(); n->key.Null(); _usednodes--; Rehash(false); } } void SQTable::AllocNodes(SQInteger nSize) { _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); for(SQInteger i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ AllocNodes(oldsize*2); else if (nelems <= oldsize/4 && /* less than 1/4? */ oldsize > MINPOWER2) AllocNodes(oldsize/2); else if(force) AllocNodes(oldsize); else return; _usednodes = 0; for (SQInteger i=0; ikey) != OT_NULL) NewSlot(old->key,old->val); } for(SQInteger k=0;k_nodes; _HashNode *src = _nodes; _HashNode *dst = nt->_nodes; SQInteger n = 0; for(n = 0; n < _numofnodes; n++) { dst->key = src->key; dst->val = src->val; if(src->next) { assert(src->next > basesrc); dst->next = basedst + (src->next - basesrc); assert(dst != dst->next); } dst++; src++; } assert(_firstfree > basesrc); assert(_firstfree != NULL); nt->_firstfree = basedst + (_firstfree - basesrc); nt->_usednodes = _usednodes; #else SQInteger ridx=0; SQObjectPtr key,val; while((ridx=Next(true,ridx,key,val))!=-1){ nt->NewSlot(key,val); } #endif nt->SetDelegate(_delegate); return nt; } bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) { if(sq_type(key) == OT_NULL) return false; _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { val = _realval(n->val); return true; } return false; } bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) { assert(sq_type(key) != OT_NULL); SQHash h = HashObj(key) & (_numofnodes - 1); _HashNode *n = _Get(key, h); if (n) { n->val = val; return false; } _HashNode *mp = &_nodes[h]; n = mp; //key not found I'll insert it //main pos is not free if(sq_type(mp->key) != OT_NULL) { n = _firstfree; /* get a free place */ SQHash mph = HashObj(mp->key) & (_numofnodes - 1); _HashNode *othern; /* main position of colliding node */ if (mp > n && (othern = &_nodes[mph]) != mp){ /* yes; move colliding node into free position */ while (othern->next != mp){ assert(othern->next != NULL); othern = othern->next; /* find previous */ } othern->next = n; /* redo the chain with `n' in place of `mp' */ n->key = mp->key; n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ n->next = mp->next; mp->key.Null(); mp->val.Null(); mp->next = NULL; /* now `mp' is free */ } else{ /* new node will go into free position */ n->next = mp->next; /* chain new position */ mp->next = n; mp = n; } } mp->key = key; for (;;) { /* correct `firstfree' */ if (sq_type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { mp->val = val; _usednodes++; return true; /* OK; table still has a free place */ } else if (_firstfree == _nodes) break; /* cannot decrement from here */ else (_firstfree)--; } Rehash(true); return NewSlot(key, val); } SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQInteger idx = (SQInteger)TranslateIndex(refpos); while (idx < _numofnodes) { if(sq_type(_nodes[idx].key) != OT_NULL) { //first found _HashNode &n = _nodes[idx]; outkey = n.key; outval = getweakrefs?(SQObject)n.val:_realval(n.val); //return idx for the next iteration return ++idx; } ++idx; } //nothing to iterate anymore return -1; } bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) { _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val = val; return true; } return false; } void SQTable::_ClearNodes() { for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); } } void SQTable::Finalize() { _ClearNodes(); SetDelegate(NULL); } void SQTable::Clear() { _ClearNodes(); _usednodes = 0; Rehash(true); } simutrans-124.3/src/squirrel/squirrel/sqtable.h000066400000000000000000000054341474050137200216700ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQTABLE_H_ #define _SQTABLE_H_ /* * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) * http://www.lua.org/copyright.html#4 * http://www.lua.org/source/4.0.1/src_ltable.c.html */ #include "sqstring.h" #define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) inline SQHash HashObj(const SQObject &key) { switch(sq_type(key)) { case OT_STRING: return _string(key)->_hash; case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); default: return hashptr(key._unVal.pRefCounted); } } struct SQTable : public SQDelegable { private: struct _HashNode { _HashNode() { next = NULL; } SQObjectPtr val; SQObjectPtr key; _HashNode *next; }; _HashNode *_firstfree; _HashNode *_nodes; SQInteger _numofnodes; SQInteger _usednodes; /////////////////////////// void AllocNodes(SQInteger nSize); void Rehash(bool force); SQTable(SQSharedState *ss, SQInteger nInitialSize); void _ClearNodes(); public: static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize) { SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); new (newtable) SQTable(ss, nInitialSize); newtable->_delegate = NULL; return newtable; } void Finalize(); SQTable *Clone(); ~SQTable() { SetDelegate(NULL); REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); SQObjectType GetType() {return OT_TABLE;} #endif inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { _HashNode *n = &_nodes[hash]; do{ if(_rawval(n->key) == _rawval(key) && sq_type(n->key) == sq_type(key)){ return n; } }while((n = n->next)); return NULL; } //for compiler use inline bool GetStr(const SQChar* key,SQInteger keylen,SQObjectPtr &val) { SQHash hash = _hashstr(key,keylen); _HashNode *n = &_nodes[hash & (_numofnodes - 1)]; _HashNode *res = NULL; do{ if(sq_type(n->key) == OT_STRING && (scstrcmp(_stringval(n->key),key) == 0)){ res = n; break; } }while((n = n->next)); if (res) { val = _realval(res->val); return true; } return false; } bool Get(const SQObjectPtr &key,SQObjectPtr &val); void Remove(const SQObjectPtr &key); bool Set(const SQObjectPtr &key, const SQObjectPtr &val); //returns true if a new slot has been created false if it was already present bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInteger CountUsed(){ return _usednodes;} void Clear(); void Release() { sq_delete(this, SQTable); } }; #endif simutrans-124.3/src/squirrel/squirrel/squserdata.h000066400000000000000000000017571474050137200224150ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQUSERDATA_H_ #define _SQUSERDATA_H_ struct SQUserData : SQDelegable { SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } ~SQUserData() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); SetDelegate(NULL); } static SQUserData* Create(SQSharedState *ss, SQInteger size) { SQUserData* ud = (SQUserData*)SQ_MALLOC(sq_aligning(sizeof(SQUserData))+size); new (ud) SQUserData(ss); ud->_size = size; ud->_typetag = 0; return ud; } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){SetDelegate(NULL);} SQObjectType GetType(){ return OT_USERDATA;} #endif void Release() { if (_hook) _hook((SQUserPointer)sq_aligning(this + 1),_size); SQInteger tsize = _size; this->~SQUserData(); SQ_FREE(this, sq_aligning(sizeof(SQUserData)) + tsize); } SQInteger _size; SQRELEASEHOOK _hook; SQUserPointer _typetag; //SQChar _val[1]; }; #endif simutrans-124.3/src/squirrel/squirrel/squtils.h000066400000000000000000000057021474050137200217370ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQUTILS_H_ #define _SQUTILS_H_ void *sq_vm_malloc(SQUnsignedInteger size); void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size); void sq_vm_free(void *p,SQUnsignedInteger size); #define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} #define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} #define SQ_MALLOC(__size) sq_vm_malloc((__size)); #define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size)); #define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size)); #define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1))) //sqvector mini vector class, supports objects by value template class sqvector { public: sqvector() { _vals = NULL; _size = 0; _allocated = 0; } sqvector(const sqvector& v) { copy(v); } void copy(const sqvector& v) { if(_size) { resize(0); //destroys all previous stuff } //resize(v._size); if(v._size > _allocated) { _realloc(v._size); } for(SQUnsignedInteger i = 0; i < v._size; i++) { new ((void *)&_vals[i]) T(v._vals[i]); } _size = v._size; } ~sqvector() { if(_allocated) { for(SQUnsignedInteger i = 0; i < _size; i++) _vals[i].~T(); SQ_FREE(_vals, (_allocated * sizeof(T))); } } void reserve(SQUnsignedInteger newsize) { _realloc(newsize); } void resize(SQUnsignedInteger newsize, const T& fill = T()) { if(newsize > _allocated) _realloc(newsize); if(newsize > _size) { while(_size < newsize) { new ((void *)&_vals[_size]) T(fill); _size++; } } else{ for(SQUnsignedInteger i = newsize; i < _size; i++) { _vals[i].~T(); } _size = newsize; } } void shrinktofit() { if(_size > 4) { _realloc(_size); } } T& top() const { return _vals[_size - 1]; } inline SQUnsignedInteger size() const { return _size; } bool empty() const { return (_size <= 0); } inline T &push_back(const T& val = T()) { if(_allocated <= _size) _realloc(_size * 2); return *(new ((void *)&_vals[_size++]) T(val)); } inline void pop_back() { _size--; _vals[_size].~T(); } void insert(SQUnsignedInteger idx, const T& val) { resize(_size + 1); for(SQUnsignedInteger i = _size - 1; i > idx; i--) { _vals[i] = _vals[i - 1]; } _vals[idx] = val; } void remove(SQUnsignedInteger idx) { _vals[idx].~T(); if(idx < (_size - 1)) { memmove(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1)); } _size--; } SQUnsignedInteger capacity() { return _allocated; } inline T &back() const { return _vals[_size - 1]; } inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; } T* _vals; private: void _realloc(SQUnsignedInteger newsize) { newsize = (newsize > 0)?newsize:4; _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); _allocated = newsize; } SQUnsignedInteger _size; SQUnsignedInteger _allocated; }; #endif simutrans-124.3/src/squirrel/squirrel/sqvm.cc000066400000000000000000001454721474050137200213700ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #include "sqpcheader.h" #include #include #include "sqopcodes.h" #include "sqvm.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqstring.h" #include "sqtable.h" #include "squserdata.h" #include "sqarray.h" #include "sqclass.h" #define TOP() (_stack._vals[_top-1]) #define TARGET _stack._vals[_stackbase+arg0] #define STK(a) _stack._vals[_stackbase+(a)] bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) { SQInteger res; if((sq_type(o1)| sq_type(o2)) == OT_INTEGER) { SQInteger i1 = _integer(o1), i2 = _integer(o2); switch(op) { case BW_AND: res = i1 & i2; break; case BW_OR: res = i1 | i2; break; case BW_XOR: res = i1 ^ i2; break; case BW_SHIFTL: res = i1 << i2; break; case BW_SHIFTR: res = i1 >> i2; break; case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break; default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; } } } else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;} trg = res; return true; } #define _ARITH_(op,trg,o1,o2) \ { \ SQInteger tmask = sq_type(o1)|sq_type(o2); \ switch(tmask) { \ case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \ case (OT_FLOAT|OT_INTEGER): \ case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ } \ } #define _ARITH_NOZERO(op,trg,o1,o2,err) \ { \ SQInteger tmask = sq_type(o1)|sq_type(o2); \ switch(tmask) { \ case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\ case (OT_FLOAT|OT_INTEGER): \ case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ } \ } bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) { SQInteger tmask = sq_type(o1)| sq_type(o2); switch(tmask) { case OT_INTEGER:{ SQInteger res, i1 = _integer(o1), i2 = _integer(o2); switch(op) { case '+': res = i1 + i2; break; case '-': res = i1 - i2; break; case '/': if (i2 == 0) { Raise_Error(_SC("division by zero")); return false; } else if (i2 == -1 && i1 == INT_MIN) { Raise_Error(_SC("integer overflow")); return false; } res = i1 / i2; break; case '*': res = i1 * i2; break; case '%': if (i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; } else if (i2 == -1 && i1 == INT_MIN) { res = 0; break; } res = i1 % i2; break; default: res = 0xDEADBEEF; } trg = res; } break; case (OT_FLOAT|OT_INTEGER): case (OT_FLOAT):{ SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2); switch(op) { case '+': res = f1 + f2; break; case '-': res = f1 - f2; break; case '/': res = f1 / f2; break; case '*': res = f1 * f2; break; case '%': res = SQFloat(fmod((double)f1,(double)f2)); break; default: res = 0x0f; } trg = res; } break; default: if(op == '+' && (tmask & _RT_STRING)){ if(!StringCat(o1, o2, trg)) return false; } else if(!ArithMetaMethod(op,o1,o2,trg)) { return false; } } return true; } SQVM::SQVM(SQSharedState *ss) { _sharedstate=ss; _suspended = SQFalse; _suspended_target = -1; _suspended_root = SQFalse; _suspended_traps = -1; _foreignptr = NULL; _nnativecalls = 0; _nmetamethodscall = 0; _lasterror.Null(); _errorhandler.Null(); _debughook = false; _debughook_native = NULL; _debughook_closure.Null(); _openouters = NULL; ci = NULL; _releasehook = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _ops_remaining = 0; _ops_total = 0; _ops_grace_amount = 500; _throw_if_no_ops = true; } void SQVM::Finalize() { if(_releasehook) { _releasehook(_foreignptr,0); _releasehook = NULL; } if(_openouters) CloseOuters(&_stack._vals[0]); _roottable.Null(); _lasterror.Null(); _errorhandler.Null(); _debughook = false; _debughook_native = NULL; _debughook_closure.Null(); temp_reg.Null(); _callstackdata.resize(0); SQInteger size=_stack.size(); for(SQInteger i=0;i_gc_chain,this); } bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) { SQMetaMethod mm; switch(op){ case _SC('+'): mm=MT_ADD; break; case _SC('-'): mm=MT_SUB; break; case _SC('/'): mm=MT_DIV; break; case _SC('*'): mm=MT_MUL; break; case _SC('%'): mm=MT_MODULO; break; default: mm = MT_ADD; assert(0); break; //shutup compiler } if(is_delegable(o1) && _delegable(o1)->_delegate) { SQObjectPtr closure; if(_delegable(o1)->GetMetaMethod(this, mm, closure)) { Push(o1);Push(o2); return CallMetaMethod(closure,mm,2,dest); } } Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false; } bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) { switch(sq_type(o)) { case OT_INTEGER: trg = -_integer(o); return true; case OT_FLOAT: trg = -_float(o); return true; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o)->_delegate) { SQObjectPtr closure; if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) { Push(o); if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false; _Swap(trg,temp_reg); return true; } } default:break; //shutup compiler } Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); return false; } #define _RET_SUCCEED(exp) { result = (exp); return true; } bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) { SQObjectType t1 = sq_type(o1), t2 = sq_type(o2); if(t1 == t2) { if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0); SQObjectPtr res; switch(t1){ case OT_STRING: _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); case OT_INTEGER: _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:1); case OT_FLOAT: _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o1)->_delegate) { SQObjectPtr closure; if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) { Push(o1);Push(o2); if(CallMetaMethod(closure,MT_CMP,2,res)) { if(sq_type(res) != OT_INTEGER) { Raise_Error(_SC("_cmp must return an integer")); return false; } _RET_SUCCEED(_integer(res)) } return false; } } //continues through (no break needed) default: _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 ); } assert(0); //if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } // _RET_SUCCEED(_integer(res)); } else{ if(sq_isnumeric(o1) && sq_isnumeric(o2)){ if((t1==OT_INTEGER) && (t2==OT_FLOAT)) { if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } _RET_SUCCEED(1); } else{ if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } _RET_SUCCEED(1); } } else if(t1==OT_NULL) {_RET_SUCCEED(-1);} else if(t2==OT_NULL) {_RET_SUCCEED(1);} else { Raise_CompareError(o1,o2); return false; } } assert(0); _RET_SUCCEED(0); //cannot happen } bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) { SQInteger r; if(ObjCmp(o1,o2,r)) { switch(op) { case CMP_G: res = (r > 0); return true; case CMP_GE: res = (r >= 0); return true; case CMP_L: res = (r < 0); return true; case CMP_LE: res = (r <= 0); return true; case CMP_3W: res = r; return true; } assert(0); } return false; } bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) { switch(sq_type(o)) { case OT_STRING: res = o; return true; case OT_FLOAT: scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o)); break; case OT_INTEGER: scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o)); break; case OT_BOOL: scsprintf(_sp(sq_rsl(6)),sq_rsl(6),_integer(o)?_SC("true"):_SC("false")); break; case OT_NULL: scsprintf(_sp(sq_rsl(5)),sq_rsl(5),_SC("null")); break; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o)->_delegate) { SQObjectPtr closure; if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) { Push(o); if(CallMetaMethod(closure,MT_TOSTRING,1,res)) { if(sq_type(res) == OT_STRING) return true; } else { return false; } } } default: scsprintf(_sp(sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR)),sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o)); } res = SQString::Create(_ss(this),_spval); return true; } bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) { SQObjectPtr a, b; if(!ToString(str, a)) return false; if(!ToString(obj, b)) return false; SQInteger l = _string(a)->_len , ol = _string(b)->_len; SQChar *s = _sp(sq_rsl(l + ol + 1)); memcpy(s, _stringval(a), sq_rsl(l)); memcpy(s + l, _stringval(b), sq_rsl(ol)); dest = SQString::Create(_ss(this), _spval, l + ol); return true; } bool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) { if(is_delegable(obj1) && _delegable(obj1)->_delegate) { SQObjectPtr closure; if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) { Push(obj1); return CallMetaMethod(closure,MT_TYPEOF,1,dest); } } dest = SQString::Create(_ss(this),GetTypeName(obj1)); return true; } bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) { _stack.resize(stacksize); _alloccallsstacksize = 4; _callstackdata.resize(_alloccallsstacksize); _callsstacksize = 0; _callsstack = &_callstackdata[0]; _stackbase = 0; _top = 0; if(!friendvm) { _roottable = SQTable::Create(_ss(this), 0); sq_base_register(this); } else { _roottable = friendvm->_roottable; _errorhandler = friendvm->_errorhandler; _debughook = friendvm->_debughook; _debughook_native = friendvm->_debughook_native; _debughook_closure = friendvm->_debughook_closure; } return true; } bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall) { SQFunctionProto *func = closure->_function; SQInteger paramssize = func->_nparameters; const SQInteger newtop = stackbase + func->_stacksize; SQInteger nargs = args; if(func->_varparams) { paramssize--; if (nargs < paramssize) { const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; const SQChar *name = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL; Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s:%s"), nargs, paramssize, src, name); return false; } //dumpstack(stackbase); SQInteger nvargs = nargs - paramssize; SQArray *arr = SQArray::Create(_ss(this),nvargs); SQInteger pbase = stackbase+paramssize; for(SQInteger n = 0; n < nvargs; n++) { arr->_values[n] = _stack._vals[pbase]; _stack._vals[pbase].Null(); pbase++; } _stack._vals[stackbase+paramssize] = arr; //dumpstack(stackbase); } else if (paramssize != nargs) { SQInteger ndef = func->_ndefaultparams; SQInteger diff; if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) { for(SQInteger n = ndef - diff; n < ndef; n++) { _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; } } else { const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; const SQChar *name = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL; Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s:%s"), nargs, paramssize, src, name); return false; } } if(closure->_env) { _stack._vals[stackbase] = closure->_env->_obj; } if(!EnterFrame(stackbase, newtop, tailcall)) return false; ci->_closure = closure; ci->_literals = func->_literals; ci->_ip = func->_instructions; ci->_target = (SQInt32)target; if (_debughook) { CallDebugHook(_SC('c')); } if (closure->_function->_bgenerator) { SQFunctionProto *f = closure->_function; SQGenerator *gen = SQGenerator::Create(_ss(this), closure); if(!gen->Yield(this,f->_stacksize)) return false; SQObjectPtr temp; Return(1, target, temp); STK(target) = gen; } return true; } bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) { SQBool _isroot = ci->_root; SQInteger callerbase = _stackbase - ci->_prevstkbase; if (_debughook) { for(SQInteger i=0; i_ncalls; i++) { CallDebugHook(_SC('r')); } } SQObjectPtr *dest; if (_isroot) { dest = &(retval); } else if (ci->_target == -1) { dest = NULL; } else { dest = &_stack._vals[callerbase + ci->_target]; } if (dest) { if(_arg0 != 0xFF) { *dest = _stack._vals[_stackbase+_arg1]; } else { dest->Null(); } //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_; } LeaveFrame(); return _isroot ? true : false; } #define _RET_ON_FAIL(exp) { if(!exp) return false; } bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) { SQObjectPtr trg; _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); target = a; a = trg; return true; } bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx) { SQObjectPtr tmp, tself = self, tkey = key; if (!Get(tself, tkey, tmp, 0, selfidx)) { return false; } _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) if (!Set(tself, tkey, target,selfidx)) { return false; } if (postfix) target = tmp; return true; } #define arg0 (_i_._arg0) #define sarg0 ((SQInteger)*((const signed char *)&_i_._arg0)) #define arg1 (_i_._arg1) #define sarg1 (*((const SQInt32 *)&_i_._arg1)) #define arg2 (_i_._arg2) #define arg3 (_i_._arg3) #define sarg3 ((SQInteger)*((const signed char *)&_i_._arg3)) SQRESULT SQVM::Suspend() { if (_suspended) return sq_throwerror(this, _SC("cannot suspend an already suspended vm")); if (_nnativecalls!=2) return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods")); return SQ_SUSPEND_FLAG; } #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; } bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger SQ_UNUSED_ARG(arg_2),int exitpos,int &jump) { SQInteger nrefidx; switch(sq_type(o1)) { case OT_TABLE: if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_ARRAY: if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos); o4 = (SQInteger) nrefidx; _FINISH(1); case OT_STRING: if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_CLASS: if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_USERDATA: case OT_INSTANCE: if(_delegable(o1)->_delegate) { SQObjectPtr itr; SQObjectPtr closure; if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) { Push(o1); Push(o4); if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) { o4 = o2 = itr; if(sq_type(itr) == OT_NULL) _FINISH(exitpos); if(!Get(o1, itr, o3, 0, DONT_FALL_BACK)) { Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed return false; } _FINISH(1); } else { return false; } } Raise_Error(_SC("_nexti failed")); return false; } break; case OT_GENERATOR: if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos); if(_generator(o1)->_state == SQGenerator::eSuspended) { SQInteger idx = 0; if(sq_type(o4) == OT_INTEGER) { idx = _integer(o4) + 1; } o2 = idx; o4 = idx; _generator(o1)->Resume(this, o3); _FINISH(0); } default: Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); } return false; //cannot be hit(just to avoid warnings) } #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) #define SQ_THROW() { goto exception_trap; } #define _GUARD(exp) { if(!exp) { SQ_THROW();} } bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) { SQInteger nouters; SQClosure *closure = SQClosure::Create(_ss(this), func,_table(_roottable)->GetWeakRef(OT_TABLE)); if((nouters = func->_noutervalues)) { for(SQInteger i = 0; i_outervalues[i]; switch(v._type){ case otLOCAL: FindOuter(closure->_outervalues[i], &STK(_integer(v._src))); break; case otOUTER: closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)]; break; } } } SQInteger ndefparams; if((ndefparams = func->_ndefaultparams)) { for(SQInteger i = 0; i < ndefparams; i++) { SQInteger spos = func->_defaultparams[i]; closure->_defaultparams[i] = _stack._vals[_stackbase + spos]; } } target = closure; return true; } bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) { SQClass *base = NULL; SQObjectPtr attrs; if(baseclass != -1) { if(sq_type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } base = _class(_stack._vals[_stackbase + baseclass]); } if(attributes != MAX_FUNC_STACKSIZE) { attrs = _stack._vals[_stackbase+attributes]; } target = SQClass::Create(_ss(this),base); if(sq_type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { int nparams = 2; SQObjectPtr ret; Push(target); Push(attrs); if(!Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false)) { Pop(nparams); return false; } Pop(nparams); } _class(target)->_attributes = attrs; return true; } bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res) { SQObjectType t1 = sq_type(o1), t2 = sq_type(o2); if(t1 == t2) { if (t1 == OT_FLOAT) { res = (_float(o1) == _float(o2)); } else { res = (_rawval(o1) == _rawval(o2)); } } else { if(sq_isnumeric(o1) && sq_isnumeric(o2)) { res = (tofloat(o1) == tofloat(o2)); } else { res = false; } } return true; } bool SQVM::IsFalse(SQObjectPtr &o) { if(((sq_type(o) & SQOBJECT_CANBEFALSE) && ( ((sq_type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) )) #if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64)) || (_integer(o) == 0) ) //OT_NULL|OT_INTEGER|OT_BOOL #else || (((sq_type(o) != OT_FLOAT) && (_integer(o) == 0))) ) //OT_NULL|OT_INTEGER|OT_BOOL #endif { return true; } return false; } extern SQInstructionDesc g_InstrDesc[]; bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et, SQBool can_suspend) { if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } _nnativecalls++; AutoDec ad(&_nnativecalls); SQInteger traps = 0; CallInfo *prevci = ci; switch(et) { case ET_CALL: { temp_reg = closure; if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { //call the handler if there are no calls in the stack, if not relies on the previous node if(ci == NULL) CallErrorHandler(_lasterror); return false; } if(ci == prevci) { outres = STK(_top-nargs); return true; } ci->_root = SQTrue; } break; case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break; case ET_RESUME_VM: case ET_RESUME_THROW_VM: traps = _suspended_traps; ci->_root = _suspended_root; _suspended = SQFalse; if(et == ET_RESUME_THROW_VM) { SQ_THROW(); } break; } exception_restore: // { for(;;) { _ops_total++; _ops_remaining --; if (_ops_remaining < 0) { // suspend vm if (can_suspend && !_throw_if_no_ops) { _suspended = SQTrue; _suspended_root = ci->_root; _suspended_traps = traps; _suspended_target = -1; return true; } else { // throw error (if within unsuspendable function give some grace opcodes) if (_throw_if_no_ops || (_ops_remaining + _ops_grace_amount < 0) ) { Raise_Error(_SC("script took too long: remain = %d grac = %d"), _ops_remaining, _ops_grace_amount); SQ_THROW(); } } } const SQInstruction &_i_ = *ci->_ip++; //dumpstack(_stackbase); //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-_closure(ci->_closure)->_function->_instructions,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); switch(_i_.op) { case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue; case _OP_LOAD: TARGET = ci->_literals[arg1]; continue; case _OP_LOADINT: #ifndef _SQ64 TARGET = (SQInteger)arg1; continue; #else TARGET = (SQInteger)((SQInt32)arg1); continue; #endif case _OP_LOADFLOAT: SQFloat v; memcpy(&v, &arg1, sizeof(SQFloat)); TARGET = v; continue; case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; case _OP_TAILCALL:{ SQObjectPtr &t = STK(arg1); if (sq_type(t) == OT_CLOSURE && (!_closure(t)->_function->_bgenerator)){ SQObjectPtr clo = t; SQInteger last_top = _top; if(_openouters) CloseOuters(&(_stack._vals[_stackbase])); for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true)); if (last_top >= _top) { _top = last_top; } continue; } } case _OP_CALL: { SQObjectPtr clo = STK(arg1); switch (sq_type(clo)) { case OT_CLOSURE: _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false)); continue; case OT_NATIVECLOSURE: { bool suspend; bool tailcall; _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo, (SQInt32)sarg0, suspend, tailcall)); if(suspend){ _suspended = SQTrue; _suspended_target = sarg0; _suspended_root = ci->_root; _suspended_traps = traps; outres = clo; return true; } if(sarg0 != -1 && !tailcall) { STK(arg0) = clo; } } continue; case OT_CLASS:{ SQObjectPtr inst; _GUARD(CreateClassInstance(_class(clo),inst,clo)); if(sarg0 != -1) { STK(arg0) = inst; } SQInteger stkbase; switch(sq_type(clo)) { case OT_CLOSURE: stkbase = _stackbase+arg2; _stack._vals[stkbase] = inst; _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false)); break; case OT_NATIVECLOSURE: bool dummy; stkbase = _stackbase+arg2; _stack._vals[stkbase] = inst; _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo, -1, dummy, dummy)); break; default: break; //shutup GCC 4.x } } break; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE:{ SQObjectPtr closure; if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) { Push(clo); for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW(); if(sarg0 != -1) { STK(arg0) = clo; } break; } //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); //SQ_THROW(); } default: Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); SQ_THROW(); } } continue; case _OP_PREPCALL: case _OP_PREPCALLK: { SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); SQObjectPtr &o = STK(arg2); if (!Get(o, key, temp_reg,0,arg2)) { SQ_THROW(); } STK(arg3) = o; _Swap(TARGET,temp_reg);//TARGET = temp_reg; } continue; case _OP_GETK: if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, 0,arg2)) { SQ_THROW();} _Swap(TARGET,temp_reg);//TARGET = temp_reg; continue; case _OP_MOVE: TARGET = STK(arg1); continue; case _OP_NEWSLOT: _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); if(arg0 != 0xFF) TARGET = STK(arg3); continue; case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; case _OP_SET: if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); } if (arg0 != 0xFF) TARGET = STK(arg3); continue; case _OP_GET: if (!Get(STK(arg1), STK(arg2), temp_reg, 0,arg1)) { SQ_THROW(); } _Swap(TARGET,temp_reg);//TARGET = temp_reg; continue; case _OP_EQ:{ bool res; if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } TARGET = res?true:false; }continue; case _OP_NE:{ bool res; if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } TARGET = (!res)?true:false; } continue; case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue; case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue; case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue; case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue; case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue; case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; case _OP_RETURN: if((ci)->_generator) { (ci)->_generator->Kill(); } if(Return(arg0, arg1, temp_reg)){ assert(traps==0); //outres = temp_reg; _Swap(outres,temp_reg); return true; } continue; case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue; case _OP_LOADROOT: { SQWeakRef *w = _closure(ci->_closure)->_root; if(sq_type(w->_obj) != OT_NULL) { TARGET = w->_obj; } else { TARGET = _roottable; //shoud this be like this? or null } } continue; case _OP_LOADBOOL: TARGET = arg1?true:false; continue; case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue; case _OP_JMP: ci->_ip += (sarg1); continue; //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; case _OP_JCMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg)); if(IsFalse(temp_reg)) ci->_ip+=(sarg1); continue; case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; case _OP_GETOUTER: { SQClosure *cur_cls = _closure(ci->_closure); SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); TARGET = *(otr->_valptr); } continue; case _OP_SETOUTER: { SQClosure *cur_cls = _closure(ci->_closure); SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); *(otr->_valptr) = STK(arg2); if(arg0 != 0xFF) { TARGET = STK(arg2); } } continue; case _OP_NEWOBJ: switch(arg3) { case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; default: assert(0); continue; } case _OP_APPENDARRAY: { SQObject val; val._unVal.raw = 0; switch(arg2) { case AAT_STACK: val = STK(arg1); break; case AAT_LITERAL: val = ci->_literals[arg1]; break; case AAT_INT: val._type = OT_INTEGER; #ifndef _SQ64 val._unVal.nInteger = (SQInteger)arg1; #else val._unVal.nInteger = (SQInteger)((SQInt32)arg1); #endif break; case AAT_FLOAT: val._type = OT_FLOAT; memcpy(&val._unVal.fFloat, &arg1, sizeof(SQFloat)); break; case AAT_BOOL: val._type = OT_BOOL; val._unVal.nInteger = arg1; break; default: val._type = OT_INTEGER; assert(0); break; } _array(STK(arg0))->Append(val); continue; } case _OP_COMPARITH: { SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16); _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx)); } continue; case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue; case _OP_INCL: { SQObjectPtr &a = STK(arg1); if(sq_type(a) == OT_INTEGER) { a._unVal.nInteger = _integer(a) + sarg3; } else { SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o)); _ARITH_(+,a,a,o); } } continue; case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue; case _OP_PINCL: { SQObjectPtr &a = STK(arg1); if(sq_type(a) == OT_INTEGER) { TARGET = a; a._unVal.nInteger = _integer(a) + sarg3; } else { SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o)); } } continue; case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW, DONT_FALL_BACK) ? true : false; continue; case _OP_INSTANCEOF: if(sq_type(STK(arg1)) != OT_CLASS) {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} TARGET = (sq_type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false; continue; case _OP_AND: if(IsFalse(STK(arg2))) { TARGET = STK(arg2); ci->_ip += (sarg1); } continue; case _OP_OR: if(!IsFalse(STK(arg2))) { TARGET = STK(arg2); ci->_ip += (sarg1); } continue; case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue; case _OP_BWNOT: if(sq_type(STK(arg1)) == OT_INTEGER) { SQInteger t = _integer(STK(arg1)); TARGET = SQInteger(~t); continue; } Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); SQ_THROW(); case _OP_CLOSURE: { SQClosure *c = ci->_closure._unVal.pClosure; SQFunctionProto *fp = c->_function; if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } continue; } case _OP_YIELD:{ if(ci->_generator) { if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); if (_openouters) CloseOuters(&_stack._vals[_stackbase]); _GUARD(ci->_generator->Yield(this,arg2)); traps -= ci->_etraps; if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg; } else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} if(Return(arg0, arg1, temp_reg)){ assert(traps == 0); outres = temp_reg; return true; } } continue; case _OP_RESUME: if(sq_type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();} _GUARD(_generator(STK(arg1))->Resume(this, TARGET)); traps += ci->_etraps; continue; case _OP_FOREACH:{ int tojump; _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump)); ci->_ip += tojump; } continue; case _OP_POSTFOREACH: assert(sq_type(STK(arg0)) == OT_GENERATOR); if(_generator(STK(arg0))->_state == SQGenerator::eDead) ci->_ip += (sarg1 - 1); continue; case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue; case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue; case _OP_PUSHTRAP:{ SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions; _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++; ci->_etraps++; } continue; case _OP_POPTRAP: { for(SQInteger i = 0; i < arg0; i++) { _etraps.pop_back(); traps--; ci->_etraps--; } } continue; case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; case _OP_NEWSLOTA: _GUARD(NewSlotA(STK(arg1),STK(arg2),STK(arg3),(arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr(),(arg0&NEW_SLOT_STATIC_FLAG)?true:false,false)); continue; case _OP_GETBASE:{ SQClosure *clo = _closure(ci->_closure); if(clo->_base) { TARGET = clo->_base; } else { TARGET.Null(); } continue; } case _OP_CLOSE: if(_openouters) CloseOuters(&(STK(arg1))); continue; } } } exception_trap: { SQObjectPtr currerror = _lasterror; // dumpstack(_stackbase); // SQInteger n = 0; SQInteger last_top = _top; if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror); while( ci ) { if(ci->_etraps > 0) { SQExceptionTrap &et = _etraps.top(); ci->_ip = et._ip; _top = et._stacksize; _stackbase = et._stackbase; _stack._vals[_stackbase + et._extarget] = currerror; _etraps.pop_back(); traps--; ci->_etraps--; while(last_top >= _top) _stack._vals[last_top--].Null(); goto exception_restore; } else if (_debughook) { //notify debugger of a "return" //even if it really an exception unwinding the stack for(SQInteger i = 0; i < ci->_ncalls; i++) { CallDebugHook(_SC('r')); } } if(ci->_generator) ci->_generator->Kill(); bool mustbreak = ci && ci->_root; LeaveFrame(); if(mustbreak) break; } _lasterror = currerror; return false; } assert(0); } bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) { inst = theclass->CreateInstance(); if(!theclass->GetConstructor(constructor)) { constructor.Null(); } return true; } void SQVM::CallErrorHandler(SQObjectPtr &error) { if(sq_type(_errorhandler) != OT_NULL) { SQObjectPtr out; Push(_roottable); Push(error); Call(_errorhandler, 2, _top-2, out,SQFalse); Pop(2); } } void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) { _debughook = false; SQFunctionProto *func=_closure(ci->_closure)->_function; if(_debughook_native) { const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; const SQChar *fname = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL; SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip); _debughook_native(this,type,src,line,fname); } else { SQObjectPtr temp_reg; SQInteger nparams=5; Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse); Pop(nparams); } _debughook = true; } bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target,bool &suspend, bool &tailcall) { SQInteger nparamscheck = nclosure->_nparamscheck; SQInteger newtop = newbase + nargs + nclosure->_noutervalues; if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) || ((nparamscheck < 0) && (nargs < (-nparamscheck))))) { const SQChar *src = sq_type(nclosure->_name) == OT_STRING?_stringval(nclosure->_name):NULL; Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s"), nargs, nparamscheck, src); return false; } SQInteger tcs; SQIntVec &tc = nclosure->_typecheck; if((tcs = tc.size())) { for(SQInteger i = 0; i < nargs && i < tcs; i++) { if((tc._vals[i] != -1) && !(sq_type(_stack._vals[newbase+i]) & tc._vals[i])) { Raise_ParamTypeError(i,tc._vals[i], sq_type(_stack._vals[newbase+i])); return false; } } } if(!EnterFrame(newbase, newtop, false)) return false; ci->_closure = nclosure; ci->_target = target; SQInteger outers = nclosure->_noutervalues; for (SQInteger i = 0; i < outers; i++) { _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i]; } if(nclosure->_env) { _stack._vals[newbase] = nclosure->_env->_obj; } _nnativecalls++; SQInteger ret = (nclosure->_function)(this); _nnativecalls--; suspend = false; tailcall = false; if (ret == SQ_TAILCALL_FLAG) { tailcall = true; return true; } else if (ret == SQ_SUSPEND_FLAG) { suspend = true; } else if (ret < 0) { LeaveFrame(); Raise_Error(_lasterror); return false; } if(ret) { retval = _stack._vals[_top-1]; } else { retval.Null(); } //retval = ret ? _stack._vals[_top-1] : _null_; LeaveFrame(); return true; } bool SQVM::TailCall(SQClosure *closure, SQInteger parambase,SQInteger nparams) { SQInteger last_top = _top; SQObjectPtr clo = closure; if (ci->_root) { Raise_Error("root calls cannot invoke tailcalls"); return false; } for (SQInteger i = 0; i < nparams; i++) STK(i) = STK(parambase + i); bool ret = StartCall(closure, ci->_target, nparams, _stackbase, true); if (last_top >= _top) { _top = last_top; } return ret; } #define FALLBACK_OK 0 #define FALLBACK_NO_MATCH 1 #define FALLBACK_ERROR 2 bool SQVM::Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx) { switch(sq_type(self)){ case OT_TABLE: if(_table(self)->Get(key,dest))return true; break; case OT_ARRAY: if (sq_isnumeric(key)) { if (_array(self)->Get(tointeger(key), dest)) { return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; } break; case OT_INSTANCE: if(_instance(self)->Get(key,dest)) return true; break; case OT_CLASS: if(_class(self)->Get(key,dest)) return true; break; case OT_STRING: if(sq_isnumeric(key)){ SQInteger n = tointeger(key); SQInteger len = _string(self)->_len; if (n < 0) { n += len; } if (n >= 0 && n < len) { dest = SQInteger(_stringval(self)[n]); return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; } break; default:break; //shut up compiler } if ((getflags & GET_FLAG_RAW) == 0) { switch(FallBackGet(self,key,dest)) { case FALLBACK_OK: return true; //okie case FALLBACK_NO_MATCH: break; //keep falling back case FALLBACK_ERROR: return false; // the metamethod failed } if(InvokeDefaultDelegate(self,key,dest)) { return true; } } //#ifdef ROOT_FALLBACK if(selfidx == 0) { SQWeakRef *w = _closure(ci->_closure)->_root; if(sq_type(w->_obj) != OT_NULL) { if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,0,DONT_FALL_BACK)) return true; } } //#endif if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; } bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) { SQTable *ddel = NULL; switch(sq_type(self)) { case OT_CLASS: ddel = _class_ddel; break; case OT_TABLE: ddel = _table_ddel; break; case OT_ARRAY: ddel = _array_ddel; break; case OT_STRING: ddel = _string_ddel; break; case OT_INSTANCE: ddel = _instance_ddel; break; case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break; case OT_GENERATOR: ddel = _generator_ddel; break; case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break; case OT_THREAD: ddel = _thread_ddel; break; case OT_WEAKREF: ddel = _weakref_ddel; break; default: return false; } return ddel->Get(key,dest); } SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) { switch(sq_type(self)){ case OT_TABLE: case OT_USERDATA: //delegation if(_delegable(self)->_delegate) { if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK; } else { return FALLBACK_NO_MATCH; } //go through case OT_INSTANCE: { SQObjectPtr closure; if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) { Push(self);Push(key); _nmetamethodscall++; AutoDec ad(&_nmetamethodscall); if(Call(closure, 2, _top - 2, dest, SQFalse)) { Pop(2); return FALLBACK_OK; } else { Pop(2); if(sq_type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) return FALLBACK_ERROR; } } } } break; default: break;//shutup GCC 4.x } // no metamethod or no fallback type return FALLBACK_NO_MATCH; } bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx) { switch(sq_type(self)){ case OT_TABLE: if(_table(self)->Set(key,val)) return true; break; case OT_INSTANCE: if(_instance(self)->Set(key,val)) return true; break; case OT_ARRAY: if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } if(!_array(self)->Set(tointeger(key),val)) { Raise_IdxError(key); return false; } return true; case OT_USERDATA: break; // must fall back default: Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); return false; } switch(FallBackSet(self,key,val)) { case FALLBACK_OK: return true; //okie case FALLBACK_NO_MATCH: break; //keep falling back case FALLBACK_ERROR: return false; // the metamethod failed } if(selfidx == 0) { if(_table(_roottable)->Set(key,val)) return true; } Raise_IdxError(key); return false; } SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) { switch(sq_type(self)) { case OT_TABLE: if(_table(self)->_delegate) { if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK; } //keps on going case OT_INSTANCE: case OT_USERDATA:{ SQObjectPtr closure; SQObjectPtr t; if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) { Push(self);Push(key);Push(val); _nmetamethodscall++; AutoDec ad(&_nmetamethodscall); if(Call(closure, 3, _top - 3, t, SQFalse)) { Pop(3); return FALLBACK_OK; } else { Pop(3); if(sq_type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) return FALLBACK_ERROR; } } } } break; default: break;//shutup GCC 4.x } // no metamethod or no fallback type return FALLBACK_NO_MATCH; } bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) { SQObjectPtr temp_reg; SQObjectPtr newobj; switch(sq_type(self)){ case OT_TABLE: newobj = _table(self)->Clone(); goto cloned_mt; case OT_INSTANCE: { newobj = _instance(self)->Clone(_ss(this)); cloned_mt: SQObjectPtr closure; if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) { Push(newobj); Push(self); if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg)) return false; } } target = newobj; return true; case OT_ARRAY: target = _array(self)->Clone(); return true; default: Raise_Error(_SC("cloning a %s"), GetTypeName(self)); return false; } } bool SQVM::NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw) { if(sq_type(self) != OT_CLASS) { Raise_Error(_SC("object must be a class")); return false; } SQClass *c = _class(self); if(!raw) { SQObjectPtr &mm = c->_metamethods[MT_NEWMEMBER]; if(sq_type(mm) != OT_NULL ) { Push(self); Push(key); Push(val); Push(attrs); Push(bstatic); return CallMetaMethod(mm,MT_NEWMEMBER,5,temp_reg); } } if(!NewSlot(self, key, val,bstatic)) return false; if(sq_type(attrs) != OT_NULL) { c->SetAttributes(key,attrs); } return true; } bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { if(sq_type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } switch(sq_type(self)) { case OT_TABLE: { bool rawcall = true; if(_table(self)->_delegate) { SQObjectPtr res; if(!_table(self)->Get(key,res)) { SQObjectPtr closure; if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { Push(self);Push(key);Push(val); if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { return false; } rawcall = false; } else { rawcall = true; } } } if(rawcall) _table(self)->NewSlot(key,val); //cannot fail break;} case OT_INSTANCE: { SQObjectPtr res; SQObjectPtr closure; if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { Push(self);Push(key);Push(val); if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { return false; } break; } Raise_Error(_SC("class instances do not support the new slot operator")); return false; break;} case OT_CLASS: if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { if(_class(self)->_locked) { Raise_Error(_SC("trying to modify a class that has already been instantiated")); return false; } else { SQObjectPtr oval = PrintObjVal(key); Raise_Error(_SC("the property '%s' already exists"),_stringval(oval)); return false; } } break; default: Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; break; } return true; } bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) { switch(sq_type(self)) { case OT_TABLE: case OT_INSTANCE: case OT_USERDATA: { SQObjectPtr t; //bool handled = false; SQObjectPtr closure; if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) { Push(self);Push(key); return CallMetaMethod(closure,MT_DELSLOT,2,res); } else { if(sq_type(self) == OT_TABLE) { if(_table(self)->Get(key,t)) { _table(self)->Remove(key); } else { Raise_IdxError((const SQObject &)key); return false; } } else { Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self)); return false; } } res = t; } break; default: Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self)); return false; } return true; } bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror, SQBool can_suspend) { #ifdef _DEBUG SQInteger prevstackbase = _stackbase; #endif switch(sq_type(closure)) { case OT_CLOSURE: return Execute(closure, nparams, stackbase, outres, raiseerror, ET_CALL, can_suspend); break; case OT_NATIVECLOSURE:{ bool dummy; return CallNative(_nativeclosure(closure), nparams, stackbase, outres, -1, dummy, dummy); } break; case OT_CLASS: { SQObjectPtr constr; SQObjectPtr temp; CreateClassInstance(_class(closure),outres,constr); SQObjectType ctype = sq_type(constr); if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) { _stack[stackbase] = outres; return Call(constr,nparams,stackbase,temp,raiseerror); } return true; } break; default: Raise_Error(_SC("attempt to call '%s'"), GetTypeName(closure)); return false; } #ifdef _DEBUG if(!_suspended) { assert(_stackbase == prevstackbase); } #endif return true; } bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod SQ_UNUSED_ARG(mm),SQInteger nparams,SQObjectPtr &outres) { //SQObjectPtr closure; _nmetamethodscall++; if(Call(closure, nparams, _top - nparams, outres, SQFalse)) { _nmetamethodscall--; Pop(nparams); return true; } _nmetamethodscall--; //} Pop(nparams); return false; } void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex) { SQOuter **pp = &_openouters; SQOuter *p; SQOuter *otr; while ((p = *pp) != NULL && p->_valptr >= stackindex) { if (p->_valptr == stackindex) { target = SQObjectPtr(p); return; } pp = &p->_next; } otr = SQOuter::Create(_ss(this), stackindex); otr->_next = *pp; otr->_idx = (stackindex - _stack._vals); __ObjAddRef(otr); *pp = otr; target = SQObjectPtr(otr); } bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall) { if( !tailcall ) { if( _callsstacksize == _alloccallsstacksize ) { GrowCallStack(); } ci = &_callsstack[_callsstacksize++]; ci->_prevstkbase = (SQInt32)(newbase - _stackbase); ci->_prevtop = (SQInt32)(_top - _stackbase); ci->_etraps = 0; ci->_ncalls = 1; ci->_generator = NULL; ci->_root = SQFalse; } else { ci->_ncalls++; } _stackbase = newbase; _top = newtop; if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) { if(_nmetamethodscall) { Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod")); return false; } _stack.resize(newtop + (MIN_STACK_OVERHEAD << 2)); RelocateOuters(); } return true; } void SQVM::LeaveFrame() { SQInteger last_top = _top; SQInteger last_stackbase = _stackbase; SQInteger css = --_callsstacksize; /* First clean out the call stack frame */ ci->_closure.Null(); _stackbase -= ci->_prevstkbase; _top = _stackbase + ci->_prevtop; ci = (css) ? &_callsstack[css-1] : NULL; if(_openouters) CloseOuters(&(_stack._vals[last_stackbase])); while (last_top >= _top) { _stack._vals[last_top--].Null(); } } void SQVM::RelocateOuters() { SQOuter *p = _openouters; while (p) { p->_valptr = _stack._vals + p->_idx; p = p->_next; } } void SQVM::CloseOuters(SQObjectPtr *stackindex) { SQOuter *p; while ((p = _openouters) != NULL && p->_valptr >= stackindex) { p->_value = *(p->_valptr); p->_valptr = &p->_value; _openouters = p->_next; __ObjRelease(p); } } void SQVM::Remove(SQInteger n) { n = (n >= 0)?n + _stackbase - 1:_top + n; for(SQInteger i = n; i < _top; i++){ _stack[i] = _stack[i+1]; } _stack[_top].Null(); _top--; } void SQVM::Pop() { _stack[--_top].Null(); } void SQVM::Pop(SQInteger n) { for(SQInteger i = 0; i < n; i++){ _stack[--_top].Null(); } } void SQVM::PushNull() { _stack[_top++].Null(); } void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } #ifdef _DEBUG_DUMP void SQVM::dumpstack(SQInteger stackbase,bool dumpall) { SQInteger size=dumpall?_stack.size():_top; SQInteger n=0; scprintf(_SC("\n>>>>stack dump<<<<\n")); CallInfo &ci=_callsstack[_callsstacksize-1]; scprintf(_SC("IP: %p\n"),ci._ip); scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); scprintf(_SC("prev top: %d\n"),ci._prevtop); for(SQInteger i=0;i"));else scprintf(_SC(" ")); scprintf(_SC("[" _PRINT_INT_FMT "]:"),n); switch(sq_type(obj)){ case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; case OT_INTEGER: scprintf(_SC("INTEGER " _PRINT_INT_FMT),_integer(obj));break; case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; case OT_NULL: scprintf(_SC("NULL")); break; case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break; case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break; case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break; case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break; case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break; case OT_GENERATOR: scprintf(_SC("GENERATOR %p"),_generator(obj));break; case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break; case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break; case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break; case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break; case OT_WEAKREF: scprintf(_SC("WEAKREF %p"),_weakref(obj));break; default: assert(0); break; }; scprintf(_SC("\n")); ++n; } } #endif simutrans-124.3/src/squirrel/squirrel/sqvm.h000066400000000000000000000204471474050137200212240ustar00rootroot00000000000000/* see copyright notice in squirrel.h */ #ifndef _SQVM_H_ #define _SQVM_H_ #include "sqopcodes.h" #include "sqobject.h" #define MAX_NATIVE_CALLS 100 #define MIN_STACK_OVERHEAD 15 #define SQ_SUSPEND_FLAG -666 #define SQ_TAILCALL_FLAG -777 #define DONT_FALL_BACK 666 //#define EXISTS_FALL_BACK -1 #define GET_FLAG_RAW 0x00000001 #define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002 //base lib void sq_base_register(HSQUIRRELVM v); struct SQExceptionTrap{ SQExceptionTrap() {} SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} SQInteger _stackbase; SQInteger _stacksize; SQInstruction *_ip; SQInteger _extarget; }; #define _INLINE typedef sqvector ExceptionsTraps; struct SQVM : public CHAINABLE_OBJ { struct CallInfo{ //CallInfo() { _generator = NULL;} SQInstruction *_ip; SQObjectPtr *_literals; SQObjectPtr _closure; SQGenerator *_generator; SQInt32 _etraps; SQInt32 _prevstkbase; SQInt32 _prevtop; SQInt32 _target; SQInt32 _ncalls; SQBool _root; }; typedef sqvector CallInfoVec; public: void DebugHookProxy(SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM }; SQVM(SQSharedState *ss); ~SQVM(); bool Init(SQVM *friendvm, SQInteger stacksize); bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL, SQBool can_suspend = false); //starts a native call return when the NATIVE closure returns bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall); bool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams); //starts a SQUIRREL call in the same "Execution loop" bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); //call a generic closure pure SQUIRREL or NATIVE // @param can_suspend is by default FALSE, only set it to true if you handle the case that vm is suspended after call. bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror, SQBool can_suspend = false); SQRESULT Suspend(); void CallDebugHook(SQInteger type,SQInteger forcedline=0); void CallErrorHandler(SQObjectPtr &e); bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx); SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx); SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val); bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); bool NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw); bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); bool Clone(const SQObjectPtr &self, SQObjectPtr &target); bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res); bool ToString(const SQObjectPtr &o,SQObjectPtr &res); SQString *PrintObjVal(const SQObjectPtr &o); void Raise_Error(const SQChar *s, ...); void Raise_Error_vl(const SQChar *s, va_list vl); void Raise_Error(const SQObjectPtr &desc); void Raise_IdxError(const SQObjectPtr &o); void Raise_CompareError(const SQObject &o1, const SQObject &o2); void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex); void RelocateOuters(); void CloseOuters(SQObjectPtr *stackindex); bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); bool CallMetaMethod(SQObjectPtr &closure, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres); bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); //new stuff _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); //return true if the loop is finished bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); //_INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger arg0); #ifdef _DEBUG_DUMP void dumpstack(SQInteger stackbase=-1, bool dumpall = false); #endif #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); SQObjectType GetType() {return OT_THREAD;} #endif void Finalize(); void GrowCallStack() { SQInteger newsize = _alloccallsstacksize*2; _callstackdata.resize(newsize); _callsstack = &_callstackdata[0]; _alloccallsstacksize = newsize; } bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall); void LeaveFrame(); void Release(){ sq_delete(this,SQVM); } //////////////////////////////////////////////////////////////////////////// //stack functions for the api void Remove(SQInteger n); static bool IsFalse(SQObjectPtr &o); void Pop(); void Pop(SQInteger n); void Push(const SQObjectPtr &o); void PushNull(); SQObjectPtr &Top(); SQObjectPtr &PopGet(); SQObjectPtr &GetUp(SQInteger n); SQObjectPtr &GetAt(SQInteger n); SQObjectPtrVec _stack; SQInteger _top; SQInteger _stackbase; SQOuter *_openouters; SQObjectPtr _roottable; SQObjectPtr _lasterror; SQObjectPtr _errorhandler; bool _debughook; SQDEBUGHOOK _debughook_native; SQObjectPtr _debughook_closure; SQObjectPtr temp_reg; CallInfo* _callsstack; SQInteger _callsstacksize; SQInteger _alloccallsstacksize; sqvector _callstackdata; ExceptionsTraps _etraps; CallInfo *ci; SQUserPointer _foreignptr; //VMs sharing the same state SQSharedState *_sharedstate; SQInteger _nnativecalls; SQInteger _nmetamethodscall; SQRELEASEHOOK _releasehook; //suspend infos SQBool _suspended; SQBool _suspended_root; SQInteger _suspended_target; SQInteger _suspended_traps; SQInteger _ops_remaining; /// number of ops the vm can do till break SQInteger _ops_grace_amount; /// raise error if _ops_remaining is less than -_ops_grace_amount for pure native calls SQInteger _ops_total; /// total number of ops performed bool _throw_if_no_ops; /// is no-ops an error or can call suspended? default: true }; struct AutoDec{ AutoDec(SQInteger *n) { _n = n; } ~AutoDec() { (*_n)--; } SQInteger *_n; }; inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} #define _ss(_vm_) (_vm_)->_sharedstate #ifndef NO_GARBAGE_COLLECTOR #define _opt_ss(_vm_) (_vm_)->_sharedstate #else #define _opt_ss(_vm_) NULL #endif #define PUSH_CALLINFO(v,nci){ \ SQInteger css = v->_callsstacksize; \ if(css == v->_alloccallsstacksize) { \ v->GrowCallStack(); \ } \ v->ci = &v->_callsstack[css]; \ *(v->ci) = nci; \ v->_callsstacksize++; \ } #define POP_CALLINFO(v){ \ SQInteger css = --v->_callsstacksize; \ v->ci->_closure.Null(); \ v->ci = css?&v->_callsstack[css-1]:NULL; \ } #endif simutrans-124.3/src/squirrel/squirrel_modifications.diff000066400000000000000000000514701474050137200236270ustar00rootroot00000000000000diff --git b/simutrans/trunk/squirrel/sqstdlib/sqstdaux.cc a/simutrans/trunk/squirrel/sqstdlib/sqstdaux.cc index e569acfcf..0d196d9d7 100644 --- b/simutrans/trunk/squirrel/sqstdlib/sqstdaux.cc +++ a/simutrans/trunk/squirrel/sqstdlib/sqstdaux.cc @@ -23,13 +23,14 @@ void sqstd_printcallstack(HSQUIRRELVM v) const SQChar *src=_SC("unknown"); if(si.funcname)fn=si.funcname; if(si.source)src=si.source; - pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); - level++; + pf(v,_SC("* FUNCTION [%s()]
* %s"), fn,src); + if (si.line > 0) { + pf(v,_SC("* line [%d]"),si.line); } - level=0; - pf(v,_SC("\nLOCALS\n")); + pf(v,_SC("
\n")); + + pf(v,_SC("- - LOCALS\n")); - for(level=0;level<10;level++){ seq=0; while((name = sq_getlocal(v,level,seq))) { @@ -37,63 +38,83 @@ void sqstd_printcallstack(HSQUIRRELVM v) switch(sq_gettype(v,-1)) { case OT_NULL: - pf(v,_SC("[%s] NULL\n"),name); + pf(v,_SC("- - - [%s] NULL\n"),name); break; case OT_INTEGER: sq_getinteger(v,-1,&i); - pf(v,_SC("[%s] %d\n"),name,i); + pf(v,_SC("- - - [%s] %d\n"),name,i); break; case OT_FLOAT: sq_getfloat(v,-1,&f); - pf(v,_SC("[%s] %.14g\n"),name,f); + pf(v,_SC("- - - [%s] %.14g\n"),name,f); break; case OT_USERPOINTER: - pf(v,_SC("[%s] USERPOINTER\n"),name); + pf(v,_SC("- - - [%s] USERPOINTER\n"),name); break; case OT_STRING: sq_getstring(v,-1,&s); - pf(v,_SC("[%s] \"%s\"\n"),name,s); + pf(v,_SC("- - - [%s] \"%s\"\n"),name,s); break; case OT_TABLE: - pf(v,_SC("[%s] TABLE\n"),name); + pf(v,_SC("- - - [%s] TABLE (%d entries)\n"),name, sq_getsize(v, -1)); break; case OT_ARRAY: - pf(v,_SC("[%s] ARRAY\n"),name); + pf(v,_SC("- - - [%s] ARRAY (%d entries)\n"),name, sq_getsize(v, -1)); break; case OT_CLOSURE: - pf(v,_SC("[%s] CLOSURE\n"),name); + pf(v,_SC("- - - [%s] CLOSURE\n"),name); break; case OT_NATIVECLOSURE: - pf(v,_SC("[%s] NATIVECLOSURE\n"),name); + pf(v,_SC("- - - [%s] NATIVECLOSURE\n"),name); break; case OT_GENERATOR: - pf(v,_SC("[%s] GENERATOR\n"),name); + pf(v,_SC("- - - [%s] GENERATOR\n"),name); break; case OT_USERDATA: - pf(v,_SC("[%s] USERDATA\n"),name); + pf(v,_SC("- - - [%s] USERDATA\n"),name); break; case OT_THREAD: - pf(v,_SC("[%s] THREAD\n"),name); + pf(v,_SC("- - - [%s] THREAD\n"),name); break; case OT_CLASS: - pf(v,_SC("[%s] CLASS\n"),name); + pf(v,_SC("- - - [%s] CLASS\n"),name); break; case OT_INSTANCE: - pf(v,_SC("[%s] INSTANCE\n"),name); + { + // try to obtain class name + sq_getclass(v, -1); + sq_pushnull(v); + if (SQ_SUCCEEDED(sq_getattributes(v, -2))) { + // stack: instance, class, attributes + sq_pushstring(v, "classname", -1); + if (SQ_SUCCEEDED(sq_get(v, -2))) { + const char* cn; + if (SQ_SUCCEEDED(sq_getstring(v, -1, &cn))) { + pf(v,_SC("- - - [%s] INSTANCE(%s)\n"),name, cn); + sq_pop(v, 3); break; + } + } + sq_poptop(v); + } + sq_poptop(v); + pf(v,_SC("- - - [%s] INSTANCE\n"),name); + break; + } case OT_WEAKREF: - pf(v,_SC("[%s] WEAKREF\n"),name); + pf(v,_SC("- - - [%s] WEAKREF\n"),name); break; case OT_BOOL:{ SQBool bval; sq_getbool(v,-1,&bval); - pf(v,_SC("[%s] %s\n"),name,bval == SQTrue ? _SC("true"):_SC("false")); + pf(v,_SC("- - - [%s] %s\n"),name,bval == SQTrue ? _SC("true"):_SC("false")); } break; default: assert(0); break; } sq_pop(v,1); } + level++; } } } @@ -102,16 +123,18 @@ static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { + pf(v,_SC("")); const SQChar *sErr = 0; if(sq_gettop(v)>=1) { if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { - pf(v,_SC("\nAN ERROR HAS OCCURRED [%s]\n"),sErr); + pf(v,_SC("\nError: [%s]\n"),sErr); } else{ - pf(v,_SC("\nAN ERROR HAS OCCURRED [unknown]\n")); + pf(v,_SC("\nError: [unknown]\n")); } sqstd_printcallstack(v); } + pf(v,_SC("")); } return 0; } @@ -120,7 +143,9 @@ void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSourc { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { + pf(v,_SC("")); pf(v,_SC("%s line = (%d) column = (%d) : error %s\n"),sSource,line,column,sErr); + pf(v,_SC("")); } } diff --git b/simutrans/trunk/squirrel/sqstdlib/sqstdblob.cc a/simutrans/trunk/squirrel/sqstdlib/sqstdblob.cc index 13d68f0c0..dac94cc62 100644 --- b/simutrans/trunk/squirrel/sqstdlib/sqstdblob.cc +++ a/simutrans/trunk/squirrel/sqstdlib/sqstdblob.cc @@ -185,22 +185,6 @@ static const SQRegFunction _blob_methods[] = { //GLOBAL FUNCTIONS -static SQInteger _g_blob_casti2f(HSQUIRRELVM v) -{ - SQInteger i; - sq_getinteger(v,2,&i); - sq_pushfloat(v,*((const SQFloat *)&i)); - return 1; -} - -static SQInteger _g_blob_castf2i(HSQUIRRELVM v) -{ - SQFloat f; - sq_getfloat(v,2,&f); - sq_pushinteger(v,*((const SQInteger *)&f)); - return 1; -} - static SQInteger _g_blob_swap2(HSQUIRRELVM v) { SQInteger i; @@ -231,8 +215,6 @@ static SQInteger _g_blob_swapfloat(HSQUIRRELVM v) #define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck} static const SQRegFunction bloblib_funcs[]={ - _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(".n")), - _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(".n")), _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")), _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")), _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")), diff --git b/simutrans/trunk/squirrel/squirrel.h a/simutrans/trunk/squirrel/squirrel.h index 65df9c5bb..2fb201356 100644 --- b/simutrans/trunk/squirrel/squirrel.h +++ a/simutrans/trunk/squirrel/squirrel.h @@ -60,7 +60,7 @@ struct SQDelegable; struct SQOuter; #ifdef _UNICODE -#define SQUNICODE +// #define SQUNICODE #endif #include "sqconfig.h" @@ -398,10 +399,10 @@ SQUIRREL_API void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook); #define SQ_FAILED(res) (res<0) #define SQ_SUCCEEDED(res) (res>=0) -#ifdef __GNUC__ -# define SQ_UNUSED_ARG(x) x __attribute__((__unused__)) +#ifdef XX__GNUC__ +# define SQ_UNUSED_ARG(x) __attribute__((unused)) x #else -# define SQ_UNUSED_ARG(x) x +# define SQ_UNUSED_ARG(x) #endif #ifdef __cplusplus diff --git b/simutrans/trunk/squirrel/squirrel/sqapi.cc a/simutrans/trunk/squirrel/squirrel/sqapi.cc index 4ab6f00ba..a19cd0e39 100644 --- b/simutrans/trunk/squirrel/squirrel/sqapi.cc +++ a/simutrans/trunk/squirrel/squirrel/sqapi.cc @@ -1078,8 +1078,10 @@ SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) v->Pop(); return sq_throwerror(v,_SC("rawget works only on array/table/instance and class")); } + // modified: call Raise_IdxError + v->Raise_IdxError(v->GetUp(-1)); v->Pop(); - return sq_throwerror(v,_SC("the index doesn't exist")); + return SQ_ERROR; } SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) @@ -1172,20 +1174,33 @@ SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) return sq_throwerror(v,_SC("only generators can be resumed")); } +/* modified for our purposes to handle suspended scripts */ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror) { SQObjectPtr res; - if(!v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){ - v->Pop(params); //pop args - return SQ_ERROR; + + if(v->_suspended) { + v->Pop(params);//pop closure and args + return sq_throwerror(v,_SC("script took to long")); + } + // we can suspend call only when vm is not already running (thus when we are not called from squirrel) + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false, sq_getvmstate(v)==SQ_VMSTATE_IDLE)){ + + if(!v->_suspended) { + v->Pop(params);//pop closure and args + } + if(retval){ + v->Push(res); return SQ_OK; } - if(!v->_suspended) - v->Pop(params); //pop args - if(retval) - v->Push(res); // push result return SQ_OK; } + else { + v->Pop(params); + return SQ_ERROR; // sq_throwerror(v,_SC("call failed")); + } +} +/* TODO check whether this works with our suspend logic; wont be missed SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams) { SQObjectPtr &res = v->GetUp(-(nparams + 1)); @@ -1204,6 +1219,7 @@ SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams) } return SQ_TAILCALL_FLAG; } +*/ SQRESULT sq_suspendvm(HSQUIRRELVM v) { @@ -1223,7 +1239,7 @@ SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseer v->Pop(); } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); } SQObjectPtr dummy; - if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) { + if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM, true /*can_suspend*/)) { return SQ_ERROR; } if(retval) diff --git b/simutrans/trunk/squirrel/squirrel/sqbaselib.cc a/simutrans/trunk/squirrel/squirrel/sqbaselib.cc index aa9f07d5e..130f2a191 100644 --- b/simutrans/trunk/squirrel/squirrel/sqbaselib.cc +++ a/simutrans/trunk/squirrel/squirrel/sqbaselib.cc @@ -955,9 +955,14 @@ static SQInteger string_find(HSQUIRRELVM v) return 1; \ } +static char toalnum(char c) +{ + return isalnum(c) && c >=0 ? c : '_'; +} STRING_TOFUNCZ(tolower) STRING_TOFUNCZ(toupper) +STRING_TOFUNCZ(toalnum) const SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ {_SC("len"),default_delegate_len,1, _SC("s")}, @@ -968,6 +973,7 @@ const SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ {_SC("find"),string_find,-2, _SC("s s n")}, {_SC("tolower"),string_tolower,-1, _SC("s n n")}, {_SC("toupper"),string_toupper,-1, _SC("s n n")}, + {_SC("toalnum"),string_toalnum,1, _SC("s")}, {_SC("weakref"),obj_delegate_weakref,1, NULL }, {NULL,(SQFUNCTION)0,0,NULL} }; @@ -990,11 +996,13 @@ static SQInteger closure_pcall(HSQUIRRELVM v) static SQInteger closure_call(HSQUIRRELVM v) { + /* has to wait until sq_tailcall is enabled SQObjectPtr &c = stack_get(v, -1); if (sq_type(c) == OT_CLOSURE && (_closure(c)->_function->_bgenerator == false)) { return sq_tailcall(v, sq_gettop(v) - 1); } + */ return SQ_SUCCEEDED(sq_call(v, sq_gettop(v) - 1, SQTrue, SQTrue)) ? 1 : SQ_ERROR; } diff --git b/simutrans/trunk/squirrel/squirrel/sqcompiler.cc a/simutrans/trunk/squirrel/squirrel/sqcompiler.cc index 3f23b9054..774d9cfbe 100644 --- b/simutrans/trunk/squirrel/squirrel/sqcompiler.cc +++ a/simutrans/trunk/squirrel/squirrel/sqcompiler.cc @@ -940,6 +940,19 @@ public: SQInteger stackbase = _fs->PopTarget(); SQInteger closure = _fs->PopTarget(); _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); +#if 0 + /* + * disabled as it breaks existing scripts like + * + * local a = [] + * local b = a.len() + * // open some new block + * { + * local c = 0 + * } + * + * see https://github.com/albertodemichelis/squirrel/issues/177 + */ if (_token == '{') { SQInteger retval = _fs->TopTarget(); @@ -964,6 +977,7 @@ public: } Lex(); } +#endif } void ParseTableOrClass(SQInteger separator,SQInteger terminator) { diff --git b/simutrans/trunk/squirrel/squirrel/sqdebug.cc a/simutrans/trunk/squirrel/squirrel/sqdebug.cc index 06fcf4ddb..dcf35c090 100644 --- b/simutrans/trunk/squirrel/squirrel/sqdebug.cc +++ a/simutrans/trunk/squirrel/squirrel/sqdebug.cc @@ -60,9 +60,14 @@ void SQVM::Raise_Error(const SQChar *s, ...) { va_list vl; va_start(vl, s); + Raise_Error_vl(s, vl); + va_end(vl); +} + +void SQVM::Raise_Error_vl(const SQChar *s, va_list vl) +{ SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2); scvsprintf(_sp(sq_rsl(buffersize)),buffersize, s, vl); - va_end(vl); _lasterror = SQString::Create(_ss(this),_spval,-1); } diff --git b/simutrans/trunk/squirrel/squirrel/sqopcodes.h a/simutrans/trunk/squirrel/squirrel/sqopcodes.h index a74893ede..4cffe1393 100644 --- b/simutrans/trunk/squirrel/squirrel/sqopcodes.h +++ a/simutrans/trunk/squirrel/squirrel/sqopcodes.h @@ -99,7 +99,7 @@ enum SQOpcode _OP_THROW= 0x39, _OP_NEWSLOTA= 0x3A, _OP_GETBASE= 0x3B, - _OP_CLOSE= 0x3C + _OP_CLOSE= 0x3C, }; struct SQInstructionDesc { @@ -110,7 +110,8 @@ struct SQInstruction { SQInstruction(){}; SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) - { op = (unsigned char)_op; + { + op = (unsigned char)_op; _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; } diff --git b/simutrans/trunk/squirrel/squirrel/sqvm.cc a/simutrans/trunk/squirrel/squirrel/sqvm.cc index 61a65d877..82085aad2 100644 --- b/simutrans/trunk/squirrel/squirrel/sqvm.cc +++ a/simutrans/trunk/squirrel/squirrel/sqvm.cc @@ -126,6 +126,10 @@ SQVM::SQVM(SQSharedState *ss) ci = NULL; _releasehook = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); + _ops_remaining = 0; + _ops_total = 0; + _ops_grace_amount = 500; + _throw_if_no_ops = true; } void SQVM::Finalize() @@ -386,8 +388,9 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQIntege { paramssize--; if (nargs < paramssize) { - Raise_Error(_SC("wrong number of parameters (%d passed, at least %d required)"), - (int)nargs, (int)paramssize); + const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; + const SQChar *name = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL; + Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s:%s"), nargs, paramssize, src, name); return false; } @@ -413,8 +416,9 @@ bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQIntege } } else { - Raise_Error(_SC("wrong number of parameters (%d passed, %d required)"), - (int)nargs, (int)paramssize); + const SQChar *src = sq_type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; + const SQChar *name = sq_type(func->_name) == OT_STRING?_stringval(func->_name):NULL; + Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s:%s"), nargs, paramssize, src, name); return false; } } @@ -679,7 +683,8 @@ bool SQVM::IsFalse(SQObjectPtr &o) return false; } extern SQInstructionDesc g_InstrDesc[]; -bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et, SQBool can_suspend) { if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } _nnativecalls++; @@ -717,6 +722,26 @@ exception_restore: { for(;;) { + _ops_total++; + _ops_remaining --; + if (_ops_remaining < 0) { + // suspend vm + if (can_suspend && !_throw_if_no_ops) { + _suspended = SQTrue; + _suspended_root = ci->_root; + _suspended_traps = traps; + _suspended_target = -1; + return true; + } + else { + // throw error (if within unsuspendable function give some grace opcodes) + if (_throw_if_no_ops || (_ops_remaining + _ops_grace_amount < 0) ) { + Raise_Error(_SC("script took too long: remain = %d grac = %d"), _ops_remaining, _ops_grace_amount); + SQ_THROW(); + } + } + } + const SQInstruction &_i_ = *ci->_ip++; //dumpstack(_stackbase); //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-_closure(ci->_closure)->_function->_instructions,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); @@ -730,7 +755,11 @@ exception_restore: #else TARGET = (SQInteger)((SQInt32)arg1); continue; #endif - case _OP_LOADFLOAT: TARGET = *((const SQFloat *)&arg1); continue; + case _OP_LOADFLOAT: + SQFloat v; + memcpy(&v, &arg1, sizeof(SQFloat)); + TARGET = v; + continue; case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; case _OP_TAILCALL:{ SQObjectPtr &t = STK(arg1); @@ -932,7 +961,7 @@ exception_restore: break; case AAT_FLOAT: val._type = OT_FLOAT; - val._unVal.fFloat = *((const SQFloat *)&arg1); + memcpy(&val._unVal.fFloat, &arg1, sizeof(SQFloat)); break; case AAT_BOOL: val._type = OT_BOOL; @@ -1165,7 +1194,8 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) || ((nparamscheck < 0) && (nargs < (-nparamscheck))))) { - Raise_Error(_SC("wrong number of parameters")); + const SQChar *src = sq_type(nclosure->_name) == OT_STRING?_stringval(nclosure->_name):NULL; + Raise_Error(_SC("wrong number of parameters: %d provided (instead %d) in call to %s"), nargs, nparamscheck, src); return false; } @@ -1577,14 +1607,14 @@ bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr return true; } -bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror) +bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror, SQBool can_suspend) { #ifdef _DEBUG SQInteger prevstackbase = _stackbase; #endif switch(sq_type(closure)) { case OT_CLOSURE: - return Execute(closure, nparams, stackbase, outres, raiseerror); + return Execute(closure, nparams, stackbase, outres, raiseerror, ET_CALL, can_suspend); break; case OT_NATIVECLOSURE:{ bool dummy; diff --git b/simutrans/trunk/squirrel/squirrel/sqvm.h a/simutrans/trunk/squirrel/squirrel/sqvm.h index c82e44c26..e768220e0 100644 --- b/simutrans/trunk/squirrel/squirrel/sqvm.h +++ a/simutrans/trunk/squirrel/squirrel/sqvm.h @@ -55,7 +55,7 @@ public: SQVM(SQSharedState *ss); ~SQVM(); bool Init(SQVM *friendvm, SQInteger stacksize); - bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); + bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL, SQBool can_suspend = false); //starts a native call return when the NATIVE closure returns bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, SQInt32 target, bool &suspend,bool &tailcall); bool TailCall(SQClosure *closure, SQInteger firstparam, SQInteger nparams); @@ -63,7 +63,8 @@ public: bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); //call a generic closure pure SQUIRREL or NATIVE - bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror); + // @param can_suspend is by default FALSE, only set it to true if you handle the case that vm is suspended after call. + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror, SQBool can_suspend = false); SQRESULT Suspend(); void CallDebugHook(SQInteger type,SQInteger forcedline=0); @@ -85,6 +86,7 @@ public: void Raise_Error(const SQChar *s, ...); + void Raise_Error_vl(const SQChar *s, va_list vl); void Raise_Error(const SQObjectPtr &desc); void Raise_IdxError(const SQObjectPtr &o); void Raise_CompareError(const SQObject &o1, const SQObject &o2); @@ -177,6 +179,11 @@ public: SQBool _suspended_root; SQInteger _suspended_target; SQInteger _suspended_traps; + + SQInteger _ops_remaining; /// number of ops the vm can do till break + SQInteger _ops_grace_amount; /// raise error if _ops_remaining is less than -_ops_grace_amount for pure native calls + SQInteger _ops_total; /// total number of ops performed + bool _throw_if_no_ops; /// is no-ops an error or can call suspended? default: true }; struct AutoDec{ diff --git b/simutrans/trunk/squirrel/update_squirrel.sh a/simutrans/trunk/squirrel/update_squirrel.sh index e3f41794c..a23dc59be 100755 --- b/simutrans/trunk/squirrel/update_squirrel.sh +++ a/simutrans/trunk/squirrel/update_squirrel.sh @@ -41,11 +41,11 @@ for i in *.h; do gawk -f ../update_squirrel.awk "$i" > temp; mv temp "$i"; done cd .. cd .. -git diff -w --ignore-blank-lines --ignore-space-at-eol -b -R > update_squirrel.diff -# -# git checkout -- squirrel/squirrel -# git checkout -- squirrel/sqstdlib -# git checkout -- squirrel/sq*.h -# git checkout -- simutrans/license_squirrel.txt -# -# patch --ignore-whitespace -p3 < update_squirrel.diff +git diff -w --ignore-blank-lines --ignore-space-at-eol -b > update_squirrel.diff + +git checkout -- squirrel/squirrel +git checkout -- squirrel/sqstdlib +git checkout -- squirrel/sq*.h +git checkout -- simutrans/license_squirrel.txt + +patch --ignore-whitespace -p3 < update_squirrel.diff simutrans-124.3/src/squirrel/update_squirrel.awk000066400000000000000000000006141474050137200221250ustar00rootroot00000000000000# gawk file to minimize patch size # strip trailing whitespace { sub(/[[:space:]]+$/, "") } # replace include by include "../sq*.h" /include.*\/, "\"../\\1\"", "g"); print a next } # replace four spaces by tabs / / { a = gensub(/ /, "\t", "g"); print a next } # replace stupid endif comments /endif.*_H_/ { print "#endif" next } { print $0 } simutrans-124.3/src/squirrel/update_squirrel.sh000077500000000000000000000031411474050137200217560ustar00rootroot00000000000000#!/bin/bash # # Script to update squirrel source code from SQUIRREL3 # # Call with ``update_squirrel PATH_TO_SQUIRREL'', where # PATH_TO_SQUIRREL is path of local clone of https://github.com/albertodemichelis/squirrel # # Call it within a git repo of simutrans. # # Still needs manual review, to make sure none of our modifications are reverted. SQPATH=$1 # copy and rename files echo $SQPATH/COPYRIGHT ../simutrans/license_squirrel.txt cp $SQPATH/COPYRIGHT ../simutrans/license_squirrel.txt cp $SQPATH/include/* . cp $SQPATH/squirrel/*.h squirrel/ cp $SQPATH/squirrel/*.h squirrel/ cp $SQPATH/squirrel/*.cpp squirrel/ for i in *.h; do gawk -f update_squirrel.awk "$i" > temp; mv temp "$i"; done cd squirrel # rename for i in *.cpp; do mv "$i" "${i/.cpp}".cc; done # replace include by include "../sq*.h" for i in *.cc; do gawk -f ../update_squirrel.awk "$i" > temp; mv temp "$i"; done for i in *.h; do gawk -f ../update_squirrel.awk "$i" > temp; mv temp "$i"; done cd .. cp $SQPATH/sqstdlib/*.h sqstdlib/ cp $SQPATH/sqstdlib/*.cpp sqstdlib/ cd sqstdlib # rename for i in *.cpp; do mv "$i" "${i/.cpp}".cc; done # replace include by include "../sq*.h" for i in *.cc; do gawk -f ../update_squirrel.awk "$i" > temp; mv temp "$i"; done for i in *.h; do gawk -f ../update_squirrel.awk "$i" > temp; mv temp "$i"; done cd .. cd .. git diff -w --ignore-blank-lines --ignore-space-at-eol -b > update_squirrel.diff git checkout -- squirrel/squirrel git checkout -- squirrel/sqstdlib git checkout -- squirrel/sq*.h git checkout -- simutrans/license_squirrel.txt patch --ignore-whitespace -p3 < update_squirrel.diff simutrans-124.3/src/steam/000077500000000000000000000000001474050137200154535ustar00rootroot00000000000000simutrans-124.3/src/steam/achievements.cc000066400000000000000000000062561474050137200204460ustar00rootroot00000000000000#include "achievements.h" #include "../simutrans/simachenum.h" #include "../simutrans/simdebug.h" #include "isteamuser.h" #include "isteamutils.h" // Generating the initial array from the enum. I love the X Macro, so powerful! #define X(id) { id, #id, "", "", 0, 0 }, achievement_t achievements_list[] = { ACHIEVEMENTS }; #undef X steam_achievements_t::steam_achievements_t() : app_id(0), stats_initialized(false), m_CallbackUserStatsReceived(this, &steam_achievements_t::on_user_stats_received), m_CallbackUserStatsStored(this, &steam_achievements_t::on_user_stats_stored), m_CallbackAchievementStored(this, &steam_achievements_t::on_achievement_stored) { app_id = SteamUtils()->GetAppID(); achievements = achievements_list; request_stats(); } bool steam_achievements_t::request_stats() { if (NULL == SteamUserStats() || NULL == SteamUser()) { return false; } if (!SteamUser()->BLoggedOn()) { return false; } return SteamUserStats()->RequestCurrentStats(); } void steam_achievements_t::on_user_stats_received(UserStatsReceived_t *callback) { if (app_id == callback->m_nGameID) { if (k_EResultOK == callback->m_eResult) { dbg->message("steam_achievements_t::on_user_stats_received", "Received stats and achievements from Steam\n"); stats_initialized = true; // load achievements for (int iAch = 0; iAch < NUM_ACHIEVEMENTS; ++iAch) { achievement_t &ach = achievements[iAch]; SteamUserStats()->GetAchievement(ach.m_pchAchievementID, &ach.m_bAchieved); snprintf(ach.m_rgchName, sizeof(ach.m_rgchName), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "name")); snprintf(ach.m_rgchDescription, sizeof(ach.m_rgchDescription), "%s", SteamUserStats()->GetAchievementDisplayAttribute(ach.m_pchAchievementID, "desc")); } // retry achievements sent before the callback completed for (int ach_id : achievements_queue) { set_achievement(ach_id); } achievements_queue.clear(); } else { dbg->error("steam_achievements_t::on_user_stats_received", "RequestStats - failed, %d\n", callback->m_eResult); } } } void steam_achievements_t::on_user_stats_stored(UserStatsStored_t *callback) { if (app_id == callback->m_nGameID) { if (k_EResultOK == callback->m_eResult) { dbg->message("steam_achievements_t::on_user_stats_stored", "Stored stats for Steam\n"); } else { dbg->error("steam_achievements_t::on_user_stats_received", "StatsStored - failed, %d\n", callback->m_eResult); } } } void steam_achievements_t::on_achievement_stored(UserAchievementStored_t *callback) { if (app_id == callback->m_nGameID) { dbg->message("steam_achievements_t::on_achievement_stored", "Stored Achievement for Steam\n"); } } bool steam_achievements_t::set_achievement(int ach_enum) { if (stats_initialized && !achievements[ach_enum].m_bAchieved) { dbg->message("steam_achievements_t::set_achievement", "Earned achievement %s\n", achievements[ach_enum].m_pchAchievementID); SteamUserStats()->SetAchievement(achievements[ach_enum].m_pchAchievementID); return SteamUserStats()->StoreStats(); } else { // Too early! Add them to the queue to retry on_user_stats_received achievements_queue.push_back(ach_enum); } return false; }simutrans-124.3/src/steam/achievements.h000066400000000000000000000017431474050137200203040ustar00rootroot00000000000000#include "isteamuserstats.h" #include "steam_api.h" #include struct achievement_t { int m_eAchievementID; const char *m_pchAchievementID; char m_rgchName[128]; char m_rgchDescription[256]; bool m_bAchieved; int m_iIconImage; }; class steam_achievements_t { private: uint64 app_id; achievement_t *achievements; bool stats_initialized; std::vector achievements_queue; public: steam_achievements_t(); bool request_stats(); // Note: not declaring type as "simachievements_enum" instead of "int" to avoid circular dependency issues bool set_achievement(int ach_enum); achievement_t *get_achievements() { return achievements; }; STEAM_CALLBACK(steam_achievements_t, on_user_stats_received, UserStatsReceived_t, m_CallbackUserStatsReceived); STEAM_CALLBACK(steam_achievements_t, on_user_stats_stored, UserStatsStored_t, m_CallbackUserStatsStored); STEAM_CALLBACK(steam_achievements_t, on_achievement_stored, UserAchievementStored_t, m_CallbackAchievementStored); };simutrans-124.3/src/steam/steam.cc000066400000000000000000000176411474050137200171040ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include "steam.h" #include #include #include "../simutrans/dataobj/environment.h" #include "../simutrans/simdebug.h" #include "isteamugc.h" #include "isteamutils.h" #include "steam_api.h" #define MAX_WORKSHOP_ITEMS 1000 // API fetch limit #define MAX_TAG_LENGTH 100 steam_t* steam_t::steam = nullptr; steam_t::steam_t() { if (!(is_api_initialized = SteamAPI_Init())) { dbg->warning("steam_t::steam_t()", "Steam API Initialization FAILED, Steam functionality won't be available!"); } else { steam_achievements = new steam_achievements_t(); } } steam_t* steam_t::get_instance() { if (steam == nullptr) { steam = new steam_t(); } return steam; } /** * 0. Get previously installed items (saved in wokshop.txt) * 1. Get subscribed items: https://partner.steamgames.com/doc/api/ISteamUGC#GetSubscribedItems * 2. Compare to ge new items and items to uninstall * 3. Uninstall old items that are no longer subscribed * 4. Get details of the new susbcribed items to fetch tags: * 5. Get the number of tags for each new item: https://partner.steamgames.com/doc/api/ISteamUGC#GetQueryUGCNumKeyValueTags * 6. Get the values of the tags for each new item: https://partner.steamgames.com/doc/api/ISteamUGC#GetQueryUGCKeyValueTag * 7. Install the new items in an appropiate location based on their tags */ void steam_t::install_workshop_items() { if (!is_api_initialized) return; std::vector previously_installed_items = steam_t::read_installed_items(); int num_subscribed_items = SteamUGC()->GetNumSubscribedItems(); PublishedFileId_t subscribed_items[MAX_WORKSHOP_ITEMS]; SteamUGC()->GetSubscribedItems(subscribed_items, num_subscribed_items); existing_items = steam_t::uninstall_old_items(previously_installed_items, subscribed_items, num_subscribed_items); new_items_ids = steam_t::get_new_items(existing_items, subscribed_items, num_subscribed_items); if (new_items_ids.size()) { UGCQueryHandle_t ugc_query = SteamUGC()->CreateQueryUGCDetailsRequest(new_items_ids.data(), new_items_ids.size()); if (ugc_query != k_UGCQueryHandleInvalid) { SteamUGC()->SetReturnMetadata(ugc_query, true); SteamAPICall_t hSteamAPICall = SteamUGC()->SendQueryUGCRequest(ugc_query); get_items_details_result.Set(hSteamAPICall, steam, &steam_t::on_get_items_details); dbg->message("steam_t::install_workshop_items()", "Fetching details of new items..."); is_installing = true; // Calls will resolve asynchronously, but we need to wait until paksets are installed! while (is_installing) { SteamAPI_RunCallbacks(); } } } else if (existing_items.size() != previously_installed_items.size()) { write_existing_items(); } } void steam_t::on_get_items_details(SteamUGCQueryCompleted_t* callback, bool failure) { std::vector installed_items; if (!failure && callback->m_eResult == 1) { int num_results = callback->m_unNumResultsReturned; int num_tags_vector[MAX_WORKSHOP_ITEMS]; for (int result_index = 0; result_index < num_results; result_index++) { num_tags_vector[result_index] = SteamUGC()->GetQueryUGCNumTags(callback->m_handle, result_index); } for (int result_index = 0; result_index < num_results; result_index++) { SteamUGCDetails_t pDetails = SteamUGCDetails_t(); SteamUGC()->GetQueryUGCResult(callback->m_handle, result_index, &pDetails); workshop_item_t item = workshop_item_t(new_items_ids[result_index], pDetails.m_rgchTitle); for (int tag_index = 0; tag_index < num_tags_vector[result_index]; tag_index++) { char tag[MAX_TAG_LENGTH]; SteamUGC()->GetQueryUGCTagDisplayName(callback->m_handle, result_index, tag_index, tag, MAX_TAG_LENGTH); if (!item.set_category_tag(tag) && !item.add_pakset_tag(tag)) { dbg->error("steam_t::on_get_items_details()", "Tag name '%s' is not a valid tag!", tag); } } char folder[1024]; SteamUGC()->GetItemInstallInfo(item.get_id(), NULL, folder, sizeof(folder), NULL); if (item.install(folder)) { installed_items.push_back(item); } } } steam_t::write_installed_items(installed_items); is_installing = false; SteamUGC()->ReleaseQueryUGCRequest(callback->m_handle); } /** * Get the list of installed items from a command-separated list in a file * First value should be the workshop item id, then files installed */ std::vector steam_t::read_installed_items() { std::string file_path = std::string(env_t::base_dir) + "workshop.txt"; std::vector installed_items; std::ifstream file(file_path); if (file.is_open()) { std::string line; std::string delimiter = ","; while (getline(file, line)) { // dbg->message("steam_t::read_installed_items()", "Reading line: '%s'", line.c_str()); std::string id = line.substr(0, line.find(delimiter)); line.erase(0, line.find(delimiter) + delimiter.length()); std::vector files; while (true) { std::string path = line.substr(0, line.find(delimiter)); files.push_back(path); // dbg->message("steam_t::read_installed_items()", "Reading line: '%s'", line.c_str()); if (line.find(delimiter) == line.npos) { break; } else { line.erase(0, line.find(delimiter) + delimiter.length()); } } installed_items.push_back({std::stoull(id), files}); } file.close(); } return installed_items; } void steam_t::write_installed_items(std::vector installed_items) { for (auto item : installed_items) { existing_items.push_back(item); } write_existing_items(); } void steam_t::write_existing_items() { std::string file_path = std::string(env_t::base_dir) + "workshop.txt"; std::remove(file_path.c_str()); std::ofstream file(file_path); if (file.is_open()) { for (auto item : existing_items) { std::string line = std::to_string(item.get_id()); for (auto item_file : item.get_files()) { line.append("," + item_file); } file << line + "\n"; } file.close(); } else { dbg->error("steam_t::write_existing_items()", "Could not open %s file for writing", file_path.c_str()); } } std::vector steam_t::get_new_items(std::vector installed_items, PublishedFileId_t subscribed_items[], int num_subscribed_items) { std::vector new_items; for (int i = 0; i < num_subscribed_items; i++) { bool found_item = false; for (auto item : installed_items) { if (item.get_id() == subscribed_items[i]) { found_item = true; break; } } if (!found_item) { new_items.push_back(subscribed_items[i]); dbg->message("steam_t::get_new_items()", "Found new workshop item: %lu", subscribed_items[i]); } } return new_items; } std::vector steam_t::uninstall_old_items(std::vector installed_items, PublishedFileId_t subscribed_items[], int num_subscribed_items) { std::vector old_items; std::vector current_items; for (auto item : installed_items) { bool found_item = false; for (int i = 0; i < num_subscribed_items; i++) { if (item.get_id() == subscribed_items[i]) { found_item = true; existing_items.push_back(item); break; } } if (!found_item) { old_items.push_back(item); } else { current_items.push_back(item); } } for (auto item : old_items) { item.uninstall(); } return current_items; } void steam_t::update_ui(uint32 year, uint32 total_convoys) { if (!is_api_initialized) return; std::string pakset = env_t::pak_name; pakset.pop_back(); // Remove path separator SteamFriends()->SetRichPresence("pakset", pakset.c_str()); SteamFriends()->SetRichPresence("year", std::to_string(year).c_str()); SteamFriends()->SetRichPresence("convoys", std::to_string(total_convoys).c_str()); SteamFriends()->SetRichPresence("steam_display", "#Playing"); SteamAPI_RunCallbacks(); } void steam_t::shutdown() { SteamAPI_Shutdown(); if (steam_achievements) delete steam_achievements; }simutrans-124.3/src/steam/steam.h000066400000000000000000000030201474050137200167300ustar00rootroot00000000000000/* * This file is part of the Simutrans project under the Artistic License. * (see LICENSE.txt) */ #include #include #include #include "achievements.h" #include "isteamugc.h" #include "workshop_item.h" /** * Singleton class to prevent the Steam API from being initialized more than once */ class steam_t { private: steam_t(); steam_t(steam_t& other) = delete; steam_t& operator=(steam_t& other) = delete; static steam_t* steam; steam_achievements_t* steam_achievements = NULL; bool is_api_initialized = false; bool is_installing = false; std::vector new_items_ids; std::vector existing_items; CCallResult get_items_details_result; void on_get_items_details(SteamUGCQueryCompleted_t* callback, bool failure); std::vector read_installed_items(); void write_installed_items(std::vector installed_items); void write_existing_items(); std::vector get_new_items(std::vector installed_items, PublishedFileId_t subscribed_items[], int num_subscribed_items); std::vector uninstall_old_items(std::vector installed_items, PublishedFileId_t subscribed_items[], int num_subscribed_items); public: static steam_t* get_instance(); void install_workshop_items(); void update_ui(uint32 year, uint32 total_convoys); steam_achievements_t* get_achievements() { return steam_achievements; } void shutdown(); }; simutrans-124.3/src/steam/workshop_item.cc000066400000000000000000000063601474050137200206610ustar00rootroot00000000000000#include "workshop_item.h" #include #include #include "../simutrans/dataobj/environment.h" #include "../simutrans/simdebug.h" #include "../simutrans/sys/simsys.h" #include "../simutrans/utils/simstring.h" namespace fs = std::filesystem; // Current categories available on Steam Workshop static const std::set valid_paksets({"pak", "Pak64", "Pak128", "pak128.japan", "pak192.comic"}); static const std::set valid_categories({"pakset", "map", "addon", "Scenario"}); workshop_item_t::workshop_item_t(PublishedFileId_t id, std::vector files) { this->id = id; this->files = files; }; workshop_item_t::workshop_item_t(PublishedFileId_t id, std::string title) { this->id = id; str_to_lowercase(title); this->title = title; }; bool workshop_item_t::set_category_tag(std::string tag) { auto search = valid_categories.find(tag); if (search != valid_categories.end()) { category_tag = tag; return true; } return false; } bool workshop_item_t::add_pakset_tag(std::string tag) { auto search = valid_paksets.find(tag); if (search != valid_paksets.end()) { str_to_lowercase(tag); if (tag == "pak") { pakset_tags.push_back("pak64"); } else { pakset_tags.push_back(tag); } return true; } return false; } void workshop_item_t::fill_paths() { if (category_tag == "map") { paths.push_back("maps"); } else if (category_tag == "pakset") { paths.push_back("paksets" + std::string(PATH_SEPARATOR) + title); } else if (category_tag == "addon") { for (auto pakset_name : pakset_tags) { paths.push_back("addons" + std::string(PATH_SEPARATOR) + pakset_name); } } else if (category_tag == "Scenario") { for (auto pakset_name : pakset_tags) { paths.push_back("addons" + std::string(PATH_SEPARATOR) + pakset_name + std::string(PATH_SEPARATOR) + "scenario" + std::string(PATH_SEPARATOR) + this->title); } } } bool workshop_item_t::install(std::string origin) { this->fill_paths(); if (paths.size()) { for (auto path : paths) { fs::create_directories(env_t::user_dir + path); const auto copyOptions = std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive; std::filesystem::copy(origin, env_t::user_dir + path, copyOptions); dbg->message("workshop_item_t::install()", "Installed workshop item %lu from %s to %s", this->id, origin.c_str(), (env_t::user_dir + path).c_str()); } // For other categories we save the full list of files, we will need them when uninstalling to avoid deleting unrelated items if (this->category_tag == "map" || this->category_tag == "addon") { std::vector files; for (auto path : paths) { for (auto const& dir_entry : std::filesystem::directory_iterator{origin}) { files.push_back(env_t::user_dir + path + std::string(PATH_SEPARATOR) + dir_entry.path().filename().string()); } } this->files = files; } else { this->files = paths; } return true; } dbg->error("workshop_item_t::install()", "Could NOT install workshop item %lu: no valid paths!", this->id); return false; } void workshop_item_t::uninstall() { if(files.size()){ for(auto file : files ) { fs::remove_all(file); } } dbg->message("workshop_item_t::uninstall()", "Uninstalled workshop item %lu", this->id); }simutrans-124.3/src/steam/workshop_item.h000066400000000000000000000014611474050137200205200ustar00rootroot00000000000000 #include "isteamugc.h" #include #include class workshop_item_t { private: PublishedFileId_t id; std::string title; std::vector paths; std::vector files; std::string category_tag; std::vector pakset_tags; void fill_paths(); public: workshop_item_t(PublishedFileId_t id, std::vector files); workshop_item_t(PublishedFileId_t id, std::string title); /** * Sets the category tag. It must be "pakset", "scenario", "map", or "addon" * @returns false if it was unable to set category */ bool set_category_tag(std::string tag); bool add_pakset_tag(std::string tag); bool install(std::string origin); void uninstall(); PublishedFileId_t get_id() { return id; }; std::vector get_files() { return files; }; };simutrans-124.3/src/toolkit_text.dat000066400000000000000000000051411474050137200175660ustar00rootroot00000000000000obj=script_toolkit name=Way key %s is not defined. note=messages hm_way_tl - obj=script_toolkit name=No way was detected between %s. note=messages hm_way_tl - obj=script_toolkit name=Selected way %s is not available. note=messages hm_way_tl - obj=script_toolkit name=Way %s (%s) is not found! note=messages hm_way_tl - obj=script_toolkit name=Way building path from ($s) to (%s) is not found! note=messages hm_way_tl - obj=script_toolkit name=Bridge %s (%s) is not found! note==messages hm_bridge_tl - obj=script_toolkit name=Bridge building path from (%s) to (%s) is not found! note==messages hm_bridge_tl - obj=script_toolkit name=Depot key %s is not defined. note==messages hm_depot_tl - obj=script_toolkit name=No depot was detected between %s. note==messages hm_depot_tl - obj=script_toolkit name=Selected depot %s is not available. note==messages hm_depot_tl - obj=script_toolkit name=Depot %s (%s) is not found! note==messages hm_depot_tl - obj=script_toolkit name=No ways were found at %s. note=message hm_remove_tl - obj=script_toolkit name=Sign key %s is not defined. note=message hm_sign_tl - obj=script_toolkit name=No sign was detected between %s. note=message hm_sign_tl - obj=script_toolkit name=Selected sign %s is not available. note=message hm_sign_tl - obj=script_toolkit name=Sign %s (%s) is not found! note=message hm_sign_tl - obj=script_toolkit name=Error constructing signal on tile %s. note=message hm_sign_tl - obj=script_toolkit name=Tile %s is not a valid ground! note=message hm_slope_tl - obj=script_toolkit name=Station key %s is not defined. note=message hm_station_tl - obj=script_toolkit name=No station was detected between %s. note=message hm_station_tl - obj=script_toolkit name=Selected station %s is not available. note=message hm_station_tl - obj=script_toolkit name=Station %s (%s) is not found! note=message hm_station_tl - obj=script_toolkit name=Wayobj key %s is not defined. note=message hm_wayobj_tl - obj=script_toolkit name=No wayobj was detected between %s. note=message hm_wayobj_tl - obj=script_toolkit name=Selected wayobj %s is not available. note=message hm_wayobj_tl - obj=script_toolkit name=Wayobj %s (%s) is not found! note=message hm_wayobj_tl - obj=script_toolkit name=Wayobj building path from ($s) to (%s) is not found! note=message hm_wayobj_tl - obj=script_toolkit name=Selected area not free for build! note=message hm_test_area_tl - obj=script_toolkit name=The terrain is not suitable for construction. note=message hm_test_area_tl - #obj=script_toolkit #name= #note= #- simutrans-124.3/tests/000077500000000000000000000000001474050137200147155ustar00rootroot00000000000000simutrans-124.3/tests/all_tests.nut000066400000000000000000000166251474050137200174510ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // list containing all tests // include("tests/test_building") include("tests/test_city") include("tests/test_climate") include("tests/test_depot") include("tests/test_dir") include("tests/test_factory") include("tests/test_good") include("tests/test_groundobj") include("tests/test_halt") include("tests/test_headquarters") include("tests/test_label") include("tests/test_player") include("tests/test_powerline") include("tests/test_reservation") include("tests/test_scenario") include("tests/test_sign") include("tests/test_slope") include("tests/test_terraform") include("tests/test_transport") include("tests/test_trees") include("tests/test_way_bridge") include("tests/test_way_road") include("tests/test_way_runway") include("tests/test_way_tram") include("tests/test_way_tunnel") include("tests/test_wayobj") all_tests <- [ test_building_build_house_invalid_param, test_building_build_house_random, test_building_build_house_valid_desc, test_building_build_house_invalid_desc, test_building_build_house_auto_rotation_attraction, test_building_build_house_auto_rotation_citybuilding, test_building_build_multi_tile_sloped, test_building_buy_house_invalid_param, test_building_buy_house_from_public_player, test_building_buy_house_attraction, test_building_rotate_house, test_building_rotate_harbour, test_building_rotate_station, test_building_rotate_factory, test_city_add_invalid, test_city_add_cannot_afford, test_city_add_by_public_player, test_city_add_on_existing_townhall, test_city_add_near_map_border, test_city_change_size_invalid_params, test_city_change_size_to_minimum test_climate_invalid, test_climate_flat, test_climate_cliff, test_depot_build_invalid_params, test_depot_build_invalid_pos, test_depot_build_road, test_depot_build_road_on_tram_crossing, test_depot_build_water, test_depot_build_monorail, test_depot_build_tram, test_depot_build_sloped, test_depot_build_on_tunnel_entrance, test_depot_build_on_bridge_end, test_depot_build_on_halt, test_depot_convoy_add_normal, test_depot_convoy_add_nonelectrified, test_dir_is_single, test_dir_is_twoway, test_dir_is_threeway, test_dir_is_curve, test_dir_is_straight, test_dir_double, test_dir_backward, test_dir_to_slope, test_dir_to_coord, test_factory_build_pp, test_factory_build_with_fields, test_factory_build_climate, test_factory_link, test_good_is_interchangeable, test_good_speed_bonus, test_groundobj_build_invalid_param, test_groundobj_build_invalid_pos, test_groundobj_build_random, test_groundobj_build_specific, test_groundobj_build_invalid_climate, test_groundobj_build_ignore_climate, test_groundobj_build_occupied, test_groundobj_build_on_trees, test_groundobj_build_on_slope, test_halt_build_rail_single_tile, test_halt_build_harbour, test_halt_build_flat_dock_near_water, test_halt_build_flat_dock_near_water_multiple_rotations, test_halt_build_flat_dock_near_water_fixed_rotation_valid, test_halt_build_flat_dock_near_water_fixed_rotation_invalid, test_halt_build_flat_dock_outside_map, test_halt_build_flat_dock_near_map_border_auto_rotation, test_halt_build_flat_dock_near_map_border_fixed_rotation test_halt_build_flat_dock_on_bridge, test_halt_build_flat_dock_on_slope, test_halt_build_flat_dock_near_cliff, test_halt_build_flat_dock_in_water, test_halt_build_flat_dock_occupied, test_halt_build_air, test_halt_build_multi_tile, test_halt_build_multi_mode, test_halt_build_multi_player, test_halt_build_separate, test_halt_build_near_factory, test_halt_build_near_factories, test_halt_build_on_tunnel_entrance, test_halt_build_on_bridge_end, test_halt_build_on_depot, test_halt_build_station_invalid_param, test_halt_build_station_extension, test_halt_upgrade_downgrade, test_halt_make_public_single, test_halt_make_public_multi_tile, test_halt_make_public_underground, test_halt_move_stop_invalid_param, test_headquarters_build_flat, test_label, test_player_cash, test_player_isactive, test_player_headquarters, test_player_name, test_player_lines, test_powerline_connect, test_powerline_build_below_powerbridge, test_powerline_build_powerbridge_above_powerline, test_powerline_build_transformer, test_powerline_build_over_transformer, test_powerline_build_transformer_multiple, test_powerline_remove_powerbridge, test_powerline_ways, test_reservation_clear_ground, test_reservation_clear_road, test_reservation_clear_rail, test_scenario_rules_allow_forbid_tool, test_scenario_rules_allow_forbid_way_tool_rect, test_scenario_rules_allow_forbid_way_tool_cube, test_scenario_rules_allow_forbid_tool_stacked_rect, test_scenario_rules_allow_forbid_tool_stacked_cube, test_sign_build_oneway, test_sign_build_trafficlight, test_sign_remove_trafficlight, test_sign_build_private_way, test_sign_build_signal, test_sign_build_signal_multiple, test_sign_replace_signal, test_sign_signal_when_player_removed, test_slope_to_dir, test_slope_can_set, test_slope_set_and_restore, test_slope_get_price, test_slope_set_near_map_border, test_slope_restore_on_foundation, test_slope_restore_on_bridge, test_slope_restore_on_label, test_slope_max_height_diff, test_terraform_raise_lower_land, test_terraform_raise_lower_land_at_map_border, test_terraform_raise_lower_land_at_water_center, test_terraform_raise_lower_land_at_water_corner, test_terraform_raise_lower_land_at_water_edge, test_terraform_raise_lower_land_below_way, test_terraform_raise_lower_water_level, test_transport_generate_pax_invalid_pos, test_transport_generate_pax_walked, test_transport_generate_pax_no_route, test_transport_pax_valid_route, test_transport_mail_valid_route, test_transport_freight_valid_route, test_trees_plant_single_invalid_pos, test_trees_plant_single_invalid_param, test_trees_plant_single_null_param, test_trees_plant_single_empty_param, test_trees_plant_single_invalid_desc, test_trees_plant_single_when_disabled, test_trees_plant_single_random_age, test_trees_plant_single_ignore_climate, test_trees_plant_single_max_per_square, test_trees_plant_single_occupied, test_trees_plant_forest, test_way_bridge_build_ground, test_way_bridge_build_at_slope, test_way_bridge_build_at_slope_stacked, test_way_bridge_build_above_way, test_way_bridge_build_above_runway, test_way_bridge_planner, test_way_road_build_single_tile, test_way_road_build_straight, test_way_road_build_bend, test_way_road_build_parallel, test_way_road_build_below_powerline, test_way_road_build_crossing, test_way_road_upgrade_crossing, test_way_road_upgrade_downgrade, test_way_road_upgrade_downgrade_across_bridge, test_way_road_cityroad_build, test_way_road_cityroad_upgrade_with_cityroad, test_way_road_cityroad_downgrade_with_cityroad, test_way_road_cityroad_replace_by_normal_road, test_way_road_cityroad_replace_keep_existing, test_way_road_has_double_slopes, test_way_road_make_public, test_way_runway_build_rw_flat, test_way_runway_build_tw_flat, test_way_runway_build_mixed_flat, test_way_tram_build_flat, test_way_tram_build_parallel, test_way_tram_build_on_road, test_way_tram_build_across_road_bridge, test_way_tram_build_across_crossing, test_way_tram_build_in_tunel, test_way_tram_has_double_slopes, test_way_tunnel_build_straight, test_way_tunnel_build_up_down, test_way_tunnel_make_public, test_wayobj_build_straight, test_wayobj_build_disconnected, test_wayobj_upgrade_downgrade, test_wayobj_electrify_depot ] simutrans-124.3/tests/empty-16x16.sve000066400000000000000000000072671474050137200173710ustar00rootroot00000000000000‹íÚ TN{¿ÀñÝäIB†JIåÈ*:¥(œâ$'ê8J) ’¡(*%™RŠN’9³FEÒ¡CD†ÄÉÔDˆÔÛ€{λîû®»Ö½÷Ü»Þ÷ûyÖÞ¿ßþÿþÿýü÷ÿÙÏZ{=ë±^°p‰¯Ã¢ÅêÚÃuFŒ®3ÌËÁ]FN„¾B;s±ö(ýéXªekmjjnnþÔ$ìØÞêž‘dK.×Võ´ÅÛŠMÍŸ_2Âß¿,Æ÷ì*-¼‘ ·Ú:·Ô²õü´µÚÜòn—[¢SÛ¤ä„)mSê h÷t4ZÚ´%…ŽÂ¼¾Ëðñtpj)'Ìóttôp^ìë¹È¹­Uvvt¤ŒàâàçìÑv|Ù&:²£à´ÀÇ·íP¢#%YÁa±—«ƒG{Û^»Öéüý‰¦M„? ã ][š¡H$ZVG\p^$&&ü‘öç$B$ Ói«éT‰ÎwQh»hÿ¤ãÿHúºåŽ4·Ù%ßÏÏkêÚbQDûñÜåMŠÚ’íÑK«±-þ>ç][¬)iï/—ú±ý|uíu!~ÄÃÖä_ö§~ŸÏ÷yüçói·6|šìçy¶.NëªthÙº¶l2Bû­×š+µ.–xëíÕroˆkëè´n½çÚ–´5Ñ ·YLJRX#è¨úH$ÛîGí–3K6ÿ’‚ަ¨íÍ¥/¶|š#¥å Bûþ_ÙkY÷•­ó‘øtƒZæüùÊÅŒÕÚ.å}kwII1õ×âŸÆH·vÉWè¶ßÌ·~SÁó_NŒÚVš±ë‘ÔýûÇüô|½VòŠÑÑ›<¾(¿»<>FÉùªddÓ-K¿æß„»-,mèzÊãáûi•µs—/ét~^iW;k½3'Ì+*Ö»ÌX¤ûöbÔüo¢rלÞjj}pÛÑüé^6ÇVÖËv­²QKÝ.Ä>]r;Âà¥Ì‰­9ß/{­¸tƒóÉß)$ûåW…‹,§º®P³s=U!7¸W—?›URæn¢ûj¼}¦TʸCƒ§-©j¬ÊÙp®V^JézßÛ÷>Hkù} w]vç¥ìKcÃÙ> K›¾Î»Þb°âÂÍcCÌÇ„_1p²ïeÜ>=³§(ÏÿþµóÛ/­WSw6¹Ó™ccU´fˆR.NŽÑ»¿_ÊDÑѰl~éÝj™/'{ÏrÒ‘PÛ¬µ.ɪ›ï ?Åå^n;#i÷Z|èµIv`Èø¸Ä[ö¯zÚ.?y[Ëþ»uWTìÛ™;v´`´Ô³4¨ƒ¯Êâ|ËçþIÓ¿Ýü"øÈØ•«v§½×PÍL˜+ûº²Ïó©oœƒG7zäp§sÒ̲ËóßFõ•±µë©èX_S[~té×ì‚jV+ØÆ”ª{Ù½îÄOç”Öôj8¸ë°]]×’çåþ*¹¶zûuÕmÖ ‰cæ:Ì,Zü!±`vß8õúüüsSÌn‰Æ~µtwâ®Ýó­¿½ÿG«¤”Ûša+Šîå$:Wd™šÖ¯ï\d\u@fÆñÊÒ_Ë·ªùÅîò¿dØŒƒÒ2=ÄÕ„øÃ϶ÄûÚgžqa·ä”ä‘™û¤ß¾zºPíbüe­Õýi;§Ç&ÉÜ ¥Ð#dåêŠ9šù) N—Ư}WT±Ý? ÓÀ½({ØÙ·iåi67¾Íšh8|½E£Ø-{ÿ;ìˆ8w» ®þ—ï |{n\ãEi½' ½U|ÃÓíEþuñêϾw7QmêP{ªPä~¹v›(ñç1'#Vg¼º^ã:÷ε5áw"4êó6ˆ»EÞÖÙ¹z­ø‰þjÖ}^ùfû(Î[zúMcÐìD»7 ~5Ðwã1•ʃ«Ò_|Hµü~†K¾e*ï,»¸v|"oXêmž6,Ïxøö†Yƒ…ºü3Þö«^ ÞÑl1qÖÁM§Ò|ÝuîfÎ8 !Êp^(ˆÞY­ÑÌ—,göƒ³gÝ NÏžÝï¬_5ä@vc眭ú ÊÑ™»ÄU–ÏQ‹q‰Zó䧇_Ÿý½ÜìG.»ßPØtlMz©­dì³GV£ßúºèYüV¤. IªVÝvxìì«O^Ïíf5½^ÛÉûΕþæ.厶ҥ“ŠR½Í\ÍN×}¦æÑ­Kpjöää÷‡5É>¯:/ž hÑT1öèKë‡w¿ŽKX°®ðd¤CܾêÎþ±1a)oôñ 5Y#i:xžgñ…nœ:û~Ð=7»à>NGö¬—{&öÑÕúp7§ª„ÀõiAo‹öª^[š!Qÿ ãè[I/CnÛþª™Ÿ¿3ôfIIà¨:nARQ6W&Ÿ«x¡iúZ792È|Pø°[m—»ÑG'÷ØsAÔ·{Ÿf‰¡sjÔûhÉÔv¿ÒeÕ>çl›‚=Œî¾ŸtäföÞòø½.J>] oï6з¹Xl—=»]»¯ ;7Ya°LŒ©¡ºÿ›Âù ám ÍÜ&DWvŸÖÁOp‹©Þyi›È»÷ÕÐ\ñªÌ¹y%:šeÊÇfvq_™fc:üqƨ¬…»_ÙlÒ›¾iÁ‰kÏz9ÆÕŠr?\–y±·ß£MZß|÷³¡UõÌCa‹¼¯Gí\#¹ßjÜ蜯VçoŒ±3®:z {A­îb‡Äõû=Ÿ5VŸ3ñ×wïýõñi&…A•Ž#žÉ+†%÷,;ülõq£š‡ÆqY;ûä^È+ñ1P’yh¹uY©Ù#)÷Óþ»™®U,7h‰H0M¿Z´èŽWÃÔóK•Ì«&‹ÈÓœ>”°uÎþ©#ïu·Òwù°aȉ§5¾z[¯t«Ï¨Þ{Cݶk8¯ö{Õ ç¯n¼™#;.Sõƒ£§~yÞÓÞzoÇJŸ êßáë{/ÌççYVœzé°á¿º~ËJêç†_hšvcfÂÉê£QÖÉ.¡ÙçüÄhÕ” *½ÙÙåTåÐs…© NR­¿8=ëÖcÙ5Qõ[R:N÷Ⱦ‘´HÃb²Îö0/Å_U¬²—Xè)?.¢ÏÇëÞÛ~6ïWtàL°R£ÊK…b7ů•µL‰êwÉ$i[¶´Aaέgù…ÓÖ/ötq7UÞ3h‡TÁ¢üªXGe‹^ò?VW®ÞX‘%Qw6iör 󚹪J3ÇW. ³ÜÕ¤1vVr÷H³jûJÃÎOË;±¤óSË‹Í[”Í5ª4Uô¸“}7¡¬özÖ†µ¬lL+ä,œ¢òÑLµÓªž^öOÆfȾžzÊ4àâíÍæG2†z¾NÊÞ_²ºÿoÛÂ߬z'J•šŸâžýq–ä#Ç×Ù]‚ì¬Ó®ieîzÞQ­ÒrºÕî!Ù^O$´Êß´6ʧá¡ú岇['õ1ͯx;õ»ßÄöŽ0-燼 ÷zôOW3º°ß c£UûÚë_3¸:SL'-ÐÓu}mr²ªa½ÚìWõ|×9ê÷0z¼Iwi×™#Ëôç/”Ô˜4¨¡°¸É_w|βÑCÎÏÖ}o»¤«ÁÖ”Þ 3WÜuôxµó‚Lw©ò…Ãã¢W¯×—1ÏxíÔœÿÀtEM¡Ò~ÏøÇ.|p–œtxö¯÷®$I•‡¿¼/1K[zÇǦÝUÃÅlfŠRâŠ/Ž Ò%¡7®ÿ½¢!ï*žŠ:n;y‹³kmƒ”¹¡ÉFÉNá³oÉrX“¥üF%æTŒsͦ`=é{›5%{=wõŒ\á1fƒ§‘®iT|J—1—J~±š4aÝIÓ½ rÔšFYßq:ûķ):÷÷žwf©ZÜÒ¸ÅvHJèæþ™5j§g¤Ê­­ª®Ly^7ýIµÛQÃWĦ[þ®¼q¹¯ŒÉÅÇíƒoÆVçÄ6^ô-Ó]­;S^-xÂ:ƒ²¬õ°ïc ¿É¶­—–r~iƉËÍqCß$†|[“•6Ï!r…YöeG#÷<¿G •én&uøÁ™7Ó2û_yª`a¼iê}çÃgÓNNjÔì:yáâˆry‹µF,õ¯¿ÐôÆeAÕ{=•#ßô¯Þ1 rDÄÇ”þ/ÆTk6:YŠññV< {$@éÓÓ\ËC¾ êÝò'&¼o}lZkIIIIIIIIIIÿÅS‰sÂèõùwÿ6Ÿr%¥N’Ê_ ìðGÔ©S§N:€ÿS:­»æÿ¨CGÁËÃa¹³ú°–®ÒêÂãoš¿t¦#Ö””:I*)ü±Ã}êü%R§þïTçûAú?®ÿUÒ›Ú¾Ÿ#àGºbSs‹/à¿‹ÿ'À_#]±©¹Å—þeé´îþÙ¥/‡åÎ>êÚݤþŸj}lú­Hù1K­‹simutrans-124.3/tests/scenario.nut000066400000000000000000000032621474050137200172530ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // map.file = "empty-16x16.sve" scenario.short_description = "Automated tests" scenario.author = "ceeac" scenario.version = "0.1" // // Includes // include("test_helpers") include("all_tests") // // test runner stuff // local num_tests_done = 0 local num_tests = all_tests.len() local error_msg = null function run_all_tests() { num_tests_done = 0 error_msg = null print("============================================================") print("== Running tests ... =======================================") print("============================================================") foreach (i,test_func in all_tests) { local func_name = test_func.getinfos().name print("[" + (num_tests_done+1) + "/" + num_tests + "] " + func_name) test_func() // run the test ++num_tests_done } print("Tests completed successfully.") } // // Required for scenario // function get_rule_text(pl) { return ttext("Don't touch.") } function get_goal_text(pl) { return ttext("Wait for all tests to pass.") } function get_info_text(pl) { if (error_msg != null) { // an error ocurred return error_msg } local msg = ttext("{ndone}/{ntests} completed.") msg.ndone = num_tests_done msg.ntests = num_tests return msg } function get_result_text(pl) { return get_info_text(pl) } function is_tool_allowed(pl, tool_id, wt, name) { return true } function start() { run_all_tests() } function resume_game() { run_all_tests() } function is_scenario_completed(pl) { if (error_msg != null) { return -1 } else if (num_tests == 0) { return 100 } return (100*num_tests_done) / num_tests } simutrans-124.3/tests/test_helpers.nut000066400000000000000000000101141474050137200201430ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Test helpers // function make_assertion_str(val) { if (typeof val == "string") { return "\"" + val + "\"" } else { return "" + val } } function ASSERT_EQUAL(act, exp) { if (!(act == exp)) { local err = ttext("Assertion failed, '{act} == {exp}' was not true") err.act = make_assertion_str(act) err.exp = make_assertion_str(exp) throw err.tostring() } } function ASSERT_LESS(lhs, rhs) { if (!(lhs < rhs)) { local err = ttext("Assertion failed, '{lhs} < {rhs}' was not true") err.lhs = make_assertion_str(lhs) err.rhs = make_assertion_str(rhs) throw err.tostring() } } function ASSERT_GREATER(lhs, rhs) { if (!(lhs > rhs)) { local err = ttext("Assertion failed, '{lhs} > {rhs}' was not true") err.lhs = make_assertion_str(lhs) err.rhs = make_assertion_str(rhs) throw err.tostring() } } function ASSERT_TRUE(a) { if (!(a == true)) { local err = ttext("Assertion failed, '{a}' was not true") err.a = make_assertion_str(a) throw err.tostring() } } function ASSERT_FALSE(a) { if (!(a == false)) { local err = ttext("Assertion failed, '{a}' was not false") err.a = make_assertion_str(a) throw err.tostring() } } // Set player funds (incl. non-cash assets) to some specific amount (in credit-cents) function SET_PLAYER_FUNDS(pl, amount) { pl.book_cash(amount - pl.get_current_net_wealth()) } function RESET_ALL_PLAYER_FUNDS() { local default_cash = 200000 * 100 for (local i = 0; i < 8; ++i) { local pl = player_x(i) if (pl.is_valid()) { ASSERT_EQUAL(pl.get_current_maintenance(), 0) SET_PLAYER_FUNDS(pl, default_cash) } } } function char_to_dir(ch) { switch (ch) { case '.': return dir.none // '.' == dontcare case '0': return dir.none case '1': return dir.north case '2': return dir.east case '3': return dir.northeast case '4': return dir.south case '5': return dir.northsouth case '6': return dir.southeast case '7': return dir.northsoutheast case '8': return dir.west case '9': return dir.northwest case 'A': return dir.eastwest case 'B': return dir.northeastwest case 'C': return dir.southwest case 'D': return dir.northsouthwest case 'E': return dir.southeastwest case 'F': return dir.all } ASSERT_TRUE(false) // should not reach here } function ASSERT_WAY_PATTERN(waytype, lefttop, pattern) { local z = lefttop.z for (local y = 0; y < pattern.len(); ++y) { for (local x = 0; x < pattern[y].len(); ++x) { local tile = square_x(lefttop.x + x, lefttop.y + y).get_tile_at_height(z) local expected_dir = char_to_dir(pattern[y][x]) if (tile != null) { local actual_dir = 0 if (waytype != wt_power) { actual_dir = tile.get_way_dirs(waytype) } else { // powerlines connect to other powerlines automatically. local powerline = tile.find_object(mo_powerline) actual_dir = 0 if (powerline) { for (local i = 0; i < 4; ++i) { local offset = dir.to_coord(1< 0; --h) { for (local y = 0; y < 3; ++y) { for (local x = 0; x < 3; ++x) { ASSERT_EQUAL(setslope(pl, pos + coord3d(x, y, h), slope.all_down_slope), null) } } } ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(15, 15, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_depot.nut000066400000000000000000000524051474050137200207670ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for depots // function test_depot_build_invalid_params() { local pl = player_x(0) local public_pl = player_x(1) // invalid default_param { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_depot).work(pl, coord3d(0, 0, 0), null), "") } catch (e) { error_caught = true; ASSERT_EQUAL(e, "Error during initializing tool") } local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_depot).work(pl, coord3d(0, 0, 0), ""), "") } catch (e) { error_caught = true; ASSERT_EQUAL(e, "Error during initializing tool") } local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_depot).work(pl, coord3d(0, 0, 0), "nonexistent"), "") } catch (e) { error_caught = true; ASSERT_EQUAL(e, "Error during initializing tool") } } // build as public player { local error_caught = false try { command_x.build_depot(public_pl, coord3d(0, 0, 0), get_depot_by_wt(wt_road)) } catch (e) { error_caught = true; ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_road).len(), 0) } RESET_ALL_PLAYER_FUNDS() } function test_depot_build_invalid_pos() { local pl = player_x(0) local public_pl = player_x(1) local road_depot = get_depot_by_wt(wt_road) local hangar = get_depot_by_wt(wt_air) local shipyard = get_depot_by_wt(wt_water) local runway_desc = way_desc_x.get_available_ways(wt_air, st_elevated)[0] local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local road_descs = way_desc_x.get_available_ways(wt_road, st_flat) local rail_descs = way_desc_x.get_available_ways(wt_rail, st_flat) road_descs.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) rail_descs.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) local road_desc = road_descs[0] local rail_desc = rail_descs[0] ASSERT_TRUE(runway_desc != null) ASSERT_TRUE(road_desc != null) ASSERT_TRUE(rail_desc != null) // invalid pos { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(-1, -1, 0), road_depot), "") } // no shipyards on land { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), shipyard), "Ship depots must be built on water!") } // no land depots on water { ASSERT_EQUAL(command_x(tool_set_climate).work(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), hangar), "Depots must be built on flat dead-end way tiles!") ASSERT_EQUAL(command_x(tool_set_climate).work(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) } // no hangars on runways { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 5, 0), coord3d(5, 7, 0), runway_desc, true), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 5, 0), hangar), "Depots cannot be built on runways!") ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 5, 0), coord3d(5, 7, 0), "" + wt_air), null) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) // no depot in the middle of a road { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 3, 0), road_depot), "Depots must be built on flat dead-end way tiles!") } // no depot over a stop { ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 2, 0), station_desc, 0), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), road_depot), "Tile not empty.") ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) } // do not replace existing depots { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), road_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), road_depot), "Tile not empty.") ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), road_desc, true), null) // no depot on road-road crossings { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 3, 0), road_depot), "Depots must be built on flat dead-end way tiles!") } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), rail_desc, true), null) // no depot on road-rail crossings { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 3, 0), road_depot), "Tile not empty.") } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_road() { local pl = player_x(0) local public_pl = player_x(1) local default_depot = get_depot_by_wt(wt_road) local way_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] // preconditions ASSERT_TRUE(default_depot != null) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_road).len(), 0) ASSERT_TRUE(way_desc != null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(3, 3, 0), coord3d(5, 3, 0), way_desc, true), null) // build depot as normal player, all 4 directions { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 4, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 0), default_depot), null) ASSERT_EQUAL(depot_x.get_depot_list(player_x(0), wt_road).len(), 4) ASSERT_TRUE(depot_x(4, 2, 0).is_valid()) ASSERT_TRUE(depot_x(5, 3, 0).is_valid()) ASSERT_TRUE(depot_x(4, 4, 0).is_valid()) ASSERT_TRUE(depot_x(3, 3, 0).is_valid()) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_road_on_tram_crossing() { local pl = player_x(0) local public_pl = player_x(1) local default_depot = get_depot_by_wt(wt_road) local way_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local tramtrack = way_desc_x.get_available_ways(wt_rail, st_tram)[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 2, 0), coord3d(4, 2, 0), tramtrack, true), null) { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), default_depot), "Tile not empty.") } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 2, 0), coord3d(4, 2, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_water() { local pl = player_x(0) local public_pl = player_x(1) local default_depot = get_depot_by_wt(wt_water) // preconditions ASSERT_TRUE(default_depot != null) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_water).len(), 0) ASSERT_EQUAL(command_x(tool_set_climate).work(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) // build depot as normal player { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), default_depot), null) ASSERT_EQUAL(depot_x.get_depot_list(player_x(0), wt_water).len(), 1) ASSERT_TRUE(depot_x(4, 2, 0).is_valid()) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_set_climate).work(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_monorail() { local pl = player_x(0) local public_pl = player_x(1) local default_depot = get_depot_by_wt(wt_monorail) local way_desc = way_desc_x.get_available_ways(wt_monorail, st_flat)[0] local elevated_monorail = way_desc_x.get_available_ways(wt_monorail, st_elevated)[0] // preconditions ASSERT_TRUE(default_depot != null) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_monorail).len(), 0) ASSERT_TRUE(way_desc != null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(3, 3, 0), coord3d(5, 3, 0), way_desc, true), null) // build depot as normal player, all 4 directions { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 4, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 0), default_depot), null) ASSERT_EQUAL(depot_x.get_depot_list(player_x(0), wt_monorail).len(), 4) ASSERT_TRUE(depot_x(4, 2, 0).is_valid()) ASSERT_TRUE(depot_x(5, 3, 0).is_valid()) ASSERT_TRUE(depot_x(4, 4, 0).is_valid()) ASSERT_TRUE(depot_x(3, 3, 0).is_valid()) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_monorail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), "" + wt_monorail), null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), elevated_monorail, true), null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(3, 3, 0), coord3d(5, 3, 0), elevated_monorail, true), null) // build elevated monorail depot, with foundation, all 4 directions { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 1), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 1), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 4, 1), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 1), default_depot), null) ASSERT_EQUAL(depot_x.get_depot_list(player_x(0), wt_monorail).len(), 4) ASSERT_TRUE(depot_x(4, 2, 1).is_valid()) ASSERT_TRUE(depot_x(5, 3, 1).is_valid()) ASSERT_TRUE(depot_x(4, 4, 1).is_valid()) ASSERT_TRUE(depot_x(3, 3, 1).is_valid()) ASSERT_FALSE(square_x(4, 2).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(5, 3).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(4, 4).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(3, 3).get_tile_at_height(0).is_empty()) // This leaves behind the depot foundations ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 1)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 1)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 4, 1)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 1)), null) } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 1), coord3d(4, 4, 1), "" + wt_monorail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 1), coord3d(5, 3, 1), "" + wt_monorail), null) ASSERT_FALSE(square_x(4, 2).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(5, 3).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(4, 4).get_tile_at_height(0).is_empty()) ASSERT_FALSE(square_x(3, 3).get_tile_at_height(0).is_empty()) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) // clean up RESET_ALL_PLAYER_FUNDS() } function test_depot_build_tram() { local pl = player_x(0) local public_pl = player_x(1) local default_depot = get_depot_by_wt(wt_tram) local way_desc = way_desc_x.get_available_ways(wt_rail, st_tram)[0] // preconditions ASSERT_TRUE(default_depot != null) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_tram).len(), 0) ASSERT_TRUE(way_desc != null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(3, 3, 0), coord3d(5, 3, 0), way_desc, true), null) // build depot as normal player, all 4 directions { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 4, 0), default_depot), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 0), default_depot), null) ASSERT_EQUAL(depot_x.get_depot_list(player_x(0), wt_tram).len(), 4) ASSERT_TRUE(depot_x(4, 2, 0).is_valid()) ASSERT_TRUE(depot_x(5, 3, 0).is_valid()) ASSERT_TRUE(depot_x(4, 4, 0).is_valid()) ASSERT_TRUE(depot_x(3, 3, 0).is_valid()) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) // note: wt_tram does not work ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_sloped() { local pl = player_x(0) local setslope = command_x.set_slope local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local wayremover = command_x(tool_remove_way) local pos = coord3d(4, 3, 0) { for (local sl = slope.flat+1; sl < slope.raised; ++sl) { ASSERT_EQUAL(setslope(pl, pos, sl), null) local d = slope.to_dir(sl) if (d != dir.none) { // only consider slopes we can build roads on RESET_ALL_PLAYER_FUNDS() local c = dir.to_coord(dir.backward(d)) local adjacent = pos + coord3d(c.x, c.y, 0) ASSERT_EQUAL(command_x.build_way(pl, adjacent, pos, road, true), null) local old_maintenance = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_depot(pl, pos, get_depot_by_wt(wt_road)), "Depots must be built on flat dead-end way tiles!") ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) ASSERT_EQUAL(tile_x(pos.x, pos.y, pos.z).find_object(mo_building), null) ASSERT_EQUAL(wayremover.work(pl, pos, adjacent, "" + wt_road), null) } } } // clean up ASSERT_EQUAL(setslope(pl, pos, slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_on_tunnel_entrance() { local pl = player_x(0) local rail_tunnel = tunnel_desc_x.get_available_tunnels(wt_rail)[0] ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(4, 1, 0), rail_tunnel.get_name()), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(3, 2, 0), rail_tunnel.get_name()), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(5, 2, 0), rail_tunnel.get_name()), null) // Building depots on tunnel entrance works (contrary to stations) { for (local d = dir.north; d < dir.all; d = d*2) { local p = coord3d(4, 2, 0) + dir.to_coord(d) ASSERT_EQUAL(command_x.build_depot(pl, p, get_depot_by_wt(wt_rail)), null) } } local remover = command_x(tool_remover) remover.set_flags(2) ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0)), null) ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0)), null) ASSERT_EQUAL(remover.work(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(remover.work(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(remover.work(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_build_on_bridge_end() { local pl = player_x(0) local rail_bridge = bridge_desc_x.get_available_bridges(wt_rail)[0] local setslope = command_x.set_slope // north-south direction { ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.north), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(4, 2, 0), rail_bridge.get_name()), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 4, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.flat), null) } // east-west direction { ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.east), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 0), slope.west), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(3, 3, 0), rail_bridge.get_name()), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 0), slope.flat), null) } RESET_ALL_PLAYER_FUNDS() } function test_depot_build_on_halt() { local pl = player_x(0) local rail_desc = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x.passenger)[0] local depot = get_depot_by_wt(wt_rail) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), rail_desc, true), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 2, 0), station_desc), null) { ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), depot), "Tile not empty.") } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_convoy_add_normal() { // build depot local pl = player_x(0) local public_pl = player_x(1) local way_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_EQUAL(command_x.build_way(public_pl, coord3d(0, 0, 0), coord3d(0, 1, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(0, 0, 0), get_depot_by_wt(wt_road)), null) ASSERT_EQUAL(depot_x.get_depot_list(pl, wt_road).len(), 1) local the_depot = depot_x.get_depot_list(pl, wt_road)[0] ASSERT_EQUAL(the_depot.get_convoy_list().len(), 0) local vehicle_desc = vehicle_desc_x.get_available_vehicles(wt_road)[0] ASSERT_TRUE(vehicle_desc != null) { ASSERT_TRUE(the_depot.append_vehicle(pl, convoy_x(0), vehicle_desc)) ASSERT_EQUAL(the_depot.get_convoy_list().len(), 1) local cnv = the_depot.get_convoy_list()[0] ASSERT_EQUAL(cnv.get_vehicles().len(), 1) ASSERT_EQUAL(cnv.get_pos().tostring(), coord3d(0, 0, 0).tostring()) ASSERT_EQUAL(cnv.get_pos().tostring(), cnv.get_home_depot().tostring()) ASSERT_EQUAL(cnv.get_speed(), 0) ASSERT_EQUAL(cnv.get_traveled_distance()[0], 0) ASSERT_EQUAL(cnv.get_distance_traveled_total(), 0) ASSERT_TRUE(cnv.is_in_depot()) ASSERT_FALSE(cnv.is_waiting()) ASSERT_EQUAL(cnv.get_line(), null) ASSERT_TRUE(cnv.destroy(player_x(0))) ASSERT_EQUAL(the_depot.get_convoy_list().len(), 0) } // clean up local remover = command_x(tool_remover) ASSERT_EQUAL(remover.work(player_x(1), tile_x(0, 0, 0)), null) ASSERT_EQUAL(remover.work(player_x(1), tile_x(0, 0, 0)), null) ASSERT_EQUAL(remover.work(player_x(1), tile_x(0, 1, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_depot_convoy_add_nonelectrified() { local pl = player_x(0) local way_desc = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local electro_loco = vehicle_desc_x.get_available_vehicles(wt_rail).filter(@(idx, v) ( v.needs_electrification() && v.can_be_first() ))[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), get_depot_by_wt(wt_rail)), null) local the_depot = depot_x(4, 2, 0) { ASSERT_TRUE(the_depot.append_vehicle(pl, convoy_x(0), electro_loco)) // can add loco via script even if depot is not electrified ASSERT_EQUAL(the_depot.get_convoy_list().len(), 1) local cnv = the_depot.get_convoy_list()[0] ASSERT_EQUAL(cnv.get_vehicles().len(), 1) ASSERT_EQUAL(cnv.get_pos().tostring(), coord3d(4, 2, 0).tostring()) ASSERT_TRUE(cnv.destroy(pl)) } ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_dir.nut000066400000000000000000000201071474050137200204240ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for dir/coord // function test_dir_is_single() { ASSERT_FALSE(dir.is_single(dir.none)) ASSERT_TRUE(dir.is_single(dir.north)) ASSERT_TRUE(dir.is_single(dir.east)) ASSERT_TRUE(dir.is_single(dir.south)) ASSERT_TRUE(dir.is_single(dir.west)) ASSERT_FALSE(dir.is_single(dir.northeast)) ASSERT_FALSE(dir.is_single(dir.northsouth)) ASSERT_FALSE(dir.is_single(dir.northwest)) ASSERT_FALSE(dir.is_single(dir.southeast)) ASSERT_FALSE(dir.is_single(dir.eastwest)) ASSERT_FALSE(dir.is_single(dir.southwest)) ASSERT_FALSE(dir.is_single(dir.northsoutheast)) ASSERT_FALSE(dir.is_single(dir.northeastwest)) ASSERT_FALSE(dir.is_single(dir.northsouthwest)) ASSERT_FALSE(dir.is_single(dir.southeastwest)) ASSERT_FALSE(dir.is_single(dir.all)) } function test_dir_is_twoway() { ASSERT_FALSE(dir.is_twoway(dir.none)) ASSERT_FALSE(dir.is_twoway(dir.north)) ASSERT_FALSE(dir.is_twoway(dir.east)) ASSERT_FALSE(dir.is_twoway(dir.south)) ASSERT_FALSE(dir.is_twoway(dir.west)) ASSERT_TRUE(dir.is_twoway(dir.northeast)) ASSERT_TRUE(dir.is_twoway(dir.northsouth)) ASSERT_TRUE(dir.is_twoway(dir.northwest)) ASSERT_TRUE(dir.is_twoway(dir.southeast)) ASSERT_TRUE(dir.is_twoway(dir.eastwest)) ASSERT_TRUE(dir.is_twoway(dir.southwest)) ASSERT_FALSE(dir.is_twoway(dir.northsoutheast)) ASSERT_FALSE(dir.is_twoway(dir.northeastwest)) ASSERT_FALSE(dir.is_twoway(dir.northsouthwest)) ASSERT_FALSE(dir.is_twoway(dir.southeastwest)) ASSERT_FALSE(dir.is_twoway(dir.all)) } function test_dir_is_threeway() { ASSERT_FALSE(dir.is_threeway(dir.none)) ASSERT_FALSE(dir.is_threeway(dir.north)) ASSERT_FALSE(dir.is_threeway(dir.east)) ASSERT_FALSE(dir.is_threeway(dir.south)) ASSERT_FALSE(dir.is_threeway(dir.west)) ASSERT_FALSE(dir.is_threeway(dir.northeast)) ASSERT_FALSE(dir.is_threeway(dir.northsouth)) ASSERT_FALSE(dir.is_threeway(dir.northwest)) ASSERT_FALSE(dir.is_threeway(dir.southeast)) ASSERT_FALSE(dir.is_threeway(dir.eastwest)) ASSERT_FALSE(dir.is_threeway(dir.southwest)) ASSERT_TRUE(dir.is_threeway(dir.northsoutheast)) ASSERT_TRUE(dir.is_threeway(dir.northeastwest)) ASSERT_TRUE(dir.is_threeway(dir.northsouthwest)) ASSERT_TRUE(dir.is_threeway(dir.southeastwest)) ASSERT_TRUE(dir.is_threeway(dir.all)) } function test_dir_is_curve() { ASSERT_FALSE(dir.is_curve(dir.none)) ASSERT_FALSE(dir.is_curve(dir.north)) ASSERT_FALSE(dir.is_curve(dir.east)) ASSERT_FALSE(dir.is_curve(dir.south)) ASSERT_FALSE(dir.is_curve(dir.west)) ASSERT_TRUE(dir.is_curve(dir.northeast)) ASSERT_FALSE(dir.is_curve(dir.northsouth)) ASSERT_TRUE(dir.is_curve(dir.northwest)) ASSERT_TRUE(dir.is_curve(dir.southeast)) ASSERT_FALSE(dir.is_curve(dir.eastwest)) ASSERT_TRUE(dir.is_curve(dir.southwest)) ASSERT_FALSE(dir.is_curve(dir.northsoutheast)) ASSERT_FALSE(dir.is_curve(dir.northeastwest)) ASSERT_FALSE(dir.is_curve(dir.northsouthwest)) ASSERT_FALSE(dir.is_curve(dir.southeastwest)) ASSERT_FALSE(dir.is_curve(dir.all)) } function test_dir_is_straight() { ASSERT_FALSE(dir.is_straight(dir.none)) ASSERT_TRUE(dir.is_straight(dir.north)) ASSERT_TRUE(dir.is_straight(dir.east)) ASSERT_TRUE(dir.is_straight(dir.south)) ASSERT_TRUE(dir.is_straight(dir.west)) ASSERT_FALSE(dir.is_straight(dir.northeast)) ASSERT_TRUE(dir.is_straight(dir.northsouth)) ASSERT_FALSE(dir.is_straight(dir.northwest)) ASSERT_FALSE(dir.is_straight(dir.southeast)) ASSERT_TRUE(dir.is_straight(dir.eastwest)) ASSERT_FALSE(dir.is_straight(dir.southwest)) ASSERT_FALSE(dir.is_straight(dir.northsoutheast)) ASSERT_FALSE(dir.is_straight(dir.northeastwest)) ASSERT_FALSE(dir.is_straight(dir.northsouthwest)) ASSERT_FALSE(dir.is_straight(dir.southeastwest)) ASSERT_FALSE(dir.is_straight(dir.all)) } function test_dir_double() { ASSERT_EQUAL(dir.double(dir.none), dir.none) ASSERT_EQUAL(dir.double(dir.north), dir.northsouth) ASSERT_EQUAL(dir.double(dir.east), dir.eastwest) ASSERT_EQUAL(dir.double(dir.south), dir.northsouth) ASSERT_EQUAL(dir.double(dir.west), dir.eastwest) ASSERT_EQUAL(dir.double(dir.northeast), dir.none) ASSERT_EQUAL(dir.double(dir.northsouth), dir.northsouth) ASSERT_EQUAL(dir.double(dir.northwest), dir.none) ASSERT_EQUAL(dir.double(dir.southeast), dir.none) ASSERT_EQUAL(dir.double(dir.eastwest), dir.eastwest) ASSERT_EQUAL(dir.double(dir.southwest), dir.none) ASSERT_EQUAL(dir.double(dir.northsoutheast), dir.none) ASSERT_EQUAL(dir.double(dir.northeastwest), dir.none) ASSERT_EQUAL(dir.double(dir.northsouthwest), dir.none) ASSERT_EQUAL(dir.double(dir.southeastwest), dir.none) ASSERT_EQUAL(dir.double(dir.all), dir.none) } function test_dir_backward() { ASSERT_EQUAL(dir.backward(dir.none), dir.all) ASSERT_EQUAL(dir.backward(dir.north), dir.south) ASSERT_EQUAL(dir.backward(dir.east), dir.west) ASSERT_EQUAL(dir.backward(dir.south), dir.north) ASSERT_EQUAL(dir.backward(dir.west), dir.east) ASSERT_EQUAL(dir.backward(dir.northeast), dir.southwest) ASSERT_EQUAL(dir.backward(dir.northsouth), dir.northsouth) ASSERT_EQUAL(dir.backward(dir.northwest), dir.southeast) ASSERT_EQUAL(dir.backward(dir.southeast), dir.northwest) ASSERT_EQUAL(dir.backward(dir.eastwest), dir.eastwest) ASSERT_EQUAL(dir.backward(dir.southwest), dir.northeast) ASSERT_EQUAL(dir.backward(dir.northsoutheast), dir.west) ASSERT_EQUAL(dir.backward(dir.northeastwest), dir.south) ASSERT_EQUAL(dir.backward(dir.northsouthwest), dir.east) ASSERT_EQUAL(dir.backward(dir.southeastwest), dir.north) ASSERT_EQUAL(dir.backward(dir.all), dir.none) } function test_dir_to_slope() { ASSERT_EQUAL(dir.to_slope(dir.none), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.north), slope.south) ASSERT_EQUAL(dir.to_slope(dir.east), slope.west) ASSERT_EQUAL(dir.to_slope(dir.south), slope.north) ASSERT_EQUAL(dir.to_slope(dir.west), slope.east) ASSERT_EQUAL(dir.to_slope(dir.northeast), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.northsouth), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.northwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.southeast), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.eastwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.southwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.northsouthwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.northeastwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.northsouthwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.southeastwest), slope.flat) ASSERT_EQUAL(dir.to_slope(dir.all), slope.flat) local error_raised = false try { // out-of-range dir: ANDed with dir.all ASSERT_EQUAL(dir.to_slope(0x2A), dir.to_slope(0x0A)) } catch (e) { error_raised = true; } ASSERT_FALSE(error_raised) } function test_dir_to_coord() { ASSERT_EQUAL(dir.to_coord(dir.none).tostring(), coord( 0, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.north).tostring(), coord( 0, -1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.east).tostring(), coord( 1, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.south).tostring(), coord( 0, 1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.west).tostring(), coord(-1, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northeast).tostring(), coord( 1, -1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northsouth).tostring(), coord( 0, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.southeast).tostring(), coord( 1, 1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northwest).tostring(), coord(-1, -1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.eastwest).tostring(), coord( 0, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.southwest).tostring(), coord(-1, 1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northsouthwest).tostring(), coord(-1, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.southeastwest).tostring(), coord( 0, 1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northsoutheast).tostring(), coord( 1, 0).tostring()) ASSERT_EQUAL(dir.to_coord(dir.northeastwest).tostring(), coord( 0, -1).tostring()) ASSERT_EQUAL(dir.to_coord(dir.all).tostring(), coord( 0, 0).tostring()) local error_raised = false try { dir.to_coord(42) // out-of-range dir } catch (e) { ASSERT_EQUAL(e, "Invalid dir 42 (valid values are 0..15)") error_raised = true } ASSERT_TRUE(error_raised) } simutrans-124.3/tests/tests/test_factory.nut000066400000000000000000000275211474050137200213240ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for factories / factory links // function build_factory(pl, pos, ignore_climates, rotation, base_prod, name) { local factory_builder = command_x(tool_build_factory) return factory_builder.work(pl, pos, "" + ignore_climates.tointeger() + rotation + base_prod + "," + name) } function test_factory_build_pp() { local pl = player_x(0) local public_pl = player_x(1) { // FIXME Causes signed integer overflow even though < 2^30 // local production = 1024 * 1000 * 1000 local production = 1024 // 1/s ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), 0, 1, production, "Aufwindkraftwerk"), null) local factory = factory_x(3, 4) ASSERT_TRUE(factory_x(5, 6) != null) ASSERT_EQUAL(factory_list_x().get_count(), 1) local desc = factory.get_desc(); ASSERT_TRUE(desc != null) ASSERT_EQUAL(desc.get_name(), "Aufwindkraftwerk") // FIXME Max electricity production for PPs not queryable via script? ASSERT_EQUAL(factory.get_consumers().len(), 0) ASSERT_EQUAL(factory.get_suppliers().len(), 0) ASSERT_EQUAL(factory.get_production()[0], 0) ASSERT_EQUAL(factory.get_power()[0], 0) ASSERT_EQUAL(factory.get_boost_electric()[0], 0) ASSERT_EQUAL(factory.get_boost_pax()[0], 0) ASSERT_EQUAL(factory.get_boost_mail()[0], 0) ASSERT_EQUAL(factory.get_pax_generated()[0], 0) ASSERT_EQUAL(factory.get_pax_departed()[0], 0) ASSERT_EQUAL(factory.get_pax_arrived()[0], 0) ASSERT_EQUAL(factory.get_mail_generated()[0], 0) ASSERT_EQUAL(factory.get_tile_list().len(), 3 * 3) ASSERT_EQUAL(factory.get_halt_list().len(), 0) ASSERT_FALSE(factory.is_transformer_connected()) ASSERT_EQUAL(factory.get_transformer(), null) ASSERT_EQUAL(factory.get_field_count(), 0) ASSERT_EQUAL(factory.get_min_field_count(), 0) ASSERT_TRUE(factory.input.len() == 0) ASSERT_TRUE(factory.output.len() == 0) } { // and remove factory; only public player can remove them ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 4, 0)), "Der Besitzer erlaubt das Entfernen nicht") ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } RESET_ALL_PLAYER_FUNDS() } function test_factory_build_climate() { local pl = player_x(0) local public_pl = player_x(1) local setclimate = command_x(tool_set_climate) local allowed_climates = [ cl_temperate, cl_tundra, cl_rocky, cl_arctic ] local all_climates = [ cl_water, cl_desert, cl_tropic, cl_mediterran, cl_temperate, cl_tundra, cl_rocky, cl_arctic ] { foreach (cl in all_climates) { ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl), null) local err = build_factory(pl, coord3d(3, 4, 0), false /*don't ignore climates*/, 1, 1024, "Kohlegrube") if (allowed_climates.find(cl) != null) { ASSERT_EQUAL(err, null) ASSERT_EQUAL(factory_list_x().get_count(), 1) // and remove it ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } else { ASSERT_EQUAL(err, "No suitable ground!") ASSERT_EQUAL(factory_list_x().get_count(), 0) } RESET_ALL_PLAYER_FUNDS() } } // and ignore climates { foreach (cl in all_climates) { ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl), null) local err = build_factory(pl, coord3d(3, 4, 0), 1 /*ignore climates*/, 1, 1024, "Kohlegrube") if (cl != cl_water) { ASSERT_EQUAL(err, null) ASSERT_EQUAL(factory_list_x().get_count(), 1) // and remove it ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } else { ASSERT_EQUAL(err, "No suitable ground!") ASSERT_EQUAL(factory_list_x().get_count(), 0) } RESET_ALL_PLAYER_FUNDS() } ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } // partially on disallowed climate { ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(3, 7, 0), "" + cl_temperate), null) ASSERT_EQUAL(setclimate.work(pl, coord3d(4, 0, 0), coord3d(7, 7, 0), "" + cl_mediterran), null) ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), false /*don't ignore climates*/, 1, 1024, "Kohlegrube"), "No suitable ground!") ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), true /*ignore climates*/, 1, 1024, "Kohlegrube"), null) ASSERT_EQUAL(factory_list_x().get_count(), 1) // and remove it ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } // clean up ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_factory_build_with_fields() { local pl = player_x(0) local public_pl = player_x(1) local setclimate = command_x(tool_set_climate) // build normal { ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), 0, 1, 1024, "PVkraftwerk"), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } // build in non-suitable climate { ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl_arctic), null) ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), 0, 1, 1024, "PVkraftwerk"), "No suitable ground!") } // Force building in non-suitable climate, factory should have no fields { ASSERT_EQUAL(build_factory(pl, coord3d(3, 4, 0), 1, 1, 1024, "PVkraftwerk"), null) for (local y = 0; y < 8; ++y) { for (local x = 0; x < 8; ++x) { ASSERT_EQUAL(tile_x(x, y, 0).find_object(mo_field), null) } } ASSERT_EQUAL(factory_list_x().get_count(), 1) // and remove it ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 4, 0)), null) } // clean up ASSERT_EQUAL(setclimate.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_factory_link() { local pl = player_x(0) local public_pl = player_x(1) local production = 1024 // 1/s // build coal mine + coal power plant ASSERT_EQUAL(build_factory(public_pl, coord3d(0, 0, 0), 1, 1, production, "Kohlegrube"), null) ASSERT_EQUAL(build_factory(public_pl, coord3d(6, 6, 0), 1, 1, production, "Kohlekraftwerk"), null) local mine = factory_x(0, 0) local pp = factory_x(6, 6) ASSERT_TRUE(mine != null) ASSERT_TRUE(pp != null) // test pre-conditions { ASSERT_EQUAL(mine.get_consumers().len(), 0) ASSERT_EQUAL(mine.get_suppliers().len(), 0) // ASSERT_EQUAL(mine.get_production()[0], 0) // FIXME this is 1024 when using the -scenario switch ASSERT_EQUAL(mine.get_power()[0], 0) ASSERT_TRUE(mine.input.len() == 0) ASSERT_TRUE(mine.output.len() == 1) local out = mine.output.Kohle ASSERT_TRUE(out != null) // ASSERT_EQUAL(out.get_storage()[0], 0) // FIXME this is 122 when using the -scenario switch ASSERT_EQUAL(out.get_received()[0], 0) ASSERT_EQUAL(out.get_consumed()[0], 0) ASSERT_EQUAL(out.get_in_transit()[0], 0) ASSERT_EQUAL(out.get_delivered()[0], 0) ASSERT_EQUAL(out.get_produced()[0], 0) ASSERT_EQUAL(out.get_base_production(), production) ASSERT_EQUAL(out.get_base_consumption(), production) ASSERT_EQUAL(out.get_production_factor(), 100) ASSERT_EQUAL(out.max_storage, 122) { local error_caught = false try { ASSERT_EQUAL(out.get_consumption_factor(), 0) } catch (e) { ASSERT_EQUAL(e, "No input slot [0] in factory at (0,0,0)") error_caught = true } ASSERT_TRUE(error_caught) } ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 0) ASSERT_EQUAL(pp.get_production()[0], 0) ASSERT_EQUAL(pp.get_power()[0], 0) ASSERT_TRUE(pp.input.len() == 1) ASSERT_TRUE(pp.output.len() == 0) local inp = pp.input.Kohle ASSERT_TRUE(inp != null) ASSERT_EQUAL(inp.get_storage()[0], 0) ASSERT_EQUAL(inp.get_received()[0], 0) ASSERT_EQUAL(inp.get_consumed()[0], 0) ASSERT_EQUAL(inp.get_in_transit()[0], 0) ASSERT_EQUAL(inp.get_delivered()[0], 0) ASSERT_EQUAL(inp.get_produced()[0], 0) ASSERT_EQUAL(inp.get_base_production(), production) ASSERT_EQUAL(inp.get_base_consumption(), production) ASSERT_EQUAL(inp.get_consumption_factor(), 100) ASSERT_EQUAL(inp.max_storage, 1153) { local error_caught = false try { ASSERT_EQUAL(inp.get_production_factor(), 0) } catch (e) { ASSERT_EQUAL(e, "No output slot [-1] in factory at (6,6,0)") error_caught = true } ASSERT_TRUE(error_caught) } } // link first factory with nothing - should fail { ASSERT_EQUAL(command_x(tool_link_factory).work(pl, coord3d(0, 0, 0), coord3d(15, 15, 0), ""), "") ASSERT_EQUAL(mine.get_consumers().len(), 0) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 0) } // link factory with itself - should fail { ASSERT_EQUAL(command_x(tool_link_factory).work(pl, coord3d(0, 0, 0), coord3d(0, 0, 0), ""), "") ASSERT_EQUAL(mine.get_consumers().len(), 0) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 0) } // link factories { // default_param is necessary even though it is not used ASSERT_EQUAL(command_x(tool_link_factory).work(pl, coord3d(0, 0, 0), coord3d(6, 6, 0), ""), null) ASSERT_EQUAL(mine.get_consumers().len(), 1) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(mine.get_consumers()[0].x, pp.x) ASSERT_EQUAL(mine.get_consumers()[0].y, pp.y) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 1) ASSERT_EQUAL(pp.get_suppliers()[0].x, mine.x) ASSERT_EQUAL(pp.get_suppliers()[0].y, mine.y) } // second link should have no effect { ASSERT_EQUAL(command_x(tool_link_factory).work(pl, coord3d(0, 0, 0), coord3d(6, 6, 0), ""), null) ASSERT_EQUAL(mine.get_consumers().len(), 1) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(mine.get_consumers()[0].x, pp.x) ASSERT_EQUAL(mine.get_consumers()[0].y, pp.y) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 1) ASSERT_EQUAL(pp.get_suppliers()[0].x, mine.x) ASSERT_EQUAL(pp.get_suppliers()[0].y, mine.y) } // unlink factories { local tool = command_x(tool_link_factory) tool.set_flags(2) // ctrl == unlink ASSERT_EQUAL(tool.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), ""), null) ASSERT_EQUAL(mine.get_consumers().len(), 0) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 0) } // second unlink should have no effect { local tool = command_x(tool_link_factory) tool.set_flags(2) // ctrl == unlink ASSERT_EQUAL(tool.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), ""), null) ASSERT_EQUAL(mine.get_consumers().len(), 0) ASSERT_EQUAL(mine.get_suppliers().len(), 0) ASSERT_EQUAL(pp.get_consumers().len(), 0) ASSERT_EQUAL(pp.get_suppliers().len(), 0) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(7, 7, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_factory_desc() { local desc = factory_desc_x("Raffinerie") local inp = desc.get_inputs() local out = desc.get_outputs() ASSERT_EQUAL(desc.get_name(), "Raffinerie") ASSERT_EQUAL(desc.is_electricity_producer(), false) ASSERT_EQUAL(inp.len(), 1) ASSERT_EQUAL(out.len(), 3) { local inp_goods = [] for(local i=0; i= 3) ASSERT_TRUE(ore.get_catg_index() >= 3) } function test_good_speed_bonus() { local pax = good_desc_x.passenger local concrete = good_desc_x("Concrete") ASSERT_TRUE(concrete.calc_revenue(wt_road, 0) == concrete.calc_revenue(wt_road, 999)) // this has a speed bonus of 0 local wtypes = [ wt_road, wt_rail, wt_water, wt_monorail, wt_maglev, wt_narrowgauge ] local goods = [ pax, concrete ] foreach (g in goods) { foreach (wt in wtypes) { local last = 0 for (local speed = 0; speed <= 999; ++speed) { local current = g.calc_revenue(wt, speed) ASSERT_TRUE(current >= last) last = current } } } } simutrans-124.3/tests/tests/test_groundobj.nut000066400000000000000000000123571474050137200216470ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for groundobj/movingobj // function test_groundobj_build_invalid_param() { // not long enough { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(0, 0, 0), "0"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(0, 0, 0), "0a"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(0, 0, 0), "0ab"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // invalid default_param: first char not '0' or '1' { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(0, 0, 0), "afoo"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_invalid_pos() { // invalid pos { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(-1, -1, 0), ""), null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_random() { { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), null), null) local go = tile_x(4, 2, 0).find_object(mo_groundobj) ASSERT_TRUE(go != null) ASSERT_EQUAL(go.type, mo_groundobj) ASSERT_EQUAL(go.owner.nr, 16) ASSERT_EQUAL(go.is_removable(player_x(0)), null) } { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(2, 4, 0), ""), null) local go = tile_x(2, 4, 0).find_object(mo_groundobj) ASSERT_TRUE(go != null) ASSERT_EQUAL(go.type, mo_groundobj) ASSERT_EQUAL(go.owner.nr, 16) ASSERT_EQUAL(go.is_removable(player_x(0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(2, 4, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_specific() { { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "0__See1"), null) local go = tile_x(4, 2, 0).find_object(mo_groundobj) ASSERT_TRUE(go != null) ASSERT_EQUAL(go.type, mo_groundobj) ASSERT_EQUAL(go.owner.nr, 16) ASSERT_EQUAL(go.is_removable(player_x(0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_invalid_climate() { { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "0__Hochsitz1"), "") ASSERT_EQUAL(tile_x(4, 2, 0).find_object(mo_groundobj), null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_ignore_climate() { { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "1__Hochsitz1"), null) local go = tile_x(4, 2, 0).find_object(mo_groundobj) ASSERT_TRUE(go != null) ASSERT_EQUAL(go.type, mo_groundobj) ASSERT_EQUAL(go.owner.nr, 16) ASSERT_EQUAL(go.is_removable(player_x(0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_occupied() { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "0__See1"), null) { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "1__Hochsitz1"), "") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_on_trees() { ASSERT_EQUAL(command_x(tool_plant_tree).work(player_x(1), coord3d(4, 2, 0), "11,Ahorn-1"), null) // trees_on_top = 0 -> fail { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "1__See1"), "") ASSERT_EQUAL(tile_x(4, 2, 0).find_object(mo_groundobj), null) } // trees_on_top = 1 -> success { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "0__moles"), null) local go = tile_x(4, 2, 0).find_object(mo_groundobj) ASSERT_TRUE(go != null) ASSERT_EQUAL(go.type, mo_groundobj) ASSERT_EQUAL(go.owner.nr, 16) ASSERT_EQUAL(go.is_removable(player_x(0)), null) local tree = tile_x(4, 2, 0).find_object(mo_tree) ASSERT_TRUE(tree != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_groundobj_build_on_slope() { ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.south), null) { ASSERT_EQUAL(command_x(tool_build_groundobj).work(player_x(0), coord3d(4, 2, 0), "1__See1"), null) ASSERT_EQUAL(tile_x(4, 2, 0).find_object(mo_groundobj), null) } // clean up ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_halt.nut000066400000000000000000001366341474050137200206130ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // test for halts/stops // function test_halt_build_rail_single_tile() { local pl = player_x(0) local setslope = command_x.set_slope local stationbuilder = command_x(tool_build_station) local wayremover = command_x(tool_remove_way) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] // road because it has double slopes available local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_road, {} )[0] local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] // preconditions ASSERT_TRUE(road_desc != null) ASSERT_TRUE(station_desc != null) ASSERT_TRUE(bridge_desc != null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) local pos = coord3d(4, 2, 0) { for (local sl = slope.flat; sl < slope.raised; ++sl) { ASSERT_EQUAL(setslope(pl, pos, sl), sl != slope.flat ? null : "") ASSERT_EQUAL(stationbuilder.work(pl, pos, station_desc.get_name()), "No suitable way on the ground!") ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(tile_x(pos.x, pos.y, pos.z).find_object(mo_building), null) } } ASSERT_EQUAL(setslope(pl, pos, slope.flat), null) // cannot build on non-flat tile { for (local sl = slope.flat+1; sl < slope.raised; ++sl) { ASSERT_EQUAL(setslope(pl, pos, sl), null) local d = slope.to_dir(sl) if (d != dir.none) { // only consider slopes we can build roads on RESET_ALL_PLAYER_FUNDS() local c = dir.to_coord(dir.backward(d)) local adjacent = pos + coord3d(c.x, c.y, 0) ASSERT_EQUAL(command_x.build_way(pl, adjacent, pos, road_desc, true), null) local old_maintenance = pl.get_current_maintenance() ASSERT_EQUAL(stationbuilder.work(pl, pos, station_desc.get_name()), "No suitable way on the ground!") ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) ASSERT_EQUAL(tile_x(pos.x, pos.y, pos.z).find_object(mo_building), null) ASSERT_EQUAL(wayremover.work(pl, pos, adjacent, "" + wt_road), null) } } } ASSERT_EQUAL(setslope(pl, pos, slope.flat), null) // build on bridge { ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 4, 0), slope.north), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(3, 2, 0), bridge_desc.get_name()), null) local old_maintenance = pl.get_current_maintenance() ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 3, 1), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 1)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) // note z = 0 instead of 1 ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 2, 0), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) // note z = 0 instead of 1 ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 4, 0), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 4, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 4, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 4, 0), slope.flat), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_build_harbour() { local pl = player_x(0) local stationbuilder = command_x(tool_build_station) local station_desc = building_desc_x.get_available_stations(building_desc_x.harbour, wt_water, good_desc_x.passenger)[0] // FIXME: null instead of pax fails local setclimate = command_x(tool_set_climate) // build harbour on flat land: should fail { ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), station_desc.get_name()), "Dock must be built on single slope!") ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_building), null) } // build harbour on sloped land: should fail { ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), station_desc.get_name()), "") ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_building), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 4, 0)), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), station_desc.get_name()), "") ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_building), null) } // build harbour on sloped land adjacent to water: Should succeed { ASSERT_EQUAL(setclimate.work(pl, coord3d(4, 3, -1), coord3d(4, 3, -1), "" + cl_water), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 2, -1), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 3, -1)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_building), null) ASSERT_EQUAL(setclimate.work(pl, coord3d(4, 3, -1), coord3d(4, 3, -1), "" + cl_mediterran), null) } // clean up ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 4, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_water() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 0), "LakeShipStop"), null) } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_water_multiple_rotations() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(3, 3, 0), coord3d(3, 3, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 0), "LakeShipStop"), "More than one possibility to build this dock found.") } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(3, 3, 0), coord3d(3, 3, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_water_fixed_rotation_valid() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 0), "LakeShipStop,2"), null) } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_water_fixed_rotation_invalid() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 0), "LakeShipStop,1"), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_outside_map() { { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(-1, -1, 0), "LakeShipStop"), "") } // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_map_border_auto_rotation() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 1, 0), coord3d(4, 1, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 0, 0), "LakeShipStop"), null) } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 1, 0), coord3d(4, 0, 0), "" + cl_mediterran), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 0, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_map_border_fixed_rotation() { { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 0, 0), "LakeShipStop,2"), "No suitable ground!") } // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_on_bridge() { ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 4, 0), slope.north), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(player_x(0), coord3d(4, 2, 0), "Schiffhebewerk"), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 1), "LakeShipStop"), "") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 4, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_on_slope() { ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.north), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 2, 0), "LakeShipStop"), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 2, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_near_cliff() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 3, 0), slope.all_up_slope), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 3, 1), "LakeShipStop"), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) ASSERT_EQUAL(command_x.set_slope(player_x(0), coord3d(4, 3, 1), slope.all_down_slope), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_in_water() { ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_water), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 2, 0), "LakeShipStop"), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_set_climate).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 2, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_flat_dock_occupied() { ASSERT_EQUAL(command_x(tool_build_house).work(player_x(1), coord3d(4, 2, 0), "11RES_01_23"), null) { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 2, 0), "LakeShipStop"), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(1), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_air() { local pl = player_x(0) local runway = way_desc_x.get_available_ways(wt_air, st_runway)[0] local taxiway = way_desc_x.get_available_ways(wt_air, st_flat)[0] local airhalt = building_desc_x("AirStop") ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 5, 0), coord3d(5, 7, 0), runway, true), null) // air halts must be on taxiways (contrary to the untranslated error message) { ASSERT_EQUAL(command_x.build_station(pl, coord3d(5, 5, 0), airhalt), "Flugzeughalt muss auf\nRunway liegen!\n") ASSERT_EQUAL(command_x.build_station(pl, coord3d(5, 6, 0), airhalt), "Flugzeughalt muss auf\nRunway liegen!\n") ASSERT_EQUAL(command_x.build_station(pl, coord3d(5, 7, 0), airhalt), "Flugzeughalt muss auf\nRunway liegen!\n") } ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 6, 0), coord3d(3, 6, 0), taxiway, true), null) // not in the middle of a taxiway { ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 6, 0), airhalt), "No terminal station here!") } // end of taxiway -> success { ASSERT_EQUAL(command_x.build_station(pl, coord3d(3, 6, 0), airhalt), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 6, 0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 6, 0), coord3d(5, 6, 0), "" + wt_air), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 5, 0), coord3d(5, 7, 0), "" + wt_air), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_multi_tile() { local pl = player_x(0) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_road, {})[0] local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] // 2 adjacent tiles { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), road, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(2, 2, 0), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(3, 2, 0), station_desc.get_name()), null) local halt = halt_x.get_halt(coord3d(2, 2, 0), pl) ASSERT_TRUE(halt != null) ASSERT_EQUAL(tile_x(2, 2, 0).get_halt().get_name(), tile_x(3, 2, 0).get_halt().get_name()) // check that this is really the same halt ASSERT_EQUAL(halt.get_owner().get_name(), pl.get_name()) ASSERT_EQUAL(halt.is_connected(halt, good_desc_x.passenger), 1) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_FALSE(halt.accepts_good(good_desc_x.mail)) ASSERT_EQUAL(halt.get_arrived()[0], 0) ASSERT_EQUAL(halt.get_departed()[0], 0) ASSERT_EQUAL(halt.get_waiting()[0], 0) ASSERT_EQUAL(halt.get_happy()[0], 0) ASSERT_EQUAL(halt.get_unhappy()[0], 0) ASSERT_EQUAL(halt.get_noroute()[0], 0) ASSERT_EQUAL(halt.get_convoys()[0], 0) ASSERT_EQUAL(halt.get_walked()[0], 0) ASSERT_EQUAL(halt.get_convoy_list().get_count(), 0) ASSERT_EQUAL(halt.get_line_list().get_count(), 0) ASSERT_EQUAL(halt.get_factory_list().len(), 0) local tile_list = halt.get_tile_list() local expected_tiles = [ tile_x(2, 2, 0), tile_x(3, 2, 0) ] foreach (t in tile_list) { ASSERT_TRUE(t.find_object(mo_building) != null) // expected_tiles.find(t) != null won't work ASSERT_EQUAL(expected_tiles.filter(@(idx, val) t.x == val.x && t.y == val.y && t.z == val.z).len(), 1) } ASSERT_EQUAL(halt.get_freight_to_dest(good_desc_x.passenger, coord(2, 2)), 0) ASSERT_EQUAL(halt.get_freight_to_halt(good_desc_x.passenger, halt), 0) // this also depends on the separate_halt_capacities setting ASSERT_EQUAL(halt.get_capacity(good_desc_x.passenger), 64) ASSERT_EQUAL(halt.get_capacity(good_desc_x.mail), 0) ASSERT_EQUAL(halt.get_capacity(good_desc_x("Kohle")), 0) ASSERT_EQUAL(halt.get_capacity(good_desc_x("nonexistent")), 0) ASSERT_EQUAL(halt.get_connections(good_desc_x.passenger).len(), 0) ASSERT_EQUAL(halt.get_connections(good_desc_x.mail).len(), 0) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } // 2 tiles on top of each other { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), road, true), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), bridge_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(3, 4, 0), station_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(3, 4, 1), station_desc.get_name()), null) local lower_halt = halt_x.get_halt(coord3d(3, 4, 0), pl) local upper_halt = halt_x.get_halt(coord3d(3, 4, 1), pl) ASSERT_EQUAL(lower_halt.get_name(), upper_halt.get_name()) ASSERT_EQUAL(lower_halt.get_tile_list().len(), 2) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 2, 0), coord3d(3, 6, 0), "" + wt_road), null) } RESET_ALL_PLAYER_FUNDS() local old_cash = pl.get_cash()[0] ASSERT_EQUAL(old_cash, 200*1000) // 16x16 station { for (local x = 0; x < 16; ++x) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(x, 0, 0), coord3d(x, 15, 0), road, true), null) for (local y = 0; y < 16; ++y) { ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(x, y, 0), station_desc.get_name()), null) } } ASSERT_EQUAL(pl.get_current_maintenance(), 16*16*(road.get_maintenance() + station_desc.get_maintenance())) ASSERT_EQUAL(pl.get_cash()[0]*100, old_cash*100 - 16*16*(road.get_cost() + station_desc.get_cost())) local halt = halt_x.get_halt(coord3d(0, 0, 0), pl) ASSERT_TRUE(halt != null) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_FALSE(halt.accepts_good(good_desc_x.mail)) ASSERT_EQUAL(halt.is_connected(halt, good_desc_x.passenger), 1) ASSERT_EQUAL(halt.is_connected(halt, good_desc_x.mail), 1) for (local x = 0; x < 16; ++x) { ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(x, 0, 0), coord3d(x, 15, 0), "" + wt_road), null) } ASSERT_EQUAL(pl.get_current_maintenance(), 0) } RESET_ALL_PLAYER_FUNDS() } function test_halt_build_multi_mode() { local pl = player_x(0) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local rail_desc = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local pax_stop = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local pax_station = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x.passenger)[0] { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(4, 4, 0), road_desc, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 3, 0), coord3d(5, 4, 0), rail_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 4, 0), pax_stop.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(5, 4, 0), pax_station.get_name()), null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 4, 0), pl).get_name(), halt_x.get_halt(coord3d(5, 4, 0), pl).get_name()) local halt = halt_x.get_halt(coord3d(4, 4, 0), pl) ASSERT_EQUAL(halt.get_capacity(good_desc_x.passenger), 64) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 4, 0), coord3d(4, 3, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 4, 0), coord3d(5, 3, 0), "" + wt_rail), null) } RESET_ALL_PLAYER_FUNDS() } function test_halt_build_multi_player() { local pl = player_x(0) local public_pl = player_x(1) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 4, 0), coord3d(3, 4, 0), road_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 4, 0), pax_halt.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(public_pl, coord3d(3, 4, 0), pax_halt.get_name()), null) ASSERT_TRUE(halt_x.get_halt(coord3d(3, 4, 0), pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 4, 0), public_pl), null) local my_halt = halt_x.get_halt(coord3d(4, 4, 0), pl) local pub_halt = halt_x.get_halt(coord3d(3, 4, 0), public_pl) ASSERT_TRUE(my_halt != null) ASSERT_TRUE(pub_halt != null) ASSERT_TRUE(my_halt.get_name() != pub_halt.get_name()) ASSERT_EQUAL(my_halt.get_tile_list().len(), 1) ASSERT_EQUAL(pub_halt.get_tile_list().len(), 1) ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, coord3d(4, 4, 0), coord3d(3, 4, 0), "" + wt_road), null) } RESET_ALL_PLAYER_FUNDS() } function test_halt_build_separate() { local pl = player_x(0) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 4, 0), coord3d(3, 4, 0), road_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(5, 4, 0), pax_halt.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(3, 4, 0), pax_halt.get_name()), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 4, 0), pax_halt.get_name()), null) local halt3 = halt_x.get_halt(coord3d(3, 4, 0), pl) local halt4 = halt_x.get_halt(coord3d(4, 4, 0), pl) local halt5 = halt_x.get_halt(coord3d(5, 4, 0), pl) ASSERT_TRUE(halt3 != null) ASSERT_TRUE(halt4 != null) ASSERT_TRUE(halt5 != null) ASSERT_TRUE(halt3.get_name() != halt5.get_name()) ASSERT_TRUE(halt4.get_name() == halt5.get_name()) ASSERT_TRUE(halt4.get_name() != halt3.get_name()) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 4, 0), coord3d(3, 4, 0), "" + wt_road), null) } RESET_ALL_PLAYER_FUNDS() } function test_halt_build_near_factory() { local pl = player_x(0) local public_pl = player_x(1) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local freight_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x("Kohle"))[0] local remover = command_x(tool_remover) // build coal mine + coal power plant, then link them ASSERT_EQUAL(build_factory(pl, coord3d(0, 0, 0), 1, 1, 1024, "Kohlegrube"), null) { // also depends on station catchment area size ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 4, 0), coord3d(4, 3, 0), road_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 4, 0), pax_halt.get_name()), null) local halt = halt_x.get_halt(coord3d(4, 4, 0), pl) ASSERT_TRUE(halt != null) ASSERT_EQUAL(halt.get_factory_list().len(), 1) ASSERT_EQUAL(halt.get_factory_list()[0].get_name(), "Coal mine") ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 4, 0), coord3d(4, 3, 0), "" + wt_road), null) } ASSERT_EQUAL(remover.work(public_pl, coord3d(0, 0, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_near_factories() { local pl = player_x(0) local public_pl = player_x(1) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local freight_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x("Kohle"))[0] local remover = command_x(tool_remover) // build coal mine + coal power plant, then link them ASSERT_EQUAL(build_factory(pl, coord3d(0, 0, 0), 1, 1, 1024, "Kohlegrube"), null) ASSERT_EQUAL(build_factory(pl, coord3d(6, 6, 0), 1, 1, 1024, "Kohlekraftwerk"), null) ASSERT_EQUAL(command_x(tool_link_factory).work(pl, coord3d(0, 0, 0), coord3d(6, 6, 0), ""), null) { // also depends on station catchment area size ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 4, 0), coord3d(4, 3, 0), road_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 4, 0), pax_halt.get_name()), null) local halt = halt_x.get_halt(coord3d(4, 4, 0), pl) ASSERT_TRUE(halt != null) ASSERT_EQUAL(halt.get_factory_list().len(), 2) ASSERT_EQUAL(halt.get_factory_list()[0].get_name(), "Coal power station") ASSERT_EQUAL(halt.get_factory_list()[1].get_name(), "Coal mine") ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 4, 0), coord3d(4, 3, 0), "" + wt_road), null) } // this only works with catchment area size of 4 { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 7, 0), coord3d(1, 7, 0), road_desc, true), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(1, 7, 0), pax_halt.get_name()), null) local halt = halt_x.get_halt(coord3d(1, 7, 0), pl) ASSERT_TRUE(halt != null) ASSERT_EQUAL(halt.get_factory_list().len(), 0) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(0, 7, 0), coord3d(1, 7, 0), "" + wt_road), null) } ASSERT_EQUAL(remover.work(public_pl, coord3d(0, 0, 0)), null) ASSERT_EQUAL(remover.work(public_pl, coord3d(6, 6, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_on_tunnel_entrance() { local pl = player_x(0) local rail_tunnel = tunnel_desc_x.get_available_tunnels(wt_rail)[0] local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x.passenger)[0] ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(4, 1, 0), rail_tunnel.get_name()), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(3, 2, 0), rail_tunnel.get_name()), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(5, 2, 0), rail_tunnel.get_name()), null) // Building station on tunnel entrance fails (contrary to depots) { for (local d = dir.north; d < dir.all; d = d*2) { local p = coord3d(4, 2, 0) + dir.to_coord(d) ASSERT_EQUAL(command_x.build_station(pl, p, station_desc), "No suitable way on the ground!") } } local remover = command_x(tool_remover) remover.set_flags(2) ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_on_bridge_end() { local pl = player_x(0) local rail_bridge = bridge_desc_x.get_available_bridges(wt_rail)[0] local setslope = command_x.set_slope local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x.passenger)[0] // north-south direction { ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.north), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(4, 2, 0), rail_bridge.get_name()), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 2, 0), station_desc), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 4, 0), station_desc), null) // tool_remover removes halt first, then bridge, then depot (depot is automatically removed when destroying bridge) // So here we have to remove things on the tile twice (contrary to test_depot_build_on_bridge_end) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.flat), null) } // east-west direction { ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.east), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 0), slope.west), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(3, 3, 0), rail_bridge.get_name()), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(3, 3, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(5, 3, 0), get_depot_by_wt(wt_rail)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 0), slope.flat), null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_build_on_depot() { local pl = player_x(0) local rail_desc = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_rail, good_desc_x.passenger)[0] local depot = get_depot_by_wt(wt_rail) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), rail_desc, true), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 2, 0), depot), null) { ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 2, 0), station_desc), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_build_station_invalid_param() { // null default_param { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), null), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // empty default_param { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), ""), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // rotation information not a number { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), "foo,bar"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // rotation information number out of range 1 { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), "foo,16"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // rotation information number out of range 2 { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), "foo,-2"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // rotation information number out of range 3 (out of sint8 range) { local error_caught = false try { ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(0, 0, 0), "foo,1000"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_build_station_extension() { local pl = player_x(0) local setslope = command_x.set_slope local stationbuilder = command_x(tool_build_station) local wayremover = command_x(tool_remove_way) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] // road because it has double slopes available local station_desc = building_desc_x.get_available_stations(building_desc_x.station, wt_road, {})[0] local stext_desc = building_desc_x.get_available_stations(building_desc_x.station_extension, wt_rail, good_desc_x.passenger)[0] local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] ASSERT_TRUE(station_desc != null) ASSERT_TRUE(stext_desc != null) ASSERT_TRUE(bridge_desc != null) ASSERT_TRUE(road_desc != null) // build station extension without station: should fail { ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), stext_desc.get_name()), "Post muss neben\nHaltestelle\nliegen!\n") ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_building), null) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), station_desc.get_name()), null) local old_maintenance = pl.get_current_maintenance() // build station extension next to station: should succeed { ASSERT_EQUAL(stationbuilder.work(pl, coord3d(5, 3, 0), stext_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) // and diagonal ASSERT_EQUAL(stationbuilder.work(pl, coord3d(5, 2, 0), stext_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) } // build station extension on raised tile: should succeed { ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 1), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 3, 2), slope.all_up_slope), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(5, 3, 3), stext_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 3, 3)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) // up slope is automatically removed ASSERT_EQUAL(square_x(5, 3).get_tile_at_height(1), null) ASSERT_EQUAL(square_x(5, 3).get_tile_at_height(2), null) } { // diagonal too ASSERT_EQUAL(setslope(pl, coord3d(5, 2, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(5, 2, 1), slope.all_up_slope), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(5, 2, 2), stext_desc.get_name()), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(5, 2, 2)), null) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) // up slope is automatically removed ASSERT_EQUAL(square_x(5, 3).get_tile_at_height(1), null) ASSERT_EQUAL(square_x(5, 3).get_tile_at_height(2), null) } ASSERT_EQUAL(wayremover.work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // clean up RESET_ALL_PLAYER_FUNDS() } function test_halt_upgrade_downgrade() { local pl = player_x(0) local stationbuilder = command_x(tool_build_station) local wayremover = command_x(tool_remove_way) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pax_halts = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger) pax_halts.sort(@(a, b) a.get_capacity() <=> b.get_capacity()) ASSERT_TRUE(pax_halts.len() >= 2) local small_halt = pax_halts[0] local big_halt = pax_halts[1] local pos = coord3d(3, 3, 0) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), road_desc, true), null) // upgrade station { ASSERT_EQUAL(stationbuilder.work(pl, pos, small_halt.get_name()), null) local halt = halt_x.get_halt(pos, pl) ASSERT_TRUE(halt != null) local old_capacity = halt.get_capacity(good_desc_x.passenger) local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(stationbuilder.work(pl, pos, big_halt.get_name()), null) ASSERT_TRUE(halt.is_valid()) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_TRUE(halt.get_capacity(good_desc_x.passenger) > old_capacity) ASSERT_EQUAL(halt.get_tile_list().len(), 1) ASSERT_TRUE(pl.get_current_maintenance() > old_maint) ASSERT_EQUAL(pl.get_current_maintenance() - old_maint, big_halt.get_maintenance() - small_halt.get_maintenance()) } // upgrade station to same level { local halt = halt_x.get_halt(pos, pl) local old_capacity = halt.get_capacity(good_desc_x.passenger) local old_maint = pl.get_current_maintenance() local old_cash = pl.get_current_cash() ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 3, 0), big_halt.get_name()), null) ASSERT_TRUE(halt.is_valid()) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_EQUAL(halt.get_capacity(good_desc_x.passenger), old_capacity) ASSERT_EQUAL(halt.get_tile_list().len(), 1) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // downgrade without ctrl, should fail { local halt = halt_x.get_halt(pos, pl) local old_capacity = halt.get_capacity(good_desc_x.passenger) local old_maint = pl.get_current_maintenance() local old_cash = pl.get_current_cash() ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 3, 0), small_halt.get_name()), "Upgrade must have\na higher level") ASSERT_TRUE(halt.is_valid()) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_EQUAL(halt.get_capacity(good_desc_x.passenger), old_capacity) ASSERT_EQUAL(halt.get_tile_list().len(), 1) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // downgrade with ctrl { local halt = halt_x.get_halt(pos, pl) local old_capacity = halt.get_capacity(good_desc_x.passenger) local old_maint = pl.get_current_maintenance() local old_cash = pl.get_current_cash() stationbuilder.set_flags(2) // ctrl ASSERT_EQUAL(stationbuilder.work(pl, coord3d(3, 3, 0), small_halt.get_name()), null) ASSERT_TRUE(halt.is_valid()) ASSERT_TRUE(halt.accepts_good(good_desc_x.passenger)) ASSERT_TRUE(halt.get_capacity(good_desc_x.passenger) < old_capacity) ASSERT_EQUAL(halt.get_tile_list().len(), 1) ASSERT_TRUE(pl.get_current_maintenance() < old_maint) ASSERT_EQUAL(pl.get_current_maintenance() - old_maint, small_halt.get_maintenance() - big_halt.get_maintenance()) } // clean up ASSERT_EQUAL(wayremover.work(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_make_public_single() { local pl = player_x(0) local public_pl = player_x(1) local stationbuilder = command_x(tool_build_station) local wayremover = command_x(tool_remove_way) local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local makepublic = command_x(tool_make_stop_public) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 3, 0), pax_halt), null) // invalid pos { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(-1, -1, -1)), "No suitable ground!") ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // no stop under cursor { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // valid stop - Making the stop public also makes the road under it public { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint - 1*pax_halt.get_maintenance() - 1*road_desc.get_maintenance()) ASSERT_EQUAL(pl.get_current_cash()*100, old_cash*100 - 60 * (1*pax_halt.get_maintenance() + 1*road_desc.get_maintenance()) ) ASSERT_EQUAL(public_pl.get_current_maintenance(), 1*pax_halt.get_maintenance() + 1*road_desc.get_maintenance()) } // already public - should have no effect { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(pl.get_current_cash(), old_cash) } // same for public player { local old_cash = public_pl.get_current_cash() local old_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(public_pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(public_pl.get_current_cash(), old_cash) } ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 3, 0), pax_halt), null) // If public player uses this tool, he pays for it { local old_cash = public_pl.get_current_cash() local old_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) // only halt maintenance because the road is already public ASSERT_EQUAL(public_pl.get_current_cash()*100, 100*old_cash + 60 * pax_halt.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_maint + pax_halt.get_maintenance()) } ASSERT_EQUAL(wayremover.work(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 3, 0), pax_halt), null) // Public player can make halts of other players public even if road underneath is not public { local old_cash = public_pl.get_current_cash() local old_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) // halt + road maintenance ASSERT_EQUAL(public_pl.get_current_cash()*100, 100*old_cash + 60 * pax_halt.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_maint + pax_halt.get_maintenance() + road_desc.get_maintenance()) } ASSERT_EQUAL(wayremover.work(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_make_public_multi_tile() { local pl = player_x(0) local public_pl = player_x(1) local stationbuilder = command_x(tool_build_station) local wayremover = command_x(tool_remove_way) local pax_halt = building_desc_x.get_available_stations(building_desc_x.station, wt_road, good_desc_x.passenger)[0] local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local makepublic = command_x(tool_make_stop_public) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 5, 0), road_desc, true), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 3, 0), pax_halt), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 4, 0), pax_halt), null) // valid stop - Making the stop public also makes the road under it public { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint - 2*pax_halt.get_maintenance() - 2*road_desc.get_maintenance()) ASSERT_EQUAL(pl.get_current_cash()*100, old_cash*100 - 60 * (2*pax_halt.get_maintenance() + 2*road_desc.get_maintenance()) ) ASSERT_EQUAL(public_pl.get_current_maintenance(), 2*pax_halt.get_maintenance() + 2*road_desc.get_maintenance()) } // already public - should have no effect { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(pl.get_current_cash(), old_cash) } // same for public player { local old_cash = public_pl.get_current_cash() local old_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(public_pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(public_pl.get_current_cash(), old_cash) } ASSERT_EQUAL(wayremover.work(public_pl, coord3d(4, 2, 0), coord3d(4, 5, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 5, 0), road_desc, true), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 3, 0), pax_halt), null) ASSERT_EQUAL(command_x.build_station(pl, coord3d(4, 4, 0), pax_halt), null) // If public player uses this tool, he pays for it { local old_cash = public_pl.get_current_cash() local old_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(public_pl.get_current_cash()*100, 100*old_cash + 60 * 2*pax_halt.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_maint + (2*pax_halt.get_maintenance() + 2*road_desc.get_maintenance())) } ASSERT_EQUAL(wayremover.work(public_pl, coord3d(4, 2, 0), coord3d(4, 5, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_halt_make_public_underground() { local pl = player_x(0) local public_pl = player_x(1) local tunnel_desc = tunnel_desc_x.get_available_tunnels(wt_road)[0] local pax_halt = building_desc_x("LongBusStop") local makepublic = command_x(tool_make_stop_public) local stationbuilder = command_x(tool_build_station) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(5, 4, 0)), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(4, 2, 0), tunnel_desc.get_name()), null) ASSERT_EQUAL(stationbuilder.work(pl, coord3d(4, 3, 0), pax_halt.get_name()), null) // valid underground stop { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(halt_x.get_halt(coord3d(4, 3, 0), public_pl) != null) ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 3, 0), public_pl).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint - 1*pax_halt.get_maintenance() - 1*tunnel_desc.get_maintenance()) ASSERT_EQUAL(pl.get_current_cash()*100, old_cash*100 - 60 * (1*pax_halt.get_maintenance() + 1*tunnel_desc.get_maintenance()) ) ASSERT_EQUAL(public_pl.get_current_maintenance(), 1*pax_halt.get_maintenance() + 1*tunnel_desc.get_maintenance()) } ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(5, 4, 0)), null) } function test_halt_move_stop_invalid_param() { // out of map limits { local error_caught = false try { ASSERT_EQUAL(command_x(tool_stop_mover).work(player_x(0), coord3d(-1, -1, 0), coord3d(-1, -1, 0)), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // no way { local error_caught = false try { ASSERT_EQUAL(command_x(tool_stop_mover).work(player_x(0), coord3d(1, 1, 0), coord3d(3, 1, 0)), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // clean up RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_headquarters.nut000066400000000000000000000050761474050137200223460ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Test building/upgrading/removing headquarters // function get_hq_by_level(level) { local list = building_desc_x.get_building_list(building_desc_x.headquarter) list.sort(@(a, b) a.get_headquarter_level() <=> b.get_headquarter_level()) return list[level] } function test_headquarters_build_flat() { local pl = player_x(0) local public_pl = player_x(1) local hq_builder = command_x(tool_headquarter) local pos1 = coord3d(2, 3, 0) local pos2 = coord3d(4, 1, 0) local pos1_2d = coord(2, 3) local pos2_2d = coord(4, 1) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), coord(-1, -1).tostring()) // place normal { ASSERT_EQUAL(hq_builder.work(pl, pos1, get_hq_by_level(0).get_name()), null) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos1_2d.tostring()) } // replace my existing HQ { ASSERT_EQUAL(hq_builder.work(pl, pos1, get_hq_by_level(1).get_name()), null) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos1_2d.tostring()) } { // cannot downgrade headquarters FIXME this depends on whether timeline is enabled ?! ASSERT_EQUAL(hq_builder.work(pl, pos2, get_hq_by_level(0).get_name()), "Insufficient funds!") ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos1_2d.tostring()) pl.book_cash(1*1000*1000*100) ASSERT_EQUAL(hq_builder.work(pl, pos2, get_hq_by_level(0).get_name()), null) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos2_2d.tostring()) } // cannot replace other people's headquarters (not even public player!) { ASSERT_EQUAL(hq_builder.work(public_pl, pos2, get_hq_by_level(1).get_name()), "No suitable ground!") ASSERT_EQUAL(public_pl.get_headquarter_pos().tostring(), coord(-1, -1).tostring()) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos2_2d.tostring()) ASSERT_EQUAL(hq_builder.work(public_pl, pos1, get_hq_by_level(1).get_name()), null) ASSERT_EQUAL(public_pl.get_headquarter_pos().tostring(), pos1_2d.tostring()) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), pos2_2d.tostring()) } // remove hq local remover = command_x(tool_remover) ASSERT_EQUAL(remover.work(pl, tile_x(2, 3, 0)), "Der Besitzer erlaubt das Entfernen nicht") // cannot remove HQ of other players ASSERT_EQUAL(remover.work(public_pl, tile_x(2, 3, 0)), null) ASSERT_EQUAL(remover.work(public_pl, tile_x(4, 1, 0)), null) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), coord(-1, -1).tostring()) ASSERT_EQUAL(public_pl.get_headquarter_pos().tostring(), coord(-1, -1).tostring()) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_label.nut000066400000000000000000000040761474050137200207340ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for labels // function test_label() { local remover = command_x(tool_remover) local pl = player_x(0) local public_pl = player_x(1) // build label on ground { ASSERT_EQUAL(label_x.create(coord3d(4, 1, 0), pl, "Foo2"), null) // test label list local count = 0 foreach(label in world.get_label_list()) { ASSERT_EQUAL(label.get_text(), "Foo2") count ++ } ASSERT_EQUAL(count, 1) ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0)), null) ASSERT_EQUAL(world.get_label_list().get_count(), 0) } // Build label on invalid ground, same as building on map ground { ASSERT_EQUAL(label_x.create(coord3d(3, 1, -2), pl, "Foo1"), null) local label = tile_x(3, 1, 0).find_object(mo_label) ASSERT_TRUE(label != null) ASSERT_TRUE(label.is_valid()) ASSERT_EQUAL(label.get_owner().get_name(), pl.get_name()) // TODO More secure way to check for player equality ASSERT_EQUAL(label.get_waytype(), wt_invalid) ASSERT_EQUAL(label.get_text(), "Foo1") ASSERT_EQUAL(label.set_text("Bar"), true) ASSERT_EQUAL(label.get_text(), "Bar") ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0)), null) ASSERT_FALSE(label.is_valid()) } // build label on existing label, should fail { ASSERT_EQUAL(label_x.create(coord3d(5, 1, 0), pl, "Foo3"), null) ASSERT_EQUAL(label_x.create(coord3d(5, 1, 0), pl, "Foo4"), "Das Feld gehoert\neinem anderen Spieler\n") ASSERT_EQUAL(remover.work(pl, coord3d(5, 1, 0)), null) } // players cannot remove labels of other players (except public player) { ASSERT_EQUAL(label_x.create(coord3d(5, 1, 0), pl, "Foo1"), null) ASSERT_EQUAL(label_x.create(coord3d(5, 2, 0), public_pl, "Foo2"), null) ASSERT_EQUAL(remover.work(pl, coord3d(5, 2, 0)), "Der Besitzer erlaubt das Entfernen nicht") ASSERT_TRUE(tile_x(5, 2, 0).find_object(mo_label) != null) ASSERT_EQUAL(remover.work(public_pl, coord3d(5, 2, 0)), null) ASSERT_EQUAL(remover.work(public_pl, coord3d(5, 1, 0)), null) } // clean up RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_player.nut000066400000000000000000000057101474050137200211450ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for player_x stuff // function test_player_cash() { local pl = player_x(0) ASSERT_EQUAL(pl.get_current_cash(), 200000) // get_current_cash is in credits (returns float) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000*100) // get_current_net_wealth is in 1/100 credits ASSERT_EQUAL(pl.get_current_maintenance(), 0) local ok = pl.book_cash(0) ASSERT_EQUAL(ok, true) ASSERT_EQUAL(pl.get_current_cash(), 200000) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000 * 100) ASSERT_EQUAL(pl.get_current_maintenance(), 0) ok = pl.book_cash(-200000 * 100) // book_cash is in 1/100 credits ASSERT_EQUAL(ok, true) ASSERT_EQUAL(pl.get_current_cash(), 0) ASSERT_EQUAL(pl.get_current_net_wealth(), 0) ASSERT_EQUAL(pl.get_current_maintenance(), 0) ok = pl.book_cash(-1) ASSERT_EQUAL(ok, true) ASSERT_EQUAL(pl.get_current_cash(), -0.01) ASSERT_EQUAL(pl.get_current_net_wealth(), -1) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // clean up ok = pl.book_cash(200000 * 100 + 1) ASSERT_EQUAL(ok, true) ASSERT_EQUAL(pl.get_current_cash(), 200000) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000 * 100) ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_player_isactive() { local pl = player_x(0) ASSERT_EQUAL(pl.is_valid(), true) ASSERT_EQUAL(pl.is_active(), true) local public_pl = player_x(1) ASSERT_EQUAL(public_pl.is_valid(), true) ASSERT_EQUAL(public_pl.is_active(), true) local nonexist = player_x(2) ASSERT_EQUAL(nonexist.is_valid(), false) ASSERT_EQUAL(nonexist.is_active(), false) RESET_ALL_PLAYER_FUNDS() } function test_player_headquarters() { local pl = player_x(0) ASSERT_EQUAL(pl.get_headquarter_level(), 0) ASSERT_EQUAL(pl.get_headquarter_pos().tostring(), coord(-1, -1).tostring()) RESET_ALL_PLAYER_FUNDS() } function test_player_name() { local pl = player_x(0) ASSERT_EQUAL(pl.get_name(), "Human player") ASSERT_TRUE(pl.set_name("Foo")) ASSERT_EQUAL(pl.get_name(), "Foo") ASSERT_TRUE(pl.set_name("Foo")) ASSERT_EQUAL(pl.get_name(), "Foo") // clean up ASSERT_TRUE(pl.set_name("Human player")) RESET_ALL_PLAYER_FUNDS() } function test_player_lines() { local pl = player_x(0) // empty line list { local line_list = pl.get_line_list() ASSERT_TRUE(line_list != null) ASSERT_EQUAL(line_list.get_count(), 0) } // non-empty line list { ASSERT_TRUE(pl.create_line(wt_road)) local line_list = pl.get_line_list() ASSERT_TRUE(line_list != null) ASSERT_EQUAL(line_list.get_count(), 1) foreach (line in line_list) { ASSERT_TRUE(line != null) ASSERT_EQUAL(line.is_valid(), true) ASSERT_EQUAL(line.get_waytype(), wt_road) } foreach (line in line_list) { ASSERT_TRUE(line.destroy(pl)) } ASSERT_EQUAL(pl.get_line_list().get_count(), 0) } // TODO Destroy lines owned by other players // clean up RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_powerline.nut000066400000000000000000000435221474050137200216600ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for powerline stuff and transformers // function test_powerline_connect() { local pl = player_x(0) local public_pl = player_x(1) local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] local wayremover = command_x(tool_remove_way) ASSERT_TRUE(powerline != null) local center = coord3d(3, 4, 0) local north = center + dir.to_coord(dir.north) local east = center + dir.to_coord(dir.east) local south = center + dir.to_coord(dir.south) local west = center + dir.to_coord(dir.west) // preconditions ASSERT_EQUAL(pl.get_current_maintenance(), 0) { ASSERT_EQUAL(command_x.build_way(pl, center, south, powerline, true), null) ASSERT_EQUAL(wayremover.work(pl, south, south, "" + wt_power), null) ASSERT_TRUE(powerline_x(center.x, center.y, center.z).is_connected(powerline_x(center.x, center.y, center.z))) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "...0....", "........", "........", "........" ]) } local maint_per_tile = pl.get_current_maintenance() ASSERT_TRUE(maint_per_tile > 0) { ASSERT_EQUAL(command_x.build_way(pl, center, north, powerline, true), null) ASSERT_TRUE(powerline_x(center.x, center.y, center.z).is_connected(powerline_x(north.x, north.y, north.z))) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...1....", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), 2*maint_per_tile) } { ASSERT_EQUAL(command_x.build_way(pl, center, east, powerline, true), null) ASSERT_TRUE(powerline_x(center.x, center.y, center.z).is_connected(powerline_x(east.x, east.y, east.z))) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...38...", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), 3*maint_per_tile) } { ASSERT_EQUAL(command_x.build_way(pl, center, south, powerline, true), null) ASSERT_TRUE(powerline_x(center.x, center.y, center.z).is_connected(powerline_x(south.x, south.y, south.z))) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...78...", "...1....", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), 4*maint_per_tile) } { ASSERT_EQUAL(command_x.build_way(pl, center, west, powerline, true), null) ASSERT_TRUE(powerline_x(center.x, center.y, center.z).is_connected(powerline_x(west.x, west.y, west.z))) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "..2F8...", "...1....", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), 5*maint_per_tile) } // clean up ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), "" + wt_power), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), "" + wt_power), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_powerline_build_below_powerbridge() { local pl = player_x(0) local power_bridge = bridge_desc_x.get_available_bridges(wt_power)[0] local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), power_bridge), null) // build normal powerline below power bridge, should fail { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), powerline, true), "") } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), "" + wt_power), null) RESET_ALL_PLAYER_FUNDS() } function test_powerline_build_powerbridge_above_powerline() { local pl = player_x(0) local power_bridge = bridge_desc_x.get_available_bridges(wt_power)[0] local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] // Note: Build way first, then bridge (see above for why) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), powerline, true), null) // build flat powerline bridge { ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), power_bridge), null) local bridge_part = powerline_x(3, 3, 1) local ground_part = powerline_x(3, 3, 0) ASSERT_TRUE(bridge_part != null) ASSERT_TRUE(ground_part != null) ASSERT_FALSE(bridge_part.is_connected(ground_part)) ASSERT_FALSE(ground_part.is_connected(bridge_part)) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), "" + wt_power), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 2, 0), coord3d(3, 4, 0), "" + wt_power), null) RESET_ALL_PLAYER_FUNDS() } function test_powerline_build_transformer() { local pl = player_x(0) local public_pl = player_x(1) local build_trafo = command_x(tool_build_transformer) local setclimate = command_x(tool_set_climate) local setslope = command_x.set_slope local power_tunnel = tunnel_desc_x.get_available_tunnels(wt_power)[0] // preconditions ASSERT_TRUE(power_tunnel != null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // build coal mine + coal power plant, then link them ASSERT_EQUAL(build_factory(public_pl, coord3d(0, 0, 0), 1, 1, 1024, "Kohlegrube"), null) ASSERT_EQUAL(build_factory(public_pl, coord3d(6, 6, 0), 1, 1, 1024, "Kohlekraftwerk"), null) command_x(tool_link_factory).work(public_pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "") ASSERT_EQUAL(pl.get_current_maintenance(), 0) { // build transformer not adjacent to a factory ASSERT_EQUAL(build_trafo.work(pl, coord3d(0, 7, 0)), "Transformer only next to factory!") ASSERT_EQUAL(pl.get_current_maintenance(), 0) // diagonally adjacent to factory, not allowed ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 3, 0)), "Transformer only next to factory!") ASSERT_EQUAL(pl.get_current_maintenance(), 0) } { // cannot build transformer on water even if adjacent to factory ASSERT_EQUAL(setclimate.work(pl, coord3d(3, 2, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 0)), "Transformer only on flat bare land!") ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(setclimate.work(pl, coord3d(3, 2, 0), coord3d(3, 2, 0), "" + cl_mediterran), null) } { // build transformer in the air, same as building on map ground ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 1)), null) ASSERT_TRUE(pl.get_current_maintenance() > 0) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } { // cannot build transformer on sloped tile ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.north), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 0)), "Transformer only on flat bare land!") ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 1)), "Transformer only on flat bare land!") ASSERT_EQUAL(pl.get_current_maintenance(), 0) } { // Cannot build transformer underground adjacent to factory // Depends also on allow_underground_transformers setting ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.all_up_slope), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 0)), "Transformer only next to factory!") // 2 height levels ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 1), slope.all_up_slope), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 0)), "Transformer only next to factory!") // However, building on flat ground on a different height level works ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 2)), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 2, 2)), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 2), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 1), slope.all_down_slope), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } { // Build transformer underground below mine (senke_t) ASSERT_EQUAL(build_trafo.work(pl, coord3d(2, 2, -1)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 2, -1)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // And below power plant (pumpe_t) ASSERT_EQUAL(build_trafo.work(pl, coord3d(6, 6, -1)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(6, 6, -1)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } { // build underground transformer on underground powerline, should fail local digger = command_x(tool_build_tunnel) digger.set_flags(2) # Ctrl ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 4, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 4, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(digger.work(pl, coord3d(2, 3, -1), power_tunnel.get_name()), null) ASSERT_EQUAL(digger.work(pl, coord3d(2, 3, -1), coord3d(2, 2, -1), power_tunnel.get_name()), null) // test local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(build_trafo.work(pl, coord3d(2, 2, -1)), "Tile not empty.") ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 2, -1)), null) // and clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 2, -1)), "") // underground ??? ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 3, -1)), null) // above ground ??? ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 4, -1)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 4, -1)), null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(7, 7, 0)), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_powerline_build_over_transformer() { local pl = player_x(0) local public_pl = player_x(1) local build_trafo = command_x(tool_build_transformer) local production = 1024 // 1/s local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] ASSERT_EQUAL(build_factory(public_pl, coord3d(0, 0, 0), 1, 1, production, "Kohlegrube"), null) { ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 1, 0)), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 0, 0), coord3d(3, 2, 0), powerline, true), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 0, 0), coord3d(3, 2, 0), "" + wt_power), null) ASSERT_EQUAL(tile_x(3, 1, 0).find_object(mo_transformer_s), null) ASSERT_EQUAL(tile_x(3, 1, 0).find_object(mo_transformer_c), null) } ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(0, 0, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_powerline_build_transformer_multiple() { local pl = player_x(0) local public_pl = player_x(1) local build_trafo = command_x(tool_build_transformer) local production = 1024 // 1/s local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] // build coal mine + coal power plant ASSERT_EQUAL(build_factory(public_pl, coord3d(0, 0, 0), 1, 1, production, "Kohlegrube"), null) ASSERT_EQUAL(build_factory(public_pl, coord3d(3, 0, 0), 1, 1, production, "Kohlekraftwerk"), null) // single transformer adjacent to multiple factories { ASSERT_EQUAL(build_trafo.work(pl, coord3d(3, 2, 0)), null) ASSERT_TRUE(tile_x(3, 2, 0).find_object(mo_transformer_s) != null) ASSERT_TRUE(tile_x(3, 2, 0).find_object(mo_transformer_c) == null) local trafo = transformer_x(3, 2, 0) local pp = factory_x(3, 0) local mine = factory_x(0, 0) ASSERT_EQUAL(trafo.get_factory().get_name(), pp.get_name()) ASSERT_TRUE(pp.is_transformer_connected()) ASSERT_FALSE(mine.is_transformer_connected()) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 2, 0)), null) } // multiple transformers next to single factory { ASSERT_EQUAL(build_trafo.work(pl, coord3d(0, 3, 0)), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(1, 3, 0)), "Only one transformer per factory!") ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(0, 3, 0)), null) } // same as before, but for electricity producers { ASSERT_EQUAL(build_trafo.work(pl, coord3d(5, 1, 0)), null) ASSERT_EQUAL(build_trafo.work(pl, coord3d(5, 0, 0)), "Only one transformer per factory!") } // remove factory, should remove transformer and disconnect power nets { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 0, 0), coord3d(6, 0, 0), powerline, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 2, 0), coord3d(6, 2, 0), powerline, true), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(3, 0, 0)), null) ASSERT_EQUAL(tile_x(5, 1, 0).find_object(mo_transformer_s), null) ASSERT_EQUAL(tile_x(5, 1, 0).find_object(mo_transformer_c), null) ASSERT_FALSE(powerline_x(5, 0, 0).is_connected(powerline_x(5, 2, 0))) ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, coord3d(5, 0, 0), coord3d(6, 0, 0), "" + wt_power), null) ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, coord3d(5, 2, 0), coord3d(6, 2, 0), "" + wt_power), null) } ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(0, 0, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_powerline_ways() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local tramway = way_desc_x.get_available_ways(wt_rail, st_tram)[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), road, true), null) { // road-powerline crossing ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), powerline, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..1.....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", ".2A8....", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), "" + wt_power), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..1.....", "........", "........", "........", "........" ]) } { // build powerline ending on road ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(2, 2, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // build powerline over end of road ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(2, 3, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // build powerline in the same direction as way below ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 0, 0), coord3d(2, 4, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // remove straight way, add diagonal way ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(7, 0, 0), coord3d(0, 7, 0), road, true), null) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 4, 0), coord3d(6, 4, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) // and the other direction ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 1, 0), coord3d(4, 6, 0), powerline, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } ASSERT_EQUAL(wayremover.work(pl, coord3d(0, 7, 0), coord3d(7, 0, 0), "" + wt_road), null) // clean up RESET_ALL_PLAYER_FUNDS() } function test_powerline_remove_powerbridge() { local pl = player_x(0) local power_bridge = bridge_desc_x.get_available_bridges(wt_power)[0] ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 3, 0), slope.east), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 3, 0), slope.west), null) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), power_bridge), null) // try removing the bridge from its centre { ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 1)), "Cannot delete a bridge from its centre") ASSERT_TRUE(tile_x(2, 3, 0).find_object(mo_bridge) != null) } // try removing the bridge from one of its ends { ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 3, 0)), null) ASSERT_TRUE(tile_x(2, 3, 0).find_object(mo_bridge) == null) ASSERT_TRUE(tile_x(3, 3, 1).find_object(mo_bridge) == null) ASSERT_TRUE(tile_x(4, 3, 0).find_object(mo_bridge) == null) ASSERT_TRUE(tile_x(2, 3, 0).find_object(mo_powerline) != null) ASSERT_TRUE(tile_x(4, 3, 0).find_object(mo_powerline) != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 3, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 3, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 3, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_reservation.nut000066400000000000000000000030331474050137200222060ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests convoi reservation // function test_reservation_clear_ground() { local clear_reservation = command_x(tool_clear_reservation) local pl = player_x(0) // invalid coord { ASSERT_EQUAL(clear_reservation.work(pl, coord3d(-1, -1, 0)), null) } // flat ground { ASSERT_EQUAL(clear_reservation.work(pl, coord3d(0, 0, 0)), null) } RESET_ALL_PLAYER_FUNDS() } function test_reservation_clear_road() { local clear_reservation = command_x(tool_clear_reservation) local pl = player_x(0) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road, true), null) { ASSERT_EQUAL(clear_reservation.work(pl, coord3d(4, 3, 0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_reservation_clear_rail() { local clear_reservation = command_x(tool_clear_reservation) local pl = player_x(0) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), rail, true), null) { ASSERT_EQUAL(clear_reservation.work(pl, coord3d(4, 3, 0)), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_reservation_clear_rail_occupied() { // TODO } simutrans-124.3/tests/tests/test_scenario.nut000066400000000000000000000255211474050137200214560ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for scenario rules/conditions // function test_scenario_rules_allow_forbid_tool() { local pl = player_x(0) { ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), null) // FIXME this should fail ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 1)), null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_scenario_rules_allow_forbid_way_tool() { local waybuilder = command_x(tool_build_way) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local pl = player_x(0) rules.forbid_way_tool_rect(0, tool_build_way, wt_road, road.get_name(), coord(2, 2), coord(5, 5), "Foo Bar") // Fully in forbiden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(5, 5, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // Ending in forbidden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 2, 0), coord3d(2, 2, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // Starting in forbidden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // make sure we can build other ways { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), rail, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "........", "2A8.....", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), "" + wt_rail), null) } // clean up rules.clear() RESET_ALL_PLAYER_FUNDS() } function test_scenario_rules_allow_forbid_way_tool_rect() { local waybuilder = command_x(tool_build_way) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local pl = player_x(0) rules.forbid_way_tool_rect(0, tool_build_way, wt_road, "", coord(2, 2), coord(5, 5), "Foo Bar") // Fully in forbiden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(5, 5, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // Ending in forbidden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 2, 0), coord3d(2, 2, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // Starting in forbidden zone { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // make sure we can build other ways { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), rail, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "........", "2A8.....", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), "" + wt_rail), null) } // clean up rules.clear() RESET_ALL_PLAYER_FUNDS() } function test_scenario_rules_allow_forbid_way_tool_cube() { local waybuilder = command_x(tool_build_way) local setslope = command_x.set_slope local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local pl = player_x(0) rules.forbid_way_tool_cube(0, tool_build_way, wt_road, "", coord3d(2, 2, 1), coord3d(5, 5, 2), "Foo Bar") // build below { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "2A8.....", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), "" + wt_road), null) } // build into forbidden zone { ASSERT_EQUAL(setslope(pl, coord3d(3, 4, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.north), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 0, 0), coord3d(3, 4, 1), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(setslope(pl, coord3d(3, 4, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.flat), null) } rules.clear() rules.forbid_way_tool_cube(0, tool_build_way, wt_road, "", coord3d(0, 0, 1), coord3d(0, 0, 1), "Foo Bar") // build double height slope through forbidden cube { ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), (2*slope.east)), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(1, 1, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", ".28.....", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(1, 1, 0), "" + wt_road), null) ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), slope.flat), null) } // clean up rules.clear() RESET_ALL_PLAYER_FUNDS() } function test_scenario_rules_allow_forbid_tool_stacked_rect() { local pl = player_x(0) local waybuilder = command_x(tool_build_way) local setslope = command_x.set_slope local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] rules.forbid_way_tool_rect(0, tool_build_way, wt_road, "", coord(1, 1), coord(14, 14), "Foo Bar 1") // build in outer allowed ring, near map border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 0, 0), coord3d(0, 5, 0), road_desc, false), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5.......", "5.......", "5.......", "1.......", "........", "........" ]) } // build in outer forbidden ring { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 1, 0), coord3d(1, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5.......", "5.......", "5.......", "1.......", "........", "........" ]) } rules.allow_way_tool_rect(0, tool_build_way, wt_road, "", coord(2, 2), coord(13, 13)) // try building in allowed ring, does work since introdcued allowed rules { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 2, 0), coord3d(2, 5, 0), road_desc, false), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } // try building from inside allowed ring to forbidden rect, must fail { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 1, 0), coord3d(2, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } // try building from inside allowed ring to outside, must fail => we cannot cross border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 0, 0), coord3d(2, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } rules.clear() ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 0, 0), coord3d(0, 5, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 2, 0), coord3d(2, 5, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_scenario_rules_allow_forbid_tool_stacked_cube() { local pl = player_x(0) local waybuilder = command_x(tool_build_way) local setslope = command_x.set_slope local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] rules.forbid_way_tool_cube(0, tool_build_way, wt_road, "", coord3d(1, 1, 0), coord3d(14, 14, 0), "Foo Bar 1") // build in outer allowed ring, near map border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 0, 0), coord3d(0, 5, 0), road_desc, false), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5.......", "5.......", "5.......", "1.......", "........", "........" ]) } // build in outer forbidden ring { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 1, 0), coord3d(1, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5.......", "5.......", "5.......", "1.......", "........", "........" ]) } rules.allow_way_tool_rect(0, tool_build_way, wt_road, "", coord(2, 2), coord(13, 13)) // try building in allowed ring, does work since introdcued allowed rules { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 2, 0), coord3d(2, 5, 0), road_desc, false), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } // try building from inside allowed ring to forbidden rect, must fail { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 1, 0), coord3d(2, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } // try building from inside allowed ring to outside, must fail => we cannot cross border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 0, 0), coord3d(2, 5, 0), road_desc, false), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "6AAAA8..", "5.......", "5..6A8..", "5.69....", "5.5.....", "1.1.....", "........", "........" ]) } rules.clear() ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 0, 0), coord3d(0, 5, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(5, 2, 0), coord3d(2, 5, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_sign.nut000066400000000000000000000657471474050137200206310ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for signs/signals // function test_sign_build_oneway() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local remover = command_x(tool_remover) local road = way_desc_x("dirt_road") local rail = way_desc_x("sand_track") local sign = sign_desc_x.get_available_signs(wt_road).filter(@(idx, sign) sign.is_one_way())[0] ASSERT_TRUE(road != null) ASSERT_TRUE(sign != null) ASSERT_TRUE(sign.is_one_way()) // on ground without way { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // in the air { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 1), sign), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // build way ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), road, true), null) { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_signal), null) local s = tile_x(2, 3, 0).find_object(mo_roadsign) ASSERT_TRUE(s != null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_TRUE(s.can_pass(public_pl)) local w = tile_x(2, 3, 0).find_object(mo_way) ASSERT_TRUE(w != null) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.south) // change direction of sign ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_TRUE(s.can_pass(public_pl)) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.north) // change direction again, should have original direction ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_TRUE(s.can_pass(public_pl)) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.south) } // build road/rail crossing over sign, should succeed if crossing is possible without sign { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), rail, true), null) ASSERT_WAY_PATTERN_MASKED(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..4.....", "..1.....", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", ".2A8....", "........", "........", "........", "........" ]) local w = tile_x(2, 3, 0).find_object(mo_way) ASSERT_TRUE(w.is_crossing()) // change direction of sign on rail-road crossing, should succeed ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_WAY_PATTERN_MASKED(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..1.....", "..1.....", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", ".2A8....", "........", "........", "........", "........" ]) // and remove rail ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), "" + wt_rail), null) } // build road/road crossing over sign, should succeed { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2F8....", "..1.....", "........", "........", "........" ]) local w = tile_x(2, 3, 0).find_object(mo_way) ASSERT_FALSE(w.is_crossing()) ASSERT_WAY_PATTERN_MASKED(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2B8....", "..1.....", "........", "........", "........" ]) // change direction of sign on road crossing, should fail local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) } catch (e) { ASSERT_EQUAL(e, "Tool has no effects") error_caught = true } ASSERT_TRUE(error_caught) } // remove sign, try to build again (should fail because of crossing) { ASSERT_EQUAL(remover.work(pl, coord3d(2, 3, 0)), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2F8....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_roadsign), null) local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) } catch (e) { ASSERT_EQUAL(e, "Tool has no effects") error_caught = true } ASSERT_TRUE(error_caught) } ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), "" + wt_road), null) // Cannot remove signs of other players (except public player) { ASSERT_EQUAL(command_x.build_sign_at(public_pl, coord3d(2, 2, 0), sign), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(2, 2, 0)), "Der Besitzer erlaubt das Entfernen nicht") ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(2, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(2, 3, 0)), null) } // remove stuff ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_sign_build_trafficlight() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local remover = command_x(tool_remover) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local trafficlight = sign_desc_x.get_available_signs(wt_road).filter(@(idx, sign) sign.is_traffic_light())[0] ASSERT_TRUE(trafficlight != null) // on ground { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), trafficlight), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), road, true), null) // end of way { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 1, 0), trafficlight), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // 2-way { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), trafficlight), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(2, 3, 0), road, true), null) // 3-way { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), trafficlight), null) local tl = tile_x(2, 3, 0).find_object(mo_roadsign) ASSERT_TRUE(tl != null) ASSERT_TRUE(tl.can_pass(pl)) ASSERT_TRUE(tl.can_pass(public_pl)) ASSERT_TRUE(tl.get_desc().is_traffic_light()) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2D.....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(tile_x(2, 3, 0).get_way_dirs_masked(wt_road), dir.northsouthwest) } // Make 4-way from 3-way { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 3, 0), coord3d(3, 3, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2F8....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(tile_x(2, 3, 0).get_way_dirs_masked(wt_road), dir.all) } // remove traffic light on crossing via wayremover { ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), "" + wt_road), null) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_roadsign), null) } ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_sign_remove_trafficlight() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local trafficlight = sign_desc_x.get_available_signs(wt_road).filter(@(idx, sign) sign.is_traffic_light())[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 4, 0), coord3d(5, 6, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 5, 0), coord3d(6, 5, 0), road, true), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 2, 0), trafficlight), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(5, 5, 0), trafficlight), null) // Note that both traffic lights must have the same direction for the test to work // So the second traffic light must not change direction between the two wayremover calls { ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), "" + wt_road), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(4, 5, 0), coord3d(6, 5, 0), "" + wt_road), null) ASSERT_EQUAL(tile_x(2, 2, 0).find_object(mo_signal), null) ASSERT_EQUAL(tile_x(5, 5, 0).find_object(mo_signal), null) } ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), "" + wt_road), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(5, 4, 0), coord3d(5, 6, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_sign_build_private_way() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local remover = command_x(tool_remover) local road = way_desc_x("dirt_road") local rail = way_desc_x("sand_track") local sign = sign_desc_x.get_available_signs(wt_road).filter(@(idx, sign) sign.is_private_way())[0] ASSERT_TRUE(road != null) ASSERT_TRUE(sign != null) ASSERT_TRUE(sign.is_private_way()) // on ground { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // in the air { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 1), sign), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) } // build way ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), road, true), null) { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_signal), null) local s = tile_x(2, 3, 0).find_object(mo_roadsign) ASSERT_TRUE(s != null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_FALSE(s.can_pass(public_pl)) local w = tile_x(2, 3, 0).find_object(mo_way) ASSERT_TRUE(w != null) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.northsouth) // change direction of sign ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_FALSE(s.can_pass(public_pl)) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.northsouth) // change direction again, should have original direction ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) ASSERT_TRUE(s.is_valid()) ASSERT_TRUE(s.can_pass(pl)) ASSERT_FALSE(s.can_pass(public_pl)) ASSERT_EQUAL(w.get_dirs(), dir.northsouth) ASSERT_EQUAL(w.get_dirs_masked(), dir.northsouth) } // build road/rail crossing over sign, should succeed if crossing is possible without sign { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), rail, true), null) ASSERT_WAY_PATTERN_MASKED(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..5.....", "..1.....", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", ".2A8....", "........", "........", "........", "........" ]) ASSERT_TRUE(tile_x(2, 3, 0).find_object(mo_way).is_crossing()) // and remove rail ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), "" + wt_rail), null) } // build road/road crossing over sign, should succeed { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2F8....", "..1.....", "........", "........", "........" ]) local w = tile_x(2, 3, 0).find_object(mo_way) ASSERT_FALSE(w.is_crossing()) ASSERT_EQUAL(w.get_dirs_masked(), dir.all) // change direction of sign on road crossing, should fail local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) } catch (e) { ASSERT_EQUAL(e, "Tool has no effects") error_caught = true } ASSERT_TRUE(error_caught) } // remove sign, try to build again (should fail because of crossing) { ASSERT_EQUAL(remover.work(pl, coord3d(2, 3, 0)), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", ".2F8....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_roadsign), null) local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), sign), null) } catch (e) { ASSERT_EQUAL(e, "Tool has no effects") error_caught = true } ASSERT_TRUE(error_caught) } // remove stuff ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 3, 0), coord3d(3, 3, 0), "" + wt_road), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 1, 0), coord3d(2, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_sign_build_signal() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local remover = command_x(tool_remover) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local signal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_signal())[0] local presignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_pre_signal())[0] local priosignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_priority_signal())[0] local lbsignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_longblock_signal())[0] local chsignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_choose_sign())[0] local eocsignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_end_choose_signal())[0] local all_signals = [ signal, presignal, priosignal, lbsignal, chsignal, eocsignal ] foreach (s in all_signals) { ASSERT_TRUE(s != null) } { // Build signs on flat ground, should fail foreach (s in all_signals) { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), s), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_signal), null) } } ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 0, 0), coord3d(2, 7, 0), road, true), null) { // Rail signals on road, should fail foreach (s in all_signals) { local error_caught = false try { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(2, 3, 0), s), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Tool has no effects") } ASSERT_TRUE(error_caught) ASSERT_EQUAL(tile_x(2, 3, 0).find_object(mo_signal), null) } } ASSERT_EQUAL(wayremover.work(pl, coord3d(2, 0, 0), coord3d(2, 7, 0), "" + wt_road), null) // build signals { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(2, i, 0), rail, true), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(1, i, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "........", "........" ]) } // make signals directional { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(2, i, 0), rail, true), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(1, i, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "288.....", "288.....", "288.....", "288.....", "288.....", "2A8.....", "........", "........" ]) } // signals into different direction { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(2, i, 0), rail, true), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(1, i, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(1, i, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "2A8.....", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "228.....", "228.....", "228.....", "228.....", "228.....", "2A8.....", "........", "........" ]) } // build way across signal { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 0, 0), coord3d(1, all_signals.len()-1, 0), rail, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "2E8.....", "2F8.....", "2F8.....", "2F8.....", "2F8.....", "2B8.....", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "268.....", "278.....", "278.....", "278.....", "278.....", "2B8.....", "........", "........" ]) } // remove everything { foreach (i, s in all_signals) { ASSERT_EQUAL(wayremover.work(pl, coord3d(0, i, 0), coord3d(2, i, 0), "" + wt_rail), null) } ASSERT_EQUAL(wayremover.work(pl, coord3d(1, 0, 0), coord3d(1, all_signals.len()-1, 0), "" + wt_rail), null) } // build signals, dir 2 { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(i, 0, 0), coord3d(i, 2, 0), rail, true), null) ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(i, 1, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "444444..", "555555..", "111111..", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "444444..", "555555..", "111111..", "........", "........", "........", "........", "........" ]) } // make signals directional, dir 2 { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(i, 1, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "444444..", "555555..", "111111..", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "444444..", "444445..", "111111..", "........", "........", "........", "........", "........" ]) } // signals into different direction, dir 2 { foreach (i, s in all_signals) { ASSERT_EQUAL(command_x.build_sign_at(pl, coord3d(i, 1, 0), s), null) if (s == eocsignal) { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_roadsign) != null) // for end-of-choose } else { ASSERT_TRUE(tile_x(i, 1, 0).find_object(mo_signal) != null) } } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "444444..", "555555..", "111111..", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "444444..", "111115..", "111111..", "........", "........", "........", "........", "........" ]) } // build way across signal { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 1, 0), coord3d(all_signals.len()-1, 1, 0), rail, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "444444..", "7FFFFD..", "111111..", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "444444..", "3BBBBD..", "111111..", "........", "........", "........", "........", "........" ]) } // remove everything again { foreach (i, s in all_signals) { ASSERT_EQUAL(wayremover.work(pl, coord3d(i, 2, 0), coord3d(i, 0, 0), "" + wt_rail), null) } ASSERT_EQUAL(wayremover.work(pl, coord3d(0, 1, 0), coord3d(all_signals.len()-1, 1, 0), "" + wt_rail), null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_sign_build_signal_multiple() { local pl = player_x(0) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local signal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_signal())[0] // starts on way end, not possible { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 2, 0), coord3d(7, 2, 0), rail, true), null) ASSERT_EQUAL(command_x(tool_build_roadsign).work(pl, coord3d(0, 2, 0), coord3d(7, 2, 0), signal.get_name()), "Hier kann kein\nSignal aufge-\nstellt werden!\n") for (local x = 2; x <= 7; ++x) { ASSERT_EQUAL(tile_x(x, 2, 0).find_object(mo_signal), null) } ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "2AAAAAA8", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(0, 2, 0), coord3d(7, 2, 0), "" + wt_rail), null) } // FIXME click-and-drag for tools using script is not supported { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 2, 0), coord3d(7, 2, 0), rail, true), null) local error_caught = false try { command_x(tool_build_roadsign).work(pl, coord3d(1, 2, 0), coord3d(6, 2, 0), signal.get_name()) } catch (e) { ASSERT_EQUAL(e, "First click has side effects") error_caught = true } ASSERT_EQUAL(error_caught, true) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(0, 2, 0), coord3d(7, 2, 0), "" + wt_rail), null) } RESET_ALL_PLAYER_FUNDS() } function test_sign_replace_signal() { local pl = player_x(0) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local signal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_signal())[0] local presignal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_pre_signal())[0] // preconditions ASSERT_TRUE(signal != null) ASSERT_TRUE(presignal != null) ASSERT_TRUE(rail != null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(6, 3, 0), rail, true), null) ASSERT_EQUAL(command_x(tool_build_roadsign).work(pl, coord3d(5, 3, 0), signal.name), null) // replace two-directional signals { local old_cash = pl.current_cash * 100 local old_maint = pl.current_maintenance command_x(tool_build_roadsign).work(pl, coord3d(5, 3, 0), presignal.name) local s = sign_x(5, 3, 0) ASSERT_TRUE(s != null) ASSERT_EQUAL(s.desc.name, presignal.name) ASSERT_EQUAL(pl.current_cash * 100, old_cash - signal.cost - presignal.cost) ASSERT_EQUAL(pl.current_maintenance, old_maint + signal.maintenance - presignal.maintenance) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", "....2A8.", "........", "........", "........", "........" ]) } // make 2-way signal 1-way ASSERT_EQUAL(command_x(tool_build_roadsign).work(pl, coord3d(5, 3, 0), presignal.name), null) // and one-directional signals { local old_cash = pl.current_cash * 100 local old_maint = pl.current_maintenance command_x(tool_build_roadsign).work(pl, coord3d(5, 3, 0), signal.name) local s = sign_x(5, 3 , 0) ASSERT_TRUE(s != null) ASSERT_EQUAL(s.desc.name, signal.name) ASSERT_EQUAL(pl.current_cash * 100, old_cash - signal.cost - presignal.cost) ASSERT_EQUAL(pl.current_maintenance, old_maint - signal.maintenance + presignal.maintenance) ASSERT_WAY_PATTERN_MASKED(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", "....288.", "........", "........", "........", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(6, 3, 0), coord3d(4, 3, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_sign_signal_when_player_removed() { local pl = player_x(0) local public_pl = player_x(1) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local signal = sign_desc_x.get_available_signs(wt_rail).filter(@(idx, sign) sign.is_signal())[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(6, 3, 0), rail, true), null) ASSERT_EQUAL(command_x(tool_build_roadsign).work(public_pl, coord3d(5, 3, 0), signal.get_name()), null) { world.remove_player(pl) ASSERT_EQUAL(tile_x(5, 3, 0).find_object(mo_way), null) ASSERT_TRUE(tile_x(5, 3, 0).find_object(mo_signal) != null) } ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(5, 3, 0)), null) ASSERT_TRUE(tile_x(5, 3, 0).find_object(mo_signal) == null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_slope.nut000066400000000000000000000170701474050137200207750ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Test set_/can_set_slope // function test_slope_to_dir() { local slope_to_dir = {} slope_to_dir[slope.north] <- dir.south slope_to_dir[slope.east ] <- dir.west slope_to_dir[slope.south] <- dir.north slope_to_dir[slope.west ] <- dir.east slope_to_dir[2*slope.north] <- dir.south slope_to_dir[2*slope.east ] <- dir.west slope_to_dir[2*slope.south] <- dir.north slope_to_dir[2*slope.west ] <- dir.east for (local sl = 0; sl < 81; ++sl) { if (sl in slope_to_dir) { ASSERT_EQUAL(slope.to_dir(sl), slope_to_dir[sl]) } else { ASSERT_EQUAL(slope.to_dir(sl), dir.none) } } } function test_slope_can_set() { local pl = player_x(0) local pos = coord3d(2, 3, 0) for (local sl = 0; sl < slope.raised; ++sl) { for (local target_sl = 0; target_sl < slope.raised; ++target_sl) { command_x.set_slope(pl, pos, sl) ASSERT_EQUAL(tile_x(2, 3, 0).get_slope(), sl) RESET_ALL_PLAYER_FUNDS() local expected = "" ASSERT_EQUAL(command_x.can_set_slope(pl, pos, sl), expected) local sq = square_x(2, 3) ASSERT_TRUE(sq != null && sq.is_valid()) ASSERT_EQUAL(sq.get_climate(), cl_mediterran) local tile = sq.get_tile_at_height(0) ASSERT_TRUE(tile != null && tile.is_valid()) ASSERT_EQUAL(tile.get_slope(), sl) ASSERT_EQUAL(pl.get_current_cash(), 200000) // get_current_cash is in credits (returns float) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000*100) // get_current_net_wealth is in 1/100 credits } } // reset to normal slope command_x.set_slope(pl, pos + coord3d(0, 0, 1), slope.all_down_slope) command_x.set_slope(pl, pos, slope.all_down_slope) RESET_ALL_PLAYER_FUNDS() ASSERT_EQUAL(command_x.can_set_slope(pl, pos + coord3d(0, 0, 1), slope.all_up_slope), "") ASSERT_EQUAL(command_x.can_set_slope(pl, pos - coord3d(0, 0, 1), slope.all_down_slope), "") ASSERT_EQUAL(pl.get_current_cash(), 200000) // get_current_cash is in credits (returns float) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000*100) // get_current_net_wealth is in 1/100 credits RESET_ALL_PLAYER_FUNDS() } function test_slope_set_and_restore() { local pl = player_x(0) local setslope = command_x.set_slope local restoreslope = command_x(tool_restoreslope) { ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 0), slope.north), null) ASSERT_EQUAL(tile_x(2, 3, 0).get_slope(), slope.north) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 0), slope.south), null) ASSERT_EQUAL(tile_x(2, 3, 0).get_slope(), slope.south) ASSERT_EQUAL(restoreslope.work(pl, coord3d(2, 3, 0)), null) ASSERT_EQUAL(tile_x(2, 3, 0).get_slope(), slope.flat) } { ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 0), slope.all_up_slope), null) ASSERT_TRUE(tile_x(2, 3, 0).is_valid()) ASSERT_TRUE(tile_x(2, 3, 1).is_valid()) ASSERT_EQUAL(tile_x(2, 3, 1).get_slope(), slope.flat) // fails as expected because ground is 1 unit higher ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 0), slope.all_up_slope), "") // TODO check tile height ASSERT_EQUAL(restoreslope.work(pl, coord3d(2, 3, 0)), "") ASSERT_TRUE(tile_x(2, 3, 0).is_valid()) ASSERT_EQUAL(tile_x(2, 3, 0).get_slope(), slope.flat) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 1), slope.all_down_slope), null) ASSERT_EQUAL(tile_x(2, 3, 1).get_slope(), slope.flat) } RESET_ALL_PLAYER_FUNDS() } function test_slope_set_near_map_border() { local pl = player_x(0) local setslope = command_x.set_slope // map edge { for (local sl = 0; sl < slope.raised; ++sl) { ASSERT_EQUAL(setslope(pl, coord3d(0, 3, 0), sl), "Zu nah am Kartenrand") } } // map corner { for (local sl = 0; sl < slope.raised; ++sl) { ASSERT_EQUAL(setslope(pl, coord3d(0, 0, 0), sl), "Zu nah am Kartenrand") } } RESET_ALL_PLAYER_FUNDS() } function test_slope_max_height_diff() { local pl = player_x(0) local setslope = command_x.set_slope // build upwards, height difference = 4 { ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 1), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 2), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 3), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 4), slope.all_up_slope), "Maximum tile height difference reached.") } // diagonally, the height difference is unlimited (technically limited to 2*max_diff) { ASSERT_EQUAL(setslope(pl, coord3d(2, 3, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -2), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -3), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -4), slope.all_down_slope), "Maximum tile height difference reached.") } // and clean up ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 4), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 3), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 2), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -4), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -3), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -2), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(2, 3, -1), slope.all_up_slope), null) RESET_ALL_PLAYER_FUNDS() } function test_slope_get_price() { local pl = player_x(0) for (local sl = 0; sl < slope.raised; ++sl) { ASSERT_EQUAL(command_x.slope_get_price(slope.flat), 2000 * 100) } local restore_slope = 84 ASSERT_EQUAL(command_x.slope_get_price(restore_slope), 1500 * 100) ASSERT_EQUAL(pl.get_current_cash(), 200000) // get_current_cash is in credits (returns float) ASSERT_EQUAL(pl.get_current_net_wealth(), 200000*100) // get_current_net_wealth is in 1/100 credits RESET_ALL_PLAYER_FUNDS() } function test_slope_restore_on_foundation() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_house).work(pl, coord3d(4, 2, 0), "11RES_01_23"), null) { ASSERT_EQUAL(command_x(tool_restoreslope).work(pl, coord3d(4, 2, 0)), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(1), coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_slope_restore_on_bridge() { local pl = player_x(0) local rail_bridge = bridge_desc_x.get_available_bridges(wt_rail)[0] ASSERT_TRUE(rail_bridge != null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 4, 0), slope.north), null) ASSERT_EQUAL(command_x(tool_build_bridge).work(pl, coord3d(4, 2, 0), rail_bridge.get_name()), null) { ASSERT_EQUAL(command_x(tool_restoreslope).work(pl, coord3d(4, 2, 0)), "No suitable ground!") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 2, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 4, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_slope_restore_on_label() { local pl = player_x(0) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(label_x.create(coord(4, 2), pl, "foo"), null) { ASSERT_EQUAL(command_x(tool_restoreslope).work(pl, coord3d(4, 2, 0)), "Tile not empty.") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(4, 2, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_terraform.nut000066400000000000000000000517301474050137200216550ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for terraforming terrain // function test_terraform_raise_lower_land() { // TODO check terrain height local err = command_x.grid_raise(player_x(0), coord(3, 2)) ASSERT_EQUAL(err, "Zu nah am Kartenrand") // TODO Fix error message? ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 100)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 1)), null) // clean up ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_terraform_raise_lower_land_at_map_border() { // TODO Check terrain height ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord(0, 0)), "Zu nah am Kartenrand") ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(0, 0, 100)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(0, 0, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(0, 0, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(0, 0, 1)), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(0, 0, 1)), null) // clean up ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(0, 0, 0)), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(0, 0, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_terraform_raise_lower_land_at_water_center() { local clim = command_x(tool_set_climate) { clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water) // raise center piece local err = command_x.grid_lower(player_x(0), coord3d(3, 3, 0)) ASSERT_EQUAL(err, "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } { clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water) // lower center piece local err = command_x.grid_lower(player_x(0), coord3d(3, 3, 0)) ASSERT_EQUAL(err, "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } RESET_ALL_PLAYER_FUNDS() } function test_terraform_raise_lower_land_at_water_corner() { local clim = command_x(tool_set_climate) // FIXME inconsistencies with raising/lowering depending on direction // raise north-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(2, 2, 0)), "") ASSERT_FALSE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // lower north-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(2, 2, 0)), "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // raise south-east corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(2, 4, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(2, 4, 0)), null) } // lower south-east corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(2, 4, 0)), null) ASSERT_FALSE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(2, 4, 0)), null) } // raise south-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 4, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 4, 0)), null) } // lower south-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 4, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 4, 0)), null) } // raise north-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 2, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 2, 0)), null) } // lower north-west corner { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 2, 0)), null) ASSERT_FALSE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 2, 0)), null) } // clean up ASSERT_EQUAL(clim.work(player_x(0), coord3d(3, 2, 0), coord3d(2, 3, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_terraform_raise_lower_land_at_water_edge() { local clim = command_x(tool_set_climate) // FIXME inconsistencies with raising/lowering depending on direction // raise north edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 2, 0)), "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // lower north edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 2, 0)), "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // raise east edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 3, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 3, 0)), null) } // lower east edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(4, 3, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(4, 3, 0)), null) } // raise south edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 4, 0)), null) ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 4, 0)), null) } // lower south edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(3, 4, 0)), null) ASSERT_FALSE(tile_x(2, 2, 0).is_water()) ASSERT_FALSE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_FALSE(tile_x(3, 3, 0).is_water()) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(3, 4, 0)), null) } // raise west edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_raise(player_x(0), coord3d(2, 3, 0)), "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_FALSE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // lower west edge { ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_water), null) ASSERT_EQUAL(command_x.grid_lower(player_x(0), coord3d(2, 3, 0)), "") ASSERT_TRUE(tile_x(2, 2, 0).is_water()) ASSERT_TRUE(tile_x(3, 2, 0).is_water()) ASSERT_TRUE(tile_x(2, 3, 0).is_water()) ASSERT_TRUE(tile_x(3, 3, 0).is_water()) } // clean up ASSERT_EQUAL(clim.work(player_x(0), coord3d(2, 3, 0), coord3d(3, 2, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS() } function test_terraform_raise_lower_land_below_way() { local pl = player_x(0) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local setslope = command_x.set_slope ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) // raise below way { ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 4, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 5, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 2, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 3, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 4, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(5, 5, 0)), "Tile not empty.") } // and lower { ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 4, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 5, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 2, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 3, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 4, 0)), "Tile not empty.") ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(5, 5, 0)), "Tile not empty.") } // set slope up { ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.south), "") ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), 2*slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.north), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.north), "") ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), 2*slope.north), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), null) } // set slope down { ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 2, 0), slope.all_down_slope), "") ASSERT_EQUAL(setslope(pl, coord3d(4, 2, -1), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(4, 4, 0), slope.all_down_slope), "") ASSERT_EQUAL(setslope(pl, coord3d(4, 4, -1), slope.all_up_slope), null) } // non-dead-end, should fail for all slopes { for (local sl = slope.flat+1; sl <= slope.all_down_slope; ++sl) { if (sl != slope.raised && sl != 81) { ASSERT_EQUAL(setslope(pl, coord3d(4, 3, 0), sl), "Tile not empty.") } } } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } /// Helper function: Raise / lower land along the edge of a rectangular region function terraform_volcano(pl, pos, size, h) { local raise = h > 0 local tool = raise ? command_x.grid_raise : command_x.grid_lower for (local dz = 0; raise ? dzh; dz += raise?1:-1) { for (local i = 0; i 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.passenger, to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 30) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 30) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 30) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 30) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_mail_valid_route() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 2, 0), coord3d(4, 8, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 2, 0), "PostStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 7, 0), "PostStop"), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 8, 0), building_desc_x("CarDepot")), null) local depot = depot_x(4, 8, 0) local from_halt = halt_x.get_halt(coord3d(4, 7, 0), pl) local to_halt = halt_x.get_halt(coord3d(4, 2, 0), pl) // create vehicle ... depot.append_vehicle(pl, convoy_x(0), vehicle_desc_x("Posttransporter")) local cnv = depot.get_convoy_list()[0] // ... with simple 2-entry schedule ... cnv.change_schedule(pl, create_simple_schedule(wt_road, [ coord3d(4, 7, 0), coord3d(4, 2, 0) ])) // and start the convoy depot.start_all_convoys(pl) // make sure that the graph linking and all halts is updated while(!halt_x.is_rerouting_finished()) { sleep() } { ASSERT_EQUAL(world.generate_goods(coord(3, 7), coord(3, 2), good_desc_x.mail, 30), 1) // 1 == OK } sleep() sleep() { ASSERT_EQUAL(from_halt.waiting[0], 30) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.mail, to_halt), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(3, 2, 0)), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 0) ASSERT_EQUAL(from_halt.arrived[0], 0) ASSERT_EQUAL(from_halt.convoys[0], 0) } while (from_halt.convoys[0] == 0) { sleep() } // Loading is not instant, so we need to make sure loading has finished while (from_halt.waiting[0] > 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.mail, to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 30) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 30) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 30) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_freight_valid_route() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 2, 0), coord3d(4, 8, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 7, 0), coord3d(5, 7, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 2, 0), "CarStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(5, 7, 0), "CarStop"), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 8, 0), building_desc_x("CarDepot")), null) local depot = depot_x(4, 8, 0) local from_halt = halt_x.get_halt(coord3d(5, 7, 0), pl) local to_halt = halt_x.get_halt(coord3d(4, 2, 0), pl) // create vehicle ... depot.append_vehicle(pl, convoy_x(0), vehicle_desc_x("Kohletransporter")) local cnv = depot.get_convoy_list()[0] // ... with simple 2-entry schedule ... cnv.change_schedule(pl, create_simple_schedule(wt_road, [ coord3d(5, 7, 0), coord3d(4, 2, 0) ])) // and start the convoy depot.start_all_convoys(pl) // make sure that the graph linking and all halts is updated while(!halt_x.is_rerouting_finished()) { sleep() } { ASSERT_EQUAL(world.generate_goods(coord(3, 7), coord(3, 2), good_desc_x("Kohle"), 18), 1) // 1 == OK } sleep() sleep() { ASSERT_EQUAL(from_halt.waiting[0], 18) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x("Kohle"), to_halt), 18) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(3, 2, 0)), 18) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 0) ASSERT_EQUAL(from_halt.arrived[0], 0) ASSERT_EQUAL(from_halt.convoys[0], 0) } while (from_halt.convoys[0] == 0) { sleep() } // Loading is not instant, so we need to make sure loading has finished while (from_halt.waiting[0] > 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x("Kohle"), to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 18) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 18) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 18) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(5, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(5, 7, 0), coord3d(4, 7, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } // // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // function create_simple_schedule(waytype, stop_positions) { return schedule_x(waytype, stop_positions.map(@(pos) schedule_entry_x(pos, 0, 0))) } // // Tests for transporting passengers, mail and goods // function test_transport_generate_pax_invalid_pos() { ASSERT_EQUAL(world.generate_goods(coord(-1, -1), coord(-1, -1), good_desc_x.passenger, 42), 0) ASSERT_EQUAL(world.generate_goods(coord( 0, 0), coord(-1, -1), good_desc_x.passenger, 42), 0) ASSERT_EQUAL(world.generate_goods(coord(-1, -1), coord( 0, 0), good_desc_x.passenger, 42), 0) } function test_transport_generate_pax_walked() { ASSERT_EQUAL(command_x(tool_build_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 3, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 2, 0), "BusStop"), null) { ASSERT_EQUAL(world.generate_goods(coord(3, 2), coord(5, 2), good_desc_x.passenger, 42), 2) // 2 == walked ASSERT_EQUAL(halt_x.get_halt(coord3d(4, 2, 0), player_x(0)).get_walked()[0], 42) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 3, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_generate_pax_no_route() { ASSERT_EQUAL(command_x(tool_build_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 7, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 2, 0), "BusStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(player_x(0), coord3d(4, 7, 0), "BusStop"), null) { ASSERT_EQUAL(world.generate_goods(coord(3, 2), coord(3, 7), good_desc_x.passenger, 42), 0) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 7, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_pax_valid_route() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 2, 0), coord3d(4, 8, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 2, 0), "BusStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 7, 0), "BusStop"), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 8, 0), building_desc_x("CarDepot")), null) local depot = depot_x(4, 8, 0) local from_halt = halt_x.get_halt(coord3d(4, 7, 0), pl) local to_halt = halt_x.get_halt(coord3d(4, 2, 0), pl) // create vehicle ... depot.append_vehicle(pl, convoy_x(0), vehicle_desc_x("Buessig")) local cnv = depot.get_convoy_list()[0] // ... with simple 2-entry schedule ... cnv.change_schedule(pl, create_simple_schedule(wt_road, [ coord3d(4, 7, 0), coord3d(4, 2, 0) ])) // and start the convoy depot.start_all_convoys(pl) // make sure that the graph linking all halts is updated // make sure that the graph linking and all halts is updated while(!halt_x.is_rerouting_finished()) { sleep() } { ASSERT_EQUAL(world.generate_goods(coord(3, 7), coord(3, 2), good_desc_x.passenger, 30), 1) // 1 == OK ASSERT_EQUAL(from_halt.waiting[0], 30) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.passenger, to_halt), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(3, 2, 0)), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 30) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 0) ASSERT_EQUAL(from_halt.arrived[0], 0) ASSERT_EQUAL(from_halt.convoys[0], 0) } while (from_halt.convoys[0] == 0) { sleep() } // Loading is not instant, so we need to make sure loading has finished while (from_halt.waiting[0] > 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.passenger, to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.passenger, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 30) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 30) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 30) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 30) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_mail_valid_route() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 2, 0), coord3d(4, 8, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 2, 0), "PostStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 7, 0), "PostStop"), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 8, 0), building_desc_x("CarDepot")), null) local depot = depot_x(4, 8, 0) local from_halt = halt_x.get_halt(coord3d(4, 7, 0), pl) local to_halt = halt_x.get_halt(coord3d(4, 2, 0), pl) // create vehicle ... depot.append_vehicle(pl, convoy_x(0), vehicle_desc_x("Posttransporter")) local cnv = depot.get_convoy_list()[0] // ... with simple 2-entry schedule ... cnv.change_schedule(pl, create_simple_schedule(wt_road, [ coord3d(4, 7, 0), coord3d(4, 2, 0) ])) // and start the convoy depot.start_all_convoys(pl) // make sure that the graph linking all halts is updated // make sure that the graph linking and all halts is updated while(!halt_x.is_rerouting_finished()) { sleep() } { ASSERT_EQUAL(world.generate_goods(coord(3, 7), coord(3, 2), good_desc_x.mail, 30), 1) // 1 == OK } sleep() sleep() { ASSERT_EQUAL(from_halt.waiting[0], 30) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.mail, to_halt), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(3, 2, 0)), 30) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 0) ASSERT_EQUAL(from_halt.arrived[0], 0) ASSERT_EQUAL(from_halt.convoys[0], 0) } while (from_halt.convoys[0] == 0) { sleep() } // Loading is not instant, so we need to make sure loading has finished while (from_halt.waiting[0] > 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x.mail, to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x.mail, coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 30) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 30) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 30) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_transport_freight_valid_route() { local pl = player_x(0) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 2, 0), coord3d(4, 8, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_way).work(pl, coord3d(4, 7, 0), coord3d(5, 7, 0), "cobblestone_road"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(4, 2, 0), "CarStop"), null) ASSERT_EQUAL(command_x(tool_build_station).work(pl, coord3d(5, 7, 0), "CarStop"), null) ASSERT_EQUAL(command_x.build_depot(pl, coord3d(4, 8, 0), building_desc_x("CarDepot")), null) local depot = depot_x(4, 8, 0) local from_halt = halt_x.get_halt(coord3d(5, 7, 0), pl) local to_halt = halt_x.get_halt(coord3d(4, 2, 0), pl) // create vehicle ... depot.append_vehicle(pl, convoy_x(0), vehicle_desc_x("Kohletransporter")) local cnv = depot.get_convoy_list()[0] // ... with simple 2-entry schedule ... cnv.change_schedule(pl, create_simple_schedule(wt_road, [ coord3d(5, 7, 0), coord3d(4, 2, 0) ])) // and start the convoy depot.start_all_convoys(pl) // make sure that the graph linking all halts is updated // make sure that the graph linking and all halts is updated while(!halt_x.is_rerouting_finished()) { sleep() } { ASSERT_EQUAL(world.generate_goods(coord(3, 7), coord(3, 2), good_desc_x("Kohle"), 18), 1) // 1 == OK } sleep() sleep() { ASSERT_EQUAL(from_halt.waiting[0], 18) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x("Kohle"), to_halt), 18) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(3, 2, 0)), 18) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 0) ASSERT_EQUAL(from_halt.arrived[0], 0) ASSERT_EQUAL(from_halt.convoys[0], 0) } while (from_halt.convoys[0] == 0) { sleep() } // Loading is not instant, so we need to make sure loading has finished while (from_halt.waiting[0] > 0) { sleep() } { ASSERT_EQUAL(from_halt.convoys[0], 1) ASSERT_EQUAL(from_halt.waiting[0], 0) ASSERT_EQUAL(from_halt.get_freight_to_halt(good_desc_x("Kohle"), to_halt), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(3, 2, 0)), 0) ASSERT_EQUAL(from_halt.get_freight_to_dest(good_desc_x("Kohle"), coord3d(4, 2, 0)), 0) ASSERT_EQUAL(from_halt.happy[0], 0) ASSERT_EQUAL(from_halt.unhappy[0], 0) ASSERT_EQUAL(from_halt.noroute[0], 0) ASSERT_EQUAL(from_halt.walked[0], 0) ASSERT_EQUAL(from_halt.departed[0], 18) ASSERT_EQUAL(from_halt.arrived[0], 0) } while (to_halt.convoys[0] == 0) { sleep() } // make sure unloading has finished while (to_halt.arrived[0] < 18) { sleep() } { ASSERT_EQUAL(to_halt.waiting[0], 0) ASSERT_EQUAL(to_halt.happy[0], 0) ASSERT_EQUAL(to_halt.unhappy[0], 0) ASSERT_EQUAL(to_halt.noroute[0], 0) ASSERT_EQUAL(to_halt.walked[0], 0) ASSERT_EQUAL(to_halt.departed[0], 0) ASSERT_EQUAL(to_halt.arrived[0], 18) } // clean up cnv.destroy(pl) sleep() sleep() // make sure the convoy is destroyed ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(5, 7, 0)), null) ASSERT_EQUAL(command_x(tool_remover).work(player_x(0), coord3d(4, 8, 0)), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(4, 2, 0), coord3d(4, 8, 0), "" + wt_road), null) ASSERT_EQUAL(command_x(tool_remove_way).work(player_x(0), coord3d(5, 7, 0), coord3d(4, 7, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_trees.nut000066400000000000000000000207711474050137200207770ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for building trees and forests // function build_tree(pl, pos, desc, ignore_climate = false, random_age = false) { return command_x(tool_plant_tree).work(pl, pos, "" + ignore_climate.tointeger() + random_age.tointeger() + "," + desc.get_name()) } function test_trees_plant_single_invalid_pos() { local pl = player_x(0) local public_pl = player_x(1) local tree_desc = tree_desc_x("Ahorn-1") ASSERT_TRUE(tree_desc != null) // build outside of map borders, should fail (obv) { ASSERT_EQUAL(build_tree(public_pl, coord3d(100, 100, 0), tree_desc), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_invalid_param() { local public_pl = player_x(1) // invalid default_param -> don't crash { local error_caught = false try { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), "1"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) == null) } // invalid default_param -> don't crash { local error_caught = false try { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), "11"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) == null) } // invalid default_param -> don't crash { local error_caught = false try { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), "11,"), "") } catch (e) { error_caught = true ASSERT_EQUAL(e, "Error during initializing tool") } ASSERT_TRUE(error_caught) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) == null) } // clean up RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_null_param() { local public_pl = player_x(1) // null default_param -> random tree { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), null), null) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_empty_param() { local public_pl = player_x(1) // empty default_param -> random tree { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), ""), null) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_invalid_desc() { local public_pl = player_x(1) // invalid desc name -> random tree { ASSERT_EQUAL(command_x(tool_plant_tree).work(public_pl, coord3d(4, 2, 0), "11,bla"), null) ASSERT_TRUE(tile_x(4, 2, 0).find_object(mo_tree) != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 2, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_when_disabled() { local pl = player_x(0) local public_pl = player_x(1) local tree_desc = tree_desc_x("Ahorn-1") // build single tree, should fail because trees are disallowed { ASSERT_EQUAL(build_tree(pl, coord3d(4, 3, 0), tree_desc), "Trees disabled!") ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_tree), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) } // public player can build trees anyway { ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) local tree = tile_x(4, 3, 0).find_object(mo_tree) ASSERT_TRUE(tree != null) ASSERT_EQUAL(tree.get_desc().get_name(), tree_desc.get_name()) ASSERT_EQUAL(public_pl.get_current_maintenance(), 0) ASSERT_TRUE(tree.get_owner() != null) // tree is owned by everybody (player_all) but there is no way to check for player == player_all ASSERT_EQUAL(tree.get_age(), 0) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_random_age() { local public_pl = player_x(1) local tree_desc = tree_desc_x("Ahorn-1") // check planting with random age { ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc, false, true), null) local tree = tile_x(4, 3, 0).find_object(mo_tree) ASSERT_TRUE(tree != null) ASSERT_EQUAL(tree.get_desc().get_name(), tree_desc.get_name()) ASSERT_EQUAL(public_pl.get_current_maintenance(), 0) ASSERT_TRUE(tree.get_owner() != null) // tree is owned by everybody (player_all) but there is no way to check for player == player_all ASSERT_TRUE(tree.get_age() >= 0) ASSERT_TRUE(tree.get_age() < (1<<12)) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 3, 0)), null) RESET_ALL_PLAYER_FUNDS(); } function test_trees_plant_single_ignore_climate() { local public_pl = player_x(1) local tree_desc = tree_desc_x("Ahorn-1") ASSERT_EQUAL(command_x(tool_set_climate).work(public_pl, coord3d(4, 3, 0), coord3d(4, 3, 0), "" + cl_arctic), null) // Check planting with ignore_climate = true { ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc, false, false), "") ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_tree), null) ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc, true, false), null) ASSERT_TRUE(tile_x(4, 3, 0).find_object(mo_tree) != null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x(tool_set_climate).work(public_pl, coord3d(4, 3, 0), coord3d(4, 3, 0), "" + cl_mediterran), null) RESET_ALL_PLAYER_FUNDS(); } function test_trees_plant_single_max_per_square() { local public_pl = player_x(1) local tree_desc = tree_desc_x("Ahorn-1") ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), null) // Check building over max_no_of_trees_on_square limit (= 5) { ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 3, 0), tree_desc), "") } // clean up ASSERT_EQUAL(command_x(tool_remover).work(public_pl, coord3d(4, 3, 0)), null) // removes all trees at once ASSERT_EQUAL(tile_x(4, 3, 0).find_object(mo_tree), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_single_occupied() { local pl = player_x(0) local public_pl = player_x(1) local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] local tree_desc = tree_desc_x("Ahorn-1") ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(4, 5, 0), road, true), null) // Cannot build trees on ways { ASSERT_EQUAL(build_tree(public_pl, coord3d(4, 4, 0), tree_desc), "") ASSERT_EQUAL(tile_x(4, 4, 0).find_object(mo_tree), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(4, 3, 0), coord3d(4, 5, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_trees_plant_forest() { local pl = player_x(0) local public_pl = player_x(1) local planter = command_x(tool_forest) local tree_desc = tree_desc_x("Busch_1") local topleft = coord3d(1, 1, 0) local bottomright = coord3d(6, 6, 0) // 1x1 { ASSERT_EQUAL(planter.work(public_pl, topleft, topleft, ""), null) ASSERT_EQUAL(tile_x(topleft.x, topleft.y, 0).find_object(mo_tree), null) } // 2x2 { ASSERT_EQUAL(planter.work(public_pl, topleft, topleft + coord(1, 1), ""), null) ASSERT_EQUAL(tile_x(topleft.x+0, topleft.y+0, 0).find_object(mo_tree), null) ASSERT_EQUAL(tile_x(topleft.x+1, topleft.y+0, 0).find_object(mo_tree), null) ASSERT_EQUAL(tile_x(topleft.x+0, topleft.y+1, 0).find_object(mo_tree), null) ASSERT_TRUE(tile_x(topleft.x+1, topleft.y+1, 0).find_object(mo_tree) != null) } // this works with player 0 even though trees are disabled { ASSERT_EQUAL(planter.work(pl, topleft, bottomright, ""), null) for (local y = 0; y < 8; ++y) { for (local x = 0; x < 8; ++x) { local outside = ((y+1)%8 < 3) || ((x+1)%8 < 3) // FIXME: this should fail for == 2 if (outside) { ASSERT_EQUAL(tile_x(x, y, 0).find_object(mo_tree), null) } } } ASSERT_EQUAL(pl.get_current_maintenance(), 0) } // clean up for (local y = 0; y < 8; ++y) { for (local x = 0; x < 8; ++x) { command_x(tool_remover).work(pl, coord3d(x, y, 0)) } } RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_way_bridge.nut000066400000000000000000000403251474050137200217660ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for bridge building / removal // function test_way_bridge_build_ground() { local pl = player_x(0) local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] local remover = command_x(tool_remove_way) ASSERT_TRUE(bridge_desc != null) // build bridge on flat ground ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(3, 5, 0), coord3d(3, 2, 0), bridge_desc), null) { // test bridge object local t = tile_x(3, 5, 0) local bridge = t.find_object(mo_bridge) ASSERT_TRUE(bridge != null) ASSERT_EQUAL(bridge.get_desc().get_name(), bridge_desc.get_name()) } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "...5....", "...0....", "...0....", "...5....", "...1....", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) // build bridge over bridgehead (should fail) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), bridge_desc), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) // build bridgehead slope under bridge (should fail) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(3, 3, 0), coord3d(5, 3, 0), bridge_desc), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) // build bridge crossing (should fail) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), bridge_desc), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) ASSERT_EQUAL(remover.work(pl, tile_x(3, 1, 0), tile_x(3, 6, 0), "" + wt_road), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } function test_way_bridge_build_at_slope() { local start_pos = coord3d(2, 1, 0) local end_pos = coord3d(2, 6, 0) local remover = command_x(tool_remove_way) local setslope = command_x.set_slope local pl = player_x(0) local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] ASSERT_EQUAL(setslope(pl, coord3d(2, 1, 0), slope.south), null) { // down slope local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, "Bridge is too long for this type!\n") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // wrong single-height slope ASSERT_EQUAL(setslope(pl, end_pos, slope.west), null) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, "A bridge must start on a way!") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // double height slope ASSERT_EQUAL(setslope(pl, end_pos, 2*slope.north), null) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, "Cannot connect to the\ncenter of a double slope!") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // wrong double height slope ASSERT_EQUAL(setslope(pl, end_pos, 2*slope.west), null) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, "Cannot connect to the\ncenter of a double slope!") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { // flat double height slope (i.e. 2 stacked flat slopes) ASSERT_EQUAL(setslope(pl, end_pos, slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, end_pos + coord3d(0, 0, 1), slope.all_up_slope), null) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, "Cannot connect to the\ncenter of a double slope!") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(setslope(pl, end_pos + coord3d(0, 0, 2), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, end_pos + coord3d(0, 0, 1), slope.all_down_slope), null) } { // flat single height slope ASSERT_EQUAL(setslope(pl, end_pos, slope.all_up_slope), null) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "..4.....", "..5.....", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) // remove way ASSERT_EQUAL(remover.work(pl, start_pos, end_pos + coord3d(0, 0, 1), "" + wt_road), null) // remove slope ASSERT_EQUAL(setslope(pl, end_pos + coord3d(0, 0, 1), slope.all_down_slope), null) } { // correct slope setslope(pl, end_pos, slope.north) local err = command_x.build_bridge_at(pl, start_pos, bridge_desc) ASSERT_EQUAL(err, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "..4.....", "..5.....", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) // remove way ASSERT_EQUAL(remover.work(pl, start_pos, end_pos, "" + wt_road), null) // remove slope ASSERT_EQUAL(setslope(pl, end_pos, slope.flat), null) } // clean up ASSERT_EQUAL(setslope(pl, start_pos, slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_way_bridge_build_at_slope_stacked() { local remover = command_x(tool_remove_way) local setslope = command_x.set_slope local pl = player_x(0) local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] { ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.north), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 2, 0), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "...4....", "...5....", "...5....", "...1....", "........", "........" ]) // second bridge layer ASSERT_EQUAL(setslope(pl, coord3d(3, 1, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 1, 1), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 6, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 6, 1), slope.north), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 1, 1), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...4....", "...5....", "...5....", "...1....", "...1....", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 2), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) } { // remove lower bridge and rebuild it ASSERT_EQUAL(remover.work(pl, coord3d(3, 2, 0), coord3d(3, 5, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 2, 0), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "...4....", "...4....", "...5....", "...5....", "...1....", "...1....", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 2), [ "........", "...4....", "...5....", "...5....", "...5....", "...5....", "...1....", "........" ]) ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 1), coord3d(3, 6, 1), "" + wt_road), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 1, 1), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 6, 1), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 1, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 6, 1), slope.all_down_slope), null) } { // second bridge layer ASSERT_EQUAL(setslope(pl, coord3d(1, 3, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(1, 3, 1), slope.east), null) ASSERT_EQUAL(setslope(pl, coord3d(6, 3, 0), slope.all_up_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(6, 3, 1), slope.west), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(1, 3, 1), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "...4....", ".2.5..8.", "...5....", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 2), [ "........", "........", "...4....", ".2AAAA8.", "........", "...1....", "........", "........" ]) } { // remove lower bridge and rebuild it ASSERT_EQUAL(remover.work(pl, coord3d(3, 5, 0), coord3d(3, 2, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 5, 0), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "...4....", ".2.5..8.", "...5....", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 2), [ "........", "........", "...4....", ".2AAAA8.", "........", "...1....", "........", "........" ]) } // clean up ASSERT_EQUAL(remover.work(pl, coord3d(3, 2, 0), coord3d(3, 5, 0), "" + wt_road), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, 3, 1), coord3d(6, 3, 1), "" + wt_road), null) ASSERT_EQUAL(setslope(pl, coord3d(1, 3, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(1, 3, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(6, 3, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(6, 3, 1), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.all_down_slope), null) RESET_ALL_PLAYER_FUNDS() } // TODO Try to build bridge when way_height_clearance == 2 function test_way_bridge_build_above_way() { local remover = command_x(tool_remove_way) local setslope = command_x.set_slope local pl = player_x(0) local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] local way_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_TRUE(bridge_desc != null) ASSERT_TRUE(way_desc != null) { ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.north), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), way_desc, true), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 2, 0), bridge_desc), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "..2A8...", "........", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "...4....", "...5....", "...5....", "...1....", "........", "........" ]) } { // remove way, rebuild it under bridge ASSERT_EQUAL(remover.work(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), way_desc, true), null) } ASSERT_EQUAL(remover.work(pl, coord3d(2, 3, 0), coord3d(4, 3, 0), "" + wt_road), null) ASSERT_EQUAL(remover.work(pl, coord3d(3, 2, 0), coord3d(3, 5, 0), "" + wt_road), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 2, 0), slope.all_down_slope), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.all_down_slope), null) RESET_ALL_PLAYER_FUNDS() } function test_way_bridge_build_above_runway() { local pl = player_x(0) local wayremover = command_x(tool_remove_way) local taxiway = way_desc_x.get_available_ways(wt_air, st_flat)[0] local runway = way_desc_x.get_available_ways(wt_air, st_elevated)[0] local bridge = bridge_desc_x.get_available_bridges(wt_road)[0] local setslope = command_x.set_slope // preconditions // build bridge across taxiway { ASSERT_EQUAL(command_x.build_way(pl, coord3d(7, 7, 0), coord3d(7, 9, 0), taxiway, true), null) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(6, 8, 0), coord3d(8, 8, 0), bridge), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", "........", "..4.....", "..5.....", "..1.....", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(5, 5, 0), [ "........", "........", "........", "2A.A8...", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(7, 7, 0), coord3d(7, 9, 0), "" + wt_air), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(5, 8, 0), coord3d(9, 8, 0), "" + wt_road), null) } // build bridge across runway, should fail { ASSERT_EQUAL(command_x.build_way(pl, coord3d(7, 7, 0), coord3d(7, 9, 0), runway, true), null) ASSERT_EQUAL(command_x.build_bridge(pl, coord3d(6, 8, 0), coord3d(8, 8, 0), bridge), "") ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", "........", "..4.....", "..5.....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(7, 7, 0), coord3d(7, 9, 0), "" + wt_air), null) } // clean up ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_bridge_planner() { local pl = player_x(0) local start_pos = coord3d(2, 3, 0) local end_pos = coord3d(2, 6, 0) local bridge_desc = bridge_desc_x.get_available_bridges(wt_road)[0] local working_slopes = [ slope.north ] // maybe also slope.south in the future ASSERT_EQUAL(command_x.set_slope(pl, start_pos, slope.south), null) { for (local sl = slope.flat; sl < slope.raised; ++sl) { command_x.set_slope(pl, end_pos, sl) local end = bridge_planner_x.find_end(pl, start_pos, dir.south, bridge_desc, 0) local expected_end = (working_slopes.find(sl) != null) ? end_pos : coord3d(-1, -1, -1) ASSERT_EQUAL(end.tostring(), expected_end.tostring()) } ASSERT_EQUAL(command_x.set_slope(pl, end_pos, slope.all_up_slope), null) local end = bridge_planner_x.find_end(pl, start_pos, dir.south, bridge_desc, 0) ASSERT_EQUAL(end.tostring(), (end_pos + coord3d(0, 0, 1)).tostring()) // clean up ASSERT_EQUAL(command_x.set_slope(pl, start_pos, slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, end_pos + coord3d(0, 0, 1), slope.all_down_slope), null) } // min length { ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 1, 0), slope.south), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(3, 1, 0), slope.south), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 2, 0), slope.north), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(3, 3, 0), slope.north), null) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(2, 1, 0), dir.south, bridge_desc, 0).tostring(), coord3d(2, 2, 0).tostring()) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(2, 1, 0), dir.south, bridge_desc, 1).tostring(), coord3d(2, 2, 0).tostring()) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(3, 1, 0), dir.south, bridge_desc, 0).tostring(), coord3d(3, 3, 0).tostring()) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(3, 1, 0), dir.south, bridge_desc, 1).tostring(), coord3d(-1, -1, -1).tostring()) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(3, 1, 0), dir.south, bridge_desc, 2).tostring(), coord3d(3, 3, 0).tostring()) ASSERT_EQUAL(bridge_planner_x.find_end(pl, coord3d(3, 1, 0), dir.south, bridge_desc, 3).tostring(), coord3d(-1, -1, -1).tostring()) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 1, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(3, 1, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(2, 2, 0), slope.flat), null) ASSERT_EQUAL(command_x.set_slope(pl, coord3d(3, 3, 0), slope.flat), null) } ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_way_road.nut000066400000000000000000001016351474050137200214610ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for way building / removal // function test_way_road_build_single_tile() { local pl = player_x(0) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local default_cash = pl.get_current_cash() ASSERT_TRUE(road_desc != null) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), road_desc, true), "") ASSERT_EQUAL(pl.get_current_cash(), default_cash) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 2, 0), road_desc, false), "") ASSERT_EQUAL(pl.get_current_cash(), default_cash) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } RESET_ALL_PLAYER_FUNDS() } function test_way_road_build_straight() { local default_cash = 200000 * 100 local current_cash = default_cash local pl = player_x(0) local desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_TRUE(desc != null) //prerequisites ASSERT_EQUAL(pl.get_current_maintenance(), 0) local tool_result = command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 6, 0), desc, true) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) ASSERT_TRUE(pl.get_current_net_wealth() < current_cash) ASSERT_TRUE(pl.get_current_maintenance() > 0) ASSERT_TRUE(pl.get_current_cash() < default_cash / 100) current_cash = pl.get_current_net_wealth() local maintenance_per_tile = pl.get_current_maintenance() / 6 tool_result = command_x.build_way(pl, coord3d(2, 2, 0), coord3d(6, 2, 0), desc, true) ASSERT_EQUAL(tool_result, null) ASSERT_TRUE(pl.get_current_net_wealth() < current_cash) ASSERT_EQUAL(pl.get_current_maintenance(), maintenance_per_tile * (6 + 4)) ASSERT_TRUE(pl.get_current_cash() < default_cash / 100) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..7AAA8.", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) tool_result = command_x.build_way(pl, coord3d(16, 5, 0), coord3d(5, 5, 0), desc, true) ASSERT_EQUAL(tool_result, "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..7AAA8.", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) tool_result = command_x.build_way(pl, coord3d(1, 1, 1), coord3d(1, 5, 1), desc, true) ASSERT_EQUAL(tool_result, "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..7AAA8.", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) tool_result = command_x.build_way(pl, coord3d(1, 1, -1), coord3d(1, 5, -1), desc, true) ASSERT_EQUAL(tool_result, "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..7AAA8.", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) // clean up local remover = command_x(tool_remove_way) tool_result = remover.work(pl, tile_x(2, 2, 0), tile_x(6, 2, 0), "" + wt_road) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..5.....", "..5.....", "..5.....", "..1.....", "........" ]) tool_result = remover.work(pl, tile_x(2, 3, 0), tile_x(2, 4, 0), "" + wt_road) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", "..5.....", "..1.....", "..4.....", "..5.....", "..1.....", "........" ]) tool_result = remover.work(pl, tile_x(2, 1, 0), tile_x(2, 2, 0), "" + wt_road) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "..4.....", "..1.....", "..4.....", "..5.....", "..1.....", "........" ]) tool_result = remover.work(pl, tile_x(2, 2, 0), tile_x(2, 6, 0), "" + wt_road) ASSERT_EQUAL(tool_result, "Ways not connected") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "..4.....", "..1.....", "..4.....", "..5.....", "..1.....", "........" ]) tool_result = remover.work(pl, tile_x(2, 2, 0), tile_x(2, 3, 0), "" + wt_road) ASSERT_EQUAL(tool_result, null) tool_result = remover.work(pl, tile_x(2, 4, 0), tile_x(2, 6, 0), "" + wt_road) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) RESET_ALL_PLAYER_FUNDS() } function test_way_road_build_bend() { local pl = player_x(0) local desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local remover = command_x(tool_remove_way) ASSERT_TRUE(desc != null) { local tool_result = command_x.build_way(pl, coord3d(0, 1, 0), coord3d(1, 0, 0), desc, true) ASSERT_EQUAL(tool_result, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ ".4......", "29......", "........", "........", "........", "........", "........", "........" ]) remover.work(pl, tile_x(0, 1, 0), coord3d(1, 0, 0), "" + wt_road) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } { command_x.grid_raise(pl, coord3d(2, 2, 0)) local err = command_x.build_way(pl, coord3d(0, 1, 0), coord3d(1, 0, 0), desc, true) ASSERT_EQUAL(err, null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "68......", "1.......", "........", "........", "........", "........", "........", "........" ]) remover.work(pl, tile_x(0, 1, 0), coord3d(1, 0, 0), "" + wt_road) command_x.grid_lower(pl, coord3d(2, 2, 0)) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } RESET_ALL_PLAYER_FUNDS() } function test_way_road_build_parallel() { local pl = player_x(0) local desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local rail_desc = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local remover = command_x(tool_remove_way) { for (local i = 1; i < 16; ++i) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(i, i, 0), desc, true), null) } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "................", "28..............", "2A8.............", "2AA8............", "2AAA8...........", "2AAAA8..........", "2AAAAA8.........", "2AAAAAA8........", "2AAAAAAA8.......", "2AAAAAAAA8......", "2AAAAAAAAA8.....", "2AAAAAAAAAA8....", "2AAAAAAAAAAA8...", "2AAAAAAAAAAAA8..", "2AAAAAAAAAAAAA8.", "2AAAAAAAAAAAAAA8" ]) for (local i = 1; i < 16; ++i) { ASSERT_EQUAL(remover.work(pl, coord3d(0, i, 0), coord3d(i, i, 0), "" + wt_road), null) } } { for (local i = 1; i < 16; ++i) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(i, i, 0), desc, false), null) } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "................", "28..............", "2A8.............", "2AA8............", "2AAA8...........", "2AAAA8..........", "2AAAAA8.........", "2AAAAAA8........", "2AAAAAAA8.......", "2AAAAAAAA8......", "2AAAAAAAAA8.....", "2AAAAAAAAAA8....", "2AAAAAAAAAAA8...", "2AAAAAAAAAAAA8..", "2AAAAAAAAAAAAA8.", "2AAAAAAAAAAAAAA8" ]) for (local i = 1; i < 16; ++i) { ASSERT_EQUAL(remover.work(pl, coord3d(0, i, 0), coord3d(i, i, 0), "" + wt_road), null) } } { for (local i = 0; i < 16; ++i) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(15, i, 0), desc, false), null) } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8" ]) for (local i = 0; i < 16; ++i) { ASSERT_EQUAL(remover.work(pl, coord3d(0, i, 0), coord3d(15, i, 0), "" + wt_road), null) } } RESET_ALL_PLAYER_FUNDS() } function test_way_road_build_below_powerline() { local pl = player_x(0) local public_pl = player_x(1) local remover = command_x(tool_remove_way) local powerline = way_desc_x.get_available_ways(wt_power, st_flat)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_EQUAL(pl.get_current_maintenance(), 0) ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 1, 0), coord3d(3, 1, 0), powerline, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), powerline, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(1, 3, 0), powerline, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(1, 1, 0), powerline, true), null) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", ".6AC....", ".5.5....", ".3A9....", "........", "........", "........", "........" ]) // build way along powerline above, should fail { local old_maintenance = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 1, 0), coord3d(3, 1, 0), road, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) } // build way ending below power line, should succeed { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(2, 1, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(3, 2, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(2, 3, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(1, 2, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "..4.....", ".2F8....", "..1.....", "........", "........", "........", "........" ]) } // remove ways ASSERT_EQUAL(remover.work(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), "" + wt_road), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), "" + wt_road), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) // build way not ending under power line, should succeed { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(2, 0, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(2, 4, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(0, 2, 0), road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "..4.....", "..5.....", "2AFA8...", "..5.....", "..1.....", "........", "........", "........" ]) } // remove ways ASSERT_EQUAL(remover.work(pl, coord3d(2, 0, 0), coord3d(2, 4, 0), "" + wt_road), null) ASSERT_EQUAL(remover.work(pl, coord3d(0, 2, 0), coord3d(4, 2, 0), "" + wt_road), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, 1, 0), coord3d(3, 3, 0), "" + wt_power), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, 1, 0), coord3d(3, 3, 0), "" + wt_power), null) ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // build way under end of powerline, should fail ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), powerline, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), powerline, true), null) { local old_maintenance = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 1, 0), coord3d(3, 1, 0), road, true), "") ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), road, true), "") ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(1, 3, 0), road, true), "") ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 3, 0), coord3d(1, 1, 0), road, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "........", "..4.....", ".2F8....", "..1.....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } ASSERT_EQUAL(remover.work(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), "" + wt_power), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, 2, 0), coord3d(3, 2, 0), "" + wt_power), null) ASSERT_EQUAL(pl.get_current_maintenance(), 0) // add diagonal power line ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), powerline, true), null) { // build way across diagonal power line, should fail ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, 7, 0), coord3d(7, 0, 0), road, true), "") ASSERT_WAY_PATTERN(wt_power, coord3d(0, 0, 0), [ "2C......", ".3C.....", "..3C....", "...3C...", "....3C..", ".....3C.", "......3C", ".......1" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // and remove power line ASSERT_EQUAL(remover.work(pl, coord3d(0, 0, 0), coord3d(7, 7, 0), "" + wt_power), null) // clean up ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_road_build_crossing() { local pl = player_x(0) local public_pl = player_x(1) local remover = command_x(tool_remove_way) local rail = way_desc_x("sand_track") local slow_road = way_desc_x("dirt_road") local fast_road = way_desc_x("asphalt_road") // road too fast, cannot build crossing { ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), rail, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), fast_road, true), translate("No suitable crossing")) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "...4....", "...5....", "...1....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_FALSE(way_x(3, 2, 0).is_crossing()) ASSERT_FALSE(tile_x(3, 2, 0).has_two_ways()) } // road slow enough for crossing -> works { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), slow_road, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "...4....", "...5....", "...1....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "..2A8...", "........", "........", "........", "........", "........" ]) ASSERT_TRUE(way_x(3, 2, 0).is_crossing()) ASSERT_EQUAL(way_x(3, 2, 0).get_max_speed(), slow_road.get_topspeed()) ASSERT_TRUE(tile_x(3, 2, 0).has_two_ways()) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_road).get_max_speed(), slow_road.get_topspeed()) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_rail).get_max_speed(), rail.get_topspeed()) } // clean up ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_upgrade_crossing() { local pl = player_x(0) local public_pl = player_x(1) local remover = command_x(tool_remove_way) local rail = way_desc_x("sand_track") local slow_road = way_desc_x("dirt_road") local fast_road = way_desc_x("asphalt_road") ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), rail, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), slow_road, true), null) // hard-coded because there is no crossing_desc_x/crossing_x local crossing_road_speed = 80 local crossing_rail_speed = 160 // upgrade road past max crossing speed; works, but road crossing speed is limited { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), fast_road, true), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "...4....", "...5....", "...1....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "..2A8...", "........", "........", "........", "........", "........" ]) ASSERT_TRUE(way_x(3, 2, 0).is_crossing()) ASSERT_EQUAL(way_x(3, 2, 0).get_max_speed(), min(crossing_road_speed, fast_road.get_topspeed())) ASSERT_TRUE(tile_x(3, 2, 0).has_two_ways()) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_road).get_max_speed(), min(crossing_road_speed, fast_road.get_topspeed())) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_rail).get_max_speed(), min(crossing_rail_speed, rail.get_topspeed())) } // clean up ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), "" + wt_road), null) // upgrade rail with crossing; the crossing is upgraded { local fast_rail = way_desc_x("wooden_sleeper_track") ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), slow_road, true), null) // The crossing whose speed limit for rail is 80kph is built here. ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), rail, true), null) // upgrade rail. The crossing should be upgraded to the one whose speed limit for rail is 160kph. ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), fast_rail, true), null) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_road).get_max_speed(), min(crossing_road_speed, slow_road.get_topspeed())) ASSERT_EQUAL(tile_x(3, 2, 0).get_way(wt_rail).get_max_speed(), min(crossing_rail_speed, fast_rail.get_topspeed())) } // clean up ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0), coord3d(3, 3, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(2, 2, 0), coord3d(4, 2, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_upgrade_downgrade() { local pl = player_x(0) local public_pl = player_x(1) local remover = command_x(tool_remove_way) local start_pos = coord3d(4, 3, 0) local end_pos = coord3d(4, 5, 0) local all_ways = way_desc_x.get_available_ways(wt_road, st_flat) all_ways.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) ASSERT_TRUE(all_ways.len() >= 2) local slow_road = all_ways[0] local fast_road = all_ways[1] ASSERT_TRUE(slow_road.get_name() != fast_road.get_name()) ASSERT_TRUE(slow_road.get_topspeed() < fast_road.get_topspeed()) // build road ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, slow_road, true), null) // upgrade road { ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, fast_road, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "....4...", "....5...", "....1...", "........", "........" ]) } // Replace road with same road, should incur no cost { local old_cash = pl.get_current_cash() ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, fast_road, true), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "....4...", "....5...", "....1...", "........", "........" ]) } // downgrade road without ctrl; should fail // note that we cannot use command_x.buid_way for this, because there is no way to enable // ctrl-pressed behaviour (the way is replaced in any case) { local old_maintenance = pl.get_current_maintenance() local old_cash = pl.get_current_cash() local tool = command_x(tool_build_way) ASSERT_EQUAL(tool.work(pl, start_pos, end_pos, slow_road.get_name()), null) ASSERT_EQUAL(tile_x(4, 4, 0).find_object(mo_way).get_desc().get_name(), fast_road.get_name()) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "....4...", "....5...", "....1...", "........", "........" ]) } // downgrade road with ctrl { local tool = command_x(tool_build_way) tool.set_flags(2) // ctrl ASSERT_EQUAL(tool.work(pl, start_pos, end_pos, slow_road.get_name()), null) ASSERT_EQUAL(tile_x(4, 4, 0).find_object(mo_way).get_desc().get_name(), slow_road.get_name()) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "....4...", "....5...", "....1...", "........", "........" ]) } ASSERT_EQUAL(remover.work(pl, start_pos, end_pos, "" + wt_road), null) // clean up ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_road_upgrade_downgrade_across_bridge() { local pl = player_x(0) local public_pl = player_x(1) local remover = command_x(tool_remove_way) local start_pos = coord3d(3, 6, 0) local end_pos = coord3d(3, 2, 0) local bridge = bridge_desc_x.get_available_bridges(wt_road)[0] local all_ways = way_desc_x.get_available_ways(wt_road, st_flat) all_ways.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) ASSERT_TRUE(all_ways.len() >= 2) local slow_road = all_ways[0] local fast_road = all_ways[1] ASSERT_TRUE(slow_road.get_name() != fast_road.get_name()) ASSERT_TRUE(slow_road.get_topspeed() < fast_road.get_topspeed()) // build bridge ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 6, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 6, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 5, 0), bridge), null) // upgrade road { ASSERT_TRUE(tile_x(3, 6, 0).find_object(mo_way) != null) ASSERT_TRUE(tile_x(3, 2, 0).find_object(mo_way) != null) ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, fast_road, true), null) ASSERT_EQUAL(tile_x(3, 6, 0).find_object(mo_way).get_desc().get_name(), fast_road.get_name()) ASSERT_EQUAL(tile_x(3, 2, 0).find_object(mo_way).get_desc().get_name(), fast_road.get_name()) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "........", "...5....", "...1....", "........" ]) } // Replace road with same road, should incur no cost { local old_cash = pl.get_current_cash() ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, fast_road, true), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "........", "...5....", "...1....", "........" ]) } // downgrade road without ctrl; should fail // note that we cannot use command_x.buid_way for this, because there is no way to enable // ctrl-pressed behaviour (the way is replaced in any case) { local old_maintenance = pl.get_current_maintenance() local old_cash = pl.get_current_cash() local tool = command_x(tool_build_way) ASSERT_EQUAL(tool.work(pl, start_pos, end_pos, slow_road.get_name()), null) ASSERT_EQUAL(tile_x(3, 6, 0).find_object(mo_way).get_desc().get_name(), fast_road.get_name()) ASSERT_EQUAL(tile_x(3, 2, 0).find_object(mo_way).get_desc().get_name(), fast_road.get_name()) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maintenance) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "........", "...5....", "...1....", "........" ]) } // downgrade road with ctrl { local tool = command_x(tool_build_way) tool.set_flags(2) // ctrl ASSERT_EQUAL(tool.work(pl, start_pos, end_pos, slow_road.get_name()), null) ASSERT_EQUAL(tile_x(3, 6, 0).find_object(mo_way).get_desc().get_name(), slow_road.get_name()) ASSERT_EQUAL(tile_x(3, 2, 0).find_object(mo_way).get_desc().get_name(), slow_road.get_name()) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "........", "...5....", "...1....", "........" ]) } // remove bridge ASSERT_EQUAL(remover.work(pl, start_pos, end_pos, "" + wt_road), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 6, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 6, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), null) // clean up ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_road_cityroad_build() { local public_pl = player_x(1) local start_pos = coord3d(3, 2, 0) local end_pos = coord3d(3, 6, 0) // build single tile -> should fail { ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, start_pos, "city_road"), "") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // build city road { ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "city_road"), null) for (local y = start_pos.y; y < end_pos.y; ++y) { local r = way_x(start_pos.x, y, start_pos.z) ASSERT_TRUE(r != null) ASSERT_TRUE(r.is_valid()) ASSERT_TRUE(r.has_sidewalk()) ASSERT_EQUAL(r.desc.name, "city_road") } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "...5....", "...5....", "...1....", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, start_pos, end_pos, "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_cityroad_upgrade_with_cityroad() { local public_pl = player_x(1) local start_pos = coord3d(3, 2, 0) local end_pos = coord3d(3, 6, 0) ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "city_road"), null) // upgrade cityroad { ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "cobblestone_road"), null) for (local y = start_pos.y; y < end_pos.y; ++y) { local r = way_x(start_pos.x, y, start_pos.z) ASSERT_TRUE(r != null) ASSERT_TRUE(r.is_valid()) ASSERT_TRUE(r.has_sidewalk()) ASSERT_EQUAL(r.desc.name, "city_road") // FIXME Should this not be cobblestone_road? } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "...5....", "...5....", "...1....", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, start_pos, end_pos, "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_cityroad_downgrade_with_cityroad() { local public_pl = player_x(1) local start_pos = coord3d(3, 2, 0) local end_pos = coord3d(3, 6, 0) ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "cobblestone_road"), null) // downgrade cityroad { local builder = command_x(tool_build_cityroad) builder.set_flags(2) ASSERT_EQUAL(builder.work(public_pl, start_pos, end_pos, "city_road"), null) for (local y = start_pos.y; y < end_pos.y; ++y) { local r = way_x(start_pos.x, y, start_pos.y) ASSERT_TRUE(r != null) ASSERT_TRUE(r.is_valid()) ASSERT_TRUE(r.has_sidewalk()) ASSERT_EQUAL(r.desc.name, "city_road") } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "...5....", "...5....", "...1....", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, start_pos, end_pos, "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_cityroad_replace_by_normal_road() { local public_pl = player_x(1) local start_pos = coord3d(3, 2, 0) local end_pos = coord3d(3, 6, 0) ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "city_road"), null) // replace cityroad by normal road { ASSERT_EQUAL(command_x.build_way(public_pl start_pos, end_pos, way_desc_x("cobblestone_road"), true), null) for (local y = start_pos.y; y < end_pos.y; ++y) { local r = way_x(start_pos.x, y, start_pos.z) ASSERT_TRUE(r != null) ASSERT_TRUE(r.is_valid()) ASSERT_FALSE(r.has_sidewalk()) ASSERT_EQUAL(r.desc.name, "cobblestone_road") } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "...5....", "...5....", "...1....", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, start_pos, end_pos, "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_cityroad_replace_keep_existing() { local public_pl = player_x(1) local start_pos = coord3d(3, 2, 0) local end_pos = coord3d(3, 6, 0) ASSERT_EQUAL(command_x(tool_build_cityroad).work(public_pl, start_pos, end_pos, "city_road"), null) // replace cityroad by normal road { local builder = command_x(tool_build_way) builder.set_flags(1) // enable shift -> keep city roads ASSERT_EQUAL(builder.work(public_pl, start_pos, end_pos, "cobblestone_road"), null) for (local y = start_pos.y; y < end_pos.y; ++y) { local r = way_x(start_pos.x, y, start_pos.z) ASSERT_TRUE(r != null) ASSERT_TRUE(r.is_valid()) ASSERT_TRUE(r.has_sidewalk()) ASSERT_EQUAL(r.desc.name, "city_road") } ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "...4....", "...5....", "...5....", "...5....", "...1....", "........" ]) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, start_pos, end_pos, "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_road_has_double_slopes() { local roads = way_desc_x.get_available_ways(wt_road, st_flat) foreach (r in roads) { ASSERT_TRUE(r.has_double_slopes()) } } function test_way_road_make_public() { local pl = player_x(0) local public_pl = player_x(1) local wayremover = command_x(tool_remove_way) local road_desc = way_desc_x.get_available_ways(wt_road, st_flat)[0] local makepublic = command_x(tool_make_stop_public) ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 2, 0), coord3d(4, 4, 0), road_desc, true), null) // invalid coord { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(-1, -1, -1)), "No suitable ground!") ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // nothing to make public { local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(3, 4, 0)), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // make road public { local old_pl_cash = pl.get_current_cash() local old_pl_maint = pl.get_current_maintenance() local old_public_cash = public_pl.get_current_cash() local old_public_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 2, 0)), null) ASSERT_TRUE(way_x(4, 2, 0).get_owner() != null) ASSERT_EQUAL(way_x(4, 2, 0).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_cash()*100, old_pl_cash*100 - 60 * road_desc.get_maintenance()) // 60 == cst_make_public_months ASSERT_EQUAL(pl.get_current_maintenance(), old_pl_maint - road_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_public_maint + road_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_cash(), old_public_cash) } ASSERT_EQUAL(wayremover.work(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_way_runway.nut000066400000000000000000000144311474050137200220560ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // tests for runways/taxiways // function test_way_runway_build_rw_flat() { local pl = player_x(0) local wayremover = command_x(tool_remove_way) local runway = way_desc_x.get_available_ways(wt_air, st_elevated)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] // preconditions ASSERT_TRUE(runway != null) ASSERT_TRUE(road != null) // Build runway next to map border, should fail (causes glitches with planes taking off/landing) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(4, 5, 0), runway, true), "") ASSERT_WAY_PATTERN(wt_air, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) } // Straight runway away from map border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(6, 6, 0), coord3d(6, 8, 0), runway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", ".5......", ".1......", "........", "........", "........", "........" ]) } // Cross runway with existing one { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 7, 0), coord3d(7, 7, 0), runway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", "2F8.....", ".1......", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(5, 7, 0), coord3d(7, 7, 0), "" + wt_air), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", ".5......", ".1......", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(6, 6, 0), coord3d(6, 8, 0), "" + wt_air), null) } // no runways across ways { ASSERT_EQUAL(command_x.build_way(pl, coord3d(8, 8, 0), coord3d(10, 8, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(9, 7, 0), coord3d(9, 9, 0), runway, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(6, 6, 0), [ "........", "........", "..2A8...", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_air, coord3d(6, 6, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(8, 8, 0), coord3d(10, 8, 0), "" + wt_road), null) } ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_runway_build_tw_flat() { local pl = player_x(0) local wayremover = command_x(tool_remove_way) local taxiway = way_desc_x.get_available_ways(wt_air, st_flat)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] // preconditions ASSERT_TRUE(taxiway != null) ASSERT_TRUE(road != null) // Build taxiway next to map border, should succeed (contrary to runway) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(4, 3, 0), coord3d(4, 5, 0), taxiway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(0, 0, 0), [ "........", "........", "........", "....4...", "....5...", "....1...", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(4, 3, 0), coord3d(4, 5, 0), "" + wt_air), null) } // Straight taxiway away from map border { ASSERT_EQUAL(command_x.build_way(pl, coord3d(6, 6, 0), coord3d(6, 8, 0), taxiway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", ".5......", ".1......", "........", "........", "........", "........" ]) } // Cross taxiway with existing one { ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 7, 0), coord3d(7, 7, 0), taxiway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", "2F8.....", ".1......", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(5, 7, 0), coord3d(7, 7, 0), "" + wt_air), null) ASSERT_WAY_PATTERN(wt_air, coord3d(5, 5, 0), [ "........", ".4......", ".5......", ".1......", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(6, 6, 0), coord3d(6, 8, 0), "" + wt_air), null) } // no taxiways across ways { ASSERT_EQUAL(command_x.build_way(pl, coord3d(8, 8, 0), coord3d(10, 8, 0), road, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(9, 7, 0), coord3d(9, 9, 0), taxiway, true), "") ASSERT_WAY_PATTERN(wt_road, coord3d(6, 6, 0), [ "........", "........", "..2A8...", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_air, coord3d(6, 6, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(8, 8, 0), coord3d(10, 8, 0), "" + wt_road), null) } ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } function test_way_runway_build_mixed_flat() { local pl = player_x(0) local wayremover = command_x(tool_remove_way) local taxiway = way_desc_x.get_available_ways(wt_air, st_flat)[0] local runway = way_desc_x.get_available_ways(wt_air, st_flat)[0] // t junction { ASSERT_EQUAL(command_x.build_way(pl, coord3d(8, 8, 0), coord3d(8, 10, 0), runway, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(7, 9, 0), coord3d(8, 9, 0), taxiway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(6, 6, 0), [ "........", "........", "..4.....", ".2D.....", "..1.....", "........", "........", "........" ]) } // crossing { ASSERT_EQUAL(command_x.build_way(pl, coord3d(7, 9, 0), coord3d(9, 9, 0), taxiway, true), null) ASSERT_WAY_PATTERN(wt_air, coord3d(6, 6, 0), [ "........", "........", "..4.....", ".2F8....", "..1.....", "........", "........", "........" ]) ASSERT_EQUAL(wayremover.work(pl, coord3d(7, 9, 0), coord3d(9, 9, 0), "" + wt_air), null) ASSERT_EQUAL(wayremover.work(pl, coord3d(8, 8, 0), coord3d(8, 10, 0), "" + wt_air), null) } ASSERT_EQUAL(pl.get_current_maintenance(), 0) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_way_tram.nut000066400000000000000000000235011474050137200214720ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for tramways // function test_way_tram_build_flat() { local pl = player_x(0) local tramway = way_desc_x.get_available_ways(wt_rail, st_tram)[0] // build straight { ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), tramway, true), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), "" + wt_rail), null) } RESET_ALL_PLAYER_FUNDS() } function test_way_tram_build_parallel() { local pl = player_x(0) local rail_desc = way_desc_x.get_available_ways(wt_rail, st_tram)[0] local remover = command_x(tool_remove_way) { for (local i = 0; i < 16; ++i) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(15, i, 0), rail_desc, true), null) } ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8", "2AAAAAAAAAAAAAA8" ]) for (local i = 0; i < 16; ++i) { ASSERT_EQUAL(remover.work(pl, coord3d(0, i, 0), coord3d(15, i, 0), "" + wt_rail), null) } } RESET_ALL_PLAYER_FUNDS() { for (local i = 0; i < 16; ++i) { ASSERT_EQUAL(command_x.build_way(pl, coord3d(0, i, 0), coord3d(15, i, 0), rail_desc, false), null) } // FIXME this is different from the road pattern (which is all straight roads even without ctrl) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "6EEAAAAAAAAAAAE8", "7B9...........3C", "5..............5", "5..............5", "5..............5", "5..............5", "5..............5", "5..............5", "5..............5", "1..............1", "6EEAAAAAAAAAAAE8", "7B9...........3C", "5..............5", "5..............5", "5..............5", "1..............1" ]) ASSERT_EQUAL(remover.work(pl, coord3d(0, 9, 0), coord3d(15, 9, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(0, 15, 0), coord3d(15, 15, 0), "" + wt_rail), null) for (local i = 0; i < 15; i = i + 10) { ASSERT_EQUAL(remover.work(pl, coord3d(1, i, 0), coord3d(0, 1+i, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(1, i+1, 0), coord3d(2, i, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(14, i, 0), coord3d(15, i, 0), "" + wt_rail), null) } } RESET_ALL_PLAYER_FUNDS() } function test_way_tram_build_on_road() { local pl = player_x(0) local tramway = way_desc_x.get_available_ways(wt_rail, st_tram)[0] local road = way_desc_x.get_available_ways(wt_road, st_flat)[0] ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), road, true), null) // build fully on existing road { ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), tramway, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...5....", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...5....", "...1....", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), "" + wt_rail), null) } // cross existing road { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), tramway, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "...4....", "...5....", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "........", "........", "........", "..2A8...", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), "" + wt_rail), null) } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tram_build_across_road_bridge() { local pl = player_x(0) local bridge = bridge_desc_x.get_available_bridges(wt_road)[0] local setslope = command_x.set_slope local tramway = way_desc_x.get_available_ways(wt_rail, st_tram)[0] // build bridge ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.south), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.north), null) ASSERT_EQUAL(command_x.build_bridge_at(pl, coord3d(3, 3, 0), bridge), null) // and build tram track { ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), tramway, true), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 1), [ "........", "........", "........", "...4....", "...5....", "...1....", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 1), [ "........", "........", "........", "...4....", "...5....", "...1....", "........", "........" ]) // do not remove tram tracks here, this is done by tool_remover below } ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 3, 0), slope.flat), null) ASSERT_EQUAL(setslope(pl, coord3d(3, 5, 0), slope.flat), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tram_build_across_crossing() { local pl = player_x(0) local tramways = way_desc_x.get_available_ways(wt_rail, st_tram) tramways.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) local tramway = tramways[0] local roads = way_desc_x.get_available_ways(wt_road, st_flat) roads.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) local road = roads[0] local rails = way_desc_x.get_available_ways(wt_rail, st_flat) rails.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) rails.filter(@(idx, desc) desc.get_topspeed() >= tramway.get_topspeed()) local rail = rails[0] // build crossing ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), rail, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), road, true), null) // build tram track { ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), tramway, true), null) // crossing should have been replaced by tramway ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), "" + wt_rail), null) } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 3, 0), coord3d(3, 5, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 4, 0), coord3d(4, 4, 0), "" + wt_road), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tram_build_in_tunel() { local pl = player_x(0) local tramway = way_desc_x.get_available_ways(wt_rail, st_tram)[0] local road_tunnel = tunnel_desc_x.get_available_tunnels(wt_road)[0] local rail_tunnel = tunnel_desc_x.get_available_tunnels(wt_rail)[0] ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(1, 2, 0), road_tunnel.get_name()), null) // build tramway through road tunnel { ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(4, 2, 0), tramway, true), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(1, 2, 0), coord3d(4, 2, 0), "" + wt_rail), null) } // cross road tunnel with tramway { local tunnel_builder = command_x(tool_build_tunnel) tunnel_builder.set_flags(2) // ctrl ASSERT_EQUAL(command_x.build_way(pl, coord3d(1, 2, 0), coord3d(4, 2, 0), tramway, true), null) ASSERT_EQUAL(tunnel_builder.work(pl, coord3d(2, 1, 0), rail_tunnel.get_name()), null) ASSERT_EQUAL(tunnel_builder.work(pl, coord3d(2, 3, 0), rail_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "..0.....", ".2AA8...", "..0.....", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 3, 0), tramway, true), "") ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ "........", "..0.....", ".2AA8...", "..0.....", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", ".2AA8...", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(2, 1, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 3, 0), coord3d(2, 3, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(1, 2, 0), coord3d(4, 2, 0), "" + wt_rail), null) } ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(1, 2, 0), coord3d(4, 2, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 3, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 3, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 1)), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tram_has_double_slopes() { local roads = way_desc_x.get_available_ways(wt_rail, st_tram) foreach (r in roads) { ASSERT_FALSE(r.has_double_slopes()) } } simutrans-124.3/tests/tests/test_way_tunnel.nut000066400000000000000000000270331474050137200220400ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for building and removal of tunnels // function test_way_tunnel_build_straight() { local digger = command_x(tool_build_tunnel) local remover = command_x(tool_remover) local default_tunnel = tunnel_desc_x.get_available_tunnels(wt_road)[0] local pl = player_x(0) ASSERT_TRUE(default_tunnel != null) { ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 2, 0)), null) digger.set_flags(2) ASSERT_EQUAL(digger.work(pl, tile_x(3, 1, 0), default_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...0....", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(digger.work(pl, tile_x(3, 2, 0), default_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...0....", "...0....", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0)), null) ASSERT_EQUAL(remover.work(pl, coord3d(3, 2, 0)), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) digger.set_flags(0) } { ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(digger.work(pl, tile_x(3, 1, 0), default_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "...5....", "...1....", "........", "........", "........", "........" ]) { // test tunnel object local t = tile_x(3, 1, 0) local tunnel = t.find_object(mo_tunnel) ASSERT_TRUE(tunnel != null) ASSERT_EQUAL(tunnel.get_desc().get_name(), default_tunnel.get_name()) } } { ASSERT_EQUAL(digger.work(pl, tile_x(2, 2, 0), default_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "..2D....", "...1....", "........", "........", "........", "........" ]) // building with ctrl digger.set_flags(2) ASSERT_EQUAL(digger.work(pl, tile_x(4, 2, 0), default_tunnel.get_name()), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "..2D0...", "...1....", "........", "........", "........", "........" ]) digger.set_flags(0) // remove the single tunnel entrance ASSERT_EQUAL(remover.work(pl, coord3d(4, 2, 0)), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "..2D....", "...1....", "........", "........", "........", "........" ]) // remove tunnel network (more than 2 entrances) // should fail without ctrl local err = remover.work(pl, coord3d(3, 3, 0)) ASSERT_EQUAL(err, "This tunnel branches. You can try Control+Click to remove.") ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "...4....", "..2D....", "...1....", "........", "........", "........", "........" ]) remover.set_flags(2) // activate ctrl ASSERT_EQUAL(remover.work(pl, coord3d(3, 3, 0)), null) ASSERT_WAY_PATTERN(wt_road, coord3d(0, 0, 0), [ "........", "........", "........", "........", "........", "........", "........", "........" ]) remover.set_flags(0) // deactivate ctrl } // clean up ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(3, 3, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 2, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(4, 3, 0)), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tunnel_build_up_down() { local digger = command_x(tool_build_tunnel) local setslope = command_x.set_slope local remover = command_x(tool_remover) local default_tunnel = tunnel_desc_x.get_available_tunnels(wt_rail)[0] local pl = player_x(0) ASSERT_TRUE(default_tunnel != null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(1, 1, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 1, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(1, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 2, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(1, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 3, 0)), null) digger.set_flags(2) // ctrl ASSERT_EQUAL(digger.work(pl, coord3d(1, 0, 0), default_tunnel.get_name()), null) ASSERT_EQUAL(digger.work(pl, coord3d(1, 0, 0), coord3d(1, 1, 0), default_tunnel.get_name()), null) // invalid param { ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), 42), "Only up and down movement in the underground!") ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), // no change [ ".4......", ".1......", "........", "........", "........", "........", "........", "........" ]) } // Build up: Does not work: surface in the way { ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), slope.all_up_slope), "Tile not empty.") ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), // no change [ ".4......", ".1......", "........", "........", "........", "........", "........", "........" ]) } // Build down { local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), slope.all_down_slope), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ ".4......", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, -1), [ "........", ".1......", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // try building duble slope down, rail does not support double slopes { local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(setslope(pl, coord3d(1, 1, -1), slope.all_down_slope), "Tile not empty.") ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ ".4......", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, -1), [ "........", ".1......", "........", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } ASSERT_EQUAL(digger.work(pl, coord3d(1, 1, -1), coord3d(1, 2, -1), default_tunnel.get_name()), null) // Build up { local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(setslope(pl, coord3d(1, 2, -1), slope.all_up_slope), null) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ ".4......", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, -1), [ "........", ".5......", ".1......", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) } // try building double slope up, rail does not support double slopes { ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(1, 2, 1)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 2, 1)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(1, 3, 1)), null) ASSERT_EQUAL(command_x.grid_raise(pl, coord3d(2, 3, 1)), null) local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(setslope(pl, coord3d(1, 1, 0), slope.all_up_slope), "") ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, 0), [ ".4......", "........", "........", "........", "........", "........", "........", "........" ]) ASSERT_WAY_PATTERN(wt_rail, coord3d(0, 0, -1), [ "........", ".5......", ".1......", "........", "........", "........", "........", "........" ]) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(1, 2, 2)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 2, 2)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(1, 3, 2)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 3, 2)), null) } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, coord3d(1, 0, 0)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(1, 1, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 1, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(1, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 2, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(1, 3, 1)), null) ASSERT_EQUAL(command_x.grid_lower(pl, coord3d(2, 3, 1)), null) RESET_ALL_PLAYER_FUNDS() } function test_way_tunnel_make_public() { local pl = player_x(0) local public_pl = player_x(1) local tunnel_desc = tunnel_desc_x.get_available_tunnels(wt_road)[0] local makepublic = command_x(tool_make_stop_public) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(4, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(5, 3, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(4, 4, 0)), null) ASSERT_EQUAL(command_x.grid_raise(public_pl, coord3d(5, 4, 0)), null) ASSERT_EQUAL(command_x(tool_build_tunnel).work(pl, coord3d(4, 2, 0), tunnel_desc.get_name()), null) // make tunnel portal public { local old_pl_cash = pl.get_current_cash() local old_pl_maint = pl.get_current_maintenance() local old_public_cash = public_pl.get_current_cash() local old_public_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 2, 0)), null) ASSERT_TRUE(way_x(4, 2, 0).get_owner() != null) ASSERT_EQUAL(way_x(4, 2, 0).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_cash()*100, old_pl_cash*100 - 60 * tunnel_desc.get_maintenance()) // 60 == cst_make_public_months ASSERT_EQUAL(pl.get_current_maintenance(), old_pl_maint - tunnel_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_public_maint + tunnel_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_cash(), old_public_cash) } // make tunnel inside public { local old_pl_cash = pl.get_current_cash() local old_pl_maint = pl.get_current_maintenance() local old_public_cash = public_pl.get_current_cash() local old_public_maint = public_pl.get_current_maintenance() ASSERT_EQUAL(makepublic.work(pl, coord3d(4, 3, 0)), null) ASSERT_TRUE(way_x(4, 3, 0).get_owner() != null) ASSERT_EQUAL(way_x(4, 3, 0).get_owner().get_name(), public_pl.get_name()) ASSERT_EQUAL(pl.get_current_cash()*100, old_pl_cash*100 - 60 * tunnel_desc.get_maintenance()) // 60 == cst_make_public_months ASSERT_EQUAL(pl.get_current_maintenance(), old_pl_maint - tunnel_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_maintenance(), old_public_maint + tunnel_desc.get_maintenance()) ASSERT_EQUAL(public_pl.get_current_cash(), old_public_cash) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(public_pl, coord3d(4, 2, 0), coord3d(4, 4, 0), "" + wt_road), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(4, 3, 1)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(5, 3, 1)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(4, 4, 1)), null) ASSERT_EQUAL(command_x.grid_lower(public_pl, coord3d(5, 4, 1)), null) RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/tests/tests/test_wayobj.nut000066400000000000000000000260311474050137200211430ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // // // Tests for wayobj // function test_wayobj_build_straight() { local pl = player_x(0) local remover = command_x(tool_remove_wayobj) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local overhead_line = wayobj_desc_x.get_available_wayobjs(wt_rail).filter(@(idx, wobj) wobj.is_overhead_line())[0] ASSERT_TRUE(overhead_line != null) { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(2, 1, 0), coord3d(2, 1, 0), overhead_line), "") ASSERT_EQUAL(tile_x(2, 1, 0).find_object(mo_wayobj), null) ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 1, 0), coord3d(2, 1, 0), overhead_line), "") ASSERT_EQUAL(tile_x(3, 1, 0).find_object(mo_wayobj), null) ASSERT_EQUAL(tile_x(2, 1, 0).find_object(mo_wayobj), null) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(5, 1, 0), rail, true), null) // now build wayobj { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(2, 1, 0), coord3d(2, 1, 0), overhead_line), null) local wo = tile_x(2, 1, 0).find_object(mo_wayobj) ASSERT_TRUE(wo != null) ASSERT_TRUE(wo.is_valid()) } { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 1, 0), coord3d(4, 1, 0), overhead_line), null) local wo = tile_x(3, 1, 0).find_object(mo_wayobj) ASSERT_TRUE(wo != null) ASSERT_TRUE(wo.is_valid()) wo = tile_x(4, 1, 0).find_object(mo_wayobj) ASSERT_TRUE(wo != null) ASSERT_TRUE(wo.is_valid()) // todo: check for wayobj ribis ? } { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(2, 1, 0), coord3d(4, 1, 0), overhead_line), null) local wo = tile_x(3, 1, 0).find_object(mo_wayobj) ASSERT_TRUE(wo != null) ASSERT_TRUE(wo.is_valid()) } // remove wayobj { ASSERT_EQUAL(remover.work(pl, coord3d(2, 1, 0), coord3d(2, 2, 0), "" + wt_rail), "") ASSERT_EQUAL(remover.work(pl, coord3d(2, 1, 0), coord3d(3, 1, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(2, 1, 0), coord3d(3, 1, 0), "" + wt_rail), null) // returns success even if nothing was removed ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0), coord3d(4, 1, 0), "" + wt_rail), null) ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0), coord3d(4, 1, 0), "" + wt_rail), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(5, 1, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_wayobj_build_disconnected() { local pl = player_x(0) local remover = command_x(tool_remove_wayobj) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local overhead_line = wayobj_desc_x.get_available_wayobjs(wt_rail).filter(@(idx, wobj) wobj.is_overhead_line())[0] ASSERT_TRUE(overhead_line != null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(5, 1, 0), rail, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 5, 0), coord3d(5, 5, 0), rail, true), null) // build disconnected { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 5, 0), coord3d(3, 1, 0), overhead_line), "Ways not connected") ASSERT_EQUAL(tile_x(3, 5, 0).find_object(mo_wayobj), null) ASSERT_EQUAL(tile_x(3, 1, 0).find_object(mo_wayobj), null) } // remove disconnected wayobj { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(2, 1, 0), coord3d(5, 1, 0), overhead_line), null) ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(2, 5, 0), coord3d(5, 5, 0), overhead_line), null) ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0), coord3d(3, 5, 0), "" + wt_rail), "Ways not connected") ASSERT_TRUE(tile_x(3, 1, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 5, 0).find_object(mo_wayobj) != null) } ASSERT_EQUAL(command_x.build_way(pl, coord3d(2, 1, 0), coord3d(2, 5, 0), rail, true), null) ASSERT_EQUAL(command_x.build_way(pl, coord3d(5, 1, 0), coord3d(5, 5, 0), rail, true), null) { ASSERT_EQUAL(remover.work(pl, coord3d(3, 1, 0), coord3d(3, 5, 0), "" + wt_rail), null) ASSERT_TRUE(tile_x(3, 1, 0).find_object(mo_wayobj) == null) ASSERT_TRUE(tile_x(3, 5, 0).find_object(mo_wayobj) == null) ASSERT_TRUE(tile_x(4, 1, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 5, 0).find_object(mo_wayobj) != null) } // clean up ASSERT_EQUAL(remover.work(pl, coord3d(4, 1, 0), coord3d(4, 5, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(5, 5, 0), "" + wt_rail), null) ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(2, 1, 0), coord3d(5, 5, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_wayobj_upgrade_downgrade() { local pl = player_x(0) local wobj_remover = command_x(tool_remove_wayobj) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local catenaries = wayobj_desc_x.get_available_wayobjs(wt_rail).filter(@(idx, wobj) wobj.is_overhead_line()) catenaries.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) // FIXME need at least 2 catenaries ASSERT_TRUE(catenaries.len() >= 2) local slow_cat = catenaries[0] local fast_cat = catenaries[1] ASSERT_EQUAL(command_x.build_way(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), rail, true), null) // upgrade wayobj { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat), null) ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), fast_cat), null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_EQUAL(wobj_remover.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) } // upgrade wayobj to same type, should incur no cost { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat), null) local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj).get_desc().is_equal(slow_cat)) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj).get_desc().is_equal(slow_cat)) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj).get_desc().is_equal(slow_cat)) ASSERT_EQUAL(wobj_remover.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) } // upgrade wayobj to faster type { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat), null) local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), fast_cat), null) ASSERT_TRUE(pl.get_current_cash() < old_cash) ASSERT_TRUE(pl.get_current_maintenance() > old_maint) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_EQUAL(wobj_remover.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) } // downgrade wayobj without ctrl, should fail { ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), fast_cat), null) local old_cash = pl.get_current_cash() local old_maint = pl.get_current_maintenance() ASSERT_EQUAL(command_x.build_wayobj(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat), null) ASSERT_EQUAL(pl.get_current_cash(), old_cash) ASSERT_EQUAL(pl.get_current_maintenance(), old_maint) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_EQUAL(wobj_remover.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) } // downgrade wayobj with ctrl, should succeed { local builder = command_x(tool_build_wayobj) builder.set_flags(2) // enable ctrl ASSERT_EQUAL(builder.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), fast_cat.get_name()), null) ASSERT_EQUAL(builder.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), slow_cat.get_name()), null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj) != null) ASSERT_TRUE(tile_x(3, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(4, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_TRUE(tile_x(5, 4, 0).find_object(mo_wayobj).get_desc().is_equal(fast_cat)) ASSERT_EQUAL(wobj_remover.work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) } // clean up ASSERT_EQUAL(command_x(tool_remove_way).work(pl, coord3d(3, 4, 0), coord3d(5, 4, 0), "" + wt_rail), null) RESET_ALL_PLAYER_FUNDS() } function test_wayobj_electrify_depot() { local pl = player_x(0) local start_pos = coord3d(3, 4, 0) local end_pos = coord3d(5, 4, 0) local wayremover = command_x(tool_remove_way) local wobj_remover = command_x(tool_remove_wayobj) local rail = way_desc_x.get_available_ways(wt_rail, st_flat)[0] local catenaries = wayobj_desc_x.get_available_wayobjs(wt_rail).filter(@(idx, wobj) wobj.is_overhead_line()) catenaries.sort(@(a, b) a.get_topspeed() <=> b.get_topspeed()) local slow_cat = catenaries[0] local fast_cat = catenaries[1] local depot = get_depot_by_wt(wt_rail) ASSERT_TRUE(slow_cat != null) ASSERT_TRUE(fast_cat != null) ASSERT_TRUE(depot != null) ASSERT_EQUAL(command_x.build_way(pl, start_pos, end_pos, rail, true), null) ASSERT_EQUAL(command_x.build_depot(pl, start_pos, depot), null) ASSERT_EQUAL(command_x.build_depot(pl, end_pos, depot), null) { ASSERT_EQUAL(command_x.build_wayobj(pl, start_pos, end_pos, slow_cat), null) ASSERT_TRUE(way_x(start_pos.x, start_pos.y, start_pos.z).is_electrified()) ASSERT_TRUE(way_x(end_pos.x, end_pos.y, end_pos.z).is_electrified()) // TODO check that depot is really electrified } // clean up ASSERT_EQUAL(command_x(tool_remover).work(pl, start_pos, "" + mo_depot_rail), null) ASSERT_EQUAL(command_x(tool_remover).work(pl, end_pos, "" + mo_depot_rail), null) ASSERT_EQUAL(wayremover.work(pl, start_pos, end_pos, "" + wt_rail), null) // also removes way with wayobj RESET_ALL_PLAYER_FUNDS() } simutrans-124.3/themes.src/000077500000000000000000000000001474050137200156265ustar00rootroot00000000000000simutrans-124.3/themes.src/aero/000077500000000000000000000000001474050137200165545ustar00rootroot00000000000000simutrans-124.3/themes.src/aero/aero.tab000066400000000000000000000131071474050137200201740ustar00rootroot00000000000000# # name of the theme (will be shown with file selector) name=Aero skin (standard size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #AFEEEE # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #1E90FF # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) bottom_window_darkness = 20 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #A7D1EA #################################colour stuff################################# # color used for the default titlebars default_window_title_color = #338FCC # gui_color_text = #000000 gui_color_text_highlight = #005C9E gui_color_text_shadow = #BDD3DF gui_color_text_title = #338FCC gui_color_text_strong = #E46A0B gui_color_obsolete = #2878ff gui_color_empty = #868c86 gui_color_edit_text = #000000 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #666666 gui_color_edit_background_selected = #72B2DD gui_color_edit_beam = #1E90FF gui_color_chart_background = #D6EBF7 gui_color_chart_lines_zero = #005C9E gui_color_chart_lines_odd = #FFFFFF gui_color_chart_lines_even = #336699 gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #72B2DD gui_color_button_text = #000000 gui_color_button_text_disabled = #666666 gui_color_button_text_selected = #FAFAFA gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #FAFAFA # gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #666666 gui_color_ticker_background = #D6ECF7 gui_color_ticker_divider = #6095B8 # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #72B2DD gui_color_statusbar_divider = #6095B8 gui_highlight_color = #FAFAFA gui_shadow_color = #CCDDFF gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #ff0000 # Colo loadbar, save game, load game, server... gui_color_loadingbar_progress = #6495ED gui_color_loadingbar_inner = #D6ECF7 # Color player brigth gui_player_color_dark = 1 gui_player_color_bright = 3 ##################################size stuff################################## # force main menu icon size icon_width = 32 # titlebar height gui_titlebar_height = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 18 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 16 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 icon_scaling = 100 ###################################pakstuff################################### # pak with the images for this theme themeimages=aerotheme.pak simutrans-124.3/themes.src/aero/alt_back.png000066400000000000000000000030561474050137200210260ustar00rootroot00000000000000‰PNG  IHDR€À è´gõIDATxÚíÝKN”M†a4˜èH »ù—áB]ƒ#·âˆÄ&˜ðK [è}¨êï¾®™–*HÞ§ªÞïðêÛÝÝ—‹°7××£‡0ÔíÕÕè!ƒ¼=Ƹ=€Ñ./Û¿‚Ûц±ˆj/¹yÿ~ô†°ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ êòÍõõÅíÕÕèq s?ÿ²òßž‹‹¯Ÿ?ïôý?~ü=俼}ûv¯Ïÿ÷éÓè) u9zÀ8³ôÚøG»üåâvô(ÆþFa¨òßžß+èÇEtßõ÷ãnÜb½võƒ¸Õ9sÁ|(òc|ø÷ºÐZýÚº°(ºüùóçè1 UŸ?¬³ºCéPa5Ë|f`aÛ¬†­˜—K@€¸M=+æåjW?ˆ;§À:šÀ/£Ÿ?,Bÿ2vÀ‹éœ7==Â>|ø0dõlÅ>‡võƒ¸cbþ<èÄçÛz¸‰Jq_;Ûæ —;o9/zz„}ÿþ}ô¨]ý n–Õü¾ÇJ›æqî¼;=€øüi[Êyþ.óXÊœÁÂf[ º8ßÜÜŒžÒÔôôÛ¦àŽ,¢ïÞ½úù¥kW?à/Oí–¾K(ÓˆÏS\[ì€Ív¶¾é¨çñx ý¡ ;›­ˆnzÁlãE»úAܱWò§(¼Ïõ(fë]ÌH >Ú>~ü¸ö&©sè lzÑû9Ìa;›å`ûîDfëIœ ==Îýíêq»< ”åшϟ6ŽÍÂNu¥Ì!ƒÆyÿáèè6b°oè¼äó«W:ÙùüÖ®~7úZy/¤K >Úî‹áSI}Ì⪠Ӱ€°ûÀã#‘§Þûkż\zz°ö(hô1ÇÓ®~€~˜@|þ´­ÿMOÕÜôõMžÛMlzžÇa¬µ©0¢pïó<„‡Ìîôô[ªû©Æ5ÛiW?ˆ[ʪySñßtŒU¥Ÿ?m³ã1Ñ£ïq˜‰ÄͶ">ä«ÝP¶ž€Leß+Ø^»úAœÂÚ¦Ÿ?Ðõzôm¶¾Æ¬ôô`qmmÇ J >Úv=*±²^–öù°ö.YÙôôˆ›ñ]‚ç4ÚÕâŽYh÷ C—Â?M >Úf¹\ò”YñÿÃÎãÆÐÐ ì¥Eö;‡‡Ÿ!ާ]ý n)G@Û¼`–¹ÎD >8†Ç÷+øm~†Ä¿ì€ƒy\dÜùéè¶Z¤×5c·9Byé1‹°£]ý î˜EýÐãxàý¾‡£Ÿ?mç¾ò>÷ñfa«wÅÎþ, /t?,==ÂV ü± þsG6ÏýÜÕïî1.}™võƒ¸Ù‹â6´º+xn—`÷ð¯Wßî§ç`Q JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@”ˆQ JD €(%¢@ÔÿÎ>÷`*ëIEND®B`‚simutrans-124.3/themes.src/aero/back.png000066400000000000000000000012231474050137200201600ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜlZIDATxÚíÓQ €0 EQ´/µ‚"Dð…’á€?²w–\mw¶Õg÷–Úœ?½äûÇ. ,AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH¼ÃxŸÀ¯ÿLêdûq_É­t€äÌùÓ‹<¼d @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@X‚Öêê@‰\ÇÇmIEND®B`‚simutrans-124.3/themes.src/aero/button.png000066400000000000000000000050561474050137200206030ustar00rootroot00000000000000‰PNG  IHDR@[*ÉÇ õIDATxÚíÛÛK—ÙÀáß×Íž›º©h."¢ˆŠè@›° †Ê4É­e e;³’l:ab R1¤QhOe+‹ÐN ÑšÖ¶+æ&ön‚ý}d¼‰õ®õ®÷ó,¦”¾ÖÐÐþê÷ÿŽ=f¬eÿ¯ûÃ;wö\êºÐ•únô…›ÿ<æ<ö| ò±ˆ6þî?ºC+++KmmméÊ•+éöíÛipp°øeþoݺ•®_¿ž®]»–.]º”:îü¬ôùÁ¨««K§NJ7oÞ ³._¾œêëëÃÐÛ—oC@(²Ê•©«««ˆ€¼ïOGP”ù("èÆÅ1ˆvC<Ô?ZéóøéèèHÏŸ?O/Æ^„Yy¬ÃÃÃa#(?2$€"knn.ö¾¡¡¡422’=z”?~fþóx|zÜ»w/´·/ß~!ÚüÿÛÐz{{ÓØØXz1ö"½~ý:½yó¦øeþóX_¾|™&&&ŠcpÿþýPë?Ïwd_ÐÝ»wÓãÇÓ«W¯Â,€¼èGFFÂлwïBÆYOOO±æÈûþtE €éÊ¢ÝG_ÿ¥Ïãçùóçirr2MMM…Yy¬ù@D <ß‘ ãltt´ØûrD\Ÿ9àÀÀ@¨õŸ¯‘}  'ÁÓ§O‹E0}aˆyÜùhŽ@$€ @ŽÁððpÿâÂ-ò±È¯¿"}þá À»”¿…ÈýàÉ“'é~°@ ã@ùæ7?ÊÿÿþýûB”ùÏcÍÂgÏž¥ÁÁÁpëz¾£*åøyôèQñþ3âF8ý8ÿÌïÂóñpˆ}A@Ö´õž¿}¹sçNq#)€Š§]££!ãG½÷gðÄ&Œ_}”ÿ&é&°¿¿?ä§ÖÿWA@~%e¬ù©ä¹ú&ù{±ïùû¿ûß@@8@@  €€@@  € €€@@  €€@@ @  €€@@  €€@€@@  €€@ðÝO‚Réc=ÿÄZ ‘Çní—Päß P@ÈE@ ô剶lþH9ˆ@Ö~àŠ~ØürD?ìÿÖ~¨ràhó7ÿ(öÓžÈû¿µ/€@ˆÀ"îÿæÛ+0°  €8ûŸƒ  €€@@  €€@@@  €€@@  € €€@@  €€@@ @  €€@@ ðßùÓzñÓZ®oìIEND®B`‚simutrans-124.3/themes.src/aero/checkbutton.png000066400000000000000000000020331474050137200215710ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆâIDATxÚíØMHaÇñgÖÝuÝ_w´mÝ,Y+¨®öB/DXЩ (‹ÊSà!*:JDé”ÐE2ì…‚ C—" êuÙ^\³"uÙrˬÝtߦÿΘ, >ÒÿðlôûÀê8ò_ç;ó̪ÅLSq¶³Ói1­I>ŸO&“gz{Å¿`CËÑ·osB¸„ ù5kß;!îÆÌ¼êÑæ%‰¤R©â=yKsk«êÑ$´˜iÞ»zµ­­Íív°KŠD"áõëU)±scÿ¡ã›W,­Ö ùÐÜÚ—øÈ‰Ã»­Ú:õ}ÝGª”ø18GñÎh4ªë:½¥Eõ€sqÒ«¢¢"›Íj–™´MW€êñæå¹ÓØë.{ûIõ84‡™Ï]éîJN¦7í9Òwû»êéär¹Ü{FFFh§ßïO$ª§“(D÷žÉÉI»!ñûÞcoü ¾áø—Ûç:í`Wüýë—ÏîèèÒª›5ƒª‡“£'‡L&3<yž÷=w\ßl·»f…'''ŽYÓ;f¦¦>9|¸ôŠÕûþüùÒ"}³ïúîܹÑÑÑñññ‘ññÒ«jøåÚµÛ·ovìXé!«4üìYé ‘·UõTéìÚµ«Ñhü>2RzU ƒs¯ÍÌÌôhC=~\zB¤QÝ®NOoÙ²eÇŽKKK‹‹‹¥'ÕóêÕ«¡¡¡Ý»wW¯Ò[V£Ûã^T½‚7oÞ¼|2ª†JÒz–7oذallì‡ÉÉÒsþwZÕ‡¸v»Ýjµ–ï/,, ”ÞTK§Ó©j6›UC=*=§¶ê€—žùð!V¡Qz½M@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD¤õõéÓûöí[¿~ýÈÈH«ÕZ\\Þ¾½ôª~»sçÅ‹KKKNçîÝ»Ÿ=ZzQ= ÷ï—žiÍÏϯ]»¶:U=UC¥'ÕüÞ ~ùòe»Ýîïï/=§¶^ܼR«ª§j¨Ùl ,_JOª§üþ TeTzNm½¸y%W ÂzqóJ®@…õâæ•\ ëÅÍ+õÍv»¥7ÐÃ|DD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD¤uuzúéÓ§h½Ñh4º›6•^UCwvvéN§sñâůN*½¨žÁ¹¹Ò"­úöìÙ'OžlÛ¶­Ûí6›Íg¥7Õ244TÕóüùóëׯoê©ô—õ÷÷—žiU·­[·Þ¼ysãÆccc}}}½кuënܸ177÷åÉ“¥çÔ688XzB¤o¶Û­~ÌLM=xð`bbbçοöÔkbh~þòåË>ìÅz*£¥„ÞTùéÂ…{÷îµÛíÏ/½ª†oΜþâĉÒCVéñ­[ÉŸWïÝwgðÏù÷ž¹z¤õþÎÞƒ÷®Yóó¥KÿÁQûíÙ³gûþý¥W¬Þ•+Wþòwþæ¹\EIù3¸Á*øˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆˆ€ˆˆÈžs¬;IEND®B`‚simutrans-124.3/themes.src/aero/gadget.png000066400000000000000000000067501474050137200205250ustar00rootroot00000000000000‰PNG  IHDR@@}g_H ¯IDATxÚíÜ}pÔõÇñßãîþ~ûü˜Í†˜’4DÄ€èq0UôôzÞu¼³Òk¯¥ŠD[‹•öN½ª'7wZ=¦=p´•ú0ò,‰’1l÷!ûüôûýî»ä†:iœÞÌoáó†ÙlòÇ;Éf?ù²ËÒýŠBÀÿ·Bšî×Úì} tvv’ UUUo>¬vÎUŒÿúj«þ½½mÛðÈÏq%%%K×®U;çk{°~AïéÜ׿tzå›Gލóõübýú£G^¾ýÌŸ?ÿŸ¶nU;ê:êÿëïÿwïñ÷¿8N.{ÊëÊfßóú¿< vÔuÔ?N¢·‡ü-L-S;äZ-Ÿ7ÏcµÕͪ-**"«Ðïóhi ý¶©Ií´+úÀi±þËÞyi›YpTN«)ô'S©³g»[ZN”VºîX»Jí´kò­Ù³‹¬öš[êÜÅE4E _ôu´¶öü¯;¦vÚ5Y6gŽÃᨭ­-"ý4uñ‚¯­­Íï÷ïjnV;íºè_´pÉYRzóe^+y³g`´ïä¡ÑÁžƒ‡w¨v]ôCÎ^c´r«'¿ñßV¿téÒŠÚZ»ÓA3LÈï?}¢eÏîÝ»?9røÂµ'ö¦ÑúËÞ}aGMå-%7xY–erÓ¡eY‰ÇR'Û;BgV|÷Aµ¯âÒ©w̹µþî%%³jÍ6¹& \hm=üþG››ß<×­vàUÜVzãÜs—ÜµäæšZ‡ÃES²?lmoÙûÁžÆCMGÏŸU;p’÷Ï«]R~늿X|ëœÊ]$× ãÍŸþ~ocwã;M­©8ÉûÇ;{ÑÄ lUÝ-Sy~ñì¹3nªqz YŽ%« g¥@GûÉ}Ç›{3™ÿ9ž¿Iscõ·—ÌsK’á¢/=8HêuYiJVšë.ˆ•LYsËìü¬óëg_5í›·[ÉÒ2E)­ÐŠ"+<«›>í¦è~öÈŽ]õ«—©yEß®©_êSí.vSj‰ŽOÂBËäÍyÕe¤`ÝÌY/¶·¨yEwÍšUHνuºˆåû“‰‘…UßÜ{r[B¹êÜEA/ù€Z4Ó?§tö¡ÎÓ\F+ý ëWVͯ¨¬rZ…´$÷ûcäJIQÈ›UUUÉÈÂ;ï¸ßþíjgNÚþq.Ÿ½ÆhâföÏ,,?k‹žOÛ, EçîG%ŠˆCÁj… ûÕnœ§ézâ³?.ÔÏõxhŠî>ÛõôÖı3ݧ׬xhã?>ËqLUÍô–ÓCwì¸}õjµc'ðÚæÍ®ØÈ¬Ú)¶ìJEuÍëY¢c;—ª.¡Â¾Ðk ßjhP;v¯lÞæB–Jð¡­+ô¹/nØ´ìÝŸ¾ïâšeÿüÖ¿!ÍV*èßÑBÿËw?óÞ½d€ŸÞõ—ÑT"ÿûÿaózË‘ä''}Ç\ºÿ”d%‘–Fc)³»4ê÷=ÚðÞK ÷¨; ûÇ!g¯³=ù~^ç‘EwLŒÁ!£P™°6Q¼>÷MȦ”PT F<2])ˆ-ºóßìS;v€Öû¿lÜÙkLþŸÀ'OÝà*p±´ÉfvrM¯ëüLf–œÎ$yƒŽU¸P"*1§Ô.7®Þ`µrzù>h¢žHGXs©QÎfi™qZÝn»‡¢åx,R]U§H,•¥hIo·q[.ª]:1¾çTÕ]OAÀbÍêNV´3:=MÓŠ”’b~ê¸ÈhÔqâÃNµK'vf¤ãƹOÂn¡_Yíûñ¾ÛyŽ¥s‡xÊf³2\@Ç$²Û';Ô.½z¿Y$?½>gî10ú'>±èУoåy,Ø?å¦Å «cyÞnÌ¢^ϳä“ÎÊäøŒpR6#XÜCg[Õ.œý—iñì5Æ)+N±x,6³èpÏ4ø"|€:°é¶ûRÆÑ¸× á@Ð&Éj—N€W/˜¬¼»ÍfÒù_IV)ƒž“3du)Š¥5íùÏí¿Üñò%Mó,§7(ÙTZíÈ+r8e—›²º‹ÍΙ½”Á"óz†!ŸK’J†ŽÑÅÅi—Ô.½“ìvP….“Å"’{ÿwŽÓQ—Ìã.ÖxŸˆ»”sV ô[.Šêðº‹HF"·'Êí*Èó~^oÔ‹f³Ùh5êVAÔsÜ¥§1‘0 £0¹‡t¥×Qä†ôìK?Úü½-óçÕ¥ÓT2Eqz:œ.+ËÓç 3xÝÁêàä`£D;ËësŸ†”¢¢÷j&«% † Gâöâij—NÎ~JËg¯1îÿ`Æ4ƒÑòåõzû;OäÞË4Kf‰Ì†ûÕ.w¹Þdsf3e1Ó¢@î@éD’Ü~ò¼žP¸D,E³^OqŲÔìÚº?[p;sé¹(ù[¦ú‡ÏVVVª]:1kM},õ¦¢/RLš|ñ&Z)–V’IŠ•e’ŸR"‰‹–šj—NlnEý©øWjm‹ù£èú%¦­G2›sŸšÍ¢(t*&'c½sËëÕ.½¦þ\¶Ýº€{úãÔÆH4”ÿýÅ߸90xÁ +0_:¯ˆNϳäÇ7•–”KÈ…d4P\>SíÒÉé+Î^còÿFôYFùØåõzçérצ’2Íð’Kõ·:Ônœ3V?O2‚Y±ÙÈ}(e4Qf3m5+Vo´ÄRɼ­'–¯{øÓö÷SéÜ?’ÑÒñÇräFÅÐÏ‘}£â‰X Ósëòåj—NlÕ¦-í~W ‘͌侓¶[(‹‘ü¡-&Ên—ES0‘ý,à¾oÓµK'öÇ·Hƒ.ò[ŽÀ™m»ÍhiSž«çŸ:®üÄfuˆ‚)™ÈÈCîG7j£¿Yù1Y¯ve«UgÔDÿ‹OÞŠGc)r^1 :²a]nÃÈ’™Ež\ ïJEƒÏoº[íÒɉìÓWÿQ;ðšTUÈz‘ézæÁ;žWDA1³‚˜äùáHøð鮿mÌÓ—³È Ø·66vvý –ËÅlÔJý˜å?\ÓÑÝHn*¹§ÿ+Ô§-M‘D˜asÿ®O†>i{{å÷ÿFíÆ¯²ò•ÖŽû. &$>CdÖ,+æ +&(Ý`8º÷„ïÞ—ó÷?!¯þ¼íTcÿH (¥X&#ˆ²ñŒô2›©žj¼øÊsyýü¸þ3ÒKÙ¨¡þ¯oèüìÓ¾¡ˆ$+ ÃÑ"Æ24ys ïl?¶óõõj7Bþ:øPÅØzÕW/ÚÓØØÑÓãò§»{÷5}º³÷Ü}'ÚÕn¼¢?¼”Ôk«–O3 ¥U•î/˳þÁó]]g"‘¿úÍ;jG^“¦_íZ4o‰Ål ¹ÜŒÑ25ìýnßÎeëþNí´kòÆã‹+fPe•Ó<……´B öõœélSÖ6hãež|êÏKjøé7–{]à |Þ×Õw*µiÃnµÓ®‹þ5ÿ«ÉYT]^<ÕkaêÜ`ääÙ¡èÈ…_o{Lí´¯²òÁ-6ï7J‹œü9‡ãép,Ýë Œœ!;­vì$´sÅÔΡä¦#—¯yí¡ûS¡r0: ø¯7Ô¼Šñ/æ«­úqv½ún»Û,˜%I %Bë׭S;êkxëÅgbÑf)ë#gIA,Öéf¯|ìqµ£¾†í¿üéÅȱX¦Ÿfh‹Pä5Ô­}ôGjG]Gý?üÙî¾ÞîDx˜\íE%SnxvÃRµ£® í½Ú?5ö€æ`À@“0` I0Ð$ h 4 š„M€€&aÀ@“0` I0Ð$ h 4 š„M€€&aÀ@“0` I0Ð$ h 4 š„M€€&aÀ@“0` I0Ð$ h 4 š„M€€&aÀ@“0` I0Ð$ h 4 š„M€€&aÀ@“0` I0Ð$ h 4 š„Mú_8¹áµß²IEND®B`‚simutrans-124.3/themes.src/aero/listbox.png000066400000000000000000000007541474050137200207540ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûP³IDATxÚíݱ € EQ÷¯YņAhÀ,(ÑLL4r€ŸBÇVj;æÌíÞÿå΋Ö#€’@HI $€$€@@H d H $$€’@HI $€$€@HH $$€’@HI $€@Hz¨Ô}€½èÚ @@@@@@@@@@@½½{$€@HH $$€’@H S@H $€@HH $$€@@HQ€ö>¢þÙÊtýÛ yI $€$€@@H $€2$€’@HI $€$€@@H $$€’@HI $€$€@HH $¤Oºh#¼ºQ·GéIEND®B`‚simutrans-124.3/themes.src/aero/posbutton.png000066400000000000000000000016671474050137200213310ustar00rootroot00000000000000‰PNG  IHDRÀ@Ãïˆ~IDATxÚíØ½kqÇñ{ªy¸&ikL‚H«ÔÖ©H©ˆPE(™UWŸpPðptíRêС›8- ‚›Ç.ÒVBÅZkÛ<]r9¿ö‚›¿û_ŸØ8~š{çw¹êÓÓÓµZ-›Íæ®\Ñ:лÅÅBqC+¼ýpRzKÕµ5×u£Ñ¨‘ÉHo  ù|~``àÅÜœô˜ t]׺õzòÂyé]jLÓô¿GÓ½Œn¶ôž÷W@õz½P(¤R)éUÊB­ê˜®ëXŸ ãC=gòyéEjüS‡.ÁÖÖV8–ž£²Ü±m›Ï•••É«W¥W) Ûšë}«~x5t¨téæué9Ê袣too¾ŒšÙ¬ôí¨R©,//onn^¾{Wz’šöc|ås¥ðìtÄ»xã–ô¢ èÎEg]…èà ô5ÖÏïš6;;Ç;®ž_¾¾z:1rbtjJzˆ2ÿý___§g—Ž«‡Xô ^ZZš˜”®_8wöØØ˜ôŽ èý§§–d2Yïí•Þ„^:¸ÓIr€ÿ,X° `A@À‚€€ ,X° `A@À‚€€ ,X° `A@À‚€€ ,X° `A@À‚€€ ,X° `A@À‚€€ ,X° `A@À‚€€Ë]â¸É8VIEND®B`‚simutrans-124.3/themes.src/aero/roundbutton.png000066400000000000000000000044431474050137200216520ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPêIDATxÚíÝolõÇñûgßùOç¿I-JS­ë²©+ÚUXClL¢ US¥!•n+“6Á6±iÒx iÒÊ@TÚƒ UcÑ­ZÖf“†€(‚jÚjªJ+ICÚ$vb»±}¾ýb‡ÄMÝÝgðã§~^Rªæ”:ßúÞ÷»;ûõ ÏÓj¼188°{·¦Ž¡ƒ¿¾k—ì)‚;rà€ì úć½òì³Éd²··7ÑÛ+{*οýöéÓ§¿uÿý² ¨>—“=d) QHgóæÍ†a\I$dOåƒ3»hhhHцÂÓÓ²G€â럇uuumذ¡\.—J%Ù#ùãºn4íëëÇ€ìY‚ð·8‚;;;«;C4$û)õ§:sSSSGGÇÑÁAÙã\w,qWWWgYVõû|>o˞ɗl6+2MS4499){ßÄ.{ˆ5::ºmÛ¶\.‡EFâ¦V@… ±‰«7ÛVköEÅbQö+“ÉÔ××G"‘êÐòR¤ŠêÀb7ˆu4 ÉÇ7g®eõ÷÷Ÿ9sfÇŽV…8Ž=üQ?Eâ º\!Îe²Çñ-ËbõïÜùÒþý333ÝÝÝâ¢Z\L¨õºD5 ………áááöövÙãø¦ü $¾Ö¯_òäÉææfq#£ëºZÅb1q:22"î%ï{è!Ùãøæ8Žì K/$<˜J¥6mÚtY©c"šÉ;vl||\Åz„¤ì@+oe¼søð¹sçÄ¥è]{öȞʇžzJÜ|gï^Ùƒ4}êòÏÅûúÝ̵[>¹G[Vî¹n½ûî[5í½×^ûžµÿ£­[·ölß.{ŠàNœ8qÍŸù÷e€’ðG^Yˆ0d@jc@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@a@±V}ÿÒþ·îy𫲧òaÿcÇüõm²§î{·ÿI¿z‹çyº¾jÛÙèU¶.~ú¤¦lce»·Ð~ù·Ë³¥Öd£ì§ÔŸnnâgGùí7eÐcOCöÁéË+ÐÏ8m¬ï¿ý».,{*:zš‹®÷Èž#O¸Kö,AÌʲGN¬~‹=ù‹#3N¬w˳–a¹Š}ïtÉ3Úë6ܰoÏ+Ïø®ìq|›šW8 q^³^~þõ7Ç ë¿pcÉ -èºjýhW+X†ÓYŸJ5üôǃOÿ~·ì‰ü)­¹ UŠgýktz*Ò¶Î ë¦Qòô©9SöLþ¸ºYÖ\Í4‹ §G?øëó/~ûûdåÃY][sqêç¡ø7—ËÖxv!š¨ÏäËci7æ˜Õˆs+7_Ì/hÝmñ»ßþ£ZeËŠ]tÖ2Ä ±µîdCk"¶Cz8³B²§ò'æØ–æ™–QÖÝ–Hº¡!*{"ŸóGÙ#'>ëKÉâ»Ù”Ýù•hÚ¦j¯,65dzو—+¤óÓÉK¿m`›ì‰üiiQlɯ%NžÖ÷²wêñçæÒFóF3¤9ªvDËL×-X‡·ö$¾|ç²'òljȞ³˜ÿÃþà7¿ú]Æ)6õ}ÑVíŒìÄ4wv&v¨'|ñÞí“=ŽoâPöZs]MŸð–nÜŸyüI·õæ–ÏoÞõµ9ãrøÔä…£éˆx;¸Wö,A¼™YûV„_ø#äº5oeì{ôá¼øçÔ»Ç5¥º|üÐöŸë»ãÙƒôÞ Ï-íüê2â]ýBÜGm¬¼;Uýn%Ÿ P³qÍË€³Q×ËåšHQ©‘‘®-[dOÜÈ«¯VÿâUvÄò–^Í~ùøn©Tû€ÕíÞÕ»õ£6¦yÍßUûꪟ4 Cù€H.ÕîÚé3†„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„dõ‡–»ccfg§ì©|(²§®0:*{ÈÊG^.\¸à8N<Ÿ‹ÅdOåC$Îd2¡®.ÙƒÔ꺲G€,­@¢žº ]×çdÏäK,³m{*•R´¡r¹,{HåèâÅh4*ÖmÍû~ö‰ ÃH$â=Ëõh1 B¡ N^Zeg¨ø3 E"‘ÒØ˜ìq®;–¸ˆÏþògƒ+·¢º®+ó‹ÿÅ•+Wdã›rOø*Öüü|[[›Ø ¥RIìW ±ª ‰s™ìq|S> qþ²,Ë4Íj:ËK‘*ªÝˆÝ þ*¤â̵¬d2977×ÒÒ¢è\M_L.Ñ|>¯Ò+Î/{ˆ¥%“îùóÅbQ܈É&ˆjôbºtéRõV@-Ê-ù«,¾‹ÅÒét8¶m[ö<¾‰#XÔ#Qq.ŽvwËÇ7WýZK¯D—Çdz٬8ÅãñI¥Ž‰–RI¬=¹\NÅz„¤ì@+oeè““âŽLÜ ‡oºIöT>ÌŸ=+f¶×­“=H@uÙ¬ì +U™SSnk«ì©|°gfeO\þý÷¯ù3k_^ ¶å“xäÕù¢öIÇ€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ò—²CãöIEND®B`‚simutrans-124.3/themes.src/aero/scrollbar.png000066400000000000000000000124201474050137200212440ustar00rootroot00000000000000‰PNG  IHDR€560×IDATxÚí[LUéù‡¹óÞ;o›xÕ&íE“^6klÆ´‰‡ÎhÒñ„‡z¨ŽÖ*Ò«XetT6r¶¢€ "9* âY¡ˆŽ"Êù|ò ÔÝŸ{…=Èà¬8¿OŸ7OÈb¥aÞµ×o=ëûÖ·v ÈÌÌÌÎÎ>1T'Ož,VÉÉÉÍ^¯É.Y²dåP­V³gÏ6¼ÿ–––ÖÖÖŽWTcc£áý+!ãüø³¤\)]†÷¯„ ŒòãÏ’r¥tÞ¿òªð(WJ—áý>|¸¬¬ìº¯ÊËË+**´Q1TÇð˜3gΦM›¶øjóæÍáááÚª… ÞSSS__ß_ù7üe~€”Zœä(ENœ”+¥Ëðþ•Zœä(ENœ”+¥ËüØˆÌ “Òeº€t›êíí}òäÉÓÑ*??ßðÐmJ7áôôô#£ÕòåË ï_·©ÿ¼¢ÚÛÛ ï¿¸¸Ø÷ÕÝÝ­‘áý¯^½ú¯R~PÔ€Èðþ;;;_QÊ•ÆA¦ èèÑ£Jù³a¥Üìß¿ßÙ>vì˜á°`Á‚}ûöe +åfæÌ™ÎöâŋͿƒõ÷÷—ŽrS__ïlKO†÷¯„8QQf”œáAR®”.ÃûWBœ¨(3JÎð )WJ—ù70'*Ê̈;™reÁL³ôÚÚÚþ¡ÒGÃΩS§:¿š?‡×,=22òèPiÈ3~üø€€çWóçðŠˆ†ŸÏ‡JíÅ‹5pp~5?@JˆeFÉQ~üYR®¬ÈeFÉQ~üYR®¬ÈeFÉQ~üYR®,SUU%wêgpp°bô±¯ûJ÷Ã@‰Ù¶m›‚®Ÿ'N ªÃ¾š?¾áý+1>T\ô³¼¼Ü¿àÜÄšUf÷¯„8Qqb£ü(EþD™?…WBœ¨ø“£ùeþ^q¢â_PŠü‰2 pêÔ©êêê#GŽLz¹îûÊív~Š{DDļyó^®(_MŸ>Ýðþ5‡WP£ü—뉯êêê ï_ q¢2"?J”r¥tÞ¿âDeD~”(åJé2¼%ĉʈü(QÊ•Òeº€Îœ9SSS£vKJJ-Z4y¨Z|•””dø¬]»v÷îÝñññkÖ¬™0a‚?@ßøjÖ¬Y†÷ßÕÕ¥áógÏ´QZZZ0TÎc”††ÃûWBœ¨ø“£)KJ”r¥tÞ¿âDÅŸ¥HYR¢”+¥Ëðþ•'*þä(EÊ’ö(WÚ0]@—.]Ò1Ȕ΋ééé3f̘2eJ§¯Ì_F ‰‰ILLÜ¿BBÂܹsǧ%úÊüeÔžžž§OŸ:MçNpüøqgù˨JˆeFÉQ~œ×š´G¹Rº ï_ q¢¢Ì(9ÊR¤,ir¥tÞ¿âDE™q¼¯9{”+¥Ët•••µµµi´&_>zôHº›Éý}•››kølÚ´I³€ÔÔT] iiiÚÐÝL÷áT_-]ºÔðþûúú”•ÁÁAMãÕSHcg[§Æðþ•'*ÊŒ’£ ¥HYÒ†šWº ï_ q¢¢Ì(9ÚPŠ”%m(WJ—áýëCv¢¢Ì(9ζ“%åJé2]@°566v¿¢Ì_† ‹=øŠ2¾··WwªW”Ëð¯ r¥tÞ¿òªð(WJ—áý;ï‘ZÊ•Òeº€Š~¬ ?€+Ãûïü±2¼òC~Æ$ Ãû€÷€€ @@€€ @@€€ @@€€ @@€€ @@€€ @@À- Øu)))VŸ€xËkÄá¸\ìúüC7ž´:?MNô2ýîÐ¤×ØùÑÐαÿ…7ÛéÛè{EGGgffVWWÛu.^¼èv»í Ð#ËË aa…ËWæ~É®Ï?Ê]R`o~NWvØKIeG€ß>ÅÅÅÝÝÝv5\[[k¯ƒ:-/ç(,ô¬XSt(§öhI£]Ÿ湦]ñŸf[šÏÕ6{Éú¶í…€ÒÓÓsrršššÚ}e× èèèhmm-++“Cm P‡å¥CÙ=mEáö´ï¢ îÇ5Øõù'œnÜs¬vÅöo§fZ9…/i±˜ÓÍÎcˆk×®I@---º˜í:/nn¾wï^VVÖ~Û`½ŠŠËÿÍüŒOw^ ϪÝu¼ÎuÊ2EŸjü*ïþçÉßýú¯E³—Û—Ÿè’‹9Ý û¤¦¦VVV:Ò•l× ¸{÷îíÛ·õóìÙ³qqqÖ¨ÞòZšü³e…Ÿì­Úšsÿ«‚ú žf»>WQËö¼ºÏSk~võWóRãâÒìêÿ˼Î/ó»ÆÄØÿ›òEnGÀÆ ._¾|ëÖ­ššý´ëܼy³¢¢¢¼¼üüùó‰‰‰Ö è®åõ‡`÷/Ö_þýŽÊÉwÿ–ÑœaÙ>ÄÓñ—¤ú¹ 5Ó\·~¾ázà »ú_›óÀ^Öåô¬ZµêÂ… º†«««Ùuîܹ#i§C°qIÞöÐ'ëÜÜs3ð@}È‘–uÙ¡ù}v}þ ¬õ´/OmüÌ]÷ÛÍ¥!«×[6*°—MÅééén·[·²ºº:gf× PÏ j^ݱc‡uê¶¼¶îŠýÓÖÂe=¡'žþëœ7â‚eŸÿ×W¼›O®É{üç} ŸmÏÍ͵«ÿ¨ ‹q]÷½ˆèr¹®^½ª0uuuõööÚuzzzÔvss³æ_IIIÖ è¡åõb³%f‘»*ìôóˆËÞÈë–}þ{ÿí ?ï Éî™·õèž½ö=CL¸m7/”“““pïÞ½þþþ»N€îëë;qâÄîÝ»­K´¼œ£Xñ]A)å»nxãîXöù»k½ÿ<×µôëŒðQ6æ'©Á›Ü8&ÆþÞ˜uC_ÅHIIÙ¶m[YY™d× ÐM³HKí#l¯ï¦lÙ¾>.}çyË1bªZþ¾3.2:ÖÒüé}~¤×;6ÆþÞ´®çßÃãñìܹó‡ßî1œˆˆˆØX[Ó#ªÆV7nÜøÑ=?Ý_ÖžáÇ’šv8"r¯]Ÿÿ–=®üü|{ó³!*:ÔaoÌ ü¿þß;£¾ß9ö¿0lgôÿ°soÌzWÌÈ/£æååÙuJJJìMˆ|r¹\oeÏOñ—­þðEé•+V÷Ÿ“ãp,;[Œøõuvz^®,_½æÎ×ùoù÷üð™›—Çÿ¼3 @@€€ @@€€@@€€ @@€€ €€ @@€€ @@|ØÊÌÌ<|øðÉ“'³³³=ª_óóóO:uæÌ™K—.•––™|sæÌ Z²dÉ‚ ôëòå˃ƒƒ×®]brÿ---MMM­­­-¾jooïìììêêêéééííÕ¶Éý'''{<eæØ±c OFF†ÛíNJJR¨rssµÓðüÌž={áÂ…ÊÌâÅ‹žùóçOŸ>}Ö¬Y ÕÒ¥KµÓðü466:™qòÓÜÜ\WW×ÐРPµµµi§áù wÊÊʺ»»•uFmmmUUUuuuMMC‡gx€äM›6%#]J’áZ¶lÙæÍ›e'@*9(..N2JIIQ’ nSŽ€œ©†H½ÏÒày¸€Ô±N†rN€¤!äÁópi0oÞ¼øøx'@ÒárD?\@úðýÒO[´ÿþ©S§~üñÇ“&MšûúúºººdŸŠŠŠÛ·o777ËAµµµ:(c›Ÿ²%æO[ ÿ¸çæ/Ö_þÙ²ÂßÌÏÙm~Ûùùùß÷Ïs]áç½›O®õ´ÿ%©~{^ÝWy÷÷«Ý_R`lóPè y“_P~×pM2\@ $$$\½zUÑ×Õ{ùòåÊÊÊk×®ÉJÑÑÑægh÷îÝ'NœqêêêÔyyy¹äÞ½{eee&Ûç}ЊìZä®Z–Ñx þ÷;*?Ù[õéÎkÓV.Xè1??‘ѱK¿ÎÉîY“÷xyjãÜ„šÏSk>OþnÅöo? 4ڡ<϶mÛt¹*ýº€«««oݺÕ4TÅÅŶ8(11QÍK çÏŸ?{ölVV–ù¿Ú¸e{PJyØéç¡'ž†iY‘|wkÎýð¬Úíiß­XSVh~~ÂwDÍÛzôÏû>s×MsÝúeØÕ_ÿµhZ`¦ámËÎÝc·€vîÜ©‘B¿¦02ŽìSSSÓâ«ööv]™™¦Ÿ‡¤¤¤;vh4'ÅÅÅí?pÀ‚{¯ýJM;¼>.}× oÄeï¿Îy×ewþ-£á«‚ú]Çë¢ îÊ©]¾Ò‚‡AbÏÞ¸Oƒ¶ÿvséÏ7\ÿÕ¼ÔÙË-ÈõÊËËS¸eŸÞÞ^IGö‘ƒ4 jmm•€tIhXqÀ†‹ÙFlPé•+‘{wž¿wÇyÝqÁšßœÑ¾ÁÓì:Õ_Ôp´¤ñ‹ðK.×+NGnnnÈêõ ƒââÒ¬hø=ylä5ôÑï! @@À! x_xñ „€|x²} ô!âr¹¼1<„F@`º€X†Œ€‚÷VÁB@>L± o «`0æF@ð.xÝU0Þ™€X†‡W èÆ~R1F@ðöñx<ïÉ¿Šl# xsXŒ€ÀZñ @@ÈJ± oLVVS0`F ˆ÷€ÁÛ‡‡Ð0&XŒ€! „€à«`€€! ,ÃÓÄ2< xûð „€! @@ðÿ* VÁÁ»! @@ð.xÝU0£ÂwÁ`,ð¯b# 0]@LÁÁÛ‡ „€àÃËð€€€²VÁ`,¼î*F@ðÎÄ2< xWb ¯ÿ.¼1<F@€€‚S@,ÃÃÃ*Œž# 0]@,Âw' –ááUb ~j1F@ðöa  d'¬‚ÁXÄ2<0F@Á‡Å‹‡ÐŒ€`,b ޘܼ¼õ®˜´®çê^ÈuÝ»©x`]Nß¹ѧÛãO7g}ÛVòâ= C—áÿ ¹ù—ƒÛ‚FIEND®B`‚simutrans-124.3/themes.src/aero/skins_aero.dat000066400000000000000000000103041474050137200214010ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi # # All image name must starts with "> " to have them unzoomeable # # This theme tries a macintosh-look # -- Obj=menu name=Button # unpressed left, middle, right Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.0.0 Image[28]=> button.0.2 Image[29]=> button.0.1 Image[30]=> button.0.3 Image[31]=> button.0.5 Image[32]=> button.0.4 Image[33]=> button.0.6 Image[34]=> button.0.8 Image[35]=> button.0.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.2 Image[2]=> editfield.0.1 Image[3]=> editfield.1.0 Image[4]=> editfield.1.2 Image[5]=> editfield.1.1 Image[6]=> editfield.2.0 Image[7]=> editfield.2.2 Image[8]=> editfield.2.1 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.2 Image[2]=> listbox.0.1 Image[3]=> listbox.1.0 Image[4]=> listbox.1.2 Image[5]=> listbox.1.1 Image[6]=> listbox.2.0 Image[7]=> listbox.2.2 Image[8]=> listbox.2.1 -- Obj=menu name=Roundbutton # unpressed left, middle, right # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 -- Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=> scrollbar.1.0 Image[7]=> scrollbar.1.2 Image[8]=> scrollbar.1.1 # scrollbar knob left center right Image[9]=> scrollbar.1.3 Image[10]=> scrollbar.1.5 Image[11]=> scrollbar.1.4 # back up and down Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.2 Image[14]=> scrollbar.2.1 # knob up and down Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.5 Image[17]=> scrollbar.2.4 # scrollbar back up center down Image[18]=> scrollbar.3.0 Image[19]=> scrollbar.3.2 Image[20]=> scrollbar.3.1 # scrollbar knob up center down Image[21]=> scrollbar.3.3 Image[22]=> scrollbar.3.5 Image[23]=> scrollbar.3.4 -- # window background Obj=menu name=Back Image[0]=> alt_back.0.0 Image[1]=> alt_back.0.1 Image[2]=> alt_back.0.2 Image[3]=> alt_back.1.0 Image[4]=> alt_back.1.1 Image[5]=> alt_back.1.2 Image[6]=> alt_back.2.0 Image[7]=> alt_back.2.1 Image[8]=> alt_back.2.2 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- --simutrans-124.3/themes.src/aero/skins_aero.png000066400000000000000000000242761474050137200214320ustar00rootroot00000000000000‰PNG  IHDRÀ€µ%H(…IDATxÚìÝ tSe‚ðûLró¼Iš¤/¬¼ÚJA˳@ApØ£.ç Èx¾ÖÕuUqtƃŽ"ê0ƒ#»³:3ê‘yøYõ¨3Î8@yRä-JySšÒgÒ&iÞ¹{Cw¤i{/í—¤ÿßéÁ›Ûÿ¯Üüùî—Ü„¦Thkk#A•M›6õyŸP(4dyt:Ý€î¿hÑ¢!Ë6š$é¢=·ÎšUWW'o”——¸e é€}àH i(Ë1ó ¥…UUN‹øÝêê»/–kµÉí¾þ?µtz?Ù¾t´^¡@AŽËîCHžñï¬Îþ‰œçÒ$9_¬ÕÅÅógVÏŸ?¿´²Òj·Ñ ãmo¿zléúµkgo9s†tÀÔ²ûèPéÂb"RR=]ÙóG÷l§ìñ w¦lج¶xÒä™EÅUWQ<®ktGš›å¨&‹Os¸Å#n›<åví$3(¨‹ÅHGÎL•²ϱ ©ØÚ>¡ Hÿí>óéˆhf(𢤏$ż>}‹§Bb¼­í¤3¦†…a-ÍT.Çfyë9s¯ .O‹Ž‘¨hW¢ËHñZ¹A©XXòúõŸ3A— ú‡ç\÷«MH‡½ TÉö5Pê‚ÙÜE™c³¼Œß (¨’ík hIP ÃÚå}‚[qcÑ3K¡@A•l_¤è@{¹Ÿ÷¿ð˜;g‚ì>úTì—Xâër TÉ5Ћ®ì³i<#ŸKP 0¬éÎIùñG˜åAŸP  J¶¯öHy" (¡O¹pô¨™&(†Ur` ôüvoïÔÛþÞ\:uííòvÈv(P€Ôz«<U8 ÿ¥§m1/Î (PP%Û×@3pbxÑsYɲûèP)3'zø\ølU²} ”ÔɲÊ7¸Ã¥Ÿ ÑOßÄÇç(¨’ík Cl OèC†ÃÑÃ* Ô@‚*Ù¾  C:¤ƒ'Ü3f   Ö@2f  aúªdûhN1„Þ @a¸KyyJú ªäÀè¿(ª9—dýÑ Æe©³µ­šjƇÊe(¨2Ö@Õ»ìe‡öÌ(P€A‡+8s TÉö5ÐþwÙeœ«öüV¨ÑÝG?€J™y Ÿæý@qaRFA‚*Ù¾ªÞùR»Œ3Ê4¿æ­  Ðù.C© [(PP%—Ö@S>Փ改ÿgÓhØ\•ÝG?€J—¥Õü)=ðaGY  ªdûh¦Í 3-¤‡…aíÂKzH] OˆË^(PP%—Ö@/Wi^z~éï|á}.½./cÊÙ}ô¨DªÒ”õ…ÒK'§˜®fºI’HgÈJÏ@o5«®®NÞ(//ÿpËÒñì£5kZÛÚxŽ+..ž¿d é8vWõ¬“‡’?ÿ’«ÊÞÙº•tœø¯Çß¶mÛùƒgÆŒ?\½št¨á5Šyì'w}Ö|t—¼í=iä”›ÞüŤCåxþÌ@VU9-⤉•………ò®&·{÷ž½-ÞO¶o'²_>~eI°•_à, …ÃÇÛ³gwIYÞÜ%‹IGë—{¦L)´XÇOžä(*¤)ªµÑ]»woCGû›;w’ŽÖ·S§Úl¶ÊÊÊB9üåå÷Ç—M.¾"ŸeY†‘û‡N$¤î@øÀþÚ³Þ#7?ré€}¸£äʹS§Wß8¯xb¥I´É{|žŽ3{÷nùlÝæ;Þ9uŒtÀtf–Œš6kÚ¼æ]3¾ÒfË£©D»Ç³wÿž/þ¾¾æ«íÛN'0÷GQU9oôô›ÿùúéSË\N«^ÞÓâéÞq¸ù¯_Ô«ùxûÞu¤ælþä‡Ê-ž4yfQq•ÃUëÝ‘ƒ‡Bj5 #bñiWuñˆÛ&O!3?¾ðziq•ÓQ ŘDœŠGéXLŠÇ$žÕ\5öjc |ëûŸ’ΘÎýã+g”äO­p9(3ÕÌúëYÿa3Ý,߬ªpÎéZ:a"錽ºaâÄyÒ?ÉIR|“;X7ªdTçf‹©¼IŽÂñùòHgð(F—\٬ϖQÌ®^\P>£´¬Ün"ñDS{@þ’7ä›åååE³¯›{;éŒ9›ŸýѳϮ[¹jªÑâhoåšÏOó×Õúët® ¬?©‰K­Í- ý騩}ûù—œg̘Ò–gNœ:òƒ'îyçý߬\ýDGGÛìéó(‰2êíÇœjvï-©¨ 6…7V¬íÜ:g‚%ßÑn`K]{b­;Ï}}“ðì§»ÝÚhÜwºíp»wâܹ¤Ã^ìµ+vÛ.N2°Î¶8¸Å÷íÕËöÙ-wW?S¶ x6äö3±vw[¤Ñ;%óÂ÷6ŠŸ»ò§»åŽ™O¹!àöíÍðQüÇŠ¿¶ÜŸ_Z%±Ú6o𘻳¾Ás¸ÁsèTÇñ¦.?,1|··¥æ(}ÓÜRÒas0?÷Àœ¹W —§EÇHT´+Ñe¤x­|LÅ’ׯ÷øœ ºLÐ?<çº_mÚ@:m G;JóªäÓv†aí¶üç–½dÅ>}÷Å—Ÿ~êÑÕ4Kk„ÄâÔ‡×\K:jJÇ6n7RŸïð˜9/¤8ÊÀ²‰¡¤X„ ¥3'x-ÃÈc QAAçÕ0šn»O²[㤓¦bL8lTAžÑlÖ˽ãr¸4œ†:W NG‘VÇëø`wžtÊ’‘áSÂbÈ£¨Ú|G¡<Šh\>¤(Gž+“GÁk Z½Éd2X Z»EÐk9îÜÓ¨r^¾é D:qùn¤“æf~Î1¡‚÷·êóDÑn3›­¼Ù Z*ùøD9VžPĆ÷t8'd⢌ÑFå^š¡4¥ÕP4M½ðÊW<ºjFÕ¤H„ …)NKw[GŽI:ijBé8^Ó¢³Ø8›<ÿ)½•åµÉaÄÔŸghZÃøµšN}i&þüǬÐiÏŠ&‡Íny«þö»Kßý[ë#=jó8NþkéÒi[ÊG'´¿£0 É—@8ìrÒ79^zûØíþöL…¥`´ü °™t¢IgxƒŽ×ðÉg†£1In"yƒa˜._·µh,餹™ŸyróF(¢3˜¢M°˜9‹‰‘O¾¬"+šuQ/Š:£%Œ.Û¼‘tÔÔ$.èöÉsO­–âxJ£¥¦TNúάkåIœü8æä_TSëñ²²2ÒIS³Œ¯Dü’Ö$m”ÙB[ŒŒÝÂ8,´h¦-fÉlOè ¾ ß<~&é¤)L+­vNoÒ‹f‹iÿñ›/Ë'ïÉq‰f³!O¯1†ÝÓFW“N:€Q$Ã[-r{~~2óGQ4æšpÀ£Óp¦só5½Ž“;È(h’ÛÚäNùŒ8äï(=tÒÜ”ìø‹½³;Ä&Ii³‰2)“‰¶˜$‹ÈÌpè´ÅF:g¯.½÷›ýŸ…#É“t¹45<űœ<“ÏxNîWª;舞˜¾p!餩-^¾j{^G0Óä.m5SfƒüE›”ÕšÐ=ÁØ·Ž[—¯"4…‡žZoÎ „¢gÍVÑ`Þ'½XÍ?·KZ)ZlzÁ F-ŽŸÌÄð½b‡ô“YÜóû¥Õ!óGñËgn” ´3–çk=½)—©\šr“šôÉö”¿ö{^Z~#餹)Y ÷o«©©«;ëi²\T'H&ƒd0Ä}ˆç[}][ÕßW“Ñ#-|â¶Úc5’”œrÊ¿~³g»/ØÅ°Éóúî÷ë}-zì_IgLgÑk{×írŸié Æù(­K°¦„dвú ¥iîò±Û}Ë«{HgìÕëÿ¹ï`MS[‡'f™¨ OŽÄ_e£z*Èøk_{1C—ÿÓŒâHü]Â-£øàÍeuß~ÓÐâ‹'$ù„W.M¹CY†–ožíè®Û¿óƒ7'1gýãRÎ7/kJÊË®|–g[Ýͧëëø|wþécÒ!ûeû[ŸÎ©šg6éh.Y£ò™{k»÷Ï>X°ôßHGë—·Ÿº¾t5²l¬³ €–èÖ¶æ†GêöIKžÍÜË0Î{æ¹ïç¯5:?ÏÅ1ÜÙÖ¶Ã õ ÃË—­%m¸Œâ¶{ÿÛh/¬]te¾Y>;Õì;p¼Åßvæk&-Ew­óÇ”Ú/]•Ï ºº#]ÈIwGçÙ#ò¿¤Ã¦pñ»1½q÷íao›<•3Ø]wüþmÒñæÓ×ã°:L‚){ƒÞ³­g¿·t)éPðá/ðïˆÇÜò\ZÐi4S=üéPýõî¯ÖèÛˆ6Ñ m óu“–<øcÒ¡†×(žøùÚ†“Ç‚]­ò¶ÞZX<⊖Í'ª¹V ÐO éÙ    @!(€B(P…P  ¡@B(„P   @!(€B(P…P  ¡@B(„P   @!(€B(P…P  ¡@B(„P   @!(€B(P…P  ¡@B(„P   @!(€B(P…P  ¡@B(„P   @!(€B(P…P  ¡@B(ÄõügåCqçH’Ô³'‘Hç׬!°_fùþ±cqŠâ)JÎOŸÛw‚¢>o’¤£õ¡æ“Oä»V«í¹É0Ìù¿YKKËw–,!1§ï»/}þ_¼÷éŒé|ùÞ{N§óüMš¦å#¿g;Çb±é ’ΘÎcK–¤Ï¿ò·¿%1š&A•d®{ç+Vh4š ¿Ñó0¨Ýºutu5é}¸qö›KW/7ÖB'ëSÎMw47þðž#Æßsãìß}öÕ½¤¦FKJJX–¥ÎýÌ{ ˆþÿ£Jþ7ŒtÀÏo0\.WÏvOr¹€zòÇãñ£G’˜ãù³]²@Aø_öî¸É:Áãxž$MÓ$}oé‹ ´ °ˆˆpˆ"Ú« ãªs¢Eo ‚2¸ãœzw»³ë9êŒëz3ݕ;9 ‚ŽÝóåD—qG@<Ôáäõx«myiKßÒ&iÒÜ¿y – ùÇúϾŸédž<©á—äÉïùÿŸ'©bOeDDoè»+Kr;ìyÛ®†.ÑžVÃî ýÇ ¿ôú7Îþ»?Ô´«NƒxòG%ö^ÆÙvÅuuuª^àù333GŒa9=bèKPss³ê€x~Ýõ[¿Ïçë:­3BŒÄ¥šçþöXó‹Kïø—ŸÝu¼©y玭ßlÿ¤lîFæðp–Su¸Ä.ˆ›qšx Ö¬Yc.‹[U¼Àó···;"Þzë-Ñ8©}ˆQE[[›ê€x~Ýõ¨x®EQO/CtÁœš%9O¶k_göè^>²ç«ê?.ã•κlj°ôîíµ!wŽKuºDËtttDÛgãÆ=öغuëÌ«â%PP&ÿúõëuÉ/šQÅs.’‹üÑÇb>.ÕÏ7¿xÎu̯»Þ)¼Çãq¹\}§ðbÁœˆ šê„±åd{ òóR‹ó§Ì}æóÕO;3r¯ûYUv~nWwωÖd?çt:ÅH_<á{÷î­ªª—æ3/v`–È©<ÕãË¿oß>s½.ùÍ¡ƒ%2nll\¶lÙ† *++KKKÅãNuÀóÍ/ˆ ûòåËõʯ»ÞãQ ÑóÑS–H·ªN[a^faËé°ä=¸äðÖ7G]û×c¯,öÞnKÃñ,ÕébO¾x¶kjjV¬XÑwý‰'Äekk«ê€ç›åÊ•:æ ͨ~¿ß\óõ×_/]ºtñâÅcÇŽíwf5 EóG‰}ØSO=5þ|-òë®·@½^¯Ûí8[j·ÛU'ŒÍeµ¤;-a«gÉVyr‹œžÞ“ñ‹{W²O!SRRÄV>mÚ´üüüU«V:tÈ\o~0(ùßýò744è•_$4£ŠÝ€¹¦¤¤dîܹæN<:ÕÏ7TQQ‘Fùu×Ûbò …Äh¿ß‰<Ñžâ¦["çø’YîÉM†mư¡%bPRôê ’2:;UGHH›Ëe.¬øÕGM-ÁüÂì‡ÿqŠêPqxëµûwÖ=ùÒ­ªƒHÚ³³Iuy¢PoüIžê 95í)ªsüøñV«Õ§:S\DlÑûï¿öš¦êóéõ|)П/¨qeg\Ëe©éÕâS\šÛ ?Yùί«nWEFK Guy†öÐH~º~ý°aÃFÝ¡:R|B¡Ëåš0a‚Øܵh‘ê8q ‡µßˆ^üÅ;'î1“†¶Ø­öf§9¶¤gŽ.z¤òíWªîR'n':4{ÞAÿ¿÷$RKKË%—\b‰”‘Ž*2çääðúëªã\tÞúýÿ¥>à™t¦ø ïÛ;"²ìVç%µ®ÌÇ—è·ý-v­T?‰²¿SU•žžn·Ÿz$]]]©ª3ÅÅëõеÙl¢C;¦:NÜÄ®:BB¾>Ò|"mÈp§Ã°YƒaãD»Mu¢ø„ [%d±Ùº³3w9þ_¿ã§ îU*ǽ†eÀÉ™øˆa`‚÷ ý/ë6\È~äÈ‘iÓ¦uvv:Q£Á`P¯ DˆA¨ÕjMMÕ+{¯îînÕRïõ»²2ÚºzêZCn§- Û˜â@›½³£»Ëo9ij7tÅÖm¯éU ÞÍ:÷eÕÿ,¼½­­-###--MthÏèPTf`QCb’’¢:NÜtÌÜWZªedaf~–Û‘šb8RÜvÍŽÛ™j·„mvkÊKkÍÌt©Ng~—Suyо?$ûõ×_¿{÷î3fØ#Ä8N¯‚Ëå2Ï}‰¹|CCƒê8qóx<ª#$äêÂîÿñÖ¦^r­+Ýéq¥ÚtûfFN®ÇëM wZ»š ?)+Ÿ¦:Q|òò4ñô¥ÿ9$Q ³g¿¹|ùÉ“'Gއm6›^ŸK4 Ôï÷oÛ¶­  @uœ¸é>ÿØÂÏÿ®½µØš{…-ÅâÔm<”šfé ØB¡€ýè¶É¥YgÍR(>Î4Õ .n½»¯’’’/¿ü277·¸¸Ø0 ½ Ôívwuumß¾½¥¥åÞ¥KUlj›S»Ê9S»ÅòÄ?=üÜÓ/·9»s&\•ªÛ9§Ûj9ÙµS©ãè=‹Q'nb í9$K(¤æßýú&Ò¦êêÚÚÚòòòqãÆ5i5&rµµmذ¡¾¾^Çö UHÐÑÓ ¯<ÿb(DÞØñs®+U*5ß;üÁŸŠÓ³-TEÆ_Ú~3^‰ßƒ¤P(\‘£ÛAŸ3}÷Uέ55HOOï÷íæ$·ê7¿ÉÈȸc¡–[¿ÐüÍ7‰üç½ße>óHÒÀ5ƒwÏbMöWD¯þùuµÇç.Yü#zã½÷¨~:ãV>uʰI“T§÷WÇ™ æ+ýƒ}_²ï_ ûÞ¡¹~à+~Ö•V›-æ¿Õ÷oˆôûM«Uïá§¥ï~dEš”Iû=¨B€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PdßòöÛÝÝÝ999]]]bÁ0 §Óép8RRRÄ¥Õjíèè¸â¦›Tç<§_TVÆÌÿÄK/©ŽyNW¯v»Ý©©©"|(êééimmuDˆõbÇãIæçÿñûï™?™Ÿÿ"ÃP³ Ç1b„èš@ ꦳³S,‹7€xWˆ>Ú³gê1€Öù‡ RPPPZZjDƒÁ'Nˆäb`¶ÒŽ;Tg¼ó‰°Ûl6k„¸¥¥¥effÖÕÕEߢŒT'ŒA÷üôe7̈«_|ñÅ´iÓÌVõ¤:a ºçª®®^·n]8öûýføY³fÍ›7Ou®8ò¯_¿¾ïšòòròz+Æœ|™×÷îÝ»bÅ q)ÞÉæÛXuÂæ_¹r¥FùU\Þyç¹¹¹Ñ•§¢¢Bu´øòçääDWŠá¿.ùiýû¥ªªJ\®Zµ* ™¤:a|´Ëm—Ë5gΜèžà¾ûîª:]Üù£ëuÉ$âŒ~ùøãÅØM,:thóæÍæÈB#"ÿ¾}ûÄBCCƒ.ù{"Ìå²²²ÒÒR±PRR2}útC‡Äýò_~ùåb¡¨¨H—ü@"z Ô,šÎÎÎêêêhé¬Y³¦££Cu¼óÒ7t¥FùûMee¥¸œ;w®yhBu´‹"? Í=PXSSÓÔÔ½A´ÏÚµkUÇ;ß`æonnŽ®÷ûýZä7E÷[bºxñbóSAÑ‘]òë›þüùÚåäØÃbiΜ9÷ßÿÀÏñ©NƒîùMÑÁšx,×\s¸ì9Mu´‹"? Çn9}À¬!»ÝžŸŸ/:ȼ9ùOÂèž_Œ”C¡¸ìû-³zÄ#Jþ€îùDØ?îõzÅäÝçó ü6žÓéLòs©ºçCæýû÷×ÕÕ üª nUðÏ$ÂhÐáT50Hø.<‘ì3\HZ(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@ ’(PD€$ $Q  ‰I(H¢@@’Ñ÷½þéúõŸ~úiFFÆ¥—^z{e¥êx±íݼyÛ¶m .t¹\^¯·3" :·Ûm‹Ø½{÷Áƒoš3GuسX¿lÙÍ7ß|å•W†B!ŸÏ×ÝÝÝÑÑ!.SRRÒÒÒÄ/†át:W¯^ü/ÇÊ—ÿmÇÑ”.¿¥Ø:þÒœ¿Yp›êD±Õnßþág[sËf;\>¯Åßeinêðúü#3‚¶pÈa³äØú½M =úL™ê°g±ýÝw·®½zîþvC„÷uYƒÞNŸÛâÛ-Á|5Ëa}æñþsC…ê°gQdª#$Ä]úâÝw:$j¨¢¢¢­­­¥¥åªª¬¬¬ëgÏVòû”NŸ.úqÆ ·ÞzkO„hÏ@ zS,‹_hooßµk×̇Rô÷âó¿«µŽò;x´õ›Û¾¬kû¿Ãï<ñìíªsÅ0lÒ¤‰›?ø“kòl›‘ÝÓòû|¾NGØj w{ÚµÞUÿäK·ªNzN‘2úQïõ𙿃Þ©)ü¦êêcÇŽM:uÆŒ';;{ìØ±“&Mƒ ·_}UuÈîX¸°¾¾~Ë–-~¿_”¦¾‰KQ âj]]ݦM›hÏÁöÜÓ/·Ý_zm~–{h®kҸ⒟Œ<Øêüù‚ÕÑb›pÛmÅiáúÏ756·¶v¼¾@—?p¼­ûèIÿÞÝM_l9œÌí µz tkMMmmmYYÙÈ‘#ív»˜<ŠgnnnAAÁĉÇŒ“üzïÒ¥b˜)Æ¡b‡Å¥¨Î¯¾újëÖ­´ç`{åùí£g¼"'Ý™éJ¹¬Ð}õ¥ž«FeM½a¸+;ců>R0¶Ù‹ë9Ú¼scñæ¶ÎP[WðÃoZ>ÙòmÝžÚ_W%õ ZlíÍgÁZë-Д——‹C¨Õj5/Q¦ãÇ/,,T36Ñ¡bÔùÞ{ïíܹsÿþý¢OO¶¶Þµh‘ê\¸?¿±.”?¢dÂUéi†Ç•êHMq;)v«ËiKÏLv㈦– êŒçå¡Ç™˜ÙØýÕê#õG÷6øŒ#û.ïùö•ª»TçBR³ïxÿýôôôqãÆ†! ÈlÏ`0èóùÌ“b„~øúëå>¨:m e< :ÂE§öxcÞÄ2—ÃâwZ|!‹˜Àx='}Á¢ôݰ¤¦Ùó ³ß\þÙÝNU4¶{/õÞ{o|[Ìä§\7õ§ ’}ƒ·˜Ç>Ï<Œ“ýê™3¯¶XšÌkâÇuú¶žÈ?ˆ}ù˜1ª£"Í]²øÌ鑟ïL^¬:c&Κ%~T§øá…)ÙÁÁç@ ŸÁqÒÁAch© ’(P@sLÏÕ¡@@ªG÷‘>Ƥª'ð#`3$(pác¢3H(P@c -Õ¢@@ hŽé¹:¨bœB¢˜Ä«C*Æ1,$Â8ó/ÏŸ Ù ¡@‹ûéÁAªÇ,ƒmlP ê1‹‡´P0ÙzlDg^g $( ·sÿ_9ûý~x¨bÌ­}Q ÿßÞå& Q³ÿ%‡ÔÙAdkò4ôœŸ ÔÏéM†X%ÌþÎ.×àX$ y¶x–ùwvYšg‹§š+" ÐØÍ2ÚrŠh˜É†¾4Ìn} (4g‰ÉP€E 9Æ”% ðû|Ô^D@¡1ǘ²`‘€,PhÎzž# ÐœçC9 ùVÎ, óx”ãó¹õ{Ž1ÕÐ0ôx€ët…Æ\€³`‘€BsÖó…ælñ9æÓ}vÜœ‰-" aðcVC@á÷YtŠhžáf™ &K@óü @S ÍÙ`r4ÌþÎ߉”% aöw`ÈŠ(ü®Ó54ÏO53VD@ólñ,3fל>M©· œ®qº‡v¿gåi;÷Ö#â±øûï¢pÆd æÒÊ”#¾ÅµdXk6Üý;åâ‹rÆ3eÁwñu¯|ßœ÷xúæ»h÷xþêŠå^ ß|t¿öÝñгEô©ùËÄæØâóçÉw{Ϻ÷ºvgEà) ÷¦>¶rž°°Ã•ù¼&¸ÿŒg=WÃU±Å§O Ùq@¼½©Ð$£MëÜ ˜XÒJŠ{J#å3V³¦–Æ¥øE;iny “òjÃéa ½íèT¡yV&‚0Â?®ðj𿹂ööÐ%Šõá+Ø•<a†#çßX@hß>åãßs…§¸‰OÀf ÈÇÍ´Ø/é3¶òÁ9cÇâî¤óA7ÃÊ@ e&¡¨))üXÁrûˆ9M Øä,§&×w”ÎÚÄéµFŠ( iÙV)ŒøÑRCÆ™K`faåÊM²aQqŽ2ÍZ”UTµjS«¹–ÊUªÖZ[µ–Z…q“¦¡ÕÖš”DÞ6¬0ë©ç^:wéÚkoÝÂg”ÁC†Ž:Ú°™fžHÿ)Sì³M[´J«,^²tÕÕ–mÄÚλlÞ²u×ݶ=P»QýŠ}Cîרњ#VÎ:ýD ê"Èé„3 – quÐÉ1‹•JIŽœc›Ó' FìàLrÄ€`Y”xÓ»Oä~‰[àò·pKï Ý?\pènä~âöµi§¢äg¡û4æ bÛØ–¥ºbå”j#FìSņÁ‘óÂd/¹¡`a•Å7wª²ÜÀµƒg*ÍòX*½ÂúÉ †Z4ÙÛ¢0¬ŠqîNlZîœðËv‹b]R§O—8:ïÝ·¤ê¿?Þ÷Òq$<ÞG’;"Ä ­ºgMÝ lny/ðߤ¾€—ît –6AÎ|)þÐzëDˆ^ZÑD¼3ú§Ò_éÔðCåë­Ú˜mµ mº0’Ø2hY;M¬[!´"Æ¡ƒÊ=. $E;Oñ¯ÞÃß}á· ÿA‰@4VWØ2S“æÅÃŒ¦¢ÿCVcDžЮ]MÚÚMw²é ~b*øåÜ8xkéŸ÷ÂÈý&hp¶t)u%ëºÅ&¾ñטÌˉž<`I(]¤£üŠ­1‘:t¸÷Éxæî,Åß°NØ kꩇOSï…çGÁ®{ÕŽ‚.F#Û21²Ó9ÎÈýdZˆ ÝQ pR@Ãâaµ{Äaðê-AÎ×X ªÝs÷ŒøëA“8 €¦×‘…Ò3â,ïš:Âo_Ц¿žó‰žáNzíNïmö©pæî÷‡ÏáŽYp}ÛÍ+‹Ïdø¾×k«i éWúšN_yèÛ>ÂçFl 8¿”‰À±eì<'˜hÁ´G'8ˆá˜´RÞŠSO)ïàìƒ^6À ‡¼ßÛoAÿ ‚z{6d÷ Tš´«ÃKÈbzTXtRaw profile type iptcxÚ=‰± €@ ûLÁIl=a’†î öá%°%묓kÞ)Û ]t,e÷•¥:öÆ€CaˆÞ—¹L¶9û¡Í1Ä뻪ò2æé{ XTiTXtXML:com.adobe.xmp .†ä­bKGDÿÿÿ ½§“ pHYs  šœtIMEâ.® •IDATxÚíÕQ €0 @ÁL-¶‰@Fµà\ ü†;m_¶Ú{ßç,ic”äRï¿^kxk³„€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ DícŸ3ï÷y¦>@D¤Þ¿! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€! „€! ~¢e "\ñCõZËð…! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€B@ „€! ~à|O;k ÐKIEND®B`‚simutrans-124.3/themes.src/flat/button.png000066400000000000000000000075301474050137200206020ustar00rootroot00000000000000‰PNG  IHDR@ÔH^gAMA± üa :iCCPPhotoshop ICC profileH‰–wTTׇϽwz¡Í0)Cï½ ½7©ÒDa˜`(34±!¢EDA‚"Œ†"±"Š…€`Á  Ä`QQy3²Vtåå½——ßg}kŸ½÷=gï}Öº¼ý¹¼tX €4ž€âåJŒŠ¦cû ðÌ`²23B=ÀH>nôL‘ø"€7wÄ+7¼ƒètðÿIš•ÁˆÒ‰Ø‚ÍÉd‰¸Pĩق ±}FÄÔø1Ã(1óE±¼˜Ùð³Ï";‹™Æc‹X|æ v[Ì="Þš%äˆñqQ—“-â["ÖL¦qEüV›Æaf€"‰í+IĦ"&ñÃBÜD¼)ñ+ŽÿŠœøRné¹|nb’€®ËÒ£›ÙÚ2èÞœìTŽ@`Äd¥0ùlº[zZ“— Àâ?KF\[º¨ÈÖf¶ÖÖFæÆf_ê¿nþM‰{»H¯‚?÷ ¢õ}±ý•_z=ŒYQmv|±Åï c3ò÷¿Ø4 )ê[ûÀW÷¡‰ç%I Ȱ31ÉÎÎ6ærXÆâ‚þ¡ÿéð7ôÕ÷ŒÅéþ(Ý“À¦ è⺱ÒSÓ…|zf“Å¡ýyˆÿqà_ŸÃ0„“Àásx¢ˆpÑ”qy‰¢vóØ\7GçòþSÿaØŸ´8×"Q>j¬1 ä×>€¢s@´ýÑ7|8¿¼ՉŹÿ,èß³Âeâ%“›ø9Î-$ŒÎò³÷ÄÏ H*P*@è#`l€=pÀ‚0VHi€²A>ØŠ@ ØvƒjP @h'@8 .€Ëà:¸nƒ`Œƒç`¼óa!2D UH 2€Ì!äy@þPÅA‰BùÐ&¨*‡ª¡:¨ ú:]€®BƒÐ=hš‚~‡ÞÃL‚©°2¬ ›À ØöƒÃà•p"¼΃ áíp\ƒÛá ðuø6<?‡g€¢†! Ä D¢‘„¬CŠ‘J¤iAº^ä&2‚L#ïPEG¡ìQÞ¨å(j5jªU:‚jGõ n¢FQ3¨Oh2Z m€¶Cû #щèltº݈nC_BßF£ß`0FcƒñÆDa’1k0¥˜ý˜VÌyÌ f 3‹Åb°Xl –‰`‹°{±Ç°ç°CØqì[§Š3Çyâ¢q<\®ww7„›ÀÍã¥ðZx;| žÏÅ—áð]øü8~ž MÐ!8ÂÉ„„*B áá!á‘HT'Úƒ‰\âbñ8ñ q”øŽ$CÒ'¹‘bHBÒvÒaÒyÒ=Ò+2™¬Mv&G“äíä&òEòcò[ Š„±„[b½DD»ÄÄ I¼¤–¤‹ä*É<ÉJÉ“’’ÓRx)m)7)¦Ô:©©SRÃR³Òi3é@é4éRé£ÒW¥'e°2Ú22l™B™C2eÆ(EƒâFaQ6Q(—(ãT U‡êCM¦–P¿£öSgded-eÃesdkdÏȎК6͇–J+£ Ý¡½—S–s‘ãÈm“k‘’›“_"ï,Ï‘/–o•¿-ÿ^®à¡¢°S¡Cá‘"JQ_1X1[ñ€â%Åé%Ô%öKXKŠ—œXr_ VÒW QZ£tH©OiVYEÙK9Cy¯òEåišŠ³J²J…ÊY•)UŠª£*WµBõœê3º,Ý…žJ¯¢÷ÐgÔ”Ô¼Õ„jujýjóê:êËÕ Ô[Õi4 Ý3šªššùšÍš÷µðZ ­$­=Z½ZsÚ:ÚÚ[´;´'uäu|tòtšuê’utWëÖëÞÒÃè1ôRôöëÝЇõ­ô“ôkô `k®Á~ƒAC´¡­!ϰÞp؈däb”eÔl4jL3ö7.0î0~a¢im²Ó¤×ä“©•iªiƒé33_³³.³ßÍõÍYæ5æ·,Èžë-:-^ZXr,XÞµ¢XXm±ê¶úhmcÍ·n±ž²Ñ´‰³Ùg3Ì 2‚¥Œ+¶h[WÛõ¶§mßÙYÛ ìNØýfodŸbÔ~r©ÎRÎÒ†¥cêL‡:‡GºcœãAÇ'5'¦S½Óg g¶s£ó„‹žK²Ë1—®¦®|×6×97;·µnçÝw/÷b÷~åÕ=Õ==›=g¼¬¼Öx÷F{ûyïôöQöaù4ùÌøÚø®õíñ#ù…úUû=ñ×÷çûwÀ¾».ÓZÆ[Ö}w> Ò Zôc0&8(¸&øiˆYH~Ho(%46ôhè›0×°²°Ëu— —w‡K†Ç„7…ÏE¸G”GŒDšD®¼¥ÅêŒÆF‡G7FÏ®ðX±{ÅxŒULQÌ•:+sV^]¥¸*uÕ™XÉXfìÉ8t\DÜѸÌ@f=s6Þ'~_ü ˵‡õœíÌ®`Oq8圉‡„ò„ÉD‡Ä]‰SINI•IÓ\7n5÷e²wrmò\J`Êá”…ÔˆÔÖ4\Z\Ú)ž /…ד®’ž“>˜aQ”1²ÚnõîÕ3|?~c&”¹2³S@ýLõ u…›…£YŽY5Yo³Ã³OæHçðrúrõs·åNäyæ}»µ†µ¦;_-cþèZ—µuë uñëº×k¬/\?¾ÁkÑ„)*0-(/x½)bSW¡rá†Â±Í^››‹$ŠøEÃ[ì·ÔnEmåníßf±mï¶OÅìâk%¦%•%JY¥×¾1û¦ê›…í ÛûˬËìÀìàí¸³Óiç‘réò¼ò±]»Ú+èůwÇî¾ZiYY»‡°G¸g¤Ê¿ªs¯æÞ{?T'Uß®q­iݧ´oÛ¾¹ýìýCœ´Ô*×–Ô¾?È=x·Î«®½^»¾òæPÖ¡§ á ½ß2¾mjTl,iüx˜wxäHÈ‘ž&›¦¦£JGËšáfaóÔ±˜c7¾sÿ®³Å¨¥®•ÖZrö}Ü÷wNøè>É8ÙòƒÖûÚ(mÅíP{nûLGRÇHgTçà)ßSÝ]ö]m?ÿxø´Úéš3²gÊÎΞ]8—wnö|Æùé ‰ƺc»\Œ¼x«'¸§ÿ’ߥ+—=/_ìué=wÅáÊé«vWO]c\ë¸n}½½Ïª¯í'«ŸÚú­ûÛl:oØÞè\:xvÈièÂM÷›—oùܺ~{ÙíÁ;ËïÜŽ¹Ë¾;y/õÞËûY÷çlxˆ~XüHêQåc¥Çõ?ëýÜ:b=rfÔ}´ïIè“c¬±ç¿dþòa¼ð)ùiå„êDÓ¤ùäé)Ï©ÏV<žñ|~ºèWé_÷½Ð}ñÃoοõÍDÎŒ¿ä¿\ø½ô•«ï-_wÏÍ>~“öf~®ø­ÂÛ#ïïzßG¼Ÿ˜Ïþ€ýPõQïc×'¿OÒþ˜óü%wu cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYs  šœtIMEâ,„Î+ÜcIDATxÚíÚÁQ"A†af«'CQƒXËHÈ9Ìä@$±›'"à0Ø¢ÜÞ’ƒP¶ßìóœ(OMûÓ¯2Ým6›ÕßÖã¸Ê±†…­?Îy„}·ø»ãñôbš¦¬É©Öjš¦êÊš¢jÿã¦(}~ÊûèÏežžçZ%¯?ñZ´ðà ` `ð±b €†ªÇ¨Y— ÒŸ§¯¿ÛϳŸ¶·¿ÃúC%Î Wñ @À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   €Û)Ûa¨~´Ç 7°¼õçÊÚù÷?}ý¦Èùó¿ÍÿÀ000 ¾n?ÏvO[Ò->·¿^âž#`p_! ` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` `p;ÝýÃ}õ£—_¿ƒÞÀóãÃÂÖçéçÓéÅz㿆ӋÝë.krªõ‡Ú½îÎó“8EÕþÇMQúü”÷Pôéy èõ'@þ šð"[4T=Fͺđþ 8}ý%ñæÕ…q»—xsoIÚJ?¬¿­n?Ï>EÄñ @À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   €Û)¶€+ݧ‡¾·øVëuèûê-dý"¢¿€ù)é¿Ôü’p  _! ` `pK@KÑQÓŸ§¯¿ ëHÔíçÙ.Ç30   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@À@À@À000  nç ÔeÀïOÁrìIEND®B`‚simutrans-124.3/themes.src/flat/checkbutton-small.png000066400000000000000000000057351474050137200227130ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa :iCCPPhotoshop ICC profileH‰–wTTׇϽwz¡Í0)Cï½ ½7©ÒDa˜`(34±!¢EDA‚"Œ†"±"Š…€`Á  Ä`QQy3²Vtåå½——ßg}kŸ½÷=gï}Öº¼ý¹¼tX €4ž€âåJŒŠ¦cû ðÌ`²23B=ÀH>nôL‘ø"€7wÄ+7¼ƒètðÿIš•ÁˆÒ‰Ø‚ÍÉd‰¸Pĩق ±}FÄÔø1Ã(1óE±¼˜Ùð³Ï";‹™Æc‹X|æ v[Ì="Þš%äˆñqQ—“-â["ÖL¦qEüV›Æaf€"‰í+IĦ"&ñÃBÜD¼)ñ+ŽÿŠœøRné¹|nb’€®ËÒ£›ÙÚ2èÞœìTŽ@`Äd¥0ùlº[zZ“— Àâ?KF\[º¨ÈÖf¶ÖÖFæÆf_ê¿nþM‰{»H¯‚?÷ ¢õ}±ý•_z=ŒYQmv|±Åï c3ò÷¿Ø4 )ê[ûÀW÷¡‰ç%I Ȱ31ÉÎÎ6ærXÆâ‚þ¡ÿéð7ôÕ÷ŒÅéþ(Ý“À¦ è⺱ÒSÓ…|zf“Å¡ýyˆÿqà_ŸÃ0„“Àásx¢ˆpÑ”qy‰¢vóØ\7GçòþSÿaØŸ´8×"Q>j¬1 ä×>€¢s@´ýÑ7|8¿¼ՉŹÿ,èß³Âeâ%“›ø9Î-$ŒÎò³÷ÄÏ H*P*@è#`l€=pÀ‚0VHi€²A>ØŠ@ ØvƒjP @h'@8 .€Ëà:¸nƒ`Œƒç`¼óa!2D UH 2€Ì!äy@þPÅA‰BùÐ&¨*‡ª¡:¨ ú:]€®BƒÐ=hš‚~‡ÞÃL‚©°2¬ ›À ØöƒÃà•p"¼΃ áíp\ƒÛá ðuø6<?‡g€¢†! Ä D¢‘„¬CŠ‘J¤iAº^ä&2‚L#ïPEG¡ìQÞ¨å(j5jªU:‚jGõ n¢FQ3¨Oh2Z m€¶Cû #щèltº݈nC_BßF£ß`0FcƒñÆDa’1k0¥˜ý˜VÌyÌ f 3‹Åb°Xl –‰`‹°{±Ç°ç°CØqì[§Š3Çyâ¢q<\®ww7„›ÀÍã¥ðZx;| žÏÅ—áð]øü8~ž MÐ!8ÂÉ„„*B áá!á‘HT'Úƒ‰\âbñ8ñ q”øŽ$CÒ'¹‘bHBÒvÒaÒyÒ=Ò+2™¬Mv&G“äíä&òEòcò[ Š„±„[b½DD»ÄÄ I¼¤–¤‹ä*É<ÉJÉ“’’ÓRx)m)7)¦Ô:©©SRÃR³Òi3é@é4éRé£ÒW¥'e°2Ú22l™B™C2eÆ(EƒâFaQ6Q(—(ãT U‡êCM¦–P¿£öSgded-eÃesdkdÏȎК6͇–J+£ Ý¡½—S–s‘ãÈm“k‘’›“_"ï,Ï‘/–o•¿-ÿ^®à¡¢°S¡Cá‘"JQ_1X1[ñ€â%Åé%Ô%öKXKŠ—œXr_ VÒW QZ£tH©OiVYEÙK9Cy¯òEåišŠ³J²J…ÊY•)UŠª£*WµBõœê3º,Ý…žJ¯¢÷ÐgÔ”Ô¼Õ„jujýjóê:êËÕ Ô[Õi4 Ý3šªššùšÍš÷µðZ ­$­=Z½ZsÚ:ÚÚ[´;´'uäu|tòtšuê’utWëÖëÞÒÃè1ôRôöëÝЇõ­ô“ôkô `k®Á~ƒAC´¡­!ϰÞp؈däb”eÔl4jL3ö7.0î0~a¢im²Ó¤×ä“©•iªiƒé33_³³.³ßÍõÍYæ5æ·,Èžë-:-^ZXr,XÞµ¢XXm±ê¶úhmcÍ·n±ž²Ñ´‰³Ùg3Ì 2‚¥Œ+¶h[WÛõ¶§mßÙYÛ ìNØýfodŸbÔ~r©ÎRÎÒ†¥cêL‡:‡GºcœãAÇ'5'¦S½Óg g¶s£ó„‹žK²Ë1—®¦®|×6×97;·µnçÝw/÷b÷~åÕ=Õ==›=g¼¬¼Öx÷F{ûyïôöQöaù4ùÌøÚø®õíñ#ù…úUû=ñ×÷çûwÀ¾».ÓZÆ[Ö}w> Ò Zôc0&8(¸&øiˆYH~Ho(%46ôhè›0×°²°Ëu— —w‡K†Ç„7…ÏE¸G”GŒDšD®¼¥ÅêŒÆF‡G7FÏ®ðX±{ÅxŒULQÌ•:+sV^]¥¸*uÕ™XÉXfìÉ8t\DÜѸÌ@f=s6Þ'~_ü ˵‡õœíÌ®`Oq8圉‡„ò„ÉD‡Ä]‰SINI•IÓ\7n5÷e²wrmò\J`Êá”…ÔˆÔÖ4\Z\Ú)ž /…ד®’ž“>˜aQ”1²ÚnõîÕ3|?~c&”¹2³S@ýLõ u…›…£YŽY5Yo³Ã³OæHçðrúrõs·åNäyæ}»µ†µ¦;_-cþèZ—µuë uñëº×k¬/\?¾ÁkÑ„)*0-(/x½)bSW¡rá†Â±Í^››‹$ŠøEÃ[ì·ÔnEmåníßf±mï¶OÅìâk%¦%•%JY¥×¾1û¦ê›…í ÛûˬËìÀìàí¸³Óiç‘réò¼ò±]»Ú+èůwÇî¾ZiYY»‡°G¸g¤Ê¿ªs¯æÞ{?T'Uß®q­iݧ´oÛ¾¹ýìýCœ´Ô*×–Ô¾?È=x·Î«®½^»¾òæPÖ¡§ á ½ß2¾mjTl,iüx˜wxäHÈ‘ž&›¦¦£JGËšáfaóÔ±˜c7¾sÿ®³Å¨¥®•ÖZrö}Ü÷wNøè>É8ÙòƒÖûÚ(mÅíP{nûLGRÇHgTçà)ßSÝ]ö]m?ÿxø´Úéš3²gÊÎΞ]8—wnö|Æùé ‰ƺc»\Œ¼x«'¸§ÿ’ߥ+—=/_ìué=wÅáÊé«vWO]c\ë¸n}½½Ïª¯í'«ŸÚú­ûÛl:oØÞè\:xvÈièÂM÷›—oùܺ~{ÙíÁ;ËïÜŽ¹Ë¾;y/õÞËûY÷çlxˆ~XüHêQåc¥Çõ?ëýÜ:b=rfÔ}´ïIè“c¬±ç¿dþòa¼ð)ùiå„êDÓ¤ùäé)Ï©ÏV<žñ|~ºèWé_÷½Ð}ñÃoοõÍDÎŒ¿ä¿\ø½ô•«ï-_wÏÍ>~“öf~®ø­ÂÛ#ïïzßG¼Ÿ˜Ïþ€ýPõQïc×'¿OÒþ˜óü%wu cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYs  šœtIMEâ $íói èIDATxÚíØ± ‚@€á‡a$BbÇîìàt‡Ð={ãÙyú}å]óBþK¸«º®‹²ã0ĺú>õü‡ÝöÍîùz[ùüuD”Ç12È>³o^®Ï—yýÃ×ñÚ¶}Z™¦)ø¼O€€B@ð—·0w®o”彤$ûü)Þ{Jªû²8FøB@€B@ „€! B@! B@„€! „€@@! B@€B@ „€! ò{Ê£õøIEND®B`‚simutrans-124.3/themes.src/flat/divider.png000066400000000000000000000003051474050137200207060ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰bKGDÿÿÿ ½§“ pHYs  šœtIMEâ )ÖÆàmRIDAThÞíÏ 00¸oô"ƒëXÒ:hÏL%뽋¼ ' à=0ÛÊ‚WIEND®B`‚simutrans-124.3/themes.src/flat/editfield.png000066400000000000000000000010251474050137200212110ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPbKGDÿÿÿ ½§“ pHYs  šœtIMEâ" w“â¢IDATxÚíÝAà †ÑЉZ<°‡‚Ȩ DõC;;}Ï?ßcÚ£ge͈£¸Òû·{ïžz™! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€! „€QÆ9#zfݼ¯«ô¬µJïïB@! B@„€! „€@@ˆk÷ÞVÀ „€! „€@@! B@„€B@ „€! B@€B@„€ñ çŒè™u0#ªßAéýýlŸ0„€! B@€B@ „€! „€@@! B@„€B@ „€! B@€B@ „€! ÄŸø„4Ú·5ÜIEND®B`‚simutrans-124.3/themes.src/flat/flat-skin-large.tab000066400000000000000000000101731474050137200222260ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 1 (to not occupy so much screen space) icon_scaling = 150 gui_titlebar_height = 22 gui_gadget_width = 22 gui_tab_header_vsize = 26 gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 toolbar_max_width = 0 toolbar_max_height = 0 gui_button_height = 24 gui_button_width = 100 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat.pak simutrans-124.3/themes.src/flat/flat-skin-touch.dat000066400000000000000000000163471474050137200222710ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: Phystam # # All image names must start with "> " to have them non zoomable # # This theme has the scalable standard look # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab #!pak64 -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.0.0 Image[28]=> button.0.2 Image[29]=> button.0.1 Image[30]=> button.0.3 Image[31]=> button.0.5 Image[32]=> button.0.4 Image[33]=> button.0.6 Image[34]=> button.0.8 Image[35]=> button.0.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- # titlebar background Obj=menu name=Titlebar Image[0]=> titlebar.0.0 Image[1]=> titlebar.0.1 Image[2]=> titlebar.0.2 Image[3]=> titlebar.1.0 Image[4]=> titlebar.1.1 Image[5]=> titlebar.1.2 Image[6]=> titlebar.2.0 Image[7]=> titlebar.2.1 Image[8]=> titlebar.2.2 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[9]=> titlebar.3.0 Image[10]=> titlebar.3.1 Image[11]=> titlebar.3.2 Image[12]=> titlebar.4.0 Image[13]=> titlebar.4.1 Image[14]=> titlebar.4.2 Image[15]=> titlebar.5.0 Image[16]=> titlebar.5.1 Image[17]=> titlebar.5.2 -- # Gadgets background Obj=menu name=GadgetBack # all gadget-touch except close Image[0]=> titlebar.0.0 Image[1]=> titlebar.0.1 Image[2]=> titlebar.0.2 Image[3]=> titlebar.1.0 Image[4]=> titlebar.1.1 Image[5]=> titlebar.1.2 Image[6]=> titlebar.2.0 Image[7]=> titlebar.2.1 Image[8]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[9]=> titlebar.3.0 Image[10]=> titlebar.3.1 Image[11]=> titlebar.3.2 Image[12]=> titlebar.4.0 Image[13]=> titlebar.4.1 Image[14]=> titlebar.4.2 Image[15]=> titlebar.5.0 Image[16]=> titlebar.5.1 Image[17]=> titlebar.5.2 # close background when buttons at left Image[18]=> titlebar.0.0 Image[19]=> titlebar.0.1 Image[20]=> titlebar.0.3 Image[21]=> titlebar.1.0 Image[22]=> titlebar.1.1 Image[23]=> titlebar.1.2 Image[24]=> titlebar.2.0 Image[25]=> titlebar.2.1 Image[26]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> titlebar.3.0 Image[28]=> titlebar.3.1 Image[29]=> titlebar.3.3 Image[30]=> titlebar.4.0 Image[31]=> titlebar.4.1 Image[32]=> titlebar.4.2 Image[33]=> titlebar.5.0 Image[34]=> titlebar.5.1 Image[35]=> titlebar.5.2 # close background when buttons at right Image[36]=> titlebar.1.3 Image[37]=> titlebar.0.1 Image[38]=> titlebar.0.2 Image[39]=> titlebar.1.0 Image[40]=> titlebar.1.1 Image[41]=> titlebar.1.2 Image[42]=> titlebar.2.0 Image[43]=> titlebar.2.1 Image[44]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[45]=> titlebar.4.3 Image[46]=> titlebar.3.1 Image[47]=> titlebar.3.2 Image[48]=> titlebar.4.0 Image[49]=> titlebar.4.1 Image[50]=> titlebar.4.2 Image[51]=> titlebar.5.0 Image[52]=> titlebar.5.1 Image[53]=> titlebar.5.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton-small.0.0 # pressed Image[1]=> checkbutton-small.0.1 # disabled Image[2]=> checkbutton-small.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton-small.0.0 # pressed Image[1]=> posbutton-small.0.1 # disabled Image[2]=> posbutton-small.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar-touch.0.0 Image[1]=> scrollbar-touch.0.1 Image[2]=> scrollbar-touch.0.2 Image[3]=> scrollbar-touch.0.3 Image[4]=> scrollbar-touch.0.4 Image[5]=> scrollbar-touch.0.5 # scrollbar back left center right Image[6]=- Image[7]=> scrollbar-touch.1.6 Image[8]=- # scrollbar knob left center right Image[9]=> scrollbar-touch.1.0 Image[10]=> scrollbar-touch.1.2 Image[11]=> scrollbar-touch.1.1 # back up and down Image[12]=> scrollbar-touch.2.0 Image[13]=> scrollbar-touch.2.2 Image[14]=> scrollbar-touch.2.1 # knob up and down Image[15]=> scrollbar-touch.2.3 Image[16]=> scrollbar-touch.2.5 Image[17]=> scrollbar-touch.2.4 # scrollbar back up center down Image[18]=- Image[19]=> scrollbar-touch.3.6 Image[20]=- # scrollbar knob up center down Image[21]=> scrollbar-touch.3.0 Image[22]=> scrollbar-touch.3.2 Image[23]=> scrollbar-touch.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget-touch.0.0 # help Image[1]=> gadget-touch.0.1 # minimize Image[2]=> gadget-touch.0.2 # previous Image[3]=> gadget-touch.0.3 # next Image[4]=> gadget-touch.0.4 # unsticky Image[5]=> gadget-touch.0.5 # sticky Image[6]=> gadget-touch.0.6 # resize corner Image[7]=> gadget-touch.0.7 # goto pos Image[8]=> gadget-touch.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/themes.src/flat/flat-skin-touch.tab000066400000000000000000000101751474050137200222600ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat (touch) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears #toolbar_max_width = 0 toolbar_max_height = 1 (to not occupy so much screen space) icon_scaling = 200 gui_titlebar_height = 28 gui_gadget_width = 28 gui_tab_header_vsize = 26 gui_button_text_offset = 7,0,7 gui_color_button_text_offset = 7,0,7 toolbar_max_width = 0 toolbar_max_height = 0 gui_button_height = 28 gui_button_width = 100 gui_scrollbar_width = 28 gui_scrollbar_height = 28 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat-touch.pak simutrans-124.3/themes.src/flat/flat-skin.dat000066400000000000000000000162611474050137200211440ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: Phystam # # All image names must start with "> " to have them non zoomable # # This theme has the scalable standard look # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab #!pak64 -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.0.0 Image[28]=> button.0.2 Image[29]=> button.0.1 Image[30]=> button.0.3 Image[31]=> button.0.5 Image[32]=> button.0.4 Image[33]=> button.0.6 Image[34]=> button.0.8 Image[35]=> button.0.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- # titlebar background Obj=menu name=Titlebar Image[0]=> titlebar.0.0 Image[1]=> titlebar.0.1 Image[2]=> titlebar.0.2 Image[3]=> titlebar.1.0 Image[4]=> titlebar.1.1 Image[5]=> titlebar.1.2 Image[6]=> titlebar.2.0 Image[7]=> titlebar.2.1 Image[8]=> titlebar.2.2 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[9]=> titlebar.3.0 Image[10]=> titlebar.3.1 Image[11]=> titlebar.3.2 Image[12]=> titlebar.4.0 Image[13]=> titlebar.4.1 Image[14]=> titlebar.4.2 Image[15]=> titlebar.5.0 Image[16]=> titlebar.5.1 Image[17]=> titlebar.5.2 -- # Gadgets background Obj=menu name=GadgetBack # all gadget except close Image[0]=> titlebar.0.0 Image[1]=> titlebar.0.1 Image[2]=> titlebar.0.2 Image[3]=> titlebar.1.0 Image[4]=> titlebar.1.1 Image[5]=> titlebar.1.2 Image[6]=> titlebar.2.0 Image[7]=> titlebar.2.1 Image[8]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[9]=> titlebar.3.0 Image[10]=> titlebar.3.1 Image[11]=> titlebar.3.2 Image[12]=> titlebar.4.0 Image[13]=> titlebar.4.1 Image[14]=> titlebar.4.2 Image[15]=> titlebar.5.0 Image[16]=> titlebar.5.1 Image[17]=> titlebar.5.2 # close background when buttons at left Image[18]=> titlebar.0.0 Image[19]=> titlebar.0.1 Image[20]=> titlebar.0.3 Image[21]=> titlebar.1.0 Image[22]=> titlebar.1.1 Image[23]=> titlebar.1.2 Image[24]=> titlebar.2.0 Image[25]=> titlebar.2.1 Image[26]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> titlebar.3.0 Image[28]=> titlebar.3.1 Image[29]=> titlebar.3.3 Image[30]=> titlebar.4.0 Image[31]=> titlebar.4.1 Image[32]=> titlebar.4.2 Image[33]=> titlebar.5.0 Image[34]=> titlebar.5.1 Image[35]=> titlebar.5.2 # close background when buttons at right Image[36]=> titlebar.1.3 Image[37]=> titlebar.0.1 Image[38]=> titlebar.0.2 Image[39]=> titlebar.1.0 Image[40]=> titlebar.1.1 Image[41]=> titlebar.1.2 Image[42]=> titlebar.2.0 Image[43]=> titlebar.2.1 Image[44]=> titlebar.2.2 # color mask for above (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[45]=> titlebar.4.3 Image[46]=> titlebar.3.1 Image[47]=> titlebar.3.2 Image[48]=> titlebar.4.0 Image[49]=> titlebar.4.1 Image[50]=> titlebar.4.2 Image[51]=> titlebar.5.0 Image[52]=> titlebar.5.1 Image[53]=> titlebar.5.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton-small.0.0 # pressed Image[1]=> checkbutton-small.0.1 # disabled Image[2]=> checkbutton-small.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton-small.0.0 # pressed Image[1]=> posbutton-small.0.1 # disabled Image[2]=> posbutton-small.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar-small.0.0 Image[1]=> scrollbar-small.0.1 Image[2]=> scrollbar-small.0.2 Image[3]=> scrollbar-small.0.3 Image[4]=> scrollbar-small.0.4 Image[5]=> scrollbar-small.0.5 # scrollbar back left center right Image[6]=- Image[7]=> scrollbar-small.1.6 Image[8]=- # scrollbar knob left center right Image[9]=> scrollbar-small.1.0 Image[10]=> scrollbar-small.1.2 Image[11]=> scrollbar-small.1.1 # back up and down Image[12]=> scrollbar-small.2.0 Image[13]=> scrollbar-small.2.2 Image[14]=> scrollbar-small.2.1 # knob up and down Image[15]=> scrollbar-small.2.3 Image[16]=> scrollbar-small.2.5 Image[17]=> scrollbar-small.2.4 # scrollbar back up center down Image[18]=- Image[19]=> scrollbar-small.3.6 Image[20]=- # scrollbar knob up center down Image[21]=> scrollbar-small.3.0 Image[22]=> scrollbar-small.3.2 Image[23]=> scrollbar-small.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7,-2,-2 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/themes.src/flat/flat-skin.tab000066400000000000000000000077471474050137200211530ustar00rootroot00000000000000# Flat Skin theme # Created by Phystam # # name of the theme (will be shown with file selector) name=Flat # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 250 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 10000 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 #cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Use the default height #gui_button_height = 22 # larger icons too icon_width = 32 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) # Should be rather a user setting, if the theme does not absolutely require it #window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) # Should be rather a user setting, if the theme does not absolutely require it #second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #7b7b7b # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #CFCFCF #################################colour stuff################################# gui_color_text = #101010 gui_color_text_highlight = #fafafa gui_color_text_shadow = #202020 gui_color_text_title = #fafafa gui_color_text_strong = #ef4026 gui_color_obsolete = #00004a gui_color_empty = #FFFFFF gui_color_edit_text = #fafafa gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #333333 gui_color_edit_background_selected = #333333 gui_color_edit_beam = #333333 gui_color_chart_background = #a3a3a3 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #333333 gui_color_chart_lines_even = #646464 gui_color_button_text = #101010 gui_color_button_text_disabled = #333333 gui_color_button_text_selected = #FAFAFA gui_color_loadingbar_progress = #4d4d4d gui_color_loadingbar_inner = #cfcfcf ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears icon_scaling = 100 # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ##################################pakstuff################################## # pak with the images for this theme themeimages=flat.pak simutrans-124.3/themes.src/flat/gadget-touch.png000066400000000000000000000025221474050137200216360ustar00rootroot00000000000000‰PNG  IHDR@@}g_HIDATxÚíÝMNÜ0Æñ ꦩ»ÂÍàU7{TÔK 7ƒî¸@—4ª©1þOæÃïãùÿ„F0™ÅëÄñ'™°z~}òeµÊ¾ÿõ.`oJÑ.¥g bî$#õp¨·«ý“‡®³ÝH[ ‹ `~¸¹¹É~`½^OÃP*$V»ëB¥b<~?ͯO½ “ °údÅàTfcz¹EdXÁàŠtÄx©Ûr;Ei·õ Ÿþäõ­³Eß:OŠý+2g¥Š³¥×—vQJ¯õ?á;í{ö%íô™,W¤D©ÉÜÙæŸ«Ë+ÿÓ»"%f`ÑáXt(Z_ÚWš^þ—p‘åC샦ÁV¤-òÁ ràl¹“ìÒ¨)×Ç®¯¯{—öÖÃÞRâºÐHÛÅ °“”6Gß‹¦¡÷‹:P´×—šâʹ¶¹Â(ÃljÙ{ÓfÚ\ÿ‹[d‡åîapÝkwo–nünìÿÌ.5µ“‡éÕ»–VËÆz›ë—™byõVÔçñn¾µ2y‚´>cîuéÊ/5 ?Ó÷®ˆ w!ú3?f#?ÍŠÞì]×’&l;³ÙÒÒËÍ0ØW?Π¿µ{ °ÊZ¿1ݺvŇº_JjÎ6¡=ÃÌ6d˜ôr$2, KwÖç^½›‚>ê7£¦Chø™úm®‡ö>Ûj µ6€Öï¶YsÚ„Æõo¶!ƒ¥—#‘aPÁu¯ýúp ±q 5;€zréå´¬³ 2½ã–Þ*\ºtñ|ÒÍÆÜ;î÷———Ž­¨÷Ÿ¾‡ùKç^õ‹‘õOÅ×À6Ž¡fPO4½œúú7ÛÓk2¼Ú!¤ý{2ô´vƒÌ~†ƒ]Çü¤yÖW 7<å˜Ǹïèéü²L_—i§¬Ðó8òAO7E-µÊ-z|"é «F zC¾_û7݈ƽVx[µË¯Iq1¼LØËÐ VÊøYöðÓÔô4Aã7ÿËñ5ô,ƒ@&Ñóen=@ZyìUÏùÚúAÇõÞv«ûc¨Ç¬ö•åè ŠÏ¡C |>UŸ„ìö‚æ›j)àÕ–G®E×oÇ'ÁآŒZ‚Fû Û@Øÿ¬•;Õ£ lû`|­8êFàöíÛ³_>ìùxnPÇã–Açɽ»+ahôyÐë xÙ§÷åøÎërï3„¡ò]d…Å((Í{hOlZYwÂJ%P üN~Ií$heÏ~­l½È´È¥×弟×;àè@ëýh=!1ôèQªðÓʽaëã¢:°üŸÙêÝsǸãúïòì𭯽ºóvôÉh}<»2ZþßÛ€vëø‡••eùJYÿ¬×»À±qHÖðýzÊ´Fã¾<«zîý¡hà÷[¯Çl4hêm| Fƒ¼[lû KIçg)^vjckÜ©½ Q~^>+Ëw¿ÕÞŸ^Úƒ€b@sŒéÙZ ?ñ&Ôã²<Œ‡ Šì¾2Ìn4*Mø•]ª²„Ÿuù,ߎšzÛŽÓøZ ØÞzëµø7¿kÔë>¨eÛµý€v긟AY¯Ã_.ë.õ´NŒæïÏþþñ£°ó¯Àƒn_ƒoJ™w×ÿá·?¦Þ® öÃÔ›0eÙÓ‡ ¬á'lïÒގʤ>ìVæ:nÍNmëÛ P1k¿ çA|ŽðóÃÔú*2E/ÐdzÃ×ß?*óËw¶/c`dì²®ëîÐÙÚ@àµÇ?¹j?R¼õ¦Ü¼ˆó ö{@++ëOatw3ÔÅHîW-ëø€1(­£þWˆn@/uü d éøßà€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒ€€t HGÒù ôb¢ºÒt îIEND®B`‚simutrans-124.3/themes.src/flat/listbox.png000066400000000000000000000141561474050137200207550ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPzTXtRaw profile type exifxÚíW[®ä( ýg³l06Ë Òì`–?’ªû¾R·ú§¥[©„ˆm|ìƒæÿ®ð~,CµRK‰øåš+7ÜX¼~WK1Ÿëù{ÏoúÃs€Ñ•Цë±Ì{~C¿¼¼ ùîïoûƒÞ’ØnA÷ÀC`ÚšùÅ»%¾úé~õ~¯åW˹ϤGÄsòûç¬p† :ž‰Rĵl-é:N;WÁ$:=ùî±Ï}ž·ïœ÷¼{ç»ØîþôÖ!–{By磻Ÿäsß½¶ˆ^4¿èú ‚¾[Ëm­y­®åO•p/ê±”s‡‰®L終Cq îõ‡a‰Nw ÙqŒ@•Þ\”ɩѢyÚA&fž¬h™§ÓgI¹òH‚¼Z¬©&À‚Ój Ýü´…ŽÞzô 2hvÂL&#¼ñáŸuþÎñ´Ö]¢hO_Á.Þ36rûŠY„ÖíS9þ=Gx7ñ° Êq³a-öKDz‰­tpN˜'1‡x…;©ßà"èC ÄBI¨PTf%‚ ø4XÎ)s$ÂNa›” À1ÞºñŽÒ™ËÂW7¨@H*IMM `å,ˆ͆j’$)¢bR¥•Tr‘RŠ–ÍQM“f-ªjZµY²lbÅÔ̪µÊ5¤–ª¡Z­µ5(mÝðvÃŒÖ:÷Ôs—^ºvëµ·ðyÈ(C‡:š³'Gú{q n^½M𥙧Ì2uÚ¬³-ÄÚJ+/Yeé²UW{¢v£ú5z‡Ü÷¨ÑÚF,Ÿyú‚ºU"hÓ‰lÌ€gâº@@óÆ,å̹Y¬Œ¤j$§Ì“X=±{Aî[Ü‚ä_¿B.lèþraCw#÷·OPóvv”tÚY¸}Ó±-,«±ÍhÂl•±O†ƒ=¢¤‰ÁžSņ…Y-~ÑB•¹ œ« ppO¹¶4¦–n°ÞÄ`YS.kµXVÅè«“4Í×~YÛ¢h³˜ïáG—µú*lûùñþÞ:Ž„çûHòÈqB«.à#×5Áæ-­ þsêkøÒ·CJu³\ŠZoÑK«…/þ¨ô;>¨ü|©­tq 0;Õ>!(¥šÈ|Hu€FN½Çí{®fߣó j¿÷â ¿SçÙR÷ž­Í€ÂcUåf*HQp'ˆ¨§4Ò NF2ל2g]£õ OÀbKGDùC» pHYs  šœtIMEä0–ðœ1¨IDATxÚíÝA !@Ñ¥Y•Ѥªð‡¦šT2X=´™ô=ËÌ·´ÖjÄ‘ÖèýÈ/ï ÊÚû€OÝŒ! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€! „€‘Æ9z¯y°×J½€9gêù»B@„€! „€@@! âÇÊÚÛp! „€@@! B@„€! „€! B@€B@ „€! „€@@|ù^ïûó‘÷£÷ì;¨y?ÞÏVð„! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€! „€! þĉhÎõUIEND®B`‚simutrans-124.3/themes.src/flat/posbutton-small.png000066400000000000000000000061261474050137200224320ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa :iCCPPhotoshop ICC profileH‰–wTTׇϽwz¡Í0)Cï½ ½7©ÒDa˜`(34±!¢EDA‚"Œ†"±"Š…€`Á  Ä`QQy3²Vtåå½——ßg}kŸ½÷=gï}Öº¼ý¹¼tX €4ž€âåJŒŠ¦cû ðÌ`²23B=ÀH>nôL‘ø"€7wÄ+7¼ƒètðÿIš•ÁˆÒ‰Ø‚ÍÉd‰¸Pĩق ±}FÄÔø1Ã(1óE±¼˜Ùð³Ï";‹™Æc‹X|æ v[Ì="Þš%äˆñqQ—“-â["ÖL¦qEüV›Æaf€"‰í+IĦ"&ñÃBÜD¼)ñ+ŽÿŠœøRné¹|nb’€®ËÒ£›ÙÚ2èÞœìTŽ@`Äd¥0ùlº[zZ“— Àâ?KF\[º¨ÈÖf¶ÖÖFæÆf_ê¿nþM‰{»H¯‚?÷ ¢õ}±ý•_z=ŒYQmv|±Åï c3ò÷¿Ø4 )ê[ûÀW÷¡‰ç%I Ȱ31ÉÎÎ6ærXÆâ‚þ¡ÿéð7ôÕ÷ŒÅéþ(Ý“À¦ è⺱ÒSÓ…|zf“Å¡ýyˆÿqà_ŸÃ0„“Àásx¢ˆpÑ”qy‰¢vóØ\7GçòþSÿaØŸ´8×"Q>j¬1 ä×>€¢s@´ýÑ7|8¿¼ՉŹÿ,èß³Âeâ%“›ø9Î-$ŒÎò³÷ÄÏ H*P*@è#`l€=pÀ‚0VHi€²A>ØŠ@ ØvƒjP @h'@8 .€Ëà:¸nƒ`Œƒç`¼óa!2D UH 2€Ì!äy@þPÅA‰BùÐ&¨*‡ª¡:¨ ú:]€®BƒÐ=hš‚~‡ÞÃL‚©°2¬ ›À ØöƒÃà•p"¼΃ áíp\ƒÛá ðuø6<?‡g€¢†! Ä D¢‘„¬CŠ‘J¤iAº^ä&2‚L#ïPEG¡ìQÞ¨å(j5jªU:‚jGõ n¢FQ3¨Oh2Z m€¶Cû #щèltº݈nC_BßF£ß`0FcƒñÆDa’1k0¥˜ý˜VÌyÌ f 3‹Åb°Xl –‰`‹°{±Ç°ç°CØqì[§Š3Çyâ¢q<\®ww7„›ÀÍã¥ðZx;| žÏÅ—áð]øü8~ž MÐ!8ÂÉ„„*B áá!á‘HT'Úƒ‰\âbñ8ñ q”øŽ$CÒ'¹‘bHBÒvÒaÒyÒ=Ò+2™¬Mv&G“äíä&òEòcò[ Š„±„[b½DD»ÄÄ I¼¤–¤‹ä*É<ÉJÉ“’’ÓRx)m)7)¦Ô:©©SRÃR³Òi3é@é4éRé£ÒW¥'e°2Ú22l™B™C2eÆ(EƒâFaQ6Q(—(ãT U‡êCM¦–P¿£öSgded-eÃesdkdÏȎК6͇–J+£ Ý¡½—S–s‘ãÈm“k‘’›“_"ï,Ï‘/–o•¿-ÿ^®à¡¢°S¡Cá‘"JQ_1X1[ñ€â%Åé%Ô%öKXKŠ—œXr_ VÒW QZ£tH©OiVYEÙK9Cy¯òEåišŠ³J²J…ÊY•)UŠª£*WµBõœê3º,Ý…žJ¯¢÷ÐgÔ”Ô¼Õ„jujýjóê:êËÕ Ô[Õi4 Ý3šªššùšÍš÷µðZ ­$­=Z½ZsÚ:ÚÚ[´;´'uäu|tòtšuê’utWëÖëÞÒÃè1ôRôöëÝЇõ­ô“ôkô `k®Á~ƒAC´¡­!ϰÞp؈däb”eÔl4jL3ö7.0î0~a¢im²Ó¤×ä“©•iªiƒé33_³³.³ßÍõÍYæ5æ·,Èžë-:-^ZXr,XÞµ¢XXm±ê¶úhmcÍ·n±ž²Ñ´‰³Ùg3Ì 2‚¥Œ+¶h[WÛõ¶§mßÙYÛ ìNØýfodŸbÔ~r©ÎRÎÒ†¥cêL‡:‡GºcœãAÇ'5'¦S½Óg g¶s£ó„‹žK²Ë1—®¦®|×6×97;·µnçÝw/÷b÷~åÕ=Õ==›=g¼¬¼Öx÷F{ûyïôöQöaù4ùÌøÚø®õíñ#ù…úUû=ñ×÷çûwÀ¾».ÓZÆ[Ö}w> Ò Zôc0&8(¸&øiˆYH~Ho(%46ôhè›0×°²°Ëu— —w‡K†Ç„7…ÏE¸G”GŒDšD®¼¥ÅêŒÆF‡G7FÏ®ðX±{ÅxŒULQÌ•:+sV^]¥¸*uÕ™XÉXfìÉ8t\DÜѸÌ@f=s6Þ'~_ü ˵‡õœíÌ®`Oq8圉‡„ò„ÉD‡Ä]‰SINI•IÓ\7n5÷e²wrmò\J`Êá”…ÔˆÔÖ4\Z\Ú)ž /…ד®’ž“>˜aQ”1²ÚnõîÕ3|?~c&”¹2³S@ýLõ u…›…£YŽY5Yo³Ã³OæHçðrúrõs·åNäyæ}»µ†µ¦;_-cþèZ—µuë uñëº×k¬/\?¾ÁkÑ„)*0-(/x½)bSW¡rá†Â±Í^››‹$ŠøEÃ[ì·ÔnEmåníßf±mï¶OÅìâk%¦%•%JY¥×¾1û¦ê›…í ÛûˬËìÀìàí¸³Óiç‘réò¼ò±]»Ú+èůwÇî¾ZiYY»‡°G¸g¤Ê¿ªs¯æÞ{?T'Uß®q­iݧ´oÛ¾¹ýìýCœ´Ô*×–Ô¾?È=x·Î«®½^»¾òæPÖ¡§ á ½ß2¾mjTl,iüx˜wxäHÈ‘ž&›¦¦£JGËšáfaóÔ±˜c7¾sÿ®³Å¨¥®•ÖZrö}Ü÷wNøè>É8ÙòƒÖûÚ(mÅíP{nûLGRÇHgTçà)ßSÝ]ö]m?ÿxø´Úéš3²gÊÎΞ]8—wnö|Æùé ‰ƺc»\Œ¼x«'¸§ÿ’ߥ+—=/_ìué=wÅáÊé«vWO]c\ë¸n}½½Ïª¯í'«ŸÚú­ûÛl:oØÞè\:xvÈièÂM÷›—oùܺ~{ÙíÁ;ËïÜŽ¹Ë¾;y/õÞËûY÷çlxˆ~XüHêQåc¥Çõ?ëýÜ:b=rfÔ}´ïIè“c¬±ç¿dþòa¼ð)ùiå„êDÓ¤ùäé)Ï©ÏV<žñ|~ºèWé_÷½Ð}ñÃoοõÍDÎŒ¿ä¿\ø½ô•«ï-_wÏÍ>~“öf~®ø­ÂÛ#ïïzßG¼Ÿ˜Ïþ€ýPõQïc×'¿OÒþ˜óü%wu cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYs  šœtIMEâ 9QBßaIDATxÚíØ½MÃ@€á‹ÅVè=@€-è¢øv`§Hv`‡sZ¶€d÷O‘P€B” ŠOzžÊÅ'Ý«“|£¦iÂ)‹EªÇù<ëùïïnO~óôü2Øù¯BÇZ.—ÿ4¹™y»Yo†<|q¸J)M§Ó”R¦ËPUUÓ4UUe:ß÷›õ¦ïû¼Æþ h·Û}\´m›R:Üf'ƘoC!„íë6¯†ŠïÚ¶]­Vù®†.Ða҆Π¨®ëc¾ Rêº.ßùÇ×ã²,s ¨®ëÙl¦õüô7ÞÞ£žßTEŒ1ëtº®ËúȪ,˼Òù ÈQáe ü¨ð¸ÑÛ~o ùã¿0B@„€! „€! B@€B@ „€! „€@@! B@„€! „€œçÖ°hm~†IEND®B`‚simutrans-124.3/themes.src/flat/scrollbar-small.png000066400000000000000000000102611474050137200223530ustar00rootroot00000000000000‰PNG  IHDRÀ«¯1gAMA± üa :iCCPPhotoshop ICC profileH‰–wTTׇϽwz¡Í0)Cï½ ½7©ÒDa˜`(34±!¢EDA‚"Œ†"±"Š…€`Á  Ä`QQy3²Vtåå½——ßg}kŸ½÷=gï}Öº¼ý¹¼tX €4ž€âåJŒŠ¦cû ðÌ`²23B=ÀH>nôL‘ø"€7wÄ+7¼ƒètðÿIš•ÁˆÒ‰Ø‚ÍÉd‰¸Pĩق ±}FÄÔø1Ã(1óE±¼˜Ùð³Ï";‹™Æc‹X|æ v[Ì="Þš%äˆñqQ—“-â["ÖL¦qEüV›Æaf€"‰í+IĦ"&ñÃBÜD¼)ñ+ŽÿŠœøRné¹|nb’€®ËÒ£›ÙÚ2èÞœìTŽ@`Äd¥0ùlº[zZ“— Àâ?KF\[º¨ÈÖf¶ÖÖFæÆf_ê¿nþM‰{»H¯‚?÷ ¢õ}±ý•_z=ŒYQmv|±Åï c3ò÷¿Ø4 )ê[ûÀW÷¡‰ç%I Ȱ31ÉÎÎ6ærXÆâ‚þ¡ÿéð7ôÕ÷ŒÅéþ(Ý“À¦ è⺱ÒSÓ…|zf“Å¡ýyˆÿqà_ŸÃ0„“Àásx¢ˆpÑ”qy‰¢vóØ\7GçòþSÿaØŸ´8×"Q>j¬1 ä×>€¢s@´ýÑ7|8¿¼ՉŹÿ,èß³Âeâ%“›ø9Î-$ŒÎò³÷ÄÏ H*P*@è#`l€=pÀ‚0VHi€²A>ØŠ@ ØvƒjP @h'@8 .€Ëà:¸nƒ`Œƒç`¼óa!2D UH 2€Ì!äy@þPÅA‰BùÐ&¨*‡ª¡:¨ ú:]€®BƒÐ=hš‚~‡ÞÃL‚©°2¬ ›À ØöƒÃà•p"¼΃ áíp\ƒÛá ðuø6<?‡g€¢†! Ä D¢‘„¬CŠ‘J¤iAº^ä&2‚L#ïPEG¡ìQÞ¨å(j5jªU:‚jGõ n¢FQ3¨Oh2Z m€¶Cû #щèltº݈nC_BßF£ß`0FcƒñÆDa’1k0¥˜ý˜VÌyÌ f 3‹Åb°Xl –‰`‹°{±Ç°ç°CØqì[§Š3Çyâ¢q<\®ww7„›ÀÍã¥ðZx;| žÏÅ—áð]øü8~ž MÐ!8ÂÉ„„*B áá!á‘HT'Úƒ‰\âbñ8ñ q”øŽ$CÒ'¹‘bHBÒvÒaÒyÒ=Ò+2™¬Mv&G“äíä&òEòcò[ Š„±„[b½DD»ÄÄ I¼¤–¤‹ä*É<ÉJÉ“’’ÓRx)m)7)¦Ô:©©SRÃR³Òi3é@é4éRé£ÒW¥'e°2Ú22l™B™C2eÆ(EƒâFaQ6Q(—(ãT U‡êCM¦–P¿£öSgded-eÃesdkdÏȎК6͇–J+£ Ý¡½—S–s‘ãÈm“k‘’›“_"ï,Ï‘/–o•¿-ÿ^®à¡¢°S¡Cá‘"JQ_1X1[ñ€â%Åé%Ô%öKXKŠ—œXr_ VÒW QZ£tH©OiVYEÙK9Cy¯òEåišŠ³J²J…ÊY•)UŠª£*WµBõœê3º,Ý…žJ¯¢÷ÐgÔ”Ô¼Õ„jujýjóê:êËÕ Ô[Õi4 Ý3šªššùšÍš÷µðZ ­$­=Z½ZsÚ:ÚÚ[´;´'uäu|tòtšuê’utWëÖëÞÒÃè1ôRôöëÝЇõ­ô“ôkô `k®Á~ƒAC´¡­!ϰÞp؈däb”eÔl4jL3ö7.0î0~a¢im²Ó¤×ä“©•iªiƒé33_³³.³ßÍõÍYæ5æ·,Èžë-:-^ZXr,XÞµ¢XXm±ê¶úhmcÍ·n±ž²Ñ´‰³Ùg3Ì 2‚¥Œ+¶h[WÛõ¶§mßÙYÛ ìNØýfodŸbÔ~r©ÎRÎÒ†¥cêL‡:‡GºcœãAÇ'5'¦S½Óg g¶s£ó„‹žK²Ë1—®¦®|×6×97;·µnçÝw/÷b÷~åÕ=Õ==›=g¼¬¼Öx÷F{ûyïôöQöaù4ùÌøÚø®õíñ#ù…úUû=ñ×÷çûwÀ¾».ÓZÆ[Ö}w> Ò Zôc0&8(¸&øiˆYH~Ho(%46ôhè›0×°²°Ëu— —w‡K†Ç„7…ÏE¸G”GŒDšD®¼¥ÅêŒÆF‡G7FÏ®ðX±{ÅxŒULQÌ•:+sV^]¥¸*uÕ™XÉXfìÉ8t\DÜѸÌ@f=s6Þ'~_ü ˵‡õœíÌ®`Oq8圉‡„ò„ÉD‡Ä]‰SINI•IÓ\7n5÷e²wrmò\J`Êá”…ÔˆÔÖ4\Z\Ú)ž /…ד®’ž“>˜aQ”1²ÚnõîÕ3|?~c&”¹2³S@ýLõ u…›…£YŽY5Yo³Ã³OæHçðrúrõs·åNäyæ}»µ†µ¦;_-cþèZ—µuë uñëº×k¬/\?¾ÁkÑ„)*0-(/x½)bSW¡rá†Â±Í^››‹$ŠøEÃ[ì·ÔnEmåníßf±mï¶OÅìâk%¦%•%JY¥×¾1û¦ê›…í ÛûˬËìÀìàí¸³Óiç‘réò¼ò±]»Ú+èůwÇî¾ZiYY»‡°G¸g¤Ê¿ªs¯æÞ{?T'Uß®q­iݧ´oÛ¾¹ýìýCœ´Ô*×–Ô¾?È=x·Î«®½^»¾òæPÖ¡§ á ½ß2¾mjTl,iüx˜wxäHÈ‘ž&›¦¦£JGËšáfaóÔ±˜c7¾sÿ®³Å¨¥®•ÖZrö}Ü÷wNøè>É8ÙòƒÖûÚ(mÅíP{nûLGRÇHgTçà)ßSÝ]ö]m?ÿxø´Úéš3²gÊÎΞ]8—wnö|Æùé ‰ƺc»\Œ¼x«'¸§ÿ’ߥ+—=/_ìué=wÅáÊé«vWO]c\ë¸n}½½Ïª¯í'«ŸÚú­ûÛl:oØÞè\:xvÈièÂM÷›—oùܺ~{ÙíÁ;ËïÜŽ¹Ë¾;y/õÞËûY÷çlxˆ~XüHêQåc¥Çõ?ëýÜ:b=rfÔ}´ïIè“c¬±ç¿dþòa¼ð)ùiå„êDÓ¤ùäé)Ï©ÏV<žñ|~ºèWé_÷½Ð}ñÃoοõÍDÎŒ¿ä¿\ø½ô•«ï-_wÏÍ>~“öf~®ø­ÂÛ#ïïzßG¼Ÿ˜Ïþ€ýPõQïc×'¿OÒþ˜óü%wu cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYs  šœtIMEâ92Ìí¼IDATxÚíÜ1nYÀñq‚û)#+›Ü`›ÒYÌ49ï0Ì|‚4oh£l³7Hb!—Ós ³² kc{møà÷ë‚)ã?ïÙžtªªÊs>gûêb4 ½þ/Ÿ>>úœï?¹þÖóó®ÓÉ"ëeYöpCëºÎxMþøðÀW/_îùúÍù9Z]—à hJéìì,¥ô%åy^UUžçA×?ŸÏ/_ÎçóXË66ÆæØz{{›Rjšfõψoƒ²,ã~?æóùìznÙ«Qiš&¥qr–ʲŒÛÐ,Ëf×3 ÝY@'“ɪžA7ê¹sMÓL&“¸ë×Pžл{OõTÏ64îY^CyN@˲,Š"î+iÛ6ô›¶ßïN‡1UEQ„þ0K)µmwýƒ“A¿ßW··>‡C ÕЗ×s8ª§z]@»Ý®}¨†¾|ïÙíFýó8õäIzë•eúüÕ¶mè?Þî÷ûáÞË^cclŽz ÀÓv n¶Û­è7Û™ós´:7‹…«ìDôÿLÄ@@@@PP@@@@@@PP@@@@@@PPP@@@@PPP@@@@PP@@ ŽNUUçãqÜp1E_ô2?æçÙò<½þžÏݪª*ôúëºöMÄPP@@@@€ÿäVÎs+$ÄÕ¹Y,\GxP@@@@@@PPP@@@@PPP@@@@PP@@@@PP@@@@PP€ƒÖ»¶yÞùx¼Ÿ/ úú¿|ú¸ÍÓ¾ÿüåú[ÿáÍÏ»N'v@³,«ªêá'Õuí£æõ|þëóÃOøñ÷}^¿ù1?Žð<}zOJ©,˸/)Ïó¶mã®z5=}nÙ)¥õ Ržçë¤éÕtýÁˆƒ; )¥¦ibþ½·AY–)¥  ^Mg׳ˆ£¿›¸ݸÔ@?|XŽ€îò¿ªgÓ47!ê¹|3lÜPD©çìz¶qC±ÏŠ¢xô‘X;èXoÁÉàÑGxÅ€®ê¹ÚPÄ U=WŠX ]Õsµ¡ˆÕв,ï³(ŠX‡˜¶mï|¸CÌéûӻŜ l?ß4 ëG°‡²@G°Xoàõ#ØÆCYˆ††«ç½†ýЪ¡êùfzA\ÛÁb9Œ×êG(A׿lhÜ_B.»©ž;hèß¼g¡~aúÀèLC ’A:®#<OÞºQd·¢ß(b~ÌÏÑêÜ,®°Ñï…w„PP@@@@@@PPP@@@@PPP@@@@PP@@@@PP@@@@PP€ƒ×©ªj›çÇûù.F£èëô[P×µëoý¹þ¾}Ûæi~ýºŸëïíí•ÝRôõGg~p„@@@@PP@@@@@@PP@@@@@@PPP@@@@PPP@@@@PPu @@@@PPP@@@@€§ûù?Å[ãm‡hIEND®B`‚simutrans-124.3/themes.src/flat/scrollbar-touch.png000066400000000000000000000041431474050137200223670ustar00rootroot00000000000000‰PNG  IHDRÀ«¯1*IDATxÚíÝÁQ[WÇa)ôà\IÊÈŠ™l܃X ¼É «”‘~Ü,ˆ2w’¼DH<ý‘tïy|ߌµ|-Îù¡g Xo6›Õ¹}{|<ûÇ<ä·íöìó× Ü'‡|x8ûǼæý_ýüægß5ïÿ/ëõÕþ®K¸ÙýÙœõó½½ÀD22óçõSïT% \ÐÝÝ]ï#À%­¾ç½ä¼¾*¹mNJO‹QḓZ}+ÚJÔ]Œ¶ã/F›ûûûUÙi1*¼ë´€Vߊ¶ ///«š‹1]†ñ£ÍIÑi1*ÌqB@§õl·µLW¢ÝÖRw Š6t:*:Uwx77 ÓzV4­gEÕ hC åYUϾ–1úÚÝ2i(ïT=ûZÒÐkhwK§¼Põìky㮡Ý-o¨::Põìk©ƒ®¡Ý-u´®ï`@Õ³¯e¸†v·ì»š·ªž}-~¸Ÿžžv·ÏÏϽÒPš·Ú&»MyEm2noo{$T}3«^ÏÕߣU=@˳ë8x ¯¡}-u¸ÕsK°+;ö$’†öµ¼WÏA,o´zyçeLÚ×’]=±¤¡êîýÒkh_ËwõÄ2Æi³¾•SCûª>ôê9ˆêƒ4 ¹?LDCûª8úmZÔsGh|'ü8»iC+–tÚЊ%­µÓi)ZÏ騨'o:í*WߊiC+®Ät Æ_‰6!çdeT˜çä_éQz+VõÏA­ß3QwNVF…’_*Wz+V•W¢±WcT8ί5ݬꙥ/óçµþñúÚû À'õe½î}„q P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„Ö›ÍæÛãcïcä¾?»ívÛû@hýãõµ÷Jr P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„n¾?<œýƒ~{|¼Ú?à·íöìó×Íæjç¯~ÿW?¿ùÙwÍûÿËz}µ¿ënv6gý|o/0‘ŒÌüði¹„ (@H@B P€ÐÜ€ÞÝÝõ>ꇜ÷™âëóÜ4 èfεzînŸŸŸ{8Ñê¹»-š¡vìÝíø_‚/´C Up5TÁaƪ‘½ж÷÷÷OOOÚæãåååöö¶bC§¼¡ÿŒÊüwj¨þ•ùï2ÔPeÇ|¨÷Î%üt%Úm­kùéJ´ÛZ³²¿ƒìê¾ ž«‘†*¨çj¤¡úÈ` ;Tã;Ðý•gÜçØ_‰qÆ}ŽCc=渷G‘»G”'½W{û¶{u÷ˆò¤÷jo?Âgä#S]e#t0 ‡PTiè¡Uz|'GØØ}§6tœz6§6tœz6ÙT¿ #{; Ç/ÇÆoèñ˱ñ:g'ÇÙÛ©ù ­žÍü†ŽVÏæÔ©y Jx# sþ3kä†ÎùϬ‘:'GÛÞfNCǬg3§¡cÖ³™?ÕcÎ-ÿèü§Ælèü§Ælè©;9æoèÈõlŽ7täz6s¦z´É/ê?=õ‰ÔÑzê©£54~JáPCǯgs¨¡ã׳9>ÕãÌ|uÿÔËPúZÞËPöZ¥žÍ~C«Ô³94Õ#LûbüP/Cék‘/C™Õ8£2ßt¨Æ•ùöcØQ)ê?߉´îÝcÉS:ÎJ´ï©8µ¡ã¬Dö=-ƒ¯Ät¨Æ•ù¦C5ΨÌ7ªÁG¥¢ÿ+gÅŸª8âS‹ñÖк£ÕZw´Úá9ZÝùqv\CÝz6uëÙ¨ç…(@H@B P€€„þzSõgéËüði­¼¾ö>ðI}Y¯{áC\„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ¡õf³9ûýöøxµÀ÷‡‡êç?ï§`»Ýºÿ¿Êùÿøý÷³ÌŸùåj翹æu ÕÏ_]õû¿úùéË%<@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ ô'ÊwZ3x7Ì-IEND®B`‚simutrans-124.3/themes.src/flat/titlebar.png000066400000000000000000000021401474050137200210650ustar00rootroot00000000000000‰PNG  IHDR€Í +ébKGDÿÿÿ ½§“ pHYs  šœtIMEâ"'EHŽZíIDATxÚíØÁ«0@QóåZ\IÊHô/\PF*y P†g1#e;Ò|=rÎ*ì̃k Ëãñ(/Ö1J*[ïå*Ò ÿmþ×_K)­µ¼7MêÅ¿ŠˆÔóOºþ>˜|ªå˜Óð€@ €@ €@ €@ €@ €@  #@ ÀeÕ­÷ÖÚ÷Áí~OwÏ}¿Æ•ˆˆuŒtËÞz?g\µðKçêß\_Æ_Oø±sš¾@ €@ €@ €@ €@ €@ €@ÀÀ¨[ïëyOà¹ï©/@D¤žöû§f/8"lcÿQ껿”²sºŠø€@ €@ €@ €@ €@ €@  #@ €@ ¸Žºõþz¼Ž‘ëÞÖŸZºá¿Í?ãúk)¥µ–÷¦I½øWáx€à,Çœ¦€'€@ €@ €@ €@ €@ €@ €@ .«n½·Ö¾n÷{ºxîû5®DD¬c¤[öÖûù;ãú«=€ß8wψð €o®ïüãäæ é,Çœ¦€o€@ €@ €@ €@ €@ €@ 0€@ðjöØzO½þuŒ Ì?ïY,Çœ¶¼@ €@ €@ €@ €@ €@ €€ €@ .á à/dÇQøPòIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/000077500000000000000000000000001474050137200214135ustar00rootroot00000000000000simutrans-124.3/themes.src/highcontrast-large/back.png000066400000000000000000000007601474050137200230240ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<’IDATxÚìÔ± €0 EAeØ9oa$V úp×PÇ~xÍLUu¥:ë rç¼°Û¿‹ „€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@B@€)öù|:ö×ZÑ ˜™èù»@! B@€B@ „€! „€@@! B@„€! „€! B@€B@ „€! „€@@ñ;ý3c‹.±¨ÃÐvè! B@€B@ „€! „€@@! B@„€! „€ „€! B@€B@ „€! ÄÜ Lk 6#ÁEIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/button.png000066400000000000000000000030111474050137200234270ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe<«IDATxÚìÜ¿K+IÀq÷°6V‚V±µ2µ *V‚øˆX¤´O‘¤°Š‚eJKKÔ‘€`moc*ÑFìö nñ°<Ï—™äó)–uo‹¹aw¿³$/Y³Ùœ*¡ÞjME©û9°h‡Wrü©k·ÛÃOxÊs×ÏwXȲ¤¯ÏÏŸ¯˜ž‚/¨'~׿£]LÔŽQÉŠ´ôd>@tý1ä¿U*@zûøø0A¤000Ì ` ` `Œ™Ì/)à   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@À@À@À0¡én«Uæ¼z¹Ó~¿büѯäøS×n·‡Ÿð”箟ï°eI_9ÍfÓóÇóçצá|E=ñ¸žø íÊ`¢pŒJV¬€þk]­VÃv0XA[AåH×°ÏÀfff®®®677ÍÉìøøxiiÉ{Àö÷÷Ã[W±¿»»{ppv:N¯×3SD°£££n·{}}V­VÏÏÏÃÁÛÛÛF£ašˆ7`777a»ººvwwöŸŸŸ···ÍQ¬×ëu:¢asssageeåýýÝuÀ‚F£Q4,ØÚÚ &€8ýó2‡†½¼¼/df€dœœœ˜"—ù%Rä×è000   @À@À@À000    @À@À@À0000   @À@À@À@À000   `lLw[­2çÕËöûãvx%ÇŸºv»=ü„§   øG‚Ç#tþŽþ~Ô»Ýn³Ùüb0`!êPEc£ÜÝÝÝýõ'44À@Rœý¹ùQ: aóÿm`[£Ñ`«ÕŠmÙû÷2çBH ³g =TxøÍÍ@'Œ„cï‘zg Vþß›@ý¨¨¨ËËKQN8,,,99933ŽŽvww/..Êÿ«ôõõµ¨|kkk¢ 7:Öòòr“É„ÇËË˽½½ÛÛÛåÿw‚hÏë$Êè£Ñ†=ùùù؃¥ïÜÜÖðB äŠþÿ9Ut?¦¹¹9++KÚãõzÙ¿) 4dØ^]]IËòÇö¤¥¥Õ××WWW'%%áUô=(?³³³ô€}i322ÐT 8ôx\\\QQ‘N§‹Ç\†¾áààÀétB ´ÒôàÂÈž‰{&È?55Õh4&$$ Á ÌP···x ‹öââ⦦¦¼¼<é¦ÁÎÎŽÍfÃÛ Qp›ÐïG ¡íuuujµÛÄÄDtÊ]]]cccX¢ã¥””L^%%%7,,Ëææ&{ Na_€4(;;5&==Sæ¦ÕÕÕ˜˜˜šššÊÊJh$]'(N===+++§9"·@è$ž4ªÁejj sVii)zd<ÍÍÍ5™L˜ªÐÁ-i'Øßßïì윘˜}æRÈøû#ÒóósEÙ&''!Gaa¡V«ÅZ E¨¶¶I¢%’Þ€z³½½ýñãÇññq·Û-®:ÑÑјš2þaOÀ/º‡uoooiiitt}±´ç‡{Þpzz {”™ÿËQÔ—?ÒRfã‰ü‡‡‡Q Ñôh4š‡_™!áããã‘‘‘ÁÁÁ½ÄEZZ*å«“'ÓªÐ# Q°°êïï—Öçû1aaEÖ××ǯ|þÛHimÍ¿Eú~Y­V\ UUUÒ]÷ééiØ333#­ê —ñߨð[[[¨C˜ÑÊÊʰÇétÎÏÏû|>ѯ $k?´¾¾®V«ñ‹/ÌbŠj¾‰J¥‚ñÏ=UPäñxBîUHép)”Ì<—?Œq8îÁƒ^·1I ƒÁðÕýÏ=}‚txP •þ!áUb™Íæ¦W õr~1›…οåÝ;½^ÿ*¡ìv{÷§OrW ‹Å‚ ðâÃá‚Pò_¢çïr¹ðÁX"IEND®B`‚simutrans-124.3/themes.src/highcontrast-large/divider.png000066400000000000000000000002601474050137200235450ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰tEXtSoftwareAdobe ImageReadyqÉe<RIDATxÚìÏA  íÔgßnЀNRŸõVd󹙤Í,IEND®B`‚simutrans-124.3/themes.src/highcontrast-large/editfield.png000066400000000000000000000007611474050137200240560ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<“IDATxÚìÔÁ €@ EÁ]Ù"´ÿæÒÅ,AAˆÎ\}ºœoÓª~‹µk×>~üX‘hXÄwµeËQîܹs’ÄRÙ~ Ð1Ä1…9F`_äÑ1cÆ(9tW”aÅ8ËCÎÎ΢€Ô´/?³\YYYŸ>}B¯RaïÝ»=ª¦£ùåLJŽ6…z¡,>ÇÜÜ•4wîÜÈÈHŒ˜½zõª­­Å~…ƒ†mÛ¶ÍÂÂBeïÕ êW>Œû¥K—ðÙ±cGl–••ýË ØÄNy‚¢L‡¡_L$j×A¼xñBÌ(ªÏ„ ´›%%%²,<™²À„É:‡îBÒÄx*çu¯^½ª~ýCz,X0kÖ,¶àþýûÇŽÛ³gšaC®ž?Ž¡.¸¥Fnß¾-îûª<÷ ÓäÐÐP 1 .DÆpâÄ è¼ &Fý–3eÊ”ãÇ‹²ê%F1 ºví:þ|™íÑ{ý:Ë—/_·njéfûöíaTBBBž>}ŠC0ô»wïöööÆ!tŠ”””nݺÁî«èÀÌþšHl0¹S¿7˜MgggËMÅçß´Ók'N…€€­Â©?D÷üùóña¹¤z•——ãºÐ† ûXTT¤ì蟚šŠ8û÷ïŒM쇛‡!ƒ¶á¨´ÂÊ’ŸŸ/næÁ{áWñåËì·±±Q¿·>zôHT{qqñÈ‘#333Û´icö×B”!Z¡z*2~8`¨W= U( Ea'ᜆ“ñ•fÛt¢I6ŠÜSnnÙ²E{'L¢ò*&HWll¬¼«$ÔËÄœ)ÿÛ·oÅ;´•:˜W'ŠÅP´'eãǯµ\ˆ~ñÈ‘#ÜtT|Ä ]×ßß_΢ȳ”15ã|ø ™Ê1C¤zA¦NŠáclåéÓ§=<<0`AÏ ƒšñÃ`Ah!·ãÆ[³fÍñãÇ<.áÙ³g>>>—/_Æ YWW§ÔŒhãÞK}VYY‰ÏïDrSSS#ÊõН4/?0¤œÚ»_fÆ›aÚÇÂÔI(@”‘¸!•ÖKü‡–åÀÀ@í e×š ‚t©¿`ìoAËIJJŠ‹‹Óš0e8p P¯âââèè訨(Ø—ÚÚZ3ã dgΜ¹wï2n¦€~ÆÃ‡'MšôòåKhØÄ‰¿~ý ؼy³‰}TÇÇüh*74T2<.ɧOŸÜÜÜ`¿JJJ¼¼¼<==a¿°éêêŠC ãd|EQˆò#¢ŒºóaòçÑÑ ª¼ûâìì,ï„•——«ü ÍÍÍ·Ö¡a°¿;vìxûömZZšX¡#ÐÔ!Zðð1c¡^è ûöíèªlØŽŽŽÂ0àúõëÈ~„z‰eü.°h………¸eçNÄ£x¾¾¾bRº]»vØÿîÝ;£mŠ÷Rß?>88¸¢¢¢mÛ¶'›mÛ¶¡ ¼y󦬬 lb'ᜆ“ñ•f»á{`yyyr¸‰ÇçªU«äØŠ„T{²²÷0ÐuEðfš÷VÔGÍøåãØÐa%“““ÃÂÂÔÿgK¯]»y3y@ÁøÅM/“ˆŸ-DT-~sss¤Ìq˜­­mDDrçššyéóöíÛ—,Y"§‰”ŠßÚÚúÊ•+ƒÞ¿?òè1,£x*%%EÁößtǰaÃ6lØàî°°€tݼyû]\\ºwïŽõBê³lÙ²»wïªPÿ Xxx8¬ºœy–K{s]=Y}“2Ö¸kQ3~hÀ“'OêÏeÕ÷‘Š/¢Akƒ”s¹B·nÝ*eL©ø!]Ú§…å‚ËëuÔ~$nnnÇŽëÙ³guu5ÔËÒÒr×®]Úy]ÕâGŠ€ÔáÎ;âAl3ã-=ñ(Rý±U~•”úÔ¯ƒÁ0׈½½½ÁvV)**JKKCb¡½û¨–€A®nݺ%;ð¸qãÄcË:åë9Ð¥eV¶£®ÅÛ+ÊËË!c?›BT6~¹òÐ$™Ð×* åøñãå大§Ï™3GÁøãââädCvv6Ó¿}‡úõ„:''§S§Nð^P/“W1)¿x ÕÞôWaQÀþDûAkAoEöÓµkWlVTTܸq#Rý‡hÕz"šŽT/t`ùÒ Äû™ÌŒOwâ4õŸ†‘ï^²µµ ÑÝ[ºsssµvðàAýöá·Ä‹}}}U‰‚x‰”_‡Ø w^¿~mccÓàËpÕÁÇÇgõêÕQQQÚ—‹h‹ŒPoþgTVVž3¢xœ¦¦}Ò VL{(88X}Ñ2‰ä´gAA}íªÂ-Ó_$߈P25#„néå]3MÇÒÒ²cÇŽ{ö쉈ˆP6HGGÇ„„hXËûï`ÈŸ£±™›ˆ²S(b)¼c#·Áøßy0þ–¿Á`˜9sæô^ŠÄïååURR"^\¤£ú×;zoÿ-YÀ?ãgüŒŸ´àúo­ B¿0~ÆÏø?ù«sþx„BôH«3÷!„BF!„PÀ!„ !„ !„B#„B(`„B(`„BŒB¡€B!0B!0B!„F!„PÀ!„PÀ!„ !„B#„B#„B(`„BŒB¡€B¡€B!0B!„F!„F!„PÀ!„ !„ !„B#„B(`„BŒBŒB¡€B!0B!0B!„F!„PÀ!„PÀ!„ !„B#„Bþ›ÿ0I½á@º…/IEND®B`‚simutrans-124.3/themes.src/highcontrast-large/high-contrast-large.tab000066400000000000000000000122221474050137200257440ustar00rootroot00000000000000# # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=High Contrast (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #000000 # tooltip text color (240=black, 215=white) tooltip_text_color = 215 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # make the chat window transparent in network games gui_chat_window_network_transparency = 13 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #000000 #################################colour stuff################################# default_window_title_color = #194766 gui_color_text = #c98926 gui_color_text_highlight = #FAFAFA gui_color_text_shadow = #868c86 gui_color_text_title = #bee6c1 #gui_color_text_strong = #E46A0B gui_color_empty = #FAFAFA gui_color_obsolete = #2878ff gui_color_edit_text = #c98926 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #868c86 gui_color_edit_background_selected = #5686a6 gui_color_edit_beam = #ffffff gui_color_chart_background = #333333 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #39a1e6 gui_color_chart_lines_even = #ffffff gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #5686a6 gui_color_list_background_selected_nofocus = #5686a6 gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #868c86 gui_color_button_text_selected = #b3b3b3 gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #b3b3b3 gui_color_checkbox_text = #c98926 gui_color_checkbox_text_disabled = #868c86 gui_color_ticker_background = #000000 gui_color_ticker_divider = #ffffff gui_color_statusbar_text = #c98926 gui_color_statusbar_background = #000000 gui_color_statusbar_divider = #ffffff gui_highlight_color = #ffffff gui_shadow_color = #ffffff # gui_color_text_minus = #C00000 gui_color_text_plus = #c98926 # gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #000000 # Color of load bar in loag game, load serve etc gui_color_loadingbar_progress = #000000 gui_color_loadingbar_inner = #868c86 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #ffffff gui_player_color_dark = 5 gui_player_color_bright = 5 ##################################size stuff################################## # force main menu icon size icon_scaling = 150 # titlebar height gui_titlebar_height = 22 gui_gadget_width = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 26 # gui_label_size = 24 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 24 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 24 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=highcontrast-large.pak simutrans-124.3/themes.src/highcontrast-large/listbox.png000066400000000000000000000007551474050137200236140ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<IDATxÚìÔ± €0 EÁ1ì?Ùâà ) w uì‡+Éã ú®`›ÖÕ•˜ëÈB@„€! „€@@! B@€B@ „€! B@! B@„€! „€@@! B@€xS%y>³í뻅 è>! „€@@! B@„€! „€! B@€B@ „€! „€@@! B@„€! „€! ~bïþ€$¶èÑU]þ`\ „€! B@€B@ „€! „€@@! B@„€B@ „€! B@€B@ÈB@„€èâ`ÇNøú[:ùIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/posbutton.png000066400000000000000000000007021474050137200241550ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆtEXtSoftwareAdobe ImageReadyqÉe<dIDATxÚìÙÁiÃ0€ÑX‡NÐC¦ê*ct©êÐ zq.F˜Pù'–Ðû"[$ø!Ydúšç“T[ª¸çÜùo~ûžºþþŸ×k߀bh/ †Ú ˆ!†nMËKôB.XäÿÉmPøyŸ~~zïzñ±>.—‡ŸŸÞ»^|Ø t.¬Üí¯C‹’­±ýuhQ²56¾¥YìeÃîe)j"†Æ4”çbh@C)v:†F3”Âgdh(Cñ€rç€Z8ÕïéŧúD=­¢g4=‘€èPO zÆÔó(îÇöõ,kl_Ïòø·Æ–õœÖ?S«ê=®=åA½Çµ§<¨«gïfçvç D=õ€è¡§þH >Æ $€@HH $$€@@H $€@HH $$€@@zi¿ Û’†õËIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/roundbutton.png000066400000000000000000000017141474050137200245070ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe<nIDATxÚì×Á ƒ0 @Ѹb –bŒìäŒÁRŒ‘²CUE†÷.\CdåË‘™­µ£÷VÓ9ÆÎ_ùYe(=9ÞïÏ/> ŠkN·€   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@À@À@À000   @À`¥íãþ½ýgœ¿:ó³ÊQzr2Óüxl`¼K\sºl` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` `+mç÷çè½è<ãüÕ™ŸUöˆÒ““™æÇûcà]âšÓ-`@À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@À@À@À000   @À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@Ààÿ¾ y(FGf²FIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/scrollbar.png000066400000000000000000000063701474050137200241120ustar00rootroot00000000000000‰PNG  IHDRJòY0tEXtSoftwareAdobe ImageReadyqÉe< šIDATxÚìÝÁOYðî‰M/n¢'Lô Gá"ñ4p٣̎ÑãºË°³®'ã—™ÌI&!ðMô¤‰^LP=²¯»àQ- Ãl¿7~>éHUWÙyÝ]]ß÷{U]]___¯†—µö8uH£ýÚ¯ý|j>ó|šŽêõúâ°jˆßCûµ_ûóm?*¼#ûFGG‡‡‡;;;r|Â#×jƒƒµŽµ¯F²|Ãúûû{{{=:>>ž`óæææÖÖÖ¦¦¦îß¿ŸãËûÓdíõ›ÚÌLmòÇ,7±±±÷ïß/---,,Ø»qh0¼©££#ÌÎÏÏçõ<¯6öûáßãdzfö>õn »þ0ûôéÓd›:Ô4111µ)¯—zðJãöïokfIþÍË…¦‘‘‘¥Mvs0§èòŸ>}:ǧwþüF—¿ëó,ßžîîî¾¾¾ð.œ¥EO-;¡»0ÑTœ3V>‰ ¡»zúá*Ëþ¾m'd¡ó Beúå“ à{*€íâYµ½†€ÒÏâ¨í5”¦xGm¯! dí>”¾Ý‡€Ò·ûÔ®9|xí/8ÜÞö;Ì ÒwÛå4ÐùùùøMà‚íyèÇ[ßN°ý{žúôéÓøMà¤Úú—.]j¹æ‡NMªý?MÖ.^l½æ‡NMªýccc===-×üÐi ÀPU<|—éÁâá»L¿ßåûE°ò~?Ç/‚•÷û9~¬¼-ù"QØtn7U.‘‹ð¡ýW¸}[½D6IÖ499Y¹DúâYdÙ] ¢Ï"ËîR…x™KApðˆâ'9^ .¯çù ùIþGébpy‰Ÿäx1¸d›:==ïÅàjÍSò½\­yˆÅÅàØ§ÖÇ>J²_„Ñ~í×þÄÛO{ù€àSr¤\æKûµ_ûAÀ¾Ô_è;¨€@ €@ €€@ €@ 8†ª1 ³/nLÏü’èëÿþýû .ÓÝÝÝ+++qQ˜íéé)¦———íû¨ír àÌ™3qK*„Ùpg.O¬»«vîܶ{ÂlwW6oÌÉ“'Ëã?A˜ w&Þì©©©8=::Z^Tž-¯–”™™­é‘kÛ•gË«%¥œ¸}}}åEåÙòj€†‡‡7úDM•;Ó78¸1ñömãV¹3}ñèËû¦ÊÉ 5bÜZ*ƒŽÿ•Ù°BX-ñ +–ŒM;ëÈÄÅ’1l-q‹Êâ@¥d<Ú´³Ž„PîÝW†k˳ÉåáÊpmy6ÙQ rï¾2\[žM¿(—Œ; Ê FQJ%ã΂2}å’qgA …êµ€:;;ççç[öÂl\VKóùtœ¨=ÜìéW†kÃl\VKSè¬Å“>+õa6.Š}º”MLL”/&˜ÑøOáÞwÛ.&fó2;;[¾˜ ñvª?ñûP¢½?‰§ý ¶Ÿ—O¶ýû¼œx²íßçåÄÛÛ~€¨ökÿ'Ú~ÚË/‚|¢Ž”{ùÒ~í×~P°/õú*€@ €@ €@ €@ €@ Ï‘S‡ô@/Ûôþí¯×ë~„õõõ6¶ÿç»wåq¾¼ySûÜþ[·nøîܹӯöÿ¥^ðïÜþÃÑü `ÀËÌŸÀKïa[µ«ç¨ý @ @ €@ €@  €@ €@ €^€@ ÙøŸŸxõþª’‘ÏIEND®B`‚simutrans-124.3/themes.src/highcontrast-large/theme.dat000066400000000000000000000120011474050137200232010ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=- Image[7]=> scrollbar.1.6 Image[8]=- # scrollbar knob left center right Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # back up and down Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.2 Image[14]=> scrollbar.2.1 # knob up and down Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.5 Image[17]=> scrollbar.2.4 # scrollbar back up center down Image[18]=- Image[19]=> scrollbar.3.6 Image[20]=- # scrollbar knob up center down Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- --simutrans-124.3/themes.src/highcontrast/000077500000000000000000000000001474050137200203235ustar00rootroot00000000000000simutrans-124.3/themes.src/highcontrast/back.png000066400000000000000000000007461474050137200217400ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<ˆIDATxÚìÕQ €@ DÁ+Aø.ü 3Ú¾ÜM’{;V½êýÏ•,xk³„€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ DIr7pÎT }ÿ^ „€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ „€ø‰½}€$®ø¡¹_B@„€! „€@@! B@€B@ „€! B@! B@„€! „€@@! d! B@ˆ_xž÷nÒIEND®B`‚simutrans-124.3/themes.src/highcontrast/button.png000066400000000000000000000030111474050137200223370ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe<«IDATxÚìÜ¿K+IÀq÷°6V‚V±µ2µ *V‚øˆX¤´O‘¤°Š‚eJKKÔ‘€`moc*ÑFìö nñ°<Ï—™äó)–uo‹¹aw¿³$/Y³Ùœ*¡ÞjME©û9°h‡Wrü©k·ÛÃOxÊs×ÏwXȲ¤¯ÏÏŸ¯˜ž‚/¨'~׿£]LÔŽQÉŠ´ôd>@tý1ä¿U*@zûøø0A¤000Ì ` ` `Œ™Ì/)à   @À@À@À@À000   @À@À@À000    @À@À@À0000   @À@À@À@À0¡én«Uæ¼z¹Ó~¿büѯäøS×n·‡Ÿð”箟ï°eI_9ÍfÓóÇóçצá|E=ñ¸žø íÊ`¢pŒJV¬€þk]­VÃv0XA[AåH×°ÏÀfff®®®677ÍÉìøøxiiÉ{Àö÷÷Ã[W±¿»»{ppv:N¯×3SD°£££n·{}}V­VÏÏÏÃÁÛÛÛF£ašˆ7`777a»ººvwwöŸŸŸ···ÍQ¬×ëu:¢asssageeåýýÝuÀ‚F£Q4,ØÚÚ &€8ýó2‡†½¼¼/df€dœœœ˜"—ù%Rä×è000   @À@À@À000    @À@À@À0000   @À@À@À@À000   `lLw[­2çÕËöûãvx%ÇŸºv»=ü„§š]–ìü?û}“˾&“4çïÇ«,Ëç5Œì]rŸ:>¿`·Û%;|¯è®Ï»‚·4 ²¾±˜ÿp8œN§Ùl–éüyt½^³h»Ý‡Ã|çÏåù÷:³ê¬×ëÇü‹Åb<Ç›ï;«NKEõ™6ëÍjµªª*æsÏf³‰žÏçù|ž×ª“Ýóïucç:õ©¹º«od4Ù¹| kä±UECõ/qÔ“û1N@­ŠÝêq܉÷±ùt[ÐïÒÍD7õª“ÑÁY@iY.—>Ô¶Jü/ý/å>Êÿ©x©üÍüéã€! B@€B@ „€! „€@@! B@„€! „€! B@€øo •ikcfJIEND®B`‚simutrans-124.3/themes.src/highcontrast/divider.png000066400000000000000000000002601474050137200224550ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰tEXtSoftwareAdobe ImageReadyqÉe<RIDATxÚìÏA  íÔgßnЀNRŸõVd󹙤Í,IEND®B`‚simutrans-124.3/themes.src/highcontrast/editfield.png000066400000000000000000000007551474050137200227710ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<IDATxÚìÕÁ Ã0 A)Pvÿͱ‹s ò0™é€äBÚIf»V½êýŸ±}~𱄀! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ Ds­5ÍÜ{W Iõþ½@! B@€B@ „€! „€@@! B@„€! „€! B@€B@ „€! „€@@ñ'NûI\ñÍ€¦|€qC_B@ „€! B@€B@„€! „€@@! B@YB@€B@ „€! B@! B@¾ò0Œg Ð\IEND®B`‚simutrans-124.3/themes.src/highcontrast/gadget.png000066400000000000000000000037561474050137200222770ustar00rootroot00000000000000‰PNG  IHDR@@}g_HtEXtSoftwareAdobe ImageReadyqÉe<IDATxÚìÜkHTiÇñÑ¢"2(kÀZa³"GéJE—%ܲ¨ ËB:LÙ‹„(­È ìòF&²ìMРÅö&r›(¡ûhTô"Ê.ÔRF`K¥îoÏgg-Z[–õyìûâ™ã¼øŸÇsÎïùŸ9NJwwwàkü°Ëè¯|?õS?õS_í,óÿßúNÿRRRzùî¯M»ÿõSÿ7^zzú‹/˜ËÓËNNÏj ©ªªjll¼ãihh(..ýZ/ÓËEáp¸ìH0%¥÷9`Ýžx''g•ÇOÜ… š-ÇwñØÚ¼yó³gÏ®_¿¾hÑ¢1cÆØ\jffæ‘#G´ª­­ …B.Îö²eËb±˜ß²(ÏôÒéô:yòdFF†öÂé 3½WŠ Ø€tÙ?|øp“G½ÔF7̬CÍà€§ÇFû)«öìÙ“››û£çÑ£Gèû÷ï7ƒ ˜ZI“ÇÚ)·Z®K—.uvvîÝ»7üóü}÷îݹsçl®9k¡6lذµk×& %Y$q«!»r劚xµ,ºâk±¯Ô)SܺÖ92àÝ5ée=&ý—è÷^öw`“&M:þ|}}ýºuëFx4ÐKmÔÜ°æææÊÊJ ¾÷h —ÚèУøþýû466š]pÅ… Lâú‡ËĉõÿåË—]Ù…êêjµ\7nܘ9sfjjjWW׃V¬X1pàÀ²²2ËLWVVÖÁƒõ[Б£õD[[›²¹sçº2ÿ555W¯^]²d‰£ÍJ4U㨖ÝO/yòäIQQ‘vÍ­Ó¹Gïey6yòä³gÏΞ=[kÍ7þàÑ@/µQ?Ò쬂9sæŒ~ 6ÏÿÇKKKóï“D"óäa(ò¦7‘fÿ ¬ôÒ5H ÙŸ0a‚‹ ºººüü| NŸ>Ý£‰t+À í‹Vvèݶ~ó·":ÚÛÛ]A6Ãb±˜Ÿ^–ׯÄúÇO¼l°`/>ârñüµ¼þÏ<…èú/@‹¸õë׫ K¾ùÆDýß`ýápØ446×?jÔ¨^~–µÖûï9äø'À¸€R?õ÷«ú{ÿeÄXã§ï|pü;ž©Ÿú©Ÿúû0˜ÿ¾ìÀžó“¥2   @€@€@€0000 À À À€€€```    @€@€@€000 À À ÀàÛõ‡5 8¬§8ÛIEND®B`‚simutrans-124.3/themes.src/highcontrast/high-contrast.tab000066400000000000000000000120751474050137200235720ustar00rootroot00000000000000# # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=High Contrast # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #000000 # tooltip text color (240=black, 215=white) tooltip_text_color = 215 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 # make the chat window transparent in network games gui_chat_window_network_transparency = 13 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #000000 #################################colour stuff################################# default_window_title_color = #194766 gui_color_text = #c98926 gui_color_text_highlight = #FAFAFA gui_color_text_shadow = #868c86 gui_color_text_title = #bee6c1 #gui_color_text_strong = #E46A0B gui_color_empty = #FAFAFA gui_color_obsolete = #2878ff gui_color_edit_text = #c98926 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #868c86 gui_color_edit_background_selected = #5686a6 gui_color_edit_beam = #ffffff gui_color_chart_background = #333333 gui_color_chart_lines_zero = #FAFAFA gui_color_chart_lines_odd = #39a1e6 gui_color_chart_lines_even = #ffffff gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #5686a6 gui_color_list_background_selected_nofocus = #5686a6 gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #868c86 gui_color_button_text_selected = #b3b3b3 gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #b3b3b3 gui_color_checkbox_text = #c98926 gui_color_checkbox_text_disabled = #868c86 gui_color_ticker_background = #000000 gui_color_ticker_divider = #ffffff gui_color_statusbar_text = #c98926 gui_color_statusbar_background = #000000 gui_color_statusbar_divider = #ffffff gui_highlight_color = #ffffff gui_shadow_color = #ffffff # gui_color_text_minus = #C00000 gui_color_text_plus = #c98926 # gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #000000 # Color of load bar in loag game, load serve etc gui_color_loadingbar_progress = #000000 gui_color_loadingbar_inner = #868c86 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #ffffff gui_player_color_dark = 5 gui_player_color_bright = 5 ##################################size stuff################################## # force main menu icon size icon_scaling = 100 # titlebar height gui_titlebar_height = 15 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 22 # gui_label_size = 24 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 16 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=highcontrast.pak simutrans-124.3/themes.src/highcontrast/listbox.png000066400000000000000000000007551474050137200225240ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<IDATxÚìÕÁ Ã0 A)Pvÿͱ‹s ò0™é€äBÚIf»V½êýŸ±}~𱄀! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ Ds­5ÍÜ{W Iõþ½@! B@€B@ „€! „€@@! B@„€! „€! B@€B@ „€! „€@@ñ'NûI\ñÍ€¦|€qC_B@ „€! B@€B@„€! „€@@! B@YB@€B@ „€! B@! B@¾ò0Œg Ð\IEND®B`‚simutrans-124.3/themes.src/highcontrast/posbutton.png000066400000000000000000000006231474050137200230670ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆtEXtSoftwareAdobe ImageReadyqÉe<5IDATxÚìÙ½ ‚@€a¡p Ga ã4&àê¶làRR8 6*&þå¾ø¼GÉ“»²]Û¤WË{ÆÆÁŸm¸ÏBßÿv³ hQ–¡ -çyhCÓ¢a(ë–°NIs²Ò<Ó$?ÓFíõx{Aw>ñ™f2›]·tçC.aÖ2kÙg1Äл€bè]@Mp@‰ï„ž–æN(§‡ž¯¢‡ž¾×ø»‹²¬ë:®žå<_¯Ú¸z¦EQUUâzú ._†BïšCÏ=ç/C‰ßdæ_˜~ô&$€’@H $€@HH $$€@@H $€@HH $$€@@Hé?: 0…T³ùÏ6IEND®B`‚simutrans-124.3/themes.src/highcontrast/roundbutton.png000066400000000000000000000017331474050137200234200ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe<}IDATxÚìØÑ ‚@EÑ¥ù°%Ë '(Ã’Ôš0cø±8§‚^ö&Dfn­°[kÕÏ_ýt4F”ûÇýóX3Tsñ 000   @À@À@À000    @À@À@À0000   @À@À@À@À000   @À@À@À000    €Î†ï;®÷¬û8õ ÙOGcÔÞÏçe?îŸýbÍlP_ˆ€€€€€€€€ ` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€@oÃsYÓT÷pþê²ŸŽÆˆÒã™çÙ~Ü?»Åš)ã”ã"€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ `ÐÛà@]·ˆÒçß2}D ÎH83¿000   @À@À@À000    @À@À@À0000   @À@À@À@À000   @À@À@À000    €Þ~ 4´D^*!ynIEND®B`‚simutrans-124.3/themes.src/highcontrast/scrollbar.png000066400000000000000000000061611474050137200230200ustar00rootroot00000000000000‰PNG  IHDRJòY0tEXtSoftwareAdobe ImageReadyqÉe< IDATxÚìÜ]hTgð3‹¤4ˆ`#!ŠÕAñ¿nl“•ô€J[QÚB[W¡jnZ…]Rh¡¥e´½© ÈÆZØÛ´E½¨tMÛ›XÅ”€­ &m@ÅZofß™“¤£ÖínÎÛü~Äá™sŽðœ™wÎÿÌ;g&—Ïç“Ñ“dKÍn¯ýëR#¿\.wŸ[?hZüè_ÿú·†Ð<à?ùä“7Fº{ õÉž¿'o¾ëÓ3yòäæææ¥K—f¿Õ0HÂP &Ò‡: ’0T€‰T$a¨„ã ÆýqÇ¥uuu6lX¼xñĉÃÝk׮ŵW“&%Íë’¦Éãî^»Ù³R]]½`Á‚3fTUU…»7oÞÌ~ÏãÇ_Rôý÷ß8p`óæÍ=æãÆ%‹þ~ø!9|$ù`kráBLcfôèÑ³Š®\¹rêÔ©#GŽôöö:ÀñŽû«W¯^ßÒòHœ;ŽûË_N^{5Ö'#÷V®]ÛóÝwñ©pÒ°®¨§§g÷îÝ;wîŒ+ ÂIê?þÂñsïGÉž#K‚pÒÐXTS[»{Û¶cÇŽIî&—ÏçÓ‘Z[[—-[VYYYZwùòå“'O>|xÓ¦Mé’°q¯‚HûßúAòÌÓÉ£¬ºòcrætòÅÑä½÷“ì÷¿jÕª9sæTTT”V]¿~½««ëìÙ³‡Ê~ÿAKKKSSÓÌ™3ÇŒSÚàÆû÷ï_±bEöû§O5&Ó¦'U lðÓOÉgŸ'ëš#xü.\8uêÔðVläÈ‘¥ nݺuüøñ]»ve³²§OŸž6mZ(Â[ø/¿ü²­­mß¾}e[gùÐþ¯dʔ’ðþ«¯“ƒ“O?K"êÿ­·Þ;vl!·®\ §Ìß~ûmGGGDýöÜsÏ-Y²dþüùéâ™3g¦OŸQÿÏ>S˜ zò‰þ)Äsç’ú?ÆôøÏ;wöìÙá }:…ØÝÝF—àv®¦>盵µµ•••‹–/_~ûP–8™L˜P˜ gmáï…çï0”e/^ çkUEóæÍ»} (ãî6tû[™lºÛPZQ¸ÛPZŽtÜÑÀPòŸW®\YSó‹/îÙ³'Š9ÜôCà—^Lª«±Í?þÇnú!p}}ý¨Q£oóÍ7ßdv·Ôkkk8i¼êç$Ù²iÓà3þR8i(NœñÏÂIÃàUW¯^mooü!°) îú /Ô׋Ê.Ex¡¾óná¯ì2ÐX„êÇEe—Æ%ÒË@K"½ ´Äe ·ÎçóÜýë_ÿñöÏ20Œß”imm;wn(:::V¬XÝ.mý ™5³Pœ8™¬kŽï)YµjÕ„ BqñâÅ]»vÅÒöÆÇŠÁc&Œ¥pÛÕÕõúë¯g¼ÿ7ßHÆ+ƒÇLKÁ¥KÉ;ïfýñ_ºtéèÑ£C1xÌ„±nûúú>þøc;îuuuË–-«¬¬ ummíÛo¿ÝÙÙÑþLš”<ótò装:Eÿú·äÂ…˜žêêê9sæTTT„ºªª*Üííí¢ó©S§.Y²$§OŸÞ´iS(ZZZ–/_ж¶¶ì÷?er²hQ¡8w.yïýBñÚ«É ÏŠƒ#xüÇŽ;kÖ¬b\]:tèP(.\8o޼™ЉŽtÜQùÐêÕ«Ó£Šp7®ýYþrÿÑ?E¸—†††ôè„"Ü¥ó-[¶¤ESSSYQZ•é7ŽÛú‹§ˋҪ,;räH)‰ËŠÒ*¸G¬oi ·ß…båÊ•qíO8k ~ø¡ð¼ôbdÏÇʵkÃí•¢PÔ××ÇÒùÑ£GÓ13sæÌtIZ„…aUöû?ÖÞ?f¦Mï_’aaX•}çÏŸOÇL:W*°ʑŽ{@]]Ý#ÅâË¢PÔÔÔ„…±ì̤IýÅW_þŠ3* ³¯ºººç»ïBÑYŠQ£F……±ôàÀp;f̘çŠBQZ…ÃÅåªÇ’gŸ)ü…¢´0 §N ·#GŽœ[ŠÒB¸wlذ!-ÚŠÊf_óºþâàÁyÛÒÂì[°`AZ|[T¶0û6oÞœKŠÊfß[û‹E‹ú?¼0ûJS=³‹ÊÂí~ñ!ðâÅ‹ÃíåË—÷íÛ—á$.]…¦â¡òÊɧŸõá$®)šãg2cÆŒp{ýúõŽŽŽ´'qéÂ(„w-?'Ix9þütIOOOD”®xò‰þ¢·7¦‹z{{kjkÛÈÒ»ö«W¯ÆrCü ±±qâĉ¡8yòdº$-°*û{ÒPŸ<þx¡8sºIZ„… 1L¤Ož<¹ªª*)^4™.I‹°0¬ŠeðE¸¾D’gŽ?^ú"¡ù~].ŸÏ?Ðo‰dðǰô¯ýGÚ?CËo S#’ø#Pÿú×?<„\·Ñ0,™€@ €@ €@€@ €@ €@ †½5øz2¶¿ƒþs¹Ü}nœÏç³Öÿ§;v<ÐöϾòŠþÛþ׬YsŸoß¾=kýÍ娾Ÿ—@ºYw>ï¨ý[@Oä;Ðã9RY;  ·þá¿a @ €@ €@  €@ €@ €€@ €@ þ—þ-ÀY,U˜“„¡IEND®B`‚simutrans-124.3/themes.src/highcontrast/theme.dat000066400000000000000000000120011474050137200221110ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=- Image[7]=> scrollbar.1.6 Image[8]=- # scrollbar knob left center right Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # back up and down Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.2 Image[14]=> scrollbar.2.1 # knob up and down Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.5 Image[17]=> scrollbar.2.4 # scrollbar back up center down Image[18]=- Image[19]=> scrollbar.3.6 Image[20]=- # scrollbar knob up center down Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- --simutrans-124.3/themes.src/modern/000077500000000000000000000000001474050137200171125ustar00rootroot00000000000000simutrans-124.3/themes.src/modern/back.png000066400000000000000000000415271474050137200205310ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜl pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡;ËiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T15:56:11-03:00 2018-05-20T15:56:11-03:00 image/png 3 * wsRGB xmp.iid:289933eb-34d7-7046-b4c2-bd44cb633cbd xmp.did:44001ed7-4aa3-1c4b-acc4-13a698be1c5a xmp.did:44001ed7-4aa3-1c4b-acc4-13a698be1c5a created xmp.iid:44001ed7-4aa3-1c4b-acc4-13a698be1c5a 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:c75c4423-b803-3044-952d-751cc1e76333 2014-04-03T22:11-03:00 Adobe Photoshop CC (Windows) / saved xmp.iid:289933eb-34d7-7046-b4c2-bd44cb633cbd 2018-05-20T15:56:11-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 192 ê¬c cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:DIDATxÚìׯJƒQÇáïd V1z»«`Ù%˜ ‹®Ø¼›e+‚ÉKXD0,"¢†ÉŠ¢S”cP¼ˆç‰o;¿÷|ÞsÞF)%P«%#@ €@ €@ €@ €@ €@ €@ €@ €`Q4;½a9ØÙú°½¾Ú¨igÏïÅ6øuxzžA·]Õûwà €@ €@ €@ €@ €@ €@  €@ '€¯y>>¿M¢r{൶u7›Ë+GדÙþfk#I2+¥ªܽÌíþ$WOIr\ã¨q3ÉhJŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡<—iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T15:38:06-03:00 2018-05-20T15:38:06-03:00 image/png 3 * wsRGB xmp.did:a0d628f0-9eb0-dc4a-9a99-79196e93bd0d xmp.iid:30960daa-b92a-9546-b4c8-9b380812ce57 xmp.did:a0d628f0-9eb0-dc4a-9a99-79196e93bd0d xmp.did:a0d628f0-9eb0-dc4a-9a99-79196e93bd0d created xmp.iid:a0d628f0-9eb0-dc4a-9a99-79196e93bd0d 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:b3be8c66-9192-3940-ae87-1d0cac43c5d8 2014-04-03T23:51:10-03:00 Adobe Photoshop CC (Windows) / saved xmp.iid:30960daa-b92a-9546-b4c8-9b380812ce57 2018-05-20T15:38:06-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 576 256  s cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:IDATxÚìÛ?oTÙÆá÷Ž--ñì°cl­V HˆhH+¥ _Á•Ó„KKAoaŠ4ä¤Ú23BBrá–jiÂW [i%@hÈx-f|ñ`”xn À :þDçyš»±Ï¹gæüîñ¸úîÿL’“I–“œ]­æòžœ\Ïj½ð?_FIÖ’ Wë…[)̹Áõ6…;tô›ýçß/¯Jû_¯ÝÝ¿þ£õ;Y­Š‰FëwF³‡ª:S¯¾õѯÿ÷‹Ç?øõo'{ÙÚ¸;zŸûŸõÿé™Nr"Uusæ‹ù|Öí½×öfü¼½ñ|,íd2û|g{e÷ÉæÊ¹Áõc«õÂýR7ÿB7€@ÁÖžïŒ/èõ‹ž„ç;ÛIrÅr(K'ÉòÌó9Ðë绀bTNôú™98—¼8(Åp÷Éfž›´“Iqƒo'“<7Ù}ò8I†–CY¦“,½ï“ŸÿŸ}~0»O6Ï'¹dY…¸¶=µÛ÷Uòâ  Ãñæ/Ùm63™ì7øÉd/»Ífž>~˜$CË¡,ÓI–J<ùyÛïÎe¼ùëù$—,  ·Û¶=µýhcyûÑÆRiƒÿí矶òú#÷Jé'àUÛ¶Þ€¢ø/0@  €€@@  €€@€@@  €€@@  € €€@@  €€@@@  €€@@  €Þiz0$ÉÉ$ËIÎ&™ûØ¿T]×ìg ƒQ’µ$ú®o•¶ƒA[ú‹àèÑ£ûÏ«’Æ~íÚµý뿾¾žº®‹‰Ö××G‡>ÔétŠ^ÿ“É$£º®ç¬ÿ‚(ɉ$7ûý~ºÝn^½Jqäȑ٧OŸ®4M³2 ŽÕu}¿ÔͿРÀm%[ÛÙÙ¹ØëõŠž„$¹b9”¥“d¹ßï§×ë?IRUUz½^úý~òâ  æi2Ó¶å´m›ñxœ¦i’dh9”e:ÉR·Û-~"ºÝnš¦9Ÿä’e” ®ëÛƒÁàTÓ4ËMÓ,•6þlåõG î•6þÒOÀ««(›ÿ€@@  €€@@   €€@@  €€@@@  €€@@  € €€@@  €€@à¦_>þ'ÉÔËçUasо|Ü{c>J?e¯ãÇõ7þ¢tÞŠŸ’M%ù·i€2Hü¼6m €‚ì™sQrPîMŸ¿Ü@­j[Êâ@@  €€@@  € €€@@  €€@@ @  €€@@  €€@€@@  €€@@ €wú/ÿÿƒmëìIEND®B`‚simutrans-124.3/themes.src/modern/checkbutton-small.png000066400000000000000000000412241474050137200232420ustar00rootroot00000000000000‰PNG  IHDRÀ@Llxß pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡;ÒiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T16:23:20-03:00 2018-05-20T16:23:20-03:00 image/png 3 * wsRGB xmp.iid:4a5bfd30-1efd-8a4f-b8c1-917b2d770753 xmp.did:5b23a10f-64a9-8444-afec-90050295a64f xmp.did:5b23a10f-64a9-8444-afec-90050295a64f created xmp.iid:5b23a10f-64a9-8444-afec-90050295a64f 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:67b2a5ab-bf60-8644-95be-a6a903eb1140 2017-03-15T21:02:51-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:4a5bfd30-1efd-8a4f-b8c1-917b2d770753 2018-05-20T16:23:20-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 64 x—í cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:zIDATxÚìÙ1NA†áOCB« ‰ð¹‚µ­•¶[J@Il¤µ³¥Õ+ñ€dm·Â†Lb=û<ÉÐüüÙÙpr÷üv›d’¤J·U’ÙK}ýšÝÏß{=ÿ|>ÿ×üu]9ÿ Éäñf\]^œw~a½ùª¦‹åC’"7Àü™ŒF£j8v.¶m[5MSìü§IþøI²[»J¹z?ÿ¡ÃŸ$»µbç„_ÓÅ2ëÍ×ïÁ¼Û”ÂÚ‚?×ÎÏPºýwË‹3ÒÞö¸ó÷ó °:vß]o¾“ä£à=èýümÛ\Ü­;ÿ ÉlºXû#ä3ÉSÁ ÷ó7MÓÛùO¶Û­ç ^‚A €@ €@ €@ €@ €@ €@À ôÏÿÿ`¿“DOÒIEND®B`‚simutrans-124.3/themes.src/modern/checkbutton.png000066400000000000000000000421561474050137200221410ustar00rootroot00000000000000‰PNG  IHDRÀ@Llxß pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡<›iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T20:31:16-03:00 2018-05-20T20:31:16-03:00 image/png 3 * wsRGB xmp.did:a0d628f0-9eb0-dc4a-9a99-79196e93bd0d xmp.iid:298d6879-51e3-714a-ab83-a90f8ff0e09a xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c created xmp.iid:65acacb1-325c-6f4f-b675-de5fc347692c 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:89dcb680-cb9e-4d43-b08d-a765a5a1363e 2017-03-15T21:02:53-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:298d6879-51e3-714a-ab83-a90f8ff0e09a 2018-05-20T20:31:16-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 64 o€¿ cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:‹IDATxÚìÚ¿ka€ñ'GJ¤GðRt)b¤+Y….Z¡8»t²Ð Í¿ÅÅt)tèÖÅU)\ ®¥X[\*ÒIêAšB¨äZÁhšÝîò|Ö»wø^Þç%$—[zûà°¼&èí'°¬_Ö«ÏI³åú‡‘ž¿^¯_{þjµšêÙó@9û ³ÓÌ–' c=4[祃ãÚæÎaíW»}8JùæéùëõzØ¢ˆ0 ‚ çýI’”NOOkq×€ÔÏ+ ³ÓÌW¦ú~øaaŒùÊ/ßçòÔH»‘Ÿ?Š"ŠÅbßÍËå(‹DQ”‰ù`q¶<9ôÂ'ï¼ÎÀùùÃ0zÑåšÔÏŸ&9ùº„|_LƒŽùw¿ý`}{ø¬ÕqS4^`ùÙ#*woenþANþÿN΋5©Ÿ?@ºm~€ø¬Åúöž(c  ËF¿Î5€d’HNÑxáÊk7{\“dÂòÜL×^ oðjnÆ”1yà¤Ù:ú¿€fëà$Ï cþÊÔmÞ,=©ùÛíöÐÿ´ÛíLÌ;ÇC/üøù;ÀZ6ÀÈÏßl6‡^t¹f- ¬nî²µ{ôçTë{òmíñîÓW¸x#0íF~þ8Ži4$IÒ÷æ$Ih4Äqœ‰ùsÿ¼½”ú¬ÉòëÐ#9ÿ_¯C=Ú_‡Î R½”Uþ $ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @2É$ @ºÂoÿÿF=ã±së?IEND®B`‚simutrans-124.3/themes.src/modern/divider.png000066400000000000000000000406141474050137200212530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡;ÑiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T16:02:24-03:00 2018-05-20T16:02:24-03:00 image/png 3 * wsRGB xmp.iid:4e131d24-6645-074e-a50a-9fecd7612153 xmp.did:a171d045-6984-e64c-ba8b-157f6178a32b xmp.did:a171d045-6984-e64c-ba8b-157f6178a32b created xmp.iid:a171d045-6984-e64c-ba8b-157f6178a32b 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:18fb08cc-21d4-5340-8f6a-c1be75d0763b 2017-03-15T21:02:50-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:4e131d24-6645-074e-a50a-9fecd7612153 2018-05-20T16:02:24-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 64 64 WÐ8 cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:sIDATxÚìÐ ± ÿ ª°‚áƒï9¸ö>w*¸ž‰þ¯UáÀ=ÿÿ'çµÂ`\nIEND®B`‚simutrans-124.3/themes.src/modern/editfield.png000066400000000000000000000414721474050137200215610ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜl pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡;ØiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T17:11:53-03:00 2018-05-20T17:11:53-03:00 image/png 3 * wsRGB xmp.iid:99a63b93-2601-cb48-86db-02ef834f38d3 xmp.did:c215b240-9b8f-7044-a264-acd98be88211 xmp.did:c215b240-9b8f-7044-a264-acd98be88211 created xmp.iid:c215b240-9b8f-7044-a264-acd98be88211 2014-01-31T17:15:40-02:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:1c1ac3b5-241f-7f47-8433-56119550371a 2018-05-20T17:08:18-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:99a63b93-2601-cb48-86db-02ef834f38d3 2018-05-20T17:11:53-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 192 ‹eÁ… cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:IDATxÚì×±QÃ@†Ñߌk"2±bR"Z%P€;@•‘:E1&q .À!t°$Tá}oæ ÐÞ}§¹ÍëûçK’ý2 Oihœ×Joç$Çe>:~ü6Éþíùq×u÷—ih}ú¯·ŸÝátI’–lªº_€tö`€@ €@ €@ €@ €@ €@ @ €@p‡ŒóZIªñ ªûú?þÐͦªLo€@ €@ €@ €@ €@ €@ 0€@ €; `œ×¯ëí§Ï :¯ëí·Æy=wÝüm’ãátÉ2 -0Îk÷Kð;ɱëÇoª*à €@ €@ €@ €@ €@ €@ @ €@ Ü?ÿÿ£·¤¼snIEND®B`‚simutrans-124.3/themes.src/modern/gadget.png000066400000000000000000000421021474050137200210520ustar00rootroot00000000000000‰PNG  IHDR@@òÈ pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡;×iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T20:36:45-03:00 2018-05-20T20:36:45-03:00 image/png 3 * wsRGB xmp.iid:c252be1d-21d9-3e45-91bb-0e4b19085a83 xmp.did:5d2c9fca-00dd-1f41-a15e-af5d6a447761 xmp.did:5d2c9fca-00dd-1f41-a15e-af5d6a447761 created xmp.iid:5d2c9fca-00dd-1f41-a15e-af5d6a447761 2014-01-31T17:15:40-02:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:518b804b-2044-c54c-b614-5c099de1caf6 2018-05-20T15:25:04-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:c252be1d-21d9-3e45-91bb-0e4b19085a83 2018-05-20T20:36:45-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 576 64 >ל, cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:#IDATxÚìݱqÛ0†QR§äiX¨Òn5[ÍáÊ…¶ÑHø¤¤ÿ{w¹ø7$Að,Es)e€TŸ_ßÏ~¤LÓ4ß®'k §¶ãçv½ÌNƒŠ0ÏsYÿqV€´¹ïãã#}.,·ëeþüúö ÐÑ)ø¸ÿÜ»ß/¥XއÄëž<ÞëC¾wü{ÿ6ŠÞüW-ç%2~þþwüžˆAÇûñÕ áÆ_ÇÏr^~'ƒûÏ]…ÆpÚuO=îu¬¿ž—‘# ”2o-—ó2‡uü”išæ„{¿Á£>ÿ{P'€Þ÷Fõfßš RÊ¿7A&E@2tÿç~H½y/=~v€Úk¾ŽüQŸÿÇW&€´?éAÿîC?á(~2#¨ÿÆAœ­øz¨·»ÙÆPýþhóÁ¡½“² (¥Ìõ×Eœpì{Ûû ç@ü<ß ñšomý÷œN§¸…ÐècàYüŒü.°6~êüÞ^ÿúu}>Œ4¯>ö@ãâçY¥]‚–üÍ¢ç•×÷<ÈÀà´?Þ6¦ã»+€”­ðÄøiÉh(3~ÛßöØ×+á„ëd/z~ýÕÎyuì·oªã¡·S4\y'íMÑ>RPüdÞïëcO[ïzu ¤ÇÏÞ¢wëõ@#…yýQ½•ân@ò‹¡Éy8î÷îý¤y¡Ý 8€^þÙ„ÁØz-\¡áßß[ù§í$¾íŸíUQêXê¸ß;î¤s’>Òâ§ßÑÿbï`Ýx:n6îÿQÌ> ~ãÄø €Qø4x@  €€@@  €€@€@@  €€@@  € €€@@  €€@@@ŒêÿÿÖ<ÃñXIEND®B`‚simutrans-124.3/themes.src/modern/listbox.png000066400000000000000000000411111474050137200213020ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜl pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡:çiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T17:12:07-03:00 2018-05-20T17:12:07-03:00 image/png 3 * wsRGB xmp.did:c215b240-9b8f-7044-a264-acd98be88211 xmp.iid:91ec5a08-e1bd-ea4b-81ac-9c2430b68007 xmp.did:2cfaaaa4-9d95-d248-94af-63f562d61bec xmp.did:2cfaaaa4-9d95-d248-94af-63f562d61bec created xmp.iid:2cfaaaa4-9d95-d248-94af-63f562d61bec 2014-01-31T17:15:40-02:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:91ec5a08-e1bd-ea4b-81ac-9c2430b68007 2018-05-20T17:12:07-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 192 ~Š¬Ö cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:IDATxÚì×±QÃ@†Ñߌk"2±bR"Z%P€;@•‘:E1&q .À!t°$Tá}oæ ÐÞ}§¹ÍëûçK’ý2 Oihœ×Joç$Çe>:~ü6Éþíùq×u÷—ih}ú¯·ŸÝátI’–lªº_€tö`€@ €@ €@ €@ €@ €@ @ €@p‡ŒóZIªñ ªûú?þÐͦªLo€@ €@ €@ €@ €@ €@ 0€@ €; `œ×¯ëí§Ï :¯ëí·Æy=wÝüm’ãátÉ2 -0Îk÷Kð;ɱëÇoª*à €@ €@ €@ €@ €@ €@ @ €@ Ü?ÿÿ£·¤¼snIEND®B`‚simutrans-124.3/themes.src/modern/posbutton-small.png000066400000000000000000000427511474050137200227740ustar00rootroot00000000000000‰PNG  IHDRÀ@Llxß pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡=ÝiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T19:19:58-03:00 2018-05-20T19:19:58-03:00 image/png 3 * wsRGB adobe:docid:photoshop:d11ea01d-5c7b-11e8-83d5-8b2a77c378fe xmp.did:5b23a10f-64a9-8444-afec-90050295a64f xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 xmp.iid:722741ec-42e5-0b42-ae10-ed9c1595e4cf xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 created xmp.iid:906000d6-0fcb-7d4a-92fd-6321c11bbc13 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:32aa376c-7741-674f-a8e8-907fa9bac528 2017-03-15T21:02:43-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:722741ec-42e5-0b42-ae10-ed9c1595e4cf 2018-05-20T19:19:58-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 64 h#´ cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:ÄIDATxÚìÙ=La‡ñÿµXH+`-Š0øLi`qp$°¹2©c'B‚ƒ‰+$»7'˜Œ.°™ˆ`tˆ JRLj[Ûãh#¥@œß÷ù}oy?ž»këOËÅüdnóǹ„<ÿ™êïüVî¿ãûVÕ…å, € € € € € € € € € € € € €@€½þÿÿú¦¾ÂùÑY§IEND®B`‚simutrans-124.3/themes.src/modern/posbutton.png000066400000000000000000000434111474050137200216600ustar00rootroot00000000000000‰PNG  IHDRÀ@Llxß pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡=ÏiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T19:38-03:00 2018-05-20T19:38-03:00 image/png 3 * wsRGB adobe:docid:photoshop:d11ea01d-5c7b-11e8-83d5-8b2a77c378fe xmp.did:5b23a10f-64a9-8444-afec-90050295a64f xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 xmp.iid:6068431f-fd8d-404e-ac81-da485fcbe2c6 xmp.did:d5d7b47a-7cd9-6c4d-b4e6-cf0493e304ec xmp.did:d5d7b47a-7cd9-6c4d-b4e6-cf0493e304ec created xmp.iid:d5d7b47a-7cd9-6c4d-b4e6-cf0493e304ec 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:2b5f03b0-5d94-1649-960f-dbf3c8c8cf70 2014-04-03T23:08:59-03:00 Adobe Photoshop CC (Windows) / saved xmp.iid:6068431f-fd8d-404e-ac81-da485fcbe2c6 2018-05-20T19:38-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 64 ÈâV¹ cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:òIDATxÚìÚ±oeÆñçÞ8±ñÝùÜ0hG‘Ú‰HÉЂTu!C3T,‘èÐ!ü °á Tê1Љ •¨R%rÔ¥-åR’“*1$µ{=_zŽÉû²4ˆT!wóû>ŸÑÊ;üœ÷ûÞÙgK)…KåÅQ³fÁÁæÌ]+÷Ñå>ZøõÕß^hþþÂIÿ³©7»zþ……¬®®¾Ðü…BÁŸššêêù­¾ø¾˜¿81‚‰âìtï ¢V•å5\¯<ÀßR_+¯vóp©¼X„eùYoi;Kˆÿ^I‰Vô[Á& T×Ï_.—‹–eùžçÁ¶mˆ„ù¥”ˆ¢A@)5\*•ºz~`öâÄÎ>–¸ùÀN÷âÜéc¸0~ÏNn7›õqó‰›,!qóÈæ^Öf~Ïóàºnâæ!\×E.—Ób~`f¢8ÔñÂ3c¯Àe 6ÀLÚv;^”vrÚÌoÛvÇ‹ÇÑb~ ÿù“ÿóï~ÆZ£™x%ЯÁè·DÏž.¿ŠWܾ„+A6ó?òoll Ýn'^ t˜?µß‹wW6ñËÃG8;VÀôø‰CÝédôh#ƒ/a©â†_ÇÓ¶4jþ8ŽQ«Õà8<Ï;Ô­Q7_þçέ{+øä«ŸpëÞ ¤TFmaY˜ÎáÊ»Lç , ¦i6›X__G³Ù4/€ß„xó?þŠO¿®àîʦq›ÀîëÁô©||æ5ŒÍ7¿”FµZ q›‘ÎRIM§0=~ïŒ „y·OÛ7ü:–ª!¤RÆÍ/„€çy»ßú˜€ÎŽpáíãp2}æ]ú•ÂR5ÄârÑöŽ‘§£ ‚÷ àÔx²ˆ¡#Ž‘ÿxÿ¯-|{¿Ž?Ãm#çÏd2ÈçóèíÕÿÛ¿€zÔjïyðá{o%.ŒZm¨kðÔ•ÜÙó,àËÛµÄEJîh3¿”rϳ€ÁÁÁC}8Öa~`¾²¼ÖñÂî?€«l€ùVv¼¨=Ñfþ(Š:^ôlÍU˜»^y€›wª»§zâÉóNßÜþæ4Øs[Á&âð1”L~।D>ÆVðH›ùƒ @†»§zâɆ!‚ Ðb~‹?‡æÏ¡þ9´2ð«=¢ÿÞ1"@Ĉ bD €ˆ1"@Ĉ bD €ˆ1"@Ĉ bD €ˆ1"@Ĉ bD €ˆ1"@Ĉ bD €ˆ1"@Ĉ bDûøgŠÚR™¡gžµIEND®B`‚simutrans-124.3/themes.src/modern/scrollbar-small.png000066400000000000000000000543461474050137200227250ustar00rootroot00000000000000‰PNG  IHDRÀ$Í¦Ç pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡E iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T19:19:17-03:00 2018-05-20T19:19:17-03:00 image/png 3 * wsRGB xmp.did:5b23a10f-64a9-8444-afec-90050295a64f xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 xmp.iid:51712e0b-289a-9a4a-bf72-296a67ebec46 adobe:docid:photoshop:d11ea01d-5c7b-11e8-83d5-8b2a77c378fe xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 created xmp.iid:923e78b0-ad70-bf40-8908-229684da8ad1 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:cfe2683b-4399-be4f-9e8b-8143cff4272c 2017-03-15T21:02:39-03:00 Adobe Photoshop CC 2017 (Windows) / derived converted from image/png to application/vnd.adobe.photoshop saved xmp.iid:f8cc9e9a-3887-0e44-9f99-28746f8b8ce3 2018-05-20T19:19:09-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:c6c71cf0-3aa3-4846-bea3-0604440224ca 2018-05-20T19:19:17-03:00 Adobe Photoshop CC 2017 (Windows) / converted from application/vnd.adobe.photoshop to image/png derived converted from application/vnd.adobe.photoshop to image/png saved xmp.iid:51712e0b-289a-9a4a-bf72-296a67ebec46 2018-05-20T19:19:17-03:00 Adobe Photoshop CC 2017 (Windows) / xmp.iid:c6c71cf0-3aa3-4846-bea3-0604440224ca xmp.did:f8cc9e9a-3887-0e44-9f99-28746f8b8ce3 xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 1 720000/10000 720000/10000 2 65535 448 256 p2½: cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó: þIDATxÚìÝÏoœõÀñÏŒÇøWí8¶cÀ°K! °‚&.T +U !‹\ VJ©.ÝC,T¢¬àÀÀ!‘"*µÎa7ëRôÕJ¡V¥ • ”$mµü‚qgbïØžØãÙCÆNì4Z-‡}¾¯×Åy9>þê¿ã¹G:kÛ*Iü«V­Š–––(‹É ­]ÛžÜÝ«š“ÚïùJ%òuuñÉ…©xçø¥¸Tš]rn¤tØÞÞ…B!HC>"Žœ>yÉÿì^Õ;·nŽˆˆÓç‹gx FJã£KBw©4û?ú¦ökà"®}*«Ž”Ëå¥WE…BtuuEDDm[–ÿǵ[7߿ڹq$Ûó!æ+s±ÿ£onˆ_%Jã£YŸÿæ¿««ë¦øÕ¶eùø'¸·ö=§•~Õ÷hD¼‘á5xev¦´§8òù­¾üj†÷oí{N©ÿ7^ûÃ]±y¥ „ˆØ›áýuv¦´»8rö–_„Ïòñ¯ÍªÇ?i¹”ñ€tå-€€€€€€€€€€€€€€€€€€€€ € € € € € € € € € € € € €ð](DDôoŒˆñÓ¡¾Î” px<"ÞŒˆ}C}'R€þÁájÊ'ÀÐ@_Îü›ÿT½úO?J:€¹Ÿýæ÷ ùü‰¶¬-z¢¥¡>—Ò”ʳÕÃ'Gâ­Ã§bn~~íÐ@߉Í@ÒoýƒÃ#—;Ѽª+ZZcïLjþwýîLµ\šˆ©+cÕjróÿ/ÿñyÒóÿ‹-=I0;^ز>žyô¾hi¨OnZêã™Gï‹ç¸.jw¤eGóª®hlm\¾.½+à|>[Û£¹­Óü“d·oÙГüBüèá{#"þÙH$g{CKkò‹Ðð½6óO’ìHñÎo¹;Áˆè0ÉéHñÎïæ;Á:óO’€$8^*Ï&¿µ57ɯÎW’_„Ú˜’ à›‡OŽ$¿ÿùÉWÿf$’óf¹4™ü"”KæŸ$¸ï­Ã§âý"R¼,•gãý"ÞþðLDÄ>#‘œ}SWÆbf²Õùùïüæcf²SW.™’Sè;Ù?8üÐ÷Oì8ðþ‰íC}I-ÀKû]Žë_>—Úô'},ÌÿTñ⎩âÅíë’ÚÿË_–ôüy:ñ¤ý €\µZ Hß@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@¾…þÁám±+"zWxÍ‘ˆØ;4Ðw ‹ PÛÿ=ѳÂKF"╬îÿàààmÿ¬ÿŸDÄΈøÁ /ùSD¼‘áùÿIDì¾Åü¯fxþoëøguþ“`Dìzíù'z¼{õ²/8}þrïëo´+"²:{êZ:º#_WX²a¾2¥ñÑžÙ™Òž ïÿ®îîîÞ†††e7–ËåÞÑÑÑ,ÿ]¯=ÿÃÍÞݾÒü?žñùß}mþïŒ|]ÝróOó¿ùóÿxÆç?iùˆX¿?Ÿ»9wqñçÚ¶Þ ¯Aíä¿¿Gîlއïl¾¶8u…héèŽ[\gÁ’øMOOÇôôôâϵmY>þ+Æ/ùï¾)~ ÍÿŠñKdþ“¿\tu®Þÿ4r¹\q×â…ß‚ã¦âß?ú&‰ã?66¶äÂ/"¢©©)ºººT"ãw€‹;'¦côÊT¼{ì\r‹ñôºöèl®Î–úxêöäöbb"æææbnn.&''“Ú÷mOn\rÁwG¡.¶ýãCÉìÿ;Ç/Ål¥ºøól¥¿û¯KÉì{{û’ ¾\.ííé½$À£·ÃTܽ…¦âÆè-Ä0Ý«šãÙMkÞºéþXÓÖ”Ìþ_*ÍÆ{Ÿ>t¦—¦f“ÙÿB¡­­­‹?·µµE¡ÎÓŸäxàƒqu®²¸aáqh*ž{¤3êë®_.>MD±XŒjõúÀ·‡¦b!z7Æ0 Ñ»1†©XˆÞ1$Ã> Ø™Àg+™¯ÌÅþ>똯¤q䳎ë=sµ?§3ÿ•È×Õ->ö¬F,>Meþ#–>öLéóïÔïž>¿òÕÞéó—#®},«FJã£1_©,¿ÒøhĵïfÕÑr¹¼âÆÚ¶,ÿ#µˆk¿øòØÚ5‰Íÿ…Åп0Ÿ\˜Jiþ|{þ›šš¢©©)¥ùOþpïëo¸3þÆA3¼¯ÎΔvG>¿å3¼ÿ{GGGS>þ{kßó»å_áýev¦´§8rö–DÆç?å㟴ܷ?÷€Tø»@@@@@@@@@@@@@@@@@@@@€ïD!"¢pxCD숈íÑQÛ6oFľ¡¾“Y]€þÁáñ_¿øôê–†úe·—ʳñÒþC—‡ú:2ºÿÕ¡¾¿õšèËex’žÿÕ÷<°:—_þZ¸:?—¿þ,³óÿÒþCÕ;ºþ>VÞÿJ\û2~ýâÓ™œÿO/ÍToçuu6frÿ ýƒÃ ùü§/lY[6ôÄBJåÙŽÃ'G^~ëð©—û‡è;‘Ñ÷€7Ÿùå3Þ·ìÆÃ'G¢öFH6°1r¹O›WuECKkäòu o|åÒäËSWÆ2?ÿåÒÄ/[Û—ÝX.MdzþKåÙhȯü ,—¯‹RyÖ‰’QùˆØñ–õñÌ£÷Å·ï‚Zêã™Gï‹¶¬ÚÕqVí{ëð©8xìì’A/•gãà±³ñÖáSûŒJfíh^Õ­í‹ñ[xãklmæU]™Ÿÿ©+c13y9ªó•%w>3—cêʘù'³ ±}ˆž_°eCOxÿÄO#âå,.ÀÐ@߉þÁáûûÇS;~ûÇS¿ˆ¥Àþ5®=û¨dÖö†–¶76´´ÆTñbæçª8¶cª8fþIJ®Z­Z…„ù Ôç¿ãï¼åkÆ¿<ÙùOý3@¿ @’€ÿKKð¿“Ëýÿÿç±ü[€;@pˆ»'w€ € € € € € € € € € € € € € € € € €                    ™ó?¨:—4©eÉIEND®B`‚simutrans-124.3/themes.src/modern/scrollbar.png000066400000000000000000000522541474050137200216130ustar00rootroot00000000000000‰PNG  IHDRÀ$Í¦Ç pHYs  šœ¶iCCPPhotoshop ICC profilexÚí•klSeÆŸsº­]WÆu\/ÛœÛÜÜ`æD`-® +–v²‹‚œžsZ_<í{<ç¬íÊE! ⢂™"*JtAÐ *!â !‰\‚8† "÷KÔ`æ‡Â DüÄÇ=Ÿ<ÿ÷ùçŸ_òÖÅ 3ž¡°¡y]RWß@ÌGaƒ<²1XuÕí«ªÁ-uy?8Ø[ôÿ¹ÿ”Õ_ãu‰ÀÛüuõ WÀ.ɺ$ïà—d=˜U€Ÿ¬ñ:SÀÛ‚ñ|»Vãu\5ÀÛ´¸ŸÀ5TÀvQÕ ÀZ`j]}‰¯p¡.cûu5åÛ“qÝcÀ¦½@Æ‚ë^v: øl”بEâväa <Å´`¾ÃÏ äJ97G¹EÜn×Á'ñùüÞàWñßðgLƒLMQÓ{¦ ¶„Ê„XBk‰ĜD!±%ñ—$’$&­M:mežgÞaéo Z6%[“g$o´¦Xeë֔̔æ”ö±¶Õ½,½Ô^S«R7ôÎêýJš9mNÚ…>JŸÎt)½½¯Ø÷7ûöswÌÎHÌx©é·¾ÿ„þ¨“®äôëà™¹™;†èC3‡n'ÑayÃf½]•Ý•³ùÎXîèÜ¿îú2ïÙüê‚~wo,\XTOq±¥¸½dëð–óKå²É#KG m}¥üô½íîk³ëþcwŽûqü¾ÊCŽãÎópUé®Ü‰c&=ü :yiõGî=S.{2§º¼†ï횟¦%׎¯kªÿ¤áâ£eÓc3¶Ì4 ^ÿ›âYÙx-xŽVÏú@±†Bá6µâÉwôtcAã¥è¬Ø±ÙÓ›=õÈÓGæ‰óO>Y˜°hùâ¼ç¶,™öüù¥Ë– qßËÍËsVì~uîë%+¿±ªeÚ[}W·­YþnÃÚ¬÷O­ûüÃ%­­¹!uãïŸnß´nó²/¢[ü[újÜ×#¾Íû~Ø™;ï²;«­`ßÈýŽŸ}‡çYqôãö=;œ¨<©œZyfçy\,¿¬ýÙú÷ÙJ»šººzXèa¡‡…nf!þ§Ö:5Y0d‰ø›ˆ›ŠÓYÀ µN h,D&¸=D÷º$B5£QPˆ$G¨(““d…¨ PE.$ÎJ·§‚Ô:}×,`ÚµA9JÃA"²°D ÊÂz!Âq¹Ýž âÑ Ðp†Á‰*¨²V’%*‘)LÕpx´Â $0¨¡@"40è`ÀA-œð@‚ ‚ pà x CC ÈÕ—B` Cëž@¡Cƒ 0D@¡Á@#( Ðá… ‚À‰Ê[ô\ÛF… D0„!¢— Cïn–…8vS‡ ÜÝ=^Ȉ€B¿š-Š¡@€vµ5~­bˆ`к»B8 n“nàËR@¢º×åÀí–!Ç p2µI£ÁÇ ’'æ“%%e7pìdšÊ4Á ,LòÜL¢G½Rb~™øštCédRXÌ€qn7Ò‡hV¡>+iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2014-01-31T17:15:40-02:00 2018-05-20T20:16:32-03:00 2018-05-20T20:16:32-03:00 image/png 3 * wsRGB adobe:docid:photoshop:d11ea01d-5c7b-11e8-83d5-8b2a77c378fe xmp.did:5b23a10f-64a9-8444-afec-90050295a64f xmp.did:65acacb1-325c-6f4f-b675-de5fc347692c xmp.did:906000d6-0fcb-7d4a-92fd-6321c11bbc13 xmp.did:923e78b0-ad70-bf40-8908-229684da8ad1 xmp.did:d5d7b47a-7cd9-6c4d-b4e6-cf0493e304ec xmp.iid:bd5e8eed-dd30-9648-97be-4f5f7f4beb00 xmp.did:87137f23-3e56-d144-8af1-3b329113d129 xmp.did:87137f23-3e56-d144-8af1-3b329113d129 created xmp.iid:87137f23-3e56-d144-8af1-3b329113d129 2014-01-31T17:15:40-02:00 Adobe Photoshop CC (Windows) saved xmp.iid:70f3d5fe-181b-534c-8457-57afa53f610b 2017-03-15T21:02:41-03:00 Adobe Photoshop CC 2017 (Windows) / saved xmp.iid:bd5e8eed-dd30-9648-97be-4f5f7f4beb00 2018-05-20T20:16:32-03:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 448 256 Ê­ÅL cHRMz'€ƒúd€Òv†ìé9žþÆ~Ó:9IDATxÚìÝÍo\UžÆñçÞ¸âÂõærˆ<©8 qì¸'h"$,i §…,"Â(,2l,a Y¸Ôê‘@¢ÿ X ö"iyi„‚D4¬ÖÐ0š82ʨ3ã×@bL[;U®WªRøÞY¸ äÅ)—{3uÎ÷³óËYüNýn=çž:öu|ß×ÐÈx¤aIƒ’âz´´¤ó’FÇ’3jpo^úZ©ÅùmÕß–èšyûäÁ†®ÿÒ¥KZ\\ÜVý‰DbæäÉ“Þô?ýouÿÛÌyíÝO:›\÷ÖéþÃêïîP¨9ðÈ…rE³Kº01§=¯g,90Ûào~rœ[-±v5‡¢r\÷‘¿ï{žÊ…¬Š™É÷¾þ‘‘‘NÇqnÅb1…B!¹5ê÷&@àõoVôÞ•Ùš[@&¯~_îm«¹dòêwuuµæ5o‚¥»:ÿŸÓúë‹zõx·Žîk·ªþÐÎzåh»Žïêé”f¾/Z· ’N§•ÏçÕÚÚª`0ÈEaÒB)p(éè¾výjï.ýijQLΫXþѪ ™ù¾¨¹åôlgD/ö´é±€]k„`0¨={öX¿º¡¥¹I¯ôué×–mnø¡âéã™”•[ Òúa¶@- ÀõÝÑoþvŸúíÑÅ/¾²îŒçûºr+«ÿ^*h ;nå!˜p8¬––+Ál\Ï÷&tê™'Ú·îù¾®.ä4>›Váîš•oŽ‚±4j€àN þýýæhBï]™µnr w×ôÁõ]¹•Õ˽öxv]Wñx\ápX«««ÖÔ}t_»^=Þ­Ž¸«þ™ï‹úp*¥ïrw­¬? ªµµU@@0ü=NRªP~ô‡ŽxXo¼ôô½á°>&eÀ¤|ïÑ+Üïrwuvòö=ß«Ž1¢þZÛœ@@»wï¾÷a}Œõßßÿo¼ôtÍð3¹ÿÏNÞ®~&÷ÿîÝ»k†ŸAýo}žû|êÛºNÌ.Iëÿ¶Ñ+²u*rÆÔ_(ê¿;^cBý竽\—ê5s΄ú«½\gÿg©ÿ¯èê·>G/NÞÐÿ¼ Zw‚+ß?þyA&æ$iÔ€9-f[•¿…¾ç©”[]ÿgÀ†ÔŸÉd”Ëå¶tàÅó<år9e2cê¿01Wwÿ_œ¼aPÿ¯l£ÿïÐÿfÔo5‡Ç!ñ8‡DÿÓÿ<ÉÚÀ6œï€€€€€€€€€€€€€€€€€€€@@@@@@@К$ihd¼SÒ°¤3cÉ]6MÀÐÈøIç$Ž%nÙÖC#ã¾Í@[¢ËI-Îï¯öÿë–öÿYI£m‰®…·O¤ÿ-òÖ?=gu:¯½ûIO“ëNŸê;¤çz÷*Ôplš€B¹â>õ­.NÞОwd,90cYXý042~DŽ3ÝÛ¥æPTïüc—UýÿÆ¿Ïûå|VÅìÉ÷­ëÿ7/}muÿ¿Þßauº’†O÷Ö‰cjX7¡æ€N; Óý‡U½ €]†[bí FârÜö­€Ý Fãj‰µÓÿ°2û»;¬Ÿˆê ÒÖlE­Ÿ„êÐÿ°.ã6Þù=ìNPRœ–°NÜq9 VúÖ       €éB¹býDTç MKX'í{žõ“PúÖàù‰Ù%ë'¢:çi ëœ/²ÖOBuèX€£&ætùÚMÙx'X(WtùÚM]˜˜“¤QZÂ:£ÅÌŠJ¹´|oÍÂ;¿5•²i3+ô?¬Ó4–˜ßÿþÕ¹á÷¯ÎKX5¿ýç)Ùý8$«/€¶D×Ljqþ@que¸¸ºòºÔeUýé¿|Ò/‡dÛëŸZœ·<ìþ?ÐŽïûØgúNÉêú9                                       €€€€€€€ 4IÒÐÈx§¤aIg$µÕ“’tNÒèXràV£OÀ›—¾Vjq~[õ·%ºn½}ò`C×éÒ%-..n«þD"qëäÉ“  Œï¯Öÿúë?[íÿCú[õ·%º éÿmÕŸH$Lè›9¯½ûIO“ëNŸê;¤çz÷*Ôxä€B¹¢Ï§¾ÕÅÉúÑóŽŒ%füͯGŽ3ÝÝ¥æpTŽ»ã‘¿ï{k*²*fîH¾ßðõŒŒô8Ž3F‡åºÞðŸW¥RQ¥RQ>Ÿ·¦îWw?t±çºŽ^=Þm|ýN¥ºØó|_N¥Œ¯¿µµu[?ƒAX(Wtñ‹¯~úúƒÉyåKw­™”Ç®ºÞÝx±§M¡;¬©ßóÉö§A8¾¥p€íx                   €€€€€€€€€€€€€€€€€€€€€€€€€€€ü¿×$IC#ã’†%‘ÔVcLJÒ9I£cÉ[>C#ã©ý爇šu+”+úí>M%Ú¼~,9°Ý±K8\ÿ›—¾Vjq~µÿ_ßbÿŸ•4Ú–èZxûäÁ†ïÿøß<wÜúÖ¾ç)ý—¯Œèÿ¶D׶Ʀç¾ÿ%ùåø†®¿ihd¼§Éu§OõÒs½{U+ åJÛçSß¾uqòÆ[C#ãGÆ’3 Þç'f—~÷ÂSu š˜]’¤ó¬¡[jq¾GŽ3ÝÛ¥æPTŽ»£ÆÿZ[9Ÿý}1{ç÷©Åù#ÒÁ†ïÿr!û»`¤µ®AåB–þGÃs% Ÿî?¬Çh+wA¡æ€N; Óý‡U]57ºÑ sº|í¦ åÊ–îü._»© s’4J 5¼á–X»‚‘xÍð“$ÇÝ¡`4®–X»1ý_̬¨”KË÷Ö¶pç·¦R6­bf…þGÃk’4ØßÝQ÷ÀþîýÛÍ Jú—Fž€±äÀÌÐÈøþ÷¯Î ¿uκ-`h°9­{Ps(ªâêrÃ÷[¢k&µ8 ¸º2\\]©{ ˜öA#s|ßg,fûg€ ÿmþ púNÉêÏ9 °                                       €€€€€€€€€€€€€€€€€€àaþo¼jÙ)B{ÇIEND®B`‚simutrans-124.3/themes.src/modern/standard-large.dat000066400000000000000000000112511474050137200224740ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # # All image names must start with "> " to have them non zoomable # # This theme has the scalable standard look # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # normal Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # normal Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # normal Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # normal Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # normal/pressed/disabled left button Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 # normal/pressed/disabled right button Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # left/center/right scrollbar background Image[6]=- Image[7]=> scrollbar.1.6 Image[8]=- # left/center/right scrollbar knob Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # normal/pressed/disabled up button Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.1 Image[14]=> scrollbar.2.2 # normal/pressed/disabled down button Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.4 Image[17]=> scrollbar.2.5 # up/center/down scrollbar background Image[18]=- Image[19]=> scrollbar.3.6 Image[20]=- # up/center/down scrollbar knob Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # divider line Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/themes.src/modern/standard.dat000066400000000000000000000115051474050137200214060ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # # All image names must start with "> " to have them non zoomable # # This theme has the scalable standard look # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # normal Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # normal Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # normal Image[0]=> checkbutton-small.0.0 # pressed Image[1]=> checkbutton-small.0.1 # disabled Image[2]=> checkbutton-small.0.2 -- Obj=menu name=Posbutton # normal Image[0]=> posbutton-small.0.0 # pressed Image[1]=> posbutton-small.0.1 # disabled Image[2]=> posbutton-small.0.2 -- Obj=menu name=Scrollbar # normal/pressed/disabled left button Image[0]=> scrollbar-small.0.0 Image[1]=> scrollbar-small.0.1 Image[2]=> scrollbar-small.0.2 # normal/pressed/disabled right button Image[3]=> scrollbar-small.0.3 Image[4]=> scrollbar-small.0.4 Image[5]=> scrollbar-small.0.5 # left/center/right scrollbar background Image[6]=- Image[7]=> scrollbar-small.1.6 Image[8]=- # left/center/right scrollbar knob Image[9]=> scrollbar-small.1.0 Image[10]=> scrollbar-small.1.2 Image[11]=> scrollbar-small.1.1 # normal/pressed/disabled up button Image[12]=> scrollbar-small.2.0 Image[13]=> scrollbar-small.2.1 Image[14]=> scrollbar-small.2.2 # normal/pressed/disabled down button Image[15]=> scrollbar-small.2.3 Image[16]=> scrollbar-small.2.4 Image[17]=> scrollbar-small.2.5 # up/center/down scrollbar background Image[18]=- Image[19]=> scrollbar-small.3.6 Image[20]=- # up/center/down scrollbar knob Image[21]=> scrollbar-small.3.0 Image[22]=> scrollbar-small.3.2 Image[23]=> scrollbar-small.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # divider line Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/themes.src/modern/theme-large.tab000066400000000000000000000123551474050137200220020ustar00rootroot00000000000000# Simutrans default touch theme # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=Modern (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 #################################colour stuff################################# default_window_title_color = #D74700 # gui_color_text = #000000 gui_color_text_highlight = #005C9E gui_color_text_shadow = #BDD3DF gui_color_text_title = #338FCC gui_color_text_strong = #EC6E0C ########Test######## gui_color_empty = #868c86 gui_color_obsolete = #2878ff gui_color_edit_text = #000000 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #666666 gui_color_edit_background_selected = #72B2DD gui_color_edit_beam = #000000 gui_color_chart_background = #FAFAFA gui_color_chart_lines_zero = #005C9E gui_color_chart_lines_odd = #338FCC gui_color_chart_lines_even = #338FCC gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #72B2DD gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #666666 gui_color_button_text_selected = #FAFAFA gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #FAFAFA # gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #666666 gui_color_ticker_background = #D6ECF7 gui_color_ticker_divider = #6095B8 # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #72B2DD gui_color_statusbar_divider = #6095B8 gui_highlight_color = #8FC5E6 gui_shadow_color = #8FC5E6 # gui_color_text_minus = #C00000 # gui_color_text_plus = #000000 gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #ff0000 # Colo loadbar, save game, load game, server... gui_color_loadingbar_progress = #76b9e6 gui_color_loadingbar_inner = #D6ECF7 # Color player brigth gui_player_color_dark = 1 gui_player_color_bright = 3 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #D6ECF7 ##################################size stuff################################## # force main menu icon size icon_scaling = 150 # titlebar height gui_titlebar_height = 22 # width of the window elements gui_gadget_width = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 22 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 22 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=modern-large.pak simutrans-124.3/themes.src/modern/themes.tab000066400000000000000000000123171474050137200210730ustar00rootroot00000000000000# Simutrans default touch theme # # Read the wiki article for better explanation and full parameters list # https://wiki.simutrans.com/en_themeDef # # name of the theme (will be shown with file selector) name=Modern # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 # tooltip text color (240=black, 215=white) tooltip_text_color = 240 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 # windows drop a little shadow (default off) # gui_drop_shadows = 1 #################################window stuff################################# # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like Windows) # window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window # window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 1 bottom_window_bar_color = 3 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #C0C0C0 #################################colour stuff################################# default_window_title_color = #D74700 # gui_color_text = #000000 gui_color_text_highlight = #005C9E gui_color_text_shadow = #BDD3DF gui_color_text_title = #338FCC gui_color_text_strong = #E46A0B ########Test######## gui_color_empty = #868c86 gui_color_obsolete = #2878ff gui_color_edit_text = #000000 gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #666666 gui_color_edit_background_selected = #72B2DD gui_color_edit_beam = #000000 gui_color_chart_background = #FAFAFA gui_color_chart_lines_zero = #005C9E gui_color_chart_lines_odd = #338FCC gui_color_chart_lines_even = #338FCC gui_color_list_text_selected_focus = #FAFAFA gui_color_list_text_selected_nofocus = #FAFAFA gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #72B2DD gui_color_button_text = #FAFAFA gui_color_button_text_disabled = #666666 gui_color_button_text_selected = #FAFAFA gui_color_colored_button_text = #FAFAFA gui_color_colored_button_text_selected = #FAFAFA # gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #666666 gui_color_ticker_background = #D6ECF7 gui_color_ticker_divider = #6095B8 # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #72B2DD gui_color_statusbar_divider = #6095B8 gui_highlight_color = #8FC5E6 gui_shadow_color = #8FC5E6 # gui_color_text_minus = #C00000 # gui_color_text_plus = #000000 gui_color_text_unused = #E46A0B # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #ff0000 # Colo loadbar, save game, load game, server... gui_color_loadingbar_progress = #76b9e6 gui_color_loadingbar_inner = #D6ECF7 # Color player brigth gui_player_color_dark = 1 gui_player_color_bright = 3 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #D6ECF7 ##################################size stuff################################## # force main menu icon size icon_scaling = 100 # titlebar height gui_titlebar_height = 22 # safe margin around windows # gui_frame_left = 10 # gui_frame_top = 10 # gui_frame_right = 10 # gui_frame_bottom = 10 # horizontal and vertical margins between objects # gui_hspace = 4 # gui_vspace = 4 # tab minimum sizes gui_tab_header_vsize = 18 # input boxes height # minimum height is the height of the position button graphic # gui_edit_height = 22 # checkbox height, default sizes come from the checkbox graphic # gui_checkbox_width = 10 # gui_checkbox_height = 10 # sum of the top and bottom margins for divider lines # default is twice the size of gui_vspace # gui_divider_vsize = 8 # buttons sizes gui_button_height = 16 # for buttons with fixed widths gui_button_width = 100 # text margins inside the buttons (left, top, right) gui_button_text_offset = 5,0,5 gui_color_button_text_offset = 5,0,5 # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 ###################################pakstuff################################### # pak with the images for this theme themeimages=modern.pak simutrans-124.3/themes.src/pak192comic/000077500000000000000000000000001474050137200176505ustar00rootroot00000000000000simutrans-124.3/themes.src/pak192comic/pak192comic.tab000066400000000000000000000115661474050137200223730ustar00rootroot00000000000000name=Pak192.Comic ##################################pakstuff################################## # pak with the images for this theme # These are under CC-BY-SA 3.0! themeimages=menu.pak192comic.pak ####sizes#### gui_indicator_size = 20,6 gui_waitingbar_width = 5 ####general#### font-size = 12 # Main text color, used everywhere. gui_color_text = #403022 # Color of text in tabs, finance window headlines, ware list bonus text, minimap zoom indicator, fps info in video options. gui_color_text_highlight = #e8d8ca #Color of the title text in the welcome screen and in help. gui_color_text_title = #FFFFFF #Color of strong/bold text in help. gui_color_text_strong = #e8d8ca #Background color of selected elements in lists. gui_color_list_background_selected_focus = #7b5942 gui_color_list_background_selected_f = #7b5942 #Text color of selected elements in lists. gui_color_list_text_selected_focus = #bd9263 #Background color of the elements in lists. gui_color_list_background_selected_nofocus = #7b5942 gui_color_list_background_selected_nf = #7b5942 #Text color of the elements in lists. gui_color_list_text_selected_nofocus = #bd9263 ####charts#### #Background color of charts. gui_color_chart_background = #cfb094 #Color for the horizontal zero line. gui_color_chart_lines_zero = #e8d8ca #Color of the odd vertical lines. gui_color_chart_lines_odd = #e8d8ca #Color of the even vertical lines. gui_color_chart_lines_even = #FFFFFF ####edit areas#### #Text color in edit areas. gui_color_edit_text = #e8d8ca #Text color in edit areas when the text is selected. gui_color_edit_text_selected = #bd9263 #Text color in disabled edit areas. gui_color_edit_text_disabled = #cfb094 #Background of the selected text in edit areas. gui_color_edit_background_selected = #7b5942 #Color of the editing beam/cursor. gui_color_edit_beam = #e8d8ca ####buttons#### #Text color for buttons. gui_color_button_text = #e8d8ca #Text color for disabled buttons. gui_color_button_text_disabled = #bd9263 #Text color for selected buttons. gui_color_button_text_selected = #e8d8ca #Text color for colored buttons, like in the finance window or charts. gui_color_colored_button_text = #FFFFFF #Text color for selected colored buttons. gui_color_colored_button_text_selected = #FFFFFF #Button Height gui_button_height = 18 ####checkboxes#### #Text color for checkboxes. gui_color_checkbox_text = #403022 #Text color for disabled checkboxes. gui_color_checkbox_text_disabled = #7b5942 ####tooltips###### # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #bd9263 # tooltip text color (240=black, 215=white) tooltip_text_color = #e8d8ca # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ####bottom#### #Background color for the ticker (bar shown above the statusbar with info)#B3B3B3 gui_color_ticker_background = #bd9263 #Color for the top divider of the ticker.#000000 gui_color_ticker_divider #cfb094 #Text color of the statusbar.#000000 gui_color_statusbar_text =#e8d8ca #Background color for the statusbar.#9B9B9B gui_color_statusbar_background = #bd9263 #Color for the top divider in the Statusbar.#DFDFDF gui_color_statusbar_divider = #cfb094 ####random#### # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #294ab9 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 12 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 1 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # first: draw a frame with titlebar color around active window window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 0 bottom_window_bar_color = 0 # third (best together with 2nd):use different text color for bar front_window_text_color = #efd3b5 bottom_window_text_color = #bd9a84 #Title color (Newer) default_window_title_color = #422810 bottom_window_darkness = 30 gui_chat_window_network_transparency = 0 ##################################toolbar################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # icon size icon_scaling = 100 simutrans-124.3/themes.src/pak192comic/pak192comic/000077500000000000000000000000001474050137200216725ustar00rootroot00000000000000simutrans-124.3/themes.src/pak192comic/pak192comic/back.png000066400000000000000000000063251474050137200233060ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe< wIDATxÚì?rLJ{f˾€uëÖ5”òŽ9rêÄ©"éN±Jº€Ë®bꢫèÈU IG ±˜ÏΛ~ýúuÏ`Q˜©ï€‹ÅîbÁþöýë×oš7?~Bøý7/Ã6õËO߇ëÕ«W/ÿþ¾ùÃÖÿ÷¿üêëM¿ÿïþö—×oß¿Üìûo~†€Ð§ªå¿ @€ @€!@€!B€!B„!B„B„ „ @ @€ @€!B€!B„!B„!B„B„ „ @€ ôœ:üòÓ÷_~õõð‡?nôøï·ÒÛM× }¯·íÃÜýåÃôÑéÔƒüàdïïû¾Ë_¹Ÿž˜ÝÙ´çg5mÓÄiÛ-½ÿýçÝë·ïxón«mý0®Ÿ®S8”€Œ£Sÿñƒ,öŒÂýÑr (” ¤Ÿ6g³=þRyýÊ£&zÎÿ3ýi¾'=1'lÃhóÁpB«k&+¤úÑè YQ% ;´i½ É‘Ê艩 Ð´) PbFMú©Çe|ç]CékÓ§ùC/V¤?¬s©|èÕZ˜e>D,Fþ…JgÕcÊ=îÛòömþøâ7§Ñ©Mëwȃ]¼ÜH°Vir&«s~X/ž.:¯ù¥&,Žþx§TUR•¶“û«n€ÖÔýÝ]ò‰l ýꃛøÄNW×xœDØP‹`¦_w«i%â>ó7Þ?Ý3Þ°®mŽÉN;‰{vиmw“lÌè¢3’(çpÓZ—¤7R„k ÏŒ–‚˜§`Ó'ëø,%g2Æïç„«³ ]|Æì+÷ÄÐæ²rwsûäði4H‡›r±gÕöÉüøe´X6 –Û.ä²ÖK ;ßvtEi|Zà˜Ò˧<­®:£ÄTk3c˜RÔU;wC¼UÊàòXªÝGǧ†gN O[´Žb@ãi)-ÛdN\PR‰©cøb#ù©â(&¤LâÄybX.ç¤lvhûÈÄËi9ͧ_íÐçzò‚{–¸'÷°ùEb€åBéd ǧÇHÙfì¶F OÌ<­ëºIUßáLÅ”feÇÐ9ßnÛËöCÍ›Z‹Èô~BY!¬Öh}}ñÛß¹Ú]¸Pþ‰eÆQwÇ£MïçeŽ?Õ:¤CPB`‹WV!lÚCΟ¾+[”Òý¸fûe¡Í¤ Œ7\ð‘Ù†Â&uee¯YÞÜ0û_jK\h\†Éã;JÜâ U³°!Ëœ+éÓž”]ZÝ^°‹WÔïTTCo1f¹óÊj•³=‹ûµév‘ÞеC²Cé×r˜W:y¨ÁÀgØÊÜo#'“ößVÿ+ÙË3âa!ó çOã…ŠƒÉÒ˺s}9‡9¬Qï#–)Û, qÛ\ÊÖæ‘ÝLK&÷Èí6D_š2û…¥ WEì.¼‡¥(G¹)ÙÚÇÆêö7S?~x°÷/KÄ‚T¹ŽÕ[öÒ´Ÿ¦z»/q’î­à+4e~ܱŠê¾º>Þ>1Æ4SØ×-_Kûí–~ŠÉhå,ÌÅ¥_hÚÃM›µ»ÛŸiƒ,svµû²Iënng³”U‰:»òx @Ï-›×¨Gsk/ÍŠvõXEéMÜAŽà™¦ú%ïò­®Î”…,=;è±ßIG¢Ø]›ò#^.ÛƒÂå…‡iYÙfø™QÌMŽ;Ôñ¤@€~]é.·Û¼¬Ú9#ñàF¦Z 霟½^îþ´ÒÞ©Ù¤L÷ðwv²góeE9aB·We§Œ¯ÆbŒsI¥ßÑ’tmÏÕœ€¶¡Õ‰»éÞtãŸâ[ kqag_Óæ‘rÈŽ~ÚÍKéù²IÐ|ôØò§•h}Am¾6Õ!¤,,¾™îIèZÒxmöÞM?ë1ˆ®ðPvs$>¡.ë·Û«ÆœX³³sý¸!ÒèšÒx#?28uô¨½¹;*nc«wYÕøøû{}‘¹uÄžÿ²ÙʱúܦåTÆêás< omÒ¸ðÕ~°ܠ¨âO$fÏ¥ ³“Š9‹î¹#jYç¿é¯ +R¥M¢˜Ý1ôi²ÖÄÇÿ† ¼"¡ó¾/"ëÏ…].‡›2ޱgn²†EéÅi³i¯×új%=Î9:Ï•¿ê@W“ÆgY3¥]ÑÇåÇÁÜ·iþKõœ†:8­(^(%—ÉyµÃß¶åÐUÄ@²ÆÚjcG€$É|]Q»ÝaX¢™ÎžÍh²áQ}­Y̸“½‘`p,R l¦^ÅPÌrçɉXîtܱ¯²G±l»–Ǩ5’M·÷µUϲÐ :Ï2ÉQålMuR]¾ZM¹å«Ý…(És1xÙK_¯]i ,ç®§$µfqOã=‡vγô†‹“–2/׆qÁ\…¸•‘6ˬÃê{ëLëC<˜Îq=I»4lTãY7vÓE²b½RM¯˜­‘Å1îL`>R3ïÓ\³92mF¥; ë0B8Üãú—sã«AEëE Ù<¼:iºén퉰òü°—Y ;0Õ¸ƒ;ÖG,"6s3Ó4çÊ‹©sì?~ÅAúFöÛã,Π»`aWçšÃžZZõÛÁ]¿!ŸQçË<Ñ/ÍW°O¬ŽgHÇæítÎØÐäa­_ªŽbÉðŠ9yyŠÃú¬rgbkéÄ ÅÈLí´÷d0Mû¯n¾"­ìÂB>¤Ìõ/ÛšáÒü9bgþh²:Ù\ÄÜøU‡”Wvm‹6þž4~ý?àæÆ÷ªÙÍâ<¨…38§^ý®~¦Â¶W/ ©ÌËÖñ@;Çêzj>ìÚImGl?5èø&è2j|ÑRPÝG[êtó3öh&Àûƒ`ÖÈõYLHí3t[èþ´r“Š–)Fò9å¦`8¥üK Nûè®ßþVÆÜ=xy1úê¹m¾ÖÕeú EÇZàœóZdv> ’9Wyw­‰…Ðæèj[¦±¼9ßß¶zÉÔ ]©.´õ¦G™¾÷[h}éå Ý¥ã!Ÿº2è‹ûc:Îá*=qí¾©¥ ã—*vÍî®Í³Ç:ÐÔ"ø`(ýY™uÅE;5”“âàzëà¸VÆuénÚI°1J”|°†ësu¥,y‹Ÿ'Ü´þb—ÆMÑÕ€®E·ECYÕq\˜ê]Ý×L×hjÌÕ-†ÞeŤx¦L/Bå¶T»Â€К’šm÷YÚè®v¿_hpÖÔ]^Ü67P¡7‡VuÇC:¬“ñ»?Ö¯ï @+KüQ<¤g½Iuò¦ÎZ°u<;ñ©¬1.æ\M[¾m{õC‰v‡Î^²0Y•Üd]fqÿA¾º1Ž’êu ²hÉLäøäNç:Ðu¹°Pôl‘ÊR´QMˆ.ÊP)UõF~ªº³he€æUqk³´êÇG­_ŒWeü–~7:ôQiãÌtÐúY˜øŽ3šlÂ÷r?—<ìv:ðšm-]Ú"¿È¡+BêðhkÕ;òe{¸ÔA0—;-ðhÿ†-è].êHbe¯:¨×†v——³~Ó_aC{¡Ð$}™@Ϥt.,zŸêÌ”rYµ l¹¬®±‹™\üŒ3sI¾ë™'Y 'ÒøkÊÂÌÕžÃSìl—¡w¥³+==Á_’7Û2Óhýã‡si0öÕ/õ•×òÍvÐÚ.Ì!•íLÙ³v9‹Qe©F¯Ñ,—¹˜_Ê•vš¶;øYAeåi¯:ôâŋ޼ÛèðÏÿ/ úó_¿Ýôðúí{VqMðó>N— •Ôò_€ @ @€ @€!@€!B€!B„!B„B„ „ @ @€!@€!B€!B„!B„!B„B„ @zNý_€%O³=‡„ûIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/button.png000066400000000000000000000453051474050137200237220ustar00rootroot00000000000000‰PNG  IHDR@@TrëtEXtSoftwareAdobe ImageReadyqÉe<&iTXtXML:com.adobe.xmp [3ËÓG5IDATxÚì½yŒ]Ù} w^­¬½¸ïû¾5 6g4V·Ü-Ûq4µ#C3£ ÀäâùÃF¸Ù <0 8ˆ'œÀ`âX¤[,ZH6ÉæV$«Š¬*²ªX k_Xd½œïTªºº¨êü{ß÷5ªß{÷{îò~÷žïþι—¥r¹ T*]Š/)}ëk_ÇOŸ ÝBéÅløó¿ù(¸Ýåå·Ä}qi­2_¹°?ìÞ½'üè—7CUU)<èy¿hû+–Õ±Ýßßš››ÃóçÏÃÂÂBøþOî”Þ{ûl a|¨?üòáD!¶=ÆvyØ.­,óÕ¸í]}ÄJ¨¯¯ 7» ÿ_ÿÒ©ò–-[ÂíÛ·CCCC<Îw‡„íÛ·‡§OŸ†#GŽ„šššÐÛÛZZZBOOOhjj [·n óóóabb)ÚÛÛÓç 6„M›6…ÑÑÑðìÙ³pàÀpÿþýPWW6nܦ§§ÃÁƒõk×Bcccعsgxùòeš^__†‡‡Ã‰'Â;wÒºð™å²nÔG\æz?~^¼xñjÓò™¶wïÞT¶ªª*ŒŒŒ¤zøýÚÚÚVÇöœ÷OîÝšš›Òz?¾~çÖÖ¶øU9\íè-õØ?²³½\[[›â¹£o$µñïRQâ{=ÎÜ^^Xxæææbl´†ÙÙÙ‹1ÆCuuuŠ}âdbb2ÅMuuUŠ/vÏôôTŠËÆÆ¦“Ä×Ò9¢>K˜÷Ù³±G­ñ}u˜ššŠõ6Çúž§8­O*O,R'ËdÚÀÀ@œÎ1µ1ý.,svv.-‹ò+uuµ©ì³g£aÇŽ1ö_Æãu(Å{cãR9–577›Žb™ãcrròS±]³Üþ(¾¼ógßþ“0ð¤/ôö m­ñÀ~îß¾>\˜øþù¿º»ºÂ.w¾÷ûq‡¿»ºÌÌÌL¸yó“t+Úñ/þÉ[i›81644ÆàHüÝwÄmžÛ¶m ]]Ýñd¿%•á„KLLMMÇ“rs<ÑoããcáI†Æ8/A¸ÿþt0 ÄÀ$~ÆÓô­[·…ÁÁÁtPìܹ#ù`:PÚÛÛb™±˜Si8sŸO¿â†g6¤ímí©ÌÁCÃóùç©,.NÐsB{øða8ËŒO¤Œï7oÞÖí¦!!Ô‡øqN|!V 1Ʋ§C‡¥xç3ÇrÔÙÙ™ö;ßsl°\D‹ïº»»SýÔÉoA9ê¥ Ó;::Òú°,‹2¬óêØŽpéAÿØ»wz‡ß¹x²)“ÄóÍÏϽ’«¢B£Ëö^¾óˆ?F~*éâß™8)—SÌÖ×oH‚Q*U%Áç×ê$Cµµ5é<Êw”Aôމås5ebz)ùùÅ‹…$X55µ©üâb9KÄòÈÈhª»¡aC’¥ۗĤ¦vy ËI~(Úâ–óù† õéÜÕÛê§ ÇÂÃñ‡°±>;lÇóçóéB£9JþÊØ®YÎü¼ó?ýã°ð"hm»vïK;„ƒ~ßÁC!ÄF03N÷îÝ+ÐКZÂ[g†Ÿ~Òýûcu&ˆΉ£¾fCÚÁEâþÆ[¡çQOØ%g(ž@9–L}מ}ÉÒ[£…7·n UÑÂk74†¦hû5¥ïP ^öËž½ûS€7ÅFdîù‹PUSŽ;ž‚¸µ}Sº‚ Î[¶†½{ö†¹|§c|íJ'Ÿú†¦X÷³PœÍ[·ÇFæ@xôèQ d®¸zmhn í›¶„½ûö…ñ(U##Ãé Œ§#Ïb=Í±Ìæè[¶mÕµõ¡º®>´Æu>×§7JÔç‰m¶ûøñãIظÿy÷/R™ØH„ÜH…ÏÛ«‰Bä# œ¬Ùœ É¾p';³gÏž¿CCCé3eºâÓ®]»ÒtdeÇŽ)VˆGæ#~È!G qLüSW¾R¦¾Ó§O'iÉ# 7Þx#É>uШäŠ:8áç?`YëÂ6ðJsì LÄ)BF½Lgݲ•±ýW—b›‹¾Kñ÷}¿Ò²¿7:ûóÛ*M~ £o4þô³_ M}vÚÀø§>öŒÌ¬Q#±zÞ©µþtåôÉ¥—þ±åÏñ*spò3³tçy†¦^¿QýãkL\ûÜVª”TŸÈš@©TþÆo_ˆÂ´#ܽy-5j44L4x\EüðÖÀgºŠrÜ|ñÈÆò¾(•¿¸ÕÌ»QòVwÑ`¯EöÁ{_8RF†?þøã$?üöìăì¿ÿ±cÇÒ•$Û‹Ð ØdY²1é\ãaA*îÞ½›dQ:sæL¸~ýz8yòdú™'ÛD—_ˆ%¯HY ®JY¤ˆu`ß³¦s‘AL"8¬ õqEŒ ݸq#- Ááab:°]ÄüÊØþèfɳÀ§cÜ6±r¨qH¥CCBãOÃDÃq…ÌU;ï9!õÉö’m &­ÂðkE§ˆû€.[º“.^¼˜²adWHÉç1AçÎKÂ@¶…LÂPäÌ Y„i"õêÕ”UBŒÈæ A9¾,–GŸyÏ>å3eȪ’„ì 2,÷Ô©SËã.Êé•õC´X_~7²–¼²Îdw–ÆS4%é!~‘5ÄycLÓÊØ–b^ØÈç£Ê] Äî ®’irCÂk‘OŒt½Ð Ò-Hf£Ò „‘`Ì cbÈÄðšÇÚ°­dJr¦9!kƒä°¿nÞ¼™ê![ÄÀf„‰¸¡Ï”Cª²0Q7²C†ˆyø#ÃDÜå§ÌƒŒ3fi,ÒØ¸¸.ŒéAh( Ù¡› êb™”ç{$l¥Ü¯ŽmYŠiåG©8hìjëjS#AƒF#ÅÕ7 ÕÊñnEu’5"ó„À"Hd‰X.Ù!ºË¨‹®3Ö9BªØ¾×Ŷˆ$RиРBƒ”(<®Àéj(24’d€Øö¢ ðÿ<ÙA6è&B‡,Cd‰Ä‚˜@>rwÂCå‘&¤ˆrÈ "x!B¤øŒdååñ‡¸P÷Ò)ÍirVˆì ¿ "ƒñʺðGY²Uy !‡L¿%¿#ëN},‡øe½/_¾üªÛ«Rb[d=$Ïi9uöpí—?KÆ… ÒU=Ù ’"CcKöàßþäJEþödSÈ„äG%äŒ bÁ˜²+Èc|Ææð—n¡Òƒü NÈ1CF Iâvw?çn*$„òtQQEÜ †œgdoÆé 3ta‘­!CÉz‘ºråJÊòGf¡!SE9ˆy,w3 ;wß±^•Û"f€DÖ;â•u]m]ºJ§KƒÆ†&?ÿ¥ÈÐÈÓxæ F¥ÁmìdPºª„°ðÛóéáû<@ùìÙ³)kCŒ 5H ƒ£bù ‹H}ȱE܆¾ô,”šWwo‘Íaù”AP(C²Ã´üì*~£| ;‚E݈ëE9¤YBfÉQ/ÝoùÁ‡¬õ"<•Û"f€DÖÆ%?‡…†Ž«ðóçϧ+l®š‹L~2ñàÔËôàJƒŒA×™>#„H²’ïèBfˆ ¤‰`z×Ãwù¶w²0ˆ Ó–.Ú2DÄòÂw¼§n2OyÐ4ñ‡\Q7¿ÉÒSw«Se‰KêbB”ÇñpûûÒìêS—V~æトaÄŠõÏOÁe+%¶Ẻ¬ Wôt/ðÊÕ? "O‘!3Àà^Ç¥ÇÓWˆ~sž£“ïþÊbƒ€ J~°ä§Ì"ÏñƒHå1=d†(ƒÐ ÌGW+û9?íœåÐMF¦†ìâ’»ÅR²?ÔKYºÅø©BÄÈ‘YʃҩŸÛõ‘,Æ&‘Í¢<ˤ\¾Ã¯’b[DYï ˆ W¾£‡†"teÓŠ Ϧ¡ÁæqñK¯,¤$:æ•x ;0ß•ŸåÃíçÈóÐ……˜ ü!EÈ3ÝJdÈÄ ”HS¾; ¡aö3Ó/䈘#Sƒñ=ãvº³¨—xdÈq{=’†D1ËË·³³NHó°ÞŸrM×å*)¶EÖÃK©xîwÜ s3Ó¡>6XRAcDãÄ"“À7³þŸJ ) K‹L]IdI 21dhˆü`B²*¼'[”Ÿt0~Fw”!Qd—è®â{1a3-ÿÑHß1 ib¹ˆ±‡¤ 9¬Ÿ¹S‘®6ÄŒe V·nÝJÒÄ{ĉòš˜˜Hõ´··§Ï6l›6m £££áÙ³gáÀáþýû¡®®.lܸ1LOO‡ƒ†k×®…ÆÆÆ°sçÎðòåË4½¾¾> ‡'N„;wî¤uá3Ëeݨ¯¹¹ùU½?/^¼xµ‹‹‹iùLÛ»wo*[UUFFFR=Äo[[[šþüùóÛpÞëìÁ°mS[8|è@Õuaë¶maxh8ìÛ¿/ü'ÿÅ]*ȹ.ß³)Ð\šMûéßûÆ7Ëõñ3ûî?û/ÿÛÔÄ¿KE‰ï•üÖ™)ö:6¶µ„ÿî_ÿ›ð?|û?//Æø#–J¥ªóaï¾}a(ÆþBÜ?m­­)Þ8Fª««c„ç ÏÃý’›cccaóæ-¡­½-ôÆãc>ÆVkKkšglìY˜œœ û÷ïÝÝã±Tã¾ÝŽ#âðñã'aç®aCý†ÐÏ/ñä’b´¶¶6®ouübŒOÆã£Ž1LOM¥8ç¸!†9Þ8þ¦¦¦ÃôÌt:®_.ƸNÇÉÜÜÜ«c‡u]Û5Ëñ£øòÎÅ“ûÓ Q1¯mmíqå'BGßhÚøššR¸yó“t …“û¶¤âòGïÇýðn¹ün–Ÿ•û£óÞõÐÞÖ¢¹PÅžõ¡59ÛɉžW~ë¹¹ùô=¿5MkëR sò LCÆ|/ÒCÀ [·nI'Z>¿xñ2žôkÓA555™uÇŽ1ÇÒôÙÙ¹´_7oÞôª^Nò³³K'&7¯CuuM˜‰ÁýüùB:‰³ÜÖÖ¶t⢱á7,—S¬ Û°¸ø2NoNe8)®×Æ6òó/ÿÅ—ÃÛg„Ÿ|ò0|ûþaøÂÁÖ´·= KÄÎ¥F¢ ¬ÛìGb¢¯¯/í»—¡*<èOܘ¡‘`›úûûÓÉ©!NŽ=šb“;û€íDFˆ3ä…ãäÉ“'©óP'Xö²Á|LCB¨ñâüðáÃI¬81?|ø0-q:tèPŠ]>Óq uvv¦F€ï‰y–ˉžïº»»SýÔÉoA9ê¥ Ó;::Òú°,‹2¬3åX.Ÿ¿õû¿ué/ÿ÷Þýé'Ýï|åâá$bMÍÕ¡§»3Œ‡'½…ùù¹P_½Î+Scé·ÿOÿåwøêÇÈOQ/ôŽ;–bŠóðüìtšvãã+1¦6†ÁÁÁxf,‡Ûw„›×¯¥XDÚ_.̇ᧃ¡¹±!Ãçg§R\ÍL‡¶–ætmjÜîÄ‹'Ddl|,4D9Ùº©=\»úËPëàœ>ÏÝ ”!®æfR,§øžW]÷ï¥xåâãqï£$?íQªc¼nZãGKÓ‡‡îxñ°u3#¡¯çQü›Òvp¬ïQ¾¦&ÚÓqÑØØºÜ‹Ëßü©Ø®YÎü¼s|ÏædPldcÜØùùçéÊ¢¶öU’(̆P[Zj@Šs0̧†ñäÞ-áNïð;;—öÇ¥•ûãÞ½{I’9 Nà±9KûíåäͶ":b2==•‚—˜@\¶mÛº„Qv6nÜ”Nö,HbAÀ#H/£…AÍ2øÛ¸±=Ö7“–Ã<4.,z°}NHÔµ¸8›Ê3?–Y__•ê§QAˆxOy’u55õIÊhÔ›šÓÉžyiÐ9 8ñq`¯Ûw{G’üÄ«ÝÐ÷áí8ÏHP&6!7Eáu±ýk‰B±-^ " ü¦KWœU)ûB¼Ù³gO: ¥Ï”éêê »víJÓ‘N¼œÐ™«S2F[ ±>¯Z© Q¢ õ>}:œsƈøã7R–‰:ˆUâ—ã:fff^ýëÌrX¶W~G „‰ß!£^¦³îÇÇOëK¦)ÊUqÑwé—;ß—;?³þu~oÎ œKÎüƒ³)ƒñ_ý«ÿ%õA‘å¸Ð;zê\ظe[ÊöÂw¿÷áçœûï ¹OJELõ‰üÿH‹—ODù½Û;~ðßü‡aû±7Ãà½+黜Z¶·OQ”ãæ“ÛÊ4Œ'ΜWzáûð*]‚¥•ÝÝÿö5Ý}EØï}áH™+Æ?þ8Éâ°oß¾$d¸RäÊ™ ¶¡¡%Ë‚ÌDaA*îÞ½›dQ:sæL¸~ýz8yòdúž‹d’.7.¼¸àé! „˜³Hë€,±¦s‘€„!8¬ õ‘ÉAnܸ‘–…àð‡01Ø.„‹ß™ Ö•zضnö—< ,e4‹vlËúÔ¸ ¤Ò!uÂpž·—§ñ~å ±¨'HºdÈ>- A…ûOÆ*¦‘X›Ð.^¼˜2ÛdW¸RÎc‚Î;—„l ™„¡È™²< ÒDVòêÕ«)«„‘ÍA‚¨‡ý‹d±<º øÌ{ö)Ÿ)Cw IÈ"ÃrO:µœÉ,§WÖÑb}‘'²x¼²Îdw(Ãg¤‡,²†ø oŒi"ûCFŠï¤˜6òùð.0©x¸¢?}`[Êö >Y~øü­÷¾Xè#YCºohØ+­‘@X ÆÌ0&†L ¯y¬ ÛJ¦$gZ²6HqsóæÍTÙ"6#LÝh|¦R•…‰º‘2DÌÃ&~º±æ!K´yóæ4eYÖ…1= •ÆìDÙ¡› êb™”ç{$ŒúÈ*Q–$^åW1­ü˜©8×TUU _ûâñOùùÇoHW×E¾:¤'‹Q[W›ýJ»:F 21ddÓCæÁ [BÖ„í¦ Œ¤È ÂÄ÷ì7„‚ï‘%ʤ»LâtäÉA–˜aºžèÒZø¿!É'²B¬™~²>dz¨ƒq<™&2vÔ‰°å.42xd›)²>t—!NÔǺñŠTñžº+$lel‹˜©@ææfScD×·Šþ£CmI~h(hŠ 2ÛN7P‘îîü¼ ˆÝDdg‘Ü=EFŒÈ¢ÃÝ)¹» áA6(D!”#ÓC¶Ù@‚—|Ko^H uS†ïY‡œ";C,"2ˆ¯¬ ”E~ò 2B™,ÄŠß’u§>–Cü²Þ—/_~Õí…¨UBl‹˜YÆyü»o¿™žÙráÂ…”àjyéÖùâBV‚.–¯œ9nr£â~{2(dBrV á±`LûÙ`Œ²ÃØþr–ùAœb†n.$‰L ƒŸs7Byº¨rƈ:¸ 9!ÎÈø >džº°ÈF‘™c=è‚»råJÊòGf¡!SE9ˆy,w3 ;wß±^•Û"f€DÖÆ‹Æ‰F„FƆ&?ÿ¥ÈpÇÙ‰ºÚºÏ=¨HÐå•»Àèªb ÂÂoÏ{¤‡ïóå³gϾzNRƒÄ08á`_"dÕ¨¹bŸR·¡#NÄY¾{‹lË_zÎVk*ød‡iˆ™b2ßÂŽ`QwÒƒ,!òd‡¨—çå²nÔ›2Dìcä…ïxOÝdžò iö?rEÝCüÑ…FY~'êbBD=|æöwêc]èÒb;èêb¼1ŒX¥'ã.? ”u¬”Ø1$²4v4 råJ™+{®þii|Š Ý)l/ "û¡Ò@ÈØ°xŽN¾û+‹ ‚h (ù=ÂB]OH#‚ÃþC¤ò˜2C”Ƀ›™îUâŒºÈØ°ºÉÈÔB\r·¤œz)K·ß#UˆY"2Ky`:õÓ‹d16‰låY&åX/¨¤ØQ€DÖ†ŒgÒpñ¬–<Еq48E††‘m¤{¤»À¤$:æ•ý@·h¾;+?ˇÛÏ‘ æ¡ 1A8øCŠI²ˆdÈÄ ”Hu!2 óoLG¼Ò?525Hß3nÁ¡;‹z‰GÖl·×#iHó±¼|;;ë„1O~Z~Ê5]s”«¤ØQ€D>‡ñÏbŒÍ,¤Æ?#²4FE&ý{Suõ¡³ãv¸ßq·â~{)Èÿ¾Òƒ¨db‚x@JȪ,ý0_Ýu…Ì,ýC‘Ãé=w”å»È(‡”KÔC½L#ëÃËB¼y 4b…Ø ZÔ‹¤ F²B÷,]m¬#Ë`:B–…XEàòÃSDƹ]’üPQ±-²þS"""Rq˜HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD Q€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDD HDDDD)5ùM©Tº_ÞM¹Ò·¾öåP*¿µ -¡ôb6üùß|Tˆ·»¼üöƒr¹|i­2_¹°?ìÞ½'<èyž = úÇC,[´í¯XVÇvhnnÏŸ? áû?¹Szïí³adt,446„ñ¡þðˇ…ØöÛå5b»´²ÌWã¶wtõ+¡¾¾.Üì,LüýK§Ê[¶l ·oß ñ8ß}Ž9jjjBooohii ===¡©©)lݺ5ÌÏχ‰‰¥8hooOŸ7lØ6mÚFGGógÏÂÂýû÷C]]]ظqc˜žž ×®] açÎáåË—iz}}}'NœwîÜIëÂg–˺Qq™ë}üøqxñâÅ«uX\\LËgÚÞ½{SÙªªª022’êá÷kkk[ÛpÞ?¹wKhjnJëý;¿q>ttt„ÖÖÖ´­ýáµRQý#;Û˵µµ)ž;úFR;ÿ.%¾×ã~ï­2qËï<;;ÆÆÆÂŽ;Òë£GÇñ™²%1–ˆÅÉÉÉË'§NJåˆß7ß|3 ¦y™‡x£A"5333éäÈ q`:ÛÉ ™ß“&1L\=z4tù#fˆgæÙµkWŒ»ñTõ±÷Äe"b”“;ß:t(Åû­[·’@±|–Ç~¯®®NÇ ¿ñÜ××—Nð;ÔK9ä©Ê'yêA–h$XgÖmelÌU•ô¥óÿÅ“ûS9¶—ùXGŽ©Þѹ й#»Êlçå;Òù?þ½[”Øþ<œØ»¹ÜÒÒšÎãì‡xIœb`é¼ZßOÅ×ê$­­-éÅ|]]mŒé¦XþÅ«¸_’ò—é¸!Æ©cnn6]4ŒŒŒ¦ønhØãz!JP{lR<77·Äßa1M¯©©NqNÜ §uá3Ë­­­‰uÎ¥õÏõNLL¦ãòWëPŸ¶2+c»f9óóÎwþôÃB\ÉæÖöÐÓy/­dyaɘ2l qïÞ½Â'´†¦–ðÖك᧟t¿ÃþX â„Ã255U¸`vr,탾Giûx??=‘L||äi ðË?ûé«€y64¬º¼?êJÁ„½sÀœ=]÷S uÄùÔØî_YûP\Öx²ü;Ÿ\Kû”† _‘rptô¥ è[H‚ÒÛÕ—•¿½y=ÉË}ú¤'­¯ÔMyb•r,—+’Ô@<ìjB¸®Ô°qP ¶¦c½Øf:W W?ïþE*s§w8\<Ù”–U>Ol755†D¡ ®ˆ=Nèìâì ±…HìÙ³'I1ÎgÊSˆÓ‘f¤„X!>™ø!cDÜ!ì_êB”(C}§OŸNÒ’3FÄòo¼‘dŸ:h,8¾êà„Ÿÿ€uf9¬ ÛÀ+qÎ9ÇU²tL-7*×+cû¯þ.Å6þ¥øû¾_iÙßýùmÊüTÚösÁÂèg¿Zã|00þ©=#3kÔˆp¬ž÷5ç–§+§O.½ô-ž apò3³tçy†~M[Ü?¾VK·vH¥˜®Èš@©TþÆo_=»ÒÕ8  bôÃ[Ÿ¹.ÊqóÅ#ËûöíKìß_½îFÉ[¢Á^‹"ìƒ÷¾p¤Lvçã?NòÃoÏþ@<Ȳðû;v,]I²½ ¢Mö™!fÒ¹<Æ Â‚Tܽ{7É¢tæÌ™pýúõpòäÉô=]Q?]n\l –¼"=d{Ö!gØ÷,‡ésss)&Ö…ú¸¸à·»qãFZ‚Ã_îzÈ]„ü¯Œínö—< |:Æm+‡wT:4$44L4S©ÊÂDÝÈ"æá qG7±Ç<È8cÖ˜Æ2!‹ë˜žÜí‹ !;tsD],“ò|„­”ûÕ±-K1­ü(@"wÐHРÑHqõMCµr¼[O’4Êd€h8HXiR€0äŒ Ÿùí;ƒð5a›éã®d)A@<8YBŒÈâbŸSLcêgD ¡ex¬äìR‚,¥±‰Ë¢”e‡¸dl\@Mæ Eȱ\²Ct—Q]g¬;r„T±}¯‹mH¤¡q¡Ë)7P4x\ÓÕPdh$ÉѰrE¥AfÙ ›9@² ‘$ b‚}”»«º˜(4!E”C^iă "Åg$+/?Ä…º)Ã÷¬CÎ ‘á7Ad#^Y—ÜMK¶*"#„àÉâ·$†Ywêc9Ä/ë}ùòåWÝ^•Û"ëá ©xxN C¾=øÂ… 骞l I‘¡±%{Ÿ)SiM!’•3.ˆczÈ® ŒñAveþÒ-´QzÄ ù!fȨ!IÜîÎàçÜM…„PžLõ!PÔÁ`È qFöñaœ2“Ÿ¹B†’õ #uåÊ•$8”åÌBCìRb^‹ÁÝ ÈÎÝw¬W%Ŷˆ ‘õ‚å+k®ÒéÒ 1¤¡ÉÏ)24ò4ž4Ð4â•âG) «Š1@ùY8¼Gzø>P>{ölÊÚ#ì3$†Áѱƒ|E¤>äŠØ¢nCGœò³PbŽåSA¡ ]`ÈÓò³«øò-ìu#^¬åd %;D½t¿å²nÔ‹ðTRl‹˜Y—‘¡©W WáçÏŸOWØ\5™üdbrVViñɃàÉÄð!D*•|G2C\ %HÓó¸¾Ë·½“…AT˜¶ôpц”!"¶¾ã=u“yʃ¦‘䊺ùMâ.4Ê—ÔÅ´üÄ\>sû;õ±.tiåÁüŒ"†+ÖŸ2ÌÃ:VJl‹˜Y‡ü@D®èé^à•«DŸ"Cf€Á½Œ=Yù`ÈJQ cÃoÎstòÝ_YlDAÉïºÈèzBž„‘ÊczJÊ 4ÈóÑÕŠ„ä§³ºÉÈÔB\r·RJö‡z)K·ß#UˆY"2KyP:õs»>’ÅØ$²Y”g™”ËwøURl‹(@"ë±áÊÝ4y +ã8˜Vdx6 v[i !HItÌ+ñÿY &?ˇÛÏ‘ æ¡ 1A8øCŠgº•È ±?J¤)ß…Ð0û™éˆr´ôÏ ´& â{Æí 8tgQ/ñÈ:-âöz$ ‰b>–—ogg æa½!?åš®9ÊURl‹(@"ëp¿ãn8zê\¨­«OÙ#²4FE&=€of!œ9s¶"A@ ò¿ï…ô *ì 21ˆ A< %dUx¥*ßu…Ì 8Lç=w”å»È(·òm¤^¦!Üü±,”§@#Vˆ ¢E½H b„@!+<°‘®6Ö‘e0!ËÂF¬"pùa‹Œ)"ã“þy›åß¶’b[d=ü§0DDD¤â0$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆ(@"""" ˆˆˆˆ$"""Rjò›R©t)¾¼ÿšr¥o}íË¡T~jZBéÅløó¿ù¨; nwyùíårùÒZe¾raؽ{OxÐó$<zô‡X¶hÛ_±¬ŽíþþþÐÜÜž?Â÷r§ôÞÛgÃÈèXhhlãCýá—' ±í1¶ËkÄvie™¯Æmïèê#VB}}]¸Ù=X˜øÿú—N•·lÙnß¾âq¾;oذ!lÚ´)ŒŽŽ†gÏž…„û÷ºº°qãÆ0==<®]»ÃÎ;ÃË—/Óôúúú0<<Nœ8îܹ“Ö…Ï,—u£>â2×ûøñãðâÅ‹Wë°¸¸˜–Ï´½{÷¦²UUUadd$ÕÃï×ÖÖ¶:¶?à¼rï–ÐÔÜ”Öûw~ã|èèè­­­i[ÿúÃk¥¢ûGv¶—kkkSÖ‡øçâødY6óÿ;>LÇq̺°ìãǧïVÆv‰…ÇŠ·ï?ûöŸ„'}¡·ça(Åÿ8 Œ= ßýÞ‡¥?úæ{adh0t‡ñý"þð¿[îîê ?¸ÜÉÇÇýñîê2¿ybédG`ptô¦øæWß.³-œã p$þî;ÂÌÌtضm[èêêŽ'û-i{ù퉉©©éØÍñD¿9Œ…'Q㼋‹/SÀ ÃÃ#q?ãiúÖ­ÛÒA@Àïܹ# ¦~{{[:`&'§Ò:pæ ŸOÈBÿ<•­ª*¥† ©©9pBã8ËŒO¤“=ßoÞ¼9 ¬Ží°:¶Y$ˆƒíÉ“'áçÝ©XÙHtC€bl—׈íÒªF"¬j$E8~ÿ­å|‚DjfffÒÉ‘*âÀt¶“2¿;'Mb˜¸8zôh:éòGÌÏ̳k×®wã©êcÿï‰/Ê DÄ('w¾?tèPŠ÷[·n%bù,ý^]]Ž ~'⹯¯/à9v¨—r4È R•OòÔƒ,ÑH°Î¬ÛÊØ™«*=èKçÿ‹'÷§rl/ó±ŽS½£s… sGv•ÙÎËw¥óü{·(±ýy8±ws¹¥¥5ÇÙñ’8ÅÀÒyµ*¾ŸŠ¯ÕI"Z[[Òy´TªJeˆSÊLÄsu]]}ŠùººÚÓM±ü‹Wq¿$å/ÓqCŒSÇÜÜlºhMñÝа!ÆõB” öØ6 ¤xnnn‰¿Ãbš^SS✸NëÂg–[[[ëœKëŸë˜˜LÇå¯Ö¡>meVÆvÍræçïü釅¸’Í­í¡§ó^ZÉòÂ’1eØ@ãÞ½{… Nh M-á­³ÃO?é~‡ý±:Ä ‡djjªpÀìäXÚ}Òöñ~~z"™øøÈÓà—öÓWólh Xuy!<~Ô•‚ {ç€!8{ºî§@ëˆ'ò©±Ý¿²ö¡þ¸¬ñdùw>¹–ö) A¾"åàèèKA;з¥·«/5*{óz’1–ûôIOZ^©›òÄ*åX.W$©xØ6Ô„(p]©aã lM Æz±Ít®6®(~Þý‹TæNïp¸x²)-«(|žØnjj +‰BA\{œÐÙÄ;Ùb ‘سgO’ bœÏ”!¦ ¦#ÍH ±B|2ñCƈ¸C686ؿԅ(Q†úNŸ>¤%gŒˆå7Þx#É>uÐXp|!2ÔÁ ?ÿëÌrX¶Wâœ+rŽ«,dé˜ZnT8®WÆö_ý]ŠmýKñ÷}¿Ò²¿7:ûóÛ”ù©´íç‚'„ÑÏ~1´Æù``üS{FfÖ¨áX=ïkÎ-OWNŸ\zé[þ<ÂàägféÎó ýš¶¸|­–níJ1]‘5€R©üß¾zv¥«q5&<Ä臷>s\”ãæ‹G6–÷íÛ—Ù¿¿z7Ü’·:Dƒ½EØï}áH™ìÎÇœä‡ßžýxeá÷?vìXº’d{D›ì 2C̤syŒ„©¸{÷n’DéÌ™3áúõëáäÉ“é{º¢~ºÜ¸Ø@,yEzÈ!÷¬CαïYÓçææRL"8¬ õqqÁowãÆ´,‡¿Üõ»..ù_ÛÝì/­ü}+µ=pT&5î©thHh$h˜hx ®¹jÏ] E…í%Û@&£¹¹)N.¤è¼ºl»»»ÃÅ‹S6Œì )ù<&ˆñ Ù2=±’3/dy¤‰ìæÕ«WSV 1"›ƒQÙ$‹åÑõÅgÞÓðò™2d'IBv–KVÊ]S¬¢Åú"Od-yeÉîP†ÏHñ‹¬!>ÈcšVÆvþ}_'¹•†òSYx˜xÄÆ€F«ä<`ކ„×"C× bŒ[i ,ˆcfC&†Wº³D2%9Ó‚œµArØ_7oÞLõ-b`3ÂDÜÐÆgÊ!UY˜¨Ù!CÄ<ü‘a"îèÆ"ö˜gÌÓX&¤±qq]Ó“»}$d‡n.@‚¨‹eRžï‘°•r¿Vl³•ÜøWúö+@" wÐHРÑHqõMCU¤ñnkA£Lˆ†“„•R€0äŒ Ÿùí;ƒð5¡a¤ Œ»R¤A<òàdd 1"‹CVˆ}JL1y¨ŸyM$„r”á=²’³OH ²”Æ&.‹R–â’±qy5™'A"KÄrÉÑ]F]t±îÈRÅöURl‹(@"ë@ãB— Rn h𸧫¡ÈÐH’¢aåŠJƒÌ²A7r€8d"3H Äû(wW!dݨᩤØ1$²4.#CS¯:®ÂÏŸ?Ÿ®°¹j.2ùÉÄ4ä<¬¬Ò ã“Á“‰á3BˆT +ùŽ.d†¸@J¦çq=|—o{' ƒ¨0méᢠ)CDl!/|Ç{ê&ó”M#)Èuó› 1Ä]h”%.©‹iù‰¹|æöwêc]èÒʃùD #V¬?e˜‡u¬”Ø1$²ùˆ\ÑÓ½À+Wÿ4ˆ4>E†Ìƒ{{²òÁ•¢@Ɔߜçè仿²Ø ˆ‚’ß#,t‘Ñõ„<#8"•Çô ””Ah棫 ÉO;g9t“‘©!;„¸än1¤”ìõR–n1¾Gª1²Dd–òKÔÏíúHc“ÈfQžeR.ßáWI±-¢‰¬wĆ+wÐP䮌ã`Z‘áÙ44Øypl¥„ %yÐ1¯ÄCþg1˜ü,n?G.˜‡.,Äáà)BžéV"ƒÄþD(‘¦|wBÃ<ìg¦#^ÈÑÒ?3К$ˆï·ƒàÐE½Ä#ë@¶ˆÛë‘4$ŠùX^¾uB‚˜‡õ†ü”kºæ(WI±-¢‰¬ÃýŽ»áè©s¡¶®>eCh hŒÈЙô¾™…pæÌÙŠ )Èÿ¾Òƒ¨°/ÈÄ 2ñ€”Uá•n¨|×2ƒà0÷ÜQ–ï"£ÜÊ´‘z™†póDzPžX!6ˆõ")ˆ…¬ðÀFºÚXG–Át„, ±ŠÀå‡-2¦ˆŒOúçm–ÛJŠm‘õðŸÂ‘ŠÃ ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆHA¨ÉoJ¥Ò¥øòþkÊ•¾õµ/‡RùE¨mh ¥³áÏÿæ£B쀸Ýåå·”ËåKk•ùÊ…ýa÷î=áAÏ“ðdèYxÐ?bÙ¢mŲ2¶ÿÕ_ÿm)Oÿ÷ë\yaa!|ÿ'wJï½}6ŒŒŽ…†Æ†0>Ô~ùp¢Ûc»¼Fl—V–ùjÜöŽ®>b%Ô××…›Ýƒ…‰ÿ¯éTyË–-áöíÛ¡¡¡!ç»ÃƒÂöíÛÃÓ§OÑ#GBMMMèíí ---¡§§'455…­[·†ùùù01±íííéó† ¦M›ÂèèhxöìY8pà@¸ÿ~¨«« 7n ÓÓÓáàÁƒáÚµk¡±±1ìܹ3¼|ù2M¯¯¯ÃÃÃáĉáÎ;i]øÌrY7êknn~UïãÇË/^­ÃââbZ>ÓöîÝ›ÊVUU…‘‘‘T¿_[[[šþüùó°ÛpÞ?¹wKhjnJëý;¿q>ttt„ÖÖÖ´­ýáµRQý#;Û˵µµ)ž;úFR;ÿ.%¾×ã~ï­2qËï<;;ÆÆÆÂŽ;Òë£GÇñ™²%1–ˆÅÉÉÉË'§NJåˆß7ß|3 ¦y™‡x£Ëc¿WWW§cƒ€ß‰xîëëK'xŽê¥ rƒTå“<õ K4¬3ëÖW>ÌU•ô¥óÿÅ“ûS9¶—ùXGŽ©Þѹ й#»Êlçå;Òù?þ½[”Øþ<œØ»¹ÜÒÒšÎãì‡xIœb`é¼ZßOÅ×ê$­­-éÅ|]]mŒé¦XþÅ«¸_’ò—é¸!Æ©cnn6]4ŒŒŒ¦ønhØãz!JP{lR<77·Äßa1M¯©©NqNÜ §uá3Ë­­­‰uÎ¥õÏõNLL¦ãòWëPŸ¶2+c»f9óóÎwþôÃB\ÉæÖöÐÓy/­dyaɘ2l qïÞ½Â'´†¦–ðÖك᧟t¿ÃþX â„Ã255U¸`vr,탾Giûx??=‘L||äi ðË?ûé«€y64¬º¼?êJÁ„½sÀœ=]÷S uÄùÔØî_YûP\Öx²ü;Ÿ\Kû”† _‘rptô¥ è[H‚ÒÛÕ—•¿½y=ÉË}ú¤'­¯ÔMyb•r,—+’Ô@<ìjB¸®Ô°qP ¶¦c­Ø^K~àg]ã%–wz‡ÃÅ“MiYEáóÄvSScXÑH âŠØã„Î~ Þɾð›#{öìIDŒó™2Ä"Át. äžød>⊌q‡lpl°© Q¢ õ>}:IKÎËo¼ñF’}ê ±àøBd¨ƒ~þÖ™å°.l¯Ä9WäWYÈÒ1µÜ¨p\s%ÌúrµüW÷‹°Üè_Š¿ïû•–ý½ÑٟߦÌO¥m?77—$ Áa]¨‹ ~»7n¤e!8ü宇Üup!@È?ëJ=lÛo ”*)ã±Î¹ pÇ·üzjÜRéÐü:Š|2¤¡%Û@&£¹¹)N®¨í§Ë¶»»;\¼x1eÃÈ®’Ïc‚¯€0m!Óƒp 9óB–!AšÈn^½z5e•#²9HõA²X]_|æ=.Ÿ)Cv$d‘a¹d5‘¡Ü5Åú!Z¬/òDFžWÖ™ìeøŒô¥BÖä1MdÈHåî=Ö!7þ•Úð+?•‰w‰Alоp°µÿ>óÝ릺^hó`ÜJaA$3Ø21¼Ò…ÄÐ’)É™䄬 ’Ãþºyófª‡l›&„n4>S©ÊÂDÝÈ"æá Ùº±æ!KĘ5¦±LHcãâº0¦'wû"HÈÝ\€Qˤ<ß#aÔ‡ìæÁ ¬#¯6ø•#û¢‰|;î*àü·RvŸ"÷Y e2@4œ $¬4„!gdøLæ…±3YEºÀ¸+YAJÄ#NF–#²8d…اÄÓ˜‡ú™ÑDB(GÞ#+9û„” Kilâ²(eÙAž—P“yB`$²D,—ìÝeÔE×ëŽ!Ulu°}Ô½r,'å*¹ñ¯ôíW€D*ºVHPú£á¢«¡ÈÐH’¢aåŠJƒÌ²A7r€8d"3H±@TØG¹» á¡‹‰òHRD9ä…l )"DŠÏHV^ˆ uS†ïY‡œ";Ão‚È F¼².üQ–lUDFÁ!“Åo‰T±îÔÇrˆ_Öûòå˯º½9–]ôØYÇIÅÃsZhòíÁt1pUO÷ ÉÏ»' »í4¶dò3e* ²)dBò£rƱ`LÙdƒ1>È¢Ì_º…6Jòƒ8!?Ä 5$‰ÛÝüœ»©Ê“i£>Š:¸ 9!ÎÈÞ >ŒÓAfò3WÈP²d¤®\¹’‡²ü‘ÙAhˆ]Ê!@Ì‹`1¸›Ù¹ûŽõºpá§b[Ä H%ËWÖ\¥Ó¥AcHC“ŸÿRdhäiP>{ölÊÚ#ì3$†Áѱƒ|ÐÍE}ȱE܆Ž8åg¡ %Ä˧ ‚BºÀ¦ågWñå[Ø,êF¼X/Ê!=ÈKvˆzÉfæ²nÔ‹ðTRl‹˜Y—‘¡©W WáçÏŸOWØ\5™üdbrVViñA"è"Ãg„©@Vò]È q” LÏãzø.ßöNQaÚÒÃER†ˆØB^øŽ÷ÔMæ)šFR+êæ7Abˆ?ºÐ(K\RÓòsùÌíïÔǺХÅvÍd|1ŒX±þ”aÖ±Rb[Ä È:ä"rEO÷¯\ýÓ Òø2 îeìÉÊCV ˆ~sž£“ïþÊbƒ€ J~°ÐEF×òŒà ˆTÓƒPR¡A>˜®V$$?íœåÐMF¦†ìâ’»ÅR²?ÔKYºÅø©BÄÈ‘YÊw©ŸÛõ‘,Æ&‘Í¢<ˤ\¾Ã¯’b[DYï ˆ Wî. ¡È]ÇÁ´"óih°óàØJ AJò c^‰‡üÏb 0ùY>Œ C.˜‡.,Äáà)BžéV"ƒÄþD(‘¦|wBÃ<ìg¦#^ÈÑÒ?3К$ˆï·ƒàÐE½Ä#ë@¶ˆÛë‘4$ŠùX^¾uB‚˜‡õ†ü”kºæ(WI±-¢‰¬ÃýŽ»áè©s¡¶®>eCh hŒÈЙô¾™…pæÌÙŠ )Èÿ¾Òƒ¨°/ÈÄ 2ñ€”Uá•n¨|×2ƒà0÷ÜQ–ï"£ÜÊ´‘z™–>ȲPžX!6ˆõ")ˆ…¬ðÀFºÚXG–Át„, ±ŠÀå‡-2¦ˆŒOúçm–ÛJŠm‘õðŸÂ‘ŠÃ ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆHAøÿ.”¹$‘v¢“IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/button_.png000066400000000000000000000031511474050137200240520ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe< IDATxÚìÚ±KœwÀñ{ÃýÞpH„k@ qÊp‡n\œºtN¸£KÖé\ Þ ”t¨‹à(ÒœR‚‚ I©ÓMùÞ>õWD·âYçîó!9o|Þ÷~ïïû¾žÕ¨®F«ªâµ¼Ï%ïä7çOíø`»µ°|v¸Ûîí¤þ|kcøáóÑéåðä"ã*ŠùS/ž•þ ¬Ÿí_wß¾K7ÿÏß~¯ÖϤ4Ëk(ïîY!iÃòžùbiu³ãY__ùìqÒá£^yÏ|ܽåXêzý“®«{·Îâ|Ò†Åüö/fV\³qåÆõ覭WÒǯìõý÷ ìz'Íø Œ>¾OýœîÚÅа¬O0'Ì_a”ùìúÔ'ýæ^u»ñ/íñ{£[ú[0ã7Ìäæ¿ƒG. H•ýO` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` `0žfùѪªxÕuºÈ;ùÍùSë,ο|ö¸óüI»·“nøó­¯¾ùnôñýÒêfÆUó§^<+ýAY?kkks¯ºéæ¯>ý‹'ÞX? X족†òîžå’6,ï™/†'n¹‡;¹…åŒp©W^q÷–;`×õŠ› Œc^l'mXÒÓ.`ÜOê:®ÜŸ~ø>J0÷ôEÒ£Húø5nNÁ6º··—÷cè<’z½ùõ»0ã7ìêM¾_!Fº™¿Â(ó'XÞS_tß¾‹ˆ{·Œ«?düÞè–þÀÌø 3¹ùïÀ_! `ðPªìx@À@À@À000    @À@À@À0000   @À@À@À000    @À@À@À0000   €ñ4ËVUÅ먮Ó@ÞÉoΟÚñÁö—¿NãM»·“nøó­x}óËïÓ‹Œ«¨ÌŸ×Jë'ÞÄJº~†>^Z? Xì¡e %Ý=Ë!$mXÞ3_,­nº dLûûûÑ€ßzù&/õò N,`×õj-,×iWgq>iÃʳ ̦¸fãÊë7éü¥^I¿ÊïÒ?•zî¶Ÿ¾àá–tøHW#óWeþÄ+§>þg¬Wãê{—v£ÑMûdü½ÿ-ý-˜ñfróß¿B@Àà¡TÙ!ð€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `ãi–ç[ñÚîí¤;€¼“ßœ:ä]?Ó1¿õcýÌÚúy4×À4]Æü§€MÍÖ¯aà©ËÌVÀœÀÖ¯^U£ºv¸—_ßaLv~[?žÀ@ÀàÿáWˆx@À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   `Æý-À1ÑœX™;IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/checkbutton.png000066400000000000000000000361251474050137200247200ustar00rootroot00000000000000‰PNG  IHDRÀ@Llxß pHYs  šœ8%iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2017-05-24T17:52:38+02:00 2017-12-10T15:33:25+01:00 2017-12-10T15:33:25+01:00 image/png 3 xmp.iid:2fb8790c-d83a-344e-965d-f6e79d1bce92 xmp.did:2fb8790c-d83a-344e-965d-f6e79d1bce92 xmp.did:2fb8790c-d83a-344e-965d-f6e79d1bce92 created xmp.iid:2fb8790c-d83a-344e-965d-f6e79d1bce92 2017-05-24T17:52:38+02:00 Adobe Photoshop CC 2017 (Windows) 1 720000/10000 720000/10000 2 65535 192 64 ˆV`¥ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFªIDATxÚìÙ¿oeÆñïݽñï8vœØà8J$š"ÂÒ…!¨ B H0!Ä„Q¦fÌÿ¬HQÙ(Ha ´•¨‚"š0¤$±ê‹Ä9Ûçó Dbb??Ÿñ½é9¿_/gEQ„eYÿ#Š"‹˜ÒþÑÝo,ËŠ>»û ç-—0 Éf²LM•°€³V›‹‹ ÎN°,+ŠãK°,+º}ë%+"‘H2 |‚a€…M·×£\.3[™Ôþ˜î7A¿‡wÞäøè˜d27[ÃmºôÂ0¤ãkߣ8‘&›ãÞýÇ×çŸ~ø»»»Ü|ùu໑Ø_›™Ã1†§Oÿ¤Z½ûý ŒB†Ã!ssst:—ìíï“Ïã]yäóyðã]€1†L:ͽûY_[eeyží6¾ú–ß{×uGb¿c Æööÿ P(bYsóó±Þoär9Üf÷Ì¥Þ8¡<]ÆqÂ(¤×ëây^¬/€ïû|ýý#Ö×V¹s÷s*‹·XYžg}m•/¾ù~¯ûýÓSÓ4'T*r¹'§§œ·Û±Þoz½.“¥¶mÓõºØ¶M­6ÃÔô4Ãá'??‰ °²¼õ*›[×gïÞ~Çq°-{$ög²ÆÆÆX\Xàðð×=c¦6ëýàÉo¿b²E¶<&JQww0ŽÁ1 |?Ä$R±þñ§'ÒLVjäóy¾|m•h6]®¼+lËÆ$Ggÿd±@d 周oéK°¾ò~+Š"DF•­W @Dˆ( ¢D€ˆQ" @Dˆ( ¢D€ˆQ" @Dˆ( ¢D€ˆQ" @Dˆ( ¢D€ˆQ" @Dˆ( ¢D€ˆQ" @Dˆ( ¢D€ˆQ" @Dˆ(qFktX׎|IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/checkbutton_.png000066400000000000000000000011261474050137200250500ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆtEXtSoftwareAdobe ImageReadyqÉe<øIDATxÚìØ?KaÀñçþh½„šŠ„hèÀš„¤)php±¥±Å¦‡–‡¦{-MB¯ š‚Ph ¡Iˆ^@Ùö»žCÂÜðý@p§Ë¯ó{Ï=êun[æív»~}gæÛáVaÊ»7óÏT8>ZÞØqßh5Ïou£@)Z™øzµZ5jç—‹y~:ÿÃg½¿>}ôºF-¹Üò1”·×GIrßíÙSEóËäö@æ÷‚@NÎ.ú/:’µGJdtï÷ÉßPW@’‹DãÆ¤å°â¯OãùÙe¿]ùl ry÷U¹t´[,ØtlL¥hU×üA˜i(½{UÉŠ{`!ߌfa>¯næ?÷°²€ÆÏ¬ôðüDÕ**Ü}]‡6÷5ÍŸ^pg a4.,º;8¥›hû Ëj6´| ³0÷TgZ6pi@µZM×w–‰›hÙ5Ûã¨b¤]óG•c÷TÑöß+צ¼=ÿ?d]íMYi–êÌ?Û€úêöý @@ €€@@ €€@@ @@  €€@@€@@ `‚=.0þ#IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/divider.png000066400000000000000000000003101474050137200240200ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰tEXtSoftwareAdobe ImageReadyqÉe<jIDATxÚìÏ1€0°–«1„àADw†*`BFkõï©ç±—d­7:PŸûÊ|sF¶N@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@à‡%ÀÃG TQRIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/editfield.png000066400000000000000000000011171474050137200243310ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<ñIDATxÚìÝ/nÂPÀñ÷kR,M:_Q9‡¨BÏÔí»Á²+`v  bY1Õc”žù%ŸOÒê÷çÛ׺æ¶.SJ?§kŠiýºHñÅ]ÿÙt5UwéC~²ÿýÿúüˆ;þ<Œc‚{½X„€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ )·uÙTE¿ÝÀß÷&ô,ßÞ‡óa¾ê@x…€B@ „€! B@! ¸GÆÑ*àB@€B@ „€! B@! B@„€! „€@@! B@€x„ÜÖeSývu—cè ·é>_õAÇ?›êéº.úð´Øßzð „€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ D7=«)ðk®IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/gadget.png000066400000000000000000000371421474050137200236420ustar00rootroot00000000000000‰PNG  IHDR@@}g_H pHYs  šœ8%iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2017-05-24T17:52:38+02:00 2017-12-10T15:28:22+01:00 2017-12-10T15:28:22+01:00 image/png 3 xmp.iid:3f6784cf-468b-8049-95ba-24e52cea075b xmp.did:3f6784cf-468b-8049-95ba-24e52cea075b xmp.did:3f6784cf-468b-8049-95ba-24e52cea075b created xmp.iid:3f6784cf-468b-8049-95ba-24e52cea075b 2017-05-24T17:52:38+02:00 Adobe Photoshop CC 2017 (Windows) 1 720000/10000 720000/10000 2 65535 576 64 9F™ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF·IDATxÚìÛ]H›WÇñó¬©BÝì1µ†Àº¸Çf )H Rr5‚iG®& +^ØPón/‘VF;ÚÒÁ`®tÁÉèֵޒ±!l%:Ö‰EBk3olâ"µ”±§¹©zaqÒèvµÕüõû¹Jž«óœ·ß9''ÖƒÕUø¯uìo¼ýõðÿ±0€DžMö>~Ë*þJ<¯Ï·ëáÿääŽý æ;°g`nï)é+ÿô¼<ÀÐ…Û¶wîÜ999é·ØbnX[­yÑ}ÆŒÖu‡°ˆ—JötÚ¶ µÖ…B!•J9ŽsöÊ q !7·Š—åßgžÚÝøòlUUUñö[ÖŸ|)Øw¸«üë}ìëó/îÙ366vôÄžwߌ¾~xx – Û¶øâƒ¸Äš—[òâ (ÂÉžÎãg.•ɬ®ú-+ g³Ù¶¶¶þþ~¥ÔÙ+7dµ…»÷—d&º†N)¥‚Á ˆ¥ÏSvóæÍööö[©>3Üôúù—Q pû÷©™ÙÙ£'.šÂ¿úJPk-tíS2°e½ÅÕsÝõõõB ¶¶vxà”Ü ³mÛ”ß|MĶmK)¼¹½ý†ÖÚëõ¾óé·âZAèÞËoY3£ƒ¹\.ÒÕë>œÔZ×”ñXð”t¥T{{ûwŸ¼ç·¬¯>|«aïÞôÈOÝç/‹èFÝç/O÷?Îçó‚:P²§óÀJ)Ç£”ZYYÉd2‚&Só¡PhvvVî2 ^=×-+ÃÜÄ2ço‰XØëõºOdÕ¿ã8…BÁqYÅ.Ù{ Ê3“^/¿ÖánâmÛŽtõš'²×Ë6Ã>®µþ¾ï}q)ãß|\]]½ïp—Äß0܃ÜÝ»w‹K/·ðápxyyYhz----,,d³YYõïÆX:.¾¹—ˆ…S©””·qÙdÓ콊‡­û»i¤«7ÙÓ977gºYUDºz!š×¨««3'W‰XøÈ‘#î)íñëo·uõ Òû“’ù'6Sø;v455 ­ÿååå|>/ñú€a¦žâ[ˆ‰XXP«§µÊ¼Ìÿ²÷”mn†™s—‰X8”ó1žµé•ÉdÌè53Q4”a¢gÿµ#YnŸ>&µü÷ïß—xrî*¹wîŽYÌq({¯g?sší—Û—” kôÓ÷rù|ÞÍ[÷•¤4ƒß²î %ëêêøû׆¹;H¹=gÝ’‹{é­ ºóþ#sÉ5t¡Ë·L&ãóùèŽl"·àöØRý.s6Á"`+`+xŽ*```   @€@€@€@€000 À À À À€€€````   @€@€@€0000 À À À¢ü ÿÿs›ÎaVu|)IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/listbox.png000066400000000000000000000011151474050137200240620ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<ïIDATxÚìÚ!nÂ`€áŸ…C€jÒL“b¦*zƒŠªáwœ€ ¸fz@M1À11ÕÝ‚õ8È—€q8M÷E—ƒÎ?Ÿêéû>úà†€! B@€B@ „€! „€@@! B@„€B@ „€! B@€B@H@! B@Á=ÿ à*ÒßIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/posbutton.png000066400000000000000000000366471474050137200244550ustar00rootroot00000000000000‰PNG  IHDRÀ@Ãïˆ pHYs  šœ9ßiTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2017-05-24T17:52:38+02:00 2017-12-10T15:45:36+01:00 2017-12-10T15:45:36+01:00 image/png 3 xmp.iid:906552fc-e8e5-324e-a96e-e8656e67fa16 xmp.did:4b64aae8-28c4-4543-845c-fb6a8401d677 xmp.did:4b64aae8-28c4-4543-845c-fb6a8401d677 created xmp.iid:4b64aae8-28c4-4543-845c-fb6a8401d677 2017-05-24T17:52:38+02:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:906552fc-e8e5-324e-a96e-e8656e67fa16 2017-12-10T15:45:36+01:00 Adobe Photoshop CC 2017 (Windows) / 1 720000/10000 720000/10000 2 65535 192 64 ?KÌL cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFBIDATxÚìØoHqÇñïívÓå…[·áæNc †V ûó¤(1Œ¨@„,ezb= ÌÀzЃ1¨'Q$"HŠèA$„P,B›‚C'·y˶›.\w¬’‹´|^îž}·ß›ßýî8­PðsýV(PÉÃüÿ‘ÝÏqïÝÔÓËétZ$­åóÙlV–åÙéI?Ç•øoðsÜÞÆºj_•®g\.·¦ivÁBê^&æïënWU•ã¸ÚÚÚ|>OD‹‹‹MMMñx¼ôç·ÑJ&Ý;0hÝŸ:Ô,I’ÃáˆéŸ>LÏ <ÛÜO_½µ®Ãí-†aHÒ¶x<î ìfb~‡Ã12%"¢]‡w–——óoëî9òxŸOMÓê¶01ÿüü<µõ[騪šJ¥ü~?Ïól4=ñ¾£uO"‘$ϛȤõUËívɯ³ñ/–Ýàm¶D2©(JVÏVº*k¶7”9ÙØdYîë®ËårN§saaÁ4͵µ5QA(ýá9|‰ÆüüÍ[     @@ @@ @@ @@þ•!U(™¥^IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/posbutton_.png000066400000000000000000000007641474050137200246030ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆtEXtSoftwareAdobe ImageReadyqÉe<–IDATxÚìØ±+„aÀñ#¥øÈ (Q)E)eS®”EÊxe“Åê?¸-+›IEJBJ1p#eâqïõ&£túÕçÛsïûÞvïÛçÞçyߦóÝr¡VÇ\©°Å‘Þì`çü.âïÞ«„¾þ-éÓÙ?–¶ÕÚ™D<É¡î\RDF/÷_»˜×¿%Û]îo ήÄe4>Ðõý†„Q£e†Ò6(£Ö¶ö©Ñ¾÷·WŒ\óï‰QiR{º:É—±¥±¶0±±<“//"2J£²4é”—þÇåÍõBäFçW¿î£7§5P¢s|ý˜Ž.‚Nõ)¸F'èsMêðì6mKÛa¡ƒÎïeV\:iÑ“ô ó/5M ÷dGA_Ä¥•f±XŒK'_)‡£STýø°ÔŸ=ÆK $€$€@@H $€’@HI $€$€@@H $$€’@HI $€$€@È%@ú·> úÏ¿ÈIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/roundbutton.png000066400000000000000000000300201474050137200247560ustar00rootroot00000000000000‰PNG  IHDR@ÀìµÜÇtEXtSoftwareAdobe ImageReadyqÉe<&iTXtXML:com.adobe.xmp Bà¹Ù,€IDATxÚìYleÉyß¿ËæN6Éîf/ì}ß7·FJ4#V„HH8Hô` âäA°áÀyqÏNü`È,H¿¶6E€dM4‚MïûÆf¯Ü÷&ÙÜoίÈjµFc@Ï}~¿qï=§NUs¾ªï__Õ9]©V«•Jåíâã,ß‹m•( ÅyWW¿¾Sü½¯G Ï¿´|å ŸŠCÇNDO÷½¨,>¯ÿåJcÿŸ=³«ºmÛöøáû×¢¦¦÷ú&JÕþ¿ô‰£ÕÎÎθqãF455ŶmÛâÞ½{±yóæŒýû÷Gmmm<~ü8Ö®]=Š–––ظqcÌÍÍÅäädʧ££#ýnllŒõë×ÇèèhŒÅîÝ»ãîÝ»Q__ëÖ­‹éé騳gO\ºt)𛛣««+–––Òö†††ŽÃ‡ÇÍ›7S]øM¹ÔüZ[[_äûôéÓX\\|Q‡åååT>ÛvìØ‘ÒÖÔÔÄÈÈHʧhëÑÞÞž¶ÏÏÏÇÂÂB|û½›ñÖë'bdt<šš›bb¨/Þ0Yšûÿù×OToß’®MCC}\ë(•ýÿæ§OW±=lèСC1;;·oߎºººX³fMÚ†ícoì»uëV²)Úí»Ü´iSôôô$ûÆÎð¡;w™™xøðaìÛ·/Ù*Ç`ËØ/í‡kŽ­>þ<¥¿|ùrj”Mû£NÏž=KùQÚÛÏŸ?ŸÊÞµkWj·´Qò$oÒÓ€c¨é8¶¿¿?}RçÜÞ*d^Tä‡Eú7þä?ú{ŸÄøú/üöo|¦Úsÿ~|÷\7?ß-þÞ,“úòç_¯r¾tŒMMÍEÇ=RÙ–Âx§“aß¿ßSkg2BŒœšš.Œ­µèè7ÄÄÄxôöõEsqìòòR26Œqxx$¶lÙããiûÆ›b`` 5‚®®-…1$ìèh/ÒŒ†;•ê€ãÀ'&'’¡.5 Çó¼h€í)Íž½{b~n>¥ÅqÓˆh0--­©=xð öi&&&SgÏþ 6Dÿ@TŠœÇøøX|ã[ßßùò[ÑÐÔïÿÝRYÿåÛï–Æþ?yxc59ò¥úto?-•øâÇW ˆ:e:í¶¶¶Ô1#ØÎuAŒ`wt¼Øpooo8p u¶üaóØ3Çlݺµ°»‰”ùq}ïØiDØ("ˆý{÷îMö~ýúõ$ (Ÿò²#¢mà0¶lÙ’ìùÉ“'IäÐvÈ—t6Ä ¢ '–ÏçE‡O©[_Ñ^}üþ=“ üÎÙÑ-­-©Ìîþò ý]U®ÝŠí”n ||ÏæêÂÂb7íím©Ÿ\ZZ.ì¼9Ù¶N˜œ|–lkÍššdS\žéé©d³ÍÍ-Éþ±Ï!ÙúdŽOvX[»¦ðS©^X˜OB=b%=öLž”É6„J±¹ð ëVÅOMQ¯ÙTé±åúúº”vll´h]ÉÇ %qÖܼ’޲fgWüB[[{j§$„.¿#ªQ³ùyãÿàwcaq)ZÛ:J5úO*¶em|üÄ~¾ñsñÊÂÇ~ùãѵmgìܳ/¢fMìÝ0ª•šØº}g²…¶Â[ÛÖEûúÎØ½ï@tnêŠã'OEûº 14R8ËʚؾcW4·®Í[·ÇìübÔÔ6Äþƒ‡¢cýÆØ¹{Ol+ö϶µ®sc=~2šZÛ¢±¹5¶ïÜë;7Åæ®m±¾Hu ±aãæ8tählÞ²5¶u8}æ£1·°œŽé*ò?Xì;rìDLÏÌFËÚ¶˜(„Ssk{<+~74µen(òn)ê¹9ÖÔ5Äšú†tÇOŽÅåjl-ÎuËÖm©ì“¿ô‘×FGc»sçN©ìŸÎÐÐÐXÊè"! ¦ã¦“'úBˆNšh û-ˆÄ £J„ŽaN縧£¥ïà8¾“Bˆë‹ÈÙ¾}û G144ÇŽKý‚áÁHûäÉ“/"9tø€Yú5Iì䈎€c(AEò¨ÁD”K~Ø7õÀ0ª§ÎDšèïøÝ|<œò$¯rõÿÍÅ=oÉâçÝÕëQ°ì Q€Ð¬Ej’ÀÀ~ggç’ª««]µ§j3ëÖ­Oâgru°º²oéEd‡cB‹‹ iÐ\[[—l˜ã±÷Ñ2˜l1‚Xâ“?ÄÓ Õ$~P ¶ù¤Ï"ÄM{1 &ÿéé™âóK;«ýÃã±\Ûœnü‡ƒl®”eð/¾ð‰j{bÄ„é`éì1F¦8,!GÆNz ‘k…ÁÒèt•bØ8Ò1²ÆAГžÎ™B#ÂH‰Ì7£RûÉ3‡S‰<á,(§Ãv ùR.†O>”›GÞ4ª4êUbtƒÓÀÉñÇ÷¿ú?×ã7>}¦L[âÖµK)ÿwo–ÆþÿÑþuU®ÓO®÷$çwëñp©"@oýƒýU¢;/^|a›\ì“( ötðàÁdÇØ"Ñ"Fˆ"l•`ï´DÓˆû÷ïÇñãÇShÿÈ‘#i?¶‹íÑŽ?Ø=Ÿ)Úm:ä(5å°vŠXBàPò£Í`ïW®\IeÑ.øÃÞÙœm™öG ®äùýíõþ|¯qü¥_‘·—¥ÿ/ûdVå¯}3ʶö%ó½‹*0ˆRÿŸ}çG•27:IýãxÊç‹hÅ 762ú.Õù3eËú…×^{-‰f"(í¼&èÔ©SI0 – 8D^ˆ¸ Â$ˆ&„ø… RT aD4”í ‘EyL}ñ›ïô7ü& Iˆ„ å=ztuÚ¡š>©B‹úr߈ZòIst‡ßˆ=b áƒxc½ƒyzoµÏÃù—n d{/÷ûeºe»F 7»¬âçï1¯GÙAáЈ|á%— ¢c8Äju9E6Ê‚!A”51DbøÄ1ôDJr¤qBÔ‘ÃõºvíZʇh ›L¦ÑøM:DULäØ!BÄ1üaÂîòz ŽAŒeeBZWÔ…5=D ±“~"‚È‹2IÏ~DX÷äŸEŸesø¿Hÿ/%êû½RvpvuõuÉId‡VpÊD€èø™k/ˆ‚•5P+~yaÍ‚‡¨ ׆)°îîî$V%„G^œŒXBÅ!*”×±cÈŸc˜zB„Ž4|G¬äèS~ê&?aƒPÊbñÄ´r^@Mä ‹@"JD¹D‡˜.#/¦Î¨;âQÅù‘çGÞ/¯w+ûÀϯH¤”à\˜Á!á ÊN’ç΢²Ad±Á4âáÅ‘A¢0 „ â#OW!x˜b"=¢ QD:Ä BgJ„!ÅïY¤<þ.äMöS‡zyQ5ˆOêÂi‰Vå5@D„8D²¸—ÜGêN~”ÃTõ>wîÜ‹i/Äe¯.‚)-µ^);¼§å艓qéýÿ›œF™ÀÙ=øßï/å½'šB$$¿*!G\ö^Öæð‡(Aô ~Nù½&DÔI<îžßkÂ4"„ôLQ‘Ši(¤a ±Ã¶üî*îQ~„EÞ/êE:Db 1Ktˆ|™~Ë/>¤nä‹à¡Þˆ¨ün##@"%ç²ò^ŠŸ:º²ßL<0…S_(ݽ'⃈`jˆH ¿„ˆ ÄJ~¢ 1CtQ‚ˆ`{^×þüØ;Q„ ÛV^.Ú”"DØâ%¿©–¼‰<åEÓØ⊼ó«ˆð0…FZ쒼؆ Êëxxü}åý- iJ‹ó`ª‹õA§OŸNŠúç—ÀQG¶“!#@"%g‡C`DÏôB™ 2Àâ^œãÊÛYËBˆ ÷ž÷èä§¿²°A€ 4(ù{~ÉSOˆgöƒÊkzˆ ‘Aƒøà8¦Z¹Îù½T”Ã4‘¢C—<-†(%úC¾¤eZŒýˆ*„Q""Kyá.ùó¸>"‹µID³HO™¤ËOøqžD¶{?}ÙœˆH¤œ p\ù‰ž²= λipؼ-5ÿ— e‚(É‹ŽùÄò‹€ÉïòáñsÄÇ0……0Apð‡(B<3­D‰H ‚Ñ”ŸÎBÐp ×™í/Ä6G¤Ä~Öí p˜Î"_"5Ôh×#ÒQGyùqvê„âê ˆ"JLÍ‘./âfRÙ¦{E>ˆC)=woߊٙéh(Vw÷½R{zßÌ‹×Ü—®,¢€)-"9L%%A`‰!Bƒ€È/&$ªÂw¢EùMЈŽÏïâ‰2DÑ%¦«ØÀF˜p½Ù–ÿß$Dû؆h¢\„‘‚È¡NüæIE¦Úf”°âÿC4ñáDzÞ(Mäa˹P.÷6ÿ§ªÔŸüX$Rf*¾û@DDDʆS`"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" Q‰ˆˆˆ(€DDDD@""""¯µùK¥Ry»ø8Ë÷jµZ)Ë(λºúõâïíâÜKe/iÙßÕËËÕxó£ÇãéÓ'ñÝ _Iûïé{WeåûW?U­Ö6Åž}ûãöõ«ñÍïüí+Ûþ+«çÜ÷Rÿן8ZíììŒ7nDSSSlÛ¶-îÝ»›7oŽÁÁÁØ¿ÔÖÖÆãÇcíÚµñèÑ£hii‰7ÆÜÜ\LNN¦|:::ÒïÆÆÆX¿~}ŒŽŽÆØØXìÞ½;îÞ½õõõ±nݺ˜žžŽ={öÄ¥K—¢¹¹9ºººbii)mohhˆááá8|øpܼy3Õ…ß”KÝȯµµõE¾OŸ>ÅÅÅuX^^Nå³mÇŽ)mMMMŒŒŒ¤|8ÿööö´}~~>âÛïÝŒ£»6¥}5‹3±¥³#¾wñÑ+{ÿïèL÷écÇö¤{ù…_û§Õ­»÷ÇÌÔdô>yï|훯¬ý¿qdSÔÕÕÅáã§cx°?þâûâW?y¬Š=OMM¥?¾ckÏž=KvŒýp°_ì ûÁÖùıµ¡¡¡d£´#òÇž¯_¿žì—kÎv>'&&RÀ±?ì2Û#mŒýØ0vIû#_ÚÄÀÀ@lÚ´)•;;;›êA¹äIúçÏŸ§t”{ôèÑ”wOOOj»÷ïßOmµ¿¿?ÚÚÚb||<¥?tèPj+µ«†ñC®ÏkGv¥ƒËđ馟»ùñ÷fq-Þ,“Ú¾®!÷#äsÍš5…¡Í¥ý ­mm2žÆÆ¦”¦©©±0ÔÅâû\êÈ''Ÿ†Ö™Œ›ß‹‹KE£©+l«¦hXÏ’QoÙ²¥h4ãiûóç³É`7lXÿ"_Ɖq×Ö®IÆžë°fMmÌÌLå-¤FC¹mmí©àl¸‡ÕêrʃºpËËKÅöÖ”†MšBÞ§ú··wÛ&ãö“Ñ”¶¶¶×®]Me½ê ~r[çtß¹ímÑÞÖZжÎùg„môõõ¥N˜Ž;9pà@²A:õ'OžàSgŽ!^h'½½½)Ç΀vD§ÎqlC„>`çûöíK óàÁƒT6yïÞ½Évù°¡ uww'‡Â~lžrq죃'òÄŽ|IÃöÛ·o§úp”EêL:ÊÅ)ñ›ß‡ƒg?~bOlZßûöî~¥m€>‚ëÂ}å-EM ö÷¥ïˆ®×êUôôs033“ì9âB¼ñ™ÏÅrÑ`sôÕô«;v– Ûi/®UǦmÉ^8~xx$ææc÷®Ýi°ˆ­cƒ6tF{G{<.ÄÒ\ѯüÊç¦cÆÇÇRصkWa³R¿ÞÔ±1Öm‚¶HôôiotmíŠÆ†Æx\ˆÐââ§öxèD]á{Ö6¼úô††zÄJLB ñBß…_A¨Ñ.¦¦¦cºð´=‡Nmq8ÞúÒÇ’Ƀ꺱SÃCñs×ΨYü¼qhû†• ¦gJ%€è\RçXŒ ¸DòH± Ð7†Gƒçþó½¾¾! DoMM%ñÜÜ|2¤––æÂë ž"\è<! z|" kMeÐ ¯|¯Π#}ÒpPõøÊHcEÍcì­­-)¢2¹ã§~¤E  ’?¢±±ÑÕ‘n%íC”Ñ0Ò±œ÷tnn6‰9΃Qùf8oœÃ«>Àù¿ÜÖïܹ“®-#¤2µõà Œ8±l‰è Q :Yû6xl‘¿uëÖÔù2:ƾ¥bSØÇñüÕf³}ûöÔ~HÃèöرc+‚¬«+‰+¢L'Ož|ÉA›ö‚íâ¼rć¨ÇPí:±ÿáÇÉöɃrÉûK=hÇŒ~©3‘&ú»âïÝ_í‰çÓÏRž¯¾̦{Ç5›šºÂ)ÿÞ¿ÿOìzwõz¼’‰çS…í×ÕÄ¥ ïÇÓ'b ¿7nûF†b¡¸ö£Cƒ1Ð÷4F‡SÙ³3Sé˜׮ĨðPÔ÷ãéã‡ñèAOQæPÜ»s;–碱¾6ŠügŠõ“b¥º‹ôÄØH\»r¹¨g_<è¾£ÃÅ}KçÀýí-êP)|Àý{wŠÏR<ê鎾â\òw?N ³Ç÷lNNŽðð¾¥@ë ?ÝÞRt •åxëõñ×ï]=û*7‚ræÐÎÔI¶´ìIÂ…Lᓎ´³0ò¥æ•È@MM{êˆó¨¶vn,ŽÝÒMÇb|ääþäÆÇ‹‘ÕÒbTê:­Ñ¶¯+m_X˜Ie}ò#§’ã ƒÏâfhh¾È“¼WÓ¶ÝÛŠðóØU8+=é+•ú4ªÀ‰à˜ñRg:mŽY^žÃG§ŽŸQn /Õ *ÿ¡ƒi_ã|®?L#œÊáÕ°ø«,~>ØÖŸ $ÇÊ5fX¦¶ÎõøüÇö¥Ñ0¢‡ë€p8qâD²'¢üá8ò6íQÁuc;ÛˆŠ[·n%±Ã4ÀñãÇãòåËqäÈ‘”i8áBx'Œ0¡}"²CZyê€ü]Œd;Dn¸9ºƒ-_¹r%•Å(öIlGØq^6lHåÐ^®^½šD×K¶þ&}ÞwÏuŸsÝñ§ñêÚ÷‰ÕñžHŒÿø§žw½óª÷ûØÆ£§b]ç¦4Ý ßøÖ÷Á£ôJ^“ÊOCƒ¥_ ²rAVG†^ÒÜï*ÓALù}äðÎähþæ'Ý¥ þÖç¹Jôaß¡ciDö_ÿæÇ¥Zøo~ýÓUDB‚èá€H@°d¡Èf`€¸@P „ˆ¸AeÀ1 XÛCT‰}¤Cä/Q„Sä‡#f:Œþ±Ž˜Éö‰¢,Êe]¾S ¡E¾ˆx¢x“×6äµÜW" ¨#y°.‚ô䃠úÑíáÊËï²ö{^ƒrRÃÍö†ÇϿף\à<˜&cŽÓ(DXüÈ:»l\¸p! ¢‚DVˆŠð™×ÚÐ0E4Ñ€@&jƒÈÁn®]»–ò!R„ø9uêT3D”²BTñA‘7B‡ÑË&îÑP Ç €ˆÚ°2¨uA¬å…Ÿˆ"DÓ\ÀbnòÊ‘&ö#ÂȨùç)0>uø?ßÿK‰—@Ê ²éø˜ÃI• 8α®¾.9ý²(@0 &ˆÎð›È k~!JKùi„R;ˆ'¦´È“¨Q;‰(å2ÍAˆ¼˜:£îˆ#DçGœy ràçù+€DJÌììó䌈á4Ê™sg¨ OÀ}";ˆ ¦‰‡,†òÚ„E~4áx@ð°™ôˆ&Dé/Jœ)"„T˜…ÈÊåñ‡p!ï<ÝErTèåEÕ#>© ¤%ZEþÔ#?:L$ Ûå^Rwò£¦Ê¨÷¹sçR¤ó@ÌQöê"h‘ÒRë%²ƒÃa]Æ?~ý#é-e‚è„Ï?7®^)ݽ'šB$¡ÁµÈ——ßY‚ØØ¹sg;¬›Éï"Aô ~Nˆ"ADI¬ïaÍOž¦B„ž)*ò[yuÄdz q‚`!zƒðab&?p@dŽz‘:þ|8¤åÈ‚†Hé@‹Àbq7 ²óôõ:sæLª'‘¿•×Bˆ)-8/œN$¿³¥,0…Ct¢¾®¾”k€xò ¢€©*Ö!X)|Gô°Ÿ)+à 1¢6&D "†ÅÑŽür8¢j䇸ʮ³pᄹA”Í¡ü•÷l­,nf ±Ã6„‘l2?ÂŽÀ"o„õ"¢±„':D¾L¿åR7òÍï]ADåw‰)uh)9SAeÇž_&™§iÊDSCDbøNo‰-Ä –¼¾‡è ¢Áö¼®‡}Çbc¢0¶!>;Dˆ¸Æˆöñ¼‰<åEÓ\Äy#À1Dx˜B#-÷‰¼Ø† Êëxxüü¨ SZœS]¬:}útVÔ?¿ ”:²|ˆ‰)18;œ‹\ó“1eé"8D®CÙ@(±áðüôW6„%G°0EÆÔ¢ÃõCHå5=D†Hƒ A|pÓ«Øy±¡¦ÉˆÔB¸äi1"8ˆrò%-ÓbìGT!ĈYÊ wÉŸi\Dk“ˆf‘ž2IG½€ó$²…Ø{ùE " ‘²ò†àJr\/^,Õ¹ãqªL”q ‚(É‹Žùä:0-šŸÎ"j‚ÀàñsÄÇ0……0Apð‡(BLE$‚D$A‰hÊOg!h8{c;Â+ýw Å=Èïåa?ëv8Lg‘/‘ê@´ˆÇëiˆ(Ž£¼,Ú©"ˆcòÍ9D”˜š#]^ÄÍ¥•7¥‹(€DJ-€êêjc|fáÅËèÊBúÿ¦ê¢ûö¸{ûVéî=Qÿ/DB› ƒA@ N%DUød*?u…˜Yù’†Ówž(ËO‘‘îå7–“/ÛˆúðGYoÞ°BØ ´È‘‚0B@!V˜žeª:RÛdY°!œp”Í9±¦ˆˆâ6ÿ7 Ø7çB}H/Rf*¾û@DDDʆ Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆ(€DDDD@"""" ‘W„Úü¥R©¼]|œå{µZ­”åç]]ýúNñ÷vqî¥2€—ο´|å ŸŠJu1êšÖFeñy|ý/Pûÿì™]Õm۶ǽG½Ñ;4÷ú&JÕþ¿ô‰£ÕÎÎθqãF455ŶmÛâÞ½{±yóæŒýû÷Gmmm<~ü8Ö®]=Š–––ظqcÌÍÍÅäädʧ££#ýnllŒõë×ÇèèhŒÅîÝ»ãîÝ»Q__ëÖ­‹éé騳gO\ºt)𛛣««+–––Òö†††ŽÃ‡ÇÍ›7S]øM¹ÔüZ[[_äûôéÓX\\|Q‡åååT>ÛvìØ‘ÒÖÔÔÄÈÈHʧhëÑÞÞž¶ÏÏÏÇÂÂB|û½›ñÖë'bdt<šš›bb¨/Þ0Yšûÿù×OToß’®MCC}\ë(•ýÿæ§OW±=lèСC1;;·oߎºººX³fMÚ†ícoì»uëV²)Úí»Ü´iSôôô$ûÆÎð¡;w™™xøðaìÛ·/Ù*Ç`ËØ/í‡kŽ­>þ<¥¿|ùrj”Mû£NÏž=KùQÚÛÏŸ?ŸÊÞµkWj·´Qò$oÒÓ€c¨é8¶¿¿?}RçÜÞjWà‹7þä?ú{Ÿ”Êùý«_ÿ•è¹?¾{®ñ÷fq-Þ,“úçŸûx20:Ʀ¦æ¢ã)ŒlKa¼Óɰïßï)Œµ3¥Áˆ1À©©éÂØZ‹Ž~CLLŒGo__4Ç.//%cLJGbË–Í1>>‘¶oܸ)R#èêÚRã@2ÀŽŽö"Íxa¸S©8 ybr"êBÑQÓ€p<Ï‹ØÑÞ‘ÒìÙ»'æçæSÚššJjD4˜––ÖÔ€ù“'Ž„täK¶ãĨçAY¤¡Î¹m úøÍÀï¯ß»zöȎΘ¯ÖÄèl¹îÿ­îÇéšp?\®UY|B›Ùºukê#±§S§N¥OÄ ¶ÈµÀÞ>•lÓ Ž=šl A Ó×rìý§ri)ÒR”àÆ¾ÉŸþ{g;m< 76 CCCÉŸ`蠟Ï Ú!öNŸNåÚ ƒØ8mvjj*Ù9炘c"޶Á¹£tSäçÿàwÓ ÎÍ>÷Gÿ¹4 ø÷~ë‹Õîûbpt"~|µ§t‘ _{ãxCÀPøËªCd$‹M`|HGL'Ì'‡áa¨tútªt&Œh¯_¿ž FÀv>'&&^Œh(8‹<"¥!°ÇACA /" á„£\F!ÔƒrÉ“ô4\ÒQ. ’¼i°Œ hˆ4BÔ?FOã$}n ßøïÅï|ù­¸ï΋Ñîõ•ÆþÿáÞö*מë÷t|.n?-Õø_~ñ“éüéÀ±]lÎÛ¢CÆvÙ†-ò›4ØÛi8Ä#ÎûÄ.霉ú vèˆi´-ŽGpÒ·`‡:q®=6‰í±-··Ü¾h3Ø.ÇÒVø¤ Ð>© ΋sàxì<ßOþhc5Ú#blžvI›âøÿö¿~½Nà׎ìJ×áÆÃ¡ÒÜÿSû·V¹Öçn>äç» ‚ùR–þÿðŽ ÕµkÛÒ@–ë…$ÀV–5Å÷©âsMê[ÛÚÖ&;­TjRšì&‹Áj}}Cê¿ëëë ÁÒR¤_LÂV¢’KÉ.ñ-ä1[è ÚËÈÈh²Ë¦¦Æ¢ß^(l}%RC;km][܇崽¶vM²{ÚÝÐÐpª ¿)·®®¶Ès6Õ?ç;9¹Ò—ÿ´+þ4´©ìψ=ûÕ¯¤ ›[Û¢÷Á½R._<ýÃã±\ÛGwm*ÿàÙUQX è\„91NŒÅL§Ž²FÕcHtÞ9äˆÓ±“ž€±bT$ÇçQ)‡¢àépI‡#@ôpŸ4ÉÈ•NŸít@ˆ1>ùÃði(G9ÔañœùPîÕ«W“³ uÚ¾}{¹çõ#/öSàĨõ¤Îe‚ëÀ5âšõ^¸Uº¶Ž `Ê)Ûä‰'’í`ÿüò\íóÞŽ®ÌÑΗûý2]ƒ2E{?t˜GØòSã÷z”¬ g€S`”\&ˆŽáóbܲ`AH0íEd…¨Ÿy­ }ÑE„Ä QD×ëÚµk)"E,lF0!@ˆ(ñ›tˆª,˜È±C„èåv—×Ip bœ¨ Û(ÒÚ¸¢.D}ò´/ ±“~"‚È+GšØËâžü³Hâ³lÿéÿ¥D}¿—@ÊÎŽu8 ÚÇ”' „S&´2µ9[º{(@0äˆ ¿‰¼°vÁCÔ§ÈT.‹’+ˆƒé*¢ˆ%„Q¢B\SlŠm“×ù 4!¤# ß+9ú”ŸºÉkñJYì ž˜Ò"O¢FDž°$¢D”Ktˆµ äÅÔuG!ª8?òàüțȑ?Ï_$Rbp.L9àpPä«ÿ쟼²çŽ“$„ceaÙ ²ƒØ`šq€pÈb(¯AXä…ùyº ÁÃéMˆ"Ò!^Ò8S"D)~çÈ"åñ‡p!oÒ°Ÿ:ä¨Ñî BaÄ'uÉÓ´D«ÈŸzäˆdq/±aêN~”ÃTõ>wîÜ‹i/Äe³O¤ÌÔz ¤ìðÄÎÑ>Nãƒ|íÏÿç+{î8[¢ù2eƒh ‘üª„qyù‰Å—ßk‚PÎO""z?§ü^"jˆ$žËï5a Bz"m䇀"cÇŽ%q‚`!zƒðùà{MˆPR"R¼CZþˆì h°]Ò!€8Åândçé;êuæÌ™TO"”)bH¤Ì`udÍ()ß-͹ãäqž8èüÎŽ2ð#‚‚(`ªŠ5@D ß=ìÏ ”yBŒ¨ ‚)¿¬ÅÑŽüj¢ˆä‡¸ÊO-òÄÂ)? Œ(Áæ(Ÿ4Ò0†Øa[~w÷ÛD !°ÈáE½H‡èA,!`‰‘/ÓoùŇÔ|<Ô•ßm$bH¤Äà\F†¦~ÆÑ•…üfâ•w+•o4Ÿ¼žH ¿„ˆ ÄJ~¢ 1CtQ‚ˆ`{^×Ã>Žc±1Q„ ÛV^.Ú”"DØâ%¿kм‰<åEÓˆÄysO1Dx˜B#-vI^lCåu<<þN~Ô…)­¼˜ŸõA§OŸNŠú“†c¨#Ûɇˆˆ ‘ƒ³FôL/” ",îeíI¾e¡@Ć{Ï{tòÓ_YØ @”üÁÂSOˆgN~GU^Óƒ $ ‚ñÁqLµ"BòÛÎ)‡i2"5D‡.yZ QJô‡|IË´X~‡BŒ(Q~©"?ë#²X›D4‹ô”Iºü„çId ±‡°Q‰”¹Ž+O”íQpÞMƒÃ΋cË"Q’ó‰=0˜ŸÎÊïòáñsÄÇ0……0Apð‡(B<3­D‰ë‰ D4å§³4Ãuf; q´ò–ݶ$‚ØÏºÓYäK¤†:-âñzD"Šã(/?ÎNAC½!¿åš©9ÒåEܬQÂÞE@"%æîí[qà詨«oHÑ2‘^À7³ÇŸ(¥B òÿï…èA¨p-ˆÄ dˆD Q>™†ÊO]!fò¼Èwž(ËO‘‘QBD‰|È—mnþ( Ê[ V„ù"RF(Ä /ldª:RÛdY°!œpùe‹¬)"âÃÚŸ|o¹ßœ õ!½H™©øî)F€DDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""¢Q‰ˆˆˆ(€DDDD^þ¿D‘2ugÜŒúIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/roundbutton_.png000066400000000000000000000031511474050137200251220ustar00rootroot00000000000000‰PNG  IHDR@ÔH^tEXtSoftwareAdobe ImageReadyqÉe< IDATxÚìÚ±KœwÀñ{ÃýÞpH„k@ qÊp‡n\œºtN¸£KÖé\ Þ ”t¨‹à(ÒœR‚‚ I©ÓMùÞ>õWD·âYçîó!9o|Þ÷~ïïû¾žÕ¨®F«ªâµ¼Ï%ïä7çOíø`»µ°|v¸Ûîí¤þ|kcøáóÑéåðä"ã*ŠùS/ž•þ ¬Ÿí_wß¾K7ÿÏß~¯ÖϤ4Ëk(ïîY!iÃòžùbiu³ãY__ùìqÒá£^yÏ|ܽåXêzý“®«{·Îâ|Ò†Åüö/fV\³qåÆõ覭WÒǯìõý÷ ìz'Íø Œ>¾OýœîÚÅа¬O0'Ì_a”ùìúÔ'ýæ^u»ñ/íñ{£[ú[0ã7Ìäæ¿ƒG. H•ýO` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` `0žfùѪªxÕuºÈ;ùÍùSë,ο|ö¸óüI»·“nøó­¯¾ùnôñýÒêfÆUó§^<+ýAY?kkks¯ºéæ¯>ý‹'ÞX? X족†òîžå’6,ï™/†'n¹‡;¹…åŒp©W^q÷–;`×õŠ› Œc^l'mXÒÓ.`ÜOê:®ÜŸ~ø>J0÷ôEÒ£Húø5nNÁ6º··—÷cè<’z½ùõ»0ã7ìêM¾_!Fº™¿Â(ó'XÞS_tß¾‹ˆ{·Œ«?düÞè–þÀÌø 3¹ùïÀ_! `ðPªìx@À@À@À000    @À@À@À0000   @À@À@À000    @À@À@À0000   €ñ4ËVUÅ먮Ó@ÞÉoΟÚñÁö—¿NãM»·“nøó­x}óËïÓ‹Œ«¨ÌŸ×Jë'ÞÄJº~†>^Z? Xì¡e %Ý=Ë!$mXÞ3_,­nº dLûûûÑ€ßzù&/õò N,`×õj-,×iWgq>iÃʳ ̦¸fãÊë7éü¥^I¿ÊïÒ?•zî¶Ÿ¾àá–tøHW#óWeþÄ+§>þg¬Wãê{—v£ÑMûdü½ÿ-ý-˜ñfróß¿B@Àà¡TÙ!ð€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€ ` ` `€€€€€€ ` ` ` `ãi–ç[ñÚîí¤;€¼“ßœ:ä]?Ó1¿õcýÌÚúy4×À4]Æü§€MÍÖ¯aà©ËÌVÀœÀÖ¯^U£ºv¸—_ßaLv~[?žÀ@ÀàÿáWˆx@À@À@À0000   @À@À@À@À000   @À@À@À000    @À@À@À0000   `Æý-À1ÑœX™;IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/scrollbar.png000066400000000000000000000561201474050137200243670ustar00rootroot00000000000000‰PNG  IHDRJòY0 pHYs  šœ8&iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2017-05-24T17:52:38+02:00 2017-12-10T15:45:43+01:00 2017-12-10T15:45:43+01:00 image/png 3 xmp.iid:10dc57e4-e402-d54b-b2b7-df4d40added3 xmp.did:10dc57e4-e402-d54b-b2b7-df4d40added3 xmp.did:10dc57e4-e402-d54b-b2b7-df4d40added3 created xmp.iid:10dc57e4-e402-d54b-b2b7-df4d40added3 2017-05-24T17:52:38+02:00 Adobe Photoshop CC 2017 (Windows) 1 720000/10000 720000/10000 2 65535 512 256 %Jb cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF#¤IDATxÚìÝ}wy'ð_¿Î[ÏKOÏëîÎÎîì®õbÉ–°£ˆ`>“œ˜”yI l8Ž$&Á®"E ÎGÝ…»ƒpä’ØU¸.1/̽P¦HlÈ,Œ°$[Ziµ;;3;¯=ïÓ=3ýz l i­UùŠh~Î÷ó‡j5ë—gžyº¿ýëî™a*®›fò*®K¦êGý¨ŸÒúßsxéÊÿÀ߸@oý·ÌÞû•'§¹~>Í0_ûëÿrö…S9ÒjµdY¶LKUUKçÒ 3å3”f˜—R×--ªª*Š¢ã8<Ï ‚03I™Šú?v×[AèõzŠ¢0 S©T†F ÃPQÿcÿýÏ[j]UUAbŠ¢éz»Ýž››;wú§TÔÿks3©d«ÕŒDäJ¥Â |LQ\—äfãTÔÿ‡ï}k±XdfqqQ×uBÈæææ¡C‡òùüô×?ÙKj]¹øcÇŽMyýŸŠ×Àëõær¹N§ó×ÿó„¬n×ϼôÒxÚ‚àóù>ûWOyðî7Ürpá¶û T_®” !Õ³ÏVÎ>{øÎû!ÿî·o+‹ã±AEý½^÷’úÿèw3›ÍÒ2ÿO|îž§Oå?óèS„w¿á†•••Éj€"Û粨8óöʨŸ'„´ÛíF£ñ¥o<5Ùu^¼W¢â9°W*•{òùKê÷ûüTÔßjµVVV>ýå¯OvýÛsGEý3陟m{lïFï}çoTÛõÇãqBÖ.©ÿ¾Ã²,ZV??±°÷øýñxœ®½çÃ_øüê™ZªzñUé?·ýóÅõÓ’¯ï±'Ÿ»¼~A¤#À?ýå¯?ñ¹{.y¼^¯Ó±òˆ¿°Iì=R=ûljï‘Û^}Šú›ÍæŽõù¡ORQ§Ó¹ø¯“¸íþGÞþš½tA¯žyáÔOž«·»·=LKÍ—º]?E=ç !ÅbñCÇ^ŸÚ{ä’#hI Ò±·š|ð—×Ɇ=µÆ=o=zÛý\²h4TÔßnµ/þëö àB‰Žú/9T›Ôÿö×ì½dÇ:½@¿xªj²øÝsd{e@‹–ªÖÛÝÎ@ÿñê:-5û‡'¶žÏNê§,‚Á`ƒã>qÏÛ&'@·w£^¯‡Šç`F­Vûý·¿î’ú3™ õ;Ž ÿäýw~æo'?¿@YYY!ϬNýÇ^¼ë$„üé‡ß}òäIIŠPÑ޽´þßyóMsss´\ƒ±mûâ]?!ä÷¼­^¯·Z-ŠöDßNÑ9ô‹K¥õÀh4êt:š¦Ýuëá@ 0Ù(:‚†B£Ñh~~þ¿~À²¬íú]Ç¡¢þX,¶±±1;;{ìµû‰Äd&„Ôj5*êŽF„ÔÞ#„>øÛ¶-Ëš-5ºÔÕÏ[¦R)A*•ÊÊõt\CZ[[#„Üvÿ#“]±X¬V«étš–kH;îLitIýÓ ÐÏàø¾ß7\MÓ“É„ZmÝñú›ôápÐïûƒa*ú~ôÐõ™Üž6xíüR³Ù]–§¢~Q-ËjµZŽã„Ãá»ßrs2™ÜÜÜT…ŠúOŸ8þÎ7¿ºT*)J쟞ýéä(H–å¾>¢#€%Ï—ú$Dz¥­­l6ÛnµÃ‘ðÂu×{|t¬æææþð½¹^¯çóù666lÛÖ4M’$Znâ „0«Ç_êWîž_¡±r*öþ„ïFý¨õ_+ñÞ߸ò»¥RwÜ;ÍõW¿õWþ¦¼~†öe¼<,Z€ @€ @€ @@€ @€ @€€ àƒ'„¤fò—ŠëR÷¨.þâú)Uq]Ìæçe{ý¡Õõÿ݉ t@šazàcÝvÓqŸÀgïÿP¯×kÕJi†¡qþôü^,¦0„ôûý@ `†mÛ@À²¬^·›J§ëõº(ˆ¡Pãy–eÛí¶®i,Ç)ŠbÃ0¶mw:l6[©TÆã±Ç㠇Æa8Ž3½ Š’$•J¥ÉÙqœxßæùj(âyžÂ󼪪¦i†ÃaÓ4›Íæâ⢪ªk<ϲl 8ÿÂOF2™”eÙqŸÏW©T4M ‡ÃÕj5—Ëõûýx<Î0ŒeYŽã<ó½ïÆb±T*uþÅB(ÞÈç !Š>´…Òù™‰…SÑàá#¯!ßü>•õ+¡ÙÙ™N»#&#Ûó³±±±²ïºÕÕÕ ;øk7·.šŸ”<3™ŸjµÿùüüÊ {!³±Ïç«VwœŸ€"-lÏÏó,Ë.¤÷t»ÝF£±2Ÿºx~B&W#—›»d~ÖÖÖR±Ø¡}KÅbIŽF/¬¯ßû•'±¾†XBˆã:¶mg³TF±®é¢ ÒûH’tîüyÓ4eYžkF#Žã\×]^^ž™™9þ¼$Iš¦9Ž“H$J¥Òüü¼$I ±Xl²•š¦Y.—†©×ë^¯×¶í~¿ßï÷-Ë Žã Žã,˪Õj“Í»^¯OþAƒA­VÛØØFãñ8‰´Z­P(T.—Çã1Çq…BAÅR©$I’,˺®w{]QBÁ !Äq]Ìϵ›Ÿ ½ó ± ¾ö+I’ΨªÇë¥ñ 8®3 u}Lé P®TggÒ¦aœ={Öçóiš–Ëå$I:uêT.—ÛÜÜœlÌõz]–å .ÌÎΊ¢xúôé……]×;ŽmÛÉdr4¥R©­­-¿ßoYV,ÛÜÜTeyyùôéÓ>Ÿ¯Ýn/,, ‡CÛ¶%IÊd2“3EŠ¢´ÛmY–ÛíöÚÚZ ØÞ_$“Éb±¨iš(Š«««{öì) [[[Š¢8ŽS*mMN™H©IùühšFéüT*•t*eÛócÛö+àõ0 £Š2Y?RgeyÙ¶íÕg~Lé à÷ùX–››^×uBˆeYù|~Ïž=¦i^ýõÍf³\.ÏÌÌL6ÑÁ`Ðívc±˜eY­VkeeÅ0Œb±èñx …Âòò2ÏóçÎ+ ^¯·ÛíL&FOž<¹±±qýõ×[–U¯×{½ž×ë­T*§ÑhB@4 ¥Rinnnmm-•J¹®Ûjµ2™L>Ÿo4–ey<–e——–4}è÷91rsóTϪª”ÎÏçcY&žõxDºæg46¼^ïíG×6ú½A§ÝæxžÆ'`Yv¥REZWñ333¦i‹%†!¦i¦R)–e“Éd§Ói·Û¹\β,MÓúý>˲G„F£1??ï8ÎÒÒR½^g& ŽF#˲.\¸°°°H$ªÕêp8TE„r¹< $IǦinnn...Š¢¨ëz(òûýõzÝï÷kšfš¦$I£ÑèìÙ³,Ë–J%Y–E™Ú¶H$$IÚÜÜôûýÍf³×ëB´õó³´/FëüÌΣQ±Xâ8–¢ù‘$©Õî°÷ížÀ^ø€Çë G"R @ãh¨ B½0 :öu+Ë­V˲¬d2¹¶¶–Íf …B.—[[[ …B²,ó<ï÷ûkµÃ0óóó“ë½[[[‘H„2&Wö¢Ñh¿ßo6›“»z&ë&KõÁ` (Ê䮡~¿Ï0ŒßïgYÖuÝp8,‚ªªÉdRUUMÓ–——ý~ÿÆÆF*•ªÕj~¿8ò< …*•J2™t]7¯ž;O=ÔÏ—ÎóW„AÐj7÷íÙÓét(š†aähôÌ™UÚO¡ÐŽ%„(в™ÏSzŸmYúphY¥/€®k++Ë–e…Ãa–e ð,˲¬ÙÙÙjµê8ŽßïO$µZ­Ùl†B!–eëõúäÈKÅ@ Ðh4:Žëº†a”ËežçA˜,ùmÛv]wräµ°°Ðív××׆ét:²,çóùõõõV«eš¦ óóóN§ßïg2™jµZ¯×ƒÁÆÆ†ßïF†ax½^Q5M³m;Ÿß,K‰xœ•#´ÏaÏÏ2­óOı ¾ö+€ÕÓ?åòÓÇŸÿ8…O 90 ÃáEZà*Í~¹yŠçxÇu}^ï…ÒIŽç Ï>Ïr¬mYÇõ²$õXÖóÂZÁ²ìT*Y¯7ªm­Õj3 ×;Q F£ÑÈ3r¢Ñè–ÚïvµYªÖÚ›ÕÖÜ\¦ÛëVÛšã8‚à)ÕÔÙÙ™|¥6&âVµEÉv<^/™¦99~¡TŸŸŸ/\(Z–í7™|õ!$ ](•$I×uµ?EOq«‹9„l:¾÷à›(½ ô¦£¯3L#žJS:?ûo¼™eŸÏG™_Þ×ívoNe†Ã!DzrrŽã8¿ß”¤¥}7T*˲öÏÌT«UY–›Íæ\.$Ëòüò¾Á`0=O,›¼×$ zƒŠKÜl6k·€í8ûn¼¹P(d2™J¥2;;ë Å!Ù…l»Õ …Æa,í³ëõ:!äÖÛ_U©Tf¯ £áŽDz½^0ôGâ>ŸoåúCµZ]ŽF™ÕãTï@Ý=¿Buý ÞÉ9%õÓ`˜ÌÏÿ‡‘êúSwÜK}`ð¯> @€ @€ @€€ @€ @€ Z€ ¯ñ¿©¨ÿ¿z ,úýž ˆš®ün·#ŠbZ QQÿ'?ðvŽã:Ž ív;™Lº®[(dYžþú'{ù—úÕ±cÇpþK_Ô+[íZikãÇqùÍúã÷Ý¡ªª$IõŽNÅsàwq&fF2âÿÚwÖþàîÛu]Eñ†›’¿ûÎô׿µµµ²²’L&Æ#ÿç‡ïûÍW;޳¸¸Èqý¯W·>õù¿¹üñ·ýúMTÔ?Òÿø£Ó—?þðŸÿéß~÷¹é¯ÿÂ… _}êäåèØëiÙ íx˜?9‚Æ>ú—‘HäÌóíÙÙÙ‡þVõ쳩½Gøà;:N¯×£åiøý~Y–¿ðÕ˜Ôÿ‘wßZ.—çÛ*Š—e¹×ëy<ž/}ã©'>wÏm÷?òÑßzÓêêj.—£¢þp8L©þâ¶šÚ{¤Ñ¨SQ<#$yý. ç!ŽãBžøÜ=?xÛýȲL×Îhû\V…’ο°„n· zø['ÿ"!äÄã_üì_ýýx<žlØÓOu]ÿÒ7žÚ®ÿ _ý‡™™Ž£ã·ßï÷z½ÿéÑo?x÷!Þý†ÿúØw“Éd¡P ¢~˲!¬M~vš6ãËë§… „§Oå·™ü\.—éÚû?ü…ÏâÃøà»î¼ÂU)¯ÿà«n¢«~–’N§†!„¤÷Ùþ3™Lê:§€RɤmÛ—Ô¿¹¹i;õ·ÛíR©D¹åàÂöŸÕj•çy*ê÷x<Ç^»ÿð÷m?røÎûÞùëX–Žf棿õ¦Kêßo¾š–Öuý¾w½ñ3>µýÈg}êSz×d£ Èê™Nýä¹ÏŸ¤ôhšÆú¶ø‹¯?99|ž˜,hYBŽÇÆ×¾wê’úfÕãñPQ4}ìÉç'‡ÿÞý†oþàìäÈnú•J¥l6»}à<ùs~~ž–ùÙ>R¾¸þ™™‘’þg2™Ñh´}à?ùÓuÝápH×´¥ªõv·3Ð h¬ŸAl8ÿl9³÷!¤KÉ5€F£±cý´¬`$IÚ>ðŸ˜ü<77GÇ ,•RUõo{Íä úð÷}ì®·4±1¦¢~^šÍæö"àð÷ýΛo²,KQb´lÆívûî¾}²øÌ£O½û 7¼øâ‹“Ss´¨¸î_}íñ„^ÛªÒx `RÿW×骟'„LN5¤.Úþli/ŠT<‡d2I^,\^ÿ`0 ¢þ|>O¹íþG.y¼^§ã"j­Vã8.‘HüÛ÷¼9µ÷ÈÇîzK·Û]\\ܬý„ŠúžÏårÍfóOÞgjï‘?yÿkkk‘Ä,õ‹Å={öôz½ûÞõÆÛîäßwÇÆÆF …B„¬øÌ€_ø+ W’xBÈO~øôoÞãñxUµÁ0L4u\W .äé8:}áÏþHUUŽåâ‰ød—”N§¥-§°ÆþÞ±F£1çææTUM&“çΣå"|q}µoõŸ$ óºsë[ Qô<}üyäãô¡}ËþH\Dæçç¿üï÷ ¢°çà«666²‹KTÔ¿°°`šf­VsçÎ_ÛÓív]×µmÛ¡äØ+³züÒ0 ä>¾âº—]³Þz©L›ÎÔM3 ùÚ?^M&Ooýß;õó.ž¤“ÔÔuÇD¨ÿ_¤þUŠê§Ý-³ÇŽ£÷ý Fà_'|€ @€ @€  @€ @€ @´@^9xBHša^ê××ò'f˜ÏÞÿ¡ÕÓ'tMw\geyÙ²ì†Ú°-«90Ÿxæù) i†ùÄïßõâÉçBÁ eÙ³³³Õje8%âñr³÷¿¾ÿ*^ªççÖ#ûfbáËç禣¯ûø§ÿ|úççè¾LJ ƒAÛ²fgg+Õêh8Š'âûo¼ù#þ‡)¯ÿ=‡—n9˜½÷+ONžËíGû‡'&53«Ç+gŸMÝq/vÓ¿ÄH3ÌC|Ìב$i4ö{×£(Êê韦fú·á^¯ç8N(†¶mW*eBˆ>†CÅkàõxDQ(•¶t]3MsÏu+ÅbIUÕé/>Í0âŠv\W HÃÑH D'*G²é8óÓíöRÑàócTÌ ðK¹Üd~F£‘cÛûöí)KíV ;8Ø}Ðm7õ®jÛöU*J§ÝG"Çð=> SñZµÒÀ Ä0t}¼úÌEQEѲ,^ôRQ@ l®u»½®ã8³3i–QÛ6 #¦Ä)Lý>xhÿŠmÛMUÍÍÍOæg3Ÿß{ðMä±ïLý‡ö/>òBˆ¦iªª.í‹y½^Ã0â©4À íVk2?©d"*GLà ‡Éd;8Ø=×Ù*me³Y×˲,ÇóR °ÿþ§??ýO âºTŸ‚ „˜†‘ÍÎëºnš¦ëºº®ƒÁùùÌ©sy*fÈuÝçg«´EÍü|óûôÎÏØ42™9Eš¦iÛö`0ss³£Ñ;8Ø%®0â§ä9P±•^A<‘xîŸÏʲ\­V=O6›­T*š¦Q±_¹ùýÒ£˜Ÿ_¶˜¢T«ÕËç'6“Åv_Àµ%Š¢ªª£Ñˆçùñx< ¢Ñh*•jigÑxÙóи2Üzí5›Íååe˲æççƒÁ mÛ½^o0 4vÕj·wœŸ~¿æ`깄eÙåååÕÕUMÓ8޳,«ÕjƒAô®b~Üç' ¡7pe8tíÙŽÍó|>Ÿƒ333–eY–Å0L·WCs`WŽãì4ÓŽã¸`0Øï÷3™Œ ¥R)ŸÏkš¦kC4v_ųìŽó£iš€i×jµÖ××C¡P³ÙÔ4ÍqœÔëõæ ˆæÀ®:öúºqùüð<¶nØíè-¸æ&wmF£É½Žãèº> ’É$š»ŠDäç'N£9€ `ÐívEI&“¥R)™LV«ÕL&S(иšÀŽó“ÏçѸ2,¯½x,^ &ïÜQE’$BÈææ&óÒŸq°MQ”ÀNósÝ(šXL;ŽcÓét*•Ò4M’¤Á` ˲±X Í«˜nÇùI$ði €˜þ×€ã†Ãáúúz<džaÔjµd2Éqš»ÏËb~@«Éå;I’dYÖ4Íï÷/--ùý~AиŠùï8?¢(¢9pe¸pí ‡Ãv»mF»Ý®Õj®ë†ÃaÓ4{ý1šW;ÏO,=æ`ÚÅb±§k5AdYvG–e–e[­–ÅùÐØ•¢(µæGŽâ"0 hÇ'÷üŒÇãÉ7‚u»Ýbßé /~6ó›è \®\{õz=QÓé4Ã0Žã -p•æ´J$š¦Çãn·{þüùñxÜétgggÑØU,ßq~2ó4p'•Jy<žP($Ë2Çq…B¡R© 3°+†Ùy~¶¶¶Ð¸2\˜Š%¼eY~¿8&‰ Û¶†I&“ä4NãÂ.Ôf3ä‰]>?ø, À €†×€ec±ØäN>žç³ÙìÒÒ!dk«ŒæÀËžŸbŸ& XL=MÓ666,Ë’eù…^E1ò—ËÇcEQxž:øF0Ø]¿?ŸKçGÆE`À `úÇãT*e†®ë–eåóyÇS«Õ\ê /~ð¡Ð€<O§> …BÉd²P(0 Ójµ&_ê„æÀÕÌÏäÂï%ó£ª*š€i—N§µv½\.×j5Ç3y+¿ëºã1¾v—L&%IÂüÀË€S@×Þä~íx<¾¸¸hÛ¶×ëM$Çëõ¢9°«b±´ãüø|øNiÀ `êE"‘«§yžoµZ¹\®Ûíú|>Žã$IBs`Wáp¸T*a~+*q'Ã0lj¢èº.!daaaŒOs„«Ù†YvÇùÁ§€“ÓµÁ`PQ”µµµx<ÞétF·ÓAsàj&hÇùi·Ûh ¦(ŠÝnwûì­išñxŸO&““ûùaw·óüظ‰ÓOÓ´ÅÅÅÑhÄóüÂÂ˲.\°,ËëÃÂÀît];pã¾ËççæÙ4ÓÇõûý~¿ŸÏç !©TjyyÙ0ŒÊO¢9ð²çDz,4ÓNEBH4µm›ã¸n·;Y– …Bh¼ìùÉ,íEsàÊpøÚÓ4Íq¿ß?ý?—L&‡£š»Òu}çùÁmÄ€˜~Á`вìr¹"ËÑd2éº$º®Ë2 š»òû†a–J[áp$Û¶‰Dp( èà¢Ä”Þ /ˆbCmúsç×8ž·lœÃ…Ý1,‘#ín‡ãøZ­îõzϬ®†Á PÕf±XŠÇâ[åJ³Ù1‘77 ^¸ ½^ok«œL¤*Õj«Ý½Þ¨¬‹%ÇÁWBÂ.þß]Kî¸ôínIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comic/theme.dat000066400000000000000000000124211474050137200234660ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images Image[36]=> button.4.0 Image[37]=> button.4.2 Image[38]=> button.4.1 Image[39]=> button.4.3 Image[40]=> button.4.5 Image[41]=> button.4.4 Image[42]=> button.4.6 Image[43]=> button.4.8 Image[44]=> button.4.7 -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=> scrollbar.0.6 Image[7]=> scrollbar.1.6 Image[8]=> scrollbar.0.7 # scrollbar knob left center right Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # back up and down Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.2 Image[14]=> scrollbar.2.1 # knob up and down Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.5 Image[17]=> scrollbar.2.4 # scrollbar back up center down Image[18]=> scrollbar.2.6 Image[19]=> scrollbar.3.6 Image[20]=> scrollbar.2.7 # scrollbar knob up center down Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- --simutrans-124.3/themes.src/pak192comic/pak192comicxxl.tab000066400000000000000000000124001474050137200231130ustar00rootroot00000000000000name=Pak192.ComicXXL ##################################pakstuff################################## # pak with the images for this theme # These are under CC-BY-SA 3.0! themeimages=menu.pak192comicxxl.pak ####sizes#### gui_titlebar_height = 34 gui_frame_left = 20 gui_frame_top = 20 gui_frame_right = 20 gui_frame_bottom = 20 gui_hspace = 6 gui_vspace = 6 gui_tab_header_vsize = 32 gui_button_text_offset = 2,2,2 gui_checkbox_width =34 gui_checkbox_height = 34 gui_button_height = 34 gui_indicator_size = 20,10 gui_waitingbar_width = 10 ####general#### font-size = 20 # Main text color, used everywhere. gui_color_text = #403022 # Color of text in tabs, finance window headlines, ware list bonus text, minimap zoom indicator, fps info in video options. gui_color_text_highlight = #e8d8ca #Color of the title text in the welcome screen and in help. gui_color_text_title = #FFFFFF #Color of strong/bold text in help. gui_color_text_strong = #e8d8ca #Background color of selected elements in lists. gui_color_list_background_selected_focus = #7b5942 gui_color_list_background_selected_f = #7b5942 #Text color of selected elements in lists. gui_color_list_text_selected_focus = #bd9263 #Background color of the elements in lists. gui_color_list_background_selected_nofocus = #7b5942 gui_color_list_background_selected_nf = #7b5942 #Text color of the elements in lists. gui_color_list_text_selected_nofocus = #bd9263 ####charts#### #Background color of charts. gui_color_chart_background = #cfb094 #Color for the horizontal zero line. gui_color_chart_lines_zero = #e8d8ca #Color of the odd vertical lines. gui_color_chart_lines_odd = #e8d8ca #Color of the even vertical lines. gui_color_chart_lines_even = #FFFFFF ####edit areas#### #Text color in edit areas. gui_color_edit_text = #e8d8ca #Text color in edit areas when the text is selected. gui_color_edit_text_selected = #bd9263 #Text color in disabled edit areas. gui_color_edit_text_disabled = #cfb094 #Background of the selected text in edit areas. gui_color_edit_background_selected = #7b5942 #Color of the editing beam/cursor. gui_color_edit_beam = #e8d8ca ####buttons#### #Text color for buttons. gui_color_button_text = #e8d8ca #Text color for disabled buttons. gui_color_button_text_disabled = #bd9263 #Text color for selected buttons. gui_color_button_text_selected = #e8d8ca #Text color for colored buttons, like in the finance window or charts. gui_color_colored_button_text = #FFFFFF #Text color for selected colored buttons. gui_color_colored_button_text_selected = #FFFFFF ####checkboxes#### #Text color for checkboxes. gui_color_checkbox_text = #403022 #Text color for disabled checkboxes. gui_color_checkbox_text_disabled = #7b5942 ####tooltips###### # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = #bd9263 # tooltip text color (240=black, 215=white) tooltip_text_color = #e8d8ca # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ####bottom#### #Background color for the ticker (bar shown above the statusbar with info)#B3B3B3 gui_color_ticker_background = #bd9263 #Color for the top divider of the ticker.#000000 gui_color_ticker_divider #cfb094 #Text color of the statusbar.#000000 gui_color_statusbar_text =#e8d8ca #Background color for the statusbar.#9B9B9B gui_color_statusbar_background = #bd9263 #Color for the top divider in the Statusbar.#DFDFDF gui_color_statusbar_divider = #cfb094 ####random#### # Color of cursor overlay, which is blended over marked ground tiles cursor_overlay_color = #294ab9 # windows drop a little shadow (default off) # gui_drop_shadows = 1 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 24 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 1 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # first: draw a frame with titlebar color around active window window_frame_active = 0 # second: draw the title with a different brightness (0: dark ... 6: bright) front_window_bar_color = 0 bottom_window_bar_color = 0 # third (best together with 2nd):use different text color for bar front_window_text_color = #efd3b5 bottom_window_text_color = #bd9a84 #Title color (Newer) default_window_title_color = #422810 bottom_window_darkness = 30 gui_chat_window_network_transparency = 0 ##################################toolbar################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # icon size icon_scaling = 200 simutrans-124.3/themes.src/pak192comic/pak192comicxxl/000077500000000000000000000000001474050137200224265ustar00rootroot00000000000000simutrans-124.3/themes.src/pak192comic/pak192comicxxl/back.png000066400000000000000000000063251474050137200240420ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe< wIDATxÚì?rLJ{f˾€uëÖ5”òŽ9rêÄ©"éN±Jº€Ë®bꢫèÈU IG ±˜ÏΛ~ýúuÏ`Q˜©ï€‹ÅîbÁþöýë×oš7?~Bøý7/Ã6õËO߇ëÕ«W/ÿþ¾ùÃÖÿ÷¿üêëM¿ÿïþö—×oß¿Üìûo~†€Ð§ªå¿ @€ @€!@€!B€!B„!B„B„ „ @ @€ @€!B€!B„!B„!B„B„ „ @€ ôœ:üòÓ÷_~õõð‡?nôøï·ÒÛM× }¯·íÃÜýåÃôÑéÔƒüàdïïû¾Ë_¹Ÿž˜ÝÙ´çg5mÓÄiÛ-½ÿýçÝë·ïxón«mý0®Ÿ®S8”€Œ£Sÿñƒ,öŒÂýÑr (” ¤Ÿ6g³=þRyýÊ£&zÎÿ3ýi¾'=1'lÃhóÁpB«k&+¤úÑè YQ% ;´i½ É‘Ê艩 Ð´) PbFMú©Çe|ç]CékÓ§ùC/V¤?¬s©|èÕZ˜e>D,Fþ…JgÕcÊ=îÛòömþøâ7§Ñ©Mëwȃ]¼ÜH°Vir&«s~X/ž.:¯ù¥&,Žþx§TUR•¶“û«n€ÖÔýÝ]ò‰l ýꃛøÄNW×xœDØP‹`¦_w«i%â>ó7Þ?Ý3Þ°®mŽÉN;‰{vиmw“lÌè¢3’(çpÓZ—¤7R„k ÏŒ–‚˜§`Ó'ëø,%g2Æïç„«³ ]|Æì+÷ÄÐæ²rwsûäði4H‡›r±gÕöÉüøe´X6 –Û.ä²ÖK ;ßvtEi|Zà˜Ò˧<­®:£ÄTk3c˜RÔU;wC¼UÊàòXªÝGǧ†gN O[´Žb@ãi)-ÛdN\PR‰©cøb#ù©â(&¤LâÄybX.ç¤lvhûÈÄËi9ͧ_íÐçzò‚{–¸'÷°ùEb€åBéd ǧÇHÙfì¶F OÌ<­ëºIUßáLÅ”feÇÐ9ßnÛËöCÍ›Z‹Èô~BY!¬Öh}}ñÛß¹Ú]¸Pþ‰eÆQwÇ£MïçeŽ?Õ:¤CPB`‹WV!lÚCΟ¾+[”Òý¸fûe¡Í¤ Œ7\ð‘Ù†Â&uee¯YÞÜ0û_jK\h\†Éã;JÜâ U³°!Ëœ+éÓž”]ZÝ^°‹WÔïTTCo1f¹óÊj•³=‹ûµév‘ÞеC²Cé×r˜W:y¨ÁÀgØÊÜo#'“ößVÿ+ÙË3âa!ó çOã…ŠƒÉÒ˺s}9‡9¬Qï#–)Û, qÛ\ÊÖæ‘ÝLK&÷Èí6D_š2û…¥ WEì.¼‡¥(G¹)ÙÚÇÆêö7S?~x°÷/KÄ‚T¹ŽÕ[öÒ´Ÿ¦z»/q’î­à+4e~ܱŠê¾º>Þ>1Æ4SØ×-_Kûí–~ŠÉhå,ÌÅ¥_hÚÃM›µ»ÛŸiƒ,svµû²Iënng³”U‰:»òx @Ï-›×¨Gsk/ÍŠvõXEéMÜAŽà™¦ú%ïò­®Î”…,=;è±ßIG¢Ø]›ò#^.ÛƒÂå…‡iYÙfø™QÌMŽ;Ôñ¤@€~]é.·Û¼¬Ú9#ñàF¦Z 霟½^îþ´ÒÞ©Ù¤L÷ðwv²góeE9aB·We§Œ¯ÆbŒsI¥ßÑ’tmÏÕœ€¶¡Õ‰»éÞtãŸâ[ kqag_Óæ‘rÈŽ~ÚÍKéù²IÐ|ôØò§•h}Am¾6Õ!¤,,¾™îIèZÒxmöÞM?ë1ˆ®ðPvs$>¡.ë·Û«ÆœX³³sý¸!ÒèšÒx#?28uô¨½¹;*nc«wYÕøøû{}‘¹uÄžÿ²ÙʱúܦåTÆêás< omÒ¸ðÕ~°ܠ¨âO$fÏ¥ ³“Š9‹î¹#jYç¿é¯ +R¥M¢˜Ý1ôi²ÖÄÇÿ† ¼"¡ó¾/"ëÏ…].‡›2ޱgn²†EéÅi³i¯×új%=Î9:Ï•¿ê@W“ÆgY3¥]ÑÇåÇÁÜ·iþKõœ†:8­(^(%—ÉyµÃß¶åÐUÄ@²ÆÚjcG€$É|]Q»ÝaX¢™ÎžÍh²áQ}­Y̸“½‘`p,R l¦^ÅPÌrçɉXîtܱ¯²G±l»–Ǩ5’M·÷µUϲÐ :Ï2ÉQålMuR]¾ZM¹å«Ý…(És1xÙK_¯]i ,ç®§$µfqOã=‡vγô†‹“–2/׆qÁ\…¸•‘6ˬÃê{ëLëC<˜Îq=I»4lTãY7vÓE²b½RM¯˜­‘Å1îL`>R3ïÓ\³92mF¥; ë0B8Üãú—sã«AEëE Ù<¼:iºén퉰òü°—Y ;0Õ¸ƒ;ÖG,"6s3Ó4çÊ‹©sì?~ÅAúFöÛã,Π»`aWçšÃžZZõÛÁ]¿!ŸQçË<Ñ/ÍW°O¬ŽgHÇæítÎØÐäa­_ªŽbÉðŠ9yyŠÃú¬rgbkéÄ ÅÈLí´÷d0Mû¯n¾"­ìÂB>¤Ìõ/ÛšáÒü9bgþh²:Ù\ÄÜøU‡”Wvm‹6þž4~ý?àæÆ÷ªÙÍâ<¨…38§^ý®~¦Â¶W/ ©ÌËÖñ@;Çêzj>ìÚImGl?5èø&è2j|ÑRPÝG[êtó3öh&Àûƒ`ÖÈõYLHí3t[èþ´r“Š–)Fò9å¦`8¥üK Nûè®ßþVÆÜ=xy1úê¹m¾ÖÕeú EÇZàœóZdv> ’9Wyw­‰…Ðæèj[¦±¼9ßß¶zÉÔ ]©.´õ¦G™¾÷[h}éå Ý¥ã!Ÿº2è‹ûc:Îá*=qí¾©¥ ã—*vÍî®Í³Ç:ÐÔ"ø`(ýY™uÅE;5”“âàzëà¸VÆuénÚI°1J”|°†ësu¥,y‹Ÿ'Ü´þb—ÆMÑÕ€®E·ECYÕq\˜ê]Ý×L×hjÌÕ-†ÞeŤx¦L/Bå¶T»Â€К’šm÷YÚè®v¿_hpÖÔ]^Ü67P¡7‡VuÇC:¬“ñ»?Ö¯ï @+KüQ<¤g½Iuò¦ÎZ°u<;ñ©¬1.æ\M[¾m{õC‰v‡Î^²0Y•Üd]fqÿA¾º1Ž’êu ²hÉLäøäNç:Ðu¹°Pôl‘ÊR´QMˆ.ÊP)UõF~ªº³he€æUqk³´êÇG­_ŒWeü–~7:ôQiãÌtÐúY˜øŽ3šlÂ÷r?—<ìv:ðšm-]Ú"¿È¡+BêðhkÕ;òe{¸ÔA0—;-ðhÿ†-è].êHbe¯:¨×†v——³~Ó_aC{¡Ð$}™@Ϥt.,zŸêÌ”rYµ l¹¬®±‹™\üŒ3sI¾ë™'Y 'ÒøkÊÂÌÕžÃSìl—¡w¥³+==Á_’7Û2Óhýã‡si0öÕ/õ•×òÍvÐÚ.Ì!•íLÙ³v9‹Qe©F¯Ñ,—¹˜_Ê•vš¶;øYAeåi¯:ôâŋ޼ÛèðÏÿ/ úó_¿Ýôðúí{VqMðó>N— •Ôò_€ @ @€ @€!@€!B€!B„!B„B„ „ @ @€!@€!B€!B„!B„!B„B„ @zNý_€%O³=‡„ûIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/button.png000066400000000000000000000453051474050137200244560ustar00rootroot00000000000000‰PNG  IHDR@@TrëtEXtSoftwareAdobe ImageReadyqÉe<&iTXtXML:com.adobe.xmp [3ËÓG5IDATxÚì½yŒ]Ù} w^­¬½¸ïû¾5 6g4V·Ü-Ûq4µ#C3£ ÀäâùÃF¸Ù <0 8ˆ'œÀ`âX¤[,ZH6ÉæV$«Š¬*²ªX k_Xd½œïTªºº¨êü{ß÷5ªß{÷{îò~÷žïþι—¥r¹ T*]Š/)}ëk_ÇOŸ ÝBéÅløó¿ù(¸Ýåå·Ä}qi­2_¹°?ìÞ½'üè—7CUU)<èy¿hû+–Õ±Ýßßš››ÃóçÏÃÂÂBøþOî”Þ{ûl a|¨?üòáD!¶=ÆvyØ.­,óÕ¸í]}ÄJ¨¯¯ 7» ÿ_ÿÒ©ò–-[ÂíÛ·CCCC<Îw‡„íÛ·‡§OŸ†#GŽ„šššÐÛÛZZZBOOOhjj [·n óóóabb)ÚÛÛÓç 6„M›6…ÑÑÑðìÙ³pàÀpÿþýPWW6nܦ§§ÃÁƒõk×Bcccعsgxùòeš^__†‡‡Ã‰'Â;wÒºð™å²nÔG\æz?~^¼xñjÓò™¶wïÞT¶ªª*ŒŒŒ¤zøýÚÚÚVÇöœ÷OîÝšš›Òz?¾~çÖÖ¶øU9\íè-õØ?²³½\[[›â¹£o$µñïRQâ{=ÎÜ^^Xxæææbl´†ÙÙÙ‹1ÆCuuuŠ}âdbb2ÅMuuUŠ/vÏôôTŠËÆÆ¦“Ä×Ò9¢>K˜÷Ù³±G­ñ}u˜ššŠõ6Çúž§8­O*O,R'ËdÚÀÀ@œÎ1µ1ý.,svv.-‹ò+uuµ©ì³g£aÇŽ1ö_Æãu(Å{cãR9–577›Žb™ãcrròS±]³Üþ(¾¼ógßþ“0ð¤/ôö m­ñÀ~îß¾>\˜øþù¿º»ºÂ.w¾÷ûq‡¿»ºÌÌÌL¸yó“t+Úñ/þÉ[i›81644ÆàHüÝwÄmžÛ¶m ]]Ýñd¿%•á„KLLMMÇ“rs<ÑoããcáI†Æ8/A¸ÿþt0 ÄÀ$~ÆÓô­[·…ÁÁÁtPìܹ#ù`:PÚÛÛb™±˜Si8sŸO¿â†g6¤ímí©ÌÁCÃóùç©,.NÐsB{øða8ËŒO¤Œï7oÞÖí¦!!Ô‡øqN|!V 1Ʋ§C‡¥xç3ÇrÔÙÙ™ö;ßsl°\D‹ïº»»SýÔÉoA9ê¥ Ó;::Òú°,‹2¬óêØŽpéAÿØ»wz‡ß¹x²)“ÄóÍÏϽ’«¢B£Ëö^¾óˆ?F~*éâß™8)—SÌÖ×oH‚Q*U%Áç×ê$Cµµ5é<Êw”Aôމås5ebz)ùùÅ‹…$X55µ©üâb9KÄòÈÈhª»¡aC’¥ۗĤ¦vy ËI~(Úâ–óù† õéÜÕÛê§ ÇÂÃñ‡°±>;lÇóçóéB£9JþÊØ®YÎü¼ó?ýã°ð"hm»vïK;„ƒ~ßÁC!ÄF03N÷îÝ+ÐКZÂ[g†Ÿ~Òýûcu&ˆΉ£¾fCÚÁEâþÆ[¡çQOØ%g(ž@9–L}מ}ÉÒ[£…7·n UÑÂk74†¦hû5¥ïP ^öËž½ûS€7ÅFdîù‹PUSŽ;ž‚¸µ}Sº‚ Î[¶†½{ö†¹|§c|íJ'Ÿú†¦X÷³PœÍ[·ÇFæ@xôèQ d®¸zmhn í›¶„½ûö…ñ(U##Ãé Œ§#Ïb=Í±Ìæè[¶mÕµõ¡º®>´Æu>×§7JÔç‰m¶ûøñãIظÿy÷/R™ØH„ÜH…ÏÛ«‰Bä# œ¬Ùœ É¾p';³gÏž¿CCCé3eºâÓ®]»ÒtdeÇŽ)VˆGæ#~È!G qLüSW¾R¦¾Ó§O'iÉ# 7Þx#É>uШäŠ:8áç?`YëÂ6ðJsì LÄ)BF½Lgݲ•±ýW—b›‹¾Kñ÷}¿Ò²¿7:ûóÛ*M~ £o4þô³_ M}vÚÀø§>öŒÌ¬Q#±zÞ©µþtåôÉ¥—þ±åÏñ*spò3³tçy†¦^¿QýãkL\ûÜVª”TŸÈš@©TþÆo_ˆÂ´#ܽy-5j44L4x\EüðÖÀgºŠrÜ|ñÈÆò¾(•¿¸ÕÌ»QòVwÑ`¯EöÁ{_8RF†?þøã$?üöìăì¿ÿ±cÇÒ•$Û‹Ð ØdY²1é\ãaA*îÞ½›dQ:sæL¸~ýz8yòdú™'ÛD—_ˆ%¯HY ®JY¤ˆu`ß³¦s‘AL"8¬ õqEŒ ݸq#- Ááab:°]ÄüÊØþèfɳÀ§cÜ6±r¨qH¥CCBãOÃDÃq…ÌU;ï9!õÉö’m &­ÂðkE§ˆû€.[º“.^¼˜²adWHÉç1AçÎKÂ@¶…LÂPäÌ Y„i"õêÕ”UBŒÈæ A9¾,–GŸyÏ>å3eȪ’„ì 2,÷Ô©SËã.Êé•õC´X_~7²–¼²Îdw–ÆS4%é!~‘5ÄycLÓÊØ–b^ØÈç£Ê] Äî ®’irCÂk‘OŒt½Ð Ò-Hf£Ò „‘`Ì cbÈÄðšÇÚ°­dJr¦9!kƒä°¿nÞ¼™ê![ÄÀf„‰¸¡Ï”Cª²0Q7²C†ˆyø#ÃDÜå§ÌƒŒ3fi,ÒØ¸¸.ŒéAh( Ù¡› êb™”ç{$l¥Ü¯ŽmYŠiåG©8hìjëjS#AƒF#ÅÕ7 ÕÊñnEu’5"ó„À"Hd‰X.Ù!ºË¨‹®3Ö9BªØ¾×Ŷˆ$RиРBƒ”(<®Àéj(24’d€Øö¢ ðÿ<ÙA6è&B‡,Cd‰Ä‚˜@>rwÂCå‘&¤ˆrÈ "x!B¤øŒdååñ‡¸P÷Ò)ÍirVˆì ¿ "ƒñʺðGY²Uy !‡L¿%¿#ëN},‡øe½/_¾üªÛ«Rb[d=$Ïi9uöpí—?KÆ… ÒU=Ù ’"CcKöàßþäJEþödSÈ„äG%äŒ bÁ˜²+Èc|Ææð—n¡Òƒü NÈ1CF Iâvw?çn*$„òtQQEÜ †œgdoÆé 3ta‘­!CÉz‘ºråJÊòGf¡!SE9ˆy,w3 ;wß±^•Û"f€DÖ;â•u]m]ºJ§KƒÆ†&?ÿ¥ÈÐÈÓxæ F¥ÁmìdPºª„°ðÛóéáû<@ùìÙ³)kCŒ 5H ƒ£bù ‹H}ȱE܆¾ô,”šWwo‘Íaù”AP(C²Ã´üì*~£| ;‚E݈ëE9¤YBfÉQ/ÝoùÁ‡¬õ"<•Û"f€DÖÆ%?‡…†Ž«ðóçϧ+l®š‹L~2ñàÔËôàJƒŒA×™>#„H²’ïèBfˆ ¤‰`z×Ãwù¶w²0ˆ Ó–.Ú2DÄòÂw¼§n2OyÐ4ñ‡\Q7¿ÉÒSw«Se‰KêbB”ÇñpûûÒìêS—V~æトaÄŠõÏOÁe+%¶Ẻ¬ Wôt/ðÊÕ? "O‘!3Àà^Ç¥ÇÓWˆ~sž£“ïþÊbƒ€ J~°ä§Ì"ÏñƒHå1=d†(ƒÐ ÌGW+û9?íœåÐMF¦†ìâ’»ÅR²?ÔKYºÅø©BÄÈ‘YʃҩŸÛõ‘,Æ&‘Í¢<ˤ\¾Ã¯’b[DYï ˆ W¾£‡†"teÓŠ Ϧ¡ÁæqñK¯,¤$:æ•x ;0ß•ŸåÃíçÈóÐ……˜ ü!EÈ3ÝJdÈÄ ”HS¾; ¡aö3Ó/䈘#Sƒñ=ãvº³¨—xdÈq{=’†D1ËË·³³NHó°ÞŸrM×å*)¶EÖÃK©xîwÜ s3Ó¡>6XRAcDãÄ"“À7³þŸJ ) K‹L]IdI 21dhˆü`B²*¼'[”Ÿt0~Fw”!Qd—è®â{1a3-ÿÑHß1 ib¹ˆ±‡¤ 9¬Ÿ¹S‘®6ÄŒe V·nÝJÒÄ{ĉòš˜˜Hõ´··§Ï6l›6m £££áÙ³gáÀáþýû¡®®.lܸ1LOO‡ƒ†k×®…ÆÆÆ°sçÎðòåË4½¾¾> ‡'N„;wî¤uá3Ëeݨ¯¹¹ùU½?/^¼xµ‹‹‹iùLÛ»wo*[UUFFFR=Äo[[[šþüùóÛpÞëìÁ°mS[8|è@Õuaë¶maxh8ìÛ¿/ü'ÿÅ]*ȹ.ß³)Ð\šMûéßûÆ7Ëõñ3ûî?û/ÿÛÔÄ¿KE‰ï•üÖ™)ö:6¶µ„ÿî_ÿ›ð?|û?//Æø#–J¥ªóaï¾}a(ÆþBÜ?m­­)Þ8Fª««c„ç ÏÃý’›cccaóæ-¡­½-ôÆãc>ÆVkKkšglìY˜œœ û÷ïÝÝã±Tã¾ÝŽ#âðñã'aç®aCý†ÐÏ/ñä’b´¶¶6®ouübŒOÆã£Ž1LOM¥8ç¸!†9Þ8þ¦¦¦ÃôÌt:®_.ƸNÇÉÜÜÜ«c‡u]Û5Ëñ£øòÎÅ“ûÓ Q1¯mmíqå'BGßhÚøššR¸yó“t …“û¶¤âòGïÇýðn¹ün–Ÿ•û£óÞõÐÞÖ¢¹PÅžõ¡59ÛɉžW~ë¹¹ùô=¿5MkëR sò LCÆ|/ÒCÀ [·nI'Z>¿xñ2žôkÓA555™uÇŽ1ÇÒôÙÙ¹´_7oÞôª^Nò³³K'&7¯CuuM˜‰ÁýüùB:‰³ÜÖÖ¶t⢱á7,—S¬ Û°¸ø2NoNe8)®×Æ6òó/ÿÅ—ÃÛg„Ÿ|ò0|ûþaøÂÁÖ´·= KÄÎ¥F¢ ¬ÛìGb¢¯¯/í»—¡*<èOܘ¡‘`›úûûÓÉ©!NŽ=šb“;û€íDFˆ3ä…ãäÉ“'©óP'Xö²Á|LCB¨ñâüðáÃI¬81?|ø0-q:tèPŠ]>Óq uvv¦F€ï‰y–ˉžïº»»SýÔÉoA9ê¥ Ó;::Òú°,‹2¬3åX.Ÿ¿õû¿ué/ÿ÷Þýé'Ýï|åâá$bMÍÕ¡§»3Œ‡'½…ùù¹P_½Î+Scé·ÿOÿåwøêÇÈOQ/ôŽ;–bŠóðüìtšvãã+1¦6†ÁÁÁxf,‡Ûw„›×¯¥XDÚ_.̇ᧃ¡¹±!Ãçg§R\ÍL‡¶–ætmjÜîÄ‹'Ddl|,4D9Ùº©=\»úËPëàœ>ÏÝ ”!®æfR,§øžW]÷ï¥xåâãqï£$?íQªc¼nZãGKÓ‡‡îxñ°u3#¡¯çQü›Òvp¬ïQ¾¦&ÚÓqÑØØºÜ‹Ëßü©Ø®YÎü¼s|ÏædPldcÜØùùçéÊ¢¶öU’(̆P[Zj@Šs0̧†ñäÞ-áNïð;;—öÇ¥•ûãÞ½{I’9 Nà±9KûíåäͶ":b2==•‚—˜@\¶mÛº„Qv6nÜ”Nö,HbAÀ#H/£…AÍ2øÛ¸±=Ö7“–Ã<4.,z°}NHÔµ¸8›Ê3?–Y__•ê§QAˆxOy’u55õIÊhÔ›šÓÉžyiÐ9 8ñq`¯Ûw{G’üÄ«ÝÐ÷áí8ÏHP&6!7Eáu±ýk‰B±-^ " ü¦KWœU)ûB¼Ù³gO: ¥Ï”éêê »víJÓ‘N¼œÐ™«S2F[ ±>¯Z© Q¢ õ>}:œsƈøã7R–‰:ˆUâ—ã:fff^ýëÌrX¶W~G „‰ß!£^¦³îÇÇOëK¦)ÊUqÑwé—;ß—;?³þu~oÎ œKÎüƒ³)ƒñ_ý«ÿ%õA‘å¸Ð;zê\ظe[ÊöÂw¿÷áçœûï ¹OJELõ‰üÿH‹—ODù½Û;~ðßü‡aû±7Ãà½+黜Z¶·OQ”ãæ“ÛÊ4Œ'ΜWzáûð*]‚¥•ÝÝÿö5Ý}EØï}áH™+Æ?þ8Éâ°oß¾$d¸RäÊ™ ¶¡¡%Ë‚ÌDaA*îÞ½›dQ:sæL¸~ýz8yòdúž‹d’.7.¼¸àé! „˜³Hë€,±¦s‘€„!8¬ õ‘ÉAnܸ‘–…àð‡01Ø.„‹ß™ Ö•zضnö—< ,e4‹vlËúÔ¸ ¤Ò!uÂpž·—§ñ~å ±¨'HºdÈ>- A…ûOÆ*¦‘X›Ð.^¼˜2ÛdW¸RÎc‚Î;—„l ™„¡È™²< ÒDVòêÕ«)«„‘ÍA‚¨‡ý‹d±<º øÌ{ö)Ÿ)Cw IÈ"ÃrO:µœÉ,§WÖÑb}‘'²x¼²Îdw(Ãg¤‡,²†ø oŒi"ûCFŠï¤˜6òùð.0©x¸¢?}`[Êö >Y~øü­÷¾Xè#YCºohØ+­‘@X ÆÌ0&†L ¯y¬ ÛJ¦$gZ²6HqsóæÍTÙ"6#LÝh|¦R•…‰º‘2DÌÃ&~º±æ!K´yóæ4eYÖ…1= •ÆìDÙ¡› êb™”ç{$ŒúÈ*Q–$^åW1­ü˜©8×TUU _ûâñOùùÇoHW×E¾:¤'‹Q[W›ýJ»:F 21ddÓCæÁ [BÖ„í¦ Œ¤È ÂÄ÷ì7„‚ï‘%ʤ»LâtäÉA–˜aºžèÒZø¿!É'²B¬™~²>dz¨ƒq<™&2vÔ‰°å.42xd›)²>t—!NÔǺñŠTñžº+$lel‹˜©@ææfScD×·Šþ£CmI~h(hŠ 2ÛN7P‘îîü¼ ˆÝDdg‘Ü=EFŒÈ¢ÃÝ)¹» áA6(D!”#ÓC¶Ù@‚—|Ko^H uS†ïY‡œ";C,"2ˆ¯¬ ”E~ò 2B™,ÄŠß’u§>–Cü²Þ—/_~Õí…¨UBl‹˜YÆyü»o¿™žÙráÂ…”àjyéÖùâBV‚.–¯œ9nr£â~{2(dBrV á±`LûÙ`Œ²ÃØþr–ùAœb†n.$‰L ƒŸs7Byº¨rƈ:¸ 9!ÎÈø >džº°ÈF‘™c=è‚»råJÊòGf¡!SE9ˆy,w3 ;wß±^•Û"f€DÖÆ‹Æ‰F„FƆ&?ÿ¥ÈpÇÙ‰ºÚºÏ=¨HÐå•»Àèªb ÂÂoÏ{¤‡ïóå³gϾzNRƒÄ08á`_"dÕ¨¹bŸR·¡#NÄY¾{‹lË_zÎVk*ød‡iˆ™b2ßÂŽ`QwÒƒ,!òd‡¨—çå²nÔ›2Dìcä…ïxOÝdžò iö?rEÝCüÑ…FY~'êbBD=|æöwêc]èÒb;èêb¼1ŒX¥'ã.? ”u¬”Ø1$²4v4 råJ™+{®þii|Š Ý)l/ "û¡Ò@ÈØ°xŽN¾û+‹ ‚h (ù=ÂB]OH#‚ÃþC¤ò˜2C”Ƀ›™îUâŒºÈØ°ºÉÈÔB\r·¤œz)K·ß#UˆY"2Ky`:õÓ‹d16‰låY&åX/¨¤ØQ€DÖ†ŒgÒpñ¬–<Еq48E††‘m¤{¤»À¤$:æ•ý@·h¾;+?ˇÛÏ‘ æ¡ 1A8øCŠI²ˆdÈÄ ”Hu!2 óoLG¼Ò?525Hß3nÁ¡;‹z‰GÖl·×#iHó±¼|;;ë„1O~Z~Ê5]s”«¤ØQ€D>‡ñÏbŒÍ,¤Æ?#²4FE&ý{Suõ¡³ãv¸ßq·â~{)Èÿ¾Òƒ¨db‚x@JȪ,ý0_Ýu…Ì,ýC‘Ãé=w”å»È(‡”KÔC½L#ëÃËB¼y 4b…Ø ZÔ‹¤ F²B÷,]m¬#Ë`:B–…XEàòÃSDƹ]’üPQ±-²þS"""Rq˜HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD Q€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDDDQ€DDDD HDDD HDDDD)5ùM©Tº_ÞM¹Ò·¾öåP*¿µ -¡ôb6üùß|Tˆ·»¼üöƒr¹|i­2_¹°?ìÞ½'<èyž = úÇC,[´í¯XVÇvhnnÏŸ? áû?¹Szïí³adt,446„ñ¡þðˇ…ØöÛå5b»´²ÌWã¶wtõ+¡¾¾.Üì,LüýK§Ê[¶l ·oß ñ8ß}Ž9jjjBooohii ===¡©©)lݺ5ÌÏχ‰‰¥8hooOŸ7lØ6mÚFGGógÏÂÂýû÷C]]]ظqc˜žž ×®] açÎáåË—iz}}}'NœwîÜIëÂg–˺Qq™ë}üøqxñâÅ«uX\\LËgÚÞ½{SÙªªª022’êá÷kkk[ÛpÞ?¹wKhjnJëý;¿q>ttt„ÖÖÖ´­ýáµRQý#;Û˵µµ)ž;úFR;ÿ.%¾×ã~ï­2qËï<;;ÆÆÆÂŽ;Òë£GÇñ™²%1–ˆÅÉÉÉË'§NJåˆß7ß|3 ¦y™‡x£A"5333éäÈ q`:ÛÉ ™ß“&1L\=z4tù#fˆgæÙµkWŒ»ñTõ±÷Äe"b”“;ß:t(Åû­[·’@±|–Ç~¯®®NÇ ¿ñÜ××—Nð;ÔK9ä©Ê'yêA–h$XgÖmelÌU•ô¥óÿÅ“ûS9¶—ùXGŽ©Þѹ й#»Êlçå;Òù?þ½[”Øþ<œØ»¹ÜÒÒšÎãì‡xIœb`é¼ZßOÅ×ê$­­-éÅ|]]mŒé¦XþÅ«¸_’ò—é¸!Æ©cnn6]4ŒŒŒ¦ønhØãz!JP{lR<77·Äßa1M¯©©NqNÜ §uá3Ë­­­‰uÎ¥õÏõNLL¦ãòWëPŸ¶2+c»f9óóÎwþôÃB\ÉæÖöÐÓy/­dyaɘ2l qïÞ½Â'´†¦–ðÖك᧟t¿ÃþX â„Ã255U¸`vr,탾Giûx??=‘L||äi ðË?ûé«€y64¬º¼?êJÁ„½sÀœ=]÷S uÄùÔØî_YûP\Öx²ü;Ÿ\Kû”† _‘rptô¥ è[H‚ÒÛÕ—•¿½y=ÉË}ú¤'­¯ÔMyb•r,—+’Ô@<ìjB¸®Ô°qP ¶¦c½Øf:W W?ïþE*s§w8\<Ù”–U>Ol755†D¡ ®ˆ=Nèìâì ±…HìÙ³'I1ÎgÊSˆÓ‘f¤„X!>™ø!cDÜ!ì_êB”(C}§OŸNÒ’3FÄòo¼‘dŸ:h,8¾êà„Ÿÿ€uf9¬ ÛÀ+qÎ9ÇU²tL-7*×+cû¯þ.Å6þ¥øû¾_iÙßýùmÊüTÚösÁÂèg¿Zã|00þ©=#3kÔˆp¬ž÷5ç–§+§O.½ô-ž apò3³tçy†~M[Ü?¾VK·vH¥˜®Èš@©TþÆo_=»ÒÕ8  bôÃ[Ÿ¹.ÊqóÅ#ËûöíKìß_½îFÉ[¢Á^‹"ìƒ÷¾p¤Lvçã?NòÃoÏþ@<Ȳðû;v,]I²½ ¢Mö™!fÒ¹<Æ Â‚Tܽ{7É¢tæÌ™pýúõpòäÉô=]Q?]n\l –¼"=d{Ö!gØ÷,‡ésss)&Ö…ú¸¸à·»qãFZ‚Ã_îzÈ]„ü¯Œínö—< |:Æm+‡wT:4$44L4S©ÊÂDÝÈ"æá qG7±Ç<È8cÖ˜Æ2!‹ë˜žÜí‹ !;tsD],“ò|„­”ûÕ±-K1­ü(@"wÐHРÑHqõMCµr¼[O’4Êd€h8HXiR€0äŒ Ÿùí;ƒð5a›éã®d)A@<8YBŒÈâbŸSLcêgD ¡ex¬äìR‚,¥±‰Ë¢”e‡¸dl\@Mæ Eȱ\²Ct—Q]g¬;r„T±}¯‹mH¤¡q¡Ë)7P4x\ÓÕPdh$ÉѰrE¥AfÙ ›9@² ‘$ b‚}”»«º˜(4!E”C^iă "Åg$+/?Ä…º)Ã÷¬CÎ ‘á7Ad#^Y—ÜMK¶*"#„àÉâ·$†Ywêc9Ä/ë}ùòåWÝ^•Û"ëá ©xxN C¾=øÂ… 骞l I‘¡±%{Ÿ)SiM!’•3.ˆczÈ® ŒñAveþÒ-´QzÄ ù!fȨ!IÜîÎàçÜM…„PžLõ!PÔÁ`È qFöñaœ2“Ÿ¹B†’õ #uåÊ•$8”åÌBCìRb^‹ÁÝ ÈÎÝw¬W%Ŷˆ ‘õ‚å+k®ÒéÒ 1¤¡ÉÏ)24ò4ž4Ð4â•âG) «Š1@ùY8¼Gzø>P>{ölÊÚ#ì3$†Áѱƒ|E¤>äŠØ¢nCGœò³PbŽåSA¡ ]`ÈÓò³«øò-ìu#^¬åd %;D½t¿å²nÔ‹ðTRl‹˜Y—‘¡©W WáçÏŸOWØ\5™üdbrVViñɃàÉÄð!D*•|G2C\ %HÓó¸¾Ë·½“…AT˜¶ôpц”!"¶¾ã=u“yʃ¦‘䊺ùMâ.4Ê—ÔÅ´üÄ\>sû;õ±.tiåÁüŒ"†+ÖŸ2ÌÃ:VJl‹˜Y‡ü@D®èé^à•«DŸ"Cf€Á½Œ=Yù`ÈJQ cÃoÎstòÝ_YlDAÉïºÈèzBž„‘ÊczJÊ 4ÈóÑÕŠ„ä§³ºÉÈÔB\r·RJö‡z)K·ß#UˆY"2KyP:õs»>’ÅØ$²Y”g™”ËwøURl‹(@"ë±áÊÝ4y +ã8˜Vdx6 v[i !HItÌ+ñÿY &?ˇÛÏ‘ æ¡ 1A8øCŠgº•È ±?J¤)ß…Ð0û™éˆr´ôÏ ´& â{Æí 8tgQ/ñÈ:-âöz$ ‰b>–—ogg æa½!?åš®9ÊURl‹(@"ëp¿ãn8zê\¨­«OÙ#²4FE&=€of!œ9s¶"A@ ò¿ï…ô *ì 21ˆ A< %dUx¥*ßu…Ì 8Lç=w”å»È(·òm¤^¦!Üü±,”§@#Vˆ ¢E½H b„@!+<°‘®6Ö‘e0!ËÂF¬"pùa‹Œ)"ã“þy›åß¶’b[d=ü§0DDD¤â0$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆ(@"""" ˆˆˆˆ$"""Rjò›R©t)¾¼ÿšr¥o}íË¡T~jZBéÅløó¿ù¨; nwyùíårùÒZe¾raؽ{OxÐó$<zô‡X¶hÛ_±¬ŽíþþþÐÜÜž?Â÷r§ôÞÛgÃÈèXhhlãCýá—' ±í1¶ËkÄvie™¯Æmïèê#VB}}]¸Ù=X˜øÿú—N•·lÙnß¾âq¾;oذ!lÚ´)ŒŽŽ†gÏž…„û÷ºº°qãÆ0==<®]»ÃÎ;ÃË—/Óôúúú0<<Nœ8îܹ“Ö…Ï,—u£>â2×ûøñãðâÅ‹Wë°¸¸˜–Ï´½{÷¦²UUUadd$ÕÃï×ÖÖ¶:¶?à¼rï–ÐÔÜ”Öûw~ã|èèè­­­i[ÿúÃk¥¢ûGv¶—kkkSÖ‡øçâødY6óÿ;>LÇq̺°ìãǧïVÆv‰…ÇŠ·ï?ûöŸ„'}¡·ça(Åÿ8 Œ= ßýÞ‡¥?úæ{adh0t‡ñý"þð¿[îîê ?¸ÜÉÇÇýñîê2¿ybédG`ptô¦øæWß.³-œã p$þî;ÂÌÌtضm[èêêŽ'û-i{ù퉉©©éØÍñD¿9Œ…'Q㼋‹/SÀ ÃÃ#q?ãiúÖ­ÛÒA@Àïܹ# ¦~{{[:`&'§Ò:pæ ŸOÈBÿ<•­ª*¥† ©©9pBã8ËŒO¤“=ßoÞ¼9 ¬Ží°:¶Y$ˆƒíÉ“'áçÝ©XÙHtC€bl—׈íÒªF"¬j$E8~ÿ­å|‚DjfffÒÉ‘*âÀt¶“2¿;'Mb˜¸8zôh:éòGÌÏ̳k×®wã©êcÿï‰/Ê DÄ('w¾?tèPŠ÷[·n%bù,ý^]]Ž ~'⹯¯/à9v¨—r4È R•OòÔƒ,ÑH°Î¬ÛÊØ™«*=èKçÿ‹'÷§rl/ó±ŽS½£s… sGv•ÙÎËw¥óü{·(±ýy8±ws¹¥¥5ÇÙñ’8ÅÀÒyµ*¾ŸŠ¯ÕI"Z[[Òy´TªJeˆSÊLÄsu]]}ŠùººÚÓM±ü‹Wq¿$å/ÓqCŒSÇÜÜlºhMñÝа!ÆõB” öØ6 ¤xnnn‰¿Ãbš^SS✸NëÂg–[[[ëœKëŸë˜˜LÇå¯Ö¡>meVÆvÍræçïü釅¸’Í­í¡§ó^ZÉòÂ’1eØ@ãÞ½{… Nh M-á­³ÃO?é~‡ý±:Ä ‡djjªpÀìäXÚ}Òöñ~~z"™øøÈÓà—öÓWólh Xuy!<~Ô•‚ {ç€!8{ºî§@ëˆ'ò©±Ý¿²ö¡þ¸¬ñdùw>¹–ö) A¾"åàèèKA;з¥·«/5*{óz’1–ûôIOZ^©›òÄ*åX.W$©xØ6Ô„(p]©aã lM Æz±Ít®6®(~Þý‹TæNïp¸x²)-«(|žØnjj +‰BA\{œÐÙÄ;Ùb ‘سgO’ bœÏ”!¦ ¦#ÍH ±B|2ñCƈ¸C686ؿԅ(Q†úNŸ>¤%gŒˆå7Þx#É>uÐXp|!2ÔÁ ?ÿëÌrX¶Wâœ+rŽ«,dé˜ZnT8®WÆö_ý]ŠmýKñ÷}¿Ò²¿7:ûóÛ”ù©´íç‚'„ÑÏ~1´Æù``üS{FfÖ¨áX=ïkÎ-OWNŸ\zé[þ<ÂàägféÎó ýš¶¸|­–níJ1]‘5€R©üß¾zv¥«q5&<Ä臷>s\”ãæ‹G6–÷íÛ—Ù¿¿z7Ü’·:Dƒ½EØï}áH™ìÎÇœä‡ßžýxeá÷?vìXº’d{D›ì 2C̤syŒ„©¸{÷n’DéÌ™3áúõëáäÉ“é{º¢~ºÜ¸Ø@,yEzÈ!÷¬CαïYÓçææRL"8¬ õqqÁowãÆ´,‡¿Üõ»..ù_ÛÝì/­ü}+µ=pT&5î©thHh$h˜hx ®¹jÏ] E…í%Û@&£¹¹)N.¤è¼ºl»»»ÃÅ‹S6Œì )ù<&ˆñ Ù2=±’3/dy¤‰ìæÕ«WSV 1"›ƒQÙ$‹åÑõÅgÞÓðò™2d'IBv–KVÊ]S¬¢Åú"Od-yeÉîP†ÏHñ‹¬!>ÈcšVÆvþ}_'¹•†òSYx˜xÄÆ€F«ä<`ކ„×"C× bŒ[i ,ˆcfC&†Wº³D2%9Ó‚œµArØ_7oÞLõ-b`3ÂDÜÐÆgÊ!UY˜¨Ù!CÄ<ü‘a"îèÆ"ö˜gÌÓX&¤±qq]Ó“»}$d‡n.@‚¨‹eRžï‘°•r¿Vl³•ÜøWúö+@" wÐHРÑHqõMCU¤ñnkA£Lˆ†“„•R€0äŒ Ÿùí;ƒð5¡a¤ Œ»R¤A<òàdd 1"‹CVˆ}JL1y¨ŸyM$„r”á=²’³OH ²”Æ&.‹R–â’±qy5™'A"KÄrÉÑ]F]t±îÈRÅöURl‹(@"ë@ãB— Rn h𸧫¡ÈÐH’¢aåŠJƒÌ²A7r€8d"3H Äû(wW!dݨᩤØ1$²4.#CS¯:®ÂÏŸ?Ÿ®°¹j.2ùÉÄ4ä<¬¬Ò ã“Á“‰á3BˆT +ùŽ.d†¸@J¦çq=|—o{' ƒ¨0méᢠ)CDl!/|Ç{ê&ó”M#)Èuó› 1Ä]h”%.©‹iù‰¹|æöwêc]èÒʃùD #V¬?e˜‡u¬”Ø1$²ùˆ\ÑÓ½À+Wÿ4ˆ4>E†Ìƒ{{²òÁ•¢@Ɔߜçè仿²Ø ˆ‚’ß#,t‘Ñõ„<#8"•Çô ””Ah棫 ÉO;g9t“‘©!;„¸än1¤”ìõR–n1¾Gª1²Dd–òKÔÏíúHc“ÈfQžeR.ßáWI±-¢‰¬wĆ+wÐP䮌ã`Z‘áÙ44Øypl¥„ %yÐ1¯ÄCþg1˜ü,n?G.˜‡.,Äáà)BžéV"ƒÄþD(‘¦|wBÃ<ìg¦#^ÈÑÒ?3К$ˆï·ƒàÐE½Ä#ë@¶ˆÛë‘4$ŠùX^¾uB‚˜‡õ†ü”kºæ(WI±-¢‰¬ÃýŽ»áè©s¡¶®>eCh hŒÈЙô¾™…pæÌÙŠ )Èÿ¾Òƒ¨°/ÈÄ 2ñ€”Uá•n¨|×2ƒà0÷ÜQ–ï"£ÜÊ´‘z™†póDzPžX!6ˆõ")ˆ…¬ðÀFºÚXG–Át„, ±ŠÀå‡-2¦ˆŒOúçm–ÛJŠm‘õðŸÂ‘ŠÃ ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆHA¨ÉoJ¥Ò¥øòþkÊ•¾õµ/‡RùE¨mh ¥³áÏÿæ£B쀸Ýåå·”ËåKk•ùÊ…ýa÷î=áAÏ“ðdèYxÐ?bÙ¢mŲ2¶ÿÕ_ÿm)Oÿ÷ë\yaa!|ÿ'wJï½}6ŒŒŽ…†Æ†0>Ô~ùp¢Ûc»¼Fl—V–ùjÜöŽ®>b%Ô××…›Ýƒ…‰ÿ¯éTyË–-áöíÛ¡¡¡!ç»ÃƒÂöíÛÃÓ§OÑ#GBMMMèíí ---¡§§'455…­[·†ùùù01±íííéó† ¦M›ÂèèhxöìY8pà@¸ÿ~¨«« 7n ÓÓÓáàÁƒáÚµk¡±±1ìܹ3¼|ù2M¯¯¯ÃÃÃáĉáÎ;i]øÌrY7êknn~UïãÇË/^­ÃââbZ>ÓöîÝ›ÊVUU…‘‘‘T¿_[[[šþüùó°ÛpÞ?¹wKhjnJëý;¿q>ttt„ÖÖÖ´­ýáµRQý#;Û˵µµ)ž;úFR;ÿ.%¾×ã~ï­2qËï<;;ÆÆÆÂŽ;Òë£GÇñ™²%1–ˆÅÉÉÉË'§NJåˆß7ß|3 ¦y™‡x£Ëc¿WWW§cƒ€ß‰xîëëK'xŽê¥ rƒTå“<õ K4¬3ëÖW>ÌU•ô¥óÿÅ“ûS9¶—ùXGŽ©Þѹ й#»Êlçå;Òù?þ½[”Øþ<œØ»¹ÜÒÒšÎãì‡xIœb`é¼ZßOÅ×ê$­­-éÅ|]]mŒé¦XþÅ«¸_’ò—é¸!Æ©cnn6]4ŒŒŒ¦ønhØãz!JP{lR<77·Äßa1M¯©©NqNÜ §uá3Ë­­­‰uÎ¥õÏõNLL¦ãòWëPŸ¶2+c»f9óóÎwþôÃB\ÉæÖöÐÓy/­dyaɘ2l qïÞ½Â'´†¦–ðÖك᧟t¿ÃþX â„Ã255U¸`vr,탾Giûx??=‘L||äi ðË?ûé«€y64¬º¼?êJÁ„½sÀœ=]÷S uÄùÔØî_YûP\Öx²ü;Ÿ\Kû”† _‘rptô¥ è[H‚ÒÛÕ—•¿½y=ÉË}ú¤'­¯ÔMyb•r,—+’Ô@<ìjB¸®Ô°qP ¶¦c­Ø^K~àg]ã%–wz‡ÃÅ“MiYEáóÄvSScXÑH âŠØã„Î~ Þɾð›#{öìIDŒó™2Ä"Át. äžød>⊌q‡lpl°© Q¢ õ>}:IKÎËo¼ñF’}ê ±àøBd¨ƒ~þÖ™å°.l¯Ä9WäWYÈÒ1µÜ¨p\s%ÌúrµüW÷‹°Üè_Š¿ïû•–ý½ÑٟߦÌO¥m?77—$ Áa]¨‹ ~»7n¤e!8ü宇Üup!@È?ëJ=lÛo ”*)ã±Î¹ pÇ·üzjÜRéÐü:Š|2¤¡%Û@&£¹¹)N®¨í§Ë¶»»;\¼x1eÃÈ®’Ïc‚¯€0m!Óƒp 9óB–!AšÈn^½z5e•#²9HõA²X]_|æ=.Ÿ)Cv$d‘a¹d5‘¡Ü5Åú!Z¬/òDFžWÖ™ìeøŒô¥BÖä1MdÈHåî=Ö!7þ•Úð+?•‰w‰Alоp°µÿ>óÝ릺^hó`ÜJaA$3Ø21¼Ò…ÄÐ’)É™䄬 ’Ãþºyófª‡l›&„n4>S©ÊÂDÝÈ"æá Ùº±æ!KĘ5¦±LHcãâº0¦'wû"HÈÝ\€Qˤ<ß#aÔ‡ìæÁ ¬#¯6ø•#û¢‰|;î*àü·RvŸ"÷Y e2@4œ $¬4„!gdøLæ…±3YEºÀ¸+YAJÄ#NF–#²8d…اÄÓ˜‡ú™ÑDB(GÞ#+9û„” Kilâ²(eÙAž—P“yB`$²D,—ìÝeÔE×ëŽ!Ulu°}Ô½r,'å*¹ñ¯ôíW€D*ºVHPú£á¢«¡ÈÐH’¢aåŠJƒÌ²A7r€8d"3H±@TØG¹» á¡‹‰òHRD9ä…l )"DŠÏHV^ˆ uS†ïY‡œ";Ão‚È F¼².üQ–lUDFÁ!“Åo‰T±îÔÇrˆ_Öûòå˯º½9–]ôØYÇIÅÃsZhòíÁt1pUO÷ ÉÏ»' »í4¶dò3e* ²)dBò£rƱ`LÙdƒ1>È¢Ì_º…6Jòƒ8!?Ä 5$‰ÛÝüœ»©Ê“i£>Š:¸ 9!ÎÈÞ >ŒÓAfò3WÈP²d¤®\¹’‡²ü‘ÙAhˆ]Ê!@Ì‹`1¸›Ù¹ûŽõºpá§b[Ä H%ËWÖ\¥Ó¥AcHC“ŸÿRdhäiP>{ölÊÚ#ì3$†Áѱƒ|ÐÍE}ȱE܆Ž8åg¡ %Ä˧ ‚BºÀ¦ågWñå[Ø,êF¼X/Ê!=ÈKvˆzÉfæ²nÔ‹ðTRl‹˜Y—‘¡©W WáçÏŸOWØ\5™üdbrVViñA"è"Ãg„©@Vò]È q” LÏãzø.ßöNQaÚÒÃER†ˆØB^øŽ÷ÔMæ)šFR+êæ7Abˆ?ºÐ(K\RÓòsùÌíïÔǺХÅvÍd|1ŒX±þ”aÖ±Rb[Ä È:ä"rEO÷¯\ýÓ Òø2 îeìÉÊCV ˆ~sž£“ïþÊbƒ€ J~°ÐEF×òŒà ˆTÓƒPR¡A>˜®V$$?íœåÐMF¦†ìâ’»ÅR²?ÔKYºÅø©BÄÈ‘YÊw©ŸÛõ‘,Æ&‘Í¢<ˤ\¾Ã¯’b[DYï ˆ Wî. ¡È]ÇÁ´"óih°óàØJ AJò c^‰‡üÏb 0ùY>Œ C.˜‡.,Äáà)BžéV"ƒÄþD(‘¦|wBÃ<ìg¦#^ÈÑÒ?3К$ˆï·ƒàÐE½Ä#ë@¶ˆÛë‘4$ŠùX^¾uB‚˜‡õ†ü”kºæ(WI±-¢‰¬ÃýŽ»áè©s¡¶®>eCh hŒÈЙô¾™…pæÌÙŠ )Èÿ¾Òƒ¨°/ÈÄ 2ñ€”Uá•n¨|×2ƒà0÷ÜQ–ï"£ÜÊ´‘z™–>ȲPžX!6ˆõ")ˆ…¬ðÀFºÚXG–Át„, ±ŠÀå‡-2¦ˆŒOúçm–ÛJŠm‘õðŸÂ‘ŠÃ ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""" ˆˆˆˆ$"""¢‰ˆˆˆ(@"""¢‰ˆˆˆ(@"""" ˆˆˆHAøÿ.”¹$‘v¢“IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/checkbutton.png000066400000000000000000000044141474050137200254500ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆtEXtSoftwareAdobe ImageReadyqÉe<®IDATxÚìš[h£iÇ›sÒæÐ$=Nš4ž¦é:ÌtÇaw™UÙ]Ä {§^¸âxå\aÁYP½EAWe/< +8{ ËÐθ¶¶i·í´9´6i“4mÓ¤iü%/İqâM^áùC?Þ~yÿçyÿÏéËgØ,—[ªè5ZA틚@ø7æû¯=ÿÜ»óÿXFËå²×ëu:ÛÛÛ@`cc£««+ þM¥RN·g+•å+úœdÆB§§§9H9«ÕÊÚíöd³Y§³-“Ér@n·ûðð°µµµT*éÆÿŸœœÜ¿ÿû|>üÏ: âùîîîX,†ÿûúú’ÉdGGG¡PЄ…T¾õ•/äöïoÄïñ´'“;f³…ƒñû}3‘({n\iµš?5¯ ÿÇG;PÝn›ŸŸG(Ñh”¸M§Óýýý ÊÿÃÃÃøÿààÀb±‹ÅŸþñvÓùWÒæË/~¹Ýëe½X[‰Ìát¥˜öövÂ1AÚY‹änzms·ÍåæHæ×·›kÞèrÁ&¿øö¹óÜW¿ÿXØõ@þ¿yc¾¶ç“O^r8Zö§ÛMçÿÁ‰s¤¨¢\ú_ýÏÍýýýP(„¤~}k®¹üüåö3&£éö[‹®,R¡Tþ2dN #Z«À6HÛ,¦ë“—°ªP8Ö¤(õtTÁâöÚþYþJ=lgñÊ­¹î@¿&üM&Ê »<Œÿ©e˜°»»‹ŒšÎ¼" Ëut˜[^˜¥3€ßææ&Jïéé9“BFÅ%g®­­±H$´ï.F¬V fëà}"µ¶&í+ ýåx=ÿß½Qêa½Úì®ûb‡¹R¿Þÿ³³³hD¦…€@*µKò\ZZ¿4=tm6› 3¨¾[[[°Ç˜ÑÑQêô… ”=6›]Ÿ&è³S•h0GMC¤ÅÿÍ¥T½zØÆæŸ¼üM}øG«³KCþ÷x<:0¯hggù³ H˜\á=77õ‰‰ ¿ßO]Q=)SF#]•Ø`0ê`ý²Õj£“8«¡·W3¯GvΪçÓ7ÙÛÛÃMÔãr¹õ?SŽ 2Æ#vÞiå(´÷îÝ›œœDæ¤J(ÒëT‡††˜*s¹U™mŽj·ÛZZ’M·ò\áÿ™§ß8T›Œ\è*Ôú=êyúÑóðw¹Ý»UásµhÈÿXTMB‘æg ƒÑàt9!ÇIܹsêL„b窄o•B¹Ò¾UWœ+:M%~Wü¯ ¶×òÐÀÀ é{Ôó¹g? øÓm`ŽUÀh„d£þÇùìÔ¢„¹œ.‹Ù QÒ&\«ý‘’5¥ï³ÆÖœušÁ’ fåu8X™Í¦ÿ\ ×k¨^=|ôoþ§eÎLþpVOCþ'¨ÂZÆ››pêíí%¨Môq0&…bÉôô´ÊœÇÇÇÔcš8xìÏç´xšn6íì$ëùÿ§õüUÒÒ?N¦éiÔÿÌžº(‹ù}>J/å–ÉA‘¢ {:5ª¬Ûíf€¼råÊùóçÙɧ$ÒññqÂZ“€zàYãÿÊëÿ¬ïšë{êŸÿy¦Æ?‘ˆ Eø£žP(Ô¨ÿIWù|^ QƒÍ‹š á§UŒŒPƒéC)ºÄåvff†²¼^/20èÑCHBŠÿ_}³¦žD"YE½†þ0}Oñg0Ôä)¢šcò? i! ¤ÍdáN§Q=² a’9!J¿Æ}ªïêêêåË—™*I­X…¤Ó““’2årðüå_ÿ^Ÿ{Ò™ }ÏÙÙþÕ©%øw÷ô`¦ü‘Žjêò? £¨i1Æ“6&cw7.í!‘’NI’ÔcõˆEZ|J@¤R)ö„Ãa²îþ~åwJ=+ S+xZø¡GdþúÙž+kî\¼zÝÙæÔd å4êz8šk-2c¼Ãî ÂZè€Èf³\©ntjdQÊ0v²íîÝ»Œ |O‡PcüBôO ŸylPñÿì3×Îæ¡/}ã%ú MÆxFýÕìÑB@‰Xt#¾Þîõ­¬¬PÎàÊUMÔ)¥ØÓ²ÑåE"Ö™Ã"q¯‰€ê‡©šz®ûêù?u©·¦¡Úæ’ïmmmáX¼úðþ§êqÕE@¥ãÃé©7˜eJ§e:õÐÅ‹©Ç”^r&~ï«‚nŽ2ìpû;éB¡X­:”zžë:Ëÿó{¢~Ͼû¢×ç×ÿðð0=2ú Æÿh‹N 5?ý«Êž˜Yím«Ñ8œŠÅ“ê{Xnô^*’TUg³YI´--ålvŸ`"XŒ§4y!k´Ïïóz¦fWù÷S7ÞÇúúövwi&ªÍþIå'n—«/øÁ¯^cÏw¾~Óf³ß|á%MøôÚMÏòò²ÏçÃítÓÁ`šnš‚ ’Ëåâ&ngRS‡Â4Ðtþ•¢449ÖÏ0 Wêq¹|ZyïÇfGæ…Â1µÙélã£ãã_õAÇ?›êéº.úð´Øßzð „€! „€@@! B@„€B@ „€! B@€B@„€! „€@@! B@„€B@ D7=«)ðk®IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/gadget.png000066400000000000000000000021671474050137200243750ustar00rootroot00000000000000‰PNG  IHDR@@ÅÛ8-tEXtSoftwareAdobe ImageReadyqÉe<!PLTEçÿÿy[A¦ˆnºœ‚в˜Ï°”¢„j¯‘w¶—}v0ìIDATxÚì›Ûv! E-ÄØnÿÿƒ ââ±ë®éx ™ôì—&Ô±GA.ò󆀤“ $ÎaUÞÿöµÿ iSŸ½´R øú¹tå-5 ®…ð/¿ª1ªcd©fÔi% |«£¤”׭ÿ ¯îkÈ|Sas  Í?­ê´7ü Õï^ìok5¼9ó Øø6¦ÿ,«üÑ-À„–Ÿ’žë€äÎâ[€ ¼Ìú,aý ™@[3ÈüÉnÒ|ò*Ð’uxø\?Ë ¸aÉ~îÄ=‘°@:jp <|›óBYH«Bþ%¬ôðÇ)Ð4?&ÐgÚ æOX :ˆAµŒã÷?$еx±wDzšC[Ü ˆ?Ý ÄŸ¤;¢e@ó3HR)S{ʦj;V ]øÄÿèMŸ+e$jÐ/ùóØùWnþì]ü™M¤5¨ûƒd©Ôz©i;8]HóÇž¿­@%~qƒ‚þì«éÀô©Ï­¬„ýŠÔÓN?^ƒczÊß÷g+Ù§F lîO¨‚®)èSþ`E j¥gnOß¾ÃæÞ‰–ø[3?dÐu‡÷s«9—)ÐÖŠÔZqAvÅý™‚È»m—¾³‚üî[ÿÚçGöáúDr¶ð,^ö¯ÑÍ/9M´úyìæ‘nÃþX?„j ïç[ï´5à¬:Ê@Nbi~ÈÙP3~«"ÅÐ0Ú‚ ƒ ]Xäó«CuØ^ g&@Sõ%Å–°Ô êkx™K¿?uöƒ,Ý¿ £èiPT ÿõ"ºEÔ/âëk#×9®/¨¿ˆžÍ0ìbP‰Âí–m0v•aHÑÏ×½.:÷»»“ªØÆ7ƒÒL`aD@ƒÖÊÅÇ«Æ2À«8-ôFbäQêÎÇ;(½!ÐH¬—ûB,¦CÔÐ ð>+z Þ S?æ¿$¼%Tÿ=†«·‡5Û72úA«ŽÓÑ+9¿! ½Ì¦Æ2Ї⮶5{ª>î“„ô¸$û£õƒ3Ð" ´ò:ÇJ.Mœ~ ãîÎÅïÍo¾äå7ºO{¡¬pÝUN™;ÁÀÔÃWZÇ ´}ƒÎy¥u¹@È•VüRý7èÌHþ¯£×Zqhá&âäOŸýQ ú1%úCÀ2ŒB!„B!„B!„B!„B!„B!„B!„B!„B!„rZþ0CWìyG IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/listbox.png000066400000000000000000000011151474050137200246160ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPtEXtSoftwareAdobe ImageReadyqÉe<ïIDATxÚìÚ!nÂ`€áŸ…C€jÒL“b¦*zƒŠªáwœ€ ¸fz@M1À11ÕÝ‚õ8È—€q8M÷E—ƒÎ?Ÿêéû>úà†€! B@€B@ „€! „€@@! B@„€B@ „€! B@€B@H@! B@Á=ÿ à*ÒßIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/posbutton.png000066400000000000000000000006531474050137200251750ustar00rootroot00000000000000‰PNG  IHDRÀ@{²ˆítEXtSoftwareAdobe ImageReadyqÉe<PLTEçÿÿ¼gϰ”|]AèØÊ@0"µ†\* ­)IDATxÚì×у DQþÿ»+E }r&©i2÷]º§µ [ò6¢§¯ßÒ¾ïÌ©”B]O~¾/pPK¤’3CEpÀÁP‚Œ"Ä/ÀP BŒ!ÀBÌpB„`8¡pBÀ„7&tJp@Â`„&D˜a„Ð 9€‹‚`–`ÀýVÀý/à `–3 n€Ü‚€ìÁ·ô'ì!°n?ÀÇ` á Œ?ð‹¨ðá€Æïb+f+ò€ã·¨Í˜¨Íà €Ç*·.•ÛŽ;€ß0ò@’ÉÑ9?s ÉÏ ã 䎔ÿ~¨WJ)¥”RJ)¥”RJ)¥”RJ)¥Ô{ 0Fö ñºÇ'•IEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/roundbutton.png000066400000000000000000000300201474050137200255120ustar00rootroot00000000000000‰PNG  IHDR@ÀìµÜÇtEXtSoftwareAdobe ImageReadyqÉe<&iTXtXML:com.adobe.xmp Bà¹Ù,€IDATxÚìYleÉyß¿ËæN6Éîf/ì}ß7·FJ4#V„HH8Hô` âäA°áÀyqÏNü`È,H¿¶6E€dM4‚MïûÆf¯Ü÷&ÙÜoίÈjµFc@Ï}~¿qï=§NUs¾ªï__Õ9]©V«•Jåíâã,ß‹m•( ÅyWW¿¾Sü½¯G Ï¿´|å ŸŠCÇNDO÷½¨,>¯ÿåJcÿŸ=³«ºmÛöøáû×¢¦¦÷ú&JÕþ¿ô‰£ÕÎÎθqãF455ŶmÛâÞ½{±yóæŒýû÷Gmmm<~ü8Ö®]=Š–––ظqcÌÍÍÅäädʧ££#ýnllŒõë×ÇèèhŒÅîÝ»ãîÝ»Q__ëÖ­‹éé騳gO\ºt)𛛣««+–––Òö†††ŽÃ‡ÇÍ›7S]øM¹ÔüZ[[_äûôéÓX\\|Q‡åååT>ÛvìØ‘ÒÖÔÔÄÈÈHʧhëÑÞÞž¶ÏÏÏÇÂÂB|û½›ñÖë'bdt<šš›bb¨/Þ0Yšûÿù×OToß’®MCC}\ë(•ýÿæ§OW±=lèСC1;;·oߎºººX³fMÚ†ícoì»uëV²)Úí»Ü´iSôôô$ûÆÎð¡;w™™xøðaìÛ·/Ù*Ç`ËØ/í‡kŽ­>þ<¥¿|ùrj”Mû£NÏž=KùQÚÛÏŸ?ŸÊÞµkWj·´Qò$oÒÓ€c¨é8¶¿¿?}RçÜÞ*d^Tä‡Eú7þä?ú{ŸÄøú/üöo|¦Úsÿ~|÷\7?ß-þÞ,“úòç_¯r¾tŒMMÍEÇ=RÙ–Âx§“aß¿ßSkg2BŒœšš.Œ­µèè7ÄÄÄxôöõEsqìòòR26Œqxx$¶lÙããiûÆ›b`` 5‚®®-…1$ìèh/ÒŒ†;•ê€ãÀ'&'’¡.5 Çó¼h€í)Íž½{b~n>¥ÅqÓˆh0--­©=xð öi&&&SgÏþ 6Dÿ@TŠœÇøøX|ã[ßßùò[ÑÐÔïÿÝRYÿåÛï–Æþ?yxc59ò¥úto?-•øâÇW ˆ:e:í¶¶¶Ô1#ØÎuAŒ`wt¼Øpooo8p u¶üaóØ3Çlݺµ°»‰”ùq}ïØiDØ("ˆý{÷îMö~ýúõ$ (Ÿò²#¢mà0¶lÙ’ìùÉ“'IäÐvÈ—t6Ä ¢ '–ÏçE‡O©[_Ñ^}üþ=“ üÎÙÑ-­-©Ìîþò ý]U®ÝŠí”n ||ÏæêÂÂb7íím©Ÿ\ZZ.ì¼9Ù¶N˜œ|–lkÍššdS\žéé©d³ÍÍ-Éþ±Ï!ÙúdŽOvX[»¦ðS©^X˜OB=b%=öLž”É6„J±¹ð ëVÅOMQ¯ÙTé±åúúº”vll´h]ÉÇ %qÖܼ’޲fgWüB[[{j§$„.¿#ªQ³ùyãÿàwcaq)ZÛ:J5úO*¶em|üÄ~¾ñsñÊÂÇ~ùãѵmgìܳ/¢fMìÝ0ª•šØº}g²…¶Â[ÛÖEûúÎØ½ï@tnêŠã'OEûº 14R8ËʚؾcW4·®Í[·ÇìübÔÔ6Äþƒ‡¢cýÆØ¹{Ol+ö϶µ®sc=~2šZÛ¢±¹5¶ïÜë;7Åæ®m±¾Hu ±aãæ8tählÞ²5¶u8}æ£1·°œŽé*ò?Xì;rìDLÏÌFËÚ¶˜(„Ssk{<+~74µen(òn)ê¹9ÖÔ5Äšú†tÇOŽÅåjl-ÎuËÖm©ì“¿ô‘×FGc»sçN©ìŸÎÐÐÐXÊè"! ¦ã¦“'úBˆNšh û-ˆÄ £J„ŽaN縧£¥ïà8¾“Bˆë‹ÈÙ¾}û G144ÇŽKý‚áÁHûäÉ“/"9tø€Yú5Iì䈎€c(AEò¨ÁD”K~Ø7õÀ0ª§ÎDšèïøÝ|<œò$¯rõÿÍÅ=oÉâçÝÕëQ°ì Q€Ð¬Ej’ÀÀ~ggç’ª««]µ§j3ëÖ­Oâgru°º²oéEd‡cB‹‹ iÐ\[[—l˜ã±÷Ñ2˜l1‚Xâ“?ÄÓ Õ$~P ¶ù¤Ï"ÄM{1 &ÿéé™âóK;«ýÃã±\Ûœnü‡ƒl®”eð/¾ð‰j{bÄ„é`éì1F¦8,!GÆNz ‘k…ÁÒèt•bØ8Ò1²ÆAГžÎ™B#ÂH‰Ì7£RûÉ3‡S‰<á,(§Ãv ùR.†O>”›GÞ4ª4êUbtƒÓÀÉñÇ÷¿ú?×ã7>}¦L[âÖµK)ÿwo–ÆþÿÑþuU®ÓO®÷$çwëñp©"@oýƒýU¢;/^|a›\ì“( ötðàÁdÇØ"Ñ"Fˆ"l•`ï´DÓˆû÷ïÇñãÇShÿÈ‘#i?¶‹íÑŽ?Ø=Ÿ)Úm:ä(5å°vŠXBàPò£Í`ïW®\IeÑ.øÃÞÙœm™öG ®äùýíõþ|¯qü¥_‘·—¥ÿ/ûdVå¯}3ʶö%ó½‹*0ˆRÿŸ}çG•27:IýãxÊç‹hÅ 762ú.Õù3eËú…×^{-‰f"(í¼&èÔ©SI0 – 8D^ˆ¸ Â$ˆ&„ø… RT aD4”í ‘EyL}ñ›ïô7ü& Iˆ„ å=ztuÚ¡š>©B‹úr߈ZòIst‡ßˆ=b áƒxc½ƒyzoµÏÃù—n d{/÷ûeºe»F 7»¬âçï1¯GÙAáЈ|á%— ¢c8Äju9E6Ê‚!A”51DbøÄ1ôDJr¤qBÔ‘ÃõºvíZʇh ›L¦ÑøM:DULäØ!BÄ1üaÂîòz ŽAŒeeBZWÔ…5=D ±“~"‚È‹2IÏ~DX÷äŸEŸesø¿Hÿ/%êû½RvpvuõuÉId‡VpÊD€èø™k/ˆ‚•5P+~yaÍ‚‡¨ ׆)°îîî$V%„G^œŒXBÅ!*”×±cÈŸc˜zB„Ž4|G¬äèS~ê&?aƒPÊbñÄ´r^@Mä ‹@"JD¹D‡˜.#/¦Î¨;âQÅù‘çGÞ/¯w+ûÀϯH¤”à\˜Á!á ÊN’ç΢²Ad±Á4âáÅ‘A¢0 „ â#OW!x˜b"=¢ QD:Ä BgJ„!ÅïY¤<þ.äMöS‡zyQ5ˆOêÂi‰Vå5@D„8D²¸—ÜGêN~”ÃTõ>wîÜ‹i/Äe¯.‚)-µ^);¼§å艓qéýÿ›œF™ÀÙ=øßï/å½'šB$$¿*!G\ö^Öæð‡(Aô ~Nù½&DÔI<îžßkÂ4"„ôLQ‘Ši(¤a ±Ã¶üî*îQ~„EÞ/êE:Db 1Ktˆ|™~Ë/>¤nä‹à¡Þˆ¨ün##@"%ç²ò^ŠŸ:º²ßL<0…S_(ݽ'⃈`jˆH ¿„ˆ ÄJ~¢ 1CtQ‚ˆ`{^×þüØ;Q„ ÛV^.Ú”"DØâ%¿©–¼‰<åEÓØ⊼ó«ˆð0…FZ쒼؆ Êëxxü}åý- iJ‹ó`ª‹õA§OŸNŠúç—ÀQG¶“!#@"%g‡C`DÏôB™ 2Àâ^œãÊÛYËBˆ ÷ž÷èä§¿²°A€ 4(ù{~ÉSOˆgöƒÊkzˆ ‘Aƒøà8¦Z¹Îù½T”Ã4‘¢C—<-†(%úC¾¤eZŒýˆ*„Q""Kyá.ùó¸>"‹µID³HO™¤ËOøqžD¶{?}ÙœˆH¤œ p\ù‰ž²= λipؼ-5ÿ— e‚(É‹ŽùÄò‹€ÉïòáñsÄÇ0……0Apð‡(B<3­D‰H ‚Ñ”ŸÎBÐp ×™í/Ä6G¤Ä~Öí p˜Î"_"5Ôh×#ÒQGyùqvê„âê ˆ"JLÍ‘./âfRÙ¦{E>ˆC)=woߊٙéh(Vw÷½R{zßÌ‹×Ü—®,¢€)-"9L%%A`‰!Bƒ€È/&$ªÂw¢EùMЈŽÏïâ‰2DÑ%¦«ØÀF˜p½Ù–ÿß$Dû؆h¢\„‘‚È¡NüæIE¦Úf”°âÿC4ñáDzÞ(Mäa˹P.÷6ÿ§ªÔŸüX$Rf*¾û@DDDʆS`"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" Q‰ˆˆˆ(€DDDD@""""¯µùK¥Ry»ø8Ë÷jµZ)Ë(λºúõâïíâÜKe/iÙßÕËËÕxó£ÇãéÓ'ñÝ _Iûïé{WeåûW?U­Ö6Åž}ûãöõ«ñÍïüí+Ûþ+«çÜ÷Rÿן8ZíììŒ7nDSSSlÛ¶-îÝ»›7oŽÁÁÁØ¿ÔÖÖÆãÇcíÚµñèÑ£hii‰7ÆÜÜ\LNN¦|:::ÒïÆÆÆX¿~}ŒŽŽÆØØXìÞ½;îÞ½õõõ±nݺ˜žžŽ={öÄ¥K—¢¹¹9ºººbii)mohhˆááá8|øpܼy3Õ…ß”KÝȯµµõE¾OŸ>ÅÅÅuX^^Nå³mÇŽ)mMMMŒŒŒ¤|8ÿööö´}~~>âÛïÝŒ£»6¥}5‹3±¥³#¾wñÑ+{ÿïèL÷écÇö¤{ù…_û§Õ­»÷ÇÌÔdô>yï|훯¬ý¿qdSÔÕÕÅáã§cx°?þâûâW?y¬Š=OMM¥?¾ckÏž=KvŒýp°_ì ûÁÖùıµ¡¡¡d£´#òÇž¯_¿žì—kÎv>'&&RÀ±?ì2Û#mŒýØ0vIû#_ÚÄÀÀ@lÚ´)•;;;›êA¹äIúçÏŸ§t”{ôèÑ”wOOOj»÷ïßOmµ¿¿?ÚÚÚb||<¥?tèPj+µ«†ñC®ÏkGv¥ƒËđ馟»ùñ÷fq-Þ,“Ú¾®!÷#äsÍš5…¡Í¥ý ­mm2žÆÆ¦”¦©©±0ÔÅâû\êÈ''Ÿ†Ö™Œ›ß‹‹KE£©+l«¦hXÏ’QoÙ²¥h4ãiûóç³É`7lXÿ"_Ɖq×Ö®IÆžë°fMmÌÌLå-¤FC¹mmí©àl¸‡ÕêrʃºpËËKÅöÖ”†MšBÞ§ú··wÛ&ãö“Ñ”¶¶¶×®]Me½ê ~r[çtß¹ímÑÞÖZжÎùg„môõõ¥N˜Ž;9pà@²A:õ'OžàSgŽ!^h'½½½)Ç΀vD§ÎqlC„>`çûöíK óàÁƒT6yïÞ½Évù°¡ uww'‡Â~lžrq죃'òÄŽ|IÃöÛ·o§úp”EêL:ÊÅ)ñ›ß‡ƒg?~bOlZßûöî~¥m€>‚ëÂ}å-EM ö÷¥ïˆ®×êUôôs033“ì9âB¼ñ™ÏÅrÑ`sôÕô«;v– Ûi/®UǦmÉ^8~xx$ææc÷®Ýi°ˆ­cƒ6tF{G{<.ÄÒ\ѯüÊç¦cÆÇÇRصkWa³R¿ÞÔ±1Öm‚¶HôôiotmíŠÆ†Æx\ˆÐââ§öxèD]á{Ö6¼úô††zÄJLB ñBß…_A¨Ñ.¦¦¦cºð´=‡Nmq8ÞúÒÇ’Ƀ꺱SÃCñs×ΨYü¼qhû†• ¦gJ%€è\RçXŒ ¸DòH± Ð7†Gƒçþó½¾¾! DoMM%ñÜÜ|2¤––æÂë ž"\è<! z|" kMeÐ ¯|¯Π#}ÒpPõøÊHcEÍcì­­-)¢2¹ã§~¤E  ’?¢±±ÑÕ‘n%íC”Ñ0Ò±œ÷tnn6‰9΃Qùf8oœÃ«>Àù¿ÜÖïܹ“®-#¤2µõà Œ8±l‰è Q :Yû6xl‘¿uëÖÔù2:ƾ¥bSØÇñüÕf³}ûöÔ~HÃèöرc+‚¬«+‰+¢L'Ož|ÉA›ö‚íâ¼rć¨ÇPí:±ÿáÇÉöɃrÉûK=hÇŒ~©3‘&ú»âïÝ_í‰çÓÏRž¯¾̦{Ç5›šºÂ)ÿÞ¿ÿOìzwõz¼’‰çS…í×ÕÄ¥ ïÇÓ'b ¿7nûF†b¡¸ö£Cƒ1Ð÷4F‡SÙ³3Sé˜׮ĨðPÔ÷ãéã‡ñèAOQæPÜ»s;–碱¾6ŠügŠõ“b¥º‹ôÄØH\»r¹¨g_<è¾£ÃÅ}KçÀýí-êP)|Àý{wŠÏR<ê鎾â\òw?N ³Ç÷lNNŽðð¾¥@ë ?ÝÞRt •åxëõñ×ï]=û*7‚ræÐÎÔI¶´ìIÂ…Lᓎ´³0ò¥æ•È@MM{êˆó¨¶vn,ŽÝÒMÇb|ääþäÆÇ‹‘ÕÒbTê:­Ñ¶¯+m_X˜Ie}ò#§’ã ƒÏâfhh¾È“¼WÓ¶ÝÛŠðóØU8+=é+•ú4ªÀ‰à˜ñRg:mŽY^žÃG§ŽŸQn /Õ *ÿ¡ƒi_ã|®?L#œÊáÕ°ø«,~>ØÖŸ $ÇÊ5fX¦¶ÎõøüÇö¥Ñ0¢‡ë€p8qâD²'¢üá8ò6íQÁuc;ÛˆŠ[·n%±Ã4ÀñãÇãòåËqäÈ‘”i8áBx'Œ0¡}"²CZyê€ü]Œd;Dn¸9ºƒ-_¹r%•Å(öIlGØq^6lHåÐ^®^½šD×K¶þ&}ÞwÏuŸsÝñ§ñêÚ÷‰ÕñžHŒÿø§žw½óª÷ûØÆ£§b]ç¦4Ý ßøÖ÷Á£ôJ^“ÊOCƒ¥_ ²rAVG†^ÒÜï*ÓALù}äðÎähþæ'Ý¥ þÖç¹Jôaß¡ciDö_ÿæÇ¥Zøo~ýÓUDB‚èá€H@°d¡Èf`€¸@P „ˆ¸AeÀ1 XÛCT‰}¤Cä/Q„Sä‡#f:Œþ±Ž˜Éö‰¢,Êe]¾S ¡E¾ˆx¢x“×6äµÜW" ¨#y°.‚ô䃠úÑíáÊËï²ö{^ƒrRÃÍö†ÇϿף\à<˜&cŽÓ(DXüÈ:»l\¸p! ¢‚DVˆŠð™×ÚÐ0E4Ñ€@&jƒÈÁn®]»–ò!R„ø9uêT3D”²BTñA‘7B‡ÑË&îÑP Ç €ˆÚ°2¨uA¬å…Ÿˆ"DÓ\ÀbnòÊ‘&ö#ÂȨùç)0>uø?ßÿK‰—@Ê ²éø˜ÃI• 8α®¾.9ý²(@0 &ˆÎð›È k~!JKùi„R;ˆ'¦´È“¨Q;‰(å2ÍAˆ¼˜:£îˆ#DçGœy ràçù+€DJÌììó䌈á4Ê™sg¨ OÀ}";ˆ ¦‰‡,†òÚ„E~4áx@ð°™ôˆ&Dé/Jœ)"„T˜…ÈÊåñ‡p!ï<ÝErTèåEÕ#>© ¤%ZEþÔ#?:L$ Ûå^Rwò£¦Ê¨÷¹sçR¤ó@ÌQöê"h‘ÒRë%²ƒÃa]Æ?~ý#é-e‚è„Ï?7®^)ݽ'šB$¡ÁµÈ——ßY‚ØØ¹sg;¬›Éï"Aô ~Nˆ"ADI¬ïaÍOž¦B„ž)*ò[yuÄdz q‚`!zƒðab&?p@dŽz‘:þ|8¤åÈ‚†Hé@‹Àbq7 ²óôõ:sæLª'‘¿•×Bˆ)-8/œN$¿³¥,0…Ct¢¾®¾”k€xò ¢€©*Ö!X)|Gô°Ÿ)+à 1¢6&D "†ÅÑŽür8¢j䇸ʮ³pᄹA”Í¡ü•÷l­,nf ±Ã6„‘l2?ÂŽÀ"o„õ"¢±„':D¾L¿åR7òÍï]ADåw‰)uh)9SAeÇž_&™§iÊDSCDbøNo‰-Ä –¼¾‡è ¢Áö¼®‡}Çbc¢0¶!>;Dˆ¸Æˆöñ¼‰<åEÓ\Äy#À1Dx˜B#-÷‰¼Ø† Êëxxüü¨ SZœS]¬:}útVÔ?¿ ”:²|ˆ‰)18;œ‹\ó“1eé"8D®CÙ@(±áðüôW6„%G°0EÆÔ¢ÃõCHå5=D†Hƒ A|pÓ«Øy±¡¦ÉˆÔB¸äi1"8ˆrò%-ÓbìGT!ĈYÊ wÉŸi\Dk“ˆf‘ž2IG½€ó$²…Ø{ùE " ‘²ò†àJr\/^,Õ¹ãqªL”q ‚(É‹Žùä:0-šŸÎ"j‚ÀàñsÄÇ0……0Apð‡(BLE$‚D$A‰hÊOg!h8{c;Â+ýw Å=Èïåa?ëv8Lg‘/‘ê@´ˆÇëiˆ(Ž£¼,Ú©"ˆcòÍ9D”˜š#]^ÄÍ¥•7¥‹(€DJ-€êêjc|fáÅËèÊBúÿ¦ê¢ûö¸{ûVéî=Qÿ/DB› ƒA@ N%DUød*?u…˜Yù’†Ówž(ËO‘‘îå7–“/ÛˆúðGYoÞ°BØ ´È‘‚0B@!V˜žeª:RÛdY°!œp”Í9±¦ˆˆâ6ÿ7 Ø7çB}H/Rf*¾û@DDDʆ Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆ(€DDDD@"""" ‘W„Úü¥R©¼]|œå{µZ­”åç]]ýúNñ÷vqî¥2€—ο´|å ŸŠJu1êšÖFeñy|ý/Pûÿì™]Õm۶ǽG½Ñ;4÷ú&JÕþ¿ô‰£ÕÎÎθqãF455ŶmÛâÞ½{±yóæŒýû÷Gmmm<~ü8Ö®]=Š–––ظqcÌÍÍÅäädʧ££#ýnllŒõë×ÇèèhŒÅîÝ»ãîÝ»Q__ëÖ­‹éé騳gO\ºt)𛛣««+–––Òö†††ŽÃ‡ÇÍ›7S]øM¹ÔüZ[[_äûôéÓX\\|Q‡åååT>ÛvìØ‘ÒÖÔÔÄÈÈHʧhëÑÞÞž¶ÏÏÏÇÂÂB|û½›ñÖë'bdt<šš›bb¨/Þ0Yšûÿù×OToß’®MCC}\ë(•ýÿæ§OW±=lèСC1;;·oߎºººX³fMÚ†ícoì»uëV²)Úí»Ü´iSôôô$ûÆÎð¡;w™™xøðaìÛ·/Ù*Ç`ËØ/í‡kŽ­>þ<¥¿|ùrj”Mû£NÏž=KùQÚÛÏŸ?ŸÊÞµkWj·´Qò$oÒÓ€c¨é8¶¿¿?}RçÜÞjWà‹7þä?ú{Ÿ”Êùý«_ÿ•è¹?¾{®ñ÷fq-Þ,“úçŸûx20:Ʀ¦æ¢ã)ŒlKa¼Óɰïßï)Œµ3¥Áˆ1À©©éÂØZ‹Ž~CLLŒGo__4Ç.//%cLJGbË–Í1>>‘¶oܸ)R#èêÚRã@2ÀŽŽö"Íxa¸S©8 ybr"êBÑQÓ€p<Ï‹ØÑÞ‘ÒìÙ»'æçæSÚššJjD4˜––ÖÔ€ù“'Ž„täK¶ãĨçAY¤¡Î¹m úøÍÀï¯ß»zöȎΘ¯ÖÄèl¹îÿ­îÇéšp?\®UY|B›Ùºukê#±§S§N¥OÄ ¶ÈµÀÞ>•lÓ Ž=šl A Ó×rìý§ri)ÒR”àÆ¾ÉŸþ{g;m< 76 CCCÉŸ`蠟Ï Ú!öNŸNåÚ ƒØ8mvjj*Ù9炘c"޶Á¹£tSäçÿàwÓ ÎÍ>÷Gÿ¹4 ø÷~ë‹Õîûbpt"~|µ§t‘ _{ãxCÀPøËªCd$‹M`|HGL'Ì'‡áa¨tútªt&Œh¯_¿ž FÀv>'&&^Œh(8‹<"¥!°ÇACA /" á„£\F!ÔƒrÉ“ô4\ÒQ. ’¼i°Œ hˆ4BÔ?FOã$}n ßøïÅï|ù­¸ï΋Ñîõ•ÆþÿáÞö*מë÷t|.n?-Õø_~ñ“éüéÀ±]lÎÛ¢CÆvÙ†-ò›4ØÛi8Ä#ÎûÄ.霉ú vèˆi´-ŽGpÒ·`‡:q®=6‰í±-··Ü¾h3Ø.ÇÒVø¤ Ð>© ΋sàxì<ßOþhc5Ú#blžvI›âøÿö¿~½Nà׎ìJ×áÆÃ¡ÒÜÿSû·V¹Öçn>äç» ‚ùR–þÿðŽ ÕµkÛÒ@–ë…$ÀV–5Å÷©âsMê[ÛÚÖ&;­TjRšì&‹Áj}}Cê¿ëëë ÁÒR¤_LÂV¢’KÉ.ñ-ä1[è ÚËÈÈh²Ë¦¦Æ¢ß^(l}%RC;km][܇崽¶vM²{ÚÝÐÐpª ¿)·®®¶Ès6Õ?ç;9¹Ò—ÿ´+þ4´©ìψ=ûÕ¯¤ ›[Û¢÷Á½R._<ýÃã±\ÛGwm*ÿàÙUQX è\„91NŒÅL§Ž²FÕcHtÞ9äˆÓ±“ž€±bT$ÇçQ)‡¢àépI‡#@ôpŸ4ÉÈ•NŸít@ˆ1>ùÃði(G9ÔañœùPîÕ«W“³ uÚ¾}{¹çõ#/öSàĨõ¤Îe‚ëÀ5âšõ^¸Uº¶Ž `Ê)Ûä‰'’í`ÿüò\íóÞŽ®ÌÑΗûý2]ƒ2E{?t˜GØòSã÷z”¬ g€S`”\&ˆŽáóbܲ`AH0íEd…¨Ÿy­ }ÑE„Ä QD×ëÚµk)"E,lF0!@ˆ(ñ›tˆª,˜È±C„èåv—×Ip bœ¨ Û(ÒÚ¸¢.D}ò´/ ±“~"‚È+GšØËâžü³Hâ³lÿéÿ¥D}¿—@ÊÎŽu8 ÚÇ”' „S&´2µ9[º{(@0äˆ ¿‰¼°vÁCÔ§ÈT.‹’+ˆƒé*¢ˆ%„Q¢B\SlŠm“×ù 4!¤# ß+9ú”ŸºÉkñJYì ž˜Ò"O¢FDž°$¢D”Ktˆµ äÅÔuG!ª8?òàüțȑ?Ï_$Rbp.L9àpPä«ÿ쟼²çŽ“$„ceaÙ ²ƒØ`šq€pÈb(¯AXä…ùyº ÁÃéMˆ"Ò!^Ò8S"D)~çÈ"åñ‡p!oÒ°Ÿ:ä¨Ñî BaÄ'uÉÓ´D«ÈŸzäˆdq/±aêN~”ÃTõ>wîÜ‹i/Äe³O¤ÌÔz ¤ìðÄÎÑ>Nãƒ|íÏÿç+{î8[¢ù2eƒh ‘üª„qyù‰Å—ßk‚PÎO""z?§ü^"jˆ$žËï5a Bz"m䇀"cÇŽ%q‚`!zƒðùà{MˆPR"R¼CZþˆì h°]Ò!€8Åândçé;êuæÌ™TO"”)bH¤Ì`udÍ()ß-͹ãäqž8èüÎŽ2ð#‚‚(`ªŠ5@D ß=ìÏ ”yBŒ¨ ‚)¿¬ÅÑŽüj¢ˆä‡¸ÊO-òÄÂ)? Œ(Áæ(Ÿ4Ò0†Øa[~w÷ÛD !°ÈáE½H‡èA,!`‰‘/ÓoùŇÔ|<Ô•ßm$bH¤Äà\F†¦~ÆÑ•…üfâ•w+•o4Ÿ¼žH ¿„ˆ ÄJ~¢ 1CtQ‚ˆ`{^×Ã>Žc±1Q„ ÛV^.Ú”"DØâ%¿kм‰<åEÓˆÄysO1Dx˜B#-vI^lCåu<<þN~Ô…)­¼˜ŸõA§OŸNŠú“†c¨#Ûɇˆˆ ‘ƒ³FôL/” ",îeíI¾e¡@Ć{Ï{tòÓ_YØ @”üÁÂSOˆgN~GU^Óƒ $ ‚ñÁqLµ"BòÛÎ)‡i2"5D‡.yZ QJô‡|IË´X~‡BŒ(Q~©"?ë#²X›D4‹ô”Iºü„çId ±‡°Q‰”¹Ž+O”íQpÞMƒÃ΋cË"Q’ó‰=0˜ŸÎÊïòáñsÄÇ0……0Apð‡(B<3­D‰ë‰ D4å§³4Ãuf; q´ò–ݶ$‚ØÏºÓYäK¤†:-âñzD"Šã(/?ÎNAC½!¿åš©9ÒåEܬQÂÞE@"%æîí[qà詨«oHÑ2‘^À7³ÇŸ(¥B òÿï…èA¨p-ˆÄ dˆD Q>™†ÊO]!fò¼Èwž(ËO‘‘QBD‰|È—mnþ( Ê[ V„ù"RF(Ä /ldª:RÛdY°!œpùe‹¬)"âÃÚŸ|o¹ßœ õ!½H™©øî)F€DDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""" ˆˆˆˆHDDDD$"""¢Q‰ˆˆˆ(€DDDD@"""¢Q‰ˆˆˆ(€DDDD^þ¿D‘2ugÜŒúIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/scrollbar.png000066400000000000000000000365571474050137200251370ustar00rootroot00000000000000‰PNG  IHDRJòY0tEXtSoftwareAdobe ImageReadyqÉe<=IDATxÚìyŒ£÷yßyß÷Íá 93œα³—W²dÉIì(ªÚQP5\¤iÁE¡€kÿhm×ð_õœº)R h\  𦵑JAÀµaYVµ»ZÍsç gxß÷Ý/ùÚÌfµÚÚ‰ùRûý`E½ó¾/Éçý½Ï÷9Þ‹ÒX¯'à•J%£0|£H ý´ŸöO®ýŸº|èü?¾u 1jöÅÐ{¾þ•ÏÇÏ¢‘ãÃ^¯g6›µZ]6›q»=‰DÂn·Çq©Dêv»óùœB.; ‡ññøŒYñ;»Ýn¥R†QZ­V¥RaÚd2‹EƒA_(!“ÉT­Vu:]§Ó›ý/tµÝnc´1þ6›Í`0`zff&bØ#‘ˆT*žžN§Ó‡£ÙlŠÍ~úýç§ £Ï¯$Èû™-šˆÐw¸ÂW¿ð9™L֨׌ÝÉñ‰ÃéH%“‹¥\.»à=''*•º×ëú|>™\~|°{>Jf ?¸s(‚ý~»êU(NXžJA¨…BA¯××ëu³Ù’N§ %„a·Û°™ÍfK.—áÏ[»Q‘ØÿÑêÕh4+++›››êÉɉËåÊçó@`kk ! ¸¸¸ˆm¬T*J¥²ÕjýÑ_¼-ûé?ôŸŸ2ú¿úÍïH>@|ã7>þÆcñç€~ÛøÅϼ25=£3˜ÎŽö÷·nÃéwvvà10ÊŸ©©©Z­§1 ÀD¡XŒ§ó]…Ø…’ ¦B«ÒÇÚ™¥RÉï÷CÒú½»c·ŸþCÿaôŸÐÐ?= £Øy÷ÆÛÒv-“É CT °Z­øóìì Í#šzt¾(„·ýÖ'>òÝëwe2©H6–蔽=ŸÇþß|ñ™d*)ó%r¹ÊDuvNû_ùäGPâá]b0~è?¿ÿ'¯ÿ¨/^²?Ô~Ä&™TúÔåuúÏŸ¿qû<ö£üæêºýç¾õýóØ?WWWÅã?T^~ùe‰äÏDnd?˜M†\:¹·¹ á±X •‚ÓéD™€žŽúß?ØÆš½A±º{÷<¬'Žcˆ¨tZ­¦Ûjìt:ç´sóÞó{!“JH$ãÏϳ³³0ýûcíÿÒ—¾$¼Þ¹s•VÃøýçþî ÀdÚ¯T*ŽŽÛ0 ϧÿ܉Ïi¿8ýç~y´ý¢ò2æPxÂõwwwï?J(“ɶ¶¶Þ †Â‚¥j…¦^¯‰d3 …‚Û`É~Ù€EÊ1ôì°_ôýö£¦Ëår"±_ðŸáŸ÷‡ÑŸ[vÂZ$³P(”H$–——···Åé?#Ù/Bÿþyx?ûEå?H¼ËO÷{ñ'€ÓÓS‡Ëƒ T (|>â¢ÏCC§ÀôôôÛ÷ÕjµHÔ«R©Gµ?™HÊer‘¨×h4¶Ûí‡Úÿ@èÚFM&“ìúÏÜF?ùáT^¯‹M§ÿŒd¿ýçù÷§÷Ú/ÿ!cN¨ ET46›M§Ó¾}Tz¿Ð)€~S¯×k4MzìÛ€r¯£Ú•;-½öl&°ÿ¡¡h¿ËåB'‘lÝþ¡ÿŸ/Qî4›-1lƒL&/—+*õhöüØiD öcüÑ’¿wü‘`?¶®R©ˆÄ~Á:?~Á»´´„Putt„ÂynnN„þ3’ý"ôŸG„þ÷Ú/ÿ™Ä¸ù1¾ŸP À3Ün·ÇãA#Œv²Ýn{½Þ $ÇÇÇ £¥Rÿ9Yâ¶Bêv;F²_g² .ƒ?Z­F¾ßø?4 ôí×éQ<@qè?’ƒü{Cç¿ø•Þ»wKONNÕ°³³³[[["ôŸ‘ì¡ÿ<`¿à3ïk¿hüçeñß.õÁåG‡€ôz=¼¹ÓéÀ-J¥R±XÄœZ­†E¿úóŒFãa´ÉA®!’c °M¥Rj?æ`MqT 2Xˆ îö?`?¶«‰Ä~ÁŸx:Øl6s¹\(BÄ™šš ƒ …âÖ­[‡C„þ3’ý"ôŸBÿ£í‰ÿLèS ?P `og»^­¨5šƒƒ}»ÝŽ&Ñår©Õjèá^h!…BCx[¾ÚBÝ$—Ëe“I¦Ñh÷övÏiÿúÕ§MkôèP öÇãqÈÒb±ìî>Æþa@×¢[$ `è?ÃÐùËÏ,¢Ø¬V«Cûa¼ð$²ÓÓSü)Nÿ9¿ýâôŸaè¬ý¢òïòÓ= _0Úœ‘¸V§-–Ê=N§³P(¬­­ Ï•½téôëV+¢R<[Ü G!µZ%†m°ÙìFý4™é?}þö/®^œžå2©Ù…%‰äµ±Û¿¸¸ƒaí9íÇÈCÆBÝ'†ñúϵ€q!8ßàóûØEëëëðŸcQúÏÓ³ÆùùÇÛ/Zÿ9§ý¢òÿsû+œ|_™qè úl6 /iµÚƒßÁ0ÕjµN§«Óõ+Ý.äj2¡MFçXBr'šÉb\ z‚³>Jµrá"Ú^DRáišívÒét2™¬N§u8’^¯Ý•XmöV«õ;¿ûe‘ØÿÒ³K^¯wßf³aØ…³ÁØ0Ýz»ÝFC¹b&†êvÊ·¸+ûé?ôŸŸ¼ƒùö7úM@è©T`ݹÛ~ÛóÒ«Ð9àÚŠÕ%|Åd2õzp®Z­AÉÐl6 ƒAE(”Ð6ÂÉT*Õ­c‘œøì¿šÓj4ÉøŠèzµ’IõPé@åb¾Õné´º|6ݬW‰DheU!w~ú³_•ý¿ý½y„NkpŒ¶ÙlN&“CIè展]4]XX0 ÿù}OTöÓè??ˆ’1ä€÷Y*òÄ€@ÿð2 ÑÿGÀ°ŽÕíDµ%´ŸöÓþɵ}Àû¥1Ð 5û! €BÈ!„0Ba „Â@!„ €B!„&B!L„B˜!„0Ba „Â@!„ €B!„&B!L„B˜!„0Ba „Â@!„ €B!„&B!L„Â@!„ €B!„&B!L„B˜!„0Ba „Â@!„ €B!„&B!L„B˜!„0Ba „Â@!äï0x¥R¼N\>˜P³°r¡ÿÐ~~áòüDÛÿÇ·&Ú~Åоþ•ÏÇÏ¢·ÿò×~é0†ýªáöžëõzf³Y«Õe³·ÛS­V\.W8|èt:°èôôÔív—Ë£Ñ`³Ù …üY,¦ÓêºÝN ÈårétÆãqçóÌq:]‰DB¡Px½žx<¡V«-s>Ÿ/•ÊøŠl6k4 Å‚V«m5›Á`ðää¤V¯[Ì,š›Ÿk6šXA&“Öjµb±¨×”JåÑÑÑüü\¡Pl6›˜o·Û㉸T"…Uù|nè?+~g·Û¸ñ_›uu:ÉõŸi«†c‡ªTªJ¥l2™›Í†ÑhJ§SƒQ"éåry“ÉÔh445vh­V…«`å^¯‹]Y©TËeø†©Z­aö>ö»L&‡·‹…B©Ói«Õj½ÞÀWT*FP©”ívÇårf2ÙV«…u°Èáp¶Ûm¬ •J[-¸Jî'—Ë3™4á]N»Ùl zøÒ¬Â'?¿`>æïÿê>×jw &ËÄm€^¯×êÏ­ÏM¨†Ÿ~ö¹“ã‡Ó‘J&ç– Æ©i?Td²X &«L.Sjtz~v^8žÊd‘§gõz]o0Ô›m™B½°‚PM¤ˆ·[Ιé™z£®ÑU|¾)H]­Õ+59™Tjwºçæf¡s‹ÅšN§µØå6ÇŒß_È T‹ÅR(•|¾éd&§Ö,6;‚£Ãå–+Õr•Ú¤Ó—B‘““)ŸÁÂçóùçæÿñÛu¥R ‰gò P"N]YÒN¨ÿx½ÞT*…\( äDyìì8äcär,B¶ÙlˆÑñxL.WÀ% ácÈí6"²A"‘jµÄt|¦­V+Vh4šX$“É0DI.‡¨Ä€ƒO°Z ˆãX K1¯(_`òJ&“3``á“ø@¼ @0+À‡QÙÀN÷ê7¿Ã(¹šOá]ød¼â[Pøûý~D¡€’J‘0&þÕ¿ýs.# ƒ« “WÍ9uÒh2ët9_¸œDÿ¹¼8]ŸqìììX†ûþó¡Ÿ{j_ðŸÍ¾ÿ4ÔêŽÏbÿ±Ýï?XÇlF9¾³ ðûà?nÁàW½^ÞÒ÷Ÿf~íC‚g"Ê÷ýG/üù£Ppþÿ˜Ë\Á&‚Ç‹ ÿEÂ…\öÍïþõñþÖäm€TúÔåuD%&“¸P+ ýû ªBåÕBÀ…1 £!-dˆ~³?= Í ¬£¸Ã[Ê\.×ÔÔdJðððPèÁñ^( •>†%`e|‚B<G{Ž`u ½™™¬‹Å°Ëˢ€n766ŽŽŽ WÄd|T·  ;;;à ºXyx̧_i*{3ûÄ¿\.{æêºQ-Ó($ôŸqùç! ³ÉK'÷67à1·ÕjõîÝ;ƒcšy €„ LTOPËââ"DùE£Ql‘Ïç럛ƒ„ ,Åjx j1ÔV?ÖÄŸ"Þ ýã!0ìG”u³³³Ð!>áýdŒiDhïààâÄüAó®@则Ð?>o‡È±Ÿ€E˜Áã»`>‹`†pb%!¦ñx;ÂŽÛjDd™DÿÙܼ÷üÇ^ȤÉýçgï?dÌ@n‡»ìîîNÜ Þ?©Õš ݨ ·Ûú2ÞÚÚBçŽr ¢Å|HÔãñ Žœ¦Q©¡Î:99–Ъ£jƒœ°&&ð^´Û‚&QèAÞX„’mmmM¯×£¸CˆD"/^„Úñˆ_ YNùÊñ!˜ƒ²«áÓPñu˜2"Ç[ðÉx/üD(ëB¡Ì@Ñ'l¾}¢ýgpœþ36ÿ!ãìÕ.&&±‚ƒÿÁeß¾w·›Ä€"et;8ðj^__‡0¢––– 4¨•v Äý ÔÂü uA?ÛÛÛØü{÷î]¸p­÷ÊÊ Þ‚EXR ‡Ã"$Á£ˆC†¯@8@ñ…® êzsDp¡Lƒ°oß¾”ËåÐ*> sb`¡ÝnǧÕjµ;wî . šÑ_¥RO´ÿ$I¹LNÿ‹ÿ1'ìr¡|À®¸ €Í¨/P§h4ˆA鉳?@W×®]C) áA3›››Ø#—.]B’ ôñ@¨ªÐ£ªòûýhØßyç€4J3hUØ·nÝÂg¢ÅÆ4& TLczs| XÈŸ¼ºº Å ºÅ÷"ÀŒ$ y¼Â ¡LÃ4ŠA¨(!]D“……D„r¹<¸ÆCIãu¢ý¯–~üð2æç°X,ØÈÒ·hNQÎ×½M‡è }4"öä]¡²†zQ=Aá(Ó UlãÝ»w…#¼1DU£úƒ *O9ʱÁ…ž¬£ÜÛÛS(>»eZrˆ3ûw (ܰ±Â†=‚Ú¡á¹¹¹ûëA€x;¾ÚƼ¾±û&¾B8©8¹þ㙞m¶šôŸŸ½ÿ|`n„œà€=­TõƒÂ9&n௃P­Õꓸ Øn· ™¡Ú:==Em!A(” aÈìàà nÂBùñ`>”†Eæ`ó!oh«A~X Í5Ús,Em‹¸ âíøÔhØÅ(Ü ð–L&ƒÚ  âí".&QBü(ÜS r¼_ŠWLàCÐË#è ý1¡PÈ í$ûO¯/Ð~öþóâ3WX†ó(þCí€;;~â6žŠvÆ×ëµIÜdƒîe”&ôÝÂÑRA®(«…¢…¢°4Qa)j(¤m( †1-q €ñ!X„ùø (šž„¤÷|öÁ P/>ß‚jBE]‰Å¨Â¼ŸñÃ’7n;Â>\8‰‡èŸJ¥'Ú FÃà(úÏü‡Œ¹@·º~ñÝëoa?MÜÀ#Q’üå7't bB$hÐ^!!«Õ*Ükã÷û7â÷Š)¨R‡zQô¡z…¶Qmll@ù(ß 1¬ƒÖ[¨òð–µµ5¨"DÕé¢6„2Ñ’£TDç‡o1™L7oÞ„PåP£Aœ¨±ÆÊ>Ÿo{{î•ñW¯^Å·£ŽÃÇbýÑÚ£†˜\ÿ9Ø?ÀVÓ~öþóúCFá1'€þA=eÿ\?ds0E¡PH¸ÕSx¤bŸp«'>¡rÅÊxŽ¥(ë xJ6áQBøóàà–@½øRØ#¹q(“IÑ(¥ì?¾ÙàâÒ¢ä­úÏÏØb×ÃŒÂcNØ£Ø7p#áÔÍd²Nœ(wšÍ‰¼¢U›pZ u¦Œ ÈO¸<"ä÷971’<ŠK…5Ãá0Š,ž%§Ee‡5b&&ð!¨ /]º)bÿ" àC„»ðèê?­{oÄŸˆƒx¦oß¾÷â‹Ðž :>>¾|ù2BìÁ"¬†¯Æ¼ ÕÜ €—Ë•z‚ý'àÄN#ôŸ±ø#ýsðì tèã&nP• ¦€Wa+&q@^¯ƒáÂáŽJA¢Â-þž0¢ÔBsl ¡bAöÂñYôéX$œ¦Ãš{{{ á¹+ø4t÷¨Îêõ:¤(tôˆw(ßð Xýàaf„ ´ó¨…ªñ9Éd±¥"JK¬ƒÅRáR+X‹Gxú›R©€1í?ØÌIl_>þCÆœà z½{q¯¤¼uë–ð8à =† Ao‰5¼b_8NẠáÒìÙÙÙÁãu‡’›=#Úö;èX u’tŽ7B–'VÃh`BTÝŠú Æüíím½9>õ¾%ÞÖÖb‡pA$>1Q28 c5XÒo Tèñ±T8© … ‰Šo¢ý›€½@ÿ‹ÿ1'€½íƒM¥JRhâ6 ‹Jµ…"tB„=jn!?lê,È‚ê 7PxE—-\YeB¨˜ƒ‰™™áª,…Þ„Guâð§t>n~~!E8À'@{4/œ¼žžÆWã£0ÁB":ŠpOP<GÕ†*Adáé`ø.¬ƒ?a^» ¢PÿY¿ú´wzF"•ÓÆâ?dÌ ÀhsD⇧‰b©vâÆÿ—^üå•K×tÓìÂýg,þCÆHÿèýŸsšqè zìàÄ‹“µÏ{-ÂïKìD3“xWÞ sîV«‚Èl6 ~5©«×ë jèE\±Xœs“ î¹—T*åÁÝzáq]±—ÁE8 ᇟ 9ĩׄ_üž‘Bƃ;òuøsðD_‰Åbňáckµ:>ë@É*•+ärY'™ì—r:])>‡ÉdÎã©Õ*LK$½×w"ðŸ+AOpÖ§Q©¾úú›“5þÿíßýk«ÍŽ¡þßýò$úÏþ›ßÆþÅNžÚnw̳RÑÿÕ—z£‘éþ6xÖÁÆåóý+8—c±8ÜF*ÅþÕÉäý‹ã‰¸Óáè_’ËY-8¤pduðópõ~’°˜¥i8Œ&OŠ8Þëuá¤årÿQ?X©Ï«5¬‹ƒ NûøøxpžÀ„O€¿aM„~á¾³L& ¿r8’^ïSÿþkŒÂãì %ƒ»™¡ák+úI|žâ|ýÆÖñ„Þ“ÐŒÀ=¸M²«V÷³YBc¨Ôd²þ…Õèl0‹l6‚rq𛎃G°)!b| FÃD ºU(ú?èÑíöÎQ|Alø­Vƒ aµZ²?ðz6BC¡G…k4jTpf³ŸƒEV«Að%áü!¬j6ƒ3‡z|i£Qž)øÏ…МvÏÃ7ë…ÜùéÏ~yBý'?s¹\õj%“êÁ°Óe’®\!Ï®ÒAbÓª•…BÉ‹ffü’ngw{5Äi</Bz\ÛÓoݺ­:i¤v¥L ; ï£{899AV€‹ÆNO¦|¾t2¡Ñj j*álóiäxvnî4r3`ðÉ©ÄC¸Àf1%“ Y.W£]kµ[:­.ŸM7ëÕD"ñOw®Otí…žšø@˜âzÑþÉ…þCÿùi¸õ­ÿ8Ñö{^zõ’!„q8©dr~a©\._¸t9rr2åó÷z]ŸÏ矛?>ØÕêϭωć`†ß®+•J …Âëõ¦R)N[(ôz=4 1¤Ó)¥R ah4¨·Ùl©Õê+KZñØÿÑãìì æ]½zussóääÄårAà [[[0áÉb±@½•J‘èŸÿC³xì§ÿÐþ>Šè‡"Xìeø;Ip‚/~æ“ɨ3˜ÎŽöo_³^¯ï¯^CwAù355U«Õà4ýš"ÆD¡XŒ§ó]…n5à»Á€9—Ö6Õ…€ÇnªÏ8vvv¬NÃíwÖ\Á~€‰|¾Mf.ç Wƒb°ÿ×§e`j hµZ¨Ú`?¶Ó¨4±;<`?¶1›ÍbMD+¿ßÿ«?A öÓè?O‡PqÀªzJÌ9Æÿáï}mgë¦}þ€¨ú­;€èQÅλ7Þ–¶k™L5‚j€Õjýöw%÷â¿àES"΄:B&•>uyý»×ïÊdR‘l,Ñ){3{<¬ýr¹ì™«ëÉTR4æKär9$Š ô<ö£—_]]E‰‡w‰Áø¡ÿüþŸ¼~ßì’D’ìÿÿ^ü½où­O|D„þóçoÜ>§ý¿ùâ3"ôŸ?øÖ÷Ïiÿ+Ÿüˆxüç±4›N‹6€>盘Hæ ¢>d6réäÞæF0D|‰Åb(œNç}ýÿõƒŽˆók¿à8::BlB§‰Øt÷î¼öıKP©µZM·ÕˆzçœöonÞ{þc/dR ‰ä`ìöÏÎÎB½èßßkÿ—¾ô%¬€×ì¿sç*k¬,†ñúO¿.;‡K`wˆÓîDŠç´_œþ#¸Êc×Ç:¢òŸ‰ “ŽLø O¸þîî®ËåB év»Õjõýë¡g …Bív{yy¹Ùl*•JµZ#žÍ( £Ú +ûQŽj?zñØ/øÏù×§ÿŒd¿ýg$ûEå?Hи uá_¾\upzzêpy0 ¦ÏçÛÚÚzû¨4t)L êùp6ëõzáj2™lzzúí{‡©1ªW¥Rj2‘”Ëä"Q¯ÑhDpÀþa5÷¥ØFM&“ìúÏÏ-;1ÎŽDXáÙ Eœþ3’ý"ôØ/¸Ê£ËÁ~ñøÏ£(&Ä@ßX¯÷ès"ê´Z-¤ˆŠ& H$ríÚµ÷® a”ËåV«e³ÙÐoêõzƒA/†m@9£P(Fµ¯N§S öët:Ø3ªýèÐ(ˆÁþûýç<ë‹ÙÎo¿8ýçüö‹ÇÞ/€þ—ÿñ-—ÕŒû§qÑÐ?¾uðÆãoüÆÇº é$DpÀ*J‹Å‚à%¼óÎ;Ífó?ýÏÿû@„?Q“¢Ê…BÙlvp¹q«öŠ2h`Tûa|³ÕE–ÉÇö?PÇáχØß‹ýCÿAu)}ÿ;’°è•O~DÌþs~ûÅé?°ÿý-ûÅá?“Î0Ä¿ý üCd?Ï?1Dÿ‚z•ªþ1Í»wï¢:xÄ©!Ôz»»»SSSðž^¯Z«ÕER*rƒA;¢ý½B^'—`³PAd?VËårb°ÿÿ‘ä±²øýçÜö‹ÔÎi¿xü烑w2ÿ™¤·Ú¹Þ"’«Wû Þsxxˆ®ÐëõÂþè/Þ~èaPáHú§_zþàà V«i4F”¢Ø…<•JÏ»çG²ÿê‡ {¢0Ækk -ùÐþ‡qÂáÝ¡ýkkkûûû"±ÿ~ÿù'?§}è‘tÌüõð!D[‘ûÏ9í­ÿÀþ‡ž Àœûí‰ÿ t>â(УßÛ =å =%ž0‰©«hooÏãñ@Ãp •Jõè7œžž¶ÛíÕÕÕd2‰ 1lÔk6›Gµÿ`ÿ ÑhˆÁ~¨×ï÷j?ʽz]ôþ ßoÍH$"~ÿ9§ý¢õŸsÚ/ÿ!cN2™L…~peØùö¸ ‹^¿qhµZc±˜B¡ÉI0™LŠ"nTûUjÕâÒ¢ì—Ëå(â†ö?úîÐ~Tܱ8Æÿoüñ¥Ûí¾ôìÒGÒñç3ófŒ¿Ïç³ÿœß~qúÏÐþ÷žCzÀ~ñøó! ¸šqøM>Ÿ?Ï{*•ÊÜÜ\¢Üi6[â°¼\®¨Ô£Ùðb§1ØñO$£Ž?B&DbÿÐfffZ­‡8ÆåË—ªŽŽŽP8‹ÖÎo¿8ýçüö‹ÇȘjx†ÛíþÖ›;½D8’þñn·Tª›Íq[!u»#Ù¯3ÙDr/ŒVÛ?è,Œÿcïäïöí×é€ìúp Èï÷·ÛíW>éIÇħ~ñòÉÉI&“Á:³³³[[["ôŸ‘ì¡ÿ<`ÿðL^b¿hü‡Œ9 dÐëõ#ysÿ6È\C$Ç@áý*•zTûñ®R©$’C(F£q¤ûòa?bS±X‰ý‚ÿt:„Œ* Üû×Aá955  Å­[·‡ýg$ûEè?#Ù/ÿ!cN{;ÛõjE=x–ˆô|?+‘¯¶P7‰DÀårÙd’i4ÚóÛ¿~õi“Å=:ƒýñx²´X,’ó=ËEèúQt‹DÀCÿ98Ø·Ûíˆ5.—ëìììãýgMöwÇo}âYÌždwzzŠh%NÿÙÛÛ=§ýâôŸÝÝíÜé½ö‹ÊȘ€Ñæ<ˆÄµ:íµ€q!8_©Tà¡P³³³séÒ%xÜ &©Õêx¶¸ŽBjµJ Û`³Ùúi2óô¬q~þñö/®^œžå2©Ù…%‰äµ±Û¿¸¸X(`í9íÇÈCÆBÝ'†ñúO±TFèq:Øœµµ5ØÿáJE°zzZ°}}þs,JÿA&8ý¢õŸsÚ/6ÿ!ãl…gV¬Ì8ô}6›3ŽfO–­Kî„c­VÒÍ6öjµZ§ÓûÁ»»L¥Â=â‘DÒ+KîÝÄbŠJ‡Ëƒ „EhdèêEF¸I§Ó°Ûrçί×{rr‚EˆGoß;D‰*š"Z‡ƒÐ S©”N§EHÒëõÈ6›-N ®Ñhý›Í,¿²¤ÿ\ z4õÒÊ…• ›Í&Üi[ä ,šÍ¦™àr&“ÅF…œNI¯×îJj•²\®øÜ—¿&ÿÁP«TêQý'™HÊerFÀ'=Àû¿ø™WL&£Î`:;Ú¿}ýMDÏïýÕk¨w, Ê74ðÔ(‘0& Åb<ï*t«—x4|mE°Òn·Qf"WµZk›Í„"‹Pèa‹’PÝØ:IŠ¡†å^†øxxxxíÚ5„!Ër¹ƒæ}aaåº{¬†HŠðŠ˜%‘¤Çýç\FlB£ÑX]xì¦úŒ…³Õiø±ÿ8k.ƒà?ù|!šÌ:]ήÅã?BsZ&?CP¯V2©zÄl6[.æ[í–N«ËgÓÍz{!´²ª;?ýÙ/‹Äßñ:ªÿàµÓÒ3²Dˆ&ïÞx[Ú®e2‡Ã¡`µZñ'j (Õ| ¹U&•>uyý»×ïÊdR‘l† áÿ•}ôÊÑ\L"šcÐb%Äév»ßyçì P¤!WAØXºE ‰D𺹹‰”†$‡WÑl‚T§ìÍxìñxü±þ#—Ëž¹ºžL%Eã>øÏãxí¢ò /ð¨þ㙞m¶šŒ€OzøÀ\4¹‚è¯TõÉÞ½{ŠEˆ„¤Àééi©TZYYé­º{×n·Cç»»»èÉ  Z«Õ9ìÜx…B!7´#úO¯/0>áÈ8c§IO¡ˆbÙh4¢gÏçó¨”Ãá0ºx—Ë…šîääªFAE³³³‚æåršŽi·ÛµZmTÿQ*•n‡£Ç@ÆÝ…)P#¤‹ª 2F+€ =‹F~aa‹ Øh4êõz±B2™L¥R*•Òh4qôˆL&“É0Çëñrô˜È˜DsU(ÚØØ@óõ¢pÃütº‚7—ËáϹ¹¹B¡àp8Z­$=??§Ó)Ž©Tʨ!FõŸƒƒƒ½½=ŽÞ“^}rÆ¿” ôì‘H2Öét':zÔn½^¯Z­¢”Ûßß7›ÍKKKP/fb5ÌAùÒO’ªpŸø@ÇÕ®=û¼FEù³ ã¦Õl%SÉÙÙYtè(Ö„†Àb±øý~$›Íæñx*•J£ÑÀ"ŸÏ©£ \‚ÅÇxþåÿÅbiTÿ‘Ëä=ú‡`ìx¼‡Ý­–J%hñx<‘H@Ã(ß ^áÆ"(<›ÍFánþ\.ÏÑ#&“Ñ`0Œê?åJ%ráè11“ÏåÑ•oooçóy¨wffF*•šL¦ããckSSSÐv,S*•z½þäädssS­Ö`Ž©Õjr¹lTÿAÒ@>àè11#—ËQÎËd2¤þZ2™f³ Å`zzzKÑé‡Ãa¬ ã-ïâè©TÖn·GõƒÑ€u8zO8< 4~Òé´Íé‚2———s¹d £LCŸ.<=M«Õ&“ÉþOÕê³³3§ÓF+öàQäIGxÌÆ¨þ“ËæØAvãgvn.›É¢.+ v»=»Íf›››ƒ¤¡^È=fBÛôââ" ÿÁ­ÿ%½ÞÀÑ#ð–J¥<ªÿ ìÀ"Žw&—›Ì&hR§ÓAèζ··ãñxÿw Z­|>/hKOOO»Ýn±XÜû£¨Õª=gÐÉ”*e6—åè11ƒ®Üjµº\.ôéÊ P,J6ŸÏ×ëõ äããc¬éñx `L`&4œç³\ˆDR,t:ý¨þƒ©‚£Ç@ÆŒÁ`8ž 7púý~ôì©T Îd2(âP²™L&È{ª¶X,èî[­&:zŽQ©ÔðŠQý§^«éu|47hÌ¥2šá(m$Ai6??£mo4ú¿g€¥Â/4¨ÕjÌž5 G$ƒ„«Œê?£Qè'P©L*M§Ó¯÷A¨Ð'еv»‹Å¼^ï¥K—Þ}÷ÝååeÌAM§ÐëIìv;GÀk¤£û¤×C’àè11c³Ûô½ðSÌhäÖÑ¡ÏÍÍÕjµ+W®@«ÂÏ”oooc¦pG>Ÿo·[• OzáÉ?#ùO½QG2àè=áð>€ñÓl4å2¹ßïï?Ümp[*8Ts˜³··‡â®^¯¯¬¬T«Uü‰EX-™Ljµºr¹ÌÑ#NTÿYZ½¸³u£Ç@Æ â¸ðä4ìÝn·Pè_Ûƒª­ÙlBÃr¹eD‡×ÖÖ¹ÝîR¬`6›"Ùð .2TÿQ*•S¾)‰d‹ø$ÃC@¢àìììøøim;:ôÁ~É…óu˜^XX€z/\¸pttÏÎÎb~¯×­VýIŸ\.?ªÿt:\6Ç¡c c]¹Ëå ƒ©T êE{Ž|‰¢Fóz½¨ãvwwñº±±a41¼Óél·;¼ ˆ”ÿp¡Qý§Õjñ* ÂC@ãâDívzzª×ë¡I‹Å‚:=;úôl6 ¡:Ž™™HÂFY‡•‰D½^3›Í’$O<é @ÕT:Vàè± cšLg2 …¢ÝnCÀ­ðøÆb±X*•êõ:äò­ÿ#®^/Zx«ÕŠâN"‘bŽç”ËåQýG*•Æb1Ž3(Ùì6ÚsHTxb»ðËx››Ã|´ö@ NC½èô+• ä²N&“sôÜF¯7Œê?³³³È=&2fòùŸ£Ç@ÆL¡P€DN'd‰Jmmm Z5™LÂ|¨éÐ"@Û›››H*•êÝwßE³ŸÍæŠE> ŽHêõšF£Õ¢ÑèÙÙG €Œ™é™iéõ€½½½p8 IC·ËËË1ZxtîhíѶétý[Àìv›B¡äèøIÿgÁFô¿ßß a ãå0|(•I…ç´@½ÕjõÒ¥K(ÖÜn7” ­ éµy¨×ëõ¢i@¯Ói9z$“ÉÂ=FõüiµY9zO8< 4~”*e­Z¨Ñj—G"‘l6ǯ]»C´»»»V«U&“a>Úy»Ýž9͵Û-ŽÃ4›ÍZM:’ÿ`>¦9zLdÜ-¼ÙÒh6Ð’w»Ý\.'<¯å[±XDW©TP¬¡¾;99ÁÌùùywX"Z­îá÷/Žä?X­TäÂ?éðÐø.ÍÞØØhµZ(ÍVVVÖ××F p: …rÕjµ.Ž µZíp8ÐÔcš£GšÍ–^¯ÙdÒÁÉÂ@ÆJÿ'œ$ý3xÂå@õz=¤+\¶±¼¼\«õŸùƒ‚nvvöÞ½{ét…^·ÛAqÇÑ#Vkÿ$ð¨þƒž½'?wïÞu¸=J¥êÝÛÛƒb¡R½^¿°°pxx ÏÌÌ$“It èâm6›ðC¯.—{ðÜG>îI'#,ÏØGòŸ™ù…VÎÀŒtåR©Ôív£Cw¹\2™Ì`0  LÃÌÕÕUa¤+ÌÝÚÚ‚€S©¤PÙ‘'œÁs$£úOø œËói LdÜ@¥¾):ôN§ƒ­R©ÈårˆðkèèK¥¤ Ig³YTphÞ‘6T*Þ@$ƒÑb±Žê?&³I§Õqô˜È˜nQ»A¢˜@™• ?ï‡9°ðG¨Z¸Ö•Ô‹ôzC»Ýáè‘^¯+<ùg$ÿ±ÛìH =&2fªÕªðähuœÉd>Ùñôô4“É@Õhä!l«ÕŠâ•æcM—ËÉÑ#Íf ÿ¨þ“H&B¡Gï ‡'ÇZ­F±e ÏðR©TB‡E ˜ açóyä‰áÕŸkkkùÆMˆœ£G y­V·kÔ#ùO!_ˆUø8qvdÜd³YTm‹-9*µH´P( %Édháëõ:4 CÞX¤P([-Þ Lú$fTÿQkÔ¼ˆ€°?(Ó„ßoJ§Ó+++P¯^¯?;;ûЇ>T.—‰„ÙlFq§T*u:ª9„~§ÓÑ¿ 4Wç>á ®o·;£úÏÒÒJ½Â›ÉÙq³··‡&àæÍ›¨ÎB¡¦!i4ò@àÎ;˜€¶ãñ8J9Tp¨òPÁAê•J•7‚JÁ*£úðÊÑc cÆãñ ~Ô©ÿƒ®[[[FC8\‹>½×ë¡£Çëòò2^‹Åb4-õ):< L$&“Q¥RŽê?©djqq‘£÷„ÃC@ã§ÀbC½†öEt+ÜŃ §ÓY«Õ0ªF’°ÙlÐùéé)æÇûvó$0éŸÐh´£úÕf­”øƒBìȸ1 ‘hdssóÞ½{(ÓЪooo›Ífh¹-<Ô‹iÔtáp8ŸÏ#î+ ›?èA€J¥Îå²£úO±P4›ø“¢ìȸAÌ»ªZÝ¿’¯÷c ÛV« Ëd2Tmèܧ¦¦Pî¡‘Ÿ››³Ûí(÷8zD©Tx<Þ…ûHþã™ñWK¼ ”7ùB^¸M¯‰DÂb±@Éét:‹AÏ/^DÕÖétnß¾-\È!üŒp2™lµx''‘Ôjõn·3ªÿì pô˜È˜Ñëôá£Ñxtt433£Õj…SvP2äFQÊÕjµ .@ψûx…¤Gx (‘ ~ë15ªÿ¨Ô*T=&2f„{v„g¹ ps¹\gggèÙ5 ¢|*•ÂüP(„âñ¸Á`ÀüÁ“ßM(ô8z¤^¯Éd²QýÇåt FŽ3¨Ú,f ê²ùùyxwwW¸Y¿^¯C·¨ãæææŠÅ" ={½^tú&“ ë#mpôš0ŒŸ½½=Hôðð‚„†OOOc±XµZžž†ŒM&ÓÑÑÑÕ«Wççç¡a,E}·ººŠ¦Ï"’ÁÓ@á'£úÏÁþúŽ÷>ÉTh”JÈúìv»¨æ–––„ø…Bhê›ÍæÍ›7ÑÅû|>«Õ …£”s:y˜À¤ …|TÿQ©U‹K< Ì@Æp‘†p^UÂz«Õºqã„*ÌG‡/_¾¼¾¾.üÀ7dl·Ûù£ðdäåreTÿ øÍ%ò¤Ã“ÀãG£ÑÈår·Û-òûýhÒ½^¯dp“p§ÓòXŠ‚.“É`ÙÙÙ­­­R©n6[8zD©„Š¥n·c$ÿÑ™lè8zìÈØ+8št¨ZÕét¨×‰D±XÄ+år9tñGGGZ­6 bµ[·n hžÇp J¥jµzTÿÁ»°&Gï çÿ 0D;1øÉUâIEND®B`‚simutrans-124.3/themes.src/pak192comic/pak192comicxxl/theme.dat000066400000000000000000000120711474050137200242230ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=> scrollbar.0.6 Image[7]=> scrollbar.1.6 Image[8]=> scrollbar.0.7 # scrollbar knob left center right Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # back up and down Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.2 Image[14]=> scrollbar.2.1 # knob up and down Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.5 Image[17]=> scrollbar.2.4 # scrollbar back up center down Image[18]=> scrollbar.2.6 Image[19]=> scrollbar.3.6 Image[20]=> scrollbar.2.7 # scrollbar knob up center down Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- --simutrans-124.3/themes.src/pak64german/000077500000000000000000000000001474050137200177455ustar00rootroot00000000000000simutrans-124.3/themes.src/pak64german/files/000077500000000000000000000000001474050137200210475ustar00rootroot00000000000000simutrans-124.3/themes.src/pak64german/files/back.png000066400000000000000000000070031474050137200224550ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûP ÊIDATxÚíœÛoéy‡y¦fDr†‘%Ú”å•cl6l,Ú -ú‡å/(» 7¹Ðöª½/P䀤Ý`‘ÃfmËÖZ¶l®(“rÈÎp†§þ†Þæ2(üb2ù€ß³ A¶Èò÷>óÈá—ío·BÞ•\Ú¿Q DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D"" ÁËÚé½´wç“ýq¾Ph5[A¸X…Ñz³)—Ëþ|ž/ä;w»OwN:Aàú·F£žÉå‚ùÜjXaz®[©VõJ% aYÖÁÕ‹/õƒñdÔ>lFCëà a5¯.Ÿ&ºþOþåß¿ÿ£¦½‹ïN!í_@NÖª[®ëerÙL>_.—ü¹Ÿ/[ÍËÇ_tîtÝ™;9Š®iÖÃÕj:›†Y.ïáÁ™Ìaîßô4MÇ#ãèßàéÍ£ö峋ä×WåK˜Ù¨»ž[­V ¹\¹Pð]/ŸËâr¿xò(Ž®çía©T*k¢[©xÊt26ê $’p!ºøÆ±íRyo½Z!+Ø£‘e5Í&¢‹Ô’ôúiïŸåBDÍz#“Í!C8î å¦Z3.?:;»ïL&ÞlŠësÆãJ¥ŠÇÛöÈ0êøUNJEgê”´½( ‘<œ‘ c Ó¼~ù2Š"”˜¤×O{ÿ¤(/P«}\*£Eà:SüѬ×Q,Îϸ®‹ëÑmÛ㑦iøiàyˆîz»Î¬×åRiµÙ ›©VªQTk5Ç™˜žb‡h\ ³Ž’^?íý“¢¼@¨h8D±¹~þÜ0îlæy.ª’ÇàÍ›|.7(¾Çàñ™M\VBd€0Ô÷÷ýo8ŽƒÇ¯–K4ËqåBt=·Ý>N~}µQ^ ¹A«Tq¹ßö^— rYoŽN%‡ÑÉ:kD4“ÙUsµZ]ß÷ÃÅz»1k*”®é(@¥r)îWö4ÈÕÜÙ´ut…QÒë§½R”( Z¥‚+þ«ë•ZͲ,ô%ÚÇ'¸èƒ Ø=*‹TÆá]b ÃE>›Ã„íz3}_·Ç¶¶¯Gñ¤ÝD\µ=Ý›ÍZGíõz…AÒë§½R”su¹Xì¿zeÔ܃þíM>—ïtî8ÎÉc½Ù U ^¬—þGn}´Y4(®ïA Íï~Å›Ï;wï:ñ†#X» <›ôúiïŸåB8·}\âV£Ñ¿ù e¥{ÿ=ÏC2Ël6š¶‡ë~½ZúÁB¯TÃ0*”K…BÙ $@[3¶Gççß°‡ƒ|¾ˆx·Ð2¯ÂÁ^Å~$»~Úû'EyP Jå2ºŠÁp€Ø4š‡ƒþ féõrY©V‘3âÊó0 ¡•KÅU´DƒŸFË£“ç8~ô7ƒ7·ÈÓ™ƒоøA`Z2rOÒë§½R”$_,í!bi`&êߌ‡ÃL6WœÖa†î<Ž.º“ø-ˆpQ.ï¡ÅKÅ""úðƒoõz¯3lÛn4Q€ûöqý lp&“¤×O{ÿ¤(/ÒC¨,š®÷{¯§“1ÊaÖ1¡Ë@Óº‹î #´ï{hlшhú>’†ó‡Þïõ^ç³yg<î|­VÝ{÷Çö!w]÷/°¾ê(/æçŠi–ŠegêŠ%«yXÈåœÙÕÑÍl·(%ñ‹xf}0|S5Íh÷NçÙ½÷®¯¯tm½°up†!V{ø~œ0ÐÛâ;-JI¯ŸöþIQ^ t':®~ÌÓj¶[LJ¥bÁŸÏÑá¶ÖÛ RÈàMüæ%"‡† 2J÷ô^ïÕõîõ½)ºcä†Lf{þðý«Ë‹B.‹y< ù|CVÒë§½R”µGàǯ쵎3¹º]à­¼×ï÷1B_½øª LhµÛ×/_ + Y~àçsÙó‡ß¼|üEæë×”½|±/ñ_Òë§½R”hw5¸”Íz}Ù¢)1ÍF¡TŒßBßNÝÓÓ‹'QPPeP\ÐÍôozVÃB ÂSð0”³ûýá·èc0!ê¨S¨YÈvÒë§½R”ÿD»fµõåmtíñý).n„°Ó¹{ùô¢{z†H¯—+´)q¡i¶WÓ0}ž/ÎÎ|þ»ÏÐùÆ÷]L|6·K ÛÌ®¾$½¾ê(/¦b´ˆ1Æi„ÙÞ•MÓÑðî¢û¤}|âÇi S5 DõÅŸûf½è"t»gŸ}úß•šßžG·\FÙÚ­¿œ“ôúiïŸå•*Ƶã°ó"çÍfAàÇѽxÜ:<Œû]ÇEßïõÚ;ˆn5~/s† ‚è~úëO0“Wk5D– /ÁÃW«U´ -š¤×O{ÿ¤(/Pü–ä2²šÍëW/-ëÀ™9Ú¾Þít¯ž]4¬¤Šh±ƒ`8èwâèÎK´ºˆ7‚ýÉ/~zvvß4MÄÉ*˜5® ºhžƒ…%½~Úû'E}0N·ÛWÏ/‘У”J%šË/ŸVj5}¿‚TFÑppÛ¹sŠ߃:’Ë·OŽþ_ÿùÑÇ‹~¹!˜ÏKÚžiÔãÛÄâÆ%Eš˜JXÂë§½R”(ŽîÕó³ûçöîÞäøÃ—Ïp­ÇËj‰êóutgS]ÓÃ`§´ŽŽùóŸ}ïþ) ˆwàzZµòö^‹él¿Ž¼ÙTMÓ_`øZ'½~Úû'Ey®¯®P;ÐÛ¢j A¹xü¨sz¯s§›‰ïJŽnooÞfLCȘ}ÚÇw>ýŸ_}ïïÿ1Žî|>ugˆn«u?ÆöȈûåõ×-ðfƒy*éõÓÞ?)Ê Ô>9q§ST ”ËgçFË0ð<Äo:tïžâ*GëÍdÛG'¿ûìÓï~üwÞÜCeñvïz€Áàv<¡§y{k˜3™¬WkD7î‹^?íý“¢¼@ƒÑ0“Gì²ý›×Ý{gù\ü*‹ƒáyµÆq¦oß4hŸt>ÿãï?úîǼ¿ëKxd—þW½ÛþMóð¨P(˜¦áLÆx0Æ«Á›[Ó²’^?íý“¢ü µòÞzß¾Ž2@ƃñv3¶‡ÝÓ{|¤õvo:'˧O>üöwÆ“* êbìa\YNŽï”‹%mß¾Yo¶­fÓ¶GÕJü9Ф×O{ÿ¤(ŸÖÛøõ\„UÈîú^#Uà*ïßÞà§š^Áå~yùô›~{lâ›u6ÛR|'W#z\†Nï!Ô†iÂ,…è¢Äèñë~3tÍI¯ŸöþIQ^ ­VøZ©T//UkUD4ðý~ï5þÒ¨7Z»FøáÃúý¾;‹ß‚ÂÒ~:¶ín÷ s¸V©ôv7ë–ç¹™lÎÅàýït&½¾Ò(/ÐÛ£·ÚÇ—ÏŸµO*5Ý+ D&—CÑ©Vªøþüýz½WzüÙ¿mÜš —är¨;gïGë%’šÙj­†‰ÝÝ}Ò4ZFˆ.Fn}OOzý´÷OŠòYÖAe¿rýâ9¾"78¶=u&(6ñ­Û *ÎÙùƒ«çÏv/O1û  Uâ3ÂvçNàÏÑ£55åÆªÕ*I|7êt‚Ô‚é=éõÓÞ?)Ê7цٸ¼¼Ðtã1®ì©;3ªµø£}?žÝ?¿øâ˜wc‘7¶å2âúöƒ¡þÜ7jFÕˆoN]­ÖÔ]m_Oìöa±·šÍ¤×O{ÿ¤(ŸpõÇ/7¬`ᇾñ| tQ>ñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ÿð| tQ^ ž”.Ê ÄóÒEyx>Pº¨/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQþƒ…<(]”Ï@<(]”(ÃóREyx>Pº(/ÏJå›hž”.…üó¾ÿ£¦ýk¼;?ù·ÿøs?þåoÞuá'ÿ¯G%½þ_=Ùþv›öï@Fùˆ¤ ""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "âÃ"&q¼³™IEND®B`‚simutrans-124.3/themes.src/pak64german/files/button.png000066400000000000000000000040651474050137200230750ustar00rootroot00000000000000‰PNG  IHDR@[*ÉÇgAMA± üa pHYsÃÃÇo¨d×IDATx^íÚAŠI€Ñ>«+×îEE¼€'tãFã1jˆf²È Cß xÌ´™›ø£ªã[ôÃïÛívøòåËýÿ+Š{>û/ûðáÃÅjF;{ÿþýíÝ»w··oßÞ^½zµ|ggóù׌ó?[ÍhgçÏ~ñó?ŸÍ=€>}úôè<œ‚±çñ%X=+8νj¾V3ÚÙø% €ºÆ Æùæùì®?Ãùì‹èãÇwó€v7ö<1¾«ç»;Ÿ}ÑêB(@×ó¯9æ0οø;°?ÃqîUûBTŒ=»8¬f´3´þTœgQ<ÿrü cÿe—¿‚š]èzþ5«™@…"­~! ëù׬fˆ´ú… €®ç_³š T ÒꂺžÍj&P!€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žrs  'Ož\÷|6ö_÷ôéÓÛ³gÏnÏŸ?_Îhg/^¼¸X½³³yÿ5çÏÿøy5£ÍóX½³³yÿ5÷:.ƒóp Æ—X=+8ö_%€®¿VïìlÞ͘ÁñùùòåóÙÝØóaõ|wçý=Ð?ã‹0hwã‹X=ßÝyÿEèÏ ±dÞÍ1‡ñùýúõe6cÏÅ}ŽýW=œãg| VCÚÙ¸ôÎVïìlÞZ_ˆóþkγxóæÍåç‚âžÏÆþËü4ièïbÁ¼ÿšÕL B‘&€Úâ¼ÿšÕL B‘&€Úâ¼ÿšÕL B‘&€Úâ¼ÿšÕL B9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä ç@¿~ýº<,(îùlì¿ìÇ«íìû÷ï·o߾ݾ~ýzûüùóòÍç_3Îÿl5£?ûÅÏÿ|þ5÷úùóç£óp ƞǗ`õ¬à8÷ªùBXÍhgã—€ê3ç˜ç³»rü ç³/z  ó…0hwcÏcã‹°z¾»óÙ­.„t=ÿšcãü‹¿Ëñ3ç^õð·/DÅØ³ €ÃjF;@ëÏAÅyÅó/ÇÏ0ö_æ Iû×…P €®ç_³š T ÒꂺžÍj&P!€H«_èzþ5«™@…"­~! ëù׬fÈ@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9—ëüsÁX«¯°®k5£ÍkõÎάëZÍhgóZ½³³úºбÎÃ)8ÖêYu]«íl^«wvV_ó æùìî¼VÏwW_t^ó€vw^«ç»³®k5£ÍkõÎÎêkžÃy6ÇZ=+¨¯‡ÿÿ{_«!íl^«wvf]×jF;›×êÕ×<‹óÏc­þ½¢¾ü4ióZ½³³y­ÞÙY}­fˆ´y­ÞÙÙ¼Vï쬾V3 DÚ¼Vïìl^«wvV_«™@…"m^«wv6¯Õ;;«¯ÕL B9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä ævûÅuñGah³IEND®B`‚simutrans-124.3/themes.src/pak64german/files/checkbutton.png000066400000000000000000000017051474050137200240710ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa pHYsÃÃÇo¨dgIDATx^íÙÝK“aÇñç? : : :‘" DËÒ`à Eka. iÎWlk³9ÝÆ³[Ù^Ô!d’½!$ôrÐAýër{ÐqEîŽë྿‹ÏÈ}èwÛý¨õ»^oU©T …ÂBc–––èkvÀp•åÜn.þ5NŸö;›0\<·m{µ1™L&‹±¦9¨T*e³YŠf¾1ápx®1“““‘Hdÿ˜±Ê?ÊÙ_vòçBô{„ÌíÎv“ü3[Óì°è‡ÿê“N§Ùas8RÏøø¸ßï…Bû;:¤ž»Ûwn¿½Ø °£ROsŒmh/ ¶õÐø|¾`0غi޶õ¯=c£lÑmëiý‚Ø¢ öR©ghhh`` uÓ*õônô\Zu±EC8( [4U­Vë¡¡›5Û×®ú¾ªX‰ÔÂl];º5;u(L4eëÚYÅbQ±žþþþ‰‰ ¶¯Ý³eÅzο˼^¯Çã¡û5;`¸¹õÙ›%ïÅçÎÎ\_¾öhå!;`8ºNÐsq¹1ÉdÒÀ[3Ãø/Dˆ A@ ‚€@"Dˆ A@ ‚€@"Dˆ A@ ‚€@"Dˆ A@ ‚€@"Dˆ A@ ‚€@"Dˆ A@ ‚€@zýê2Aà.o{xIEND®B`‚simutrans-124.3/themes.src/pak64german/files/compass-iso.png000066400000000000000000000076031474050137200240200ustar00rootroot00000000000000‰PNG  IHDR@õ]©¾ pHYsÃÃÇo¨d5IDATxÚí][sÇÞ_ìBe—ËoöƒßL!-¯ù P±ƒË©Š“8N¨"å ©r¥p\Æ"è„a$@ŠŒ¹(` aq «Õ}‘IەĘû?tæk©W³³Ó3Ý=³3==ûÐÈ!»Ã~ç;÷s¶•Y¿aC¦zª§zÒyè-½³äÔà©K ðì†ÌÜÓ5„ýïVàJ~pžfü­6üÐ…Â /¥ñ/‘='¦Hm½ùXÌd(áv4täSƒ\Ãá§¿…ÏŽ:1ÿØãd]]6UøËcç‘ b$ðúeOψ®ãfçÑq#ñ×®D}æèÓ†ŸE=æèê8'MøK^ÄN óÜ<1-ê³ÃóòL@0ÓðƒWÆ-/ÊßÂŰñð³3Wó¬Q%Y”°+ʞϦ‰ µ¾Ýøý^oÀï-àúG¾M¤7t’ ¯.ë-aIÅÿA{®ÄøE£º1øÿ–+Q~QüN½¹¹ù-cñ»¾Ñ5àôÞNFƒÈòz³kž!NqDItzMÁ¾A†”üûº§‰Óøe²¹äãŸ"Nå—ÉfœY#ν'žLŒþËàç>ÄM’P¸¾t*—-÷ž`Râ÷ü;ñ'ËÍ@ÆoŸ ¸w~ &á—J!™8vqA¯”hÅë}Øx‰Œ?ÿ"qKáÂH¡˜t 舚ðŒ)¼ùø§OùUñ—•O­!;zŒÂïù`^*‰³ÿdèäõø¦½¤Pó\Iê¦J/•ÂÙJüWfQÃç?J7“ñ;ÿn¥‹*~{) ji¼sžØpüAÞ÷Ã~9ùÙºûªxRr“Eäߤø¯Vÿå‰ïÈv%düàÂ4üiç¿RøCk6ÙM‰8ÏyÙò~[¦N– inü¤¾Žëõå¤ÀÇÑl±+Áá/ÂÆŸ—2~óðÇÏ¿³Ùl ~)ˆ4˜8xæ®ëyo¶Ÿ¸ àèýѲ×N=$¿ß9¤ùEü‚Jpðóàø¿œ|H¶ì–2~Õ¦¬ŽøUø¿XÅ_9o$ªˆÌ ;¿Xl ýø€üjò¸«ZïŽÔF,åÚeÕ:²à½2°RAÑÏ”àØyüµÿ¸´ñÓf¬øÓΔø3•ê@ÛËÞ.ôy àäÒ8¹2ó=. ž6a"XUíÀÚ•€EüC~¾¬ñ›‚_wþE&PI¯$ÑN´Ó t]'{/»  ÿAl?t]|„Ë¢X§t}uÉÂð†ºñ' øm¼S;üÊK(² Êœ@ç…y*€m3ÿ hº;HÚ¯’ß4\VÎkÔ—kÈ~F¦G.ΓÞû·Kð¾6IÞlT6~L^’Œ?müë¤ÿÊBK•8s dð? äô×Sd[ûp ðè¸Æ±—-;–±+Açùz¿ž$l»ÈøQ÷%šùÿûÄ}Ò§þ€·Ìä9mÍ#Àó:­Ñݲ“ ¤Ý—–HçÙ»ÊÆÏ›´$•ÿ%røì\¬ø§BªŠ‹ó~ËõÄ’Ïð«~v¦Ç–iüaà¯ò¿ÌœøCH…*+ðöö›ÊàéxEƒoc©ÌjJ ";:^M8þ*ÿËülj?!¨Ì¬  *¸õÝN£2³µcQ«€¿Êÿ2–8ñ‡– ©Ô±þ4§}‡ŒŸh$MW…w)’޼Nžï"cGÿBòÛÉXO“Ô. øqfþÕC¦>“Þ¥(à±Âˆ-&‘E–É/ŽXŠÿÉ7ÿšäv¿NF÷ü‚äÿú[2qºYh†ŠE lSá`¯úe¶>ã)âXä˜üç'$¿ÿM2ºó’ûègÖÏWIn×f’oÝBeã·C‘tü8cG? £{ß ·v½Fn}üsúsôÀï¨lLçg¢¿äÛ·Z2ø%Ý÷É·m%ãÝÇ¢ÿÞŒo0áK XcÄÁ6›×LQŠž³HÏ5l²ÎÆÕc9Æ«Y‚ ·ƒ¯W®AÊð?(øŽµ è«¸7­ÊÁ’ £×ØÔüPô\ãë¥Ü¯8ÆöÓ9.ÿX J:~:èzÿ–Là½ô¿ø•Þ„ ðf¬0:×VR]D;¾°õ§EðËÿ½‘zE¯Å lOa„wpËŠòK!á÷ÚêBª‹hgÇ 0Y +BiÄ[œJ:~D;ÿÈŠPñ‡ŒÀoe»îüo¤Yщþ‘HñKßc†+Œ°¿Ì;XmÄv\0ãćg@PïÒ”·èù6•DC¤D¨‹Ü&°5…ÕI¿ƒ{Ö*6÷ÄÏÛîB½{‹f?Î `S1 B_Í1tÈq0+ÇÂÌé„áÇ‚‹“Ô»HyK¹·ý´J"ôEÜøÇÖdÒùG¿ %oyö³,ôE¢ä_îj¤ù!¡²è–›| rA²+ùp–r@Iœ‹P&Âõ>È©dÅOW\-Ò@#¤‚\–”•@ˆ–r@I ,P¦@P¦$ᇳvãÎNÞéø‹ü[ÁAÂÉ?‚ ‚JÒù‡s/OÿWeà€ %ÿÒi†WÂÒ'ùHkÞÑæ'BzÈR%7! ½rK»Ž‰Þ«4ÁÎ7Ò»,h`•‰Qò¯ÜõDãÁ­!Fü–SyÚèqk¡ ‚%^F€F kº ûJ©Ò]_ü8hô¬6ÁJÓ4ˆ’ŽÇ ?½«QЖ úµn¡bÖ4vsh4kßÅøYsÞ\± ,ÍÐ Žšÿ@oÆ£6–Àˆ£ ùq`Ô %# +*Â0ؘÄKµ`ä²Vƒñ ~àƒ£C¶ƒ’)1¢" #-øáèíÐzØrˆŠ0 ŒA1*ÆÈ˜ç0jÖ?Fµ<ãLjé$ÌÊvh?ŒŽ‚_¡¶5ÿá,ýø€.'`IÁ|©]±êb¤Æn¯á K:-¨à.ô;P{½&Iø±¤%ƒýÔÅH™°e(/'0¤+ÿW½¿ˆ­í:-uÐï@_ ¥ñ‰37cá?TAÈÏ€¡9"úZ»Ökø›jeñËÊÊ4üEþy†âátüMÅBÆoäÿ¡íB«@èª_ÀÐi\¿ªÌLÁ_¿¤ÀдÂ/iüÀ¢ÿ¡_MTP}/¾Š©ƒ¨â÷j–¥‘IÃaN_E×ÿùE% :ðZê§šÊ`VD:¤‚ªŸÝ¹(“6üEþ¢'sZàWüì:ð+ùtÁ¡y$p-SR• Nn 3iÁ_äßclægH¸–.‰Æƒ§¸ùW~#."Ä…„Èo¦[S¼ÅÑgâ‚Æ¨‰ ?¶æ¼gLÇþy‹3¢… jãÀ YU; ØnÄÖlœú¯,\E„|ºÕtw®Nb{ 4"3dÞ³£NÃÆ’´ã÷›¡{Väø‡¿ düt«QýW€*ùXdÀ6V±¿ ÀB°H!;KgÿÆŽˆ»â•Â/;K7 ¿ð,Ýa`øe5‘ãW0~,2a›QýWy¨’l1aÑMئÂB…êL¿¶*Š‘®ø£yE‚_Á DÊ¿‚ñi¨ÿÒ@Ý£4³Ì®îQ{  xÕQVm¼Té™*þñ+Œ×j+Ž^ig¡VSþ¥^Œ_=Ƭ_bpöªƒvšñ+œ+E~ÚñãÄ‚_ T?~õz» :ñ_1ò1žàyc|ƒÉM^÷›Étœ‡ HÜÊ'~Œ?lü2÷+3â_r<™ýy„=–Àw˜íÀ×+ý>ƒLç9ÌT¸Š_ü÷Ðñ‡<–Ô…¡u ,w"Ek0\``€Ì×E„°¯{*´(Pů!~ƒÜ×=þc„'Iã_è¬TWA¸eE¶+ÒŒ K’ˆÿÃÆK¡à¿qçÒ±£§"ˆ`øý›q¡ñ_¡ „úïû„šŠé®XÂ=kª÷¸‰4傤‚ºãçÕåM{Èøó/’ÅL&þú Á»@÷¼õUïŽ^ýwFZüšÖŸèÌânè¸ûöÿ­— Ýôž½úïÌÔ;š:×õ}ÈoÚÿ ྗüÐsf_ÐìéŒt ÍE{Àœ ÿÚü'lúïŒÃÛqÈ0ÅàÝóÐÐíúÏßúo‹Ï«ñI²Ÿ[û$yÀm ÿž¸½·<ŸÆí¾ny^ø4ß·÷â–çÓ¸Ý×-Ï ^ €TuªÊ’!©3?ÔJV¤ÎüP+Y‘:óC­dEê̵’©3?ÔJV¤ÎüP+Y‘:óC­´žÓŠ?ïK5hõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TK#üü7€ç”’Cú×HäŸB"ÿù§Ìóÿð zx“ ¼F9/å—š9Eèj~+”“üS('ù§PNçüï€P+¿:ž(§TÓʯNõK#džP$¿:ž(§TÓʯŽ'Ê)Õ´ò«ã‰rJ5­üêx¢œRM+¿:ž(§TÓʯÎo }ÖÄé瓃*KÊùˆš¿©=<ˆÂâŸæ·%s>â“5™óß1ÿ»@‹ ­­Ö³(ɳ”MÕÇ÷i~­¥Q¶Ç÷iþY”äYʦêãû4¿Ö‡Òƒ(Ûãû4¿3™S‹Ì¬­ÖÎdN-2³¶Z;“9µÈÌÚj=Ë» ×ÚjŸõá)•¥Ì©µ¶ZÇç‹_!¤ê ¡Ì©µ¶ZÇg}x …É`R-i«u>–¾J‡RuPæÔZ[­ã³>lHÍ©µ¶ZÇg}ØšSkmµŽÏú°!5§ÖÚjŸõá. €ÜÊ©¾--§¶rªoKË©­œêSƒ=ûij+§ú¶´œÚÊ©¾--§¶rªoKË©­œêÛÒrj+§úƒ\éHÕ÷DikN9Rõ=QÚšSŽTýq¤g³å”#Uߥ­9åHÕ÷DikN9Rõ=QÚšSŽT}O”¶æ”#UŠË M“ ¼FQ[N™ä_€¢¶œ2É¿Em9e’ŠÚrÊ4ÉÿjdÐP˪R3ÝPH©EU©™n(¤Ô¢ªÔL7RjQUj¦ )µ¨*5Ó …”ZT•šé†BJ-ªJÍtC!¥U¥fŽðóߤ懦©æ‡¦©ÜÖR®mI5?84ÝH5?84ÝH5?84ÝH5?84ÝH5?84×óÃh˜„Þ“ÉŸþ<»5Ùí¾ny>Íà}/ €¿ Bÿ×°[ŸÝîë–çÓÌÞ—pèÿöl²Ï­}’¬dðÖ €Û@ÿ?ÍÎnwÏÅJBô¿ùŸ†p²ÿ¡V‚'´ùwv í2r¨#`܆ì?oáס«"û°¸ëOôd}·Aý—x ¿ˆKK…º±²!:ññÝKZÙ|ÀmPÿy¿‹ºJK++{¢³Rk5G=YÓ Àm ÿ‚–>³²'U­´-ËZqaËbÁ!ô~‘kþ €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦0¶äûûa"U²`¶ˆùIEND®B`‚simutrans-124.3/themes.src/pak64german/files/display_factory_label.png000066400000000000000000000177701474050137200261240ustar00rootroot00000000000000‰PNG  IHDRÀëí½fzTXtRaw profile type exifxÚíW[’ã6 üç)r$ð8|Vå9~”ì±=YÏnU¾Ö‹GA4º…ùÏß+ü…ëÁ!‰Z.9ø¤’ WœØq~ê>Ò‘öñö¡ëøi>ôÛ¿Sc9ßÇ—óä5*;ôVNvñÃüÞ˜{ô}ÿ­5lí=c5e„:_›ºmqŸá¾S¾´¸–ÅO`B÷·àkÈêÔ‚ÐðíTˆ×¢Dƒ*-š{ìÔábâXqÂÜ9îI‹Ê…ûF2ù—+0Ñrß°§Èw_h/[Žöj†•áV&#<òíoøîk9àDË~Æ ~1{°á†#çGÜh]A•àÛ÷ñã¸FÀ&e§HA`Ûi¢ ýP‚¸Ž¸Q0žt!—„K œ¡€E¡L‡2+i¨Âuމ p’8lŒ}i<¢´oeaLÌCÌ€„ÄØ€e+%Aþh2äP•(ID²¨˜©9æ”%ç¬ÙE±jÔT4«ªiÑjÑ’‰eS3+V —Ñ”’‹+¥ÔŠ5+,W<]qC­[l©Ih¹i³VZíHŸžºôܵ[/½q@?F:l”Q'M¤ÒLSfž:m–YRmŰҒ•—.[eÕ;j¬Oßo Fj¼‘òõŽfUo&ÈåD3†*B@\$4;f‡QJìÈ9fGüEa8)ŽÙ G ¦I,‹nØ>uä~ · énü«È‡î›È=ãö µQ·dzЃzD°oq³ @Ke°©¶[UFf[Ê˵‘ÊLuŽÕZqmšØoDýŒ½ JBut”ËŠ¿ãi\Öš£,“±V춯Q}&IWî ‚æ×XH×VÙ£vuTne`qß² ¯†µF³ùÌhØNkkj!¿î€/Âlë¾26ÝOyXz¹PÉLîÿìçc«“²  È;^‡Ÿ¹m+ûA©M8ɳëiâ¶çýhXç“xNdÈ‚ ¢…Ü4ÈSAцÀmŸ»³s&èíÇX4™Ð#ƒY“ا‘&Ö†Œ)räÁq½ ë0¶ ©Ë@ª¡;â}D4@BÂíäãHuUÍ•jJŠ5†8Ë*‰ 3v’¯Ê)Oˆ%påΔˆ7§‰H 41êæÝ‡ÏK ³µÍ‹ õ¿¸`'¾bBxƒ è(.#BNMtiÕö$aám=E³È‹Št‡›¢Â~C+Wf,¸Ç”1JGÓ@bhÃWÂÛœ·Å(«Ö™ÝšZh[φ'/TØCêµëþ,þg.#›Vp¥Ëσë6@ºù1šw)`ÖÜ@#·Ç`íÞ"؈NÑEx|YêÌö€ç^'œ…‡S©#;ñO:?5Ñü5UP Ð@·Mæø &Û¿g2¼ró]“ˆµ^gì"­w$­'dNBúŽ1!ÓÐ?V´¡è%ñ614î¼m5¡Ù;9]Y¦oGßÒÕ¯Ç?†þ7C ¹F ÿ$6S‰Þð®„iCCPICC profilexœ}‘;HÃP†ÿ¦Š*‚vqÈP,øBµ E¨j…VLnú‚& IŠ‹£àZpð±XupqÖÕÁU ®.NŠ.Râ¹I¡EŒ'\òñßóÿÜ{. ÔJL³ÚÆM·Íd<&¦3«bÇ+èB}ã2³Œ9IJÀ·¾î©›ê.ʳüûþ¬5k1 Ï2ô‰7ˆ§7mƒó>q˜d•øœxÔ¤?r]ñøsÞeg†ÍTrž8L,æ[XiaV05â)∪é”/¤=V9oqÖJÖ8'¿a(«¯,sÖâXÄ$ˆPPA%؈Ò_'ÅB’öc>þA×/‘K!WŒ (CƒìúÁßà÷l­Üä„—Ší/Žó1 tìõªã|;Ný>WzÓ_®3Ÿ¤W›ZäèÝ.®›š²\îO†lÊ®¤%ärÀû=S迺׼¹5öqú¤hV‰ààÉSöºÏ½;[çöoOc~?^ÁrŸGÙ‘«2iTXtXML:com.adobe.xmp c74bKGDç}?ž[³ pHYs  šœtIMEç ;$˜î›W”IDATxÚíסja†áošµÜB]db#cjGæª#öj"&2"WG*Bï zŠînwË ¥{žÇ aÝ?çç¤É~c’&5Œ©­ eMö]†n6dÑ·% › ¥`Ñ·£@’ŒÕ/CEëw¾ ]ÿ6—ÿêì8ççç™N§%†áå©î¿ÏoËÜ<¾no6b޶ÿX_þ¯_¦N¦€÷ï.2¿lDñ `óõÿôñÃæòŸœÖøt³¡ì°¾üÛ›€-øwš$c7’$óË6Irý0dÑ·M…¸û<Ž•àîþvç½'É¢o׳qh³þ«1ÉÑê™­g ¤ˆß]îo•åÈ\Àm Å·@@@@@@@Ê›T?€»û[S€ @@@@@@@ø‹<¿-“$óËÖɱ~×ëwO-Íê9v³ag NN7¿´—§ŒÆ ¹~øñþ}»=¸É¾A¸:;Nrát x~[ææñÕAßv¶€Õ— ÄW › 6€ŸïÜ׿ðÐ,úv\] 'Sïâ»üÅ7€mc¡a°¸øÀñù%tjˆâ“øIEND®B`‚simutrans-124.3/themes.src/pak64german/files/display_marker_label.png000066400000000000000000000175231474050137200257320ustar00rootroot00000000000000‰PNG  IHDRÀëí½f_zTXtRaw profile type exifxÚíW[vä( ýg³ !$–ÃóœÙÁ,®°+IU*é®ôçŒ} ˜‡ºzæ?¯ðž˜9‡$j¹ä|àI%•XѰã|ê.éH»¼=t•wý¡ß†#º5Ÿ¿–¯U·~º#sPEK>²‹µû’.úö@èÚˆ£ˆÆ¸•‹Çs€.õ<Ö‘‹éÇ#´yÖãv;¿àë¦ýFäñ?)¤7ãdâ%óÅûÇ+„’â@i»­»¼ y&§·§€£å¬¦§“~ ­Xá­¯)ü äüV?í$ÏQÙ¢ÿ°s²«ïûq";9z¾k [ûÌ8EM¢ÎסnGÜ-ÌkØÂ·¶Öò¡ø$t¿¯A«;PBÃÛ©P\‹ ª´hîºS‹)Î{äÝi¬±Ä¾‘LþÒŠÊ…ÐŒÜ7ì‰ã/´·-G{7Ã΃05ˆ–¼ü†W¬å€¹,û)+ð£ l8r^b¡u U¶€oïãã¸2—²›H`ÛI¢ ½{Þ@3& êÓ\HÇE"ÂÖf`‰€±P¦CcT"ÒPë‘Sl@€Dâ“11g`cÑ·Æ¥=5JDw@?œΰ0B`¥$ÐMªÂ’D$‹ŠI‘ ‡˜²äœ5»S¬Êš‚ŠfU5-Z-™X65³bµÄÂpšRrÑb¥”Z±gåŠÕjm±qKMBËM›µÒj‡úôÔ¥ç®ÝzéuÄÁþcä¡ÃFuÒ„*Í4eæ©Óf™uAÕ‡•–¬¼tÙ*«¾¡vÁúé}5ºP‹)Ÿ¨o¨¡WõF‚܈cÀbHÄÕ!€BGÇì0J):rŽÙQàþX"˜Çl#Ó¤(‹nØ…x"êÈýnAÓnñ§È‡îEä>ãö µQ·#æ[¡ õ`Xü‰UȪ'Wl-ç6DA¾G&ŠH=ç$1Ç4÷J{jé*ØËKS…lóQ£ÿÝ+«?Ïz…Ìk޲L`ùعWñº#¯gŒö‹ñÖVG¼+g[iž+Îù÷ÔFN:<âã'*?á,¼‘|Fñ‘/®3ZwSÊ8ǯpGe4D‰äÁkÍÚy)ôµq–5gRÉ|ªpW4úâ2‡Õž ÙV-Om1JÛMmpk_°buõ ³-¤-嵎9'À•e}sã‚•"=†–ÁŽ¡û›)ÎÏ„…@g®Àߟ-D¶¯ëp×A³kípåmçcÁ 6'²ýMC–*Å{J<h+g£ܲ¦ä"ˆhü-?3öàìeæÇáðÎL„32G@æ ¶F7ˆ aë+“·œà—àtµr8Bˆ ÎKÐ"ÎMû¤_ÕÚ©(ý©*§¢|V“_jIøJMâ&Êu« #Ž®¶à>ü”5ñª~ÜÛš®BµêPî¹zbD]ˆÉ iO>ÈEyÓõûÕ¦ÜùÃÏé~“TÏ´ÖðÃðžxÔGªÇ1Ë™8†ýióîÜü¥wªèû@·ö†ÐŒì3Àa›à#ÆÏÖÒ¾8¼€ð·ž ¼„ñ70l¯OtþMåí·4>|¥òZÆKÿ•?±#Τ†«þríBvëù†ó’gŸœ;‚>;­¸§îûZÃm¡Uãr2ŽãÙÙ)l¤P•áYÍ HZRòÔdºâßíüÇýo^™Ù}bö¾"…iCCPICC profilexœ}‘=HÃP…OS‹¢;ˆ8d¨NDEµ E¨j…VL^úM’GÁµààÏbÕÁÅYWWAüquqRt‘ïK -b¼ðxçÝsxï>@¨—™fuŒšn›©D\ÌdWÅÎWЃ~„™eÌIR¾õuOÝTw1žåß÷gõª9‹‘x–¦M¼A<½iœ÷‰#¬(«ÄçÄc&]ø‘ëŠÇoœ . <3b¦SóÄb±ÐÆJ³¢©OGUM§|!ã±Êy‹³V®²æ=ù Ã9}e™ë´†‘À"– A„‚*J(ÃFŒv ):ûø‡\¿D.…\%0r,  ²ëÿƒß³µò“^R8„^çcèÜ5Çù>vœÆ |®ô–¿Rf>I¯µ´èз \\·4e¸ÜŸ Ù”])HKÈç÷3ú¦,0p t¯yskžãôHÓ¬’7ÀÁ!0Z ìuŸwwµÏíßžæü~ÉTrc-½¤Á2iTXtXML:com.adobe.xmp K«h~bKGDç}?ž[³ pHYs  šœtIMEç  x¹Á¦IDATxÚíØ¿m"AÆáwOt°’{ #uLJ–()€.À!²èáRt =œ´5¬ðò¬ó¿“¿çIœYòÌ|¿™u“çõIšÔЧ¶&”5xnfËMÖ‹i‰˜-7¥Àz1í…àK]Í¿ ¯> öüxùpõŸy‰\]ÐÍkÿ ‹á¿»½Éx<.qöû}ÙO€®ëòýǯëC%¯x¼g Þjèÿö ùdh;‹hÛ6óI›Õî`1ÞèepöIõ&1x¡¿þ…O·ÿÝíMÚ¶M’ŒF£7Ál¹)ýOÀùdxñð øü—Á{ý‡ýràe1øÈ¡øOb`¨¬IÒÏ–›$É|2L’¬v‡¬Ó¦Âlö}å°}¸¿Ø÷$Y/¦§³Á÷Í€ € € € € € € € ÀŸ ª/ÀöáÞ)À @@@@@@@xEº®K’Ì'C+SÄi¯O{O-Íñg?[n.Äh4j*,À~¿ïƒdµ;$IÖ‹éù¹ Ú'ÀjwpÒuÝÓðS÷pñ 8Þ%nÙrãð{ÏÝþÅ Îc°^LûãPX™zƒoø‹¿Îõ…ƒ€Á>Ä#†¥‡B¼3àIEND®B`‚simutrans-124.3/themes.src/pak64german/files/display_station_label.png000066400000000000000000000166761474050137200261420ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜl zTXtRaw profile type exifxÚí˜[’ã8Eÿ¹ŠYß倯ˆÞÁ,(Ù•ÎtVWu÷ÏD´¶d‰"\àâ2ÍúïÛü‡WHÙ›˜JÍ-gË+¶Ø¼pRíõ’óíl<ßç5î[ü~¹nž7<—Çpý¬ùÿ¸îž\á,}˜¨Þ3¹þz£Å{þúi¢{¡ yNæ=Q»' þºáî ärËæVËGúºŽóáI½>F¿B9s?'ùü;¢7ƒ÷+¸`ùá6 è'˜ œ¸ó]½ž¥søv¡Ý–wqz¾g¶šßzAåyæÞ_7ŸÑŠþ>9?o¯—Þ£rBÿaåXï3ÿz°ÆeѧèëgïY÷ñ/$fBo§®œ3Æu–Ð¥«Á´l ŸÄå¼ïJVP›¬×yל®í¢›NÜv뇘ý2¾pâýðá\¬¡øæÇA2êÛm_B 3T@öüÓw–mv˜³Zeåéê“9ùí·ùÝöÖØ:gë3VØå½39ýfˆ¸}5?ÞŸ_ŠkÁ¤QÖi¶_Sôä~0A8@&ŽW¹¸2ï K'Œq@ªpÙÙâ}qŽ@VL÷!ú.%?1ÒÇ2ØPI,Í#Å¡>y.®Cf ‘BlZÀŠ1‘?%VrHRH1¥”SI5µ$9ä˜Sιd%E)¡DSRÉ¥”ZZ‘j¬©æZj­­Jó-@š©åVZm­‰°¦0³ð´0@¤ûzìÉôÜK¯½u¤Ïˆ#<ʨ£ ™~† Ì<ˬ³MYn‘J+®´ò*«®¶d“j;˜wÚy—]wÛòDí†õËû7Ps7jþ ¥Ë5®–ò˜Â)$Å Àè"Ä‹B@B{ÅÌV£Wä3Û ¿m÷ÀÎø QEîoáfJ|ÁÍÿUäŒB÷›È}ÅíjSN; !­B ª Tßs^ÑŠ£Hš"iÍžW—T[4QÊ»žC[Å­žòÞ9´‚ÃMèÔOVȲCßsJMVÅÞéÓÄÆ¶k]F@u: Åèº_£KKjÿ„ÈÆUx2 áê­ÍÑë(-¥ª5ŽÕ›s¦ù:NÙVCÔBÆö€IÁ-,ܾVr^»u%Ó¢^΢f`nÑ׊þöé8!“Θ2™Q——™CÀ¶„ɽ­á\ÊúȪ/@·Íã‘Ð{玵Ü+û‰x¶£ßÙ÷ÞÃôå@ ОҎˆaøipëÎcwoÿd*¨öŸ™ê öOLe.y‚\'IÓ²­…Ø»D?Ï^â¤/Öº‰•«$¼+ÌÜ+[KjŒrÉ'3gM.ÖÚä:ƒ/þÂÑüÕÿèÿm"7C‚„\O©Ïj^â cA®—4ÇŠÚë!¸*±’¹SF¬£Z²qÒ3â„+y=z /¶‡]ÑŽºÇ0©ˆ…ø×ò!mjq¹Ð°*Æñ‚ˆÝ~`7fqérãvÂÜ>ÜX{ùÀc/^àâ?êƒ}qÁ^<@G}ëÊç·N˜7^|Àâ 1”¶lž)‘ê¤'Z/ò8!)zóH: aù>q汞’»·½VV Sày  ,më¢Û°ER¬hf[ªÆHSÄ߬']“î‹ß‹ DÈPÇ¡dTk*,ó6ã|#‘&÷k‹–ºÇƒ@TúÌì­Ülë&ê–zîR7j Ý×NÖAÝj4X'T²& zÇwIhQX±æå_*ê'¶0Âö^V }‚ꜩ”f€oóNË«× ™†`lM*öH#ýoÀ9c¯zÙÒo›`.ô™©k̆j²à;9ý(3fegyŒwõ$Æ_ãŠ#–±ˆ0–ÏtÚ·•ã!TÒȈ»o’R@&ÛæÝîÿÉã<ÂaeƒÄ³è¹˜‹gGA~LŒ¿¢‘ s‘ÓÅeMaI=P]( 9JQÓ—MÂ97?äãçãŽÈV 'RTL›ˆŒ ²X´„ ½q©;¦T¡å¥÷´©lxÁ[û[,×#!ÙÐ0±JO¨™î3ЪÊ"µ°G?©KÚ­ÏÉŒš‡ñ±, 5±Ó R3é–¶R•5§ª”¤‡üillK¦ÝÕ‹ÜMùÝÕï•­æè[£!(íÇJw'iè<×B^ZË®XôŒ£ÉRUoWÆš‰ú%q驱^è¥À/)%-P-3-²p%ªy–™7›[%ö’³ßš°X{‘™îv6õ±]RÈì¥=Ñæ‹p»iØÝ”ˆ°“}ÈI×?ÅušŸSë(Ú;µTâs·µŽÌ¾ÊèÛ"ºÑ¤X¾¥ª“¿Gg¿¦ðÙ¦eDò›ä®Wr›·IýMrdߥ7¸ÒŽö·©­¶^Íékz«µWϹRÜ~ë¹ånµâMEꬮ. e·Ê §µÜD÷cñk鱿[—¢%&ºj}·èµ¤.ø\Oåé¶}\Óè¢oûX·/vÈ„z@(güEÜ ²ªUmGÑÒçÐøäG@e¹Ê›®éDrû–žGóg~õøïDÿNô7& ûÍfþ×q3IÕ»é„iCCPICC profilexœ}‘=HÃP…OS¥Eªvé¡:YqÔ*¡B¨Zu0yé41$).Ž‚kÁÁŸÅªƒ‹³®®‚ øâêâ¤è"%Þ—ZÄxáñ>λçðÞ}€Ð¨2Íê4Ý63©¤˜Ë¯ˆ¡WFÄdf³’”†o}ÝS7Õ]‚gù÷ýY½jÁb@@$ža†i¯OmÚç}â(+Ë*ñ9ñ¨I$~äºâñç’ËÏŒšÙÌq”X,u°ÒÁ¬ljÄ“ÄqUÓ)_Èy¬rÞâ¬Uk¬uOþÂHA_^â:­RXÀ"$ˆPPCUØHЮ“b!CçIÿë—È¥«FŽyl@ƒìúÁÿà÷l­âĸ—IÝ/Žó1 „vfÝq¾§yŸ+½íßhÓŸ¤×ÛZüèß.®Ûš²\îƒO†lÊ®¤%‹Àû}S¸zV½¹µÎqúdiVéàà)QöšÏ»Ãsû·§5¿õúru‘ý¦iTXtXML:com.adobe.xmp @£ÖbKGD@ò-R/ý pHYs  šœtIMEçšL¿Ò|IDATxÚíÕ±MAEÑ7ÖÖ‚(…ÈÜ"'tŽÜ™ *–­aˆXŒD~ç„“Íÿs5#ÉÌ_#]f¨Ýÿ’$/çýàãí¹jÛ×wo×¶û=€û»‡ß!” àúîõÞù`í·g$™ÇÓe?x}M8ž.Ó3Øwÿó&j¬f@ tY’äkû¬@óÝñ E–$Ù¶µvÍwÇ€@ €@ €@ €@ €@ €@ €@ X’dÝÖÚ4ß?åF’ùÏY“éTïnÒ7.z%Š7aM$IEND®B`‚simutrans-124.3/themes.src/pak64german/files/display_text_label.png000066400000000000000000000154001474050137200254250ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜlúzTXtRaw profile type exifxÚí˜Y’ë8Eÿ¹Š^‚8‚\LjÞA-¿(yÌt½¡ë«âÙiK&)À.À4ó¯ÿ.ó^ÞŠ3!JN%¥ƒW(¡¸ÊM>ÎWÝßöû{¿ú5Åï—qsŸp y®þü™Óµþ6nïÎKå.> Ê—$Û^'J¸äç7A×F^5rÜŒKP¹ywNØK@=Í:RÉòlB›çuÜ,ÉçÇè——-û.äýw¼7"ƒÞ¹é­?øöþRÀëÇ_¹±û;8½ ÜG/|[ó ùÎO÷WA£¥ª†o½ r¿³ß›w´‚»–ø7'§ûõÛqcã÷¨l×?íòuç^Çy¾½y_?k¼¶ÍXQCÂÕé2êî5½aB‚n ª¥CøDDÈ~Þ™¨î 6寻ÛbÞ_6Øa«]vîk·ƒ›Æ 7Îuç÷`öâŠëþÄ·]N|ñÃg@îöàÝ]»·-G7{·ÌÎòÔY„Yùå·ùÕÖÒT°öÈw_¡—sêlÔPäô›e b×åÔ¸|{¿¿W‚Q½¬)Rpl;E´hLà7О…‘ë™.VÆ%±uDëAÔ¬6ÙCœkqd ŠêŽœi `ct%]ð>Mvº5ˆÝK]t Æ!3ˆ>‘a„*`…‰ ™ªÑÇcLQbŽ%ÖäSH1¥$II±Š—`$J‘,Ejö9ä˜S–œsɵ¸â!ÍXR‘’K)µ²gEråéÊ‚Z›k¾…MKMZn¥ÕNøôÐcO]zî¥×á†ðÇHCFeÔi'¡4ÃŒ3M™y–Y¡¶¼YaÅ•–¬¼ÊªwÔ.X¿¼5{¡æ6RºPî¨1*ra•N¢b`T â¢ÐN1;² Á)rŠÙQ ?JFÅlXE ô..{ÃθQEîÿÂÍHxÁÍý.rF¡ûEä¾âöj£îrê7Bš…êÔÓ}ðÉ<Ò}^Óz¼Å,¶VLèÁä1còÅ.i3Uöɨ^£›ÉR^& ¸Úš1Žˆ²ÔÛš‡ýG,F«JRa+ÌIÖ*„,×u‰¾4“Öµ“ç+´ [¶•ÇNã0XMrWÃþ«C~-’´¨©.Ô¼Õ¤”™ÞMx³ÀS¨'”#ðZsÖ\ÓÜ´K³ÈJgSjØÝ  #ÎÃÎ1ÓWÌÍxi[Á>—(~ZrÚñ°âÍè ZÚë‡ÇͦOKN;ž­ ’<›@iÂó°‚@øY;ž  ÕèëðÉÔlâãÍÅZò´´ñz,>ÞwŠÕD™§Í`LšÐˆrö<û £™F½Nž˜¥ûŒZ€—£6qÕ8m9Ï~[Ž(®¾¡|2èCëƒ U°#‘zˆiÆ3J2ÕѶ& ŽQõl€ÝgÁN‰&gß’´·›ëÊIeej}Ì+vI©OßIÙ\ÇÑ­8Ùèf²64Fv}òT K} u„¢¥F3O>@.N•*sh´Ì ÁúÁb»×ú¿_i~~éß®¬&k¡õ¶ÑëI¯ðg²0µ ]ƒìÈŸVã«Ð¿ù¬6ax/CÅÇnh!7‡¿_m+²#Ø‘?t{…F-¾Œ~ôO‚£¹ú$Ös؆I1ºòM‡ÍÀgüt™ËÕïÅœ?RÿÝzƒù§ñ´ãßûdvõÜéôuÜ<"]ÜÔ6vv ëíΗ‘Zi£ËiktþY–yÉè’جäOE‰hšÚ)¢øÏ:‡©b{ÂISΚ;„¦žÍžƒÊ|×?ôÝýßmhížÞ¶uâi´îÇÑSq®”îjŠ”ïAÑS¡:ŽV·!»Lñ ü'–_ú£¨ÃI‡I$™Árr±P£ކ¡q^ê,*p¢ÒÊŽ.*PF¿Âá#tÎpA¦;×Z‚µVMõèÁBçÖàyziéhÆå9´Õ:{?¥¥ùÏþìõ ?‚þATÛ5ô_íÿÞFBiÎçX„`zTXtRaw profile type iptcxÚ=IÉ €0 ûg FHb£–uH?üú`a*-[>ìšwÙ¶À4t&§ø#F”'šbGÂ%ÈCâzJÏ©Nìhïn9¾ên0¹ÝœŸ,9„iCCPICC profilexœ}‘=HÃP…OÓŠ"-qÈP,ˆŠ8jŠP!Ô ­:˜¼ôš4$).Ž‚kÁÁŸÅªƒ‹³®®‚ øâêâ¤è"%Þ—ZÄxáñ>λçðÞ}€Ð¨0Í šn›édBÌæVÅîWB1 ÈÌ2æ$)ßúº§nª»8Ïòïû³"jÞb@@$že†ioOoÚç}â(+É*ñ9ñ˜I$~äºâñç¢ËÏŒš™ôþ!×/‘K!WŒ ¨BƒìúÁÿà÷l­Âä„—N]/Žó1tïͺã|;Nó>WzÛ_m3Ÿ¤×ÛZìèÛ.®Ûš²\îƒO†lÊ®¤% Àû}Sè¿z×¼¹µÎqúdhV©àà-RöºÏ»{:çöoOk~?1ér½Ò{àiTXtXML:com.adobe.xmp I±þzbKGD`„§ÎÿI% pHYs  šœtIMEç 9 “ÈŠŸIDATxÚíÖ¡QQ…á³™54 ¢©‚pé€Á#ã:À¥% PTAX\›„¡‚œï“ÏÝw÷Ÿ·C’9§†t™CíþÇ$¹¹Z^襁}<{»¶Ý/\]®—Pvdz×P8óÊÚÎÏdÞlwËÁóÃíÐt›ínö,»ÿý&j¬¬f@ t“äkú¬½€æÙñ EÆ$™¦}í4ÏŽ/@òýñV{ͳã@ €@ €@ €@ €@ €@ €à1I.Öׇ“÷ת 8™½]Ùî—öÓ¾vçͳãˆrC’ùŸ³&³Ï zÿp–~w .žÌÀhIEND®B`‚simutrans-124.3/themes.src/pak64german/files/divider.png000066400000000000000000000002761474050137200232100ustar00rootroot00000000000000‰PNG  IHDR@@% 扅IDATxÚíÏA €0À@†[2ÏðDƱDž¤UpóšÇŸ÷skÃÞÀ»–6luj@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐìöm=ÓÃÞIEND®B`‚simutrans-124.3/themes.src/pak64german/files/editfield.png000066400000000000000000000011721474050137200235070ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPAIDATxÚíÝÁIA†QW¼¤‹¤•€Åĵ„-!ä"–a=zK WkÈ' ïUð3û1sÜe=­çëåaZo/¯£'üƒy?Ár۶јØãèÌM@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²¬§õ|½Œžq¿Ï÷Ñ’ãóq·?Œ^q?7‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²Ü¶mô&æ"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€Hž~¾¿vûÃè÷ûÛ?zB5õùûÙ ‰'ŒD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HDò * ÷;"0 IEND®B`‚simutrans-124.3/themes.src/pak64german/files/gadget.png000066400000000000000000000027151474050137200230150ustar00rootroot00000000000000‰PNG  IHDR@@}g_HgAMA± üa pHYsÃÃÇo¨doIDATx^íÛë/c[Æq…¿‰D2ÎA]Â&.Í$ÇÝa´(Æ¥-{"^/$âÍœ—çÏpžZìL–’yÑ9Ö¯ù®|ÒìînɳW¶ýìÕ1eÿ>>Š®¬ŒìïÅü@ñýøç‡x;Q\™Ö^nxûQ\Ì/“[{±û”r=?½ ïS(ºçÛÍËð>Eq•ìüêÒ™šš:>>Îd2ggg###\LÂî´sÁ|M{4ÊËËŸ·ž†wd€~^{9Þ(®Âׄw¹xoç´«««çç烃ƒÚŽÅbÚN&“¶Î¢hÂûûû-N»Ý䎒¿_pgh”°««kaaáòòòþþ^¯ÍÍÍ•••&’¿Þ1†<ŸÀÓð> GdŠ›J¥Òé´Ë­×™™™£££O㨮½ÜÛD"‘Íf B ÐlollXœvežœœÔmÔè5£ØªŸÃ¿Þ,…Tc©·Ô^Ú0Ñ^ÞÂ+âf‚f[cþïùä·dj)¥ ·Ç;,2)h}}ýéééøø¸¶UÚnooóÞ’Ÿï—ÀÚëîîŽöî){á2¥íééÑ HC¶’;Ê<55¥üñxÜh~µ¯+`7T†úX9U`Zé5üÌùù}cxG†O™çfæÄåw#³•ÙËíiÃ;øÃ¤ UUU›››¹\nww·®®.Àè¿(?û™ÌÀÀ€•SPÎÎÎÎíímM¾ÆáááÁÁÁÞÞ^oo¯¡S½ººzxx˜ŸÏ?¾y„O™õÐssssww§&3t Šê†û N½¥pC{´ß;>LÊ©änxfoÉåñœ¦:Zoi,%–ÖRkÏoÊÊ6Ö‚û6åÍ4 :==}{{»²²Zè_§ä‰DbbbÂÖ)(­²Ù¬æ_÷ ýýý¦¦&C§ ¨ºïììì\\\˜.0=:œœœXy€SH7t͸W WcÑFyy¹÷SRx-]lõnÈ–Ÿîw‡w|È”vm%_Wnûûê÷­õ­ÌÎáÞa´s⯰£(b<Ÿ_\\4WŽ2¯¯¯kc4|EEÅòòr:®­­5w \]]­ÛƒŒÎÿðð°òëj+¿Òº¡Ærw ·ab¦„Þqè­Â‡ŸÜ:Ípô=¡^sÙÜÖÆÖjj5ùíùÏßô:ÐÖWY¢(ŸV-¹\®±±QÛUUUÚŽþ¦ÃŽÅbCCCæ’;Š­ßÛ––»ùU½¶¾‹(s__Ÿ•¿zxM±£û¾®Æ´á—¶àðŽDÑi’—“Ën¶5¾Æ¿}Éß?Ýhý£U¯Þ|¬iòA[[£qÑkCCƒÑÿG¥ÌcGJ MMÅS°›ÜQroÕòzOàU+0CKƒ&|nvέ´¢ÑÔØk‹iÃ;øÃäB¿õÖ eÞÝݽ¾¾¶¾dØ|ӗ¿Î_pg°\Z o?~77íŸ{>·ýÙö©ù“¸=Þa!(å‹C3®u¤ûÏÞGÂÇoîÊWÖËð> G‰_Ï>€wðË‹÷q}L¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0èññ?~C¸e‘ÜïIEND®B`‚simutrans-124.3/themes.src/pak64german/files/gadget_new.png000066400000000000000000000022231474050137200236600ustar00rootroot00000000000000‰PNG  IHDR@@}g_HsRGB®ÎégAMA± üa pHYsÃÃÇo¨d(IDATx^íÚ½GP¥C[9‰ÈPJB¶` ‚ ™ 2HCa( Ð¨Ýåá°·UÃ<ãØÓ|=›¼Ÿþyà¡~ûø¡Œðv à±¾þ÷÷Ry;ð@kïÊ8owÚûòù¯KeÐSyswefs±÷²{Z`wŸ’»ž..ÿþóGØË| ›ýåÝÍzsïeö OÉáƒã£ˆ—Ïún/gñ>âF”Á†¦ä<±¸ùÎæ›;è¾ì{¯P&ðvÇ;°Ãg寡>"a>îwÇy7벇2ÞР¨'·`mÝ‘²÷ eNgqµ/•iOwð`´<1‡ƒ E¼´ïoBŽw“Éï*'6™›_ü”QG¤}­XWÿ¥EÈýµíŸ9”W*ÓzŠëüéÏ_u» Ç¿Ä)ó¡),“û‹ð©óâ gÎb/'vV—£ íiGþN±œX݈uEÔ¼åhOe×µ+3Zy/ªKy´œø,ǶDÜ|‡ó‡2­¿Ÿú/!®s¦MûH9¥³‰á'f¾&òïr]efC™vJà²å*ÊänÖ.Õõû¯?GõîƒKŸ»Z`Kdͧ§IâW)ù§,!¢îÉ÷ŸËäÎ.ÃÈŸQ'^ö b —Ö¡rbC{þþs§uM™ßͺ—{¯=*°÷áG<ýE\ð¼òoAÄÎä©Lk¨ÎU”i­ìš%2ßÐ|9!/~ÿÀe³u¨œÒʺ¼¥½ÊµìG›tØ™ÿ 1bxúÅÏüã–P§2­¡8WQ¦õ´'_"ü¥u¨œØS,¡yÚò¡¿¦œÕͺÈ7:lヒ”ñܤüc™ÜVdƒbïr sóïKeNCuO^æL‘kI¹¨2³§Ü9mÙfÝPNìf]äR`×´.°ˆXÞÛÃÁæ"j*G§~‰üùѱ–‰™¿G¬%–6eQÍÓî{”»Ê¹ ­ë¼ÊéFåÑrâ³Ô‹”‡ïíCpC>9S¾›{Ú_%5e]+çúôŸï.´ÏFÕ¥8ZNy¢ƒ»ñÞÆø”Ï}Ìzr2ꈴç¶n{ñð_*Óžîxv#èÝ ­ÌJ{nƒîÅ ¨?‚ÿøÆSÿÇ9¬Ðú{tð1ê`J+LÉùƒP`\£À€Öל¹À–ø«´ö8Ÿ“g¥ÀI0’`$ÀH €‘#)0FR`Œ¤ÀI0’`$ÀH €‘#)0FR`Œ¤ÀI0’`$ÀH €‘#)0FR`Œ¤ÀI0’`$ÀH €‘#)0FR`Œ¤ÀI0’`$ÀH €‘#)0FR`Œ¤ÀI0ÐËË7ϲoÍã{IEND®B`‚simutrans-124.3/themes.src/pak64german/files/listbox.png000066400000000000000000000013031474050137200232360ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPgAMA± üa pHYs¯¯÷ýK„eIDATx^íݱmAEÁË? ™ €e*Œå¶,â&jPή7øwæ¾>ÏŸç¹ëßîŸq©Cn×Ã:‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€H^Ÿg¼ºåÇÏ·Ó>~ŒÝ" eZ6ö8G@ËÆçhÙØã-{œ# ecs´lìqŽ€–=Îв±Ç9Z6ö8G@ËÆçhÙØã-{œ# ecs´lìqŽ€–=Îв±Ç9Z6ö8G@ËÆçœh<׈D@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"y½ÿz¯nß.9çùïF·œÿúgÜèa$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‚çù á“|+­AwIEND®B`‚simutrans-124.3/themes.src/pak64german/files/ls-symbols.png000066400000000000000000001041271474050137200236660ustar00rootroot00000000000000‰PNG  IHDR@@ÛTügAMA± üa pHYsÃÃÇo¨d‡ùIDATx^í\TÇÞ¿}ÀVÊÒ{ï½I•^¤‹”*Šˆ4EiV+öÞ{ï±Ç%‰¦ßÄÜ4Ƽï?ÿÌɹçJQve¾Ÿçî=;;gÎÌž9çÉ, ùæÏ? ÑAÛÀÂmxhH\b|BfJratRQHl~Hlž‡ï(#so¬ò›ãååU)¶IMMņ#vó`Ã!¼cˆÀ"ApDÖ¢%û÷¹súê7»NÝkÛvnîò½Ój—ÎmÙÔº|׊õG—¬?²uÿÅM;OO¯mÍ)žáœˆµÐ7@`C_%޼†€k¥§ª£ÄÖW⤎°n*ÍŠ³.+Ø´¼`ÙœÑÓ§sÞ°¤påœä¬ *×ÔD6WG­™ŸR_â½iIÚÁµcÖ.H:±£ºµÒ÷ÊŒÍÍñÓÒ­[*ƒªòÝŠL¦¤[×®Ÿè™3BoF÷Ô±vÙ‘úeÁÅÉyqÆu“ý¦ç{‹5ËK²v5æE ÓÖá*È•¢:7t(tŽØxüvÒÜÜŒC=ïï ö±áÞ1D`„$:±`RM[eóÎ¥k:r£}ã±ÊºåSf´&çNÏÌ«¨žÖ°¨jNû¬yk›ZêËg-œ×¶ïàùÃÇ®ì>paÅúC WìÎ-œî툵Ù+ºD•§ài©êaœdk¡ÆÉOtXÚ˜0!Í¡yv⪖ÌÖºÄÒ Ç…•±;–çÍ<|A™ÿºÚ°Õ³£¶µ¥×ºom{éhíáME§÷ToZáp噽¥ëæÇ·TÕ¸MÏr*Š3.Ïthšä©_•3¬:ǵ ÎhæïÉcí¦f:Íšà]:Î}r¦sn¢m”N´¯¡&KŽ#)#IuíýXõ‘gýN~~~§¿:Úo/VîwPûØpï"0ÂÀ’U¶rӱͮÌiÛµbÛ¹sg¯ï\³¶}IÛ²––5«W­Zµbö̺Ùå3UTmmlØÞT¿©©¶eFuSMmë¼–ùs—¬lß¹mÏÙÝûÎíÝu¼±~qäˆ$¬ýÒ½ÀxòòŠ,Yé@wãÑ‘võeÑaîºÅnKF‡™.ŸŸ¶®eÌü²¨%Õ¡;VžÚV°jªß‘Ö‘‡WŒÞ8?añTŸ£›².š½}iÊv}p ä²s{'\96sÞŸ+ÇMN¶*ˆ6š‘íÖTì5%Á|Úûº|÷©)Ö9nUy“Òlg• /ïTYà^œf?9ÓÅV‡cÄa¨ò%¨ÞuØ`€Œð®)**Ù¼õàñS×îß}|ûÊ{—.^;zðü¦µW7¶rtßýãûnÚy`UsÕ”i¡aÉ9ã kJË—ÖÎX;»ª}fÙ¶æ†-- *'N®,›1­|öüy+ÛWî\¹lÛ–‡êg-ÆÔºxBWÈóuÖ7ÓV6Uå»ê€ºÚ[3sÊó½jKCG×kž}bó”ƒÍÉÇ–¹upú…5ãnϹ²!ëð’ÔÝ‹Olξvlö¹=…ŸÜÚòðæªkÇf^;:ùã+ ¶.µsÅø¦š$‹ê±ö«kFÌãИáÔRì=?×µ*Ãavá° 3 =K3íkKü* =£}t}­•â|„,–4ÕA"°î qRgl\R¦ØK=‡Œðîˆ ‹Ý¶~û™#gNì=xãô©['Ü:¸ýÃ-Ëo®k¾½nÉùÅón¯i»º¼ùøüYûêËÛgÍ;VWß!)µxzIÕâŠêm3.n:¼¢uÛ¢ykæÍm¨œ12&%%)»©añþ½§vl;4íÓC~¼ÓüÕ©™?_ªüüؤO÷ߨ?åÜúŒ;æÝ=UûùÍÖ«Çfܽ0çûÏöíXšzùøìöÚðµuQkŠ=[²œ¶ÏˆÞ\ì³v¢ß¦²À-åK £¶¬üÆÞ­W7¯:µ¼ùðœé»fNÚ·°qm[û”²†‚Âʘ،ѩ…¹yåY¹SS2§¸{&`GÝ "'%e­¯è¢`:kjLý´ˆ’qÙ ÖófÄ.™³ºqdûD¿e_^¨ùá\å³[K~½³ø·¯6=½ÛôÛƒEÿº2ÿöêŒonÌÿáþŠ[§*¾º½èÁùêG·×|°{âÙíE—w”l­>Ùµ·ÄïLmø…#ŽL:Vr¥9õÔÜÄ-Å~•£,  ê'ùfF›Œ‰0¨Ÿ7\ßň/”cÉ¥Ö`D`Ý@&‚tUÚFå³·Ü¢+ô"0»`íŠ-:½uAË… .­\vmuË…UsN.¯ßR;ñÈœéGg–~¸°âã–òæN»V7ußÔÜå9) ã’§gg–OÎ/(ÓÕ2™”S°aþœ£+Ûöµ.Ø»°¡­|J턒̱SÕôüå¸vB=Ók§„¸”òؤ)q£JƒCÇc}x%ÝLbèP–„¤º‚¼‰²üp'Â4—¦Ê„ Kr[f%ÕúMËpÛÑšº§%ñô’Œ{»+žºå·ê~ÿùÌ‹o÷½øáÈËßî<ÿrÇ¿OÖüú å‡uß^¯ÿþî¢Ç7—<:_{÷Èä”\Û˜w{}ÑÕÖä 5aÏÿl}þ½Æ¨³¢¾Þ1õãUcŽMkNs˜7Þ}rŠmN´aEžÛ䱎Q^šæª zlyIꋈï‡Àš››Ao#þz»ícÃ!¼ÚL¯S]ÛèiO à‚2d<2/H‹ÎÀV¹ 2´ƒvÄ^zKlÞ¼ïôþcG7n¹¸iãéÖy÷Ö·}pó§;WÝØ²øò†…‡æMßQ^°}JæžÒñ»JòVÏZœWXíåãïêîç2lrÁÄœô¬1#“âÒ£#Óƒü¢-L]•5ìþ‡k=„k'­äbä8ÒÌ5‰¯7\V覬dï6ÖÝ'304'4< ëIWº,s”XröBkõ ÍQAÆ…éÎi1våA *ã7Ï˘—ëymUƃö¬ÇÛ&>ÿêÄóÇk_|½ùù·»~ÿùì/¿zñÝÁ—/>{þxñ/Îþåþ’§_o{úõþ'·|´gÂÃÃVŒ~r¬ü»cwçÆ=Z4òÇ#Õ_´~¼4íû퓾k{wé¸ÃÓB–NôªNµ)mS]ä•aî*éc`!äËIPßC|?&ÖÁ†Cè RlôD]ÌížhŒL<@¾À5óí“G6lX¼x ˜,7"/u¯±Ýý%{ñùŠ—Ï®¿øfÇËçwÿøýë?^~ûü‹U¿Ü]üüëÍ¿>ZñéÉÊ?ßõýÇí·ŽûjñÓ~=1ùûÕ)ŸÎùùLýWËGý°iܯ‡Ê~Ú’ý¯%çj"·–ÌëX•ã–ªWšé2mœ«…PIFîýûýÛú=­·Ý>6¤(Øè•ºvÞüÏÓ¿Õ˜Hƒ–\ðÆú“¸r d}ý†£þ×xñ€  y¨Ö} )Ø ü‡ä‡Z†`íGNï:þáŽW·m9µ~Õž–æóîn^²hrEuFјÐQa>!n.ž.ΞŽÃ<]½}½ü‡Ù ñ YÞ²&($ÞÃ3(}tVÎØÜ)ùÅs++§f­È3¯ kÓ̲EåÓlÍMͽ ¬ü5ÍLœ"U}|£rýG«™„ʪzéXŦSäœâá‹õŠI7“—”Òá±ôUB\t£}tò¬Ö·¦oZš=£hø˜ÓòDëC3Ão¶çþk_ÑÏgÊž¶èÅW;þxùÍËg7^>=ûý§ÿñÊËŸ¿|zëÅ“]?]›÷ÍÙò]i|r½ù§ÛÍ¿}¾åןžúÓ‘IçŽøasÖ§¡ßµÆürpê;Š>_‘vafäò,ׯ©£­'{Okè fÈSP”~ÿÖá™þLo´íŸIYÙï ö±áHQ°ñ:uÁ[pzºà‘ÞîÆaD`" Z*¡K…rWgàéýc{î,Ûìdó¤ý-,Ѻ êÓ)Ò¢;B` ÚGbÃŽÛ/ÜzøÁé‹·wî>°xq{CÃÜÒ²²¬¼ÜČԈ¤XÿWë3SwKOM [};#Sk3'g+·Â¬Â¤„ÄÜñ5ÓgåeåfdNÏÏm()ž’6:#$¸eú´` Y]›p#»hCËp›H¡ŽŠ–—²–§¼ê0ž^OÇmlÑ´æåí¥³“R lmƒ°¾Ñt#0–„¤€ãg¥馟3ÒzfžûŒ"ïŠ|ï¹5ÑÙ\õÁ¢„OV=>^ýõ¶‚öMxñÅž—/>}ùâ“ß9ÿÇËï_>üûϧ@f¿ÿ¸÷Å¿ÏþöxÕoŸ¯úå“eß]˜õí¾ü§Wëž±é‡Sõ?nHý×ÊQßÌ ÿræðï–übiâ£æ„ÏÄ. >½`̲ŠÚbÏ’dËš<ïì8+3®ÜP©÷ï÷ÀдìßÀ¬FD`ïð ÒÏëÔwØ€·¶áÔÀ6”¼rÕÛðˆ¶_˜Hƒl¾3M¹«3púÁ^À—1*XnD-%ßÕ1 |Ä(ÿàX33O;«á~ÃB'Ö”N/WP^;·rrSYImñ„¦‰SZ*k‹Ç©«Z±ø¶ÿà9 tüôŒ4t}j.šz>ºÞmoƒ0 Ãðà+Ö¬Y¾¢%}¬ÌâµL=°"ºx‚+-ëi©U˜ìº &rß²ŒíËrož°}yÖ܉~Ë+´¦ŸoMýxŘ/÷Uüteño_oøãÅã—ÏξüõÄËg·aíõûÓ:d/>úý—ßì¸ýâ‡~¼ÑøËÝUÏŸœÿñDÍ¿·ç}¿$ö»e£þ½%÷IkôÏ{ò¾_7æ‡'u¨rWÉðšÑ6u¼×ÌM¬Êuƒ% _º£_TˆÀº Ø›S_o¹d‰ê—Ã<2ù§íy?ïü¯mû*C—V…­ž;j}KêÜ©~aæj ,ªs!ë&D`oHkùr{8¬çßà-¦º®à¿­aÞ4؆G¦ºà¶á^ÛÐ2Úm¿"0‘ }ô“€òÏŸ‚®NNK!]!cÍ ±E³¡Z‡É*e*¶¡A¦À`;tŸqöOœ»öؔʥÙ3GÄ•–’VÜ8{IÛâõKZVN^¿nóÚ5[ËËfÅD¥deyz99x{zGÄ$O¯¬Û°n[ë‚̬֜‰Y¹%ãóÓF×W–ÕUׄù…óæCþ©#É2“d™È²ÍU5]õ-‚¼ÃsT|…Æ~æ.qBãá&öaB7%¡·¦NÐ0Ÿ”æ¶õSª›|"2ÝýS-íð®¯,sd‡åI˸)³G»é•dz6WG-«OØ·jüŠºØ¹E^{«#ïí«üöú²_?ÛóôîŠ_®Ì{zºä·Ï®N{ñ颗/ÂÚëù—«^>»ôòŃ?þøá÷gן¿ó÷§W^üxøÅ÷{Ÿ?jvgé/‡&þºm̯›S^<Þöìôä'í)?lÎüõTųës¿ß?õXcü²áKgG­kN›3=6ÊÛ”ý×èQˆÀº ½ Xa7TU™[¶¸0¡MÖ«Õ­1¤.Tyºà-…mx„mØ/Þ§Ù,˜HƒA£üÓ)0ZT4 0€i5-Åàzë\„ý'Ðú* Ø¡ûLåü£'/KœSX6seü¸©…“ëò󪧔6„G$ïÝwbÕêÍ©£³âã’·lÞuéâõÓ§>HKÍ”‘hèšN-ŸþÃßUN+³17Ÿ’_™_˜9jd˼¦Õ³ m£ ¬G8{¥øŽáòÌ­­ƒÝ¢ô-ýšöÛç¥ì[·¯}âå]¥çWän¬‹½º0åÉ‘Ú'×Wÿúõ±ß~8ùÛWû{´îéñ ÏΖ<ÿtáï?ýý‡m/>ßüû“SüþõËgÿþƒŸo¬ùæ@õÃÅ_ìŸòõÑò/Íy²eü³[Ÿž(}þhÅ‹o÷¼|þÙ³ÇGnl(ÞÖ’Q•ácr}Së¦Ä´R'Ï‘E5ó—nJËœ|ûãO?ù싪ªÚóægeŒK•R:¹ldܨÚ³W.[5ÌcøÄ‰eK–´~ýå'gOiœ9û샧wïØ¾®}Ò„’¬ìÉ|5‡´´’õ«¶9ÚyO(œ“am雕9iÚ´š9M-ã² ›Z–µmhhh:söà×ß}6³~^`øc;?K×[·D%-/K‡W¯‘†nÌ¿R`, Imy–¡"[WQÑR™ïc LöÑ+K´o( ÜÙ0jß²ôÝ‹ÓvÌsfqÖƒö‚'W>ûrÓ‹ï÷=ÿjóó¯¶=ûdñï?íþ店¿Ý~þy۳ǟÞÛðâ‹}/Ÿ}ôë'ëþzÏW‡§~³uÒ—§}¹£ü_Û ž}¸ð×S3»½øÅ^|·óé£=ÿ¾·öÄÒq»Úò¶µŽË‰5Íi“m¥ÏVü¯O;ó~ ¦âÛÜÑ §ž÷wPûØp4dÊZA%âjnžÑl Z` *´Á\€ºÃ°iÐ_¤(èÉ+ÕåPÞ[T=ÅAóîFßýß±ú‹é¿……ETþ¨ uÁ.Ð=¬qsq&úZ´@Ï’~XüØ)¹KÊêÛ6ï;•\ààë6<%4¶( :ÇÕoä'¿ýôþãã{ö_;~lNMM[Ëâ…sj+«<|dßÁeåÅ“sR3¾üõÍ‹×æT×-YP¿zÅÜãGöÇÆŒ²±õˆÌ‰ŠÉZ»aËÅ+WL--“FgFEgL¯Y8{î gÏH)y=)yCiyóê >ÿüî»WǦg'ŵ.Ø>ÎÑ-Ù7hœ†±¯•gœ¹g ³Ï¯˜äС C%•eåŒØì` å8cµh{­ÉiNsò=vÔEÚ¿gYFëä ö\ïû«2¾ØUôÓ¥ºß>[ýÛ§›~»Ýôë©éÏn4<´òÅ·[»µôß'fÿ|méÓ;«ž~uðéãÃ?œo¾·ê½U9wWOxrvû~¾Üüüóí/žœ}ñÝ៯û´}ܱù_²}qú‘u[–æ9j³uYrléÿüú÷F`^-?ô;0±Ñ ‡öïËìwPûØp4X$-TÒi®æØÎôD`HQÈRH`´ÆÀm[È7 l_tÄn‚~lvÇÔ«.x„:èÖDß è v8€¬§ Hÿû °B.t+Ç@ÀRŒùÍØ¡û@aEË¢ '­9‘P_dlnfc뚬¦ïëê“䜑>á䳟|ôðÚÙ‹óçLX²bñÒC{öíÙ¾sUë’Åsæ.7ÿãk×+'MÞÚ¾öðž-;·­:~øàŽí{ƒB8Øüôê’g÷7<½µê§]¥¿\_ýìó}ϸúë¿®<ûüôW–][=ñBkö§‡æ?<·â“sKÏ/L?QŸôéš¼}MiÛ&n«¹nFä†Eɵ…ËgÅæEÛ8 åÔY,ž”´¬„”äпþ bgˆÀº µ¹§_@ícÃyÇ RÖê *A5­®¶¶¶^ ,5U»0M†ÒBh£ë" À4†© nPÌm¨'Õ„ u1K^§.XÀzŽÀê¼ À+8Ó]†Ò¢Wí ´`ž¢W_)0hM/æ^(XOþ–ÂÉsWl¾’3½Å#$-`DnbFuÁ”Å*:~U/¡–Wͬöˆ˜m½aj¦f~Ë–¬ÉJKÏVQZ–—5VcW­Ü½iý‘Ý;¦äçL›P¸gÓúÖ¹M›Ö®ÉÏÉm_½qÿÁSMó—·¯Û[2¹vx`”³ÛpU53YY–1‹kÊWµWÕt70 qtM1552±s ÑÐvRÚ9»­Ý°=?¯ÌÙ%HߨÝÍ;ÑÝ/ÍÔæ?˜˜ÜPIei999-Ë‘Ãöâr‚Uø•fÚm~ÍÁ&KÂ,Öåøm¯Ž85gäù¶¬KJ®.;ºzâÃ]¥_ï«úùJÛÓks~ºÔüìÚ¼¯¬ýåêŠ_¯ïöí™_nlúùáùï>Xþù•6N;5'ýÓ]uÍ9·pÜù5%GGí¯‰ß4/må´€+›§ÌÊqY:3fBŠãè@Ó1>F¦ ,mK…Å‚ŽIIH²$¥ä$;¾JÏ––×u\5÷¿÷T`hh”µ:ƒJ:Äõ*umë ºÒ±¦^ Ø }¾G;,.N)0xD`;Ò Á™ºbnÃK¨ÏHWýnn†Wi{!uA!Ö2“w!0ì¾Ï«)š`}f‚Õìw$Ì%Läà|ÃY‡!ñ@{ ¤ÃW]‚©Jº Í4™Ð^–!Ñò>¶ôßT„r¬3ÝÓ¾ñ|z~sb~mvé¬é³—®ÞrÒÁs¤’–›•s|Dlî¨ÑEÊ6®^±šFuûêš9ëV¬\4w¬½¦N,©)¯hšY}íìñoÝÛ³yÍìŠÒ3‡÷Ô”•çN›\V;³ÞÉÅ£¬rf}Ó²´ôI¶Þ³ë[||GrØVJ*NÒòÆêÚžò\{¡¦Ÿ£KšC*OÙÕÆ)ÂÑ-6”5J&W.œ·¨nvsl|¶­ÓoÿL+û(ºÛ´ÀÀ ÊÒ²š²òªr,[¶¢—cÃaû ¸)ªÜQªÜ±º‚IÚs,¶çm›¹«&æä̸ó )W7ÜYWü馉7§ÿëÄŒgoüiÇħ÷6üx¡í—ë+>¹â—ç~~pðë³m_ÛucQÕ׿¸yèúÖÚÏÚ«îhø°­è̺ÉSn+=P¹{yqQù¬|ŸêPÓ`mž§žš®KW^^]ž¥ )Í’”äÉtx 4¦ %%-!AÖ 0;î‚ïÀРÀF°–BZB%÷ÿת ]ãèÒÆ|¨r‡É:dH`ËŽÿ JÐ# _¹ WÝ« …6ž¨ Aö÷`}f‚Õìw@`VzpÖ™+08ßh:BÀ:h™E {¡É‡ur#âa}†>WèO¡eس ÓëL7„E¦6-:è61ÚÂ=§ï”Ö®ˆH*Ò2ó2u Š*ˆM(p÷ [±~·wP‚™½ŸgPÜþ½‡÷mÝ>}ÊÔIEóêfM¯Z³lÉ—ŸÝùðƒSÇ÷m{póâGWNOŸ\’’˜>vlnT\šŠš±‘©“­wHP|CcËúM{cGæèë{KË)k8雸«iyKÊXüÏP3ŽÀM¨3lxØ[—X¡¶µStȈÑ9ÙÅUÓëÖ¬Ü>Ü?ÙÜ&ÒÍ;]SÛõœ˜ôС Yu9– [у­èÂf{ñy.oËûbwÍç'þûü¢ÏÖÿtlÞ¯müåüÊ'Öþûì†/o|¼wù•ÖiŸï[òðЪûûæßÛØøhoÃw«']hË?5o̶…c—eú¬™>Éߢ1Øz¡½aˆ€ãÊe+(hËË åX\ÙŽµ—„ ý( ¶ß¡yø6Òy3|»ícÃy« áP ®Î 9¡t|=cÆŒ~QWW@`±#h!‡……þíÒù·£^ôùuêBa ¬çêB¼uawüßOî˜%X}QƒÙUà÷¤s MG8Ó°fBuÐ4…tÔ¡^ëœÇ¨A({Á.Pˆ*cÁúó:ò¦Ì-©Û<¾¤¥fÆrãp-³hÀt¯àäñ³Ì,Â55Ýr ª[Ví”ç¹{„fgŽ=±wת…‹‚½½'çç—=³¼ìóÏ|óøáO¾üéëOÚæÌHOIHŸç2Ø!GKu¢–z¸²ÒpÏJ‘­ÁbÉJJÊJH‚Æä%¨?æ«(%ý~L¬ƒ ç-ŽEY«3¨nô´£ֿꢡ¿1ˆ>9„§ è^`Ô[0êy×ôV]ˆw-0t f–`õE fWwÜ4ù`ÂyEûöÉ#Z`¦ºè`6B«.°@ÕèUû¿’úôJ ¦-ŠÊª95+»vlú”Ç®üøãž¹ ±iuee›oÀ-coy¾…¾¾sÊÈÑ !Á¹‰ 1>Þ5E…Õ…ǤÍ,´kÃê¯~ôä‹Ov®_è5ÜÛsxh´¦‰[ÃE†cû$†§Žðòõpó*š\enï›_½¼ý ¹m ´‚á YEKu/žªWÅRIÝÎÚ1,1mЇo‚²®‡©CD°ôÖ5V,[›6^ß&ÐÄœú1˜ÜP ¾´œšKKŽ¥Ãb²Xæ ®<î(”² VY1M“;^_0ÕF}¶‡Á‚pKX­å¼+Ém[nÐé©¡×gFÈ ¼13áã¥Yê’?iξR“ö`Á¤o·4}3·ñËåÍŸ®^úQkíÃ5-®¬»4»üöôI·Ë‹¾_ßðd×’GS2ŽDú¶zXnñ²l´5Xâb–¯¡œ¥¡Vc¤£¢4K¨–ÍáëË+(ËÈ*JK+Ëʱ$¥d$$ä%¥y²²ï‡À`>¿À%Óyc|»ícÃéwÐ(ku•ÀÑ!HZ$0(yêbêBÍ¢…8 J°:Ý€zŽi¬oêB¼]1oô¬]ÄeÆì$ðîûæ Z-Á †“ }Æ )‹O™‹0ð<`bMÕû+P»Pµ»ëÒ+Éš¼À.¤ÀÐiTiåòƺÖ}»Þ»÷ùʵ;‹§5š9‡p•ìåä­%¬öÿü§0:tTqzúìÂìÚq«+§/«(¯ÌÎØ²tÁ’ºÊÖÙU“Æ¥ vµ²pqtÕ2°Ñ·ôµt‹×7 –e;›»¸™Yùû„ó•Mu‡†¥%¥M2±ô“dé»xŽRÓÆbÛÉs¬YsSë`K»pe gžÅ?Y¦| × “f>tlyûÊôÂ}sË(>×zàHI³%eTd;^Æ,׎˳çp\y<_>'BÀÍPå¦iðòô…¶j >†Ã g:k/ ·Üì´{¼×ÑI¡K†_™~½2þJUÌ­òÈOf&=œ“ýÉÔô;s'~ÙTóxIÓg-3n›s©qÚš²O'ß8þæø´‡ÓKWW]Iu4Ƈ›õr{Ó…ÖºËìŒ÷»Î±Ò+73WQš«£9W[ÃD^ÁLAQEV« %Í“–‘—’†uØ{#°§÷;pÉtÞ;ÚßÓ2¶ßAícÃéGPç)ku•À}‚~օ졆®èž_¹}5êB?Ã^í 0 hìMÔ…x§Cwf9¶—èÀì$@u½3Ìrl¯~Í•N½V`¦rLåFÄ Q„iAÕèüù DÛÌOQ ¼ët°.½’”¢¹va}âʲ‹ç§f–î9z¥¾y‹Ghæyã!RÚCåm¤lµ |]]Ã|Ü'g¤ŒðoHMš3:qNfêòªÉG×´Öæ§'Ç„y¸Xë{ûùy‡˜¸[:ˆ-âk8qøfÞŽža¾A~qCþ¡ÁU¶ó H4±ô6µö×5ò ŽÈÑ3 ø #®ÏF tVäÛʱ­ôŒ ,B”톇¥65¯œ0½&¯¬ÌÆ=\IÕÏ3„žƒtåå5Y,}ËÃñàñ‚|¾À™Ï÷äó"ø¬4v– L_uŠ¡ÊSÕ)V©NZó‚ÍÚ‚L×ÇX·';­ÏöÞ51`ÿϳÓ÷TĘt¯4úã%…·'¤|6¯ðqcÉýš’›3J¬¬ûpfÑÝéÓ—Ox<¹ð“¬rÇÝ-)ºS4þ|”ßno‡5ÎæÍö¦MÖ†;S‹4•Æi«…(+Wë/6Óð“ÕTLåØRÒ°ÈÈJJH(J¿?+0Ì=ý jsO¿€ÚdžÓ/ nSÖê *é׫~¯ .dxÚókvÀéMßÕ…x‹CeÞâzù‚"ú‹0f÷€é?šŽhj¾ò#DÓI`/ºKÙ/”ÏõàóÂù cUØE¼}p‰Zƒ¥fƒ½ÖOÃVoÃÕ!æË‚L7°=9¬-ÚnëÄàÝE›2<ÏÎN:“òaSâµÂ‘·Æ]™šz£dÌ•iæÖ|ÑPûÙ”’ϧY^|kbÁÍ’â¯*J>­­ü(?}‰ƒÑZW«r#ítNަr­‘Nµ“ùcý:+ÓÕ¶¦Stµr´4¬8M–¼¢´´’¬GFZVR’¬ÄQ`¨Ã”µ:ƒJнžVö{]èúEW+Öà{Ï»uãg„ù*¶¯(Àì@u𿫨¾ýš”0;ájÉ S¹«Àи螠ßúBÛH`¨R×+W`nV`+0W¯ˆÜÊU)SV»D”(éø;z$'¥W&$M··½våë[O[âè㜵fó±Óg.Ý¿}ÿꡃ뫦Ύ ž>|IzÜœìQÕiQ™¾Nþ¦zA>ŽÃ|<œƒL-ƒTu†) e¹¦’r–FÖVúV,Y})i³ 5”Õ2TuÈ.GÉÊÙ£ã#DM]_9+Y+5-o™Œ¼5›ï"£håì›ÌÕtÓµŠZžîÃÓG¥–¨kR+0¶„œjçç‡à0sE+EE.׋Ï‚ùìÑÊ “5ú*¦Âr#•&k6Ý ÞfK¼—˜îŽqj³Û›é½7ÍgwŽÿ®,ïý…!§ ‚îW%>Ì‹{¼bâ½ )ßÌœðÕ¼Ú»eS¾®›þÉ´Ò/ËJîŒûaËâÙIŸ/jyܾòbBÄËÅNsìm&Ô›é•êk§© + u'YVëÔ˜èÖ™èD++™*(Âb‘#%­Á’‡¥ØÀ &äßο¦ô ¼p¢®RÖê *W!]ÕÕù£.ê÷ºÐuŠ5; üù»<€¾UÞÖ°éû)[¾ ˆò"ŒÙ1` ú¦&ÌÑnŠ‚£#o¡ß÷¢Ðë­À`´ñ·7©ÀðèÜÒ¥Žþùª&aJÚÁº& :F‘aB=OSÛ޲Ÿ¤¼Ë)s}ãÐÿÌܬêÔ¸;ã˼ØŽþ÷šºïJо)Ìù¶¾îû¥K¿ijørVõ“õ‹ïæŽy\1ý³ÚYf¥.pqXéáÔb¦»ÁɼÎX«PS5]M)\ ˜hnRffXjf\na2ZUP¢«)ŽÓÖtâ°½UUÞžÀž´hÿ-0!anÀ¶o¯@wjhçm¤So·}l8=.^êÂû+ÐO¸¥@›HQè‡[⢮êôÈ^4O>—°ÊýÎ[y ÐM†^¾Ðw^Ø@%¢¹cv xåò åm÷½]V¿ËŒ T*¢•C/¿0´ŠP}´ ÚXÑñ¨P ô*„õ Ã~Xäè¢ezn™ÚN‰:¶ ÂòCb&ù„ä ÈLάµreå”`瑬n0œ%°—e[*ðmäUmuL]+kάn»°tþÎé%IkfÌšX”Ÿäçfd榮㒞5ÃÑm$H à«:ðTì‡ÊJÉù§Ö¡:’²F<EžÕP)]Ž’­¬‚Ùâåû<|“† Qvòˆóžîà2ê’&ò\emo}‹ð¢©mVÎ JNšÆê~ª¶Ðyp€¼¤¤PFÖL^ÁF‘ VŠlOσÏ÷àñ†ñùÃù¼x>7S™;VY1Wƒ;Q›_c :Ç\s¾µæ<[õEÚË]õ–z­ò0Úêm¼}˜éfo³ÝÃ­Ž†XÝár5Ö÷nRÈã1±OŠržç~W˜õ¸8ïÑÔ)çŽ{Ÿýp|úÇyãÎ%G_z,»ÁÚl‡‡]“™N“Åe^¦¢–Z‰±Á4GÇé¶6IÊ‚jƒ¹fú¥†:‰jª`Y/àí [Ít¶o¯@SZ|ƒ §‡ ë…©.äEðS`"®.¤+˜ 3´ºRglxÝ», `…]yë¼Õw½õ(TÑÛ_Äôf—ª£¯ ³&ÖΛƒÞ+æ_“‚ ¡µÓ=˜Àh‡Ñ*b ŒÞ…Þ ·zŽ…õ ÃÊ18¿l•oŽ®c´…[‚½gbÜè2gïÔqE ÇV—ÏZ3«¡=#³ÌÍ#ÆÊ.–Gr†C¤u†H ù<õì‘ Ë§M¾¼fÙ¾Ö9 §Mh_0'/s¼“³¯»o”¡¹ŸŠº‹žñpE¾µ¤œ±ÛBFÞ¼5TÚ`¨”¾¤´¾Œ¼ÉÿüSKJÎèŸÒ†r°ئeV/Z¶ÇÁ5ÔØÒo|ÁlUM7)9³¡2f<5w7¿ ÿˆB)¶µŽiˆ®E¨¦‘¿²š5t -!¡"#§-ÇÒd±täåaf¡ÈÆã… ø±JJ1~‚/[‰S¢Â›®¦Ô -¬×V¨Ôš¨-±Ôn·×kuÐnuÔis5hw3^íf°ÞÃx«Ù~O³K¡.„z|–0üÓ‘_Žù]á¸M*üvê„ÛIQwS®§Žº9nÌ쬋Éñ;<\VZ/±7]mo²Å϶ÅT¯ÂD?G™W¬¥Rem6ÕÜ$CG'×H7ÇÈ CSmŒªr°?[K˜¤©þövc¯nÏÁöíp׆ÿœ}¡ÿƒzÞßAícÃé!—5µCÛpÓ´Àࢯ®†|½übª«ÏCꪫ›Ž6º×Xÿ¿ôMÁ\¾ €B‰Þ"ŒÙ ›åÊ[í?õfýõc0x„9 ’WÚˆ­1(§UdaaAïÒµ2ðJ‡Á±°^aè;̘½£|ÖÆŒ‚êŠÚÖŒüÊ13½ƒÆë™EE<{çù³ÿû×'_îÙr }ŶyóÚcr­\#}F%ç¥'YXU~dÕ¢_Þýþþ‡«æ7&ÄŽæ:"i|hL.GÉASß[]ÇSŠe:TÆHUÓ¯âÀS¶WàY±yÖBMwi– ,Âþ!¥÷OÉŽE˜Š†›©ÕðíûΙwü%Žøä)æÖaÿ6TÒöÖ0 êúÊpmMmcÔ ‡ õ|*ÿ¨ 8@¢ó!J•*É‘”U‘•Ó’cËËÛ+*ºrØn|X‡ñ¹œ,¶b¾§PÈ›¨Á/×U®6¶šk·;é¯÷4Ùæf¼ÁÓl½—éÎá6k}m×z[ð³¿>ÂëjذÉa¢¼§Œx”‘ø8%âN\Ð×yi_ŒOº9zä­Ñ ÷2Ó®Fø®quYcmR§-œo¨Ua¤›Áç”è©O5ÖŸ «:ÍTsK û*çyÎV…:j#•¸)šj£5Õ¢”ùZªoO`ÀOô{¶WoA‚‰×ïÀõÒ鯎öóNõ;¨}l8ÝpîܹÎK™²ìÛi¥Žëš.„GS`¨NÇn"¦.ð<¢%S]´½ú 0Z]LºwØ[ºË£ Ó€Bu†YkíÝÃì @u‘ñù' <¥^x›ý§Æø‹Pˆ6ºº†™Z‚šÌ]˜hPMª ÀÑ™]z%mKÕÔ­_¾vß… 7ë—úGdò4†š0¶Ö2rß±i÷7wÞ¾øáÖõ;·®›^9ßÒ.ÌyX‚o@rffñ¡={?ºxòԞ͟}üáí+çwnß:«~^X\š“{dFVePèX¡­PÝ+°Ð1ðTÕtòO-0ÖÿQ*£+!k Ƕ„Å,Ñþ!¥/:©j9XÚù¬Ûz\ j_8<(KVÑZšm£ ì4DÚµŒÕ ‡kø¡žƒ:ÿ0•Žl¨”@¶ã;†,–)‹e)/ïÄãòx£9 ã¹ “”yªœiJ‹ô4–™k/´Ò\ã`°ËÅ8ão»%ÀñHŒóÇÃÎGGøŸöw=|=:ðFÒˆ‡q7cƒ$FÝ x<6ô㔘û£G~–yÒÇe‰¹áZ;“¹Æší ÊtÔÇ 8ñr&?«`â¤kçðHjÉ)Z*«;©hÛh¸+ ]x*NB­aò+I–™¾©/_hæ7}ÆBI-y¶ƒ¤Œ•Š–§²–Wè¦c"Ðô´tŒ·vzŽ‹0E))¶””|ÇŸ”`IJ*ÉÈjȱtYò&òò6œŽ¯uŒàqÇr¹<öT!¿Z]¹ZGµÎH½ÙX«ÝÆ`½³á©X·MÃL7¹íñ³8âe{ÚßåR°Ë)o‡ÃÝ.…û>s5Ü÷ñ˜èkAîwüNy;~4Âïv”σž'œ-V8˜ö¶Ÿc©Ui¤6ÇH£ÉR¯PSy¬ªJ²?@Y)BÀKÔR£©%TI7ÐÏ·1Ÿeg>ÓÆ ^]ØÁM°W÷YL`´·hˆÀ ql8ÝõáR‚]huÁT‡§¨œ¶¤Ón¢û³.$0Z]˜·è§³·ÜÚ½ûï¿àó·êjëÌÀ¬ãîÎ:%(TÑ_aî…µù.av@}ƒ €êt—ÀK¨s/¬Í7+DÐ6BÀqᢠ®°Ÿ±Ã4º5Oób±0(H«Œ…ô(P5àu`2kÖœ†Ö­Éã+öï9pÿÚ½±c«4M"Có¦–ÌÙ¿÷Ã’ây&MM+ÇfMI[®­Èºkøh긆H÷ö S`ñ‡9 ¯™:ûâés¿þøÝ¿?EïêŸ/ÿüóŽÿòÍ“±Éc£cýBã-íƒØ–BMwS_‡‡H3«`s«7ÏD i= Y=c÷!ü‰e áÑ9C†h(òœ…º¾\¡ë?eÍ4  ­FX;´wŠD=ÇV`(°“*Á“’Õ’—·TTÆañ¹!<^:Ÿ;]Y¹A]­AK8KSu®¶Z‹¡f‘Ú\3mÎ&‹ì´Zt6¹šmv3Ûíi»ÄÖpƒÙÃÝöûº] õ¼êy3Òÿâp§+n>«dÊìàˆŒŽ_“ëø©ÕðÀ´Ââ™U•MÅESÍ]9jD–£…—»½WÃŒY|ôÕ£_=úìÿþ÷?^<ÿßߟÿß/_¾|öáíÛSËêìíÂm¬ÃÔ„ö††®AÁ#ÃÂ’‡GE¥S,'oÈUvÒ3õü‡´rݼÕ~ÁiJê®RŠÖ–UW5=?gŸ16.qt·ÁC‡ªÈÊØ+*(°ä¤:þ±YI …Ž‘YWž%‘Èʩȱ´YòæŠ ¶lv03šÇÏSRš£¦>™ÏÏã±´Õju„õ†û¬ ·š¬¶2\ne´ÛÁ|•Ñùˆá­MÎø8í°1¾èrÂÉâ²»Õ®ÖGmL–›é®0ÕYgeØb¦S®+œ¬¡”§*ÈPd*óÒü1C¨ç¯ØÛè?:Vˆ@/ÀÀC`®ŸÒÐ/Á,ÿ­ôЇŠh/ ¨†l‡‡½®ÕMëKk—ùø›¯î”¤jäkïµiížÖÖ »w>wæÊªöõ™Ù…S«šÌm%d M-CÃFŒ›9%66­¡nÁÒæåå“j£²ôT­ 5Ì6¯Ýxå¹§?ÿûÿþxñòù¯¿?ÿõÏ?ÿØ·{×Ä e¥%³l‚ uµ5-Ý]‡—•V×Ï^P:¥zÝÚm[6ïÒÒv‘‘·ó Lý§œjf~ÙâU»Öÿ”³` „z¾Žž£CcKtÍènÓ+0I ¡<‹/+-Ùñ/GR‘„õ™¤ŒªËTQÑËuârcüle¥\r:‡S£&œ¥ªºØ@{žºÚ }í™Z*[Mõ—kÏ7Ó_i®¿ÝÉv¿‡ÝNG‹U¦‡]¬×Ú˜^õu8ig²Ó”v |X“•ÑGËUÖFMš:êyBAª©Ìãeéj褪 3õ´F( ü…ª#TU¢ùü4Cí2ÝlÍž~ îàt÷DÛt¢Ž{üáÃh› f©nxØXSTh•Àé€Œê ¶£HñJ!Æzò!Ðø 9Œ†öÚ`ª €m¬ÄÛº§c³EŸ9ªè¿ÃlkÿmÃ<4@u¨3HW¯\~Ñ…(̰öû: Vˆ@/Ñö^÷ù! Öùà «@/Ñmö\`¡1…A1Eí«wüöý¯3g¶F$•äOjš^>ÇÉ)0&:µtòôc'N~ùÍ7J§gå•JJë²,‚Ò4`‰¦c±|Ùš»·îܺzsvżaöAY)ÿúê»g?ÿøòÅÏ/_üòçŸ/ÿïåoÇím˜]Ÿ—]šœP §éli6lN㢊ò𢂒éeÕ‹Kk*ëJ&”[X —S° ¯¢a0ºðè©æ¶ÁòJNr<{eW]‹pß1*Z®t·1a‰ÉHt|¡ÃPAއ˱QP°éü;^|¾;—ÈãUiªU¨«U UÇó¹E\ÞtåBåV­juåùÚmÆËÍ Wë6è–«*ïq·®VV*+¯ÑÓ=ìhqÜÓv•ƒÙ+½fCÍõ 5å*Õt®Â"#Ýñ|Ž?LS­PS8BE)@]Ý_]ÝËõV$iÝJ¡*ÊFŠŠ½¤ó†ÙêîÛôœePó±ç¼ùGˆo#0(4@êyµ \…Ö^ð–všë¿Ô…J°]D$­®ƒíÞª †BÛ ‚ÖU]è)Ö¢Ƽq¯\~AÐu ªè¿3P‹0æA×õ …*ý+ï²ÿpôB.mDW‡Ý¹cÐë-èìO¿ HH¯—?ó‡¯ùôã¯&L™£¢7ldê”±Sâc²b£Æx ^¹bí³§/6¬ß2eR“¹Q°¡ž»ž¶MaAIMÍŒ3§NýòÿŸÿòô«Ç_üñüåŸÿ÷çÿ½|öÇï?üùç‹ÏÜ9êĆU«ê›|†`É xÎZš®‘1É3fÖçåçç64Ì™7gqúè‰vÖ~Z–Yc*Ì‚ŠóëO½22!O¨ë¥¨6LJÙ«ãk`¢¬Üñ78L®ä†J* •aKËð¤eø2²ÊrrZòòÆŠ lEŽ?4¥àêâó}øüH¾`\ç#‚0%å%¥*ua‘@)—Ë­ÖÕªÕNWV^d¬_%T¡£1][£LM¸ÜXo“™Áf#ݵ†:íÆz›Í V˜êÍÑS¯×+ñË4TR…ÊSµÔÇhª‡q¹ñBa†ºúhe^0Ÿç¯.ôRR ÓÔ4VT´WR2åpUUÌ9ì €+‚nèôÝLá,ƒŠ˜=çÍ»UµßA¡ÁBûëë7ô;¨}l8ðNÂê ‰ ¥ó̓U¤(ZcèÔ…†ƒUþ[@Wè3C$-½©KÞÇ–~Š5BóVFÝλ®8£Ø Šº„Ùv”·ó Õ•Wõ. ª”f;ØQúè&0Ú@`,˜^¬´`†A5XuåFįèøj$fbî¤ÏU•]8ëî­ŸÞû,qt^íÜÕM-² Ê òËf/INŸ1&MûÆG>¿vå゜ªðÄÚM;wíúô³ûkV­8~èÈïÏŸÿù¿ÿ¯ã}üãÿýúÓÇ>Þ½mÛÜÙãÒÇ/™ßvþì媚yNNÑf¦aÖÖÁ^¾aåå³<ÜýÛÚ–8qtãÆMáqîn¾É‰um q9³f´nÚ°³¤¤ÖÈ"XY×WÍ4Lh ®;ŒÙgl&9t(GR¦ãŸ“W´Td[±Ùòò*,–PŽ…þ¯•¢â0– xðx6l6&NEe¢š0M]=NI§¢T¢¤”Ãåæp8Ó5Õ3•Õšê¹**q\@_ “ºY!P›°/LVìÐÝв|÷•+·¯|pyòÔém«7Í_²fdzöÌY ëg·äNKJïä8ìâÅ‹Ÿ~úùœÆ…ùÅmmKOŸ9~ùêÙ#÷Þºúáw_~}ïÖG‡÷î?´g_ËÜæñéÙI±£,ÜRâ²Â|ãó²'Œ51ñ15 ôöNÈ_2vìËa+V¬þâËOwîÚ¼xIóƒÏžý`áÂÅÅESÚWoX¿~ÓŒšy1ñÅZFšf¡šÆ\AÇ_¢Á‹0yI)¡¬¬ [AUVlÁ—‘S“c9q¸à*°— —ãÂáºñùž<ž#gÉfÛ**Æ« AfñJ‚0åÑ¥D>/MC-AE0V[#J™Ÿ)T åóý9œH>7UU¹ÒP7UY©XM˜ª¤'( 2T”Ó55BÁ[A´Ph¢ è¯ª­¥¥ÎbYs¸Ö|ž¦›+#£¥ ©©é­ªÂ–‘5TTTQï¡Àà bÞ‚BäTÞç {õp\³X¡Ø4†ö°‚©1L]hÛý•ô¿À¨ù«B àuwfkرÞÌÃT'^‘ê?tØöùêsçv|oÊ-:ÿuJp ^«ÀLä þÓiî„”×}_‘ö‚¦f…qÐý®‡Ô4¬Ø{ðìéSÖ¯Û¼mû¾ÙsZ|Â×oÞ;±¨|lÚ¤ÄøÜ¨‰{÷íþù—Ö®]3aBá¹ó§·mß´eÛú[^ÿèÚû·ïܽ÷üÉÓûvîZ¹x傆EÓ&Vņ&MÈž8,ÖÉÎßÛ7ÆÀÐÍcX\TÔ8s‹a#ã³}½¢Ë§Õ\¼øÁÍ›îØ±«nöœ¶¶•'NœX¸pÁ–-[Ö®Ù°tñú²²fçX%o]Óÿ|} “êüüOzèPÙ¡Z,eY–è„ͶTP´ápœù|>ߦÈNTUŽWQ äóGþ|¾Ÿ®ª:ÞPo—ÆçC¹’’篢£¥ÈãŽRâB‚>?YIiªP8^UÅO ðæ „B-–¼›mÁåY)+ dd¹\K_AZš'# K136ÇOMU‡Ã…îI•è­À˜…`T“ºã3}xJFè!ñ ¥‰­ÇÀ^HfrÐ[u!ÞT`Ì›5ÐÍòÍ~êÉkò.aÌÝ÷¿‡{7ý‡n`ƒ§¨{èæ‚ê€´à6‚%¹eHtuú¨L[Š6 ú̇öe´',[³ÿС³Kš—Üs¬rF³™säÕ[ŸnÞ¸+5iÒ¤âÆ…óWüë»/þåû3§O¯\¹òø‰“óç/\´hñ¶Í[?¼teߎ]së¶®ßÔ2oÁæµ¶¬Ý´¢ue}uS뜓f•—6%žàäâèâ1,JSËn˜{T숱M ­õ ëZCGk¨ZÖÏ^pöì¹ã'Žž>ufÉâöÙ3[jg,=¶ÒÐ"D¨å†õ¶«À˜áÉȰ¥¤•dd•dd4X,ÍθٞÃqâñ<ùÿÞJŸÃDñ¸™nŸ—ÌVŒá°ÁRÉÊÊ‘BÕo”Š ECÃÇó¼xg.ÏOÀwáó}x¼‘ªªÅêjÑ|ž%‡íÏŒ×Ôp䤤,”•a½å¥¢ U•WÔasd%¥UY lieËžÏÓWP€¾_ûE`3æ¯@!µÕ™îŸÂ¾ÐÂ›Ø @‚ÁÜÓ/ Á ö1÷ô ¨}l8„n]½PÚ~u!úY`Ô-üÃl;bÿÂ<@þ5é¡À Ì6±#öÐ $°‹ÅÂöbeØ.,L‚‹ « ‘Þ`E…~ú…>o„GªÀ*÷Í^@îĆå+÷•ÍØ¶ñÐögøš.µ ‹¾ùêɆµ‡Æe”56´Üp÷_ÿúòàK/=°ïÈÎmûÝ]ýÃGìÛ¾ëȾƒ»·nŸßиhÎܪiåkV¬Þ¾qû²–)ñcв'M+öö‰upîë5*1ÇÜÜÓÊÒ7rÄØ¨¨tkk[ë@Má03£€¤„ì•+Ö8pxýúm‹k=\#]Ã’RKÌñåð:IKHdeyÒÒ²’¡¬,GBFCNN›ÕñçêØ.´ÎãÅr9‰ÅdyV†‚|‹5šÅÛ|^‚€7ISuœ€—«"HUU‰p“•¸ã5UcøÜJ‚XM`¡0HOÛ™Çõð£U•'èjr;¾6²4ååÍÙŠ’Šl[_­hÅãqee¡cúlEèêdO†,ÁÊôRÇ„þ+°4§¶:ÓýSØ÷•ó­W€P;o#þàß#ЀŸÀX!ÁU÷M]ˆ7ó6 üíò«çy7‹æ!ñê?ÜA$Ì%ÐR ”OáŠzå}ªóÏ(RAÐçÕ+ƒµÓs¦ÖmŒ]‘’^yáƒOfÏ^X?eïž#_|ñe[ÛÒÑ)i«Vnüù‡Ÿn\¹¼eݦö¶5·®|\_=|Z~ÛÂeÇÛµeÛ‡—>øäãË—.wrðIIʪ›µ°rz]ÉÄÊàÀèèȤøØÔÂüÒÖE«Æeº{F:‹³r õž¤¬é8TNÃ1×ÚedLª¬™—[8ÓÍ3UÏ$HÛp˜O@ÖIÄëF)¢3r’’ ’Rjr,II–„”&‹¥Ç’·c+Z(²½y¼(%~¼€ŸÀåÆq8¹lÎEùL.;•¯8IMPª¡œÅgg« rµ„ãTyyZÂRSÝÙŽFÓMµ+, §YŽÓU©§cÍfiª©ÊÈè+²ØŠ Š®ÊKNAVÆFÀ·Qâkȳ„`MŸÙ+H¿ ÑéîÛS¬ÍÞ‚#¾Á†Cèä*P½ëÉ75º¡?Fݼû)Ì–±ãöÌCÔû)Ì–±ãö pÁ´ÛØ«L/ÞBƒ*ÓÁjöqc&Í]²‡§â”“3«µuóŽmÇ÷ï=½wÏ¡CŽÈΚ²ç±K§/]:syÇÆË-›Y1sJѤ[¶ܽ÷äá£ûwîn¬­›VZ\>mfUÅìéåµñq£ý|BÌk;¸ÿTbÂØ¿ u Çg—YÚ‡hè:óT¬$åtÿ)­emèï8*7¿b˜O‚"ßQ æjalíˆuñ:Ñ‘éø+SÒÊ?…’Q””Q’1PP0–W€’>‹åÊåúòx1\N8“ÈåŽår²¸Š\…lev¥Žò'½©zÊÕ†Â;ÝYöz“´•fê+-j¬5S•9Å:*»GÚÆ« BՄÕ•} 4½Õ”AQf\N‰‰¾:Ÿ­©¨à¬©n-HJtü­a%K¾sF§çà ià¥7 ÖZ<~;î!ÇPÏû;¨}l8„ž€4`å} ï·0æ èÉòÎ:ºoÂUôú¼íE ³q@ìúzò·ö(&NkšZÑfh™2vãºCËÛ665,ÊÍž¢­nëç5£¬qצ}N^8´gßÚ•ËÖ®\ræøÁ‡woŸ=~²´¸t|Z^ãìy›7ïØ½ëÀºµ› &ÅÅ&®\±aÏ®£5Uõ°ªË›R^VŸåí;Rm ®içå?*¥x|VyzÊ„àwhK›޲ƒP×ÝÄšúÇSºÒ½À$‡íXu •àKɩʱô9†\®†,KS¾ã; 1G'N )Tg¨]¬«>^ÈÍãÄrØ)ÊüI à +…™jü=•Z[íX>'V‰;ÃI·ÞUÇ—Ï­£r8g؆Ûr[Ý8®ƒN™ƒ¶/kÍãç˜pY,_›ËÖe³Ñg†R’’<êJO&â ÁhŸÜÜ;ýÕÑ>únÿ‚ÚdžCxÇô›À¨Ûv·A÷\ª¨Û0ÛÇŽþæ0¨Cvªë¡Šº ³}ìèoÕ‘´böœõ-ËÏhÚ?²È×3j÷Σ³fÎ]Û‘1.mRá¸É 5sׯ\ÿñÍ=¸÷ŧ÷~øöóÛ×®ŒINM‰OÙ·ýà‰£§¯_»yòÄ™õë6mÚ´íæÍöï=š—SÞj¬_ÁQq±cÂÃS².\·º}Oûš½KZ7VL›3Ì#ÖÊ:TSg˜–·[Ö1&»ƒ°$$xÒ2B9y}6[]NN_AQIVΆÇM²3¹r8N\Ž-Ÿç£ªZng8^K9Y](à‡ðy ®:ÃÌŠÅzJ›¢¬*,„‰Êü]•…^ú|n€²`ãH«SSB–kðËLTo͜㩟®­Ôàa¢"°ª(J˘«(0Ò“’”–”Ôç°©>u†¬ˆÀ}¼ý1oÍ@O–/êŽÛª¨Û¼½E ³Y@ìú n`…¢FUÓš¶-Çö¾4kÆüÖÖ¶Ë—¯´¶,[²xÞío]¹yâà‰ó'.\=ýöÕ»÷nÞ»ûáík\>yèèÑý>ùøã[7nÞðàÞ½ûwîÜ=yòÔ²eËêç­[³½nÖoÏà’‰«Wn.<£nV˪ÛV­ØÚP×ÚÔ°tÑ‚UÓ“KâmbÜcŒ¬}°^1é‰À`ù‹0ޤ¬KÞX±ãOr³Ù掮<ˆÃIÔVͰԳb³ù‚HuÕ :ÕÖšEvÚ^‰æÙR_XuM·Vßg•««”,äG¨| Ò5•}øüf_ý"C¥ S}Z"­Ë­µn΋>1-|†›ÑÖÄa•NV¬|5„BEM¥(3=) ‰Xc}i)ª[D`ÝB6èQ7ì¿ Ì$tÛ… ªèïÂ< Ö‡7Ù,@ìï":ýPO°Bd梕 —¬]¾lÝŽ;OŸ:qùÒ¥Ó'Î]¹péÖÕkw>¼uãÒkçoìß~ôà®c—Ï^¹qùú·Ÿñí¾~üà³OîݽûÑ­[ž?æÐÁ{÷ìºpþÒáC§§–VϬiljhÙ½óH[ëš kv¶-^;oN[UE㤠յ3æÕTÍ+ÌŸ=2~²`¦sÖŒž Òù“0¹ŽOõY,–¼…‚¢¿€¨¦êÄå&i©”Ùh[+*º øc Õ²Œ„7fHÖUm(ürKF¼†ÒÂ`ÓEIŽ.<î u?¥Tõx+Wf«å+àOqÒ½R6FGysŽ×½ÍSµ•OV†§ši ää2ít奥eeæ%úÉHI™*+9hR}"ë"°Á@_î€Ì›2ÐÃåKßò61̱ë?B\”–7­ZpËÖCö½zþÒ½ë×?º|ëö•ÁXçŽ=òÌ™cÇ>¼ôÁÑý{®}pîу»W?8sþÔ±Û×/_¹pæâ¹Sð…_?þäÑ' ²/\кmëÞ¥‹×®mß´wÏþ¥m«ç¶ÎnZ<¡lÖ¤©³ò Ê“GçJÌup ÂzÒ•žLrèPEIi 9–‰¢¢Y甲æp9Ü<¡Ò4]Õa<®§@°Ð×(P‰ï.à/·ô(íÈpß^£¡ôÍ–1EæjGK|ò] ,Áp|Î8S50Y¨o¤ ©£¢Êb((Ô„X­IwͱԹµ4e’³Á­yQê<–”´³ ÇM‰}ˆ1PSå²-Õ”õ¸¿†BÖ D`ƒ~u«~ka ëIß`6P‡yka ëÉ› F¦Î\°uÏ©E‹7ìÙuê쉜®_»póÊù«×>¸²mã¦KçÎܸrtõé½Þ½ýñ­?ùø£ÏîßýêÑ'_~öðу?¾uý£[Þ¹óуŸØtQó²ÛŸ;sùÐÁc›·ì^·qׂÖ5Ëë³ò¦'&21sÁúðJz"0Ù¡R*²r–l¶Ÿ×ñg8x<>ßµó—‘³U ±a<^†ºRª¦j¬Ž°!ÀÄJ‘=ÚPõó iú*·æEV8i]¯ È4Töä±íÙŠ‘ÚÊ<Ž=Ë“’U–…¥ÝP©¡†ŠŠ«ÓÝ 4öOò-²×z¸&Í_(ÈÊqdeLÙŠ2’’ΪJ¿š&ÏR–g¡^AÞ5w~ÿm¤Ó_ä÷ÀÞgz}dÞŽ·º|AéßE ³)@ìú/¾ŒÉ+­ª_1vüŒ•kÎîØ~nï®ã÷>{úòéçvíÜ{ëÚõÇ<~øð³û÷?x<øè£û·oÃ#pçÃïÞ¸qÿîkׯ={áòÅëÎ]=}òÊžG¶lÚµfÍöéUMþ!£BbÆFÌó>ÚÈÿ‹¯£‡+0eY9ËB‘mÇå:òx`//>Xç_DÌPdãqc¸œh%n”š @U`Ífñ¹ó| ×EšmO²nðÐý`‚{ªªb†Šb¾&/V…®Ì3b)ÈIHJÿõ‹]ò’Ò>jʵîz-ÁÆE¶ÇJ‡Û±9Æò Ú,ycE yy­NoÉIJ±¤Þ·Ÿ‰u°áÞ1o*°wÖŸÞ‚µöîÁú3¨pñŒŒJ˜œœY¿pÑŽìÜyâø‰K‡ŸÞ²mÏõ+7>ºvë£ë·[Woܸtýæåo\¾~탫WÎ_¾rþ<~pgN:{ðÀÑíÛö®Y½mýÚ×ï^½zÇÔiI©âRŠ<¼ã±ƒvOO‘•ÊÉ™°ä­Øl.×–Ûñ÷|ýøü`/Y^>_3ŠÅŠæpÃyX–|~ Ÿ=ßM»ÒB­Ê\¸d¸~¥©j•‘°ÑD}¾¹z£©p¬€«.+ j”—R•‘1•WÎáæi)•h+O±Ó˜?Üą˵Qd{ñx!<hÒ\ñ?ŸÒy?öøí„üØ` wÃîÅÖ«žƒµ3P`½l¸û%UÕ.߰騦­Ç¶î8zàðÙµ›vîÞ±ÿÒéK—Ï^¾xúâ¥3—Î=sêðéS‡N?pâØþãÇ?qàÄ¡}÷ïß·k×Þ ë·®\±níšm×í^Ò²vÆŒæœÜªˆ˜ñÆV¯þmånè¡À °`R—cé±X¦ ¦ ŠŸ(r¹àª¶b‹tþ)ùd6(m$[1ž­P àLÓÔè©6šª×ë¨×ª¨Õ Õjª·éh/ÒÑrUPP””ÒcÉq8¸üLy…i<¥¾ B[%WC y|~$›//Éã¹ðxò’à»ÿÊ{#°£þ×ûôjÖ…5ýùQ °^ NâFæ-hÙ¸~Ë‘ö{[Wl\»fë¾íŽî?qìÀ‰Ã{!í9²ç¡][ölÛ°sûÆ]Û·îX»nÝêÕð°eù²õ-‹VÏoZQ2¡vTBž«Ûß|Ûðuô\`é¡’I)%Y9Xñ¤eôå:¾F‹0+•ÅoÆòYÜ l^ ‡—Æ’ÏTP˜ÌáW ”ë„jóÕÔ‹9¼qŠœ2¾Ò #½&csyŽ””=‡[Àår6¥ Ðloà¦ÀNär3Ù~<ž=— Žtæp:ÿ1CK^Rºãw«ÿú‘¬ˆÀä#Äw ÖŸANäÈìÒ‹ëZ¶´.Û¹zÕžU«ö¬]{`õê½ëö®jß¾|åÖ+·¶-ßÔ¶lÓ²[–´7Îi«®iž:uÞÔ© “§8:t÷{ÊK¯FGf¨Tǧ’Rª²r– жòò–ò –ŠŠ® Š IòŠc¹I ŠQŠ ð˜© XÄá-1Ñ%¨ÉÊ‚´¤%;~ö%3T‚-%Å•–V•–ÕãÊÓË+YIÉaŠŠjr,Aç? ­ % R”d8Ò² R5æÚ¶JŠP“¬ˆÀ½ð6ˆ™?aBSMÍòººµMM,ØÚÒ²½¹eóœ¹k›æ´7ÍYÓиjÆÌe“KæedLO5!((k¡oôM`¯ H }'Cj¨„´„„¬¤„ž¼‚-‡kÍf+(€«:_ì‡()ÈXýD`ƒ"0‚halâêèäï?2*z|bbIRÒäø¸¢ˆˆìÿ4gçh#£~¾eƒÐ/$ˆcˆÀºl0@FÔP*Û`Ã;Àä÷À}†Œ@ b @ Ä"0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0ámÑØØX^^ŽÒÌù+X9¡_Ò¬ðžAN0ðVu?~|Ù²e¯tXRRR{g&Nœˆ½Dxs½P°—ïäìöê‚ø+Ø«NN/ƒíNè@Zð˜êÊËËÛÞÌa`/Xx½à‘¬ßa^žÌmÂûG¿Zê¦øW°WÅ…¶¶¶nf<ÔA©a¢¾õ6X#„7tö‚ xlü+°*€±:?8ìlƒÌè} ývý¾îr&¼ôÏ©EwCê¾.bwö^FAÏøÃ‡C ý½ tPù€Óù®wt m@z¸µCx@E ¤¿ S]...X;ËÉ¿ V_ &4#pÍ¢ Wgg´Ñ5X#¢õv¿>XýÁ ú³ŸzÒå)¬‘¢ó]ï©´¨-19MÐI,XQ`ng™zd/P Öڷŵk׆……uó(j·Nj6÷)XS"¼ÃÝŸˆˆ Œþ~f ¼á]Ëß·%0jë3P þ£@¯¨­¿FA=yU°v ºŸhÒÃm¬QƒÙ[Šh Œ¾±wl—7¤ýî[°v x[©ý]Ð9 ƒµ3P «Bõò5£^c¼Šµ3€Poh/ƒ5" QÁ‚ 6À[à3ˆˆÛ‹šC†Tö,TmѸ~©©Ð§`M èͤÞÜž킵3àÀ[Š:Ö5è ‡`»¼!ýüP}ý;K½,zo=Õ­nÿ ‚ªÁÖˆ(Ð}¯D³ÏL¨÷ºÁv5@ZÝü%‘¢s.÷%X;Õ›^kd¡:Ôû`툨cÔ%úWP! Vÿ õÛ ¾4ŠØ÷ „÷ "0@ ˆ%D`@KˆÀ –A,!#‚XBF ±„Œ@ b @ Ä"0@ ˆ%»³lGuúºžs'¤Ð%Âû õ÷mÄ6ØpÄ8¬œð0\Ú+´Ã*$Ì%ä}lá€z»+|c~7Ðuèú]aÖÄ “æ÷“û˜ƒ§Si„wCq´íê’¬ðV¡< ¶Á†#Ž0í%¾Kòö°Bч)§^a 2CÛ*Æú˜cÈ1Vz4¦rt V+Áv¤Ë™…@Çt©š¸nmÛÇô. Ÿ´h‹Ñ lòä!0ñ1 «&Ê€ºJG:LеkÉ÷É 6Ç^%ôæÝüuÛ]é€8Ž8ç`nˆH]L° ¢ -¤7¡›E*‚G ½Я‚éÝ¡ ª†@;Ø6èpˆêø‘?A`´±À^z"L|Э1z«&²xY©EÙ4dzT¦8Ããèá&å‰NXBO oè]7^G‡Ä9ØpÄ8X‡–úWNè§X5‘SQ€¥2 ²Úî´£ŸÂîÐSK]W¨´€6€Žé+°êôîîîècCX𔤈‚©1«&š„»è:h'ùƒ´¦ÄÛDÚ;jƒÉ «Iè èžÎ|ìž ˆs°áˆp˜`¯Š´´h° ¢ SE}ƒ^B1}C ¹* ]°¥¼J7B7EƒžB5ôˆè˜1ÉÉÉ´±°§¢\¯«&šØkÅ3Èan•ìgáªã¡L†Õ$¼ (ˆm°áˆ´´Ä]`ÌVA”ÁlÔ7Ð7;cW˜ŽaÆ >Ú啳IU@ ‡1a®½3æ÷“ûæNH¹³lØ;fR¬ÝH/Ãq¡–m2¬Î ‚º7¿&XeõZç«ÔÖßÛQLƒF!îÀi°Bqa ôƒ•*¯ù*/«˜ßûxå.ÈR´Àº:ìÕ«N±ÀTሠ6(AO ï€âh[Xu!“a/ B¨{ó«ÒõUæŽ(ì¼%þMèÊbzÔb œ&Ø«¢2VW°j" S'=$6 èça°üÂV`è]]¡W`LK1†9 k¶Åþ ˆ Ô͵ÇéùîèÕŽUwgP sGôؓлˆuÐ(Ä8¬œðÀŒÒºú`LC;x]e@…±!KaCÐC Ò{‘ICèzlw¸/S/üwÐýšù*óNo¿nwf˜•Å:h✬„ðnÀŒò&€½T:…„dCûÀ>9DÀ² *„††ÒÕè/q`ö°iȼ!ô?Í›7Ÿ8q¢¢¢ÂÓÓ!ð…~Š¡&¶;Ü—;ÛÀC߯QæíÛFõ» ³)±=j¡`RÁ ?úëfEÃ\!ßÐÖQ1Öïê0´\KNN†:ØŽ]Õ… «!àˆä ô?Ð-0zž¢’ »Ywsï~åîXèÝaC¬Cš@è˜T˜€`À=°Å+WQ]¡íÂj|ÐR„UŒõaFï‚ ÷{¦ºCè5EC.BÿÓÛ`»Ã}™zá¯`wjTáu·ï®»w ½/lˆuèQ}€Z0èø^'0¤%æS¤Ø‹)€vr] [@… -Pì°Dc:ŒùEDh\„þ‡º¹ö8]w§<óW˜u˜¯vÝèº{×Ð;†X‡5Ð6^ ÂÂÂüT AcØW UŒõ¦Þ SNhw¦~0]ÌÝ¡X[x1¡E € rP÷fF°W) 1<Ĥs¿O¯*‹lèQ}€ÖFW]ÀHà6TŒõAQðÛP‡¶-'Ú^´2j3"À*ÿý•æÏÃh‡‘ € fPwî¿‚½Ú[¨VÄ6Øp„^™ƒIÜ„vZB*Dâ¡A&ƒG¤"æKðíN·éÚa¯ÚDÇE{a_è€rÔ¹ƒÊbl8B¯À´Aö‚ÇÔHº.’´¥ÈdØK´uh ^¢y%°;( ­Þ½˜C@;ä j(ˆm°á½ÓÙ ¦Òù· èB8y @¦AÛPÀ.è)S9ÈIPØÀ`_tDz_d/×ZÝš"aPCy@lƒ ‡@èÈ1à ÚL{!B§M„:` ´ƒG „T„œ„Œ‚¾£ÊÑ” WÑ6*˜í3¡+Ðm"ÃSÝá1,›%蛊ä j(ˆm°á½ÙlÄt¬ºÐ†Š±¾i¢;¸Ó Á~¸…@•™5QeTØý'‡Ðæ.LÀ`#444??Ÿþý0r5”Ä6Øp„^A ÖXúäÙ‹¶’³9èê0àuöBî„ÃÑ5™‡@m"“æ§ZXXÐOÉ@ÔPÛ`Ã!zØ[ZNÀ4°•?жmºs»«Ã˜ÒBÀ±°jPH:†-òÐáЉr5”Ä6Øp„^Á”Òóé+?$¤¡-‚^…¦àZ Ûdª  ‚Péümh槈Ô ´ïZË£E. †ò€ØÐ+@ èom¼’® æ6 Ó(tØ^K¡Ö˜?ië*ª×A7H‚Œ@  < ¶Á†C ô ôïƒÐ#¶Ãä>£Í€Hh˜åh¬)мDÿÄ ¶Q}z­K1æÏÃЫó4ä j(ˆm°á½œJ+mÐò í‚l*Ðò` Œé0´ ²•t ‚n«ÀÜë}´A. †ò€ØÐ+@ÈÌGDP<*Aþ ¡-‚ €BºjÛ=E/¨¹@¿ ë0z)Ƭ@;’ €0¨¡< ¶Á†C ô ÚLä;ÿD/ýÙ‚^Ÿ!{1a @Õ˜t-¤[£7è§phðý]ú›ŠÐ¸ †4F/¿ÐSTŒ@  < ¶Á†óæì¼ùZRglÀ*ÄÐ-p,qhyÀ6r’ý”¶Ð{Ñþc½ í£š`2ô30Ôè*GP;D`„A å± 6œ7Då’2­+`/xÄ*ÄL`4è   ‹ÀÔŽ?(E¿D×GУÁ* P›à$º€¹–Â` 9•. aPCy@lƒ çÍA›½å44¨«Lw0ÑÚ€ Ð('99† t}í-´Ã^E@k½Šbj «‰ê ½;s/"0 i@|ƒ çÍa ‚6ˆÀÞW˜£í mPWhh(]H—3÷BÐÃÊò9t³Ìöf5zw&Ì à0°)Z1NFÔ Û´øΛ¢J±»Böþ©¨«ZЯ9C!öñ]×OÿºZ  …U£¥`?QCÌ}Ñ¡SÉ¿FôPÛ`ÃysÐϺ^V™ î€À*€q!Š ¤4c}ú/t€3Їxh E×é ÝúÃTÚ=Òt}€ÞìE A·ÐâLNN†£5”Ä6Øpú—Ù[n‘o¾ß€0U пiaaÛL÷À#]§+]Ûéº> -0¦ÃPeúШüJV`„Áå± 6œþ…ì½§åççÃ*¶‘ºhè:4̘t­óÊÊ´®huÑ  Ìvè ‡ðHFÔPÛ`Ãé_ˆÀÞ{@N´'h0aÝ Û·«xè—º‚*±[Uém¤(úˆÌ6‰ÀƒÊbl8ý Ø{@+<‘›ËCH]¦¨Ð4‘úù¶ -žW6`˜ ¿DÅ$mj »»{Tþ¨ÐÐPxÊl‡>:<5”Ä6Øpú"°÷Z`°f ã•k/º2Ýz•®¢bBWc–À 6à199ìCuè¦ttx$# j(ˆm°áô/D`ï=˜ÀLU O`Ð/1÷b AWC5Q$ª®Ð» og„esP9lÐ/1A=!# j(ˆm°á½¢çà l/S]®Œ*¼TH›ˆaX9‚n # v(ˆm°á½¢‡ÃJ˜•iÓ0r³fÍØ­ªô´kz/ ÍBP—ˆÀƒÊbl8B¯è‰À0èjqsSÐ2 ¬œ^i®ÐÕh{ÑÐ/1¡wDöB_îG!aPCy@lƒ ‡@è´ÀLä@ !ئ]Õ h/&LÑ`uTŽy‹ ¼úºÑKÌ!¹ƒÊbl8B¯!¡/¬Ãú lAKâ• :4´o0^÷*ÓX£®jÒÐ…ÌÊôQ°>ä j(ˆm°á½‚^…esèïû1Á„ACW`šÀ܃Aû ÁT‚~‰¹},¬äg`„Áå± 6¡W¼òg`]AÂ`n ˜šéZK4HW¥×µiu!è ô¾ô±tt𠹃Êbl8B¯è¡À$]Hk ÝÃÔ*gn  HWå·ÇuUí‚èÚd/è<¹ƒÊbl8B¯è^`´<ZôSx¤?u¤eÓU?] ´·hÐŽLèúôiÀ$Ì%È@ÔPÛ`Ã!zEßV`¬í›W‚É ŒÅ\~Qù£à«;2¾„ã"{!È@ÔPÛ`Ã!zS`´“À̧h™m èWi0ßÐö˜Z‚—à‘Vúú> T@;BeúˆD`ÂAy@lƒ ‡@è´À!Ð6ÓÌmä ú)‚Þ@¾ÁJ´½0ÀUP ìëF`tƒ°MÛ aPCy@lƒ ‡@èH`´º‡iì%h„éº.G0Õ…Á´&0Ô,³ä j(ˆm°á½¢ç£ÕEÃ| ûC¨ñJÑ%]í…^ÅÐ#È@ÔPÛ`Ã!zÅ+ÖÕOt!€þ–. zÙù†Þ…þ£ô«´±0huÑßì€BL`t³4PH. †ò€ØÐ+°Ÿa˜È°¢ Ëæ c!I˜KÀ¾¨* F0ÑЯv/°ÒëÚL´Ãèvè6ä j(ˆm°á½‚”À”,¡Ð_GDêi ´´©°#ú7šƒ‚äÑ^t ¯^B6b:lâvuú)òR”°v$#^ å± 6¡W`C‚AÈ 0 ‹ÐÐPä0°Ú«!¨&jm#Ðê Ál@Ò*Ý3¶ ›”i¡r¼„ö¢›en#È@ÔPÛ`Ã!zíä ä§Wr±!‡Ñ:ÁìBWFO‘~PûHQ“æ§2Ÿ2AåhºYæ6‚\„A å± 6¡Wt& Ð,¶èOÁ[ô" €ÝQ!ªŒÙ…®†ž¢–èX°ö¢·{"°® €0¨¡< ¶Á†C ôŠîFˆ ýÉ!x  BƒÊ™¯b*‚íÜÜÿÈ Àì ]˜{1–É@ÔPÛ`Ã!z­Ú=ha CÐPÍ®õ™åØq»Þ…Ù&l €@øÕ3*º2mæ\¬ð~@ýwø°ófX¡8qéðqÆÇZ+eNž<ùgç#V.€«>øàÂ÷??grçÎ(ÇjŠCS$cóÇTñ'4 §.5¨ZmÓ¸ÕºiVM4ùóRÄß–ˆ2Ð[Š}2¯+Y( ˆo¨aœÀ¨+´hþÄÖcðˆ Q¹Xðÿ>íPóQÜ©Nñ}A·Ð6 V.€¨žüòÂgÌÆâÅWŠ_†G؆¨Ë±yß©G?bDo¾‚ÕMî-÷úîKDèí7k; uÕµDd¡4 ¾éXª’â¿öWáLQw--&t¹xÒÊqà .±X~Ñ«.”®ÛX}‘…ؤ¶kɵ§ý‹öŠ‹À\[¦îü0qû5V@ûÙa‹Y5m7ª^óϸB¬²‚n÷Lcu-eˆÀ20ô™!€¼…¨¬¬¤ËE_`å­ øËabò°(H]\ì KÑ(̬¾¨~êŠ_ÑöýÏÏá)¶‹¨ºî¤öÝKN]-9xeÒ¡«±Ûθœ·ï²òØiXMä?·û¿ŒÕµD”!È€ŸÐ’ Ù F„€mú%ØÀ†-RPêBöú±Žâ/‡X}Ѥµ/A@k/ôˆÕY@TLcѬ¦¨rzÝϽÀ^îÉká©è ̱fytËÖ?;zãÞÝûŸÞðÉý{÷;ž^¾‰ÕAèÛ}Ç¿ÓX]KD"° R<Òöºqq í0ZlذE Ü^ ‡a5EúcCÚ^â"0ÚUô# VŽí%:€œ^÷s/¦Ì°½D Ø”m§ÁXˆ[õ‰7Ê|ïß¼þðÓǰÃ*‹L]uÜô/Et-Áv)ˆÀ20ÚaL{Á]ΰÈqéUË/†À:&ÚßK¤×^²” ‡a5EÛKt Öõç^4Ø.¢ 8,ñ:$°O?ûâv™Ï‡ÚßÿøëÇ_ÿ€Õ50]5¦éZ‚í"R d:ÆpbHee%ˆ Ù‹~„(‡0,št#0¬¦‚\Ðk/$0X–a5El¥Õi«Ž`åØ^¢-0¿âýâõs/ Xð„ª¯¾ùþ_O~úáçßm©¿žÌ{ö¿Õ›öc•E ¦®«º–ˆ2D`šÎ¯ ¢wÁp`/ ãë•bð5z´ÌÂö×ò Àê‹`)´ÃÖ^bñù! (Švó‚Õ5@T +÷äµà-„¸üÜ –ض;µ®åéÿy‹æ›§/›Ú°ú¢}»§]ÕµD”!ÐtÚ -° ÅÂaÀ†yu!h]!u¡Gñ²æ-f V_¤Qݹsý¸‹F,~îÕ•qkpñJβ- ­“¿ªÞr°bñê›¶ LÁjŠèvÏtU×Q†l@“ù_¿û…¾µ`: ¶¨\E9ì/èrQŒÅ\{Á¶xÙ  ]…Òu«/j€«º‚Õ ´ ®Ü¾wúì…½û>zâÆÍ;‹œä̪‰p»Ç\ÕµD”!Ðt 骲²žL‡¡BlØ¢ SZ¢¯.²ò ?÷Â@–‚G´‚•Þ°Ò*\»Âê]ÀÑÓ‡¤”w ÚË/ ««ÄÈ^ô–æu%" eñ =*@ììõÄêo!"{Á£8ª«+â²ê"¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|ƒ‡@ ƒJâl<@$Pß`ã! Ҁø@  ”Ä7Øx0H 4 ¾ÁÆC „A¥ñ 6@ ( ˆo°ña@i@|óg¥W÷`5°Þv«/j`½í V_Ô ¦É;b5 ’¾¥û[¤èß@Iÿj‘ Pþö0O–Bõ’„¤oÁn‘Ý?AÞ³þcˆ~ÿ©iD2@A§à#CÃW‚*ˆ2ƒ !ékÐ-»‚Êé©&š`=ìþ©Ò}E¿ÿÔ4"  S®ú-5ƒŒäýºEÒ7JìŽ)ú7PfÏ™`¯Š,Ì®b0_Y¨iD2@A§€^ra  ¢Lç HHúìÙýS„¾Ñw…~U”aöóu¢ 5H(èÀLyePQ¦s$$} v£Ä6DÿŠõ°û§"ý>w…~U”¡¦É˜)t˜OQQ¦c $$}}£dÞ1±§¢ ÖÃ ÐÃîÁê‹Ô4"  SóROˆÀHÞûзHæM“Yˆ6Df±Î£z[4龇¢ßj‘ PÐ)€™B‡ùUe:Æ@BÒçˆû ”ô`¡¦É˜)t˜OQQ¦c $$}Ü"»›p¢ÖÛ®`õE ¬·]Áê‹Ô4"  SÐi+*¨œÞfž,õ–„¤ÁæÐ+¨iD2@¡Ï2V×ÐuD“ÎAô5Ø|"z5H(=9 ôÉA¨.’ô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô-Ø|"z5H(Øé;¨aô!C†üïõ‡+8í9IEND®B`‚simutrans-124.3/themes.src/pak64german/files/ls-symbols_stops.png000066400000000000000000000034601474050137200251140ustar00rootroot00000000000000‰PNG  IHDR€@ØQégAMA± üaçIDATx^íÜ1Žì4ð‡8ûÒ^aáO+8¢£F¢ƒ’‚–Іž‚† À!àˆS,†O²¢d7“Lû›y¿§h5»›ØÎ/ŽÿŽgç}ð÷óóÿ @€Î%€m @€@g7ëS ðßò3 @ ¿€¶O€àèýçYj$@€lX @€xz¶Y˜ö @€@,€  @€À<½ÿÇvRíŠ%@ ¹€6üh/¹übGô~óÓï}úUò1âF›÷æÿ7ÚxÍ~OtÐöƒï{ÒuœæŠ@ ÝϾþ±l/pDo¤¯>£#EúÊà3l•ÙP@ï àÌ7öÇ_|·kkØ5˜=O‚kú à“ºÍ4weðIÈŠm"Ð2€cR_¶2ñoÒ¸þ…”ƯܱÓxËöì²+zëÎý…ï¸ÆŸÿø§¾­»ò¢Þ&_~ÿK¶^tWg¶òl!ú>.ë]žE³ŽÜ-cP¬¼Ý(VœE½cã¥~¹UÎ1N3Ïâa4©¶mûë½LÙš]â6.A ׋/bu:a_ly6üÒžs¦[¹gãÛO—¿½‰1ê/D¾±¥I¯õ‹?ßRøú>Í8Ò÷v¸®FÇÈX¶Ù·øxŸÛUÂòØuøÙ;¿{÷n6PF ¯­ï —=Ïná®òK{ÊsyiüÊ×lm¾8J®ì° §ÛÎÑV.AùU¶«0ÃY®:”Ÿ”f'\8ÒŽ?jžÀϪ[Ÿ^¯¨¦oÉ×ÒòºBgQ¿-H÷¼duV7Ûïô OáíÛ·;|ìV&vñÇY©†ÑHß‹œmô¯så+^4ì ­ŠŠô½›ž-–ñ³T«r®è6ÓC6£Mûù‡5¨b|™>AÖGÉ勃­ouxp¤ïö-Ïôuo§º–ŸÕ™¥o]\IÀÑŸžž^¼ëÇêjótÍyå#­:ö®rjG ¯l©æ 5«f/b&?œ¾žÆÛ.Ÿ;ßè%˜ÊÄXTr·|GÞÙèÔqW³¹Î²;½Öyâç»êZî|z¯Ì/òŒ¤Ó5ç]¢ƒú­¿õžþmù®×­›—3û+èT‰õÚÉÖu ‹·@ªÓ¹›Žô½ˆ;¤ºµGÅ@´2uK5éfß×x[¾h>ð]W`éÍÛ3,n€ØÿºêškãÑïã½–×¶Ùo›·äº«çö«ÊyÖÓÏç+—m¾ÑǯÙîÅÇ÷écñuÝõŒ£¶ãÇ æìTËçÝå}†Þ‘2§o»,;O]A™ýªþüHÕåØ6OÀ»žZ~”¶ôæ§PúSήé'òâ0Tϱþö`ïixxøïÊà† h[Ôô 8çX9=ßÚ16¾ÿR÷o‹v]i_Üíº›žñc·8¤yKŸyñ_Ú>é?Çß…l| /Þ™w8Ø®>¼6låz,;ÖÕÕwàúm™ð¦Ql¿Î3lUòúÿݪ–ãålœ}¦íÿ×µÿ¸[«®kÎ{9ÎevOO°ZÃrv5o×ÎÙ8€/Ög @ à}ÿ¥NC€š`L€àèM¦N !@€›À˜ ÀÐozʦñ ÐD@ ` 0@@@o2uRÜ´À¿Û_GlOéþ¼IEND®B`‚simutrans-124.3/themes.src/pak64german/files/ls-symbols_stops_new.png000066400000000000000000000031751474050137200257700ustar00rootroot00000000000000‰PNG  IHDR€@ØQégAMA± üa pHYsÃÃÇo¨dIDATx^íÚ;Ž%E…á‘XC勺аV €…ð°‘ðÀÄÀÅÂÁÇÀa°fˆU41÷ä Rç¾êÕÕÍŸú4ÊÊªŠŠ›••Áïþ~~ƒQ€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€(@ €` P€ñãoïÅÆÍïýÇNa±wÇfãÀ®°@-eÑͬóTw¿ýùðñg_ÛY,Ójï±ÙY`?XÀ–Tq?ÿæ§p¥[é»Ë´Â{lvØVçlí³>6;‹ÿ9 p-û*íØ•µKS;ˆhÓ± ^‹È_ßj4;ÕûäËï{{Ø:-¥, ÖÈŠ›Õ7GR–^ÙÃ*z3N¿ßë_4PhÕÒŒ½CE÷—?ÿQçU`域knŽýœE+~²~uíÖ™ù¬da1V‚þF;‘––|õïZB…«Hú¬®³ é›5ñÁfÿÓ‡‡ìŸewÂ&ü:»ÓÙbXÀÎEnò·Ä׫ЫÅÛ¢C_±öP€•CÈ|.ö#v¨‹Œ)¢”æjµÌë'þr¬%TµŠÄ»Én/¡öT|°Ù¿Y€ƒ…-gS}“ÝŽ)l ¬dÁ§[U€ãÁ¹­O¥„V°¶?å_onˆ´‘¾€ÅY ZØ1ròO ªö#v¨‹¼z)§ì²o¦+™ø»¸~‹:ñgvìP×[ÁúŰž/{:ùÙéÃ^„‰Ý2š †TÎgÏfoöˆ‰¶/À XØabíæÞEHɨ>åa?b©“¿ºpëÌÉÏ|.ö#v¨‹¼1½}ž!_J°‹‡y||ÔÆg"=ý™+ãú úÏú̞2Œž®ÍQIª“#§‡R˜sÈ/w¼JLiÌðéäg§? zw¤Ö¡þ¶²Ò×Zm;’ƒUìíoÂ1ÑòüÝÅ’s}K(ä ¶›K}‹Åùgÿìa?b‡±È#Ùÿ ”bnû$¥Ÿy»~˜»»»‡C»¿¿ïó™EËfox–œC,†ÈA«Bù¨?ë0;¼„›¥våm,*ÀщôÔ9e7Ž×¿}Íd?býKƒϳöˆ‰(ÀÒPþË(‚E#'=‹<Ò«+ÀéééIoÿ,×dg3HœÊ~ mâÚPf©Ýúc1DZÊGýY‡Ù±àã-~µo¡§„<ËËà›jwÒX–ÏbyŒœüõ,ò‡Ou›f‘ÇxKØÒ›¢vëï÷¾Ü çfÇ‚3™ØôN¡wgÑÆËmDs{]ÕnÓëß¾²êG¬iPý±GLôâ86Ç›}‹(þ~T¼ÉD³Ûýú|)O«•Šçâµó÷õRnm¬T<—aþÇÿñšôü¿ýf£,?†Ÿv릫6µf~(ô•iÞ¹Å*wlþ³íEóÇCLv%ØÏ¿kô›^*íg‹ˆq<7„Àdç?¬üËÿÔdçÿË÷ë‡Ë{·ê²\¿ïÖVÄ›q(œûè\9óþ™16Ì›XáŽM?>ø“ÆS^÷ó~Ì9—ÇñÚ”çÂêÿ0Ó.ààkí“ýWKT×ð›húßmÕåö‡óÇø;vo}œ½q¶T[•È$Îw¾¹Û}ùOÇÿLzþê?Vü'§<ÿ²=ë>çRž[ÝÿLuþ{÷¯µåŸ£hcÅïÓºüºSFDÜÙ™ü. €›»åËË “1–þñȧÕäàa[ž[Ó€f €_ÍþÏ_ÌwÙ šÿç7jÉx (Îùo¾½hþ1¯d8´|¨Z:ý“ðPª Á]ÌÆøóf}Q÷n̯|òÞä/÷P._*¥^™¿<|øé.G£ï¿CÓlj/f¸ÜÀf@ÔÁ_uÙ¿óf¿ˆŠ@¸½[7Ýç?õfØ@{ᕾ*‹ŸúhÖŸŽ;€±Æ ÂQeÿZÛU†û!V~š ôXæF07‚e¼lï~Ýüöã¥õà‡7N­ ÇÀ“Ÿô7‚iþÀ ¤TU“tÞ³®Ú®ÊP1ž9"r¨/ÖÍ•+W>öNV4ÿ¡ù¥ ¾ÙoÏJ¹Û–‡mé+Æñ\÷š#còš.J5?î…9õÍ?šßúzI4çÙÐèçMÿi)GïÅü5;©tõN5†dû «ÿ!²ìúÕ4þ¨“B`þ¼]Àă٬.W¯ž$ýŒç¾bp4çE³_ x-É{‘ùð/õZiο,Hxô/Îý¯@†]ÀJœ ÅW`ã­²öÚš áÑ¿øåË3•`îí)§}ÊÒ©!§€¦­™ .“ÌÊêÿÙÀäwG—wË!à"p Êõ­ëš?¹1ív;Â’’N±;ã®{nÆÇÇ­!·àÞ|ã õ„ õ„ÙÚÚrÛ.«ãsc7InûÀ%y:6Åzòtl*•ÊêêªÛ‰×õ¤å¿¨gssÓ.Änc$²4>œ»»;»P¸‘HB:6¡žpöózì—££#·'*–Λõ„tÖ××÷ööÜ–¨d¼3v7ó y Èε«ÇîxjµZ«Õr«#”§êyzÛIëÙØØ(Åçù¬”Wcw<¥ø<Ÿ„tlB:ÓÓÓ–”[3÷Æcc7ËnM̲^žÇ®V¥øôžKB:6vƒÜh4Ü¿ãW¬§\éY8÷÷N§\_ÉÂÂÂÊÊÊåå¥ûGYX:ÕjµŒéÝn×N~Ìß´},qÿ…€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚„€ ! H‚~ÿ&û@IöIEND®B`‚simutrans-124.3/themes.src/pak64german/files/roundbutton.png000066400000000000000000000022311474050137200241360ustar00rootroot00000000000000‰PNG  IHDR@Àc×K pHYsÃÃÇo¨dKIDATxÚíÚ1kAÇáýfbe¬-EìR%† …¥­]A !"$ˆ(„TÉA@,EðŽƒèLj›L2L}dÿÜOqåÜ{³ïïŠíþ^]/Þÿ¨Ÿƒ„»=¶Ýi9ÿ³õ·“çoNŸ½>‰<3ÿH;gUâüëåI½?Íüuåkl¼ûÞKüúc÷w(7`eò¹LÀ†( (ç]¯vø¡®¶±wQD`ï¢, Ô€Ý ?”€ ØÀ€• „>ÂÑõª“ÏÕÅ/ Ý©4ªe$`îÏw&tþÑõªÎÕEOŸQ-P°UøÓÃx&`†€!`&`†€!`&` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` `˜) `ðŸöøÕIâ=v{þl[GUäü7­~øtÿÁ“‘çoæió°Jœ½<©÷§™¢Û€­½üÚKüúc÷w(7`eò¹LÀ†( (ç]¯vø¡®¶¶}\D`û¸, Ô€Ý ?”€ ØÀ€• „>ÂÑõª“ÏÕÅ/ ­# hTËHÀÜŸ%îLèü£ëUœËKÜÛ0[…?=x 00 0CÀ@ÀLÀ000   @À@À@À@À000   @À@À@À000    @À@À@À@À000   @À@À@À000V6`Ó?‰_ ôØíù³MæUäü'³O§¿?~ûµÿågæùçáfUâüë剽?³h·;8¿ìEþç—ý ØÍäƒ ˜€ PP$Î?º^íðCu7;tQd`QPlÀÙLÀ†¬d ôŽ®W|®.Í- Q-#s–¸3¡ó®W p./qpo TÀlþôà-DLÀLÀ0LÀ 0CÀ@À@À000   @À@À@À000    @À@À@À0000   @À@À@À000    @À@À@ÀX1ÿOÅÝ?HÆÒçIEND®B`‚simutrans-124.3/themes.src/pak64german/files/scrollbar.png000066400000000000000000000103751474050137200235460ustar00rootroot00000000000000‰PNG  IHDRÀ«¯1gAMA± üa pHYsÃÃÇo¨dŸIDATx^íÜO‹ÕW¶Æñ¼‹¼€;ÏÄIfÅ8ÐQA"Õ$C!hblŒh4B4¢’ü "Š $ó;†@f„ôðó¼«ÎZìþÝU§Nª7d¯ýôý>|(šó~ëÔÞÏÙ¿T:oüÏë×ûôË/¿üöÛoéA!o¾ùæoüóÎææÍ›ß}÷]z°œ- [éA!¶$la¤…Ø’°…‘bŸ¿vÒ<»ýôÓOÿ½ŠíÅ­òÖ[oý×*¶O·Êýû÷···=zôÃ?LX ¾*|…ØRIÏÎÏW…¯[*éÙùÙ’°…aËÉ-•ôìü¢†t“æinß¾}ïÞ½g«ØÆð*Ðwß}÷Ð*o¿ývëPKzÙ´ÚçoÛ£eÎõê´øj±Ë¶‹O/›V,‹U{ÚRñ5c‹'½lZ^ -rŸÔnÒ<_åË/¿´ßÇ·±ïÛ*éõ³9uêÔÖÖÖ{«,;´Õhzýlî/Λ»3a.ÛÓ·®Ç–¯¥ôúÙ´ê´øj±eãëÇ’-§ôúÙ¤mQ9“F éÆÇX®‹wh«QïP¯Ñ6ùTÚŽõë_v¨×¨ïiïÑl¡oèÍ– Ô«ÓÒÚÓWÎîßEzã$–íé«Å¯6í›+½q{hËäM5¤›Õ—nþÖõuÓ–ŽÅ¶‡×hš¿\Û·ß·»þ¶o-6iû$½½œÿi(ûŸeÂõêl¿…å¯`ù[h¿‚ôör^–¶,¾ |¶,6fz{¹kñLøç¦¨!ݨ/ õ ¬^ í“·(~ù…µÅï+ß⃴ÅïklÂZÃkÔ–ÑÚ•´ìÐ6ùTös éÓ¥7Nâ¾ì-¼æ– Ÿ¹-­ «ÓùúÕ¦5oñÑæ¬N÷§Ê-ü_›4Ï^߯m=¥×ÏÆW¼Å®Ö.Ûb×oƒX|¨ôúÙlnÒ9 Ô׆ÔþiûGm É–SzýlüR}…ØÅûš±q|YÒëg³WNÞ›MÔnÒˆ·gzÙ´Rªôf5¤›4Ïni…¥gçç»Â¯ßIÏÎoÙ¤èò³êÍ&µgzv~^ r½ÙD é&ͳ/µô ßêéA!þç¦ô`9ûH¿–¯Îô [þihÿ¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†t“æ€a¢†tóz‘4›„›%=%A=[‹¤Ñ$è^¹óë×Í«W¯léþÜ)Ðßÿù»K¿ vÙ?ÿãg#Z íÃe{`õE¼“4šÝ+w~ýºYÛJB?£@½ƒÒïF‚_¹n¶ëåº:LHžã¶WI ñë×͆n’øùR þíC ´D+PÛ i4 vÙÏŸ?O YµpÖ¶’ÐÏÿ„ýæÎ7h ´Öª…„³¡›$~R Åü“×EÖZµpÖ¶’ÐO ´˜òº(ÐZ«Άn’øIóO^ZkÕBÂYÛJB?)ÐbþÉë¢@k­ZH8ºIâ'ZÌ?y]h­U gm+ ý¤@‹ù'¯Ë Ô7CM‚]6Z˜ Ý$ñs§@ÛfH¿ Öžh! ´–òºYÛJB?£@½ƒÒïF‚]¶-Ðvý¢ZŠÖ]¶túõëfC7Iü´Åÿ¯¤ß„¸ôUÒSâÒeóë"i4 ºWîüúu³¡›$~J–Ì€€N(t¢@  (PèD@' :Q Ð‰€N(t¢@  (PèD@' :Q Ð‰€N(t¢@  (PèD@' :Q Ð‰€N(t¢@  (PèD@' :Q Ð‰€N(t¢@  (PèD@' :Q Ð‰€N(t¢@  (PèD@' :Q Ð‰€Nk ôÊ•+×®]K ùøãoÞ¼™TaW®uñ/_¾ü~•Çß»wïÎ;_ýõ—«|þùçŸ~úé™3gÒ[¦ràÀƒ¾³Ê¡C‡>|ìØ±÷Þ{ïƒU>úè£S§N¥·Lå»}$½e*o¨'Íclé_¼x1=(äøñãÖ¡éAó¯øäÅ‹ÚÓÚçüùóé-S9räHjÏV ÞžgÏžMo™Š}Ýþ°1“G é&ÍsõêUßéq.\°ÕòäÉô¸„û÷ïû¢·ÿ‘žš–@½=÷*Ї¦·LåôéÓ­=—ÇOoOËöövzËl=zäËfwì©ôâÙD é&Ísùòe_ý7nÜHOI8qâÄêÞ냻w獵æg{Õ×ýü›viÃñSâV`yüL7ï6Ezñ„Ú²ÙùRÔn–Ã\¿~½­þO>ùdù”„[·nµÕoGéôìüÚQbþƒÃ’]íÚö´ß‚Ä7ÁÑ£G÷jO'½xBíÆewæ¿•‰ÒÍr˜K—.µÕoY>%ÁÖ}[ýçÎKÏN.m¡»ø'OžX¦ö´lmm¥WÎÉŽÉ;ÿàóرԞ–ôÊi­½‹öìYzÙ„¢†tÓ&ùöÛomøº±dËèöíÛíÙù=xðÀ7Àjóîl€§OŸ¦×Ì,݈ ÝÅÿøã~üôölëÇI¯œ“­üvüôöôõ#ô§Ôµwñ÷îÝK/›PÔnÚ$_|ñÅòæË“Ö]ügŸ}Ö6€Ma³hý9;"´îâ¿úê«åñÓ~ ZÇ{ÿý÷w¾{ÿïúI¯™ÙÚ»x‰PÔnÚ$©=-¶ªÚ³ó³»\ý¶ŸmW§×LËÖz¬úE„îâí»*­û>K¯™™ìš—ëÇÎé5“ýŽÒaw+¾úÛ°;»¯±»›6ê̬.Ûê÷ `Ø}¥Ý]¦WÎÉî¶bá/"tÿôéÓ¶~v¾{?øàÁƒé53³/°åú±Å£²òÑ5¤Ã×- oOË꟪Sù7Ò·¶¶V›÷_ÇOË;wž|øèÑ£Ëiçd_¶íøÐÚÓŽŸV ´ö`y„îâ¯^½ÚÖÏ­[·Ò³ó³»ø¶~®_¿žž•Ðîâ…¾z£†tc3ìÕž‡zçw–ÓÎÉŽÉkÛÓî‹?~œ^<¡µBõÝÅß½{××ω'ÒSnܸáëçòåËé)m! -›¨!ÝØgmíÓ ´µg+ÐÓ§O§™§òðáýÚÓ ôåË—é-³i‡ÝѺ‹?yò¤­Ÿ .¤ÇUøúQü¿`¸v+#tã5¤›³gϦö\?-GŽI3Oåüùó{¨µç÷ßÿâÅ‹ô–©¨ÿÇ –ìVàøñãéA!/^´õ“Ô²úoÑ(ýÛ{QCºií¹<~¶ö ls-symbols.0.7 -------------------- Obj=symbol name=ColorOptions Image[0]=> ls-symbols.0.8 -------------------- Obj=symbol name=Flags Image[0]=> ls-symbols.0.2 -------------------- Obj=symbol name=Message Image[0]=> ls-symbols.0.0 -------------------- Obj=symbol name=NewYear Image[0]=> ls-symbols.0.4 -------------------- Obj=symbol name=BusStop #Image[0]=> ls-symbols.1.2 Image[0]=> ls-symbols_stops_new.0.2 -------------------- Obj=symbol name=TrainStop #Image[0]=> ls-symbols.1.1 Image[0]=> ls-symbols_stops_new.0.1 -------------------- Obj=symbol name=CarStop #Image[0]=> ls-symbols.1.0 Image[0]=> ls-symbols_stops_new.0.0 -------------------- Obj=symbol name=ShipStop #Image[0]=> ls-symbols.1.3 Image[0]=> ls-symbols_stops_new.0.3 -------------------- Obj=symbol name=AirStop #Image[0]=> ls-symbols.1.4 Image[0]=> ls-symbols_stops_new.0.4 -------------------- Obj=symbol name=MonorailStop #Image[0]=> ls-symbols.1.5 Image[0]=> ls-symbols_stops_new.0.5 -------------------- Obj=symbol name=TramStop #Image[0]=> ls-symbols.1.6 Image[0]=> ls-symbols_stops_new.0.6 -------------------- Obj=symbol name=MaglevStop #Image[0]=> ls-symbols.1.7 Image[0]=> ls-symbols_stops_new.0.7 -------------------- Obj=symbol name=NarrowgaugeStop #Image[0]=> ls-symbols.1.8 Image[0]=> ls-symbols_stops_new.0.9 -------------------- Obj=symbol name=Passagiere Image[0]=> stations_status.1.0 -------------------- Obj=symbol name=Post Image[0]=> stations_status.1.1 -------------------- Obj=symbol name=Waren Image[0]=> stations_status.1.2 -------------------- Obj=symbol name=Happy #copyright= Image[0]=> stations_status.0.0 -------------------- Obj=symbol name=Unhappy #copyright= Image[0]=> stations_status.0.1 -------------------- Obj=symbol name=NoRoute #copyright= Image[0]=> stations_status.0.2 -------------------- Obj=symbol name=MessageOptions Image[0]=> ls-symbols.2.3 -------------------- Obj=symbol name=Electricity Image[0]=> stations_status.2.0 -------------------- Obj=symbol name=InTown Image[0]=> stations_status.2.1 -------------------- Obj=symbol name=Seasons Image[3]=> ls-symbols.3.0 Image[0]=> ls-symbols.3.1 Image[1]=> ls-symbols.3.2 Image[2]=> ls-symbols.3.3 -------------------- Obj=symbol name=networksym Image[0]=> ls-symbols.3.4 -------------------- Obj=symbol name=timelinesym Image[0]=> ls-symbols.3.5 -------------------- Obj=symbol name=fastforwardsym Image[0]=> ls-symbols.3.6 -------------------- Obj=symbol name=pausesym Image[0]=> ls-symbols.3.7 -------------------- Obj=symbol name=CompassIso copyright=FrankP Image[0]=> compass-iso.0.0 Image[1]=> compass-iso.0.1 Image[2]=> compass-iso.0.2 Image[3]=> compass-iso.0.3 -------------------- Obj=symbol name=CompassMap copyright=prissi Image[0]=> compass-map.0.0 Image[1]=> compass-map.0.1 Image[2]=> compass-map.0.2 Image[3]=> compass-map.0.3 Image[4]=> - #compass-map.0.4 Image[5]=> - #compass-map.0.5 Image[6]=> - #compass-map.0.6 Image[7]=> - #compass-map.0.7 -------------------- Obj=symbol name=station_type # used in line display only currently # the number is the stationtype (emtpy images must be defined as "-" # loadingbay=0, railstation = 1, dock = 2, busstop = 3, airstop = 4, monorailstop = 5, tramstop = 6, maglevstop=7, narrowgaugestop=8 # maximum size please 11x11 Image[0]=- Image[1]=- Image[2]=> ls-symbols.4.0 Image[3]=- Image[4]=> ls-symbols.4.1 Image[5]=- Image[6]=- Image[7]=> ls-symbols.4.2 Image[8]=- -------------------- Obj=symbol name=MessageOptions #Image[0]=> ls-symbols.2.3 Image[0]=> singlesMessageSymbols.0.0 Image[1]=> singlesMessageSymbols.0.1 Image[2]=> singlesMessageSymbols.0.2 -------------------- simutrans-124.3/themes.src/pak64german/files/singlesMessageSymbols.png000066400000000000000000000012011474050137200260710ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa pHYsÃÃÇo¨d#IDATx^íÖAJÃ@†áÃmÁË.¡è®¼x^À·è%zÿf’8ù¤i?ÚÌÀ;<È$ša_Ò.~ª ¸A’èqs÷¸YöÙ }ß­0¯E¸ß!ÞöÐ<#5¹¬¢ùÈ}·Â¼ì”«vévþ’¡€zo—ö²“¸ïV˜×1 ÐÍŠ È„ÍÇ?s“ÞÓÄ·N|ß­0;;îÒë)Bú|ÛDb¹$ï»rêyûþš"~pvuùÇas·Ï!ñã·4P“K‰ßŒ~ø³ÃµI|ÖIîñ|ØÞrÞ: ÷×Õöyùp¿ˆ‰Åé4Ü ó õ„:É­ƒ‚ß@/OËÏmP/—R¾5µ/¡ã|tÌøê1¶·f—Ã#»€.n…yÙéÇ£ÙâðÈ- Ûs7/5 ý~8v»Ýz½¶K›Øeõï+›„›ö—véVÈGæÿ€“J èÜáVÈ]U: úEsÞp+䃀®j0 ûä²âþKÍu=º?s+äÃw ÷T>Ü>‡¸§n&0AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$AUý:Ú#èqIEND®B`‚simutrans-124.3/themes.src/pak64german/files/skins_neu.png000066400000000000000000000262771474050137200235710ustar00rootroot00000000000000‰PNG  IHDRÀÀºG/$gAMA± üa pHYsÃÃÇo¨d,aIDATx^íOs\Çy¯ñ)¤eªô´º+ïµðâ.²ðæZå­t7YDª$•J$Y% "ñ &h@E‚"B0‚bZòeY 9Ydq]u?„î¯û=zÝzg0dz<ÓÓ¨§ë©®÷œÓ§Ñ}æÌƒ·gƒ¥›—ó_ü{×ýgwÿK,öÚÙ¾óÀê2‹ŽZoâÿùÿ?ù¯²> 5.¯G7-þ¿ß}×5›«ÿºµ~ùðó[÷nýzwkýÓk÷nÞØÙ¸úé_>>~°qõB:tssíâ»ÚóéÖGjÿÖ–Zn^½¨úàîMÕYGûŸ­]:¿»ý+Õj ÕáÉ£ß̺ÿ0˜3´1.#ìçõ(fÆ2vc:Þ[@êt{Vk4î§îØ\]9¸ó‰Ä´»s]ÈJ;×W%²ã{W–÷nëlåv“þÔlãÊ»Û÷oœNTpggkíC‰R-“Ý®,«þúäH{fݘ̙¥•ÎKðQwÈA’ ÉȯË`‰ÒjÃbëg‚òÔì4uê¨×£×a3ÜOÝ!£)¿Ëià YÉr・×.žKvÛ¹¾¶òž<¥f²[2àÍÉn;×ïßÞV5·½µvI$ý©ÙÕ‹j£ìRg)[œuÿa:0gÈ@cJr$¸².ƒ’ÒžØéî¸ÓPc ž%µºÜ,#ÜOÝ!£îí ¹I©<¥Uóåå·¥ºggåÜ?Ëk÷oo«–æ´²–Îä¾,¸U5P3-´S°½!d7mÞ»¹iï¡ëK'uVŽoû'fÚ˜ÌÚ·’ã:³Ú0u–èèhmŒîqBçV¢ý:Ýûñ®Fû ÷SwÈA’šVÖ²R .—ÔRn˜=%”÷¥D2©ð—j œQ‡”-*CüÞnkªµš6ß)[”é”xª™’ÇY÷¦s6Æ•dÚòÀ]&LaÖÒëÑ=^? þSÊÚ™ðöTøá~ê©jãÒûZ+X[yO†:yô›ä)å‰W/ÊY²•¼6$‰rÖ­_K[9[\Ëú[½vᓇ_¨¥ŽÊtÊÓb<>åž3î?Læ ¯6¦”‘0m¹Èd«ÓP3¯ËM£ŒK¼ÿ²‹94¼h`”{ÂýÔ™ì&m\ù@æ’Ý´|Þ¸²,ëIRZhËVÉnù3íÉ\Ûrœì–>]tcM©åããô3g‹ß¯Ä×”0¦öyÁ>ÓþÃt`Î6Æ­$$,¯¥§ÉŸx÷ÀëÓ6GñT£˜C-=;á~êÙMþJŸx¿yãøð¾T%gIUÒ“6%,{ëFþ²÷vìm)L)¡ÎJ¹¡­µ¯|`‰¡<<æ´™^âœqÿa:0ghcÜDò”’Ôi”G-[OÀŠ^\Û¦j;·ü)á~êyJKiêpïöÎÆU[nKOGûŸiœí¶-÷)VK-Ÿí¨¤–ìv¸/9J…¹‡ŠÅ×'Ô›²Hõ&Áͺÿ0˜3´1n"!1‰É#dxc ¼Ý‹lXÖeà¸4­.±NŒp?u‡ +½å½õ‘ÃÍÕ•ü–NzrkãŠì¦Dïðó[2j­Ç“¹ò_É€:W.Ó)j£ÄPû¿ùýc¨ÓÕ›ŽÊ‰³î?Læ ¯6Æ4$ßÉ›¦Î²Å{0¶žŒ„8ZdÉ2pu–±õî§î0»¥,ou%-“ooíßÉŸÚP Ékö¾yú ­²o¬)<:¸kY¡ÙMj“Ëž|ub/Vª7¢N¤ÅY÷¦s† ´1æM×åiÞ È\eàµáq¹ÓË@u”¸.Ëz”p?u‡–’Áµ¥$™Î^””§dºï³Â•ãŸkAm«lm*P†(¯é5ÓNñÍï›´˜¿oI½é\%‰Éw3î?Læ mŒéL¦{ªF­™c7½žŒlhu”ÈŒ^[0Šuî§î’$&­¥*³[Zbç? Ôž­õ˲۵‹ç”!jÌ% *UTn¨C&AåŒO~{¬CJ í%ŒŠÕ³1ÓþÃt`Î ÐÆ˜†Ìb¥COC-Ë Üô=eÐO)ó£ŽüX.MÃz0ÂýÔ’‘ܤµs^)'»mm\JîT?Ø[[yO;s³Kj“>Ë©0Û-å†[=ùÝ—é3I)©Lo §ônvûúä‘òG%‰²›ög»¥¯¡Ë‚KØ>ëþÃt`Î6Æ”­¤§Q“êPˆÇÖNØê¹ Bí¸1}S Æþˆp?uGÎæ’‰´ˆNïØÜþxóêE·Û½üñ#éLm®]xg°[v™&»­¼û†âƒô¤U¥‡R^bþ"%¢gݘÌÚ˜RFB¶*kÙj,:Z^e<ï¿ nO5ý†ö„û©;¤6ÉèèànzßFkäüÕœ'‡û¶j>üü––Õ ”ÚÜrCÉëñ—ÿöþ¯ùÍŸ”iÊnj?Ømk]¾Sª8ëþÃt`Î ÐÆ”>2[…MÕò”£=£Å^;aSøðÎ26$вÏп‹ÃýÔ’‘½ ®õµÈ’TþDѲXz·'}f(Û-e…×”!&»m­?>~ðÖ?üíÑÁ=µÑ)J*“ÝövÕxkíCÅêÊ׿3í?Læ ¯6Æ•T"Y]æ,7ר@uœ†w[Ö%ÚcÝ–=—µî§îÝÒ§ÖîÊ_ò‘‚µ‹ï*¹SÞg‹åÁnù{9• Jp'~ñO—ívS§˜Ý´©ÆêJµÚ¤Drë#³î?Læ hcJ™¹¬¶Àuæ±IÍ-¤æAˆëÍïÖÑY†ŽŽÖF‡û©;¤§Ã½Û2‘ĤÜðòòÛJúŽï'ymÿêòòÏÓÊ:ý'¸µaõýðàýŸÿãñƒ½Ü M"S{Õk+ïe»­¥³Ý¤ËY÷¦s6ÆMËʺÄ׆ޖuL@”µ1¶Ã±;KÂýÔéUÅ­u!¯]»ðŽ–ÉZGÜùD‹kûþ²•òGiîäpåÜ¿Hg–JŽÜããCÅ×.ž“ÝäDõ ÇÙëž[k—fݘÌÚ˜RF¥×,0ÊØ°wxFÕvšæUƆÚtt´»3ÜOÝ¡¼ow'ý Ì+ËJú”$Znh¯ZJétûÔу=å'¿°W*Ó÷Ô­_V2¨sWο©6Zƒíßq»É‰òà¬ûÓ9Ãk 11b¦ózshx«'0v§Î²Z¨A@‡BjÃãp?u‡ô$[åϺoËh÷ó'ÞµX–Ú”'¦ðʲœ•ÞZyOëkÙMæ’ÚTë\¥—Ï¿%!êÄ£ƒ{ê*ÙMš³/¦Ë˜Ÿiÿa:0gÈ@SZI˜Ý<6ÊØp{Z4ªZû­“€íW­6£èÐØ ÔŽ6ÃýÔ2Q²ÒÆUéL†Ò¢Xkjå}ʵ˽þøø%µ¥—,“ÈTÛÇ„2GÛ#»iÁ®=2`ê|Æý‡éÀœA q•ÊsÍY]NéPìtLç¨}>òß;©ex]F¸ŸºCR'gîËVÙn»Z,o\z_vÓÂY‹nå‰Ê ÓB{풲ūä2qíÂ;Ò¢òļ N{ò¹éÛ’§Ü3 t¦ý‡éÀœA )e$\‚¨.ƒQ\£%ÖC@Ížýí=µã›á~êŽô5wv”J[r“T%‘Yn¨5²„%£=þò¡„¥œQ+qÉnsuE;%;%’Zqk ®X(‘”Ô´6ÏvKÿ¿H=̺ÿ0˜3¼ÚWR‰dW֣Ȓeàê,){+³ÎɨڗA¨rO¸Ÿºãþííã{Ò™œ%iu,1IaJý´LÖÎ'¿ûR)¤ì¦å³ì&—ÉbªåD Q'êIM¦3»¥7…Ò[Fé«?Õ~Öý‡éÀœ!mŒ[) ëY=ùÑj|³D;¥9¹òYÔéèçŽÖŽ·1ÂýÔZ;Ëh;ù›>”å)–°lá¬_ŸÉew?ÕNÙJ‡³ÝÒ¿ØL¯BjSvËKr¥„j–’Çüß8tÔì9ëþÃt`Î ÐÆ¸‰ )o´.ÃäXÆ.MG§8ÏîP5ö:lzmXî§î>-d)^þ—m²•Ì¥|ðññù.º¹¹vñ]푼Ғ<ÿs7ù+©ðîMÕYGûŸÉkÒœÙM'ªÃ“G¿™uÿa:0ghcÜG’ Ç¾éu@~,—¦¡SJÓ9ÚùÔôÓ±ö^—”{ÂýÔ¶š–˜vó÷ËJ;×W%²¼î^ÎÃL¯6ºÝR2˜_ÄTªx?ÿ/âÜÙQÚ(Qªe²Û•eÕ)»\¿<ëþÃt`Îðhc‚ždÃ26ʸÄtéÁu–<5ý,ãP´3ÜOÝ!£)¿Ëià YÉr・×.žKvÛ¹¾¶òž<¥f²[2àÍÉn;×µ|V5·­e¸:IúS³ü¿Œ”]ê,e‹³î?Læ hc‚’„„8Zbêô@ÍFM7j=k)thÖÀ›•›^á~êípo7½Îxë×Jíä)­š//¿-噳ì5Êd·üEÈ97ÌédþbãtVþšN5Óf¶ÛæñƒÏ•f*[T³Y÷¦s6ÆM$Ün«.ǤiYç¨ÔF7Kt¢jV¢^‡=ePn†û©;ŽîÉGÊ e( NYaZYç¯Ý”Ô丣ý;Y|éÛ@ÔFv“ÎvóGÙ“¯_“×´¾NvË ðtîÖzbþÍY÷¦s6¦T’cŽS]Sg鸲.)÷èÄÑZ F±ö”{|§î§îÐj:eyÙPRÒÚÅwS˜ ¥,O™£RHYÌs@iNÖKvË_l¬sÍq›«+ÚÔ‰Þ›ju>ëþÃt`ÎðhcÜD†IÍÕeàhK­¬2ž€weu轕q¨m†û©;².Imâòù·ä)²[ÒÓþg–²<)Lëè,µôÏ9îßþX¾w>‘þ’Ý®^T¡Cj©tºä¨µù¬ûÓ9CÚ˜ÒG†Iͳ›£=ÒÖ¨Ôʺ Jìt¼.щ†Öe`„û©;$,ùèþ•sÿ,¯Ý¿½­ZšKr¾ý+¹/ .ý—75ÓB;ékå6d7mÞ»¹iï¡ëK'uVŽÓ_»Û'fÚ˜ÌÚ˜RFŽDVÖAm¦°Óê2‹ukÅ^;ÚT'£—=[î§îƒ$5­¬e¥\:/©¥Ü0{J(ïK‰dRá/Õ@9£)[T†ø½ÝÒ_¯k5m¾S¶(Ó)ñT3%³î?Læ mL©$aòòØPGûCìõä@xçx=–Ñ·§Æöî§îª6.½¯±‚µüo2Oý&yJyâÕ‹r–l%¯ I¢œuë×ÒVÎײþÒW~œ<üB-uT¦Sæ˜ãù3ð)÷œqÿa:0gx ´1n¢·ØiŸÙT›2ðº NCÝz`±£ßí<ÜOÝ!‘Én2ÑÆ•d.ÙMËç+Ëé¿fn­k¡-[%»åÏ´'smoÈq²[útÑ5¥–ÓΜ-~¿_S˜ÚçûLûÓ9CÚ˜à#9ËêQujÿä`l]b—±×0“ªÙØnÃýÔ²›ü•>ñ~óÆñá}©JÎ’ª¤'û×öÖüeïíØÛ8R˜RB•rC[kçÿÏ!'ê}76ÓKœ3î?Læ mL)#!U=Ë_[ªexý,˜ -p¦§ŸV;vbùÃýÔò”–Ò2ÔáÞí«¶Ü–žŽòÿÞÈvÛ–û«¥–ÏvTRKv;Ü—¥ÂÜà Åâë“GêMY¤z“àfݘÌÚS’ªL“jæò`B]†~D”›ŽIÓ¯Kì,#ÜOÝaÂJoyo}¤Äpsu%¿¥“^…ÜÚ¸"»)Ñ;L_ÁyMµÖãÉ\ù¯€d@+—éµQb¨ýßüþ±NÔéêMGåÄY÷¦s†×@c’é‚=ÇjÔZŽ^?;Ò¢ÕF Y² ¼.±~ÂýÔf·”å­®¤eòíí£ýô­sZk+Îä5{ß<}…‡VÙ7Ö”åÿW,‘™Ý¤6¹ìÉW'öb¥zÓ)êDZœuÿa:0gÈ@#Q2`Y?Ékr=y°¬Ë E–ñi„û©;¤°” ®}(%Étö¢¤<%Ó}Ÿ®çÿYd«lm*P†(¯é5ÓNñÍï›´˜¿oI½é\%‰Éw3î?Læ mŒyÍ*&kT½›ªKF÷8rbY—!3zpÖU¸ŸºCJ’˜´v–ªÌni‰ÿ€R{¶Ö/Ën×.žS†¨=2—$¨TQ¹¡™•3>ùí±)1´S”0*VÏÆLûÓ9ƒ@c2•}*:er=ý”2¶M F‘%ËÚ)û÷SwHFr“ÖÎy¥œì¶µqE(¹S}ü`omå=íÌÍ.©Mú,§rÀl·”n}ôäw_¦Ï$¥¤2½žòDÙ-ÿ5Q²çŒûÓ9Ãk 1•õd‡ª×aSõ3~b8îM«ƒ:ý§‡û©;¤-¥{Bv;ÜÛÕ¦‰)Ùíð¾t&‘ín­KpòZú·šùMå’f·¯O)T’(»i¶[úº,¸ô‡í³î?Læ hcÌGŽleª$ì´Í§Ö£Ø[;æMT«ÁØnÃýÔ9›K&Ò":½csûãÍ«Ýn÷òǤ3µ¹váÁnÙeR˜ì¶òîŠÒ’V•JyIˆù‹”tŠ:œuÿa:0ghcÜDòT˜¿d«€•A¨Ÿò§ŒâÞ“V¸ŸºCj“ŒŽî¦÷m´FÎ_Íyr¸o«æÃÏoiY­@¹¡­Á-7”¼ùoï¿ñ÷Ú™ßüI™¦ì¦öƒÝ¶Öå;¥Š³î?Læ mLŸ´UÖ†Út´ ÆÖeàŒö6S§wèjT‡û©;$#{\ëk-%©ü‰¢d±ônOúÌP¶[Ê ¯)CLvÛZ|üà­øÛ£ƒ{j£S”T&»ííªñÖÚ‡ŠÕ•¯ÍgÚ˜Ì^mŒùHÈYe`ó@”ó Ôψ÷lõ(å(û/k#ÜOÝ!»¥O­Ü•¿ä#kßUr§¼Ï˃Ýò÷r*”àNüâŸþ.Ûí¦N1»iSÕ•jµI‰äÖG fݘÌ2ÐÆ¸‰ É«¬G)VÆ¡ž€:)¯ ÅÞÏh·V‡û©;¤§Ã½Û2‘ĤÜðòòÛJúŽï'ymÿêòòÏÓÊ:ý'¸µaõýðàýŸÿãñƒ½Ü M"S{Õk+ïe»­¥³Ý¤ËY÷¦s6F*EVn–A@ûÇzm4(±=ðÞ P›2µî§îH¯*n­ yíÚ…w´LÖ:úàÎ'Z\Û÷w(­”?Js'‡û+çþE:³Pr”à*¾vñœì&'ª9Î^÷ÜZ»4ëþÃt`Î ÐÆ¸‰ ‰¬¬ÇâïðŒ•Zi·ÓÐée­SÚ_¡.ƒp?u‡ò¾Ýô/07®,+éS’h¹¡½j)ý¥wÒíSGö”?ž<üÂ^©LßS·~YÉ Î]9ÿ¦Úh ~´Çí&'ʃ³î?Læ ¯6ÆMd:ó Ô†©³ŒƒF2.QûP«å(¾ß‚±µî§îžd«üY÷mí~þÄ»ËR›òÄ”^Y–³ÒA+ïi}-»É\R›j«´ñòù·$DxtpO]%»IsöÅtùó3í?Læ hcJ™Ô7}[’â”{fδÿ0˜3´1¦!Gr,“¦£HšV—X5{jÖ©f!µã›á~êŽô5wv”J[r“T%‘Yn¨5²„%£=þò¡„¥œQ+qÉnsuE;%;%’Zqk ®X(‘”Ô´6ÏvKÿ¿H=̺ÿ0˜3¼ÚWR‰dW֣Ȓeàê,){+SÎÉé§Ú—A¨rO¸Ÿºãþííã{Ò™œ%iu,1IaJý´LÖÎ'¿ûR)¤ì¦å³ì&—ÉbªåD Q'êIM¦3»¥7…Ò[Fé«?Õ~Öý‡éÀœ!mŒ[) ëY=ùÑj|³D;¥9¹òYÔéèçŽÖŽ·1ÂýÔZ;Ëh;ù›>”å)–°lá¬_ŸÉew?ÕNÙJ‡³ÝÒ¿ØL¯BjSvËKr¥„j–’Çüß8tÔì9ëþÃt`Î,…mxF(@%gM K?,á(,,Ó6—çž{nˆr -‡3¥]h{áÏ_\äK¶é÷Êw}Ïhð£ã»sÑ _{íµÕÕÕGýáPýÊ+¯üä'?YäÁ?åZ‡ÍEFãô·S,¶wXwOùÉÁŽ.½c³èñ9`UmãWÝÑlüfÏî.¾áSèèþÑ ­È›V«˜F=xî¹çÂY‹‰Æ¯|ÙF.õw¶„74bÝ={ÎÙªº¯)h´ºìBƒ^¿øÝýö²"cšzT,è%Õ Ã›HÚÔøyðqd«©Ó2оî!aãïnØ%yö4lð¢Ó‡À/¾êNÇïÒ±bUZ. 6à±%´\~02 Ô3Å=:Ԧе@…ßïø5òînGc¶_^ ;¤l£{VhcþÁ5b¨ =M£«7‘ ¶¯Ÿ=týûh§¹¿¡‘~ìÎEƬö/ O¹ÖasñÑhÏ@zè÷úsç,½< gí^Ñuïwým†.=ö€9€h*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*úÅËk¯½æ-ºàõï¾(Yzò³Ðà ðÕW_}ûí·agG<ÿüóKK ÷ [—T6ìì]R]ذæFº¡Mš›E‘@ö³ndÒüñw›Žº´ùãЬSîÝ»÷0=Ï{|ª¿ð •‹žç øT·«jWX—:]|ìªÚÖ¥GaÖ,•ö<ÿ}1þøÇ8¨´çÒw¯d.½þ?BãŽøàƒVWW·sÑÛ4Ú‘@_zé¥åòâ‹/ºCUB³æ˜=í ÛÕÖe×ÅÍ–á²f{êRÛ5×ÅÍ`F${ªô%P·ç_÷¾Ñ¯@_ÏåÍ7ßÔsØŠiÔžázª‡ö‹Æ«¯¾úòË/ÿM.¥C]£¡}sJ{š:­è!°Ç"´_4\*vµuÙíúëÐÃÚÃ_–A ƒ8s‘=»¨ÛsH?{hyÇ«˜C]£e*N\Ü86þÒ¡¦Q{†/àÓÔ©âö´+?:—pâ‚PÚÓ®¶6ÜKšW8þ"Dº=ûè{v"М4ĬÁî{¿õUôô6†Ó›ãÞQ1ï¨hüîÍΦ©çy8½9¦NŸE9…r>…pzsL*~ ©Ø]dñ[HEÓ §Ã”ü@ Áž}e £öìB ½?z\¥Ç_60¿yìÎQ±‰øÍcÑþî%“¦—Òž*¡õ2HÓ)ìÙ…@gY‚Y '.ϲ¶Ù…›ccV™0f=4 ¨NÃFh£ ÷ŒŠM uÎŽô1&“¦—Á=ØÓ¤éôfÏ’Ó² >„ö‹†=cU4Z [Eã×DTlR¡}sl¨6Z»Ú>T=z8BûEÆjWXƒ·k®éØ£ ÚÃ_–áƒÍƒ2‹â-ºÀ¥é„ÝaO •ðÄÍ=uÍJ*ÙKƒ˜B³æ”ƒ´Z Í ÕÙ34ƒ±pð G{VÛø5‘p´9åØ:ò¦ìŽÂ¬A Ý`O•°³#LUags4¤Ôú³cê ;an P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  PÉÒwE ǺÀËÿü_ÿ;ê‚ÞËëo_qÂÔºà,¿GÂtº# ô?þó?Œp¬ 4ìÇOþKt*P¿ø¢ç€®¼¦Ö>ø30þ ÓéŽA æ p¬ läý ÔÇß)&Ð~³‰í;œp¨ Êñ÷H˜NwœÚÓ8꿸@;}2ø3ygg'ê§„étÇYè‡ÿú!mm‹¿SÂtº6Æ®|¿ жøø;%L§;hcìÊ÷ m‹¿SÂtº6Æ®|¿ жøø;%L§;hcìÊ÷ m‹¿SÂtº6Æ®|¿ жøø;%L§;hcìÊ÷‹]ù~Ÿ þLF MÓéŽ$P2„c] {"І жøø;%L§;ö+ Üè}üýbíT@¶—p¨ †¡w[ÂtºcIw¿ŽuÁY|S”0µ.†žK8ÔÃл-a:ÝÁ×ÙT‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*‰ýÑ~ôâ‹/†±½½½ººv.2ß~ûíW¹<|øðÞ½{6þryóÍ7_ýõW_}5œ²Phx/¿üòßäòÒK/Ùýó /üU.Ï?ÿüÒ¿¤áÌ2F *agG˜}ÂÎEæ©ö”žÂ) …Òªâ•@UÂ)g†´L"Êý½P (ZdÌž=¦Ÿ†ªûGÅ’ÐÐà,êÏr/”ö ‡™~ÓO£LBýþ‘@- Î?hù(÷÷BiŸph‘™`O=¡ñ¢Ñ–¶ûÇœ%þ,Ðò9Ðcì£,2èèøõ@„f K2èÈýÓÝ-ðß% Ôž·öðC]àöñgrh°ÈXúƯG!4[X‚÷íþA pæù³@ý9à 1?ÔeúÖ—}DJ>GÆßÑÆ¾»ßÁÿ]ònN¿ß}B€³Ç P–Íh°àŒÞ?¡ÀÙc(ob4gtü¡Á‚3zÿ„g$P>F³ ”ㇺ ¼Â!€3I(ä^Êñ‡C]PÞ?áÀ™äÏ=Í¡eëÅDƒtº=Uò_v&P8ÔåýœI–ø2‹…ÂÆvv„Ý?a'ÀYe‰¯S[(lüagGØývœUz’ ÀB@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨déOúÓÿøÇ¯¾úêáÇwïÞÝÞÞ^]]]^^~ã7^{íµW^yå§?ýi8g¡`ümÑð4H UÖ°5xMAÑt4)MM §,Œ¿-*ÇÇÇ“ëpÊB@ÓûøP[zÿozNY(hcz?jKïã®[‡S Ú˜ÞÇ€ÚÒûø'xÓëpÊBÁ›Hé] Ð–Þ\9¶§,´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-´1¦ ´-Kº¾^±.†žK8ÔÃл-z{ Së‚a蹄C]0 ½Û2Y‹_/éw”—ðØtÁ0ô\¡.†ÞmQúã%L­ †¡çuÁ0ônË7uQ/)Ï÷›.†žK8ÔÃл-ZMKxlº`z.áP Cï¶ ŸfÊ%L­ †¡çuÁ0ônË7uQ/ ŸgÍ%<6]0 =—p¨ †¡w[†ÏÓç¦ÖÃÐs ‡º`z·e‚›º¨—†¿¨Ê%<6]0 =—p¨ †¡w[†¿èÌ%L­ †¡çuÁ0ônË7uQóe"• P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@%  P ¨T‚@*A • P€J(@% Šï¾ûÿ½k)b3·…:IEND®B`‚simutrans-124.3/themes.src/pak64german/files/stations_status.png000066400000000000000000000107741474050137200250350ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜlgAMA± üa pHYsÃÃÇo¨džIDATx^íÚwxUUÖð;TJE@AAŽ€]‚€é%ÔAš i’PuDŠ8DýÀàФzMHB-ò~kr¯Ü°ä›ùþ;g­ûûìçÉÊzOIpPPÊŽ•¸zv;rSÃõs{²{Ý=sœìHõ~8UcN×ÀIÚÆUëËÎsª]mÛâôk¯YvÓ>7Ç)¼€_§Ð?9äð{ ížr“éëLsH\íu²Óܪów¤Õ†ø­æ7ÎÄšƒ]{8nÖÅžçèÙèÛèÞèÚõ³ß§Ы{ŽÝy€6£>ÿ ¸ƒìcŸÐà* ‰¶?Å•ÿÀísŸW~Àí oݳˆ\©ý’jö4~A&çk ÅU¿ìùv‡ŽÜj×ÿ¾KYÇ;ubϵ3+±£Ë?½¤.Gê¯31wp.ˆŸd„`eÄxìû–ît[ú mÖ£ìbv…:#‘]kRèʶ@ã»Å“ 5"·vNVïîcWWèQo¾‰[¯¿ŽßiŸcŽ¡}{\¥-·†]YÀªªÀõ€Sø*¢=ž®Õ·uÎÒár4mÞ ‚_¦@  yÍÕ•ØÅìjG¡˜Z¹'èy?ƒšü\~ÓŸ"æÊŸL²h|½Œ«Ô ™» €šú=ëßhÝú¾nµicÍåÖ°+×Ü.ëPc×âZ nýóx»CEjö†t P\mˆà¿WŦŸ¡@´¤;@-`CmDtý» Ý\÷ DÄ“½àòõG«2ðý=^®öÔô檉î iÕ ¢\WT.Óù¶Ã‘jCpœÂÀ­g7‰ÍèÑ·Q#dùù!³jUdV©ò§Ì4lˆÌæÍÙµìȵa$5û÷õŸ©ÙQÓ'4ÓM€ô¦@J#àR ä%¶¥ýÖÛCó¶4À/ï>Á.h7¨;ÉOôÂÞAóÑ} ¸\/`pÙÎH P\¨Ú¿Tì7Jùã/óGhäרÛ0YUèNX÷=v=»1Í™žñÓ6nDÚ×_#mýzÞ† Hûî;dУš4aײ#×÷c+_5vÒÕý8½è$Ñ7y(5ü2˜žûß¡™ãi4éOsè]aËóˆûà)vA»A½ ˆ/ÿ6°ü[¬Š=WÙ71`æ§Øødo¤ˆV£ñÂ0ºÎ_ËÁµvÁH¨Ôxn »žÝ ^=¤<³ÿ|ÒÆS/ԯϮeG®5Ã*!ã#ºì¥d'S“§Î¢m85{™CÌþ"àÂbº+ÌÄÕ#Ý‘¾©öL¯Ê.h7¨;ñ÷Df÷ܤ/›1ú\«Òÿ®LÞê@ŸæŸìëHz†^–« &±ëÙ è±&‹ží×­CâÚµ8·j+qÍ$ÇÄ íÅ:uصìÈõƳ¾À&*À·oãXìŠø zì!ç—Rã/¡@,£±å43»¦ãôÖ¾ô(Ô]ž+É.h7Ûž¢@WŠSÓcO±vH÷i‡ãÅÛc´ï›èW® ÑãOÊCíqÞçuœ¥ñ3åºãJÍ ,~¬5»žÝ|\¾jòùOõFz­A¸Vs ÔÀú:žö“kÆ:#0·| v»šSº4®–-‹ ?Œxr–®òw3cçI.Í™Gs¹5ìÊó—`+¿Ð{@Ö(2…s‚q;>H¤Æ¿<È¡÷ƒÓÝ×ünÇéÊÍo.P“›¿$æÿÔl)鵆 ×o6WêÌžow–,‰œR¥Q¢’H|>³oÆÌ±u¾¾ì¹væ €ašÛ ÂÁ.ô"ÜŸîé®@ÛC°eyCÇ6¿Ûöªô|_û¤×²þÿù?Aæªoîiµ±²‚³þTл>ˆä"É*VÌböw“±„;Çî¼àfýÕÆ¥ÐûåGÑ©åÃŽoü‚¶VéŠÛuéŽWo,ÒýS©;Ï©ÌKn‹“^x9l”’B DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €íÿ ÀC^¿bì1'1g6ÿ¼?o›÷ÿ²ykF„Œe×¶+— IUÒ™psœÂ+ãü|Ðø‘B^p% )?®ós’y«·Â€ÌÉ@úÔÿNæ:w&ÂþÌ®mG¨á§’Y¤7éCêæï?^ïYö;ó UÙÂXò|1 ¨]Òs°Q£&¸yz?ý °k÷.4oÑÂsÌ)&.›¤x AÚ$àb0BMýŸ0sÓ'#ål8FD„°kÛQjôî¤ ƒÈr²ˆ4Êãγ+O^-WS«¹Ð¡ìß`ÈÜPú¸”}ÅÚæääxŽ9Epô<|³÷C>4›Þ't'H1A¸Tšsñ};2›öDa\ä vm;z‹Ü|úÓÖ4H‚ò™ý¦d0áηOF×/ƒÉO»°‹~˜-?e­X…¼¼<$''#33©©©^';Á¢uK‘”°ŸÇ.Ä!‚TjpO ^ùóÑœ£4w}ìbœKÇü•ï³kÛ‘yæwÌU(1ß’˜;1† 'Í·†xpcïH Ö|ó§3¿¾5¶aÃFܸq)))¸pá¼Nv‚è˜tk›ƒƒ¿ÍFô‘ع/üÎãMÆ{w‹¬†'fߌѱûÃñ!Í‹£;äõéˆ^;‘]ÛŽLBH_âþ¸›Þhs×~k­a'žÜ>ºˆ§o:#}ü«Yc[¶Æ"77׺òñññ^';AtÌr w&5øz¦9ç¦â×aî×Ñ8qx=ÿQó_š„“Gg#ô›hDRã_Kø€æR L(r¦Ú>庅£bÿe(ôôk¨;y#fRc›—Þpb>&æŠïÂKù^$Üzvâ Àº¦´Cßpvº½ÔÌÛ·s;ý›‡Œ´‹¸DÅÅyìV®‡ÐUþÎÕþÄ‘|¶5_m_ˆÅ›–a;Ývî ¥ý(|·c¡uì@ÜÜ?•®M³u\¾Ï¡Ûúƒ–ê£ÖX(Ù¨‡µC nÞÌ£yö/ƒ[ÓN<¨úf; ˜Õßoþ3ßj­‰^޳)i¸yí*2².cóß{ìVrf&"íÌLlÚ¾ÿÚ3i§§c×¾0¬Þºk©é·ï›‡Ì33°g6þ² GMhè¥9ç[àñÞ‹Qyp4ŠÔhg5½1ô×K¶7¾MûX_›;û·AîÇ ¶ÄQwW§pù£Îè¥ø(t¶5öT݆x²÷4‰¨÷cáÜ;ãNbàÆ,$˜†/·E`çpüž4Õú-¹Ê_ŽŸf±®ø'ãvêì?J/Í8cBcï;€i~óq7ñÝ<ûn¥[°¶ ¨áÍKqsÒŠ<3îλ¢yP¸_8\'ÁÕn­þê MzÓø{8±/†µoãwЍ/——C±á—ؼcÁÍnýº3yÉS,ž1zì¹zîü¼g>…€Þ›2g"ÊÆ0=b­´ã¼§éÍc¹ ÈöŒUì4¿ Ä#/”°šßQp ˆ€«Ãû–Áó>ñLøk˾põ E@ç]ý°•³wl1¶î Cn"½Üfл½ô"îœK$}"Ý ‚±covYЧ°kÛiló1Û!»Ó¼¶Féý­m£9[€~ïàÙÀ¸ºÍ‚«i/¯I…Áõêp¯1§è: [ÎÄ ;}p•®è×Ò‹í¢û3sr"'k)¶'|>sf²kÛňÃ×­&w_íÍ•ßl÷gYÛ2m‡XÍù€¸Ï#±äÝ!ÈÚùí=“ŠŽ@‘^öþ!ÿ™ò/øãù€áx90¯ýw^¡sš Âc­üÙµífä±VÃÿíŠ×¶ìKÃ<x;vœcšßð`SÔ¬ ŸŽ›G¶ß3©pß0ø \pϸr¦QÇoZ?òh®µu7¿ÁÍ·3OÆé‡Ð £ppãš{&í9…‡FÞ3®œmô©[h¶ÍÓü {z?;'ƒ»vÄÆ¨yX6ížIO6n‹²m»Þ3®”Ýy`¬ ŸÿY¹Ìk‚RNæ£M‹¦^_+åd÷@)I4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñ4J4 €M DÓ(Ñî€ëÏ>{G½zìq)‚ªUcÇÀårÉÆÅMró+ꃀÎ/ZŠúaç8Û’pE1ÜWî˜8»8síssœ€m I¸¢Ò}<ÍŸ›ãlSHÂEzóW|¬ pj½3ÆÍµ;¶)$áŠ"ùñ§hü¹›—.ðbÆÌ1î;c›B’‚‘Üü£úùãÁŠ¡EÃZ´-jm[æïßÙ³æpçÚÛ’Ü] wóÿ™»ç:Qìg³PºT üôé4Ïv˪éÖ¾{kæpçÚÛ’Ü] ®éÝîžç4±«g`+5ûÃë·q>ÎnYfmbWXîŒEZ[3ÇÌ5çpkÙ Û’pEq3/ÂNo~#ïÄ—¸¼5òNÆàÔKÑñåÆð)Tç;v´˜ý·^i‚“?.±æ\=°Æ:‡[Ënئ„+Šán~ ˆœ6ƒ»½l]ÕK±ÑKá[ì gO‹ïXc%‹?dÍ1sÍ9ÜZvÃ6…$\Q )ÍoÜ€R%Šc› 5}^³oÆÌ1 €ÃpE‘ÔüFÁüë£Hø.‚‡é¥×0ûfLà@wÃÝø^üAlÇs0w|?lûl|©Éw}…%Ãû¡…_ ‹Ù7cæ˜ù-мIØIçpkÙ Û’,HÁ<®œ…m I ÄÓü‚ÿ+„$lSHÂE¯ür°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Û’pEQr°M! W%Ûb¸ð¿na²D”ŸIEND®B`‚simutrans-124.3/themes.src/pak64german/files/theme.dat000066400000000000000000000152351474050137200226510ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> skins_neu.0.2 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> skins_neu.2.2 Image[1]=> skins_neu.2.3 Image[2]=> scrollbar.0.2 Image[3]=> skins_neu.2.4 Image[4]=> skins_neu.2.5 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=- Image[7]=> skins_neu.6.6 Image[8]=- # scrollbar knob left center right Image[9]=> skins_neu.6.0 Image[10]=> skins_neu.6.2 Image[11]=> skins_neu.6.1 # arrow buttons up unpressed pressed disabled Image[12]=> skins_neu.4.0 Image[13]=> skins_neu.4.1 Image[14]=> scrollbar.2.2 # arrow buttons down unpressed pressed disabled Image[15]=> skins_neu.4.2 Image[16]=> skins_neu.4.3 Image[17]=> scrollbar.2.5 # scrollbar back up center down Image[18]=- Image[19]=> skins_neu.5.6 Image[20]=- # scrollbar knob up center down Image[21]=> skins_neu.5.0 Image[22]=> skins_neu.5.2 Image[23]=> skins_neu.5.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget_new.0.0 # help Image[1]=> gadget_new.0.1 # minimize Image[2]=> gadget_new.0.2 # previous Image[3]=> gadget_new.0.3 # next Image[4]=> gadget_new.0.4 # unsticky Image[5]=> gadget_new.0.5 # sticky Image[6]=> gadget_new.0.6 # resize corner Image[7]=> gadget_new.0.7 # goto pos Image[8]=> gadget_new.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- ################################################### # text labels Obj=menu name=DisplayTextLabel Image[0]=> display_text_label.0.0 Image[1]=> display_text_label.0.1 Image[2]=> display_text_label.0.2 Image[3]=> display_text_label.1.0 Image[4]=> display_text_label.1.1 Image[5]=> display_text_label.1.2 Image[6]=> display_text_label.2.0 Image[7]=> display_text_label.2.1 Image[8]=> display_text_label.2.2 -- Obj=menu name=DisplayStationLabel Image[0]=> display_station_label.0.0 Image[1]=> display_station_label.0.1 Image[2]=> display_station_label.0.2 Image[3]=> display_station_label.1.0 Image[4]=> display_station_label.1.1 Image[5]=> display_station_label.1.2 Image[6]=> display_station_label.2.0 Image[7]=> display_station_label.2.1 Image[8]=> display_station_label.2.2 -- Obj=menu name=DisplayMarkerLabel Image[0]=> display_marker_label.0.0 Image[1]=> display_marker_label.0.1 Image[2]=> display_marker_label.0.2 Image[3]=> display_marker_label.1.0 Image[4]=> display_marker_label.1.1 Image[5]=> display_marker_label.1.2 Image[6]=> display_marker_label.2.0 Image[7]=> display_marker_label.2.1 Image[8]=> display_marker_label.2.2 Image[9]=> display_marker_label.0.3 -- Obj=menu name=DisplayFactoryLabel Image[0]=> display_factory_label.0.0 Image[1]=> display_factory_label.0.1 Image[2]=> display_factory_label.0.2 Image[3]=> display_factory_label.1.0 Image[4]=> display_factory_label.1.1 Image[5]=> display_factory_label.1.2 Image[6]=> display_factory_label.2.0 Image[7]=> display_factory_label.2.1 Image[8]=> display_factory_label.2.2 -- simutrans-124.3/themes.src/pak64german/files_large/000077500000000000000000000000001474050137200222215ustar00rootroot00000000000000simutrans-124.3/themes.src/pak64german/files_large/back.png000066400000000000000000000070031474050137200236270ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûP ÊIDATxÚíœÛoéy‡y¦fDr†‘%Ú”å•cl6l,Ú -ú‡å/(» 7¹Ðöª½/P䀤Ý`‘ÃfmËÖZ¶l®(“rÈÎp†§þ†Þæ2(üb2ù€ß³ A¶Èò÷>óÈá—ío·BÞ•\Ú¿Q DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D"" ÁËÚé½´wç“ýq¾Ph5[A¸X…Ñz³)—Ëþ|ž/ä;w»OwN:Aàú·F£žÉå‚ùÜjXaz®[©VõJ% aYÖÁÕ‹/õƒñdÔ>lFCëà a5¯.Ÿ&ºþOþåß¿ÿ£¦½‹ïN!í_@NÖª[®ëerÙL>_.—ü¹Ÿ/[ÍËÇ_tîtÝ™;9Š®iÖÃÕj:›†Y.ïáÁ™Ìaîßô4MÇ#ãèßàéÍ£ö峋ä×WåK˜Ù¨»ž[­V ¹\¹Pð]/ŸËâr¿xò(Ž®çía©T*k¢[©xÊt26ê $’p!ºøÆ±íRyo½Z!+Ø£‘e5Í&¢‹Ô’ôúiïŸåBDÍz#“Í!C8î å¦Z3.?:;»ïL&ÞlŠësÆãJ¥ŠÇÛöÈ0êøUNJEgê”´½( ‘<œ‘ c Ó¼~ù2Š"”˜¤×O{ÿ¤(/P«}\*£Eà:SüѬ×Q,Îϸ®‹ëÑmÛ㑦iøiàyˆîz»Î¬×åRiµÙ ›©VªQTk5Ç™˜žb‡h\ ³Ž’^?íý“¢¼@¨h8D±¹~þÜ0îlæy.ª’ÇàÍ›|.7(¾Çàñ™M\VBd€0Ô÷÷ýo8ŽƒÇ¯–K4ËqåBt=·Ý>N~}µQ^ ¹A«Tq¹ßö^— rYoŽN%‡ÑÉ:kD4“ÙUsµZ]ß÷ÃÅz»1k*”®é(@¥r)îWö4ÈÕÜÙ´ut…QÒë§½R”( Z¥‚+þ«ë•ZͲ,ô%ÚÇ'¸èƒ Ø=*‹TÆá]b ÃE>›Ã„íz3}_·Ç¶¶¯Gñ¤ÝD\µ=Ý›ÍZGíõz…AÒë§½R”su¹Xì¿zeÔ܃þíM>—ïtî8ÎÉc½Ù U ^¬—þGn}´Y4(®ïA Íï~Å›Ï;wï:ñ†#X» <›ôúiïŸåB8·}\âV£Ñ¿ù e¥{ÿ=ÏC2Ël6š¶‡ë~½ZúÁB¯TÃ0*”K…BÙ $@[3¶Gççß°‡ƒ|¾ˆx·Ð2¯ÂÁ^Å~$»~Úû'EyP Jå2ºŠÁp€Ø4š‡ƒþ féõrY©V‘3âÊó0 ¡•KÅU´DƒŸFË£“ç8~ô7ƒ7·ÈÓ™ƒоøA`Z2rOÒë§½R”$_,í!bi`&êߌ‡ÃL6WœÖa†î<Ž.º“ø-ˆpQ.ï¡ÅKÅ""úðƒoõz¯3lÛn4Q€ûöqý lp&“¤×O{ÿ¤(/ÒC¨,š®÷{¯§“1ÊaÖ1¡Ë@Óº‹î #´ï{hlшhú>’†ó‡Þïõ^ç³yg<î|­VÝ{÷Çö!w]÷/°¾ê(/æçŠi–ŠegêŠ%«yXÈåœÙÕÑÍl·(%ñ‹xf}0|S5Íh÷NçÙ½÷®¯¯tm½°up†!V{ø~œ0ÐÛâ;-JI¯ŸöþIQ^ t':®~ÌÓj¶[LJ¥bÁŸÏÑá¶ÖÛ RÈàMüæ%"‡† 2J÷ô^ïÕõîõ½)ºcä†Lf{þðý«Ë‹B.‹y< ù|CVÒë§½R”µGàǯ쵎3¹º]à­¼×ï÷1B_½øª LhµÛ×/_ + Y~àçsÙó‡ß¼|üEæë×”½|±/ñ_Òë§½R”hw5¸”Íz}Ù¢)1ÍF¡TŒßBßNÝÓÓ‹'QPPeP\ÐÍôozVÃB ÂSð0”³ûýá·èc0!ê¨S¨YÈvÒë§½R”ÿD»fµõåmtíñý).n„°Ó¹{ùô¢{z†H¯—+´)q¡i¶WÓ0}ž/ÎÎ|þ»ÏÐùÆ÷]L|6·K ÛÌ®¾$½¾ê(/¦b´ˆ1Æi„ÙÞ•MÓÑðî¢û¤}|âÇi S5 DõÅŸûf½è"t»gŸ}úß•šßžG·\FÙÚ­¿œ“ôúiïŸå•*Ƶã°ó"çÍfAàÇѽxÜ:<Œû]ÇEßïõÚ;ˆn5~/s† ‚è~úëO0“Wk5D– /ÁÃW«U´ -š¤×O{ÿ¤(/Pü–ä2²šÍëW/-ëÀ™9Ú¾Þít¯ž]4¬¤Šh±ƒ`8èwâèÎK´ºˆ7‚ýÉ/~zvvß4MÄÉ*˜5® ºhžƒ…%½~Úû'E}0N·ÛWÏ/‘У”J%šË/ŸVj5}¿‚TFÑppÛ¹sŠ߃:’Ë·OŽþ_ÿùÑÇ‹~¹!˜ÏKÚžiÔãÛÄâÆ%Eš˜JXÂë§½R”(ŽîÕó³ûçöîÞäøÃ—Ïp­ÇËj‰êóutgS]ÓÃ`§´ŽŽùóŸ}ïþ) ˆwàzZµòö^‹él¿Ž¼ÙTMÓ_`øZ'½~Úû'Ey®¯®P;ÐÛ¢j A¹xü¨sz¯s§›‰ïJŽnooÞfLCȘ}ÚÇw>ýŸ_}ïïÿ1Žî|>ugˆn«u?ÆöȈûåõ×-ðfƒy*éõÓÞ?)Ê Ô>9q§ST ”ËgçFË0ð<Äo:tïžâ*GëÍdÛG'¿ûìÓï~üwÞÜCeñvïz€Áàv<¡§y{k˜3™¬WkD7î‹^?íý“¢¼@ƒÑ0“Gì²ý›×Ý{gù\ü*‹ƒáyµÆq¦oß4hŸt>ÿãï?úîǼ¿ëKxd—þW½ÛþMóð¨P(˜¦áLÆx0Æ«Á›[Ó²’^?íý“¢ü µòÞzß¾Ž2@ƃñv3¶‡ÝÓ{|¤õvo:'˧O>üöwÆ“* êbìa\YNŽï”‹%mß¾Yo¶­fÓ¶GÕJü9Ф×O{ÿ¤(ŸÖÛøõ\„UÈîú^#Uà*ïßÞà§š^Áå~yùô›~{lâ›u6ÛR|'W#z\†Nï!Ô†iÂ,…è¢Äèñë~3tÍI¯ŸöþIQ^ ­VøZ©T//UkUD4ðý~ï5þÒ¨7Z»FøáÃúý¾;‹ß‚ÂÒ~:¶ín÷ s¸V©ôv7ë–ç¹™lÎÅàýït&½¾Ò(/ÐÛ£·ÚÇ—ÏŸµO*5Ý+ D&—CÑ©Vªøþüýz½WzüÙ¿mÜš —är¨;gïGë%’šÙj­†‰ÝÝ}Ò4ZFˆ.Fn}OOzý´÷OŠòYÖAe¿rýâ9¾"78¶=u&(6ñ­Û *ÎÙùƒ«çÏv/O1û  Uâ3ÂvçNàÏÑ£55åÆªÕ*I|7êt‚Ô‚é=éõÓÞ?)Ê7цٸ¼¼Ðtã1®ì©;3ªµø£}?žÝ?¿øâ˜wc‘7¶å2âúöƒ¡þÜ7jFÕˆoN]­ÖÔ]m_Oìöa±·šÍ¤×O{ÿ¤(ŸpõÇ/7¬`ᇾñ| tQ>ñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ÿð| tQ^ ž”.Ê ÄóÒEyx>Pº¨/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQþƒ…<(]”Ï@<(]”(ÃóREyx>Pº(/ÏJå›hž”.…üó¾ÿ£¦ýk¼;?ù·ÿøs?þåoÞuá'ÿ¯G%½þ_=Ùþv›öï@Fùˆ¤ ""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "âÃ"&q¼³™IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/button.png000066400000000000000000000040651474050137200242470ustar00rootroot00000000000000‰PNG  IHDR@[*ÉÇgAMA± üa pHYsÃÃÇo¨d×IDATx^íÚAŠI€Ñ>«+×îEE¼€'tãFã1jˆf²È Cß xÌ´™›ø£ªã[ôÃïÛívøòåËýÿ+Š{>û/ûðáÃÅjF;{ÿþýíÝ»w··oßÞ^½zµ|ggóù׌ó?[ÍhgçÏ~ñó?ŸÍ=€>}úôè<œ‚±çñ%X=+8νj¾V3ÚÙø% €ºÆ Æùæùì®?Ãùì‹èãÇwó€v7ö<1¾«ç»;Ÿ}ÑêB(@×ó¯9æ0οø;°?ÃqîUûBTŒ=»8¬f´3´þTœgQ<ÿrü cÿe—¿‚š]èzþ5«™@…"­~! ëù׬fˆ´ú… €®ç_³š T ÒꂺžÍj&P!€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žrs  'Ož\÷|6ö_÷ôéÓÛ³gÏnÏŸ?_Îhg/^¼¸X½³³yÿ5çÏÿøy5£ÍóX½³³yÿ5÷:.ƒóp Æ—X=+8ö_%€®¿VïìlÞ͘ÁñùùòåóÙÝØóaõ|wçý=Ð?ã‹0hwã‹X=ßÝyÿEèÏ ±dÞÍ1‡ñùýúõe6cÏÅ}ŽýW=œãg| VCÚÙ¸ôÎVïìlÞZ_ˆóþkγxóæÍåç‚âžÏÆþËü4ièïbÁ¼ÿšÕL B‘&€Úâ¼ÿšÕL B‘&€Úâ¼ÿšÕL B‘&€Úâ¼ÿšÕL B9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä ç@¿~ýº<,(îùlì¿ìÇ«íìû÷ï·o߾ݾ~ýzûüùóòÍç_3Îÿl5£?ûÅÏÿ|þ5÷úùóç£óp ƞǗ`õ¬à8÷ªùBXÍhgã—€ê3ç˜ç³»rü ç³/z  ó…0hwcÏcã‹°z¾»óÙ­.„t=ÿšcãü‹¿Ëñ3ç^õð·/DÅØ³ €ÃjF;@ëÏAÅyÅó/ÇÏ0ö_æ Iû×…P €®ç_³š T ÒꂺžÍj&P!€H«_èzþ5«™@…"­~! ëù׬fÈ@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9—ëüsÁX«¯°®k5£ÍkõÎάëZÍhgóZ½³³úºбÎÃ)8ÖêYu]«íl^«wvV_ó æùìî¼VÏwW_t^ó€vw^«ç»³®k5£ÍkõÎÎêkžÃy6ÇZ=+¨¯‡ÿÿ{_«!íl^«wvf]×jF;›×êÕ×<‹óÏc­þ½¢¾ü4ióZ½³³y­ÞÙY}­fˆ´y­ÞÙÙ¼Vï쬾V3 DÚ¼Vïìl^«wvV_«™@…"m^«wv6¯Õ;;«¯ÕL B9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä G9È@@Žr#€€ä ævûÅuñGah³IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/checkbutton.png000066400000000000000000000017711474050137200252460ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa pHYsÃÃÇo¨d›IDATx^íÚ[KTaÆñý‚n‚n‚n¢ˆ¢‚„È, ¤ Ë("³ƒBà˜šN92ŽšeŽcŠPмè„ÐᢋúÓj­—a»)]k¶#<¿«hæE÷_Ð=;ú],–1ÉáõÇöˆ'ÿ®^RU&?æIn!Gz¾ö”ô}ê#ÙwY¢^RUzxYÞTlƒ¼nžzIÂ2Y"  ÞOBé­“×Û-^ЧÞjUääÉЯ,Iÿì']ßS% í¤uþFÉ•-äîÛ;D½Õªïü‹e.ÃSo•„€L´²t®óZx÷xñ÷LÒÊÒ¹0wžœzs’´¾n%êm#ßùPÄŠ–|F™„€ìéÈšxm¼Ò °§#޽l —g›‰:¢¢ä;*0O® :¢B2 É ‡jxËMç ï8¯tF¼Ò©Ÿ­#û¦jˆ:¢¢Â•w:¢B2‰ <ßtdrËQç®ð¾@|Ó©™N¢Žs'· Ã5w]Oç! “hŒªáÙÓ9Ê»ÉSç¹{QGTB@&! !į­tâ䑸µ•Nœ=£$Ó™, Hðñm¡^õ§'į­tâä`(â¿—|:! “%Š“Û\òku#¯wŽ'·ÕKªJÇt;91ÑHö>ÙCvŒl'GF‘kãW‰zIU‘?näã¦|li^2· ËC@È䔇€À &L˜ 0A@`‚€À &L˜ 0A@`‚€À &L˜ 0A@`‚€À &L˜ 0(ÿÁÖ`_DÇIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/compass-iso.png000066400000000000000000000423541474050137200251740ustar00rootroot00000000000000‰PNG  IHDR€}WÑ zTXtRaw profile type exifxÚ­šiv[;’„ÿc½ÌÃr0žS;èå÷¸¤-ËÒ+»«$K¤)ò^ 322€Ùÿû¯cþ‡¯ìS51•š[Ζ¯Øbó'Õ>_ýþv6Þßï/ÿzõ—×MýùggáùoÍÏ£{¿þ¾ÐëÑuž¥š¯?Œ_ÿÐâëúõÓ…^7 ‘ƶ^j¯ ÿüÁ½.ПiÙÜjù8…±ŸÇõžI}~Œ~ÍýÌÛ½îöùÿ±½•x1x¿/óÛÿ èÇ™Ðõ‡û;óÆç¹õJy„€|'ûaT括¸¯²¿IJÈÏ; /üÌüãñË×]ú:øæ†øÃÃ|=óŸ^·®|žÎûçœUÍ9û™]™æ×¤ÞS¼Ïxã`rá~,ó]øIN7bôÛ½Ÿ$J¯ÕP|ó3XCn¢¾Ýñ%´°B%™“ô^õ?Æâî}Û½Ýt•/Ç;½ãbNP0úõßøþöBçòÎ)˜ñ‰ãò!ÃPæô›wéç£tüþþü¥¼®–n˜+ìv<—ɽ°%…›èÀò\Y¯ 0 îŒ dÀf’ËÎï‹sı’ŸÎ…ªÑRàRò‹Qú¨–â«×½ùLq÷½>ùçe8‹D¤C!5-tr!6ðSbC=…SJ9•TSK=‡sÊ9—,òë%”XRÉ¥”ZZé5ÔXS͵Ôjj«½ù ÇÔr+­¶Özç¦+w>ÝyCïÃ0âH#2êh£Oà3ãL3Ï2«™möåWXðÄÊ«¬ºÚêÛm ´ãN;ï²ën» v‰'|Ê©§þ#kÎZÊûNt’”32æ£#ãEÐ^9³ÕÅèR§œÙ橊äeRr–SÆÈ`ÜΧã~äîgæ~É›‰ñ?Ê›gÎ(uÿÌ¥î›Ìýž·/²¶Ôm¦ æfHe¨ Ú@ùí8â„›Êqvµ:²-Ÿ^Óðnõ9ÀzNõŒ¼§Þ’C]kC¯Y{¯zÊ"ÌcͳÚÞ[•5F„ÜÕf™‹'°êè9õ´b#’Å¥9©9M†¦Š‡1WÝa¸ÝÒ&Ln5b7b©ioè—2«ÇWî×zmjh±äœf=u=³eÛ;C.1"^Ç"á]{•3ƒ+Jïl@êŽèpƒKTŸJX ð¬(7ë®qû>N-!æ³×\9“²(¬?~¨³ºXz.LɆ±ï°f¡•ü ²M®æ< '×>F» ÏìúHsÕØ —÷šžü륥PmäÂÍãZ‡¿ý0z);óB™„vžšçf`9íÒí^+ŒC3?Þ·™IéóŽVsï©nØÎçn@µsà£2›æöôcŒüòÐ0Ï-Mj<Ó×dçñîÄYܨm“ËYDi;Fkîê&ðAWûÜ ³35` ô˜uô-%˜¹-·r+¤Õ¹g9góñdÀè?îð³¬Qr8µÒóÞÂÔ>…!Ígû Ùÿyà Ê› ÛbU>é6 =­À€ðb°µIFŽ!•uÑá[ŸÒ™s"-lÚpÒÌÑW"xà[ʼC#9Árª@™BÛ¼Ó,Gé¥B¸âòAð(Z ¬&ÈrT7Z<¾C¼ÀHÅë°NP±jƒh„4‡A‡ÀÝ­à*1&«ÀAÑ(>)²åÚ‹|» q•à2¬Å´O&N Ì?aÈá+26s«°!`7ýG¹¢d)»îwŒ »S’}C”Ô–›ÔDT·%ÚÀÁòpÆ Öèî¹-tÓd†À@-‚ M^cŽÞA8>ž²òœOÀžàPqé†ðxnæE#d¤òÖ˜R6}Ÿ$2ß}6±r;\ÔÁn€ˆæ9Ó°ÙÄ3øÕ(OþD¾Z&6Mêe¦6O#‡uøðÊm”p2¯ThßoŠ¿Ât?··e®BÐéàà$O3Zæ"Y‘ÐŒƒlÀeé‰È“4jþ‘Gó‹Hcÿ‰bÿ5„Íßcøk›¿Çð×6ƒaæÖ7?NNv“C—Üô sô¹v2ñ°-â¹ÑÍ"ÀI0†_¤?Í$Фup½ÔPràhÂÛ(Íâ©4L)H¨ƒô¹"MŽ‚£¢#RZpÝö)LµU TÀÿ)g-†hK„Ñg€R¦YXeêP=]„È.>¥ï1ü5„ÍG ç/0Œ"B›@‚® Ç ƒÌIÈ`„ððQ•u톌Ö`·˜ü,;(rTÿ@¾ññ1·ôýW~? @VšjYbIYo‰VáMo¹Ò šº~ê9Ҹ%Bjˆ¶·Z?’äîÄ”7úˆw µ²êÎnÎÐÎÀ5Ò(##é„Ôx‰§+Sð Ûñ‰q¨°Dè™cƒh.³‹Ãkb íÀÙÑî#!H@Ú«•: ˆäa-ÄÛFg‘œ†?·A:&'÷®)zÿNQ|È¥½€.Š'”‹í~yôhÔ x f"Ù¹$ÄK )À='­’«PqN?‚X|F±©\é®Üô$Ó:ªÒA‹¹ã~¿eÒK¤ÄETJqt©Z਒¡ŸvÁÑ^¨ô Þ±wÔFl›‘s)йöÙgÑH{âug¥mæ¾_6Þ!zŒK¨ FX©:@ HÐ ááÚ°Ó°"ÅçF«®_ÈȺCÛ÷Á4-X H º™” °æøŒæ©ò3`9Dßt†Y(§P‰fºC}Â[ÞCþD ¦è°/2Á4rFlzÑ ú> tæFê—ºÎ`„Uòib"Çv´#we7¢¼«[6o°°îÍâA†00„àAµ ™fDk˜(Á3Í`'PLp®ŽÓ)s%ÙØi\,ìÔFL‹ÖÚ¨¨4V¸d–$:Äl™ŒÇÈŠÞÔ×öeëâ¡ úbƒÁ^ÕJgغav\‰þ<‘I¾óÌÏi p3ToØ\[~%2„.Ù@}Âù)è&±Ý6Ž˜:AUë$G÷ža;µn,C‡&¼ê„útËÒùí°¤S@7LD ñu6+ÏL¯…;mž‹,’AŽ;lDÆ> !•ŠÝ¡Û¸¶+"› ¯lñ®t¾!)W¼ŠtÃÅèª*|ƒöRìì`{o¤- cP쟀Ó|DçN2%MA`! q%rR,Q·`‘i^­‹¸'øM£ L väñ61Èð]&…žu5 ¨„rPÏ…È@ øs½à…ìP¡ ú Í%ž d͆^äRÀ HÝÛ•(€]r¤Ñ”Ô ‹l'žx•¶|ïV&¦ÀP $ŠÅSlµeZîð;ú AhsŒIÉ2\Ì%ˆþDf˜ ï˜ d¯S{ (K¨A(4Àvøñ’J[!m0êêð2üä!U™ŸVTs­šhC/Œ—­RS“–5éû…àÙR舞LÎc*D |ÒçŽ {l´º"/"dÙP/YúÍŸAuÿOüi>¨_Su”‡ à!§iè~äÞn9„Š„j4%H ¨.4Ù!Ø=ElhU¦D.pá6Fv:/&¥æh›>Ä»nÔ¹ºþ]ÍNñ½æP3@]åýsþ4ÿL ¿òç¦s “ÎIŠøs½PyÀî¿‹?Q ˆ/$+2ÁQ½ž\wuùñðg¨Zz 1ú±|мŠXÀSÍ¿ö0hNŒ{QÚ©`Åñ`8®´ ¿@êŸ`AFEèDì04HòÈê¸ SCƒCñ@æ­&tT’@ù£<ŠÛhl÷B† ã"S©½µ82óá¢~#»ÞÿQAÎÚ Mþj]â~$ɉRdA;€1ý†Oó  ßáÓý;|šO1Q'!Ò¡¹§8—Aï6©Òrs÷G¯¿ÁY¥ØÆ¦«5gIAÏê…´á™Èæ”Ïè°m3:õÿSD;ôæ#µ>Zs8bg$‰K–á&ͧŠ9Xy¨”‚­A *26käé}Öèb†ùÓU { è”)nšïòr^¡¨³W´JW%ǵÑÁxØêŽæ‹š·Câ¶’ÀMw5´$ŸãC Ð6í(”‰ø¡1ÛÏõ•Þc7ò‰Hÿk‹Çƒý%@Íg„þjrIñBÅG‡vJ±»Æì%qª‹h»Å.äì¦#@ §ºÇýá®ñ;ÐÁ‰jˆ3Èÿ™CSjÃ3Û-&ýpðit2‡8Ã[©ôŠÇÎH.äÝi‹jULºœ\'@lßlŠUaí»~©¢ÍmÖJÛ¼n˜ôiô65*)D´@¤Õ•¸g¼Nßiçkkë 5¿°T8:-zC! ÏêÆDkzœœi¥’Y‹ÇU‰›eÉlÚFiPÐsÉgáz%€”jóZ×7¸P&¯† ˆW6'õ€èEæµ€K™[-~ÔKæ6dÎ áÆ 'â‰ÄÓÍI80èä¡í9Ä]¼€§’AÇÀ¨¡wWÿnù;ª.¾åÏÏò”…Cü! B¥”°§'„mœâ¡Aû•έ9¬›Ï£rŽö•n÷’¢ÔŽBM9ˆª¦Ìx«ÚŠz2$SûÓ“ÝíÉ͇i«Sž óä1R삦<ù¥U+æLªÅ…NmJÕjmUkÅ'J”T-Ó áD›û‰¨\ŠºI ª”nKÏ»;Kü…q°`†x ³yÚ2D´jEÇA2¸‡(2ªð!$eœZ T²="UŒº®Å÷kû…#ê-ÚªL*§Îø‚tTÒ•uP~ºû¯A;Òð²Xg¿øÎ¤ë öCxXVÿF¨Vt/ßJ3Hoó˜oi6í÷  é÷×½äë²4¸¸FL+ZPNP&H köK,mêf9 ªÍuÔ&ŠWkÖÓµ“<0ïÑF/>¯6ô 6æ^^%GJôM‡óhAäæI]¦D[¾&ÃÊ* ª]“‚vSˆ¡£Hù¶„¹µÎM añ×Öæ×GŒ"§¯¦xzøhcÅV+ûŠÂ~Ô»|}€‰g×&¦Fm\ûàp®DÖšµG´hx^Ò/I¾Žuœ´µo'äª=ÀšLk„N‘£gœäl½rVWaHI Bê ^Xr–ùJÎÚgý÷‘³‹»¢ˆéñ%„¾$#R W‘:â@vüÑxp6ñ §ÐDÔB¥€t1”$e¨´yÔ3Î/Éí`›qŸN>G§4x“ÖOhþ;oGsÇ‹­²ÞP™G@KÈ¡¡,ž¡Pz¿g?Z¿àûí²Ÿ^+_•ˆ&"ñªD«%Ú,•hÕ… GÑhëX®öT‡dÖLìJ%© S0;í½É»ý‚9e¬RúÄœæ;ê|˜5¹‡Ö>¢¶Yª4ÃК÷ö4ÑçÁ ”µAUä€ùúÍè¢Mk\'òÓ“‹Þ=KTÆ(û…8Í7Ìù×Äi¾aÎÏÄé<6Œ6©ýûUg7ØÚ׿ëìæ·Öîèºô[ú%1ÒVF „ظ,ãC`%ôã›8å>Ý€ÖÈ~"{e?¯ó»• :s¤‹&t$E¹Õã/Ù=³óYøÄæ+ò,7üI¾â¹ÓàxïVù‹<;®h÷}x²r­êýñ§=¬Ö{-4«—nÚt“= ÔqFä6Ia-ûX¥°–̶:[XкÂ'€8e³›®Œt¼u«¾¾L!VêäéêìÏ]ý·¦îìϦî.6íY¦ÍœFœZòÔèLÕ€{„"÷YÊ3¦g±ÒÞå Û‰--ŠÒ’mÖRbÕ¾‚Ë(™i†QÐ@Fy­œje뚎L±|qÚô’ó^›­áë:9‘µ"s—fc6ú„¶‡_k³„Ìí×νÒÎZbzhÿÌè%œwá2¸%ôgT›ÂŠîj+IòŸðÅ×Ö‚¤–ŽuhEHb\ô;~ ý;É 3Ulœ–åu>€F GƒX(ökб…¦ÁãxQ{ÖÊX{ÚóºÛÄw¡]û´Zio%îì.´Ó´‰:ü›¨¥H‘ÑÕ0]Ú\˜ðR{mæGUj0a8á=-Q<Ä“ë©-j±»hƒ*8ìŠI»ÂkõyùeFœMZ¥¹ƒ÷Aq 5´É«A\Œá‘â{ (i‰ûn’ÀcóVÁ¡˜ ™¼½âî¾:¢4ÙÑ¥ot_JÝ qxÁü; ;c-"A°¡Dñ=+-®‰,Є´] ¡Ž2×]ÚùŸ4å``Ão h>Q CùÃ&w¯° ¼w7uM[2£MÜ©]ø{<¤5þ{‚A§cZ»'JÐE%âNÊ=P™µ3ÛW25þÚÃÕÂë øïÐü%†aþoSŒ¿ Øœ¿ðþ¿æ8Sûܰ‚Ñô{€Ýï~áw¼O'b ïq ÒëØ€ä9VSiŸ´+.¼Ãë|âέ”<žS;#/¦¬S;ŽÙ‹]tL…k/5IyŽ(Ȉ{DÃõ :Õƒ½ýl‚A߀t°æ9xDŧ׹#µ#|O‹ÏÁ#|x!btØä¶íÆ à®´–¿R¦?I¯µ´Èг \\·4y¸ÜúŸtÉÉOS(€÷3ú¦Ðw WÝÞšû8}2ÔÕÒ ppŒ){ÍãÝ]í½ý{¦ÙßÇ}rÉ݆•¤œiTXtXML:com.adobe.xmp *“KXbKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEå íL/¤³IDATxÚíy”Tյƿžªšî®@FB‹ˆŠ€¢ÏL¨OÁ¨¨K—fÐ8&+&fð׋1y>3šèÊKŒÆLºt™#´ˆ1fE‘4ai¡Ç깫ºû¾?ö9U]·kºCUÝï÷Tuõ­ªûÝ}{ûœ³@!„B!„ì'Gÿç‘g·0®ªpãÅÉáéÉ>v”–0»+¦ïO”þ5ÕJÿ%Ô?Ñq~Ï gR¢uþJ„þú¾0诜}xõ÷€þ¹<%„Bˆ‡+šoý|£E%ù€o~v.3Á, 0 ·öÔQ3üoýbƒè_\@ý³×3¦UŠÃ7©ðQÿ,Õ_é:cš8|³ ¾O å‹þ3BÔ?‹õg€Ba`¤cÈË—áÛæ3Ì ô˜ž¯+€d2z1ëë¹Ô?ƒÐcýíí½¯èQÿÌFõ¶zDÿ+:º ©åoÉ\ýY „BX0wÚ œ4®pû§f2#LC"3÷d3øÈ rXÿš±Ô?Ñ•;M²<꟡ú«ÊÍý¬àDV5Ár™C2;ÐJý³@V!„Vâwy€o~îf‚.b–©'ëüãÍ(‡õç,qWùÁï¶ÐÕ„Οúg˜þ¿×ú÷à ç‰YEѪû qWV!„V’¯L›â\÷É©Ì VfnõX],'8í”Jêï ÷=úOãÃç?R«çêPÿ4Óÿ1­ntý-ž«ë~süš[ýãSÔ?ƒôg€BaÀœXcÚ Ê¿_½á,f‚²½Ìo@aG[\¯·zl.ÖXÓý¯?›ú[È÷·E­ÊéÃhÎß®¹9Ôßmý7‹þ~Œæüìš›k®‘fÐW8=ØOý3@V!„Vbkì1òy®HXcov;ÿúÇ{¡?g‰§Ä×~ü9ß&ç×éU9ÔßaýyCéŸçŠóOõ~tìÝ&ÀÇΨáu†ú³@!„°`_%`\u àóKOc&8 z¬§ãð1ÀÝ(?~hÔßszn¢Np|õÀ-—SÿÑõ—±þ¦féÀ¯ówzõ·7þ›Z´þñ9?§WaÄ\…4¦ ð¯ý à›.õOCýY „BXHÜ©Ä;+Y£Í×oâ,á£ÇzNœ'9oe=­€Kþ, 8Ðö{nͺMtVjä÷úúÔ^ÙÚhÀÚõ{£ÆI¬¸rkÕ õ·†uÛDÿ5ë÷D=O±Î«[«.ÌV%õ–WÖýq@ߤ©Ô?õg€Ba çšà,åH‡S7­ °ì‚ZgÌ®zî¹Ä•Lô¡§6©ÝÖúâÊü*ZŽ?|3À×Ý!çÏå^܉ÎRüž§*ú/õªþíýI9Û«l¨¿3ñŸ®«,ô\€À¸É€WïùyX% ]+AÔŸB!„·+¥cd,ûΫìÝgü{ ’ùµövήœ¸a²3NêK?ø›tÔÊÏK*óóïß ˜uÍ¥Òg}mªN°´Ä§ô?=+õ_»å¨]÷oùÞyyíü©rú¿´n7R‰ÿtqþ‘Üÿ?5`¨¬‚úgþ¬B!$ߪÕ¨uþzýòpf£2—Á¡¨Ï‡ÔóºÇøOŸÛaÀ—¯ŸmKFv´Gf­åÚÚz‚xb£ëíµ$óÓëiÓ­³VM•Ò¿%RÿÜúŠþ=Á¬ÔÿÛ¿|ËRç¯ûi¤Ôôø·Êùé~ éFYíxêŸú³@!„x˳,= Y‡3üz•¯‘ŒçúE§¦ôYïw…¡¾° °8WÆžN)‘Y«7O_Òû¬yûˆ+Ö6„}¿T3¿LY?kÖÏ Ñï©òøqJÿ‹2Cÿ—7‰þ«êw‡}¿T¦ôÏðºþŒêŸIú³@!„°:©v63«èŽGÉνmóÓ©Œ/2Ôï›}qRÇÿÖÏ¥7zS[¯'3Mª­Ìœ@Q‘ü{Ç•éªÿšÛz<éü©?ãßÎJõ·GV!„V¬ÃªNg‘•9}aù¬¸>ûÝÛŸ7 7$³Lce€Õ…²‹Õ­3Îõøk7¿oÀ «e]~þðçóvæ?Bÿ;]E:ŸÒÿjwõ_ó¶èÿâK»”þ¹¶8·:eRÿôˆ·:%RoèÏ !„ €õÜýƒ× +Qd&UX ­ >E]Øw©oÞcÀ3þ–áÅÊõÏ¿2ë“QÏÍwÕºÎC[3?§:cÙMªc9aý—9¥¿¬ë?ÜØa«ówª3&õgüSïêÏ !„ €õXÝݬ Ñs¾¸í9:z“Ê«}²þô¤®I€?¬|7ì}ìÊüôù±«–ÓXÝÛÌ ëµµúWú¿°ò½ýíqþúûQÿôПñŸ•êÏ !„BÒ¥ Ñ=ÑÛ½ŽTŠüò¸iÒÀ¾®æ¸2ÀS‹¥§õÖzãiiêgæoVï‰Ë ùå46|01ý‹´þ2ÆßÚ¤ó÷’þŒÿ¬ÐÿõÚÎ)ŸLýY „Bˆ+Í]­7ìtP‘™W¾Ê 7Ÿü6 $WfWûrdö¨¿@ÆzJšdýçÖõíQ?—Ý™ŸU=¯Ó;zÕ°ózU€Æ®J@[@útõ™ù§zVð ýqû´Ñù{Hÿ¶vÆ?ãÿCñ°Õ“ú³@!„°à>õ[ðÂÊ÷`G%`IÙÀPO@¸ð‡Æy¶d~z_êq>ÙmjÙ¤ùò9ª§ÓDá¥ÿV¾ +@y©üü?zWˆþÝ*ãÏrJeðW{Ïô¥–8ÿ"¿<ÞZµú»¨ÿpüûE‡ÁãÆô€Ï).ü¥ýã–Æ‘_dÞZùõOý5—ÖȪÃÕÏîžnËý?Ýõg€BaÀ}žþ·¬ØY/=š[›ƒ)U–MÌkðÈÉøze•ÁP¨_@å}Å’éM8 °ªãc)e~úqë qïu†÷šöûdÿçGϼŽN šþ¯Hð–¦Ô:µ-«Þ8°EôW•Ã0”þjw°\ù7·Ô/ï3E*B/5ÍIÊùç+ýÛ꨿›úk.ËW•Ÿ–#añC­#W×An‰Tê &Ÿ%ú·ŸÇøÏý—VJåwðƒõw Sé®îÿ…RñËõO¬îYâ‰û?+„B+Îóäî7 è õ…=?Ñ'NlÍÓÇ¢:ýX•€ªÉ?Ù÷¼düjÌw ¤^aDÿ@…%r¼é ¯ô~4¡ÌOg¨›'mJè<ÔŠóxèŒ+<åLõ/ý_þ}£‰þñ9e¡_‹Úã1.}C[wÉü•xµôs‰9­-õOý¯,_'aXÍ) öÄçŒÆV6N¼Ð*L(þÇΔûÏß:·Sõ¿ªJæ`…Tý=£Ç¿Oîÿyã§Jü,OêþŸ)ú³@!„°`?¿Þ³Á€c½¸^ïoQ™øú–„*×VýMeþ2j̯¹I*Õ5Ua™ß‰ç+%3ª:°¾üó e~ååù ù2ÛxȬÒƒ‰%’ÿWÝ’¬r‰ê_Ò"™ñÖõí 9kª%ó8¸U.tå0"uÖ!ÐÜÔv]ä–VÈñ§Éðk=Äåü§È”¼Üºú»¨¿fyî³¢Cëû ÅNžôlϯ=Cœœïª¸âçäw”³Ê¡þé ÿÐoD‡Žæ8ã_é_"«B¦Þ h ù³RV!„V¬çÙC[ hh?šÔï县"ùi“OR˜ŒÕ†egäîNó— ¬EÞ×0y#ê)É)+ï?[fƒ¾Þ1gÔ̯Hg u²Ê`kçAKÎ_•šzïÌÌtVélœßö–P\Nà†ò5€Ác{DÏ`œ—¾ºÔ\|5ü/Y>4~ ©ëOþµ8–w¨¿-úŸV+ý|¾¢Qãÿü·ý;׋ªÝ&qŸý±Z’§*oVßWüÔ‰³ÝÖyˆú»ÿ7ÖJåop¿\F_wœ å:0 äúÊ?©°¢ÿÒ¬ŒV!„bÛæÄßß%=·µHé8½CâÜæ/,ƒ8ÿ¾PôÌ?TëzÕ:oÊ‘ù›8Bµ>TwŠ2Ëüu&ÚÛ'cÌ[WKOùñ‹dgß`(©ï]W1Qœìäs22ó·\ÿËOlúSøn‘‘ûºç*=rr ”޹£fú¦~@é¯;Eêžñ!³ëN9ƒM«©¿ úŸ§ô6Åÿ9Eya÷‘ñQã_÷‡Ð÷Xñß×'ŸsÛ*©Œ[LýÝŒ ô)ùÑïóf×…ú»¡;Efkü³@!„°`zÌâ{ ’ íiK2C‘hCÇ^À¬ÐY£fþ:Ë#³9‡ZÕ“Ù¾¦³@ÕØ‹î ÈïÕûÆÊ§6É,rTuÄõ=Ç«^ä7O_³~­Öc‡ŒåϪ‹Oÿ¼±SDÿq Æð*€ðÙþ¦³ÀUgH½G„Ï$RôçÐNPQRkõÏi—ó×ú¿Ü4 °°øMQ¹§Ã$þ5þugH½G„Þ-RÿDüEÿº&¹¾ÚªZ¨¿úWç‹£ž9cLtýCJõ|®šÅŸ[ ý†ú{Š]9Ô{Døºó²2þY „B<ˆãÙæýï®0 ©?¾ÌècÏtî*Œ+ó×`Q¾db4þR2ÀÎø2qÝ *¿ötÀŸ‹ÂŽ«‰·pé§¥£ÜÑþð ¸TÍ2½uÆùžêüå”þš‹B/íWÂÅè¦;AN9ðbË…ÔßEý5sÌOJÿÅÅoÈó{¤ü‰Np&·Â|™;’;VœàkE×Zz £ê«pÉMRA8¤þ)éx~\Î?¡ÃE]Ò`°Mõâ^ dÿú§åã+ nÎêøg€BaÀyîÞþ¼mÁðuš§•Ì©r÷”°L?ÞÌ_gf—Ul”LJ¤CÓ ± ˜+Ê­šxiàŠQ3Íx3Áª9î¬Å2¦|ÓGÎåî_ê?¨Áå%õ¢¿rF—ºÔ®€Å2Æœ§Öý®j]@ý³Hÿ¥e—ÇÿÙƒ½J~#,þsŠewÞ¤ÙâÏ ;^ÈÄé›U*«eÕÒ¬%EÔ? ýý S”qJÈùßÿk¤ÀÀ·%þ»Ä‰ç ©YþêïÀð®°jî@¾ª®lžŸÕñÏ !„ €{Ô7ï1`åÙEmN«dÞ}mFJ™dÆø©Š×%óS½¨õzñ¼q’iÖ·×qͯ]&=ÅÏ™Hà¢þúõ7ÌPsdö®ž5žèq¨¿=úJ¥îã‡/´Eÿk'ˆ#ÔëÅõ¬ñúŽ1Ž“\%`ù2™S´„úÇÿ-g«øOÎùÐ-(:_Y!sBŒ.ÙeVWõª±e‹Û =ÿ¬B!¬¤ÿ÷§†™dÆVZ"ctþŠKk– >ùÀ:€4Ðê)•¶^WÔ?Ã⿼$1G™d%à‰Qÿxô!Bÿd¿‰NS§øÿ¬B!¬x*ó׿W^*à¤qŽd‚“'ÈXãßv€‹ú×M«“×õÏø·ÈašUj'”)ý¹À ç¯u™1­šñÏ !„âMòÓåƒüjeƒý¡G32Íðn_ÛÆëãè}¦5ú} r£¾Þ—½wô¡FY}°vóû\<÷d:ô×»¹ ÷ò¦þÞŽÿ‚è^(4¬³™þyÑ_Ÿ]ÿòºaÍÛ¢ÿ%ó¨?üjE„þ69Æ?+„B+éòAÜÊü‡\©¼°z'¯>õthN;꟦ñïP%àÅ—vQôhúÛìüLtñjü³@!„x×ÇŸô¬_§3ý>¥Ò£{f݄诳ùsÕø¥GôwîºÀ“cné?w¶è]\$úÇ»Ï<õÏÒøŸaÿ6;Òj‰Ò7õW³þrþ‘ñ_Täótü³@!„°àÿù=úúÝÉü«d€ù—KG¨Ò~Ö¡³\ɯ¸Xv¡»dÞ$O8tÑÿ<¥N«ì8:Dý=ÿÕùcdó8Ç+K—Ì\:ßúÿâEÑ¿¿ÐQç?¬¥L›¿TÖåoèØëÉû?+„Bˆq|Às¯î3àØñnW2ÿ9 ¥ãWO¬Ç}§ó Ê„$ñ;³ÐÕà Ëü잺bmƒ'.¸tÓ«Ò?˜/³{&‰þóŽÎ£þŠÿ ¡ô¯ýç¾/úë}èí^°ª~·7ô_§ôoêvÅùŸ·° ÐVÓØÖyÈÓ÷V!„âøxÓOŸÛa8™ùWÕȾÎs–ÈXϾ^ÙºÏz‡‚aûÔãSK¥WtÍû§Èó6íKù=ü2+ôÁ,íŸiúo ˆC°k_zêŸæñdŠŠ‹ö¥á`ýå¢ÿ·o?7»õwÈùWVû”þ²þ>ÞÿY „B<ŽcsœÎü¯]vàƒÒ#€£ým }Þ÷:e•퀟-¼>8±nÙ®1¡¶ö^ÀÚ-G¥Wô9³Â dªþã|â¾põ,Gõ§óO“ø¯Rñ‘еnÝ®9m,‡œÿòe§Žiýƒ¼ÿ³@!„ÌÐë=»z‚¶fþ±öYþÉÎ×dÝqĘÙ~|ã”–TO;®S»—=öOd´ þÔ?+õwh÷ºG¿ññ ×—èßÝo«ó¯P¦ô?—ñÏ !„B\©¬úçaþµ¯ÅÖÌùå³ÄÞWùÉÝoÐÜßWX\ ³G=óº¸Î‘]=ÍýåÒ«üþ[æg” þÞÖ_óÃg¶žÐߦžöþŠÂŒÔ¥Šÿ†½-¶:ÿ«.› ¸dãŸB!„¸[°+óOu÷¤‡w¬5âÉŸ˜{SRÇ·«Çù% §=!#œõ·VÿÝóÑŒr€^Õß®÷/œX<'Câÿi­zížÈû?+„Bˆç±¼€]™¿U»%/–ÙÂ{š£þ¼¦°,¥ïÇ•§ç#{žß$׉®Y¿ÇÓÎÏëúí‘7ŒL¨x]ÿ;¯RúGô¼?¡gr}֮ߛño“ó·j·DÞÿY „BÂøwðþÏ !„âARβþ÷·›TœŸÛξ¿«Þ€{g.qôý­ê”çö¬pêŸñΚ/Ȭ勹 P~ü8öóÀ€à™=ýÊ}¿´WM¢þ£`U§¼}õBwãÿ7[Œd>÷°þ.w:ôúýŸB!„€øùñsÛÂ;^eyg»tq‚‘çµ¢\2h§g…Sgô/:²°ð‡w„U4ýe2vyfG›£çñ=_¡yÁþ°ç{Ë«/ß÷[@GIeTý3­³¡íú'¹~¾¢¢HÅ¿³«~üì;qÆvt6ÌÖû?+„B+±yþµýì=ØšóK×õËéF²ë©þÒŽœWêïŒþÁMo.üѾîŽQÏ©¹o\s‹ãþøÔ¨¯ Œ› Xñ¥Çeµã©$»žþỎÿm 9ÿtí_àõû?+„B+±Ñ³¾3e–z¦“è,{»+ÔßôúúñgÔ$ô{vWô¬ÿtùÕJõOobͧêÌÍŽo×\’`üÇ›Oµðà›Lâßž¹ÄÙû?+„B+±ŸUcËÄZÌÆêýåÒë+7œ™nÔ?³0«OÖ©›9Žõ§yüGŒÕWTîI4þMœ¿Us HzÜÿY „BÁ»@÷¼õUïŽ^ýwFZüšÖŸèÌânè¸ûöÿ­— Ýôž½úïÌÔ;š:×õ}ÈoÚÿ ྗüÐsf_ÐìéŒt ÍE{Àœ ÿÚü'lúïŒÃÛqÈ0ÅàÝóÐÐíúÏßúo‹Ï«ñI²Ÿ[û$yÀm ÿž¸½·<ŸÆí¾ny^ø4ß·÷â–çÓ¸Ý×-Ï ^ €TuªÊ’!©3?ÔJV¤ÎüP+Y‘:óC­dEê̵’©3?ÔJV¤ÎüP+Y‘:óC­´žÓŠ?ïK5hõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TKVÔœ5dõCµdEÍYCV?TK#üü7€ç”’Cú×HäŸB"ÿù§Ìóÿð zx“ ¼F9/å—š9Eèj~+”“üS('ù§PNçüï€P+¿:ž(§TÓʯNõK#džP$¿:ž(§TÓʯŽ'Ê)Õ´ò«ã‰rJ5­üêx¢œRM+¿:ž(§TÓʯÎo }ÖÄé瓃*KÊùˆš¿©=<ˆÂâŸæ·%s>â“5™óß1ÿ»@‹ ­­Ö³(ɳ”MÕÇ÷i~­¥Q¶Ç÷iþY”äYʦêãû4¿Ö‡Òƒ(Ûãû4¿3™S‹Ì¬­ÖÎdN-2³¶Z;“9µÈÌÚj=Ë» ×ÚjŸõá)•¥Ì©µ¶ZÇç‹_!¤ê ¡Ì©µ¶ZÇg}x …É`R-i«u>–¾J‡RuPæÔZ[­ã³>lHÍ©µ¶ZÇg}ØšSkmµŽÏú°!5§ÖÚjŸõá. €ÜÊ©¾--§¶rªoKË©­œêSƒ=ûij+§ú¶´œÚÊ©¾--§¶rªoKË©­œêÛÒrj+§úƒ\éHÕ÷DikN9Rõ=QÚšSŽTýq¤g³å”#Uߥ­9åHÕ÷DikN9Rõ=QÚšSŽT}O”¶æ”#UŠË M“ ¼FQ[N™ä_€¢¶œ2É¿Em9e’ŠÚrÊ4ÉÿjdÐP˪R3ÝPH©EU©™n(¤Ô¢ªÔL7RjQUj¦ )µ¨*5Ó …”ZT•šé†BJ-ªJÍtC!¥U¥fŽðóߤ懦©æ‡¦©ÜÖR®mI5?84ÝH5?84ÝH5?84ÝH5?84ÝH5?84×óÃh˜„Þ“ÉŸþ<»5Ùí¾ny>Íà}/ €¿ Bÿ×°[ŸÝîë–çÓÌÞ—pèÿöl²Ï­}’¬dðÖ €Û@ÿ?ÍÎnwÏÅJBô¿ùŸ†p²ÿ¡V‚'´ùwv í2r¨#`܆ì?oáס«"û°¸ëOôd}·Aý—x ¿ˆKK…º±²!:ññÝKZÙ|ÀmPÿy¿‹ºJK++{¢³Rk5G=YÓ Àm ÿ‚–>³²'U­´-ËZqaËbÁ!ô~‘kþ €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦06…°) €Mal `S›ÂØÀ¦0¶äûûa"U²`¶ˆùIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/dat_128.txt000066400000000000000000000002551474050137200241260ustar00rootroot00000000000000Obj=symbol name=CompassIso copyright=FrankP Image[0]=> compass-iso.0.0 Image[1]=> compass-iso.0.1 Image[2]=> compass-iso.0.2 Image[3]=> compass-iso.0.3 -------------------- simutrans-124.3/themes.src/pak64german/files_large/divider.png000066400000000000000000000002761474050137200243620ustar00rootroot00000000000000‰PNG  IHDR@@% 扅IDATxÚíÏA €0À@†[2ÏðDƱDž¤UpóšÇŸ÷skÃÞÀ»–6luj@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐìöm=ÓÃÞIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/editfield.png000066400000000000000000000011721474050137200246610ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPAIDATxÚíÝÁIA†QW¼¤‹¤•€Åĵ„-!ä"–a=zK WkÈ' ïUð3û1sÜe=­çëåaZo/¯£'üƒy?Ár۶јØãèÌM@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²¬§õ|½Œžq¿Ï÷Ñ’ãóq·?Œ^q?7‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²Ü¶mô&æ"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€Hž~¾¿vûÃè÷ûÛ?zB5õùûÙ ‰'ŒD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HDò * ÷;"0 IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/gadget.png000066400000000000000000000027151474050137200241670ustar00rootroot00000000000000‰PNG  IHDR@@}g_HgAMA± üa pHYsÃÃÇo¨doIDATx^íÛë/c[Æq…¿‰D2ÎA]Â&.Í$ÇÝa´(Æ¥-{"^/$âÍœ—çÏpžZìL–’yÑ9Ö¯ù®|ÒìînɳW¶ýìÕ1eÿ>>Š®¬ŒìïÅü@ñýøç‡x;Q\™Ö^nxûQ\Ì/“[{±û”r=?½ ïS(ºçÛÍËð>Eq•ìüêÒ™šš:>>Îd2ggg###\LÂî´sÁ|M{4ÊËËŸ·ž†wd€~^{9Þ(®Âׄw¹xoç´«««çç烃ƒÚŽÅbÚN&“¶Î¢hÂûûû-N»Ý䎒¿_pgh”°««kaaáòòòþþ^¯ÍÍÍ•••&’¿Þ1†<ŸÀÓð> GdŠ›J¥Òé´Ë­×™™™£££O㨮½ÜÛD"‘Íf B ÐlollXœvežœœÔmÔè5£ØªŸÃ¿Þ,…Tc©·Ô^Ú0Ñ^ÞÂ+âf‚f[cþïùä·dj)¥ ·Ç;,2)h}}ýéééøø¸¶UÚnooóÞ’Ÿï—ÀÚëîîŽöî){á2¥íééÑ HC¶’;Ê<55¥üñxÜh~µ¯+`7T†úX9U`Zé5üÌùù}cxG†O™çfæÄåw#³•ÙËíiÃ;øÃ¤ UUU›››¹\nww·®®.Àè¿(?û™ÌÀÀ€•SPÎÎÎÎíímM¾ÆáááÁÁÁÞÞ^oo¯¡S½ººzxx˜ŸÏ?¾y„O™õÐssssww§&3t Šê†û N½¥pC{´ß;>LÊ©änxfoÉåñœ¦:Zoi,%–ÖRkÏoÊÊ6Ö‚û6åÍ4 :==}{{»²²Zè_§ä‰DbbbÂÖ)(­²Ù¬æ_÷ ýýý¦¦&C§ ¨ºïììì\\\˜.0=:œœœXy€SH7t͸W WcÑFyy¹÷SRx-]lõnÈ–Ÿîw‡w|È”vm%_Wnûûê÷­õ­ÌÎáÞa´s⯰£(b<Ÿ_\\4WŽ2¯¯¯kc4|EEÅòòr:®­­5w \]]­ÛƒŒÎÿðð°òëj+¿Òº¡Ærw ·ab¦„Þqè­Â‡ŸÜ:Ípô=¡^sÙÜÖÆÖjj5ùíùÏßô:ÐÖWY¢(ŸV-¹\®±±QÛUUUÚŽþ¦ÃŽÅbCCCæ’;Š­ßÛ––»ùU½¶¾‹(s__Ÿ•¿zxM±£û¾®Æ´á—¶àðŽDÑi’—“Ën¶5¾Æ¿}Éß?Ýhý£U¯Þ|¬iòA[[£qÑkCCƒÑÿG¥ÌcGJ MMÅS°›ÜQroÕòzOàU+0CKƒ&|nvέ´¢ÑÔØk‹iÃ;øÃäB¿õÖ eÞÝݽ¾¾¶¾dØ|ӗ¿Î_pg°\Z o?~77íŸ{>·ýÙö©ù“¸=Þa!(å‹C3®u¤ûÏÞGÂÇoîÊWÖËð> G‰_Ï>€wðË‹÷q}L¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0‰˜DL¢À&Q`“(0€IÀ$ `0èññ?~C¸e‘ÜïIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/gadget_new.png000066400000000000000000000035421474050137200250370ustar00rootroot00000000000000‰PNG  IHDR@@}g_HgAMA± üa pHYsÃÃÇo¨dIDATx^íØA®óD…a¶Ã˜=Á°6Á˜°Ä€!Køÿ XƇ¥ƒ¬ÃiwâäúºÊÉ+=£¤ª}Úî¤$õ÷—/€&~øîëE|ˆM 0h„¶ Zøëÿ¿­â+lb€@ °G1À ˜^º(À&‹éµˆlz»öçÿ~Ý)”‹éN±H+þÚÐE61À¦¢@¹ø‘î‹´skeØtg€Å9XDÁ]Ѿˆ‚D€Õ¿ÿ¢` (¡ßcüloèüûw†!ቶqÜG± €ú=ÆÏö†Î¿ß˜X!бi×ó£ Q¶Éë«“_Ýéó™(^èóXŸj}Mî|·<ïÉŸBüHƒWÆ"åâmá¦hÁ&؆(^èóXŸj}Mî|·<ïÉŸBüHƒWÆ"åbVmŠlzàâþcá5µ‡IWT7Kòh=>ƒî¶‹‚i8?…ø©.üÛh,ï oˆÆ&üÞîí‡c€}¨ŸAwÛEA‰ˆ´ˆœÆŸBüTþm4–‹)uC46á÷vh?Ü&èöñÏ;&¿ú(Šú\Éݬþ³éºÇŠK´â9kïühL%Qö’|¿'ó$z"οÆBñ†ð®h/ä÷ó—Ÿ¿}ˆ÷Ʋ‡`€mÔ+¹›Õ6]÷Xq‰V %Þ î‹”М ¤=ÆÞ¸Ä1Àþ¥œJ>ªÚ…®+cžÛfõq‰&<á˜<ŠK̲I¿ßø®£¸„§r}JL¦b‘º“ãÚoìK|ÐLÖd ?.³O¢½!åTòQ‡](ƒŒÙF³šX¶ OØ9¹çéœóQžfÜo,RbÌ&}Æ[Á‡ÄR'Ó=ôÁ3úñûo>t£ |Æc€MÒaÊ c¶Ñ¬&–mÂvNîy:ç|”çŸ÷‹”³IŸ„1“KL÷𘬙ãÑ‘hiH9gù%Z yªYæÙç±Tžp–\¢±DDZÌ2Gc9Ï6ò]ì¡®¸D‰Yþ ýoý9±àÉto0‰Ø«([0À¦œ³ü-…<Õ,óìóXª O8K.ÑX""-f™£±œgù.öPW\¢Ä,‡„ñoþ„Xðdº‡ °¦”ГËU’‹gž}íM(›ÒŽ™GÑ^""…q/Ñ~šø žó9µ»sJñµ ãMàÓbÙÓèîÝ]q¨6EËêØ1Æû«$Ï<û$Ú›P6¥3¢½DD ã^¢ý4ñ?<çsjwç”$â-jÆzZ,{ݽ—`kŽ…—Ù'ÑÞ„²)­ëœÙ)§Œù%ZZQÂYòQ´—ˆHaÜK´ZCnòä{¨+.QÈwQ›-þÁ?(?™îäsc,ÊVÇŽ.a€ýGçÌN9eÌ/ÑÒŠÎ’¢½DD ã^¢½Ðr“'ßC]q‰B¾‹Úlñ?þA±øÉt'_j€­9~\Fã·±T9¥RN×3í̸‹+æ—q.KD¤Å,s46çÉgÆÆ"…~ö{ãÄÛÅÍ]7¹x~™ž'ÇótÎyß—ø~£¸Pm¶˜:Š •Ðý‡Ð~co\âƒî °5LjDñÊköwáù Ñ™ñ“Å%fÙ$Š_ŒïT¢ òèO¿[¶× »*>öðÞXö 0´à'DgÆON—˜e“(~1¾S‰‚BÊÃû<º«óé.ïe±k€=÷sõz_!Ê€Õz`ÝÎ̘J¢ 'ÓS`€Cwx¿h? ¬fÑíÌŒ©$Êp2=Ø9t‡÷‹öÃ=ð Q¢à®h_DA¡¶ˆ”ˆ‡²ˆ‚i(¤âå1Àšf{gñPQP""-¢…`ïéÎ{UúÒë ÇSz}žH·

ÏŸç¹ëßîŸq©Cn×Ã:‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€H^Ÿg¼ºåÇÏ·Ó>~ŒÝ" eZ6ö8G@ËÆçhÙØã-{œ# ecs´lìqŽ€–=Îв±Ç9Z6ö8G@ËÆçhÙØã-{œ# ecs´lìqŽ€–=Îв±Ç9Z6ö8G@ËÆçœh<׈D@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"y½ÿz¯nß.9çùïF·œÿúgÜèa$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‚çù á“|+­AwIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/ls-symbols.png000066400000000000000000001026041474050137200250360ustar00rootroot00000000000000‰PNG  IHDR@@ÛTügAMA± üa pHYsttÞfx…&IDATx^í\×Úÿ}ÀVÊÒ{ï½IUéJP@•ŽŠ""ˆŠ° *öÞ{ïÝh,±D“˜fúM¹iyßþœÉܹ% ˆ»òü>ß»wöÌ™3çìΜoβ`¯¯ÿüAdc ¿¾ÑQƒR“Sr†¦'¤•D%F%„±²¦*¿;¹¶)¯tZXd*Õ‹ëýüh Ô $B'3]-¾¹– c sCetî 犢þ[V-Ÿ3ll–÷¤‘Þ›–¯š“ž;ÐbAuìÒ©q‹jâ×Í:»,xËÒÌÃ뇯_vjWMSu¿½«²·.Jž”åÜX1¥Ð¯$ÅfB–ó¨XãÙcóšM+ ž8Âmtœy}EdiºCÁ ëYãÃ&L²+Hsöµ ècl"ÔPí­Ät®woè<5¹ðàÕdÑ¢EÄ1Ìó®iŸÒÍ À×IBjѸ©ÍÕ‹v/[âȱ›k7Ÿ¨žµb´¦ôüÉ9U5“êO™³vƼõ ³+g,œ×|àðÅ£'®î=tiåÆ# WîÍ/žNµÙ)ÚDW¤èh`áê '(LõXVŸ2&ÓcÑÌÔÕ9M³R˳=V'íZQ0w|ßý6ÔÆ¬™¿£9kV±ÿöæWŽ×ÝRrv_Í–ÅÉ—ŽVŸÛ_¾a~r㔈Ú"¿É¹^%ƒ¬+s<ÆÄ™OÉëS“ç[4Èjú˜àñ#Ü&æxÍ\>Ò|Žw~ªk|ˆIB¨¥!OM ¨¢ÈtíÍXͱG]Naaa«¿ZÚ_[ªÝåö©á Ý y= Í­XµåÄÖCWç4ïY¹ãÂ…ó7v¯[¿vióòÆÆukV¯^½ræôY3+§-®š²½¾ngÃì- µÓj¦Ö6Íkœ?w骵»wì;¿÷À…ý{NÖÏ^70j¿ƒ´/0‘ºº&OUCE9ÜßzXœÛ슄ÓÒl¿¥õ)ÃblWÌÏÜÐ8|~EüÒšè]«‹Ïì(Z=1ìXÓà£+‡mžŸ²dbÈñ-¹—Ìܹlèç÷÷¼u¨ìÒ¡Š ûÇ\=1}Þ„]«FŽOw*J°š6Ú¯¡4hBŠý¤áî³ ý'u®Êó›R0.ÓuFYßÊQ^ÕEþ¥™îãs|\MVž…®Xé ¬=P`=ÒÝ”””mÝ~øä™ëÜ{pçêÍ÷¯\¾~üðÅ-ë¯m^ûÑñœ¼óm+nmXtgÃÒ‹KæÝY×|mÅ¢“óg˜]¹vÆŒaI#LÍ=Ò2J'—MYRU³£~Úá% GW6íX³vñ…­Ë·Ï™²{VÕ¹yuçæO}{YíÕùSn̯¹PW~læØ]ÓKæ—åŽ*‘šy$$g×VTÞÜ¿ýÚÖÕgV,::gòžéã,¬_ß¼vBE]QqubRö°Œâü‚ÊÜü‰Cs&ø¦Pgí ¢¦¤äl®îc:¨¿íŒ‰‰³' (0:ÅyÞ´¤¥3×Ô^;6lsEÿ/.MýáBõ£ÛK½»ä·/·<¼×ðÛýÅÿº:ÿΚì¯oÎÿვ·ÏT}ygñý‹5ŸÞY÷ÖÞ±çw–¼½«lûì„ÓuñûËÂÎÕÆ^š6ðØäˆ•QWeœ™›º­4¬zˆCQ¬Åìq¡9 6ÃXÌž>¨¯¹•XªÆSíͬÁP`퀓AÚª‹l“ò™Ûn³: éÖ¯ÜöÖ‘³Û4Z¸àʪå××4^Z=çôŠÙÛjÇ›3ùøôòwV½×XùîÜI×gM<01EÞк‘é“Gç”—Ž/,ª05²—W´iþœã«š4-Ø¿°®¹rB혲œõÌú© ݤ&!f¶QÎ^)ƒ†V&¥M4¤<2zÕ‡gÒŽÀz÷æ)(êk¨Ûh«÷õ2)Îôi¨NÙ´4¿qFÚÔâ°IÙ~»š2ö5¦ž]šýþÞªÇoûíÝY¿ÿ|îÉ7žüpìéow±ëß§§þz¿ñ‡›³¾¹1û»{‹ÜZúéÅÚ{ÇÆ¿{¨ìúæ‚;K®5¥_šóÞüäO6¾_sFüW»&¾·zø‰É1‹2=æò?Ô5/Á²ªÀoüÏø C{] 3¾†º"óEÄ7C`‹-¼Š´úëÕ¶O y¬™ž§.¶¶ÉÓŽ€“à†éÕ«Xúð«¿:øýïîóáѪû+‡}¢òÛU÷æútñàÕ|Þ<ìÁ²ÌïvŽûvíˆ{ËFµllPM†Kù0—š’ ¬–±¾ÒÁ!R±šó=Ä7C`rj8H[ˆ¢`£#êânwDc(0ù€ø÷Ì7ߺiÓ¦%K¶Éò$`WûkÑÝ_ƒD·LFUërvo;txëîã[¶žÙ´ùäŠæ#óëo¬i>»xþ¶éÕfTÏ;º<#9/2lÌ øÊ¬Åq)iA±Q¾Qý‚ã]|¼œ=“¢âJsF.ž9«v„¡ý¼ƒú8ºEEY;„ðô|ÔýUôÝCS]û¦‡$hÛ«ë÷臻fx¥¸yÇ÷ý›_kG`*½$*jbÍ0WýÜdײ>yƒ 3¼2ã †¸.(íwqËÄýÓã¿<8îÑíY?ž¬zúÛ'O>[ùôÑ'_ïzúøÞ¿õÇÓo¾ú—{Kµõ×OW~|ºúÇÏö|÷ÞÚ·üò`éÃwê~=5þ»5C?žõó¹Ù_®òÖ‘¿©øiÛèí*»05n{Eÿi#<§äùeE›•çøLéâ ÕRQ{ó¾Fÿ*B~OëU·O áBR×î[ÿyú·CÉ4dÉ`¬?9;J6ÎÞt¼ßcA" "Bªµh Žÿù‘–!ÔI»³{N¾³ëеÛÎl\½¯qÑ®ù ÷.Zºx|UMvÉðè!1!Q~>>Þž}}ƒCƒúõqëµ¢q]DTr@`Dְܼù KçVWOÌQ•3|^Qî–é‹+'¹Ú{ÛÚY8õ3´ïoã§kŸïÝo˜žM´ªn‰sDRVÉá%¡‘C’¨^qiG`êŠJ&"¾—¹N”iBˆIAŠÓƦ¬-ËFO+é;|€meªó‘é±·Öæÿë@ÉÏç*²øÉ—»þxúõÓG7Ÿ>¼ûý§w~ÿñêÓ'Ÿ=}xûÉ÷{~º>ïëó•ÿºZÿýE?ÝYôÛgÛ~}§þáù‰?÷áÜ?lÍý¸>úÛ¦Ä_OüaWÉg+3/M[‘ë[Ÿ0q˜Sýøà‰#ÜÃ=ô,Eš ÊožÀZ<ÓÕË›l@û熮êrHûÔpQl><åÁÉš¯výp`Ì“Ï÷=}òñÓ'ýþËÅ?ž~÷ôñƒß>2ûýÇýOþ}þ·«ûlõ/-ÿöÒŒo>¼6ëñç[~83ûÇMÿZ5äë¹±_LïûíòÁŸ/KýtQÊ' ’VDž]0|yUTmi`YºãÔ‚àуœìt„j½•Þ¼ß#—e×®j²ëNÀ7D?ÏSÌ<°/lÃ[ÛPòÌUlÃ#Ù~(0™†Ø|ï4ã®ÖÀÛö¾HÔˆÀò$Cå¹c†î—‹³CËv@5sLkØÉ.H|áâ0ê¼/ÏÊ…k.9µiÙ’EõõÓ+çd$'D ‹Š‹Höqñw¶÷J Ñ/9sh¡¯gÿØCúE&ÙÙº9õ ë=®¨xjù䲑E•Eùs«Ç7T”Õ–Ži;¡±º¶tD‰¾®Oìú‘·Ä$Ì̺¿iˆDÏÇÐ,ÄÀ4Xb¬cc`90{åºu+V6f„•Y²‘mÕCB;O•UŠÓ}L;°<{çò¼£[Çì\‘;wlØŠªØcMY›2Þ[9ü‹U?]]òÛW›þxòàé£óO=õôÑX{ýþð­–Ù“wÿåTë7;î<ùá­oÖÿroõãï/þxjê¿w|·4éÛåCþ½-ÿû¦„Ÿ÷|·aø»‹>]’þå‘ê=e}§s™5&xÝÜÔ)ù~°t1+·ô‹ ¬ À^žÙ³—.uƒGªüyåtdÕEÔ%D]dÔ'º"õ¹Û°ñLP`2  Þoxw¿ùþSFA­’ãýn¬À6ŒÒ„E[{Áp°PƒcáñÏ?O2·/ÂMø*VX6kÏ®óóë–Ž+)OšÕ×opZbAYÁÔ˜~É#)š<îÊ1ÅU9ÃK‡gTÔÕ7•WΈŽI‹‹Ö0cAãüëš–Ïš8¥¢0¯®jÂŒ‰ãËrò23„§j‰l Œ| ,Bùúšº>°ê˜9ÄØ{²uO´÷¤eff›è0tåÚ='Ïž3iªWX²{`¢Ž‘;ÕO )õî­¥ªd£Ÿ“ä2cBÄÆ¦'vM½p´ñü±…§¶W¿½iâGû«~º¹òáßoùÕÊ¡ï/~úÛå§¿€Àüñô«ß^üÍÖß¿;ñô·ë¿ÿxì÷ö<þéò£÷û`ÎÃV>ú`ÙÃks¿ß_ú󮼟6eüz|ük‡ürtìÇÆÿ´³àçýãÿµ£è@uô²)1kæÙؘ1wbXvŒ½žé\kP`íö2€´V¬p'€Ã:®1ð Þ⪋è þÛ¶áEƒmxäª aæ:؆Fˆ±È±dûy Àd"0òÑ\Œþü„tm|XŠèŠkF” ,¸%ðÕZLVý+W° rÔ©_ï~©sן˜P½ltÑôÉ£úÆgÍ,­Ÿ¹´yÉÆ¥kJ‹Çoܰuýºí•3ã‡ææ”DxyGHLŸ\=kÓ†M šòrrÇææ—e*Ì6»ºbVÍÔ˜°X±Ä¾×?MyvŠ<U¾½®¡¯¹CDplž®U¨Ô:ÌÞgÔº¯{ŒÔÄOKlhÑ'dè¢æjBäø÷Ëpt¡º -vÙÌø ‹2çLNжåÿõzX;AÈ‹@¶Ã”)vÀ¶m>\X“uj5ÆjŒ¨‹Bgž§.xIaa6€%K¶ÁÛÇm–&ÓAˆÃÿ´ Œ  àZ K1¸ßZaÿ ´F¾ÊƒÀuê¦zþ®aãĤދN,®˜¾*yäÄâñ³ j&”×ÅHßàÔê5[3†å&Jß¶uÏ•Ë7Ξy+3#GEMb`j;±rò?|[=©ÂÅÞ~ÂèÂêÂâœ!ƒç5L«™ieééê`á<Ð;hhHøp¡ÈÞÙ9ÂÓ/ÞÜ1Lbè.ÒwSXé™ûÍ]¼aÑ’õ‰ƒPËËÜ6".-lõ¼ð„ÂÈ‘A}³ MèEX;+0˜žÏU?ØÓxršÇìÒ°µóӬȹµ¿bûÒ¬½‹†ÝÝ4î‹Óu?ßZûëººà—·çý|¶âáéñ¿½»à÷Î>}xééo7~ÿ÷®§O>€§®?}xõ÷Ÿ.>þfÿ¯Ÿîüå“ý?^ZôÓÙù¿œòÛ»«ÿöÂãÏ6Ýððä˜Gç˼ð÷ŸŽÿþÃŽ'Ÿmýýû3üþÕÓGþþÝ[?ß\÷õ¡šw•~~pÂWÇ+¼2çûm£½ÓôðTùãOW>ùfßÓÇŸO`w—ï‚«hì lÚ´­þ‘£²ÇÏnhÚ’šYî88»dêüe[2sÆßyïã>ù|Ê”ÚóæçfL2´||ÅàACj§Í\µ|uŸ€¾cÇV,]ÚôÕ?u¬~úÌó‡ŸÝ»kç†µãÆ”åŽ/ÖóÈÌ,Û¸z‡§[ð˜âɃ³CssÆMš4uNCãÈÜ↺ÆåÍ›êêÎ?üÕ·ŸLŸ=/ßôäÛÝ?Ý÷ï÷ןZ6rOsÁަ‘yI¶£»ä&8™ó5ÿëÓÃÖ¼ƒKñUæGr…3Ï»:¤}j8¯2dÆZ­!%-âZ´hZk¨C(X¨Èw5V\lê"£d!g|fˆ¢ 'ÏT”CxmIeò”:K÷ Œý»Ù]Åk鿃ƒC|á uÁ!Ð=ªœpkIùZ´À^%](°äò«–VÌnÞzà||z‘G`’_ß¡ÑI%ýò|Ãôà›?xprßÁë'OÌ™:µ¹qÉÂú9µÕ5'=và𴊪ÊÒñyÙß=øêÖåësjf-]0{Íʹ'LJââ: ./>1wý¦m—¯^µutL–Ÿ=yê™sWzÆ)©›)©[*«Û×L[ðÙg÷îÞ»6"ktZrIÓ‚m±±#=ýÒC#FX‡:²Läöù™SìÝ[£·¢¶ªšŸi =ÈZ/ÁÝh|¦×œÂ€]³âÏl*Ü·<»i|ÄÚüàVg¾§ä§+³~ûdÍooùíNïg&?ºY÷øÓUO¾ÙþÛíeÿ>5óçëËÞ]ýðËÃýáâ¢÷N|uÞ½5c¾??÷ч~~{ÑãÏv>ùþü“oþûâ¬×Ž<±²ðÝ‹Kw.É:¶kÖ¶ežÆ|Sž_ù?¿þÅæXPã]\Øä ‡ö—ÈérHûÔp^#d°DZ$¤¤Õ\‹’ZÓEK±·m:߀x¨cÉÛ ù±9œR¬ºàꩉ Ø u:ÖQ^Kÿ_@`¥BèUNA¥÷7š©S¿ÅU‹7^¼îÈ€”â˜äk—X;÷DWßt=óPß´ÐþéÙYcN:ÿÑ»^?y~ýœ‰cËV.Yvdß};w¯nZºdÎÜeóæ¿wýFõ¸ñÛ×®?ºoÛî«O=¼kçþˆ¨ÈÖÙ5¬²ºö½û N6oÁòý®Œ+opõ‰t÷‹éºhé{)©ÛššûÁJ®aÎÜ ¦¦$.˜¿Úͽ¿©ehqÙü¾FÙzpKÓ2ýÏßТ’PSPÔPP)©Xkhk‰œE©F:MA¶ÍÃ}wTDn¨ŠÝX;`OUüÛóÒwÏNÙ>.ü~]òÇÊ^©ôþÚGŸ®ýårýÃ×üö~ÓGjÝ\öã忼·áѧ|pòÇ/o½{páµµe̽¤þ‡‹ ?Ý9é_Ǧþ|vÆÏ··~¶~Ô»»'¬ŠnžÔõÌA'wN™;i@v¼ë°Hg3 ¾¢ ÷ ô$(°vè9#Ãd¬ÕR·6„¨+¯5ðôo”ÀX{‘äì"êÀââ4€œ ;ÕÀ<oðÞ ØÅÔkÍÜ1C™­¿ÍÂÌFè&q§~ªŽ,Cõœ@Õy€ÀȧˆmË)JK`¯Q.ð2ðNÈ×:¨jiͶ\ã­_凑Àé¨nt„€Ð¸9Ë—ÍZ›“Vîœáâ›.5éçæ7ÜÆ)~Äè™>ƒ ½ÃÆ$Ñ4oÙäò‰©IÉ%yÓ&Wç猜1¹jCóÒ3g,š=k|aþÎõëNÜóÖ¹“'–oÞ´£²ªÎ¯ÏoßÈ~á é9ùEãÌ-ÝüýÿGA_‘g¢¬aÉ—¸ð%nÿP²=Œ}íý¬müllKÆVnÞ¶DÎ$W¯hw¿¯îÁ©&öÿù0J` ^ïÞR5+u ÏG(ÈÕ×ê¯#ζ“nŽpØí·<ÛûðŒ¸ó‡\™“üVy̹Ùñ÷Ö|}tò·{Çÿzué¯÷·>¼¶ôÑ›Þ^ýÓžò_n¬yôÙÇ?\ûõ_W}vöËK˯¯{©iôÇGæxaåG–]\˜ujvÚÇë 4dî¾cÖà Óâ6-N¯-X1#© ÁÅCªi©®¡Ï㉔”U”{ÿõg[ƒk"Ò>åž.´O §›!d¬ÕRBnjV]ÍÍÍXF†1vᚌ ¤EÉFÛE@iŒRLPÜm¨o© !êâ–xøLÃük7ì/_Û7<ÞÛ¯¯®žªŠ…*Ïš'´ëºëú[ØDyúµµO²²ŽróŒ20öÒ–ºyûG¬ß´³° ÂÛ'ÂÜÚß/8Õ?,ÓÖå?˜ƒ˜ZoEme555#ÏSÀ "uÄÕvÆÍa‹"m–Æ8lÈ ÛY3àÌœÁ›s¯l*»¶lôµ5c?ÜSþÕ)?_m~x}ÎOW=º>ïǫ빶ò×}sî—›[~þðâ·o­øìê®O7O:3'ëã=³>=2ç‘ו«rpjò–y™«&õ¿ºuÂŒ<ŸeÓÇ õn;<ÄÊVƒgÌãéðxÐ1%Ež¢’šbËWéùÊ*àZX;À]Ó2ÿ½¡#Cc¬ÕRÒ"®g©kGkÈN5õLÀ^äó=Öaƒésê@¢18#WWÜmØEúLtÕÒïE‹`/k/¢.(¤ZæÒ£æ}.TMÙ„ê3ªf—£`¯`Û_ ÞoxÁaD<â(iñU›P*‚’¶#W ¹˜ÈQŽQ ê!®ìßT„rª3í³vóŬÂE©…µ£ËgLž¹lͶÓƒµŒüœ¼“$åV¢màâ”dh Ðw¯™:gÃÊU‹ç.€µ×ıeS+«¦×\?ò›Oßß·uÝ̪òsG÷M­¨(Í+ž4¾¢vúl/Ÿ€Šêé³–gfsõž9»1$t°€ï¤¥ã¥¬n­o¨.t—†yúdºydˆ´}]¼xú¥À†¶GÙøê…óÏš¹()y´«×Àà~9Nîñl·Y´•U UÕuÕx®|M?¡ÀEÀ•‡ê ‡è G˜JÆyÏéï°3/bÇä¸=SOOt±nèµ-Ew7”~¼eì{‹²þujÚ£÷6ÿ´kìÃ÷7ýx©ù—«~>½ò—û~¾ø«óÍ_^Øssñ”¯6Õ~ëÈíµŸ¬òþ¡ºwšKÎm¿¹>ãðŽòC•q{W”–DØÏ( ©‰¶4šé™ªñLÕÕõÕyŠÊ#Ÿ+ì'‡Ð2§€«ŠÒ„êL;ÄÄe4,>3¶pÒÂ}gï–×®Vbddë_””Rä³rãÞàˆ;÷°ÀˆA÷=°}çä Ư̈̄]7cò”uË—~ñÉÝwÞ:sòÀŽû·.¿{õìäñeCS³FŒÈ”©£gmeëåæ‘\W߸qËþ¤ÁyææÁʪVÚ^æ6ýôŒ‚Uþ§·@â'5éÓ7f¸«O’Ô8ÄÙ+!j఼ѥS&ÏZ·jgß~éö.q~ÁY†Æn¤ç¬À”{÷(¨ê«ñ\øš|M>?H,ò h +¥VÒùžæÓÂmçÇ:lÈÞ16b[~èþ±á·ëRo/Ìx]ÞgÍŸïúÙæ±ÿ¾¸øÇó³:1ï×w7ÿrqÕ÷‡Öÿûü¦ßÞü`ÿŠ«M“>;°ôÃ#«?80ÿýÍõŸî¯ûv͸KÍ…gæ ß±pÄòœucÇõs¨t^èn%ø ùÖÆêêR5žPEµeí¥ #? ƒí7C`ä:|i _mûÔp^)d8Ì‚«5DN$-_Ϙ6­KÔÕXÒàV`Äa@q±ÅŸ&ø´þí¨ç}~žºH¸븺¯\`ÔŒÿûé·„ª/kp» tsÿA*xï)‘ËÞiX3‘:ä2…´Ôaöµ^ǤA({Á!PH*S¡úó< &Ì-›µuTYãÔi+L¬c쳂"ÓGͰsˆ54ôË+ªi\½[]lå=:gÄ©ý{V/\<¾°°täÈ¡q Ó++>ûäþ×>üñû/~úê£æ9Ó²†¦dŽ*ð雤k¢"p½cƒõX²xÉœEK ,\FL12ó50÷uó‰Ó;«h8òÅžZúÞ"]Gs›@# ?©±gNÞ;¯ÖA©‰™'v¨©˜i`dç5ÈÒ.ôœ ” Ò»7_QUK§Ïã™òx~°ü‹ûˆDÑÚ‚aº‚23Ý2;é^ƳúY­â±;ÃÿâìA‡ËúŸ©Š¿^;è\}ÊíE¹Ÿ¬ûÑæ ¬)ýñòÊO×”~»Ö÷ûç~¹`ÎKë>ß¾ü«ý›?ÙÜðÞî…wÖ4Üž7ö«“kÿ½gö·[§|»³j{Šÿî¢Ä…±ŽõAVsû;nŒôÈ3Òk¤«­ÕW"rÒäðxªŠŠª Š 1uæùj*)¿“ëPÃyEs1Öj )‰B–b¬ÀºV],ì7É'‡ðí Œ@z &#=o›Îª‹ÐÝ#S0·„ª/kp» tsÿÉÅW!¼¯Äaß|ÿ)+0W]l(‘UX `j´ HŽ©ýßÉQ]z&E“ÇçÎŽ<1wt투 §N\ýñÇß=[3}A}ÚêêæÐþìƒÕÅææÞCK‰ŠÌOMI žZR\S\4vxæôòq{6­ùòÃw¿ÿü£ÝW%„õ ì`hãÇ7ðQ¸þ㟩±ƒBü‚JÆO±w]X³bía{×pe Ë^ &ªšŽ:úA"]¡Ž£–¾›³gLjæ„€ÐmÓ[‘ý¶¯Û´rùª¤ÌQæ.á6öÌÁˆÀÔz+ˆ•ÕôÔxFj<ϒdz×Ðð ‡HÄC´%IÚš™†ÂQæ’‰.ú3,Ä: lÍï=i~;ò#ÎNŒ¾1=þTAøÍé)ï-˽4+ý£E£¯Nͼ¿`Ü7Û¾ž[ÿÅŠE¯YönSí‡ëßY5ëÊÌÊ;“ÇÝ©,ùncÝ÷{–~:!ûX\hS€ã¶ ÇzW‹¥>v…Ú¹zS­Ìu´fHõF ÄæêÚ*ªšÊÊÚªj˜ZvkZùýU³Þ™^roò¤•cŒ/þ¨8÷Ýü‘÷ÊJî–Œº¶7Øc·ý"wÛgËÝCcK µFëEik×X›/±3ˆÓõtlÕ5øJʰ“¨¨**(h*¿9+0Ê=] iŸrO—@Ú§†Ó%n3Öj )i׳~¯‹ ndxÚñ{öµÓ:šWá•;Åìò…DöaÜÿär$—æ3?B„pöb»4Z¤L€: 9€]„=ó³D(' R•ê…•CŸÌñM!Ãfª Ž*È)ž¹dýñø!“Ü|‡=cëž³s¬M:!aHyíÜu6íœ=mÖ첂ÆâÌêˆÐ9q±ÃÓj³7MU›“çåêdïc瘕šÙÇ/ÒÒ6D×4@l Ä·RQ7 t÷uñÔÓrøŸX(óþ§·ŽPbmdî«¥ç¦.t46ï«% àK¼”xŽfV-/m½Ø°ssòIÐÐuퟘç2صOœ¿tg÷h}}f&TRÓWãYñÔ45]…B±¨¿X-ˆE±b:üQ™9¸D¯ÎѰÎÝhi eS°åš(ûå¶[ºÊéÓœà¶}läÞ’ð-Ùçg¦+ˆz§!õzñà;u#¯N̸Y6üꤢOçNý¼®ö“ eŸM,ý¢²ôöØ¢[e¥_V•}\[ýnaÖR«õ¾N•VÆY:‚¸väðÆ)gÆEΉí»4kМÑCj2ãsB½úÙšExx„xö èïåaë¡kÒGSê©*´UT3p´rv2w⩚+)Ûý£·…¢ªI¯Þº½z ZNÞ-!š†ªi8©j8éƒÌTÔùbM'ïÐt¡¡Ÿ©Ó@bèß7kHF™¾!³ã+¨é¶~~³×ÐtÒÔô ƒÄ" R̦­1ÞPRe®Se+­´Òip6hö1Ýl·4ØzYÛ½‰^kcÜöçïÏ Ù›×oOnðÁ⨳ELIý°`Ѓ•cß3ôëéc¾œW{¯bÂW³&4©ü‹Š²÷‹Fþ°mÉýÑiŸ-n|°vÕå” <—x9Ìqwom1ÛάÜÜ8S_Zei:ÎÁ²ÆÚdªé,“m-[ MX, ”” xê°{½ƒ òo¯¿.é.0xá$]e¬ÕR{!mÕÕú£.æ÷ºÈ}J5ûZøówu€*|¥¼ªa³ó)Z¾Èò"ŒÛ1àuõŸ\šp¶#0Pœx‹ü¾+0€uXg‡¿¤ÂcòË—yö+Ôµ‰Ñ2Ž4µI1±Š³pˆ‘šÚº& ´ÃÕ}z)Ù›[G÷ï—“Ÿ[“1¨ÀÓ)¬8½piiÑŒ¸À %i&å­«wdÙ¢å5Sr’Ò|\ííü=|âm¢¥Fþ|‰‹²º­‚ª•ª¦]oeóÞ*FæA–¶ý‰ÔËÀ4PAÙBK×Ó§Oª£ë€–ʹC©f_ D]#£4îÔX7 ŒÌømíCµðzáv `ºÛ&Ü:T ]¹@A9ñ…Càj†ËšY{oqaÆ]„¥È¹ú©šÜ£;IôË(n2õÊ2pM6wOJœ2{þá¾±…C_‹p¾vÈ ooM^½ÌzýìW/CEeã`ÿèûöŸ3eë„ÜÆÜ”¥cF]ݵå­=»Â"m-] œ@`± ŦVab]Ou¡ tJ<›(š*¨Xòøö±£•mÿ€àt‘–«PËÍÉ=NM`'–ºšI ûèèýSÉQ íÇ“x*j:Xö×Ðö’š†êYöuòllî h*(I”UuÔxf­s ýE"¿V|Åâ~bašX3WŸd Uc¡[e£SçfÐäi¼ÜËdµ·éŽP»=®ÇølòÜå¾=Ækw´ï¡Ä€[£#?›™ýEAÒ¿Š‡ý{ݬoËJ¾.Îûfö¬ï–-ûº¡î‹5ßo\r/øƒªÉŸÔÎx'7cǪ¯F;ÓM^ö³¬Š u³ô´b%’±ö6v–åvÖ•6Ãt%e¦†qRéHcC/?XWçÕ ìûFã¿.H¸6`ƒ:¶S™ÚyiÁ«mŸNÇ›—¹ñþ ô¦h“(ŠüpK^ÔU“5Ø‹åûÏÔªr—óJ^2 ²°Ëvæ… R"›‹0n—€g.¿H^uÿÉËåÔú»ÌD`Ø å "V9ìò‹ÀªˆÔ'‡Zþ)áBöàDT¯(ÜûÄ +Ynæ—cì•jâšÒ'¢0*q\HT^Ÿþ9é9µN^Cœ¼RÜÒõ-úò$îª|G ±‹º®«‰­O}õÔskš/-›¿{rY}vÚúºi3Æ–d%§……ÄXÙù雸dåNóô Òĺ"÷Þ*–JjÖ½þiÔ«·‰¢ª•HÇCSäÔ[ÉT åªªa·dŀд^½´½õÍòðòEu¡‡¶q°¹ClÉÄf'ï -/Cëp}‹0]Wè<8@]QQª¢j§®á¢É‡G'M~ H ˆD}Äâ¾bQ²X˜£-¡­™o k,žj¡;ÇÞp¾³áúbß¶CkWî˜7omRJ¾“oœgHÊô‚¬´á §T[½øÉ÷¾ûàÕóëS’÷ ‰˜6*:1_ åah¬o¨Ä³í­b¥kè/Öñi»kˆœø"g©¡¿2ÏaÿP2û§bË"LÇÀÏÖ©ïάì[þGrú{ç˜([jXö—š†ª]m]õ,ûJÍB$:-ÿ¨ 8@¡õ!*÷VPí­(PTÕQU3RãY««»kjú ø~bX‡‰b…‚\¾f¡– X*k ®4Õ®±’6Ù¯õ2ßh³ÃÏzS ÝÆ ÛÝ}]Ö‡º®v<æ~c`е˜>÷ÓcîÇ?:ðÓìÔCÜñUAæç£Òn |{XÊû9™×„®óõYçl3ËX:ßÒ¨ÊÊ4[,(3ÓŸhm>ÆTw’­á¶pÿÕ!Þó¼ŠMôk ‡ê 3Ô‹×é¾:?2ïÔQ….¼.î—Vµ´^p¦Ë!íSÃi‡ .´ÞÊŒ¥àØV+µÜ×l!ÖÀ¹~®Ûú{KôÞÕÏóh¸÷ñýÎöó=?(òFBøÍ´fº•q?5þƒ¤þFD¿74ñƒaƒ?I;â³ÔÞr½›Í\kÃÍî&ú#$‚d‘°ÊÚl¤T<Þ\w–‡Ã3ƒBSƒÙžNÕVÆ£Œ¥c,Œj¬Ms õºA`Ô7€¹c†P`Ð85œv€úp+ÁtAî_H‹¬Zrò¦¤„ *@IËÍ/Kêb½E>3äªëeÖŽºÖÔ*¨C]üÒ°ÓZ¾7ƒ„)jì,Â¸ÝØþ3n²÷ÕõŸ9M«À Ü]»ƒ§ßŒÓ'À6Ô¤¡ê“CØÖHMÎÎ=ï3Y·vOÆèI“N=¿wãÌÌj±qÿ°ð¼È¾™~)Ɔ^ VíÙsbjí‚ð˜ WïDCó0E5%U3MYHHlmmý¾ûìÜûïï¿‚×óé“Gï¼}ëÄ¡Óß}õÇw?Þ´fËÙcç s‹ÆŽ›êìûE#5MGm}/c m©HÇKjÔG]à¤È³3· KíBÂMž¶PQÅHâ¤c¨m$”ú™ØFI =“=’žÁ"LSI‰¯¤¤Þò'xŠŠZ*ªjg‚=õõ»úáÈÄk±¡†'\ð¿t&ØóÝawâCî <åí°ÒÃöh°ûG£j+½9V ŽfņÚ#tuÒµÄýµµHD©Fzà õã¥:Yæ….ö3Üì§»X$ëK;"0˜;5ϲPc½Å‚ƒÆ©á´Ô‡[ aÕ—:<%嬽 ­v“ÝŸu±ê¢¼Å>¹íöÞ½ÿŸ¿UWsk^ÀZfwNÈ[BÂýîQT›Ý ·éÜL§Ûv‘:Ü£¨6_rªÀڈ煛$º¢~Æ—Ñíy†—K¥êTe (dGAªÏë—3æÔ5mOUupß¡®¿?bÄC›áÑËæÜÿNYé<‹€††U#r'dŒ¨46Ký-B M|cfÅhðÄ}¼úN8óòÙ ¿þøí¿?$¯êŸOÿüó–ÿÿþëïG¤HHL ‹NvtÔà;J ý-lC]<¸xÄÙ9EÚ;Eù¦*(›)¨š™Xû÷R­¨‹MÈëÕË@Sä-5 J}ÿ©jg`ÙßÒi ³÷`w¯8ÒsjFë0•Þ "%U#uuGMÍ>~„X%e‰…“µµëôõꌤ3 uçë5Zβқkg°ÃÛf±›Q“‡É_»­~v{]—ºZ®ó°{«¯ßÁP¿ëÑ—¢oÅõ»Ü×ëê¿K.WûzÜŠîsØÛa§›Í2W«{“ ÆÚLµË Ä’)F:K}'èŒ66Ì0NqµKÓ–$jiÅkkMv²m¬_hk™×±‰À Tùß Œò ©ðòßB|ãF„DÒj¨ÿ¨ …p‹±ÛäiGnºnì6âj¬­·Ø ² æ­ÖPMq鈺ºU`ìÜG –_òÆ0EEaÜÏ\~ÁÍaž´†ÔyEý'§  PNFÎw,( DEÙ‹å ¶1òo4³79%0Ùµq@Ë#´ü¼pIš±ýð[‹×î½}óƧï~˜‘Y¡¡0 ©tLá´E ·.Y¼oöôUb‡OwvÀù¨‹<”Ô¬=}âÃ#Óûô‰<(=cHž½©OTèÀC{öÿñø×ÿ}òã÷_ùó÷?þïÓÿ}úè÷ß>~ôï_.¿}y\Ťх•zúÞÿø§©}´·O Á‘Ñ™&f>…ŵf>Êjæb‡ÿù§ØÝ'r^Ó6ežµ–~Oänd¡ î "pÕ2 rñI¶v %=g&TV²ÓP÷ ½%" ÀXC]ªªæÊ‡µ—ÐS tæ œ45ý‚!bÑ0±(OKR®%©Hj uê-ôÛ6Û7Ú5ÙïãºÁÓv—ÝWÛ}W#7;Y^íçs1Ðõíþ¾çÃüŽzÚíu±9êi{ÔÏi±½Yƒ­qƒµIµ¡nµ‘ÎDCíÑRQ¾®džñ‘¢!ãµ%#´E©:Z# ¥e6ÕN¶óm-F›¥hiÍv´¬47è”À Ô.ö ñÏ„ø‰’R®.¨LµÜq WpC‘K®kQCû”{ºÒ>5œ¶@µ .€–ZÕF]¬®¸ÛT ¯"0Ñ+-Ö[¬º  FG5Bqq¿2që0®º¸Þb¡Z ¼BµNìÿòö0Eœp¥Znqº w)á:Œ”@¸ÇR-¿0äT!ìb—S`¯›ûMïÞµäz‹vÀ ùW›a€£(u¤ hìy X´zOí¢ ¿üüÓû×oÇÄf÷K,M<ÆÄÐÙÔÔÃÍ%<Ð/.99·lÂÌÈÙ-¿ ¦ÖòS«¾á™Å¥Ó§T7”–LXƒØnƒz÷ÖQUq×Ô°Ðà©)µüc%ªŠ &-ÿ"³©:O¢¢*QUÓQãóÔí55\ùüH‘`˜H\ ¥5GO¼X\ â×ëÕšHg[p²Üno±ÆÉr…“Õ^û NVôÝìls.Äk—‹õåpŸS^oû;½åë|ÜÅf…éJ[“ N–v&•¦ÒñZº’l-I޶(K".¦k‰ó-LҴŵ$qQŒŽV‰‰þééÞäàiöæÀu°u‘P?u¨L±ã@O¸ŸžumÈH_iûÔpÚB¾»AõÉ-²úKW¤„lSÇÊ\‡±ºbå°ê"C£& 0®Ã(u±"HªB—½dÜéh»ü‚°ïl0Eœ¼ÞE÷Ô·ÿ¤Ïæùsö*úONAÈ.x¬Óö“CvlÀòß©¿ùP‘EÕˆíà°çu€¢¦acyíŠ/|ýåŸôHÓµ u÷‹ß²~_SÓ¦½{Î^8wuõÚ9£‹'Ni°w WPµ´uŒŽ8rD΄¤¤ÌºY –-ZQ9njj|®™®“¥ÝÖõ›¯^ºððçÿßOž>þõ÷Ç¿þùçöî;¦¢¼l¦‡K„¥©§±¡£¿oߊòšÙ3”O¨Ù°~Ƕ­{ŒŒ}TÔÝBÂ3þ©¦›SX±dõ ‰ó?Õx©Y¨gà°è¤2S»þl·Ù‰Š¢‚T'VUVlù—#™(ÂúLQEWg«©é'z …Iñhm­|‰v–@0UO:CWw‰…ñ<}½•æÆÓt¶Ûš¯°6žog¾ÊÞ|§—ëÁ·Ýž«m-Žú8¯w±½êqÚÍf·ƒ(íPlŸ'«¥žŽ«­, «Lô ¤’l?ÃP?R$Ê55*µ0ÉЗæ˜ Ô–ô“êÔÕI‹3-+lLGvô[ˆ0ƒCÈìI¶!äZæø£GÉ6ÊRíð’+0¹5 ®¨È6 )·2¤5Ô2Å3F ëȆ\@Wà'â0Ö[dƒ«.¶©F¯J`dN§ïûÎ1Eÿn Tû¯î©¦C­!ºzæò‹-$á¶@µÿb³P…²‹µð¼Ï ÄX °Ö5 f(ª ìbÛì¸À¢‹#KÖ®ÙõÛw¿NŸÞ4 ­¬p\ÃäÊ9^^በåã'Ÿ8uú‹¯¿S>9· \QÙ”§áØ?"Ó–h&+–¯»wûîík·fVÍëã‘;´è__~ûèçŸ>ùùé“_þüóéÿ=ýíä‘ýu3gŒ.OO)23ôv´ë3§~qUåÔ’¢²É5cK˧VÏ*SéàÐWMÃ%zÀ(ç”aÅÇÏÜ´wT×òR¹khûš:Äú„×1òe»M Œ HLE¡å –ê!B‹††Këßé‹ý…Âp‘hŠ¡^•¾^µTw”XX"MÖÑž&Õn²0ªÑמoaÜlm±ÂÎr•µé" ÓJ]í}þÎ5zÒjmíuf¦G=Nº®ö°[êd¶ÈÒ°ÎD¿JO{Љn–Pc±•é(± ÌP¯ØP:PG«¿¾~?}}¡0X[’f õ“hEëh[ijvJ`Ö ³%ÌìÛ² ÞeP÷±ã¼üGˆ¯"0(2@æyW‡´O ‡\EÖ^ð’¶šë¿ÔEJ¨Cd"­¶ƒíΪ‹@FÂÚ BÖV]ä)Õ¡kƸg.¿ ä>ÀSôßy]‹0îIçõ. SúWº³ÿpöR!kB[‡Ý½k °ë-è7O— HɪY8ý‡¯~ùø½/ÇL˜£cÖgpƄْs“â‡õ‰\µrý£‡O6mÜ6a\ƒ½U¤¥™¿™±KqQÙÔ©ÓÎ9óËÿ~üËÃ/|þÇã§þߟÿ÷ôÑ¿ÿðçŸO>¹÷â™S›V¯©›ÝÒw OÍZ"ò62ôKLŸ6}vA~iaaq]Ýœys–d ëæfdà˜;¼ÊÞ*¢´pö©ãW§HMƒ4õú(iû MB-£´µ[þ+0ЕZoEÞ*|e‘²ŠXEU[MÍH]ÝZSïiÒò‡¦4<@]bqˆX'–Œlý¢à‰$FK;EKkо´D¢•/Ö˜ÕH'kk/¶6Ÿ"Õfb0ÙØ BOºÂÚl‹ÅV+Óõ–&k­Í¶Ú[¬´5›c¦?ÛHZª%®0ÐÉjO4Òn¨#&K¥ÙúúôE‘bQ?}i–NŒ¡¡µ¦¦»––­@®«c/àwP`Üq2¡CÈS2™Â» *â>vœ—XÒvÝ.E íoœ½©Ë!íSá€WVWDT$­/¶¬º¸E±# .2ªòߺ"ŸiAØmJ]ê!®ìSª–W"0f:o¸[à…ÀSÔ&Üv¨³¼:¸'˜®<+¤ÿ$pc0¥œpÛ¡ÎÒµ@(±cÁåÀJ ®0¨«®üÉ´|5ˆˆP3qáò–;etñŒ{·ïüþ'©Ã jç®ihÜ4º¨²¨°²næÒôÔQÙà ׭Ýüé§Ÿ]¿ú^QޔبÔÚi »÷ìùø“Ö­^yòȱß?þóÿ_ËëøÇÿûõ‡ïÜoïŽsgÖ̵t~óÅóoO™:ÏË+ÁÎ6ÆÙ92(4¦²rF€¿ææå§Nß¼yË€ØAþ~¡é©Ùõ³šSåִ͘eÓî²²Z+‡HmÓP=Û©e}Ó>Ü>S+0ÅÞ½Š*-ÿ<˜º¦£&߉Ï7PW×áñ¤j<ò~45ûˆD °‰$@$ráóA0ƒttÆêI3õõiI t´Ê´´ò„Â<`²¡~Ž–¤ÆP?_GgP8\Gk„HX$6n´4]fn4ÛÂxšî(©v¾t°Tg¨®ö0}=‰$PK’hbì&:‰DFŽ~˜¶Ö@i¼¡¦’²‹Xl®ÁÓ×ì´Ààb`7ØP6zP`íCtÅ.Å:~CɬÆ`b±ÃX¨ gÆj )u‘§ °)S¦P-PtÁKɲŽ,_ž9õ“tÿ"Œ{: ƒË¯ç ¡Ûú} â!‹­‘Qš ( ?_TW(c¨¯ÀÅÅií¬À¤M8.VêÔíиbïÕ«w®¾õöø‰“›×l™¿tÝà¬ÑÓg,œ=³©(RZÊ(/Ï>—/_þøãÏæÔ/,*,mn^vöÜÉ·¯?vxÿíkï|ûÅWïß~÷èþƒGöhœ»hTÖè´¤a~C寄&Œß7<ÉÆ&ÄÖ&<88%wTÙˆc\û¬\¹æó/>Þ½gë’¥‹îßÿðüù·.\RZ2aíšM7n™6u^br©‘UC»hCëp¡¤å/H±PƒE˜º¢’TUÕ†¯¡«ª¶«¨é©ñ¼BpØËG(ðýÄâ@‘ÈS$räó]55“õ¤ ³d-IŒŽö0‰VªX”i —¢#al¯-ΑêD‹Åý‚8±0CW»ÚÒ4C[«TOš¡¥5H")Ò–dëhgDƒ·$’©ÔFC³Ÿ®N‚‘‘>ç,:‹E†|¡ŠŠ‘†fœ¡a°®_EÕRSSGC½ƒƒwò÷ò± ¬#€Ãàž¥ å¢1ª°ƒ€½ˆÀ\Qê"ÛÔáϤëÆLäÏ +€çÍþ$ÜÖ¨s½ ¸§˜N<+2Õè%°óõçÎmùÞ ”;´þë”à0ì«Àlû«A9ü§ÓÜ1CŸ÷}E8 šš# ó]™Z·rÿáógÏ\Ú¸aëŽfÎiò‰Ý¸uÿØ’Ê™ãR“óã¦î?°÷ç_~X¿~ݘ1Å.žÝ±s˶o¿sãÝë7?¸s÷ðÞýOŸ=°{Ϫ%«Ô-ž4vJRtژѓÃû$y¹õ M´°ô è3(>~¤½CŸÁÉ£Cƒ*'M½|ù­[·ÞÙµkϬ™sš›W:ujáÂÛ¶m[¿nÓ²%+*¹x'i™›ÚþçëJ`p˜Rë78àʽ{«öV0âih«òŒ@'|¾£†¦‹@à-ˆÅ 0M~ª®v²ŽN¸Xr,÷¤aùºƒGŽœ_ºhùá}'ª§-²óŽ»vûã­›÷d¤WZ¿pþÊ}ûÅÏ¿|wîìÙU«Viàˆ†º¦úÙ ëg5E‡3Ðuœ=sÁùóNž:~ö̹¥KÖΜÞX;mÙ°Õ–QR#?ª·mÆHE…¯¤¬¥¢ª¥¢bÀã¶þÃÍî—H(nù÷V"Ä¢D±$^$̳Ţt¾f¢€–J×ÖŽ“ê&ŠDCt$C ÂD¢P‰$H$ñŠÂ$b±8D$¬«[ª¯— 9 øýÄ’Q†ž‰š’’ƒ¶6¬·‚t´Á£ºêš&|ª¢².Oƒ¯¬¢Í㹋EæÐ7ðk—¬åŠù+PÈlµ¦ý§p,´ð2öˆ`(÷t D0¤}Ê=]iŸÒ +°Š"Û/£.B Œ™Â_:Ü6©3v-ÜÌ韓 Âm“:cWÝ »\*][ª ÛÅÅipSQÕòq"Ѭ¨ÈO¿Èçð¢"¸@å³?¶nŪe%Óvl>²s×9±¡OmÝ⯿ü~Óú##³+êë?¸ï_ÿúâð¡CK—,;tàØîý}ûÅ„<°sϱ‡÷nß9¿®~ñœ¹S&U®[¹fçæËWM^2züˆÌÒà$¾¡añCRóìíC㎈Ïrvqu7”ö±³êŸ–2zÕʇݸqÇØÒÚß8_Œr+{zùƒœ<£ú¦izöV3ì ¥nÙÙ㪧ÎË/žî˜afalÙ'¤ÕIÂóÆ(¢5jŠŠŠJzj< EEž‚’!gÆSwãk:hòƒE¢x-q²Dœ"òù‚ášê9B~†Xsœž¤Ü@;WÌ­+É7’ŽÔIËmMgzZM¶5®r°œäh9ÒT°™‰3Ÿ_b¨§«¢b®É·âkhhújK$<5 U‰ØEKl Î“‚5%bn¯ ]"0x$o÷‹=¥Úì,Ä1òj8HûWºØXG¾©Ñ])0fòî¢p[¦ÎÛUpO0'î¢p[¦ÎÛ%À$ƒ´ÛÔ^.K–lc!•ÙP5»ŠAÃÇÍ]ºO¤ã•—7£©ië®'î?»ß‘#‡G„;áàîWÎ^¹rîí]›w-_¼|zÕô %ãvoÛvxïþÓGܽ·¾vÖ¤òªÄ„ôÊIÓ§TÍœ\Y›…q'h #Ëx×ɼ LÑóóª1ÜÆ¹ë?éÉßÚëu1vRÃĪfK›ð˜¸‚訛7YѼ¹¡nqþè Æú®añÓ*ê÷l9péô¥#û¬_µ|ýª¥çNþðÞó'O——–Ê,¨Ÿ9oëÖ]{÷Ú°~kqѸAI©«VnÚ·çøÔ)õ³aUW0¡²¢69978t°ßBßÐ-(4yÈÐÒQ¹•YCÇDEõHpt‰h{HMýmœ™<¥-í L±wï–UWo±’š®ÏLS`)¨ò Õ[¾ÓóI$ƒ¥:#-KMõGIEÃD‚$¨¶xœ…tSËjkiŽž¸ÌL§ÖÕ8I,HÒNó2ík* 3Ñ9š×gS¢k¥«é ‰x®‡I…‡q¨Hè,çÙZy<‰ØXÈ7åóÉg†JŠŠ"éIG&ãÁŸÞÚ倹[ýÕÒ>ùn×BÚ§†ƒt3]&0fÚn7dÎ%aŠÚ ·}êì/·q€9e»aºÞ¦¨ÝpÛ§Îþò0ýI{fÎÙØ¸âè´†-ɃKBã÷î>>cúÜ™µ‹dÌW=µÌÓ#ÙÕ#ÉÃ?ÑÊ9„ê—Ž –?°(ªñÔ­5[þ$‡5Ÿo/˜ªó\‚TcÝlG3'>ßS,‰Ó×ã`RãlXâfÜ_"*s1<_ «®ÉÎú[9å›j¥KÅt$u!Y†Ú!bñ¢PóK­KCãœ+nÍK85)všŸÕöÔ>Õ^Ncœ­B ¤RMC­x;3%…$kse%¦[(°vAõºF`Ì„ýw+‰L»°Áý]¸g¡úð2p›˜“ý]d§ÿé U(ƒL_¼jáÒõ+–oصk÷Ù3§Þ¾råì© W/]¹}íúÝwnß¼róúÅ›w?¼çÄÛç¯Þ|ûÆ7Ÿ}þÍçŸ~õàþ'½ïÞ»·o¿sñâ¹#‡íß·çÒÅ+GœX^3}j}C]ãÞÝÇš›ÖmZ·»yÉúysš§TÕSS;mÞÔ)óŠ gNß/<ÇÍ{ÕŠŽ Òú“0µ–OÍy<žºƒ†f?‰8\O×K(L3Ò©p1vÖÔô“ˆGXêåZIoΘnª3ÌRúŶìd­…‘¶‹Ó<}DÂ1úa:Z6úÉ:_‘¨ÂÕ(T"žàezµ6f¸‰öÖ¼ ÷·ŽÍ0Ö>]›ag$QSËq3UWVÒTU™—¦¢¤d«­åiaÈô Ö.(°žÀ‹Ì€ÜIèàòåÅò*1ܹë?A^”W6¬ÞxxÛö#‡ö¿vñÊû7n¼ûöí;Wßc]8qþâésçNœxçÊ[Çî»þÖ…Oïß»öÖ¹‹gNܹñöÕKç._8PøÕƒ>ý¨eAvèÐÑ… švlß¿lÉúõk·ìßwpYóšú¹M3–Œ©˜1n⌂¢ÊôaCRó=¼"¨ž´¥#SìÝ[SQÙ@g£©i×ú¥œO°@ª5ÉT·H(‘, µ ×ûKÄKb%Z»²ýw–G'h}½mx‰½Þñ²B G0œX0ÒVL-[ihÄ™èèòxS£œÖeùæ9šÜ^6tœ·Åíyñáú"ž’²·ŽÀOK }H´ÐÓòõ´Í„-¿F‚kXO  ÆLÕ¯,ÜsQ=y1¸ Ìi^Y¸ç¢zò2È‘À€‰Ólßwfñ’Mûöœ9êæ[g€×/ݺzñÚõ·®îؼåÊ…s7¯^]}üþ»Þ»óÞíw>zïÝO>¸÷å§}ñɇŸÞï½Û7Þ½ýÎÝ»ïÞ¿ÿñ¡ƒÇ/Z¾{çÑ çÞ>røÄÖm{7lÞ³ iÝØÊÙ¹“SÓJÂ#‡ØØùP}x&˜jo%U5G>ßK,jù3"‘XìÛúËÈ£u$ ±>"Q¶¾V†¡n’‰´®¿“&˜¥îg›2³ÍunÏ‹«ò2º1µŽ¥v ˆïÎ׌3Öö ÜEB‘’ª¶*,íz+õV°ÔÔ\“å—japp\h‰»Ñ‡ë2ûI%U5ªŠ-_SEQÑ[W«åWÓÔyÚê<Ò+È›!°E­_ÇiõþØ›L§g@ît ¼Òå I×.b¸Mr×ùexAù”Ù+GŒš¶jÝù];/ìßsòð³çϾ}öÔ…=»÷ß¾~ãÁ‡÷|øá'|ðàþ}àþ»ï~pç<wßyçÞܻ͛{ýÆõóç/½}ùÆ¥ ×Ξ¾ºo÷±m[ö¬[·sò”†~QC¢G$ .è×w˜•5ý7žGW`Úªj<žƒ&ßM(ô‰À^AbqŸÖ¿ˆ˜­É)&  ZÂx=I]‰3Ÿ!Î µÜg·3͹.Àô­1þºšÙ:š…†¢$Q¬¶ÈЧ¡¦ ¨ü×/v©+*‡èi×ú›5FZ—¸œ(ïëÆX«kóÔ­54 ÔÕZ½¥¦¨ÄSzÓ~&ס†ƒt3/+°î‡êOg¡Zë~¨þô(|ãâSƧçÌ^¸x׿M‡vï>uòÔ•#GÏnÛ±ïÆÕ›ï^¿ýî;Àík7o^¹qëíwn¾}ãú[×®^|ûêÅ+ðøÖ…KçΟ;sæüáCÇwîØ¿nÍŽëwoÞ¸wÍš]'Õ§eŒ4´$ 8™:iûtD`U©šš O݉Ïw ]…-Ï7L,މÒÕÕ 5Cx¼0V$€eÐ_,NóçûW;èM±—.ík^m«;ÅJZo£?ß^¿ÞV:B"ÔWU5ª+(骨تkô Œ´ÊŒµ'¸Ìïkã#ºhòƒD¢(‘4i¯ùŸOÙ¼{ðj‚¿ÖèœÀ¨¹øuAõªãPí¼.¨^õ4üÃҦԮشåÄ–í'¶ï:~èèùõ[vïÝuðÊÙ+oŸûòÙËWÎ]9wüÜ™£gÏ9sòЩOžxðÀž=û7mܾjå†õëvlÞ°wiãúiÓååO8ÊÚéÙ¿­ÜLúj<3ÏVCÃVC³åE¡\•È×Ìæñ€Ö¿#¥ž®Á¥ æk&ó5Š$‚I&’©fºõ¶ú³MôkuôfKõê7›/61òÕÐÐTT2ã©Gc„âuI"­2±¤ÊX'ß@ ybqŸŸ¬®'ùˆDêŠà»ÿÊ#°ãýnt9ä#>ÒþŒKëºüQ@½¨^õL .Xиyã¶ck7ïoZ¹yýºív:~ðÔ‰C§Žî?A8²ïØÁÝGölÛ·cÓî›÷ìܾký† kÖÀöË76.^3¿aeÙ˜Ú!)¾~ómÃçÑqA”{+ •´TÕ`5&RV1Wkù}X„ñx<x 4VÈŽá‹Ê¢LžzކÆxxŠD{–To¾ž~©@4RSP!ÖZieÖ`mb¯®!PRr‹„â#ÞvC44¹[øiðS…ÂlM~˜Hä.‚#½ÖÌÅ’ÇSWTnùÝê¿>EDµ ¬'€!v7Tz8qƒG—O[2«q[ÓòÝkVï[½zßúõ‡Ö¬Ùß²±aÿêµ;W¬Ú¾rÕöæ[š—oY¾rsãÒµõsšk¦.š8qÞĉ ÓR'xz´÷{ÊK§ÆF¥·R˧ŠJºªjŽš®êêŽêŽšš¾šáiêšÃ5…išñš𘣡Y"-µ1"‘詪‚´”[~ö¥Ò[¯¤$TVÖUV5ª³Ë+UEÅ>ššzj&&¦GY›:™«ù…B5%#À+Üþ[‘q±ÿÑÏ-¼mùKòªÆlý]¨v^¤ÿ$Ð+fë¯Q0Ožª×ÛO²éà6ÕŽ¬Áí-ž’PÕ^#°„u6äExlç;ŠÝ±D¾fOæšx¡PMÉÄ^ܼí#D^Æn0¯xW¿æ])°g†wž¹Aµóº ý@—:¨Oµóº Pí¼Fàõ¤J {äufCú ¡j¾F$‰···••l@6mÚ°ƒÇââbx]Q°ä"?!ƒ€Ã¨_#¬Àþ6²&0öÚànT;¯ xý_,T;¯‹ˆˆˆ”””‚Öïnœ‰l ŒØÛ uÈKÒ5ƒ~¿X¨v^ð²2ú»÷€ ÕÎë‚ܦ—Ïq³³—jç5¼  Õˆ,@D 2ØoÏ 2n/æ²èÕ«ºcajËÆýË\ /ª©×y1™·c!‡Pí¼và%%kò‚C¨C^’.~ ˜Î>ÿ•evËÞKÏt«Ýÿ‚`jpB5" ´ß+Ùì3æµî@¨e V;‰C¦h½–_$T;¯ ¦7 ÕÈk„éPçCµ# Ž1·è_!…$Tý—DÖ§3‘_êeì{†ò†CAä‚ "— ÀA¹† ‚È%(0AD.A!‚ r A‘KP`‚ ˆ\‚CAä’Ý]¾«&k [O¹c†²%ò¦Âü}¹ 5yÞUŽtöqË:…qL•‚½‚zˆ+<PÂn·El-n¶[¿-ÜšT!¡å¢ùýô®Ãà)ÀUÒ=”&¸®)ëO"¯Ærj8ò×^ò«±´à`€*”}¸rêŽQ 3²­cmN9†@ãÔߌŶ¿[BU¦J¨Ùrn!Ðr¹L»a}ó{ì.—J¿o4–£Øøñ½à§€Bªš,ê*ì1.É­±0$'ÒžÚ‹tîlþ¼í¶´H@žC G÷ànÈD]\¨ ² +¤—¡E*‚G »°{Á‚ìáP…T#jtØ DuòØŸ 0ÖX`/;H.|Ы1v›ª&³9é—Ä»ÔåTõ†Ça}m*S½¨:HG`'ô¶Ï£Eòj8r¼T‡•ùWNاT5™…RÑ K1bb²ÝdÆ>…á®–Ú{ ¤´@6€–ËV`5YýýýÉdž°à);HnWcUM6‰õ1 ÷0N µiMHv/Šs‰ô4“A9UédNç>¶O‹ä9Ôpäx¸P{åVZ,TY†«¢ƒ]Bq}à †‚¸*C¨¥ìea›b!O¡y$´\1éé鬱¨§²ÜÏ„ª&›ôw7JêcQ8Ð9/Ö)=Ìf€¯Yb€91Uy0ÛPÑ;XiÉ»À¸+0ª‚,CÙèÅ ßì Ž!^á:†  €úäg Ì%Cƒ@Æ…»ö"´\1¿Ÿ>0wÌлËw‘!¡Àº™qInƒƒ,GF;¬É¨:= fn~N¨Êf_ë^fëïB(§!£wàm¨By¡ ôC•:Ïù*»ÀUÜï}<ób)V`mölÕd \`«q,HD†”§H7Pšà «.b2jW„™›Ÿ•¶{¹ °uJü›°•å:ì¨åx¸P{eb¬¶PÕd®N:HlDÈÏÃ`ùE­ÀȺڮÀ¸–â ŒrÕ2lËý €È ÌäÚátüp²·eÕÝRÂ=%¶`×gÄ^\¸H5.m ÙÖØ ö)œ¼Å~׃ý¦"4”ñ@z4Œä6Ôp¤S°–âB¾j!#ªs°ò ¢buÅÕIž)0¶UNAEÙ/z°@7tZÿ–é×yx =Ærj8Ò)ˆ–àWð”ëò”«%àoW`„´®‡±Ë/ò”T@!ã¹ 5œ—g÷­ç’1mU‘w@¬ À °ÄaåÛÄDDìSÖ^@GìÅú{F ²Ú'5Ádäg`¤'Ð+RN*vP`H†ñ€Ü†ÎË¢ò:©-`/x¤*#ò%0ò ІƒƒCxFË”bw±õ ¬ÆX¨ Ò&8‰m஥(¸g$B%Ne ¨†Cz4Œä6Ôp^"°™ÛnCãðÈBʩʈ¼C ŒÕl€6@9éééà0RH`ëXo‘Eµ—­ì*Š«1ª&©CV`ìáÜ£P`H†h@~C çåá B6P`o*\±öÈ6¨+::š-d˹GXQå1£l³Üön5öp.Ü à0°)YqÏŽCz4dš–ßPÃyy@TÓ6Ác[P`o”ŠÚª…üš3Rßµýô¯­uöZT5VZõ5òÈ=–œ:<ÿ=0¤ÇÃx@nC çå!?ëzTeDÞU#£4A DiÖæ:ì_ègñÈŠ­Ó¶)ò‡©ryd7Øú{Ø‹m`Å™žžgA!=Ærj8]ËÌm·ñ›‡o6 Jò/F:88À6×=ðÈÖiKÛvÚ‡­Ï Œë0R™=5)¿â éé0ÛPÃéZP`o<í¬°°V9°MÔÅÂÖaá¶À¥mgVfuŪ‹…Tà¶Ã¶=„GÒ£a< ·¡†Óµ ÀÞx@N¬'X(aíŒ:¶­xØ]m!•¤íºì6 Q {Fn›(0¤GÃx@nC §kA½ñ¬Äùù"²AÔeÛú‡ mS™ŸoQ‡°âyfƒU ùKT\2'†ûûûÇ‰ŽŽ†§ÜvسÃ# éÑ0ÛPÃéZP`o<¬À`ÊÆ3×^le¶ ²—­¢âÂVã–À 6à1==ì#uئrvxD!=Ærj8] 쇫 â v÷(®l5R“T ¢j {ùvFÌh)‡ vÒÒ£a< ·¡†ƒ ¢ã£ ê(€R[­L*<RÈœNaT9m@!=Ærj8Ò):(0ª„[™5 ( q«qáÖLÚ®K OÛV`àÔÐ,„t †ôtÈm¨á H§èˆÀ(Øjƒæ%Ä4°rz¦uÚÂVcíÅÂîâÂHìE¾ÜO:ƒ7Ò£a< ·¡†ƒ ‚˜m5ÐH¶YWµ9Š W`,T€”SÞâ{Ÿ÷"ÙÅ]â €ôhÈm¨á H§‘/¬Ãú AlÁJâ™:,¬o(ž·—k¬!× YØBneö,T¼ ã¹ 5éì ,f´€ý¾J,l®iÊ=¬Ÿ\uØ]Ü£ØsQ}ÀŸ!=Ærj8Ò)žù3°¶ap7\Í´«%¢«òƬºlöXö\9;x‹o¤GÃx@nC A:EyØBV3ë®~H9wƒT ºª¼3²­ºäBÛ{Açñ@z4Œä6Ôp¤S´/0V+ö)<²Ÿ:²²i«Ÿ¶@Ö[,ä@.l}öŒ,D` ö x =Ærj8Ò)^lF *°¾y&”œÀXÜå_8©jp ÷àK8/±o¤GÃx@nC A:W`¬“Àܧd›˜ƒlؽ,”oX{\-Á.xdÕE¾¾OÆÈP™=# Aþ Ærj8Ò)XCm®3¸ÛÄìS{@|C•X{Q€« Ø ÖŽÀØa›µ€7Ò£a< ·¡†ƒ ‚ŒµQûpÍAí‚F¸¾a ÙrW]\{Qc!Ír;€7Ò£a< ·¡†ƒ ¢ãcÕÅÂÝKCý!RHx¦ÀØ’¶ö"{)lã¼ ã¹ 5éÏX[?±…ù[º,d/± ñ {ûG=ؽ¬±(Xu±ßì€BJ`l³,Pˆ7Ò£a< ·¡†ƒ ‚ú…m56@T1£ÄXD` ö p,)‡ ¤J`,ìÞöV~Ø+0€uÛÛ&o¤GÃx@nC A:+0(+ XB‘¿ŽHÔÒ@i™Ãá@òo4GD¨“£Øž ì"6â:lìN}ö)ñQ”°vD!Èsa< ·¡†ƒ ‚ Ù †988DGG‡½ÈX 5I d›@Vonû‘Vù¾°]Ü Í Œ”`9Šm–»MÀéÑ0ÛPÃANAÆz……x‚øé™€œ@lÄa¬N(»°•ÉS¢Ò>QÔ¸ùܧ\H99„m–»MÀéÑ0ÛPÃANÑV`”$@?°Øb?Eo±‹0'…¤2e¶yJZ&sÁÚ‹ÝîˆÀÚ‚7Ò£a< ·¡†ƒ ¢}±âÂ~rÞ"X£°rî^JE°Ÿÿ™”½r÷(.Ð2ÞH†ñ€Ü†‚t "0 V¬{È6Á1*F`šmësË)¨ó¶{·MØÀAþCÍ´ª¶Lš>—ª† oÌÉo¨ñ»oµ@ÊWþ‡.‘gBœM©YæôéÓ¶>Rår¸ê­·.}÷óc.wïÞ…rª¦LÁÜÉÏ UYùóÊ€¿-‘e · TžW"³0W‰ü†Æ©^l€º¢Kæm:¤”Ëÿïãuqåš¡!²/0ñÙ&¡ÊåÕ÷¿< ¾¹tÉÕÒ%oÃ#lC‰ì ì]KËgÂÞà²ÌûKzÁ\ß~‰,½ýz} ¬®Ú–È,­ç´Œ,UÍð_û«°Wެ߬´¸°åòH+ÏC €ºäbùÅ®ºHÚnSõeV`㚯§×žíW²_Žö[F… ¬e®ç«m‰,ƒ{1Ï â-Buu5[.ûoýk Ã_“#ˆ·€Åúòb/€XŠ}$á–Põe ðS[ÂJ °ï~~ O©Cd ¸‹Ù%¹ÁeœÿL÷«m‰,ƒ{?‘%±ŒˆÛì.Ø †-S0ê"öúqÃ_¨ú² Hë@Š)@Ö^䑪#³€¨¸Æb!TMYäô¼Ÿ{½üÓ×ÃSÙ¼ÚÏ ì¢*Ë ìtß2ã·«m‰,ƒ{!Š‚GÖ^7/'dÙK [Ö íÅqUS6a?6dí%/c]Å>’PåÔQ²Èéy?÷âÊŒ:J¦€»¸õ%gÂ} ÛTe„««–IÿÊ€¶%Ô!2 ìuÆÀ: †ÃÚ 6Ørî€eŽ+ÏZ~qÖâ0Ùþ^"»öˆ½ „8Œª)ƒt0ÔQ²+°¶?÷b¡‘5à.f^å¿æ#æIëSª² Béª>«WÛê™ö:Ó2†S½ª««ATÄ^ì#”@9„;`Ù¤Q5eâ*€]{Á²Œª)ƒP+­Öi³%T9u”ìÀ ,¬ô ýÜ‹ ÜÅ­/9îSrƒË8\]Wµ-‘eP`¯5­_A$?î‚áÀ^@Ë×7ªåàkôd™E;ì¯å@Õ—)ÀRdF­½äâóCPë*î#„ª)k€¨@WþéëÁ[¹ø¹¸‰[dõW¸Oa›ª,ƒ°Ó=몶%² 쵦Õ^D`dF€mR(þã0‚Ì«‹Àꊨ‹<Ê—½ ¬±ZŸµ„[BÕ—)@TwïÞ%?îb‘ýŸ{q›¸õ%gBnkv›ª,ƒéžëª¶%² ìµ&ç¿~÷‹|kƒÀu5lYƒ¸ŠqØ_°å² ‹»ö‚mù²ÀºŠ¤í6U_ÖWµ…ª#ãÀ}Üâ«gvQ•e ˜î)Wµ-‘eP`¯5­#ºª®®†§×a¤¶l•–ì«‹@ìE¼ÈÅϽ( ÄUd›„*G^)̽üœP•e¶®’#{Ð[–ç•È,Ì%"¿!à ¢bGȽþƒ\ý-Db/x”GuµE^V]‚Œä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~CAé!0ßPãAAzŒä7ÔxA£ù 5A¤‡Àh@~óguPûP–5¨Þ¶…ª/kP½m U_Ö`.# ƒéþ´?EÊþŠý½0—ƒÁt¨)²ý§2ÈÖ Ùï?sa0L÷‡L‘ðØRÎNU² ÕÃöŸÊ í÷PöûÏ\F Óý!S$;QR3¦ìO Üžs¡öÊ,Ü®Rp÷Ê,Ìe„Á`0ÝjŠlÿ© ÂNôma÷Ê2Ü~>ïQ–a.# ƒéþP%µ!û(ÕÃöŸÊ ìëÜv¯,Ã\F Óýa'JîŒI=•e¨¶ÿT¶U_Ö`.# ƒéþ°S$wÒä’ ™…ÛCªó¤„Ý–MÚï¡ì÷Ÿ¹Œ0 ¦û#ï(öÿõÂ\F Óý)²}¨ KÖ zÛª¾¬Aõ¶-T}Yƒ¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º?Ô|„ ‚¹Œ0 ¦ûCÍGÒ)˜ËƒÁ`º9½zýà"ŸúŠºIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/ls-symbols_stops.png000066400000000000000000000034601474050137200262660ustar00rootroot00000000000000‰PNG  IHDR€@ØQégAMA± üaçIDATx^íÜ1Žì4ð‡8ûÒ^aáO+8¢£F¢ƒ’‚–Іž‚† À!àˆS,†O²¢d7“Lû›y¿§h5»›ØÎ/ŽÿŽgç}ð÷óóÿ @€Î%€m @€@g7ëS ðßò3 @ ¿€¶O€àèýçYj$@€lX @€xz¶Y˜ö @€@,€  @€À<½ÿÇvRíŠ%@ ¹€6üh/¹übGô~óÓï}úUò1âF›÷æÿ7ÚxÍ~OtÐöƒï{ÒuœæŠ@ ÝϾþ±l/pDo¤¯>£#EúÊà3l•ÙP@ï àÌ7öÇ_|·kkØ5˜=O‚kú à“ºÍ4weðIÈŠm"Ð2€cR_¶2ñoÒ¸þ…”ƯܱÓxËöì²+zëÎý…ï¸ÆŸÿø§¾­»ò¢Þ&_~ÿK¶^tWg¶òl!ú>.ë]žE³ŽÜ-cP¬¼Ý(VœE½cã¥~¹UÎ1N3Ïâa4©¶mûë½LÙš]â6.A ׋/bu:a_ly6üÒžs¦[¹gãÛO—¿½‰1ê/D¾±¥I¯õ‹?ßRøú>Í8Ò÷v¸®FÇÈX¶Ù·øxŸÛUÂòØuøÙ;¿{÷n6PF ¯­ï —=Ïná®òK{ÊsyiüÊ×lm¾8J®ì° §ÛÎÑV.AùU¶«0ÃY®:”Ÿ”f'\8ÒŽ?jžÀϪ[Ÿ^¯¨¦oÉ×ÒòºBgQ¿-H÷¼duV7Ûïô OáíÛ·;|ìV&vñÇY©†ÑHß‹œmô¯så+^4ì ­ŠŠô½›ž-–ñ³T«r®è6ÓC6£Mûù‡5¨b|™>AÖGÉ勃­ouxp¤ïö-Ïôuo§º–ŸÕ™¥o]\IÀÑŸžž^¼ëÇêjótÍyå#­:ö®rjG ¯l©æ 5«f/b&?œ¾žÆÛ.Ÿ;ßè%˜ÊÄXTr·|GÞÙèÔqW³¹Î²;½Öyâç»êZî|z¯Ì/òŒ¤Ó5ç]¢ƒú­¿õžþmù®×­›—3û+èT‰õÚÉÖu ‹·@ªÓ¹›Žô½ˆ;¤ºµGÅ@´2uK5éfß×x[¾h>ð]W`éÍÛ3,n€ØÿºêškãÑïã½–×¶Ùo›·äº«çö«ÊyÖÓÏç+—m¾ÑǯÙîÅÇ÷écñuÝõŒ£¶ãÇ æìTËçÝå}†Þ‘2§o»,;O]A™ýªþüHÕåØ6OÀ»žZ~”¶ôæ§PúSήé'òâ0Tϱþö`ïixxøïÊà† h[Ôô 8çX9=ßÚ16¾ÿR÷o‹v]i_Üíº›žñc·8¤yKŸyñ_Ú>é?Çß…l| /Þ™w8Ø®>¼6låz,;ÖÕÕwàúm™ð¦Ql¿Î3lUòúÿݪ–ãålœ}¦íÿ×µÿ¸[«®kÎ{9ÎevOO°ZÃrv5o×ÎÙ8€/Ög @ à}ÿ¥NC€š`L€àèM¦N !@€›À˜ ÀÐozʦñ ÐD@ ` 0@@@o2uRÜ´À¿Û_GlOéþ¼IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/ls-symbols_stops_new.png000066400000000000000000000055031474050137200271370ustar00rootroot00000000000000‰PNG  IHDR€@ØQégAMA± üa pHYsÃÃÇo¨d åIDATx^íÙ?®.9ð‘X;‰-<ØÀÁˆ1„“NDBN@Â`Ì"«xøõ±jÇ×¾nw»m¾{J¿àSÙm×uÿ©§™¯þýù³™™™=Ì ØÌÌl7`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌp6»Ó·û^È„Sþþ¯·É43ûälv'龉L8Eúni_!̶âÔl\Ùh9Ãâ’NÜnÿ焯ñÛD&ä®K!̶âÔl\Ùb9Ãâ’NnÀ§ä~[ ™l¶ ?šfã¸Åþòwß΃\ø¦vÓer¡åN[ ™l¶ ?šfã¸Åº/”;m%d²Ù&ühšãë¼Pî´•Éf›ð£yU~Å+!“íÅp‹u^"¿iGÈP’Ž!³åüP^•_îJÈd{1e‹åL).eÓeÒ}¹ü#ËoÚ2”ä#dÈl¹wJùþǾ\²3Ÿ_G ™Öé§¿þcƒ|1¹¼“,»„”d¡l®œ)Å…Â xXÏ+Ü3ÇìynÀ_B¦u’.%ä‹™ÈådÙ%¤¤å/ÿüO@›œ!Þ,ñ›?ý5‘)‘"?²žW¸gŽÙóª%Þn´øqä•TùfbàcWÎéRI|©ã â‹™Èåï’Å—“ò>¾§Ò5oÄO›Ô€e—[È·ˆ÷ô]xI%™üìÓ§D’§HIóÈyÞH6ú8äV.!% 7à/QÎ|ìÊ9 ý)‰/uT|1¹ü]²ørRÞ CSä» ül̆çÿ᚟"‚Ï’½n![܇Ð/©$7àD6ú8äV.!% 7à‚ç>v< Ò™B|©ã â‹™ð m¼”볞ÑÚœö(`TŠ|a/Ü€e—ÛÉvÃðç÷ÃK*Éäz)ï^r†·“í^›Ü¸­H©‰ðÁs;…èX"¾ÔqPñÅLx…6^ÊõYÏhmN{0*E¾07àa²Ý0üùýð’J2qNd»×&7n+RjRmÀ¸@>@I¬äÂ}ð#È/.ï-²ž9ѽ’ò x¦”×Àë@¹>ë­ÍiF¥ÈÙp€ýäò+^²óâø_Ëü§q¿ËL{”×—­O‰º!)õ:Wû`ñ»ÌÔF!îE"›Þ ŸG„ ½ 3¹TddÚ¹YÛâšÝ€¿²ž9ѽ’ò x¦”×Àë@¹>ë­ÍiF¥ÈÙp€ýäò~ßÁOK΄—ü.3ø]fð›ÿ´^À(Hñýx|ø¢’„3ø]fÚ£¼¾l} Ân¤Ôëp\íƒÅï2S…¸‰lz/|2ô&ÌäR‘‘iäfm‹k¾¡?CÊkÃcÇÍÐHxYd‚Lxz8Sï.E6ð:P®ÏzFksÚ£€Q)rÔ 0§$KõxùÌ—ÇW/‰JÎÄÉ´Gö’2:ñ+³)õ °„U¤È»p‹Å«œ¿ñ#8€| &Á^RF'^'¾€o~Èfhï(¥öxòØö)i ¾Ìy¹n!Û Hj÷±G<WdÂ5¿Ñ€óoRd»|åäàg¨Ý{¤È¾[¸–3yã#8?&/t„ )²‹3yŒvn´[5à|G‹à"çÉ›QHy ò¨lEJ­É3…œÏòÆRäY|yÅ¡3Èv¸ÂqÍnÀWƒŸ!>e΃ÙÀm×r&o|çÇä…Ž!!Eöàaq&‘Âî¶̀p )¯A•­H©5ùo¦óy@Þ˜BŠ<‹Ï!¯8òbÙnW¸3®ùÄ]ÉçW„L;%/Q„L“×*BŽcX^®;¤¼é|!/T„Lë”/.B¦)ò,9½ÇH÷âF[f`«¼*¤¼wå˶ )¯-_³YH‘Wä×­!_P Ù⢼h%dò-òÒ•ÉáD)y¥"dÚ)y‰"dÚ˜¼VòX ËËu‡”× /ä…ŠiòÅEÈ´ Ež%§÷)c6龉LxF¾—Û„”÷®|Ù6!åµåk6 )òмâòº5ä *![\”­„L¾E^º29œ(%¯T„L;%/Q„L“×*B‹ay¹îò†å厡y¡#dh9É©dëÙ¤û&2áùŽnRÞ»òeÛ„”×–¯Ù,¤È+òŠGÈëÖ/¨„lqQ^´2ùyéJÈäp¢”¼R2피D2mL^«y,†ååºCÊ–—;B†ä…Ž¡yä$§’­g“î›È„gä;ºMHyïÊ—mR^[¾f³"¯È+!¯[C¾ ²ÅEyÑJÈä[ä¥+!“ÔRÌ>,龉L037`33³Ü€ÍÌÌp633[À ØÌÌl7`33³Ü€ÍÌÌ÷ùó9iiƒNîídIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/new-symbols.png000066400000000000000000000022411474050137200252050ustar00rootroot00000000000000‰PNG  IHDR€€°¾ hIDATxÚíÛ¿‹eð©B„4’B dŠà<Ï"Mš4Ö‚…?ª‹Çj„CAŽ€EHk!„àX¤ Š]E,å8¤¹Ò2Åù÷:ÏìÌíîå.Ö™çó‡}o÷šwwöù¾ïÌNU ê‹õ¬«¶«2TŒgUÙç_ªjÖUÛU*ÆiæOU<>(þ~T¼ÉD³Ûýú|)O«•Šçâµó÷õRnm¬T<—aþÇÿñšôü¿ýf£,?†Ÿv릫6µf~(ô•iÞ¹Å*wlþ³íEóÇCLv%ØÏ¿kô›^*íg‹ˆq<7„Àdç?¬üËÿÔdçÿË÷ë‡Ë{·ê²\¿ïÖVÄ›q(œûè\9óþ™16Ì›XáŽM?>ø“ÆS^÷ó~Ì9—ÇñÚ”çÂêÿ0Ó.ààkí“ýWKT×ð›húßmÕåö‡óÇø;vo}œ½q¶T[•È$Îw¾¹Û}ùOÇÿLzþê?Vü'§<ÿ²=ë>çRž[ÝÿLuþ{÷¯µåŸ£hcÅïÓºüºSFDÜÙ™ü. €›»åËË “1–þñȧÕäàa[ž[Ó€f €_ÍþÏ_ÌwÙ šÿç7jÉx (Îùo¾½hþ1¯d8´|¨Z:ý“ðPª Á]ÌÆøóf}Q÷n̯|òÞä/÷P._*¥^™¿<|øé.G£ï¿CÓlj/f¸ÜÀf@ÔÁ_uÙ¿óf¿ˆŠ@¸½[7Ýç?õfØ@{ᕾ*‹ŸúhÖŸŽ;€±Æ ÂQeÿZÛU†û!V~š ôXæF07‚e¼lï~Ýüöã¥õà‡7N­ ÇÀ“Ÿô7‚iþÀ ¤TU“tÞ³®Ú®ÊP1ž9"r¨/ÖÍ•+W>öNV4ÿ¡ù¥ ¾ÙoÏJ¹Û–‡mé+Æñ\÷š#còš.J5?î…9õÍ?šßúzI4çÙÐèçMÿi)GïÅü5;©tõN5†dû «ÿ!²ìúÕ4þ¨“B`þ¼]Àă٬.W¯ž$ýŒç¾bp4çE³_ x-É{‘ùð/õZiο,Hxô/Îý¯@†]ÀJœ ÅW`ã­²öÚš áÑ¿øåË3•`îí)§}ÊÒ©!§€¦­™ .“ÌÊêÿÙÀäwG—wË!à"p Êõ­ëš?¹Þ÷cÍh´ë÷î=gȧ¿áOøw>ÎSx¦á—ð1LBÚØÃD:ð{àW˜¾½CIž¼Ó—w(ý ßÃçð-L_Þ¡´±O$ 1ø1ð5| ÓÏonõ2@:/ë×aúñÍZ²ÿùÐÆ> ›Ò=ò!¼˜ž¸²Ëh ª ¤ófàmx¦®ìí-ÙÛ?sd@-Oc4°L‡h€h=°ŒÚL˜ÞqQoJ‡h Ž8m=p#nÇ}§W\Ôû´dÛ¤ È€ZžÆh€!ceÄPS,£6X+„é}îU1WÔËg¨ pZN^— ܱ.Ô±§­£nÄí .®£Y§›kYvmþAlüŸèšßÃeÜ5ûÀJj?¡ö èa>‘€j¢A×Ô˨ÍF4ÓW¶8'prîÜŽûŽL\Ùû´m.K È€ZžkÍ80zÖP›˜~~s9§åäP— Üq¹,½= ½å²Ô€6öð1âšz`,fúöå´uôÀ`úòÚ.K hcCg Óg‡ó%—¥´Î/ý.¡mìášþ¬z/ H[¶4 mi@ÚÒ€´¥iKÒ–¤- H[¶4 mi@ÚÒ€´¥iKÒ–¤- H[¶4 mi@ÚÒ€´¥iKÒ–¤- H[¶4 mi@ÚÒ€´¥iKÒ–¤- H[¶4 mi@ÚÒ€´¥iKÒ†çó*¡^1¶IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/roundbutton.png000066400000000000000000000022311474050137200253100ustar00rootroot00000000000000‰PNG  IHDR@Àc×K pHYsÃÃÇo¨dKIDATxÚíÚ1kAÇáýfbe¬-EìR%† …¥­]A !"$ˆ(„TÉA@,EðŽƒèLj›L2L}dÿÜOqåÜ{³ïïŠíþ^]/Þÿ¨Ÿƒ„»=¶Ýi9ÿ³õ·“çoNŸ½>‰<3ÿH;gUâüëåI½?Íüuåkl¼ûÞKüúc÷w(7`eò¹LÀ†( (ç]¯vø¡®¶±wQD`ï¢, Ô€Ý ?”€ ØÀ€• „>ÂÑõª“ÏÕÅ/ Ý©4ªe$`îÏw&tþÑõªÎÕEOŸQ-P°UøÓÃx&`†€!`&`†€!`&` `€€€€€€ ` ` `€€€€€€ ` ` ` `€€€€€€€€ ` ` `€€€€€€ ` ` `˜) `ðŸöøÕIâ=v{þl[GUäü7­~øtÿÁ“‘çoæió°Jœ½<©÷§™¢Û€­½üÚKüúc÷w(7`eò¹LÀ†( (ç]¯vø¡®¶¶}\D`û¸, Ô€Ý ?”€ ØÀ€• „>ÂÑõª“ÏÕÅ/ ­# hTËHÀÜŸ%îLèü£ëUœËKÜÛ0[…?=x 00 0CÀ@ÀLÀ000   @À@À@À@À000   @À@À@À000    @À@À@À@À000   @À@À@À000V6`Ó?‰_ ôØíù³MæUäü'³O§¿?~ûµÿågæùçáfUâüë剽?³h·;8¿ìEþç—ý ØÍäƒ ˜€ PP$Î?º^íðCu7;tQd`QPlÀÙLÀ†¬d ôŽ®W|®.Í- Q-#s–¸3¡ó®W p./qpo TÀlþôà-DLÀLÀ0LÀ 0CÀ@À@À000   @À@À@À000    @À@À@À0000   @À@À@À000    @À@À@ÀX1ÿOÅÝ?HÆÒçIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/scrollbar.png000066400000000000000000000153131474050137200247150ustar00rootroot00000000000000‰PNG  IHDRÀ«¯1gAMA± üa pHYsÃÃÇo¨dmIDATx^íM«­ÙU…ó/üöí¤°c/M‰6´•†ˆR¡lÄhT¢ø‘F%¦%Á\ ˆ’DìÛ{iH¥iÓŸPnæ3Ù¬«Î©µßõ1Ã<Åy?ÖœkÎ9n}î=õ‰ÿýàƒËùïÐÿ„äR ~.ô‰\*Á×Bß É¥Ë¡ÊT\.•€*Sq¹TªLÅåR 8ÿÂ’|.qb´äR §yç3ƉђK—C•©¸\*U¦âr©T™ŠË¥pþ…%ù ðŸ¡ÿjÄ8!¹ù@~!ôó'$7È›Ð;¡o‡¾b´äæËÉ2‡²ü!ºBn>,s(Ë¢+äæ¡ÊTœêÓ t…Ü| iCu%ù À¨äÜ„ržBró0*97¡œ§Ü| Œ cÃ1NŒ–Ü|9YæP–?DWÈÍ’eeùCt…Ü| T™ŠS}:®›$m¨®$Ÿåë¡o…¾ÓˆAŒC%oçWBŸnô‹!&§§‘<¾þüž^Œ–<~9T™ŠgùCĆˆ–Èåñíd™Ñ tE¶HˆÎ‘Ç·C•³äÎ?ÿ´¡º’|>Ê@I(ʹ 1NŒ–<¾Æ g"Ĩ069Cäñíô石҉ђÇ/‡*Sñ,ˆØÑ¹<¾,s#:®È Ñ9òøv¨r–¼ÓùçŸ6TW’ðǾ¢ ­(¥Êé 1TòÂÅ|>ôV賆œŒƒ!ÆI^¸˜7!¾)ã´œŒÄhÉ /‡*gÉCt]‘-Òˆ.Ê– É C•©ø­ôwe[„è–lEwÉ C•³äˆ.¢£Þ„ä…‹Iª+ÉGÈÑú9Æ&g(ÄhÉ C‹ÓîÙû!F"ç#t›™»'FK^¸˜7!ÚÖÏ9x@Œ–¼ðr¨r–$:®{’-¦’6TW´ z¼]PÛ4ˆáAŒ“œ×å°Wn߈Ø2Ðñ“Q¦×ˆÜó B·YºI¶»þ ôócЋwÊv—C•©Ê„^ªêkÑWA¶»ªœ›…ˆ!jD´DžÉ„È1nÄiÈv—C•³ä‰wÒ™²Ýå¤ ÕUvM¨o¶iPvM¨oš1Zr^—Ã^¹}#bË@CÄOF™^#rσ1Z²ÝåЦ´löïEâ²ÝåPeª€²¡—ª€úZôUí.‡*çf!bÈ€-‘g2!rÌ„q²ÝåPå,ùEât¦lw9iCuU½ª0mJËfÿ^$Þ)Û]Næè¥“ïÏõ'OgÊv—“›…ˆ! -‘£L&DŽ™pˆÓ@t¦lw9T9K~‘x')Û]NÚP]ѦÙA¡¾PÛLÙA¡¾m$çu9´){¡Ü>Dlhˆøez!rσÉv—C›Ò²Ù¿‰wÊv—ÓŸ9zéäû3GýÉÓ™²Ýåäf!bÈ€BDKä(“ ‘c&â4)Û]UÎ’_$ÞIgÊv—“6TWm2´lÛL(»)ôRKõÍ„Ú÷φ–¥}sû±!¢ÍÐCd”é…2íl1•7!>Îç£ýìè!1²Ååä7;gºîÖ~7ÉSÉíCVˆh3ô‘Ê„Ct([L…*gɇD§Ñu·ö»I¶˜JÚP]µÉÜz÷&Z9{*”=z½±²›µïŸ íK+çö!bCD›¡‡È(Ó eÚ!Ùb*·Þ½‰V¦­³Ç‡ÄhÉ—“GÜhìœéº[ûÝ$[L%·eX!¢ÍÐCdDv(Ñut l1ªœ%F×ÝÚï&Ùb*iCu%ù´õ3í%/\ 1´"6¢EÄOF(“ É CCÓÜ4zvýb´ä…—Óž*jOõ§JGÑ]òÂÅd@!âDDN.ˆìÈ·•¼p1T9Kþ€è":Šî’.&m¨®$§Ý³ËBm“¡¶ÉÐ íE ­ˆhñ“Ê$CòÂÅÐâ´;­Ÿsð€-yáå´§ŠÚSEý©ÒQt—¼p1Pˆ8‘“ ";òm%/\ UÎ’? ºˆŽ¢»ä…‹Iª+ÉçcÉ^kôzÃÉãÛ¡é‰- ?"#²“Ç·CÓ3 CNF'FK¿œ—N²=ÃVòøvˆŠh‰e2!r¤säñíPå,y':„n¡säñí¤ Õ•äó±Ðp­ÚæËŽ ÑvòøvbË@CÄȈìäñí0Œ㑳҉ђÇ/祓lϰ•<¾¢"Z"G™Lˆéy|;T9KÞ‰¡[èy|;iCu%ù ðz ÊÍBœ(C‘‘Ü| CÂÀ0<Œ–Ü|9/]!7Ñfè!2BróPe*NõéºBn>´¡º’|`T^jD¹ù@ˆeè!2’›„Qal!Ɖђ›/ç¥s£+äæ!Ú =DFHn>ªLÅ©>@WÈÍ’6TW’Ï%´M)—JÀðÔŸ¿ÍhÉ¥Ëᔨ¸\*ñSq¹TªLÅåR Ò†êJò¹Ɖ֔K%`œêÆÏ81Zrér8%*.—J@üT\.•€*Sq¹T‚´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡ºúàIžÇÒ‹¼ä¶c©®·^¤y,nH.• C/«†è¥Škèfª+ç “¤y,nH.• C/«ÖŒ*®Ó@ßÿÉû‚ÔéXˆö½½w§–Þ¼(ŒgÞJÒ<– 7$—J¡—þÓZR­µ t3÷/Š t/zYá?˜QÅõ‡ ´µ!©Ó±´1…‘ÛŽE‚/Gk ¬‘¤y,ï4’K%ÈÐË Â…*®m ›‘àË]r欑¤y,9Ç!¹T‚ ½¬Z3ª¸þ™2з?÷ö †Yn;–6þŠ`—œ9kCÒ<¢ýnH.•€øë ÿi-©ÖÚº™6þŠ`šœ9kCÒ<¢µîþƒU\ÿŒè»ßx÷† t=˜&gΚÁ4…hm »„ áB×6ÐÍܼ(˜&gΚÁ4…hm »ts¢4¦*kèfî^L“3gÍ`HšÇB´6Ð]ÂZKªµ¶næ~àEÁ49sÖ †¤y,DkÝ%ü3ª¸¶næ~àEÁ49sÖ †¤y,DkÝ%lª¸¶næ~àEÁ49sÖ †¤y,DkÝ¥ÖŒ*®m ›¹xQ0MΜ5ƒ!i ÑÚ@w ÿi-©ÖÚº™ûÓäÌY3’æ±­ t—ð̨âÚº™ûÓäÌY3’æ±­ t—°!\¨âÚº™ûÓäÌY3’æ±­ t—Z3ª¸¶næ~àEÁ49sÖ †¤y,DkÝ%ü§µ¤Zkèfî^L“3gÍ`HšÇB´6Ð]Â0£Škèfî^L“3Ï™IšÇB´6Ð]†p¡Škèfî^è^ˆ¿®Z3ª¸N•©¸!u:¬Óº è^ˆ¿®ðŸÖ’j­m ›‘c/‡ t/Ä_WøfTqý!mmHêt,DÛÂ0ËmÇ"Á—£7ÐZfD´H.• C/+lª¸¶nF‚/‡ t/zYµfTqM焤NÇ’áv’ÛŽ%Ã-«¿ IóX2Ü\*A†^VØPkIµÖ9½¤NÇ’áv’ÛŽ%Ã-«œƒN’æ±d¸!¹T‚ ½¬Z3ª¸.c4Æs6PcŒÄjŒ1ƒØ@1f¨1Æ b5ƘAl Æ3ˆ Ôc±cÌ 6PcŒÄjŒ1ƒØ@1f¨1Æ b5ƘAl Æ3ˆ Ôc±cÌ 6PcŒÄjŒ1ƒØ@1f¨1Æ b5ƘAl Æ3ˆ Ôc±cÌ 6PcŒÄjŒ1ƒØ@1f¨1Æ b5ƘAl Æ3ˆ Ôc±cÌ 6PcŒÄjŒ1ƒØ@1f‡ ôË¡¯†äR ~7ôµ\:bFréþ#ô½FÿúVè¡¿ }¥ÑŸ„þ ô…¼vŸ }*ôK>úåЯ…>ú­F¿ú|H^»Œo^$yí2>Q]’ÏGbÝ1#¹t6Pè3¤ Õ•äó‘Ðô’K%øõ6*—'»;$—á¡1ëÄz¾’×.ã3¡tÍPo¨5ÐÖ:¿’×.ƒ?\¿ÿ„xƒ¼viCu%ù|$´¾ t=é!¹t6Pè3¤ Õ•ä#üU({?$7Ο†hýßÉ Çò&”=â+rÛvø¾µNô¸þsH^»Œß õÖ‰^·NôNH^»˜o‡²QOÉ«“6TW’`Ýv™â+rÛvl 6ÐgHª+ÉGøËPÛú’ÛŽå7C´>úÇÜv Œevzˆ¯Èm‡ÐèãÖy·*½öÖ‰Z%yÕèl”‡ÅSòªÅ¤ Õ•ä#Ø@wAsg§‡øŠÜv6нÐÙ(‹§äU‹Iª+ÉçÎß„úÖÿýÜ| Ê®Ñú|(!7ß^e§‡øŠÜvÄö¸uR‹~5ôÓZ'ÙÉ«¶ÀÇ;Ù(‹§äU‹Iª+ÉçŽ t/XRvzˆ¯Èm‡@l6Ð]`…Ù(‹§äU‹Iª+ÉçΟ‡úÖGróÐî}ëÿQHn> Ú:{¼Wå‘íükÅVÐKýóVH^²>LÀ:ƒÚþ!$/ÙŒe£¼ªï„äñ-¤ Õ•äsǺ ,2;½Wå‘íØ@OÀºA’Ï1Ù)!ˆfúzH<„ e‘Ë¿…äÁCàÛìôN\•G¶óï¡ö›÷Ö:çOÿp¼d#ô<ÖÙ~óN´DŽÈåÌTBod£¼*~Ü'o!m¨®$Ÿ4-N» ˆ–²Îãõ1àª<²è ÐÙ(¯Êz™$Ÿj€Ö¡™h¬“”ô‡!â$fâ'ò:ùG¾þWå‘CøëæÈ9sæœ?µ8ùŸ3üFˆÎAÄLüäB^òà!ðñN6Ê«:ç?€Ò†êJò¹aÝ ™Þ‰«òÈ!Ø@÷bÝ Éç-B»Ð:´QöTˆV“%fâ'òb¼uyp;´uöø«bTäñíðÇçÌ™sþÔ‚Îá7yðøÏâ$fâ'òâ?/äÁ£àØl”N\•G6’6TW’Ï …¦¡h& Ù@g`Ý‹ t=iCuÕ&ÃGã´ ­ƒh&‹Øù¸ÞÛ7ìs$Z"'Äp?îàGò’ðÑ~vú«âÇòøvøÑ§Íù#:ñ#>yðøì¥þ¡sNëùz#¥W呤 ÕU›Œ t/6нØ@ד6TWm2Ù)!ˆfÊÞaˆ¿~ܾa/üõl"GäÒZ'â¯|ó׿å%á¯7g§¿ªÓ¾káŸ*pþmÿ°–›„ÈQÛ?üÓ¹ù@øx'¥W呤 ÕU› í‚h šž@é!èµØ@O€ÈQÛ?6Ф Õi`+´ ­C»Óú¨ýæ_»À¯`¸ŸÅFøÆ„˜‰Ÿ\h}²C|óŽžcC´uöøÃâ)yÕvøu-Ô"['įw‘›„%õýïב›…ÞÎF ñ¹m;iCuE´Mƒõ`V˜þ°xJ^µè ÐÛÙ(!¾"·m'm¨®HƒvÁzúÖï­“_=˯¡½ŸÅFø0øÉ¥m}ÔZ'?®á×Ë«¶ÀÙé‹§äUÛáWVgë„øµÖrÛ±ð+ÃÛþá׊Ëm‡Cod£„øŠÜ¶´¡º" L²®‡æÎNX<%¯ÚŽ ôèl”_‘Û¶“6TW+ÖƒZí­µÊÿ–KÎeü/ɈüqëD(ÿ[4yíbøö*;ýañ”¼êøç ôÿk?¹áp²uB|(!7ïd£„øŠÜ¶´¡º²Ú@g`Ý v™â+rÛvÒ†êê‹! è%ëD½u¢Ï„ä\–ñ¥ñ?n Xç÷B?Ék—ñµPöøxƒ¼v;|¨òë!¹TþQ ý#— Á?®EréÒ†êÊj ôÒ;CréÒ†ê ëi­µú’u~*ôÉœË2¾³N´÷[øìî§%¯Ý¶ŽÊ¥|5ôå\*U@réÒ†êÊjCkÝ U@réÒ†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êJò1Ƙe¤ Õ•äcŒ1ËHª+ÉÇc–‘6TW’1Æ,#m¨®$cŒYFÚP]I>ƳŒ´¡º’|Œ1fiCu%ùcÌ2Ò†êêƒKÅ;匦‚ÞÿÉû7ÞûÑ{¼ûwo¼ý¹·oTŒvÅÿãÐ[—J¶˜ ñ7ôNè“CâäOˆL»âG? ]µ–-¦bµ>Ìà]%Ùb*ÄßP:âO)Nþ„øÇ´+~„ñ]µ–-¦’ÊÑŽ1e=¦‚Ú[|è 0û>¯õü!²æEäH¶˜JCzáv?–Ç\µ–-¦bMl c0Àìû¼Ö° í:ÿ›ë}¤ >³–-¦ò!•™ü©À†(ƒì1ÔF‚•Œ±+þêšS؈Q|\DÎZ¶0¯Àù×5PÔÚßókÙb*6б+~(‘³–-Ì+pþ6Ðv-[Lå2Ý5Àìx­d‹© êúÌ3´DÎZ¶0¯ðüù£]çå1W­e‹©Ø@?B²ÅT ”ÈYËæž?´ëü[ã»j-[Leé°™T×@Í^ª(jíïùµl1Ûf ÔŒaíײÅT ls-symbols.0.7 -------------------- Obj=symbol name=ColorOptions Image[0]=> ls-symbols.0.8 -------------------- Obj=symbol name=Flags Image[0]=> ls-symbols.0.2 -------------------- Obj=symbol name=Message Image[0]=> ls-symbols.0.0 -------------------- Obj=symbol name=NewYear Image[0]=> ls-symbols.0.4 -------------------- Obj=symbol name=BusStop #Image[0]=> ls-symbols.1.2 Image[0]=> ls-symbols_stops_new.0.2 -------------------- Obj=symbol name=TrainStop #Image[0]=> ls-symbols.1.1 Image[0]=> ls-symbols_stops_new.0.1 -------------------- Obj=symbol name=CarStop #Image[0]=> ls-symbols.1.0 Image[0]=> ls-symbols_stops_new.0.0 -------------------- Obj=symbol name=ShipStop #Image[0]=> ls-symbols.1.3 Image[0]=> ls-symbols_stops_new.0.3 -------------------- Obj=symbol name=AirStop #Image[0]=> ls-symbols.1.4 Image[0]=> ls-symbols_stops_new.0.4 -------------------- Obj=symbol name=MonorailStop #Image[0]=> ls-symbols.1.5 Image[0]=> ls-symbols_stops_new.0.5 -------------------- Obj=symbol name=TramStop #Image[0]=> ls-symbols.1.6 Image[0]=> ls-symbols_stops_new.0.6 -------------------- Obj=symbol name=MaglevStop #Image[0]=> ls-symbols.1.7 Image[0]=> ls-symbols_stops_new.0.7 -------------------- Obj=symbol name=NarrowgaugeStop #Image[0]=> ls-symbols.1.8 Image[0]=> ls-symbols_stops_new.0.9 -------------------- Obj=symbol name=Passagiere Image[0]=> stations_status.1.0 -------------------- Obj=symbol name=Post Image[0]=> stations_status.1.1 -------------------- Obj=symbol name=Waren Image[0]=> stations_status.1.2 -------------------- Obj=symbol name=Happy #copyright= Image[0]=> stations_status.0.0 -------------------- Obj=symbol name=Unhappy #copyright= Image[0]=> stations_status.0.1 -------------------- Obj=symbol name=NoRoute #copyright= Image[0]=> stations_status.0.2 -------------------- Obj=symbol name=MessageOptions Image[0]=> ls-symbols.2.3 -------------------- Obj=symbol name=Electricity Image[0]=> stations_status.2.0 -------------------- Obj=symbol name=InTown Image[0]=> stations_status.2.1 -------------------- Obj=symbol name=Seasons Image[3]=> ls-symbols.3.0 Image[0]=> ls-symbols.3.1 Image[1]=> ls-symbols.3.2 Image[2]=> ls-symbols.3.3 -------------------- Obj=symbol name=networksym Image[0]=> ls-symbols.3.4 -------------------- Obj=symbol name=timelinesym Image[0]=> ls-symbols.3.5 -------------------- Obj=symbol name=fastforwardsym Image[0]=> ls-symbols.3.6 -------------------- Obj=symbol name=pausesym Image[0]=> ls-symbols.3.7 -------------------- Obj=symbol name=CompassMap copyright=prissi Image[0]=> compass-map.0.0 Image[1]=> compass-map.0.1 Image[2]=> compass-map.0.2 Image[3]=> compass-map.0.3 Image[4]=> - #compass-map.0.4 Image[5]=> - #compass-map.0.5 Image[6]=> - #compass-map.0.6 Image[7]=> - #compass-map.0.7 -------------------- Obj=symbol name=station_type # used in line display only currently # the number is the stationtype (emtpy images must be defined as "-" # loadingbay=0, railstation = 1, dock = 2, busstop = 3, airstop = 4, monorailstop = 5, tramstop = 6, maglevstop=7, narrowgaugestop=8 # maximum size please 11x11 Image[0]=- Image[1]=- Image[2]=> ls-symbols.4.0 Image[3]=- Image[4]=> ls-symbols.4.1 Image[5]=- Image[6]=- Image[7]=> ls-symbols.4.2 Image[8]=- -------------------- Obj=symbol name=MessageOptions #Image[0]=> ls-symbols.2.3 Image[0]=> singlesMessageSymbols.0.0 Image[1]=> singlesMessageSymbols.0.1 Image[2]=> singlesMessageSymbols.0.2 -------------------- simutrans-124.3/themes.src/pak64german/files_large/singlesMessageSymbols.png000066400000000000000000000012011474050137200272430ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆgAMA± üa pHYsÃÃÇo¨d#IDATx^íÖAJÃ@†áÃmÁË.¡è®¼x^À·è%zÿf’8ù¤i?ÚÌÀ;<È$ša_Ò.~ª ¸A’èqs÷¸YöÙ }ß­0¯E¸ß!ÞöÐ<#5¹¬¢ùÈ}·Â¼ì”«vévþ’¡€zo—ö²“¸ïV˜×1 ÐÍŠ È„ÍÇ?s“ÞÓÄ·N|ß­0;;îÒë)Bú|ÛDb¹$ï»rêyûþš"~pvuùÇas·Ï!ñã·4P“K‰ßŒ~ø³ÃµI|ÖIîñ|ØÞrÞ: ÷×Õöyùp¿ˆ‰Åé4Ü ó õ„:É­ƒ‚ß@/OËÏmP/—R¾5µ/¡ã|tÌøê1¶·f—Ã#»€.n…yÙéÇ£ÙâðÈ- Ûs7/5 ý~8v»Ýz½¶K›Øeõï+›„›ö—véVÈGæÿ€“J èÜáVÈ]U: úEsÞp+䃀®j0 ûä²âþKÍu=º?s+äÃw ÷T>Ü>‡¸§n&0AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$ AB@$AUý:Ú#èqIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/skins_neu.png000066400000000000000000000401151474050137200247260ustar00rootroot00000000000000‰PNG  IHDRÀÀºG/$gAMA± üa pHYsÃÃÇo¨d?ïIDATx^íËr]Éu¦ñòxØ~€õÈs4èžt;<•{⥰[7וU4Ä« BE U*’ª*’‚+XÁué ià¶tGôCTÿ;¿TFÖÚ JàäÞIü+¾ÈÈsNî<+÷þ×ÏÜ8‡ÀÖ»ƒÇ?ýŸCsðôî?þ¤tè—¶°ÿà mÝ9½Êlâ7ÿþÿ^|úu{\wJ;Hÿÿ|öÙÐܾùÏ{·®~øÞïýàþÞ­ßÙùàÝ;ww¯ÿøÎw_<{²{ýíé¥woï\~MÏüxï{ÿè½=¼}ý²Úƒ÷ßÕ«:êéãŸì\yãþþ÷Õj€Ô„Ï?þÙ¦çË1±.L1#ÀõJ;g¬ûÅ1 e¶€¬³¸g³‚ž†ãöÍíƒ?’1Ý¿ûŽ+Ý}禌ìÙ“‡»×.>¼§—äVÅÝd¶{í­ûû»îýp:Pw÷v¾#£ÔÈÉÝ®]Rû«çOõ̦çË1ÙÚ<‚ ‡ž oô4²ªÝ+oêŽXí×åPÏ?þÙäSÚ'^¿,Ï’[É×ò&QžõÞd[i·¸“ìïæ·_yþÑO5R¯Êé´sœnÆÓwà§½ç†çË1ñÏ@¦6#m#“[‡†•¶~u¿¦Ì_·G‚‡†@ýLÐÓpÈÈänr¢Ýkoɹänº}Þ½vI®'“Ò¶Üjr·ôöɹöwåqr·éÛEwv´µ|ñìpz2íw'¾£ ã4>ݰotþ°Óï@¦¸’a•Vötò7ÞK§´Ç=œSÞ¨îÌÁCé„™ AOÃ!w“Mßx÷γÃG²*y–¬Jö¤‡2,>º‘ñÙãÈ´%ÔQÓÞ{íko±1ÔKÏ?:Íéáô#Î Ï–c:c]˜âDò):2©ã¨_¥d{å]è”6P¬“>Õrlý.AOÃ!ŸÒ­´êðá½»»×¹Ý–==}üÝ#'wÛ—÷©¯‘º}æU™Úän‡e޲Â4Ãõůž¬Ù´‹Ôl2¸MÏ–c:c]˜âDBÆ$Nþ?BPÓ)íüá‘È ë¶îŠiÒÖ0 = †5}ä½÷=m oßÜNéL?…ÜÛ½&wÓFïðÃ÷ätju?>9Wú_@r@+/Ó!£¡žÿí¯_è@®ÙôªÔ 5wÙz¨Žvˆò5¢azRüö×?Ÿl1ý¾%ͦcµIœünÃó‡å˜ÎØ@;“Ó}¡2¬tŽ|XÚ“‘ÒÖ9ciéÌaª §á%ɘtï,«Âݦ[ìô(õÌÞ­«r·—_ÕQÏȹd‚Ú*jo¨—0Aí?ýù3½¤!‡hè¾f†Î–c:c]l«=ô84²îÔË3u' w©;øcéäu§˜&0= ‡ÌHÞ¤{çt§<¹ÛÞî5¡ÍÚgOîl¿®'Ó°+3}—S{ÀänÓÞpï{Ÿþâ“é;IÓ¦rú}Ú'ÊÝÒÿ&šÜsÃó‡å˜Îøg  S›‘[}¡‡ ¬;¥…º$z—º=bšô9¼~Ç §ámi»'än‡ïë!Æ4¹Ûá#Ù™ŒìþÞ-œ|íÆÛÿ”6Ó—Þq·_=ÿXûGmånz>¹Ûôkè’ÁMÿ±}Óó‡å˜Îxº0XR@n%{š;©^ ý#ÛBx(4sÝ m¡8fy¨G¾EÐÓp¤ÝÜäDº‰ž>±¹÷ÃÛ×/wû }ýHv¦17Þ~%»[ò2Y˜Ümûµ¯«0}!馶‡²¼ÉÓ/RÒ!špÓó‡å˜ÎØ@¦6#!·ª[¹Õ‘èÕºSZ¨ûGRæ¯;âž0 Ð3AOÃ!k“==xúÜF÷ÈéWs>?|Ì]óá‡ïé¶Zí ¹go(ózñÉ¿¼ùõ¿Ñ“éßi§)wÓøìn{·äwÚ*nzþ°ÓèÂÔ~„[…‡jåS=3ïÐ/m!<å-ÊäP÷AZÏæW‡~ÐÓpÈŒø\÷׺A–I¥o½%›>홾3”ÜmÚÞÐqr·½[/ž=ùæßþÕÓƒ4F‡hS9¹ÛÃû¼·óõ5U¹7ßèüa9¦3þèÂKª‘ÑÖ<«8בµuç8Ê´u[£g˜¶ž¹n AOÃ!w›¾µ~ð¾üK~¤ÎÎå×´¹Ó¾›åìné÷rj'(ƒ{þÑÁ?ýý_'w{W‡ànz¨ÁšJ­ÆLɽ侀éùÃrLg¼]˜ÚŒp.Z:ÅÎJS+.L­tB¿Àl¥S¦-è(Ыóê~ÐÓpÈžÞ“ɘ´7¼zéÛÚô=;|4™×þ÷¯^úÖtg=ý%¸|÷ýÑÁ›ßú»gO¦“£ÉÈ4^íÎöëÉÝv¦ “»É.7=XŽéŒ taŠäeu[ÃÍ5èÕº­;' IꎜðÈ'k‚ž†cú©âÞ-!_»ñö+ºMÖ}ôÁƒéæšßß¡ŽÜJûGÙÜóÃÇÛ¯þ£ìŒ  ÌQ÷âÙ¡ú7.¿*w“'jy?÷ÜÛ¹²éùÃrLgl  S›Qíkt îŸðÌ­í8›+診ЫóöÈ'ƒž†Cû¾ûw§?¹{í’6}Ú$²7ä§–²¿é“t¾uôä¡öÏ?ú)?©œ~OÝ­«Ú êØí7¾¡1ºúøAq7y¢|pÓó‡å˜Îøg  ƒ1ÍÁéJ; õŽ|RGÑ è¥Ð-”~ÐÓpÈžäVé»îûr´GéïºY–µiŸ8í¯]’gMm¿®ûk¹›œKÖ¦VÇjÛxõoÊuàÓƒ4Õän²9~1]úÂüFçË1ñtajW¸[éC݇➴ÁFÕêy& ð¼Z™£—Žì„¶ ‡AOÃ!'š\i÷ºìL¥›bÝSkß§}¢n±… ‹Ñ_<{¢—&k›~d9™Z¾~$´sä¹›nØõŒpš|Ãó‡å˜ÎØ@¦˜QmyÅæhëN¡öÐÒápœ® 1|?ÿäÿ螺u§´u‚ž†C¤}œ<ëùác¹Ur·ûºYÞ½ò¦ÜM7κéÖ>Q{ÃéF{çŠv‹»×ß–—‰o¿"[Ô>1ÝPOϤc§ß–¤þ´÷LºÑùÃrLgl  S›‘(&HGmÝ™Sl´†vúÿh_ú¡-”‡AOÃ1ýšwµ7”mÉ›dU22ö†ºG–aÉÑ^|ò‘ K{F݉ËìnßÜÖ“2;m$uÇ­{põ5‰6’25Ý›'w›þ~‘fØôüa9¦3þèÂKª‘ÙÕí¹dÝ)ÖYSÏVï:OÞj|Ý -ÔÏ= Ç£{ûÏž<”ɳdgº;–1É´õÓm²žüôŸh )wÓí³ÜM^&S+O”!ê@"S“ÓánÓ‡BÓGFÓ¯þÔøMÏ–c:ãèÂW ÈõhDþH[:åaž”ÍÉ+Oc½ï¼-”1ô4ºw–£ÝM¿éC»<õeXÜ8ëÉ_=*/;xÿÇzRn¥—“»Mbsú)¤ÊÝÒ-¹¶„6mÓ_ãЫ¸ç¦çË1±.Lq"åÍÛº˜cÝ/¦YÐ!…Ó{¨—6<,-ÐzŽüm!¶xéO¶É­ä\Ú¾xöD~7½ôîí˯é™×tKžþ¸›ük²Â÷ßÕ«:êéãŸÈ×ds¸›Ô„Ï?þÙ¦çË1±.Lñ#™`é—‡¥ ÈëN1MÐ!µÓôän? Œ/mMýLÐÓpp7-cºŸ~?±\éî;7edé¾ûRúæôÓÆânÓf0ýS[ÅGéoOwµm”Qjään×.©v—·®nzþ°Óÿ ta‚=É ë>Ôýì²tN°Îš/Ü~ÖýÐôdÐÓpÈÑ´¿KÛÀ;r%ö†OÞ¿qùÕÉÝî¾³³ýº|JÃän“¾{gr·»ïèöYm²¹}݆k’Éþ4,ý-#í.u”v‹›ž?,ÇtÆ;Ð… –$dˆóvÖY:6wº¹ë1Rè¥`@V?,-= ‡íðáýéçŒïý@[;ù”^ú¶,Ïâg”“»¥_„œö†i;™~±ñtTú5¦‡ÉÝn?{ò¡¶™Ú-jئçË1±.Lq"QÜ­ôÕ֦ɮsnjó‡5:°t4¬FO–6:™ÚôÇ9Ýû¡üN<ø‘ìor·ë—5Fè%Ô :\æ¨{óMÏ–c:ãèÂÔ~˜Zéàn=#Ûš›ZÝÖ/ÒÖè@ÐKó¶î@ÐÓpȰäGÜÝ~õäkîí«•ÍMÿå|ÿûò¾dpÓ_yÓ0ÝhOé×ÊíÊÝôðƒwoóºa;©£Rúßî|i£ó‡å˜ÎØ@¦6£‚Œ¬nƒµaaǵuçH˜–ýÒôP“Ì'¯g¦ô4ò ™šî¬åJSçÊ2µio˜|Jhß7m$'+ü®hϨ—´[Ôñwî6ýïuÝMãwÚ-Êé´ñÔ0m7=XŽéŒ tajK˜WéƒÆô|è—öäŽ(“Ó)í‘Ì?ž:rΠ§áUí^ySwÄêì¤?“ùüãŸM>¥}âõËò,¹•|-oåYïý@¶•v‹;Éþ¦_ùñü£Ÿj¤^•Óiç8ÝŒ§ïÀO{Ï Ï–c:ãŸ.Lq¢šâbÇ}gScêNiëÎqhÚÒ¡O'P>è/o$æ“= ‡ŒLî&'Ú½ö–œKî¦ÛçÝk—¦¿š¹wK7Úr«ÉÝÒwÚ'çÚß•ÇÉݦoÝÙÑÖòųÃéÉ´[üÝøŽ6ŒÓøtþÑùÃrLg¼]˜àGò,Ú¹uêù“;G¶5L^÷K{8©†9mÐÓpÈÝä_Ó7Þß½óìð‘¬Jž%«’=ñ§5øèFþÅg;|Œ# Ó–PGM{CîµÓßç'ê%~7N?âÜðüa9¦36Ð…©ÍHȪNó¿-5²î”ö4à†t áaÙ~Ò8°~Ç §áOéVZuøðÞÝÝëÜnËžž¦¿½‘Üm_Þ§¾Fêö™Wej“»>–9Ê Ó wÔ¿zþ±fÓ.R³Éà6=XŽéŒ ta°$!«Â:O6Pœ«tNhëè-êNý°€i–Nik8 ‚ž†Ú>òÞûž6†·on§t¦ŸBîí^“»i£w8ý Îju?>9Wú_@r@+/Ó!£¡žÿí¯_è@®Ùôªý ÝeßÙÑ~ðiú{Å22ÜMÖ&/ûô—Ïùa¥fÓ!šD¶¸éùÃrLg¼]%Èëö ‘y܉|°nëN@Y÷#èi8daÓfpç;²$9?””OÉé~·+Ü~–þfwÙz¨Žvˆò5¢azRüö×?Ÿl1ý¾%ͦcµIœünÃó‡å˜ÎØ@_+*N¶Q .mx¨¶fþLAžX·u䌥sLô4²$“îeU¸Ût‹þ¥žÙ»uUîvãò«Ú!ê9—LP[Eí õ&¨=ã§?¦—´1ämÕ×̰ÑùÃrLgl  ƒ á_µ~!:ääöHô.uŸ‡tæÈ%ë¶PÏô42#y“îÓòän{»×„6wjŸ=y¸³ýºžLîhÌô]Ní“»M{ýï}ú‹O¦ï$M›ÊéôiŸ(wKÿ›hrÏ Ï–c:ãŸ. þU·'{¨Æ”6¼¯‡Óän‡dg2²û{·dpòµéÏj¦y´—ÄÝ~õücíµI”»éùänÓ¯¡K7ýÇöMÏ–c:ãèÂàG¹ª&<ÉÃ/lçðG¶|³tÔjÀ‘Ó= GÚÍMN¤›èé›{?¼}ýrq·Ò×dgsãíW²»%/“…Éݶ_ûºúÓ’nj{(Ë› 1ý"%¢ 7=XŽéŒ taŠɧêþ%· 襺ÚÓS¿Ëœâ›âä÷ zY›ÌèéÁûÓç6ºGN¿šóùácîš?|O·ÕêhoÈ=8{C™×‹OþåͯÿžLþL;M¹›ÆgwÛ»%¿ÓVqÓó‡å˜ÎØ@&Ÿl«nAczµîÙÖÂ|þð°€u– KGmé¨ z™‚ëþZ7È2©ô¢·äbÓ§=Ów†’»M»ÂÚ!Nî¶wëų'ßüÛ¿zzðÆèm*'w{x_ƒ÷v¾£¾¦*÷æ?,ÇtÆ?]üHȳê.V:¢v±Ò í))3ÓΩߢž¿n!èi8änÓ·ÖÞ—ÉÔÙ¹üš6wÚ÷q³œÝ-ý^NíepÏ?:ø§¿ÿëänïêÜM5XS©Õ˜i#¹÷=u6=XŽéŒw  Sœd^u;§v´ºÚÐ$u§´ ~™g>--ÐzÙÓáÃ{r"“ö†W/}[›¾g‡&óÚÿþÕKߚ¿·“ï¾?:xó[÷ìÉÃ4`r4™Æ«ÝÙ~=¹ÛÎ4ar7Ùå¦çË1±.Œ<¨6²úaÝ èù#}mÞ©áÀÒ)³ hLÝ -= ÇôSŽ[B¾vãíWt›¬ûèƒ?ÒÍ5¿¿C¹•ö²¹ç‡·_ýGÙ@™£ îųCõo\~Uî&OÔ ò8~î¹·seÓó‡å˜ÎØ@¦8ÈÈêöHÊ'ÿè§ü¤rú=u·®j3¨c·ßø†ÆèüéãÅÝä‰òÁMÏ–c:ãŸ.Lq"ì¬tB XgÝ6 u¿FãC«‘sÊótŽl AOÃ!{’[¥ïºïËÑ¥o¼ëfYÖ¦}â´¼vIž5}´ýºî¯ånr.Y›Z«mãÕ7¾)CÔO>ÐT“»ÉæøÅté ó?,ÇtÆ;Ð…©ÍS+µGrF…Óü—' «;¥-èaÐÓpȉ&WÚ½.;“Cé¦X÷ÔÚ÷iŸ¨[l!ÃâcôÏžè¥ÉÚ¦YNF¦–¯ íyFî¦v=#œ&ßðüa9¦36Ð…‘ Éç-Ô}(Žy$/‚Íô*îy–ÿòD+‚ž†C¤}œ<ëùác¹Ur·ûºYÞ½ò¦ÜM7κéÖ>Q{ÃéF{çŠv‹»×ß–—‰o¿"[Ô>1ÝPOϤc§ß–¤þ´÷LºÑùÃrLgl  ƒ dŽuÓ,92MÚfhØî:5,ôC[(ƒž†cú5îjo(Û’7ɪddì u,Ã’£½øä#–öŒº—Ùݾ¹­'evÚHêŽ[÷àêkm$ejº7Oî6ýý"ͰéùÃrLgü3Ð…)–T#³«Û9rɺS¬³¦ž­Þrž¼ýÔøºZ¨Ÿ zŽG÷öŸ=y(;“gÉÎtw,c’…ië§Ûd=ùé/>ÑRî¦Ûg¹›¼L.¦Vž(CÔ:D¦&§Ãݦ…¦Œ¦_ý©ñ›ž?,ÇtÆ;Ð…)®ëщü‘¶tÊÃ=)›“WžÆ: zßy[(c èi8tï,G»›~Ó‡vyê˰¸qÖ“¿zþT^vðþõ¤ÜJ/'w›þÄæôSH=”»¥[rm 5lÚ<¦¿Æ¡WqÏMÏ–c:³cŒ9%6PcŒiäe3ЭÏGxÕ³ZrѦøÒ—¾”{)ÂÈõðRYŒN4?ø+?\ó©¹÷Ì­%?ÏÿÈ'Wˆ’üêW¿zóæÍ?þø7¿ùÚ¯|å+ög¶æä¿à\‡‡kFy–Sèó‰Ç(ù¿LpþG<óÊyhÍ(syPÿü™5£<å˜òM¹§:+wOñ¹ä”+­’´Z>r]ù@IªhKÝ’|YË(Õ## [9J˜½†Ë\(ç¡ÿÝUÚÚÁ)Ô!äA< #W‹R•jªvýi.?¥‹¢~Ɉ¯¼Œrö•gIU± TyÊw´ƒVÚ@%´Á*”sù—l,”s9ùcå¯l îå›2 BÏèù0~µ(U%ÏtýiÇü”±ÔSsp S_`#Öª–üÕ´òÇ=‡;ùP–0~”$!ߤU`£¥ó¥/})µN”¿öËd.ëì”±Ô#ìžýQÎÅCÕŽµe«Ó.”¼ôü—“?Ü¿^„ëQÐeª$ÇHz¨üל|ÌL¹bì@ÇÒ ÿáÒ®Qæ#º'¼ô”“¯vÐü‹éب:aä !á##Œ\ŸËL‰–„ú#z(KÚ@…’7e>œl Ê™=ÿJ;lÙæÏ¬e«è9.EeŒ’ú´Œ¡>De;VÂ/:ÿãè {Pæóä|rͰ"<¿B¾à\‡‡ëGÙ¾;З€qÏ¿•³F¹ /›VtÞǽ4Æ€ t1têížÆ˜ØhŒ1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦‘l ?ý||õ«_-#†àkŸý´fëÓ¿.¿Lñ¯)ÂKCð)¶R„—ÎÎg,¼4œ%ÎXxÉt`(¦y» è_üÅ0„i~ù³ÛèÖí/‡aìk/ v€5„—ÎÎg,¼4œ%ÎXxÉt`«vÏ7~è—¿<€Õî¹õÙ×2É@·¾ö_Âà—’R|Tv@„Á+äRüaØŸ;ù4¥È§/g5 ^!ù4¥È§/g5 6çÎd Á=chqÏÿôÙ›`-¯J=×}Šì)Âàs'Ÿ¦ùô¥à¬†Á+$Ÿ¦ùô¥à¬†ÁæÜÉš3…Üs8-î™·Ÿ/¯¾•âfŠý*(x ÀÂá‹ó')þ¸Šÿœ‚‚ÏÕ_E8üÜá,qÆòéK‘Ok Î6g>¾8ù4UÁ™ä¬æSœ‚37g$hqϱ ô÷´¦‡/eœk:¥NÙg¨"~îp–8cùô¥È§5g›3_œ|šªàLrVó)NÁ™‡›3ò9 î9Ötîž/~­Šo¤ Œë ¼)õ\ý)0…0agþ2ÅŸ§øÓ*(æ\Ù)(x À„çg)Ÿ²œIÎj>ÅUpò%I&ì g‰3–O_Š|ZSp¶ó©OÁáê„ ÍïŦY¢vOE½B²i*÷´*„¡D)×\»)(é\ß)rݧÀ°†0á¹ÃYʧ,g’³šOq\…|IR„ ;ÃYâŒåÓ—"ŸÖœí|êSpE¸:aBó{1}MÓ,‘½s÷„lš…aÝ3«;E-q‚r¥€‰\Ó)(xŠŸÀÂ[l2!7²Í©§`Eyy)(l‚RÏÕŸSoqîp–ò)KÁ™d-+"N³®ð…³”OY Îd>­)rZ)È6§ž‚±:ÖÞœ@þž]¶Ì*ʈ!(¦Y† k<ÅÉB';AÙgH5„·Ø(dBnd›SOÁŠòòRäúNAÙgH5„·8w8Kù”¥àL²‚§YWx‹ÂYʧ,g2ŸÖ9­d›SOÁŠXë oaN`ã_T6'ƒÜ‰Ó˨EOPüvÞîÜá½òÛWAn9ÑäÏŠòòª`íùD¤ÀÂÛ;œ%VAä¤8nÄ|-óU„·;w8KùÍRCN¨ ²%󼘬1/¸ Šð^fŽ ta²êSÌ¥_‹žÈªO1—>@` áíÎÞ+¿}ä–MAþ¬(/¯ ÖžOD ¬!¼Ý¹ÃYbD^@ŠãVAÌ×2_Ex»s‡³”ß,9䄪 [2Ï‹IÁó‚«Ð©ïeæØ@f£СF7 yÎÄq™Ïs&æ™seÃÛ;ùÍRCN(Ù’9‘“‚5æ§àlº¬á½ÌèÂPf¹RÌË€¨‹!W@Šy”Ax»sÇJÌ3çʆ·;wò›¥ ‡œP ²%s"/&kÌ NÁÙ l §Áº"(¹ºˆ\ )Ž+‰y1á-6Jm¦ùíSA¶9õ¬(//E^vŠðçNN±Š¶<¹j\Áð%¿}ŠœV ²Í©§`E¬ŽÈ NÁUã †·0'`]”¥˜k"E®‰'F®†*Â[lÊRÌoŸ‚ܲͩ§`Eyy)ò²S„·8wrŠU´åÉUã †·Ø(ùíSä´RmN=+buD^p ®W0¼…9誡,ÏRaÂÎCäF¶ù³""/2E˜ðÜ©³"꬈yV\®N˜°39¡äI9k!Xë­#Lh~/l «†¥\s•¤¨‹„¨‹„XCyCäF¶ù³""/2E˜ðÜ©³"꬈yV\®N˜°39¡äI9k!Xë­#Lh~/l ƒ‘k¥Š“ &¾8-¹åDS?ÁŠX]8üÜ9.“:‡:Âá‹CVdKæD^L ÖÈ™‡›3b ¦ŽºxrŤ lÂá‹C“[N4ù¬ˆÕ…ÃÏã2©s¨#¾8dE¶dNäŤ`œùp¸9#6Ðá9¹„ÂàBžDN=+ ƒÏãÞ—³¯²Í©§`EDlÎèðPêÇR¼Bȓȩ§`Eað¹sÜûrVÃàB¶9õ¬ˆƒÍ¹c} ©‹*¼4ŸüyÎXxiÈŸ3^2°¾„`”Vxi°ƒ>ùó.œ±ðÒ?g,¼d:`5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4²õÙ1Æ­–yü×ÿö?D¶ZF¯}ûÚ‘„e®–v! [-!íáËèÂŒ¡ a™«%¤]ÃVKH{8Âr†#è¿ýû¿¸ÕB¶/>ýÂXZNø Pœóš°ÌÕÒ.„a«%¤=a9Ãa]˜rÂź,!íáËŽÏhmCaÜj©s†±.LH~8j¥a™«eÿÁ“# ÃVKH{8Âr†Ãº0!ùáÀ.m KÒްœáx© ”Òµö¤>çôÇ*ŒRÉ…»)°Õ’ްœá°.LÿˆÔçœþX…Q*¹`íIXÎp¼$úþލ‹9 [-å„J}ÎéU¥’ 6О„å ‡ taÊ ”úœÓ«0J%l = Ëè”>(õ9§?Va”J.Ø@{–36Ð…)'|PêsN¬Â(•\°ö$,g8l  SNø ÔçœþX…Q*¹`íIXÎpØ@¦œðA©Ï9ý± £TrÁÚ“°œá°.L9áƒRŸsúcF©ä‚ ´'a9Ãa]˜rÂ¥>çôÇ*ŒRÉhOÂr†Ãº0å„J}ÎéU¥’ 6О„å ‡ taÊ ”úœÓ«0J%l = Ëè”>(õ9§?Va”J.Ø@{–36Ð…)'|PêsN¬Â(•\°ö$,g8l  SNø Ôç|ĨshOÂr†Ãº0儊 tYBòÖ3Ù@CUˆ0nµ`6Ð¥°.KH~8Âr†Ãº0á´‡ tYBòÖ3Ÿ3Ð ˆœkFÏD8ç”ÄXD¶óÃVKNwØËè„ä…sníONwØËŽ-¤?'Œ[-!íB¶ZBÚÃñÛc",sµätg†­–œî°–36Ð… iG®ƒY„e®–œî,°ՒÓ6Âr†c+<6ÆsJl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#_` œâ?§/ Á~Š›)ÂK+á_Sü²ŠR|¢Îÿ­*¾‘âk)þ2E˜¶¼ûŸ§øÓ*þ$E­Ÿ?Jñ‡UüAŠ­aZc†Àº06P¨—S(^‚ÚzÂK+!»fŠ6ëļ´ݘg27Pbn£(¦5fl  “½3… Ô˜±8Ö@çe@„a«å8 ÃVBmÄqùÏ 4LµdBg£è‡À@‰0•1a]6PcFä ”¨Ë [-ÇYO¶j=½ubUaªE˜g•¥“¢ÖZßȇ©Œè*°3"Çèqe†­–ì:)jë ÃVB›ur]ÂT‹@nÄsl4nÌpØ@W™'çO„Ãçô™Û@ÍËÁç ” NSõ±kàô™¯¹€O“8dUœæ*„CŒèê8MþáUqš«1fP>g þc œ&ÿpȪ8~Â!Æ Š tuœ&ÿpȪ8~Â!Æ Êç Ô_ä^§É?²*²tR§Ÿpˆ1ƒb]§É?²*²tR§Ÿpˆ1ƒ’ Ô¿Ìbm—¶Z²tRÔú ÃŒ¨ t#d館õ†34Ù@ý }×FN=E¶ZŽÓOfÌÐØ@m á8ý„aÆ ÍJœÞFË\ B&Dm µõ`ÖI„©VÂqù‡a«å8ý„aÆ ÔºŽÓOfÌÐlý²ŠÚF+€¹bXaÞnÌ3™[Õ7ïPE˜v%äÔS„—† ÖOxɘ—hŽ0íJÈ©§/ A­Ÿð’1/[ÿš";hŠ6 óvƒw¯­“¨ tnÖ¹•"L»êüÃKCPë'¼dÌK€ ÔºAjý„—Œy X©qcÌú±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓÈÖÿMñ¿Sü2ÅG)ÞO±ŸâfŠK)¾žâ«)¾’â¿§óvÃù/›?ïN&dE†dK欂±:Vʪ9aÚn8ÿeó'ž¥8K?LÛ ¨ó?¼;™’-™³ VÄêX)«æ „i»áü—ÍŸÀÏÒÓvÃêüÏïN&dE†dK欂±:Vʪ9aÚn8ÿeóÇþj+lë‡i»auþg‚w'²"C²%sVÁŠX+eÕœ0m7œÿ²ù×&x–~˜¶6Pç&xw2!+2$[2g¬ˆÕ±RVÍÓvÃù/›?Q[a[?LÛ ¨ó?¼;™’-™³ VÄêX)«æ „i»áü—ÍŸÀÏÒÓvÃêüÏïN&dE†dK欂±:Vʪ9aÚn8ÿeóÇþj+lë‡i»auþg‚w'²"C²%sVÁŠX+eÕœ0m7œÿ²ù×&x–~˜¶þ"ý _¤Œ¬‘8rGú”%AyP*” %¦5®>J@(µ T„¢PJCu(0LÛ ¢¶Â¶~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶&x–~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶Ø_m…mý0m7l  ƒ|‘2²FâÈéS”åA©P6”P˜Ö\¸ú(U Ô‚rPŠB]( Õ¡À0m7jJ@(µ T„¢PJCu(0LÛ ¢¶Â¶~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶&x–~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶Ø_m…mý0m7l  ƒ|‘2²FâÈéS”åA©P6”P˜Ö\¸ú(U Ô‚rPŠB]( Õ¡À0m7jJ@(µ T„¢PJCu(0LÛ ¢¶Â¶~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶&x–~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶Ø_m…mý0m7l  ƒ|‘2²FâÈéS”åA©P6”P˜Ö\¸ú(U Ô‚rPŠB]( Õ¡À0m7jJ@(µ T„¢PJCu(0LÛ ¢¶Â¶~˜¶6Ð…A¾HY#qäŽô)J‚ò T(J(Lk.\}”€*PjA9¨E¡.”†êP`˜¶„0âïÛÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»a]ä‹”‘5GîHŸ2 $(J…²¡„´æ‚ÀÕG ¨… ”ƒŠPêBi¨†i»AÔVØÖÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP ÓvƒÀÏÒÓvú0È)#k$ŽÜ‘>e@IP” eC …iÍ«P A-(¡(Ô…ÒP Óvû«­°­¦í† ta/RFÖH¹#}Ê€’ <(ʆ Óš W%  ‚ZP*BQ¨ ¥¡:¦íFm‚gé‡i»±Åé›G·Zrº³ÃVKNwØ €ç–¹Zrº³ÃVKNwبMpľ tarºÃF®ƒY„e®–œî,°ՒÓ6j3±¿Å6~á:­–œî,°ՒÓ6¸yœGXæjÉéÎ" [-9Ýaª-i¬¾ tarºÃF®ƒY„e®–œî,°ՒÓ6j3±¿Å“ç®ÓjÉéÎ" [-9Ýaƒ.æ–¹Zrº³ÃVKNwØÀ†jK«o]˜œî°‘ë`a™«%§;‹0lµät‡ÚŒFìoñµ†y„ë´Zrº³ÃVKNwØàK3óË\-9ÝY„a«%§;l`Cµ%Õ·.LNwØÈu0‹°ÌÕ’ÓE¶ZrºÃFmF#ö·øzí<ÂuZ-9ÝY„a«%§;lð…íy„e®–œî,°ՒÓ6°¡Ú’ÆêÛ@&§;lä:˜EXæjÉéÎ" [-9Ýa£6£û[ü7¯y„ë´Zrº³ÃVKNwØà? Î#,sµätg†­–œî° Õ–4Vߺ09Ýa#×Á,Â2WKNwaØjÉ鵨ßÊë˜E¸N«%§;‹0lµät‡ì£³Ë\-9ÝY„a«%§;l`Cµ%Õ·.LNwØÈu0‹°ÌÕ’ÓE¶ZrºÃFmF#ö·òÏrg®ÓjÉéÎ" [-9Ýa#–4‹°ÌÕ’ÓE¶ZrºÃ6T[ÒX}èÂät‡\³Ë\-9ÝY„a«%§;lÔf4b+Ÿuá:­–œî,°ՒÓ6ò÷ég–¹Zrº³ÃVKNwØÀ†jK«o]˜œî°‘ë`a™«%§;‹0lµät‡ÚŒFìoåÿÓ?‹pVKNwaØjÉéùwŠÌ",sµätg†­–œî° Õ–4Vߺ09Ýa#×Á,Â2WKNwaØjÉ鵨ßÊ¿×tá:­–œî,°ՒÓ6òïUžEXæjÉéÎ" [-9Ýaª-i¬¾ tarºÃF®ƒY„e®–œî,°ՒÓ6j3±¿•ÿ¶Ó,ÂuZ-9ÝY„a«%§;lä¿-7‹°ÌÕ’ÓE¶ZrºÃ6T[ÒX}èÂät‡\³Ë\-9ÝY„a«%§;lÔf4b+\cŒ1§ÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cL#6PcŒiÄjŒ1Ø@1¦¨1Æ4b5ƘFl ÆÓˆ Ôc±cLŸ}öÿA*¥§FtÂbIEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/stations_status.png000066400000000000000000000117531474050137200262050ustar00rootroot00000000000000‰PNG  IHDRÀÀRÜlgAMA± üa pHYsÃÃÇo¨dIDATx^íÜxÅÞð|ŸPiWE°€ HG) v MŠt½\T@"$ôÐQ¯(^EA?0xiRô’ÞIh!€2ßÌ»;1Yþ„ˆÊÙœùŸçù=OvÏìì0¾¯ÙC¢> BˆÜˆÛº·o‹ñ¿À…¨·c%P×zƒºÁ±Šþp¼b8*¿VÂÊwêZo°½I8þòˤò=…ºÖ͸¹Ä0¬â籑nK³ügI²\ŒµˆT›ýŠ^ÔÜyÁ•jÿ„¤Êý ¢bOÐÁ×NØ¢+õ‚3UÂåjC€š;/;Zºvµ´ooiÛ–¦ßïÒÅÒ©Ps» à:¸†@üûiKê—–“«àÌ¡@$,³Äȯ•“ù#ÿ‚«QŸ8·®®y œ÷q«sUÞ€˜J½ÁøÑ…H¨ÜÎWÔ½ÜH´liiÑÂâçWš6…ÿÞ@†«dÎÓªP÷r.€ÀЄ-â‡-ñ !þç™: DT %b¢%E~-- »¿ úz±Q~;”’&ÝYoî&¢Ú`8S¹ÄÉÇ%\†Y¡ÂN‰°%Vê « €£ºuo78'?È*¢ys¸òÊ+ð›Ô võšíG,Ÿg wñÖ)K¢$–ë?•ê¯ñƒÿù‡%hÁW°«Ö8]ÖDõw€Z‹'èàŸõ󃤵k-_}eY½úæ¬Ycùö[H‘¬QWfH¢Öâ \.€Ùøîí2B_Ê€*Ûäc‹r¸¥%FþCSbûZâúØz[âß°$ ·Ä µu·~Ѳñ){ïp.ÄSDqÿë ~ËB÷Oñæàð1¬}¸3ÄÙB …gúCÁG;@BZ:¤5‘¥»€xr,PkñQCþËIJ:2ä)å¯~% ¢¦ü—¬D­Å¸\³ °¢_i¡¤|PÄ.ùmJ‰•!Vâ'Yb§Yâ‚mSlêœ2Û’8Ç’ç´‡äu `ç„r@-ÆDõ·!âÁŽÚ>.Ë·”ý6ýJ+Ûþ[¦ ˆnr/ûµ×&Î\€˜Çú@\Ù žÔZÁvQÎ¥L—s+Ô½=‰ `ã^-³?5·œbk‰W#,"Z†]9;Ú’>Ôr¼¸=øN‡å㎒Vu$Ê+úס£mú—áôq´,‹’\¹\¬:6”n Ô½ÜèýÂ…!½HH)Tblסß×ãõõ+‹ê^nÀpà^MWûÚXb»[R{Zå×ʯ­`ãÂZ ¯£æÎ ¶”kú?’O®2ôÿþDÿoRô£Ž~tJªÒ––|¨¹ó‚7ï¼¶ÚNÚN(@Òïï°½m£æv.Àup /€“ôKuŠ@çîƒV ï¼øÙT¶-\­>D·!¹jXUºP×zý¬î¾¾$·ý€+·¸¹Ä0¼Œy#.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3ÚŸ.Àç}ž‡·ªjŒ› š26ü8~Ü<ý–Ú°)¾ ÔÝÀÏÇZÚÊÙZÛ¨kò. WŒ+À°ª¾PçÞÛ€£ˆs1÷ýJ Æ¸Ùôe3A\ ¶¤Ž¶$û{¥Žµ\ €àjžTR†[g›dëlëb«nÓç¬ñ8Psº € #ã Шx>˜ûTð¯Rœãj×® —ï‘ Ûwl‡ú €ó:·92ÄDÌ‘4ÊrrŒ%N†ô¯¤çMV%-â§Á @ ÖèI-d˜•ö¶¶¶^¶…¶Ù¶Ú6=ŽšÛ ¸\€W€—Jäƒqåå·<©Eq‹s\àÔ Ð¯SgÎ~¥§§ƒó:·³d:|½ë}Øÿëd ïÚdP•8U†?!^Ρœ”sJ‡L…u;ðZ£'½&ëèWwùµ¢ƒ_×Öß6ÀAŸ¯gëm£îå \.@ŽŒ+ÀКÅ`ô£>°]þCQÖyô¸E‹CFFÄÆÆBjj*ÄÇÇCÖ¹ÝhöÊy9> ¿Ê("^…Wº¦ÄãM6ö8}=ÏA9§²:tDENƒKßjž¤ÿšÓùÒ:}m:ð mú‘H{Ë6Ðö´ºç­Äàäȸ\Ú5D¨üC+â8¬šQô¸5kÖÂ¥K— ..!22²ÎíFKV-‘>öý2–¬_ÛvOƒÌ¯)ïXô‡åÌ€Ûôy=ξnÛ9ô¾œS qa,ùd$Pkô$]€@[W›óå ºÖØæ<ÿ¬ºç­Äàäȸ\=8D„üC*)¡Ðů<èq7…ÂÅ‹A?òhun7Z²j!ˆ‹–¤–d^)=j¼ÿý|˜úÕ8² ˆS2ô C/=8‚¾^ dØ•´È÷@$ËqŠ.Jú8ðtJ´›¥ºÏ‡Û}ª^ 2¬ŠþA×4›~éèGg!žwxÎF­åVâp€ `[XD‚üÃ)gC»çŸ=n÷¶- D¤$„S¶_àëÜn”Y€ –xJÅ~´9r >Ý_n™sÖ͇-òñHÙ¶+æ¬[ ßnúº½aSášÕiãÁSð)ú$´[½/› CV€.@áÚ@O‘áUô_‹êÅú¯=oTZÓ­Äàp²*×¼)øOª ßmxÞè zÜŠ% !<. .§‡”ÓgaÃúï ëÜn”Y€ôI–Ä‘t"Öm™ ÿÙ9’ŽO€í»ƒaù¦¹ð‰ ¹²e÷tH=1vî †µ?͂ȃ âßµ¤ËÇ"ÉSx°ó(Ó{ Ü^±)è k}>ýv¥@Ñz]@¿¯‰ôȜІ›Ø\ûÄà]ŸV-~c ÚÐyðAÐdÐã©^ î<ž¾¿fM Yçv£Ì\’á—bŽŒ‡/6‡À¶½òñFú-fè_eÐ2g#Æg“ùˆsR>ÞHWãÇž}AðYhœ%PDº¼FòTtðõ+kè•‚O´çy§»úƒ>ž)íè”Õ·5²=6¬&Pkº•¸\.@VùºMŸ–£,M-³— Îñ>u;[Z¾Göì‚~̓s¼Û,þbˆ³A°æ§™°a«åš`ë_q°3bÇfsÍ8ûÃîù¨÷àÇ3à³Põks„H €Å2ü µÆ¿“þ°ë :À½¶&€>Öô‡aý(4`ïpŽ+Õj´ü¦?ÜûL!ÐÁ縀 ý„ˆ¥Å»Ùôžþ8ÇÿoîàÓ)ªõŸ Îqn¼t2„š›vÃÅè÷@¤Œ²Ø?èIòñç8eK–®¥«²ÊÖ]Á°ãÀ<üp,Pkü;éÀê—>î³# ®w¬ÝÝ ;èãÚS6À1έ¸VpõK[€ný߀Çû‚O»I–zÀ9^»­Çlðyi PcܨkÐ$ØxbœIžâ¼| ƒï,€3øµ–[‰ À.€-ì³0÷Í>pzÛ7à甿wÜÞ)¨1ntÿ3~ðTðBÿþðÒ€¿×‹òJÝžàF~@­Ñº:à9×;.þ|?pàõP‹Û‚¯q¸$c °nñLX1m\>°œãœòu ßž3Ãò®!‡/ƒüàƒA;ƒ¯Qs¹ €åŠ1Þ§ûÖ®ç8§ü'@¾¾ €üÇÐcW Nðfp¿VÇN@]ë&\vS¼¶½Û¶„µ‹§ÃŠàñàçôp&P¼I[ Æ0æ6\f´k  -6þoé| Æ0–×q˜Ñ®[­qƒz@½ÇX^Ç`F»aóf\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f4.3€ ÀŒÆ`Fã0£q˜Ñ¸Ìh\f´›.À…ÇÏ®F  Æz»åËõžÛùøø˜Ú”ÜàüŽ ‡Q›’&¿@~_èÑú¹lòûÞÔ5nG†Â$Ô¦ä€ à¨MÉIfðmÔo%Â×XŽ®ÊÎ>O]ãvd(LBmJN¸\¯BmJN2ÃoУvMð¨kÜŽ …I¨MÉ àú¨kÜŽ …I¨M¡˜üRqluŽô8j·"CajS(\.€W¢6…’Y5ÆÛä¿Ý~X06Ì›™#=N_GÍé6d(LBm … ÀðJÔ¦debð‡tóƒ;ï( jU†;ïÈú¸¡MŸÿýغNÏCÝÃ-ÈP˜„Ú”¬¸\¯FmŠâ þEÍ™W„~: î.R~øx<87.›ú¼óXÏCÝÃ-ÈP˜„Ú… õAÍ™Wp BmŠB…:7¨¹Ü.tùDØ$C­\Ú¿ÂÖ΀ðóAG†.Êæ÷q @ëyô¼ú>Ô<… …I¨MQ¨pç5—Ûq FmJnèˆååàkG¾€³{–CÆÑUpìûyÐò…:à{Ûmвe6úük/Ö…£ßÏ=Ïù½+@߇Zƒ§¡0 µ)¹ÁàxjSrâ ¾7`Áø¾Ð»Ý  U ¼B—̃¢îѱc6Eïç%=®pÁ»@Ï£çÕ÷¡Öà)d(LBmJN¸\¯BmJN¼)øÚõ P¤PAØ,C­è gtè>¯Çéë¸yµ)9áp¼ µ)o ¾v£üçƒà›ïv¸§H¡lôy=Ž ‡P›Báp¼µ)Š3ð×e(¦æÈ+¶~>¦ï›?Eeˆ•í-†¹»Aƒª³Ñçõ8}þUˆé£zÀ6y…Zƒ§¡0 µ) v € —Q›’ú,¨kXÞA†Â$Ô¦dE…>+ê–w¡0 µ)Y]z/xäa¿#CajS²âx72&¡6…¢ @½Çò.2&¡6…ÂðNd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â$Ô¦0s¡0 µ)Ìd(LBm 3 “P›ÂÌA†Â>âÿ»H ù­IEND®B`‚simutrans-124.3/themes.src/pak64german/files_large/theme.dat000066400000000000000000000121441474050137200240170ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi, modified by Leartin # # All image name must starts with "> " to have them unzoomeable # # This theme has the scalable standard look for pak 192.comic # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will used the unporessed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> skins_neu.0.2 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # unpressed pressed disabled left and right Image[0]=> skins_neu.2.2 Image[1]=> skins_neu.2.3 Image[2]=> scrollbar.0.2 Image[3]=> skins_neu.2.4 Image[4]=> skins_neu.2.5 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=- Image[7]=> skins_neu.6.6 Image[8]=- # scrollbar knob left center right Image[9]=> skins_neu.6.0 Image[10]=> skins_neu.6.2 Image[11]=> skins_neu.6.1 # arrow buttons up unpressed pressed disabled Image[12]=> skins_neu.4.0 Image[13]=> skins_neu.4.1 Image[14]=> scrollbar.2.2 # arrow buttons down unpressed pressed disabled Image[15]=> skins_neu.4.2 Image[16]=> skins_neu.4.3 Image[17]=> scrollbar.2.5 # scrollbar back up center down Image[18]=- Image[19]=> skins_neu.5.6 Image[20]=- # scrollbar knob up center down Image[21]=> skins_neu.5.0 Image[22]=> skins_neu.5.2 Image[23]=> skins_neu.5.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget_new.0.0 # help Image[1]=> gadget_new.0.1 # minimize Image[2]=> gadget_new.0.2 # previous Image[3]=> gadget_new.0.3 # next Image[4]=> gadget_new.0.4 # unsticky Image[5]=> gadget_new.0.5 # sticky Image[6]=> gadget_new.0.6 # resize corner Image[7]=> gadget_new.0.7 # goto pos Image[8]=> gadget_new.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/themes.src/pak64german/pak64german.tab000066400000000000000000000151221474050137200225550ustar00rootroot00000000000000# pak64.german theme # # name of the theme (will be shown with file selector) name=pak64.german ##################################tooltip stuff################################## # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 169 # tooltip text color (240=black, 215=white) tooltip_text_color = 145 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ################################## ################################## # show graphs old style (right to left, default) or rather left to right left_to_right_graphs = 0 # larger icons too icon_scaling = 100 # Default button width gui_button_width = 130 # use the larger Button height gui_button_height = 22 # arrows gui_horizontal_arrow_width = 20 gui_horizontal_arrow_height = 18 gui_vertical_arrow_width = 18 gui_vertical_arrow_height = 20 # check button gui_checkbox_width = 18 gui_checkbox_height = 18 # The titlebar height gui_titlebar_height = 27 # width and hight of the window elements gui_gadget_width = 27 gui_gadget_height = 27 # request larger font size (the resulting spacing is about 15% larger due to decent) font_size = 17 # You can use a system font. BUT you must specify the whole path to it! # This can be only set in the user defined simuconf.tab #fontname=C:\Windows\fonts\arial.ttf # windows: msjhbd.ttc - Microsoft JhengHei # gui_indicator_size = 18,8 # size tabs gui_tab_header_vsize = 22 gui_tab_header_hsize = 50 # gui_filelist_vspace = 4 ##################################color stuff################################### # gui_color_empty = #ffffff # status bar and ticker # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #D6ECF7 #gui_color_statusbar_divider = #6095B8 # gui_color_ticker_background = #D6ECF7 #gui_color_ticker_divider = #6095B8 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Color of the title text in the welcome screen and in help. gui_color_text_title = #0000FF # Shadow of some texts, like in the welcome screen and help. gui_color_text_shadow = #60A0FF # Background color of charts. gui_color_chart_background = #A49DBF # Text color of the lists area (background is listbox.png) #gui_color_list_text_selected_focus = #5c5c88 gui_color_list_text_selected_nofocus= #ffffff #gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #8c9bbc # Text color in edit areas. #gui_color_edit_text = #000000 #gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #7187b7 #gui_color_edit_background_selected = #72B2DD #gui_color_edit_beam = #000000 # Color of text in tabs, finance window headlines, ware list bonus text, minimap zoom # indicator, fps info in video options. gui_color_text_highlight = #1488E2 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #5f7e99 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 1 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window window_frame_active = 1 ## second: draw the title with a different brightness (0: dark ... 6: bright) ##front_window_bar_color = 1 ##bottom_window_bar_color = 3 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # color used for the default titlebars default_window_title_color = 154 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = 215 bottom_window_text_color = 213 # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears toolbar_max_width = 20 toolbar_max_height = 0 # horizontal and vertical margins between objects gui_hspace = 5 gui_vspace = 5 ##################################labels#################################### # text labels # text margins inside the labels (left, top, right, bottom) gui_display_text_label_margins = 8, 6, 8, 5 # The color of the label text. Can be a number 1-7, to indicate player color # brightness or it cant be a RGB value like #000000 gui_display_text_label_color = #FFDD55 # station labels # text margins inside the labels (left, top, right, bottom) gui_display_station_label_margins = 8, 5, 8, 5 # The color of the label text. Can be a number 1-7, to indicate player color # brightness or it cant be a RGB value like #000000. gui_display_station_label_color = 7 # marker labels # text margins inside the labels (left, top, right, bottom) gui_display_marker_label_margins = 12, 6, 12, 4 # The color of the label text. Can be a number 1-7, to indicate player color # brightness or it cant be a RGB value like #000000. gui_display_marker_label_color = #000000 # factory labels # text margins inside the labels (left, top, right, bottom) gui_display_factory_label_margins = 12, 7, 12, 7 # The color of the label text. Can be a number 1-7, to indicate player color # brightness or it cant be a RGB value like #000000. gui_display_factory_label_color = #000000 ##################################pakstuff################################## # pak with the images for this theme themeimages=menu.pak64german.pak simutrans-124.3/themes.src/pak64german/pak64german_large.tab000066400000000000000000000133341474050137200237320ustar00rootroot00000000000000# pak64.german theme # # name of the theme (will be shown with file selector) name=pak64.german (large size) ##################################tooltip stuff################################## # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 169 # tooltip text color (240=black, 215=white) tooltip_text_color = 145 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ################################## ################################## # show graphs old style (right to left, default) or rather left to right left_to_right_graphs = 0 # larger icons too icon_scaling = 150 # Default button width gui_button_width = 130 # use the larger Button height gui_button_height = 38 # arrows gui_horizontal_arrow_width = 38 #gui_horizontal_arrow_height = 36 gui_vertical_arrow_width = 36 #gui_vertical_arrow_height = 38 # check button gui_checkbox_width = 32 gui_checkbox_height = 32 # The titlebar height gui_titlebar_height = 42 # width and hight of the window elements gui_gadget_width = 42 gui_gadget_height = 42 # request larger font size (the resulting spacing is about 15% larger due to decent) font_size = 19 # You can use a system font. BUT you must specify the whole path to it! # This can be only set in the user defined simuconf.tab #fontname=C:\Windows\fonts\arial.ttf # windows: msjhbd.ttc - Microsoft JhengHei # gui_indicator_size = 28,15 # size tabs gui_tab_header_vsize = 32 gui_tab_header_hsize = 150 # gui_filelist_vspace = 9 ##################################color stuff################################### # gui_color_empty = #ffffff # status bar and ticker # gui_color_statusbar_text = #000000 gui_color_statusbar_background = #D6ECF7 #gui_color_statusbar_divider = #6095B8 # gui_color_ticker_background = #D6ECF7 #gui_color_ticker_divider = #6095B8 # Color of cursor overlay, which is blended over marked ground tiles # The available colors and their numbers can be found on # http://simutrans-germany.com/wiki/wiki/tiki-index.php?page=en_FactoryDef#mapcolor # Suggested values (155 is the default) # -- pak64, pak.german, pak128 cursor_overlay_color = 155 # -- pak128.japan #cursor_overlay_color = 149 # in default theme white text gui_text_highlight= #FFFFFF # Color of the title text in the welcome screen and in help. gui_color_text_title = #0000FF # Shadow of some texts, like in the welcome screen and help. gui_color_text_shadow = #60A0FF # Background color of charts. gui_color_chart_background = #a49dbf # Text color of the lists area (background is listbox.png) #gui_color_list_text_selected_focus = #5c5c88 gui_color_list_text_selected_nofocus= #ffffff #gui_color_list_background_selected_focus = #72B2DD gui_color_list_background_selected_nofocus = #8c9bbc # Text color in edit areas #gui_color_edit_text = #000000 #gui_color_edit_text_selected = #FAFAFA gui_color_edit_text_disabled = #7187b7 #gui_color_edit_background_selected = #72B2DD #gui_color_edit_beam = #000000 # Color of text in tabs, finance window headlines, ware list bonus text, minimap zoom # indicator, fps info in video options. gui_color_text_highlight = #1488E2 # Transparency color in factories boost icons (mail, energy, passengers) gui_color_image_transparency = #5f7e99 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 1 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window window_frame_active = 1 ## second: draw the title with a different brightness (0: dark ... 6: bright) ##front_window_bar_color = 1 ##bottom_window_bar_color = 3 # second: draw the title with a dark overlay (0=none, 100=full black) bottom_window_darkness = 25 # color used for the default titlebars default_window_title_color = 154 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = 215 bottom_window_text_color = 213 # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 5 gui_player_color_dark = 2 # Version 120.1.2+ # If and where to display a compass # 0=off (default for main screen) # 1=top, 2=vertical centre, 3=bottom, 4=left, 8=horizontal centre, 12=right # default for minimap is 1+12=13 compass_screen_position = 7 compass_map_position = 13 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears toolbar_max_width = 30 toolbar_max_height = 0 # safe margin around windows gui_frame_left = 20 gui_frame_top = 20 gui_frame_right = 20 gui_frame_bottom = 20 # horizontal and vertical margins between objects gui_hspace = 23 gui_vspace = 20 ##################################pakstuff################################## # pak with the images for this theme themeimages=menu.pak64german_large.pak simutrans-124.3/themes.src/standard/000077500000000000000000000000001474050137200174265ustar00rootroot00000000000000simutrans-124.3/themes.src/standard/back.png000066400000000000000000000070031474050137200210340ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûP ÊIDATxÚíœÛoéy‡y¦fDr†‘%Ú”å•cl6l,Ú -ú‡å/(» 7¹Ðöª½/P䀤Ý`‘ÃfmËÖZ¶l®(“rÈÎp†§þ†Þæ2(üb2ù€ß³ A¶Èò÷>óÈá—ío·BÞ•\Ú¿Q DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D"" ÁËÚé½´wç“ýq¾Ph5[A¸X…Ñz³)—Ëþ|ž/ä;w»OwN:Aàú·F£žÉå‚ùÜjXaz®[©VõJ% aYÖÁÕ‹/õƒñdÔ>lFCëà a5¯.Ÿ&ºþOþåß¿ÿ£¦½‹ïN!í_@NÖª[®ëerÙL>_.—ü¹Ÿ/[ÍËÇ_tîtÝ™;9Š®iÖÃÕj:›†Y.ïáÁ™Ìaîßô4MÇ#ãèßàéÍ£ö峋ä×WåK˜Ù¨»ž[­V ¹\¹Pð]/ŸËâr¿xò(Ž®çía©T*k¢[©xÊt26ê $’p!ºøÆ±íRyo½Z!+Ø£‘e5Í&¢‹Ô’ôúiïŸåBDÍz#“Í!C8î å¦Z3.?:;»ïL&ÞlŠësÆãJ¥ŠÇÛöÈ0êøUNJEgê”´½( ‘<œ‘ c Ó¼~ù2Š"”˜¤×O{ÿ¤(/P«}\*£Eà:SüѬ×Q,Îϸ®‹ëÑmÛ㑦iøiàyˆîz»Î¬×åRiµÙ ›©VªQTk5Ç™˜žb‡h\ ³Ž’^?íý“¢¼@¨h8D±¹~þÜ0îlæy.ª’ÇàÍ›|.7(¾Çàñ™M\VBd€0Ô÷÷ýo8ŽƒÇ¯–K4ËqåBt=·Ý>N~}µQ^ ¹A«Tq¹ßö^— rYoŽN%‡ÑÉ:kD4“ÙUsµZ]ß÷ÃÅz»1k*”®é(@¥r)îWö4ÈÕÜÙ´ut…QÒë§½R”( Z¥‚+þ«ë•ZͲ,ô%ÚÇ'¸èƒ Ø=*‹TÆá]b ÃE>›Ã„íz3}_·Ç¶¶¯Gñ¤ÝD\µ=Ý›ÍZGíõz…AÒë§½R”su¹Xì¿zeÔ܃þíM>—ïtî8ÎÉc½Ù U ^¬—þGn}´Y4(®ïA Íï~Å›Ï;wï:ñ†#X» <›ôúiïŸåB8·}\âV£Ñ¿ù e¥{ÿ=ÏC2Ël6š¶‡ë~½ZúÁB¯TÃ0*”K…BÙ $@[3¶Gççß°‡ƒ|¾ˆx·Ð2¯ÂÁ^Å~$»~Úû'EyP Jå2ºŠÁp€Ø4š‡ƒþ féõrY©V‘3âÊó0 ¡•KÅU´DƒŸFË£“ç8~ô7ƒ7·ÈÓ™ƒоøA`Z2rOÒë§½R”$_,í!bi`&êߌ‡ÃL6WœÖa†î<Ž.º“ø-ˆpQ.ï¡ÅKÅ""úðƒoõz¯3lÛn4Q€ûöqý lp&“¤×O{ÿ¤(/ÒC¨,š®÷{¯§“1ÊaÖ1¡Ë@Óº‹î #´ï{hlшhú>’†ó‡Þïõ^ç³yg<î|­VÝ{÷Çö!w]÷/°¾ê(/æçŠi–ŠegêŠ%«yXÈåœÙÕÑÍl·(%ñ‹xf}0|S5Íh÷NçÙ½÷®¯¯tm½°up†!V{ø~œ0ÐÛâ;-JI¯ŸöþIQ^ t':®~ÌÓj¶[LJ¥bÁŸÏÑá¶ÖÛ RÈàMüæ%"‡† 2J÷ô^ïÕõîõ½)ºcä†Lf{þðý«Ë‹B.‹y< ù|CVÒë§½R”µGàǯ쵎3¹º]à­¼×ï÷1B_½øª LhµÛ×/_ + Y~àçsÙó‡ß¼|üEæë×”½|±/ñ_Òë§½R”hw5¸”Íz}Ù¢)1ÍF¡TŒßBßNÝÓÓ‹'QPPeP\ÐÍôozVÃB ÂSð0”³ûýá·èc0!ê¨S¨YÈvÒë§½R”ÿD»fµõåmtíñý).n„°Ó¹{ùô¢{z†H¯—+´)q¡i¶WÓ0}ž/ÎÎ|þ»ÏÐùÆ÷]L|6·K ÛÌ®¾$½¾ê(/¦b´ˆ1Æi„ÙÞ•MÓÑðî¢û¤}|âÇi S5 DõÅŸûf½è"t»gŸ}úß•šßžG·\FÙÚ­¿œ“ôúiïŸå•*Ƶã°ó"çÍfAàÇѽxÜ:<Œû]ÇEßïõÚ;ˆn5~/s† ‚è~úëO0“Wk5D– /ÁÃW«U´ -š¤×O{ÿ¤(/Pü–ä2²šÍëW/-ëÀ™9Ú¾Þít¯ž]4¬¤Šh±ƒ`8èwâèÎK´ºˆ7‚ýÉ/~zvvß4MÄÉ*˜5® ºhžƒ…%½~Úû'E}0N·ÛWÏ/‘У”J%šË/ŸVj5}¿‚TFÑppÛ¹sŠ߃:’Ë·OŽþ_ÿùÑÇ‹~¹!˜ÏKÚžiÔãÛÄâÆ%Eš˜JXÂë§½R”(ŽîÕó³ûçöîÞäøÃ—Ïp­ÇËj‰êóutgS]ÓÃ`§´ŽŽùóŸ}ïþ) ˆwàzZµòö^‹él¿Ž¼ÙTMÓ_`øZ'½~Úû'Ey®¯®P;ÐÛ¢j A¹xü¨sz¯s§›‰ïJŽnooÞfLCȘ}ÚÇw>ýŸ_}ïïÿ1Žî|>ugˆn«u?ÆöȈûåõ×-ðfƒy*éõÓÞ?)Ê Ô>9q§ST ”ËgçFË0ð<Äo:tïžâ*GëÍdÛG'¿ûìÓï~üwÞÜCeñvïz€Áàv<¡§y{k˜3™¬WkD7î‹^?íý“¢¼@ƒÑ0“Gì²ý›×Ý{gù\ü*‹ƒáyµÆq¦oß4hŸt>ÿãï?úîǼ¿ëKxd—þW½ÛþMóð¨P(˜¦áLÆx0Æ«Á›[Ó²’^?íý“¢ü µòÞzß¾Ž2@ƃñv3¶‡ÝÓ{|¤õvo:'˧O>üöwÆ“* êbìa\YNŽï”‹%mß¾Yo¶­fÓ¶GÕJü9Ф×O{ÿ¤(ŸÖÛøõ\„UÈîú^#Uà*ïßÞà§š^Áå~yùô›~{lâ›u6ÛR|'W#z\†Nï!Ô†iÂ,…è¢Äèñë~3tÍI¯ŸöþIQ^ ­VøZ©T//UkUD4ðý~ï5þÒ¨7Z»FøáÃúý¾;‹ß‚ÂÒ~:¶ín÷ s¸V©ôv7ë–ç¹™lÎÅàýït&½¾Ò(/ÐÛ£·ÚÇ—ÏŸµO*5Ý+ D&—CÑ©Vªøþüýz½WzüÙ¿mÜš —är¨;gïGë%’šÙj­†‰ÝÝ}Ò4ZFˆ.Fn}OOzý´÷OŠòYÖAe¿rýâ9¾"78¶=u&(6ñ­Û *ÎÙùƒ«çÏv/O1û  Uâ3ÂvçNàÏÑ£55åÆªÕ*I|7êt‚Ô‚é=éõÓÞ?)Ê7цٸ¼¼Ðtã1®ì©;3ªµø£}?žÝ?¿øâ˜wc‘7¶å2âúöƒ¡þÜ7jFÕˆoN]­ÖÔ]m_Oìöa±·šÍ¤×O{ÿ¤(ŸpõÇ/7¬`ᇾñ| tQ>ñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQ^ ž”.Ê ÄóÒEyx>Pº(/ÏJåâù@颼@<(]”ÿð| tQ^ ž”.Ê ÄóÒEyx>Pº¨/ÏJåâù@颼@<(]”ˆç¥‹òñ| tQþƒ…<(]”Ï@<(]”(ÃóREyx>Pº(/ÏJå›hž”.…üó¾ÿ£¦ýk¼;?ù·ÿøs?þåoÞuá'ÿ¯G%½þ_=Ùþv›öï@Fùˆ¤ ""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "‚ˆˆ @D""(Aˆ DDP "âÃ"&q¼³™IEND®B`‚simutrans-124.3/themes.src/standard/button.png000066400000000000000000000033331474050137200214510ustar00rootroot00000000000000‰PNG  IHDR@ÔH^¢IDATxÚíÚ1o÷‡a2à’©Ð¦ØK=Å£ÈÞ5ƒ÷ttÒ8E† Ù3&µ Cùº{k‡@ô'° <p¦x s-U+Å ½äó@ÈÅø‰>Ü{Gq¾Z­fg^ÍzÏÌçó“ ¿KÅáöÿÄhÏ_<¿ñdzìñsôøh¹\~÷à;ÇÏË—ëïÝþ`ô–­_ÿ/þúEôø99{ñ£³ÓÐúÉ»§§¡–ó³gÔù‹•~ñ¹"Ž—Çw?½[¼šÒ5zÂV޾?=a+‹õîtýZßÛ˜ÏçëŸüå“âÌtã5zÂ^ï_Œðû¨_Á~*FËþ«cñêôÃâ½×ÚzùWÿvú½åòû»vào0@Ô;£ÀeIÉž€;0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀHšß»wïüÉß<½gc_þytùÅýi>œŽ¢[·nÝùì³Ñ[6öãG‡‡‡Þ¹3zÈå÷ž°•§OŸ><5=vü Ù?zÂV³ÓÐúI1ëñÅå÷w]¼øZ¬tOCõÔ÷OWУ'° ¦û˜ÑöhöÎì_L÷.ÝÛ—Yóm‡]Úÿ´ÿ(}yjôŠË»yóæè {½1z°¿þðþû£'ØæSˆ$ Ió“Õjôؘ;0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀHš¯V«ó'¯F¯¹„ó÷'ß|3zÎå÷w½~ýúÍ/o¦ï\¿6zËÆ~ý÷O/_¾|öìÙñò¸xüLûGOØÊµë×~:ûŠÇÏ‹þkúîøe1;=½}vp0zÏÆÎÏžQÿ{ñ›‚Ç WÍúâOþxôM³GOØÊ“'OFOØÊbýãítðd”®×ì0¶qÿþýóÇÅ€M7^£'ìõþÅè¿úuì§âÛnö_‹ÿþÝëà xïµ¶~ß|ºv+^¾Íšïû\>…@’€4?¹ð1z¨p@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I‹ÑØ'?.§ïïÝþ`ôË,/ξ¸ô„­L/þù¯PüøÇã£éûGŸÞ=ä’êÇO>`o^<ÿù??ÏšG?09^/—˯n;zÈÆºéZ«Ÿ6߬{½®WWý ¨xÌp¥L‡ÐGÓ×èíÈßÀœFöÍÛ;°nºËwc?À(;rÀ¾0’æ'«Õè °1w`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€$`$ I@’€ô?ˆ# IEND®B`‚simutrans-124.3/themes.src/standard/checkbutton.png000066400000000000000000000006511474050137200224470ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆpIDATxÚíØ1jÂ`†am…ººy ¥§(=…ŽÃc8tpt«CAG…kQJ)*ÊgýSû<  Éò /!Z_¾-k4Í—õºVmO½Þ‘»ý~é7¾¿±ùL§Óï—&ϓҫÎ3 ö^_¾-祷âP%­÷Uõ÷7¶‡ÅëâëR»ÝÞ|‡ÃÒÛÎÐív·'N§ô–ÿ¥QzÀÅH§ˆ»Ò~Ëö9ÊoÛÐx<.=ì<?¥|ôçÞš©ŽÝ;Ðl6ûq§Ø4J/¹ï=×W?~»ú$¶ÞWGîÎïJ¼ñýõê'B•ÝìÏx®C@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDäÂ+<™ôþ§IEND®B`‚simutrans-124.3/themes.src/standard/classic-large.tab000066400000000000000000000113331474050137200226300ustar00rootroot00000000000000# Default simutrans theme # # name of the theme (will be shown with file selector) name=Simutrans classic (large size) # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 tooltip_text_color = #000000 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # larger icons too icon_scaling = 150 # use the larger Button height gui_button_height = 22 # titlebar height gui_titlebar_height = 22 # width of the window elements gui_gadget_width = 22 # arrows and scrollbars gui_horizontal_arrow_height = 22 gui_horizontal_arrow_width = 22 gui_vertical_arrow_height = 22 gui_vertical_arrow_width = 22 gui_scrollbar_width = 22 gui_scrollbar_height = 22 # and a matching edit field height gui_edit_height = 22 # request larger font size (the resulting spacing is about 15% larger due to decent) font_size = 16 #################################colour stuff################################# gui_color_text = #000000 gui_color_text_highlight = #F8FCF8 gui_color_text_shadow = #000000 gui_color_text_title = #C0FC60 gui_color_text_strong = #C00000 gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #F8FC00 gui_color_edit_text = #F8FCF8 gui_color_edit_text_selected = #A8ACA8 gui_color_edit_text_disabled = #606060 gui_color_edit_background_selected = #404040 gui_color_edit_beam = #F8FCF8 gui_color_chart_background = #989898 gui_color_chart_lines_zero = #D8DCD8 gui_color_chart_lines_odd = #F8FCF8 gui_color_chart_lines_even = #686868 gui_color_list_text_selected_focus = #F8FCF8 gui_color_list_text_selected_nofocus = #C8C8C8 gui_color_list_background_selected_focus = #0000F8 gui_color_list_background_selected_nofocus = #60A0F8 gui_color_obsolete = #0000F8 gui_color_empty = #F8FCF8 gui_color_button_text = #000000 gui_color_button_text_disabled = #686868 gui_color_button_text_selected = #000000 gui_color_colored_button_text = #000000 gui_color_colored_button_text_selected = #F8FCF8 gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #686868 gui_color_ticker_background = #B0B0B0 gui_color_ticker_divider = #000000 gui_color_statusbar_text = #000000 gui_color_statusbar_background = #989898 gui_color_statusbar_divider = #D8DCD8 gui_highlight_color = #D8DCD8 gui_shadow_color = #686868 gui_color_loadingbar_inner = #A8ACA8 gui_color_loadingbar_progress = #0000F8 cursor_overlay_color = #F88000 tooltip_background_color = #7094B8 tooltip_text_color = #000000 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #D74700 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) #bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 4 gui_player_color_dark = 1 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #EEEEEE ##################################pakstuff################################## # pak with the images for this theme themeimages=classic.pak simutrans-124.3/themes.src/standard/classic.tab000066400000000000000000000100641474050137200215400ustar00rootroot00000000000000# Default simutrans theme # # name of the theme (will be shown with file selector) name=Simutrans classic # show tooltips (default 1=show) show_tooltips = 1 # tooltip background color (+-1 around this index is used), taken from player-color table tooltip_background_color = 4 tooltip_text_color = #000000 # delay before showing tooltip in ms (default 500ms) tooltip_delay = 500 # duration in ms during tooltip is visible (default 5000ms=5s) tooltip_duration = 5000 ##################################size stuff################################## # maximum size of tool bars in tools (0 = no limit, negative relative to window width) # if more tools than allowed by height, # next and prev arrows for scrolling appears # this should be left for the user to customize #toolbar_max_width = 0 #toolbar_max_height = 0 # size of tools (negative number: scaling factor in %) icon_scaling = 100 #################################colour stuff################################# gui_color_text = #000000 gui_color_text_highlight = #F8FCF8 gui_color_text_shadow = #000000 gui_color_text_title = #C0FC60 gui_color_text_strong = #C00000 gui_color_text_minus = #C00000 gui_color_text_plus = #000000 gui_color_text_unused = #F8FC00 gui_color_edit_text = #F8FCF8 gui_color_edit_text_selected = #A8ACA8 gui_color_edit_text_disabled = #606060 gui_color_edit_background_selected = #404040 gui_color_edit_beam = #F8FCF8 gui_color_chart_background = #989898 gui_color_chart_lines_zero = #D8DCD8 gui_color_chart_lines_odd = #F8FCF8 gui_color_chart_lines_even = #686868 gui_color_list_text_selected_focus = #F8FCF8 gui_color_list_text_selected_nofocus = #C8C8C8 gui_color_list_background_selected_focus = #0000F8 gui_color_list_background_selected_nofocus = #60A0F8 gui_color_obsolete = #0000F8 gui_color_empty = #F8FCF8 gui_color_button_text = #000000 gui_color_button_text_disabled = #686868 gui_color_button_text_selected = #000000 gui_color_colored_button_text = #000000 gui_color_colored_button_text_selected = #F8FCF8 gui_color_checkbox_text = #000000 gui_color_checkbox_text_disabled = #686868 gui_color_ticker_background = #B0B0B0 gui_color_ticker_divider = #000000 gui_color_statusbar_text = #000000 gui_color_statusbar_background = #989898 gui_color_statusbar_divider = #D8DCD8 gui_highlight_color = #D8DCD8 gui_shadow_color = #686868 gui_color_loadingbar_inner = #A8ACA8 gui_color_loadingbar_progress = #0000F8 cursor_overlay_color = #F88000 ##################################window stuff################################## # when moving, you can use windows to snap onto each other seamlessly # if you do not like it, set the catch radius to zero window_snap_distance = 8 # show the windows close etc. buttons on the right (like windows 98) window_buttons_right = 0 # closes windows/toolbar when button clicked a second time (default off=0) second_open_closes_win = 0 # restores window position when window is reopening # This will be saved, but will be discarded when screen is resized remember_window_positions = 1 # color used for the default titlebars default_window_title_color = #D74700 # there are three different ways to indicate an active window # first: draw a frame with titlebar color around active window #window_frame_active = 0 # second: draw the title with a dark overlay (0=none, 100=full black) #bottom_window_darkness = 25 # third (best together with 2nd):use different text color for bar # some colors are 215-white, 240-black 208-214- all shades of gray front_window_text_color = #FFFFFF bottom_window_text_color = #DDDDDD # How much shade for player colors (7 brightest 0 darkest) gui_player_color_bright = 4 gui_player_color_dark = 1 # make the chat window transparent in network games gui_chat_window_network_transparency = 25 # if defined, use plain color for chat window in network games gui_color_chat_window_network_transparency = #EEEEEE ##################################pakstuff################################## # pak with the images for this theme themeimages=classic.pak simutrans-124.3/themes.src/standard/divider.png000066400000000000000000000002761474050137200215670ustar00rootroot00000000000000‰PNG  IHDR@@% 扅IDATxÚíÏA €0À@†[2ÏðDƱDž¤UpóšÇŸ÷skÃÞÀ»–6luj@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐ4  h@Ѐìöm=ÓÃÞIEND®B`‚simutrans-124.3/themes.src/standard/editfield.png000066400000000000000000000011721474050137200220660ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPAIDATxÚíÝÁIA†QW¼¤‹¤•€Åĵ„-!ä"–a=zK WkÈ' ïUð3û1sÜe=­çëåaZo/¯£'üƒy?Ár۶јØãèÌM@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²¬§õ|½Œžq¿Ï÷Ñ’ãóq·?Œ^q?7‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²Ü¶mô&æ"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€Hž~¾¿vûÃè÷ûÛ?zB5õùûÙ ‰'ŒD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HDò * ÷;"0 IEND®B`‚simutrans-124.3/themes.src/standard/gadget.png000066400000000000000000000031651474050137200213740ustar00rootroot00000000000000‰PNG  IHDR@@}g_H2ɯþv5¸!L ...úÿúÿIIÜ›7offfš ŸEEEZæóÓ§OÇÆÆ¤½Lø]»vÉ}œíPëàúß½mmm2llIPnnîµk×´ŒùÕdcò›ŸÒ²Åv¨x™™{òäI™¹9992t½k/9ì]ÿ¬tÖt6öýÑ—‘žáç¹à]ÉòEî}®\¹"¡Ï;'kùÁÁAÛ!ãb†~Àu¹Ÿ™™µ+^¾±±qÏž=©©©ò3==}eeåýû÷=òóZ½ÍÍÍûöí{ùò¥í, JII‘a‡ö€ëîÇ<“Þ’p¶ØN·>ÓÓÓ±XL>mYŸ5o@U !I. /§º®w_OKK«ù©æÀäç[w|;>)0ÓsssUUU÷îÝ“+i4moo÷gôÕÜMúúúFFFššš…—ØG­¬¬,((ÈÈȸpá‚–]ü/^”ö’ èóçÏmÇIлwïäà———wttøvÞº9×ÍgÏž›§‡6_¤ äK~~¾í˜ñî‹,wïÞ-ߥ€¥†Uœ‚€òµ×­ßoÕüXc.A½ÑÞà† Øýûååfc¤=âÏá]™¸{÷î•1$× EíåüÝÝݯ_¿®¯¯×Þ¹¨¨¨…BÒ^—/_Öµ Ož<Ù¹s§t€í _djjJ&ððð°í q1#DFŽ´WàCc™w:@¾H™¹ßèó-óçºÀÇÒ­®®îïïWÑaŸ{øP²Ëú.ËùÊ --/ÍÍϽ}ûÖÙû+f;ãÚÖx‰#ËÚëáÇYYY‘ˆO‹÷s$ííÛ·7mÚ$wЊb;L‡‰¼¼³.^*^6ñлö2Ì´½ÑsÃÔðþªý——–––Ný|*ðaD®;]ÿ‹OÞ—8dí’››;88(5V[[+7AwïÞÕÕa?Öõî†Çê?æ)bÂËò¥¤¤Äv–-..ŽŽŽª{}ÀñêÕ+÷›{æ½>Û¡ââÎl‡úÿüËÚ˳S~f¦mׯ]oÞ¼‘®:vü˜Ù~âø‰P(ÔÒÚâÛ½ð®ÀFFF$±´—Ù¥7Ú¹ª¯þî½°á‹ÂË)8räˆí D"zOç½sgFèb‡úŸÞq²zGÌ8iin™ŸŸ7OPη÷ù>z—VzÿÌ Üßߟ——WZZª(vòѵjOŽäÉ„³`‹îdö$öÿ¬644´eËÛ)¾uGŽöäÀ—Ó5þ“ð6Gݪ€$,0À· ÕvAT¢À*Q`•(0€J@%  P‰¨DT¢À*Q`•(0€J@%  P‰¨DT¢À*Q`•(0€J@%  P‰¨DT¢À*Q`•(0€J@%  P‰¨DT¢À*Q`•(0€J@%  P‰¨DT¢À*Q`•(0€J@%  Péo&½ˆ/õ¼CIEND®B`‚simutrans-124.3/themes.src/standard/listbox.png000066400000000000000000000012001474050137200216110ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûPGIDATxÚíݱiÃPEQ)¸Iç"EÜ%#¼ÿ!o¡xÝÀÏç€ú‡tù¨h]–eÛ÷eZ—u=áÌûÖy§ó¼ÀÜD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$ëëÚö}ôŒã¶ûcô„äüq~ÿú½â8'‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD²NýA4Ã9HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ’Óv\n×Ñ3Ž{í=!¹Þ®ÏÑŠé¶ò9z@7u@§Ñª©ïþ?àˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€HD" ‘ˆD@$"‰€H~ã#áIÿ8åIEND®B`‚simutrans-124.3/themes.src/standard/posbutton.png000066400000000000000000000007261474050137200221760ustar00rootroot00000000000000‰PNG  IHDRÀ@ÃïˆIDATxÚíÕ=NQ@á‡Nâ c=$î‚b\‚¥¥ 1,Å‚%¸„é´0‘’Ÿ<ø =‰Ã•ó%\ÞPÝÌ ³~Z§­ÇãÐÅéY9œÏ&mï²ûWùU×užý~?ÅÌhz5mÎCÙ¹”nÿª¼­VuªSØŒ׋áɰ¹ ÷RØŒªæ”Ê3nF¹¡<ÍèUŸ®›Œ–7ËÑht·Ù´½áϼÏh2›Ü·½Ïï”tº)íþþÕ×n·Ú^ Éõº½¶·Ø jÒ™Ïçy†ûù)r:ƒãAŠðõýNw;Cìÿéìˆ@é//Ç)r:åËtZÑiNÓIo÷=¼õÿcÿNÐn´#Ú^@±b@B Hˆ 1 !$Ä€„b@B Hˆ 1 !$Ä€„b@B Hˆ 1 !$Ä€„b@B Hˆ 1 !$Ä€„b@B Hˆ 1 !$Ä€„b@B Hˆ 1 !$Ä€„b@B HÈ3í‰{PeY²*IEND®B`‚simutrans-124.3/themes.src/standard/roundbutton.png000066400000000000000000000025701474050137200225230ustar00rootroot00000000000000‰PNG  IHDR@Àc×K?IDATxÚíÚ1oUu‡á^r&Ó­êŒ4q÷ °ë6‡Ž$ƤÄàwppgÓÁÐ~ $P˜$.\½¶éz{‰ÿ¾íó´ç.ä׿ä¾çœÞÙb±Ø8òv£gëè`6›œøY*¶Öÿ/F{ñòÅû?ßOŸoß½eeì=›þíí=|ô°xþLûGOXËÍí›{G?Bñüùõ§'ÓWçÏ(óÃ7 å‹ËW®ŽÞ³²ãwϨã_~ÔÕà9ÃY³¼†¸·ý`ô•M³GOXË“ŸŸŒž°–ùòÛ²—¯Œž³ºt½ÎÁþ+£P6›ÍŽïýØ Øtã5zÂ…Þ?=àÓ¨_GÀÅT|ìfÿÙ1{øä°xïµ´|n~oûAñòm£ùÜà,¸4zœ†€”üè9¸ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €¤Ù;wŽ_|ÿèÑè=+ûáîÝèò“ûÓvww§³èÆ·nß½ee¿<~¼µµõÕ­[£‡œ~ÿè kÙßßß=4;†ì=a-óÃ7 å‹b–ã‹ËOîï:yðš/¿u߆ê¨ïŸ® GOà<˜îcFO¸@³ÏÍþùtïÒ½}Ùh>v8Oû÷û@è»C£WœÞõë×GO¸Ðûç£×g×®ž`˜O!$`$Í‹Ñ`eîÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ i¶X,Ž_¼½æ¶Žv&÷ïžsúý]ïÞ½û{ssôŠSúøúÍ«W¯ž?þlïYñü©›Îÿ7¯ß,/}ùÅè9+{ùÛïÓ×îùóñè—5ß8|úïUðmhÿᯣW¬µô„µlÏΚå5Ä×ß~3zÈʦ٣'¬åéÓ§£'¬e¾ü¶lÀ¥à›Qº^“î½ ¬oggçø¸°éÆkô„ ½>zÀ§Q¿Ž€‹©øØÍþ³cþïß½67‹÷^KËçæÓµ[ñò €Só)D’ €¤ÙÁ‰Ñ@…;0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀH0’ €$ IÀHúV™÷aŒ¤ÖöIEND®B`‚simutrans-124.3/themes.src/standard/scrollbar.png000066400000000000000000000046031474050137200221220ustar00rootroot00000000000000‰PNG  IHDRÀ«¯1 JIDATxÚíÜ¿oÔ÷Çñ»Ôf™0KåH•ÌèD©³fNUñ/ š£éŸ€EêÒ¨ƒˆ­¢ü•:°b ì&¼Á€g *÷ƒ¿ä¸úW|¯KøÜçüx ÿ8%oŸ{ò¾NÿÙÞ^ïwÿûS÷Á÷¿;×kÐßÿú·îƒ›_ߪ=ËŒÏ礼—úýÚ#LdîÀçÝýagg§\^þÃågGåušuçéöúírùÍ¿¾©=N8wgø÷»µÇ9•î´,--õÚÌhwZ:-f¨›yôäðÖ¼ èh:w_ìnooמm<£éüüÆçåòÚõkÏkO5îü£w€†æ/f§·Ók6£åïÚOÿòéðÓ3$£U¼ ètÖil‡Óùþûï×jìù[?ôÝÉi7£Ýãe,s¥ží¦³·VÚMg7ÿ,ôaFïÿçþ`0hî) ÑŒÞúúV+èNÔb¯×èü ™›Ÿ›/}e_ía¥˜->×9ö÷Õžb"åD]Z¼T{ 0Wv„î…°F3ú§ë×÷?¸ÛÈK.”e¡›–…a:766Êesëg§¤ó“?ÒkùOdfNÔô{õhwÐÛÍhwP®]¿Ök3£ÝüMzéœMŸ¢½yþpFkÏ6­eíŸk½–ÓÙ=`—Ný#OüðÝ­-Þz?¦^³ç©¡ùóO¢õ7Ò÷=÷À h= ïÔ U P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ 4·8òÉóÚÓ†ó÷ûýg{{µÇÉçoÔ7†±¾^{œ±}¹?‹“Îß®¬®®nnn6zÙßÛÛ{ºó´ûaÎ/½WûöÛ;Ow_ì–>øã-ôÇŸoüF}õ¯666º[¼ý/õûN>:»J¦¡ƒñå\÷ct :¿Tûæ_7y»ZŸ¿3 jÖ¿Q­Ï_½€^ÎÈs w¿½[{„³nee¥ö¡ÅÅÖŸGiXõNx9 }´õ¨ö@¢zm @«ªÐ ´ªzm @«ªÐ ´ªzm @«ªÐJ}í¾‡‰ºªðWØ@›~/·÷0A»ªpÂË׿‰T2´µµuóÃ[µoϱ•±k0‘™ù€FߎÞèØ33õNxù¿HÛâoþ.pëó·èñãÇÃ/,/×gl? kk =üÚQ‹KèðÓ†ÖÏÎá%´•õs8ÿ%ÔúùÖØ@ù5Y?9SÞ)Y•CàE€†–ÐÃëg§•%ô¸·.5·„v·sëgg¸„öZ[?‡ó—PëçÛôúUø’›Ú“Ð<ë'gÍÜüü|í&RŸ—/_Öžb¢ùÚ4OP¶žî]Í­Ÿ²Äuh£ë[™¿{w£ó7ªÉ÷̳¡‰ç OàE$€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ ! (@H@B P€€„ $ !õ÷ööNu½~ÿÙé®ù–-özOwžî¾Ø=î ¶mmmÝ^¿ÝèüÅÝoïNíü?|8 ¦|þ®3Ø7ó—ó¿¹¹¹ººú‹—¿_]­=ìæzûwà®qò}{ ',­¬=ËY´±±ñ‹×)wàÚcíâÅ‹åòòåËüñ‘W(yºwï^í1gÖ)ëY.ŸOþû Ìuÿ8¹’M„©¬iµG8£†ÝÞÞ>ù SèåÂÂ………®ðÑòòGW®Ôsf²žS½þ¢ò¸öœÇê÷ûµG8뻇+++‡¿{\U¡7hëüÒ{ç—NºÒÍoÝüúVíQ6Ï žÊ‚¶¼|®L볟LƒÖ7P¯ÂÕœ~­=éѨæôhíI& @56P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B6P€  dÙ@B­o ÿÍ.NqÙÆIEND®B`‚simutrans-124.3/themes.src/standard/standard.dat000066400000000000000000000115561474050137200217300ustar00rootroot00000000000000# # Simutrans window skin definitions for themes # Author: prissi # # All image names must start with "> " to have them non zoomable # # This theme has the scalable standard look # ################################################ # # Button have 3 rows with left middle right images for one state # # If only top row is there, button will be centered vertically in area if the size does not match. # If all nine are there, you can set any size in themes.tab # -- Obj=menu name=Button # unpressed Image[0]=> button.0.0 Image[1]=> button.0.2 Image[2]=> button.0.1 Image[3]=> button.0.3 Image[4]=> button.0.5 Image[5]=> button.0.4 Image[6]=> button.0.6 Image[7]=> button.0.8 Image[8]=> button.0.7 # pressed Image[9]=> button.1.0 Image[10]=> button.1.2 Image[11]=> button.1.1 Image[12]=> button.1.3 Image[13]=> button.1.5 Image[14]=> button.1.4 Image[15]=> button.1.6 Image[16]=> button.1.8 Image[17]=> button.1.7 # disabled (will use the unpressed color mask) Image[18]=> button.2.0 Image[19]=> button.2.2 Image[20]=> button.2.1 Image[21]=> button.2.3 Image[22]=> button.2.5 Image[23]=> button.2.4 Image[24]=> button.2.6 Image[25]=> button.2.8 Image[26]=> button.2.7 # color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area) Image[27]=> button.3.0 Image[28]=> button.3.2 Image[29]=> button.3.1 Image[30]=> button.3.3 Image[31]=> button.3.5 Image[32]=> button.3.4 Image[33]=> button.3.6 Image[34]=> button.3.8 Image[35]=> button.3.7 # If the position of the colored area is different for a pressed button (i.e. protruding knobs) # then here can come another nine mask images -- Obj=menu name=Roundbutton # unpressed Image[0]=> roundbutton.0.0 Image[1]=> roundbutton.0.2 Image[2]=> roundbutton.0.1 Image[3]=> roundbutton.0.3 Image[4]=> roundbutton.0.5 Image[5]=> roundbutton.0.4 Image[6]=> roundbutton.0.6 Image[7]=> roundbutton.0.8 Image[8]=> roundbutton.0.7 # pressed Image[9]=> roundbutton.1.0 Image[10]=> roundbutton.1.2 Image[11]=> roundbutton.1.1 Image[12]=> roundbutton.1.3 Image[13]=> roundbutton.1.5 Image[14]=> roundbutton.1.4 Image[15]=> roundbutton.1.6 Image[16]=> roundbutton.1.8 Image[17]=> roundbutton.1.7 # disabled Image[18]=> roundbutton.2.0 Image[19]=> roundbutton.2.2 Image[20]=> roundbutton.2.1 Image[21]=> roundbutton.2.3 Image[22]=> roundbutton.2.5 Image[23]=> roundbutton.2.4 Image[24]=> roundbutton.2.6 Image[25]=> roundbutton.2.8 Image[26]=> roundbutton.2.7 -- Obj=menu name=Editfield #should be either scalable or at least LINESPACE+2px high Image[0]=> editfield.0.0 Image[1]=> editfield.0.1 Image[2]=> editfield.0.2 Image[3]=> editfield.1.0 Image[4]=> editfield.1.1 Image[5]=> editfield.1.2 Image[6]=> editfield.2.0 Image[7]=> editfield.2.1 Image[8]=> editfield.2.2 -- Obj=menu name=Listbox #Must be scalable! Image[0]=> listbox.0.0 Image[1]=> listbox.0.1 Image[2]=> listbox.0.2 Image[3]=> listbox.1.0 Image[4]=> listbox.1.1 Image[5]=> listbox.1.2 Image[6]=> listbox.2.0 Image[7]=> listbox.2.1 Image[8]=> listbox.2.2 -- # window background Obj=menu name=Back Image[0]=> back.0.0 Image[1]=> back.0.1 Image[2]=> back.0.2 Image[3]=> back.1.0 Image[4]=> back.1.1 Image[5]=> back.1.2 Image[6]=> back.2.0 Image[7]=> back.2.1 Image[8]=> back.2.2 -- ################################################################# # # The following control only have one (or three) images, and are not stretchable # Obj=menu name=Checkbutton # unpressed Image[0]=> checkbutton.0.0 # pressed Image[1]=> checkbutton.0.1 # disabled Image[2]=> checkbutton.0.2 -- Obj=menu name=Posbutton # unpressed Image[0]=> posbutton.0.0 # pressed Image[1]=> posbutton.0.1 # disabled Image[2]=> posbutton.0.2 -- Obj=menu name=Scrollbar # arrow buttons left unpressed pressed disabled Image[0]=> scrollbar.0.0 Image[1]=> scrollbar.0.1 Image[2]=> scrollbar.0.2 # arrow buttons right unpressed pressed disabled Image[3]=> scrollbar.0.3 Image[4]=> scrollbar.0.4 Image[5]=> scrollbar.0.5 # scrollbar back left center right Image[6]=- Image[7]=> scrollbar.1.6 Image[8]=- # scrollbar knob left center right Image[9]=> scrollbar.1.0 Image[10]=> scrollbar.1.2 Image[11]=> scrollbar.1.1 # arrow buttons up unpressed pressed disabled Image[12]=> scrollbar.2.0 Image[13]=> scrollbar.2.1 Image[14]=> scrollbar.2.2 # arrow buttons down unpressed pressed disabled Image[15]=> scrollbar.2.3 Image[16]=> scrollbar.2.4 Image[17]=> scrollbar.2.5 # scrollbar back up center down Image[18]=- Image[19]=> scrollbar.3.6 Image[20]=- # scrollbar knob up center down Image[21]=> scrollbar.3.0 Image[22]=> scrollbar.3.2 Image[23]=> scrollbar.3.1 -- # window symbols Obj=menu name=Gadget # close Image[0]=> gadget.0.0 # help Image[1]=> gadget.0.1 # minimize Image[2]=> gadget.0.2 # previous Image[3]=> gadget.0.3 # next Image[4]=> gadget.0.4 # unsticky Image[5]=> gadget.0.5 # sticky Image[6]=> gadget.0.6 # resize corner Image[7]=> gadget.0.7 # goto pos Image[8]=> gadget.0.8 -- # window background Obj=menu name=Divider Image[0]=- Image[1]=> divider.0.0 Image[2]=- -- simutrans-124.3/todo.txt000066400000000000000000000012071474050137200152610ustar00rootroot00000000000000To be done: - weight limit on ways by axle_load entry in vehicles (to avoid problem when going back and forth with diff. load) - busy platform images - city wayobj instead just sidewalks - building/tree heights in dats - fog view to the top? - instant text updates - bahnhofsdetaildialog (more text on the station buildings) partially done: - connection weighted by their intermediate stops => A* for goods routing [A* did not worked out, but intermediate stops may be considered] reconsider: - leave stop if other convoi has arrived there patch - viewports (even if they are perfomance killers ... ) - routing penalty sign (but a proper one) simutrans-124.3/tools/000077500000000000000000000000001474050137200147135ustar00rootroot00000000000000simutrans-124.3/tools/cleanup_code.sh000077500000000000000000000010261474050137200176720ustar00rootroot00000000000000# # properly rename include guards (needs perl) echo "Checking include guards" find . -type f -name "*.h" | grep -v "squirrel/" | while read f; do guard="$(echo $f | cut -b 3- | tr '[[:lower:]]' '[[:upper:]]' | tr -C '[[:alnum:]]' '_' | rev | cut -c2- | rev)"; perl -i -p0e "s/(\n){2,}#ifndef [^\n]*\n#define [^\n]*(\n)+/\n\n#ifndef $guard\n#define $guard\n\n\n/" $f; done # # remove trailing spaces echo "Removing trailing whitespaces" find . -type f -name "*.h" -o -name "*.cc" | grep -v "squirrel" | xargs sed -i -e "s/[ \t]*$//" simutrans-124.3/tools/distribute.sh000077500000000000000000000166761474050137200174500ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # parameters (in this order): # "-no-lang" prevents downloading the translations # "-no-rev" do not include revision number in zip file name # "-rev=###" overide SDL revision with ## (number) # # should be called from the main directory "tools/distribute.sh" # # get pthreads DLL getDLL() { # Use curl if available, else use wget echo "Downloading pthreadGC2.dll" curl -q -h > /dev/null if [ $? -eq 0 ]; then curl -q ftp://sourceware.org/pub/pthreads-win32/dll-latest/dll/x86/pthreadGC2.dll > pthreadGC2.dll || { echo "Error: download of PthreadGC2.dll failed (curl returned $?)" >&2 exit 4 } else wget -q --help > /dev/null if [ $? -eq 0 ]; then wget -q -N ftp://sourceware.org/pub/pthreads-win32/dll-latest/dll/x86/pthreadGC2.dll || { echo "Error: download of PthreadGC2.dll failed (wget returned $?)" >&2 exit 4 } else echo "Error: Neither curl or wget are available on your system, please install either and try again!" >&2 exit 6 fi fi } getSDL2mac() { # Use curl if available, else use wget curl -h > /dev/null if [ $? -eq 0 ]; then curl http://www.libsdl.org/release/SDL2-2.0.10.dmg > SDL2-2.0.10.dmg || { echo "Error: download of file SDL2-2.0.10.dmg failed (curl returned $?)" >&2 rm -f "SDL2-2.0.10.dmg" exit 4 } curl http://www.libsdl.org/release/SDL2-2.0.10.dmg > SDL2-2.0.10.dmg || { echo "Error: download of file SDL2-2.0.10.dmg failed (curl returned $?)" >&2 rm -f "SDL2-2.0.10.dmg" exit 4 } else wget --help > /dev/null if [ $? -eq 0 ]; then wget -N http://www.libsdl.org/release/SDL2-2.0.10.dmg || { echo "Error: download of file SDL2-2.0.10.dmg failed (wget returned $?)" >&2 rm -f "SDL2-2.0.10.dmg" exit 4 } wget -N http://www.libsdl.org/release/SDL2-2.0.10.dmg || { echo "Error: download of file SDL2-2.0.10.dmg failed (wget returned $?)" >&2 rm -f "SDL2-2.0.10.dmg" exit 4 } else echo "Error: Neither curl or wget are available on your system, please install either and try again!" >&2 exit 6 fi fi } # first assume unix name defaults ... simexe= updatepath="tools/" updater="get_pak.sh" OST=unknown # now get the OSTYPE from config.default and remove all spaces around OST=`grep "^OSTYPE" config.default | sed "s/OSTYPE[ ]*[:]*=[ ]*//" | sed "s/[ ]*\#.*//"` PGC=0 # now get the BUNDLE_PTHREADGC2 from config.default and remove all spaces around PGC=`grep "^BUNDLE_PTHREADGC2" config.default | sed -E "s/BUNDLE_PTHREADGC2[ :]*=[ ]*//" | sed -E "s/[ ]*\#.*//"` BUILDDIR=`grep "^PROGDIR" config.default | sed "s/PROGDIR[ ]*[:]*=[ ]*//" | sed "s/[ ]*\#.*//"` if [ -n "$BUILDDIR" ]; then BUILDDIR=../sim else BUILDDIR=../build/default/sim fi # now make the correct archive name simexe= if [ "$OST" = "mac" ]; then simarchivbase=simumac elif [ "$OST" = "haiku" ]; then simarchivbase=simuhaiku elif [ "$OST" = "mingw" ]; then simexe=.exe SDLTEST=`grep "^BACKEND" config.default | sed "s/BACKEND[ ]*[:]*=[ ]*//" | sed "s/[ ]*\#.*//"` if [ "$SDLTEST" = "sdl" ] || [ "$SDLTEST" = "sdl2" ]; then simarchivbase=simuwin-sdl else simarchivbase=simuwin # Missing: Copy matching SDL dll! fi cd simutrans if [ "$PGC" -ne 0 ]; then getDLL fi cd .. updatepath="src/Windows/nsis/" updater="download-paksets.exe" if ! [[ -f "$updatepath$updater" ]]; then (cd "$updatepath" && makensis onlineupgrade.nsi) fi elif [ "$OST" = "linux" ]; then simarchivbase=simulinux elif [ "$OST" = "freebsd" ]; then simarchivbase=simubsd elif [ "$OST" = "amiga" ]; then simarchivbase=simuamiga fi # Test if there is something to distribute ... if [ ! -f ./simutrans/$BUILDDIR$simexe ]; then echo "No simutrans executable found! Aborted!" exit 1 fi cp $updatepath$updater simutrans # now add revision number without any modificators # fetch language files if [ "$#" = "0" ]; then # try local answer assuming we use svn REV_NR=`svnversion` if [ -z "$REV_NR" ]; then # nothing, then use revision number from server (assuming we are up to date) REV_NR=`svn info --show-item revision svn://servers.simutrans.org/simutrans | sed "s/[0-9]*://" | sed "s/M.*//"` fi simarchiv=$simarchivbase-$REV_NR elif [ `expr match "$*" ".*-rev="` > 0 ]; then REV_NR=$(echo $* | sed "s/.*-rev=[ ]*//" | sed "s/[^0-9]*//") simarchiv=$simarchivbase-$REV_NR else echo "No revision given!" simarchiv=$simarchivbase fi echo "Targeting archive $simarchiv" # (otherwise there will be many .svn included under windows) distribute() { # pack all files of the current release FILELISTE=`find simutrans -type f "(" -name "*.tab" -o -name "*.mid" -o -name "*.bdf" -o -name "*.fnt" -o -name "*.txt" -o -name "*.dll" -o -name "*.pak" -o -name "*.nut" -o -name "*.dll" ")"` zip -9 $simarchiv.zip $FILELISTE simutrans/simutrans$simexe simutrans/$updater } buildOSX() { echo "Build Mac OS package" # builds a bundle for MAC OS mkdir -p "simutrans.app/Contents/MacOS" mkdir -p "simutrans.app/Contents/Resources" cp $BUILDDIR$simexe "simutrans.app/Contents/MacOS/simutrans" strip "simutrans.app/Contents/MacOS/simutrans" cp "src/OSX/simutrans.icns" "simutrans.app/Contents/Resources/simutrans.icns" localostype=`uname -o` if [ "Msys" == "$localostype" ] || [ "Linux" == "$localostype" ]; then # only 7z on linux and windows can do that ... getSDL2mac 7z x "SDL2-2.0.10.dmg" rm SDL2-2.0.10.dmg else # assume MacOS mkdir -p "simutrans.app/Contents/Frameworks/" cp "/usr/local/opt/freetype/lib/libfreetype.6.dylib" \ "/usr/local/opt/libpng/lib/libpng16.16.dylib" \ "/usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib" \ "simutrans.app/Contents/Frameworks/" install_name_tool -change "/usr/local/opt/freetype/lib/libfreetype.6.dylib" "@executable_path/../Frameworks/libfreetype.6.dylib" "simutrans.app/Contents/MacOS/simutrans" install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Frameworks/libpng16.16.dylib" "simutrans.app/Contents/MacOS/simutrans" sudo install_name_tool -change "/usr/local/opt/libpng/lib/libpng16.16.dylib" "@executable_path/../Frameworks/libpng16.16.dylib" "simutrans.app/Contents/Frameworks/libfreetype.6.dylib" install_name_tool -change "/usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib" "@executable_path/../Frameworks/libSDL2-2.0.0.dylib" "simutrans.app/Contents/MacOS/simutrans" fi echo "APPL????" > "simutrans.app/Contents/PkgInfo" sh src/OSX/plistgen.sh "simutrans.app" "simutrans" if [ ! -d "pak" ]; then curl --progress-bar -L -o "pak.zip" "http://downloads.sourceforge.net/project/simutrans/pak64/122-0/simupak64-122-0.zip" unzip -qoC "pak.zip" -d .. rm -f "pak.zip" fi } # fetch language files if [ "$#" = "0" ] || [ `expr match "$*" "-no-lang"` = "0" ]; then sh tools/get_lang_files.sh fi # now built the archive for distribution cd simutrans if [ "$OST" = "mac" ]; then buildOSX cd .. ls pwd zip -r -9 - simutrans > simumac.zip cd simutrans rm -rf simutrans.app exit 0 else echo "Build default zip archive" cp $BUILDDIR$simexe ./simutrans$simexe strip simutrans$simexe cp ../$updatepath$updater $updater cd .. distribute # .. finally delete executable and language files rm simutrans/simutrans$simexe fi # cleanup dll's if [[ -n "$PGC" ]] && [[ "$PGC" -ne 0 ]]; then rm simutrans/pthreadGC2.dll fi # swallow any error values, return success in any case exit 0 simutrans-124.3/tools/get_lang_files.ps1000066400000000000000000000022121474050137200202770ustar00rootroot00000000000000# Downloade translations after post request and extract them #$translator_url = "https://translator.simutrans.com" $translator_url = "https://makie.de/translator" <# not sure why the second does not work ... $translator_url = "https://makie.de/translator" # Stackoverflow: First we create the request and get the status code $HTTP_Request = [System.Net.WebRequest]::Create("$translator_url") $HTTP_Response = $HTTP_Request.GetResponse() $HTTP_Status = [int]$HTTP_Response.StatusCode If ($HTTP_Status -ne 200) { $translator_url = "https://makie.de/translator" } #> Write-Output "Downloading and installing languag files from $translator_url" # now download $dummy=(New-Object System.Net.WebClient).UploadString("$translator_url/script/main.php?page=wrap", "version=0&choice=all&submit=Export!") Invoke-WebRequest -Uri "$translator_url/data/tab/language_pack-Base+texts.zip" -OutFile "temp.zip" #(New-Object System.Net.WebClient).DownloadFile("$translator_url/data/tab/language_pack-Base+texts.zip", ".") Remove-Item -ErrorAction Ignore "simutrans/text" -Recurse ; $null expand-archive -path "temp.zip" -DestinationPath "simutrans/text" Remove-Item "temp.zip" simutrans-124.3/tools/get_lang_files.sh000077500000000000000000000116371474050137200202240ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # updating SVN too? UPDATE_SVN=0 if [ "$#" -gt 0 ] && [ "$1" = '-svn' ]; then echo "Updating SVN too" UPDATE_SVN=1 else echo "Use option -svn to update the repo." fi move_if_differ_add() { pattern="$1" dest_path="$2" mkdir -p $dest_path if [[ $UPDATE_SVN -eq 1 ]]; then # only copy changed texts for f in $pattern; do if [[ -f "$dest_path/$f" ]]; then cat $f | grep "^[^#]" > $f.tmp a=`cat $dest_path/$f | grep "^[^#]" | diff -wq $f.tmp -` if [[ ! -z "$a" ]] ; then echo "Updating $f to texts" mv $f $dest_path/$f fi else # new file: move it and add it to svn echo "Creating $f to texts" mv $f $dest_path/$f svn add $dest_path/$f svn ps svn:eol-style native $dest_path/$f fi done else # only copy changed texts for f in $pattern; do cat $f | grep "^[^#]" > $f.tmp a=`cat $dest_path/$f | grep "^[^#]" | diff -wq $f.tmp -` if [[ ! -z "$a" ]] ; then echo "Updating $f to texts" mv $f $dest_path/$f fi done fi } move_add() { pattern="$1" dest_path="$2" if ! [[ -d "$dest_path" ]]; then mkdir -p $dest_path if [[ $UPDATE_SVN -eq 1 ]];then svn add $dest_path fi fi # only copy changed texts for f in $pattern; do if [[ $UPDATE_SVN -eq 1 ]] && ! [[ -f "$dest_path/$f" ]]; then # new file: move it and add it to svn echo "Creating $f to texts" mv $f $dest_path/$f svn add $dest_path/$f svn ps svn:eol-style native $dest_path/$f else mv $f $dest_path/$f fi done } # # script to fetch language files # # assumes to be called from main dir "tools/get_lang_files.sh" # OUTPUT_DIR=simutrans/text TEMP_DIR=lang-tmp #TRANSLATOR_URL=https://translator.simutrans.com TRANSLATOR_URL=https://makie.de/translator # get the translations for basis # The first file is longer, but only because it contains SQL error messages # - discard it after complete download (although parsing it would give us the archive's name): # first test which URL actually works # Use curl if available, else use wget curl -q -h > /dev/null if [ $? -eq 0 ]; then if ![ curl --head --silent --fail $TRANSLATOR_URL 2> /dev/null ]; then TRANSLATOR_URL=https://translator.simutrans.com fi echo "Using translator at $TRANSLATOR_URL" curl -q -L -d "version=0&choice=all&submit=Export%21" $TRANSLATOR_URL/script/main.php?page=wrap > /dev/null || { echo "Error: generating file language_pack-Base+texts.zip failed (curl returned $?)" >&2; exit 3; } curl -q -L $TRANSLATOR_URL/data/tab/language_pack-Base+texts.zip > language_pack-Base+texts.zip || { echo "Error: download of file language_pack-Base+texts.zip failed (curl returned $?)" >&2 rm -f "language_pack-Base+texts.zip" exit 4 } else wget -q --help > /dev/null if [ $? -eq 0 ]; then if ![ wget -q --method=HEAD $TRANSLATOR_URL 2> /dev/null ]; then TRANSLATOR_URL=https://translator.simutrans.com fi echo "Using translator at $TRANSLATOR_URL" wget -q --post-data "version=0&choice=all&submit=Export!" --delete-after $TRANSLATOR_URL/script/main.php?page=wrap || { echo "Error: generating file language_pack-Base+texts.zip failed (wget returned $?)" >&2; exit 3; } wget -q -N $TRANSLATOR_URL/data/tab/language_pack-Base+texts.zip || { echo "Error: download of file language_pack-Base+texts.zip failed (wget returned $?)" >&2 rm -f "language_pack-Base+texts.zip" exit 4 } else echo "Error: Neither curl or wget are available on your system, please install either and try again!" >&2 exit 6 fi fi # create temporary directory rm -rf $TEMP_DIR mkdir $TEMP_DIR # test archive unzip -otv "language_pack-Base+texts.zip" -d $TEMP_DIR || { echo "Error: file language_pack-Base+texts.zip seems to be defective" >&2 rm -f "language_pack-Base+texts.zip" exit 5 } unzip -o "language_pack-Base+texts.zip" -d $TEMP_DIR rm language_pack-Base+texts.zip # now we do this inside the tmmp directory cd $TEMP_DIR # remove Chris English (may become simple English ... ) rm -f ce.tab rmdir ce rm -f _objectlist.txt # Remove check test #rm xx.tab #rm -rf xx # user credits mv _translate_users.txt ../$OUTPUT_DIR/translate_users.txt # only copy changed texts move_if_differ_add "*.tab" "../$OUTPUT_DIR/" #if [[ $UPDATE_SVN -eq 1 ]]; then # svn ps svn:eol-style native ../$OUTPUT_DIR/*.tab #fi # remove the unchanged files (apart from dates and translators) rm *.tab rm *.tab.tmp # now move the help files for f in *; do if [ -z "$(ls -A $f)" ]; then echo "Remove empty help files for $f" else cd $f move_add "*.txt" "../../$OUTPUT_DIR/$f" cd .. rm -rf $f fi done cd .. rm -rf $TEMP_DIR simutrans-124.3/tools/get_pak.ps1000066400000000000000000000006321474050137200167530ustar00rootroot00000000000000# Downloades a simple zip file and unzips it. Assumes everything is according to Simutrans norm. Write-Output "Downloading and installing "$($args[0]) (New-Object System.Net.WebClient).DownloadFile($args[0], "temp.zip") expand-archive -path "temp.zip" -DestinationPath "." -Force del "temp.zip" if (Test-Path -Path "simutrans") { Move-Item -Path 'simutrans\*' -Destination . -Force rmdir -Force "simutrans" }simutrans-124.3/tools/get_pak.sh000077500000000000000000000363431474050137200166750ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # script to fetch pak sets # Downloads pak sets and installs them into $(pwd)/ # with option -generate_h it will instead update the NSIS and isntall files # # make sure that non-existing variables are not ignored set -u # fall back to "/tmp" if TEMP is not set TEMP=${TEMP:-/tmp} # # Download file. # Parameters: # URL # filename # # Status codes: # 0: Success # 1: Generic error # 2: File not found # do_download() { if which curl >/dev/null; then curl --progress-bar -L "$1" > "$2" || { echo "Error: download of file '$2' failed (curl returned $?)" >&2 rm -f "$2" return 1 } elif which wget >/dev/null; then wget -q --show-progress -O "$2" "$1" || { result=$? rm -f "$2" if [[ $result -eq 8 ]]; then echo "Error downloading file: Not found at URL '$1'" >&2 return 2 else echo "Unknown error downloading file (wget returned $result)" >&2 return 1 fi } else echo "Error: Neither curl or wget are available on your system, please install either and try again!" >&2 return 1 fi return 0 } install_cab() { pakzippath="$1" files=$(cabextract --list "$pakzippath" 2>/dev/null) || { #echo "Warning: no cabextract, assuming mingw on windows" >&2 files=$(extrac32 //D "$pakzippath" 2>/dev/null) || { echo "Error: Cannot extract .cab file (Either cabextract or makecab required)" >&2 return 1 } # this is likely Mingw on windows using extrac32 # First check if we only have a simutrans/ directory at the root. files=$(echo "$files" | grep ' simutrans\\') if [ $? -eq 0 ]; then # has simutrans folder, but cabextract cannot handle unix path on windows destdir="." else mkdir -p simutrans destdir="simutrans" fi files=$(extrac32 //L "$destdir" //Y //E "$pakzippath" 2>/dev/null) || { echo "Error: Could not extract '$pakzippath' to '$destdir'" >&2 return 1 } return 0 } # First check if we only have a simutrans/ directory at the root. files=$(echo "$files" | grep "| simutrans/") if [ $? -eq 0 ]; then # has simutrans folder, but cabextract cannot handle unix path on windows destdir="." else mkdir -p simutrans destdir="simutrans" fi cabextract -qd "$destdir" "$pakzippath" || { echo "Error: Could not extract '$pakzippath' to '$destdir'" >&2 return 1 } return 0 } install_tgz() { pakzippath="$1" files=$(tar -ztf "$pakzippath") || { echo "Error: Cannot extract .tar.gz file (tar with gzip support required)" >&2 return 1 } # First check if we only have a simutrans/ directory at the root. files=$(echo "$files"|grep "^simutrans") if [ $? -eq 0 ]; then # has simutrans folder destdir="$(pwd)" extra="--strip-components=1" else mkdir -p simutrans destdir="$(pwd)/simutrans" extra="" fi # No quotes around $extra, since adding quotes breaks extraction if $extra evaluates to the empty string # (This will be interpreted as the file(s) to extract and not as a command line parameter) tar -xzf "$pakzippath" $extra -C "$destdir" || { echo "Error: Could not extract '$pakzippath' to '$destdir'" >&2 return 1 } return 0 } install_zip() { pakzippath="$1" # First check if we only have a simutrans/ directory at the root. files=$(unzip -Z1 "$pakzippath" | grep "^simutrans/") if [ $? -eq 0 ]; then # we have simutrans already destdir="$(pwd)" echo "Extracting '$pakzippath' to '$destdir'..." temp=$(mktemp -d) && unzip -qoC "$pakzippath" -d "$temp" && mv "$temp"/*/* "$destdir" && rmdir "$temp"/* "$temp" else destdir="$(pwd)" echo "Extracting '$pakzippath' to '$destdir'..." unzip -qoC "$pakzippath" -d "$destdir" fi result=$? if [ $result -ge 2 ]; then # unzip failed echo "Error: Could not extract '$pakzippath' to '$destdir' (unzip returned: $result)" >&2 return 1 fi return 0 } # two parameters: # - url # - zipfilename download_and_install_pakset() { url="$1" pakzippath="$2" echo "Downloading from '$1'" do_download "$url" "$pakzippath" || return 1 if [ -n "$(file "$pakzippath" | grep -i "Microsoft Cabinet archive data")" ]; then # .cab file install_cab "$pakzippath" elif [ -n "$(file "$pakzippath" | grep -i "gzip compressed data")" ]; then # .tar.gz install_tgz "$pakzippath" elif [ -n "$(file "$pakzippath" | grep -i "Zip archive data")" ]; then # .zip install_zip "$pakzippath" elif [ "$(od --address-radix=n --read-bytes=4 --format=x1 $pakzippath)" = " 50 4b 03 04" ]; then # also .zip, if file failed for some reason install_zip "$pakzippath" else rm -f "$pakzippath" echo "Error: Cannot extract unknown archive format" >&2 return 1 fi result=$? rm -f "$pakzippath" if [ $result -ne 0 ]; then echo "Installation failed." >&2 return 1 fi echo "Installation completed." return 0 } # generated list of pak sets obsolete_start_index=12 paksets=( \ "http://downloads.sourceforge.net/project/simutrans/pak64/124-3/simupak64-124-3.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak128/pak128%20for%20ST%20124.3up%20%282.10.0%29/simupak128-2-10-for124-3up.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak192.comic/pak192.comic%20V0.7.2/pak192-comic.zip" \ "http://simutrans-germany.com/pak.german/pak64.german_0-124-0-0-5_full.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak64.japan/123-0/simupak64.japan-123-0.zip" \ "https://github.com/wa-st/pak-nippon/releases/download/v0.6.2/pak.nippon-v0.6.2.zip" \ "http://downloads.sourceforge.net/project/simutrans/Pak128.CS/nightly%20builds/pak128.CS-r2096.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak128.britain/pak128.Britain%20for%20120-3/pak128.Britain.1.18-120-3.zip" \ "http://pak128-german.de/PAK128.german_2.3_beta.zip" \ "https://github.com/Varkalandar/pak144.Excentrique/releases/download/r0.08/pak144.Excentrique_v008.zip" \ "http://downloads.sourceforge.net/project/simutrans/pakTTD/simupakTTD-124-0.zip" \ "http://codeberg.org/Nazalassa/pak48.bitlit/releases/download/0.1d/pak48.bitlit_0.1d.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak96.comic/pak96.comic%20for%20111-3/pak96.comic-0.4.10-plus.zip" \ "http://pak128.jpn.org/souko/pak128.japan.120.0.cab" \ "http://downloads.sourceforge.net/project/simutrans/pak32.comic/pak32.comic%20for%20102-0/pak32.comic_102-0.zip" \ "https://github.com/Varkalandar/pak48.Excentrique/releases/download/v0.19_RC3/pak48.excentrique_v019rc3.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak64.contrast/pak64.Contrast_910.zip" \ "http://downloads.sourceforge.net/project/simutrans/OldFiles/PakHD_v04B_100-0.zip" \ "http://downloads.sourceforge.net/project/simutrans/pakHAJO/pakHAJO_102-2-2/pakHAJO_0-102-2-2.zip" \ "http://downloads.sourceforge.net/project/simutrans/pak64.scifi/pak64.scifi_112.x_v0.2.zip" \ # "https://simutrans.bilkinfo.de/pak64.ho-scale-latest.tar.gz" \ #lost it ) # # main script # choices=() installpak=() paks_header="../../src/paksetinfo.h" nsis_header="../../src/Windows/nsis/paksets.nsh" if [ "$#" -gt 0 ] && [ "$1" = '-generate_h' ]; then echo "Generate input file for Simutrans and NSIS" mkdir tmp cd tmp mkdir simutrans echo "; Generated by \"get_pak.sh -generate_h\". DO NOT EDIT." > "$nsis_header" echo "// Generated by \"get_pak.sh -generate_h\". DO NOT EDIT." > "$paks_header" echo "#define PAKSET_COUNT ${#paksets[@]}" >> "$paks_header" echo "#define OBSOLETE_FROM ($obsolete_start_index)" >> "$paks_header" echo "paksetinfo_t pakinfo[PAKSET_COUNT] = {" >> "$paks_header" pakcount=0 for urlname in "${paksets[@]}" do zipname="${urlname##http*\/}" echo "Downloading $zipname" do_download "$urlname" "$zipname" || return 1 downloadcall="" skip_in_exe="0" destdir="" if [ -n "$(file "$zipname" | grep -i "Microsoft Cabinet archive data")" ]; then # .cab file install_cab "$zipname" skip_in_exe="1" downloadcall="DownloadInstallCabWithoutSimutrans" elif [ -n "$(file "$zipname" | grep -i "gzip compressed data")" ]; then # .tar.gz install_tgz "$zipname" skip_in_exe="1" downloadcall="DownloadInstallTgzWithoutSimutrans" elif [ -n "$(file "$zipname" | grep -i "Zip archive data")" ]; then # .zip # First check if we only have a simutrans/ directory at the root. files=$(unzip -Z1 "$zipname" | grep "^simutrans/") if [ $? -eq 0 ]; then # we have simutrans already downloadcall="DownloadInstallZip" unzip -qoC "$zipname" else downloadcall="DownloadInstallZipWithoutSimutrans" unzip -qoC "$zipname" -d "simutrans" echo "without" fi else rm -f "$zipname" echo "Error: Cannot extract unknown archive format" >&2 exit 1 fi size="$(du -s -Bk simutrans | sed 's/K.*$//')" echo "Size $size" rm -rf simutrans/themes rm -rf simutrans/config rm -rf simutrans/addons choicename="$(ls simutrans)" echo "choicename >$choicename<" versionstring="" count="$( od -An -tu2 -j 99 -N2 --endian=little simutrans/$choicename/ground.Outside.pak | tr -d ' ')" echo "count $count" if [ "$count" != "0" ] ; then versionstring="$(dd bs=1 skip=101 count=$count if=simutrans/$choicename/ground.Outside.pak status=none)" echo "version $versionstring" fi # paksetinfo.h echo $'\t'\{ "\"$urlname\", \"$choicename\", \"$versionstring\", $size }," >> "$paks_header" # nsh output if ((pakcount == $obsolete_start_index )); then # obsolete paks from here printf '\n; OBSOLETE PAKS from here\nSectionGroup /e "Not currently developed" slowPakgroup\n\n' >> "$nsis_header" fi if [ "$choicename" == "pak" ]; then # sectiongroup for pak64 printf "SectionGroup /e \"Pak64: main and addons\" pak64group\n\n" >> "$nsis_header" fi # normal section echo $"Section /o \"$choicename\" $choicename" >> "$nsis_header" echo $" AddSize $size" >> "$nsis_header" echo $" StrCpy \$downloadlink \"$urlname\"" >> "$nsis_header" echo " SetOutPath \$PAKDIR" >> "$nsis_header" echo " StrCpy \$archievename \"$zipname\"" >> "$nsis_header" echo " StrCpy \$downloadname \"$choicename\"" >> "$nsis_header" echo " StrCpy \$VersionString \"$versionstring\"" >> "$nsis_header" echo " Call $downloadcall" >> "$nsis_header" echo "SectionEnd" >> "$nsis_header" if [ "$choicename" == "pak" ]; then # pak64 addons printf "Section /o \"pak64 Food addon\"\n AddSize 228\n StrCpy \$downloadlink \"http://downloads.sourceforge.net/project/simutrans/pak64/121-0/simupak64-addon-food-120-4.zip\"\n StrCpy \$archievename \"simupak64-addon-food-120-4.zip\"\n StrCpy \$downloadname \"pak\"\n" >> "$nsis_header" printf " StrCpy \$VersionString \"\"\n StrCmp \$multiuserinstall \"1\" +3\n ; no multiuser => install in normal directory\n Call DownloadInstallAddonZipPortable\n goto +2\n Call DownloadInstallAddonZip\nSectionEnd\n\n" >> "$nsis_header" printf "SectionGroupEnd\n\n" >> "$nsis_header" fi echo "" >> "$nsis_header" rm -rf simutrans rm -rf $zipname mkdir simutrans pakcount=$((pakcount+1)) done printf "SectionGroupEnd\n\n" >> "$nsis_header" echo "};" >> "$paks_header" cd .. rm -rf tmp exit 0 fi pwd | grep "/simutrans$" >/dev/null || { echo "Warning install csb-paksets might fail if not in a simutrans/ directory" >&2 } # first find out, if we have a command options and just install these paks # parameter is the full path to the pakset if [ "$#" -gt 0 ]; then for pakname in "$@" do if [[ $pakname == "http"* ]]; then # direct download if whatever zipname="${pakname##http*\/}" choicename="${zipname%.*}" choicename="${choicename%.tar}" # for .tar.gz choicename="${choicename/simupak/pak}" echo "-- Installing $choicename --" tempzipname="$TEMP/$zipname" download_and_install_pakset "$urlname" "$tempzipname" || { echo "Error installing pakset $choicename" exit 1 } else # find pakset with this folder name has_match="0" for urlname in "${paksets[@]}" do if [[ $urlname == *"/$pakname"/* ]]; then zipname="${urlname##http*\/}" choicename="${zipname%.*}" choicename="${choicename%.tar}" # for .tar.gz choicename="${choicename/simupak/pak}" echo "-- Installing $choicename --" tempzipname="$TEMP/$zipname" download_and_install_pakset "$urlname" "$tempzipname" || { echo "Error installing pakset $choicename" exit 1 } has_match="1" fi done if [[ $has_match == "0" ]]; then echo "No pak matches $pakname" exit 1 fi fi done exit 0 fi echo "-- Choose at least one of these paks --" let setcount=0 let choicecount=0 let "maxcount = ${#paksets[*]}" while [ "$setcount" -lt "$maxcount" ]; do installpak[choicecount]=0 urlname=${paksets[$setcount]} zipname="${urlname##http*\/}" choicename="${zipname%.*}" choicename="${choicename%.tar}" # for .tar.gz choicename="${choicename/simupak/pak}" choices[choicecount]=$choicename let "setcount += 1" let "choicecount += 1" echo "${choicecount}) ${choicename}" done while true; do read -p "Which paks to install? (enter number or (i) to install or (x) to exit)" pak #exit? if [[ $pak = [xX] ]]; then exit 0 fi # test if installation now if [[ $pak = [iI] ]]; then echo "" echo "You will install now" let setcount=0 while [ $setcount -lt $choicecount ]; do if [ ${installpak[$setcount]} -gt 0 ]; then let "displaycount=$setcount+1" echo "${displaycount}) ${choices[$setcount]}" fi let "setcount += 1" done echo "into directory '$(pwd)'" read -p "Is this correct? (y/n)" yn if [[ $yn = [yY] ]]; then break fi # edit again echo "" echo "-- Choose again one of these paks --" let setcount=0 while [ $setcount -lt $choicecount ]; do echo "${setcount}) ${choices[$setcount]}" let "setcount += 1" done let "pak=0" fi # otherwise it should be a number if [[ $pak =~ ^[0-9]+$ ]]; then let "setcount=pak-1" if [ $setcount -lt $choicecount ]; then if [ $setcount -ge 0 ]; then status=${installpak[$setcount]} if [ $status -lt 1 ]; then echo "adding ${choices[$setcount]}" installpak[$setcount]=1 else echo "not installing ${choices[$setcount]}" installpak[$setcount]=0 fi fi fi fi done echo "" # install the regular pak sets first let setcount=0 let "maxcount = ${#paksets[*]}" fail=0 while [ "$setcount" -lt "$maxcount" ]; do if [ "${installpak[$setcount]}" -gt 0 ]; then urlname=${paksets[$setcount]} zipname="${urlname##http*\/}" echo "-- Installing ${choices[$setcount]} --" tempzipname="$TEMP/$zipname" download_and_install_pakset "$urlname" "$tempzipname" || { echo "Error installing pakset ${choices[$setcount]}" let "fail++" } echo "" fi let "setcount++" done exit $fail simutrans-124.3/tools/get_revision.bat000066400000000000000000000001751474050137200201030ustar00rootroot00000000000000powershell.exe -ExecutionPolicy Bypass -NoProfile -NonInteractive -command "tools/get_revision.ps1 src/simutrans/revision.h" simutrans-124.3/tools/get_revision.ps1000066400000000000000000000026261474050137200200430ustar00rootroot00000000000000$revision = 0 $answer = svnversion $has_svn = $? #$answer=$answer.Trim("MSP:") $answer=$answer.substring(0,5); $is_number = ($null -ne ($answer -as [int])) if($has_svn -and $is_number) { # svnversion valid number $revision = [int]$answer } else { # try git $answer = git log -1 if($?) { # we have git! $answer = $answer | Select-String -Pattern 'git-svn-id:' if($null -ne $answer) { $answer = $answer -match "trunk\@(.*) " $answer = $matches[1] $is_number = ($null -ne ($answer -as [int])) } if(!$is_number) { # not a standard git use some random number ... $answer=git rev-list --count --first-parent HEAD $is_number = ($null -ne ($answer -as [int])) if($is_number) { # svnversion valid number $answer = [int]$answer $answer = $answer + 331 } } } } if(!$is_number -and $has_svn) { # svn cammnd exists but not repo $answer = svn info svn://servers.simutrans.org/simutrans $answer = $answer | Select-String -Pattern 'Revision:' $a=$answer.tostring(); $answer = $a.Substring(10) $is_number = ($null -ne ($answer -as [int])) } if($is_number) { # valid revision ... $answer if($args.count -eq 1) { # create revision.h "Create $($args[0])" $revfile = "#define REVISION $answer`n" $revfile | Out-File $args[0] } } else { "0" if($args.count -eq 1) { # create revision.h $revfile = "#define REVISION unrevisioned`n" $revfile | Out-File $($args[0]) } } simutrans-124.3/tools/get_revision.sh000077500000000000000000000012271474050137200177510ustar00rootroot00000000000000#!/bin/bash # # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # # script to the revision number and put it into the file revision.h # svn info 2>/dev/null 1>/dev/null if [ $? -eq 0 ]; then # using svn for verything REV=$(svnversion) HASH=$REV else # try using git git describe --always 2>/dev/null 1>/dev/null if [ $? -eq 0 ]; then REV=$(git log -1 | grep "git-svn-id" | sed "s/^.*trunk\@//" | sed "s/ .*$//") if [ -z "$REV" ]; then # make preudo rev from git REV=$(git rev-list --count --first-parent HEAD) REV=`expr $REV + 328` fi else REV="" fi fi echo "$REV"simutrans-124.3/tools/install-building-libs-arm64.bat000066400000000000000000000007271474050137200225300ustar00rootroot00000000000000@echo Please add the english language pack to MSVC. Then clone @echo https://github.com/Microsoft/vcpkg @echo open a commandline in this folder and run @echo then run bootstrap-vcpkg.bat before running this script @echo from the vcpgk folder! @pause vcpkg integrate install @rem arm64 builds vcpkg install freetype:arm64-windows-static vcpkg install miniupnpc:arm64-windows-static vcpkg install pthreads:arm64-windows-static vcpkg install zstd:arm64-windows-static @pausesimutrans-124.3/tools/install-building-libs-x64.bat000066400000000000000000000007201474050137200222110ustar00rootroot00000000000000@echo Please add the english language pack to MSVC. Then clone @echo https://github.com/Microsoft/vcpkg @echo open a commandline in this folder and run @echo then run bootstrap-vcpkg.bat before running this script @echo from the vcpgk folder! @pause vcpkg integrate install @rem 64 bit builds vcpkg install freetype:x64-windows-static vcpkg install miniupnpc:x64-windows-static vcpkg install pthreads:x64-windows-static vcpkg install zstd:x64-windows-static @pausesimutrans-124.3/tools/install-building-libs-x86.bat000066400000000000000000000007201474050137200222150ustar00rootroot00000000000000@echo Please add the english language pack to MSVC. Then clone @echo https://github.com/Microsoft/vcpkg @echo open a commandline in this folder and run @echo then run bootstrap-vcpkg.bat before running this script @echo from the vcpgk folder! @pause vcpkg integrate install @rem 32 bit builds vcpkg install freetype:x86-windows-static vcpkg install miniupnpc:x86-windows-static vcpkg install pthreads:x86-windows-static vcpkg install zstd:x86-windows-static @pausesimutrans-124.3/tools/revision.jse000066400000000000000000000037601474050137200172620ustar00rootroot00000000000000// // This file is part of the Simutrans project under the Artistic License. // (see LICENSE.txt) // var ForReading = 1; var ForWriting = 2; var fso = new ActiveXObject("Scripting.FileSystemObject"); var shell = new ActiveXObject("WScript.Shell"); var rev; var filename = "src\\simutrans\\revision.h"; var file; var file_ts; var errorcode; // First, get the file, if it doesn't exist create it. if (!fso.FileExists(filename)) { fso.CreateTextFile(filename); file = fso.GetFile(filename); file_ts = file.OpenAsTextStream(ForWriting, -2); file_ts.WriteLine("#define REVISION UNDEFINED"); file_ts.Close(); errorcode = 0; } else { file = fso.GetFile(filename); errorcode = 1; } var errormsg = !errorcode ? " Revision number will be set to zero. You won't be able to play online with this build." : " A revision file already exists and its revision number won't be updated. Make sure the revision number is correct or you won't be able to play online with this build."; // Try to get revision number try { var svnRevNum = shell.Exec("svnversion"); rev = svnRevNum.StdOut.ReadAll(); // Check if SVN output is valid if (typeof parseInt(rev) !== "number") { WSH.Echo("svnversion : Unversioned directory warning SVNUD" + errorcode + ":SVN output not valid! Check if the folder is actually versioned." + errormsg); rev = 0; } } catch (e) { WSH.Echo("svnversion : SVN not found warning SVNNF" + errorcode + ":SVN could not be found!" + errormsg); rev = 0; } // Read revision.h file_ts = file.OpenAsTextStream(ForReading, -2); var current_line = file_ts.ReadLine() + "\r\n"; file_ts.Close(); var new_line = !rev ? "" : "#define REVISION " + String(rev); if (!errorcode || (!!rev && new_line !== current_line)) { // It has changed, update the .h WSH.Echo("revision.h(0) : info SVNUPD:" + (!rev ? "No revision number set!" : "SVN version updated! " + String(rev))); file_ts = file.OpenAsTextStream(ForWriting, -2); file_ts.WriteLine(new_line); file_ts.Close(); } simutrans-124.3/tools/run-automated-tests.sh000077500000000000000000000014261474050137200212020ustar00rootroot00000000000000#!/bin/bash set -e pushd simutrans ../sim -use_workdir -objects pak -lang en -scenario automated-tests -addons -debug 2 2>&1 | ts -s | tee output.log & pid=$! result=1 while : do sleep 1 if [[ ! -d /proc/$pid/ ]] then # process crashed etc. echo "Process crashed (test failed)" result=1 break fi if [[ -n "$(grep 'Tests completed successfully.' output.log)" ]] then # kill echo "Killing process (test succeeded)" kill %1 result=0 break fi if [[ -n "$(grep 'error \[Call function failed\] calling' output.log)" || -n "$(grep 'error \[Reading / compiling script failed] calling' output.log)" || -n "$(grep '' output.log)" ]] then # kill echo "Killing process (test failed)" kill %1 result=1 break fi done popd exit $result simutrans-124.3/tools/setup-debian.sh000077500000000000000000000006161474050137200176350ustar00rootroot00000000000000#!/bin/bash echo "We need to have a current system or it fails" apt update apt -y upgrade echo "Now installing dependencies" # neccessary packets apt -y install autoconf pkg-config subversion zip unzip cmake make apt -y install gcc g++ libbz2-dev libfreetype-dev libfontconfig-dev libpng-dev libminiupnpc-dev libzstd-dev libfluidsynth-dev # optional for SLD2 builds: apt -y install libsdl2-dev simutrans-124.3/tools/setup-mingw.sh000077500000000000000000000023371474050137200175360ustar00rootroot00000000000000#!/bin/bash echo "First we update the system" pacman -Syu pacman -Syu echo "Now installing dependencies" # neccessary packets pacman -S --noconfirm make autoconf pkg-config subversion zip unzip zstd pacman -S --noconfirm $MINGW_PACKAGE_PREFIX-gcc $MINGW_PACKAGE_PREFIX-bzip2 $MINGW_PACKAGE_PREFIX-freetype $MINGW_PACKAGE_PREFIX-libpng $MINGW_PACKAGE_PREFIX-brotli $MINGW_PACKAGE_PREFIX-cmake # optional for SLD2 builds: pacman -S --noconfirm $MINGW_PACKAGE_PREFIX-SDL2 # optional for installer: pacman -S --noconfirm $MINGW_PACKAGE_PREFIX-nsis rm -rf master.zip wget https://github.com/miniupnp/miniupnp/archive/master.zip unzip -o master.zip cd miniupnp-master/miniupnpc cat Makefile.mingw | sed 's|[ \t]wingenminiupnpcstrings.exe |'"$(printf '\t')"'./wingenminiupnpcstrings.exe |' >Makefile.mingw2 make -f Makefile.mingw2 cp libminiupnpc.a $MINGW_PREFIX/lib cp *.h $MINGW_PREFIX/lib mkdir -p $MINGW_PREFIX/include/miniupnpc cp *.h $MINGW_PREFIX/include/miniupnpc cp include/*.h $MINGW_PREFIX/include/miniupnpc cd ../.. rm -rf master.zip rm -rf miniupnpc-master # libbrotli static is broken but needed for freetype for f in libbrotlidec libbrotlienc libbrotlicommon; do mv "$MINGW_PREFIX/lib/$f-static.a" "$MINGW_PREFIX/lib/$f.a" done simutrans-124.3/tools/zipsrc.sh000077500000000000000000000026721474050137200165730ustar00rootroot00000000000000#!/bin/bash # packen() { # pack all files of the current release FILELISTE=`find . -type f "(" -name "*.c" -o -name "*.h" -o -name "*.cc" -o -name "*.mm" ")"` FILELISTF=`find . -type f "(" -name "*.sh" -o -name "*.mk" -o -name "*.nut" ")"` FILELISTG=`find . -type f "(" -name "*.txt" -o -name "*.bdf" -o -name "*.fnt" -o -name "*.mid" -o -name "*.tab" ")"` FILELISTI=`find . -type f "(" -name "*.tab" -o -name "*.dat" -o -name "*.png" -o -name "*.svg" -o -name "*.desktop" ")"` rm ../simutrans-src.zip zip ../simutrans-src.zip $FILELISTE zip ../simutrans-src.zip $FILELISTF zip ../simutrans-src.zip $FILELISTG zip ../simutrans-src.zip $FILELISTH zip ../simutrans-src.zip $FILELISTI zip ../simutrans-src.zip Makefile src/makeobj/Makefile src/nettool/Makefile zip ../simutrans-src.zip cmake/*.cmake zip ../simutrans-src.zip configure.ac config.default.in config.template src/OSX/simutrans.icns zip ../simutrans-src.zip documentation/*.pal simutrans/themes/*.pak zip -r ../simutrans-src.zip src/Windows } # not used (stumbles in private: in class definition ... :( ) beautify() { # convert all source files and reformats them FILELISTE=`find . -type f "(" -name "*.c" -o -name "*.h" -o -name "*.cc" ")"` for file in $FILELISTE; do bcpp -f 2 -t -i 2 -ylcnc -yq bcl -yo -qb 1000 < $file > _tmpfile touch -r $file _tmpfile echo "bcpp $file" cp -f _tmpfile $file rm -f _tmpfile done } # take action! cd .. autoconf packen simutrans-124.3/translate_code/000077500000000000000000000000001474050137200165425ustar00rootroot00000000000000simutrans-124.3/translate_code/base_things.csv000066400000000000000000000004431474050137200215460ustar00rootroot00000000000000neues_jahr,new_year zeige_info,open_info_window neuer_monat,new_month finde_anzahl_hersteller,count_producers anzahl_hersteller,producer_count anzahl_staedte,city_count vehikel_anzahl,vehicle_count get_bild_anzahl,get_count get_waren_anzahl,get_count get_anzahl_besch,get_count anzahl,count simutrans-124.3/translate_code/batch_replace.sh000077500000000000000000000006521474050137200216600ustar00rootroot00000000000000#/bin/bash while IFS=, read from to do echo "Replace $from by $to" REPLACE="s#$from#$to#g" find ../ -name "*.cc" -or -name "*.h" -or -name "Makefile" -or -name "*.*proj" | while read fname; do sed "${REPLACE}" $fname > tmp.sed if [ $? -ne 0 ]; then break fi cmp -s tmp.sed $fname res=$? if [ $res -eq 1 ] then echo "Replace in $fname" mv tmp.sed $fname else rm tmp.sed fi done done < $1 simutrans-124.3/translate_code/translate_besch.csv000066400000000000000000000130011474050137200224130ustar00rootroot00000000000000\\\\([^.]\\),_desc\\1 baum_besch_t,tree_desc_t comapility,compatibility compare_baum_desc,compare_tree_desc baumlist,tree_list baum_typen,tree_list baumtype,tree_id bruecke_besch_t,bridge_desc_t _Rampe,_Ramp _rampe,_ramp bruecken_by_name,desc_table finde_ende,find_end_pos ist_ende_ok,can_place_ramp baue_auffahrt,build_ramp baue_bruecke,build_bridge \\,build brueckenbauer_t,bridge_builder_t gewichtung,chance field_class_besch_t,field_class_desc_t field_group_besch_t,field_group_desc_t rauch_besch_t,smoke_desc_t fabrik_lieferant_besch_t,factory_supplier_desc_t kapazitaet,capacity verbrauch\\>,consumption fabrik_produkt_besch_t,factory_product_desc_t faktor,factor fabrik_besch_t,factory_desc_t platzierung,placement produktivitaet,productivity bereich,range kennfarbe\\([^._]\\),color\\1 lieferanten,supplier_count produkte\\>,product_count lieferant,supplier produkt,product get_rauch,get_smoke fabrikbauer_t,factory_builder_t fabs_to,factories_to finde_hersteller,find_producer verteile_tourist,distribute_attractions baue_fabrik,build_factory, baue_hierarchy,build_chain baue_link_hierarchie,build_chain_link ist_bauplatz,check_construction_site finde_zufallsbauplatz,find_random_construction_site fab_desc,fac_desc fablist,factory_list hersteller,producer_d \\,fd Wasser,Water Stadt,City fussgaenger_besch_t,pedestrian_desc_t grund_besch_t,ground_besch_t ausserhalb,outside haus_tile_besch_t,building_tile_desc_t haus_besch_t,building_desc_t phasen,phases \\,building haus_desc,building_desc FLAG_KEINE_INFO,FLAG_NO_INFO FLAG_KEINE_GRUBE,FLAG_NO_PIT get_h\\>,get_y get_b\\>,get_x ist_mit_boden,needs_ground ist_ohne_grube,no_construction_pit ist_ohne_info,no_info_window get_post_level,get_mail_level unbekannt,unknown denkmal,monument ist*_fabrik\\>,is_factory \\,factory ist_rathaus,is_townhall rathaus,townhall weitere,others ist_firmensitz,is_headquarter ist_ausflugsziel,is_attraction firmensitz,headquarter get_haus\\>,get_building \\,bdsc \\,tdsc layout_anpassen,adjust_layout hauslist,building_list baue_hierarchie,build_link alles_geladen,successfully_loaded waehle_aus_liste,get_random_desc waehle_sehenswuerdigkeit,get_random_attraction waehle_monument,get_random_monument monument_gebaut,monument_erected neues_gebaeude,build_station_extension_depot sehenswuerdigkeiten_land,attractions_land sehenswuerdigkeiten_city,attractions_city ungebaute_denkmaeler,unbuilt_monuments denkmaeler,monuments rathaeuser,townhalls wohnhaeuser,city_residential gewerbehaeuser,city_commercial industriehaeuser,city_industry warne_ungeladene,warn_missing_objects spezial_objekte,special_objects wegtyp1,waytype1 wegtyp2,waytype2 kreuzung_besch_t,crossing_desc_t roadsign_besch_t,roadsign_desc_t sound_besch_t,sound_desc_t \\,build_tunnel baue_einfahrt,build_tunnel_portal tunnelbauer_t,tunnel_builder_t find_tunnel,get_tunnel_desc zuladung,capacity gewicht,weight sum_gear_und_leistung,sum_gear_and_power leistung,power \\,leader_count \\,trailer_count get_vorgaenger_count,get_leader_count get_nachfolger_count,get_trailer_count get_vorgaenger,get_leader get_nachfolger,get_trailer get_betriebskosten,get_running_cost vehikelbauer_t,vehicle_builder_t weg_besch_t,way_desc_t weg_desc,way_desc alle_wegtypen,desc_table alle_wege_geladen,successfully_loaded bruecke_desc,bridge_desc wegbauer_t,way_builder_t baue_tunnel_und_bruecken,build_tunnel_and_bridges baue_tunnelboden,build_tunnel_tile baue_elevated,build_elevated baue_strasse,build_road baue_schiene,build_track baue_leitung,build_powerline baue_fluss,build_river route_fuer,init_builder check_for_leitung,check_powerline get_image_id_switch,get_switch_image_id get_hang_imageid,get_slope_image_id hang_img,slope_img get_diagonal_imageid,get_diagonal_image_id is_hintergrund_phases,is_background_animated vehikel_besch_t,vehicle_desc_t \\,list \\,list2d ware_besch_t,goods_desc_t good_reader_t,goods_reader_t good_writer_t,goods_writer_t warenbauer_t,goods_manager_t load_passagiere,load_passengers load_post,load_mail load_nichts,load_none \\,goods :post,:mail \\,passengers \\,none ware_index,goods_index get_post_enabled,get_mail_enabled \\,mail mail-p,post-p skin_besch_t,skin_desc_t xref_besch_t,xref_desc_t baum_besch,tree_desc bild_besch,image bruecke_besch,bridge_desc fabrik_besch,factory_desc fussgaenger_besch,pedestrian_desc groundobj_besch,groundobj_desc grund_besch,ground_desc haus_besch,building_desc kreuzung_besch,crossing_desc obj_besch,obj_desc obj_besch_std_name,obj_base_desc roadsign_besch,roadsign_desc skin_besch,skin_desc sound_besch,sound_desc stadtauto_besch,citycar_desc text_besch,text_desc tunnel_besch,tunnel_desc vehikel_besch,vehicle_desc ware_besch,goods_desc way_obj_besch,way_obj_desc weg_besch,way_desc xref_besch,xref_desc besch\\/,descriptor/ ground_besch,ground_desc _BESCH_H,_DESC_H GETBESCHFUNC,GETDESCFUNC begin_besch_class,begin_desc_class export_besch,export_desc _besch_,_desc_ besch_alt,besch_old fabesch,factory_desc besch1,desc1 besch2,desc2 besch_vorgaenger,desc_leader besch_nachfolger,desc_trailer Modulbeschreibung,Description besch_,desc_ besch\\\\,descriptor\\\\ \\,desc simutrans-124.3/translate_code/translate_bild.csv000066400000000000000000000016171474050137200222530ustar00rootroot00000000000000target_besch,target_image bild_dest,image_dest \\,imglist \\,imgarray get_daten,get_data get_nummer,get_id bild_besch_t,image_t get_bild_nr,get_image_id get_vordergrund,get_foreground get_hintergrund,get_background get_bilder,get_images get_bild,get_image bild_besch_t,image_t bildliste_besch_t,image_list_t bildliste2d_besch_t,image_array_t get_liste,get_list calc_bild,calc_image set_bild,set_image \\,image Vordergrundbilder,Foreground-images Hintergrundbilder,Background-images back_bild,back_image backbild,back_image after_bild,foreground_image tmp_bild,tmp_image bild_nr,imageid _image_nr,_imageid bild0,image0 basis_bild,base_image bild_data,image_data _bild\\>,_image Bildliste2D,Image-list 2d Bildliste,Image-list baum_bild_alter,tree_age_index ground_bild_list,ground_image_list bild_index,index bild_in,image_in Kindknoten,Child nodes Beschreibung\\>,Description (keine),(none) simutrans-124.3/translate_code/translate_dataobj.csv000066400000000000000000000021521474050137200227400ustar00rootroot00000000000000autofahrplan,truck_schedule zugfahrplan,train_schedule schifffahrplan,ship_schedule airfahrplan,airplane_schedule monorailfahrplan,monorail_schedule tramfahrplan,tram_schedule maglevfahrplan,maglev_schedule narrowgaugefahrplan,narrowgauge_schedule fpl,schedule ist_abgeschlossen,is_editing_finished abgeschlossen,editing_finished eingabe_abschliessen,finish_editing eingabe_beginnen,start_editing ladegrad,minimum_loading aktuell\\>,current_stop fehlermeldung,get_error_msg anzahl_staedte,city_count einwohnerzahl,citizen_count linieneintrag,schedule_entry current_eintrag,current_entry dummy_eintrag,dummy_entry eintrag\\>,entries mittlere_,mean_ zustand,state neue_karte,new_world \\,schedule fahrplan_gui_,schedule_gui_ tool_fahrplan_,tool_schedule_ groesse_x,size_x groesse_y,size_y groesse\\>,size karte_nummer,map_number nummer\\>,map_number verkehr_level,traffic_level position_bei,at FAHRPLANEINGABE,EDIT_SCHEDULE fahrplan_gui,schedule_gui fahrplaneingabe,open_schedule_editor fahrplan_h,schedule_h fahrplan_t,schedule_t set_fahrplan,set_schedule fahrplan_index,schedule_index ist_halt_erlaubt,is_stop_allowed simutrans-124.3/translate_code/translate_display.csv000066400000000000000000000000751474050137200230030ustar00rootroot00000000000000karte_ansicht_t,main_view_t stunden,hours IMG_LEER,IMG_EMPTY simutrans-124.3/translate_code/translate_fahrplan_h.csv000066400000000000000000000000731474050137200234360ustar00rootroot00000000000000fahrplan\\.h,schedule.h linieneintrag\\.h,schedule_entry.h simutrans-124.3/translate_code/translate_nsew.csv000066400000000000000000000001441474050137200223070ustar00rootroot00000000000000nordost,northeast suedost,southeast ostwest,eastwest nord,north sued,south \\,east nsow,nsew simutrans-124.3/translate_code/translate_ribi.csv000066400000000000000000000017301474050137200222620ustar00rootroot00000000000000hang_t::typ,slope_t::type hang_t::doppel,slope_t::doubles hang_t::wegbar_ns,slope_t::way_ns hang_t::wegbar_ow,slope_t::way_ew hang_t::einfach,slope_t::single hang_t::all_up,slope_t::all_up corner1,corner_sw corner2,corner_se corner3,corner_ne corner4,corner_nw slope_t::corner,slope4_t::corner hang_typ,slope_type hang_t::flach,slope_t::flat hang_t::erhoben,slope_t::raised hang_t::gegenueber,slope_t::opposite hang_t::ist_einfach,slope_t::is_single hang_t::ist_wegbar_ns,slope_t::is_way_ns hang_t::ist_wegbar_ow,slope_t::is_way_ew hang_t::ist_wegbar,slope_t::is_way hang_t::,slope_t:: ribi_t::ist_exakt_orthogonal,ribi_t::is_perpendicular ribi_t::ist_einfach,ribi_t::is_single ribi_t::ist_kurve,ribi_t::is_bend ribi_t::ist_gerade_ns,ribi_t::is_straight_ns ribi_t::ist_gerade_ow,ribi_t::is_straight_ew ribi_t::ist_gerade,ribi_t::is_straight ribi_t::doppelt,ribi_t::doubles ribi_t::rueckwaerts,ribi_t::backward ribi_t::keine,ribi_t::none ribi_t::alle,ribi_t::all ribi_typ\\>,ribi_type simutrans-124.3/uncommon.mk000066400000000000000000000031451474050137200157420ustar00rootroot00000000000000# # This file is part of the Simutrans project under the Artistic License. # (see LICENSE.txt) # # Source files located in ../ OBJS := $(patsubst %, $(BUILDDIR)/%-$(TOOL).o, $(basename $(patsubst ../simutrans/%, %,$(filter ../simutrans/%,$(SOURCES))))) # Source files located in current directory OBJS += $(patsubst %, $(BUILDDIR)/$(TOOL)/%-$(TOOL).o, $(basename $(filter-out ../simutrans/%,$(SOURCES)))) DEPS := $(patsubst %.o, %.d, $(OBJS)) DIRS := $(sort $(dir $(OBJS))) BUILDCONFIG_FILES := ../../uncommon.mk Makefile ../../config.$(CFG) # Make build directories DUMMY := $(shell mkdir -p $(DIRS)) .PHONY: all clean clean-prog ifeq ($(VERBOSE),) Q = @ else Q = endif all: $(TOOL_PROGDIR)/$(PROG) $(TOOL_PROGDIR)/$(PROG): $(OBJS) @echo "===> LD $@" $(Q)$(CXX) $(OBJS) $(LDFLAGS) $(STD_LIBS) $(LIBS) -o $(TOOL_PROGDIR)/$(PROG) clean-prog: $(Q)rm -f $(TOOL_PROGDIR)/$(PROG) clean: @echo "===> Cleaning up" $(Q)rm -f $(OBJS) $(Q)rm -f $(DEPS) $(Q)rm -f $(TOOL_PROGDIR)/$(PROG) -include $(DEPS) # Silence stale header dependency errors %.h: @true # Source files located in ../ $(BUILDDIR)/%-$(TOOL).o: ../simutrans/%.cc $(BUILDCONFIG_FILES) @echo "===> CC $<" $(Q)$(CC) $(CCFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/%-$(TOOL).o: ../simutrans/%.cc $(BUILDCONFIG_FILES) @echo "===> CXX $<" $(Q)$(CXX) $(CXXFLAGS) -c -MMD -o $@ $< # Source files located in current directory $(BUILDDIR)/$(TOOL)/%-$(TOOL).o: %.c $(BUILDCONFIG_FILES) @echo "===> CC $<" $(Q)$(CC) $(CCFLAGS) -c -MMD -o $@ $< $(BUILDDIR)/$(TOOL)/%-$(TOOL).o: %.cc $(BUILDCONFIG_FILES) @echo "===> CXX $<" $(Q)$(CXX) $(CXXFLAGS) -c -MMD -o $@ $< simutrans-124.3/vcpkg.json000066400000000000000000000003521474050137200155600ustar00rootroot00000000000000{ "version-string": "1.0.0", "dependencies": [ "freetype", "miniupnpc", "pthread", "zstd", "sdl2", "zlib" ], "builtin-baseline": "3c76dc55f8bd2b7f4824bcd860055094bfbbb9ea" }

Os Detalhes do Comboio abrem-se do botão de opções Detalhes na janela da Informação do Comboio (use a ferramenta Consultar sobre um Comboio).
Se todos os itens não estão visíveis, reajuste a janela dos Detalhes do Comboio ou use as barras laterais para ver os outros itens.